Merge "Update V8 to version 4.1.0.21"
diff --git a/AUTHORS b/AUTHORS
index f18761e..89caae6 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -14,6 +14,9 @@
 BlackBerry Limited
 Opera Software ASA
 Intel Corporation
+MIPS Technologies, Inc.
+Imagination Technologies, LLC
+Loongson Technology Corporation Limited
 
 Akinori MUSHA <knu@FreeBSD.org>
 Alexander Botero-Lowry <alexbl@FreeBSD.org>
@@ -24,6 +27,7 @@
 Baptiste Afsa <baptiste.afsa@arm.com>
 Bert Belder <bertbelder@gmail.com>
 Burcu Dogan <burcujdogan@gmail.com>
+Caitlin Potter <caitpotter88@gmail.com>
 Craig Schlenter <craig.schlenter@gmail.com>
 Chunyang Dai <chunyang.dai@intel.com>
 Daniel Andersson <kodandersson@gmail.com>
@@ -35,6 +39,7 @@
 Filipe David Manana <fdmanana@gmail.com>
 Haitao Feng <haitao.feng@intel.com>
 Ioseb Dzmanashvili <ioseb.dzmanashvili@gmail.com>
+Isiah Meadows <impinball@gmail.com>
 Jacob Bramley <jacob.bramley@arm.com>
 Jan de Mooij <jandemooij@gmail.com>
 Jay Freeman <saurik@saurik.com>
diff --git a/Android.d8.mk b/Android.d8.mk
index ffacf4b..ec122eb 100644
--- a/Android.d8.mk
+++ b/Android.d8.mk
@@ -30,7 +30,7 @@
 $(D8_GEN): $(LOCAL_JS_D8_FILES) $(JS2C_PY)
 	@echo "Generating d8-js.cc"
 	@mkdir -p $(dir $@)
-	python $(SCRIPT) $@ D8 off $(LOCAL_JS_D8_FILES)
+	python $(SCRIPT) $@ D8 $(LOCAL_JS_D8_FILES)
 LOCAL_GENERATED_SOURCES += $(D8_GEN)
 
 LOCAL_CPP_EXTENSION := .cc
diff --git a/Android.libv8.mk b/Android.libv8.mk
index 41815ce..a4f8351 100644
--- a/Android.libv8.mk
+++ b/Android.libv8.mk
@@ -47,7 +47,7 @@
 $(GEN1): $(LOCAL_JS_LIBRARY_FILES) $(JS2C_PY)
 	@echo "Generating libraries.cc"
 	@mkdir -p $(dir $@)
-	python $(SCRIPT) $@ CORE off $(LOCAL_JS_LIBRARY_FILES)
+	python $(SCRIPT) $@ CORE $(LOCAL_JS_LIBRARY_FILES)
 V8_GENERATED_LIBRARIES := $(generated_sources)/libraries.cc
 
 # Generate experimental-libraries.cc
@@ -56,7 +56,7 @@
 $(GEN2): $(LOCAL_JS_EXPERIMENTAL_LIBRARY_FILES) $(JS2C_PY)
 	@echo "Generating experimental-libraries.cc"
 	@mkdir -p $(dir $@)
-	python $(SCRIPT) $@ EXPERIMENTAL off $(LOCAL_JS_EXPERIMENTAL_LIBRARY_FILES)
+	python $(SCRIPT) $@ EXPERIMENTAL $(LOCAL_JS_EXPERIMENTAL_LIBRARY_FILES)
 V8_GENERATED_LIBRARIES += $(generated_sources)/experimental-libraries.cc
 
 LOCAL_GENERATED_SOURCES += $(V8_GENERATED_LIBRARIES)
diff --git a/Android.mksnapshot.mk b/Android.mksnapshot.mk
index f5377a8..28e0b0c 100644
--- a/Android.mksnapshot.mk
+++ b/Android.mksnapshot.mk
@@ -54,7 +54,7 @@
 $(GEN3): $(LOCAL_JS_LIBRARY_FILES) $(JS2C_PY)
 	@echo "Generating libraries.cc"
 	@mkdir -p $(dir $@)
-	python $(SCRIPT) $@ CORE off $(LOCAL_JS_LIBRARY_FILES)
+	python $(SCRIPT) $@ CORE $(LOCAL_JS_LIBRARY_FILES)
 LOCAL_GENERATED_SOURCES := $(generated_sources)/libraries.cc
 
 # Generate experimental-libraries.cc
@@ -63,7 +63,7 @@
 $(GEN4): $(LOCAL_JS_EXPERIMENTAL_LIBRARY_FILES) $(JS2C_PY)
 	@echo "Generating experimental-libraries.cc"
 	@mkdir -p $(dir $@)
-	python $(SCRIPT) $@ EXPERIMENTAL off $(LOCAL_JS_EXPERIMENTAL_LIBRARY_FILES)
+	python $(SCRIPT) $@ EXPERIMENTAL $(LOCAL_JS_EXPERIMENTAL_LIBRARY_FILES)
 LOCAL_GENERATED_SOURCES += $(generated_sources)/experimental-libraries.cc
 
 LOCAL_CFLAGS := \
diff --git a/Android.v8common.mk b/Android.v8common.mk
index bf8b072..a8d9bb5 100644
--- a/Android.v8common.mk
+++ b/Android.v8common.mk
@@ -9,6 +9,8 @@
 	src/arguments.cc \
 	src/assembler.cc \
 	src/assert-scope.cc \
+	src/ast-numbering.cc \
+	src/ast-this-access-visitor.cc \
 	src/ast-value-factory.cc \
 	src/ast.cc \
 	src/background-parsing-task.cc \
@@ -16,6 +18,7 @@
 	src/base/bits.cc \
 	src/base/cpu.cc \
 	src/base/division-by-constant.cc \
+	src/base/functional.cc \
 	src/base/logging.cc \
 	src/base/once.cc \
 	src/base/platform/condition-variable.cc \
@@ -24,24 +27,33 @@
 	src/base/platform/time.cc \
 	src/base/sys-info.cc \
 	src/base/utils/random-number-generator.cc \
+	src/basic-block-profiler.cc \
 	src/bignum-dtoa.cc \
 	src/bignum.cc \
+	src/bit-vector.cc \
 	src/bootstrapper.cc \
 	src/builtins.cc \
 	src/cached-powers.cc \
+	src/char-predicates.cc \
 	src/checks.cc \
 	src/code-factory.cc \
 	src/code-stubs-hydrogen.cc \
 	src/code-stubs.cc \
 	src/codegen.cc \
 	src/compilation-cache.cc \
+	src/compilation-statistics.cc \
 	src/compiler.cc \
 	src/compiler/access-builder.cc \
 	src/compiler/ast-graph-builder.cc \
+	src/compiler/ast-loop-assignment-analyzer.cc \
+	src/compiler/basic-block-instrumentor.cc \
 	src/compiler/change-lowering.cc \
 	src/compiler/code-generator.cc \
+	src/compiler/common-node-cache.cc \
 	src/compiler/common-operator.cc \
+	src/compiler/common-operator-reducer.cc \
 	src/compiler/control-builders.cc \
+	src/compiler/control-reducer.cc \
 	src/compiler/gap-resolver.cc \
 	src/compiler/graph-builder.cc \
 	src/compiler/graph-reducer.cc \
@@ -55,19 +67,31 @@
 	src/compiler/js-generic-lowering.cc \
 	src/compiler/js-graph.cc \
 	src/compiler/js-inlining.cc \
+	src/compiler/js-intrinsic-builder.cc \
+	src/compiler/js-operator.cc \
 	src/compiler/js-typed-lowering.cc \
+	src/compiler/jump-threading.cc \
 	src/compiler/linkage.cc \
+	src/compiler/load-elimination.cc \
+	src/compiler/loop-analysis.cc \
 	src/compiler/machine-operator-reducer.cc \
 	src/compiler/machine-operator.cc \
 	src/compiler/machine-type.cc \
+	src/compiler/move-optimizer.cc \
 	src/compiler/node-cache.cc \
 	src/compiler/node.cc \
+	src/compiler/opcodes.cc \
 	src/compiler/operator.cc \
+	src/compiler/operator-properties.cc \
 	src/compiler/pipeline.cc \
+	src/compiler/pipeline-statistics.cc \
 	src/compiler/raw-machine-assembler.cc \
 	src/compiler/register-allocator.cc \
+	src/compiler/register-allocator-verifier.cc \
+	src/compiler/register-configuration.cc \
 	src/compiler/schedule.cc \
 	src/compiler/scheduler.cc \
+	src/compiler/select-lowering.cc \
 	src/compiler/simplified-lowering.cc \
 	src/compiler/simplified-operator-reducer.cc \
 	src/compiler/simplified-operator.cc \
@@ -75,11 +99,11 @@
 	src/compiler/typer.cc \
 	src/compiler/value-numbering-reducer.cc \
 	src/compiler/verifier.cc \
+	src/compiler/zone-pool.cc \
 	src/contexts.cc \
 	src/conversions.cc \
 	src/counters.cc \
 	src/cpu-profiler.cc \
-	src/data-flow.cc \
 	src/date.cc \
 	src/dateparser.cc \
 	src/debug.cc \
@@ -115,7 +139,6 @@
 	src/heap/objects-visiting.cc \
 	src/heap/spaces.cc \
 	src/heap/store-buffer.cc \
-	src/heap/sweeper-thread.cc \
 	src/hydrogen-bce.cc \
 	src/hydrogen-bch.cc \
 	src/hydrogen-canonicalize.cc \
@@ -155,6 +178,7 @@
 	src/interpreter-irregexp.cc \
 	src/isolate.cc \
 	src/jsregexp.cc \
+	src/layout-descriptor.cc \
 	src/libplatform/default-platform.cc \
 	src/libplatform/task-queue.cc \
 	src/libplatform/worker-thread.cc \
@@ -179,8 +203,34 @@
 	src/regexp-macro-assembler.cc \
 	src/regexp-stack.cc \
 	src/rewriter.cc \
+	src/runtime/runtime-api.cc \
+	src/runtime/runtime-array.cc \
+	src/runtime/runtime.cc \
+	src/runtime/runtime-classes.cc \
+	src/runtime/runtime-collections.cc \
+	src/runtime/runtime-compiler.cc \
+	src/runtime/runtime-date.cc \
+	src/runtime/runtime-debug.cc \
+	src/runtime/runtime-function.cc \
+	src/runtime/runtime-generator.cc \
+	src/runtime/runtime-i18n.cc \
+	src/runtime/runtime-internal.cc \
+	src/runtime/runtime-json.cc \
+	src/runtime/runtime-literals.cc \
+	src/runtime/runtime-liveedit.cc \
+	src/runtime/runtime-maths.cc \
+	src/runtime/runtime-numbers.cc \
+	src/runtime/runtime-object.cc \
+	src/runtime/runtime-observe.cc \
+	src/runtime/runtime-proxy.cc \
+	src/runtime/runtime-regexp.cc \
+	src/runtime/runtime-scopes.cc \
+	src/runtime/runtime-strings.cc \
+	src/runtime/runtime-symbol.cc \
+	src/runtime/runtime-test.cc \
+	src/runtime/runtime-typedarray.cc \
+	src/runtime/runtime-uri.cc \
 	src/runtime-profiler.cc \
-	src/runtime.cc \
 	src/safepoint-table.cc \
 	src/sampler.cc \
 	src/scanner-character-streams.cc \
@@ -190,6 +240,7 @@
 	src/serialize.cc \
 	src/snapshot-common.cc \
 	src/snapshot-source-sink.cc \
+	src/string-builder.cc \
 	src/string-search.cc \
 	src/string-stream.cc \
 	src/strtod.cc \
@@ -200,6 +251,7 @@
 	src/types.cc \
 	src/typing.cc \
 	src/unicode.cc \
+	src/unicode-decoder.cc \
 	src/utils.cc \
 	src/v8.cc \
 	src/v8threads.cc \
@@ -208,7 +260,7 @@
 	src/zone.cc
 
 LOCAL_SRC_FILES += \
-	third_party/fdlibm/fdlibm.cc
+	src/third_party/fdlibm/fdlibm.cc
 
 v8_local_src_files_arm := \
 		src/arm/assembler-arm.cc \
@@ -271,6 +323,9 @@
 		src/ic/arm64/stub-cache-arm64.cc
 
 v8_local_src_files_mips := \
+		src/compiler/mips/code-generator-mips.cc \
+		src/compiler/mips/instruction-selector-mips.cc \
+		src/compiler/mips/linkage-mips.cc \
 		src/ic/mips/access-compiler-mips.cc\
 		src/ic/mips/handler-compiler-mips.cc \
 		src/ic/mips/ic-compiler-mips.cc \
@@ -296,6 +351,9 @@
 		src/mips/simulator-mips.cc
 
 v8_local_src_files_mips64 := \
+		src/compiler/mips64/code-generator-mips64.cc \
+		src/compiler/mips64/instruction-selector-mips64.cc \
+		src/compiler/mips64/linkage-mips64.cc \
 		src/ic/mips64/access-compiler-mips64.cc \
 		src/ic/mips64/handler-compiler-mips64.cc \
 		src/ic/mips64/ic-compiler-mips64.cc \
@@ -394,7 +452,7 @@
 	src/string.js \
 	src/array.js \
 	src/uri.js \
-	third_party/fdlibm/fdlibm.js \
+	src/third_party/fdlibm/fdlibm.js \
 	src/math.js \
 	src/apinatives.js \
 	src/date.js \
@@ -423,4 +481,10 @@
 	src/proxy.js \
 	src/harmony-string.js \
 	src/harmony-array.js \
-	src/harmony-classes.js
+	src/harmony-array-includes.js \
+	src/harmony-classes.js \
+	src/harmony-regexp.js \
+	src/harmony-templates.js \
+	src/harmony-tostring.js \
+	src/harmony-typedarray.js
+
diff --git a/BUILD.gn b/BUILD.gn
index 315c203..6534eea 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -2,9 +2,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+# Because standalone V8 builds are not supported, assume this is part of a
+# Chromium build.
+import("//build/module_args/v8.gni")
+
 # TODO(jochen): These will need to be user-settable to support standalone V8
 # builds.
-v8_compress_startup_data = "off"
 v8_deprecation_warnings = false
 v8_enable_disassembler = false
 v8_enable_gdbjit = false
@@ -15,7 +18,6 @@
 v8_object_print = false
 v8_postmortem_support = false
 v8_use_snapshot = true
-v8_use_external_startup_data = false
 v8_enable_extra_checks = is_debug
 v8_target_arch = cpu_arch
 v8_random_seed = "314159265"
@@ -95,11 +97,6 @@
       "V8_I18N_SUPPORT",
     ]
   }
-  if (v8_compress_startup_data == "bz2") {
-    defines += [
-      "COMPRESS_STARTUP_DATA_BZ2",
-    ]
-  }
   if (v8_enable_extra_checks == true) {
     defines += [
       "ENABLE_EXTRA_CHECKS",
@@ -182,7 +179,7 @@
     "src/array.js",
     "src/string.js",
     "src/uri.js",
-    "third_party/fdlibm/fdlibm.js",
+    "src/third_party/fdlibm/fdlibm.js",
     "src/math.js",
     "src/apinatives.js",
     "src/date.js",
@@ -216,7 +213,6 @@
   args = [
     rebase_path("$target_gen_dir/libraries.cc", root_build_dir),
     "CORE",
-    v8_compress_startup_data
   ] + rebase_path(sources, root_build_dir)
 
   if (v8_use_external_startup_data) {
@@ -243,7 +239,12 @@
     "src/generator.js",
     "src/harmony-string.js",
     "src/harmony-array.js",
+    "src/harmony-array-includes.js",
+    "src/harmony-typedarray.js",
     "src/harmony-classes.js",
+    "src/harmony-tostring.js",
+    "src/harmony-templates.js",
+    "src/harmony-regexp.js"
   ]
 
   outputs = [
@@ -253,7 +254,6 @@
   args = [
     rebase_path("$target_gen_dir/experimental-libraries.cc", root_build_dir),
     "EXPERIMENTAL",
-    v8_compress_startup_data
   ] + rebase_path(sources, root_build_dir)
 
   if (v8_use_external_startup_data) {
@@ -280,7 +280,7 @@
     ]
 
     outputs = [
-      "$root_gen_dir/natives_blob.bin"
+      "$root_out_dir/natives_blob.bin"
     ]
 
     script = "tools/concatenate-files.py"
@@ -333,10 +333,10 @@
   }
 
   if (v8_use_external_startup_data) {
-    outputs += [ "$root_gen_dir/snapshot_blob.bin" ]
+    outputs += [ "$root_out_dir/snapshot_blob.bin" ]
     args += [
       "--startup_blob",
-      rebase_path("$root_gen_dir/snapshot_blob.bin", root_build_dir)
+      rebase_path("$root_out_dir/snapshot_blob.bin", root_build_dir)
     ]
   }
 }
@@ -359,7 +359,6 @@
     "$target_gen_dir/libraries.cc",
     "$target_gen_dir/experimental-libraries.cc",
     "src/snapshot-empty.cc",
-    "src/snapshot-common.cc",
   ]
 
   configs -= [ "//build/config/compiler:chromium_code" ]
@@ -381,7 +380,6 @@
     "$target_gen_dir/libraries.cc",
     "$target_gen_dir/experimental-libraries.cc",
     "$target_gen_dir/snapshot.cc",
-    "src/snapshot-common.cc",
   ]
 
   configs -= [ "//build/config/compiler:chromium_code" ]
@@ -432,6 +430,10 @@
     "src/assembler.h",
     "src/assert-scope.h",
     "src/assert-scope.cc",
+    "src/ast-numbering.cc",
+    "src/ast-numbering.h",
+    "src/ast-this-access-visitor.cc",
+    "src/ast-this-access-visitor.h",
     "src/ast-value-factory.cc",
     "src/ast-value-factory.h",
     "src/ast.cc",
@@ -440,10 +442,14 @@
     "src/background-parsing-task.h",
     "src/bailout-reason.cc",
     "src/bailout-reason.h",
+    "src/basic-block-profiler.cc",
+    "src/basic-block-profiler.h",
     "src/bignum-dtoa.cc",
     "src/bignum-dtoa.h",
     "src/bignum.cc",
     "src/bignum.h",
+    "src/bit-vector.cc",
+    "src/bit-vector.h",
     "src/bootstrapper.cc",
     "src/bootstrapper.h",
     "src/builtins.cc",
@@ -451,6 +457,7 @@
     "src/bytecodes-irregexp.h",
     "src/cached-powers.cc",
     "src/cached-powers.h",
+    "src/char-predicates.cc",
     "src/char-predicates-inl.h",
     "src/char-predicates.h",
     "src/checks.cc",
@@ -467,28 +474,37 @@
     "src/codegen.h",
     "src/compilation-cache.cc",
     "src/compilation-cache.h",
+    "src/compilation-statistics.cc",
+    "src/compilation-statistics.h",
     "src/compiler/access-builder.cc",
     "src/compiler/access-builder.h",
     "src/compiler/ast-graph-builder.cc",
     "src/compiler/ast-graph-builder.h",
+    "src/compiler/ast-loop-assignment-analyzer.cc",
+    "src/compiler/ast-loop-assignment-analyzer.h",
+    "src/compiler/basic-block-instrumentor.cc",
+    "src/compiler/basic-block-instrumentor.h",
     "src/compiler/change-lowering.cc",
     "src/compiler/change-lowering.h",
     "src/compiler/code-generator-impl.h",
     "src/compiler/code-generator.cc",
     "src/compiler/code-generator.h",
+    "src/compiler/common-node-cache.cc",
     "src/compiler/common-node-cache.h",
+    "src/compiler/common-operator-reducer.cc",
+    "src/compiler/common-operator-reducer.h",
     "src/compiler/common-operator.cc",
     "src/compiler/common-operator.h",
     "src/compiler/control-builders.cc",
     "src/compiler/control-builders.h",
+    "src/compiler/control-equivalence.h",
+    "src/compiler/control-reducer.cc",
+    "src/compiler/control-reducer.h",
+    "src/compiler/diamond.h",
     "src/compiler/frame.h",
     "src/compiler/gap-resolver.cc",
     "src/compiler/gap-resolver.h",
-    "src/compiler/generic-algorithm-inl.h",
     "src/compiler/generic-algorithm.h",
-    "src/compiler/generic-graph.h",
-    "src/compiler/generic-node-inl.h",
-    "src/compiler/generic-node.h",
     "src/compiler/graph-builder.cc",
     "src/compiler/graph-builder.h",
     "src/compiler/graph-inl.h",
@@ -516,18 +532,29 @@
     "src/compiler/js-graph.h",
     "src/compiler/js-inlining.cc",
     "src/compiler/js-inlining.h",
+    "src/compiler/js-intrinsic-builder.cc",
+    "src/compiler/js-intrinsic-builder.h",
+    "src/compiler/js-operator.cc",
     "src/compiler/js-operator.h",
     "src/compiler/js-typed-lowering.cc",
     "src/compiler/js-typed-lowering.h",
+    "src/compiler/jump-threading.cc",
+    "src/compiler/jump-threading.h",
     "src/compiler/linkage-impl.h",
     "src/compiler/linkage.cc",
     "src/compiler/linkage.h",
+    "src/compiler/load-elimination.cc",
+    "src/compiler/load-elimination.h",
+    "src/compiler/loop-analysis.cc",
+    "src/compiler/loop-analysis.h",
     "src/compiler/machine-operator-reducer.cc",
     "src/compiler/machine-operator-reducer.h",
     "src/compiler/machine-operator.cc",
     "src/compiler/machine-operator.h",
     "src/compiler/machine-type.cc",
     "src/compiler/machine-type.h",
+    "src/compiler/move-optimizer.cc",
+    "src/compiler/move-optimizer.h",
     "src/compiler/node-aux-data-inl.h",
     "src/compiler/node-aux-data.h",
     "src/compiler/node-cache.cc",
@@ -537,23 +564,31 @@
     "src/compiler/node-properties.h",
     "src/compiler/node.cc",
     "src/compiler/node.h",
+    "src/compiler/opcodes.cc",
     "src/compiler/opcodes.h",
-    "src/compiler/operator-properties-inl.h",
+    "src/compiler/operator-properties.cc",
     "src/compiler/operator-properties.h",
     "src/compiler/operator.cc",
     "src/compiler/operator.h",
-    "src/compiler/phi-reducer.h",
     "src/compiler/pipeline.cc",
     "src/compiler/pipeline.h",
+    "src/compiler/pipeline-statistics.cc",
+    "src/compiler/pipeline-statistics.h",
     "src/compiler/raw-machine-assembler.cc",
     "src/compiler/raw-machine-assembler.h",
     "src/compiler/register-allocator.cc",
     "src/compiler/register-allocator.h",
+    "src/compiler/register-allocator-verifier.cc",
+    "src/compiler/register-allocator-verifier.h",
+    "src/compiler/register-configuration.cc",
+    "src/compiler/register-configuration.h",
     "src/compiler/representation-change.h",
     "src/compiler/schedule.cc",
     "src/compiler/schedule.h",
     "src/compiler/scheduler.cc",
     "src/compiler/scheduler.h",
+    "src/compiler/select-lowering.cc",
+    "src/compiler/select-lowering.h",
     "src/compiler/simplified-lowering.cc",
     "src/compiler/simplified-lowering.h",
     "src/compiler/simplified-operator-reducer.cc",
@@ -568,6 +603,8 @@
     "src/compiler/value-numbering-reducer.h",
     "src/compiler/verifier.cc",
     "src/compiler/verifier.h",
+    "src/compiler/zone-pool.cc",
+    "src/compiler/zone-pool.h",
     "src/compiler.cc",
     "src/compiler.h",
     "src/contexts.cc",
@@ -580,8 +617,6 @@
     "src/cpu-profiler-inl.h",
     "src/cpu-profiler.cc",
     "src/cpu-profiler.h",
-    "src/data-flow.cc",
-    "src/data-flow.h",
     "src/date.cc",
     "src/date.h",
     "src/dateparser-inl.h",
@@ -620,7 +655,6 @@
     "src/factory.h",
     "src/fast-dtoa.cc",
     "src/fast-dtoa.h",
-    "src/feedback-slots.h",
     "src/field-index.h",
     "src/field-index-inl.h",
     "src/fixed-dtoa.cc",
@@ -670,8 +704,6 @@
     "src/heap/store-buffer-inl.h",
     "src/heap/store-buffer.cc",
     "src/heap/store-buffer.h",
-    "src/heap/sweeper-thread.h",
-    "src/heap/sweeper-thread.cc",
     "src/hydrogen-alias-analysis.h",
     "src/hydrogen-bce.cc",
     "src/hydrogen-bce.h",
@@ -756,6 +788,9 @@
     "src/jsregexp-inl.h",
     "src/jsregexp.cc",
     "src/jsregexp.h",
+    "src/layout-descriptor-inl.h",
+    "src/layout-descriptor.cc",
+    "src/layout-descriptor.h",
     "src/list-inl.h",
     "src/list.h",
     "src/lithium-allocator-inl.h",
@@ -820,8 +855,35 @@
     "src/rewriter.h",
     "src/runtime-profiler.cc",
     "src/runtime-profiler.h",
-    "src/runtime.cc",
-    "src/runtime.h",
+    "src/runtime/runtime-api.cc",
+    "src/runtime/runtime-array.cc",
+    "src/runtime/runtime-classes.cc",
+    "src/runtime/runtime-collections.cc",
+    "src/runtime/runtime-compiler.cc",
+    "src/runtime/runtime-date.cc",
+    "src/runtime/runtime-debug.cc",
+    "src/runtime/runtime-function.cc",
+    "src/runtime/runtime-generator.cc",
+    "src/runtime/runtime-i18n.cc",
+    "src/runtime/runtime-internal.cc",
+    "src/runtime/runtime-json.cc",
+    "src/runtime/runtime-literals.cc",
+    "src/runtime/runtime-liveedit.cc",
+    "src/runtime/runtime-maths.cc",
+    "src/runtime/runtime-numbers.cc",
+    "src/runtime/runtime-object.cc",
+    "src/runtime/runtime-observe.cc",
+    "src/runtime/runtime-proxy.cc",
+    "src/runtime/runtime-regexp.cc",
+    "src/runtime/runtime-scopes.cc",
+    "src/runtime/runtime-strings.cc",
+    "src/runtime/runtime-symbol.cc",
+    "src/runtime/runtime-test.cc",
+    "src/runtime/runtime-typedarray.cc",
+    "src/runtime/runtime-uri.cc",
+    "src/runtime/runtime-utils.h",
+    "src/runtime/runtime.cc",
+    "src/runtime/runtime.h",
     "src/safepoint-table.cc",
     "src/safepoint-table.h",
     "src/sampler.cc",
@@ -838,9 +900,12 @@
     "src/serialize.h",
     "src/small-pointer-list.h",
     "src/smart-pointers.h",
+    "src/snapshot-common.cc",
     "src/snapshot-source-sink.cc",
     "src/snapshot-source-sink.h",
     "src/snapshot.h",
+    "src/string-builder.cc",
+    "src/string-builder.h",
     "src/string-search.cc",
     "src/string-search.h",
     "src/string-stream.cc",
@@ -867,8 +932,9 @@
     "src/unicode-inl.h",
     "src/unicode.cc",
     "src/unicode.h",
+    "src/unicode-decoder.cc",
+    "src/unicode-decoder.h",
     "src/unique.h",
-    "src/uri.h",
     "src/utils-inl.h",
     "src/utils.cc",
     "src/utils.h",
@@ -886,8 +952,8 @@
     "src/zone-inl.h",
     "src/zone.cc",
     "src/zone.h",
-    "third_party/fdlibm/fdlibm.cc",
-    "third_party/fdlibm/fdlibm.h",
+    "src/third_party/fdlibm/fdlibm.cc",
+    "src/third_party/fdlibm/fdlibm.h",
   ]
 
   if (v8_target_arch == "x86") {
@@ -922,6 +988,8 @@
       "src/compiler/ia32/instruction-codes-ia32.h",
       "src/compiler/ia32/instruction-selector-ia32.cc",
       "src/compiler/ia32/linkage-ia32.cc",
+      "src/ic/ia32/access-compiler-ia32.cc",
+      "src/ic/ia32/handler-compiler-ia32.cc",
       "src/ic/ia32/ic-ia32.cc",
       "src/ic/ia32/ic-compiler-ia32.cc",
       "src/ic/ia32/stub-cache-ia32.cc",
@@ -1090,6 +1158,10 @@
       "src/mips/regexp-macro-assembler-mips.cc",
       "src/mips/regexp-macro-assembler-mips.h",
       "src/mips/simulator-mips.cc",
+      "src/compiler/mips/code-generator-mips.cc",
+      "src/compiler/mips/instruction-codes-mips.h",
+      "src/compiler/mips/instruction-selector-mips.cc",
+      "src/compiler/mips/linkage-mips.cc",
       "src/ic/mips/access-compiler-mips.cc",
       "src/ic/mips/handler-compiler-mips.cc",
       "src/ic/mips/ic-mips.cc",
@@ -1151,11 +1223,6 @@
     # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
     cflags = [ "/wd4267" ]
   }
-  if (is_linux) {
-    if (v8_compress_startup_data == "bz2") {
-      libs += [ "bz2" ]
-    }
-  }
 
   if (v8_enable_i18n_support) {
     deps += [ "//third_party/icu" ]
@@ -1199,6 +1266,9 @@
     "src/base/division-by-constant.cc",
     "src/base/division-by-constant.h",
     "src/base/flags.h",
+    "src/base/functional.cc",
+    "src/base/functional.h",
+    "src/base/iterator.h",
     "src/base/lazy-instance.h",
     "src/base/logging.cc",
     "src/base/logging.h",
@@ -1270,8 +1340,6 @@
     sources += [
       "src/base/platform/platform-win32.cc",
       "src/base/win32-headers.h",
-      "src/base/win32-math.cc",
-      "src/base/win32-math.h",
     ]
 
     defines += [ "_CRT_RAND_S" ]  # for rand_s()
@@ -1327,11 +1395,8 @@
       ":v8_base",
       ":v8_libplatform",
       ":v8_nosnapshot",
+      "//build/config/sanitizers:deps",
     ]
-
-    if (v8_compress_startup_data == "bz2") {
-      libs = [ "bz2" ]
-    }
   }
 }
 
@@ -1346,7 +1411,7 @@
     "src/v8dll-main.cc",
   ]
 
-  if (v8_use_external_startup_data) {
+  if (v8_use_snapshot && v8_use_external_startup_data) {
     deps = [
       ":v8_base",
       ":v8_external_snapshot",
@@ -1357,6 +1422,7 @@
       ":v8_snapshot",
     ]
   } else {
+    assert(!v8_use_external_startup_data)
     deps = [
       ":v8_base",
       ":v8_nosnapshot",
@@ -1378,7 +1444,7 @@
 } else {
 
 group("v8") {
-  if (v8_use_external_startup_data) {
+  if (v8_use_snapshot && v8_use_external_startup_data) {
     deps = [
       ":v8_base",
       ":v8_external_snapshot",
@@ -1389,6 +1455,7 @@
       ":v8_snapshot",
     ]
   } else {
+    assert(!v8_use_external_startup_data)
     deps = [
       ":v8_base",
       ":v8_nosnapshot",
diff --git a/ChangeLog b/ChangeLog
index d787965..d42a2f1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,856 @@
+2015-01-07: Version 3.32.3
+
+        Performance and stability improvements on all platforms.
+
+
+2015-01-07: Version 3.32.2
+
+        Performance and stability improvements on all platforms.
+
+
+2015-01-07: Version 3.32.1
+
+        [turbofan] Don't crash when typing load from a Uint8ClampedArray
+        (Chromium issue 446156).
+
+        [turbofan] Truncation of Bit/Word8/16 to Word32 is a no-op (Chromium
+        issue 445859).
+
+        [x64] Rearrange code for OOB integer loads (Chromium issue 445858).
+
+        Fix %NeverOptimizeFunction() intrinsic (Chromium issue 445732).
+
+        [turbofan] Fix invalid bounds check with overflowing offset (Chromium
+        issue 445267).
+
+        [turbofan] Raise max virtual registers and call parameter limit (issue
+        3786).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-23: Version 3.31.74
+
+        [turbofan] Turn DCHECK for fixed slot index into a CHECK (Chromium issue
+        444681).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-23: Version 3.31.73
+
+        [turbofan] Fix missing ChangeUint32ToUint64 in lowering of LoadBuffer
+        (Chromium issue 444695).
+
+        Enable the embedder to specify what kind of context was disposed.
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-22: Version 3.31.72
+
+        [turbofan] Correctify lowering of Uint8ClampedArray buffer access
+        (Chromium issue 444508).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-20: Version 3.31.71
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-20: Version 3.31.70
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-20: Version 3.31.69
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-19: Version 3.31.68
+
+        [turbofan] Fix unsafe out-of-bounds check for checked loads/stores
+        (Chromium issue 443744).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-19: Version 3.31.67
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-19: Version 3.31.66
+
+        Ship ES6 template literals (issue 3230).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-18: Version 3.31.65
+
+        ES6 template literals should not use legacy octal strings (issue 3736).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-18: Version 3.31.64
+
+        Fixed -fsanitize=float-cast-overflow problems (issue 3773).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-18: Version 3.31.63
+
+        ES6 computed property names (issue 3754).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-17: Version 3.31.62
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-17: Version 3.31.61
+
+        ES6: Update unscopables to match spec (issue 3632).
+
+        ES6 computed property names (issue 3754).
+
+        More -fsanitize=vptr fixes (Chromium issue 441099).
+
+        [turbofan] Cache conversions inserted during typed lowering (issue
+        3763).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-16: Version 3.31.60
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-16: Version 3.31.59
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-16: Version 3.31.58
+
+        Ship ES6 classes (issue 3330).
+
+        ES6 computed property names (issue 3754).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-12: Version 3.31.57
+
+        Consistently use only one of virtual/OVERRIDE/FINAL (issue 3753).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-12: Version 3.31.56
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-12: Version 3.31.55
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-11: Version 3.31.54
+
+        Implement Array.from() (issue 3336).
+
+        move v8_use_external_startup_data to standalone.gypi (Chromium issue
+        421063).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-11: Version 3.31.53
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-11: Version 3.31.52
+
+        Ship ES6 block scoping (issue 2198).
+
+        Optimize Object.seal and Object.preventExtensions (issue 3662, Chromium
+        issue 115960).
+
+        Add Array.prototype.includes (issue 3575).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-10: Version 3.31.51
+
+        [x64] Fix optimization for certain checked load/stores (Chromium issue
+        439743).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-09: Version 3.31.50
+
+        Temporarily restore make dependencies.
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-09: Version 3.31.49
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-09: Version 3.31.48
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-09: Version 3.31.47
+
+        Temporarily restore make dependencies.
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-08: Version 3.31.46
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-08: Version 3.31.45
+
+        Update all DEPS to match chromium's DEPS at edb488e.
+
+        Turn on DCHECKs and other debugging code if dcheck_always_on is 1 (issue
+        3731).
+
+        Optimize GetPrototype.
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-05: Version 3.31.44
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-04: Version 3.31.43
+
+        ES6 template literals: Fix issue with template after rbrace (issue
+        3734).
+
+        Stage ES6 template literals (issue 3230).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-04: Version 3.31.42
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-04: Version 3.31.41
+
+        Simplify template literal raw string creation (issue 3710).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-03: Version 3.31.40
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-03: Version 3.31.39
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-03: Version 3.31.38
+
+        Stage ES6 classes and object literal extensions (issue 3330).
+
+        Fixed environment handling for LFlooringDivI on ARM (Chromium issue
+        437765).
+
+        Add GetIdentityHash to v8::Name object API (Chromium issue 437416).
+
+        Set V8_CC_GNU or V8_CC_MSVC for clang in gcc / cl mode (Chromium issue
+        82385).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-02: Version 3.31.37
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-02: Version 3.31.36
+
+        Set V8_CC_GNU or V8_CC_MSVC for clang in gcc / cl mode (Chromium issue
+        82385).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-02: Version 3.31.35
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-01: Version 3.31.34
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-01: Version 3.31.33
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-01: Version 3.31.32
+
+        Performance and stability improvements on all platforms.
+
+
+2014-12-01: Version 3.31.31
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-29: Version 3.31.30
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-28: Version 3.31.29
+
+        Stage @@toStringTag (--harmony-tostring).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-28: Version 3.31.28
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-28: Version 3.31.27
+
+        Ship harmony-strings.
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-28: Version 3.31.26
+
+        Abort optimization in corner case (Chromium issue 436893).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-26: Version 3.31.25
+
+        Stage ES6 block scoping (issue 2198).
+
+        Introduce legacy const slots in correct context (Chromium issue 410030).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-26: Version 3.31.24
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-25: Version 3.31.23
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-25: Version 3.31.22
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-24: Version 3.31.21
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-24: Version 3.31.20
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-22: Version 3.31.19
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-21: Version 3.31.18
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-21: Version 3.31.17
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-21: Version 3.31.16
+
+        Cache template literal callSiteObj (issue 3230).
+
+        Rename String.prototype.contains to 'includes'.
+
+        Reserve code range block for evacuation (Chromium issue 430118).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-20: Version 3.31.15
+
+        Rename String.prototype.contains to 'includes'.
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-19: Version 3.31.14
+
+        Remove Weak{Map,Set}.prototype.clear.
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-19: Version 3.31.13
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-19: Version 3.31.12
+
+        Classes: Expand test to cover strict runtime behavior (issue 3330).
+
+        v8::String::Concat must not throw (Chromium issue 420240).
+
+        Fix disabling all break points from within the debug event callback
+        (Chromium issue 432493).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-18: Version 3.31.11
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-17: Version 3.31.10
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-17: Version 3.31.9
+
+        Expose internal properties of map/set iterators via mirrors.
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-17: Version 3.31.8
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-15: Version 3.31.7
+
+        Classes: Add support for stepping through default constructors (issue
+        3674).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-14: Version 3.31.6
+
+        Fix desugaring of let bindings in for loops to handle continue properly
+        (issue 3683).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-14: Version 3.31.5
+
+        Classes: Implement correct name binding (issue 3330).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-14: Version 3.31.4
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-14: Version 3.31.3
+
+        Classes: Cleanup default constructor flag.
+
+        Soft fail for invalid cache data.
+
+        Implement .of() on typed arrays (issue 3578).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-13: Version 3.31.2
+
+        MIPS: Leaving a generator via an exception causes it to close (issue
+        3096).
+
+        MIPS: ES6: Add support for super in object literals (issue 3571).
+
+        Increase the target new space size to the max new space size (issue
+        3626).
+
+        Leaving a generator via an exception causes it to close (issue 3096).
+
+        Correctly compute line numbers in functions from the function
+        constructor (Chromium issue 109362).
+
+        Rename v8::Exception::GetMessage to CreateMessage.
+
+        Classes: Add support for arguments in default constructor (issue 3672).
+
+        ES6: Add support for super in object literals (issue 3571).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-12: Version 3.31.1
+
+        Fix has_constant_parameter_count() confusion in LReturn (Chromium issue
+        431602).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-05: Version 3.30.33
+
+        `1..isPrototypeOf.call(null)` should return false, not throw TypeError
+        (issue 3483).
+
+        Refactor ObjectGetOwnPropertyKeys to accept bitmask rather than boolean
+        (issue 3549).
+
+        Add debug mirror support for ES6 Map/Set iterators (Chromium issue
+        427868).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-04: Version 3.30.30
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-02: Version 3.30.27
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-02: Version 3.30.26
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-01: Version 3.30.25
+
+        Performance and stability improvements on all platforms.
+
+
+2014-11-01: Version 3.30.24
+
+        Ensure we don't try to inline raw access to indexed interceptor
+        receivers (Chromium issue 419220).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-31: Version 3.30.23
+
+        Introduce v8::Exception::GetMessage to find location of an error object
+        (Chromium issue 427954).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-30: Version 3.30.22
+
+        MIPS: Classes: Add super support in methods and accessors (issue 3330).
+
+        Classes: Add super support in methods and accessors (issue 3330).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-29: Version 3.30.21
+
+        MIPS: Classes: Add basic support for properties (issue 3330).
+
+        Classes: Add more tests for prototype edge cases (Chromium issue 3655).
+
+        Classes: Add test for method prototype (issue 3330).
+
+        Get stack trace for uncaught exceptions/promise rejections from the
+        simple stack when available.
+
+        Classes: Add basic support for properties (issue 3330).
+
+        Allow duplicate property names in classes (issue 3570).
+
+        Windows: use SystemTimeToTzSpecificLocalTime instead of localtime_s
+        (Chromium issue 417640).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-28: Version 3.30.20
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-27: Version 3.30.19
+
+        Check string literals with escapes in PreParserTraits::GetSymbol()
+        (issue 3606).
+
+        only define ARRAYSIZE_UNSAFE for NaCl builds (Chromium issue 405225).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-24: Version 3.30.18
+
+        Narrow cases where Sparse/Smart versions of Array methods are used
+        (issues 2615, 3612, 3621).
+
+        Shrink new space in idle notification (Chromium issue 424423).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-23: Version 3.30.17
+
+        ARM64: Fix stack manipulation (Chromium issue 425585).
+
+        Speed up creation of Objects whose prototype has dictionary elements
+        (Chromium issue 422754).
+
+        Enable libstdc++ debug mode in debug builds (issue 3638).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-22: Version 3.30.16
+
+        Remove v8stdint.h, it doesn't serve a purpose anymore.
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-21: Version 3.30.15
+
+        Avoid the Marsaglia effect in 3D (Chromium issue 423311).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-20: Version 3.30.14
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-17: Version 3.30.13
+
+        Don't expose Array.prototype.values as it breaks webcompat (Chromium
+        issue 409858).
+
+        Fix break location calculation (Chromium issue 419663).
+
+        Enable libstdc++ debug mode in debug builds (issue 3638).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-17: Version 3.30.12
+
+        Implement .forEach() on typed arrays (issue 3578).
+
+        Introduce v8::Exception::GetStackTrace API method.
+
+        Remove SmartMove, bringing Array methods further into spec compliance
+        (issue 2615).
+
+        Convert argument toObject() in Object.getOwnPropertyNames/Descriptors
+        (issue 3443).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-15: Version 3.30.11
+
+        Array.prototype.{every, filter, find, findIndex, forEach, map, some}:
+        Use fresh primitive wrapper for calls (issue 3536).
+
+        Correctly expand literal buffer for surrogate pairs (Chromium issue
+        423212).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-15: Version 3.30.10
+
+        Squeeze the layout of various AST node types (Chromium issue 417697).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-14: Version 3.30.9
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-13: Version 3.30.8
+
+        AST nodes have at most one bailout/typefeedback ID now, saving lots of
+        memory (Chromium issue 417697).
+
+        Allow identifier code points from supplementary multilingual planes
+        (issue 3617).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-10: Version 3.30.7
+
+        Fix computation of UTC time from local time at DST change points (issue
+        3116, Chromium issues 415424, 417640).
+
+        Convert `obj` ToObject in Object.keys() (issue 3587).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-09: Version 3.30.6
+
+        Update unicode to 7.0.0 (issue 2892).
+
+        Classes: Add support for toString (issue 3330).
+
+        Don't enable WPO on Win64 and require Server 2003 / x64 for win64
+        (Chromium issue 421363).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-08: Version 3.30.5
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-08: Version 3.30.4
+
+        This uses a runtime function to set up the the constructor and its
+        prototype (issue 3330).
+
+        Remove PersistentBase::ClearAndLeak.
+
+        Squeeze the layout of variable proxy nodes (Chromium issue 417697).
+
+        Add MonotonicallyIncreasingTime to V8 Platform (Chromium issue 417668).
+
+        Fix representation of HLoadRoot (Chromium issue 419036).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-03: Version 3.30.3
+
+        Removed the Isolate* field from literal nodes (Chromium issue 417697).
+
+        Squeeze the layout of expression nodes a bit (Chromium issue 417697).
+
+        Merged FeedbackSlotInterface into AstNode, removing the need for a 2nd
+        vtable (Chromium issue 417697).
+
+        Extend CPU profiler with mapping ticks to source lines.
+
+        Remove support for parallel sweeping.
+
+        Introduce v8::Object::GetIsolate().
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-02: Version 3.30.2
+
+        Fix Hydrogen's BuildStore() (Chromium issue 417508).
+
+        Move unit tests to test/unittests (issue 3489).
+
+        Changes to ALLOW_UNUSED to match upcoming changes to the Chromium trunk:
+        * Eliminate usage of ALLOW_UNUSED to define COMPILE_ASSERT and just use
+        static_assert() in all cases now that all platforms build with C++11. *
+        Convert remaining uses of ALLOW_UNUSED to ALLOW_UNUSED_TYPE to match how
+        Chromium will be splitting this functionality.  (In Chromium we'll have
+        both   ALLOW_UNUSED_TYPE and ALLOW_UNUSED_LOCAL, which have different
+        syntax to   enable us to use these with MSVC.) (Chromium issue 81439).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-10-01: Version 3.30.1
+
+        Introduce PromiseRejectCallback (issue 3093).
+
+        ES6: Implement object literal property shorthand (issue 3584).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-09-30: Version 3.29.93
+
+        Add a getter for the address and size of the code range to the pulic API
+        (issue 3598).
+
+        Convert `obj` ToObject in Object.keys() (issue 3587).
+
+        Performance and stability improvements on all platforms.
+
+
+2014-09-29: Version 3.29.92
+
+        Performance and stability improvements on all platforms.
+
+
+2014-09-26: Version 3.29.91
+
+        Performance and stability improvements on all platforms.
+
+
 2014-09-25: Version 3.29.88
 
         Performance and stability improvements on all platforms.
diff --git a/DEPS b/DEPS
index d4139c6..a81c7ec 100644
--- a/DEPS
+++ b/DEPS
@@ -3,44 +3,32 @@
 # all paths in here must match this assumption.
 
 vars = {
-  "chromium_git": "https://chromium.googlesource.com",
-
-  "chromium_trunk": "https://src.chromium.org/svn/trunk",
-
-  "buildtools_revision": "fb782d4369d5ae04f17a2fceef7de5a63e50f07b",
+  "git_url": "https://chromium.googlesource.com",
 }
 
 deps = {
-  # Remember to keep the revision in sync with the Makefile.
   "v8/build/gyp":
-    "http://gyp.googlecode.com/svn/trunk@1831",
-
+    Var("git_url") + "/external/gyp.git" + "@" + "fe00999dfaee449d3465a9316778434884da4fa7",  # from svn revision 2010
   "v8/third_party/icu":
-    Var("chromium_trunk") + "/deps/third_party/icu52@277999",
-
+    Var("git_url") + "/chromium/deps/icu.git" + "@" + "51c1a4ce5f362676aa1f1cfdb5b7e52edabfa5aa",
   "v8/buildtools":
-    "https://chromium.googlesource.com/chromium/buildtools.git@" +
-    Var("buildtools_revision"),
-
+    Var("git_url") + "/chromium/buildtools.git" + "@" + "23a4e2f545c7b6340d7e5a2b74801941b0a86535",
   "v8/testing/gtest":
-    "http://googletest.googlecode.com/svn/trunk@692",
-
+    Var("git_url") + "/external/googletest.git" + "@" + "8245545b6dc9c4703e6496d1efd19e975ad2b038",  # from svn revision 700
   "v8/testing/gmock":
-    "http://googlemock.googlecode.com/svn/trunk@485",
+    Var("git_url") + "/external/googlemock.git" + "@" + "29763965ab52f24565299976b936d1265cb6a271",  # from svn revision 501
+  "v8/tools/clang":
+    Var("git_url") + "/chromium/src/tools/clang.git" + "@" + "c945be21f6485fa177b43814f910b76cce921653",
 }
 
 deps_os = {
   "android": {
     "v8/third_party/android_tools":
-      Var("chromium_git") + "/android_tools.git" + "@" +
-          "31869996507de16812bb53a3d0aaa15cd6194c16",
+      Var("git_url") + "/android_tools.git" + "@" + "4f723e2a5fa5b7b8a198072ac19b92344be2b271",
   },
   "win": {
     "v8/third_party/cygwin":
-      Var("chromium_trunk") + "/deps/third_party/cygwin@66844",
-
-    "v8/third_party/python_26":
-      Var("chromium_trunk") + "/tools/third_party/python_26@89111",
+      Var("git_url") + "/chromium/deps/cygwin.git" + "@" + "c89e446b273697fadf3a10ff1007a97c0b7de6df",
   }
 }
 
@@ -93,6 +81,13 @@
     ],
   },
   {
+    # Pull clang if needed or requested via GYP_DEFINES.
+    # Note: On Win, this should run after win_toolchain, as it may use it.
+    'name': 'clang',
+    'pattern': '.',
+    'action': ['python', 'v8/tools/clang/scripts/update.py', '--if-needed'],
+  },
+  {
     # A change to a .gyp, .gypi, or to GYP itself should run the generator.
     "pattern": ".",
     "action": ["python", "v8/build/gyp_v8"],
diff --git a/Makefile b/Makefile
index 2fbe1ba..606b5d7 100644
--- a/Makefile
+++ b/Makefile
@@ -64,6 +64,10 @@
 ifeq ($(verifyheap), on)
   GYPFLAGS += -Dv8_enable_verify_heap=1
 endif
+# tracemaps=on
+ifeq ($(tracemaps), on)
+  GYPFLAGS += -Dv8_trace_maps=1
+endif
 # backtrace=off
 ifeq ($(backtrace), off)
   GYPFLAGS += -Dv8_enable_backtrace=0
@@ -78,6 +82,9 @@
 ifeq ($(snapshot), off)
   GYPFLAGS += -Dv8_use_snapshot='false'
 endif
+ifeq ($(snapshot), external)
+  GYPFLAGS += -Dv8_use_external_startup_data=1
+endif
 # extrachecks=on/off
 ifeq ($(extrachecks), on)
   GYPFLAGS += -Dv8_enable_extra_checks=1 -Dv8_enable_handle_zapping=1
@@ -140,10 +147,15 @@
 # asan=/path/to/clang++
 ifneq ($(strip $(asan)),)
   GYPFLAGS += -Dasan=1
+  export CC=$(dir $(asan))clang
   export CXX=$(asan)
   export CXX_host=$(asan)
   export LINK=$(asan)
-  export ASAN_SYMBOLIZER_PATH="$(dir $(asan))llvm-symbolizer"
+  export ASAN_SYMBOLIZER_PATH=$(dir $(asan))llvm-symbolizer
+  TESTFLAGS += --asan
+  ifeq ($(lsan), on)
+    GYPFLAGS += -Dlsan=1
+  endif
 endif
 
 # arm specific flags.
@@ -230,8 +242,8 @@
 
 # List of files that trigger Makefile regeneration:
 GYPFILES = build/all.gyp build/features.gypi build/standalone.gypi \
-           build/toolchain.gypi samples/samples.gyp src/compiler/compiler.gyp \
-           src/d8.gyp test/cctest/cctest.gyp tools/gyp/v8.gyp
+           build/toolchain.gypi samples/samples.gyp src/d8.gyp \
+           test/cctest/cctest.gyp test/unittests/unittests.gyp tools/gyp/v8.gyp
 
 # If vtunejit=on, the v8vtune.gyp will be appended.
 ifeq ($(vtunejit), on)
@@ -252,7 +264,7 @@
 ENVFILE = $(OUTDIR)/environment
 
 .PHONY: all check clean builddeps dependencies $(ENVFILE).new native \
-        qc quickcheck $(QUICKCHECKS) \
+        qc quickcheck $(QUICKCHECKS) turbocheck \
         $(addsuffix .quickcheck,$(MODES)) $(addsuffix .quickcheck,$(ARCHES)) \
         $(ARCHES) $(MODES) $(BUILDS) $(CHECKS) $(addsuffix .clean,$(ARCHES)) \
         $(addsuffix .check,$(MODES)) $(addsuffix .check,$(ARCHES)) \
@@ -381,6 +393,15 @@
 	    --arch-and-mode=$(FASTTESTMODES) $(TESTFLAGS) --quickcheck
 qc: quickcheck
 
+turbocheck: $(subst $(COMMA),$(SPACE),$(FASTCOMPILEMODES))
+	tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+	    --arch-and-mode=$(SUPERFASTTESTMODES) $(TESTFLAGS) \
+	    --quickcheck --variants=turbofan --download-data mozilla webkit
+	tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+	    --arch-and-mode=$(FASTTESTMODES) $(TESTFLAGS) \
+	    --quickcheck --variants=turbofan
+tc: turbocheck
+
 # Clean targets. You can clean each architecture individually, or everything.
 $(addsuffix .clean, $(ARCHES) $(ANDROID_ARCHES) $(NACL_ARCHES)):
 	rm -f $(OUTDIR)/Makefile.$(basename $@)*
@@ -472,7 +493,7 @@
 # "dependencies" includes also dependencies required for development.
 # Remember to keep these in sync with the DEPS file.
 builddeps:
-	svn checkout --force http://gyp.googlecode.com/svn/trunk build/gyp \
+	svn checkout --force https://gyp.googlecode.com/svn/trunk build/gyp \
 	    --revision 1831
 	if svn info third_party/icu 2>&1 | grep -q icu46 ; then \
 	  svn switch --force \
@@ -483,9 +504,9 @@
 	      https://src.chromium.org/chrome/trunk/deps/third_party/icu52 \
 	      third_party/icu --revision 277999 ; \
 	fi
-	svn checkout --force http://googletest.googlecode.com/svn/trunk \
+	svn checkout --force https://googletest.googlecode.com/svn/trunk \
 	    testing/gtest --revision 692
-	svn checkout --force http://googlemock.googlecode.com/svn/trunk \
+	svn checkout --force https://googlemock.googlecode.com/svn/trunk \
 	    testing/gmock --revision 485
 
 dependencies: builddeps
diff --git a/Makefile.android b/Makefile.android
index 8e200f1..2a36403 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -38,12 +38,10 @@
 ANDROID_NDK_HOST_ARCH ?= $(shell uname -m | sed -e 's/i[3456]86/x86/')
 ifeq ($(HOST_OS), linux)
   TOOLCHAIN_DIR = linux-$(ANDROID_NDK_HOST_ARCH)
+else ifeq ($(HOST_OS), mac)
+  TOOLCHAIN_DIR = darwin-$(ANDROID_NDK_HOST_ARCH)
 else
-  ifeq ($(HOST_OS), mac)
-    TOOLCHAIN_DIR = darwin-$(ANDROID_NDK_HOST_ARCH)
-  else
-    $(error Host platform "${HOST_OS}" is not supported)
-  endif
+  $(error Host platform "${HOST_OS}" is not supported)
 endif
 
 ifeq ($(ARCH), android_arm)
@@ -52,38 +50,29 @@
   TOOLCHAIN_ARCH = arm-linux-androideabi
   TOOLCHAIN_PREFIX = $(TOOLCHAIN_ARCH)
   TOOLCHAIN_VER = 4.8
+else ifeq ($(ARCH), android_arm64)
+  DEFINES  = target_arch=arm64 v8_target_arch=arm64 android_target_arch=arm64 android_target_platform=21
+  TOOLCHAIN_ARCH = aarch64-linux-android
+  TOOLCHAIN_PREFIX = $(TOOLCHAIN_ARCH)
+  TOOLCHAIN_VER = 4.9
+else ifeq ($(ARCH), android_mipsel)
+  DEFINES  = target_arch=mipsel v8_target_arch=mipsel android_target_platform=14
+  DEFINES += android_target_arch=mips mips_arch_variant=mips32r2
+  TOOLCHAIN_ARCH = mipsel-linux-android
+  TOOLCHAIN_PREFIX = $(TOOLCHAIN_ARCH)
+  TOOLCHAIN_VER = 4.8
+else ifeq ($(ARCH), android_ia32)
+  DEFINES = target_arch=ia32 v8_target_arch=ia32 android_target_arch=x86 android_target_platform=14
+  TOOLCHAIN_ARCH = x86
+  TOOLCHAIN_PREFIX = i686-linux-android
+  TOOLCHAIN_VER = 4.8
+else ifeq ($(ARCH), android_x87)
+  DEFINES = target_arch=x87 v8_target_arch=x87 android_target_arch=x86 android_target_platform=14
+  TOOLCHAIN_ARCH = x86
+  TOOLCHAIN_PREFIX = i686-linux-android
+  TOOLCHAIN_VER = 4.8
 else
-  ifeq ($(ARCH), android_arm64)
-    DEFINES  = target_arch=arm64 v8_target_arch=arm64 android_target_arch=arm64 android_target_platform=L
-    TOOLCHAIN_ARCH = aarch64-linux-android
-    TOOLCHAIN_PREFIX = $(TOOLCHAIN_ARCH)
-    TOOLCHAIN_VER = 4.9
-  else
-    ifeq ($(ARCH), android_mipsel)
-      DEFINES  = target_arch=mipsel v8_target_arch=mipsel android_target_platform=14
-      DEFINES += android_target_arch=mips mips_arch_variant=mips32r2
-      TOOLCHAIN_ARCH = mipsel-linux-android
-      TOOLCHAIN_PREFIX = $(TOOLCHAIN_ARCH)
-      TOOLCHAIN_VER = 4.8
-
-    else
-      ifeq ($(ARCH), android_ia32)
-        DEFINES = target_arch=ia32 v8_target_arch=ia32 android_target_arch=x86 android_target_platform=14
-        TOOLCHAIN_ARCH = x86
-        TOOLCHAIN_PREFIX = i686-linux-android
-        TOOLCHAIN_VER = 4.8
-      else
-        ifeq ($(ARCH), android_x87)
-          DEFINES = target_arch=x87 v8_target_arch=x87 android_target_arch=x86 android_target_platform=14
-          TOOLCHAIN_ARCH = x86
-          TOOLCHAIN_PREFIX = i686-linux-android
-          TOOLCHAIN_VER = 4.8
-	else
-          $(error Target architecture "${ARCH}" is not supported)
-        endif
-      endif
-    endif
-  endif
+  $(error Target architecture "${ARCH}" is not supported)
 endif
 
 TOOLCHAIN_PATH = \
diff --git a/Makefile.nacl b/Makefile.nacl
index 34bd960..3459c42 100644
--- a/Makefile.nacl
+++ b/Makefile.nacl
@@ -36,41 +36,29 @@
                    $(addsuffix .$(mode),$(NACL_ARCHES)))
 
 HOST_OS = $(shell uname -s | sed -e 's/Linux/linux/;s/Darwin/mac/')
-ifeq ($(HOST_OS), linux)
-  TOOLCHAIN_DIR = linux_x86_glibc
-else
-  ifeq ($(HOST_OS), mac)
-    TOOLCHAIN_DIR = mac_x86_glibc
-  else
-    $(error Host platform "${HOST_OS}" is not supported)
-  endif
-endif
-
 TOOLCHAIN_PATH = $(realpath ${NACL_SDK_ROOT}/toolchain)
-NACL_TOOLCHAIN ?= ${TOOLCHAIN_PATH}/${TOOLCHAIN_DIR}
-
-ifeq ($(ARCH), nacl_ia32)
-  GYPENV = nacl_target_arch=nacl_ia32 v8_target_arch=arm v8_host_arch=ia32
-  TOOLCHAIN_ARCH = x86-4.4
-  NACL_CC = "$(NACL_TOOLCHAIN)/bin/i686-nacl-gcc"
-  NACL_CXX = "$(NACL_TOOLCHAIN)/bin/i686-nacl-g++"
-  NACL_LINK = "$(NACL_TOOLCHAIN)/bin/i686-nacl-g++"
-else
-  ifeq ($(ARCH), nacl_x64)
-    GYPENV = nacl_target_arch=nacl_x64 v8_target_arch=arm v8_host_arch=ia32
-    TOOLCHAIN_ARCH = x86-4.4
-    NACL_CC = "$(NACL_TOOLCHAIN)/bin/x86_64-nacl-gcc"
-    NACL_CXX = "$(NACL_TOOLCHAIN)/bin/x86_64-nacl-g++"
-    NACL_LINK = "$(NACL_TOOLCHAIN)/bin/x86_64-nacl-g++"
-  else
-    $(error Target architecture "${ARCH}" is not supported)
-  endif
-endif
+NACL_TOOLCHAIN ?= ${TOOLCHAIN_PATH}/linux_pnacl
 
 ifeq ($(wildcard $(NACL_TOOLCHAIN)),)
   $(error Cannot find Native Client toolchain in "${NACL_TOOLCHAIN}")
 endif
 
+ifeq ($(ARCH), nacl_ia32)
+  GYPENV = nacl_target_arch=nacl_ia32 v8_target_arch=arm v8_host_arch=ia32
+  NACL_CC = "$(NACL_TOOLCHAIN)/bin/pnacl-clang"
+  NACL_CXX = "$(NACL_TOOLCHAIN)/bin/pnacl-clang++"
+  NACL_LINK = "$(NACL_TOOLCHAIN)/bin/pnacl-clang++ --pnacl-allow-native -arch x86-32"
+else
+  ifeq ($(ARCH), nacl_x64)
+    GYPENV = nacl_target_arch=nacl_x64 v8_target_arch=arm v8_host_arch=ia32
+    NACL_CC = "$(NACL_TOOLCHAIN)/bin/pnacl-clang"
+    NACL_CXX = "$(NACL_TOOLCHAIN)/bin/pnacl-clang++"
+    NACL_LINK = "$(NACL_TOOLCHAIN)/bin/pnacl-clang++ --pnacl-allow-native -arch x86-64"
+  else
+    $(error Target architecture "${ARCH}" is not supported)
+  endif
+endif
+
 # For mksnapshot host generation.
 GYPENV += host_os=${HOST_OS}
 
@@ -85,7 +73,11 @@
 # For some reason the $$(basename $$@) expansion didn't work here...
 $(NACL_BUILDS): $(NACL_MAKEFILES)
 	@$(MAKE) -C "$(OUTDIR)" -f Makefile.$@ \
+	            CC=${NACL_CC} \
 	            CXX=${NACL_CXX} \
+	            AR="$(NACL_TOOLCHAIN)/bin/pnacl-ar" \
+	            RANLIB="$(NACL_TOOLCHAIN)/bin/pnacl-ranlib" \
+	            LD="$(NACL_TOOLCHAIN)/bin/pnacl-ld" \
 	            LINK=${NACL_LINK} \
 	            BUILDTYPE=$(shell echo $(subst .,,$(suffix $@)) | \
 	                        python -c "print raw_input().capitalize()") \
@@ -97,6 +89,7 @@
 	GYP_DEFINES="${GYPENV}" \
 	CC=${NACL_CC} \
 	CXX=${NACL_CXX} \
+	LINK=${NACL_LINK} \
 	PYTHONPATH="$(shell pwd)/tools/generate_shim_headers:$(shell pwd)/build:$(PYTHONPATH)" \
 	build/gyp/gyp --generator-output="${OUTDIR}" build/all.gyp \
 	              -Ibuild/standalone.gypi --depth=. \
diff --git a/OWNERS b/OWNERS
index f67b3ec..22a05cb 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,4 @@
+adamk@chromium.org
 bmeurer@chromium.org
 danno@chromium.org
 dcarney@chromium.org
@@ -16,7 +17,6 @@
 svenpanne@chromium.org
 titzer@chromium.org
 ulan@chromium.org
-vegorov@chromium.org
 verwaest@chromium.org
 vogelheim@chromium.org
 yangguo@chromium.org
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 3a9895d..6d19a4e 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -244,11 +244,11 @@
       'v8_linux_rel': set(['defaulttests']),
       'v8_linux_dbg': set(['defaulttests']),
       'v8_linux_nosnap_rel': set(['defaulttests']),
-      'v8_linux_nosnap_dbg': set(['defaulttests']),
       'v8_linux64_rel': set(['defaulttests']),
       'v8_linux_arm_dbg': set(['defaulttests']),
       'v8_linux_arm64_rel': set(['defaulttests']),
       'v8_linux_layout_dbg': set(['defaulttests']),
+      'v8_linux_chromium_gn_rel': set(['defaulttests']),
       'v8_mac_rel': set(['defaulttests']),
       'v8_win_rel': set(['defaulttests']),
       'v8_win64_compile_rel': set(['defaulttests']),
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..bc1685a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,33 @@
+V8 JavaScript Engine
+=============
+
+V8 is Google's open source JavaScript engine.
+
+V8 implements ECMAScript as specified in ECMA-262.
+
+V8 is written in C++ and is used in Google Chrome, the open source
+browser from Google.
+
+V8 can run standalone, or can be embedded into any C++ application.
+
+V8 Project page: https://code.google.com/p/v8/
+
+
+Getting the Code
+=============
+
+Checkout [depot tools](http://www.chromium.org/developers/how-tos/install-depot-tools), and run
+
+> `fetch v8`
+
+This will checkout V8 into the directory `v8` and fetch all of its dependencies.
+To stay up to date, run
+
+> `git pull origin`
+> `gclient sync`
+
+For fetching all branches, add the following into your remote
+configuration in `.git/config`:
+
+        fetch = +refs/branch-heads/*:refs/remotes/branch-heads/*
+        fetch = +refs/tags/*:refs/tags/*
diff --git a/V8_MERGE_REVISION b/V8_MERGE_REVISION
index fd6b1b2..aab9fb9 100644
--- a/V8_MERGE_REVISION
+++ b/V8_MERGE_REVISION
@@ -1,2 +1,2 @@
-v8 3.29.88.18
-https://chromium.googlesource.com/v8/v8/+/f0158730a3b758d746287cacc315ae262b83232d
+v8 4.1.0.21
+https://chromium.googlesource.com/v8/v8/+/4.1.0.21
diff --git a/build/all.gyp b/build/all.gyp
index 1e420fa..4aeb507 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -9,18 +9,14 @@
       'type': 'none',
       'dependencies': [
         '../samples/samples.gyp:*',
-        '../src/base/base.gyp:base-unittests',
-        '../src/compiler/compiler.gyp:compiler-unittests',
         '../src/d8.gyp:d8',
-        '../src/heap/heap.gyp:heap-unittests',
-        '../src/libplatform/libplatform.gyp:libplatform-unittests',
         '../test/cctest/cctest.gyp:*',
+        '../test/unittests/unittests.gyp:*',
       ],
       'conditions': [
         ['component!="shared_library"', {
           'dependencies': [
-            '../tools/lexer-shell.gyp:lexer-shell',
-            '../tools/lexer-shell.gyp:parser-shell',
+            '../tools/parser-shell.gyp:parser-shell',
           ],
         }],
       ]
diff --git a/build/android.gypi b/build/android.gypi
index f984ea3..5d3b25a 100644
--- a/build/android.gypi
+++ b/build/android.gypi
@@ -74,13 +74,13 @@
         ],
       },  # Release
     },  # configurations
-    'cflags': [ '-Wno-abi', '-Wall', '-W', '-Wno-unused-parameter',
-                '-Wnon-virtual-dtor', '-fno-rtti', '-fno-exceptions',
-                # Note: Using -std=c++0x will define __STRICT_ANSI__, which in
-                # turn will leave out some template stuff for 'long long'. What
-                # we want is -std=c++11, but this is not supported by GCC 4.6 or
-                # Xcode 4.2
-                '-std=gnu++0x' ],
+    'cflags': [ '-Wno-abi', '-Wall', '-W', '-Wno-unused-parameter'],
+    'cflags_cc': [ '-Wnon-virtual-dtor', '-fno-rtti', '-fno-exceptions',
+                   # Note: Using -std=c++0x will define __STRICT_ANSI__, which
+                   # in turn will leave out some template stuff for 'long
+                   # long'.  What we want is -std=c++11, but this is not
+                   # supported by GCC 4.6 or Xcode 4.2
+                   '-std=gnu++0x' ],
     'target_conditions': [
       ['_toolset=="target"', {
         'cflags!': [
@@ -93,11 +93,13 @@
           '-fno-short-enums',
           '-finline-limit=64',
           '-Wa,--noexecstack',
-          '-Wno-error=non-virtual-dtor',  # TODO(michaelbai): Fix warnings.
           # Note: This include is in cflags to ensure that it comes after
           # all of the includes.
           '-I<(android_include)',
         ],
+        'cflags_cc': [
+          '-Wno-error=non-virtual-dtor',  # TODO(michaelbai): Fix warnings.
+        ],
         'defines': [
           'ANDROID',
           #'__GNU_SOURCE=1',  # Necessary for clone()
@@ -213,8 +215,7 @@
               '-fno-stack-protector',
             ],
           }],
-          ['target_arch=="arm64" or target_arch=="x64"', {
-            # TODO(ulan): Enable PIE for other architectures (crbug.com/373219).
+          ['(target_arch=="arm" or target_arch=="arm64" or target_arch=="x64") and component!="shared_library"', {
             'cflags': [
               '-fPIE',
             ],
diff --git a/build/features.gypi b/build/features.gypi
index 8201ea9..465eba9 100644
--- a/build/features.gypi
+++ b/build/features.gypi
@@ -29,8 +29,6 @@
 
 {
   'variables': {
-    'v8_compress_startup_data%': 'off',
-
     'v8_enable_disassembler%': 0,
 
     'v8_enable_gdbjit%': 0,
@@ -39,6 +37,8 @@
 
     'v8_enable_verify_heap%': 0,
 
+    'v8_trace_maps%': 0,
+
     'v8_use_snapshot%': 'true',
 
     'v8_enable_verify_predictable%': 0,
@@ -59,9 +59,8 @@
     # Enable compiler warnings when using V8_DEPRECATED apis.
     'v8_deprecation_warnings%': 0,
 
-    # Use external files for startup data blobs:
-    # the JS builtins sources and the start snapshot.
-    'v8_use_external_startup_data%': 0,
+    # Set to 1 to enable DCHECKs in release builds.
+    'dcheck_always_on%': 0,
   },
   'target_defaults': {
     'conditions': [
@@ -77,6 +76,9 @@
       ['v8_enable_verify_heap==1', {
         'defines': ['VERIFY_HEAP',],
       }],
+      ['v8_trace_maps==1', {
+        'defines': ['TRACE_MAPS',],
+      }],
       ['v8_enable_verify_predictable==1', {
         'defines': ['VERIFY_PREDICTABLE',],
       }],
@@ -89,12 +91,12 @@
       ['v8_enable_i18n_support==1', {
         'defines': ['V8_I18N_SUPPORT',],
       }],
-      ['v8_compress_startup_data=="bz2"', {
-        'defines': ['COMPRESS_STARTUP_DATA_BZ2',],
-      }],
       ['v8_use_external_startup_data==1', {
         'defines': ['V8_USE_EXTERNAL_STARTUP_DATA',],
       }],
+      ['dcheck_always_on!=0', {
+        'defines': ['DEBUG',],
+      }],
     ],  # conditions
     'configurations': {
       'DebugBaseCommon': {
diff --git a/build/standalone.gypi b/build/standalone.gypi
index 32ad028..ee91e78 100644
--- a/build/standalone.gypi
+++ b/build/standalone.gypi
@@ -33,6 +33,8 @@
   'includes': ['toolchain.gypi'],
   'variables': {
     'component%': 'static_library',
+    'make_clang_dir%': '../third_party/llvm-build/Release+Asserts',
+    'clang_xcode%': 0,
     'asan%': 0,
     'tsan%': 0,
     'visibility%': 'hidden',
@@ -91,6 +93,12 @@
     #     near-release speeds.
     'v8_optimized_debug%': 0,
 
+    # Use external files for startup data blobs:
+    # the JS builtins sources and the start snapshot.
+    # Embedders that don't use standalone.gypi will need to add
+    # their own default value.
+    'v8_use_external_startup_data%': 0,
+
     # Relative path to icu.gyp from this file.
     'icu_gyp_path': '../third_party/icu/icu.gyp',
 
@@ -146,6 +154,14 @@
     'configurations': {
       'DebugBaseCommon': {
         'cflags': [ '-g', '-O0' ],
+        'conditions': [
+          ['(v8_target_arch=="ia32" or v8_target_arch=="x87") and \
+            OS=="linux"', {
+            'defines': [
+              '_GLIBCXX_DEBUG'
+            ],
+          }],
+        ],
       },
       'Optdebug': {
         'inherit_from': [ 'DebugBaseCommon', 'DebugBase2' ],
@@ -323,9 +339,15 @@
           },
           'VCLibrarianTool': {
             'AdditionalOptions': ['/ignore:4221'],
+            'conditions': [
+              ['v8_target_arch=="x64"', {
+                'TargetMachine': '17',  # x64
+              }, {
+                'TargetMachine': '1',  # ia32
+              }],
+            ],
           },
           'VCLinkerTool': {
-            'MinimumRequiredVersion': '5.01',  # XP.
             'AdditionalDependencies': [
               'ws2_32.lib',
             ],
@@ -350,6 +372,13 @@
                   'advapi32.lib',
                 ],
               }],
+              ['v8_target_arch=="x64"', {
+                'MinimumRequiredVersion': '5.02',  # Server 2003.
+                'TargetMachine': '17',  # x64
+              }, {
+                'MinimumRequiredVersion': '5.01',  # XP.
+                'TargetMachine': '1',  # ia32
+              }],
             ],
           },
         },
@@ -357,6 +386,7 @@
     }],  # OS=="win"
     ['OS=="mac"', {
       'xcode_settings': {
+        'SDKROOT': 'macosx',
         'SYMROOT': '<(DEPTH)/xcodebuild',
       },
       'target_defaults': {
@@ -411,5 +441,20 @@
         ],  # target_conditions
       },  # target_defaults
     }],  # OS=="mac"
+    ['clang==1 and ((OS!="mac" and OS!="ios") or clang_xcode==0) '
+        'and OS!="win"', {
+      'make_global_settings': [
+        ['CC', '<(make_clang_dir)/bin/clang'],
+        ['CXX', '<(make_clang_dir)/bin/clang++'],
+        ['CC.host', '$(CC)'],
+        ['CXX.host', '$(CXX)'],
+      ],
+    }],
+    ['clang==1 and OS=="win"', {
+      'make_global_settings': [
+        # On Windows, gyp's ninja generator only looks at CC.
+        ['CC', '<(make_clang_dir)/bin/clang-cl'],
+      ],
+    }],
   ],
 }
diff --git a/build/toolchain.gypi b/build/toolchain.gypi
index 38c9aee..ac10065 100644
--- a/build/toolchain.gypi
+++ b/build/toolchain.gypi
@@ -30,7 +30,6 @@
 {
   'variables': {
     'msvs_use_common_release': 0,
-    'gcc_version%': 'unknown',
     'clang%': 0,
     'v8_target_arch%': '<(target_arch)',
     # Native Client builds currently use the V8 ARM JIT and
@@ -888,7 +887,6 @@
           ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \
             OS=="qnx"', {
             'cflags!': [
-              '-O0',
               '-O3',
               '-O2',
               '-O1',
@@ -905,6 +903,9 @@
             },
           }],
         ],
+        'defines': [
+          'ENABLE_SLOW_DCHECKS',
+        ],
       },  # DebugBase0
       # Abstract configuration for v8_optimized_debug == 1.
       'DebugBase1': {
@@ -929,6 +930,9 @@
             'LinkIncremental': '2',
           },
         },
+        'defines': [
+          'ENABLE_SLOW_DCHECKS',
+        ],
         'conditions': [
           ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \
             OS=="qnx"', {
@@ -943,14 +947,6 @@
               '-ffunction-sections',
               '-O1', # TODO(2807) should be -O3.
             ],
-            'conditions': [
-              ['gcc_version==44 and clang==0', {
-                'cflags': [
-                  # Avoid crashes with gcc 4.4 in the v8 test suite.
-                  '-fno-tree-vrp',
-                ],
-              }],
-            ],
           }],
           ['OS=="mac"', {
             'xcode_settings': {
@@ -977,10 +973,6 @@
               }, {
                 'RuntimeLibrary': '1',  #/MTd
               }],
-              ['v8_target_arch=="x64"', {
-                # TODO(2207): remove this option once the bug is fixed.
-                'WholeProgramOptimization': 'true',
-              }],
             ],
           },
           'VCLinkerTool': {
@@ -1001,9 +993,6 @@
               '-fdata-sections',
               '-ffunction-sections',
             ],
-            'defines': [
-              'OPTIMIZED_DEBUG'
-            ],
             'conditions': [
               # TODO(crbug.com/272548): Avoid -O3 in NaCl
               ['nacl_target_arch=="none"', {
@@ -1013,12 +1002,6 @@
                 'cflags': ['-O2'],
                 'cflags!': ['-O3'],
               }],
-              ['gcc_version==44 and clang==0', {
-                'cflags': [
-                  # Avoid crashes with gcc 4.4 in the v8 test suite.
-                  '-fno-tree-vrp',
-                ],
-              }],
             ],
           }],
           ['OS=="mac"', {
@@ -1037,7 +1020,8 @@
           'V8_ENABLE_CHECKS',
           'OBJECT_PRINT',
           'VERIFY_HEAP',
-          'DEBUG'
+          'DEBUG',
+          'TRACE_MAPS'
         ],
         'conditions': [
           ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \
@@ -1058,6 +1042,7 @@
                 # TODO(2304): pass DISABLE_DEBUG_ASSERT instead of hiding DEBUG.
                 'defines!': [
                   'DEBUG',
+                  'ENABLE_SLOW_DCHECKS',
                 ],
               }],
             ],
@@ -1090,12 +1075,6 @@
               '<(wno_array_bounds)',
             ],
             'conditions': [
-              [ 'gcc_version==44 and clang==0', {
-                'cflags': [
-                  # Avoid crashes with gcc 4.4 in the v8 test suite.
-                  '-fno-tree-vrp',
-                ],
-              }],
               # TODO(crbug.com/272548): Avoid -O3 in NaCl
               ['nacl_target_arch=="none"', {
                 'cflags': ['-O3'],
@@ -1116,14 +1095,6 @@
               '-ffunction-sections',
               '-O2',
             ],
-            'conditions': [
-              [ 'gcc_version==44 and clang==0', {
-                'cflags': [
-                  # Avoid crashes with gcc 4.4 in the v8 test suite.
-                  '-fno-tree-vrp',
-                ],
-              }],
-            ],
           }],
           ['OS=="mac"', {
             'xcode_settings': {
@@ -1150,10 +1121,6 @@
                   }, {
                     'RuntimeLibrary': '0',  #/MT
                   }],
-                  ['v8_target_arch=="x64"', {
-                    # TODO(2207): remove this option once the bug is fixed.
-                    'WholeProgramOptimization': 'true',
-                  }],
                 ],
               },
               'VCLinkerTool': {
diff --git a/buildtools b/buildtools
new file mode 160000
index 0000000..3b302fe
--- /dev/null
+++ b/buildtools
@@ -0,0 +1 @@
+Subproject commit 3b302fef93f7cc58d9b8168466905237484b2772
diff --git a/codereview.settings b/codereview.settings
index b7f853c..a7ee88e 100644
--- a/codereview.settings
+++ b/codereview.settings
@@ -1,8 +1,9 @@
 CODE_REVIEW_SERVER: https://codereview.chromium.org
 CC_LIST: v8-dev@googlegroups.com
-VIEW_VC: https://code.google.com/p/v8/source/detail?r=
+VIEW_VC: https://chromium.googlesource.com/v8/v8/+/
 STATUS: http://v8-status.appspot.com/status
 TRY_ON_UPLOAD: False
 TRYSERVER_SVN_URL: svn://svn.chromium.org/chrome-try-v8
 TRYSERVER_ROOT: v8
 PROJECT: v8
+PENDING_REF_PREFIX: refs/pending/
diff --git a/include/v8-platform.h b/include/v8-platform.h
index 1f1679f..67fb384 100644
--- a/include/v8-platform.h
+++ b/include/v8-platform.h
@@ -55,6 +55,15 @@
    * scheduling. The definition of "foreground" is opaque to V8.
    */
   virtual void CallOnForegroundThread(Isolate* isolate, Task* task) = 0;
+
+  /**
+   * Monotonically increasing time in seconds from an arbitrary fixed point in
+   * the past. This function is expected to return at least
+   * millisecond-precision values. For this reason,
+   * it is recommended that the fixed point be no further in the past than
+   * the epoch.
+   **/
+  virtual double MonotonicallyIncreasingTime() = 0;
 };
 
 }  // namespace v8
diff --git a/include/v8-profiler.h b/include/v8-profiler.h
index 7fc193d..d021520 100644
--- a/include/v8-profiler.h
+++ b/include/v8-profiler.h
@@ -22,6 +22,14 @@
  */
 class V8_EXPORT CpuProfileNode {
  public:
+  struct LineTick {
+    /** The 1-based number of the source line where the function originates. */
+    int line;
+
+    /** The count of samples associated with the source line. */
+    unsigned int hit_count;
+  };
+
   /** Returns function name (empty string for anonymous functions.) */
   Handle<String> GetFunctionName() const;
 
@@ -43,6 +51,18 @@
    */
   int GetColumnNumber() const;
 
+  /**
+   * Returns the number of the function's source lines that collect the samples.
+   */
+  unsigned int GetHitLineCount() const;
+
+  /** Returns the set of source lines that collect the samples.
+   *  The caller allocates buffer and responsible for releasing it.
+   *  True if all available entries are copied, otherwise false.
+   *  The function copies nothing if buffer is not large enough.
+   */
+  bool GetLineTicks(LineTick* entries, unsigned int length) const;
+
   /** Returns bailout reason for the function
     * if the optimization was disabled for it.
     */
diff --git a/include/v8.h b/include/v8.h
index ec1941e..b445525 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -15,7 +15,11 @@
 #ifndef V8_H_
 #define V8_H_
 
-#include "v8stdint.h"
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "v8config.h"
 
 // We reserve the V8_* prefix for macros defined in V8 public API and
 // assume there are no name conflicts with the embedder's code.
@@ -85,6 +89,7 @@
 class ObjectTemplate;
 class Platform;
 class Primitive;
+class Promise;
 class RawOperationDescriptor;
 class Script;
 class Signature;
@@ -135,6 +140,17 @@
 class PropertyCallbackArguments;
 class FunctionCallbackArguments;
 class GlobalHandles;
+
+class CallbackData {
+ public:
+  V8_INLINE v8::Isolate* GetIsolate() const { return isolate_; }
+
+ protected:
+  explicit CallbackData(v8::Isolate* isolate) : isolate_(isolate) {}
+
+ private:
+  v8::Isolate* isolate_;
+};
 }
 
 
@@ -413,22 +429,53 @@
 };
 
 
-template<class T, class P>
-class WeakCallbackData {
+template <typename T>
+class PhantomCallbackData : public internal::CallbackData {
+ public:
+  typedef void (*Callback)(const PhantomCallbackData<T>& data);
+
+  V8_INLINE T* GetParameter() const { return parameter_; }
+
+  PhantomCallbackData<T>(Isolate* isolate, T* parameter)
+      : internal::CallbackData(isolate), parameter_(parameter) {}
+
+ private:
+  T* parameter_;
+};
+
+
+template <class T, class P>
+class WeakCallbackData : public PhantomCallbackData<P> {
  public:
   typedef void (*Callback)(const WeakCallbackData<T, P>& data);
 
-  V8_INLINE Isolate* GetIsolate() const { return isolate_; }
   V8_INLINE Local<T> GetValue() const { return handle_; }
-  V8_INLINE P* GetParameter() const { return parameter_; }
 
  private:
   friend class internal::GlobalHandles;
-  WeakCallbackData(Isolate* isolate, Local<T> handle, P* parameter)
-    : isolate_(isolate), handle_(handle), parameter_(parameter) { }
-  Isolate* isolate_;
+  WeakCallbackData(Isolate* isolate, P* parameter, Local<T> handle)
+      : PhantomCallbackData<P>(isolate, parameter), handle_(handle) {}
   Local<T> handle_;
-  P* parameter_;
+};
+
+
+template <typename T, typename U>
+class InternalFieldsCallbackData : public internal::CallbackData {
+ public:
+  typedef void (*Callback)(const InternalFieldsCallbackData<T, U>& data);
+
+  InternalFieldsCallbackData(Isolate* isolate, T* internalField1,
+                             U* internalField2)
+      : internal::CallbackData(isolate),
+        internal_field1_(internalField1),
+        internal_field2_(internalField2) {}
+
+  V8_INLINE T* GetInternalField1() const { return internal_field1_; }
+  V8_INLINE U* GetInternalField2() const { return internal_field2_; }
+
+ private:
+  T* internal_field1_;
+  U* internal_field2_;
 };
 
 
@@ -466,22 +513,23 @@
   template <class S>
   V8_INLINE void Reset(Isolate* isolate, const PersistentBase<S>& other);
 
-  V8_INLINE bool IsEmpty() const { return val_ == 0; }
+  V8_INLINE bool IsEmpty() const { return val_ == NULL; }
+  V8_INLINE void Empty() { val_ = 0; }
 
   template <class S>
   V8_INLINE bool operator==(const PersistentBase<S>& that) const {
     internal::Object** a = reinterpret_cast<internal::Object**>(this->val_);
     internal::Object** b = reinterpret_cast<internal::Object**>(that.val_);
-    if (a == 0) return b == 0;
-    if (b == 0) return false;
+    if (a == NULL) return b == NULL;
+    if (b == NULL) return false;
     return *a == *b;
   }
 
   template <class S> V8_INLINE bool operator==(const Handle<S>& that) const {
     internal::Object** a = reinterpret_cast<internal::Object**>(this->val_);
     internal::Object** b = reinterpret_cast<internal::Object**>(that.val_);
-    if (a == 0) return b == 0;
-    if (b == 0) return false;
+    if (a == NULL) return b == NULL;
+    if (b == NULL) return false;
     return *a == *b;
   }
 
@@ -511,6 +559,21 @@
       P* parameter,
       typename WeakCallbackData<S, P>::Callback callback);
 
+  // Phantom persistents work like weak persistents, except that the pointer to
+  // the object being collected is not available in the finalization callback.
+  // This enables the garbage collector to collect the object and any objects
+  // it references transitively in one GC cycle. At the moment you can either
+  // specify a parameter for the callback or the location of two internal
+  // fields in the dying object.
+  template <typename P>
+  V8_INLINE void SetPhantom(P* parameter,
+                            typename PhantomCallbackData<P>::Callback callback);
+
+  template <typename P, typename Q>
+  V8_INLINE void SetPhantom(
+      void (*callback)(const InternalFieldsCallbackData<P, Q>&),
+      int internal_field_index1, int internal_field_index2);
+
   template<typename P>
   V8_INLINE P* ClearWeak();
 
@@ -696,9 +759,6 @@
     return Persistent<S>::Cast(*this);
   }
 
-  // This will be removed.
-  V8_INLINE T* ClearAndLeak();
-
  private:
   friend class Isolate;
   friend class Utils;
@@ -997,7 +1057,7 @@
   /**
    * Runs the script returning the resulting value. It will be run in the
    * context in which it was created (ScriptCompiler::CompileBound or
-   * UnboundScript::BindToGlobalContext()).
+   * UnboundScript::BindToCurrentContext()).
    */
   Local<Value> Run();
 
@@ -1031,7 +1091,11 @@
       BufferOwned
     };
 
-    CachedData() : data(NULL), length(0), buffer_policy(BufferNotOwned) {}
+    CachedData()
+        : data(NULL),
+          length(0),
+          rejected(false),
+          buffer_policy(BufferNotOwned) {}
 
     // If buffer_policy is BufferNotOwned, the caller keeps the ownership of
     // data and guarantees that it stays alive until the CachedData object is
@@ -1044,6 +1108,7 @@
     // which will be called when V8 no longer needs the data.
     const uint8_t* data;
     int length;
+    bool rejected;
     BufferPolicy buffer_policy;
 
    private:
@@ -1224,6 +1289,26 @@
   static Local<Script> Compile(Isolate* isolate, StreamedSource* source,
                                Handle<String> full_source_string,
                                const ScriptOrigin& origin);
+
+  /**
+   * Return a version tag for CachedData for the current V8 version & flags.
+   *
+   * This value is meant only for determining whether a previously generated
+   * CachedData instance is still valid; the tag has no other meaing.
+   *
+   * Background: The data carried by CachedData may depend on the exact
+   *   V8 version number or currently compiler flags. This means when
+   *   persisting CachedData, the embedder must take care to not pass in
+   *   data from another V8 version, or the same version with different
+   *   features enabled.
+   *
+   *   The easiest way to do so is to clear the embedder's cache on any
+   *   such change.
+   *
+   *   Alternatively, this tag can be stored alongside the cached data and
+   *   compared when it is being used.
+   */
+  static uint32_t CachedDataVersionTag();
 };
 
 
@@ -1415,6 +1500,27 @@
 };
 
 
+// A StateTag represents a possible state of the VM.
+enum StateTag { JS, GC, COMPILER, OTHER, EXTERNAL, IDLE };
+
+
+// A RegisterState represents the current state of registers used
+// by the sampling profiler API.
+struct RegisterState {
+  RegisterState() : pc(NULL), sp(NULL), fp(NULL) {}
+  void* pc;  // Instruction pointer.
+  void* sp;  // Stack pointer.
+  void* fp;  // Frame pointer.
+};
+
+
+// The output structure filled up by GetStackSample API function.
+struct SampleInfo {
+  size_t frames_count;
+  StateTag vm_state;
+};
+
+
 /**
  * A JSON Parser.
  */
@@ -1561,6 +1667,18 @@
   bool IsRegExp() const;
 
   /**
+   * Returns true if this value is a Generator function.
+   * This is an experimental feature.
+   */
+  bool IsGeneratorFunction() const;
+
+  /**
+   * Returns true if this value is a Generator object (iterator).
+   * This is an experimental feature.
+   */
+  bool IsGeneratorObject() const;
+
+  /**
    * Returns true if this value is a Promise.
    * This is an experimental feature.
    */
@@ -1579,6 +1697,18 @@
   bool IsSet() const;
 
   /**
+   * Returns true if this value is a Map Iterator.
+   * This is an experimental feature.
+   */
+  bool IsMapIterator() const;
+
+  /**
+   * Returns true if this value is a Set Iterator.
+   * This is an experimental feature.
+   */
+  bool IsSetIterator() const;
+
+  /**
    * Returns true if this value is a WeakMap.
    * This is an experimental feature.
    */
@@ -1668,14 +1798,24 @@
    */
   bool IsDataView() const;
 
-  Local<Boolean> ToBoolean() const;
-  Local<Number> ToNumber() const;
-  Local<String> ToString() const;
-  Local<String> ToDetailString() const;
-  Local<Object> ToObject() const;
-  Local<Integer> ToInteger() const;
-  Local<Uint32> ToUint32() const;
-  Local<Int32> ToInt32() const;
+  Local<Boolean> ToBoolean(Isolate* isolate) const;
+  Local<Number> ToNumber(Isolate* isolate) const;
+  Local<String> ToString(Isolate* isolate) const;
+  Local<String> ToDetailString(Isolate* isolate) const;
+  Local<Object> ToObject(Isolate* isolate) const;
+  Local<Integer> ToInteger(Isolate* isolate) const;
+  Local<Uint32> ToUint32(Isolate* isolate) const;
+  Local<Int32> ToInt32(Isolate* isolate) const;
+
+  // TODO(dcarney): deprecate all these.
+  inline Local<Boolean> ToBoolean() const;
+  inline Local<Number> ToNumber() const;
+  inline Local<String> ToString() const;
+  inline Local<String> ToDetailString() const;
+  inline Local<Object> ToObject() const;
+  inline Local<Integer> ToInteger() const;
+  inline Local<Uint32> ToUint32() const;
+  inline Local<Int32> ToInt32() const;
 
   /**
    * Attempts to convert a string to an array index.
@@ -1728,6 +1868,15 @@
  */
 class V8_EXPORT Name : public Primitive {
  public:
+  /**
+   * Returns the identity hash for this object. The current implementation
+   * uses an inline property on the object to store the identity hash.
+   *
+   * The return value will never be 0. Also, it is not guaranteed to be
+   * unique.
+   */
+  int GetIdentityHash();
+
   V8_INLINE static Name* Cast(v8::Value* obj);
  private:
   static void CheckCast(v8::Value* obj);
@@ -1742,7 +1891,6 @@
   enum Encoding {
     UNKNOWN_ENCODING = 0x1,
     TWO_BYTE_ENCODING = 0x0,
-    ASCII_ENCODING = 0x4,  // TODO(yangguo): deprecate this.
     ONE_BYTE_ENCODING = 0x4
   };
   /**
@@ -1798,7 +1946,6 @@
     NO_OPTIONS = 0,
     HINT_MANY_WRITES_EXPECTED = 1,
     NO_NULL_TERMINATION = 2,
-    PRESERVE_ASCII_NULL = 4,  // TODO(yangguo): deprecate this.
     PRESERVE_ONE_BYTE_NULL = 4,
     // Used by WriteUtf8 to replace orphan surrogate code units with the
     // unicode replacement character. Needs to be set to guarantee valid UTF-8
@@ -1837,9 +1984,6 @@
    */
   bool IsExternalOneByte() const;
 
-  // TODO(yangguo): deprecate this.
-  bool IsExternalAscii() const { return IsExternalOneByte(); }
-
   class V8_EXPORT ExternalStringResourceBase {  // NOLINT
    public:
     virtual ~ExternalStringResourceBase() {}
@@ -1918,8 +2062,6 @@
     ExternalOneByteStringResource() {}
   };
 
-  typedef ExternalOneByteStringResource ExternalAsciiStringResource;
-
   /**
    * If the string is an external string, return the ExternalStringResourceBase
    * regardless of the encoding, otherwise return NULL.  The encoding of the
@@ -1940,11 +2082,6 @@
    */
   const ExternalOneByteStringResource* GetExternalOneByteStringResource() const;
 
-  // TODO(yangguo): deprecate this.
-  const ExternalAsciiStringResource* GetExternalAsciiStringResource() const {
-    return GetExternalOneByteStringResource();
-  }
-
   V8_INLINE static String* Cast(v8::Value* obj);
 
   enum NewStringType {
@@ -2107,6 +2244,7 @@
   // Well-known symbols
   static Local<Symbol> GetIterator(Isolate* isolate);
   static Local<Symbol> GetUnscopables(Isolate* isolate);
+  static Local<Symbol> GetToStringTag(Isolate* isolate);
 
   V8_INLINE static Symbol* Cast(v8::Value* obj);
 
@@ -2400,6 +2538,8 @@
   /** Gets the number of internal fields for this Object. */
   int InternalFieldCount();
 
+  static const int kNoInternalFieldIndex = -1;
+
   /** Same as above, but works for Persistents */
   V8_INLINE static int InternalFieldCount(
       const PersistentBase<Object>& object) {
@@ -2484,15 +2624,6 @@
   bool DeleteHiddenValue(Handle<String> key);
 
   /**
-   * Returns true if this is an instance of an api function (one
-   * created from a function created from a function template) and has
-   * been modified since it was created.  Note that this method is
-   * conservative and may return true for objects that haven't actually
-   * been modified.
-   */
-  bool IsDirty();
-
-  /**
    * Clone this object with a fast but shallow copy.  Values will point
    * to the same values as the original object.
    */
@@ -2552,6 +2683,11 @@
    */
   Local<Value> CallAsConstructor(int argc, Handle<Value> argv[]);
 
+  /**
+   * Return the isolate to which the Object belongs to.
+   */
+  Isolate* GetIsolate();
+
   static Local<Object> New(Isolate* isolate);
 
   V8_INLINE static Object* Cast(Value* obj);
@@ -2818,6 +2954,12 @@
   Local<Promise> Catch(Handle<Function> handler);
   Local<Promise> Then(Handle<Function> handler);
 
+  /**
+   * Returns true if the promise has at least one derived promise, and
+   * therefore resolve/reject handlers (including default handler).
+   */
+  bool HasHandler();
+
   V8_INLINE static Promise* Cast(Value* obj);
 
  private:
@@ -2920,10 +3062,15 @@
   bool IsExternal() const;
 
   /**
+   * Returns true if this ArrayBuffer may be neutered.
+   */
+  bool IsNeuterable() const;
+
+  /**
    * Neuters this ArrayBuffer and all its views (typed arrays).
    * Neutering sets the byte length of the buffer and all typed arrays to zero,
    * preventing JavaScript from ever accessing underlying backing store.
-   * ArrayBuffer should have been externalized.
+   * ArrayBuffer should have been externalized and must be neuterable.
    */
   void Neuter();
 
@@ -3455,6 +3602,51 @@
     const PropertyCallbackInfo<Array>& info);
 
 
+// TODO(dcarney): Deprecate and remove previous typedefs, and replace
+// GenericNamedPropertyFooCallback with just NamedPropertyFooCallback.
+/**
+ * GenericNamedProperty[Getter|Setter] are used as interceptors on object.
+ * See ObjectTemplate::SetNamedPropertyHandler.
+ */
+typedef void (*GenericNamedPropertyGetterCallback)(
+    Local<Name> property, const PropertyCallbackInfo<Value>& info);
+
+
+/**
+ * Returns the value if the setter intercepts the request.
+ * Otherwise, returns an empty handle.
+ */
+typedef void (*GenericNamedPropertySetterCallback)(
+    Local<Name> property, Local<Value> value,
+    const PropertyCallbackInfo<Value>& info);
+
+
+/**
+ * Returns a non-empty handle if the interceptor intercepts the request.
+ * The result is an integer encoding property attributes (like v8::None,
+ * v8::DontEnum, etc.)
+ */
+typedef void (*GenericNamedPropertyQueryCallback)(
+    Local<Name> property, const PropertyCallbackInfo<Integer>& info);
+
+
+/**
+ * Returns a non-empty handle if the deleter intercepts the request.
+ * The return value is true if the property could be deleted and false
+ * otherwise.
+ */
+typedef void (*GenericNamedPropertyDeleterCallback)(
+    Local<Name> property, const PropertyCallbackInfo<Boolean>& info);
+
+
+/**
+ * Returns an array containing the names of the properties the named
+ * property getter intercepts.
+ */
+typedef void (*GenericNamedPropertyEnumeratorCallback)(
+    const PropertyCallbackInfo<Array>& info);
+
+
 /**
  * Returns the value of the property if the getter intercepts the
  * request.  Otherwise, returns an empty handle.
@@ -3707,6 +3899,65 @@
 };
 
 
+enum class PropertyHandlerFlags { kNone = 0, kAllCanRead = 1 };
+
+
+struct NamedPropertyHandlerConfiguration {
+  NamedPropertyHandlerConfiguration(
+      /** Note: getter is required **/
+      GenericNamedPropertyGetterCallback getter = 0,
+      GenericNamedPropertySetterCallback setter = 0,
+      GenericNamedPropertyQueryCallback query = 0,
+      GenericNamedPropertyDeleterCallback deleter = 0,
+      GenericNamedPropertyEnumeratorCallback enumerator = 0,
+      Handle<Value> data = Handle<Value>(),
+      PropertyHandlerFlags flags = PropertyHandlerFlags::kNone)
+      : getter(getter),
+        setter(setter),
+        query(query),
+        deleter(deleter),
+        enumerator(enumerator),
+        data(data),
+        flags(flags) {}
+
+  GenericNamedPropertyGetterCallback getter;
+  GenericNamedPropertySetterCallback setter;
+  GenericNamedPropertyQueryCallback query;
+  GenericNamedPropertyDeleterCallback deleter;
+  GenericNamedPropertyEnumeratorCallback enumerator;
+  Handle<Value> data;
+  PropertyHandlerFlags flags;
+};
+
+
+struct IndexedPropertyHandlerConfiguration {
+  IndexedPropertyHandlerConfiguration(
+      /** Note: getter is required **/
+      IndexedPropertyGetterCallback getter = 0,
+      IndexedPropertySetterCallback setter = 0,
+      IndexedPropertyQueryCallback query = 0,
+      IndexedPropertyDeleterCallback deleter = 0,
+      IndexedPropertyEnumeratorCallback enumerator = 0,
+      Handle<Value> data = Handle<Value>(),
+      PropertyHandlerFlags flags = PropertyHandlerFlags::kNone)
+      : getter(getter),
+        setter(setter),
+        query(query),
+        deleter(deleter),
+        enumerator(enumerator),
+        data(data),
+        flags(flags) {}
+
+  IndexedPropertyGetterCallback getter;
+  IndexedPropertySetterCallback setter;
+  IndexedPropertyQueryCallback query;
+  IndexedPropertyDeleterCallback deleter;
+  IndexedPropertyEnumeratorCallback enumerator;
+  Handle<Value> data;
+  PropertyHandlerFlags flags;
+};
+
+
 /**
  * An ObjectTemplate is used to create objects at runtime.
  *
@@ -3776,6 +4027,9 @@
    * from this object template, the provided callback is invoked instead of
    * accessing the property directly on the JavaScript object.
    *
+   * Note that new code should use the second version that can intercept
+   * symbol-named properties as well as string-named properties.
+   *
    * \param getter The callback to invoke when getting a property.
    * \param setter The callback to invoke when setting a property.
    * \param query The callback to invoke to check if a property is present,
@@ -3786,6 +4040,7 @@
    * \param data A piece of data that will be passed to the callbacks
    *   whenever they are invoked.
    */
+  // TODO(dcarney): deprecate
   void SetNamedPropertyHandler(
       NamedPropertyGetterCallback getter,
       NamedPropertySetterCallback setter = 0,
@@ -3793,6 +4048,7 @@
       NamedPropertyDeleterCallback deleter = 0,
       NamedPropertyEnumeratorCallback enumerator = 0,
       Handle<Value> data = Handle<Value>());
+  void SetHandler(const NamedPropertyHandlerConfiguration& configuration);
 
   /**
    * Sets an indexed property handler on the object template.
@@ -3810,14 +4066,18 @@
    * \param data A piece of data that will be passed to the callbacks
    *   whenever they are invoked.
    */
+  void SetHandler(const IndexedPropertyHandlerConfiguration& configuration);
+  // TODO(dcarney): deprecate
   void SetIndexedPropertyHandler(
       IndexedPropertyGetterCallback getter,
       IndexedPropertySetterCallback setter = 0,
       IndexedPropertyQueryCallback query = 0,
       IndexedPropertyDeleterCallback deleter = 0,
       IndexedPropertyEnumeratorCallback enumerator = 0,
-      Handle<Value> data = Handle<Value>());
-
+      Handle<Value> data = Handle<Value>()) {
+    SetHandler(IndexedPropertyHandlerConfiguration(getter, setter, query,
+                                                   deleter, enumerator, data));
+  }
   /**
    * Sets the callback to be used when calling instances created from
    * this template as a function.  If no callback is set, instances
@@ -4122,6 +4382,19 @@
   static Local<Value> SyntaxError(Handle<String> message);
   static Local<Value> TypeError(Handle<String> message);
   static Local<Value> Error(Handle<String> message);
+
+  /**
+   * Creates an error message for the given exception.
+   * Will try to reconstruct the original stack trace from the exception value,
+   * or capture the current stack trace if not available.
+   */
+  static Local<Message> CreateMessage(Handle<Value> exception);
+
+  /**
+   * Returns the original stack trace that was captured at the creation time
+   * of a given exception, or an empty handle if not available.
+   */
+  static Local<StackTrace> GetStackTrace(Handle<Value> exception);
 };
 
 
@@ -4137,18 +4410,19 @@
 typedef void (*AddHistogramSampleCallback)(void* histogram, int sample);
 
 // --- Memory Allocation Callback ---
-  enum ObjectSpace {
-    kObjectSpaceNewSpace = 1 << 0,
-    kObjectSpaceOldPointerSpace = 1 << 1,
-    kObjectSpaceOldDataSpace = 1 << 2,
-    kObjectSpaceCodeSpace = 1 << 3,
-    kObjectSpaceMapSpace = 1 << 4,
-    kObjectSpaceLoSpace = 1 << 5,
-
-    kObjectSpaceAll = kObjectSpaceNewSpace | kObjectSpaceOldPointerSpace |
-      kObjectSpaceOldDataSpace | kObjectSpaceCodeSpace | kObjectSpaceMapSpace |
-      kObjectSpaceLoSpace
-  };
+enum ObjectSpace {
+  kObjectSpaceNewSpace = 1 << 0,
+  kObjectSpaceOldPointerSpace = 1 << 1,
+  kObjectSpaceOldDataSpace = 1 << 2,
+  kObjectSpaceCodeSpace = 1 << 3,
+  kObjectSpaceMapSpace = 1 << 4,
+  kObjectSpaceCellSpace = 1 << 5,
+  kObjectSpacePropertyCellSpace = 1 << 6,
+  kObjectSpaceLoSpace = 1 << 7,
+  kObjectSpaceAll = kObjectSpaceNewSpace | kObjectSpaceOldPointerSpace |
+                    kObjectSpaceOldDataSpace | kObjectSpaceCodeSpace |
+                    kObjectSpaceMapSpace | kObjectSpaceLoSpace
+};
 
   enum AllocationAction {
     kAllocationActionAllocate = 1 << 0,
@@ -4163,6 +4437,37 @@
 // --- Leave Script Callback ---
 typedef void (*CallCompletedCallback)();
 
+// --- Promise Reject Callback ---
+enum PromiseRejectEvent {
+  kPromiseRejectWithNoHandler = 0,
+  kPromiseHandlerAddedAfterReject = 1
+};
+
+class PromiseRejectMessage {
+ public:
+  PromiseRejectMessage(Handle<Promise> promise, PromiseRejectEvent event,
+                       Handle<Value> value, Handle<StackTrace> stack_trace)
+      : promise_(promise),
+        event_(event),
+        value_(value),
+        stack_trace_(stack_trace) {}
+
+  V8_INLINE Handle<Promise> GetPromise() const { return promise_; }
+  V8_INLINE PromiseRejectEvent GetEvent() const { return event_; }
+  V8_INLINE Handle<Value> GetValue() const { return value_; }
+
+  // DEPRECATED. Use v8::Exception::CreateMessage(GetValue())->GetStackTrace()
+  V8_INLINE Handle<StackTrace> GetStackTrace() const { return stack_trace_; }
+
+ private:
+  Handle<Promise> promise_;
+  PromiseRejectEvent event_;
+  Handle<Value> value_;
+  Handle<StackTrace> stack_trace_;
+};
+
+typedef void (*PromiseRejectCallback)(PromiseRejectMessage message);
+
 // --- Microtask Callback ---
 typedef void (*MicrotaskCallback)(void* data);
 
@@ -4334,6 +4639,27 @@
 
 
 /**
+ * Interface for iterating through all external resources in the heap.
+ */
+class V8_EXPORT ExternalResourceVisitor {  // NOLINT
+ public:
+  virtual ~ExternalResourceVisitor() {}
+  virtual void VisitExternalString(Handle<String> string) {}
+};
+
+
+/**
+ * Interface for iterating through all the persistent handles in the heap.
+ */
+class V8_EXPORT PersistentHandleVisitor {  // NOLINT
+ public:
+  virtual ~PersistentHandleVisitor() {}
+  virtual void VisitPersistentHandle(Persistent<Value>* value,
+                                     uint16_t class_id) {}
+};
+
+
+/**
  * Isolate represents an isolated instance of the V8 engine.  V8 isolates have
  * completely separate states.  Objects from one isolate must not be used in
  * other isolates.  The embedder can create multiple isolates and use them in
@@ -4473,6 +4799,7 @@
    */
   enum UseCounterFeature {
     kUseAsm = 0,
+    kBreakIterator = 1,
     kUseCounterFeatureCount  // This enum value must be last.
   };
 
@@ -4494,6 +4821,8 @@
   /**
    * Returns the entered isolate for the current thread or NULL in
    * case there is no current isolate.
+   *
+   * This method must not be invoked before V8::Initialize() was invoked.
    */
   static Isolate* GetCurrent();
 
@@ -4548,6 +4877,21 @@
   void GetHeapStatistics(HeapStatistics* heap_statistics);
 
   /**
+   * Get a call stack sample from the isolate.
+   * \param state Execution state.
+   * \param frames Caller allocated buffer to store stack frames.
+   * \param frames_limit Maximum number of frames to capture. The buffer must
+   *                     be large enough to hold the number of frames.
+   * \param sample_info The sample info is filled up by the function
+   *                    provides number of actual captured stack frames and
+   *                    the current VM state.
+   * \note GetStackSample should only be called when the JS thread is paused or
+   *       interrupted. Otherwise the behavior is undefined.
+   */
+  void GetStackSample(const RegisterState& state, void** frames,
+                      size_t frames_limit, SampleInfo* sample_info);
+
+  /**
    * Adjusts the amount of registered external memory. Used to give V8 an
    * indication of the amount of externally allocated memory that is kept alive
    * by JavaScript objects. V8 uses this to decide when to perform global
@@ -4676,12 +5020,47 @@
    */
   void RemoveGCEpilogueCallback(GCEpilogueCallback callback);
 
+
+  /**
+   * Forcefully terminate the current thread of JavaScript execution
+   * in the given isolate.
+   *
+   * This method can be used by any thread even if that thread has not
+   * acquired the V8 lock with a Locker object.
+   */
+  void TerminateExecution();
+
+  /**
+   * Is V8 terminating JavaScript execution.
+   *
+   * Returns true if JavaScript execution is currently terminating
+   * because of a call to TerminateExecution.  In that case there are
+   * still JavaScript frames on the stack and the termination
+   * exception is still active.
+   */
+  bool IsExecutionTerminating();
+
+  /**
+   * Resume execution capability in the given isolate, whose execution
+   * was previously forcefully terminated using TerminateExecution().
+   *
+   * When execution is forcefully terminated using TerminateExecution(),
+   * the isolate can not resume execution until all JavaScript frames
+   * have propagated the uncatchable exception which is generated.  This
+   * method allows the program embedding the engine to handle the
+   * termination event and resume execution capability, even if
+   * JavaScript frames remain on the stack.
+   *
+   * This method can be used by any thread even if that thread has not
+   * acquired the V8 lock with a Locker object.
+   */
+  void CancelTerminateExecution();
+
   /**
    * Request V8 to interrupt long running JavaScript code and invoke
    * the given |callback| passing the given |data| to it. After |callback|
    * returns control will be returned to the JavaScript code.
-   * At any given moment V8 can remember only a single callback for the very
-   * last interrupt request.
+   * There may be a number of interrupt requests in flight.
    * Can be called from another thread without acquiring a |Locker|.
    * Registered |callback| must not reenter interrupted Isolate.
    */
@@ -4691,7 +5070,8 @@
    * Clear interrupt request created by |RequestInterrupt|.
    * Can be called from another thread without acquiring a |Locker|.
    */
-  void ClearInterrupt();
+  V8_DEPRECATED("There's no way to clear interrupts in flight.",
+                void ClearInterrupt());
 
   /**
    * Request garbage collection in this Isolate. It is only valid to call this
@@ -4723,6 +5103,13 @@
    */
   void RemoveCallCompletedCallback(CallCompletedCallback callback);
 
+
+  /**
+   * Set callback to notify about promise reject with no handler, or
+   * revocation of such a previous notification once the handler is added.
+   */
+  void SetPromiseRejectCallback(PromiseRejectCallback callback);
+
   /**
    * Experimental: Runs the Microtask Work Queue until empty
    * Any exceptions thrown by microtask callbacks are swallowed.
@@ -4773,17 +5160,23 @@
 
   /**
    * Optional notification that the embedder is idle.
-   * V8 uses the notification to reduce memory footprint.
+   * V8 uses the notification to perform garbage collection.
    * This call can be used repeatedly if the embedder remains idle.
    * Returns true if the embedder should stop calling IdleNotification
    * until real work has been done.  This indicates that V8 has done
    * as much cleanup as it will be able to do.
    *
-   * The idle_time_in_ms argument specifies the time V8 has to do reduce
-   * the memory footprint. There is no guarantee that the actual work will be
+   * The idle_time_in_ms argument specifies the time V8 has to perform
+   * garbage collection. There is no guarantee that the actual work will be
    * done within the time limit.
+   * The deadline_in_seconds argument specifies the deadline V8 has to finish
+   * garbage collection work. deadline_in_seconds is compared with
+   * MonotonicallyIncreasingTime() and should be based on the same timebase as
+   * that function. There is no guarantee that the actual work will be done
+   * within the time limit.
    */
   bool IdleNotification(int idle_time_in_ms);
+  bool IdleNotificationDeadline(double deadline_in_seconds);
 
   /**
    * Optional notification that the system is running low on memory.
@@ -4796,8 +5189,11 @@
    * these notifications to guide the GC heuristic. Returns the number
    * of context disposals - including this one - since the last time
    * V8 had a chance to clean up.
+   *
+   * The optional parameter |dependant_context| specifies whether the disposed
+   * context was depending on state from other contexts or not.
    */
-  int ContextDisposedNotification();
+  int ContextDisposedNotification(bool dependant_context = true);
 
   /**
    * Allows the host application to provide the address of a function that is
@@ -4835,6 +5231,99 @@
    */
   void SetStackLimit(uintptr_t stack_limit);
 
+  /**
+   * Returns a memory range that can potentially contain jitted code.
+   *
+   * On Win64, embedders are advised to install function table callbacks for
+   * these ranges, as default SEH won't be able to unwind through jitted code.
+   *
+   * The first page of the code range is reserved for the embedder and is
+   * committed, writable, and executable.
+   *
+   * Might be empty on other platforms.
+   *
+   * https://code.google.com/p/v8/issues/detail?id=3598
+   */
+  void GetCodeRange(void** start, size_t* length_in_bytes);
+
+  /** Set the callback to invoke in case of fatal errors. */
+  void SetFatalErrorHandler(FatalErrorCallback that);
+
+  /**
+   * Set the callback to invoke to check if code generation from
+   * strings should be allowed.
+   */
+  void SetAllowCodeGenerationFromStringsCallback(
+      AllowCodeGenerationFromStringsCallback callback);
+
+  /**
+  * Check if V8 is dead and therefore unusable.  This is the case after
+  * fatal errors such as out-of-memory situations.
+  */
+  bool IsDead();
+
+  /**
+   * Adds a message listener.
+   *
+   * The same message listener can be added more than once and in that
+   * case it will be called more than once for each message.
+   *
+   * If data is specified, it will be passed to the callback when it is called.
+   * Otherwise, the exception object will be passed to the callback instead.
+   */
+  bool AddMessageListener(MessageCallback that,
+                          Handle<Value> data = Handle<Value>());
+
+  /**
+   * Remove all message listeners from the specified callback function.
+   */
+  void RemoveMessageListeners(MessageCallback that);
+
+  /** Callback function for reporting failed access checks.*/
+  void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback);
+
+  /**
+   * Tells V8 to capture current stack trace when uncaught exception occurs
+   * and report it to the message listeners. The option is off by default.
+   */
+  void SetCaptureStackTraceForUncaughtExceptions(
+      bool capture, int frame_limit = 10,
+      StackTrace::StackTraceOptions options = StackTrace::kOverview);
+
+  /**
+   * Enables the host application to provide a mechanism to be notified
+   * and perform custom logging when V8 Allocates Executable Memory.
+   */
+  void AddMemoryAllocationCallback(MemoryAllocationCallback callback,
+                                   ObjectSpace space, AllocationAction action);
+
+  /**
+   * Removes callback that was installed by AddMemoryAllocationCallback.
+   */
+  void RemoveMemoryAllocationCallback(MemoryAllocationCallback callback);
+
+  /**
+   * Iterates through all external resources referenced from current isolate
+   * heap.  GC is not invoked prior to iterating, therefore there is no
+   * guarantee that visited objects are still alive.
+   */
+  void VisitExternalResources(ExternalResourceVisitor* visitor);
+
+  /**
+   * Iterates through all the persistent handles in the current isolate's heap
+   * that have class_ids.
+   */
+  void VisitHandlesWithClassIds(PersistentHandleVisitor* visitor);
+
+  /**
+   * Iterates through all the persistent handles in the current isolate's heap
+   * that have class_ids and are candidates to be marked as partially dependent
+   * handles. This will visit handles to young objects created since the last
+   * garbage collection but is free to visit an arbitrary superset of these
+   * objects.
+   */
+  void VisitHandlesForPartialDependence(PersistentHandleVisitor* visitor);
+
  private:
   template<class K, class V, class Traits> friend class PersistentValueMap;
 
@@ -4853,43 +5342,12 @@
 
 class V8_EXPORT StartupData {
  public:
-  enum CompressionAlgorithm {
-    kUncompressed,
-    kBZip2
-  };
-
   const char* data;
-  int compressed_size;
   int raw_size;
 };
 
 
 /**
- * A helper class for driving V8 startup data decompression.  It is based on
- * "CompressedStartupData" API functions from the V8 class.  It isn't mandatory
- * for an embedder to use this class, instead, API functions can be used
- * directly.
- *
- * For an example of the class usage, see the "shell.cc" sample application.
- */
-class V8_EXPORT StartupDataDecompressor {  // NOLINT
- public:
-  StartupDataDecompressor();
-  virtual ~StartupDataDecompressor();
-  int Decompress();
-
- protected:
-  virtual int DecompressData(char* raw_data,
-                             int* raw_data_size,
-                             const char* compressed_data,
-                             int compressed_data_size) = 0;
-
- private:
-  char** raw_data;
-};
-
-
-/**
  * EntropySource is used as a callback function when v8 needs a source
  * of entropy.
  */
@@ -4914,39 +5372,20 @@
 
 
 /**
- * Interface for iterating through all external resources in the heap.
- */
-class V8_EXPORT ExternalResourceVisitor {  // NOLINT
- public:
-  virtual ~ExternalResourceVisitor() {}
-  virtual void VisitExternalString(Handle<String> string) {}
-};
-
-
-/**
- * Interface for iterating through all the persistent handles in the heap.
- */
-class V8_EXPORT PersistentHandleVisitor {  // NOLINT
- public:
-  virtual ~PersistentHandleVisitor() {}
-  virtual void VisitPersistentHandle(Persistent<Value>* value,
-                                     uint16_t class_id) {}
-};
-
-
-/**
  * Container class for static utility functions.
  */
 class V8_EXPORT V8 {
  public:
   /** Set the callback to invoke in case of fatal errors. */
-  static void SetFatalErrorHandler(FatalErrorCallback that);
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void SetFatalErrorHandler(FatalErrorCallback that);
 
   /**
    * Set the callback to invoke to check if code generation from
    * strings should be allowed.
    */
-  static void SetAllowCodeGenerationFromStringsCallback(
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void SetAllowCodeGenerationFromStringsCallback(
       AllowCodeGenerationFromStringsCallback that);
 
   /**
@@ -4958,34 +5397,11 @@
   static void SetArrayBufferAllocator(ArrayBuffer::Allocator* allocator);
 
   /**
-   * Check if V8 is dead and therefore unusable.  This is the case after
-   * fatal errors such as out-of-memory situations.
-   */
-  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
-   *
-   * A helper class StartupDataDecompressor is provided. It implements
-   * the protocol of the interaction described above, and can be used in
-   * most cases instead of calling these API functions directly.
-   */
-  static StartupData::CompressionAlgorithm GetCompressedStartupDataAlgorithm();
-  static int GetCompressedStartupDataCount();
-  static void GetCompressedStartupData(StartupData* compressed_data);
-  static void SetDecompressedStartupData(StartupData* decompressed_data);
+  * Check if V8 is dead and therefore unusable.  This is the case after
+  * fatal errors such as out-of-memory situations.
+  */
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static bool IsDead();
 
   /**
    * Hand startup data to V8, in case the embedder has chosen to build
@@ -5006,6 +5422,13 @@
   static void SetSnapshotDataBlob(StartupData* startup_blob);
 
   /**
+   * Create a new isolate and context for the purpose of capturing a snapshot
+   * Returns { NULL, 0 } on failure.
+   * The caller owns the data array in the return value.
+   */
+  static StartupData CreateSnapshotDataBlob();
+
+  /**
    * Adds a message listener.
    *
    * The same message listener can be added more than once and in that
@@ -5014,21 +5437,23 @@
    * If data is specified, it will be passed to the callback when it is called.
    * Otherwise, the exception object will be passed to the callback instead.
    */
-  static bool AddMessageListener(MessageCallback that,
-                                 Handle<Value> data = Handle<Value>());
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static bool AddMessageListener(
+      MessageCallback that, Handle<Value> data = Handle<Value>());
 
   /**
    * Remove all message listeners from the specified callback function.
    */
-  static void RemoveMessageListeners(MessageCallback that);
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void RemoveMessageListeners(MessageCallback that);
 
   /**
    * Tells V8 to capture current stack trace when uncaught exception occurs
    * and report it to the message listeners. The option is off by default.
    */
-  static void SetCaptureStackTraceForUncaughtExceptions(
-      bool capture,
-      int frame_limit = 10,
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void SetCaptureStackTraceForUncaughtExceptions(
+      bool capture, int frame_limit = 10,
       StackTrace::StackTraceOptions options = StackTrace::kOverview);
 
   /**
@@ -5047,7 +5472,9 @@
   static const char* GetVersion();
 
   /** Callback function for reporting failed access checks.*/
-  static void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback);
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void SetFailedAccessCheckCallbackFunction(
+      FailedAccessCheckCallback);
 
   /**
    * Enables the host application to receive a notification before a
@@ -5059,6 +5486,7 @@
    * register the same callback function two times with different
    * GCType filters.
    */
+  // TODO(dcarney): deprecate this.
   static void AddGCPrologueCallback(
       GCPrologueCallback callback, GCType gc_type_filter = kGCTypeAll);
 
@@ -5066,7 +5494,8 @@
    * This function removes callback which was installed by
    * AddGCPrologueCallback function.
    */
-  static void RemoveGCPrologueCallback(GCPrologueCallback callback);
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void RemoveGCPrologueCallback(GCPrologueCallback callback);
 
   /**
    * Enables the host application to receive a notification after a
@@ -5078,6 +5507,7 @@
    * register the same callback function two times with different
    * GCType filters.
    */
+  // TODO(dcarney): deprecate this.
   static void AddGCEpilogueCallback(
       GCEpilogueCallback callback, GCType gc_type_filter = kGCTypeAll);
 
@@ -5085,20 +5515,24 @@
    * This function removes callback which was installed by
    * AddGCEpilogueCallback function.
    */
-  static void RemoveGCEpilogueCallback(GCEpilogueCallback callback);
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void RemoveGCEpilogueCallback(GCEpilogueCallback callback);
 
   /**
    * Enables the host application to provide a mechanism to be notified
    * and perform custom logging when V8 Allocates Executable Memory.
    */
-  static void AddMemoryAllocationCallback(MemoryAllocationCallback callback,
-                                          ObjectSpace space,
-                                          AllocationAction action);
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void AddMemoryAllocationCallback(
+      MemoryAllocationCallback callback, ObjectSpace space,
+      AllocationAction action);
 
   /**
    * Removes callback that was installed by AddMemoryAllocationCallback.
    */
-  static void RemoveMemoryAllocationCallback(MemoryAllocationCallback callback);
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void RemoveMemoryAllocationCallback(
+      MemoryAllocationCallback callback);
 
   /**
    * Initializes V8. This function needs to be called before the first Isolate
@@ -5128,7 +5562,8 @@
    *
    * \param isolate The isolate in which to terminate the current JS execution.
    */
-  static void TerminateExecution(Isolate* isolate);
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void TerminateExecution(Isolate* isolate);
 
   /**
    * Is V8 terminating JavaScript execution.
@@ -5140,7 +5575,8 @@
    *
    * \param isolate The isolate in which to check.
    */
-  static bool IsExecutionTerminating(Isolate* isolate = NULL);
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static bool IsExecutionTerminating(Isolate* isolate = NULL);
 
   /**
    * Resume execution capability in the given isolate, whose execution
@@ -5158,7 +5594,8 @@
    *
    * \param isolate The isolate in which to resume execution capability.
    */
-  static void CancelTerminateExecution(Isolate* isolate);
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void CancelTerminateExecution(Isolate* isolate);
 
   /**
    * Releases any resources used by v8 and stops any utility threads
@@ -5176,13 +5613,25 @@
    * heap.  GC is not invoked prior to iterating, therefore there is no
    * guarantee that visited objects are still alive.
    */
-  static void VisitExternalResources(ExternalResourceVisitor* visitor);
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void VisitExternalResources(
+      ExternalResourceVisitor* visitor);
 
   /**
    * Iterates through all the persistent handles in the current isolate's heap
    * that have class_ids.
    */
-  static void VisitHandlesWithClassIds(PersistentHandleVisitor* visitor);
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void VisitHandlesWithClassIds(
+      PersistentHandleVisitor* visitor);
+
+  /**
+   * Iterates through all the persistent handles in isolate's heap that have
+   * class_ids.
+   */
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void VisitHandlesWithClassIds(
+      Isolate* isolate, PersistentHandleVisitor* visitor);
 
   /**
    * Iterates through all the persistent handles in the current isolate's heap
@@ -5191,7 +5640,8 @@
    * garbage collection but is free to visit an arbitrary superset of these
    * objects.
    */
-  static void VisitHandlesForPartialDependence(
+  // TODO(dcarney): deprecate this.
+  V8_INLINE static void VisitHandlesForPartialDependence(
       Isolate* isolate, PersistentHandleVisitor* visitor);
 
   /**
@@ -5215,17 +5665,30 @@
    */
   static void ShutdownPlatform();
 
+  /**
+   * Returns the current v8::Platform in use.
+   */
+  static v8::Platform* GetCurrentPlatform();
+
  private:
   V8();
 
+  enum WeakHandleType { PhantomHandle, NonphantomHandle };
+
   static internal::Object** GlobalizeReference(internal::Isolate* isolate,
                                                internal::Object** handle);
   static internal::Object** CopyPersistent(internal::Object** handle);
   static void DisposeGlobal(internal::Object** global_handle);
   typedef WeakCallbackData<Value, void>::Callback WeakCallback;
-  static void MakeWeak(internal::Object** global_handle,
-                       void* data,
+  static void MakeWeak(internal::Object** global_handle, void* data,
                        WeakCallback weak_callback);
+  static void MakePhantom(internal::Object** global_handle, void* data,
+                          PhantomCallbackData<void>::Callback weak_callback);
+  static void MakePhantom(
+      internal::Object** global_handle,
+      InternalFieldsCallbackData<void, void>::Callback weak_callback,
+      int internal_field_index1,
+      int internal_field_index2 = Object::kNoInternalFieldIndex);
   static void* ClearWeak(internal::Object** global_handle);
   static void Eternalize(Isolate* isolate,
                          Value* handle,
@@ -5251,9 +5714,17 @@
    * all TryCatch blocks should be stack allocated because the memory
    * location itself is compared against JavaScript try/catch blocks.
    */
+  // TODO(dcarney): deprecate.
   TryCatch();
 
   /**
+   * Creates a new try/catch block and registers it with v8.  Note that
+   * all TryCatch blocks should be stack allocated because the memory
+   * location itself is compared against JavaScript try/catch blocks.
+   */
+  TryCatch(Isolate* isolate);
+
+  /**
    * Unregisters and deletes this try/catch block.
    */
   ~TryCatch();
@@ -5692,8 +6163,6 @@
   bool top_level_;
   internal::Isolate* isolate_;
 
-  static bool active_;
-
   // Disallow copying and assigning.
   Locker(const Locker&);
   void operator=(const Locker&);
@@ -5802,7 +6271,7 @@
   static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
   static const int kFixedArrayHeaderSize = 2 * kApiPointerSize;
   static const int kContextHeaderSize = 2 * kApiPointerSize;
-  static const int kContextEmbedderDataIndex = 95;
+  static const int kContextEmbedderDataIndex = 76;
   static const int kFullStringRepresentationMask = 0x07;
   static const int kStringEncodingMask = 0x4;
   static const int kExternalTwoByteRepresentationTag = 0x02;
@@ -5820,7 +6289,7 @@
   static const int kNullValueRootIndex = 7;
   static const int kTrueValueRootIndex = 8;
   static const int kFalseValueRootIndex = 9;
-  static const int kEmptyStringRootIndex = 164;
+  static const int kEmptyStringRootIndex = 154;
 
   // The external allocation limit should be below 256 MB on all architectures
   // to avoid that resource-constrained embedders run low on memory.
@@ -5828,14 +6297,14 @@
 
   static const int kNodeClassIdOffset = 1 * kApiPointerSize;
   static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
-  static const int kNodeStateMask = 0xf;
+  static const int kNodeStateMask = 0x7;
   static const int kNodeStateIsWeakValue = 2;
   static const int kNodeStateIsPendingValue = 3;
   static const int kNodeStateIsNearDeathValue = 4;
-  static const int kNodeIsIndependentShift = 4;
-  static const int kNodeIsPartiallyDependentShift = 5;
+  static const int kNodeIsIndependentShift = 3;
+  static const int kNodeIsPartiallyDependentShift = 4;
 
-  static const int kJSObjectType = 0xbc;
+  static const int kJSObjectType = 0xbd;
   static const int kFirstNonstringType = 0x80;
   static const int kOddballType = 0x83;
   static const int kForeignType = 0x88;
@@ -6090,8 +6559,7 @@
     typename WeakCallbackData<S, P>::Callback callback) {
   TYPE_CHECK(S, T);
   typedef typename WeakCallbackData<Value, void>::Callback Callback;
-  V8::MakeWeak(reinterpret_cast<internal::Object**>(this->val_),
-               parameter,
+  V8::MakeWeak(reinterpret_cast<internal::Object**>(this->val_), parameter,
                reinterpret_cast<Callback>(callback));
 }
 
@@ -6106,7 +6574,29 @@
 
 
 template <class T>
-template<typename P>
+template <typename P>
+void PersistentBase<T>::SetPhantom(
+    P* parameter, typename PhantomCallbackData<P>::Callback callback) {
+  typedef typename PhantomCallbackData<void>::Callback Callback;
+  V8::MakePhantom(reinterpret_cast<internal::Object**>(this->val_), parameter,
+                  reinterpret_cast<Callback>(callback));
+}
+
+
+template <class T>
+template <typename U, typename V>
+void PersistentBase<T>::SetPhantom(
+    void (*callback)(const InternalFieldsCallbackData<U, V>&),
+    int internal_field_index1, int internal_field_index2) {
+  typedef typename InternalFieldsCallbackData<void, void>::Callback Callback;
+  V8::MakePhantom(reinterpret_cast<internal::Object**>(this->val_),
+                  reinterpret_cast<Callback>(callback), internal_field_index1,
+                  internal_field_index2);
+}
+
+
+template <class T>
+template <typename P>
 P* PersistentBase<T>::ClearWeak() {
   return reinterpret_cast<P*>(
     V8::ClearWeak(reinterpret_cast<internal::Object**>(this->val_)));
@@ -6133,15 +6623,6 @@
 }
 
 
-template <class T, class M>
-T* Persistent<T, M>::ClearAndLeak() {
-  T* old;
-  old = this->val_;
-  this->val_ = NULL;
-  return old;
-}
-
-
 template <class T>
 void PersistentBase<T>::SetWrapperClassId(uint16_t class_id) {
   typedef internal::Internals I;
@@ -6547,6 +7028,44 @@
 }
 
 
+Local<Boolean> Value::ToBoolean() const {
+  return ToBoolean(Isolate::GetCurrent());
+}
+
+
+Local<Number> Value::ToNumber() const {
+  return ToNumber(Isolate::GetCurrent());
+}
+
+
+Local<String> Value::ToString() const {
+  return ToString(Isolate::GetCurrent());
+}
+
+
+Local<String> Value::ToDetailString() const {
+  return ToDetailString(Isolate::GetCurrent());
+}
+
+
+Local<Object> Value::ToObject() const {
+  return ToObject(Isolate::GetCurrent());
+}
+
+
+Local<Integer> Value::ToInteger() const {
+  return ToInteger(Isolate::GetCurrent());
+}
+
+
+Local<Uint32> Value::ToUint32() const {
+  return ToUint32(Isolate::GetCurrent());
+}
+
+
+Local<Int32> Value::ToInt32() const { return ToInt32(Isolate::GetCurrent()); }
+
+
 Name* Name::Cast(v8::Value* value) {
 #ifdef V8_ENABLE_CHECKS
   CheckCast(value);
@@ -6937,6 +7456,119 @@
 }
 
 
+void V8::SetAllowCodeGenerationFromStringsCallback(
+    AllowCodeGenerationFromStringsCallback callback) {
+  Isolate* isolate = Isolate::GetCurrent();
+  isolate->SetAllowCodeGenerationFromStringsCallback(callback);
+}
+
+
+bool V8::IsDead() {
+  Isolate* isolate = Isolate::GetCurrent();
+  return isolate->IsDead();
+}
+
+
+bool V8::AddMessageListener(MessageCallback that, Handle<Value> data) {
+  Isolate* isolate = Isolate::GetCurrent();
+  return isolate->AddMessageListener(that, data);
+}
+
+
+void V8::RemoveMessageListeners(MessageCallback that) {
+  Isolate* isolate = Isolate::GetCurrent();
+  isolate->RemoveMessageListeners(that);
+}
+
+
+void V8::SetFailedAccessCheckCallbackFunction(
+    FailedAccessCheckCallback callback) {
+  Isolate* isolate = Isolate::GetCurrent();
+  isolate->SetFailedAccessCheckCallbackFunction(callback);
+}
+
+
+void V8::SetCaptureStackTraceForUncaughtExceptions(
+    bool capture, int frame_limit, StackTrace::StackTraceOptions options) {
+  Isolate* isolate = Isolate::GetCurrent();
+  isolate->SetCaptureStackTraceForUncaughtExceptions(capture, frame_limit,
+                                                     options);
+}
+
+
+void V8::SetFatalErrorHandler(FatalErrorCallback callback) {
+  Isolate* isolate = Isolate::GetCurrent();
+  isolate->SetFatalErrorHandler(callback);
+}
+
+
+void V8::RemoveGCPrologueCallback(GCPrologueCallback callback) {
+  Isolate* isolate = Isolate::GetCurrent();
+  isolate->RemoveGCPrologueCallback(
+      reinterpret_cast<v8::Isolate::GCPrologueCallback>(callback));
+}
+
+
+void V8::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
+  Isolate* isolate = Isolate::GetCurrent();
+  isolate->RemoveGCEpilogueCallback(
+      reinterpret_cast<v8::Isolate::GCEpilogueCallback>(callback));
+}
+
+
+void V8::AddMemoryAllocationCallback(MemoryAllocationCallback callback,
+                                     ObjectSpace space,
+                                     AllocationAction action) {
+  Isolate* isolate = Isolate::GetCurrent();
+  isolate->AddMemoryAllocationCallback(callback, space, action);
+}
+
+
+void V8::RemoveMemoryAllocationCallback(MemoryAllocationCallback callback) {
+  Isolate* isolate = Isolate::GetCurrent();
+  isolate->RemoveMemoryAllocationCallback(callback);
+}
+
+
+void V8::TerminateExecution(Isolate* isolate) { isolate->TerminateExecution(); }
+
+
+bool V8::IsExecutionTerminating(Isolate* isolate) {
+  if (isolate == NULL) {
+    isolate = Isolate::GetCurrent();
+  }
+  return isolate->IsExecutionTerminating();
+}
+
+
+void V8::CancelTerminateExecution(Isolate* isolate) {
+  isolate->CancelTerminateExecution();
+}
+
+
+void V8::VisitExternalResources(ExternalResourceVisitor* visitor) {
+  Isolate* isolate = Isolate::GetCurrent();
+  isolate->VisitExternalResources(visitor);
+}
+
+
+void V8::VisitHandlesWithClassIds(PersistentHandleVisitor* visitor) {
+  Isolate* isolate = Isolate::GetCurrent();
+  isolate->VisitHandlesWithClassIds(visitor);
+}
+
+
+void V8::VisitHandlesWithClassIds(Isolate* isolate,
+                                  PersistentHandleVisitor* visitor) {
+  isolate->VisitHandlesWithClassIds(visitor);
+}
+
+
+void V8::VisitHandlesForPartialDependence(Isolate* isolate,
+                                          PersistentHandleVisitor* visitor) {
+  isolate->VisitHandlesForPartialDependence(visitor);
+}
+
 /**
  * \example shell.cc
  * A simple shell that takes a list of expressions on the
diff --git a/include/v8config.h b/include/v8config.h
index 87de994..d1ca22c 100644
--- a/include/v8config.h
+++ b/include/v8config.h
@@ -120,7 +120,6 @@
 //  V8_LIBC_BIONIC  - Bionic libc
 //  V8_LIBC_BSD     - BSD libc derivate
 //  V8_LIBC_GLIBC   - GNU C library
-//  V8_LIBC_UCLIBC  - uClibc
 //
 // Note that testing for libc must be done using #if not #ifdef. For example,
 // to test for the GNU C library, use:
@@ -133,8 +132,6 @@
 #elif defined(__BIONIC__)
 # define V8_LIBC_BIONIC 1
 # define V8_LIBC_BSD 1
-#elif defined(__UCLIBC__)
-# define V8_LIBC_UCLIBC 1
 #elif defined(__GLIBC__) || defined(__GNU_LIBRARY__)
 # define V8_LIBC_GLIBC 1
 #else
@@ -145,13 +142,12 @@
 // -----------------------------------------------------------------------------
 // Compiler detection
 //
-//  V8_CC_CLANG   - Clang
-//  V8_CC_GNU     - GNU C++
+//  V8_CC_GNU     - GCC, or clang in gcc mode
 //  V8_CC_INTEL   - Intel C++
 //  V8_CC_MINGW   - Minimalist GNU for Windows
 //  V8_CC_MINGW32 - Minimalist GNU for Windows (mingw32)
 //  V8_CC_MINGW64 - Minimalist GNU for Windows (mingw-w64)
-//  V8_CC_MSVC    - Microsoft Visual C/C++
+//  V8_CC_MSVC    - Microsoft Visual C/C++, or clang in cl.exe mode
 //
 // C++11 feature detection
 //
@@ -178,6 +174,7 @@
 //  V8_HAS_BUILTIN_CLZ                  - __builtin_clz() supported
 //  V8_HAS_BUILTIN_CTZ                  - __builtin_ctz() supported
 //  V8_HAS_BUILTIN_EXPECT               - __builtin_expect() supported
+//  V8_HAS_BUILTIN_FRAME_ADDRESS        - __builtin_frame_address() supported
 //  V8_HAS_BUILTIN_POPCOUNT             - __builtin_popcount() supported
 //  V8_HAS_BUILTIN_SADD_OVERFLOW        - __builtin_sadd_overflow() supported
 //  V8_HAS_BUILTIN_SSUB_OVERFLOW        - __builtin_ssub_overflow() supported
@@ -186,7 +183,6 @@
 //  V8_HAS_DECLSPEC_NOINLINE            - __declspec(noinline) supported
 //  V8_HAS___FINAL                      - __final supported in non-C++11 mode
 //  V8_HAS___FORCEINLINE                - __forceinline supported
-//  V8_HAS_SEALED                       - MSVC style sealed marker supported
 //
 // Note that testing for compilers and/or features must be done using #if
 // not #ifdef. For example, to test for Intel C++ Compiler, use:
@@ -196,7 +192,11 @@
 
 #if defined(__clang__)
 
-# define V8_CC_CLANG 1
+#if defined(__GNUC__)  // Clang in gcc mode.
+# define V8_CC_GNU 1
+#elif defined(_MSC_VER)  // Clang in cl mode.
+# define V8_CC_MSVC 1
+#endif
 
 // Clang defines __alignof__ as alias for __alignof
 # define V8_HAS___ALIGNOF 1
@@ -214,6 +214,7 @@
 # define V8_HAS_BUILTIN_CLZ (__has_builtin(__builtin_clz))
 # define V8_HAS_BUILTIN_CTZ (__has_builtin(__builtin_ctz))
 # define V8_HAS_BUILTIN_EXPECT (__has_builtin(__builtin_expect))
+# define V8_HAS_BUILTIN_FRAME_ADDRESS (__has_builtin(__builtin_frame_address))
 # define V8_HAS_BUILTIN_POPCOUNT (__has_builtin(__builtin_popcount))
 # define V8_HAS_BUILTIN_SADD_OVERFLOW (__has_builtin(__builtin_sadd_overflow))
 # define V8_HAS_BUILTIN_SSUB_OVERFLOW (__has_builtin(__builtin_ssub_overflow))
@@ -251,6 +252,7 @@
 # define V8_HAS_BUILTIN_CLZ (V8_GNUC_PREREQ(3, 4, 0))
 # define V8_HAS_BUILTIN_CTZ (V8_GNUC_PREREQ(3, 4, 0))
 # define V8_HAS_BUILTIN_EXPECT (V8_GNUC_PREREQ(2, 96, 0))
+# define V8_HAS_BUILTIN_FRAME_ADDRESS (V8_GNUC_PREREQ(2, 96, 0))
 # define V8_HAS_BUILTIN_POPCOUNT (V8_GNUC_PREREQ(3, 4, 0))
 
 // g++ requires -std=c++0x or -std=gnu++0x to support C++11 functionality
@@ -277,14 +279,11 @@
 
 # define V8_HAS___ALIGNOF 1
 
-// Override control was added with Visual Studio 2005, but
-// Visual Studio 2010 and earlier spell "final" as "sealed".
-# define V8_HAS_CXX11_FINAL (_MSC_VER >= 1700)
-# define V8_HAS_CXX11_OVERRIDE (_MSC_VER >= 1400)
-# define V8_HAS_SEALED (_MSC_VER >= 1400)
+# define V8_HAS_CXX11_FINAL 1
+# define V8_HAS_CXX11_OVERRIDE 1
 
 # define V8_HAS_DECLSPEC_ALIGN 1
-# define V8_HAS_DECLSPEC_DEPRECATED (_MSC_VER >= 1300)
+# define V8_HAS_DECLSPEC_DEPRECATED 1
 # define V8_HAS_DECLSPEC_NOINLINE 1
 
 # define V8_HAS___FORCEINLINE 1
diff --git a/include/v8stdint.h b/include/v8stdint.h
deleted file mode 100644
index 9a935dd..0000000
--- a/include/v8stdint.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Load definitions of standard types.
-
-#ifndef V8STDINT_H_
-#define V8STDINT_H_
-
-#include <stddef.h>
-#include <stdio.h>
-
-#include "v8config.h"
-
-#if V8_OS_WIN && !V8_CC_MINGW
-
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef short int16_t;  // NOLINT
-typedef unsigned short uint16_t;  // NOLINT
-typedef int int32_t;
-typedef unsigned int uint32_t;
-typedef __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-// intptr_t and friends are defined in crtdefs.h through stdio.h.
-
-#else
-
-#include <stdint.h>  // NOLINT
-
-#endif
-
-#endif  // V8STDINT_H_
diff --git a/samples/process.cc b/samples/process.cc
index e5c9b7a..f447970 100644
--- a/samples/process.cc
+++ b/samples/process.cc
@@ -32,10 +32,6 @@
 #include <map>
 #include <string>
 
-#ifdef COMPRESS_STARTUP_DATA_BZ2
-#error Using compressed startup data is not supported for this sample
-#endif
-
 using namespace std;
 using namespace v8;
 
@@ -116,10 +112,8 @@
                            const PropertyCallbackInfo<Value>& info);
 
   // Callbacks that access maps
-  static void MapGet(Local<String> name,
-                     const PropertyCallbackInfo<Value>& info);
-  static void MapSet(Local<String> name,
-                     Local<Value> value,
+  static void MapGet(Local<Name> name, const PropertyCallbackInfo<Value>& info);
+  static void MapSet(Local<Name> name, Local<Value> value,
                      const PropertyCallbackInfo<Value>& info);
 
   // Utility methods for wrapping C++ objects as JavaScript objects,
@@ -359,13 +353,15 @@
 }
 
 
-void JsHttpRequestProcessor::MapGet(Local<String> name,
+void JsHttpRequestProcessor::MapGet(Local<Name> name,
                                     const PropertyCallbackInfo<Value>& info) {
+  if (name->IsSymbol()) return;
+
   // Fetch the map wrapped by this object.
   map<string, string>* obj = UnwrapMap(info.Holder());
 
   // Convert the JavaScript string to a std::string.
-  string key = ObjectToString(name);
+  string key = ObjectToString(Local<String>::Cast(name));
 
   // Look up the value if it exists using the standard STL ideom.
   map<string, string>::iterator iter = obj->find(key);
@@ -381,14 +377,15 @@
 }
 
 
-void JsHttpRequestProcessor::MapSet(Local<String> name,
-                                    Local<Value> value_obj,
+void JsHttpRequestProcessor::MapSet(Local<Name> name, Local<Value> value_obj,
                                     const PropertyCallbackInfo<Value>& info) {
+  if (name->IsSymbol()) return;
+
   // Fetch the map wrapped by this object.
   map<string, string>* obj = UnwrapMap(info.Holder());
 
   // Convert the key and value to std::strings.
-  string key = ObjectToString(name);
+  string key = ObjectToString(Local<String>::Cast(name));
   string value = ObjectToString(value_obj);
 
   // Update the map.
@@ -405,7 +402,7 @@
 
   Local<ObjectTemplate> result = ObjectTemplate::New(isolate);
   result->SetInternalFieldCount(1);
-  result->SetNamedPropertyHandler(MapGet, MapSet);
+  result->SetHandler(NamedPropertyHandlerConfiguration(MapGet, MapSet));
 
   // Again, return the result through the current handle scope.
   return handle_scope.Escape(result);
diff --git a/samples/samples.gyp b/samples/samples.gyp
index 0c4c705..31e96f4 100644
--- a/samples/samples.gyp
+++ b/samples/samples.gyp
@@ -67,11 +67,5 @@
         'process.cc',
       ],
     },
-    {
-      'target_name': 'lineprocessor',
-      'sources': [
-        'lineprocessor.cc',
-      ],
-    }
   ],
 }
diff --git a/samples/shell.cc b/samples/shell.cc
index b66e8f7..1a08aff 100644
--- a/samples/shell.cc
+++ b/samples/shell.cc
@@ -35,10 +35,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#ifdef COMPRESS_STARTUP_DATA_BZ2
-#error Using compressed startup data is not supported for this sample
-#endif
-
 /**
  * This sample program shows how to implement a simple javascript shell
  * based on V8.  This includes initializing V8 with command line options,
diff --git a/src/DEPS b/src/DEPS
index 260f5b2..4dbb3c7 100644
--- a/src/DEPS
+++ b/src/DEPS
@@ -3,8 +3,7 @@
   "-src/compiler",
   "+src/compiler/pipeline.h",
   "-src/libplatform",
-  "-include/libplatform",
-  "+testing",
+  "-include/libplatform"
 ]
 
 specific_include_rules = {
diff --git a/src/accessors.cc b/src/accessors.cc
index 011372c..662a9e1 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -56,17 +56,6 @@
 }
 
 
-template <class C>
-static C* FindInstanceOf(Isolate* isolate, Object* obj) {
-  for (PrototypeIterator iter(isolate, obj,
-                              PrototypeIterator::START_AT_RECEIVER);
-       !iter.IsAtEnd(); iter.Advance()) {
-    if (Is<C>(iter.GetCurrent())) return C::cast(iter.GetCurrent());
-  }
-  return NULL;
-}
-
-
 static V8_INLINE bool CheckForName(Handle<Name> name,
                                    Handle<String> property_name,
                                    int offset,
@@ -183,13 +172,16 @@
   LookupIterator it(object, Utils::OpenHandle(*name));
   CHECK_EQ(LookupIterator::ACCESSOR, it.state());
   DCHECK(it.HolderIsReceiverOrHiddenPrototype());
-  Object::SetDataProperty(&it, value);
+
+  if (Object::SetDataProperty(&it, value).is_null()) {
+    isolate->OptionalRescheduleException(false);
+  }
 }
 
 
 Handle<AccessorInfo> Accessors::ArgumentsIteratorInfo(
     Isolate* isolate, PropertyAttributes attributes) {
-  Handle<Name> name(isolate->native_context()->iterator_symbol(), isolate);
+  Handle<Name> name = isolate->factory()->iterator_symbol();
   return MakeAccessor(isolate, name, &ArgumentsIteratorGetter,
                       &ArgumentsIteratorSetter, attributes);
 }
@@ -258,7 +250,7 @@
 
   if (uint32_v->Number() == number_v->Number()) {
     maybe = JSArray::SetElementsLength(array_handle, uint32_v);
-    maybe.Check();
+    if (maybe.is_null()) isolate->OptionalRescheduleException(false);
     return;
   }
 
@@ -330,6 +322,98 @@
 }
 
 
+template <typename Char>
+inline int CountRequiredEscapes(Handle<String> source) {
+  DisallowHeapAllocation no_gc;
+  int escapes = 0;
+  Vector<const Char> src = source->GetCharVector<Char>();
+  for (int i = 0; i < src.length(); i++) {
+    if (src[i] == '/' && (i == 0 || src[i - 1] != '\\')) escapes++;
+  }
+  return escapes;
+}
+
+
+template <typename Char, typename StringType>
+inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source,
+                                                   Handle<StringType> result) {
+  DisallowHeapAllocation no_gc;
+  Vector<const Char> src = source->GetCharVector<Char>();
+  Vector<Char> dst(result->GetChars(), result->length());
+  int s = 0;
+  int d = 0;
+  while (s < src.length()) {
+    if (src[s] == '/' && (s == 0 || src[s - 1] != '\\')) dst[d++] = '\\';
+    dst[d++] = src[s++];
+  }
+  DCHECK_EQ(result->length(), d);
+  return result;
+}
+
+
+MaybeHandle<String> EscapeRegExpSource(Isolate* isolate,
+                                       Handle<String> source) {
+  String::Flatten(source);
+  if (source->length() == 0) return isolate->factory()->query_colon_string();
+  bool one_byte = source->IsOneByteRepresentationUnderneath();
+  int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source)
+                         : CountRequiredEscapes<uc16>(source);
+  if (escapes == 0) return source;
+  int length = source->length() + escapes;
+  if (one_byte) {
+    Handle<SeqOneByteString> result;
+    ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
+                               isolate->factory()->NewRawOneByteString(length),
+                               String);
+    return WriteEscapedRegExpSource<uint8_t>(source, result);
+  } else {
+    Handle<SeqTwoByteString> result;
+    ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
+                               isolate->factory()->NewRawTwoByteString(length),
+                               String);
+    return WriteEscapedRegExpSource<uc16>(source, result);
+  }
+}
+
+
+// Implements ECMA262 ES6 draft 21.2.5.9
+void Accessors::RegExpSourceGetter(
+    v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
+  HandleScope scope(isolate);
+
+  Handle<Object> holder =
+      Utils::OpenHandle(*v8::Local<v8::Value>(info.Holder()));
+  Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(holder);
+  Handle<String> result;
+  if (regexp->TypeTag() == JSRegExp::NOT_COMPILED) {
+    result = isolate->factory()->empty_string();
+  } else {
+    Handle<String> pattern(regexp->Pattern(), isolate);
+    MaybeHandle<String> maybe = EscapeRegExpSource(isolate, pattern);
+    if (!maybe.ToHandle(&result)) {
+      isolate->OptionalRescheduleException(false);
+      return;
+    }
+  }
+  info.GetReturnValue().Set(Utils::ToLocal(result));
+}
+
+
+void Accessors::RegExpSourceSetter(v8::Local<v8::Name> name,
+                                   v8::Local<v8::Value> value,
+                                   const v8::PropertyCallbackInfo<void>& info) {
+  UNREACHABLE();
+}
+
+
+Handle<AccessorInfo> Accessors::RegExpSourceInfo(
+    Isolate* isolate, PropertyAttributes attributes) {
+  return MakeAccessor(isolate, isolate->factory()->source_string(),
+                      &RegExpSourceGetter, &RegExpSourceSetter, attributes);
+}
+
+
 //
 // Accessors::ScriptColumnOffset
 //
@@ -892,9 +976,8 @@
 }
 
 
-static Handle<Object> SetFunctionPrototype(Isolate* isolate,
-                                           Handle<JSFunction> function,
-                                           Handle<Object> value) {
+MUST_USE_RESULT static MaybeHandle<Object> SetFunctionPrototype(
+    Isolate* isolate, Handle<JSFunction> function, Handle<Object> value) {
   Handle<Object> old_value;
   bool is_observed = function->map()->is_observed();
   if (is_observed) {
@@ -908,21 +991,17 @@
   DCHECK(function->prototype() == *value);
 
   if (is_observed && !old_value->SameValue(*value)) {
-    JSObject::EnqueueChangeRecord(
+    MaybeHandle<Object> result = JSObject::EnqueueChangeRecord(
         function, "update", isolate->factory()->prototype_string(), old_value);
+    if (result.is_null()) return MaybeHandle<Object>();
   }
 
   return function;
 }
 
 
-Handle<Object> Accessors::FunctionGetPrototype(Handle<JSFunction> function) {
-  return GetFunctionPrototype(function->GetIsolate(), function);
-}
-
-
-Handle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function,
-                                               Handle<Object> prototype) {
+MaybeHandle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function,
+                                                    Handle<Object> prototype) {
   DCHECK(function->should_have_prototype());
   Isolate* isolate = function->GetIsolate();
   return SetFunctionPrototype(isolate, function, prototype);
@@ -953,7 +1032,9 @@
   }
   Handle<JSFunction> object =
       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
-  SetFunctionPrototype(isolate, object, value);
+  if (SetFunctionPrototype(isolate, object, value).is_null()) {
+    isolate->OptionalRescheduleException(false);
+  }
 }
 
 
diff --git a/src/accessors.h b/src/accessors.h
index 8fc1f84..0210d53 100644
--- a/src/accessors.h
+++ b/src/accessors.h
@@ -21,6 +21,7 @@
   V(FunctionName)                 \
   V(FunctionLength)               \
   V(FunctionPrototype)            \
+  V(RegExpSource)                 \
   V(ScriptColumnOffset)           \
   V(ScriptCompilationType)        \
   V(ScriptContextData)            \
@@ -66,9 +67,8 @@
   };
 
   // Accessor functions called directly from the runtime system.
-  static Handle<Object> FunctionSetPrototype(Handle<JSFunction> object,
-                                             Handle<Object> value);
-  static Handle<Object> FunctionGetPrototype(Handle<JSFunction> object);
+  MUST_USE_RESULT static MaybeHandle<Object> FunctionSetPrototype(
+      Handle<JSFunction> object, Handle<Object> value);
   static Handle<Object> FunctionGetArguments(Handle<JSFunction> object);
 
   // Accessor infos.
diff --git a/src/allocation.cc b/src/allocation.cc
index cae1c10..96fd71f 100644
--- a/src/allocation.cc
+++ b/src/allocation.cc
@@ -85,7 +85,7 @@
 
 void* AlignedAlloc(size_t size, size_t alignment) {
   DCHECK_LE(V8_ALIGNOF(void*), alignment);
-  DCHECK(base::bits::IsPowerOfTwo32(alignment));
+  DCHECK(base::bits::IsPowerOfTwo64(alignment));
   void* ptr;
 #if V8_OS_WIN
   ptr = _aligned_malloc(size, alignment);
diff --git a/src/api.cc b/src/api.cc
index e11d140..a459076 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -14,6 +14,7 @@
 #include "include/v8-testing.h"
 #include "src/assert-scope.h"
 #include "src/background-parsing-task.h"
+#include "src/base/functional.h"
 #include "src/base/platform/platform.h"
 #include "src/base/platform/time.h"
 #include "src/base/utils/random-number-generator.h"
@@ -38,8 +39,9 @@
 #include "src/property.h"
 #include "src/property-details.h"
 #include "src/prototype.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 #include "src/runtime-profiler.h"
+#include "src/sampler.h"
 #include "src/scanner-character-streams.h"
 #include "src/simulator.h"
 #include "src/snapshot.h"
@@ -51,9 +53,8 @@
 
 #define LOG_API(isolate, expr) LOG(isolate, ApiEntryCall(expr))
 
-#define ENTER_V8(isolate)                                          \
-  DCHECK((isolate)->IsInitialized());                              \
-  i::VMState<i::OTHER> __state__((isolate))
+#define ENTER_V8(isolate)             \
+  i::VMState<v8::OTHER> __state__((isolate))
 
 namespace v8 {
 
@@ -186,14 +187,7 @@
 }
 
 
-bool V8::IsDead() {
-  i::Isolate* isolate = i::Isolate::Current();
-  return isolate->IsDead();
-}
-
-
 static inline bool IsExecutionTerminatingCheck(i::Isolate* isolate) {
-  if (!isolate->IsInitialized()) return false;
   if (isolate->has_scheduled_exception()) {
     return isolate->scheduled_exception() ==
         isolate->heap()->termination_exception();
@@ -202,162 +196,60 @@
 }
 
 
-StartupDataDecompressor::StartupDataDecompressor()
-    : raw_data(i::NewArray<char*>(V8::GetCompressedStartupDataCount())) {
-  for (int i = 0; i < V8::GetCompressedStartupDataCount(); ++i) {
-    raw_data[i] = NULL;
-  }
-}
-
-
-StartupDataDecompressor::~StartupDataDecompressor() {
-  for (int i = 0; i < V8::GetCompressedStartupDataCount(); ++i) {
-    i::DeleteArray(raw_data[i]);
-  }
-  i::DeleteArray(raw_data);
-}
-
-
-int StartupDataDecompressor::Decompress() {
-  int compressed_data_count = V8::GetCompressedStartupDataCount();
-  StartupData* compressed_data =
-      i::NewArray<StartupData>(compressed_data_count);
-  V8::GetCompressedStartupData(compressed_data);
-  for (int i = 0; i < compressed_data_count; ++i) {
-    char* decompressed = raw_data[i] =
-        i::NewArray<char>(compressed_data[i].raw_size);
-    if (compressed_data[i].compressed_size != 0) {
-      int result = DecompressData(decompressed,
-                                  &compressed_data[i].raw_size,
-                                  compressed_data[i].data,
-                                  compressed_data[i].compressed_size);
-      if (result != 0) return result;
-    } else {
-      DCHECK_EQ(0, compressed_data[i].raw_size);
-    }
-    compressed_data[i].data = decompressed;
-  }
-  V8::SetDecompressedStartupData(compressed_data);
-  i::DeleteArray(compressed_data);
-  return 0;
-}
-
-
-StartupData::CompressionAlgorithm V8::GetCompressedStartupDataAlgorithm() {
-#ifdef COMPRESS_STARTUP_DATA_BZ2
-  return StartupData::kBZip2;
-#else
-  return StartupData::kUncompressed;
-#endif
-}
-
-
-enum CompressedStartupDataItems {
-  kSnapshot = 0,
-  kSnapshotContext,
-  kLibraries,
-  kExperimentalLibraries,
-  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();
-
-  i::Vector<const i::byte> libraries_source = i::Natives::GetScriptsSource();
-  compressed_data[kLibraries].data =
-      reinterpret_cast<const char*>(libraries_source.start());
-  compressed_data[kLibraries].compressed_size = libraries_source.length();
-  compressed_data[kLibraries].raw_size = i::Natives::GetRawScriptsSize();
-
-  i::Vector<const i::byte> exp_libraries_source =
-      i::ExperimentalNatives::GetScriptsSource();
-  compressed_data[kExperimentalLibraries].data =
-      reinterpret_cast<const char*>(exp_libraries_source.start());
-  compressed_data[kExperimentalLibraries].compressed_size =
-      exp_libraries_source.length();
-  compressed_data[kExperimentalLibraries].raw_size =
-      i::ExperimentalNatives::GetRawScriptsSize();
-#endif
-}
-
-
-void V8::SetDecompressedStartupData(StartupData* decompressed_data) {
-#ifdef COMPRESS_STARTUP_DATA_BZ2
-  DCHECK_EQ(i::Snapshot::raw_size(), decompressed_data[kSnapshot].raw_size);
-  i::Snapshot::set_raw_data(
-      reinterpret_cast<const i::byte*>(decompressed_data[kSnapshot].data));
-
-  DCHECK_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));
-
-  DCHECK_EQ(i::Natives::GetRawScriptsSize(),
-            decompressed_data[kLibraries].raw_size);
-  i::Vector<const char> libraries_source(
-      decompressed_data[kLibraries].data,
-      decompressed_data[kLibraries].raw_size);
-  i::Natives::SetRawScriptsSource(libraries_source);
-
-  DCHECK_EQ(i::ExperimentalNatives::GetRawScriptsSize(),
-            decompressed_data[kExperimentalLibraries].raw_size);
-  i::Vector<const char> exp_libraries_source(
-      decompressed_data[kExperimentalLibraries].data,
-      decompressed_data[kExperimentalLibraries].raw_size);
-  i::ExperimentalNatives::SetRawScriptsSource(exp_libraries_source);
-#endif
-}
-
-
 void V8::SetNativesDataBlob(StartupData* natives_blob) {
-#ifdef V8_USE_EXTERNAL_STARTUP_DATA
-  i::SetNativesFromFile(natives_blob);
-#else
-  CHECK(false);
-#endif
+  i::V8::SetNativesBlob(natives_blob);
 }
 
 
 void V8::SetSnapshotDataBlob(StartupData* snapshot_blob) {
-#ifdef V8_USE_EXTERNAL_STARTUP_DATA
-  i::SetSnapshotFromFile(snapshot_blob);
-#else
-  CHECK(false);
-#endif
+  i::V8::SetSnapshotBlob(snapshot_blob);
 }
 
 
-void V8::SetFatalErrorHandler(FatalErrorCallback that) {
-  i::Isolate* isolate = i::Isolate::Current();
-  isolate->set_exception_behavior(that);
-}
+StartupData V8::CreateSnapshotDataBlob() {
+  Isolate::CreateParams params;
+  params.enable_serializer = true;
+  Isolate* isolate = v8::Isolate::New(params);
+  StartupData result = {NULL, 0};
+  {
+    Isolate::Scope isolate_scope(isolate);
+    i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
+    Persistent<Context> context;
+    {
+      HandleScope handle_scope(isolate);
+      context.Reset(isolate, Context::New(isolate));
+    }
+    if (!context.IsEmpty()) {
+      // Make sure all builtin scripts are cached.
+      {
+        HandleScope scope(isolate);
+        for (int i = 0; i < i::Natives::GetBuiltinsCount(); i++) {
+          internal_isolate->bootstrapper()->NativesSourceLookup(i);
+        }
+      }
+      // If we don't do this then we end up with a stray root pointing at the
+      // context even after we have disposed of the context.
+      internal_isolate->heap()->CollectAllAvailableGarbage("mksnapshot");
+      i::Object* raw_context = *v8::Utils::OpenPersistent(context);
+      context.Reset();
 
+      i::SnapshotByteSink snapshot_sink;
+      i::StartupSerializer ser(internal_isolate, &snapshot_sink);
+      ser.SerializeStrongReferences();
 
-void V8::SetAllowCodeGenerationFromStringsCallback(
-    AllowCodeGenerationFromStringsCallback callback) {
-  i::Isolate* isolate = i::Isolate::Current();
-  isolate->set_allow_code_gen_callback(callback);
+      i::SnapshotByteSink context_sink;
+      i::PartialSerializer context_ser(internal_isolate, &ser, &context_sink);
+      context_ser.Serialize(&raw_context);
+      ser.SerializeWeakReferences();
+
+      i::SnapshotData sd(snapshot_sink, ser);
+      i::SnapshotData csd(context_sink, context_ser);
+
+      result = i::Snapshot::CreateSnapshotBlob(sd.RawData(), csd.RawData());
+    }
+  }
+  isolate->Dispose();
+  return result;
 }
 
 
@@ -494,26 +386,40 @@
 i::Object** V8::GlobalizeReference(i::Isolate* isolate, i::Object** obj) {
   LOG_API(isolate, "Persistent::New");
   i::Handle<i::Object> result = isolate->global_handles()->Create(*obj);
-#ifdef DEBUG
+#ifdef VERIFY_HEAP
   (*obj)->ObjectVerify();
-#endif  // DEBUG
+#endif  // VERIFY_HEAP
   return result.location();
 }
 
 
 i::Object** V8::CopyPersistent(i::Object** obj) {
   i::Handle<i::Object> result = i::GlobalHandles::CopyGlobal(obj);
-#ifdef DEBUG
+#ifdef VERIFY_HEAP
   (*obj)->ObjectVerify();
-#endif  // DEBUG
+#endif  // VERIFY_HEAP
   return result.location();
 }
 
 
-void V8::MakeWeak(i::Object** object,
-                  void* parameters,
+void V8::MakeWeak(i::Object** object, void* parameter,
                   WeakCallback weak_callback) {
-  i::GlobalHandles::MakeWeak(object, parameters, weak_callback);
+  i::GlobalHandles::MakeWeak(object, parameter, weak_callback);
+}
+
+
+void V8::MakePhantom(i::Object** object, void* parameter,
+                     PhantomCallbackData<void>::Callback weak_callback) {
+  i::GlobalHandles::MakePhantom(object, parameter, weak_callback);
+}
+
+
+void V8::MakePhantom(
+    i::Object** object,
+    InternalFieldsCallbackData<void, void>::Callback weak_callback,
+    int internal_field_index1, int internal_field_index2) {
+  i::GlobalHandles::MakePhantom(object, weak_callback, internal_field_index1,
+                                internal_field_index2);
 }
 
 
@@ -750,11 +656,11 @@
 // about this there is no HandleScope in this method.  When you add one to the
 // site calling this method you should check that you ensured the VM was not
 // dead first.
-void NeanderArray::add(i::Handle<i::Object> value) {
+void NeanderArray::add(i::Isolate* isolate, i::Handle<i::Object> value) {
   int length = this->length();
   int size = obj_.size();
   if (length == size - 1) {
-    i::Factory* factory = i::Isolate::Current()->factory();
+    i::Factory* factory = isolate->factory();
     i::Handle<i::FixedArray> new_elms = factory->NewFixedArray(2 * size);
     for (int i = 0; i < length; i++)
       new_elms->set(i + 1, get(i));
@@ -789,12 +695,12 @@
     Utils::OpenHandle(templ)->set_property_list(*list);
   }
   NeanderArray array(list);
-  array.add(isolate->factory()->NewNumberFromInt(length));
+  array.add(isolate, isolate->factory()->NewNumberFromInt(length));
   for (int i = 0; i < length; i++) {
     i::Handle<i::Object> value = data[i].IsEmpty() ?
         i::Handle<i::Object>(isolate->factory()->undefined_value()) :
         Utils::OpenHandle(*data[i]);
-    array.add(value);
+    array.add(isolate, value);
   }
 }
 
@@ -802,7 +708,7 @@
 void Template::Set(v8::Handle<Name> name,
                    v8::Handle<Data> value,
                    v8::PropertyAttribute attribute) {
-  i::Isolate* isolate = i::Isolate::Current();
+  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
   const int kSize = 3;
@@ -908,6 +814,9 @@
     v8::Handle<Signature> signature,
     int length) {
   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+  // Changes to the environment cannot be captured in the snapshot. Expect no
+  // function templates when the isolate is created for serialization.
+  DCHECK(!i_isolate->serializer_enabled());
   LOG_API(i_isolate, "FunctionTemplate::New");
   ENTER_V8(i_isolate);
   return FunctionTemplateNew(
@@ -1084,11 +993,9 @@
 
 
 int TypeSwitch::match(v8::Handle<Value> value) {
-  i::Isolate* isolate = i::Isolate::Current();
-  LOG_API(isolate, "TypeSwitch::match");
-  USE(isolate);
-  i::Handle<i::Object> obj = Utils::OpenHandle(*value);
   i::Handle<i::TypeSwitchInfo> info = Utils::OpenHandle(this);
+  LOG_API(info->GetIsolate(), "TypeSwitch::match");
+  i::Handle<i::Object> obj = Utils::OpenHandle(*value);
   i::FixedArray* types = i::FixedArray::cast(info->types());
   for (int i = 0; i < types->length(); i++) {
     if (i::FunctionTemplateInfo::cast(types->get(i))->IsTemplateFor(*obj))
@@ -1249,6 +1156,9 @@
 Local<ObjectTemplate> ObjectTemplate::New(
     i::Isolate* isolate,
     v8::Handle<FunctionTemplate> constructor) {
+  // Changes to the environment cannot be captured in the snapshot. Expect no
+  // object templates when the isolate is created for serialization.
+  DCHECK(!isolate->serializer_enabled());
   LOG_API(isolate, "ObjectTemplate::New");
   ENTER_V8(isolate);
   i::Handle<i::Struct> struct_obj =
@@ -1292,7 +1202,7 @@
     info->set_property_accessors(*list);
   }
   NeanderArray array(list);
-  array.add(obj);
+  array.add(isolate, obj);
 }
 
 
@@ -1394,30 +1304,31 @@
 }
 
 
-void ObjectTemplate::SetNamedPropertyHandler(
-    NamedPropertyGetterCallback getter,
-    NamedPropertySetterCallback setter,
-    NamedPropertyQueryCallback query,
-    NamedPropertyDeleterCallback remover,
-    NamedPropertyEnumeratorCallback enumerator,
-    Handle<Value> data) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+template <typename Getter, typename Setter, typename Query, typename Deleter,
+          typename Enumerator>
+static void ObjectTemplateSetNamedPropertyHandler(
+    ObjectTemplate* templ, Getter getter, Setter setter, Query query,
+    Deleter remover, Enumerator enumerator, Handle<Value> data,
+    bool can_intercept_symbols, PropertyHandlerFlags flags) {
+  i::Isolate* isolate = Utils::OpenHandle(templ)->GetIsolate();
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
-  EnsureConstructor(isolate, this);
-  i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(
-      Utils::OpenHandle(this)->constructor());
+  EnsureConstructor(isolate, templ);
+  i::FunctionTemplateInfo* constructor =
+      i::FunctionTemplateInfo::cast(Utils::OpenHandle(templ)->constructor());
   i::Handle<i::FunctionTemplateInfo> cons(constructor);
-  i::Handle<i::Struct> struct_obj =
-      isolate->factory()->NewStruct(i::INTERCEPTOR_INFO_TYPE);
-  i::Handle<i::InterceptorInfo> obj =
-      i::Handle<i::InterceptorInfo>::cast(struct_obj);
+  auto obj = i::Handle<i::InterceptorInfo>::cast(
+      isolate->factory()->NewStruct(i::INTERCEPTOR_INFO_TYPE));
 
   if (getter != 0) SET_FIELD_WRAPPED(obj, set_getter, getter);
   if (setter != 0) SET_FIELD_WRAPPED(obj, set_setter, setter);
   if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query);
   if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover);
   if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator);
+  obj->set_flags(0);
+  obj->set_can_intercept_symbols(can_intercept_symbols);
+  obj->set_all_can_read(static_cast<int>(flags) &
+                        static_cast<int>(PropertyHandlerFlags::kAllCanRead));
 
   if (data.IsEmpty()) {
     data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate));
@@ -1427,6 +1338,24 @@
 }
 
 
+void ObjectTemplate::SetNamedPropertyHandler(
+    NamedPropertyGetterCallback getter, NamedPropertySetterCallback setter,
+    NamedPropertyQueryCallback query, NamedPropertyDeleterCallback remover,
+    NamedPropertyEnumeratorCallback enumerator, Handle<Value> data) {
+  ObjectTemplateSetNamedPropertyHandler(this, getter, setter, query, remover,
+                                        enumerator, data, false,
+                                        PropertyHandlerFlags::kNone);
+}
+
+
+void ObjectTemplate::SetHandler(
+    const NamedPropertyHandlerConfiguration& config) {
+  ObjectTemplateSetNamedPropertyHandler(
+      this, config.getter, config.setter, config.query, config.deleter,
+      config.enumerator, config.data, true, config.flags);
+}
+
+
 void ObjectTemplate::MarkAsUndetectable() {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ENTER_V8(isolate);
@@ -1470,13 +1399,8 @@
 }
 
 
-void ObjectTemplate::SetIndexedPropertyHandler(
-    IndexedPropertyGetterCallback getter,
-    IndexedPropertySetterCallback setter,
-    IndexedPropertyQueryCallback query,
-    IndexedPropertyDeleterCallback remover,
-    IndexedPropertyEnumeratorCallback enumerator,
-    Handle<Value> data) {
+void ObjectTemplate::SetHandler(
+    const IndexedPropertyHandlerConfiguration& config) {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
@@ -1484,17 +1408,21 @@
   i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(
       Utils::OpenHandle(this)->constructor());
   i::Handle<i::FunctionTemplateInfo> cons(constructor);
-  i::Handle<i::Struct> struct_obj =
-      isolate->factory()->NewStruct(i::INTERCEPTOR_INFO_TYPE);
-  i::Handle<i::InterceptorInfo> obj =
-      i::Handle<i::InterceptorInfo>::cast(struct_obj);
+  auto obj = i::Handle<i::InterceptorInfo>::cast(
+      isolate->factory()->NewStruct(i::INTERCEPTOR_INFO_TYPE));
 
-  if (getter != 0) SET_FIELD_WRAPPED(obj, set_getter, getter);
-  if (setter != 0) SET_FIELD_WRAPPED(obj, set_setter, setter);
-  if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query);
-  if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover);
-  if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator);
+  if (config.getter != 0) SET_FIELD_WRAPPED(obj, set_getter, config.getter);
+  if (config.setter != 0) SET_FIELD_WRAPPED(obj, set_setter, config.setter);
+  if (config.query != 0) SET_FIELD_WRAPPED(obj, set_query, config.query);
+  if (config.deleter != 0) SET_FIELD_WRAPPED(obj, set_deleter, config.deleter);
+  if (config.enumerator != 0) {
+    SET_FIELD_WRAPPED(obj, set_enumerator, config.enumerator);
+  }
+  obj->set_flags(0);
+  obj->set_all_can_read(static_cast<int>(config.flags) &
+                        static_cast<int>(PropertyHandlerFlags::kAllCanRead));
 
+  v8::Local<v8::Value> data = config.data;
   if (data.IsEmpty()) {
     data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate));
   }
@@ -1556,7 +1484,10 @@
 
 ScriptCompiler::CachedData::CachedData(const uint8_t* data_, int length_,
                                        BufferPolicy buffer_policy_)
-    : data(data_), length(length_), buffer_policy(buffer_policy_) {}
+    : data(data_),
+      length(length_),
+      rejected(false),
+      buffer_policy(buffer_policy_) {}
 
 
 ScriptCompiler::CachedData::~CachedData() {
@@ -1587,7 +1518,7 @@
       function_info(i::SharedFunctionInfo::cast(*obj), obj->GetIsolate());
   i::Handle<i::JSFunction> function =
       obj->GetIsolate()->factory()->NewFunctionFromSharedFunctionInfo(
-          function_info, obj->GetIsolate()->global_context());
+          function_info, obj->GetIsolate()->native_context());
   return ToApiHandle<Script>(function);
 }
 
@@ -1717,6 +1648,12 @@
     options = kConsumeParserCache;
   }
 
+  // Don't try to produce any kind of cache when the debugger is loaded.
+  if (isolate->debug()->is_loaded() &&
+      (options == kProduceParserCache || options == kProduceCodeCache)) {
+    options = kNoCompileOptions;
+  }
+
   i::ScriptData* script_data = NULL;
   if (options == kConsumeParserCache || options == kConsumeCodeCache) {
     DCHECK(source->cached_data);
@@ -1752,7 +1689,7 @@
     EXCEPTION_PREAMBLE(isolate);
     i::Handle<i::SharedFunctionInfo> result = i::Compiler::CompileScript(
         str, name_obj, line_offset, column_offset, is_shared_cross_origin,
-        isolate->global_context(), NULL, &script_data, options,
+        isolate->native_context(), NULL, &script_data, options,
         i::NOT_NATIVES_CODE);
     has_pending_exception = result.is_null();
     if (has_pending_exception && script_data != NULL) {
@@ -1772,6 +1709,8 @@
       source->cached_data = new CachedData(
           script_data->data(), script_data->length(), CachedData::BufferOwned);
       script_data->ReleaseDataOwnership();
+    } else if (options == kConsumeParserCache || options == kConsumeCodeCache) {
+      source->cached_data->rejected = script_data->rejected();
     }
     delete script_data;
   }
@@ -1797,17 +1736,6 @@
 ScriptCompiler::ScriptStreamingTask* ScriptCompiler::StartStreamingScript(
     Isolate* v8_isolate, StreamedSource* source, CompileOptions options) {
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-  if (!isolate->global_context().is_null() &&
-      !isolate->global_context()->IsNativeContext()) {
-    // The context chain is non-trivial, and constructing the corresponding
-    // non-trivial Scope chain outside the V8 heap is not implemented. Don't
-    // stream the script. This will only occur if Harmony scoping is enabled and
-    // a previous script has introduced "let" or "const" variables. TODO(marja):
-    // Implement externalizing ScopeInfos and constructing non-trivial Scope
-    // chains independent of the V8 heap so that we can stream also in this
-    // case.
-    return NULL;
-  }
   return new i::BackgroundParsingTask(source->impl(), options,
                                       i::FLAG_stack_size, isolate);
 }
@@ -1844,13 +1772,14 @@
                                          v8::True(v8_isolate));
     }
     source->info->set_script(script);
-    source->info->SetContext(isolate->global_context());
+    source->info->SetContext(isolate->native_context());
 
     EXCEPTION_PREAMBLE(isolate);
 
     // Do the parsing tasks which need to be done on the main thread. This will
     // also handle parse errors.
     source->parser->Internalize();
+    source->parser->HandleSourceURLComments();
 
     i::Handle<i::SharedFunctionInfo> result =
         i::Handle<i::SharedFunctionInfo>::null();
@@ -1877,6 +1806,13 @@
 }
 
 
+uint32_t ScriptCompiler::CachedDataVersionTag() {
+  return static_cast<uint32_t>(base::hash_combine(
+      internal::Version::Hash(), internal::FlagList::Hash(),
+      static_cast<uint32_t>(internal::CpuFeatures::SupportedFeatures())));
+}
+
+
 Local<Script> Script::Compile(v8::Handle<String> source,
                               v8::ScriptOrigin* origin) {
   i::Handle<i::String> str = Utils::OpenHandle(*source);
@@ -1920,8 +1856,24 @@
 }
 
 
+v8::TryCatch::TryCatch(v8::Isolate* isolate)
+    : isolate_(reinterpret_cast<i::Isolate*>(isolate)),
+      next_(isolate_->try_catch_handler()),
+      is_verbose_(false),
+      can_continue_(true),
+      capture_message_(true),
+      rethrow_(false),
+      has_terminated_(false) {
+  ResetInternal();
+  // Special handling for simulators which have a separate JS stack.
+  js_stack_comparable_address_ =
+      reinterpret_cast<void*>(v8::internal::SimulatorStack::RegisterCTryCatch(
+          v8::internal::GetCurrentStackPosition()));
+  isolate_->RegisterTryCatchHandler(this);
+}
+
+
 v8::TryCatch::~TryCatch() {
-  DCHECK(isolate_ == i::Isolate::Current());
   if (rethrow_) {
     v8::Isolate* isolate = reinterpret_cast<Isolate*>(isolate_);
     v8::HandleScope scope(isolate);
@@ -1974,7 +1926,6 @@
 
 
 v8::Local<Value> v8::TryCatch::Exception() const {
-  DCHECK(isolate_ == i::Isolate::Current());
   if (HasCaught()) {
     // Check for out of memory exception.
     i::Object* exception = reinterpret_cast<i::Object*>(exception_);
@@ -1986,7 +1937,6 @@
 
 
 v8::Local<Value> v8::TryCatch::StackTrace() const {
-  DCHECK(isolate_ == i::Isolate::Current());
   if (HasCaught()) {
     i::Object* raw_obj = reinterpret_cast<i::Object*>(exception_);
     if (!raw_obj->IsJSObject()) return v8::Local<Value>();
@@ -2010,7 +1960,6 @@
 
 
 v8::Local<v8::Message> v8::TryCatch::Message() const {
-  DCHECK(isolate_ == i::Isolate::Current());
   i::Object* message = reinterpret_cast<i::Object*>(message_obj_);
   DCHECK(message->IsJSMessageObject() || message->IsTheHole());
   if (HasCaught() && !message->IsTheHole()) {
@@ -2022,7 +1971,6 @@
 
 
 void v8::TryCatch::Reset() {
-  DCHECK(isolate_ == i::Isolate::Current());
   if (!rethrow_ && HasCaught() && isolate_->has_scheduled_exception()) {
     // If an exception was caught but is still scheduled because no API call
     // promoted it, then it is canceled to prevent it from being propagated.
@@ -2110,11 +2058,8 @@
 
 
 MUST_USE_RESULT static i::MaybeHandle<i::Object> CallV8HeapFunction(
-    const char* name,
-    i::Handle<i::Object> recv,
-    int argc,
+    i::Isolate* isolate, const char* name, i::Handle<i::Object> recv, int argc,
     i::Handle<i::Object> argv[]) {
-  i::Isolate* isolate = i::Isolate::Current();
   i::Handle<i::Object> object_fun =
       i::Object::GetProperty(
           isolate, isolate->js_builtins_object(), name).ToHandleChecked();
@@ -2124,13 +2069,10 @@
 
 
 MUST_USE_RESULT static i::MaybeHandle<i::Object> CallV8HeapFunction(
-    const char* name,
-    i::Handle<i::Object> data) {
+    i::Isolate* isolate, const char* name, i::Handle<i::Object> data) {
   i::Handle<i::Object> argv[] = { data };
-  return CallV8HeapFunction(name,
-                            i::Isolate::Current()->js_builtins_object(),
-                            arraysize(argv),
-                            argv);
+  return CallV8HeapFunction(isolate, name, isolate->js_builtins_object(),
+                            arraysize(argv), argv);
 }
 
 
@@ -2142,8 +2084,9 @@
 
   EXCEPTION_PREAMBLE(isolate);
   i::Handle<i::Object> result;
-  has_pending_exception = !CallV8HeapFunction(
-      "GetLineNumber", Utils::OpenHandle(this)).ToHandle(&result);
+  has_pending_exception =
+      !CallV8HeapFunction(isolate, "GetLineNumber", Utils::OpenHandle(this))
+           .ToHandle(&result);
   EXCEPTION_BAILOUT_CHECK(isolate, 0);
   return static_cast<int>(result->Number());
 }
@@ -2177,8 +2120,9 @@
   i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
   EXCEPTION_PREAMBLE(isolate);
   i::Handle<i::Object> start_col_obj;
-  has_pending_exception = !CallV8HeapFunction(
-      "GetPositionInLine", data_obj).ToHandle(&start_col_obj);
+  has_pending_exception =
+      !CallV8HeapFunction(isolate, "GetPositionInLine", data_obj)
+           .ToHandle(&start_col_obj);
   EXCEPTION_BAILOUT_CHECK(isolate, 0);
   return static_cast<int>(start_col_obj->Number());
 }
@@ -2192,8 +2136,9 @@
   i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
   EXCEPTION_PREAMBLE(isolate);
   i::Handle<i::Object> start_col_obj;
-  has_pending_exception = !CallV8HeapFunction(
-      "GetPositionInLine", data_obj).ToHandle(&start_col_obj);
+  has_pending_exception =
+      !CallV8HeapFunction(isolate, "GetPositionInLine", data_obj)
+           .ToHandle(&start_col_obj);
   EXCEPTION_BAILOUT_CHECK(isolate, 0);
   i::Handle<i::JSMessageObject> message =
       i::Handle<i::JSMessageObject>::cast(data_obj);
@@ -2223,8 +2168,9 @@
   EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
   EXCEPTION_PREAMBLE(isolate);
   i::Handle<i::Object> result;
-  has_pending_exception = !CallV8HeapFunction(
-      "GetSourceLine", Utils::OpenHandle(this)).ToHandle(&result);
+  has_pending_exception =
+      !CallV8HeapFunction(isolate, "GetSourceLine", Utils::OpenHandle(this))
+           .ToHandle(&result);
   EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::String>());
   if (result->IsString()) {
     return scope.Escape(Utils::ToLocal(i::Handle<i::String>::cast(result)));
@@ -2568,13 +2514,36 @@
 }
 
 
-Local<String> Value::ToString() const {
+bool Value::IsGeneratorFunction() const {
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  if (!obj->IsJSFunction()) return false;
+  i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(obj);
+  return func->shared()->is_generator();
+}
+
+
+bool Value::IsGeneratorObject() const {
+  return Utils::OpenHandle(this)->IsJSGeneratorObject();
+}
+
+
+bool Value::IsMapIterator() const {
+  return Utils::OpenHandle(this)->IsJSMapIterator();
+}
+
+
+bool Value::IsSetIterator() const {
+  return Utils::OpenHandle(this)->IsJSSetIterator();
+}
+
+
+Local<String> Value::ToString(Isolate* v8_isolate) const {
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
   i::Handle<i::Object> str;
   if (obj->IsString()) {
     str = obj;
   } else {
-    i::Isolate* isolate = i::Isolate::Current();
+    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
     LOG_API(isolate, "ToString");
     ENTER_V8(isolate);
     EXCEPTION_PREAMBLE(isolate);
@@ -2586,13 +2555,13 @@
 }
 
 
-Local<String> Value::ToDetailString() const {
+Local<String> Value::ToDetailString(Isolate* v8_isolate) const {
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
   i::Handle<i::Object> str;
   if (obj->IsString()) {
     str = obj;
   } else {
-    i::Isolate* isolate = i::Isolate::Current();
+    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
     LOG_API(isolate, "ToDetailString");
     ENTER_V8(isolate);
     EXCEPTION_PREAMBLE(isolate);
@@ -2604,13 +2573,13 @@
 }
 
 
-Local<v8::Object> Value::ToObject() const {
+Local<v8::Object> Value::ToObject(Isolate* v8_isolate) const {
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
   i::Handle<i::Object> val;
   if (obj->IsJSObject()) {
     val = obj;
   } else {
-    i::Isolate* isolate = i::Isolate::Current();
+    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
     LOG_API(isolate, "ToObject");
     ENTER_V8(isolate);
     EXCEPTION_PREAMBLE(isolate);
@@ -2622,12 +2591,12 @@
 }
 
 
-Local<Boolean> Value::ToBoolean() const {
+Local<Boolean> Value::ToBoolean(Isolate* v8_isolate) const {
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
   if (obj->IsBoolean()) {
     return ToApiHandle<Boolean>(obj);
   } else {
-    i::Isolate* isolate = i::Isolate::Current();
+    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
     LOG_API(isolate, "ToBoolean");
     ENTER_V8(isolate);
     i::Handle<i::Object> val =
@@ -2637,13 +2606,13 @@
 }
 
 
-Local<Number> Value::ToNumber() const {
+Local<Number> Value::ToNumber(Isolate* v8_isolate) const {
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
   i::Handle<i::Object> num;
   if (obj->IsNumber()) {
     num = obj;
   } else {
-    i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate();
+    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
     LOG_API(isolate, "ToNumber");
     ENTER_V8(isolate);
     EXCEPTION_PREAMBLE(isolate);
@@ -2655,13 +2624,13 @@
 }
 
 
-Local<Integer> Value::ToInteger() const {
+Local<Integer> Value::ToInteger(Isolate* v8_isolate) const {
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
   i::Handle<i::Object> num;
   if (obj->IsSmi()) {
     num = obj;
   } else {
-    i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate();
+    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
     LOG_API(isolate, "ToInteger");
     ENTER_V8(isolate);
     EXCEPTION_PREAMBLE(isolate);
@@ -2676,7 +2645,6 @@
 void i::Internals::CheckInitializedImpl(v8::Isolate* external_isolate) {
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(external_isolate);
   Utils::ApiCheck(isolate != NULL &&
-                  isolate->IsInitialized() &&
                   !isolate->IsDead(),
                   "v8::internal::Internals::CheckInitialized()",
                   "Isolate is not initialized or V8 has died");
@@ -2924,13 +2892,13 @@
 }
 
 
-Local<Int32> Value::ToInt32() const {
+Local<Int32> Value::ToInt32(Isolate* v8_isolate) const {
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
   i::Handle<i::Object> num;
   if (obj->IsSmi()) {
     num = obj;
   } else {
-    i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate();
+    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
     LOG_API(isolate, "ToInt32");
     ENTER_V8(isolate);
     EXCEPTION_PREAMBLE(isolate);
@@ -2941,13 +2909,13 @@
 }
 
 
-Local<Uint32> Value::ToUint32() const {
+Local<Uint32> Value::ToUint32(Isolate* v8_isolate) const {
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
   i::Handle<i::Object> num;
   if (obj->IsSmi()) {
     num = obj;
   } else {
-    i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate();
+    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
     LOG_API(isolate, "ToUInt32");
     ENTER_V8(isolate);
     EXCEPTION_PREAMBLE(isolate);
@@ -3010,8 +2978,13 @@
 
 
 bool Value::Equals(Handle<Value> that) const {
-  i::Isolate* isolate = i::Isolate::Current();
   i::Handle<i::Object> obj = Utils::OpenHandle(this, true);
+  i::Handle<i::Object> other = Utils::OpenHandle(*that);
+  if (obj->IsSmi() && other->IsSmi()) {
+    return obj->Number() == other->Number();
+  }
+  i::Object* ho = obj->IsSmi() ? *other : *obj;
+  i::Isolate* isolate = i::HeapObject::cast(ho)->GetIsolate();
   if (!Utils::ApiCheck(!obj.is_null() && !that.IsEmpty(),
                        "v8::Value::Equals()",
                        "Reading from empty handle")) {
@@ -3019,7 +2992,6 @@
   }
   LOG_API(isolate, "Equals");
   ENTER_V8(isolate);
-  i::Handle<i::Object> other = Utils::OpenHandle(*that);
   // If both obj and other are JSObjects, we'd better compare by identity
   // immediately when going into JS builtin.  The reason is Invoke
   // would overwrite global object receiver with global proxy.
@@ -3029,23 +3001,27 @@
   i::Handle<i::Object> args[] = { other };
   EXCEPTION_PREAMBLE(isolate);
   i::Handle<i::Object> result;
-  has_pending_exception = !CallV8HeapFunction(
-      "EQUALS", obj, arraysize(args), args).ToHandle(&result);
+  has_pending_exception =
+      !CallV8HeapFunction(isolate, "EQUALS", obj, arraysize(args), args)
+           .ToHandle(&result);
   EXCEPTION_BAILOUT_CHECK(isolate, false);
   return *result == i::Smi::FromInt(i::EQUAL);
 }
 
 
 bool Value::StrictEquals(Handle<Value> that) const {
-  i::Isolate* isolate = i::Isolate::Current();
   i::Handle<i::Object> obj = Utils::OpenHandle(this, true);
+  i::Handle<i::Object> other = Utils::OpenHandle(*that);
+  if (obj->IsSmi()) {
+    return other->IsNumber() && obj->Number() == other->Number();
+  }
+  i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate();
   if (!Utils::ApiCheck(!obj.is_null() && !that.IsEmpty(),
                        "v8::Value::StrictEquals()",
                        "Reading from empty handle")) {
     return false;
   }
   LOG_API(isolate, "StrictEquals");
-  i::Handle<i::Object> other = Utils::OpenHandle(*that);
   // Must check HeapNumber first, since NaN !== NaN.
   if (obj->IsHeapNumber()) {
     if (!other->IsNumber()) return false;
@@ -3162,6 +3138,44 @@
 }
 
 
+i::MaybeHandle<i::Object> DeleteObjectProperty(
+    i::Isolate* isolate, i::Handle<i::JSReceiver> receiver,
+    i::Handle<i::Object> key, i::JSReceiver::DeleteMode mode) {
+  // Check if the given key is an array index.
+  uint32_t index;
+  if (key->ToArrayIndex(&index)) {
+    // In Firefox/SpiderMonkey, Safari and Opera you can access the
+    // characters of a string using [] notation.  In the case of a
+    // String object we just need to redirect the deletion to the
+    // underlying string if the index is in range.  Since the
+    // underlying string does nothing with the deletion, we can ignore
+    // such deletions.
+    if (receiver->IsStringObjectWithCharacterAt(index)) {
+      return isolate->factory()->true_value();
+    }
+
+    return i::JSReceiver::DeleteElement(receiver, index, mode);
+  }
+
+  i::Handle<i::Name> name;
+  if (key->IsName()) {
+    name = i::Handle<i::Name>::cast(key);
+  } else {
+    // Call-back into JavaScript to convert the key to a string.
+    i::Handle<i::Object> converted;
+    if (!i::Execution::ToString(isolate, key).ToHandle(&converted)) {
+      return i::MaybeHandle<i::Object>();
+    }
+    name = i::Handle<i::String>::cast(converted);
+  }
+
+  if (name->IsString()) {
+    name = i::String::Flatten(i::Handle<i::String>::cast(name));
+  }
+  return i::JSReceiver::DeleteProperty(receiver, name, mode);
+}
+
+
 bool v8::Object::ForceDelete(v8::Handle<Value> key) {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ON_BAILOUT(isolate, "v8::Object::ForceDelete()", return false);
@@ -3180,8 +3194,9 @@
 
   EXCEPTION_PREAMBLE(isolate);
   i::Handle<i::Object> obj;
-  has_pending_exception = !i::Runtime::DeleteObjectProperty(
-      isolate, self, key_obj, i::JSReceiver::FORCE_DELETION).ToHandle(&obj);
+  has_pending_exception =
+      !DeleteObjectProperty(isolate, self, key_obj,
+                            i::JSReceiver::FORCE_DELETION).ToHandle(&obj);
   EXCEPTION_BAILOUT_CHECK(isolate, false);
   return obj->IsTrue();
 }
@@ -3256,11 +3271,10 @@
   i::Handle<i::Object> args[] = { obj, key_name };
   EXCEPTION_PREAMBLE(isolate);
   i::Handle<i::Object> result;
-  has_pending_exception = !CallV8HeapFunction(
-      "ObjectGetOwnPropertyDescriptor",
-      isolate->factory()->undefined_value(),
-      arraysize(args),
-      args).ToHandle(&result);
+  has_pending_exception =
+      !CallV8HeapFunction(isolate, "ObjectGetOwnPropertyDescriptor",
+                          isolate->factory()->undefined_value(),
+                          arraysize(args), args).ToHandle(&result);
   EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
   return Utils::ToLocal(result);
 }
@@ -3359,6 +3373,37 @@
 }
 
 
+static bool GetPredefinedToString(i::Handle<i::String> tag,
+                                  Local<String>* result) {
+  i::Isolate* i_isolate = tag->GetIsolate();
+  Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
+  i::Factory* factory = i_isolate->factory();
+
+  if (i::String::Equals(tag, factory->Arguments_string())) {
+    *result = v8::String::NewFromUtf8(isolate, "[object ~Arguments]");
+  } else if (i::String::Equals(tag, factory->Array_string())) {
+    *result = v8::String::NewFromUtf8(isolate, "[object ~Array]");
+  } else if (i::String::Equals(tag, factory->Boolean_string())) {
+    *result = v8::String::NewFromUtf8(isolate, "[object ~Boolean]");
+  } else if (i::String::Equals(tag, factory->Date_string())) {
+    *result = v8::String::NewFromUtf8(isolate, "[object ~Date]");
+  } else if (i::String::Equals(tag, factory->Error_string())) {
+    *result = v8::String::NewFromUtf8(isolate, "[object ~Error]");
+  } else if (i::String::Equals(tag, factory->Function_string())) {
+    *result = v8::String::NewFromUtf8(isolate, "[object ~Function]");
+  } else if (i::String::Equals(tag, factory->Number_string())) {
+    *result = v8::String::NewFromUtf8(isolate, "[object ~Number]");
+  } else if (i::String::Equals(tag, factory->RegExp_string())) {
+    *result = v8::String::NewFromUtf8(isolate, "[object ~RegExp]");
+  } else if (i::String::Equals(tag, factory->String_string())) {
+    *result = v8::String::NewFromUtf8(isolate, "[object ~String]");
+  } else {
+    return false;
+  }
+  return true;
+}
+
+
 Local<String> v8::Object::ObjectProtoToString() {
   i::Isolate* i_isolate = Utils::OpenHandle(this)->GetIsolate();
   Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
@@ -3368,6 +3413,7 @@
   i::Handle<i::JSObject> self = Utils::OpenHandle(this);
 
   i::Handle<i::Object> name(self->class_name(), i_isolate);
+  i::Handle<i::Object> tag;
 
   // Native implementation of Object.prototype.toString (v8natives.js):
   //   var c = %_ClassOf(this);
@@ -3382,6 +3428,27 @@
                           i_isolate->factory()->Arguments_string())) {
       return v8::String::NewFromUtf8(isolate, "[object Object]");
     } else {
+      if (internal::FLAG_harmony_tostring) {
+        i::Handle<i::Symbol> toStringTag =
+            Utils::OpenHandle(*Symbol::GetToStringTag(isolate));
+        EXCEPTION_PREAMBLE(i_isolate);
+        has_pending_exception =
+            !i::Runtime::GetObjectProperty(i_isolate, self, toStringTag)
+                 .ToHandle(&tag);
+        EXCEPTION_BAILOUT_CHECK(i_isolate, Local<v8::String>());
+
+        if (!tag->IsUndefined()) {
+          if (!tag->IsString())
+            return v8::String::NewFromUtf8(isolate, "[object ???]");
+          i::Handle<i::String> tag_name = i::Handle<i::String>::cast(tag);
+          if (!i::String::Equals(class_name, tag_name)) {
+            Local<String> result;
+            if (GetPredefinedToString(tag_name, &result)) return result;
+
+            class_name = tag_name;
+          }
+        }
+      }
       const char* prefix = "[object ";
       Local<String> str = Utils::ToLocal(class_name);
       const char* postfix = "]";
@@ -3434,8 +3501,9 @@
   i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
   EXCEPTION_PREAMBLE(isolate);
   i::Handle<i::Object> obj;
-  has_pending_exception = !i::Runtime::DeleteObjectProperty(
-      isolate, self, key_obj, i::JSReceiver::NORMAL_DELETION).ToHandle(&obj);
+  has_pending_exception =
+      !DeleteObjectProperty(isolate, self, key_obj,
+                            i::JSReceiver::NORMAL_DELETION).ToHandle(&obj);
   EXCEPTION_BAILOUT_CHECK(isolate, false);
   return obj->IsTrue();
 }
@@ -3453,11 +3521,22 @@
   i::Handle<i::JSReceiver> self = Utils::OpenHandle(this);
   i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
   EXCEPTION_PREAMBLE(isolate);
-  i::Handle<i::Object> obj;
-  has_pending_exception = !i::Runtime::HasObjectProperty(
-      isolate, self, key_obj).ToHandle(&obj);
+  Maybe<bool> maybe;
+  // Check if the given key is an array index.
+  uint32_t index;
+  if (key_obj->ToArrayIndex(&index)) {
+    maybe = i::JSReceiver::HasElement(self, index);
+  } else {
+    // Convert the key to a name - possibly by calling back into JavaScript.
+    i::Handle<i::Name> name;
+    if (i::Runtime::ToName(isolate, key_obj).ToHandle(&name)) {
+      maybe = i::JSReceiver::HasProperty(self, name);
+    }
+  }
+  if (!maybe.has_value) has_pending_exception = true;
   EXCEPTION_BAILOUT_CHECK(isolate, false);
-  return obj->IsTrue();
+  DCHECK(maybe.has_value);
+  return maybe.value;
 }
 
 
@@ -3520,7 +3599,9 @@
       i::JSObject::SetAccessor(Utils::OpenHandle(obj), info),
       false);
   if (result->IsUndefined()) return false;
-  if (fast) i::JSObject::MigrateSlowToFast(Utils::OpenHandle(obj), 0);
+  if (fast) {
+    i::JSObject::MigrateSlowToFast(Utils::OpenHandle(obj), 0, "APISetAccessor");
+  }
   return true;
 }
 
@@ -3706,17 +3787,13 @@
   // as optimized code does not always handle access checks.
   i::Deoptimizer::DeoptimizeGlobalObject(*obj);
 
-  i::Handle<i::Map> new_map = i::Map::Copy(i::Handle<i::Map>(obj->map()));
+  i::Handle<i::Map> new_map =
+      i::Map::Copy(i::Handle<i::Map>(obj->map()), "APITurnOnAccessCheck");
   new_map->set_is_access_check_needed(true);
   i::JSObject::MigrateToMap(obj, new_map);
 }
 
 
-bool v8::Object::IsDirty() {
-  return Utils::OpenHandle(this)->IsDirty();
-}
-
-
 Local<v8::Object> v8::Object::Clone() {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ON_BAILOUT(isolate, "v8::Object::Clone()", return Local<Object>());
@@ -4223,6 +4300,16 @@
 }
 
 
+int Name::GetIdentityHash() {
+  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+  ON_BAILOUT(isolate, "v8::Name::GetIdentityHash()", return 0);
+  ENTER_V8(isolate);
+  i::HandleScope scope(isolate);
+  i::Handle<i::Name> self = Utils::OpenHandle(this);
+  return static_cast<int>(self->Hash());
+}
+
+
 int String::Length() const {
   i::Handle<i::String> str = Utils::OpenHandle(this);
   return str->length();
@@ -5041,6 +5128,9 @@
   i::V8::ShutdownPlatform();
 }
 
+v8::Platform* v8::V8::GetCurrentPlatform() {
+  return i::V8::GetCurrentPlatform();
+}
 
 bool v8::V8::Initialize() {
   i::V8::Initialize();
@@ -5081,50 +5171,6 @@
                                   heap_size_limit_(0) { }
 
 
-void v8::V8::VisitExternalResources(ExternalResourceVisitor* visitor) {
-  i::Isolate* isolate = i::Isolate::Current();
-  isolate->heap()->VisitExternalResources(visitor);
-}
-
-
-class VisitorAdapter : public i::ObjectVisitor {
- public:
-  explicit VisitorAdapter(PersistentHandleVisitor* visitor)
-      : visitor_(visitor) {}
-  virtual void VisitPointers(i::Object** start, i::Object** end) {
-    UNREACHABLE();
-  }
-  virtual void VisitEmbedderReference(i::Object** p, uint16_t class_id) {
-    Value* value = ToApi<Value>(i::Handle<i::Object>(p));
-    visitor_->VisitPersistentHandle(
-        reinterpret_cast<Persistent<Value>*>(&value), class_id);
-  }
- private:
-  PersistentHandleVisitor* visitor_;
-};
-
-
-void v8::V8::VisitHandlesWithClassIds(PersistentHandleVisitor* visitor) {
-  i::Isolate* isolate = i::Isolate::Current();
-  i::DisallowHeapAllocation no_allocation;
-
-  VisitorAdapter visitor_adapter(visitor);
-  isolate->global_handles()->IterateAllRootsWithClassIds(&visitor_adapter);
-}
-
-
-void v8::V8::VisitHandlesForPartialDependence(
-    Isolate* exported_isolate, PersistentHandleVisitor* visitor) {
-  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(exported_isolate);
-  DCHECK(isolate == i::Isolate::Current());
-  i::DisallowHeapAllocation no_allocation;
-
-  VisitorAdapter visitor_adapter(visitor);
-  isolate->global_handles()->IterateAllRootsInNewSpaceWithClassIds(
-      &visitor_adapter);
-}
-
-
 bool v8::V8::InitializeICU(const char* icu_data_file) {
   return i::InitializeICU(icu_data_file);
 }
@@ -5220,25 +5266,25 @@
 
 
 void v8::Context::SetSecurityToken(Handle<Value> token) {
-  i::Isolate* isolate = i::Isolate::Current();
-  ENTER_V8(isolate);
   i::Handle<i::Context> env = Utils::OpenHandle(this);
+  i::Isolate* isolate = env->GetIsolate();
+  ENTER_V8(isolate);
   i::Handle<i::Object> token_handle = Utils::OpenHandle(*token);
   env->set_security_token(*token_handle);
 }
 
 
 void v8::Context::UseDefaultSecurityToken() {
-  i::Isolate* isolate = i::Isolate::Current();
-  ENTER_V8(isolate);
   i::Handle<i::Context> env = Utils::OpenHandle(this);
+  i::Isolate* isolate = env->GetIsolate();
+  ENTER_V8(isolate);
   env->set_security_token(env->global_object());
 }
 
 
 Handle<Value> v8::Context::GetSecurityToken() {
-  i::Isolate* isolate = i::Isolate::Current();
   i::Handle<i::Context> env = Utils::OpenHandle(this);
+  i::Isolate* isolate = env->GetIsolate();
   i::Object* security_token = env->security_token();
   i::Handle<i::Object> token_handle(security_token, isolate);
   return Utils::ToLocal(token_handle);
@@ -5297,40 +5343,42 @@
 
 
 Local<v8::Object> ObjectTemplate::NewInstance() {
-  i::Isolate* isolate = i::Isolate::Current();
+  i::Handle<i::ObjectTemplateInfo> info = Utils::OpenHandle(this);
+  i::Isolate* isolate = info->GetIsolate();
   ON_BAILOUT(isolate, "v8::ObjectTemplate::NewInstance()",
              return Local<v8::Object>());
   LOG_API(isolate, "ObjectTemplate::NewInstance");
   ENTER_V8(isolate);
   EXCEPTION_PREAMBLE(isolate);
   i::Handle<i::Object> obj;
-  has_pending_exception = !i::Execution::InstantiateObject(
-      Utils::OpenHandle(this)).ToHandle(&obj);
+  has_pending_exception = !i::Execution::InstantiateObject(info).ToHandle(&obj);
   EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
   return Utils::ToLocal(i::Handle<i::JSObject>::cast(obj));
 }
 
 
 Local<v8::Function> FunctionTemplate::GetFunction() {
-  i::Isolate* isolate = i::Isolate::Current();
+  i::Handle<i::FunctionTemplateInfo> info = Utils::OpenHandle(this);
+  i::Isolate* isolate = info->GetIsolate();
   ON_BAILOUT(isolate, "v8::FunctionTemplate::GetFunction()",
              return Local<v8::Function>());
   LOG_API(isolate, "FunctionTemplate::GetFunction");
   ENTER_V8(isolate);
   EXCEPTION_PREAMBLE(isolate);
   i::Handle<i::Object> obj;
-  has_pending_exception = !i::Execution::InstantiateFunction(
-      Utils::OpenHandle(this)).ToHandle(&obj);
+  has_pending_exception =
+      !i::Execution::InstantiateFunction(info).ToHandle(&obj);
   EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Function>());
   return Utils::ToLocal(i::Handle<i::JSFunction>::cast(obj));
 }
 
 
 bool FunctionTemplate::HasInstance(v8::Handle<v8::Value> value) {
-  ON_BAILOUT(i::Isolate::Current(), "v8::FunctionTemplate::HasInstanceOf()",
-             return false);
+  i::Handle<i::FunctionTemplateInfo> info = Utils::OpenHandle(this);
+  i::Isolate* isolate = info->GetIsolate();
+  ON_BAILOUT(isolate, "v8::FunctionTemplate::HasInstanceOf()", return false);
   i::Object* obj = *Utils::OpenHandle(*value);
-  return Utils::OpenHandle(this)->IsTemplateFor(obj);
+  return info->IsTemplateFor(obj);
 }
 
 
@@ -5476,28 +5524,26 @@
   LOG_API(isolate, "String::New(char)");
   ENTER_V8(isolate);
   i::Handle<i::String> right_string = Utils::OpenHandle(*right);
-  // We do not expect this to fail. Change this if it does.
+  // If we are steering towards a range error, do not wait for the error to be
+  // thrown, and return the null handle instead.
+  if (left_string->length() + right_string->length() > i::String::kMaxLength) {
+    return Local<String>();
+  }
   i::Handle<i::String> result = isolate->factory()->NewConsString(
       left_string, right_string).ToHandleChecked();
   return Utils::ToLocal(result);
 }
 
 
-static i::Handle<i::String> NewExternalStringHandle(
-    i::Isolate* isolate,
-    v8::String::ExternalStringResource* resource) {
-  // We do not expect this to fail. Change this if it does.
-  return isolate->factory()->NewExternalStringFromTwoByte(
-      resource).ToHandleChecked();
+static i::MaybeHandle<i::String> NewExternalStringHandle(
+    i::Isolate* isolate, v8::String::ExternalStringResource* resource) {
+  return isolate->factory()->NewExternalStringFromTwoByte(resource);
 }
 
 
-static i::Handle<i::String> NewExternalOneByteStringHandle(
+static i::MaybeHandle<i::String> NewExternalOneByteStringHandle(
     i::Isolate* isolate, v8::String::ExternalOneByteStringResource* resource) {
-  // We do not expect this to fail. Change this if it does.
-  return isolate->factory()
-      ->NewExternalStringFromOneByte(resource)
-      .ToHandleChecked();
+  return isolate->factory()->NewExternalStringFromOneByte(resource);
 }
 
 
@@ -5508,9 +5554,13 @@
   LOG_API(i_isolate, "String::NewExternal");
   ENTER_V8(i_isolate);
   CHECK(resource && resource->data());
-  i::Handle<i::String> result = NewExternalStringHandle(i_isolate, resource);
-  i_isolate->heap()->external_string_table()->AddString(*result);
-  return Utils::ToLocal(result);
+  EXCEPTION_PREAMBLE(i_isolate);
+  i::Handle<i::String> string;
+  has_pending_exception =
+      !NewExternalStringHandle(i_isolate, resource).ToHandle(&string);
+  EXCEPTION_BAILOUT_CHECK(i_isolate, Local<String>());
+  i_isolate->heap()->external_string_table()->AddString(*string);
+  return Utils::ToLocal(string);
 }
 
 
@@ -5546,10 +5596,13 @@
   LOG_API(i_isolate, "String::NewExternal");
   ENTER_V8(i_isolate);
   CHECK(resource && resource->data());
-  i::Handle<i::String> result =
-      NewExternalOneByteStringHandle(i_isolate, resource);
-  i_isolate->heap()->external_string_table()->AddString(*result);
-  return Utils::ToLocal(result);
+  EXCEPTION_PREAMBLE(i_isolate);
+  i::Handle<i::String> string;
+  has_pending_exception =
+      !NewExternalOneByteStringHandle(i_isolate, resource).ToHandle(&string);
+  EXCEPTION_BAILOUT_CHECK(i_isolate, Local<String>());
+  i_isolate->heap()->external_string_table()->AddString(*string);
+  return Utils::ToLocal(string);
 }
 
 
@@ -5581,7 +5634,6 @@
 
 
 bool v8::String::CanMakeExternal() {
-  if (!internal::FLAG_clever_optimizations) return false;
   i::Handle<i::String> obj = Utils::OpenHandle(this);
   i::Isolate* isolate = obj->GetIsolate();
 
@@ -5593,6 +5645,12 @@
 }
 
 
+Isolate* v8::Object::GetIsolate() {
+  i::Isolate* i_isolate = Utils::OpenHandle(this)->GetIsolate();
+  return reinterpret_cast<Isolate*>(i_isolate);
+}
+
+
 Local<v8::Object> v8::Object::New(Isolate* isolate) {
   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   LOG_API(i_isolate, "Object::New");
@@ -5715,7 +5773,6 @@
 
 void v8::Date::DateTimeConfigurationChangeNotification(Isolate* isolate) {
   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
-  if (!i_isolate->IsInitialized()) return;
   ON_BAILOUT(i_isolate, "v8::Date::DateTimeConfigurationChangeNotification()",
              return);
   LOG_API(i_isolate, "Date::DateTimeConfigurationChangeNotification");
@@ -5970,11 +6027,26 @@
 }
 
 
+bool Promise::HasHandler() {
+  i::Handle<i::JSObject> promise = Utils::OpenHandle(this);
+  i::Isolate* isolate = promise->GetIsolate();
+  LOG_API(isolate, "Promise::HasRejectHandler");
+  ENTER_V8(isolate);
+  i::Handle<i::Symbol> key = isolate->factory()->promise_has_handler_symbol();
+  return i::JSObject::GetDataProperty(promise, key)->IsTrue();
+}
+
+
 bool v8::ArrayBuffer::IsExternal() const {
   return Utils::OpenHandle(this)->is_external();
 }
 
 
+bool v8::ArrayBuffer::IsNeuterable() const {
+  return Utils::OpenHandle(this)->is_neuterable();
+}
+
+
 v8::ArrayBuffer::Contents v8::ArrayBuffer::Externalize() {
   i::Handle<i::JSArrayBuffer> obj = Utils::OpenHandle(this);
   Utils::ApiCheck(!obj->is_external(),
@@ -5995,6 +6067,8 @@
   Utils::ApiCheck(obj->is_external(),
                   "v8::ArrayBuffer::Neuter",
                   "Only externalized ArrayBuffers can be neutered");
+  Utils::ApiCheck(obj->is_neuterable(), "v8::ArrayBuffer::Neuter",
+                  "Only neuterable ArrayBuffers can be neutered");
   LOG_API(obj->GetIsolate(), "v8::ArrayBuffer::Neuter()");
   ENTER_V8(isolate);
   i::Runtime::NeuterArrayBuffer(obj);
@@ -6063,78 +6137,22 @@
 }
 
 
-static inline void SetupArrayBufferView(
-    i::Isolate* isolate,
-    i::Handle<i::JSArrayBufferView> obj,
-    i::Handle<i::JSArrayBuffer> buffer,
-    size_t byte_offset,
-    size_t byte_length) {
-  DCHECK(byte_offset + byte_length <=
-         static_cast<size_t>(buffer->byte_length()->Number()));
-
-  obj->set_buffer(*buffer);
-
-  obj->set_weak_next(buffer->weak_first_view());
-  buffer->set_weak_first_view(*obj);
-
-  i::Handle<i::Object> byte_offset_object =
-      isolate->factory()->NewNumberFromSize(byte_offset);
-  obj->set_byte_offset(*byte_offset_object);
-
-  i::Handle<i::Object> byte_length_object =
-      isolate->factory()->NewNumberFromSize(byte_length);
-  obj->set_byte_length(*byte_length_object);
-}
-
-template<typename ElementType,
-         ExternalArrayType array_type,
-         i::ElementsKind elements_kind>
-i::Handle<i::JSTypedArray> NewTypedArray(
-    i::Isolate* isolate,
-    Handle<ArrayBuffer> array_buffer, size_t byte_offset, size_t length) {
-  i::Handle<i::JSTypedArray> obj =
-      isolate->factory()->NewJSTypedArray(array_type);
-  i::Handle<i::JSArrayBuffer> buffer = Utils::OpenHandle(*array_buffer);
-
-  DCHECK(byte_offset % sizeof(ElementType) == 0);
-
-  CHECK(length <= (std::numeric_limits<size_t>::max() / sizeof(ElementType)));
-  CHECK(length <= static_cast<size_t>(i::Smi::kMaxValue));
-  size_t byte_length = length * sizeof(ElementType);
-  SetupArrayBufferView(
-      isolate, obj, buffer, byte_offset, byte_length);
-
-  i::Handle<i::Object> length_object =
-      isolate->factory()->NewNumberFromSize(length);
-  obj->set_length(*length_object);
-
-  i::Handle<i::ExternalArray> elements =
-      isolate->factory()->NewExternalArray(
-          static_cast<int>(length), array_type,
-          static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
-  i::Handle<i::Map> map =
-      i::JSObject::GetElementsTransitionMap(obj, elements_kind);
-  i::JSObject::SetMapAndElements(obj, map, elements);
-  return obj;
-}
-
-
 #define TYPED_ARRAY_NEW(Type, type, TYPE, ctype, size)                       \
   Local<Type##Array> Type##Array::New(Handle<ArrayBuffer> array_buffer,      \
-                                    size_t byte_offset, size_t length) {     \
+                                      size_t byte_offset, size_t length) {   \
     i::Isolate* isolate = Utils::OpenHandle(*array_buffer)->GetIsolate();    \
     LOG_API(isolate,                                                         \
-        "v8::" #Type "Array::New(Handle<ArrayBuffer>, size_t, size_t)");     \
+            "v8::" #Type "Array::New(Handle<ArrayBuffer>, size_t, size_t)"); \
     ENTER_V8(isolate);                                                       \
     if (!Utils::ApiCheck(length <= static_cast<size_t>(i::Smi::kMaxValue),   \
-            "v8::" #Type "Array::New(Handle<ArrayBuffer>, size_t, size_t)",  \
-            "length exceeds max allowed value")) {                           \
-      return Local<Type##Array>();                                          \
+                         "v8::" #Type                                        \
+                         "Array::New(Handle<ArrayBuffer>, size_t, size_t)",  \
+                         "length exceeds max allowed value")) {              \
+      return Local<Type##Array>();                                           \
     }                                                                        \
-    i::Handle<i::JSTypedArray> obj =                                         \
-        NewTypedArray<ctype, v8::kExternal##Type##Array,                     \
-                      i::EXTERNAL_##TYPE##_ELEMENTS>(                        \
-            isolate, array_buffer, byte_offset, length);                     \
+    i::Handle<i::JSArrayBuffer> buffer = Utils::OpenHandle(*array_buffer);   \
+    i::Handle<i::JSTypedArray> obj = isolate->factory()->NewJSTypedArray(    \
+        v8::kExternal##Type##Array, buffer, byte_offset, length);            \
     return Utils::ToLocal##Type##Array(obj);                                 \
   }
 
@@ -6148,9 +6166,8 @@
   i::Isolate* isolate = buffer->GetIsolate();
   LOG_API(isolate, "v8::DataView::New(void*, size_t, size_t)");
   ENTER_V8(isolate);
-  i::Handle<i::JSDataView> obj = isolate->factory()->NewJSDataView();
-  SetupArrayBufferView(
-      isolate, obj, buffer, byte_offset, byte_length);
+  i::Handle<i::JSDataView> obj =
+      isolate->factory()->NewJSDataView(buffer, byte_offset, byte_length);
   return Utils::ToLocal(obj);
 }
 
@@ -6200,22 +6217,21 @@
 }
 
 
-static Local<Symbol> GetWellKnownSymbol(Isolate* isolate, const char* name) {
-  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
-  i::Handle<i::String> i_name =
-      Utils::OpenHandle(*String::NewFromUtf8(isolate, name));
-  i::Handle<i::String> part = i_isolate->factory()->for_intern_string();
-  return Utils::ToLocal(SymbolFor(i_isolate, i_name, part));
-}
-
-
 Local<Symbol> v8::Symbol::GetIterator(Isolate* isolate) {
-  return GetWellKnownSymbol(isolate, "Symbol.iterator");
+  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+  return Utils::ToLocal(i_isolate->factory()->iterator_symbol());
 }
 
 
 Local<Symbol> v8::Symbol::GetUnscopables(Isolate* isolate) {
-  return GetWellKnownSymbol(isolate, "Symbol.unscopables");
+  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+  return Utils::ToLocal(i_isolate->factory()->unscopables_symbol());
+}
+
+
+Local<Symbol> v8::Symbol::GetToStringTag(Isolate* isolate) {
+  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+  return Utils::ToLocal(i_isolate->factory()->to_string_tag_symbol());
 }
 
 
@@ -6253,7 +6269,6 @@
 
 Local<Number> v8::Number::New(Isolate* isolate, double value) {
   i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
-  DCHECK(internal_isolate->IsInitialized());
   if (std::isnan(value)) {
     // Introduce only canonical NaN value into the VM, to avoid signaling NaNs.
     value = base::OS::nan_value();
@@ -6266,7 +6281,6 @@
 
 Local<Integer> v8::Integer::New(Isolate* isolate, int32_t value) {
   i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
-  DCHECK(internal_isolate->IsInitialized());
   if (i::Smi::IsValid(value)) {
     return Utils::IntegerToLocal(i::Handle<i::Object>(i::Smi::FromInt(value),
                                                       internal_isolate));
@@ -6279,7 +6293,6 @@
 
 Local<Integer> v8::Integer::NewFromUnsigned(Isolate* isolate, uint32_t value) {
   i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
-  DCHECK(internal_isolate->IsInitialized());
   bool fits_into_int32_t = (value & (1 << 31)) == 0;
   if (fits_into_int32_t) {
     return Integer::New(isolate, static_cast<int32_t>(value));
@@ -6290,57 +6303,6 @@
 }
 
 
-bool V8::AddMessageListener(MessageCallback that, Handle<Value> data) {
-  i::Isolate* isolate = i::Isolate::Current();
-  ON_BAILOUT(isolate, "v8::V8::AddMessageListener()", return false);
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  NeanderArray listeners(isolate->factory()->message_listeners());
-  NeanderObject obj(isolate, 2);
-  obj.set(0, *isolate->factory()->NewForeign(FUNCTION_ADDR(that)));
-  obj.set(1, data.IsEmpty() ? isolate->heap()->undefined_value()
-          : *Utils::OpenHandle(*data));
-  listeners.add(obj.value());
-  return true;
-}
-
-
-void V8::RemoveMessageListeners(MessageCallback that) {
-  i::Isolate* isolate = i::Isolate::Current();
-  ON_BAILOUT(isolate, "v8::V8::RemoveMessageListeners()", return);
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  NeanderArray listeners(isolate->factory()->message_listeners());
-  for (int i = 0; i < listeners.length(); i++) {
-    if (listeners.get(i)->IsUndefined()) continue;  // skip deleted ones
-
-    NeanderObject listener(i::JSObject::cast(listeners.get(i)));
-    i::Handle<i::Foreign> callback_obj(i::Foreign::cast(listener.get(0)));
-    if (callback_obj->foreign_address() == FUNCTION_ADDR(that)) {
-      listeners.set(i, isolate->heap()->undefined_value());
-    }
-  }
-}
-
-
-void V8::SetCaptureStackTraceForUncaughtExceptions(
-    bool capture,
-    int frame_limit,
-    StackTrace::StackTraceOptions options) {
-  i::Isolate::Current()->SetCaptureStackTraceForUncaughtExceptions(
-      capture,
-      frame_limit,
-      options);
-}
-
-
-void V8::SetFailedAccessCheckCallbackFunction(
-    FailedAccessCheckCallback callback) {
-  i::Isolate* isolate = i::Isolate::Current();
-  isolate->SetFailedAccessCheckCallback(callback);
-}
-
-
 void Isolate::CollectAllGarbage(const char* gc_reason) {
   reinterpret_cast<i::Isolate*>(this)->heap()->CollectAllGarbage(
       i::Heap::kNoGCFlags, gc_reason);
@@ -6470,13 +6432,6 @@
 }
 
 
-void V8::RemoveGCPrologueCallback(GCPrologueCallback callback) {
-  i::Isolate* isolate = i::Isolate::Current();
-  isolate->heap()->RemoveGCPrologueCallback(
-      reinterpret_cast<v8::Isolate::GCPrologueCallback>(callback));
-}
-
-
 void V8::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
   i::Isolate* isolate = i::Isolate::Current();
   isolate->heap()->AddGCEpilogueCallback(
@@ -6486,62 +6441,49 @@
 }
 
 
-void V8::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
-  i::Isolate* isolate = i::Isolate::Current();
-  isolate->heap()->RemoveGCEpilogueCallback(
-      reinterpret_cast<v8::Isolate::GCEpilogueCallback>(callback));
-}
-
-
-void V8::AddMemoryAllocationCallback(MemoryAllocationCallback callback,
-                                     ObjectSpace space,
-                                     AllocationAction action) {
-  i::Isolate* isolate = i::Isolate::Current();
+void Isolate::AddMemoryAllocationCallback(MemoryAllocationCallback callback,
+                                          ObjectSpace space,
+                                          AllocationAction action) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
   isolate->memory_allocator()->AddMemoryAllocationCallback(
       callback, space, action);
 }
 
 
-void V8::RemoveMemoryAllocationCallback(MemoryAllocationCallback callback) {
-  i::Isolate* isolate = i::Isolate::Current();
+void Isolate::RemoveMemoryAllocationCallback(
+    MemoryAllocationCallback callback) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
   isolate->memory_allocator()->RemoveMemoryAllocationCallback(
       callback);
 }
 
 
-void V8::TerminateExecution(Isolate* isolate) {
-  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
-  i_isolate->stack_guard()->RequestTerminateExecution();
+void Isolate::TerminateExecution() {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  isolate->stack_guard()->RequestTerminateExecution();
 }
 
 
-bool V8::IsExecutionTerminating(Isolate* isolate) {
-  i::Isolate* i_isolate = isolate != NULL ?
-      reinterpret_cast<i::Isolate*>(isolate) : i::Isolate::Current();
-  return IsExecutionTerminatingCheck(i_isolate);
+bool Isolate::IsExecutionTerminating() {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  return IsExecutionTerminatingCheck(isolate);
 }
 
 
-void V8::CancelTerminateExecution(Isolate* isolate) {
-  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
-  i_isolate->stack_guard()->ClearTerminateExecution();
-  i_isolate->CancelTerminateExecution();
+void Isolate::CancelTerminateExecution() {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  isolate->stack_guard()->ClearTerminateExecution();
+  isolate->CancelTerminateExecution();
 }
 
 
 void Isolate::RequestInterrupt(InterruptCallback callback, void* data) {
-  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(this);
-  i_isolate->set_api_interrupt_callback(callback);
-  i_isolate->set_api_interrupt_callback_data(data);
-  i_isolate->stack_guard()->RequestApiInterrupt();
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  isolate->RequestInterrupt(callback, data);
 }
 
 
 void Isolate::ClearInterrupt() {
-  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(this);
-  i_isolate->stack_guard()->ClearApiInterrupt();
-  i_isolate->set_api_interrupt_callback(NULL);
-  i_isolate->set_api_interrupt_callback_data(NULL);
 }
 
 
@@ -6567,7 +6509,7 @@
 
 
 Isolate* Isolate::New(const Isolate::CreateParams& params) {
-  i::Isolate* isolate = new i::Isolate();
+  i::Isolate* isolate = new i::Isolate(params.enable_serializer);
   Isolate* v8_isolate = reinterpret_cast<Isolate*>(isolate);
   if (params.entry_hook) {
     isolate->set_function_entry_hook(params.entry_hook);
@@ -6578,9 +6520,6 @@
                                            params.code_event_handler);
   }
   SetResourceConstraints(isolate, params.constraints);
-  if (params.enable_serializer) {
-    isolate->enable_serializer();
-  }
   // TODO(jochen): Once we got rid of Isolate::Current(), we can remove this.
   Isolate::Scope isolate_scope(v8_isolate);
   if (params.entry_hook || !i::Snapshot::Initialize(isolate)) {
@@ -6670,14 +6609,6 @@
 
 void Isolate::GetHeapStatistics(HeapStatistics* heap_statistics) {
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
-  if (!isolate->IsInitialized()) {
-    heap_statistics->total_heap_size_ = 0;
-    heap_statistics->total_heap_size_executable_ = 0;
-    heap_statistics->total_physical_size_ = 0;
-    heap_statistics->used_heap_size_ = 0;
-    heap_statistics->heap_size_limit_ = 0;
-    return;
-  }
   i::Heap* heap = isolate->heap();
   heap_statistics->total_heap_size_ = heap->CommittedMemory();
   heap_statistics->total_heap_size_executable_ =
@@ -6688,9 +6619,17 @@
 }
 
 
+void Isolate::GetStackSample(const RegisterState& state, void** frames,
+                             size_t frames_limit, SampleInfo* sample_info) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  i::TickSample::GetStackSample(isolate, state, i::TickSample::kSkipCEntryFrame,
+                                frames, frames_limit, sample_info);
+}
+
+
 void Isolate::SetEventLogger(LogEventCallback that) {
   // Do not overwrite the event logger if we want to log explicitly.
-  if (i::FLAG_log_timer_events) return;
+  if (i::FLAG_log_internal_timer_events) return;
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
   isolate->set_event_logger(that);
 }
@@ -6709,6 +6648,13 @@
 }
 
 
+void Isolate::SetPromiseRejectCallback(PromiseRejectCallback callback) {
+  if (callback == NULL) return;
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  isolate->SetPromiseRejectCallback(callback);
+}
+
+
 void Isolate::RunMicrotasks() {
   reinterpret_cast<i::Isolate*>(this)->RunMicrotasks();
 }
@@ -6771,7 +6717,7 @@
 }
 
 
-bool v8::Isolate::IdleNotification(int idle_time_in_ms) {
+bool Isolate::IdleNotification(int idle_time_in_ms) {
   // Returning true tells the caller that it need not
   // continue to call IdleNotification.
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
@@ -6780,7 +6726,16 @@
 }
 
 
-void v8::Isolate::LowMemoryNotification() {
+bool Isolate::IdleNotificationDeadline(double deadline_in_seconds) {
+  // Returning true tells the caller that it need not
+  // continue to call IdleNotification.
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  if (!i::FLAG_use_idle_notification) return true;
+  return isolate->heap()->IdleNotification(deadline_in_seconds);
+}
+
+
+void Isolate::LowMemoryNotification() {
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
   {
     i::HistogramTimerScope idle_notification_scope(
@@ -6790,14 +6745,14 @@
 }
 
 
-int v8::Isolate::ContextDisposedNotification() {
+int Isolate::ContextDisposedNotification(bool dependant_context) {
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
-  return isolate->heap()->NotifyContextDisposed();
+  return isolate->heap()->NotifyContextDisposed(dependant_context);
 }
 
 
-void v8::Isolate::SetJitCodeEventHandler(JitCodeEventOptions options,
-                                         JitCodeEventHandler event_handler) {
+void Isolate::SetJitCodeEventHandler(JitCodeEventOptions options,
+                                     JitCodeEventHandler event_handler) {
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
   // Ensure that logging is initialized for our isolate.
   isolate->InitializeLoggingAndCounters();
@@ -6805,13 +6760,134 @@
 }
 
 
-void v8::Isolate::SetStackLimit(uintptr_t stack_limit) {
+void Isolate::SetStackLimit(uintptr_t stack_limit) {
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
   CHECK(stack_limit);
   isolate->stack_guard()->SetStackLimit(stack_limit);
 }
 
 
+void Isolate::GetCodeRange(void** start, size_t* length_in_bytes) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  if (isolate->code_range()->valid()) {
+    *start = isolate->code_range()->start();
+    *length_in_bytes = isolate->code_range()->size();
+  } else {
+    *start = NULL;
+    *length_in_bytes = 0;
+  }
+}
+
+
+void Isolate::SetFatalErrorHandler(FatalErrorCallback that) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  isolate->set_exception_behavior(that);
+}
+
+
+void Isolate::SetAllowCodeGenerationFromStringsCallback(
+    AllowCodeGenerationFromStringsCallback callback) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  isolate->set_allow_code_gen_callback(callback);
+}
+
+
+bool Isolate::IsDead() {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  return isolate->IsDead();
+}
+
+
+bool Isolate::AddMessageListener(MessageCallback that, Handle<Value> data) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  ON_BAILOUT(isolate, "v8::V8::AddMessageListener()", return false);
+  ENTER_V8(isolate);
+  i::HandleScope scope(isolate);
+  NeanderArray listeners(isolate->factory()->message_listeners());
+  NeanderObject obj(isolate, 2);
+  obj.set(0, *isolate->factory()->NewForeign(FUNCTION_ADDR(that)));
+  obj.set(1, data.IsEmpty() ? isolate->heap()->undefined_value()
+                            : *Utils::OpenHandle(*data));
+  listeners.add(isolate, obj.value());
+  return true;
+}
+
+
+void Isolate::RemoveMessageListeners(MessageCallback that) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  ON_BAILOUT(isolate, "v8::V8::RemoveMessageListeners()", return);
+  ENTER_V8(isolate);
+  i::HandleScope scope(isolate);
+  NeanderArray listeners(isolate->factory()->message_listeners());
+  for (int i = 0; i < listeners.length(); i++) {
+    if (listeners.get(i)->IsUndefined()) continue;  // skip deleted ones
+
+    NeanderObject listener(i::JSObject::cast(listeners.get(i)));
+    i::Handle<i::Foreign> callback_obj(i::Foreign::cast(listener.get(0)));
+    if (callback_obj->foreign_address() == FUNCTION_ADDR(that)) {
+      listeners.set(i, isolate->heap()->undefined_value());
+    }
+  }
+}
+
+
+void Isolate::SetFailedAccessCheckCallbackFunction(
+    FailedAccessCheckCallback callback) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  isolate->SetFailedAccessCheckCallback(callback);
+}
+
+
+void Isolate::SetCaptureStackTraceForUncaughtExceptions(
+    bool capture, int frame_limit, StackTrace::StackTraceOptions options) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  isolate->SetCaptureStackTraceForUncaughtExceptions(capture, frame_limit,
+                                                     options);
+}
+
+
+void Isolate::VisitExternalResources(ExternalResourceVisitor* visitor) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  isolate->heap()->VisitExternalResources(visitor);
+}
+
+
+class VisitorAdapter : public i::ObjectVisitor {
+ public:
+  explicit VisitorAdapter(PersistentHandleVisitor* visitor)
+      : visitor_(visitor) {}
+  virtual void VisitPointers(i::Object** start, i::Object** end) {
+    UNREACHABLE();
+  }
+  virtual void VisitEmbedderReference(i::Object** p, uint16_t class_id) {
+    Value* value = ToApi<Value>(i::Handle<i::Object>(p));
+    visitor_->VisitPersistentHandle(
+        reinterpret_cast<Persistent<Value>*>(&value), class_id);
+  }
+
+ private:
+  PersistentHandleVisitor* visitor_;
+};
+
+
+void Isolate::VisitHandlesWithClassIds(PersistentHandleVisitor* visitor) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  i::DisallowHeapAllocation no_allocation;
+  VisitorAdapter visitor_adapter(visitor);
+  isolate->global_handles()->IterateAllRootsWithClassIds(&visitor_adapter);
+}
+
+
+void Isolate::VisitHandlesForPartialDependence(
+    PersistentHandleVisitor* visitor) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  i::DisallowHeapAllocation no_allocation;
+  VisitorAdapter visitor_adapter(visitor);
+  isolate->global_handles()->IterateAllRootsInNewSpaceWithClassIds(
+      &visitor_adapter);
+}
+
+
 String::Utf8Value::Utf8Value(v8::Handle<v8::Value> obj)
     : str_(NULL), length_(0) {
   i::Isolate* isolate = i::Isolate::Current();
@@ -6819,7 +6895,7 @@
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
   TryCatch try_catch;
-  Handle<String> str = obj->ToString();
+  Handle<String> str = obj->ToString(reinterpret_cast<v8::Isolate*>(isolate));
   if (str.IsEmpty()) return;
   i::Handle<i::String> i_str = Utils::OpenHandle(*str);
   length_ = v8::Utf8Length(*i_str, isolate);
@@ -6840,7 +6916,7 @@
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
   TryCatch try_catch;
-  Handle<String> str = obj->ToString();
+  Handle<String> str = obj->ToString(reinterpret_cast<v8::Isolate*>(isolate));
   if (str.IsEmpty()) return;
   length_ = str->Length();
   str_ = i::NewArray<uint16_t>(length_ + 1);
@@ -6886,6 +6962,27 @@
 #undef DEFINE_ERROR
 
 
+Local<Message> Exception::CreateMessage(Handle<Value> exception) {
+  i::Handle<i::Object> obj = Utils::OpenHandle(*exception);
+  if (!obj->IsHeapObject()) return Local<Message>();
+  i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate();
+  ENTER_V8(isolate);
+  i::HandleScope scope(isolate);
+  return Utils::MessageToLocal(
+      scope.CloseAndEscape(isolate->CreateMessage(obj, NULL)));
+}
+
+
+Local<StackTrace> Exception::GetStackTrace(Handle<Value> exception) {
+  i::Handle<i::Object> obj = Utils::OpenHandle(*exception);
+  if (!obj->IsJSObject()) return Local<StackTrace>();
+  i::Handle<i::JSObject> js_obj = i::Handle<i::JSObject>::cast(obj);
+  i::Isolate* isolate = js_obj->GetIsolate();
+  ENTER_V8(isolate);
+  return Utils::StackTraceToLocal(isolate->GetDetailedStackTrace(js_obj));
+}
+
+
 // --- D e b u g   S u p p o r t ---
 
 bool Debug::SetDebugEventListener(EventCallback that, Handle<Value> data) {
@@ -6946,7 +7043,6 @@
 Local<Value> Debug::Call(v8::Handle<v8::Function> fun,
                          v8::Handle<v8::Value> data) {
   i::Isolate* isolate = i::Isolate::Current();
-  if (!isolate->IsInitialized()) return Local<Value>();
   ON_BAILOUT(isolate, "v8::Debug::Call()", return Local<Value>());
   ENTER_V8(isolate);
   i::MaybeHandle<i::Object> maybe_result;
@@ -6967,7 +7063,6 @@
 
 Local<Value> Debug::GetMirror(v8::Handle<v8::Value> obj) {
   i::Isolate* isolate = i::Isolate::Current();
-  if (!isolate->IsInitialized()) return Local<Value>();
   ON_BAILOUT(isolate, "v8::Debug::GetMirror()", return Local<Value>());
   ENTER_V8(isolate);
   v8::EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
@@ -7056,6 +7151,19 @@
 }
 
 
+unsigned int CpuProfileNode::GetHitLineCount() const {
+  const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
+  return node->GetHitLineCount();
+}
+
+
+bool CpuProfileNode::GetLineTicks(LineTick* entries,
+                                  unsigned int length) const {
+  const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
+  return node->GetLineTicks(entries, length);
+}
+
+
 const char* CpuProfileNode::GetBailoutReason() const {
   const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
   return node->entry()->bailout_reason();
@@ -7173,13 +7281,13 @@
 
 void CpuProfiler::SetIdle(bool is_idle) {
   i::Isolate* isolate = reinterpret_cast<i::CpuProfiler*>(this)->isolate();
-  i::StateTag state = isolate->current_vm_state();
-  DCHECK(state == i::EXTERNAL || state == i::IDLE);
+  v8::StateTag state = isolate->current_vm_state();
+  DCHECK(state == v8::EXTERNAL || state == v8::IDLE);
   if (isolate->js_entry_sp() != NULL) return;
   if (is_idle) {
-    isolate->set_current_vm_state(i::IDLE);
-  } else if (state == i::IDLE) {
-    isolate->set_current_vm_state(i::EXTERNAL);
+    isolate->set_current_vm_state(v8::IDLE);
+  } else if (state == v8::IDLE) {
+    isolate->set_current_vm_state(v8::EXTERNAL);
   }
 }
 
diff --git a/src/api.h b/src/api.h
index 9aed5dd..1d2a8c8 100644
--- a/src/api.h
+++ b/src/api.h
@@ -54,7 +54,8 @@
     return obj_.value();
   }
 
-  void add(v8::internal::Handle<v8::internal::Object> value);
+  void add(internal::Isolate* isolate,
+           v8::internal::Handle<v8::internal::Object> value);
 
   int length();
 
@@ -232,6 +233,8 @@
 
   static inline Local<Message> MessageToLocal(
       v8::internal::Handle<v8::internal::Object> obj);
+  static inline Local<Promise> PromiseToLocal(
+      v8::internal::Handle<v8::internal::JSObject> obj);
   static inline Local<StackTrace> StackTraceToLocal(
       v8::internal::Handle<v8::internal::JSArray> obj);
   static inline Local<StackFrame> StackFrameToLocal(
@@ -355,6 +358,7 @@
 MAKE_TO_LOCAL(AccessorSignatureToLocal, FunctionTemplateInfo, AccessorSignature)
 MAKE_TO_LOCAL(ToLocal, TypeSwitchInfo, TypeSwitch)
 MAKE_TO_LOCAL(MessageToLocal, Object, Message)
+MAKE_TO_LOCAL(PromiseToLocal, JSObject, Promise)
 MAKE_TO_LOCAL(StackTraceToLocal, JSArray, StackTrace)
 MAKE_TO_LOCAL(StackFrameToLocal, JSObject, StackFrame)
 MAKE_TO_LOCAL(NumberToLocal, Object, Number)
diff --git a/src/arguments.h b/src/arguments.h
index 9fb2da3..e6c6db5 100644
--- a/src/arguments.h
+++ b/src/arguments.h
@@ -67,39 +67,24 @@
 // For each type of callback, we have a list of arguments
 // They are used to generate the Call() functions below
 // These aren't included in the list as they have duplicate signatures
-// F(NamedPropertyEnumeratorCallback, ...)
+// F(GenericNamedPropertyEnumeratorCallback, ...)
+// F(GenericNamedPropertyGetterCallback, ...)
 
 #define FOR_EACH_CALLBACK_TABLE_MAPPING_0(F) \
-  F(IndexedPropertyEnumeratorCallback, v8::Array) \
+  F(IndexedPropertyEnumeratorCallback, v8::Array)
 
-#define FOR_EACH_CALLBACK_TABLE_MAPPING_1(F) \
-  F(NamedPropertyGetterCallback, v8::Value, v8::Local<v8::String>) \
-  F(AccessorNameGetterCallback, v8::Value, v8::Local<v8::Name>) \
-  F(NamedPropertyQueryCallback, \
-    v8::Integer, \
-    v8::Local<v8::String>) \
-  F(NamedPropertyDeleterCallback, \
-    v8::Boolean, \
-    v8::Local<v8::String>) \
-  F(IndexedPropertyGetterCallback, \
-    v8::Value, \
-    uint32_t) \
-  F(IndexedPropertyQueryCallback, \
-    v8::Integer, \
-    uint32_t) \
-  F(IndexedPropertyDeleterCallback, \
-    v8::Boolean, \
-    uint32_t) \
+#define FOR_EACH_CALLBACK_TABLE_MAPPING_1(F)                               \
+  F(AccessorNameGetterCallback, v8::Value, v8::Local<v8::Name>)            \
+  F(GenericNamedPropertyQueryCallback, v8::Integer, v8::Local<v8::Name>)   \
+  F(GenericNamedPropertyDeleterCallback, v8::Boolean, v8::Local<v8::Name>) \
+  F(IndexedPropertyGetterCallback, v8::Value, uint32_t)                    \
+  F(IndexedPropertyQueryCallback, v8::Integer, uint32_t)                   \
+  F(IndexedPropertyDeleterCallback, v8::Boolean, uint32_t)
 
-#define FOR_EACH_CALLBACK_TABLE_MAPPING_2(F) \
-  F(NamedPropertySetterCallback, \
-    v8::Value, \
-    v8::Local<v8::String>, \
-    v8::Local<v8::Value>) \
-  F(IndexedPropertySetterCallback, \
-    v8::Value, \
-    uint32_t, \
-    v8::Local<v8::Value>) \
+#define FOR_EACH_CALLBACK_TABLE_MAPPING_2(F)                            \
+  F(GenericNamedPropertySetterCallback, v8::Value, v8::Local<v8::Name>, \
+    v8::Local<v8::Value>)                                               \
+  F(IndexedPropertySetterCallback, v8::Value, uint32_t, v8::Local<v8::Value>)
 
 #define FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(F) \
   F(AccessorNameSetterCallback, \
diff --git a/src/arm/assembler-arm-inl.h b/src/arm/assembler-arm-inl.h
index 8b5c4b8..876cd3d 100644
--- a/src/arm/assembler-arm-inl.h
+++ b/src/arm/assembler-arm-inl.h
@@ -70,6 +70,12 @@
 }
 
 
+// static
+int DwVfpRegister::NumAllocatableAliasedRegisters() {
+  return LowDwVfpRegister::kMaxNumLowRegisters - kNumReservedRegisters;
+}
+
+
 int DwVfpRegister::ToAllocationIndex(DwVfpRegister reg) {
   DCHECK(!reg.is(kDoubleRegZero));
   DCHECK(!reg.is(kScratchDoubleReg));
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index 96f28f9..105d711 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -109,6 +109,9 @@
 
   if (cpu.architecture() >= 7) {
     if (FLAG_enable_armv7) supported_ |= 1u << ARMv7;
+    if (FLAG_enable_armv8 && cpu.architecture() >= 8) {
+      supported_ |= 1u << ARMv8;
+    }
     if (FLAG_enable_unaligned_accesses) supported_ |= 1u << UNALIGNED_ACCESSES;
     // Use movw/movt for QUALCOMM ARMv7 cores.
     if (FLAG_enable_movw_movt && cpu.implementer() == base::CPU::QUALCOMM) {
@@ -124,6 +127,11 @@
   }
 
   if (FLAG_enable_32dregs && cpu.has_vfp3_d32()) supported_ |= 1u << VFP32DREGS;
+
+  if (cpu.implementer() == base::CPU::NVIDIA &&
+      cpu.variant() == base::CPU::NVIDIA_DENVER) {
+    supported_ |= 1u << COHERENT_CACHE;
+  }
 #endif
 
   DCHECK(!IsSupported(VFP3) || IsSupported(ARMv7));
@@ -185,14 +193,15 @@
 void CpuFeatures::PrintFeatures() {
   printf(
     "ARMv7=%d VFP3=%d VFP32DREGS=%d NEON=%d SUDIV=%d UNALIGNED_ACCESSES=%d "
-    "MOVW_MOVT_IMMEDIATE_LOADS=%d",
+    "MOVW_MOVT_IMMEDIATE_LOADS=%d COHERENT_CACHE=%d",
     CpuFeatures::IsSupported(ARMv7),
     CpuFeatures::IsSupported(VFP3),
     CpuFeatures::IsSupported(VFP32DREGS),
     CpuFeatures::IsSupported(NEON),
     CpuFeatures::IsSupported(SUDIV),
     CpuFeatures::IsSupported(UNALIGNED_ACCESSES),
-    CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS));
+    CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS),
+    CpuFeatures::IsSupported(COHERENT_CACHE));
 #ifdef __arm__
   bool eabi_hardfloat = base::OS::ArmUsingHardFloat();
 #elif USE_EABI_HARDFLOAT
@@ -472,7 +481,6 @@
   first_const_pool_32_use_ = -1;
   first_const_pool_64_use_ = -1;
   last_bound_pos_ = 0;
-  constant_pool_available_ = !FLAG_enable_ool_constant_pool;
   ClearRecordedAstId();
 }
 
@@ -1056,7 +1064,8 @@
 
 static bool use_mov_immediate_load(const Operand& x,
                                    const Assembler* assembler) {
-  if (assembler != NULL && !assembler->is_constant_pool_available()) {
+  if (FLAG_enable_ool_constant_pool && assembler != NULL &&
+      !assembler->is_ool_constant_pool_available()) {
     return true;
   } else if (CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS) &&
              (assembler == NULL || !assembler->predictable_code_size())) {
@@ -1137,7 +1146,7 @@
       mov(rd, target, LeaveCC, cond);
     }
   } else {
-    DCHECK(is_constant_pool_available());
+    DCHECK(!FLAG_enable_ool_constant_pool || is_ool_constant_pool_available());
     ConstantPoolArray::LayoutSection section = ConstantPoolAddEntry(rinfo);
     if (section == ConstantPoolArray::EXTENDED_SECTION) {
       DCHECK(FLAG_enable_ool_constant_pool);
@@ -1335,7 +1344,7 @@
 void Assembler::b(int branch_offset, Condition cond) {
   DCHECK((branch_offset & 3) == 0);
   int imm24 = branch_offset >> 2;
-  DCHECK(is_int24(imm24));
+  CHECK(is_int24(imm24));
   emit(cond | B27 | B25 | (imm24 & kImm24Mask));
 
   if (cond == al) {
@@ -1349,7 +1358,7 @@
   positions_recorder()->WriteRecordedPositions();
   DCHECK((branch_offset & 3) == 0);
   int imm24 = branch_offset >> 2;
-  DCHECK(is_int24(imm24));
+  CHECK(is_int24(imm24));
   emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask));
 }
 
@@ -1359,7 +1368,7 @@
   DCHECK((branch_offset & 1) == 0);
   int h = ((branch_offset & 2) >> 1)*B24;
   int imm24 = branch_offset >> 2;
-  DCHECK(is_int24(imm24));
+  CHECK(is_int24(imm24));
   emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask));
 }
 
@@ -1501,7 +1510,7 @@
     //
     // When the label gets bound: target_at extracts the link and target_at_put
     // patches the instructions.
-    DCHECK(is_uint24(link));
+    CHECK(is_uint24(link));
     BlockConstPoolScope block_const_pool(this);
     emit(link);
     nop(dst.code());
@@ -1571,11 +1580,27 @@
 }
 
 
-void Assembler::mul(Register dst, Register src1, Register src2,
-                    SBit s, Condition cond) {
+void Assembler::mul(Register dst, Register src1, Register src2, SBit s,
+                    Condition cond) {
   DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
   // dst goes in bits 16-19 for this instruction!
-  emit(cond | s | dst.code()*B16 | src2.code()*B8 | B7 | B4 | src1.code());
+  emit(cond | s | dst.code() * B16 | src2.code() * B8 | B7 | B4 | src1.code());
+}
+
+
+void Assembler::smmla(Register dst, Register src1, Register src2, Register srcA,
+                      Condition cond) {
+  DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
+  emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 |
+       srcA.code() * B12 | src2.code() * B8 | B4 | src1.code());
+}
+
+
+void Assembler::smmul(Register dst, Register src1, Register src2,
+                      Condition cond) {
+  DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
+  emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 | 0xf * B12 |
+       src2.code() * B8 | B4 | src1.code());
 }
 
 
@@ -1779,71 +1804,119 @@
 }
 
 
-void Assembler::uxtb(Register dst,
-                     const Operand& src,
-                     Condition cond) {
+void Assembler::sxtb(Register dst, Register src, int rotate, Condition cond) {
+  // Instruction details available in ARM DDI 0406C.b, A8.8.233.
+  // cond(31-28) | 01101010(27-20) | 1111(19-16) |
+  // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
+  DCHECK(!dst.is(pc));
+  DCHECK(!src.is(pc));
+  DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
+  emit(cond | 0x6A * B20 | 0xF * B16 | dst.code() * B12 |
+       ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
+}
+
+
+void Assembler::sxtab(Register dst, Register src1, Register src2, int rotate,
+                      Condition cond) {
+  // Instruction details available in ARM DDI 0406C.b, A8.8.233.
+  // cond(31-28) | 01101010(27-20) | Rn(19-16) |
+  // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
+  DCHECK(!dst.is(pc));
+  DCHECK(!src1.is(pc));
+  DCHECK(!src2.is(pc));
+  DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
+  emit(cond | 0x6A * B20 | src1.code() * B16 | dst.code() * B12 |
+       ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
+}
+
+
+void Assembler::sxth(Register dst, Register src, int rotate, Condition cond) {
+  // Instruction details available in ARM DDI 0406C.b, A8.8.235.
+  // cond(31-28) | 01101011(27-20) | 1111(19-16) |
+  // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
+  DCHECK(!dst.is(pc));
+  DCHECK(!src.is(pc));
+  DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
+  emit(cond | 0x6B * B20 | 0xF * B16 | dst.code() * B12 |
+       ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
+}
+
+
+void Assembler::sxtah(Register dst, Register src1, Register src2, int rotate,
+                      Condition cond) {
+  // Instruction details available in ARM DDI 0406C.b, A8.8.235.
+  // cond(31-28) | 01101011(27-20) | Rn(19-16) |
+  // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
+  DCHECK(!dst.is(pc));
+  DCHECK(!src1.is(pc));
+  DCHECK(!src2.is(pc));
+  DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
+  emit(cond | 0x6B * B20 | src1.code() * B16 | dst.code() * B12 |
+       ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
+}
+
+
+void Assembler::uxtb(Register dst, Register src, int rotate, Condition cond) {
   // Instruction details available in ARM DDI 0406C.b, A8.8.274.
   // cond(31-28) | 01101110(27-20) | 1111(19-16) |
   // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
   DCHECK(!dst.is(pc));
-  DCHECK(!src.rm().is(pc));
-  DCHECK(!src.rm().is(no_reg));
-  DCHECK(src.rs().is(no_reg));
-  DCHECK((src.shift_imm_ == 0) ||
-         (src.shift_imm_ == 8) ||
-         (src.shift_imm_ == 16) ||
-         (src.shift_imm_ == 24));
-  // Operand maps ROR #0 to LSL #0.
-  DCHECK((src.shift_op() == ROR) ||
-         ((src.shift_op() == LSL) && (src.shift_imm_ == 0)));
-  emit(cond | 0x6E*B20 | 0xF*B16 | dst.code()*B12 |
-       ((src.shift_imm_ >> 1)&0xC)*B8 | 7*B4 | src.rm().code());
+  DCHECK(!src.is(pc));
+  DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
+  emit(cond | 0x6E * B20 | 0xF * B16 | dst.code() * B12 |
+       ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
 }
 
 
-void Assembler::uxtab(Register dst,
-                      Register src1,
-                      const Operand& src2,
+void Assembler::uxtab(Register dst, Register src1, Register src2, int rotate,
                       Condition cond) {
   // Instruction details available in ARM DDI 0406C.b, A8.8.271.
   // cond(31-28) | 01101110(27-20) | Rn(19-16) |
   // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
   DCHECK(!dst.is(pc));
   DCHECK(!src1.is(pc));
-  DCHECK(!src2.rm().is(pc));
-  DCHECK(!src2.rm().is(no_reg));
-  DCHECK(src2.rs().is(no_reg));
-  DCHECK((src2.shift_imm_ == 0) ||
-         (src2.shift_imm_ == 8) ||
-         (src2.shift_imm_ == 16) ||
-         (src2.shift_imm_ == 24));
-  // Operand maps ROR #0 to LSL #0.
-  DCHECK((src2.shift_op() == ROR) ||
-         ((src2.shift_op() == LSL) && (src2.shift_imm_ == 0)));
-  emit(cond | 0x6E*B20 | src1.code()*B16 | dst.code()*B12 |
-       ((src2.shift_imm_ >> 1) &0xC)*B8 | 7*B4 | src2.rm().code());
+  DCHECK(!src2.is(pc));
+  DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
+  emit(cond | 0x6E * B20 | src1.code() * B16 | dst.code() * B12 |
+       ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
 }
 
 
-void Assembler::uxtb16(Register dst,
-                       const Operand& src,
-                       Condition cond) {
+void Assembler::uxtb16(Register dst, Register src, int rotate, Condition cond) {
   // Instruction details available in ARM DDI 0406C.b, A8.8.275.
   // cond(31-28) | 01101100(27-20) | 1111(19-16) |
   // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
   DCHECK(!dst.is(pc));
-  DCHECK(!src.rm().is(pc));
-  DCHECK(!src.rm().is(no_reg));
-  DCHECK(src.rs().is(no_reg));
-  DCHECK((src.shift_imm_ == 0) ||
-         (src.shift_imm_ == 8) ||
-         (src.shift_imm_ == 16) ||
-         (src.shift_imm_ == 24));
-  // Operand maps ROR #0 to LSL #0.
-  DCHECK((src.shift_op() == ROR) ||
-         ((src.shift_op() == LSL) && (src.shift_imm_ == 0)));
-  emit(cond | 0x6C*B20 | 0xF*B16 | dst.code()*B12 |
-       ((src.shift_imm_ >> 1)&0xC)*B8 | 7*B4 | src.rm().code());
+  DCHECK(!src.is(pc));
+  DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
+  emit(cond | 0x6C * B20 | 0xF * B16 | dst.code() * B12 |
+       ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
+}
+
+
+void Assembler::uxth(Register dst, Register src, int rotate, Condition cond) {
+  // Instruction details available in ARM DDI 0406C.b, A8.8.276.
+  // cond(31-28) | 01101111(27-20) | 1111(19-16) |
+  // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
+  DCHECK(!dst.is(pc));
+  DCHECK(!src.is(pc));
+  DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
+  emit(cond | 0x6F * B20 | 0xF * B16 | dst.code() * B12 |
+       ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
+}
+
+
+void Assembler::uxtah(Register dst, Register src1, Register src2, int rotate,
+                      Condition cond) {
+  // Instruction details available in ARM DDI 0406C.b, A8.8.273.
+  // cond(31-28) | 01101111(27-20) | Rn(19-16) |
+  // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
+  DCHECK(!dst.is(pc));
+  DCHECK(!src1.is(pc));
+  DCHECK(!src2.is(pc));
+  DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
+  emit(cond | 0x6F * B20 | src1.code() * B16 | dst.code() * B12 |
+       ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
 }
 
 
@@ -2418,6 +2491,12 @@
 }
 
 
+void Assembler::vmov(const SwVfpRegister dst, float imm) {
+  mov(ip, Operand(bit_cast<int32_t>(imm)));
+  vmov(dst, ip);
+}
+
+
 static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
   uint64_t i;
   memcpy(&i, &d, 8);
@@ -2492,7 +2571,7 @@
     int vd, d;
     dst.split_code(&vd, &d);
     emit(al | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | enc);
-  } else if (FLAG_enable_vldr_imm && is_constant_pool_available()) {
+  } else if (FLAG_enable_vldr_imm && is_ool_constant_pool_available()) {
     // TODO(jfb) Temporarily turned off until we have constant blinding or
     //           some equivalent mitigation: an attacker can otherwise control
     //           generated data which also happens to be executable, a Very Bad
@@ -2526,27 +2605,20 @@
     uint32_t lo, hi;
     DoubleAsTwoUInt32(imm, &lo, &hi);
 
-    if (scratch.is(no_reg)) {
-      if (dst.code() < 16) {
-        const LowDwVfpRegister loc = LowDwVfpRegister::from_code(dst.code());
-        // Move the low part of the double into the lower of the corresponsing S
-        // registers of D register dst.
-        mov(ip, Operand(lo));
-        vmov(loc.low(), ip);
-
-        // Move the high part of the double into the higher of the
-        // corresponsing S registers of D register dst.
-        mov(ip, Operand(hi));
-        vmov(loc.high(), ip);
+    if (lo == hi) {
+      // Move the low and high parts of the double to a D register in one
+      // instruction.
+      mov(ip, Operand(lo));
+      vmov(dst, ip, ip);
+    } else if (scratch.is(no_reg)) {
+      mov(ip, Operand(lo));
+      vmov(dst, VmovIndexLo, ip);
+      if ((lo & 0xffff) == (hi & 0xffff)) {
+        movt(ip, hi >> 16);
       } else {
-        // D16-D31 does not have S registers, so move the low and high parts
-        // directly to the D register using vmov.32.
-        // Note: This may be slower, so we only do this when we have to.
-        mov(ip, Operand(lo));
-        vmov(dst, VmovIndexLo, ip);
         mov(ip, Operand(hi));
-        vmov(dst, VmovIndexHi, ip);
       }
+      vmov(dst, VmovIndexHi, ip);
     } else {
       // Move the low and high parts of the double to a D register in one
       // instruction.
@@ -3075,6 +3147,76 @@
 }
 
 
+void Assembler::vrinta(const DwVfpRegister dst, const DwVfpRegister src) {
+  // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
+  // 10(19-18) | RM=00(17-16) |  Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
+  // M(5) | 0(4) | Vm(3-0)
+  DCHECK(CpuFeatures::IsSupported(ARMv8));
+  int vd, d;
+  dst.split_code(&vd, &d);
+  int vm, m;
+  src.split_code(&vm, &m);
+  emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 |
+       0x5 * B9 | B8 | B6 | m * B5 | vm);
+}
+
+
+void Assembler::vrintn(const DwVfpRegister dst, const DwVfpRegister src) {
+  // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
+  // 10(19-18) | RM=01(17-16) |  Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
+  // M(5) | 0(4) | Vm(3-0)
+  DCHECK(CpuFeatures::IsSupported(ARMv8));
+  int vd, d;
+  dst.split_code(&vd, &d);
+  int vm, m;
+  src.split_code(&vm, &m);
+  emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 |
+       vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
+}
+
+
+void Assembler::vrintp(const DwVfpRegister dst, const DwVfpRegister src) {
+  // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
+  // 10(19-18) | RM=10(17-16) |  Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
+  // M(5) | 0(4) | Vm(3-0)
+  DCHECK(CpuFeatures::IsSupported(ARMv8));
+  int vd, d;
+  dst.split_code(&vd, &d);
+  int vm, m;
+  src.split_code(&vm, &m);
+  emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 |
+       vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
+}
+
+
+void Assembler::vrintm(const DwVfpRegister dst, const DwVfpRegister src) {
+  // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
+  // 10(19-18) | RM=11(17-16) |  Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
+  // M(5) | 0(4) | Vm(3-0)
+  DCHECK(CpuFeatures::IsSupported(ARMv8));
+  int vd, d;
+  dst.split_code(&vd, &d);
+  int vm, m;
+  src.split_code(&vm, &m);
+  emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 |
+       vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
+}
+
+
+void Assembler::vrintz(const DwVfpRegister dst, const DwVfpRegister src,
+                       const Condition cond) {
+  // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) |
+  // Vd(15-12) | 101(11-9) | sz=1(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
+  DCHECK(CpuFeatures::IsSupported(ARMv8));
+  int vd, d;
+  dst.split_code(&vd, &d);
+  int vm, m;
+  src.split_code(&vm, &m);
+  emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x3 * B17 | vd * B12 |
+       0x5 * B9 | B8 | B7 | B6 | m * B5 | vm);
+}
+
+
 // Support for NEON.
 
 void Assembler::vld1(NeonSize size,
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index 108d5cb..4a719e6 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -218,6 +218,11 @@
   inline static int NumReservedRegisters();
   inline static int NumAllocatableRegisters();
 
+  // TODO(turbofan): This is a temporary work-around required because our
+  // register allocator does not yet support the aliasing of single/double
+  // registers on ARM.
+  inline static int NumAllocatableAliasedRegisters();
+
   inline static int ToAllocationIndex(DwVfpRegister reg);
   static const char* AllocationIndexToString(int index);
   inline static DwVfpRegister FromAllocationIndex(int index);
@@ -970,6 +975,11 @@
   void mul(Register dst, Register src1, Register src2,
            SBit s = LeaveCC, Condition cond = al);
 
+  void smmla(Register dst, Register src1, Register src2, Register srcA,
+             Condition cond = al);
+
+  void smmul(Register dst, Register src1, Register src2, Condition cond = al);
+
   void smlal(Register dstL, Register dstH, Register src1, Register src2,
              SBit s = LeaveCC, Condition cond = al);
 
@@ -1024,12 +1034,20 @@
   void pkhtb(Register dst, Register src1, const Operand& src2,
              Condition cond = al);
 
-  void uxtb(Register dst, const Operand& src, Condition cond = al);
-
-  void uxtab(Register dst, Register src1, const Operand& src2,
+  void sxtb(Register dst, Register src, int rotate = 0, Condition cond = al);
+  void sxtab(Register dst, Register src1, Register src2, int rotate = 0,
+             Condition cond = al);
+  void sxth(Register dst, Register src, int rotate = 0, Condition cond = al);
+  void sxtah(Register dst, Register src1, Register src2, int rotate = 0,
              Condition cond = al);
 
-  void uxtb16(Register dst, const Operand& src, Condition cond = al);
+  void uxtb(Register dst, Register src, int rotate = 0, Condition cond = al);
+  void uxtab(Register dst, Register src1, Register src2, int rotate = 0,
+             Condition cond = al);
+  void uxtb16(Register dst, Register src, int rotate = 0, Condition cond = al);
+  void uxth(Register dst, Register src, int rotate = 0, Condition cond = al);
+  void uxtah(Register dst, Register src1, Register src2, int rotate = 0,
+             Condition cond = al);
 
   // Status register access instructions
 
@@ -1162,6 +1180,7 @@
             SwVfpRegister last,
             Condition cond = al);
 
+  void vmov(const SwVfpRegister dst, float imm);
   void vmov(const DwVfpRegister dst,
             double imm,
             const Register scratch = no_reg);
@@ -1269,6 +1288,14 @@
              const DwVfpRegister src,
              const Condition cond = al);
 
+  // ARMv8 rounding instructions.
+  void vrinta(const DwVfpRegister dst, const DwVfpRegister src);
+  void vrintn(const DwVfpRegister dst, const DwVfpRegister src);
+  void vrintm(const DwVfpRegister dst, const DwVfpRegister src);
+  void vrintp(const DwVfpRegister dst, const DwVfpRegister src);
+  void vrintz(const DwVfpRegister dst, const DwVfpRegister src,
+              const Condition cond = al);
+
   // Support for NEON.
   // All these APIs support D0 to D31 and Q0 to Q15.
 
@@ -1483,8 +1510,6 @@
   // Generate the constant pool for the generated code.
   void PopulateConstantPool(ConstantPoolArray* constant_pool);
 
-  bool is_constant_pool_available() const { return constant_pool_available_; }
-
   bool use_extended_constant_pool() const {
     return constant_pool_builder_.current_section() ==
            ConstantPoolArray::EXTENDED_SECTION;
@@ -1544,10 +1569,6 @@
            (pc_offset() < no_const_pool_before_);
   }
 
-  void set_constant_pool_available(bool available) {
-    constant_pool_available_ = available;
-  }
-
  private:
   int next_buffer_check_;  // pc offset of next buffer check
 
@@ -1610,10 +1631,6 @@
   // The bound position, before this we cannot do instruction elimination.
   int last_bound_pos_;
 
-  // Indicates whether the constant pool can be accessed, which is only possible
-  // if the pp register points to the current code object's constant pool.
-  bool constant_pool_available_;
-
   // Code emission
   inline void CheckBuffer();
   void GrowBuffer();
@@ -1649,9 +1666,6 @@
   friend class RelocInfo;
   friend class CodePatcher;
   friend class BlockConstPoolScope;
-  friend class FrameAndConstantPoolScope;
-  friend class ConstantPoolUnavailableScope;
-
   PositionsRecorder positions_recorder_;
   friend class PositionsRecorder;
   friend class EnsureSpace;
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index 9d1a72a..8ce57d5 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -10,7 +10,7 @@
 #include "src/debug.h"
 #include "src/deoptimizer.h"
 #include "src/full-codegen.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -372,13 +372,13 @@
         MemOperand bit_field3 = FieldMemOperand(r2, Map::kBitField3Offset);
         // Check if slack tracking is enabled.
         __ ldr(r4, bit_field3);
-        __ DecodeField<Map::ConstructionCount>(r3, r4);
-        __ cmp(r3, Operand(JSFunction::kNoSlackTracking));
-        __ b(eq, &allocate);
+        __ DecodeField<Map::Counter>(r3, r4);
+        __ cmp(r3, Operand(Map::kSlackTrackingCounterEnd));
+        __ b(lt, &allocate);
         // Decrease generous allocation count.
-        __ sub(r4, r4, Operand(1 << Map::ConstructionCount::kShift));
+        __ sub(r4, r4, Operand(1 << Map::Counter::kShift));
         __ str(r4, bit_field3);
-        __ cmp(r3, Operand(JSFunction::kFinishSlackTracking));
+        __ cmp(r3, Operand(Map::kSlackTrackingCounterEnd));
         __ b(ne, &allocate);
 
         __ push(r1);
@@ -431,9 +431,9 @@
 
         // Check if slack tracking is enabled.
         __ ldr(ip, FieldMemOperand(r2, Map::kBitField3Offset));
-        __ DecodeField<Map::ConstructionCount>(ip);
-        __ cmp(ip, Operand(JSFunction::kNoSlackTracking));
-        __ b(eq, &no_inobject_slack_tracking);
+        __ DecodeField<Map::Counter>(ip);
+        __ cmp(ip, Operand(Map::kSlackTrackingCounterEnd));
+        __ b(lt, &no_inobject_slack_tracking);
 
         // Allocate object with a slack.
         __ ldr(r0, FieldMemOperand(r2, Map::kInstanceSizesOffset));
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 25270d1..ef286bb 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -15,7 +15,7 @@
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -234,61 +234,6 @@
 }
 
 
-void WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(
-    Isolate* isolate) {
-  WriteInt32ToHeapNumberStub stub1(isolate, r1, r0, r2);
-  WriteInt32ToHeapNumberStub stub2(isolate, r2, r0, r3);
-  stub1.GetCode();
-  stub2.GetCode();
-}
-
-
-// See comment for class.
-void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) {
-  Label max_negative_int;
-  // the_int_ has the answer which is a signed int32 but not a Smi.
-  // We test for the special value that has a different exponent.  This test
-  // has the neat side effect of setting the flags according to the sign.
-  STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
-  __ cmp(the_int(), Operand(0x80000000u));
-  __ b(eq, &max_negative_int);
-  // Set up the correct exponent in scratch_.  All non-Smi int32s have the same.
-  // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased).
-  uint32_t non_smi_exponent =
-      (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
-  __ mov(scratch(), Operand(non_smi_exponent));
-  // Set the sign bit in scratch_ if the value was negative.
-  __ orr(scratch(), scratch(), Operand(HeapNumber::kSignMask), LeaveCC, cs);
-  // Subtract from 0 if the value was negative.
-  __ rsb(the_int(), the_int(), Operand::Zero(), LeaveCC, cs);
-  // We should be masking the implict first digit of the mantissa away here,
-  // but it just ends up combining harmlessly with the last digit of the
-  // exponent that happens to be 1.  The sign bit is 0 so we shift 10 to get
-  // the most significant 1 to hit the last bit of the 12 bit sign and exponent.
-  DCHECK(((1 << HeapNumber::kExponentShift) & non_smi_exponent) != 0);
-  const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
-  __ orr(scratch(), scratch(), Operand(the_int(), LSR, shift_distance));
-  __ str(scratch(),
-         FieldMemOperand(the_heap_number(), HeapNumber::kExponentOffset));
-  __ mov(scratch(), Operand(the_int(), LSL, 32 - shift_distance));
-  __ str(scratch(),
-         FieldMemOperand(the_heap_number(), HeapNumber::kMantissaOffset));
-  __ Ret();
-
-  __ bind(&max_negative_int);
-  // The max negative int32 is stored as a positive number in the mantissa of
-  // a double because it uses a sign bit instead of using two's complement.
-  // The actual mantissa bits stored are all 0 because the implicit most
-  // significant 1 bit is not stored.
-  non_smi_exponent += 1 << HeapNumber::kExponentShift;
-  __ mov(ip, Operand(HeapNumber::kSignMask | non_smi_exponent));
-  __ str(ip, FieldMemOperand(the_heap_number(), HeapNumber::kExponentOffset));
-  __ mov(ip, Operand::Zero());
-  __ str(ip, FieldMemOperand(the_heap_number(), HeapNumber::kMantissaOffset));
-  __ Ret();
-}
-
-
 // Handle the case where the lhs and rhs are the same object.
 // Equality is almost reflexive (everything but NaN), so this is a test
 // for "identity and not NaN".
@@ -967,7 +912,6 @@
 
 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
   CEntryStub::GenerateAheadOfTime(isolate);
-  WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
   StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
   StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
@@ -1441,7 +1385,7 @@
   __ b(ne, &slow);
 
   // Null is not instance of anything.
-  __ cmp(scratch, Operand(isolate()->factory()->null_value()));
+  __ cmp(object, Operand(isolate()->factory()->null_value()));
   __ b(ne, &object_not_null);
   if (ReturnTrueFalseObject()) {
     __ Move(r0, factory->false_value());
@@ -1494,15 +1438,54 @@
 void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
   Label miss;
   Register receiver = LoadDescriptor::ReceiverRegister();
+  // Ensure that the vector and slot registers won't be clobbered before
+  // calling the miss handler.
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(r4, r5, VectorLoadICDescriptor::VectorRegister(),
+                     VectorLoadICDescriptor::SlotRegister()));
 
-  NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, r3,
-                                                          r4, &miss);
+  NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, r4,
+                                                          r5, &miss);
   __ bind(&miss);
   PropertyAccessCompiler::TailCallBuiltin(
       masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
 }
 
 
+void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
+  // Return address is in lr.
+  Label miss;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register index = LoadDescriptor::NameRegister();
+  Register scratch = r5;
+  Register result = r0;
+  DCHECK(!scratch.is(receiver) && !scratch.is(index));
+  DCHECK(!FLAG_vector_ics ||
+         (!scratch.is(VectorLoadICDescriptor::VectorRegister()) &&
+          result.is(VectorLoadICDescriptor::SlotRegister())));
+
+  // StringCharAtGenerator doesn't use the result register until it's passed
+  // the different miss possibilities. If it did, we would have a conflict
+  // when FLAG_vector_ics is true.
+  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
+                                          &miss,  // When not a string.
+                                          &miss,  // When not a number.
+                                          &miss,  // When index out of range.
+                                          STRING_INDEX_IS_ARRAY_INDEX,
+                                          RECEIVER_IS_STRING);
+  char_at_generator.GenerateFast(masm);
+  __ Ret();
+
+  StubRuntimeCallHelper call_helper;
+  char_at_generator.GenerateSlow(masm, call_helper);
+
+  __ bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
   // The displacement is the offset of the last parameter (if any)
   // relative to the frame pointer.
@@ -2376,13 +2359,13 @@
 
   // A monomorphic miss (i.e, here the cache is not uninitialized) goes
   // megamorphic.
-  __ CompareRoot(r4, Heap::kUninitializedSymbolRootIndex);
+  __ CompareRoot(r4, Heap::kuninitialized_symbolRootIndex);
   __ b(eq, &initialize);
   // MegamorphicSentinel is an immortal immovable object (undefined) so no
   // write-barrier is needed.
   __ bind(&megamorphic);
   __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
-  __ LoadRoot(ip, Heap::kMegamorphicSymbolRootIndex);
+  __ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex);
   __ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
   __ jmp(&done);
 
@@ -2658,6 +2641,10 @@
 void CallICStub::Generate(MacroAssembler* masm) {
   // r1 - function
   // r3 - slot id (Smi)
+  const int with_types_offset =
+      FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
+  const int generic_offset =
+      FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
   Label slow, non_function, wrap, cont;
   Label have_js_function;
@@ -2696,26 +2683,70 @@
   }
 
   __ bind(&extra_checks_or_miss);
-  Label miss;
+  Label uninitialized, miss;
 
-  __ CompareRoot(r4, Heap::kMegamorphicSymbolRootIndex);
+  __ CompareRoot(r4, Heap::kmegamorphic_symbolRootIndex);
   __ b(eq, &slow_start);
-  __ CompareRoot(r4, Heap::kUninitializedSymbolRootIndex);
-  __ b(eq, &miss);
 
-  if (!FLAG_trace_ic) {
-    // We are going megamorphic. If the feedback is a JSFunction, it is fine
-    // to handle it here. More complex cases are dealt with in the runtime.
-    __ AssertNotSmi(r4);
-    __ CompareObjectType(r4, r5, r5, JS_FUNCTION_TYPE);
-    __ b(ne, &miss);
-    __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
-    __ LoadRoot(ip, Heap::kMegamorphicSymbolRootIndex);
-    __ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
-    __ jmp(&slow_start);
+  // The following cases attempt to handle MISS cases without going to the
+  // runtime.
+  if (FLAG_trace_ic) {
+    __ jmp(&miss);
   }
 
-  // We are here because tracing is on or we are going monomorphic.
+  __ CompareRoot(r4, Heap::kuninitialized_symbolRootIndex);
+  __ b(eq, &uninitialized);
+
+  // We are going megamorphic. If the feedback is a JSFunction, it is fine
+  // to handle it here. More complex cases are dealt with in the runtime.
+  __ AssertNotSmi(r4);
+  __ CompareObjectType(r4, r5, r5, JS_FUNCTION_TYPE);
+  __ b(ne, &miss);
+  __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
+  __ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex);
+  __ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
+  // We have to update statistics for runtime profiling.
+  __ ldr(r4, FieldMemOperand(r2, with_types_offset));
+  __ sub(r4, r4, Operand(Smi::FromInt(1)));
+  __ str(r4, FieldMemOperand(r2, with_types_offset));
+  __ ldr(r4, FieldMemOperand(r2, generic_offset));
+  __ add(r4, r4, Operand(Smi::FromInt(1)));
+  __ str(r4, FieldMemOperand(r2, generic_offset));
+  __ jmp(&slow_start);
+
+  __ bind(&uninitialized);
+
+  // We are going monomorphic, provided we actually have a JSFunction.
+  __ JumpIfSmi(r1, &miss);
+
+  // Goto miss case if we do not have a function.
+  __ CompareObjectType(r1, r4, r4, JS_FUNCTION_TYPE);
+  __ b(ne, &miss);
+
+  // Make sure the function is not the Array() function, which requires special
+  // behavior on MISS.
+  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, r4);
+  __ cmp(r1, r4);
+  __ b(eq, &miss);
+
+  // Update stats.
+  __ ldr(r4, FieldMemOperand(r2, with_types_offset));
+  __ add(r4, r4, Operand(Smi::FromInt(1)));
+  __ str(r4, FieldMemOperand(r2, with_types_offset));
+
+  // Store the function.
+  __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
+  __ add(r4, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ str(r1, MemOperand(r4, 0));
+
+  // Update the write barrier.
+  __ mov(r5, r1);
+  __ RecordWrite(r2, r4, r5, kLRHasNotBeenSaved, kDontSaveFPRegs,
+                 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+  __ jmp(&have_js_function);
+
+  // We are here because tracing is on or we encountered a MISS case we can't
+  // handle here.
   __ bind(&miss);
   GenerateMiss(masm);
 
@@ -2759,14 +2790,16 @@
 // StringCharCodeAtGenerator
 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
   // If the receiver is a smi trigger the non-string case.
-  __ JumpIfSmi(object_, receiver_not_string_);
+  if (check_mode_ == RECEIVER_IS_UNKNOWN) {
+    __ JumpIfSmi(object_, receiver_not_string_);
 
-  // Fetch the instance type of the receiver into result register.
-  __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
-  __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
-  // If the receiver is not a string trigger the non-string case.
-  __ tst(result_, Operand(kIsNotStringMask));
-  __ b(ne, receiver_not_string_);
+    // Fetch the instance type of the receiver into result register.
+    __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
+    __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
+    // If the receiver is not a string trigger the non-string case.
+    __ tst(result_, Operand(kIsNotStringMask));
+    __ b(ne, receiver_not_string_);
+  }
 
   // If the index is non-smi trigger the non-smi case.
   __ JumpIfNotSmi(index_, &index_not_smi_);
@@ -3137,8 +3170,8 @@
   // r2: length
   // r3: from index (untagged)
   __ SmiTag(r3, r3);
-  StringCharAtGenerator generator(
-      r0, r3, r2, r0, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
+  StringCharAtGenerator generator(r0, r3, r2, r0, &runtime, &runtime, &runtime,
+                                  STRING_INDEX_IS_NUMBER, RECEIVER_IS_STRING);
   generator.GenerateFast(masm);
   __ Drop(3);
   __ Ret();
@@ -3146,6 +3179,49 @@
 }
 
 
+void ToNumberStub::Generate(MacroAssembler* masm) {
+  // The ToNumber stub takes one argument in r0.
+  Label not_smi;
+  __ JumpIfNotSmi(r0, &not_smi);
+  __ Ret();
+  __ bind(&not_smi);
+
+  Label not_heap_number;
+  __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+  __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
+  // r0: object
+  // r1: instance type.
+  __ cmp(r1, Operand(HEAP_NUMBER_TYPE));
+  __ b(ne, &not_heap_number);
+  __ Ret();
+  __ bind(&not_heap_number);
+
+  Label not_string, slow_string;
+  __ cmp(r1, Operand(FIRST_NONSTRING_TYPE));
+  __ b(hs, &not_string);
+  // Check if string has a cached array index.
+  __ ldr(r2, FieldMemOperand(r0, String::kHashFieldOffset));
+  __ tst(r2, Operand(String::kContainsCachedArrayIndexMask));
+  __ b(ne, &slow_string);
+  __ IndexFromHash(r2, r0);
+  __ Ret();
+  __ bind(&slow_string);
+  __ push(r0);  // Push argument.
+  __ TailCallRuntime(Runtime::kStringToNumber, 1, 1);
+  __ bind(&not_string);
+
+  Label not_oddball;
+  __ cmp(r1, Operand(ODDBALL_TYPE));
+  __ b(ne, &not_oddball);
+  __ ldr(r0, FieldMemOperand(r0, Oddball::kToNumberOffset));
+  __ Ret();
+  __ bind(&not_oddball);
+
+  __ push(r0);  // Push argument.
+  __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
+}
+
+
 void StringHelper::GenerateFlatOneByteStringEquals(
     MacroAssembler* masm, Register left, Register right, Register scratch1,
     Register scratch2, Register scratch3) {
diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h
index 727bb1b..e1fab29 100644
--- a/src/arm/code-stubs-arm.h
+++ b/src/arm/code-stubs-arm.h
@@ -46,44 +46,6 @@
 };
 
 
-// This stub can convert a signed int32 to a heap number (double).  It does
-// not work for int32s that are in Smi range!  No GC occurs during this stub
-// so you don't have to set up the frame.
-class WriteInt32ToHeapNumberStub : public PlatformCodeStub {
- public:
-  WriteInt32ToHeapNumberStub(Isolate* isolate, Register the_int,
-                             Register the_heap_number, Register scratch)
-      : PlatformCodeStub(isolate) {
-    minor_key_ = IntRegisterBits::encode(the_int.code()) |
-                 HeapNumberRegisterBits::encode(the_heap_number.code()) |
-                 ScratchRegisterBits::encode(scratch.code());
-  }
-
-  static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
-
- private:
-  Register the_int() const {
-    return Register::from_code(IntRegisterBits::decode(minor_key_));
-  }
-
-  Register the_heap_number() const {
-    return Register::from_code(HeapNumberRegisterBits::decode(minor_key_));
-  }
-
-  Register scratch() const {
-    return Register::from_code(ScratchRegisterBits::decode(minor_key_));
-  }
-
-  // Minor key encoding in 16 bits.
-  class IntRegisterBits: public BitField<int, 0, 4> {};
-  class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
-  class ScratchRegisterBits: public BitField<int, 8, 4> {};
-
-  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
-  DEFINE_PLATFORM_CODE_STUB(WriteInt32ToHeapNumber, PlatformCodeStub);
-};
-
-
 class RecordWriteStub: public PlatformCodeStub {
  public:
   RecordWriteStub(Isolate* isolate,
@@ -112,7 +74,7 @@
     INCREMENTAL_COMPACTION
   };
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
   static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
     masm->instr_at_put(pos, (masm->instr_at(pos) & ~B27) | (B24 | B20));
@@ -235,9 +197,9 @@
     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
   };
 
-  virtual inline Major MajorKey() const FINAL OVERRIDE { return RecordWrite; }
+  inline Major MajorKey() const FINAL { return RecordWrite; }
 
-  virtual void Generate(MacroAssembler* masm) OVERRIDE;
+  void Generate(MacroAssembler* masm) OVERRIDE;
   void GenerateIncremental(MacroAssembler* masm, Mode mode);
   void CheckNeedsToInformIncrementalMarker(
       MacroAssembler* masm,
@@ -245,7 +207,7 @@
       Mode mode);
   void InformIncrementalMarker(MacroAssembler* masm);
 
-  void Activate(Code* code) {
+  void Activate(Code* code) OVERRIDE {
     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
   }
 
@@ -293,7 +255,7 @@
   void GenerateCall(MacroAssembler* masm, Register target);
 
  private:
-  bool NeedsImmovableCode() { return true; }
+  bool NeedsImmovableCode() OVERRIDE { return true; }
 
   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
   DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
@@ -325,7 +287,7 @@
                                      Register r0,
                                      Register r1);
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
  private:
   static const int kInlinedProbes = 4;
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index d050399..fd1b0ef 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -288,8 +288,8 @@
 
     __ bind(&loop);
     __ ldr(temp1, MemOperand(src, 4, PostIndex));
-    __ uxtb16(temp3, Operand(temp1, ROR, 0));
-    __ uxtb16(temp4, Operand(temp1, ROR, 8));
+    __ uxtb16(temp3, temp1);
+    __ uxtb16(temp4, temp1, 8);
     __ pkhbt(temp1, temp3, Operand(temp4, LSL, 16));
     __ str(temp1, MemOperand(dest));
     __ pkhtb(temp1, temp4, Operand(temp3, ASR, 16));
@@ -301,9 +301,9 @@
     __ mov(chars, Operand(chars, LSL, 31), SetCC);  // bit0 => ne, bit1 => cs
     __ b(&not_two, cc);
     __ ldrh(temp1, MemOperand(src, 2, PostIndex));
-    __ uxtb(temp3, Operand(temp1, ROR, 8));
+    __ uxtb(temp3, temp1, 8);
     __ mov(temp3, Operand(temp3, LSL, 16));
-    __ uxtab(temp3, temp3, Operand(temp1, ROR, 0));
+    __ uxtab(temp3, temp3, temp1);
     __ str(temp3, MemOperand(dest, 4, PostIndex));
     __ bind(&not_two);
     __ ldrb(temp1, MemOperand(src), ne);
@@ -604,8 +604,22 @@
   __ add(src_elements, elements,
          Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag + 4));
   __ add(dst_elements, array, Operand(FixedArray::kHeaderSize));
-  __ add(array, array, Operand(kHeapObjectTag));
   __ add(dst_end, dst_elements, Operand(length, LSL, 1));
+
+  // Allocating heap numbers in the loop below can fail and cause a jump to
+  // gc_required. We can't leave a partly initialized FixedArray behind,
+  // so pessimistically fill it with holes now.
+  Label initialization_loop, initialization_loop_entry;
+  __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
+  __ b(&initialization_loop_entry);
+  __ bind(&initialization_loop);
+  __ str(scratch, MemOperand(dst_elements, kPointerSize, PostIndex));
+  __ bind(&initialization_loop_entry);
+  __ cmp(dst_elements, dst_end);
+  __ b(lt, &initialization_loop);
+
+  __ add(dst_elements, array, Operand(FixedArray::kHeaderSize));
+  __ add(array, array, Operand(kHeapObjectTag));
   __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
   // Using offsetted addresses in src_elements to fully take advantage of
   // post-indexing.
diff --git a/src/arm/constants-arm.h b/src/arm/constants-arm.h
index 375ef89..0037ce1 100644
--- a/src/arm/constants-arm.h
+++ b/src/arm/constants-arm.h
@@ -161,26 +161,26 @@
 
 // Instruction encoding bits and masks.
 enum {
-  H   = 1 << 5,   // Halfword (or byte).
-  S6  = 1 << 6,   // Signed (or unsigned).
-  L   = 1 << 20,  // Load (or store).
-  S   = 1 << 20,  // Set condition code (or leave unchanged).
-  W   = 1 << 21,  // Writeback base register (or leave unchanged).
-  A   = 1 << 21,  // Accumulate in multiply instruction (or not).
-  B   = 1 << 22,  // Unsigned byte (or word).
-  N   = 1 << 22,  // Long (or short).
-  U   = 1 << 23,  // Positive (or negative) offset/index.
-  P   = 1 << 24,  // Offset/pre-indexed addressing (or post-indexed addressing).
-  I   = 1 << 25,  // Immediate shifter operand (or not).
-
-  B4  = 1 << 4,
-  B5  = 1 << 5,
-  B6  = 1 << 6,
-  B7  = 1 << 7,
-  B8  = 1 << 8,
-  B9  = 1 << 9,
+  H = 1 << 5,   // Halfword (or byte).
+  S6 = 1 << 6,  // Signed (or unsigned).
+  L = 1 << 20,  // Load (or store).
+  S = 1 << 20,  // Set condition code (or leave unchanged).
+  W = 1 << 21,  // Writeback base register (or leave unchanged).
+  A = 1 << 21,  // Accumulate in multiply instruction (or not).
+  B = 1 << 22,  // Unsigned byte (or word).
+  N = 1 << 22,  // Long (or short).
+  U = 1 << 23,  // Positive (or negative) offset/index.
+  P = 1 << 24,  // Offset/pre-indexed addressing (or post-indexed addressing).
+  I = 1 << 25,  // Immediate shifter operand (or not).
+  B4 = 1 << 4,
+  B5 = 1 << 5,
+  B6 = 1 << 6,
+  B7 = 1 << 7,
+  B8 = 1 << 8,
+  B9 = 1 << 9,
   B12 = 1 << 12,
   B16 = 1 << 16,
+  B17 = 1 << 17,
   B18 = 1 << 18,
   B19 = 1 << 19,
   B20 = 1 << 20,
@@ -194,16 +194,16 @@
   B28 = 1 << 28,
 
   // Instruction bit masks.
-  kCondMask   = 15 << 28,
-  kALUMask    = 0x6f << 21,
-  kRdMask     = 15 << 12,  // In str instruction.
+  kCondMask = 15 << 28,
+  kALUMask = 0x6f << 21,
+  kRdMask = 15 << 12,  // In str instruction.
   kCoprocessorMask = 15 << 8,
   kOpCodeMask = 15 << 21,  // In data-processing instructions.
-  kImm24Mask  = (1 << 24) - 1,
-  kImm16Mask  = (1 << 16) - 1,
-  kImm8Mask  = (1 << 8) - 1,
-  kOff12Mask  = (1 << 12) - 1,
-  kOff8Mask  = (1 << 8) - 1
+  kImm24Mask = (1 << 24) - 1,
+  kImm16Mask = (1 << 16) - 1,
+  kImm8Mask = (1 << 8) - 1,
+  kOff12Mask = (1 << 12) - 1,
+  kOff8Mask = (1 << 8) - 1
 };
 
 
@@ -332,9 +332,9 @@
 // standard SoftwareInterrupCode. Bit 23 is reserved for the stop feature.
 enum SoftwareInterruptCodes {
   // transition to C code
-  kCallRtRedirected= 0x10,
+  kCallRtRedirected = 0x10,
   // break point
-  kBreakpoint= 0x20,
+  kBreakpoint = 0x20,
   // stop
   kStopCode = 1 << 23
 };
diff --git a/src/arm/cpu-arm.cc b/src/arm/cpu-arm.cc
index 9c7104e..4a34070 100644
--- a/src/arm/cpu-arm.cc
+++ b/src/arm/cpu-arm.cc
@@ -27,6 +27,8 @@
 void CpuFeatures::FlushICache(void* start, size_t size) {
   if (size == 0) return;
 
+  if (CpuFeatures::IsSupported(COHERENT_CACHE)) return;
+
 #if defined(USE_SIMULATOR)
   // Not generating ARM instructions for C-code. This means that we are
   // building an ARM emulator based target.  We should notify the simulator
diff --git a/src/arm/debug-arm.cc b/src/arm/debug-arm.cc
index 6d7d6b8..c910057 100644
--- a/src/arm/debug-arm.cc
+++ b/src/arm/debug-arm.cc
@@ -178,7 +178,11 @@
   // Calling convention for IC load (from ic-arm.cc).
   Register receiver = LoadDescriptor::ReceiverRegister();
   Register name = LoadDescriptor::NameRegister();
-  Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit(), 0);
+  RegList regs = receiver.bit() | name.bit();
+  if (FLAG_vector_ics) {
+    regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
+  }
+  Generate_DebugBreakCallHelper(masm, regs, 0);
 }
 
 
diff --git a/src/arm/deoptimizer-arm.cc b/src/arm/deoptimizer-arm.cc
index 0455a3b..b3a6173 100644
--- a/src/arm/deoptimizer-arm.cc
+++ b/src/arm/deoptimizer-arm.cc
@@ -21,6 +21,12 @@
 }
 
 
+void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
+  // Empty because there is no need for relocation information for the code
+  // patching in Deoptimizer::PatchCodeForDeoptimization below.
+}
+
+
 void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
   Address code_start_address = code->instruction_start();
   // Invalidate the relocation information, as it will become invalid by the
diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc
index 85977b1..4e631b0 100644
--- a/src/arm/disasm-arm.cc
+++ b/src/arm/disasm-arm.cc
@@ -148,7 +148,7 @@
 
 // These condition names are defined in a way to match the native disassembler
 // formatting. See for example the command "objdump -d <binary file>".
-static const char* cond_names[kNumberOfConditions] = {
+static const char* const cond_names[kNumberOfConditions] = {
   "eq", "ne", "cs" , "cc" , "mi" , "pl" , "vs" , "vc" ,
   "hi", "ls", "ge", "lt", "gt", "le", "", "invalid",
 };
@@ -1027,7 +1027,75 @@
               UNREACHABLE();
               break;
             case 1:
-              UNREACHABLE();
+              if (instr->Bits(9, 6) == 1) {
+                if (instr->Bit(20) == 0) {
+                  if (instr->Bits(19, 16) == 0xF) {
+                    switch (instr->Bits(11, 10)) {
+                      case 0:
+                        Format(instr, "sxtb'cond 'rd, 'rm");
+                        break;
+                      case 1:
+                        Format(instr, "sxtb'cond 'rd, 'rm, ror #8");
+                        break;
+                      case 2:
+                        Format(instr, "sxtb'cond 'rd, 'rm, ror #16");
+                        break;
+                      case 3:
+                        Format(instr, "sxtb'cond 'rd, 'rm, ror #24");
+                        break;
+                    }
+                  } else {
+                    switch (instr->Bits(11, 10)) {
+                      case 0:
+                        Format(instr, "sxtab'cond 'rd, 'rn, 'rm");
+                        break;
+                      case 1:
+                        Format(instr, "sxtab'cond 'rd, 'rn, 'rm, ror #8");
+                        break;
+                      case 2:
+                        Format(instr, "sxtab'cond 'rd, 'rn, 'rm, ror #16");
+                        break;
+                      case 3:
+                        Format(instr, "sxtab'cond 'rd, 'rn, 'rm, ror #24");
+                        break;
+                    }
+                  }
+                } else {
+                  if (instr->Bits(19, 16) == 0xF) {
+                    switch (instr->Bits(11, 10)) {
+                      case 0:
+                        Format(instr, "sxth'cond 'rd, 'rm");
+                        break;
+                      case 1:
+                        Format(instr, "sxth'cond 'rd, 'rm, ror #8");
+                        break;
+                      case 2:
+                        Format(instr, "sxth'cond 'rd, 'rm, ror #16");
+                        break;
+                      case 3:
+                        Format(instr, "sxth'cond 'rd, 'rm, ror #24");
+                        break;
+                    }
+                  } else {
+                    switch (instr->Bits(11, 10)) {
+                      case 0:
+                        Format(instr, "sxtah'cond 'rd, 'rn, 'rm");
+                        break;
+                      case 1:
+                        Format(instr, "sxtah'cond 'rd, 'rn, 'rm, ror #8");
+                        break;
+                      case 2:
+                        Format(instr, "sxtah'cond 'rd, 'rn, 'rm, ror #16");
+                        break;
+                      case 3:
+                        Format(instr, "sxtah'cond 'rd, 'rn, 'rm, ror #24");
+                        break;
+                    }
+                  }
+                }
+              } else {
+                UNREACHABLE();
+              }
               break;
             case 2:
               if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
@@ -1054,36 +1122,70 @@
               }
               break;
             case 3:
-              if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
-                if (instr->Bits(19, 16) == 0xF) {
-                  switch (instr->Bits(11, 10)) {
-                    case 0:
-                      Format(instr, "uxtb'cond 'rd, 'rm");
-                      break;
-                    case 1:
-                      Format(instr, "uxtb'cond 'rd, 'rm, ror #8");
-                      break;
-                    case 2:
-                      Format(instr, "uxtb'cond 'rd, 'rm, ror #16");
-                      break;
-                    case 3:
-                      Format(instr, "uxtb'cond 'rd, 'rm, ror #24");
-                      break;
+              if ((instr->Bits(9, 6) == 1)) {
+                if ((instr->Bit(20) == 0)) {
+                  if (instr->Bits(19, 16) == 0xF) {
+                    switch (instr->Bits(11, 10)) {
+                      case 0:
+                        Format(instr, "uxtb'cond 'rd, 'rm");
+                        break;
+                      case 1:
+                        Format(instr, "uxtb'cond 'rd, 'rm, ror #8");
+                        break;
+                      case 2:
+                        Format(instr, "uxtb'cond 'rd, 'rm, ror #16");
+                        break;
+                      case 3:
+                        Format(instr, "uxtb'cond 'rd, 'rm, ror #24");
+                        break;
+                    }
+                  } else {
+                    switch (instr->Bits(11, 10)) {
+                      case 0:
+                        Format(instr, "uxtab'cond 'rd, 'rn, 'rm");
+                        break;
+                      case 1:
+                        Format(instr, "uxtab'cond 'rd, 'rn, 'rm, ror #8");
+                        break;
+                      case 2:
+                        Format(instr, "uxtab'cond 'rd, 'rn, 'rm, ror #16");
+                        break;
+                      case 3:
+                        Format(instr, "uxtab'cond 'rd, 'rn, 'rm, ror #24");
+                        break;
+                    }
                   }
                 } else {
-                  switch (instr->Bits(11, 10)) {
-                    case 0:
-                      Format(instr, "uxtab'cond 'rd, 'rn, 'rm");
-                      break;
-                    case 1:
-                      Format(instr, "uxtab'cond 'rd, 'rn, 'rm, ror #8");
-                      break;
-                    case 2:
-                      Format(instr, "uxtab'cond 'rd, 'rn, 'rm, ror #16");
-                      break;
-                    case 3:
-                      Format(instr, "uxtab'cond 'rd, 'rn, 'rm, ror #24");
-                      break;
+                  if (instr->Bits(19, 16) == 0xF) {
+                    switch (instr->Bits(11, 10)) {
+                      case 0:
+                        Format(instr, "uxth'cond 'rd, 'rm");
+                        break;
+                      case 1:
+                        Format(instr, "uxth'cond 'rd, 'rm, ror #8");
+                        break;
+                      case 2:
+                        Format(instr, "uxth'cond 'rd, 'rm, ror #16");
+                        break;
+                      case 3:
+                        Format(instr, "uxth'cond 'rd, 'rm, ror #24");
+                        break;
+                    }
+                  } else {
+                    switch (instr->Bits(11, 10)) {
+                      case 0:
+                        Format(instr, "uxtah'cond 'rd, 'rn, 'rm");
+                        break;
+                      case 1:
+                        Format(instr, "uxtah'cond 'rd, 'rn, 'rm, ror #8");
+                        break;
+                      case 2:
+                        Format(instr, "uxtah'cond 'rd, 'rn, 'rm, ror #16");
+                        break;
+                      case 3:
+                        Format(instr, "uxtah'cond 'rd, 'rn, 'rm, ror #24");
+                        break;
+                    }
                   }
                 }
               } else {
@@ -1096,6 +1198,17 @@
       break;
     }
     case db_x: {
+      if (instr->Bits(22, 20) == 0x5) {
+        if (instr->Bits(7, 4) == 0x1) {
+          if (instr->Bits(15, 12) == 0xF) {
+            Format(instr, "smmul'cond 'rn, 'rm, 'rs");
+          } else {
+            // SMMLA (in V8 notation matching ARM ISA format)
+            Format(instr, "smmla'cond 'rn, 'rm, 'rs, 'rd");
+          }
+          break;
+        }
+      }
       if (FLAG_enable_sudiv) {
         if (instr->Bits(5, 4) == 0x1) {
           if ((instr->Bit(22) == 0x0) && (instr->Bit(20) == 0x1)) {
@@ -1266,6 +1379,14 @@
         } else {
           Unknown(instr);  // Not used by V8.
         }
+      } else if (((instr->Opc2Value() == 0x6)) && instr->Opc3Value() == 0x3) {
+        bool dp_operation = (instr->SzValue() == 1);
+        // vrintz - round towards zero (truncate)
+        if (dp_operation) {
+          Format(instr, "vrintz'cond.f64.f64 'Dd, 'Dm");
+        } else {
+          Unknown(instr);  // Not used by V8.
+        }
       } else {
         Unknown(instr);  // Not used by V8.
       }
@@ -1616,6 +1737,50 @@
         Unknown(instr);
       }
       break;
+    case 0x1D:
+      if (instr->Opc1Value() == 0x7 && instr->Bits(19, 18) == 0x2 &&
+          instr->Bits(11, 9) == 0x5 && instr->Bits(7, 6) == 0x1 &&
+          instr->Bit(4) == 0x0) {
+        // VRINTA, VRINTN, VRINTP, VRINTM (floating-point)
+        bool dp_operation = (instr->SzValue() == 1);
+        int rounding_mode = instr->Bits(17, 16);
+        switch (rounding_mode) {
+          case 0x0:
+            if (dp_operation) {
+              Format(instr, "vrinta.f64.f64 'Dd, 'Dm");
+            } else {
+              Unknown(instr);
+            }
+            break;
+          case 0x1:
+            if (dp_operation) {
+              Format(instr, "vrintn.f64.f64 'Dd, 'Dm");
+            } else {
+              Unknown(instr);
+            }
+            break;
+          case 0x2:
+            if (dp_operation) {
+              Format(instr, "vrintp.f64.f64 'Dd, 'Dm");
+            } else {
+              Unknown(instr);
+            }
+            break;
+          case 0x3:
+            if (dp_operation) {
+              Format(instr, "vrintm.f64.f64 'Dd, 'Dm");
+            } else {
+              Unknown(instr);
+            }
+            break;
+          default:
+            UNREACHABLE();  // Case analysis is exhaustive.
+            break;
+        }
+      } else {
+        Unknown(instr);
+      }
+      break;
     default:
       Unknown(instr);
       break;
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index eb60c3f..3dc5420 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -195,10 +195,10 @@
     // Argument to NewContext is the function, which is still in r1.
     Comment cmnt(masm_, "[ Allocate context");
     bool need_write_barrier = true;
-    if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
+    if (FLAG_harmony_scoping && info->scope()->is_script_scope()) {
       __ push(r1);
       __ Push(info->scope()->GetScopeInfo());
-      __ CallRuntime(Runtime::kNewGlobalContext, 2);
+      __ CallRuntime(Runtime::kNewScriptContext, 2);
     } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
       FastNewContextStub stub(isolate(), heap_slots);
       __ CallStub(&stub);
@@ -937,7 +937,7 @@
   EmitDebugCheckDeclarationContext(variable);
 
   // Load instance object.
-  __ LoadContext(r1, scope_->ContextChainLength(scope_->GlobalScope()));
+  __ LoadContext(r1, scope_->ContextChainLength(scope_->ScriptScope()));
   __ ldr(r1, ContextOperand(r1, variable->interface()->Index()));
   __ ldr(r1, ContextOperand(r1, Context::EXTENSION_INDEX));
 
@@ -1102,7 +1102,7 @@
 
 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
   Comment cmnt(masm_, "[ ForInStatement");
-  int slot = stmt->ForInFeedbackSlot();
+  FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
   SetStatementPosition(stmt);
 
   Label loop, exit;
@@ -1111,6 +1111,7 @@
 
   // Get the object to enumerate over. If the object is null or undefined, skip
   // over the loop.  See ECMA-262 version 5, section 12.6.4.
+  SetExpressionPosition(stmt->enumerable());
   VisitForAccumulatorValue(stmt->enumerable());
   __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
   __ cmp(r0, ip);
@@ -1131,6 +1132,7 @@
   __ push(r0);
   __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
   __ bind(&done_convert);
+  PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
   __ push(r0);
 
   // Check for proxies.
@@ -1155,6 +1157,7 @@
   __ bind(&call_runtime);
   __ push(r0);  // Duplicate the enumerable object on the stack.
   __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
+  PrepareForBailoutForId(stmt->EnumId(), TOS_REG);
 
   // If we got a map from the runtime call, we can do a fast
   // modification check. Otherwise, we got a fixed array, and we have
@@ -1194,7 +1197,8 @@
 
   __ Move(r1, FeedbackVector());
   __ mov(r2, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate())));
-  __ str(r2, FieldMemOperand(r1, FixedArray::OffsetOfElementAt(slot)));
+  int vector_index = FeedbackVector()->GetIndex(slot);
+  __ str(r2, FieldMemOperand(r1, FixedArray::OffsetOfElementAt(vector_index)));
 
   __ mov(r1, Operand(Smi::FromInt(1)));  // Smi indicates slow check
   __ ldr(r2, MemOperand(sp, 0 * kPointerSize));  // Get enumerated object
@@ -1211,6 +1215,8 @@
   // Generate code for doing the condition check.
   PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
   __ bind(&loop);
+  SetExpressionPosition(stmt->each());
+
   // Load the current count to r0, load the length to r1.
   __ Ldrd(r0, r1, MemOperand(sp, 0 * kPointerSize));
   __ cmp(r0, r1);  // Compare to the array length.
@@ -1280,48 +1286,6 @@
 }
 
 
-void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
-  Comment cmnt(masm_, "[ ForOfStatement");
-  SetStatementPosition(stmt);
-
-  Iteration loop_statement(this, stmt);
-  increment_loop_depth();
-
-  // var iterator = iterable[Symbol.iterator]();
-  VisitForEffect(stmt->assign_iterator());
-
-  // Loop entry.
-  __ bind(loop_statement.continue_label());
-
-  // result = iterator.next()
-  VisitForEffect(stmt->next_result());
-
-  // if (result.done) break;
-  Label result_not_done;
-  VisitForControl(stmt->result_done(),
-                  loop_statement.break_label(),
-                  &result_not_done,
-                  &result_not_done);
-  __ bind(&result_not_done);
-
-  // each = result.value
-  VisitForEffect(stmt->assign_each());
-
-  // Generate code for the body of the loop.
-  Visit(stmt->body());
-
-  // Check stack before looping.
-  PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
-  EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
-  __ jmp(loop_statement.continue_label());
-
-  // Exit and decrement the loop depth.
-  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
-  __ bind(loop_statement.break_label());
-  decrement_loop_depth();
-}
-
-
 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
                                        bool pretenure) {
   // Use the fast case closure allocation code that allocates in new
@@ -1364,7 +1328,13 @@
   Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
   __ Move(LoadDescriptor::NameRegister(), home_object_symbol);
 
-  CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  if (FLAG_vector_ics) {
+    __ mov(VectorLoadICDescriptor::SlotRegister(),
+           Operand(SmiFromSlot(expr->HomeObjectFeedbackSlot())));
+    CallLoadIC(NOT_CONTEXTUAL);
+  } else {
+    CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  }
 
   __ cmp(r0, Operand(isolate()->factory()->undefined_value()));
   Label done;
@@ -1374,6 +1344,19 @@
 }
 
 
+void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
+                                                  int offset) {
+  if (NeedsHomeObject(initializer)) {
+    __ ldr(StoreDescriptor::ReceiverRegister(), MemOperand(sp));
+    __ mov(StoreDescriptor::NameRegister(),
+           Operand(isolate()->factory()->home_object_symbol()));
+    __ ldr(StoreDescriptor::ValueRegister(),
+           MemOperand(sp, offset * kPointerSize));
+    CallStoreIC();
+  }
+}
+
+
 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
                                                       TypeofState typeof_state,
                                                       Label* slow) {
@@ -1426,7 +1409,7 @@
   __ mov(LoadDescriptor::NameRegister(), Operand(proxy->var()->name()));
   if (FLAG_vector_ics) {
     __ mov(VectorLoadICDescriptor::SlotRegister(),
-           Operand(Smi::FromInt(proxy->VariableFeedbackSlot())));
+           Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
   }
 
   ContextualMode mode = (typeof_state == INSIDE_TYPEOF)
@@ -1515,7 +1498,7 @@
       __ mov(LoadDescriptor::NameRegister(), Operand(var->name()));
       if (FLAG_vector_ics) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
-               Operand(Smi::FromInt(proxy->VariableFeedbackSlot())));
+               Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
       }
       CallLoadIC(CONTEXTUAL);
       context()->Plug(r0);
@@ -1691,6 +1674,7 @@
     FastCloneShallowObjectStub stub(isolate(), properties_count);
     __ CallStub(&stub);
   }
+  PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
 
   // If result_saved is true the result is on top of the stack.  If
   // result_saved is false the result is in r0.
@@ -1719,6 +1703,8 @@
         DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
         // Fall through.
       case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             VisitForAccumulatorValue(value);
@@ -1727,6 +1713,14 @@
             __ ldr(StoreDescriptor::ReceiverRegister(), MemOperand(sp));
             CallStoreIC(key->LiteralFeedbackId());
             PrepareForBailoutForId(key->id(), NO_REGISTERS);
+
+            if (NeedsHomeObject(value)) {
+              __ Move(StoreDescriptor::ReceiverRegister(), r0);
+              __ mov(StoreDescriptor::NameRegister(),
+                     Operand(isolate()->factory()->home_object_symbol()));
+              __ ldr(StoreDescriptor::ValueRegister(), MemOperand(sp));
+              CallStoreIC();
+            }
           } else {
             VisitForEffect(value);
           }
@@ -1738,6 +1732,7 @@
         VisitForStackValue(key);
         VisitForStackValue(value);
         if (property->emit_store()) {
+          EmitSetHomeObjectIfNeeded(value, 2);
           __ mov(r0, Operand(Smi::FromInt(SLOPPY)));  // PropertyAttributes
           __ push(r0);
           __ CallRuntime(Runtime::kSetProperty, 4);
@@ -1751,7 +1746,7 @@
         __ push(r0);
         VisitForStackValue(value);
         if (property->emit_store()) {
-          __ CallRuntime(Runtime::kSetPrototype, 2);
+          __ CallRuntime(Runtime::kInternalSetPrototype, 2);
         } else {
           __ Drop(2);
         }
@@ -1775,7 +1770,9 @@
     __ push(r0);
     VisitForStackValue(it->first);
     EmitAccessor(it->second->getter);
+    EmitSetHomeObjectIfNeeded(it->second->getter, 2);
     EmitAccessor(it->second->setter);
+    EmitSetHomeObjectIfNeeded(it->second->setter, 3);
     __ mov(r0, Operand(Smi::FromInt(NONE)));
     __ push(r0);
     __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
@@ -1883,16 +1880,8 @@
 
   Comment cmnt(masm_, "[ Assignment");
 
-  // Left-hand side can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* property = expr->target()->AsProperty();
-  if (property != NULL) {
-    assign_type = (property->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(property);
 
   // Evaluate LHS expression.
   switch (assign_type) {
@@ -1908,6 +1897,32 @@
         VisitForStackValue(property->obj());
       }
       break;
+    case NAMED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Push(result_register());
+      if (expr->is_compound()) {
+        const Register scratch = r1;
+        __ ldr(scratch, MemOperand(sp, kPointerSize));
+        __ Push(scratch);
+        __ Push(result_register());
+      }
+      break;
+    case KEYED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForAccumulatorValue(property->key());
+      __ Push(result_register());
+      if (expr->is_compound()) {
+        const Register scratch = r1;
+        __ ldr(scratch, MemOperand(sp, 2 * kPointerSize));
+        __ Push(scratch);
+        __ ldr(scratch, MemOperand(sp, 2 * kPointerSize));
+        __ Push(scratch);
+        __ Push(result_register());
+      }
+      break;
     case KEYED_PROPERTY:
       if (expr->is_compound()) {
         VisitForStackValue(property->obj());
@@ -1935,6 +1950,14 @@
           EmitNamedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
           break;
+        case NAMED_SUPER_PROPERTY:
+          EmitNamedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
+        case KEYED_SUPER_PROPERTY:
+          EmitKeyedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
         case KEYED_PROPERTY:
           EmitKeyedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
@@ -1981,6 +2004,14 @@
     case NAMED_PROPERTY:
       EmitNamedPropertyAssignment(expr);
       break;
+    case NAMED_SUPER_PROPERTY:
+      EmitNamedSuperPropertyStore(property);
+      context()->Plug(r0);
+      break;
+    case KEYED_SUPER_PROPERTY:
+      EmitKeyedSuperPropertyStore(property);
+      context()->Plug(r0);
+      break;
     case KEYED_PROPERTY:
       EmitKeyedPropertyAssignment(expr);
       break;
@@ -2110,7 +2141,7 @@
       __ ldr(load_name, MemOperand(sp, 2 * kPointerSize));
       if (FLAG_vector_ics) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
-               Operand(Smi::FromInt(expr->KeyedLoadFeedbackSlot())));
+               Operand(SmiFromSlot(expr->KeyedLoadFeedbackSlot())));
       }
       Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
       CallIC(ic, TypeFeedbackId::None());
@@ -2130,7 +2161,7 @@
       __ LoadRoot(load_name, Heap::kdone_stringRootIndex);  // "done"
       if (FLAG_vector_ics) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
-               Operand(Smi::FromInt(expr->DoneFeedbackSlot())));
+               Operand(SmiFromSlot(expr->DoneFeedbackSlot())));
       }
       CallLoadIC(NOT_CONTEXTUAL);                           // r0=result.done
       Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
@@ -2143,7 +2174,7 @@
       __ LoadRoot(load_name, Heap::kvalue_stringRootIndex);  // "value"
       if (FLAG_vector_ics) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
-               Operand(Smi::FromInt(expr->ValueFeedbackSlot())));
+               Operand(SmiFromSlot(expr->ValueFeedbackSlot())));
       }
       CallLoadIC(NOT_CONTEXTUAL);                            // r0=result.value
       context()->DropAndPlug(2, r0);                         // drop iter and g
@@ -2164,15 +2195,6 @@
   VisitForAccumulatorValue(value);
   __ pop(r1);
 
-  // Check generator state.
-  Label wrong_state, closed_state, done;
-  __ ldr(r3, FieldMemOperand(r1, JSGeneratorObject::kContinuationOffset));
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
-  __ cmp(r3, Operand(Smi::FromInt(0)));
-  __ b(eq, &closed_state);
-  __ b(lt, &wrong_state);
-
   // Load suspended function and context.
   __ ldr(cp, FieldMemOperand(r1, JSGeneratorObject::kContextOffset));
   __ ldr(r4, FieldMemOperand(r1, JSGeneratorObject::kFunctionOffset));
@@ -2195,7 +2217,7 @@
 
   // Enter a new JavaScript frame, and initialize its slots as they were when
   // the generator was suspended.
-  Label resume_frame;
+  Label resume_frame, done;
   __ bind(&push_frame);
   __ bl(&resume_frame);
   __ jmp(&done);
@@ -2255,26 +2277,6 @@
   // Not reached: the runtime call returns elsewhere.
   __ stop("not-reached");
 
-  // Reach here when generator is closed.
-  __ bind(&closed_state);
-  if (resume_mode == JSGeneratorObject::NEXT) {
-    // Return completed iterator result when generator is closed.
-    __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
-    __ push(r2);
-    // Pop value from top-of-stack slot; box result into result register.
-    EmitCreateIteratorResult(true);
-  } else {
-    // Throw the provided value.
-    __ push(r0);
-    __ CallRuntime(Runtime::kThrow, 1);
-  }
-  __ jmp(&done);
-
-  // Throw error if we attempt to operate on a running generator.
-  __ bind(&wrong_state);
-  __ push(r1);
-  __ CallRuntime(Runtime::kThrowGeneratorStateError, 1);
-
   __ bind(&done);
   context()->Plug(result_register());
 }
@@ -2284,23 +2286,26 @@
   Label gc_required;
   Label allocated;
 
-  Handle<Map> map(isolate()->native_context()->iterator_result_map());
+  const int instance_size = 5 * kPointerSize;
+  DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
+            instance_size);
 
-  __ Allocate(map->instance_size(), r0, r2, r3, &gc_required, TAG_OBJECT);
+  __ Allocate(instance_size, r0, r2, r3, &gc_required, TAG_OBJECT);
   __ jmp(&allocated);
 
   __ bind(&gc_required);
-  __ Push(Smi::FromInt(map->instance_size()));
+  __ Push(Smi::FromInt(instance_size));
   __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
   __ ldr(context_register(),
          MemOperand(fp, StandardFrameConstants::kContextOffset));
 
   __ bind(&allocated);
-  __ mov(r1, Operand(map));
+  __ ldr(r1, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
+  __ ldr(r1, FieldMemOperand(r1, GlobalObject::kNativeContextOffset));
+  __ ldr(r1, ContextOperand(r1, Context::ITERATOR_RESULT_MAP_INDEX));
   __ pop(r2);
   __ mov(r3, Operand(isolate()->factory()->ToBoolean(done)));
   __ mov(r4, Operand(isolate()->factory()->empty_fixed_array()));
-  DCHECK_EQ(map->instance_size(), 5 * kPointerSize);
   __ str(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
   __ str(r4, FieldMemOperand(r0, JSObject::kPropertiesOffset));
   __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
@@ -2319,11 +2324,12 @@
 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
+  DCHECK(!prop->IsSuperAccess());
 
   __ mov(LoadDescriptor::NameRegister(), Operand(key->value()));
   if (FLAG_vector_ics) {
     __ mov(VectorLoadICDescriptor::SlotRegister(),
-           Operand(Smi::FromInt(prop->PropertyFeedbackSlot())));
+           Operand(SmiFromSlot(prop->PropertyFeedbackSlot())));
     CallLoadIC(NOT_CONTEXTUAL);
   } else {
     CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
@@ -2332,15 +2338,12 @@
 
 
 void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object.
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
   DCHECK(!key->value()->IsSmi());
   DCHECK(prop->IsSuperAccess());
 
-  SuperReference* super_ref = prop->obj()->AsSuperReference();
-  EmitLoadHomeObject(super_ref);
-  __ Push(r0);
-  VisitForStackValue(super_ref->this_var());
   __ Push(key->value());
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 }
@@ -2351,7 +2354,7 @@
   Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
   if (FLAG_vector_ics) {
     __ mov(VectorLoadICDescriptor::SlotRegister(),
-           Operand(Smi::FromInt(prop->PropertyFeedbackSlot())));
+           Operand(SmiFromSlot(prop->PropertyFeedbackSlot())));
     CallIC(ic);
   } else {
     CallIC(ic, prop->PropertyFeedbackId());
@@ -2359,6 +2362,14 @@
 }
 
 
+void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object, key.
+  SetSourcePosition(prop->position());
+
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+}
+
+
 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
                                               Token::Value op,
                                               OverwriteMode mode,
@@ -2453,6 +2464,63 @@
 }
 
 
+void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
+  // Constructor is in r0.
+  DCHECK(lit != NULL);
+  __ push(r0);
+
+  // No access check is needed here since the constructor is created by the
+  // class literal.
+  Register scratch = r1;
+  __ ldr(scratch,
+         FieldMemOperand(r0, JSFunction::kPrototypeOrInitialMapOffset));
+  __ push(scratch);
+
+  for (int i = 0; i < lit->properties()->length(); i++) {
+    ObjectLiteral::Property* property = lit->properties()->at(i);
+    Literal* key = property->key()->AsLiteral();
+    Expression* value = property->value();
+    DCHECK(key != NULL);
+
+    if (property->is_static()) {
+      __ ldr(scratch, MemOperand(sp, kPointerSize));  // constructor
+    } else {
+      __ ldr(scratch, MemOperand(sp, 0));  // prototype
+    }
+    __ push(scratch);
+    VisitForStackValue(key);
+    VisitForStackValue(value);
+    EmitSetHomeObjectIfNeeded(value, 2);
+
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT:
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+      case ObjectLiteral::Property::COMPUTED:
+      case ObjectLiteral::Property::PROTOTYPE:
+        __ CallRuntime(Runtime::kDefineClassMethod, 3);
+        break;
+
+      case ObjectLiteral::Property::GETTER:
+        __ CallRuntime(Runtime::kDefineClassGetter, 3);
+        break;
+
+      case ObjectLiteral::Property::SETTER:
+        __ CallRuntime(Runtime::kDefineClassSetter, 3);
+        break;
+
+      default:
+        UNREACHABLE();
+    }
+  }
+
+  // prototype
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+
+  // constructor
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+}
+
+
 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
                                      Token::Value op,
                                      OverwriteMode mode) {
@@ -2468,16 +2536,8 @@
 void FullCodeGenerator::EmitAssignment(Expression* expr) {
   DCHECK(expr->IsValidReferenceExpression());
 
-  // Left-hand side can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* prop = expr->AsProperty();
-  if (prop != NULL) {
-    assign_type = (prop->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(prop);
 
   switch (assign_type) {
     case VARIABLE: {
@@ -2496,6 +2556,42 @@
       CallStoreIC();
       break;
     }
+    case NAMED_SUPER_PROPERTY: {
+      __ Push(r0);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      // stack: value, this; r0: home_object
+      Register scratch = r2;
+      Register scratch2 = r3;
+      __ mov(scratch, result_register());              // home_object
+      __ ldr(r0, MemOperand(sp, kPointerSize));        // value
+      __ ldr(scratch2, MemOperand(sp, 0));             // this
+      __ str(scratch2, MemOperand(sp, kPointerSize));  // this
+      __ str(scratch, MemOperand(sp, 0));              // home_object
+      // stack: this, home_object; r0: value
+      EmitNamedSuperPropertyStore(prop);
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      __ Push(r0);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForAccumulatorValue(prop->key());
+      Register scratch = r2;
+      Register scratch2 = r3;
+      __ ldr(scratch2, MemOperand(sp, 2 * kPointerSize));  // value
+      // stack: value, this, home_object; r0: key, r3: value
+      __ ldr(scratch, MemOperand(sp, kPointerSize));  // this
+      __ str(scratch, MemOperand(sp, 2 * kPointerSize));
+      __ ldr(scratch, MemOperand(sp, 0));  // home_object
+      __ str(scratch, MemOperand(sp, kPointerSize));
+      __ str(r0, MemOperand(sp, 0));
+      __ Move(r0, scratch2);
+      // stack: this, home_object, key; r0: value.
+      EmitKeyedSuperPropertyStore(prop);
+      break;
+    }
     case KEYED_PROPERTY: {
       __ push(r0);  // Preserve value.
       VisitForStackValue(prop->obj());
@@ -2589,8 +2685,9 @@
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
+  } else if (IsSignallingAssignmentToConst(var, op, strict_mode())) {
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
   }
-  // Non-initializing assignments to consts are ignored.
 }
 
 
@@ -2612,6 +2709,35 @@
 }
 
 
+void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // r0 : value
+  // stack : receiver ('this'), home_object
+  DCHECK(prop != NULL);
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(key != NULL);
+
+  __ Push(key->value());
+  __ Push(r0);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
+                                          : Runtime::kStoreToSuper_Sloppy),
+                 4);
+}
+
+
+void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // r0 : value
+  // stack : receiver ('this'), home_object, key
+  DCHECK(prop != NULL);
+
+  __ Push(r0);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict
+                                          : Runtime::kStoreKeyedToSuper_Sloppy),
+                 4);
+}
+
+
 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
   // Assignment to a property, using a keyed store IC.
 
@@ -2638,16 +2764,27 @@
       __ Move(LoadDescriptor::ReceiverRegister(), r0);
       EmitNamedPropertyLoad(expr);
     } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
       EmitNamedSuperPropertyLoad(expr);
     }
     PrepareForBailoutForId(expr->LoadId(), TOS_REG);
     context()->Plug(r0);
   } else {
-    VisitForStackValue(expr->obj());
-    VisitForAccumulatorValue(expr->key());
-    __ Move(LoadDescriptor::NameRegister(), r0);
-    __ pop(LoadDescriptor::ReceiverRegister());
-    EmitKeyedPropertyLoad(expr);
+    if (!expr->IsSuperAccess()) {
+      VisitForStackValue(expr->obj());
+      VisitForAccumulatorValue(expr->key());
+      __ Move(LoadDescriptor::NameRegister(), r0);
+      __ pop(LoadDescriptor::ReceiverRegister());
+      EmitKeyedPropertyLoad(expr);
+    } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForStackValue(expr->key());
+      EmitKeyedSuperPropertyLoad(expr);
+    }
     context()->Plug(r0);
   }
 }
@@ -2712,16 +2849,16 @@
   __ Push(r0);
   VisitForAccumulatorValue(super_ref->this_var());
   __ Push(r0);
-  __ ldr(scratch, MemOperand(sp, kPointerSize));
-  __ Push(scratch);
   __ Push(r0);
+  __ ldr(scratch, MemOperand(sp, kPointerSize * 2));
+  __ Push(scratch);
   __ Push(key->value());
 
   // Stack here:
   //  - home_object
   //  - this (receiver)
-  //  - home_object <-- LoadFromSuper will pop here and below.
-  //  - this (receiver)
+  //  - this (receiver) <-- LoadFromSuper will pop here and below.
+  //  - home_object
   //  - key
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 
@@ -2759,6 +2896,43 @@
 }
 
 
+void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
+  Expression* callee = expr->expression();
+  DCHECK(callee->IsProperty());
+  Property* prop = callee->AsProperty();
+  DCHECK(prop->IsSuperAccess());
+
+  SetSourcePosition(prop->position());
+  // Load the function from the receiver.
+  const Register scratch = r1;
+  SuperReference* super_ref = prop->obj()->AsSuperReference();
+  EmitLoadHomeObject(super_ref);
+  __ Push(r0);
+  VisitForAccumulatorValue(super_ref->this_var());
+  __ Push(r0);
+  __ Push(r0);
+  __ ldr(scratch, MemOperand(sp, kPointerSize * 2));
+  __ Push(scratch);
+  VisitForStackValue(prop->key());
+
+  // Stack here:
+  //  - home_object
+  //  - this (receiver)
+  //  - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
+  //  - home_object
+  //  - key
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+
+  // Replace home_object with target function.
+  __ str(r0, MemOperand(sp, kPointerSize));
+
+  // Stack here:
+  // - target function
+  // - this (receiver)
+  EmitCall(expr, CallICState::METHOD);
+}
+
+
 void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
   // Load the arguments.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2773,7 +2947,7 @@
   SetSourcePosition(expr->position());
   Handle<Code> ic = CallIC::initialize_stub(
       isolate(), arg_count, call_type);
-  __ mov(r3, Operand(Smi::FromInt(expr->CallFeedbackSlot())));
+  __ mov(r3, Operand(SmiFromSlot(expr->CallFeedbackSlot())));
   __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
   // Don't assign a type feedback id to the IC, since type feedback is provided
   // by the vector above.
@@ -2814,6 +2988,14 @@
 }
 
 
+void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
+  DCHECK(super_ref != NULL);
+  __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ Push(r0);
+  __ CallRuntime(Runtime::kGetPrototype, 1);
+}
+
+
 void FullCodeGenerator::VisitCall(Call* expr) {
 #ifdef DEBUG
   // We want to verify that RecordJSReturnSite gets called on all paths
@@ -2853,6 +3035,8 @@
       // r1 (receiver). Touch up the stack with the right values.
       __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
       __ str(r1, MemOperand(sp, arg_count * kPointerSize));
+
+      PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
     }
 
     // Record source position for debugger.
@@ -2886,6 +3070,7 @@
     __ Push(context_register(), r2);
     __ CallRuntime(Runtime::kLoadLookupSlot, 2);
     __ Push(r0, r1);  // Function, receiver.
+    PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
 
     // If fast case code has been generated, emit code to push the
     // function and receiver and have the slow path jump around this
@@ -2909,9 +3094,12 @@
   } else if (call_type == Call::PROPERTY_CALL) {
     Property* property = callee->AsProperty();
     bool is_named_call = property->key()->IsPropertyName();
-    // super.x() is handled in EmitCallWithLoadIC.
-    if (property->IsSuperAccess() && is_named_call) {
-      EmitSuperCallWithLoadIC(expr);
+    if (property->IsSuperAccess()) {
+      if (is_named_call) {
+        EmitSuperCallWithLoadIC(expr);
+      } else {
+        EmitKeyedSuperCallWithLoadIC(expr);
+      }
     } else {
       {
         PreservePositionScope scope(masm()->positions_recorder());
@@ -2923,6 +3111,12 @@
         EmitKeyedCallWithLoadIC(expr, property->key());
       }
     }
+  } else if (call_type == Call::SUPER_CALL) {
+    SuperReference* super_ref = callee->AsSuperReference();
+    EmitLoadSuperConstructor(super_ref);
+    __ Push(result_register());
+    VisitForStackValue(super_ref->this_var());
+    EmitCall(expr, CallICState::METHOD);
   } else {
     DCHECK(call_type == Call::OTHER_CALL);
     // Call to an arbitrary expression not handled specially above.
@@ -2951,7 +3145,12 @@
   // Push constructor on the stack.  If it's not a function it's used as
   // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
   // ignored.
-  VisitForStackValue(expr->expression());
+  if (expr->expression()->IsSuperReference()) {
+    EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
+    __ Push(result_register());
+  } else {
+    VisitForStackValue(expr->expression());
+  }
 
   // Push the arguments ("left-to-right") on the stack.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2971,12 +3170,12 @@
   // Record call targets in unoptimized code.
   if (FLAG_pretenuring_call_new) {
     EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
-    DCHECK(expr->AllocationSiteFeedbackSlot() ==
-           expr->CallNewFeedbackSlot() + 1);
+    DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
+           expr->CallNewFeedbackSlot().ToInt() + 1);
   }
 
   __ Move(r2, FeedbackVector());
-  __ mov(r3, Operand(Smi::FromInt(expr->CallNewFeedbackSlot())));
+  __ mov(r3, Operand(SmiFromSlot(expr->CallNewFeedbackSlot())));
 
   CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
@@ -3287,6 +3486,32 @@
 }
 
 
+void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ JumpIfSmi(r0, if_false);
+  Register map = r1;
+  Register type_reg = r2;
+  __ ldr(map, FieldMemOperand(r0, HeapObject::kMapOffset));
+  __ ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  __ sub(type_reg, type_reg, Operand(FIRST_JS_PROXY_TYPE));
+  __ cmp(type_reg, Operand(LAST_JS_PROXY_TYPE - FIRST_JS_PROXY_TYPE));
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(ls, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
 
 void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
   DCHECK(expr->arguments()->length() == 0);
@@ -4177,7 +4402,7 @@
     __ mov(LoadDescriptor::NameRegister(), Operand(expr->name()));
     if (FLAG_vector_ics) {
       __ mov(VectorLoadICDescriptor::SlotRegister(),
-             Operand(Smi::FromInt(expr->CallRuntimeFeedbackSlot())));
+             Operand(SmiFromSlot(expr->CallRuntimeFeedbackSlot())));
       CallLoadIC(NOT_CONTEXTUAL);
     } else {
       CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
@@ -4333,17 +4558,8 @@
   Comment cmnt(masm_, "[ CountOperation");
   SetSourcePosition(expr->position());
 
-  // Expression can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* prop = expr->expression()->AsProperty();
-  // In case of a property we use the uninitialized expression context
-  // of the key to detect a named property.
-  if (prop != NULL) {
-    assign_type =
-        (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(prop);
 
   // Evaluate expression and get value.
   if (assign_type == VARIABLE) {
@@ -4356,18 +4572,55 @@
       __ mov(ip, Operand(Smi::FromInt(0)));
       __ push(ip);
     }
-    if (assign_type == NAMED_PROPERTY) {
-      // Put the object both on the stack and in the register.
-      VisitForStackValue(prop->obj());
-      __ ldr(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
-      EmitNamedPropertyLoad(prop);
-    } else {
-      VisitForStackValue(prop->obj());
-      VisitForStackValue(prop->key());
-      __ ldr(LoadDescriptor::ReceiverRegister(),
-             MemOperand(sp, 1 * kPointerSize));
-      __ ldr(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
-      EmitKeyedPropertyLoad(prop);
+    switch (assign_type) {
+      case NAMED_PROPERTY: {
+        // Put the object both on the stack and in the register.
+        VisitForStackValue(prop->obj());
+        __ ldr(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
+        EmitNamedPropertyLoad(prop);
+        break;
+      }
+
+      case NAMED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        __ Push(result_register());
+        const Register scratch = r1;
+        __ ldr(scratch, MemOperand(sp, kPointerSize));
+        __ Push(scratch);
+        __ Push(result_register());
+        EmitNamedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        __ Push(result_register());
+        VisitForAccumulatorValue(prop->key());
+        __ Push(result_register());
+        const Register scratch = r1;
+        __ ldr(scratch, MemOperand(sp, 2 * kPointerSize));
+        __ Push(scratch);
+        __ ldr(scratch, MemOperand(sp, 2 * kPointerSize));
+        __ Push(scratch);
+        __ Push(result_register());
+        EmitKeyedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_PROPERTY: {
+        VisitForStackValue(prop->obj());
+        VisitForStackValue(prop->key());
+        __ ldr(LoadDescriptor::ReceiverRegister(),
+               MemOperand(sp, 1 * kPointerSize));
+        __ ldr(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
+        EmitKeyedPropertyLoad(prop);
+        break;
+      }
+
+      case VARIABLE:
+        UNREACHABLE();
     }
   }
 
@@ -4401,9 +4654,15 @@
           case NAMED_PROPERTY:
             __ str(r0, MemOperand(sp, kPointerSize));
             break;
+          case NAMED_SUPER_PROPERTY:
+            __ str(r0, MemOperand(sp, 2 * kPointerSize));
+            break;
           case KEYED_PROPERTY:
             __ str(r0, MemOperand(sp, 2 * kPointerSize));
             break;
+          case KEYED_SUPER_PROPERTY:
+            __ str(r0, MemOperand(sp, 3 * kPointerSize));
+            break;
         }
       }
     }
@@ -4431,9 +4690,15 @@
         case NAMED_PROPERTY:
           __ str(r0, MemOperand(sp, kPointerSize));
           break;
+        case NAMED_SUPER_PROPERTY:
+          __ str(r0, MemOperand(sp, 2 * kPointerSize));
+          break;
         case KEYED_PROPERTY:
           __ str(r0, MemOperand(sp, 2 * kPointerSize));
           break;
+        case KEYED_SUPER_PROPERTY:
+          __ str(r0, MemOperand(sp, 3 * kPointerSize));
+          break;
       }
     }
   }
@@ -4489,6 +4754,28 @@
       }
       break;
     }
+    case NAMED_SUPER_PROPERTY: {
+      EmitNamedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(r0);
+      }
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      EmitKeyedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(r0);
+      }
+      break;
+    }
     case KEYED_PROPERTY: {
       __ Pop(StoreDescriptor::ReceiverRegister(),
              StoreDescriptor::NameRegister());
@@ -4519,7 +4806,7 @@
     __ mov(LoadDescriptor::NameRegister(), Operand(proxy->name()));
     if (FLAG_vector_ics) {
       __ mov(VectorLoadICDescriptor::SlotRegister(),
-             Operand(Smi::FromInt(proxy->VariableFeedbackSlot())));
+             Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
     }
     // Use a regular load, not a contextual load, to avoid a reference
     // error.
@@ -4756,7 +5043,7 @@
 
 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
   Scope* declaration_scope = scope()->DeclarationScope();
-  if (declaration_scope->is_global_scope() ||
+  if (declaration_scope->is_script_scope() ||
       declaration_scope->is_module_scope()) {
     // Contexts nested in the native context have a canonical empty function
     // as their closure, not the anonymous closure containing the global
diff --git a/src/arm/interface-descriptors-arm.cc b/src/arm/interface-descriptors-arm.cc
index 9bbc1f5..6e77ee4 100644
--- a/src/arm/interface-descriptors-arm.cc
+++ b/src/arm/interface-descriptors-arm.cc
@@ -29,6 +29,9 @@
 const Register StoreDescriptor::ValueRegister() { return r0; }
 
 
+const Register StoreTransitionDescriptor::MapRegister() { return r3; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() { return r3; }
 
 
@@ -149,6 +152,15 @@
 }
 
 
+void AllocateHeapNumberDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // register state
+  // cp -- context
+  Register registers[] = {cp};
+  data->Initialize(arraysize(registers), registers, nullptr);
+}
+
+
 void ArrayConstructorConstantArgCountDescriptor::Initialize(
     CallInterfaceDescriptorData* data) {
   // register state
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 13a46a2..e5de950 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <sstream>
+
 #include "src/v8.h"
 
 #include "src/arm/lithium-codegen-arm.h"
@@ -316,9 +318,9 @@
 
 void LStoreNamedField::PrintDataTo(StringStream* stream) {
   object()->PrintTo(stream);
-  OStringStream os;
+  std::ostringstream os;
   os << hydrogen()->access() << " <- ";
-  stream->Add(os.c_str());
+  stream->Add(os.str().c_str());
   value()->PrintTo(stream);
 }
 
@@ -697,11 +699,7 @@
     // Shift operations can only deoptimize if we do a logical shift
     // by 0 and the result cannot be truncated to int32.
     if (op == Token::SHR && constant_value == 0) {
-      if (FLAG_opt_safe_uint32_operations) {
-        does_deopt = !instr->CheckFlag(HInstruction::kUint32);
-      } else {
-        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32);
-      }
+      does_deopt = !instr->CheckFlag(HInstruction::kUint32);
     }
 
     LInstruction* result =
@@ -1100,9 +1098,17 @@
       UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
   LOperand* name_register =
       UseFixed(instr->name(), LoadDescriptor::NameRegister());
+  LOperand* slot = NULL;
+  LOperand* vector = NULL;
+  if (FLAG_vector_ics) {
+    slot = UseFixed(instr->slot(), VectorLoadICDescriptor::SlotRegister());
+    vector =
+        UseFixed(instr->vector(), VectorLoadICDescriptor::VectorRegister());
+  }
+
   // Not marked as call. It can't deoptimize, and it never returns.
   return new (zone()) LTailCallThroughMegamorphicCache(
-      context, receiver_register, name_register);
+      context, receiver_register, name_register, slot, vector);
 }
 
 
@@ -1399,8 +1405,16 @@
   LOperand* divisor = UseRegister(instr->right());
   LOperand* temp =
       CpuFeatures::IsSupported(SUDIV) ? NULL : TempDoubleRegister();
-  LFlooringDivI* div = new(zone()) LFlooringDivI(dividend, divisor, temp);
-  return AssignEnvironment(DefineAsRegister(div));
+  LInstruction* result =
+      DefineAsRegister(new (zone()) LFlooringDivI(dividend, divisor, temp));
+  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
+      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
+      (instr->CheckFlag(HValue::kCanOverflow) &&
+       (!CpuFeatures::IsSupported(SUDIV) ||
+        !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)))) {
+    result = AssignEnvironment(result);
+  }
+  return result;
 }
 
 
@@ -2113,7 +2127,7 @@
   LOperand* global_object =
       UseFixed(instr->global_object(), LoadDescriptor::ReceiverRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
   LLoadGlobalGeneric* result =
@@ -2172,7 +2186,7 @@
   LOperand* object =
       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
 
@@ -2239,7 +2253,7 @@
       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
   LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
 
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index f9feaf6..1920935 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -166,17 +166,13 @@
   V(WrapReceiver)
 
 
-#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)                        \
-  virtual Opcode opcode() const FINAL OVERRIDE {                      \
-    return LInstruction::k##type;                                           \
-  }                                                                         \
-  virtual void CompileToNative(LCodeGen* generator) FINAL OVERRIDE;   \
-  virtual const char* Mnemonic() const FINAL OVERRIDE {               \
-    return mnemonic;                                                        \
-  }                                                                         \
-  static L##type* cast(LInstruction* instr) {                               \
-    DCHECK(instr->Is##type());                                              \
-    return reinterpret_cast<L##type*>(instr);                               \
+#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)            \
+  Opcode opcode() const FINAL { return LInstruction::k##type; } \
+  void CompileToNative(LCodeGen* generator) FINAL;              \
+  const char* Mnemonic() const FINAL { return mnemonic; }       \
+  static L##type* cast(LInstruction* instr) {                   \
+    DCHECK(instr->Is##type());                                  \
+    return reinterpret_cast<L##type*>(instr);                   \
   }
 
 
@@ -291,11 +287,9 @@
  public:
   // Allow 0 or 1 output operands.
   STATIC_ASSERT(R == 0 || R == 1);
-  virtual bool HasResult() const FINAL OVERRIDE {
-    return R != 0 && result() != NULL;
-  }
+  bool HasResult() const FINAL { return R != 0 && result() != NULL; }
   void set_result(LOperand* operand) { results_[0] = operand; }
-  LOperand* result() const { return results_[0]; }
+  LOperand* result() const OVERRIDE { return results_[0]; }
 
  protected:
   EmbeddedContainer<LOperand*, R> results_;
@@ -313,11 +307,11 @@
 
  private:
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return I; }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return I; }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return T; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return temps_[i]; }
+  int TempCount() FINAL { return T; }
+  LOperand* TempAt(int i) FINAL { return temps_[i]; }
 };
 
 
@@ -332,8 +326,8 @@
   }
 
   // Can't use the DECLARE-macro here because of sub-classes.
-  virtual bool IsGap() const OVERRIDE { return true; }
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsGap() const OVERRIDE { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   static LGap* cast(LInstruction* instr) {
     DCHECK(instr->IsGap());
     return reinterpret_cast<LGap*>(instr);
@@ -373,7 +367,7 @@
  public:
   explicit LInstructionGap(HBasicBlock* block) : LGap(block) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
     return !IsRedundant();
   }
 
@@ -385,10 +379,10 @@
  public:
   explicit LGoto(HBasicBlock* block) : block_(block) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
   DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
-  virtual bool IsControl() const OVERRIDE { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsControl() const OVERRIDE { return true; }
 
   int block_id() const { return block_->block_id(); }
 
@@ -431,7 +425,7 @@
 
 class LDeoptimize FINAL : public LTemplateInstruction<0, 0, 0> {
  public:
-  virtual bool IsControl() const OVERRIDE { return true; }
+  bool IsControl() const OVERRIDE { return true; }
   DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
   DECLARE_HYDROGEN_ACCESSOR(Deoptimize)
 };
@@ -442,12 +436,10 @@
   explicit LLabel(HBasicBlock* block)
       : LGap(block), replacement_(NULL) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(Label, "label")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int block_id() const { return block()->block_id(); }
   bool is_loop_header() const { return block()->IsLoopHeader(); }
@@ -465,7 +457,7 @@
 
 class LParameter FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const { return false; }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter")
 };
 
@@ -484,30 +476,33 @@
 
 
 class LTailCallThroughMegamorphicCache FINAL
-    : public LTemplateInstruction<0, 3, 0> {
+    : public LTemplateInstruction<0, 5, 0> {
  public:
-  explicit LTailCallThroughMegamorphicCache(LOperand* context,
-                                            LOperand* receiver,
-                                            LOperand* name) {
+  LTailCallThroughMegamorphicCache(LOperand* context, LOperand* receiver,
+                                   LOperand* name, LOperand* slot,
+                                   LOperand* vector) {
     inputs_[0] = context;
     inputs_[1] = receiver;
     inputs_[2] = name;
+    inputs_[3] = slot;
+    inputs_[4] = vector;
   }
 
   LOperand* context() { return inputs_[0]; }
   LOperand* receiver() { return inputs_[1]; }
   LOperand* name() { return inputs_[2]; }
+  LOperand* slot() { return inputs_[3]; }
+  LOperand* vector() { return inputs_[4]; }
 
   DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
                                "tail-call-through-megamorphic-cache")
   DECLARE_HYDROGEN_ACCESSOR(TailCallThroughMegamorphicCache)
 };
 
+
 class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown-osr-value")
 };
 
@@ -517,7 +512,7 @@
  public:
   LControlInstruction() : false_label_(NULL), true_label_(NULL) { }
 
-  virtual bool IsControl() const FINAL OVERRIDE { return true; }
+  bool IsControl() const FINAL { return true; }
 
   int SuccessorCount() { return hydrogen()->SuccessorCount(); }
   HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); }
@@ -606,7 +601,7 @@
   LOperand* length() { return inputs_[1]; }
   LOperand* index() { return inputs_[2]; }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -869,7 +864,7 @@
     return hydrogen()->representation().IsDouble();
   }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1053,7 +1048,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1070,7 +1065,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1085,7 +1080,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1103,7 +1098,7 @@
                                "is-undetectable-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1125,7 +1120,7 @@
 
   Token::Value op() const { return hydrogen()->token(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1141,7 +1136,7 @@
                                "has-instance-type-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1171,7 +1166,7 @@
                                "has-cached-array-index-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1189,7 +1184,7 @@
                                "class-of-test-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1401,7 +1396,7 @@
   DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
   DECLARE_HYDROGEN_ACCESSOR(Branch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1546,11 +1541,9 @@
   LOperand* left() { return inputs_[0]; }
   LOperand* right() { return inputs_[1]; }
 
-  virtual Opcode opcode() const OVERRIDE {
-    return LInstruction::kArithmeticD;
-  }
-  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
-  virtual const char* Mnemonic() const OVERRIDE;
+  Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticD; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
 
  private:
   Token::Value op_;
@@ -1574,11 +1567,9 @@
   LOperand* right() { return inputs_[2]; }
   Token::Value op() const { return op_; }
 
-  virtual Opcode opcode() const OVERRIDE {
-    return LInstruction::kArithmeticT;
-  }
-  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
-  virtual const char* Mnemonic() const OVERRIDE;
+  Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticT; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
 
  private:
   Token::Value op_;
@@ -1687,7 +1678,7 @@
   DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
   DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   uint32_t base_offset() const { return hydrogen()->base_offset(); }
 };
 
@@ -1768,7 +1759,7 @@
 
   int slot_index() { return hydrogen()->slot_index(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1787,7 +1778,7 @@
 
   int slot_index() { return hydrogen()->slot_index(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1826,7 +1817,7 @@
   LOperand* function() { return inputs_[0]; }
   LOperand* code_object() { return inputs_[1]; }
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry, "store-code-entry")
   DECLARE_HYDROGEN_ACCESSOR(StoreCodeEntry)
@@ -1843,7 +1834,7 @@
   LOperand* base_object() const { return inputs_[0]; }
   LOperand* offset() const { return inputs_[1]; }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object")
 };
@@ -1887,7 +1878,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallJSFunction, "call-js-function")
   DECLARE_HYDROGEN_ACCESSOR(CallJSFunction)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1907,11 +1898,12 @@
 
   const CallInterfaceDescriptor descriptor() { return descriptor_; }
 
- private:
-  DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
   DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+ private:
+  DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 
@@ -1919,11 +1911,11 @@
   ZoneList<LOperand*> inputs_;
 
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return inputs_.length(); }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return inputs_.length(); }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return 0; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return NULL; }
+  int TempCount() FINAL { return 0; }
+  LOperand* TempAt(int i) FINAL { return NULL; }
 };
 
 
@@ -1940,7 +1932,7 @@
   DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function")
   DECLARE_HYDROGEN_ACCESSOR(InvokeFunction)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1976,7 +1968,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
   DECLARE_HYDROGEN_ACCESSOR(CallNew)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1995,7 +1987,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
   DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -2012,7 +2004,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
   DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
 
-  virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
+  bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
     return save_doubles() == kDontSaveFPRegs;
   }
 
@@ -2206,7 +2198,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
   DECLARE_HYDROGEN_ACCESSOR(StoreNamedField)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Representation representation() const {
     return hydrogen()->field_representation();
@@ -2229,7 +2221,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
   DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Handle<Object> name() const { return hydrogen()->name(); }
   StrictMode strict_mode() { return hydrogen()->strict_mode(); }
@@ -2261,7 +2253,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed")
   DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   bool NeedsCanonicalization() {
     if (hydrogen()->value()->IsAdd() || hydrogen()->value()->IsSub() ||
         hydrogen()->value()->IsMul() || hydrogen()->value()->IsDiv()) {
@@ -2293,7 +2285,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
   DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   StrictMode strict_mode() { return hydrogen()->strict_mode(); }
 };
@@ -2317,7 +2309,7 @@
                                "transition-elements-kind")
   DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Handle<Map> original_map() { return hydrogen()->original_map().handle(); }
   Handle<Map> transitioned_map() {
@@ -2611,7 +2603,7 @@
 
   Handle<String> type_literal() { return hydrogen()->type_literal(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -2632,9 +2624,7 @@
  public:
   LOsrEntry() {}
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry")
 };
 
@@ -2839,7 +2829,7 @@
 
   // An input operand in register, stack slot or a constant operand.
   // Will not be moved to a register even if one is freely available.
-  virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE;
+  MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE;
 
   // Temporary operand that must be in a register.
   MUST_USE_RESULT LUnallocated* TempRegister();
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index a06ed73..9d9591b 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -27,9 +27,9 @@
         deopt_mode_(mode) { }
   virtual ~SafepointGenerator() {}
 
-  virtual void BeforeCall(int call_size) const OVERRIDE {}
+  void BeforeCall(int call_size) const OVERRIDE {}
 
-  virtual void AfterCall() const OVERRIDE {
+  void AfterCall() const OVERRIDE {
     codegen_->RecordSafepoint(pointers_, deopt_mode_);
   }
 
@@ -1158,7 +1158,7 @@
     __ and_(dividend, dividend, Operand(mask));
     __ rsb(dividend, dividend, Operand::Zero(), SetCC);
     if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
-      DeoptimizeIf(eq, instr);
+      DeoptimizeIf(eq, instr, "minus zero");
     }
     __ b(&done);
   }
@@ -1176,7 +1176,7 @@
   DCHECK(!dividend.is(result));
 
   if (divisor == 0) {
-    DeoptimizeIf(al, instr);
+    DeoptimizeIf(al, instr, "division by zero");
     return;
   }
 
@@ -1191,7 +1191,7 @@
     Label remainder_not_zero;
     __ b(ne, &remainder_not_zero);
     __ cmp(dividend, Operand::Zero());
-    DeoptimizeIf(lt, instr);
+    DeoptimizeIf(lt, instr, "minus zero");
     __ bind(&remainder_not_zero);
   }
 }
@@ -1211,7 +1211,7 @@
     // case because we can't return a NaN.
     if (hmod->CheckFlag(HValue::kCanBeDivByZero)) {
       __ cmp(right_reg, Operand::Zero());
-      DeoptimizeIf(eq, instr);
+      DeoptimizeIf(eq, instr, "division by zero");
     }
 
     // Check for kMinInt % -1, sdiv will return kMinInt, which is not what we
@@ -1222,7 +1222,7 @@
       __ b(ne, &no_overflow_possible);
       __ cmp(right_reg, Operand(-1));
       if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
-        DeoptimizeIf(eq, instr);
+        DeoptimizeIf(eq, instr, "minus zero");
       } else {
         __ b(ne, &no_overflow_possible);
         __ mov(result_reg, Operand::Zero());
@@ -1243,7 +1243,7 @@
       __ cmp(result_reg, Operand::Zero());
       __ b(ne, &done);
       __ cmp(left_reg, Operand::Zero());
-      DeoptimizeIf(lt, instr);
+      DeoptimizeIf(lt, instr, "minus zero");
     }
     __ bind(&done);
 
@@ -1268,7 +1268,7 @@
     // NaN.
     if (hmod->CheckFlag(HValue::kCanBeDivByZero)) {
       __ cmp(right_reg, Operand::Zero());
-      DeoptimizeIf(eq, instr);
+      DeoptimizeIf(eq, instr, "division by zero");
     }
 
     __ Move(result_reg, left_reg);
@@ -1298,7 +1298,7 @@
     if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
       __ b(ne, &done);
       __ cmp(left_reg, Operand::Zero());
-      DeoptimizeIf(mi, instr);
+      DeoptimizeIf(mi, instr, "minus zero");
     }
     __ bind(&done);
   }
@@ -1316,19 +1316,19 @@
   HDiv* hdiv = instr->hydrogen();
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
     __ cmp(dividend, Operand::Zero());
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "minus zero");
   }
   // Check for (kMinInt / -1).
   if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) {
     __ cmp(dividend, Operand(kMinInt));
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "overflow");
   }
   // Deoptimize if remainder will not be 0.
   if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
       divisor != 1 && divisor != -1) {
     int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
     __ tst(dividend, Operand(mask));
-    DeoptimizeIf(ne, instr);
+    DeoptimizeIf(ne, instr, "lost precision");
   }
 
   if (divisor == -1) {  // Nice shortcut, not needed for correctness.
@@ -1356,7 +1356,7 @@
   DCHECK(!dividend.is(result));
 
   if (divisor == 0) {
-    DeoptimizeIf(al, instr);
+    DeoptimizeIf(al, instr, "division by zero");
     return;
   }
 
@@ -1364,7 +1364,7 @@
   HDiv* hdiv = instr->hydrogen();
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
     __ cmp(dividend, Operand::Zero());
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "minus zero");
   }
 
   __ TruncatingDiv(result, dividend, Abs(divisor));
@@ -1374,7 +1374,7 @@
     __ mov(ip, Operand(divisor));
     __ smull(scratch0(), ip, result, ip);
     __ sub(scratch0(), scratch0(), dividend, SetCC);
-    DeoptimizeIf(ne, instr);
+    DeoptimizeIf(ne, instr, "lost precision");
   }
 }
 
@@ -1389,7 +1389,7 @@
   // Check for x / 0.
   if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
     __ cmp(divisor, Operand::Zero());
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "division by zero");
   }
 
   // Check for (0 / -x) that will produce negative zero.
@@ -1401,7 +1401,7 @@
     }
     __ b(pl, &positive);
     __ cmp(dividend, Operand::Zero());
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "minus zero");
     __ bind(&positive);
   }
 
@@ -1413,7 +1413,7 @@
     // support because, on ARM, sdiv kMinInt, -1 -> kMinInt.
     __ cmp(dividend, Operand(kMinInt));
     __ cmp(divisor, Operand(-1), eq);
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "overflow");
   }
 
   if (CpuFeatures::IsSupported(SUDIV)) {
@@ -1436,7 +1436,7 @@
     Register remainder = scratch0();
     __ Mls(remainder, result, divisor, dividend);
     __ cmp(remainder, Operand::Zero());
-    DeoptimizeIf(ne, instr);
+    DeoptimizeIf(ne, instr, "lost precision");
   }
 }
 
@@ -1487,13 +1487,13 @@
   // If the divisor is negative, we have to negate and handle edge cases.
   __ rsb(result, dividend, Operand::Zero(), SetCC);
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "minus zero");
   }
 
   // Dividing by -1 is basically negation, unless we overflow.
   if (divisor == -1) {
     if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
-      DeoptimizeIf(vs, instr);
+      DeoptimizeIf(vs, instr, "overflow");
     }
     return;
   }
@@ -1516,7 +1516,7 @@
   DCHECK(!dividend.is(result));
 
   if (divisor == 0) {
-    DeoptimizeIf(al, instr);
+    DeoptimizeIf(al, instr, "division by zero");
     return;
   }
 
@@ -1524,7 +1524,7 @@
   HMathFloorOfDiv* hdiv = instr->hydrogen();
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
     __ cmp(dividend, Operand::Zero());
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "minus zero");
   }
 
   // Easy case: We need no dynamic check for the dividend and the flooring
@@ -1565,7 +1565,7 @@
   // Check for x / 0.
   if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
     __ cmp(right, Operand::Zero());
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "division by zero");
   }
 
   // Check for (0 / -x) that will produce negative zero.
@@ -1577,7 +1577,7 @@
     }
     __ b(pl, &positive);
     __ cmp(left, Operand::Zero());
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "minus zero");
     __ bind(&positive);
   }
 
@@ -1589,7 +1589,7 @@
     // support because, on ARM, sdiv kMinInt, -1 -> kMinInt.
     __ cmp(left, Operand(kMinInt));
     __ cmp(right, Operand(-1), eq);
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "overflow");
   }
 
   if (CpuFeatures::IsSupported(SUDIV)) {
@@ -1635,14 +1635,14 @@
       // The case of a null constant will be handled separately.
       // If constant is negative and left is null, the result should be -0.
       __ cmp(left, Operand::Zero());
-      DeoptimizeIf(eq, instr);
+      DeoptimizeIf(eq, instr, "minus zero");
     }
 
     switch (constant) {
       case -1:
         if (overflow) {
           __ rsb(result, left, Operand::Zero(), SetCC);
-          DeoptimizeIf(vs, instr);
+          DeoptimizeIf(vs, instr, "overflow");
         } else {
           __ rsb(result, left, Operand::Zero());
         }
@@ -1652,7 +1652,7 @@
           // If left is strictly negative and the constant is null, the
           // result is -0. Deoptimize if required, otherwise return 0.
           __ cmp(left, Operand::Zero());
-          DeoptimizeIf(mi, instr);
+          DeoptimizeIf(mi, instr, "minus zero");
         }
         __ mov(result, Operand::Zero());
         break;
@@ -1702,7 +1702,7 @@
         __ smull(result, scratch, left, right);
       }
       __ cmp(scratch, Operand(result, ASR, 31));
-      DeoptimizeIf(ne, instr);
+      DeoptimizeIf(ne, instr, "overflow");
     } else {
       if (instr->hydrogen()->representation().IsSmi()) {
         __ SmiUntag(result, left);
@@ -1718,7 +1718,7 @@
       __ b(pl, &done);
       // Bail out if the result is minus zero.
       __ cmp(result, Operand::Zero());
-      DeoptimizeIf(eq, instr);
+      DeoptimizeIf(eq, instr, "minus zero");
       __ bind(&done);
     }
   }
@@ -1781,7 +1781,7 @@
       case Token::SHR:
         if (instr->can_deopt()) {
           __ mov(result, Operand(left, LSR, scratch), SetCC);
-          DeoptimizeIf(mi, instr);
+          DeoptimizeIf(mi, instr, "negative value");
         } else {
           __ mov(result, Operand(left, LSR, scratch));
         }
@@ -1818,7 +1818,7 @@
         } else {
           if (instr->can_deopt()) {
             __ tst(left, Operand(0x80000000));
-            DeoptimizeIf(ne, instr);
+            DeoptimizeIf(ne, instr, "negative value");
           }
           __ Move(result, left);
         }
@@ -1833,7 +1833,7 @@
             } else {
               __ SmiTag(result, left, SetCC);
             }
-            DeoptimizeIf(vs, instr);
+            DeoptimizeIf(vs, instr, "overflow");
           } else {
             __ mov(result, Operand(left, LSL, shift_count));
           }
@@ -1865,7 +1865,7 @@
   }
 
   if (can_overflow) {
-    DeoptimizeIf(vs, instr);
+    DeoptimizeIf(vs, instr, "overflow");
   }
 }
 
@@ -1886,7 +1886,7 @@
   }
 
   if (can_overflow) {
-    DeoptimizeIf(vs, instr);
+    DeoptimizeIf(vs, instr, "overflow");
   }
 }
 
@@ -1940,9 +1940,9 @@
   DCHECK(!scratch.is(object));
 
   __ SmiTst(object);
-  DeoptimizeIf(eq, instr);
+  DeoptimizeIf(eq, instr, "Smi");
   __ CompareObjectType(object, scratch, scratch, JS_DATE_TYPE);
-  DeoptimizeIf(ne, instr);
+  DeoptimizeIf(ne, instr, "not a date object");
 
   if (index->value() == 0) {
     __ ldr(result, FieldMemOperand(object, JSDate::kValueOffset));
@@ -2059,7 +2059,7 @@
   }
 
   if (can_overflow) {
-    DeoptimizeIf(vs, instr);
+    DeoptimizeIf(vs, instr, "overflow");
   }
 }
 
@@ -2285,7 +2285,7 @@
       } else if (expected.NeedsMap()) {
         // If we need a map later and have a Smi -> deopt.
         __ SmiTst(reg);
-        DeoptimizeIf(eq, instr);
+        DeoptimizeIf(eq, instr, "Smi");
       }
 
       const Register map = scratch0();
@@ -2341,7 +2341,7 @@
       if (!expected.IsGeneric()) {
         // We've seen something for the first time -> deopt.
         // This can only happen if we are not generic already.
-        DeoptimizeIf(al, instr);
+        DeoptimizeIf(al, instr, "unexpected object");
       }
     }
   }
@@ -2785,11 +2785,11 @@
     DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
                                   LInstanceOfKnownGlobal* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_,
                                                  &load_bool_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
     Label* map_check() { return &map_check_; }
     Label* load_bool() { return &load_bool_; }
 
@@ -2964,6 +2964,7 @@
         __ add(sp, sp, Operand(sp_delta));
       }
     } else {
+      DCHECK(info()->IsStub());  // Functions would need to drop one more value.
       Register reg = ToRegister(instr->parameter_count());
       // The argument count parameter is a smi
       __ SmiUntag(reg);
@@ -2986,7 +2987,7 @@
   if (instr->hydrogen()->RequiresHoleCheck()) {
     __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
     __ cmp(result, ip);
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "hole");
   }
 }
 
@@ -2994,13 +2995,18 @@
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
-  Register vector = ToRegister(instr->temp_vector());
-  DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
-  __ Move(vector, instr->hydrogen()->feedback_vector());
+  Register vector_register = ToRegister(instr->temp_vector());
+  Register slot_register = VectorLoadICDescriptor::SlotRegister();
+  DCHECK(vector_register.is(VectorLoadICDescriptor::VectorRegister()));
+  DCHECK(slot_register.is(r0));
+
+  AllowDeferredHandleDereference vector_structure_check;
+  Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+  __ Move(vector_register, vector);
   // No need to allocate this register.
-  DCHECK(VectorLoadICDescriptor::SlotRegister().is(r0));
-  __ mov(VectorLoadICDescriptor::SlotRegister(),
-         Operand(Smi::FromInt(instr->hydrogen()->slot())));
+  FeedbackVectorICSlot slot = instr->hydrogen()->slot();
+  int index = vector->GetIndex(slot);
+  __ mov(slot_register, Operand(Smi::FromInt(index)));
 }
 
 
@@ -3015,7 +3021,7 @@
     EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
   }
   ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), mode).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3036,7 +3042,7 @@
     Register payload = ToRegister(instr->temp());
     __ ldr(payload, FieldMemOperand(cell, Cell::kValueOffset));
     __ CompareRoot(payload, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "hole");
   }
 
   // Store the value.
@@ -3053,7 +3059,7 @@
     __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
     __ cmp(result, ip);
     if (instr->hydrogen()->DeoptimizesOnHole()) {
-      DeoptimizeIf(eq, instr);
+      DeoptimizeIf(eq, instr, "hole");
     } else {
       __ mov(result, Operand(factory()->undefined_value()), LeaveCC, eq);
     }
@@ -3074,7 +3080,7 @@
     __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
     __ cmp(scratch, ip);
     if (instr->hydrogen()->DeoptimizesOnHole()) {
-      DeoptimizeIf(eq, instr);
+      DeoptimizeIf(eq, instr, "hole");
     } else {
       __ b(ne, &skip_assignment);
     }
@@ -3137,7 +3143,8 @@
   if (FLAG_vector_ics) {
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic =
+      CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS);
 }
 
@@ -3154,7 +3161,7 @@
   // Check that the function has a prototype or an initial map.
   __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
   __ cmp(result, ip);
-  DeoptimizeIf(eq, instr);
+  DeoptimizeIf(eq, instr, "hole");
 
   // If the function does not have an initial map, we're done.
   Label done;
@@ -3280,7 +3287,7 @@
         __ ldr(result, mem_operand);
         if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
           __ cmp(result, Operand(0x80000000));
-          DeoptimizeIf(cs, instr);
+          DeoptimizeIf(cs, instr, "negative value");
         }
         break;
       case FLOAT32_ELEMENTS:
@@ -3333,7 +3340,7 @@
   if (instr->hydrogen()->RequiresHoleCheck()) {
     __ ldr(scratch, MemOperand(scratch, sizeof(kHoleNanLower32)));
     __ cmp(scratch, Operand(kHoleNanUpper32));
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "hole");
   }
 }
 
@@ -3367,11 +3374,11 @@
   if (instr->hydrogen()->RequiresHoleCheck()) {
     if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
       __ SmiTst(result);
-      DeoptimizeIf(ne, instr);
+      DeoptimizeIf(ne, instr, "not a Smi");
     } else {
       __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
       __ cmp(result, scratch);
-      DeoptimizeIf(eq, instr);
+      DeoptimizeIf(eq, instr, "hole");
     }
   }
 }
@@ -3428,7 +3435,7 @@
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
+  Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS);
 }
 
@@ -3513,9 +3520,9 @@
 
   // Deoptimize if the receiver is not a JS object.
   __ SmiTst(receiver);
-  DeoptimizeIf(eq, instr);
+  DeoptimizeIf(eq, instr, "Smi");
   __ CompareObjectType(receiver, scratch, scratch, FIRST_SPEC_OBJECT_TYPE);
-  DeoptimizeIf(lt, instr);
+  DeoptimizeIf(lt, instr, "not a JavaScript object");
 
   __ b(&result_in_receiver);
   __ bind(&global_object);
@@ -3550,7 +3557,7 @@
   // adaptor frame below it.
   const uint32_t kArgumentsLimit = 1 * KB;
   __ cmp(length, Operand(kArgumentsLimit));
-  DeoptimizeIf(hi, instr);
+  DeoptimizeIf(hi, instr, "too many arguments");
 
   // Push the receiver and use the register to keep the original
   // number of arguments.
@@ -3680,7 +3687,7 @@
   __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
   __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
   __ cmp(scratch, Operand(ip));
-  DeoptimizeIf(ne, instr);
+  DeoptimizeIf(ne, instr, "not a heap number");
 
   Label done;
   Register exponent = scratch0();
@@ -3748,7 +3755,7 @@
   // if input is positive.
   __ rsb(result, input, Operand::Zero(), SetCC, mi);
   // Deoptimize on overflow.
-  DeoptimizeIf(vs, instr);
+  DeoptimizeIf(vs, instr, "overflow");
 }
 
 
@@ -3758,10 +3765,11 @@
    public:
     DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LMathAbs* instr_;
   };
@@ -3794,7 +3802,7 @@
   Label done, exact;
 
   __ TryInt32Floor(result, input, input_high, double_scratch0(), &done, &exact);
-  DeoptimizeIf(al, instr);
+  DeoptimizeIf(al, instr, "lost precision or NaN");
 
   __ bind(&exact);
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
@@ -3802,7 +3810,7 @@
     __ cmp(result, Operand::Zero());
     __ b(ne, &done);
     __ cmp(input_high, Operand::Zero());
-    DeoptimizeIf(mi, instr);
+    DeoptimizeIf(mi, instr, "minus zero");
   }
   __ bind(&done);
 }
@@ -3827,7 +3835,8 @@
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     __ VmovHigh(input_high, input);
     __ cmp(input_high, Operand::Zero());
-    DeoptimizeIf(mi, instr);  // [-0.5, -0].
+    // [-0.5, -0].
+    DeoptimizeIf(mi, instr, "minus zero");
   }
   __ VFPCompareAndSetFlags(input, dot_five);
   __ mov(result, Operand(1), LeaveCC, eq);  // +0.5.
@@ -3841,7 +3850,7 @@
   // Reuse dot_five (double_scratch0) as we no longer need this value.
   __ TryInt32Floor(result, input_plus_dot_five, input_high, double_scratch0(),
                    &done, &done);
-  DeoptimizeIf(al, instr);
+  DeoptimizeIf(al, instr, "lost precision or NaN");
   __ bind(&done);
 }
 
@@ -3905,7 +3914,7 @@
     __ ldr(r6, FieldMemOperand(tagged_exponent, HeapObject::kMapOffset));
     __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
     __ cmp(r6, Operand(ip));
-    DeoptimizeIf(ne, instr);
+    DeoptimizeIf(ne, instr, "not a heap number");
     __ bind(&no_deopt);
     MathPowStub stub(isolate(), MathPowStub::TAGGED);
     __ CallStub(&stub);
@@ -3979,54 +3988,91 @@
   DCHECK(name.is(LoadDescriptor::NameRegister()));
   DCHECK(receiver.is(r1));
   DCHECK(name.is(r2));
+  Register scratch = r4;
+  Register extra = r5;
+  Register extra2 = r6;
+  Register extra3 = r9;
 
-  Register scratch = r3;
-  Register extra = r4;
-  Register extra2 = r5;
-  Register extra3 = r6;
+#ifdef DEBUG
+  Register slot = FLAG_vector_ics ? ToRegister(instr->slot()) : no_reg;
+  Register vector = FLAG_vector_ics ? ToRegister(instr->vector()) : no_reg;
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(slot, vector, scratch, extra, extra2, extra3));
+#endif
 
   // Important for the tail-call.
   bool must_teardown_frame = NeedsEagerFrame();
 
-  // The probe will tail call to a handler if found.
-  isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
-                                         must_teardown_frame, receiver, name,
-                                         scratch, extra, extra2, extra3);
+  if (!instr->hydrogen()->is_just_miss()) {
+    DCHECK(!instr->hydrogen()->is_keyed_load());
+
+    // The probe will tail call to a handler if found.
+    isolate()->stub_cache()->GenerateProbe(
+        masm(), Code::LOAD_IC, instr->hydrogen()->flags(), must_teardown_frame,
+        receiver, name, scratch, extra, extra2, extra3);
+  }
 
   // Tail call to miss if we ended up here.
   if (must_teardown_frame) __ LeaveFrame(StackFrame::INTERNAL);
-  LoadIC::GenerateMiss(masm());
+  if (instr->hydrogen()->is_keyed_load()) {
+    KeyedLoadIC::GenerateMiss(masm());
+  } else {
+    LoadIC::GenerateMiss(masm());
+  }
 }
 
 
 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
   DCHECK(ToRegister(instr->result()).is(r0));
 
-  LPointerMap* pointers = instr->pointer_map();
-  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+  if (instr->hydrogen()->IsTailCall()) {
+    if (NeedsEagerFrame()) __ LeaveFrame(StackFrame::INTERNAL);
 
-  if (instr->target()->IsConstantOperand()) {
-    LConstantOperand* target = LConstantOperand::cast(instr->target());
-    Handle<Code> code = Handle<Code>::cast(ToHandle(target));
-    generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
-    PlatformInterfaceDescriptor* call_descriptor =
-        instr->descriptor().platform_specific_descriptor();
-    __ Call(code, RelocInfo::CODE_TARGET, TypeFeedbackId::None(), al,
-            call_descriptor->storage_mode());
-  } else {
-    DCHECK(instr->target()->IsRegister());
-    Register target = ToRegister(instr->target());
-    generator.BeforeCall(__ CallSize(target));
-    // Make sure we don't emit any additional entries in the constant pool
-    // before the call to ensure that the CallCodeSize() calculated the correct
-    // number of instructions for the constant pool load.
-    {
-      ConstantPoolUnavailableScope constant_pool_unavailable(masm_);
-      __ add(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
+    if (instr->target()->IsConstantOperand()) {
+      LConstantOperand* target = LConstantOperand::cast(instr->target());
+      Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+      __ Jump(code, RelocInfo::CODE_TARGET);
+    } else {
+      DCHECK(instr->target()->IsRegister());
+      Register target = ToRegister(instr->target());
+      // Make sure we don't emit any additional entries in the constant pool
+      // before the call to ensure that the CallCodeSize() calculated the
+      // correct
+      // number of instructions for the constant pool load.
+      {
+        ConstantPoolUnavailableScope constant_pool_unavailable(masm_);
+        __ add(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
+      }
+      __ Jump(target);
     }
-    __ Call(target);
+  } else {
+    LPointerMap* pointers = instr->pointer_map();
+    SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+
+    if (instr->target()->IsConstantOperand()) {
+      LConstantOperand* target = LConstantOperand::cast(instr->target());
+      Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+      generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
+      PlatformInterfaceDescriptor* call_descriptor =
+          instr->descriptor().platform_specific_descriptor();
+      __ Call(code, RelocInfo::CODE_TARGET, TypeFeedbackId::None(), al,
+              call_descriptor->storage_mode());
+    } else {
+      DCHECK(instr->target()->IsRegister());
+      Register target = ToRegister(instr->target());
+      generator.BeforeCall(__ CallSize(target));
+      // Make sure we don't emit any additional entries in the constant pool
+      // before the call to ensure that the CallCodeSize() calculated the
+      // correct
+      // number of instructions for the constant pool load.
+      {
+        ConstantPoolUnavailableScope constant_pool_unavailable(masm_);
+        __ add(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
+      }
+      __ Call(target);
+    }
+    generator.AfterCall();
   }
-  generator.AfterCall();
 }
 
 
@@ -4257,7 +4303,7 @@
     __ stop("eliminated bounds check failed");
     __ bind(&done);
   } else {
-    DeoptimizeIf(cc, instr);
+    DeoptimizeIf(cc, instr, "out of bounds");
   }
 }
 
@@ -4505,7 +4551,7 @@
   Register temp = ToRegister(instr->temp());
   Label no_memento_found;
   __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found);
-  DeoptimizeIf(eq, instr);
+  DeoptimizeIf(eq, instr, "memento found");
   __ bind(&no_memento_found);
 }
 
@@ -4526,10 +4572,9 @@
    public:
     DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredStringCharCodeAt(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredStringCharCodeAt(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStringCharCodeAt* instr_;
   };
@@ -4582,10 +4627,11 @@
    public:
     DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredStringCharFromCode(instr_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStringCharFromCode* instr_;
   };
@@ -4659,14 +4705,15 @@
    public:
     DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredNumberTagIU(instr_,
                                        instr_->value(),
                                        instr_->temp1(),
                                        instr_->temp2(),
                                        SIGNED_INT32);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagI* instr_;
   };
@@ -4686,14 +4733,15 @@
    public:
     DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredNumberTagIU(instr_,
                                        instr_->value(),
                                        instr_->temp1(),
                                        instr_->temp2(),
                                        UNSIGNED_INT32);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagU* instr_;
   };
@@ -4780,10 +4828,9 @@
    public:
     DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredNumberTagD(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredNumberTagD(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagD* instr_;
   };
@@ -4839,12 +4886,12 @@
   if (hchange->CheckFlag(HValue::kCanOverflow) &&
       hchange->value()->CheckFlag(HValue::kUint32)) {
     __ tst(input, Operand(0xc0000000));
-    DeoptimizeIf(ne, instr);
+    DeoptimizeIf(ne, instr, "overflow");
   }
   if (hchange->CheckFlag(HValue::kCanOverflow) &&
       !hchange->value()->CheckFlag(HValue::kUint32)) {
     __ SmiTag(output, input, SetCC);
-    DeoptimizeIf(vs, instr);
+    DeoptimizeIf(vs, instr, "overflow");
   } else {
     __ SmiTag(output, input);
   }
@@ -4858,7 +4905,7 @@
     STATIC_ASSERT(kHeapObjectTag == 1);
     // If the input is a HeapObject, SmiUntag will set the carry flag.
     __ SmiUntag(result, input, SetCC);
-    DeoptimizeIf(cs, instr);
+    DeoptimizeIf(cs, instr, "not a Smi");
   } else {
     __ SmiUntag(result, input);
   }
@@ -4886,7 +4933,7 @@
     if (can_convert_undefined_to_nan) {
       __ b(ne, &convert);
     } else {
-      DeoptimizeIf(ne, instr);
+      DeoptimizeIf(ne, instr, "not a heap number");
     }
     // load heap number
     __ vldr(result_reg, input_reg, HeapNumber::kValueOffset - kHeapObjectTag);
@@ -4896,7 +4943,7 @@
       __ b(ne, &done);
       __ VmovHigh(scratch, result_reg);
       __ cmp(scratch, Operand(HeapNumber::kSignMask));
-      DeoptimizeIf(eq, instr);
+      DeoptimizeIf(eq, instr, "minus zero");
     }
     __ jmp(&done);
     if (can_convert_undefined_to_nan) {
@@ -4904,7 +4951,7 @@
       // Convert undefined (and hole) to NaN.
       __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
       __ cmp(input_reg, Operand(ip));
-      DeoptimizeIf(ne, instr);
+      DeoptimizeIf(ne, instr, "not a heap number/undefined");
       __ LoadRoot(scratch, Heap::kNanValueRootIndex);
       __ vldr(result_reg, scratch, HeapNumber::kValueOffset - kHeapObjectTag);
       __ jmp(&done);
@@ -4972,7 +5019,7 @@
     __ bind(&check_false);
     __ LoadRoot(ip, Heap::kFalseValueRootIndex);
     __ cmp(scratch2, Operand(ip));
-    DeoptimizeIf(ne, instr, "cannot truncate");
+    DeoptimizeIf(ne, instr, "not a heap number/undefined/true/false");
     __ mov(input_reg, Operand::Zero());
   } else {
     DeoptimizeIf(ne, instr, "not a heap number");
@@ -4999,10 +5046,9 @@
    public:
     DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredTaggedToI(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredTaggedToI(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LTaggedToI* instr_;
   };
@@ -5057,14 +5103,14 @@
   } else {
     __ TryDoubleToInt32Exact(result_reg, double_input, double_scratch);
     // Deoptimize if the input wasn't a int32 (inside a double).
-    DeoptimizeIf(ne, instr);
+    DeoptimizeIf(ne, instr, "lost precision or NaN");
     if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
       Label done;
       __ cmp(result_reg, Operand::Zero());
       __ b(ne, &done);
       __ VmovHigh(scratch1, double_input);
       __ tst(scratch1, Operand(HeapNumber::kSignMask));
-      DeoptimizeIf(ne, instr);
+      DeoptimizeIf(ne, instr, "minus zero");
       __ bind(&done);
     }
   }
@@ -5082,26 +5128,26 @@
   } else {
     __ TryDoubleToInt32Exact(result_reg, double_input, double_scratch);
     // Deoptimize if the input wasn't a int32 (inside a double).
-    DeoptimizeIf(ne, instr);
+    DeoptimizeIf(ne, instr, "lost precision or NaN");
     if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
       Label done;
       __ cmp(result_reg, Operand::Zero());
       __ b(ne, &done);
       __ VmovHigh(scratch1, double_input);
       __ tst(scratch1, Operand(HeapNumber::kSignMask));
-      DeoptimizeIf(ne, instr);
+      DeoptimizeIf(ne, instr, "minus zero");
       __ bind(&done);
     }
   }
   __ SmiTag(result_reg, SetCC);
-  DeoptimizeIf(vs, instr);
+  DeoptimizeIf(vs, instr, "overflow");
 }
 
 
 void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
   LOperand* input = instr->value();
   __ SmiTst(ToRegister(input));
-  DeoptimizeIf(ne, instr);
+  DeoptimizeIf(ne, instr, "not a Smi");
 }
 
 
@@ -5109,7 +5155,7 @@
   if (!instr->hydrogen()->value()->type().IsHeapObject()) {
     LOperand* input = instr->value();
     __ SmiTst(ToRegister(input));
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "Smi");
   }
 }
 
@@ -5130,13 +5176,13 @@
 
     // If there is only one type in the interval check for equality.
     if (first == last) {
-      DeoptimizeIf(ne, instr);
+      DeoptimizeIf(ne, instr, "wrong instance type");
     } else {
-      DeoptimizeIf(lo, instr);
+      DeoptimizeIf(lo, instr, "wrong instance type");
       // Omit check for the last type.
       if (last != LAST_TYPE) {
         __ cmp(scratch, Operand(last));
-        DeoptimizeIf(hi, instr);
+        DeoptimizeIf(hi, instr, "wrong instance type");
       }
     }
   } else {
@@ -5147,11 +5193,11 @@
     if (base::bits::IsPowerOfTwo32(mask)) {
       DCHECK(tag == 0 || base::bits::IsPowerOfTwo32(tag));
       __ tst(scratch, Operand(mask));
-      DeoptimizeIf(tag == 0 ? ne : eq, instr);
+      DeoptimizeIf(tag == 0 ? ne : eq, instr, "wrong instance type");
     } else {
       __ and_(scratch, scratch, Operand(mask));
       __ cmp(scratch, Operand(tag));
-      DeoptimizeIf(ne, instr);
+      DeoptimizeIf(ne, instr, "wrong instance type");
     }
   }
 }
@@ -5170,7 +5216,7 @@
   } else {
     __ cmp(reg, Operand(object));
   }
-  DeoptimizeIf(ne, instr);
+  DeoptimizeIf(ne, instr, "value mismatch");
 }
 
 
@@ -5185,7 +5231,7 @@
     __ StoreToSafepointRegisterSlot(r0, scratch0());
   }
   __ tst(scratch0(), Operand(kSmiTagMask));
-  DeoptimizeIf(eq, instr);
+  DeoptimizeIf(eq, instr, "instance migration failed");
 }
 
 
@@ -5196,11 +5242,12 @@
         : LDeferredCode(codegen), instr_(instr), object_(object) {
       SetExit(check_maps());
     }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredInstanceMigration(instr_, object_);
     }
     Label* check_maps() { return &check_maps_; }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LCheckMaps* instr_;
     Label check_maps_;
@@ -5242,7 +5289,7 @@
   if (instr->hydrogen()->HasMigrationTarget()) {
     __ b(ne, deferred->entry());
   } else {
-    DeoptimizeIf(ne, instr);
+    DeoptimizeIf(ne, instr, "wrong map");
   }
 
   __ bind(&success);
@@ -5281,7 +5328,7 @@
   // Check for undefined. Undefined is converted to zero for clamping
   // conversions.
   __ cmp(input_reg, Operand(factory()->undefined_value()));
-  DeoptimizeIf(ne, instr);
+  DeoptimizeIf(ne, instr, "not a heap number/undefined");
   __ mov(result_reg, Operand::Zero());
   __ jmp(&done);
 
@@ -5324,10 +5371,9 @@
    public:
     DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredAllocate(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredAllocate(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LAllocate* instr_;
   };
@@ -5689,10 +5735,9 @@
    public:
     DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredStackCheck(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredStackCheck(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStackCheck* instr_;
   };
@@ -5751,19 +5796,19 @@
 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
   __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
   __ cmp(r0, ip);
-  DeoptimizeIf(eq, instr);
+  DeoptimizeIf(eq, instr, "undefined");
 
   Register null_value = r5;
   __ LoadRoot(null_value, Heap::kNullValueRootIndex);
   __ cmp(r0, null_value);
-  DeoptimizeIf(eq, instr);
+  DeoptimizeIf(eq, instr, "null");
 
   __ SmiTst(r0);
-  DeoptimizeIf(eq, instr);
+  DeoptimizeIf(eq, instr, "Smi");
 
   STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
   __ CompareObjectType(r0, r1, r1, LAST_JS_PROXY_TYPE);
-  DeoptimizeIf(le, instr);
+  DeoptimizeIf(le, instr, "wrong instance type");
 
   Label use_cache, call_runtime;
   __ CheckEnumCache(null_value, &call_runtime);
@@ -5779,7 +5824,7 @@
   __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
   __ LoadRoot(ip, Heap::kMetaMapRootIndex);
   __ cmp(r1, ip);
-  DeoptimizeIf(ne, instr);
+  DeoptimizeIf(ne, instr, "wrong map");
   __ bind(&use_cache);
 }
 
@@ -5801,7 +5846,7 @@
   __ ldr(result,
          FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
   __ cmp(result, Operand::Zero());
-  DeoptimizeIf(eq, instr);
+  DeoptimizeIf(eq, instr, "no cache");
 
   __ bind(&done);
 }
@@ -5812,7 +5857,7 @@
   Register map = ToRegister(instr->map());
   __ ldr(scratch0(), FieldMemOperand(object, HeapObject::kMapOffset));
   __ cmp(map, scratch0());
-  DeoptimizeIf(ne, instr);
+  DeoptimizeIf(ne, instr, "wrong map");
 }
 
 
@@ -5845,10 +5890,11 @@
           object_(object),
           index_(index) {
     }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredLoadMutableDouble(instr_, result_, object_, index_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LLoadFieldByIndex* instr_;
     Register result_;
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index cb137d1..65cc213 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -237,7 +237,7 @@
   void DeoptimizeIf(Condition condition, LInstruction* instr,
                     const char* detail, Deoptimizer::BailoutType bailout_type);
   void DeoptimizeIf(Condition condition, LInstruction* instr,
-                    const char* detail = NULL);
+                    const char* detail);
 
   void AddToTranslation(LEnvironment* environment,
                         Translation* translation,
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index c845a3d..0aa886b 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -15,7 +15,7 @@
 #include "src/cpu-profiler.h"
 #include "src/debug.h"
 #include "src/isolate-inl.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -967,7 +967,7 @@
   add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
   if (FLAG_enable_ool_constant_pool) {
     LoadConstantPoolPointerRegister();
-    set_constant_pool_available(true);
+    set_ool_constant_pool_available(true);
   }
 }
 
@@ -992,16 +992,16 @@
   }
   if (FLAG_enable_ool_constant_pool) {
     LoadConstantPoolPointerRegister();
-    set_constant_pool_available(true);
+    set_ool_constant_pool_available(true);
   }
 }
 
 
 void MacroAssembler::EnterFrame(StackFrame::Type type,
-                                bool load_constant_pool) {
+                                bool load_constant_pool_pointer_reg) {
   // r0-r3: preserved
   PushFixedFrame();
-  if (FLAG_enable_ool_constant_pool && load_constant_pool) {
+  if (FLAG_enable_ool_constant_pool && load_constant_pool_pointer_reg) {
     LoadConstantPoolPointerRegister();
   }
   mov(ip, Operand(Smi::FromInt(type)));
@@ -1699,11 +1699,12 @@
   }
 
   bind(&done);
-  // Check that the value is a normal property.
+  // Check that the value is a field property.
   // t2: elements + (index * kPointerSize)
   const int kDetailsOffset =
       SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
   ldr(t1, FieldMemOperand(t2, kDetailsOffset));
+  DCHECK_EQ(FIELD, 0);
   tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
   b(ne, miss);
 
@@ -2251,23 +2252,37 @@
 }
 
 
-void MacroAssembler::DispatchMap(Register obj,
-                                 Register scratch,
-                                 Handle<Map> map,
-                                 Handle<Code> success,
-                                 SmiCheckType smi_check_type) {
+void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
+                                     Register scratch2, Handle<WeakCell> cell,
+                                     Handle<Code> success,
+                                     SmiCheckType smi_check_type) {
   Label fail;
   if (smi_check_type == DO_SMI_CHECK) {
     JumpIfSmi(obj, &fail);
   }
-  ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
-  mov(ip, Operand(map));
-  cmp(scratch, ip);
+  ldr(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset));
+  CmpWeakValue(scratch1, cell, scratch2);
   Jump(success, RelocInfo::CODE_TARGET, eq);
   bind(&fail);
 }
 
 
+void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
+                                  Register scratch) {
+  mov(scratch, Operand(cell));
+  ldr(scratch, FieldMemOperand(scratch, WeakCell::kValueOffset));
+  cmp(value, scratch);
+}
+
+
+void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
+                                   Label* miss) {
+  mov(value, Operand(cell));
+  ldr(value, FieldMemOperand(value, WeakCell::kValueOffset));
+  JumpIfSmi(value, miss);
+}
+
+
 void MacroAssembler::TryGetFunctionPrototype(Register function,
                                              Register result,
                                              Register scratch,
@@ -3653,18 +3668,6 @@
 }
 
 
-void MacroAssembler::CheckMapDeprecated(Handle<Map> map,
-                                        Register scratch,
-                                        Label* if_deprecated) {
-  if (map->CanBeDeprecated()) {
-    mov(scratch, Operand(map));
-    ldr(scratch, FieldMemOperand(scratch, Map::kBitField3Offset));
-    tst(scratch, Operand(Map::Deprecated::kMask));
-    b(ne, if_deprecated);
-  }
-}
-
-
 void MacroAssembler::JumpIfBlack(Register object,
                                  Register scratch0,
                                  Register scratch1,
@@ -4071,21 +4074,22 @@
   DCHECK(!dividend.is(ip));
   DCHECK(!result.is(ip));
   base::MagicNumbersForDivision<uint32_t> mag =
-      base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
+      base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
   mov(ip, Operand(mag.multiplier));
-  smull(ip, result, dividend, ip);
-  bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
+  bool neg = (mag.multiplier & (1U << 31)) != 0;
   if (divisor > 0 && neg) {
-    add(result, result, Operand(dividend));
-  }
-  if (divisor < 0 && !neg && mag.multiplier > 0) {
-    sub(result, result, Operand(dividend));
+    smmla(result, dividend, ip, dividend);
+  } else {
+    smmul(result, dividend, ip);
+    if (divisor < 0 && !neg && mag.multiplier > 0) {
+      sub(result, result, Operand(dividend));
+    }
   }
   if (mag.shift > 0) mov(result, Operand(result, ASR, mag.shift));
   add(result, result, Operand(dividend, LSR, 31));
 }
 
-
-} }  // namespace v8::internal
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_TARGET_ARCH_ARM
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index d2a1786..d83b64b 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -200,10 +200,6 @@
                      Condition cc,
                      Label* condition_met);
 
-  void CheckMapDeprecated(Handle<Map> map,
-                          Register scratch,
-                          Label* if_deprecated);
-
   // Check if object is in new space.  Jumps if the object is not in new space.
   // The register scratch can be object itself, but scratch will be clobbered.
   void JumpIfNotInNewSpace(Register object,
@@ -918,15 +914,19 @@
                 SmiCheckType smi_check_type);
 
 
-  // Check if the map of an object is equal to a specified map and branch to a
-  // specified target if equal. Skip the smi check if not required (object is
-  // known to be a heap object)
-  void DispatchMap(Register obj,
-                   Register scratch,
-                   Handle<Map> map,
-                   Handle<Code> success,
-                   SmiCheckType smi_check_type);
+  // Check if the map of an object is equal to a specified weak map and branch
+  // to a specified target if equal. Skip the smi check if not required
+  // (object is known to be a heap object)
+  void DispatchWeakMap(Register obj, Register scratch1, Register scratch2,
+                       Handle<WeakCell> cell, Handle<Code> success,
+                       SmiCheckType smi_check_type);
 
+  // Compare the given value and the value of weak cell.
+  void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
+
+  // Load the value of the weak cell in the value register. Branch to the given
+  // miss label if the weak cell was cleared.
+  void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
 
   // Compare the object in a register to a value from the root list.
   // Uses the ip register as scratch.
@@ -1401,7 +1401,8 @@
   }
 
   // Activation support.
-  void EnterFrame(StackFrame::Type type, bool load_constant_pool = false);
+  void EnterFrame(StackFrame::Type type,
+                  bool load_constant_pool_pointer_reg = false);
   // Returns the pc offset at which the frame ends.
   int LeaveFrame(StackFrame::Type type);
 
@@ -1530,71 +1531,6 @@
 };
 
 
-class FrameAndConstantPoolScope {
- public:
-  FrameAndConstantPoolScope(MacroAssembler* masm, StackFrame::Type type)
-      : masm_(masm),
-        type_(type),
-        old_has_frame_(masm->has_frame()),
-        old_constant_pool_available_(masm->is_constant_pool_available())  {
-    // We only want to enable constant pool access for non-manual frame scopes
-    // to ensure the constant pool pointer is valid throughout the scope.
-    DCHECK(type_ != StackFrame::MANUAL && type_ != StackFrame::NONE);
-    masm->set_has_frame(true);
-    masm->set_constant_pool_available(true);
-    masm->EnterFrame(type, !old_constant_pool_available_);
-  }
-
-  ~FrameAndConstantPoolScope() {
-    masm_->LeaveFrame(type_);
-    masm_->set_has_frame(old_has_frame_);
-    masm_->set_constant_pool_available(old_constant_pool_available_);
-  }
-
-  // Normally we generate the leave-frame code when this object goes
-  // out of scope.  Sometimes we may need to generate the code somewhere else
-  // in addition.  Calling this will achieve that, but the object stays in
-  // scope, the MacroAssembler is still marked as being in a frame scope, and
-  // the code will be generated again when it goes out of scope.
-  void GenerateLeaveFrame() {
-    DCHECK(type_ != StackFrame::MANUAL && type_ != StackFrame::NONE);
-    masm_->LeaveFrame(type_);
-  }
-
- private:
-  MacroAssembler* masm_;
-  StackFrame::Type type_;
-  bool old_has_frame_;
-  bool old_constant_pool_available_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(FrameAndConstantPoolScope);
-};
-
-
-// Class for scoping the the unavailability of constant pool access.
-class ConstantPoolUnavailableScope {
- public:
-  explicit ConstantPoolUnavailableScope(MacroAssembler* masm)
-     : masm_(masm),
-       old_constant_pool_available_(masm->is_constant_pool_available()) {
-    if (FLAG_enable_ool_constant_pool) {
-      masm_->set_constant_pool_available(false);
-    }
-  }
-  ~ConstantPoolUnavailableScope() {
-    if (FLAG_enable_ool_constant_pool) {
-     masm_->set_constant_pool_available(old_constant_pool_available_);
-    }
-  }
-
- private:
-  MacroAssembler* masm_;
-  int old_constant_pool_available_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ConstantPoolUnavailableScope);
-};
-
-
 // -----------------------------------------------------------------------------
 // Static helper functions.
 
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
index 0444025..e34c311 100644
--- a/src/arm/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -2629,7 +2629,89 @@
               UNIMPLEMENTED();
               break;
             case 1:
-              UNIMPLEMENTED();
+              if (instr->Bits(9, 6) == 1) {
+                if (instr->Bit(20) == 0) {
+                  if (instr->Bits(19, 16) == 0xF) {
+                    // Sxtb.
+                    int32_t rm_val = get_register(instr->RmValue());
+                    int32_t rotate = instr->Bits(11, 10);
+                    switch (rotate) {
+                      case 0:
+                        break;
+                      case 1:
+                        rm_val = (rm_val >> 8) | (rm_val << 24);
+                        break;
+                      case 2:
+                        rm_val = (rm_val >> 16) | (rm_val << 16);
+                        break;
+                      case 3:
+                        rm_val = (rm_val >> 24) | (rm_val << 8);
+                        break;
+                    }
+                    set_register(rd, static_cast<int8_t>(rm_val));
+                  } else {
+                    // Sxtab.
+                    int32_t rn_val = get_register(rn);
+                    int32_t rm_val = get_register(instr->RmValue());
+                    int32_t rotate = instr->Bits(11, 10);
+                    switch (rotate) {
+                      case 0:
+                        break;
+                      case 1:
+                        rm_val = (rm_val >> 8) | (rm_val << 24);
+                        break;
+                      case 2:
+                        rm_val = (rm_val >> 16) | (rm_val << 16);
+                        break;
+                      case 3:
+                        rm_val = (rm_val >> 24) | (rm_val << 8);
+                        break;
+                    }
+                    set_register(rd, rn_val + static_cast<int8_t>(rm_val));
+                  }
+                } else {
+                  if (instr->Bits(19, 16) == 0xF) {
+                    // Sxth.
+                    int32_t rm_val = get_register(instr->RmValue());
+                    int32_t rotate = instr->Bits(11, 10);
+                    switch (rotate) {
+                      case 0:
+                        break;
+                      case 1:
+                        rm_val = (rm_val >> 8) | (rm_val << 24);
+                        break;
+                      case 2:
+                        rm_val = (rm_val >> 16) | (rm_val << 16);
+                        break;
+                      case 3:
+                        rm_val = (rm_val >> 24) | (rm_val << 8);
+                        break;
+                    }
+                    set_register(rd, static_cast<int16_t>(rm_val));
+                  } else {
+                    // Sxtah.
+                    int32_t rn_val = get_register(rn);
+                    int32_t rm_val = get_register(instr->RmValue());
+                    int32_t rotate = instr->Bits(11, 10);
+                    switch (rotate) {
+                      case 0:
+                        break;
+                      case 1:
+                        rm_val = (rm_val >> 8) | (rm_val << 24);
+                        break;
+                      case 2:
+                        rm_val = (rm_val >> 16) | (rm_val << 16);
+                        break;
+                      case 3:
+                        rm_val = (rm_val >> 24) | (rm_val << 8);
+                        break;
+                    }
+                    set_register(rd, rn_val + static_cast<int16_t>(rm_val));
+                  }
+                }
+              } else {
+                UNREACHABLE();
+              }
               break;
             case 2:
               if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
@@ -2650,8 +2732,7 @@
                       rm_val = (rm_val >> 24) | (rm_val << 8);
                       break;
                   }
-                  set_register(rd,
-                               (rm_val & 0xFF) | (rm_val & 0xFF0000));
+                  set_register(rd, (rm_val & 0xFF) | (rm_val & 0xFF0000));
                 } else {
                   UNIMPLEMENTED();
                 }
@@ -2660,44 +2741,85 @@
               }
               break;
             case 3:
-              if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
-                if (instr->Bits(19, 16) == 0xF) {
-                  // Uxtb.
-                  uint32_t rm_val = get_register(instr->RmValue());
-                  int32_t rotate = instr->Bits(11, 10);
-                  switch (rotate) {
-                    case 0:
-                      break;
-                    case 1:
-                      rm_val = (rm_val >> 8) | (rm_val << 24);
-                      break;
-                    case 2:
-                      rm_val = (rm_val >> 16) | (rm_val << 16);
-                      break;
-                    case 3:
-                      rm_val = (rm_val >> 24) | (rm_val << 8);
-                      break;
+              if ((instr->Bits(9, 6) == 1)) {
+                if (instr->Bit(20) == 0) {
+                  if (instr->Bits(19, 16) == 0xF) {
+                    // Uxtb.
+                    uint32_t rm_val = get_register(instr->RmValue());
+                    int32_t rotate = instr->Bits(11, 10);
+                    switch (rotate) {
+                      case 0:
+                        break;
+                      case 1:
+                        rm_val = (rm_val >> 8) | (rm_val << 24);
+                        break;
+                      case 2:
+                        rm_val = (rm_val >> 16) | (rm_val << 16);
+                        break;
+                      case 3:
+                        rm_val = (rm_val >> 24) | (rm_val << 8);
+                        break;
+                    }
+                    set_register(rd, (rm_val & 0xFF));
+                  } else {
+                    // Uxtab.
+                    uint32_t rn_val = get_register(rn);
+                    uint32_t rm_val = get_register(instr->RmValue());
+                    int32_t rotate = instr->Bits(11, 10);
+                    switch (rotate) {
+                      case 0:
+                        break;
+                      case 1:
+                        rm_val = (rm_val >> 8) | (rm_val << 24);
+                        break;
+                      case 2:
+                        rm_val = (rm_val >> 16) | (rm_val << 16);
+                        break;
+                      case 3:
+                        rm_val = (rm_val >> 24) | (rm_val << 8);
+                        break;
+                    }
+                    set_register(rd, rn_val + (rm_val & 0xFF));
                   }
-                  set_register(rd, (rm_val & 0xFF));
                 } else {
-                  // Uxtab.
-                  uint32_t rn_val = get_register(rn);
-                  uint32_t rm_val = get_register(instr->RmValue());
-                  int32_t rotate = instr->Bits(11, 10);
-                  switch (rotate) {
-                    case 0:
-                      break;
-                    case 1:
-                      rm_val = (rm_val >> 8) | (rm_val << 24);
-                      break;
-                    case 2:
-                      rm_val = (rm_val >> 16) | (rm_val << 16);
-                      break;
-                    case 3:
-                      rm_val = (rm_val >> 24) | (rm_val << 8);
-                      break;
+                  if (instr->Bits(19, 16) == 0xF) {
+                    // Uxth.
+                    uint32_t rm_val = get_register(instr->RmValue());
+                    int32_t rotate = instr->Bits(11, 10);
+                    switch (rotate) {
+                      case 0:
+                        break;
+                      case 1:
+                        rm_val = (rm_val >> 8) | (rm_val << 24);
+                        break;
+                      case 2:
+                        rm_val = (rm_val >> 16) | (rm_val << 16);
+                        break;
+                      case 3:
+                        rm_val = (rm_val >> 24) | (rm_val << 8);
+                        break;
+                    }
+                    set_register(rd, (rm_val & 0xFFFF));
+                  } else {
+                    // Uxtah.
+                    uint32_t rn_val = get_register(rn);
+                    uint32_t rm_val = get_register(instr->RmValue());
+                    int32_t rotate = instr->Bits(11, 10);
+                    switch (rotate) {
+                      case 0:
+                        break;
+                      case 1:
+                        rm_val = (rm_val >> 8) | (rm_val << 24);
+                        break;
+                      case 2:
+                        rm_val = (rm_val >> 16) | (rm_val << 16);
+                        break;
+                      case 3:
+                        rm_val = (rm_val >> 24) | (rm_val << 8);
+                        break;
+                    }
+                    set_register(rd, rn_val + (rm_val & 0xFFFF));
                   }
-                  set_register(rd, rn_val + (rm_val & 0xFF));
                 }
               } else {
                 UNIMPLEMENTED();
@@ -2710,6 +2832,27 @@
       break;
     }
     case db_x: {
+      if (instr->Bits(22, 20) == 0x5) {
+        if (instr->Bits(7, 4) == 0x1) {
+          int rm = instr->RmValue();
+          int32_t rm_val = get_register(rm);
+          int rs = instr->RsValue();
+          int32_t rs_val = get_register(rs);
+          if (instr->Bits(15, 12) == 0xF) {
+            // SMMUL (in V8 notation matching ARM ISA format)
+            // Format(instr, "smmul'cond 'rn, 'rm, 'rs");
+            rn_val = base::bits::SignedMulHigh32(rm_val, rs_val);
+          } else {
+            // SMMLA (in V8 notation matching ARM ISA format)
+            // Format(instr, "smmla'cond 'rn, 'rm, 'rs, 'rd");
+            int rd = instr->RdValue();
+            int32_t rd_val = get_register(rd);
+            rn_val = base::bits::SignedMulHighAndAdd32(rm_val, rs_val, rd_val);
+          }
+          set_register(rn, rn_val);
+          return;
+        }
+      }
       if (FLAG_enable_sudiv) {
         if (instr->Bits(5, 4) == 0x1) {
           if ((instr->Bit(22) == 0x0) && (instr->Bit(20) == 0x1)) {
@@ -2720,15 +2863,12 @@
             int rs = instr->RsValue();
             int32_t rs_val = get_register(rs);
             int32_t ret_val = 0;
-            DCHECK(rs_val != 0);
             // udiv
             if (instr->Bit(21) == 0x1) {
-              ret_val = static_cast<int32_t>(static_cast<uint32_t>(rm_val) /
-                                             static_cast<uint32_t>(rs_val));
-            } else if ((rm_val == kMinInt) && (rs_val == -1)) {
-              ret_val = kMinInt;
+              ret_val = bit_cast<int32_t>(base::bits::UnsignedDiv32(
+                  bit_cast<uint32_t>(rm_val), bit_cast<uint32_t>(rs_val)));
             } else {
-              ret_val = rm_val / rs_val;
+              ret_val = base::bits::SignedDiv32(rm_val, rs_val);
             }
             set_register(rn, ret_val);
             return;
@@ -2939,6 +3079,12 @@
         } else {
           UNREACHABLE();  // Not used by v8.
         }
+      } else if (((instr->Opc2Value() == 0x6)) && (instr->Opc3Value() == 0x3)) {
+        // vrintz - truncate
+        double dm_value = get_double_from_d_register(vm);
+        double dd_value = trunc(dm_value);
+        dd_value = canonicalizeNaN(dd_value);
+        set_d_register_from_double(vd, dd_value);
       } else {
         UNREACHABLE();  // Not used by V8.
       }
@@ -3589,6 +3735,50 @@
         UNIMPLEMENTED();
       }
       break;
+    case 0x1D:
+      if (instr->Opc1Value() == 0x7 && instr->Opc3Value() == 0x1 &&
+          instr->Bits(11, 9) == 0x5 && instr->Bits(19, 18) == 0x2 &&
+          instr->Bit(8) == 0x1) {
+        int vm = instr->VFPMRegValue(kDoublePrecision);
+        int vd = instr->VFPDRegValue(kDoublePrecision);
+        double dm_value = get_double_from_d_register(vm);
+        double dd_value = 0.0;
+        int rounding_mode = instr->Bits(17, 16);
+        switch (rounding_mode) {
+          case 0x0:  // vrinta - round with ties to away from zero
+            dd_value = round(dm_value);
+            break;
+          case 0x1: {  // vrintn - round with ties to even
+            dd_value = std::floor(dm_value);
+            double error = dm_value - dd_value;
+            // Take care of correctly handling the range [-0.5, -0.0], which
+            // must yield -0.0.
+            if ((-0.5 <= dm_value) && (dm_value < 0.0)) {
+              dd_value = -0.0;
+              // If the error is greater than 0.5, or is equal to 0.5 and the
+              // integer result is odd, round up.
+            } else if ((error > 0.5) ||
+                       ((error == 0.5) && (fmod(dd_value, 2) != 0))) {
+              dd_value++;
+            }
+            break;
+          }
+          case 0x2:  // vrintp - ceil
+            dd_value = std::ceil(dm_value);
+            break;
+          case 0x3:  // vrintm - floor
+            dd_value = std::floor(dm_value);
+            break;
+          default:
+            UNREACHABLE();  // Case analysis is exhaustive.
+            break;
+        }
+        dd_value = canonicalizeNaN(dd_value);
+        set_d_register_from_double(vd, dd_value);
+      } else {
+        UNIMPLEMENTED();
+      }
+      break;
     default:
       UNIMPLEMENTED();
       break;
diff --git a/src/arm64/assembler-arm64-inl.h b/src/arm64/assembler-arm64-inl.h
index 5e1bed1..4547efe 100644
--- a/src/arm64/assembler-arm64-inl.h
+++ b/src/arm64/assembler-arm64-inl.h
@@ -503,7 +503,7 @@
     DCHECK(addrmode == Offset);
 
     regoffset_ = offset.reg();
-    shift_= offset.shift();
+    shift_ = offset.shift();
     shift_amount_ = offset.shift_amount();
 
     extend_ = NO_EXTEND;
@@ -520,7 +520,7 @@
     extend_ = offset.extend();
     shift_amount_ = offset.shift_amount();
 
-    shift_= NO_SHIFT;
+    shift_ = NO_SHIFT;
     offset_ = 0;
 
     // These assertions match those in the extended-register constructor.
diff --git a/src/arm64/assembler-arm64.cc b/src/arm64/assembler-arm64.cc
index c1213e9..770d425 100644
--- a/src/arm64/assembler-arm64.cc
+++ b/src/arm64/assembler-arm64.cc
@@ -44,22 +44,27 @@
 // CpuFeatures implementation.
 
 void CpuFeatures::ProbeImpl(bool cross_compile) {
-  if (cross_compile) {
-    // Always align csp in cross compiled code - this is safe and ensures that
-    // csp will always be aligned if it is enabled by probing at runtime.
-    if (FLAG_enable_always_align_csp) supported_ |= 1u << ALWAYS_ALIGN_CSP;
-  } else {
-    base::CPU cpu;
-    if (FLAG_enable_always_align_csp &&
-        (cpu.implementer() == base::CPU::NVIDIA || FLAG_debug_code)) {
-      supported_ |= 1u << ALWAYS_ALIGN_CSP;
-    }
+  // AArch64 has no configuration options, no further probing is required.
+  supported_ = 0;
+
+  // Only use statically determined features for cross compile (snapshot).
+  if (cross_compile) return;
+
+  // Probe for runtime features
+  base::CPU cpu;
+  if (cpu.implementer() == base::CPU::NVIDIA &&
+      cpu.variant() == base::CPU::NVIDIA_DENVER) {
+    supported_ |= 1u << COHERENT_CACHE;
   }
 }
 
 
 void CpuFeatures::PrintTarget() { }
-void CpuFeatures::PrintFeatures() { }
+
+
+void CpuFeatures::PrintFeatures() {
+  printf("COHERENT_CACHE=%d\n", CpuFeatures::IsSupported(COHERENT_CACHE));
+}
 
 
 // -----------------------------------------------------------------------------
@@ -612,9 +617,12 @@
 void Assembler::CheckLabelLinkChain(Label const * label) {
 #ifdef DEBUG
   if (label->is_linked()) {
+    static const int kMaxLinksToCheck = 64;  // Avoid O(n2) behaviour.
+    int links_checked = 0;
     int linkoffset = label->pos();
     bool end_of_chain = false;
     while (!end_of_chain) {
+      if (++links_checked > kMaxLinksToCheck) break;
       Instruction * link = InstructionAt(linkoffset);
       int linkpcoffset = link->ImmPCOffset();
       int prevlinkoffset = linkoffset + linkpcoffset;
@@ -1936,6 +1944,12 @@
 }
 
 
+void Assembler::frintp(const FPRegister& fd, const FPRegister& fn) {
+  DCHECK(fd.SizeInBits() == fn.SizeInBits());
+  FPDataProcessing1Source(fd, fn, FRINTP);
+}
+
+
 void Assembler::frintz(const FPRegister& fd,
                        const FPRegister& fn) {
   DCHECK(fd.SizeInBits() == fn.SizeInBits());
diff --git a/src/arm64/assembler-arm64.h b/src/arm64/assembler-arm64.h
index 82b4500..53496f3 100644
--- a/src/arm64/assembler-arm64.h
+++ b/src/arm64/assembler-arm64.h
@@ -276,6 +276,11 @@
       (kAllocatableHighRangeEnd - kAllocatableHighRangeBegin + 1);
   static int NumAllocatableRegisters() { return kMaxNumAllocatableRegisters; }
 
+  // TODO(turbofan): Proper float32 support.
+  static int NumAllocatableAliasedRegisters() {
+    return NumAllocatableRegisters();
+  }
+
   // Return true if the register is one that crankshaft can allocate.
   bool IsAllocatable() const {
     return (Bit() & kAllocatableFPRegisters) != 0;
@@ -1658,6 +1663,9 @@
   // FP round to integer (nearest with ties to even).
   void frintn(const FPRegister& fd, const FPRegister& fn);
 
+  // FP round to integer (towards plus infinity).
+  void frintp(const FPRegister& fd, const FPRegister& fn);
+
   // FP round to integer (towards zero.)
   void frintz(const FPRegister& fd, const FPRegister& fn);
 
diff --git a/src/arm64/builtins-arm64.cc b/src/arm64/builtins-arm64.cc
index 0013e24..9f140c2 100644
--- a/src/arm64/builtins-arm64.cc
+++ b/src/arm64/builtins-arm64.cc
@@ -10,7 +10,7 @@
 #include "src/debug.h"
 #include "src/deoptimizer.h"
 #include "src/full-codegen.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -156,7 +156,7 @@
   __ Cbz(argc, &no_arguments);
   // First args = sp[(argc - 1) * 8].
   __ Sub(argc, argc, 1);
-  __ Claim(argc, kXRegSize);
+  __ Drop(argc, kXRegSize);
   // jssp now point to args[0], load and drop args[0] + receiver.
   Register arg = argc;
   __ Ldr(arg, MemOperand(jssp, 2 * kPointerSize, PostIndex));
@@ -367,13 +367,13 @@
             FieldMemOperand(init_map, Map::kBitField3Offset);
         // Check if slack tracking is enabled.
         __ Ldr(x4, bit_field3);
-        __ DecodeField<Map::ConstructionCount>(constructon_count, x4);
-        __ Cmp(constructon_count, Operand(JSFunction::kNoSlackTracking));
-        __ B(eq, &allocate);
+        __ DecodeField<Map::Counter>(constructon_count, x4);
+        __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
+        __ B(lt, &allocate);
         // Decrease generous allocation count.
-        __ Subs(x4, x4, Operand(1 << Map::ConstructionCount::kShift));
+        __ Subs(x4, x4, Operand(1 << Map::Counter::kShift));
         __ Str(x4, bit_field3);
-        __ Cmp(constructon_count, Operand(JSFunction::kFinishSlackTracking));
+        __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
         __ B(ne, &allocate);
 
         // Push the constructor and map to the stack, and the constructor again
@@ -381,7 +381,7 @@
         __ Push(constructor, init_map, constructor);
         __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
         __ Pop(init_map, constructor);
-        __ Mov(constructon_count, Operand(JSFunction::kNoSlackTracking));
+        __ Mov(constructon_count, Operand(Map::kSlackTrackingCounterEnd - 1));
         __ Bind(&allocate);
       }
 
@@ -434,8 +434,8 @@
         Label no_inobject_slack_tracking;
 
         // Check if slack tracking is enabled.
-        __ Cmp(constructon_count, Operand(JSFunction::kNoSlackTracking));
-        __ B(eq, &no_inobject_slack_tracking);
+        __ Cmp(constructon_count, Operand(Map::kSlackTrackingCounterEnd));
+        __ B(lt, &no_inobject_slack_tracking);
         constructon_count = NoReg;
 
         // Fill the pre-allocated fields with undef.
diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc
index 4978e5e..e773b53 100644
--- a/src/arm64/code-stubs-arm64.cc
+++ b/src/arm64/code-stubs-arm64.cc
@@ -14,7 +14,7 @@
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -1412,6 +1412,11 @@
 void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
   Label miss;
   Register receiver = LoadDescriptor::ReceiverRegister();
+  // Ensure that the vector and slot registers won't be clobbered before
+  // calling the miss handler.
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(x10, x11, VectorLoadICDescriptor::VectorRegister(),
+                     VectorLoadICDescriptor::SlotRegister()));
 
   NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, x10,
                                                           x11, &miss);
@@ -1422,6 +1427,40 @@
 }
 
 
+void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
+  // Return address is in lr.
+  Label miss;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register index = LoadDescriptor::NameRegister();
+  Register result = x0;
+  Register scratch = x10;
+  DCHECK(!scratch.is(receiver) && !scratch.is(index));
+  DCHECK(!FLAG_vector_ics ||
+         (!scratch.is(VectorLoadICDescriptor::VectorRegister()) &&
+          result.is(VectorLoadICDescriptor::SlotRegister())));
+
+  // StringCharAtGenerator doesn't use the result register until it's passed
+  // the different miss possibilities. If it did, we would have a conflict
+  // when FLAG_vector_ics is true.
+  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
+                                          &miss,  // When not a string.
+                                          &miss,  // When not a number.
+                                          &miss,  // When index out of range.
+                                          STRING_INDEX_IS_ARRAY_INDEX,
+                                          RECEIVER_IS_STRING);
+  char_at_generator.GenerateFast(masm);
+  __ Ret();
+
+  StubRuntimeCallHelper call_helper;
+  char_at_generator.GenerateSlow(masm, call_helper);
+
+  __ Bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
 void InstanceofStub::Generate(MacroAssembler* masm) {
   // Stack on entry:
   // jssp[0]: function.
@@ -1569,7 +1608,7 @@
   __ Mov(result, res_false);
 
   // Null is not instance of anything.
-  __ Cmp(object_type, Operand(isolate()->factory()->null_value()));
+  __ Cmp(object, Operand(isolate()->factory()->null_value()));
   __ B(ne, &object_not_null);
   __ Ret();
 
@@ -2683,13 +2722,13 @@
 
   // A monomorphic miss (i.e, here the cache is not uninitialized) goes
   // megamorphic.
-  __ JumpIfRoot(scratch1, Heap::kUninitializedSymbolRootIndex, &initialize);
+  __ JumpIfRoot(scratch1, Heap::kuninitialized_symbolRootIndex, &initialize);
   // MegamorphicSentinel is an immortal immovable object (undefined) so no
   // write-barrier is needed.
   __ Bind(&megamorphic);
   __ Add(scratch1, feedback_vector,
          Operand::UntagSmiAndScale(index, kPointerSizeLog2));
-  __ LoadRoot(scratch2, Heap::kMegamorphicSymbolRootIndex);
+  __ LoadRoot(scratch2, Heap::kmegamorphic_symbolRootIndex);
   __ Str(scratch2, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
   __ B(&done);
 
@@ -2988,6 +3027,10 @@
 
   // x1 - function
   // x3 - slot id (Smi)
+  const int with_types_offset =
+      FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
+  const int generic_offset =
+      FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
   Label slow, non_function, wrap, cont;
   Label have_js_function;
@@ -3036,24 +3079,72 @@
   }
 
   __ bind(&extra_checks_or_miss);
-  Label miss;
+  Label uninitialized, miss;
 
-  __ JumpIfRoot(x4, Heap::kMegamorphicSymbolRootIndex, &slow_start);
-  __ JumpIfRoot(x4, Heap::kUninitializedSymbolRootIndex, &miss);
+  __ JumpIfRoot(x4, Heap::kmegamorphic_symbolRootIndex, &slow_start);
 
-  if (!FLAG_trace_ic) {
-    // We are going megamorphic. If the feedback is a JSFunction, it is fine
-    // to handle it here. More complex cases are dealt with in the runtime.
-    __ AssertNotSmi(x4);
-    __ JumpIfNotObjectType(x4, x5, x5, JS_FUNCTION_TYPE, &miss);
-    __ Add(x4, feedback_vector,
-           Operand::UntagSmiAndScale(index, kPointerSizeLog2));
-    __ LoadRoot(x5, Heap::kMegamorphicSymbolRootIndex);
-    __ Str(x5, FieldMemOperand(x4, FixedArray::kHeaderSize));
-    __ B(&slow_start);
+  // The following cases attempt to handle MISS cases without going to the
+  // runtime.
+  if (FLAG_trace_ic) {
+    __ jmp(&miss);
   }
 
-  // We are here because tracing is on or we are going monomorphic.
+  __ JumpIfRoot(x4, Heap::kuninitialized_symbolRootIndex, &miss);
+
+  // We are going megamorphic. If the feedback is a JSFunction, it is fine
+  // to handle it here. More complex cases are dealt with in the runtime.
+  __ AssertNotSmi(x4);
+  __ JumpIfNotObjectType(x4, x5, x5, JS_FUNCTION_TYPE, &miss);
+  __ Add(x4, feedback_vector,
+         Operand::UntagSmiAndScale(index, kPointerSizeLog2));
+  __ LoadRoot(x5, Heap::kmegamorphic_symbolRootIndex);
+  __ Str(x5, FieldMemOperand(x4, FixedArray::kHeaderSize));
+  // We have to update statistics for runtime profiling.
+  __ Ldr(x4, FieldMemOperand(feedback_vector, with_types_offset));
+  __ Subs(x4, x4, Operand(Smi::FromInt(1)));
+  __ Str(x4, FieldMemOperand(feedback_vector, with_types_offset));
+  __ Ldr(x4, FieldMemOperand(feedback_vector, generic_offset));
+  __ Adds(x4, x4, Operand(Smi::FromInt(1)));
+  __ Str(x4, FieldMemOperand(feedback_vector, generic_offset));
+  __ B(&slow_start);
+
+  __ bind(&uninitialized);
+
+  // We are going monomorphic, provided we actually have a JSFunction.
+  __ JumpIfSmi(function, &miss);
+
+  // Goto miss case if we do not have a function.
+  __ JumpIfNotObjectType(function, x5, x5, JS_FUNCTION_TYPE, &miss);
+
+  // Make sure the function is not the Array() function, which requires special
+  // behavior on MISS.
+  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, x5);
+  __ Cmp(function, x5);
+  __ B(eq, &miss);
+
+  // Update stats.
+  __ Ldr(x4, FieldMemOperand(feedback_vector, with_types_offset));
+  __ Adds(x4, x4, Operand(Smi::FromInt(1)));
+  __ Str(x4, FieldMemOperand(feedback_vector, with_types_offset));
+
+  // Store the function.
+  __ Add(x4, feedback_vector,
+         Operand::UntagSmiAndScale(index, kPointerSizeLog2));
+  __ Str(function, FieldMemOperand(x4, FixedArray::kHeaderSize));
+
+  __ Add(x4, feedback_vector,
+         Operand::UntagSmiAndScale(index, kPointerSizeLog2));
+  __ Add(x4, x4, FixedArray::kHeaderSize - kHeapObjectTag);
+  __ Str(function, MemOperand(x4, 0));
+
+  // Update the write barrier.
+  __ Mov(x5, function);
+  __ RecordWrite(feedback_vector, x4, x5, kLRHasNotBeenSaved, kDontSaveFPRegs,
+                 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+  __ B(&have_js_function);
+
+  // We are here because tracing is on or we encountered a MISS case we can't
+  // handle here.
   __ bind(&miss);
   GenerateMiss(masm);
 
@@ -3097,14 +3188,16 @@
 
 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
   // If the receiver is a smi trigger the non-string case.
-  __ JumpIfSmi(object_, receiver_not_string_);
+  if (check_mode_ == RECEIVER_IS_UNKNOWN) {
+    __ JumpIfSmi(object_, receiver_not_string_);
 
-  // Fetch the instance type of the receiver into result register.
-  __ Ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
-  __ Ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
+    // Fetch the instance type of the receiver into result register.
+    __ Ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
+    __ Ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
 
-  // If the receiver is not a string trigger the non-string case.
-  __ TestAndBranchIfAnySet(result_, kIsNotStringMask, receiver_not_string_);
+    // If the receiver is not a string trigger the non-string case.
+    __ TestAndBranchIfAnySet(result_, kIsNotStringMask, receiver_not_string_);
+  }
 
   // If the index is non-smi trigger the non-smi case.
   __ JumpIfNotSmi(index_, &index_not_smi_);
@@ -3782,9 +3875,9 @@
   // x12: input_type
   // x15: from (untagged)
   __ SmiTag(from);
-  StringCharAtGenerator generator(
-      input_string, from, result_length, x0,
-      &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
+  StringCharAtGenerator generator(input_string, from, result_length, x0,
+                                  &runtime, &runtime, &runtime,
+                                  STRING_INDEX_IS_NUMBER, RECEIVER_IS_STRING);
   generator.GenerateFast(masm);
   __ Drop(3);
   __ Ret();
@@ -3792,6 +3885,49 @@
 }
 
 
+void ToNumberStub::Generate(MacroAssembler* masm) {
+  // The ToNumber stub takes one argument in x0.
+  Label not_smi;
+  __ JumpIfNotSmi(x0, &not_smi);
+  __ Ret();
+  __ Bind(&not_smi);
+
+  Label not_heap_number;
+  __ Ldr(x1, FieldMemOperand(x0, HeapObject::kMapOffset));
+  __ Ldrb(x1, FieldMemOperand(x1, Map::kInstanceTypeOffset));
+  // x0: object
+  // x1: instance type
+  __ Cmp(x1, HEAP_NUMBER_TYPE);
+  __ B(ne, &not_heap_number);
+  __ Ret();
+  __ Bind(&not_heap_number);
+
+  Label not_string, slow_string;
+  __ Cmp(x1, FIRST_NONSTRING_TYPE);
+  __ B(hs, &not_string);
+  // Check if string has a cached array index.
+  __ Ldr(x2, FieldMemOperand(x0, String::kHashFieldOffset));
+  __ Tst(x2, Operand(String::kContainsCachedArrayIndexMask));
+  __ B(ne, &slow_string);
+  __ IndexFromHash(x2, x0);
+  __ Ret();
+  __ Bind(&slow_string);
+  __ Push(x0);  // Push argument.
+  __ TailCallRuntime(Runtime::kStringToNumber, 1, 1);
+  __ Bind(&not_string);
+
+  Label not_oddball;
+  __ Cmp(x1, ODDBALL_TYPE);
+  __ B(ne, &not_oddball);
+  __ Ldr(x0, FieldMemOperand(x0, Oddball::kToNumberOffset));
+  __ Ret();
+  __ Bind(&not_oddball);
+
+  __ Push(x0);  // Push argument.
+  __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
+}
+
+
 void StringHelper::GenerateFlatOneByteStringEquals(
     MacroAssembler* masm, Register left, Register right, Register scratch1,
     Register scratch2, Register scratch3) {
@@ -4236,18 +4372,10 @@
 }
 
 
-static unsigned int GetProfileEntryHookCallSize(MacroAssembler* masm) {
-  // The entry hook is a "BumpSystemStackPointer" instruction (sub),
-  // followed by a "Push lr" instruction, followed by a call.
-  unsigned int size =
-      Assembler::kCallSizeWithRelocation + (2 * kInstructionSize);
-  if (CpuFeatures::IsSupported(ALWAYS_ALIGN_CSP)) {
-    // If ALWAYS_ALIGN_CSP then there will be an extra bic instruction in
-    // "BumpSystemStackPointer".
-    size += kInstructionSize;
-  }
-  return size;
-}
+// The entry hook is a "BumpSystemStackPointer" instruction (sub), followed by
+// a "Push lr" instruction, followed by a call.
+static const unsigned int kProfileEntryHookCallSize =
+    Assembler::kCallSizeWithRelocation + (2 * kInstructionSize);
 
 
 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
@@ -4260,7 +4388,7 @@
     __ Push(lr);
     __ CallStub(&stub);
     DCHECK(masm->SizeOfCodeGeneratedSince(&entry_hook_call_start) ==
-           GetProfileEntryHookCallSize(masm));
+           kProfileEntryHookCallSize);
 
     __ Pop(lr);
   }
@@ -4278,7 +4406,7 @@
   const int kNumSavedRegs = kCallerSaved.Count();
 
   // Compute the function's address as the first argument.
-  __ Sub(x0, lr, GetProfileEntryHookCallSize(masm));
+  __ Sub(x0, lr, kProfileEntryHookCallSize);
 
 #if V8_HOST_ARCH_ARM64
   uintptr_t entry_hook =
diff --git a/src/arm64/code-stubs-arm64.h b/src/arm64/code-stubs-arm64.h
index 03dab5b..c9ee2c9 100644
--- a/src/arm64/code-stubs-arm64.h
+++ b/src/arm64/code-stubs-arm64.h
@@ -97,7 +97,7 @@
     INCREMENTAL_COMPACTION
   };
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
   static Mode GetMode(Code* stub) {
     // Find the mode depending on the first two instructions.
@@ -275,9 +275,9 @@
     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
   };
 
-  virtual inline Major MajorKey() const FINAL OVERRIDE { return RecordWrite; }
+  inline Major MajorKey() const FINAL { return RecordWrite; }
 
-  virtual void Generate(MacroAssembler* masm) OVERRIDE;
+  void Generate(MacroAssembler* masm) OVERRIDE;
   void GenerateIncremental(MacroAssembler* masm, Mode mode);
   void CheckNeedsToInformIncrementalMarker(
       MacroAssembler* masm,
@@ -285,7 +285,7 @@
       Mode mode);
   void InformIncrementalMarker(MacroAssembler* masm);
 
-  void Activate(Code* code) {
+  void Activate(Code* code) OVERRIDE {
     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
   }
 
@@ -328,7 +328,7 @@
   void GenerateCall(MacroAssembler* masm, Register target);
 
  private:
-  bool NeedsImmovableCode() { return true; }
+  bool NeedsImmovableCode() OVERRIDE { return true; }
 
   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
   DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
@@ -360,7 +360,7 @@
                                      Register scratch1,
                                      Register scratch2);
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
  private:
   static const int kInlinedProbes = 4;
diff --git a/src/arm64/codegen-arm64.cc b/src/arm64/codegen-arm64.cc
index 91eaba7..cda6e5b 100644
--- a/src/arm64/codegen-arm64.cc
+++ b/src/arm64/codegen-arm64.cc
@@ -290,15 +290,28 @@
   Register src_elements = x10;
   Register dst_elements = x11;
   Register dst_end = x12;
+  Register the_hole = x14;
+  __ LoadRoot(the_hole, Heap::kTheHoleValueRootIndex);
   __ Add(src_elements, elements,
          FixedDoubleArray::kHeaderSize - kHeapObjectTag);
   __ Add(dst_elements, array, FixedArray::kHeaderSize);
-  __ Add(array, array, kHeapObjectTag);
   __ Add(dst_end, dst_elements, Operand(length, LSL, kPointerSizeLog2));
 
-  Register the_hole = x14;
+  // Allocating heap numbers in the loop below can fail and cause a jump to
+  // gc_required. We can't leave a partly initialized FixedArray behind,
+  // so pessimistically fill it with holes now.
+  Label initialization_loop, initialization_loop_entry;
+  __ B(&initialization_loop_entry);
+  __ bind(&initialization_loop);
+  __ Str(the_hole, MemOperand(dst_elements, kPointerSize, PostIndex));
+  __ bind(&initialization_loop_entry);
+  __ Cmp(dst_elements, dst_end);
+  __ B(lt, &initialization_loop);
+
+  __ Add(dst_elements, array, FixedArray::kHeaderSize);
+  __ Add(array, array, kHeapObjectTag);
+
   Register heap_num_map = x15;
-  __ LoadRoot(the_hole, Heap::kTheHoleValueRootIndex);
   __ LoadRoot(heap_num_map, Heap::kHeapNumberMapRootIndex);
 
   Label entry;
diff --git a/src/arm64/cpu-arm64.cc b/src/arm64/cpu-arm64.cc
index 39beb6d..11ba7c9 100644
--- a/src/arm64/cpu-arm64.cc
+++ b/src/arm64/cpu-arm64.cc
@@ -43,6 +43,8 @@
 void CpuFeatures::FlushICache(void* address, size_t length) {
   if (length == 0) return;
 
+  if (CpuFeatures::IsSupported(COHERENT_CACHE)) return;
+
 #ifdef USE_SIMULATOR
   // TODO(all): consider doing some cache simulation to ensure every address
   // run has been synced.
diff --git a/src/arm64/debug-arm64.cc b/src/arm64/debug-arm64.cc
index f57d5b5..dae5a28 100644
--- a/src/arm64/debug-arm64.cc
+++ b/src/arm64/debug-arm64.cc
@@ -238,7 +238,11 @@
   // Calling convention for IC load (from ic-arm.cc).
   Register receiver = LoadDescriptor::ReceiverRegister();
   Register name = LoadDescriptor::NameRegister();
-  Generate_DebugBreakCallHelper(masm, receiver.Bit() | name.Bit(), 0, x10);
+  RegList regs = receiver.Bit() | name.Bit();
+  if (FLAG_vector_ics) {
+    regs |= VectorLoadICTrampolineDescriptor::SlotRegister().Bit();
+  }
+  Generate_DebugBreakCallHelper(masm, regs, 0, x10);
 }
 
 
diff --git a/src/arm64/delayed-masm-arm64.cc b/src/arm64/delayed-masm-arm64.cc
index c3bda91..b51e77e 100644
--- a/src/arm64/delayed-masm-arm64.cc
+++ b/src/arm64/delayed-masm-arm64.cc
@@ -16,8 +16,8 @@
 
 
 void DelayedMasm::StackSlotMove(LOperand* src, LOperand* dst) {
-  DCHECK(src->IsStackSlot());
-  DCHECK(dst->IsStackSlot());
+  DCHECK((src->IsStackSlot() && dst->IsStackSlot()) ||
+         (src->IsDoubleStackSlot() && dst->IsDoubleStackSlot()));
   MemOperand src_operand = cgen_->ToMemOperand(src);
   MemOperand dst_operand = cgen_->ToMemOperand(dst);
   if (pending_ == kStackSlotMove) {
diff --git a/src/arm64/deoptimizer-arm64.cc b/src/arm64/deoptimizer-arm64.cc
index d67dc8f..b83bbbe 100644
--- a/src/arm64/deoptimizer-arm64.cc
+++ b/src/arm64/deoptimizer-arm64.cc
@@ -21,6 +21,11 @@
 }
 
 
+void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
+  // Empty because there is no need for relocation information for the code
+  // patching in Deoptimizer::PatchCodeForDeoptimization below.
+}
+
 
 void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
   // Invalidate the relocation information, as it will become invalid by the
diff --git a/src/arm64/disasm-arm64.cc b/src/arm64/disasm-arm64.cc
index ac7cb37..36bad37 100644
--- a/src/arm64/disasm-arm64.cc
+++ b/src/arm64/disasm-arm64.cc
@@ -1695,7 +1695,7 @@
   DCHECK(format[0] == 'M');
   USE(format);
 
-  static const char* options[4][4] = {
+  static const char* const options[4][4] = {
     { "sy (0b0000)", "oshld", "oshst", "osh" },
     { "sy (0b0100)", "nshld", "nshst", "nsh" },
     { "sy (0b1000)", "ishld", "ishst", "ish" },
diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc
index 25a9efd..0d3d34b 100644
--- a/src/arm64/full-codegen-arm64.cc
+++ b/src/arm64/full-codegen-arm64.cc
@@ -196,10 +196,10 @@
     // Argument to NewContext is the function, which is still in x1.
     Comment cmnt(masm_, "[ Allocate context");
     bool need_write_barrier = true;
-    if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
+    if (FLAG_harmony_scoping && info->scope()->is_script_scope()) {
       __ Mov(x10, Operand(info->scope()->GetScopeInfo()));
       __ Push(x1, x10);
-      __ CallRuntime(Runtime::kNewGlobalContext, 2);
+      __ CallRuntime(Runtime::kNewScriptContext, 2);
     } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
       FastNewContextStub stub(isolate(), heap_slots);
       __ CallStub(&stub);
@@ -299,24 +299,26 @@
       }
       VisitDeclarations(scope()->declarations());
     }
-  }
 
-  { Comment cmnt(masm_, "[ Stack check");
-    PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
-    Label ok;
-    DCHECK(jssp.Is(__ StackPointer()));
-    __ CompareRoot(jssp, Heap::kStackLimitRootIndex);
-    __ B(hs, &ok);
-    PredictableCodeSizeScope predictable(masm_,
-                                         Assembler::kCallSizeWithRelocation);
-    __ Call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
-    __ Bind(&ok);
-  }
+    {
+      Comment cmnt(masm_, "[ Stack check");
+      PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
+      Label ok;
+      DCHECK(jssp.Is(__ StackPointer()));
+      __ CompareRoot(jssp, Heap::kStackLimitRootIndex);
+      __ B(hs, &ok);
+      PredictableCodeSizeScope predictable(masm_,
+                                           Assembler::kCallSizeWithRelocation);
+      __ Call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
+      __ Bind(&ok);
+    }
 
-  { Comment cmnt(masm_, "[ Body");
-    DCHECK(loop_depth() == 0);
-    VisitStatements(function()->body());
-    DCHECK(loop_depth() == 0);
+    {
+      Comment cmnt(masm_, "[ Body");
+      DCHECK(loop_depth() == 0);
+      VisitStatements(function()->body());
+      DCHECK(loop_depth() == 0);
+    }
   }
 
   // Always emit a 'return undefined' in case control fell off the end of
@@ -932,7 +934,7 @@
   EmitDebugCheckDeclarationContext(variable);
 
   // Load instance object.
-  __ LoadContext(x1, scope_->ContextChainLength(scope_->GlobalScope()));
+  __ LoadContext(x1, scope_->ContextChainLength(scope_->ScriptScope()));
   __ Ldr(x1, ContextMemOperand(x1, variable->interface()->Index()));
   __ Ldr(x1, ContextMemOperand(x1, Context::EXTENSION_INDEX));
 
@@ -1097,7 +1099,7 @@
 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
   ASM_LOCATION("FullCodeGenerator::VisitForInStatement");
   Comment cmnt(masm_, "[ ForInStatement");
-  int slot = stmt->ForInFeedbackSlot();
+  FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
   // TODO(all): This visitor probably needs better comments and a revisit.
   SetStatementPosition(stmt);
 
@@ -1107,6 +1109,7 @@
 
   // Get the object to enumerate over. If the object is null or undefined, skip
   // over the loop.  See ECMA-262 version 5, section 12.6.4.
+  SetExpressionPosition(stmt->enumerable());
   VisitForAccumulatorValue(stmt->enumerable());
   __ JumpIfRoot(x0, Heap::kUndefinedValueRootIndex, &exit);
   Register null_value = x15;
@@ -1124,6 +1127,7 @@
   __ Push(x0);
   __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
   __ Bind(&done_convert);
+  PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
   __ Push(x0);
 
   // Check for proxies.
@@ -1147,6 +1151,7 @@
   __ Bind(&call_runtime);
   __ Push(x0);  // Duplicate the enumerable object on the stack.
   __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
+  PrepareForBailoutForId(stmt->EnumId(), TOS_REG);
 
   // If we got a map from the runtime call, we can do a fast
   // modification check. Otherwise, we got a fixed array, and we have
@@ -1181,7 +1186,8 @@
 
   __ LoadObject(x1, FeedbackVector());
   __ Mov(x10, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate())));
-  __ Str(x10, FieldMemOperand(x1, FixedArray::OffsetOfElementAt(slot)));
+  int vector_index = FeedbackVector()->GetIndex(slot);
+  __ Str(x10, FieldMemOperand(x1, FixedArray::OffsetOfElementAt(vector_index)));
 
   __ Mov(x1, Smi::FromInt(1));  // Smi indicates slow check.
   __ Peek(x10, 0);  // Get enumerated object.
@@ -1197,6 +1203,8 @@
   // Generate code for doing the condition check.
   PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
   __ Bind(&loop);
+  SetExpressionPosition(stmt->each());
+
   // Load the current count to x0, load the length to x1.
   __ PeekPair(x0, x1, 0);
   __ Cmp(x0, x1);  // Compare to the array length.
@@ -1266,48 +1274,6 @@
 }
 
 
-void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
-  Comment cmnt(masm_, "[ ForOfStatement");
-  SetStatementPosition(stmt);
-
-  Iteration loop_statement(this, stmt);
-  increment_loop_depth();
-
-  // var iterator = iterable[Symbol.iterator]();
-  VisitForEffect(stmt->assign_iterator());
-
-  // Loop entry.
-  __ Bind(loop_statement.continue_label());
-
-  // result = iterator.next()
-  VisitForEffect(stmt->next_result());
-
-  // if (result.done) break;
-  Label result_not_done;
-  VisitForControl(stmt->result_done(),
-                  loop_statement.break_label(),
-                  &result_not_done,
-                  &result_not_done);
-  __ Bind(&result_not_done);
-
-  // each = result.value
-  VisitForEffect(stmt->assign_each());
-
-  // Generate code for the body of the loop.
-  Visit(stmt->body());
-
-  // Check stack before looping.
-  PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
-  EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
-  __ B(loop_statement.continue_label());
-
-  // Exit and decrement the loop depth.
-  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
-  __ Bind(loop_statement.break_label());
-  decrement_loop_depth();
-}
-
-
 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
                                        bool pretenure) {
   // Use the fast case closure allocation code that allocates in new space for
@@ -1350,7 +1316,13 @@
   Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
   __ Mov(LoadDescriptor::NameRegister(), Operand(home_object_symbol));
 
-  CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  if (FLAG_vector_ics) {
+    __ Mov(VectorLoadICDescriptor::SlotRegister(),
+           SmiFromSlot(expr->HomeObjectFeedbackSlot()));
+    CallLoadIC(NOT_CONTEXTUAL);
+  } else {
+    CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  }
 
   __ Mov(x10, Operand(isolate()->factory()->undefined_value()));
   __ cmp(x0, x10);
@@ -1361,6 +1333,18 @@
 }
 
 
+void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
+                                                  int offset) {
+  if (NeedsHomeObject(initializer)) {
+    __ Peek(StoreDescriptor::ReceiverRegister(), 0);
+    __ Mov(StoreDescriptor::NameRegister(),
+           Operand(isolate()->factory()->home_object_symbol()));
+    __ Peek(StoreDescriptor::ValueRegister(), offset * kPointerSize);
+    CallStoreIC();
+  }
+}
+
+
 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
                                                       TypeofState typeof_state,
                                                       Label* slow) {
@@ -1408,7 +1392,7 @@
   __ Mov(LoadDescriptor::NameRegister(), Operand(proxy->var()->name()));
   if (FLAG_vector_ics) {
     __ Mov(VectorLoadICDescriptor::SlotRegister(),
-           Smi::FromInt(proxy->VariableFeedbackSlot()));
+           SmiFromSlot(proxy->VariableFeedbackSlot()));
   }
 
   ContextualMode mode = (typeof_state == INSIDE_TYPEOF) ? NOT_CONTEXTUAL
@@ -1493,7 +1477,7 @@
       __ Mov(LoadDescriptor::NameRegister(), Operand(var->name()));
       if (FLAG_vector_ics) {
         __ Mov(VectorLoadICDescriptor::SlotRegister(),
-               Smi::FromInt(proxy->VariableFeedbackSlot()));
+               SmiFromSlot(proxy->VariableFeedbackSlot()));
       }
       CallLoadIC(CONTEXTUAL);
       context()->Plug(x0);
@@ -1671,6 +1655,7 @@
     FastCloneShallowObjectStub stub(isolate(), properties_count);
     __ CallStub(&stub);
   }
+  PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
 
   // If result_saved is true the result is on top of the stack.  If
   // result_saved is false the result is in x0.
@@ -1699,6 +1684,8 @@
         DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
         // Fall through.
       case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             VisitForAccumulatorValue(value);
@@ -1707,6 +1694,14 @@
             __ Peek(StoreDescriptor::ReceiverRegister(), 0);
             CallStoreIC(key->LiteralFeedbackId());
             PrepareForBailoutForId(key->id(), NO_REGISTERS);
+
+            if (NeedsHomeObject(value)) {
+              __ Mov(StoreDescriptor::ReceiverRegister(), x0);
+              __ Mov(StoreDescriptor::NameRegister(),
+                     Operand(isolate()->factory()->home_object_symbol()));
+              __ Peek(StoreDescriptor::ValueRegister(), 0);
+              CallStoreIC();
+            }
           } else {
             VisitForEffect(value);
           }
@@ -1718,6 +1713,7 @@
           __ Push(x0);
           VisitForStackValue(key);
           VisitForStackValue(value);
+          EmitSetHomeObjectIfNeeded(value, 2);
           __ Mov(x0, Smi::FromInt(SLOPPY));  // Strict mode
           __ Push(x0);
           __ CallRuntime(Runtime::kSetProperty, 4);
@@ -1732,7 +1728,7 @@
           __ Peek(x0, 0);
           __ Push(x0);
           VisitForStackValue(value);
-          __ CallRuntime(Runtime::kSetPrototype, 2);
+          __ CallRuntime(Runtime::kInternalSetPrototype, 2);
         } else {
           VisitForEffect(value);
         }
@@ -1755,7 +1751,9 @@
       __ Push(x10);
       VisitForStackValue(it->first);
       EmitAccessor(it->second->getter);
+      EmitSetHomeObjectIfNeeded(it->second->getter, 2);
       EmitAccessor(it->second->setter);
+      EmitSetHomeObjectIfNeeded(it->second->setter, 3);
       __ Mov(x10, Smi::FromInt(NONE));
       __ Push(x10);
       __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
@@ -1862,16 +1860,8 @@
 
   Comment cmnt(masm_, "[ Assignment");
 
-  // Left-hand side can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* property = expr->target()->AsProperty();
-  if (property != NULL) {
-    assign_type = (property->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(property);
 
   // Evaluate LHS expression.
   switch (assign_type) {
@@ -1887,6 +1877,30 @@
         VisitForStackValue(property->obj());
       }
       break;
+    case NAMED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Push(result_register());
+      if (expr->is_compound()) {
+        const Register scratch = x10;
+        __ Peek(scratch, kPointerSize);
+        __ Push(scratch, result_register());
+      }
+      break;
+    case KEYED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForAccumulatorValue(property->key());
+      __ Push(result_register());
+      if (expr->is_compound()) {
+        const Register scratch1 = x10;
+        const Register scratch2 = x11;
+        __ Peek(scratch1, 2 * kPointerSize);
+        __ Peek(scratch2, kPointerSize);
+        __ Push(scratch1, scratch2, result_register());
+      }
+      break;
     case KEYED_PROPERTY:
       if (expr->is_compound()) {
         VisitForStackValue(property->obj());
@@ -1913,6 +1927,14 @@
           EmitNamedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
           break;
+        case NAMED_SUPER_PROPERTY:
+          EmitNamedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
+        case KEYED_SUPER_PROPERTY:
+          EmitKeyedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
         case KEYED_PROPERTY:
           EmitKeyedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
@@ -1959,6 +1981,14 @@
     case NAMED_PROPERTY:
       EmitNamedPropertyAssignment(expr);
       break;
+    case NAMED_SUPER_PROPERTY:
+      EmitNamedSuperPropertyStore(property);
+      context()->Plug(x0);
+      break;
+    case KEYED_SUPER_PROPERTY:
+      EmitKeyedSuperPropertyStore(property);
+      context()->Plug(x0);
+      break;
     case KEYED_PROPERTY:
       EmitKeyedPropertyAssignment(expr);
       break;
@@ -1974,7 +2004,7 @@
   __ Mov(LoadDescriptor::NameRegister(), Operand(key->value()));
   if (FLAG_vector_ics) {
     __ Mov(VectorLoadICDescriptor::SlotRegister(),
-           Smi::FromInt(prop->PropertyFeedbackSlot()));
+           SmiFromSlot(prop->PropertyFeedbackSlot()));
     CallLoadIC(NOT_CONTEXTUAL);
   } else {
     CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
@@ -1983,15 +2013,12 @@
 
 
 void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object.
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
   DCHECK(!key->value()->IsSmi());
   DCHECK(prop->IsSuperAccess());
 
-  SuperReference* super_ref = prop->obj()->AsSuperReference();
-  EmitLoadHomeObject(super_ref);
-  __ Push(x0);
-  VisitForStackValue(super_ref->this_var());
   __ Push(key->value());
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 }
@@ -1999,11 +2026,11 @@
 
 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
   SetSourcePosition(prop->position());
-  // Call keyed load IC. It has arguments key and receiver in r0 and r1.
+  // Call keyed load IC. It has arguments key and receiver in x0 and x1.
   Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
   if (FLAG_vector_ics) {
     __ Mov(VectorLoadICDescriptor::SlotRegister(),
-           Smi::FromInt(prop->PropertyFeedbackSlot()));
+           SmiFromSlot(prop->PropertyFeedbackSlot()));
     CallIC(ic);
   } else {
     CallIC(ic, prop->PropertyFeedbackId());
@@ -2011,6 +2038,14 @@
 }
 
 
+void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object, key.
+  SetSourcePosition(prop->position());
+
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+}
+
+
 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
                                               Token::Value op,
                                               OverwriteMode mode,
@@ -2126,19 +2161,68 @@
 }
 
 
+void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
+  // Constructor is in x0.
+  DCHECK(lit != NULL);
+  __ push(x0);
+
+  // No access check is needed here since the constructor is created by the
+  // class literal.
+  Register scratch = x1;
+  __ Ldr(scratch,
+         FieldMemOperand(x0, JSFunction::kPrototypeOrInitialMapOffset));
+  __ Push(scratch);
+
+  for (int i = 0; i < lit->properties()->length(); i++) {
+    ObjectLiteral::Property* property = lit->properties()->at(i);
+    Literal* key = property->key()->AsLiteral();
+    Expression* value = property->value();
+    DCHECK(key != NULL);
+
+    if (property->is_static()) {
+      __ Peek(scratch, kPointerSize);  // constructor
+    } else {
+      __ Peek(scratch, 0);  // prototype
+    }
+    __ Push(scratch);
+    VisitForStackValue(key);
+    VisitForStackValue(value);
+    EmitSetHomeObjectIfNeeded(value, 2);
+
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT:
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+      case ObjectLiteral::Property::COMPUTED:
+      case ObjectLiteral::Property::PROTOTYPE:
+        __ CallRuntime(Runtime::kDefineClassMethod, 3);
+        break;
+
+      case ObjectLiteral::Property::GETTER:
+        __ CallRuntime(Runtime::kDefineClassGetter, 3);
+        break;
+
+      case ObjectLiteral::Property::SETTER:
+        __ CallRuntime(Runtime::kDefineClassSetter, 3);
+        break;
+
+      default:
+        UNREACHABLE();
+    }
+  }
+
+  // prototype
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+
+  // constructor
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+}
+
+
 void FullCodeGenerator::EmitAssignment(Expression* expr) {
   DCHECK(expr->IsValidReferenceExpression());
 
-  // Left-hand side can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* prop = expr->AsProperty();
-  if (prop != NULL) {
-    assign_type = (prop->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(prop);
 
   switch (assign_type) {
     case VARIABLE: {
@@ -2159,6 +2243,42 @@
       CallStoreIC();
       break;
     }
+    case NAMED_SUPER_PROPERTY: {
+      __ Push(x0);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      // stack: value, this; x0: home_object
+      Register scratch = x10;
+      Register scratch2 = x11;
+      __ mov(scratch, result_register());  // home_object
+      __ Peek(x0, kPointerSize);           // value
+      __ Peek(scratch2, 0);                // this
+      __ Poke(scratch2, kPointerSize);     // this
+      __ Poke(scratch, 0);                 // home_object
+      // stack: this, home_object; x0: value
+      EmitNamedSuperPropertyStore(prop);
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      __ Push(x0);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForAccumulatorValue(prop->key());
+      Register scratch = x10;
+      Register scratch2 = x11;
+      __ Peek(scratch2, 2 * kPointerSize);  // value
+      // stack: value, this, home_object; x0: key, x11: value
+      __ Peek(scratch, kPointerSize);  // this
+      __ Poke(scratch, 2 * kPointerSize);
+      __ Peek(scratch, 0);  // home_object
+      __ Poke(scratch, kPointerSize);
+      __ Poke(x0, 0);
+      __ Move(x0, scratch2);
+      // stack: this, home_object, key; x0: value.
+      EmitKeyedSuperPropertyStore(prop);
+      break;
+    }
     case KEYED_PROPERTY: {
       __ Push(x0);  // Preserve value.
       VisitForStackValue(prop->obj());
@@ -2253,8 +2373,9 @@
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
+  } else if (IsSignallingAssignmentToConst(var, op, strict_mode())) {
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
   }
-  // Non-initializing assignments to consts are ignored.
 }
 
 
@@ -2277,6 +2398,35 @@
 }
 
 
+void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // x0 : value
+  // stack : receiver ('this'), home_object
+  DCHECK(prop != NULL);
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(key != NULL);
+
+  __ Push(key->value());
+  __ Push(x0);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
+                                          : Runtime::kStoreToSuper_Sloppy),
+                 4);
+}
+
+
+void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // x0 : value
+  // stack : receiver ('this'), home_object, key
+  DCHECK(prop != NULL);
+
+  __ Push(x0);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict
+                                          : Runtime::kStoreKeyedToSuper_Sloppy),
+                 4);
+}
+
+
 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
   ASM_LOCATION("FullCodeGenerator::EmitKeyedPropertyAssignment");
   // Assignment to a property, using a keyed store IC.
@@ -2305,16 +2455,27 @@
       __ Move(LoadDescriptor::ReceiverRegister(), x0);
       EmitNamedPropertyLoad(expr);
     } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
       EmitNamedSuperPropertyLoad(expr);
     }
     PrepareForBailoutForId(expr->LoadId(), TOS_REG);
     context()->Plug(x0);
   } else {
-    VisitForStackValue(expr->obj());
-    VisitForAccumulatorValue(expr->key());
-    __ Move(LoadDescriptor::NameRegister(), x0);
-    __ Pop(LoadDescriptor::ReceiverRegister());
-    EmitKeyedPropertyLoad(expr);
+    if (!expr->IsSuperAccess()) {
+      VisitForStackValue(expr->obj());
+      VisitForAccumulatorValue(expr->key());
+      __ Move(LoadDescriptor::NameRegister(), x0);
+      __ Pop(LoadDescriptor::ReceiverRegister());
+      EmitKeyedPropertyLoad(expr);
+    } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForStackValue(expr->key());
+      EmitKeyedSuperPropertyLoad(expr);
+    }
     context()->Plug(x0);
   }
 }
@@ -2379,14 +2540,14 @@
   VisitForAccumulatorValue(super_ref->this_var());
   __ Push(x0);
   __ Peek(scratch, kPointerSize);
-  __ Push(scratch, x0);
+  __ Push(x0, scratch);
   __ Push(key->value());
 
   // Stack here:
   //  - home_object
   //  - this (receiver)
-  //  - home_object <-- LoadFromSuper will pop here and below.
-  //  - this (receiver)
+  //  - this (receiver) <-- LoadFromSuper will pop here and below.
+  //  - home_object
   //  - key
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 
@@ -2423,6 +2584,43 @@
 }
 
 
+void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
+  Expression* callee = expr->expression();
+  DCHECK(callee->IsProperty());
+  Property* prop = callee->AsProperty();
+  DCHECK(prop->IsSuperAccess());
+
+  SetSourcePosition(prop->position());
+
+  // Load the function from the receiver.
+  const Register scratch = x10;
+  SuperReference* super_ref = callee->AsProperty()->obj()->AsSuperReference();
+  EmitLoadHomeObject(super_ref);
+  __ Push(x0);
+  VisitForAccumulatorValue(super_ref->this_var());
+  __ Push(x0);
+  __ Peek(scratch, kPointerSize);
+  __ Push(x0, scratch);
+  VisitForStackValue(prop->key());
+
+  // Stack here:
+  //  - home_object
+  //  - this (receiver)
+  //  - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
+  //  - home_object
+  //  - key
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+
+  // Replace home_object with target function.
+  __ Poke(x0, kPointerSize);
+
+  // Stack here:
+  // - target function
+  // - this (receiver)
+  EmitCall(expr, CallICState::METHOD);
+}
+
+
 void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
   // Load the arguments.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2437,7 +2635,7 @@
 
   Handle<Code> ic = CallIC::initialize_stub(
       isolate(), arg_count, call_type);
-  __ Mov(x3, Smi::FromInt(expr->CallFeedbackSlot()));
+  __ Mov(x3, SmiFromSlot(expr->CallFeedbackSlot()));
   __ Peek(x1, (arg_count + 1) * kXRegSize);
   // Don't assign a type feedback id to the IC, since type feedback is provided
   // by the vector above.
@@ -2478,6 +2676,14 @@
 }
 
 
+void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
+  DCHECK(super_ref != NULL);
+  __ ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ Push(x0);
+  __ CallRuntime(Runtime::kGetPrototype, 1);
+}
+
+
 void FullCodeGenerator::VisitCall(Call* expr) {
 #ifdef DEBUG
   // We want to verify that RecordJSReturnSite gets called on all paths
@@ -2517,6 +2723,8 @@
       // The runtime call returns a pair of values in x0 (function) and
       // x1 (receiver). Touch up the stack with the right values.
       __ PokePair(x1, x0, arg_count * kPointerSize);
+
+      PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
     }
 
     // Record source position for debugger.
@@ -2552,6 +2760,7 @@
     __ Push(context_register(), x10);
     __ CallRuntime(Runtime::kLoadLookupSlot, 2);
     __ Push(x0, x1);  // Receiver, function.
+    PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
 
     // If fast case code has been generated, emit code to push the
     // function and receiver and have the slow path jump around this
@@ -2574,9 +2783,12 @@
   } else if (call_type == Call::PROPERTY_CALL) {
     Property* property = callee->AsProperty();
     bool is_named_call = property->key()->IsPropertyName();
-    // super.x() is handled in EmitCallWithLoadIC.
-    if (property->IsSuperAccess() && is_named_call) {
-      EmitSuperCallWithLoadIC(expr);
+    if (property->IsSuperAccess()) {
+      if (is_named_call) {
+        EmitSuperCallWithLoadIC(expr);
+      } else {
+        EmitKeyedSuperCallWithLoadIC(expr);
+      }
     } else {
       {
         PreservePositionScope scope(masm()->positions_recorder());
@@ -2588,6 +2800,12 @@
         EmitKeyedCallWithLoadIC(expr, property->key());
       }
     }
+  } else if (call_type == Call::SUPER_CALL) {
+    SuperReference* super_ref = callee->AsSuperReference();
+    EmitLoadSuperConstructor(super_ref);
+    __ Push(result_register());
+    VisitForStackValue(super_ref->this_var());
+    EmitCall(expr, CallICState::METHOD);
   } else {
     DCHECK(call_type == Call::OTHER_CALL);
     // Call to an arbitrary expression not handled specially above.
@@ -2616,7 +2834,12 @@
   // Push constructor on the stack.  If it's not a function it's used as
   // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
   // ignored.
-  VisitForStackValue(expr->expression());
+  if (expr->expression()->IsSuperReference()) {
+    EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
+    __ Push(result_register());
+  } else {
+    VisitForStackValue(expr->expression());
+  }
 
   // Push the arguments ("left-to-right") on the stack.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2636,12 +2859,12 @@
   // Record call targets in unoptimized code.
   if (FLAG_pretenuring_call_new) {
     EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
-    DCHECK(expr->AllocationSiteFeedbackSlot() ==
-           expr->CallNewFeedbackSlot() + 1);
+    DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
+           expr->CallNewFeedbackSlot().ToInt() + 1);
   }
 
   __ LoadObject(x2, FeedbackVector());
-  __ Mov(x3, Smi::FromInt(expr->CallNewFeedbackSlot()));
+  __ Mov(x3, SmiFromSlot(expr->CallNewFeedbackSlot()));
 
   CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
@@ -2964,6 +3187,32 @@
 }
 
 
+void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ JumpIfSmi(x0, if_false);
+  Register map = x10;
+  Register type_reg = x11;
+  __ Ldr(map, FieldMemOperand(x0, HeapObject::kMapOffset));
+  __ Ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  __ Sub(type_reg, type_reg, Operand(FIRST_JS_PROXY_TYPE));
+  __ Cmp(type_reg, Operand(LAST_JS_PROXY_TYPE - FIRST_JS_PROXY_TYPE));
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(ls, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
 
 void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
   DCHECK(expr->arguments()->length() == 0);
@@ -3843,7 +4092,7 @@
     __ Mov(LoadDescriptor::NameRegister(), Operand(name));
     if (FLAG_vector_ics) {
       __ Mov(VectorLoadICDescriptor::SlotRegister(),
-             Smi::FromInt(expr->CallRuntimeFeedbackSlot()));
+             SmiFromSlot(expr->CallRuntimeFeedbackSlot()));
       CallLoadIC(NOT_CONTEXTUAL);
     } else {
       CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
@@ -3997,17 +4246,8 @@
   Comment cmnt(masm_, "[ CountOperation");
   SetSourcePosition(expr->position());
 
-  // Expression can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* prop = expr->expression()->AsProperty();
-  // In case of a property we use the uninitialized expression context
-  // of the key to detect a named property.
-  if (prop != NULL) {
-    assign_type =
-        (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(prop);
 
   // Evaluate expression and get value.
   if (assign_type == VARIABLE) {
@@ -4019,18 +4259,52 @@
     if (expr->is_postfix() && !context()->IsEffect()) {
       __ Push(xzr);
     }
-    if (assign_type == NAMED_PROPERTY) {
-      // Put the object both on the stack and in the register.
-      VisitForStackValue(prop->obj());
-      __ Peek(LoadDescriptor::ReceiverRegister(), 0);
-      EmitNamedPropertyLoad(prop);
-    } else {
-      // KEYED_PROPERTY
-      VisitForStackValue(prop->obj());
-      VisitForStackValue(prop->key());
-      __ Peek(LoadDescriptor::ReceiverRegister(), 1 * kPointerSize);
-      __ Peek(LoadDescriptor::NameRegister(), 0);
-      EmitKeyedPropertyLoad(prop);
+    switch (assign_type) {
+      case NAMED_PROPERTY: {
+        // Put the object both on the stack and in the register.
+        VisitForStackValue(prop->obj());
+        __ Peek(LoadDescriptor::ReceiverRegister(), 0);
+        EmitNamedPropertyLoad(prop);
+        break;
+      }
+
+      case NAMED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        __ Push(result_register());
+        const Register scratch = x10;
+        __ Peek(scratch, kPointerSize);
+        __ Push(scratch, result_register());
+        EmitNamedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        __ Push(result_register());
+        VisitForAccumulatorValue(prop->key());
+        __ Push(result_register());
+        const Register scratch1 = x10;
+        const Register scratch2 = x11;
+        __ Peek(scratch1, 2 * kPointerSize);
+        __ Peek(scratch2, kPointerSize);
+        __ Push(scratch1, scratch2, result_register());
+        EmitKeyedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_PROPERTY: {
+        VisitForStackValue(prop->obj());
+        VisitForStackValue(prop->key());
+        __ Peek(LoadDescriptor::ReceiverRegister(), 1 * kPointerSize);
+        __ Peek(LoadDescriptor::NameRegister(), 0);
+        EmitKeyedPropertyLoad(prop);
+        break;
+      }
+
+      case VARIABLE:
+        UNREACHABLE();
     }
   }
 
@@ -4064,9 +4338,15 @@
           case NAMED_PROPERTY:
             __ Poke(x0, kPointerSize);
             break;
+          case NAMED_SUPER_PROPERTY:
+            __ Poke(x0, kPointerSize * 2);
+            break;
           case KEYED_PROPERTY:
             __ Poke(x0, kPointerSize * 2);
             break;
+          case KEYED_SUPER_PROPERTY:
+            __ Poke(x0, kPointerSize * 3);
+            break;
         }
       }
     }
@@ -4094,9 +4374,15 @@
         case NAMED_PROPERTY:
           __ Poke(x0, kXRegSize);
           break;
+        case NAMED_SUPER_PROPERTY:
+          __ Poke(x0, 2 * kXRegSize);
+          break;
         case KEYED_PROPERTY:
           __ Poke(x0, 2 * kXRegSize);
           break;
+        case KEYED_SUPER_PROPERTY:
+          __ Poke(x0, 3 * kXRegSize);
+          break;
       }
     }
   }
@@ -4154,6 +4440,28 @@
       }
       break;
     }
+    case NAMED_SUPER_PROPERTY: {
+      EmitNamedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(x0);
+      }
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      EmitKeyedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(x0);
+      }
+      break;
+    }
     case KEYED_PROPERTY: {
       __ Pop(StoreDescriptor::NameRegister());
       __ Pop(StoreDescriptor::ReceiverRegister());
@@ -4184,7 +4492,7 @@
     __ Mov(LoadDescriptor::NameRegister(), Operand(proxy->name()));
     if (FLAG_vector_ics) {
       __ Mov(VectorLoadICDescriptor::SlotRegister(),
-             Smi::FromInt(proxy->VariableFeedbackSlot()));
+             SmiFromSlot(proxy->VariableFeedbackSlot()));
     }
     // Use a regular load, not a contextual load, to avoid a reference
     // error.
@@ -4540,7 +4848,7 @@
       __ Peek(load_name, 2 * kPointerSize);
       if (FLAG_vector_ics) {
         __ Mov(VectorLoadICDescriptor::SlotRegister(),
-               Smi::FromInt(expr->KeyedLoadFeedbackSlot()));
+               SmiFromSlot(expr->KeyedLoadFeedbackSlot()));
       }
       Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
       CallIC(ic, TypeFeedbackId::None());
@@ -4560,7 +4868,7 @@
       __ LoadRoot(load_name, Heap::kdone_stringRootIndex);  // "done"
       if (FLAG_vector_ics) {
         __ Mov(VectorLoadICDescriptor::SlotRegister(),
-               Smi::FromInt(expr->DoneFeedbackSlot()));
+               SmiFromSlot(expr->DoneFeedbackSlot()));
       }
       CallLoadIC(NOT_CONTEXTUAL);                           // x0=result.done
       // The ToBooleanStub argument (result.done) is in x0.
@@ -4573,7 +4881,7 @@
       __ LoadRoot(load_name, Heap::kvalue_stringRootIndex);  // "value"
       if (FLAG_vector_ics) {
         __ Mov(VectorLoadICDescriptor::SlotRegister(),
-               Smi::FromInt(expr->ValueFeedbackSlot()));
+               SmiFromSlot(expr->ValueFeedbackSlot()));
       }
       CallLoadIC(NOT_CONTEXTUAL);                            // x0=result.value
       context()->DropAndPlug(2, x0);                         // drop iter and g
@@ -4587,7 +4895,6 @@
     Expression *value,
     JSGeneratorObject::ResumeMode resume_mode) {
   ASM_LOCATION("FullCodeGenerator::EmitGeneratorResume");
-  Register value_reg = x0;
   Register generator_object = x1;
   Register the_hole = x2;
   Register operand_stack_size = w3;
@@ -4595,21 +4902,12 @@
 
   // The value stays in x0, and is ultimately read by the resumed generator, as
   // if CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it
-  // is read to throw the value when the resumed generator is already closed. r1
+  // is read to throw the value when the resumed generator is already closed. x1
   // will hold the generator object until the activation has been resumed.
   VisitForStackValue(generator);
   VisitForAccumulatorValue(value);
   __ Pop(generator_object);
 
-  // Check generator state.
-  Label wrong_state, closed_state, done;
-  __ Ldr(x10, FieldMemOperand(generator_object,
-                              JSGeneratorObject::kContinuationOffset));
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
-  __ CompareAndBranch(x10, Smi::FromInt(0), eq, &closed_state);
-  __ CompareAndBranch(x10, Smi::FromInt(0), lt, &wrong_state);
-
   // Load suspended function and context.
   __ Ldr(cp, FieldMemOperand(generator_object,
                              JSGeneratorObject::kContextOffset));
@@ -4635,7 +4933,7 @@
 
   // Enter a new JavaScript frame, and initialize its slots as they were when
   // the generator was suspended.
-  Label resume_frame;
+  Label resume_frame, done;
   __ Bl(&resume_frame);
   __ B(&done);
 
@@ -4680,26 +4978,6 @@
   // Not reached: the runtime call returns elsewhere.
   __ Unreachable();
 
-  // Reach here when generator is closed.
-  __ Bind(&closed_state);
-  if (resume_mode == JSGeneratorObject::NEXT) {
-    // Return completed iterator result when generator is closed.
-    __ LoadRoot(x10, Heap::kUndefinedValueRootIndex);
-    __ Push(x10);
-    // Pop value from top-of-stack slot; box result into result register.
-    EmitCreateIteratorResult(true);
-  } else {
-    // Throw the provided value.
-    __ Push(value_reg);
-    __ CallRuntime(Runtime::kThrow, 1);
-  }
-  __ B(&done);
-
-  // Throw error if we attempt to operate on a running generator.
-  __ Bind(&wrong_state);
-  __ Push(generator_object);
-  __ CallRuntime(Runtime::kThrowGeneratorStateError, 1);
-
   __ Bind(&done);
   context()->Plug(result_register());
 }
@@ -4709,16 +4987,18 @@
   Label gc_required;
   Label allocated;
 
-  Handle<Map> map(isolate()->native_context()->iterator_result_map());
+  const int instance_size = 5 * kPointerSize;
+  DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
+            instance_size);
 
   // Allocate and populate an object with this form: { value: VAL, done: DONE }
 
   Register result = x0;
-  __ Allocate(map->instance_size(), result, x10, x11, &gc_required, TAG_OBJECT);
+  __ Allocate(instance_size, result, x10, x11, &gc_required, TAG_OBJECT);
   __ B(&allocated);
 
   __ Bind(&gc_required);
-  __ Push(Smi::FromInt(map->instance_size()));
+  __ Push(Smi::FromInt(instance_size));
   __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
   __ Ldr(context_register(),
          MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -4729,11 +5009,13 @@
   Register boolean_done = x3;
   Register empty_fixed_array = x4;
   Register untagged_result = x5;
-  __ Mov(map_reg, Operand(map));
+  __ Ldr(map_reg, GlobalObjectMemOperand());
+  __ Ldr(map_reg, FieldMemOperand(map_reg, GlobalObject::kNativeContextOffset));
+  __ Ldr(map_reg,
+         ContextMemOperand(map_reg, Context::ITERATOR_RESULT_MAP_INDEX));
   __ Pop(result_value);
   __ Mov(boolean_done, Operand(isolate()->factory()->ToBoolean(done)));
   __ Mov(empty_fixed_array, Operand(isolate()->factory()->empty_fixed_array()));
-  DCHECK_EQ(map->instance_size(), 5 * kPointerSize);
   STATIC_ASSERT(JSObject::kPropertiesOffset + kPointerSize ==
                 JSObject::kElementsOffset);
   STATIC_ASSERT(JSGeneratorObject::kResultValuePropertyOffset + kPointerSize ==
@@ -4785,7 +5067,7 @@
 
 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
   Scope* declaration_scope = scope()->DeclarationScope();
-  if (declaration_scope->is_global_scope() ||
+  if (declaration_scope->is_script_scope() ||
       declaration_scope->is_module_scope()) {
     // Contexts nested in the native context have a canonical empty function
     // as their closure, not the anonymous closure containing the global
diff --git a/src/arm64/interface-descriptors-arm64.cc b/src/arm64/interface-descriptors-arm64.cc
index 690c8c2..57eebcc 100644
--- a/src/arm64/interface-descriptors-arm64.cc
+++ b/src/arm64/interface-descriptors-arm64.cc
@@ -29,6 +29,9 @@
 const Register StoreDescriptor::ValueRegister() { return x0; }
 
 
+const Register StoreTransitionDescriptor::MapRegister() { return x3; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() { return x3; }
 
 
@@ -182,6 +185,14 @@
 }
 
 
+void AllocateHeapNumberDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // cp: context
+  Register registers[] = {cp};
+  data->Initialize(arraysize(registers), registers, nullptr);
+}
+
+
 void ArrayConstructorConstantArgCountDescriptor::Initialize(
     CallInterfaceDescriptorData* data) {
   // cp: context
diff --git a/src/arm64/lithium-arm64.cc b/src/arm64/lithium-arm64.cc
index 502b046..2d5f7f2 100644
--- a/src/arm64/lithium-arm64.cc
+++ b/src/arm64/lithium-arm64.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <sstream>
+
 #include "src/v8.h"
 
 #include "src/arm64/lithium-codegen-arm64.h"
@@ -282,9 +284,9 @@
 
 void LStoreNamedField::PrintDataTo(StringStream* stream) {
   object()->PrintTo(stream);
-  OStringStream os;
+  std::ostringstream os;
   os << hydrogen()->access();
-  stream->Add(os.c_str());
+  stream->Add(os.str().c_str());
   stream->Add(" <- ");
   value()->PrintTo(stream);
 }
@@ -1562,9 +1564,17 @@
       UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
   LOperand* name_register =
       UseFixed(instr->name(), LoadDescriptor::NameRegister());
+  LOperand* slot = NULL;
+  LOperand* vector = NULL;
+  if (FLAG_vector_ics) {
+    slot = UseFixed(instr->slot(), VectorLoadICDescriptor::SlotRegister());
+    vector =
+        UseFixed(instr->vector(), VectorLoadICDescriptor::VectorRegister());
+  }
+
   // Not marked as call. It can't deoptimize, and it never returns.
   return new (zone()) LTailCallThroughMegamorphicCache(
-      context, receiver_register, name_register);
+      context, receiver_register, name_register, slot, vector);
 }
 
 
@@ -1673,7 +1683,7 @@
   LOperand* global_object =
       UseFixed(instr->global_object(), LoadDescriptor::ReceiverRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
 
@@ -1736,7 +1746,7 @@
       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
   LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
 
@@ -1758,7 +1768,7 @@
   LOperand* object =
       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
 
@@ -2234,11 +2244,7 @@
                            (JSShiftAmountFromHConstant(instr->right()) == 0);
   bool can_deopt = false;
   if ((op == Token::SHR) && right_can_be_zero) {
-    if (FLAG_opt_safe_uint32_operations) {
-      can_deopt = !instr->CheckFlag(HInstruction::kUint32);
-    } else {
-      can_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32);
-    }
+    can_deopt = !instr->CheckFlag(HInstruction::kUint32);
   }
 
   LInstruction* result;
@@ -2402,7 +2408,7 @@
   LOperand* temp1 = NULL;
 
   if (instr->access().IsExternalMemory() ||
-      instr->field_representation().IsDouble()) {
+      (!FLAG_unbox_double_fields && instr->field_representation().IsDouble())) {
     value = UseRegister(instr->value());
   } else if (instr->NeedsWriteBarrier()) {
     value = UseRegisterAndClobber(instr->value());
diff --git a/src/arm64/lithium-arm64.h b/src/arm64/lithium-arm64.h
index 6ead3fe..424ecba 100644
--- a/src/arm64/lithium-arm64.h
+++ b/src/arm64/lithium-arm64.h
@@ -178,17 +178,13 @@
   V(WrapReceiver)
 
 
-#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)                        \
-  virtual Opcode opcode() const FINAL OVERRIDE {                      \
-    return LInstruction::k##type;                                           \
-  }                                                                         \
-  virtual void CompileToNative(LCodeGen* generator) FINAL OVERRIDE;   \
-  virtual const char* Mnemonic() const FINAL OVERRIDE {               \
-    return mnemonic;                                                        \
-  }                                                                         \
-  static L##type* cast(LInstruction* instr) {                               \
-    DCHECK(instr->Is##type());                                              \
-    return reinterpret_cast<L##type*>(instr);                               \
+#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)            \
+  Opcode opcode() const FINAL { return LInstruction::k##type; } \
+  void CompileToNative(LCodeGen* generator) FINAL;              \
+  const char* Mnemonic() const FINAL { return mnemonic; }       \
+  static L##type* cast(LInstruction* instr) {                   \
+    DCHECK(instr->Is##type());                                  \
+    return reinterpret_cast<L##type*>(instr);                   \
   }
 
 
@@ -295,11 +291,9 @@
  public:
   // Allow 0 or 1 output operands.
   STATIC_ASSERT(R == 0 || R == 1);
-  virtual bool HasResult() const FINAL OVERRIDE {
-    return (R != 0) && (result() != NULL);
-  }
+  bool HasResult() const FINAL { return (R != 0) && (result() != NULL); }
   void set_result(LOperand* operand) { results_[0] = operand; }
-  LOperand* result() const { return results_[0]; }
+  LOperand* result() const OVERRIDE { return results_[0]; }
 
  protected:
   EmbeddedContainer<LOperand*, R> results_;
@@ -317,28 +311,32 @@
 
  private:
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return I; }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return I; }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return T; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return temps_[i]; }
+  int TempCount() FINAL { return T; }
+  LOperand* TempAt(int i) FINAL { return temps_[i]; }
 };
 
 
 class LTailCallThroughMegamorphicCache FINAL
-    : public LTemplateInstruction<0, 3, 0> {
+    : public LTemplateInstruction<0, 5, 0> {
  public:
-  explicit LTailCallThroughMegamorphicCache(LOperand* context,
-                                            LOperand* receiver,
-                                            LOperand* name) {
+  LTailCallThroughMegamorphicCache(LOperand* context, LOperand* receiver,
+                                   LOperand* name, LOperand* slot,
+                                   LOperand* vector) {
     inputs_[0] = context;
     inputs_[1] = receiver;
     inputs_[2] = name;
+    inputs_[3] = slot;
+    inputs_[4] = vector;
   }
 
   LOperand* context() { return inputs_[0]; }
   LOperand* receiver() { return inputs_[1]; }
   LOperand* name() { return inputs_[2]; }
+  LOperand* slot() { return inputs_[3]; }
+  LOperand* vector() { return inputs_[4]; }
 
   DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
                                "tail-call-through-megamorphic-cache")
@@ -348,9 +346,7 @@
 
 class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown-osr-value")
 };
 
@@ -360,7 +356,7 @@
  public:
   LControlInstruction() : false_label_(NULL), true_label_(NULL) { }
 
-  virtual bool IsControl() const FINAL OVERRIDE { return true; }
+  bool IsControl() const FINAL { return true; }
 
   int SuccessorCount() { return hydrogen()->SuccessorCount(); }
   HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); }
@@ -410,8 +406,8 @@
   }
 
   // Can't use the DECLARE-macro here because of sub-classes.
-  virtual bool IsGap() const OVERRIDE { return true; }
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsGap() const OVERRIDE { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   static LGap* cast(LInstruction* instr) {
     DCHECK(instr->IsGap());
     return reinterpret_cast<LGap*>(instr);
@@ -451,7 +447,7 @@
  public:
   explicit LInstructionGap(HBasicBlock* block) : LGap(block) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
     return !IsRedundant();
   }
 
@@ -492,10 +488,10 @@
  public:
   explicit LGoto(HBasicBlock* block) : block_(block) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
   DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
-  virtual bool IsControl() const OVERRIDE { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsControl() const OVERRIDE { return true; }
 
   int block_id() const { return block_->block_id(); }
 
@@ -525,12 +521,10 @@
   explicit LLabel(HBasicBlock* block)
       : LGap(block), replacement_(NULL) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(Label, "label")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int block_id() const { return block()->block_id(); }
   bool is_loop_header() const { return block()->IsLoopHeader(); }
@@ -550,9 +544,7 @@
  public:
   LOsrEntry() {}
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry")
 };
 
@@ -573,7 +565,7 @@
   LOperand* length() { return inputs_[1]; }
   LOperand* index() { return inputs_[2]; }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -721,11 +713,9 @@
   LOperand* left() { return inputs_[0]; }
   LOperand* right() { return inputs_[1]; }
 
-  virtual Opcode opcode() const OVERRIDE {
-    return LInstruction::kArithmeticD;
-  }
-  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
-  virtual const char* Mnemonic() const OVERRIDE;
+  Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticD; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
 
  private:
   Token::Value op_;
@@ -749,11 +739,9 @@
   LOperand* right() { return inputs_[2]; }
   Token::Value op() const { return op_; }
 
-  virtual Opcode opcode() const OVERRIDE {
-    return LInstruction::kArithmeticT;
-  }
-  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
-  virtual const char* Mnemonic() const OVERRIDE;
+  Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticT; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
 
  private:
   Token::Value op_;
@@ -838,7 +826,7 @@
   DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
   DECLARE_HYDROGEN_ACCESSOR(Branch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -853,7 +841,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallJSFunction, "call-js-function")
   DECLARE_HYDROGEN_ACCESSOR(CallJSFunction)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -889,7 +877,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
   DECLARE_HYDROGEN_ACCESSOR(CallNew)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -908,7 +896,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
   DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -925,7 +913,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
   DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
 
-  virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
+  bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
     return save_doubles() == kDontSaveFPRegs;
   }
 
@@ -1097,7 +1085,7 @@
                                "class-of-test-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1215,7 +1203,7 @@
     return hydrogen()->representation().IsDouble();
   }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1313,7 +1301,7 @@
 
 class LDeoptimize FINAL : public LTemplateInstruction<0, 0, 0> {
  public:
-  virtual bool IsControl() const OVERRIDE { return true; }
+  bool IsControl() const OVERRIDE { return true; }
   DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
   DECLARE_HYDROGEN_ACCESSOR(Deoptimize)
 };
@@ -1447,7 +1435,7 @@
                                "has-cached-array-index-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1465,7 +1453,7 @@
                                "has-instance-type-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1479,7 +1467,7 @@
   LOperand* base_object() const { return inputs_[0]; }
   LOperand* offset() const { return inputs_[1]; }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object")
 };
@@ -1555,11 +1543,12 @@
 
   CallInterfaceDescriptor descriptor() { return descriptor_; }
 
- private:
-  DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
   DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+ private:
+  DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 
@@ -1567,11 +1556,11 @@
   ZoneList<LOperand*> inputs_;
 
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return inputs_.length(); }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return inputs_.length(); }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return 0; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return NULL; }
+  int TempCount() FINAL { return 0; }
+  LOperand* TempAt(int i) FINAL { return NULL; }
 };
 
 
@@ -1588,7 +1577,7 @@
   DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function")
   DECLARE_HYDROGEN_ACCESSOR(InvokeFunction)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1624,7 +1613,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1641,7 +1630,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1656,7 +1645,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1674,7 +1663,7 @@
                                "is-undetectable-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1691,7 +1680,7 @@
 
   int slot_index() const { return hydrogen()->slot_index(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -2272,7 +2261,7 @@
 
 class LParameter FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const { return false; }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter")
 };
 
@@ -2331,11 +2320,11 @@
 
  private:
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return inputs_.length(); }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return inputs_.length(); }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return 0; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return NULL; }
+  int TempCount() FINAL { return 0; }
+  LOperand* TempAt(int i) FINAL { return NULL; }
 };
 
 
@@ -2585,7 +2574,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
   DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   StrictMode strict_mode() { return hydrogen()->strict_mode(); }
 };
@@ -2609,7 +2598,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
   DECLARE_HYDROGEN_ACCESSOR(StoreNamedField)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Representation representation() const {
     return hydrogen()->field_representation();
@@ -2632,7 +2621,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
   DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Handle<Object> name() const { return hydrogen()->name(); }
   StrictMode strict_mode() { return hydrogen()->strict_mode(); }
@@ -2707,7 +2696,7 @@
 
   Token::Value op() const { return hydrogen()->token(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -2786,7 +2775,7 @@
   LOperand* code_object() { return inputs_[1]; }
   LOperand* temp() { return temps_[0]; }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry, "store-code-entry")
   DECLARE_HYDROGEN_ACCESSOR(StoreCodeEntry)
@@ -2810,7 +2799,7 @@
 
   int slot_index() { return hydrogen()->slot_index(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -2916,7 +2905,7 @@
                                "transition-elements-kind")
   DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Handle<Map> original_map() { return hydrogen()->original_map().handle(); }
   Handle<Map> transitioned_map() {
@@ -2991,7 +2980,7 @@
 
   Handle<String> type_literal() const { return hydrogen()->type_literal(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc
index 2998642..df9e7b5 100644
--- a/src/arm64/lithium-codegen-arm64.cc
+++ b/src/arm64/lithium-codegen-arm64.cc
@@ -557,11 +557,6 @@
       safepoint.DefinePointerRegister(ToRegister(pointer), zone());
     }
   }
-
-  if (kind & Safepoint::kWithRegisters) {
-    // Register cp always contains a pointer to the context.
-    safepoint.DefinePointerRegister(cp, zone());
-  }
 }
 
 void LCodeGen::RecordSafepoint(LPointerMap* pointers,
@@ -1063,9 +1058,8 @@
 }
 
 
-void LCodeGen::Deoptimize(LInstruction* instr,
-                          Deoptimizer::BailoutType* override_bailout_type,
-                          const char* detail) {
+void LCodeGen::Deoptimize(LInstruction* instr, const char* detail,
+                          Deoptimizer::BailoutType* override_bailout_type) {
   DeoptimizeBranch(instr, detail, always, NoReg, -1, override_bailout_type);
 }
 
@@ -1516,7 +1510,7 @@
 
   if (can_overflow) {
     __ Adds(result, left, right);
-    DeoptimizeIf(vs, instr);
+    DeoptimizeIf(vs, instr, "overflow");
   } else {
     __ Add(result, left, right);
   }
@@ -1530,7 +1524,7 @@
   Operand right = ToOperand(instr->right());
   if (can_overflow) {
     __ Adds(result, left, right);
-    DeoptimizeIf(vs, instr);
+    DeoptimizeIf(vs, instr, "overflow");
   } else {
     __ Add(result, left, right);
   }
@@ -1656,7 +1650,7 @@
   // adaptor frame below it.
   const uint32_t kArgumentsLimit = 1 * KB;
   __ Cmp(length, kArgumentsLimit);
-  DeoptimizeIf(hi, instr);
+  DeoptimizeIf(hi, instr, "too many arguments");
 
   // Push the receiver and use the register to keep the original
   // number of arguments.
@@ -1838,7 +1832,7 @@
   if (FLAG_debug_code && instr->hydrogen()->skip_check()) {
     __ Assert(NegateCondition(cond), kEliminatedBoundsCheckFailed);
   } else {
-    DeoptimizeIf(cond, instr);
+    DeoptimizeIf(cond, instr, "out of bounds");
   }
 }
 
@@ -1917,7 +1911,7 @@
         __ JumpIfSmi(value, true_label);
       } else if (expected.NeedsMap()) {
         // If we need a map later and have a smi, deopt.
-        DeoptimizeIfSmi(value, instr);
+        DeoptimizeIfSmi(value, instr, "Smi");
       }
 
       Register map = NoReg;
@@ -1978,7 +1972,7 @@
       if (!expected.IsGeneric()) {
         // We've seen something for the first time -> deopt.
         // This can only happen if we are not generic already.
-        Deoptimize(instr);
+        Deoptimize(instr, "unexpected object");
       }
     }
   }
@@ -2048,23 +2042,33 @@
   DCHECK(name.is(LoadDescriptor::NameRegister()));
   DCHECK(receiver.is(x1));
   DCHECK(name.is(x2));
-
-  Register scratch = x3;
-  Register extra = x4;
-  Register extra2 = x5;
-  Register extra3 = x6;
+  Register scratch = x4;
+  Register extra = x5;
+  Register extra2 = x6;
+  Register extra3 = x7;
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(ToRegister(instr->slot()), ToRegister(instr->vector()),
+                     scratch, extra, extra2, extra3));
 
   // Important for the tail-call.
   bool must_teardown_frame = NeedsEagerFrame();
 
-  // The probe will tail call to a handler if found.
-  isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
-                                         must_teardown_frame, receiver, name,
-                                         scratch, extra, extra2, extra3);
+  if (!instr->hydrogen()->is_just_miss()) {
+    DCHECK(!instr->hydrogen()->is_keyed_load());
+
+    // The probe will tail call to a handler if found.
+    isolate()->stub_cache()->GenerateProbe(
+        masm(), Code::LOAD_IC, instr->hydrogen()->flags(), must_teardown_frame,
+        receiver, name, scratch, extra, extra2, extra3);
+  }
 
   // Tail call to miss if we ended up here.
   if (must_teardown_frame) __ LeaveFrame(StackFrame::INTERNAL);
-  LoadIC::GenerateMiss(masm());
+  if (instr->hydrogen()->is_keyed_load()) {
+    KeyedLoadIC::GenerateMiss(masm());
+  } else {
+    LoadIC::GenerateMiss(masm());
+  }
 }
 
 
@@ -2072,25 +2076,44 @@
   DCHECK(instr->IsMarkedAsCall());
   DCHECK(ToRegister(instr->result()).Is(x0));
 
-  LPointerMap* pointers = instr->pointer_map();
-  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+  if (instr->hydrogen()->IsTailCall()) {
+    if (NeedsEagerFrame()) __ LeaveFrame(StackFrame::INTERNAL);
 
-  if (instr->target()->IsConstantOperand()) {
-    LConstantOperand* target = LConstantOperand::cast(instr->target());
-    Handle<Code> code = Handle<Code>::cast(ToHandle(target));
-    generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
-    // TODO(all): on ARM we use a call descriptor to specify a storage mode
-    // but on ARM64 we only have one storage mode so it isn't necessary. Check
-    // this understanding is correct.
-    __ Call(code, RelocInfo::CODE_TARGET, TypeFeedbackId::None());
+    if (instr->target()->IsConstantOperand()) {
+      LConstantOperand* target = LConstantOperand::cast(instr->target());
+      Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+      // TODO(all): on ARM we use a call descriptor to specify a storage mode
+      // but on ARM64 we only have one storage mode so it isn't necessary. Check
+      // this understanding is correct.
+      __ Jump(code, RelocInfo::CODE_TARGET);
+    } else {
+      DCHECK(instr->target()->IsRegister());
+      Register target = ToRegister(instr->target());
+      __ Add(target, target, Code::kHeaderSize - kHeapObjectTag);
+      __ Br(target);
+    }
   } else {
-    DCHECK(instr->target()->IsRegister());
-    Register target = ToRegister(instr->target());
-    generator.BeforeCall(__ CallSize(target));
-    __ Add(target, target, Code::kHeaderSize - kHeapObjectTag);
-    __ Call(target);
+    LPointerMap* pointers = instr->pointer_map();
+    SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+
+    if (instr->target()->IsConstantOperand()) {
+      LConstantOperand* target = LConstantOperand::cast(instr->target());
+      Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+      generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
+      // TODO(all): on ARM we use a call descriptor to specify a storage mode
+      // but on ARM64 we only have one storage mode so it isn't necessary. Check
+      // this understanding is correct.
+      __ Call(code, RelocInfo::CODE_TARGET, TypeFeedbackId::None());
+    } else {
+      DCHECK(instr->target()->IsRegister());
+      Register target = ToRegister(instr->target());
+      generator.BeforeCall(__ CallSize(target));
+      __ Add(target, target, Code::kHeaderSize - kHeapObjectTag);
+      __ Call(target);
+    }
+    generator.AfterCall();
   }
-  generator.AfterCall();
+
   after_push_argument_ = false;
 }
 
@@ -2163,7 +2186,7 @@
         instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
     __ StoreToSafepointRegisterSlot(x0, temp);
   }
-  DeoptimizeIfSmi(temp, instr);
+  DeoptimizeIfSmi(temp, instr, "instance migration failed");
 }
 
 
@@ -2218,7 +2241,7 @@
   if (instr->hydrogen()->HasMigrationTarget()) {
     __ B(ne, deferred->entry());
   } else {
-    DeoptimizeIf(ne, instr);
+    DeoptimizeIf(ne, instr, "wrong map");
   }
 
   __ Bind(&success);
@@ -2227,7 +2250,7 @@
 
 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
   if (!instr->hydrogen()->value()->type().IsHeapObject()) {
-    DeoptimizeIfSmi(ToRegister(instr->value()), instr);
+    DeoptimizeIfSmi(ToRegister(instr->value()), instr, "Smi");
   }
 }
 
@@ -2235,7 +2258,7 @@
 void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
   Register value = ToRegister(instr->value());
   DCHECK(!instr->result() || ToRegister(instr->result()).Is(value));
-  DeoptimizeIfNotSmi(value, instr);
+  DeoptimizeIfNotSmi(value, instr, "not a Smi");
 }
 
 
@@ -2253,15 +2276,15 @@
     __ Cmp(scratch, first);
     if (first == last) {
       // If there is only one type in the interval check for equality.
-      DeoptimizeIf(ne, instr);
+      DeoptimizeIf(ne, instr, "wrong instance type");
     } else if (last == LAST_TYPE) {
       // We don't need to compare with the higher bound of the interval.
-      DeoptimizeIf(lo, instr);
+      DeoptimizeIf(lo, instr, "wrong instance type");
     } else {
       // If we are below the lower bound, set the C flag and clear the Z flag
       // to force a deopt.
       __ Ccmp(scratch, last, CFlag, hs);
-      DeoptimizeIf(hi, instr);
+      DeoptimizeIf(hi, instr, "wrong instance type");
     }
   } else {
     uint8_t mask;
@@ -2271,9 +2294,11 @@
     if (base::bits::IsPowerOfTwo32(mask)) {
       DCHECK((tag == 0) || (tag == mask));
       if (tag == 0) {
-        DeoptimizeIfBitSet(scratch, MaskToBit(mask), instr);
+        DeoptimizeIfBitSet(scratch, MaskToBit(mask), instr,
+                           "wrong instance type");
       } else {
-        DeoptimizeIfBitClear(scratch, MaskToBit(mask), instr);
+        DeoptimizeIfBitClear(scratch, MaskToBit(mask), instr,
+                             "wrong instance type");
       }
     } else {
       if (tag == 0) {
@@ -2282,7 +2307,7 @@
         __ And(scratch, scratch, mask);
         __ Cmp(scratch, tag);
       }
-      DeoptimizeIf(ne, instr);
+      DeoptimizeIf(ne, instr, "wrong instance type");
     }
   }
 }
@@ -2321,7 +2346,8 @@
   __ JumpIfHeapNumber(input, &is_heap_number);
 
   // Check for undefined. Undefined is coverted to zero for clamping conversion.
-  DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr);
+  DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr,
+                      "not a heap number/undefined");
   __ Mov(result, 0);
   __ B(&done);
 
@@ -2626,7 +2652,7 @@
   } else {
     __ Cmp(reg, Operand(object));
   }
-  DeoptimizeIf(ne, instr);
+  DeoptimizeIf(ne, instr, "value mismatch");
 }
 
 
@@ -2650,9 +2676,9 @@
   DCHECK(object.is(result) && object.Is(x0));
   DCHECK(instr->IsMarkedAsCall());
 
-  DeoptimizeIfSmi(object, instr);
+  DeoptimizeIfSmi(object, instr, "Smi");
   __ CompareObjectType(object, temp1, temp1, JS_DATE_TYPE);
-  DeoptimizeIf(ne, instr);
+  DeoptimizeIf(ne, instr, "not a date object");
 
   if (index->value() == 0) {
     __ Ldr(result, FieldMemOperand(object, JSDate::kValueOffset));
@@ -2688,7 +2714,7 @@
     type = Deoptimizer::LAZY;
   }
 
-  Deoptimize(instr, &type, instr->hydrogen()->reason());
+  Deoptimize(instr, instr->hydrogen()->reason(), &type);
 }
 
 
@@ -2702,21 +2728,21 @@
   // Check for (0 / -x) that will produce negative zero.
   HDiv* hdiv = instr->hydrogen();
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
-    DeoptimizeIfZero(dividend, instr);
+    DeoptimizeIfZero(dividend, instr, "division by zero");
   }
   // Check for (kMinInt / -1).
   if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) {
     // Test dividend for kMinInt by subtracting one (cmp) and checking for
     // overflow.
     __ Cmp(dividend, 1);
-    DeoptimizeIf(vs, instr);
+    DeoptimizeIf(vs, instr, "overflow");
   }
   // Deoptimize if remainder will not be 0.
   if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
       divisor != 1 && divisor != -1) {
     int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
     __ Tst(dividend, mask);
-    DeoptimizeIf(ne, instr);
+    DeoptimizeIf(ne, instr, "lost precision");
   }
 
   if (divisor == -1) {  // Nice shortcut, not needed for correctness.
@@ -2744,14 +2770,14 @@
   DCHECK(!AreAliased(dividend, result));
 
   if (divisor == 0) {
-    Deoptimize(instr);
+    Deoptimize(instr, "division by zero");
     return;
   }
 
   // Check for (0 / -x) that will produce negative zero.
   HDiv* hdiv = instr->hydrogen();
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
-    DeoptimizeIfZero(dividend, instr);
+    DeoptimizeIfZero(dividend, instr, "minus zero");
   }
 
   __ TruncatingDiv(result, dividend, Abs(divisor));
@@ -2763,7 +2789,7 @@
     __ Sxtw(dividend.X(), dividend);
     __ Mov(temp, divisor);
     __ Smsubl(temp.X(), result, temp, dividend.X());
-    DeoptimizeIfNotZero(temp, instr);
+    DeoptimizeIfNotZero(temp, instr, "lost precision");
   }
 }
 
@@ -2786,7 +2812,7 @@
 
   // Check for x / 0.
   if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
-    DeoptimizeIfZero(divisor, instr);
+    DeoptimizeIfZero(divisor, instr, "division by zero");
   }
 
   // Check for (0 / -x) as that will produce negative zero.
@@ -2798,7 +2824,7 @@
     // If the divisor >= 0 (pl, the opposite of mi) set the flags to
     // condition ne, so we don't deopt, ie. positive divisor doesn't deopt.
     __ Ccmp(dividend, 0, NoFlag, mi);
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "minus zero");
   }
 
   // Check for (kMinInt / -1).
@@ -2810,13 +2836,13 @@
     // -1. If overflow is clear, set the flags for condition ne, as the
     // dividend isn't -1, and thus we shouldn't deopt.
     __ Ccmp(divisor, -1, NoFlag, vs);
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "overflow");
   }
 
   // Compute remainder and deopt if it's not zero.
   Register remainder = ToRegister32(instr->temp());
   __ Msub(remainder, result, divisor, dividend);
-  DeoptimizeIfNotZero(remainder, instr);
+  DeoptimizeIfNotZero(remainder, instr, "lost precision");
 }
 
 
@@ -2825,11 +2851,11 @@
   Register result = ToRegister32(instr->result());
 
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-    DeoptimizeIfMinusZero(input, instr);
+    DeoptimizeIfMinusZero(input, instr, "minus zero");
   }
 
   __ TryRepresentDoubleAsInt32(result, input, double_scratch());
-  DeoptimizeIf(ne, instr);
+  DeoptimizeIf(ne, instr, "lost precision or NaN");
 
   if (instr->tag_result()) {
     __ SmiTag(result.X());
@@ -2890,7 +2916,7 @@
   __ LoadInstanceDescriptors(map, result);
   __ Ldr(result, FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
   __ Ldr(result, FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
-  DeoptimizeIfZero(result, instr);
+  DeoptimizeIfZero(result, instr, "no cache");
 
   __ Bind(&done);
 }
@@ -2903,17 +2929,17 @@
   DCHECK(instr->IsMarkedAsCall());
   DCHECK(object.Is(x0));
 
-  DeoptimizeIfRoot(object, Heap::kUndefinedValueRootIndex, instr);
+  DeoptimizeIfRoot(object, Heap::kUndefinedValueRootIndex, instr, "undefined");
 
   __ LoadRoot(null_value, Heap::kNullValueRootIndex);
   __ Cmp(object, null_value);
-  DeoptimizeIf(eq, instr);
+  DeoptimizeIf(eq, instr, "null");
 
-  DeoptimizeIfSmi(object, instr);
+  DeoptimizeIfSmi(object, instr, "Smi");
 
   STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
   __ CompareObjectType(object, x1, x1, LAST_JS_PROXY_TYPE);
-  DeoptimizeIf(le, instr);
+  DeoptimizeIf(le, instr, "not a JavaScript object");
 
   Label use_cache, call_runtime;
   __ CheckEnumCache(object, null_value, x1, x2, x3, x4, &call_runtime);
@@ -2927,7 +2953,7 @@
   CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
 
   __ Ldr(x1, FieldMemOperand(object, HeapObject::kMapOffset));
-  DeoptimizeIfNotRoot(x1, Heap::kMetaMapRootIndex, instr);
+  DeoptimizeIfNotRoot(x1, Heap::kMetaMapRootIndex, instr, "wrong map");
 
   __ Bind(&use_cache);
 }
@@ -3320,7 +3346,7 @@
   __ Ldr(result, ContextMemOperand(context, instr->slot_index()));
   if (instr->hydrogen()->RequiresHoleCheck()) {
     if (instr->hydrogen()->DeoptimizesOnHole()) {
-      DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr);
+      DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr, "hole");
     } else {
       Label not_the_hole;
       __ JumpIfNotRoot(result, Heap::kTheHoleValueRootIndex, &not_the_hole);
@@ -3341,7 +3367,7 @@
                                  JSFunction::kPrototypeOrInitialMapOffset));
 
   // Check that the function has a prototype or an initial map.
-  DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr);
+  DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr, "hole");
 
   // If the function does not have an initial map, we're done.
   Label done;
@@ -3361,7 +3387,7 @@
   __ Mov(result, Operand(Handle<Object>(instr->hydrogen()->cell().handle())));
   __ Ldr(result, FieldMemOperand(result, Cell::kValueOffset));
   if (instr->hydrogen()->RequiresHoleCheck()) {
-    DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr);
+    DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr, "hole");
   }
 }
 
@@ -3369,13 +3395,18 @@
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
-  Register vector = ToRegister(instr->temp_vector());
-  DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
-  __ Mov(vector, instr->hydrogen()->feedback_vector());
+  Register vector_register = ToRegister(instr->temp_vector());
+  Register slot_register = VectorLoadICDescriptor::SlotRegister();
+  DCHECK(vector_register.is(VectorLoadICDescriptor::VectorRegister()));
+  DCHECK(slot_register.is(x0));
+
+  AllowDeferredHandleDereference vector_structure_check;
+  Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+  __ Mov(vector_register, vector);
   // No need to allocate this register.
-  DCHECK(VectorLoadICDescriptor::SlotRegister().is(x0));
-  __ Mov(VectorLoadICDescriptor::SlotRegister(),
-         Smi::FromInt(instr->hydrogen()->slot()));
+  FeedbackVectorICSlot slot = instr->hydrogen()->slot();
+  int index = vector->GetIndex(slot);
+  __ Mov(slot_register, Smi::FromInt(index));
 }
 
 
@@ -3389,7 +3420,7 @@
     EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
   }
   ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), mode).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3492,7 +3523,7 @@
         if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
           // Deopt if value > 0x80000000.
           __ Tst(result, 0xFFFFFFFF80000000);
-          DeoptimizeIf(ne, instr);
+          DeoptimizeIf(ne, instr, "negative value");
         }
         break;
       case FLOAT32_ELEMENTS:
@@ -3589,7 +3620,7 @@
     STATIC_ASSERT(kHoleNanInt64 == 0x7fffffffffffffff);
     __ Ldr(scratch, mem_op);
     __ Cmn(scratch, 1);
-    DeoptimizeIf(vs, instr);
+    DeoptimizeIf(vs, instr, "hole");
   }
 }
 
@@ -3627,9 +3658,9 @@
 
   if (instr->hydrogen()->RequiresHoleCheck()) {
     if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
-      DeoptimizeIfNotSmi(result, instr);
+      DeoptimizeIfNotSmi(result, instr, "not a Smi");
     } else {
-      DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr);
+      DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr, "hole");
     }
   }
 }
@@ -3643,7 +3674,7 @@
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
+  Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 
   DCHECK(ToRegister(instr->result()).Is(x0));
@@ -3662,6 +3693,7 @@
   }
 
   if (instr->hydrogen()->representation().IsDouble()) {
+    DCHECK(access.IsInobject());
     FPRegister result = ToDoubleRegister(instr->result());
     __ Ldr(result, FieldMemOperand(object, offset));
     return;
@@ -3699,7 +3731,8 @@
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic =
+      CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 
   DCHECK(ToRegister(instr->result()).is(x0));
@@ -3731,7 +3764,7 @@
     Register result = r.IsSmi() ? ToRegister(instr->result())
                                 : ToRegister32(instr->result());
     __ Abs(result, input);
-    DeoptimizeIf(vs, instr);
+    DeoptimizeIf(vs, instr, "overflow");
   }
 }
 
@@ -3883,7 +3916,7 @@
   Register result = ToRegister(instr->result());
 
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-    DeoptimizeIfMinusZero(input, instr);
+    DeoptimizeIfMinusZero(input, instr, "minus zero");
   }
 
   __ Fcvtms(result, input);
@@ -3893,7 +3926,7 @@
   __ Cmp(result, Operand(result, SXTW));
   //  - The input was not NaN.
   __ Fccmp(input, input, NoFlag, eq);
-  DeoptimizeIf(ne, instr);
+  DeoptimizeIf(ne, instr, "lost precision or NaN");
 }
 
 
@@ -3919,13 +3952,13 @@
   // If the divisor is negative, we have to negate and handle edge cases.
   __ Negs(result, dividend);
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "minus zero");
   }
 
   // Dividing by -1 is basically negation, unless we overflow.
   if (divisor == -1) {
     if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
-      DeoptimizeIf(vs, instr);
+      DeoptimizeIf(vs, instr, "overflow");
     }
     return;
   }
@@ -3948,14 +3981,14 @@
   DCHECK(!AreAliased(dividend, result));
 
   if (divisor == 0) {
-    Deoptimize(instr);
+    Deoptimize(instr, "division by zero");
     return;
   }
 
   // Check for (0 / -x) that will produce negative zero.
   HMathFloorOfDiv* hdiv = instr->hydrogen();
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
-    DeoptimizeIfZero(dividend, instr);
+    DeoptimizeIfZero(dividend, instr, "minus zero");
   }
 
   // Easy case: We need no dynamic check for the dividend and the flooring
@@ -3998,14 +4031,14 @@
   __ Sdiv(result, dividend, divisor);
 
   // Check for x / 0.
-  DeoptimizeIfZero(divisor, instr);
+  DeoptimizeIfZero(divisor, instr, "division by zero");
 
   // Check for (kMinInt / -1).
   if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
     // The V flag will be set iff dividend == kMinInt.
     __ Cmp(dividend, 1);
     __ Ccmp(divisor, -1, NoFlag, vs);
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "overflow");
   }
 
   // Check for (0 / -x) that will produce negative zero.
@@ -4015,7 +4048,7 @@
     // "divisor" can't be null because the code would have already been
     // deoptimized. The Z flag is set only if (divisor < 0) and (dividend == 0).
     // In this case we need to deoptimize to produce a -0.
-    DeoptimizeIf(eq, instr);
+    DeoptimizeIf(eq, instr, "minus zero");
   }
 
   Label done;
@@ -4174,18 +4207,18 @@
 
   // Deoptimize if the result > 1, as it must be larger than 32 bits.
   __ Cmp(result, 1);
-  DeoptimizeIf(hi, instr);
+  DeoptimizeIf(hi, instr, "overflow");
 
   // Deoptimize for negative inputs, which at this point are only numbers in
   // the range [-0.5, -0.0]
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     __ Fmov(result, input);
-    DeoptimizeIfNegative(result, instr);
+    DeoptimizeIfNegative(result, instr, "minus zero");
   }
 
   // Deoptimize if the input was NaN.
   __ Fcmp(input, dot_five);
-  DeoptimizeIf(vs, instr);
+  DeoptimizeIf(vs, instr, "NaN");
 
   // Now, the only unhandled inputs are in the range [0.0, 1.5[ (or [-0.5, 1.5[
   // if we didn't generate a -0.0 bailout). If input >= 0.5 then return 1,
@@ -4263,7 +4296,7 @@
     __ And(dividend, dividend, mask);
     __ Negs(dividend, dividend);
     if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
-      DeoptimizeIf(eq, instr);
+      DeoptimizeIf(eq, instr, "minus zero");
     }
     __ B(&done);
   }
@@ -4282,7 +4315,7 @@
   DCHECK(!AreAliased(dividend, result, temp));
 
   if (divisor == 0) {
-    Deoptimize(instr);
+    Deoptimize(instr, "division by zero");
     return;
   }
 
@@ -4296,7 +4329,7 @@
   if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
     Label remainder_not_zero;
     __ Cbnz(result, &remainder_not_zero);
-    DeoptimizeIfNegative(dividend, instr);
+    DeoptimizeIfNegative(dividend, instr, "minus zero");
     __ bind(&remainder_not_zero);
   }
 }
@@ -4311,12 +4344,12 @@
   // modulo = dividend - quotient * divisor
   __ Sdiv(result, dividend, divisor);
   if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
-    DeoptimizeIfZero(divisor, instr);
+    DeoptimizeIfZero(divisor, instr, "division by zero");
   }
   __ Msub(result, result, divisor, dividend);
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     __ Cbnz(result, &done);
-    DeoptimizeIfNegative(dividend, instr);
+    DeoptimizeIfNegative(dividend, instr, "minus zero");
   }
   __ Bind(&done);
 }
@@ -4339,10 +4372,10 @@
   if (bailout_on_minus_zero) {
     if (right < 0) {
       // The result is -0 if right is negative and left is zero.
-      DeoptimizeIfZero(left, instr);
+      DeoptimizeIfZero(left, instr, "minus zero");
     } else if (right == 0) {
       // The result is -0 if the right is zero and the left is negative.
-      DeoptimizeIfNegative(left, instr);
+      DeoptimizeIfNegative(left, instr, "minus zero");
     }
   }
 
@@ -4352,7 +4385,7 @@
       if (can_overflow) {
         // Only 0x80000000 can overflow here.
         __ Negs(result, left);
-        DeoptimizeIf(vs, instr);
+        DeoptimizeIf(vs, instr, "overflow");
       } else {
         __ Neg(result, left);
       }
@@ -4368,7 +4401,7 @@
     case 2:
       if (can_overflow) {
         __ Adds(result, left, left);
-        DeoptimizeIf(vs, instr);
+        DeoptimizeIf(vs, instr, "overflow");
       } else {
         __ Add(result, left, left);
       }
@@ -4387,7 +4420,7 @@
           DCHECK(!AreAliased(scratch, left));
           __ Cls(scratch, left);
           __ Cmp(scratch, right_log2);
-          DeoptimizeIf(lt, instr);
+          DeoptimizeIf(lt, instr, "overflow");
         }
 
         if (right >= 0) {
@@ -4397,7 +4430,7 @@
           // result = -left << log2(-right)
           if (can_overflow) {
             __ Negs(result, Operand(left, LSL, right_log2));
-            DeoptimizeIf(vs, instr);
+            DeoptimizeIf(vs, instr, "overflow");
           } else {
             __ Neg(result, Operand(left, LSL, right_log2));
           }
@@ -4455,13 +4488,13 @@
     //  - If so (eq), set N (mi) if left + right is negative.
     //  - Otherwise, clear N.
     __ Ccmn(left, right, NoFlag, eq);
-    DeoptimizeIf(mi, instr);
+    DeoptimizeIf(mi, instr, "minus zero");
   }
 
   if (can_overflow) {
     __ Smull(result.X(), left, right);
     __ Cmp(result.X(), Operand(result, SXTW));
-    DeoptimizeIf(ne, instr);
+    DeoptimizeIf(ne, instr, "overflow");
   } else {
     __ Mul(result, left, right);
   }
@@ -4485,7 +4518,7 @@
     //  - If so (eq), set N (mi) if left + right is negative.
     //  - Otherwise, clear N.
     __ Ccmn(left, right, NoFlag, eq);
-    DeoptimizeIf(mi, instr);
+    DeoptimizeIf(mi, instr, "minus zero");
   }
 
   STATIC_ASSERT((kSmiShift == 32) && (kSmiTag == 0));
@@ -4493,7 +4526,7 @@
     __ Smulh(result, left, right);
     __ Cmp(result, Operand(result.W(), SXTW));
     __ SmiTag(result);
-    DeoptimizeIf(ne, instr);
+    DeoptimizeIf(ne, instr, "overflow");
   } else {
     if (AreAliased(result, left, right)) {
       // All three registers are the same: half untag the input and then
@@ -4669,13 +4702,14 @@
     // Load heap number.
     __ Ldr(result, FieldMemOperand(input, HeapNumber::kValueOffset));
     if (instr->hydrogen()->deoptimize_on_minus_zero()) {
-      DeoptimizeIfMinusZero(result, instr);
+      DeoptimizeIfMinusZero(result, instr, "minus zero");
     }
     __ B(&done);
 
     if (can_convert_undefined_to_nan) {
       __ Bind(&convert_undefined);
-      DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr);
+      DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr,
+                          "not a heap number/undefined");
 
       __ LoadRoot(scratch, Heap::kNanValueRootIndex);
       __ Ldr(result, FieldMemOperand(scratch, HeapNumber::kValueOffset));
@@ -4766,6 +4800,7 @@
     int parameter_count = ToInteger32(instr->constant_parameter_count());
     __ Drop(parameter_count + 1);
   } else {
+    DCHECK(info()->IsStub());  // Functions would need to drop one more value.
     Register parameter_count = ToRegister(instr->parameter_count());
     __ DropBySMI(parameter_count);
   }
@@ -4868,7 +4903,7 @@
   Register output = ToRegister(instr->result());
   if (hchange->CheckFlag(HValue::kCanOverflow) &&
       hchange->value()->CheckFlag(HValue::kUint32)) {
-    DeoptimizeIfNegative(input.W(), instr);
+    DeoptimizeIfNegative(input.W(), instr, "overflow");
   }
   __ SmiTag(output, input);
 }
@@ -4880,7 +4915,7 @@
   Label done, untag;
 
   if (instr->needs_check()) {
-    DeoptimizeIfNotSmi(input, instr);
+    DeoptimizeIfNotSmi(input, instr, "not a Smi");
   }
 
   __ Bind(&untag);
@@ -4905,7 +4940,7 @@
         if (instr->can_deopt()) {
           // If `left >>> right` >= 0x80000000, the result is not representable
           // in a signed 32-bit smi.
-          DeoptimizeIfNegative(result, instr);
+          DeoptimizeIfNegative(result, instr, "negative value");
         }
         break;
       default: UNREACHABLE();
@@ -4915,7 +4950,7 @@
     int shift_count = JSShiftAmountFromLConstant(right_op);
     if (shift_count == 0) {
       if ((instr->op() == Token::SHR) && instr->can_deopt()) {
-        DeoptimizeIfNegative(left, instr);
+        DeoptimizeIfNegative(left, instr, "negative value");
       }
       __ Mov(result, left, kDiscardForSameWReg);
     } else {
@@ -4968,7 +5003,7 @@
         if (instr->can_deopt()) {
           // If `left >>> right` >= 0x80000000, the result is not representable
           // in a signed 32-bit smi.
-          DeoptimizeIfNegative(result, instr);
+          DeoptimizeIfNegative(result, instr, "negative value");
         }
         break;
       default: UNREACHABLE();
@@ -4978,7 +5013,7 @@
     int shift_count = JSShiftAmountFromLConstant(right_op);
     if (shift_count == 0) {
       if ((instr->op() == Token::SHR) && instr->can_deopt()) {
-        DeoptimizeIfNegative(left, instr);
+        DeoptimizeIfNegative(left, instr, "negative value");
       }
       __ Mov(result, left);
     } else {
@@ -5017,7 +5052,6 @@
   Register scratch2 = x6;
   DCHECK(instr->IsMarkedAsCall());
 
-  ASM_UNIMPLEMENTED_BREAK("DoDeclareGlobals");
   // TODO(all): if Mov could handle object in new space then it could be used
   // here.
   __ LoadHeapObject(scratch1, instr->hydrogen()->pairs());
@@ -5107,7 +5141,7 @@
   if (instr->hydrogen()->RequiresHoleCheck()) {
     __ Ldr(scratch, target);
     if (instr->hydrogen()->DeoptimizesOnHole()) {
-      DeoptimizeIfRoot(scratch, Heap::kTheHoleValueRootIndex, instr);
+      DeoptimizeIfRoot(scratch, Heap::kTheHoleValueRootIndex, instr, "hole");
     } else {
       __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, &skip_assignment);
     }
@@ -5145,7 +5179,7 @@
   if (instr->hydrogen()->RequiresHoleCheck()) {
     Register payload = ToRegister(instr->temp2());
     __ Ldr(payload, FieldMemOperand(cell, Cell::kValueOffset));
-    DeoptimizeIfRoot(payload, Heap::kTheHoleValueRootIndex, instr);
+    DeoptimizeIfRoot(payload, Heap::kTheHoleValueRootIndex, instr, "hole");
   }
 
   // Store the value.
@@ -5349,7 +5383,7 @@
 
   __ AssertNotSmi(object);
 
-  if (representation.IsDouble()) {
+  if (!FLAG_unbox_double_fields && representation.IsDouble()) {
     DCHECK(access.IsInobject());
     DCHECK(!instr->hydrogen()->has_transition());
     DCHECK(!instr->hydrogen()->NeedsWriteBarrier());
@@ -5358,8 +5392,6 @@
     return;
   }
 
-  Register value = ToRegister(instr->value());
-
   DCHECK(!representation.IsSmi() ||
          !instr->value()->IsConstantOperand() ||
          IsInteger32Constant(LConstantOperand::cast(instr->value())));
@@ -5391,8 +5423,12 @@
     destination = temp0;
   }
 
-  if (representation.IsSmi() &&
-     instr->hydrogen()->value()->representation().IsInteger32()) {
+  if (FLAG_unbox_double_fields && representation.IsDouble()) {
+    DCHECK(access.IsInobject());
+    FPRegister value = ToDoubleRegister(instr->value());
+    __ Str(value, FieldMemOperand(object, offset));
+  } else if (representation.IsSmi() &&
+             instr->hydrogen()->value()->representation().IsInteger32()) {
     DCHECK(instr->hydrogen()->store_mode() == STORE_TO_INITIALIZED_ENTRY);
 #ifdef DEBUG
     Register temp0 = ToRegister(instr->temp0());
@@ -5407,12 +5443,15 @@
 #endif
     STATIC_ASSERT(static_cast<unsigned>(kSmiValueSize) == kWRegSizeInBits);
     STATIC_ASSERT(kSmiTag == 0);
+    Register value = ToRegister(instr->value());
     __ Store(value, UntagSmiFieldMemOperand(destination, offset),
              Representation::Integer32());
   } else {
+    Register value = ToRegister(instr->value());
     __ Store(value, FieldMemOperand(destination, offset), representation);
   }
   if (instr->hydrogen()->NeedsWriteBarrier()) {
+    Register value = ToRegister(instr->value());
     __ RecordWriteField(destination,
                         offset,
                         value,                        // Clobbered.
@@ -5562,7 +5601,7 @@
 
   if (can_overflow) {
     __ Subs(result, left, right);
-    DeoptimizeIf(vs, instr);
+    DeoptimizeIf(vs, instr, "overflow");
   } else {
     __ Sub(result, left, right);
   }
@@ -5576,7 +5615,7 @@
   Operand right = ToOperand(instr->right());
   if (can_overflow) {
     __ Subs(result, left, right);
-    DeoptimizeIf(vs, instr);
+    DeoptimizeIf(vs, instr, "overflow");
   } else {
     __ Sub(result, left, right);
   }
@@ -5616,7 +5655,8 @@
 
     // Output contains zero, undefined is converted to zero for truncating
     // conversions.
-    DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr);
+    DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr,
+                        "not a heap number/undefined/true/false");
   } else {
     Register output = ToRegister32(instr->result());
     DoubleRegister dbl_scratch2 = ToDoubleRegister(temp2);
@@ -5774,7 +5814,7 @@
 
   Label no_memento_found;
   __ TestJSArrayForAllocationMemento(object, temp1, temp2, &no_memento_found);
-  DeoptimizeIf(eq, instr);
+  DeoptimizeIf(eq, instr, "memento found");
   __ Bind(&no_memento_found);
 }
 
@@ -5899,7 +5939,7 @@
   Register temp = ToRegister(instr->temp());
   __ Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
   __ Cmp(map, temp);
-  DeoptimizeIf(ne, instr);
+  DeoptimizeIf(ne, instr, "wrong map");
 }
 
 
@@ -5933,10 +5973,10 @@
   __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex, &global_object);
 
   // Deoptimize if the receiver is not a JS object.
-  DeoptimizeIfSmi(receiver, instr);
+  DeoptimizeIfSmi(receiver, instr, "Smi");
   __ CompareObjectType(receiver, result, result, FIRST_SPEC_OBJECT_TYPE);
   __ B(ge, &copy_receiver);
-  Deoptimize(instr);
+  Deoptimize(instr, "not a JavaScript object");
 
   __ Bind(&global_object);
   __ Ldr(result, FieldMemOperand(function, JSFunction::kContextOffset));
@@ -5979,10 +6019,11 @@
           object_(object),
           index_(index) {
     }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredLoadMutableDouble(instr_, result_, object_, index_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LLoadFieldByIndex* instr_;
     Register result_;
diff --git a/src/arm64/lithium-codegen-arm64.h b/src/arm64/lithium-codegen-arm64.h
index a141dfa..a73bb8c 100644
--- a/src/arm64/lithium-codegen-arm64.h
+++ b/src/arm64/lithium-codegen-arm64.h
@@ -217,32 +217,27 @@
                         BranchType branch_type, Register reg = NoReg,
                         int bit = -1,
                         Deoptimizer::BailoutType* override_bailout_type = NULL);
-  void Deoptimize(LInstruction* instr,
-                  Deoptimizer::BailoutType* override_bailout_type = NULL,
-                  const char* detail = NULL);
-  void DeoptimizeIf(Condition cond, LInstruction* instr,
-                    const char* detail = NULL);
-  void DeoptimizeIfZero(Register rt, LInstruction* instr,
-                        const char* detail = NULL);
+  void Deoptimize(LInstruction* instr, const char* detail,
+                  Deoptimizer::BailoutType* override_bailout_type = NULL);
+  void DeoptimizeIf(Condition cond, LInstruction* instr, const char* detail);
+  void DeoptimizeIfZero(Register rt, LInstruction* instr, const char* detail);
   void DeoptimizeIfNotZero(Register rt, LInstruction* instr,
-                           const char* detail = NULL);
+                           const char* detail);
   void DeoptimizeIfNegative(Register rt, LInstruction* instr,
-                            const char* detail = NULL);
-  void DeoptimizeIfSmi(Register rt, LInstruction* instr,
-                       const char* detail = NULL);
-  void DeoptimizeIfNotSmi(Register rt, LInstruction* instr,
-                          const char* detail = NULL);
+                            const char* detail);
+  void DeoptimizeIfSmi(Register rt, LInstruction* instr, const char* detail);
+  void DeoptimizeIfNotSmi(Register rt, LInstruction* instr, const char* detail);
   void DeoptimizeIfRoot(Register rt, Heap::RootListIndex index,
-                        LInstruction* instr, const char* detail = NULL);
+                        LInstruction* instr, const char* detail);
   void DeoptimizeIfNotRoot(Register rt, Heap::RootListIndex index,
-                           LInstruction* instr, const char* detail = NULL);
+                           LInstruction* instr, const char* detail);
   void DeoptimizeIfNotHeapNumber(Register object, LInstruction* instr);
   void DeoptimizeIfMinusZero(DoubleRegister input, LInstruction* instr,
-                             const char* detail = NULL);
+                             const char* detail);
   void DeoptimizeIfBitSet(Register rt, int bit, LInstruction* instr,
-                          const char* detail = NULL);
+                          const char* detail);
   void DeoptimizeIfBitClear(Register rt, int bit, LInstruction* instr,
-                            const char* detail = NULL);
+                            const char* detail);
 
   MemOperand PrepareKeyedExternalArrayOperand(Register key,
                                               Register base,
diff --git a/src/arm64/macro-assembler-arm64-inl.h b/src/arm64/macro-assembler-arm64-inl.h
index 23767e4..b691e21 100644
--- a/src/arm64/macro-assembler-arm64-inl.h
+++ b/src/arm64/macro-assembler-arm64-inl.h
@@ -825,6 +825,12 @@
 }
 
 
+void MacroAssembler::Frintp(const FPRegister& fd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  frintp(fd, fn);
+}
+
+
 void MacroAssembler::Frintz(const FPRegister& fd, const FPRegister& fn) {
   DCHECK(allow_macro_instructions_);
   frintz(fd, fn);
@@ -1120,6 +1126,14 @@
 }
 
 
+void MacroAssembler::Umull(const Register& rd, const Register& rn,
+                           const Register& rm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  umaddl(rd, rn, rm, xzr);
+}
+
+
 void MacroAssembler::Stnp(const CPURegister& rt,
                           const CPURegister& rt2,
                           const MemOperand& dst) {
@@ -1230,14 +1244,7 @@
 void MacroAssembler::BumpSystemStackPointer(const Operand& space) {
   DCHECK(!csp.Is(sp_));
   if (!TmpList()->IsEmpty()) {
-    if (CpuFeatures::IsSupported(ALWAYS_ALIGN_CSP)) {
-      UseScratchRegisterScope temps(this);
-      Register temp = temps.AcquireX();
-      Sub(temp, StackPointer(), space);
-      Bic(csp, temp, 0xf);
-    } else {
-      Sub(csp, StackPointer(), space);
-    }
+    Sub(csp, StackPointer(), space);
   } else {
     // TODO(jbramley): Several callers rely on this not using scratch
     // registers, so we use the assembler directly here. However, this means
@@ -1274,11 +1281,7 @@
   DCHECK(emit_debug_code());
   DCHECK(!csp.Is(sp_));
   { InstructionAccurateScope scope(this);
-    if (CpuFeatures::IsSupported(ALWAYS_ALIGN_CSP)) {
-      bic(csp, StackPointer(), 0xf);
-    } else {
-      mov(csp, StackPointer());
-    }
+    mov(csp, StackPointer());
   }
   AssertStackConsistency();
 }
diff --git a/src/arm64/macro-assembler-arm64.cc b/src/arm64/macro-assembler-arm64.cc
index f670403..0253e7c 100644
--- a/src/arm64/macro-assembler-arm64.cc
+++ b/src/arm64/macro-assembler-arm64.cc
@@ -13,7 +13,7 @@
 #include "src/cpu-profiler.h"
 #include "src/debug.h"
 #include "src/isolate-inl.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -1308,7 +1308,7 @@
   // Avoid emitting code when !use_real_abort() since non-real aborts cause too
   // much code to be generated.
   if (emit_debug_code() && use_real_aborts()) {
-    if (csp.Is(StackPointer()) || CpuFeatures::IsSupported(ALWAYS_ALIGN_CSP)) {
+    if (csp.Is(StackPointer())) {
       // Always check the alignment of csp if ALWAYS_ALIGN_CSP is true.  We
       // can't check the alignment of csp without using a scratch register (or
       // clobbering the flags), but the processor (or simulator) will abort if
@@ -3064,6 +3064,13 @@
 }
 
 
+void MacroAssembler::EnterFrame(StackFrame::Type type,
+                                bool load_constant_pool_pointer_reg) {
+  // Out-of-line constant pool not implemented on arm64.
+  UNREACHABLE();
+}
+
+
 void MacroAssembler::EnterFrame(StackFrame::Type type) {
   DCHECK(jssp.Is(StackPointer()));
   UseScratchRegisterScope temps(this);
@@ -3781,23 +3788,38 @@
 }
 
 
-void MacroAssembler::DispatchMap(Register obj,
-                                 Register scratch,
-                                 Handle<Map> map,
-                                 Handle<Code> success,
-                                 SmiCheckType smi_check_type) {
+void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
+                                     Register scratch2, Handle<WeakCell> cell,
+                                     Handle<Code> success,
+                                     SmiCheckType smi_check_type) {
   Label fail;
   if (smi_check_type == DO_SMI_CHECK) {
     JumpIfSmi(obj, &fail);
   }
-  Ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
-  Cmp(scratch, Operand(map));
+  Ldr(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset));
+  CmpWeakValue(scratch1, cell, scratch2);
   B(ne, &fail);
   Jump(success, RelocInfo::CODE_TARGET);
   Bind(&fail);
 }
 
 
+void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
+                                  Register scratch) {
+  Mov(scratch, Operand(cell));
+  Ldr(scratch, FieldMemOperand(scratch, WeakCell::kValueOffset));
+  Cmp(value, scratch);
+}
+
+
+void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
+                                   Label* miss) {
+  Mov(value, Operand(cell));
+  Ldr(value, FieldMemOperand(value, WeakCell::kValueOffset));
+  JumpIfSmi(value, miss);
+}
+
+
 void MacroAssembler::TestMapBitfield(Register object, uint64_t mask) {
   UseScratchRegisterScope temps(this);
   Register temp = temps.AcquireX();
@@ -4080,7 +4102,7 @@
 
   // Check the context is a native context.
   if (emit_debug_code()) {
-    // Read the first word and compare to the global_context_map.
+    // Read the first word and compare to the native_context_map.
     Ldr(scratch2, FieldMemOperand(scratch1, HeapObject::kMapOffset));
     CompareRoot(scratch2, Heap::kNativeContextMapRootIndex);
     Check(eq, kExpectedNativeContext);
@@ -4206,10 +4228,11 @@
   }
 
   Bind(&done);
-  // Check that the value is a normal property.
+  // Check that the value is a field property.
   const int kDetailsOffset =
       SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
   Ldrsw(scratch1, UntagSmiFieldMemOperand(scratch2, kDetailsOffset));
+  DCHECK_EQ(FIELD, 0);
   TestAndBranchIfAnySet(scratch1, PropertyDetails::TypeField::kMask, miss);
 
   // Get the value at the masked, scaled index and return.
@@ -4626,17 +4649,6 @@
 }
 
 
-void MacroAssembler::CheckMapDeprecated(Handle<Map> map,
-                                        Register scratch,
-                                        Label* if_deprecated) {
-  if (map->CanBeDeprecated()) {
-    Mov(scratch, Operand(map));
-    Ldrsw(scratch, FieldMemOperand(scratch, Map::kBitField3Offset));
-    TestAndBranchIfAnySet(scratch, Map::Deprecated::kMask, if_deprecated);
-  }
-}
-
-
 void MacroAssembler::JumpIfBlack(Register object,
                                  Register scratch0,
                                  Register scratch1,
diff --git a/src/arm64/macro-assembler-arm64.h b/src/arm64/macro-assembler-arm64.h
index 7a106a1..ee43589 100644
--- a/src/arm64/macro-assembler-arm64.h
+++ b/src/arm64/macro-assembler-arm64.h
@@ -422,6 +422,7 @@
   inline void Frinta(const FPRegister& fd, const FPRegister& fn);
   inline void Frintm(const FPRegister& fd, const FPRegister& fn);
   inline void Frintn(const FPRegister& fd, const FPRegister& fn);
+  inline void Frintp(const FPRegister& fd, const FPRegister& fn);
   inline void Frintz(const FPRegister& fd, const FPRegister& fn);
   inline void Fsqrt(const FPRegister& fd, const FPRegister& fn);
   inline void Fsub(const FPRegister& fd,
@@ -489,6 +490,7 @@
   inline void Smulh(const Register& rd,
                     const Register& rn,
                     const Register& rm);
+  inline void Umull(const Register& rd, const Register& rn, const Register& rm);
   inline void Stnp(const CPURegister& rt,
                    const CPURegister& rt2,
                    const MemOperand& dst);
@@ -759,9 +761,9 @@
   // it can be evidence of a potential bug because the ABI forbids accesses
   // below csp.
   //
-  // If StackPointer() is the system stack pointer (csp) or ALWAYS_ALIGN_CSP is
-  // enabled, then csp will be dereferenced to  cause the processor
-  // (or simulator) to abort if it is not properly aligned.
+  // If StackPointer() is the system stack pointer (csp), then csp will be
+  // dereferenced to cause the processor (or simulator) to abort if it is not
+  // properly aligned.
   //
   // If emit_debug_code() is false, this emits no code.
   void AssertStackConsistency();
@@ -829,9 +831,7 @@
   inline void BumpSystemStackPointer(const Operand& space);
 
   // Re-synchronizes the system stack pointer (csp) with the current stack
-  // pointer (according to StackPointer()).  This function will ensure the
-  // new value of the system stack pointer is remains aligned to 16 bytes, and
-  // is lower than or equal to the value of the current stack pointer.
+  // pointer (according to StackPointer()).
   //
   // This method asserts that StackPointer() is not csp, since the call does
   // not make sense in that context.
@@ -1478,14 +1478,19 @@
                 Label* fail,
                 SmiCheckType smi_check_type);
 
-  // Check if the map of an object is equal to a specified map and branch to a
-  // specified target if equal. Skip the smi check if not required (object is
-  // known to be a heap object)
-  void DispatchMap(Register obj,
-                   Register scratch,
-                   Handle<Map> map,
-                   Handle<Code> success,
-                   SmiCheckType smi_check_type);
+  // Check if the map of an object is equal to a specified weak map and branch
+  // to a specified target if equal. Skip the smi check if not required
+  // (object is known to be a heap object)
+  void DispatchWeakMap(Register obj, Register scratch1, Register scratch2,
+                       Handle<WeakCell> cell, Handle<Code> success,
+                       SmiCheckType smi_check_type);
+
+  // Compare the given value and the value of weak cell.
+  void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
+
+  // Load the value of the weak cell in the value register. Branch to the given
+  // miss label if the weak cell was cleared.
+  void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
 
   // Test the bitfield of the heap object map with mask and set the condition
   // flags. The object register is preserved.
@@ -1627,6 +1632,7 @@
 
   // Activation support.
   void EnterFrame(StackFrame::Type type);
+  void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
   void LeaveFrame(StackFrame::Type type);
 
   // Returns map with validated enum cache in object register.
@@ -1774,10 +1780,6 @@
                           int mask,
                           Label* if_all_clear);
 
-  void CheckMapDeprecated(Handle<Map> map,
-                          Register scratch,
-                          Label* if_deprecated);
-
   // Check if object is in new space and jump accordingly.
   // Register 'object' is preserved.
   void JumpIfNotInNewSpace(Register object,
diff --git a/src/arm64/simulator-arm64.cc b/src/arm64/simulator-arm64.cc
index 129252b..bc524af 100644
--- a/src/arm64/simulator-arm64.cc
+++ b/src/arm64/simulator-arm64.cc
@@ -413,7 +413,7 @@
 
   // Reset debug helpers.
   breakpoints_.empty();
-  break_on_next_= false;
+  break_on_next_ = false;
 }
 
 
@@ -2463,6 +2463,12 @@
         set_sreg(fd, FPRoundInt(sreg(fn), FPNegativeInfinity)); break;
     case FRINTM_d:
         set_dreg(fd, FPRoundInt(dreg(fn), FPNegativeInfinity)); break;
+    case FRINTP_s:
+      set_sreg(fd, FPRoundInt(sreg(fn), FPPositiveInfinity));
+      break;
+    case FRINTP_d:
+      set_dreg(fd, FPRoundInt(dreg(fn), FPPositiveInfinity));
+      break;
     case FRINTN_s: set_sreg(fd, FPRoundInt(sreg(fn), FPTieEven)); break;
     case FRINTN_d: set_dreg(fd, FPRoundInt(dreg(fn), FPTieEven)); break;
     case FRINTZ_s: set_sreg(fd, FPRoundInt(sreg(fn), FPZero)); break;
@@ -2767,6 +2773,10 @@
       // We always use floor(value).
       break;
     }
+    case FPPositiveInfinity: {
+      int_result = ceil(value);
+      break;
+    }
     default: UNIMPLEMENTED();
   }
   return int_result;
diff --git a/src/array-iterator.js b/src/array-iterator.js
index 5ced9da..17d55f0 100644
--- a/src/array-iterator.js
+++ b/src/array-iterator.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-'use strict';
+"use strict";
 
 
 // This file relies on the fact that the following declaration has been made
@@ -112,6 +112,8 @@
   %FunctionSetName(ArrayIteratorIterator, '[Symbol.iterator]');
   %AddNamedProperty(ArrayIterator.prototype, symbolIterator,
                     ArrayIteratorIterator, DONT_ENUM);
+  %AddNamedProperty(ArrayIterator.prototype, symbolToStringTag,
+                    "Array Iterator", READ_ONLY | DONT_ENUM);
 }
 SetUpArrayIterator();
 
diff --git a/src/array.js b/src/array.js
index 81f1f65..c702d8c 100644
--- a/src/array.js
+++ b/src/array.js
@@ -90,7 +90,8 @@
   // Only use the sparse variant on arrays that are likely to be sparse and the
   // number of elements touched in the operation is relatively small compared to
   // the overall size of the array.
-  if (!is_array || length < 1000 || %IsObserved(array)) {
+  if (!is_array || length < 1000 || %IsObserved(array) ||
+      %HasComplexElements(array)) {
     return false;
   }
   if (!%_IsSmi(length)) {
@@ -203,7 +204,7 @@
 
 // This function implements the optimized splice implementation that can use
 // special array operations to handle sparse arrays in a sensible fashion.
-function SmartSlice(array, start_i, del_count, len, deleted_elements) {
+function SparseSlice(array, start_i, del_count, len, deleted_elements) {
   // Move deleted elements to a new array (the return value from splice).
   var indices = %GetArrayKeys(array, start_i + del_count);
   if (IS_NUMBER(indices)) {
@@ -211,7 +212,7 @@
     for (var i = start_i; i < limit; ++i) {
       var current = array[i];
       if (!IS_UNDEFINED(current) || i in array) {
-        deleted_elements[i - start_i] = current;
+        %AddElement(deleted_elements, i - start_i, current, NONE);
       }
     }
   } else {
@@ -222,7 +223,7 @@
         if (key >= start_i) {
           var current = array[key];
           if (!IS_UNDEFINED(current) || key in array) {
-            deleted_elements[key - start_i] = current;
+            %AddElement(deleted_elements, key - start_i, current, NONE);
           }
         }
       }
@@ -233,9 +234,14 @@
 
 // This function implements the optimized splice implementation that can use
 // special array operations to handle sparse arrays in a sensible fashion.
-function SmartMove(array, start_i, del_count, len, num_additional_args) {
+function SparseMove(array, start_i, del_count, len, num_additional_args) {
+  // Bail out if no moving is necessary.
+  if (num_additional_args === del_count) return;
   // Move data to new array.
-  var new_array = new InternalArray(len - del_count + num_additional_args);
+  var new_array = new InternalArray(
+      // Clamp array length to 2^32-1 to avoid early RangeError.
+      MathMin(len - del_count + num_additional_args, 0xffffffff));
+  var big_indices;
   var indices = %GetArrayKeys(array, len);
   if (IS_NUMBER(indices)) {
     var limit = indices;
@@ -264,7 +270,12 @@
         } else if (key >= start_i + del_count) {
           var current = array[key];
           if (!IS_UNDEFINED(current) || key in array) {
-            new_array[key - del_count + num_additional_args] = current;
+            var new_key = key - del_count + num_additional_args;
+            new_array[new_key] = current;
+            if (new_key > 0xffffffff) {
+              big_indices = big_indices || new InternalArray();
+              big_indices.push(new_key);
+            }
           }
         }
       }
@@ -272,6 +283,14 @@
   }
   // Move contents of new_array into this array
   %MoveArrayContents(new_array, array);
+  // Add any moved values that aren't elements anymore.
+  if (!IS_UNDEFINED(big_indices)) {
+    var length = big_indices.length;
+    for (var i = 0; i < length; ++i) {
+      var key = big_indices[i];
+      array[key] = new_array[key];
+    }
+  }
 }
 
 
@@ -279,20 +298,21 @@
 // because the receiver is not an array (so we have no choice) or because we
 // know we are not deleting or moving a lot of elements.
 function SimpleSlice(array, start_i, del_count, len, deleted_elements) {
+  var is_array = IS_ARRAY(array);
   for (var i = 0; i < del_count; i++) {
     var index = start_i + i;
-    // The spec could also be interpreted such that %HasOwnProperty
-    // would be the appropriate test.  We follow KJS in consulting the
-    // prototype.
-    var current = array[index];
-    if (!IS_UNDEFINED(current) || index in array) {
-      deleted_elements[i] = current;
+    if (HAS_INDEX(array, index, is_array)) {
+      var current = array[index];
+      // The spec requires [[DefineOwnProperty]] here, %AddElement is close
+      // enough (in that it ignores the prototype).
+      %AddElement(deleted_elements, i, current, NONE);
     }
   }
 }
 
 
 function SimpleMove(array, start_i, del_count, len, num_additional_args) {
+  var is_array = IS_ARRAY(array);
   if (num_additional_args !== del_count) {
     // Move the existing elements after the elements to be deleted
     // to the right position in the resulting array.
@@ -300,12 +320,8 @@
       for (var i = len - del_count; i > start_i; i--) {
         var from_index = i + del_count - 1;
         var to_index = i + num_additional_args - 1;
-        // The spec could also be interpreted such that
-        // %HasOwnProperty would be the appropriate test.  We follow
-        // KJS in consulting the prototype.
-        var current = array[from_index];
-        if (!IS_UNDEFINED(current) || from_index in array) {
-          array[to_index] = current;
+        if (HAS_INDEX(array, from_index, is_array)) {
+          array[to_index] = array[from_index];
         } else {
           delete array[to_index];
         }
@@ -314,12 +330,8 @@
       for (var i = start_i; i < len - del_count; i++) {
         var from_index = i + del_count;
         var to_index = i + num_additional_args;
-        // The spec could also be interpreted such that
-        // %HasOwnProperty would be the appropriate test.  We follow
-        // KJS in consulting the prototype.
-        var current = array[from_index];
-        if (!IS_UNDEFINED(current) || from_index in array) {
-          array[to_index] = current;
+        if (HAS_INDEX(array, from_index, is_array)) {
+          array[to_index] = array[from_index];
         } else {
           delete array[to_index];
         }
@@ -349,7 +361,7 @@
     func = array.join;
   }
   if (!IS_SPEC_FUNCTION(func)) {
-    return %_CallFunction(array, ObjectToString);
+    return %_CallFunction(array, NoSideEffectsObjectToString);
   }
   return %_CallFunction(array, func);
 }
@@ -378,6 +390,14 @@
   var result = %_FastOneByteArrayJoin(array, separator);
   if (!IS_UNDEFINED(result)) return result;
 
+  // Fast case for one-element arrays.
+  if (length === 1) {
+    var e = array[0];
+    if (IS_STRING(e)) return e;
+    if (IS_NULL_OR_UNDEFINED(e)) return '';
+    return NonStringToString(e);
+  }
+
   return Join(array, length, separator, ConvertToString);
 }
 
@@ -596,8 +616,8 @@
 
   var first = array[0];
 
-  if (IS_ARRAY(array)) {
-    SmartMove(array, 0, 1, len, 0);
+  if (UseSparseVariant(array, len, IS_ARRAY(array), len)) {
+    SparseMove(array, 0, 1, len, 0);
   } else {
     SimpleMove(array, 0, 1, len, 0);
   }
@@ -636,10 +656,10 @@
   var array = TO_OBJECT_INLINE(this);
   var len = TO_UINT32(array.length);
   var num_arguments = %_ArgumentsLength();
-  var is_sealed = ObjectIsSealed(array);
 
-  if (IS_ARRAY(array) && !is_sealed && len > 0) {
-    SmartMove(array, 0, 0, len, num_arguments);
+  if (len > 0 && UseSparseVariant(array, len, IS_ARRAY(array), len) &&
+     !ObjectIsSealed(array)) {
+    SparseMove(array, 0, 0, len, num_arguments);
   } else {
     SimpleMove(array, 0, 0, len, num_arguments);
   }
@@ -685,7 +705,7 @@
   if (UseSparseVariant(array, len, IS_ARRAY(array), end_i - start_i)) {
     %NormalizeElements(array);
     %NormalizeElements(result);
-    SmartSlice(array, start_i, end_i - start_i, len, result);
+    SparseSlice(array, start_i, end_i - start_i, len, result);
   } else {
     SimpleSlice(array, start_i, end_i - start_i, len, result);
   }
@@ -801,8 +821,8 @@
   if (UseSparseVariant(array, len, IS_ARRAY(array), changed_elements)) {
     %NormalizeElements(array);
     %NormalizeElements(deleted_elements);
-    SmartSlice(array, start_i, del_count, len, deleted_elements);
-    SmartMove(array, start_i, del_count, len, num_elements_to_add);
+    SparseSlice(array, start_i, del_count, len, deleted_elements);
+    SparseMove(array, start_i, del_count, len, num_elements_to_add);
   } else {
     SimpleSlice(array, start_i, del_count, len, deleted_elements);
     SimpleMove(array, start_i, del_count, len, num_elements_to_add);
@@ -964,7 +984,7 @@
   // of a prototype property.
   var CopyFromPrototype = function CopyFromPrototype(obj, length) {
     var max = 0;
-    for (var proto = %GetPrototype(obj); proto; proto = %GetPrototype(proto)) {
+    for (var proto = %_GetPrototype(obj); proto; proto = %_GetPrototype(proto)) {
       var indices = %GetArrayKeys(proto, length);
       if (IS_NUMBER(indices)) {
         // It's an interval.
@@ -993,7 +1013,7 @@
   // where a prototype of obj has an element. I.e., shadow all prototype
   // elements in that range.
   var ShadowPrototypeElements = function(obj, from, to) {
-    for (var proto = %GetPrototype(obj); proto; proto = %GetPrototype(proto)) {
+    for (var proto = %_GetPrototype(obj); proto; proto = %_GetPrototype(proto)) {
       var indices = %GetArrayKeys(proto, to);
       if (IS_NUMBER(indices)) {
         // It's an interval.
@@ -1061,7 +1081,7 @@
     }
     for (i = length - num_holes; i < length; i++) {
       // For compatability with Webkit, do not expose elements in the prototype.
-      if (i in %GetPrototype(obj)) {
+      if (i in %_GetPrototype(obj)) {
         obj[i] = UNDEFINED;
       } else {
         delete obj[i];
@@ -1125,22 +1145,25 @@
   if (!IS_SPEC_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
+  var needs_wrapper = false;
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
-    receiver = ToObject(receiver);
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
   }
 
   var result = new $Array();
   var accumulator = new InternalArray();
   var accumulator_length = 0;
+  var is_array = IS_ARRAY(array);
   var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
   for (var i = 0; i < length; i++) {
-    if (i in array) {
+    if (HAS_INDEX(array, i, is_array)) {
       var element = array[i];
       // Prepare break slots for debugger step in.
       if (stepping) %DebugPrepareStepInIfStepping(f);
-      if (%_CallFunction(receiver, element, i, array, f)) {
+      var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+      if (%_CallFunction(new_receiver, element, i, array, f)) {
         accumulator[accumulator_length++] = element;
       }
     }
@@ -1161,19 +1184,22 @@
   if (!IS_SPEC_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
+  var needs_wrapper = false;
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
-    receiver = ToObject(receiver);
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
   }
 
+  var is_array = IS_ARRAY(array);
   var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
   for (var i = 0; i < length; i++) {
-    if (i in array) {
+    if (HAS_INDEX(array, i, is_array)) {
       var element = array[i];
       // Prepare break slots for debugger step in.
       if (stepping) %DebugPrepareStepInIfStepping(f);
-      %_CallFunction(receiver, element, i, array, f);
+      var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+      %_CallFunction(new_receiver, element, i, array, f);
     }
   }
 }
@@ -1192,19 +1218,22 @@
   if (!IS_SPEC_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
+  var needs_wrapper = false;
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
-    receiver = ToObject(receiver);
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
   }
 
+  var is_array = IS_ARRAY(array);
   var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
   for (var i = 0; i < length; i++) {
-    if (i in array) {
+    if (HAS_INDEX(array, i, is_array)) {
       var element = array[i];
       // Prepare break slots for debugger step in.
       if (stepping) %DebugPrepareStepInIfStepping(f);
-      if (%_CallFunction(receiver, element, i, array, f)) return true;
+      var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+      if (%_CallFunction(new_receiver, element, i, array, f)) return true;
     }
   }
   return false;
@@ -1222,19 +1251,22 @@
   if (!IS_SPEC_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
+  var needs_wrapper = false;
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
-    receiver = ToObject(receiver);
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
   }
 
+  var is_array = IS_ARRAY(array);
   var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
   for (var i = 0; i < length; i++) {
-    if (i in array) {
+    if (HAS_INDEX(array, i, is_array)) {
       var element = array[i];
       // Prepare break slots for debugger step in.
       if (stepping) %DebugPrepareStepInIfStepping(f);
-      if (!%_CallFunction(receiver, element, i, array, f)) return false;
+      var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+      if (!%_CallFunction(new_receiver, element, i, array, f)) return false;
     }
   }
   return true;
@@ -1251,21 +1283,24 @@
   if (!IS_SPEC_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
+  var needs_wrapper = false;
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
-    receiver = ToObject(receiver);
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
   }
 
   var result = new $Array();
   var accumulator = new InternalArray(length);
+  var is_array = IS_ARRAY(array);
   var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
   for (var i = 0; i < length; i++) {
-    if (i in array) {
+    if (HAS_INDEX(array, i, is_array)) {
       var element = array[i];
       // Prepare break slots for debugger step in.
       if (stepping) %DebugPrepareStepInIfStepping(f);
-      accumulator[i] = %_CallFunction(receiver, element, i, array, f);
+      var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+      accumulator[i] = %_CallFunction(new_receiver, element, i, array, f);
     }
   }
   %MoveArrayContents(accumulator, result);
@@ -1395,12 +1430,12 @@
     throw MakeTypeError('called_non_callable', [callback]);
   }
 
+  var is_array = IS_ARRAY(array);
   var i = 0;
   find_initial: if (%_ArgumentsLength() < 2) {
     for (; i < length; i++) {
-      current = array[i];
-      if (!IS_UNDEFINED(current) || i in array) {
-        i++;
+      if (HAS_INDEX(array, i, is_array)) {
+        current = array[i++];
         break find_initial;
       }
     }
@@ -1410,7 +1445,7 @@
   var receiver = %GetDefaultReceiver(callback);
   var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(callback);
   for (; i < length; i++) {
-    if (i in array) {
+    if (HAS_INDEX(array, i, is_array)) {
       var element = array[i];
       // Prepare break slots for debugger step in.
       if (stepping) %DebugPrepareStepInIfStepping(callback);
@@ -1432,12 +1467,12 @@
     throw MakeTypeError('called_non_callable', [callback]);
   }
 
+  var is_array = IS_ARRAY(array);
   var i = length - 1;
   find_initial: if (%_ArgumentsLength() < 2) {
     for (; i >= 0; i--) {
-      current = array[i];
-      if (!IS_UNDEFINED(current) || i in array) {
-        i--;
+      if (HAS_INDEX(array, i, is_array)) {
+        current = array[i--];
         break find_initial;
       }
     }
@@ -1447,7 +1482,7 @@
   var receiver = %GetDefaultReceiver(callback);
   var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(callback);
   for (; i >= 0; i--) {
-    if (i in array) {
+    if (HAS_INDEX(array, i, is_array)) {
       var element = array[i];
       // Prepare break slots for debugger step in.
       if (stepping) %DebugPrepareStepInIfStepping(callback);
diff --git a/src/arraybuffer.js b/src/arraybuffer.js
index e1c887f..cf00693 100644
--- a/src/arraybuffer.js
+++ b/src/arraybuffer.js
@@ -77,6 +77,9 @@
   %AddNamedProperty(
       $ArrayBuffer.prototype, "constructor", $ArrayBuffer, DONT_ENUM);
 
+  %AddNamedProperty($ArrayBuffer.prototype,
+      symbolToStringTag, "ArrayBuffer", DONT_ENUM | READ_ONLY);
+
   InstallGetter($ArrayBuffer.prototype, "byteLength", ArrayBufferGetByteLen);
 
   InstallFunctions($ArrayBuffer, DONT_ENUM, $Array(
diff --git a/src/assembler.cc b/src/assembler.cc
index a705300..c73b470 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -37,6 +37,7 @@
 #include <cmath>
 #include "src/api.h"
 #include "src/base/cpu.h"
+#include "src/base/functional.h"
 #include "src/base/lazy-instance.h"
 #include "src/base/platform/platform.h"
 #include "src/builtins.h"
@@ -52,7 +53,7 @@
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
 #include "src/regexp-stack.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 #include "src/serialize.h"
 #include "src/token.h"
 
@@ -130,7 +131,8 @@
       emit_debug_code_(FLAG_debug_code),
       predictable_code_size_(false),
       // We may use the assembler without an isolate.
-      serializer_enabled_(isolate && isolate->serializer_enabled()) {
+      serializer_enabled_(isolate && isolate->serializer_enabled()),
+      ool_constant_pool_available_(false) {
   if (FLAG_mask_constants_with_cookie && isolate != NULL)  {
     jit_cookie_ = isolate->random_number_generator()->NextInt();
   }
@@ -794,8 +796,8 @@
 }
 
 
-void RelocInfo::Print(Isolate* isolate, OStream& os) {  // NOLINT
-  os << pc_ << "  " << RelocModeName(rmode_);
+void RelocInfo::Print(Isolate* isolate, std::ostream& os) {  // NOLINT
+  os << static_cast<const void*>(pc_) << "  " << RelocModeName(rmode_);
   if (IsComment(rmode_)) {
     os << "  (" << reinterpret_cast<char*>(data_) << ")";
   } else if (rmode_ == EMBEDDED_OBJECT) {
@@ -803,11 +805,11 @@
   } else if (rmode_ == EXTERNAL_REFERENCE) {
     ExternalReferenceEncoder ref_encoder(isolate);
     os << " (" << ref_encoder.NameOfAddress(target_reference()) << ")  ("
-       << target_reference() << ")";
+       << static_cast<const void*>(target_reference()) << ")";
   } else if (IsCodeTarget(rmode_)) {
     Code* code = Code::GetCodeFromTargetAddress(target_address());
-    os << " (" << Code::Kind2String(code->kind()) << ")  (" << target_address()
-       << ")";
+    os << " (" << Code::Kind2String(code->kind()) << ")  ("
+       << static_cast<const void*>(target_address()) << ")";
     if (rmode_ == CODE_TARGET_WITH_ID) {
       os << " (id=" << static_cast<int>(data_) << ")";
     }
@@ -1521,6 +1523,29 @@
 }
 
 
+bool operator==(ExternalReference lhs, ExternalReference rhs) {
+  return lhs.address() == rhs.address();
+}
+
+
+bool operator!=(ExternalReference lhs, ExternalReference rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(ExternalReference reference) {
+  return base::hash<Address>()(reference.address());
+}
+
+
+std::ostream& operator<<(std::ostream& os, ExternalReference reference) {
+  os << static_cast<const void*>(reference.address());
+  const Runtime::Function* fn = Runtime::FunctionForEntry(reference.address());
+  if (fn) os << "<" << fn->name << ".entry>";
+  return os;
+}
+
+
 void PositionsRecorder::RecordPosition(int pos) {
   DCHECK(pos != RelocInfo::kNoPosition);
   DCHECK(pos >= 0);
diff --git a/src/assembler.h b/src/assembler.h
index 3d2f7d9..e95b7ed 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -41,7 +41,7 @@
 #include "src/builtins.h"
 #include "src/gdb-jit.h"
 #include "src/isolate.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 #include "src/token.h"
 
 namespace v8 {
@@ -79,6 +79,16 @@
     return (enabled_cpu_features_ & (static_cast<uint64_t>(1) << f)) != 0;
   }
 
+  bool is_ool_constant_pool_available() const {
+    if (FLAG_enable_ool_constant_pool) {
+      return ool_constant_pool_available_;
+    } else {
+      // Out-of-line constant pool not supported on this architecture.
+      UNREACHABLE();
+      return false;
+    }
+  }
+
   // Overwrite a host NaN with a quiet target NaN.  Used by mksnapshot for
   // cross-snapshotting.
   static void QuietNaN(HeapObject* nan) { }
@@ -98,6 +108,15 @@
   int buffer_size_;
   bool own_buffer_;
 
+  void set_ool_constant_pool_available(bool available) {
+    if (FLAG_enable_ool_constant_pool) {
+      ool_constant_pool_available_ = available;
+    } else {
+      // Out-of-line constant pool not supported on this architecture.
+      UNREACHABLE();
+    }
+  }
+
   // The program counter, which points into the buffer above and moves forward.
   byte* pc_;
 
@@ -108,6 +127,14 @@
   bool emit_debug_code_;
   bool predictable_code_size_;
   bool serializer_enabled_;
+
+  // Indicates whether the constant pool can be accessed, which is only possible
+  // if the pp register points to the current code object's constant pool.
+  bool ool_constant_pool_available_;
+
+  // Constant pool.
+  friend class FrameAndConstantPoolScope;
+  friend class ConstantPoolUnavailableScope;
 };
 
 
@@ -216,7 +243,7 @@
 // unknown pc location. Assembler::bind() is used to bind a label to the
 // current pc. A label can be bound only once.
 
-class Label BASE_EMBEDDED {
+class Label {
  public:
   enum Distance {
     kNear, kFar
@@ -578,7 +605,7 @@
 #ifdef ENABLE_DISASSEMBLER
   // Printing
   static const char* RelocModeName(Mode rmode);
-  void Print(Isolate* isolate, OStream& os);  // NOLINT
+  void Print(Isolate* isolate, std::ostream& os);  // NOLINT
 #endif  // ENABLE_DISASSEMBLER
 #ifdef VERIFY_HEAP
   void Verify(Isolate* isolate);
@@ -959,14 +986,6 @@
 
   static ExternalReference stress_deopt_count(Isolate* isolate);
 
-  bool operator==(const ExternalReference& other) const {
-    return address_ == other.address_;
-  }
-
-  bool operator!=(const ExternalReference& other) const {
-    return !(*this == other);
-  }
-
  private:
   explicit ExternalReference(void* address)
       : address_(address) {}
@@ -987,6 +1006,13 @@
   void* address_;
 };
 
+bool operator==(ExternalReference, ExternalReference);
+bool operator!=(ExternalReference, ExternalReference);
+
+size_t hash_value(ExternalReference);
+
+std::ostream& operator<<(std::ostream&, ExternalReference);
+
 
 // -----------------------------------------------------------------------------
 // Position recording support
diff --git a/src/assert-scope.cc b/src/assert-scope.cc
index c4aa987..4c10fdd 100644
--- a/src/assert-scope.cc
+++ b/src/assert-scope.cc
@@ -2,20 +2,154 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-
 #include "src/assert-scope.h"
-#include "src/v8.h"
+
+#include "src/base/lazy-instance.h"
+#include "src/base/platform/platform.h"
+#include "src/isolate-inl.h"
+#include "src/utils.h"
 
 namespace v8 {
 namespace internal {
 
-uint32_t PerIsolateAssertBase::GetData(Isolate* isolate) {
-  return isolate->per_isolate_assert_data();
+namespace {
+
+struct PerThreadAssertKeyConstructTrait FINAL {
+  static void Construct(base::Thread::LocalStorageKey* key) {
+    *key = base::Thread::CreateThreadLocalKey();
+  }
+};
+
+
+typedef base::LazyStaticInstance<base::Thread::LocalStorageKey,
+                                 PerThreadAssertKeyConstructTrait>::type
+    PerThreadAssertKey;
+
+
+PerThreadAssertKey kPerThreadAssertKey;
+
+}  // namespace
+
+
+class PerThreadAssertData FINAL {
+ public:
+  PerThreadAssertData() : nesting_level_(0) {
+    for (int i = 0; i < LAST_PER_THREAD_ASSERT_TYPE; i++) {
+      assert_states_[i] = true;
+    }
+  }
+
+  ~PerThreadAssertData() {
+    for (int i = 0; i < LAST_PER_THREAD_ASSERT_TYPE; ++i) {
+      DCHECK(assert_states_[i]);
+    }
+  }
+
+  bool Get(PerThreadAssertType type) const { return assert_states_[type]; }
+  void Set(PerThreadAssertType type, bool x) { assert_states_[type] = x; }
+
+  void IncrementLevel() { ++nesting_level_; }
+  bool DecrementLevel() { return --nesting_level_ == 0; }
+
+  static PerThreadAssertData* GetCurrent() {
+    return reinterpret_cast<PerThreadAssertData*>(
+        base::Thread::GetThreadLocal(kPerThreadAssertKey.Get()));
+  }
+  static void SetCurrent(PerThreadAssertData* data) {
+    base::Thread::SetThreadLocal(kPerThreadAssertKey.Get(), data);
+  }
+
+ private:
+  bool assert_states_[LAST_PER_THREAD_ASSERT_TYPE];
+  int nesting_level_;
+
+  DISALLOW_COPY_AND_ASSIGN(PerThreadAssertData);
+};
+
+
+template <PerThreadAssertType kType, bool kAllow>
+PerThreadAssertScope<kType, kAllow>::PerThreadAssertScope()
+    : data_(PerThreadAssertData::GetCurrent()) {
+  if (data_ == NULL) {
+    data_ = new PerThreadAssertData();
+    PerThreadAssertData::SetCurrent(data_);
+  }
+  data_->IncrementLevel();
+  old_state_ = data_->Get(kType);
+  data_->Set(kType, kAllow);
 }
 
 
-void PerIsolateAssertBase::SetData(Isolate* isolate, uint32_t data) {
-  isolate->set_per_isolate_assert_data(data);
+template <PerThreadAssertType kType, bool kAllow>
+PerThreadAssertScope<kType, kAllow>::~PerThreadAssertScope() {
+  DCHECK_NOT_NULL(data_);
+  data_->Set(kType, old_state_);
+  if (data_->DecrementLevel()) {
+    PerThreadAssertData::SetCurrent(NULL);
+    delete data_;
+  }
 }
 
-} }  // namespace v8::internal
+
+// static
+template <PerThreadAssertType kType, bool kAllow>
+bool PerThreadAssertScope<kType, kAllow>::IsAllowed() {
+  PerThreadAssertData* data = PerThreadAssertData::GetCurrent();
+  return data == NULL || data->Get(kType);
+}
+
+
+template <PerIsolateAssertType kType, bool kAllow>
+class PerIsolateAssertScope<kType, kAllow>::DataBit
+    : public BitField<bool, kType, 1> {};
+
+
+template <PerIsolateAssertType kType, bool kAllow>
+PerIsolateAssertScope<kType, kAllow>::PerIsolateAssertScope(Isolate* isolate)
+    : isolate_(isolate), old_data_(isolate->per_isolate_assert_data()) {
+  DCHECK_NOT_NULL(isolate);
+  STATIC_ASSERT(kType < 32);
+  isolate_->set_per_isolate_assert_data(DataBit::update(old_data_, kAllow));
+}
+
+
+template <PerIsolateAssertType kType, bool kAllow>
+PerIsolateAssertScope<kType, kAllow>::~PerIsolateAssertScope() {
+  isolate_->set_per_isolate_assert_data(old_data_);
+}
+
+
+// static
+template <PerIsolateAssertType kType, bool kAllow>
+bool PerIsolateAssertScope<kType, kAllow>::IsAllowed(Isolate* isolate) {
+  return DataBit::decode(isolate->per_isolate_assert_data());
+}
+
+
+// -----------------------------------------------------------------------------
+// Instantiations.
+
+template class PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, false>;
+template class PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, true>;
+template class PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, false>;
+template class PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, true>;
+template class PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, false>;
+template class PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, true>;
+template class PerThreadAssertScope<DEFERRED_HANDLE_DEREFERENCE_ASSERT, false>;
+template class PerThreadAssertScope<DEFERRED_HANDLE_DEREFERENCE_ASSERT, true>;
+template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, false>;
+template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, true>;
+
+template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>;
+template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>;
+template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, false>;
+template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, true>;
+template class PerIsolateAssertScope<ALLOCATION_FAILURE_ASSERT, false>;
+template class PerIsolateAssertScope<ALLOCATION_FAILURE_ASSERT, true>;
+template class PerIsolateAssertScope<DEOPTIMIZATION_ASSERT, false>;
+template class PerIsolateAssertScope<DEOPTIMIZATION_ASSERT, true>;
+template class PerIsolateAssertScope<COMPILATION_ASSERT, false>;
+template class PerIsolateAssertScope<COMPILATION_ASSERT, true>;
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/assert-scope.h b/src/assert-scope.h
index 7cfec56..0f1e056 100644
--- a/src/assert-scope.h
+++ b/src/assert-scope.h
@@ -5,14 +5,16 @@
 #ifndef V8_ASSERT_SCOPE_H_
 #define V8_ASSERT_SCOPE_H_
 
-#include "src/allocation.h"
-#include "src/base/platform/platform.h"
-#include "src/utils.h"
+#include <stdint.h>
+#include "src/base/macros.h"
 
 namespace v8 {
 namespace internal {
 
+// Forward declarations.
 class Isolate;
+class PerThreadAssertData;
+
 
 enum PerThreadAssertType {
   HEAP_ALLOCATION_ASSERT,
@@ -33,120 +35,35 @@
 };
 
 
-class PerThreadAssertData {
+template <PerThreadAssertType kType, bool kAllow>
+class PerThreadAssertScope {
  public:
-  PerThreadAssertData() : nesting_level_(0) {
-    for (int i = 0; i < LAST_PER_THREAD_ASSERT_TYPE; i++) {
-      assert_states_[i] = true;
-    }
-  }
+  PerThreadAssertScope();
+  ~PerThreadAssertScope();
 
-  void set(PerThreadAssertType type, bool allow) {
-    assert_states_[type] = allow;
-  }
-
-  bool get(PerThreadAssertType type) const {
-    return assert_states_[type];
-  }
-
-  void increment_level() { ++nesting_level_; }
-  bool decrement_level() { return --nesting_level_ == 0; }
+  static bool IsAllowed();
 
  private:
-  bool assert_states_[LAST_PER_THREAD_ASSERT_TYPE];
-  int nesting_level_;
-
-  DISALLOW_COPY_AND_ASSIGN(PerThreadAssertData);
-};
-
-
-class PerThreadAssertScopeBase {
- protected:
-  PerThreadAssertScopeBase() {
-    data_ = GetAssertData();
-    if (data_ == NULL) {
-      data_ = new PerThreadAssertData();
-      SetThreadLocalData(data_);
-    }
-    data_->increment_level();
-  }
-
-  ~PerThreadAssertScopeBase() {
-    if (!data_->decrement_level()) return;
-    for (int i = 0; i < LAST_PER_THREAD_ASSERT_TYPE; i++) {
-      DCHECK(data_->get(static_cast<PerThreadAssertType>(i)));
-    }
-    delete data_;
-    SetThreadLocalData(NULL);
-  }
-
-  static PerThreadAssertData* GetAssertData() {
-    return reinterpret_cast<PerThreadAssertData*>(
-        base::Thread::GetThreadLocal(thread_local_key));
-  }
-
-  static base::Thread::LocalStorageKey thread_local_key;
   PerThreadAssertData* data_;
-  friend class Isolate;
-
- private:
-  static void SetThreadLocalData(PerThreadAssertData* data) {
-    base::Thread::SetThreadLocal(thread_local_key, data);
-  }
-};
-
-
-template <PerThreadAssertType type, bool allow>
-class PerThreadAssertScope : public PerThreadAssertScopeBase {
- public:
-  PerThreadAssertScope() {
-    old_state_ = data_->get(type);
-    data_->set(type, allow);
-  }
-
-  ~PerThreadAssertScope() { data_->set(type, old_state_); }
-
-  static bool IsAllowed() {
-    PerThreadAssertData* data = GetAssertData();
-    return data == NULL || data->get(type);
-  }
-
- private:
   bool old_state_;
 
   DISALLOW_COPY_AND_ASSIGN(PerThreadAssertScope);
 };
 
 
-class PerIsolateAssertBase {
- protected:
-  static uint32_t GetData(Isolate* isolate);
-  static void SetData(Isolate* isolate, uint32_t data);
-};
-
-
 template <PerIsolateAssertType type, bool allow>
-class PerIsolateAssertScope : public PerIsolateAssertBase {
+class PerIsolateAssertScope {
  public:
-  explicit PerIsolateAssertScope(Isolate* isolate) : isolate_(isolate) {
-    STATIC_ASSERT(type < 32);
-    old_data_ = GetData(isolate_);
-    SetData(isolate_, DataBit::update(old_data_, allow));
-  }
+  explicit PerIsolateAssertScope(Isolate* isolate);
+  ~PerIsolateAssertScope();
 
-  ~PerIsolateAssertScope() {
-    SetData(isolate_, old_data_);
-  }
-
-  static bool IsAllowed(Isolate* isolate) {
-    return DataBit::decode(GetData(isolate));
-  }
+  static bool IsAllowed(Isolate* isolate);
 
  private:
-  typedef BitField<bool, type, 1> DataBit;
+  class DataBit;
 
-  uint32_t old_data_;
   Isolate* isolate_;
+  uint32_t old_data_;
 
   DISALLOW_COPY_AND_ASSIGN(PerIsolateAssertScope);
 };
diff --git a/src/ast-numbering.cc b/src/ast-numbering.cc
new file mode 100644
index 0000000..c2dd70e
--- /dev/null
+++ b/src/ast-numbering.cc
@@ -0,0 +1,578 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/ast.h"
+#include "src/ast-numbering.h"
+#include "src/compiler.h"
+#include "src/scopes.h"
+
+namespace v8 {
+namespace internal {
+
+
+class AstNumberingVisitor FINAL : public AstVisitor {
+ public:
+  explicit AstNumberingVisitor(Zone* zone)
+      : AstVisitor(),
+        next_id_(BailoutId::FirstUsable().ToInt()),
+        dont_crankshaft_reason_(kNoReason),
+        dont_turbofan_reason_(kNoReason) {
+    InitializeAstVisitor(zone);
+  }
+
+  bool Renumber(FunctionLiteral* node);
+
+ private:
+// AST node visitor interface.
+#define DEFINE_VISIT(type) virtual void Visit##type(type* node) OVERRIDE;
+  AST_NODE_LIST(DEFINE_VISIT)
+#undef DEFINE_VISIT
+
+  bool Finish(FunctionLiteral* node);
+
+  void VisitStatements(ZoneList<Statement*>* statements) OVERRIDE;
+  void VisitDeclarations(ZoneList<Declaration*>* declarations) OVERRIDE;
+  void VisitArguments(ZoneList<Expression*>* arguments);
+  void VisitObjectLiteralProperty(ObjectLiteralProperty* property);
+
+  int ReserveIdRange(int n) {
+    int tmp = next_id_;
+    next_id_ += n;
+    return tmp;
+  }
+
+  void IncrementNodeCount() { properties_.add_node_count(1); }
+  void DisableCrankshaft(BailoutReason reason) {
+    dont_crankshaft_reason_ = reason;
+    properties_.flags()->Add(kDontSelfOptimize);
+  }
+  // TODO(turbofan): Remove the dont_turbofan_reason once no nodes are
+  // DontTurbofanNode.  That set of nodes must be kept in sync with
+  // Pipeline::GenerateCode.
+  void DisableTurbofan(BailoutReason reason) {
+    dont_crankshaft_reason_ = reason;
+    dont_turbofan_reason_ = reason;
+    DisableSelfOptimization();
+  }
+  void DisableSelfOptimization() {
+    properties_.flags()->Add(kDontSelfOptimize);
+  }
+  void DisableCaching(BailoutReason reason) {
+    dont_crankshaft_reason_ = reason;
+    DisableSelfOptimization();
+    properties_.flags()->Add(kDontCache);
+  }
+
+  template <typename Node>
+  void ReserveFeedbackSlots(Node* node) {
+    FeedbackVectorRequirements reqs =
+        node->ComputeFeedbackRequirements(isolate());
+    if (reqs.slots() > 0) {
+      node->SetFirstFeedbackSlot(FeedbackVectorSlot(properties_.slots()));
+      properties_.increase_slots(reqs.slots());
+    }
+    if (reqs.ic_slots() > 0) {
+      int ic_slots = properties_.ic_slots();
+      node->SetFirstFeedbackICSlot(FeedbackVectorICSlot(ic_slots));
+      properties_.increase_ic_slots(reqs.ic_slots());
+      if (FLAG_vector_ics) {
+        for (int i = 0; i < reqs.ic_slots(); i++) {
+          properties_.SetKind(ic_slots + i, node->FeedbackICSlotKind(i));
+        }
+      }
+    }
+  }
+
+  BailoutReason dont_optimize_reason() const {
+    return (dont_turbofan_reason_ != kNoReason) ? dont_turbofan_reason_
+                                                : dont_crankshaft_reason_;
+  }
+
+  int next_id_;
+  AstProperties properties_;
+  BailoutReason dont_crankshaft_reason_;
+  BailoutReason dont_turbofan_reason_;
+
+  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
+  DISALLOW_COPY_AND_ASSIGN(AstNumberingVisitor);
+};
+
+
+void AstNumberingVisitor::VisitVariableDeclaration(VariableDeclaration* node) {
+  IncrementNodeCount();
+  VisitVariableProxy(node->proxy());
+}
+
+
+void AstNumberingVisitor::VisitExportDeclaration(ExportDeclaration* node) {
+  IncrementNodeCount();
+  DisableCrankshaft(kExportDeclaration);
+  VisitVariableProxy(node->proxy());
+}
+
+
+void AstNumberingVisitor::VisitModuleUrl(ModuleUrl* node) {
+  IncrementNodeCount();
+  DisableCrankshaft(kModuleUrl);
+}
+
+
+void AstNumberingVisitor::VisitEmptyStatement(EmptyStatement* node) {
+  IncrementNodeCount();
+}
+
+
+void AstNumberingVisitor::VisitContinueStatement(ContinueStatement* node) {
+  IncrementNodeCount();
+}
+
+
+void AstNumberingVisitor::VisitBreakStatement(BreakStatement* node) {
+  IncrementNodeCount();
+}
+
+
+void AstNumberingVisitor::VisitDebuggerStatement(DebuggerStatement* node) {
+  IncrementNodeCount();
+  DisableCrankshaft(kDebuggerStatement);
+  node->set_base_id(ReserveIdRange(DebuggerStatement::num_ids()));
+}
+
+
+void AstNumberingVisitor::VisitNativeFunctionLiteral(
+    NativeFunctionLiteral* node) {
+  IncrementNodeCount();
+  DisableCrankshaft(kNativeFunctionLiteral);
+  node->set_base_id(ReserveIdRange(NativeFunctionLiteral::num_ids()));
+}
+
+
+void AstNumberingVisitor::VisitLiteral(Literal* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(Literal::num_ids()));
+}
+
+
+void AstNumberingVisitor::VisitRegExpLiteral(RegExpLiteral* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(RegExpLiteral::num_ids()));
+}
+
+
+void AstNumberingVisitor::VisitVariableProxy(VariableProxy* node) {
+  IncrementNodeCount();
+  if (node->var()->IsLookupSlot()) {
+    DisableCrankshaft(kReferenceToAVariableWhichRequiresDynamicLookup);
+  }
+  ReserveFeedbackSlots(node);
+  node->set_base_id(ReserveIdRange(VariableProxy::num_ids()));
+}
+
+
+void AstNumberingVisitor::VisitThisFunction(ThisFunction* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(ThisFunction::num_ids()));
+}
+
+
+void AstNumberingVisitor::VisitSuperReference(SuperReference* node) {
+  IncrementNodeCount();
+  DisableTurbofan(kSuperReference);
+  ReserveFeedbackSlots(node);
+  node->set_base_id(ReserveIdRange(SuperReference::num_ids()));
+  Visit(node->this_var());
+}
+
+
+void AstNumberingVisitor::VisitModuleDeclaration(ModuleDeclaration* node) {
+  IncrementNodeCount();
+  DisableCrankshaft(kModuleDeclaration);
+  VisitVariableProxy(node->proxy());
+  Visit(node->module());
+}
+
+
+void AstNumberingVisitor::VisitImportDeclaration(ImportDeclaration* node) {
+  IncrementNodeCount();
+  DisableCrankshaft(kImportDeclaration);
+  VisitVariableProxy(node->proxy());
+  Visit(node->module());
+}
+
+
+void AstNumberingVisitor::VisitModuleVariable(ModuleVariable* node) {
+  IncrementNodeCount();
+  DisableCrankshaft(kModuleVariable);
+  Visit(node->proxy());
+}
+
+
+void AstNumberingVisitor::VisitModulePath(ModulePath* node) {
+  IncrementNodeCount();
+  DisableCrankshaft(kModulePath);
+  Visit(node->module());
+}
+
+
+void AstNumberingVisitor::VisitModuleStatement(ModuleStatement* node) {
+  IncrementNodeCount();
+  DisableCrankshaft(kModuleStatement);
+  Visit(node->body());
+}
+
+
+void AstNumberingVisitor::VisitExpressionStatement(ExpressionStatement* node) {
+  IncrementNodeCount();
+  Visit(node->expression());
+}
+
+
+void AstNumberingVisitor::VisitReturnStatement(ReturnStatement* node) {
+  IncrementNodeCount();
+  Visit(node->expression());
+}
+
+
+void AstNumberingVisitor::VisitYield(Yield* node) {
+  IncrementNodeCount();
+  DisableCrankshaft(kYield);
+  ReserveFeedbackSlots(node);
+  node->set_base_id(ReserveIdRange(Yield::num_ids()));
+  Visit(node->generator_object());
+  Visit(node->expression());
+}
+
+
+void AstNumberingVisitor::VisitThrow(Throw* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(Throw::num_ids()));
+  Visit(node->exception());
+}
+
+
+void AstNumberingVisitor::VisitUnaryOperation(UnaryOperation* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(UnaryOperation::num_ids()));
+  Visit(node->expression());
+}
+
+
+void AstNumberingVisitor::VisitCountOperation(CountOperation* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(CountOperation::num_ids()));
+  Visit(node->expression());
+}
+
+
+void AstNumberingVisitor::VisitBlock(Block* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(Block::num_ids()));
+  if (node->scope() != NULL) VisitDeclarations(node->scope()->declarations());
+  VisitStatements(node->statements());
+}
+
+
+void AstNumberingVisitor::VisitFunctionDeclaration(FunctionDeclaration* node) {
+  IncrementNodeCount();
+  VisitVariableProxy(node->proxy());
+  VisitFunctionLiteral(node->fun());
+}
+
+
+void AstNumberingVisitor::VisitModuleLiteral(ModuleLiteral* node) {
+  IncrementNodeCount();
+  DisableCaching(kModuleLiteral);
+  VisitBlock(node->body());
+}
+
+
+void AstNumberingVisitor::VisitCallRuntime(CallRuntime* node) {
+  IncrementNodeCount();
+  ReserveFeedbackSlots(node);
+  if (node->is_jsruntime()) {
+    // Don't try to optimize JS runtime calls because we bailout on them.
+    DisableCrankshaft(kCallToAJavaScriptRuntimeFunction);
+  }
+  node->set_base_id(ReserveIdRange(CallRuntime::num_ids()));
+  VisitArguments(node->arguments());
+}
+
+
+void AstNumberingVisitor::VisitWithStatement(WithStatement* node) {
+  IncrementNodeCount();
+  DisableCrankshaft(kWithStatement);
+  Visit(node->expression());
+  Visit(node->statement());
+}
+
+
+void AstNumberingVisitor::VisitDoWhileStatement(DoWhileStatement* node) {
+  IncrementNodeCount();
+  DisableSelfOptimization();
+  node->set_base_id(ReserveIdRange(DoWhileStatement::num_ids()));
+  Visit(node->body());
+  Visit(node->cond());
+}
+
+
+void AstNumberingVisitor::VisitWhileStatement(WhileStatement* node) {
+  IncrementNodeCount();
+  DisableSelfOptimization();
+  node->set_base_id(ReserveIdRange(WhileStatement::num_ids()));
+  Visit(node->cond());
+  Visit(node->body());
+}
+
+
+void AstNumberingVisitor::VisitTryCatchStatement(TryCatchStatement* node) {
+  IncrementNodeCount();
+  DisableTurbofan(kTryCatchStatement);
+  Visit(node->try_block());
+  Visit(node->catch_block());
+}
+
+
+void AstNumberingVisitor::VisitTryFinallyStatement(TryFinallyStatement* node) {
+  IncrementNodeCount();
+  DisableTurbofan(kTryFinallyStatement);
+  Visit(node->try_block());
+  Visit(node->finally_block());
+}
+
+
+void AstNumberingVisitor::VisitProperty(Property* node) {
+  IncrementNodeCount();
+  ReserveFeedbackSlots(node);
+  node->set_base_id(ReserveIdRange(Property::num_ids()));
+  Visit(node->key());
+  Visit(node->obj());
+}
+
+
+void AstNumberingVisitor::VisitAssignment(Assignment* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(Assignment::num_ids()));
+  if (node->is_compound()) VisitBinaryOperation(node->binary_operation());
+  Visit(node->target());
+  Visit(node->value());
+}
+
+
+void AstNumberingVisitor::VisitBinaryOperation(BinaryOperation* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(BinaryOperation::num_ids()));
+  Visit(node->left());
+  Visit(node->right());
+}
+
+
+void AstNumberingVisitor::VisitCompareOperation(CompareOperation* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(CompareOperation::num_ids()));
+  Visit(node->left());
+  Visit(node->right());
+}
+
+
+void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) {
+  IncrementNodeCount();
+  DisableSelfOptimization();
+  ReserveFeedbackSlots(node);
+  node->set_base_id(ReserveIdRange(ForInStatement::num_ids()));
+  Visit(node->each());
+  Visit(node->enumerable());
+  Visit(node->body());
+}
+
+
+void AstNumberingVisitor::VisitForOfStatement(ForOfStatement* node) {
+  IncrementNodeCount();
+  DisableTurbofan(kForOfStatement);
+  node->set_base_id(ReserveIdRange(ForOfStatement::num_ids()));
+  Visit(node->assign_iterator());
+  Visit(node->next_result());
+  Visit(node->result_done());
+  Visit(node->assign_each());
+  Visit(node->body());
+}
+
+
+void AstNumberingVisitor::VisitConditional(Conditional* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(Conditional::num_ids()));
+  Visit(node->condition());
+  Visit(node->then_expression());
+  Visit(node->else_expression());
+}
+
+
+void AstNumberingVisitor::VisitIfStatement(IfStatement* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(IfStatement::num_ids()));
+  Visit(node->condition());
+  Visit(node->then_statement());
+  if (node->HasElseStatement()) {
+    Visit(node->else_statement());
+  }
+}
+
+
+void AstNumberingVisitor::VisitSwitchStatement(SwitchStatement* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(SwitchStatement::num_ids()));
+  Visit(node->tag());
+  ZoneList<CaseClause*>* cases = node->cases();
+  for (int i = 0; i < cases->length(); i++) {
+    VisitCaseClause(cases->at(i));
+  }
+}
+
+
+void AstNumberingVisitor::VisitCaseClause(CaseClause* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(CaseClause::num_ids()));
+  if (!node->is_default()) Visit(node->label());
+  VisitStatements(node->statements());
+}
+
+
+void AstNumberingVisitor::VisitForStatement(ForStatement* node) {
+  IncrementNodeCount();
+  DisableSelfOptimization();
+  node->set_base_id(ReserveIdRange(ForStatement::num_ids()));
+  if (node->init() != NULL) Visit(node->init());
+  if (node->cond() != NULL) Visit(node->cond());
+  if (node->next() != NULL) Visit(node->next());
+  Visit(node->body());
+}
+
+
+void AstNumberingVisitor::VisitClassLiteral(ClassLiteral* node) {
+  IncrementNodeCount();
+  DisableTurbofan(kClassLiteral);
+  node->set_base_id(ReserveIdRange(ClassLiteral::num_ids()));
+  if (node->extends()) Visit(node->extends());
+  if (node->constructor()) Visit(node->constructor());
+  if (node->class_variable_proxy()) {
+    VisitVariableProxy(node->class_variable_proxy());
+  }
+  for (int i = 0; i < node->properties()->length(); i++) {
+    VisitObjectLiteralProperty(node->properties()->at(i));
+  }
+}
+
+
+void AstNumberingVisitor::VisitObjectLiteral(ObjectLiteral* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(ObjectLiteral::num_ids()));
+  for (int i = 0; i < node->properties()->length(); i++) {
+    VisitObjectLiteralProperty(node->properties()->at(i));
+  }
+}
+
+
+void AstNumberingVisitor::VisitObjectLiteralProperty(
+    ObjectLiteralProperty* node) {
+  Visit(node->key());
+  Visit(node->value());
+}
+
+
+void AstNumberingVisitor::VisitArrayLiteral(ArrayLiteral* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(node->num_ids()));
+  for (int i = 0; i < node->values()->length(); i++) {
+    Visit(node->values()->at(i));
+  }
+}
+
+
+void AstNumberingVisitor::VisitCall(Call* node) {
+  IncrementNodeCount();
+  ReserveFeedbackSlots(node);
+  node->set_base_id(ReserveIdRange(Call::num_ids()));
+  Visit(node->expression());
+  VisitArguments(node->arguments());
+}
+
+
+void AstNumberingVisitor::VisitCallNew(CallNew* node) {
+  IncrementNodeCount();
+  ReserveFeedbackSlots(node);
+  node->set_base_id(ReserveIdRange(CallNew::num_ids()));
+  Visit(node->expression());
+  VisitArguments(node->arguments());
+}
+
+
+void AstNumberingVisitor::VisitStatements(ZoneList<Statement*>* statements) {
+  if (statements == NULL) return;
+  for (int i = 0; i < statements->length(); i++) {
+    Visit(statements->at(i));
+  }
+}
+
+
+void AstNumberingVisitor::VisitDeclarations(
+    ZoneList<Declaration*>* declarations) {
+  for (int i = 0; i < declarations->length(); i++) {
+    Visit(declarations->at(i));
+  }
+}
+
+
+void AstNumberingVisitor::VisitArguments(ZoneList<Expression*>* arguments) {
+  for (int i = 0; i < arguments->length(); i++) {
+    Visit(arguments->at(i));
+  }
+}
+
+
+void AstNumberingVisitor::VisitFunctionLiteral(FunctionLiteral* node) {
+  IncrementNodeCount();
+  node->set_base_id(ReserveIdRange(FunctionLiteral::num_ids()));
+  // We don't recurse into the declarations or body of the function literal:
+  // you have to separately Renumber() each FunctionLiteral that you compile.
+}
+
+
+bool AstNumberingVisitor::Finish(FunctionLiteral* node) {
+  node->set_ast_properties(&properties_);
+  node->set_dont_optimize_reason(dont_optimize_reason());
+  return !HasStackOverflow();
+}
+
+
+bool AstNumberingVisitor::Renumber(FunctionLiteral* node) {
+  Scope* scope = node->scope();
+
+  if (scope->HasIllegalRedeclaration()) {
+    scope->VisitIllegalRedeclaration(this);
+    DisableCrankshaft(kFunctionWithIllegalRedeclaration);
+    return Finish(node);
+  }
+  if (scope->calls_eval()) DisableCrankshaft(kFunctionCallsEval);
+  if (scope->arguments() != NULL && !scope->arguments()->IsStackAllocated()) {
+    DisableCrankshaft(kContextAllocatedArguments);
+  }
+
+  VisitDeclarations(scope->declarations());
+  if (scope->is_function_scope() && scope->function() != NULL) {
+    // Visit the name of the named function expression.
+    Visit(scope->function());
+  }
+  VisitStatements(node->body());
+
+  return Finish(node);
+}
+
+
+bool AstNumbering::Renumber(FunctionLiteral* function, Zone* zone) {
+  AstNumberingVisitor visitor(zone);
+  return visitor.Renumber(function);
+}
+}
+}  // namespace v8::internal
diff --git a/src/ast-numbering.h b/src/ast-numbering.h
new file mode 100644
index 0000000..ab97c22
--- /dev/null
+++ b/src/ast-numbering.h
@@ -0,0 +1,19 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_AST_NUMBERING_H_
+#define V8_AST_NUMBERING_H_
+
+namespace v8 {
+namespace internal {
+
+namespace AstNumbering {
+// Assign type feedback IDs and bailout IDs to an AST node tree.
+//
+bool Renumber(FunctionLiteral* function, Zone* zone);
+}
+}
+}  // namespace v8::internal
+
+#endif  // V8_AST_NUMBERING_H_
diff --git a/src/ast-this-access-visitor.cc b/src/ast-this-access-visitor.cc
new file mode 100644
index 0000000..cf4a3de
--- /dev/null
+++ b/src/ast-this-access-visitor.cc
@@ -0,0 +1,239 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/ast-this-access-visitor.h"
+#include "src/parser.h"
+
+namespace v8 {
+namespace internal {
+
+typedef class AstThisAccessVisitor ATAV;  // for code shortitude.
+
+ATAV::AstThisAccessVisitor(Zone* zone) : uses_this_(false) {
+  InitializeAstVisitor(zone);
+}
+
+
+void ATAV::VisitVariableProxy(VariableProxy* proxy) {
+  if (proxy->is_this()) {
+    uses_this_ = true;
+  }
+}
+
+
+void ATAV::VisitSuperReference(SuperReference* leaf) {
+  // disallow super.method() and super(...).
+  uses_this_ = true;
+}
+
+
+void ATAV::VisitCallNew(CallNew* e) {
+  // new super(..) does not use 'this'.
+  if (!e->expression()->IsSuperReference()) {
+    Visit(e->expression());
+  }
+  VisitExpressions(e->arguments());
+}
+
+
+// ---------------------------------------------------------------------------
+// -- Leaf nodes -------------------------------------------------------------
+// ---------------------------------------------------------------------------
+
+void ATAV::VisitVariableDeclaration(VariableDeclaration* leaf) {}
+void ATAV::VisitFunctionDeclaration(FunctionDeclaration* leaf) {}
+void ATAV::VisitModuleDeclaration(ModuleDeclaration* leaf) {}
+void ATAV::VisitImportDeclaration(ImportDeclaration* leaf) {}
+void ATAV::VisitExportDeclaration(ExportDeclaration* leaf) {}
+void ATAV::VisitModuleVariable(ModuleVariable* leaf) {}
+void ATAV::VisitModulePath(ModulePath* leaf) {}
+void ATAV::VisitModuleUrl(ModuleUrl* leaf) {}
+void ATAV::VisitEmptyStatement(EmptyStatement* leaf) {}
+void ATAV::VisitContinueStatement(ContinueStatement* leaf) {}
+void ATAV::VisitBreakStatement(BreakStatement* leaf) {}
+void ATAV::VisitDebuggerStatement(DebuggerStatement* leaf) {}
+void ATAV::VisitFunctionLiteral(FunctionLiteral* leaf) {}
+void ATAV::VisitNativeFunctionLiteral(NativeFunctionLiteral* leaf) {}
+void ATAV::VisitLiteral(Literal* leaf) {}
+void ATAV::VisitRegExpLiteral(RegExpLiteral* leaf) {}
+void ATAV::VisitThisFunction(ThisFunction* leaf) {}
+
+// ---------------------------------------------------------------------------
+// -- Pass-through nodes------------------------------------------------------
+// ---------------------------------------------------------------------------
+void ATAV::VisitModuleLiteral(ModuleLiteral* e) { Visit(e->body()); }
+
+
+void ATAV::VisitBlock(Block* stmt) { VisitStatements(stmt->statements()); }
+
+
+void ATAV::VisitExpressionStatement(ExpressionStatement* stmt) {
+  Visit(stmt->expression());
+}
+
+
+void ATAV::VisitIfStatement(IfStatement* stmt) {
+  Visit(stmt->condition());
+  Visit(stmt->then_statement());
+  Visit(stmt->else_statement());
+}
+
+
+void ATAV::VisitReturnStatement(ReturnStatement* stmt) {
+  Visit(stmt->expression());
+}
+
+
+void ATAV::VisitWithStatement(WithStatement* stmt) {
+  Visit(stmt->expression());
+  Visit(stmt->statement());
+}
+
+
+void ATAV::VisitSwitchStatement(SwitchStatement* stmt) {
+  Visit(stmt->tag());
+  ZoneList<CaseClause*>* clauses = stmt->cases();
+  for (int i = 0; i < clauses->length(); i++) {
+    Visit(clauses->at(i));
+  }
+}
+
+
+void ATAV::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
+  Visit(stmt->try_block());
+  Visit(stmt->finally_block());
+}
+
+
+void ATAV::VisitClassLiteral(ClassLiteral* e) {
+  VisitIfNotNull(e->extends());
+  Visit(e->constructor());
+  ZoneList<ObjectLiteralProperty*>* properties = e->properties();
+  for (int i = 0; i < properties->length(); i++) {
+    Visit(properties->at(i)->value());
+  }
+}
+
+
+void ATAV::VisitConditional(Conditional* e) {
+  Visit(e->condition());
+  Visit(e->then_expression());
+  Visit(e->else_expression());
+}
+
+
+void ATAV::VisitObjectLiteral(ObjectLiteral* e) {
+  ZoneList<ObjectLiteralProperty*>* properties = e->properties();
+  for (int i = 0; i < properties->length(); i++) {
+    Visit(properties->at(i)->value());
+  }
+}
+
+
+void ATAV::VisitArrayLiteral(ArrayLiteral* e) { VisitExpressions(e->values()); }
+
+
+void ATAV::VisitYield(Yield* stmt) {
+  Visit(stmt->generator_object());
+  Visit(stmt->expression());
+}
+
+
+void ATAV::VisitThrow(Throw* stmt) { Visit(stmt->exception()); }
+
+
+void ATAV::VisitProperty(Property* e) {
+  Visit(e->obj());
+  Visit(e->key());
+}
+
+
+void ATAV::VisitCall(Call* e) {
+  Visit(e->expression());
+  VisitExpressions(e->arguments());
+}
+
+
+void ATAV::VisitCallRuntime(CallRuntime* e) {
+  VisitExpressions(e->arguments());
+}
+
+
+void ATAV::VisitUnaryOperation(UnaryOperation* e) { Visit(e->expression()); }
+
+
+void ATAV::VisitBinaryOperation(BinaryOperation* e) {
+  Visit(e->left());
+  Visit(e->right());
+}
+
+
+void ATAV::VisitCompareOperation(CompareOperation* e) {
+  Visit(e->left());
+  Visit(e->right());
+}
+
+
+void ATAV::VisitCaseClause(CaseClause* cc) {
+  if (!cc->is_default()) Visit(cc->label());
+  VisitStatements(cc->statements());
+}
+
+
+void ATAV::VisitModuleStatement(ModuleStatement* stmt) { Visit(stmt->body()); }
+
+
+void ATAV::VisitTryCatchStatement(TryCatchStatement* stmt) {
+  Visit(stmt->try_block());
+  Visit(stmt->catch_block());
+}
+
+
+void ATAV::VisitDoWhileStatement(DoWhileStatement* loop) {
+  Visit(loop->body());
+  Visit(loop->cond());
+}
+
+
+void ATAV::VisitWhileStatement(WhileStatement* loop) {
+  Visit(loop->cond());
+  Visit(loop->body());
+}
+
+
+void ATAV::VisitForStatement(ForStatement* loop) {
+  VisitIfNotNull(loop->init());
+  VisitIfNotNull(loop->cond());
+  Visit(loop->body());
+  VisitIfNotNull(loop->next());
+}
+
+
+void ATAV::VisitForInStatement(ForInStatement* loop) {
+  Visit(loop->each());
+  Visit(loop->subject());
+  Visit(loop->body());
+}
+
+
+void ATAV::VisitForOfStatement(ForOfStatement* loop) {
+  Visit(loop->each());
+  Visit(loop->subject());
+  Visit(loop->body());
+}
+
+
+void ATAV::VisitAssignment(Assignment* stmt) {
+  Expression* l = stmt->target();
+  Visit(l);
+  Visit(stmt->value());
+}
+
+
+void ATAV::VisitCountOperation(CountOperation* e) {
+  Expression* l = e->expression();
+  Visit(l);
+}
+}
+}  // namespace v8::internal
diff --git a/src/ast-this-access-visitor.h b/src/ast-this-access-visitor.h
new file mode 100644
index 0000000..6030981
--- /dev/null
+++ b/src/ast-this-access-visitor.h
@@ -0,0 +1,34 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_AST_THIS_ACCESS_VISITOR_H_
+#define V8_AST_THIS_ACCESS_VISITOR_H_
+#include "src/ast.h"
+
+namespace v8 {
+namespace internal {
+
+class AstThisAccessVisitor : public AstVisitor {
+ public:
+  explicit AstThisAccessVisitor(Zone* zone);
+
+  bool UsesThis() { return uses_this_; }
+
+#define DECLARE_VISIT(type) void Visit##type(type* node) OVERRIDE;
+  AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+ private:
+  bool uses_this_;
+
+  void VisitIfNotNull(AstNode* node) {
+    if (node != NULL) Visit(node);
+  }
+
+  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
+  DISALLOW_COPY_AND_ASSIGN(AstThisAccessVisitor);
+};
+}
+}  // namespace v8::internal
+#endif  // V8_AST_THIS_ACCESS_VISITOR_H_
diff --git a/src/ast-value-factory.cc b/src/ast-value-factory.cc
index ea8474f..ff20100 100644
--- a/src/ast-value-factory.cc
+++ b/src/ast-value-factory.cc
@@ -56,22 +56,20 @@
   explicit AstRawStringInternalizationKey(const AstRawString* string)
       : string_(string) {}
 
-  virtual bool IsMatch(Object* other) OVERRIDE {
+  bool IsMatch(Object* other) OVERRIDE {
     if (string_->is_one_byte_)
       return String::cast(other)->IsOneByteEqualTo(string_->literal_bytes_);
     return String::cast(other)->IsTwoByteEqualTo(
         Vector<const uint16_t>::cast(string_->literal_bytes_));
   }
 
-  virtual uint32_t Hash() OVERRIDE {
-    return string_->hash() >> Name::kHashShift;
-  }
+  uint32_t Hash() OVERRIDE { return string_->hash() >> Name::kHashShift; }
 
-  virtual uint32_t HashForObject(Object* key) OVERRIDE {
+  uint32_t HashForObject(Object* key) OVERRIDE {
     return String::cast(key)->Hash();
   }
 
-  virtual Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
+  Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
     if (string_->is_one_byte_)
       return isolate->factory()->NewOneByteInternalizedString(
           string_->literal_bytes_, string_->hash());
@@ -117,14 +115,15 @@
 
 
 bool AstRawString::Compare(void* a, void* b) {
-  AstRawString* string1 = reinterpret_cast<AstRawString*>(a);
-  AstRawString* string2 = reinterpret_cast<AstRawString*>(b);
-  if (string1->is_one_byte_ != string2->is_one_byte_) return false;
-  if (string1->hash_ != string2->hash_) return false;
-  int length = string1->literal_bytes_.length();
-  if (string2->literal_bytes_.length() != length) return false;
-  return memcmp(string1->literal_bytes_.start(),
-                string2->literal_bytes_.start(), length) == 0;
+  return *static_cast<AstRawString*>(a) == *static_cast<AstRawString*>(b);
+}
+
+bool AstRawString::operator==(const AstRawString& rhs) const {
+  if (is_one_byte_ != rhs.is_one_byte_) return false;
+  if (hash_ != rhs.hash_) return false;
+  int len = literal_bytes_.length();
+  if (rhs.literal_bytes_.length() != len) return false;
+  return memcmp(literal_bytes_.start(), rhs.literal_bytes_.start(), len) == 0;
 }
 
 
@@ -158,9 +157,6 @@
       return DoubleToBoolean(number_);
     case SMI:
       return smi_ != 0;
-    case STRING_ARRAY:
-      UNREACHABLE();
-      break;
     case BOOLEAN:
       return bool_;
     case NULL_TYPE:
@@ -184,9 +180,8 @@
       DCHECK(!string_->string().is_null());
       break;
     case SYMBOL:
-      value_ = Object::GetProperty(
-                   isolate, handle(isolate->native_context()->builtins()),
-                   symbol_name_).ToHandleChecked();
+      DCHECK_EQ(0, strcmp(symbol_name_, "iterator_symbol"));
+      value_ = isolate->factory()->iterator_symbol();
       break;
     case NUMBER:
       value_ = isolate->factory()->NewNumber(number_, TENURED);
@@ -201,22 +196,6 @@
         value_ = isolate->factory()->false_value();
       }
       break;
-    case STRING_ARRAY: {
-      DCHECK(strings_ != NULL);
-      Factory* factory = isolate->factory();
-      int len = strings_->length();
-      Handle<FixedArray> elements = factory->NewFixedArray(len, TENURED);
-      for (int i = 0; i < len; i++) {
-        const AstRawString* string = (*strings_)[i];
-        Handle<Object> element = string->string();
-        // Strings are already internalized.
-        DCHECK(!element.is_null());
-        elements->set(i, *element);
-      }
-      value_ =
-          factory->NewJSArrayWithElements(elements, FAST_ELEMENTS, TENURED);
-      break;
-    }
     case NULL_TYPE:
       value_ = isolate->factory()->null_value();
       break;
@@ -230,7 +209,7 @@
 }
 
 
-const AstRawString* AstValueFactory::GetOneByteString(
+AstRawString* AstValueFactory::GetOneByteStringInternal(
     Vector<const uint8_t> literal) {
   uint32_t hash = StringHasher::HashSequentialString<uint8_t>(
       literal.start(), literal.length(), hash_seed_);
@@ -238,7 +217,7 @@
 }
 
 
-const AstRawString* AstValueFactory::GetTwoByteString(
+AstRawString* AstValueFactory::GetTwoByteStringInternal(
     Vector<const uint16_t> literal) {
   uint32_t hash = StringHasher::HashSequentialString<uint16_t>(
       literal.start(), literal.length(), hash_seed_);
@@ -247,13 +226,24 @@
 
 
 const AstRawString* AstValueFactory::GetString(Handle<String> literal) {
-  DisallowHeapAllocation no_gc;
-  String::FlatContent content = literal->GetFlatContent();
-  if (content.IsOneByte()) {
-    return GetOneByteString(content.ToOneByteVector());
+  // For the FlatContent to stay valid, we shouldn't do any heap
+  // allocation. Make sure we won't try to internalize the string in GetString.
+  AstRawString* result = NULL;
+  Isolate* saved_isolate = isolate_;
+  isolate_ = NULL;
+  {
+    DisallowHeapAllocation no_gc;
+    String::FlatContent content = literal->GetFlatContent();
+    if (content.IsOneByte()) {
+      result = GetOneByteStringInternal(content.ToOneByteVector());
+    } else {
+      DCHECK(content.IsTwoByte());
+      result = GetTwoByteStringInternal(content.ToUC16Vector());
+    }
   }
-  DCHECK(content.IsTwoByte());
-  return GetTwoByteString(content.ToUC16Vector());
+  isolate_ = saved_isolate;
+  if (isolate_) result->Internalize(isolate_);
+  return result;
 }
 
 
@@ -329,59 +319,45 @@
 }
 
 
+#define GENERATE_VALUE_GETTER(value, initializer) \
+  if (!value) {                                   \
+    value = new (zone_) AstValue(initializer);    \
+    if (isolate_) {                               \
+      value->Internalize(isolate_);               \
+    }                                             \
+    values_.Add(value);                           \
+  }                                               \
+  return value;
+
+
 const AstValue* AstValueFactory::NewBoolean(bool b) {
-  AstValue* value = new (zone_) AstValue(b);
-  if (isolate_) {
-    value->Internalize(isolate_);
+  if (b) {
+    GENERATE_VALUE_GETTER(true_value_, true);
+  } else {
+    GENERATE_VALUE_GETTER(false_value_, false);
   }
-  values_.Add(value);
-  return value;
-}
-
-
-const AstValue* AstValueFactory::NewStringList(
-    ZoneList<const AstRawString*>* strings) {
-  AstValue* value = new (zone_) AstValue(strings);
-  if (isolate_) {
-    value->Internalize(isolate_);
-  }
-  values_.Add(value);
-  return value;
 }
 
 
 const AstValue* AstValueFactory::NewNull() {
-  AstValue* value = new (zone_) AstValue(AstValue::NULL_TYPE);
-  if (isolate_) {
-    value->Internalize(isolate_);
-  }
-  values_.Add(value);
-  return value;
+  GENERATE_VALUE_GETTER(null_value_, AstValue::NULL_TYPE);
 }
 
 
 const AstValue* AstValueFactory::NewUndefined() {
-  AstValue* value = new (zone_) AstValue(AstValue::UNDEFINED);
-  if (isolate_) {
-    value->Internalize(isolate_);
-  }
-  values_.Add(value);
-  return value;
+  GENERATE_VALUE_GETTER(undefined_value_, AstValue::UNDEFINED);
 }
 
 
 const AstValue* AstValueFactory::NewTheHole() {
-  AstValue* value = new (zone_) AstValue(AstValue::THE_HOLE);
-  if (isolate_) {
-    value->Internalize(isolate_);
-  }
-  values_.Add(value);
-  return value;
+  GENERATE_VALUE_GETTER(the_hole_value_, AstValue::THE_HOLE);
 }
 
 
-const AstRawString* AstValueFactory::GetString(
-    uint32_t hash, bool is_one_byte, Vector<const byte> literal_bytes) {
+#undef GENERATE_VALUE_GETTER
+
+AstRawString* AstValueFactory::GetString(uint32_t hash, bool is_one_byte,
+                                         Vector<const byte> literal_bytes) {
   // literal_bytes here points to whatever the user passed, and this is OK
   // because we use vector_compare (which checks the contents) to compare
   // against the AstRawStrings which are in the string_table_. We should not
diff --git a/src/ast-value-factory.h b/src/ast-value-factory.h
index 2f84163..a189f17 100644
--- a/src/ast-value-factory.h
+++ b/src/ast-value-factory.h
@@ -64,13 +64,13 @@
 
 class AstRawString : public AstString {
  public:
-  virtual int length() const OVERRIDE {
+  int length() const OVERRIDE {
     if (is_one_byte_)
       return literal_bytes_.length();
     return literal_bytes_.length() / 2;
   }
 
-  virtual void Internalize(Isolate* isolate) OVERRIDE;
+  void Internalize(Isolate* isolate) OVERRIDE;
 
   bool AsArrayIndex(uint32_t* index) const;
 
@@ -88,12 +88,16 @@
     return *c;
   }
 
+  V8_INLINE bool IsArguments(AstValueFactory* ast_value_factory) const;
+
   // For storing AstRawStrings in a hash map.
   uint32_t hash() const {
     return hash_;
   }
   static bool Compare(void* a, void* b);
 
+  bool operator==(const AstRawString& rhs) const;
+
  private:
   friend class AstValueFactory;
   friend class AstRawStringInternalizationKey;
@@ -120,11 +124,9 @@
       : left_(left),
         right_(right) {}
 
-  virtual int length() const OVERRIDE {
-    return left_->length() + right_->length();
-  }
+  int length() const OVERRIDE { return left_->length() + right_->length(); }
 
-  virtual void Internalize(Isolate* isolate) OVERRIDE;
+  void Internalize(Isolate* isolate) OVERRIDE;
 
  private:
   friend class AstValueFactory;
@@ -190,7 +192,6 @@
     NUMBER,
     SMI,
     BOOLEAN,
-    STRING_ARRAY,
     NULL_TYPE,
     UNDEFINED,
     THE_HOLE
@@ -209,10 +210,6 @@
 
   explicit AstValue(bool b) : type_(BOOLEAN) { bool_ = b; }
 
-  explicit AstValue(ZoneList<const AstRawString*>* s) : type_(STRING_ARRAY) {
-    strings_ = s;
-  }
-
   explicit AstValue(Type t) : type_(t) {
     DCHECK(t == NULL_TYPE || t == UNDEFINED || t == THE_HOLE);
   }
@@ -234,36 +231,44 @@
 };
 
 
-// For generating string constants.
-#define STRING_CONSTANTS(F)                           \
-  F(anonymous_function, "(anonymous function)")       \
-  F(arguments, "arguments")                           \
-  F(constructor, "constructor")                       \
-  F(done, "done")                                     \
-  F(dot, ".")                                         \
-  F(dot_for, ".for")                                  \
-  F(dot_generator, ".generator")                      \
-  F(dot_generator_object, ".generator_object")        \
-  F(dot_iterator, ".iterator")                        \
-  F(dot_module, ".module")                            \
-  F(dot_result, ".result")                            \
-  F(empty, "")                                        \
-  F(eval, "eval")                                     \
-  F(initialize_const_global, "initializeConstGlobal") \
-  F(initialize_var_global, "initializeVarGlobal")     \
-  F(make_reference_error, "MakeReferenceError")       \
-  F(make_syntax_error, "MakeSyntaxError")             \
-  F(make_type_error, "MakeTypeError")                 \
-  F(module, "module")                                 \
-  F(native, "native")                                 \
-  F(next, "next")                                     \
-  F(proto, "__proto__")                               \
-  F(prototype, "prototype")                           \
-  F(this, "this")                                     \
-  F(use_asm, "use asm")                               \
-  F(use_strict, "use strict")                         \
+// For generating constants.
+#define STRING_CONSTANTS(F)                             \
+  F(anonymous_function, "(anonymous function)")         \
+  F(arguments, "arguments")                             \
+  F(constructor, "constructor")                         \
+  F(done, "done")                                       \
+  F(dot, ".")                                           \
+  F(dot_for, ".for")                                    \
+  F(dot_generator, ".generator")                        \
+  F(dot_generator_object, ".generator_object")          \
+  F(dot_iterator, ".iterator")                          \
+  F(dot_module, ".module")                              \
+  F(dot_result, ".result")                              \
+  F(empty, "")                                          \
+  F(eval, "eval")                                       \
+  F(get_template_callsite, "GetTemplateCallSite")       \
+  F(initialize_const_global, "initializeConstGlobal")   \
+  F(initialize_var_global, "initializeVarGlobal")       \
+  F(let, "let")                                         \
+  F(make_reference_error, "MakeReferenceErrorEmbedded") \
+  F(make_syntax_error, "MakeSyntaxErrorEmbedded")       \
+  F(make_type_error, "MakeTypeErrorEmbedded")           \
+  F(module, "module")                                   \
+  F(native, "native")                                   \
+  F(next, "next")                                       \
+  F(proto, "__proto__")                                 \
+  F(prototype, "prototype")                             \
+  F(this, "this")                                       \
+  F(use_asm, "use asm")                                 \
+  F(use_strict, "use strict")                           \
   F(value, "value")
 
+#define OTHER_CONSTANTS(F) \
+  F(true_value)            \
+  F(false_value)           \
+  F(null_value)            \
+  F(undefined_value)       \
+  F(the_hole_value)
 
 class AstValueFactory {
  public:
@@ -272,18 +277,26 @@
         zone_(zone),
         isolate_(NULL),
         hash_seed_(hash_seed) {
-#define F(name, str) \
-    name##_string_ = NULL;
+#define F(name, str) name##_string_ = NULL;
     STRING_CONSTANTS(F)
 #undef F
+#define F(name) name##_ = NULL;
+    OTHER_CONSTANTS(F)
+#undef F
   }
 
-  const AstRawString* GetOneByteString(Vector<const uint8_t> literal);
+  Zone* zone() const { return zone_; }
+
+  const AstRawString* GetOneByteString(Vector<const uint8_t> literal) {
+    return GetOneByteStringInternal(literal);
+  }
   const AstRawString* GetOneByteString(const char* string) {
     return GetOneByteString(Vector<const uint8_t>(
         reinterpret_cast<const uint8_t*>(string), StrLength(string)));
   }
-  const AstRawString* GetTwoByteString(Vector<const uint16_t> literal);
+  const AstRawString* GetTwoByteString(Vector<const uint16_t> literal) {
+    return GetTwoByteStringInternal(literal);
+  }
   const AstRawString* GetString(Handle<String> literal);
   const AstConsString* NewConsString(const AstString* left,
                                      const AstString* right);
@@ -293,15 +306,15 @@
     return isolate_ != NULL;
   }
 
-#define F(name, str) \
-  const AstRawString* name##_string() { \
-    if (name##_string_ == NULL) { \
-      const char* data = str; \
-      name##_string_ = GetOneByteString( \
+#define F(name, str)                                                    \
+  const AstRawString* name##_string() {                                 \
+    if (name##_string_ == NULL) {                                       \
+      const char* data = str;                                           \
+      name##_string_ = GetOneByteString(                                \
           Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), \
-                                static_cast<int>(strlen(data)))); \
-    } \
-    return name##_string_; \
+                                static_cast<int>(strlen(data))));       \
+    }                                                                   \
+    return name##_string_;                                              \
   }
   STRING_CONSTANTS(F)
 #undef F
@@ -318,8 +331,10 @@
   const AstValue* NewTheHole();
 
  private:
-  const AstRawString* GetString(uint32_t hash, bool is_one_byte,
-                                Vector<const byte> literal_bytes);
+  AstRawString* GetOneByteStringInternal(Vector<const uint8_t> literal);
+  AstRawString* GetTwoByteStringInternal(Vector<const uint16_t> literal);
+  AstRawString* GetString(uint32_t hash, bool is_one_byte,
+                          Vector<const byte> literal_bytes);
 
   // All strings are copied here, one after another (no NULLs inbetween).
   HashMap string_table_;
@@ -332,14 +347,22 @@
 
   uint32_t hash_seed_;
 
-#define F(name, str) \
-  const AstRawString* name##_string_;
+#define F(name, str) const AstRawString* name##_string_;
   STRING_CONSTANTS(F)
 #undef F
+
+#define F(name) AstValue* name##_;
+  OTHER_CONSTANTS(F)
+#undef F
 };
 
+
+bool AstRawString::IsArguments(AstValueFactory* ast_value_factory) const {
+  return ast_value_factory->arguments_string() == this;
+}
 } }  // namespace v8::internal
 
 #undef STRING_CONSTANTS
+#undef OTHER_CONSTANTS
 
 #endif  // V8_AST_VALUE_FACTORY_H_
diff --git a/src/ast.cc b/src/ast.cc
index 6816992..6329371 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -59,59 +59,56 @@
 }
 
 
-VariableProxy::VariableProxy(Zone* zone, Variable* var, int position,
-                             IdGen* id_gen)
-    : Expression(zone, position, id_gen),
-      name_(var->raw_name()),
-      var_(NULL),  // Will be set by the call to BindTo.
-      is_this_(var->is_this()),
-      is_assigned_(false),
-      interface_(var->interface()),
-      variable_feedback_slot_(kInvalidFeedbackSlot) {
+VariableProxy::VariableProxy(Zone* zone, Variable* var, int position)
+    : Expression(zone, position),
+      bit_field_(IsThisField::encode(var->is_this()) |
+                 IsAssignedField::encode(false) |
+                 IsResolvedField::encode(false)),
+      variable_feedback_slot_(FeedbackVectorICSlot::Invalid()),
+      raw_name_(var->raw_name()),
+      interface_(var->interface()) {
   BindTo(var);
 }
 
 
 VariableProxy::VariableProxy(Zone* zone, const AstRawString* name, bool is_this,
-                             Interface* interface, int position, IdGen* id_gen)
-    : Expression(zone, position, id_gen),
-      name_(name),
-      var_(NULL),
-      is_this_(is_this),
-      is_assigned_(false),
-      interface_(interface),
-      variable_feedback_slot_(kInvalidFeedbackSlot) {}
+                             Interface* interface, int position)
+    : Expression(zone, position),
+      bit_field_(IsThisField::encode(is_this) | IsAssignedField::encode(false) |
+                 IsResolvedField::encode(false)),
+      variable_feedback_slot_(FeedbackVectorICSlot::Invalid()),
+      raw_name_(name),
+      interface_(interface) {}
 
 
 void VariableProxy::BindTo(Variable* var) {
-  DCHECK(var_ == NULL);  // must be bound only once
-  DCHECK(var != NULL);  // must bind
   DCHECK(!FLAG_harmony_modules || interface_->IsUnified(var->interface()));
-  DCHECK((is_this() && var->is_this()) || name_ == var->raw_name());
+  DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name());
   // Ideally CONST-ness should match. However, this is very hard to achieve
   // because we don't know the exact semantics of conflicting (const and
   // non-const) multiple variable declarations, const vars introduced via
   // eval() etc.  Const-ness and variable declarations are a complete mess
   // in JS. Sigh...
-  var_ = var;
+  set_var(var);
+  set_is_resolved();
   var->set_is_used();
 }
 
 
 Assignment::Assignment(Zone* zone, Token::Value op, Expression* target,
-                       Expression* value, int pos, IdGen* id_gen)
-    : Expression(zone, pos, id_gen),
-      op_(op),
+                       Expression* value, int pos)
+    : Expression(zone, pos),
+      bit_field_(IsUninitializedField::encode(false) |
+                 KeyTypeField::encode(ELEMENT) |
+                 StoreModeField::encode(STANDARD_STORE) |
+                 TokenField::encode(op)),
       target_(target),
       value_(value),
-      binary_operation_(NULL),
-      assignment_id_(id_gen->GetNextId()),
-      is_uninitialized_(false),
-      store_mode_(STANDARD_STORE) {}
+      binary_operation_(NULL) {}
 
 
 Token::Value Assignment::binary_op() const {
-  switch (op_) {
+  switch (op()) {
     case Token::ASSIGN_BIT_OR: return Token::BIT_OR;
     case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR;
     case Token::ASSIGN_BIT_AND: return Token::BIT_AND;
@@ -154,6 +151,21 @@
 }
 
 
+bool FunctionLiteral::uses_super_property() const {
+  DCHECK_NOT_NULL(scope());
+  return scope()->uses_super_property() || scope()->inner_uses_super_property();
+}
+
+
+bool FunctionLiteral::uses_super_constructor_call() const {
+  DCHECK_NOT_NULL(scope());
+  return scope()->uses_super_constructor_call() ||
+         scope()->inner_uses_super_constructor_call();
+}
+
+
+// Helper to find an existing shared function info in the baseline code for the
+// given function literal. Used to canonicalize SharedFunctionInfo objects.
 void FunctionLiteral::InitializeSharedInfo(
     Handle<Code> unoptimized_code) {
   for (RelocIterator it(*unoptimized_code); !it.done(); it.next()) {
@@ -436,7 +448,7 @@
 
 
 bool BinaryOperation::ResultOverwriteAllowed() const {
-  switch (op_) {
+  switch (op()) {
     case Token::COMMA:
     case Token::OR:
     case Token::AND:
@@ -560,7 +572,7 @@
 // once we use the common type field in the AST consistently.
 
 void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
-  to_boolean_types_ = oracle->ToBooleanTypes(test_id());
+  set_to_boolean_types(oracle->ToBooleanTypes(test_id()));
 }
 
 
@@ -570,6 +582,12 @@
 }
 
 
+FeedbackVectorRequirements Call::ComputeFeedbackRequirements(Isolate* isolate) {
+  int ic_slots = IsUsingCallFeedbackSlot(isolate) ? 1 : 0;
+  return FeedbackVectorRequirements(0, ic_slots);
+}
+
+
 Call::CallType Call::GetCallType(Isolate* isolate) const {
   VariableProxy* proxy = expression()->AsVariableProxy();
   if (proxy != NULL) {
@@ -582,6 +600,8 @@
     }
   }
 
+  if (expression()->AsSuperReference() != NULL) return SUPER_CALL;
+
   Property* property = expression()->AsProperty();
   return property != NULL ? PROPERTY_CALL : OTHER_CALL;
 }
@@ -607,17 +627,14 @@
 
 
 void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
-  int allocation_site_feedback_slot = FLAG_pretenuring_call_new
-      ? AllocationSiteFeedbackSlot()
-      : CallNewFeedbackSlot();
+  FeedbackVectorSlot allocation_site_feedback_slot =
+      FLAG_pretenuring_call_new ? AllocationSiteFeedbackSlot()
+                                : CallNewFeedbackSlot();
   allocation_site_ =
       oracle->GetCallNewAllocationSite(allocation_site_feedback_slot);
   is_monomorphic_ = oracle->CallNewIsMonomorphic(CallNewFeedbackSlot());
   if (is_monomorphic_) {
     target_ = oracle->GetCallNewTarget(CallNewFeedbackSlot());
-    if (!allocation_site_.is_null()) {
-      elements_kind_ = allocation_site_->GetElementsKind();
-    }
   }
 }
 
@@ -797,14 +814,14 @@
 // output formats are alike.
 class RegExpUnparser FINAL : public RegExpVisitor {
  public:
-  RegExpUnparser(OStream& os, Zone* zone) : os_(os), zone_(zone) {}
+  RegExpUnparser(std::ostream& os, Zone* zone) : os_(os), zone_(zone) {}
   void VisitCharacterRange(CharacterRange that);
 #define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*,          \
                                                   void* data) OVERRIDE;
   FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
 #undef MAKE_CASE
  private:
-  OStream& os_;
+  std::ostream& os_;
   Zone* zone_;
 };
 
@@ -947,7 +964,7 @@
 }
 
 
-OStream& RegExpTree::Print(OStream& os, Zone* zone) {  // NOLINT
+std::ostream& RegExpTree::Print(std::ostream& os, Zone* zone) {  // NOLINT
   RegExpUnparser unparser(os, zone);
   Accept(&unparser, NULL);
   return os;
@@ -992,157 +1009,26 @@
 
 
 CaseClause::CaseClause(Zone* zone, Expression* label,
-                       ZoneList<Statement*>* statements, int pos, IdGen* id_gen)
-    : Expression(zone, pos, id_gen),
+                       ZoneList<Statement*>* statements, int pos)
+    : Expression(zone, pos),
       label_(label),
       statements_(statements),
-      compare_type_(Type::None(zone)),
-      compare_id_(id_gen->GetNextId()),
-      entry_id_(id_gen->GetNextId()) {}
+      compare_type_(Type::None(zone)) {}
 
 
-#define REGULAR_NODE(NodeType)                                   \
-  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
-    increase_node_count();                                       \
-  }
-#define REGULAR_NODE_WITH_FEEDBACK_SLOTS(NodeType)               \
-  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
-    increase_node_count();                                       \
-    add_slot_node(node);                                         \
-  }
-#define DONT_OPTIMIZE_NODE(NodeType)                             \
-  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
-    increase_node_count();                                       \
-    set_dont_crankshaft_reason(k##NodeType);                     \
-    add_flag(kDontSelfOptimize);                                 \
-  }
-#define DONT_OPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(NodeType)         \
-  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
-    increase_node_count();                                       \
-    add_slot_node(node);                                         \
-    set_dont_crankshaft_reason(k##NodeType);                     \
-    add_flag(kDontSelfOptimize);                                 \
-  }
-#define DONT_TURBOFAN_NODE(NodeType)                             \
-  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
-    increase_node_count();                                       \
-    set_dont_crankshaft_reason(k##NodeType);                     \
-    set_dont_turbofan_reason(k##NodeType);                       \
-    add_flag(kDontSelfOptimize);                                 \
-  }
-#define DONT_SELFOPTIMIZE_NODE(NodeType)                         \
-  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
-    increase_node_count();                                       \
-    add_flag(kDontSelfOptimize);                                 \
-  }
-#define DONT_SELFOPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(NodeType)     \
-  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
-    increase_node_count();                                       \
-    add_slot_node(node);                                         \
-    add_flag(kDontSelfOptimize);                                 \
-  }
-#define DONT_CACHE_NODE(NodeType)                                \
-  void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
-    increase_node_count();                                       \
-    set_dont_crankshaft_reason(k##NodeType);                     \
-    add_flag(kDontSelfOptimize);                                 \
-    add_flag(kDontCache);                                        \
-  }
-
-REGULAR_NODE(VariableDeclaration)
-REGULAR_NODE(FunctionDeclaration)
-REGULAR_NODE(Block)
-REGULAR_NODE(ExpressionStatement)
-REGULAR_NODE(EmptyStatement)
-REGULAR_NODE(IfStatement)
-REGULAR_NODE(ContinueStatement)
-REGULAR_NODE(BreakStatement)
-REGULAR_NODE(ReturnStatement)
-REGULAR_NODE(SwitchStatement)
-REGULAR_NODE(CaseClause)
-REGULAR_NODE(Conditional)
-REGULAR_NODE(Literal)
-REGULAR_NODE(ArrayLiteral)
-REGULAR_NODE(ObjectLiteral)
-REGULAR_NODE(RegExpLiteral)
-REGULAR_NODE(FunctionLiteral)
-REGULAR_NODE(Assignment)
-REGULAR_NODE(Throw)
-REGULAR_NODE(UnaryOperation)
-REGULAR_NODE(CountOperation)
-REGULAR_NODE(BinaryOperation)
-REGULAR_NODE(CompareOperation)
-REGULAR_NODE(ThisFunction)
-
-REGULAR_NODE_WITH_FEEDBACK_SLOTS(Call)
-REGULAR_NODE_WITH_FEEDBACK_SLOTS(CallNew)
-REGULAR_NODE_WITH_FEEDBACK_SLOTS(Property)
-// In theory, for VariableProxy we'd have to add:
-// if (node->var()->IsLookupSlot())
-//   set_dont_optimize_reason(kReferenceToAVariableWhichRequiresDynamicLookup);
-// But node->var() is usually not bound yet at VariableProxy creation time, and
-// LOOKUP variables only result from constructs that cannot be inlined anyway.
-REGULAR_NODE_WITH_FEEDBACK_SLOTS(VariableProxy)
-
-// We currently do not optimize any modules.
-DONT_OPTIMIZE_NODE(ModuleDeclaration)
-DONT_OPTIMIZE_NODE(ImportDeclaration)
-DONT_OPTIMIZE_NODE(ExportDeclaration)
-DONT_OPTIMIZE_NODE(ModuleVariable)
-DONT_OPTIMIZE_NODE(ModulePath)
-DONT_OPTIMIZE_NODE(ModuleUrl)
-DONT_OPTIMIZE_NODE(ModuleStatement)
-DONT_OPTIMIZE_NODE(WithStatement)
-DONT_OPTIMIZE_NODE(DebuggerStatement)
-DONT_OPTIMIZE_NODE(ClassLiteral)
-DONT_OPTIMIZE_NODE(NativeFunctionLiteral)
-DONT_OPTIMIZE_NODE(SuperReference)
-
-DONT_OPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(Yield)
-
-// TODO(turbofan): Remove the dont_turbofan_reason once this list is empty.
-DONT_TURBOFAN_NODE(ForOfStatement)
-DONT_TURBOFAN_NODE(TryCatchStatement)
-DONT_TURBOFAN_NODE(TryFinallyStatement)
-
-DONT_SELFOPTIMIZE_NODE(DoWhileStatement)
-DONT_SELFOPTIMIZE_NODE(WhileStatement)
-DONT_SELFOPTIMIZE_NODE(ForStatement)
-
-DONT_SELFOPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(ForInStatement)
-
-DONT_CACHE_NODE(ModuleLiteral)
-
-
-void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
-  increase_node_count();
-  add_slot_node(node);
-  if (node->is_jsruntime()) {
-    // Don't try to optimize JS runtime calls because we bailout on them.
-    set_dont_crankshaft_reason(kCallToAJavaScriptRuntimeFunction);
-  }
+uint32_t Literal::Hash() {
+  return raw_value()->IsString()
+             ? raw_value()->AsString()->hash()
+             : ComputeLongHash(double_to_uint64(raw_value()->AsNumber()));
 }
 
-#undef REGULAR_NODE
-#undef DONT_OPTIMIZE_NODE
-#undef DONT_SELFOPTIMIZE_NODE
-#undef DONT_CACHE_NODE
 
-
-Handle<String> Literal::ToString() {
-  if (value_->IsString()) return value_->AsString()->string();
-  DCHECK(value_->IsNumber());
-  char arr[100];
-  Vector<char> buffer(arr, arraysize(arr));
-  const char* str;
-  if (value()->IsSmi()) {
-    // Optimization only, the heap number case would subsume this.
-    SNPrintF(buffer, "%d", Smi::cast(*value())->value());
-    str = arr;
-  } else {
-    str = DoubleToCString(value()->Number(), buffer);
-  }
-  return isolate_->factory()->NewStringFromAsciiChecked(str);
+// static
+bool Literal::Match(void* literal1, void* literal2) {
+  const AstValue* x = static_cast<Literal*>(literal1)->raw_value();
+  const AstValue* y = static_cast<Literal*>(literal2)->raw_value();
+  return (x->IsString() && y->IsString() && *x->AsString() == *y->AsString()) ||
+         (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber());
 }
 
 
diff --git a/src/ast.h b/src/ast.h
index 03f43ad..43bde6a 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -11,12 +11,11 @@
 #include "src/ast-value-factory.h"
 #include "src/bailout-reason.h"
 #include "src/factory.h"
-#include "src/feedback-slots.h"
 #include "src/interface.h"
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/list-inl.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 #include "src/small-pointer-list.h"
 #include "src/smart-pointers.h"
 #include "src/token.h"
@@ -106,8 +105,7 @@
   EXPRESSION_NODE_LIST(V)
 
 // Forward declarations
-class AstConstructionVisitor;
-template<class> class AstNodeFactory;
+class AstNodeFactory;
 class AstVisitor;
 class Declaration;
 class Module;
@@ -115,7 +113,6 @@
 class Expression;
 class IterationStatement;
 class MaterializedLiteral;
-class OStream;
 class Statement;
 class TargetCollector;
 class TypeFeedbackOracle;
@@ -144,12 +141,10 @@
 typedef ZoneList<Handle<Object> > ZoneObjectList;
 
 
-#define DECLARE_NODE_TYPE(type)                                 \
-  virtual void Accept(AstVisitor* v) OVERRIDE;                  \
-  virtual AstNode::NodeType node_type() const FINAL OVERRIDE {  \
-    return AstNode::k##type;                                    \
-  }                                                             \
-  template<class> friend class AstNodeFactory;
+#define DECLARE_NODE_TYPE(type)                                          \
+  void Accept(AstVisitor* v) OVERRIDE;                                   \
+  AstNode::NodeType node_type() const FINAL { return AstNode::k##type; } \
+  friend class AstNodeFactory;
 
 
 enum AstPropertiesFlag {
@@ -159,46 +154,47 @@
 };
 
 
+class FeedbackVectorRequirements {
+ public:
+  FeedbackVectorRequirements(int slots, int ic_slots)
+      : slots_(slots), ic_slots_(ic_slots) {}
+
+  int slots() const { return slots_; }
+  int ic_slots() const { return ic_slots_; }
+
+ private:
+  int slots_;
+  int ic_slots_;
+};
+
+
 class AstProperties FINAL BASE_EMBEDDED {
  public:
   class Flags : public EnumSet<AstPropertiesFlag, int> {};
 
-AstProperties() : node_count_(0), feedback_slots_(0) {}
+  AstProperties() : node_count_(0) {}
 
   Flags* flags() { return &flags_; }
   int node_count() { return node_count_; }
   void add_node_count(int count) { node_count_ += count; }
 
-  int feedback_slots() const { return feedback_slots_; }
-  void increase_feedback_slots(int count) {
-    feedback_slots_ += count;
-  }
+  int slots() const { return spec_.slots(); }
+  void increase_slots(int count) { spec_.increase_slots(count); }
+
+  int ic_slots() const { return spec_.ic_slots(); }
+  void increase_ic_slots(int count) { spec_.increase_ic_slots(count); }
+  void SetKind(int ic_slot, Code::Kind kind) { spec_.SetKind(ic_slot, kind); }
+  const FeedbackVectorSpec& get_spec() const { return spec_; }
 
  private:
   Flags flags_;
   int node_count_;
-  int feedback_slots_;
+  FeedbackVectorSpec spec_;
 };
 
 
 class AstNode: public ZoneObject {
  public:
-  // For generating IDs for AstNodes.
-  class IdGen {
-   public:
-    explicit IdGen(int id = 0) : id_(id) {}
-
-    int GetNextId() { return ReserveIdRange(1); }
-    int ReserveIdRange(int n) {
-      int tmp = id_;
-      id_ += n;
-      return tmp;
-    }
-
-   private:
-    int id_;
-  };
-
 #define DECLARE_TYPE_ENUM(type) k##type,
   enum NodeType {
     AST_NODE_LIST(DECLARE_TYPE_ENUM)
@@ -234,12 +230,23 @@
   virtual IterationStatement* AsIterationStatement() { return NULL; }
   virtual MaterializedLiteral* AsMaterializedLiteral() { return NULL; }
 
- protected:
-  // Some nodes re-use bailout IDs for type feedback.
-  static TypeFeedbackId reuse(BailoutId id) {
-    return TypeFeedbackId(id.ToInt());
+  // The interface for feedback slots, with default no-op implementations for
+  // node types which don't actually have this. Note that this is conceptually
+  // not really nice, but multiple inheritance would introduce yet another
+  // vtable entry per node, something we don't want for space reasons.
+  virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
+      Isolate* isolate) {
+    return FeedbackVectorRequirements(0, 0);
   }
-
+  virtual void SetFirstFeedbackSlot(FeedbackVectorSlot slot) { UNREACHABLE(); }
+  virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) {
+    UNREACHABLE();
+  }
+  // Each ICSlot stores a kind of IC which the participating node should know.
+  virtual Code::Kind FeedbackICSlotKind(int index) {
+    UNREACHABLE();
+    return Code::NUMBER_OF_KINDS;
+  }
 
  private:
   // Hidden to prevent accidental usage. It would have to load the
@@ -354,9 +361,17 @@
   void set_bounds(Bounds bounds) { bounds_ = bounds; }
 
   // Whether the expression is parenthesized
-  unsigned parenthesization_level() const { return parenthesization_level_; }
-  bool is_parenthesized() const { return parenthesization_level_ > 0; }
-  void increase_parenthesization_level() { ++parenthesization_level_; }
+  bool is_parenthesized() const {
+    return IsParenthesizedField::decode(bit_field_);
+  }
+  bool is_multi_parenthesized() const {
+    return IsMultiParenthesizedField::decode(bit_field_);
+  }
+  void increase_parenthesization_level() {
+    bit_field_ =
+        IsMultiParenthesizedField::update(bit_field_, is_parenthesized());
+    bit_field_ = IsParenthesizedField::update(bit_field_, true);
+  }
 
   // Type feedback information for assignments and properties.
   virtual bool IsMonomorphic() {
@@ -367,34 +382,53 @@
     UNREACHABLE();
     return NULL;
   }
-  virtual KeyedAccessStoreMode GetStoreMode() {
+  virtual KeyedAccessStoreMode GetStoreMode() const {
     UNREACHABLE();
     return STANDARD_STORE;
   }
+  virtual IcCheckType GetKeyType() const {
+    UNREACHABLE();
+    return ELEMENT;
+  }
 
   // TODO(rossberg): this should move to its own AST node eventually.
   virtual void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle);
-  byte to_boolean_types() const { return to_boolean_types_; }
+  byte to_boolean_types() const {
+    return ToBooleanTypesField::decode(bit_field_);
+  }
 
-  BailoutId id() const { return id_; }
-  TypeFeedbackId test_id() const { return test_id_; }
+  void set_base_id(int id) { base_id_ = id; }
+  static int num_ids() { return parent_num_ids() + 2; }
+  BailoutId id() const { return BailoutId(local_id(0)); }
+  TypeFeedbackId test_id() const { return TypeFeedbackId(local_id(1)); }
 
  protected:
-  Expression(Zone* zone, int pos, IdGen* id_gen)
+  Expression(Zone* zone, int pos)
       : AstNode(pos),
+        base_id_(BailoutId::None().ToInt()),
         bounds_(Bounds::Unbounded(zone)),
-        parenthesization_level_(0),
-        id_(id_gen->GetNextId()),
-        test_id_(id_gen->GetNextId()) {}
-  void set_to_boolean_types(byte types) { to_boolean_types_ = types; }
+        bit_field_(0) {}
+  static int parent_num_ids() { return 0; }
+  void set_to_boolean_types(byte types) {
+    bit_field_ = ToBooleanTypesField::update(bit_field_, types);
+  }
+
+  int base_id() const {
+    DCHECK(!BailoutId(base_id_).IsNone());
+    return base_id_;
+  }
 
  private:
-  Bounds bounds_;
-  byte to_boolean_types_;
-  unsigned parenthesization_level_;
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
 
-  const BailoutId id_;
-  const TypeFeedbackId test_id_;
+  int base_id_;
+  Bounds bounds_;
+  class ToBooleanTypesField : public BitField16<byte, 0, 8> {};
+  class IsParenthesizedField : public BitField16<bool, 8, 1> {};
+  class IsMultiParenthesizedField : public BitField16<bool, 9, 1> {};
+  uint16_t bit_field_;
+  // Ends with 16-bit field; deriving classes in turn begin with
+  // 16-bit fields for optimum packing efficiency.
 };
 
 
@@ -410,9 +444,7 @@
   ZoneList<const AstRawString*>* labels() const { return labels_; }
 
   // Type testing & conversion.
-  virtual BreakableStatement* AsBreakableStatement() FINAL OVERRIDE {
-    return this;
-  }
+  BreakableStatement* AsBreakableStatement() FINAL { return this; }
 
   // Code generation
   Label* break_target() { return &break_target_; }
@@ -422,27 +454,34 @@
     return breakable_type_ == TARGET_FOR_ANONYMOUS;
   }
 
-  BailoutId EntryId() const { return entry_id_; }
-  BailoutId ExitId() const { return exit_id_; }
+  void set_base_id(int id) { base_id_ = id; }
+  static int num_ids() { return parent_num_ids() + 2; }
+  BailoutId EntryId() const { return BailoutId(local_id(0)); }
+  BailoutId ExitId() const { return BailoutId(local_id(1)); }
 
  protected:
   BreakableStatement(Zone* zone, ZoneList<const AstRawString*>* labels,
-                     BreakableType breakable_type, int position, IdGen* id_gen)
+                     BreakableType breakable_type, int position)
       : Statement(zone, position),
         labels_(labels),
         breakable_type_(breakable_type),
-        entry_id_(id_gen->GetNextId()),
-        exit_id_(id_gen->GetNextId()) {
+        base_id_(BailoutId::None().ToInt()) {
     DCHECK(labels == NULL || labels->length() > 0);
   }
+  static int parent_num_ids() { return 0; }
 
+  int base_id() const {
+    DCHECK(!BailoutId(base_id_).IsNone());
+    return base_id_;
+  }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
   ZoneList<const AstRawString*>* labels_;
   BreakableType breakable_type_;
   Label break_target_;
-  const BailoutId entry_id_;
-  const BailoutId exit_id_;
+  int base_id_;
 };
 
 
@@ -457,9 +496,10 @@
   ZoneList<Statement*>* statements() { return &statements_; }
   bool is_initializer_block() const { return is_initializer_block_; }
 
-  BailoutId DeclsId() const { return decls_id_; }
+  static int num_ids() { return parent_num_ids() + 1; }
+  BailoutId DeclsId() const { return BailoutId(local_id(0)); }
 
-  virtual bool IsJump() const OVERRIDE {
+  bool IsJump() const OVERRIDE {
     return !statements_.is_empty() && statements_.last()->IsJump()
         && labels() == NULL;  // Good enough as an approximation...
   }
@@ -469,17 +509,18 @@
 
  protected:
   Block(Zone* zone, ZoneList<const AstRawString*>* labels, int capacity,
-        bool is_initializer_block, int pos, IdGen* id_gen)
-      : BreakableStatement(zone, labels, TARGET_FOR_NAMED_ONLY, pos, id_gen),
+        bool is_initializer_block, int pos)
+      : BreakableStatement(zone, labels, TARGET_FOR_NAMED_ONLY, pos),
         statements_(capacity, zone),
         is_initializer_block_(is_initializer_block),
-        decls_id_(id_gen->GetNextId()),
         scope_(NULL) {}
+  static int parent_num_ids() { return BreakableStatement::num_ids(); }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
   ZoneList<Statement*> statements_;
   bool is_initializer_block_;
-  const BailoutId decls_id_;
   Scope* scope_;
 };
 
@@ -493,21 +534,15 @@
   virtual bool IsInlineable() const;
 
  protected:
-  Declaration(Zone* zone,
-              VariableProxy* proxy,
-              VariableMode mode,
-              Scope* scope,
+  Declaration(Zone* zone, VariableProxy* proxy, VariableMode mode, Scope* scope,
               int pos)
-      : AstNode(pos),
-        proxy_(proxy),
-        mode_(mode),
-        scope_(scope) {
+      : AstNode(pos), mode_(mode), proxy_(proxy), scope_(scope) {
     DCHECK(IsDeclaredVariableMode(mode));
   }
 
  private:
-  VariableProxy* proxy_;
   VariableMode mode_;
+  VariableProxy* proxy_;
 
   // Nested scope from which the declaration originated.
   Scope* scope_;
@@ -518,7 +553,7 @@
  public:
   DECLARE_NODE_TYPE(VariableDeclaration)
 
-  virtual InitializationFlag initialization() const OVERRIDE {
+  InitializationFlag initialization() const OVERRIDE {
     return mode() == VAR ? kCreatedInitialized : kNeedsInitialization;
   }
 
@@ -538,10 +573,10 @@
   DECLARE_NODE_TYPE(FunctionDeclaration)
 
   FunctionLiteral* fun() const { return fun_; }
-  virtual InitializationFlag initialization() const OVERRIDE {
+  InitializationFlag initialization() const OVERRIDE {
     return kCreatedInitialized;
   }
-  virtual bool IsInlineable() const OVERRIDE;
+  bool IsInlineable() const OVERRIDE;
 
  protected:
   FunctionDeclaration(Zone* zone,
@@ -567,7 +602,7 @@
   DECLARE_NODE_TYPE(ModuleDeclaration)
 
   Module* module() const { return module_; }
-  virtual InitializationFlag initialization() const OVERRIDE {
+  InitializationFlag initialization() const OVERRIDE {
     return kCreatedInitialized;
   }
 
@@ -591,7 +626,7 @@
   DECLARE_NODE_TYPE(ImportDeclaration)
 
   Module* module() const { return module_; }
-  virtual InitializationFlag initialization() const OVERRIDE {
+  InitializationFlag initialization() const OVERRIDE {
     return kCreatedInitialized;
   }
 
@@ -614,7 +649,7 @@
  public:
   DECLARE_NODE_TYPE(ExportDeclaration)
 
-  virtual InitializationFlag initialization() const OVERRIDE {
+  InitializationFlag initialization() const OVERRIDE {
     return kCreatedInitialized;
   }
 
@@ -725,13 +760,12 @@
 class IterationStatement : public BreakableStatement {
  public:
   // Type testing & conversion.
-  virtual IterationStatement* AsIterationStatement() FINAL OVERRIDE {
-    return this;
-  }
+  IterationStatement* AsIterationStatement() FINAL { return this; }
 
   Statement* body() const { return body_; }
 
-  BailoutId OsrEntryId() const { return osr_entry_id_; }
+  static int num_ids() { return parent_num_ids() + 1; }
+  BailoutId OsrEntryId() const { return BailoutId(local_id(0)); }
   virtual BailoutId ContinueId() const = 0;
   virtual BailoutId StackCheckId() const = 0;
 
@@ -739,21 +773,17 @@
   Label* continue_target()  { return &continue_target_; }
 
  protected:
-  IterationStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos,
-                     IdGen* id_gen)
-      : BreakableStatement(zone, labels, TARGET_FOR_ANONYMOUS, pos, id_gen),
-        body_(NULL),
-        osr_entry_id_(id_gen->GetNextId()) {}
-
-  void Initialize(Statement* body) {
-    body_ = body;
-  }
+  IterationStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+      : BreakableStatement(zone, labels, TARGET_FOR_ANONYMOUS, pos),
+        body_(NULL) {}
+  static int parent_num_ids() { return BreakableStatement::num_ids(); }
+  void Initialize(Statement* body) { body_ = body; }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
   Statement* body_;
   Label continue_target_;
-
-  const BailoutId osr_entry_id_;
 };
 
 
@@ -768,23 +798,20 @@
 
   Expression* cond() const { return cond_; }
 
-  virtual BailoutId ContinueId() const OVERRIDE { return continue_id_; }
-  virtual BailoutId StackCheckId() const OVERRIDE { return back_edge_id_; }
-  BailoutId BackEdgeId() const { return back_edge_id_; }
+  static int num_ids() { return parent_num_ids() + 2; }
+  BailoutId ContinueId() const OVERRIDE { return BailoutId(local_id(0)); }
+  BailoutId StackCheckId() const OVERRIDE { return BackEdgeId(); }
+  BailoutId BackEdgeId() const { return BailoutId(local_id(1)); }
 
  protected:
-  DoWhileStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos,
-                   IdGen* id_gen)
-      : IterationStatement(zone, labels, pos, id_gen),
-        cond_(NULL),
-        continue_id_(id_gen->GetNextId()),
-        back_edge_id_(id_gen->GetNextId()) {}
+  DoWhileStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+      : IterationStatement(zone, labels, pos), cond_(NULL) {}
+  static int parent_num_ids() { return IterationStatement::num_ids(); }
 
  private:
-  Expression* cond_;
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
 
-  const BailoutId continue_id_;
-  const BailoutId back_edge_id_;
+  Expression* cond_;
 };
 
 
@@ -798,32 +825,21 @@
   }
 
   Expression* cond() const { return cond_; }
-  bool may_have_function_literal() const {
-    return may_have_function_literal_;
-  }
-  void set_may_have_function_literal(bool value) {
-    may_have_function_literal_ = value;
-  }
 
-  virtual BailoutId ContinueId() const OVERRIDE { return EntryId(); }
-  virtual BailoutId StackCheckId() const OVERRIDE { return body_id_; }
-  BailoutId BodyId() const { return body_id_; }
+  static int num_ids() { return parent_num_ids() + 1; }
+  BailoutId ContinueId() const OVERRIDE { return EntryId(); }
+  BailoutId StackCheckId() const OVERRIDE { return BodyId(); }
+  BailoutId BodyId() const { return BailoutId(local_id(0)); }
 
  protected:
-  WhileStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos,
-                 IdGen* id_gen)
-      : IterationStatement(zone, labels, pos, id_gen),
-        cond_(NULL),
-        may_have_function_literal_(true),
-        body_id_(id_gen->GetNextId()) {}
+  WhileStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+      : IterationStatement(zone, labels, pos), cond_(NULL) {}
+  static int parent_num_ids() { return IterationStatement::num_ids(); }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
   Expression* cond_;
-
-  // True if there is a function literal subexpression in the condition.
-  bool may_have_function_literal_;
-
-  const BailoutId body_id_;
 };
 
 
@@ -845,44 +861,25 @@
   Expression* cond() const { return cond_; }
   Statement* next() const { return next_; }
 
-  bool may_have_function_literal() const {
-    return may_have_function_literal_;
-  }
-  void set_may_have_function_literal(bool value) {
-    may_have_function_literal_ = value;
-  }
-
-  virtual BailoutId ContinueId() const OVERRIDE { return continue_id_; }
-  virtual BailoutId StackCheckId() const OVERRIDE { return body_id_; }
-  BailoutId BodyId() const { return body_id_; }
-
-  bool is_fast_smi_loop() { return loop_variable_ != NULL; }
-  Variable* loop_variable() { return loop_variable_; }
-  void set_loop_variable(Variable* var) { loop_variable_ = var; }
+  static int num_ids() { return parent_num_ids() + 2; }
+  BailoutId ContinueId() const OVERRIDE { return BailoutId(local_id(0)); }
+  BailoutId StackCheckId() const OVERRIDE { return BodyId(); }
+  BailoutId BodyId() const { return BailoutId(local_id(1)); }
 
  protected:
-  ForStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos,
-               IdGen* id_gen)
-      : IterationStatement(zone, labels, pos, id_gen),
+  ForStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+      : IterationStatement(zone, labels, pos),
         init_(NULL),
         cond_(NULL),
-        next_(NULL),
-        may_have_function_literal_(true),
-        loop_variable_(NULL),
-        continue_id_(id_gen->GetNextId()),
-        body_id_(id_gen->GetNextId()) {}
+        next_(NULL) {}
+  static int parent_num_ids() { return IterationStatement::num_ids(); }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
   Statement* init_;
   Expression* cond_;
   Statement* next_;
-
-  // True if there is a function literal subexpression in the condition.
-  bool may_have_function_literal_;
-  Variable* loop_variable_;
-
-  const BailoutId continue_id_;
-  const BailoutId body_id_;
 };
 
 
@@ -903,11 +900,8 @@
   Expression* subject() const { return subject_; }
 
  protected:
-  ForEachStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos,
-                   IdGen* id_gen)
-      : IterationStatement(zone, labels, pos, id_gen),
-        each_(NULL),
-        subject_(NULL) {}
+  ForEachStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+      : IterationStatement(zone, labels, pos), each_(NULL), subject_(NULL) {}
 
  private:
   Expression* each_;
@@ -915,8 +909,7 @@
 };
 
 
-class ForInStatement FINAL : public ForEachStatement,
-    public FeedbackSlotInterface {
+class ForInStatement FINAL : public ForEachStatement {
  public:
   DECLARE_NODE_TYPE(ForInStatement)
 
@@ -925,11 +918,16 @@
   }
 
   // Type feedback information.
-  virtual int ComputeFeedbackSlotCount() { return 1; }
-  virtual void SetFirstFeedbackSlot(int slot) { for_in_feedback_slot_ = slot; }
+  virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
+      Isolate* isolate) OVERRIDE {
+    return FeedbackVectorRequirements(1, 0);
+  }
+  void SetFirstFeedbackSlot(FeedbackVectorSlot slot) OVERRIDE {
+    for_in_feedback_slot_ = slot;
+  }
 
-  int ForInFeedbackSlot() {
-    DCHECK(for_in_feedback_slot_ != kInvalidFeedbackSlot);
+  FeedbackVectorSlot ForInFeedbackSlot() {
+    DCHECK(!for_in_feedback_slot_.IsInvalid());
     return for_in_feedback_slot_;
   }
 
@@ -937,24 +935,26 @@
   ForInType for_in_type() const { return for_in_type_; }
   void set_for_in_type(ForInType type) { for_in_type_ = type; }
 
-  BailoutId BodyId() const { return body_id_; }
-  BailoutId PrepareId() const { return prepare_id_; }
-  virtual BailoutId ContinueId() const OVERRIDE { return EntryId(); }
-  virtual BailoutId StackCheckId() const OVERRIDE { return body_id_; }
+  static int num_ids() { return parent_num_ids() + 4; }
+  BailoutId BodyId() const { return BailoutId(local_id(0)); }
+  BailoutId PrepareId() const { return BailoutId(local_id(1)); }
+  BailoutId EnumId() const { return BailoutId(local_id(2)); }
+  BailoutId ToObjectId() const { return BailoutId(local_id(3)); }
+  BailoutId ContinueId() const OVERRIDE { return EntryId(); }
+  BailoutId StackCheckId() const OVERRIDE { return BodyId(); }
 
  protected:
-  ForInStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos,
-                 IdGen* id_gen)
-      : ForEachStatement(zone, labels, pos, id_gen),
+  ForInStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+      : ForEachStatement(zone, labels, pos),
         for_in_type_(SLOW_FOR_IN),
-        for_in_feedback_slot_(kInvalidFeedbackSlot),
-        body_id_(id_gen->GetNextId()),
-        prepare_id_(id_gen->GetNextId()) {}
+        for_in_feedback_slot_(FeedbackVectorSlot::Invalid()) {}
+  static int parent_num_ids() { return ForEachStatement::num_ids(); }
+
+ private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
 
   ForInType for_in_type_;
-  int for_in_feedback_slot_;
-  const BailoutId body_id_;
-  const BailoutId prepare_id_;
+  FeedbackVectorSlot for_in_feedback_slot_;
 };
 
 
@@ -1000,26 +1000,28 @@
     return assign_each_;
   }
 
-  virtual BailoutId ContinueId() const OVERRIDE { return EntryId(); }
-  virtual BailoutId StackCheckId() const OVERRIDE { return BackEdgeId(); }
+  BailoutId ContinueId() const OVERRIDE { return EntryId(); }
+  BailoutId StackCheckId() const OVERRIDE { return BackEdgeId(); }
 
-  BailoutId BackEdgeId() const { return back_edge_id_; }
+  static int num_ids() { return parent_num_ids() + 1; }
+  BailoutId BackEdgeId() const { return BailoutId(local_id(0)); }
 
  protected:
-  ForOfStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos,
-                 IdGen* id_gen)
-      : ForEachStatement(zone, labels, pos, id_gen),
+  ForOfStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+      : ForEachStatement(zone, labels, pos),
         assign_iterator_(NULL),
         next_result_(NULL),
         result_done_(NULL),
-        assign_each_(NULL),
-        back_edge_id_(id_gen->GetNextId()) {}
+        assign_each_(NULL) {}
+  static int parent_num_ids() { return ForEachStatement::num_ids(); }
+
+ private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
 
   Expression* assign_iterator_;
   Expression* next_result_;
   Expression* result_done_;
   Expression* assign_each_;
-  const BailoutId back_edge_id_;
 };
 
 
@@ -1029,7 +1031,7 @@
 
   void set_expression(Expression* e) { expression_ = e; }
   Expression* expression() const { return expression_; }
-  virtual bool IsJump() const OVERRIDE { return expression_->IsThrow(); }
+  bool IsJump() const OVERRIDE { return expression_->IsThrow(); }
 
  protected:
   ExpressionStatement(Zone* zone, Expression* expression, int pos)
@@ -1042,7 +1044,7 @@
 
 class JumpStatement : public Statement {
  public:
-  virtual bool IsJump() const FINAL OVERRIDE { return true; }
+  bool IsJump() const FINAL { return true; }
 
  protected:
   explicit JumpStatement(Zone* zone, int pos) : Statement(zone, pos) {}
@@ -1130,24 +1132,25 @@
   Label* body_target() { return &body_target_; }
   ZoneList<Statement*>* statements() const { return statements_; }
 
-  BailoutId EntryId() const { return entry_id_; }
+  static int num_ids() { return parent_num_ids() + 2; }
+  BailoutId EntryId() const { return BailoutId(local_id(0)); }
+  TypeFeedbackId CompareId() { return TypeFeedbackId(local_id(1)); }
 
-  // Type feedback information.
-  TypeFeedbackId CompareId() { return compare_id_; }
   Type* compare_type() { return compare_type_; }
   void set_compare_type(Type* type) { compare_type_ = type; }
 
+ protected:
+  static int parent_num_ids() { return Expression::num_ids(); }
+
  private:
   CaseClause(Zone* zone, Expression* label, ZoneList<Statement*>* statements,
-             int pos, IdGen* id_gen);
+             int pos);
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
 
   Expression* label_;
   Label body_target_;
   ZoneList<Statement*>* statements_;
   Type* compare_type_;
-
-  const TypeFeedbackId compare_id_;
-  const BailoutId entry_id_;
 };
 
 
@@ -1164,9 +1167,8 @@
   ZoneList<CaseClause*>* cases() const { return cases_; }
 
  protected:
-  SwitchStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos,
-                  IdGen* id_gen)
-      : BreakableStatement(zone, labels, TARGET_FOR_ANONYMOUS, pos, id_gen),
+  SwitchStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+      : BreakableStatement(zone, labels, TARGET_FOR_ANONYMOUS, pos),
         tag_(NULL),
         cases_(NULL) {}
 
@@ -1192,33 +1194,39 @@
   Statement* then_statement() const { return then_statement_; }
   Statement* else_statement() const { return else_statement_; }
 
-  virtual bool IsJump() const OVERRIDE {
+  bool IsJump() const OVERRIDE {
     return HasThenStatement() && then_statement()->IsJump()
         && HasElseStatement() && else_statement()->IsJump();
   }
 
-  BailoutId IfId() const { return if_id_; }
-  BailoutId ThenId() const { return then_id_; }
-  BailoutId ElseId() const { return else_id_; }
+  void set_base_id(int id) { base_id_ = id; }
+  static int num_ids() { return parent_num_ids() + 3; }
+  BailoutId IfId() const { return BailoutId(local_id(0)); }
+  BailoutId ThenId() const { return BailoutId(local_id(1)); }
+  BailoutId ElseId() const { return BailoutId(local_id(2)); }
 
  protected:
   IfStatement(Zone* zone, Expression* condition, Statement* then_statement,
-              Statement* else_statement, int pos, IdGen* id_gen)
+              Statement* else_statement, int pos)
       : Statement(zone, pos),
         condition_(condition),
         then_statement_(then_statement),
         else_statement_(else_statement),
-        if_id_(id_gen->GetNextId()),
-        then_id_(id_gen->GetNextId()),
-        else_id_(id_gen->GetNextId()) {}
+        base_id_(BailoutId::None().ToInt()) {}
+  static int parent_num_ids() { return 0; }
+
+  int base_id() const {
+    DCHECK(!BailoutId(base_id_).IsNone());
+    return base_id_;
+  }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
   Expression* condition_;
   Statement* then_statement_;
   Statement* else_statement_;
-  const BailoutId if_id_;
-  const BailoutId then_id_;
-  const BailoutId else_id_;
+  int base_id_;
 };
 
 
@@ -1235,9 +1243,9 @@
   void AddTarget(Label* target, Zone* zone);
 
   // Virtual behaviour. TargetCollectors are never part of the AST.
-  virtual void Accept(AstVisitor* v) OVERRIDE { UNREACHABLE(); }
-  virtual NodeType node_type() const OVERRIDE { return kInvalid; }
-  virtual TargetCollector* AsTargetCollector() OVERRIDE { return this; }
+  void Accept(AstVisitor* v) OVERRIDE { UNREACHABLE(); }
+  NodeType node_type() const OVERRIDE { return kInvalid; }
+  TargetCollector* AsTargetCollector() OVERRIDE { return this; }
 
   ZoneList<Label*>* targets() { return &targets_; }
 
@@ -1322,14 +1330,24 @@
  public:
   DECLARE_NODE_TYPE(DebuggerStatement)
 
-  BailoutId DebugBreakId() const { return debugger_id_; }
+  void set_base_id(int id) { base_id_ = id; }
+  static int num_ids() { return parent_num_ids() + 1; }
+  BailoutId DebugBreakId() const { return BailoutId(local_id(0)); }
 
  protected:
-  explicit DebuggerStatement(Zone* zone, int pos, IdGen* id_gen)
-      : Statement(zone, pos), debugger_id_(id_gen->GetNextId()) {}
+  explicit DebuggerStatement(Zone* zone, int pos)
+      : Statement(zone, pos), base_id_(BailoutId::None().ToInt()) {}
+  static int parent_num_ids() { return 0; }
+
+  int base_id() const {
+    DCHECK(!BailoutId(base_id_).IsNone());
+    return base_id_;
+  }
 
  private:
-  const BailoutId debugger_id_;
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+  int base_id_;
 };
 
 
@@ -1346,9 +1364,7 @@
  public:
   DECLARE_NODE_TYPE(Literal)
 
-  virtual bool IsPropertyName() const OVERRIDE {
-    return value_->IsPropertyName();
-  }
+  bool IsPropertyName() const OVERRIDE { return value_->IsPropertyName(); }
 
   Handle<String> AsPropertyName() {
     DCHECK(IsPropertyName());
@@ -1360,40 +1376,31 @@
     return value_->AsString();
   }
 
-  virtual bool ToBooleanIsTrue() const OVERRIDE {
-    return value()->BooleanValue();
-  }
-  virtual bool ToBooleanIsFalse() const OVERRIDE {
-    return !value()->BooleanValue();
-  }
+  bool ToBooleanIsTrue() const OVERRIDE { return value()->BooleanValue(); }
+  bool ToBooleanIsFalse() const OVERRIDE { return !value()->BooleanValue(); }
 
   Handle<Object> value() const { return value_->value(); }
   const AstValue* raw_value() const { return value_; }
 
   // Support for using Literal as a HashMap key. NOTE: Currently, this works
   // only for string and number literals!
-  uint32_t Hash() { return ToString()->Hash(); }
+  uint32_t Hash();
+  static bool Match(void* literal1, void* literal2);
 
-  static bool Match(void* literal1, void* literal2) {
-    Handle<String> s1 = static_cast<Literal*>(literal1)->ToString();
-    Handle<String> s2 = static_cast<Literal*>(literal2)->ToString();
-    return String::Equals(s1, s2);
+  static int num_ids() { return parent_num_ids() + 1; }
+  TypeFeedbackId LiteralFeedbackId() const {
+    return TypeFeedbackId(local_id(0));
   }
 
-  TypeFeedbackId LiteralFeedbackId() const { return reuse(id()); }
-
  protected:
-  Literal(Zone* zone, const AstValue* value, int position, IdGen* id_gen)
-      : Expression(zone, position, id_gen),
-        value_(value),
-        isolate_(zone->isolate()) {}
+  Literal(Zone* zone, const AstValue* value, int position)
+      : Expression(zone, position), value_(value) {}
+  static int parent_num_ids() { return Expression::num_ids(); }
 
  private:
-  Handle<String> ToString();
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
 
   const AstValue* value_;
-  // TODO(dcarney): remove.  this is only needed for Match and Hash.
-  Isolate* isolate_;
 };
 
 
@@ -1411,8 +1418,8 @@
   }
 
  protected:
-  MaterializedLiteral(Zone* zone, int literal_index, int pos, IdGen* id_gen)
-      : Expression(zone, pos, id_gen),
+  MaterializedLiteral(Zone* zone, int literal_index, int pos)
+      : Expression(zone, pos),
         literal_index_(literal_index),
         is_simple_(false),
         depth_(0) {}
@@ -1477,8 +1484,10 @@
   void set_emit_store(bool emit_store);
   bool emit_store();
 
+  bool is_static() const { return is_static_; }
+
  protected:
-  template<class> friend class AstNodeFactory;
+  friend class AstNodeFactory;
 
   ObjectLiteralProperty(Zone* zone, bool is_getter, FunctionLiteral* value,
                         bool is_static);
@@ -1535,23 +1544,28 @@
   };
 
   struct Accessors: public ZoneObject {
-    Accessors() : getter(NULL), setter(NULL) { }
+    Accessors() : getter(NULL), setter(NULL) {}
     Expression* getter;
     Expression* setter;
   };
 
+  BailoutId CreateLiteralId() const { return BailoutId(local_id(0)); }
+
+  static int num_ids() { return parent_num_ids() + 1; }
+
  protected:
   ObjectLiteral(Zone* zone, ZoneList<Property*>* properties, int literal_index,
-                int boilerplate_properties, bool has_function, int pos,
-                IdGen* id_gen)
-      : MaterializedLiteral(zone, literal_index, pos, id_gen),
+                int boilerplate_properties, bool has_function, int pos)
+      : MaterializedLiteral(zone, literal_index, pos),
         properties_(properties),
         boilerplate_properties_(boilerplate_properties),
         fast_elements_(false),
         may_store_doubles_(false),
         has_function_(has_function) {}
+  static int parent_num_ids() { return MaterializedLiteral::num_ids(); }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
   Handle<FixedArray> constant_properties_;
   ZoneList<Property*>* properties_;
   int boilerplate_properties_;
@@ -1571,9 +1585,8 @@
 
  protected:
   RegExpLiteral(Zone* zone, const AstRawString* pattern,
-                const AstRawString* flags, int literal_index, int pos,
-                IdGen* id_gen)
-      : MaterializedLiteral(zone, literal_index, pos, id_gen),
+                const AstRawString* flags, int literal_index, int pos)
+      : MaterializedLiteral(zone, literal_index, pos),
         pattern_(pattern),
         flags_(flags) {
     set_depth(1);
@@ -1594,10 +1607,12 @@
   Handle<FixedArray> constant_elements() const { return constant_elements_; }
   ZoneList<Expression*>* values() const { return values_; }
 
+  // Unlike other AST nodes, this number of bailout IDs allocated for an
+  // ArrayLiteral can vary, so num_ids() is not a static method.
+  int num_ids() const { return parent_num_ids() + values()->length(); }
+
   // Return an AST id for an element that is used in simulate instructions.
-  BailoutId GetIdForElement(int i) {
-    return BailoutId(first_element_id_.ToInt() + i);
-  }
+  BailoutId GetIdForElement(int i) { return BailoutId(local_id(i)); }
 
   // Populate the constant elements fixed array.
   void BuildConstantElements(Isolate* isolate);
@@ -1617,132 +1632,191 @@
 
  protected:
   ArrayLiteral(Zone* zone, ZoneList<Expression*>* values, int literal_index,
-               int pos, IdGen* id_gen)
-      : MaterializedLiteral(zone, literal_index, pos, id_gen),
-        values_(values),
-        first_element_id_(id_gen->ReserveIdRange(values->length())) {}
+               int pos)
+      : MaterializedLiteral(zone, literal_index, pos), values_(values) {}
+  static int parent_num_ids() { return MaterializedLiteral::num_ids(); }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
   Handle<FixedArray> constant_elements_;
   ZoneList<Expression*>* values_;
-  const BailoutId first_element_id_;
 };
 
 
-class VariableProxy FINAL : public Expression, public FeedbackSlotInterface {
+class VariableProxy FINAL : public Expression {
  public:
   DECLARE_NODE_TYPE(VariableProxy)
 
-  virtual bool IsValidReferenceExpression() const OVERRIDE {
-    return var_ == NULL ? true : var_->IsValidReference();
+  bool IsValidReferenceExpression() const OVERRIDE {
+    return !is_resolved() || var()->IsValidReference();
   }
 
-  bool IsArguments() const { return var_ != NULL && var_->is_arguments(); }
+  bool IsArguments() const { return is_resolved() && var()->is_arguments(); }
 
-  Handle<String> name() const { return name_->string(); }
-  const AstRawString* raw_name() const { return name_; }
-  Variable* var() const { return var_; }
-  bool is_this() const { return is_this_; }
+  Handle<String> name() const { return raw_name()->string(); }
+  const AstRawString* raw_name() const {
+    return is_resolved() ? var_->raw_name() : raw_name_;
+  }
+
+  Variable* var() const {
+    DCHECK(is_resolved());
+    return var_;
+  }
+  void set_var(Variable* v) {
+    DCHECK(!is_resolved());
+    DCHECK_NOT_NULL(v);
+    var_ = v;
+  }
+
+  bool is_this() const { return IsThisField::decode(bit_field_); }
+
+  bool is_assigned() const { return IsAssignedField::decode(bit_field_); }
+  void set_is_assigned() {
+    bit_field_ = IsAssignedField::update(bit_field_, true);
+  }
+
+  bool is_resolved() const { return IsResolvedField::decode(bit_field_); }
+  void set_is_resolved() {
+    bit_field_ = IsResolvedField::update(bit_field_, true);
+  }
+
   Interface* interface() const { return interface_; }
 
-  bool is_assigned() const { return is_assigned_; }
-  void set_is_assigned() { is_assigned_ = true; }
-
   // Bind this proxy to the variable var. Interfaces must match.
   void BindTo(Variable* var);
 
-  virtual int ComputeFeedbackSlotCount() { return FLAG_vector_ics ? 1 : 0; }
-  virtual void SetFirstFeedbackSlot(int slot) {
-    variable_feedback_slot_ = slot;
+  bool UsesVariableFeedbackSlot() const {
+    return FLAG_vector_ics && (var()->IsUnallocated() || var()->IsLookupSlot());
   }
 
-  int VariableFeedbackSlot() { return variable_feedback_slot_; }
+  virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
+      Isolate* isolate) OVERRIDE {
+    return FeedbackVectorRequirements(0, UsesVariableFeedbackSlot() ? 1 : 0);
+  }
+
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
+    variable_feedback_slot_ = slot;
+  }
+  Code::Kind FeedbackICSlotKind(int index) OVERRIDE { return Code::LOAD_IC; }
+  FeedbackVectorICSlot VariableFeedbackSlot() {
+    DCHECK(!UsesVariableFeedbackSlot() || !variable_feedback_slot_.IsInvalid());
+    return variable_feedback_slot_;
+  }
 
  protected:
-  VariableProxy(Zone* zone, Variable* var, int position, IdGen* id_gen);
+  VariableProxy(Zone* zone, Variable* var, int position);
 
   VariableProxy(Zone* zone, const AstRawString* name, bool is_this,
-                Interface* interface, int position, IdGen* id_gen);
+                Interface* interface, int position);
 
-  const AstRawString* name_;
-  Variable* var_;  // resolved variable, or NULL
-  bool is_this_;
-  bool is_assigned_;
+  class IsThisField : public BitField8<bool, 0, 1> {};
+  class IsAssignedField : public BitField8<bool, 1, 1> {};
+  class IsResolvedField : public BitField8<bool, 2, 1> {};
+
+  // Start with 16-bit (or smaller) field, which should get packed together
+  // with Expression's trailing 16-bit field.
+  uint8_t bit_field_;
+  FeedbackVectorICSlot variable_feedback_slot_;
+  union {
+    const AstRawString* raw_name_;  // if !is_resolved_
+    Variable* var_;                 // if is_resolved_
+  };
   Interface* interface_;
-  int variable_feedback_slot_;
 };
 
 
-class Property FINAL : public Expression, public FeedbackSlotInterface {
+class Property FINAL : public Expression {
  public:
   DECLARE_NODE_TYPE(Property)
 
-  virtual bool IsValidReferenceExpression() const OVERRIDE { return true; }
+  bool IsValidReferenceExpression() const OVERRIDE { return true; }
 
   Expression* obj() const { return obj_; }
   Expression* key() const { return key_; }
 
-  BailoutId LoadId() const { return load_id_; }
+  static int num_ids() { return parent_num_ids() + 2; }
+  BailoutId LoadId() const { return BailoutId(local_id(0)); }
+  TypeFeedbackId PropertyFeedbackId() { return TypeFeedbackId(local_id(1)); }
 
-  bool IsStringAccess() const { return is_string_access_; }
+  bool IsStringAccess() const {
+    return IsStringAccessField::decode(bit_field_);
+  }
 
   // Type feedback information.
-  virtual bool IsMonomorphic() OVERRIDE {
-    return receiver_types_.length() == 1;
+  bool IsMonomorphic() OVERRIDE { return receiver_types_.length() == 1; }
+  SmallMapList* GetReceiverTypes() OVERRIDE { return &receiver_types_; }
+  KeyedAccessStoreMode GetStoreMode() const OVERRIDE { return STANDARD_STORE; }
+  IcCheckType GetKeyType() const OVERRIDE {
+    return KeyTypeField::decode(bit_field_);
   }
-  virtual SmallMapList* GetReceiverTypes() OVERRIDE {
-    return &receiver_types_;
+  bool IsUninitialized() const {
+    return !is_for_call() && HasNoTypeInformation();
   }
-  virtual KeyedAccessStoreMode GetStoreMode() OVERRIDE {
-    return STANDARD_STORE;
+  bool HasNoTypeInformation() const {
+    return IsUninitializedField::decode(bit_field_);
   }
-  bool IsUninitialized() { return !is_for_call_ && is_uninitialized_; }
-  bool HasNoTypeInformation() {
-    return is_uninitialized_;
+  void set_is_uninitialized(bool b) {
+    bit_field_ = IsUninitializedField::update(bit_field_, b);
   }
-  void set_is_uninitialized(bool b) { is_uninitialized_ = b; }
-  void set_is_string_access(bool b) { is_string_access_ = b; }
-  void mark_for_call() { is_for_call_ = true; }
-  bool IsForCall() { return is_for_call_; }
+  void set_is_string_access(bool b) {
+    bit_field_ = IsStringAccessField::update(bit_field_, b);
+  }
+  void set_key_type(IcCheckType key_type) {
+    bit_field_ = KeyTypeField::update(bit_field_, key_type);
+  }
+  void mark_for_call() {
+    bit_field_ = IsForCallField::update(bit_field_, true);
+  }
+  bool is_for_call() const { return IsForCallField::decode(bit_field_); }
 
   bool IsSuperAccess() {
     return obj()->IsSuperReference();
   }
 
-  TypeFeedbackId PropertyFeedbackId() { return reuse(id()); }
-
-  virtual int ComputeFeedbackSlotCount() { return FLAG_vector_ics ? 1 : 0; }
-  virtual void SetFirstFeedbackSlot(int slot) {
+  virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
+      Isolate* isolate) OVERRIDE {
+    return FeedbackVectorRequirements(0, FLAG_vector_ics ? 1 : 0);
+  }
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
     property_feedback_slot_ = slot;
   }
+  Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
+    return key()->IsPropertyName() ? Code::LOAD_IC : Code::KEYED_LOAD_IC;
+  }
 
-  int PropertyFeedbackSlot() const { return property_feedback_slot_; }
+  FeedbackVectorICSlot PropertyFeedbackSlot() const {
+    DCHECK(!FLAG_vector_ics || !property_feedback_slot_.IsInvalid());
+    return property_feedback_slot_;
+  }
 
  protected:
-  Property(Zone* zone, Expression* obj, Expression* key, int pos, IdGen* id_gen)
-      : Expression(zone, pos, id_gen),
+  Property(Zone* zone, Expression* obj, Expression* key, int pos)
+      : Expression(zone, pos),
+        bit_field_(IsForCallField::encode(false) |
+                   IsUninitializedField::encode(false) |
+                   IsStringAccessField::encode(false)),
+        property_feedback_slot_(FeedbackVectorICSlot::Invalid()),
         obj_(obj),
-        key_(key),
-        load_id_(id_gen->GetNextId()),
-        property_feedback_slot_(kInvalidFeedbackSlot),
-        is_for_call_(false),
-        is_uninitialized_(false),
-        is_string_access_(false) {}
+        key_(key) {}
+  static int parent_num_ids() { return Expression::num_ids(); }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+  class IsForCallField : public BitField8<bool, 0, 1> {};
+  class IsUninitializedField : public BitField8<bool, 1, 1> {};
+  class IsStringAccessField : public BitField8<bool, 2, 1> {};
+  class KeyTypeField : public BitField8<IcCheckType, 3, 1> {};
+  uint8_t bit_field_;
+  FeedbackVectorICSlot property_feedback_slot_;
   Expression* obj_;
   Expression* key_;
-  const BailoutId load_id_;
-  int property_feedback_slot_;
-
   SmallMapList receiver_types_;
-  bool is_for_call_ : 1;
-  bool is_uninitialized_ : 1;
-  bool is_string_access_ : 1;
 };
 
 
-class Call FINAL : public Expression, public FeedbackSlotInterface {
+class Call FINAL : public Expression {
  public:
   DECLARE_NODE_TYPE(Call)
 
@@ -1750,24 +1824,27 @@
   ZoneList<Expression*>* arguments() const { return arguments_; }
 
   // Type feedback information.
-  virtual int ComputeFeedbackSlotCount() { return 1; }
-  virtual void SetFirstFeedbackSlot(int slot) {
+  virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
+      Isolate* isolate) OVERRIDE;
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
     call_feedback_slot_ = slot;
   }
+  Code::Kind FeedbackICSlotKind(int index) OVERRIDE { return Code::CALL_IC; }
 
-  bool HasCallFeedbackSlot() const {
-    return call_feedback_slot_ != kInvalidFeedbackSlot;
+  bool HasCallFeedbackSlot() const { return !call_feedback_slot_.IsInvalid(); }
+  FeedbackVectorICSlot CallFeedbackSlot() const {
+    DCHECK(!call_feedback_slot_.IsInvalid());
+    return call_feedback_slot_;
   }
-  int CallFeedbackSlot() const { return call_feedback_slot_; }
 
-  virtual SmallMapList* GetReceiverTypes() OVERRIDE {
+  SmallMapList* GetReceiverTypes() OVERRIDE {
     if (expression()->IsProperty()) {
       return expression()->AsProperty()->GetReceiverTypes();
     }
     return NULL;
   }
 
-  virtual bool IsMonomorphic() OVERRIDE {
+  bool IsMonomorphic() OVERRIDE {
     if (expression()->IsProperty()) {
       return expression()->AsProperty()->IsMonomorphic();
     }
@@ -1795,13 +1872,23 @@
   }
   bool ComputeGlobalTarget(Handle<GlobalObject> global, LookupIterator* it);
 
-  BailoutId ReturnId() const { return return_id_; }
+  static int num_ids() { return parent_num_ids() + 2; }
+  BailoutId ReturnId() const { return BailoutId(local_id(0)); }
+  BailoutId EvalOrLookupId() const { return BailoutId(local_id(1)); }
+
+  bool is_uninitialized() const {
+    return IsUninitializedField::decode(bit_field_);
+  }
+  void set_is_uninitialized(bool b) {
+    bit_field_ = IsUninitializedField::update(bit_field_, b);
+  }
 
   enum CallType {
     POSSIBLY_EVAL_CALL,
     GLOBAL_CALL,
     LOOKUP_SLOT_CALL,
     PROPERTY_CALL,
+    SUPER_CALL,
     OTHER_CALL
   };
 
@@ -1816,31 +1903,33 @@
 
  protected:
   Call(Zone* zone, Expression* expression, ZoneList<Expression*>* arguments,
-       int pos, IdGen* id_gen)
-      : Expression(zone, pos, id_gen),
+       int pos)
+      : Expression(zone, pos),
+        call_feedback_slot_(FeedbackVectorICSlot::Invalid()),
         expression_(expression),
         arguments_(arguments),
-        call_feedback_slot_(kInvalidFeedbackSlot),
-        return_id_(id_gen->GetNextId()) {
+        bit_field_(IsUninitializedField::encode(false)) {
     if (expression->IsProperty()) {
       expression->AsProperty()->mark_for_call();
     }
   }
+  static int parent_num_ids() { return Expression::num_ids(); }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+  FeedbackVectorICSlot call_feedback_slot_;
   Expression* expression_;
   ZoneList<Expression*>* arguments_;
-
   Handle<JSFunction> target_;
   Handle<Cell> cell_;
   Handle<AllocationSite> allocation_site_;
-  int call_feedback_slot_;
-
-  const BailoutId return_id_;
+  class IsUninitializedField : public BitField8<bool, 0, 1> {};
+  uint8_t bit_field_;
 };
 
 
-class CallNew FINAL : public Expression, public FeedbackSlotInterface {
+class CallNew FINAL : public Expression {
  public:
   DECLARE_NODE_TYPE(CallNew)
 
@@ -1848,57 +1937,54 @@
   ZoneList<Expression*>* arguments() const { return arguments_; }
 
   // Type feedback information.
-  virtual int ComputeFeedbackSlotCount() {
-    return FLAG_pretenuring_call_new ? 2 : 1;
+  virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
+      Isolate* isolate) OVERRIDE {
+    return FeedbackVectorRequirements(FLAG_pretenuring_call_new ? 2 : 1, 0);
   }
-  virtual void SetFirstFeedbackSlot(int slot) {
+  void SetFirstFeedbackSlot(FeedbackVectorSlot slot) OVERRIDE {
     callnew_feedback_slot_ = slot;
   }
 
-  int CallNewFeedbackSlot() {
-    DCHECK(callnew_feedback_slot_ != kInvalidFeedbackSlot);
+  FeedbackVectorSlot CallNewFeedbackSlot() {
+    DCHECK(!callnew_feedback_slot_.IsInvalid());
     return callnew_feedback_slot_;
   }
-  int AllocationSiteFeedbackSlot() {
-    DCHECK(callnew_feedback_slot_ != kInvalidFeedbackSlot);
+  FeedbackVectorSlot AllocationSiteFeedbackSlot() {
     DCHECK(FLAG_pretenuring_call_new);
-    return callnew_feedback_slot_ + 1;
+    return CallNewFeedbackSlot().next();
   }
 
   void RecordTypeFeedback(TypeFeedbackOracle* oracle);
-  virtual bool IsMonomorphic() OVERRIDE { return is_monomorphic_; }
+  bool IsMonomorphic() OVERRIDE { return is_monomorphic_; }
   Handle<JSFunction> target() const { return target_; }
-  ElementsKind elements_kind() const { return elements_kind_; }
   Handle<AllocationSite> allocation_site() const {
     return allocation_site_;
   }
 
+  static int num_ids() { return parent_num_ids() + 1; }
   static int feedback_slots() { return 1; }
-
-  BailoutId ReturnId() const { return return_id_; }
+  BailoutId ReturnId() const { return BailoutId(local_id(0)); }
 
  protected:
   CallNew(Zone* zone, Expression* expression, ZoneList<Expression*>* arguments,
-          int pos, IdGen* id_gen)
-      : Expression(zone, pos, id_gen),
+          int pos)
+      : Expression(zone, pos),
         expression_(expression),
         arguments_(arguments),
         is_monomorphic_(false),
-        elements_kind_(GetInitialFastElementsKind()),
-        callnew_feedback_slot_(kInvalidFeedbackSlot),
-        return_id_(id_gen->GetNextId()) {}
+        callnew_feedback_slot_(FeedbackVectorSlot::Invalid()) {}
+
+  static int parent_num_ids() { return Expression::num_ids(); }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
   Expression* expression_;
   ZoneList<Expression*>* arguments_;
-
   bool is_monomorphic_;
   Handle<JSFunction> target_;
-  ElementsKind elements_kind_;
   Handle<AllocationSite> allocation_site_;
-  int callnew_feedback_slot_;
-
-  const BailoutId return_id_;
+  FeedbackVectorSlot callnew_feedback_slot_;
 };
 
 
@@ -1906,7 +1992,7 @@
 // language construct. Instead it is used to call a C or JS function
 // with a set of arguments. This is used from the builtins that are
 // implemented in JavaScript (see "v8natives.js").
-class CallRuntime FINAL : public Expression, public FeedbackSlotInterface {
+class CallRuntime FINAL : public Expression {
  public:
   DECLARE_NODE_TYPE(CallRuntime)
 
@@ -1917,35 +2003,47 @@
   bool is_jsruntime() const { return function_ == NULL; }
 
   // Type feedback information.
-  virtual int ComputeFeedbackSlotCount() {
-    return (FLAG_vector_ics && is_jsruntime()) ? 1 : 0;
+  bool HasCallRuntimeFeedbackSlot() const {
+    return FLAG_vector_ics && is_jsruntime();
   }
-  virtual void SetFirstFeedbackSlot(int slot) {
+  virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
+      Isolate* isolate) OVERRIDE {
+    return FeedbackVectorRequirements(0, HasCallRuntimeFeedbackSlot() ? 1 : 0);
+  }
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
     callruntime_feedback_slot_ = slot;
   }
+  Code::Kind FeedbackICSlotKind(int index) OVERRIDE { return Code::LOAD_IC; }
 
-  int CallRuntimeFeedbackSlot() {
-    DCHECK(!is_jsruntime() ||
-           callruntime_feedback_slot_ != kInvalidFeedbackSlot);
+  FeedbackVectorICSlot CallRuntimeFeedbackSlot() {
+    DCHECK(!HasCallRuntimeFeedbackSlot() ||
+           !callruntime_feedback_slot_.IsInvalid());
     return callruntime_feedback_slot_;
   }
 
-  TypeFeedbackId CallRuntimeFeedbackId() const { return reuse(id()); }
+  static int num_ids() { return parent_num_ids() + 1; }
+  TypeFeedbackId CallRuntimeFeedbackId() const {
+    return TypeFeedbackId(local_id(0));
+  }
 
  protected:
   CallRuntime(Zone* zone, const AstRawString* name,
               const Runtime::Function* function,
-              ZoneList<Expression*>* arguments, int pos, IdGen* id_gen)
-      : Expression(zone, pos, id_gen),
+              ZoneList<Expression*>* arguments, int pos)
+      : Expression(zone, pos),
         raw_name_(name),
         function_(function),
-        arguments_(arguments) {}
+        arguments_(arguments),
+        callruntime_feedback_slot_(FeedbackVectorICSlot::Invalid()) {}
+  static int parent_num_ids() { return Expression::num_ids(); }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
   const AstRawString* raw_name_;
   const Runtime::Function* function_;
   ZoneList<Expression*>* arguments_;
-  int callruntime_feedback_slot_;
+  FeedbackVectorICSlot callruntime_feedback_slot_;
 };
 
 
@@ -1956,31 +2054,27 @@
   Token::Value op() const { return op_; }
   Expression* expression() const { return expression_; }
 
-  BailoutId MaterializeTrueId() { return materialize_true_id_; }
-  BailoutId MaterializeFalseId() { return materialize_false_id_; }
+  // For unary not (Token::NOT), the AST ids where true and false will
+  // actually be materialized, respectively.
+  static int num_ids() { return parent_num_ids() + 2; }
+  BailoutId MaterializeTrueId() const { return BailoutId(local_id(0)); }
+  BailoutId MaterializeFalseId() const { return BailoutId(local_id(1)); }
 
   virtual void RecordToBooleanTypeFeedback(
       TypeFeedbackOracle* oracle) OVERRIDE;
 
  protected:
-  UnaryOperation(Zone* zone, Token::Value op, Expression* expression, int pos,
-                 IdGen* id_gen)
-      : Expression(zone, pos, id_gen),
-        op_(op),
-        expression_(expression),
-        materialize_true_id_(id_gen->GetNextId()),
-        materialize_false_id_(id_gen->GetNextId()) {
+  UnaryOperation(Zone* zone, Token::Value op, Expression* expression, int pos)
+      : Expression(zone, pos), op_(op), expression_(expression) {
     DCHECK(Token::IsUnaryOp(op));
   }
+  static int parent_num_ids() { return Expression::num_ids(); }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
   Token::Value op_;
   Expression* expression_;
-
-  // For unary not (Token::NOT), the AST ids where true and false will
-  // actually be materialized, respectively.
-  const BailoutId materialize_true_id_;
-  const BailoutId materialize_false_id_;
 };
 
 
@@ -1988,9 +2082,9 @@
  public:
   DECLARE_NODE_TYPE(BinaryOperation)
 
-  virtual bool ResultOverwriteAllowed() const OVERRIDE;
+  bool ResultOverwriteAllowed() const OVERRIDE;
 
-  Token::Value op() const { return op_; }
+  Token::Value op() const { return static_cast<Token::Value>(op_); }
   Expression* left() const { return left_; }
   Expression* right() const { return right_; }
   Handle<AllocationSite> allocation_site() const { return allocation_site_; }
@@ -1998,39 +2092,50 @@
     allocation_site_ = allocation_site;
   }
 
-  BailoutId RightId() const { return right_id_; }
+  // The short-circuit logical operations need an AST ID for their
+  // right-hand subexpression.
+  static int num_ids() { return parent_num_ids() + 2; }
+  BailoutId RightId() const { return BailoutId(local_id(0)); }
 
-  TypeFeedbackId BinaryOperationFeedbackId() const { return reuse(id()); }
-  Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
-  void set_fixed_right_arg(Maybe<int> arg) { fixed_right_arg_ = arg; }
+  TypeFeedbackId BinaryOperationFeedbackId() const {
+    return TypeFeedbackId(local_id(1));
+  }
+  Maybe<int> fixed_right_arg() const {
+    return has_fixed_right_arg_ ? Maybe<int>(fixed_right_arg_value_)
+                                : Maybe<int>();
+  }
+  void set_fixed_right_arg(Maybe<int> arg) {
+    has_fixed_right_arg_ = arg.has_value;
+    if (arg.has_value) fixed_right_arg_value_ = arg.value;
+  }
 
   virtual void RecordToBooleanTypeFeedback(
       TypeFeedbackOracle* oracle) OVERRIDE;
 
  protected:
   BinaryOperation(Zone* zone, Token::Value op, Expression* left,
-                  Expression* right, int pos, IdGen* id_gen)
-      : Expression(zone, pos, id_gen),
-        op_(op),
+                  Expression* right, int pos)
+      : Expression(zone, pos),
+        op_(static_cast<byte>(op)),
+        has_fixed_right_arg_(false),
+        fixed_right_arg_value_(0),
         left_(left),
-        right_(right),
-        right_id_(id_gen->GetNextId()) {
+        right_(right) {
     DCHECK(Token::IsBinaryOp(op));
   }
+  static int parent_num_ids() { return Expression::num_ids(); }
 
  private:
-  Token::Value op_;
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+  const byte op_;  // actually Token::Value
+  // TODO(rossberg): the fixed arg should probably be represented as a Constant
+  // type for the RHS. Currenty it's actually a Maybe<int>
+  bool has_fixed_right_arg_;
+  int fixed_right_arg_value_;
   Expression* left_;
   Expression* right_;
   Handle<AllocationSite> allocation_site_;
-
-  // TODO(rossberg): the fixed arg should probably be represented as a Constant
-  // type for the RHS.
-  Maybe<int> fixed_right_arg_;
-
-  // The short-circuit logical operations need an AST ID for their
-  // right-hand subexpression.
-  const BailoutId right_id_;
 };
 
 
@@ -2038,55 +2143,67 @@
  public:
   DECLARE_NODE_TYPE(CountOperation)
 
-  bool is_prefix() const { return is_prefix_; }
-  bool is_postfix() const { return !is_prefix_; }
+  bool is_prefix() const { return IsPrefixField::decode(bit_field_); }
+  bool is_postfix() const { return !is_prefix(); }
 
-  Token::Value op() const { return op_; }
+  Token::Value op() const { return TokenField::decode(bit_field_); }
   Token::Value binary_op() {
     return (op() == Token::INC) ? Token::ADD : Token::SUB;
   }
 
   Expression* expression() const { return expression_; }
 
-  virtual bool IsMonomorphic() OVERRIDE {
-    return receiver_types_.length() == 1;
+  bool IsMonomorphic() OVERRIDE { return receiver_types_.length() == 1; }
+  SmallMapList* GetReceiverTypes() OVERRIDE { return &receiver_types_; }
+  IcCheckType GetKeyType() const OVERRIDE {
+    return KeyTypeField::decode(bit_field_);
   }
-  virtual SmallMapList* GetReceiverTypes() OVERRIDE {
-    return &receiver_types_;
-  }
-  virtual KeyedAccessStoreMode GetStoreMode() OVERRIDE {
-    return store_mode_;
+  KeyedAccessStoreMode GetStoreMode() const OVERRIDE {
+    return StoreModeField::decode(bit_field_);
   }
   Type* type() const { return type_; }
-  void set_store_mode(KeyedAccessStoreMode mode) { store_mode_ = mode; }
+  void set_key_type(IcCheckType type) {
+    bit_field_ = KeyTypeField::update(bit_field_, type);
+  }
+  void set_store_mode(KeyedAccessStoreMode mode) {
+    bit_field_ = StoreModeField::update(bit_field_, mode);
+  }
   void set_type(Type* type) { type_ = type; }
 
-  BailoutId AssignmentId() const { return assignment_id_; }
-
-  TypeFeedbackId CountBinOpFeedbackId() const { return count_id_; }
-  TypeFeedbackId CountStoreFeedbackId() const { return reuse(id()); }
+  static int num_ids() { return parent_num_ids() + 3; }
+  BailoutId AssignmentId() const { return BailoutId(local_id(0)); }
+  TypeFeedbackId CountBinOpFeedbackId() const {
+    return TypeFeedbackId(local_id(1));
+  }
+  TypeFeedbackId CountStoreFeedbackId() const {
+    return TypeFeedbackId(local_id(2));
+  }
 
  protected:
   CountOperation(Zone* zone, Token::Value op, bool is_prefix, Expression* expr,
-                 int pos, IdGen* id_gen)
-      : Expression(zone, pos, id_gen),
-        op_(op),
-        is_prefix_(is_prefix),
-        store_mode_(STANDARD_STORE),
-        expression_(expr),
-        assignment_id_(id_gen->GetNextId()),
-        count_id_(id_gen->GetNextId()) {}
+                 int pos)
+      : Expression(zone, pos),
+        bit_field_(IsPrefixField::encode(is_prefix) |
+                   KeyTypeField::encode(ELEMENT) |
+                   StoreModeField::encode(STANDARD_STORE) |
+                   TokenField::encode(op)),
+        type_(NULL),
+        expression_(expr) {}
+  static int parent_num_ids() { return Expression::num_ids(); }
 
  private:
-  Token::Value op_;
-  bool is_prefix_ : 1;
-  KeyedAccessStoreMode store_mode_ : 5;  // Windows treats as signed,
-                                         // must have extra bit.
-  Type* type_;
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
 
+  class IsPrefixField : public BitField16<bool, 0, 1> {};
+  class KeyTypeField : public BitField16<IcCheckType, 1, 1> {};
+  class StoreModeField : public BitField16<KeyedAccessStoreMode, 2, 4> {};
+  class TokenField : public BitField16<Token::Value, 6, 8> {};
+
+  // Starts with 16-bit field, which should get packed together with
+  // Expression's trailing 16-bit field.
+  uint16_t bit_field_;
+  Type* type_;
   Expression* expression_;
-  const BailoutId assignment_id_;
-  const TypeFeedbackId count_id_;
   SmallMapList receiver_types_;
 };
 
@@ -2100,7 +2217,10 @@
   Expression* right() const { return right_; }
 
   // Type feedback information.
-  TypeFeedbackId CompareOperationFeedbackId() const { return reuse(id()); }
+  static int num_ids() { return parent_num_ids() + 1; }
+  TypeFeedbackId CompareOperationFeedbackId() const {
+    return TypeFeedbackId(local_id(0));
+  }
   Type* combined_type() const { return combined_type_; }
   void set_combined_type(Type* type) { combined_type_ = type; }
 
@@ -2111,16 +2231,19 @@
 
  protected:
   CompareOperation(Zone* zone, Token::Value op, Expression* left,
-                   Expression* right, int pos, IdGen* id_gen)
-      : Expression(zone, pos, id_gen),
+                   Expression* right, int pos)
+      : Expression(zone, pos),
         op_(op),
         left_(left),
         right_(right),
         combined_type_(Type::None(zone)) {
     DCHECK(Token::IsCompareOp(op));
   }
+  static int parent_num_ids() { return Expression::num_ids(); }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
   Token::Value op_;
   Expression* left_;
   Expression* right_;
@@ -2137,25 +2260,25 @@
   Expression* then_expression() const { return then_expression_; }
   Expression* else_expression() const { return else_expression_; }
 
-  BailoutId ThenId() const { return then_id_; }
-  BailoutId ElseId() const { return else_id_; }
+  static int num_ids() { return parent_num_ids() + 2; }
+  BailoutId ThenId() const { return BailoutId(local_id(0)); }
+  BailoutId ElseId() const { return BailoutId(local_id(1)); }
 
  protected:
   Conditional(Zone* zone, Expression* condition, Expression* then_expression,
-              Expression* else_expression, int position, IdGen* id_gen)
-      : Expression(zone, position, id_gen),
+              Expression* else_expression, int position)
+      : Expression(zone, position),
         condition_(condition),
         then_expression_(then_expression),
-        else_expression_(else_expression),
-        then_id_(id_gen->GetNextId()),
-        else_id_(id_gen->GetNextId()) {}
+        else_expression_(else_expression) {}
+  static int parent_num_ids() { return Expression::num_ids(); }
 
  private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
   Expression* condition_;
   Expression* then_expression_;
   Expression* else_expression_;
-  const BailoutId then_id_;
-  const BailoutId else_id_;
 };
 
 
@@ -2167,7 +2290,7 @@
 
   Token::Value binary_op() const;
 
-  Token::Value op() const { return op_; }
+  Token::Value op() const { return TokenField::decode(bit_field_); }
   Expression* target() const { return target_; }
   Expression* value() const { return value_; }
   BinaryOperation* binary_operation() const { return binary_operation_; }
@@ -2175,54 +2298,59 @@
   // This check relies on the definition order of token in token.h.
   bool is_compound() const { return op() > Token::ASSIGN; }
 
-  BailoutId AssignmentId() const { return assignment_id_; }
+  static int num_ids() { return parent_num_ids() + 2; }
+  BailoutId AssignmentId() const { return BailoutId(local_id(0)); }
 
   // Type feedback information.
-  TypeFeedbackId AssignmentFeedbackId() { return reuse(id()); }
-  virtual bool IsMonomorphic() OVERRIDE {
-    return receiver_types_.length() == 1;
+  TypeFeedbackId AssignmentFeedbackId() { return TypeFeedbackId(local_id(1)); }
+  bool IsMonomorphic() OVERRIDE { return receiver_types_.length() == 1; }
+  bool IsUninitialized() const {
+    return IsUninitializedField::decode(bit_field_);
   }
-  bool IsUninitialized() { return is_uninitialized_; }
   bool HasNoTypeInformation() {
-    return is_uninitialized_;
+    return IsUninitializedField::decode(bit_field_);
   }
-  virtual SmallMapList* GetReceiverTypes() OVERRIDE {
-    return &receiver_types_;
+  SmallMapList* GetReceiverTypes() OVERRIDE { return &receiver_types_; }
+  IcCheckType GetKeyType() const OVERRIDE {
+    return KeyTypeField::decode(bit_field_);
   }
-  virtual KeyedAccessStoreMode GetStoreMode() OVERRIDE {
-    return store_mode_;
+  KeyedAccessStoreMode GetStoreMode() const OVERRIDE {
+    return StoreModeField::decode(bit_field_);
   }
-  void set_is_uninitialized(bool b) { is_uninitialized_ = b; }
-  void set_store_mode(KeyedAccessStoreMode mode) { store_mode_ = mode; }
+  void set_is_uninitialized(bool b) {
+    bit_field_ = IsUninitializedField::update(bit_field_, b);
+  }
+  void set_key_type(IcCheckType key_type) {
+    bit_field_ = KeyTypeField::update(bit_field_, key_type);
+  }
+  void set_store_mode(KeyedAccessStoreMode mode) {
+    bit_field_ = StoreModeField::update(bit_field_, mode);
+  }
 
  protected:
   Assignment(Zone* zone, Token::Value op, Expression* target, Expression* value,
-             int pos, IdGen* id_gen);
-
-  template<class Visitor>
-  void Init(Zone* zone, AstNodeFactory<Visitor>* factory) {
-    DCHECK(Token::IsAssignmentOp(op_));
-    if (is_compound()) {
-      binary_operation_ = factory->NewBinaryOperation(
-          binary_op(), target_, value_, position() + 1);
-    }
-  }
+             int pos);
+  static int parent_num_ids() { return Expression::num_ids(); }
 
  private:
-  Token::Value op_;
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+  class IsUninitializedField : public BitField16<bool, 0, 1> {};
+  class KeyTypeField : public BitField16<IcCheckType, 1, 1> {};
+  class StoreModeField : public BitField16<KeyedAccessStoreMode, 2, 4> {};
+  class TokenField : public BitField16<Token::Value, 6, 8> {};
+
+  // Starts with 16-bit field, which should get packed together with
+  // Expression's trailing 16-bit field.
+  uint16_t bit_field_;
   Expression* target_;
   Expression* value_;
   BinaryOperation* binary_operation_;
-  const BailoutId assignment_id_;
-
-  bool is_uninitialized_ : 1;
-  KeyedAccessStoreMode store_mode_ : 5;  // Windows treats as signed,
-                                         // must have extra bit.
   SmallMapList receiver_types_;
 };
 
 
-class Yield FINAL : public Expression, public FeedbackSlotInterface {
+class Yield FINAL : public Expression {
  public:
   DECLARE_NODE_TYPE(Yield)
 
@@ -2250,44 +2378,47 @@
   }
 
   // Type feedback information.
-  virtual int ComputeFeedbackSlotCount() {
-    return (FLAG_vector_ics && yield_kind() == kDelegating) ? 3 : 0;
+  bool HasFeedbackSlots() const {
+    return FLAG_vector_ics && (yield_kind() == kDelegating);
   }
-  virtual void SetFirstFeedbackSlot(int slot) {
+  virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
+      Isolate* isolate) OVERRIDE {
+    return FeedbackVectorRequirements(0, HasFeedbackSlots() ? 3 : 0);
+  }
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
     yield_first_feedback_slot_ = slot;
   }
+  Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
+    return index == 0 ? Code::KEYED_LOAD_IC : Code::LOAD_IC;
+  }
 
-  int KeyedLoadFeedbackSlot() {
-    DCHECK(yield_first_feedback_slot_ != kInvalidFeedbackSlot);
+  FeedbackVectorICSlot KeyedLoadFeedbackSlot() {
+    DCHECK(!HasFeedbackSlots() || !yield_first_feedback_slot_.IsInvalid());
     return yield_first_feedback_slot_;
   }
 
-  int DoneFeedbackSlot() {
-    DCHECK(yield_first_feedback_slot_ != kInvalidFeedbackSlot);
-    return yield_first_feedback_slot_ + 1;
+  FeedbackVectorICSlot DoneFeedbackSlot() {
+    return KeyedLoadFeedbackSlot().next();
   }
 
-  int ValueFeedbackSlot() {
-    DCHECK(yield_first_feedback_slot_ != kInvalidFeedbackSlot);
-    return yield_first_feedback_slot_ + 2;
-  }
+  FeedbackVectorICSlot ValueFeedbackSlot() { return DoneFeedbackSlot().next(); }
 
  protected:
   Yield(Zone* zone, Expression* generator_object, Expression* expression,
-        Kind yield_kind, int pos, IdGen* id_gen)
-      : Expression(zone, pos, id_gen),
+        Kind yield_kind, int pos)
+      : Expression(zone, pos),
         generator_object_(generator_object),
         expression_(expression),
         yield_kind_(yield_kind),
         index_(-1),
-        yield_first_feedback_slot_(kInvalidFeedbackSlot) {}
+        yield_first_feedback_slot_(FeedbackVectorICSlot::Invalid()) {}
 
  private:
   Expression* generator_object_;
   Expression* expression_;
   Kind yield_kind_;
   int index_;
-  int yield_first_feedback_slot_;
+  FeedbackVectorICSlot yield_first_feedback_slot_;
 };
 
 
@@ -2298,8 +2429,8 @@
   Expression* exception() const { return exception_; }
 
  protected:
-  Throw(Zone* zone, Expression* exception, int pos, IdGen* id_gen)
-      : Expression(zone, pos, id_gen), exception_(exception) {}
+  Throw(Zone* zone, Expression* exception, int pos)
+      : Expression(zone, pos), exception_(exception) {}
 
  private:
   Expression* exception_;
@@ -2349,6 +2480,13 @@
   bool is_expression() const { return IsExpression::decode(bitfield_); }
   bool is_anonymous() const { return IsAnonymous::decode(bitfield_); }
   StrictMode strict_mode() const;
+  bool uses_super_property() const;
+  bool uses_super_constructor_call() const;
+
+  static bool NeedsHomeObject(Expression* literal) {
+    return literal != NULL && literal->IsFunctionLiteral() &&
+           literal->AsFunctionLiteral()->uses_super_property();
+  }
 
   int materialized_literal_count() { return materialized_literal_count_; }
   int expected_property_count() { return expected_property_count_; }
@@ -2428,14 +2566,17 @@
   bool is_concise_method() {
     return IsConciseMethod(FunctionKindBits::decode(bitfield_));
   }
+  bool is_default_constructor() {
+    return IsDefaultConstructor(FunctionKindBits::decode(bitfield_));
+  }
 
   int ast_node_count() { return ast_properties_.node_count(); }
   AstProperties::Flags* flags() { return ast_properties_.flags(); }
   void set_ast_properties(AstProperties* ast_properties) {
     ast_properties_ = *ast_properties;
   }
-  int slot_count() {
-    return ast_properties_.feedback_slots();
+  const FeedbackVectorSpec& feedback_vector_spec() const {
+    return ast_properties_.get_spec();
   }
   bool dont_optimize() { return dont_optimize_reason_ != kNoReason; }
   BailoutReason dont_optimize_reason() { return dont_optimize_reason_; }
@@ -2452,8 +2593,8 @@
                   ParameterFlag has_duplicate_parameters,
                   IsFunctionFlag is_function,
                   IsParenthesizedFlag is_parenthesized, FunctionKind kind,
-                  int position, IdGen* id_gen)
-      : Expression(zone, position, id_gen),
+                  int position)
+      : Expression(zone, position),
         raw_name_(name),
         scope_(scope),
         body_(body),
@@ -2498,7 +2639,7 @@
   class HasDuplicateParameters : public BitField<ParameterFlag, 3, 1> {};
   class IsFunction : public BitField<IsFunctionFlag, 4, 1> {};
   class IsParenthesized : public BitField<IsParenthesizedFlag, 5, 1> {};
-  class FunctionKindBits : public BitField<FunctionKind, 6, 3> {};
+  class FunctionKindBits : public BitField<FunctionKind, 6, 4> {};
 };
 
 
@@ -2510,25 +2651,36 @@
 
   Handle<String> name() const { return raw_name_->string(); }
   const AstRawString* raw_name() const { return raw_name_; }
+  Scope* scope() const { return scope_; }
+  VariableProxy* class_variable_proxy() const { return class_variable_proxy_; }
   Expression* extends() const { return extends_; }
   Expression* constructor() const { return constructor_; }
   ZoneList<Property*>* properties() const { return properties_; }
+  int start_position() const { return position(); }
+  int end_position() const { return end_position_; }
 
  protected:
-  ClassLiteral(Zone* zone, const AstRawString* name, Expression* extends,
+  ClassLiteral(Zone* zone, const AstRawString* name, Scope* scope,
+               VariableProxy* class_variable_proxy, Expression* extends,
                Expression* constructor, ZoneList<Property*>* properties,
-               int position, IdGen* id_gen)
-      : Expression(zone, position, id_gen),
+               int start_position, int end_position)
+      : Expression(zone, start_position),
         raw_name_(name),
+        scope_(scope),
+        class_variable_proxy_(class_variable_proxy),
         extends_(extends),
         constructor_(constructor),
-        properties_(properties) {}
+        properties_(properties),
+        end_position_(end_position) {}
 
  private:
   const AstRawString* raw_name_;
+  Scope* scope_;
+  VariableProxy* class_variable_proxy_;
   Expression* extends_;
   Expression* constructor_;
   ZoneList<Property*>* properties_;
+  int end_position_;
 };
 
 
@@ -2541,8 +2693,8 @@
 
  protected:
   NativeFunctionLiteral(Zone* zone, const AstRawString* name,
-                        v8::Extension* extension, int pos, IdGen* id_gen)
-      : Expression(zone, pos, id_gen), name_(name), extension_(extension) {}
+                        v8::Extension* extension, int pos)
+      : Expression(zone, pos), name_(name), extension_(extension) {}
 
  private:
   const AstRawString* name_;
@@ -2555,8 +2707,7 @@
   DECLARE_NODE_TYPE(ThisFunction)
 
  protected:
-  ThisFunction(Zone* zone, int pos, IdGen* id_gen)
-      : Expression(zone, pos, id_gen) {}
+  ThisFunction(Zone* zone, int pos) : Expression(zone, pos) {}
 };
 
 
@@ -2566,15 +2717,38 @@
 
   VariableProxy* this_var() const { return this_var_; }
 
-  TypeFeedbackId HomeObjectFeedbackId() { return reuse(id()); }
+  static int num_ids() { return parent_num_ids() + 1; }
+  TypeFeedbackId HomeObjectFeedbackId() { return TypeFeedbackId(local_id(0)); }
 
- protected:
-  SuperReference(Zone* zone, VariableProxy* this_var, int pos, IdGen* id_gen)
-      : Expression(zone, pos, id_gen), this_var_(this_var) {
-    DCHECK(this_var->is_this());
+  // Type feedback information.
+  virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
+      Isolate* isolate) OVERRIDE {
+    return FeedbackVectorRequirements(0, FLAG_vector_ics ? 1 : 0);
+  }
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
+    homeobject_feedback_slot_ = slot;
+  }
+  Code::Kind FeedbackICSlotKind(int index) OVERRIDE { return Code::LOAD_IC; }
+
+  FeedbackVectorICSlot HomeObjectFeedbackSlot() {
+    DCHECK(!FLAG_vector_ics || !homeobject_feedback_slot_.IsInvalid());
+    return homeobject_feedback_slot_;
   }
 
+ protected:
+  SuperReference(Zone* zone, VariableProxy* this_var, int pos)
+      : Expression(zone, pos),
+        this_var_(this_var),
+        homeobject_feedback_slot_(FeedbackVectorICSlot::Invalid()) {
+    DCHECK(this_var->is_this());
+  }
+  static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
   VariableProxy* this_var_;
+  FeedbackVectorICSlot homeobject_feedback_slot_;
 };
 
 
@@ -2611,7 +2785,7 @@
   // expression.
   virtual Interval CaptureRegisters() { return Interval::Empty(); }
   virtual void AppendToText(RegExpText* text, Zone* zone);
-  OStream& Print(OStream& os, Zone* zone);  // NOLINT
+  std::ostream& Print(std::ostream& os, Zone* zone);  // NOLINT
 #define MAKE_ASTYPE(Name)                                                  \
   virtual RegExp##Name* As##Name();                                        \
   virtual bool Is##Name();
@@ -2623,16 +2797,16 @@
 class RegExpDisjunction FINAL : public RegExpTree {
  public:
   explicit RegExpDisjunction(ZoneList<RegExpTree*>* alternatives);
-  virtual void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
+  void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
                              RegExpNode* on_success) OVERRIDE;
-  virtual RegExpDisjunction* AsDisjunction() OVERRIDE;
-  virtual Interval CaptureRegisters() OVERRIDE;
-  virtual bool IsDisjunction() OVERRIDE;
-  virtual bool IsAnchoredAtStart() OVERRIDE;
-  virtual bool IsAnchoredAtEnd() OVERRIDE;
-  virtual int min_match() OVERRIDE { return min_match_; }
-  virtual int max_match() OVERRIDE { return max_match_; }
+  RegExpDisjunction* AsDisjunction() OVERRIDE;
+  Interval CaptureRegisters() OVERRIDE;
+  bool IsDisjunction() OVERRIDE;
+  bool IsAnchoredAtStart() OVERRIDE;
+  bool IsAnchoredAtEnd() OVERRIDE;
+  int min_match() OVERRIDE { return min_match_; }
+  int max_match() OVERRIDE { return max_match_; }
   ZoneList<RegExpTree*>* alternatives() { return alternatives_; }
  private:
   ZoneList<RegExpTree*>* alternatives_;
@@ -2644,16 +2818,16 @@
 class RegExpAlternative FINAL : public RegExpTree {
  public:
   explicit RegExpAlternative(ZoneList<RegExpTree*>* nodes);
-  virtual void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
+  void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
                              RegExpNode* on_success) OVERRIDE;
-  virtual RegExpAlternative* AsAlternative() OVERRIDE;
-  virtual Interval CaptureRegisters() OVERRIDE;
-  virtual bool IsAlternative() OVERRIDE;
-  virtual bool IsAnchoredAtStart() OVERRIDE;
-  virtual bool IsAnchoredAtEnd() OVERRIDE;
-  virtual int min_match() OVERRIDE { return min_match_; }
-  virtual int max_match() OVERRIDE { return max_match_; }
+  RegExpAlternative* AsAlternative() OVERRIDE;
+  Interval CaptureRegisters() OVERRIDE;
+  bool IsAlternative() OVERRIDE;
+  bool IsAnchoredAtStart() OVERRIDE;
+  bool IsAnchoredAtEnd() OVERRIDE;
+  int min_match() OVERRIDE { return min_match_; }
+  int max_match() OVERRIDE { return max_match_; }
   ZoneList<RegExpTree*>* nodes() { return nodes_; }
  private:
   ZoneList<RegExpTree*>* nodes_;
@@ -2673,15 +2847,15 @@
     NON_BOUNDARY
   };
   explicit RegExpAssertion(AssertionType type) : assertion_type_(type) { }
-  virtual void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
+  void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
                              RegExpNode* on_success) OVERRIDE;
-  virtual RegExpAssertion* AsAssertion() OVERRIDE;
-  virtual bool IsAssertion() OVERRIDE;
-  virtual bool IsAnchoredAtStart() OVERRIDE;
-  virtual bool IsAnchoredAtEnd() OVERRIDE;
-  virtual int min_match() OVERRIDE { return 0; }
-  virtual int max_match() OVERRIDE { return 0; }
+  RegExpAssertion* AsAssertion() OVERRIDE;
+  bool IsAssertion() OVERRIDE;
+  bool IsAnchoredAtStart() OVERRIDE;
+  bool IsAnchoredAtEnd() OVERRIDE;
+  int min_match() OVERRIDE { return 0; }
+  int max_match() OVERRIDE { return 0; }
   AssertionType assertion_type() { return assertion_type_; }
  private:
   AssertionType assertion_type_;
@@ -2719,15 +2893,15 @@
   explicit RegExpCharacterClass(uc16 type)
       : set_(type),
         is_negated_(false) { }
-  virtual void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
+  void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
                              RegExpNode* on_success) OVERRIDE;
-  virtual RegExpCharacterClass* AsCharacterClass() OVERRIDE;
-  virtual bool IsCharacterClass() OVERRIDE;
-  virtual bool IsTextElement() OVERRIDE { return true; }
-  virtual int min_match() OVERRIDE { return 1; }
-  virtual int max_match() OVERRIDE { return 1; }
-  virtual void AppendToText(RegExpText* text, Zone* zone) OVERRIDE;
+  RegExpCharacterClass* AsCharacterClass() OVERRIDE;
+  bool IsCharacterClass() OVERRIDE;
+  bool IsTextElement() OVERRIDE { return true; }
+  int min_match() OVERRIDE { return 1; }
+  int max_match() OVERRIDE { return 1; }
+  void AppendToText(RegExpText* text, Zone* zone) OVERRIDE;
   CharacterSet character_set() { return set_; }
   // TODO(lrn): Remove need for complex version if is_standard that
   // recognizes a mangled standard set and just do { return set_.is_special(); }
@@ -2756,15 +2930,15 @@
 class RegExpAtom FINAL : public RegExpTree {
  public:
   explicit RegExpAtom(Vector<const uc16> data) : data_(data) { }
-  virtual void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
+  void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
                              RegExpNode* on_success) OVERRIDE;
-  virtual RegExpAtom* AsAtom() OVERRIDE;
-  virtual bool IsAtom() OVERRIDE;
-  virtual bool IsTextElement() OVERRIDE { return true; }
-  virtual int min_match() OVERRIDE { return data_.length(); }
-  virtual int max_match() OVERRIDE { return data_.length(); }
-  virtual void AppendToText(RegExpText* text, Zone* zone) OVERRIDE;
+  RegExpAtom* AsAtom() OVERRIDE;
+  bool IsAtom() OVERRIDE;
+  bool IsTextElement() OVERRIDE { return true; }
+  int min_match() OVERRIDE { return data_.length(); }
+  int max_match() OVERRIDE { return data_.length(); }
+  void AppendToText(RegExpText* text, Zone* zone) OVERRIDE;
   Vector<const uc16> data() { return data_; }
   int length() { return data_.length(); }
  private:
@@ -2775,15 +2949,15 @@
 class RegExpText FINAL : public RegExpTree {
  public:
   explicit RegExpText(Zone* zone) : elements_(2, zone), length_(0) {}
-  virtual void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
+  void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
                              RegExpNode* on_success) OVERRIDE;
-  virtual RegExpText* AsText() OVERRIDE;
-  virtual bool IsText() OVERRIDE;
-  virtual bool IsTextElement() OVERRIDE { return true; }
-  virtual int min_match() OVERRIDE { return length_; }
-  virtual int max_match() OVERRIDE { return length_; }
-  virtual void AppendToText(RegExpText* text, Zone* zone) OVERRIDE;
+  RegExpText* AsText() OVERRIDE;
+  bool IsText() OVERRIDE;
+  bool IsTextElement() OVERRIDE { return true; }
+  int min_match() OVERRIDE { return length_; }
+  int max_match() OVERRIDE { return length_; }
+  void AppendToText(RegExpText* text, Zone* zone) OVERRIDE;
   void AddElement(TextElement elm, Zone* zone)  {
     elements_.Add(elm, zone);
     length_ += elm.length();
@@ -2810,7 +2984,7 @@
       max_match_ = max * body->max_match();
     }
   }
-  virtual void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
+  void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
                              RegExpNode* on_success) OVERRIDE;
   static RegExpNode* ToNode(int min,
@@ -2820,11 +2994,11 @@
                             RegExpCompiler* compiler,
                             RegExpNode* on_success,
                             bool not_at_start = false);
-  virtual RegExpQuantifier* AsQuantifier() OVERRIDE;
-  virtual Interval CaptureRegisters() OVERRIDE;
-  virtual bool IsQuantifier() OVERRIDE;
-  virtual int min_match() OVERRIDE { return min_match_; }
-  virtual int max_match() OVERRIDE { return max_match_; }
+  RegExpQuantifier* AsQuantifier() OVERRIDE;
+  Interval CaptureRegisters() OVERRIDE;
+  bool IsQuantifier() OVERRIDE;
+  int min_match() OVERRIDE { return min_match_; }
+  int max_match() OVERRIDE { return max_match_; }
   int min() { return min_; }
   int max() { return max_; }
   bool is_possessive() { return quantifier_type_ == POSSESSIVE; }
@@ -2846,20 +3020,20 @@
  public:
   explicit RegExpCapture(RegExpTree* body, int index)
       : body_(body), index_(index) { }
-  virtual void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
+  void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
                              RegExpNode* on_success) OVERRIDE;
   static RegExpNode* ToNode(RegExpTree* body,
                             int index,
                             RegExpCompiler* compiler,
                             RegExpNode* on_success);
-  virtual RegExpCapture* AsCapture() OVERRIDE;
-  virtual bool IsAnchoredAtStart() OVERRIDE;
-  virtual bool IsAnchoredAtEnd() OVERRIDE;
-  virtual Interval CaptureRegisters() OVERRIDE;
-  virtual bool IsCapture() OVERRIDE;
-  virtual int min_match() OVERRIDE { return body_->min_match(); }
-  virtual int max_match() OVERRIDE { return body_->max_match(); }
+  RegExpCapture* AsCapture() OVERRIDE;
+  bool IsAnchoredAtStart() OVERRIDE;
+  bool IsAnchoredAtEnd() OVERRIDE;
+  Interval CaptureRegisters() OVERRIDE;
+  bool IsCapture() OVERRIDE;
+  int min_match() OVERRIDE { return body_->min_match(); }
+  int max_match() OVERRIDE { return body_->max_match(); }
   RegExpTree* body() { return body_; }
   int index() { return index_; }
   static int StartRegister(int index) { return index * 2; }
@@ -2882,15 +3056,15 @@
         capture_count_(capture_count),
         capture_from_(capture_from) { }
 
-  virtual void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
+  void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
                              RegExpNode* on_success) OVERRIDE;
-  virtual RegExpLookahead* AsLookahead() OVERRIDE;
-  virtual Interval CaptureRegisters() OVERRIDE;
-  virtual bool IsLookahead() OVERRIDE;
-  virtual bool IsAnchoredAtStart() OVERRIDE;
-  virtual int min_match() OVERRIDE { return 0; }
-  virtual int max_match() OVERRIDE { return 0; }
+  RegExpLookahead* AsLookahead() OVERRIDE;
+  Interval CaptureRegisters() OVERRIDE;
+  bool IsLookahead() OVERRIDE;
+  bool IsAnchoredAtStart() OVERRIDE;
+  int min_match() OVERRIDE { return 0; }
+  int max_match() OVERRIDE { return 0; }
   RegExpTree* body() { return body_; }
   bool is_positive() { return is_positive_; }
   int capture_count() { return capture_count_; }
@@ -2908,13 +3082,13 @@
  public:
   explicit RegExpBackReference(RegExpCapture* capture)
       : capture_(capture) { }
-  virtual void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
+  void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
                              RegExpNode* on_success) OVERRIDE;
-  virtual RegExpBackReference* AsBackReference() OVERRIDE;
-  virtual bool IsBackReference() OVERRIDE;
-  virtual int min_match() OVERRIDE { return 0; }
-  virtual int max_match() OVERRIDE { return capture_->max_match(); }
+  RegExpBackReference* AsBackReference() OVERRIDE;
+  bool IsBackReference() OVERRIDE;
+  int min_match() OVERRIDE { return 0; }
+  int max_match() OVERRIDE { return capture_->max_match(); }
   int index() { return capture_->index(); }
   RegExpCapture* capture() { return capture_; }
  private:
@@ -2925,17 +3099,13 @@
 class RegExpEmpty FINAL : public RegExpTree {
  public:
   RegExpEmpty() { }
-  virtual void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
+  void* Accept(RegExpVisitor* visitor, void* data) OVERRIDE;
   virtual RegExpNode* ToNode(RegExpCompiler* compiler,
                              RegExpNode* on_success) OVERRIDE;
-  virtual RegExpEmpty* AsEmpty() OVERRIDE;
-  virtual bool IsEmpty() OVERRIDE;
-  virtual int min_match() OVERRIDE { return 0; }
-  virtual int max_match() OVERRIDE { return 0; }
-  static RegExpEmpty* GetInstance() {
-    static RegExpEmpty* instance = ::new RegExpEmpty();
-    return instance;
-  }
+  RegExpEmpty* AsEmpty() OVERRIDE;
+  bool IsEmpty() OVERRIDE;
+  int min_match() OVERRIDE { return 0; }
+  int max_match() OVERRIDE { return 0; }
 };
 
 
@@ -2973,118 +3143,49 @@
 };
 
 
-#define DEFINE_AST_VISITOR_SUBCLASS_MEMBERS()                       \
-public:                                                             \
-  virtual void Visit(AstNode* node) FINAL OVERRIDE {          \
-    if (!CheckStackOverflow()) node->Accept(this);                  \
-  }                                                                 \
-                                                                    \
-  void SetStackOverflow() { stack_overflow_ = true; }               \
-  void ClearStackOverflow() { stack_overflow_ = false; }            \
-  bool HasStackOverflow() const { return stack_overflow_; }         \
-                                                                    \
-  bool CheckStackOverflow() {                                       \
-    if (stack_overflow_) return true;                               \
-    StackLimitCheck check(zone_->isolate());                        \
-    if (!check.HasOverflowed()) return false;                       \
-    return (stack_overflow_ = true);                                \
-  }                                                                 \
-                                                                    \
-private:                                                            \
-  void InitializeAstVisitor(Zone* zone) {                           \
-    zone_ = zone;                                                   \
-    stack_overflow_ = false;                                        \
-  }                                                                 \
-  Zone* zone() { return zone_; }                                    \
-  Isolate* isolate() { return zone_->isolate(); }                   \
-                                                                    \
-  Zone* zone_;                                                      \
+#define DEFINE_AST_VISITOR_SUBCLASS_MEMBERS()               \
+ public:                                                    \
+  void Visit(AstNode* node) FINAL {                         \
+    if (!CheckStackOverflow()) node->Accept(this);          \
+  }                                                         \
+                                                            \
+  void SetStackOverflow() { stack_overflow_ = true; }       \
+  void ClearStackOverflow() { stack_overflow_ = false; }    \
+  bool HasStackOverflow() const { return stack_overflow_; } \
+                                                            \
+  bool CheckStackOverflow() {                               \
+    if (stack_overflow_) return true;                       \
+    StackLimitCheck check(zone_->isolate());                \
+    if (!check.HasOverflowed()) return false;               \
+    return (stack_overflow_ = true);                        \
+  }                                                         \
+                                                            \
+ private:                                                   \
+  void InitializeAstVisitor(Zone* zone) {                   \
+    zone_ = zone;                                           \
+    stack_overflow_ = false;                                \
+  }                                                         \
+  Zone* zone() { return zone_; }                            \
+  Isolate* isolate() { return zone_->isolate(); }           \
+                                                            \
+  Zone* zone_;                                              \
   bool stack_overflow_
 
 
 // ----------------------------------------------------------------------------
-// Construction time visitor.
-
-class AstConstructionVisitor BASE_EMBEDDED {
- public:
-  AstConstructionVisitor()
-      : dont_crankshaft_reason_(kNoReason), dont_turbofan_reason_(kNoReason) {}
-
-  AstProperties* ast_properties() { return &properties_; }
-  BailoutReason dont_optimize_reason() {
-    if (dont_turbofan_reason_ != kNoReason) {
-      return dont_turbofan_reason_;
-    } else {
-      return dont_crankshaft_reason_;
-    }
-  }
-
- private:
-  template<class> friend class AstNodeFactory;
-
-  // Node visitors.
-#define DEF_VISIT(type) \
-  void Visit##type(type* node);
-  AST_NODE_LIST(DEF_VISIT)
-#undef DEF_VISIT
-
-  void increase_node_count() { properties_.add_node_count(1); }
-  void add_flag(AstPropertiesFlag flag) { properties_.flags()->Add(flag); }
-  void set_dont_crankshaft_reason(BailoutReason reason) {
-    dont_crankshaft_reason_ = reason;
-  }
-  void set_dont_turbofan_reason(BailoutReason reason) {
-    dont_turbofan_reason_ = reason;
-  }
-
-  void add_slot_node(FeedbackSlotInterface* slot_node) {
-    int count = slot_node->ComputeFeedbackSlotCount();
-    if (count > 0) {
-      slot_node->SetFirstFeedbackSlot(properties_.feedback_slots());
-      properties_.increase_feedback_slots(count);
-    }
-  }
-
-  AstProperties properties_;
-  BailoutReason dont_crankshaft_reason_;
-  BailoutReason dont_turbofan_reason_;
-};
-
-
-class AstNullVisitor BASE_EMBEDDED {
- public:
-  // Node visitors.
-#define DEF_VISIT(type) \
-  void Visit##type(type* node) {}
-  AST_NODE_LIST(DEF_VISIT)
-#undef DEF_VISIT
-};
-
-
-
-// ----------------------------------------------------------------------------
 // AstNode factory
 
-template<class Visitor>
 class AstNodeFactory FINAL BASE_EMBEDDED {
  public:
-  AstNodeFactory(Zone* zone, AstValueFactory* ast_value_factory,
-                 AstNode::IdGen* id_gen)
-      : zone_(zone), ast_value_factory_(ast_value_factory), id_gen_(id_gen) {}
-
-  Visitor* visitor() { return &visitor_; }
-
-#define VISIT_AND_RETURN(NodeType, node) \
-  visitor_.Visit##NodeType((node)); \
-  return node;
+  explicit AstNodeFactory(AstValueFactory* ast_value_factory)
+      : zone_(ast_value_factory->zone()),
+        ast_value_factory_(ast_value_factory) {}
 
   VariableDeclaration* NewVariableDeclaration(VariableProxy* proxy,
                                               VariableMode mode,
                                               Scope* scope,
                                               int pos) {
-    VariableDeclaration* decl =
-        new(zone_) VariableDeclaration(zone_, proxy, mode, scope, pos);
-    VISIT_AND_RETURN(VariableDeclaration, decl)
+    return new (zone_) VariableDeclaration(zone_, proxy, mode, scope, pos);
   }
 
   FunctionDeclaration* NewFunctionDeclaration(VariableProxy* proxy,
@@ -3092,71 +3193,56 @@
                                               FunctionLiteral* fun,
                                               Scope* scope,
                                               int pos) {
-    FunctionDeclaration* decl =
-        new(zone_) FunctionDeclaration(zone_, proxy, mode, fun, scope, pos);
-    VISIT_AND_RETURN(FunctionDeclaration, decl)
+    return new (zone_) FunctionDeclaration(zone_, proxy, mode, fun, scope, pos);
   }
 
   ModuleDeclaration* NewModuleDeclaration(VariableProxy* proxy,
                                           Module* module,
                                           Scope* scope,
                                           int pos) {
-    ModuleDeclaration* decl =
-        new(zone_) ModuleDeclaration(zone_, proxy, module, scope, pos);
-    VISIT_AND_RETURN(ModuleDeclaration, decl)
+    return new (zone_) ModuleDeclaration(zone_, proxy, module, scope, pos);
   }
 
   ImportDeclaration* NewImportDeclaration(VariableProxy* proxy,
                                           Module* module,
                                           Scope* scope,
                                           int pos) {
-    ImportDeclaration* decl =
-        new(zone_) ImportDeclaration(zone_, proxy, module, scope, pos);
-    VISIT_AND_RETURN(ImportDeclaration, decl)
+    return new (zone_) ImportDeclaration(zone_, proxy, module, scope, pos);
   }
 
   ExportDeclaration* NewExportDeclaration(VariableProxy* proxy,
                                           Scope* scope,
                                           int pos) {
-    ExportDeclaration* decl =
-        new(zone_) ExportDeclaration(zone_, proxy, scope, pos);
-    VISIT_AND_RETURN(ExportDeclaration, decl)
+    return new (zone_) ExportDeclaration(zone_, proxy, scope, pos);
   }
 
   ModuleLiteral* NewModuleLiteral(Block* body, Interface* interface, int pos) {
-    ModuleLiteral* module =
-        new(zone_) ModuleLiteral(zone_, body, interface, pos);
-    VISIT_AND_RETURN(ModuleLiteral, module)
+    return new (zone_) ModuleLiteral(zone_, body, interface, pos);
   }
 
   ModuleVariable* NewModuleVariable(VariableProxy* proxy, int pos) {
-    ModuleVariable* module = new(zone_) ModuleVariable(zone_, proxy, pos);
-    VISIT_AND_RETURN(ModuleVariable, module)
+    return new (zone_) ModuleVariable(zone_, proxy, pos);
   }
 
   ModulePath* NewModulePath(Module* origin, const AstRawString* name, int pos) {
-    ModulePath* module = new (zone_) ModulePath(zone_, origin, name, pos);
-    VISIT_AND_RETURN(ModulePath, module)
+    return new (zone_) ModulePath(zone_, origin, name, pos);
   }
 
   ModuleUrl* NewModuleUrl(Handle<String> url, int pos) {
-    ModuleUrl* module = new(zone_) ModuleUrl(zone_, url, pos);
-    VISIT_AND_RETURN(ModuleUrl, module)
+    return new (zone_) ModuleUrl(zone_, url, pos);
   }
 
   Block* NewBlock(ZoneList<const AstRawString*>* labels,
                   int capacity,
                   bool is_initializer_block,
                   int pos) {
-    Block* block = new (zone_)
-        Block(zone_, labels, capacity, is_initializer_block, pos, id_gen_);
-    VISIT_AND_RETURN(Block, block)
+    return new (zone_)
+        Block(zone_, labels, capacity, is_initializer_block, pos);
   }
 
 #define STATEMENT_WITH_LABELS(NodeType)                                     \
   NodeType* New##NodeType(ZoneList<const AstRawString*>* labels, int pos) { \
-    NodeType* stmt = new (zone_) NodeType(zone_, labels, pos, id_gen_);     \
-    VISIT_AND_RETURN(NodeType, stmt);                                       \
+    return new (zone_) NodeType(zone_, labels, pos);                        \
   }
   STATEMENT_WITH_LABELS(DoWhileStatement)
   STATEMENT_WITH_LABELS(WhileStatement)
@@ -3169,14 +3255,10 @@
                                         int pos) {
     switch (visit_mode) {
       case ForEachStatement::ENUMERATE: {
-        ForInStatement* stmt =
-            new (zone_) ForInStatement(zone_, labels, pos, id_gen_);
-        VISIT_AND_RETURN(ForInStatement, stmt);
+        return new (zone_) ForInStatement(zone_, labels, pos);
       }
       case ForEachStatement::ITERATE: {
-        ForOfStatement* stmt =
-            new (zone_) ForOfStatement(zone_, labels, pos, id_gen_);
-        VISIT_AND_RETURN(ForOfStatement, stmt);
+        return new (zone_) ForOfStatement(zone_, labels, pos);
       }
     }
     UNREACHABLE();
@@ -3185,47 +3267,38 @@
 
   ModuleStatement* NewModuleStatement(
       VariableProxy* proxy, Block* body, int pos) {
-    ModuleStatement* stmt = new(zone_) ModuleStatement(zone_, proxy, body, pos);
-    VISIT_AND_RETURN(ModuleStatement, stmt)
+    return new (zone_) ModuleStatement(zone_, proxy, body, pos);
   }
 
   ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) {
-    ExpressionStatement* stmt =
-        new(zone_) ExpressionStatement(zone_, expression, pos);
-    VISIT_AND_RETURN(ExpressionStatement, stmt)
+    return new (zone_) ExpressionStatement(zone_, expression, pos);
   }
 
   ContinueStatement* NewContinueStatement(IterationStatement* target, int pos) {
-    ContinueStatement* stmt = new(zone_) ContinueStatement(zone_, target, pos);
-    VISIT_AND_RETURN(ContinueStatement, stmt)
+    return new (zone_) ContinueStatement(zone_, target, pos);
   }
 
   BreakStatement* NewBreakStatement(BreakableStatement* target, int pos) {
-    BreakStatement* stmt = new(zone_) BreakStatement(zone_, target, pos);
-    VISIT_AND_RETURN(BreakStatement, stmt)
+    return new (zone_) BreakStatement(zone_, target, pos);
   }
 
   ReturnStatement* NewReturnStatement(Expression* expression, int pos) {
-    ReturnStatement* stmt = new(zone_) ReturnStatement(zone_, expression, pos);
-    VISIT_AND_RETURN(ReturnStatement, stmt)
+    return new (zone_) ReturnStatement(zone_, expression, pos);
   }
 
   WithStatement* NewWithStatement(Scope* scope,
                                   Expression* expression,
                                   Statement* statement,
                                   int pos) {
-    WithStatement* stmt = new(zone_) WithStatement(
-        zone_, scope, expression, statement, pos);
-    VISIT_AND_RETURN(WithStatement, stmt)
+    return new (zone_) WithStatement(zone_, scope, expression, statement, pos);
   }
 
   IfStatement* NewIfStatement(Expression* condition,
                               Statement* then_statement,
                               Statement* else_statement,
                               int pos) {
-    IfStatement* stmt = new (zone_) IfStatement(
-        zone_, condition, then_statement, else_statement, pos, id_gen_);
-    VISIT_AND_RETURN(IfStatement, stmt)
+    return new (zone_)
+        IfStatement(zone_, condition, then_statement, else_statement, pos);
   }
 
   TryCatchStatement* NewTryCatchStatement(int index,
@@ -3234,24 +3307,20 @@
                                           Variable* variable,
                                           Block* catch_block,
                                           int pos) {
-    TryCatchStatement* stmt = new(zone_) TryCatchStatement(
-        zone_, index, try_block, scope, variable, catch_block, pos);
-    VISIT_AND_RETURN(TryCatchStatement, stmt)
+    return new (zone_) TryCatchStatement(zone_, index, try_block, scope,
+                                         variable, catch_block, pos);
   }
 
   TryFinallyStatement* NewTryFinallyStatement(int index,
                                               Block* try_block,
                                               Block* finally_block,
                                               int pos) {
-    TryFinallyStatement* stmt = new(zone_) TryFinallyStatement(
-        zone_, index, try_block, finally_block, pos);
-    VISIT_AND_RETURN(TryFinallyStatement, stmt)
+    return new (zone_)
+        TryFinallyStatement(zone_, index, try_block, finally_block, pos);
   }
 
   DebuggerStatement* NewDebuggerStatement(int pos) {
-    DebuggerStatement* stmt =
-        new (zone_) DebuggerStatement(zone_, pos, id_gen_);
-    VISIT_AND_RETURN(DebuggerStatement, stmt)
+    return new (zone_) DebuggerStatement(zone_, pos);
   }
 
   EmptyStatement* NewEmptyStatement(int pos) {
@@ -3260,65 +3329,42 @@
 
   CaseClause* NewCaseClause(
       Expression* label, ZoneList<Statement*>* statements, int pos) {
-    CaseClause* clause =
-        new (zone_) CaseClause(zone_, label, statements, pos, id_gen_);
-    VISIT_AND_RETURN(CaseClause, clause)
+    return new (zone_) CaseClause(zone_, label, statements, pos);
   }
 
   Literal* NewStringLiteral(const AstRawString* string, int pos) {
-    Literal* lit = new (zone_)
-        Literal(zone_, ast_value_factory_->NewString(string), pos, id_gen_);
-    VISIT_AND_RETURN(Literal, lit)
+    return new (zone_)
+        Literal(zone_, ast_value_factory_->NewString(string), pos);
   }
 
   // A JavaScript symbol (ECMA-262 edition 6).
   Literal* NewSymbolLiteral(const char* name, int pos) {
-    Literal* lit = new (zone_)
-        Literal(zone_, ast_value_factory_->NewSymbol(name), pos, id_gen_);
-    VISIT_AND_RETURN(Literal, lit)
+    return new (zone_) Literal(zone_, ast_value_factory_->NewSymbol(name), pos);
   }
 
   Literal* NewNumberLiteral(double number, int pos) {
-    Literal* lit = new (zone_)
-        Literal(zone_, ast_value_factory_->NewNumber(number), pos, id_gen_);
-    VISIT_AND_RETURN(Literal, lit)
+    return new (zone_)
+        Literal(zone_, ast_value_factory_->NewNumber(number), pos);
   }
 
   Literal* NewSmiLiteral(int number, int pos) {
-    Literal* lit = new (zone_)
-        Literal(zone_, ast_value_factory_->NewSmi(number), pos, id_gen_);
-    VISIT_AND_RETURN(Literal, lit)
+    return new (zone_) Literal(zone_, ast_value_factory_->NewSmi(number), pos);
   }
 
   Literal* NewBooleanLiteral(bool b, int pos) {
-    Literal* lit = new (zone_)
-        Literal(zone_, ast_value_factory_->NewBoolean(b), pos, id_gen_);
-    VISIT_AND_RETURN(Literal, lit)
-  }
-
-  Literal* NewStringListLiteral(ZoneList<const AstRawString*>* strings,
-                                int pos) {
-    Literal* lit = new (zone_) Literal(
-        zone_, ast_value_factory_->NewStringList(strings), pos, id_gen_);
-    VISIT_AND_RETURN(Literal, lit)
+    return new (zone_) Literal(zone_, ast_value_factory_->NewBoolean(b), pos);
   }
 
   Literal* NewNullLiteral(int pos) {
-    Literal* lit =
-        new (zone_) Literal(zone_, ast_value_factory_->NewNull(), pos, id_gen_);
-    VISIT_AND_RETURN(Literal, lit)
+    return new (zone_) Literal(zone_, ast_value_factory_->NewNull(), pos);
   }
 
   Literal* NewUndefinedLiteral(int pos) {
-    Literal* lit = new (zone_)
-        Literal(zone_, ast_value_factory_->NewUndefined(), pos, id_gen_);
-    VISIT_AND_RETURN(Literal, lit)
+    return new (zone_) Literal(zone_, ast_value_factory_->NewUndefined(), pos);
   }
 
   Literal* NewTheHoleLiteral(int pos) {
-    Literal* lit = new (zone_)
-        Literal(zone_, ast_value_factory_->NewTheHole(), pos, id_gen_);
-    VISIT_AND_RETURN(Literal, lit)
+    return new (zone_) Literal(zone_, ast_value_factory_->NewTheHole(), pos);
   }
 
   ObjectLiteral* NewObjectLiteral(
@@ -3327,10 +3373,8 @@
       int boilerplate_properties,
       bool has_function,
       int pos) {
-    ObjectLiteral* lit = new (zone_)
-        ObjectLiteral(zone_, properties, literal_index, boilerplate_properties,
-                      has_function, pos, id_gen_);
-    VISIT_AND_RETURN(ObjectLiteral, lit)
+    return new (zone_) ObjectLiteral(zone_, properties, literal_index,
+                                     boilerplate_properties, has_function, pos);
   }
 
   ObjectLiteral::Property* NewObjectLiteralProperty(Literal* key,
@@ -3346,122 +3390,104 @@
     ObjectLiteral::Property* prop =
         new (zone_) ObjectLiteral::Property(zone_, is_getter, value, is_static);
     prop->set_key(NewStringLiteral(value->raw_name(), pos));
-    return prop;  // Not an AST node, will not be visited.
+    return prop;
   }
 
   RegExpLiteral* NewRegExpLiteral(const AstRawString* pattern,
                                   const AstRawString* flags,
                                   int literal_index,
                                   int pos) {
-    RegExpLiteral* lit = new (zone_)
-        RegExpLiteral(zone_, pattern, flags, literal_index, pos, id_gen_);
-    VISIT_AND_RETURN(RegExpLiteral, lit);
+    return new (zone_) RegExpLiteral(zone_, pattern, flags, literal_index, pos);
   }
 
   ArrayLiteral* NewArrayLiteral(ZoneList<Expression*>* values,
                                 int literal_index,
                                 int pos) {
-    ArrayLiteral* lit =
-        new (zone_) ArrayLiteral(zone_, values, literal_index, pos, id_gen_);
-    VISIT_AND_RETURN(ArrayLiteral, lit)
+    return new (zone_) ArrayLiteral(zone_, values, literal_index, pos);
   }
 
   VariableProxy* NewVariableProxy(Variable* var,
                                   int pos = RelocInfo::kNoPosition) {
-    VariableProxy* proxy = new (zone_) VariableProxy(zone_, var, pos, id_gen_);
-    VISIT_AND_RETURN(VariableProxy, proxy)
+    return new (zone_) VariableProxy(zone_, var, pos);
   }
 
   VariableProxy* NewVariableProxy(const AstRawString* name,
                                   bool is_this,
                                   Interface* interface = Interface::NewValue(),
                                   int position = RelocInfo::kNoPosition) {
-    VariableProxy* proxy = new (zone_)
-        VariableProxy(zone_, name, is_this, interface, position, id_gen_);
-    VISIT_AND_RETURN(VariableProxy, proxy)
+    return new (zone_) VariableProxy(zone_, name, is_this, interface, position);
   }
 
   Property* NewProperty(Expression* obj, Expression* key, int pos) {
-    Property* prop = new (zone_) Property(zone_, obj, key, pos, id_gen_);
-    VISIT_AND_RETURN(Property, prop)
+    return new (zone_) Property(zone_, obj, key, pos);
   }
 
   Call* NewCall(Expression* expression,
                 ZoneList<Expression*>* arguments,
                 int pos) {
-    Call* call = new (zone_) Call(zone_, expression, arguments, pos, id_gen_);
-    VISIT_AND_RETURN(Call, call)
+    return new (zone_) Call(zone_, expression, arguments, pos);
   }
 
   CallNew* NewCallNew(Expression* expression,
                       ZoneList<Expression*>* arguments,
                       int pos) {
-    CallNew* call =
-        new (zone_) CallNew(zone_, expression, arguments, pos, id_gen_);
-    VISIT_AND_RETURN(CallNew, call)
+    return new (zone_) CallNew(zone_, expression, arguments, pos);
   }
 
   CallRuntime* NewCallRuntime(const AstRawString* name,
                               const Runtime::Function* function,
                               ZoneList<Expression*>* arguments,
                               int pos) {
-    CallRuntime* call =
-        new (zone_) CallRuntime(zone_, name, function, arguments, pos, id_gen_);
-    VISIT_AND_RETURN(CallRuntime, call)
+    return new (zone_) CallRuntime(zone_, name, function, arguments, pos);
   }
 
   UnaryOperation* NewUnaryOperation(Token::Value op,
                                     Expression* expression,
                                     int pos) {
-    UnaryOperation* node =
-        new (zone_) UnaryOperation(zone_, op, expression, pos, id_gen_);
-    VISIT_AND_RETURN(UnaryOperation, node)
+    return new (zone_) UnaryOperation(zone_, op, expression, pos);
   }
 
   BinaryOperation* NewBinaryOperation(Token::Value op,
                                       Expression* left,
                                       Expression* right,
                                       int pos) {
-    BinaryOperation* node =
-        new (zone_) BinaryOperation(zone_, op, left, right, pos, id_gen_);
-    VISIT_AND_RETURN(BinaryOperation, node)
+    return new (zone_) BinaryOperation(zone_, op, left, right, pos);
   }
 
   CountOperation* NewCountOperation(Token::Value op,
                                     bool is_prefix,
                                     Expression* expr,
                                     int pos) {
-    CountOperation* node =
-        new (zone_) CountOperation(zone_, op, is_prefix, expr, pos, id_gen_);
-    VISIT_AND_RETURN(CountOperation, node)
+    return new (zone_) CountOperation(zone_, op, is_prefix, expr, pos);
   }
 
   CompareOperation* NewCompareOperation(Token::Value op,
                                         Expression* left,
                                         Expression* right,
                                         int pos) {
-    CompareOperation* node =
-        new (zone_) CompareOperation(zone_, op, left, right, pos, id_gen_);
-    VISIT_AND_RETURN(CompareOperation, node)
+    return new (zone_) CompareOperation(zone_, op, left, right, pos);
   }
 
   Conditional* NewConditional(Expression* condition,
                               Expression* then_expression,
                               Expression* else_expression,
                               int position) {
-    Conditional* cond = new (zone_) Conditional(
-        zone_, condition, then_expression, else_expression, position, id_gen_);
-    VISIT_AND_RETURN(Conditional, cond)
+    return new (zone_) Conditional(zone_, condition, then_expression,
+                                   else_expression, position);
   }
 
   Assignment* NewAssignment(Token::Value op,
                             Expression* target,
                             Expression* value,
                             int pos) {
-    Assignment* assign =
-        new (zone_) Assignment(zone_, op, target, value, pos, id_gen_);
-    assign->Init(zone_, this);
-    VISIT_AND_RETURN(Assignment, assign)
+    DCHECK(Token::IsAssignmentOp(op));
+    Assignment* assign = new (zone_) Assignment(zone_, op, target, value, pos);
+    if (assign->is_compound()) {
+      DCHECK(Token::IsAssignmentOp(op));
+      assign->binary_operation_ =
+          NewBinaryOperation(assign->binary_op(), target, value, pos + 1);
+    }
+    return assign;
   }
 
   Yield* NewYield(Expression *generator_object,
@@ -3469,14 +3495,12 @@
                   Yield::Kind yield_kind,
                   int pos) {
     if (!expression) expression = NewUndefinedLiteral(pos);
-    Yield* yield = new (zone_)
-        Yield(zone_, generator_object, expression, yield_kind, pos, id_gen_);
-    VISIT_AND_RETURN(Yield, yield)
+    return new (zone_)
+        Yield(zone_, generator_object, expression, yield_kind, pos);
   }
 
   Throw* NewThrow(Expression* exception, int pos) {
-    Throw* t = new (zone_) Throw(zone_, exception, pos, id_gen_);
-    VISIT_AND_RETURN(Throw, t)
+    return new (zone_) Throw(zone_, exception, pos);
   }
 
   FunctionLiteral* NewFunctionLiteral(
@@ -3488,53 +3512,40 @@
       FunctionLiteral::IsFunctionFlag is_function,
       FunctionLiteral::IsParenthesizedFlag is_parenthesized, FunctionKind kind,
       int position) {
-    FunctionLiteral* lit = new (zone_) FunctionLiteral(
+    return new (zone_) FunctionLiteral(
         zone_, name, ast_value_factory, scope, body, materialized_literal_count,
         expected_property_count, handler_count, parameter_count, function_type,
-        has_duplicate_parameters, is_function, is_parenthesized, kind, position,
-        id_gen_);
-    // Top-level literal doesn't count for the AST's properties.
-    if (is_function == FunctionLiteral::kIsFunction) {
-      visitor_.VisitFunctionLiteral(lit);
-    }
-    return lit;
+        has_duplicate_parameters, is_function, is_parenthesized, kind,
+        position);
   }
 
-  ClassLiteral* NewClassLiteral(const AstRawString* name, Expression* extends,
+  ClassLiteral* NewClassLiteral(const AstRawString* name, Scope* scope,
+                                VariableProxy* proxy, Expression* extends,
                                 Expression* constructor,
                                 ZoneList<ObjectLiteral::Property*>* properties,
-                                int position) {
-    ClassLiteral* lit = new (zone_) ClassLiteral(
-        zone_, name, extends, constructor, properties, position, id_gen_);
-    VISIT_AND_RETURN(ClassLiteral, lit)
+                                int start_position, int end_position) {
+    return new (zone_)
+        ClassLiteral(zone_, name, scope, proxy, extends, constructor,
+                     properties, start_position, end_position);
   }
 
   NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name,
                                                   v8::Extension* extension,
                                                   int pos) {
-    NativeFunctionLiteral* lit =
-        new (zone_) NativeFunctionLiteral(zone_, name, extension, pos, id_gen_);
-    VISIT_AND_RETURN(NativeFunctionLiteral, lit)
+    return new (zone_) NativeFunctionLiteral(zone_, name, extension, pos);
   }
 
   ThisFunction* NewThisFunction(int pos) {
-    ThisFunction* fun = new (zone_) ThisFunction(zone_, pos, id_gen_);
-    VISIT_AND_RETURN(ThisFunction, fun)
+    return new (zone_) ThisFunction(zone_, pos);
   }
 
   SuperReference* NewSuperReference(VariableProxy* this_var, int pos) {
-    SuperReference* super =
-        new (zone_) SuperReference(zone_, this_var, pos, id_gen_);
-    VISIT_AND_RETURN(SuperReference, super);
+    return new (zone_) SuperReference(zone_, this_var, pos);
   }
 
-#undef VISIT_AND_RETURN
-
  private:
   Zone* zone_;
-  Visitor visitor_;
   AstValueFactory* ast_value_factory_;
-  AstNode::IdGen* id_gen_;
 };
 
 
diff --git "a/src/base/\043functional.h\043" "b/src/base/\043functional.h\043"
new file mode 100644
index 0000000..ff0d807
--- /dev/null
+++ "b/src/base/\043functional.h\043"
@@ -0,0 +1,227 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_BASE_FUNCTIONAL_H_
+#define V8_BASE_FUNCTIONAL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstddef>
+#include <cstring>
+#include <functional>
+#include <utility>
+
+#include "src/base/macros.h"
+
+namespace v8 {
+namespace base {
+
+// base::hash is an implementation of the hash function object specified by
+// C++11. It was designed to be compatible with std::hash (in C++11) and
+// boost:hash (which in turn is based on the hash function object specified by
+// the Draft Technical Report on C++ Library Extensions (TR1)).
+//
+// base::hash is implemented by calling the hash_value function. The namespace
+// isn't specified so that it can detect overloads via argument dependant
+// lookup. So if there is a free function hash_value in the same namespace as a
+// custom type, it will get called.
+//
+// If users are asked to implement a hash function for their own types with no
+// guidance, they generally write bad hash functions. Instead, we provide  a
+// simple function base::hash_combine to pass hash-relevant member variables
+// into, in order to define a decent hash function. base::hash_combine is
+// declared as:
+//
+//   template<typename T, typename... Ts>
+//   size_t hash_combine(const T& v, const Ts& ...vs);
+//
+// Consider the following example:
+//
+//   namespace v8 {
+//   namespace bar {
+//     struct Point { int x; int y; };
+//     size_t hash_value(Point const& p) {
+//       return base::hash_combine(p.x, p.y);
+//     }
+//   }
+//
+//   namespace foo {
+//     void DoSomeWork(bar::Point const& p) {
+//       base::hash<bar::Point> h;
+//       ...
+//       size_t hash_code = h(p);  // calls bar::hash_value(Point const&)
+//       ...
+//     }
+//   }
+//   }
+//
+// Based on the "Hashing User-Defined Types in C++1y" proposal from Jeffrey
+// Yasskin and Chandler Carruth, see
+// http://www.open-std.org/Jtc1/sc22/wg21/docs/papers/2012/n3333.html.
+
+template <typename>
+struct hash;
+
+
+V8_INLINE size_t hash_combine() { return 0u; }
+V8_INLINE size_t hash_combine(size_t seed) { return seed; }
+size_t hash_combine(size_t seed, size_t value);
+template <typename T, typename... Ts>
+V8_INLINE size_t hash_combine(T const& v, Ts const&... vs) {
+  return hash_combine(hash_combine(vs...), hash<T>()(v));
+}
+
+
+template <typename Iterator>
+V8_INLINE size_t hash_range(Iterator first, Iterator last) {
+  size_t seed = 0;
+  for (; first != last; ++first) {
+    seed = hash_combine(seed, *first);
+  }
+  return seed;
+}
+
+
+#define V8_BASE_HASH_VALUE_TRIVIAL(type) \
+  V8_INLINE size_t hash_value(type v) { return static_cast<size_t>(v); }
+V8_BASE_HASH_VALUE_TRIVIAL(bool)
+V8_BASE_HASH_VALUE_TRIVIAL(unsigned char)
+V8_BASE_HASH_VALUE_TRIVIAL(unsigned short)  // NOLINT(runtime/int)
+#undef V8_BASE_HASH_VALUE_TRIVIAL
+
+size_t hash_value(unsigned int);
+size_t hash_value(unsigned long);       // NOLINT(runtime/int)
+size_t hash_value(unsigned long long);  // NOLINT(runtime/int)
+
+#define V8_BASE_HASH_VALUE_SIGNED(type)            \
+  V8_INLINE size_t hash_value(signed type v) {     \
+    return hash_value(bit_cast<unsigned type>(v)); \
+  }
+V8_BASE_HASH_VALUE_SIGNED(char)
+V8_BASE_HASH_VALUE_SIGNED(short)      // NOLINT(runtime/int)
+V8_BASE_HASH_VALUE_SIGNED(int)        // NOLINT(runtime/int)
+V8_BASE_HASH_VALUE_SIGNED(long)       // NOLINT(runtime/int)
+V8_BASE_HASH_VALUE_SIGNED(long long)  // NOLINT(runtime/int)
+#undef V8_BASE_HASH_VALUE_SIGNED
+
+V8_INLINE size_t hash_value(float v) {
+  // 0 and -0 both hash to zero.
+  return v != 0.0f ? hash_value(bit_cast<uint32_t>(v)) : 0;
+}
+
+V8_INLINE size_t hash_value(double v) {
+  // 0 and -0 both hash to zero.
+  return v != 0.0 ? hash_value(bit_cast<uint64_t>(v)) : 0;
+}
+
+template <typename T, size_t N>
+V8_INLINE size_t hash_value(const T (&v)[N]) {
+  return hash_range(v, v + N);
+}
+
+template <typename T, size_t N>
+V8_INLINE size_t hash_value(T (&v)[N]) {
+  return hash_range(v, v + N);
+}
+
+template <typename T>
+V8_INLINE size_t hash_value(T* const& v) {
+  return hash_value(bit_cast<uintptr_t>(v));
+}
+
+template <typename T1, typename T2>
+V8_INLINE size_t hash_value(std::pair<T1, T2> const& v) {
+  return hash_combine(v.first, v.second);
+}
+
+
+template <typename T>
+struct hash : public std::unary_function<T, size_t> {
+  V8_INLINE size_t operator()(T const& v) const { return hash_value(v); }
+};
+
+#define V8_BASE_HASH_SPECIALIZE(type)                            \
+  template <>                                                    \
+  struct hash<type> : public std::unary_function<type, size_t> { \
+    V8_INLINE size_t operator()(type const v) const {            \
+      return ::v8::base::hash_value(v);                          \
+    }                                                            \
+  };
+V8_BASE_HASH_SPECIALIZE(bool)
+V8_BASE_HASH_SPECIALIZE(signed char)
+V8_BASE_HASH_SPECIALIZE(unsigned char)
+V8_BASE_HASH_SPECIALIZE(short)           // NOLINT(runtime/int)
+V8_BASE_HASH_SPECIALIZE(unsigned short)  // NOLINT(runtime/int)
+V8_BASE_HASH_SPECIALIZE(int)
+V8_BASE_HASH_SPECIALIZE(unsigned int)
+V8_BASE_HASH_SPECIALIZE(long)                // NOLINT(runtime/int)
+V8_BASE_HASH_SPECIALIZE(unsigned long)       // NOLINT(runtime/int)
+V8_BASE_HASH_SPECIALIZE(long long)           // NOLINT(runtime/int)
+V8_BASE_HASH_SPECIALIZE(unsigned long long)  // NOLINT(runtime/int)
+V8_BASE_HASH_SPECIALIZE(float)
+V8_BASE_HASH_SPECIALIZE(double)
+#undef V8_BASE_HASH_SPECIALIZE
+
+template <typename T>
+struct hash<T*> : public std::unary_function<T*, size_t> {
+  V8_INLINE size_t operator()(T* const v) const {
+    return ::v8::base::hash_value(v);
+  }
+};
+
+
+// base::bit_equal_to is a function object class for bitwise equality
+// comparison, similar to std::equal_to, except that the comparison is performed
+// on the bit representation of the operands.
+//
+// base::bit_hash is a function object class for bitwise hashing, similar to
+// base::hash. It can be used together with base::bit_equal_to to implement a
+// hash data structure based on the bitwise representation of types.
+
+template <typename T>
+struct bit_equal_to : public std::binary_function<T, T, bool> {};
+
+template <typename T>
+struct bit_hash : public std::unary_function<T, size_t> {};
+
+#define V8_BASE_BIT_SPECIALIZE_TRIVIAL(type)                 \
+  template <>                                                \
+  struct bit_equal_to<type> : public std::equal_to<type> {}; \
+  template <>                                                \
+  struct bit_hash<type> : public hash<type> {};
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(signed char)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned char)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(short)           // NOLINT(runtime/int)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned short)  // NOLINT(runtime/int)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(int)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned int)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(long)                // NOLINT(runtime/int)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned long)       // NOLINT(runtime/int)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(long long)           // NOLINT(runtime/int)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned long long)  // NOLINT(runtime/int)
+#undef V8_BASE_BIT_SPECIALIZE_TRIVIAL
+
+#define V8_BASE_BIT_SPECIALIZE_BIT_CAST(type, btype)                          \
+  template <>                                                                 \
+  struct bit_equal_to<type> : public std::binary_function<type, type, bool> { \
+    V8_INLINE bool operator()(type lhs, type rhs) const {                     \
+      return bit_cast<btype>(lhs) == bit_cast<btype>(rhs);                    \
+    }                                                                         \
+  };                                                                          \
+  template <>                                                                 \
+  struct bit_hash<type> : public std::unary_function<type, size_t> {          \
+    V8_INLINE size_t operator()(type v) const {                               \
+      hash<btype> h;                                                          \
+      return h(bit_cast<btype>(v));                                           \
+    }                                                                         \
+  };
+V8_BASE_BIT_SPECIALIZE_BIT_CAST(float, uint32_t)
+V8_BASE_BIT_SPECIALIZE_BIT_CAST(double, uint64_t)
+#undef V8_BASE_BIT_SPECIALIZE_BIT_CAST
+
+}  // namespace base
+}  // namespace v8
+
+#endif  // V8_BASE_FUNCTIONAL_H_
diff --git a/src/base/atomicops.h b/src/base/atomicops.h
index eba172f..675e43f 100644
--- a/src/base/atomicops.h
+++ b/src/base/atomicops.h
@@ -25,7 +25,7 @@
 #ifndef V8_BASE_ATOMICOPS_H_
 #define V8_BASE_ATOMICOPS_H_
 
-#include "include/v8stdint.h"
+#include <stdint.h>
 #include "src/base/build_config.h"
 
 #if defined(_WIN32) && defined(V8_HOST_ARCH_64_BIT)
@@ -42,15 +42,17 @@
 
 typedef char Atomic8;
 typedef int32_t Atomic32;
-#ifdef V8_HOST_ARCH_64_BIT
+#if defined(__native_client__)
+typedef int64_t Atomic64;
+#elif defined(V8_HOST_ARCH_64_BIT)
 // We need to be able to go between Atomic64 and AtomicWord implicitly.  This
 // means Atomic64 and AtomicWord should be the same type on 64-bit.
 #if defined(__ILP32__)
 typedef int64_t Atomic64;
 #else
 typedef intptr_t Atomic64;
-#endif
-#endif
+#endif  // defined(V8_HOST_ARCH_64_BIT)
+#endif  // defined(__native_client__)
 
 // Use AtomicWord for a machine-sized pointer.  It will use the Atomic32 or
 // Atomic64 routines below, depending on your architecture.
@@ -140,6 +142,8 @@
 #include "src/base/atomicops_internals_x86_msvc.h"
 #elif defined(__APPLE__)
 #include "src/base/atomicops_internals_mac.h"
+#elif defined(__native_client__)
+#include "src/base/atomicops_internals_portable.h"
 #elif defined(__GNUC__) && V8_HOST_ARCH_ARM64
 #include "src/base/atomicops_internals_arm64_gcc.h"
 #elif defined(__GNUC__) && V8_HOST_ARCH_ARM
diff --git a/src/base/atomicops_internals_mac.h b/src/base/atomicops_internals_mac.h
index a046872..84f9dbc 100644
--- a/src/base/atomicops_internals_mac.h
+++ b/src/base/atomicops_internals_mac.h
@@ -12,6 +12,20 @@
 namespace v8 {
 namespace base {
 
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+inline void MemoryBarrier() { OSMemoryBarrier(); }
+
+inline void AcquireMemoryBarrier() {
+// On x86 processors, loads already have acquire semantics, so
+// there is no need to put a full barrier here.
+#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
+  ATOMICOPS_COMPILER_BARRIER();
+#else
+  MemoryBarrier();
+#endif
+}
+
 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
                                          Atomic32 old_value,
                                          Atomic32 new_value) {
@@ -46,10 +60,6 @@
   return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(ptr));
 }
 
-inline void MemoryBarrier() {
-  OSMemoryBarrier();
-}
-
 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
                                        Atomic32 old_value,
                                        Atomic32 new_value) {
@@ -98,7 +108,7 @@
 
 inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
   Atomic32 value = *ptr;
-  MemoryBarrier();
+  AcquireMemoryBarrier();
   return value;
 }
 
@@ -188,7 +198,7 @@
 
 inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
   Atomic64 value = *ptr;
-  MemoryBarrier();
+  AcquireMemoryBarrier();
   return value;
 }
 
@@ -199,6 +209,7 @@
 
 #endif  // defined(__LP64__)
 
+#undef ATOMICOPS_COMPILER_BARRIER
 } }  // namespace v8::base
 
 #endif  // V8_BASE_ATOMICOPS_INTERNALS_MAC_H_
diff --git a/src/base/atomicops_internals_portable.h b/src/base/atomicops_internals_portable.h
new file mode 100644
index 0000000..a3a6e74
--- /dev/null
+++ b/src/base/atomicops_internals_portable.h
@@ -0,0 +1,138 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef V8_BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
+#define V8_BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
+
+namespace v8 {
+namespace base {
+
+inline void MemoryBarrier() { __sync_synchronize(); }
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  return __sync_val_compare_and_swap(ptr, old_value, new_value);
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  return __sync_lock_test_and_set(ptr, new_value);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return __sync_add_and_fetch(ptr, increment);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  return __sync_add_and_fetch(ptr, increment);
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value, Atomic32 new_value) {
+  return __sync_val_compare_and_swap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value, Atomic32 new_value) {
+  return __sync_val_compare_and_swap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic8* ptr, Atomic8 value) {
+  __sync_lock_test_and_set(ptr, value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  __sync_lock_test_and_set(ptr, value);
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  __sync_lock_test_and_set(ptr, value);
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  __sync_lock_test_and_set(ptr, value);
+}
+
+inline Atomic8 NoBarrier_Load(volatile const Atomic8* ptr) {
+  return __sync_add_and_fetch(ptr, 0);
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return __sync_add_and_fetch(ptr, 0);
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  return __sync_add_and_fetch(ptr, 0);
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  return __sync_add_and_fetch(ptr, 0);
+}
+
+// 64-bit versions of the operations.
+// See the 32-bit versions for comments.
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  return __sync_val_compare_and_swap(ptr, old_value, new_value);
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  return __sync_lock_test_and_set(ptr, new_value);
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  return __sync_add_and_fetch(ptr, increment);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  return __sync_add_and_fetch(ptr, increment);
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value, Atomic64 new_value) {
+  return __sync_val_compare_and_swap(ptr, old_value, new_value);
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value, Atomic64 new_value) {
+  return __sync_val_compare_and_swap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  __sync_lock_test_and_set(ptr, value);
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  __sync_lock_test_and_set(ptr, value);
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  __sync_lock_test_and_set(ptr, value);
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return __sync_add_and_fetch(ptr, 0);
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  return __sync_add_and_fetch(ptr, 0);
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  return __sync_add_and_fetch(ptr, 0);
+}
+}
+}  // namespace v8::base
+
+#endif  // V8_BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
diff --git a/src/base/base.gyp b/src/base/base.gyp
deleted file mode 100644
index e391e2e..0000000
--- a/src/base/base.gyp
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright 2014 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  'variables': {
-    'v8_code': 1,
-  },
-  'includes': ['../../build/toolchain.gypi', '../../build/features.gypi'],
-  'targets': [
-    {
-      'target_name': 'base-unittests',
-      'type': 'executable',
-      'dependencies': [
-        '../../testing/gtest.gyp:gtest',
-        '../../testing/gtest.gyp:gtest_main',
-        '../../tools/gyp/v8.gyp:v8_libbase',
-      ],
-      'include_dirs': [
-        '../..',
-      ],
-      'sources': [  ### gcmole(all) ###
-        'bits-unittest.cc',
-        'cpu-unittest.cc',
-        'division-by-constant-unittest.cc',
-        'flags-unittest.cc',
-        'platform/condition-variable-unittest.cc',
-        'platform/mutex-unittest.cc',
-        'platform/platform-unittest.cc',
-        'platform/semaphore-unittest.cc',
-        'platform/time-unittest.cc',
-        'sys-info-unittest.cc',
-        'utils/random-number-generator-unittest.cc',
-      ],
-      'conditions': [
-        ['os_posix == 1', {
-          # TODO(svenpanne): This is a temporary work-around to fix the warnings
-          # that show up because we use -std=gnu++0x instead of -std=c++11.
-          'cflags!': [
-            '-pedantic',
-          ],
-        }],
-      ],
-    },
-  ],
-}
diff --git a/src/base/bits-unittest.cc b/src/base/bits-unittest.cc
deleted file mode 100644
index 06c1183..0000000
--- a/src/base/bits-unittest.cc
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <limits>
-
-#include "src/base/bits.h"
-#include "src/base/macros.h"
-#include "testing/gtest-support.h"
-
-#ifdef DEBUG
-#define DISABLE_IN_RELEASE(Name) Name
-#else
-#define DISABLE_IN_RELEASE(Name) DISABLED_##Name
-#endif
-
-namespace v8 {
-namespace base {
-namespace bits {
-
-TEST(Bits, CountPopulation32) {
-  EXPECT_EQ(0u, CountPopulation32(0));
-  EXPECT_EQ(1u, CountPopulation32(1));
-  EXPECT_EQ(8u, CountPopulation32(0x11111111));
-  EXPECT_EQ(16u, CountPopulation32(0xf0f0f0f0));
-  EXPECT_EQ(24u, CountPopulation32(0xfff0f0ff));
-  EXPECT_EQ(32u, CountPopulation32(0xffffffff));
-}
-
-
-TEST(Bits, CountLeadingZeros32) {
-  EXPECT_EQ(32u, CountLeadingZeros32(0));
-  EXPECT_EQ(31u, CountLeadingZeros32(1));
-  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
-    EXPECT_EQ(31u - shift, CountLeadingZeros32(1u << shift));
-  }
-  EXPECT_EQ(4u, CountLeadingZeros32(0x0f0f0f0f));
-}
-
-
-TEST(Bits, CountTrailingZeros32) {
-  EXPECT_EQ(32u, CountTrailingZeros32(0));
-  EXPECT_EQ(31u, CountTrailingZeros32(0x80000000));
-  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
-    EXPECT_EQ(shift, CountTrailingZeros32(1u << shift));
-  }
-  EXPECT_EQ(4u, CountTrailingZeros32(0xf0f0f0f0));
-}
-
-
-TEST(Bits, IsPowerOfTwo32) {
-  EXPECT_FALSE(IsPowerOfTwo32(0U));
-  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
-    EXPECT_TRUE(IsPowerOfTwo32(1U << shift));
-    EXPECT_FALSE(IsPowerOfTwo32((1U << shift) + 5U));
-    EXPECT_FALSE(IsPowerOfTwo32(~(1U << shift)));
-  }
-  TRACED_FORRANGE(uint32_t, shift, 2, 31) {
-    EXPECT_FALSE(IsPowerOfTwo32((1U << shift) - 1U));
-  }
-  EXPECT_FALSE(IsPowerOfTwo32(0xffffffff));
-}
-
-
-TEST(Bits, IsPowerOfTwo64) {
-  EXPECT_FALSE(IsPowerOfTwo64(0U));
-  TRACED_FORRANGE(uint32_t, shift, 0, 63) {
-    EXPECT_TRUE(IsPowerOfTwo64(V8_UINT64_C(1) << shift));
-    EXPECT_FALSE(IsPowerOfTwo64((V8_UINT64_C(1) << shift) + 5U));
-    EXPECT_FALSE(IsPowerOfTwo64(~(V8_UINT64_C(1) << shift)));
-  }
-  TRACED_FORRANGE(uint32_t, shift, 2, 63) {
-    EXPECT_FALSE(IsPowerOfTwo64((V8_UINT64_C(1) << shift) - 1U));
-  }
-  EXPECT_FALSE(IsPowerOfTwo64(V8_UINT64_C(0xffffffffffffffff)));
-}
-
-
-TEST(Bits, RoundUpToPowerOfTwo32) {
-  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
-    EXPECT_EQ(1u << shift, RoundUpToPowerOfTwo32(1u << shift));
-  }
-  EXPECT_EQ(0u, RoundUpToPowerOfTwo32(0));
-  EXPECT_EQ(4u, RoundUpToPowerOfTwo32(3));
-  EXPECT_EQ(0x80000000u, RoundUpToPowerOfTwo32(0x7fffffffu));
-}
-
-
-TEST(BitsDeathTest, DISABLE_IN_RELEASE(RoundUpToPowerOfTwo32)) {
-  ASSERT_DEATH_IF_SUPPORTED({ RoundUpToPowerOfTwo32(0x80000001u); },
-                            "0x80000000");
-}
-
-
-TEST(Bits, RoundDownToPowerOfTwo32) {
-  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
-    EXPECT_EQ(1u << shift, RoundDownToPowerOfTwo32(1u << shift));
-  }
-  EXPECT_EQ(0u, RoundDownToPowerOfTwo32(0));
-  EXPECT_EQ(4u, RoundDownToPowerOfTwo32(5));
-  EXPECT_EQ(0x80000000u, RoundDownToPowerOfTwo32(0x80000001u));
-}
-
-
-TEST(Bits, RotateRight32) {
-  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
-    EXPECT_EQ(0u, RotateRight32(0u, shift));
-  }
-  EXPECT_EQ(1u, RotateRight32(1, 0));
-  EXPECT_EQ(1u, RotateRight32(2, 1));
-  EXPECT_EQ(0x80000000u, RotateRight32(1, 1));
-}
-
-
-TEST(Bits, RotateRight64) {
-  TRACED_FORRANGE(uint64_t, shift, 0, 63) {
-    EXPECT_EQ(0u, RotateRight64(0u, shift));
-  }
-  EXPECT_EQ(1u, RotateRight64(1, 0));
-  EXPECT_EQ(1u, RotateRight64(2, 1));
-  EXPECT_EQ(V8_UINT64_C(0x8000000000000000), RotateRight64(1, 1));
-}
-
-
-TEST(Bits, SignedAddOverflow32) {
-  int32_t val = 0;
-  EXPECT_FALSE(SignedAddOverflow32(0, 0, &val));
-  EXPECT_EQ(0, val);
-  EXPECT_TRUE(
-      SignedAddOverflow32(std::numeric_limits<int32_t>::max(), 1, &val));
-  EXPECT_EQ(std::numeric_limits<int32_t>::min(), val);
-  EXPECT_TRUE(
-      SignedAddOverflow32(std::numeric_limits<int32_t>::min(), -1, &val));
-  EXPECT_EQ(std::numeric_limits<int32_t>::max(), val);
-  EXPECT_TRUE(SignedAddOverflow32(std::numeric_limits<int32_t>::max(),
-                                  std::numeric_limits<int32_t>::max(), &val));
-  EXPECT_EQ(-2, val);
-  TRACED_FORRANGE(int32_t, i, 1, 50) {
-    TRACED_FORRANGE(int32_t, j, 1, i) {
-      EXPECT_FALSE(SignedAddOverflow32(i, j, &val));
-      EXPECT_EQ(i + j, val);
-    }
-  }
-}
-
-
-TEST(Bits, SignedSubOverflow32) {
-  int32_t val = 0;
-  EXPECT_FALSE(SignedSubOverflow32(0, 0, &val));
-  EXPECT_EQ(0, val);
-  EXPECT_TRUE(
-      SignedSubOverflow32(std::numeric_limits<int32_t>::min(), 1, &val));
-  EXPECT_EQ(std::numeric_limits<int32_t>::max(), val);
-  EXPECT_TRUE(
-      SignedSubOverflow32(std::numeric_limits<int32_t>::max(), -1, &val));
-  EXPECT_EQ(std::numeric_limits<int32_t>::min(), val);
-  TRACED_FORRANGE(int32_t, i, 1, 50) {
-    TRACED_FORRANGE(int32_t, j, 1, i) {
-      EXPECT_FALSE(SignedSubOverflow32(i, j, &val));
-      EXPECT_EQ(i - j, val);
-    }
-  }
-}
-
-}  // namespace bits
-}  // namespace base
-}  // namespace v8
diff --git a/src/base/bits.cc b/src/base/bits.cc
index 6daee53..74d747f 100644
--- a/src/base/bits.cc
+++ b/src/base/bits.cc
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 #include "src/base/bits.h"
+
+#include <limits>
+
 #include "src/base/logging.h"
 
 namespace v8 {
@@ -20,6 +23,31 @@
   return value + 1;
 }
 
+
+int32_t SignedMulHigh32(int32_t lhs, int32_t rhs) {
+  int64_t const value = static_cast<int64_t>(lhs) * static_cast<int64_t>(rhs);
+  return bit_cast<int32_t, uint32_t>(bit_cast<uint64_t>(value) >> 32u);
+}
+
+
+int32_t SignedMulHighAndAdd32(int32_t lhs, int32_t rhs, int32_t acc) {
+  return bit_cast<int32_t>(bit_cast<uint32_t>(acc) +
+                           bit_cast<uint32_t>(SignedMulHigh32(lhs, rhs)));
+}
+
+
+int32_t SignedDiv32(int32_t lhs, int32_t rhs) {
+  if (rhs == 0) return 0;
+  if (rhs == -1) return -lhs;
+  return lhs / rhs;
+}
+
+
+int32_t SignedMod32(int32_t lhs, int32_t rhs) {
+  if (rhs == 0 || rhs == -1) return 0;
+  return lhs % rhs;
+}
+
 }  // namespace bits
 }  // namespace base
 }  // namespace v8
diff --git a/src/base/bits.h b/src/base/bits.h
index e6a733a..0f4d4c7 100644
--- a/src/base/bits.h
+++ b/src/base/bits.h
@@ -5,7 +5,7 @@
 #ifndef V8_BASE_BITS_H_
 #define V8_BASE_BITS_H_
 
-#include "include/v8stdint.h"
+#include <stdint.h>
 #include "src/base/macros.h"
 #if V8_CC_MSVC
 #include <intrin.h>
@@ -19,7 +19,7 @@
 namespace bits {
 
 // CountPopulation32(value) returns the number of bits set in |value|.
-inline uint32_t CountPopulation32(uint32_t value) {
+inline unsigned CountPopulation32(uint32_t value) {
 #if V8_HAS_BUILTIN_POPCOUNT
   return __builtin_popcount(value);
 #else
@@ -28,20 +28,31 @@
   value = ((value >> 4) & 0x0f0f0f0f) + (value & 0x0f0f0f0f);
   value = ((value >> 8) & 0x00ff00ff) + (value & 0x00ff00ff);
   value = ((value >> 16) & 0x0000ffff) + (value & 0x0000ffff);
-  return value;
+  return static_cast<unsigned>(value);
+#endif
+}
+
+
+// CountPopulation64(value) returns the number of bits set in |value|.
+inline unsigned CountPopulation64(uint64_t value) {
+#if V8_HAS_BUILTIN_POPCOUNT
+  return __builtin_popcountll(value);
+#else
+  return CountPopulation32(static_cast<uint32_t>(value)) +
+         CountPopulation32(static_cast<uint32_t>(value >> 32));
 #endif
 }
 
 
 // CountLeadingZeros32(value) returns the number of zero bits following the most
 // significant 1 bit in |value| if |value| is non-zero, otherwise it returns 32.
-inline uint32_t CountLeadingZeros32(uint32_t value) {
+inline unsigned CountLeadingZeros32(uint32_t value) {
 #if V8_HAS_BUILTIN_CLZ
   return value ? __builtin_clz(value) : 32;
 #elif V8_CC_MSVC
   unsigned long result;  // NOLINT(runtime/int)
   if (!_BitScanReverse(&result, value)) return 32;
-  return static_cast<uint32_t>(31 - result);
+  return static_cast<unsigned>(31 - result);
 #else
   value = value | (value >> 1);
   value = value | (value >> 2);
@@ -53,16 +64,33 @@
 }
 
 
+// CountLeadingZeros64(value) returns the number of zero bits following the most
+// significant 1 bit in |value| if |value| is non-zero, otherwise it returns 64.
+inline unsigned CountLeadingZeros64(uint64_t value) {
+#if V8_HAS_BUILTIN_CLZ
+  return value ? __builtin_clzll(value) : 64;
+#else
+  value = value | (value >> 1);
+  value = value | (value >> 2);
+  value = value | (value >> 4);
+  value = value | (value >> 8);
+  value = value | (value >> 16);
+  value = value | (value >> 32);
+  return CountPopulation64(~value);
+#endif
+}
+
+
 // CountTrailingZeros32(value) returns the number of zero bits preceding the
 // least significant 1 bit in |value| if |value| is non-zero, otherwise it
 // returns 32.
-inline uint32_t CountTrailingZeros32(uint32_t value) {
+inline unsigned CountTrailingZeros32(uint32_t value) {
 #if V8_HAS_BUILTIN_CTZ
   return value ? __builtin_ctz(value) : 32;
 #elif V8_CC_MSVC
   unsigned long result;  // NOLINT(runtime/int)
   if (!_BitScanForward(&result, value)) return 32;
-  return static_cast<uint32_t>(result);
+  return static_cast<unsigned>(result);
 #else
   if (value == 0) return 32;
   unsigned count = 0;
@@ -73,6 +101,22 @@
 }
 
 
+// CountTrailingZeros64(value) returns the number of zero bits preceding the
+// least significant 1 bit in |value| if |value| is non-zero, otherwise it
+// returns 64.
+inline unsigned CountTrailingZeros64(uint64_t value) {
+#if V8_HAS_BUILTIN_CTZ
+  return value ? __builtin_ctzll(value) : 64;
+#else
+  if (value == 0) return 64;
+  unsigned count = 0;
+  for (value ^= value - 1; value >>= 1; ++count)
+    ;
+  return count;
+#endif
+}
+
+
 // Returns true iff |value| is a power of 2.
 inline bool IsPowerOfTwo32(uint32_t value) {
   return value && !(value & (value - 1));
@@ -143,6 +187,44 @@
 #endif
 }
 
+
+// SignedMulHigh32(lhs, rhs) multiplies two signed 32-bit values |lhs| and
+// |rhs|, extracts the most significant 32 bits of the result, and returns
+// those.
+int32_t SignedMulHigh32(int32_t lhs, int32_t rhs);
+
+
+// SignedMulHighAndAdd32(lhs, rhs, acc) multiplies two signed 32-bit values
+// |lhs| and |rhs|, extracts the most significant 32 bits of the result, and
+// adds the accumulate value |acc|.
+int32_t SignedMulHighAndAdd32(int32_t lhs, int32_t rhs, int32_t acc);
+
+
+// SignedDiv32(lhs, rhs) divides |lhs| by |rhs| and returns the quotient
+// truncated to int32. If |rhs| is zero, then zero is returned. If |lhs|
+// is minint and |rhs| is -1, it returns minint.
+int32_t SignedDiv32(int32_t lhs, int32_t rhs);
+
+
+// SignedMod32(lhs, rhs) divides |lhs| by |rhs| and returns the remainder
+// truncated to int32. If either |rhs| is zero or |lhs| is minint and |rhs|
+// is -1, it returns zero.
+int32_t SignedMod32(int32_t lhs, int32_t rhs);
+
+
+// UnsignedDiv32(lhs, rhs) divides |lhs| by |rhs| and returns the quotient
+// truncated to uint32. If |rhs| is zero, then zero is returned.
+inline uint32_t UnsignedDiv32(uint32_t lhs, uint32_t rhs) {
+  return rhs ? lhs / rhs : 0u;
+}
+
+
+// UnsignedMod32(lhs, rhs) divides |lhs| by |rhs| and returns the remainder
+// truncated to uint32. If |rhs| is zero, then zero is returned.
+inline uint32_t UnsignedMod32(uint32_t lhs, uint32_t rhs) {
+  return rhs ? lhs % rhs : 0u;
+}
+
 }  // namespace bits
 }  // namespace base
 }  // namespace v8
diff --git a/src/base/build_config.h b/src/base/build_config.h
index 2bf57c9..f528776 100644
--- a/src/base/build_config.h
+++ b/src/base/build_config.h
@@ -29,6 +29,10 @@
 #define V8_HOST_ARCH_64_BIT 1
 #endif
 #endif  // __native_client__
+#elif defined(__pnacl__)
+// PNaCl is also ILP-32.
+#define V8_HOST_ARCH_IA32 1
+#define V8_HOST_ARCH_32_BIT 1
 #elif defined(_M_IX86) || defined(__i386__)
 #define V8_HOST_ARCH_IA32 1
 #define V8_HOST_ARCH_32_BIT 1
diff --git a/src/base/compiler-specific.h b/src/base/compiler-specific.h
index 475a32c..9755fc1 100644
--- a/src/base/compiler-specific.h
+++ b/src/base/compiler-specific.h
@@ -7,15 +7,13 @@
 
 #include "include/v8config.h"
 
-// Annotate a variable indicating it's ok if the variable is not used.
-// (Typically used to silence a compiler warning when the assignment
-// is important for some other reason.)
+// Annotate a typedef or function indicating it's ok if it's not used.
 // Use like:
-//   int x ALLOW_UNUSED = ...;
+//   typedef Foo Bar ALLOW_UNUSED_TYPE;
 #if V8_HAS_ATTRIBUTE_UNUSED
-#define ALLOW_UNUSED __attribute__((unused))
+#define ALLOW_UNUSED_TYPE __attribute__((unused))
 #else
-#define ALLOW_UNUSED
+#define ALLOW_UNUSED_TYPE
 #endif
 
 
@@ -39,8 +37,6 @@
 #define FINAL final
 #elif V8_HAS___FINAL
 #define FINAL __final
-#elif V8_HAS_SEALED
-#define FINAL sealed
 #else
 #define FINAL /* NOT SUPPORTED */
 #endif
diff --git a/src/base/cpu.cc b/src/base/cpu.cc
index cd40d4f..daf3302 100644
--- a/src/base/cpu.cc
+++ b/src/base/cpu.cc
@@ -7,12 +7,18 @@
 #if V8_LIBC_MSVCRT
 #include <intrin.h>  // __cpuid()
 #endif
-#if V8_OS_POSIX
-#include <unistd.h>  // sysconf()
+#if V8_OS_LINUX
+#include <linux/auxvec.h>  // AT_HWCAP
+#endif
+#if V8_GLIBC_PREREQ(2, 16)
+#include <sys/auxv.h>  // getauxval()
 #endif
 #if V8_OS_QNX
 #include <sys/syspage.h>  // cpuinfo
 #endif
+#if V8_OS_POSIX
+#include <unistd.h>  // sysconf()
+#endif
 
 #include <ctype.h>
 #include <limits.h>
@@ -29,7 +35,9 @@
 namespace v8 {
 namespace base {
 
-#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
+#if defined(__pnacl__)
+// Portable host shouldn't do feature detection.
+#elif V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
 
 // Define __cpuid() for non-MSVC libraries.
 #if !V8_LIBC_MSVCRT
@@ -90,11 +98,12 @@
 #define HWCAP_IDIV  (HWCAP_IDIVA | HWCAP_IDIVT)
 #define HWCAP_LPAE  (1 << 20)
 
-#define AT_HWCAP 16
-
-// Read the ELF HWCAP flags by parsing /proc/self/auxv.
 static uint32_t ReadELFHWCaps() {
   uint32_t result = 0;
+#if V8_GLIBC_PREREQ(2, 16)
+  result = static_cast<uint32_t>(getauxval(AT_HWCAP));
+#else
+  // Read the ELF HWCAP flags by parsing /proc/self/auxv.
   FILE* fp = fopen("/proc/self/auxv", "r");
   if (fp != NULL) {
     struct { uint32_t tag; uint32_t value; } entry;
@@ -110,6 +119,7 @@
     }
     fclose(fp);
   }
+#endif
   return result;
 }
 
@@ -281,34 +291,42 @@
 
 #endif  // V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
 
-CPU::CPU() : stepping_(0),
-             model_(0),
-             ext_model_(0),
-             family_(0),
-             ext_family_(0),
-             type_(0),
-             implementer_(0),
-             architecture_(0),
-             part_(0),
-             has_fpu_(false),
-             has_cmov_(false),
-             has_sahf_(false),
-             has_mmx_(false),
-             has_sse_(false),
-             has_sse2_(false),
-             has_sse3_(false),
-             has_ssse3_(false),
-             has_sse41_(false),
-             has_sse42_(false),
-             has_idiva_(false),
-             has_neon_(false),
-             has_thumb2_(false),
-             has_vfp_(false),
-             has_vfp3_(false),
-             has_vfp3_d32_(false),
-             is_fp64_mode_(false) {
+CPU::CPU()
+    : stepping_(0),
+      model_(0),
+      ext_model_(0),
+      family_(0),
+      ext_family_(0),
+      type_(0),
+      implementer_(0),
+      architecture_(0),
+      variant_(-1),
+      part_(0),
+      has_fpu_(false),
+      has_cmov_(false),
+      has_sahf_(false),
+      has_mmx_(false),
+      has_sse_(false),
+      has_sse2_(false),
+      has_sse3_(false),
+      has_ssse3_(false),
+      has_sse41_(false),
+      has_sse42_(false),
+      has_avx_(false),
+      has_fma3_(false),
+      has_idiva_(false),
+      has_neon_(false),
+      has_thumb2_(false),
+      has_vfp_(false),
+      has_vfp3_(false),
+      has_vfp3_d32_(false),
+      is_fp64_mode_(false) {
   memcpy(vendor_, "Unknown", 8);
-#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
+#if V8_OS_NACL
+// Portable host shouldn't do feature detection.
+// TODO(jfb): Remove the hardcoded ARM simulator flags in the build, and
+// hardcode them here instead.
+#elif V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
   int cpu_info[4];
 
   // __cpuid with an InfoType argument of 0 returns the number of
@@ -342,6 +360,8 @@
     has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
     has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
     has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
+    has_avx_ = (cpu_info[2] & 0x10000000) != 0;
+    if (has_avx_) has_fma3_ = (cpu_info[2] & 0x00001000) != 0;
   }
 
 #if V8_HOST_ARCH_IA32
@@ -369,7 +389,7 @@
   // Extract implementor from the "CPU implementer" field.
   char* implementer = cpu_info.ExtractField("CPU implementer");
   if (implementer != NULL) {
-    char* end ;
+    char* end;
     implementer_ = strtol(implementer, &end, 0);
     if (end == implementer) {
       implementer_ = 0;
@@ -377,10 +397,20 @@
     delete[] implementer;
   }
 
+  char* variant = cpu_info.ExtractField("CPU variant");
+  if (variant != NULL) {
+    char* end;
+    variant_ = strtol(variant, &end, 0);
+    if (end == variant) {
+      variant_ = -1;
+    }
+    delete[] variant;
+  }
+
   // Extract part number from the "CPU part" field.
   char* part = cpu_info.ExtractField("CPU part");
   if (part != NULL) {
-    char* end ;
+    char* end;
     part_ = strtol(part, &end, 0);
     if (end == part) {
       part_ = 0;
@@ -408,7 +438,7 @@
     //
     // See http://code.google.com/p/android/issues/detail?id=10812
     //
-    // We try to correct this by looking at the 'elf_format'
+    // We try to correct this by looking at the 'elf_platform'
     // field reported by the 'Processor' field, which is of the
     // form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for
     // an ARMv6-one. For example, the Raspberry Pi is one popular
@@ -420,6 +450,15 @@
       }
       delete[] processor;
     }
+
+    // elf_platform moved to the model name field in Linux v3.8.
+    if (architecture_ == 7) {
+      char* processor = cpu_info.ExtractField("model name");
+      if (HasListItem(processor, "(v6l)")) {
+        architecture_ = 6;
+      }
+      delete[] processor;
+    }
   }
 
   // Try to extract the list of CPU features from ELF hwcaps.
@@ -521,7 +560,7 @@
   // Extract implementor from the "CPU implementer" field.
   char* implementer = cpu_info.ExtractField("CPU implementer");
   if (implementer != NULL) {
-    char* end ;
+    char* end;
     implementer_ = strtol(implementer, &end, 0);
     if (end == implementer) {
       implementer_ = 0;
@@ -529,10 +568,20 @@
     delete[] implementer;
   }
 
+  char* variant = cpu_info.ExtractField("CPU variant");
+  if (variant != NULL) {
+    char* end;
+    variant_ = strtol(variant, &end, 0);
+    if (end == variant) {
+      variant_ = -1;
+    }
+    delete[] variant;
+  }
+
   // Extract part number from the "CPU part" field.
   char* part = cpu_info.ExtractField("CPU part");
   if (part != NULL) {
-    char* end ;
+    char* end;
     part_ = strtol(part, &end, 0);
     if (end == part) {
       part_ = 0;
diff --git a/src/base/cpu.h b/src/base/cpu.h
index dc0eaf4..8c41f9d 100644
--- a/src/base/cpu.h
+++ b/src/base/cpu.h
@@ -47,6 +47,8 @@
   static const int NVIDIA = 0x4e;
   static const int QUALCOMM = 0x51;
   int architecture() const { return architecture_; }
+  int variant() const { return variant_; }
+  static const int NVIDIA_DENVER = 0x0;
   int part() const { return part_; }
   static const int ARM_CORTEX_A5 = 0xc05;
   static const int ARM_CORTEX_A7 = 0xc07;
@@ -68,6 +70,8 @@
   bool has_ssse3() const { return has_ssse3_; }
   bool has_sse41() const { return has_sse41_; }
   bool has_sse42() const { return has_sse42_; }
+  bool has_avx() const { return has_avx_; }
+  bool has_fma3() const { return has_fma3_; }
 
   // arm features
   bool has_idiva() const { return has_idiva_; }
@@ -90,6 +94,7 @@
   int type_;
   int implementer_;
   int architecture_;
+  int variant_;
   int part_;
   bool has_fpu_;
   bool has_cmov_;
@@ -101,6 +106,8 @@
   bool has_ssse3_;
   bool has_sse41_;
   bool has_sse42_;
+  bool has_avx_;
+  bool has_fma3_;
   bool has_idiva_;
   bool has_neon_;
   bool has_thumb2_;
diff --git a/src/base/division-by-constant-unittest.cc b/src/base/division-by-constant-unittest.cc
deleted file mode 100644
index 47c2483..0000000
--- a/src/base/division-by-constant-unittest.cc
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Check all examples from table 10-1 of "Hacker's Delight".
-
-#include "src/base/division-by-constant.h"
-
-#include <ostream>  // NOLINT
-
-#include "testing/gtest-support.h"
-
-namespace v8 {
-namespace base {
-
-template <class T>
-std::ostream& operator<<(std::ostream& os,
-                         const MagicNumbersForDivision<T>& mag) {
-  return os << "{ multiplier: " << mag.multiplier << ", shift: " << mag.shift
-            << ", add: " << mag.add << " }";
-}
-
-
-// Some abbreviations...
-
-typedef MagicNumbersForDivision<uint32_t> M32;
-typedef MagicNumbersForDivision<uint64_t> M64;
-
-
-static M32 s32(int32_t d) {
-  return SignedDivisionByConstant<uint32_t>(static_cast<uint32_t>(d));
-}
-
-
-static M64 s64(int64_t d) {
-  return SignedDivisionByConstant<uint64_t>(static_cast<uint64_t>(d));
-}
-
-
-static M32 u32(uint32_t d) { return UnsignedDivisionByConstant<uint32_t>(d); }
-static M64 u64(uint64_t d) { return UnsignedDivisionByConstant<uint64_t>(d); }
-
-
-TEST(DivisionByConstant, Signed32) {
-  EXPECT_EQ(M32(0x99999999U, 1, false), s32(-5));
-  EXPECT_EQ(M32(0x55555555U, 1, false), s32(-3));
-  int32_t d = -1;
-  for (unsigned k = 1; k <= 32 - 1; ++k) {
-    d *= 2;
-    EXPECT_EQ(M32(0x7FFFFFFFU, k - 1, false), s32(d));
-  }
-  for (unsigned k = 1; k <= 32 - 2; ++k) {
-    EXPECT_EQ(M32(0x80000001U, k - 1, false), s32(1 << k));
-  }
-  EXPECT_EQ(M32(0x55555556U, 0, false), s32(3));
-  EXPECT_EQ(M32(0x66666667U, 1, false), s32(5));
-  EXPECT_EQ(M32(0x2AAAAAABU, 0, false), s32(6));
-  EXPECT_EQ(M32(0x92492493U, 2, false), s32(7));
-  EXPECT_EQ(M32(0x38E38E39U, 1, false), s32(9));
-  EXPECT_EQ(M32(0x66666667U, 2, false), s32(10));
-  EXPECT_EQ(M32(0x2E8BA2E9U, 1, false), s32(11));
-  EXPECT_EQ(M32(0x2AAAAAABU, 1, false), s32(12));
-  EXPECT_EQ(M32(0x51EB851FU, 3, false), s32(25));
-  EXPECT_EQ(M32(0x10624DD3U, 3, false), s32(125));
-  EXPECT_EQ(M32(0x68DB8BADU, 8, false), s32(625));
-}
-
-
-TEST(DivisionByConstant, Unsigned32) {
-  EXPECT_EQ(M32(0x00000000U, 0, true), u32(1));
-  for (unsigned k = 1; k <= 30; ++k) {
-    EXPECT_EQ(M32(1U << (32 - k), 0, false), u32(1U << k));
-  }
-  EXPECT_EQ(M32(0xAAAAAAABU, 1, false), u32(3));
-  EXPECT_EQ(M32(0xCCCCCCCDU, 2, false), u32(5));
-  EXPECT_EQ(M32(0xAAAAAAABU, 2, false), u32(6));
-  EXPECT_EQ(M32(0x24924925U, 3, true), u32(7));
-  EXPECT_EQ(M32(0x38E38E39U, 1, false), u32(9));
-  EXPECT_EQ(M32(0xCCCCCCCDU, 3, false), u32(10));
-  EXPECT_EQ(M32(0xBA2E8BA3U, 3, false), u32(11));
-  EXPECT_EQ(M32(0xAAAAAAABU, 3, false), u32(12));
-  EXPECT_EQ(M32(0x51EB851FU, 3, false), u32(25));
-  EXPECT_EQ(M32(0x10624DD3U, 3, false), u32(125));
-  EXPECT_EQ(M32(0xD1B71759U, 9, false), u32(625));
-}
-
-
-TEST(DivisionByConstant, Signed64) {
-  EXPECT_EQ(M64(0x9999999999999999ULL, 1, false), s64(-5));
-  EXPECT_EQ(M64(0x5555555555555555ULL, 1, false), s64(-3));
-  int64_t d = -1;
-  for (unsigned k = 1; k <= 64 - 1; ++k) {
-    d *= 2;
-    EXPECT_EQ(M64(0x7FFFFFFFFFFFFFFFULL, k - 1, false), s64(d));
-  }
-  for (unsigned k = 1; k <= 64 - 2; ++k) {
-    EXPECT_EQ(M64(0x8000000000000001ULL, k - 1, false), s64(1LL << k));
-  }
-  EXPECT_EQ(M64(0x5555555555555556ULL, 0, false), s64(3));
-  EXPECT_EQ(M64(0x6666666666666667ULL, 1, false), s64(5));
-  EXPECT_EQ(M64(0x2AAAAAAAAAAAAAABULL, 0, false), s64(6));
-  EXPECT_EQ(M64(0x4924924924924925ULL, 1, false), s64(7));
-  EXPECT_EQ(M64(0x1C71C71C71C71C72ULL, 0, false), s64(9));
-  EXPECT_EQ(M64(0x6666666666666667ULL, 2, false), s64(10));
-  EXPECT_EQ(M64(0x2E8BA2E8BA2E8BA3ULL, 1, false), s64(11));
-  EXPECT_EQ(M64(0x2AAAAAAAAAAAAAABULL, 1, false), s64(12));
-  EXPECT_EQ(M64(0xA3D70A3D70A3D70BULL, 4, false), s64(25));
-  EXPECT_EQ(M64(0x20C49BA5E353F7CFULL, 4, false), s64(125));
-  EXPECT_EQ(M64(0x346DC5D63886594BULL, 7, false), s64(625));
-}
-
-
-TEST(DivisionByConstant, Unsigned64) {
-  EXPECT_EQ(M64(0x0000000000000000ULL, 0, true), u64(1));
-  for (unsigned k = 1; k <= 64 - 2; ++k) {
-    EXPECT_EQ(M64(1ULL << (64 - k), 0, false), u64(1ULL << k));
-  }
-  EXPECT_EQ(M64(0xAAAAAAAAAAAAAAABULL, 1, false), u64(3));
-  EXPECT_EQ(M64(0xCCCCCCCCCCCCCCCDULL, 2, false), u64(5));
-  EXPECT_EQ(M64(0xAAAAAAAAAAAAAAABULL, 2, false), u64(6));
-  EXPECT_EQ(M64(0x2492492492492493ULL, 3, true), u64(7));
-  EXPECT_EQ(M64(0xE38E38E38E38E38FULL, 3, false), u64(9));
-  EXPECT_EQ(M64(0xCCCCCCCCCCCCCCCDULL, 3, false), u64(10));
-  EXPECT_EQ(M64(0x2E8BA2E8BA2E8BA3ULL, 1, false), u64(11));
-  EXPECT_EQ(M64(0xAAAAAAAAAAAAAAABULL, 3, false), u64(12));
-  EXPECT_EQ(M64(0x47AE147AE147AE15ULL, 5, true), u64(25));
-  EXPECT_EQ(M64(0x0624DD2F1A9FBE77ULL, 7, true), u64(125));
-  EXPECT_EQ(M64(0x346DC5D63886594BULL, 7, false), u64(625));
-}
-
-}  // namespace base
-}  // namespace v8
diff --git a/src/base/division-by-constant.cc b/src/base/division-by-constant.cc
index 235d39f..5167b7a 100644
--- a/src/base/division-by-constant.cc
+++ b/src/base/division-by-constant.cc
@@ -52,7 +52,7 @@
     delta = ad - r2;
   } while (q1 < delta || (q1 == delta && r1 == 0));
   T mul = q2 + 1;
-  return {neg ? (0 - mul) : mul, p - bits, false};
+  return MagicNumbersForDivision<T>(neg ? (0 - mul) : mul, p - bits, false);
 }
 
 
@@ -93,7 +93,7 @@
     }
     delta = d - 1 - r2;
   } while (p < bits * 2 && (q1 < delta || (q1 == delta && r1 == 0)));
-  return {q2 + 1, p - bits, a};
+  return MagicNumbersForDivision<T>(q2 + 1, p - bits, a);
 }
 
 
diff --git a/src/base/flags-unittest.cc b/src/base/flags-unittest.cc
deleted file mode 100644
index a1d6f37..0000000
--- a/src/base/flags-unittest.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "include/v8stdint.h"
-#include "src/base/flags.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace v8 {
-namespace base {
-
-namespace {
-
-enum Flag1 {
-  kFlag1None = 0,
-  kFlag1First = 1u << 1,
-  kFlag1Second = 1u << 2,
-  kFlag1All = kFlag1None | kFlag1First | kFlag1Second
-};
-typedef Flags<Flag1> Flags1;
-
-
-DEFINE_OPERATORS_FOR_FLAGS(Flags1)
-
-
-Flags1 bar(Flags1 flags1) { return flags1; }
-
-}  // namespace
-
-
-TEST(FlagsTest, BasicOperations) {
-  Flags1 a;
-  EXPECT_EQ(kFlag1None, static_cast<int>(a));
-  a |= kFlag1First;
-  EXPECT_EQ(kFlag1First, static_cast<int>(a));
-  a = a | kFlag1Second;
-  EXPECT_EQ(kFlag1All, static_cast<int>(a));
-  a &= kFlag1Second;
-  EXPECT_EQ(kFlag1Second, static_cast<int>(a));
-  a = kFlag1None & a;
-  EXPECT_EQ(kFlag1None, static_cast<int>(a));
-  a ^= (kFlag1All | kFlag1None);
-  EXPECT_EQ(kFlag1All, static_cast<int>(a));
-  Flags1 b = ~a;
-  EXPECT_EQ(kFlag1All, static_cast<int>(a));
-  EXPECT_EQ(~static_cast<int>(a), static_cast<int>(b));
-  Flags1 c = a;
-  EXPECT_EQ(a, c);
-  EXPECT_NE(a, b);
-  EXPECT_EQ(a, bar(a));
-  EXPECT_EQ(a, bar(kFlag1All));
-}
-
-
-namespace {
-namespace foo {
-
-enum Option {
-  kNoOptions = 0,
-  kOption1 = 1,
-  kOption2 = 2,
-  kAllOptions = kNoOptions | kOption1 | kOption2
-};
-typedef Flags<Option> Options;
-
-}  // namespace foo
-
-
-DEFINE_OPERATORS_FOR_FLAGS(foo::Options)
-
-}  // namespace
-
-
-TEST(FlagsTest, NamespaceScope) {
-  foo::Options options;
-  options ^= foo::kNoOptions;
-  options |= foo::kOption1 | foo::kOption2;
-  EXPECT_EQ(foo::kAllOptions, static_cast<int>(options));
-}
-
-
-namespace {
-
-struct Foo {
-  enum Enum { kEnum1 = 1, kEnum2 = 2 };
-  typedef Flags<Enum, uint32_t> Enums;
-};
-
-
-DEFINE_OPERATORS_FOR_FLAGS(Foo::Enums)
-
-}  // namespace
-
-
-TEST(FlagsTest, ClassScope) {
-  Foo::Enums enums;
-  enums |= Foo::kEnum1;
-  enums |= Foo::kEnum2;
-  EXPECT_TRUE(enums & Foo::kEnum1);
-  EXPECT_TRUE(enums & Foo::kEnum2);
-}
-
-}  // namespace base
-}  // namespace v8
diff --git a/src/base/flags.h b/src/base/flags.h
index f3420ee..060dba8 100644
--- a/src/base/flags.h
+++ b/src/base/flags.h
@@ -26,8 +26,9 @@
   typedef S mask_type;
 
   Flags() : mask_(0) {}
-  Flags(flag_type flag) : mask_(flag) {}  // NOLINT(runtime/explicit)
-  explicit Flags(mask_type mask) : mask_(mask) {}
+  Flags(flag_type flag)  // NOLINT(runtime/explicit)
+      : mask_(static_cast<S>(flag)) {}
+  explicit Flags(mask_type mask) : mask_(static_cast<S>(mask)) {}
 
   Flags& operator&=(const Flags& flags) {
     mask_ &= flags.mask_;
@@ -64,42 +65,44 @@
 };
 
 
-#define DEFINE_OPERATORS_FOR_FLAGS(Type)                                       \
-  inline Type operator&(Type::flag_type lhs,                                   \
-                        Type::flag_type rhs)ALLOW_UNUSED WARN_UNUSED_RESULT;   \
-  inline Type operator&(Type::flag_type lhs, Type::flag_type rhs) {            \
-    return Type(lhs) & rhs;                                                    \
-  }                                                                            \
-  inline Type operator&(Type::flag_type lhs,                                   \
-                        const Type& rhs)ALLOW_UNUSED WARN_UNUSED_RESULT;       \
-  inline Type operator&(Type::flag_type lhs, const Type& rhs) {                \
-    return rhs & lhs;                                                          \
-  }                                                                            \
-  inline void operator&(Type::flag_type lhs, Type::mask_type rhs)ALLOW_UNUSED; \
-  inline void operator&(Type::flag_type lhs, Type::mask_type rhs) {}           \
-  inline Type operator|(Type::flag_type lhs, Type::flag_type rhs)              \
-      ALLOW_UNUSED WARN_UNUSED_RESULT;                                         \
-  inline Type operator|(Type::flag_type lhs, Type::flag_type rhs) {            \
-    return Type(lhs) | rhs;                                                    \
-  }                                                                            \
-  inline Type operator|(Type::flag_type lhs, const Type& rhs)                  \
-      ALLOW_UNUSED WARN_UNUSED_RESULT;                                         \
-  inline Type operator|(Type::flag_type lhs, const Type& rhs) {                \
-    return rhs | lhs;                                                          \
-  }                                                                            \
-  inline void operator|(Type::flag_type lhs, Type::mask_type rhs)              \
-      ALLOW_UNUSED;                                                            \
-  inline void operator|(Type::flag_type lhs, Type::mask_type rhs) {}           \
-  inline Type operator^(Type::flag_type lhs, Type::flag_type rhs)              \
-      ALLOW_UNUSED WARN_UNUSED_RESULT;                                         \
-  inline Type operator^(Type::flag_type lhs, Type::flag_type rhs) {            \
-    return Type(lhs) ^ rhs;                                                    \
-  } inline Type operator^(Type::flag_type lhs, const Type& rhs)                \
-      ALLOW_UNUSED WARN_UNUSED_RESULT;                                         \
-  inline Type operator^(Type::flag_type lhs, const Type& rhs) {                \
-    return rhs ^ lhs;                                                          \
-  } inline void operator^(Type::flag_type lhs, Type::mask_type rhs)            \
-      ALLOW_UNUSED;                                                            \
+#define DEFINE_OPERATORS_FOR_FLAGS(Type)                                      \
+  inline Type operator&(                                                      \
+      Type::flag_type lhs,                                                    \
+      Type::flag_type rhs)ALLOW_UNUSED_TYPE WARN_UNUSED_RESULT;               \
+  inline Type operator&(Type::flag_type lhs, Type::flag_type rhs) {           \
+    return Type(lhs) & rhs;                                                   \
+  }                                                                           \
+  inline Type operator&(Type::flag_type lhs,                                  \
+                        const Type& rhs)ALLOW_UNUSED_TYPE WARN_UNUSED_RESULT; \
+  inline Type operator&(Type::flag_type lhs, const Type& rhs) {               \
+    return rhs & lhs;                                                         \
+  }                                                                           \
+  inline void operator&(Type::flag_type lhs,                                  \
+                        Type::mask_type rhs)ALLOW_UNUSED_TYPE;                \
+  inline void operator&(Type::flag_type lhs, Type::mask_type rhs) {}          \
+  inline Type operator|(Type::flag_type lhs, Type::flag_type rhs)             \
+      ALLOW_UNUSED_TYPE WARN_UNUSED_RESULT;                                   \
+  inline Type operator|(Type::flag_type lhs, Type::flag_type rhs) {           \
+    return Type(lhs) | rhs;                                                   \
+  }                                                                           \
+  inline Type operator|(Type::flag_type lhs, const Type& rhs)                 \
+      ALLOW_UNUSED_TYPE WARN_UNUSED_RESULT;                                   \
+  inline Type operator|(Type::flag_type lhs, const Type& rhs) {               \
+    return rhs | lhs;                                                         \
+  }                                                                           \
+  inline void operator|(Type::flag_type lhs, Type::mask_type rhs)             \
+      ALLOW_UNUSED_TYPE;                                                      \
+  inline void operator|(Type::flag_type lhs, Type::mask_type rhs) {}          \
+  inline Type operator^(Type::flag_type lhs, Type::flag_type rhs)             \
+      ALLOW_UNUSED_TYPE WARN_UNUSED_RESULT;                                   \
+  inline Type operator^(Type::flag_type lhs, Type::flag_type rhs) {           \
+    return Type(lhs) ^ rhs;                                                   \
+  } inline Type operator^(Type::flag_type lhs, const Type& rhs)               \
+      ALLOW_UNUSED_TYPE WARN_UNUSED_RESULT;                                   \
+  inline Type operator^(Type::flag_type lhs, const Type& rhs) {               \
+    return rhs ^ lhs;                                                         \
+  } inline void operator^(Type::flag_type lhs, Type::mask_type rhs)           \
+      ALLOW_UNUSED_TYPE;                                                      \
   inline void operator^(Type::flag_type lhs, Type::mask_type rhs) {}
 
 }  // namespace base
diff --git a/src/base/functional.cc b/src/base/functional.cc
new file mode 100644
index 0000000..d212912
--- /dev/null
+++ b/src/base/functional.cc
@@ -0,0 +1,111 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This also contains public domain code from MurmurHash. From the
+// MurmurHash header:
+//
+// MurmurHash3 was written by Austin Appleby, and is placed in the public
+// domain. The author hereby disclaims copyright to this source code.
+
+#include "src/base/functional.h"
+
+#include <limits>
+
+#include "src/base/bits.h"
+
+namespace v8 {
+namespace base {
+
+namespace {
+
+// Thomas Wang, Integer Hash Functions.
+// https://gist.github.com/badboy/6267743
+template <typename T>
+V8_INLINE size_t hash_value_unsigned(T v) {
+  switch (sizeof(T)) {
+    case 4: {
+      // "32 bit Mix Functions"
+      v = ~v + (v << 15);  // v = (v << 15) - v - 1;
+      v = v ^ (v >> 12);
+      v = v + (v << 2);
+      v = v ^ (v >> 4);
+      v = v * 2057;  // v = (v + (v << 3)) + (v << 11);
+      v = v ^ (v >> 16);
+      return static_cast<size_t>(v);
+    }
+    case 8: {
+      switch (sizeof(size_t)) {
+        case 4: {
+          // "64 bit to 32 bit Hash Functions"
+          v = ~v + (v << 18);  // v = (v << 18) - v - 1;
+          v = v ^ (v >> 31);
+          v = v * 21;  // v = (v + (v << 2)) + (v << 4);
+          v = v ^ (v >> 11);
+          v = v + (v << 6);
+          v = v ^ (v >> 22);
+          return static_cast<size_t>(v);
+        }
+        case 8: {
+          // "64 bit Mix Functions"
+          v = ~v + (v << 21);  // v = (v << 21) - v - 1;
+          v = v ^ (v >> 24);
+          v = (v + (v << 3)) + (v << 8);  // v * 265
+          v = v ^ (v >> 14);
+          v = (v + (v << 2)) + (v << 4);  // v * 21
+          v = v ^ (v >> 28);
+          v = v + (v << 31);
+          return static_cast<size_t>(v);
+        }
+      }
+    }
+  }
+  UNREACHABLE();
+  return static_cast<size_t>(v);
+}
+
+}  // namespace
+
+
+// This code was taken from MurmurHash.
+size_t hash_combine(size_t seed, size_t value) {
+#if V8_HOST_ARCH_32_BIT
+  const uint32_t c1 = 0xcc9e2d51;
+  const uint32_t c2 = 0x1b873593;
+
+  value *= c1;
+  value = bits::RotateRight32(value, 15);
+  value *= c2;
+
+  seed ^= value;
+  seed = bits::RotateRight32(seed, 13);
+  seed = seed * 5 + 0xe6546b64;
+#else
+  const uint64_t m = V8_UINT64_C(0xc6a4a7935bd1e995);
+  const uint32_t r = 47;
+
+  value *= m;
+  value ^= value >> r;
+  value *= m;
+
+  seed ^= value;
+  seed *= m;
+#endif  // V8_HOST_ARCH_32_BIT
+  return seed;
+}
+
+
+size_t hash_value(unsigned int v) { return hash_value_unsigned(v); }
+
+
+size_t hash_value(unsigned long v) {  // NOLINT(runtime/int)
+  return hash_value_unsigned(v);
+}
+
+
+size_t hash_value(unsigned long long v) {  // NOLINT(runtime/int)
+  return hash_value_unsigned(v);
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/src/base/functional.h b/src/base/functional.h
new file mode 100644
index 0000000..ff0d807
--- /dev/null
+++ b/src/base/functional.h
@@ -0,0 +1,227 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_BASE_FUNCTIONAL_H_
+#define V8_BASE_FUNCTIONAL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstddef>
+#include <cstring>
+#include <functional>
+#include <utility>
+
+#include "src/base/macros.h"
+
+namespace v8 {
+namespace base {
+
+// base::hash is an implementation of the hash function object specified by
+// C++11. It was designed to be compatible with std::hash (in C++11) and
+// boost:hash (which in turn is based on the hash function object specified by
+// the Draft Technical Report on C++ Library Extensions (TR1)).
+//
+// base::hash is implemented by calling the hash_value function. The namespace
+// isn't specified so that it can detect overloads via argument dependant
+// lookup. So if there is a free function hash_value in the same namespace as a
+// custom type, it will get called.
+//
+// If users are asked to implement a hash function for their own types with no
+// guidance, they generally write bad hash functions. Instead, we provide  a
+// simple function base::hash_combine to pass hash-relevant member variables
+// into, in order to define a decent hash function. base::hash_combine is
+// declared as:
+//
+//   template<typename T, typename... Ts>
+//   size_t hash_combine(const T& v, const Ts& ...vs);
+//
+// Consider the following example:
+//
+//   namespace v8 {
+//   namespace bar {
+//     struct Point { int x; int y; };
+//     size_t hash_value(Point const& p) {
+//       return base::hash_combine(p.x, p.y);
+//     }
+//   }
+//
+//   namespace foo {
+//     void DoSomeWork(bar::Point const& p) {
+//       base::hash<bar::Point> h;
+//       ...
+//       size_t hash_code = h(p);  // calls bar::hash_value(Point const&)
+//       ...
+//     }
+//   }
+//   }
+//
+// Based on the "Hashing User-Defined Types in C++1y" proposal from Jeffrey
+// Yasskin and Chandler Carruth, see
+// http://www.open-std.org/Jtc1/sc22/wg21/docs/papers/2012/n3333.html.
+
+template <typename>
+struct hash;
+
+
+V8_INLINE size_t hash_combine() { return 0u; }
+V8_INLINE size_t hash_combine(size_t seed) { return seed; }
+size_t hash_combine(size_t seed, size_t value);
+template <typename T, typename... Ts>
+V8_INLINE size_t hash_combine(T const& v, Ts const&... vs) {
+  return hash_combine(hash_combine(vs...), hash<T>()(v));
+}
+
+
+template <typename Iterator>
+V8_INLINE size_t hash_range(Iterator first, Iterator last) {
+  size_t seed = 0;
+  for (; first != last; ++first) {
+    seed = hash_combine(seed, *first);
+  }
+  return seed;
+}
+
+
+#define V8_BASE_HASH_VALUE_TRIVIAL(type) \
+  V8_INLINE size_t hash_value(type v) { return static_cast<size_t>(v); }
+V8_BASE_HASH_VALUE_TRIVIAL(bool)
+V8_BASE_HASH_VALUE_TRIVIAL(unsigned char)
+V8_BASE_HASH_VALUE_TRIVIAL(unsigned short)  // NOLINT(runtime/int)
+#undef V8_BASE_HASH_VALUE_TRIVIAL
+
+size_t hash_value(unsigned int);
+size_t hash_value(unsigned long);       // NOLINT(runtime/int)
+size_t hash_value(unsigned long long);  // NOLINT(runtime/int)
+
+#define V8_BASE_HASH_VALUE_SIGNED(type)            \
+  V8_INLINE size_t hash_value(signed type v) {     \
+    return hash_value(bit_cast<unsigned type>(v)); \
+  }
+V8_BASE_HASH_VALUE_SIGNED(char)
+V8_BASE_HASH_VALUE_SIGNED(short)      // NOLINT(runtime/int)
+V8_BASE_HASH_VALUE_SIGNED(int)        // NOLINT(runtime/int)
+V8_BASE_HASH_VALUE_SIGNED(long)       // NOLINT(runtime/int)
+V8_BASE_HASH_VALUE_SIGNED(long long)  // NOLINT(runtime/int)
+#undef V8_BASE_HASH_VALUE_SIGNED
+
+V8_INLINE size_t hash_value(float v) {
+  // 0 and -0 both hash to zero.
+  return v != 0.0f ? hash_value(bit_cast<uint32_t>(v)) : 0;
+}
+
+V8_INLINE size_t hash_value(double v) {
+  // 0 and -0 both hash to zero.
+  return v != 0.0 ? hash_value(bit_cast<uint64_t>(v)) : 0;
+}
+
+template <typename T, size_t N>
+V8_INLINE size_t hash_value(const T (&v)[N]) {
+  return hash_range(v, v + N);
+}
+
+template <typename T, size_t N>
+V8_INLINE size_t hash_value(T (&v)[N]) {
+  return hash_range(v, v + N);
+}
+
+template <typename T>
+V8_INLINE size_t hash_value(T* const& v) {
+  return hash_value(bit_cast<uintptr_t>(v));
+}
+
+template <typename T1, typename T2>
+V8_INLINE size_t hash_value(std::pair<T1, T2> const& v) {
+  return hash_combine(v.first, v.second);
+}
+
+
+template <typename T>
+struct hash : public std::unary_function<T, size_t> {
+  V8_INLINE size_t operator()(T const& v) const { return hash_value(v); }
+};
+
+#define V8_BASE_HASH_SPECIALIZE(type)                            \
+  template <>                                                    \
+  struct hash<type> : public std::unary_function<type, size_t> { \
+    V8_INLINE size_t operator()(type const v) const {            \
+      return ::v8::base::hash_value(v);                          \
+    }                                                            \
+  };
+V8_BASE_HASH_SPECIALIZE(bool)
+V8_BASE_HASH_SPECIALIZE(signed char)
+V8_BASE_HASH_SPECIALIZE(unsigned char)
+V8_BASE_HASH_SPECIALIZE(short)           // NOLINT(runtime/int)
+V8_BASE_HASH_SPECIALIZE(unsigned short)  // NOLINT(runtime/int)
+V8_BASE_HASH_SPECIALIZE(int)
+V8_BASE_HASH_SPECIALIZE(unsigned int)
+V8_BASE_HASH_SPECIALIZE(long)                // NOLINT(runtime/int)
+V8_BASE_HASH_SPECIALIZE(unsigned long)       // NOLINT(runtime/int)
+V8_BASE_HASH_SPECIALIZE(long long)           // NOLINT(runtime/int)
+V8_BASE_HASH_SPECIALIZE(unsigned long long)  // NOLINT(runtime/int)
+V8_BASE_HASH_SPECIALIZE(float)
+V8_BASE_HASH_SPECIALIZE(double)
+#undef V8_BASE_HASH_SPECIALIZE
+
+template <typename T>
+struct hash<T*> : public std::unary_function<T*, size_t> {
+  V8_INLINE size_t operator()(T* const v) const {
+    return ::v8::base::hash_value(v);
+  }
+};
+
+
+// base::bit_equal_to is a function object class for bitwise equality
+// comparison, similar to std::equal_to, except that the comparison is performed
+// on the bit representation of the operands.
+//
+// base::bit_hash is a function object class for bitwise hashing, similar to
+// base::hash. It can be used together with base::bit_equal_to to implement a
+// hash data structure based on the bitwise representation of types.
+
+template <typename T>
+struct bit_equal_to : public std::binary_function<T, T, bool> {};
+
+template <typename T>
+struct bit_hash : public std::unary_function<T, size_t> {};
+
+#define V8_BASE_BIT_SPECIALIZE_TRIVIAL(type)                 \
+  template <>                                                \
+  struct bit_equal_to<type> : public std::equal_to<type> {}; \
+  template <>                                                \
+  struct bit_hash<type> : public hash<type> {};
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(signed char)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned char)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(short)           // NOLINT(runtime/int)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned short)  // NOLINT(runtime/int)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(int)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned int)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(long)                // NOLINT(runtime/int)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned long)       // NOLINT(runtime/int)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(long long)           // NOLINT(runtime/int)
+V8_BASE_BIT_SPECIALIZE_TRIVIAL(unsigned long long)  // NOLINT(runtime/int)
+#undef V8_BASE_BIT_SPECIALIZE_TRIVIAL
+
+#define V8_BASE_BIT_SPECIALIZE_BIT_CAST(type, btype)                          \
+  template <>                                                                 \
+  struct bit_equal_to<type> : public std::binary_function<type, type, bool> { \
+    V8_INLINE bool operator()(type lhs, type rhs) const {                     \
+      return bit_cast<btype>(lhs) == bit_cast<btype>(rhs);                    \
+    }                                                                         \
+  };                                                                          \
+  template <>                                                                 \
+  struct bit_hash<type> : public std::unary_function<type, size_t> {          \
+    V8_INLINE size_t operator()(type v) const {                               \
+      hash<btype> h;                                                          \
+      return h(bit_cast<btype>(v));                                           \
+    }                                                                         \
+  };
+V8_BASE_BIT_SPECIALIZE_BIT_CAST(float, uint32_t)
+V8_BASE_BIT_SPECIALIZE_BIT_CAST(double, uint64_t)
+#undef V8_BASE_BIT_SPECIALIZE_BIT_CAST
+
+}  // namespace base
+}  // namespace v8
+
+#endif  // V8_BASE_FUNCTIONAL_H_
diff --git a/src/base/iterator.h b/src/base/iterator.h
new file mode 100644
index 0000000..e380dc3
--- /dev/null
+++ b/src/base/iterator.h
@@ -0,0 +1,56 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_BASE_ITERATOR_H_
+#define V8_BASE_ITERATOR_H_
+
+#include <iterator>
+
+#include "src/base/macros.h"
+
+namespace v8 {
+namespace base {
+
+// The intention of the base::iterator_range class is to encapsulate two
+// iterators so that the range defined by the iterators can be used like
+// a regular STL container (actually only a subset of the full container
+// functionality is available usually).
+template <typename ForwardIterator>
+class iterator_range {
+ public:
+  typedef ForwardIterator iterator;
+  typedef ForwardIterator const_iterator;
+  typedef typename std::iterator_traits<iterator>::pointer pointer;
+  typedef typename std::iterator_traits<iterator>::reference reference;
+  typedef typename std::iterator_traits<iterator>::value_type value_type;
+  typedef
+      typename std::iterator_traits<iterator>::difference_type difference_type;
+
+  iterator_range() : begin_(), end_() {}
+  template <typename ForwardIterator2>
+  iterator_range(ForwardIterator2 const& begin, ForwardIterator2 const& end)
+      : begin_(begin), end_(end) {}
+
+  iterator begin() { return begin_; }
+  iterator end() { return end_; }
+  const_iterator begin() const { return begin_; }
+  const_iterator end() const { return end_; }
+  const_iterator cbegin() const { return begin_; }
+  const_iterator cend() const { return end_; }
+
+  bool empty() const { return cbegin() == cend(); }
+
+  // Random Access iterators only.
+  reference operator[](difference_type n) { return begin()[n]; }
+  difference_type size() const { return cend() - cbegin(); }
+
+ private:
+  const_iterator const begin_;
+  const_iterator const end_;
+};
+
+}  // namespace base
+}  // namespace v8
+
+#endif  // V8_BASE_ITERATOR_H_
diff --git a/src/base/logging.h b/src/base/logging.h
index 8e24bb0..83c1bb6 100644
--- a/src/base/logging.h
+++ b/src/base/logging.h
@@ -5,9 +5,9 @@
 #ifndef V8_BASE_LOGGING_H_
 #define V8_BASE_LOGGING_H_
 
+#include <stdint.h>
 #include <string.h>
 
-#include "include/v8stdint.h"
 #include "src/base/build_config.h"
 
 extern "C" void V8_Fatal(const char* file, int line, const char* format, ...);
diff --git a/src/base/macros.h b/src/base/macros.h
index cef088c..371d7da 100644
--- a/src/base/macros.h
+++ b/src/base/macros.h
@@ -5,9 +5,11 @@
 #ifndef V8_BASE_MACROS_H_
 #define V8_BASE_MACROS_H_
 
+#include <stddef.h>
+#include <stdint.h>
+
 #include <cstring>
 
-#include "include/v8stdint.h"
 #include "src/base/build_config.h"
 #include "src/base/compiler-specific.h"
 #include "src/base/logging.h"
@@ -18,11 +20,13 @@
 // corresponds to 'offsetof' (in stddef.h), except that it doesn't
 // use 0 or NULL, which causes a problem with the compiler warnings
 // we have enabled (which is also why 'offsetof' doesn't seem to work).
-// Here we simply use the non-zero value 4, which seems to work.
-#define OFFSET_OF(type, field)                                          \
-  (reinterpret_cast<intptr_t>(&(reinterpret_cast<type*>(4)->field)) - 4)
+// Here we simply use the aligned, non-zero value 16.
+#define OFFSET_OF(type, field) \
+  (reinterpret_cast<intptr_t>(&(reinterpret_cast<type*>(16)->field)) - 16)
 
 
+#if V8_OS_NACL
+
 // ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize,
 // but can be used on anonymous types or types defined inside
 // functions.  It's less safe than arraysize as it accepts some
@@ -63,9 +67,6 @@
   ((sizeof(a) / sizeof(*(a))) / \
    static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))  // NOLINT
 
-
-#if V8_OS_NACL
-
 // TODO(bmeurer): For some reason, the NaCl toolchain cannot handle the correct
 // definition of arraysize() below, so we have to use the unsafe version for
 // now.
@@ -130,7 +131,7 @@
 
 #define COMPILE_ASSERT(expr, msg)                \
   typedef CompileAssert<static_cast<bool>(expr)> \
-      msg[static_cast<bool>(expr) ? 1 : -1] ALLOW_UNUSED
+      msg[static_cast<bool>(expr) ? 1 : -1] ALLOW_UNUSED_TYPE
 
 // Implementation details of COMPILE_ASSERT:
 //
@@ -150,23 +151,11 @@
 //     COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
 //                               // not a compile-time constant.
 //
-// - By using the type CompileAssert<(bool(expr))>, we ensures that
+// - By using the type CompileAssert<static_cast<bool>(expr)>, we ensure that
 //   expr is a compile-time constant.  (Template arguments must be
 //   determined at compile-time.)
 //
-// - The outer parentheses in CompileAssert<(bool(expr))> are necessary
-//   to work around a bug in gcc 3.4.4 and 4.0.1.  If we had written
-//
-//     CompileAssert<bool(expr)>
-//
-//   instead, these compilers will refuse to compile
-//
-//     COMPILE_ASSERT(5 > 0, some_message);
-//
-//   (They seem to think the ">" in "5 > 0" marks the end of the
-//   template argument list.)
-//
-// - The array size is (bool(expr) ? 1 : -1), instead of simply
+// - The array size is (static_cast<bool>(expr) ? 1 : -1), instead of simply
 //
 //     ((expr) ? 1 : -1).
 //
@@ -308,10 +297,10 @@
 // actually causes each use to introduce a new defined type with a
 // name depending on the source line.
 template <int> class StaticAssertionHelper { };
-#define STATIC_ASSERT(test)                                                    \
-  typedef                                                                     \
-    StaticAssertionHelper<sizeof(StaticAssertion<static_cast<bool>((test))>)> \
-    SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__) ALLOW_UNUSED
+#define STATIC_ASSERT(test)                               \
+  typedef StaticAssertionHelper<                          \
+      sizeof(StaticAssertion<static_cast<bool>((test))>)> \
+      SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__) ALLOW_UNUSED_TYPE
 
 #endif
 
@@ -408,4 +397,22 @@
   return RoundDown<T>(static_cast<T>(x + m - 1), m);
 }
 
+
+namespace v8 {
+namespace base {
+
+// TODO(yangguo): This is a poor man's replacement for std::is_fundamental,
+// which requires C++11. Switch to std::is_fundamental once possible.
+template <typename T>
+inline bool is_fundamental() {
+  return false;
+}
+
+template <>
+inline bool is_fundamental<uint8_t>() {
+  return true;
+}
+}
+}  // namespace v8::base
+
 #endif   // V8_BASE_MACROS_H_
diff --git a/src/base/once.h b/src/base/once.h
index a8e8437..6bf741d 100644
--- a/src/base/once.h
+++ b/src/base/once.h
@@ -52,6 +52,8 @@
 #ifndef V8_BASE_ONCE_H_
 #define V8_BASE_ONCE_H_
 
+#include <stddef.h>
+
 #include "src/base/atomicops.h"
 
 namespace v8 {
diff --git a/src/base/platform/platform-freebsd.cc b/src/base/platform/platform-freebsd.cc
index 507b946..58316f8 100644
--- a/src/base/platform/platform-freebsd.cc
+++ b/src/base/platform/platform-freebsd.cc
@@ -141,7 +141,7 @@
     if (bytes_read < 8) break;
     unsigned end = StringToLong(addr_buffer);
     char buffer[MAP_LENGTH];
-    int bytes_read = -1;
+    bytes_read = -1;
     do {
       bytes_read++;
       if (bytes_read >= MAP_LENGTH - 1)
diff --git a/src/base/platform/platform-linux.cc b/src/base/platform/platform-linux.cc
index eff5ced..36857e6 100644
--- a/src/base/platform/platform-linux.cc
+++ b/src/base/platform/platform-linux.cc
@@ -8,10 +8,10 @@
 #include <pthread.h>
 #include <semaphore.h>
 #include <signal.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <sys/resource.h>
 #include <sys/time.h>
-#include <sys/types.h>
 
 // Ubuntu Dapper requires memory pages to be marked as
 // executable. Otherwise, OS raises an exception when executing code
@@ -109,7 +109,7 @@
   if (std::isnan(time)) return "";
   time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
   struct tm* t = localtime(&tv);
-  if (NULL == t) return "";
+  if (!t || !t->tm_zone) return "";
   return t->tm_zone;
 #endif
 }
diff --git a/src/base/platform/platform-posix.cc b/src/base/platform/platform-posix.cc
index 99feb65..64aed2b 100644
--- a/src/base/platform/platform-posix.cc
+++ b/src/base/platform/platform-posix.cc
@@ -13,6 +13,7 @@
 #include <pthread_np.h>  // for pthread_set_name_np
 #endif
 #include <sched.h>  // for sched_yield
+#include <stdio.h>
 #include <time.h>
 #include <unistd.h>
 
@@ -253,20 +254,14 @@
 
 
 int OS::GetCurrentThreadId() {
-#if defined(ANDROID)
-#if defined(__APPLE__)
-  uint64_t owner;
-  pthread_threadid_np(NULL, &owner);  // Requires Mac OS 10.6
-  return owner;
-#else
+#if V8_OS_MACOSX || (V8_OS_ANDROID && defined(__APPLE__))
+  return static_cast<int>(pthread_mach_thread_np(pthread_self()));
+#elif V8_OS_LINUX
   return static_cast<int>(syscall(__NR_gettid));
-#endif
-#elif defined(SYS_gettid)
-  return static_cast<int>(syscall(SYS_gettid));
+#elif V8_OS_ANDROID
+  return static_cast<int>(gettid());
 #else
-  // PNaCL doesn't have a way to get an integral thread ID, but it doesn't
-  // really matter, because we only need it in PerfJitLogger::LogRecordedBuffer.
-  return 0;
+  return static_cast<int>(reinterpret_cast<intptr_t>(pthread_self()));
 #endif
 }
 
diff --git a/src/base/platform/platform-solaris.cc b/src/base/platform/platform-solaris.cc
index b9ef465..b9a2ec8 100644
--- a/src/base/platform/platform-solaris.cc
+++ b/src/base/platform/platform-solaris.cc
@@ -31,26 +31,6 @@
 #include "src/base/platform/platform.h"
 
 
-// It seems there is a bug in some Solaris distributions (experienced in
-// SunOS 5.10 Generic_141445-09) which make it difficult or impossible to
-// access signbit() despite the availability of other C99 math functions.
-#ifndef signbit
-namespace std {
-// Test sign - usually defined in math.h
-int signbit(double x) {
-  // We need to take care of the special case of both positive and negative
-  // versions of zero.
-  if (x == 0) {
-    return fpclass(x) & FP_NZERO;
-  } else {
-    // This won't detect negative NaN but that should be okay since we don't
-    // assume that behavior.
-    return x < 0;
-  }
-}
-}  // namespace std
-#endif  // signbit
-
 namespace v8 {
 namespace base {
 
diff --git a/src/base/platform/platform-unittest.cc b/src/base/platform/platform-unittest.cc
deleted file mode 100644
index 06fbee0..0000000
--- a/src/base/platform/platform-unittest.cc
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/base/platform/platform.h"
-
-#if V8_OS_POSIX
-#include <unistd.h>  // NOLINT
-#endif
-
-#if V8_OS_WIN
-#include "src/base/win32-headers.h"
-#endif
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace v8 {
-namespace base {
-
-TEST(OS, GetCurrentProcessId) {
-#if V8_OS_POSIX
-  EXPECT_EQ(static_cast<int>(getpid()), OS::GetCurrentProcessId());
-#endif
-
-#if V8_OS_WIN
-  EXPECT_EQ(static_cast<int>(::GetCurrentProcessId()),
-            OS::GetCurrentProcessId());
-#endif
-}
-
-
-namespace {
-
-class SelfJoinThread FINAL : public Thread {
- public:
-  SelfJoinThread() : Thread(Options("SelfJoinThread")) {}
-  virtual void Run() OVERRIDE { Join(); }
-};
-
-}  // namespace
-
-
-TEST(Thread, SelfJoin) {
-  SelfJoinThread thread;
-  thread.Start();
-  thread.Join();
-}
-
-
-namespace {
-
-class ThreadLocalStorageTest : public Thread, public ::testing::Test {
- public:
-  ThreadLocalStorageTest() : Thread(Options("ThreadLocalStorageTest")) {
-    for (size_t i = 0; i < arraysize(keys_); ++i) {
-      keys_[i] = Thread::CreateThreadLocalKey();
-    }
-  }
-  ~ThreadLocalStorageTest() {
-    for (size_t i = 0; i < arraysize(keys_); ++i) {
-      Thread::DeleteThreadLocalKey(keys_[i]);
-    }
-  }
-
-  virtual void Run() FINAL OVERRIDE {
-    for (size_t i = 0; i < arraysize(keys_); i++) {
-      CHECK(!Thread::HasThreadLocal(keys_[i]));
-    }
-    for (size_t i = 0; i < arraysize(keys_); i++) {
-      Thread::SetThreadLocal(keys_[i], GetValue(i));
-    }
-    for (size_t i = 0; i < arraysize(keys_); i++) {
-      CHECK(Thread::HasThreadLocal(keys_[i]));
-    }
-    for (size_t i = 0; i < arraysize(keys_); i++) {
-      CHECK_EQ(GetValue(i), Thread::GetThreadLocal(keys_[i]));
-      CHECK_EQ(GetValue(i), Thread::GetExistingThreadLocal(keys_[i]));
-    }
-    for (size_t i = 0; i < arraysize(keys_); i++) {
-      Thread::SetThreadLocal(keys_[i], GetValue(arraysize(keys_) - i - 1));
-    }
-    for (size_t i = 0; i < arraysize(keys_); i++) {
-      CHECK(Thread::HasThreadLocal(keys_[i]));
-    }
-    for (size_t i = 0; i < arraysize(keys_); i++) {
-      CHECK_EQ(GetValue(arraysize(keys_) - i - 1),
-               Thread::GetThreadLocal(keys_[i]));
-      CHECK_EQ(GetValue(arraysize(keys_) - i - 1),
-               Thread::GetExistingThreadLocal(keys_[i]));
-    }
-  }
-
- private:
-  static void* GetValue(size_t x) {
-    return reinterpret_cast<void*>(static_cast<uintptr_t>(x + 1));
-  }
-
-  Thread::LocalStorageKey keys_[256];
-};
-
-}  // namespace
-
-
-TEST_F(ThreadLocalStorageTest, DoTest) {
-  Run();
-  Start();
-  Join();
-}
-
-}  // namespace base
-}  // namespace v8
diff --git a/src/base/platform/platform-win32.cc b/src/base/platform/platform-win32.cc
index 10f89de..d68e861 100644
--- a/src/base/platform/platform-win32.cc
+++ b/src/base/platform/platform-win32.cc
@@ -15,9 +15,7 @@
 #endif  // MINGW_HAS_SECURE_API
 #endif  // __MINGW32__
 
-#ifdef _MSC_VER
 #include <limits>
-#endif
 
 #include "src/base/win32-headers.h"
 
@@ -28,16 +26,6 @@
 #include "src/base/platform/time.h"
 #include "src/base/utils/random-number-generator.h"
 
-#ifdef _MSC_VER
-
-// Case-insensitive bounded string comparisons. Use stricmp() on Win32. Usually
-// defined in strings.h.
-int strncasecmp(const char* s1, const char* s2, int n) {
-  return _strnicmp(s1, s2, n);
-}
-
-#endif  // _MSC_VER
-
 
 // Extra functions for MinGW. Most of these are the _s functions which are in
 // the Microsoft Visual Studio C++ CRT.
@@ -367,8 +355,8 @@
   cache->InitializeIfNeeded();
 
   Win32Time rounded_to_second(*this);
-  rounded_to_second.t() = rounded_to_second.t() / 1000 / kTimeScaler *
-      1000 * kTimeScaler;
+  rounded_to_second.t() =
+      rounded_to_second.t() / 1000 / kTimeScaler * 1000 * kTimeScaler;
   // Convert to local time using POSIX localtime function.
   // Windows XP Service Pack 3 made SystemTimeToTzSpecificLocalTime()
   // very slow.  Other browsers use localtime().
@@ -832,7 +820,7 @@
 
 
 void OS::DebugBreak() {
-#ifdef _MSC_VER
+#if V8_CC_MSVC
   // To avoid Visual Studio runtime support the following code can be used
   // instead
   // __asm { int 3 }
@@ -1175,11 +1163,7 @@
 
 
 double OS::nan_value() {
-#ifdef _MSC_VER
   return std::numeric_limits<double>::quiet_NaN();
-#else  // _MSC_VER
-  return NAN;
-#endif  // _MSC_VER
 }
 
 
diff --git a/src/base/platform/platform.h b/src/base/platform/platform.h
index 9e20c08..0bf1027 100644
--- a/src/base/platform/platform.h
+++ b/src/base/platform/platform.h
@@ -21,7 +21,7 @@
 #ifndef V8_BASE_PLATFORM_PLATFORM_H_
 #define V8_BASE_PLATFORM_PLATFORM_H_
 
-#include <stdarg.h>
+#include <cstdarg>
 #include <string>
 #include <vector>
 
@@ -29,48 +29,10 @@
 #include "src/base/platform/mutex.h"
 #include "src/base/platform/semaphore.h"
 
-#ifdef __sun
-# ifndef signbit
-namespace std {
-int signbit(double x);
-}
-# endif
-#endif
-
 #if V8_OS_QNX
 #include "src/base/qnx-math.h"
 #endif
 
-// Microsoft Visual C++ specific stuff.
-#if V8_LIBC_MSVCRT
-
-#include "src/base/win32-headers.h"
-#include "src/base/win32-math.h"
-
-int strncasecmp(const char* s1, const char* s2, int n);
-
-// Visual C++ 2013 and higher implement this function.
-#if (_MSC_VER < 1800)
-inline int lrint(double flt) {
-  int intgr;
-#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87
-  __asm {
-    fld flt
-    fistp intgr
-  };
-#else
-  intgr = static_cast<int>(flt + 0.5);
-  if ((intgr & 1) != 0 && intgr - flt == 0.5) {
-    // If the number is halfway between two integers, round to the even one.
-    intgr--;
-  }
-#endif
-  return intgr;
-}
-#endif  // _MSC_VER < 1800
-
-#endif  // V8_LIBC_MSVCRT
-
 namespace v8 {
 namespace base {
 
@@ -79,7 +41,7 @@
 
 #ifndef V8_NO_FAST_TLS
 
-#if defined(_MSC_VER) && (V8_HOST_ARCH_IA32)
+#if V8_CC_MSVC && V8_HOST_ARCH_IA32
 
 #define V8_FAST_TLS_SUPPORTED 1
 
diff --git a/src/base/platform/time.cc b/src/base/platform/time.cc
index d47ccaf..40dd188 100644
--- a/src/base/platform/time.cc
+++ b/src/base/platform/time.cc
@@ -401,7 +401,7 @@
   }
   virtual ~HighResolutionTickClock() {}
 
-  virtual int64_t Now() OVERRIDE {
+  int64_t Now() OVERRIDE {
     LARGE_INTEGER now;
     BOOL result = QueryPerformanceCounter(&now);
     DCHECK(result);
@@ -419,9 +419,7 @@
     return ticks + 1;
   }
 
-  virtual bool IsHighResolution() OVERRIDE {
-    return true;
-  }
+  bool IsHighResolution() OVERRIDE { return true; }
 
  private:
   int64_t ticks_per_second_;
@@ -435,7 +433,7 @@
   RolloverProtectedTickClock() : last_seen_now_(0), rollover_ms_(1) {}
   virtual ~RolloverProtectedTickClock() {}
 
-  virtual int64_t Now() OVERRIDE {
+  int64_t Now() OVERRIDE {
     LockGuard<Mutex> lock_guard(&mutex_);
     // We use timeGetTime() to implement TimeTicks::Now(), which rolls over
     // every ~49.7 days. We try to track rollover ourselves, which works if
@@ -454,9 +452,7 @@
     return (now + rollover_ms_) * Time::kMicrosecondsPerMillisecond;
   }
 
-  virtual bool IsHighResolution() OVERRIDE {
-    return false;
-  }
+  bool IsHighResolution() OVERRIDE { return false; }
 
  private:
   Mutex mutex_;
diff --git a/src/base/sys-info.cc b/src/base/sys-info.cc
index 06c4f24..c665771 100644
--- a/src/base/sys-info.cc
+++ b/src/base/sys-info.cc
@@ -34,14 +34,12 @@
   int ncpu = 0;
   size_t len = sizeof(ncpu);
   if (sysctl(mib, arraysize(mib), &ncpu, &len, NULL, 0) != 0) {
-    UNREACHABLE();
     return 1;
   }
   return ncpu;
 #elif V8_OS_POSIX
   long result = sysconf(_SC_NPROCESSORS_ONLN);  // NOLINT(runtime/int)
   if (result == -1) {
-    UNREACHABLE();
     return 1;
   }
   return static_cast<int>(result);
@@ -60,7 +58,6 @@
   int64_t memsize = 0;
   size_t len = sizeof(memsize);
   if (sysctl(mib, arraysize(mib), &memsize, &len, NULL, 0) != 0) {
-    UNREACHABLE();
     return 0;
   }
   return memsize;
@@ -70,7 +67,6 @@
   sysctlbyname("vm.stats.vm.v_page_count", &pages, &size, NULL, 0);
   sysctlbyname("vm.stats.vm.v_page_size", &page_size, &size, NULL, 0);
   if (pages == -1 || page_size == -1) {
-    UNREACHABLE();
     return 0;
   }
   return static_cast<int64_t>(pages) * page_size;
@@ -78,7 +74,6 @@
   MEMORYSTATUSEX memory_info;
   memory_info.dwLength = sizeof(memory_info);
   if (!GlobalMemoryStatusEx(&memory_info)) {
-    UNREACHABLE();
     return 0;
   }
   int64_t result = static_cast<int64_t>(memory_info.ullTotalPhys);
@@ -87,7 +82,6 @@
 #elif V8_OS_QNX
   struct stat stat_buf;
   if (stat("/proc", &stat_buf) != 0) {
-    UNREACHABLE();
     return 0;
   }
   return static_cast<int64_t>(stat_buf.st_size);
@@ -98,7 +92,6 @@
   long pages = sysconf(_SC_PHYS_PAGES);    // NOLINT(runtime/int)
   long page_size = sysconf(_SC_PAGESIZE);  // NOLINT(runtime/int)
   if (pages == -1 || page_size == -1) {
-    UNREACHABLE();
     return 0;
   }
   return static_cast<int64_t>(pages) * page_size;
@@ -114,7 +107,6 @@
   struct rlimit rlim;
   int result = getrlimit(RLIMIT_DATA, &rlim);
   if (result != 0) {
-    UNREACHABLE();
     return 0;
   }
   return (rlim.rlim_cur == RLIM_INFINITY) ? 0 : rlim.rlim_cur;
diff --git a/src/base/sys-info.h b/src/base/sys-info.h
index d1658fc..377deb0 100644
--- a/src/base/sys-info.h
+++ b/src/base/sys-info.h
@@ -5,7 +5,7 @@
 #ifndef V8_BASE_SYS_INFO_H_
 #define V8_BASE_SYS_INFO_H_
 
-#include "include/v8stdint.h"
+#include <stdint.h>
 #include "src/base/compiler-specific.h"
 
 namespace v8 {
diff --git a/src/base/utils/random-number-generator.cc b/src/base/utils/random-number-generator.cc
index 9454936..29a48ff 100644
--- a/src/base/utils/random-number-generator.cc
+++ b/src/base/utils/random-number-generator.cc
@@ -79,7 +79,7 @@
 
 
 int RandomNumberGenerator::NextInt(int max) {
-  DCHECK_LE(0, max);
+  DCHECK_LT(0, max);
 
   // Fast path if max is a power of 2.
   if (IS_POWER_OF_TWO(max)) {
@@ -102,6 +102,13 @@
 }
 
 
+int64_t RandomNumberGenerator::NextInt64() {
+  uint64_t lo = bit_cast<unsigned>(Next(32));
+  uint64_t hi = bit_cast<unsigned>(Next(32));
+  return lo | (hi << 32);
+}
+
+
 void RandomNumberGenerator::NextBytes(void* buffer, size_t buflen) {
   for (size_t n = 0; n < buflen; ++n) {
     static_cast<uint8_t*>(buffer)[n] = static_cast<uint8_t>(Next(8));
diff --git a/src/base/utils/random-number-generator.h b/src/base/utils/random-number-generator.h
index 479423d..d1294f2 100644
--- a/src/base/utils/random-number-generator.h
+++ b/src/base/utils/random-number-generator.h
@@ -68,6 +68,13 @@
   // (exclusive), is pseudorandomly generated and returned.
   double NextDouble() WARN_UNUSED_RESULT;
 
+  // Returns the next pseudorandom, uniformly distributed int64 value from this
+  // random number generator's sequence. The general contract of |NextInt64()|
+  // is that one 64-bit int value is pseudorandomly generated and returned.
+  // All 2^64 possible integer values are produced with (approximately) equal
+  // probability.
+  int64_t NextInt64() WARN_UNUSED_RESULT;
+
   // Fills the elements of a specified array of bytes with random numbers.
   void NextBytes(void* buffer, size_t buflen);
 
diff --git a/src/base/win32-math.cc b/src/base/win32-math.cc
deleted file mode 100644
index d6fc78b..0000000
--- a/src/base/win32-math.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Extra POSIX/ANSI routines for Win32 when using Visual Studio C++. Please
-// refer to The Open Group Base Specification for specification of the correct
-// semantics for these functions.
-// (http://www.opengroup.org/onlinepubs/000095399/)
-#if defined(_MSC_VER) && (_MSC_VER < 1800)
-
-#include "src/base/win32-headers.h"
-#include <float.h>         // Required for DBL_MAX and on Win32 for finite()
-#include <limits.h>        // Required for INT_MAX etc.
-#include <cmath>
-#include "src/base/win32-math.h"
-
-#include "src/base/logging.h"
-
-
-namespace std {
-
-// Test for a NaN (not a number) value - usually defined in math.h
-int isnan(double x) {
-  return _isnan(x);
-}
-
-
-// Test for infinity - usually defined in math.h
-int isinf(double x) {
-  return (_fpclass(x) & (_FPCLASS_PINF | _FPCLASS_NINF)) != 0;
-}
-
-
-// Test for finite value - usually defined in math.h
-int isfinite(double x) {
-  return _finite(x);
-}
-
-
-// Test if x is less than y and both nominal - usually defined in math.h
-int isless(double x, double y) {
-  return isnan(x) || isnan(y) ? 0 : x < y;
-}
-
-
-// Test if x is greater than y and both nominal - usually defined in math.h
-int isgreater(double x, double y) {
-  return isnan(x) || isnan(y) ? 0 : x > y;
-}
-
-
-// Classify floating point number - usually defined in math.h
-int fpclassify(double x) {
-  // Use the MS-specific _fpclass() for classification.
-  int flags = _fpclass(x);
-
-  // Determine class. We cannot use a switch statement because
-  // the _FPCLASS_ constants are defined as flags.
-  if (flags & (_FPCLASS_PN | _FPCLASS_NN)) return FP_NORMAL;
-  if (flags & (_FPCLASS_PZ | _FPCLASS_NZ)) return FP_ZERO;
-  if (flags & (_FPCLASS_PD | _FPCLASS_ND)) return FP_SUBNORMAL;
-  if (flags & (_FPCLASS_PINF | _FPCLASS_NINF)) return FP_INFINITE;
-
-  // All cases should be covered by the code above.
-  DCHECK(flags & (_FPCLASS_SNAN | _FPCLASS_QNAN));
-  return FP_NAN;
-}
-
-
-// Test sign - usually defined in math.h
-int signbit(double x) {
-  // We need to take care of the special case of both positive
-  // and negative versions of zero.
-  if (x == 0)
-    return _fpclass(x) & _FPCLASS_NZ;
-  else
-    return x < 0;
-}
-
-}  // namespace std
-
-#endif  // _MSC_VER
diff --git a/src/base/win32-math.h b/src/base/win32-math.h
deleted file mode 100644
index e1c0350..0000000
--- a/src/base/win32-math.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Extra POSIX/ANSI routines for Win32 when using Visual Studio C++. Please
-// refer to The Open Group Base Specification for specification of the correct
-// semantics for these functions.
-// (http://www.opengroup.org/onlinepubs/000095399/)
-
-#ifndef V8_BASE_WIN32_MATH_H_
-#define V8_BASE_WIN32_MATH_H_
-
-#ifndef _MSC_VER
-#error Wrong environment, expected MSVC.
-#endif  // _MSC_VER
-
-// MSVC 2013+ provides implementations of all standard math functions.
-#if (_MSC_VER < 1800)
-enum {
-  FP_NAN,
-  FP_INFINITE,
-  FP_ZERO,
-  FP_SUBNORMAL,
-  FP_NORMAL
-};
-
-
-namespace std {
-
-int isfinite(double x);
-int isinf(double x);
-int isnan(double x);
-int isless(double x, double y);
-int isgreater(double x, double y);
-int fpclassify(double x);
-int signbit(double x);
-
-}  // namespace std
-
-#endif  // _MSC_VER < 1800
-
-#endif  // V8_BASE_WIN32_MATH_H_
diff --git a/src/basic-block-profiler.cc b/src/basic-block-profiler.cc
new file mode 100644
index 0000000..deb1a53
--- /dev/null
+++ b/src/basic-block-profiler.cc
@@ -0,0 +1,114 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/basic-block-profiler.h"
+
+#include <sstream>
+
+namespace v8 {
+namespace internal {
+
+BasicBlockProfiler::Data::Data(size_t n_blocks)
+    : n_blocks_(n_blocks), block_ids_(n_blocks_), counts_(n_blocks_, 0) {}
+
+
+BasicBlockProfiler::Data::~Data() {}
+
+
+static void InsertIntoString(std::ostringstream* os, std::string* string) {
+  string->insert(0, os->str());
+}
+
+
+void BasicBlockProfiler::Data::SetCode(std::ostringstream* os) {
+  InsertIntoString(os, &code_);
+}
+
+
+void BasicBlockProfiler::Data::SetFunctionName(std::ostringstream* os) {
+  InsertIntoString(os, &function_name_);
+}
+
+
+void BasicBlockProfiler::Data::SetSchedule(std::ostringstream* os) {
+  InsertIntoString(os, &schedule_);
+}
+
+
+void BasicBlockProfiler::Data::SetBlockId(size_t offset, size_t block_id) {
+  DCHECK(offset < n_blocks_);
+  block_ids_[offset] = block_id;
+}
+
+
+uint32_t* BasicBlockProfiler::Data::GetCounterAddress(size_t offset) {
+  DCHECK(offset < n_blocks_);
+  return &counts_[offset];
+}
+
+
+void BasicBlockProfiler::Data::ResetCounts() {
+  for (size_t i = 0; i < n_blocks_; ++i) {
+    counts_[i] = 0;
+  }
+}
+
+
+BasicBlockProfiler::BasicBlockProfiler() {}
+
+
+BasicBlockProfiler::Data* BasicBlockProfiler::NewData(size_t n_blocks) {
+  Data* data = new Data(n_blocks);
+  data_list_.push_back(data);
+  return data;
+}
+
+
+BasicBlockProfiler::~BasicBlockProfiler() {
+  for (DataList::iterator i = data_list_.begin(); i != data_list_.end(); ++i) {
+    delete (*i);
+  }
+}
+
+
+void BasicBlockProfiler::ResetCounts() {
+  for (DataList::iterator i = data_list_.begin(); i != data_list_.end(); ++i) {
+    (*i)->ResetCounts();
+  }
+}
+
+
+std::ostream& operator<<(std::ostream& os, const BasicBlockProfiler& p) {
+  os << "---- Start Profiling Data ----" << std::endl;
+  typedef BasicBlockProfiler::DataList::const_iterator iterator;
+  for (iterator i = p.data_list_.begin(); i != p.data_list_.end(); ++i) {
+    os << **i;
+  }
+  os << "---- End Profiling Data ----" << std::endl;
+  return os;
+}
+
+
+std::ostream& operator<<(std::ostream& os, const BasicBlockProfiler::Data& d) {
+  const char* name = "unknown function";
+  if (!d.function_name_.empty()) {
+    name = d.function_name_.c_str();
+  }
+  if (!d.schedule_.empty()) {
+    os << "schedule for " << name << std::endl;
+    os << d.schedule_.c_str() << std::endl;
+  }
+  os << "block counts for " << name << ":" << std::endl;
+  for (size_t i = 0; i < d.n_blocks_; ++i) {
+    os << "block " << d.block_ids_[i] << " : " << d.counts_[i] << std::endl;
+  }
+  os << std::endl;
+  if (!d.code_.empty()) {
+    os << d.code_.c_str() << std::endl;
+  }
+  return os;
+}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/basic-block-profiler.h b/src/basic-block-profiler.h
new file mode 100644
index 0000000..99fa3b1
--- /dev/null
+++ b/src/basic-block-profiler.h
@@ -0,0 +1,77 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_BASIC_BLOCK_PROFILER_H_
+#define V8_BASIC_BLOCK_PROFILER_H_
+
+#include <iosfwd>
+#include <list>
+#include <string>
+
+#include "src/v8.h"
+
+namespace v8 {
+namespace internal {
+
+class Schedule;
+class Graph;
+
+class BasicBlockProfiler {
+ public:
+  class Data {
+   public:
+    size_t n_blocks() const { return n_blocks_; }
+    const uint32_t* counts() const { return &counts_[0]; }
+
+    void SetCode(std::ostringstream* os);
+    void SetFunctionName(std::ostringstream* os);
+    void SetSchedule(std::ostringstream* os);
+    void SetBlockId(size_t offset, size_t block_id);
+    uint32_t* GetCounterAddress(size_t offset);
+
+   private:
+    friend class BasicBlockProfiler;
+    friend std::ostream& operator<<(std::ostream& os,
+                                    const BasicBlockProfiler::Data& s);
+
+    explicit Data(size_t n_blocks);
+    ~Data();
+
+    void ResetCounts();
+
+    const size_t n_blocks_;
+    std::vector<size_t> block_ids_;
+    std::vector<uint32_t> counts_;
+    std::string function_name_;
+    std::string schedule_;
+    std::string code_;
+    DISALLOW_COPY_AND_ASSIGN(Data);
+  };
+
+  typedef std::list<Data*> DataList;
+
+  BasicBlockProfiler();
+  ~BasicBlockProfiler();
+
+  Data* NewData(size_t n_blocks);
+  void ResetCounts();
+
+  const DataList* data_list() { return &data_list_; }
+
+ private:
+  friend std::ostream& operator<<(std::ostream& os,
+                                  const BasicBlockProfiler& s);
+
+  DataList data_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(BasicBlockProfiler);
+};
+
+std::ostream& operator<<(std::ostream& os, const BasicBlockProfiler& s);
+std::ostream& operator<<(std::ostream& os, const BasicBlockProfiler::Data& s);
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_BASIC_BLOCK_PROFILER_H_
diff --git a/src/bignum-dtoa.cc b/src/bignum-dtoa.cc
index 53bf418..f9a0c95 100644
--- a/src/bignum-dtoa.cc
+++ b/src/bignum-dtoa.cc
@@ -4,7 +4,6 @@
 
 #include <cmath>
 
-#include "include/v8stdint.h"
 #include "src/base/logging.h"
 #include "src/utils.h"
 
diff --git a/src/bit-vector.cc b/src/bit-vector.cc
new file mode 100644
index 0000000..198b242
--- /dev/null
+++ b/src/bit-vector.cc
@@ -0,0 +1,58 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/bit-vector.h"
+
+#include "src/base/bits.h"
+#include "src/scopes.h"
+
+namespace v8 {
+namespace internal {
+
+#ifdef DEBUG
+void BitVector::Print() {
+  bool first = true;
+  PrintF("{");
+  for (int i = 0; i < length(); i++) {
+    if (Contains(i)) {
+      if (!first) PrintF(",");
+      first = false;
+      PrintF("%d", i);
+    }
+  }
+  PrintF("}");
+}
+#endif
+
+
+void BitVector::Iterator::Advance() {
+  current_++;
+  uintptr_t val = current_value_;
+  while (val == 0) {
+    current_index_++;
+    if (Done()) return;
+    val = target_->data_[current_index_];
+    current_ = current_index_ << kDataBitShift;
+  }
+  val = SkipZeroBytes(val);
+  val = SkipZeroBits(val);
+  current_value_ = val >> 1;
+}
+
+
+int BitVector::Count() const {
+  int count = 0;
+  for (int i = 0; i < data_length_; i++) {
+    uintptr_t data = data_[i];
+    if (sizeof(data) == 8) {
+      count += base::bits::CountPopulation64(data);
+    } else {
+      count += base::bits::CountPopulation32(static_cast<uint32_t>(data));
+    }
+  }
+  return count;
+}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/bit-vector.h b/src/bit-vector.h
new file mode 100644
index 0000000..9fc747d
--- /dev/null
+++ b/src/bit-vector.h
@@ -0,0 +1,253 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_DATAFLOW_H_
+#define V8_DATAFLOW_H_
+
+#include "src/v8.h"
+
+#include "src/allocation.h"
+#include "src/ast.h"
+#include "src/compiler.h"
+#include "src/zone-inl.h"
+
+namespace v8 {
+namespace internal {
+
+class BitVector : public ZoneObject {
+ public:
+  // Iterator for the elements of this BitVector.
+  class Iterator BASE_EMBEDDED {
+   public:
+    explicit Iterator(BitVector* target)
+        : target_(target),
+          current_index_(0),
+          current_value_(target->data_[0]),
+          current_(-1) {
+      DCHECK(target->data_length_ > 0);
+      Advance();
+    }
+    ~Iterator() {}
+
+    bool Done() const { return current_index_ >= target_->data_length_; }
+    void Advance();
+
+    int Current() const {
+      DCHECK(!Done());
+      return current_;
+    }
+
+   private:
+    uintptr_t SkipZeroBytes(uintptr_t val) {
+      while ((val & 0xFF) == 0) {
+        val >>= 8;
+        current_ += 8;
+      }
+      return val;
+    }
+    uintptr_t SkipZeroBits(uintptr_t val) {
+      while ((val & 0x1) == 0) {
+        val >>= 1;
+        current_++;
+      }
+      return val;
+    }
+
+    BitVector* target_;
+    int current_index_;
+    uintptr_t current_value_;
+    int current_;
+
+    friend class BitVector;
+  };
+
+  static const int kDataBits = kPointerSize * 8;
+  static const int kDataBitShift = kPointerSize == 8 ? 6 : 5;
+  static const uintptr_t kOne = 1;  // This saves some static_casts.
+
+  BitVector(int length, Zone* zone)
+      : length_(length),
+        data_length_(SizeFor(length)),
+        data_(zone->NewArray<uintptr_t>(data_length_)) {
+    DCHECK(length > 0);
+    Clear();
+  }
+
+  BitVector(const BitVector& other, Zone* zone)
+      : length_(other.length()),
+        data_length_(SizeFor(length_)),
+        data_(zone->NewArray<uintptr_t>(data_length_)) {
+    CopyFrom(other);
+  }
+
+  static int SizeFor(int length) { return 1 + ((length - 1) / kDataBits); }
+
+  void CopyFrom(const BitVector& other) {
+    DCHECK(other.length() <= length());
+    for (int i = 0; i < other.data_length_; i++) {
+      data_[i] = other.data_[i];
+    }
+    for (int i = other.data_length_; i < data_length_; i++) {
+      data_[i] = 0;
+    }
+  }
+
+  bool Contains(int i) const {
+    DCHECK(i >= 0 && i < length());
+    uintptr_t block = data_[i / kDataBits];
+    return (block & (kOne << (i % kDataBits))) != 0;
+  }
+
+  void Add(int i) {
+    DCHECK(i >= 0 && i < length());
+    data_[i / kDataBits] |= (kOne << (i % kDataBits));
+  }
+
+  void Remove(int i) {
+    DCHECK(i >= 0 && i < length());
+    data_[i / kDataBits] &= ~(kOne << (i % kDataBits));
+  }
+
+  void Union(const BitVector& other) {
+    DCHECK(other.length() == length());
+    for (int i = 0; i < data_length_; i++) {
+      data_[i] |= other.data_[i];
+    }
+  }
+
+  bool UnionIsChanged(const BitVector& other) {
+    DCHECK(other.length() == length());
+    bool changed = false;
+    for (int i = 0; i < data_length_; i++) {
+      uintptr_t old_data = data_[i];
+      data_[i] |= other.data_[i];
+      if (data_[i] != old_data) changed = true;
+    }
+    return changed;
+  }
+
+  void Intersect(const BitVector& other) {
+    DCHECK(other.length() == length());
+    for (int i = 0; i < data_length_; i++) {
+      data_[i] &= other.data_[i];
+    }
+  }
+
+  bool IntersectIsChanged(const BitVector& other) {
+    DCHECK(other.length() == length());
+    bool changed = false;
+    for (int i = 0; i < data_length_; i++) {
+      uintptr_t old_data = data_[i];
+      data_[i] &= other.data_[i];
+      if (data_[i] != old_data) changed = true;
+    }
+    return changed;
+  }
+
+  void Subtract(const BitVector& other) {
+    DCHECK(other.length() == length());
+    for (int i = 0; i < data_length_; i++) {
+      data_[i] &= ~other.data_[i];
+    }
+  }
+
+  void Clear() {
+    for (int i = 0; i < data_length_; i++) {
+      data_[i] = 0;
+    }
+  }
+
+  bool IsEmpty() const {
+    for (int i = 0; i < data_length_; i++) {
+      if (data_[i] != 0) return false;
+    }
+    return true;
+  }
+
+  bool Equals(const BitVector& other) {
+    for (int i = 0; i < data_length_; i++) {
+      if (data_[i] != other.data_[i]) return false;
+    }
+    return true;
+  }
+
+  int Count() const;
+
+  int length() const { return length_; }
+
+#ifdef DEBUG
+  void Print();
+#endif
+
+ private:
+  const int length_;
+  const int data_length_;
+  uintptr_t* const data_;
+
+  DISALLOW_COPY_AND_ASSIGN(BitVector);
+};
+
+
+class GrowableBitVector BASE_EMBEDDED {
+ public:
+  class Iterator BASE_EMBEDDED {
+   public:
+    Iterator(const GrowableBitVector* target, Zone* zone)
+        : it_(target->bits_ == NULL ? new (zone) BitVector(1, zone)
+                                    : target->bits_) {}
+    bool Done() const { return it_.Done(); }
+    void Advance() { it_.Advance(); }
+    int Current() const { return it_.Current(); }
+
+   private:
+    BitVector::Iterator it_;
+  };
+
+  GrowableBitVector() : bits_(NULL) {}
+  GrowableBitVector(int length, Zone* zone)
+      : bits_(new (zone) BitVector(length, zone)) {}
+
+  bool Contains(int value) const {
+    if (!InBitsRange(value)) return false;
+    return bits_->Contains(value);
+  }
+
+  void Add(int value, Zone* zone) {
+    EnsureCapacity(value, zone);
+    bits_->Add(value);
+  }
+
+  void Union(const GrowableBitVector& other, Zone* zone) {
+    for (Iterator it(&other, zone); !it.Done(); it.Advance()) {
+      Add(it.Current(), zone);
+    }
+  }
+
+  void Clear() {
+    if (bits_ != NULL) bits_->Clear();
+  }
+
+ private:
+  static const int kInitialLength = 1024;
+
+  bool InBitsRange(int value) const {
+    return bits_ != NULL && bits_->length() > value;
+  }
+
+  void EnsureCapacity(int value, Zone* zone) {
+    if (InBitsRange(value)) return;
+    int new_length = bits_ == NULL ? kInitialLength : bits_->length();
+    while (new_length <= value) new_length *= 2;
+    BitVector* new_bits = new (zone) BitVector(new_length, zone);
+    if (bits_ != NULL) new_bits->CopyFrom(*bits_);
+    bits_ = new_bits;
+  }
+
+  BitVector* bits_;
+};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_DATAFLOW_H_
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 250562a..7105eb2 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -48,7 +48,7 @@
   Heap* heap = isolate_->heap();
   if (heap->natives_source_cache()->get(index)->IsUndefined()) {
     // We can use external strings for the natives.
-    Vector<const char> source = Natives::GetRawScriptSource(index);
+    Vector<const char> source = Natives::GetScriptSource(index);
     NativesExternalStringResource* resource =
         new NativesExternalStringResource(this,
                                           source.start(),
@@ -57,6 +57,8 @@
     Handle<String> source_code = isolate_->factory()
                                      ->NewExternalStringFromOneByte(resource)
                                      .ToHandleChecked();
+    // Mark this external string with a special map.
+    source_code->set_map(isolate_->heap()->native_source_string_map());
     heap->natives_source_cache()->set(index, *source_code);
   }
   Handle<Object> cached_source(heap->natives_source_cache()->get(index),
@@ -126,7 +128,7 @@
 void Bootstrapper::TearDown() {
   if (delete_these_non_arrays_on_tear_down_ != NULL) {
     int len = delete_these_non_arrays_on_tear_down_->length();
-    DCHECK(len < 28);  // Don't use this mechanism for unbounded allocations.
+    DCHECK(len < 1000);  // Don't use this mechanism for unbounded allocations.
     for (int i = 0; i < len; i++) {
       delete delete_these_non_arrays_on_tear_down_->at(i);
       delete_these_non_arrays_on_tear_down_->at(i) = NULL;
@@ -208,6 +210,16 @@
   // Used for creating a context from scratch.
   void InstallNativeFunctions();
   void InstallExperimentalNativeFunctions();
+
+#define DECLARE_FEATURE_INITIALIZATION(id, descr) \
+  void InstallNativeFunctions_##id();             \
+  void InitializeGlobal_##id();
+
+  HARMONY_INPROGRESS(DECLARE_FEATURE_INITIALIZATION)
+  HARMONY_STAGED(DECLARE_FEATURE_INITIALIZATION)
+  HARMONY_SHIPPING(DECLARE_FEATURE_INITIALIZATION)
+#undef DECLARE_FEATURE_INITIALIZATION
+
   Handle<JSFunction> InstallInternalArray(Handle<JSBuiltinsObject> builtins,
                                           const char* name,
                                           ElementsKind elements_kind);
@@ -349,8 +361,8 @@
 static void SetObjectPrototype(Handle<JSObject> object, Handle<Object> proto) {
   // object.__proto__ = proto;
   Handle<Map> old_map = Handle<Map>(object->map());
-  Handle<Map> new_map = Map::Copy(old_map);
-  new_map->set_prototype(*proto);
+  Handle<Map> new_map = Map::Copy(old_map, "SetObjectPrototype");
+  new_map->SetPrototype(proto, FAST_PROTOTYPE);
   JSObject::MigrateToMap(object, new_map);
 }
 
@@ -481,6 +493,8 @@
 
   Handle<String> object_name = factory->Object_string();
 
+  Handle<JSObject> object_function_prototype;
+
   {  // --- O b j e c t ---
     Handle<JSFunction> object_fun = factory->NewFunction(object_name);
     int unused = JSObject::kInitialGlobalObjectUnusedPropertiesCount;
@@ -495,19 +509,20 @@
     native_context()->set_object_function(*object_fun);
 
     // Allocate a new prototype for the object function.
-    Handle<JSObject> prototype = factory->NewJSObject(
-        isolate->object_function(),
-        TENURED);
-    Handle<Map> map = Map::Copy(handle(prototype->map()));
+    object_function_prototype =
+        factory->NewJSObject(isolate->object_function(), TENURED);
+    Handle<Map> map = Map::Copy(handle(object_function_prototype->map()),
+                                "EmptyObjectPrototype");
     map->set_is_prototype_map(true);
-    prototype->set_map(*map);
+    object_function_prototype->set_map(*map);
 
-    native_context()->set_initial_object_prototype(*prototype);
+    native_context()->set_initial_object_prototype(*object_function_prototype);
     // For bootstrapping set the array prototype to be the same as the object
     // prototype, otherwise the missing initial_array_prototype will cause
     // assertions during startup.
-    native_context()->set_initial_array_prototype(*prototype);
-    Accessors::FunctionSetPrototype(object_fun, prototype);
+    native_context()->set_initial_array_prototype(*object_function_prototype);
+    Accessors::FunctionSetPrototype(object_fun, object_function_prototype)
+        .Assert();
   }
 
   // Allocate the empty function as the prototype for function ECMAScript
@@ -522,8 +537,7 @@
   Handle<Map> empty_function_map =
       CreateFunctionMap(FUNCTION_WITHOUT_PROTOTYPE);
   DCHECK(!empty_function_map->is_dictionary_map());
-  empty_function_map->set_prototype(
-      native_context()->object_function()->prototype());
+  empty_function_map->SetPrototype(object_function_prototype);
   empty_function_map->set_is_prototype_map(true);
   empty_function->set_map(*empty_function_map);
 
@@ -537,10 +551,10 @@
   empty_function->shared()->DontAdaptArguments();
 
   // Set prototypes for the function maps.
-  native_context()->sloppy_function_map()->set_prototype(*empty_function);
-  native_context()->sloppy_function_without_prototype_map()->
-      set_prototype(*empty_function);
-  sloppy_function_map_writable_prototype_->set_prototype(*empty_function);
+  native_context()->sloppy_function_map()->SetPrototype(empty_function);
+  native_context()->sloppy_function_without_prototype_map()->SetPrototype(
+      empty_function);
+  sloppy_function_map_writable_prototype_->SetPrototype(empty_function);
   return empty_function;
 }
 
@@ -642,7 +656,7 @@
   Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
   SetStrictFunctionInstanceDescriptor(map, function_mode);
   map->set_function_with_prototype(IsFunctionModeWithPrototype(function_mode));
-  map->set_prototype(*empty_function);
+  map->SetPrototype(empty_function);
   return map;
 }
 
@@ -851,7 +865,6 @@
                                 Handle<JSGlobalProxy> global_proxy) {
   // Set the native context for the global object.
   global_object->set_native_context(*native_context());
-  global_object->set_global_context(*native_context());
   global_object->set_global_proxy(*global_proxy);
   global_proxy->set_native_context(*native_context());
   native_context()->set_global_proxy(*global_proxy);
@@ -896,6 +909,10 @@
   Factory* factory = isolate->factory();
   Heap* heap = isolate->heap();
 
+  Handle<ScriptContextTable> script_context_table =
+      factory->NewScriptContextTable();
+  native_context()->set_script_context_table(*script_context_table);
+
   Handle<String> object_name = factory->Object_string();
   JSObject::AddProperty(
       global_object, object_name, isolate->object_function(), DONT_ENUM);
@@ -934,7 +951,7 @@
       CallbacksDescriptor d(
           Handle<Name>(Name::cast(array_length->name())),
           array_length, attribs);
-      array_function->initial_map()->AppendDescriptor(&d);
+      initial_map->AppendDescriptor(&d);
     }
 
     // array_function is used internally. JS code creating array object should
@@ -1028,11 +1045,10 @@
 
     {
       // ECMA-262, section 15.10.7.1.
-      FieldDescriptor field(factory->source_string(),
-                            JSRegExp::kSourceFieldIndex,
-                            final,
-                            Representation::Tagged());
-      initial_map->AppendDescriptor(&field);
+      Handle<AccessorInfo> regexp_source(
+          Accessors::RegExpSourceInfo(isolate, final));
+      CallbacksDescriptor d(factory->source_string(), regexp_source, final);
+      initial_map->AppendDescriptor(&d);
     }
     {
       // ECMA-262, section 15.10.7.2.
@@ -1069,19 +1085,17 @@
       initial_map->AppendDescriptor(&field);
     }
 
-    initial_map->set_inobject_properties(5);
-    initial_map->set_pre_allocated_property_fields(5);
+    static const int num_fields = JSRegExp::kInObjectFieldCount;
+    initial_map->set_inobject_properties(num_fields);
+    initial_map->set_pre_allocated_property_fields(num_fields);
     initial_map->set_unused_property_fields(0);
-    initial_map->set_instance_size(
-        initial_map->instance_size() + 5 * kPointerSize);
-    initial_map->set_visitor_id(StaticVisitorBase::GetVisitorId(*initial_map));
+    initial_map->set_instance_size(initial_map->instance_size() +
+                                   num_fields * kPointerSize);
 
     // RegExp prototype object is itself a RegExp.
-    Handle<Map> proto_map = Map::Copy(initial_map);
-    proto_map->set_prototype(native_context()->initial_object_prototype());
+    Handle<Map> proto_map = Map::Copy(initial_map, "RegExpPrototype");
+    DCHECK(proto_map->prototype() == *isolate->initial_object_prototype());
     Handle<JSObject> proto = factory->NewJSObjectFromMap(proto_map);
-    proto->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex,
-                                 heap->query_colon_string());
     proto->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex,
                                  heap->false_value());
     proto->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex,
@@ -1092,7 +1106,7 @@
                                  Smi::FromInt(0),
                                  SKIP_WRITE_BARRIER);  // It's a Smi.
     proto_map->set_is_prototype_map(true);
-    initial_map->set_prototype(*proto);
+    initial_map->SetPrototype(proto);
     factory->SetRegExpIrregexpData(Handle<JSRegExp>::cast(proto),
                                    JSRegExp::IRREGEXP, factory->empty_string(),
                                    JSRegExp::Flags(0), 0);
@@ -1232,7 +1246,8 @@
   }
 
   {  // --- aliased arguments map
-    Handle<Map> map = Map::Copy(isolate->sloppy_arguments_map());
+    Handle<Map> map =
+        Map::Copy(isolate->sloppy_arguments_map(), "AliasedArguments");
     map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS);
     DCHECK_EQ(2, map->pre_allocated_property_fields());
     native_context()->set_aliased_arguments_map(*map);
@@ -1276,7 +1291,9 @@
     // @@iterator method is added later.
 
     map->set_function_with_prototype(true);
-    map->set_prototype(native_context()->object_function()->prototype());
+    DCHECK_EQ(native_context()->object_function()->prototype(),
+              *isolate->initial_object_prototype());
+    map->SetPrototype(isolate->initial_object_prototype());
     map->set_pre_allocated_property_fields(1);
     map->set_inobject_properties(1);
 
@@ -1358,16 +1375,12 @@
 
 
 void Genesis::InitializeExperimentalGlobal() {
-  // TODO(erikcorry): Move this into Genesis::InitializeGlobal once we no
-  // longer need to live behind a flag.
-  Handle<JSObject> builtins(native_context()->builtins());
+#define FEATURE_INITIALIZE_GLOBAL(id, descr) InitializeGlobal_##id();
 
-  Handle<HeapObject> flag(
-      FLAG_harmony_regexps ? heap()->true_value() : heap()->false_value());
-  PropertyAttributes attributes =
-      static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
-  Runtime::DefineObjectProperty(builtins, factory()->harmony_regexps_string(),
-                                flag, attributes).Assert();
+  HARMONY_INPROGRESS(FEATURE_INITIALIZE_GLOBAL)
+  HARMONY_STAGED(FEATURE_INITIALIZE_GLOBAL)
+  HARMONY_SHIPPING(FEATURE_INITIALIZE_GLOBAL)
+#undef FEATURE_INITIALIZE_GLOBAL
 }
 
 
@@ -1384,8 +1397,8 @@
   Factory* factory = isolate->factory();
   Handle<String> source_code;
   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-      isolate, source_code, factory->NewStringFromAscii(
-                                ExperimentalNatives::GetRawScriptSource(index)),
+      isolate, source_code,
+      factory->NewStringFromAscii(ExperimentalNatives::GetScriptSource(index)),
       false);
   return CompileNative(isolate, name, source_code);
 }
@@ -1503,12 +1516,6 @@
           .ToHandleChecked();                                               \
   native_context()->set_##var(Type::cast(*var##_native));
 
-#define INSTALL_NATIVE_MATH(name)                                    \
-  {                                                                  \
-    Handle<Object> fun =                                             \
-        ResolveBuiltinIdHolder(native_context(), "Math." #name);     \
-    native_context()->set_math_##name##_fun(JSFunction::cast(*fun)); \
-  }
 
 void Genesis::InstallNativeFunctions() {
   HandleScope scope(isolate());
@@ -1521,6 +1528,7 @@
   INSTALL_NATIVE(JSFunction, "ToInteger", to_integer_fun);
   INSTALL_NATIVE(JSFunction, "ToUint32", to_uint32_fun);
   INSTALL_NATIVE(JSFunction, "ToInt32", to_int32_fun);
+  INSTALL_NATIVE(JSFunction, "ToLength", to_length_fun);
 
   INSTALL_NATIVE(JSFunction, "GlobalEval", global_eval_fun);
   INSTALL_NATIVE(JSFunction, "Instantiate", instantiate_fun);
@@ -1551,30 +1559,7 @@
                  native_object_get_notifier);
   INSTALL_NATIVE(JSFunction, "NativeObjectNotifierPerformChange",
                  native_object_notifier_perform_change);
-
-  INSTALL_NATIVE(Symbol, "symbolIterator", iterator_symbol);
-  INSTALL_NATIVE(Symbol, "symbolUnscopables", unscopables_symbol);
   INSTALL_NATIVE(JSFunction, "ArrayValues", array_values_iterator);
-
-  INSTALL_NATIVE_MATH(abs)
-  INSTALL_NATIVE_MATH(acos)
-  INSTALL_NATIVE_MATH(asin)
-  INSTALL_NATIVE_MATH(atan)
-  INSTALL_NATIVE_MATH(atan2)
-  INSTALL_NATIVE_MATH(ceil)
-  INSTALL_NATIVE_MATH(cos)
-  INSTALL_NATIVE_MATH(exp)
-  INSTALL_NATIVE_MATH(floor)
-  INSTALL_NATIVE_MATH(imul)
-  INSTALL_NATIVE_MATH(log)
-  INSTALL_NATIVE_MATH(max)
-  INSTALL_NATIVE_MATH(min)
-  INSTALL_NATIVE_MATH(pow)
-  INSTALL_NATIVE_MATH(random)
-  INSTALL_NATIVE_MATH(round)
-  INSTALL_NATIVE_MATH(sin)
-  INSTALL_NATIVE_MATH(sqrt)
-  INSTALL_NATIVE_MATH(tan)
 }
 
 
@@ -1585,10 +1570,74 @@
     INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap);
     INSTALL_NATIVE(JSFunction, "ProxyEnumerate", proxy_enumerate);
   }
+
+#define INSTALL_NATIVE_FUNCTIONS_FOR(id, descr) InstallNativeFunctions_##id();
+  HARMONY_INPROGRESS(INSTALL_NATIVE_FUNCTIONS_FOR)
+  HARMONY_STAGED(INSTALL_NATIVE_FUNCTIONS_FOR)
+  HARMONY_SHIPPING(INSTALL_NATIVE_FUNCTIONS_FOR)
+#undef INSTALL_NATIVE_FUNCTIONS_FOR
+}
+
+
+#define EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(id) \
+  void Genesis::InstallNativeFunctions_##id() {}
+
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_scoping)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_modules)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_strings)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_arrays)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_array_includes)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_classes)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_object_literals)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_regexps)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_arrow_functions)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_numeric_literals)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_tostring)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_templates)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_sloppy)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_unicode)
+
+
+void Genesis::InstallNativeFunctions_harmony_proxies() {
+  if (FLAG_harmony_proxies) {
+    INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap);
+    INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap);
+    INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap);
+    INSTALL_NATIVE(JSFunction, "ProxyEnumerate", proxy_enumerate);
+  }
 }
 
 #undef INSTALL_NATIVE
 
+#define EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(id) \
+  void Genesis::InitializeGlobal_##id() {}
+
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_scoping)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_modules)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_strings)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_arrays)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_array_includes)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_classes)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_object_literals)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_arrow_functions)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_numeric_literals)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_tostring)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_proxies)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_templates)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_sloppy)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_unicode)
+
+void Genesis::InitializeGlobal_harmony_regexps() {
+  Handle<JSObject> builtins(native_context()->builtins());
+
+  Handle<HeapObject> flag(FLAG_harmony_regexps ? heap()->true_value()
+                                               : heap()->false_value());
+  PropertyAttributes attributes =
+      static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
+  Runtime::DefineObjectProperty(builtins, factory()->harmony_regexps_string(),
+                                flag, attributes).Assert();
+}
+
 
 Handle<JSFunction> Genesis::InstallInternalArray(
     Handle<JSBuiltinsObject> builtins,
@@ -1612,7 +1661,7 @@
   array_function->shared()->DontAdaptArguments();
 
   Handle<Map> original_map(array_function->initial_map());
-  Handle<Map> initial_map = Map::Copy(original_map);
+  Handle<Map> initial_map = Map::Copy(original_map, "InternalArray");
   initial_map->set_elements_kind(elements_kind);
   JSFunction::SetInitialMap(array_function, initial_map, prototype);
 
@@ -1627,7 +1676,7 @@
   {  // Add length.
     CallbacksDescriptor d(
         Handle<Name>(Name::cast(array_length->name())), array_length, attribs);
-    array_function->initial_map()->AppendDescriptor(&d);
+    initial_map->AppendDescriptor(&d);
   }
 
   return array_function;
@@ -1657,7 +1706,6 @@
       Handle<JSBuiltinsObject>::cast(factory()->NewGlobalObject(builtins_fun));
   builtins->set_builtins(*builtins);
   builtins->set_native_context(*native_context());
-  builtins->set_global_context(*native_context());
   builtins->set_global_proxy(native_context()->global_proxy());
 
 
@@ -1697,7 +1745,7 @@
         isolate()->initial_object_prototype(), Builtins::kIllegal);
     Handle<JSObject> prototype =
         factory()->NewJSObject(isolate()->object_function(), TENURED);
-    Accessors::FunctionSetPrototype(script_fun, prototype);
+    Accessors::FunctionSetPrototype(script_fun, prototype).Assert();
     native_context()->set_script_function(*script_fun);
 
     Handle<Map> script_map = Handle<Map>(script_fun->initial_map());
@@ -1839,7 +1887,7 @@
         isolate()->initial_object_prototype(), Builtins::kIllegal);
     Handle<JSObject> prototype =
         factory()->NewJSObject(isolate()->object_function(), TENURED);
-    Accessors::FunctionSetPrototype(opaque_reference_fun, prototype);
+    Accessors::FunctionSetPrototype(opaque_reference_fun, prototype).Assert();
     native_context()->set_opaque_reference_function(*opaque_reference_fun);
   }
 
@@ -1890,8 +1938,8 @@
     // Create maps for generator functions and their prototypes.  Store those
     // maps in the native context.
     Handle<Map> generator_function_map =
-        Map::Copy(sloppy_function_map_writable_prototype_);
-    generator_function_map->set_prototype(*generator_function_prototype);
+        Map::Copy(sloppy_function_map_writable_prototype_, "GeneratorFunction");
+    generator_function_map->SetPrototype(generator_function_prototype);
     native_context()->set_sloppy_generator_function_map(
         *generator_function_map);
 
@@ -1921,15 +1969,16 @@
                      rw_attribs, poison_pair);
 
     Handle<Map> strict_function_map(native_context()->strict_function_map());
-    Handle<Map> strict_generator_function_map = Map::Copy(strict_function_map);
+    Handle<Map> strict_generator_function_map =
+        Map::Copy(strict_function_map, "StrictGeneratorFunction");
     // "arguments" and "caller" already poisoned.
-    strict_generator_function_map->set_prototype(*generator_function_prototype);
+    strict_generator_function_map->SetPrototype(generator_function_prototype);
     native_context()->set_strict_generator_function_map(
         *strict_generator_function_map);
 
     Handle<JSFunction> object_function(native_context()->object_function());
     Handle<Map> generator_object_prototype_map = Map::Create(isolate(), 0);
-    generator_object_prototype_map->set_prototype(*generator_object_prototype);
+    generator_object_prototype_map->SetPrototype(generator_object_prototype);
     native_context()->set_generator_object_prototype_map(
         *generator_object_prototype_map);
   }
@@ -1939,6 +1988,17 @@
     return true;
   }
 
+  // Install public symbols.
+  {
+    static const PropertyAttributes attributes =
+        static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
+#define INSTALL_PUBLIC_SYMBOL(name, varname, description)                 \
+  Handle<String> varname = factory()->NewStringFromStaticChars(#varname); \
+  JSObject::AddProperty(builtins, varname, factory()->name(), attributes);
+    PUBLIC_SYMBOL_LIST(INSTALL_PUBLIC_SYMBOL)
+#undef INSTALL_PUBLIC_SYMBOL
+  }
+
   // Install natives.
   for (int i = Natives::GetDebuggerCount();
        i < Natives::GetBuiltinsCount();
@@ -1979,8 +2039,10 @@
     if (FLAG_vector_ics) {
       // Apply embeds an IC, so we need a type vector of size 1 in the shared
       // function info.
+      FeedbackVectorSpec spec(0, 1);
+      spec.SetKind(0, Code::CALL_IC);
       Handle<TypeFeedbackVector> feedback_vector =
-          factory()->NewTypeFeedbackVector(1);
+          factory()->NewTypeFeedbackVector(spec);
       apply->shared()->set_feedback_vector(*feedback_vector);
     }
 
@@ -2017,7 +2079,7 @@
 
     // Set prototype on map.
     initial_map->set_non_instance_prototype(false);
-    initial_map->set_prototype(*array_prototype);
+    initial_map->SetPrototype(array_prototype);
 
     // Update map with length accessor from Array and add "index" and "input".
     Map::EnsureDescriptorSlack(initial_map, 3);
@@ -2065,22 +2127,22 @@
     Handle<AccessorInfo> arguments_iterator =
         Accessors::ArgumentsIteratorInfo(isolate(), attribs);
     {
-      CallbacksDescriptor d(Handle<Name>(native_context()->iterator_symbol()),
-                            arguments_iterator, attribs);
+      CallbacksDescriptor d(factory()->iterator_symbol(), arguments_iterator,
+                            attribs);
       Handle<Map> map(native_context()->sloppy_arguments_map());
       Map::EnsureDescriptorSlack(map, 1);
       map->AppendDescriptor(&d);
     }
     {
-      CallbacksDescriptor d(Handle<Name>(native_context()->iterator_symbol()),
-                            arguments_iterator, attribs);
+      CallbacksDescriptor d(factory()->iterator_symbol(), arguments_iterator,
+                            attribs);
       Handle<Map> map(native_context()->aliased_arguments_map());
       Map::EnsureDescriptorSlack(map, 1);
       map->AppendDescriptor(&d);
     }
     {
-      CallbacksDescriptor d(Handle<Name>(native_context()->iterator_symbol()),
-                            arguments_iterator, attribs);
+      CallbacksDescriptor d(factory()->iterator_symbol(), arguments_iterator,
+                            attribs);
       Handle<Map> map(native_context()->strict_arguments_map());
       Map::EnsureDescriptorSlack(map, 1);
       map->AppendDescriptor(&d);
@@ -2095,22 +2157,46 @@
 }
 
 
-#define INSTALL_EXPERIMENTAL_NATIVE(i, flag, file)                \
-  if (FLAG_harmony_##flag &&                                      \
-      strcmp(ExperimentalNatives::GetScriptName(i).start(),       \
-          "native " file) == 0) {                                 \
-    if (!CompileExperimentalBuiltin(isolate(), i)) return false;  \
-  }
-
-
 bool Genesis::InstallExperimentalNatives() {
+  static const char* harmony_arrays_natives[] = {
+      "native harmony-array.js", "native harmony-typedarray.js", NULL};
+  static const char* harmony_array_includes_natives[] = {
+      "native harmony-array-includes.js", NULL};
+  static const char* harmony_proxies_natives[] = {"native proxy.js", NULL};
+  static const char* harmony_strings_natives[] = {"native harmony-string.js",
+                                                  NULL};
+  static const char* harmony_classes_natives[] = {"native harmony-classes.js",
+                                                  NULL};
+  static const char* harmony_modules_natives[] = {NULL};
+  static const char* harmony_scoping_natives[] = {NULL};
+  static const char* harmony_object_literals_natives[] = {NULL};
+  static const char* harmony_regexps_natives[] = {
+      "native harmony-regexp.js", NULL};
+  static const char* harmony_arrow_functions_natives[] = {NULL};
+  static const char* harmony_numeric_literals_natives[] = {NULL};
+  static const char* harmony_tostring_natives[] = {"native harmony-tostring.js",
+                                                   NULL};
+  static const char* harmony_templates_natives[] = {
+      "native harmony-templates.js", NULL};
+  static const char* harmony_sloppy_natives[] = {NULL};
+  static const char* harmony_unicode_natives[] = {NULL};
+
   for (int i = ExperimentalNatives::GetDebuggerCount();
-       i < ExperimentalNatives::GetBuiltinsCount();
-       i++) {
-    INSTALL_EXPERIMENTAL_NATIVE(i, proxies, "proxy.js")
-    INSTALL_EXPERIMENTAL_NATIVE(i, strings, "harmony-string.js")
-    INSTALL_EXPERIMENTAL_NATIVE(i, arrays, "harmony-array.js")
-    INSTALL_EXPERIMENTAL_NATIVE(i, classes, "harmony-classes.js")
+       i < ExperimentalNatives::GetBuiltinsCount(); i++) {
+#define INSTALL_EXPERIMENTAL_NATIVES(id, desc)                                \
+  if (FLAG_##id) {                                                            \
+    for (size_t j = 0; id##_natives[j] != NULL; j++) {                        \
+      Vector<const char> script_name = ExperimentalNatives::GetScriptName(i); \
+      if (strncmp(script_name.start(), id##_natives[j],                       \
+                  script_name.length()) == 0) {                               \
+        if (!CompileExperimentalBuiltin(isolate(), i)) return false;          \
+      }                                                                       \
+    }                                                                         \
+  }
+    HARMONY_INPROGRESS(INSTALL_EXPERIMENTAL_NATIVES);
+    HARMONY_STAGED(INSTALL_EXPERIMENTAL_NATIVES);
+    HARMONY_SHIPPING(INSTALL_EXPERIMENTAL_NATIVES);
+#undef INSTALL_EXPERIMENTAL_NATIVES
   }
 
   InstallExperimentalNativeFunctions();
@@ -2495,6 +2581,8 @@
           JSObject::AddProperty(to, key, constant, details.attributes());
           break;
         }
+        case ACCESSOR_FIELD:
+          UNREACHABLE();
         case CALLBACKS: {
           Handle<Name> key(descs->GetKey(i));
           LookupIterator it(to, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
@@ -2505,15 +2593,10 @@
           DCHECK(!to->HasFastProperties());
           // Add to dictionary.
           Handle<Object> callbacks(descs->GetCallbacksObject(i), isolate());
-          PropertyDetails d = PropertyDetails(
-              details.attributes(), CALLBACKS, i + 1);
+          PropertyDetails d(details.attributes(), CALLBACKS, i + 1);
           JSObject::SetNormalizedProperty(to, key, callbacks, d);
           break;
         }
-        // Do not occur since the from object has fast properties.
-        case NORMAL:
-          UNREACHABLE();
-          break;
       }
     }
   } else {
@@ -2538,6 +2621,7 @@
                                  isolate());
         }
         PropertyDetails details = properties->DetailsAt(i);
+        DCHECK_EQ(DATA, details.kind());
         JSObject::AddProperty(to, key, value, details.attributes());
       }
     }
@@ -2588,20 +2672,24 @@
 class NoTrackDoubleFieldsForSerializerScope {
  public:
   explicit NoTrackDoubleFieldsForSerializerScope(Isolate* isolate)
-      : flag_(FLAG_track_double_fields) {
+      : flag_(FLAG_track_double_fields), enabled_(false) {
     if (isolate->serializer_enabled()) {
       // Disable tracking double fields because heap numbers treated as
       // immutable by the serializer.
       FLAG_track_double_fields = false;
+      enabled_ = true;
     }
   }
 
   ~NoTrackDoubleFieldsForSerializerScope() {
-    FLAG_track_double_fields = flag_;
+    if (enabled_) {
+      FLAG_track_double_fields = flag_;
+    }
   }
 
  private:
   bool flag_;
+  bool enabled_;
 };
 
 
@@ -2635,6 +2723,15 @@
     AddToWeakNativeContextList(*native_context());
     isolate->set_context(*native_context());
     isolate->counters()->contexts_created_by_snapshot()->Increment();
+#if TRACE_MAPS
+    if (FLAG_trace_maps) {
+      Handle<JSFunction> object_fun = isolate->object_function();
+      PrintF("[TraceMap: InitialMap map= %p SFI= %d_Object ]\n",
+             reinterpret_cast<void*>(object_fun->initial_map()),
+             object_fun->shared()->unique_id());
+      Map::TraceAllTransitions(object_fun->initial_map());
+    }
+#endif
     Handle<GlobalObject> global_object;
     Handle<JSGlobalProxy> global_proxy = CreateNewGlobals(
         global_proxy_template, maybe_global_proxy, &global_object);
diff --git a/src/bootstrapper.h b/src/bootstrapper.h
index 0cc8486..9d4f270 100644
--- a/src/bootstrapper.h
+++ b/src/bootstrapper.h
@@ -158,8 +158,8 @@
   NativesExternalStringResource(Bootstrapper* bootstrapper,
                                 const char* source,
                                 size_t length);
-  virtual const char* data() const OVERRIDE { return data_; }
-  virtual size_t length() const OVERRIDE { return length_; }
+  const char* data() const OVERRIDE { return data_; }
+  size_t length() const OVERRIDE { return length_; }
 
  private:
   const char* data_;
diff --git a/src/builtins.cc b/src/builtins.cc
index d0c19e5..b8d0b42 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -182,23 +182,24 @@
 }
 
 
-static bool ArrayPrototypeHasNoElements(Heap* heap,
-                                        Context* native_context,
-                                        JSObject* array_proto) {
+static bool ArrayPrototypeHasNoElements(Heap* heap, PrototypeIterator* iter) {
   DisallowHeapAllocation no_gc;
-  // This method depends on non writability of Object and Array prototype
-  // fields.
-  if (array_proto->elements() != heap->empty_fixed_array()) return false;
-  // Object.prototype
-  PrototypeIterator iter(heap->isolate(), array_proto);
-  if (iter.IsAtEnd()) {
-    return false;
+  for (; !iter->IsAtEnd(); iter->Advance()) {
+    if (iter->GetCurrent()->IsJSProxy()) return false;
+    if (JSObject::cast(iter->GetCurrent())->elements() !=
+        heap->empty_fixed_array()) {
+      return false;
+    }
   }
-  array_proto = JSObject::cast(iter.GetCurrent());
-  if (array_proto != native_context->initial_object_prototype()) return false;
-  if (array_proto->elements() != heap->empty_fixed_array()) return false;
-  iter.Advance();
-  return iter.IsAtEnd();
+  return true;
+}
+
+
+static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
+                                                     JSArray* receiver) {
+  DisallowHeapAllocation no_gc;
+  PrototypeIterator iter(heap->isolate(), receiver);
+  return ArrayPrototypeHasNoElements(heap, &iter);
 }
 
 
@@ -213,13 +214,13 @@
   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
   // If there may be elements accessors in the prototype chain, the fast path
   // cannot be used if there arguments to add to the array.
-  if (args != NULL && array->map()->DictionaryElementsInPrototypeChainOnly()) {
+  Heap* heap = isolate->heap();
+  if (args != NULL && !IsJSArrayFastElementMovingAllowed(heap, *array)) {
     return MaybeHandle<FixedArrayBase>();
   }
   if (array->map()->is_observed()) return MaybeHandle<FixedArrayBase>();
   if (!array->map()->is_extensible()) return MaybeHandle<FixedArrayBase>();
   Handle<FixedArrayBase> elms(array->elements(), isolate);
-  Heap* heap = isolate->heap();
   Map* map = elms->map();
   if (map == heap->fixed_array_map()) {
     if (args == NULL || array->HasFastObjectElements()) return elms;
@@ -264,19 +265,6 @@
 }
 
 
-static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
-                                                     JSArray* receiver) {
-  if (!FLAG_clever_optimizations) return false;
-  DisallowHeapAllocation no_gc;
-  Context* native_context = heap->isolate()->context()->native_context();
-  JSObject* array_proto =
-      JSObject::cast(native_context->array_function()->prototype());
-  PrototypeIterator iter(heap->isolate(), receiver);
-  return iter.GetCurrent() == array_proto &&
-         ArrayPrototypeHasNoElements(heap, native_context, array_proto);
-}
-
-
 MUST_USE_RESULT static Object* CallJsBuiltin(
     Isolate* isolate,
     const char* name,
@@ -431,6 +419,10 @@
   int len = Smi::cast(array->length())->value();
   if (len == 0) return isolate->heap()->undefined_value();
 
+  if (JSArray::HasReadOnlyLength(array)) {
+    return CallJsBuiltin(isolate, "ArrayPop", args);
+  }
+
   ElementsAccessor* accessor = array->GetElementsAccessor();
   int new_length = len - 1;
   Handle<Object> element =
@@ -453,8 +445,7 @@
       EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
   Handle<FixedArrayBase> elms_obj;
   if (!maybe_elms_obj.ToHandle(&elms_obj) ||
-      !IsJSArrayFastElementMovingAllowed(heap,
-                                         *Handle<JSArray>::cast(receiver))) {
+      !IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(*receiver))) {
     return CallJsBuiltin(isolate, "ArrayShift", args);
   }
   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
@@ -463,6 +454,10 @@
   int len = Smi::cast(array->length())->value();
   if (len == 0) return heap->undefined_value();
 
+  if (JSArray::HasReadOnlyLength(array)) {
+    return CallJsBuiltin(isolate, "ArrayShift", args);
+  }
+
   // Get first element
   ElementsAccessor* accessor = array->GetElementsAccessor();
   Handle<Object> first =
@@ -499,11 +494,9 @@
   Heap* heap = isolate->heap();
   Handle<Object> receiver = args.receiver();
   MaybeHandle<FixedArrayBase> maybe_elms_obj =
-      EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
+      EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1);
   Handle<FixedArrayBase> elms_obj;
-  if (!maybe_elms_obj.ToHandle(&elms_obj) ||
-      !IsJSArrayFastElementMovingAllowed(heap,
-                                         *Handle<JSArray>::cast(receiver))) {
+  if (!maybe_elms_obj.ToHandle(&elms_obj)) {
     return CallJsBuiltin(isolate, "ArrayUnshift", args);
   }
   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
@@ -524,9 +517,6 @@
 
   Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
 
-  JSObject::EnsureCanContainElements(array, &args, 1, to_add,
-                                     DONT_ALLOW_DOUBLE_ELEMENTS);
-
   if (new_length > elms->length()) {
     // New backing storage is needed.
     int capacity = new_length + (new_length >> 1) + 16;
@@ -708,9 +698,7 @@
   MaybeHandle<FixedArrayBase> maybe_elms_obj =
       EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3);
   Handle<FixedArrayBase> elms_obj;
-  if (!maybe_elms_obj.ToHandle(&elms_obj) ||
-      !IsJSArrayFastElementMovingAllowed(heap,
-                                         *Handle<JSArray>::cast(receiver))) {
+  if (!maybe_elms_obj.ToHandle(&elms_obj)) {
     return CallJsBuiltin(isolate, "ArraySplice", args);
   }
   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
@@ -775,6 +763,11 @@
     return CallJsBuiltin(isolate, "ArraySplice", args);
   }
 
+  if (new_length != len && JSArray::HasReadOnlyLength(array)) {
+    AllowHeapAllocation allow_allocation;
+    return CallJsBuiltin(isolate, "ArraySplice", args);
+  }
+
   if (new_length == 0) {
     Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(
         elms_obj, elements_kind, actual_delete_count);
@@ -928,9 +921,10 @@
     DisallowHeapAllocation no_gc;
     Heap* heap = isolate->heap();
     Context* native_context = isolate->context()->native_context();
-    JSObject* array_proto =
-        JSObject::cast(native_context->array_function()->prototype());
-    if (!ArrayPrototypeHasNoElements(heap, native_context, array_proto)) {
+    Object* array_proto = native_context->array_function()->prototype();
+    PrototypeIterator iter(isolate, array_proto,
+                           PrototypeIterator::START_AT_RECEIVER);
+    if (!ArrayPrototypeHasNoElements(heap, &iter)) {
       AllowHeapAllocation allow_allocation;
       return CallJsBuiltin(isolate, "ArrayConcatJS", args);
     }
@@ -987,12 +981,12 @@
   Handle<FixedArrayBase> storage(result_array->elements(), isolate);
   ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
   for (int i = 0; i < n_arguments; i++) {
-    // TODO(ishell): It is crucial to keep |array| as a raw pointer to avoid
-    // performance degradation. Revisit this later.
+    // It is crucial to keep |array| in a raw pointer form to avoid performance
+    // degradation.
     JSArray* array = JSArray::cast(args[i]);
     int len = Smi::cast(array->length())->value();
-    ElementsKind from_kind = array->GetElementsKind();
     if (len > 0) {
+      ElementsKind from_kind = array->GetElementsKind();
       accessor->CopyElements(array, 0, from_kind, storage, j, len);
       j += len;
     }
@@ -1279,11 +1273,6 @@
 }
 
 
-static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
-  KeyedLoadIC::GenerateString(masm);
-}
-
-
 static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
   KeyedLoadIC::GeneratePreMonomorphic(masm);
 }
@@ -1314,6 +1303,16 @@
 }
 
 
+static void Generate_KeyedStoreIC_Megamorphic(MacroAssembler* masm) {
+  KeyedStoreIC::GenerateMegamorphic(masm, SLOPPY);
+}
+
+
+static void Generate_KeyedStoreIC_Megamorphic_Strict(MacroAssembler* masm) {
+  KeyedStoreIC::GenerateMegamorphic(masm, STRICT);
+}
+
+
 static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
   KeyedStoreIC::GenerateGeneric(masm, SLOPPY);
 }
@@ -1562,14 +1561,14 @@
       // Move the code into the object heap.
       CodeDesc desc;
       masm.GetCode(&desc);
-      Code::Flags flags =  functions[i].flags;
+      Code::Flags flags = functions[i].flags;
       Handle<Code> code =
           isolate->factory()->NewCode(desc, flags, masm.CodeObject());
       // Log the event and add the code to the builtins array.
       PROFILE(isolate,
               CodeCreateEvent(Logger::BUILTIN_TAG, *code, functions[i].s_name));
       builtins_[i] = *code;
-      if (code->kind() == Code::BUILTIN) code->set_builtin_index(i);
+      code->set_builtin_index(i);
 #ifdef ENABLE_DISASSEMBLER
       if (FLAG_print_builtin_code) {
         CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
diff --git a/src/builtins.h b/src/builtins.h
index c1ed91d..13a4b80 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -88,19 +88,21 @@
   V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC,                 \
     kNoExtraICState)                                                           \
   V(KeyedLoadIC_Generic, KEYED_LOAD_IC, GENERIC, kNoExtraICState)              \
-  V(KeyedLoadIC_String, KEYED_LOAD_IC, MEGAMORPHIC, kNoExtraICState)           \
                                                                                \
   V(StoreIC_Setter_ForDeopt, STORE_IC, MONOMORPHIC, StoreIC::kStrictModeState) \
                                                                                \
   V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED, kNoExtraICState)   \
   V(KeyedStoreIC_PreMonomorphic, KEYED_STORE_IC, PREMONOMORPHIC,               \
     kNoExtraICState)                                                           \
+  V(KeyedStoreIC_Megamorphic, KEYED_STORE_IC, MEGAMORPHIC, kNoExtraICState)    \
   V(KeyedStoreIC_Generic, KEYED_STORE_IC, GENERIC, kNoExtraICState)            \
                                                                                \
   V(KeyedStoreIC_Initialize_Strict, KEYED_STORE_IC, UNINITIALIZED,             \
     StoreIC::kStrictModeState)                                                 \
   V(KeyedStoreIC_PreMonomorphic_Strict, KEYED_STORE_IC, PREMONOMORPHIC,        \
     StoreIC::kStrictModeState)                                                 \
+  V(KeyedStoreIC_Megamorphic_Strict, KEYED_STORE_IC, MEGAMORPHIC,              \
+    StoreIC::kStrictModeState)                                                 \
   V(KeyedStoreIC_Generic_Strict, KEYED_STORE_IC, GENERIC,                      \
     StoreIC::kStrictModeState)                                                 \
   V(KeyedStoreIC_SloppyArguments, KEYED_STORE_IC, MONOMORPHIC,                 \
diff --git a/src/cached-powers.cc b/src/cached-powers.cc
index dd9e3b4..ccf8882 100644
--- a/src/cached-powers.cc
+++ b/src/cached-powers.cc
@@ -4,9 +4,9 @@
 
 #include <limits.h>
 #include <stdarg.h>
+#include <stdint.h>
 #include <cmath>
 
-#include "include/v8stdint.h"
 #include "src/base/logging.h"
 #include "src/cached-powers.h"
 #include "src/globals.h"
diff --git a/src/char-predicates.cc b/src/char-predicates.cc
new file mode 100644
index 0000000..ab551d8
--- /dev/null
+++ b/src/char-predicates.cc
@@ -0,0 +1,42 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/char-predicates.h"
+
+#ifdef V8_I18N_SUPPORT
+#include "unicode/uchar.h"
+#include "unicode/urename.h"
+#endif  // V8_I18N_SUPPORT
+
+namespace v8 {
+namespace internal {
+
+bool SupplementaryPlanes::IsIDStart(uc32 c) {
+  DCHECK(c > 0xFFFF);
+#ifdef V8_I18N_SUPPORT
+  // This only works for code points in the SMPs, since ICU does not exclude
+  // code points with properties 'Pattern_Syntax' or 'Pattern_White_Space'.
+  // Code points in the SMP do not have those properties.
+  return u_isIDStart(c);
+#else
+  // This is incorrect, but if we don't have ICU, use this as fallback.
+  return false;
+#endif  // V8_I18N_SUPPORT
+}
+
+
+bool SupplementaryPlanes::IsIDPart(uc32 c) {
+  DCHECK(c > 0xFFFF);
+#ifdef V8_I18N_SUPPORT
+  // This only works for code points in the SMPs, since ICU does not exclude
+  // code points with properties 'Pattern_Syntax' or 'Pattern_White_Space'.
+  // Code points in the SMP do not have those properties.
+  return u_isIDPart(c);
+#else
+  // This is incorrect, but if we don't have ICU, use this as fallback.
+  return false;
+#endif  // V8_I18N_SUPPORT
+}
+}
+}  // namespace v8::internal
diff --git a/src/char-predicates.h b/src/char-predicates.h
index b7c5d42..5ecb07d 100644
--- a/src/char-predicates.h
+++ b/src/char-predicates.h
@@ -22,42 +22,54 @@
 inline bool IsRegExpWord(uc32 c);
 inline bool IsRegExpNewline(uc32 c);
 
+
+struct SupplementaryPlanes {
+  static bool IsIDStart(uc32 c);
+  static bool IsIDPart(uc32 c);
+};
+
+
+// ES6 draft section 11.6
+// This includes '_', '$' and '\', and ID_Start according to
+// http://www.unicode.org/reports/tr31/, which consists of categories
+// 'Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl', but excluding properties
+// 'Pattern_Syntax' or 'Pattern_White_Space'.
+// For code points in the SMPs, we can resort to ICU (if available).
 struct IdentifierStart {
   static inline bool Is(uc32 c) {
-    switch (c) {
-      case '$': case '_': case '\\': return true;
-      default: return unibrow::Letter::Is(c);
-    }
+    if (c > 0xFFFF) return SupplementaryPlanes::IsIDStart(c);
+    return unibrow::ID_Start::Is(c);
   }
 };
 
 
+// ES6 draft section 11.6
+// This includes \u200c and \u200d, and ID_Continue according to
+// http://www.unicode.org/reports/tr31/, which consists of ID_Start,
+// the categories 'Mn', 'Mc', 'Nd', 'Pc', but excluding properties
+// 'Pattern_Syntax' or 'Pattern_White_Space'.
+// For code points in the SMPs, we can resort to ICU (if available).
 struct IdentifierPart {
   static inline bool Is(uc32 c) {
-    return IdentifierStart::Is(c)
-        || unibrow::Number::Is(c)
-        || c == 0x200C  // U+200C is Zero-Width Non-Joiner.
-        || c == 0x200D  // U+200D is Zero-Width Joiner.
-        || unibrow::CombiningMark::Is(c)
-        || unibrow::ConnectorPunctuation::Is(c);
+    if (c > 0xFFFF) return SupplementaryPlanes::IsIDPart(c);
+    return unibrow::ID_Start::Is(c) || unibrow::ID_Continue::Is(c);
   }
 };
 
 
-// WhiteSpace according to ECMA-262 5.1, 7.2.
+// ES6 draft section 11.2
+// This includes all code points of Unicode category 'Zs'.
+// \u180e stops being one as of Unicode 6.3.0, but ES6 adheres to Unicode 5.1,
+// so it is also included.
+// Further included are \u0009, \u000b, \u0020, \u00a0, \u000c, and \ufeff.
+// There are no category 'Zs' code points in the SMPs.
 struct WhiteSpace {
-  static inline bool Is(uc32 c) {
-    return c == 0x0009 ||  // <TAB>
-           c == 0x000B ||  // <VT>
-           c == 0x000C ||  // <FF>
-           c == 0xFEFF ||  // <BOM>
-           // \u0020 and \u00A0 are included in unibrow::WhiteSpace.
-           unibrow::WhiteSpace::Is(c);
-  }
+  static inline bool Is(uc32 c) { return unibrow::WhiteSpace::Is(c); }
 };
 
 
-// WhiteSpace and LineTerminator according to ECMA-262 5.1, 7.2 and 7.3.
+// WhiteSpace and LineTerminator according to ES6 draft section 11.2 and 11.3
+// This consists of \000a, \000d, \u2028, and \u2029.
 struct WhiteSpaceOrLineTerminator {
   static inline bool Is(uc32 c) {
     return WhiteSpace::Is(c) || unibrow::LineTerminator::Is(c);
diff --git a/src/checks.h b/src/checks.h
index 6303855..6ba64c1 100644
--- a/src/checks.h
+++ b/src/checks.h
@@ -7,12 +7,6 @@
 
 #include "src/base/logging.h"
 
-#ifdef DEBUG
-#ifndef OPTIMIZED_DEBUG
-#define ENABLE_SLOW_DCHECKS    1
-#endif
-#endif
-
 namespace v8 {
 
 class Value;
diff --git a/src/code-factory.cc b/src/code-factory.cc
index c969c8f..e68d539 100644
--- a/src/code-factory.cc
+++ b/src/code-factory.cc
@@ -20,13 +20,35 @@
 
 
 // static
+Callable CodeFactory::LoadICInOptimizedCode(Isolate* isolate,
+                                            ContextualMode mode) {
+  if (FLAG_vector_ics) {
+    return Callable(LoadIC::initialize_stub_in_optimized_code(
+                        isolate, LoadICState(mode).GetExtraICState()),
+                    VectorLoadICDescriptor(isolate));
+  }
+  return CodeFactory::LoadIC(isolate, mode);
+}
+
+
+// static
 Callable CodeFactory::KeyedLoadIC(Isolate* isolate) {
-  return Callable(isolate->builtins()->KeyedLoadIC_Initialize(),
+  return Callable(KeyedLoadIC::initialize_stub(isolate),
                   LoadDescriptor(isolate));
 }
 
 
 // static
+Callable CodeFactory::KeyedLoadICInOptimizedCode(Isolate* isolate) {
+  if (FLAG_vector_ics) {
+    return Callable(KeyedLoadIC::initialize_stub_in_optimized_code(isolate),
+                    VectorLoadICDescriptor(isolate));
+  }
+  return CodeFactory::KeyedLoadIC(isolate);
+}
+
+
+// static
 Callable CodeFactory::StoreIC(Isolate* isolate, StrictMode mode) {
   return Callable(StoreIC::initialize_stub(isolate, mode),
                   StoreDescriptor(isolate));
@@ -82,6 +104,13 @@
 
 
 // static
+Callable CodeFactory::AllocateHeapNumber(Isolate* isolate) {
+  AllocateHeapNumberStub stub(isolate);
+  return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
+}
+
+
+// static
 Callable CodeFactory::CallFunction(Isolate* isolate, int argc,
                                    CallFunctionFlags flags) {
   CallFunctionStub stub(isolate, argc, flags);
diff --git a/src/code-factory.h b/src/code-factory.h
index 3add384..f26bf2a 100644
--- a/src/code-factory.h
+++ b/src/code-factory.h
@@ -33,7 +33,9 @@
  public:
   // Initial states for ICs.
   static Callable LoadIC(Isolate* isolate, ContextualMode mode);
+  static Callable LoadICInOptimizedCode(Isolate* isolate, ContextualMode mode);
   static Callable KeyedLoadIC(Isolate* isolate);
+  static Callable KeyedLoadICInOptimizedCode(Isolate* isolate);
   static Callable StoreIC(Isolate* isolate, StrictMode mode);
   static Callable KeyedStoreIC(Isolate* isolate, StrictMode mode);
 
@@ -53,9 +55,13 @@
   static Callable StringAdd(Isolate* isolate, StringAddFlags flags,
                             PretenureFlag pretenure_flag);
 
+  static Callable AllocateHeapNumber(Isolate* isolate);
+
   static Callable CallFunction(Isolate* isolate, int argc,
                                CallFunctionFlags flags);
 };
-}
-}
+
+}  // namespace internal
+}  // namespace v8
+
 #endif  // V8_CODE_FACTORY_H_
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index dafef52..800a09d 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -8,6 +8,7 @@
 #include "src/code-stubs.h"
 #include "src/field-index.h"
 #include "src/hydrogen.h"
+#include "src/ic/ic.h"
 #include "src/lithium.h"
 
 namespace v8 {
@@ -34,11 +35,11 @@
 
 class CodeStubGraphBuilderBase : public HGraphBuilder {
  public:
-  CodeStubGraphBuilderBase(Isolate* isolate, HydrogenCodeStub* stub)
-      : HGraphBuilder(&info_),
+  explicit CodeStubGraphBuilderBase(CompilationInfoWithZone* info)
+      : HGraphBuilder(info),
         arguments_length_(NULL),
-        info_(stub, isolate),
-        descriptor_(stub),
+        info_(info),
+        descriptor_(info->code_stub()),
         context_(NULL) {
     int parameter_count = descriptor_.GetEnvironmentParameterCount();
     parameters_.Reset(new HParameter*[parameter_count]);
@@ -56,15 +57,16 @@
     DCHECK(arguments_length_ != NULL);
     return arguments_length_;
   }
-  CompilationInfo* info() { return &info_; }
-  HydrogenCodeStub* stub() { return info_.code_stub(); }
+  CompilationInfo* info() { return info_; }
+  HydrogenCodeStub* stub() { return info_->code_stub(); }
   HContext* context() { return context_; }
-  Isolate* isolate() { return info_.isolate(); }
+  Isolate* isolate() { return info_->isolate(); }
 
   HLoadNamedField* BuildLoadNamedField(HValue* object,
                                        FieldIndex index);
   void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index,
-                            Representation representation);
+                            Representation representation,
+                            bool transition_to_field);
 
   enum ArgumentClass {
     NONE,
@@ -98,6 +100,21 @@
                                         HValue* shared_info,
                                         HValue* native_context);
 
+  // Tail calls handler found at array[map_index + 1].
+  void TailCallHandler(HValue* receiver, HValue* name, HValue* array,
+                       HValue* map_index, HValue* slot, HValue* vector);
+
+  // Tail calls handler_code.
+  void TailCallHandler(HValue* receiver, HValue* name, HValue* slot,
+                       HValue* vector, HValue* handler_code);
+
+  void TailCallMiss(HValue* receiver, HValue* name, HValue* slot,
+                    HValue* vector, bool keyed_load);
+
+  // Handle MONOMORPHIC and POLYMORPHIC LoadIC and KeyedLoadIC cases.
+  void HandleArrayCases(HValue* array, HValue* receiver, HValue* name,
+                        HValue* slot, HValue* vector, bool keyed_load);
+
  private:
   HValue* BuildArraySingleArgumentConstructor(JSArrayBuilder* builder);
   HValue* BuildArrayNArgumentsConstructor(JSArrayBuilder* builder,
@@ -105,7 +122,7 @@
 
   SmartArrayPointer<HParameter*> parameters_;
   HValue* arguments_length_;
-  CompilationInfoWithZone info_;
+  CompilationInfoWithZone* info_;
   CodeStubDescriptor descriptor_;
   HContext* context_;
 };
@@ -119,7 +136,7 @@
     const char* name = CodeStub::MajorName(stub()->MajorKey(), false);
     PrintF("-----------------------------------------------------------\n");
     PrintF("Compiling stub %s using hydrogen\n", name);
-    isolate()->GetHTracer()->TraceCompilation(&info_);
+    isolate()->GetHTracer()->TraceCompilation(info());
   }
 
   int param_count = descriptor_.GetEnvironmentParameterCount();
@@ -188,8 +205,8 @@
 template <class Stub>
 class CodeStubGraphBuilder: public CodeStubGraphBuilderBase {
  public:
-  CodeStubGraphBuilder(Isolate* isolate, Stub* stub)
-      : CodeStubGraphBuilderBase(isolate, stub) {}
+  explicit CodeStubGraphBuilder(CompilationInfoWithZone* info)
+      : CodeStubGraphBuilderBase(info) {}
 
  protected:
   virtual HValue* BuildCodeStub() {
@@ -232,6 +249,8 @@
 
     // Generate the code for the stub.
     masm.set_generating_stub(true);
+    // TODO(yangguo): remove this once we can serialize IC stubs.
+    masm.enable_serializer();
     NoCurrentFrameScope scope(&masm);
     GenerateLightweightMiss(&masm, miss);
   }
@@ -268,52 +287,20 @@
   if (FLAG_profile_hydrogen_code_stub_compilation) {
     timer.Start();
   }
-  CodeStubGraphBuilder<Stub> builder(isolate, stub);
+  CompilationInfoWithZone info(stub, isolate);
+  CodeStubGraphBuilder<Stub> builder(&info);
   LChunk* chunk = OptimizeGraph(builder.CreateGraph());
-  // TODO(yangguo) remove this once the code serializer handles code stubs.
-  if (FLAG_serialize_toplevel) chunk->info()->PrepareForSerializing();
   Handle<Code> code = chunk->Codegen();
   if (FLAG_profile_hydrogen_code_stub_compilation) {
     OFStream os(stdout);
     os << "[Lazy compilation of " << stub << " took "
-       << timer.Elapsed().InMillisecondsF() << " ms]" << endl;
+       << timer.Elapsed().InMillisecondsF() << " ms]" << std::endl;
   }
   return code;
 }
 
 
 template <>
-HValue* CodeStubGraphBuilder<ToNumberStub>::BuildCodeStub() {
-  HValue* value = GetParameter(0);
-
-  // Check if the parameter is already a SMI or heap number.
-  IfBuilder if_number(this);
-  if_number.If<HIsSmiAndBranch>(value);
-  if_number.OrIf<HCompareMap>(value, isolate()->factory()->heap_number_map());
-  if_number.Then();
-
-  // Return the number.
-  Push(value);
-
-  if_number.Else();
-
-  // Convert the parameter to number using the builtin.
-  HValue* function = AddLoadJSBuiltin(Builtins::TO_NUMBER);
-  Add<HPushArguments>(value);
-  Push(Add<HInvokeFunction>(function, 1));
-
-  if_number.End();
-
-  return Pop();
-}
-
-
-Handle<Code> ToNumberStub::GenerateCode() {
-  return DoGenerateCode(this);
-}
-
-
-template <>
 HValue* CodeStubGraphBuilder<NumberToStringStub>::BuildCodeStub() {
   info()->MarkAsSavesCallerDoubles();
   HValue* number = GetParameter(NumberToStringStub::kNumber);
@@ -336,10 +323,8 @@
   // so that it doesn't build and eager frame.
   info()->MarkMustNotHaveEagerFrame();
 
-  HInstruction* allocation_site = Add<HLoadKeyed>(GetParameter(0),
-                                                  GetParameter(1),
-                                                  static_cast<HValue*>(NULL),
-                                                  FAST_ELEMENTS);
+  HInstruction* allocation_site =
+      Add<HLoadKeyed>(GetParameter(0), GetParameter(1), nullptr, FAST_ELEMENTS);
   IfBuilder checker(this);
   checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site,
                                                     undefined);
@@ -347,8 +332,8 @@
 
   HObjectAccess access = HObjectAccess::ForAllocationSiteOffset(
       AllocationSite::kTransitionInfoOffset);
-  HInstruction* boilerplate = Add<HLoadNamedField>(
-      allocation_site, static_cast<HValue*>(NULL), access);
+  HInstruction* boilerplate =
+      Add<HLoadNamedField>(allocation_site, nullptr, access);
   HValue* elements = AddLoadElements(boilerplate);
   HValue* capacity = AddLoadFixedArrayLength(elements);
   IfBuilder zero_capacity(this);
@@ -400,10 +385,8 @@
 HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {
   HValue* undefined = graph()->GetConstantUndefined();
 
-  HInstruction* allocation_site = Add<HLoadKeyed>(GetParameter(0),
-                                                  GetParameter(1),
-                                                  static_cast<HValue*>(NULL),
-                                                  FAST_ELEMENTS);
+  HInstruction* allocation_site =
+      Add<HLoadKeyed>(GetParameter(0), GetParameter(1), nullptr, FAST_ELEMENTS);
 
   IfBuilder checker(this);
   checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site,
@@ -412,21 +395,24 @@
 
   HObjectAccess access = HObjectAccess::ForAllocationSiteOffset(
       AllocationSite::kTransitionInfoOffset);
-  HInstruction* boilerplate = Add<HLoadNamedField>(
-      allocation_site, static_cast<HValue*>(NULL), access);
+  HInstruction* boilerplate =
+      Add<HLoadNamedField>(allocation_site, nullptr, access);
 
-  int size = JSObject::kHeaderSize + casted_stub()->length() * kPointerSize;
+  int length = casted_stub()->length();
+  if (length == 0) {
+    // Empty objects have some slack added to them.
+    length = JSObject::kInitialGlobalObjectUnusedPropertiesCount;
+  }
+  int size = JSObject::kHeaderSize + length * kPointerSize;
   int object_size = size;
   if (FLAG_allocation_site_pretenuring) {
     size += AllocationMemento::kSize;
   }
 
-  HValue* boilerplate_map = Add<HLoadNamedField>(
-      boilerplate, static_cast<HValue*>(NULL),
-      HObjectAccess::ForMap());
+  HValue* boilerplate_map =
+      Add<HLoadNamedField>(boilerplate, nullptr, HObjectAccess::ForMap());
   HValue* boilerplate_size = Add<HLoadNamedField>(
-      boilerplate_map, static_cast<HValue*>(NULL),
-      HObjectAccess::ForMapInstanceSize());
+      boilerplate_map, nullptr, HObjectAccess::ForMapInstanceSize());
   HValue* size_in_words = Add<HConstant>(object_size >> kPointerSizeLog2);
   checker.If<HCompareNumericAndBranch>(boilerplate_size,
                                        size_in_words, Token::EQ);
@@ -439,9 +425,8 @@
 
   for (int i = 0; i < object_size; i += kPointerSize) {
     HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset(i);
-    Add<HStoreNamedField>(
-        object, access, Add<HLoadNamedField>(
-            boilerplate, static_cast<HValue*>(NULL), access));
+    Add<HStoreNamedField>(object, access,
+                          Add<HLoadNamedField>(boilerplate, nullptr, access));
   }
 
   DCHECK(FLAG_allocation_site_pretenuring || (size == object_size));
@@ -510,9 +495,8 @@
   // Link the object to the allocation site list
   HValue* site_list = Add<HConstant>(
       ExternalReference::allocation_sites_list_address(isolate()));
-  HValue* site = Add<HLoadNamedField>(
-      site_list, static_cast<HValue*>(NULL),
-      HObjectAccess::ForAllocationSiteList());
+  HValue* site = Add<HLoadNamedField>(site_list, nullptr,
+                                      HObjectAccess::ForAllocationSiteList());
   // TODO(mvstanton): This is a store to a weak pointer, which we may want to
   // mark as such in order to skip the write barrier, once we have a unified
   // system for weakness. For now we decided to keep it like this because having
@@ -539,6 +523,40 @@
 
 
 template <>
+HValue* CodeStubGraphBuilder<LoadScriptContextFieldStub>::BuildCodeStub() {
+  int context_index = casted_stub()->context_index();
+  int slot_index = casted_stub()->slot_index();
+
+  HValue* script_context = BuildGetScriptContext(context_index);
+  return Add<HLoadNamedField>(script_context, nullptr,
+                              HObjectAccess::ForContextSlot(slot_index));
+}
+
+
+Handle<Code> LoadScriptContextFieldStub::GenerateCode() {
+  return DoGenerateCode(this);
+}
+
+
+template <>
+HValue* CodeStubGraphBuilder<StoreScriptContextFieldStub>::BuildCodeStub() {
+  int context_index = casted_stub()->context_index();
+  int slot_index = casted_stub()->slot_index();
+
+  HValue* script_context = BuildGetScriptContext(context_index);
+  Add<HStoreNamedField>(script_context,
+                        HObjectAccess::ForContextSlot(slot_index),
+                        GetParameter(2), STORE_TO_INITIALIZED_ENTRY);
+  return GetParameter(2);
+}
+
+
+Handle<Code> StoreScriptContextFieldStub::GenerateCode() {
+  return DoGenerateCode(this);
+}
+
+
+template <>
 HValue* CodeStubGraphBuilder<LoadFastElementStub>::BuildCodeStub() {
   HInstruction* load = BuildUncheckedMonomorphicElementAccess(
       GetParameter(LoadDescriptor::kReceiverIndex),
@@ -563,15 +581,15 @@
   HObjectAccess access = index.is_inobject()
       ? HObjectAccess::ForObservableJSObjectOffset(offset, representation)
       : HObjectAccess::ForBackingStoreOffset(offset, representation);
-  if (index.is_double()) {
+  if (index.is_double() &&
+      (!FLAG_unbox_double_fields || !index.is_inobject())) {
     // Load the heap number.
     object = Add<HLoadNamedField>(
-        object, static_cast<HValue*>(NULL),
-        access.WithRepresentation(Representation::Tagged()));
+        object, nullptr, access.WithRepresentation(Representation::Tagged()));
     // Load the double value from it.
     access = HObjectAccess::ForHeapNumberValue();
   }
-  return Add<HLoadNamedField>(object, static_cast<HValue*>(NULL), access);
+  return Add<HLoadNamedField>(object, nullptr, access);
 }
 
 
@@ -591,12 +609,10 @@
   HValue* map = AddLoadMap(GetParameter(0), NULL);
   HObjectAccess descriptors_access = HObjectAccess::ForObservableJSObjectOffset(
       Map::kDescriptorsOffset, Representation::Tagged());
-  HValue* descriptors =
-      Add<HLoadNamedField>(map, static_cast<HValue*>(NULL), descriptors_access);
+  HValue* descriptors = Add<HLoadNamedField>(map, nullptr, descriptors_access);
   HObjectAccess value_access = HObjectAccess::ForObservableJSObjectOffset(
       DescriptorArray::GetValueOffset(casted_stub()->constant_index()));
-  return Add<HLoadNamedField>(descriptors, static_cast<HValue*>(NULL),
-                              value_access);
+  return Add<HLoadNamedField>(descriptors, nullptr, value_access);
 }
 
 
@@ -605,20 +621,19 @@
 
 HValue* CodeStubGraphBuilderBase::UnmappedCase(HValue* elements, HValue* key) {
   HValue* result;
-  HInstruction* backing_store = Add<HLoadKeyed>(
-      elements, graph()->GetConstant1(), static_cast<HValue*>(NULL),
-      FAST_ELEMENTS, ALLOW_RETURN_HOLE);
+  HInstruction* backing_store =
+      Add<HLoadKeyed>(elements, graph()->GetConstant1(), nullptr, FAST_ELEMENTS,
+                      ALLOW_RETURN_HOLE);
   Add<HCheckMaps>(backing_store, isolate()->factory()->fixed_array_map());
-  HValue* backing_store_length =
-      Add<HLoadNamedField>(backing_store, static_cast<HValue*>(NULL),
-                           HObjectAccess::ForFixedArrayLength());
+  HValue* backing_store_length = Add<HLoadNamedField>(
+      backing_store, nullptr, HObjectAccess::ForFixedArrayLength());
   IfBuilder in_unmapped_range(this);
   in_unmapped_range.If<HCompareNumericAndBranch>(key, backing_store_length,
                                                  Token::LT);
   in_unmapped_range.Then();
   {
-    result = Add<HLoadKeyed>(backing_store, key, static_cast<HValue*>(NULL),
-                             FAST_HOLEY_ELEMENTS, NEVER_RETURN_HOLE);
+    result = Add<HLoadKeyed>(backing_store, key, nullptr, FAST_HOLEY_ELEMENTS,
+                             NEVER_RETURN_HOLE);
   }
   in_unmapped_range.ElseDeopt("Outside of range");
   in_unmapped_range.End();
@@ -665,19 +680,17 @@
   positive_smi.End();
 
   HValue* constant_two = Add<HConstant>(2);
-  HValue* elements = AddLoadElements(receiver, static_cast<HValue*>(NULL));
-  HValue* elements_length =
-      Add<HLoadNamedField>(elements, static_cast<HValue*>(NULL),
-                           HObjectAccess::ForFixedArrayLength());
+  HValue* elements = AddLoadElements(receiver, nullptr);
+  HValue* elements_length = Add<HLoadNamedField>(
+      elements, nullptr, HObjectAccess::ForFixedArrayLength());
   HValue* adjusted_length = AddUncasted<HSub>(elements_length, constant_two);
   IfBuilder in_range(this);
   in_range.If<HCompareNumericAndBranch>(key, adjusted_length, Token::LT);
   in_range.Then();
   {
     HValue* index = AddUncasted<HAdd>(key, constant_two);
-    HInstruction* mapped_index =
-        Add<HLoadKeyed>(elements, index, static_cast<HValue*>(NULL),
-                        FAST_HOLEY_ELEMENTS, ALLOW_RETURN_HOLE);
+    HInstruction* mapped_index = Add<HLoadKeyed>(
+        elements, index, nullptr, FAST_HOLEY_ELEMENTS, ALLOW_RETURN_HOLE);
 
     IfBuilder is_valid(this);
     is_valid.IfNot<HCompareObjectEqAndBranch>(mapped_index,
@@ -687,13 +700,11 @@
       // TODO(mvstanton): I'd like to assert from this point, that if the
       // mapped_index is not the hole that it is indeed, a smi. An unnecessary
       // smi check is being emitted.
-      HValue* the_context =
-          Add<HLoadKeyed>(elements, graph()->GetConstant0(),
-                          static_cast<HValue*>(NULL), FAST_ELEMENTS);
+      HValue* the_context = Add<HLoadKeyed>(elements, graph()->GetConstant0(),
+                                            nullptr, FAST_ELEMENTS);
       DCHECK(Context::kHeaderSize == FixedArray::kHeaderSize);
-      HValue* result =
-          Add<HLoadKeyed>(the_context, mapped_index, static_cast<HValue*>(NULL),
-                          FAST_ELEMENTS, ALLOW_RETURN_HOLE);
+      HValue* result = Add<HLoadKeyed>(the_context, mapped_index, nullptr,
+                                       FAST_ELEMENTS, ALLOW_RETURN_HOLE);
       environment()->Push(result);
     }
     is_valid.Else();
@@ -721,7 +732,7 @@
 
 void CodeStubGraphBuilderBase::BuildStoreNamedField(
     HValue* object, HValue* value, FieldIndex index,
-    Representation representation) {
+    Representation representation, bool transition_to_field) {
   DCHECK(!index.is_double() || representation.IsDouble());
   int offset = index.offset();
   HObjectAccess access =
@@ -730,12 +741,32 @@
           : HObjectAccess::ForBackingStoreOffset(offset, representation);
 
   if (representation.IsDouble()) {
-    // Load the heap number.
-    object = Add<HLoadNamedField>(
-        object, static_cast<HValue*>(NULL),
-        access.WithRepresentation(Representation::Tagged()));
-    // Store the double value into it.
-    access = HObjectAccess::ForHeapNumberValue();
+    if (!FLAG_unbox_double_fields || !index.is_inobject()) {
+      HObjectAccess heap_number_access =
+          access.WithRepresentation(Representation::Tagged());
+      if (transition_to_field) {
+        // The store requires a mutable HeapNumber to be allocated.
+        NoObservableSideEffectsScope no_side_effects(this);
+        HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize);
+
+        // TODO(hpayer): Allocation site pretenuring support.
+        HInstruction* heap_number =
+            Add<HAllocate>(heap_number_size, HType::HeapObject(), NOT_TENURED,
+                           MUTABLE_HEAP_NUMBER_TYPE);
+        AddStoreMapConstant(heap_number,
+                            isolate()->factory()->mutable_heap_number_map());
+        Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(),
+                              value);
+        // Store the new mutable heap number into the object.
+        access = heap_number_access;
+        value = heap_number;
+      } else {
+        // Load the heap number.
+        object = Add<HLoadNamedField>(object, nullptr, heap_number_access);
+        // Store the double value into it.
+        access = HObjectAccess::ForHeapNumberValue();
+      }
+    }
   } else if (representation.IsHeapObject()) {
     BuildCheckHeapObject(value);
   }
@@ -747,7 +778,7 @@
 template <>
 HValue* CodeStubGraphBuilder<StoreFieldStub>::BuildCodeStub() {
   BuildStoreNamedField(GetParameter(0), GetParameter(2), casted_stub()->index(),
-                       casted_stub()->representation());
+                       casted_stub()->representation(), false);
   return GetParameter(2);
 }
 
@@ -756,6 +787,58 @@
 
 
 template <>
+HValue* CodeStubGraphBuilder<StoreTransitionStub>::BuildCodeStub() {
+  HValue* object = GetParameter(StoreTransitionDescriptor::kReceiverIndex);
+
+  switch (casted_stub()->store_mode()) {
+    case StoreTransitionStub::ExtendStorageAndStoreMapAndValue: {
+      HValue* properties = Add<HLoadNamedField>(
+          object, nullptr, HObjectAccess::ForPropertiesPointer());
+      HValue* length = AddLoadFixedArrayLength(properties);
+      HValue* delta =
+          Add<HConstant>(static_cast<int32_t>(JSObject::kFieldsAdded));
+      HValue* new_capacity = AddUncasted<HAdd>(length, delta);
+
+      // Grow properties array.
+      ElementsKind kind = FAST_ELEMENTS;
+      Add<HBoundsCheck>(new_capacity,
+                        Add<HConstant>((Page::kMaxRegularHeapObjectSize -
+                                        FixedArray::kHeaderSize) >>
+                                       ElementsKindToShiftSize(kind)));
+
+      // Reuse this code for properties backing store allocation.
+      HValue* new_properties =
+          BuildAllocateAndInitializeArray(kind, new_capacity);
+
+      BuildCopyProperties(properties, new_properties, length, new_capacity);
+
+      Add<HStoreNamedField>(object, HObjectAccess::ForPropertiesPointer(),
+                            new_properties);
+    }
+    // Fall through.
+    case StoreTransitionStub::StoreMapAndValue:
+      // Store the new value into the "extended" object.
+      BuildStoreNamedField(
+          object, GetParameter(StoreTransitionDescriptor::kValueIndex),
+          casted_stub()->index(), casted_stub()->representation(), true);
+    // Fall through.
+
+    case StoreTransitionStub::StoreMapOnly:
+      // And finally update the map.
+      Add<HStoreNamedField>(object, HObjectAccess::ForMap(),
+                            GetParameter(StoreTransitionDescriptor::kMapIndex));
+      break;
+  }
+  return GetParameter(StoreTransitionDescriptor::kValueIndex);
+}
+
+
+Handle<Code> StoreTransitionStub::GenerateCode() {
+  return DoGenerateCode(this);
+}
+
+
+template <>
 HValue* CodeStubGraphBuilder<StringLengthStub>::BuildCodeStub() {
   HValue* string = BuildLoadNamedField(GetParameter(0),
       FieldIndex::ForInObjectOffset(JSValue::kValueOffset));
@@ -805,6 +888,22 @@
   return DoGenerateCode(this);
 }
 
+
+template <>
+HValue* CodeStubGraphBuilder<AllocateHeapNumberStub>::BuildCodeStub() {
+  HValue* result =
+      Add<HAllocate>(Add<HConstant>(HeapNumber::kSize), HType::HeapNumber(),
+                     NOT_TENURED, HEAP_NUMBER_TYPE);
+  AddStoreMapConstant(result, isolate()->factory()->heap_number_map());
+  return result;
+}
+
+
+Handle<Code> AllocateHeapNumberStub::GenerateCode() {
+  return DoGenerateCode(this);
+}
+
+
 HValue* CodeStubGraphBuilderBase::BuildArrayConstructor(
     ElementsKind kind,
     AllocationSiteOverrideMode override_mode,
@@ -1003,7 +1102,7 @@
   HIfContinuation continuation;
   Handle<Map> sentinel_map(isolate->heap()->meta_map());
   Type* type = stub->GetType(zone(), sentinel_map);
-  BuildCompareNil(GetParameter(0), type, &continuation);
+  BuildCompareNil(GetParameter(0), type, &continuation, kEmbedMapsViaWeakCells);
   IfBuilder if_nil(this, &continuation);
   if_nil.Then();
   if (continuation.IsFalseReachable()) {
@@ -1228,8 +1327,7 @@
 
   HValue* cell = Add<HConstant>(placeholder_cell);
   HObjectAccess access(HObjectAccess::ForCellPayload(isolate()));
-  HValue* cell_contents = Add<HLoadNamedField>(
-      cell, static_cast<HValue*>(NULL), access);
+  HValue* cell_contents = Add<HLoadNamedField>(cell, nullptr, access);
 
   if (stub->is_constant()) {
     IfBuilder builder(this);
@@ -1327,7 +1425,7 @@
 
   // Now link a function into a list of optimized functions.
   HValue* optimized_functions_list = Add<HLoadNamedField>(
-      native_context, static_cast<HValue*>(NULL),
+      native_context, nullptr,
       HObjectAccess::ForContextSlot(Context::OPTIMIZED_FUNCTIONS_LIST));
   Add<HStoreNamedField>(js_function,
                         HObjectAccess::ForNextFunctionLinkPointer(),
@@ -1347,8 +1445,8 @@
   Add<HStoreNamedField>(js_function,
                         HObjectAccess::ForNextFunctionLinkPointer(),
                         graph()->GetConstantUndefined());
-  HValue* code_object = Add<HLoadNamedField>(
-      shared_info, static_cast<HValue*>(NULL), HObjectAccess::ForCodeOffset());
+  HValue* code_object = Add<HLoadNamedField>(shared_info, nullptr,
+                                             HObjectAccess::ForCodeOffset());
   Add<HStoreCodeEntry>(js_function, code_object);
 }
 
@@ -1365,8 +1463,8 @@
     HValue* field_offset_value = Add<HConstant>(field_offset);
     field_slot = AddUncasted<HAdd>(iterator, field_offset_value);
   }
-  HInstruction* field_entry = Add<HLoadKeyed>(optimized_map, field_slot,
-      static_cast<HValue*>(NULL), FAST_ELEMENTS);
+  HInstruction* field_entry =
+      Add<HLoadKeyed>(optimized_map, field_slot, nullptr, FAST_ELEMENTS);
   return field_entry;
 }
 
@@ -1378,8 +1476,7 @@
   Counters* counters = isolate()->counters();
   IfBuilder is_optimized(this);
   HInstruction* optimized_map = Add<HLoadNamedField>(
-      shared_info, static_cast<HValue*>(NULL),
-      HObjectAccess::ForOptimizedCodeMap());
+      shared_info, nullptr, HObjectAccess::ForOptimizedCodeMap());
   HValue* null_constant = Add<HConstant>(0);
   is_optimized.If<HCompareObjectEqAndBranch>(optimized_map, null_constant);
   is_optimized.Then();
@@ -1412,8 +1509,7 @@
                                LoopBuilder::kPostDecrement,
                                shared_function_entry_length);
       HValue* array_length = Add<HLoadNamedField>(
-          optimized_map, static_cast<HValue*>(NULL),
-          HObjectAccess::ForFixedArrayLength());
+          optimized_map, nullptr, HObjectAccess::ForFixedArrayLength());
       HValue* start_pos = AddUncasted<HSub>(array_length,
                                             shared_function_entry_length);
       HValue* slot_iterator = loop_builder.BeginBody(start_pos,
@@ -1457,8 +1553,8 @@
 
   // Create a new closure from the given function info in new space
   HValue* size = Add<HConstant>(JSFunction::kSize);
-  HInstruction* js_function = Add<HAllocate>(size, HType::JSObject(),
-                                             NOT_TENURED, JS_FUNCTION_TYPE);
+  HInstruction* js_function =
+      Add<HAllocate>(size, HType::JSObject(), NOT_TENURED, JS_FUNCTION_TYPE);
 
   int map_index = Context::FunctionMapIndex(casted_stub()->strict_mode(),
                                             casted_stub()->kind());
@@ -1467,8 +1563,7 @@
   // as the map of the allocated object.
   HInstruction* native_context = BuildGetNativeContext();
   HInstruction* map_slot_value = Add<HLoadNamedField>(
-      native_context, static_cast<HValue*>(NULL),
-      HObjectAccess::ForContextSlot(map_index));
+      native_context, nullptr, HObjectAccess::ForContextSlot(map_index));
   Add<HStoreNamedField>(js_function, HObjectAccess::ForMap(), map_slot_value);
 
   // Initialize the rest of the function.
@@ -1480,9 +1575,8 @@
                         empty_fixed_array);
   Add<HStoreNamedField>(js_function, HObjectAccess::ForPrototypeOrInitialMap(),
                         graph()->GetConstantHole());
-  Add<HStoreNamedField>(js_function,
-                        HObjectAccess::ForSharedFunctionInfoPointer(),
-                        shared_info);
+  Add<HStoreNamedField>(
+      js_function, HObjectAccess::ForSharedFunctionInfoPointer(), shared_info);
   Add<HStoreNamedField>(js_function, HObjectAccess::ForFunctionContextPointer(),
                         context());
 
@@ -1536,7 +1630,7 @@
 
   // Copy the global object from the previous context.
   HValue* global_object = Add<HLoadNamedField>(
-      context(), static_cast<HValue*>(NULL),
+      context(), nullptr,
       HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
   Add<HStoreNamedField>(function_context,
                         HObjectAccess::ForContextSlot(
@@ -1601,8 +1695,8 @@
 class CodeStubGraphBuilder<KeyedLoadGenericStub>
     : public CodeStubGraphBuilderBase {
  public:
-  CodeStubGraphBuilder(Isolate* isolate, KeyedLoadGenericStub* stub)
-      : CodeStubGraphBuilderBase(isolate, stub) {}
+  explicit CodeStubGraphBuilder(CompilationInfoWithZone* info)
+      : CodeStubGraphBuilderBase(info) {}
 
  protected:
   virtual HValue* BuildCodeStub();
@@ -1701,16 +1795,14 @@
       (1 << Map::kHasIndexedInterceptor);
     BuildJSObjectCheck(receiver, bit_field_mask);
 
-    HValue* map = Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL),
-                                       HObjectAccess::ForMap());
+    HValue* map =
+        Add<HLoadNamedField>(receiver, nullptr, HObjectAccess::ForMap());
 
     HValue* instance_type =
-      Add<HLoadNamedField>(map, static_cast<HValue*>(NULL),
-                           HObjectAccess::ForMapInstanceType());
+        Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType());
 
-    HValue* bit_field2 = Add<HLoadNamedField>(map,
-                                              static_cast<HValue*>(NULL),
-                                              HObjectAccess::ForMapBitField2());
+    HValue* bit_field2 =
+        Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2());
 
     IfBuilder kind_if(this);
     BuildFastElementLoad(&kind_if, receiver, key, instance_type, bit_field2,
@@ -1800,12 +1892,10 @@
       BuildNonGlobalObjectCheck(receiver);
 
       HValue* properties = Add<HLoadNamedField>(
-          receiver, static_cast<HValue*>(NULL),
-          HObjectAccess::ForPropertiesPointer());
+          receiver, nullptr, HObjectAccess::ForPropertiesPointer());
 
       HValue* hash =
-          Add<HLoadNamedField>(key, static_cast<HValue*>(NULL),
-          HObjectAccess::ForNameHashField());
+          Add<HLoadNamedField>(key, nullptr, HObjectAccess::ForNameHashField());
 
       hash = AddUncasted<HShr>(hash, Add<HConstant>(Name::kHashShift));
 
@@ -1824,8 +1914,8 @@
           ExternalReference::keyed_lookup_cache_keys(isolate());
       HValue* cache_keys = Add<HConstant>(cache_keys_ref);
 
-      HValue* map = Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL),
-                                         HObjectAccess::ForMap());
+      HValue* map =
+          Add<HLoadNamedField>(receiver, nullptr, HObjectAccess::ForMap());
       HValue* base_index = AddUncasted<HMul>(hash, Add<HConstant>(2));
       base_index->ClearFlag(HValue::kCanOverflow);
 
@@ -1847,13 +1937,13 @@
               Add<HConstant>(probe_base + KeyedLookupCache::kKeyIndex));
           key_index->ClearFlag(HValue::kCanOverflow);
           HValue* map_to_check =
-              Add<HLoadKeyed>(cache_keys, map_index, static_cast<HValue*>(NULL),
-                              FAST_ELEMENTS, NEVER_RETURN_HOLE, 0);
+              Add<HLoadKeyed>(cache_keys, map_index, nullptr, FAST_ELEMENTS,
+                              NEVER_RETURN_HOLE, 0);
           lookup_if->If<HCompareObjectEqAndBranch>(map_to_check, map);
           lookup_if->And();
           HValue* key_to_check =
-              Add<HLoadKeyed>(cache_keys, key_index, static_cast<HValue*>(NULL),
-                              FAST_ELEMENTS, NEVER_RETURN_HOLE, 0);
+              Add<HLoadKeyed>(cache_keys, key_index, nullptr, FAST_ELEMENTS,
+                              NEVER_RETURN_HOLE, 0);
           lookup_if->If<HCompareObjectEqAndBranch>(key_to_check, key);
           lookup_if->Then();
           {
@@ -1863,9 +1953,9 @@
                 Add<HConstant>(cache_field_offsets_ref);
             HValue* index = AddUncasted<HAdd>(hash, Add<HConstant>(probe));
             index->ClearFlag(HValue::kCanOverflow);
-            HValue* property_index = Add<HLoadKeyed>(
-                cache_field_offsets, index, static_cast<HValue*>(NULL),
-                EXTERNAL_INT32_ELEMENTS, NEVER_RETURN_HOLE, 0);
+            HValue* property_index =
+                Add<HLoadKeyed>(cache_field_offsets, index, nullptr,
+                                EXTERNAL_INT32_ELEMENTS, NEVER_RETURN_HOLE, 0);
             Push(property_index);
           }
           lookup_if->Else();
@@ -1904,11 +1994,129 @@
 }
 
 
+void CodeStubGraphBuilderBase::TailCallHandler(HValue* receiver, HValue* name,
+                                               HValue* array, HValue* map_index,
+                                               HValue* slot, HValue* vector) {
+  // The handler is at array[map_index + 1]. Compute this with a custom offset
+  // to HLoadKeyed.
+  int offset =
+      GetDefaultHeaderSizeForElementsKind(FAST_ELEMENTS) + kPointerSize;
+  HValue* handler_code = Add<HLoadKeyed>(
+      array, map_index, nullptr, FAST_ELEMENTS, NEVER_RETURN_HOLE, offset);
+  TailCallHandler(receiver, name, slot, vector, handler_code);
+}
+
+
+void CodeStubGraphBuilderBase::TailCallHandler(HValue* receiver, HValue* name,
+                                               HValue* slot, HValue* vector,
+                                               HValue* handler_code) {
+  VectorLoadICDescriptor descriptor(isolate());
+  HValue* op_vals[] = {context(), receiver, name, slot, vector};
+  Add<HCallWithDescriptor>(handler_code, 0, descriptor,
+                           Vector<HValue*>(op_vals, 5), TAIL_CALL);
+  // We never return here, it is a tail call.
+}
+
+
+void CodeStubGraphBuilderBase::TailCallMiss(HValue* receiver, HValue* name,
+                                            HValue* slot, HValue* vector,
+                                            bool keyed_load) {
+  DCHECK(FLAG_vector_ics);
+  Add<HTailCallThroughMegamorphicCache>(
+      receiver, name, slot, vector,
+      HTailCallThroughMegamorphicCache::ComputeFlags(keyed_load, true));
+  // We never return here, it is a tail call.
+}
+
+
+void CodeStubGraphBuilderBase::HandleArrayCases(HValue* array, HValue* receiver,
+                                                HValue* name, HValue* slot,
+                                                HValue* vector,
+                                                bool keyed_load) {
+  IfBuilder if_receiver_heap_object(this);
+  if_receiver_heap_object.IfNot<HIsSmiAndBranch>(receiver);
+  if_receiver_heap_object.Then();
+  {
+    HConstant* constant_two = Add<HConstant>(2);
+    HConstant* constant_three = Add<HConstant>(3);
+
+    HValue* receiver_map = AddLoadMap(receiver, nullptr);
+    HValue* start =
+        keyed_load ? graph()->GetConstant1() : graph()->GetConstant0();
+    HValue* weak_cell = Add<HLoadKeyed>(array, start, nullptr, FAST_ELEMENTS,
+                                        ALLOW_RETURN_HOLE);
+    // Load the weak cell value. It may be Smi(0), or a map. Compare nonetheless
+    // against the receiver_map.
+    HValue* array_map = Add<HLoadNamedField>(weak_cell, nullptr,
+                                             HObjectAccess::ForWeakCellValue());
+
+    IfBuilder if_correct_map(this);
+    if_correct_map.If<HCompareObjectEqAndBranch>(receiver_map, array_map);
+    if_correct_map.Then();
+    { TailCallHandler(receiver, name, array, start, slot, vector); }
+    if_correct_map.Else();
+    {
+      // If our array has more elements, the ic is polymorphic. Look for the
+      // receiver map in the rest of the array.
+      HValue* length = AddLoadFixedArrayLength(array, nullptr);
+      LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement,
+                          constant_two);
+      start = keyed_load ? constant_three : constant_two;
+      HValue* key = builder.BeginBody(start, length, Token::LT);
+      {
+        HValue* weak_cell = Add<HLoadKeyed>(array, key, nullptr, FAST_ELEMENTS,
+                                            ALLOW_RETURN_HOLE);
+        HValue* array_map = Add<HLoadNamedField>(
+            weak_cell, nullptr, HObjectAccess::ForWeakCellValue());
+        IfBuilder if_correct_poly_map(this);
+        if_correct_poly_map.If<HCompareObjectEqAndBranch>(receiver_map,
+                                                          array_map);
+        if_correct_poly_map.Then();
+        { TailCallHandler(receiver, name, array, key, slot, vector); }
+      }
+      builder.EndBody();
+    }
+    if_correct_map.End();
+  }
+}
+
+
 template <>
 HValue* CodeStubGraphBuilder<VectorLoadStub>::BuildCodeStub() {
   HValue* receiver = GetParameter(VectorLoadICDescriptor::kReceiverIndex);
-  Add<HDeoptimize>("Always deopt", Deoptimizer::EAGER);
-  return receiver;
+  HValue* name = GetParameter(VectorLoadICDescriptor::kNameIndex);
+  HValue* slot = GetParameter(VectorLoadICDescriptor::kSlotIndex);
+  HValue* vector = GetParameter(VectorLoadICDescriptor::kVectorIndex);
+
+  // If the feedback is an array, then the IC is in the monomorphic or
+  // polymorphic state.
+  HValue* feedback =
+      Add<HLoadKeyed>(vector, slot, nullptr, FAST_ELEMENTS, ALLOW_RETURN_HOLE);
+  IfBuilder array_checker(this);
+  array_checker.If<HCompareMap>(feedback,
+                                isolate()->factory()->fixed_array_map());
+  array_checker.Then();
+  { HandleArrayCases(feedback, receiver, name, slot, vector, false); }
+  array_checker.Else();
+  {
+    // Is the IC megamorphic?
+    IfBuilder mega_checker(this);
+    HConstant* megamorphic_symbol =
+        Add<HConstant>(isolate()->factory()->megamorphic_symbol());
+    mega_checker.If<HCompareObjectEqAndBranch>(feedback, megamorphic_symbol);
+    mega_checker.Then();
+    {
+      // Probe the stub cache.
+      Add<HTailCallThroughMegamorphicCache>(
+          receiver, name, slot, vector,
+          HTailCallThroughMegamorphicCache::ComputeFlags(false, false));
+    }
+    mega_checker.End();
+  }
+  array_checker.End();
+
+  TailCallMiss(receiver, name, slot, vector, false);
+  return graph()->GetConstant0();
 }
 
 
@@ -1918,8 +2126,65 @@
 template <>
 HValue* CodeStubGraphBuilder<VectorKeyedLoadStub>::BuildCodeStub() {
   HValue* receiver = GetParameter(VectorLoadICDescriptor::kReceiverIndex);
-  Add<HDeoptimize>("Always deopt", Deoptimizer::EAGER);
-  return receiver;
+  HValue* name = GetParameter(VectorLoadICDescriptor::kNameIndex);
+  HValue* slot = GetParameter(VectorLoadICDescriptor::kSlotIndex);
+  HValue* vector = GetParameter(VectorLoadICDescriptor::kVectorIndex);
+  HConstant* zero = graph()->GetConstant0();
+
+  // If the feedback is an array, then the IC is in the monomorphic or
+  // polymorphic state.
+  HValue* feedback =
+      Add<HLoadKeyed>(vector, slot, nullptr, FAST_ELEMENTS, ALLOW_RETURN_HOLE);
+  IfBuilder array_checker(this);
+  array_checker.If<HCompareMap>(feedback,
+                                isolate()->factory()->fixed_array_map());
+  array_checker.Then();
+  {
+    // If feedback[0] is 0, then the IC has element handlers and name should be
+    // a smi. If feedback[0] is a string, verify that it matches name.
+    HValue* recorded_name = Add<HLoadKeyed>(feedback, zero, nullptr,
+                                            FAST_ELEMENTS, ALLOW_RETURN_HOLE);
+
+    IfBuilder recorded_name_is_zero(this);
+    recorded_name_is_zero.If<HCompareObjectEqAndBranch>(recorded_name, zero);
+    recorded_name_is_zero.Then();
+    { Add<HCheckSmi>(name); }
+    recorded_name_is_zero.Else();
+    {
+      IfBuilder strings_match(this);
+      strings_match.IfNot<HCompareObjectEqAndBranch>(name, recorded_name);
+      strings_match.Then();
+      TailCallMiss(receiver, name, slot, vector, true);
+      strings_match.End();
+    }
+    recorded_name_is_zero.End();
+
+    HandleArrayCases(feedback, receiver, name, slot, vector, true);
+  }
+  array_checker.Else();
+  {
+    // Check if the IC is in generic state.
+    IfBuilder generic_checker(this);
+    HConstant* generic_symbol =
+        Add<HConstant>(isolate()->factory()->generic_symbol());
+    generic_checker.If<HCompareObjectEqAndBranch>(feedback, generic_symbol);
+    generic_checker.Then();
+    {
+      // Tail-call to the generic KeyedLoadIC, treating it like a handler.
+      Handle<Code> stub = KeyedLoadIC::generic_stub(isolate());
+      HValue* constant_stub = Add<HConstant>(stub);
+      LoadDescriptor descriptor(isolate());
+      HValue* op_vals[] = {context(), receiver, name};
+      Add<HCallWithDescriptor>(constant_stub, 0, descriptor,
+                               Vector<HValue*>(op_vals, 3), TAIL_CALL);
+      // We never return here, it is a tail call.
+    }
+    generic_checker.End();
+  }
+  array_checker.End();
+
+  TailCallMiss(receiver, name, slot, vector, true);
+  return zero;
 }
 
 
@@ -1935,14 +2200,15 @@
 
 template <>
 HValue* CodeStubGraphBuilder<MegamorphicLoadStub>::BuildCodeStub() {
-  // The return address is on the stack.
   HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex);
   HValue* name = GetParameter(LoadDescriptor::kNameIndex);
 
+  // We shouldn't generate this when FLAG_vector_ics is true because the
+  // megamorphic case is handled as part of the default stub.
+  DCHECK(!FLAG_vector_ics);
+
   // Probe the stub cache.
-  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
-      Code::ComputeHandlerFlags(Code::LOAD_IC));
-  Add<HTailCallThroughMegamorphicCache>(receiver, name, flags);
+  Add<HTailCallThroughMegamorphicCache>(receiver, name);
 
   // We never continue.
   return graph()->GetConstant0();
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 5c9e1a2..895569d 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/v8.h"
+#include "src/code-stubs.h"
+
+#include <sstream>
 
 #include "src/bootstrapper.h"
-#include "src/code-stubs.h"
 #include "src/cpu-profiler.h"
 #include "src/factory.h"
 #include "src/gdb-jit.h"
@@ -74,10 +75,10 @@
 
 
 void CodeStub::RecordCodeGeneration(Handle<Code> code) {
-  IC::RegisterWeakMapDependency(code);
-  OStringStream os;
+  std::ostringstream os;
   os << *this;
-  PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, os.c_str()));
+  PROFILE(isolate(),
+          CodeCreateEvent(Logger::STUB_TAG, *code, os.str().c_str()));
   Counters* counters = isolate()->counters();
   counters->total_stubs_code_size()->Increment(code->instruction_size());
 }
@@ -103,15 +104,14 @@
   // Generate the new code.
   MacroAssembler masm(isolate(), NULL, 256);
 
-  // TODO(yangguo) remove this once the code serializer handles code stubs.
-  if (FLAG_serialize_toplevel) masm.enable_serializer();
-
   {
     // Update the static counter each time a new code stub is generated.
     isolate()->counters()->code_stubs()->Increment();
 
     // Generate the code for the stub.
     masm.set_generating_stub(true);
+    // TODO(yangguo): remove this once we can serialize IC stubs.
+    masm.enable_serializer();
     NoCurrentFrameScope scope(&masm);
     Generate(&masm);
   }
@@ -153,9 +153,9 @@
     if (FLAG_print_code_stubs) {
       CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
       OFStream os(trace_scope.file());
-      OStringStream name;
+      std::ostringstream name;
       name << *this;
-      new_object->Disassemble(name.c_str(), os);
+      new_object->Disassemble(name.str().c_str(), os);
       os << "\n";
     }
 #endif
@@ -198,12 +198,12 @@
 }
 
 
-void CodeStub::PrintBaseName(OStream& os) const {  // NOLINT
+void CodeStub::PrintBaseName(std::ostream& os) const {  // NOLINT
   os << MajorName(MajorKey(), false);
 }
 
 
-void CodeStub::PrintName(OStream& os) const {  // NOLINT
+void CodeStub::PrintName(std::ostream& os) const {  // NOLINT
   PrintBaseName(os);
   PrintState(os);
 }
@@ -222,9 +222,8 @@
     CODE_STUB_LIST(DEF_CASE)
 #undef DEF_CASE
     case NUMBER_OF_IDS:
-      UNREACHABLE();
     case NoCache:
-      *value_out = NULL;
+      UNREACHABLE();
       break;
   }
 }
@@ -279,7 +278,7 @@
 }
 
 
-void BinaryOpICStub::PrintState(OStream& os) const {  // NOLINT
+void BinaryOpICStub::PrintState(std::ostream& os) const {  // NOLINT
   os << state();
 }
 
@@ -300,7 +299,7 @@
 
 
 void BinaryOpICWithAllocationSiteStub::PrintState(
-    OStream& os) const {  // NOLINT
+    std::ostream& os) const {  // NOLINT
   os << state();
 }
 
@@ -315,7 +314,7 @@
 }
 
 
-void StringAddStub::PrintBaseName(OStream& os) const {  // NOLINT
+void StringAddStub::PrintBaseName(std::ostream& os) const {  // NOLINT
   os << "StringAddStub";
   if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
     os << "_CheckBoth";
@@ -463,17 +462,17 @@
   OFStream os(stdout);
   os << "[";
   PrintBaseName(os);
-  os << ": " << from << "=>" << to << "]" << endl;
+  os << ": " << from << "=>" << to << "]" << std::endl;
 }
 
 
-void CompareNilICStub::PrintBaseName(OStream& os) const {  // NOLINT
+void CompareNilICStub::PrintBaseName(std::ostream& os) const {  // NOLINT
   CodeStub::PrintBaseName(os);
   os << ((nil_value() == kNullValue) ? "(NullValue)" : "(UndefinedValue)");
 }
 
 
-void CompareNilICStub::PrintState(OStream& os) const {  // NOLINT
+void CompareNilICStub::PrintState(std::ostream& os) const {  // NOLINT
   os << state();
 }
 
@@ -481,7 +480,7 @@
 // TODO(svenpanne) Make this a real infix_ostream_iterator.
 class SimpleListPrinter {
  public:
-  explicit SimpleListPrinter(OStream& os) : os_(os), first_(true) {}
+  explicit SimpleListPrinter(std::ostream& os) : os_(os), first_(true) {}
 
   void Add(const char* s) {
     if (first_) {
@@ -493,12 +492,12 @@
   }
 
  private:
-  OStream& os_;
+  std::ostream& os_;
   bool first_;
 };
 
 
-OStream& operator<<(OStream& os, const CompareNilICStub::State& s) {
+std::ostream& operator<<(std::ostream& os, const CompareNilICStub::State& s) {
   os << "(";
   SimpleListPrinter p(os);
   if (s.IsEmpty()) p.Add("None");
@@ -539,17 +538,17 @@
 }
 
 
-void CallIC_ArrayStub::PrintState(OStream& os) const {  // NOLINT
+void CallIC_ArrayStub::PrintState(std::ostream& os) const {  // NOLINT
   os << state() << " (Array)";
 }
 
 
-void CallICStub::PrintState(OStream& os) const {  // NOLINT
+void CallICStub::PrintState(std::ostream& os) const {  // NOLINT
   os << state();
 }
 
 
-void InstanceofStub::PrintName(OStream& os) const {  // NOLINT
+void InstanceofStub::PrintName(std::ostream& os) const {  // NOLINT
   os << "InstanceofStub";
   if (HasArgsInRegisters()) os << "_REGS";
   if (HasCallSiteInlineCheck()) os << "_INLINE";
@@ -594,6 +593,9 @@
 
 CallInterfaceDescriptor HandlerStub::GetCallInterfaceDescriptor() {
   if (kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC) {
+    if (FLAG_vector_ics) {
+      return VectorLoadICDescriptor(isolate());
+    }
     return LoadDescriptor(isolate());
   } else {
     DCHECK_EQ(Code::STORE_IC, kind());
@@ -614,6 +616,11 @@
 }
 
 
+CallInterfaceDescriptor StoreTransitionStub::GetCallInterfaceDescriptor() {
+  return StoreTransitionDescriptor(isolate());
+}
+
+
 static void InitializeVectorLoadStub(Isolate* isolate,
                                      CodeStubDescriptor* descriptor,
                                      Address deoptimization_handler) {
@@ -624,14 +631,13 @@
 
 void VectorLoadStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
   InitializeVectorLoadStub(isolate(), descriptor,
-                           FUNCTION_ADDR(VectorLoadIC_MissFromStubFailure));
+                           FUNCTION_ADDR(LoadIC_MissFromStubFailure));
 }
 
 
 void VectorKeyedLoadStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
-  InitializeVectorLoadStub(
-      isolate(), descriptor,
-      FUNCTION_ADDR(VectorKeyedLoadIC_MissFromStubFailure));
+  InitializeVectorLoadStub(isolate(), descriptor,
+                           FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure));
 }
 
 
@@ -647,9 +653,6 @@
 void FastNewContextStub::InitializeDescriptor(CodeStubDescriptor* d) {}
 
 
-void ToNumberStub::InitializeDescriptor(CodeStubDescriptor* d) {}
-
-
 void NumberToStringStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
   NumberToStringDescriptor call_descriptor(isolate());
   descriptor->Initialize(
@@ -690,6 +693,13 @@
 }
 
 
+void AllocateHeapNumberStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  descriptor->Initialize(
+      Runtime::FunctionForId(Runtime::kAllocateHeapNumber)->entry);
+}
+
+
 void CompareNilICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
   descriptor->Initialize(FUNCTION_ADDR(CompareNilIC_Miss));
   descriptor->SetMissHandler(
@@ -772,7 +782,7 @@
 }
 
 
-void ArgumentsAccessStub::PrintName(OStream& os) const {  // NOLINT
+void ArgumentsAccessStub::PrintName(std::ostream& os) const {  // NOLINT
   os << "ArgumentsAccessStub_";
   switch (type()) {
     case READ_ELEMENT:
@@ -792,18 +802,18 @@
 }
 
 
-void CallFunctionStub::PrintName(OStream& os) const {  // NOLINT
+void CallFunctionStub::PrintName(std::ostream& os) const {  // NOLINT
   os << "CallFunctionStub_Args" << argc();
 }
 
 
-void CallConstructStub::PrintName(OStream& os) const {  // NOLINT
+void CallConstructStub::PrintName(std::ostream& os) const {  // NOLINT
   os << "CallConstructStub";
   if (RecordCallTarget()) os << "_Recording";
 }
 
 
-void ArrayConstructorStub::PrintName(OStream& os) const {  // NOLINT
+void ArrayConstructorStub::PrintName(std::ostream& os) const {  // NOLINT
   os << "ArrayConstructorStub";
   switch (argument_count()) {
     case ANY:
@@ -823,8 +833,9 @@
 }
 
 
-OStream& ArrayConstructorStubBase::BasePrintName(OStream& os,  // NOLINT
-                                                 const char* name) const {
+std::ostream& ArrayConstructorStubBase::BasePrintName(
+    std::ostream& os,  // NOLINT
+    const char* name) const {
   os << name << "_" << ElementsKindToString(elements_kind());
   if (override_mode() == DISABLE_ALLOCATION_SITES) {
     os << "_DISABLE_ALLOCATION_SITES";
@@ -843,12 +854,12 @@
 }
 
 
-void ToBooleanStub::PrintState(OStream& os) const {  // NOLINT
+void ToBooleanStub::PrintState(std::ostream& os) const {  // NOLINT
   os << types();
 }
 
 
-OStream& operator<<(OStream& os, const ToBooleanStub::Types& s) {
+std::ostream& operator<<(std::ostream& os, const ToBooleanStub::Types& s) {
   os << "(";
   SimpleListPrinter p(os);
   if (s.IsEmpty()) p.Add("None");
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 3b31399..8448e55 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -39,6 +39,7 @@
   V(KeyedLoadICTrampoline)                  \
   V(LoadICTrampoline)                       \
   V(LoadIndexedInterceptor)                 \
+  V(LoadIndexedString)                      \
   V(MathPow)                                \
   V(ProfileEntryHook)                       \
   V(RecordWrite)                            \
@@ -49,7 +50,9 @@
   V(StringCompare)                          \
   V(StubFailureTrampoline)                  \
   V(SubString)                              \
+  V(ToNumber)                               \
   /* HydrogenCodeStubs */                   \
+  V(AllocateHeapNumber)                     \
   V(ArrayNArgumentsConstructor)             \
   V(ArrayNoArgumentConstructor)             \
   V(ArraySingleArgumentConstructor)         \
@@ -66,6 +69,7 @@
   V(InternalArrayNoArgumentConstructor)     \
   V(InternalArraySingleArgumentConstructor) \
   V(KeyedLoadGeneric)                       \
+  V(LoadScriptContextField)                 \
   V(LoadDictionaryElement)                  \
   V(LoadFastElement)                        \
   V(MegamorphicLoad)                        \
@@ -73,9 +77,9 @@
   V(NumberToString)                         \
   V(RegExpConstructResult)                  \
   V(StoreFastElement)                       \
+  V(StoreScriptContextField)                \
   V(StringAdd)                              \
   V(ToBoolean)                              \
-  V(ToNumber)                               \
   V(TransitionElementsKind)                 \
   V(VectorKeyedLoad)                        \
   V(VectorLoad)                             \
@@ -85,13 +89,12 @@
   V(KeyedLoadSloppyArguments)               \
   V(StoreField)                             \
   V(StoreGlobal)                            \
+  V(StoreTransition)                        \
   V(StringLength)
 
 // List of code stubs only used on ARM 32 bits platforms.
 #if V8_TARGET_ARCH_ARM
-#define CODE_STUB_LIST_ARM(V) \
-  V(DirectCEntry)             \
-  V(WriteInt32ToHeapNumber)
+#define CODE_STUB_LIST_ARM(V) V(DirectCEntry)
 
 #else
 #define CODE_STUB_LIST_ARM(V)
@@ -110,17 +113,15 @@
 
 // List of code stubs only used on MIPS platforms.
 #if V8_TARGET_ARCH_MIPS
-#define CODE_STUB_LIST_MIPS(V)  \
-  V(DirectCEntry)               \
-  V(RestoreRegistersState)      \
-  V(StoreRegistersState)        \
-  V(WriteInt32ToHeapNumber)
+#define CODE_STUB_LIST_MIPS(V) \
+  V(DirectCEntry)              \
+  V(RestoreRegistersState)     \
+  V(StoreRegistersState)
 #elif V8_TARGET_ARCH_MIPS64
-#define CODE_STUB_LIST_MIPS(V)  \
-  V(DirectCEntry)               \
-  V(RestoreRegistersState)      \
-  V(StoreRegistersState)        \
-  V(WriteInt32ToHeapNumber)
+#define CODE_STUB_LIST_MIPS(V) \
+  V(DirectCEntry)              \
+  V(RestoreRegistersState)     \
+  V(StoreRegistersState)
 #else
 #define CODE_STUB_LIST_MIPS(V)
 #endif
@@ -136,10 +137,12 @@
 class CodeStub BASE_EMBEDDED {
  public:
   enum Major {
+    // TODO(mvstanton): eliminate the NoCache key by getting rid
+    //                  of the non-monomorphic-cache.
+    NoCache = 0,  // marker for stubs that do custom caching]
 #define DEF_ENUM(name) name,
     CODE_STUB_LIST(DEF_ENUM)
 #undef DEF_ENUM
-    NoCache,  // marker for stubs that do custom caching
     NUMBER_OF_IDS
   };
 
@@ -201,7 +204,7 @@
     return Code::NORMAL;
   }
 
-  friend OStream& operator<<(OStream& os, const CodeStub& s) {
+  friend std::ostream& operator<<(std::ostream& os, const CodeStub& s) {
     s.PrintName(os);
     return os;
   }
@@ -219,9 +222,9 @@
   // a fixed (non-moveable) code object.
   virtual bool NeedsImmovableCode() { return false; }
 
-  virtual void PrintName(OStream& os) const;        // NOLINT
-  virtual void PrintBaseName(OStream& os) const;    // NOLINT
-  virtual void PrintState(OStream& os) const { ; }  // NOLINT
+  virtual void PrintName(std::ostream& os) const;        // NOLINT
+  virtual void PrintBaseName(std::ostream& os) const;    // NOLINT
+  virtual void PrintState(std::ostream& os) const { ; }  // NOLINT
 
   // Computes the key based on major and minor.
   uint32_t GetKey() {
@@ -286,54 +289,52 @@
   DISALLOW_COPY_AND_ASSIGN(NAME)
 
 
-#define DEFINE_CODE_STUB(NAME, SUPER)              \
- protected:                                        \
-  virtual inline Major MajorKey() const OVERRIDE { \
-    return NAME;                                   \
-  };                                               \
+#define DEFINE_CODE_STUB(NAME, SUPER)                      \
+ protected:                                                \
+  inline Major MajorKey() const OVERRIDE { return NAME; }; \
   DEFINE_CODE_STUB_BASE(NAME##Stub, SUPER)
 
 
-#define DEFINE_PLATFORM_CODE_STUB(NAME, SUPER)          \
- private:                                               \
-  virtual void Generate(MacroAssembler* masm) OVERRIDE; \
+#define DEFINE_PLATFORM_CODE_STUB(NAME, SUPER)  \
+ private:                                       \
+  void Generate(MacroAssembler* masm) OVERRIDE; \
   DEFINE_CODE_STUB(NAME, SUPER)
 
 
-#define DEFINE_HYDROGEN_CODE_STUB(NAME, SUPER)                                \
- public:                                                                      \
-  virtual void InitializeDescriptor(CodeStubDescriptor* descriptor) OVERRIDE; \
-  virtual Handle<Code> GenerateCode() OVERRIDE;                               \
+#define DEFINE_HYDROGEN_CODE_STUB(NAME, SUPER)                        \
+ public:                                                              \
+  void InitializeDescriptor(CodeStubDescriptor* descriptor) OVERRIDE; \
+  Handle<Code> GenerateCode() OVERRIDE;                               \
   DEFINE_CODE_STUB(NAME, SUPER)
 
-#define DEFINE_HANDLER_CODE_STUB(NAME, SUPER)   \
- public:                                        \
-  virtual Handle<Code> GenerateCode() OVERRIDE; \
+#define DEFINE_HANDLER_CODE_STUB(NAME, SUPER) \
+ public:                                      \
+  Handle<Code> GenerateCode() OVERRIDE;       \
   DEFINE_CODE_STUB(NAME, SUPER)
 
-#define DEFINE_CALL_INTERFACE_DESCRIPTOR(NAME)                            \
- public:                                                                  \
-  virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE { \
-    return NAME##Descriptor(isolate());                                   \
+#define DEFINE_CALL_INTERFACE_DESCRIPTOR(NAME)                    \
+ public:                                                          \
+  CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE { \
+    return NAME##Descriptor(isolate());                           \
   }
 
 // There are some code stubs we just can't describe right now with a
 // CallInterfaceDescriptor. Isolate behavior for those cases with this macro.
 // An attempt to retrieve a descriptor will fail.
-#define DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR()                           \
- public:                                                                  \
-  virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE { \
-    UNREACHABLE();                                                        \
-    return CallInterfaceDescriptor();                                     \
+#define DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR()                   \
+ public:                                                          \
+  CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE { \
+    UNREACHABLE();                                                \
+    return CallInterfaceDescriptor();                             \
   }
 
 
 class PlatformCodeStub : public CodeStub {
  public:
   // Retrieve the code for the stub. Generate the code if needed.
-  virtual Handle<Code> GenerateCode() OVERRIDE;
+  Handle<Code> GenerateCode() OVERRIDE;
 
-  virtual Code::Kind GetCodeKind() const { return Code::STUB; }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::STUB; }
 
  protected:
   explicit PlatformCodeStub(Isolate* isolate) : CodeStub(isolate) {}
@@ -433,7 +434,7 @@
     INITIALIZED
   };
 
-  virtual Code::Kind GetCodeKind() const { return Code::STUB; }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::STUB; }
 
   template<class SubClass>
   static Handle<Code> GetUninitialized(Isolate* isolate) {
@@ -442,7 +443,7 @@
   }
 
   // Retrieve the code for the stub. Generate the code if needed.
-  virtual Handle<Code> GenerateCode() = 0;
+  Handle<Code> GenerateCode() OVERRIDE = 0;
 
   bool IsUninitialized() const { return IsMissBits::decode(minor_key_); }
 
@@ -540,15 +541,6 @@
 };
 
 
-class ToNumberStub: public HydrogenCodeStub {
- public:
-  explicit ToNumberStub(Isolate* isolate) : HydrogenCodeStub(isolate) { }
-
-  DEFINE_CALL_INTERFACE_DESCRIPTOR(ToNumber);
-  DEFINE_HYDROGEN_CODE_STUB(ToNumber, HydrogenCodeStub);
-};
-
-
 class NumberToStringStub FINAL : public HydrogenCodeStub {
  public:
   explicit NumberToStringStub(Isolate* isolate) : HydrogenCodeStub(isolate) {}
@@ -581,10 +573,11 @@
   bool is_arrow() const { return IsArrowFunction(kind()); }
   bool is_generator() const { return IsGeneratorFunction(kind()); }
   bool is_concise_method() const { return IsConciseMethod(kind()); }
+  bool is_default_constructor() const { return IsDefaultConstructor(kind()); }
 
  private:
   class StrictModeBits : public BitField<StrictMode, 0, 1> {};
-  class FunctionKindBits : public BitField<FunctionKind, 1, 3> {};
+  class FunctionKindBits : public BitField<FunctionKind, 1, 4> {};
 
   DEFINE_CALL_INTERFACE_DESCRIPTOR(FastNewClosure);
   DEFINE_HYDROGEN_CODE_STUB(FastNewClosure, HydrogenCodeStub);
@@ -683,7 +676,7 @@
   static Register left() { return InstanceofDescriptor::left(); }
   static Register right() { return InstanceofDescriptor::right(); }
 
-  virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
+  CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
     if (HasArgsInRegisters()) {
       return InstanceofDescriptor(isolate());
     }
@@ -703,7 +696,7 @@
     return (flags() & kReturnTrueFalseObject) != 0;
   }
 
-  virtual void PrintName(OStream& os) const OVERRIDE;  // NOLINT
+  void PrintName(std::ostream& os) const OVERRIDE;  // NOLINT
 
   class FlagBits : public BitField<Flags, 0, 3> {};
 
@@ -734,7 +727,7 @@
   void GenerateDispatchToArrayStub(MacroAssembler* masm,
                                    AllocationSiteOverrideMode mode);
 
-  virtual void PrintName(OStream& os) const OVERRIDE;  // NOLINT
+  void PrintName(std::ostream& os) const OVERRIDE;  // NOLINT
 
   class ArgumentCountBits : public BitField<ArgumentCountKey, 0, 2> {};
 
@@ -764,7 +757,7 @@
     minor_key_ = ExponentTypeBits::encode(exponent_type);
   }
 
-  virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
+  CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
     if (exponent_type() == TAGGED) {
       return MathPowTaggedDescriptor(isolate());
     } else if (exponent_type() == INTEGER) {
@@ -797,11 +790,11 @@
     return state.arg_count();
   }
 
-  virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::CALL_IC; }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::CALL_IC; }
 
-  virtual InlineCacheState GetICState() const OVERRIDE { return DEFAULT; }
+  InlineCacheState GetICState() const OVERRIDE { return DEFAULT; }
 
-  virtual ExtraICState GetExtraICState() const FINAL OVERRIDE {
+  ExtraICState GetExtraICState() const FINAL {
     return static_cast<ExtraICState>(minor_key_);
   }
 
@@ -820,7 +813,7 @@
   void GenerateMiss(MacroAssembler* masm);
 
  private:
-  virtual void PrintState(OStream& os) const OVERRIDE;  // NOLINT
+  void PrintState(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DEFINE_CALL_INTERFACE_DESCRIPTOR(CallFunctionWithFeedback);
   DEFINE_PLATFORM_CODE_STUB(CallIC, PlatformCodeStub);
@@ -832,12 +825,10 @@
   CallIC_ArrayStub(Isolate* isolate, const CallICState& state_in)
       : CallICStub(isolate, state_in) {}
 
-  virtual InlineCacheState GetICState() const FINAL OVERRIDE {
-    return MONOMORPHIC;
-  }
+  InlineCacheState GetICState() const FINAL { return MONOMORPHIC; }
 
  private:
-  virtual void PrintState(OStream& os) const OVERRIDE;  // NOLINT
+  void PrintState(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DEFINE_PLATFORM_CODE_STUB(CallIC_Array, CallICStub);
 };
@@ -849,12 +840,18 @@
   explicit FunctionPrototypeStub(Isolate* isolate)
       : PlatformCodeStub(isolate) {}
 
-  virtual Code::Kind GetCodeKind() const { return Code::HANDLER; }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::HANDLER; }
 
   // TODO(mvstanton): only the receiver register is accessed. When this is
   // translated to a hydrogen code stub, a new CallInterfaceDescriptor
   // should be created that just uses that register for more efficient code.
-  DEFINE_CALL_INTERFACE_DESCRIPTOR(Load);
+  CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
+    if (FLAG_vector_ics) {
+      return VectorLoadICDescriptor(isolate());
+    }
+    return LoadDescriptor(isolate());
+  }
+
   DEFINE_PLATFORM_CODE_STUB(FunctionPrototype, PlatformCodeStub);
 };
 
@@ -865,23 +862,36 @@
   explicit LoadIndexedInterceptorStub(Isolate* isolate)
       : PlatformCodeStub(isolate) {}
 
-  virtual Code::Kind GetCodeKind() const { return Code::HANDLER; }
-  virtual Code::StubType GetStubType() { return Code::FAST; }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::HANDLER; }
+  Code::StubType GetStubType() OVERRIDE { return Code::FAST; }
 
   DEFINE_CALL_INTERFACE_DESCRIPTOR(Load);
   DEFINE_PLATFORM_CODE_STUB(LoadIndexedInterceptor, PlatformCodeStub);
 };
 
 
+class LoadIndexedStringStub : public PlatformCodeStub {
+ public:
+  explicit LoadIndexedStringStub(Isolate* isolate)
+      : PlatformCodeStub(isolate) {}
+
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::HANDLER; }
+  Code::StubType GetStubType() OVERRIDE { return Code::FAST; }
+
+  DEFINE_CALL_INTERFACE_DESCRIPTOR(Load);
+  DEFINE_PLATFORM_CODE_STUB(LoadIndexedString, PlatformCodeStub);
+};
+
+
 class HandlerStub : public HydrogenCodeStub {
  public:
-  virtual Code::Kind GetCodeKind() const { return Code::HANDLER; }
-  virtual ExtraICState GetExtraICState() const { return kind(); }
-  virtual InlineCacheState GetICState() const { return MONOMORPHIC; }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::HANDLER; }
+  ExtraICState GetExtraICState() const OVERRIDE { return kind(); }
+  InlineCacheState GetICState() const OVERRIDE { return MONOMORPHIC; }
 
-  virtual void InitializeDescriptor(CodeStubDescriptor* descriptor) OVERRIDE;
+  void InitializeDescriptor(CodeStubDescriptor* descriptor) OVERRIDE;
 
-  virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE;
+  CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE;
 
  protected:
   explicit HandlerStub(Isolate* isolate) : HydrogenCodeStub(isolate) {}
@@ -905,8 +915,8 @@
   }
 
  protected:
-  virtual Code::Kind kind() const { return Code::LOAD_IC; }
-  virtual Code::StubType GetStubType() { return Code::FAST; }
+  Code::Kind kind() const OVERRIDE { return Code::LOAD_IC; }
+  Code::StubType GetStubType() OVERRIDE { return Code::FAST; }
 
  private:
   class LoadFieldByIndexBits : public BitField<int, 0, 13> {};
@@ -921,8 +931,8 @@
       : HandlerStub(isolate) {}
 
  protected:
-  virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
-  virtual Code::StubType GetStubType() { return Code::FAST; }
+  Code::Kind kind() const OVERRIDE { return Code::KEYED_LOAD_IC; }
+  Code::StubType GetStubType() OVERRIDE { return Code::FAST; }
 
  private:
   DEFINE_HANDLER_CODE_STUB(KeyedLoadSloppyArguments, HandlerStub);
@@ -941,8 +951,8 @@
   }
 
  protected:
-  virtual Code::Kind kind() const { return Code::LOAD_IC; }
-  virtual Code::StubType GetStubType() { return Code::FAST; }
+  Code::Kind kind() const OVERRIDE { return Code::LOAD_IC; }
+  Code::StubType GetStubType() OVERRIDE { return Code::FAST; }
 
  private:
   class ConstantIndexBits : public BitField<int, 0, kSubMinorKeyBits> {};
@@ -956,8 +966,8 @@
   explicit StringLengthStub(Isolate* isolate) : HandlerStub(isolate) {}
 
  protected:
-  virtual Code::Kind kind() const { return Code::LOAD_IC; }
-  virtual Code::StubType GetStubType() { return Code::FAST; }
+  Code::Kind kind() const OVERRIDE { return Code::LOAD_IC; }
+  Code::StubType GetStubType() OVERRIDE { return Code::FAST; }
 
   DEFINE_HANDLER_CODE_STUB(StringLength, HandlerStub);
 };
@@ -985,8 +995,8 @@
   }
 
  protected:
-  virtual Code::Kind kind() const { return Code::STORE_IC; }
-  virtual Code::StubType GetStubType() { return Code::FAST; }
+  Code::Kind kind() const OVERRIDE { return Code::STORE_IC; }
+  Code::StubType GetStubType() OVERRIDE { return Code::FAST; }
 
  private:
   class StoreFieldByIndexBits : public BitField<int, 0, 13> {};
@@ -996,6 +1006,60 @@
 };
 
 
+class StoreTransitionStub : public HandlerStub {
+ public:
+  enum StoreMode {
+    StoreMapOnly,
+    StoreMapAndValue,
+    ExtendStorageAndStoreMapAndValue
+  };
+
+  explicit StoreTransitionStub(Isolate* isolate) : HandlerStub(isolate) {
+    set_sub_minor_key(StoreModeBits::encode(StoreMapOnly));
+  }
+
+  StoreTransitionStub(Isolate* isolate, FieldIndex index,
+                      Representation representation, StoreMode store_mode)
+      : HandlerStub(isolate) {
+    DCHECK(store_mode != StoreMapOnly);
+    int property_index_key = index.GetFieldAccessStubKey();
+    uint8_t repr = PropertyDetails::EncodeRepresentation(representation);
+    set_sub_minor_key(StoreFieldByIndexBits::encode(property_index_key) |
+                      RepresentationBits::encode(repr) |
+                      StoreModeBits::encode(store_mode));
+  }
+
+  FieldIndex index() const {
+    DCHECK(store_mode() != StoreMapOnly);
+    int property_index_key = StoreFieldByIndexBits::decode(sub_minor_key());
+    return FieldIndex::FromFieldAccessStubKey(property_index_key);
+  }
+
+  Representation representation() {
+    DCHECK(store_mode() != StoreMapOnly);
+    uint8_t repr = RepresentationBits::decode(sub_minor_key());
+    return PropertyDetails::DecodeRepresentation(repr);
+  }
+
+  StoreMode store_mode() const {
+    return StoreModeBits::decode(sub_minor_key());
+  }
+
+  CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE;
+
+ protected:
+  Code::Kind kind() const OVERRIDE { return Code::STORE_IC; }
+  Code::StubType GetStubType() OVERRIDE { return Code::FAST; }
+
+ private:
+  class StoreFieldByIndexBits : public BitField<int, 0, 13> {};
+  class RepresentationBits : public BitField<uint8_t, 13, 4> {};
+  class StoreModeBits : public BitField<StoreMode, 17, 2> {};
+
+  DEFINE_HANDLER_CODE_STUB(StoreTransition, HandlerStub);
+};
+
+
 class StoreGlobalStub : public HandlerStub {
  public:
   StoreGlobalStub(Isolate* isolate, bool is_constant, bool check_global)
@@ -1023,7 +1087,7 @@
     }
   }
 
-  virtual Code::Kind kind() const { return Code::STORE_IC; }
+  Code::Kind kind() const OVERRIDE { return Code::STORE_IC; }
 
   bool is_constant() const { return IsConstantBits::decode(sub_minor_key()); }
 
@@ -1105,15 +1169,11 @@
 
   static void GenerateAheadOfTime(Isolate* isolate);
 
-  virtual Code::Kind GetCodeKind() const OVERRIDE {
-    return Code::BINARY_OP_IC;
-  }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::BINARY_OP_IC; }
 
-  virtual InlineCacheState GetICState() const FINAL OVERRIDE {
-    return state().GetICState();
-  }
+  InlineCacheState GetICState() const FINAL { return state().GetICState(); }
 
-  virtual ExtraICState GetExtraICState() const FINAL OVERRIDE {
+  ExtraICState GetExtraICState() const FINAL {
     return static_cast<ExtraICState>(sub_minor_key());
   }
 
@@ -1121,7 +1181,7 @@
     return BinaryOpICState(isolate(), GetExtraICState());
   }
 
-  virtual void PrintState(OStream& os) const FINAL OVERRIDE;  // NOLINT
+  void PrintState(std::ostream& os) const FINAL;  // NOLINT
 
   // Parameters accessed via CodeStubGraphBuilder::GetParameter()
   static const int kLeft = 0;
@@ -1154,19 +1214,15 @@
     return CodeStub::GetCodeCopy(pattern);
   }
 
-  virtual Code::Kind GetCodeKind() const OVERRIDE {
-    return Code::BINARY_OP_IC;
-  }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::BINARY_OP_IC; }
 
-  virtual InlineCacheState GetICState() const OVERRIDE {
-    return state().GetICState();
-  }
+  InlineCacheState GetICState() const OVERRIDE { return state().GetICState(); }
 
-  virtual ExtraICState GetExtraICState() const OVERRIDE {
+  ExtraICState GetExtraICState() const OVERRIDE {
     return static_cast<ExtraICState>(minor_key_);
   }
 
-  virtual void PrintState(OStream& os) const OVERRIDE;  // NOLINT
+  void PrintState(std::ostream& os) const OVERRIDE;  // NOLINT
 
  private:
   BinaryOpICState state() const {
@@ -1191,9 +1247,7 @@
   BinaryOpWithAllocationSiteStub(Isolate* isolate, const BinaryOpICState& state)
       : BinaryOpICStub(isolate, state) {}
 
-  virtual Code::Kind GetCodeKind() const FINAL OVERRIDE {
-    return Code::STUB;
-  }
+  Code::Kind GetCodeKind() const FINAL { return Code::STUB; }
 
   // Parameters accessed via CodeStubGraphBuilder::GetParameter()
   static const int kAllocationSite = 0;
@@ -1242,7 +1296,7 @@
   class StringAddFlagsBits: public BitField<StringAddFlags, 0, 2> {};
   class PretenureFlagBits: public BitField<PretenureFlag, 2, 1> {};
 
-  virtual void PrintBaseName(OStream& os) const OVERRIDE;  // NOLINT
+  void PrintBaseName(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DEFINE_CALL_INTERFACE_DESCRIPTOR(StringAdd);
   DEFINE_HYDROGEN_CODE_STUB(StringAdd, HydrogenCodeStub);
@@ -1261,7 +1315,7 @@
 
   void set_known_map(Handle<Map> map) { known_map_ = map; }
 
-  virtual InlineCacheState GetICState() const;
+  InlineCacheState GetICState() const OVERRIDE;
 
   Token::Value op() const {
     return static_cast<Token::Value>(Token::EQ + OpBits::decode(minor_key_));
@@ -1276,7 +1330,7 @@
   CompareICState::State state() const { return StateBits::decode(minor_key_); }
 
  private:
-  virtual Code::Kind GetCodeKind() const { return Code::COMPARE_IC; }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::COMPARE_IC; }
 
   void GenerateSmis(MacroAssembler* masm);
   void GenerateNumbers(MacroAssembler* masm);
@@ -1291,9 +1345,9 @@
   bool strict() const { return op() == Token::EQ_STRICT; }
   Condition GetCondition() const;
 
-  virtual void AddToSpecialCache(Handle<Code> new_object);
-  virtual bool FindCodeInSpecialCache(Code** code_out);
-  virtual bool UseSpecialCache() {
+  void AddToSpecialCache(Handle<Code> new_object) OVERRIDE;
+  bool FindCodeInSpecialCache(Code** code_out) OVERRIDE;
+  bool UseSpecialCache() OVERRIDE {
     return state() == CompareICState::KNOWN_OBJECT;
   }
 
@@ -1329,7 +1383,7 @@
     return CompareNilICStub(isolate, nil, UNINITIALIZED).GetCode();
   }
 
-  virtual InlineCacheState GetICState() const {
+  InlineCacheState GetICState() const OVERRIDE {
     State state = this->state();
     if (state.Contains(GENERIC)) {
       return MEGAMORPHIC;
@@ -1340,9 +1394,9 @@
     }
   }
 
-  virtual Code::Kind GetCodeKind() const { return Code::COMPARE_NIL_IC; }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::COMPARE_NIL_IC; }
 
-  virtual ExtraICState GetExtraICState() const { return sub_minor_key(); }
+  ExtraICState GetExtraICState() const OVERRIDE { return sub_minor_key(); }
 
   void UpdateStatus(Handle<Object> object);
 
@@ -1354,8 +1408,8 @@
     set_sub_minor_key(TypesBits::update(sub_minor_key(), 0));
   }
 
-  virtual void PrintState(OStream& os) const OVERRIDE;     // NOLINT
-  virtual void PrintBaseName(OStream& os) const OVERRIDE;  // NOLINT
+  void PrintState(std::ostream& os) const OVERRIDE;     // NOLINT
+  void PrintBaseName(std::ostream& os) const OVERRIDE;  // NOLINT
 
  private:
   CompareNilICStub(Isolate* isolate, NilValue nil,
@@ -1382,7 +1436,7 @@
     State() : EnumSet<CompareNilType, byte>(0) { }
     explicit State(byte bits) : EnumSet<CompareNilType, byte>(bits) { }
   };
-  friend OStream& operator<<(OStream& os, const State& s);
+  friend std::ostream& operator<<(std::ostream& os, const State& s);
 
   State state() const { return State(TypesBits::decode(sub_minor_key())); }
 
@@ -1396,7 +1450,7 @@
 };
 
 
-OStream& operator<<(OStream& os, const CompareNilICStub::State& s);
+std::ostream& operator<<(std::ostream& os, const CompareNilICStub::State& s);
 
 
 class CEntryStub : public PlatformCodeStub {
@@ -1423,7 +1477,7 @@
   int result_size() const { return ResultSizeBits::decode(minor_key_); }
 #endif  // _WIN64
 
-  bool NeedsImmovableCode();
+  bool NeedsImmovableCode() OVERRIDE;
 
   class SaveDoublesBits : public BitField<bool, 0, 1> {};
   class ResultSizeBits : public BitField<int, 1, 3> {};
@@ -1442,9 +1496,9 @@
   }
 
  private:
-  virtual void FinishCode(Handle<Code> code);
+  void FinishCode(Handle<Code> code) OVERRIDE;
 
-  virtual void PrintName(OStream& os) const OVERRIDE {  // NOLINT
+  void PrintName(std::ostream& os) const OVERRIDE {  // NOLINT
     os << (type() == StackFrame::ENTRY ? "JSEntryStub"
                                        : "JSConstructEntryStub");
   }
@@ -1475,7 +1529,7 @@
     minor_key_ = TypeBits::encode(type);
   }
 
-  virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
+  CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
     if (type() == READ_ELEMENT) {
       return ArgumentsAccessReadDescriptor(isolate());
     }
@@ -1490,7 +1544,7 @@
   void GenerateNewSloppyFast(MacroAssembler* masm);
   void GenerateNewSloppySlow(MacroAssembler* masm);
 
-  virtual void PrintName(OStream& os) const OVERRIDE;  // NOLINT
+  void PrintName(std::ostream& os) const OVERRIDE;  // NOLINT
 
   class TypeBits : public BitField<Type, 0, 2> {};
 
@@ -1544,7 +1598,7 @@
 
   bool NeedsChecks() const { return flags() != WRAP_AND_CALL; }
 
-  virtual void PrintName(OStream& os) const OVERRIDE;  // NOLINT
+  void PrintName(std::ostream& os) const OVERRIDE;  // NOLINT
 
   // Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
   class FlagBits : public BitField<CallFunctionFlags, 0, 2> {};
@@ -1563,7 +1617,7 @@
     minor_key_ = FlagBits::encode(flags);
   }
 
-  virtual void FinishCode(Handle<Code> code) {
+  void FinishCode(Handle<Code> code) OVERRIDE {
     code->set_has_function_cache(RecordCallTarget());
   }
 
@@ -1574,7 +1628,7 @@
     return (flags() & RECORD_CONSTRUCTOR_TARGET) != 0;
   }
 
-  virtual void PrintName(OStream& os) const OVERRIDE;  // NOLINT
+  void PrintName(std::ostream& os) const OVERRIDE;  // NOLINT
 
   class FlagBits : public BitField<CallConstructorFlags, 0, 1> {};
 
@@ -1594,6 +1648,15 @@
 };
 
 
+enum ReceiverCheckMode {
+  // We don't know anything about the receiver.
+  RECEIVER_IS_UNKNOWN,
+
+  // We know the receiver is a string.
+  RECEIVER_IS_STRING
+};
+
+
 // Generates code implementing String.prototype.charCodeAt.
 //
 // Only supports the case when the receiver is a string and the index
@@ -1606,20 +1669,19 @@
 // preserved, |scratch| and |result| are clobbered.
 class StringCharCodeAtGenerator {
  public:
-  StringCharCodeAtGenerator(Register object,
-                            Register index,
-                            Register result,
-                            Label* receiver_not_string,
-                            Label* index_not_number,
+  StringCharCodeAtGenerator(Register object, Register index, Register result,
+                            Label* receiver_not_string, Label* index_not_number,
                             Label* index_out_of_range,
-                            StringIndexFlags index_flags)
+                            StringIndexFlags index_flags,
+                            ReceiverCheckMode check_mode = RECEIVER_IS_UNKNOWN)
       : object_(object),
         index_(index),
         result_(result),
         receiver_not_string_(receiver_not_string),
         index_not_number_(index_not_number),
         index_out_of_range_(index_out_of_range),
-        index_flags_(index_flags) {
+        index_flags_(index_flags),
+        check_mode_(check_mode) {
     DCHECK(!result_.is(object_));
     DCHECK(!result_.is(index_));
   }
@@ -1651,6 +1713,7 @@
   Label* index_out_of_range_;
 
   StringIndexFlags index_flags_;
+  ReceiverCheckMode check_mode_;
 
   Label call_runtime_;
   Label index_not_smi_;
@@ -1710,21 +1773,14 @@
 // preserved, |scratch1|, |scratch2|, and |result| are clobbered.
 class StringCharAtGenerator {
  public:
-  StringCharAtGenerator(Register object,
-                        Register index,
-                        Register scratch,
-                        Register result,
-                        Label* receiver_not_string,
-                        Label* index_not_number,
-                        Label* index_out_of_range,
-                        StringIndexFlags index_flags)
-      : char_code_at_generator_(object,
-                                index,
-                                scratch,
-                                receiver_not_string,
-                                index_not_number,
-                                index_out_of_range,
-                                index_flags),
+  StringCharAtGenerator(Register object, Register index, Register scratch,
+                        Register result, Label* receiver_not_string,
+                        Label* index_not_number, Label* index_out_of_range,
+                        StringIndexFlags index_flags,
+                        ReceiverCheckMode check_mode = RECEIVER_IS_UNKNOWN)
+      : char_code_at_generator_(object, index, scratch, receiver_not_string,
+                                index_not_number, index_out_of_range,
+                                index_flags, check_mode),
         char_from_code_generator_(scratch, result) {}
 
   // Generates the fast case code. On the fallthrough path |result|
@@ -1762,7 +1818,13 @@
   explicit LoadDictionaryElementStub(Isolate* isolate)
       : HydrogenCodeStub(isolate) {}
 
-  DEFINE_CALL_INTERFACE_DESCRIPTOR(Load);
+  CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
+    if (FLAG_vector_ics) {
+      return VectorLoadICDescriptor(isolate());
+    }
+    return LoadDescriptor(isolate());
+  }
+
   DEFINE_HYDROGEN_CODE_STUB(LoadDictionaryElement, HydrogenCodeStub);
 };
 
@@ -1771,10 +1833,14 @@
  public:
   explicit KeyedLoadGenericStub(Isolate* isolate) : HydrogenCodeStub(isolate) {}
 
-  virtual Code::Kind GetCodeKind() const { return Code::KEYED_LOAD_IC; }
-  virtual InlineCacheState GetICState() const { return GENERIC; }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::KEYED_LOAD_IC; }
+  InlineCacheState GetICState() const OVERRIDE { return GENERIC; }
 
+  // Since KeyedLoadGeneric stub doesn't miss (simply calls runtime), it
+  // doesn't need to use the VectorLoadICDescriptor for the case when
+  // flag --vector-ics is true.
   DEFINE_CALL_INTERFACE_DESCRIPTOR(Load);
+
   DEFINE_HYDROGEN_CODE_STUB(KeyedLoadGeneric, HydrogenCodeStub);
 };
 
@@ -1786,13 +1852,11 @@
     minor_key_ = state.GetExtraICState();
   }
 
-  virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
 
-  virtual InlineCacheState GetICState() const FINAL OVERRIDE {
-    return GENERIC;
-  }
+  InlineCacheState GetICState() const FINAL { return DEFAULT; }
 
-  virtual ExtraICState GetExtraICState() const FINAL OVERRIDE {
+  ExtraICState GetExtraICState() const FINAL {
     return static_cast<ExtraICState>(minor_key_);
   }
 
@@ -1811,9 +1875,7 @@
   explicit KeyedLoadICTrampolineStub(Isolate* isolate)
       : LoadICTrampolineStub(isolate, LoadICState(0)) {}
 
-  virtual Code::Kind GetCodeKind() const OVERRIDE {
-    return Code::KEYED_LOAD_IC;
-  }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::KEYED_LOAD_IC; }
 
   DEFINE_PLATFORM_CODE_STUB(KeyedLoadICTrampoline, LoadICTrampolineStub);
 };
@@ -1826,17 +1888,21 @@
     set_sub_minor_key(state.GetExtraICState());
   }
 
-  virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
 
-  virtual InlineCacheState GetICState() const FINAL OVERRIDE {
-    return MEGAMORPHIC;
-  }
+  InlineCacheState GetICState() const FINAL { return MEGAMORPHIC; }
 
-  virtual ExtraICState GetExtraICState() const FINAL OVERRIDE {
+  ExtraICState GetExtraICState() const FINAL {
     return static_cast<ExtraICState>(sub_minor_key());
   }
 
-  DEFINE_CALL_INTERFACE_DESCRIPTOR(Load);
+  CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
+    if (FLAG_vector_ics) {
+      return VectorLoadICDescriptor(isolate());
+    }
+    return LoadDescriptor(isolate());
+  }
+
   DEFINE_HYDROGEN_CODE_STUB(MegamorphicLoad, HydrogenCodeStub);
 };
 
@@ -1848,13 +1914,11 @@
     set_sub_minor_key(state.GetExtraICState());
   }
 
-  virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
 
-  virtual InlineCacheState GetICState() const FINAL OVERRIDE {
-    return GENERIC;
-  }
+  InlineCacheState GetICState() const FINAL { return DEFAULT; }
 
-  virtual ExtraICState GetExtraICState() const FINAL OVERRIDE {
+  ExtraICState GetExtraICState() const FINAL {
     return static_cast<ExtraICState>(sub_minor_key());
   }
 
@@ -1871,9 +1935,7 @@
   explicit VectorKeyedLoadStub(Isolate* isolate)
       : VectorLoadStub(isolate, LoadICState(0)) {}
 
-  virtual Code::Kind GetCodeKind() const OVERRIDE {
-    return Code::KEYED_LOAD_IC;
-  }
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::KEYED_LOAD_IC; }
 
   DEFINE_CALL_INTERFACE_DESCRIPTOR(VectorLoadIC);
   DEFINE_HYDROGEN_CODE_STUB(VectorKeyedLoad, VectorLoadStub);
@@ -1893,7 +1955,7 @@
                  SSE3Bits::encode(CpuFeatures::IsSupported(SSE3) ? 1 : 0);
   }
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
  private:
   Register source() const {
@@ -1927,6 +1989,66 @@
 };
 
 
+class ScriptContextFieldStub : public HandlerStub {
+ public:
+  ScriptContextFieldStub(Isolate* isolate,
+                         const ScriptContextTable::LookupResult* lookup_result)
+      : HandlerStub(isolate) {
+    DCHECK(Accepted(lookup_result));
+    set_sub_minor_key(ContextIndexBits::encode(lookup_result->context_index) |
+                      SlotIndexBits::encode(lookup_result->slot_index));
+  }
+
+  int context_index() const {
+    return ContextIndexBits::decode(sub_minor_key());
+  }
+
+  int slot_index() const { return SlotIndexBits::decode(sub_minor_key()); }
+
+  static bool Accepted(const ScriptContextTable::LookupResult* lookup_result) {
+    return ContextIndexBits::is_valid(lookup_result->context_index) &&
+           SlotIndexBits::is_valid(lookup_result->slot_index);
+  }
+
+ private:
+  static const int kContextIndexBits = 13;
+  static const int kSlotIndexBits = 13;
+  class ContextIndexBits : public BitField<int, 0, kContextIndexBits> {};
+  class SlotIndexBits
+      : public BitField<int, kContextIndexBits, kSlotIndexBits> {};
+
+  Code::StubType GetStubType() OVERRIDE { return Code::FAST; }
+
+  DEFINE_CODE_STUB_BASE(ScriptContextFieldStub, HandlerStub);
+};
+
+
+class LoadScriptContextFieldStub : public ScriptContextFieldStub {
+ public:
+  LoadScriptContextFieldStub(
+      Isolate* isolate, const ScriptContextTable::LookupResult* lookup_result)
+      : ScriptContextFieldStub(isolate, lookup_result) {}
+
+ private:
+  Code::Kind kind() const OVERRIDE { return Code::LOAD_IC; }
+
+  DEFINE_HANDLER_CODE_STUB(LoadScriptContextField, ScriptContextFieldStub);
+};
+
+
+class StoreScriptContextFieldStub : public ScriptContextFieldStub {
+ public:
+  StoreScriptContextFieldStub(
+      Isolate* isolate, const ScriptContextTable::LookupResult* lookup_result)
+      : ScriptContextFieldStub(isolate, lookup_result) {}
+
+ private:
+  Code::Kind kind() const OVERRIDE { return Code::STORE_IC; }
+
+  DEFINE_HANDLER_CODE_STUB(StoreScriptContextField, ScriptContextFieldStub);
+};
+
+
 class LoadFastElementStub : public HydrogenCodeStub {
  public:
   LoadFastElementStub(Isolate* isolate, bool is_js_array,
@@ -1946,7 +2068,13 @@
   class ElementsKindBits: public BitField<ElementsKind, 0, 8> {};
   class IsJSArrayBits: public BitField<bool, 8, 1> {};
 
-  DEFINE_CALL_INTERFACE_DESCRIPTOR(Load);
+  CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
+    if (FLAG_vector_ics) {
+      return VectorLoadICDescriptor(isolate());
+    }
+    return LoadDescriptor(isolate());
+  }
+
   DEFINE_HYDROGEN_CODE_STUB(LoadFastElement, HydrogenCodeStub);
 };
 
@@ -2010,6 +2138,17 @@
 };
 
 
+class AllocateHeapNumberStub FINAL : public HydrogenCodeStub {
+ public:
+  explicit AllocateHeapNumberStub(Isolate* isolate)
+      : HydrogenCodeStub(isolate) {}
+
+ private:
+  DEFINE_CALL_INTERFACE_DESCRIPTOR(AllocateHeapNumber);
+  DEFINE_HYDROGEN_CODE_STUB(AllocateHeapNumber, HydrogenCodeStub);
+};
+
+
 class ArrayConstructorStubBase : public HydrogenCodeStub {
  public:
   ArrayConstructorStubBase(Isolate* isolate,
@@ -2040,7 +2179,8 @@
   static const int kAllocationSite = 1;
 
  protected:
-  OStream& BasePrintName(OStream& os, const char* name) const;  // NOLINT
+  std::ostream& BasePrintName(std::ostream& os,
+                              const char* name) const;  // NOLINT
 
  private:
   // Ensure data fits within available bits.
@@ -2064,7 +2204,7 @@
   }
 
  private:
-  virtual void PrintName(OStream& os) const OVERRIDE {  // NOLINT
+  void PrintName(std::ostream& os) const OVERRIDE {  // NOLINT
     BasePrintName(os, "ArrayNoArgumentConstructorStub");
   }
 
@@ -2084,7 +2224,7 @@
   }
 
  private:
-  virtual void PrintName(OStream& os) const {  // NOLINT
+  void PrintName(std::ostream& os) const OVERRIDE {  // NOLINT
     BasePrintName(os, "ArraySingleArgumentConstructorStub");
   }
 
@@ -2104,7 +2244,7 @@
   }
 
  private:
-  virtual void PrintName(OStream& os) const {  // NOLINT
+  void PrintName(std::ostream& os) const OVERRIDE {  // NOLINT
     BasePrintName(os, "ArrayNArgumentsConstructorStub");
   }
 
@@ -2248,18 +2388,18 @@
   Types types() const { return Types(TypesBits::decode(sub_minor_key())); }
   ResultMode mode() const { return ResultModeBits::decode(sub_minor_key()); }
 
-  virtual Code::Kind GetCodeKind() const { return Code::TO_BOOLEAN_IC; }
-  virtual void PrintState(OStream& os) const OVERRIDE;  // NOLINT
+  Code::Kind GetCodeKind() const OVERRIDE { return Code::TO_BOOLEAN_IC; }
+  void PrintState(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
   static Handle<Code> GetUninitialized(Isolate* isolate) {
     return ToBooleanStub(isolate, UNINITIALIZED).GetCode();
   }
 
-  virtual ExtraICState GetExtraICState() const { return types().ToIntegral(); }
+  ExtraICState GetExtraICState() const OVERRIDE { return types().ToIntegral(); }
 
-  virtual InlineCacheState GetICState() const {
+  InlineCacheState GetICState() const OVERRIDE {
     if (types().IsEmpty()) {
       return ::v8::internal::UNINITIALIZED;
     } else {
@@ -2281,7 +2421,7 @@
 };
 
 
-OStream& operator<<(OStream& os, const ToBooleanStub::Types& t);
+std::ostream& operator<<(std::ostream& os, const ToBooleanStub::Types& t);
 
 
 class ElementsTransitionAndStoreStub : public HydrogenCodeStub {
@@ -2371,7 +2511,7 @@
   explicit ProfileEntryHookStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
 
   // The profile entry hook function is not allowed to cause a GC.
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
   // Generates a call to the entry hook if it's enabled.
   static void MaybeCallEntryHook(MacroAssembler* masm);
@@ -2396,7 +2536,7 @@
   }
 
   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
  private:
   bool save_doubles() const { return SaveDoublesBits::decode(minor_key_); }
@@ -2417,6 +2557,15 @@
 };
 
 
+class ToNumberStub FINAL : public PlatformCodeStub {
+ public:
+  explicit ToNumberStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
+
+  DEFINE_CALL_INTERFACE_DESCRIPTOR(ToNumber);
+  DEFINE_PLATFORM_CODE_STUB(ToNumber, PlatformCodeStub);
+};
+
+
 class StringCompareStub : public PlatformCodeStub {
  public:
   explicit StringCompareStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
diff --git a/src/codegen.cc b/src/codegen.cc
index 1362232..627e836 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -11,7 +11,7 @@
 #include "src/debug.h"
 #include "src/prettyprinter.h"
 #include "src/rewriter.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -180,9 +180,7 @@
       Handle<Script> script = info->script();
       if (!script->IsUndefined() && !script->source()->IsUndefined()) {
         os << "--- Raw source ---\n";
-        ConsStringIteratorOp op;
         StringCharacterStream stream(String::cast(script->source()),
-                                     &op,
                                      function->start_position());
         // fun->end_position() points to the last character in the stream. We
         // need to compensate by adding one to calculate the length.
diff --git a/src/codegen.h b/src/codegen.h
index e01a398..ba99a40 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -6,7 +6,7 @@
 #define V8_CODEGEN_H_
 
 #include "src/code-stubs.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 // Include the declaration of the architecture defined class CodeGenerator.
 // The contract  to the shared code is that the the CodeGenerator is a subclass
diff --git a/src/collection-iterator.js b/src/collection-iterator.js
index 2bccc8d..c1a9a27 100644
--- a/src/collection-iterator.js
+++ b/src/collection-iterator.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-'use strict';
+"use strict";
 
 
 // This file relies on the fact that the following declaration has been made
@@ -77,6 +77,8 @@
   %FunctionSetName(SetIteratorSymbolIterator, '[Symbol.iterator]');
   %AddNamedProperty(SetIterator.prototype, symbolIterator,
       SetIteratorSymbolIterator, DONT_ENUM);
+  %AddNamedProperty(SetIterator.prototype, symbolToStringTag,
+      "Set Iterator", READ_ONLY | DONT_ENUM);
 }
 
 SetUpSetIterator();
@@ -174,6 +176,8 @@
   %FunctionSetName(MapIteratorSymbolIterator, '[Symbol.iterator]');
   %AddNamedProperty(MapIterator.prototype, symbolIterator,
       MapIteratorSymbolIterator, DONT_ENUM);
+  %AddNamedProperty(MapIterator.prototype, symbolToStringTag,
+      "Map Iterator", READ_ONLY | DONT_ENUM);
 }
 
 SetUpMapIterator();
diff --git a/src/collection.js b/src/collection.js
index 0027bd7..94bda70 100644
--- a/src/collection.js
+++ b/src/collection.js
@@ -30,7 +30,7 @@
     }
   }
 
-  %SetInitialize(this);
+  %_SetInitialize(this);
 
   if (IS_UNDEFINED(iter)) return;
 
@@ -56,7 +56,7 @@
   if (key === 0) {
     key = 0;
   }
-  return %SetAdd(this, key);
+  return %_SetAdd(this, key);
 }
 
 
@@ -65,7 +65,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Set.prototype.has', this]);
   }
-  return %SetHas(this, key);
+  return %_SetHas(this, key);
 }
 
 
@@ -74,7 +74,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Set.prototype.delete', this]);
   }
-  return %SetDelete(this, key);
+  return %_SetDelete(this, key);
 }
 
 
@@ -83,7 +83,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Set.prototype.size', this]);
   }
-  return %SetGetSize(this);
+  return %_SetGetSize(this);
 }
 
 
@@ -92,7 +92,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Set.prototype.clear', this]);
   }
-  %SetClear(this);
+  %_SetClear(this);
 }
 
 
@@ -105,6 +105,12 @@
   if (!IS_SPEC_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [f]);
   }
+  var needs_wrapper = false;
+  if (IS_NULL_OR_UNDEFINED(receiver)) {
+    receiver = %GetDefaultReceiver(f) || receiver;
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
+  }
 
   var iterator = new SetIterator(this, ITERATOR_KIND_VALUES);
   var key;
@@ -113,7 +119,8 @@
   while (%SetIteratorNext(iterator, value_array)) {
     if (stepping) %DebugPrepareStepInIfStepping(f);
     key = value_array[0];
-    %_CallFunction(receiver, key, key, this, f);
+    var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+    %_CallFunction(new_receiver, key, key, this, f);
   }
 }
 
@@ -126,6 +133,8 @@
   %SetCode($Set, SetConstructor);
   %FunctionSetPrototype($Set, new $Object());
   %AddNamedProperty($Set.prototype, "constructor", $Set, DONT_ENUM);
+  %AddNamedProperty(
+      $Set.prototype, symbolToStringTag, "Set", DONT_ENUM | READ_ONLY);
 
   %FunctionSetLength(SetForEach, 1);
 
@@ -161,7 +170,7 @@
     }
   }
 
-  %MapInitialize(this);
+  %_MapInitialize(this);
 
   if (IS_UNDEFINED(iter)) return;
 
@@ -184,7 +193,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Map.prototype.get', this]);
   }
-  return %MapGet(this, key);
+  return %_MapGet(this, key);
 }
 
 
@@ -200,7 +209,7 @@
   if (key === 0) {
     key = 0;
   }
-  return %MapSet(this, key, value);
+  return %_MapSet(this, key, value);
 }
 
 
@@ -209,7 +218,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Map.prototype.has', this]);
   }
-  return %MapHas(this, key);
+  return %_MapHas(this, key);
 }
 
 
@@ -218,7 +227,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Map.prototype.delete', this]);
   }
-  return %MapDelete(this, key);
+  return %_MapDelete(this, key);
 }
 
 
@@ -227,7 +236,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Map.prototype.size', this]);
   }
-  return %MapGetSize(this);
+  return %_MapGetSize(this);
 }
 
 
@@ -236,7 +245,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Map.prototype.clear', this]);
   }
-  %MapClear(this);
+  %_MapClear(this);
 }
 
 
@@ -249,13 +258,20 @@
   if (!IS_SPEC_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [f]);
   }
+  var needs_wrapper = false;
+  if (IS_NULL_OR_UNDEFINED(receiver)) {
+    receiver = %GetDefaultReceiver(f) || receiver;
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
+  }
 
   var iterator = new MapIterator(this, ITERATOR_KIND_ENTRIES);
   var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
   var value_array = [UNDEFINED, UNDEFINED];
   while (%MapIteratorNext(iterator, value_array)) {
     if (stepping) %DebugPrepareStepInIfStepping(f);
-    %_CallFunction(receiver, value_array[1], value_array[0], this, f);
+    var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+    %_CallFunction(new_receiver, value_array[1], value_array[0], this, f);
   }
 }
 
@@ -268,6 +284,8 @@
   %SetCode($Map, MapConstructor);
   %FunctionSetPrototype($Map, new $Object());
   %AddNamedProperty($Map.prototype, "constructor", $Map, DONT_ENUM);
+  %AddNamedProperty(
+      $Map.prototype, symbolToStringTag, "Map", DONT_ENUM | READ_ONLY);
 
   %FunctionSetLength(MapForEach, 1);
 
diff --git a/src/compilation-cache.cc b/src/compilation-cache.cc
index aab2fe5..6c9f95a 100644
--- a/src/compilation-cache.cc
+++ b/src/compilation-cache.cc
@@ -13,11 +13,6 @@
 
 
 // The number of generations for each sub cache.
-// The number of ScriptGenerations is carefully chosen based on histograms.
-// See issue 458: http://code.google.com/p/v8/issues/detail?id=458
-static const int kScriptGenerations = 5;
-static const int kEvalGlobalGenerations = 2;
-static const int kEvalContextualGenerations = 2;
 static const int kRegExpGenerations = 2;
 
 // Initial size of each compilation cache table allocated.
@@ -26,9 +21,9 @@
 
 CompilationCache::CompilationCache(Isolate* isolate)
     : isolate_(isolate),
-      script_(isolate, kScriptGenerations),
-      eval_global_(isolate, kEvalGlobalGenerations),
-      eval_contextual_(isolate, kEvalContextualGenerations),
+      script_(isolate, 1),
+      eval_global_(isolate, 1),
+      eval_contextual_(isolate, 1),
       reg_exp_(isolate, kRegExpGenerations),
       enabled_(true) {
   CompilationSubCache* subcaches[kSubCacheCount] =
@@ -58,6 +53,14 @@
 
 
 void CompilationSubCache::Age() {
+  // Don't directly age single-generation caches.
+  if (generations_ == 1) {
+    if (tables_[0] != isolate()->heap()->undefined_value()) {
+      CompilationCacheTable::cast(tables_[0])->Age();
+    }
+    return;
+  }
+
   // Age the generations implicitly killing off the oldest.
   for (int i = generations_ - 1; i > 0; i--) {
     tables_[i] = tables_[i - 1];
@@ -102,9 +105,7 @@
 
 CompilationCacheScript::CompilationCacheScript(Isolate* isolate,
                                                int generations)
-    : CompilationSubCache(isolate, generations),
-      script_histogram_(NULL),
-      script_histogram_initialized_(false) { }
+    : CompilationSubCache(isolate, generations) {}
 
 
 // We only re-use a cached function for some script source code if the
@@ -173,20 +174,6 @@
     }
   }
 
-  if (!script_histogram_initialized_) {
-    script_histogram_ = isolate()->stats_table()->CreateHistogram(
-        "V8.ScriptCache",
-        0,
-        kScriptGenerations,
-        kScriptGenerations + 1);
-    script_histogram_initialized_ = true;
-  }
-
-  if (script_histogram_ != NULL) {
-    // The level NUMBER_OF_SCRIPT_GENERATIONS is equivalent to a cache miss.
-    isolate()->stats_table()->AddHistogramSample(script_histogram_, generation);
-  }
-
   // Once outside the manacles of the handle scope, we need to recheck
   // to see if we actually found a cached script. If so, we return a
   // handle created in the caller's handle scope.
diff --git a/src/compilation-cache.h b/src/compilation-cache.h
index 6799b1c..a7c84b7 100644
--- a/src/compilation-cache.h
+++ b/src/compilation-cache.h
@@ -89,9 +89,6 @@
                  int column_offset,
                  bool is_shared_cross_origin);
 
-  void* script_histogram_;
-  bool script_histogram_initialized_;
-
   DISALLOW_IMPLICIT_CONSTRUCTORS(CompilationCacheScript);
 };
 
diff --git a/src/compilation-statistics.cc b/src/compilation-statistics.cc
new file mode 100644
index 0000000..2686ff7
--- /dev/null
+++ b/src/compilation-statistics.cc
@@ -0,0 +1,144 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <ostream>  // NOLINT(readability/streams)
+#include <vector>
+
+#include "src/base/platform/platform.h"
+#include "src/compilation-statistics.h"
+
+namespace v8 {
+namespace internal {
+
+void CompilationStatistics::RecordPhaseStats(const char* phase_kind_name,
+                                             const char* phase_name,
+                                             const BasicStats& stats) {
+  std::string phase_name_str(phase_name);
+  auto it = phase_map_.find(phase_name_str);
+  if (it == phase_map_.end()) {
+    PhaseStats phase_stats(phase_map_.size(), phase_kind_name);
+    it = phase_map_.insert(std::make_pair(phase_name_str, phase_stats)).first;
+  }
+  it->second.Accumulate(stats);
+}
+
+
+void CompilationStatistics::RecordPhaseKindStats(const char* phase_kind_name,
+                                                 const BasicStats& stats) {
+  std::string phase_kind_name_str(phase_kind_name);
+  auto it = phase_kind_map_.find(phase_kind_name_str);
+  if (it == phase_kind_map_.end()) {
+    PhaseKindStats phase_kind_stats(phase_kind_map_.size());
+    it = phase_kind_map_.insert(std::make_pair(phase_kind_name_str,
+                                               phase_kind_stats)).first;
+  }
+  it->second.Accumulate(stats);
+}
+
+
+void CompilationStatistics::RecordTotalStats(size_t source_size,
+                                             const BasicStats& stats) {
+  source_size += source_size;
+  total_stats_.Accumulate(stats);
+}
+
+
+void CompilationStatistics::BasicStats::Accumulate(const BasicStats& stats) {
+  delta_ += stats.delta_;
+  total_allocated_bytes_ += stats.total_allocated_bytes_;
+  if (stats.absolute_max_allocated_bytes_ > absolute_max_allocated_bytes_) {
+    absolute_max_allocated_bytes_ = stats.absolute_max_allocated_bytes_;
+    max_allocated_bytes_ = stats.max_allocated_bytes_;
+    function_name_ = stats.function_name_;
+  }
+}
+
+
+static void WriteLine(std::ostream& os, const char* name,
+                      const CompilationStatistics::BasicStats& stats,
+                      const CompilationStatistics::BasicStats& total_stats) {
+  const size_t kBufferSize = 128;
+  char buffer[kBufferSize];
+
+  double ms = stats.delta_.InMillisecondsF();
+  double percent = stats.delta_.PercentOf(total_stats.delta_);
+  double size_percent =
+      static_cast<double>(stats.total_allocated_bytes_ * 100) /
+      static_cast<double>(total_stats.total_allocated_bytes_);
+  base::OS::SNPrintF(buffer, kBufferSize,
+                     "%28s %10.3f ms / %5.1f %%"
+                     "%10u total / %5.1f %% "
+                     "%10u max %10u abs_max",
+                     name, ms, percent, stats.total_allocated_bytes_,
+                     size_percent, stats.max_allocated_bytes_,
+                     stats.absolute_max_allocated_bytes_);
+
+  os << buffer;
+  if (stats.function_name_.size() > 0) {
+    os << " : " << stats.function_name_.c_str();
+  }
+  os << std::endl;
+}
+
+
+static void WriteFullLine(std::ostream& os) {
+  os << "--------------------------------------------------------"
+        "--------------------------------------------------------\n";
+}
+
+
+static void WriteHeader(std::ostream& os) {
+  WriteFullLine(os);
+  os << "                             Turbofan timing results:\n";
+  WriteFullLine(os);
+}
+
+
+static void WritePhaseKindBreak(std::ostream& os) {
+  os << "                             ---------------------------"
+        "--------------------------------------------------------\n";
+}
+
+
+std::ostream& operator<<(std::ostream& os, const CompilationStatistics& s) {
+  // phase_kind_map_ and phase_map_ don't get mutated, so store a bunch of
+  // pointers into them.
+
+  typedef std::vector<CompilationStatistics::PhaseKindMap::const_iterator>
+      SortedPhaseKinds;
+  SortedPhaseKinds sorted_phase_kinds(s.phase_kind_map_.size());
+  for (auto it = s.phase_kind_map_.begin(); it != s.phase_kind_map_.end();
+       ++it) {
+    sorted_phase_kinds[it->second.insert_order_] = it;
+  }
+
+  typedef std::vector<CompilationStatistics::PhaseMap::const_iterator>
+      SortedPhases;
+  SortedPhases sorted_phases(s.phase_map_.size());
+  for (auto it = s.phase_map_.begin(); it != s.phase_map_.end(); ++it) {
+    sorted_phases[it->second.insert_order_] = it;
+  }
+
+  WriteHeader(os);
+  for (auto phase_kind_it : sorted_phase_kinds) {
+    const auto& phase_kind_name = phase_kind_it->first;
+    for (auto phase_it : sorted_phases) {
+      const auto& phase_stats = phase_it->second;
+      if (phase_stats.phase_kind_name_ != phase_kind_name) continue;
+      const auto& phase_name = phase_it->first;
+      WriteLine(os, phase_name.c_str(), phase_stats, s.total_stats_);
+    }
+    WritePhaseKindBreak(os);
+    const auto& phase_kind_stats = phase_kind_it->second;
+    WriteLine(os, phase_kind_name.c_str(), phase_kind_stats, s.total_stats_);
+    os << std::endl;
+  }
+  WriteFullLine(os);
+  WriteLine(os, "totals", s.total_stats_, s.total_stats_);
+
+  return os;
+}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compilation-statistics.h b/src/compilation-statistics.h
new file mode 100644
index 0000000..45ffb9b
--- /dev/null
+++ b/src/compilation-statistics.h
@@ -0,0 +1,86 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILATION_STATISTICS_H_
+#define V8_COMPILATION_STATISTICS_H_
+
+#include <map>
+#include <string>
+
+#include "src/allocation.h"
+#include "src/base/platform/time.h"
+
+namespace v8 {
+namespace internal {
+
+class CompilationInfo;
+
+class CompilationStatistics FINAL : public Malloced {
+ public:
+  CompilationStatistics() {}
+
+  class BasicStats {
+   public:
+    BasicStats()
+        : total_allocated_bytes_(0),
+          max_allocated_bytes_(0),
+          absolute_max_allocated_bytes_(0) {}
+
+    void Accumulate(const BasicStats& stats);
+
+    base::TimeDelta delta_;
+    size_t total_allocated_bytes_;
+    size_t max_allocated_bytes_;
+    size_t absolute_max_allocated_bytes_;
+    std::string function_name_;
+  };
+
+  void RecordPhaseStats(const char* phase_kind_name, const char* phase_name,
+                        const BasicStats& stats);
+
+  void RecordPhaseKindStats(const char* phase_kind_name,
+                            const BasicStats& stats);
+
+  void RecordTotalStats(size_t source_size, const BasicStats& stats);
+
+ private:
+  class TotalStats : public BasicStats {
+   public:
+    TotalStats() : source_size_(0) {}
+    uint64_t source_size_;
+  };
+
+  class OrderedStats : public BasicStats {
+   public:
+    explicit OrderedStats(size_t insert_order) : insert_order_(insert_order) {}
+    size_t insert_order_;
+  };
+
+  class PhaseStats : public OrderedStats {
+   public:
+    PhaseStats(size_t insert_order, const char* phase_kind_name)
+        : OrderedStats(insert_order), phase_kind_name_(phase_kind_name) {}
+    std::string phase_kind_name_;
+  };
+
+  friend std::ostream& operator<<(std::ostream& os,
+                                  const CompilationStatistics& s);
+
+  typedef OrderedStats PhaseKindStats;
+  typedef std::map<std::string, PhaseKindStats> PhaseKindMap;
+  typedef std::map<std::string, PhaseStats> PhaseMap;
+
+  TotalStats total_stats_;
+  PhaseKindMap phase_kind_map_;
+  PhaseMap phase_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompilationStatistics);
+};
+
+std::ostream& operator<<(std::ostream& os, const CompilationStatistics& s);
+
+}  // namespace internal
+}  // namespace v8
+
+#endif
diff --git a/src/compiler.cc b/src/compiler.cc
index ea604c9..3b52aa2 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -6,6 +6,8 @@
 
 #include "src/compiler.h"
 
+#include "src/ast-numbering.h"
+#include "src/ast-this-access-visitor.h"
 #include "src/bootstrapper.h"
 #include "src/codegen.h"
 #include "src/compilation-cache.h"
@@ -19,6 +21,7 @@
 #include "src/isolate-inl.h"
 #include "src/lithium.h"
 #include "src/liveedit.h"
+#include "src/messages.h"
 #include "src/parser.h"
 #include "src/rewriter.h"
 #include "src/runtime-profiler.h"
@@ -33,7 +36,7 @@
 
 
 ScriptData::ScriptData(const byte* data, int length)
-    : owns_data_(false), data_(data), length_(length) {
+    : owns_data_(false), rejected_(false), data_(data), length_(length) {
   if (!IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment)) {
     byte* copy = NewArray<byte>(length);
     DCHECK(IsAligned(reinterpret_cast<intptr_t>(copy), kPointerAlignment));
@@ -143,7 +146,7 @@
   isolate_ = isolate;
   function_ = NULL;
   scope_ = NULL;
-  global_scope_ = NULL;
+  script_scope_ = NULL;
   extension_ = NULL;
   cached_data_ = NULL;
   compile_options_ = ScriptCompiler::kNoCompileOptions;
@@ -165,6 +168,14 @@
   if (!script_.is_null() && script_->type()->value() == Script::TYPE_NATIVE) {
     MarkAsNative();
   }
+  // Compiling for the snapshot typically results in different code than
+  // compiling later on. This means that code recompiled with deoptimization
+  // support won't be "equivalent" (as defined by SharedFunctionInfo::
+  // EnableDeoptimizationSupport), so it will replace the old code and all
+  // its type feedback. To avoid this, always compile functions in the snapshot
+  // with deoptimization support.
+  if (isolate_->serializer_enabled()) EnableDeoptimizationSupport();
+
   if (isolate_->debug()->is_active()) MarkAsDebug();
   if (FLAG_context_specialization) MarkAsContextSpecializing();
   if (FLAG_turbo_inlining) MarkAsInliningEnabled();
@@ -282,13 +293,14 @@
 void CompilationInfo::PrepareForCompilation(Scope* scope) {
   DCHECK(scope_ == NULL);
   scope_ = scope;
+}
 
-  int length = function()->slot_count();
+
+void CompilationInfo::EnsureFeedbackVector() {
   if (feedback_vector_.is_null()) {
-    // Allocate the feedback vector too.
-    feedback_vector_ = isolate()->factory()->NewTypeFeedbackVector(length);
+    feedback_vector_ = isolate()->factory()->NewTypeFeedbackVector(
+        function()->feedback_vector_spec());
   }
-  DCHECK(feedback_vector_->length() == length);
 }
 
 
@@ -298,29 +310,29 @@
       : HOptimizedGraphBuilder(info) {
   }
 
-#define DEF_VISIT(type)                                 \
-  virtual void Visit##type(type* node) OVERRIDE {    \
-    if (node->position() != RelocInfo::kNoPosition) {   \
-      SetSourcePosition(node->position());              \
-    }                                                   \
-    HOptimizedGraphBuilder::Visit##type(node);          \
+#define DEF_VISIT(type)                               \
+  void Visit##type(type* node) OVERRIDE {             \
+    if (node->position() != RelocInfo::kNoPosition) { \
+      SetSourcePosition(node->position());            \
+    }                                                 \
+    HOptimizedGraphBuilder::Visit##type(node);        \
   }
   EXPRESSION_NODE_LIST(DEF_VISIT)
 #undef DEF_VISIT
 
-#define DEF_VISIT(type)                                          \
-  virtual void Visit##type(type* node) OVERRIDE {             \
-    if (node->position() != RelocInfo::kNoPosition) {            \
-      SetSourcePosition(node->position());                       \
-    }                                                            \
-    HOptimizedGraphBuilder::Visit##type(node);                   \
+#define DEF_VISIT(type)                               \
+  void Visit##type(type* node) OVERRIDE {             \
+    if (node->position() != RelocInfo::kNoPosition) { \
+      SetSourcePosition(node->position());            \
+    }                                                 \
+    HOptimizedGraphBuilder::Visit##type(node);        \
   }
   STATEMENT_NODE_LIST(DEF_VISIT)
 #undef DEF_VISIT
 
-#define DEF_VISIT(type)                                            \
-  virtual void Visit##type(type* node) OVERRIDE {               \
-    HOptimizedGraphBuilder::Visit##type(node);                     \
+#define DEF_VISIT(type)                        \
+  void Visit##type(type* node) OVERRIDE {      \
+    HOptimizedGraphBuilder::Visit##type(node); \
   }
   MODULE_NODE_LIST(DEF_VISIT)
   DECLARATION_NODE_LIST(DEF_VISIT)
@@ -329,13 +341,14 @@
 
 
 OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
-  DCHECK(isolate()->use_crankshaft());
   DCHECK(info()->IsOptimizing());
   DCHECK(!info()->IsCompilingForDebugging());
 
-  // We should never arrive here if optimization has been disabled on the
-  // shared function info.
-  DCHECK(!info()->shared_info()->optimization_disabled());
+  // Optimization could have been disabled by the parser.
+  if (info()->shared_info()->optimization_disabled()) {
+    return AbortOptimization(
+        info()->shared_info()->disable_optimization_reason());
+  }
 
   // Do not use crankshaft if we need to be able to set break points.
   if (isolate()->DebuggerHasBreakPoints()) {
@@ -402,20 +415,26 @@
   // Check the whitelist for TurboFan.
   if ((FLAG_turbo_asm && info()->shared_info()->asm_function()) ||
       info()->closure()->PassesFilter(FLAG_turbo_filter)) {
+    if (FLAG_trace_opt) {
+      OFStream os(stdout);
+      os << "[compiling method " << Brief(*info()->closure())
+         << " using TurboFan]" << std::endl;
+    }
+    Timer t(this, &time_taken_to_create_graph_);
     compiler::Pipeline pipeline(info());
     pipeline.GenerateCode();
     if (!info()->code().is_null()) {
-      if (FLAG_turbo_deoptimization) {
-        info()->context()->native_context()->AddOptimizedCode(*info()->code());
-      }
       return SetLastStatus(SUCCEEDED);
     }
   }
 
+  if (FLAG_trace_opt) {
+    OFStream os(stdout);
+    os << "[compiling method " << Brief(*info()->closure())
+       << " using Crankshaft]" << std::endl;
+  }
+
   if (FLAG_trace_hydrogen) {
-    Handle<String> name = info()->function()->debug_name();
-    PrintF("-----------------------------------------------------------\n");
-    PrintF("Compiling method %s using hydrogen\n", name->ToCString().get());
     isolate()->GetHTracer()->TraceCompilation(info());
   }
 
@@ -476,6 +495,9 @@
   DCHECK(last_status() == SUCCEEDED);
   // TODO(turbofan): Currently everything is done in the first phase.
   if (!info()->code().is_null()) {
+    if (FLAG_turbo_deoptimization) {
+      info()->context()->native_context()->AddOptimizedCode(*info()->code());
+    }
     RecordOptimizationStats();
     return last_status();
   }
@@ -557,18 +579,24 @@
   // the estimate conservatively.
   if (shared->GetIsolate()->serializer_enabled()) {
     estimate += 2;
-  } else if (FLAG_clever_optimizations) {
+  } else {
     // Inobject slack tracking will reclaim redundant inobject space later,
     // so we can afford to adjust the estimate generously.
     estimate += 8;
-  } else {
-    estimate += 3;
   }
 
   shared->set_expected_nof_properties(estimate);
 }
 
 
+static void MaybeDisableOptimization(Handle<SharedFunctionInfo> shared_info,
+                                     BailoutReason bailout_reason) {
+  if (bailout_reason != kNoReason) {
+    shared_info->DisableOptimization(bailout_reason);
+  }
+}
+
+
 // Sets the function info on a function.
 // The start_position points to the first '(' character after the function name
 // in the full script source. When counting characters in the script source the
@@ -595,9 +623,12 @@
   function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
   function_info->set_ast_node_count(lit->ast_node_count());
   function_info->set_is_function(lit->is_function());
-  function_info->set_bailout_reason(lit->dont_optimize_reason());
+  MaybeDisableOptimization(function_info, lit->dont_optimize_reason());
   function_info->set_dont_cache(lit->flags()->Contains(kDontCache));
   function_info->set_kind(lit->kind());
+  function_info->set_uses_super_property(lit->uses_super_property());
+  function_info->set_uses_super_constructor_call(
+      lit->uses_super_constructor_call());
   function_info->set_asm_function(lit->scope()->asm_function());
 }
 
@@ -638,12 +669,7 @@
 
 static bool CompileUnoptimizedCode(CompilationInfo* info) {
   DCHECK(AllowCompilation::IsAllowed(info->isolate()));
-  DCHECK(info->function() != NULL);
-  if (!Rewriter::Rewrite(info)) return false;
-  if (!Scope::Analyze(info)) return false;
-  DCHECK(info->scope() != NULL);
-
-  if (!FullCodeGenerator::MakeCode(info)) {
+  if (!Compiler::Analyze(info) || !FullCodeGenerator::MakeCode(info)) {
     Isolate* isolate = info->isolate();
     if (!isolate->has_pending_exception()) isolate->StackOverflow();
     return false;
@@ -663,8 +689,7 @@
   FunctionLiteral* lit = info->function();
   shared->set_strict_mode(lit->strict_mode());
   SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
-  shared->set_bailout_reason(lit->dont_optimize_reason());
-  shared->set_ast_node_count(lit->ast_node_count());
+  MaybeDisableOptimization(shared, lit->dont_optimize_reason());
 
   // Compile unoptimized code.
   if (!CompileUnoptimizedCode(info)) return MaybeHandle<Code>();
@@ -734,17 +759,107 @@
 }
 
 
-static bool CompileOptimizedPrologue(CompilationInfo* info) {
-  if (!Parser::Parse(info)) return false;
-  if (!Rewriter::Rewrite(info)) return false;
-  if (!Scope::Analyze(info)) return false;
-  DCHECK(info->scope() != NULL);
+static bool Renumber(CompilationInfo* info) {
+  if (!AstNumbering::Renumber(info->function(), info->zone())) return false;
+  if (!info->shared_info().is_null()) {
+    FunctionLiteral* lit = info->function();
+    info->shared_info()->set_ast_node_count(lit->ast_node_count());
+    MaybeDisableOptimization(info->shared_info(), lit->dont_optimize_reason());
+    info->shared_info()->set_dont_cache(lit->flags()->Contains(kDontCache));
+  }
   return true;
 }
 
 
+static void ThrowSuperConstructorCheckError(CompilationInfo* info,
+                                            Statement* stmt) {
+  MaybeHandle<Object> obj = info->isolate()->factory()->NewTypeError(
+      "super_constructor_call", HandleVector<Object>(nullptr, 0));
+  Handle<Object> exception;
+  if (!obj.ToHandle(&exception)) return;
+
+  MessageLocation location(info->script(), stmt->position(), stmt->position());
+  USE(info->isolate()->Throw(*exception, &location));
+}
+
+
+static bool CheckSuperConstructorCall(CompilationInfo* info) {
+  FunctionLiteral* function = info->function();
+  if (!function->uses_super_constructor_call()) return true;
+
+  if (function->is_default_constructor()) return true;
+
+  ZoneList<Statement*>* body = function->body();
+  CHECK(body->length() > 0);
+
+  int super_call_index = 0;
+  // Allow 'use strict' and similiar and empty statements.
+  while (true) {
+    CHECK(super_call_index < body->length());  // We know there is a super call.
+    Statement* stmt = body->at(super_call_index);
+    if (stmt->IsExpressionStatement() &&
+        stmt->AsExpressionStatement()->expression()->IsLiteral()) {
+      super_call_index++;
+      continue;
+    }
+    if (stmt->IsEmptyStatement()) {
+      super_call_index++;
+      continue;
+    }
+    break;
+  }
+
+  Statement* stmt = body->at(super_call_index);
+  ExpressionStatement* exprStm = stmt->AsExpressionStatement();
+  if (exprStm == nullptr) {
+    ThrowSuperConstructorCheckError(info, stmt);
+    return false;
+  }
+  Call* callExpr = exprStm->expression()->AsCall();
+  if (callExpr == nullptr) {
+    ThrowSuperConstructorCheckError(info, stmt);
+    return false;
+  }
+
+  if (!callExpr->expression()->IsSuperReference()) {
+    ThrowSuperConstructorCheckError(info, stmt);
+    return false;
+  }
+
+  ZoneList<Expression*>* arguments = callExpr->arguments();
+
+  AstThisAccessVisitor this_access_visitor(info->zone());
+  this_access_visitor.VisitExpressions(arguments);
+
+  if (this_access_visitor.HasStackOverflow()) return false;
+  if (this_access_visitor.UsesThis()) {
+    ThrowSuperConstructorCheckError(info, stmt);
+    return false;
+  }
+
+  return true;
+}
+
+
+bool Compiler::Analyze(CompilationInfo* info) {
+  DCHECK(info->function() != NULL);
+  if (!Rewriter::Rewrite(info)) return false;
+  if (!Scope::Analyze(info)) return false;
+  if (!Renumber(info)) return false;
+  DCHECK(info->scope() != NULL);
+  if (!CheckSuperConstructorCall(info)) return false;
+  return true;
+}
+
+
+bool Compiler::ParseAndAnalyze(CompilationInfo* info) {
+  if (!Parser::Parse(info)) return false;
+  return Compiler::Analyze(info);
+}
+
+
 static bool GetOptimizedCodeNow(CompilationInfo* info) {
-  if (!CompileOptimizedPrologue(info)) return false;
+  if (!Compiler::ParseAndAnalyze(info)) return false;
 
   TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate());
 
@@ -765,11 +880,6 @@
   InsertCodeIntoOptimizedCodeMap(info);
   RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info,
                             info->shared_info());
-  if (FLAG_trace_opt) {
-    PrintF("[completed optimizing ");
-    info->closure()->ShortPrint();
-    PrintF("]\n");
-  }
   return true;
 }
 
@@ -786,7 +896,7 @@
   }
 
   CompilationHandleScope handle_scope(info);
-  if (!CompileOptimizedPrologue(info)) return false;
+  if (!Compiler::ParseAndAnalyze(info)) return false;
   info->SaveHandles();  // Copy handles to the compilation handle scope.
 
   TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate());
@@ -826,23 +936,25 @@
 
 
 MaybeHandle<Code> Compiler::GetLazyCode(Handle<JSFunction> function) {
-  DCHECK(!function->GetIsolate()->has_pending_exception());
+  Isolate* isolate = function->GetIsolate();
+  DCHECK(!isolate->has_pending_exception());
   DCHECK(!function->is_compiled());
-
-  if (FLAG_turbo_asm && function->shared()->asm_function()) {
+  // If the debugger is active, do not compile with turbofan unless we can
+  // deopt from turbofan code.
+  if (FLAG_turbo_asm && function->shared()->asm_function() &&
+      (FLAG_turbo_deoptimization || !isolate->debug()->is_active())) {
     CompilationInfoWithZone info(function);
 
-    VMState<COMPILER> state(info.isolate());
-    PostponeInterruptsScope postpone(info.isolate());
+    VMState<COMPILER> state(isolate);
+    PostponeInterruptsScope postpone(isolate);
 
-    info.SetOptimizing(BailoutId::None(),
-                       Handle<Code>(function->shared()->code()));
-
+    info.SetOptimizing(BailoutId::None(), handle(function->shared()->code()));
     info.MarkAsContextSpecializing();
-    info.MarkAsTypingEnabled();
-    info.MarkAsInliningDisabled();
 
-    if (GetOptimizedCodeNow(&info)) return info.code();
+    if (GetOptimizedCodeNow(&info)) {
+      DCHECK(function->shared()->is_compiled());
+      return info.code();
+    }
   }
 
   if (function->shared()->is_compiled()) {
@@ -851,13 +963,12 @@
 
   CompilationInfoWithZone info(function);
   Handle<Code> result;
-  ASSIGN_RETURN_ON_EXCEPTION(info.isolate(), result,
-                             GetUnoptimizedCodeCommon(&info), Code);
+  ASSIGN_RETURN_ON_EXCEPTION(isolate, result, GetUnoptimizedCodeCommon(&info),
+                             Code);
 
-  if (FLAG_always_opt &&
-      info.isolate()->use_crankshaft() &&
+  if (FLAG_always_opt && isolate->use_crankshaft() &&
       !info.shared_info()->optimization_disabled() &&
-      !info.isolate()->DebuggerHasBreakPoints()) {
+      !isolate->DebuggerHasBreakPoints()) {
     Handle<Code> opt_code;
     if (Compiler::GetOptimizedCode(
             function, result,
@@ -900,17 +1011,26 @@
 // TODO(turbofan): In the future, unoptimized code with deopt support could
 // be generated lazily once deopt is triggered.
 bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) {
+  DCHECK(info->function() != NULL);
+  DCHECK(info->scope() != NULL);
   if (!info->shared_info()->has_deoptimization_support()) {
-    CompilationInfoWithZone unoptimized(info->shared_info());
+    Handle<SharedFunctionInfo> shared = info->shared_info();
+    CompilationInfoWithZone unoptimized(shared);
     // Note that we use the same AST that we will use for generating the
     // optimized code.
     unoptimized.SetFunction(info->function());
     unoptimized.PrepareForCompilation(info->scope());
     unoptimized.SetContext(info->context());
     unoptimized.EnableDeoptimizationSupport();
+    // If the current code has reloc info for serialization, also include
+    // reloc info for serialization for the new code, so that deopt support
+    // can be added without losing IC state.
+    if (shared->code()->kind() == Code::FUNCTION &&
+        shared->code()->has_reloc_info_for_serialization()) {
+      unoptimized.PrepareForSerializing();
+    }
     if (!FullCodeGenerator::MakeCode(&unoptimized)) return false;
 
-    Handle<SharedFunctionInfo> shared = info->shared_info();
     shared->EnableDeoptimizationSupport(*unoptimized.code());
     shared->set_feedback_vector(*unoptimized.feedback_vector());
 
@@ -1002,6 +1122,8 @@
 
   DCHECK(info->is_eval() || info->is_global());
 
+  info->MarkAsToplevel();
+
   Handle<SharedFunctionInfo> result;
 
   { VMState<COMPILER> state(info->isolate());
@@ -1139,19 +1261,20 @@
     int column_offset, bool is_shared_cross_origin, Handle<Context> context,
     v8::Extension* extension, ScriptData** cached_data,
     ScriptCompiler::CompileOptions compile_options, NativesFlag natives) {
+  Isolate* isolate = source->GetIsolate();
   if (compile_options == ScriptCompiler::kNoCompileOptions) {
     cached_data = NULL;
   } else if (compile_options == ScriptCompiler::kProduceParserCache ||
              compile_options == ScriptCompiler::kProduceCodeCache) {
     DCHECK(cached_data && !*cached_data);
     DCHECK(extension == NULL);
+    DCHECK(!isolate->debug()->is_loaded());
   } else {
     DCHECK(compile_options == ScriptCompiler::kConsumeParserCache ||
            compile_options == ScriptCompiler::kConsumeCodeCache);
     DCHECK(cached_data && *cached_data);
     DCHECK(extension == NULL);
   }
-  Isolate* isolate = source->GetIsolate();
   int source_length = source->length();
   isolate->counters()->total_load_size()->Increment(source_length);
   isolate->counters()->total_compile_size()->Increment(source_length);
@@ -1166,7 +1289,12 @@
         compile_options == ScriptCompiler::kConsumeCodeCache &&
         !isolate->debug()->is_loaded()) {
       HistogramTimerScope timer(isolate->counters()->compile_deserialize());
-      return CodeSerializer::Deserialize(isolate, *cached_data, source);
+      Handle<SharedFunctionInfo> result;
+      if (CodeSerializer::Deserialize(isolate, *cached_data, source)
+              .ToHandle(&result)) {
+        return result;
+      }
+      // Deserializer failed. Fall through to compile.
     } else {
       maybe_result = compilation_cache->LookupScript(
           source, script_name, line_offset, column_offset,
@@ -1216,8 +1344,8 @@
             isolate->counters()->compile_serialize());
         *cached_data = CodeSerializer::Serialize(isolate, result, source);
         if (FLAG_profile_deserialization) {
-          PrintF("[Compiling and serializing %d bytes took %0.3f ms]\n",
-                 (*cached_data)->length(), timer.Elapsed().InMillisecondsF());
+          PrintF("[Compiling and serializing took %0.3f ms]\n",
+                 timer.Elapsed().InMillisecondsF());
         }
       }
     }
@@ -1269,13 +1397,30 @@
   bool allow_lazy = literal->AllowsLazyCompilation() &&
       !DebuggerWantsEagerCompilation(&info, allow_lazy_without_ctx);
 
+  if (outer_info->is_toplevel() && outer_info->will_serialize()) {
+    // Make sure that if the toplevel code (possibly to be serialized),
+    // the inner function must be allowed to be compiled lazily.
+    // This is necessary to serialize toplevel code without inner functions.
+    DCHECK(allow_lazy);
+  }
+
   // Generate code
   Handle<ScopeInfo> scope_info;
   if (FLAG_lazy && allow_lazy && !literal->is_parenthesized()) {
     Handle<Code> code = isolate->builtins()->CompileLazy();
     info.SetCode(code);
+    // There's no need in theory for a lazy-compiled function to have a type
+    // feedback vector, but some parts of the system expect all
+    // SharedFunctionInfo instances to have one.  The size of the vector depends
+    // on how many feedback-needing nodes are in the tree, and when lazily
+    // parsing we might not know that, if this function was never parsed before.
+    // In that case the vector will be replaced the next time MakeCode is
+    // called.
+    info.EnsureFeedbackVector();
     scope_info = Handle<ScopeInfo>(ScopeInfo::Empty(isolate));
-  } else if (FullCodeGenerator::MakeCode(&info)) {
+  } else if (Renumber(&info) && FullCodeGenerator::MakeCode(&info)) {
+    // MakeCode will ensure that the feedback vector is present and
+    // appropriately sized.
     DCHECK(!info.code().is_null());
     scope_info = ScopeInfo::Create(info.scope(), info.zone());
   } else {
@@ -1314,6 +1459,7 @@
   Isolate* isolate = info->isolate();
   DCHECK(AllowCompilation::IsAllowed(isolate));
   VMState<COMPILER> state(isolate);
+  DCHECK(isolate->use_crankshaft());
   DCHECK(!isolate->has_pending_exception());
   PostponeInterruptsScope postpone(isolate);
 
@@ -1399,8 +1545,10 @@
 
 bool Compiler::DebuggerWantsEagerCompilation(CompilationInfo* info,
                                              bool allow_lazy_without_ctx) {
-  return LiveEditFunctionTracker::IsActive(info->isolate()) ||
-         (info->isolate()->DebuggerHasBreakPoints() && !allow_lazy_without_ctx);
+  if (LiveEditFunctionTracker::IsActive(info->isolate())) return true;
+  Debug* debug = info->isolate()->debug();
+  bool debugging = debug->is_active() || debug->has_break_points();
+  return debugging && !allow_lazy_without_ctx;
 }
 
 
diff --git a/src/compiler.h b/src/compiler.h
index f950ef7..3db32ce 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -39,6 +39,9 @@
 
   const byte* data() const { return data_; }
   int length() const { return length_; }
+  bool rejected() const { return rejected_; }
+
+  void Reject() { rejected_ = true; }
 
   void AcquireDataOwnership() {
     DCHECK(!owns_data_);
@@ -51,7 +54,8 @@
   }
 
  private:
-  bool owns_data_;
+  bool owns_data_ : 1;
+  bool rejected_ : 1;
   const byte* data_;
   int length_;
 
@@ -84,7 +88,8 @@
     kContextSpecializing = 1 << 16,
     kInliningEnabled = 1 << 17,
     kTypingEnabled = 1 << 18,
-    kDisableFutureOptimization = 1 << 19
+    kDisableFutureOptimization = 1 << 19,
+    kToplevel = 1 << 20
   };
 
   CompilationInfo(Handle<JSFunction> closure, Zone* zone);
@@ -104,7 +109,7 @@
   }
   FunctionLiteral* function() const { return function_; }
   Scope* scope() const { return scope_; }
-  Scope* global_scope() const { return global_scope_; }
+  Scope* script_scope() const { return script_scope_; }
   Handle<Code> code() const { return code_; }
   Handle<JSFunction> closure() const { return closure_; }
   Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
@@ -199,14 +204,16 @@
 
   void MarkAsInliningEnabled() { SetFlag(kInliningEnabled); }
 
-  void MarkAsInliningDisabled() { SetFlag(kInliningEnabled, false); }
-
   bool is_inlining_enabled() const { return GetFlag(kInliningEnabled); }
 
   void MarkAsTypingEnabled() { SetFlag(kTypingEnabled); }
 
   bool is_typing_enabled() const { return GetFlag(kTypingEnabled); }
 
+  void MarkAsToplevel() { SetFlag(kToplevel); }
+
+  bool is_toplevel() const { return GetFlag(kToplevel); }
+
   bool IsCodePreAgingActive() const {
     return FLAG_optimize_for_size && FLAG_age_code && !will_serialize() &&
            !is_debug();
@@ -226,10 +233,11 @@
     function_ = literal;
   }
   void PrepareForCompilation(Scope* scope);
-  void SetGlobalScope(Scope* global_scope) {
-    DCHECK(global_scope_ == NULL);
-    global_scope_ = global_scope;
+  void SetScriptScope(Scope* script_scope) {
+    DCHECK(script_scope_ == NULL);
+    script_scope_ = script_scope;
   }
+  void EnsureFeedbackVector();
   Handle<TypeFeedbackVector> feedback_vector() const {
     return feedback_vector_;
   }
@@ -386,8 +394,6 @@
     ast_value_factory_owned_ = owned;
   }
 
-  AstNode::IdGen* ast_node_id_gen() { return &ast_node_id_gen_; }
-
  protected:
   CompilationInfo(Handle<Script> script,
                   Zone* zone);
@@ -438,8 +444,8 @@
   // The scope of the function literal as a convenience.  Set to indicate
   // that scopes have been analyzed.
   Scope* scope_;
-  // The global scope provided as a convenience.
-  Scope* global_scope_;
+  // The script scope provided as a convenience.
+  Scope* script_scope_;
   // For compiled stubs, the stub object
   HydrogenCodeStub* code_stub_;
   // The compiled code.
@@ -457,7 +463,7 @@
   ScriptData** cached_data_;
   ScriptCompiler::CompileOptions compile_options_;
 
-  // The context of the caller for eval code, and the global context for a
+  // The context of the caller for eval code, and the script context for a
   // global script. Will be a null handle otherwise.
   Handle<Context> context_;
 
@@ -507,7 +513,6 @@
 
   AstValueFactory* ast_value_factory_;
   bool ast_value_factory_owned_;
-  AstNode::IdGen ast_node_id_gen_;
 
   // This flag is used by the main thread to track whether this compilation
   // should be abandoned due to dependency change.
@@ -673,11 +678,16 @@
   MUST_USE_RESULT static MaybeHandle<Code> GetDebugCode(
       Handle<JSFunction> function);
 
+  // Parser::Parse, then Compiler::Analyze.
+  static bool ParseAndAnalyze(CompilationInfo* info);
+  // Rewrite, analyze scopes, and renumber.
+  static bool Analyze(CompilationInfo* info);
+  // Adds deoptimization support, requires ParseAndAnalyze.
+  static bool EnsureDeoptimizationSupport(CompilationInfo* info);
+
   static bool EnsureCompiled(Handle<JSFunction> function,
                              ClearExceptionFlag flag);
 
-  static bool EnsureDeoptimizationSupport(CompilationInfo* info);
-
   static void CompileForLiveEdit(Handle<Script> script);
 
   // Compile a String source within a context for eval.
diff --git a/src/compiler/access-builder.cc b/src/compiler/access-builder.cc
index ac9cfa8..8c8e530 100644
--- a/src/compiler/access-builder.cc
+++ b/src/compiler/access-builder.cc
@@ -11,43 +11,73 @@
 
 // static
 FieldAccess AccessBuilder::ForMap() {
-  return {kTaggedBase, HeapObject::kMapOffset, Handle<Name>(), Type::Any(),
+  return {kTaggedBase, HeapObject::kMapOffset, MaybeHandle<Name>(), Type::Any(),
           kMachAnyTagged};
 }
 
 
 // static
 FieldAccess AccessBuilder::ForJSObjectProperties() {
-  return {kTaggedBase, JSObject::kPropertiesOffset, Handle<Name>(), Type::Any(),
-          kMachAnyTagged};
+  return {kTaggedBase, JSObject::kPropertiesOffset, MaybeHandle<Name>(),
+          Type::Any(), kMachAnyTagged};
 }
 
 
 // static
 FieldAccess AccessBuilder::ForJSObjectElements() {
-  return {kTaggedBase, JSObject::kElementsOffset, Handle<Name>(),
+  return {kTaggedBase, JSObject::kElementsOffset, MaybeHandle<Name>(),
           Type::Internal(), kMachAnyTagged};
 }
 
 
 // static
 FieldAccess AccessBuilder::ForJSFunctionContext() {
-  return {kTaggedBase, JSFunction::kContextOffset, Handle<Name>(),
+  return {kTaggedBase, JSFunction::kContextOffset, MaybeHandle<Name>(),
           Type::Internal(), kMachAnyTagged};
 }
 
 
 // static
 FieldAccess AccessBuilder::ForJSArrayBufferBackingStore() {
-  return {kTaggedBase, JSArrayBuffer::kBackingStoreOffset, Handle<Name>(),
-          Type::UntaggedPtr(), kMachPtr};
+  return {kTaggedBase, JSArrayBuffer::kBackingStoreOffset, MaybeHandle<Name>(),
+          Type::UntaggedPointer(), kMachPtr};
 }
 
 
 // static
 FieldAccess AccessBuilder::ForExternalArrayPointer() {
-  return {kTaggedBase, ExternalArray::kExternalPointerOffset, Handle<Name>(),
-          Type::UntaggedPtr(), kMachPtr};
+  return {kTaggedBase, ExternalArray::kExternalPointerOffset,
+          MaybeHandle<Name>(), Type::UntaggedPointer(), kMachPtr};
+}
+
+
+// static
+FieldAccess AccessBuilder::ForMapInstanceType() {
+  return {kTaggedBase, Map::kInstanceTypeOffset, Handle<Name>(),
+          Type::UntaggedUnsigned8(), kMachUint8};
+}
+
+
+// static
+FieldAccess AccessBuilder::ForStringLength() {
+  return {kTaggedBase, String::kLengthOffset, Handle<Name>(),
+          Type::SignedSmall(), kMachAnyTagged};
+}
+
+
+// static
+FieldAccess AccessBuilder::ForValue() {
+  return {kTaggedBase, JSValue::kValueOffset, Handle<Name>(), Type::Any(),
+          kMachAnyTagged};
+}
+
+
+// static
+FieldAccess AccessBuilder::ForContextSlot(size_t index) {
+  int offset = Context::kHeaderSize + static_cast<int>(index) * kPointerSize;
+  DCHECK_EQ(offset,
+            Context::SlotOffset(static_cast<int>(index)) + kHeapObjectTag);
+  return {kTaggedBase, offset, Handle<Name>(), Type::Any(), kMachAnyTagged};
 }
 
 
@@ -58,13 +88,6 @@
 
 
 // static
-ElementAccess AccessBuilder::ForBackingStoreElement(MachineType rep) {
-  return {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
-          rep};
-}
-
-
-// static
 ElementAccess AccessBuilder::ForTypedArrayElement(ExternalArrayType type,
                                                   bool is_external) {
   BaseTaggedness taggedness = is_external ? kUntaggedBase : kTaggedBase;
@@ -84,9 +107,9 @@
     case kExternalUint32Array:
       return {taggedness, header_size, Type::Unsigned32(), kMachUint32};
     case kExternalFloat32Array:
-      return {taggedness, header_size, Type::Number(), kRepFloat32};
+      return {taggedness, header_size, Type::Number(), kMachFloat32};
     case kExternalFloat64Array:
-      return {taggedness, header_size, Type::Number(), kRepFloat64};
+      return {taggedness, header_size, Type::Number(), kMachFloat64};
   }
   UNREACHABLE();
   return {kUntaggedBase, 0, Type::None(), kMachNone};
diff --git a/src/compiler/access-builder.h b/src/compiler/access-builder.h
index 7d0bda1..d6385e4 100644
--- a/src/compiler/access-builder.h
+++ b/src/compiler/access-builder.h
@@ -34,12 +34,21 @@
   // Provides access to ExternalArray::external_pointer() field.
   static FieldAccess ForExternalArrayPointer();
 
+  // Provides access to Map::instance_type() field.
+  static FieldAccess ForMapInstanceType();
+
+  // Provides access to String::length() field.
+  static FieldAccess ForStringLength();
+
+  // Provides access to JSValue::value() field.
+  static FieldAccess ForValue();
+
+  // Provides access Context slots.
+  static FieldAccess ForContextSlot(size_t index);
+
   // Provides access to FixedArray elements.
   static ElementAccess ForFixedArrayElement();
 
-  // TODO(mstarzinger): Raw access only for testing, drop me.
-  static ElementAccess ForBackingStoreElement(MachineType rep);
-
   // Provides access to Fixed{type}TypedArray and External{type}Array elements.
   static ElementAccess ForTypedArrayElement(ExternalArrayType type,
                                             bool is_external);
diff --git a/src/compiler/arm/code-generator-arm.cc b/src/compiler/arm/code-generator-arm.cc
index 1ec174d..cfa4de9 100644
--- a/src/compiler/arm/code-generator-arm.cc
+++ b/src/compiler/arm/code-generator-arm.cc
@@ -22,11 +22,35 @@
 
 
 // Adds Arm-specific methods to convert InstructionOperands.
-class ArmOperandConverter : public InstructionOperandConverter {
+class ArmOperandConverter FINAL : public InstructionOperandConverter {
  public:
   ArmOperandConverter(CodeGenerator* gen, Instruction* instr)
       : InstructionOperandConverter(gen, instr) {}
 
+  SwVfpRegister OutputFloat32Register(int index = 0) {
+    return ToFloat32Register(instr_->OutputAt(index));
+  }
+
+  SwVfpRegister InputFloat32Register(int index) {
+    return ToFloat32Register(instr_->InputAt(index));
+  }
+
+  SwVfpRegister ToFloat32Register(InstructionOperand* op) {
+    return ToFloat64Register(op).low();
+  }
+
+  LowDwVfpRegister OutputFloat64Register(int index = 0) {
+    return ToFloat64Register(instr_->OutputAt(index));
+  }
+
+  LowDwVfpRegister InputFloat64Register(int index) {
+    return ToFloat64Register(instr_->InputAt(index));
+  }
+
+  LowDwVfpRegister ToFloat64Register(InstructionOperand* op) {
+    return LowDwVfpRegister::from_code(ToDoubleRegister(op).code());
+  }
+
   SBit OutputSBit() const {
     switch (instr_->flags_mode()) {
       case kFlags_branch:
@@ -44,12 +68,16 @@
     switch (constant.type()) {
       case Constant::kInt32:
         return Operand(constant.ToInt32());
+      case Constant::kFloat32:
+        return Operand(
+            isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
       case Constant::kFloat64:
         return Operand(
             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
       case Constant::kInt64:
       case Constant::kExternalReference:
       case Constant::kHeapObject:
+      case Constant::kRpoNumber:
         break;
     }
     UNREACHABLE();
@@ -114,9 +142,8 @@
     return MemOperand(r0);
   }
 
-  MemOperand InputOffset() {
-    int index = 0;
-    return InputOffset(&index);
+  MemOperand InputOffset(int first_index = 0) {
+    return InputOffset(&first_index);
   }
 
   MemOperand ToMemOperand(InstructionOperand* op) const {
@@ -131,6 +158,112 @@
 };
 
 
+namespace {
+
+class OutOfLineLoadFloat32 FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadFloat32(CodeGenerator* gen, SwVfpRegister result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL {
+    __ vmov(result_, std::numeric_limits<float>::quiet_NaN());
+  }
+
+ private:
+  SwVfpRegister const result_;
+};
+
+
+class OutOfLineLoadFloat64 FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadFloat64(CodeGenerator* gen, DwVfpRegister result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL {
+    __ vmov(result_, std::numeric_limits<double>::quiet_NaN(), kScratchReg);
+  }
+
+ private:
+  DwVfpRegister const result_;
+};
+
+
+class OutOfLineLoadInteger FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadInteger(CodeGenerator* gen, Register result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL { __ mov(result_, Operand::Zero()); }
+
+ private:
+  Register const result_;
+};
+
+}  // namespace
+
+
+#define ASSEMBLE_CHECKED_LOAD_FLOAT(width)                           \
+  do {                                                               \
+    auto result = i.OutputFloat##width##Register();                  \
+    auto offset = i.InputRegister(0);                                \
+    if (instr->InputAt(1)->IsRegister()) {                           \
+      __ cmp(offset, i.InputRegister(1));                            \
+    } else {                                                         \
+      __ cmp(offset, i.InputImmediate(1));                           \
+    }                                                                \
+    auto ool = new (zone()) OutOfLineLoadFloat##width(this, result); \
+    __ b(hs, ool->entry());                                          \
+    __ vldr(result, i.InputOffset(2));                               \
+    __ bind(ool->exit());                                            \
+    DCHECK_EQ(LeaveCC, i.OutputSBit());                              \
+  } while (0)
+
+
+#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                \
+  do {                                                          \
+    auto result = i.OutputRegister();                           \
+    auto offset = i.InputRegister(0);                           \
+    if (instr->InputAt(1)->IsRegister()) {                      \
+      __ cmp(offset, i.InputRegister(1));                       \
+    } else {                                                    \
+      __ cmp(offset, i.InputImmediate(1));                      \
+    }                                                           \
+    auto ool = new (zone()) OutOfLineLoadInteger(this, result); \
+    __ b(hs, ool->entry());                                     \
+    __ asm_instr(result, i.InputOffset(2));                     \
+    __ bind(ool->exit());                                       \
+    DCHECK_EQ(LeaveCC, i.OutputSBit());                         \
+  } while (0)
+
+
+#define ASSEMBLE_CHECKED_STORE_FLOAT(width)        \
+  do {                                             \
+    auto offset = i.InputRegister(0);              \
+    if (instr->InputAt(1)->IsRegister()) {         \
+      __ cmp(offset, i.InputRegister(1));          \
+    } else {                                       \
+      __ cmp(offset, i.InputImmediate(1));         \
+    }                                              \
+    auto value = i.InputFloat##width##Register(2); \
+    __ vstr(value, i.InputOffset(3), lo);          \
+    DCHECK_EQ(LeaveCC, i.OutputSBit());            \
+  } while (0)
+
+
+#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
+  do {                                            \
+    auto offset = i.InputRegister(0);             \
+    if (instr->InputAt(1)->IsRegister()) {        \
+      __ cmp(offset, i.InputRegister(1));         \
+    } else {                                      \
+      __ cmp(offset, i.InputImmediate(1));        \
+    }                                             \
+    auto value = i.InputRegister(2);              \
+    __ asm_instr(value, i.InputOffset(3), lo);    \
+    DCHECK_EQ(LeaveCC, i.OutputSBit());           \
+  } while (0)
+
+
 // Assembles an instruction after register allocation, producing machine code.
 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
   ArmOperandConverter i(this, instr);
@@ -166,7 +299,7 @@
       break;
     }
     case kArchJmp:
-      __ b(code_->GetLabel(i.InputBlock(0)));
+      AssembleArchJump(i.InputRpo(0));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArchNop:
@@ -177,8 +310,12 @@
       AssembleReturn();
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
+    case kArchStackPointer:
+      __ mov(i.OutputRegister(), sp);
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
     case kArchTruncateDoubleToI:
-      __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
+      __ TruncateDoubleToI(i.OutputRegister(), i.InputFloat64Register(0));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmAdd:
@@ -208,6 +345,19 @@
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
+    case kArmSmmul:
+      __ smmul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmSmmla:
+      __ smmla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
+               i.InputRegister(2));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmUmull:
+      __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
+               i.InputRegister(1), i.OutputSBit());
+      break;
     case kArmSdiv: {
       CpuFeatureScope scope(masm(), SUDIV);
       __ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
@@ -255,6 +405,42 @@
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
+    case kArmSxtb:
+      __ sxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmSxth:
+      __ sxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmSxtab:
+      __ sxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
+               i.InputInt32(2));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmSxtah:
+      __ sxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
+               i.InputInt32(2));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmUxtb:
+      __ uxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmUxth:
+      __ uxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmUxtab:
+      __ uxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
+               i.InputInt32(2));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmUxtah:
+      __ uxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
+               i.InputInt32(2));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
     case kArmCmp:
       __ cmp(i.InputRegister(0), i.InputOperand2(1));
       DCHECK_EQ(SetCC, i.OutputSBit());
@@ -272,38 +458,38 @@
       DCHECK_EQ(SetCC, i.OutputSBit());
       break;
     case kArmVcmpF64:
-      __ VFPCompareAndSetFlags(i.InputDoubleRegister(0),
-                               i.InputDoubleRegister(1));
+      __ VFPCompareAndSetFlags(i.InputFloat64Register(0),
+                               i.InputFloat64Register(1));
       DCHECK_EQ(SetCC, i.OutputSBit());
       break;
     case kArmVaddF64:
-      __ vadd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
-              i.InputDoubleRegister(1));
+      __ vadd(i.OutputFloat64Register(), i.InputFloat64Register(0),
+              i.InputFloat64Register(1));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVsubF64:
-      __ vsub(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
-              i.InputDoubleRegister(1));
+      __ vsub(i.OutputFloat64Register(), i.InputFloat64Register(0),
+              i.InputFloat64Register(1));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVmulF64:
-      __ vmul(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
-              i.InputDoubleRegister(1));
+      __ vmul(i.OutputFloat64Register(), i.InputFloat64Register(0),
+              i.InputFloat64Register(1));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVmlaF64:
-      __ vmla(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
-              i.InputDoubleRegister(2));
+      __ vmla(i.OutputFloat64Register(), i.InputFloat64Register(1),
+              i.InputFloat64Register(2));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVmlsF64:
-      __ vmls(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
-              i.InputDoubleRegister(2));
+      __ vmls(i.OutputFloat64Register(), i.InputFloat64Register(1),
+              i.InputFloat64Register(2));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVdivF64:
-      __ vdiv(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
-              i.InputDoubleRegister(1));
+      __ vdiv(i.OutputFloat64Register(), i.InputFloat64Register(0),
+              i.InputFloat64Register(1));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     case kArmVmodF64: {
@@ -311,45 +497,67 @@
       // and generate a CallAddress instruction instead.
       FrameScope scope(masm(), StackFrame::MANUAL);
       __ PrepareCallCFunction(0, 2, kScratchReg);
-      __ MovToFloatParameters(i.InputDoubleRegister(0),
-                              i.InputDoubleRegister(1));
+      __ MovToFloatParameters(i.InputFloat64Register(0),
+                              i.InputFloat64Register(1));
       __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
                        0, 2);
       // Move the result in the double result register.
-      __ MovFromFloatResult(i.OutputDoubleRegister());
+      __ MovFromFloatResult(i.OutputFloat64Register());
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
-    case kArmVnegF64:
-      __ vneg(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
-      break;
     case kArmVsqrtF64:
-      __ vsqrt(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
+      __ vsqrt(i.OutputFloat64Register(), i.InputFloat64Register(0));
       break;
+    case kArmVfloorF64:
+      __ vrintm(i.OutputFloat64Register(), i.InputFloat64Register(0));
+      break;
+    case kArmVceilF64:
+      __ vrintp(i.OutputFloat64Register(), i.InputFloat64Register(0));
+      break;
+    case kArmVroundTruncateF64:
+      __ vrintz(i.OutputFloat64Register(), i.InputFloat64Register(0));
+      break;
+    case kArmVroundTiesAwayF64:
+      __ vrinta(i.OutputFloat64Register(), i.InputFloat64Register(0));
+      break;
+    case kArmVnegF64:
+      __ vneg(i.OutputFloat64Register(), i.InputFloat64Register(0));
+      break;
+    case kArmVcvtF32F64: {
+      __ vcvt_f32_f64(i.OutputFloat32Register(), i.InputFloat64Register(0));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    }
+    case kArmVcvtF64F32: {
+      __ vcvt_f64_f32(i.OutputFloat64Register(), i.InputFloat32Register(0));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    }
     case kArmVcvtF64S32: {
       SwVfpRegister scratch = kScratchDoubleReg.low();
       __ vmov(scratch, i.InputRegister(0));
-      __ vcvt_f64_s32(i.OutputDoubleRegister(), scratch);
+      __ vcvt_f64_s32(i.OutputFloat64Register(), scratch);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
     case kArmVcvtF64U32: {
       SwVfpRegister scratch = kScratchDoubleReg.low();
       __ vmov(scratch, i.InputRegister(0));
-      __ vcvt_f64_u32(i.OutputDoubleRegister(), scratch);
+      __ vcvt_f64_u32(i.OutputFloat64Register(), scratch);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
     case kArmVcvtS32F64: {
       SwVfpRegister scratch = kScratchDoubleReg.low();
-      __ vcvt_s32_f64(scratch, i.InputDoubleRegister(0));
+      __ vcvt_s32_f64(scratch, i.InputFloat64Register(0));
       __ vmov(i.OutputRegister(), scratch);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
     case kArmVcvtU32F64: {
       SwVfpRegister scratch = kScratchDoubleReg.low();
-      __ vcvt_u32_f64(scratch, i.InputDoubleRegister(0));
+      __ vcvt_u32_f64(scratch, i.InputFloat64Register(0));
       __ vmov(i.OutputRegister(), scratch);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
@@ -392,30 +600,26 @@
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
-    case kArmVldr32: {
-      SwVfpRegister scratch = kScratchDoubleReg.low();
-      __ vldr(scratch, i.InputOffset());
-      __ vcvt_f64_f32(i.OutputDoubleRegister(), scratch);
+    case kArmVldrF32: {
+      __ vldr(i.OutputFloat32Register(), i.InputOffset());
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
-    case kArmVstr32: {
+    case kArmVstrF32: {
       int index = 0;
-      SwVfpRegister scratch = kScratchDoubleReg.low();
       MemOperand operand = i.InputOffset(&index);
-      __ vcvt_f32_f64(scratch, i.InputDoubleRegister(index));
-      __ vstr(scratch, operand);
+      __ vstr(i.InputFloat32Register(index), operand);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
-    case kArmVldr64:
-      __ vldr(i.OutputDoubleRegister(), i.InputOffset());
+    case kArmVldrF64:
+      __ vldr(i.OutputFloat64Register(), i.InputOffset());
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
-    case kArmVstr64: {
+    case kArmVstrF64: {
       int index = 0;
       MemOperand operand = i.InputOffset(&index);
-      __ vstr(i.InputDoubleRegister(index), operand);
+      __ vstr(i.InputFloat64Register(index), operand);
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
@@ -436,33 +640,62 @@
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
+    case kCheckedLoadInt8:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsb);
+      break;
+    case kCheckedLoadUint8:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(ldrb);
+      break;
+    case kCheckedLoadInt16:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsh);
+      break;
+    case kCheckedLoadUint16:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(ldrh);
+      break;
+    case kCheckedLoadWord32:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(ldr);
+      break;
+    case kCheckedLoadFloat32:
+      ASSEMBLE_CHECKED_LOAD_FLOAT(32);
+      break;
+    case kCheckedLoadFloat64:
+      ASSEMBLE_CHECKED_LOAD_FLOAT(64);
+      break;
+    case kCheckedStoreWord8:
+      ASSEMBLE_CHECKED_STORE_INTEGER(strb);
+      break;
+    case kCheckedStoreWord16:
+      ASSEMBLE_CHECKED_STORE_INTEGER(strh);
+      break;
+    case kCheckedStoreWord32:
+      ASSEMBLE_CHECKED_STORE_INTEGER(str);
+      break;
+    case kCheckedStoreFloat32:
+      ASSEMBLE_CHECKED_STORE_FLOAT(32);
+      break;
+    case kCheckedStoreFloat64:
+      ASSEMBLE_CHECKED_STORE_FLOAT(64);
+      break;
   }
 }
 
 
 // Assembles branches after an instruction.
-void CodeGenerator::AssembleArchBranch(Instruction* instr,
-                                       FlagsCondition condition) {
+void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
   ArmOperandConverter i(this, instr);
-  Label done;
-
-  // Emit a branch. The true and false targets are always the last two inputs
-  // to the instruction.
-  BasicBlock* tblock = i.InputBlock(instr->InputCount() - 2);
-  BasicBlock* fblock = i.InputBlock(instr->InputCount() - 1);
-  bool fallthru = IsNextInAssemblyOrder(fblock);
-  Label* tlabel = code()->GetLabel(tblock);
-  Label* flabel = fallthru ? &done : code()->GetLabel(fblock);
-  switch (condition) {
+  Label* tlabel = branch->true_label;
+  Label* flabel = branch->false_label;
+  switch (branch->condition) {
     case kUnorderedEqual:
-      __ b(vs, flabel);
-    // Fall through.
+      // The "eq" condition will not catch the unordered case.
+      // The jump/fall through to false label will be used if the comparison
+      // was unordered.
     case kEqual:
       __ b(eq, tlabel);
       break;
     case kUnorderedNotEqual:
-      __ b(vs, tlabel);
-    // Fall through.
+      // Unordered or not equal can be tested with "ne" condtion.
+      // See ARMv7 manual A8.3 - Conditional execution.
     case kNotEqual:
       __ b(ne, tlabel);
       break;
@@ -479,26 +712,28 @@
       __ b(gt, tlabel);
       break;
     case kUnorderedLessThan:
-      __ b(vs, flabel);
-    // Fall through.
+      // The "lo" condition will not catch the unordered case.
+      // The jump/fall through to false label will be used if the comparison
+      // was unordered.
     case kUnsignedLessThan:
       __ b(lo, tlabel);
       break;
     case kUnorderedGreaterThanOrEqual:
-      __ b(vs, tlabel);
-    // Fall through.
+      // Unordered, greater than or equal can be tested with "hs" condtion.
+      // See ARMv7 manual A8.3 - Conditional execution.
     case kUnsignedGreaterThanOrEqual:
       __ b(hs, tlabel);
       break;
     case kUnorderedLessThanOrEqual:
-      __ b(vs, flabel);
-    // Fall through.
+      // The "ls" condition will not catch the unordered case.
+      // The jump/fall through to false label will be used if the comparison
+      // was unordered.
     case kUnsignedLessThanOrEqual:
       __ b(ls, tlabel);
       break;
     case kUnorderedGreaterThan:
-      __ b(vs, tlabel);
-    // Fall through.
+      // Unordered or greater than can be tested with "hi" condtion.
+      // See ARMv7 manual A8.3 - Conditional execution.
     case kUnsignedGreaterThan:
       __ b(hi, tlabel);
       break;
@@ -509,8 +744,12 @@
       __ b(vc, tlabel);
       break;
   }
-  if (!fallthru) __ b(flabel);  // no fallthru to flabel.
-  __ bind(&done);
+  if (!branch->fallthru) __ b(flabel);  // no fallthru to flabel.
+}
+
+
+void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+  if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
 }
 
 
@@ -634,28 +873,10 @@
       __ stm(db_w, sp, saves);
     }
   } else if (descriptor->IsJSFunctionCall()) {
-    CompilationInfo* info = linkage()->info();
+    CompilationInfo* info = this->info();
     __ Prologue(info->IsCodePreAgingActive());
     frame()->SetRegisterSaveAreaSize(
         StandardFrameConstants::kFixedFrameSizeFromFp);
-
-    // Sloppy mode functions and builtins need to replace the receiver with the
-    // global proxy when called as functions (without an explicit receiver
-    // object).
-    // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
-    if (info->strict_mode() == SLOPPY && !info->is_native()) {
-      Label ok;
-      // +2 for return address and saved frame pointer.
-      int receiver_slot = info->scope()->num_parameters() + 2;
-      __ ldr(r2, MemOperand(fp, receiver_slot * kPointerSize));
-      __ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
-      __ b(ne, &ok);
-      __ ldr(r2, GlobalObjectOperand());
-      __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalProxyOffset));
-      __ str(r2, MemOperand(fp, receiver_slot * kPointerSize));
-      __ bind(&ok);
-    }
-
   } else {
     __ StubPrologue();
     frame()->SetRegisterSaveAreaSize(
@@ -720,10 +941,10 @@
       __ str(temp, g.ToMemOperand(destination));
     }
   } else if (source->IsConstant()) {
+    Constant src = g.ToConstant(source);
     if (destination->IsRegister() || destination->IsStackSlot()) {
       Register dst =
           destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
-      Constant src = g.ToConstant(source);
       switch (src.type()) {
         case Constant::kInt32:
           __ mov(dst, Operand(src.ToInt32()));
@@ -731,6 +952,10 @@
         case Constant::kInt64:
           UNREACHABLE();
           break;
+        case Constant::kFloat32:
+          __ Move(dst,
+                  isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
+          break;
         case Constant::kFloat64:
           __ Move(dst,
                   isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
@@ -741,16 +966,29 @@
         case Constant::kHeapObject:
           __ Move(dst, src.ToHeapObject());
           break;
+        case Constant::kRpoNumber:
+          UNREACHABLE();  // TODO(dcarney): loading RPO constants on arm.
+          break;
       }
       if (destination->IsStackSlot()) __ str(dst, g.ToMemOperand(destination));
-    } else if (destination->IsDoubleRegister()) {
-      DwVfpRegister result = g.ToDoubleRegister(destination);
-      __ vmov(result, g.ToDouble(source));
+    } else if (src.type() == Constant::kFloat32) {
+      if (destination->IsDoubleStackSlot()) {
+        MemOperand dst = g.ToMemOperand(destination);
+        __ mov(ip, Operand(bit_cast<int32_t>(src.ToFloat32())));
+        __ str(ip, dst);
+      } else {
+        SwVfpRegister dst = g.ToFloat32Register(destination);
+        __ vmov(dst, src.ToFloat32());
+      }
     } else {
-      DCHECK(destination->IsDoubleStackSlot());
-      DwVfpRegister temp = kScratchDoubleReg;
-      __ vmov(temp, g.ToDouble(source));
-      __ vstr(temp, g.ToMemOperand(destination));
+      DCHECK_EQ(Constant::kFloat64, src.type());
+      DwVfpRegister dst = destination->IsDoubleRegister()
+                              ? g.ToFloat64Register(destination)
+                              : kScratchDoubleReg;
+      __ vmov(dst, src.ToFloat64(), kScratchReg);
+      if (destination->IsDoubleStackSlot()) {
+        __ vstr(dst, g.ToMemOperand(destination));
+      }
     }
   } else if (source->IsDoubleRegister()) {
     DwVfpRegister src = g.ToDoubleRegister(source);
@@ -851,7 +1089,7 @@
 
 void CodeGenerator::EnsureSpaceForLazyDeopt() {
   int space_needed = Deoptimizer::patch_size();
-  if (!linkage()->info()->IsStub()) {
+  if (!info()->IsStub()) {
     // Ensure that we have enough space after the previous lazy-bailout
     // instruction for patching the code here.
     int current_pc = masm()->pc_offset();
diff --git a/src/compiler/arm/instruction-codes-arm.h b/src/compiler/arm/instruction-codes-arm.h
index 7849ca9..ecd0b2d 100644
--- a/src/compiler/arm/instruction-codes-arm.h
+++ b/src/compiler/arm/instruction-codes-arm.h
@@ -26,12 +26,23 @@
   V(ArmMul)                        \
   V(ArmMla)                        \
   V(ArmMls)                        \
+  V(ArmSmmul)                      \
+  V(ArmSmmla)                      \
+  V(ArmUmull)                      \
   V(ArmSdiv)                       \
   V(ArmUdiv)                       \
   V(ArmMov)                        \
   V(ArmMvn)                        \
   V(ArmBfc)                        \
   V(ArmUbfx)                       \
+  V(ArmSxtb)                       \
+  V(ArmSxth)                       \
+  V(ArmSxtab)                      \
+  V(ArmSxtah)                      \
+  V(ArmUxtb)                       \
+  V(ArmUxth)                       \
+  V(ArmUxtab)                      \
+  V(ArmUxtah)                      \
   V(ArmVcmpF64)                    \
   V(ArmVaddF64)                    \
   V(ArmVsubF64)                    \
@@ -42,14 +53,20 @@
   V(ArmVmodF64)                    \
   V(ArmVnegF64)                    \
   V(ArmVsqrtF64)                   \
+  V(ArmVfloorF64)                  \
+  V(ArmVceilF64)                   \
+  V(ArmVroundTruncateF64)          \
+  V(ArmVroundTiesAwayF64)          \
+  V(ArmVcvtF32F64)                 \
+  V(ArmVcvtF64F32)                 \
   V(ArmVcvtF64S32)                 \
   V(ArmVcvtF64U32)                 \
   V(ArmVcvtS32F64)                 \
   V(ArmVcvtU32F64)                 \
-  V(ArmVldr32)                     \
-  V(ArmVstr32)                     \
-  V(ArmVldr64)                     \
-  V(ArmVstr64)                     \
+  V(ArmVldrF32)                    \
+  V(ArmVstrF32)                    \
+  V(ArmVldrF64)                    \
+  V(ArmVstrF64)                    \
   V(ArmLdrb)                       \
   V(ArmLdrsb)                      \
   V(ArmStrb)                       \
diff --git a/src/compiler/arm/instruction-selector-arm-unittest.cc b/src/compiler/arm/instruction-selector-arm-unittest.cc
deleted file mode 100644
index 208d2e9..0000000
--- a/src/compiler/arm/instruction-selector-arm-unittest.cc
+++ /dev/null
@@ -1,1900 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/instruction-selector-unittest.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-namespace {
-
-typedef RawMachineAssembler::Label MLabel;
-typedef Node* (RawMachineAssembler::*Constructor)(Node*, Node*);
-
-
-// Data processing instructions.
-struct DPI {
-  Constructor constructor;
-  const char* constructor_name;
-  ArchOpcode arch_opcode;
-  ArchOpcode reverse_arch_opcode;
-  ArchOpcode test_arch_opcode;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const DPI& dpi) {
-  return os << dpi.constructor_name;
-}
-
-
-static const DPI kDPIs[] = {
-    {&RawMachineAssembler::Word32And, "Word32And", kArmAnd, kArmAnd, kArmTst},
-    {&RawMachineAssembler::Word32Or, "Word32Or", kArmOrr, kArmOrr, kArmOrr},
-    {&RawMachineAssembler::Word32Xor, "Word32Xor", kArmEor, kArmEor, kArmTeq},
-    {&RawMachineAssembler::Int32Add, "Int32Add", kArmAdd, kArmAdd, kArmCmn},
-    {&RawMachineAssembler::Int32Sub, "Int32Sub", kArmSub, kArmRsb, kArmCmp}};
-
-
-// Data processing instructions with overflow.
-struct ODPI {
-  Constructor constructor;
-  const char* constructor_name;
-  ArchOpcode arch_opcode;
-  ArchOpcode reverse_arch_opcode;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const ODPI& odpi) {
-  return os << odpi.constructor_name;
-}
-
-
-static const ODPI kODPIs[] = {{&RawMachineAssembler::Int32AddWithOverflow,
-                               "Int32AddWithOverflow", kArmAdd, kArmAdd},
-                              {&RawMachineAssembler::Int32SubWithOverflow,
-                               "Int32SubWithOverflow", kArmSub, kArmRsb}};
-
-
-// Shifts.
-struct Shift {
-  Constructor constructor;
-  const char* constructor_name;
-  int32_t i_low;          // lowest possible immediate
-  int32_t i_high;         // highest possible immediate
-  AddressingMode i_mode;  // Operand2_R_<shift>_I
-  AddressingMode r_mode;  // Operand2_R_<shift>_R
-};
-
-
-std::ostream& operator<<(std::ostream& os, const Shift& shift) {
-  return os << shift.constructor_name;
-}
-
-
-static const Shift kShifts[] = {
-    {&RawMachineAssembler::Word32Sar, "Word32Sar", 1, 32,
-     kMode_Operand2_R_ASR_I, kMode_Operand2_R_ASR_R},
-    {&RawMachineAssembler::Word32Shl, "Word32Shl", 0, 31,
-     kMode_Operand2_R_LSL_I, kMode_Operand2_R_LSL_R},
-    {&RawMachineAssembler::Word32Shr, "Word32Shr", 1, 32,
-     kMode_Operand2_R_LSR_I, kMode_Operand2_R_LSR_R},
-    {&RawMachineAssembler::Word32Ror, "Word32Ror", 1, 31,
-     kMode_Operand2_R_ROR_I, kMode_Operand2_R_ROR_R}};
-
-
-// Immediates (random subset).
-static const int32_t kImmediates[] = {
-    -2147483617, -2147483606, -2113929216, -2080374784, -1996488704,
-    -1879048192, -1459617792, -1358954496, -1342177265, -1275068414,
-    -1073741818, -1073741777, -855638016,  -805306368,  -402653184,
-    -268435444,  -16777216,   0,           35,          61,
-    105,         116,         171,         245,         255,
-    692,         1216,        1248,        1520,        1600,
-    1888,        3744,        4080,        5888,        8384,
-    9344,        9472,        9792,        13312,       15040,
-    15360,       20736,       22272,       23296,       32000,
-    33536,       37120,       45824,       47872,       56320,
-    59392,       65280,       72704,       101376,      147456,
-    161792,      164864,      167936,      173056,      195584,
-    209920,      212992,      356352,      655360,      704512,
-    716800,      851968,      901120,      1044480,     1523712,
-    2572288,     3211264,     3588096,     3833856,     3866624,
-    4325376,     5177344,     6488064,     7012352,     7471104,
-    14090240,    16711680,    19398656,    22282240,    28573696,
-    30408704,    30670848,    43253760,    54525952,    55312384,
-    56623104,    68157440,    115343360,   131072000,   187695104,
-    188743680,   195035136,   197132288,   203423744,   218103808,
-    267386880,   268435470,   285212672,   402653185,   415236096,
-    595591168,   603979776,   603979778,   629145600,   1073741835,
-    1073741855,  1073741861,  1073741884,  1157627904,  1476395008,
-    1476395010,  1610612741,  2030043136,  2080374785,  2097152000};
-
-}  // namespace
-
-
-// -----------------------------------------------------------------------------
-// Data processing instructions.
-
-
-typedef InstructionSelectorTestWithParam<DPI> InstructionSelectorDPITest;
-
-
-TEST_P(InstructionSelectorDPITest, Parameters) {
-  const DPI dpi = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorDPITest, Immediate) {
-  const DPI dpi = GetParam();
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-}
-
-
-TEST_P(InstructionSelectorDPITest, ShiftByParameter) {
-  const DPI dpi = GetParam();
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    m.Return((m.*dpi.constructor)(
-        m.Parameter(0),
-        (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-    EXPECT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    m.Return((m.*dpi.constructor)(
-        (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
-        m.Parameter(2)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-    EXPECT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-}
-
-
-TEST_P(InstructionSelectorDPITest, ShiftByImmediate) {
-  const DPI dpi = GetParam();
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-      m.Return((m.*dpi.constructor)(
-          m.Parameter(0),
-          (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm))));
-      Stream s = m.Build();
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-      ASSERT_EQ(3U, s[0]->InputCount());
-      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
-      EXPECT_EQ(1U, s[0]->OutputCount());
-    }
-  }
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-      m.Return((m.*dpi.constructor)(
-          (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)),
-          m.Parameter(1)));
-      Stream s = m.Build();
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode());
-      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-      ASSERT_EQ(3U, s[0]->InputCount());
-      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
-      EXPECT_EQ(1U, s[0]->OutputCount());
-    }
-  }
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchWithParameters) {
-  const DPI dpi = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  MLabel a, b;
-  m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b);
-  m.Bind(&a);
-  m.Return(m.Int32Constant(1));
-  m.Bind(&b);
-  m.Return(m.Int32Constant(0));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchWithImmediate) {
-  const DPI dpi = GetParam();
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    MLabel a, b;
-    m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)), &a,
-             &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(1));
-    m.Bind(&b);
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-  }
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    MLabel a, b;
-    m.Branch((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)), &a,
-             &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(1));
-    m.Bind(&b);
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-  }
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchWithShiftByParameter) {
-  const DPI dpi = GetParam();
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    MLabel a, b;
-    m.Branch((m.*dpi.constructor)(
-                 m.Parameter(0),
-                 (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))),
-             &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(1));
-    m.Bind(&b);
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-  }
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    MLabel a, b;
-    m.Branch((m.*dpi.constructor)(
-                 (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
-                 m.Parameter(2)),
-             &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(1));
-    m.Bind(&b);
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-  }
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchWithShiftByImmediate) {
-  const DPI dpi = GetParam();
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-      MLabel a, b;
-      m.Branch((m.*dpi.constructor)(m.Parameter(0),
-                                    (m.*shift.constructor)(
-                                        m.Parameter(1), m.Int32Constant(imm))),
-               &a, &b);
-      m.Bind(&a);
-      m.Return(m.Int32Constant(1));
-      m.Bind(&b);
-      m.Return(m.Int32Constant(0));
-      Stream s = m.Build();
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
-      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-      ASSERT_EQ(5U, s[0]->InputCount());
-      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
-      EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-      EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-    }
-  }
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-      MLabel a, b;
-      m.Branch((m.*dpi.constructor)(
-                   (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)),
-                   m.Parameter(1)),
-               &a, &b);
-      m.Bind(&a);
-      m.Return(m.Int32Constant(1));
-      m.Bind(&b);
-      m.Return(m.Int32Constant(0));
-      Stream s = m.Build();
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
-      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-      ASSERT_EQ(5U, s[0]->InputCount());
-      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
-      EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-      EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-    }
-  }
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchIfZeroWithParameters) {
-  const DPI dpi = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  MLabel a, b;
-  m.Branch(m.Word32Equal((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)),
-                         m.Int32Constant(0)),
-           &a, &b);
-  m.Bind(&a);
-  m.Return(m.Int32Constant(1));
-  m.Bind(&b);
-  m.Return(m.Int32Constant(0));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-  EXPECT_EQ(kEqual, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchIfNotZeroWithParameters) {
-  const DPI dpi = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  MLabel a, b;
-  m.Branch(
-      m.Word32NotEqual((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)),
-                       m.Int32Constant(0)),
-      &a, &b);
-  m.Bind(&a);
-  m.Return(m.Int32Constant(1));
-  m.Bind(&b);
-  m.Return(m.Int32Constant(0));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchIfZeroWithImmediate) {
-  const DPI dpi = GetParam();
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    MLabel a, b;
-    m.Branch(m.Word32Equal(
-                 (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)),
-                 m.Int32Constant(0)),
-             &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(1));
-    m.Bind(&b);
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    MLabel a, b;
-    m.Branch(m.Word32Equal(
-                 (m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)),
-                 m.Int32Constant(0)),
-             &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(1));
-    m.Bind(&b);
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchIfNotZeroWithImmediate) {
-  const DPI dpi = GetParam();
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    MLabel a, b;
-    m.Branch(m.Word32NotEqual(
-                 (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)),
-                 m.Int32Constant(0)),
-             &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(1));
-    m.Bind(&b);
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-  }
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    MLabel a, b;
-    m.Branch(m.Word32NotEqual(
-                 (m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)),
-                 m.Int32Constant(0)),
-             &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(1));
-    m.Bind(&b);
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-  }
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorDPITest,
-                        ::testing::ValuesIn(kDPIs));
-
-
-// -----------------------------------------------------------------------------
-// Data processing instructions with overflow.
-
-
-typedef InstructionSelectorTestWithParam<ODPI> InstructionSelectorODPITest;
-
-
-TEST_P(InstructionSelectorODPITest, OvfWithParameters) {
-  const ODPI odpi = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(
-      m.Projection(1, (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1))));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_LE(1U, s[0]->OutputCount());
-  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-  EXPECT_EQ(kOverflow, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorODPITest, OvfWithImmediate) {
-  const ODPI odpi = GetParam();
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Projection(
-        1, (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_LE(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Projection(
-        1, (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_LE(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-}
-
-
-TEST_P(InstructionSelectorODPITest, OvfWithShiftByParameter) {
-  const ODPI odpi = GetParam();
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(m.Projection(
-        1, (m.*odpi.constructor)(
-               m.Parameter(0),
-               (m.*shift.constructor)(m.Parameter(1), m.Parameter(2)))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-    EXPECT_EQ(3U, s[0]->InputCount());
-    EXPECT_LE(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(m.Projection(
-        1, (m.*odpi.constructor)(
-               (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
-               m.Parameter(0))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-    EXPECT_EQ(3U, s[0]->InputCount());
-    EXPECT_LE(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-}
-
-
-TEST_P(InstructionSelectorODPITest, OvfWithShiftByImmediate) {
-  const ODPI odpi = GetParam();
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-      m.Return(m.Projection(
-          1, (m.*odpi.constructor)(m.Parameter(0),
-                                   (m.*shift.constructor)(
-                                       m.Parameter(1), m.Int32Constant(imm)))));
-      Stream s = m.Build();
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-      ASSERT_EQ(3U, s[0]->InputCount());
-      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
-      EXPECT_LE(1U, s[0]->OutputCount());
-      EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-      EXPECT_EQ(kOverflow, s[0]->flags_condition());
-    }
-  }
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-      m.Return(m.Projection(
-          1, (m.*odpi.constructor)(
-                 (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)),
-                 m.Parameter(0))));
-      Stream s = m.Build();
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
-      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-      ASSERT_EQ(3U, s[0]->InputCount());
-      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
-      EXPECT_LE(1U, s[0]->OutputCount());
-      EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-      EXPECT_EQ(kOverflow, s[0]->flags_condition());
-    }
-  }
-}
-
-
-TEST_P(InstructionSelectorODPITest, ValWithParameters) {
-  const ODPI odpi = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(
-      m.Projection(0, (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1))));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_LE(1U, s[0]->OutputCount());
-  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
-}
-
-
-TEST_P(InstructionSelectorODPITest, ValWithImmediate) {
-  const ODPI odpi = GetParam();
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Projection(
-        0, (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_LE(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
-  }
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Projection(
-        0, (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_LE(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
-  }
-}
-
-
-TEST_P(InstructionSelectorODPITest, ValWithShiftByParameter) {
-  const ODPI odpi = GetParam();
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(m.Projection(
-        0, (m.*odpi.constructor)(
-               m.Parameter(0),
-               (m.*shift.constructor)(m.Parameter(1), m.Parameter(2)))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-    EXPECT_EQ(3U, s[0]->InputCount());
-    EXPECT_LE(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
-  }
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(m.Projection(
-        0, (m.*odpi.constructor)(
-               (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
-               m.Parameter(0))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-    EXPECT_EQ(3U, s[0]->InputCount());
-    EXPECT_LE(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
-  }
-}
-
-
-TEST_P(InstructionSelectorODPITest, ValWithShiftByImmediate) {
-  const ODPI odpi = GetParam();
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-      m.Return(m.Projection(
-          0, (m.*odpi.constructor)(m.Parameter(0),
-                                   (m.*shift.constructor)(
-                                       m.Parameter(1), m.Int32Constant(imm)))));
-      Stream s = m.Build();
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-      ASSERT_EQ(3U, s[0]->InputCount());
-      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
-      EXPECT_LE(1U, s[0]->OutputCount());
-      EXPECT_EQ(kFlags_none, s[0]->flags_mode());
-    }
-  }
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-      m.Return(m.Projection(
-          0, (m.*odpi.constructor)(
-                 (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)),
-                 m.Parameter(0))));
-      Stream s = m.Build();
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
-      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-      ASSERT_EQ(3U, s[0]->InputCount());
-      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
-      EXPECT_LE(1U, s[0]->OutputCount());
-      EXPECT_EQ(kFlags_none, s[0]->flags_mode());
-    }
-  }
-}
-
-
-TEST_P(InstructionSelectorODPITest, BothWithParameters) {
-  const ODPI odpi = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
-  m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
-  Stream s = m.Build();
-  ASSERT_LE(1U, s.size());
-  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(2U, s[0]->OutputCount());
-  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-  EXPECT_EQ(kOverflow, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorODPITest, BothWithImmediate) {
-  const ODPI odpi = GetParam();
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
-    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
-    Stream s = m.Build();
-    ASSERT_LE(1U, s.size());
-    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(2U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    Node* n = (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0));
-    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
-    Stream s = m.Build();
-    ASSERT_LE(1U, s.size());
-    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(2U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-}
-
-
-TEST_P(InstructionSelectorODPITest, BothWithShiftByParameter) {
-  const ODPI odpi = GetParam();
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    Node* n = (m.*odpi.constructor)(
-        m.Parameter(0), (m.*shift.constructor)(m.Parameter(1), m.Parameter(2)));
-    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
-    Stream s = m.Build();
-    ASSERT_LE(1U, s.size());
-    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-    EXPECT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(2U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    Node* n = (m.*odpi.constructor)(
-        (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)), m.Parameter(2));
-    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
-    Stream s = m.Build();
-    ASSERT_LE(1U, s.size());
-    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-    EXPECT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(2U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-}
-
-
-TEST_P(InstructionSelectorODPITest, BothWithShiftByImmediate) {
-  const ODPI odpi = GetParam();
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-      Node* n = (m.*odpi.constructor)(
-          m.Parameter(0),
-          (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)));
-      m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
-      Stream s = m.Build();
-      ASSERT_LE(1U, s.size());
-      EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-      ASSERT_EQ(3U, s[0]->InputCount());
-      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
-      EXPECT_EQ(2U, s[0]->OutputCount());
-      EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-      EXPECT_EQ(kOverflow, s[0]->flags_condition());
-    }
-  }
-  TRACED_FOREACH(Shift, shift, kShifts) {
-    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-      Node* n = (m.*odpi.constructor)(
-          (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)),
-          m.Parameter(1));
-      m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
-      Stream s = m.Build();
-      ASSERT_LE(1U, s.size());
-      EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
-      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-      ASSERT_EQ(3U, s[0]->InputCount());
-      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
-      EXPECT_EQ(2U, s[0]->OutputCount());
-      EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-      EXPECT_EQ(kOverflow, s[0]->flags_condition());
-    }
-  }
-}
-
-
-TEST_P(InstructionSelectorODPITest, BranchWithParameters) {
-  const ODPI odpi = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  MLabel a, b;
-  Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
-  m.Branch(m.Projection(1, n), &a, &b);
-  m.Bind(&a);
-  m.Return(m.Int32Constant(0));
-  m.Bind(&b);
-  m.Return(m.Projection(0, n));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-  EXPECT_EQ(4U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-  EXPECT_EQ(kOverflow, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorODPITest, BranchWithImmediate) {
-  const ODPI odpi = GetParam();
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    MLabel a, b;
-    Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
-    m.Branch(m.Projection(1, n), &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(0));
-    m.Bind(&b);
-    m.Return(m.Projection(0, n));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    ASSERT_EQ(4U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    MLabel a, b;
-    Node* n = (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0));
-    m.Branch(m.Projection(1, n), &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(0));
-    m.Bind(&b);
-    m.Return(m.Projection(0, n));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    ASSERT_EQ(4U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-}
-
-
-TEST_P(InstructionSelectorODPITest, BranchIfZeroWithParameters) {
-  const ODPI odpi = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  MLabel a, b;
-  Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
-  m.Branch(m.Word32Equal(m.Projection(1, n), m.Int32Constant(0)), &a, &b);
-  m.Bind(&a);
-  m.Return(m.Projection(0, n));
-  m.Bind(&b);
-  m.Return(m.Int32Constant(0));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-  EXPECT_EQ(4U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-  EXPECT_EQ(kNotOverflow, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorODPITest, BranchIfNotZeroWithParameters) {
-  const ODPI odpi = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  MLabel a, b;
-  Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
-  m.Branch(m.Word32NotEqual(m.Projection(1, n), m.Int32Constant(0)), &a, &b);
-  m.Bind(&a);
-  m.Return(m.Projection(0, n));
-  m.Bind(&b);
-  m.Return(m.Int32Constant(0));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-  EXPECT_EQ(4U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-  EXPECT_EQ(kOverflow, s[0]->flags_condition());
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorODPITest,
-                        ::testing::ValuesIn(kODPIs));
-
-
-// -----------------------------------------------------------------------------
-// Shifts.
-
-
-typedef InstructionSelectorTestWithParam<Shift> InstructionSelectorShiftTest;
-
-
-TEST_P(InstructionSelectorShiftTest, Parameters) {
-  const Shift shift = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return((m.*shift.constructor)(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kArmMov, s[0]->arch_opcode());
-  EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Immediate) {
-  const Shift shift = GetParam();
-  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return((m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmMov, s[0]->arch_opcode());
-    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32EqualWithParameter) {
-  const Shift shift = GetParam();
-  {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(
-        m.Word32Equal(m.Parameter(0),
-                      (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
-    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-    EXPECT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-  {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(
-        m.Word32Equal((m.*shift.constructor)(m.Parameter(1), m.Parameter(2)),
-                      m.Parameter(0)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
-    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-    EXPECT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32EqualWithParameterAndImmediate) {
-  const Shift shift = GetParam();
-  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(m.Word32Equal(
-        (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)),
-        m.Parameter(0)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
-    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-    ASSERT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(m.Word32Equal(
-        m.Parameter(0),
-        (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
-    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-    ASSERT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32EqualToZeroWithParameters) {
-  const Shift shift = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(
-      m.Word32Equal(m.Int32Constant(0),
-                    (m.*shift.constructor)(m.Parameter(0), m.Parameter(1))));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kArmMov, s[0]->arch_opcode());
-  EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(2U, s[0]->OutputCount());
-  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-  EXPECT_EQ(kEqual, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32EqualToZeroWithImmediate) {
-  const Shift shift = GetParam();
-  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(m.Word32Equal(
-        m.Int32Constant(0),
-        (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmMov, s[0]->arch_opcode());
-    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(2U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32NotWithParameters) {
-  const Shift shift = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Word32Not((m.*shift.constructor)(m.Parameter(0), m.Parameter(1))));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kArmMvn, s[0]->arch_opcode());
-  EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32NotWithImmediate) {
-  const Shift shift = GetParam();
-  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Word32Not(
-        (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmMvn, s[0]->arch_opcode());
-    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32AndWithWord32NotWithParameters) {
-  const Shift shift = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Word32And(m.Parameter(0), m.Word32Not((m.*shift.constructor)(
-                                           m.Parameter(1), m.Parameter(2)))));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kArmBic, s[0]->arch_opcode());
-  EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
-  EXPECT_EQ(3U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32AndWithWord32NotWithImmediate) {
-  const Shift shift = GetParam();
-  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(m.Word32And(m.Parameter(0),
-                         m.Word32Not((m.*shift.constructor)(
-                             m.Parameter(1), m.Int32Constant(imm)))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmBic, s[0]->arch_opcode());
-    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
-    ASSERT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
-                        ::testing::ValuesIn(kShifts));
-
-
-// -----------------------------------------------------------------------------
-// Memory access instructions.
-
-
-namespace {
-
-struct MemoryAccess {
-  MachineType type;
-  ArchOpcode ldr_opcode;
-  ArchOpcode str_opcode;
-  bool (InstructionSelectorTest::Stream::*val_predicate)(
-      const InstructionOperand*) const;
-  const int32_t immediates[40];
-};
-
-
-std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
-  OStringStream ost;
-  ost << memacc.type;
-  return os << ost.c_str();
-}
-
-
-static const MemoryAccess kMemoryAccesses[] = {
-    {kMachInt8,
-     kArmLdrsb,
-     kArmStrb,
-     &InstructionSelectorTest::Stream::IsInteger,
-     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
-      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
-      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
-    {kMachUint8,
-     kArmLdrb,
-     kArmStrb,
-     &InstructionSelectorTest::Stream::IsInteger,
-     {-4095, -3914, -3536, -3234, -3185, -3169, -1073, -990, -859, -720, -434,
-      -127, -124, -122, -105, -91, -86, -64, -55, -53, -30, -10, -3, 0, 20, 28,
-      39, 58, 64, 73, 75, 100, 108, 121, 686, 963, 1363, 2759, 3449, 4095}},
-    {kMachInt16,
-     kArmLdrsh,
-     kArmStrh,
-     &InstructionSelectorTest::Stream::IsInteger,
-     {-255, -251, -232, -220, -144, -138, -130, -126, -116, -115, -102, -101,
-      -98, -69, -59, -56, -39, -35, -23, -19, -7, 0, 22, 26, 37, 68, 83, 87, 98,
-      102, 108, 111, 117, 171, 195, 203, 204, 245, 246, 255}},
-    {kMachUint16,
-     kArmLdrh,
-     kArmStrh,
-     &InstructionSelectorTest::Stream::IsInteger,
-     {-255, -230, -201, -172, -125, -119, -118, -105, -98, -79, -54, -42, -41,
-      -32, -12, -11, -5, -4, 0, 5, 9, 25, 28, 51, 58, 60, 89, 104, 108, 109,
-      114, 116, 120, 138, 150, 161, 166, 172, 228, 255}},
-    {kMachInt32,
-     kArmLdr,
-     kArmStr,
-     &InstructionSelectorTest::Stream::IsInteger,
-     {-4095, -1898, -1685, -1562, -1408, -1313, -344, -128, -116, -100, -92,
-      -80, -72, -71, -56, -25, -21, -11, -9, 0, 3, 5, 27, 28, 42, 52, 63, 88,
-      93, 97, 125, 846, 1037, 2102, 2403, 2597, 2632, 2997, 3935, 4095}},
-    {kMachFloat32,
-     kArmVldr32,
-     kArmVstr32,
-     &InstructionSelectorTest::Stream::IsDouble,
-     {-1020, -928, -896, -772, -728, -680, -660, -488, -372, -112, -100, -92,
-      -84, -80, -72, -64, -60, -56, -52, -48, -36, -32, -20, -8, -4, 0, 8, 20,
-      24, 40, 64, 112, 204, 388, 516, 852, 856, 976, 988, 1020}},
-    {kMachFloat64,
-     kArmVldr64,
-     kArmVstr64,
-     &InstructionSelectorTest::Stream::IsDouble,
-     {-1020, -948, -796, -696, -612, -364, -320, -308, -128, -112, -108, -104,
-      -96, -84, -80, -56, -48, -40, -20, 0, 24, 28, 36, 48, 64, 84, 96, 100,
-      108, 116, 120, 140, 156, 408, 432, 444, 772, 832, 940, 1020}}};
-
-}  // namespace
-
-
-typedef InstructionSelectorTestWithParam<MemoryAccess>
-    InstructionSelectorMemoryAccessTest;
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
-  const MemoryAccess memacc = GetParam();
-  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
-  m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_Offset_RR, s[0]->addressing_mode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  ASSERT_EQ(1U, s[0]->OutputCount());
-  EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output()));
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
-  const MemoryAccess memacc = GetParam();
-  TRACED_FOREACH(int32_t, index, memacc.immediates) {
-    StreamBuilder m(this, memacc.type, kMachPtr);
-    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Offset_RI, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
-    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
-    ASSERT_EQ(1U, s[0]->OutputCount());
-    EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output()));
-  }
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
-  const MemoryAccess memacc = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
-  m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
-  m.Return(m.Int32Constant(0));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_Offset_RR, s[0]->addressing_mode());
-  EXPECT_EQ(3U, s[0]->InputCount());
-  EXPECT_EQ(0U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
-  const MemoryAccess memacc = GetParam();
-  TRACED_FOREACH(int32_t, index, memacc.immediates) {
-    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
-    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
-            m.Parameter(1));
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Offset_RI, s[0]->addressing_mode());
-    ASSERT_EQ(3U, s[0]->InputCount());
-    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
-    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(0U, s[0]->OutputCount());
-  }
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
-                        InstructionSelectorMemoryAccessTest,
-                        ::testing::ValuesIn(kMemoryAccesses));
-
-
-// -----------------------------------------------------------------------------
-// Miscellaneous.
-
-
-TEST_F(InstructionSelectorTest, Int32AddWithInt32Mul) {
-  {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(
-        m.Int32Add(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmMla, s[0]->arch_opcode());
-    EXPECT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-  {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(
-        m.Int32Add(m.Int32Mul(m.Parameter(1), m.Parameter(2)), m.Parameter(0)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmMla, s[0]->arch_opcode());
-    EXPECT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, Int32DivWithParameters) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(4U, s.size());
-  EXPECT_EQ(kArmVcvtF64S32, s[0]->arch_opcode());
-  ASSERT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(kArmVcvtF64S32, s[1]->arch_opcode());
-  ASSERT_EQ(1U, s[1]->OutputCount());
-  EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
-  ASSERT_EQ(2U, s[2]->InputCount());
-  ASSERT_EQ(1U, s[2]->OutputCount());
-  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
-  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
-  EXPECT_EQ(kArmVcvtS32F64, s[3]->arch_opcode());
-  ASSERT_EQ(1U, s[3]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32DivWithParametersForSUDIV) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build(SUDIV);
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kArmSdiv, s[0]->arch_opcode());
-}
-
-
-TEST_F(InstructionSelectorTest, Int32ModWithParameters) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(6U, s.size());
-  EXPECT_EQ(kArmVcvtF64S32, s[0]->arch_opcode());
-  ASSERT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(kArmVcvtF64S32, s[1]->arch_opcode());
-  ASSERT_EQ(1U, s[1]->OutputCount());
-  EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
-  ASSERT_EQ(2U, s[2]->InputCount());
-  ASSERT_EQ(1U, s[2]->OutputCount());
-  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
-  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
-  EXPECT_EQ(kArmVcvtS32F64, s[3]->arch_opcode());
-  ASSERT_EQ(1U, s[3]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
-  EXPECT_EQ(kArmMul, s[4]->arch_opcode());
-  ASSERT_EQ(1U, s[4]->OutputCount());
-  ASSERT_EQ(2U, s[4]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[3]->Output()), s.ToVreg(s[4]->InputAt(0)));
-  EXPECT_EQ(s.ToVreg(s[1]->InputAt(0)), s.ToVreg(s[4]->InputAt(1)));
-  EXPECT_EQ(kArmSub, s[5]->arch_opcode());
-  ASSERT_EQ(1U, s[5]->OutputCount());
-  ASSERT_EQ(2U, s[5]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[5]->InputAt(0)));
-  EXPECT_EQ(s.ToVreg(s[4]->Output()), s.ToVreg(s[5]->InputAt(1)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32ModWithParametersForSUDIV) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build(SUDIV);
-  ASSERT_EQ(3U, s.size());
-  EXPECT_EQ(kArmSdiv, s[0]->arch_opcode());
-  ASSERT_EQ(1U, s[0]->OutputCount());
-  ASSERT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(kArmMul, s[1]->arch_opcode());
-  ASSERT_EQ(1U, s[1]->OutputCount());
-  ASSERT_EQ(2U, s[1]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
-  EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
-  EXPECT_EQ(kArmSub, s[2]->arch_opcode());
-  ASSERT_EQ(1U, s[2]->OutputCount());
-  ASSERT_EQ(2U, s[2]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[2]->InputAt(0)));
-  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32ModWithParametersForSUDIVAndMLS) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build(MLS, SUDIV);
-  ASSERT_EQ(2U, s.size());
-  EXPECT_EQ(kArmSdiv, s[0]->arch_opcode());
-  ASSERT_EQ(1U, s[0]->OutputCount());
-  ASSERT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(kArmMls, s[1]->arch_opcode());
-  ASSERT_EQ(1U, s[1]->OutputCount());
-  ASSERT_EQ(3U, s[1]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
-  EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
-  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[1]->InputAt(2)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32MulWithParameters) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Int32Mul(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kArmMul, s[0]->arch_opcode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_F(InstructionSelectorTest, Int32MulWithImmediate) {
-  // x * (2^k + 1) -> x + (x >> k)
-  TRACED_FORRANGE(int32_t, k, 1, 30) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) + 1)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmAdd, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
-    ASSERT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
-    EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-  // x * (2^k - 1) -> -x + (x >> k)
-  TRACED_FORRANGE(int32_t, k, 3, 30) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) - 1)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmRsb, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
-    ASSERT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
-    EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-  // (2^k + 1) * x -> x + (x >> k)
-  TRACED_FORRANGE(int32_t, k, 1, 30) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(0)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmAdd, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
-    ASSERT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
-    EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-  // x * (2^k - 1) -> -x + (x >> k)
-  TRACED_FORRANGE(int32_t, k, 3, 30) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Int32Mul(m.Int32Constant((1 << k) - 1), m.Parameter(0)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmRsb, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
-    ASSERT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
-    EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, Int32SubWithInt32Mul) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(
-      m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
-  Stream s = m.Build();
-  ASSERT_EQ(2U, s.size());
-  EXPECT_EQ(kArmMul, s[0]->arch_opcode());
-  ASSERT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(kArmSub, s[1]->arch_opcode());
-  ASSERT_EQ(2U, s[1]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(1)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32SubWithInt32MulForMLS) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(
-      m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
-  Stream s = m.Build(MLS);
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kArmMls, s[0]->arch_opcode());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(3U, s[0]->InputCount());
-}
-
-
-TEST_F(InstructionSelectorTest, Int32UDivWithParameters) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Int32UDiv(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(4U, s.size());
-  EXPECT_EQ(kArmVcvtF64U32, s[0]->arch_opcode());
-  ASSERT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(kArmVcvtF64U32, s[1]->arch_opcode());
-  ASSERT_EQ(1U, s[1]->OutputCount());
-  EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
-  ASSERT_EQ(2U, s[2]->InputCount());
-  ASSERT_EQ(1U, s[2]->OutputCount());
-  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
-  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
-  EXPECT_EQ(kArmVcvtU32F64, s[3]->arch_opcode());
-  ASSERT_EQ(1U, s[3]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32UDivWithParametersForSUDIV) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Int32UDiv(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build(SUDIV);
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kArmUdiv, s[0]->arch_opcode());
-}
-
-
-TEST_F(InstructionSelectorTest, Int32UModWithParameters) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(6U, s.size());
-  EXPECT_EQ(kArmVcvtF64U32, s[0]->arch_opcode());
-  ASSERT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(kArmVcvtF64U32, s[1]->arch_opcode());
-  ASSERT_EQ(1U, s[1]->OutputCount());
-  EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
-  ASSERT_EQ(2U, s[2]->InputCount());
-  ASSERT_EQ(1U, s[2]->OutputCount());
-  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
-  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
-  EXPECT_EQ(kArmVcvtU32F64, s[3]->arch_opcode());
-  ASSERT_EQ(1U, s[3]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
-  EXPECT_EQ(kArmMul, s[4]->arch_opcode());
-  ASSERT_EQ(1U, s[4]->OutputCount());
-  ASSERT_EQ(2U, s[4]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[3]->Output()), s.ToVreg(s[4]->InputAt(0)));
-  EXPECT_EQ(s.ToVreg(s[1]->InputAt(0)), s.ToVreg(s[4]->InputAt(1)));
-  EXPECT_EQ(kArmSub, s[5]->arch_opcode());
-  ASSERT_EQ(1U, s[5]->OutputCount());
-  ASSERT_EQ(2U, s[5]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[5]->InputAt(0)));
-  EXPECT_EQ(s.ToVreg(s[4]->Output()), s.ToVreg(s[5]->InputAt(1)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32UModWithParametersForSUDIV) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build(SUDIV);
-  ASSERT_EQ(3U, s.size());
-  EXPECT_EQ(kArmUdiv, s[0]->arch_opcode());
-  ASSERT_EQ(1U, s[0]->OutputCount());
-  ASSERT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(kArmMul, s[1]->arch_opcode());
-  ASSERT_EQ(1U, s[1]->OutputCount());
-  ASSERT_EQ(2U, s[1]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
-  EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
-  EXPECT_EQ(kArmSub, s[2]->arch_opcode());
-  ASSERT_EQ(1U, s[2]->OutputCount());
-  ASSERT_EQ(2U, s[2]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[2]->InputAt(0)));
-  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32UModWithParametersForSUDIVAndMLS) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build(MLS, SUDIV);
-  ASSERT_EQ(2U, s.size());
-  EXPECT_EQ(kArmUdiv, s[0]->arch_opcode());
-  ASSERT_EQ(1U, s[0]->OutputCount());
-  ASSERT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(kArmMls, s[1]->arch_opcode());
-  ASSERT_EQ(1U, s[1]->OutputCount());
-  ASSERT_EQ(3U, s[1]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
-  EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
-  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[1]->InputAt(2)));
-}
-
-
-TEST_F(InstructionSelectorTest, Word32AndWithUbfxImmediateForARMv7) {
-  TRACED_FORRANGE(int32_t, width, 1, 32) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Word32And(m.Parameter(0),
-                         m.Int32Constant(0xffffffffu >> (32 - width))));
-    Stream s = m.Build(ARMv7);
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
-    ASSERT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
-  }
-  TRACED_FORRANGE(int32_t, width, 1, 32) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)),
-                         m.Parameter(0)));
-    Stream s = m.Build(ARMv7);
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
-    ASSERT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, Word32AndWithBfcImmediateForARMv7) {
-  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
-    TRACED_FORRANGE(int32_t, width, 1, (32 - lsb) - 1) {
-      StreamBuilder m(this, kMachInt32, kMachInt32);
-      m.Return(m.Word32And(
-          m.Parameter(0),
-          m.Int32Constant(~((0xffffffffu >> (32 - width)) << lsb))));
-      Stream s = m.Build(ARMv7);
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(kArmBfc, s[0]->arch_opcode());
-      ASSERT_EQ(1U, s[0]->OutputCount());
-      EXPECT_TRUE(
-          UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy());
-      ASSERT_EQ(3U, s[0]->InputCount());
-      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
-      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
-    }
-  }
-  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
-    TRACED_FORRANGE(int32_t, width, 1, (32 - lsb) - 1) {
-      StreamBuilder m(this, kMachInt32, kMachInt32);
-      m.Return(
-          m.Word32And(m.Int32Constant(~((0xffffffffu >> (32 - width)) << lsb)),
-                      m.Parameter(0)));
-      Stream s = m.Build(ARMv7);
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(kArmBfc, s[0]->arch_opcode());
-      ASSERT_EQ(1U, s[0]->OutputCount());
-      EXPECT_TRUE(
-          UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy());
-      ASSERT_EQ(3U, s[0]->InputCount());
-      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
-      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
-    }
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediateForARMv7) {
-  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
-    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
-      uint32_t max = 1 << lsb;
-      if (max > static_cast<uint32_t>(kMaxInt)) max -= 1;
-      uint32_t jnk = rng()->NextInt(max);
-      uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
-      StreamBuilder m(this, kMachInt32, kMachInt32);
-      m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)),
-                           m.Int32Constant(lsb)));
-      Stream s = m.Build(ARMv7);
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
-      ASSERT_EQ(3U, s[0]->InputCount());
-      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
-      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
-    }
-  }
-  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
-    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
-      uint32_t max = 1 << lsb;
-      if (max > static_cast<uint32_t>(kMaxInt)) max -= 1;
-      uint32_t jnk = rng()->NextInt(max);
-      uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
-      StreamBuilder m(this, kMachInt32, kMachInt32);
-      m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)),
-                           m.Int32Constant(lsb)));
-      Stream s = m.Build(ARMv7);
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
-      ASSERT_EQ(3U, s[0]->InputCount());
-      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
-      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
-    }
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, Word32AndWithWord32Not) {
-  {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(m.Word32And(m.Parameter(0), m.Word32Not(m.Parameter(1))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmBic, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-    EXPECT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-  {
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(m.Word32And(m.Word32Not(m.Parameter(0)), m.Parameter(1)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmBic, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-    EXPECT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, Word32EqualWithParameters) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Word32Equal(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-  EXPECT_EQ(kEqual, s[0]->flags_condition());
-}
-
-
-TEST_F(InstructionSelectorTest, Word32EqualWithImmediate) {
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    if (imm == 0) continue;
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(imm)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    if (imm == 0) continue;
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Word32Equal(m.Int32Constant(imm), m.Parameter(0)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
-  {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmTst, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-  {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArmTst, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, Word32NotWithParameter) {
-  StreamBuilder m(this, kMachInt32, kMachInt32);
-  m.Return(m.Word32Not(m.Parameter(0)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kArmMvn, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
-  EXPECT_EQ(1U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrWithImmediateForARMv7) {
-  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
-    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
-      StreamBuilder m(this, kMachInt32, kMachInt32);
-      m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)),
-                           m.Int32Constant(0xffffffffu >> (32 - width))));
-      Stream s = m.Build(ARMv7);
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
-      ASSERT_EQ(3U, s[0]->InputCount());
-      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
-      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
-    }
-  }
-  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
-    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
-      StreamBuilder m(this, kMachInt32, kMachInt32);
-      m.Return(m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)),
-                           m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb))));
-      Stream s = m.Build(ARMv7);
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
-      ASSERT_EQ(3U, s[0]->InputCount());
-      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
-      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
-    }
-  }
-}
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc
index ae93b27..ef9e89e 100644
--- a/src/compiler/arm/instruction-selector-arm.cc
+++ b/src/compiler/arm/instruction-selector-arm.cc
@@ -11,16 +11,17 @@
 namespace compiler {
 
 // Adds Arm-specific methods for generating InstructionOperands.
-class ArmOperandGenerator FINAL : public OperandGenerator {
+class ArmOperandGenerator : public OperandGenerator {
  public:
   explicit ArmOperandGenerator(InstructionSelector* selector)
       : OperandGenerator(selector) {}
 
-  InstructionOperand* UseOperand(Node* node, InstructionCode opcode) {
-    if (CanBeImmediate(node, opcode)) {
-      return UseImmediate(node);
-    }
-    return UseRegister(node);
+  bool CanBeImmediate(int32_t value) const {
+    return Assembler::ImmediateFitsAddrMode1Instruction(value);
+  }
+
+  bool CanBeImmediate(uint32_t value) const {
+    return CanBeImmediate(bit_cast<int32_t>(value));
   }
 
   bool CanBeImmediate(Node* node, InstructionCode opcode) {
@@ -32,27 +33,25 @@
       case kArmMov:
       case kArmMvn:
       case kArmBic:
-        return ImmediateFitsAddrMode1Instruction(value) ||
-               ImmediateFitsAddrMode1Instruction(~value);
+        return CanBeImmediate(value) || CanBeImmediate(~value);
 
       case kArmAdd:
       case kArmSub:
       case kArmCmp:
       case kArmCmn:
-        return ImmediateFitsAddrMode1Instruction(value) ||
-               ImmediateFitsAddrMode1Instruction(-value);
+        return CanBeImmediate(value) || CanBeImmediate(-value);
 
       case kArmTst:
       case kArmTeq:
       case kArmOrr:
       case kArmEor:
       case kArmRsb:
-        return ImmediateFitsAddrMode1Instruction(value);
+        return CanBeImmediate(value);
 
-      case kArmVldr32:
-      case kArmVstr32:
-      case kArmVldr64:
-      case kArmVstr64:
+      case kArmVldrF32:
+      case kArmVstrF32:
+      case kArmVldrF64:
+      case kArmVstrF64:
         return value >= -1020 && value <= 1020 && (value % 4) == 0;
 
       case kArmLdrb:
@@ -68,49 +67,26 @@
       case kArmStrh:
         return value >= -255 && value <= 255;
 
-      case kArchCallCodeObject:
-      case kArchCallJSFunction:
-      case kArchJmp:
-      case kArchNop:
-      case kArchRet:
-      case kArchTruncateDoubleToI:
-      case kArmMul:
-      case kArmMla:
-      case kArmMls:
-      case kArmSdiv:
-      case kArmUdiv:
-      case kArmBfc:
-      case kArmUbfx:
-      case kArmVcmpF64:
-      case kArmVaddF64:
-      case kArmVsubF64:
-      case kArmVmulF64:
-      case kArmVmlaF64:
-      case kArmVmlsF64:
-      case kArmVdivF64:
-      case kArmVmodF64:
-      case kArmVnegF64:
-      case kArmVsqrtF64:
-      case kArmVcvtF64S32:
-      case kArmVcvtF64U32:
-      case kArmVcvtS32F64:
-      case kArmVcvtU32F64:
-      case kArmPush:
-        return false;
+      default:
+        break;
     }
-    UNREACHABLE();
     return false;
   }
-
- private:
-  bool ImmediateFitsAddrMode1Instruction(int32_t imm) const {
-    return Assembler::ImmediateFitsAddrMode1Instruction(imm);
-  }
 };
 
 
-static void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
-                            Node* node) {
+namespace {
+
+void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
+                    Node* node) {
+  ArmOperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsRegister(node),
+                 g.UseRegister(node->InputAt(0)));
+}
+
+
+void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
+                     Node* node) {
   ArmOperandGenerator g(selector);
   selector->Emit(opcode, g.DefineAsRegister(node),
                  g.UseRegister(node->InputAt(0)),
@@ -118,86 +94,69 @@
 }
 
 
-static bool TryMatchROR(InstructionSelector* selector,
-                        InstructionCode* opcode_return, Node* node,
-                        InstructionOperand** value_return,
-                        InstructionOperand** shift_return) {
+template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax,
+          AddressingMode kImmMode, AddressingMode kRegMode>
+bool TryMatchShift(InstructionSelector* selector,
+                   InstructionCode* opcode_return, Node* node,
+                   InstructionOperand** value_return,
+                   InstructionOperand** shift_return) {
   ArmOperandGenerator g(selector);
-  if (node->opcode() != IrOpcode::kWord32Ror) return false;
-  Int32BinopMatcher m(node);
-  *value_return = g.UseRegister(m.left().node());
-  if (m.right().IsInRange(1, 31)) {
-    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_I);
-    *shift_return = g.UseImmediate(m.right().node());
-  } else {
-    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_R);
-    *shift_return = g.UseRegister(m.right().node());
+  if (node->opcode() == kOpcode) {
+    Int32BinopMatcher m(node);
+    *value_return = g.UseRegister(m.left().node());
+    if (m.right().IsInRange(kImmMin, kImmMax)) {
+      *opcode_return |= AddressingModeField::encode(kImmMode);
+      *shift_return = g.UseImmediate(m.right().node());
+    } else {
+      *opcode_return |= AddressingModeField::encode(kRegMode);
+      *shift_return = g.UseRegister(m.right().node());
+    }
+    return true;
   }
-  return true;
+  return false;
 }
 
 
-static inline bool TryMatchASR(InstructionSelector* selector,
-                               InstructionCode* opcode_return, Node* node,
-                               InstructionOperand** value_return,
-                               InstructionOperand** shift_return) {
-  ArmOperandGenerator g(selector);
-  if (node->opcode() != IrOpcode::kWord32Sar) return false;
-  Int32BinopMatcher m(node);
-  *value_return = g.UseRegister(m.left().node());
-  if (m.right().IsInRange(1, 32)) {
-    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ASR_I);
-    *shift_return = g.UseImmediate(m.right().node());
-  } else {
-    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ASR_R);
-    *shift_return = g.UseRegister(m.right().node());
-  }
-  return true;
+bool TryMatchROR(InstructionSelector* selector, InstructionCode* opcode_return,
+                 Node* node, InstructionOperand** value_return,
+                 InstructionOperand** shift_return) {
+  return TryMatchShift<IrOpcode::kWord32Ror, 1, 31, kMode_Operand2_R_ROR_I,
+                       kMode_Operand2_R_ROR_R>(selector, opcode_return, node,
+                                               value_return, shift_return);
 }
 
 
-static inline bool TryMatchLSL(InstructionSelector* selector,
-                               InstructionCode* opcode_return, Node* node,
-                               InstructionOperand** value_return,
-                               InstructionOperand** shift_return) {
-  ArmOperandGenerator g(selector);
-  if (node->opcode() != IrOpcode::kWord32Shl) return false;
-  Int32BinopMatcher m(node);
-  *value_return = g.UseRegister(m.left().node());
-  if (m.right().IsInRange(0, 31)) {
-    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSL_I);
-    *shift_return = g.UseImmediate(m.right().node());
-  } else {
-    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSL_R);
-    *shift_return = g.UseRegister(m.right().node());
-  }
-  return true;
+bool TryMatchASR(InstructionSelector* selector, InstructionCode* opcode_return,
+                 Node* node, InstructionOperand** value_return,
+                 InstructionOperand** shift_return) {
+  return TryMatchShift<IrOpcode::kWord32Sar, 1, 32, kMode_Operand2_R_ASR_I,
+                       kMode_Operand2_R_ASR_R>(selector, opcode_return, node,
+                                               value_return, shift_return);
 }
 
 
-static inline bool TryMatchLSR(InstructionSelector* selector,
-                               InstructionCode* opcode_return, Node* node,
-                               InstructionOperand** value_return,
-                               InstructionOperand** shift_return) {
-  ArmOperandGenerator g(selector);
-  if (node->opcode() != IrOpcode::kWord32Shr) return false;
-  Int32BinopMatcher m(node);
-  *value_return = g.UseRegister(m.left().node());
-  if (m.right().IsInRange(1, 32)) {
-    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSR_I);
-    *shift_return = g.UseImmediate(m.right().node());
-  } else {
-    *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSR_R);
-    *shift_return = g.UseRegister(m.right().node());
-  }
-  return true;
+bool TryMatchLSL(InstructionSelector* selector, InstructionCode* opcode_return,
+                 Node* node, InstructionOperand** value_return,
+                 InstructionOperand** shift_return) {
+  return TryMatchShift<IrOpcode::kWord32Shl, 0, 31, kMode_Operand2_R_LSL_I,
+                       kMode_Operand2_R_LSL_R>(selector, opcode_return, node,
+                                               value_return, shift_return);
 }
 
 
-static inline bool TryMatchShift(InstructionSelector* selector,
-                                 InstructionCode* opcode_return, Node* node,
-                                 InstructionOperand** value_return,
-                                 InstructionOperand** shift_return) {
+bool TryMatchLSR(InstructionSelector* selector, InstructionCode* opcode_return,
+                 Node* node, InstructionOperand** value_return,
+                 InstructionOperand** shift_return) {
+  return TryMatchShift<IrOpcode::kWord32Shr, 1, 32, kMode_Operand2_R_LSR_I,
+                       kMode_Operand2_R_LSR_R>(selector, opcode_return, node,
+                                               value_return, shift_return);
+}
+
+
+bool TryMatchShift(InstructionSelector* selector,
+                   InstructionCode* opcode_return, Node* node,
+                   InstructionOperand** value_return,
+                   InstructionOperand** shift_return) {
   return (
       TryMatchASR(selector, opcode_return, node, value_return, shift_return) ||
       TryMatchLSL(selector, opcode_return, node, value_return, shift_return) ||
@@ -206,11 +165,10 @@
 }
 
 
-static inline bool TryMatchImmediateOrShift(InstructionSelector* selector,
-                                            InstructionCode* opcode_return,
-                                            Node* node,
-                                            size_t* input_count_return,
-                                            InstructionOperand** inputs) {
+bool TryMatchImmediateOrShift(InstructionSelector* selector,
+                              InstructionCode* opcode_return, Node* node,
+                              size_t* input_count_return,
+                              InstructionOperand** inputs) {
   ArmOperandGenerator g(selector);
   if (g.CanBeImmediate(node, *opcode_return)) {
     *opcode_return |= AddressingModeField::encode(kMode_Operand2_I);
@@ -226,9 +184,9 @@
 }
 
 
-static void VisitBinop(InstructionSelector* selector, Node* node,
-                       InstructionCode opcode, InstructionCode reverse_opcode,
-                       FlagsContinuation* cont) {
+void VisitBinop(InstructionSelector* selector, Node* node,
+                InstructionCode opcode, InstructionCode reverse_opcode,
+                FlagsContinuation* cont) {
   ArmOperandGenerator g(selector);
   Int32BinopMatcher m(node);
   InstructionOperand* inputs[5];
@@ -236,8 +194,20 @@
   InstructionOperand* outputs[2];
   size_t output_count = 0;
 
-  if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
-                               &input_count, &inputs[1])) {
+  if (m.left().node() == m.right().node()) {
+    // If both inputs refer to the same operand, enforce allocating a register
+    // for both of them to ensure that we don't end up generating code like
+    // this:
+    //
+    //   mov r0, r1, asr #16
+    //   adds r0, r0, r1, asr #16
+    //   bvs label
+    InstructionOperand* const input = g.UseRegister(m.left().node());
+    opcode |= AddressingModeField::encode(kMode_Operand2_R);
+    inputs[input_count++] = input;
+    inputs[input_count++] = input;
+  } else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
+                                      &input_count, &inputs[1])) {
     inputs[0] = g.UseRegister(m.left().node());
     input_count++;
   } else if (TryMatchImmediateOrShift(selector, &reverse_opcode,
@@ -274,13 +244,16 @@
 }
 
 
-static void VisitBinop(InstructionSelector* selector, Node* node,
-                       InstructionCode opcode, InstructionCode reverse_opcode) {
+void VisitBinop(InstructionSelector* selector, Node* node,
+                InstructionCode opcode, InstructionCode reverse_opcode) {
   FlagsContinuation cont;
   VisitBinop(selector, node, opcode, reverse_opcode, &cont);
 }
 
 
+}  // namespace
+
+
 void InstructionSelector::VisitLoad(Node* node) {
   MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
   MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
@@ -291,10 +264,10 @@
   ArchOpcode opcode;
   switch (rep) {
     case kRepFloat32:
-      opcode = kArmVldr32;
+      opcode = kArmVldrF32;
       break;
     case kRepFloat64:
-      opcode = kArmVldr64;
+      opcode = kArmVldrF64;
       break;
     case kRepBit:  // Fall through.
     case kRepWord8:
@@ -346,10 +319,10 @@
   ArchOpcode opcode;
   switch (rep) {
     case kRepFloat32:
-      opcode = kArmVstr32;
+      opcode = kArmVstrF32;
       break;
     case kRepFloat64:
-      opcode = kArmVstr64;
+      opcode = kArmVstrF64;
       break;
     case kRepBit:  // Fall through.
     case kRepWord8:
@@ -377,8 +350,86 @@
 }
 
 
-static inline void EmitBic(InstructionSelector* selector, Node* node,
-                           Node* left, Node* right) {
+void InstructionSelector::VisitCheckedLoad(Node* node) {
+  MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+  MachineType typ = TypeOf(OpParameter<MachineType>(node));
+  ArmOperandGenerator g(this);
+  Node* const buffer = node->InputAt(0);
+  Node* const offset = node->InputAt(1);
+  Node* const length = node->InputAt(2);
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepWord8:
+      opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8;
+      break;
+    case kRepWord16:
+      opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16;
+      break;
+    case kRepWord32:
+      opcode = kCheckedLoadWord32;
+      break;
+    case kRepFloat32:
+      opcode = kCheckedLoadFloat32;
+      break;
+    case kRepFloat64:
+      opcode = kCheckedLoadFloat64;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+  InstructionOperand* offset_operand = g.UseRegister(offset);
+  InstructionOperand* length_operand = g.CanBeImmediate(length, kArmCmp)
+                                           ? g.UseImmediate(length)
+                                           : g.UseRegister(length);
+  Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
+       g.DefineAsRegister(node), offset_operand, length_operand,
+       g.UseRegister(buffer), offset_operand);
+}
+
+
+void InstructionSelector::VisitCheckedStore(Node* node) {
+  MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+  ArmOperandGenerator g(this);
+  Node* const buffer = node->InputAt(0);
+  Node* const offset = node->InputAt(1);
+  Node* const length = node->InputAt(2);
+  Node* const value = node->InputAt(3);
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepWord8:
+      opcode = kCheckedStoreWord8;
+      break;
+    case kRepWord16:
+      opcode = kCheckedStoreWord16;
+      break;
+    case kRepWord32:
+      opcode = kCheckedStoreWord32;
+      break;
+    case kRepFloat32:
+      opcode = kCheckedStoreFloat32;
+      break;
+    case kRepFloat64:
+      opcode = kCheckedStoreFloat64;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+  InstructionOperand* offset_operand = g.UseRegister(offset);
+  InstructionOperand* length_operand = g.CanBeImmediate(length, kArmCmp)
+                                           ? g.UseImmediate(length)
+                                           : g.UseRegister(length);
+  Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), nullptr,
+       offset_operand, length_operand, g.UseRegister(value),
+       g.UseRegister(buffer), offset_operand);
+}
+
+
+namespace {
+
+void EmitBic(InstructionSelector* selector, Node* node, Node* left,
+             Node* right) {
   ArmOperandGenerator g(selector);
   InstructionCode opcode = kArmBic;
   InstructionOperand* value_operand;
@@ -394,6 +445,18 @@
 }
 
 
+void EmitUbfx(InstructionSelector* selector, Node* node, Node* left,
+              uint32_t lsb, uint32_t width) {
+  DCHECK_LE(1, width);
+  DCHECK_LE(width, 32 - lsb);
+  ArmOperandGenerator g(selector);
+  selector->Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(left),
+                 g.TempImmediate(lsb), g.TempImmediate(width));
+}
+
+}  // namespace
+
+
 void InstructionSelector::VisitWord32And(Node* node) {
   ArmOperandGenerator g(this);
   Int32BinopMatcher m(node);
@@ -411,33 +474,50 @@
       return;
     }
   }
-  if (IsSupported(ARMv7) && m.right().HasValue()) {
-    uint32_t value = m.right().Value();
+  if (m.right().HasValue()) {
+    uint32_t const value = m.right().Value();
     uint32_t width = base::bits::CountPopulation32(value);
     uint32_t msb = base::bits::CountLeadingZeros32(value);
-    if (width != 0 && msb + width == 32) {
+    // Try to interpret this AND as UBFX.
+    if (IsSupported(ARMv7) && width != 0 && msb + width == 32) {
       DCHECK_EQ(0, base::bits::CountTrailingZeros32(value));
       if (m.left().IsWord32Shr()) {
         Int32BinopMatcher mleft(m.left().node());
         if (mleft.right().IsInRange(0, 31)) {
-          Emit(kArmUbfx, g.DefineAsRegister(node),
-               g.UseRegister(mleft.left().node()),
-               g.UseImmediate(mleft.right().node()), g.TempImmediate(width));
-          return;
+          // UBFX cannot extract bits past the register size, however since
+          // shifting the original value would have introduced some zeros we can
+          // still use UBFX with a smaller mask and the remaining bits will be
+          // zeros.
+          uint32_t const lsb = mleft.right().Value();
+          return EmitUbfx(this, node, mleft.left().node(), lsb,
+                          std::min(width, 32 - lsb));
         }
       }
-      Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
-           g.TempImmediate(0), g.TempImmediate(width));
+      return EmitUbfx(this, node, m.left().node(), 0, width);
+    }
+    // Try to interpret this AND as BIC.
+    if (g.CanBeImmediate(~value)) {
+      Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I),
+           g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+           g.TempImmediate(~value));
+      return;
+    }
+    // Try to interpret this AND as UXTH.
+    if (value == 0xffff) {
+      Emit(kArmUxth, g.DefineAsRegister(m.node()),
+           g.UseRegister(m.left().node()), g.TempImmediate(0));
       return;
     }
     // Try to interpret this AND as BFC.
-    width = 32 - width;
-    msb = base::bits::CountLeadingZeros32(~value);
-    uint32_t lsb = base::bits::CountTrailingZeros32(~value);
-    if (msb + width + lsb == 32) {
-      Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
-           g.TempImmediate(lsb), g.TempImmediate(width));
-      return;
+    if (IsSupported(ARMv7)) {
+      width = 32 - width;
+      msb = base::bits::CountLeadingZeros32(~value);
+      uint32_t lsb = base::bits::CountTrailingZeros32(~value);
+      if (msb + width + lsb == 32) {
+        Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
+             g.TempImmediate(lsb), g.TempImmediate(width));
+        return;
+      }
     }
   }
   VisitBinop(this, node, kArmAnd, kArmAnd);
@@ -530,10 +610,7 @@
       uint32_t msb = base::bits::CountLeadingZeros32(value);
       if (msb + width + lsb == 32) {
         DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(value));
-        Emit(kArmUbfx, g.DefineAsRegister(node),
-             g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
-             g.TempImmediate(width));
-        return;
+        return EmitUbfx(this, node, mleft.left().node(), lsb, width);
       }
     }
   }
@@ -542,6 +619,20 @@
 
 
 void InstructionSelector::VisitWord32Sar(Node* node) {
+  ArmOperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  if (CanCover(m.node(), m.left().node()) && m.left().IsWord32Shl()) {
+    Int32BinopMatcher mleft(m.left().node());
+    if (mleft.right().Is(16) && m.right().Is(16)) {
+      Emit(kArmSxth, g.DefineAsRegister(node),
+           g.UseRegister(mleft.left().node()), g.TempImmediate(0));
+      return;
+    } else if (mleft.right().Is(24) && m.right().Is(24)) {
+      Emit(kArmSxtb, g.DefineAsRegister(node),
+           g.UseRegister(mleft.left().node()), g.TempImmediate(0));
+      return;
+    }
+  }
   VisitShift(this, node, TryMatchASR);
 }
 
@@ -554,17 +645,113 @@
 void InstructionSelector::VisitInt32Add(Node* node) {
   ArmOperandGenerator g(this);
   Int32BinopMatcher m(node);
-  if (m.left().IsInt32Mul() && CanCover(node, m.left().node())) {
-    Int32BinopMatcher mleft(m.left().node());
-    Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mleft.left().node()),
-         g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node()));
-    return;
+  if (CanCover(node, m.left().node())) {
+    switch (m.left().opcode()) {
+      case IrOpcode::kInt32Mul: {
+        Int32BinopMatcher mleft(m.left().node());
+        Emit(kArmMla, g.DefineAsRegister(node),
+             g.UseRegister(mleft.left().node()),
+             g.UseRegister(mleft.right().node()),
+             g.UseRegister(m.right().node()));
+        return;
+      }
+      case IrOpcode::kInt32MulHigh: {
+        Int32BinopMatcher mleft(m.left().node());
+        Emit(kArmSmmla, g.DefineAsRegister(node),
+             g.UseRegister(mleft.left().node()),
+             g.UseRegister(mleft.right().node()),
+             g.UseRegister(m.right().node()));
+        return;
+      }
+      case IrOpcode::kWord32And: {
+        Int32BinopMatcher mleft(m.left().node());
+        if (mleft.right().Is(0xff)) {
+          Emit(kArmUxtab, g.DefineAsRegister(node),
+               g.UseRegister(m.right().node()),
+               g.UseRegister(mleft.left().node()), g.TempImmediate(0));
+          return;
+        } else if (mleft.right().Is(0xffff)) {
+          Emit(kArmUxtah, g.DefineAsRegister(node),
+               g.UseRegister(m.right().node()),
+               g.UseRegister(mleft.left().node()), g.TempImmediate(0));
+          return;
+        }
+      }
+      case IrOpcode::kWord32Sar: {
+        Int32BinopMatcher mleft(m.left().node());
+        if (CanCover(mleft.node(), mleft.left().node()) &&
+            mleft.left().IsWord32Shl()) {
+          Int32BinopMatcher mleftleft(mleft.left().node());
+          if (mleft.right().Is(24) && mleftleft.right().Is(24)) {
+            Emit(kArmSxtab, g.DefineAsRegister(node),
+                 g.UseRegister(m.right().node()),
+                 g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
+            return;
+          } else if (mleft.right().Is(16) && mleftleft.right().Is(16)) {
+            Emit(kArmSxtah, g.DefineAsRegister(node),
+                 g.UseRegister(m.right().node()),
+                 g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
+            return;
+          }
+        }
+      }
+      default:
+        break;
+    }
   }
-  if (m.right().IsInt32Mul() && CanCover(node, m.right().node())) {
-    Int32BinopMatcher mright(m.right().node());
-    Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mright.left().node()),
-         g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
-    return;
+  if (CanCover(node, m.right().node())) {
+    switch (m.right().opcode()) {
+      case IrOpcode::kInt32Mul: {
+        Int32BinopMatcher mright(m.right().node());
+        Emit(kArmMla, g.DefineAsRegister(node),
+             g.UseRegister(mright.left().node()),
+             g.UseRegister(mright.right().node()),
+             g.UseRegister(m.left().node()));
+        return;
+      }
+      case IrOpcode::kInt32MulHigh: {
+        Int32BinopMatcher mright(m.right().node());
+        Emit(kArmSmmla, g.DefineAsRegister(node),
+             g.UseRegister(mright.left().node()),
+             g.UseRegister(mright.right().node()),
+             g.UseRegister(m.left().node()));
+        return;
+      }
+      case IrOpcode::kWord32And: {
+        Int32BinopMatcher mright(m.right().node());
+        if (mright.right().Is(0xff)) {
+          Emit(kArmUxtab, g.DefineAsRegister(node),
+               g.UseRegister(m.left().node()),
+               g.UseRegister(mright.left().node()), g.TempImmediate(0));
+          return;
+        } else if (mright.right().Is(0xffff)) {
+          Emit(kArmUxtah, g.DefineAsRegister(node),
+               g.UseRegister(m.left().node()),
+               g.UseRegister(mright.left().node()), g.TempImmediate(0));
+          return;
+        }
+      }
+      case IrOpcode::kWord32Sar: {
+        Int32BinopMatcher mright(m.right().node());
+        if (CanCover(mright.node(), mright.left().node()) &&
+            mright.left().IsWord32Shl()) {
+          Int32BinopMatcher mrightleft(mright.left().node());
+          if (mright.right().Is(24) && mrightleft.right().Is(24)) {
+            Emit(kArmSxtab, g.DefineAsRegister(node),
+                 g.UseRegister(m.left().node()),
+                 g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
+            return;
+          } else if (mright.right().Is(16) && mrightleft.right().Is(16)) {
+            Emit(kArmSxtah, g.DefineAsRegister(node),
+                 g.UseRegister(m.left().node()),
+                 g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
+            return;
+          }
+        }
+      }
+      default:
+        break;
+    }
   }
   VisitBinop(this, node, kArmAdd, kArmAdd);
 }
@@ -609,6 +796,22 @@
 }
 
 
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  ArmOperandGenerator g(this);
+  Emit(kArmSmmul, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
+       g.UseRegister(node->InputAt(1)));
+}
+
+
+void InstructionSelector::VisitUint32MulHigh(Node* node) {
+  ArmOperandGenerator g(this);
+  InstructionOperand* outputs[] = {g.TempRegister(), g.DefineAsRegister(node)};
+  InstructionOperand* inputs[] = {g.UseRegister(node->InputAt(0)),
+                                  g.UseRegister(node->InputAt(1))};
+  Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs);
+}
+
+
 static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
                     ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
                     InstructionOperand* result_operand,
@@ -646,7 +849,7 @@
 }
 
 
-void InstructionSelector::VisitInt32UDiv(Node* node) {
+void InstructionSelector::VisitUint32Div(Node* node) {
   VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
 }
 
@@ -678,11 +881,18 @@
 }
 
 
-void InstructionSelector::VisitInt32UMod(Node* node) {
+void InstructionSelector::VisitUint32Mod(Node* node) {
   VisitMod(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
 }
 
 
+void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
+  ArmOperandGenerator g(this);
+  Emit(kArmVcvtF64F32, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
   ArmOperandGenerator g(this);
   Emit(kArmVcvtF64S32, g.DefineAsRegister(node),
@@ -711,18 +921,25 @@
 }
 
 
+void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
+  ArmOperandGenerator g(this);
+  Emit(kArmVcvtF32F64, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitFloat64Add(Node* node) {
   ArmOperandGenerator g(this);
-  Int32BinopMatcher m(node);
+  Float64BinopMatcher m(node);
   if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) {
-    Int32BinopMatcher mleft(m.left().node());
+    Float64BinopMatcher mleft(m.left().node());
     Emit(kArmVmlaF64, g.DefineSameAsFirst(node),
          g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
          g.UseRegister(mleft.right().node()));
     return;
   }
   if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
-    Int32BinopMatcher mright(m.right().node());
+    Float64BinopMatcher mright(m.right().node());
     Emit(kArmVmlaF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
          g.UseRegister(mright.left().node()),
          g.UseRegister(mright.right().node()));
@@ -734,9 +951,14 @@
 
 void InstructionSelector::VisitFloat64Sub(Node* node) {
   ArmOperandGenerator g(this);
-  Int32BinopMatcher m(node);
+  Float64BinopMatcher m(node);
+  if (m.left().IsMinusZero()) {
+    Emit(kArmVnegF64, g.DefineAsRegister(node),
+         g.UseRegister(m.right().node()));
+    return;
+  }
   if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
-    Int32BinopMatcher mright(m.right().node());
+    Float64BinopMatcher mright(m.right().node());
     Emit(kArmVmlsF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
          g.UseRegister(mright.left().node()),
          g.UseRegister(mright.right().node()));
@@ -747,13 +969,7 @@
 
 
 void InstructionSelector::VisitFloat64Mul(Node* node) {
-  ArmOperandGenerator g(this);
-  Float64BinopMatcher m(node);
-  if (m.right().Is(-1.0)) {
-    Emit(kArmVnegF64, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
-  } else {
-    VisitRRRFloat64(this, kArmVmulF64, node);
-  }
+  VisitRRRFloat64(this, kArmVmulF64, node);
 }
 
 
@@ -775,15 +991,38 @@
 }
 
 
-void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
-                                    BasicBlock* deoptimization) {
+void InstructionSelector::VisitFloat64Floor(Node* node) {
+  DCHECK(CpuFeatures::IsSupported(ARMv8));
+  VisitRRFloat64(this, kArmVfloorF64, node);
+}
+
+
+void InstructionSelector::VisitFloat64Ceil(Node* node) {
+  DCHECK(CpuFeatures::IsSupported(ARMv8));
+  VisitRRFloat64(this, kArmVceilF64, node);
+}
+
+
+void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
+  DCHECK(CpuFeatures::IsSupported(ARMv8));
+  VisitRRFloat64(this, kArmVroundTruncateF64, node);
+}
+
+
+void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
+  DCHECK(CpuFeatures::IsSupported(ARMv8));
+  VisitRRFloat64(this, kArmVroundTiesAwayF64, node);
+}
+
+
+void InstructionSelector::VisitCall(Node* node) {
   ArmOperandGenerator g(this);
-  CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call);
+  const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
 
   FrameStateDescriptor* frame_state_descriptor = NULL;
   if (descriptor->NeedsFrameState()) {
     frame_state_descriptor =
-        GetFrameStateDescriptor(call->InputAt(descriptor->InputCount()));
+        GetFrameStateDescriptor(node->InputAt(descriptor->InputCount()));
   }
 
   CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
@@ -792,7 +1031,7 @@
   // TODO(turbofan): on ARM64 it's probably better to use the code object in a
   // register if there are multiple uses of it. Improve constant pool and the
   // heuristics in the register allocator for where to emit constants.
-  InitializeCallBuffer(call, &buffer, true, false);
+  InitializeCallBuffer(node, &buffer, true, false);
 
   // TODO(dcarney): might be possible to use claim/poke instead
   // Push any stack arguments.
@@ -818,34 +1057,39 @@
   opcode |= MiscField::encode(descriptor->flags());
 
   // Emit the call instruction.
+  InstructionOperand** first_output =
+      buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL;
   Instruction* call_instr =
-      Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(),
+      Emit(opcode, buffer.outputs.size(), first_output,
            buffer.instruction_args.size(), &buffer.instruction_args.front());
-
   call_instr->MarkAsCall();
-  if (deoptimization != NULL) {
-    DCHECK(continuation != NULL);
-    call_instr->MarkAsControl();
+}
+
+
+namespace {
+
+// Shared routine for multiple float compare operations.
+void VisitFloat64Compare(InstructionSelector* selector, Node* node,
+                         FlagsContinuation* cont) {
+  ArmOperandGenerator g(selector);
+  Float64BinopMatcher m(node);
+  if (cont->IsBranch()) {
+    selector->Emit(cont->Encode(kArmVcmpF64), nullptr,
+                   g.UseRegister(m.left().node()),
+                   g.UseRegister(m.right().node()), g.Label(cont->true_block()),
+                   g.Label(cont->false_block()))->MarkAsControl();
+  } else {
+    DCHECK(cont->IsSet());
+    selector->Emit(
+        cont->Encode(kArmVcmpF64), g.DefineAsRegister(cont->result()),
+        g.UseRegister(m.left().node()), g.UseRegister(m.right().node()));
   }
 }
 
 
-void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
-                                                    FlagsContinuation* cont) {
-  VisitBinop(this, node, kArmAdd, kArmAdd, cont);
-}
-
-
-void InstructionSelector::VisitInt32SubWithOverflow(Node* node,
-                                                    FlagsContinuation* cont) {
-  VisitBinop(this, node, kArmSub, kArmRsb, cont);
-}
-
-
-// Shared routine for multiple compare operations.
-static void VisitWordCompare(InstructionSelector* selector, Node* node,
-                             InstructionCode opcode, FlagsContinuation* cont,
-                             bool commutative) {
+// Shared routine for multiple word compare operations.
+void VisitWordCompare(InstructionSelector* selector, Node* node,
+                      InstructionCode opcode, FlagsContinuation* cont) {
   ArmOperandGenerator g(selector);
   Int32BinopMatcher m(node);
   InstructionOperand* inputs[5];
@@ -859,7 +1103,7 @@
     input_count++;
   } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(),
                                       &input_count, &inputs[1])) {
-    if (!commutative) cont->Commute();
+    if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
     inputs[0] = g.UseRegister(m.right().node());
     input_count++;
   } else {
@@ -886,63 +1130,211 @@
 }
 
 
-void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) {
-  switch (node->opcode()) {
-    case IrOpcode::kInt32Add:
-      return VisitWordCompare(this, node, kArmCmn, cont, true);
-    case IrOpcode::kInt32Sub:
-      return VisitWordCompare(this, node, kArmCmp, cont, false);
-    case IrOpcode::kWord32And:
-      return VisitWordCompare(this, node, kArmTst, cont, true);
-    case IrOpcode::kWord32Or:
-      return VisitBinop(this, node, kArmOrr, kArmOrr, cont);
-    case IrOpcode::kWord32Xor:
-      return VisitWordCompare(this, node, kArmTeq, cont, true);
-    case IrOpcode::kWord32Sar:
-      return VisitShift(this, node, TryMatchASR, cont);
-    case IrOpcode::kWord32Shl:
-      return VisitShift(this, node, TryMatchLSL, cont);
-    case IrOpcode::kWord32Shr:
-      return VisitShift(this, node, TryMatchLSR, cont);
-    case IrOpcode::kWord32Ror:
-      return VisitShift(this, node, TryMatchROR, cont);
-    default:
-      break;
+void VisitWordCompare(InstructionSelector* selector, Node* node,
+                      FlagsContinuation* cont) {
+  VisitWordCompare(selector, node, kArmCmp, cont);
+}
+
+
+// Shared routine for word comparisons against zero.
+void VisitWordCompareZero(InstructionSelector* selector, Node* user,
+                          Node* value, FlagsContinuation* cont) {
+  while (selector->CanCover(user, value)) {
+    switch (value->opcode()) {
+      case IrOpcode::kWord32Equal: {
+        // Combine with comparisons against 0 by simply inverting the
+        // continuation.
+        Int32BinopMatcher m(value);
+        if (m.right().Is(0)) {
+          user = value;
+          value = m.left().node();
+          cont->Negate();
+          continue;
+        }
+        cont->OverwriteAndNegateIfEqual(kEqual);
+        return VisitWordCompare(selector, value, cont);
+      }
+      case IrOpcode::kInt32LessThan:
+        cont->OverwriteAndNegateIfEqual(kSignedLessThan);
+        return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kInt32LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
+        return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kUint32LessThan:
+        cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
+        return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kUint32LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
+        return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kFloat64Equal:
+        cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
+        return VisitFloat64Compare(selector, value, cont);
+      case IrOpcode::kFloat64LessThan:
+        cont->OverwriteAndNegateIfEqual(kUnorderedLessThan);
+        return VisitFloat64Compare(selector, value, cont);
+      case IrOpcode::kFloat64LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual);
+        return VisitFloat64Compare(selector, value, cont);
+      case IrOpcode::kProjection:
+        // Check if this is the overflow output projection of an
+        // <Operation>WithOverflow node.
+        if (OpParameter<size_t>(value) == 1u) {
+          // We cannot combine the <Operation>WithOverflow with this branch
+          // unless the 0th projection (the use of the actual value of the
+          // <Operation> is either NULL, which means there's no use of the
+          // actual value, or was already defined, which means it is scheduled
+          // *AFTER* this branch).
+          Node* const node = value->InputAt(0);
+          Node* const result = node->FindProjection(0);
+          if (!result || selector->IsDefined(result)) {
+            switch (node->opcode()) {
+              case IrOpcode::kInt32AddWithOverflow:
+                cont->OverwriteAndNegateIfEqual(kOverflow);
+                return VisitBinop(selector, node, kArmAdd, kArmAdd, cont);
+              case IrOpcode::kInt32SubWithOverflow:
+                cont->OverwriteAndNegateIfEqual(kOverflow);
+                return VisitBinop(selector, node, kArmSub, kArmRsb, cont);
+              default:
+                break;
+            }
+          }
+        }
+        break;
+      case IrOpcode::kInt32Add:
+        return VisitWordCompare(selector, value, kArmCmn, cont);
+      case IrOpcode::kInt32Sub:
+        return VisitWordCompare(selector, value, kArmCmp, cont);
+      case IrOpcode::kWord32And:
+        return VisitWordCompare(selector, value, kArmTst, cont);
+      case IrOpcode::kWord32Or:
+        return VisitBinop(selector, value, kArmOrr, kArmOrr, cont);
+      case IrOpcode::kWord32Xor:
+        return VisitWordCompare(selector, value, kArmTeq, cont);
+      case IrOpcode::kWord32Sar:
+        return VisitShift(selector, value, TryMatchASR, cont);
+      case IrOpcode::kWord32Shl:
+        return VisitShift(selector, value, TryMatchLSL, cont);
+      case IrOpcode::kWord32Shr:
+        return VisitShift(selector, value, TryMatchLSR, cont);
+      case IrOpcode::kWord32Ror:
+        return VisitShift(selector, value, TryMatchROR, cont);
+      default:
+        break;
+    }
+    break;
   }
 
-  ArmOperandGenerator g(this);
-  InstructionCode opcode =
+  // Continuation could not be combined with a compare, emit compare against 0.
+  ArmOperandGenerator g(selector);
+  InstructionCode const opcode =
       cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R);
+  InstructionOperand* const value_operand = g.UseRegister(value);
   if (cont->IsBranch()) {
-    Emit(opcode, NULL, g.UseRegister(node), g.UseRegister(node),
-         g.Label(cont->true_block()),
-         g.Label(cont->false_block()))->MarkAsControl();
+    selector->Emit(opcode, nullptr, value_operand, value_operand,
+                   g.Label(cont->true_block()),
+                   g.Label(cont->false_block()))->MarkAsControl();
   } else {
-    Emit(opcode, g.DefineAsRegister(cont->result()), g.UseRegister(node),
-         g.UseRegister(node));
+    selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
+                   value_operand);
   }
 }
 
+}  // namespace
 
-void InstructionSelector::VisitWord32Compare(Node* node,
-                                             FlagsContinuation* cont) {
-  VisitWordCompare(this, node, kArmCmp, cont, false);
+
+void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
+                                      BasicBlock* fbranch) {
+  FlagsContinuation cont(kNotEqual, tbranch, fbranch);
+  VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
 }
 
 
-void InstructionSelector::VisitFloat64Compare(Node* node,
-                                              FlagsContinuation* cont) {
-  ArmOperandGenerator g(this);
-  Float64BinopMatcher m(node);
-  if (cont->IsBranch()) {
-    Emit(cont->Encode(kArmVcmpF64), NULL, g.UseRegister(m.left().node()),
-         g.UseRegister(m.right().node()), g.Label(cont->true_block()),
-         g.Label(cont->false_block()))->MarkAsControl();
-  } else {
-    DCHECK(cont->IsSet());
-    Emit(cont->Encode(kArmVcmpF64), g.DefineAsRegister(cont->result()),
-         g.UseRegister(m.left().node()), g.UseRegister(m.right().node()));
+void InstructionSelector::VisitWord32Equal(Node* const node) {
+  FlagsContinuation cont(kEqual, node);
+  Int32BinopMatcher m(node);
+  if (m.right().Is(0)) {
+    return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
   }
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32LessThan(Node* node) {
+  FlagsContinuation cont(kSignedLessThan, node);
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kSignedLessThanOrEqual, node);
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitUint32LessThan(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThan, node);
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
+  if (Node* ovf = node->FindProjection(1)) {
+    FlagsContinuation cont(kOverflow, ovf);
+    return VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
+  }
+  FlagsContinuation cont;
+  VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
+}
+
+
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+  if (Node* ovf = node->FindProjection(1)) {
+    FlagsContinuation cont(kOverflow, ovf);
+    return VisitBinop(this, node, kArmSub, kArmRsb, &cont);
+  }
+  FlagsContinuation cont;
+  VisitBinop(this, node, kArmSub, kArmRsb, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64Equal(Node* node) {
+  FlagsContinuation cont(kUnorderedEqual, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64LessThan(Node* node) {
+  FlagsContinuation cont(kUnorderedLessThan, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnorderedLessThanOrEqual, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+// static
+MachineOperatorBuilder::Flags
+InstructionSelector::SupportedMachineOperatorFlags() {
+  MachineOperatorBuilder::Flags flags =
+      MachineOperatorBuilder::kInt32DivIsSafe |
+      MachineOperatorBuilder::kUint32DivIsSafe;
+
+  if (CpuFeatures::IsSupported(ARMv8)) {
+    flags |= MachineOperatorBuilder::kFloat64Floor |
+             MachineOperatorBuilder::kFloat64Ceil |
+             MachineOperatorBuilder::kFloat64RoundTruncate |
+             MachineOperatorBuilder::kFloat64RoundTiesAway;
+  }
+  return flags;
 }
 
 }  // namespace compiler
diff --git a/src/compiler/arm/linkage-arm.cc b/src/compiler/arm/linkage-arm.cc
index 6673a47..3fca76f 100644
--- a/src/compiler/arm/linkage-arm.cc
+++ b/src/compiler/arm/linkage-arm.cc
@@ -35,8 +35,9 @@
 
 typedef LinkageHelper<ArmLinkageHelperTraits> LH;
 
-CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
-  return LH::GetJSCallDescriptor(zone, parameter_count);
+CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone,
+                                             CallDescriptor::Flags flags) {
+  return LH::GetJSCallDescriptor(zone, parameter_count, flags);
 }
 
 
@@ -49,10 +50,10 @@
 
 
 CallDescriptor* Linkage::GetStubCallDescriptor(
-    CallInterfaceDescriptor descriptor, int stack_parameter_count,
-    CallDescriptor::Flags flags, Zone* zone) {
+    const CallInterfaceDescriptor& descriptor, int stack_parameter_count,
+    CallDescriptor::Flags flags, Operator::Properties properties, Zone* zone) {
   return LH::GetStubCallDescriptor(zone, descriptor, stack_parameter_count,
-                                   flags);
+                                   flags, properties);
 }
 
 
diff --git a/src/compiler/arm64/code-generator-arm64.cc b/src/compiler/arm64/code-generator-arm64.cc
index 31c53d3..e025236 100644
--- a/src/compiler/arm64/code-generator-arm64.cc
+++ b/src/compiler/arm64/code-generator-arm64.cc
@@ -24,6 +24,18 @@
   Arm64OperandConverter(CodeGenerator* gen, Instruction* instr)
       : InstructionOperandConverter(gen, instr) {}
 
+  DoubleRegister InputFloat32Register(int index) {
+    return InputDoubleRegister(index).S();
+  }
+
+  DoubleRegister InputFloat64Register(int index) {
+    return InputDoubleRegister(index);
+  }
+
+  DoubleRegister OutputFloat32Register() { return OutputDoubleRegister().S(); }
+
+  DoubleRegister OutputFloat64Register() { return OutputDoubleRegister(); }
+
   Register InputRegister32(int index) {
     return ToRegister(instr_->InputAt(index)).W();
   }
@@ -46,26 +58,68 @@
 
   Register OutputRegister32() { return ToRegister(instr_->Output()).W(); }
 
+  Operand InputOperand2_32(int index) {
+    switch (AddressingModeField::decode(instr_->opcode())) {
+      case kMode_None:
+        return InputOperand32(index);
+      case kMode_Operand2_R_LSL_I:
+        return Operand(InputRegister32(index), LSL, InputInt5(index + 1));
+      case kMode_Operand2_R_LSR_I:
+        return Operand(InputRegister32(index), LSR, InputInt5(index + 1));
+      case kMode_Operand2_R_ASR_I:
+        return Operand(InputRegister32(index), ASR, InputInt5(index + 1));
+      case kMode_Operand2_R_ROR_I:
+        return Operand(InputRegister32(index), ROR, InputInt5(index + 1));
+      case kMode_MRI:
+      case kMode_MRR:
+        break;
+    }
+    UNREACHABLE();
+    return Operand(-1);
+  }
+
+  Operand InputOperand2_64(int index) {
+    switch (AddressingModeField::decode(instr_->opcode())) {
+      case kMode_None:
+        return InputOperand64(index);
+      case kMode_Operand2_R_LSL_I:
+        return Operand(InputRegister64(index), LSL, InputInt6(index + 1));
+      case kMode_Operand2_R_LSR_I:
+        return Operand(InputRegister64(index), LSR, InputInt6(index + 1));
+      case kMode_Operand2_R_ASR_I:
+        return Operand(InputRegister64(index), ASR, InputInt6(index + 1));
+      case kMode_Operand2_R_ROR_I:
+        return Operand(InputRegister64(index), ROR, InputInt6(index + 1));
+      case kMode_MRI:
+      case kMode_MRR:
+        break;
+    }
+    UNREACHABLE();
+    return Operand(-1);
+  }
+
   MemOperand MemoryOperand(int* first_index) {
     const int index = *first_index;
     switch (AddressingModeField::decode(instr_->opcode())) {
       case kMode_None:
+      case kMode_Operand2_R_LSL_I:
+      case kMode_Operand2_R_LSR_I:
+      case kMode_Operand2_R_ASR_I:
+      case kMode_Operand2_R_ROR_I:
         break;
       case kMode_MRI:
         *first_index += 2;
         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
       case kMode_MRR:
         *first_index += 2;
-        return MemOperand(InputRegister(index + 0), InputRegister(index + 1),
-                          SXTW);
+        return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
     }
     UNREACHABLE();
     return MemOperand(no_reg);
   }
 
-  MemOperand MemoryOperand() {
-    int index = 0;
-    return MemoryOperand(&index);
+  MemOperand MemoryOperand(int first_index = 0) {
+    return MemoryOperand(&first_index);
   }
 
   Operand ToOperand(InstructionOperand* op) {
@@ -89,6 +143,9 @@
         return Operand(constant.ToInt32());
       case Constant::kInt64:
         return Operand(constant.ToInt64());
+      case Constant::kFloat32:
+        return Operand(
+            isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
       case Constant::kFloat64:
         return Operand(
             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
@@ -96,6 +153,9 @@
         return Operand(constant.ToExternalReference());
       case Constant::kHeapObject:
         return Operand(constant.ToHeapObject());
+      case Constant::kRpoNumber:
+        UNREACHABLE();  // TODO(dcarney): RPO immediates on arm64.
+        break;
     }
     UNREACHABLE();
     return Operand(-1);
@@ -114,6 +174,106 @@
 };
 
 
+namespace {
+
+class OutOfLineLoadNaN32 FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadNaN32(CodeGenerator* gen, DoubleRegister result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL {
+    __ Fmov(result_, std::numeric_limits<float>::quiet_NaN());
+  }
+
+ private:
+  DoubleRegister const result_;
+};
+
+
+class OutOfLineLoadNaN64 FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadNaN64(CodeGenerator* gen, DoubleRegister result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL {
+    __ Fmov(result_, std::numeric_limits<double>::quiet_NaN());
+  }
+
+ private:
+  DoubleRegister const result_;
+};
+
+
+class OutOfLineLoadZero FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadZero(CodeGenerator* gen, Register result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL { __ Mov(result_, 0); }
+
+ private:
+  Register const result_;
+};
+
+}  // namespace
+
+
+#define ASSEMBLE_CHECKED_LOAD_FLOAT(width)                         \
+  do {                                                             \
+    auto result = i.OutputFloat##width##Register();                \
+    auto buffer = i.InputRegister(0);                              \
+    auto offset = i.InputRegister32(1);                            \
+    auto length = i.InputOperand32(2);                             \
+    __ Cmp(offset, length);                                        \
+    auto ool = new (zone()) OutOfLineLoadNaN##width(this, result); \
+    __ B(hs, ool->entry());                                        \
+    __ Ldr(result, MemOperand(buffer, offset, UXTW));              \
+    __ Bind(ool->exit());                                          \
+  } while (0)
+
+
+#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)             \
+  do {                                                       \
+    auto result = i.OutputRegister32();                      \
+    auto buffer = i.InputRegister(0);                        \
+    auto offset = i.InputRegister32(1);                      \
+    auto length = i.InputOperand32(2);                       \
+    __ Cmp(offset, length);                                  \
+    auto ool = new (zone()) OutOfLineLoadZero(this, result); \
+    __ B(hs, ool->entry());                                  \
+    __ asm_instr(result, MemOperand(buffer, offset, UXTW));  \
+    __ Bind(ool->exit());                                    \
+  } while (0)
+
+
+#define ASSEMBLE_CHECKED_STORE_FLOAT(width)          \
+  do {                                               \
+    auto buffer = i.InputRegister(0);                \
+    auto offset = i.InputRegister32(1);              \
+    auto length = i.InputOperand32(2);               \
+    auto value = i.InputFloat##width##Register(3);   \
+    __ Cmp(offset, length);                          \
+    Label done;                                      \
+    __ B(hs, &done);                                 \
+    __ Str(value, MemOperand(buffer, offset, UXTW)); \
+    __ Bind(&done);                                  \
+  } while (0)
+
+
+#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)          \
+  do {                                                     \
+    auto buffer = i.InputRegister(0);                      \
+    auto offset = i.InputRegister32(1);                    \
+    auto length = i.InputOperand32(2);                     \
+    auto value = i.InputRegister32(3);                     \
+    __ Cmp(offset, length);                                \
+    Label done;                                            \
+    __ B(hs, &done);                                       \
+    __ asm_instr(value, MemOperand(buffer, offset, UXTW)); \
+    __ Bind(&done);                                        \
+  } while (0)
+
+
 #define ASSEMBLE_SHIFT(asm_instr, width)                                       \
   do {                                                                         \
     if (instr->InputAt(1)->IsRegister()) {                                     \
@@ -123,7 +283,7 @@
       int64_t imm = i.InputOperand##width(1).immediate().value();              \
       __ asm_instr(i.OutputRegister##width(), i.InputRegister##width(0), imm); \
     }                                                                          \
-  } while (0);
+  } while (0)
 
 
 // Assembles an instruction after register allocation, producing machine code.
@@ -161,7 +321,7 @@
       break;
     }
     case kArchJmp:
-      __ B(code_->GetLabel(i.InputBlock(0)));
+      AssembleArchJump(i.InputRpo(0));
       break;
     case kArchNop:
       // don't emit code for nops.
@@ -169,25 +329,47 @@
     case kArchRet:
       AssembleReturn();
       break;
+    case kArchStackPointer:
+      __ mov(i.OutputRegister(), masm()->StackPointer());
+      break;
     case kArchTruncateDoubleToI:
       __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
       break;
+    case kArm64Float64Ceil:
+      __ Frintp(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
+      break;
+    case kArm64Float64Floor:
+      __ Frintm(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
+      break;
+    case kArm64Float64RoundTruncate:
+      __ Frintz(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
+      break;
+    case kArm64Float64RoundTiesAway:
+      __ Frinta(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
+      break;
     case kArm64Add:
-      __ Add(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      __ Add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
       break;
     case kArm64Add32:
       if (FlagsModeField::decode(opcode) != kFlags_none) {
         __ Adds(i.OutputRegister32(), i.InputRegister32(0),
-                i.InputOperand32(1));
+                i.InputOperand2_32(1));
       } else {
-        __ Add(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
+        __ Add(i.OutputRegister32(), i.InputRegister32(0),
+               i.InputOperand2_32(1));
       }
       break;
     case kArm64And:
-      __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
       break;
     case kArm64And32:
-      __ And(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
+      __ And(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand2_32(1));
+      break;
+    case kArm64Bic:
+      __ Bic(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
+      break;
+    case kArm64Bic32:
+      __ Bic(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand2_32(1));
       break;
     case kArm64Mul:
       __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
@@ -195,6 +377,34 @@
     case kArm64Mul32:
       __ Mul(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
       break;
+    case kArm64Smull:
+      __ Smull(i.OutputRegister(), i.InputRegister32(0), i.InputRegister32(1));
+      break;
+    case kArm64Umull:
+      __ Umull(i.OutputRegister(), i.InputRegister32(0), i.InputRegister32(1));
+      break;
+    case kArm64Madd:
+      __ Madd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
+              i.InputRegister(2));
+      break;
+    case kArm64Madd32:
+      __ Madd(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1),
+              i.InputRegister32(2));
+      break;
+    case kArm64Msub:
+      __ Msub(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
+              i.InputRegister(2));
+      break;
+    case kArm64Msub32:
+      __ Msub(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1),
+              i.InputRegister32(2));
+      break;
+    case kArm64Mneg:
+      __ Mneg(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      break;
+    case kArm64Mneg32:
+      __ Mneg(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
+      break;
     case kArm64Idiv:
       __ Sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
       break;
@@ -251,44 +461,57 @@
       __ Neg(i.OutputRegister32(), i.InputOperand32(0));
       break;
     case kArm64Or:
-      __ Orr(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      __ Orr(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
       break;
     case kArm64Or32:
-      __ Orr(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
+      __ Orr(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand2_32(1));
       break;
-    case kArm64Xor:
-      __ Eor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+    case kArm64Orn:
+      __ Orn(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
       break;
-    case kArm64Xor32:
-      __ Eor(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
+    case kArm64Orn32:
+      __ Orn(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand2_32(1));
+      break;
+    case kArm64Eor:
+      __ Eor(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
+      break;
+    case kArm64Eor32:
+      __ Eor(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand2_32(1));
+      break;
+    case kArm64Eon:
+      __ Eon(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
+      break;
+    case kArm64Eon32:
+      __ Eon(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand2_32(1));
       break;
     case kArm64Sub:
-      __ Sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      __ Sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand2_64(1));
       break;
     case kArm64Sub32:
       if (FlagsModeField::decode(opcode) != kFlags_none) {
         __ Subs(i.OutputRegister32(), i.InputRegister32(0),
-                i.InputOperand32(1));
+                i.InputOperand2_32(1));
       } else {
-        __ Sub(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
+        __ Sub(i.OutputRegister32(), i.InputRegister32(0),
+               i.InputOperand2_32(1));
       }
       break;
-    case kArm64Shl:
+    case kArm64Lsl:
       ASSEMBLE_SHIFT(Lsl, 64);
       break;
-    case kArm64Shl32:
+    case kArm64Lsl32:
       ASSEMBLE_SHIFT(Lsl, 32);
       break;
-    case kArm64Shr:
+    case kArm64Lsr:
       ASSEMBLE_SHIFT(Lsr, 64);
       break;
-    case kArm64Shr32:
+    case kArm64Lsr32:
       ASSEMBLE_SHIFT(Lsr, 32);
       break;
-    case kArm64Sar:
+    case kArm64Asr:
       ASSEMBLE_SHIFT(Asr, 64);
       break;
-    case kArm64Sar32:
+    case kArm64Asr32:
       ASSEMBLE_SHIFT(Asr, 32);
       break;
     case kArm64Ror:
@@ -300,9 +523,30 @@
     case kArm64Mov32:
       __ Mov(i.OutputRegister32(), i.InputRegister32(0));
       break;
+    case kArm64Sxtb32:
+      __ Sxtb(i.OutputRegister32(), i.InputRegister32(0));
+      break;
+    case kArm64Sxth32:
+      __ Sxth(i.OutputRegister32(), i.InputRegister32(0));
+      break;
     case kArm64Sxtw:
       __ Sxtw(i.OutputRegister(), i.InputRegister32(0));
       break;
+    case kArm64Ubfx:
+      __ Ubfx(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
+              i.InputInt8(2));
+      break;
+    case kArm64Ubfx32:
+      __ Ubfx(i.OutputRegister32(), i.InputRegister32(0), i.InputInt8(1),
+              i.InputInt8(2));
+      break;
+    case kArm64TestAndBranch32:
+    case kArm64TestAndBranch:
+      // Pseudo instructions turned into tbz/tbnz in AssembleArchBranch.
+      break;
+    case kArm64CompareAndBranch32:
+      // Pseudo instruction turned into cbz/cbnz in AssembleArchBranch.
+      break;
     case kArm64Claim: {
       int words = MiscField::decode(instr->opcode());
       __ Claim(words);
@@ -376,6 +620,12 @@
     case kArm64Float64Sqrt:
       __ Fsqrt(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       break;
+    case kArm64Float32ToFloat64:
+      __ Fcvt(i.OutputDoubleRegister(), i.InputDoubleRegister(0).S());
+      break;
+    case kArm64Float64ToFloat32:
+      __ Fcvt(i.OutputDoubleRegister().S(), i.InputDoubleRegister(0));
+      break;
     case kArm64Float64ToInt32:
       __ Fcvtzs(i.OutputRegister32(), i.InputDoubleRegister(0));
       break;
@@ -418,20 +668,12 @@
     case kArm64Str:
       __ Str(i.InputRegister(2), i.MemoryOperand());
       break;
-    case kArm64LdrS: {
-      UseScratchRegisterScope scope(masm());
-      FPRegister scratch = scope.AcquireS();
-      __ Ldr(scratch, i.MemoryOperand());
-      __ Fcvt(i.OutputDoubleRegister(), scratch);
+    case kArm64LdrS:
+      __ Ldr(i.OutputDoubleRegister().S(), i.MemoryOperand());
       break;
-    }
-    case kArm64StrS: {
-      UseScratchRegisterScope scope(masm());
-      FPRegister scratch = scope.AcquireS();
-      __ Fcvt(scratch, i.InputDoubleRegister(2));
-      __ Str(scratch, i.MemoryOperand());
+    case kArm64StrS:
+      __ Str(i.InputDoubleRegister(2).S(), i.MemoryOperand());
       break;
-    }
     case kArm64LdrD:
       __ Ldr(i.OutputDoubleRegister(), i.MemoryOperand());
       break;
@@ -444,9 +686,8 @@
       Register value = i.InputRegister(2);
       __ Add(index, object, Operand(index, SXTW));
       __ Str(value, MemOperand(index));
-      SaveFPRegsMode mode = code_->frame()->DidAllocateDoubleRegisters()
-                                ? kSaveFPRegs
-                                : kDontSaveFPRegs;
+      SaveFPRegsMode mode =
+          frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
       // TODO(dcarney): we shouldn't test write barriers from c calls.
       LinkRegisterStatus lr_status = kLRHasNotBeenSaved;
       UseScratchRegisterScope scope(masm());
@@ -462,81 +703,154 @@
       }
       break;
     }
+    case kCheckedLoadInt8:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(Ldrsb);
+      break;
+    case kCheckedLoadUint8:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(Ldrb);
+      break;
+    case kCheckedLoadInt16:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(Ldrsh);
+      break;
+    case kCheckedLoadUint16:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(Ldrh);
+      break;
+    case kCheckedLoadWord32:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(Ldr);
+      break;
+    case kCheckedLoadFloat32:
+      ASSEMBLE_CHECKED_LOAD_FLOAT(32);
+      break;
+    case kCheckedLoadFloat64:
+      ASSEMBLE_CHECKED_LOAD_FLOAT(64);
+      break;
+    case kCheckedStoreWord8:
+      ASSEMBLE_CHECKED_STORE_INTEGER(Strb);
+      break;
+    case kCheckedStoreWord16:
+      ASSEMBLE_CHECKED_STORE_INTEGER(Strh);
+      break;
+    case kCheckedStoreWord32:
+      ASSEMBLE_CHECKED_STORE_INTEGER(Str);
+      break;
+    case kCheckedStoreFloat32:
+      ASSEMBLE_CHECKED_STORE_FLOAT(32);
+      break;
+    case kCheckedStoreFloat64:
+      ASSEMBLE_CHECKED_STORE_FLOAT(64);
+      break;
   }
 }
 
 
 // Assemble branches after this instruction.
-void CodeGenerator::AssembleArchBranch(Instruction* instr,
-                                       FlagsCondition condition) {
+void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
   Arm64OperandConverter i(this, instr);
-  Label done;
+  Label* tlabel = branch->true_label;
+  Label* flabel = branch->false_label;
+  FlagsCondition condition = branch->condition;
+  ArchOpcode opcode = instr->arch_opcode();
 
-  // Emit a branch. The true and false targets are always the last two inputs
-  // to the instruction.
-  BasicBlock* tblock = i.InputBlock(instr->InputCount() - 2);
-  BasicBlock* fblock = i.InputBlock(instr->InputCount() - 1);
-  bool fallthru = IsNextInAssemblyOrder(fblock);
-  Label* tlabel = code()->GetLabel(tblock);
-  Label* flabel = fallthru ? &done : code()->GetLabel(fblock);
-  switch (condition) {
-    case kUnorderedEqual:
-      __ B(vs, flabel);
-    // Fall through.
-    case kEqual:
-      __ B(eq, tlabel);
-      break;
-    case kUnorderedNotEqual:
-      __ B(vs, tlabel);
-    // Fall through.
-    case kNotEqual:
-      __ B(ne, tlabel);
-      break;
-    case kSignedLessThan:
-      __ B(lt, tlabel);
-      break;
-    case kSignedGreaterThanOrEqual:
-      __ B(ge, tlabel);
-      break;
-    case kSignedLessThanOrEqual:
-      __ B(le, tlabel);
-      break;
-    case kSignedGreaterThan:
-      __ B(gt, tlabel);
-      break;
-    case kUnorderedLessThan:
-      __ B(vs, flabel);
-    // Fall through.
-    case kUnsignedLessThan:
-      __ B(lo, tlabel);
-      break;
-    case kUnorderedGreaterThanOrEqual:
-      __ B(vs, tlabel);
-    // Fall through.
-    case kUnsignedGreaterThanOrEqual:
-      __ B(hs, tlabel);
-      break;
-    case kUnorderedLessThanOrEqual:
-      __ B(vs, flabel);
-    // Fall through.
-    case kUnsignedLessThanOrEqual:
-      __ B(ls, tlabel);
-      break;
-    case kUnorderedGreaterThan:
-      __ B(vs, tlabel);
-    // Fall through.
-    case kUnsignedGreaterThan:
-      __ B(hi, tlabel);
-      break;
-    case kOverflow:
-      __ B(vs, tlabel);
-      break;
-    case kNotOverflow:
-      __ B(vc, tlabel);
-      break;
+  if (opcode == kArm64CompareAndBranch32) {
+    switch (condition) {
+      case kEqual:
+        __ Cbz(i.InputRegister32(0), tlabel);
+        break;
+      case kNotEqual:
+        __ Cbnz(i.InputRegister32(0), tlabel);
+        break;
+      default:
+        UNREACHABLE();
+    }
+  } else if (opcode == kArm64TestAndBranch32) {
+    switch (condition) {
+      case kEqual:
+        __ Tbz(i.InputRegister32(0), i.InputInt5(1), tlabel);
+        break;
+      case kNotEqual:
+        __ Tbnz(i.InputRegister32(0), i.InputInt5(1), tlabel);
+        break;
+      default:
+        UNREACHABLE();
+    }
+  } else if (opcode == kArm64TestAndBranch) {
+    switch (condition) {
+      case kEqual:
+        __ Tbz(i.InputRegister64(0), i.InputInt6(1), tlabel);
+        break;
+      case kNotEqual:
+        __ Tbnz(i.InputRegister64(0), i.InputInt6(1), tlabel);
+        break;
+      default:
+        UNREACHABLE();
+    }
+  } else {
+    switch (condition) {
+      case kUnorderedEqual:
+        // The "eq" condition will not catch the unordered case.
+        // The jump/fall through to false label will be used if the comparison
+        // was unordered.
+      case kEqual:
+        __ B(eq, tlabel);
+        break;
+      case kUnorderedNotEqual:
+        // Unordered or not equal can be tested with "ne" condtion.
+        // See ARMv8 manual C1.2.3 - Condition Code.
+      case kNotEqual:
+        __ B(ne, tlabel);
+        break;
+      case kSignedLessThan:
+        __ B(lt, tlabel);
+        break;
+      case kSignedGreaterThanOrEqual:
+        __ B(ge, tlabel);
+        break;
+      case kSignedLessThanOrEqual:
+        __ B(le, tlabel);
+        break;
+      case kSignedGreaterThan:
+        __ B(gt, tlabel);
+        break;
+      case kUnorderedLessThan:
+        // The "lo" condition will not catch the unordered case.
+        // The jump/fall through to false label will be used if the comparison
+        // was unordered.
+      case kUnsignedLessThan:
+        __ B(lo, tlabel);
+        break;
+      case kUnorderedGreaterThanOrEqual:
+        // Unordered, greater than or equal can be tested with "hs" condtion.
+        // See ARMv8 manual C1.2.3 - Condition Code.
+      case kUnsignedGreaterThanOrEqual:
+        __ B(hs, tlabel);
+        break;
+      case kUnorderedLessThanOrEqual:
+        // The "ls" condition will not catch the unordered case.
+        // The jump/fall through to false label will be used if the comparison
+        // was unordered.
+      case kUnsignedLessThanOrEqual:
+        __ B(ls, tlabel);
+        break;
+      case kUnorderedGreaterThan:
+        // Unordered or greater than can be tested with "hi" condtion.
+        // See ARMv8 manual C1.2.3 - Condition Code.
+      case kUnsignedGreaterThan:
+        __ B(hi, tlabel);
+        break;
+      case kOverflow:
+        __ B(vs, tlabel);
+        break;
+      case kNotOverflow:
+        __ B(vc, tlabel);
+        break;
+    }
   }
-  if (!fallthru) __ B(flabel);  // no fallthru to flabel.
-  __ Bind(&done);
+  if (!branch->fallthru) __ B(flabel);  // no fallthru to flabel.
+}
+
+
+void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+  if (!IsNextInAssemblyOrder(target)) __ B(GetLabel(target));
 }
 
 
@@ -620,7 +934,7 @@
       cc = vc;
       break;
   }
-  __ bind(&check);
+  __ Bind(&check);
   __ Cset(reg, cc);
   __ Bind(&done);
 }
@@ -650,28 +964,11 @@
     __ PushCalleeSavedRegisters();
     frame()->SetRegisterSaveAreaSize(20 * kPointerSize);
   } else if (descriptor->IsJSFunctionCall()) {
-    CompilationInfo* info = linkage()->info();
+    CompilationInfo* info = this->info();
     __ SetStackPointer(jssp);
     __ Prologue(info->IsCodePreAgingActive());
     frame()->SetRegisterSaveAreaSize(
         StandardFrameConstants::kFixedFrameSizeFromFp);
-
-    // Sloppy mode functions and builtins need to replace the receiver with the
-    // global proxy when called as functions (without an explicit receiver
-    // object).
-    // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
-    if (info->strict_mode() == SLOPPY && !info->is_native()) {
-      Label ok;
-      // +2 for return address and saved frame pointer.
-      int receiver_slot = info->scope()->num_parameters() + 2;
-      __ Ldr(x10, MemOperand(fp, receiver_slot * kXRegSize));
-      __ JumpIfNotRoot(x10, Heap::kUndefinedValueRootIndex, &ok);
-      __ Ldr(x10, GlobalObjectMemOperand());
-      __ Ldr(x10, FieldMemOperand(x10, GlobalObject::kGlobalProxyOffset));
-      __ Str(x10, MemOperand(fp, receiver_slot * kXRegSize));
-      __ Bind(&ok);
-    }
-
   } else {
     __ SetStackPointer(jssp);
     __ StubPrologue();
@@ -742,12 +1039,11 @@
       __ Str(temp, g.ToMemOperand(destination, masm()));
     }
   } else if (source->IsConstant()) {
-    ConstantOperand* constant_source = ConstantOperand::cast(source);
+    Constant src = g.ToConstant(ConstantOperand::cast(source));
     if (destination->IsRegister() || destination->IsStackSlot()) {
       UseScratchRegisterScope scope(masm());
       Register dst = destination->IsRegister() ? g.ToRegister(destination)
                                                : scope.AcquireX();
-      Constant src = g.ToConstant(source);
       if (src.type() == Constant::kHeapObject) {
         __ LoadObject(dst, src.ToHeapObject());
       } else {
@@ -756,15 +1052,29 @@
       if (destination->IsStackSlot()) {
         __ Str(dst, g.ToMemOperand(destination, masm()));
       }
-    } else if (destination->IsDoubleRegister()) {
-      FPRegister result = g.ToDoubleRegister(destination);
-      __ Fmov(result, g.ToDouble(constant_source));
+    } else if (src.type() == Constant::kFloat32) {
+      if (destination->IsDoubleRegister()) {
+        FPRegister dst = g.ToDoubleRegister(destination).S();
+        __ Fmov(dst, src.ToFloat32());
+      } else {
+        DCHECK(destination->IsDoubleStackSlot());
+        UseScratchRegisterScope scope(masm());
+        FPRegister temp = scope.AcquireS();
+        __ Fmov(temp, src.ToFloat32());
+        __ Str(temp, g.ToMemOperand(destination, masm()));
+      }
     } else {
-      DCHECK(destination->IsDoubleStackSlot());
-      UseScratchRegisterScope scope(masm());
-      FPRegister temp = scope.AcquireD();
-      __ Fmov(temp, g.ToDouble(constant_source));
-      __ Str(temp, g.ToMemOperand(destination, masm()));
+      DCHECK_EQ(Constant::kFloat64, src.type());
+      if (destination->IsDoubleRegister()) {
+        FPRegister dst = g.ToDoubleRegister(destination);
+        __ Fmov(dst, src.ToFloat64());
+      } else {
+        DCHECK(destination->IsDoubleStackSlot());
+        UseScratchRegisterScope scope(masm());
+        FPRegister temp = scope.AcquireD();
+        __ Fmov(temp, src.ToFloat64());
+        __ Str(temp, g.ToMemOperand(destination, masm()));
+      }
     }
   } else if (source->IsDoubleRegister()) {
     FPRegister src = g.ToDoubleRegister(source);
@@ -816,8 +1126,8 @@
     }
   } else if (source->IsStackSlot() || source->IsDoubleStackSlot()) {
     UseScratchRegisterScope scope(masm());
-    CPURegister temp_0 = scope.AcquireX();
-    CPURegister temp_1 = scope.AcquireX();
+    DoubleRegister temp_0 = scope.AcquireD();
+    DoubleRegister temp_1 = scope.AcquireD();
     MemOperand src = g.ToMemOperand(source, masm());
     MemOperand dst = g.ToMemOperand(destination, masm());
     __ Ldr(temp_0, src);
@@ -852,7 +1162,7 @@
 
 void CodeGenerator::EnsureSpaceForLazyDeopt() {
   int space_needed = Deoptimizer::patch_size();
-  if (!linkage()->info()->IsStub()) {
+  if (!info()->IsStub()) {
     // Ensure that we have enough space after the previous lazy-bailout
     // instruction for patching the code here.
     intptr_t current_pc = masm()->pc_offset();
diff --git a/src/compiler/arm64/instruction-codes-arm64.h b/src/compiler/arm64/instruction-codes-arm64.h
index 0a9a2ed..863451f 100644
--- a/src/compiler/arm64/instruction-codes-arm64.h
+++ b/src/compiler/arm64/instruction-codes-arm64.h
@@ -16,6 +16,8 @@
   V(Arm64Add32)                    \
   V(Arm64And)                      \
   V(Arm64And32)                    \
+  V(Arm64Bic)                      \
+  V(Arm64Bic32)                    \
   V(Arm64Cmp)                      \
   V(Arm64Cmp32)                    \
   V(Arm64Cmn)                      \
@@ -24,12 +26,24 @@
   V(Arm64Tst32)                    \
   V(Arm64Or)                       \
   V(Arm64Or32)                     \
-  V(Arm64Xor)                      \
-  V(Arm64Xor32)                    \
+  V(Arm64Orn)                      \
+  V(Arm64Orn32)                    \
+  V(Arm64Eor)                      \
+  V(Arm64Eor32)                    \
+  V(Arm64Eon)                      \
+  V(Arm64Eon32)                    \
   V(Arm64Sub)                      \
   V(Arm64Sub32)                    \
   V(Arm64Mul)                      \
   V(Arm64Mul32)                    \
+  V(Arm64Smull)                    \
+  V(Arm64Umull)                    \
+  V(Arm64Madd)                     \
+  V(Arm64Madd32)                   \
+  V(Arm64Msub)                     \
+  V(Arm64Msub32)                   \
+  V(Arm64Mneg)                     \
+  V(Arm64Mneg32)                   \
   V(Arm64Idiv)                     \
   V(Arm64Idiv32)                   \
   V(Arm64Udiv)                     \
@@ -42,16 +56,23 @@
   V(Arm64Not32)                    \
   V(Arm64Neg)                      \
   V(Arm64Neg32)                    \
-  V(Arm64Shl)                      \
-  V(Arm64Shl32)                    \
-  V(Arm64Shr)                      \
-  V(Arm64Shr32)                    \
-  V(Arm64Sar)                      \
-  V(Arm64Sar32)                    \
+  V(Arm64Lsl)                      \
+  V(Arm64Lsl32)                    \
+  V(Arm64Lsr)                      \
+  V(Arm64Lsr32)                    \
+  V(Arm64Asr)                      \
+  V(Arm64Asr32)                    \
   V(Arm64Ror)                      \
   V(Arm64Ror32)                    \
   V(Arm64Mov32)                    \
+  V(Arm64Sxtb32)                   \
+  V(Arm64Sxth32)                   \
   V(Arm64Sxtw)                     \
+  V(Arm64Ubfx)                     \
+  V(Arm64Ubfx32)                   \
+  V(Arm64TestAndBranch32)          \
+  V(Arm64TestAndBranch)            \
+  V(Arm64CompareAndBranch32)       \
   V(Arm64Claim)                    \
   V(Arm64Poke)                     \
   V(Arm64PokePairZero)             \
@@ -63,6 +84,12 @@
   V(Arm64Float64Div)               \
   V(Arm64Float64Mod)               \
   V(Arm64Float64Sqrt)              \
+  V(Arm64Float64Floor)             \
+  V(Arm64Float64Ceil)              \
+  V(Arm64Float64RoundTruncate)     \
+  V(Arm64Float64RoundTiesAway)     \
+  V(Arm64Float32ToFloat64)         \
+  V(Arm64Float64ToFloat32)         \
   V(Arm64Float64ToInt32)           \
   V(Arm64Float64ToUint32)          \
   V(Arm64Int32ToFloat64)           \
@@ -97,9 +124,13 @@
 // I = immediate (handle, external, int32)
 // MRI = [register + immediate]
 // MRR = [register + register]
-#define TARGET_ADDRESSING_MODE_LIST(V) \
-  V(MRI) /* [%r0 + K] */               \
-  V(MRR) /* [%r0 + %r1] */
+#define TARGET_ADDRESSING_MODE_LIST(V)  \
+  V(MRI)              /* [%r0 + K] */   \
+  V(MRR)              /* [%r0 + %r1] */ \
+  V(Operand2_R_LSL_I) /* %r0 LSL K */   \
+  V(Operand2_R_LSR_I) /* %r0 LSR K */   \
+  V(Operand2_R_ASR_I) /* %r0 ASR K */   \
+  V(Operand2_R_ROR_I) /* %r0 ROR K */
 
 }  // namespace internal
 }  // namespace compiler
diff --git a/src/compiler/arm64/instruction-selector-arm64-unittest.cc b/src/compiler/arm64/instruction-selector-arm64-unittest.cc
deleted file mode 100644
index b5562c2..0000000
--- a/src/compiler/arm64/instruction-selector-arm64-unittest.cc
+++ /dev/null
@@ -1,1121 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <list>
-
-#include "src/compiler/instruction-selector-unittest.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-namespace {
-
-typedef RawMachineAssembler::Label MLabel;
-
-template <typename T>
-struct MachInst {
-  T constructor;
-  const char* constructor_name;
-  ArchOpcode arch_opcode;
-  MachineType machine_type;
-};
-
-typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1;
-typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2;
-
-
-template <typename T>
-std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) {
-  return os << mi.constructor_name;
-}
-
-
-// Helper to build Int32Constant or Int64Constant depending on the given
-// machine type.
-Node* BuildConstant(InstructionSelectorTest::StreamBuilder& m, MachineType type,
-                    int64_t value) {
-  switch (type) {
-    case kMachInt32:
-      return m.Int32Constant(value);
-      break;
-
-    case kMachInt64:
-      return m.Int64Constant(value);
-      break;
-
-    default:
-      UNIMPLEMENTED();
-  }
-  return NULL;
-}
-
-
-// ARM64 logical instructions.
-static const MachInst2 kLogicalInstructions[] = {
-    {&RawMachineAssembler::Word32And, "Word32And", kArm64And32, kMachInt32},
-    {&RawMachineAssembler::Word64And, "Word64And", kArm64And, kMachInt64},
-    {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Or32, kMachInt32},
-    {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Or, kMachInt64},
-    {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Xor32, kMachInt32},
-    {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Xor, kMachInt64}};
-
-
-// ARM64 logical immediates: contiguous set bits, rotated about a power of two
-// sized block. The block is then duplicated across the word. Below is a random
-// subset of the 32-bit immediates.
-static const uint32_t kLogicalImmediates[] = {
-    0x00000002, 0x00000003, 0x00000070, 0x00000080, 0x00000100, 0x000001c0,
-    0x00000300, 0x000007e0, 0x00003ffc, 0x00007fc0, 0x0003c000, 0x0003f000,
-    0x0003ffc0, 0x0003fff8, 0x0007ff00, 0x0007ffe0, 0x000e0000, 0x001e0000,
-    0x001ffffc, 0x003f0000, 0x003f8000, 0x00780000, 0x007fc000, 0x00ff0000,
-    0x01800000, 0x01800180, 0x01f801f8, 0x03fe0000, 0x03ffffc0, 0x03fffffc,
-    0x06000000, 0x07fc0000, 0x07ffc000, 0x07ffffc0, 0x07ffffe0, 0x0ffe0ffe,
-    0x0ffff800, 0x0ffffff0, 0x0fffffff, 0x18001800, 0x1f001f00, 0x1f801f80,
-    0x30303030, 0x3ff03ff0, 0x3ff83ff8, 0x3fff0000, 0x3fff8000, 0x3fffffc0,
-    0x70007000, 0x7f7f7f7f, 0x7fc00000, 0x7fffffc0, 0x8000001f, 0x800001ff,
-    0x81818181, 0x9fff9fff, 0xc00007ff, 0xc0ffffff, 0xdddddddd, 0xe00001ff,
-    0xe00003ff, 0xe007ffff, 0xefffefff, 0xf000003f, 0xf001f001, 0xf3fff3ff,
-    0xf800001f, 0xf80fffff, 0xf87ff87f, 0xfbfbfbfb, 0xfc00001f, 0xfc0000ff,
-    0xfc0001ff, 0xfc03fc03, 0xfe0001ff, 0xff000001, 0xff03ff03, 0xff800000,
-    0xff800fff, 0xff801fff, 0xff87ffff, 0xffc0003f, 0xffc007ff, 0xffcfffcf,
-    0xffe00003, 0xffe1ffff, 0xfff0001f, 0xfff07fff, 0xfff80007, 0xfff87fff,
-    0xfffc00ff, 0xfffe07ff, 0xffff00ff, 0xffffc001, 0xfffff007, 0xfffff3ff,
-    0xfffff807, 0xfffff9ff, 0xfffffc0f, 0xfffffeff};
-
-
-// ARM64 arithmetic instructions.
-static const MachInst2 kAddSubInstructions[] = {
-    {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32, kMachInt32},
-    {&RawMachineAssembler::Int64Add, "Int64Add", kArm64Add, kMachInt64},
-    {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32, kMachInt32},
-    {&RawMachineAssembler::Int64Sub, "Int64Sub", kArm64Sub, kMachInt64}};
-
-
-// ARM64 Add/Sub immediates: 12-bit immediate optionally shifted by 12.
-// Below is a combination of a random subset and some edge values.
-static const int32_t kAddSubImmediates[] = {
-    0,        1,        69,       493,      599,      701,      719,
-    768,      818,      842,      945,      1246,     1286,     1429,
-    1669,     2171,     2179,     2182,     2254,     2334,     2338,
-    2343,     2396,     2449,     2610,     2732,     2855,     2876,
-    2944,     3377,     3458,     3475,     3476,     3540,     3574,
-    3601,     3813,     3871,     3917,     4095,     4096,     16384,
-    364544,   462848,   970752,   1523712,  1863680,  2363392,  3219456,
-    3280896,  4247552,  4526080,  4575232,  4960256,  5505024,  5894144,
-    6004736,  6193152,  6385664,  6795264,  7114752,  7233536,  7348224,
-    7499776,  7573504,  7729152,  8634368,  8937472,  9465856,  10354688,
-    10682368, 11059200, 11460608, 13168640, 13176832, 14336000, 15028224,
-    15597568, 15892480, 16773120};
-
-
-// ARM64 flag setting data processing instructions.
-static const MachInst2 kDPFlagSetInstructions[] = {
-    {&RawMachineAssembler::Word32And, "Word32And", kArm64Tst32, kMachInt32},
-    {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Cmn32, kMachInt32},
-    {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Cmp32, kMachInt32}};
-
-
-// ARM64 arithmetic with overflow instructions.
-static const MachInst2 kOvfAddSubInstructions[] = {
-    {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
-     kArm64Add32, kMachInt32},
-    {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow",
-     kArm64Sub32, kMachInt32}};
-
-
-// ARM64 shift instructions.
-static const MachInst2 kShiftInstructions[] = {
-    {&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Shl32, kMachInt32},
-    {&RawMachineAssembler::Word64Shl, "Word64Shl", kArm64Shl, kMachInt64},
-    {&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Shr32, kMachInt32},
-    {&RawMachineAssembler::Word64Shr, "Word64Shr", kArm64Shr, kMachInt64},
-    {&RawMachineAssembler::Word32Sar, "Word32Sar", kArm64Sar32, kMachInt32},
-    {&RawMachineAssembler::Word64Sar, "Word64Sar", kArm64Sar, kMachInt64},
-    {&RawMachineAssembler::Word32Ror, "Word32Ror", kArm64Ror32, kMachInt32},
-    {&RawMachineAssembler::Word64Ror, "Word64Ror", kArm64Ror, kMachInt64}};
-
-
-// ARM64 Mul/Div instructions.
-static const MachInst2 kMulDivInstructions[] = {
-    {&RawMachineAssembler::Int32Mul, "Int32Mul", kArm64Mul32, kMachInt32},
-    {&RawMachineAssembler::Int64Mul, "Int64Mul", kArm64Mul, kMachInt64},
-    {&RawMachineAssembler::Int32Div, "Int32Div", kArm64Idiv32, kMachInt32},
-    {&RawMachineAssembler::Int64Div, "Int64Div", kArm64Idiv, kMachInt64},
-    {&RawMachineAssembler::Int32UDiv, "Int32UDiv", kArm64Udiv32, kMachInt32},
-    {&RawMachineAssembler::Int64UDiv, "Int64UDiv", kArm64Udiv, kMachInt64}};
-
-
-// ARM64 FP arithmetic instructions.
-static const MachInst2 kFPArithInstructions[] = {
-    {&RawMachineAssembler::Float64Add, "Float64Add", kArm64Float64Add,
-     kMachFloat64},
-    {&RawMachineAssembler::Float64Sub, "Float64Sub", kArm64Float64Sub,
-     kMachFloat64},
-    {&RawMachineAssembler::Float64Mul, "Float64Mul", kArm64Float64Mul,
-     kMachFloat64},
-    {&RawMachineAssembler::Float64Div, "Float64Div", kArm64Float64Div,
-     kMachFloat64}};
-
-
-struct FPCmp {
-  MachInst2 mi;
-  FlagsCondition cond;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const FPCmp& cmp) {
-  return os << cmp.mi;
-}
-
-
-// ARM64 FP comparison instructions.
-static const FPCmp kFPCmpInstructions[] = {
-    {{&RawMachineAssembler::Float64Equal, "Float64Equal", kArm64Float64Cmp,
-      kMachFloat64},
-     kUnorderedEqual},
-    {{&RawMachineAssembler::Float64LessThan, "Float64LessThan",
-      kArm64Float64Cmp, kMachFloat64},
-     kUnorderedLessThan},
-    {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
-      kArm64Float64Cmp, kMachFloat64},
-     kUnorderedLessThanOrEqual}};
-
-
-struct Conversion {
-  // The machine_type field in MachInst1 represents the destination type.
-  MachInst1 mi;
-  MachineType src_machine_type;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const Conversion& conv) {
-  return os << conv.mi;
-}
-
-
-// ARM64 type conversion instructions.
-static const Conversion kConversionInstructions[] = {
-    {{&RawMachineAssembler::ChangeInt32ToInt64, "ChangeInt32ToInt64",
-      kArm64Sxtw, kMachInt64},
-     kMachInt32},
-    {{&RawMachineAssembler::ChangeUint32ToUint64, "ChangeUint32ToUint64",
-      kArm64Mov32, kMachUint64},
-     kMachUint32},
-    {{&RawMachineAssembler::TruncateInt64ToInt32, "TruncateInt64ToInt32",
-      kArm64Mov32, kMachInt32},
-     kMachInt64},
-    {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
-      kArm64Int32ToFloat64, kMachFloat64},
-     kMachInt32},
-    {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
-      kArm64Uint32ToFloat64, kMachFloat64},
-     kMachUint32},
-    {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
-      kArm64Float64ToInt32, kMachInt32},
-     kMachFloat64},
-    {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
-      kArm64Float64ToUint32, kMachUint32},
-     kMachFloat64}};
-
-}  // namespace
-
-
-// -----------------------------------------------------------------------------
-// Logical instructions.
-
-
-typedef InstructionSelectorTestWithParam<MachInst2>
-    InstructionSelectorLogicalTest;
-
-
-TEST_P(InstructionSelectorLogicalTest, Parameter) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  StreamBuilder m(this, type, type, type);
-  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorLogicalTest, Immediate) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  // TODO(all): Add support for testing 64-bit immediates.
-  if (type == kMachInt32) {
-    // Immediate on the right.
-    TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
-      StreamBuilder m(this, type, type);
-      m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
-      Stream s = m.Build();
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-      ASSERT_EQ(2U, s[0]->InputCount());
-      EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
-      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-      EXPECT_EQ(1U, s[0]->OutputCount());
-    }
-
-    // Immediate on the left; all logical ops should commute.
-    TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
-      StreamBuilder m(this, type, type);
-      m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)));
-      Stream s = m.Build();
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-      ASSERT_EQ(2U, s[0]->InputCount());
-      EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
-      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-      EXPECT_EQ(1U, s[0]->OutputCount());
-    }
-  }
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest,
-                        ::testing::ValuesIn(kLogicalInstructions));
-
-
-// -----------------------------------------------------------------------------
-// Add and Sub instructions.
-
-typedef InstructionSelectorTestWithParam<MachInst2>
-    InstructionSelectorAddSubTest;
-
-
-TEST_P(InstructionSelectorAddSubTest, Parameter) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  StreamBuilder m(this, type, type, type);
-  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorAddSubTest, ImmediateOnRight) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    StreamBuilder m(this, type, type);
-    m.Return((m.*dpi.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
-    EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-}
-
-
-TEST_P(InstructionSelectorAddSubTest, ImmediateOnLeft) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    StreamBuilder m(this, type, type);
-    m.Return((m.*dpi.constructor)(BuildConstant(m, type, imm), m.Parameter(0)));
-    Stream s = m.Build();
-
-    // Add can support an immediate on the left by commuting, but Sub can't
-    // commute. We test zero-on-left Sub later.
-    if (strstr(dpi.constructor_name, "Add") != NULL) {
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-      ASSERT_EQ(2U, s[0]->InputCount());
-      EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
-      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
-      EXPECT_EQ(1U, s[0]->OutputCount());
-    }
-  }
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest,
-                        ::testing::ValuesIn(kAddSubInstructions));
-
-
-TEST_F(InstructionSelectorTest, SubZeroOnLeft) {
-  // Subtraction with zero on the left maps to Neg.
-  {
-    // 32-bit subtract.
-    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(m.Int32Sub(m.Int32Constant(0), m.Parameter(0)));
-    Stream s = m.Build();
-
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Neg32, s[0]->arch_opcode());
-    EXPECT_EQ(1U, s[0]->InputCount());
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-  {
-    // 64-bit subtract.
-    StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64);
-    m.Return(m.Int64Sub(m.Int64Constant(0), m.Parameter(0)));
-    Stream s = m.Build();
-
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Neg, s[0]->arch_opcode());
-    EXPECT_EQ(1U, s[0]->InputCount());
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// Data processing controlled branches.
-
-
-typedef InstructionSelectorTestWithParam<MachInst2>
-    InstructionSelectorDPFlagSetTest;
-
-
-TEST_P(InstructionSelectorDPFlagSetTest, BranchWithParameters) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  StreamBuilder m(this, type, type, type);
-  MLabel a, b;
-  m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b);
-  m.Bind(&a);
-  m.Return(m.Int32Constant(1));
-  m.Bind(&b);
-  m.Return(m.Int32Constant(0));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
-                        InstructionSelectorDPFlagSetTest,
-                        ::testing::ValuesIn(kDPFlagSetInstructions));
-
-
-TEST_F(InstructionSelectorTest, AndBranchWithImmediateOnRight) {
-  TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    MLabel a, b;
-    m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(1));
-    m.Bind(&b);
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnRight) {
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    MLabel a, b;
-    m.Branch(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(1));
-    m.Bind(&b);
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, SubBranchWithImmediateOnRight) {
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    MLabel a, b;
-    m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(1));
-    m.Bind(&b);
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, AndBranchWithImmediateOnLeft) {
-  TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    MLabel a, b;
-    m.Branch(m.Word32And(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(1));
-    m.Bind(&b);
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
-    ASSERT_LE(1U, s[0]->InputCount());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnLeft) {
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    MLabel a, b;
-    m.Branch(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(1));
-    m.Bind(&b);
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
-    ASSERT_LE(1U, s[0]->InputCount());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// Add and subtract instructions with overflow.
-
-
-typedef InstructionSelectorTestWithParam<MachInst2>
-    InstructionSelectorOvfAddSubTest;
-
-
-TEST_P(InstructionSelectorOvfAddSubTest, OvfParameter) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  StreamBuilder m(this, type, type, type);
-  m.Return(
-      m.Projection(1, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_LE(1U, s[0]->OutputCount());
-  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-  EXPECT_EQ(kOverflow, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorOvfAddSubTest, OvfImmediateOnRight) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    StreamBuilder m(this, type, type);
-    m.Return(m.Projection(
-        1, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_LE(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-}
-
-
-TEST_P(InstructionSelectorOvfAddSubTest, ValParameter) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  StreamBuilder m(this, type, type, type);
-  m.Return(
-      m.Projection(0, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_LE(1U, s[0]->OutputCount());
-  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
-}
-
-
-TEST_P(InstructionSelectorOvfAddSubTest, ValImmediateOnRight) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    StreamBuilder m(this, type, type);
-    m.Return(m.Projection(
-        0, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_LE(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
-  }
-}
-
-
-TEST_P(InstructionSelectorOvfAddSubTest, BothParameter) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  StreamBuilder m(this, type, type, type);
-  Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
-  m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
-  Stream s = m.Build();
-  ASSERT_LE(1U, s.size());
-  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(2U, s[0]->OutputCount());
-  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-  EXPECT_EQ(kOverflow, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorOvfAddSubTest, BothImmediateOnRight) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    StreamBuilder m(this, type, type);
-    Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
-    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
-    Stream s = m.Build();
-    ASSERT_LE(1U, s.size());
-    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(2U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-}
-
-
-TEST_P(InstructionSelectorOvfAddSubTest, BranchWithParameters) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  StreamBuilder m(this, type, type, type);
-  MLabel a, b;
-  Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
-  m.Branch(m.Projection(1, n), &a, &b);
-  m.Bind(&a);
-  m.Return(m.Int32Constant(0));
-  m.Bind(&b);
-  m.Return(m.Projection(0, n));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(4U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-  EXPECT_EQ(kOverflow, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorOvfAddSubTest, BranchWithImmediateOnRight) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    StreamBuilder m(this, type, type);
-    MLabel a, b;
-    Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
-    m.Branch(m.Projection(1, n), &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(0));
-    m.Bind(&b);
-    m.Return(m.Projection(0, n));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-    ASSERT_EQ(4U, s[0]->InputCount());
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
-                        InstructionSelectorOvfAddSubTest,
-                        ::testing::ValuesIn(kOvfAddSubInstructions));
-
-
-TEST_F(InstructionSelectorTest, OvfFlagAddImmediateOnLeft) {
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Projection(
-        1, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
-    Stream s = m.Build();
-
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
-    EXPECT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_LE(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, OvfValAddImmediateOnLeft) {
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Projection(
-        0, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
-    Stream s = m.Build();
-
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_LE(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, OvfBothAddImmediateOnLeft) {
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
-    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
-    Stream s = m.Build();
-
-    ASSERT_LE(1U, s.size());
-    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(2U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, OvfBranchWithImmediateOnLeft) {
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    MLabel a, b;
-    Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
-    m.Branch(m.Projection(1, n), &a, &b);
-    m.Bind(&a);
-    m.Return(m.Int32Constant(0));
-    m.Bind(&b);
-    m.Return(m.Projection(0, n));
-    Stream s = m.Build();
-
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
-    ASSERT_EQ(4U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
-    EXPECT_EQ(kOverflow, s[0]->flags_condition());
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// Shift instructions.
-
-
-typedef InstructionSelectorTestWithParam<MachInst2>
-    InstructionSelectorShiftTest;
-
-
-TEST_P(InstructionSelectorShiftTest, Parameter) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  StreamBuilder m(this, type, type, type);
-  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Immediate) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) {
-    StreamBuilder m(this, type, type);
-    m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(2U, s[0]->InputCount());
-    EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
-                        ::testing::ValuesIn(kShiftInstructions));
-
-
-// -----------------------------------------------------------------------------
-// Mul and Div instructions.
-
-
-typedef InstructionSelectorTestWithParam<MachInst2>
-    InstructionSelectorMulDivTest;
-
-
-TEST_P(InstructionSelectorMulDivTest, Parameter) {
-  const MachInst2 dpi = GetParam();
-  const MachineType type = dpi.machine_type;
-  StreamBuilder m(this, type, type, type);
-  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest,
-                        ::testing::ValuesIn(kMulDivInstructions));
-
-
-// -----------------------------------------------------------------------------
-// Floating point instructions.
-
-typedef InstructionSelectorTestWithParam<MachInst2>
-    InstructionSelectorFPArithTest;
-
-
-TEST_P(InstructionSelectorFPArithTest, Parameter) {
-  const MachInst2 fpa = GetParam();
-  StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type);
-  m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest,
-                        ::testing::ValuesIn(kFPArithInstructions));
-
-
-typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest;
-
-
-TEST_P(InstructionSelectorFPCmpTest, Parameter) {
-  const FPCmp cmp = GetParam();
-  StreamBuilder m(this, kMachInt32, cmp.mi.machine_type, cmp.mi.machine_type);
-  m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-  EXPECT_EQ(cmp.cond, s[0]->flags_condition());
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
-                        ::testing::ValuesIn(kFPCmpInstructions));
-
-
-// -----------------------------------------------------------------------------
-// Conversions.
-
-typedef InstructionSelectorTestWithParam<Conversion>
-    InstructionSelectorConversionTest;
-
-
-TEST_P(InstructionSelectorConversionTest, Parameter) {
-  const Conversion conv = GetParam();
-  StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
-  m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(1U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
-                        InstructionSelectorConversionTest,
-                        ::testing::ValuesIn(kConversionInstructions));
-
-
-// -----------------------------------------------------------------------------
-// Memory access instructions.
-
-
-namespace {
-
-struct MemoryAccess {
-  MachineType type;
-  ArchOpcode ldr_opcode;
-  ArchOpcode str_opcode;
-  const int32_t immediates[20];
-};
-
-
-std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
-  OStringStream ost;
-  ost << memacc.type;
-  return os << ost.c_str();
-}
-
-}  // namespace
-
-
-static const MemoryAccess kMemoryAccesses[] = {
-    {kMachInt8, kArm64Ldrsb, kArm64Strb,
-     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001,
-      2121, 2442, 4093, 4094, 4095}},
-    {kMachUint8, kArm64Ldrb, kArm64Strb,
-     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001,
-      2121, 2442, 4093, 4094, 4095}},
-    {kMachInt16, kArm64Ldrsh, kArm64Strh,
-     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098,
-      4100, 4242, 6786, 8188, 8190}},
-    {kMachUint16, kArm64Ldrh, kArm64Strh,
-     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098,
-      4100, 4242, 6786, 8188, 8190}},
-    {kMachInt32, kArm64LdrW, kArm64StrW,
-     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192,
-      8196, 3276, 3280, 16376, 16380}},
-    {kMachUint32, kArm64LdrW, kArm64StrW,
-     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192,
-      8196, 3276, 3280, 16376, 16380}},
-    {kMachInt64, kArm64Ldr, kArm64Str,
-     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192,
-      8200, 16384, 16392, 32752, 32760}},
-    {kMachUint64, kArm64Ldr, kArm64Str,
-     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192,
-      8200, 16384, 16392, 32752, 32760}},
-    {kMachFloat32, kArm64LdrS, kArm64StrS,
-     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192,
-      8196, 3276, 3280, 16376, 16380}},
-    {kMachFloat64, kArm64LdrD, kArm64StrD,
-     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192,
-      8200, 16384, 16392, 32752, 32760}}};
-
-
-typedef InstructionSelectorTestWithParam<MemoryAccess>
-    InstructionSelectorMemoryAccessTest;
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
-  const MemoryAccess memacc = GetParam();
-  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
-  m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
-  const MemoryAccess memacc = GetParam();
-  TRACED_FOREACH(int32_t, index, memacc.immediates) {
-    StreamBuilder m(this, memacc.type, kMachPtr);
-    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
-    EXPECT_EQ(2U, s[0]->InputCount());
-    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
-    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
-    ASSERT_EQ(1U, s[0]->OutputCount());
-  }
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
-  const MemoryAccess memacc = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
-  m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
-  m.Return(m.Int32Constant(0));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
-  EXPECT_EQ(3U, s[0]->InputCount());
-  EXPECT_EQ(0U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
-  const MemoryAccess memacc = GetParam();
-  TRACED_FOREACH(int32_t, index, memacc.immediates) {
-    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
-    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
-            m.Parameter(1));
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
-    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
-    ASSERT_EQ(3U, s[0]->InputCount());
-    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
-    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(0U, s[0]->OutputCount());
-  }
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
-                        InstructionSelectorMemoryAccessTest,
-                        ::testing::ValuesIn(kMemoryAccesses));
-
-
-// -----------------------------------------------------------------------------
-// Comparison instructions.
-
-static const MachInst2 kComparisonInstructions[] = {
-    {&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, kMachInt32},
-    {&RawMachineAssembler::Word64Equal, "Word64Equal", kArm64Cmp, kMachInt64},
-};
-
-
-typedef InstructionSelectorTestWithParam<MachInst2>
-    InstructionSelectorComparisonTest;
-
-
-TEST_P(InstructionSelectorComparisonTest, WithParameters) {
-  const MachInst2 cmp = GetParam();
-  const MachineType type = cmp.machine_type;
-  StreamBuilder m(this, type, type, type);
-  m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-  EXPECT_EQ(kEqual, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorComparisonTest, WithImmediate) {
-  const MachInst2 cmp = GetParam();
-  const MachineType type = cmp.machine_type;
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    // Compare with 0 are turned into tst instruction.
-    if (imm == 0) continue;
-    StreamBuilder m(this, type, type);
-    m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
-    EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
-    // Compare with 0 are turned into tst instruction.
-    if (imm == 0) continue;
-    StreamBuilder m(this, type, type);
-    m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
-    EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-}
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
-                        InstructionSelectorComparisonTest,
-                        ::testing::ValuesIn(kComparisonInstructions));
-
-
-TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
-  {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-  {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, Word64EqualWithZero) {
-  {
-    StreamBuilder m(this, kMachInt64, kMachInt64);
-    m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-  {
-    StreamBuilder m(this, kMachInt64, kMachInt64);
-    m.Return(m.Word64Equal(m.Int64Constant(0), m.Parameter(0)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
-    EXPECT_EQ(kEqual, s[0]->flags_condition());
-  }
-}
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/arm64/instruction-selector-arm64.cc b/src/compiler/arm64/instruction-selector-arm64.cc
index 472ce6f..72661af 100644
--- a/src/compiler/arm64/instruction-selector-arm64.cc
+++ b/src/compiler/arm64/instruction-selector-arm64.cc
@@ -44,6 +44,10 @@
       value = OpParameter<int64_t>(node);
     else
       return false;
+    return CanBeImmediate(value, mode);
+  }
+
+  bool CanBeImmediate(int64_t value, ImmediateMode mode) {
     unsigned ignored;
     switch (mode) {
       case kLogical32Imm:
@@ -55,7 +59,6 @@
         return Assembler::IsImmLogical(static_cast<uint64_t>(value), 64,
                                        &ignored, &ignored, &ignored);
       case kArithmeticImm:
-        // TODO(dcarney): -values can be handled by instruction swapping
         return Assembler::IsImmAddSub(value);
       case kShift32Imm:
         return 0 <= value && value < 32;
@@ -83,6 +86,14 @@
 };
 
 
+static void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
+                           Node* node) {
+  Arm64OperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsRegister(node),
+                 g.UseRegister(node->InputAt(0)));
+}
+
+
 static void VisitRRR(InstructionSelector* selector, ArchOpcode opcode,
                      Node* node) {
   Arm64OperandGenerator g(selector);
@@ -110,6 +121,51 @@
 }
 
 
+template <typename Matcher>
+static bool TryMatchShift(InstructionSelector* selector, Node* node,
+                          InstructionCode* opcode, IrOpcode::Value shift_opcode,
+                          ImmediateMode imm_mode,
+                          AddressingMode addressing_mode) {
+  if (node->opcode() != shift_opcode) return false;
+  Arm64OperandGenerator g(selector);
+  Matcher m(node);
+  if (g.CanBeImmediate(m.right().node(), imm_mode)) {
+    *opcode |= AddressingModeField::encode(addressing_mode);
+    return true;
+  }
+  return false;
+}
+
+
+static bool TryMatchAnyShift(InstructionSelector* selector, Node* node,
+                             InstructionCode* opcode, bool try_ror) {
+  return TryMatchShift<Int32BinopMatcher>(selector, node, opcode,
+                                          IrOpcode::kWord32Shl, kShift32Imm,
+                                          kMode_Operand2_R_LSL_I) ||
+         TryMatchShift<Int32BinopMatcher>(selector, node, opcode,
+                                          IrOpcode::kWord32Shr, kShift32Imm,
+                                          kMode_Operand2_R_LSR_I) ||
+         TryMatchShift<Int32BinopMatcher>(selector, node, opcode,
+                                          IrOpcode::kWord32Sar, kShift32Imm,
+                                          kMode_Operand2_R_ASR_I) ||
+         (try_ror && TryMatchShift<Int32BinopMatcher>(
+                         selector, node, opcode, IrOpcode::kWord32Ror,
+                         kShift32Imm, kMode_Operand2_R_ROR_I)) ||
+         TryMatchShift<Int64BinopMatcher>(selector, node, opcode,
+                                          IrOpcode::kWord64Shl, kShift64Imm,
+                                          kMode_Operand2_R_LSL_I) ||
+         TryMatchShift<Int64BinopMatcher>(selector, node, opcode,
+                                          IrOpcode::kWord64Shr, kShift64Imm,
+                                          kMode_Operand2_R_LSR_I) ||
+         TryMatchShift<Int64BinopMatcher>(selector, node, opcode,
+                                          IrOpcode::kWord64Sar, kShift64Imm,
+                                          kMode_Operand2_R_ASR_I) ||
+         (try_ror && TryMatchShift<Int64BinopMatcher>(
+                         selector, node, opcode, IrOpcode::kWord64Ror,
+                         kShift64Imm, kMode_Operand2_R_ROR_I));
+}
+
+
 // Shared routine for multiple binary operations.
 template <typename Matcher>
 static void VisitBinop(InstructionSelector* selector, Node* node,
@@ -121,9 +177,32 @@
   size_t input_count = 0;
   InstructionOperand* outputs[2];
   size_t output_count = 0;
+  bool try_ror_operand = true;
 
-  inputs[input_count++] = g.UseRegister(m.left().node());
-  inputs[input_count++] = g.UseOperand(m.right().node(), operand_mode);
+  if (m.IsInt32Add() || m.IsInt64Add() || m.IsInt32Sub() || m.IsInt64Sub()) {
+    try_ror_operand = false;
+  }
+
+  if (g.CanBeImmediate(m.right().node(), operand_mode)) {
+    inputs[input_count++] = g.UseRegister(m.left().node());
+    inputs[input_count++] = g.UseImmediate(m.right().node());
+  } else if (TryMatchAnyShift(selector, m.right().node(), &opcode,
+                              try_ror_operand)) {
+    Matcher m_shift(m.right().node());
+    inputs[input_count++] = g.UseRegister(m.left().node());
+    inputs[input_count++] = g.UseRegister(m_shift.left().node());
+    inputs[input_count++] = g.UseImmediate(m_shift.right().node());
+  } else if (m.HasProperty(Operator::kCommutative) &&
+             TryMatchAnyShift(selector, m.left().node(), &opcode,
+                              try_ror_operand)) {
+    Matcher m_shift(m.left().node());
+    inputs[input_count++] = g.UseRegister(m.right().node());
+    inputs[input_count++] = g.UseRegister(m_shift.left().node());
+    inputs[input_count++] = g.UseImmediate(m_shift.right().node());
+  } else {
+    inputs[input_count++] = g.UseRegister(m.left().node());
+    inputs[input_count++] = g.UseRegister(m.right().node());
+  }
 
   if (cont->IsBranch()) {
     inputs[input_count++] = g.Label(cont->true_block());
@@ -155,6 +234,22 @@
 }
 
 
+template <typename Matcher>
+static void VisitAddSub(InstructionSelector* selector, Node* node,
+                        ArchOpcode opcode, ArchOpcode negate_opcode) {
+  Arm64OperandGenerator g(selector);
+  Matcher m(node);
+  if (m.right().HasValue() && (m.right().Value() < 0) &&
+      g.CanBeImmediate(-m.right().Value(), kArithmeticImm)) {
+    selector->Emit(negate_opcode, g.DefineAsRegister(node),
+                   g.UseRegister(m.left().node()),
+                   g.TempImmediate(-m.right().Value()));
+  } else {
+    VisitBinop<Matcher>(selector, node, opcode, kArithmeticImm);
+  }
+}
+
+
 void InstructionSelector::VisitLoad(Node* node) {
   MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
   MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
@@ -267,75 +362,339 @@
 }
 
 
+void InstructionSelector::VisitCheckedLoad(Node* node) {
+  MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+  MachineType typ = TypeOf(OpParameter<MachineType>(node));
+  Arm64OperandGenerator g(this);
+  Node* const buffer = node->InputAt(0);
+  Node* const offset = node->InputAt(1);
+  Node* const length = node->InputAt(2);
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepWord8:
+      opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8;
+      break;
+    case kRepWord16:
+      opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16;
+      break;
+    case kRepWord32:
+      opcode = kCheckedLoadWord32;
+      break;
+    case kRepFloat32:
+      opcode = kCheckedLoadFloat32;
+      break;
+    case kRepFloat64:
+      opcode = kCheckedLoadFloat64;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+  Emit(opcode, g.DefineAsRegister(node), g.UseRegister(buffer),
+       g.UseRegister(offset), g.UseOperand(length, kArithmeticImm));
+}
+
+
+void InstructionSelector::VisitCheckedStore(Node* node) {
+  MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+  Arm64OperandGenerator g(this);
+  Node* const buffer = node->InputAt(0);
+  Node* const offset = node->InputAt(1);
+  Node* const length = node->InputAt(2);
+  Node* const value = node->InputAt(3);
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepWord8:
+      opcode = kCheckedStoreWord8;
+      break;
+    case kRepWord16:
+      opcode = kCheckedStoreWord16;
+      break;
+    case kRepWord32:
+      opcode = kCheckedStoreWord32;
+      break;
+    case kRepFloat32:
+      opcode = kCheckedStoreFloat32;
+      break;
+    case kRepFloat64:
+      opcode = kCheckedStoreFloat64;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+  Emit(opcode, nullptr, g.UseRegister(buffer), g.UseRegister(offset),
+       g.UseOperand(length, kArithmeticImm), g.UseRegister(value));
+}
+
+
+template <typename Matcher>
+static void VisitLogical(InstructionSelector* selector, Node* node, Matcher* m,
+                         ArchOpcode opcode, bool left_can_cover,
+                         bool right_can_cover, ImmediateMode imm_mode) {
+  Arm64OperandGenerator g(selector);
+
+  // Map instruction to equivalent operation with inverted right input.
+  ArchOpcode inv_opcode = opcode;
+  switch (opcode) {
+    case kArm64And32:
+      inv_opcode = kArm64Bic32;
+      break;
+    case kArm64And:
+      inv_opcode = kArm64Bic;
+      break;
+    case kArm64Or32:
+      inv_opcode = kArm64Orn32;
+      break;
+    case kArm64Or:
+      inv_opcode = kArm64Orn;
+      break;
+    case kArm64Eor32:
+      inv_opcode = kArm64Eon32;
+      break;
+    case kArm64Eor:
+      inv_opcode = kArm64Eon;
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  // Select Logical(y, ~x) for Logical(Xor(x, -1), y).
+  if ((m->left().IsWord32Xor() || m->left().IsWord64Xor()) && left_can_cover) {
+    Matcher mleft(m->left().node());
+    if (mleft.right().Is(-1)) {
+      // TODO(all): support shifted operand on right.
+      selector->Emit(inv_opcode, g.DefineAsRegister(node),
+                     g.UseRegister(m->right().node()),
+                     g.UseRegister(mleft.left().node()));
+      return;
+    }
+  }
+
+  // Select Logical(x, ~y) for Logical(x, Xor(y, -1)).
+  if ((m->right().IsWord32Xor() || m->right().IsWord64Xor()) &&
+      right_can_cover) {
+    Matcher mright(m->right().node());
+    if (mright.right().Is(-1)) {
+      // TODO(all): support shifted operand on right.
+      selector->Emit(inv_opcode, g.DefineAsRegister(node),
+                     g.UseRegister(m->left().node()),
+                     g.UseRegister(mright.left().node()));
+      return;
+    }
+  }
+
+  if (m->IsWord32Xor() && m->right().Is(-1)) {
+    selector->Emit(kArm64Not32, g.DefineAsRegister(node),
+                   g.UseRegister(m->left().node()));
+  } else if (m->IsWord64Xor() && m->right().Is(-1)) {
+    selector->Emit(kArm64Not, g.DefineAsRegister(node),
+                   g.UseRegister(m->left().node()));
+  } else {
+    VisitBinop<Matcher>(selector, node, opcode, imm_mode);
+  }
+}
+
+
 void InstructionSelector::VisitWord32And(Node* node) {
-  VisitBinop<Int32BinopMatcher>(this, node, kArm64And32, kLogical32Imm);
+  Arm64OperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  if (m.left().IsWord32Shr() && CanCover(node, m.left().node()) &&
+      m.right().HasValue()) {
+    uint32_t mask = m.right().Value();
+    uint32_t mask_width = base::bits::CountPopulation32(mask);
+    uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
+    if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
+      // The mask must be contiguous, and occupy the least-significant bits.
+      DCHECK_EQ(0, base::bits::CountTrailingZeros32(mask));
+
+      // Select Ubfx for And(Shr(x, imm), mask) where the mask is in the least
+      // significant bits.
+      Int32BinopMatcher mleft(m.left().node());
+      if (mleft.right().IsInRange(0, 31)) {
+        // Ubfx cannot extract bits past the register size, however since
+        // shifting the original value would have introduced some zeros we can
+        // still use ubfx with a smaller mask and the remaining bits will be
+        // zeros.
+        uint32_t lsb = mleft.right().Value();
+        if (lsb + mask_width > 32) mask_width = 32 - lsb;
+
+        Emit(kArm64Ubfx32, g.DefineAsRegister(node),
+             g.UseRegister(mleft.left().node()),
+             g.UseImmediate(mleft.right().node()), g.TempImmediate(mask_width));
+        return;
+      }
+      // Other cases fall through to the normal And operation.
+    }
+  }
+  VisitLogical<Int32BinopMatcher>(
+      this, node, &m, kArm64And32, CanCover(node, m.left().node()),
+      CanCover(node, m.right().node()), kLogical32Imm);
 }
 
 
 void InstructionSelector::VisitWord64And(Node* node) {
-  VisitBinop<Int64BinopMatcher>(this, node, kArm64And, kLogical64Imm);
+  Arm64OperandGenerator g(this);
+  Int64BinopMatcher m(node);
+  if (m.left().IsWord64Shr() && CanCover(node, m.left().node()) &&
+      m.right().HasValue()) {
+    uint64_t mask = m.right().Value();
+    uint64_t mask_width = base::bits::CountPopulation64(mask);
+    uint64_t mask_msb = base::bits::CountLeadingZeros64(mask);
+    if ((mask_width != 0) && (mask_msb + mask_width == 64)) {
+      // The mask must be contiguous, and occupy the least-significant bits.
+      DCHECK_EQ(0, base::bits::CountTrailingZeros64(mask));
+
+      // Select Ubfx for And(Shr(x, imm), mask) where the mask is in the least
+      // significant bits.
+      Int64BinopMatcher mleft(m.left().node());
+      if (mleft.right().IsInRange(0, 63)) {
+        // Ubfx cannot extract bits past the register size, however since
+        // shifting the original value would have introduced some zeros we can
+        // still use ubfx with a smaller mask and the remaining bits will be
+        // zeros.
+        uint64_t lsb = mleft.right().Value();
+        if (lsb + mask_width > 64) mask_width = 64 - lsb;
+
+        Emit(kArm64Ubfx, g.DefineAsRegister(node),
+             g.UseRegister(mleft.left().node()),
+             g.UseImmediate(mleft.right().node()), g.TempImmediate(mask_width));
+        return;
+      }
+      // Other cases fall through to the normal And operation.
+    }
+  }
+  VisitLogical<Int64BinopMatcher>(
+      this, node, &m, kArm64And, CanCover(node, m.left().node()),
+      CanCover(node, m.right().node()), kLogical64Imm);
 }
 
 
 void InstructionSelector::VisitWord32Or(Node* node) {
-  VisitBinop<Int32BinopMatcher>(this, node, kArm64Or32, kLogical32Imm);
+  Int32BinopMatcher m(node);
+  VisitLogical<Int32BinopMatcher>(
+      this, node, &m, kArm64Or32, CanCover(node, m.left().node()),
+      CanCover(node, m.right().node()), kLogical32Imm);
 }
 
 
 void InstructionSelector::VisitWord64Or(Node* node) {
-  VisitBinop<Int64BinopMatcher>(this, node, kArm64Or, kLogical64Imm);
+  Int64BinopMatcher m(node);
+  VisitLogical<Int64BinopMatcher>(
+      this, node, &m, kArm64Or, CanCover(node, m.left().node()),
+      CanCover(node, m.right().node()), kLogical64Imm);
 }
 
 
 void InstructionSelector::VisitWord32Xor(Node* node) {
-  Arm64OperandGenerator g(this);
   Int32BinopMatcher m(node);
-  if (m.right().Is(-1)) {
-    Emit(kArm64Not32, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
-  } else {
-    VisitBinop<Int32BinopMatcher>(this, node, kArm64Xor32, kLogical32Imm);
-  }
+  VisitLogical<Int32BinopMatcher>(
+      this, node, &m, kArm64Eor32, CanCover(node, m.left().node()),
+      CanCover(node, m.right().node()), kLogical32Imm);
 }
 
 
 void InstructionSelector::VisitWord64Xor(Node* node) {
-  Arm64OperandGenerator g(this);
   Int64BinopMatcher m(node);
-  if (m.right().Is(-1)) {
-    Emit(kArm64Not, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
-  } else {
-    VisitBinop<Int64BinopMatcher>(this, node, kArm64Xor, kLogical32Imm);
-  }
+  VisitLogical<Int64BinopMatcher>(
+      this, node, &m, kArm64Eor, CanCover(node, m.left().node()),
+      CanCover(node, m.right().node()), kLogical64Imm);
 }
 
 
 void InstructionSelector::VisitWord32Shl(Node* node) {
-  VisitRRO(this, kArm64Shl32, node, kShift32Imm);
+  VisitRRO(this, kArm64Lsl32, node, kShift32Imm);
 }
 
 
 void InstructionSelector::VisitWord64Shl(Node* node) {
-  VisitRRO(this, kArm64Shl, node, kShift64Imm);
+  Arm64OperandGenerator g(this);
+  Int64BinopMatcher m(node);
+  if ((m.left().IsChangeInt32ToInt64() || m.left().IsChangeUint32ToUint64()) &&
+      m.right().IsInRange(32, 63)) {
+    // There's no need to sign/zero-extend to 64-bit if we shift out the upper
+    // 32 bits anyway.
+    Emit(kArm64Lsl, g.DefineAsRegister(node),
+         g.UseRegister(m.left().node()->InputAt(0)),
+         g.UseImmediate(m.right().node()));
+    return;
+  }
+  VisitRRO(this, kArm64Lsl, node, kShift64Imm);
 }
 
 
 void InstructionSelector::VisitWord32Shr(Node* node) {
-  VisitRRO(this, kArm64Shr32, node, kShift32Imm);
+  Arm64OperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  if (m.left().IsWord32And() && m.right().IsInRange(0, 31)) {
+    int32_t lsb = m.right().Value();
+    Int32BinopMatcher mleft(m.left().node());
+    if (mleft.right().HasValue()) {
+      uint32_t mask = (mleft.right().Value() >> lsb) << lsb;
+      uint32_t mask_width = base::bits::CountPopulation32(mask);
+      uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
+      // Select Ubfx for Shr(And(x, mask), imm) where the result of the mask is
+      // shifted into the least-significant bits.
+      if ((mask_msb + mask_width + lsb) == 32) {
+        DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(mask));
+        Emit(kArm64Ubfx32, g.DefineAsRegister(node),
+             g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
+             g.TempImmediate(mask_width));
+        return;
+      }
+    }
+  }
+  VisitRRO(this, kArm64Lsr32, node, kShift32Imm);
 }
 
 
 void InstructionSelector::VisitWord64Shr(Node* node) {
-  VisitRRO(this, kArm64Shr, node, kShift64Imm);
+  Arm64OperandGenerator g(this);
+  Int64BinopMatcher m(node);
+  if (m.left().IsWord64And() && m.right().IsInRange(0, 63)) {
+    int64_t lsb = m.right().Value();
+    Int64BinopMatcher mleft(m.left().node());
+    if (mleft.right().HasValue()) {
+      // Select Ubfx for Shr(And(x, mask), imm) where the result of the mask is
+      // shifted into the least-significant bits.
+      uint64_t mask = (mleft.right().Value() >> lsb) << lsb;
+      uint64_t mask_width = base::bits::CountPopulation64(mask);
+      uint64_t mask_msb = base::bits::CountLeadingZeros64(mask);
+      if ((mask_msb + mask_width + lsb) == 64) {
+        DCHECK_EQ(lsb, base::bits::CountTrailingZeros64(mask));
+        Emit(kArm64Ubfx, g.DefineAsRegister(node),
+             g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
+             g.TempImmediate(mask_width));
+        return;
+      }
+    }
+  }
+  VisitRRO(this, kArm64Lsr, node, kShift64Imm);
 }
 
 
 void InstructionSelector::VisitWord32Sar(Node* node) {
-  VisitRRO(this, kArm64Sar32, node, kShift32Imm);
+  Arm64OperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  // Select Sxth/Sxtb for (x << K) >> K where K is 16 or 24.
+  if (CanCover(node, m.left().node()) && m.left().IsWord32Shl()) {
+    Int32BinopMatcher mleft(m.left().node());
+    if (mleft.right().Is(16) && m.right().Is(16)) {
+      Emit(kArm64Sxth32, g.DefineAsRegister(node),
+           g.UseRegister(mleft.left().node()));
+      return;
+    } else if (mleft.right().Is(24) && m.right().Is(24)) {
+      Emit(kArm64Sxtb32, g.DefineAsRegister(node),
+           g.UseRegister(mleft.left().node()));
+      return;
+    }
+  }
+  VisitRRO(this, kArm64Asr32, node, kShift32Imm);
 }
 
 
 void InstructionSelector::VisitWord64Sar(Node* node) {
-  VisitRRO(this, kArm64Sar, node, kShift64Imm);
+  VisitRRO(this, kArm64Asr, node, kShift64Imm);
 }
 
 
@@ -350,23 +709,69 @@
 
 
 void InstructionSelector::VisitInt32Add(Node* node) {
-  VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32, kArithmeticImm);
+  Arm64OperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  // Select Madd(x, y, z) for Add(Mul(x, y), z).
+  if (m.left().IsInt32Mul() && CanCover(node, m.left().node())) {
+    Int32BinopMatcher mleft(m.left().node());
+    Emit(kArm64Madd32, g.DefineAsRegister(node),
+         g.UseRegister(mleft.left().node()),
+         g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node()));
+    return;
+  }
+  // Select Madd(x, y, z) for Add(x, Mul(x, y)).
+  if (m.right().IsInt32Mul() && CanCover(node, m.right().node())) {
+    Int32BinopMatcher mright(m.right().node());
+    Emit(kArm64Madd32, g.DefineAsRegister(node),
+         g.UseRegister(mright.left().node()),
+         g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
+    return;
+  }
+  VisitAddSub<Int32BinopMatcher>(this, node, kArm64Add32, kArm64Sub32);
 }
 
 
 void InstructionSelector::VisitInt64Add(Node* node) {
-  VisitBinop<Int64BinopMatcher>(this, node, kArm64Add, kArithmeticImm);
+  Arm64OperandGenerator g(this);
+  Int64BinopMatcher m(node);
+  // Select Madd(x, y, z) for Add(Mul(x, y), z).
+  if (m.left().IsInt64Mul() && CanCover(node, m.left().node())) {
+    Int64BinopMatcher mleft(m.left().node());
+    Emit(kArm64Madd, g.DefineAsRegister(node),
+         g.UseRegister(mleft.left().node()),
+         g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node()));
+    return;
+  }
+  // Select Madd(x, y, z) for Add(x, Mul(x, y)).
+  if (m.right().IsInt64Mul() && CanCover(node, m.right().node())) {
+    Int64BinopMatcher mright(m.right().node());
+    Emit(kArm64Madd, g.DefineAsRegister(node),
+         g.UseRegister(mright.left().node()),
+         g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
+    return;
+  }
+  VisitAddSub<Int64BinopMatcher>(this, node, kArm64Add, kArm64Sub);
 }
 
 
 void InstructionSelector::VisitInt32Sub(Node* node) {
   Arm64OperandGenerator g(this);
   Int32BinopMatcher m(node);
+
+  // Select Msub(a, x, y) for Sub(a, Mul(x, y)).
+  if (m.right().IsInt32Mul() && CanCover(node, m.right().node())) {
+    Int32BinopMatcher mright(m.right().node());
+    Emit(kArm64Msub32, g.DefineAsRegister(node),
+         g.UseRegister(mright.left().node()),
+         g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
+    return;
+  }
+
   if (m.left().Is(0)) {
     Emit(kArm64Neg32, g.DefineAsRegister(node),
          g.UseRegister(m.right().node()));
   } else {
-    VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32, kArithmeticImm);
+    VisitAddSub<Int32BinopMatcher>(this, node, kArm64Sub32, kArm64Add32);
   }
 }
 
@@ -374,24 +779,107 @@
 void InstructionSelector::VisitInt64Sub(Node* node) {
   Arm64OperandGenerator g(this);
   Int64BinopMatcher m(node);
+
+  // Select Msub(a, x, y) for Sub(a, Mul(x, y)).
+  if (m.right().IsInt64Mul() && CanCover(node, m.right().node())) {
+    Int64BinopMatcher mright(m.right().node());
+    Emit(kArm64Msub, g.DefineAsRegister(node),
+         g.UseRegister(mright.left().node()),
+         g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
+    return;
+  }
+
   if (m.left().Is(0)) {
     Emit(kArm64Neg, g.DefineAsRegister(node), g.UseRegister(m.right().node()));
   } else {
-    VisitBinop<Int64BinopMatcher>(this, node, kArm64Sub, kArithmeticImm);
+    VisitAddSub<Int64BinopMatcher>(this, node, kArm64Sub, kArm64Add);
   }
 }
 
 
 void InstructionSelector::VisitInt32Mul(Node* node) {
+  Arm64OperandGenerator g(this);
+  Int32BinopMatcher m(node);
+
+  if (m.left().IsInt32Sub() && CanCover(node, m.left().node())) {
+    Int32BinopMatcher mleft(m.left().node());
+
+    // Select Mneg(x, y) for Mul(Sub(0, x), y).
+    if (mleft.left().Is(0)) {
+      Emit(kArm64Mneg32, g.DefineAsRegister(node),
+           g.UseRegister(mleft.right().node()),
+           g.UseRegister(m.right().node()));
+      return;
+    }
+  }
+
+  if (m.right().IsInt32Sub() && CanCover(node, m.right().node())) {
+    Int32BinopMatcher mright(m.right().node());
+
+    // Select Mneg(x, y) for Mul(x, Sub(0, y)).
+    if (mright.left().Is(0)) {
+      Emit(kArm64Mneg32, g.DefineAsRegister(node),
+           g.UseRegister(m.left().node()),
+           g.UseRegister(mright.right().node()));
+      return;
+    }
+  }
+
   VisitRRR(this, kArm64Mul32, node);
 }
 
 
 void InstructionSelector::VisitInt64Mul(Node* node) {
+  Arm64OperandGenerator g(this);
+  Int64BinopMatcher m(node);
+
+  if (m.left().IsInt64Sub() && CanCover(node, m.left().node())) {
+    Int64BinopMatcher mleft(m.left().node());
+
+    // Select Mneg(x, y) for Mul(Sub(0, x), y).
+    if (mleft.left().Is(0)) {
+      Emit(kArm64Mneg, g.DefineAsRegister(node),
+           g.UseRegister(mleft.right().node()),
+           g.UseRegister(m.right().node()));
+      return;
+    }
+  }
+
+  if (m.right().IsInt64Sub() && CanCover(node, m.right().node())) {
+    Int64BinopMatcher mright(m.right().node());
+
+    // Select Mneg(x, y) for Mul(x, Sub(0, y)).
+    if (mright.left().Is(0)) {
+      Emit(kArm64Mneg, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+           g.UseRegister(mright.right().node()));
+      return;
+    }
+  }
+
   VisitRRR(this, kArm64Mul, node);
 }
 
 
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  // TODO(arm64): Can we do better here?
+  Arm64OperandGenerator g(this);
+  InstructionOperand* const smull_operand = g.TempRegister();
+  Emit(kArm64Smull, smull_operand, g.UseRegister(node->InputAt(0)),
+       g.UseRegister(node->InputAt(1)));
+  Emit(kArm64Asr, g.DefineAsRegister(node), smull_operand, g.TempImmediate(32));
+}
+
+
+void InstructionSelector::VisitUint32MulHigh(Node* node) {
+  // TODO(arm64): Can we do better here?
+  Arm64OperandGenerator g(this);
+  InstructionOperand* const smull_operand = g.TempRegister();
+  Emit(kArm64Umull, smull_operand, g.UseRegister(node->InputAt(0)),
+       g.UseRegister(node->InputAt(1)));
+  Emit(kArm64Lsr, g.DefineAsRegister(node), smull_operand, g.TempImmediate(32));
+}
+
+
 void InstructionSelector::VisitInt32Div(Node* node) {
   VisitRRR(this, kArm64Idiv32, node);
 }
@@ -402,12 +890,12 @@
 }
 
 
-void InstructionSelector::VisitInt32UDiv(Node* node) {
+void InstructionSelector::VisitUint32Div(Node* node) {
   VisitRRR(this, kArm64Udiv32, node);
 }
 
 
-void InstructionSelector::VisitInt64UDiv(Node* node) {
+void InstructionSelector::VisitUint64Div(Node* node) {
   VisitRRR(this, kArm64Udiv, node);
 }
 
@@ -422,16 +910,23 @@
 }
 
 
-void InstructionSelector::VisitInt32UMod(Node* node) {
+void InstructionSelector::VisitUint32Mod(Node* node) {
   VisitRRR(this, kArm64Umod32, node);
 }
 
 
-void InstructionSelector::VisitInt64UMod(Node* node) {
+void InstructionSelector::VisitUint64Mod(Node* node) {
   VisitRRR(this, kArm64Umod, node);
 }
 
 
+void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
+  Arm64OperandGenerator g(this);
+  Emit(kArm64Float32ToFloat64, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
   Arm64OperandGenerator g(this);
   Emit(kArm64Int32ToFloat64, g.DefineAsRegister(node),
@@ -468,12 +963,65 @@
 
 void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
   Arm64OperandGenerator g(this);
-  Emit(kArm64Mov32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+  Node* value = node->InputAt(0);
+  switch (value->opcode()) {
+    case IrOpcode::kWord32And:
+    case IrOpcode::kWord32Or:
+    case IrOpcode::kWord32Xor:
+    case IrOpcode::kWord32Shl:
+    case IrOpcode::kWord32Shr:
+    case IrOpcode::kWord32Sar:
+    case IrOpcode::kWord32Ror:
+    case IrOpcode::kWord32Equal:
+    case IrOpcode::kInt32Add:
+    case IrOpcode::kInt32AddWithOverflow:
+    case IrOpcode::kInt32Sub:
+    case IrOpcode::kInt32SubWithOverflow:
+    case IrOpcode::kInt32Mul:
+    case IrOpcode::kInt32MulHigh:
+    case IrOpcode::kInt32Div:
+    case IrOpcode::kInt32Mod:
+    case IrOpcode::kInt32LessThan:
+    case IrOpcode::kInt32LessThanOrEqual:
+    case IrOpcode::kUint32Div:
+    case IrOpcode::kUint32LessThan:
+    case IrOpcode::kUint32LessThanOrEqual:
+    case IrOpcode::kUint32Mod:
+    case IrOpcode::kUint32MulHigh: {
+      // 32-bit operations will write their result in a W register (implicitly
+      // clearing the top 32-bit of the corresponding X register) so the
+      // zero-extension is a no-op.
+      Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
+      return;
+    }
+    default:
+      break;
+  }
+  Emit(kArm64Mov32, g.DefineAsRegister(node), g.UseRegister(value));
+}
+
+
+void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
+  Arm64OperandGenerator g(this);
+  Emit(kArm64Float64ToFloat32, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
 }
 
 
 void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
   Arm64OperandGenerator g(this);
+  Node* value = node->InputAt(0);
+  if (CanCover(node, value)) {
+    Int64BinopMatcher m(value);
+    if ((m.IsWord64Sar() && m.right().HasValue() &&
+         (m.right().Value() == 32)) ||
+        (m.IsWord64Shr() && m.right().IsInRange(32, 63))) {
+      Emit(kArm64Lsr, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+           g.UseImmediate(m.right().node()));
+      return;
+    }
+  }
+
   Emit(kArm64Mov32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
 }
 
@@ -507,125 +1055,38 @@
 
 
 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
+  VisitRRFloat64(this, kArm64Float64Sqrt, node);
+}
+
+
+void InstructionSelector::VisitFloat64Floor(Node* node) {
+  VisitRRFloat64(this, kArm64Float64Floor, node);
+}
+
+
+void InstructionSelector::VisitFloat64Ceil(Node* node) {
+  VisitRRFloat64(this, kArm64Float64Ceil, node);
+}
+
+
+void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
+  VisitRRFloat64(this, kArm64Float64RoundTruncate, node);
+}
+
+
+void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
+  VisitRRFloat64(this, kArm64Float64RoundTiesAway, node);
+}
+
+
+void InstructionSelector::VisitCall(Node* node) {
   Arm64OperandGenerator g(this);
-  Emit(kArm64Float64Sqrt, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
-}
-
-
-void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
-                                                    FlagsContinuation* cont) {
-  VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32, kArithmeticImm, cont);
-}
-
-
-void InstructionSelector::VisitInt32SubWithOverflow(Node* node,
-                                                    FlagsContinuation* cont) {
-  VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32, kArithmeticImm, cont);
-}
-
-
-// Shared routine for multiple compare operations.
-static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
-                         InstructionOperand* left, InstructionOperand* right,
-                         FlagsContinuation* cont) {
-  Arm64OperandGenerator g(selector);
-  opcode = cont->Encode(opcode);
-  if (cont->IsBranch()) {
-    selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
-                   g.Label(cont->false_block()))->MarkAsControl();
-  } else {
-    DCHECK(cont->IsSet());
-    selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
-  }
-}
-
-
-// Shared routine for multiple word compare operations.
-static void VisitWordCompare(InstructionSelector* selector, Node* node,
-                             InstructionCode opcode, FlagsContinuation* cont,
-                             bool commutative) {
-  Arm64OperandGenerator g(selector);
-  Node* left = node->InputAt(0);
-  Node* right = node->InputAt(1);
-
-  // Match immediates on left or right side of comparison.
-  if (g.CanBeImmediate(right, kArithmeticImm)) {
-    VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
-                 cont);
-  } else if (g.CanBeImmediate(left, kArithmeticImm)) {
-    if (!commutative) cont->Commute();
-    VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
-                 cont);
-  } else {
-    VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
-                 cont);
-  }
-}
-
-
-void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) {
-  switch (node->opcode()) {
-    case IrOpcode::kInt32Add:
-      return VisitWordCompare(this, node, kArm64Cmn32, cont, true);
-    case IrOpcode::kInt32Sub:
-      return VisitWordCompare(this, node, kArm64Cmp32, cont, false);
-    case IrOpcode::kWord32And:
-      return VisitWordCompare(this, node, kArm64Tst32, cont, true);
-    default:
-      break;
-  }
-
-  Arm64OperandGenerator g(this);
-  VisitCompare(this, kArm64Tst32, g.UseRegister(node), g.UseRegister(node),
-               cont);
-}
-
-
-void InstructionSelector::VisitWord64Test(Node* node, FlagsContinuation* cont) {
-  switch (node->opcode()) {
-    case IrOpcode::kWord64And:
-      return VisitWordCompare(this, node, kArm64Tst, cont, true);
-    default:
-      break;
-  }
-
-  Arm64OperandGenerator g(this);
-  VisitCompare(this, kArm64Tst, g.UseRegister(node), g.UseRegister(node), cont);
-}
-
-
-void InstructionSelector::VisitWord32Compare(Node* node,
-                                             FlagsContinuation* cont) {
-  VisitWordCompare(this, node, kArm64Cmp32, cont, false);
-}
-
-
-void InstructionSelector::VisitWord64Compare(Node* node,
-                                             FlagsContinuation* cont) {
-  VisitWordCompare(this, node, kArm64Cmp, cont, false);
-}
-
-
-void InstructionSelector::VisitFloat64Compare(Node* node,
-                                              FlagsContinuation* cont) {
-  Arm64OperandGenerator g(this);
-  Node* left = node->InputAt(0);
-  Node* right = node->InputAt(1);
-  VisitCompare(this, kArm64Float64Cmp, g.UseRegister(left),
-               g.UseRegister(right), cont);
-}
-
-
-void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
-                                    BasicBlock* deoptimization) {
-  Arm64OperandGenerator g(this);
-  CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call);
+  const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
 
   FrameStateDescriptor* frame_state_descriptor = NULL;
   if (descriptor->NeedsFrameState()) {
     frame_state_descriptor =
-        GetFrameStateDescriptor(call->InputAt(descriptor->InputCount()));
+        GetFrameStateDescriptor(node->InputAt(descriptor->InputCount()));
   }
 
   CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
@@ -634,7 +1095,7 @@
   // TODO(turbofan): on ARM64 it's probably better to use the code object in a
   // register if there are multiple uses of it. Improve constant pool and the
   // heuristics in the register allocator for where to emit constants.
-  InitializeCallBuffer(call, &buffer, true, false);
+  InitializeCallBuffer(node, &buffer, true, false);
 
   // Push the arguments to the stack.
   bool pushed_count_uneven = buffer.pushed_nodes.size() & 1;
@@ -681,17 +1142,389 @@
   opcode |= MiscField::encode(descriptor->flags());
 
   // Emit the call instruction.
+  InstructionOperand** first_output =
+      buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL;
   Instruction* call_instr =
-      Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(),
+      Emit(opcode, buffer.outputs.size(), first_output,
            buffer.instruction_args.size(), &buffer.instruction_args.front());
-
   call_instr->MarkAsCall();
-  if (deoptimization != NULL) {
-    DCHECK(continuation != NULL);
-    call_instr->MarkAsControl();
+}
+
+
+// Shared routine for multiple compare operations.
+static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
+                         InstructionOperand* left, InstructionOperand* right,
+                         FlagsContinuation* cont) {
+  Arm64OperandGenerator g(selector);
+  opcode = cont->Encode(opcode);
+  if (cont->IsBranch()) {
+    selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
+                   g.Label(cont->false_block()))->MarkAsControl();
+  } else {
+    DCHECK(cont->IsSet());
+    selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
   }
 }
 
+
+// Shared routine for multiple word compare operations.
+static void VisitWordCompare(InstructionSelector* selector, Node* node,
+                             InstructionCode opcode, FlagsContinuation* cont,
+                             bool commutative, ImmediateMode immediate_mode) {
+  Arm64OperandGenerator g(selector);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+
+  // Match immediates on left or right side of comparison.
+  if (g.CanBeImmediate(right, immediate_mode)) {
+    VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
+                 cont);
+  } else if (g.CanBeImmediate(left, immediate_mode)) {
+    if (!commutative) cont->Commute();
+    VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
+                 cont);
+  } else {
+    VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
+                 cont);
+  }
+}
+
+
+static void VisitWord32Compare(InstructionSelector* selector, Node* node,
+                               FlagsContinuation* cont) {
+  VisitWordCompare(selector, node, kArm64Cmp32, cont, false, kArithmeticImm);
+}
+
+
+static void VisitWordTest(InstructionSelector* selector, Node* node,
+                          InstructionCode opcode, FlagsContinuation* cont) {
+  Arm64OperandGenerator g(selector);
+  VisitCompare(selector, opcode, g.UseRegister(node), g.UseRegister(node),
+               cont);
+}
+
+
+static void VisitWord32Test(InstructionSelector* selector, Node* node,
+                            FlagsContinuation* cont) {
+  VisitWordTest(selector, node, kArm64Tst32, cont);
+}
+
+
+static void VisitWord64Test(InstructionSelector* selector, Node* node,
+                            FlagsContinuation* cont) {
+  VisitWordTest(selector, node, kArm64Tst, cont);
+}
+
+
+// Shared routine for multiple float compare operations.
+static void VisitFloat64Compare(InstructionSelector* selector, Node* node,
+                                FlagsContinuation* cont) {
+  Arm64OperandGenerator g(selector);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  VisitCompare(selector, kArm64Float64Cmp, g.UseRegister(left),
+               g.UseRegister(right), cont);
+}
+
+
+void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
+                                      BasicBlock* fbranch) {
+  OperandGenerator g(this);
+  Node* user = branch;
+  Node* value = branch->InputAt(0);
+
+  FlagsContinuation cont(kNotEqual, tbranch, fbranch);
+
+  // Try to combine with comparisons against 0 by simply inverting the branch.
+  while (CanCover(user, value)) {
+    if (value->opcode() == IrOpcode::kWord32Equal) {
+      Int32BinopMatcher m(value);
+      if (m.right().Is(0)) {
+        user = value;
+        value = m.left().node();
+        cont.Negate();
+      } else {
+        break;
+      }
+    } else if (value->opcode() == IrOpcode::kWord64Equal) {
+      Int64BinopMatcher m(value);
+      if (m.right().Is(0)) {
+        user = value;
+        value = m.left().node();
+        cont.Negate();
+      } else {
+        break;
+      }
+    } else {
+      break;
+    }
+  }
+
+  // Try to combine the branch with a comparison.
+  if (CanCover(user, value)) {
+    switch (value->opcode()) {
+      case IrOpcode::kWord32Equal:
+        cont.OverwriteAndNegateIfEqual(kEqual);
+        return VisitWord32Compare(this, value, &cont);
+      case IrOpcode::kInt32LessThan:
+        cont.OverwriteAndNegateIfEqual(kSignedLessThan);
+        return VisitWord32Compare(this, value, &cont);
+      case IrOpcode::kInt32LessThanOrEqual:
+        cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
+        return VisitWord32Compare(this, value, &cont);
+      case IrOpcode::kUint32LessThan:
+        cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
+        return VisitWord32Compare(this, value, &cont);
+      case IrOpcode::kUint32LessThanOrEqual:
+        cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
+        return VisitWord32Compare(this, value, &cont);
+      case IrOpcode::kWord64Equal:
+        cont.OverwriteAndNegateIfEqual(kEqual);
+        return VisitWordCompare(this, value, kArm64Cmp, &cont, false,
+                                kArithmeticImm);
+      case IrOpcode::kInt64LessThan:
+        cont.OverwriteAndNegateIfEqual(kSignedLessThan);
+        return VisitWordCompare(this, value, kArm64Cmp, &cont, false,
+                                kArithmeticImm);
+      case IrOpcode::kInt64LessThanOrEqual:
+        cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
+        return VisitWordCompare(this, value, kArm64Cmp, &cont, false,
+                                kArithmeticImm);
+      case IrOpcode::kUint64LessThan:
+        cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
+        return VisitWordCompare(this, value, kArm64Cmp, &cont, false,
+                                kArithmeticImm);
+      case IrOpcode::kFloat64Equal:
+        cont.OverwriteAndNegateIfEqual(kUnorderedEqual);
+        return VisitFloat64Compare(this, value, &cont);
+      case IrOpcode::kFloat64LessThan:
+        cont.OverwriteAndNegateIfEqual(kUnorderedLessThan);
+        return VisitFloat64Compare(this, value, &cont);
+      case IrOpcode::kFloat64LessThanOrEqual:
+        cont.OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual);
+        return VisitFloat64Compare(this, value, &cont);
+      case IrOpcode::kProjection:
+        // Check if this is the overflow output projection of an
+        // <Operation>WithOverflow node.
+        if (OpParameter<size_t>(value) == 1u) {
+          // We cannot combine the <Operation>WithOverflow with this branch
+          // unless the 0th projection (the use of the actual value of the
+          // <Operation> is either NULL, which means there's no use of the
+          // actual value, or was already defined, which means it is scheduled
+          // *AFTER* this branch).
+          Node* node = value->InputAt(0);
+          Node* result = node->FindProjection(0);
+          if (result == NULL || IsDefined(result)) {
+            switch (node->opcode()) {
+              case IrOpcode::kInt32AddWithOverflow:
+                cont.OverwriteAndNegateIfEqual(kOverflow);
+                return VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32,
+                                                     kArithmeticImm, &cont);
+              case IrOpcode::kInt32SubWithOverflow:
+                cont.OverwriteAndNegateIfEqual(kOverflow);
+                return VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32,
+                                                     kArithmeticImm, &cont);
+              default:
+                break;
+            }
+          }
+        }
+        break;
+      case IrOpcode::kInt32Add:
+        return VisitWordCompare(this, value, kArm64Cmn32, &cont, true,
+                                kArithmeticImm);
+      case IrOpcode::kInt32Sub:
+        return VisitWordCompare(this, value, kArm64Cmp32, &cont, false,
+                                kArithmeticImm);
+      case IrOpcode::kWord32And: {
+        Int32BinopMatcher m(value);
+        if (m.right().HasValue() &&
+            (base::bits::CountPopulation32(m.right().Value()) == 1)) {
+          // If the mask has only one bit set, we can use tbz/tbnz.
+          DCHECK((cont.condition() == kEqual) ||
+                 (cont.condition() == kNotEqual));
+          Emit(cont.Encode(kArm64TestAndBranch32), NULL,
+               g.UseRegister(m.left().node()),
+               g.TempImmediate(
+                   base::bits::CountTrailingZeros32(m.right().Value())),
+               g.Label(cont.true_block()),
+               g.Label(cont.false_block()))->MarkAsControl();
+          return;
+        }
+        return VisitWordCompare(this, value, kArm64Tst32, &cont, true,
+                                kLogical32Imm);
+      }
+      case IrOpcode::kWord64And: {
+        Int64BinopMatcher m(value);
+        if (m.right().HasValue() &&
+            (base::bits::CountPopulation64(m.right().Value()) == 1)) {
+          // If the mask has only one bit set, we can use tbz/tbnz.
+          DCHECK((cont.condition() == kEqual) ||
+                 (cont.condition() == kNotEqual));
+          Emit(cont.Encode(kArm64TestAndBranch), NULL,
+               g.UseRegister(m.left().node()),
+               g.TempImmediate(
+                   base::bits::CountTrailingZeros64(m.right().Value())),
+               g.Label(cont.true_block()),
+               g.Label(cont.false_block()))->MarkAsControl();
+          return;
+        }
+        return VisitWordCompare(this, value, kArm64Tst, &cont, true,
+                                kLogical64Imm);
+      }
+      default:
+        break;
+    }
+  }
+
+  // Branch could not be combined with a compare, compare against 0 and branch.
+  Emit(cont.Encode(kArm64CompareAndBranch32), NULL, g.UseRegister(value),
+       g.Label(cont.true_block()),
+       g.Label(cont.false_block()))->MarkAsControl();
+}
+
+
+void InstructionSelector::VisitWord32Equal(Node* const node) {
+  Node* const user = node;
+  FlagsContinuation cont(kEqual, node);
+  Int32BinopMatcher m(user);
+  if (m.right().Is(0)) {
+    Node* const value = m.left().node();
+    if (CanCover(user, value)) {
+      switch (value->opcode()) {
+        case IrOpcode::kInt32Add:
+          return VisitWordCompare(this, value, kArm64Cmn32, &cont, true,
+                                  kArithmeticImm);
+        case IrOpcode::kInt32Sub:
+          return VisitWordCompare(this, value, kArm64Cmp32, &cont, false,
+                                  kArithmeticImm);
+        case IrOpcode::kWord32And:
+          return VisitWordCompare(this, value, kArm64Tst32, &cont, true,
+                                  kLogical32Imm);
+        default:
+          break;
+      }
+      return VisitWord32Test(this, value, &cont);
+    }
+  }
+  VisitWord32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32LessThan(Node* node) {
+  FlagsContinuation cont(kSignedLessThan, node);
+  VisitWord32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kSignedLessThanOrEqual, node);
+  VisitWord32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitUint32LessThan(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThan, node);
+  VisitWord32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
+  VisitWord32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitWord64Equal(Node* const node) {
+  Node* const user = node;
+  FlagsContinuation cont(kEqual, node);
+  Int64BinopMatcher m(user);
+  if (m.right().Is(0)) {
+    Node* const value = m.left().node();
+    if (CanCover(user, value)) {
+      switch (value->opcode()) {
+        case IrOpcode::kWord64And:
+          return VisitWordCompare(this, value, kArm64Tst, &cont, true,
+                                  kLogical64Imm);
+        default:
+          break;
+      }
+      return VisitWord64Test(this, value, &cont);
+    }
+  }
+  VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm);
+}
+
+
+void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
+  if (Node* ovf = node->FindProjection(1)) {
+    FlagsContinuation cont(kOverflow, ovf);
+    return VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32,
+                                         kArithmeticImm, &cont);
+  }
+  FlagsContinuation cont;
+  VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32, kArithmeticImm, &cont);
+}
+
+
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+  if (Node* ovf = node->FindProjection(1)) {
+    FlagsContinuation cont(kOverflow, ovf);
+    return VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32,
+                                         kArithmeticImm, &cont);
+  }
+  FlagsContinuation cont;
+  VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32, kArithmeticImm, &cont);
+}
+
+
+void InstructionSelector::VisitInt64LessThan(Node* node) {
+  FlagsContinuation cont(kSignedLessThan, node);
+  VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm);
+}
+
+
+void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kSignedLessThanOrEqual, node);
+  VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm);
+}
+
+
+void InstructionSelector::VisitUint64LessThan(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThan, node);
+  VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm);
+}
+
+
+void InstructionSelector::VisitFloat64Equal(Node* node) {
+  FlagsContinuation cont(kUnorderedEqual, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64LessThan(Node* node) {
+  FlagsContinuation cont(kUnorderedLessThan, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnorderedLessThanOrEqual, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+// static
+MachineOperatorBuilder::Flags
+InstructionSelector::SupportedMachineOperatorFlags() {
+  return MachineOperatorBuilder::kFloat64Floor |
+         MachineOperatorBuilder::kFloat64Ceil |
+         MachineOperatorBuilder::kFloat64RoundTruncate |
+         MachineOperatorBuilder::kFloat64RoundTiesAway |
+         MachineOperatorBuilder::kWord32ShiftIsSafe |
+         MachineOperatorBuilder::kInt32DivIsSafe |
+         MachineOperatorBuilder::kUint32DivIsSafe;
+}
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
diff --git a/src/compiler/arm64/linkage-arm64.cc b/src/compiler/arm64/linkage-arm64.cc
index 2be2cb1..291b552 100644
--- a/src/compiler/arm64/linkage-arm64.cc
+++ b/src/compiler/arm64/linkage-arm64.cc
@@ -35,8 +35,9 @@
 
 typedef LinkageHelper<Arm64LinkageHelperTraits> LH;
 
-CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
-  return LH::GetJSCallDescriptor(zone, parameter_count);
+CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone,
+                                             CallDescriptor::Flags flags) {
+  return LH::GetJSCallDescriptor(zone, parameter_count, flags);
 }
 
 
@@ -49,10 +50,10 @@
 
 
 CallDescriptor* Linkage::GetStubCallDescriptor(
-    CallInterfaceDescriptor descriptor, int stack_parameter_count,
-    CallDescriptor::Flags flags, Zone* zone) {
+    const CallInterfaceDescriptor& descriptor, int stack_parameter_count,
+    CallDescriptor::Flags flags, Operator::Properties properties, Zone* zone) {
   return LH::GetStubCallDescriptor(zone, descriptor, stack_parameter_count,
-                                   flags);
+                                   flags, properties);
 }
 
 
diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc
index 74fb0ae..cde5e71 100644
--- a/src/compiler/ast-graph-builder.cc
+++ b/src/compiler/ast-graph-builder.cc
@@ -5,10 +5,12 @@
 #include "src/compiler/ast-graph-builder.h"
 
 #include "src/compiler.h"
+#include "src/compiler/ast-loop-assignment-analyzer.h"
 #include "src/compiler/control-builders.h"
 #include "src/compiler/machine-operator.h"
-#include "src/compiler/node-properties.h"
+#include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties-inl.h"
+#include "src/compiler/node-properties.h"
 #include "src/full-codegen.h"
 #include "src/parser.h"
 #include "src/scopes.h"
@@ -17,14 +19,16 @@
 namespace internal {
 namespace compiler {
 
-AstGraphBuilder::AstGraphBuilder(CompilationInfo* info, JSGraph* jsgraph)
-    : StructuredGraphBuilder(jsgraph->graph(), jsgraph->common()),
+AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
+                                 JSGraph* jsgraph, LoopAssignmentAnalysis* loop)
+    : StructuredGraphBuilder(local_zone, jsgraph->graph(), jsgraph->common()),
       info_(info),
       jsgraph_(jsgraph),
-      globals_(0, info->zone()),
+      globals_(0, local_zone),
       breakable_(NULL),
-      execution_context_(NULL) {
-  InitializeAstVisitor(info->zone());
+      execution_context_(NULL),
+      loop_assignment_analysis_(loop) {
+  InitializeAstVisitor(local_zone);
 }
 
 
@@ -62,20 +66,29 @@
   Environment env(this, scope, graph()->start());
   set_environment(&env);
 
+  // Initialize the incoming context.
+  Node* outer_context = GetFunctionContext();
+  set_current_context(outer_context);
+
+  // Build receiver check for sloppy mode if necessary.
+  // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
+  Node* original_receiver = env.Lookup(scope->receiver());
+  Node* patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver);
+  env.Bind(scope->receiver(), patched_receiver);
+
   // Build node to initialize local function context.
   Node* closure = GetFunctionClosure();
-  Node* outer = GetFunctionContext();
-  Node* inner = BuildLocalFunctionContext(outer, closure);
+  Node* inner_context = BuildLocalFunctionContext(outer_context, closure);
 
   // Push top-level function scope for the function body.
-  ContextScope top_context(this, scope, inner);
+  ContextScope top_context(this, scope, inner_context);
 
   // Build the arguments object if it is used.
   BuildArgumentsObject(scope->arguments());
 
   // Emit tracing call if requested to do so.
   if (FLAG_trace) {
-    NewNode(javascript()->Runtime(Runtime::kTraceEnter, 0));
+    NewNode(javascript()->CallRuntime(Runtime::kTraceEnter, 0));
   }
 
   // Visit implicit declaration of the function name.
@@ -86,8 +99,8 @@
   // Visit declarations within the function scope.
   VisitDeclarations(scope->declarations());
 
-  // TODO(mstarzinger): This should do an inlined stack check.
-  Node* node = NewNode(javascript()->Runtime(Runtime::kStackGuard, 0));
+  // Build a stack-check before the body.
+  Node* node = BuildStackCheck();
   PrepareFrameState(node, BailoutId::FunctionEntry());
 
   // Visit statements in the function body.
@@ -98,7 +111,7 @@
   if (FLAG_trace) {
     // TODO(mstarzinger): Only traces implicit return.
     Node* return_value = jsgraph()->UndefinedConstant();
-    NewNode(javascript()->Runtime(Runtime::kTraceExit, 1), return_value);
+    NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value);
   }
 
   // Return 'undefined' in case we can fall off the end.
@@ -129,26 +142,6 @@
 }
 
 
-// Helper to find an existing shared function info in the baseline code for the
-// given function literal. Used to canonicalize SharedFunctionInfo objects.
-static Handle<SharedFunctionInfo> SearchSharedFunctionInfo(
-    Code* unoptimized_code, FunctionLiteral* expr) {
-  int start_position = expr->start_position();
-  for (RelocIterator it(unoptimized_code); !it.done(); it.next()) {
-    RelocInfo* rinfo = it.rinfo();
-    if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
-    Object* obj = rinfo->target_object();
-    if (obj->IsSharedFunctionInfo()) {
-      SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
-      if (shared->start_position() == start_position) {
-        return Handle<SharedFunctionInfo>(shared);
-      }
-    }
-  }
-  return Handle<SharedFunctionInfo>();
-}
-
-
 StructuredGraphBuilder::Environment* AstGraphBuilder::CopyEnvironment(
     StructuredGraphBuilder::Environment* env) {
   return new (zone()) Environment(*reinterpret_cast<Environment*>(env));
@@ -329,24 +322,40 @@
 
 void AstGraphBuilder::VisitForValue(Expression* expr) {
   AstValueContext for_value(this);
-  if (!HasStackOverflow()) {
+  if (!CheckStackOverflow()) {
     expr->Accept(this);
+  } else {
+    ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
   }
 }
 
 
 void AstGraphBuilder::VisitForEffect(Expression* expr) {
   AstEffectContext for_effect(this);
-  if (!HasStackOverflow()) {
+  if (!CheckStackOverflow()) {
     expr->Accept(this);
+  } else {
+    ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
   }
 }
 
 
 void AstGraphBuilder::VisitForTest(Expression* expr) {
   AstTestContext for_condition(this);
-  if (!HasStackOverflow()) {
+  if (!CheckStackOverflow()) {
     expr->Accept(this);
+  } else {
+    ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
+  }
+}
+
+
+void AstGraphBuilder::Visit(Expression* expr) {
+  // Reuses enclosing AstContext.
+  if (!CheckStackOverflow()) {
+    expr->Accept(this);
+  } else {
+    ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
   }
 }
 
@@ -360,8 +369,8 @@
       Handle<Oddball> value = variable->binding_needs_init()
                                   ? isolate()->factory()->the_hole_value()
                                   : isolate()->factory()->undefined_value();
-      globals()->Add(variable->name(), zone());
-      globals()->Add(value, zone());
+      globals()->push_back(variable->name());
+      globals()->push_back(value);
       break;
     }
     case Variable::PARAMETER:
@@ -392,8 +401,8 @@
           Compiler::BuildFunctionInfo(decl->fun(), info()->script(), info());
       // Check for stack-overflow exception.
       if (function.is_null()) return SetStackOverflow();
-      globals()->Add(variable->name(), zone());
-      globals()->Add(function, zone());
+      globals()->push_back(variable->name());
+      globals()->push_back(function);
       break;
     }
     case Variable::PARAMETER:
@@ -580,7 +589,7 @@
 
 void AstGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
   LoopBuilder while_loop(this);
-  while_loop.BeginLoop();
+  while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt));
   VisitIterationBody(stmt, &while_loop, 0);
   while_loop.EndBody();
   VisitForTest(stmt->cond());
@@ -592,7 +601,7 @@
 
 void AstGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
   LoopBuilder while_loop(this);
-  while_loop.BeginLoop();
+  while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt));
   VisitForTest(stmt->cond());
   Node* condition = environment()->Pop();
   while_loop.BreakUnless(condition);
@@ -605,11 +614,13 @@
 void AstGraphBuilder::VisitForStatement(ForStatement* stmt) {
   LoopBuilder for_loop(this);
   VisitIfNotNull(stmt->init());
-  for_loop.BeginLoop();
+  for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt));
   if (stmt->cond() != NULL) {
     VisitForTest(stmt->cond());
     Node* condition = environment()->Pop();
     for_loop.BreakUnless(condition);
+  } else {
+    for_loop.BreakUnless(jsgraph()->TrueConstant());
   }
   VisitIterationBody(stmt, &for_loop, 0);
   for_loop.EndBody();
@@ -639,24 +650,27 @@
     // Convert object to jsobject.
     // PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
     obj = NewNode(javascript()->ToObject(), obj);
+    PrepareFrameState(obj, stmt->ToObjectId(), OutputFrameStateCombine::Push());
     environment()->Push(obj);
     // TODO(dcarney): should do a fast enum cache check here to skip runtime.
     environment()->Push(obj);
     Node* cache_type = ProcessArguments(
-        javascript()->Runtime(Runtime::kGetPropertyNamesFast, 1), 1);
+        javascript()->CallRuntime(Runtime::kGetPropertyNamesFast, 1), 1);
+    PrepareFrameState(cache_type, stmt->EnumId(),
+                      OutputFrameStateCombine::Push());
     // TODO(dcarney): these next runtime calls should be removed in favour of
     //                a few simplified instructions.
     environment()->Push(obj);
     environment()->Push(cache_type);
     Node* cache_pair =
-        ProcessArguments(javascript()->Runtime(Runtime::kForInInit, 2), 2);
+        ProcessArguments(javascript()->CallRuntime(Runtime::kForInInit, 2), 2);
     // cache_type may have been replaced.
     Node* cache_array = NewNode(common()->Projection(0), cache_pair);
     cache_type = NewNode(common()->Projection(1), cache_pair);
     environment()->Push(cache_type);
     environment()->Push(cache_array);
     Node* cache_length = ProcessArguments(
-        javascript()->Runtime(Runtime::kForInCacheArrayLength, 2), 2);
+        javascript()->CallRuntime(Runtime::kForInCacheArrayLength, 2), 2);
     {
       // TODO(dcarney): this check is actually supposed to be for the
       //                empty enum case only.
@@ -676,7 +690,7 @@
         environment()->Push(jsgraph()->ZeroConstant());
         // PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
         LoopBuilder for_loop(this);
-        for_loop.BeginLoop();
+        for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt));
         // Check loop termination condition.
         Node* index = environment()->Peek(0);
         Node* exit_cond =
@@ -692,8 +706,8 @@
         environment()->Push(cache_array);
         environment()->Push(cache_type);
         environment()->Push(index);
-        Node* pair =
-            ProcessArguments(javascript()->Runtime(Runtime::kForInNext, 4), 4);
+        Node* pair = ProcessArguments(
+            javascript()->CallRuntime(Runtime::kForInNext, 4), 4);
         Node* value = NewNode(common()->Projection(0), pair);
         Node* should_filter = NewNode(common()->Projection(1), pair);
         environment()->Push(value);
@@ -719,7 +733,7 @@
           // result is either the string key or Smi(0) indicating the property
           // is gone.
           Node* res = ProcessArguments(
-              javascript()->Call(3, NO_CALL_FUNCTION_FLAGS), 3);
+              javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS), 3);
           // TODO(jarin): provide real bailout id.
           PrepareFrameState(res, BailoutId::None());
           Node* property_missing = NewNode(javascript()->StrictEqual(), res,
@@ -785,7 +799,7 @@
 
 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
   // TODO(turbofan): Do we really need a separate reloc-info for this?
-  Node* node = NewNode(javascript()->Runtime(Runtime::kDebugBreak, 0));
+  Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0));
   PrepareFrameState(node, stmt->DebugBreakId());
 }
 
@@ -795,8 +809,8 @@
 
   // Build a new shared function info if we cannot find one in the baseline
   // code. We also have a stack overflow if the recursive compilation did.
-  Handle<SharedFunctionInfo> shared_info =
-      SearchSharedFunctionInfo(info()->shared_info()->code(), expr);
+  expr->InitializeSharedInfo(handle(info()->shared_info()->code()));
+  Handle<SharedFunctionInfo> shared_info = expr->shared_info();
   if (shared_info.is_null()) {
     shared_info = Compiler::BuildFunctionInfo(expr, info()->script(), info());
     CHECK(!shared_info.is_null());  // TODO(mstarzinger): Set stack overflow?
@@ -804,16 +818,14 @@
 
   // Create node to instantiate a new closure.
   Node* info = jsgraph()->Constant(shared_info);
-  Node* pretenure = expr->pretenure() ? jsgraph()->TrueConstant()
-                                      : jsgraph()->FalseConstant();
-  const Operator* op = javascript()->Runtime(Runtime::kNewClosure, 3);
+  Node* pretenure = jsgraph()->BooleanConstant(expr->pretenure());
+  const Operator* op = javascript()->CallRuntime(Runtime::kNewClosure, 3);
   Node* value = NewNode(op, context, info, pretenure);
   ast_context()->ProduceValue(value);
 }
 
 
 void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) {
-  // TODO(arv): Implement.
   UNREACHABLE();
 }
 
@@ -838,7 +850,8 @@
 
 
 void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
-  Node* value = BuildVariableLoad(expr->var(), expr->id());
+  VectorSlotPair pair = CreateVectorSlotPair(expr->VariableFeedbackSlot());
+  Node* value = BuildVariableLoad(expr->var(), expr->id(), pair);
   ast_context()->ProduceValue(value);
 }
 
@@ -859,8 +872,9 @@
   Node* pattern = jsgraph()->Constant(expr->pattern());
   Node* flags = jsgraph()->Constant(expr->flags());
   const Operator* op =
-      javascript()->Runtime(Runtime::kMaterializeRegExpLiteral, 4);
+      javascript()->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
   Node* literal = NewNode(op, literals_array, literal_index, pattern, flags);
+  PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(literal);
 }
 
@@ -875,8 +889,11 @@
   Node* literal_index = jsgraph()->Constant(expr->literal_index());
   Node* constants = jsgraph()->Constant(expr->constant_properties());
   Node* flags = jsgraph()->Constant(expr->ComputeFlags());
-  const Operator* op = javascript()->Runtime(Runtime::kCreateObjectLiteral, 4);
+  const Operator* op =
+      javascript()->CallRuntime(Runtime::kCreateObjectLiteral, 4);
   Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
+  PrepareFrameState(literal, expr->CreateLiteralId(),
+                    OutputFrameStateCombine::Push());
 
   // The object is expected on the operand stack during computation of the
   // property values and is the value of the entire expression.
@@ -924,7 +941,8 @@
         Node* receiver = environment()->Pop();
         if (property->emit_store()) {
           Node* strict = jsgraph()->Constant(SLOPPY);
-          const Operator* op = javascript()->Runtime(Runtime::kSetProperty, 4);
+          const Operator* op =
+              javascript()->CallRuntime(Runtime::kSetProperty, 4);
           NewNode(op, receiver, key, value, strict);
         }
         break;
@@ -935,8 +953,12 @@
         Node* value = environment()->Pop();
         Node* receiver = environment()->Pop();
         if (property->emit_store()) {
-          const Operator* op = javascript()->Runtime(Runtime::kSetPrototype, 2);
-          NewNode(op, receiver, value);
+          const Operator* op =
+              javascript()->CallRuntime(Runtime::kInternalSetPrototype, 2);
+          Node* set_prototype = NewNode(op, receiver, value);
+          // SetPrototype should not lazy deopt on an object
+          // literal.
+          PrepareFrameState(set_prototype, BailoutId::None());
         }
         break;
       }
@@ -961,14 +983,16 @@
     Node* name = environment()->Pop();
     Node* attr = jsgraph()->Constant(NONE);
     const Operator* op =
-        javascript()->Runtime(Runtime::kDefineAccessorPropertyUnchecked, 5);
+        javascript()->CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
     Node* call = NewNode(op, literal, name, getter, setter, attr);
-    PrepareFrameState(call, it->first->id());
+    // This should not lazy deopt on a new literal.
+    PrepareFrameState(call, BailoutId::None());
   }
 
   // Transform literals that contain functions to fast properties.
   if (expr->has_function()) {
-    const Operator* op = javascript()->Runtime(Runtime::kToFastProperties, 1);
+    const Operator* op =
+        javascript()->CallRuntime(Runtime::kToFastProperties, 1);
     NewNode(op, literal);
   }
 
@@ -986,7 +1010,8 @@
   Node* literal_index = jsgraph()->Constant(expr->literal_index());
   Node* constants = jsgraph()->Constant(expr->constant_elements());
   Node* flags = jsgraph()->Constant(expr->ComputeFlags());
-  const Operator* op = javascript()->Runtime(Runtime::kCreateArrayLiteral, 4);
+  const Operator* op =
+      javascript()->CallRuntime(Runtime::kCreateArrayLiteral, 4);
   Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
 
   // The array and the literal index are both expected on the operand stack
@@ -1086,23 +1111,31 @@
     Node* old_value = NULL;
     switch (assign_type) {
       case VARIABLE: {
-        Variable* variable = expr->target()->AsVariableProxy()->var();
-        old_value = BuildVariableLoad(variable, expr->target()->id());
+        VariableProxy* proxy = expr->target()->AsVariableProxy();
+        VectorSlotPair pair =
+            CreateVectorSlotPair(proxy->VariableFeedbackSlot());
+        old_value = BuildVariableLoad(proxy->var(), expr->target()->id(), pair);
         break;
       }
       case NAMED_PROPERTY: {
         Node* object = environment()->Top();
         Unique<Name> name =
             MakeUnique(property->key()->AsLiteral()->AsPropertyName());
-        old_value = NewNode(javascript()->LoadNamed(name), object);
-        PrepareFrameState(old_value, property->LoadId(), kPushOutput);
+        VectorSlotPair pair =
+            CreateVectorSlotPair(property->PropertyFeedbackSlot());
+        old_value = NewNode(javascript()->LoadNamed(name, pair), object);
+        PrepareFrameState(old_value, property->LoadId(),
+                          OutputFrameStateCombine::Push());
         break;
       }
       case KEYED_PROPERTY: {
         Node* key = environment()->Top();
         Node* object = environment()->Peek(1);
-        old_value = NewNode(javascript()->LoadProperty(), object, key);
-        PrepareFrameState(old_value, property->LoadId(), kPushOutput);
+        VectorSlotPair pair =
+            CreateVectorSlotPair(property->PropertyFeedbackSlot());
+        old_value = NewNode(javascript()->LoadProperty(pair), object, key);
+        PrepareFrameState(old_value, property->LoadId(),
+                          OutputFrameStateCombine::Push());
         break;
       }
     }
@@ -1111,7 +1144,8 @@
     Node* right = environment()->Pop();
     Node* left = environment()->Pop();
     Node* value = BuildBinaryOp(left, right, expr->binary_op());
-    PrepareFrameState(value, expr->binary_operation()->id(), kPushOutput);
+    PrepareFrameState(value, expr->binary_operation()->id(),
+                      OutputFrameStateCombine::Push());
     environment()->Push(value);
   } else {
     VisitForValue(expr->value());
@@ -1122,8 +1156,8 @@
   switch (assign_type) {
     case VARIABLE: {
       Variable* variable = expr->target()->AsVariableProxy()->var();
-      BuildVariableAssignment(variable, value, expr->op(),
-                              expr->AssignmentId());
+      BuildVariableAssignment(variable, value, expr->op(), expr->AssignmentId(),
+                              ast_context()->GetStateCombine());
       break;
     }
     case NAMED_PROPERTY: {
@@ -1132,7 +1166,8 @@
           MakeUnique(property->key()->AsLiteral()->AsPropertyName());
       Node* store =
           NewNode(javascript()->StoreNamed(strict_mode(), name), object, value);
-      PrepareFrameState(store, expr->AssignmentId());
+      PrepareFrameState(store, expr->AssignmentId(),
+                        ast_context()->GetStateCombine());
       break;
     }
     case KEYED_PROPERTY: {
@@ -1140,7 +1175,8 @@
       Node* object = environment()->Pop();
       Node* store = NewNode(javascript()->StoreProperty(strict_mode()), object,
                             key, value);
-      PrepareFrameState(store, expr->AssignmentId());
+      PrepareFrameState(store, expr->AssignmentId(),
+                        ast_context()->GetStateCombine());
       break;
     }
   }
@@ -1162,25 +1198,27 @@
 void AstGraphBuilder::VisitThrow(Throw* expr) {
   VisitForValue(expr->exception());
   Node* exception = environment()->Pop();
-  const Operator* op = javascript()->Runtime(Runtime::kThrow, 1);
+  const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1);
   Node* value = NewNode(op, exception);
+  PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
 }
 
 
 void AstGraphBuilder::VisitProperty(Property* expr) {
   Node* value;
+  VectorSlotPair pair = CreateVectorSlotPair(expr->PropertyFeedbackSlot());
   if (expr->key()->IsPropertyName()) {
     VisitForValue(expr->obj());
     Node* object = environment()->Pop();
     Unique<Name> name = MakeUnique(expr->key()->AsLiteral()->AsPropertyName());
-    value = NewNode(javascript()->LoadNamed(name), object);
+    value = NewNode(javascript()->LoadNamed(name, pair), object);
   } else {
     VisitForValue(expr->obj());
     VisitForValue(expr->key());
     Node* key = environment()->Pop();
     Node* object = environment()->Pop();
-    value = NewNode(javascript()->LoadProperty(), object, key);
+    value = NewNode(javascript()->LoadProperty(pair), object, key);
   }
   PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
@@ -1199,8 +1237,10 @@
   bool possibly_eval = false;
   switch (call_type) {
     case Call::GLOBAL_CALL: {
-      Variable* variable = callee->AsVariableProxy()->var();
-      callee_value = BuildVariableLoad(variable, expr->expression()->id());
+      VariableProxy* proxy = callee->AsVariableProxy();
+      VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
+      callee_value =
+          BuildVariableLoad(proxy->var(), expr->expression()->id(), pair);
       receiver_value = jsgraph()->UndefinedConstant();
       break;
     }
@@ -1208,26 +1248,33 @@
       Variable* variable = callee->AsVariableProxy()->var();
       DCHECK(variable->location() == Variable::LOOKUP);
       Node* name = jsgraph()->Constant(variable->name());
-      const Operator* op = javascript()->Runtime(Runtime::kLoadLookupSlot, 2);
+      const Operator* op =
+          javascript()->CallRuntime(Runtime::kLoadLookupSlot, 2);
       Node* pair = NewNode(op, current_context(), name);
       callee_value = NewNode(common()->Projection(0), pair);
       receiver_value = NewNode(common()->Projection(1), pair);
+
+      PrepareFrameState(pair, expr->EvalOrLookupId(),
+                        OutputFrameStateCombine::Push(2));
       break;
     }
     case Call::PROPERTY_CALL: {
       Property* property = callee->AsProperty();
       VisitForValue(property->obj());
       Node* object = environment()->Top();
+      VectorSlotPair pair =
+          CreateVectorSlotPair(property->PropertyFeedbackSlot());
       if (property->key()->IsPropertyName()) {
         Unique<Name> name =
             MakeUnique(property->key()->AsLiteral()->AsPropertyName());
-        callee_value = NewNode(javascript()->LoadNamed(name), object);
+        callee_value = NewNode(javascript()->LoadNamed(name, pair), object);
       } else {
         VisitForValue(property->key());
         Node* key = environment()->Pop();
-        callee_value = NewNode(javascript()->LoadProperty(), object, key);
+        callee_value = NewNode(javascript()->LoadProperty(pair), object, key);
       }
-      PrepareFrameState(callee_value, property->LoadId(), kPushOutput);
+      PrepareFrameState(callee_value, property->LoadId(),
+                        OutputFrameStateCombine::Push());
       receiver_value = environment()->Pop();
       // Note that a PROPERTY_CALL requires the receiver to be wrapped into an
       // object for sloppy callees. This could also be modeled explicitly here,
@@ -1235,6 +1282,11 @@
       flags = CALL_AS_METHOD;
       break;
     }
+    case Call::SUPER_CALL: {
+      // todo(dslomov): implement super calls in turbofan.
+      UNIMPLEMENTED();
+      break;
+    }
     case Call::POSSIBLY_EVAL_CALL:
       possibly_eval = true;
     // Fall through.
@@ -1270,9 +1322,11 @@
     Node* strict = jsgraph()->Constant(strict_mode());
     Node* position = jsgraph()->Constant(info()->scope()->start_position());
     const Operator* op =
-        javascript()->Runtime(Runtime::kResolvePossiblyDirectEval, 6);
+        javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
     Node* pair =
         NewNode(op, callee, source, function, receiver, strict, position);
+    PrepareFrameState(pair, expr->EvalOrLookupId(),
+                      OutputFrameStateCombine::PokeAt(arg_count + 1));
     Node* new_callee = NewNode(common()->Projection(0), pair);
     Node* new_receiver = NewNode(common()->Projection(1), pair);
 
@@ -1282,7 +1336,7 @@
   }
 
   // Create node to perform the function call.
-  const Operator* call = javascript()->Call(args->length() + 2, flags);
+  const Operator* call = javascript()->CallFunction(args->length() + 2, flags);
   Node* value = ProcessArguments(call, args->length() + 2);
   PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
@@ -1297,7 +1351,7 @@
   VisitForValues(args);
 
   // Create node to perform the construct call.
-  const Operator* call = javascript()->CallNew(args->length() + 1);
+  const Operator* call = javascript()->CallConstruct(args->length() + 1);
   Node* value = ProcessArguments(call, args->length() + 1);
   PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
@@ -1312,10 +1366,13 @@
   CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS;
   Node* receiver_value = BuildLoadBuiltinsObject();
   Unique<String> unique = MakeUnique(name);
-  Node* callee_value = NewNode(javascript()->LoadNamed(unique), receiver_value);
+  VectorSlotPair pair = CreateVectorSlotPair(expr->CallRuntimeFeedbackSlot());
+  Node* callee_value =
+      NewNode(javascript()->LoadNamed(unique, pair), receiver_value);
   // TODO(jarin): Find/create a bailout id to deoptimize to (crankshaft
   // refuses to optimize functions with jsruntime calls).
-  PrepareFrameState(callee_value, BailoutId::None(), kPushOutput);
+  PrepareFrameState(callee_value, BailoutId::None(),
+                    OutputFrameStateCombine::Push());
   environment()->Push(callee_value);
   environment()->Push(receiver_value);
 
@@ -1324,7 +1381,7 @@
   VisitForValues(args);
 
   // Create node to perform the JS runtime call.
-  const Operator* call = javascript()->Call(args->length() + 2, flags);
+  const Operator* call = javascript()->CallFunction(args->length() + 2, flags);
   Node* value = ProcessArguments(call, args->length() + 2);
   PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
@@ -1347,7 +1404,7 @@
 
   // Create node to perform the runtime call.
   Runtime::FunctionId functionId = function->function_id;
-  const Operator* call = javascript()->Runtime(functionId, args->length());
+  const Operator* call = javascript()->CallRuntime(functionId, args->length());
   Node* value = ProcessArguments(call, args->length());
   PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
@@ -1386,8 +1443,10 @@
   int stack_depth = -1;
   switch (assign_type) {
     case VARIABLE: {
-      Variable* variable = expr->expression()->AsVariableProxy()->var();
-      old_value = BuildVariableLoad(variable, expr->expression()->id());
+      VariableProxy* proxy = expr->expression()->AsVariableProxy();
+      VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
+      old_value =
+          BuildVariableLoad(proxy->var(), expr->expression()->id(), pair);
       stack_depth = 0;
       break;
     }
@@ -1396,8 +1455,11 @@
       Node* object = environment()->Top();
       Unique<Name> name =
           MakeUnique(property->key()->AsLiteral()->AsPropertyName());
-      old_value = NewNode(javascript()->LoadNamed(name), object);
-      PrepareFrameState(old_value, property->LoadId(), kPushOutput);
+      VectorSlotPair pair =
+          CreateVectorSlotPair(property->PropertyFeedbackSlot());
+      old_value = NewNode(javascript()->LoadNamed(name, pair), object);
+      PrepareFrameState(old_value, property->LoadId(),
+                        OutputFrameStateCombine::Push());
       stack_depth = 1;
       break;
     }
@@ -1406,8 +1468,11 @@
       VisitForValue(property->key());
       Node* key = environment()->Top();
       Node* object = environment()->Peek(1);
-      old_value = NewNode(javascript()->LoadProperty(), object, key);
-      PrepareFrameState(old_value, property->LoadId(), kPushOutput);
+      VectorSlotPair pair =
+          CreateVectorSlotPair(property->PropertyFeedbackSlot());
+      old_value = NewNode(javascript()->LoadProperty(pair), object, key);
+      PrepareFrameState(old_value, property->LoadId(),
+                        OutputFrameStateCombine::Push());
       stack_depth = 2;
       break;
     }
@@ -1548,20 +1613,21 @@
 
 
 void AstGraphBuilder::VisitDeclarations(ZoneList<Declaration*>* declarations) {
-  DCHECK(globals()->is_empty());
+  DCHECK(globals()->empty());
   AstVisitor::VisitDeclarations(declarations);
-  if (globals()->is_empty()) return;
-  Handle<FixedArray> data =
-      isolate()->factory()->NewFixedArray(globals()->length(), TENURED);
-  for (int i = 0; i < globals()->length(); ++i) data->set(i, *globals()->at(i));
+  if (globals()->empty()) return;
+  int array_index = 0;
+  Handle<FixedArray> data = isolate()->factory()->NewFixedArray(
+      static_cast<int>(globals()->size()), TENURED);
+  for (Handle<Object> obj : *globals()) data->set(array_index++, *obj);
   int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
                       DeclareGlobalsNativeFlag::encode(info()->is_native()) |
                       DeclareGlobalsStrictMode::encode(strict_mode());
   Node* flags = jsgraph()->Constant(encoded_flags);
   Node* pairs = jsgraph()->Constant(data);
-  const Operator* op = javascript()->Runtime(Runtime::kDeclareGlobals, 3);
+  const Operator* op = javascript()->CallRuntime(Runtime::kDeclareGlobals, 3);
   NewNode(op, current_context(), pairs, flags);
-  globals()->Rewind(0);
+  globals()->clear();
 }
 
 
@@ -1585,7 +1651,8 @@
     // deleting "this" is allowed in all language modes.
     Variable* variable = expr->expression()->AsVariableProxy()->var();
     DCHECK(strict_mode() == SLOPPY || variable->is_this());
-    value = BuildVariableDelete(variable);
+    value = BuildVariableDelete(variable, expr->id(),
+                                ast_context()->GetStateCombine());
   } else if (expr->expression()->IsProperty()) {
     Property* property = expr->expression()->AsProperty();
     VisitForValue(property->obj());
@@ -1593,6 +1660,7 @@
     Node* key = environment()->Pop();
     Node* object = environment()->Pop();
     value = NewNode(javascript()->DeleteProperty(strict_mode()), object, key);
+    PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   } else {
     VisitForEffect(expr->expression());
     value = jsgraph()->TrueConstant();
@@ -1613,9 +1681,10 @@
   if (expr->expression()->IsVariableProxy()) {
     // Typeof does not throw a reference error on global variables, hence we
     // perform a non-contextual load in case the operand is a variable proxy.
-    Variable* variable = expr->expression()->AsVariableProxy()->var();
-    operand =
-        BuildVariableLoad(variable, expr->expression()->id(), NOT_CONTEXTUAL);
+    VariableProxy* proxy = expr->expression()->AsVariableProxy();
+    VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
+    operand = BuildVariableLoad(proxy->var(), expr->expression()->id(), pair,
+                                NOT_CONTEXTUAL);
   } else {
     VisitForValue(expr->expression());
     operand = environment()->Pop();
@@ -1666,6 +1735,17 @@
 }
 
 
+StrictMode AstGraphBuilder::strict_mode() const {
+  return info()->strict_mode();
+}
+
+
+VectorSlotPair AstGraphBuilder::CreateVectorSlotPair(
+    FeedbackVectorICSlot slot) const {
+  return VectorSlotPair(handle(info()->shared_info()->feedback_vector()), slot);
+}
+
+
 Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) {
   DCHECK(environment()->stack_height() >= arity);
   Node** all = info()->zone()->NewArray<Node*>(arity);
@@ -1677,10 +1757,36 @@
 }
 
 
+Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) {
+  // Sloppy mode functions and builtins need to replace the receiver with the
+  // global proxy when called as functions (without an explicit receiver
+  // object). Otherwise there is nothing left to do here.
+  if (info()->strict_mode() != SLOPPY || info()->is_native()) return receiver;
+
+  // There is no need to perform patching if the receiver is never used. Note
+  // that scope predicates are purely syntactical, a call to eval might still
+  // inspect the receiver value.
+  if (!info()->scope()->uses_this() && !info()->scope()->inner_uses_this() &&
+      !info()->scope()->calls_sloppy_eval()) {
+    return receiver;
+  }
+
+  IfBuilder receiver_check(this);
+  Node* undefined = jsgraph()->UndefinedConstant();
+  Node* check = NewNode(javascript()->StrictEqual(), receiver, undefined);
+  receiver_check.If(check);
+  receiver_check.Then();
+  environment()->Push(BuildLoadGlobalProxy());
+  receiver_check.Else();
+  environment()->Push(receiver);
+  receiver_check.End();
+  return environment()->Pop();
+}
+
+
 Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context, Node* closure) {
   int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
   if (heap_slots <= 0) return context;
-  set_current_context(context);
 
   // Allocate a new local context.
   const Operator* op = javascript()->CreateFunctionContext();
@@ -1710,7 +1816,7 @@
 
   // Allocate and initialize a new arguments object.
   Node* callee = GetFunctionClosure();
-  const Operator* op = javascript()->Runtime(Runtime::kNewArguments, 1);
+  const Operator* op = javascript()->CallRuntime(Runtime::kNewArguments, 1);
   Node* object = NewNode(op, callee);
 
   // Assign the object to the arguments variable.
@@ -1738,13 +1844,14 @@
 
 
 Node* AstGraphBuilder::BuildHoleCheckThrow(Node* value, Variable* variable,
-                                           Node* not_hole) {
+                                           Node* not_hole,
+                                           BailoutId bailout_id) {
   IfBuilder hole_check(this);
   Node* the_hole = jsgraph()->TheHoleConstant();
   Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
   hole_check.If(check);
   hole_check.Then();
-  environment()->Push(BuildThrowReferenceError(variable));
+  environment()->Push(BuildThrowReferenceError(variable, bailout_id));
   hole_check.Else();
   environment()->Push(not_hole);
   hole_check.End();
@@ -1754,6 +1861,7 @@
 
 Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
                                          BailoutId bailout_id,
+                                         const VectorSlotPair& feedback,
                                          ContextualMode contextual_mode) {
   Node* the_hole = jsgraph()->TheHoleConstant();
   VariableMode mode = variable->mode();
@@ -1762,9 +1870,10 @@
       // Global var, const, or let variable.
       Node* global = BuildLoadGlobalObject();
       Unique<Name> name = MakeUnique(variable->name());
-      const Operator* op = javascript()->LoadNamed(name, contextual_mode);
+      const Operator* op =
+          javascript()->LoadNamed(name, feedback, contextual_mode);
       Node* node = NewNode(op, global);
-      PrepareFrameState(node, bailout_id, kPushOutput);
+      PrepareFrameState(node, bailout_id, OutputFrameStateCombine::Push());
       return node;
     }
     case Variable::PARAMETER:
@@ -1782,9 +1891,9 @@
       } else if (mode == LET || mode == CONST) {
         // Perform check for uninitialized let/const variables.
         if (value->op() == the_hole->op()) {
-          value = BuildThrowReferenceError(variable);
+          value = BuildThrowReferenceError(variable, bailout_id);
         } else if (value->opcode() == IrOpcode::kPhi) {
-          value = BuildHoleCheckThrow(value, variable, value);
+          value = BuildHoleCheckThrow(value, variable, value, bailout_id);
         }
       }
       return value;
@@ -1805,7 +1914,7 @@
         value = BuildHoleCheckSilent(value, undefined, value);
       } else if (mode == LET || mode == CONST) {
         // Perform check for uninitialized let/const variables.
-        value = BuildHoleCheckThrow(value, variable, value);
+        value = BuildHoleCheckThrow(value, variable, value, bailout_id);
       }
       return value;
     }
@@ -1816,8 +1925,9 @@
           (contextual_mode == CONTEXTUAL)
               ? Runtime::kLoadLookupSlot
               : Runtime::kLoadLookupSlotNoReferenceError;
-      const Operator* op = javascript()->Runtime(function_id, 2);
+      const Operator* op = javascript()->CallRuntime(function_id, 2);
       Node* pair = NewNode(op, current_context(), name);
+      PrepareFrameState(pair, bailout_id, OutputFrameStateCombine::Push(1));
       return NewNode(common()->Projection(0), pair);
     }
   }
@@ -1826,26 +1936,32 @@
 }
 
 
-Node* AstGraphBuilder::BuildVariableDelete(Variable* variable) {
+Node* AstGraphBuilder::BuildVariableDelete(
+    Variable* variable, BailoutId bailout_id,
+    OutputFrameStateCombine state_combine) {
   switch (variable->location()) {
     case Variable::UNALLOCATED: {
       // Global var, const, or let variable.
       Node* global = BuildLoadGlobalObject();
       Node* name = jsgraph()->Constant(variable->name());
       const Operator* op = javascript()->DeleteProperty(strict_mode());
-      return NewNode(op, global, name);
+      Node* result = NewNode(op, global, name);
+      PrepareFrameState(result, bailout_id, state_combine);
+      return result;
     }
     case Variable::PARAMETER:
     case Variable::LOCAL:
     case Variable::CONTEXT:
       // Local var, const, or let variable or context variable.
-      return variable->is_this() ? jsgraph()->TrueConstant()
-                                 : jsgraph()->FalseConstant();
+      return jsgraph()->BooleanConstant(variable->is_this());
     case Variable::LOOKUP: {
       // Dynamic lookup of context variable (anywhere in the chain).
       Node* name = jsgraph()->Constant(variable->name());
-      const Operator* op = javascript()->Runtime(Runtime::kDeleteLookupSlot, 2);
-      return NewNode(op, current_context(), name);
+      const Operator* op =
+          javascript()->CallRuntime(Runtime::kDeleteLookupSlot, 2);
+      Node* result = NewNode(op, current_context(), name);
+      PrepareFrameState(result, bailout_id, state_combine);
+      return result;
     }
   }
   UNREACHABLE();
@@ -1853,9 +1969,9 @@
 }
 
 
-Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value,
-                                               Token::Value op,
-                                               BailoutId bailout_id) {
+Node* AstGraphBuilder::BuildVariableAssignment(
+    Variable* variable, Node* value, Token::Value op, BailoutId bailout_id,
+    OutputFrameStateCombine combine) {
   Node* the_hole = jsgraph()->TheHoleConstant();
   VariableMode mode = variable->mode();
   switch (variable->location()) {
@@ -1865,7 +1981,7 @@
       Unique<Name> name = MakeUnique(variable->name());
       const Operator* op = javascript()->StoreNamed(strict_mode(), name);
       Node* store = NewNode(op, global, value);
-      PrepareFrameState(store, bailout_id);
+      PrepareFrameState(store, bailout_id, combine);
       return store;
     }
     case Variable::PARAMETER:
@@ -1878,7 +1994,12 @@
           value = BuildHoleCheckSilent(current, value, current);
         }
       } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
-        // Non-initializing assignments to legacy const is ignored.
+        // Non-initializing assignments to legacy const is
+        // - exception in strict mode.
+        // - ignored in sloppy mode.
+        if (strict_mode() == STRICT) {
+          return BuildThrowConstAssignError(bailout_id);
+        }
         return value;
       } else if (mode == LET && op != Token::INIT_LET) {
         // Perform an initialization check for let declared variables.
@@ -1887,13 +2008,13 @@
         // temporal dead zone of a let declared variable.
         Node* current = environment()->Lookup(variable);
         if (current->op() == the_hole->op()) {
-          value = BuildThrowReferenceError(variable);
+          value = BuildThrowReferenceError(variable, bailout_id);
         } else if (value->opcode() == IrOpcode::kPhi) {
-          value = BuildHoleCheckThrow(current, variable, value);
+          value = BuildHoleCheckThrow(current, variable, value, bailout_id);
         }
       } else if (mode == CONST && op != Token::INIT_CONST) {
-        // All assignments to const variables are early errors.
-        UNREACHABLE();
+        // Non-initializing assignments to const is exception in all modes.
+        return BuildThrowConstAssignError(bailout_id);
       }
       environment()->Bind(variable, value);
       return value;
@@ -1907,17 +2028,22 @@
         Node* current = NewNode(op, current_context());
         value = BuildHoleCheckSilent(current, value, current);
       } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
-        // Non-initializing assignments to legacy const is ignored.
+        // Non-initializing assignments to legacy const is
+        // - exception in strict mode.
+        // - ignored in sloppy mode.
+        if (strict_mode() == STRICT) {
+          return BuildThrowConstAssignError(bailout_id);
+        }
         return value;
       } else if (mode == LET && op != Token::INIT_LET) {
         // Perform an initialization check for let declared variables.
         const Operator* op =
             javascript()->LoadContext(depth, variable->index(), false);
         Node* current = NewNode(op, current_context());
-        value = BuildHoleCheckThrow(current, variable, value);
+        value = BuildHoleCheckThrow(current, variable, value, bailout_id);
       } else if (mode == CONST && op != Token::INIT_CONST) {
-        // All assignments to const variables are early errors.
-        UNREACHABLE();
+        // Non-initializing assignments to const is exception in all modes.
+        return BuildThrowConstAssignError(bailout_id);
       }
       const Operator* op = javascript()->StoreContext(depth, variable->index());
       return NewNode(op, current_context(), value);
@@ -1928,8 +2054,11 @@
       Node* strict = jsgraph()->Constant(strict_mode());
       // TODO(mstarzinger): Use Runtime::kInitializeLegacyConstLookupSlot for
       // initializations of const declarations.
-      const Operator* op = javascript()->Runtime(Runtime::kStoreLookupSlot, 4);
-      return NewNode(op, value, current_context(), name, strict);
+      const Operator* op =
+          javascript()->CallRuntime(Runtime::kStoreLookupSlot, 4);
+      Node* store = NewNode(op, value, current_context(), name, strict);
+      PrepareFrameState(store, bailout_id, combine);
+      return store;
     }
   }
   UNREACHABLE();
@@ -1938,7 +2067,6 @@
 
 
 Node* AstGraphBuilder::BuildLoadObjectField(Node* object, int offset) {
-  // TODO(sigurds) Use simplified load here once it is ready.
   Node* field_load = NewNode(jsgraph()->machine()->Load(kMachAnyTagged), object,
                              jsgraph()->Int32Constant(offset - kHeapObjectTag));
   return field_load;
@@ -1961,17 +2089,61 @@
 }
 
 
-Node* AstGraphBuilder::BuildToBoolean(Node* value) {
-  // TODO(mstarzinger): Possible optimization is to NOP for boolean values.
-  return NewNode(javascript()->ToBoolean(), value);
+Node* AstGraphBuilder::BuildLoadGlobalProxy() {
+  Node* global = BuildLoadGlobalObject();
+  Node* proxy =
+      BuildLoadObjectField(global, JSGlobalObject::kGlobalProxyOffset);
+  return proxy;
 }
 
 
-Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable) {
+Node* AstGraphBuilder::BuildToBoolean(Node* input) {
+  // TODO(titzer): this should be in a JSOperatorReducer.
+  switch (input->opcode()) {
+    case IrOpcode::kInt32Constant:
+      return jsgraph_->BooleanConstant(!Int32Matcher(input).Is(0));
+    case IrOpcode::kFloat64Constant:
+      return jsgraph_->BooleanConstant(!Float64Matcher(input).Is(0));
+    case IrOpcode::kNumberConstant:
+      return jsgraph_->BooleanConstant(!NumberMatcher(input).Is(0));
+    case IrOpcode::kHeapConstant: {
+      Handle<Object> object = HeapObjectMatcher<Object>(input).Value().handle();
+      if (object->IsTrue()) return jsgraph_->TrueConstant();
+      if (object->IsFalse()) return jsgraph_->FalseConstant();
+      // TODO(turbofan): other constants.
+      break;
+    }
+    default:
+      break;
+  }
+  if (NodeProperties::IsTyped(input)) {
+    Type* upper = NodeProperties::GetBounds(input).upper;
+    if (upper->Is(Type::Boolean())) return input;
+  }
+
+  return NewNode(javascript()->ToBoolean(), input);
+}
+
+
+Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable,
+                                                BailoutId bailout_id) {
   // TODO(mstarzinger): Should be unified with the VisitThrow implementation.
   Node* variable_name = jsgraph()->Constant(variable->name());
-  const Operator* op = javascript()->Runtime(Runtime::kThrowReferenceError, 1);
-  return NewNode(op, variable_name);
+  const Operator* op =
+      javascript()->CallRuntime(Runtime::kThrowReferenceError, 1);
+  Node* call = NewNode(op, variable_name);
+  PrepareFrameState(call, bailout_id);
+  return call;
+}
+
+
+Node* AstGraphBuilder::BuildThrowConstAssignError(BailoutId bailout_id) {
+  // TODO(mstarzinger): Should be unified with the VisitThrow implementation.
+  const Operator* op =
+      javascript()->CallRuntime(Runtime::kThrowConstAssignError, 0);
+  Node* call = NewNode(op);
+  PrepareFrameState(call, bailout_id);
+  return call;
 }
 
 
@@ -2019,6 +2191,24 @@
 }
 
 
+Node* AstGraphBuilder::BuildStackCheck() {
+  IfBuilder stack_check(this);
+  Node* limit =
+      NewNode(jsgraph()->machine()->Load(kMachPtr),
+              jsgraph()->ExternalConstant(
+                  ExternalReference::address_of_stack_limit(isolate())),
+              jsgraph()->ZeroConstant());
+  Node* stack = NewNode(jsgraph()->machine()->LoadStackPointer());
+  Node* tag = NewNode(jsgraph()->machine()->UintLessThan(), limit, stack);
+  stack_check.If(tag, BranchHint::kTrue);
+  stack_check.Then();
+  stack_check.Else();
+  Node* guard = NewNode(javascript()->CallRuntime(Runtime::kStackGuard, 0));
+  stack_check.End();
+  return guard;
+}
+
+
 void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id,
                                         OutputFrameStateCombine combine) {
   if (OperatorProperties::HasFrameStateInput(node->op())) {
@@ -2029,6 +2219,13 @@
   }
 }
 
+
+BitVector* AstGraphBuilder::GetVariablesAssignedInLoop(
+    IterationStatement* stmt) {
+  if (loop_assignment_analysis_ == NULL) return NULL;
+  return loop_assignment_analysis_->GetVariablesAssignedInLoop(stmt);
 }
-}
-}  // namespace v8::internal::compiler
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/ast-graph-builder.h b/src/compiler/ast-graph-builder.h
index 6a7e3db..0337c81 100644
--- a/src/compiler/ast-graph-builder.h
+++ b/src/compiler/ast-graph-builder.h
@@ -16,8 +16,9 @@
 namespace compiler {
 
 class ControlBuilder;
-class LoopBuilder;
 class Graph;
+class LoopAssignmentAnalysis;
+class LoopBuilder;
 
 // The AstGraphBuilder produces a high-level IR graph, based on an
 // underlying AST. The produced graph can either be compiled into a
@@ -25,7 +26,8 @@
 // of function inlining.
 class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor {
  public:
-  AstGraphBuilder(CompilationInfo* info, JSGraph* jsgraph);
+  AstGraphBuilder(Zone* local_zone, CompilationInfo* info, JSGraph* jsgraph,
+                  LoopAssignmentAnalysis* loop_assignment = NULL);
 
   // Creates a graph by visiting the entire AST.
   bool CreateGraph();
@@ -55,11 +57,7 @@
   // Support for control flow builders. The concrete type of the environment
   // depends on the graph builder, but environments themselves are not virtual.
   typedef StructuredGraphBuilder::Environment BaseEnvironment;
-  virtual BaseEnvironment* CopyEnvironment(BaseEnvironment* env);
-
-  // TODO(mstarzinger): The pipeline only needs to be a friend to access the
-  // function context. Remove as soon as the context is a parameter.
-  friend class Pipeline;
+  BaseEnvironment* CopyEnvironment(BaseEnvironment* env) OVERRIDE;
 
   // Getters for values in the activation record.
   Node* GetFunctionClosure();
@@ -71,6 +69,9 @@
   // other dependencies tracked by the environment might be mutated though.
   //
 
+  // Builder to create a receiver check for sloppy mode.
+  Node* BuildPatchReceiverToGlobalProxy(Node* receiver);
+
   // Builder to create a local function context.
   Node* BuildLocalFunctionContext(Node* context, Node* closure);
 
@@ -79,14 +80,19 @@
 
   // Builders for variable load and assignment.
   Node* BuildVariableAssignment(Variable* var, Node* value, Token::Value op,
-                                BailoutId bailout_id);
-  Node* BuildVariableDelete(Variable* var);
+                                BailoutId bailout_id,
+                                OutputFrameStateCombine state_combine =
+                                    OutputFrameStateCombine::Ignore());
+  Node* BuildVariableDelete(Variable* var, BailoutId bailout_id,
+                            OutputFrameStateCombine state_combine);
   Node* BuildVariableLoad(Variable* var, BailoutId bailout_id,
+                          const VectorSlotPair& feedback,
                           ContextualMode mode = CONTEXTUAL);
 
   // Builders for accessing the function context.
   Node* BuildLoadBuiltinsObject();
   Node* BuildLoadGlobalObject();
+  Node* BuildLoadGlobalProxy();
   Node* BuildLoadClosure();
   Node* BuildLoadObjectField(Node* object, int offset);
 
@@ -94,22 +100,27 @@
   Node* BuildToBoolean(Node* value);
 
   // Builders for error reporting at runtime.
-  Node* BuildThrowReferenceError(Variable* var);
+  Node* BuildThrowReferenceError(Variable* var, BailoutId bailout_id);
+  Node* BuildThrowConstAssignError(BailoutId bailout_id);
 
   // Builders for dynamic hole-checks at runtime.
   Node* BuildHoleCheckSilent(Node* value, Node* for_hole, Node* not_hole);
-  Node* BuildHoleCheckThrow(Node* value, Variable* var, Node* not_hole);
+  Node* BuildHoleCheckThrow(Node* value, Variable* var, Node* not_hole,
+                            BailoutId bailout_id);
 
   // Builders for binary operations.
   Node* BuildBinaryOp(Node* left, Node* right, Token::Value op);
 
-#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+  // Builder for stack-check guards.
+  Node* BuildStackCheck();
+
+#define DECLARE_VISIT(type) void Visit##type(type* node) OVERRIDE;
   // Visiting functions for AST nodes make this an AstVisitor.
   AST_NODE_LIST(DECLARE_VISIT)
 #undef DECLARE_VISIT
 
   // Visiting function for declarations list is overridden.
-  virtual void VisitDeclarations(ZoneList<Declaration*>* declarations);
+  void VisitDeclarations(ZoneList<Declaration*>* declarations) OVERRIDE;
 
  private:
   CompilationInfo* info_;
@@ -117,7 +128,7 @@
   JSGraph* jsgraph_;
 
   // List of global declarations for functions and variables.
-  ZoneList<Handle<Object> > globals_;
+  ZoneVector<Handle<Object>> globals_;
 
   // Stack of breakable statements entered by the visitor.
   BreakableScope* breakable_;
@@ -129,15 +140,21 @@
   SetOncePointer<Node> function_closure_;
   SetOncePointer<Node> function_context_;
 
-  CompilationInfo* info() { return info_; }
-  StrictMode strict_mode() { return info()->strict_mode(); }
+  // Result of loop assignment analysis performed before graph creation.
+  LoopAssignmentAnalysis* loop_assignment_analysis_;
+
+  CompilationInfo* info() const { return info_; }
+  inline StrictMode strict_mode() const;
   JSGraph* jsgraph() { return jsgraph_; }
   JSOperatorBuilder* javascript() { return jsgraph_->javascript(); }
-  ZoneList<Handle<Object> >* globals() { return &globals_; }
+  ZoneVector<Handle<Object>>* globals() { return &globals_; }
 
   // Current scope during visitation.
   inline Scope* current_scope() const;
 
+  // Named and keyed loads require a VectorSlotPair for successful lowering.
+  VectorSlotPair CreateVectorSlotPair(FeedbackVectorICSlot slot) const;
+
   // Process arguments to a call by popping {arity} elements off the operand
   // stack and build a call node using the given call operator.
   Node* ProcessArguments(const Operator* op, int arity);
@@ -146,6 +163,7 @@
   void VisitIfNotNull(Statement* stmt);
 
   // Visit expressions.
+  void Visit(Expression* expr);
   void VisitForTest(Expression* expr);
   void VisitForEffect(Expression* expr);
   void VisitForValue(Expression* expr);
@@ -173,10 +191,11 @@
   void VisitForInAssignment(Expression* expr, Node* value);
 
   // Builds deoptimization for a given node.
-  void PrepareFrameState(Node* node, BailoutId ast_id,
-                         OutputFrameStateCombine combine = kIgnoreOutput);
+  void PrepareFrameState(
+      Node* node, BailoutId ast_id,
+      OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore());
 
-  OutputFrameStateCombine StateCombineFromAstContext();
+  BitVector* GetVariablesAssignedInLoop(IterationStatement* stmt);
 
   DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
   DISALLOW_COPY_AND_ASSIGN(AstGraphBuilder);
@@ -288,7 +307,8 @@
   // Determines how to combine the frame state with the value
   // that is about to be plugged into this AstContext.
   OutputFrameStateCombine GetStateCombine() {
-    return IsEffect() ? kIgnoreOutput : kPushOutput;
+    return IsEffect() ? OutputFrameStateCombine::Ignore()
+                      : OutputFrameStateCombine::Push();
   }
 
   // Plug a node into this expression context.  Call this function in tail
@@ -327,9 +347,9 @@
  public:
   explicit AstEffectContext(AstGraphBuilder* owner)
       : AstContext(owner, Expression::kEffect) {}
-  virtual ~AstEffectContext();
-  virtual void ProduceValue(Node* value) OVERRIDE;
-  virtual Node* ConsumeValue() OVERRIDE;
+  ~AstEffectContext() FINAL;
+  void ProduceValue(Node* value) FINAL;
+  Node* ConsumeValue() FINAL;
 };
 
 
@@ -338,9 +358,9 @@
  public:
   explicit AstValueContext(AstGraphBuilder* owner)
       : AstContext(owner, Expression::kValue) {}
-  virtual ~AstValueContext();
-  virtual void ProduceValue(Node* value) OVERRIDE;
-  virtual Node* ConsumeValue() OVERRIDE;
+  ~AstValueContext() FINAL;
+  void ProduceValue(Node* value) FINAL;
+  Node* ConsumeValue() FINAL;
 };
 
 
@@ -349,9 +369,9 @@
  public:
   explicit AstTestContext(AstGraphBuilder* owner)
       : AstContext(owner, Expression::kTest) {}
-  virtual ~AstTestContext();
-  virtual void ProduceValue(Node* value) OVERRIDE;
-  virtual Node* ConsumeValue() OVERRIDE;
+  ~AstTestContext() FINAL;
+  void ProduceValue(Node* value) FINAL;
+  Node* ConsumeValue() FINAL;
 };
 
 
@@ -423,8 +443,9 @@
 Scope* AstGraphBuilder::current_scope() const {
   return execution_context_->scope();
 }
-}
-}
-}  // namespace v8::internal::compiler
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_AST_GRAPH_BUILDER_H_
diff --git a/src/compiler/ast-loop-assignment-analyzer.cc b/src/compiler/ast-loop-assignment-analyzer.cc
new file mode 100644
index 0000000..7adac56
--- /dev/null
+++ b/src/compiler/ast-loop-assignment-analyzer.cc
@@ -0,0 +1,305 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/ast-loop-assignment-analyzer.h"
+#include "src/parser.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+typedef class AstLoopAssignmentAnalyzer ALAA;  // for code shortitude.
+
+ALAA::AstLoopAssignmentAnalyzer(Zone* zone, CompilationInfo* info)
+    : info_(info), loop_stack_(zone) {
+  InitializeAstVisitor(zone);
+}
+
+
+LoopAssignmentAnalysis* ALAA::Analyze() {
+  LoopAssignmentAnalysis* a = new (zone()) LoopAssignmentAnalysis(zone());
+  result_ = a;
+  VisitStatements(info()->function()->body());
+  result_ = NULL;
+  return a;
+}
+
+
+void ALAA::Enter(IterationStatement* loop) {
+  int num_variables = 1 + info()->scope()->num_parameters() +
+                      info()->scope()->num_stack_slots();
+  BitVector* bits = new (zone()) BitVector(num_variables, zone());
+  loop_stack_.push_back(bits);
+}
+
+
+void ALAA::Exit(IterationStatement* loop) {
+  DCHECK(loop_stack_.size() > 0);
+  BitVector* bits = loop_stack_.back();
+  loop_stack_.pop_back();
+  if (!loop_stack_.empty()) {
+    loop_stack_.back()->Union(*bits);
+  }
+  result_->list_.push_back(
+      std::pair<IterationStatement*, BitVector*>(loop, bits));
+}
+
+
+// ---------------------------------------------------------------------------
+// -- Leaf nodes -------------------------------------------------------------
+// ---------------------------------------------------------------------------
+
+void ALAA::VisitVariableDeclaration(VariableDeclaration* leaf) {}
+void ALAA::VisitFunctionDeclaration(FunctionDeclaration* leaf) {}
+void ALAA::VisitModuleDeclaration(ModuleDeclaration* leaf) {}
+void ALAA::VisitImportDeclaration(ImportDeclaration* leaf) {}
+void ALAA::VisitExportDeclaration(ExportDeclaration* leaf) {}
+void ALAA::VisitModuleVariable(ModuleVariable* leaf) {}
+void ALAA::VisitModulePath(ModulePath* leaf) {}
+void ALAA::VisitModuleUrl(ModuleUrl* leaf) {}
+void ALAA::VisitEmptyStatement(EmptyStatement* leaf) {}
+void ALAA::VisitContinueStatement(ContinueStatement* leaf) {}
+void ALAA::VisitBreakStatement(BreakStatement* leaf) {}
+void ALAA::VisitDebuggerStatement(DebuggerStatement* leaf) {}
+void ALAA::VisitFunctionLiteral(FunctionLiteral* leaf) {}
+void ALAA::VisitNativeFunctionLiteral(NativeFunctionLiteral* leaf) {}
+void ALAA::VisitVariableProxy(VariableProxy* leaf) {}
+void ALAA::VisitLiteral(Literal* leaf) {}
+void ALAA::VisitRegExpLiteral(RegExpLiteral* leaf) {}
+void ALAA::VisitThisFunction(ThisFunction* leaf) {}
+void ALAA::VisitSuperReference(SuperReference* leaf) {}
+
+
+// ---------------------------------------------------------------------------
+// -- Pass-through nodes------------------------------------------------------
+// ---------------------------------------------------------------------------
+void ALAA::VisitModuleLiteral(ModuleLiteral* e) { Visit(e->body()); }
+
+
+void ALAA::VisitBlock(Block* stmt) { VisitStatements(stmt->statements()); }
+
+
+void ALAA::VisitExpressionStatement(ExpressionStatement* stmt) {
+  Visit(stmt->expression());
+}
+
+
+void ALAA::VisitIfStatement(IfStatement* stmt) {
+  Visit(stmt->condition());
+  Visit(stmt->then_statement());
+  Visit(stmt->else_statement());
+}
+
+
+void ALAA::VisitReturnStatement(ReturnStatement* stmt) {
+  Visit(stmt->expression());
+}
+
+
+void ALAA::VisitWithStatement(WithStatement* stmt) {
+  Visit(stmt->expression());
+  Visit(stmt->statement());
+}
+
+
+void ALAA::VisitSwitchStatement(SwitchStatement* stmt) {
+  Visit(stmt->tag());
+  ZoneList<CaseClause*>* clauses = stmt->cases();
+  for (int i = 0; i < clauses->length(); i++) {
+    Visit(clauses->at(i));
+  }
+}
+
+
+void ALAA::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
+  Visit(stmt->try_block());
+  Visit(stmt->finally_block());
+}
+
+
+void ALAA::VisitClassLiteral(ClassLiteral* e) {
+  VisitIfNotNull(e->extends());
+  VisitIfNotNull(e->constructor());
+  ZoneList<ObjectLiteralProperty*>* properties = e->properties();
+  for (int i = 0; i < properties->length(); i++) {
+    Visit(properties->at(i)->value());
+  }
+}
+
+
+void ALAA::VisitConditional(Conditional* e) {
+  Visit(e->condition());
+  Visit(e->then_expression());
+  Visit(e->else_expression());
+}
+
+
+void ALAA::VisitObjectLiteral(ObjectLiteral* e) {
+  ZoneList<ObjectLiteralProperty*>* properties = e->properties();
+  for (int i = 0; i < properties->length(); i++) {
+    Visit(properties->at(i)->value());
+  }
+}
+
+
+void ALAA::VisitArrayLiteral(ArrayLiteral* e) { VisitExpressions(e->values()); }
+
+
+void ALAA::VisitYield(Yield* stmt) {
+  Visit(stmt->generator_object());
+  Visit(stmt->expression());
+}
+
+
+void ALAA::VisitThrow(Throw* stmt) { Visit(stmt->exception()); }
+
+
+void ALAA::VisitProperty(Property* e) {
+  Visit(e->obj());
+  Visit(e->key());
+}
+
+
+void ALAA::VisitCall(Call* e) {
+  Visit(e->expression());
+  VisitExpressions(e->arguments());
+}
+
+
+void ALAA::VisitCallNew(CallNew* e) {
+  Visit(e->expression());
+  VisitExpressions(e->arguments());
+}
+
+
+void ALAA::VisitCallRuntime(CallRuntime* e) {
+  VisitExpressions(e->arguments());
+}
+
+
+void ALAA::VisitUnaryOperation(UnaryOperation* e) { Visit(e->expression()); }
+
+
+void ALAA::VisitBinaryOperation(BinaryOperation* e) {
+  Visit(e->left());
+  Visit(e->right());
+}
+
+
+void ALAA::VisitCompareOperation(CompareOperation* e) {
+  Visit(e->left());
+  Visit(e->right());
+}
+
+
+void ALAA::VisitCaseClause(CaseClause* cc) {
+  if (!cc->is_default()) Visit(cc->label());
+  VisitStatements(cc->statements());
+}
+
+
+// ---------------------------------------------------------------------------
+// -- Interesting nodes-------------------------------------------------------
+// ---------------------------------------------------------------------------
+void ALAA::VisitModuleStatement(ModuleStatement* stmt) {
+  Visit(stmt->body());
+  // TODO(turbofan): can a module appear in a loop?
+  AnalyzeAssignment(stmt->proxy()->var());
+}
+
+
+void ALAA::VisitTryCatchStatement(TryCatchStatement* stmt) {
+  Visit(stmt->try_block());
+  Visit(stmt->catch_block());
+  // TODO(turbofan): are catch variables well-scoped?
+  AnalyzeAssignment(stmt->variable());
+}
+
+
+void ALAA::VisitDoWhileStatement(DoWhileStatement* loop) {
+  Enter(loop);
+  Visit(loop->body());
+  Visit(loop->cond());
+  Exit(loop);
+}
+
+
+void ALAA::VisitWhileStatement(WhileStatement* loop) {
+  Enter(loop);
+  Visit(loop->cond());
+  Visit(loop->body());
+  Exit(loop);
+}
+
+
+void ALAA::VisitForStatement(ForStatement* loop) {
+  VisitIfNotNull(loop->init());
+  Enter(loop);
+  VisitIfNotNull(loop->cond());
+  Visit(loop->body());
+  VisitIfNotNull(loop->next());
+  Exit(loop);
+}
+
+
+void ALAA::VisitForInStatement(ForInStatement* loop) {
+  Enter(loop);
+  Visit(loop->each());
+  Visit(loop->subject());
+  Visit(loop->body());
+  Exit(loop);
+}
+
+
+void ALAA::VisitForOfStatement(ForOfStatement* loop) {
+  Enter(loop);
+  Visit(loop->each());
+  Visit(loop->subject());
+  Visit(loop->body());
+  Exit(loop);
+}
+
+
+void ALAA::VisitAssignment(Assignment* stmt) {
+  Expression* l = stmt->target();
+  Visit(l);
+  Visit(stmt->value());
+  if (l->IsVariableProxy()) AnalyzeAssignment(l->AsVariableProxy()->var());
+}
+
+
+void ALAA::VisitCountOperation(CountOperation* e) {
+  Expression* l = e->expression();
+  Visit(l);
+  if (l->IsVariableProxy()) AnalyzeAssignment(l->AsVariableProxy()->var());
+}
+
+
+void ALAA::AnalyzeAssignment(Variable* var) {
+  if (!loop_stack_.empty() && var->IsStackAllocated()) {
+    loop_stack_.back()->Add(GetVariableIndex(info()->scope(), var));
+  }
+}
+
+
+int ALAA::GetVariableIndex(Scope* scope, Variable* var) {
+  CHECK(var->IsStackAllocated());
+  if (var->is_this()) return 0;
+  if (var->IsParameter()) return 1 + var->index();
+  return 1 + scope->num_parameters() + var->index();
+}
+
+
+int LoopAssignmentAnalysis::GetAssignmentCountForTesting(Scope* scope,
+                                                         Variable* var) {
+  int count = 0;
+  int var_index = AstLoopAssignmentAnalyzer::GetVariableIndex(scope, var);
+  for (size_t i = 0; i < list_.size(); i++) {
+    if (list_[i].second->Contains(var_index)) count++;
+  }
+  return count;
+}
+}
+}
+}  // namespace v8::internal::compiler
diff --git a/src/compiler/ast-loop-assignment-analyzer.h b/src/compiler/ast-loop-assignment-analyzer.h
new file mode 100644
index 0000000..00a7f2d
--- /dev/null
+++ b/src/compiler/ast-loop-assignment-analyzer.h
@@ -0,0 +1,78 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_AST_LOOP_ASSIGNMENT_ANALYZER_H_
+#define V8_COMPILER_AST_LOOP_ASSIGNMENT_ANALYZER_H_
+
+#include "src/ast.h"
+#include "src/bit-vector.h"
+#include "src/v8.h"
+#include "src/zone-containers.h"
+
+namespace v8 {
+namespace internal {
+
+class Variable;
+class Scope;
+
+namespace compiler {
+
+// The result of analyzing loop assignments.
+class LoopAssignmentAnalysis : public ZoneObject {
+ public:
+  BitVector* GetVariablesAssignedInLoop(IterationStatement* loop) {
+    for (size_t i = 0; i < list_.size(); i++) {
+      // TODO(turbofan): hashmap or binary search for loop assignments.
+      if (list_[i].first == loop) return list_[i].second;
+    }
+    UNREACHABLE();  // should never ask for loops that aren't here!
+    return NULL;
+  }
+
+  int GetAssignmentCountForTesting(Scope* scope, Variable* var);
+
+ private:
+  friend class AstLoopAssignmentAnalyzer;
+  explicit LoopAssignmentAnalysis(Zone* zone) : list_(zone) {}
+  ZoneVector<std::pair<IterationStatement*, BitVector*>> list_;
+};
+
+
+// The class that performs loop assignment analysis by walking the AST.
+class AstLoopAssignmentAnalyzer : public AstVisitor {
+ public:
+  AstLoopAssignmentAnalyzer(Zone* zone, CompilationInfo* info);
+
+  LoopAssignmentAnalysis* Analyze();
+
+#define DECLARE_VISIT(type) void Visit##type(type* node) OVERRIDE;
+  AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+  static int GetVariableIndex(Scope* scope, Variable* var);
+
+ private:
+  CompilationInfo* info_;
+  ZoneDeque<BitVector*> loop_stack_;
+  LoopAssignmentAnalysis* result_;
+
+  CompilationInfo* info() { return info_; }
+
+  void Enter(IterationStatement* loop);
+  void Exit(IterationStatement* loop);
+
+  void VisitIfNotNull(AstNode* node) {
+    if (node != NULL) Visit(node);
+  }
+
+  void AnalyzeAssignment(Variable* var);
+
+  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
+  DISALLOW_COPY_AND_ASSIGN(AstLoopAssignmentAnalyzer);
+};
+}
+}
+}  // namespace v8::internal::compiler
+
+#endif  // V8_COMPILER_AST_LOOP_ASSIGNMENT_ANALYZER_H_
diff --git a/src/compiler/basic-block-instrumentor.cc b/src/compiler/basic-block-instrumentor.cc
new file mode 100644
index 0000000..d7d3ade
--- /dev/null
+++ b/src/compiler/basic-block-instrumentor.cc
@@ -0,0 +1,106 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/basic-block-instrumentor.h"
+
+#include <sstream>
+
+#include "src/compiler.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/operator-properties.h"
+#include "src/compiler/schedule.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// Find the first place to insert new nodes in a block that's already been
+// scheduled that won't upset the register allocator.
+static NodeVector::iterator FindInsertionPoint(BasicBlock* block) {
+  NodeVector::iterator i = block->begin();
+  for (; i != block->end(); ++i) {
+    const Operator* op = (*i)->op();
+    if (OperatorProperties::IsBasicBlockBegin(op)) continue;
+    switch (op->opcode()) {
+      case IrOpcode::kParameter:
+      case IrOpcode::kPhi:
+      case IrOpcode::kEffectPhi:
+        continue;
+    }
+    break;
+  }
+  return i;
+}
+
+
+// TODO(dcarney): need to mark code as non-serializable.
+static const Operator* PointerConstant(CommonOperatorBuilder* common,
+                                       void* ptr) {
+  return kPointerSize == 8
+             ? common->Int64Constant(reinterpret_cast<intptr_t>(ptr))
+             : common->Int32Constant(
+                   static_cast<int32_t>(reinterpret_cast<intptr_t>(ptr)));
+}
+
+
+BasicBlockProfiler::Data* BasicBlockInstrumentor::Instrument(
+    CompilationInfo* info, Graph* graph, Schedule* schedule) {
+  // Skip the exit block in profiles, since the register allocator can't handle
+  // it and entry into it means falling off the end of the function anyway.
+  size_t n_blocks = static_cast<size_t>(schedule->RpoBlockCount()) - 1;
+  BasicBlockProfiler::Data* data =
+      info->isolate()->GetOrCreateBasicBlockProfiler()->NewData(n_blocks);
+  // Set the function name.
+  if (!info->shared_info().is_null() &&
+      info->shared_info()->name()->IsString()) {
+    std::ostringstream os;
+    String::cast(info->shared_info()->name())->PrintUC16(os);
+    data->SetFunctionName(&os);
+  }
+  // Capture the schedule string before instrumentation.
+  {
+    std::ostringstream os;
+    os << *schedule;
+    data->SetSchedule(&os);
+  }
+  // Add the increment instructions to the start of every block.
+  CommonOperatorBuilder common(graph->zone());
+  Node* zero = graph->NewNode(common.Int32Constant(0));
+  Node* one = graph->NewNode(common.Int32Constant(1));
+  MachineOperatorBuilder machine(graph->zone());
+  BasicBlockVector* blocks = schedule->rpo_order();
+  size_t block_number = 0;
+  for (BasicBlockVector::iterator it = blocks->begin(); block_number < n_blocks;
+       ++it, ++block_number) {
+    BasicBlock* block = (*it);
+    data->SetBlockId(block_number, block->id().ToSize());
+    // TODO(dcarney): wire effect and control deps for load and store.
+    // Construct increment operation.
+    Node* base = graph->NewNode(
+        PointerConstant(&common, data->GetCounterAddress(block_number)));
+    Node* load = graph->NewNode(machine.Load(kMachUint32), base, zero);
+    Node* inc = graph->NewNode(machine.Int32Add(), load, one);
+    Node* store = graph->NewNode(
+        machine.Store(StoreRepresentation(kMachUint32, kNoWriteBarrier)), base,
+        zero, inc);
+    // Insert the new nodes.
+    static const int kArraySize = 6;
+    Node* to_insert[kArraySize] = {zero, one, base, load, inc, store};
+    int insertion_start = block_number == 0 ? 0 : 2;
+    NodeVector::iterator insertion_point = FindInsertionPoint(block);
+    block->InsertNodes(insertion_point, &to_insert[insertion_start],
+                       &to_insert[kArraySize]);
+    // Tell the scheduler about the new nodes.
+    for (int i = insertion_start; i < kArraySize; ++i) {
+      schedule->SetBlockForNode(block, to_insert[i]);
+    }
+  }
+  return data;
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/basic-block-instrumentor.h b/src/compiler/basic-block-instrumentor.h
new file mode 100644
index 0000000..7edac0d
--- /dev/null
+++ b/src/compiler/basic-block-instrumentor.h
@@ -0,0 +1,32 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_BASIC_BLOCK_INSTRUMENTOR_H_
+#define V8_COMPILER_BASIC_BLOCK_INSTRUMENTOR_H_
+
+#include "src/v8.h"
+
+#include "src/basic-block-profiler.h"
+
+namespace v8 {
+namespace internal {
+
+class CompilationInfo;
+
+namespace compiler {
+
+class Graph;
+class Schedule;
+
+class BasicBlockInstrumentor : public AllStatic {
+ public:
+  static BasicBlockProfiler::Data* Instrument(CompilationInfo* info,
+                                              Graph* graph, Schedule* schedule);
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif
diff --git a/src/compiler/change-lowering-unittest.cc b/src/compiler/change-lowering-unittest.cc
deleted file mode 100644
index 994027a..0000000
--- a/src/compiler/change-lowering-unittest.cc
+++ /dev/null
@@ -1,476 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/change-lowering.h"
-#include "src/compiler/compiler-test-utils.h"
-#include "src/compiler/graph-unittest.h"
-#include "src/compiler/js-graph.h"
-#include "src/compiler/node-properties-inl.h"
-#include "src/compiler/simplified-operator.h"
-#include "src/compiler/typer.h"
-#include "testing/gmock-support.h"
-
-using testing::_;
-using testing::AllOf;
-using testing::Capture;
-using testing::CaptureEq;
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-// TODO(bmeurer): Find a new home for these functions.
-inline std::ostream& operator<<(std::ostream& os, const MachineType& type) {
-  OStringStream ost;
-  ost << type;
-  return os << ost.c_str();
-}
-
-
-class ChangeLoweringTest : public GraphTest {
- public:
-  ChangeLoweringTest() : simplified_(zone()) {}
-  virtual ~ChangeLoweringTest() {}
-
-  virtual MachineType WordRepresentation() const = 0;
-
- protected:
-  int HeapNumberValueOffset() const {
-    STATIC_ASSERT(HeapNumber::kValueOffset % kApiPointerSize == 0);
-    return (HeapNumber::kValueOffset / kApiPointerSize) * PointerSize() -
-           kHeapObjectTag;
-  }
-  bool Is32() const { return WordRepresentation() == kRepWord32; }
-  int PointerSize() const {
-    switch (WordRepresentation()) {
-      case kRepWord32:
-        return 4;
-      case kRepWord64:
-        return 8;
-      default:
-        break;
-    }
-    UNREACHABLE();
-    return 0;
-  }
-  int SmiMaxValue() const { return -(SmiMinValue() + 1); }
-  int SmiMinValue() const {
-    return static_cast<int>(0xffffffffu << (SmiValueSize() - 1));
-  }
-  int SmiShiftAmount() const { return kSmiTagSize + SmiShiftSize(); }
-  int SmiShiftSize() const {
-    return Is32() ? SmiTagging<4>::SmiShiftSize()
-                  : SmiTagging<8>::SmiShiftSize();
-  }
-  int SmiValueSize() const {
-    return Is32() ? SmiTagging<4>::SmiValueSize()
-                  : SmiTagging<8>::SmiValueSize();
-  }
-
-  Node* Parameter(int32_t index = 0) {
-    return graph()->NewNode(common()->Parameter(index), graph()->start());
-  }
-
-  Reduction Reduce(Node* node) {
-    Typer typer(zone());
-    MachineOperatorBuilder machine(WordRepresentation());
-    JSOperatorBuilder javascript(zone());
-    JSGraph jsgraph(graph(), common(), &javascript, &typer, &machine);
-    CompilationInfo info(isolate(), zone());
-    Linkage linkage(&info);
-    ChangeLowering reducer(&jsgraph, &linkage);
-    return reducer.Reduce(node);
-  }
-
-  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
-
-  Matcher<Node*> IsAllocateHeapNumber(const Matcher<Node*>& effect_matcher,
-                                      const Matcher<Node*>& control_matcher) {
-    return IsCall(
-        _, IsHeapConstant(Unique<HeapObject>::CreateImmovable(
-               CEntryStub(isolate(), 1).GetCode())),
-        IsExternalConstant(ExternalReference(
-            Runtime::FunctionForId(Runtime::kAllocateHeapNumber), isolate())),
-        IsInt32Constant(0), IsNumberConstant(0.0), effect_matcher,
-        control_matcher);
-  }
-  Matcher<Node*> IsWordEqual(const Matcher<Node*>& lhs_matcher,
-                             const Matcher<Node*>& rhs_matcher) {
-    return Is32() ? IsWord32Equal(lhs_matcher, rhs_matcher)
-                  : IsWord64Equal(lhs_matcher, rhs_matcher);
-  }
-
- private:
-  SimplifiedOperatorBuilder simplified_;
-};
-
-
-// -----------------------------------------------------------------------------
-// Common.
-
-
-class ChangeLoweringCommonTest
-    : public ChangeLoweringTest,
-      public ::testing::WithParamInterface<MachineType> {
- public:
-  virtual ~ChangeLoweringCommonTest() {}
-
-  virtual MachineType WordRepresentation() const FINAL OVERRIDE {
-    return GetParam();
-  }
-};
-
-
-TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBitToBool) {
-  Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeBitToBool(), val);
-  Reduction reduction = Reduce(node);
-  ASSERT_TRUE(reduction.Changed());
-
-  Node* phi = reduction.replacement();
-  Capture<Node*> branch;
-  EXPECT_THAT(phi,
-              IsPhi(static_cast<MachineType>(kTypeBool | kRepTagged),
-                    IsTrueConstant(), IsFalseConstant(),
-                    IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
-                                           IsBranch(val, graph()->start()))),
-                            IsIfFalse(CaptureEq(&branch)))));
-}
-
-
-TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBoolToBit) {
-  Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeBoolToBit(), val);
-  Reduction reduction = Reduce(node);
-  ASSERT_TRUE(reduction.Changed());
-
-  EXPECT_THAT(reduction.replacement(), IsWordEqual(val, IsTrueConstant()));
-}
-
-
-TARGET_TEST_P(ChangeLoweringCommonTest, ChangeFloat64ToTagged) {
-  Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeFloat64ToTagged(), val);
-  Reduction reduction = Reduce(node);
-  ASSERT_TRUE(reduction.Changed());
-
-  Node* finish = reduction.replacement();
-  Capture<Node*> heap_number;
-  EXPECT_THAT(
-      finish,
-      IsFinish(
-          AllOf(CaptureEq(&heap_number),
-                IsAllocateHeapNumber(IsValueEffect(val), graph()->start())),
-          IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number),
-                  IsInt32Constant(HeapNumberValueOffset()), val,
-                  CaptureEq(&heap_number), graph()->start())));
-}
-
-
-TARGET_TEST_P(ChangeLoweringCommonTest, StringAdd) {
-  Node* node =
-      graph()->NewNode(simplified()->StringAdd(), Parameter(0), Parameter(1));
-  Reduction reduction = Reduce(node);
-  EXPECT_FALSE(reduction.Changed());
-}
-
-
-INSTANTIATE_TEST_CASE_P(ChangeLoweringTest, ChangeLoweringCommonTest,
-                        ::testing::Values(kRepWord32, kRepWord64));
-
-
-// -----------------------------------------------------------------------------
-// 32-bit
-
-
-class ChangeLowering32Test : public ChangeLoweringTest {
- public:
-  virtual ~ChangeLowering32Test() {}
-  virtual MachineType WordRepresentation() const FINAL OVERRIDE {
-    return kRepWord32;
-  }
-};
-
-
-TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) {
-  Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
-  Reduction reduction = Reduce(node);
-  ASSERT_TRUE(reduction.Changed());
-
-  Node* phi = reduction.replacement();
-  Capture<Node*> add, branch, heap_number, if_true;
-  EXPECT_THAT(
-      phi,
-      IsPhi(kMachAnyTagged,
-            IsFinish(
-                AllOf(CaptureEq(&heap_number),
-                      IsAllocateHeapNumber(_, CaptureEq(&if_true))),
-                IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number),
-                        IsInt32Constant(HeapNumberValueOffset()),
-                        IsChangeInt32ToFloat64(val), CaptureEq(&heap_number),
-                        CaptureEq(&if_true))),
-            IsProjection(
-                0, AllOf(CaptureEq(&add), IsInt32AddWithOverflow(val, val))),
-            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
-                    IsIfFalse(AllOf(CaptureEq(&branch),
-                                    IsBranch(IsProjection(1, CaptureEq(&add)),
-                                             graph()->start()))))));
-}
-
-
-TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
-  STATIC_ASSERT(kSmiTag == 0);
-  STATIC_ASSERT(kSmiTagSize == 1);
-
-  Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
-  Reduction reduction = Reduce(node);
-  ASSERT_TRUE(reduction.Changed());
-
-  Node* phi = reduction.replacement();
-  Capture<Node*> branch, if_true;
-  EXPECT_THAT(
-      phi,
-      IsPhi(
-          kMachFloat64,
-          IsLoad(kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
-                 IsControlEffect(CaptureEq(&if_true))),
-          IsChangeInt32ToFloat64(
-              IsWord32Sar(val, IsInt32Constant(SmiShiftAmount()))),
-          IsMerge(
-              AllOf(CaptureEq(&if_true),
-                    IsIfTrue(AllOf(
-                        CaptureEq(&branch),
-                        IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
-                                 graph()->start())))),
-              IsIfFalse(CaptureEq(&branch)))));
-}
-
-
-TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) {
-  STATIC_ASSERT(kSmiTag == 0);
-  STATIC_ASSERT(kSmiTagSize == 1);
-
-  Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
-  Reduction reduction = Reduce(node);
-  ASSERT_TRUE(reduction.Changed());
-
-  Node* phi = reduction.replacement();
-  Capture<Node*> branch, if_true;
-  EXPECT_THAT(
-      phi,
-      IsPhi(kMachInt32,
-            IsChangeFloat64ToInt32(IsLoad(
-                kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
-                IsControlEffect(CaptureEq(&if_true)))),
-            IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())),
-            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
-                    IsIfFalse(AllOf(
-                        CaptureEq(&branch),
-                        IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
-                                 graph()->start()))))));
-}
-
-
-TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToUint32) {
-  STATIC_ASSERT(kSmiTag == 0);
-  STATIC_ASSERT(kSmiTagSize == 1);
-
-  Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val);
-  Reduction reduction = Reduce(node);
-  ASSERT_TRUE(reduction.Changed());
-
-  Node* phi = reduction.replacement();
-  Capture<Node*> branch, if_true;
-  EXPECT_THAT(
-      phi,
-      IsPhi(kMachUint32,
-            IsChangeFloat64ToUint32(IsLoad(
-                kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
-                IsControlEffect(CaptureEq(&if_true)))),
-            IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())),
-            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
-                    IsIfFalse(AllOf(
-                        CaptureEq(&branch),
-                        IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
-                                 graph()->start()))))));
-}
-
-
-TARGET_TEST_F(ChangeLowering32Test, ChangeUint32ToTagged) {
-  STATIC_ASSERT(kSmiTag == 0);
-  STATIC_ASSERT(kSmiTagSize == 1);
-
-  Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val);
-  Reduction reduction = Reduce(node);
-  ASSERT_TRUE(reduction.Changed());
-
-  Node* phi = reduction.replacement();
-  Capture<Node*> branch, heap_number, if_false;
-  EXPECT_THAT(
-      phi,
-      IsPhi(
-          kMachAnyTagged, IsWord32Shl(val, IsInt32Constant(SmiShiftAmount())),
-          IsFinish(
-              AllOf(CaptureEq(&heap_number),
-                    IsAllocateHeapNumber(_, CaptureEq(&if_false))),
-              IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number),
-                      IsInt32Constant(HeapNumberValueOffset()),
-                      IsChangeUint32ToFloat64(val), CaptureEq(&heap_number),
-                      CaptureEq(&if_false))),
-          IsMerge(
-              IsIfTrue(AllOf(CaptureEq(&branch),
-                             IsBranch(IsUint32LessThanOrEqual(
-                                          val, IsInt32Constant(SmiMaxValue())),
-                                      graph()->start()))),
-              AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
-}
-
-
-// -----------------------------------------------------------------------------
-// 64-bit
-
-
-class ChangeLowering64Test : public ChangeLoweringTest {
- public:
-  virtual ~ChangeLowering64Test() {}
-  virtual MachineType WordRepresentation() const FINAL OVERRIDE {
-    return kRepWord64;
-  }
-};
-
-
-TARGET_TEST_F(ChangeLowering64Test, ChangeInt32ToTagged) {
-  Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
-  Reduction reduction = Reduce(node);
-  ASSERT_TRUE(reduction.Changed());
-
-  EXPECT_THAT(reduction.replacement(),
-              IsWord64Shl(IsChangeInt32ToInt64(val),
-                          IsInt32Constant(SmiShiftAmount())));
-}
-
-
-TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
-  STATIC_ASSERT(kSmiTag == 0);
-  STATIC_ASSERT(kSmiTagSize == 1);
-
-  Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
-  Reduction reduction = Reduce(node);
-  ASSERT_TRUE(reduction.Changed());
-
-  Node* phi = reduction.replacement();
-  Capture<Node*> branch, if_true;
-  EXPECT_THAT(
-      phi,
-      IsPhi(
-          kMachFloat64,
-          IsLoad(kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
-                 IsControlEffect(CaptureEq(&if_true))),
-          IsChangeInt32ToFloat64(IsTruncateInt64ToInt32(
-              IsWord64Sar(val, IsInt32Constant(SmiShiftAmount())))),
-          IsMerge(
-              AllOf(CaptureEq(&if_true),
-                    IsIfTrue(AllOf(
-                        CaptureEq(&branch),
-                        IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
-                                 graph()->start())))),
-              IsIfFalse(CaptureEq(&branch)))));
-}
-
-
-TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) {
-  STATIC_ASSERT(kSmiTag == 0);
-  STATIC_ASSERT(kSmiTagSize == 1);
-
-  Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
-  Reduction reduction = Reduce(node);
-  ASSERT_TRUE(reduction.Changed());
-
-  Node* phi = reduction.replacement();
-  Capture<Node*> branch, if_true;
-  EXPECT_THAT(
-      phi,
-      IsPhi(kMachInt32,
-            IsChangeFloat64ToInt32(IsLoad(
-                kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
-                IsControlEffect(CaptureEq(&if_true)))),
-            IsTruncateInt64ToInt32(
-                IsWord64Sar(val, IsInt32Constant(SmiShiftAmount()))),
-            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
-                    IsIfFalse(AllOf(
-                        CaptureEq(&branch),
-                        IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
-                                 graph()->start()))))));
-}
-
-
-TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToUint32) {
-  STATIC_ASSERT(kSmiTag == 0);
-  STATIC_ASSERT(kSmiTagSize == 1);
-
-  Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val);
-  Reduction reduction = Reduce(node);
-  ASSERT_TRUE(reduction.Changed());
-
-  Node* phi = reduction.replacement();
-  Capture<Node*> branch, if_true;
-  EXPECT_THAT(
-      phi,
-      IsPhi(kMachUint32,
-            IsChangeFloat64ToUint32(IsLoad(
-                kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
-                IsControlEffect(CaptureEq(&if_true)))),
-            IsTruncateInt64ToInt32(
-                IsWord64Sar(val, IsInt32Constant(SmiShiftAmount()))),
-            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
-                    IsIfFalse(AllOf(
-                        CaptureEq(&branch),
-                        IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
-                                 graph()->start()))))));
-}
-
-
-TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) {
-  STATIC_ASSERT(kSmiTag == 0);
-  STATIC_ASSERT(kSmiTagSize == 1);
-
-  Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val);
-  Reduction reduction = Reduce(node);
-  ASSERT_TRUE(reduction.Changed());
-
-  Node* phi = reduction.replacement();
-  Capture<Node*> branch, heap_number, if_false;
-  EXPECT_THAT(
-      phi,
-      IsPhi(
-          kMachAnyTagged, IsWord64Shl(IsChangeUint32ToUint64(val),
-                                      IsInt32Constant(SmiShiftAmount())),
-          IsFinish(
-              AllOf(CaptureEq(&heap_number),
-                    IsAllocateHeapNumber(_, CaptureEq(&if_false))),
-              IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number),
-                      IsInt32Constant(HeapNumberValueOffset()),
-                      IsChangeUint32ToFloat64(val), CaptureEq(&heap_number),
-                      CaptureEq(&if_false))),
-          IsMerge(
-              IsIfTrue(AllOf(CaptureEq(&branch),
-                             IsBranch(IsUint32LessThanOrEqual(
-                                          val, IsInt32Constant(SmiMaxValue())),
-                                      graph()->start()))),
-              AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
-}
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/change-lowering.cc b/src/compiler/change-lowering.cc
index b13db4c..7ddc751 100644
--- a/src/compiler/change-lowering.cc
+++ b/src/compiler/change-lowering.cc
@@ -3,9 +3,13 @@
 // found in the LICENSE file.
 
 #include "src/compiler/change-lowering.h"
-#include "src/compiler/machine-operator.h"
 
+#include "src/code-factory.h"
+#include "src/compiler/diamond.h"
 #include "src/compiler/js-graph.h"
+#include "src/compiler/linkage.h"
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/node-properties-inl.h"
 
 namespace v8 {
 namespace internal {
@@ -45,7 +49,7 @@
   STATIC_ASSERT(HeapNumber::kValueOffset % kPointerSize == 0);
   const int heap_number_value_offset =
       ((HeapNumber::kValueOffset / kPointerSize) * (machine()->Is64() ? 8 : 4));
-  return jsgraph()->Int32Constant(heap_number_value_offset - kHeapObjectTag);
+  return jsgraph()->IntPtrConstant(heap_number_value_offset - kHeapObjectTag);
 }
 
 
@@ -60,24 +64,21 @@
 Node* ChangeLowering::SmiShiftBitsConstant() {
   const int smi_shift_size = machine()->Is32() ? SmiTagging<4>::SmiShiftSize()
                                                : SmiTagging<8>::SmiShiftSize();
-  return jsgraph()->Int32Constant(smi_shift_size + kSmiTagSize);
+  return jsgraph()->IntPtrConstant(smi_shift_size + kSmiTagSize);
 }
 
 
 Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node* control) {
-  // The AllocateHeapNumber() runtime function does not use the context, so we
-  // can safely pass in Smi zero here.
-  Node* context = jsgraph()->ZeroConstant();
+  // The AllocateHeapNumberStub does not use the context, so we can safely pass
+  // in Smi zero here.
+  Callable callable = CodeFactory::AllocateHeapNumber(isolate());
+  CallDescriptor* descriptor = linkage()->GetStubCallDescriptor(
+      callable.descriptor(), 0, CallDescriptor::kNoFlags);
+  Node* target = jsgraph()->HeapConstant(callable.code());
+  Node* context = jsgraph()->NoContextConstant();
   Node* effect = graph()->NewNode(common()->ValueEffect(1), value);
-  const Runtime::Function* function =
-      Runtime::FunctionForId(Runtime::kAllocateHeapNumber);
-  DCHECK_EQ(0, function->nargs);
-  CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(
-      function->function_id, 0, Operator::kNoProperties);
-  Node* heap_number = graph()->NewNode(
-      common()->Call(desc), jsgraph()->CEntryStubConstant(),
-      jsgraph()->ExternalConstant(ExternalReference(function, isolate())),
-      jsgraph()->Int32Constant(function->nargs), context, effect, control);
+  Node* heap_number = graph()->NewNode(common()->Call(descriptor), target,
+                                       context, effect, control);
   Node* store = graph()->NewNode(
       machine()->Store(StoreRepresentation(kMachFloat64, kNoWriteBarrier)),
       heap_number, HeapNumberValueIndexConstant(), value, heap_number, control);
@@ -85,6 +86,16 @@
 }
 
 
+Node* ChangeLowering::ChangeInt32ToFloat64(Node* value) {
+  return graph()->NewNode(machine()->ChangeInt32ToFloat64(), value);
+}
+
+
+Node* ChangeLowering::ChangeSmiToFloat64(Node* value) {
+  return ChangeInt32ToFloat64(ChangeSmiToInt32(value));
+}
+
+
 Node* ChangeLowering::ChangeSmiToInt32(Node* value) {
   value = graph()->NewNode(machine()->WordSar(), value, SmiShiftBitsConstant());
   if (machine()->Is64()) {
@@ -94,28 +105,44 @@
 }
 
 
+Node* ChangeLowering::ChangeUint32ToFloat64(Node* value) {
+  return graph()->NewNode(machine()->ChangeUint32ToFloat64(), value);
+}
+
+
+Node* ChangeLowering::ChangeUint32ToSmi(Node* value) {
+  if (machine()->Is64()) {
+    value = graph()->NewNode(machine()->ChangeUint32ToUint64(), value);
+  }
+  return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant());
+}
+
+
 Node* ChangeLowering::LoadHeapNumberValue(Node* value, Node* control) {
   return graph()->NewNode(machine()->Load(kMachFloat64), value,
-                          HeapNumberValueIndexConstant(),
-                          graph()->NewNode(common()->ControlEffect(), control));
+                          HeapNumberValueIndexConstant(), graph()->start(),
+                          control);
+}
+
+
+Node* ChangeLowering::TestNotSmi(Node* value) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagMask == 1);
+  return graph()->NewNode(machine()->WordAnd(), value,
+                          jsgraph()->IntPtrConstant(kSmiTagMask));
+}
+
+
+Node* ChangeLowering::Uint32LessThanOrEqual(Node* lhs, Node* rhs) {
+  return graph()->NewNode(machine()->Uint32LessThanOrEqual(), lhs, rhs);
 }
 
 
 Reduction ChangeLowering::ChangeBitToBool(Node* val, Node* control) {
-  Node* branch = graph()->NewNode(common()->Branch(), val, control);
-
-  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-  Node* true_value = jsgraph()->TrueConstant();
-
-  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
-  Node* false_value = jsgraph()->FalseConstant();
-
-  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-  Node* phi = graph()->NewNode(
-      common()->Phi(static_cast<MachineType>(kTypeBool | kRepTagged), 2),
-      true_value, false_value, merge);
-
-  return Replace(phi);
+  MachineType const type = static_cast<MachineType>(kTypeBool | kRepTagged);
+  return Replace(graph()->NewNode(common()->Select(type), val,
+                                  jsgraph()->TrueConstant(),
+                                  jsgraph()->FalseConstant()));
 }
 
 
@@ -130,109 +157,109 @@
 }
 
 
-Reduction ChangeLowering::ChangeInt32ToTagged(Node* val, Node* control) {
+Reduction ChangeLowering::ChangeInt32ToTagged(Node* value, Node* control) {
   if (machine()->Is64()) {
+    return Replace(graph()->NewNode(
+        machine()->Word64Shl(),
+        graph()->NewNode(machine()->ChangeInt32ToInt64(), value),
+        SmiShiftBitsConstant()));
+  } else if (NodeProperties::GetBounds(value).upper->Is(Type::SignedSmall())) {
     return Replace(
-        graph()->NewNode(machine()->Word64Shl(),
-                         graph()->NewNode(machine()->ChangeInt32ToInt64(), val),
-                         SmiShiftBitsConstant()));
+        graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant()));
   }
 
-  Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), val, val);
+  Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value);
   Node* ovf = graph()->NewNode(common()->Projection(1), add);
 
-  Node* branch = graph()->NewNode(common()->Branch(), ovf, control);
-
-  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-  Node* heap_number = AllocateHeapNumberWithValue(
-      graph()->NewNode(machine()->ChangeInt32ToFloat64(), val), if_true);
-
-  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
-  Node* smi = graph()->NewNode(common()->Projection(0), add);
-
-  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-  Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), heap_number,
-                               smi, merge);
-
-  return Replace(phi);
+  Diamond d(graph(), common(), ovf, BranchHint::kFalse);
+  d.Chain(control);
+  return Replace(
+      d.Phi(kMachAnyTagged,
+            AllocateHeapNumberWithValue(ChangeInt32ToFloat64(value), d.if_true),
+            graph()->NewNode(common()->Projection(0), add)));
 }
 
 
-Reduction ChangeLowering::ChangeTaggedToUI32(Node* val, Node* control,
+Reduction ChangeLowering::ChangeTaggedToUI32(Node* value, Node* control,
                                              Signedness signedness) {
-  STATIC_ASSERT(kSmiTag == 0);
-  STATIC_ASSERT(kSmiTagMask == 1);
-
-  Node* tag = graph()->NewNode(machine()->WordAnd(), val,
-                               jsgraph()->Int32Constant(kSmiTagMask));
-  Node* branch = graph()->NewNode(common()->Branch(), tag, control);
-
-  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  const MachineType type = (signedness == kSigned) ? kMachInt32 : kMachUint32;
   const Operator* op = (signedness == kSigned)
                            ? machine()->ChangeFloat64ToInt32()
                            : machine()->ChangeFloat64ToUint32();
-  Node* change = graph()->NewNode(op, LoadHeapNumberValue(val, if_true));
-
-  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
-  Node* number = ChangeSmiToInt32(val);
-
-  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-  Node* phi = graph()->NewNode(
-      common()->Phi((signedness == kSigned) ? kMachInt32 : kMachUint32, 2),
-      change, number, merge);
-
-  return Replace(phi);
+  Diamond d(graph(), common(), TestNotSmi(value), BranchHint::kFalse);
+  d.Chain(control);
+  return Replace(
+      d.Phi(type, graph()->NewNode(op, LoadHeapNumberValue(value, d.if_true)),
+            ChangeSmiToInt32(value)));
 }
 
 
-Reduction ChangeLowering::ChangeTaggedToFloat64(Node* val, Node* control) {
-  STATIC_ASSERT(kSmiTag == 0);
-  STATIC_ASSERT(kSmiTagMask == 1);
+namespace {
 
-  Node* tag = graph()->NewNode(machine()->WordAnd(), val,
-                               jsgraph()->Int32Constant(kSmiTagMask));
-  Node* branch = graph()->NewNode(common()->Branch(), tag, control);
+bool CanCover(Node* value, IrOpcode::Value opcode) {
+  if (value->opcode() != opcode) return false;
+  bool first = true;
+  for (Edge const edge : value->use_edges()) {
+    if (NodeProperties::IsEffectEdge(edge)) continue;
+    DCHECK(NodeProperties::IsValueEdge(edge));
+    if (!first) return false;
+    first = false;
+  }
+  return true;
+}
 
-  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-  Node* load = LoadHeapNumberValue(val, if_true);
+}  // namespace
 
-  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
-  Node* number = graph()->NewNode(machine()->ChangeInt32ToFloat64(),
-                                  ChangeSmiToInt32(val));
 
-  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-  Node* phi =
-      graph()->NewNode(common()->Phi(kMachFloat64, 2), load, number, merge);
+Reduction ChangeLowering::ChangeTaggedToFloat64(Node* value, Node* control) {
+  if (CanCover(value, IrOpcode::kJSToNumber)) {
+    // ChangeTaggedToFloat64(JSToNumber(x)) =>
+    //   if IsSmi(x) then ChangeSmiToFloat64(x)
+    //   else let y = JSToNumber(x) in
+    //     if IsSmi(y) then ChangeSmiToFloat64(y)
+    //     else LoadHeapNumberValue(y)
+    Node* const object = NodeProperties::GetValueInput(value, 0);
+    Node* const context = NodeProperties::GetContextInput(value);
+    Node* const effect = NodeProperties::GetEffectInput(value);
+    Node* const control = NodeProperties::GetControlInput(value);
 
-  return Replace(phi);
+    Diamond d1(graph(), common(), TestNotSmi(object), BranchHint::kFalse);
+    d1.Chain(control);
+
+    Node* number =
+        graph()->NewNode(value->op(), object, context, effect, d1.if_true);
+    Diamond d2(graph(), common(), TestNotSmi(number));
+    d2.Nest(d1, true);
+    Node* phi2 = d2.Phi(kMachFloat64, LoadHeapNumberValue(number, d2.if_true),
+                        ChangeSmiToFloat64(number));
+
+    Node* phi1 = d1.Phi(kMachFloat64, phi2, ChangeSmiToFloat64(object));
+    Node* ephi1 = d1.EffectPhi(number, effect);
+
+    for (Edge edge : value->use_edges()) {
+      if (NodeProperties::IsEffectEdge(edge)) {
+        edge.UpdateTo(ephi1);
+      }
+    }
+    return Replace(phi1);
+  }
+
+  Diamond d(graph(), common(), TestNotSmi(value), BranchHint::kFalse);
+  d.Chain(control);
+  Node* load = LoadHeapNumberValue(value, d.if_true);
+  Node* number = ChangeSmiToFloat64(value);
+  return Replace(d.Phi(kMachFloat64, load, number));
 }
 
 
-Reduction ChangeLowering::ChangeUint32ToTagged(Node* val, Node* control) {
-  STATIC_ASSERT(kSmiTag == 0);
-  STATIC_ASSERT(kSmiTagMask == 1);
-
-  Node* cmp = graph()->NewNode(machine()->Uint32LessThanOrEqual(), val,
-                               SmiMaxValueConstant());
-  Node* branch = graph()->NewNode(common()->Branch(), cmp, control);
-
-  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-  Node* smi = graph()->NewNode(
-      machine()->WordShl(),
-      machine()->Is64()
-          ? graph()->NewNode(machine()->ChangeUint32ToUint64(), val)
-          : val,
-      SmiShiftBitsConstant());
-
-  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
-  Node* heap_number = AllocateHeapNumberWithValue(
-      graph()->NewNode(machine()->ChangeUint32ToFloat64(), val), if_false);
-
-  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-  Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), smi,
-                               heap_number, merge);
-
-  return Replace(phi);
+Reduction ChangeLowering::ChangeUint32ToTagged(Node* value, Node* control) {
+  Diamond d(graph(), common(),
+            Uint32LessThanOrEqual(value, SmiMaxValueConstant()),
+            BranchHint::kTrue);
+  d.Chain(control);
+  return Replace(d.Phi(
+      kMachAnyTagged, ChangeUint32ToSmi(value),
+      AllocateHeapNumberWithValue(ChangeUint32ToFloat64(value), d.if_false)));
 }
 
 
diff --git a/src/compiler/change-lowering.h b/src/compiler/change-lowering.h
index 5d7ab41..773fd08 100644
--- a/src/compiler/change-lowering.h
+++ b/src/compiler/change-lowering.h
@@ -21,9 +21,9 @@
  public:
   ChangeLowering(JSGraph* jsgraph, Linkage* linkage)
       : jsgraph_(jsgraph), linkage_(linkage) {}
-  virtual ~ChangeLowering();
+  ~ChangeLowering() FINAL;
 
-  virtual Reduction Reduce(Node* node) OVERRIDE;
+  Reduction Reduce(Node* node) FINAL;
 
  private:
   Node* HeapNumberValueIndexConstant();
@@ -31,16 +31,23 @@
   Node* SmiShiftBitsConstant();
 
   Node* AllocateHeapNumberWithValue(Node* value, Node* control);
+  Node* ChangeInt32ToFloat64(Node* value);
+  Node* ChangeSmiToFloat64(Node* value);
   Node* ChangeSmiToInt32(Node* value);
+  Node* ChangeUint32ToFloat64(Node* value);
+  Node* ChangeUint32ToSmi(Node* value);
   Node* LoadHeapNumberValue(Node* value, Node* control);
+  Node* TestNotSmi(Node* value);
+  Node* Uint32LessThanOrEqual(Node* lhs, Node* rhs);
 
-  Reduction ChangeBitToBool(Node* val, Node* control);
-  Reduction ChangeBoolToBit(Node* val);
-  Reduction ChangeFloat64ToTagged(Node* val, Node* control);
-  Reduction ChangeInt32ToTagged(Node* val, Node* control);
-  Reduction ChangeTaggedToFloat64(Node* val, Node* control);
-  Reduction ChangeTaggedToUI32(Node* val, Node* control, Signedness signedness);
-  Reduction ChangeUint32ToTagged(Node* val, Node* control);
+  Reduction ChangeBitToBool(Node* value, Node* control);
+  Reduction ChangeBoolToBit(Node* value);
+  Reduction ChangeFloat64ToTagged(Node* value, Node* control);
+  Reduction ChangeInt32ToTagged(Node* value, Node* control);
+  Reduction ChangeTaggedToFloat64(Node* value, Node* control);
+  Reduction ChangeTaggedToUI32(Node* value, Node* control,
+                               Signedness signedness);
+  Reduction ChangeUint32ToTagged(Node* value, Node* control);
 
   Graph* graph() const;
   Isolate* isolate() const;
diff --git a/src/compiler/code-generator-impl.h b/src/compiler/code-generator-impl.h
index a3f7e4c..7942344 100644
--- a/src/compiler/code-generator-impl.h
+++ b/src/compiler/code-generator-impl.h
@@ -5,15 +5,12 @@
 #ifndef V8_COMPILER_CODE_GENERATOR_IMPL_H_
 #define V8_COMPILER_CODE_GENERATOR_IMPL_H_
 
+#include "src/code-stubs.h"
 #include "src/compiler/code-generator.h"
-#include "src/compiler/common-operator.h"
-#include "src/compiler/generic-graph.h"
 #include "src/compiler/instruction.h"
 #include "src/compiler/linkage.h"
-#include "src/compiler/machine-operator.h"
-#include "src/compiler/node.h"
 #include "src/compiler/opcodes.h"
-#include "src/compiler/operator.h"
+#include "src/macro-assembler.h"
 
 namespace v8 {
 namespace internal {
@@ -28,6 +25,8 @@
   InstructionOperandConverter(CodeGenerator* gen, Instruction* instr)
       : gen_(gen), instr_(instr) {}
 
+  // -- Instruction operand accesses with conversions --------------------------
+
   Register InputRegister(int index) {
     return ToRegister(instr_->InputAt(index));
   }
@@ -60,27 +59,31 @@
     return ToHeapObject(instr_->InputAt(index));
   }
 
-  Label* InputLabel(int index) {
-    return gen_->code()->GetLabel(InputBlock(index));
-  }
+  Label* InputLabel(int index) { return ToLabel(instr_->InputAt(index)); }
 
-  BasicBlock* InputBlock(int index) {
-    NodeId block_id = static_cast<NodeId>(InputInt32(index));
-    // operand should be a block id.
-    DCHECK(block_id >= 0);
-    DCHECK(block_id < gen_->schedule()->BasicBlockCount());
-    return gen_->schedule()->GetBlockById(block_id);
+  BasicBlock::RpoNumber InputRpo(int index) {
+    return ToRpoNumber(instr_->InputAt(index));
   }
 
   Register OutputRegister(int index = 0) {
     return ToRegister(instr_->OutputAt(index));
   }
 
+  Register TempRegister(int index) { return ToRegister(instr_->TempAt(index)); }
+
   DoubleRegister OutputDoubleRegister() {
     return ToDoubleRegister(instr_->Output());
   }
 
-  Register TempRegister(int index) { return ToRegister(instr_->TempAt(index)); }
+  // -- Conversions for operands -----------------------------------------------
+
+  Label* ToLabel(InstructionOperand* op) {
+    return gen_->GetLabel(ToRpoNumber(op));
+  }
+
+  BasicBlock::RpoNumber ToRpoNumber(InstructionOperand* op) {
+    return ToConstant(op).ToRpoNumber();
+  }
 
   Register ToRegister(InstructionOperand* op) {
     DCHECK(op->IsRegister());
@@ -92,19 +95,17 @@
     return DoubleRegister::FromAllocationIndex(op->index());
   }
 
-  Constant ToConstant(InstructionOperand* operand) {
-    if (operand->IsImmediate()) {
-      return gen_->code()->GetImmediate(operand->index());
+  Constant ToConstant(InstructionOperand* op) {
+    if (op->IsImmediate()) {
+      return gen_->code()->GetImmediate(op->index());
     }
-    return gen_->code()->GetConstant(operand->index());
+    return gen_->code()->GetConstant(op->index());
   }
 
-  double ToDouble(InstructionOperand* operand) {
-    return ToConstant(operand).ToFloat64();
-  }
+  double ToDouble(InstructionOperand* op) { return ToConstant(op).ToFloat64(); }
 
-  Handle<HeapObject> ToHeapObject(InstructionOperand* operand) {
-    return ToConstant(operand).ToHeapObject();
+  Handle<HeapObject> ToHeapObject(InstructionOperand* op) {
+    return ToConstant(op).ToHeapObject();
   }
 
   Frame* frame() const { return gen_->frame(); }
@@ -117,6 +118,27 @@
 };
 
 
+// Generator for out-of-line code that is emitted after the main code is done.
+class OutOfLineCode : public ZoneObject {
+ public:
+  explicit OutOfLineCode(CodeGenerator* gen);
+  virtual ~OutOfLineCode();
+
+  virtual void Generate() = 0;
+
+  Label* entry() { return &entry_; }
+  Label* exit() { return &exit_; }
+  MacroAssembler* masm() const { return masm_; }
+  OutOfLineCode* next() const { return next_; }
+
+ private:
+  Label entry_;
+  Label exit_;
+  MacroAssembler* const masm_;
+  OutOfLineCode* const next_;
+};
+
+
 // TODO(dcarney): generify this on bleeding_edge and replace this call
 // when merged.
 static inline void FinishCode(MacroAssembler* masm) {
diff --git a/src/compiler/code-generator.cc b/src/compiler/code-generator.cc
index f22c479..cfe4f06 100644
--- a/src/compiler/code-generator.cc
+++ b/src/compiler/code-generator.cc
@@ -12,9 +12,14 @@
 namespace internal {
 namespace compiler {
 
-CodeGenerator::CodeGenerator(InstructionSequence* code)
-    : code_(code),
-      current_block_(NULL),
+CodeGenerator::CodeGenerator(Frame* frame, Linkage* linkage,
+                             InstructionSequence* code, CompilationInfo* info)
+    : frame_(frame),
+      linkage_(linkage),
+      code_(code),
+      info_(info),
+      labels_(zone()->NewArray<Label>(code->InstructionBlockCount())),
+      current_block_(BasicBlock::RpoNumber::Invalid()),
       current_source_position_(SourcePosition::Invalid()),
       masm_(code->zone()->isolate(), NULL, 0),
       resolver_(this),
@@ -22,11 +27,16 @@
       deoptimization_states_(code->zone()),
       deoptimization_literals_(code->zone()),
       translations_(code->zone()),
-      last_lazy_deopt_pc_(0) {}
+      last_lazy_deopt_pc_(0),
+      ools_(nullptr) {
+  for (int i = 0; i < code->InstructionBlockCount(); ++i) {
+    new (&labels_[i]) Label;
+  }
+}
 
 
 Handle<Code> CodeGenerator::GenerateCode() {
-  CompilationInfo* info = linkage()->info();
+  CompilationInfo* info = this->info();
 
   // Emit a code line info recording start event.
   PositionsRecorder* recorder = masm()->positions_recorder();
@@ -41,15 +51,42 @@
   info->set_prologue_offset(masm()->pc_offset());
   AssemblePrologue();
 
-  // Assemble all instructions.
-  for (InstructionSequence::const_iterator i = code()->begin();
-       i != code()->end(); ++i) {
-    AssembleInstruction(*i);
+  // Assemble all non-deferred blocks, followed by deferred ones.
+  for (int deferred = 0; deferred < 2; ++deferred) {
+    for (auto const block : code()->instruction_blocks()) {
+      if (block->IsDeferred() == (deferred == 0)) {
+        continue;
+      }
+      // Align loop headers on 16-byte boundaries.
+      if (block->IsLoopHeader()) masm()->Align(16);
+      // Bind a label for a block.
+      current_block_ = block->rpo_number();
+      if (FLAG_code_comments) {
+        // TODO(titzer): these code comments are a giant memory leak.
+        Vector<char> buffer = Vector<char>::New(32);
+        SNPrintF(buffer, "-- B%d start --", block->id().ToInt());
+        masm()->RecordComment(buffer.start());
+      }
+      masm()->bind(GetLabel(current_block_));
+      for (int i = block->code_start(); i < block->code_end(); ++i) {
+        AssembleInstruction(code()->InstructionAt(i));
+      }
+    }
+  }
+
+  // Assemble all out-of-line code.
+  if (ools_) {
+    masm()->RecordComment("-- Out of line code --");
+    for (OutOfLineCode* ool = ools_; ool; ool = ool->next()) {
+      masm()->bind(ool->entry());
+      ool->Generate();
+      masm()->jmp(ool->exit());
+    }
   }
 
   FinishCode(masm());
 
-  // Ensure there is space for lazy deopt.
+  // Ensure there is space for lazy deoptimization in the code.
   if (!info->IsStub()) {
     int target_offset = masm()->pc_offset() + Deoptimizer::patch_size();
     while (masm()->pc_offset() < target_offset) {
@@ -72,6 +109,11 @@
 
   PopulateDeoptimizationData(result);
 
+  // Ensure there is space for lazy deoptimization in the relocation info.
+  if (!info->IsStub()) {
+    Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(result);
+  }
+
   // Emit a code line info recording stop event.
   void* line_info = recorder->DetachJITHandlerData();
   LOG_CODE_EVENT(isolate(), CodeEndLinePosInfoRecordEvent(*result, line_info));
@@ -80,6 +122,12 @@
 }
 
 
+bool CodeGenerator::IsNextInAssemblyOrder(BasicBlock::RpoNumber block) const {
+  return code()->InstructionBlockAt(current_block_)->ao_number().IsNext(
+      code()->InstructionBlockAt(block)->ao_number());
+}
+
+
 void CodeGenerator::RecordSafepoint(PointerMap* pointers, Safepoint::Kind kind,
                                     int arguments,
                                     Safepoint::DeoptMode deopt_mode) {
@@ -100,18 +148,6 @@
 
 
 void CodeGenerator::AssembleInstruction(Instruction* instr) {
-  if (instr->IsBlockStart()) {
-    // Bind a label for a block start and handle parallel moves.
-    BlockStartInstruction* block_start = BlockStartInstruction::cast(instr);
-    current_block_ = block_start->block();
-    if (FLAG_code_comments) {
-      // TODO(titzer): these code comments are a giant memory leak.
-      Vector<char> buffer = Vector<char>::New(32);
-      SNPrintF(buffer, "-- B%d start --", block_start->block()->id());
-      masm()->RecordComment(buffer.start());
-    }
-    masm()->bind(block_start->label());
-  }
   if (instr->IsGapMoves()) {
     // Handle parallel moves associated with the gap instruction.
     AssembleGap(GapInstruction::cast(instr));
@@ -121,18 +157,39 @@
     // Assemble architecture-specific code for the instruction.
     AssembleArchInstruction(instr);
 
-    // Assemble branches or boolean materializations after this instruction.
     FlagsMode mode = FlagsModeField::decode(instr->opcode());
     FlagsCondition condition = FlagsConditionField::decode(instr->opcode());
-    switch (mode) {
-      case kFlags_none:
+    if (mode == kFlags_branch) {
+      // Assemble a branch after this instruction.
+      InstructionOperandConverter i(this, instr);
+      BasicBlock::RpoNumber true_rpo =
+          i.InputRpo(static_cast<int>(instr->InputCount()) - 2);
+      BasicBlock::RpoNumber false_rpo =
+          i.InputRpo(static_cast<int>(instr->InputCount()) - 1);
+
+      if (true_rpo == false_rpo) {
+        // redundant branch.
+        if (!IsNextInAssemblyOrder(true_rpo)) {
+          AssembleArchJump(true_rpo);
+        }
         return;
-      case kFlags_set:
-        return AssembleArchBoolean(instr, condition);
-      case kFlags_branch:
-        return AssembleArchBranch(instr, condition);
+      }
+      if (IsNextInAssemblyOrder(true_rpo)) {
+        // true block is next, can fall through if condition negated.
+        std::swap(true_rpo, false_rpo);
+        condition = NegateFlagsCondition(condition);
+      }
+      BranchInfo branch;
+      branch.condition = condition;
+      branch.true_label = GetLabel(true_rpo);
+      branch.false_label = GetLabel(false_rpo);
+      branch.fallthru = IsNextInAssemblyOrder(false_rpo);
+      // Assemble architecture-specific branch.
+      AssembleArchBranch(instr, &branch);
+    } else if (mode == kFlags_set) {
+      // Assemble a boolean materialization after this instruction.
+      AssembleArchBoolean(instr, condition);
     }
-    UNREACHABLE();
   }
 }
 
@@ -147,7 +204,7 @@
     masm()->positions_recorder()->WriteRecordedPositions();
     if (FLAG_code_comments) {
       Vector<char> buffer = Vector<char>::New(256);
-      CompilationInfo* info = linkage()->info();
+      CompilationInfo* info = this->info();
       int ln = Script::GetLineNumber(info->script(), code_pos);
       int cn = Script::GetColumnNumber(info->script(), code_pos);
       if (info->script()->name()->IsString()) {
@@ -177,7 +234,7 @@
 
 
 void CodeGenerator::PopulateDeoptimizationData(Handle<Code> code_object) {
-  CompilationInfo* info = linkage()->info();
+  CompilationInfo* info = this->info();
   int deopt_count = static_cast<int>(deoptimization_states_.size());
   if (deopt_count == 0) return;
   Handle<DeoptimizationInputData> data =
@@ -260,17 +317,17 @@
     // because it is only used to get locals and arguments (by the debugger and
     // f.arguments), and those are the same in the pre-call and post-call
     // states.
-    if (descriptor->state_combine() != kIgnoreOutput) {
-      deopt_state_id =
-          BuildTranslation(instr, -1, frame_state_offset, kIgnoreOutput);
+    if (!descriptor->state_combine().IsOutputIgnored()) {
+      deopt_state_id = BuildTranslation(instr, -1, frame_state_offset,
+                                        OutputFrameStateCombine::Ignore());
     }
 #if DEBUG
     // Make sure all the values live in stack slots or they are immediates.
     // (The values should not live in register because registers are clobbered
     // by calls.)
-    for (size_t i = 0; i < descriptor->size(); i++) {
+    for (size_t i = 0; i < descriptor->GetSize(); i++) {
       InstructionOperand* op = instr->InputAt(frame_state_offset + 1 + i);
-      CHECK(op->IsStackSlot() || op->IsImmediate());
+      CHECK(op->IsStackSlot() || op->IsDoubleStackSlot() || op->IsImmediate());
     }
 #endif
     safepoints()->RecordLazyDeoptimizationIndex(deopt_state_id);
@@ -296,6 +353,44 @@
   return code()->GetFrameStateDescriptor(state_id);
 }
 
+struct OperandAndType {
+  OperandAndType(InstructionOperand* operand, MachineType type)
+      : operand_(operand), type_(type) {}
+
+  InstructionOperand* operand_;
+  MachineType type_;
+};
+
+static OperandAndType TypedOperandForFrameState(
+    FrameStateDescriptor* descriptor, Instruction* instr,
+    size_t frame_state_offset, size_t index, OutputFrameStateCombine combine) {
+  DCHECK(index < descriptor->GetSize(combine));
+  switch (combine.kind()) {
+    case OutputFrameStateCombine::kPushOutput: {
+      DCHECK(combine.GetPushCount() <= instr->OutputCount());
+      size_t size_without_output =
+          descriptor->GetSize(OutputFrameStateCombine::Ignore());
+      // If the index is past the existing stack items, return the output.
+      if (index >= size_without_output) {
+        return OperandAndType(instr->OutputAt(index - size_without_output),
+                              kMachAnyTagged);
+      }
+      break;
+    }
+    case OutputFrameStateCombine::kPokeAt:
+      size_t index_from_top =
+          descriptor->GetSize(combine) - 1 - combine.GetOffsetToPokeAt();
+      if (index >= index_from_top &&
+          index < index_from_top + instr->OutputCount()) {
+        return OperandAndType(instr->OutputAt(index - index_from_top),
+                              kMachAnyTagged);
+      }
+      break;
+  }
+  return OperandAndType(instr->InputAt(frame_state_offset + index),
+                        descriptor->GetType(index));
+}
+
 
 void CodeGenerator::BuildTranslationForFrameStateDescriptor(
     FrameStateDescriptor* descriptor, Instruction* instr,
@@ -305,7 +400,7 @@
   if (descriptor->outer_state() != NULL) {
     BuildTranslationForFrameStateDescriptor(descriptor->outer_state(), instr,
                                             translation, frame_state_offset,
-                                            kIgnoreOutput);
+                                            OutputFrameStateCombine::Ignore());
   }
 
   int id = Translation::kSelfLiteralId;
@@ -318,7 +413,8 @@
     case JS_FRAME:
       translation->BeginJSFrame(
           descriptor->bailout_id(), id,
-          static_cast<unsigned int>(descriptor->GetHeight(state_combine)));
+          static_cast<unsigned int>(descriptor->GetSize(state_combine) -
+                                    descriptor->parameters_count()));
       break;
     case ARGUMENTS_ADAPTOR:
       translation->BeginArgumentsAdaptorFrame(
@@ -327,19 +423,10 @@
   }
 
   frame_state_offset += descriptor->outer_state()->GetTotalSize();
-  for (size_t i = 0; i < descriptor->size(); i++) {
-    AddTranslationForOperand(
-        translation, instr,
-        instr->InputAt(static_cast<int>(frame_state_offset + i)));
-  }
-
-  switch (state_combine) {
-    case kPushOutput:
-      DCHECK(instr->OutputCount() == 1);
-      AddTranslationForOperand(translation, instr, instr->OutputAt(0));
-      break;
-    case kIgnoreOutput:
-      break;
+  for (size_t i = 0; i < descriptor->GetSize(state_combine); i++) {
+    OperandAndType op = TypedOperandForFrameState(
+        descriptor, instr, frame_state_offset, i, state_combine);
+    AddTranslationForOperand(translation, instr, op.operand_, op.type_);
   }
 }
 
@@ -368,15 +455,38 @@
 
 void CodeGenerator::AddTranslationForOperand(Translation* translation,
                                              Instruction* instr,
-                                             InstructionOperand* op) {
+                                             InstructionOperand* op,
+                                             MachineType type) {
   if (op->IsStackSlot()) {
-    translation->StoreStackSlot(op->index());
+    if (type == kMachBool || type == kMachInt32 || type == kMachInt8 ||
+        type == kMachInt16) {
+      translation->StoreInt32StackSlot(op->index());
+    } else if (type == kMachUint32 || type == kMachUint16 ||
+               type == kMachUint8) {
+      translation->StoreUint32StackSlot(op->index());
+    } else if ((type & kRepMask) == kRepTagged) {
+      translation->StoreStackSlot(op->index());
+    } else {
+      CHECK(false);
+    }
   } else if (op->IsDoubleStackSlot()) {
+    DCHECK((type & (kRepFloat32 | kRepFloat64)) != 0);
     translation->StoreDoubleStackSlot(op->index());
   } else if (op->IsRegister()) {
     InstructionOperandConverter converter(this, instr);
-    translation->StoreRegister(converter.ToRegister(op));
+    if (type == kMachBool || type == kMachInt32 || type == kMachInt8 ||
+        type == kMachInt16) {
+      translation->StoreInt32Register(converter.ToRegister(op));
+    } else if (type == kMachUint32 || type == kMachUint16 ||
+               type == kMachUint8) {
+      translation->StoreUint32Register(converter.ToRegister(op));
+    } else if ((type & kRepMask) == kRepTagged) {
+      translation->StoreRegister(converter.ToRegister(op));
+    } else {
+      CHECK(false);
+    }
   } else if (op->IsDoubleRegister()) {
+    DCHECK((type & (kRepFloat32 | kRepFloat64)) != 0);
     InstructionOperandConverter converter(this, instr);
     translation->StoreDoubleRegister(converter.ToDoubleRegister(op));
   } else if (op->IsImmediate()) {
@@ -385,22 +495,25 @@
     Handle<Object> constant_object;
     switch (constant.type()) {
       case Constant::kInt32:
+        DCHECK(type == kMachInt32 || type == kMachUint32);
         constant_object =
             isolate()->factory()->NewNumberFromInt(constant.ToInt32());
         break;
       case Constant::kFloat64:
+        DCHECK(type == kMachFloat64 || type == kMachAnyTagged);
         constant_object = isolate()->factory()->NewNumber(constant.ToFloat64());
         break;
       case Constant::kHeapObject:
+        DCHECK((type & kRepMask) == kRepTagged);
         constant_object = constant.ToHeapObject();
         break;
       default:
-        UNREACHABLE();
+        CHECK(false);
     }
     int literal_id = DefineDeoptimizationLiteral(constant_object);
     translation->StoreLiteral(literal_id);
   } else {
-    UNREACHABLE();
+    CHECK(false);
   }
 }
 
@@ -417,7 +530,7 @@
 
 
 void CodeGenerator::AssembleArchBranch(Instruction* instr,
-                                       FlagsCondition condition) {
+                                       BranchInfo* branch) {
   UNIMPLEMENTED();
 }
 
@@ -428,6 +541,11 @@
 }
 
 
+void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+  UNIMPLEMENTED();
+}
+
+
 void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
   UNIMPLEMENTED();
 }
@@ -455,6 +573,15 @@
 
 #endif  // !V8_TURBOFAN_BACKEND
 
+
+OutOfLineCode::OutOfLineCode(CodeGenerator* gen)
+    : masm_(gen->masm()), next_(gen->ools_) {
+  gen->ools_ = this;
+}
+
+
+OutOfLineCode::~OutOfLineCode() {}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
diff --git a/src/compiler/code-generator.h b/src/compiler/code-generator.h
index ddc2f9a..747bad2 100644
--- a/src/compiler/code-generator.h
+++ b/src/compiler/code-generator.h
@@ -5,8 +5,6 @@
 #ifndef V8_COMPILER_CODE_GENERATOR_H_
 #define V8_COMPILER_CODE_GENERATOR_H_
 
-#include <deque>
-
 #include "src/compiler/gap-resolver.h"
 #include "src/compiler/instruction.h"
 #include "src/deoptimizer.h"
@@ -17,33 +15,44 @@
 namespace internal {
 namespace compiler {
 
+// Forward declarations.
+class Linkage;
+class OutOfLineCode;
+
+struct BranchInfo {
+  FlagsCondition condition;
+  Label* true_label;
+  Label* false_label;
+  bool fallthru;
+};
+
+
 // Generates native code for a sequence of instructions.
 class CodeGenerator FINAL : public GapResolver::Assembler {
  public:
-  explicit CodeGenerator(InstructionSequence* code);
+  explicit CodeGenerator(Frame* frame, Linkage* linkage,
+                         InstructionSequence* code, CompilationInfo* info);
 
   // Generate native code.
   Handle<Code> GenerateCode();
 
   InstructionSequence* code() const { return code_; }
-  Frame* frame() const { return code()->frame(); }
-  Graph* graph() const { return code()->graph(); }
+  Frame* frame() const { return frame_; }
   Isolate* isolate() const { return zone()->isolate(); }
-  Linkage* linkage() const { return code()->linkage(); }
-  Schedule* schedule() const { return code()->schedule(); }
+  Linkage* linkage() const { return linkage_; }
+
+  Label* GetLabel(BasicBlock::RpoNumber rpo) { return &labels_[rpo.ToSize()]; }
 
  private:
   MacroAssembler* masm() { return &masm_; }
   GapResolver* resolver() { return &resolver_; }
   SafepointTableBuilder* safepoints() { return &safepoints_; }
   Zone* zone() const { return code()->zone(); }
+  CompilationInfo* info() const { return info_; }
 
   // Checks if {block} will appear directly after {current_block_} when
   // assembling code, in which case, a fall-through can be used.
-  bool IsNextInAssemblyOrder(const BasicBlock* block) const {
-    return block->rpo_number_ == (current_block_->rpo_number_ + 1) &&
-           block->deferred_ == current_block_->deferred_;
-  }
+  bool IsNextInAssemblyOrder(BasicBlock::RpoNumber block) const;
 
   // Record a safepoint with the given pointer map.
   void RecordSafepoint(PointerMap* pointers, Safepoint::Kind kind,
@@ -59,7 +68,8 @@
   // ===========================================================================
 
   void AssembleArchInstruction(Instruction* instr);
-  void AssembleArchBranch(Instruction* instr, FlagsCondition condition);
+  void AssembleArchJump(BasicBlock::RpoNumber target);
+  void AssembleArchBranch(Instruction* instr, BranchInfo* branch);
   void AssembleArchBoolean(Instruction* instr, FlagsCondition condition);
 
   void AssembleDeoptimizerCall(int deoptimization_id);
@@ -76,10 +86,10 @@
   // ===========================================================================
 
   // Interface used by the gap resolver to emit moves and swaps.
-  virtual void AssembleMove(InstructionOperand* source,
-                            InstructionOperand* destination) OVERRIDE;
-  virtual void AssembleSwap(InstructionOperand* source,
-                            InstructionOperand* destination) OVERRIDE;
+  void AssembleMove(InstructionOperand* source,
+                    InstructionOperand* destination) FINAL;
+  void AssembleSwap(InstructionOperand* source,
+                    InstructionOperand* destination) FINAL;
 
   // ===========================================================================
   // Deoptimization table construction
@@ -96,7 +106,7 @@
       Translation* translation, size_t frame_state_offset,
       OutputFrameStateCombine state_combine);
   void AddTranslationForOperand(Translation* translation, Instruction* instr,
-                                InstructionOperand* op);
+                                InstructionOperand* op, MachineType type);
   void AddNopForSmiCodeInlining();
   void EnsureSpaceForLazyDeopt();
   void MarkLazyDeoptSite();
@@ -119,8 +129,14 @@
     int pc_offset_;
   };
 
-  InstructionSequence* code_;
-  BasicBlock* current_block_;
+  friend class OutOfLineCode;
+
+  Frame* const frame_;
+  Linkage* const linkage_;
+  InstructionSequence* const code_;
+  CompilationInfo* const info_;
+  Label* const labels_;
+  BasicBlock::RpoNumber current_block_;
   SourcePosition current_source_position_;
   MacroAssembler masm_;
   GapResolver resolver_;
@@ -129,6 +145,7 @@
   ZoneDeque<Handle<Object> > deoptimization_literals_;
   TranslationBuffer translations_;
   int last_lazy_deopt_pc_;
+  OutOfLineCode* ools_;
 };
 
 }  // namespace compiler
diff --git a/src/compiler/common-node-cache.cc b/src/compiler/common-node-cache.cc
new file mode 100644
index 0000000..ee1fa0f
--- /dev/null
+++ b/src/compiler/common-node-cache.cc
@@ -0,0 +1,29 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/common-node-cache.h"
+
+#include "src/assembler.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+Node** CommonNodeCache::FindExternalConstant(ExternalReference value) {
+  return external_constants_.Find(zone(), bit_cast<intptr_t>(value.address()));
+}
+
+
+void CommonNodeCache::GetCachedNodes(ZoneVector<Node*>* nodes) {
+  int32_constants_.GetCachedNodes(nodes);
+  int64_constants_.GetCachedNodes(nodes);
+  float32_constants_.GetCachedNodes(nodes);
+  float64_constants_.GetCachedNodes(nodes);
+  external_constants_.GetCachedNodes(nodes);
+  number_constants_.GetCachedNodes(nodes);
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/common-node-cache.h b/src/compiler/common-node-cache.h
index 1ed2b04..7ec70ae 100644
--- a/src/compiler/common-node-cache.h
+++ b/src/compiler/common-node-cache.h
@@ -5,47 +5,67 @@
 #ifndef V8_COMPILER_COMMON_NODE_CACHE_H_
 #define V8_COMPILER_COMMON_NODE_CACHE_H_
 
-#include "src/assembler.h"
 #include "src/compiler/node-cache.h"
 
 namespace v8 {
 namespace internal {
+
+// Forward declarations.
+class ExternalReference;
+
+
 namespace compiler {
 
 // Bundles various caches for common nodes.
-class CommonNodeCache FINAL : public ZoneObject {
+class CommonNodeCache FINAL {
  public:
   explicit CommonNodeCache(Zone* zone) : zone_(zone) {}
+  ~CommonNodeCache() {}
 
   Node** FindInt32Constant(int32_t value) {
-    return int32_constants_.Find(zone_, value);
+    return int32_constants_.Find(zone(), value);
+  }
+
+  Node** FindInt64Constant(int64_t value) {
+    return int64_constants_.Find(zone(), value);
+  }
+
+  Node** FindFloat32Constant(float value) {
+    // We canonicalize float constants at the bit representation level.
+    return float32_constants_.Find(zone(), bit_cast<int32_t>(value));
   }
 
   Node** FindFloat64Constant(double value) {
     // We canonicalize double constants at the bit representation level.
-    return float64_constants_.Find(zone_, bit_cast<int64_t>(value));
+    return float64_constants_.Find(zone(), bit_cast<int64_t>(value));
   }
 
-  Node** FindExternalConstant(ExternalReference reference) {
-    return external_constants_.Find(zone_, reference.address());
-  }
+  Node** FindExternalConstant(ExternalReference value);
 
   Node** FindNumberConstant(double value) {
     // We canonicalize double constants at the bit representation level.
-    return number_constants_.Find(zone_, bit_cast<int64_t>(value));
+    return number_constants_.Find(zone(), bit_cast<int64_t>(value));
   }
 
+  // Return all nodes from the cache.
+  void GetCachedNodes(ZoneVector<Node*>* nodes);
+
   Zone* zone() const { return zone_; }
 
  private:
   Int32NodeCache int32_constants_;
+  Int64NodeCache int64_constants_;
+  Int32NodeCache float32_constants_;
   Int64NodeCache float64_constants_;
-  PtrNodeCache external_constants_;
+  IntPtrNodeCache external_constants_;
   Int64NodeCache number_constants_;
   Zone* zone_;
+
+  DISALLOW_COPY_AND_ASSIGN(CommonNodeCache);
 };
-}
-}
-}  // namespace v8::internal::compiler
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_COMMON_NODE_CACHE_H_
diff --git a/src/compiler/common-operator-reducer.cc b/src/compiler/common-operator-reducer.cc
new file mode 100644
index 0000000..cf597ea
--- /dev/null
+++ b/src/compiler/common-operator-reducer.cc
@@ -0,0 +1,41 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/common-operator-reducer.h"
+
+#include "src/compiler/common-operator.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+Reduction CommonOperatorReducer::Reduce(Node* node) {
+  switch (node->opcode()) {
+    case IrOpcode::kEffectPhi:
+    case IrOpcode::kPhi: {
+      int const input_count = node->InputCount();
+      if (input_count > 1) {
+        Node* const replacement = node->InputAt(0);
+        for (int i = 1; i < input_count - 1; ++i) {
+          if (node->InputAt(i) != replacement) return NoChange();
+        }
+        return Replace(replacement);
+      }
+      break;
+    }
+    case IrOpcode::kSelect: {
+      if (node->InputAt(1) == node->InputAt(2)) {
+        return Replace(node->InputAt(1));
+      }
+      break;
+    }
+    default:
+      break;
+  }
+  return NoChange();
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/common-operator-reducer.h b/src/compiler/common-operator-reducer.h
new file mode 100644
index 0000000..10543db
--- /dev/null
+++ b/src/compiler/common-operator-reducer.h
@@ -0,0 +1,27 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_COMMON_OPERATOR_REDUCER_H_
+#define V8_COMPILER_COMMON_OPERATOR_REDUCER_H_
+
+#include "src/compiler/graph-reducer.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// Performs strength reduction on nodes that have common operators.
+class CommonOperatorReducer FINAL : public Reducer {
+ public:
+  CommonOperatorReducer() {}
+  ~CommonOperatorReducer() FINAL {}
+
+  Reduction Reduce(Node* node) FINAL;
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_COMMON_OPERATOR_REDUCER_H_
diff --git a/src/compiler/common-operator-unittest.cc b/src/compiler/common-operator-unittest.cc
deleted file mode 100644
index 5001770..0000000
--- a/src/compiler/common-operator-unittest.cc
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/common-operator.h"
-
-#include <limits>
-
-#include "src/compiler/operator-properties-inl.h"
-#include "src/test/test-utils.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-
-// -----------------------------------------------------------------------------
-// Shared operators.
-
-
-namespace {
-
-struct SharedOperator {
-  const Operator* (CommonOperatorBuilder::*constructor)();
-  IrOpcode::Value opcode;
-  Operator::Properties properties;
-  int value_input_count;
-  int effect_input_count;
-  int control_input_count;
-  int effect_output_count;
-  int control_output_count;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const SharedOperator& fop) {
-  return os << IrOpcode::Mnemonic(fop.opcode);
-}
-
-
-const SharedOperator kSharedOperators[] = {
-#define SHARED(Name, properties, value_input_count, effect_input_count,        \
-               control_input_count, effect_output_count, control_output_count) \
-  {                                                                            \
-    &CommonOperatorBuilder::Name, IrOpcode::k##Name, properties,               \
-        value_input_count, effect_input_count, control_input_count,            \
-        effect_output_count, control_output_count                              \
-  }
-    SHARED(Dead, Operator::kFoldable, 0, 0, 0, 0, 1),
-    SHARED(End, Operator::kFoldable, 0, 0, 1, 0, 0),
-    SHARED(Branch, Operator::kFoldable, 1, 0, 1, 0, 2),
-    SHARED(IfTrue, Operator::kFoldable, 0, 0, 1, 0, 1),
-    SHARED(IfFalse, Operator::kFoldable, 0, 0, 1, 0, 1),
-    SHARED(Throw, Operator::kFoldable, 1, 0, 1, 0, 1),
-    SHARED(Return, Operator::kNoProperties, 1, 1, 1, 1, 1),
-    SHARED(ControlEffect, Operator::kPure, 0, 0, 1, 1, 0)
-#undef SHARED
-};
-
-
-class CommonSharedOperatorTest
-    : public TestWithZone,
-      public ::testing::WithParamInterface<SharedOperator> {};
-
-}  // namespace
-
-
-TEST_P(CommonSharedOperatorTest, InstancesAreGloballyShared) {
-  const SharedOperator& sop = GetParam();
-  CommonOperatorBuilder common1(zone());
-  CommonOperatorBuilder common2(zone());
-  EXPECT_EQ((common1.*sop.constructor)(), (common2.*sop.constructor)());
-}
-
-
-TEST_P(CommonSharedOperatorTest, NumberOfInputsAndOutputs) {
-  CommonOperatorBuilder common(zone());
-  const SharedOperator& sop = GetParam();
-  const Operator* op = (common.*sop.constructor)();
-
-  EXPECT_EQ(sop.value_input_count, OperatorProperties::GetValueInputCount(op));
-  EXPECT_EQ(sop.effect_input_count,
-            OperatorProperties::GetEffectInputCount(op));
-  EXPECT_EQ(sop.control_input_count,
-            OperatorProperties::GetControlInputCount(op));
-  EXPECT_EQ(
-      sop.value_input_count + sop.effect_input_count + sop.control_input_count,
-      OperatorProperties::GetTotalInputCount(op));
-
-  EXPECT_EQ(0, OperatorProperties::GetValueOutputCount(op));
-  EXPECT_EQ(sop.effect_output_count,
-            OperatorProperties::GetEffectOutputCount(op));
-  EXPECT_EQ(sop.control_output_count,
-            OperatorProperties::GetControlOutputCount(op));
-}
-
-
-TEST_P(CommonSharedOperatorTest, OpcodeIsCorrect) {
-  CommonOperatorBuilder common(zone());
-  const SharedOperator& sop = GetParam();
-  const Operator* op = (common.*sop.constructor)();
-  EXPECT_EQ(sop.opcode, op->opcode());
-}
-
-
-TEST_P(CommonSharedOperatorTest, Properties) {
-  CommonOperatorBuilder common(zone());
-  const SharedOperator& sop = GetParam();
-  const Operator* op = (common.*sop.constructor)();
-  EXPECT_EQ(sop.properties, op->properties());
-}
-
-
-INSTANTIATE_TEST_CASE_P(CommonOperatorTest, CommonSharedOperatorTest,
-                        ::testing::ValuesIn(kSharedOperators));
-
-
-// -----------------------------------------------------------------------------
-// Other operators.
-
-
-namespace {
-
-class CommonOperatorTest : public TestWithZone {
- public:
-  CommonOperatorTest() : common_(zone()) {}
-  virtual ~CommonOperatorTest() {}
-
-  CommonOperatorBuilder* common() { return &common_; }
-
- private:
-  CommonOperatorBuilder common_;
-};
-
-
-const int kArguments[] = {1, 5, 6, 42, 100, 10000, kMaxInt};
-
-const float kFloat32Values[] = {
-    std::numeric_limits<float>::min(), -1.0f, -0.0f, 0.0f, 1.0f,
-    std::numeric_limits<float>::max()};
-
-}  // namespace
-
-
-TEST_F(CommonOperatorTest, Float32Constant) {
-  TRACED_FOREACH(float, value, kFloat32Values) {
-    const Operator* op = common()->Float32Constant(value);
-    EXPECT_FLOAT_EQ(value, OpParameter<float>(op));
-    EXPECT_EQ(0, OperatorProperties::GetValueInputCount(op));
-    EXPECT_EQ(0, OperatorProperties::GetTotalInputCount(op));
-    EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
-    EXPECT_EQ(0, OperatorProperties::GetEffectOutputCount(op));
-    EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
-  }
-}
-
-
-TEST_F(CommonOperatorTest, ValueEffect) {
-  TRACED_FOREACH(int, arguments, kArguments) {
-    const Operator* op = common()->ValueEffect(arguments);
-    EXPECT_EQ(arguments, OperatorProperties::GetValueInputCount(op));
-    EXPECT_EQ(arguments, OperatorProperties::GetTotalInputCount(op));
-    EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
-    EXPECT_EQ(1, OperatorProperties::GetEffectOutputCount(op));
-    EXPECT_EQ(0, OperatorProperties::GetValueOutputCount(op));
-  }
-}
-
-
-TEST_F(CommonOperatorTest, Finish) {
-  TRACED_FOREACH(int, arguments, kArguments) {
-    const Operator* op = common()->Finish(arguments);
-    EXPECT_EQ(1, OperatorProperties::GetValueInputCount(op));
-    EXPECT_EQ(arguments, OperatorProperties::GetEffectInputCount(op));
-    EXPECT_EQ(arguments + 1, OperatorProperties::GetTotalInputCount(op));
-    EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
-    EXPECT_EQ(0, OperatorProperties::GetEffectOutputCount(op));
-    EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
-  }
-}
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/common-operator.cc b/src/compiler/common-operator.cc
index 19792bd..a6cca45 100644
--- a/src/compiler/common-operator.cc
+++ b/src/compiler/common-operator.cc
@@ -7,6 +7,8 @@
 #include "src/assembler.h"
 #include "src/base/lazy-instance.h"
 #include "src/compiler/linkage.h"
+#include "src/compiler/opcodes.h"
+#include "src/compiler/operator.h"
 #include "src/unique.h"
 #include "src/zone.h"
 
@@ -14,209 +16,430 @@
 namespace internal {
 namespace compiler {
 
-namespace {
-
-// TODO(turbofan): Use size_t instead of int here.
-class ControlOperator : public Operator1<int> {
- public:
-  ControlOperator(IrOpcode::Value opcode, Properties properties, int inputs,
-                  int outputs, int controls, const char* mnemonic)
-      : Operator1<int>(opcode, properties, inputs, outputs, mnemonic,
-                       controls) {}
-
-  virtual OStream& PrintParameter(OStream& os) const FINAL { return os; }
-};
-
-}  // namespace
-
-
-// Specialization for static parameters of type {ExternalReference}.
-template <>
-struct StaticParameterTraits<ExternalReference> {
-  static OStream& PrintTo(OStream& os, ExternalReference reference) {
-    os << reference.address();
-    // TODO(bmeurer): Move to operator<<(os, ExternalReference)
-    const Runtime::Function* function =
-        Runtime::FunctionForEntry(reference.address());
-    if (function) {
-      os << " <" << function->name << ".entry>";
-    }
-    return os;
+std::ostream& operator<<(std::ostream& os, BranchHint hint) {
+  switch (hint) {
+    case BranchHint::kNone:
+      return os << "None";
+    case BranchHint::kTrue:
+      return os << "True";
+    case BranchHint::kFalse:
+      return os << "False";
   }
-  static int HashCode(ExternalReference reference) {
-    return bit_cast<int>(static_cast<uint32_t>(
-        reinterpret_cast<uintptr_t>(reference.address())));
+  UNREACHABLE();
+  return os;
+}
+
+
+BranchHint BranchHintOf(const Operator* const op) {
+  DCHECK_EQ(IrOpcode::kBranch, op->opcode());
+  return OpParameter<BranchHint>(op);
+}
+
+
+bool operator==(SelectParameters const& lhs, SelectParameters const& rhs) {
+  return lhs.type() == rhs.type() && lhs.hint() == rhs.hint();
+}
+
+
+bool operator!=(SelectParameters const& lhs, SelectParameters const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(SelectParameters const& p) {
+  return base::hash_combine(p.type(), p.hint());
+}
+
+
+std::ostream& operator<<(std::ostream& os, SelectParameters const& p) {
+  return os << p.type() << "|" << p.hint();
+}
+
+
+SelectParameters const& SelectParametersOf(const Operator* const op) {
+  DCHECK_EQ(IrOpcode::kSelect, op->opcode());
+  return OpParameter<SelectParameters>(op);
+}
+
+
+size_t hash_value(OutputFrameStateCombine const& sc) {
+  return base::hash_combine(sc.kind_, sc.parameter_);
+}
+
+
+std::ostream& operator<<(std::ostream& os, OutputFrameStateCombine const& sc) {
+  switch (sc.kind_) {
+    case OutputFrameStateCombine::kPushOutput:
+      if (sc.parameter_ == 0) return os << "Ignore";
+      return os << "Push(" << sc.parameter_ << ")";
+    case OutputFrameStateCombine::kPokeAt:
+      return os << "PokeAt(" << sc.parameter_ << ")";
   }
-  static bool Equals(ExternalReference lhs, ExternalReference rhs) {
-    return lhs == rhs;
-  }
-};
+  UNREACHABLE();
+  return os;
+}
 
 
-#define SHARED_OP_LIST(V)               \
-  V(Dead, Operator::kFoldable, 0, 0)    \
-  V(End, Operator::kFoldable, 0, 1)     \
-  V(Branch, Operator::kFoldable, 1, 1)  \
-  V(IfTrue, Operator::kFoldable, 0, 1)  \
-  V(IfFalse, Operator::kFoldable, 0, 1) \
-  V(Throw, Operator::kFoldable, 1, 1)   \
-  V(Return, Operator::kNoProperties, 1, 1)
+bool operator==(FrameStateCallInfo const& lhs, FrameStateCallInfo const& rhs) {
+  return lhs.type() == rhs.type() && lhs.bailout_id() == rhs.bailout_id() &&
+         lhs.state_combine() == rhs.state_combine();
+}
 
 
-struct CommonOperatorBuilderImpl FINAL {
-#define SHARED(Name, properties, value_input_count, control_input_count)       \
-  struct Name##Operator FINAL : public ControlOperator {                       \
-    Name##Operator()                                                           \
-        : ControlOperator(IrOpcode::k##Name, properties, value_input_count, 0, \
-                          control_input_count, #Name) {}                       \
-  };                                                                           \
+bool operator!=(FrameStateCallInfo const& lhs, FrameStateCallInfo const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(FrameStateCallInfo const& info) {
+  return base::hash_combine(info.type(), info.bailout_id(),
+                            info.state_combine());
+}
+
+
+std::ostream& operator<<(std::ostream& os, FrameStateCallInfo const& info) {
+  return os << info.type() << ", " << info.bailout_id() << ", "
+            << info.state_combine();
+}
+
+
+#define CACHED_OP_LIST(V)                     \
+  V(Dead, Operator::kFoldable, 0, 0, 0, 1)    \
+  V(End, Operator::kFoldable, 0, 0, 1, 0)     \
+  V(IfTrue, Operator::kFoldable, 0, 0, 1, 1)  \
+  V(IfFalse, Operator::kFoldable, 0, 0, 1, 1) \
+  V(Throw, Operator::kFoldable, 1, 1, 1, 1)   \
+  V(Return, Operator::kNoProperties, 1, 1, 1, 1)
+
+
+#define CACHED_LOOP_LIST(V) \
+  V(1)                      \
+  V(2)
+
+
+#define CACHED_MERGE_LIST(V) \
+  V(1)                       \
+  V(2)                       \
+  V(3)                       \
+  V(4)                       \
+  V(5)                       \
+  V(6)                       \
+  V(7)                       \
+  V(8)
+
+
+#define CACHED_PARAMETER_LIST(V) \
+  V(0)                           \
+  V(1)                           \
+  V(2)                           \
+  V(3)                           \
+  V(4)                           \
+  V(5)                           \
+  V(6)
+
+
+struct CommonOperatorGlobalCache FINAL {
+#define CACHED(Name, properties, value_input_count, effect_input_count,     \
+               control_input_count, control_output_count)                   \
+  struct Name##Operator FINAL : public Operator {                           \
+    Name##Operator()                                                        \
+        : Operator(IrOpcode::k##Name, properties, #Name, value_input_count, \
+                   effect_input_count, control_input_count, 0, 0,           \
+                   control_output_count) {}                                 \
+  };                                                                        \
   Name##Operator k##Name##Operator;
-  SHARED_OP_LIST(SHARED)
-#undef SHARED
+  CACHED_OP_LIST(CACHED)
+#undef CACHED
 
-  struct ControlEffectOperator FINAL : public SimpleOperator {
-    ControlEffectOperator()
-        : SimpleOperator(IrOpcode::kControlEffect, Operator::kPure, 0, 0,
-                         "ControlEffect") {}
+  template <BranchHint kBranchHint>
+  struct BranchOperator FINAL : public Operator1<BranchHint> {
+    BranchOperator()
+        : Operator1<BranchHint>(                       // --
+              IrOpcode::kBranch, Operator::kFoldable,  // opcode
+              "Branch",                                // name
+              1, 0, 1, 0, 0, 2,                        // counts
+              kBranchHint) {}                          // parameter
   };
-  ControlEffectOperator kControlEffectOperator;
+  BranchOperator<BranchHint::kNone> kBranchNoneOperator;
+  BranchOperator<BranchHint::kTrue> kBranchTrueOperator;
+  BranchOperator<BranchHint::kFalse> kBranchFalseOperator;
+
+  template <size_t kInputCount>
+  struct LoopOperator FINAL : public Operator {
+    LoopOperator()
+        : Operator(                                  // --
+              IrOpcode::kLoop, Operator::kFoldable,  // opcode
+              "Loop",                                // name
+              0, 0, kInputCount, 0, 0, 1) {}         // counts
+  };
+#define CACHED_LOOP(input_count) \
+  LoopOperator<input_count> kLoop##input_count##Operator;
+  CACHED_LOOP_LIST(CACHED_LOOP)
+#undef CACHED_LOOP
+
+  template <size_t kInputCount>
+  struct MergeOperator FINAL : public Operator {
+    MergeOperator()
+        : Operator(                                   // --
+              IrOpcode::kMerge, Operator::kFoldable,  // opcode
+              "Merge",                                // name
+              0, 0, kInputCount, 0, 0, 1) {}          // counts
+  };
+#define CACHED_MERGE(input_count) \
+  MergeOperator<input_count> kMerge##input_count##Operator;
+  CACHED_MERGE_LIST(CACHED_MERGE)
+#undef CACHED_MERGE
+
+  template <int kIndex>
+  struct ParameterOperator FINAL : public Operator1<int> {
+    ParameterOperator()
+        : Operator1<int>(                             // --
+              IrOpcode::kParameter, Operator::kPure,  // opcode
+              "Parameter",                            // name
+              1, 0, 0, 1, 0, 0,                       // counts,
+              kIndex) {}                              // parameter
+  };
+#define CACHED_PARAMETER(index) \
+  ParameterOperator<index> kParameter##index##Operator;
+  CACHED_PARAMETER_LIST(CACHED_PARAMETER)
+#undef CACHED_PARAMETER
 };
 
 
-static base::LazyInstance<CommonOperatorBuilderImpl>::type kImpl =
+static base::LazyInstance<CommonOperatorGlobalCache>::type kCache =
     LAZY_INSTANCE_INITIALIZER;
 
 
 CommonOperatorBuilder::CommonOperatorBuilder(Zone* zone)
-    : impl_(kImpl.Get()), zone_(zone) {}
+    : cache_(kCache.Get()), zone_(zone) {}
 
 
-#define SHARED(Name, properties, value_input_count, control_input_count) \
-  const Operator* CommonOperatorBuilder::Name() {                        \
-    return &impl_.k##Name##Operator;                                     \
+#define CACHED(Name, properties, value_input_count, effect_input_count, \
+               control_input_count, control_output_count)               \
+  const Operator* CommonOperatorBuilder::Name() {                       \
+    return &cache_.k##Name##Operator;                                   \
   }
-SHARED_OP_LIST(SHARED)
-#undef SHARED
+CACHED_OP_LIST(CACHED)
+#undef CACHED
+
+
+const Operator* CommonOperatorBuilder::Branch(BranchHint hint) {
+  switch (hint) {
+    case BranchHint::kNone:
+      return &cache_.kBranchNoneOperator;
+    case BranchHint::kTrue:
+      return &cache_.kBranchTrueOperator;
+    case BranchHint::kFalse:
+      return &cache_.kBranchFalseOperator;
+  }
+  UNREACHABLE();
+  return nullptr;
+}
 
 
 const Operator* CommonOperatorBuilder::Start(int num_formal_parameters) {
   // Outputs are formal parameters, plus context, receiver, and JSFunction.
   const int value_output_count = num_formal_parameters + 3;
-  return new (zone()) ControlOperator(IrOpcode::kStart, Operator::kFoldable, 0,
-                                      value_output_count, 0, "Start");
+  return new (zone()) Operator(               // --
+      IrOpcode::kStart, Operator::kFoldable,  // opcode
+      "Start",                                // name
+      0, 0, 0, value_output_count, 1, 1);     // counts
 }
 
 
-const Operator* CommonOperatorBuilder::Merge(int controls) {
-  return new (zone()) ControlOperator(IrOpcode::kMerge, Operator::kFoldable, 0,
-                                      0, controls, "Merge");
+const Operator* CommonOperatorBuilder::Loop(int control_input_count) {
+  switch (control_input_count) {
+#define CACHED_LOOP(input_count) \
+  case input_count:              \
+    return &cache_.kLoop##input_count##Operator;
+    CACHED_LOOP_LIST(CACHED_LOOP)
+#undef CACHED_LOOP
+    default:
+      break;
+  }
+  // Uncached.
+  return new (zone()) Operator(              // --
+      IrOpcode::kLoop, Operator::kFoldable,  // opcode
+      "Loop",                                // name
+      0, 0, control_input_count, 0, 0, 1);   // counts
 }
 
 
-const Operator* CommonOperatorBuilder::Loop(int controls) {
-  return new (zone()) ControlOperator(IrOpcode::kLoop, Operator::kFoldable, 0,
-                                      0, controls, "Loop");
+const Operator* CommonOperatorBuilder::Merge(int control_input_count) {
+  switch (control_input_count) {
+#define CACHED_MERGE(input_count) \
+  case input_count:               \
+    return &cache_.kMerge##input_count##Operator;
+    CACHED_MERGE_LIST(CACHED_MERGE)
+#undef CACHED_MERGE
+    default:
+      break;
+  }
+  // Uncached.
+  return new (zone()) Operator(               // --
+      IrOpcode::kMerge, Operator::kFoldable,  // opcode
+      "Merge",                                // name
+      0, 0, control_input_count, 0, 0, 1);    // counts
+}
+
+
+const Operator* CommonOperatorBuilder::Terminate(int effects) {
+  return new (zone()) Operator(               // --
+      IrOpcode::kTerminate, Operator::kPure,  // opcode
+      "Terminate",                            // name
+      0, effects, 1, 0, 0, 1);                // counts
 }
 
 
 const Operator* CommonOperatorBuilder::Parameter(int index) {
-  return new (zone()) Operator1<int>(IrOpcode::kParameter, Operator::kPure, 1,
-                                     1, "Parameter", index);
+  switch (index) {
+#define CACHED_PARAMETER(index) \
+  case index:                   \
+    return &cache_.kParameter##index##Operator;
+    CACHED_PARAMETER_LIST(CACHED_PARAMETER)
+#undef CACHED_PARAMETER
+    default:
+      break;
+  }
+  // Uncached.
+  return new (zone()) Operator1<int>(         // --
+      IrOpcode::kParameter, Operator::kPure,  // opcode
+      "Parameter",                            // name
+      1, 0, 0, 1, 0, 0,                       // counts
+      index);                                 // parameter
 }
 
 
 const Operator* CommonOperatorBuilder::Int32Constant(int32_t value) {
-  return new (zone()) Operator1<int32_t>(
-      IrOpcode::kInt32Constant, Operator::kPure, 0, 1, "Int32Constant", value);
+  return new (zone()) Operator1<int32_t>(         // --
+      IrOpcode::kInt32Constant, Operator::kPure,  // opcode
+      "Int32Constant",                            // name
+      0, 0, 0, 1, 0, 0,                           // counts
+      value);                                     // parameter
 }
 
 
 const Operator* CommonOperatorBuilder::Int64Constant(int64_t value) {
-  return new (zone()) Operator1<int64_t>(
-      IrOpcode::kInt64Constant, Operator::kPure, 0, 1, "Int64Constant", value);
+  return new (zone()) Operator1<int64_t>(         // --
+      IrOpcode::kInt64Constant, Operator::kPure,  // opcode
+      "Int64Constant",                            // name
+      0, 0, 0, 1, 0, 0,                           // counts
+      value);                                     // parameter
 }
 
 
 const Operator* CommonOperatorBuilder::Float32Constant(volatile float value) {
   return new (zone())
-      Operator1<float>(IrOpcode::kFloat32Constant, Operator::kPure, 0, 1,
-                       "Float32Constant", value);
+      Operator1<float, base::bit_equal_to<float>, base::bit_hash<float>>(  // --
+          IrOpcode::kFloat32Constant, Operator::kPure,  // opcode
+          "Float32Constant",                            // name
+          0, 0, 0, 1, 0, 0,                             // counts
+          value);                                       // parameter
 }
 
 
 const Operator* CommonOperatorBuilder::Float64Constant(volatile double value) {
-  return new (zone())
-      Operator1<double>(IrOpcode::kFloat64Constant, Operator::kPure, 0, 1,
-                        "Float64Constant", value);
+  return new (zone()) Operator1<double, base::bit_equal_to<double>,
+                                base::bit_hash<double>>(  // --
+      IrOpcode::kFloat64Constant, Operator::kPure,        // opcode
+      "Float64Constant",                                  // name
+      0, 0, 0, 1, 0, 0,                                   // counts
+      value);                                             // parameter
 }
 
 
 const Operator* CommonOperatorBuilder::ExternalConstant(
     const ExternalReference& value) {
-  return new (zone())
-      Operator1<ExternalReference>(IrOpcode::kExternalConstant, Operator::kPure,
-                                   0, 1, "ExternalConstant", value);
+  return new (zone()) Operator1<ExternalReference>(  // --
+      IrOpcode::kExternalConstant, Operator::kPure,  // opcode
+      "ExternalConstant",                            // name
+      0, 0, 0, 1, 0, 0,                              // counts
+      value);                                        // parameter
 }
 
 
 const Operator* CommonOperatorBuilder::NumberConstant(volatile double value) {
-  return new (zone())
-      Operator1<double>(IrOpcode::kNumberConstant, Operator::kPure, 0, 1,
-                        "NumberConstant", value);
+  return new (zone()) Operator1<double, base::bit_equal_to<double>,
+                                base::bit_hash<double>>(  // --
+      IrOpcode::kNumberConstant, Operator::kPure,         // opcode
+      "NumberConstant",                                   // name
+      0, 0, 0, 1, 0, 0,                                   // counts
+      value);                                             // parameter
 }
 
 
 const Operator* CommonOperatorBuilder::HeapConstant(
-    const Unique<Object>& value) {
-  return new (zone()) Operator1<Unique<Object> >(
-      IrOpcode::kHeapConstant, Operator::kPure, 0, 1, "HeapConstant", value);
+    const Unique<HeapObject>& value) {
+  return new (zone()) Operator1<Unique<HeapObject>>(  // --
+      IrOpcode::kHeapConstant, Operator::kPure,       // opcode
+      "HeapConstant",                                 // name
+      0, 0, 0, 1, 0, 0,                               // counts
+      value);                                         // parameter
+}
+
+
+const Operator* CommonOperatorBuilder::Select(MachineType type,
+                                              BranchHint hint) {
+  return new (zone()) Operator1<SelectParameters>(  // --
+      IrOpcode::kSelect, Operator::kPure,           // opcode
+      "Select",                                     // name
+      3, 0, 0, 1, 0, 0,                             // counts
+      SelectParameters(type, hint));                // parameter
 }
 
 
 const Operator* CommonOperatorBuilder::Phi(MachineType type, int arguments) {
-  DCHECK(arguments > 0);  // Disallow empty phis.
-  return new (zone()) Operator1<MachineType>(IrOpcode::kPhi, Operator::kPure,
-                                             arguments, 1, "Phi", type);
+  DCHECK(arguments > 0);                       // Disallow empty phis.
+  return new (zone()) Operator1<MachineType>(  // --
+      IrOpcode::kPhi, Operator::kPure,         // opcode
+      "Phi",                                   // name
+      arguments, 0, 1, 1, 0, 0,                // counts
+      type);                                   // parameter
 }
 
 
 const Operator* CommonOperatorBuilder::EffectPhi(int arguments) {
-  DCHECK(arguments > 0);  // Disallow empty phis.
-  return new (zone()) Operator1<int>(IrOpcode::kEffectPhi, Operator::kPure, 0,
-                                     0, "EffectPhi", arguments);
-}
-
-
-const Operator* CommonOperatorBuilder::ControlEffect() {
-  return &impl_.kControlEffectOperator;
+  DCHECK(arguments > 0);                      // Disallow empty phis.
+  return new (zone()) Operator(               // --
+      IrOpcode::kEffectPhi, Operator::kPure,  // opcode
+      "EffectPhi",                            // name
+      0, arguments, 1, 0, 1, 0);              // counts
 }
 
 
 const Operator* CommonOperatorBuilder::ValueEffect(int arguments) {
-  DCHECK(arguments > 0);  // Disallow empty value effects.
-  return new (zone()) SimpleOperator(IrOpcode::kValueEffect, Operator::kPure,
-                                     arguments, 0, "ValueEffect");
+  DCHECK(arguments > 0);                        // Disallow empty value effects.
+  return new (zone()) Operator(                 // --
+      IrOpcode::kValueEffect, Operator::kPure,  // opcode
+      "ValueEffect",                            // name
+      arguments, 0, 0, 0, 1, 0);                // counts
 }
 
 
 const Operator* CommonOperatorBuilder::Finish(int arguments) {
-  DCHECK(arguments > 0);  // Disallow empty finishes.
-  return new (zone()) Operator1<int>(IrOpcode::kFinish, Operator::kPure, 1, 1,
-                                     "Finish", arguments);
+  DCHECK(arguments > 0);                   // Disallow empty finishes.
+  return new (zone()) Operator(            // --
+      IrOpcode::kFinish, Operator::kPure,  // opcode
+      "Finish",                            // name
+      1, arguments, 0, 1, 0, 0);           // counts
 }
 
 
 const Operator* CommonOperatorBuilder::StateValues(int arguments) {
-  return new (zone()) Operator1<int>(IrOpcode::kStateValues, Operator::kPure,
-                                     arguments, 1, "StateValues", arguments);
+  return new (zone()) Operator(                 // --
+      IrOpcode::kStateValues, Operator::kPure,  // opcode
+      "StateValues",                            // name
+      arguments, 0, 0, 1, 0, 0);                // counts
 }
 
 
 const Operator* CommonOperatorBuilder::FrameState(
     FrameStateType type, BailoutId bailout_id,
     OutputFrameStateCombine state_combine, MaybeHandle<JSFunction> jsfunction) {
-  return new (zone()) Operator1<FrameStateCallInfo>(
-      IrOpcode::kFrameState, Operator::kPure, 4, 1, "FrameState",
+  return new (zone()) Operator1<FrameStateCallInfo>(  // --
+      IrOpcode::kFrameState, Operator::kPure,         // opcode
+      "FrameState",                                   // name
+      4, 0, 0, 1, 0, 0,                               // counts
       FrameStateCallInfo(type, bailout_id, state_combine, jsfunction));
 }
 
@@ -224,18 +447,17 @@
 const Operator* CommonOperatorBuilder::Call(const CallDescriptor* descriptor) {
   class CallOperator FINAL : public Operator1<const CallDescriptor*> {
    public:
-    // TODO(titzer): Operator still uses int, whereas CallDescriptor uses
-    // size_t.
     CallOperator(const CallDescriptor* descriptor, const char* mnemonic)
         : Operator1<const CallDescriptor*>(
-              IrOpcode::kCall, descriptor->properties(),
-              static_cast<int>(descriptor->InputCount() +
-                               descriptor->FrameStateCount()),
-              static_cast<int>(descriptor->ReturnCount()), mnemonic,
-              descriptor) {}
+              IrOpcode::kCall, descriptor->properties(), mnemonic,
+              descriptor->InputCount() + descriptor->FrameStateCount(),
+              Operator::ZeroIfPure(descriptor->properties()),
+              Operator::ZeroIfPure(descriptor->properties()),
+              descriptor->ReturnCount(),
+              Operator::ZeroIfPure(descriptor->properties()), 0, descriptor) {}
 
-    virtual OStream& PrintParameter(OStream& os) const OVERRIDE {
-      return os << "[" << *parameter() << "]";
+    void PrintParameter(std::ostream& os) const OVERRIDE {
+      os << "[" << *parameter() << "]";
     }
   };
   return new (zone()) CallOperator(descriptor, "Call");
@@ -243,8 +465,11 @@
 
 
 const Operator* CommonOperatorBuilder::Projection(size_t index) {
-  return new (zone()) Operator1<size_t>(IrOpcode::kProjection, Operator::kPure,
-                                        1, 1, "Projection", index);
+  return new (zone()) Operator1<size_t>(       // --
+      IrOpcode::kProjection, Operator::kPure,  // opcode
+      "Projection",                            // name
+      1, 0, 0, 1, 0, 0,                        // counts
+      index);                                  // parameter
 }
 
 }  // namespace compiler
diff --git a/src/compiler/common-operator.h b/src/compiler/common-operator.h
index a3659ad..af6066b 100644
--- a/src/compiler/common-operator.h
+++ b/src/compiler/common-operator.h
@@ -13,22 +13,105 @@
 
 // Forward declarations.
 class ExternalReference;
-class OStream;
 
 
 namespace compiler {
 
 // Forward declarations.
 class CallDescriptor;
-struct CommonOperatorBuilderImpl;
+struct CommonOperatorGlobalCache;
 class Operator;
 
 
+// Prediction hint for branches.
+enum class BranchHint : uint8_t { kNone, kTrue, kFalse };
+
+inline size_t hash_value(BranchHint hint) { return static_cast<size_t>(hint); }
+
+std::ostream& operator<<(std::ostream&, BranchHint);
+
+BranchHint BranchHintOf(const Operator* const);
+
+
+class SelectParameters FINAL {
+ public:
+  explicit SelectParameters(MachineType type,
+                            BranchHint hint = BranchHint::kNone)
+      : type_(type), hint_(hint) {}
+
+  MachineType type() const { return type_; }
+  BranchHint hint() const { return hint_; }
+
+ private:
+  const MachineType type_;
+  const BranchHint hint_;
+};
+
+bool operator==(SelectParameters const&, SelectParameters const&);
+bool operator!=(SelectParameters const&, SelectParameters const&);
+
+size_t hash_value(SelectParameters const& p);
+
+std::ostream& operator<<(std::ostream&, SelectParameters const& p);
+
+SelectParameters const& SelectParametersOf(const Operator* const);
+
+
 // Flag that describes how to combine the current environment with
 // the output of a node to obtain a framestate for lazy bailout.
-enum OutputFrameStateCombine {
-  kPushOutput,   // Push the output on the expression stack.
-  kIgnoreOutput  // Use the frame state as-is.
+class OutputFrameStateCombine {
+ public:
+  enum Kind {
+    kPushOutput,  // Push the output on the expression stack.
+    kPokeAt       // Poke at the given environment location,
+                  // counting from the top of the stack.
+  };
+
+  static OutputFrameStateCombine Ignore() {
+    return OutputFrameStateCombine(kPushOutput, 0);
+  }
+  static OutputFrameStateCombine Push(size_t count = 1) {
+    return OutputFrameStateCombine(kPushOutput, count);
+  }
+  static OutputFrameStateCombine PokeAt(size_t index) {
+    return OutputFrameStateCombine(kPokeAt, index);
+  }
+
+  Kind kind() const { return kind_; }
+  size_t GetPushCount() const {
+    DCHECK_EQ(kPushOutput, kind());
+    return parameter_;
+  }
+  size_t GetOffsetToPokeAt() const {
+    DCHECK_EQ(kPokeAt, kind());
+    return parameter_;
+  }
+
+  bool IsOutputIgnored() const {
+    return kind_ == kPushOutput && parameter_ == 0;
+  }
+
+  size_t ConsumedOutputCount() const {
+    return kind_ == kPushOutput ? GetPushCount() : 1;
+  }
+
+  bool operator==(OutputFrameStateCombine const& other) const {
+    return kind_ == other.kind_ && parameter_ == other.parameter_;
+  }
+  bool operator!=(OutputFrameStateCombine const& other) const {
+    return !(*this == other);
+  }
+
+  friend size_t hash_value(OutputFrameStateCombine const&);
+  friend std::ostream& operator<<(std::ostream&,
+                                  OutputFrameStateCombine const&);
+
+ private:
+  OutputFrameStateCombine(Kind kind, size_t parameter)
+      : kind_(kind), parameter_(parameter) {}
+
+  Kind const kind_;
+  size_t const parameter_;
 };
 
 
@@ -62,24 +145,32 @@
   MaybeHandle<JSFunction> jsfunction_;
 };
 
+bool operator==(FrameStateCallInfo const&, FrameStateCallInfo const&);
+bool operator!=(FrameStateCallInfo const&, FrameStateCallInfo const&);
+
+size_t hash_value(FrameStateCallInfo const&);
+
+std::ostream& operator<<(std::ostream&, FrameStateCallInfo const&);
+
 
 // Interface for building common operators that can be used at any level of IR,
 // including JavaScript, mid-level, and low-level.
-class CommonOperatorBuilder FINAL {
+class CommonOperatorBuilder FINAL : public ZoneObject {
  public:
   explicit CommonOperatorBuilder(Zone* zone);
 
   const Operator* Dead();
   const Operator* End();
-  const Operator* Branch();
+  const Operator* Branch(BranchHint = BranchHint::kNone);
   const Operator* IfTrue();
   const Operator* IfFalse();
   const Operator* Throw();
+  const Operator* Terminate(int effects);
   const Operator* Return();
 
   const Operator* Start(int num_formal_parameters);
-  const Operator* Merge(int controls);
-  const Operator* Loop(int controls);
+  const Operator* Loop(int control_input_count);
+  const Operator* Merge(int control_input_count);
   const Operator* Parameter(int index);
 
   const Operator* Int32Constant(int32_t);
@@ -88,11 +179,11 @@
   const Operator* Float64Constant(volatile double);
   const Operator* ExternalConstant(const ExternalReference&);
   const Operator* NumberConstant(volatile double);
-  const Operator* HeapConstant(const Unique<Object>&);
+  const Operator* HeapConstant(const Unique<HeapObject>&);
 
+  const Operator* Select(MachineType, BranchHint = BranchHint::kNone);
   const Operator* Phi(MachineType type, int arguments);
   const Operator* EffectPhi(int arguments);
-  const Operator* ControlEffect();
   const Operator* ValueEffect(int arguments);
   const Operator* Finish(int arguments);
   const Operator* StateValues(int arguments);
@@ -106,8 +197,10 @@
  private:
   Zone* zone() const { return zone_; }
 
-  const CommonOperatorBuilderImpl& impl_;
+  const CommonOperatorGlobalCache& cache_;
   Zone* const zone_;
+
+  DISALLOW_COPY_AND_ASSIGN(CommonOperatorBuilder);
 };
 
 }  // namespace compiler
diff --git a/src/compiler/compiler-test-utils.h b/src/compiler/compiler-test-utils.h
deleted file mode 100644
index 437abd6..0000000
--- a/src/compiler/compiler-test-utils.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_COMPILER_COMPILER_TEST_UTILS_H_
-#define V8_COMPILER_COMPILER_TEST_UTILS_H_
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-// The TARGET_TEST(Case, Name) macro works just like
-// TEST(Case, Name), except that the test is disabled
-// if the platform is not a supported TurboFan target.
-#if V8_TURBOFAN_TARGET
-#define TARGET_TEST(Case, Name) TEST(Case, Name)
-#else
-#define TARGET_TEST(Case, Name) TEST(Case, DISABLED_##Name)
-#endif
-
-
-// The TARGET_TEST_F(Case, Name) macro works just like
-// TEST_F(Case, Name), except that the test is disabled
-// if the platform is not a supported TurboFan target.
-#if V8_TURBOFAN_TARGET
-#define TARGET_TEST_F(Case, Name) TEST_F(Case, Name)
-#else
-#define TARGET_TEST_F(Case, Name) TEST_F(Case, DISABLED_##Name)
-#endif
-
-
-// The TARGET_TEST_P(Case, Name) macro works just like
-// TEST_P(Case, Name), except that the test is disabled
-// if the platform is not a supported TurboFan target.
-#if V8_TURBOFAN_TARGET
-#define TARGET_TEST_P(Case, Name) TEST_P(Case, Name)
-#else
-#define TARGET_TEST_P(Case, Name) TEST_P(Case, DISABLED_##Name)
-#endif
-
-
-// The TARGET_TYPED_TEST(Case, Name) macro works just like
-// TYPED_TEST(Case, Name), except that the test is disabled
-// if the platform is not a supported TurboFan target.
-#if V8_TURBOFAN_TARGET
-#define TARGET_TYPED_TEST(Case, Name) TYPED_TEST(Case, Name)
-#else
-#define TARGET_TYPED_TEST(Case, Name) TYPED_TEST(Case, DISABLED_##Name)
-#endif
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
-
-#endif  // V8_COMPILER_COMPILER_TEST_UTILS_H_
diff --git a/src/compiler/compiler.gyp b/src/compiler/compiler.gyp
deleted file mode 100644
index ec5ec28..0000000
--- a/src/compiler/compiler.gyp
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2014 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  'variables': {
-    'v8_code': 1,
-  },
-  'includes': ['../../build/toolchain.gypi', '../../build/features.gypi'],
-  'targets': [
-    {
-      'target_name': 'compiler-unittests',
-      'type': 'executable',
-      'dependencies': [
-        '../test/test.gyp:run-all-unittests',
-      ],
-      'include_dirs': [
-        '../..',
-      ],
-      'sources': [  ### gcmole(all) ###
-        'change-lowering-unittest.cc',
-        'common-operator-unittest.cc',
-        'compiler-test-utils.h',
-        'graph-reducer-unittest.cc',
-        'graph-unittest.cc',
-        'graph-unittest.h',
-        'instruction-selector-unittest.cc',
-        'instruction-selector-unittest.h',
-        'js-builtin-reducer-unittest.cc',
-        'machine-operator-reducer-unittest.cc',
-        'machine-operator-unittest.cc',
-        'simplified-operator-reducer-unittest.cc',
-        'simplified-operator-unittest.cc',
-        'value-numbering-reducer-unittest.cc',
-      ],
-      'conditions': [
-        ['v8_target_arch=="arm"', {
-          'sources': [  ### gcmole(arch:arm) ###
-            'arm/instruction-selector-arm-unittest.cc',
-          ],
-        }],
-        ['v8_target_arch=="arm64"', {
-          'sources': [  ### gcmole(arch:arm64) ###
-            'arm64/instruction-selector-arm64-unittest.cc',
-          ],
-        }],
-        ['v8_target_arch=="ia32"', {
-          'sources': [  ### gcmole(arch:ia32) ###
-            'ia32/instruction-selector-ia32-unittest.cc',
-          ],
-        }],
-        ['v8_target_arch=="x64"', {
-          'sources': [  ### gcmole(arch:x64) ###
-            'x64/instruction-selector-x64-unittest.cc',
-          ],
-        }],
-      ],
-    },
-  ],
-}
diff --git a/src/compiler/control-builders.cc b/src/compiler/control-builders.cc
index 3b7d05b..8725244 100644
--- a/src/compiler/control-builders.cc
+++ b/src/compiler/control-builders.cc
@@ -9,8 +9,8 @@
 namespace compiler {
 
 
-void IfBuilder::If(Node* condition) {
-  builder_->NewBranch(condition);
+void IfBuilder::If(Node* condition, BranchHint hint) {
+  builder_->NewBranch(condition, hint);
   else_environment_ = environment()->CopyForConditional();
 }
 
@@ -32,9 +32,9 @@
 }
 
 
-void LoopBuilder::BeginLoop() {
+void LoopBuilder::BeginLoop(BitVector* assigned) {
   builder_->NewLoop();
-  loop_environment_ = environment()->CopyForLoop();
+  loop_environment_ = environment()->CopyForLoop(assigned);
   continue_environment_ = environment()->CopyAsUnreachable();
   break_environment_ = environment()->CopyAsUnreachable();
 }
@@ -78,7 +78,6 @@
   body_environment_ = environment()->CopyAsUnreachable();
   label_environment_ = environment()->CopyAsUnreachable();
   break_environment_ = environment()->CopyAsUnreachable();
-  body_environments_.AddBlock(NULL, case_count(), zone());
 }
 
 
diff --git a/src/compiler/control-builders.h b/src/compiler/control-builders.h
index 695282b..11adfdb 100644
--- a/src/compiler/control-builders.h
+++ b/src/compiler/control-builders.h
@@ -14,7 +14,6 @@
 namespace internal {
 namespace compiler {
 
-
 // Base class for all control builders. Also provides a common interface for
 // control builders to handle 'break' and 'continue' statements when they are
 // used to model breakable statements.
@@ -32,7 +31,7 @@
   typedef StructuredGraphBuilder Builder;
   typedef StructuredGraphBuilder::Environment Environment;
 
-  Zone* zone() const { return builder_->zone(); }
+  Zone* zone() const { return builder_->local_zone(); }
   Environment* environment() { return builder_->environment(); }
   void set_environment(Environment* env) { builder_->set_environment(env); }
 
@@ -41,7 +40,7 @@
 
 
 // Tracks control flow for a conditional statement.
-class IfBuilder : public ControlBuilder {
+class IfBuilder FINAL : public ControlBuilder {
  public:
   explicit IfBuilder(StructuredGraphBuilder* builder)
       : ControlBuilder(builder),
@@ -49,7 +48,7 @@
         else_environment_(NULL) {}
 
   // Primitive control commands.
-  void If(Node* condition);
+  void If(Node* condition, BranchHint hint = BranchHint::kNone);
   void Then();
   void Else();
   void End();
@@ -61,7 +60,7 @@
 
 
 // Tracks control flow for an iteration statement.
-class LoopBuilder : public ControlBuilder {
+class LoopBuilder FINAL : public ControlBuilder {
  public:
   explicit LoopBuilder(StructuredGraphBuilder* builder)
       : ControlBuilder(builder),
@@ -70,13 +69,13 @@
         break_environment_(NULL) {}
 
   // Primitive control commands.
-  void BeginLoop();
+  void BeginLoop(BitVector* assigned);
   void EndBody();
   void EndLoop();
 
   // Primitive support for break and continue.
-  virtual void Continue();
-  virtual void Break();
+  void Continue() FINAL;
+  void Break() FINAL;
 
   // Compound control command for conditional break.
   void BreakUnless(Node* condition);
@@ -89,7 +88,7 @@
 
 
 // Tracks control flow for a switch statement.
-class SwitchBuilder : public ControlBuilder {
+class SwitchBuilder FINAL : public ControlBuilder {
  public:
   explicit SwitchBuilder(StructuredGraphBuilder* builder, int case_count)
       : ControlBuilder(builder),
@@ -108,21 +107,21 @@
   void EndSwitch();
 
   // Primitive support for break.
-  virtual void Break();
+  void Break() FINAL;
 
   // The number of cases within a switch is statically known.
-  int case_count() const { return body_environments_.capacity(); }
+  size_t case_count() const { return body_environments_.size(); }
 
  private:
   Environment* body_environment_;   // Environment after last case body.
   Environment* label_environment_;  // Environment for next label condition.
   Environment* break_environment_;  // Environment after the switch exits.
-  ZoneList<Environment*> body_environments_;
+  ZoneVector<Environment*> body_environments_;
 };
 
 
 // Tracks control flow for a block statement.
-class BlockBuilder : public ControlBuilder {
+class BlockBuilder FINAL : public ControlBuilder {
  public:
   explicit BlockBuilder(StructuredGraphBuilder* builder)
       : ControlBuilder(builder), break_environment_(NULL) {}
@@ -132,13 +131,14 @@
   void EndBlock();
 
   // Primitive support for break.
-  virtual void Break();
+  void Break() FINAL;
 
  private:
   Environment* break_environment_;  // Environment after the block exits.
 };
-}
-}
-}  // namespace v8::internal::compiler
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_CONTROL_BUILDERS_H_
diff --git a/src/compiler/control-equivalence.h b/src/compiler/control-equivalence.h
new file mode 100644
index 0000000..cca087f
--- /dev/null
+++ b/src/compiler/control-equivalence.h
@@ -0,0 +1,361 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_CONTROL_EQUIVALENCE_H_
+#define V8_COMPILER_CONTROL_EQUIVALENCE_H_
+
+#include "src/v8.h"
+
+#include "src/compiler/graph.h"
+#include "src/compiler/node.h"
+#include "src/compiler/node-properties.h"
+#include "src/zone-containers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// Determines control dependence equivalence classes for control nodes. Any two
+// nodes having the same set of control dependences land in one class. These
+// classes can in turn be used to:
+//  - Build a program structure tree (PST) for controls in the graph.
+//  - Determine single-entry single-exit (SESE) regions within the graph.
+//
+// Note that this implementation actually uses cycle equivalence to establish
+// class numbers. Any two nodes are cycle equivalent if they occur in the same
+// set of cycles. It can be shown that control dependence equivalence reduces
+// to undirected cycle equivalence for strongly connected control flow graphs.
+//
+// The algorithm is based on the paper, "The program structure tree: computing
+// control regions in linear time" by Johnson, Pearson & Pingali (PLDI94) which
+// also contains proofs for the aforementioned equivalence. References to line
+// numbers in the algorithm from figure 4 have been added [line:x].
+class ControlEquivalence : public ZoneObject {
+ public:
+  ControlEquivalence(Zone* zone, Graph* graph)
+      : zone_(zone),
+        graph_(graph),
+        dfs_number_(0),
+        class_number_(1),
+        node_data_(graph->NodeCount(), EmptyData(), zone) {}
+
+  // Run the main algorithm starting from the {exit} control node. This causes
+  // the following iterations over control edges of the graph:
+  //  1) A breadth-first backwards traversal to determine the set of nodes that
+  //     participate in the next step. Takes O(E) time and O(N) space.
+  //  2) An undirected depth-first backwards traversal that determines class
+  //     numbers for all participating nodes. Takes O(E) time and O(N) space.
+  void Run(Node* exit) {
+    if (GetClass(exit) != kInvalidClass) return;
+    DetermineParticipation(exit);
+    RunUndirectedDFS(exit);
+  }
+
+  // Retrieves a previously computed class number.
+  size_t ClassOf(Node* node) {
+    DCHECK(GetClass(node) != kInvalidClass);
+    return GetClass(node);
+  }
+
+ private:
+  static const size_t kInvalidClass = static_cast<size_t>(-1);
+  typedef enum { kInputDirection, kUseDirection } DFSDirection;
+
+  struct Bracket {
+    DFSDirection direction;  // Direction in which this bracket was added.
+    size_t recent_class;     // Cached class when bracket was topmost.
+    size_t recent_size;      // Cached set-size when bracket was topmost.
+    Node* from;              // Node that this bracket originates from.
+    Node* to;                // Node that this bracket points to.
+  };
+
+  // The set of brackets for each node during the DFS walk.
+  typedef ZoneLinkedList<Bracket> BracketList;
+
+  struct DFSStackEntry {
+    DFSDirection direction;            // Direction currently used in DFS walk.
+    Node::InputEdges::iterator input;  // Iterator used for "input" direction.
+    Node::UseEdges::iterator use;      // Iterator used for "use" direction.
+    Node* parent_node;                 // Parent node of entry during DFS walk.
+    Node* node;                        // Node that this stack entry belongs to.
+  };
+
+  // The stack is used during the undirected DFS walk.
+  typedef ZoneStack<DFSStackEntry> DFSStack;
+
+  struct NodeData {
+    size_t class_number;  // Equivalence class number assigned to node.
+    size_t dfs_number;    // Pre-order DFS number assigned to node.
+    bool visited;         // Indicates node has already been visited.
+    bool on_stack;        // Indicates node is on DFS stack during walk.
+    bool participates;    // Indicates node participates in DFS walk.
+    BracketList blist;    // List of brackets per node.
+  };
+
+  // The per-node data computed during the DFS walk.
+  typedef ZoneVector<NodeData> Data;
+
+  // Called at pre-visit during DFS walk.
+  void VisitPre(Node* node) {
+    Trace("CEQ: Pre-visit of #%d:%s\n", node->id(), node->op()->mnemonic());
+
+    // Dispense a new pre-order number.
+    SetNumber(node, NewDFSNumber());
+    Trace("  Assigned DFS number is %d\n", GetNumber(node));
+  }
+
+  // Called at mid-visit during DFS walk.
+  void VisitMid(Node* node, DFSDirection direction) {
+    Trace("CEQ: Mid-visit of #%d:%s\n", node->id(), node->op()->mnemonic());
+    BracketList& blist = GetBracketList(node);
+
+    // Remove brackets pointing to this node [line:19].
+    BracketListDelete(blist, node, direction);
+
+    // Potentially introduce artificial dependency from start to end.
+    if (blist.empty()) {
+      DCHECK_EQ(kInputDirection, direction);
+      VisitBackedge(node, graph_->end(), kInputDirection);
+    }
+
+    // Potentially start a new equivalence class [line:37].
+    BracketListTrace(blist);
+    Bracket* recent = &blist.back();
+    if (recent->recent_size != blist.size()) {
+      recent->recent_size = blist.size();
+      recent->recent_class = NewClassNumber();
+    }
+
+    // Assign equivalence class to node.
+    SetClass(node, recent->recent_class);
+    Trace("  Assigned class number is %d\n", GetClass(node));
+  }
+
+  // Called at post-visit during DFS walk.
+  void VisitPost(Node* node, Node* parent_node, DFSDirection direction) {
+    Trace("CEQ: Post-visit of #%d:%s\n", node->id(), node->op()->mnemonic());
+    BracketList& blist = GetBracketList(node);
+
+    // Remove brackets pointing to this node [line:19].
+    BracketListDelete(blist, node, direction);
+
+    // Propagate bracket list up the DFS tree [line:13].
+    if (parent_node != NULL) {
+      BracketList& parent_blist = GetBracketList(parent_node);
+      parent_blist.splice(parent_blist.end(), blist);
+    }
+  }
+
+  // Called when hitting a back edge in the DFS walk.
+  void VisitBackedge(Node* from, Node* to, DFSDirection direction) {
+    Trace("CEQ: Backedge from #%d:%s to #%d:%s\n", from->id(),
+          from->op()->mnemonic(), to->id(), to->op()->mnemonic());
+
+    // Push backedge onto the bracket list [line:25].
+    Bracket bracket = {direction, kInvalidClass, 0, from, to};
+    GetBracketList(from).push_back(bracket);
+  }
+
+  // Performs and undirected DFS walk of the graph. Conceptually all nodes are
+  // expanded, splitting "input" and "use" out into separate nodes. During the
+  // traversal, edges towards the representative nodes are preferred.
+  //
+  //   \ /        - Pre-visit: When N1 is visited in direction D the preferred
+  //    x   N1      edge towards N is taken next, calling VisitPre(N).
+  //    |         - Mid-visit: After all edges out of N2 in direction D have
+  //    |   N       been visited, we switch the direction and start considering
+  //    |           edges out of N1 now, and we call VisitMid(N).
+  //    x   N2    - Post-visit: After all edges out of N1 in direction opposite
+  //   / \          to D have been visited, we pop N and call VisitPost(N).
+  //
+  // This will yield a true spanning tree (without cross or forward edges) and
+  // also discover proper back edges in both directions.
+  void RunUndirectedDFS(Node* exit) {
+    ZoneStack<DFSStackEntry> stack(zone_);
+    DFSPush(stack, exit, NULL, kInputDirection);
+    VisitPre(exit);
+
+    while (!stack.empty()) {  // Undirected depth-first backwards traversal.
+      DFSStackEntry& entry = stack.top();
+      Node* node = entry.node;
+
+      if (entry.direction == kInputDirection) {
+        if (entry.input != node->input_edges().end()) {
+          Edge edge = *entry.input;
+          Node* input = edge.to();
+          ++(entry.input);
+          if (NodeProperties::IsControlEdge(edge) &&
+              NodeProperties::IsControl(input)) {
+            // Visit next control input.
+            if (!GetData(input)->participates) continue;
+            if (GetData(input)->visited) continue;
+            if (GetData(input)->on_stack) {
+              // Found backedge if input is on stack.
+              if (input != entry.parent_node) {
+                VisitBackedge(node, input, kInputDirection);
+              }
+            } else {
+              // Push input onto stack.
+              DFSPush(stack, input, node, kInputDirection);
+              VisitPre(input);
+            }
+          }
+          continue;
+        }
+        if (entry.use != node->use_edges().end()) {
+          // Switch direction to uses.
+          entry.direction = kUseDirection;
+          VisitMid(node, kInputDirection);
+          continue;
+        }
+      }
+
+      if (entry.direction == kUseDirection) {
+        if (entry.use != node->use_edges().end()) {
+          Edge edge = *entry.use;
+          Node* use = edge.from();
+          ++(entry.use);
+          if (NodeProperties::IsControlEdge(edge) &&
+              NodeProperties::IsControl(use)) {
+            // Visit next control use.
+            if (!GetData(use)->participates) continue;
+            if (GetData(use)->visited) continue;
+            if (GetData(use)->on_stack) {
+              // Found backedge if use is on stack.
+              if (use != entry.parent_node) {
+                VisitBackedge(node, use, kUseDirection);
+              }
+            } else {
+              // Push use onto stack.
+              DFSPush(stack, use, node, kUseDirection);
+              VisitPre(use);
+            }
+          }
+          continue;
+        }
+        if (entry.input != node->input_edges().end()) {
+          // Switch direction to inputs.
+          entry.direction = kInputDirection;
+          VisitMid(node, kUseDirection);
+          continue;
+        }
+      }
+
+      // Pop node from stack when done with all inputs and uses.
+      DCHECK(entry.input == node->input_edges().end());
+      DCHECK(entry.use == node->use_edges().end());
+      DFSPop(stack, node);
+      VisitPost(node, entry.parent_node, entry.direction);
+    }
+  }
+
+  void DetermineParticipationEnqueue(ZoneQueue<Node*>& queue, Node* node) {
+    if (!GetData(node)->participates) {
+      GetData(node)->participates = true;
+      queue.push(node);
+    }
+  }
+
+  void DetermineParticipation(Node* exit) {
+    ZoneQueue<Node*> queue(zone_);
+    DetermineParticipationEnqueue(queue, exit);
+    while (!queue.empty()) {  // Breadth-first backwards traversal.
+      Node* node = queue.front();
+      queue.pop();
+      int max = NodeProperties::PastControlIndex(node);
+      for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) {
+        DetermineParticipationEnqueue(queue, node->InputAt(i));
+      }
+    }
+  }
+
+ private:
+  NodeData* GetData(Node* node) { return &node_data_[node->id()]; }
+  int NewClassNumber() { return class_number_++; }
+  int NewDFSNumber() { return dfs_number_++; }
+
+  // Template used to initialize per-node data.
+  NodeData EmptyData() {
+    return {kInvalidClass, 0, false, false, false, BracketList(zone_)};
+  }
+
+  // Accessors for the DFS number stored within the per-node data.
+  size_t GetNumber(Node* node) { return GetData(node)->dfs_number; }
+  void SetNumber(Node* node, size_t number) {
+    GetData(node)->dfs_number = number;
+  }
+
+  // Accessors for the equivalence class stored within the per-node data.
+  size_t GetClass(Node* node) { return GetData(node)->class_number; }
+  void SetClass(Node* node, size_t number) {
+    GetData(node)->class_number = number;
+  }
+
+  // Accessors for the bracket list stored within the per-node data.
+  BracketList& GetBracketList(Node* node) { return GetData(node)->blist; }
+  void SetBracketList(Node* node, BracketList& list) {
+    GetData(node)->blist = list;
+  }
+
+  // Mutates the DFS stack by pushing an entry.
+  void DFSPush(DFSStack& stack, Node* node, Node* from, DFSDirection dir) {
+    DCHECK(GetData(node)->participates);
+    DCHECK(!GetData(node)->visited);
+    GetData(node)->on_stack = true;
+    Node::InputEdges::iterator input = node->input_edges().begin();
+    Node::UseEdges::iterator use = node->use_edges().begin();
+    stack.push({dir, input, use, from, node});
+  }
+
+  // Mutates the DFS stack by popping an entry.
+  void DFSPop(DFSStack& stack, Node* node) {
+    DCHECK_EQ(stack.top().node, node);
+    GetData(node)->on_stack = false;
+    GetData(node)->visited = true;
+    stack.pop();
+  }
+
+  // TODO(mstarzinger): Optimize this to avoid linear search.
+  void BracketListDelete(BracketList& blist, Node* to, DFSDirection direction) {
+    for (BracketList::iterator i = blist.begin(); i != blist.end(); /*nop*/) {
+      if (i->to == to && i->direction != direction) {
+        Trace("  BList erased: {%d->%d}\n", i->from->id(), i->to->id());
+        i = blist.erase(i);
+      } else {
+        ++i;
+      }
+    }
+  }
+
+  void BracketListTrace(BracketList& blist) {
+    if (FLAG_trace_turbo_scheduler) {
+      Trace("  BList: ");
+      for (Bracket bracket : blist) {
+        Trace("{%d->%d} ", bracket.from->id(), bracket.to->id());
+      }
+      Trace("\n");
+    }
+  }
+
+  void Trace(const char* msg, ...) {
+    if (FLAG_trace_turbo_scheduler) {
+      va_list arguments;
+      va_start(arguments, msg);
+      base::OS::VPrint(msg, arguments);
+      va_end(arguments);
+    }
+  }
+
+  Zone* zone_;
+  Graph* graph_;
+  int dfs_number_;    // Generates new DFS pre-order numbers on demand.
+  int class_number_;  // Generates new equivalence class numbers on demand.
+  Data node_data_;    // Per-node data stored as a side-table.
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_CONTROL_EQUIVALENCE_H_
diff --git a/src/compiler/control-reducer.cc b/src/compiler/control-reducer.cc
new file mode 100644
index 0000000..eef8a49
--- /dev/null
+++ b/src/compiler/control-reducer.cc
@@ -0,0 +1,592 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/control-reducer.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/zone-containers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+enum VisitState { kUnvisited = 0, kOnStack = 1, kRevisit = 2, kVisited = 3 };
+enum Decision { kFalse, kUnknown, kTrue };
+
+class ReachabilityMarker : public NodeMarker<uint8_t> {
+ public:
+  explicit ReachabilityMarker(Graph* graph) : NodeMarker<uint8_t>(graph, 8) {}
+  bool SetReachableFromEnd(Node* node) {
+    uint8_t before = Get(node);
+    Set(node, before | kFromEnd);
+    return before & kFromEnd;
+  }
+  bool IsReachableFromEnd(Node* node) { return Get(node) & kFromEnd; }
+  bool SetReachableFromStart(Node* node) {
+    uint8_t before = Get(node);
+    Set(node, before | kFromStart);
+    return before & kFromStart;
+  }
+  bool IsReachableFromStart(Node* node) { return Get(node) & kFromStart; }
+  void Push(Node* node) { Set(node, Get(node) | kFwStack); }
+  void Pop(Node* node) { Set(node, Get(node) & ~kFwStack); }
+  bool IsOnStack(Node* node) { return Get(node) & kFwStack; }
+
+ private:
+  enum Bit { kFromEnd = 1, kFromStart = 2, kFwStack = 4 };
+};
+
+
+#define TRACE(x) \
+  if (FLAG_trace_turbo_reduction) PrintF x
+
+class ControlReducerImpl {
+ public:
+  ControlReducerImpl(Zone* zone, JSGraph* jsgraph,
+                     CommonOperatorBuilder* common)
+      : zone_(zone),
+        jsgraph_(jsgraph),
+        common_(common),
+        state_(jsgraph->graph()->NodeCount(), kUnvisited, zone_),
+        stack_(zone_),
+        revisit_(zone_),
+        dead_(NULL) {}
+
+  Zone* zone_;
+  JSGraph* jsgraph_;
+  CommonOperatorBuilder* common_;
+  ZoneVector<VisitState> state_;
+  ZoneDeque<Node*> stack_;
+  ZoneDeque<Node*> revisit_;
+  Node* dead_;
+
+  void Reduce() {
+    Push(graph()->end());
+    do {
+      // Process the node on the top of the stack, potentially pushing more
+      // or popping the node off the stack.
+      ReduceTop();
+      // If the stack becomes empty, revisit any nodes in the revisit queue.
+      // If no nodes in the revisit queue, try removing dead loops.
+      // If no dead loops, then finish.
+    } while (!stack_.empty() || TryRevisit() || RepairAndRemoveLoops());
+  }
+
+  bool TryRevisit() {
+    while (!revisit_.empty()) {
+      Node* n = revisit_.back();
+      revisit_.pop_back();
+      if (state_[n->id()] == kRevisit) {  // state can change while in queue.
+        Push(n);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // Repair the graph after the possible creation of non-terminating or dead
+  // loops. Removing dead loops can produce more opportunities for reduction.
+  bool RepairAndRemoveLoops() {
+    // TODO(turbofan): we can skip this if the graph has no loops, but
+    // we have to be careful about proper loop detection during reduction.
+
+    // Gather all nodes backwards-reachable from end (through inputs).
+    ReachabilityMarker marked(graph());
+    NodeVector nodes(zone_);
+    AddNodesReachableFromEnd(marked, nodes);
+
+    // Walk forward through control nodes, looking for back edges to nodes
+    // that are not connected to end. Those are non-terminating loops (NTLs).
+    Node* start = graph()->start();
+    marked.Push(start);
+    marked.SetReachableFromStart(start);
+
+    // We use a stack of (Node, UseIter) pairs to avoid O(n^2) traversal.
+    typedef std::pair<Node*, UseIter> FwIter;
+    ZoneVector<FwIter> fw_stack(zone_);
+    fw_stack.push_back(FwIter(start, start->uses().begin()));
+
+    while (!fw_stack.empty()) {
+      Node* node = fw_stack.back().first;
+      TRACE(("ControlFw: #%d:%s\n", node->id(), node->op()->mnemonic()));
+      bool pop = true;
+      while (fw_stack.back().second != node->uses().end()) {
+        Node* succ = *(fw_stack.back().second);
+        if (marked.IsOnStack(succ) && !marked.IsReachableFromEnd(succ)) {
+          // {succ} is on stack and not reachable from end.
+          Node* added = ConnectNTL(succ);
+          nodes.push_back(added);
+          marked.SetReachableFromEnd(added);
+          AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1);
+
+          // Reset the use iterators for the entire stack.
+          for (size_t i = 0; i < fw_stack.size(); i++) {
+            FwIter& iter = fw_stack[i];
+            fw_stack[i] = FwIter(iter.first, iter.first->uses().begin());
+          }
+          pop = false;  // restart traversing successors of this node.
+          break;
+        }
+        if (IrOpcode::IsControlOpcode(succ->opcode()) &&
+            !marked.IsReachableFromStart(succ)) {
+          // {succ} is a control node and not yet reached from start.
+          marked.Push(succ);
+          marked.SetReachableFromStart(succ);
+          fw_stack.push_back(FwIter(succ, succ->uses().begin()));
+          pop = false;  // "recurse" into successor control node.
+          break;
+        }
+        ++fw_stack.back().second;
+      }
+      if (pop) {
+        marked.Pop(node);
+        fw_stack.pop_back();
+      }
+    }
+
+    // Trim references from dead nodes to live nodes first.
+    jsgraph_->GetCachedNodes(&nodes);
+    TrimNodes(marked, nodes);
+
+    // Any control nodes not reachable from start are dead, even loops.
+    for (size_t i = 0; i < nodes.size(); i++) {
+      Node* node = nodes[i];
+      if (IrOpcode::IsControlOpcode(node->opcode()) &&
+          !marked.IsReachableFromStart(node)) {
+        ReplaceNode(node, dead());  // uses will be added to revisit queue.
+      }
+    }
+    return TryRevisit();  // try to push a node onto the stack.
+  }
+
+  // Connect {loop}, the header of a non-terminating loop, to the end node.
+  Node* ConnectNTL(Node* loop) {
+    TRACE(("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic()));
+
+    if (loop->opcode() != IrOpcode::kTerminate) {
+      // Insert a {Terminate} node if the loop has effects.
+      ZoneDeque<Node*> effects(zone_);
+      for (Node* const use : loop->uses()) {
+        if (use->opcode() == IrOpcode::kEffectPhi) effects.push_back(use);
+      }
+      int count = static_cast<int>(effects.size());
+      if (count > 0) {
+        Node** inputs = zone_->NewArray<Node*>(1 + count);
+        for (int i = 0; i < count; i++) inputs[i] = effects[i];
+        inputs[count] = loop;
+        loop = graph()->NewNode(common_->Terminate(count), 1 + count, inputs);
+        TRACE(("AddTerminate: #%d:%s[%d]\n", loop->id(), loop->op()->mnemonic(),
+               count));
+      }
+    }
+
+    Node* to_add = loop;
+    Node* end = graph()->end();
+    CHECK_EQ(IrOpcode::kEnd, end->opcode());
+    Node* merge = end->InputAt(0);
+    if (merge == NULL || merge->opcode() == IrOpcode::kDead) {
+      // The end node died; just connect end to {loop}.
+      end->ReplaceInput(0, loop);
+    } else if (merge->opcode() != IrOpcode::kMerge) {
+      // Introduce a final merge node for {end->InputAt(0)} and {loop}.
+      merge = graph()->NewNode(common_->Merge(2), merge, loop);
+      end->ReplaceInput(0, merge);
+      to_add = merge;
+      // Mark the node as visited so that we can revisit later.
+      EnsureStateSize(merge->id());
+      state_[merge->id()] = kVisited;
+    } else {
+      // Append a new input to the final merge at the end.
+      merge->AppendInput(graph()->zone(), loop);
+      merge->set_op(common_->Merge(merge->InputCount()));
+    }
+    return to_add;
+  }
+
+  void AddNodesReachableFromEnd(ReachabilityMarker& marked, NodeVector& nodes) {
+    Node* end = graph()->end();
+    marked.SetReachableFromEnd(end);
+    if (!end->IsDead()) {
+      nodes.push_back(end);
+      AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1);
+    }
+  }
+
+  void AddBackwardsReachableNodes(ReachabilityMarker& marked, NodeVector& nodes,
+                                  size_t cursor) {
+    while (cursor < nodes.size()) {
+      Node* node = nodes[cursor++];
+      for (Node* const input : node->inputs()) {
+        if (!marked.SetReachableFromEnd(input)) {
+          nodes.push_back(input);
+        }
+      }
+    }
+  }
+
+  void Trim() {
+    // Gather all nodes backwards-reachable from end through inputs.
+    ReachabilityMarker marked(graph());
+    NodeVector nodes(zone_);
+    AddNodesReachableFromEnd(marked, nodes);
+
+    // Process cached nodes in the JSGraph too.
+    jsgraph_->GetCachedNodes(&nodes);
+    TrimNodes(marked, nodes);
+  }
+
+  void TrimNodes(ReachabilityMarker& marked, NodeVector& nodes) {
+    // Remove dead->live edges.
+    for (size_t j = 0; j < nodes.size(); j++) {
+      Node* node = nodes[j];
+      for (Edge edge : node->use_edges()) {
+        Node* use = edge.from();
+        if (!marked.IsReachableFromEnd(use)) {
+          TRACE(("DeadLink: #%d:%s(%d) -> #%d:%s\n", use->id(),
+                 use->op()->mnemonic(), edge.index(), node->id(),
+                 node->op()->mnemonic()));
+          edge.UpdateTo(NULL);
+        }
+      }
+    }
+#if DEBUG
+    // Verify that no inputs to live nodes are NULL.
+    for (size_t j = 0; j < nodes.size(); j++) {
+      Node* node = nodes[j];
+      for (Node* const input : node->inputs()) {
+        CHECK_NE(NULL, input);
+      }
+      for (Node* const use : node->uses()) {
+        CHECK(marked.IsReachableFromEnd(use));
+      }
+    }
+#endif
+  }
+
+  // Reduce the node on the top of the stack.
+  // If an input {i} is not yet visited or needs to be revisited, push {i} onto
+  // the stack and return. Otherwise, all inputs are visited, so apply
+  // reductions for {node} and pop it off the stack.
+  void ReduceTop() {
+    size_t height = stack_.size();
+    Node* node = stack_.back();
+
+    if (node->IsDead()) return Pop();  // Node was killed while on stack.
+
+    TRACE(("ControlReduce: #%d:%s\n", node->id(), node->op()->mnemonic()));
+
+    // Recurse on an input if necessary.
+    for (Node* const input : node->inputs()) {
+      if (Recurse(input)) return;
+    }
+
+    // All inputs should be visited or on stack. Apply reductions to node.
+    Node* replacement = ReduceNode(node);
+    if (replacement != node) ReplaceNode(node, replacement);
+
+    // After reducing the node, pop it off the stack.
+    CHECK_EQ(static_cast<int>(height), static_cast<int>(stack_.size()));
+    Pop();
+
+    // If there was a replacement, reduce it after popping {node}.
+    if (replacement != node) Recurse(replacement);
+  }
+
+  void EnsureStateSize(size_t id) {
+    if (id >= state_.size()) {
+      state_.resize((3 * id) / 2, kUnvisited);
+    }
+  }
+
+  // Push a node onto the stack if its state is {kUnvisited} or {kRevisit}.
+  bool Recurse(Node* node) {
+    size_t id = static_cast<size_t>(node->id());
+    EnsureStateSize(id);
+    if (state_[id] != kRevisit && state_[id] != kUnvisited) return false;
+    Push(node);
+    return true;
+  }
+
+  void Push(Node* node) {
+    state_[node->id()] = kOnStack;
+    stack_.push_back(node);
+  }
+
+  void Pop() {
+    int pos = static_cast<int>(stack_.size()) - 1;
+    DCHECK_GE(pos, 0);
+    DCHECK_EQ(kOnStack, state_[stack_[pos]->id()]);
+    state_[stack_[pos]->id()] = kVisited;
+    stack_.pop_back();
+  }
+
+  // Queue a node to be revisited if it has been visited once already.
+  void Revisit(Node* node) {
+    size_t id = static_cast<size_t>(node->id());
+    if (id < state_.size() && state_[id] == kVisited) {
+      TRACE(("  Revisit #%d:%s\n", node->id(), node->op()->mnemonic()));
+      state_[id] = kRevisit;
+      revisit_.push_back(node);
+    }
+  }
+
+  Node* dead() {
+    if (dead_ == NULL) dead_ = graph()->NewNode(common_->Dead());
+    return dead_;
+  }
+
+  //===========================================================================
+  // Reducer implementation: perform reductions on a node.
+  //===========================================================================
+  Node* ReduceNode(Node* node) {
+    if (node->op()->ControlInputCount() == 1) {
+      // If a node has only one control input and it is dead, replace with dead.
+      Node* control = NodeProperties::GetControlInput(node);
+      if (control->opcode() == IrOpcode::kDead) {
+        TRACE(("ControlDead: #%d:%s\n", node->id(), node->op()->mnemonic()));
+        return control;
+      }
+    }
+
+    // Reduce branches, phis, and merges.
+    switch (node->opcode()) {
+      case IrOpcode::kBranch:
+        return ReduceBranch(node);
+      case IrOpcode::kLoop:
+      case IrOpcode::kMerge:
+        return ReduceMerge(node);
+      case IrOpcode::kSelect:
+        return ReduceSelect(node);
+      case IrOpcode::kPhi:
+      case IrOpcode::kEffectPhi:
+        return ReducePhi(node);
+      default:
+        return node;
+    }
+  }
+
+  // Try to statically fold a condition.
+  Decision DecideCondition(Node* cond) {
+    switch (cond->opcode()) {
+      case IrOpcode::kInt32Constant:
+        return Int32Matcher(cond).Is(0) ? kFalse : kTrue;
+      case IrOpcode::kInt64Constant:
+        return Int64Matcher(cond).Is(0) ? kFalse : kTrue;
+      case IrOpcode::kNumberConstant:
+        return NumberMatcher(cond).Is(0) ? kFalse : kTrue;
+      case IrOpcode::kHeapConstant: {
+        Handle<Object> object =
+            HeapObjectMatcher<Object>(cond).Value().handle();
+        if (object->IsTrue()) return kTrue;
+        if (object->IsFalse()) return kFalse;
+        // TODO(turbofan): decide more conditions for heap constants.
+        break;
+      }
+      default:
+        break;
+    }
+    return kUnknown;
+  }
+
+  // Reduce redundant selects.
+  Node* ReduceSelect(Node* const node) {
+    Node* const tvalue = node->InputAt(1);
+    Node* const fvalue = node->InputAt(2);
+    if (tvalue == fvalue) return tvalue;
+    Decision result = DecideCondition(node->InputAt(0));
+    if (result == kTrue) return tvalue;
+    if (result == kFalse) return fvalue;
+    return node;
+  }
+
+  // Reduce redundant phis.
+  Node* ReducePhi(Node* node) {
+    int n = node->InputCount();
+    if (n <= 1) return dead();            // No non-control inputs.
+    if (n == 2) return node->InputAt(0);  // Only one non-control input.
+
+    // Never remove an effect phi from a (potentially non-terminating) loop.
+    // Otherwise, we might end up eliminating effect nodes, such as calls,
+    // before the loop.
+    if (node->opcode() == IrOpcode::kEffectPhi &&
+        NodeProperties::GetControlInput(node)->opcode() == IrOpcode::kLoop) {
+      return node;
+    }
+
+    Node* replacement = NULL;
+    Node::Inputs inputs = node->inputs();
+    for (InputIter it = inputs.begin(); n > 1; --n, ++it) {
+      Node* input = *it;
+      if (input->opcode() == IrOpcode::kDead) continue;  // ignore dead inputs.
+      if (input != node && input != replacement) {       // non-redundant input.
+        if (replacement != NULL) return node;
+        replacement = input;
+      }
+    }
+    return replacement == NULL ? dead() : replacement;
+  }
+
+  // Reduce merges by trimming away dead inputs from the merge and phis.
+  Node* ReduceMerge(Node* node) {
+    // Count the number of live inputs.
+    int live = 0;
+    int index = 0;
+    int live_index = 0;
+    for (Node* const input : node->inputs()) {
+      if (input->opcode() != IrOpcode::kDead) {
+        live++;
+        live_index = index;
+      }
+      index++;
+    }
+
+    if (live > 1 && live == node->InputCount()) return node;  // nothing to do.
+
+    TRACE(("ReduceMerge: #%d:%s (%d live)\n", node->id(),
+           node->op()->mnemonic(), live));
+
+    if (live == 0) return dead();  // no remaining inputs.
+
+    // Gather phis and effect phis to be edited.
+    ZoneVector<Node*> phis(zone_);
+    for (Node* const use : node->uses()) {
+      if (use->opcode() == IrOpcode::kPhi ||
+          use->opcode() == IrOpcode::kEffectPhi) {
+        phis.push_back(use);
+      }
+    }
+
+    if (live == 1) {
+      // All phis are redundant. Replace them with their live input.
+      for (Node* const phi : phis) ReplaceNode(phi, phi->InputAt(live_index));
+      // The merge itself is redundant.
+      return node->InputAt(live_index);
+    }
+
+    // Edit phis in place, removing dead inputs and revisiting them.
+    for (Node* const phi : phis) {
+      TRACE(("  PhiInMerge: #%d:%s (%d live)\n", phi->id(),
+             phi->op()->mnemonic(), live));
+      RemoveDeadInputs(node, phi);
+      Revisit(phi);
+    }
+    // Edit the merge in place, removing dead inputs.
+    RemoveDeadInputs(node, node);
+    return node;
+  }
+
+  // Reduce branches if they have constant inputs.
+  Node* ReduceBranch(Node* node) {
+    Decision result = DecideCondition(node->InputAt(0));
+    if (result == kUnknown) return node;
+
+    TRACE(("BranchReduce: #%d:%s = %s\n", node->id(), node->op()->mnemonic(),
+           (result == kTrue) ? "true" : "false"));
+
+    // Replace IfTrue and IfFalse projections from this branch.
+    Node* control = NodeProperties::GetControlInput(node);
+    for (Edge edge : node->use_edges()) {
+      Node* use = edge.from();
+      if (use->opcode() == IrOpcode::kIfTrue) {
+        TRACE(("  IfTrue: #%d:%s\n", use->id(), use->op()->mnemonic()));
+        edge.UpdateTo(NULL);
+        ReplaceNode(use, (result == kTrue) ? control : dead());
+      } else if (use->opcode() == IrOpcode::kIfFalse) {
+        TRACE(("  IfFalse: #%d:%s\n", use->id(), use->op()->mnemonic()));
+        edge.UpdateTo(NULL);
+        ReplaceNode(use, (result == kTrue) ? dead() : control);
+      }
+    }
+    return control;
+  }
+
+  // Remove inputs to {node} corresponding to the dead inputs to {merge}
+  // and compact the remaining inputs, updating the operator.
+  void RemoveDeadInputs(Node* merge, Node* node) {
+    int pos = 0;
+    for (int i = 0; i < node->InputCount(); i++) {
+      // skip dead inputs.
+      if (i < merge->InputCount() &&
+          merge->InputAt(i)->opcode() == IrOpcode::kDead)
+        continue;
+      // compact live inputs.
+      if (pos != i) node->ReplaceInput(pos, node->InputAt(i));
+      pos++;
+    }
+    node->TrimInputCount(pos);
+    if (node->opcode() == IrOpcode::kPhi) {
+      node->set_op(common_->Phi(OpParameter<MachineType>(node->op()), pos - 1));
+    } else if (node->opcode() == IrOpcode::kEffectPhi) {
+      node->set_op(common_->EffectPhi(pos - 1));
+    } else if (node->opcode() == IrOpcode::kMerge) {
+      node->set_op(common_->Merge(pos));
+    } else if (node->opcode() == IrOpcode::kLoop) {
+      node->set_op(common_->Loop(pos));
+    } else {
+      UNREACHABLE();
+    }
+  }
+
+  // Replace uses of {node} with {replacement} and revisit the uses.
+  void ReplaceNode(Node* node, Node* replacement) {
+    if (node == replacement) return;
+    TRACE(("  Replace: #%d:%s with #%d:%s\n", node->id(),
+           node->op()->mnemonic(), replacement->id(),
+           replacement->op()->mnemonic()));
+    for (Node* const use : node->uses()) {
+      // Don't revisit this node if it refers to itself.
+      if (use != node) Revisit(use);
+    }
+    node->ReplaceUses(replacement);
+    node->Kill();
+  }
+
+  Graph* graph() { return jsgraph_->graph(); }
+};
+
+
+void ControlReducer::ReduceGraph(Zone* zone, JSGraph* jsgraph,
+                                 CommonOperatorBuilder* common) {
+  ControlReducerImpl impl(zone, jsgraph, common);
+  impl.Reduce();
+}
+
+
+void ControlReducer::TrimGraph(Zone* zone, JSGraph* jsgraph) {
+  ControlReducerImpl impl(zone, jsgraph, NULL);
+  impl.Trim();
+}
+
+
+Node* ControlReducer::ReducePhiForTesting(JSGraph* jsgraph,
+                                          CommonOperatorBuilder* common,
+                                          Node* node) {
+  Zone zone(jsgraph->graph()->zone()->isolate());
+  ControlReducerImpl impl(&zone, jsgraph, common);
+  return impl.ReducePhi(node);
+}
+
+
+Node* ControlReducer::ReduceMergeForTesting(JSGraph* jsgraph,
+                                            CommonOperatorBuilder* common,
+                                            Node* node) {
+  Zone zone(jsgraph->graph()->zone()->isolate());
+  ControlReducerImpl impl(&zone, jsgraph, common);
+  return impl.ReduceMerge(node);
+}
+
+
+Node* ControlReducer::ReduceBranchForTesting(JSGraph* jsgraph,
+                                             CommonOperatorBuilder* common,
+                                             Node* node) {
+  Zone zone(jsgraph->graph()->zone()->isolate());
+  ControlReducerImpl impl(&zone, jsgraph, common);
+  return impl.ReduceBranch(node);
+}
+}
+}
+}  // namespace v8::internal::compiler
diff --git a/src/compiler/control-reducer.h b/src/compiler/control-reducer.h
new file mode 100644
index 0000000..e25bb88
--- /dev/null
+++ b/src/compiler/control-reducer.h
@@ -0,0 +1,39 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_CONTROL_REDUCER_H_
+#define V8_COMPILER_CONTROL_REDUCER_H_
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class JSGraph;
+class CommonOperatorBuilder;
+class Node;
+
+class ControlReducer {
+ public:
+  // Perform branch folding and dead code elimination on the graph.
+  static void ReduceGraph(Zone* zone, JSGraph* graph,
+                          CommonOperatorBuilder* builder);
+
+  // Trim nodes in the graph that are not reachable from end.
+  static void TrimGraph(Zone* zone, JSGraph* graph);
+
+  // Testing interface.
+  static Node* ReducePhiForTesting(JSGraph* graph,
+                                   CommonOperatorBuilder* builder, Node* node);
+  static Node* ReduceBranchForTesting(JSGraph* graph,
+                                      CommonOperatorBuilder* builder,
+                                      Node* node);
+  static Node* ReduceMergeForTesting(JSGraph* graph,
+                                     CommonOperatorBuilder* builder,
+                                     Node* node);
+};
+}
+}
+}  // namespace v8::internal::compiler
+
+#endif  // V8_COMPILER_CONTROL_REDUCER_H_
diff --git a/src/compiler/diamond.h b/src/compiler/diamond.h
new file mode 100644
index 0000000..6133cc5
--- /dev/null
+++ b/src/compiler/diamond.h
@@ -0,0 +1,85 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_DIAMOND_H_
+#define V8_COMPILER_DIAMOND_H_
+
+#include "src/v8.h"
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph-inl.h"
+#include "src/compiler/node.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// A helper to make it easier to build diamond-shaped control patterns.
+struct Diamond {
+  Graph* graph;
+  CommonOperatorBuilder* common;
+  Node* branch;
+  Node* if_true;
+  Node* if_false;
+  Node* merge;
+
+  Diamond(Graph* g, CommonOperatorBuilder* b, Node* cond,
+          BranchHint hint = BranchHint::kNone) {
+    graph = g;
+    common = b;
+    branch = graph->NewNode(common->Branch(hint), cond, graph->start());
+    if_true = graph->NewNode(common->IfTrue(), branch);
+    if_false = graph->NewNode(common->IfFalse(), branch);
+    merge = graph->NewNode(common->Merge(2), if_true, if_false);
+  }
+
+  // Place {this} after {that} in control flow order.
+  void Chain(Diamond& that) { branch->ReplaceInput(1, that.merge); }
+
+  // Place {this} after {that} in control flow order.
+  void Chain(Node* that) { branch->ReplaceInput(1, that); }
+
+  // Nest {this} into either the if_true or if_false branch of {that}.
+  void Nest(Diamond& that, bool if_true) {
+    if (if_true) {
+      branch->ReplaceInput(1, that.if_true);
+      that.merge->ReplaceInput(0, merge);
+    } else {
+      branch->ReplaceInput(1, that.if_false);
+      that.merge->ReplaceInput(1, merge);
+    }
+  }
+
+  Node* Phi(MachineType machine_type, Node* tv, Node* fv) {
+    return graph->NewNode(common->Phi(machine_type, 2), tv, fv, merge);
+  }
+
+  Node* EffectPhi(Node* tv, Node* fv) {
+    return graph->NewNode(common->EffectPhi(2), tv, fv, merge);
+  }
+
+  void OverwriteWithPhi(Node* node, MachineType machine_type, Node* tv,
+                        Node* fv) {
+    DCHECK(node->InputCount() >= 3);
+    node->set_op(common->Phi(machine_type, 2));
+    node->ReplaceInput(0, tv);
+    node->ReplaceInput(1, fv);
+    node->ReplaceInput(2, merge);
+    node->TrimInputCount(3);
+  }
+
+  void OverwriteWithEffectPhi(Node* node, Node* te, Node* fe) {
+    DCHECK(node->InputCount() >= 3);
+    node->set_op(common->EffectPhi(2));
+    node->ReplaceInput(0, te);
+    node->ReplaceInput(1, fe);
+    node->ReplaceInput(2, merge);
+    node->TrimInputCount(3);
+  }
+};
+}
+}
+}  // namespace v8::internal::compiler
+
+#endif  // V8_COMPILER_DIAMOND_H_
diff --git a/src/compiler/frame.h b/src/compiler/frame.h
index afcbc37..f99d7bd 100644
--- a/src/compiler/frame.h
+++ b/src/compiler/frame.h
@@ -7,7 +7,7 @@
 
 #include "src/v8.h"
 
-#include "src/data-flow.h"
+#include "src/bit-vector.h"
 
 namespace v8 {
 namespace internal {
@@ -17,7 +17,7 @@
 // registers for a compiled function. Frames are usually populated by the
 // register allocator and are used by Linkage to generate code for the prologue
 // and epilogue to compiled code.
-class Frame {
+class Frame : public ZoneObject {
  public:
   Frame()
       : register_save_area_size_(0),
@@ -69,6 +69,8 @@
   int double_spill_slot_count_;
   BitVector* allocated_registers_;
   BitVector* allocated_double_registers_;
+
+  DISALLOW_COPY_AND_ASSIGN(Frame);
 };
 
 
diff --git a/src/compiler/gap-resolver.h b/src/compiler/gap-resolver.h
index 98aaab2..4f4f4e4 100644
--- a/src/compiler/gap-resolver.h
+++ b/src/compiler/gap-resolver.h
@@ -39,8 +39,9 @@
   // Assembler used to emit moves and save registers.
   Assembler* const assembler_;
 };
-}
-}
-}  // namespace v8::internal::compiler
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_GAP_RESOLVER_H_
diff --git a/src/compiler/generic-algorithm-inl.h b/src/compiler/generic-algorithm-inl.h
deleted file mode 100644
index a25131f..0000000
--- a/src/compiler/generic-algorithm-inl.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_COMPILER_GENERIC_ALGORITHM_INL_H_
-#define V8_COMPILER_GENERIC_ALGORITHM_INL_H_
-
-#include <vector>
-
-#include "src/compiler/generic-algorithm.h"
-#include "src/compiler/generic-graph.h"
-#include "src/compiler/generic-node.h"
-#include "src/compiler/generic-node-inl.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-template <class N>
-class NodeInputIterationTraits {
- public:
-  typedef N Node;
-  typedef typename N::Inputs::iterator Iterator;
-
-  static Iterator begin(Node* node) { return node->inputs().begin(); }
-  static Iterator end(Node* node) { return node->inputs().end(); }
-  static int max_id(GenericGraphBase* graph) { return graph->NodeCount(); }
-  static Node* to(Iterator iterator) { return *iterator; }
-  static Node* from(Iterator iterator) { return iterator.edge().from(); }
-};
-
-template <class N>
-class NodeUseIterationTraits {
- public:
-  typedef N Node;
-  typedef typename N::Uses::iterator Iterator;
-
-  static Iterator begin(Node* node) { return node->uses().begin(); }
-  static Iterator end(Node* node) { return node->uses().end(); }
-  static int max_id(GenericGraphBase* graph) { return graph->NodeCount(); }
-  static Node* to(Iterator iterator) { return *iterator; }
-  static Node* from(Iterator iterator) { return iterator.edge().to(); }
-};
-}
-}
-}  // namespace v8::internal::compiler
-
-#endif  // V8_COMPILER_GENERIC_ALGORITHM_INL_H_
diff --git a/src/compiler/generic-algorithm.h b/src/compiler/generic-algorithm.h
index cd4984f..391757e 100644
--- a/src/compiler/generic-algorithm.h
+++ b/src/compiler/generic-algorithm.h
@@ -6,69 +6,60 @@
 #define V8_COMPILER_GENERIC_ALGORITHM_H_
 
 #include <stack>
+#include <vector>
 
-#include "src/compiler/generic-graph.h"
-#include "src/compiler/generic-node.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/node.h"
 #include "src/zone-containers.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
+class Graph;
+class Node;
+
 // GenericGraphVisit allows visitation of graphs of nodes and edges in pre- and
 // post-order. Visitation uses an explicitly allocated stack rather than the
-// execution stack to avoid stack overflow. Although GenericGraphVisit is
-// primarily intended to traverse networks of nodes through their
-// dependencies and uses, it also can be used to visit any graph-like network
-// by specifying custom traits.
+// execution stack to avoid stack overflow.
 class GenericGraphVisit {
  public:
-  enum Control {
-    CONTINUE = 0x0,  // Continue depth-first normally
-    SKIP = 0x1,      // Skip this node and its successors
-    REENTER = 0x2,   // Allow reentering this node
-    DEFER = SKIP | REENTER
-  };
-
   // struct Visitor {
-  //   Control Pre(Traits::Node* current);
-  //   Control Post(Traits::Node* current);
-  //   void PreEdge(Traits::Node* from, int index, Traits::Node* to);
-  //   void PostEdge(Traits::Node* from, int index, Traits::Node* to);
+  //   void Pre(Node* current);
+  //   void Post(Node* current);
+  //   void PreEdge(Node* from, int index, Node* to);
+  //   void PostEdge(Node* from, int index, Node* to);
   // }
-  template <class Visitor, class Traits, class RootIterator>
-  static void Visit(GenericGraphBase* graph, Zone* zone,
-                    RootIterator root_begin, RootIterator root_end,
-                    Visitor* visitor) {
-    typedef typename Traits::Node Node;
-    typedef typename Traits::Iterator Iterator;
+  template <class Visitor>
+  static void Visit(Graph* graph, Zone* zone, Node** root_begin,
+                    Node** root_end, Visitor* visitor) {
+    typedef typename Node::InputEdges::iterator Iterator;
     typedef std::pair<Iterator, Iterator> NodeState;
     typedef std::stack<NodeState, ZoneDeque<NodeState> > NodeStateStack;
     NodeStateStack stack((ZoneDeque<NodeState>(zone)));
-    BoolVector visited(Traits::max_id(graph), false, zone);
+    BoolVector visited(graph->NodeCount(), false, zone);
     Node* current = *root_begin;
     while (true) {
       DCHECK(current != NULL);
       const int id = current->id();
       DCHECK(id >= 0);
-      DCHECK(id < Traits::max_id(graph));  // Must be a valid id.
+      DCHECK(id < graph->NodeCount());  // Must be a valid id.
       bool visit = !GetVisited(&visited, id);
       if (visit) {
-        Control control = visitor->Pre(current);
-        visit = !IsSkip(control);
-        if (!IsReenter(control)) SetVisited(&visited, id, true);
+        visitor->Pre(current);
+        SetVisited(&visited, id);
       }
-      Iterator begin(visit ? Traits::begin(current) : Traits::end(current));
-      Iterator end(Traits::end(current));
+      Iterator begin(visit ? current->input_edges().begin()
+                           : current->input_edges().end());
+      Iterator end(current->input_edges().end());
       stack.push(NodeState(begin, end));
       Node* post_order_node = current;
       while (true) {
         NodeState top = stack.top();
         if (top.first == top.second) {
           if (visit) {
-            Control control = visitor->Post(post_order_node);
-            DCHECK(!IsSkip(control));
-            SetVisited(&visited, post_order_node->id(), !IsReenter(control));
+            visitor->Post(post_order_node);
+            SetVisited(&visited, post_order_node->id());
           }
           stack.pop();
           if (stack.empty()) {
@@ -76,48 +67,42 @@
             current = *root_begin;
             break;
           }
-          post_order_node = Traits::from(stack.top().first);
+          post_order_node = (*stack.top().first).from();
           visit = true;
         } else {
-          visitor->PreEdge(Traits::from(top.first), top.first.edge().index(),
-                           Traits::to(top.first));
-          current = Traits::to(top.first);
+          visitor->PreEdge((*top.first).from(), (*top.first).index(),
+                           (*top.first).to());
+          current = (*top.first).to();
           if (!GetVisited(&visited, current->id())) break;
         }
         top = stack.top();
-        visitor->PostEdge(Traits::from(top.first), top.first.edge().index(),
-                          Traits::to(top.first));
+        visitor->PostEdge((*top.first).from(), (*top.first).index(),
+                          (*top.first).to());
         ++stack.top().first;
       }
     }
   }
 
-  template <class Visitor, class Traits>
-  static void Visit(GenericGraphBase* graph, Zone* zone,
-                    typename Traits::Node* current, Visitor* visitor) {
-    typename Traits::Node* array[] = {current};
-    Visit<Visitor, Traits>(graph, zone, &array[0], &array[1], visitor);
+  template <class Visitor>
+  static void Visit(Graph* graph, Zone* zone, Node* current, Visitor* visitor) {
+    Node* array[] = {current};
+    Visit<Visitor>(graph, zone, &array[0], &array[1], visitor);
   }
 
-  template <class B, class S>
   struct NullNodeVisitor {
-    Control Pre(GenericNode<B, S>* node) { return CONTINUE; }
-    Control Post(GenericNode<B, S>* node) { return CONTINUE; }
-    void PreEdge(GenericNode<B, S>* from, int index, GenericNode<B, S>* to) {}
-    void PostEdge(GenericNode<B, S>* from, int index, GenericNode<B, S>* to) {}
+    void Pre(Node* node) {}
+    void Post(Node* node) {}
+    void PreEdge(Node* from, int index, Node* to) {}
+    void PostEdge(Node* from, int index, Node* to) {}
   };
 
  private:
-  static bool IsSkip(Control c) { return c & SKIP; }
-  static bool IsReenter(Control c) { return c & REENTER; }
-
-  // TODO(turbofan): resizing could be optionally templatized away.
-  static void SetVisited(BoolVector* visited, int id, bool value) {
+  static void SetVisited(BoolVector* visited, int id) {
     if (id >= static_cast<int>(visited->size())) {
       // Resize and set all values to unvisited.
       visited->resize((3 * id) / 2, false);
     }
-    visited->at(id) = value;
+    visited->at(id) = true;
   }
 
   static bool GetVisited(BoolVector* visited, int id) {
@@ -125,8 +110,11 @@
     return visited->at(id);
   }
 };
-}
-}
-}  // namespace v8::internal::compiler
+
+typedef GenericGraphVisit::NullNodeVisitor NullNodeVisitor;
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_GENERIC_ALGORITHM_H_
diff --git a/src/compiler/generic-graph.h b/src/compiler/generic-graph.h
deleted file mode 100644
index a555456..0000000
--- a/src/compiler/generic-graph.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_COMPILER_GENERIC_GRAPH_H_
-#define V8_COMPILER_GENERIC_GRAPH_H_
-
-#include "src/compiler/generic-node.h"
-
-namespace v8 {
-namespace internal {
-
-class Zone;
-
-namespace compiler {
-
-class GenericGraphBase : public ZoneObject {
- public:
-  explicit GenericGraphBase(Zone* zone) : zone_(zone), next_node_id_(0) {}
-
-  Zone* zone() const { return zone_; }
-
-  NodeId NextNodeID() { return next_node_id_++; }
-  NodeId NodeCount() const { return next_node_id_; }
-
- private:
-  Zone* zone_;
-  NodeId next_node_id_;
-};
-
-template <class V>
-class GenericGraph : public GenericGraphBase {
- public:
-  explicit GenericGraph(Zone* zone)
-      : GenericGraphBase(zone), start_(NULL), end_(NULL) {}
-
-  V* start() { return start_; }
-  V* end() { return end_; }
-
-  void SetStart(V* start) { start_ = start; }
-  void SetEnd(V* end) { end_ = end; }
-
- private:
-  V* start_;
-  V* end_;
-
-  DISALLOW_COPY_AND_ASSIGN(GenericGraph);
-};
-}
-}
-}  // namespace v8::internal::compiler
-
-#endif  // V8_COMPILER_GENERIC_GRAPH_H_
diff --git a/src/compiler/generic-node-inl.h b/src/compiler/generic-node-inl.h
deleted file mode 100644
index c2dc24e..0000000
--- a/src/compiler/generic-node-inl.h
+++ /dev/null
@@ -1,256 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_COMPILER_GENERIC_NODE_INL_H_
-#define V8_COMPILER_GENERIC_NODE_INL_H_
-
-#include "src/v8.h"
-
-#include "src/compiler/generic-graph.h"
-#include "src/compiler/generic-node.h"
-#include "src/zone.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-template <class B, class S>
-GenericNode<B, S>::GenericNode(GenericGraphBase* graph, int input_count)
-    : BaseClass(graph->zone()),
-      input_count_(input_count),
-      has_appendable_inputs_(false),
-      use_count_(0),
-      first_use_(NULL),
-      last_use_(NULL) {
-  inputs_.static_ = reinterpret_cast<Input*>(this + 1), AssignUniqueID(graph);
-}
-
-template <class B, class S>
-inline void GenericNode<B, S>::AssignUniqueID(GenericGraphBase* graph) {
-  id_ = graph->NextNodeID();
-}
-
-template <class B, class S>
-inline typename GenericNode<B, S>::Inputs::iterator
-GenericNode<B, S>::Inputs::begin() {
-  return typename GenericNode<B, S>::Inputs::iterator(this->node_, 0);
-}
-
-template <class B, class S>
-inline typename GenericNode<B, S>::Inputs::iterator
-GenericNode<B, S>::Inputs::end() {
-  return typename GenericNode<B, S>::Inputs::iterator(
-      this->node_, this->node_->InputCount());
-}
-
-template <class B, class S>
-inline typename GenericNode<B, S>::Uses::iterator
-GenericNode<B, S>::Uses::begin() {
-  return typename GenericNode<B, S>::Uses::iterator(this->node_);
-}
-
-template <class B, class S>
-inline typename GenericNode<B, S>::Uses::iterator
-GenericNode<B, S>::Uses::end() {
-  return typename GenericNode<B, S>::Uses::iterator();
-}
-
-template <class B, class S>
-void GenericNode<B, S>::ReplaceUses(GenericNode* replace_to) {
-  for (Use* use = first_use_; use != NULL; use = use->next) {
-    use->from->GetInputRecordPtr(use->input_index)->to = replace_to;
-  }
-  if (replace_to->last_use_ == NULL) {
-    DCHECK_EQ(NULL, replace_to->first_use_);
-    replace_to->first_use_ = first_use_;
-    replace_to->last_use_ = last_use_;
-  } else if (first_use_ != NULL) {
-    DCHECK_NE(NULL, replace_to->first_use_);
-    replace_to->last_use_->next = first_use_;
-    first_use_->prev = replace_to->last_use_;
-    replace_to->last_use_ = last_use_;
-  }
-  replace_to->use_count_ += use_count_;
-  use_count_ = 0;
-  first_use_ = NULL;
-  last_use_ = NULL;
-}
-
-template <class B, class S>
-template <class UnaryPredicate>
-void GenericNode<B, S>::ReplaceUsesIf(UnaryPredicate pred,
-                                      GenericNode* replace_to) {
-  for (Use* use = first_use_; use != NULL;) {
-    Use* next = use->next;
-    if (pred(static_cast<S*>(use->from))) {
-      RemoveUse(use);
-      replace_to->AppendUse(use);
-      use->from->GetInputRecordPtr(use->input_index)->to = replace_to;
-    }
-    use = next;
-  }
-}
-
-template <class B, class S>
-void GenericNode<B, S>::RemoveAllInputs() {
-  for (typename Inputs::iterator iter(inputs().begin()); iter != inputs().end();
-       ++iter) {
-    iter.GetInput()->Update(NULL);
-  }
-}
-
-template <class B, class S>
-void GenericNode<B, S>::TrimInputCount(int new_input_count) {
-  if (new_input_count == input_count_) return;  // Nothing to do.
-
-  DCHECK(new_input_count < input_count_);
-
-  // Update inline inputs.
-  for (int i = new_input_count; i < input_count_; i++) {
-    typename GenericNode<B, S>::Input* input = GetInputRecordPtr(i);
-    input->Update(NULL);
-  }
-  input_count_ = new_input_count;
-}
-
-template <class B, class S>
-void GenericNode<B, S>::ReplaceInput(int index, GenericNode<B, S>* new_to) {
-  Input* input = GetInputRecordPtr(index);
-  input->Update(new_to);
-}
-
-template <class B, class S>
-void GenericNode<B, S>::Input::Update(GenericNode<B, S>* new_to) {
-  GenericNode* old_to = this->to;
-  if (new_to == old_to) return;  // Nothing to do.
-  // Snip out the use from where it used to be
-  if (old_to != NULL) {
-    old_to->RemoveUse(use);
-  }
-  to = new_to;
-  // And put it into the new node's use list.
-  if (new_to != NULL) {
-    new_to->AppendUse(use);
-  } else {
-    use->next = NULL;
-    use->prev = NULL;
-  }
-}
-
-template <class B, class S>
-void GenericNode<B, S>::EnsureAppendableInputs(Zone* zone) {
-  if (!has_appendable_inputs_) {
-    void* deque_buffer = zone->New(sizeof(InputDeque));
-    InputDeque* deque = new (deque_buffer) InputDeque(zone);
-    for (int i = 0; i < input_count_; ++i) {
-      deque->push_back(inputs_.static_[i]);
-    }
-    inputs_.appendable_ = deque;
-    has_appendable_inputs_ = true;
-  }
-}
-
-template <class B, class S>
-void GenericNode<B, S>::AppendInput(Zone* zone, GenericNode<B, S>* to_append) {
-  EnsureAppendableInputs(zone);
-  Use* new_use = new (zone) Use;
-  Input new_input;
-  new_input.to = to_append;
-  new_input.use = new_use;
-  inputs_.appendable_->push_back(new_input);
-  new_use->input_index = input_count_;
-  new_use->from = this;
-  to_append->AppendUse(new_use);
-  input_count_++;
-}
-
-template <class B, class S>
-void GenericNode<B, S>::InsertInput(Zone* zone, int index,
-                                    GenericNode<B, S>* to_insert) {
-  DCHECK(index >= 0 && index < InputCount());
-  // TODO(turbofan): Optimize this implementation!
-  AppendInput(zone, InputAt(InputCount() - 1));
-  for (int i = InputCount() - 1; i > index; --i) {
-    ReplaceInput(i, InputAt(i - 1));
-  }
-  ReplaceInput(index, to_insert);
-}
-
-template <class B, class S>
-void GenericNode<B, S>::RemoveInput(int index) {
-  DCHECK(index >= 0 && index < InputCount());
-  // TODO(turbofan): Optimize this implementation!
-  for (; index < InputCount() - 1; ++index) {
-    ReplaceInput(index, InputAt(index + 1));
-  }
-  TrimInputCount(InputCount() - 1);
-}
-
-template <class B, class S>
-void GenericNode<B, S>::AppendUse(Use* use) {
-  use->next = NULL;
-  use->prev = last_use_;
-  if (last_use_ == NULL) {
-    first_use_ = use;
-  } else {
-    last_use_->next = use;
-  }
-  last_use_ = use;
-  ++use_count_;
-}
-
-template <class B, class S>
-void GenericNode<B, S>::RemoveUse(Use* use) {
-  if (last_use_ == use) {
-    last_use_ = use->prev;
-  }
-  if (use->prev != NULL) {
-    use->prev->next = use->next;
-  } else {
-    first_use_ = use->next;
-  }
-  if (use->next != NULL) {
-    use->next->prev = use->prev;
-  }
-  --use_count_;
-}
-
-template <class B, class S>
-inline bool GenericNode<B, S>::OwnedBy(GenericNode* owner) const {
-  return first_use_ != NULL && first_use_->from == owner &&
-         first_use_->next == NULL;
-}
-
-template <class B, class S>
-S* GenericNode<B, S>::New(GenericGraphBase* graph, int input_count,
-                          S** inputs) {
-  size_t node_size = sizeof(GenericNode);
-  size_t inputs_size = input_count * sizeof(Input);
-  size_t uses_size = input_count * sizeof(Use);
-  int size = static_cast<int>(node_size + inputs_size + uses_size);
-  Zone* zone = graph->zone();
-  void* buffer = zone->New(size);
-  S* result = new (buffer) S(graph, input_count);
-  Input* input =
-      reinterpret_cast<Input*>(reinterpret_cast<char*>(buffer) + node_size);
-  Use* use =
-      reinterpret_cast<Use*>(reinterpret_cast<char*>(input) + inputs_size);
-
-  for (int current = 0; current < input_count; ++current) {
-    GenericNode* to = *inputs++;
-    input->to = to;
-    input->use = use;
-    use->input_index = current;
-    use->from = result;
-    to->AppendUse(use);
-    ++use;
-    ++input;
-  }
-  return result;
-}
-}
-}
-}  // namespace v8::internal::compiler
-
-#endif  // V8_COMPILER_GENERIC_NODE_INL_H_
diff --git a/src/compiler/generic-node.h b/src/compiler/generic-node.h
deleted file mode 100644
index 3dc324d..0000000
--- a/src/compiler/generic-node.h
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_COMPILER_GENERIC_NODE_H_
-#define V8_COMPILER_GENERIC_NODE_H_
-
-#include "src/v8.h"
-
-#include "src/zone-containers.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-class GenericGraphBase;
-
-typedef int NodeId;
-
-// A GenericNode<> is the basic primitive of graphs. GenericNode's are
-// chained together by input/use chains but by default otherwise contain only an
-// identifying number which specific applications of graphs and nodes can use
-// to index auxiliary out-of-line data, especially transient data.
-// Specializations of the templatized GenericNode<> class must provide a base
-// class B that contains all of the members to be made available in each
-// specialized Node instance. GenericNode uses a mixin template pattern to
-// ensure that common accessors and methods expect the derived class S type
-// rather than the GenericNode<B, S> type.
-template <class B, class S>
-class GenericNode : public B {
- public:
-  typedef B BaseClass;
-  typedef S DerivedClass;
-
-  inline NodeId id() const { return id_; }
-
-  int InputCount() const { return input_count_; }
-  S* InputAt(int index) const {
-    return static_cast<S*>(GetInputRecordPtr(index)->to);
-  }
-  inline void ReplaceInput(int index, GenericNode* new_input);
-  inline void AppendInput(Zone* zone, GenericNode* new_input);
-  inline void InsertInput(Zone* zone, int index, GenericNode* new_input);
-  inline void RemoveInput(int index);
-
-  int UseCount() { return use_count_; }
-  S* UseAt(int index) {
-    DCHECK(index < use_count_);
-    Use* current = first_use_;
-    while (index-- != 0) {
-      current = current->next;
-    }
-    return static_cast<S*>(current->from);
-  }
-  inline void ReplaceUses(GenericNode* replace_to);
-  template <class UnaryPredicate>
-  inline void ReplaceUsesIf(UnaryPredicate pred, GenericNode* replace_to);
-  inline void RemoveAllInputs();
-
-  inline void TrimInputCount(int input_count);
-
-  class Inputs {
-   public:
-    class iterator;
-    iterator begin();
-    iterator end();
-
-    explicit Inputs(GenericNode* node) : node_(node) {}
-
-   private:
-    GenericNode* node_;
-  };
-
-  Inputs inputs() { return Inputs(this); }
-
-  class Uses {
-   public:
-    class iterator;
-    iterator begin();
-    iterator end();
-    bool empty() { return begin() == end(); }
-
-    explicit Uses(GenericNode* node) : node_(node) {}
-
-   private:
-    GenericNode* node_;
-  };
-
-  Uses uses() { return Uses(this); }
-
-  class Edge;
-
-  bool OwnedBy(GenericNode* owner) const;
-
-  static S* New(GenericGraphBase* graph, int input_count, S** inputs);
-
- protected:
-  friend class GenericGraphBase;
-
-  class Use : public ZoneObject {
-   public:
-    GenericNode* from;
-    Use* next;
-    Use* prev;
-    int input_index;
-  };
-
-  class Input {
-   public:
-    GenericNode* to;
-    Use* use;
-
-    void Update(GenericNode* new_to);
-  };
-
-  void EnsureAppendableInputs(Zone* zone);
-
-  Input* GetInputRecordPtr(int index) const {
-    if (has_appendable_inputs_) {
-      return &((*inputs_.appendable_)[index]);
-    } else {
-      return inputs_.static_ + index;
-    }
-  }
-
-  inline void AppendUse(Use* use);
-  inline void RemoveUse(Use* use);
-
-  void* operator new(size_t, void* location) { return location; }
-
-  GenericNode(GenericGraphBase* graph, int input_count);
-
- private:
-  void AssignUniqueID(GenericGraphBase* graph);
-
-  typedef ZoneDeque<Input> InputDeque;
-
-  NodeId id_;
-  int input_count_ : 31;
-  bool has_appendable_inputs_ : 1;
-  union {
-    // When a node is initially allocated, it uses a static buffer to hold its
-    // inputs under the assumption that the number of outputs will not increase.
-    // When the first input is appended, the static buffer is converted into a
-    // deque to allow for space-efficient growing.
-    Input* static_;
-    InputDeque* appendable_;
-  } inputs_;
-  int use_count_;
-  Use* first_use_;
-  Use* last_use_;
-
-  DISALLOW_COPY_AND_ASSIGN(GenericNode);
-};
-
-// An encapsulation for information associated with a single use of node as a
-// input from another node, allowing access to both the defining node and
-// the ndoe having the input.
-template <class B, class S>
-class GenericNode<B, S>::Edge {
- public:
-  S* from() const { return static_cast<S*>(input_->use->from); }
-  S* to() const { return static_cast<S*>(input_->to); }
-  int index() const {
-    int index = input_->use->input_index;
-    DCHECK(index < input_->use->from->input_count_);
-    return index;
-  }
-
- private:
-  friend class GenericNode<B, S>::Uses::iterator;
-  friend class GenericNode<B, S>::Inputs::iterator;
-
-  explicit Edge(typename GenericNode<B, S>::Input* input) : input_(input) {}
-
-  typename GenericNode<B, S>::Input* input_;
-};
-
-// A forward iterator to visit the nodes which are depended upon by a node
-// in the order of input.
-template <class B, class S>
-class GenericNode<B, S>::Inputs::iterator {
- public:
-  iterator(const typename GenericNode<B, S>::Inputs::iterator& other)  // NOLINT
-      : node_(other.node_),
-        index_(other.index_) {}
-
-  S* operator*() { return static_cast<S*>(GetInput()->to); }
-  typename GenericNode<B, S>::Edge edge() {
-    return typename GenericNode::Edge(GetInput());
-  }
-  bool operator==(const iterator& other) const {
-    return other.index_ == index_ && other.node_ == node_;
-  }
-  bool operator!=(const iterator& other) const { return !(other == *this); }
-  iterator& operator++() {
-    DCHECK(node_ != NULL);
-    DCHECK(index_ < node_->input_count_);
-    ++index_;
-    return *this;
-  }
-  iterator& UpdateToAndIncrement(GenericNode<B, S>* new_to) {
-    typename GenericNode<B, S>::Input* input = GetInput();
-    input->Update(new_to);
-    index_++;
-    return *this;
-  }
-  int index() { return index_; }
-
- private:
-  friend class GenericNode;
-
-  explicit iterator(GenericNode* node, int index)
-      : node_(node), index_(index) {}
-
-  Input* GetInput() const { return node_->GetInputRecordPtr(index_); }
-
-  GenericNode* node_;
-  int index_;
-};
-
-// A forward iterator to visit the uses of a node. The uses are returned in
-// the order in which they were added as inputs.
-template <class B, class S>
-class GenericNode<B, S>::Uses::iterator {
- public:
-  iterator(const typename GenericNode<B, S>::Uses::iterator& other)  // NOLINT
-      : current_(other.current_),
-        index_(other.index_) {}
-
-  S* operator*() { return static_cast<S*>(current_->from); }
-  typename GenericNode<B, S>::Edge edge() {
-    return typename GenericNode::Edge(CurrentInput());
-  }
-
-  bool operator==(const iterator& other) { return other.current_ == current_; }
-  bool operator!=(const iterator& other) { return other.current_ != current_; }
-  iterator& operator++() {
-    DCHECK(current_ != NULL);
-    index_++;
-    current_ = current_->next;
-    return *this;
-  }
-  iterator& UpdateToAndIncrement(GenericNode<B, S>* new_to) {
-    DCHECK(current_ != NULL);
-    index_++;
-    typename GenericNode<B, S>::Input* input = CurrentInput();
-    current_ = current_->next;
-    input->Update(new_to);
-    return *this;
-  }
-  int index() const { return index_; }
-
- private:
-  friend class GenericNode<B, S>::Uses;
-
-  iterator() : current_(NULL), index_(0) {}
-  explicit iterator(GenericNode<B, S>* node)
-      : current_(node->first_use_), index_(0) {}
-
-  Input* CurrentInput() const {
-    return current_->from->GetInputRecordPtr(current_->input_index);
-  }
-
-  typename GenericNode<B, S>::Use* current_;
-  int index_;
-};
-}
-}
-}  // namespace v8::internal::compiler
-
-#endif  // V8_COMPILER_GENERIC_NODE_H_
diff --git a/src/compiler/graph-builder.cc b/src/compiler/graph-builder.cc
index 8992881..6321aaa 100644
--- a/src/compiler/graph-builder.cc
+++ b/src/compiler/graph-builder.cc
@@ -4,53 +4,65 @@
 
 #include "src/compiler/graph-builder.h"
 
+#include "src/bit-vector.h"
 #include "src/compiler.h"
-#include "src/compiler/generic-graph.h"
-#include "src/compiler/generic-node.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph-visualizer.h"
+#include "src/compiler/node.h"
 #include "src/compiler/node-properties.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/operator-properties.h"
-#include "src/compiler/operator-properties-inl.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
 
-StructuredGraphBuilder::StructuredGraphBuilder(Graph* graph,
+StructuredGraphBuilder::StructuredGraphBuilder(Zone* local_zone, Graph* graph,
                                                CommonOperatorBuilder* common)
     : GraphBuilder(graph),
       common_(common),
       environment_(NULL),
+      local_zone_(local_zone),
+      input_buffer_size_(0),
+      input_buffer_(NULL),
       current_context_(NULL),
-      exit_control_(NULL) {}
+      exit_control_(NULL) {
+  EnsureInputBufferSize(kInputBufferSizeIncrement);
+}
+
+
+Node** StructuredGraphBuilder::EnsureInputBufferSize(int size) {
+  if (size > input_buffer_size_) {
+    size += kInputBufferSizeIncrement;
+    input_buffer_ = local_zone()->NewArray<Node*>(size);
+  }
+  return input_buffer_;
+}
 
 
 Node* StructuredGraphBuilder::MakeNode(const Operator* op,
                                        int value_input_count,
-                                       Node** value_inputs) {
-  DCHECK(op->InputCount() == value_input_count);
+                                       Node** value_inputs, bool incomplete) {
+  DCHECK(op->ValueInputCount() == value_input_count);
 
   bool has_context = OperatorProperties::HasContextInput(op);
   bool has_framestate = OperatorProperties::HasFrameStateInput(op);
-  bool has_control = OperatorProperties::GetControlInputCount(op) == 1;
-  bool has_effect = OperatorProperties::GetEffectInputCount(op) == 1;
+  bool has_control = op->ControlInputCount() == 1;
+  bool has_effect = op->EffectInputCount() == 1;
 
-  DCHECK(OperatorProperties::GetControlInputCount(op) < 2);
-  DCHECK(OperatorProperties::GetEffectInputCount(op) < 2);
+  DCHECK(op->ControlInputCount() < 2);
+  DCHECK(op->EffectInputCount() < 2);
 
   Node* result = NULL;
   if (!has_context && !has_framestate && !has_control && !has_effect) {
-    result = graph()->NewNode(op, value_input_count, value_inputs);
+    result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
   } else {
     int input_count_with_deps = value_input_count;
     if (has_context) ++input_count_with_deps;
     if (has_framestate) ++input_count_with_deps;
     if (has_control) ++input_count_with_deps;
     if (has_effect) ++input_count_with_deps;
-    Node** buffer = zone()->NewArray<Node*>(input_count_with_deps);
+    Node** buffer = EnsureInputBufferSize(input_count_with_deps);
     memcpy(buffer, value_inputs, kPointerSize * value_input_count);
     Node** current_input = buffer + value_input_count;
     if (has_context) {
@@ -68,11 +80,11 @@
     if (has_control) {
       *current_input++ = environment_->GetControlDependency();
     }
-    result = graph()->NewNode(op, input_count_with_deps, buffer);
+    result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
     if (has_effect) {
       environment_->UpdateEffectDependency(result);
     }
-    if (OperatorProperties::HasControlOutput(result->op()) &&
+    if (result->op()->ControlOutputCount() > 0 &&
         !environment()->IsMarkedAsUnreachable()) {
       environment_->UpdateControlDependency(result);
     }
@@ -95,7 +107,7 @@
 
 StructuredGraphBuilder::Environment* StructuredGraphBuilder::CopyEnvironment(
     Environment* env) {
-  return new (zone()) Environment(*env);
+  return new (local_zone()) Environment(*env);
 }
 
 
@@ -111,7 +123,11 @@
     : builder_(copy.builder()),
       control_dependency_(copy.control_dependency_),
       effect_dependency_(copy.effect_dependency_),
-      values_(copy.values_) {}
+      values_(copy.zone()) {
+  const size_t kStackEstimate = 7;  // optimum from experimentation!
+  values_.reserve(copy.values_.size() + kStackEstimate);
+  values_.insert(values_.begin(), copy.values_.begin(), copy.values_.end());
+}
 
 
 void StructuredGraphBuilder::Environment::Merge(Environment* other) {
@@ -124,7 +140,9 @@
   // placing a singleton merge as the new control dependency.
   if (this->IsMarkedAsUnreachable()) {
     Node* other_control = other->control_dependency_;
-    control_dependency_ = graph()->NewNode(common()->Merge(1), other_control);
+    Node* inputs[] = {other_control};
+    control_dependency_ =
+        graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true);
     effect_dependency_ = other->effect_dependency_;
     values_ = other->values_;
     return;
@@ -150,11 +168,22 @@
 }
 
 
-void StructuredGraphBuilder::Environment::PrepareForLoop() {
+void StructuredGraphBuilder::Environment::PrepareForLoop(BitVector* assigned) {
   Node* control = GetControlDependency();
-  for (int i = 0; i < static_cast<int>(values()->size()); ++i) {
-    Node* phi = builder_->NewPhi(1, values()->at(i), control);
-    values()->at(i) = phi;
+  int size = static_cast<int>(values()->size());
+  if (assigned == NULL) {
+    // Assume that everything is updated in the loop.
+    for (int i = 0; i < size; ++i) {
+      Node* phi = builder_->NewPhi(1, values()->at(i), control);
+      values()->at(i) = phi;
+    }
+  } else {
+    // Only build phis for those locals assigned in this loop.
+    for (int i = 0; i < size; ++i) {
+      if (i < assigned->length() && !assigned->Contains(i)) continue;
+      Node* phi = builder_->NewPhi(1, values()->at(i), control);
+      values()->at(i) = phi;
+    }
   }
   Node* effect = builder_->NewEffectPhi(1, GetEffectDependency(), control);
   UpdateEffectDependency(effect);
@@ -163,10 +192,10 @@
 
 Node* StructuredGraphBuilder::NewPhi(int count, Node* input, Node* control) {
   const Operator* phi_op = common()->Phi(kMachAnyTagged, count);
-  Node** buffer = zone()->NewArray<Node*>(count + 1);
+  Node** buffer = EnsureInputBufferSize(count + 1);
   MemsetPointer(buffer, input, count);
   buffer[count] = control;
-  return graph()->NewNode(phi_op, count + 1, buffer);
+  return graph()->NewNode(phi_op, count + 1, buffer, true);
 }
 
 
@@ -174,29 +203,30 @@
 Node* StructuredGraphBuilder::NewEffectPhi(int count, Node* input,
                                            Node* control) {
   const Operator* phi_op = common()->EffectPhi(count);
-  Node** buffer = zone()->NewArray<Node*>(count + 1);
+  Node** buffer = EnsureInputBufferSize(count + 1);
   MemsetPointer(buffer, input, count);
   buffer[count] = control;
-  return graph()->NewNode(phi_op, count + 1, buffer);
+  return graph()->NewNode(phi_op, count + 1, buffer, true);
 }
 
 
 Node* StructuredGraphBuilder::MergeControl(Node* control, Node* other) {
-  int inputs = OperatorProperties::GetControlInputCount(control->op()) + 1;
+  int inputs = control->op()->ControlInputCount() + 1;
   if (control->opcode() == IrOpcode::kLoop) {
     // Control node for loop exists, add input.
     const Operator* op = common()->Loop(inputs);
-    control->AppendInput(zone(), other);
+    control->AppendInput(graph_zone(), other);
     control->set_op(op);
   } else if (control->opcode() == IrOpcode::kMerge) {
     // Control node for merge exists, add input.
     const Operator* op = common()->Merge(inputs);
-    control->AppendInput(zone(), other);
+    control->AppendInput(graph_zone(), other);
     control->set_op(op);
   } else {
     // Control node is a singleton, introduce a merge.
     const Operator* op = common()->Merge(inputs);
-    control = graph()->NewNode(op, control, other);
+    Node* inputs[] = {control, other};
+    control = graph()->NewNode(op, arraysize(inputs), inputs, true);
   }
   return control;
 }
@@ -204,12 +234,12 @@
 
 Node* StructuredGraphBuilder::MergeEffect(Node* value, Node* other,
                                           Node* control) {
-  int inputs = OperatorProperties::GetControlInputCount(control->op());
+  int inputs = control->op()->ControlInputCount();
   if (value->opcode() == IrOpcode::kEffectPhi &&
       NodeProperties::GetControlInput(value) == control) {
     // Phi already exists, add input.
     value->set_op(common()->EffectPhi(inputs));
-    value->InsertInput(zone(), inputs - 1, other);
+    value->InsertInput(graph_zone(), inputs - 1, other);
   } else if (value != other) {
     // Phi does not exist yet, introduce one.
     value = NewEffectPhi(inputs, value, control);
@@ -221,12 +251,12 @@
 
 Node* StructuredGraphBuilder::MergeValue(Node* value, Node* other,
                                          Node* control) {
-  int inputs = OperatorProperties::GetControlInputCount(control->op());
+  int inputs = control->op()->ControlInputCount();
   if (value->opcode() == IrOpcode::kPhi &&
       NodeProperties::GetControlInput(value) == control) {
     // Phi already exists, add input.
     value->set_op(common()->Phi(kMachAnyTagged, inputs));
-    value->InsertInput(zone(), inputs - 1, other);
+    value->InsertInput(graph_zone(), inputs - 1, other);
   } else if (value != other) {
     // Phi does not exist yet, introduce one.
     value = NewPhi(inputs, value, control);
diff --git a/src/compiler/graph-builder.h b/src/compiler/graph-builder.h
index c966c29..d88b125 100644
--- a/src/compiler/graph-builder.h
+++ b/src/compiler/graph-builder.h
@@ -14,6 +14,9 @@
 
 namespace v8 {
 namespace internal {
+
+class BitVector;
+
 namespace compiler {
 
 class Node;
@@ -24,42 +27,44 @@
   explicit GraphBuilder(Graph* graph) : graph_(graph) {}
   virtual ~GraphBuilder() {}
 
-  Node* NewNode(const Operator* op) {
-    return MakeNode(op, 0, static_cast<Node**>(NULL));
+  Node* NewNode(const Operator* op, bool incomplete = false) {
+    return MakeNode(op, 0, static_cast<Node**>(NULL), incomplete);
   }
 
-  Node* NewNode(const Operator* op, Node* n1) { return MakeNode(op, 1, &n1); }
+  Node* NewNode(const Operator* op, Node* n1) {
+    return MakeNode(op, 1, &n1, false);
+  }
 
   Node* NewNode(const Operator* op, Node* n1, Node* n2) {
     Node* buffer[] = {n1, n2};
-    return MakeNode(op, arraysize(buffer), buffer);
+    return MakeNode(op, arraysize(buffer), buffer, false);
   }
 
   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3) {
     Node* buffer[] = {n1, n2, n3};
-    return MakeNode(op, arraysize(buffer), buffer);
+    return MakeNode(op, arraysize(buffer), buffer, false);
   }
 
   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4) {
     Node* buffer[] = {n1, n2, n3, n4};
-    return MakeNode(op, arraysize(buffer), buffer);
+    return MakeNode(op, arraysize(buffer), buffer, false);
   }
 
   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4,
                 Node* n5) {
     Node* buffer[] = {n1, n2, n3, n4, n5};
-    return MakeNode(op, arraysize(buffer), buffer);
+    return MakeNode(op, arraysize(buffer), buffer, false);
   }
 
   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4,
                 Node* n5, Node* n6) {
     Node* nodes[] = {n1, n2, n3, n4, n5, n6};
-    return MakeNode(op, arraysize(nodes), nodes);
+    return MakeNode(op, arraysize(nodes), nodes, false);
   }
 
-  Node* NewNode(const Operator* op, int value_input_count,
-                Node** value_inputs) {
-    return MakeNode(op, value_input_count, value_inputs);
+  Node* NewNode(const Operator* op, int value_input_count, Node** value_inputs,
+                bool incomplete = false) {
+    return MakeNode(op, value_input_count, value_inputs, incomplete);
   }
 
   Graph* graph() const { return graph_; }
@@ -67,7 +72,7 @@
  protected:
   // Base implementation used by all factory methods.
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) = 0;
+                         Node** value_inputs, bool incomplete) = 0;
 
  private:
   Graph* graph_;
@@ -79,8 +84,9 @@
 // StubGraphBuilder).
 class StructuredGraphBuilder : public GraphBuilder {
  public:
-  StructuredGraphBuilder(Graph* graph, CommonOperatorBuilder* common);
-  virtual ~StructuredGraphBuilder() {}
+  StructuredGraphBuilder(Zone* zone, Graph* graph,
+                         CommonOperatorBuilder* common);
+  ~StructuredGraphBuilder() OVERRIDE {}
 
   // Creates a new Phi node having {count} input values.
   Node* NewPhi(int count, Node* input, Node* control);
@@ -94,10 +100,10 @@
   // Helpers to create new control nodes.
   Node* NewIfTrue() { return NewNode(common()->IfTrue()); }
   Node* NewIfFalse() { return NewNode(common()->IfFalse()); }
-  Node* NewMerge() { return NewNode(common()->Merge(1)); }
-  Node* NewLoop() { return NewNode(common()->Loop(1)); }
-  Node* NewBranch(Node* condition) {
-    return NewNode(common()->Branch(), condition);
+  Node* NewMerge() { return NewNode(common()->Merge(1), true); }
+  Node* NewLoop() { return NewNode(common()->Loop(1), true); }
+  Node* NewBranch(Node* condition, BranchHint hint = BranchHint::kNone) {
+    return NewNode(common()->Branch(hint), condition);
   }
 
  protected:
@@ -108,8 +114,8 @@
   // The following method creates a new node having the specified operator and
   // ensures effect and control dependencies are wired up. The dependencies
   // tracked by the environment might be mutated.
-  virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) FINAL;
+  Node* MakeNode(const Operator* op, int value_input_count, Node** value_inputs,
+                 bool incomplete) FINAL;
 
   Environment* environment() const { return environment_; }
   void set_environment(Environment* env) { environment_ = env; }
@@ -122,9 +128,9 @@
 
   Node* dead_control();
 
-  // TODO(mstarzinger): Use phase-local zone instead!
-  Zone* zone() const { return graph()->zone(); }
-  Isolate* isolate() const { return zone()->isolate(); }
+  Zone* graph_zone() const { return graph()->zone(); }
+  Zone* local_zone() const { return local_zone_; }
+  Isolate* isolate() const { return graph_zone()->isolate(); }
   CommonOperatorBuilder* common() const { return common_; }
 
   // Helper to wrap a Handle<T> into a Unique<T>.
@@ -144,6 +150,13 @@
   CommonOperatorBuilder* common_;
   Environment* environment_;
 
+  // Zone local to the builder for data not leaking into the graph.
+  Zone* local_zone_;
+
+  // Temporary storage for building node input lists.
+  int input_buffer_size_;
+  Node** input_buffer_;
+
   // Node representing the control dependency for dead code.
   SetOncePointer<Node> dead_control_;
 
@@ -153,6 +166,12 @@
   // Merge of all control nodes that exit the function body.
   Node* exit_control_;
 
+  // Growth increment for the temporary buffer used to construct input lists to
+  // new nodes.
+  static const int kInputBufferSizeIncrement = 64;
+
+  Node** EnsureInputBufferSize(int size);
+
   DISALLOW_COPY_AND_ASSIGN(StructuredGraphBuilder);
 };
 
@@ -199,23 +218,22 @@
   }
 
   // Copies this environment at a loop header control-flow point.
-  Environment* CopyForLoop() {
-    PrepareForLoop();
+  Environment* CopyForLoop(BitVector* assigned) {
+    PrepareForLoop(assigned);
     return builder()->CopyEnvironment(this);
   }
 
   Node* GetContext() { return builder_->current_context(); }
 
  protected:
-  // TODO(mstarzinger): Use phase-local zone instead!
-  Zone* zone() const { return graph()->zone(); }
+  Zone* zone() const { return builder_->local_zone(); }
   Graph* graph() const { return builder_->graph(); }
   StructuredGraphBuilder* builder() const { return builder_; }
   CommonOperatorBuilder* common() { return builder_->common(); }
   NodeVector* values() { return &values_; }
 
   // Prepare environment to be used as loop header.
-  void PrepareForLoop();
+  void PrepareForLoop(BitVector* assigned);
 
  private:
   StructuredGraphBuilder* builder_;
diff --git a/src/compiler/graph-inl.h b/src/compiler/graph-inl.h
index 571ffb3..c135ae5 100644
--- a/src/compiler/graph-inl.h
+++ b/src/compiler/graph-inl.h
@@ -5,7 +5,7 @@
 #ifndef V8_COMPILER_GRAPH_INL_H_
 #define V8_COMPILER_GRAPH_INL_H_
 
-#include "src/compiler/generic-algorithm-inl.h"
+#include "src/compiler/generic-algorithm.h"
 #include "src/compiler/graph.h"
 
 namespace v8 {
@@ -13,25 +13,13 @@
 namespace compiler {
 
 template <class Visitor>
-void Graph::VisitNodeUsesFrom(Node* node, Visitor* visitor) {
-  GenericGraphVisit::Visit<Visitor, NodeUseIterationTraits<Node> >(
-      this, zone(), node, visitor);
-}
-
-
-template <class Visitor>
-void Graph::VisitNodeUsesFromStart(Visitor* visitor) {
-  VisitNodeUsesFrom(start(), visitor);
-}
-
-
-template <class Visitor>
 void Graph::VisitNodeInputsFromEnd(Visitor* visitor) {
-  GenericGraphVisit::Visit<Visitor, NodeInputIterationTraits<Node> >(
-      this, zone(), end(), visitor);
+  Zone tmp_zone(zone()->isolate());
+  GenericGraphVisit::Visit<Visitor>(this, &tmp_zone, end(), visitor);
 }
-}
-}
-}  // namespace v8::internal::compiler
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_GRAPH_INL_H_
diff --git a/src/compiler/graph-reducer-unittest.cc b/src/compiler/graph-reducer-unittest.cc
deleted file mode 100644
index 6567203..0000000
--- a/src/compiler/graph-reducer-unittest.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/graph.h"
-#include "src/compiler/graph-reducer.h"
-#include "src/compiler/operator.h"
-#include "src/test/test-utils.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using testing::_;
-using testing::DefaultValue;
-using testing::Return;
-using testing::Sequence;
-using testing::StrictMock;
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-namespace {
-
-SimpleOperator OP0(0, Operator::kNoWrite, 0, 1, "op0");
-SimpleOperator OP1(1, Operator::kNoProperties, 1, 1, "op1");
-
-
-struct MockReducer : public Reducer {
-  MOCK_METHOD1(Reduce, Reduction(Node*));
-};
-
-}  // namespace
-
-
-class GraphReducerTest : public TestWithZone {
- public:
-  GraphReducerTest() : graph_(zone()) {}
-
-  static void SetUpTestCase() {
-    TestWithZone::SetUpTestCase();
-    DefaultValue<Reduction>::Set(Reducer::NoChange());
-  }
-
-  static void TearDownTestCase() {
-    DefaultValue<Reduction>::Clear();
-    TestWithZone::TearDownTestCase();
-  }
-
- protected:
-  void ReduceNode(Node* node, Reducer* r) {
-    GraphReducer reducer(graph());
-    reducer.AddReducer(r);
-    reducer.ReduceNode(node);
-  }
-
-  void ReduceNode(Node* node, Reducer* r1, Reducer* r2) {
-    GraphReducer reducer(graph());
-    reducer.AddReducer(r1);
-    reducer.AddReducer(r2);
-    reducer.ReduceNode(node);
-  }
-
-  void ReduceNode(Node* node, Reducer* r1, Reducer* r2, Reducer* r3) {
-    GraphReducer reducer(graph());
-    reducer.AddReducer(r1);
-    reducer.AddReducer(r2);
-    reducer.AddReducer(r3);
-    reducer.ReduceNode(node);
-  }
-
-  Graph* graph() { return &graph_; }
-
- private:
-  Graph graph_;
-};
-
-
-TEST_F(GraphReducerTest, NodeIsDeadAfterReplace) {
-  StrictMock<MockReducer> r;
-  Node* node0 = graph()->NewNode(&OP0);
-  Node* node1 = graph()->NewNode(&OP1, node0);
-  Node* node2 = graph()->NewNode(&OP1, node0);
-  EXPECT_CALL(r, Reduce(node1)).WillOnce(Return(Reducer::Replace(node2)));
-  ReduceNode(node1, &r);
-  EXPECT_FALSE(node0->IsDead());
-  EXPECT_TRUE(node1->IsDead());
-  EXPECT_FALSE(node2->IsDead());
-}
-
-
-TEST_F(GraphReducerTest, ReduceOnceForEveryReducer) {
-  StrictMock<MockReducer> r1, r2;
-  Node* node0 = graph()->NewNode(&OP0);
-  EXPECT_CALL(r1, Reduce(node0));
-  EXPECT_CALL(r2, Reduce(node0));
-  ReduceNode(node0, &r1, &r2);
-}
-
-
-TEST_F(GraphReducerTest, ReduceAgainAfterChanged) {
-  Sequence s1, s2;
-  StrictMock<MockReducer> r1, r2, r3;
-  Node* node0 = graph()->NewNode(&OP0);
-  EXPECT_CALL(r1, Reduce(node0));
-  EXPECT_CALL(r2, Reduce(node0));
-  EXPECT_CALL(r3, Reduce(node0)).InSequence(s1, s2).WillOnce(
-      Return(Reducer::Changed(node0)));
-  EXPECT_CALL(r1, Reduce(node0)).InSequence(s1);
-  EXPECT_CALL(r2, Reduce(node0)).InSequence(s2);
-  ReduceNode(node0, &r1, &r2, &r3);
-}
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/graph-reducer.cc b/src/compiler/graph-reducer.cc
index 36a54e0..9a6b121 100644
--- a/src/compiler/graph-reducer.cc
+++ b/src/compiler/graph-reducer.cc
@@ -12,86 +12,190 @@
 namespace internal {
 namespace compiler {
 
-GraphReducer::GraphReducer(Graph* graph)
-    : graph_(graph), reducers_(graph->zone()) {}
+enum class GraphReducer::State : uint8_t {
+  kUnvisited,
+  kRevisit,
+  kOnStack,
+  kVisited
+};
 
 
-static bool NodeIdIsLessThan(const Node* node, NodeId id) {
-  return node->id() < id;
+GraphReducer::GraphReducer(Graph* graph, Zone* zone)
+    : graph_(graph),
+      state_(graph, 4),
+      reducers_(zone),
+      revisit_(zone),
+      stack_(zone) {}
+
+
+void GraphReducer::AddReducer(Reducer* reducer) {
+  reducers_.push_back(reducer);
 }
 
 
 void GraphReducer::ReduceNode(Node* node) {
-  ZoneVector<Reducer*>::iterator skip = reducers_.end();
-  static const unsigned kMaxAttempts = 16;
-  bool reduce = true;
-  for (unsigned attempts = 0; attempts <= kMaxAttempts; ++attempts) {
-    if (!reduce) return;
-    reduce = false;  // Assume we don't need to rerun any reducers.
-    int before = graph_->NodeCount();
-    for (ZoneVector<Reducer*>::iterator i = reducers_.begin();
-         i != reducers_.end(); ++i) {
-      if (i == skip) continue;  // Skip this reducer.
-      Reduction reduction = (*i)->Reduce(node);
-      Node* replacement = reduction.replacement();
-      if (replacement == NULL) {
-        // No change from this reducer.
-      } else if (replacement == node) {
-        // {replacement == node} represents an in-place reduction.
-        // Rerun all the reducers except the current one for this node,
-        // as now there may be more opportunities for reduction.
-        reduce = true;
-        skip = i;
-        break;
-      } else {
-        if (node == graph_->start()) graph_->SetStart(replacement);
-        if (node == graph_->end()) graph_->SetEnd(replacement);
-        // If {node} was replaced by an old node, unlink {node} and assume that
-        // {replacement} was already reduced and finish.
-        if (replacement->id() < before) {
-          node->ReplaceUses(replacement);
-          node->Kill();
-          return;
-        }
-        // Otherwise, {node} was replaced by a new node. Replace all old uses of
-        // {node} with {replacement}. New nodes created by this reduction can
-        // use {node}.
-        node->ReplaceUsesIf(
-            std::bind2nd(std::ptr_fun(&NodeIdIsLessThan), before), replacement);
-        // Unlink {node} if it's no longer used.
-        if (node->uses().empty()) {
-          node->Kill();
-        }
-        // Rerun all the reductions on the {replacement}.
-        skip = reducers_.end();
-        node = replacement;
-        reduce = true;
-        break;
+  DCHECK(stack_.empty());
+  DCHECK(revisit_.empty());
+  Push(node);
+  for (;;) {
+    if (!stack_.empty()) {
+      // Process the node on the top of the stack, potentially pushing more or
+      // popping the node off the stack.
+      ReduceTop();
+    } else if (!revisit_.empty()) {
+      // If the stack becomes empty, revisit any nodes in the revisit queue.
+      Node* const node = revisit_.top();
+      revisit_.pop();
+      if (state_.Get(node) == State::kRevisit) {
+        // state can change while in queue.
+        Push(node);
       }
+    } else {
+      break;
+    }
+  }
+  DCHECK(revisit_.empty());
+  DCHECK(stack_.empty());
+}
+
+
+void GraphReducer::ReduceGraph() { ReduceNode(graph()->end()); }
+
+
+Reduction GraphReducer::Reduce(Node* const node) {
+  auto skip = reducers_.end();
+  for (auto i = reducers_.begin(); i != reducers_.end();) {
+    if (i != skip) {
+      Reduction reduction = (*i)->Reduce(node);
+      if (!reduction.Changed()) {
+        // No change from this reducer.
+      } else if (reduction.replacement() == node) {
+        // {replacement} == {node} represents an in-place reduction. Rerun
+        // all the other reducers for this node, as now there may be more
+        // opportunities for reduction.
+        skip = i;
+        i = reducers_.begin();
+        continue;
+      } else {
+        // {node} was replaced by another node.
+        return reduction;
+      }
+    }
+    ++i;
+  }
+  if (skip == reducers_.end()) {
+    // No change from any reducer.
+    return Reducer::NoChange();
+  }
+  // At least one reducer did some in-place reduction.
+  return Reducer::Changed(node);
+}
+
+
+void GraphReducer::ReduceTop() {
+  NodeState& entry = stack_.top();
+  Node* node = entry.node;
+  DCHECK(state_.Get(node) == State::kOnStack);
+
+  if (node->IsDead()) return Pop();  // Node was killed while on stack.
+
+  // Recurse on an input if necessary.
+  int start = entry.input_index < node->InputCount() ? entry.input_index : 0;
+  for (int i = start; i < node->InputCount(); i++) {
+    Node* input = node->InputAt(i);
+    entry.input_index = i + 1;
+    if (input != node && Recurse(input)) return;
+  }
+  for (int i = 0; i < start; i++) {
+    Node* input = node->InputAt(i);
+    entry.input_index = i + 1;
+    if (input != node && Recurse(input)) return;
+  }
+
+  // Remember the node count before reduction.
+  const int node_count = graph()->NodeCount();
+
+  // All inputs should be visited or on stack. Apply reductions to node.
+  Reduction reduction = Reduce(node);
+
+  // If there was no reduction, pop {node} and continue.
+  if (!reduction.Changed()) return Pop();
+
+  // Check if the reduction is an in-place update of the {node}.
+  Node* const replacement = reduction.replacement();
+  if (replacement == node) {
+    // In-place update of {node}, may need to recurse on an input.
+    for (int i = 0; i < node->InputCount(); ++i) {
+      Node* input = node->InputAt(i);
+      entry.input_index = i + 1;
+      if (input != node && Recurse(input)) return;
+    }
+  }
+
+  // After reducing the node, pop it off the stack.
+  Pop();
+
+  // Revisit all uses of the node.
+  for (Node* const use : node->uses()) {
+    // Don't revisit this node if it refers to itself.
+    if (use != node) Revisit(use);
+  }
+
+  // Check if we have a new replacement.
+  if (replacement != node) {
+    if (node == graph()->start()) graph()->SetStart(replacement);
+    if (node == graph()->end()) graph()->SetEnd(replacement);
+    // If {node} was replaced by an old node, unlink {node} and assume that
+    // {replacement} was already reduced and finish.
+    if (replacement->id() < node_count) {
+      node->ReplaceUses(replacement);
+      node->Kill();
+    } else {
+      // Otherwise {node} was replaced by a new node. Replace all old uses of
+      // {node} with {replacement}. New nodes created by this reduction can
+      // use {node}.
+      node->ReplaceUsesIf(
+          [node_count](Node* const node) { return node->id() < node_count; },
+          replacement);
+      // Unlink {node} if it's no longer used.
+      if (node->uses().empty()) {
+        node->Kill();
+      }
+
+      // If there was a replacement, reduce it after popping {node}.
+      Recurse(replacement);
     }
   }
 }
 
 
-// A helper class to reuse the node traversal algorithm.
-struct GraphReducerVisitor FINAL : public NullNodeVisitor {
-  explicit GraphReducerVisitor(GraphReducer* reducer) : reducer_(reducer) {}
-  GenericGraphVisit::Control Post(Node* node) {
-    reducer_->ReduceNode(node);
-    return GenericGraphVisit::CONTINUE;
-  }
-  GraphReducer* reducer_;
-};
-
-
-void GraphReducer::ReduceGraph() {
-  GraphReducerVisitor visitor(this);
-  // Perform a post-order reduction of all nodes starting from the end.
-  graph()->VisitNodeInputsFromEnd(&visitor);
+void GraphReducer::Pop() {
+  Node* node = stack_.top().node;
+  state_.Set(node, State::kVisited);
+  stack_.pop();
 }
 
 
-// TODO(titzer): partial graph reductions.
+void GraphReducer::Push(Node* const node) {
+  DCHECK(state_.Get(node) != State::kOnStack);
+  state_.Set(node, State::kOnStack);
+  stack_.push({node, 0});
+}
+
+
+bool GraphReducer::Recurse(Node* node) {
+  if (state_.Get(node) > State::kRevisit) return false;
+  Push(node);
+  return true;
+}
+
+
+void GraphReducer::Revisit(Node* node) {
+  if (state_.Get(node) == State::kVisited) {
+    state_.Set(node, State::kRevisit);
+    revisit_.push(node);
+  }
+}
 
 }  // namespace compiler
 }  // namespace internal
diff --git a/src/compiler/graph-reducer.h b/src/compiler/graph-reducer.h
index e0e4f7a..09a650c 100644
--- a/src/compiler/graph-reducer.h
+++ b/src/compiler/graph-reducer.h
@@ -5,17 +5,13 @@
 #ifndef V8_COMPILER_GRAPH_REDUCER_H_
 #define V8_COMPILER_GRAPH_REDUCER_H_
 
+#include "src/compiler/graph.h"
 #include "src/zone-containers.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
-// Forward declarations.
-class Graph;
-class Node;
-
-
 // Represents the result of trying to reduce a node in the graph.
 class Reduction FINAL {
  public:
@@ -55,20 +51,42 @@
 // Performs an iterative reduction of a node graph.
 class GraphReducer FINAL {
  public:
-  explicit GraphReducer(Graph* graph);
+  GraphReducer(Graph* graph, Zone* zone);
 
   Graph* graph() const { return graph_; }
 
-  void AddReducer(Reducer* reducer) { reducers_.push_back(reducer); }
+  void AddReducer(Reducer* reducer);
 
   // Reduce a single node.
-  void ReduceNode(Node* node);
+  void ReduceNode(Node* const);
   // Reduce the whole graph.
   void ReduceGraph();
 
  private:
+  enum class State : uint8_t;
+  struct NodeState {
+    Node* node;
+    int input_index;
+  };
+
+  // Reduce a single node.
+  Reduction Reduce(Node* const);
+  // Reduce the node on top of the stack.
+  void ReduceTop();
+
+  // Node stack operations.
+  void Pop();
+  void Push(Node* node);
+
+  // Revisit queue operations.
+  bool Recurse(Node* node);
+  void Revisit(Node* node);
+
   Graph* graph_;
+  NodeMarker<State> state_;
   ZoneVector<Reducer*> reducers_;
+  ZoneStack<Node*> revisit_;
+  ZoneStack<NodeState> stack_;
 
   DISALLOW_COPY_AND_ASSIGN(GraphReducer);
 };
diff --git a/src/compiler/graph-replay.cc b/src/compiler/graph-replay.cc
index 494d431..3a0b783 100644
--- a/src/compiler/graph-replay.cc
+++ b/src/compiler/graph-replay.cc
@@ -9,7 +9,7 @@
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/node.h"
 #include "src/compiler/operator.h"
-#include "src/compiler/operator-properties-inl.h"
+#include "src/compiler/operator-properties.h"
 
 namespace v8 {
 namespace internal {
@@ -24,14 +24,13 @@
 }
 
 
-GenericGraphVisit::Control GraphReplayPrinter::Pre(Node* node) {
+void GraphReplayPrinter::Pre(Node* node) {
   PrintReplayOpCreator(node->op());
   PrintF("  Node* n%d = graph.NewNode(op", node->id());
   for (int i = 0; i < node->InputCount(); ++i) {
     PrintF(", nil");
   }
   PrintF("); USE(n%d);\n", node->id());
-  return GenericGraphVisit::CONTINUE;
 }
 
 
@@ -60,14 +59,14 @@
       PrintF("unique_constant");
       break;
     case IrOpcode::kPhi:
-      PrintF("%d", op->InputCount());
+      PrintF("%d", op->ValueInputCount());
       break;
     case IrOpcode::kEffectPhi:
-      PrintF("%d", OperatorProperties::GetEffectInputCount(op));
+      PrintF("%d", op->EffectInputCount());
       break;
     case IrOpcode::kLoop:
     case IrOpcode::kMerge:
-      PrintF("%d", OperatorProperties::GetControlInputCount(op));
+      PrintF("%d", op->ControlInputCount());
       break;
     default:
       break;
diff --git a/src/compiler/graph-replay.h b/src/compiler/graph-replay.h
index 53d5247..f41311e 100644
--- a/src/compiler/graph-replay.h
+++ b/src/compiler/graph-replay.h
@@ -5,6 +5,7 @@
 #ifndef V8_COMPILER_GRAPH_REPLAY_H_
 #define V8_COMPILER_GRAPH_REPLAY_H_
 
+#include "src/compiler/generic-algorithm.h"
 #include "src/compiler/node.h"
 
 namespace v8 {
@@ -25,7 +26,7 @@
   static void PrintReplay(Graph* graph) {}
 #endif
 
-  GenericGraphVisit::Control Pre(Node* node);
+  void Pre(Node* node);
   void PostEdge(Node* from, int index, Node* to);
 
  private:
diff --git a/src/compiler/graph-unittest.cc b/src/compiler/graph-unittest.cc
deleted file mode 100644
index 75e70cb..0000000
--- a/src/compiler/graph-unittest.cc
+++ /dev/null
@@ -1,779 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/graph-unittest.h"
-
-#include <ostream>  // NOLINT(readability/streams)
-
-#include "src/compiler/node-properties-inl.h"
-
-using testing::_;
-using testing::MakeMatcher;
-using testing::MatcherInterface;
-using testing::MatchResultListener;
-using testing::StringMatchResultListener;
-
-namespace v8 {
-namespace internal {
-
-// TODO(bmeurer): Find a new home for these functions.
-template <typename T>
-inline std::ostream& operator<<(std::ostream& os, const Unique<T>& value) {
-  return os << *value.handle();
-}
-inline std::ostream& operator<<(std::ostream& os,
-                                const ExternalReference& value) {
-  OStringStream ost;
-  compiler::StaticParameterTraits<ExternalReference>::PrintTo(ost, value);
-  return os << ost.c_str();
-}
-
-namespace compiler {
-
-GraphTest::GraphTest(int num_parameters) : common_(zone()), graph_(zone()) {
-  graph()->SetStart(graph()->NewNode(common()->Start(num_parameters)));
-}
-
-
-GraphTest::~GraphTest() {}
-
-
-Node* GraphTest::Parameter(int32_t index) {
-  return graph()->NewNode(common()->Parameter(index), graph()->start());
-}
-
-
-Node* GraphTest::Float32Constant(volatile float value) {
-  return graph()->NewNode(common()->Float32Constant(value));
-}
-
-
-Node* GraphTest::Float64Constant(volatile double value) {
-  return graph()->NewNode(common()->Float64Constant(value));
-}
-
-
-Node* GraphTest::Int32Constant(int32_t value) {
-  return graph()->NewNode(common()->Int32Constant(value));
-}
-
-
-Node* GraphTest::Int64Constant(int64_t value) {
-  return graph()->NewNode(common()->Int64Constant(value));
-}
-
-
-Node* GraphTest::NumberConstant(volatile double value) {
-  return graph()->NewNode(common()->NumberConstant(value));
-}
-
-
-Node* GraphTest::HeapConstant(const Unique<HeapObject>& value) {
-  return graph()->NewNode(common()->HeapConstant(value));
-}
-
-
-Node* GraphTest::FalseConstant() {
-  return HeapConstant(
-      Unique<HeapObject>::CreateImmovable(factory()->false_value()));
-}
-
-
-Node* GraphTest::TrueConstant() {
-  return HeapConstant(
-      Unique<HeapObject>::CreateImmovable(factory()->true_value()));
-}
-
-
-Matcher<Node*> GraphTest::IsFalseConstant() {
-  return IsHeapConstant(
-      Unique<HeapObject>::CreateImmovable(factory()->false_value()));
-}
-
-
-Matcher<Node*> GraphTest::IsTrueConstant() {
-  return IsHeapConstant(
-      Unique<HeapObject>::CreateImmovable(factory()->true_value()));
-}
-
-namespace {
-
-template <typename T>
-bool PrintMatchAndExplain(const T& value, const char* value_name,
-                          const Matcher<T>& value_matcher,
-                          MatchResultListener* listener) {
-  StringMatchResultListener value_listener;
-  if (!value_matcher.MatchAndExplain(value, &value_listener)) {
-    *listener << "whose " << value_name << " " << value << " doesn't match";
-    if (value_listener.str() != "") {
-      *listener << ", " << value_listener.str();
-    }
-    return false;
-  }
-  return true;
-}
-
-
-class NodeMatcher : public MatcherInterface<Node*> {
- public:
-  explicit NodeMatcher(IrOpcode::Value opcode) : opcode_(opcode) {}
-
-  virtual void DescribeTo(std::ostream* os) const OVERRIDE {
-    *os << "is a " << IrOpcode::Mnemonic(opcode_) << " node";
-  }
-
-  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
-      OVERRIDE {
-    if (node == NULL) {
-      *listener << "which is NULL";
-      return false;
-    }
-    if (node->opcode() != opcode_) {
-      *listener << "whose opcode is " << IrOpcode::Mnemonic(node->opcode())
-                << " but should have been " << IrOpcode::Mnemonic(opcode_);
-      return false;
-    }
-    return true;
-  }
-
- private:
-  const IrOpcode::Value opcode_;
-};
-
-
-class IsBranchMatcher FINAL : public NodeMatcher {
- public:
-  IsBranchMatcher(const Matcher<Node*>& value_matcher,
-                  const Matcher<Node*>& control_matcher)
-      : NodeMatcher(IrOpcode::kBranch),
-        value_matcher_(value_matcher),
-        control_matcher_(control_matcher) {}
-
-  virtual void DescribeTo(std::ostream* os) const OVERRIDE {
-    NodeMatcher::DescribeTo(os);
-    *os << " whose value (";
-    value_matcher_.DescribeTo(os);
-    *os << ") and control (";
-    control_matcher_.DescribeTo(os);
-    *os << ")";
-  }
-
-  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
-      OVERRIDE {
-    return (NodeMatcher::MatchAndExplain(node, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
-                                 "value", value_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
-                                 "control", control_matcher_, listener));
-  }
-
- private:
-  const Matcher<Node*> value_matcher_;
-  const Matcher<Node*> control_matcher_;
-};
-
-
-class IsMergeMatcher FINAL : public NodeMatcher {
- public:
-  IsMergeMatcher(const Matcher<Node*>& control0_matcher,
-                 const Matcher<Node*>& control1_matcher)
-      : NodeMatcher(IrOpcode::kMerge),
-        control0_matcher_(control0_matcher),
-        control1_matcher_(control1_matcher) {}
-
-  virtual void DescribeTo(std::ostream* os) const OVERRIDE {
-    NodeMatcher::DescribeTo(os);
-    *os << " whose control0 (";
-    control0_matcher_.DescribeTo(os);
-    *os << ") and control1 (";
-    control1_matcher_.DescribeTo(os);
-    *os << ")";
-  }
-
-  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
-      OVERRIDE {
-    return (NodeMatcher::MatchAndExplain(node, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetControlInput(node, 0),
-                                 "control0", control0_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetControlInput(node, 1),
-                                 "control1", control1_matcher_, listener));
-  }
-
- private:
-  const Matcher<Node*> control0_matcher_;
-  const Matcher<Node*> control1_matcher_;
-};
-
-
-class IsControl1Matcher FINAL : public NodeMatcher {
- public:
-  IsControl1Matcher(IrOpcode::Value opcode,
-                    const Matcher<Node*>& control_matcher)
-      : NodeMatcher(opcode), control_matcher_(control_matcher) {}
-
-  virtual void DescribeTo(std::ostream* os) const OVERRIDE {
-    NodeMatcher::DescribeTo(os);
-    *os << " whose control (";
-    control_matcher_.DescribeTo(os);
-    *os << ")";
-  }
-
-  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
-      OVERRIDE {
-    return (NodeMatcher::MatchAndExplain(node, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
-                                 "control", control_matcher_, listener));
-  }
-
- private:
-  const Matcher<Node*> control_matcher_;
-};
-
-
-class IsFinishMatcher FINAL : public NodeMatcher {
- public:
-  IsFinishMatcher(const Matcher<Node*>& value_matcher,
-                  const Matcher<Node*>& effect_matcher)
-      : NodeMatcher(IrOpcode::kFinish),
-        value_matcher_(value_matcher),
-        effect_matcher_(effect_matcher) {}
-
-  virtual void DescribeTo(std::ostream* os) const OVERRIDE {
-    NodeMatcher::DescribeTo(os);
-    *os << " whose value (";
-    value_matcher_.DescribeTo(os);
-    *os << ") and effect (";
-    effect_matcher_.DescribeTo(os);
-    *os << ")";
-  }
-
-  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
-      OVERRIDE {
-    return (NodeMatcher::MatchAndExplain(node, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
-                                 "value", value_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
-                                 effect_matcher_, listener));
-  }
-
- private:
-  const Matcher<Node*> value_matcher_;
-  const Matcher<Node*> effect_matcher_;
-};
-
-
-template <typename T>
-class IsConstantMatcher FINAL : public NodeMatcher {
- public:
-  IsConstantMatcher(IrOpcode::Value opcode, const Matcher<T>& value_matcher)
-      : NodeMatcher(opcode), value_matcher_(value_matcher) {}
-
-  virtual void DescribeTo(std::ostream* os) const OVERRIDE {
-    NodeMatcher::DescribeTo(os);
-    *os << " whose value (";
-    value_matcher_.DescribeTo(os);
-    *os << ")";
-  }
-
-  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
-      OVERRIDE {
-    return (NodeMatcher::MatchAndExplain(node, listener) &&
-            PrintMatchAndExplain(OpParameter<T>(node), "value", value_matcher_,
-                                 listener));
-  }
-
- private:
-  const Matcher<T> value_matcher_;
-};
-
-
-class IsPhiMatcher FINAL : public NodeMatcher {
- public:
-  IsPhiMatcher(const Matcher<MachineType>& type_matcher,
-               const Matcher<Node*>& value0_matcher,
-               const Matcher<Node*>& value1_matcher,
-               const Matcher<Node*>& control_matcher)
-      : NodeMatcher(IrOpcode::kPhi),
-        type_matcher_(type_matcher),
-        value0_matcher_(value0_matcher),
-        value1_matcher_(value1_matcher),
-        control_matcher_(control_matcher) {}
-
-  virtual void DescribeTo(std::ostream* os) const OVERRIDE {
-    NodeMatcher::DescribeTo(os);
-    *os << " whose type (";
-    type_matcher_.DescribeTo(os);
-    *os << "), value0 (";
-    value0_matcher_.DescribeTo(os);
-    *os << "), value1 (";
-    value1_matcher_.DescribeTo(os);
-    *os << ") and control (";
-    control_matcher_.DescribeTo(os);
-    *os << ")";
-  }
-
-  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
-      OVERRIDE {
-    return (NodeMatcher::MatchAndExplain(node, listener) &&
-            PrintMatchAndExplain(OpParameter<MachineType>(node), "type",
-                                 type_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
-                                 "value0", value0_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
-                                 "value1", value1_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
-                                 "control", control_matcher_, listener));
-  }
-
- private:
-  const Matcher<MachineType> type_matcher_;
-  const Matcher<Node*> value0_matcher_;
-  const Matcher<Node*> value1_matcher_;
-  const Matcher<Node*> control_matcher_;
-};
-
-
-class IsProjectionMatcher FINAL : public NodeMatcher {
- public:
-  IsProjectionMatcher(const Matcher<size_t>& index_matcher,
-                      const Matcher<Node*>& base_matcher)
-      : NodeMatcher(IrOpcode::kProjection),
-        index_matcher_(index_matcher),
-        base_matcher_(base_matcher) {}
-
-  virtual void DescribeTo(std::ostream* os) const OVERRIDE {
-    NodeMatcher::DescribeTo(os);
-    *os << " whose index (";
-    index_matcher_.DescribeTo(os);
-    *os << ") and base (";
-    base_matcher_.DescribeTo(os);
-    *os << ")";
-  }
-
-  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
-      OVERRIDE {
-    return (NodeMatcher::MatchAndExplain(node, listener) &&
-            PrintMatchAndExplain(OpParameter<size_t>(node), "index",
-                                 index_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
-                                 base_matcher_, listener));
-  }
-
- private:
-  const Matcher<size_t> index_matcher_;
-  const Matcher<Node*> base_matcher_;
-};
-
-
-class IsCallMatcher FINAL : public NodeMatcher {
- public:
-  IsCallMatcher(const Matcher<CallDescriptor*>& descriptor_matcher,
-                const Matcher<Node*>& value0_matcher,
-                const Matcher<Node*>& value1_matcher,
-                const Matcher<Node*>& value2_matcher,
-                const Matcher<Node*>& value3_matcher,
-                const Matcher<Node*>& effect_matcher,
-                const Matcher<Node*>& control_matcher)
-      : NodeMatcher(IrOpcode::kCall),
-        descriptor_matcher_(descriptor_matcher),
-        value0_matcher_(value0_matcher),
-        value1_matcher_(value1_matcher),
-        value2_matcher_(value2_matcher),
-        value3_matcher_(value3_matcher),
-        effect_matcher_(effect_matcher),
-        control_matcher_(control_matcher) {}
-
-  virtual void DescribeTo(std::ostream* os) const OVERRIDE {
-    NodeMatcher::DescribeTo(os);
-    *os << " whose value0 (";
-    value0_matcher_.DescribeTo(os);
-    *os << ") and value1 (";
-    value1_matcher_.DescribeTo(os);
-    *os << ") and value2 (";
-    value2_matcher_.DescribeTo(os);
-    *os << ") and value3 (";
-    value3_matcher_.DescribeTo(os);
-    *os << ") and effect (";
-    effect_matcher_.DescribeTo(os);
-    *os << ") and control (";
-    control_matcher_.DescribeTo(os);
-    *os << ")";
-  }
-
-  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
-      OVERRIDE {
-    return (NodeMatcher::MatchAndExplain(node, listener) &&
-            PrintMatchAndExplain(OpParameter<CallDescriptor*>(node),
-                                 "descriptor", descriptor_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
-                                 "value0", value0_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
-                                 "value1", value1_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
-                                 "value2", value2_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 3),
-                                 "value3", value3_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
-                                 effect_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
-                                 "control", control_matcher_, listener));
-  }
-
- private:
-  const Matcher<CallDescriptor*> descriptor_matcher_;
-  const Matcher<Node*> value0_matcher_;
-  const Matcher<Node*> value1_matcher_;
-  const Matcher<Node*> value2_matcher_;
-  const Matcher<Node*> value3_matcher_;
-  const Matcher<Node*> effect_matcher_;
-  const Matcher<Node*> control_matcher_;
-};
-
-
-class IsLoadMatcher FINAL : public NodeMatcher {
- public:
-  IsLoadMatcher(const Matcher<LoadRepresentation>& rep_matcher,
-                const Matcher<Node*>& base_matcher,
-                const Matcher<Node*>& index_matcher,
-                const Matcher<Node*>& effect_matcher)
-      : NodeMatcher(IrOpcode::kLoad),
-        rep_matcher_(rep_matcher),
-        base_matcher_(base_matcher),
-        index_matcher_(index_matcher),
-        effect_matcher_(effect_matcher) {}
-
-  virtual void DescribeTo(std::ostream* os) const OVERRIDE {
-    NodeMatcher::DescribeTo(os);
-    *os << " whose rep (";
-    rep_matcher_.DescribeTo(os);
-    *os << "), base (";
-    base_matcher_.DescribeTo(os);
-    *os << "), index (";
-    index_matcher_.DescribeTo(os);
-    *os << ") and effect (";
-    effect_matcher_.DescribeTo(os);
-    *os << ")";
-  }
-
-  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
-      OVERRIDE {
-    return (NodeMatcher::MatchAndExplain(node, listener) &&
-            PrintMatchAndExplain(OpParameter<LoadRepresentation>(node), "rep",
-                                 rep_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
-                                 base_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
-                                 "index", index_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
-                                 effect_matcher_, listener));
-  }
-
- private:
-  const Matcher<LoadRepresentation> rep_matcher_;
-  const Matcher<Node*> base_matcher_;
-  const Matcher<Node*> index_matcher_;
-  const Matcher<Node*> effect_matcher_;
-};
-
-
-class IsStoreMatcher FINAL : public NodeMatcher {
- public:
-  IsStoreMatcher(const Matcher<MachineType>& type_matcher,
-                 const Matcher<WriteBarrierKind> write_barrier_matcher,
-                 const Matcher<Node*>& base_matcher,
-                 const Matcher<Node*>& index_matcher,
-                 const Matcher<Node*>& value_matcher,
-                 const Matcher<Node*>& effect_matcher,
-                 const Matcher<Node*>& control_matcher)
-      : NodeMatcher(IrOpcode::kStore),
-        type_matcher_(type_matcher),
-        write_barrier_matcher_(write_barrier_matcher),
-        base_matcher_(base_matcher),
-        index_matcher_(index_matcher),
-        value_matcher_(value_matcher),
-        effect_matcher_(effect_matcher),
-        control_matcher_(control_matcher) {}
-
-  virtual void DescribeTo(std::ostream* os) const OVERRIDE {
-    NodeMatcher::DescribeTo(os);
-    *os << " whose type (";
-    type_matcher_.DescribeTo(os);
-    *os << "), write barrier (";
-    write_barrier_matcher_.DescribeTo(os);
-    *os << "), base (";
-    base_matcher_.DescribeTo(os);
-    *os << "), index (";
-    index_matcher_.DescribeTo(os);
-    *os << "), value (";
-    value_matcher_.DescribeTo(os);
-    *os << "), effect (";
-    effect_matcher_.DescribeTo(os);
-    *os << ") and control (";
-    control_matcher_.DescribeTo(os);
-    *os << ")";
-  }
-
-  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
-      OVERRIDE {
-    return (NodeMatcher::MatchAndExplain(node, listener) &&
-            PrintMatchAndExplain(
-                OpParameter<StoreRepresentation>(node).machine_type(), "type",
-                type_matcher_, listener) &&
-            PrintMatchAndExplain(
-                OpParameter<StoreRepresentation>(node).write_barrier_kind(),
-                "write barrier", write_barrier_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
-                                 base_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
-                                 "index", index_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
-                                 "value", value_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
-                                 effect_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
-                                 "control", control_matcher_, listener));
-  }
-
- private:
-  const Matcher<MachineType> type_matcher_;
-  const Matcher<WriteBarrierKind> write_barrier_matcher_;
-  const Matcher<Node*> base_matcher_;
-  const Matcher<Node*> index_matcher_;
-  const Matcher<Node*> value_matcher_;
-  const Matcher<Node*> effect_matcher_;
-  const Matcher<Node*> control_matcher_;
-};
-
-
-class IsBinopMatcher FINAL : public NodeMatcher {
- public:
-  IsBinopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& lhs_matcher,
-                 const Matcher<Node*>& rhs_matcher)
-      : NodeMatcher(opcode),
-        lhs_matcher_(lhs_matcher),
-        rhs_matcher_(rhs_matcher) {}
-
-  virtual void DescribeTo(std::ostream* os) const OVERRIDE {
-    NodeMatcher::DescribeTo(os);
-    *os << " whose lhs (";
-    lhs_matcher_.DescribeTo(os);
-    *os << ") and rhs (";
-    rhs_matcher_.DescribeTo(os);
-    *os << ")";
-  }
-
-  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
-      OVERRIDE {
-    return (NodeMatcher::MatchAndExplain(node, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "lhs",
-                                 lhs_matcher_, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), "rhs",
-                                 rhs_matcher_, listener));
-  }
-
- private:
-  const Matcher<Node*> lhs_matcher_;
-  const Matcher<Node*> rhs_matcher_;
-};
-
-
-class IsUnopMatcher FINAL : public NodeMatcher {
- public:
-  IsUnopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& input_matcher)
-      : NodeMatcher(opcode), input_matcher_(input_matcher) {}
-
-  virtual void DescribeTo(std::ostream* os) const OVERRIDE {
-    NodeMatcher::DescribeTo(os);
-    *os << " whose input (";
-    input_matcher_.DescribeTo(os);
-    *os << ")";
-  }
-
-  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
-      OVERRIDE {
-    return (NodeMatcher::MatchAndExplain(node, listener) &&
-            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
-                                 "input", input_matcher_, listener));
-  }
-
- private:
-  const Matcher<Node*> input_matcher_;
-};
-}
-
-
-Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
-                        const Matcher<Node*>& control_matcher) {
-  return MakeMatcher(new IsBranchMatcher(value_matcher, control_matcher));
-}
-
-
-Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,
-                       const Matcher<Node*>& control1_matcher) {
-  return MakeMatcher(new IsMergeMatcher(control0_matcher, control1_matcher));
-}
-
-
-Matcher<Node*> IsIfTrue(const Matcher<Node*>& control_matcher) {
-  return MakeMatcher(new IsControl1Matcher(IrOpcode::kIfTrue, control_matcher));
-}
-
-
-Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher) {
-  return MakeMatcher(
-      new IsControl1Matcher(IrOpcode::kIfFalse, control_matcher));
-}
-
-
-Matcher<Node*> IsControlEffect(const Matcher<Node*>& control_matcher) {
-  return MakeMatcher(
-      new IsControl1Matcher(IrOpcode::kControlEffect, control_matcher));
-}
-
-
-Matcher<Node*> IsValueEffect(const Matcher<Node*>& value_matcher) {
-  return MakeMatcher(new IsUnopMatcher(IrOpcode::kValueEffect, value_matcher));
-}
-
-
-Matcher<Node*> IsFinish(const Matcher<Node*>& value_matcher,
-                        const Matcher<Node*>& effect_matcher) {
-  return MakeMatcher(new IsFinishMatcher(value_matcher, effect_matcher));
-}
-
-
-Matcher<Node*> IsExternalConstant(
-    const Matcher<ExternalReference>& value_matcher) {
-  return MakeMatcher(new IsConstantMatcher<ExternalReference>(
-      IrOpcode::kExternalConstant, value_matcher));
-}
-
-
-Matcher<Node*> IsHeapConstant(
-    const Matcher<Unique<HeapObject> >& value_matcher) {
-  return MakeMatcher(new IsConstantMatcher<Unique<HeapObject> >(
-      IrOpcode::kHeapConstant, value_matcher));
-}
-
-
-Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher) {
-  return MakeMatcher(
-      new IsConstantMatcher<int32_t>(IrOpcode::kInt32Constant, value_matcher));
-}
-
-
-Matcher<Node*> IsInt64Constant(const Matcher<int64_t>& value_matcher) {
-  return MakeMatcher(
-      new IsConstantMatcher<int64_t>(IrOpcode::kInt64Constant, value_matcher));
-}
-
-
-Matcher<Node*> IsFloat32Constant(const Matcher<float>& value_matcher) {
-  return MakeMatcher(
-      new IsConstantMatcher<float>(IrOpcode::kFloat32Constant, value_matcher));
-}
-
-
-Matcher<Node*> IsFloat64Constant(const Matcher<double>& value_matcher) {
-  return MakeMatcher(
-      new IsConstantMatcher<double>(IrOpcode::kFloat64Constant, value_matcher));
-}
-
-
-Matcher<Node*> IsNumberConstant(const Matcher<double>& value_matcher) {
-  return MakeMatcher(
-      new IsConstantMatcher<double>(IrOpcode::kNumberConstant, value_matcher));
-}
-
-
-Matcher<Node*> IsPhi(const Matcher<MachineType>& type_matcher,
-                     const Matcher<Node*>& value0_matcher,
-                     const Matcher<Node*>& value1_matcher,
-                     const Matcher<Node*>& merge_matcher) {
-  return MakeMatcher(new IsPhiMatcher(type_matcher, value0_matcher,
-                                      value1_matcher, merge_matcher));
-}
-
-
-Matcher<Node*> IsProjection(const Matcher<size_t>& index_matcher,
-                            const Matcher<Node*>& base_matcher) {
-  return MakeMatcher(new IsProjectionMatcher(index_matcher, base_matcher));
-}
-
-
-Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
-                      const Matcher<Node*>& value0_matcher,
-                      const Matcher<Node*>& value1_matcher,
-                      const Matcher<Node*>& value2_matcher,
-                      const Matcher<Node*>& value3_matcher,
-                      const Matcher<Node*>& effect_matcher,
-                      const Matcher<Node*>& control_matcher) {
-  return MakeMatcher(new IsCallMatcher(
-      descriptor_matcher, value0_matcher, value1_matcher, value2_matcher,
-      value3_matcher, effect_matcher, control_matcher));
-}
-
-
-Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher,
-                      const Matcher<Node*>& base_matcher,
-                      const Matcher<Node*>& index_matcher,
-                      const Matcher<Node*>& effect_matcher) {
-  return MakeMatcher(new IsLoadMatcher(rep_matcher, base_matcher, index_matcher,
-                                       effect_matcher));
-}
-
-
-Matcher<Node*> IsStore(const Matcher<MachineType>& type_matcher,
-                       const Matcher<WriteBarrierKind>& write_barrier_matcher,
-                       const Matcher<Node*>& base_matcher,
-                       const Matcher<Node*>& index_matcher,
-                       const Matcher<Node*>& value_matcher,
-                       const Matcher<Node*>& effect_matcher,
-                       const Matcher<Node*>& control_matcher) {
-  return MakeMatcher(new IsStoreMatcher(
-      type_matcher, write_barrier_matcher, base_matcher, index_matcher,
-      value_matcher, effect_matcher, control_matcher));
-}
-
-
-#define IS_BINOP_MATCHER(Name)                                            \
-  Matcher<Node*> Is##Name(const Matcher<Node*>& lhs_matcher,              \
-                          const Matcher<Node*>& rhs_matcher) {            \
-    return MakeMatcher(                                                   \
-        new IsBinopMatcher(IrOpcode::k##Name, lhs_matcher, rhs_matcher)); \
-  }
-IS_BINOP_MATCHER(NumberLessThan)
-IS_BINOP_MATCHER(Word32And)
-IS_BINOP_MATCHER(Word32Sar)
-IS_BINOP_MATCHER(Word32Shl)
-IS_BINOP_MATCHER(Word32Ror)
-IS_BINOP_MATCHER(Word32Equal)
-IS_BINOP_MATCHER(Word64And)
-IS_BINOP_MATCHER(Word64Sar)
-IS_BINOP_MATCHER(Word64Shl)
-IS_BINOP_MATCHER(Word64Equal)
-IS_BINOP_MATCHER(Int32AddWithOverflow)
-IS_BINOP_MATCHER(Int32Mul)
-IS_BINOP_MATCHER(Uint32LessThanOrEqual)
-#undef IS_BINOP_MATCHER
-
-
-#define IS_UNOP_MATCHER(Name)                                                \
-  Matcher<Node*> Is##Name(const Matcher<Node*>& input_matcher) {             \
-    return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \
-  }
-IS_UNOP_MATCHER(ChangeFloat64ToInt32)
-IS_UNOP_MATCHER(ChangeFloat64ToUint32)
-IS_UNOP_MATCHER(ChangeInt32ToFloat64)
-IS_UNOP_MATCHER(ChangeInt32ToInt64)
-IS_UNOP_MATCHER(ChangeUint32ToFloat64)
-IS_UNOP_MATCHER(ChangeUint32ToUint64)
-IS_UNOP_MATCHER(TruncateFloat64ToInt32)
-IS_UNOP_MATCHER(TruncateInt64ToInt32)
-IS_UNOP_MATCHER(Float64Sqrt)
-#undef IS_UNOP_MATCHER
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/graph-unittest.h b/src/compiler/graph-unittest.h
deleted file mode 100644
index 1dc9c3d..0000000
--- a/src/compiler/graph-unittest.h
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_COMPILER_GRAPH_UNITTEST_H_
-#define V8_COMPILER_GRAPH_UNITTEST_H_
-
-#include "src/compiler/common-operator.h"
-#include "src/compiler/graph.h"
-#include "src/compiler/machine-operator.h"
-#include "src/test/test-utils.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace v8 {
-namespace internal {
-
-// Forward declarations.
-class HeapObject;
-template <class T>
-class Unique;
-
-namespace compiler {
-
-using ::testing::Matcher;
-
-
-class GraphTest : public TestWithContext, public TestWithZone {
- public:
-  explicit GraphTest(int parameters = 1);
-  virtual ~GraphTest();
-
- protected:
-  Node* Parameter(int32_t index);
-  Node* Float32Constant(volatile float value);
-  Node* Float64Constant(volatile double value);
-  Node* Int32Constant(int32_t value);
-  Node* Int64Constant(int64_t value);
-  Node* NumberConstant(volatile double value);
-  Node* HeapConstant(const Unique<HeapObject>& value);
-  Node* FalseConstant();
-  Node* TrueConstant();
-
-  Matcher<Node*> IsFalseConstant();
-  Matcher<Node*> IsTrueConstant();
-
-  CommonOperatorBuilder* common() { return &common_; }
-  Graph* graph() { return &graph_; }
-
- private:
-  CommonOperatorBuilder common_;
-  Graph graph_;
-};
-
-
-Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
-                        const Matcher<Node*>& control_matcher);
-Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,
-                       const Matcher<Node*>& control1_matcher);
-Matcher<Node*> IsIfTrue(const Matcher<Node*>& control_matcher);
-Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher);
-Matcher<Node*> IsControlEffect(const Matcher<Node*>& control_matcher);
-Matcher<Node*> IsValueEffect(const Matcher<Node*>& value_matcher);
-Matcher<Node*> IsFinish(const Matcher<Node*>& value_matcher,
-                        const Matcher<Node*>& effect_matcher);
-Matcher<Node*> IsExternalConstant(
-    const Matcher<ExternalReference>& value_matcher);
-Matcher<Node*> IsHeapConstant(
-    const Matcher<Unique<HeapObject> >& value_matcher);
-Matcher<Node*> IsFloat32Constant(const Matcher<float>& value_matcher);
-Matcher<Node*> IsFloat64Constant(const Matcher<double>& value_matcher);
-Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher);
-Matcher<Node*> IsInt64Constant(const Matcher<int64_t>& value_matcher);
-Matcher<Node*> IsNumberConstant(const Matcher<double>& value_matcher);
-Matcher<Node*> IsPhi(const Matcher<MachineType>& type_matcher,
-                     const Matcher<Node*>& value0_matcher,
-                     const Matcher<Node*>& value1_matcher,
-                     const Matcher<Node*>& merge_matcher);
-Matcher<Node*> IsProjection(const Matcher<size_t>& index_matcher,
-                            const Matcher<Node*>& base_matcher);
-Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
-                      const Matcher<Node*>& value0_matcher,
-                      const Matcher<Node*>& value1_matcher,
-                      const Matcher<Node*>& value2_matcher,
-                      const Matcher<Node*>& value3_matcher,
-                      const Matcher<Node*>& effect_matcher,
-                      const Matcher<Node*>& control_matcher);
-
-Matcher<Node*> IsNumberLessThan(const Matcher<Node*>& lhs_matcher,
-                                const Matcher<Node*>& rhs_matcher);
-
-Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher,
-                      const Matcher<Node*>& base_matcher,
-                      const Matcher<Node*>& index_matcher,
-                      const Matcher<Node*>& effect_matcher);
-Matcher<Node*> IsStore(const Matcher<MachineType>& type_matcher,
-                       const Matcher<WriteBarrierKind>& write_barrier_matcher,
-                       const Matcher<Node*>& base_matcher,
-                       const Matcher<Node*>& index_matcher,
-                       const Matcher<Node*>& value_matcher,
-                       const Matcher<Node*>& effect_matcher,
-                       const Matcher<Node*>& control_matcher);
-Matcher<Node*> IsWord32And(const Matcher<Node*>& lhs_matcher,
-                           const Matcher<Node*>& rhs_matcher);
-Matcher<Node*> IsWord32Sar(const Matcher<Node*>& lhs_matcher,
-                           const Matcher<Node*>& rhs_matcher);
-Matcher<Node*> IsWord32Shl(const Matcher<Node*>& lhs_matcher,
-                           const Matcher<Node*>& rhs_matcher);
-Matcher<Node*> IsWord32Ror(const Matcher<Node*>& lhs_matcher,
-                           const Matcher<Node*>& rhs_matcher);
-Matcher<Node*> IsWord32Equal(const Matcher<Node*>& lhs_matcher,
-                             const Matcher<Node*>& rhs_matcher);
-Matcher<Node*> IsWord64And(const Matcher<Node*>& lhs_matcher,
-                           const Matcher<Node*>& rhs_matcher);
-Matcher<Node*> IsWord64Shl(const Matcher<Node*>& lhs_matcher,
-                           const Matcher<Node*>& rhs_matcher);
-Matcher<Node*> IsWord64Sar(const Matcher<Node*>& lhs_matcher,
-                           const Matcher<Node*>& rhs_matcher);
-Matcher<Node*> IsWord64Equal(const Matcher<Node*>& lhs_matcher,
-                             const Matcher<Node*>& rhs_matcher);
-Matcher<Node*> IsInt32AddWithOverflow(const Matcher<Node*>& lhs_matcher,
-                                      const Matcher<Node*>& rhs_matcher);
-Matcher<Node*> IsInt32Mul(const Matcher<Node*>& lhs_matcher,
-                          const Matcher<Node*>& rhs_matcher);
-Matcher<Node*> IsUint32LessThanOrEqual(const Matcher<Node*>& lhs_matcher,
-                                       const Matcher<Node*>& rhs_matcher);
-Matcher<Node*> IsChangeFloat64ToInt32(const Matcher<Node*>& input_matcher);
-Matcher<Node*> IsChangeFloat64ToUint32(const Matcher<Node*>& input_matcher);
-Matcher<Node*> IsChangeInt32ToFloat64(const Matcher<Node*>& input_matcher);
-Matcher<Node*> IsChangeInt32ToInt64(const Matcher<Node*>& input_matcher);
-Matcher<Node*> IsChangeUint32ToFloat64(const Matcher<Node*>& input_matcher);
-Matcher<Node*> IsChangeUint32ToUint64(const Matcher<Node*>& input_matcher);
-Matcher<Node*> IsTruncateFloat64ToInt32(const Matcher<Node*>& input_matcher);
-Matcher<Node*> IsTruncateInt64ToInt32(const Matcher<Node*>& input_matcher);
-Matcher<Node*> IsFloat64Sqrt(const Matcher<Node*>& input_matcher);
-
-}  //  namespace compiler
-}  //  namespace internal
-}  //  namespace v8
-
-#endif  // V8_COMPILER_GRAPH_UNITTEST_H_
diff --git a/src/compiler/graph-visualizer.cc b/src/compiler/graph-visualizer.cc
index 10d6698..e018c7a 100644
--- a/src/compiler/graph-visualizer.cc
+++ b/src/compiler/graph-visualizer.cc
@@ -4,9 +4,10 @@
 
 #include "src/compiler/graph-visualizer.h"
 
-#include "src/compiler/generic-algorithm.h"
-#include "src/compiler/generic-node.h"
-#include "src/compiler/generic-node-inl.h"
+#include <sstream>
+#include <string>
+
+#include "src/code-stubs.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/node.h"
@@ -14,33 +15,223 @@
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/opcodes.h"
 #include "src/compiler/operator.h"
+#include "src/compiler/register-allocator.h"
+#include "src/compiler/schedule.h"
+#include "src/compiler/scheduler.h"
 #include "src/ostreams.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
+static int SafeId(Node* node) { return node == NULL ? -1 : node->id(); }
+static const char* SafeMnemonic(Node* node) {
+  return node == NULL ? "null" : node->op()->mnemonic();
+}
+
 #define DEAD_COLOR "#999999"
 
-class GraphVisualizer : public NullNodeVisitor {
+class AllNodes {
  public:
-  GraphVisualizer(OStream& os, Zone* zone, const Graph* graph);  // NOLINT
+  enum State { kDead, kGray, kLive };
+
+  AllNodes(Zone* local_zone, const Graph* graph)
+      : state(graph->NodeCount(), kDead, local_zone),
+        live(local_zone),
+        gray(local_zone) {
+    Node* end = graph->end();
+    state[end->id()] = kLive;
+    live.push_back(end);
+    // Find all live nodes reachable from end.
+    for (size_t i = 0; i < live.size(); i++) {
+      for (Node* const input : live[i]->inputs()) {
+        if (input == NULL) {
+          // TODO(titzer): print a warning.
+          continue;
+        }
+        if (input->id() >= graph->NodeCount()) {
+          // TODO(titzer): print a warning.
+          continue;
+        }
+        if (state[input->id()] != kLive) {
+          live.push_back(input);
+          state[input->id()] = kLive;
+        }
+      }
+    }
+
+    // Find all nodes that are not reachable from end that use live nodes.
+    for (size_t i = 0; i < live.size(); i++) {
+      for (Node* const use : live[i]->uses()) {
+        if (state[use->id()] == kDead) {
+          gray.push_back(use);
+          state[use->id()] = kGray;
+        }
+      }
+    }
+  }
+
+  bool IsLive(Node* node) {
+    return node != NULL && node->id() < static_cast<int>(state.size()) &&
+           state[node->id()] == kLive;
+  }
+
+  ZoneVector<State> state;
+  NodeVector live;
+  NodeVector gray;
+};
+
+
+class Escaped {
+ public:
+  explicit Escaped(const std::ostringstream& os,
+                   const char* escaped_chars = "<>|{}")
+      : str_(os.str()), escaped_chars_(escaped_chars) {}
+
+  friend std::ostream& operator<<(std::ostream& os, const Escaped& e) {
+    for (std::string::const_iterator i = e.str_.begin(); i != e.str_.end();
+         ++i) {
+      if (e.needs_escape(*i)) os << "\\";
+      os << *i;
+    }
+    return os;
+  }
+
+ private:
+  bool needs_escape(char ch) const {
+    for (size_t i = 0; i < strlen(escaped_chars_); ++i) {
+      if (ch == escaped_chars_[i]) return true;
+    }
+    return false;
+  }
+
+  const std::string str_;
+  const char* const escaped_chars_;
+};
+
+class JSONGraphNodeWriter {
+ public:
+  JSONGraphNodeWriter(std::ostream& os, Zone* zone, const Graph* graph)
+      : os_(os), all_(zone, graph), first_node_(true) {}
+
+  void Print() {
+    for (Node* const node : all_.live) PrintNode(node);
+  }
+
+  void PrintNode(Node* node) {
+    if (first_node_) {
+      first_node_ = false;
+    } else {
+      os_ << ",";
+    }
+    std::ostringstream label;
+    label << *node->op();
+    os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << Escaped(label, "\"")
+        << "\"";
+    IrOpcode::Value opcode = node->opcode();
+    if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) {
+      os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node)
+          << "]";
+      os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node)
+          << "]";
+    } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse ||
+               opcode == IrOpcode::kLoop) {
+      os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node)
+          << "]";
+    }
+    if (opcode == IrOpcode::kBranch) {
+      os_ << ",\"rankInputs\":[0]";
+    }
+    os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\"";
+    os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true"
+                                                               : "false");
+    os_ << "}";
+  }
+
+ private:
+  std::ostream& os_;
+  AllNodes all_;
+  bool first_node_;
+
+  DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter);
+};
+
+
+class JSONGraphEdgeWriter {
+ public:
+  JSONGraphEdgeWriter(std::ostream& os, Zone* zone, const Graph* graph)
+      : os_(os), all_(zone, graph), first_edge_(true) {}
+
+  void Print() {
+    for (Node* const node : all_.live) PrintEdges(node);
+  }
+
+  void PrintEdges(Node* node) {
+    for (int i = 0; i < node->InputCount(); i++) {
+      Node* input = node->InputAt(i);
+      if (input == NULL) continue;
+      PrintEdge(node, i, input);
+    }
+  }
+
+  void PrintEdge(Node* from, int index, Node* to) {
+    if (first_edge_) {
+      first_edge_ = false;
+    } else {
+      os_ << ",";
+    }
+    const char* edge_type = NULL;
+    if (index < NodeProperties::FirstValueIndex(from)) {
+      edge_type = "unknown";
+    } else if (index < NodeProperties::FirstContextIndex(from)) {
+      edge_type = "value";
+    } else if (index < NodeProperties::FirstFrameStateIndex(from)) {
+      edge_type = "context";
+    } else if (index < NodeProperties::FirstEffectIndex(from)) {
+      edge_type = "frame-state";
+    } else if (index < NodeProperties::FirstControlIndex(from)) {
+      edge_type = "effect";
+    } else {
+      edge_type = "control";
+    }
+    os_ << "{\"source\":" << SafeId(to) << ",\"target\":" << SafeId(from)
+        << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}";
+  }
+
+ private:
+  std::ostream& os_;
+  AllNodes all_;
+  bool first_edge_;
+
+  DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter);
+};
+
+
+std::ostream& operator<<(std::ostream& os, const AsJSON& ad) {
+  Zone tmp_zone(ad.graph.zone()->isolate());
+  os << "{\"nodes\":[";
+  JSONGraphNodeWriter(os, &tmp_zone, &ad.graph).Print();
+  os << "],\"edges\":[";
+  JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print();
+  os << "]}";
+  return os;
+}
+
+
+class GraphVisualizer {
+ public:
+  GraphVisualizer(std::ostream& os, Zone* zone, const Graph* graph)
+      : all_(zone, graph), os_(os) {}
 
   void Print();
 
-  GenericGraphVisit::Control Pre(Node* node);
-  GenericGraphVisit::Control PreEdge(Node* from, int index, Node* to);
+  void PrintNode(Node* node, bool gray);
 
  private:
-  void AnnotateNode(Node* node);
-  void PrintEdge(Node::Edge edge);
+  void PrintEdge(Edge edge);
 
-  Zone* zone_;
-  NodeSet all_nodes_;
-  NodeSet white_nodes_;
-  bool use_to_def_;
-  OStream& os_;
-  const Graph* const graph_;
+  AllNodes all_;
+  std::ostream& os_;
 
   DISALLOW_COPY_AND_ASSIGN(GraphVisualizer);
 };
@@ -49,92 +240,24 @@
 static Node* GetControlCluster(Node* node) {
   if (OperatorProperties::IsBasicBlockBegin(node->op())) {
     return node;
-  } else if (OperatorProperties::GetControlInputCount(node->op()) == 1) {
+  } else if (node->op()->ControlInputCount() == 1) {
     Node* control = NodeProperties::GetControlInput(node, 0);
-    return OperatorProperties::IsBasicBlockBegin(control->op()) ? control
-                                                                : NULL;
+    return control != NULL &&
+                   OperatorProperties::IsBasicBlockBegin(control->op())
+               ? control
+               : NULL;
   } else {
     return NULL;
   }
 }
 
 
-GenericGraphVisit::Control GraphVisualizer::Pre(Node* node) {
-  if (all_nodes_.count(node) == 0) {
-    Node* control_cluster = GetControlCluster(node);
-    if (control_cluster != NULL) {
-      os_ << "  subgraph cluster_BasicBlock" << control_cluster->id() << " {\n";
-    }
-    os_ << "  ID" << node->id() << " [\n";
-    AnnotateNode(node);
-    os_ << "  ]\n";
-    if (control_cluster != NULL) os_ << "  }\n";
-    all_nodes_.insert(node);
-    if (use_to_def_) white_nodes_.insert(node);
+void GraphVisualizer::PrintNode(Node* node, bool gray) {
+  Node* control_cluster = GetControlCluster(node);
+  if (control_cluster != NULL) {
+    os_ << "  subgraph cluster_BasicBlock" << control_cluster->id() << " {\n";
   }
-  return GenericGraphVisit::CONTINUE;
-}
-
-
-GenericGraphVisit::Control GraphVisualizer::PreEdge(Node* from, int index,
-                                                    Node* to) {
-  if (use_to_def_) return GenericGraphVisit::CONTINUE;
-  // When going from def to use, only consider white -> other edges, which are
-  // the dead nodes that use live nodes. We're probably not interested in
-  // dead nodes that only use other dead nodes.
-  if (white_nodes_.count(from) > 0) return GenericGraphVisit::CONTINUE;
-  return GenericGraphVisit::SKIP;
-}
-
-
-class Escaped {
- public:
-  explicit Escaped(const OStringStream& os) : str_(os.c_str()) {}
-
-  friend OStream& operator<<(OStream& os, const Escaped& e) {
-    for (const char* s = e.str_; *s != '\0'; ++s) {
-      if (needs_escape(*s)) os << "\\";
-      os << *s;
-    }
-    return os;
-  }
-
- private:
-  static bool needs_escape(char ch) {
-    switch (ch) {
-      case '>':
-      case '<':
-      case '|':
-      case '}':
-      case '{':
-        return true;
-      default:
-        return false;
-    }
-  }
-
-  const char* const str_;
-};
-
-
-static bool IsLikelyBackEdge(Node* from, int index, Node* to) {
-  if (from->opcode() == IrOpcode::kPhi ||
-      from->opcode() == IrOpcode::kEffectPhi) {
-    Node* control = NodeProperties::GetControlInput(from, 0);
-    return control->opcode() != IrOpcode::kMerge && control != to && index != 0;
-  } else if (from->opcode() == IrOpcode::kLoop) {
-    return index != 0;
-  } else {
-    return false;
-  }
-}
-
-
-void GraphVisualizer::AnnotateNode(Node* node) {
-  if (!use_to_def_) {
-    os_ << "    style=\"filled\"\n"
-        << "    fillcolor=\"" DEAD_COLOR "\"\n";
-  }
+  os_ << "  ID" << SafeId(node) << " [\n";
 
   os_ << "    shape=\"record\"\n";
   switch (node->opcode()) {
@@ -153,68 +276,89 @@
       break;
   }
 
-  OStringStream label;
-  label << *node->op();
-  os_ << "    label=\"{{#" << node->id() << ":" << Escaped(label);
+  if (gray) {
+    os_ << "    style=\"filled\"\n"
+        << "    fillcolor=\"" DEAD_COLOR "\"\n";
+  }
 
-  InputIter i = node->inputs().begin();
-  for (int j = OperatorProperties::GetValueInputCount(node->op()); j > 0;
-       ++i, j--) {
-    os_ << "|<I" << i.index() << ">#" << (*i)->id();
+  std::ostringstream label;
+  label << *node->op();
+  os_ << "    label=\"{{#" << SafeId(node) << ":" << Escaped(label);
+
+  auto i = node->input_edges().begin();
+  for (int j = node->op()->ValueInputCount(); j > 0; ++i, j--) {
+    os_ << "|<I" << (*i).index() << ">#" << SafeId((*i).to());
   }
   for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0;
        ++i, j--) {
-    os_ << "|<I" << i.index() << ">X #" << (*i)->id();
+    os_ << "|<I" << (*i).index() << ">X #" << SafeId((*i).to());
   }
   for (int j = OperatorProperties::GetFrameStateInputCount(node->op()); j > 0;
        ++i, j--) {
-    os_ << "|<I" << i.index() << ">F #" << (*i)->id();
+    os_ << "|<I" << (*i).index() << ">F #" << SafeId((*i).to());
   }
-  for (int j = OperatorProperties::GetEffectInputCount(node->op()); j > 0;
-       ++i, j--) {
-    os_ << "|<I" << i.index() << ">E #" << (*i)->id();
+  for (int j = node->op()->EffectInputCount(); j > 0; ++i, j--) {
+    os_ << "|<I" << (*i).index() << ">E #" << SafeId((*i).to());
   }
 
-  if (!use_to_def_ || OperatorProperties::IsBasicBlockBegin(node->op()) ||
+  if (OperatorProperties::IsBasicBlockBegin(node->op()) ||
       GetControlCluster(node) == NULL) {
-    for (int j = OperatorProperties::GetControlInputCount(node->op()); j > 0;
-         ++i, j--) {
-      os_ << "|<I" << i.index() << ">C #" << (*i)->id();
+    for (int j = node->op()->ControlInputCount(); j > 0; ++i, j--) {
+      os_ << "|<I" << (*i).index() << ">C #" << SafeId((*i).to());
     }
   }
   os_ << "}";
 
-  if (FLAG_trace_turbo_types && !NodeProperties::IsControl(node)) {
+  if (FLAG_trace_turbo_types && NodeProperties::IsTyped(node)) {
     Bounds bounds = NodeProperties::GetBounds(node);
-    OStringStream upper;
+    std::ostringstream upper;
     bounds.upper->PrintTo(upper);
-    OStringStream lower;
+    std::ostringstream lower;
     bounds.lower->PrintTo(lower);
     os_ << "|" << Escaped(upper) << "|" << Escaped(lower);
   }
   os_ << "}\"\n";
+
+  os_ << "  ]\n";
+  if (control_cluster != NULL) os_ << "  }\n";
 }
 
 
-void GraphVisualizer::PrintEdge(Node::Edge edge) {
+static bool IsLikelyBackEdge(Node* from, int index, Node* to) {
+  if (from->opcode() == IrOpcode::kPhi ||
+      from->opcode() == IrOpcode::kEffectPhi) {
+    Node* control = NodeProperties::GetControlInput(from, 0);
+    return control != NULL && control->opcode() != IrOpcode::kMerge &&
+           control != to && index != 0;
+  } else if (from->opcode() == IrOpcode::kLoop) {
+    return index != 0;
+  } else {
+    return false;
+  }
+}
+
+
+void GraphVisualizer::PrintEdge(Edge edge) {
   Node* from = edge.from();
   int index = edge.index();
   Node* to = edge.to();
+
+  if (!all_.IsLive(to)) return;  // skip inputs that point to dead or NULL.
+
   bool unconstrained = IsLikelyBackEdge(from, index, to);
-  os_ << "  ID" << from->id();
-  if (all_nodes_.count(to) == 0) {
-    os_ << ":I" << index << ":n -> DEAD_INPUT";
-  } else if (OperatorProperties::IsBasicBlockBegin(from->op()) ||
-             GetControlCluster(from) == NULL ||
-             (OperatorProperties::GetControlInputCount(from->op()) > 0 &&
-              NodeProperties::GetControlInput(from) != to)) {
-    os_ << ":I" << index << ":n -> ID" << to->id() << ":s"
+  os_ << "  ID" << SafeId(from);
+
+  if (OperatorProperties::IsBasicBlockBegin(from->op()) ||
+      GetControlCluster(from) == NULL ||
+      (from->op()->ControlInputCount() > 0 &&
+       NodeProperties::GetControlInput(from) != to)) {
+    os_ << ":I" << index << ":n -> ID" << SafeId(to) << ":s"
         << "[" << (unconstrained ? "constraint=false, " : "")
         << (NodeProperties::IsControlEdge(edge) ? "style=bold, " : "")
         << (NodeProperties::IsEffectEdge(edge) ? "style=dotted, " : "")
         << (NodeProperties::IsContextEdge(edge) ? "style=dashed, " : "") << "]";
   } else {
-    os_ << " -> ID" << to->id() << ":s [color=transparent, "
+    os_ << " -> ID" << SafeId(to) << ":s [color=transparent, "
         << (unconstrained ? "constraint=false, " : "")
         << (NodeProperties::IsControlEdge(edge) ? "style=dashed, " : "") << "]";
   }
@@ -233,50 +377,456 @@
       << "  \n";
 
   // Make sure all nodes have been output before writing out the edges.
-  use_to_def_ = true;
-  // TODO(svenpanne) Remove the need for the const_casts.
-  const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this);
-  white_nodes_.insert(const_cast<Graph*>(graph_)->start());
-
-  // Visit all uses of white nodes.
-  use_to_def_ = false;
-  GenericGraphVisit::Visit<GraphVisualizer, NodeUseIterationTraits<Node> >(
-      const_cast<Graph*>(graph_), zone_, white_nodes_.begin(),
-      white_nodes_.end(), this);
-
-  os_ << "  DEAD_INPUT [\n"
-      << "    style=\"filled\" \n"
-      << "    fillcolor=\"" DEAD_COLOR "\"\n"
-      << "  ]\n"
-      << "\n";
+  for (Node* const node : all_.live) PrintNode(node, false);
+  for (Node* const node : all_.gray) PrintNode(node, true);
 
   // With all the nodes written, add the edges.
-  for (NodeSetIter i = all_nodes_.begin(); i != all_nodes_.end(); ++i) {
-    Node::Inputs inputs = (*i)->inputs();
-    for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
-         ++iter) {
-      PrintEdge(iter.edge());
+  for (Node* const node : all_.live) {
+    for (Edge edge : node->use_edges()) {
+      PrintEdge(edge);
     }
   }
   os_ << "}\n";
 }
 
 
-GraphVisualizer::GraphVisualizer(OStream& os, Zone* zone,
-                                 const Graph* graph)  // NOLINT
-    : zone_(zone),
-      all_nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)),
-      white_nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)),
-      use_to_def_(true),
-      os_(os),
-      graph_(graph) {}
-
-
-OStream& operator<<(OStream& os, const AsDOT& ad) {
+std::ostream& operator<<(std::ostream& os, const AsDOT& ad) {
   Zone tmp_zone(ad.graph.zone()->isolate());
   GraphVisualizer(os, &tmp_zone, &ad.graph).Print();
   return os;
 }
+
+
+class GraphC1Visualizer {
+ public:
+  GraphC1Visualizer(std::ostream& os, Zone* zone);  // NOLINT
+
+  void PrintCompilation(const CompilationInfo* info);
+  void PrintSchedule(const char* phase, const Schedule* schedule,
+                     const SourcePositionTable* positions,
+                     const InstructionSequence* instructions);
+  void PrintAllocator(const char* phase, const RegisterAllocator* allocator);
+  Zone* zone() const { return zone_; }
+
+ private:
+  void PrintIndent();
+  void PrintStringProperty(const char* name, const char* value);
+  void PrintLongProperty(const char* name, int64_t value);
+  void PrintIntProperty(const char* name, int value);
+  void PrintBlockProperty(const char* name, BasicBlock::Id block_id);
+  void PrintNodeId(Node* n);
+  void PrintNode(Node* n);
+  void PrintInputs(Node* n);
+  void PrintInputs(InputIter* i, int count, const char* prefix);
+  void PrintType(Node* node);
+
+  void PrintLiveRange(LiveRange* range, const char* type);
+  class Tag FINAL BASE_EMBEDDED {
+   public:
+    Tag(GraphC1Visualizer* visualizer, const char* name) {
+      name_ = name;
+      visualizer_ = visualizer;
+      visualizer->PrintIndent();
+      visualizer_->os_ << "begin_" << name << "\n";
+      visualizer->indent_++;
+    }
+
+    ~Tag() {
+      visualizer_->indent_--;
+      visualizer_->PrintIndent();
+      visualizer_->os_ << "end_" << name_ << "\n";
+      DCHECK(visualizer_->indent_ >= 0);
+    }
+
+   private:
+    GraphC1Visualizer* visualizer_;
+    const char* name_;
+  };
+
+  std::ostream& os_;
+  int indent_;
+  Zone* zone_;
+
+  DISALLOW_COPY_AND_ASSIGN(GraphC1Visualizer);
+};
+
+
+void GraphC1Visualizer::PrintIndent() {
+  for (int i = 0; i < indent_; i++) {
+    os_ << "  ";
+  }
+}
+
+
+GraphC1Visualizer::GraphC1Visualizer(std::ostream& os, Zone* zone)
+    : os_(os), indent_(0), zone_(zone) {}
+
+
+void GraphC1Visualizer::PrintStringProperty(const char* name,
+                                            const char* value) {
+  PrintIndent();
+  os_ << name << " \"" << value << "\"\n";
+}
+
+
+void GraphC1Visualizer::PrintLongProperty(const char* name, int64_t value) {
+  PrintIndent();
+  os_ << name << " " << static_cast<int>(value / 1000) << "\n";
+}
+
+
+void GraphC1Visualizer::PrintBlockProperty(const char* name,
+                                           BasicBlock::Id block_id) {
+  PrintIndent();
+  os_ << name << " \"B" << block_id << "\"\n";
+}
+
+
+void GraphC1Visualizer::PrintIntProperty(const char* name, int value) {
+  PrintIndent();
+  os_ << name << " " << value << "\n";
+}
+
+
+void GraphC1Visualizer::PrintCompilation(const CompilationInfo* info) {
+  Tag tag(this, "compilation");
+  if (info->IsOptimizing()) {
+    Handle<String> name = info->function()->debug_name();
+    PrintStringProperty("name", name->ToCString().get());
+    PrintIndent();
+    os_ << "method \"" << name->ToCString().get() << ":"
+        << info->optimization_id() << "\"\n";
+  } else {
+    CodeStub::Major major_key = info->code_stub()->MajorKey();
+    PrintStringProperty("name", CodeStub::MajorName(major_key, false));
+    PrintStringProperty("method", "stub");
+  }
+  PrintLongProperty("date",
+                    static_cast<int64_t>(base::OS::TimeCurrentMillis()));
+}
+
+
+void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << SafeId(n); }
+
+
+void GraphC1Visualizer::PrintNode(Node* n) {
+  PrintNodeId(n);
+  os_ << " " << *n->op() << " ";
+  PrintInputs(n);
+}
+
+
+void GraphC1Visualizer::PrintInputs(InputIter* i, int count,
+                                    const char* prefix) {
+  if (count > 0) {
+    os_ << prefix;
+  }
+  while (count > 0) {
+    os_ << " ";
+    PrintNodeId(**i);
+    ++(*i);
+    count--;
+  }
+}
+
+
+void GraphC1Visualizer::PrintInputs(Node* node) {
+  auto i = node->inputs().begin();
+  PrintInputs(&i, node->op()->ValueInputCount(), " ");
+  PrintInputs(&i, OperatorProperties::GetContextInputCount(node->op()),
+              " Ctx:");
+  PrintInputs(&i, OperatorProperties::GetFrameStateInputCount(node->op()),
+              " FS:");
+  PrintInputs(&i, node->op()->EffectInputCount(), " Eff:");
+  PrintInputs(&i, node->op()->ControlInputCount(), " Ctrl:");
+}
+
+
+void GraphC1Visualizer::PrintType(Node* node) {
+  if (NodeProperties::IsTyped(node)) {
+    Bounds bounds = NodeProperties::GetBounds(node);
+    os_ << " type:";
+    bounds.upper->PrintTo(os_);
+    os_ << "..";
+    bounds.lower->PrintTo(os_);
+  }
+}
+
+
+void GraphC1Visualizer::PrintSchedule(const char* phase,
+                                      const Schedule* schedule,
+                                      const SourcePositionTable* positions,
+                                      const InstructionSequence* instructions) {
+  Tag tag(this, "cfg");
+  PrintStringProperty("name", phase);
+  const BasicBlockVector* rpo = schedule->rpo_order();
+  for (size_t i = 0; i < rpo->size(); i++) {
+    BasicBlock* current = (*rpo)[i];
+    Tag block_tag(this, "block");
+    PrintBlockProperty("name", current->id());
+    PrintIntProperty("from_bci", -1);
+    PrintIntProperty("to_bci", -1);
+
+    PrintIndent();
+    os_ << "predecessors";
+    for (BasicBlock::Predecessors::iterator j = current->predecessors_begin();
+         j != current->predecessors_end(); ++j) {
+      os_ << " \"B" << (*j)->id() << "\"";
+    }
+    os_ << "\n";
+
+    PrintIndent();
+    os_ << "successors";
+    for (BasicBlock::Successors::iterator j = current->successors_begin();
+         j != current->successors_end(); ++j) {
+      os_ << " \"B" << (*j)->id() << "\"";
+    }
+    os_ << "\n";
+
+    PrintIndent();
+    os_ << "xhandlers\n";
+
+    PrintIndent();
+    os_ << "flags\n";
+
+    if (current->dominator() != NULL) {
+      PrintBlockProperty("dominator", current->dominator()->id());
+    }
+
+    PrintIntProperty("loop_depth", current->loop_depth());
+
+    const InstructionBlock* instruction_block =
+        instructions->InstructionBlockAt(current->GetRpoNumber());
+    if (instruction_block->code_start() >= 0) {
+      int first_index = instruction_block->first_instruction_index();
+      int last_index = instruction_block->last_instruction_index();
+      PrintIntProperty("first_lir_id", LifetimePosition::FromInstructionIndex(
+                                           first_index).Value());
+      PrintIntProperty("last_lir_id", LifetimePosition::FromInstructionIndex(
+                                          last_index).Value());
+    }
+
+    {
+      Tag states_tag(this, "states");
+      Tag locals_tag(this, "locals");
+      int total = 0;
+      for (BasicBlock::const_iterator i = current->begin(); i != current->end();
+           ++i) {
+        if ((*i)->opcode() == IrOpcode::kPhi) total++;
+      }
+      PrintIntProperty("size", total);
+      PrintStringProperty("method", "None");
+      int index = 0;
+      for (BasicBlock::const_iterator i = current->begin(); i != current->end();
+           ++i) {
+        if ((*i)->opcode() != IrOpcode::kPhi) continue;
+        PrintIndent();
+        os_ << index << " ";
+        PrintNodeId(*i);
+        os_ << " [";
+        PrintInputs(*i);
+        os_ << "]\n";
+        index++;
+      }
+    }
+
+    {
+      Tag HIR_tag(this, "HIR");
+      for (BasicBlock::const_iterator i = current->begin(); i != current->end();
+           ++i) {
+        Node* node = *i;
+        if (node->opcode() == IrOpcode::kPhi) continue;
+        int uses = node->UseCount();
+        PrintIndent();
+        os_ << "0 " << uses << " ";
+        PrintNode(node);
+        if (FLAG_trace_turbo_types) {
+          os_ << " ";
+          PrintType(node);
+        }
+        if (positions != NULL) {
+          SourcePosition position = positions->GetSourcePosition(node);
+          if (!position.IsUnknown()) {
+            DCHECK(!position.IsInvalid());
+            os_ << " pos:" << position.raw();
+          }
+        }
+        os_ << " <|@\n";
+      }
+
+      BasicBlock::Control control = current->control();
+      if (control != BasicBlock::kNone) {
+        PrintIndent();
+        os_ << "0 0 ";
+        if (current->control_input() != NULL) {
+          PrintNode(current->control_input());
+        } else {
+          os_ << -1 - current->id().ToInt() << " Goto";
+        }
+        os_ << " ->";
+        for (BasicBlock::Successors::iterator j = current->successors_begin();
+             j != current->successors_end(); ++j) {
+          os_ << " B" << (*j)->id();
+        }
+        if (FLAG_trace_turbo_types && current->control_input() != NULL) {
+          os_ << " ";
+          PrintType(current->control_input());
+        }
+        os_ << " <|@\n";
+      }
+    }
+
+    if (instructions != NULL) {
+      Tag LIR_tag(this, "LIR");
+      for (int j = instruction_block->first_instruction_index();
+           j <= instruction_block->last_instruction_index(); j++) {
+        PrintIndent();
+        PrintableInstruction printable = {RegisterConfiguration::ArchDefault(),
+                                          instructions->InstructionAt(j)};
+        os_ << j << " " << printable << " <|@\n";
+      }
+    }
+  }
+}
+
+
+void GraphC1Visualizer::PrintAllocator(const char* phase,
+                                       const RegisterAllocator* allocator) {
+  Tag tag(this, "intervals");
+  PrintStringProperty("name", phase);
+
+  for (auto range : allocator->fixed_double_live_ranges()) {
+    PrintLiveRange(range, "fixed");
+  }
+
+  for (auto range : allocator->fixed_live_ranges()) {
+    PrintLiveRange(range, "fixed");
+  }
+
+  for (auto range : allocator->live_ranges()) {
+    PrintLiveRange(range, "object");
+  }
+}
+
+
+void GraphC1Visualizer::PrintLiveRange(LiveRange* range, const char* type) {
+  if (range != NULL && !range->IsEmpty()) {
+    PrintIndent();
+    os_ << range->id() << " " << type;
+    if (range->HasRegisterAssigned()) {
+      InstructionOperand* op = range->CreateAssignedOperand(zone());
+      int assigned_reg = op->index();
+      if (op->IsDoubleRegister()) {
+        os_ << " \"" << DoubleRegister::AllocationIndexToString(assigned_reg)
+            << "\"";
+      } else {
+        DCHECK(op->IsRegister());
+        os_ << " \"" << Register::AllocationIndexToString(assigned_reg) << "\"";
+      }
+    } else if (range->IsSpilled()) {
+      int index = -1;
+      if (range->TopLevel()->HasSpillRange()) {
+        index = kMaxInt;  // This hasn't been set yet.
+      } else {
+        index = range->TopLevel()->GetSpillOperand()->index();
+      }
+      if (range->TopLevel()->Kind() == DOUBLE_REGISTERS) {
+        os_ << " \"double_stack:" << index << "\"";
+      } else if (range->TopLevel()->Kind() == GENERAL_REGISTERS) {
+        os_ << " \"stack:" << index << "\"";
+      } else {
+        os_ << " \"const(nostack):" << index << "\"";
+      }
+    }
+    int parent_index = -1;
+    if (range->IsChild()) {
+      parent_index = range->parent()->id();
+    } else {
+      parent_index = range->id();
+    }
+    InstructionOperand* op = range->FirstHint();
+    int hint_index = -1;
+    if (op != NULL && op->IsUnallocated()) {
+      hint_index = UnallocatedOperand::cast(op)->virtual_register();
+    }
+    os_ << " " << parent_index << " " << hint_index;
+    UseInterval* cur_interval = range->first_interval();
+    while (cur_interval != NULL && range->Covers(cur_interval->start())) {
+      os_ << " [" << cur_interval->start().Value() << ", "
+          << cur_interval->end().Value() << "[";
+      cur_interval = cur_interval->next();
+    }
+
+    UsePosition* current_pos = range->first_pos();
+    while (current_pos != NULL) {
+      if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
+        os_ << " " << current_pos->pos().Value() << " M";
+      }
+      current_pos = current_pos->next();
+    }
+
+    os_ << " \"\"\n";
+  }
+}
+
+
+std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac) {
+  Zone tmp_zone(ac.info_->isolate());
+  GraphC1Visualizer(os, &tmp_zone).PrintCompilation(ac.info_);
+  return os;
+}
+
+
+std::ostream& operator<<(std::ostream& os, const AsC1V& ac) {
+  Zone tmp_zone(ac.schedule_->zone()->isolate());
+  GraphC1Visualizer(os, &tmp_zone)
+      .PrintSchedule(ac.phase_, ac.schedule_, ac.positions_, ac.instructions_);
+  return os;
+}
+
+
+std::ostream& operator<<(std::ostream& os, const AsC1VAllocator& ac) {
+  Zone tmp_zone(ac.allocator_->code()->zone()->isolate());
+  GraphC1Visualizer(os, &tmp_zone).PrintAllocator(ac.phase_, ac.allocator_);
+  return os;
+}
+
+const int kUnvisited = 0;
+const int kOnStack = 1;
+const int kVisited = 2;
+
+std::ostream& operator<<(std::ostream& os, const AsRPO& ar) {
+  Zone local_zone(ar.graph.zone()->isolate());
+  ZoneVector<byte> state(ar.graph.NodeCount(), kUnvisited, &local_zone);
+  ZoneStack<Node*> stack(&local_zone);
+
+  stack.push(ar.graph.end());
+  state[ar.graph.end()->id()] = kOnStack;
+  while (!stack.empty()) {
+    Node* n = stack.top();
+    bool pop = true;
+    for (Node* const i : n->inputs()) {
+      if (state[i->id()] == kUnvisited) {
+        state[i->id()] = kOnStack;
+        stack.push(i);
+        pop = false;
+        break;
+      }
+    }
+    if (pop) {
+      state[n->id()] = kVisited;
+      stack.pop();
+      os << "#" << SafeId(n) << ":" << SafeMnemonic(n) << "(";
+      int j = 0;
+      for (Node* const i : n->inputs()) {
+        if (j++ > 0) os << ", ";
+        os << "#" << SafeId(i) << ":" << SafeMnemonic(i);
+      }
+      os << ")" << std::endl;
+    }
+  }
+  return os;
+}
 }
 }
 }  // namespace v8::internal::compiler
diff --git a/src/compiler/graph-visualizer.h b/src/compiler/graph-visualizer.h
index 12532ba..3dd66ea 100644
--- a/src/compiler/graph-visualizer.h
+++ b/src/compiler/graph-visualizer.h
@@ -5,25 +5,80 @@
 #ifndef V8_COMPILER_GRAPH_VISUALIZER_H_
 #define V8_COMPILER_GRAPH_VISUALIZER_H_
 
-#include "src/v8.h"
+#include <iosfwd>
 
 namespace v8 {
 namespace internal {
 
-class OStream;
+class CompilationInfo;
 
 namespace compiler {
 
 class Graph;
+class InstructionSequence;
+class RegisterAllocator;
+class Schedule;
+class SourcePositionTable;
+
 
 struct AsDOT {
   explicit AsDOT(const Graph& g) : graph(g) {}
   const Graph& graph;
 };
 
-OStream& operator<<(OStream& os, const AsDOT& ad);
-}
-}
-}  // namespace v8::internal::compiler
+std::ostream& operator<<(std::ostream& os, const AsDOT& ad);
+
+
+struct AsJSON {
+  explicit AsJSON(const Graph& g) : graph(g) {}
+  const Graph& graph;
+};
+
+std::ostream& operator<<(std::ostream& os, const AsJSON& ad);
+
+struct AsRPO {
+  explicit AsRPO(const Graph& g) : graph(g) {}
+  const Graph& graph;
+};
+
+std::ostream& operator<<(std::ostream& os, const AsRPO& ad);
+
+
+struct AsC1VCompilation {
+  explicit AsC1VCompilation(const CompilationInfo* info) : info_(info) {}
+  const CompilationInfo* info_;
+};
+
+
+struct AsC1V {
+  AsC1V(const char* phase, const Schedule* schedule,
+        const SourcePositionTable* positions = NULL,
+        const InstructionSequence* instructions = NULL)
+      : schedule_(schedule),
+        instructions_(instructions),
+        positions_(positions),
+        phase_(phase) {}
+  const Schedule* schedule_;
+  const InstructionSequence* instructions_;
+  const SourcePositionTable* positions_;
+  const char* phase_;
+};
+
+struct AsC1VAllocator {
+  explicit AsC1VAllocator(const char* phase,
+                          const RegisterAllocator* allocator = NULL)
+      : phase_(phase), allocator_(allocator) {}
+  const char* phase_;
+  const RegisterAllocator* allocator_;
+};
+
+std::ostream& operator<<(std::ostream& os, const AsDOT& ad);
+std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac);
+std::ostream& operator<<(std::ostream& os, const AsC1V& ac);
+std::ostream& operator<<(std::ostream& os, const AsC1VAllocator& ac);
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_GRAPH_VISUALIZER_H_
diff --git a/src/compiler/graph.cc b/src/compiler/graph.cc
index 7b5f228..995046b 100644
--- a/src/compiler/graph.cc
+++ b/src/compiler/graph.cc
@@ -5,29 +5,42 @@
 #include "src/compiler/graph.h"
 
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/node.h"
 #include "src/compiler/node-aux-data-inl.h"
 #include "src/compiler/node-properties.h"
 #include "src/compiler/node-properties-inl.h"
+#include "src/compiler/opcodes.h"
 #include "src/compiler/operator-properties.h"
-#include "src/compiler/operator-properties-inl.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
-Graph::Graph(Zone* zone) : GenericGraph<Node>(zone), decorators_(zone) {}
+Graph::Graph(Zone* zone)
+    : zone_(zone),
+      start_(NULL),
+      end_(NULL),
+      mark_max_(0),
+      next_node_id_(0),
+      decorators_(zone) {}
 
 
-Node* Graph::NewNode(const Operator* op, int input_count, Node** inputs) {
-  DCHECK_LE(op->InputCount(), input_count);
-  Node* result = Node::New(this, input_count, inputs);
-  result->Initialize(op);
+void Graph::Decorate(Node* node) {
   for (ZoneVector<GraphDecorator*>::iterator i = decorators_.begin();
        i != decorators_.end(); ++i) {
-    (*i)->Decorate(result);
+    (*i)->Decorate(node);
+  }
+}
+
+
+Node* Graph::NewNode(const Operator* op, int input_count, Node** inputs,
+                     bool incomplete) {
+  DCHECK_LE(op->ValueInputCount(), input_count);
+  Node* result = Node::New(this, input_count, inputs, incomplete);
+  result->Initialize(op);
+  if (!incomplete) {
+    Decorate(result);
   }
   return result;
 }
diff --git a/src/compiler/graph.h b/src/compiler/graph.h
index 07eb02f..d619da2 100644
--- a/src/compiler/graph.h
+++ b/src/compiler/graph.h
@@ -8,7 +8,6 @@
 #include <map>
 #include <set>
 
-#include "src/compiler/generic-algorithm.h"
 #include "src/compiler/node.h"
 #include "src/compiler/node-aux-data.h"
 #include "src/compiler/source-position.h"
@@ -17,19 +16,21 @@
 namespace internal {
 namespace compiler {
 
+// Forward declarations.
 class GraphDecorator;
 
 
-class Graph : public GenericGraph<Node> {
+class Graph : public ZoneObject {
  public:
   explicit Graph(Zone* zone);
 
   // Base implementation used by all factory methods.
-  Node* NewNode(const Operator* op, int input_count, Node** inputs);
+  Node* NewNode(const Operator* op, int input_count, Node** inputs,
+                bool incomplete = false);
 
   // Factories for nodes with static input counts.
   Node* NewNode(const Operator* op) {
-    return NewNode(op, 0, static_cast<Node**>(NULL));
+    return NewNode(op, 0, static_cast<Node**>(nullptr));
   }
   Node* NewNode(const Operator* op, Node* n1) { return NewNode(op, 1, &n1); }
   Node* NewNode(const Operator* op, Node* n1, Node* n2) {
@@ -54,15 +55,26 @@
     Node* nodes[] = {n1, n2, n3, n4, n5, n6};
     return NewNode(op, arraysize(nodes), nodes);
   }
+  Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4,
+                Node* n5, Node* n6, Node* n7) {
+    Node* nodes[] = {n1, n2, n3, n4, n5, n6, n7};
+    return NewNode(op, arraysize(nodes), nodes);
+  }
 
   template <class Visitor>
-  void VisitNodeUsesFrom(Node* node, Visitor* visitor);
+  inline void VisitNodeInputsFromEnd(Visitor* visitor);
 
-  template <class Visitor>
-  void VisitNodeUsesFromStart(Visitor* visitor);
+  Zone* zone() const { return zone_; }
+  Node* start() const { return start_; }
+  Node* end() const { return end_; }
 
-  template <class Visitor>
-  void VisitNodeInputsFromEnd(Visitor* visitor);
+  void SetStart(Node* start) { start_ = start; }
+  void SetEnd(Node* end) { end_ = end; }
+
+  NodeId NextNodeID() { return next_node_id_++; }
+  NodeId NodeCount() const { return next_node_id_; }
+
+  void Decorate(Node* node);
 
   void AddDecorator(GraphDecorator* decorator) {
     decorators_.push_back(decorator);
@@ -76,10 +88,56 @@
   }
 
  private:
+  template <typename State>
+  friend class NodeMarker;
+
+  Zone* zone_;
+  Node* start_;
+  Node* end_;
+  Mark mark_max_;
+  NodeId next_node_id_;
   ZoneVector<GraphDecorator*> decorators_;
+
+  DISALLOW_COPY_AND_ASSIGN(Graph);
 };
 
 
+// A NodeMarker uses monotonically increasing marks to assign local "states"
+// to nodes. Only one NodeMarker per graph is valid at a given time.
+template <typename State>
+class NodeMarker BASE_EMBEDDED {
+ public:
+  NodeMarker(Graph* graph, uint32_t num_states)
+      : mark_min_(graph->mark_max_), mark_max_(graph->mark_max_ += num_states) {
+    DCHECK(num_states > 0);         // user error!
+    DCHECK(mark_max_ > mark_min_);  // check for wraparound.
+  }
+
+  State Get(Node* node) {
+    Mark mark = node->mark();
+    if (mark < mark_min_) {
+      mark = mark_min_;
+      node->set_mark(mark_min_);
+    }
+    DCHECK_LT(mark, mark_max_);
+    return static_cast<State>(mark - mark_min_);
+  }
+
+  void Set(Node* node, State state) {
+    Mark local = static_cast<Mark>(state);
+    DCHECK(local < (mark_max_ - mark_min_));
+    DCHECK_LT(node->mark(), mark_max_);
+    node->set_mark(local + mark_min_);
+  }
+
+ private:
+  Mark mark_min_;
+  Mark mark_max_;
+};
+
+
+// A graph decorator can be used to add behavior to the creation of nodes
+// in a graph.
 class GraphDecorator : public ZoneObject {
  public:
   virtual ~GraphDecorator() {}
diff --git a/src/compiler/ia32/code-generator-ia32.cc b/src/compiler/ia32/code-generator-ia32.cc
index deab7cd..55f7426 100644
--- a/src/compiler/ia32/code-generator-ia32.cc
+++ b/src/compiler/ia32/code-generator-ia32.cc
@@ -33,8 +33,6 @@
 
   Operand OutputOperand() { return ToOperand(instr_->Output()); }
 
-  Operand TempOperand(int index) { return ToOperand(instr_->TempAt(index)); }
-
   Operand ToOperand(InstructionOperand* op, int extra = 0) {
     if (op->IsRegister()) {
       DCHECK(extra == 0);
@@ -59,6 +57,9 @@
     switch (constant.type()) {
       case Constant::kInt32:
         return Immediate(constant.ToInt32());
+      case Constant::kFloat32:
+        return Immediate(
+            isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
       case Constant::kFloat64:
         return Immediate(
             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
@@ -68,44 +69,216 @@
         return Immediate(constant.ToHeapObject());
       case Constant::kInt64:
         break;
+      case Constant::kRpoNumber:
+        return Immediate::CodeRelativeOffset(ToLabel(operand));
     }
     UNREACHABLE();
     return Immediate(-1);
   }
 
-  Operand MemoryOperand(int* first_input) {
-    const int offset = *first_input;
-    switch (AddressingModeField::decode(instr_->opcode())) {
-      case kMode_MR1I:
-        *first_input += 2;
-        return Operand(InputRegister(offset + 0), InputRegister(offset + 1),
-                       times_1,
-                       0);  // TODO(dcarney): K != 0
-      case kMode_MRI:
-        *first_input += 2;
-        return Operand::ForRegisterPlusImmediate(InputRegister(offset + 0),
-                                                 InputImmediate(offset + 1));
-      case kMode_MI:
-        *first_input += 1;
-        return Operand(InputImmediate(offset + 0));
-      default:
-        UNREACHABLE();
-        return Operand(no_reg);
-    }
+  static int NextOffset(int* offset) {
+    int i = *offset;
+    (*offset)++;
+    return i;
   }
 
-  Operand MemoryOperand() {
-    int first_input = 0;
+  static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) {
+    STATIC_ASSERT(0 == static_cast<int>(times_1));
+    STATIC_ASSERT(1 == static_cast<int>(times_2));
+    STATIC_ASSERT(2 == static_cast<int>(times_4));
+    STATIC_ASSERT(3 == static_cast<int>(times_8));
+    int scale = static_cast<int>(mode - one);
+    DCHECK(scale >= 0 && scale < 4);
+    return static_cast<ScaleFactor>(scale);
+  }
+
+  Operand MemoryOperand(int* offset) {
+    AddressingMode mode = AddressingModeField::decode(instr_->opcode());
+    switch (mode) {
+      case kMode_MR: {
+        Register base = InputRegister(NextOffset(offset));
+        int32_t disp = 0;
+        return Operand(base, disp);
+      }
+      case kMode_MRI: {
+        Register base = InputRegister(NextOffset(offset));
+        int32_t disp = InputInt32(NextOffset(offset));
+        return Operand(base, disp);
+      }
+      case kMode_MR1:
+      case kMode_MR2:
+      case kMode_MR4:
+      case kMode_MR8: {
+        Register base = InputRegister(NextOffset(offset));
+        Register index = InputRegister(NextOffset(offset));
+        ScaleFactor scale = ScaleFor(kMode_MR1, mode);
+        int32_t disp = 0;
+        return Operand(base, index, scale, disp);
+      }
+      case kMode_MR1I:
+      case kMode_MR2I:
+      case kMode_MR4I:
+      case kMode_MR8I: {
+        Register base = InputRegister(NextOffset(offset));
+        Register index = InputRegister(NextOffset(offset));
+        ScaleFactor scale = ScaleFor(kMode_MR1I, mode);
+        int32_t disp = InputInt32(NextOffset(offset));
+        return Operand(base, index, scale, disp);
+      }
+      case kMode_M1:
+      case kMode_M2:
+      case kMode_M4:
+      case kMode_M8: {
+        Register index = InputRegister(NextOffset(offset));
+        ScaleFactor scale = ScaleFor(kMode_M1, mode);
+        int32_t disp = 0;
+        return Operand(index, scale, disp);
+      }
+      case kMode_M1I:
+      case kMode_M2I:
+      case kMode_M4I:
+      case kMode_M8I: {
+        Register index = InputRegister(NextOffset(offset));
+        ScaleFactor scale = ScaleFor(kMode_M1I, mode);
+        int32_t disp = InputInt32(NextOffset(offset));
+        return Operand(index, scale, disp);
+      }
+      case kMode_MI: {
+        int32_t disp = InputInt32(NextOffset(offset));
+        return Operand(Immediate(disp));
+      }
+      case kMode_None:
+        UNREACHABLE();
+        return Operand(no_reg, 0);
+    }
+    UNREACHABLE();
+    return Operand(no_reg, 0);
+  }
+
+  Operand MemoryOperand(int first_input = 0) {
     return MemoryOperand(&first_input);
   }
 };
 
 
-static bool HasImmediateInput(Instruction* instr, int index) {
+namespace {
+
+bool HasImmediateInput(Instruction* instr, int index) {
   return instr->InputAt(index)->IsImmediate();
 }
 
 
+class OutOfLineLoadInteger FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadInteger(CodeGenerator* gen, Register result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL { __ xor_(result_, result_); }
+
+ private:
+  Register const result_;
+};
+
+
+class OutOfLineLoadFloat FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL { __ pcmpeqd(result_, result_); }
+
+ private:
+  XMMRegister const result_;
+};
+
+
+class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
+ public:
+  OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result,
+                             XMMRegister input)
+      : OutOfLineCode(gen), result_(result), input_(input) {}
+
+  void Generate() FINAL {
+    __ sub(esp, Immediate(kDoubleSize));
+    __ movsd(MemOperand(esp, 0), input_);
+    __ SlowTruncateToI(result_, esp, 0);
+    __ add(esp, Immediate(kDoubleSize));
+  }
+
+ private:
+  Register const result_;
+  XMMRegister const input_;
+};
+
+}  // namespace
+
+
+#define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr)                          \
+  do {                                                                  \
+    auto result = i.OutputDoubleRegister();                             \
+    auto offset = i.InputRegister(0);                                   \
+    if (instr->InputAt(1)->IsRegister()) {                              \
+      __ cmp(offset, i.InputRegister(1));                               \
+    } else {                                                            \
+      __ cmp(offset, i.InputImmediate(1));                              \
+    }                                                                   \
+    OutOfLineCode* ool = new (zone()) OutOfLineLoadFloat(this, result); \
+    __ j(above_equal, ool->entry());                                    \
+    __ asm_instr(result, i.MemoryOperand(2));                           \
+    __ bind(ool->exit());                                               \
+  } while (false)
+
+
+#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                          \
+  do {                                                                    \
+    auto result = i.OutputRegister();                                     \
+    auto offset = i.InputRegister(0);                                     \
+    if (instr->InputAt(1)->IsRegister()) {                                \
+      __ cmp(offset, i.InputRegister(1));                                 \
+    } else {                                                              \
+      __ cmp(offset, i.InputImmediate(1));                                \
+    }                                                                     \
+    OutOfLineCode* ool = new (zone()) OutOfLineLoadInteger(this, result); \
+    __ j(above_equal, ool->entry());                                      \
+    __ asm_instr(result, i.MemoryOperand(2));                             \
+    __ bind(ool->exit());                                                 \
+  } while (false)
+
+
+#define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr)                 \
+  do {                                                          \
+    auto offset = i.InputRegister(0);                           \
+    if (instr->InputAt(1)->IsRegister()) {                      \
+      __ cmp(offset, i.InputRegister(1));                       \
+    } else {                                                    \
+      __ cmp(offset, i.InputImmediate(1));                      \
+    }                                                           \
+    Label done;                                                 \
+    __ j(above_equal, &done, Label::kNear);                     \
+    __ asm_instr(i.MemoryOperand(3), i.InputDoubleRegister(2)); \
+    __ bind(&done);                                             \
+  } while (false)
+
+
+#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)            \
+  do {                                                       \
+    auto offset = i.InputRegister(0);                        \
+    if (instr->InputAt(1)->IsRegister()) {                   \
+      __ cmp(offset, i.InputRegister(1));                    \
+    } else {                                                 \
+      __ cmp(offset, i.InputImmediate(1));                   \
+    }                                                        \
+    Label done;                                              \
+    __ j(above_equal, &done, Label::kNear);                  \
+    if (instr->InputAt(2)->IsRegister()) {                   \
+      __ asm_instr(i.MemoryOperand(3), i.InputRegister(2));  \
+    } else {                                                 \
+      __ asm_instr(i.MemoryOperand(3), i.InputImmediate(2)); \
+    }                                                        \
+    __ bind(&done);                                          \
+  } while (false)
+
+
 // Assembles an instruction after register allocation, producing machine code.
 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
   IA32OperandConverter i(this, instr);
@@ -136,7 +309,7 @@
       break;
     }
     case kArchJmp:
-      __ jmp(code()->GetLabel(i.InputBlock(0)));
+      AssembleArchJump(i.InputRpo(0));
       break;
     case kArchNop:
       // don't emit code for nops.
@@ -144,9 +317,19 @@
     case kArchRet:
       AssembleReturn();
       break;
-    case kArchTruncateDoubleToI:
-      __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
+    case kArchStackPointer:
+      __ mov(i.OutputRegister(), esp);
       break;
+    case kArchTruncateDoubleToI: {
+      auto result = i.OutputRegister();
+      auto input = i.InputDoubleRegister(0);
+      auto ool = new (zone()) OutOfLineTruncateDoubleToI(this, result, input);
+      __ cvttsd2si(result, Operand(input));
+      __ cmp(result, 1);
+      __ j(overflow, ool->entry());
+      __ bind(ool->exit());
+      break;
+    }
     case kIA32Add:
       if (HasImmediateInput(instr, 1)) {
         __ add(i.InputOperand(0), i.InputImmediate(1));
@@ -182,12 +365,18 @@
         __ imul(i.OutputRegister(), i.InputOperand(1));
       }
       break;
+    case kIA32ImulHigh:
+      __ imul(i.InputRegister(1));
+      break;
+    case kIA32UmulHigh:
+      __ mul(i.InputRegister(1));
+      break;
     case kIA32Idiv:
       __ cdq();
       __ idiv(i.InputOperand(1));
       break;
     case kIA32Udiv:
-      __ xor_(edx, edx);
+      __ Move(edx, Immediate(0));
       __ div(i.InputOperand(1));
       break;
     case kIA32Not:
@@ -219,46 +408,46 @@
       break;
     case kIA32Shl:
       if (HasImmediateInput(instr, 1)) {
-        __ shl(i.OutputRegister(), i.InputInt5(1));
+        __ shl(i.OutputOperand(), i.InputInt5(1));
       } else {
-        __ shl_cl(i.OutputRegister());
+        __ shl_cl(i.OutputOperand());
       }
       break;
     case kIA32Shr:
       if (HasImmediateInput(instr, 1)) {
-        __ shr(i.OutputRegister(), i.InputInt5(1));
+        __ shr(i.OutputOperand(), i.InputInt5(1));
       } else {
-        __ shr_cl(i.OutputRegister());
+        __ shr_cl(i.OutputOperand());
       }
       break;
     case kIA32Sar:
       if (HasImmediateInput(instr, 1)) {
-        __ sar(i.OutputRegister(), i.InputInt5(1));
+        __ sar(i.OutputOperand(), i.InputInt5(1));
       } else {
-        __ sar_cl(i.OutputRegister());
+        __ sar_cl(i.OutputOperand());
       }
       break;
     case kIA32Ror:
       if (HasImmediateInput(instr, 1)) {
-        __ ror(i.OutputRegister(), i.InputInt5(1));
+        __ ror(i.OutputOperand(), i.InputInt5(1));
       } else {
-        __ ror_cl(i.OutputRegister());
+        __ ror_cl(i.OutputOperand());
       }
       break;
     case kSSEFloat64Cmp:
       __ ucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
       break;
     case kSSEFloat64Add:
-      __ addsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+      __ addsd(i.InputDoubleRegister(0), i.InputOperand(1));
       break;
     case kSSEFloat64Sub:
-      __ subsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+      __ subsd(i.InputDoubleRegister(0), i.InputOperand(1));
       break;
     case kSSEFloat64Mul:
-      __ mulsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+      __ mulsd(i.InputDoubleRegister(0), i.InputOperand(1));
       break;
     case kSSEFloat64Div:
-      __ divsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+      __ divsd(i.InputDoubleRegister(0), i.InputOperand(1));
       break;
     case kSSEFloat64Mod: {
       // TODO(dcarney): alignment is wrong.
@@ -288,6 +477,30 @@
     case kSSEFloat64Sqrt:
       __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0));
       break;
+    case kSSEFloat64Floor: {
+      CpuFeatureScope sse_scope(masm(), SSE4_1);
+      __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                 v8::internal::Assembler::kRoundDown);
+      break;
+    }
+    case kSSEFloat64Ceil: {
+      CpuFeatureScope sse_scope(masm(), SSE4_1);
+      __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                 v8::internal::Assembler::kRoundUp);
+      break;
+    }
+    case kSSEFloat64RoundTruncate: {
+      CpuFeatureScope sse_scope(masm(), SSE4_1);
+      __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                 v8::internal::Assembler::kRoundToZero);
+      break;
+    }
+    case kSSECvtss2sd:
+      __ cvtss2sd(i.OutputDoubleRegister(), i.InputOperand(0));
+      break;
+    case kSSECvtsd2ss:
+      __ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0));
+      break;
     case kSSEFloat64ToInt32:
       __ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
       break;
@@ -303,9 +516,32 @@
       __ cvtsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
       break;
     case kSSEUint32ToFloat64:
-      // TODO(turbofan): IA32 SSE LoadUint32() should take an operand.
-      __ LoadUint32(i.OutputDoubleRegister(), i.InputRegister(0));
+      __ LoadUint32(i.OutputDoubleRegister(), i.InputOperand(0));
       break;
+    case kAVXFloat64Add: {
+      CpuFeatureScope avx_scope(masm(), AVX);
+      __ vaddsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                i.InputOperand(1));
+      break;
+    }
+    case kAVXFloat64Sub: {
+      CpuFeatureScope avx_scope(masm(), AVX);
+      __ vsubsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                i.InputOperand(1));
+      break;
+    }
+    case kAVXFloat64Mul: {
+      CpuFeatureScope avx_scope(masm(), AVX);
+      __ vmulsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                i.InputOperand(1));
+      break;
+    }
+    case kAVXFloat64Div: {
+      CpuFeatureScope avx_scope(masm(), AVX);
+      __ vdivsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                i.InputOperand(1));
+      break;
+    }
     case kIA32Movsxbl:
       __ movsx_b(i.OutputRegister(), i.MemoryOperand());
       break;
@@ -363,14 +599,47 @@
     case kIA32Movss:
       if (instr->HasOutput()) {
         __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
-        __ cvtss2sd(i.OutputDoubleRegister(), i.OutputDoubleRegister());
       } else {
         int index = 0;
         Operand operand = i.MemoryOperand(&index);
-        __ cvtsd2ss(xmm0, i.InputDoubleRegister(index));
-        __ movss(operand, xmm0);
+        __ movss(operand, i.InputDoubleRegister(index));
       }
       break;
+    case kIA32Lea: {
+      AddressingMode mode = AddressingModeField::decode(instr->opcode());
+      // Shorten "leal" to "addl", "subl" or "shll" if the register allocation
+      // and addressing mode just happens to work out. The "addl"/"subl" forms
+      // in these cases are faster based on measurements.
+      if (mode == kMode_MI) {
+        __ Move(i.OutputRegister(), Immediate(i.InputInt32(0)));
+      } else if (i.InputRegister(0).is(i.OutputRegister())) {
+        if (mode == kMode_MRI) {
+          int32_t constant_summand = i.InputInt32(1);
+          if (constant_summand > 0) {
+            __ add(i.OutputRegister(), Immediate(constant_summand));
+          } else if (constant_summand < 0) {
+            __ sub(i.OutputRegister(), Immediate(-constant_summand));
+          }
+        } else if (mode == kMode_MR1) {
+          if (i.InputRegister(1).is(i.OutputRegister())) {
+            __ shl(i.OutputRegister(), 1);
+          } else {
+            __ lea(i.OutputRegister(), i.MemoryOperand());
+          }
+        } else if (mode == kMode_M2) {
+          __ shl(i.OutputRegister(), 1);
+        } else if (mode == kMode_M4) {
+          __ shl(i.OutputRegister(), 2);
+        } else if (mode == kMode_M8) {
+          __ shl(i.OutputRegister(), 3);
+        } else {
+          __ lea(i.OutputRegister(), i.MemoryOperand());
+        }
+      } else {
+        __ lea(i.OutputRegister(), i.MemoryOperand());
+      }
+      break;
+    }
     case kIA32Push:
       if (HasImmediateInput(instr, 0)) {
         __ push(i.InputImmediate(0));
@@ -384,31 +653,59 @@
       Register value = i.InputRegister(2);
       __ mov(Operand(object, index, times_1, 0), value);
       __ lea(index, Operand(object, index, times_1, 0));
-      SaveFPRegsMode mode = code_->frame()->DidAllocateDoubleRegisters()
-                                ? kSaveFPRegs
-                                : kDontSaveFPRegs;
+      SaveFPRegsMode mode =
+          frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
       __ RecordWrite(object, index, value, mode);
       break;
     }
+    case kCheckedLoadInt8:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_b);
+      break;
+    case kCheckedLoadUint8:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_b);
+      break;
+    case kCheckedLoadInt16:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_w);
+      break;
+    case kCheckedLoadUint16:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_w);
+      break;
+    case kCheckedLoadWord32:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(mov);
+      break;
+    case kCheckedLoadFloat32:
+      ASSEMBLE_CHECKED_LOAD_FLOAT(movss);
+      break;
+    case kCheckedLoadFloat64:
+      ASSEMBLE_CHECKED_LOAD_FLOAT(movsd);
+      break;
+    case kCheckedStoreWord8:
+      ASSEMBLE_CHECKED_STORE_INTEGER(mov_b);
+      break;
+    case kCheckedStoreWord16:
+      ASSEMBLE_CHECKED_STORE_INTEGER(mov_w);
+      break;
+    case kCheckedStoreWord32:
+      ASSEMBLE_CHECKED_STORE_INTEGER(mov);
+      break;
+    case kCheckedStoreFloat32:
+      ASSEMBLE_CHECKED_STORE_FLOAT(movss);
+      break;
+    case kCheckedStoreFloat64:
+      ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
+      break;
   }
 }
 
 
-// Assembles branches after an instruction.
-void CodeGenerator::AssembleArchBranch(Instruction* instr,
-                                       FlagsCondition condition) {
+// Assembles a branch after an instruction.
+void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
   IA32OperandConverter i(this, instr);
-  Label done;
-
-  // Emit a branch. The true and false targets are always the last two inputs
-  // to the instruction.
-  BasicBlock* tblock = i.InputBlock(instr->InputCount() - 2);
-  BasicBlock* fblock = i.InputBlock(instr->InputCount() - 1);
-  bool fallthru = IsNextInAssemblyOrder(fblock);
-  Label* tlabel = code()->GetLabel(tblock);
-  Label* flabel = fallthru ? &done : code()->GetLabel(fblock);
-  Label::Distance flabel_distance = fallthru ? Label::kNear : Label::kFar;
-  switch (condition) {
+  Label::Distance flabel_distance =
+      branch->fallthru ? Label::kNear : Label::kFar;
+  Label* tlabel = branch->true_label;
+  Label* flabel = branch->false_label;
+  switch (branch->condition) {
     case kUnorderedEqual:
       __ j(parity_even, flabel, flabel_distance);
     // Fall through.
@@ -464,8 +761,13 @@
       __ j(no_overflow, tlabel);
       break;
   }
-  if (!fallthru) __ jmp(flabel, flabel_distance);  // no fallthru to flabel.
-  __ bind(&done);
+  // Add a jump if not falling through to the next block.
+  if (!branch->fallthru) __ jmp(flabel);
+}
+
+
+void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+  if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
 }
 
 
@@ -484,7 +786,7 @@
   switch (condition) {
     case kUnorderedEqual:
       __ j(parity_odd, &check, Label::kNear);
-      __ mov(reg, Immediate(0));
+      __ Move(reg, Immediate(0));
       __ jmp(&done, Label::kNear);
     // Fall through.
     case kEqual:
@@ -512,7 +814,7 @@
       break;
     case kUnorderedLessThan:
       __ j(parity_odd, &check, Label::kNear);
-      __ mov(reg, Immediate(0));
+      __ Move(reg, Immediate(0));
       __ jmp(&done, Label::kNear);
     // Fall through.
     case kUnsignedLessThan:
@@ -528,7 +830,7 @@
       break;
     case kUnorderedLessThanOrEqual:
       __ j(parity_odd, &check, Label::kNear);
-      __ mov(reg, Immediate(0));
+      __ Move(reg, Immediate(0));
       __ jmp(&done, Label::kNear);
     // Fall through.
     case kUnsignedLessThanOrEqual:
@@ -558,7 +860,7 @@
     // Emit a branch to set a register to either 1 or 0.
     Label set;
     __ j(cc, &set, Label::kNear);
-    __ mov(reg, Immediate(0));
+    __ Move(reg, Immediate(0));
     __ jmp(&done, Label::kNear);
     __ bind(&set);
     __ mov(reg, Immediate(1));
@@ -704,7 +1006,7 @@
 
 void CodeGenerator::AssemblePrologue() {
   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
-  Frame* frame = code_->frame();
+  Frame* frame = this->frame();
   int stack_slots = frame->GetSpillSlotCount();
   if (descriptor->kind() == CallDescriptor::kCallAddress) {
     // Assemble a prologue similar the to cdecl calling convention.
@@ -721,28 +1023,10 @@
       frame->SetRegisterSaveAreaSize(register_save_area_size);
     }
   } else if (descriptor->IsJSFunctionCall()) {
-    CompilationInfo* info = linkage()->info();
+    CompilationInfo* info = this->info();
     __ Prologue(info->IsCodePreAgingActive());
     frame->SetRegisterSaveAreaSize(
         StandardFrameConstants::kFixedFrameSizeFromFp);
-
-    // Sloppy mode functions and builtins need to replace the receiver with the
-    // global proxy when called as functions (without an explicit receiver
-    // object).
-    // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
-    if (info->strict_mode() == SLOPPY && !info->is_native()) {
-      Label ok;
-      // +2 for return address and saved frame pointer.
-      int receiver_slot = info->scope()->num_parameters() + 2;
-      __ mov(ecx, Operand(ebp, receiver_slot * kPointerSize));
-      __ cmp(ecx, isolate()->factory()->undefined_value());
-      __ j(not_equal, &ok, Label::kNear);
-      __ mov(ecx, GlobalObjectOperand());
-      __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalProxyOffset));
-      __ mov(Operand(ebp, receiver_slot * kPointerSize), ecx);
-      __ bind(&ok);
-    }
-
   } else {
     __ StubPrologue();
     frame->SetRegisterSaveAreaSize(
@@ -831,24 +1115,35 @@
       }
     } else if (destination->IsRegister()) {
       Register dst = g.ToRegister(destination);
-      __ mov(dst, g.ToImmediate(source));
+      __ Move(dst, g.ToImmediate(source));
     } else if (destination->IsStackSlot()) {
       Operand dst = g.ToOperand(destination);
-      __ mov(dst, g.ToImmediate(source));
-    } else {
-      double v = g.ToDouble(source);
-      uint64_t int_val = bit_cast<uint64_t, double>(v);
-      int32_t lower = static_cast<int32_t>(int_val);
-      int32_t upper = static_cast<int32_t>(int_val >> kBitsPerInt);
+      __ Move(dst, g.ToImmediate(source));
+    } else if (src_constant.type() == Constant::kFloat32) {
+      // TODO(turbofan): Can we do better here?
+      uint32_t src = bit_cast<uint32_t>(src_constant.ToFloat32());
       if (destination->IsDoubleRegister()) {
         XMMRegister dst = g.ToDoubleRegister(destination);
-        __ Move(dst, v);
+        __ Move(dst, src);
+      } else {
+        DCHECK(destination->IsDoubleStackSlot());
+        Operand dst = g.ToOperand(destination);
+        __ Move(dst, Immediate(src));
+      }
+    } else {
+      DCHECK_EQ(Constant::kFloat64, src_constant.type());
+      uint64_t src = bit_cast<uint64_t>(src_constant.ToFloat64());
+      uint32_t lower = static_cast<uint32_t>(src);
+      uint32_t upper = static_cast<uint32_t>(src >> 32);
+      if (destination->IsDoubleRegister()) {
+        XMMRegister dst = g.ToDoubleRegister(destination);
+        __ Move(dst, src);
       } else {
         DCHECK(destination->IsDoubleStackSlot());
         Operand dst0 = g.ToOperand(destination);
         Operand dst1 = g.HighOperand(destination);
-        __ mov(dst0, Immediate(lower));
-        __ mov(dst1, Immediate(upper));
+        __ Move(dst0, Immediate(lower));
+        __ Move(dst1, Immediate(upper));
       }
     }
   } else if (source->IsDoubleRegister()) {
@@ -908,7 +1203,7 @@
     __ movaps(xmm0, src);
     __ movaps(src, dst);
     __ movaps(dst, xmm0);
-  } else if (source->IsDoubleRegister() && source->IsDoubleStackSlot()) {
+  } else if (source->IsDoubleRegister() && destination->IsDoubleStackSlot()) {
     // XMM register-memory swap.  We rely on having xmm0
     // available as a fixed scratch register.
     XMMRegister reg = g.ToDoubleRegister(source);
@@ -940,7 +1235,7 @@
 
 void CodeGenerator::EnsureSpaceForLazyDeopt() {
   int space_needed = Deoptimizer::patch_size();
-  if (!linkage()->info()->IsStub()) {
+  if (!info()->IsStub()) {
     // Ensure that we have enough space after the previous lazy-bailout
     // instruction for patching the code here.
     int current_pc = masm()->pc_offset();
diff --git a/src/compiler/ia32/instruction-codes-ia32.h b/src/compiler/ia32/instruction-codes-ia32.h
index 0f46088..ec9fd18 100644
--- a/src/compiler/ia32/instruction-codes-ia32.h
+++ b/src/compiler/ia32/instruction-codes-ia32.h
@@ -20,6 +20,8 @@
   V(IA32Xor)                       \
   V(IA32Sub)                       \
   V(IA32Imul)                      \
+  V(IA32ImulHigh)                  \
+  V(IA32UmulHigh)                  \
   V(IA32Idiv)                      \
   V(IA32Udiv)                      \
   V(IA32Not)                       \
@@ -35,10 +37,19 @@
   V(SSEFloat64Div)                 \
   V(SSEFloat64Mod)                 \
   V(SSEFloat64Sqrt)                \
+  V(SSEFloat64Floor)               \
+  V(SSEFloat64Ceil)                \
+  V(SSEFloat64RoundTruncate)       \
+  V(SSECvtss2sd)                   \
+  V(SSECvtsd2ss)                   \
   V(SSEFloat64ToInt32)             \
   V(SSEFloat64ToUint32)            \
   V(SSEInt32ToFloat64)             \
   V(SSEUint32ToFloat64)            \
+  V(AVXFloat64Add)                 \
+  V(AVXFloat64Sub)                 \
+  V(AVXFloat64Mul)                 \
+  V(AVXFloat64Div)                 \
   V(IA32Movsxbl)                   \
   V(IA32Movzxbl)                   \
   V(IA32Movb)                      \
@@ -48,6 +59,7 @@
   V(IA32Movl)                      \
   V(IA32Movss)                     \
   V(IA32Movsd)                     \
+  V(IA32Lea)                       \
   V(IA32Push)                      \
   V(IA32StoreWriteBarrier)
 
@@ -59,23 +71,31 @@
 //
 // We use the following local notation for addressing modes:
 //
-// R = register
-// O = register or stack slot
-// D = double register
-// I = immediate (handle, external, int32)
-// MR = [register]
-// MI = [immediate]
-// MRN = [register + register * N in {1, 2, 4, 8}]
-// MRI = [register + immediate]
-// MRNI = [register + register * N in {1, 2, 4, 8} + immediate]
+// M = memory operand
+// R = base register
+// N = index register * N for N in {1, 2, 4, 8}
+// I = immediate displacement (int32_t)
+
 #define TARGET_ADDRESSING_MODE_LIST(V) \
-  V(MI)   /* [K] */                    \
-  V(MR)   /* [%r0] */                  \
-  V(MRI)  /* [%r0 + K] */              \
-  V(MR1I) /* [%r0 + %r1 * 1 + K] */    \
-  V(MR2I) /* [%r0 + %r1 * 2 + K] */    \
-  V(MR4I) /* [%r0 + %r1 * 4 + K] */    \
-  V(MR8I) /* [%r0 + %r1 * 8 + K] */
+  V(MR)   /* [%r1            ] */      \
+  V(MRI)  /* [%r1         + K] */      \
+  V(MR1)  /* [%r1 + %r2*1    ] */      \
+  V(MR2)  /* [%r1 + %r2*2    ] */      \
+  V(MR4)  /* [%r1 + %r2*4    ] */      \
+  V(MR8)  /* [%r1 + %r2*8    ] */      \
+  V(MR1I) /* [%r1 + %r2*1 + K] */      \
+  V(MR2I) /* [%r1 + %r2*2 + K] */      \
+  V(MR4I) /* [%r1 + %r2*3 + K] */      \
+  V(MR8I) /* [%r1 + %r2*4 + K] */      \
+  V(M1)   /* [      %r2*1    ] */      \
+  V(M2)   /* [      %r2*2    ] */      \
+  V(M4)   /* [      %r2*4    ] */      \
+  V(M8)   /* [      %r2*8    ] */      \
+  V(M1I)  /* [      %r2*1 + K] */      \
+  V(M2I)  /* [      %r2*2 + K] */      \
+  V(M4I)  /* [      %r2*4 + K] */      \
+  V(M8I)  /* [      %r2*8 + K] */      \
+  V(MI)   /* [              K] */
 
 }  // namespace compiler
 }  // namespace internal
diff --git a/src/compiler/ia32/instruction-selector-ia32-unittest.cc b/src/compiler/ia32/instruction-selector-ia32-unittest.cc
deleted file mode 100644
index 60708c1..0000000
--- a/src/compiler/ia32/instruction-selector-ia32-unittest.cc
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/instruction-selector-unittest.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-namespace {
-
-// Immediates (random subset).
-static const int32_t kImmediates[] = {
-    kMinInt, -42, -1, 0,  1,  2,    3,      4,          5,
-    6,       7,   8,  16, 42, 0xff, 0xffff, 0x0f0f0f0f, kMaxInt};
-
-}  // namespace
-
-
-TEST_F(InstructionSelectorTest, Int32AddWithParameter) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Int32Add(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kIA32Add, s[0]->arch_opcode());
-}
-
-
-TEST_F(InstructionSelectorTest, Int32AddWithImmediate) {
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    {
-      StreamBuilder m(this, kMachInt32, kMachInt32);
-      m.Return(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)));
-      Stream s = m.Build();
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(kIA32Add, s[0]->arch_opcode());
-      ASSERT_EQ(2U, s[0]->InputCount());
-      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    }
-    {
-      StreamBuilder m(this, kMachInt32, kMachInt32);
-      m.Return(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)));
-      Stream s = m.Build();
-      ASSERT_EQ(1U, s.size());
-      EXPECT_EQ(kIA32Add, s[0]->arch_opcode());
-      ASSERT_EQ(2U, s[0]->InputCount());
-      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-    }
-  }
-}
-
-
-TEST_F(InstructionSelectorTest, Int32SubWithParameter) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(m.Int32Sub(m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kIA32Sub, s[0]->arch_opcode());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_F(InstructionSelectorTest, Int32SubWithImmediate) {
-  TRACED_FOREACH(int32_t, imm, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32);
-    m.Return(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(kIA32Sub, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// Loads and stores
-
-namespace {
-
-struct MemoryAccess {
-  MachineType type;
-  ArchOpcode load_opcode;
-  ArchOpcode store_opcode;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
-  OStringStream ost;
-  ost << memacc.type;
-  return os << ost.c_str();
-}
-
-
-static const MemoryAccess kMemoryAccesses[] = {
-    {kMachInt8, kIA32Movsxbl, kIA32Movb},
-    {kMachUint8, kIA32Movzxbl, kIA32Movb},
-    {kMachInt16, kIA32Movsxwl, kIA32Movw},
-    {kMachUint16, kIA32Movzxwl, kIA32Movw},
-    {kMachInt32, kIA32Movl, kIA32Movl},
-    {kMachUint32, kIA32Movl, kIA32Movl},
-    {kMachFloat32, kIA32Movss, kIA32Movss},
-    {kMachFloat64, kIA32Movsd, kIA32Movsd}};
-
-}  // namespace
-
-
-typedef InstructionSelectorTestWithParam<MemoryAccess>
-    InstructionSelectorMemoryAccessTest;
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
-  const MemoryAccess memacc = GetParam();
-  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
-  m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateBase) {
-  const MemoryAccess memacc = GetParam();
-  TRACED_FOREACH(int32_t, base, kImmediates) {
-    StreamBuilder m(this, memacc.type, kMachPtr);
-    m.Return(m.Load(memacc.type, m.Int32Constant(base), m.Parameter(0)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
-    EXPECT_EQ(base, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
-  const MemoryAccess memacc = GetParam();
-  TRACED_FOREACH(int32_t, index, kImmediates) {
-    StreamBuilder m(this, memacc.type, kMachPtr);
-    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
-    ASSERT_EQ(2U, s[0]->InputCount());
-    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
-    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(1U, s[0]->OutputCount());
-  }
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
-  const MemoryAccess memacc = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
-  m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
-  m.Return(m.Int32Constant(0));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(3U, s[0]->InputCount());
-  EXPECT_EQ(0U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateBase) {
-  const MemoryAccess memacc = GetParam();
-  TRACED_FOREACH(int32_t, base, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachInt32, memacc.type);
-    m.Store(memacc.type, m.Int32Constant(base), m.Parameter(0), m.Parameter(1));
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
-    ASSERT_EQ(3U, s[0]->InputCount());
-    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
-    EXPECT_EQ(base, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(0U, s[0]->OutputCount());
-  }
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
-  const MemoryAccess memacc = GetParam();
-  TRACED_FOREACH(int32_t, index, kImmediates) {
-    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
-    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
-            m.Parameter(1));
-    m.Return(m.Int32Constant(0));
-    Stream s = m.Build();
-    ASSERT_EQ(1U, s.size());
-    EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
-    ASSERT_EQ(3U, s[0]->InputCount());
-    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
-    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
-    EXPECT_EQ(0U, s[0]->OutputCount());
-  }
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
-                        InstructionSelectorMemoryAccessTest,
-                        ::testing::ValuesIn(kMemoryAccesses));
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/ia32/instruction-selector-ia32.cc b/src/compiler/ia32/instruction-selector-ia32.cc
index 24ebc38..16063ab 100644
--- a/src/compiler/ia32/instruction-selector-ia32.cc
+++ b/src/compiler/ia32/instruction-selector-ia32.cc
@@ -37,15 +37,98 @@
         return false;
     }
   }
+
+  AddressingMode GenerateMemoryOperandInputs(Node* index, int scale, Node* base,
+                                             Node* displacement_node,
+                                             InstructionOperand* inputs[],
+                                             size_t* input_count) {
+    AddressingMode mode = kMode_MRI;
+    int32_t displacement = (displacement_node == NULL)
+                               ? 0
+                               : OpParameter<int32_t>(displacement_node);
+    if (base != NULL) {
+      if (base->opcode() == IrOpcode::kInt32Constant) {
+        displacement += OpParameter<int32_t>(base);
+        base = NULL;
+      }
+    }
+    if (base != NULL) {
+      inputs[(*input_count)++] = UseRegister(base);
+      if (index != NULL) {
+        DCHECK(scale >= 0 && scale <= 3);
+        inputs[(*input_count)++] = UseRegister(index);
+        if (displacement != 0) {
+          inputs[(*input_count)++] = TempImmediate(displacement);
+          static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I,
+                                                       kMode_MR4I, kMode_MR8I};
+          mode = kMRnI_modes[scale];
+        } else {
+          static const AddressingMode kMRn_modes[] = {kMode_MR1, kMode_MR2,
+                                                      kMode_MR4, kMode_MR8};
+          mode = kMRn_modes[scale];
+        }
+      } else {
+        if (displacement == 0) {
+          mode = kMode_MR;
+        } else {
+          inputs[(*input_count)++] = TempImmediate(displacement);
+          mode = kMode_MRI;
+        }
+      }
+    } else {
+      DCHECK(scale >= 0 && scale <= 3);
+      if (index != NULL) {
+        inputs[(*input_count)++] = UseRegister(index);
+        if (displacement != 0) {
+          inputs[(*input_count)++] = TempImmediate(displacement);
+          static const AddressingMode kMnI_modes[] = {kMode_MRI, kMode_M2I,
+                                                      kMode_M4I, kMode_M8I};
+          mode = kMnI_modes[scale];
+        } else {
+          static const AddressingMode kMn_modes[] = {kMode_MR, kMode_M2,
+                                                     kMode_M4, kMode_M8};
+          mode = kMn_modes[scale];
+        }
+      } else {
+        inputs[(*input_count)++] = TempImmediate(displacement);
+        return kMode_MI;
+      }
+    }
+    return mode;
+  }
+
+  AddressingMode GetEffectiveAddressMemoryOperand(Node* node,
+                                                  InstructionOperand* inputs[],
+                                                  size_t* input_count) {
+    BaseWithIndexAndDisplacement32Matcher m(node, true);
+    DCHECK(m.matches());
+    if ((m.displacement() == NULL || CanBeImmediate(m.displacement()))) {
+      return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(),
+                                         m.displacement(), inputs, input_count);
+    } else {
+      inputs[(*input_count)++] = UseRegister(node->InputAt(0));
+      inputs[(*input_count)++] = UseRegister(node->InputAt(1));
+      return kMode_MR1;
+    }
+  }
+
+  bool CanBeBetterLeftOperand(Node* node) const {
+    return !selector()->IsLive(node);
+  }
 };
 
 
+static void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
+                           Node* node) {
+  IA32OperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsRegister(node),
+                 g.UseRegister(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitLoad(Node* node) {
   MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
   MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
-  IA32OperandGenerator g(this);
-  Node* base = node->InputAt(0);
-  Node* index = node->InputAt(1);
 
   ArchOpcode opcode;
   // TODO(titzer): signed/unsigned small loads
@@ -71,23 +154,16 @@
       UNREACHABLE();
       return;
   }
-  if (g.CanBeImmediate(base)) {
-    if (Int32Matcher(index).Is(0)) {  // load [#base + #0]
-      Emit(opcode | AddressingModeField::encode(kMode_MI),
-           g.DefineAsRegister(node), g.UseImmediate(base));
-    } else {  // load [#base + %index]
-      Emit(opcode | AddressingModeField::encode(kMode_MRI),
-           g.DefineAsRegister(node), g.UseRegister(index),
-           g.UseImmediate(base));
-    }
-  } else if (g.CanBeImmediate(index)) {  // load [%base + #index]
-    Emit(opcode | AddressingModeField::encode(kMode_MRI),
-         g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
-  } else {  // load [%base + %index + K]
-    Emit(opcode | AddressingModeField::encode(kMode_MR1I),
-         g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
-  }
-  // TODO(turbofan): addressing modes [r+r*{2,4,8}+K]
+
+  IA32OperandGenerator g(this);
+  InstructionOperand* outputs[1];
+  outputs[0] = g.DefineAsRegister(node);
+  InstructionOperand* inputs[3];
+  size_t input_count = 0;
+  AddressingMode mode =
+      g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
+  InstructionCode code = opcode | AddressingModeField::encode(mode);
+  Emit(code, 1, outputs, input_count, inputs);
 }
 
 
@@ -111,14 +187,7 @@
     return;
   }
   DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
-  InstructionOperand* val;
-  if (g.CanBeImmediate(value)) {
-    val = g.UseImmediate(value);
-  } else if (rep == kRepWord8 || rep == kRepBit) {
-    val = g.UseByteRegister(value);
-  } else {
-    val = g.UseRegister(value);
-  }
+
   ArchOpcode opcode;
   switch (rep) {
     case kRepFloat32:
@@ -142,22 +211,114 @@
       UNREACHABLE();
       return;
   }
-  if (g.CanBeImmediate(base)) {
-    if (Int32Matcher(index).Is(0)) {  // store [#base], %|#value
-      Emit(opcode | AddressingModeField::encode(kMode_MI), NULL,
-           g.UseImmediate(base), val);
-    } else {  // store [#base + %index], %|#value
-      Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
-           g.UseRegister(index), g.UseImmediate(base), val);
-    }
-  } else if (g.CanBeImmediate(index)) {  // store [%base + #index], %|#value
-    Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
-         g.UseRegister(base), g.UseImmediate(index), val);
-  } else {  // store [%base + %index], %|#value
-    Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL,
-         g.UseRegister(base), g.UseRegister(index), val);
+
+  InstructionOperand* val;
+  if (g.CanBeImmediate(value)) {
+    val = g.UseImmediate(value);
+  } else if (rep == kRepWord8 || rep == kRepBit) {
+    val = g.UseByteRegister(value);
+  } else {
+    val = g.UseRegister(value);
   }
-  // TODO(turbofan): addressing modes [r+r*{2,4,8}+K]
+
+  InstructionOperand* inputs[4];
+  size_t input_count = 0;
+  AddressingMode mode =
+      g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
+  InstructionCode code = opcode | AddressingModeField::encode(mode);
+  inputs[input_count++] = val;
+  Emit(code, 0, static_cast<InstructionOperand**>(NULL), input_count, inputs);
+}
+
+
+void InstructionSelector::VisitCheckedLoad(Node* node) {
+  MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+  MachineType typ = TypeOf(OpParameter<MachineType>(node));
+  IA32OperandGenerator g(this);
+  Node* const buffer = node->InputAt(0);
+  Node* const offset = node->InputAt(1);
+  Node* const length = node->InputAt(2);
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepWord8:
+      opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8;
+      break;
+    case kRepWord16:
+      opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16;
+      break;
+    case kRepWord32:
+      opcode = kCheckedLoadWord32;
+      break;
+    case kRepFloat32:
+      opcode = kCheckedLoadFloat32;
+      break;
+    case kRepFloat64:
+      opcode = kCheckedLoadFloat64;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+  InstructionOperand* offset_operand = g.UseRegister(offset);
+  InstructionOperand* length_operand =
+      g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
+  if (g.CanBeImmediate(buffer)) {
+    Emit(opcode | AddressingModeField::encode(kMode_MRI),
+         g.DefineAsRegister(node), offset_operand, length_operand,
+         offset_operand, g.UseImmediate(buffer));
+  } else {
+    Emit(opcode | AddressingModeField::encode(kMode_MR1),
+         g.DefineAsRegister(node), offset_operand, length_operand,
+         g.UseRegister(buffer), offset_operand);
+  }
+}
+
+
+void InstructionSelector::VisitCheckedStore(Node* node) {
+  MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+  IA32OperandGenerator g(this);
+  Node* const buffer = node->InputAt(0);
+  Node* const offset = node->InputAt(1);
+  Node* const length = node->InputAt(2);
+  Node* const value = node->InputAt(3);
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepWord8:
+      opcode = kCheckedStoreWord8;
+      break;
+    case kRepWord16:
+      opcode = kCheckedStoreWord16;
+      break;
+    case kRepWord32:
+      opcode = kCheckedStoreWord32;
+      break;
+    case kRepFloat32:
+      opcode = kCheckedStoreFloat32;
+      break;
+    case kRepFloat64:
+      opcode = kCheckedStoreFloat64;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+  InstructionOperand* value_operand =
+      g.CanBeImmediate(value)
+          ? g.UseImmediate(value)
+          : ((rep == kRepWord8 || rep == kRepBit) ? g.UseByteRegister(value)
+                                                  : g.UseRegister(value));
+  InstructionOperand* offset_operand = g.UseRegister(offset);
+  InstructionOperand* length_operand =
+      g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
+  if (g.CanBeImmediate(buffer)) {
+    Emit(opcode | AddressingModeField::encode(kMode_MRI), nullptr,
+         offset_operand, length_operand, value_operand, offset_operand,
+         g.UseImmediate(buffer));
+  } else {
+    Emit(opcode | AddressingModeField::encode(kMode_MR1), nullptr,
+         offset_operand, length_operand, value_operand, g.UseRegister(buffer),
+         offset_operand);
+  }
 }
 
 
@@ -166,20 +327,35 @@
                        InstructionCode opcode, FlagsContinuation* cont) {
   IA32OperandGenerator g(selector);
   Int32BinopMatcher m(node);
+  Node* left = m.left().node();
+  Node* right = m.right().node();
   InstructionOperand* inputs[4];
   size_t input_count = 0;
   InstructionOperand* outputs[2];
   size_t output_count = 0;
 
   // TODO(turbofan): match complex addressing modes.
-  // TODO(turbofan): if commutative, pick the non-live-in operand as the left as
-  // this might be the last use and therefore its register can be reused.
-  if (g.CanBeImmediate(m.right().node())) {
-    inputs[input_count++] = g.Use(m.left().node());
-    inputs[input_count++] = g.UseImmediate(m.right().node());
+  if (left == right) {
+    // If both inputs refer to the same operand, enforce allocating a register
+    // for both of them to ensure that we don't end up generating code like
+    // this:
+    //
+    //   mov eax, [ebp-0x10]
+    //   add eax, [ebp-0x10]
+    //   jo label
+    InstructionOperand* const input = g.UseRegister(left);
+    inputs[input_count++] = input;
+    inputs[input_count++] = input;
+  } else if (g.CanBeImmediate(right)) {
+    inputs[input_count++] = g.UseRegister(left);
+    inputs[input_count++] = g.UseImmediate(right);
   } else {
-    inputs[input_count++] = g.UseRegister(m.left().node());
-    inputs[input_count++] = g.Use(m.right().node());
+    if (node->op()->HasProperty(Operator::kCommutative) &&
+        g.CanBeBetterLeftOperand(right)) {
+      std::swap(left, right);
+    }
+    inputs[input_count++] = g.UseRegister(left);
+    inputs[input_count++] = g.Use(right);
   }
 
   if (cont->IsBranch()) {
@@ -226,7 +402,7 @@
   IA32OperandGenerator g(this);
   Int32BinopMatcher m(node);
   if (m.right().Is(-1)) {
-    Emit(kIA32Not, g.DefineSameAsFirst(node), g.Use(m.left().node()));
+    Emit(kIA32Not, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()));
   } else {
     VisitBinop(this, node, kIA32Xor);
   }
@@ -240,25 +416,73 @@
   Node* left = node->InputAt(0);
   Node* right = node->InputAt(1);
 
-  // TODO(turbofan): assembler only supports some addressing modes for shifts.
   if (g.CanBeImmediate(right)) {
     selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
                    g.UseImmediate(right));
   } else {
-    Int32BinopMatcher m(node);
-    if (m.right().IsWord32And()) {
-      Int32BinopMatcher mright(right);
-      if (mright.right().Is(0x1F)) {
-        right = mright.left().node();
-      }
-    }
     selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
                    g.UseFixed(right, ecx));
   }
 }
 
 
+namespace {
+
+void VisitMulHigh(InstructionSelector* selector, Node* node,
+                  ArchOpcode opcode) {
+  IA32OperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsFixed(node, edx),
+                 g.UseFixed(node->InputAt(0), eax),
+                 g.UseUniqueRegister(node->InputAt(1)));
+}
+
+
+void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
+  IA32OperandGenerator g(selector);
+  InstructionOperand* temps[] = {g.TempRegister(edx)};
+  selector->Emit(opcode, g.DefineAsFixed(node, eax),
+                 g.UseFixed(node->InputAt(0), eax),
+                 g.UseUnique(node->InputAt(1)), arraysize(temps), temps);
+}
+
+
+void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
+  IA32OperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsFixed(node, edx),
+                 g.UseFixed(node->InputAt(0), eax),
+                 g.UseUnique(node->InputAt(1)));
+}
+
+void EmitLea(InstructionSelector* selector, Node* result, Node* index,
+             int scale, Node* base, Node* displacement) {
+  IA32OperandGenerator g(selector);
+  InstructionOperand* inputs[4];
+  size_t input_count = 0;
+  AddressingMode mode = g.GenerateMemoryOperandInputs(
+      index, scale, base, displacement, inputs, &input_count);
+
+  DCHECK_NE(0, static_cast<int>(input_count));
+  DCHECK_GE(arraysize(inputs), input_count);
+
+  InstructionOperand* outputs[1];
+  outputs[0] = g.DefineAsRegister(result);
+
+  InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea;
+
+  selector->Emit(opcode, 1, outputs, input_count, inputs);
+}
+
+}  // namespace
+
+
 void InstructionSelector::VisitWord32Shl(Node* node) {
+  Int32ScaleMatcher m(node, true);
+  if (m.matches()) {
+    Node* index = node->InputAt(0);
+    Node* base = m.power_of_two_plus_one() ? index : NULL;
+    EmitLea(this, node, index, m.scale(), base, NULL);
+    return;
+  }
   VisitShift(this, node, kIA32Shl);
 }
 
@@ -279,6 +503,29 @@
 
 
 void InstructionSelector::VisitInt32Add(Node* node) {
+  IA32OperandGenerator g(this);
+
+  // Try to match the Add to a lea pattern
+  BaseWithIndexAndDisplacement32Matcher m(node);
+  if (m.matches() &&
+      (m.displacement() == NULL || g.CanBeImmediate(m.displacement()))) {
+    InstructionOperand* inputs[4];
+    size_t input_count = 0;
+    AddressingMode mode = g.GenerateMemoryOperandInputs(
+        m.index(), m.scale(), m.base(), m.displacement(), inputs, &input_count);
+
+    DCHECK_NE(0, static_cast<int>(input_count));
+    DCHECK_GE(arraysize(inputs), input_count);
+
+    InstructionOperand* outputs[1];
+    outputs[0] = g.DefineAsRegister(node);
+
+    InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea;
+    Emit(opcode, 1, outputs, input_count, inputs);
+    return;
+  }
+
+  // No lea pattern match, use add
   VisitBinop(this, node, kIA32Add);
 }
 
@@ -295,31 +542,36 @@
 
 
 void InstructionSelector::VisitInt32Mul(Node* node) {
+  Int32ScaleMatcher m(node, true);
+  if (m.matches()) {
+    Node* index = node->InputAt(0);
+    Node* base = m.power_of_two_plus_one() ? index : NULL;
+    EmitLea(this, node, index, m.scale(), base, NULL);
+    return;
+  }
   IA32OperandGenerator g(this);
   Node* left = node->InputAt(0);
   Node* right = node->InputAt(1);
   if (g.CanBeImmediate(right)) {
     Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left),
          g.UseImmediate(right));
-  } else if (g.CanBeImmediate(left)) {
-    Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(right),
-         g.UseImmediate(left));
   } else {
-    // TODO(turbofan): select better left operand.
+    if (g.CanBeBetterLeftOperand(right)) {
+      std::swap(left, right);
+    }
     Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(left),
          g.Use(right));
   }
 }
 
 
-static inline void VisitDiv(InstructionSelector* selector, Node* node,
-                            ArchOpcode opcode) {
-  IA32OperandGenerator g(selector);
-  InstructionOperand* temps[] = {g.TempRegister(edx)};
-  size_t temp_count = arraysize(temps);
-  selector->Emit(opcode, g.DefineAsFixed(node, eax),
-                 g.UseFixed(node->InputAt(0), eax),
-                 g.UseUnique(node->InputAt(1)), temp_count, temps);
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  VisitMulHigh(this, node, kIA32ImulHigh);
+}
+
+
+void InstructionSelector::VisitUint32MulHigh(Node* node) {
+  VisitMulHigh(this, node, kIA32UmulHigh);
 }
 
 
@@ -328,32 +580,27 @@
 }
 
 
-void InstructionSelector::VisitInt32UDiv(Node* node) {
+void InstructionSelector::VisitUint32Div(Node* node) {
   VisitDiv(this, node, kIA32Udiv);
 }
 
 
-static inline void VisitMod(InstructionSelector* selector, Node* node,
-                            ArchOpcode opcode) {
-  IA32OperandGenerator g(selector);
-  InstructionOperand* temps[] = {g.TempRegister(eax), g.TempRegister(edx)};
-  size_t temp_count = arraysize(temps);
-  selector->Emit(opcode, g.DefineAsFixed(node, edx),
-                 g.UseFixed(node->InputAt(0), eax),
-                 g.UseUnique(node->InputAt(1)), temp_count, temps);
-}
-
-
 void InstructionSelector::VisitInt32Mod(Node* node) {
   VisitMod(this, node, kIA32Idiv);
 }
 
 
-void InstructionSelector::VisitInt32UMod(Node* node) {
+void InstructionSelector::VisitUint32Mod(Node* node) {
   VisitMod(this, node, kIA32Udiv);
 }
 
 
+void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
+  IA32OperandGenerator g(this);
+  Emit(kSSECvtss2sd, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
   IA32OperandGenerator g(this);
   Emit(kSSEInt32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
@@ -362,9 +609,7 @@
 
 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
   IA32OperandGenerator g(this);
-  // TODO(turbofan): IA32 SSE LoadUint32() should take an operand.
-  Emit(kSSEUint32ToFloat64, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  Emit(kSSEUint32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
 }
 
 
@@ -380,31 +625,57 @@
 }
 
 
+void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
+  IA32OperandGenerator g(this);
+  Emit(kSSECvtsd2ss, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitFloat64Add(Node* node) {
   IA32OperandGenerator g(this);
-  Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
-       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
+  if (IsSupported(AVX)) {
+    Emit(kAVXFloat64Add, g.DefineAsRegister(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  } else {
+    Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  }
 }
 
 
 void InstructionSelector::VisitFloat64Sub(Node* node) {
   IA32OperandGenerator g(this);
-  Emit(kSSEFloat64Sub, g.DefineSameAsFirst(node),
-       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
+  if (IsSupported(AVX)) {
+    Emit(kAVXFloat64Sub, g.DefineAsRegister(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  } else {
+    Emit(kSSEFloat64Sub, g.DefineSameAsFirst(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  }
 }
 
 
 void InstructionSelector::VisitFloat64Mul(Node* node) {
   IA32OperandGenerator g(this);
-  Emit(kSSEFloat64Mul, g.DefineSameAsFirst(node),
-       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
+  if (IsSupported(AVX)) {
+    Emit(kAVXFloat64Mul, g.DefineAsRegister(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  } else {
+    Emit(kSSEFloat64Mul, g.DefineSameAsFirst(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  }
 }
 
 
 void InstructionSelector::VisitFloat64Div(Node* node) {
   IA32OperandGenerator g(this);
-  Emit(kSSEFloat64Div, g.DefineSameAsFirst(node),
-       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
+  if (IsSupported(AVX)) {
+    Emit(kAVXFloat64Div, g.DefineAsRegister(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  } else {
+    Emit(kSSEFloat64Div, g.DefineSameAsFirst(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  }
 }
 
 
@@ -423,104 +694,44 @@
 }
 
 
-void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
-                                                    FlagsContinuation* cont) {
-  VisitBinop(this, node, kIA32Add, cont);
+void InstructionSelector::VisitFloat64Floor(Node* node) {
+  DCHECK(CpuFeatures::IsSupported(SSE4_1));
+  VisitRRFloat64(this, kSSEFloat64Floor, node);
 }
 
 
-void InstructionSelector::VisitInt32SubWithOverflow(Node* node,
-                                                    FlagsContinuation* cont) {
-  VisitBinop(this, node, kIA32Sub, cont);
+void InstructionSelector::VisitFloat64Ceil(Node* node) {
+  DCHECK(CpuFeatures::IsSupported(SSE4_1));
+  VisitRRFloat64(this, kSSEFloat64Ceil, node);
 }
 
 
-// Shared routine for multiple compare operations.
-static inline void VisitCompare(InstructionSelector* selector,
-                                InstructionCode opcode,
-                                InstructionOperand* left,
-                                InstructionOperand* right,
-                                FlagsContinuation* cont) {
-  IA32OperandGenerator g(selector);
-  if (cont->IsBranch()) {
-    selector->Emit(cont->Encode(opcode), NULL, left, right,
-                   g.Label(cont->true_block()),
-                   g.Label(cont->false_block()))->MarkAsControl();
-  } else {
-    DCHECK(cont->IsSet());
-    // TODO(titzer): Needs byte register.
-    selector->Emit(cont->Encode(opcode), g.DefineAsRegister(cont->result()),
-                   left, right);
-  }
+void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
+  DCHECK(CpuFeatures::IsSupported(SSE4_1));
+  VisitRRFloat64(this, kSSEFloat64RoundTruncate, node);
 }
 
 
-// Shared routine for multiple word compare operations.
-static inline void VisitWordCompare(InstructionSelector* selector, Node* node,
-                                    InstructionCode opcode,
-                                    FlagsContinuation* cont, bool commutative) {
-  IA32OperandGenerator g(selector);
-  Node* left = node->InputAt(0);
-  Node* right = node->InputAt(1);
-
-  // Match immediates on left or right side of comparison.
-  if (g.CanBeImmediate(right)) {
-    VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont);
-  } else if (g.CanBeImmediate(left)) {
-    if (!commutative) cont->Commute();
-    VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont);
-  } else {
-    VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
-  }
+void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
+  UNREACHABLE();
 }
 
 
-void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) {
-  switch (node->opcode()) {
-    case IrOpcode::kInt32Sub:
-      return VisitWordCompare(this, node, kIA32Cmp, cont, false);
-    case IrOpcode::kWord32And:
-      return VisitWordCompare(this, node, kIA32Test, cont, true);
-    default:
-      break;
-  }
-
+void InstructionSelector::VisitCall(Node* node) {
   IA32OperandGenerator g(this);
-  VisitCompare(this, kIA32Test, g.Use(node), g.TempImmediate(-1), cont);
-}
-
-
-void InstructionSelector::VisitWord32Compare(Node* node,
-                                             FlagsContinuation* cont) {
-  VisitWordCompare(this, node, kIA32Cmp, cont, false);
-}
-
-
-void InstructionSelector::VisitFloat64Compare(Node* node,
-                                              FlagsContinuation* cont) {
-  IA32OperandGenerator g(this);
-  Node* left = node->InputAt(0);
-  Node* right = node->InputAt(1);
-  VisitCompare(this, kSSEFloat64Cmp, g.UseRegister(left), g.Use(right), cont);
-}
-
-
-void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
-                                    BasicBlock* deoptimization) {
-  IA32OperandGenerator g(this);
-  CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call);
+  const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
 
   FrameStateDescriptor* frame_state_descriptor = NULL;
 
   if (descriptor->NeedsFrameState()) {
     frame_state_descriptor =
-        GetFrameStateDescriptor(call->InputAt(descriptor->InputCount()));
+        GetFrameStateDescriptor(node->InputAt(descriptor->InputCount()));
   }
 
   CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
 
   // Compute InstructionOperands for inputs and outputs.
-  InitializeCallBuffer(call, &buffer, true, true);
+  InitializeCallBuffer(node, &buffer, true, true);
 
   // Push any stack arguments.
   for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
@@ -547,17 +758,254 @@
   opcode |= MiscField::encode(descriptor->flags());
 
   // Emit the call instruction.
+  InstructionOperand** first_output =
+      buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL;
   Instruction* call_instr =
-      Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(),
+      Emit(opcode, buffer.outputs.size(), first_output,
            buffer.instruction_args.size(), &buffer.instruction_args.front());
-
   call_instr->MarkAsCall();
-  if (deoptimization != NULL) {
-    DCHECK(continuation != NULL);
-    call_instr->MarkAsControl();
+}
+
+
+namespace {
+
+// Shared routine for multiple compare operations.
+void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
+                  InstructionOperand* left, InstructionOperand* right,
+                  FlagsContinuation* cont) {
+  IA32OperandGenerator g(selector);
+  if (cont->IsBranch()) {
+    selector->Emit(cont->Encode(opcode), NULL, left, right,
+                   g.Label(cont->true_block()),
+                   g.Label(cont->false_block()))->MarkAsControl();
+  } else {
+    DCHECK(cont->IsSet());
+    // TODO(titzer): Needs byte register.
+    selector->Emit(cont->Encode(opcode), g.DefineAsRegister(cont->result()),
+                   left, right);
   }
 }
 
+
+// Shared routine for multiple compare operations.
+void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
+                  Node* left, Node* right, FlagsContinuation* cont,
+                  bool commutative) {
+  IA32OperandGenerator g(selector);
+  if (commutative && g.CanBeBetterLeftOperand(right)) {
+    std::swap(left, right);
+  }
+  VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
+}
+
+
+// Shared routine for multiple float compare operations.
+void VisitFloat64Compare(InstructionSelector* selector, Node* node,
+                         FlagsContinuation* cont) {
+  VisitCompare(selector, kSSEFloat64Cmp, node->InputAt(0), node->InputAt(1),
+               cont, node->op()->HasProperty(Operator::kCommutative));
+}
+
+
+// Shared routine for multiple word compare operations.
+void VisitWordCompare(InstructionSelector* selector, Node* node,
+                      InstructionCode opcode, FlagsContinuation* cont) {
+  IA32OperandGenerator g(selector);
+  Node* const left = node->InputAt(0);
+  Node* const right = node->InputAt(1);
+
+  // Match immediates on left or right side of comparison.
+  if (g.CanBeImmediate(right)) {
+    VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont);
+  } else if (g.CanBeImmediate(left)) {
+    if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
+    VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont);
+  } else {
+    VisitCompare(selector, opcode, left, right, cont,
+                 node->op()->HasProperty(Operator::kCommutative));
+  }
+}
+
+
+void VisitWordCompare(InstructionSelector* selector, Node* node,
+                      FlagsContinuation* cont) {
+  VisitWordCompare(selector, node, kIA32Cmp, cont);
+}
+
+
+// Shared routine for word comparison with zero.
+void VisitWordCompareZero(InstructionSelector* selector, Node* user,
+                          Node* value, FlagsContinuation* cont) {
+  // Try to combine the branch with a comparison.
+  while (selector->CanCover(user, value)) {
+    switch (value->opcode()) {
+      case IrOpcode::kWord32Equal: {
+        // Try to combine with comparisons against 0 by simply inverting the
+        // continuation.
+        Int32BinopMatcher m(value);
+        if (m.right().Is(0)) {
+          user = value;
+          value = m.left().node();
+          cont->Negate();
+          continue;
+        }
+        cont->OverwriteAndNegateIfEqual(kEqual);
+        return VisitWordCompare(selector, value, cont);
+      }
+      case IrOpcode::kInt32LessThan:
+        cont->OverwriteAndNegateIfEqual(kSignedLessThan);
+        return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kInt32LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
+        return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kUint32LessThan:
+        cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
+        return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kUint32LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
+        return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kFloat64Equal:
+        cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
+        return VisitFloat64Compare(selector, value, cont);
+      case IrOpcode::kFloat64LessThan:
+        cont->OverwriteAndNegateIfEqual(kUnorderedLessThan);
+        return VisitFloat64Compare(selector, value, cont);
+      case IrOpcode::kFloat64LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual);
+        return VisitFloat64Compare(selector, value, cont);
+      case IrOpcode::kProjection:
+        // Check if this is the overflow output projection of an
+        // <Operation>WithOverflow node.
+        if (OpParameter<size_t>(value) == 1u) {
+          // We cannot combine the <Operation>WithOverflow with this branch
+          // unless the 0th projection (the use of the actual value of the
+          // <Operation> is either NULL, which means there's no use of the
+          // actual value, or was already defined, which means it is scheduled
+          // *AFTER* this branch).
+          Node* node = value->InputAt(0);
+          Node* result = node->FindProjection(0);
+          if (result == NULL || selector->IsDefined(result)) {
+            switch (node->opcode()) {
+              case IrOpcode::kInt32AddWithOverflow:
+                cont->OverwriteAndNegateIfEqual(kOverflow);
+                return VisitBinop(selector, node, kIA32Add, cont);
+              case IrOpcode::kInt32SubWithOverflow:
+                cont->OverwriteAndNegateIfEqual(kOverflow);
+                return VisitBinop(selector, node, kIA32Sub, cont);
+              default:
+                break;
+            }
+          }
+        }
+        break;
+      case IrOpcode::kInt32Sub:
+        return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kWord32And:
+        return VisitWordCompare(selector, value, kIA32Test, cont);
+      default:
+        break;
+    }
+    break;
+  }
+
+  // Continuation could not be combined with a compare, emit compare against 0.
+  IA32OperandGenerator g(selector);
+  VisitCompare(selector, kIA32Cmp, g.Use(value), g.TempImmediate(0), cont);
+}
+
+}  // namespace
+
+
+void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
+                                      BasicBlock* fbranch) {
+  FlagsContinuation cont(kNotEqual, tbranch, fbranch);
+  VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
+}
+
+
+void InstructionSelector::VisitWord32Equal(Node* const node) {
+  FlagsContinuation cont(kEqual, node);
+  Int32BinopMatcher m(node);
+  if (m.right().Is(0)) {
+    return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
+  }
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32LessThan(Node* node) {
+  FlagsContinuation cont(kSignedLessThan, node);
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kSignedLessThanOrEqual, node);
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitUint32LessThan(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThan, node);
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
+  if (Node* ovf = node->FindProjection(1)) {
+    FlagsContinuation cont(kOverflow, ovf);
+    return VisitBinop(this, node, kIA32Add, &cont);
+  }
+  FlagsContinuation cont;
+  VisitBinop(this, node, kIA32Add, &cont);
+}
+
+
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+  if (Node* ovf = node->FindProjection(1)) {
+    FlagsContinuation cont(kOverflow, ovf);
+    return VisitBinop(this, node, kIA32Sub, &cont);
+  }
+  FlagsContinuation cont;
+  VisitBinop(this, node, kIA32Sub, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64Equal(Node* node) {
+  FlagsContinuation cont(kUnorderedEqual, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64LessThan(Node* node) {
+  FlagsContinuation cont(kUnorderedLessThan, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnorderedLessThanOrEqual, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+// static
+MachineOperatorBuilder::Flags
+InstructionSelector::SupportedMachineOperatorFlags() {
+  if (CpuFeatures::IsSupported(SSE4_1)) {
+    return MachineOperatorBuilder::kFloat64Floor |
+           MachineOperatorBuilder::kFloat64Ceil |
+           MachineOperatorBuilder::kFloat64RoundTruncate |
+           MachineOperatorBuilder::kWord32ShiftIsSafe;
+  }
+  return MachineOperatorBuilder::Flag::kNoFlags;
+}
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
diff --git a/src/compiler/ia32/linkage-ia32.cc b/src/compiler/ia32/linkage-ia32.cc
index f2c5fab..12cc34f 100644
--- a/src/compiler/ia32/linkage-ia32.cc
+++ b/src/compiler/ia32/linkage-ia32.cc
@@ -30,8 +30,9 @@
 
 typedef LinkageHelper<IA32LinkageHelperTraits> LH;
 
-CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
-  return LH::GetJSCallDescriptor(zone, parameter_count);
+CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone,
+                                             CallDescriptor::Flags flags) {
+  return LH::GetJSCallDescriptor(zone, parameter_count, flags);
 }
 
 
@@ -44,10 +45,10 @@
 
 
 CallDescriptor* Linkage::GetStubCallDescriptor(
-    CallInterfaceDescriptor descriptor, int stack_parameter_count,
-    CallDescriptor::Flags flags, Zone* zone) {
+    const CallInterfaceDescriptor& descriptor, int stack_parameter_count,
+    CallDescriptor::Flags flags, Operator::Properties properties, Zone* zone) {
   return LH::GetStubCallDescriptor(zone, descriptor, stack_parameter_count,
-                                   flags);
+                                   flags, properties);
 }
 
 
diff --git a/src/compiler/instruction-codes.h b/src/compiler/instruction-codes.h
index 2d921bd..ea17854 100644
--- a/src/compiler/instruction-codes.h
+++ b/src/compiler/instruction-codes.h
@@ -5,12 +5,18 @@
 #ifndef V8_COMPILER_INSTRUCTION_CODES_H_
 #define V8_COMPILER_INSTRUCTION_CODES_H_
 
+#include <iosfwd>
+
 #if V8_TARGET_ARCH_ARM
 #include "src/compiler/arm/instruction-codes-arm.h"
 #elif V8_TARGET_ARCH_ARM64
 #include "src/compiler/arm64/instruction-codes-arm64.h"
 #elif V8_TARGET_ARCH_IA32
 #include "src/compiler/ia32/instruction-codes-ia32.h"
+#elif V8_TARGET_ARCH_MIPS
+#include "src/compiler/mips/instruction-codes-mips.h"
+#elif V8_TARGET_ARCH_MIPS64
+#include "src/compiler/mips64/instruction-codes-mips64.h"
 #elif V8_TARGET_ARCH_X64
 #include "src/compiler/x64/instruction-codes-x64.h"
 #else
@@ -21,9 +27,6 @@
 
 namespace v8 {
 namespace internal {
-
-class OStream;
-
 namespace compiler {
 
 // Target-specific opcodes that specify which assembly sequence to emit.
@@ -34,7 +37,20 @@
   V(ArchJmp)                \
   V(ArchNop)                \
   V(ArchRet)                \
+  V(ArchStackPointer)       \
   V(ArchTruncateDoubleToI)  \
+  V(CheckedLoadInt8)        \
+  V(CheckedLoadUint8)       \
+  V(CheckedLoadInt16)       \
+  V(CheckedLoadUint16)      \
+  V(CheckedLoadWord32)      \
+  V(CheckedLoadFloat32)     \
+  V(CheckedLoadFloat64)     \
+  V(CheckedStoreWord8)      \
+  V(CheckedStoreWord16)     \
+  V(CheckedStoreWord32)     \
+  V(CheckedStoreFloat32)    \
+  V(CheckedStoreFloat64)    \
   TARGET_ARCH_OPCODE_LIST(V)
 
 enum ArchOpcode {
@@ -46,7 +62,7 @@
 #undef COUNT_ARCH_OPCODE
 };
 
-OStream& operator<<(OStream& os, const ArchOpcode& ao);
+std::ostream& operator<<(std::ostream& os, const ArchOpcode& ao);
 
 // Addressing modes represent the "shape" of inputs to an instruction.
 // Many instructions support multiple addressing modes. Addressing modes
@@ -65,12 +81,12 @@
 #undef COUNT_ADDRESSING_MODE
 };
 
-OStream& operator<<(OStream& os, const AddressingMode& am);
+std::ostream& operator<<(std::ostream& os, const AddressingMode& am);
 
 // The mode of the flags continuation (see below).
 enum FlagsMode { kFlags_none = 0, kFlags_branch = 1, kFlags_set = 2 };
 
-OStream& operator<<(OStream& os, const FlagsMode& fm);
+std::ostream& operator<<(std::ostream& os, const FlagsMode& fm);
 
 // The condition of flags continuation (see below).
 enum FlagsCondition {
@@ -94,7 +110,11 @@
   kNotOverflow
 };
 
-OStream& operator<<(OStream& os, const FlagsCondition& fc);
+inline FlagsCondition NegateFlagsCondition(FlagsCondition condition) {
+  return static_cast<FlagsCondition>(condition ^ 1);
+}
+
+std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc);
 
 // The InstructionCode is an opaque, target-specific integer that encodes
 // what code to emit for an instruction in the code generator. It is not
@@ -107,10 +127,10 @@
 // continuation into a single InstructionCode which is stored as part of
 // the instruction.
 typedef BitField<ArchOpcode, 0, 7> ArchOpcodeField;
-typedef BitField<AddressingMode, 7, 4> AddressingModeField;
-typedef BitField<FlagsMode, 11, 2> FlagsModeField;
-typedef BitField<FlagsCondition, 13, 5> FlagsConditionField;
-typedef BitField<int, 13, 19> MiscField;
+typedef BitField<AddressingMode, 7, 5> AddressingModeField;
+typedef BitField<FlagsMode, 12, 2> FlagsModeField;
+typedef BitField<FlagsCondition, 14, 5> FlagsConditionField;
+typedef BitField<int, 14, 18> MiscField;
 
 }  // namespace compiler
 }  // namespace internal
diff --git a/src/compiler/instruction-selector-impl.h b/src/compiler/instruction-selector-impl.h
index d00109e..bdcd952 100644
--- a/src/compiler/instruction-selector-impl.h
+++ b/src/compiler/instruction-selector-impl.h
@@ -8,6 +8,7 @@
 #include "src/compiler/instruction.h"
 #include "src/compiler/instruction-selector.h"
 #include "src/compiler/linkage.h"
+#include "src/macro-assembler.h"
 
 namespace v8 {
 namespace internal {
@@ -44,8 +45,9 @@
 
   InstructionOperand* DefineAsConstant(Node* node) {
     selector()->MarkAsDefined(node);
-    sequence()->AddConstant(node->id(), ToConstant(node));
-    return ConstantOperand::Create(node->id(), zone());
+    int virtual_register = selector_->GetVirtualRegister(node);
+    sequence()->AddConstant(virtual_register, ToConstant(node));
+    return ConstantOperand::Create(virtual_register, zone());
   }
 
   InstructionOperand* DefineAsLocation(Node* node, LinkageLocation location,
@@ -54,9 +56,9 @@
   }
 
   InstructionOperand* Use(Node* node) {
-    return Use(node,
-               new (zone()) UnallocatedOperand(
-                   UnallocatedOperand::ANY, UnallocatedOperand::USED_AT_START));
+    return Use(
+        node, new (zone()) UnallocatedOperand(
+                  UnallocatedOperand::NONE, UnallocatedOperand::USED_AT_START));
   }
 
   InstructionOperand* UseRegister(Node* node) {
@@ -68,7 +70,7 @@
   // Use register or operand for the node. If a register is chosen, it won't
   // alias any temporary or output registers.
   InstructionOperand* UseUnique(Node* node) {
-    return Use(node, new (zone()) UnallocatedOperand(UnallocatedOperand::ANY));
+    return Use(node, new (zone()) UnallocatedOperand(UnallocatedOperand::NONE));
   }
 
   // Use a unique register for the node that does not alias any temporary or
@@ -127,13 +129,18 @@
     return ImmediateOperand::Create(index, zone());
   }
 
+  InstructionOperand* TempLocation(LinkageLocation location, MachineType type) {
+    UnallocatedOperand* op = ToUnallocatedOperand(location, type);
+    op->set_virtual_register(sequence()->NextVirtualRegister());
+    return op;
+  }
+
   InstructionOperand* Label(BasicBlock* block) {
-    // TODO(bmeurer): We misuse ImmediateOperand here.
-    return TempImmediate(block->id());
+    int index = sequence()->AddImmediate(Constant(block->GetRpoNumber()));
+    return ImmediateOperand::Create(index, zone());
   }
 
  protected:
-  Graph* graph() const { return selector()->graph(); }
   InstructionSelector* selector() const { return selector_; }
   InstructionSequence* sequence() const { return selector()->sequence(); }
   Isolate* isolate() const { return zone()->isolate(); }
@@ -146,8 +153,10 @@
         return Constant(OpParameter<int32_t>(node));
       case IrOpcode::kInt64Constant:
         return Constant(OpParameter<int64_t>(node));
-      case IrOpcode::kNumberConstant:
+      case IrOpcode::kFloat32Constant:
+        return Constant(OpParameter<float>(node));
       case IrOpcode::kFloat64Constant:
+      case IrOpcode::kNumberConstant:
         return Constant(OpParameter<double>(node));
       case IrOpcode::kExternalConstant:
         return Constant(OpParameter<ExternalReference>(node));
@@ -163,7 +172,7 @@
   UnallocatedOperand* Define(Node* node, UnallocatedOperand* operand) {
     DCHECK_NOT_NULL(node);
     DCHECK_NOT_NULL(operand);
-    operand->set_virtual_register(node->id());
+    operand->set_virtual_register(selector_->GetVirtualRegister(node));
     selector()->MarkAsDefined(node);
     return operand;
   }
@@ -171,7 +180,7 @@
   UnallocatedOperand* Use(Node* node, UnallocatedOperand* operand) {
     DCHECK_NOT_NULL(node);
     DCHECK_NOT_NULL(operand);
-    operand->set_virtual_register(node->id());
+    operand->set_virtual_register(selector_->GetVirtualRegister(node));
     selector()->MarkAsUsed(node);
     return operand;
   }
@@ -247,7 +256,7 @@
 
   void Negate() {
     DCHECK(!IsNone());
-    condition_ = static_cast<FlagsCondition>(condition_ ^ 1);
+    condition_ = NegateFlagsCondition(condition_);
   }
 
   void Commute() {
@@ -307,8 +316,6 @@
     if (negate) Negate();
   }
 
-  void SwapBlocks() { std::swap(true_block_, false_block_); }
-
   // Encodes this flags continuation into the given opcode.
   InstructionCode Encode(InstructionCode opcode) {
     opcode |= FlagsModeField::encode(mode_);
@@ -331,10 +338,10 @@
 // TODO(bmeurer): Get rid of the CallBuffer business and make
 // InstructionSelector::VisitCall platform independent instead.
 struct CallBuffer {
-  CallBuffer(Zone* zone, CallDescriptor* descriptor,
+  CallBuffer(Zone* zone, const CallDescriptor* descriptor,
              FrameStateDescriptor* frame_state);
 
-  CallDescriptor* descriptor;
+  const CallDescriptor* descriptor;
   FrameStateDescriptor* frame_state_descriptor;
   NodeVector output_nodes;
   InstructionOperandVector outputs;
diff --git a/src/compiler/instruction-selector-unittest.cc b/src/compiler/instruction-selector-unittest.cc
deleted file mode 100644
index aa70735..0000000
--- a/src/compiler/instruction-selector-unittest.cc
+++ /dev/null
@@ -1,496 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/instruction-selector-unittest.h"
-
-#include "src/compiler/compiler-test-utils.h"
-#include "src/flags.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-namespace {
-
-typedef RawMachineAssembler::Label MLabel;
-
-}  // namespace
-
-
-InstructionSelectorTest::InstructionSelectorTest() : rng_(FLAG_random_seed) {}
-
-
-InstructionSelectorTest::~InstructionSelectorTest() {}
-
-
-InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
-    InstructionSelector::Features features,
-    InstructionSelectorTest::StreamBuilderMode mode) {
-  Schedule* schedule = Export();
-  if (FLAG_trace_turbo) {
-    OFStream out(stdout);
-    out << "=== Schedule before instruction selection ===" << endl << *schedule;
-  }
-  EXPECT_NE(0, graph()->NodeCount());
-  CompilationInfo info(test_->isolate(), test_->zone());
-  Linkage linkage(&info, call_descriptor());
-  InstructionSequence sequence(&linkage, graph(), schedule);
-  SourcePositionTable source_position_table(graph());
-  InstructionSelector selector(&sequence, &source_position_table, features);
-  selector.SelectInstructions();
-  if (FLAG_trace_turbo) {
-    OFStream out(stdout);
-    out << "=== Code sequence after instruction selection ===" << endl
-        << sequence;
-  }
-  Stream s;
-  std::set<int> virtual_registers;
-  for (InstructionSequence::const_iterator i = sequence.begin();
-       i != sequence.end(); ++i) {
-    Instruction* instr = *i;
-    if (instr->opcode() < 0) continue;
-    if (mode == kTargetInstructions) {
-      switch (instr->arch_opcode()) {
-#define CASE(Name) \
-  case k##Name:    \
-    break;
-        TARGET_ARCH_OPCODE_LIST(CASE)
-#undef CASE
-        default:
-          continue;
-      }
-    }
-    if (mode == kAllExceptNopInstructions && instr->arch_opcode() == kArchNop) {
-      continue;
-    }
-    for (size_t i = 0; i < instr->OutputCount(); ++i) {
-      InstructionOperand* output = instr->OutputAt(i);
-      EXPECT_NE(InstructionOperand::IMMEDIATE, output->kind());
-      if (output->IsConstant()) {
-        s.constants_.insert(std::make_pair(
-            output->index(), sequence.GetConstant(output->index())));
-        virtual_registers.insert(output->index());
-      } else if (output->IsUnallocated()) {
-        virtual_registers.insert(
-            UnallocatedOperand::cast(output)->virtual_register());
-      }
-    }
-    for (size_t i = 0; i < instr->InputCount(); ++i) {
-      InstructionOperand* input = instr->InputAt(i);
-      EXPECT_NE(InstructionOperand::CONSTANT, input->kind());
-      if (input->IsImmediate()) {
-        s.immediates_.insert(std::make_pair(
-            input->index(), sequence.GetImmediate(input->index())));
-      } else if (input->IsUnallocated()) {
-        virtual_registers.insert(
-            UnallocatedOperand::cast(input)->virtual_register());
-      }
-    }
-    s.instructions_.push_back(instr);
-  }
-  for (std::set<int>::const_iterator i = virtual_registers.begin();
-       i != virtual_registers.end(); ++i) {
-    int virtual_register = *i;
-    if (sequence.IsDouble(virtual_register)) {
-      EXPECT_FALSE(sequence.IsReference(virtual_register));
-      s.doubles_.insert(virtual_register);
-    }
-    if (sequence.IsReference(virtual_register)) {
-      EXPECT_FALSE(sequence.IsDouble(virtual_register));
-      s.references_.insert(virtual_register);
-    }
-  }
-  for (int i = 0; i < sequence.GetFrameStateDescriptorCount(); i++) {
-    s.deoptimization_entries_.push_back(sequence.GetFrameStateDescriptor(
-        InstructionSequence::StateId::FromInt(i)));
-  }
-  return s;
-}
-
-
-// -----------------------------------------------------------------------------
-// Return.
-
-
-TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) {
-  StreamBuilder m(this, kMachInt32, kMachInt32);
-  m.Return(m.Parameter(0));
-  Stream s = m.Build(kAllInstructions);
-  ASSERT_EQ(2U, s.size());
-  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
-  ASSERT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(kArchRet, s[1]->arch_opcode());
-  EXPECT_EQ(1U, s[1]->InputCount());
-}
-
-
-TARGET_TEST_F(InstructionSelectorTest, ReturnZero) {
-  StreamBuilder m(this, kMachInt32);
-  m.Return(m.Int32Constant(0));
-  Stream s = m.Build(kAllInstructions);
-  ASSERT_EQ(2U, s.size());
-  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
-  ASSERT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind());
-  EXPECT_EQ(0, s.ToInt32(s[0]->OutputAt(0)));
-  EXPECT_EQ(kArchRet, s[1]->arch_opcode());
-  EXPECT_EQ(1U, s[1]->InputCount());
-}
-
-
-// -----------------------------------------------------------------------------
-// Conversions.
-
-
-TARGET_TEST_F(InstructionSelectorTest, TruncateFloat64ToInt32WithParameter) {
-  StreamBuilder m(this, kMachInt32, kMachFloat64);
-  m.Return(m.TruncateFloat64ToInt32(m.Parameter(0)));
-  Stream s = m.Build(kAllInstructions);
-  ASSERT_EQ(3U, s.size());
-  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
-  EXPECT_EQ(kArchTruncateDoubleToI, s[1]->arch_opcode());
-  EXPECT_EQ(1U, s[1]->InputCount());
-  EXPECT_EQ(1U, s[1]->OutputCount());
-  EXPECT_EQ(kArchRet, s[2]->arch_opcode());
-}
-
-
-// -----------------------------------------------------------------------------
-// Parameters.
-
-
-TARGET_TEST_F(InstructionSelectorTest, DoubleParameter) {
-  StreamBuilder m(this, kMachFloat64, kMachFloat64);
-  Node* param = m.Parameter(0);
-  m.Return(param);
-  Stream s = m.Build(kAllInstructions);
-  EXPECT_TRUE(s.IsDouble(param->id()));
-}
-
-
-TARGET_TEST_F(InstructionSelectorTest, ReferenceParameter) {
-  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged);
-  Node* param = m.Parameter(0);
-  m.Return(param);
-  Stream s = m.Build(kAllInstructions);
-  EXPECT_TRUE(s.IsReference(param->id()));
-}
-
-
-// -----------------------------------------------------------------------------
-// Finish.
-
-
-TARGET_TEST_F(InstructionSelectorTest, Finish) {
-  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged);
-  Node* param = m.Parameter(0);
-  Node* finish = m.NewNode(m.common()->Finish(1), param, m.graph()->start());
-  m.Return(finish);
-  Stream s = m.Build(kAllInstructions);
-  ASSERT_EQ(3U, s.size());
-  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
-  ASSERT_EQ(1U, s[0]->OutputCount());
-  ASSERT_TRUE(s[0]->Output()->IsUnallocated());
-  EXPECT_EQ(param->id(), s.ToVreg(s[0]->Output()));
-  EXPECT_EQ(kArchNop, s[1]->arch_opcode());
-  ASSERT_EQ(1U, s[1]->InputCount());
-  ASSERT_TRUE(s[1]->InputAt(0)->IsUnallocated());
-  EXPECT_EQ(param->id(), s.ToVreg(s[1]->InputAt(0)));
-  ASSERT_EQ(1U, s[1]->OutputCount());
-  ASSERT_TRUE(s[1]->Output()->IsUnallocated());
-  EXPECT_TRUE(UnallocatedOperand::cast(s[1]->Output())->HasSameAsInputPolicy());
-  EXPECT_EQ(finish->id(), s.ToVreg(s[1]->Output()));
-  EXPECT_TRUE(s.IsReference(finish->id()));
-}
-
-
-// -----------------------------------------------------------------------------
-// Phi.
-
-
-typedef InstructionSelectorTestWithParam<MachineType>
-    InstructionSelectorPhiTest;
-
-
-TARGET_TEST_P(InstructionSelectorPhiTest, Doubleness) {
-  const MachineType type = GetParam();
-  StreamBuilder m(this, type, type, type);
-  Node* param0 = m.Parameter(0);
-  Node* param1 = m.Parameter(1);
-  MLabel a, b, c;
-  m.Branch(m.Int32Constant(0), &a, &b);
-  m.Bind(&a);
-  m.Goto(&c);
-  m.Bind(&b);
-  m.Goto(&c);
-  m.Bind(&c);
-  Node* phi = m.Phi(type, param0, param1);
-  m.Return(phi);
-  Stream s = m.Build(kAllInstructions);
-  EXPECT_EQ(s.IsDouble(phi->id()), s.IsDouble(param0->id()));
-  EXPECT_EQ(s.IsDouble(phi->id()), s.IsDouble(param1->id()));
-}
-
-
-TARGET_TEST_P(InstructionSelectorPhiTest, Referenceness) {
-  const MachineType type = GetParam();
-  StreamBuilder m(this, type, type, type);
-  Node* param0 = m.Parameter(0);
-  Node* param1 = m.Parameter(1);
-  MLabel a, b, c;
-  m.Branch(m.Int32Constant(1), &a, &b);
-  m.Bind(&a);
-  m.Goto(&c);
-  m.Bind(&b);
-  m.Goto(&c);
-  m.Bind(&c);
-  Node* phi = m.Phi(type, param0, param1);
-  m.Return(phi);
-  Stream s = m.Build(kAllInstructions);
-  EXPECT_EQ(s.IsReference(phi->id()), s.IsReference(param0->id()));
-  EXPECT_EQ(s.IsReference(phi->id()), s.IsReference(param1->id()));
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorPhiTest,
-                        ::testing::Values(kMachFloat64, kMachInt8, kMachUint8,
-                                          kMachInt16, kMachUint16, kMachInt32,
-                                          kMachUint32, kMachInt64, kMachUint64,
-                                          kMachPtr, kMachAnyTagged));
-
-
-// -----------------------------------------------------------------------------
-// ValueEffect.
-
-
-TARGET_TEST_F(InstructionSelectorTest, ValueEffect) {
-  StreamBuilder m1(this, kMachInt32, kMachPtr);
-  Node* p1 = m1.Parameter(0);
-  m1.Return(m1.Load(kMachInt32, p1, m1.Int32Constant(0)));
-  Stream s1 = m1.Build(kAllInstructions);
-  StreamBuilder m2(this, kMachInt32, kMachPtr);
-  Node* p2 = m2.Parameter(0);
-  m2.Return(m2.NewNode(m2.machine()->Load(kMachInt32), p2, m2.Int32Constant(0),
-                       m2.NewNode(m2.common()->ValueEffect(1), p2)));
-  Stream s2 = m2.Build(kAllInstructions);
-  EXPECT_LE(3U, s1.size());
-  ASSERT_EQ(s1.size(), s2.size());
-  TRACED_FORRANGE(size_t, i, 0, s1.size() - 1) {
-    const Instruction* i1 = s1[i];
-    const Instruction* i2 = s2[i];
-    EXPECT_EQ(i1->arch_opcode(), i2->arch_opcode());
-    EXPECT_EQ(i1->InputCount(), i2->InputCount());
-    EXPECT_EQ(i1->OutputCount(), i2->OutputCount());
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// Calls with deoptimization.
-TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
-  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
-                  kMachAnyTagged);
-
-  BailoutId bailout_id(42);
-
-  Node* function_node = m.Parameter(0);
-  Node* receiver = m.Parameter(1);
-  Node* context = m.Parameter(2);
-
-  Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(1));
-  Node* locals = m.NewNode(m.common()->StateValues(0));
-  Node* stack = m.NewNode(m.common()->StateValues(0));
-  Node* context_dummy = m.Int32Constant(0);
-
-  Node* state_node = m.NewNode(
-      m.common()->FrameState(JS_FRAME, bailout_id, kPushOutput), parameters,
-      locals, stack, context_dummy, m.UndefinedConstant());
-  Node* call = m.CallJS0(function_node, receiver, context, state_node);
-  m.Return(call);
-
-  Stream s = m.Build(kAllExceptNopInstructions);
-
-  // Skip until kArchCallJSFunction.
-  size_t index = 0;
-  for (; index < s.size() && s[index]->arch_opcode() != kArchCallJSFunction;
-       index++) {
-  }
-  // Now we should have two instructions: call and return.
-  ASSERT_EQ(index + 2, s.size());
-
-  EXPECT_EQ(kArchCallJSFunction, s[index++]->arch_opcode());
-  EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
-
-  // TODO(jarin) Check deoptimization table.
-}
-
-
-TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
-  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
-                  kMachAnyTagged);
-
-  BailoutId bailout_id_before(42);
-
-  // Some arguments for the call node.
-  Node* function_node = m.Parameter(0);
-  Node* receiver = m.Parameter(1);
-  Node* context = m.Int32Constant(1);  // Context is ignored.
-
-  // Build frame state for the state before the call.
-  Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
-  Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44));
-  Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45));
-
-  Node* context_sentinel = m.Int32Constant(0);
-  Node* frame_state_before = m.NewNode(
-      m.common()->FrameState(JS_FRAME, bailout_id_before, kPushOutput),
-      parameters, locals, stack, context_sentinel, m.UndefinedConstant());
-
-  // Build the call.
-  Node* call = m.CallFunctionStub0(function_node, receiver, context,
-                                   frame_state_before, CALL_AS_METHOD);
-
-  m.Return(call);
-
-  Stream s = m.Build(kAllExceptNopInstructions);
-
-  // Skip until kArchCallJSFunction.
-  size_t index = 0;
-  for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject;
-       index++) {
-  }
-  // Now we should have two instructions: call, return.
-  ASSERT_EQ(index + 2, s.size());
-
-  // Check the call instruction
-  const Instruction* call_instr = s[index++];
-  EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode());
-  size_t num_operands =
-      1 +  // Code object.
-      1 +
-      4 +  // Frame state deopt id + one input for each value in frame state.
-      1 +  // Function.
-      1;   // Context.
-  ASSERT_EQ(num_operands, call_instr->InputCount());
-
-  // Code object.
-  EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate());
-
-  // Deoptimization id.
-  int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1));
-  FrameStateDescriptor* desc_before =
-      s.GetFrameStateDescriptor(deopt_id_before);
-  EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
-  EXPECT_EQ(kPushOutput, desc_before->state_combine());
-  EXPECT_EQ(1u, desc_before->parameters_count());
-  EXPECT_EQ(1u, desc_before->locals_count());
-  EXPECT_EQ(1u, desc_before->stack_count());
-  EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2)));
-  EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3)));
-  EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(4)));
-  EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(5)));
-
-  // Function.
-  EXPECT_EQ(function_node->id(), s.ToVreg(call_instr->InputAt(6)));
-  // Context.
-  EXPECT_EQ(context->id(), s.ToVreg(call_instr->InputAt(7)));
-
-  EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
-
-  EXPECT_EQ(index, s.size());
-}
-
-
-TARGET_TEST_F(InstructionSelectorTest,
-              CallFunctionStubDeoptRecursiveFrameState) {
-  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
-                  kMachAnyTagged);
-
-  BailoutId bailout_id_before(42);
-  BailoutId bailout_id_parent(62);
-
-  // Some arguments for the call node.
-  Node* function_node = m.Parameter(0);
-  Node* receiver = m.Parameter(1);
-  Node* context = m.Int32Constant(66);
-
-  // Build frame state for the state before the call.
-  Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63));
-  Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64));
-  Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65));
-  Node* frame_state_parent = m.NewNode(
-      m.common()->FrameState(JS_FRAME, bailout_id_parent, kIgnoreOutput),
-      parameters, locals, stack, context, m.UndefinedConstant());
-
-  Node* context2 = m.Int32Constant(46);
-  Node* parameters2 =
-      m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
-  Node* locals2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44));
-  Node* stack2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45));
-  Node* frame_state_before = m.NewNode(
-      m.common()->FrameState(JS_FRAME, bailout_id_before, kPushOutput),
-      parameters2, locals2, stack2, context2, frame_state_parent);
-
-  // Build the call.
-  Node* call = m.CallFunctionStub0(function_node, receiver, context2,
-                                   frame_state_before, CALL_AS_METHOD);
-
-  m.Return(call);
-
-  Stream s = m.Build(kAllExceptNopInstructions);
-
-  // Skip until kArchCallJSFunction.
-  size_t index = 0;
-  for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject;
-       index++) {
-  }
-  // Now we should have three instructions: call, return.
-  EXPECT_EQ(index + 2, s.size());
-
-  // Check the call instruction
-  const Instruction* call_instr = s[index++];
-  EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode());
-  size_t num_operands =
-      1 +  // Code object.
-      1 +  // Frame state deopt id
-      4 +  // One input for each value in frame state + context.
-      4 +  // One input for each value in the parent frame state + context.
-      1 +  // Function.
-      1;   // Context.
-  EXPECT_EQ(num_operands, call_instr->InputCount());
-  // Code object.
-  EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate());
-
-  // Deoptimization id.
-  int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1));
-  FrameStateDescriptor* desc_before =
-      s.GetFrameStateDescriptor(deopt_id_before);
-  EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
-  EXPECT_EQ(1u, desc_before->parameters_count());
-  EXPECT_EQ(1u, desc_before->locals_count());
-  EXPECT_EQ(1u, desc_before->stack_count());
-  EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2)));
-  // Context:
-  EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(3)));
-  EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(4)));
-  EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(5)));
-  // Values from parent environment should follow.
-  EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(6)));
-  EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(7)));
-  EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(8)));
-  EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(9)));
-
-  // Function.
-  EXPECT_EQ(function_node->id(), s.ToVreg(call_instr->InputAt(10)));
-  // Context.
-  EXPECT_EQ(context2->id(), s.ToVreg(call_instr->InputAt(11)));
-  // Continuation.
-
-  EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
-  EXPECT_EQ(index, s.size());
-}
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/instruction-selector-unittest.h b/src/compiler/instruction-selector-unittest.h
deleted file mode 100644
index 4e12dab..0000000
--- a/src/compiler/instruction-selector-unittest.h
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
-#define V8_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
-
-#include <deque>
-#include <set>
-
-#include "src/base/utils/random-number-generator.h"
-#include "src/compiler/instruction-selector.h"
-#include "src/compiler/raw-machine-assembler.h"
-#include "src/test/test-utils.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-class InstructionSelectorTest : public TestWithContext, public TestWithZone {
- public:
-  InstructionSelectorTest();
-  virtual ~InstructionSelectorTest();
-
-  base::RandomNumberGenerator* rng() { return &rng_; }
-
-  class Stream;
-
-  enum StreamBuilderMode {
-    kAllInstructions,
-    kTargetInstructions,
-    kAllExceptNopInstructions
-  };
-
-  class StreamBuilder FINAL : public RawMachineAssembler {
-   public:
-    StreamBuilder(InstructionSelectorTest* test, MachineType return_type)
-        : RawMachineAssembler(new (test->zone()) Graph(test->zone()),
-                              MakeMachineSignature(test->zone(), return_type)),
-          test_(test) {}
-    StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
-                  MachineType parameter0_type)
-        : RawMachineAssembler(
-              new (test->zone()) Graph(test->zone()),
-              MakeMachineSignature(test->zone(), return_type, parameter0_type)),
-          test_(test) {}
-    StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
-                  MachineType parameter0_type, MachineType parameter1_type)
-        : RawMachineAssembler(
-              new (test->zone()) Graph(test->zone()),
-              MakeMachineSignature(test->zone(), return_type, parameter0_type,
-                                   parameter1_type)),
-          test_(test) {}
-    StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
-                  MachineType parameter0_type, MachineType parameter1_type,
-                  MachineType parameter2_type)
-        : RawMachineAssembler(
-              new (test->zone()) Graph(test->zone()),
-              MakeMachineSignature(test->zone(), return_type, parameter0_type,
-                                   parameter1_type, parameter2_type)),
-          test_(test) {}
-
-    Stream Build(CpuFeature feature) {
-      return Build(InstructionSelector::Features(feature));
-    }
-    Stream Build(CpuFeature feature1, CpuFeature feature2) {
-      return Build(InstructionSelector::Features(feature1, feature2));
-    }
-    Stream Build(StreamBuilderMode mode = kTargetInstructions) {
-      return Build(InstructionSelector::Features(), mode);
-    }
-    Stream Build(InstructionSelector::Features features,
-                 StreamBuilderMode mode = kTargetInstructions);
-
-   private:
-    MachineSignature* MakeMachineSignature(Zone* zone,
-                                           MachineType return_type) {
-      MachineSignature::Builder builder(zone, 1, 0);
-      builder.AddReturn(return_type);
-      return builder.Build();
-    }
-
-    MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
-                                           MachineType parameter0_type) {
-      MachineSignature::Builder builder(zone, 1, 1);
-      builder.AddReturn(return_type);
-      builder.AddParam(parameter0_type);
-      return builder.Build();
-    }
-
-    MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
-                                           MachineType parameter0_type,
-                                           MachineType parameter1_type) {
-      MachineSignature::Builder builder(zone, 1, 2);
-      builder.AddReturn(return_type);
-      builder.AddParam(parameter0_type);
-      builder.AddParam(parameter1_type);
-      return builder.Build();
-    }
-
-    MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
-                                           MachineType parameter0_type,
-                                           MachineType parameter1_type,
-                                           MachineType parameter2_type) {
-      MachineSignature::Builder builder(zone, 1, 3);
-      builder.AddReturn(return_type);
-      builder.AddParam(parameter0_type);
-      builder.AddParam(parameter1_type);
-      builder.AddParam(parameter2_type);
-      return builder.Build();
-    }
-
-   private:
-    InstructionSelectorTest* test_;
-  };
-
-  class Stream FINAL {
-   public:
-    size_t size() const { return instructions_.size(); }
-    const Instruction* operator[](size_t index) const {
-      EXPECT_LT(index, size());
-      return instructions_[index];
-    }
-
-    bool IsDouble(const InstructionOperand* operand) const {
-      return IsDouble(ToVreg(operand));
-    }
-    bool IsDouble(int virtual_register) const {
-      return doubles_.find(virtual_register) != doubles_.end();
-    }
-
-    bool IsInteger(const InstructionOperand* operand) const {
-      return IsInteger(ToVreg(operand));
-    }
-    bool IsInteger(int virtual_register) const {
-      return !IsDouble(virtual_register) && !IsReference(virtual_register);
-    }
-
-    bool IsReference(const InstructionOperand* operand) const {
-      return IsReference(ToVreg(operand));
-    }
-    bool IsReference(int virtual_register) const {
-      return references_.find(virtual_register) != references_.end();
-    }
-
-    int32_t ToInt32(const InstructionOperand* operand) const {
-      return ToConstant(operand).ToInt32();
-    }
-
-    int64_t ToInt64(const InstructionOperand* operand) const {
-      return ToConstant(operand).ToInt64();
-    }
-
-    int ToVreg(const InstructionOperand* operand) const {
-      if (operand->IsConstant()) return operand->index();
-      EXPECT_EQ(InstructionOperand::UNALLOCATED, operand->kind());
-      return UnallocatedOperand::cast(operand)->virtual_register();
-    }
-
-    FrameStateDescriptor* GetFrameStateDescriptor(int deoptimization_id) {
-      EXPECT_LT(deoptimization_id, GetFrameStateDescriptorCount());
-      return deoptimization_entries_[deoptimization_id];
-    }
-
-    int GetFrameStateDescriptorCount() {
-      return static_cast<int>(deoptimization_entries_.size());
-    }
-
-   private:
-    Constant ToConstant(const InstructionOperand* operand) const {
-      ConstantMap::const_iterator i;
-      if (operand->IsConstant()) {
-        i = constants_.find(operand->index());
-        EXPECT_FALSE(constants_.end() == i);
-      } else {
-        EXPECT_EQ(InstructionOperand::IMMEDIATE, operand->kind());
-        i = immediates_.find(operand->index());
-        EXPECT_FALSE(immediates_.end() == i);
-      }
-      EXPECT_EQ(operand->index(), i->first);
-      return i->second;
-    }
-
-    friend class StreamBuilder;
-
-    typedef std::map<int, Constant> ConstantMap;
-
-    ConstantMap constants_;
-    ConstantMap immediates_;
-    std::deque<Instruction*> instructions_;
-    std::set<int> doubles_;
-    std::set<int> references_;
-    std::deque<FrameStateDescriptor*> deoptimization_entries_;
-  };
-
-  base::RandomNumberGenerator rng_;
-};
-
-
-template <typename T>
-class InstructionSelectorTestWithParam
-    : public InstructionSelectorTest,
-      public ::testing::WithParamInterface<T> {};
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
-
-#endif  // V8_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc
index 3c32b64..ffb8f9f 100644
--- a/src/compiler/instruction-selector.cc
+++ b/src/compiler/instruction-selector.cc
@@ -4,6 +4,7 @@
 
 #include "src/compiler/instruction-selector.h"
 
+#include "src/compiler/graph.h"
 #include "src/compiler/instruction-selector-impl.h"
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties-inl.h"
@@ -13,17 +14,23 @@
 namespace internal {
 namespace compiler {
 
-InstructionSelector::InstructionSelector(InstructionSequence* sequence,
+InstructionSelector::InstructionSelector(Zone* local_zone, Graph* graph,
+                                         Linkage* linkage,
+                                         InstructionSequence* sequence,
+                                         Schedule* schedule,
                                          SourcePositionTable* source_positions,
                                          Features features)
-    : zone_(sequence->isolate()),
+    : zone_(local_zone),
+      linkage_(linkage),
       sequence_(sequence),
       source_positions_(source_positions),
       features_(features),
+      schedule_(schedule),
+      node_map_(graph->NodeCount(), kNodeUnmapped, zone()),
       current_block_(NULL),
       instructions_(zone()),
-      defined_(graph()->NodeCount(), false, zone()),
-      used_(graph()->NodeCount(), false, zone()) {}
+      defined_(graph->NodeCount(), false, zone()),
+      used_(graph->NodeCount(), false, zone()) {}
 
 
 void InstructionSelector::SelectInstructions() {
@@ -32,17 +39,16 @@
   for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end(); ++i) {
     BasicBlock* block = *i;
     if (!block->IsLoopHeader()) continue;
-    DCHECK_NE(0, block->PredecessorCount());
-    DCHECK_NE(1, block->PredecessorCount());
+    DCHECK_NE(0, static_cast<int>(block->PredecessorCount()));
+    DCHECK_NE(1, static_cast<int>(block->PredecessorCount()));
     for (BasicBlock::const_iterator j = block->begin(); j != block->end();
          ++j) {
       Node* phi = *j;
       if (phi->opcode() != IrOpcode::kPhi) continue;
 
       // Mark all inputs as used.
-      Node::Inputs inputs = phi->inputs();
-      for (InputIter k = inputs.begin(); k != inputs.end(); ++k) {
-        MarkAsUsed(*k);
+      for (Node* const k : phi->inputs()) {
+        MarkAsUsed(k);
       }
     }
   }
@@ -55,13 +61,15 @@
   // Schedule the selected instructions.
   for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end(); ++i) {
     BasicBlock* block = *i;
-    size_t end = block->code_end_;
-    size_t start = block->code_start_;
-    sequence()->StartBlock(block);
+    InstructionBlock* instruction_block =
+        sequence()->InstructionBlockAt(block->GetRpoNumber());
+    size_t end = instruction_block->code_end();
+    size_t start = instruction_block->code_start();
+    sequence()->StartBlock(block->GetRpoNumber());
     while (start-- > end) {
-      sequence()->AddInstruction(instructions_[start], block);
+      sequence()->AddInstruction(instructions_[start]);
     }
-    sequence()->EndBlock(block);
+    sequence()->EndBlock(block->GetRpoNumber());
   }
 }
 
@@ -124,6 +132,31 @@
 
 
 Instruction* InstructionSelector::Emit(
+    InstructionCode opcode, InstructionOperand* output, InstructionOperand* a,
+    InstructionOperand* b, InstructionOperand* c, InstructionOperand* d,
+    InstructionOperand* e, size_t temp_count, InstructionOperand** temps) {
+  size_t output_count = output == NULL ? 0 : 1;
+  InstructionOperand* inputs[] = {a, b, c, d, e};
+  size_t input_count = arraysize(inputs);
+  return Emit(opcode, output_count, &output, input_count, inputs, temp_count,
+              temps);
+}
+
+
+Instruction* InstructionSelector::Emit(
+    InstructionCode opcode, InstructionOperand* output, InstructionOperand* a,
+    InstructionOperand* b, InstructionOperand* c, InstructionOperand* d,
+    InstructionOperand* e, InstructionOperand* f, size_t temp_count,
+    InstructionOperand** temps) {
+  size_t output_count = output == NULL ? 0 : 1;
+  InstructionOperand* inputs[] = {a, b, c, d, e, f};
+  size_t input_count = arraysize(inputs);
+  return Emit(opcode, output_count, &output, input_count, inputs, temp_count,
+              temps);
+}
+
+
+Instruction* InstructionSelector::Emit(
     InstructionCode opcode, size_t output_count, InstructionOperand** outputs,
     size_t input_count, InstructionOperand** inputs, size_t temp_count,
     InstructionOperand** temps) {
@@ -140,18 +173,25 @@
 }
 
 
-bool InstructionSelector::IsNextInAssemblyOrder(const BasicBlock* block) const {
-  return block->rpo_number_ == (current_block_->rpo_number_ + 1) &&
-         block->deferred_ == current_block_->deferred_;
-}
-
-
 bool InstructionSelector::CanCover(Node* user, Node* node) const {
   return node->OwnedBy(user) &&
          schedule()->block(node) == schedule()->block(user);
 }
 
 
+int InstructionSelector::GetVirtualRegister(const Node* node) {
+  if (node_map_[node->id()] == kNodeUnmapped) {
+    node_map_[node->id()] = sequence()->NextVirtualRegister();
+  }
+  return node_map_[node->id()];
+}
+
+
+int InstructionSelector::GetMappedVirtualRegister(const Node* node) const {
+  return node_map_[node->id()];
+}
+
+
 bool InstructionSelector::IsDefined(Node* node) const {
   DCHECK_NOT_NULL(node);
   NodeId id = node->id();
@@ -190,27 +230,48 @@
 
 bool InstructionSelector::IsDouble(const Node* node) const {
   DCHECK_NOT_NULL(node);
-  return sequence()->IsDouble(node->id());
+  int virtual_register = GetMappedVirtualRegister(node);
+  if (virtual_register == kNodeUnmapped) return false;
+  return sequence()->IsDouble(virtual_register);
 }
 
 
 void InstructionSelector::MarkAsDouble(Node* node) {
   DCHECK_NOT_NULL(node);
   DCHECK(!IsReference(node));
-  sequence()->MarkAsDouble(node->id());
+  sequence()->MarkAsDouble(GetVirtualRegister(node));
 }
 
 
 bool InstructionSelector::IsReference(const Node* node) const {
   DCHECK_NOT_NULL(node);
-  return sequence()->IsReference(node->id());
+  int virtual_register = GetMappedVirtualRegister(node);
+  if (virtual_register == kNodeUnmapped) return false;
+  return sequence()->IsReference(virtual_register);
 }
 
 
 void InstructionSelector::MarkAsReference(Node* node) {
   DCHECK_NOT_NULL(node);
   DCHECK(!IsDouble(node));
-  sequence()->MarkAsReference(node->id());
+  sequence()->MarkAsReference(GetVirtualRegister(node));
+}
+
+
+void InstructionSelector::MarkAsRepresentation(MachineType rep,
+                                               InstructionOperand* op) {
+  UnallocatedOperand* unalloc = UnallocatedOperand::cast(op);
+  switch (RepresentationOf(rep)) {
+    case kRepFloat32:
+    case kRepFloat64:
+      sequence()->MarkAsDouble(unalloc->virtual_register());
+      break;
+    case kRepTagged:
+      sequence()->MarkAsReference(unalloc->virtual_register());
+      break;
+    default:
+      break;
+  }
 }
 
 
@@ -232,7 +293,7 @@
 
 // TODO(bmeurer): Get rid of the CallBuffer business and make
 // InstructionSelector::VisitCall platform independent instead.
-CallBuffer::CallBuffer(Zone* zone, CallDescriptor* d,
+CallBuffer::CallBuffer(Zone* zone, const CallDescriptor* d,
                        FrameStateDescriptor* frame_desc)
     : descriptor(d),
       frame_state_descriptor(frame_desc),
@@ -253,9 +314,11 @@
                                                bool call_code_immediate,
                                                bool call_address_immediate) {
   OperandGenerator g(this);
-  DCHECK_EQ(call->op()->OutputCount(), buffer->descriptor->ReturnCount());
-  DCHECK_EQ(OperatorProperties::GetValueInputCount(call->op()),
-            buffer->input_count() + buffer->frame_state_count());
+  DCHECK_EQ(call->op()->ValueOutputCount(),
+            static_cast<int>(buffer->descriptor->ReturnCount()));
+  DCHECK_EQ(
+      call->op()->ValueInputCount(),
+      static_cast<int>(buffer->input_count() + buffer->frame_state_count()));
 
   if (buffer->descriptor->ReturnCount() > 0) {
     // Collect the projections that represent multiple outputs from this call.
@@ -267,15 +330,27 @@
     }
 
     // Filter out the outputs that aren't live because no projection uses them.
+    size_t outputs_needed_by_framestate =
+        buffer->frame_state_descriptor == NULL
+            ? 0
+            : buffer->frame_state_descriptor->state_combine()
+                  .ConsumedOutputCount();
     for (size_t i = 0; i < buffer->output_nodes.size(); i++) {
-      if (buffer->output_nodes[i] != NULL) {
-        Node* output = buffer->output_nodes[i];
+      bool output_is_live =
+          buffer->output_nodes[i] != NULL || i < outputs_needed_by_framestate;
+      if (output_is_live) {
         MachineType type =
             buffer->descriptor->GetReturnType(static_cast<int>(i));
         LinkageLocation location =
             buffer->descriptor->GetReturnLocation(static_cast<int>(i));
-        MarkAsRepresentation(type, output);
-        buffer->outputs.push_back(g.DefineAsLocation(output, location, type));
+
+        Node* output = buffer->output_nodes[i];
+        InstructionOperand* op =
+            output == NULL ? g.TempLocation(location, type)
+                           : g.DefineAsLocation(output, location, type);
+        MarkAsRepresentation(type, op);
+
+        buffer->outputs.push_back(op);
       }
     }
   }
@@ -303,7 +378,7 @@
                         buffer->descriptor->GetInputType(0)));
       break;
   }
-  DCHECK_EQ(1, buffer->instruction_args.size());
+  DCHECK_EQ(1, static_cast<int>(buffer->instruction_args.size()));
 
   // If the call needs a frame state, we insert the state information as
   // follows (n is the number of value inputs to the frame state):
@@ -328,11 +403,10 @@
   // arguments require an explicit push instruction before the call and do
   // not appear as arguments to the call. Everything else ends up
   // as an InstructionOperand argument to the call.
-  InputIter iter(call->inputs().begin());
+  auto iter(call->inputs().begin());
   int pushed_count = 0;
   for (size_t index = 0; index < input_count; ++iter, ++index) {
     DCHECK(iter != call->inputs().end());
-    DCHECK(index == static_cast<size_t>(iter.index()));
     DCHECK((*iter)->op()->opcode() != IrOpcode::kFrameState);
     if (index == 0) continue;  // The first argument (callee) is already done.
     InstructionOperand* op =
@@ -382,9 +456,10 @@
   }
 
   // We're done with the block.
-  // TODO(bmeurer): We should not mutate the schedule.
-  block->code_end_ = current_block_end;
-  block->code_start_ = static_cast<int>(instructions_.size());
+  InstructionBlock* instruction_block =
+      sequence()->InstructionBlockAt(block->GetRpoNumber());
+  instruction_block->set_code_start(static_cast<int>(instructions_.size()));
+  instruction_block->set_code_end(current_block_end);
 
   current_block_ = NULL;
 }
@@ -402,11 +477,11 @@
 
 
 void InstructionSelector::VisitControl(BasicBlock* block) {
-  Node* input = block->control_input_;
-  switch (block->control_) {
-    case BasicBlockData::kGoto:
+  Node* input = block->control_input();
+  switch (block->control()) {
+    case BasicBlock::kGoto:
       return VisitGoto(block->SuccessorAt(0));
-    case BasicBlockData::kBranch: {
+    case BasicBlock::kBranch: {
       DCHECK_EQ(IrOpcode::kBranch, input->opcode());
       BasicBlock* tbranch = block->SuccessorAt(0);
       BasicBlock* fbranch = block->SuccessorAt(1);
@@ -417,16 +492,16 @@
       if (tbranch == fbranch) return VisitGoto(tbranch);
       return VisitBranch(input, tbranch, fbranch);
     }
-    case BasicBlockData::kReturn: {
+    case BasicBlock::kReturn: {
       // If the result itself is a return, return its input.
       Node* value = (input != NULL && input->opcode() == IrOpcode::kReturn)
                         ? input->InputAt(0)
                         : input;
       return VisitReturn(value);
     }
-    case BasicBlockData::kThrow:
+    case BasicBlock::kThrow:
       return VisitThrow(input);
-    case BasicBlockData::kNone: {
+    case BasicBlock::kNone: {
       // TODO(titzer): exit block doesn't have control.
       DCHECK(input == NULL);
       break;
@@ -438,6 +513,135 @@
 }
 
 
+MachineType InstructionSelector::GetMachineType(Node* node) {
+  DCHECK_NOT_NULL(schedule()->block(node));  // should only use scheduled nodes.
+  switch (node->opcode()) {
+    case IrOpcode::kStart:
+    case IrOpcode::kLoop:
+    case IrOpcode::kEnd:
+    case IrOpcode::kBranch:
+    case IrOpcode::kIfTrue:
+    case IrOpcode::kIfFalse:
+    case IrOpcode::kEffectPhi:
+    case IrOpcode::kMerge:
+    case IrOpcode::kTerminate:
+      // No code needed for these graph artifacts.
+      return kMachNone;
+    case IrOpcode::kFinish:
+      return kMachAnyTagged;
+    case IrOpcode::kParameter:
+      return linkage()->GetParameterType(OpParameter<int>(node));
+    case IrOpcode::kPhi:
+      return OpParameter<MachineType>(node);
+    case IrOpcode::kProjection:
+      // TODO(jarin) Really project from outputs.
+      return kMachAnyTagged;
+    case IrOpcode::kInt32Constant:
+      return kMachInt32;
+    case IrOpcode::kInt64Constant:
+      return kMachInt64;
+    case IrOpcode::kExternalConstant:
+      return kMachPtr;
+    case IrOpcode::kFloat64Constant:
+      return kMachFloat64;
+    case IrOpcode::kHeapConstant:
+    case IrOpcode::kNumberConstant:
+      return kMachAnyTagged;
+    case IrOpcode::kCall:
+      return kMachAnyTagged;
+    case IrOpcode::kFrameState:
+    case IrOpcode::kStateValues:
+      return kMachNone;
+    case IrOpcode::kLoad:
+      return OpParameter<LoadRepresentation>(node);
+    case IrOpcode::kStore:
+      return kMachNone;
+    case IrOpcode::kCheckedLoad:
+      return OpParameter<MachineType>(node);
+    case IrOpcode::kCheckedStore:
+      return kMachNone;
+    case IrOpcode::kWord32And:
+    case IrOpcode::kWord32Or:
+    case IrOpcode::kWord32Xor:
+    case IrOpcode::kWord32Shl:
+    case IrOpcode::kWord32Shr:
+    case IrOpcode::kWord32Sar:
+    case IrOpcode::kWord32Ror:
+      return kMachInt32;
+    case IrOpcode::kWord32Equal:
+      return kMachBool;
+    case IrOpcode::kWord64And:
+    case IrOpcode::kWord64Or:
+    case IrOpcode::kWord64Xor:
+    case IrOpcode::kWord64Shl:
+    case IrOpcode::kWord64Shr:
+    case IrOpcode::kWord64Sar:
+    case IrOpcode::kWord64Ror:
+      return kMachInt64;
+    case IrOpcode::kWord64Equal:
+      return kMachBool;
+    case IrOpcode::kInt32Add:
+    case IrOpcode::kInt32AddWithOverflow:
+    case IrOpcode::kInt32Sub:
+    case IrOpcode::kInt32SubWithOverflow:
+    case IrOpcode::kInt32Mul:
+    case IrOpcode::kInt32Div:
+    case IrOpcode::kInt32Mod:
+      return kMachInt32;
+    case IrOpcode::kInt32LessThan:
+    case IrOpcode::kInt32LessThanOrEqual:
+    case IrOpcode::kUint32LessThan:
+    case IrOpcode::kUint32LessThanOrEqual:
+      return kMachBool;
+    case IrOpcode::kInt64Add:
+    case IrOpcode::kInt64Sub:
+    case IrOpcode::kInt64Mul:
+    case IrOpcode::kInt64Div:
+    case IrOpcode::kInt64Mod:
+      return kMachInt64;
+    case IrOpcode::kInt64LessThan:
+    case IrOpcode::kInt64LessThanOrEqual:
+      return kMachBool;
+    case IrOpcode::kChangeFloat32ToFloat64:
+    case IrOpcode::kChangeInt32ToFloat64:
+    case IrOpcode::kChangeUint32ToFloat64:
+      return kMachFloat64;
+    case IrOpcode::kChangeFloat64ToInt32:
+      return kMachInt32;
+    case IrOpcode::kChangeFloat64ToUint32:
+      return kMachUint32;
+    case IrOpcode::kChangeInt32ToInt64:
+      return kMachInt64;
+    case IrOpcode::kChangeUint32ToUint64:
+      return kMachUint64;
+    case IrOpcode::kTruncateFloat64ToFloat32:
+      return kMachFloat32;
+    case IrOpcode::kTruncateFloat64ToInt32:
+    case IrOpcode::kTruncateInt64ToInt32:
+      return kMachInt32;
+    case IrOpcode::kFloat64Add:
+    case IrOpcode::kFloat64Sub:
+    case IrOpcode::kFloat64Mul:
+    case IrOpcode::kFloat64Div:
+    case IrOpcode::kFloat64Mod:
+    case IrOpcode::kFloat64Sqrt:
+    case IrOpcode::kFloat64Floor:
+    case IrOpcode::kFloat64Ceil:
+    case IrOpcode::kFloat64RoundTruncate:
+    case IrOpcode::kFloat64RoundTiesAway:
+      return kMachFloat64;
+    case IrOpcode::kFloat64Equal:
+    case IrOpcode::kFloat64LessThan:
+    case IrOpcode::kFloat64LessThanOrEqual:
+      return kMachBool;
+    default:
+      V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d",
+               node->opcode(), node->op()->mnemonic(), node->id());
+  }
+  return kMachNone;
+}
+
+
 void InstructionSelector::VisitNode(Node* node) {
   DCHECK_NOT_NULL(schedule()->block(node));  // should only use scheduled nodes.
   SourcePosition source_position = source_positions_->GetSourcePosition(node);
@@ -476,6 +680,8 @@
     case IrOpcode::kInt64Constant:
     case IrOpcode::kExternalConstant:
       return VisitConstant(node);
+    case IrOpcode::kFloat32Constant:
+      return MarkAsDouble(node), VisitConstant(node);
     case IrOpcode::kFloat64Constant:
       return MarkAsDouble(node), VisitConstant(node);
     case IrOpcode::kHeapConstant:
@@ -483,7 +689,7 @@
       // TODO(turbofan): only mark non-smis as references.
       return MarkAsReference(node), VisitConstant(node);
     case IrOpcode::kCall:
-      return VisitCall(node, NULL, NULL);
+      return VisitCall(node);
     case IrOpcode::kFrameState:
     case IrOpcode::kStateValues:
       return;
@@ -536,22 +742,26 @@
       return VisitInt32SubWithOverflow(node);
     case IrOpcode::kInt32Mul:
       return VisitInt32Mul(node);
+    case IrOpcode::kInt32MulHigh:
+      return VisitInt32MulHigh(node);
     case IrOpcode::kInt32Div:
       return VisitInt32Div(node);
-    case IrOpcode::kInt32UDiv:
-      return VisitInt32UDiv(node);
     case IrOpcode::kInt32Mod:
       return VisitInt32Mod(node);
-    case IrOpcode::kInt32UMod:
-      return VisitInt32UMod(node);
     case IrOpcode::kInt32LessThan:
       return VisitInt32LessThan(node);
     case IrOpcode::kInt32LessThanOrEqual:
       return VisitInt32LessThanOrEqual(node);
+    case IrOpcode::kUint32Div:
+      return VisitUint32Div(node);
     case IrOpcode::kUint32LessThan:
       return VisitUint32LessThan(node);
     case IrOpcode::kUint32LessThanOrEqual:
       return VisitUint32LessThanOrEqual(node);
+    case IrOpcode::kUint32Mod:
+      return VisitUint32Mod(node);
+    case IrOpcode::kUint32MulHigh:
+      return VisitUint32MulHigh(node);
     case IrOpcode::kInt64Add:
       return VisitInt64Add(node);
     case IrOpcode::kInt64Sub:
@@ -560,16 +770,20 @@
       return VisitInt64Mul(node);
     case IrOpcode::kInt64Div:
       return VisitInt64Div(node);
-    case IrOpcode::kInt64UDiv:
-      return VisitInt64UDiv(node);
     case IrOpcode::kInt64Mod:
       return VisitInt64Mod(node);
-    case IrOpcode::kInt64UMod:
-      return VisitInt64UMod(node);
     case IrOpcode::kInt64LessThan:
       return VisitInt64LessThan(node);
     case IrOpcode::kInt64LessThanOrEqual:
       return VisitInt64LessThanOrEqual(node);
+    case IrOpcode::kUint64Div:
+      return VisitUint64Div(node);
+    case IrOpcode::kUint64LessThan:
+      return VisitUint64LessThan(node);
+    case IrOpcode::kUint64Mod:
+      return VisitUint64Mod(node);
+    case IrOpcode::kChangeFloat32ToFloat64:
+      return MarkAsDouble(node), VisitChangeFloat32ToFloat64(node);
     case IrOpcode::kChangeInt32ToFloat64:
       return MarkAsDouble(node), VisitChangeInt32ToFloat64(node);
     case IrOpcode::kChangeUint32ToFloat64:
@@ -582,6 +796,8 @@
       return VisitChangeInt32ToInt64(node);
     case IrOpcode::kChangeUint32ToUint64:
       return VisitChangeUint32ToUint64(node);
+    case IrOpcode::kTruncateFloat64ToFloat32:
+      return MarkAsDouble(node), VisitTruncateFloat64ToFloat32(node);
     case IrOpcode::kTruncateFloat64ToInt32:
       return VisitTruncateFloat64ToInt32(node);
     case IrOpcode::kTruncateInt64ToInt32:
@@ -604,91 +820,33 @@
       return VisitFloat64LessThan(node);
     case IrOpcode::kFloat64LessThanOrEqual:
       return VisitFloat64LessThanOrEqual(node);
+    case IrOpcode::kFloat64Floor:
+      return MarkAsDouble(node), VisitFloat64Floor(node);
+    case IrOpcode::kFloat64Ceil:
+      return MarkAsDouble(node), VisitFloat64Ceil(node);
+    case IrOpcode::kFloat64RoundTruncate:
+      return MarkAsDouble(node), VisitFloat64RoundTruncate(node);
+    case IrOpcode::kFloat64RoundTiesAway:
+      return MarkAsDouble(node), VisitFloat64RoundTiesAway(node);
+    case IrOpcode::kLoadStackPointer:
+      return VisitLoadStackPointer(node);
+    case IrOpcode::kCheckedLoad: {
+      MachineType rep = OpParameter<MachineType>(node);
+      MarkAsRepresentation(rep, node);
+      return VisitCheckedLoad(node);
+    }
+    case IrOpcode::kCheckedStore:
+      return VisitCheckedStore(node);
     default:
       V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d",
                node->opcode(), node->op()->mnemonic(), node->id());
+      break;
   }
 }
 
 
 #if V8_TURBOFAN_BACKEND
 
-void InstructionSelector::VisitWord32Equal(Node* node) {
-  FlagsContinuation cont(kEqual, node);
-  Int32BinopMatcher m(node);
-  if (m.right().Is(0)) {
-    return VisitWord32Test(m.left().node(), &cont);
-  }
-  VisitWord32Compare(node, &cont);
-}
-
-
-void InstructionSelector::VisitInt32LessThan(Node* node) {
-  FlagsContinuation cont(kSignedLessThan, node);
-  VisitWord32Compare(node, &cont);
-}
-
-
-void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
-  FlagsContinuation cont(kSignedLessThanOrEqual, node);
-  VisitWord32Compare(node, &cont);
-}
-
-
-void InstructionSelector::VisitUint32LessThan(Node* node) {
-  FlagsContinuation cont(kUnsignedLessThan, node);
-  VisitWord32Compare(node, &cont);
-}
-
-
-void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
-  FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
-  VisitWord32Compare(node, &cont);
-}
-
-
-void InstructionSelector::VisitWord64Equal(Node* node) {
-  FlagsContinuation cont(kEqual, node);
-  Int64BinopMatcher m(node);
-  if (m.right().Is(0)) {
-    return VisitWord64Test(m.left().node(), &cont);
-  }
-  VisitWord64Compare(node, &cont);
-}
-
-
-void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
-  if (Node* ovf = node->FindProjection(1)) {
-    FlagsContinuation cont(kOverflow, ovf);
-    return VisitInt32AddWithOverflow(node, &cont);
-  }
-  FlagsContinuation cont;
-  VisitInt32AddWithOverflow(node, &cont);
-}
-
-
-void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
-  if (Node* ovf = node->FindProjection(1)) {
-    FlagsContinuation cont(kOverflow, ovf);
-    return VisitInt32SubWithOverflow(node, &cont);
-  }
-  FlagsContinuation cont;
-  VisitInt32SubWithOverflow(node, &cont);
-}
-
-
-void InstructionSelector::VisitInt64LessThan(Node* node) {
-  FlagsContinuation cont(kSignedLessThan, node);
-  VisitWord64Compare(node, &cont);
-}
-
-
-void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
-  FlagsContinuation cont(kSignedLessThanOrEqual, node);
-  VisitWord64Compare(node, &cont);
-}
-
-
 void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
   OperandGenerator g(this);
   Emit(kArchTruncateDoubleToI, g.DefineAsRegister(node),
@@ -696,27 +854,15 @@
 }
 
 
-void InstructionSelector::VisitFloat64Equal(Node* node) {
-  FlagsContinuation cont(kUnorderedEqual, node);
-  VisitFloat64Compare(node, &cont);
-}
-
-
-void InstructionSelector::VisitFloat64LessThan(Node* node) {
-  FlagsContinuation cont(kUnorderedLessThan, node);
-  VisitFloat64Compare(node, &cont);
-}
-
-
-void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
-  FlagsContinuation cont(kUnorderedLessThanOrEqual, node);
-  VisitFloat64Compare(node, &cont);
+void InstructionSelector::VisitLoadStackPointer(Node* node) {
+  OperandGenerator g(this);
+  Emit(kArchStackPointer, g.DefineAsRegister(node));
 }
 
 #endif  // V8_TURBOFAN_BACKEND
 
 // 32 bit targets do not implement the following instructions.
-#if V8_TARGET_ARCH_32_BIT && V8_TURBOFAN_BACKEND
+#if V8_TARGET_ARCH_32_BIT && !V8_TARGET_ARCH_X64 && V8_TURBOFAN_BACKEND
 
 void InstructionSelector::VisitWord64And(Node* node) { UNIMPLEMENTED(); }
 
@@ -739,6 +885,9 @@
 void InstructionSelector::VisitWord64Ror(Node* node) { UNIMPLEMENTED(); }
 
 
+void InstructionSelector::VisitWord64Equal(Node* node) { UNIMPLEMENTED(); }
+
+
 void InstructionSelector::VisitInt64Add(Node* node) { UNIMPLEMENTED(); }
 
 
@@ -751,13 +900,24 @@
 void InstructionSelector::VisitInt64Div(Node* node) { UNIMPLEMENTED(); }
 
 
-void InstructionSelector::VisitInt64UDiv(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitInt64LessThan(Node* node) { UNIMPLEMENTED(); }
+
+
+void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
+  UNIMPLEMENTED();
+}
+
+
+void InstructionSelector::VisitUint64Div(Node* node) { UNIMPLEMENTED(); }
 
 
 void InstructionSelector::VisitInt64Mod(Node* node) { UNIMPLEMENTED(); }
 
 
-void InstructionSelector::VisitInt64UMod(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitUint64LessThan(Node* node) { UNIMPLEMENTED(); }
+
+
+void InstructionSelector::VisitUint64Mod(Node* node) { UNIMPLEMENTED(); }
 
 
 void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
@@ -774,24 +934,7 @@
   UNIMPLEMENTED();
 }
 
-#endif  // V8_TARGET_ARCH_32_BIT && V8_TURBOFAN_BACKEND
-
-
-// 32-bit targets and unsupported architectures need dummy implementations of
-// selected 64-bit ops.
-#if V8_TARGET_ARCH_32_BIT || !V8_TURBOFAN_BACKEND
-
-void InstructionSelector::VisitWord64Test(Node* node, FlagsContinuation* cont) {
-  UNIMPLEMENTED();
-}
-
-
-void InstructionSelector::VisitWord64Compare(Node* node,
-                                             FlagsContinuation* cont) {
-  UNIMPLEMENTED();
-}
-
-#endif  // V8_TARGET_ARCH_32_BIT || !V8_TURBOFAN_BACKEND
+#endif  // V8_TARGET_ARCH_32_BIT && !V8_TARGET_ARCH_X64 && V8_TURBOFAN_BACKEND
 
 
 void InstructionSelector::VisitFinish(Node* node) {
@@ -811,9 +954,15 @@
 
 
 void InstructionSelector::VisitPhi(Node* node) {
-  // TODO(bmeurer): Emit a PhiInstruction here.
-  for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) {
-    MarkAsUsed(*i);
+  const int input_count = node->op()->ValueInputCount();
+  PhiInstruction* phi = new (instruction_zone())
+      PhiInstruction(instruction_zone(), GetVirtualRegister(node),
+                     static_cast<size_t>(input_count));
+  sequence()->InstructionBlockAt(current_block_->GetRpoNumber())->AddPhi(phi);
+  for (int i = 0; i < input_count; ++i) {
+    Node* const input = node->InputAt(i);
+    MarkAsUsed(input);
+    phi->Extend(instruction_zone(), GetVirtualRegister(input));
   }
 }
 
@@ -846,124 +995,9 @@
 
 
 void InstructionSelector::VisitGoto(BasicBlock* target) {
-  if (IsNextInAssemblyOrder(target)) {
-    // fall through to the next block.
-    Emit(kArchNop, NULL)->MarkAsControl();
-  } else {
-    // jump to the next block.
-    OperandGenerator g(this);
-    Emit(kArchJmp, NULL, g.Label(target))->MarkAsControl();
-  }
-}
-
-
-void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
-                                      BasicBlock* fbranch) {
+  // jump to the next block.
   OperandGenerator g(this);
-  Node* user = branch;
-  Node* value = branch->InputAt(0);
-
-  FlagsContinuation cont(kNotEqual, tbranch, fbranch);
-
-  // If we can fall through to the true block, invert the branch.
-  if (IsNextInAssemblyOrder(tbranch)) {
-    cont.Negate();
-    cont.SwapBlocks();
-  }
-
-  // Try to combine with comparisons against 0 by simply inverting the branch.
-  while (CanCover(user, value)) {
-    if (value->opcode() == IrOpcode::kWord32Equal) {
-      Int32BinopMatcher m(value);
-      if (m.right().Is(0)) {
-        user = value;
-        value = m.left().node();
-        cont.Negate();
-      } else {
-        break;
-      }
-    } else if (value->opcode() == IrOpcode::kWord64Equal) {
-      Int64BinopMatcher m(value);
-      if (m.right().Is(0)) {
-        user = value;
-        value = m.left().node();
-        cont.Negate();
-      } else {
-        break;
-      }
-    } else {
-      break;
-    }
-  }
-
-  // Try to combine the branch with a comparison.
-  if (CanCover(user, value)) {
-    switch (value->opcode()) {
-      case IrOpcode::kWord32Equal:
-        cont.OverwriteAndNegateIfEqual(kEqual);
-        return VisitWord32Compare(value, &cont);
-      case IrOpcode::kInt32LessThan:
-        cont.OverwriteAndNegateIfEqual(kSignedLessThan);
-        return VisitWord32Compare(value, &cont);
-      case IrOpcode::kInt32LessThanOrEqual:
-        cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
-        return VisitWord32Compare(value, &cont);
-      case IrOpcode::kUint32LessThan:
-        cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
-        return VisitWord32Compare(value, &cont);
-      case IrOpcode::kUint32LessThanOrEqual:
-        cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
-        return VisitWord32Compare(value, &cont);
-      case IrOpcode::kWord64Equal:
-        cont.OverwriteAndNegateIfEqual(kEqual);
-        return VisitWord64Compare(value, &cont);
-      case IrOpcode::kInt64LessThan:
-        cont.OverwriteAndNegateIfEqual(kSignedLessThan);
-        return VisitWord64Compare(value, &cont);
-      case IrOpcode::kInt64LessThanOrEqual:
-        cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
-        return VisitWord64Compare(value, &cont);
-      case IrOpcode::kFloat64Equal:
-        cont.OverwriteAndNegateIfEqual(kUnorderedEqual);
-        return VisitFloat64Compare(value, &cont);
-      case IrOpcode::kFloat64LessThan:
-        cont.OverwriteAndNegateIfEqual(kUnorderedLessThan);
-        return VisitFloat64Compare(value, &cont);
-      case IrOpcode::kFloat64LessThanOrEqual:
-        cont.OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual);
-        return VisitFloat64Compare(value, &cont);
-      case IrOpcode::kProjection:
-        // Check if this is the overflow output projection of an
-        // <Operation>WithOverflow node.
-        if (OpParameter<size_t>(value) == 1u) {
-          // We cannot combine the <Operation>WithOverflow with this branch
-          // unless the 0th projection (the use of the actual value of the
-          // <Operation> is either NULL, which means there's no use of the
-          // actual value, or was already defined, which means it is scheduled
-          // *AFTER* this branch).
-          Node* node = value->InputAt(0);
-          Node* result = node->FindProjection(0);
-          if (result == NULL || IsDefined(result)) {
-            switch (node->opcode()) {
-              case IrOpcode::kInt32AddWithOverflow:
-                cont.OverwriteAndNegateIfEqual(kOverflow);
-                return VisitInt32AddWithOverflow(node, &cont);
-              case IrOpcode::kInt32SubWithOverflow:
-                cont.OverwriteAndNegateIfEqual(kOverflow);
-                return VisitInt32SubWithOverflow(node, &cont);
-              default:
-                break;
-            }
-          }
-        }
-        break;
-      default:
-        break;
-    }
-  }
-
-  // Branch could not be combined with a compare, emit compare against 0.
-  VisitWord32Test(value, &cont);
+  Emit(kArchJmp, NULL, g.Label(target))->MarkAsControl();
 }
 
 
@@ -983,14 +1017,29 @@
 }
 
 
+void InstructionSelector::FillTypeVectorFromStateValues(
+    ZoneVector<MachineType>* types, Node* state_values) {
+  DCHECK(state_values->opcode() == IrOpcode::kStateValues);
+  int count = state_values->InputCount();
+  types->reserve(static_cast<size_t>(count));
+  for (int i = 0; i < count; i++) {
+    types->push_back(GetMachineType(state_values->InputAt(i)));
+  }
+}
+
+
 FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
     Node* state) {
   DCHECK(state->opcode() == IrOpcode::kFrameState);
   DCHECK_EQ(5, state->InputCount());
+  DCHECK_EQ(IrOpcode::kStateValues, state->InputAt(0)->opcode());
+  DCHECK_EQ(IrOpcode::kStateValues, state->InputAt(1)->opcode());
+  DCHECK_EQ(IrOpcode::kStateValues, state->InputAt(2)->opcode());
   FrameStateCallInfo state_info = OpParameter<FrameStateCallInfo>(state);
-  int parameters = OpParameter<int>(state->InputAt(0));
-  int locals = OpParameter<int>(state->InputAt(1));
-  int stack = OpParameter<int>(state->InputAt(2));
+
+  int parameters = state->InputAt(0)->InputCount();
+  int locals = state->InputAt(1)->InputCount();
+  int stack = state->InputAt(2)->InputCount();
 
   FrameStateDescriptor* outer_state = NULL;
   Node* outer_node = state->InputAt(4);
@@ -998,8 +1047,8 @@
     outer_state = GetFrameStateDescriptor(outer_node);
   }
 
-  return new (instruction_zone())
-      FrameStateDescriptor(state_info, parameters, locals, stack, outer_state);
+  return new (instruction_zone()) FrameStateDescriptor(
+      instruction_zone(), state_info, parameters, locals, stack, outer_state);
 }
 
 
@@ -1034,23 +1083,36 @@
   DCHECK_EQ(IrOpcode::kStateValues, locals->op()->opcode());
   DCHECK_EQ(IrOpcode::kStateValues, stack->op()->opcode());
 
-  DCHECK_EQ(descriptor->parameters_count(), parameters->InputCount());
-  DCHECK_EQ(descriptor->locals_count(), locals->InputCount());
-  DCHECK_EQ(descriptor->stack_count(), stack->InputCount());
+  DCHECK_EQ(static_cast<int>(descriptor->parameters_count()),
+            parameters->InputCount());
+  DCHECK_EQ(static_cast<int>(descriptor->locals_count()), locals->InputCount());
+  DCHECK_EQ(static_cast<int>(descriptor->stack_count()), stack->InputCount());
+
+  ZoneVector<MachineType> types(instruction_zone());
+  types.reserve(descriptor->GetSize());
 
   OperandGenerator g(this);
+  size_t value_index = 0;
   for (int i = 0; i < static_cast<int>(descriptor->parameters_count()); i++) {
-    inputs->push_back(UseOrImmediate(&g, parameters->InputAt(i)));
+    Node* input_node = parameters->InputAt(i);
+    inputs->push_back(UseOrImmediate(&g, input_node));
+    descriptor->SetType(value_index++, GetMachineType(input_node));
   }
   if (descriptor->HasContext()) {
     inputs->push_back(UseOrImmediate(&g, context));
+    descriptor->SetType(value_index++, kMachAnyTagged);
   }
   for (int i = 0; i < static_cast<int>(descriptor->locals_count()); i++) {
-    inputs->push_back(UseOrImmediate(&g, locals->InputAt(i)));
+    Node* input_node = locals->InputAt(i);
+    inputs->push_back(UseOrImmediate(&g, input_node));
+    descriptor->SetType(value_index++, GetMachineType(input_node));
   }
   for (int i = 0; i < static_cast<int>(descriptor->stack_count()); i++) {
-    inputs->push_back(UseOrImmediate(&g, stack->InputAt(i)));
+    Node* input_node = stack->InputAt(i);
+    inputs->push_back(UseOrImmediate(&g, input_node));
+    descriptor->SetType(value_index++, GetMachineType(input_node));
   }
+  DCHECK(value_index == descriptor->GetSize());
 }
 
 
@@ -1062,38 +1124,21 @@
 #undef DECLARE_UNIMPLEMENTED_SELECTOR
 
 
-void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
-                                                    FlagsContinuation* cont) {
+void InstructionSelector::VisitCall(Node* node) { UNIMPLEMENTED(); }
+
+
+void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
+                                      BasicBlock* fbranch) {
   UNIMPLEMENTED();
 }
 
 
-void InstructionSelector::VisitInt32SubWithOverflow(Node* node,
-                                                    FlagsContinuation* cont) {
-  UNIMPLEMENTED();
+// static
+MachineOperatorBuilder::Flags
+InstructionSelector::SupportedMachineOperatorFlags() {
+  return MachineOperatorBuilder::Flag::kNoFlags;
 }
 
-
-void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) {
-  UNIMPLEMENTED();
-}
-
-
-void InstructionSelector::VisitWord32Compare(Node* node,
-                                             FlagsContinuation* cont) {
-  UNIMPLEMENTED();
-}
-
-
-void InstructionSelector::VisitFloat64Compare(Node* node,
-                                              FlagsContinuation* cont) {
-  UNIMPLEMENTED();
-}
-
-
-void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
-                                    BasicBlock* deoptimization) {}
-
 #endif  // !V8_TURBOFAN_BACKEND
 
 }  // namespace compiler
diff --git a/src/compiler/instruction-selector.h b/src/compiler/instruction-selector.h
index a86e156..5e3c52f 100644
--- a/src/compiler/instruction-selector.h
+++ b/src/compiler/instruction-selector.h
@@ -19,13 +19,20 @@
 // Forward declarations.
 struct CallBuffer;  // TODO(bmeurer): Remove this.
 class FlagsContinuation;
+class Linkage;
+
+typedef IntVector NodeToVregMap;
 
 class InstructionSelector FINAL {
  public:
+  static const int kNodeUnmapped = -1;
+
   // Forward declarations.
   class Features;
 
-  InstructionSelector(InstructionSequence* sequence,
+  // TODO(dcarney): pass in vreg mapping instead of graph.
+  InstructionSelector(Zone* local_zone, Graph* graph, Linkage* linkage,
+                      InstructionSequence* sequence, Schedule* schedule,
                       SourcePositionTable* source_positions,
                       Features features = SupportedFeatures());
 
@@ -52,6 +59,16 @@
                     InstructionOperand* a, InstructionOperand* b,
                     InstructionOperand* c, InstructionOperand* d,
                     size_t temp_count = 0, InstructionOperand* *temps = NULL);
+  Instruction* Emit(InstructionCode opcode, InstructionOperand* output,
+                    InstructionOperand* a, InstructionOperand* b,
+                    InstructionOperand* c, InstructionOperand* d,
+                    InstructionOperand* e, size_t temp_count = 0,
+                    InstructionOperand* *temps = NULL);
+  Instruction* Emit(InstructionCode opcode, InstructionOperand* output,
+                    InstructionOperand* a, InstructionOperand* b,
+                    InstructionOperand* c, InstructionOperand* d,
+                    InstructionOperand* e, InstructionOperand* f,
+                    size_t temp_count = 0, InstructionOperand* *temps = NULL);
   Instruction* Emit(InstructionCode opcode, size_t output_count,
                     InstructionOperand** outputs, size_t input_count,
                     InstructionOperand** inputs, size_t temp_count = 0,
@@ -84,17 +101,13 @@
     return Features(CpuFeatures::SupportedFeatures());
   }
 
- private:
-  friend class OperandGenerator;
+  // TODO(sigurds) This should take a CpuFeatures argument.
+  static MachineOperatorBuilder::Flags SupportedMachineOperatorFlags();
 
   // ===========================================================================
   // ============ Architecture-independent graph covering methods. =============
   // ===========================================================================
 
-  // Checks if {block} will appear directly after {current_block_} when
-  // assembling code, in which case, a fall-through can be used.
-  bool IsNextInAssemblyOrder(const BasicBlock* block) const;
-
   // Used in pattern matching during code generation.
   // Check if {node} can be covered while generating code for the current
   // instruction. A node can be covered if the {user} of the node has the only
@@ -105,13 +118,24 @@
   // generated for it.
   bool IsDefined(Node* node) const;
 
-  // Inform the instruction selection that {node} was just defined.
-  void MarkAsDefined(Node* node);
-
   // Checks if {node} has any uses, and therefore code has to be generated for
   // it.
   bool IsUsed(Node* node) const;
 
+  // Checks if {node} is currently live.
+  bool IsLive(Node* node) const { return !IsDefined(node) && IsUsed(node); }
+
+  int GetVirtualRegister(const Node* node);
+  // Gets the current mapping if it exists, kNodeUnmapped otherwise.
+  int GetMappedVirtualRegister(const Node* node) const;
+  const NodeToVregMap& GetNodeMapForTesting() const { return node_map_; }
+
+ private:
+  friend class OperandGenerator;
+
+  // Inform the instruction selection that {node} was just defined.
+  void MarkAsDefined(Node* node);
+
   // Inform the instruction selection that {node} has at least one use and we
   // will need to generate code for it.
   void MarkAsUsed(Node* node);
@@ -132,6 +156,10 @@
   // by {node}.
   void MarkAsRepresentation(MachineType rep, Node* node);
 
+  // Inform the register allocation of the representation of the unallocated
+  // operand {op}.
+  void MarkAsRepresentation(MachineType rep, InstructionOperand* op);
+
   // Initialize the call buffer with the InstructionOperands, nodes, etc,
   // corresponding
   // to the inputs and outputs of the call.
@@ -142,8 +170,11 @@
                             bool call_address_immediate);
 
   FrameStateDescriptor* GetFrameStateDescriptor(Node* node);
+  void FillTypeVectorFromStateValues(ZoneVector<MachineType>* parameters,
+                                     Node* state_values);
   void AddFrameStateInputs(Node* state, InstructionOperandVector* inputs,
                            FrameStateDescriptor* descriptor);
+  MachineType GetMachineType(Node* node);
 
   // ===========================================================================
   // ============= Architecture-specific graph covering methods. ===============
@@ -163,22 +194,12 @@
   MACHINE_OP_LIST(DECLARE_GENERATOR)
 #undef DECLARE_GENERATOR
 
-  void VisitInt32AddWithOverflow(Node* node, FlagsContinuation* cont);
-  void VisitInt32SubWithOverflow(Node* node, FlagsContinuation* cont);
-
-  void VisitWord32Test(Node* node, FlagsContinuation* cont);
-  void VisitWord64Test(Node* node, FlagsContinuation* cont);
-  void VisitWord32Compare(Node* node, FlagsContinuation* cont);
-  void VisitWord64Compare(Node* node, FlagsContinuation* cont);
-  void VisitFloat64Compare(Node* node, FlagsContinuation* cont);
-
   void VisitFinish(Node* node);
   void VisitParameter(Node* node);
   void VisitPhi(Node* node);
   void VisitProjection(Node* node);
   void VisitConstant(Node* node);
-  void VisitCall(Node* call, BasicBlock* continuation,
-                 BasicBlock* deoptimization);
+  void VisitCall(Node* call);
   void VisitGoto(BasicBlock* target);
   void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch);
   void VisitReturn(Node* value);
@@ -187,19 +208,21 @@
 
   // ===========================================================================
 
-  Graph* graph() const { return sequence()->graph(); }
-  Linkage* linkage() const { return sequence()->linkage(); }
-  Schedule* schedule() const { return sequence()->schedule(); }
+  Schedule* schedule() const { return schedule_; }
+  Linkage* linkage() const { return linkage_; }
   InstructionSequence* sequence() const { return sequence_; }
   Zone* instruction_zone() const { return sequence()->zone(); }
-  Zone* zone() { return &zone_; }
+  Zone* zone() const { return zone_; }
 
   // ===========================================================================
 
-  Zone zone_;
-  InstructionSequence* sequence_;
-  SourcePositionTable* source_positions_;
+  Zone* const zone_;
+  Linkage* const linkage_;
+  InstructionSequence* const sequence_;
+  SourcePositionTable* const source_positions_;
   Features features_;
+  Schedule* const schedule_;
+  NodeToVregMap node_map_;
   BasicBlock* current_block_;
   ZoneDeque<Instruction*> instructions_;
   BoolVector defined_;
diff --git a/src/compiler/instruction.cc b/src/compiler/instruction.cc
index 9ab81b6..f83cdeb 100644
--- a/src/compiler/instruction.cc
+++ b/src/compiler/instruction.cc
@@ -2,18 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/compiler/instruction.h"
-
 #include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/instruction.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
-OStream& operator<<(OStream& os, const InstructionOperand& op) {
+std::ostream& operator<<(std::ostream& os,
+                         const PrintableInstructionOperand& printable) {
+  const InstructionOperand& op = *printable.op_;
+  const RegisterConfiguration* conf = printable.register_configuration_;
   switch (op.kind()) {
-    case InstructionOperand::INVALID:
-      return os << "(0)";
     case InstructionOperand::UNALLOCATED: {
       const UnallocatedOperand* unalloc = UnallocatedOperand::cast(&op);
       os << "v" << unalloc->virtual_register();
@@ -24,10 +25,10 @@
         case UnallocatedOperand::NONE:
           return os;
         case UnallocatedOperand::FIXED_REGISTER:
-          return os << "(=" << Register::AllocationIndexToString(
+          return os << "(=" << conf->general_register_name(
                                    unalloc->fixed_register_index()) << ")";
         case UnallocatedOperand::FIXED_DOUBLE_REGISTER:
-          return os << "(=" << DoubleRegister::AllocationIndexToString(
+          return os << "(=" << conf->double_register_name(
                                    unalloc->fixed_register_index()) << ")";
         case UnallocatedOperand::MUST_HAVE_REGISTER:
           return os << "(R)";
@@ -46,11 +47,9 @@
     case InstructionOperand::DOUBLE_STACK_SLOT:
       return os << "[double_stack:" << op.index() << "]";
     case InstructionOperand::REGISTER:
-      return os << "[" << Register::AllocationIndexToString(op.index())
-                << "|R]";
+      return os << "[" << conf->general_register_name(op.index()) << "|R]";
     case InstructionOperand::DOUBLE_REGISTER:
-      return os << "[" << DoubleRegister::AllocationIndexToString(op.index())
-                << "|R]";
+      return os << "[" << conf->double_register_name(op.index()) << "|R]";
   }
   UNREACHABLE();
   return os;
@@ -95,9 +94,17 @@
 }
 
 
-OStream& operator<<(OStream& os, const MoveOperands& mo) {
-  os << *mo.destination();
-  if (!mo.source()->Equals(mo.destination())) os << " = " << *mo.source();
+std::ostream& operator<<(std::ostream& os,
+                         const PrintableMoveOperands& printable) {
+  const MoveOperands& mo = *printable.move_operands_;
+  PrintableInstructionOperand printable_op = {printable.register_configuration_,
+                                              mo.destination()};
+
+  os << printable_op;
+  if (!mo.source()->Equals(mo.destination())) {
+    printable_op.op_ = mo.source();
+    os << " = " << printable_op;
+  }
   return os << ";";
 }
 
@@ -110,14 +117,27 @@
 }
 
 
-OStream& operator<<(OStream& os, const ParallelMove& pm) {
+bool GapInstruction::IsRedundant() const {
+  for (int i = GapInstruction::FIRST_INNER_POSITION;
+       i <= GapInstruction::LAST_INNER_POSITION; i++) {
+    if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant())
+      return false;
+  }
+  return true;
+}
+
+
+std::ostream& operator<<(std::ostream& os,
+                         const PrintableParallelMove& printable) {
+  const ParallelMove& pm = *printable.parallel_move_;
   bool first = true;
   for (ZoneList<MoveOperands>::iterator move = pm.move_operands()->begin();
        move != pm.move_operands()->end(); ++move) {
     if (move->IsEliminated()) continue;
     if (!first) os << " ";
     first = false;
-    os << *move;
+    PrintableMoveOperands pmo = {printable.register_configuration_, move};
+    os << pmo;
   }
   return os;
 }
@@ -152,7 +172,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const PointerMap& pm) {
+std::ostream& operator<<(std::ostream& os, const PointerMap& pm) {
   os << "{";
   for (ZoneList<InstructionOperand*>::iterator op =
            pm.pointer_operands_.begin();
@@ -164,7 +184,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const ArchOpcode& ao) {
+std::ostream& operator<<(std::ostream& os, const ArchOpcode& ao) {
   switch (ao) {
 #define CASE(Name) \
   case k##Name:    \
@@ -177,7 +197,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const AddressingMode& am) {
+std::ostream& operator<<(std::ostream& os, const AddressingMode& am) {
   switch (am) {
     case kMode_None:
       return os;
@@ -192,7 +212,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const FlagsMode& fm) {
+std::ostream& operator<<(std::ostream& os, const FlagsMode& fm) {
   switch (fm) {
     case kFlags_none:
       return os;
@@ -206,7 +226,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const FlagsCondition& fc) {
+std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc) {
   switch (fc) {
     case kEqual:
       return os << "equal";
@@ -250,11 +270,16 @@
 }
 
 
-OStream& operator<<(OStream& os, const Instruction& instr) {
+std::ostream& operator<<(std::ostream& os,
+                         const PrintableInstruction& printable) {
+  const Instruction& instr = *printable.instr_;
+  PrintableInstructionOperand printable_op = {printable.register_configuration_,
+                                              NULL};
   if (instr.OutputCount() > 1) os << "(";
   for (size_t i = 0; i < instr.OutputCount(); i++) {
     if (i > 0) os << ", ";
-    os << *instr.OutputAt(i);
+    printable_op.op_ = instr.OutputAt(i);
+    os << printable_op;
   }
 
   if (instr.OutputCount() > 1) os << ") = ";
@@ -266,7 +291,11 @@
     for (int i = GapInstruction::FIRST_INNER_POSITION;
          i <= GapInstruction::LAST_INNER_POSITION; i++) {
       os << "(";
-      if (gap->parallel_moves_[i] != NULL) os << *gap->parallel_moves_[i];
+      if (gap->parallel_moves_[i] != NULL) {
+        PrintableParallelMove ppm = {printable.register_configuration_,
+                                     gap->parallel_moves_[i]};
+        os << ppm;
+      }
       os << ") ";
     }
   } else if (instr.IsSourcePosition()) {
@@ -287,57 +316,175 @@
   }
   if (instr.InputCount() > 0) {
     for (size_t i = 0; i < instr.InputCount(); i++) {
-      os << " " << *instr.InputAt(i);
+      printable_op.op_ = instr.InputAt(i);
+      os << " " << printable_op;
     }
   }
-  return os << "\n";
+  return os;
 }
 
 
-OStream& operator<<(OStream& os, const Constant& constant) {
+std::ostream& operator<<(std::ostream& os, const Constant& constant) {
   switch (constant.type()) {
     case Constant::kInt32:
       return os << constant.ToInt32();
     case Constant::kInt64:
       return os << constant.ToInt64() << "l";
+    case Constant::kFloat32:
+      return os << constant.ToFloat32() << "f";
     case Constant::kFloat64:
       return os << constant.ToFloat64();
     case Constant::kExternalReference:
-      return os << constant.ToExternalReference().address();
+      return os << static_cast<const void*>(
+                       constant.ToExternalReference().address());
     case Constant::kHeapObject:
       return os << Brief(*constant.ToHeapObject());
+    case Constant::kRpoNumber:
+      return os << "RPO" << constant.ToRpoNumber().ToInt();
   }
   UNREACHABLE();
   return os;
 }
 
 
-Label* InstructionSequence::GetLabel(BasicBlock* block) {
-  return GetBlockStart(block)->label();
+InstructionBlock::InstructionBlock(Zone* zone, BasicBlock::Id id,
+                                   BasicBlock::RpoNumber rpo_number,
+                                   BasicBlock::RpoNumber loop_header,
+                                   BasicBlock::RpoNumber loop_end,
+                                   bool deferred)
+    : successors_(zone),
+      predecessors_(zone),
+      phis_(zone),
+      id_(id),
+      ao_number_(rpo_number),
+      rpo_number_(rpo_number),
+      loop_header_(loop_header),
+      loop_end_(loop_end),
+      code_start_(-1),
+      code_end_(-1),
+      deferred_(deferred) {}
+
+
+size_t InstructionBlock::PredecessorIndexOf(
+    BasicBlock::RpoNumber rpo_number) const {
+  size_t j = 0;
+  for (InstructionBlock::Predecessors::const_iterator i = predecessors_.begin();
+       i != predecessors_.end(); ++i, ++j) {
+    if (*i == rpo_number) break;
+  }
+  return j;
 }
 
 
-BlockStartInstruction* InstructionSequence::GetBlockStart(BasicBlock* block) {
-  return BlockStartInstruction::cast(InstructionAt(block->code_start_));
+static BasicBlock::RpoNumber GetRpo(BasicBlock* block) {
+  if (block == NULL) return BasicBlock::RpoNumber::Invalid();
+  return block->GetRpoNumber();
 }
 
 
-void InstructionSequence::StartBlock(BasicBlock* block) {
-  block->code_start_ = static_cast<int>(instructions_.size());
-  BlockStartInstruction* block_start =
-      BlockStartInstruction::New(zone(), block);
-  AddInstruction(block_start, block);
+static BasicBlock::RpoNumber GetLoopEndRpo(const BasicBlock* block) {
+  if (!block->IsLoopHeader()) return BasicBlock::RpoNumber::Invalid();
+  return block->loop_end()->GetRpoNumber();
 }
 
 
-void InstructionSequence::EndBlock(BasicBlock* block) {
+static InstructionBlock* InstructionBlockFor(Zone* zone,
+                                             const BasicBlock* block) {
+  InstructionBlock* instr_block = new (zone) InstructionBlock(
+      zone, block->id(), block->GetRpoNumber(), GetRpo(block->loop_header()),
+      GetLoopEndRpo(block), block->deferred());
+  // Map successors and precessors
+  instr_block->successors().reserve(block->SuccessorCount());
+  for (auto it = block->successors_begin(); it != block->successors_end();
+       ++it) {
+    instr_block->successors().push_back((*it)->GetRpoNumber());
+  }
+  instr_block->predecessors().reserve(block->PredecessorCount());
+  for (auto it = block->predecessors_begin(); it != block->predecessors_end();
+       ++it) {
+    instr_block->predecessors().push_back((*it)->GetRpoNumber());
+  }
+  return instr_block;
+}
+
+
+InstructionBlocks* InstructionSequence::InstructionBlocksFor(
+    Zone* zone, const Schedule* schedule) {
+  InstructionBlocks* blocks = zone->NewArray<InstructionBlocks>(1);
+  new (blocks) InstructionBlocks(
+      static_cast<int>(schedule->rpo_order()->size()), NULL, zone);
+  size_t rpo_number = 0;
+  for (BasicBlockVector::const_iterator it = schedule->rpo_order()->begin();
+       it != schedule->rpo_order()->end(); ++it, ++rpo_number) {
+    DCHECK_EQ(NULL, (*blocks)[rpo_number]);
+    DCHECK((*it)->GetRpoNumber().ToSize() == rpo_number);
+    (*blocks)[rpo_number] = InstructionBlockFor(zone, *it);
+  }
+  ComputeAssemblyOrder(blocks);
+  return blocks;
+}
+
+
+void InstructionSequence::ComputeAssemblyOrder(InstructionBlocks* blocks) {
+  int ao = 0;
+  for (auto const block : *blocks) {
+    if (!block->IsDeferred()) {
+      block->set_ao_number(BasicBlock::RpoNumber::FromInt(ao++));
+    }
+  }
+  for (auto const block : *blocks) {
+    if (block->IsDeferred()) {
+      block->set_ao_number(BasicBlock::RpoNumber::FromInt(ao++));
+    }
+  }
+}
+
+
+InstructionSequence::InstructionSequence(Zone* instruction_zone,
+                                         InstructionBlocks* instruction_blocks)
+    : zone_(instruction_zone),
+      instruction_blocks_(instruction_blocks),
+      block_starts_(zone()),
+      constants_(ConstantMap::key_compare(),
+                 ConstantMap::allocator_type(zone())),
+      immediates_(zone()),
+      instructions_(zone()),
+      next_virtual_register_(0),
+      pointer_maps_(zone()),
+      doubles_(std::less<int>(), VirtualRegisterSet::allocator_type(zone())),
+      references_(std::less<int>(), VirtualRegisterSet::allocator_type(zone())),
+      deoptimization_entries_(zone()) {
+  block_starts_.reserve(instruction_blocks_->size());
+}
+
+
+BlockStartInstruction* InstructionSequence::GetBlockStart(
+    BasicBlock::RpoNumber rpo) const {
+  const InstructionBlock* block = InstructionBlockAt(rpo);
+  return BlockStartInstruction::cast(InstructionAt(block->code_start()));
+}
+
+
+void InstructionSequence::StartBlock(BasicBlock::RpoNumber rpo) {
+  DCHECK(block_starts_.size() == rpo.ToSize());
+  InstructionBlock* block = InstructionBlockAt(rpo);
+  int code_start = static_cast<int>(instructions_.size());
+  block->set_code_start(code_start);
+  block_starts_.push_back(code_start);
+  BlockStartInstruction* block_start = BlockStartInstruction::New(zone());
+  AddInstruction(block_start);
+}
+
+
+void InstructionSequence::EndBlock(BasicBlock::RpoNumber rpo) {
   int end = static_cast<int>(instructions_.size());
-  DCHECK(block->code_start_ >= 0 && block->code_start_ < end);
-  block->code_end_ = end;
+  InstructionBlock* block = InstructionBlockAt(rpo);
+  DCHECK(block->code_start() >= 0 && block->code_start() < end);
+  block->set_code_end(end);
 }
 
 
-int InstructionSequence::AddInstruction(Instruction* instr, BasicBlock* block) {
+int InstructionSequence::AddInstruction(Instruction* instr) {
   // TODO(titzer): the order of these gaps is a holdover from Lithium.
   GapInstruction* gap = GapInstruction::New(zone());
   if (instr->IsControl()) instructions_.push_back(gap);
@@ -355,15 +502,17 @@
 }
 
 
-BasicBlock* InstructionSequence::GetBasicBlock(int instruction_index) {
-  // TODO(turbofan): Optimize this.
-  for (;;) {
-    DCHECK_LE(0, instruction_index);
-    Instruction* instruction = InstructionAt(instruction_index--);
-    if (instruction->IsBlockStart()) {
-      return BlockStartInstruction::cast(instruction)->block();
-    }
-  }
+const InstructionBlock* InstructionSequence::GetInstructionBlock(
+    int instruction_index) const {
+  DCHECK(instruction_blocks_->size() == block_starts_.size());
+  auto begin = block_starts_.begin();
+  auto end = std::lower_bound(begin, block_starts_.end(), instruction_index,
+                              std::less_equal<int>());
+  size_t index = std::distance(begin, end) - 1;
+  auto block = instruction_blocks_->at(index);
+  DCHECK(block->code_start() <= instruction_index &&
+         instruction_index < block->code_end());
+  return block;
 }
 
 
@@ -412,7 +561,81 @@
 }
 
 
-OStream& operator<<(OStream& os, const InstructionSequence& code) {
+FrameStateDescriptor::FrameStateDescriptor(
+    Zone* zone, const FrameStateCallInfo& state_info, size_t parameters_count,
+    size_t locals_count, size_t stack_count, FrameStateDescriptor* outer_state)
+    : type_(state_info.type()),
+      bailout_id_(state_info.bailout_id()),
+      frame_state_combine_(state_info.state_combine()),
+      parameters_count_(parameters_count),
+      locals_count_(locals_count),
+      stack_count_(stack_count),
+      types_(zone),
+      outer_state_(outer_state),
+      jsfunction_(state_info.jsfunction()) {
+  types_.resize(GetSize(), kMachNone);
+}
+
+size_t FrameStateDescriptor::GetSize(OutputFrameStateCombine combine) const {
+  size_t size = parameters_count() + locals_count() + stack_count() +
+                (HasContext() ? 1 : 0);
+  switch (combine.kind()) {
+    case OutputFrameStateCombine::kPushOutput:
+      size += combine.GetPushCount();
+      break;
+    case OutputFrameStateCombine::kPokeAt:
+      break;
+  }
+  return size;
+}
+
+
+size_t FrameStateDescriptor::GetTotalSize() const {
+  size_t total_size = 0;
+  for (const FrameStateDescriptor* iter = this; iter != NULL;
+       iter = iter->outer_state_) {
+    total_size += iter->GetSize();
+  }
+  return total_size;
+}
+
+
+size_t FrameStateDescriptor::GetFrameCount() const {
+  size_t count = 0;
+  for (const FrameStateDescriptor* iter = this; iter != NULL;
+       iter = iter->outer_state_) {
+    ++count;
+  }
+  return count;
+}
+
+
+size_t FrameStateDescriptor::GetJSFrameCount() const {
+  size_t count = 0;
+  for (const FrameStateDescriptor* iter = this; iter != NULL;
+       iter = iter->outer_state_) {
+    if (iter->type_ == JS_FRAME) {
+      ++count;
+    }
+  }
+  return count;
+}
+
+
+MachineType FrameStateDescriptor::GetType(size_t index) const {
+  return types_[index];
+}
+
+
+void FrameStateDescriptor::SetType(size_t index, MachineType type) {
+  DCHECK(index < GetSize());
+  types_[index] = type;
+}
+
+
+std::ostream& operator<<(std::ostream& os,
+                         const PrintableInstructionSequence& printable) {
+  const InstructionSequence& code = *printable.sequence_;
   for (size_t i = 0; i < code.immediates_.size(); ++i) {
     Constant constant = code.immediates_[i];
     os << "IMM#" << i << ": " << constant << "\n";
@@ -422,57 +645,53 @@
        it != code.constants_.end(); ++i, ++it) {
     os << "CST#" << i << ": v" << it->first << " = " << it->second << "\n";
   }
-  for (int i = 0; i < code.BasicBlockCount(); i++) {
-    BasicBlock* block = code.BlockAt(i);
+  for (int i = 0; i < code.InstructionBlockCount(); i++) {
+    BasicBlock::RpoNumber rpo = BasicBlock::RpoNumber::FromInt(i);
+    const InstructionBlock* block = code.InstructionBlockAt(rpo);
+    CHECK(block->rpo_number() == rpo);
 
-    int bid = block->id();
-    os << "RPO#" << block->rpo_number_ << ": B" << bid;
-    CHECK(block->rpo_number_ == i);
+    os << "RPO#" << block->rpo_number();
+    os << ": AO#" << block->ao_number();
+    os << ": B" << block->id();
+    if (block->IsDeferred()) os << " (deferred)";
     if (block->IsLoopHeader()) {
-      os << " loop blocks: [" << block->rpo_number_ << ", " << block->loop_end_
-         << ")";
+      os << " loop blocks: [" << block->rpo_number() << ", "
+         << block->loop_end() << ")";
     }
-    os << "  instructions: [" << block->code_start_ << ", " << block->code_end_
-       << ")\n  predecessors:";
+    os << "  instructions: [" << block->code_start() << ", "
+       << block->code_end() << ")\n  predecessors:";
 
-    BasicBlock::Predecessors predecessors = block->predecessors();
-    for (BasicBlock::Predecessors::iterator iter = predecessors.begin();
-         iter != predecessors.end(); ++iter) {
-      os << " B" << (*iter)->id();
+    for (auto pred : block->predecessors()) {
+      const InstructionBlock* pred_block = code.InstructionBlockAt(pred);
+      os << " B" << pred_block->id();
     }
     os << "\n";
 
-    for (BasicBlock::const_iterator j = block->begin(); j != block->end();
-         ++j) {
-      Node* phi = *j;
-      if (phi->opcode() != IrOpcode::kPhi) continue;
-      os << "     phi: v" << phi->id() << " =";
-      Node::Inputs inputs = phi->inputs();
-      for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
-           ++iter) {
-        os << " v" << (*iter)->id();
+    for (auto phi : block->phis()) {
+      PrintableInstructionOperand printable_op = {
+          printable.register_configuration_, phi->output()};
+      os << "     phi: " << printable_op << " =";
+      for (auto input : phi->inputs()) {
+        printable_op.op_ = input;
+        os << " " << printable_op;
       }
       os << "\n";
     }
 
     ScopedVector<char> buf(32);
+    PrintableInstruction printable_instr;
+    printable_instr.register_configuration_ = printable.register_configuration_;
     for (int j = block->first_instruction_index();
          j <= block->last_instruction_index(); j++) {
       // TODO(svenpanne) Add some basic formatting to our streams.
       SNPrintF(buf, "%5d", j);
-      os << "   " << buf.start() << ": " << *code.InstructionAt(j);
+      printable_instr.instr_ = code.InstructionAt(j);
+      os << "   " << buf.start() << ": " << printable_instr << "\n";
     }
 
-    os << "  " << block->control_;
-
-    if (block->control_input_ != NULL) {
-      os << " v" << block->control_input_->id();
-    }
-
-    BasicBlock::Successors successors = block->successors();
-    for (BasicBlock::Successors::iterator iter = successors.begin();
-         iter != successors.end(); ++iter) {
-      os << " B" << (*iter)->id();
+    for (auto succ : block->successors()) {
+      const InstructionBlock* succ_block = code.InstructionBlockAt(succ);
+      os << " B" << succ_block->id();
     }
     os << "\n";
   }
diff --git a/src/compiler/instruction.h b/src/compiler/instruction.h
index 6d00784..daa83f2 100644
--- a/src/compiler/instruction.h
+++ b/src/compiler/instruction.h
@@ -6,48 +6,39 @@
 #define V8_COMPILER_INSTRUCTION_H_
 
 #include <deque>
+#include <iosfwd>
 #include <map>
 #include <set>
 
 #include "src/compiler/common-operator.h"
 #include "src/compiler/frame.h"
-#include "src/compiler/graph.h"
 #include "src/compiler/instruction-codes.h"
 #include "src/compiler/opcodes.h"
+#include "src/compiler/register-configuration.h"
 #include "src/compiler/schedule.h"
-// TODO(titzer): don't include the macro-assembler?
-#include "src/macro-assembler.h"
+#include "src/compiler/source-position.h"
 #include "src/zone-allocator.h"
 
 namespace v8 {
 namespace internal {
-
-// Forward declarations.
-class OStream;
-
 namespace compiler {
 
-// Forward declarations.
-class Linkage;
-
 // A couple of reserved opcodes are used for internal use.
 const InstructionCode kGapInstruction = -1;
 const InstructionCode kBlockStartInstruction = -2;
 const InstructionCode kSourcePositionInstruction = -3;
 
-
-#define INSTRUCTION_OPERAND_LIST(V)              \
-  V(Constant, CONSTANT, 128)                     \
-  V(Immediate, IMMEDIATE, 128)                   \
-  V(StackSlot, STACK_SLOT, 128)                  \
-  V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128)     \
-  V(Register, REGISTER, Register::kNumRegisters) \
-  V(DoubleRegister, DOUBLE_REGISTER, DoubleRegister::kMaxNumRegisters)
+#define INSTRUCTION_OPERAND_LIST(V)                                  \
+  V(Constant, CONSTANT, 0)                                           \
+  V(Immediate, IMMEDIATE, 0)                                         \
+  V(StackSlot, STACK_SLOT, 128)                                      \
+  V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128)                         \
+  V(Register, REGISTER, RegisterConfiguration::kMaxGeneralRegisters) \
+  V(DoubleRegister, DOUBLE_REGISTER, RegisterConfiguration::kMaxDoubleRegisters)
 
 class InstructionOperand : public ZoneObject {
  public:
   enum Kind {
-    INVALID,
     UNALLOCATED,
     CONSTANT,
     IMMEDIATE,
@@ -57,7 +48,6 @@
     DOUBLE_REGISTER
   };
 
-  InstructionOperand() : value_(KindField::encode(INVALID)) {}
   InstructionOperand(Kind kind, int index) { ConvertTo(kind, index); }
 
   Kind kind() const { return KindField::decode(value_); }
@@ -66,16 +56,15 @@
   bool Is##name() const { return kind() == type; }
   INSTRUCTION_OPERAND_LIST(INSTRUCTION_OPERAND_PREDICATE)
   INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED, 0)
-  INSTRUCTION_OPERAND_PREDICATE(Ignored, INVALID, 0)
 #undef INSTRUCTION_OPERAND_PREDICATE
-  bool Equals(InstructionOperand* other) const {
+  bool Equals(const InstructionOperand* other) const {
     return value_ == other->value_;
   }
 
   void ConvertTo(Kind kind, int index) {
     if (kind == REGISTER || kind == DOUBLE_REGISTER) DCHECK(index >= 0);
     value_ = KindField::encode(kind);
-    value_ |= index << KindField::kSize;
+    value_ |= bit_cast<unsigned>(index << KindField::kSize);
     DCHECK(this->index() == index);
   }
 
@@ -84,14 +73,20 @@
   static void TearDownCaches();
 
  protected:
-  typedef BitField<Kind, 0, 3> KindField;
+  typedef BitField64<Kind, 0, 3> KindField;
 
-  unsigned value_;
+  uint64_t value_;
 };
 
 typedef ZoneVector<InstructionOperand*> InstructionOperandVector;
 
-OStream& operator<<(OStream& os, const InstructionOperand& op);
+struct PrintableInstructionOperand {
+  const RegisterConfiguration* register_configuration_;
+  const InstructionOperand* op_;
+};
+
+std::ostream& operator<<(std::ostream& os,
+                         const PrintableInstructionOperand& op);
 
 class UnallocatedOperand : public InstructionOperand {
  public:
@@ -122,6 +117,7 @@
 
   explicit UnallocatedOperand(ExtendedPolicy policy)
       : InstructionOperand(UNALLOCATED, 0) {
+    value_ |= VirtualRegisterField::encode(kInvalidVirtualRegister);
     value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
     value_ |= ExtendedPolicyField::encode(policy);
     value_ |= LifetimeField::encode(USED_AT_END);
@@ -130,14 +126,16 @@
   UnallocatedOperand(BasicPolicy policy, int index)
       : InstructionOperand(UNALLOCATED, 0) {
     DCHECK(policy == FIXED_SLOT);
+    value_ |= VirtualRegisterField::encode(kInvalidVirtualRegister);
     value_ |= BasicPolicyField::encode(policy);
-    value_ |= index << FixedSlotIndexField::kShift;
+    value_ |= static_cast<int64_t>(index) << FixedSlotIndexField::kShift;
     DCHECK(this->fixed_slot_index() == index);
   }
 
   UnallocatedOperand(ExtendedPolicy policy, int index)
       : InstructionOperand(UNALLOCATED, 0) {
     DCHECK(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER);
+    value_ |= VirtualRegisterField::encode(kInvalidVirtualRegister);
     value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
     value_ |= ExtendedPolicyField::encode(policy);
     value_ |= LifetimeField::encode(USED_AT_END);
@@ -146,6 +144,7 @@
 
   UnallocatedOperand(ExtendedPolicy policy, Lifetime lifetime)
       : InstructionOperand(UNALLOCATED, 0) {
+    value_ |= VirtualRegisterField::encode(kInvalidVirtualRegister);
     value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
     value_ |= ExtendedPolicyField::encode(policy);
     value_ |= LifetimeField::encode(lifetime);
@@ -183,24 +182,25 @@
   //     +------------------------------------------+    P ... Policy
   //
   // The slot index is a signed value which requires us to decode it manually
-  // instead of using the BitField utility class.
+  // instead of using the BitField64 utility class.
 
   // The superclass has a KindField.
   STATIC_ASSERT(KindField::kSize == 3);
 
   // BitFields for all unallocated operands.
-  class BasicPolicyField : public BitField<BasicPolicy, 3, 1> {};
-  class VirtualRegisterField : public BitField<unsigned, 4, 18> {};
+  class BasicPolicyField : public BitField64<BasicPolicy, 3, 1> {};
+  class VirtualRegisterField : public BitField64<unsigned, 4, 30> {};
 
   // BitFields specific to BasicPolicy::FIXED_SLOT.
-  class FixedSlotIndexField : public BitField<int, 22, 10> {};
+  class FixedSlotIndexField : public BitField64<int, 34, 30> {};
 
   // BitFields specific to BasicPolicy::EXTENDED_POLICY.
-  class ExtendedPolicyField : public BitField<ExtendedPolicy, 22, 3> {};
-  class LifetimeField : public BitField<Lifetime, 25, 1> {};
-  class FixedRegisterField : public BitField<int, 26, 6> {};
+  class ExtendedPolicyField : public BitField64<ExtendedPolicy, 34, 3> {};
+  class LifetimeField : public BitField64<Lifetime, 37, 1> {};
+  class FixedRegisterField : public BitField64<int, 38, 6> {};
 
-  static const int kMaxVirtualRegisters = VirtualRegisterField::kMax + 1;
+  static const int kInvalidVirtualRegister = VirtualRegisterField::kMax;
+  static const int kMaxVirtualRegisters = VirtualRegisterField::kMax;
   static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize;
   static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1;
   static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1));
@@ -244,7 +244,8 @@
   // [fixed_slot_index]: Only for FIXED_SLOT.
   int fixed_slot_index() const {
     DCHECK(HasFixedSlotPolicy());
-    return static_cast<int>(value_) >> FixedSlotIndexField::kShift;
+    return static_cast<int>(bit_cast<int64_t>(value_) >>
+                            FixedSlotIndexField::kShift);
   }
 
   // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER.
@@ -260,7 +261,7 @@
   }
 
   // [lifetime]: Only for non-FIXED_SLOT.
-  bool IsUsedAtStart() {
+  bool IsUsedAtStart() const {
     DCHECK(basic_policy() == EXTENDED_POLICY);
     return LifetimeField::decode(value_) == USED_AT_START;
   }
@@ -288,16 +289,12 @@
   }
 
   // A move is redundant if it's been eliminated, if its source and
-  // destination are the same, or if its destination is unneeded or constant.
+  // destination are the same, or if its destination is  constant.
   bool IsRedundant() const {
-    return IsEliminated() || source_->Equals(destination_) || IsIgnored() ||
+    return IsEliminated() || source_->Equals(destination_) ||
            (destination_ != NULL && destination_->IsConstant());
   }
 
-  bool IsIgnored() const {
-    return destination_ != NULL && destination_->IsIgnored();
-  }
-
   // We clear both operands to indicate move that's been eliminated.
   void Eliminate() { source_ = destination_ = NULL; }
   bool IsEliminated() const {
@@ -310,7 +307,15 @@
   InstructionOperand* destination_;
 };
 
-OStream& operator<<(OStream& os, const MoveOperands& mo);
+
+struct PrintableMoveOperands {
+  const RegisterConfiguration* register_configuration_;
+  const MoveOperands* move_operands_;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const PrintableMoveOperands& mo);
+
 
 template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands>
 class SubKindOperand FINAL : public InstructionOperand {
@@ -326,13 +331,18 @@
     return reinterpret_cast<SubKindOperand*>(op);
   }
 
+  static const SubKindOperand* cast(const InstructionOperand* op) {
+    DCHECK(op->kind() == kOperandKind);
+    return reinterpret_cast<const SubKindOperand*>(op);
+  }
+
   static void SetUpCache();
   static void TearDownCache();
 
  private:
   static SubKindOperand* cache;
 
-  SubKindOperand() : InstructionOperand() {}
+  SubKindOperand() : InstructionOperand(kOperandKind, 0) {}  // For the caches.
   explicit SubKindOperand(int index)
       : InstructionOperand(kOperandKind, index) {}
 };
@@ -363,7 +373,15 @@
   ZoneList<MoveOperands> move_operands_;
 };
 
-OStream& operator<<(OStream& os, const ParallelMove& pm);
+
+struct PrintableParallelMove {
+  const RegisterConfiguration* register_configuration_;
+  const ParallelMove* parallel_move_;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const PrintableParallelMove& pm);
+
 
 class PointerMap FINAL : public ZoneObject {
  public:
@@ -391,14 +409,14 @@
   void RecordUntagged(InstructionOperand* op, Zone* zone);
 
  private:
-  friend OStream& operator<<(OStream& os, const PointerMap& pm);
+  friend std::ostream& operator<<(std::ostream& os, const PointerMap& pm);
 
   ZoneList<InstructionOperand*> pointer_operands_;
   ZoneList<InstructionOperand*> untagged_operands_;
   int instruction_position_;
 };
 
-OStream& operator<<(OStream& os, const PointerMap& pm);
+std::ostream& operator<<(std::ostream& os, const PointerMap& pm);
 
 // TODO(titzer): s/PointerMap/ReferenceMap/
 class Instruction : public ZoneObject {
@@ -417,6 +435,10 @@
     DCHECK(i < InputCount());
     return operands_[OutputCount() + i];
   }
+  void SetInputAt(size_t i, InstructionOperand* operand) {
+    DCHECK(i < InputCount());
+    operands_[OutputCount() + i] = operand;
+  }
 
   size_t TempCount() const { return TempCountField::decode(bit_field_); }
   InstructionOperand* TempAt(size_t i) const {
@@ -496,6 +518,17 @@
 
   void operator delete(void* pointer, void* location) { UNREACHABLE(); }
 
+  void OverwriteWithNop() {
+    opcode_ = ArchOpcodeField::encode(kArchNop);
+    bit_field_ = 0;
+    pointer_map_ = NULL;
+  }
+
+  bool IsNop() const {
+    return arch_opcode() == kArchNop && InputCount() == 0 &&
+           OutputCount() == 0 && TempCount() == 0;
+  }
+
  protected:
   explicit Instruction(InstructionCode opcode)
       : opcode_(opcode),
@@ -538,7 +571,13 @@
   InstructionOperand* operands_[1];
 };
 
-OStream& operator<<(OStream& os, const Instruction& instr);
+
+struct PrintableInstruction {
+  const RegisterConfiguration* register_configuration_;
+  const Instruction* instr_;
+};
+std::ostream& operator<<(std::ostream& os, const PrintableInstruction& instr);
+
 
 // Represents moves inserted before an instruction due to register allocation.
 // TODO(titzer): squash GapInstruction back into Instruction, since essentially
@@ -565,6 +604,14 @@
     return parallel_moves_[pos];
   }
 
+  const ParallelMove* GetParallelMove(InnerPosition pos) const {
+    return parallel_moves_[pos];
+  }
+
+  bool IsRedundant() const;
+
+  ParallelMove** parallel_moves() { return parallel_moves_; }
+
   static GapInstruction* New(Zone* zone) {
     void* buffer = zone->New(sizeof(GapInstruction));
     return new (buffer) GapInstruction(kGapInstruction);
@@ -589,22 +636,19 @@
   }
 
  private:
-  friend OStream& operator<<(OStream& os, const Instruction& instr);
+  friend std::ostream& operator<<(std::ostream& os,
+                                  const PrintableInstruction& instr);
   ParallelMove* parallel_moves_[LAST_INNER_POSITION + 1];
 };
 
 
 // This special kind of gap move instruction represents the beginning of a
 // block of code.
-// TODO(titzer): move code_start and code_end from BasicBlock to here.
 class BlockStartInstruction FINAL : public GapInstruction {
  public:
-  BasicBlock* block() const { return block_; }
-  Label* label() { return &label_; }
-
-  static BlockStartInstruction* New(Zone* zone, BasicBlock* block) {
+  static BlockStartInstruction* New(Zone* zone) {
     void* buffer = zone->New(sizeof(BlockStartInstruction));
-    return new (buffer) BlockStartInstruction(block);
+    return new (buffer) BlockStartInstruction();
   }
 
   static BlockStartInstruction* cast(Instruction* instr) {
@@ -612,12 +656,13 @@
     return static_cast<BlockStartInstruction*>(instr);
   }
 
- private:
-  explicit BlockStartInstruction(BasicBlock* block)
-      : GapInstruction(kBlockStartInstruction), block_(block) {}
+  static const BlockStartInstruction* cast(const Instruction* instr) {
+    DCHECK(instr->IsBlockStart());
+    return static_cast<const BlockStartInstruction*>(instr);
+  }
 
-  BasicBlock* block_;
-  Label label_;
+ private:
+  BlockStartInstruction() : GapInstruction(kBlockStartInstruction) {}
 };
 
 
@@ -654,21 +699,34 @@
 
 class Constant FINAL {
  public:
-  enum Type { kInt32, kInt64, kFloat64, kExternalReference, kHeapObject };
+  enum Type {
+    kInt32,
+    kInt64,
+    kFloat32,
+    kFloat64,
+    kExternalReference,
+    kHeapObject,
+    kRpoNumber
+  };
 
   explicit Constant(int32_t v) : type_(kInt32), value_(v) {}
   explicit Constant(int64_t v) : type_(kInt64), value_(v) {}
+  explicit Constant(float v) : type_(kFloat32), value_(bit_cast<int32_t>(v)) {}
   explicit Constant(double v) : type_(kFloat64), value_(bit_cast<int64_t>(v)) {}
   explicit Constant(ExternalReference ref)
       : type_(kExternalReference), value_(bit_cast<intptr_t>(ref)) {}
   explicit Constant(Handle<HeapObject> obj)
       : type_(kHeapObject), value_(bit_cast<intptr_t>(obj)) {}
+  explicit Constant(BasicBlock::RpoNumber rpo)
+      : type_(kRpoNumber), value_(rpo.ToInt()) {}
 
   Type type() const { return type_; }
 
   int32_t ToInt32() const {
-    DCHECK_EQ(kInt32, type());
-    return static_cast<int32_t>(value_);
+    DCHECK(type() == kInt32 || type() == kInt64);
+    const int32_t value = static_cast<int32_t>(value_);
+    DCHECK_EQ(value_, static_cast<int64_t>(value));
+    return value;
   }
 
   int64_t ToInt64() const {
@@ -677,6 +735,11 @@
     return value_;
   }
 
+  float ToFloat32() const {
+    DCHECK_EQ(kFloat32, type());
+    return bit_cast<float>(static_cast<int32_t>(value_));
+  }
+
   double ToFloat64() const {
     if (type() == kInt32) return ToInt32();
     DCHECK_EQ(kFloat64, type());
@@ -688,6 +751,11 @@
     return bit_cast<ExternalReference>(static_cast<intptr_t>(value_));
   }
 
+  BasicBlock::RpoNumber ToRpoNumber() const {
+    DCHECK_EQ(kRpoNumber, type());
+    return BasicBlock::RpoNumber::FromInt(static_cast<int>(value_));
+  }
+
   Handle<HeapObject> ToHeapObject() const {
     DCHECK_EQ(kHeapObject, type());
     return bit_cast<Handle<HeapObject> >(static_cast<intptr_t>(value_));
@@ -701,18 +769,10 @@
 
 class FrameStateDescriptor : public ZoneObject {
  public:
-  FrameStateDescriptor(const FrameStateCallInfo& state_info,
+  FrameStateDescriptor(Zone* zone, const FrameStateCallInfo& state_info,
                        size_t parameters_count, size_t locals_count,
                        size_t stack_count,
-                       FrameStateDescriptor* outer_state = NULL)
-      : type_(state_info.type()),
-        bailout_id_(state_info.bailout_id()),
-        frame_state_combine_(state_info.state_combine()),
-        parameters_count_(parameters_count),
-        locals_count_(locals_count),
-        stack_count_(stack_count),
-        outer_state_(outer_state),
-        jsfunction_(state_info.jsfunction()) {}
+                       FrameStateDescriptor* outer_state = NULL);
 
   FrameStateType type() const { return type_; }
   BailoutId bailout_id() const { return bailout_id_; }
@@ -722,55 +782,17 @@
   size_t stack_count() const { return stack_count_; }
   FrameStateDescriptor* outer_state() const { return outer_state_; }
   MaybeHandle<JSFunction> jsfunction() const { return jsfunction_; }
-
-  size_t size() const {
-    return parameters_count_ + locals_count_ + stack_count_ +
-           (HasContext() ? 1 : 0);
-  }
-
-  size_t GetTotalSize() const {
-    size_t total_size = 0;
-    for (const FrameStateDescriptor* iter = this; iter != NULL;
-         iter = iter->outer_state_) {
-      total_size += iter->size();
-    }
-    return total_size;
-  }
-
-  size_t GetHeight(OutputFrameStateCombine override) const {
-    size_t height = size() - parameters_count();
-    switch (override) {
-      case kPushOutput:
-        ++height;
-        break;
-      case kIgnoreOutput:
-        break;
-    }
-    return height;
-  }
-
-  size_t GetFrameCount() const {
-    size_t count = 0;
-    for (const FrameStateDescriptor* iter = this; iter != NULL;
-         iter = iter->outer_state_) {
-      ++count;
-    }
-    return count;
-  }
-
-  size_t GetJSFrameCount() const {
-    size_t count = 0;
-    for (const FrameStateDescriptor* iter = this; iter != NULL;
-         iter = iter->outer_state_) {
-      if (iter->type_ == JS_FRAME) {
-        ++count;
-      }
-    }
-    return count;
-  }
-
   bool HasContext() const { return type_ == JS_FRAME; }
 
+  size_t GetSize(OutputFrameStateCombine combine =
+                     OutputFrameStateCombine::Ignore()) const;
+  size_t GetTotalSize() const;
+  size_t GetFrameCount() const;
+  size_t GetJSFrameCount() const;
+
+  MachineType GetType(size_t index) const;
+  void SetType(size_t index, MachineType type);
+
  private:
   FrameStateType type_;
   BailoutId bailout_id_;
@@ -778,11 +800,128 @@
   size_t parameters_count_;
   size_t locals_count_;
   size_t stack_count_;
+  ZoneVector<MachineType> types_;
   FrameStateDescriptor* outer_state_;
   MaybeHandle<JSFunction> jsfunction_;
 };
 
-OStream& operator<<(OStream& os, const Constant& constant);
+std::ostream& operator<<(std::ostream& os, const Constant& constant);
+
+
+class PhiInstruction FINAL : public ZoneObject {
+ public:
+  typedef ZoneVector<InstructionOperand*> Inputs;
+
+  PhiInstruction(Zone* zone, int virtual_register, size_t reserved_input_count)
+      : virtual_register_(virtual_register),
+        operands_(zone),
+        output_(nullptr),
+        inputs_(zone) {
+    UnallocatedOperand* output =
+        new (zone) UnallocatedOperand(UnallocatedOperand::NONE);
+    output->set_virtual_register(virtual_register);
+    output_ = output;
+    inputs_.reserve(reserved_input_count);
+    operands_.reserve(reserved_input_count);
+  }
+
+  int virtual_register() const { return virtual_register_; }
+  const IntVector& operands() const { return operands_; }
+
+  void Extend(Zone* zone, int virtual_register) {
+    UnallocatedOperand* input =
+        new (zone) UnallocatedOperand(UnallocatedOperand::ANY);
+    input->set_virtual_register(virtual_register);
+    operands_.push_back(virtual_register);
+    inputs_.push_back(input);
+  }
+
+  InstructionOperand* output() const { return output_; }
+  const Inputs& inputs() const { return inputs_; }
+  Inputs& inputs() { return inputs_; }
+
+ private:
+  // TODO(dcarney): some of these fields are only for verification, move them to
+  // verifier.
+  const int virtual_register_;
+  IntVector operands_;
+  InstructionOperand* output_;
+  Inputs inputs_;
+};
+
+
+// Analogue of BasicBlock for Instructions instead of Nodes.
+class InstructionBlock FINAL : public ZoneObject {
+ public:
+  InstructionBlock(Zone* zone, BasicBlock::Id id,
+                   BasicBlock::RpoNumber rpo_number,
+                   BasicBlock::RpoNumber loop_header,
+                   BasicBlock::RpoNumber loop_end, bool deferred);
+
+  // Instruction indexes (used by the register allocator).
+  int first_instruction_index() const {
+    DCHECK(code_start_ >= 0);
+    DCHECK(code_end_ > 0);
+    DCHECK(code_end_ >= code_start_);
+    return code_start_;
+  }
+  int last_instruction_index() const {
+    DCHECK(code_start_ >= 0);
+    DCHECK(code_end_ > 0);
+    DCHECK(code_end_ >= code_start_);
+    return code_end_ - 1;
+  }
+
+  int32_t code_start() const { return code_start_; }
+  void set_code_start(int32_t start) { code_start_ = start; }
+
+  int32_t code_end() const { return code_end_; }
+  void set_code_end(int32_t end) { code_end_ = end; }
+
+  bool IsDeferred() const { return deferred_; }
+
+  BasicBlock::Id id() const { return id_; }
+  BasicBlock::RpoNumber ao_number() const { return ao_number_; }
+  BasicBlock::RpoNumber rpo_number() const { return rpo_number_; }
+  BasicBlock::RpoNumber loop_header() const { return loop_header_; }
+  BasicBlock::RpoNumber loop_end() const {
+    DCHECK(IsLoopHeader());
+    return loop_end_;
+  }
+  inline bool IsLoopHeader() const { return loop_end_.IsValid(); }
+
+  typedef ZoneVector<BasicBlock::RpoNumber> Predecessors;
+  Predecessors& predecessors() { return predecessors_; }
+  const Predecessors& predecessors() const { return predecessors_; }
+  size_t PredecessorCount() const { return predecessors_.size(); }
+  size_t PredecessorIndexOf(BasicBlock::RpoNumber rpo_number) const;
+
+  typedef ZoneVector<BasicBlock::RpoNumber> Successors;
+  Successors& successors() { return successors_; }
+  const Successors& successors() const { return successors_; }
+  size_t SuccessorCount() const { return successors_.size(); }
+
+  typedef ZoneVector<PhiInstruction*> PhiInstructions;
+  const PhiInstructions& phis() const { return phis_; }
+  void AddPhi(PhiInstruction* phi) { phis_.push_back(phi); }
+
+  void set_ao_number(BasicBlock::RpoNumber ao_number) {
+    ao_number_ = ao_number;
+  }
+
+ private:
+  Successors successors_;
+  Predecessors predecessors_;
+  PhiInstructions phis_;
+  const BasicBlock::Id id_;
+  BasicBlock::RpoNumber ao_number_;  // Assembly order number.
+  const BasicBlock::RpoNumber rpo_number_;
+  const BasicBlock::RpoNumber loop_header_;
+  const BasicBlock::RpoNumber loop_end_;
+  int32_t code_start_;   // start index of arch-specific code.
+  int32_t code_end_;     // end index of arch-specific code.
+  const bool deferred_;  // Block contains deferred code.
+};
 
 typedef ZoneDeque<Constant> ConstantDeque;
 typedef std::map<int, Constant, std::less<int>,
@@ -791,49 +930,49 @@
 typedef ZoneDeque<Instruction*> InstructionDeque;
 typedef ZoneDeque<PointerMap*> PointerMapDeque;
 typedef ZoneVector<FrameStateDescriptor*> DeoptimizationVector;
+typedef ZoneVector<InstructionBlock*> InstructionBlocks;
+
+struct PrintableInstructionSequence;
+
 
 // Represents architecture-specific generated code before, during, and after
 // register allocation.
 // TODO(titzer): s/IsDouble/IsFloat64/
-class InstructionSequence FINAL {
+class InstructionSequence FINAL : public ZoneObject {
  public:
-  InstructionSequence(Linkage* linkage, Graph* graph, Schedule* schedule)
-      : graph_(graph),
-        linkage_(linkage),
-        schedule_(schedule),
-        constants_(ConstantMap::key_compare(),
-                   ConstantMap::allocator_type(zone())),
-        immediates_(zone()),
-        instructions_(zone()),
-        next_virtual_register_(graph->NodeCount()),
-        pointer_maps_(zone()),
-        doubles_(std::less<int>(), VirtualRegisterSet::allocator_type(zone())),
-        references_(std::less<int>(),
-                    VirtualRegisterSet::allocator_type(zone())),
-        deoptimization_entries_(zone()) {}
+  static InstructionBlocks* InstructionBlocksFor(Zone* zone,
+                                                 const Schedule* schedule);
+  // Puts the deferred blocks last.
+  static void ComputeAssemblyOrder(InstructionBlocks* blocks);
+
+  InstructionSequence(Zone* zone, InstructionBlocks* instruction_blocks);
 
   int NextVirtualRegister() { return next_virtual_register_++; }
   int VirtualRegisterCount() const { return next_virtual_register_; }
 
-  int ValueCount() const { return graph_->NodeCount(); }
-
-  int BasicBlockCount() const {
-    return static_cast<int>(schedule_->rpo_order()->size());
+  const InstructionBlocks& instruction_blocks() const {
+    return *instruction_blocks_;
   }
 
-  BasicBlock* BlockAt(int rpo_number) const {
-    return (*schedule_->rpo_order())[rpo_number];
+  int InstructionBlockCount() const {
+    return static_cast<int>(instruction_blocks_->size());
   }
 
-  BasicBlock* GetContainingLoop(BasicBlock* block) {
-    return block->loop_header_;
+  InstructionBlock* InstructionBlockAt(BasicBlock::RpoNumber rpo_number) {
+    return instruction_blocks_->at(rpo_number.ToSize());
   }
 
-  int GetLoopEnd(BasicBlock* block) const { return block->loop_end_; }
+  int LastLoopInstructionIndex(const InstructionBlock* block) {
+    return instruction_blocks_->at(block->loop_end().ToSize() - 1)
+        ->last_instruction_index();
+  }
 
-  BasicBlock* GetBasicBlock(int instruction_index);
+  const InstructionBlock* InstructionBlockAt(
+      BasicBlock::RpoNumber rpo_number) const {
+    return instruction_blocks_->at(rpo_number.ToSize());
+  }
 
-  int GetVirtualRegister(Node* node) const { return node->id(); }
+  const InstructionBlock* GetInstructionBlock(int instruction_index) const;
 
   bool IsReference(int virtual_register) const;
   bool IsDouble(int virtual_register) const;
@@ -843,12 +982,12 @@
 
   void AddGapMove(int index, InstructionOperand* from, InstructionOperand* to);
 
-  Label* GetLabel(BasicBlock* block);
-  BlockStartInstruction* GetBlockStart(BasicBlock* block);
+  BlockStartInstruction* GetBlockStart(BasicBlock::RpoNumber rpo) const;
 
   typedef InstructionDeque::const_iterator const_iterator;
   const_iterator begin() const { return instructions_.begin(); }
   const_iterator end() const { return instructions_.end(); }
+  const InstructionDeque& instructions() const { return instructions_; }
 
   GapInstruction* GapAt(int index) const {
     return GapInstruction::cast(InstructionAt(index));
@@ -860,22 +999,22 @@
     return instructions_[index];
   }
 
-  Frame* frame() { return &frame_; }
-  Graph* graph() const { return graph_; }
   Isolate* isolate() const { return zone()->isolate(); }
-  Linkage* linkage() const { return linkage_; }
-  Schedule* schedule() const { return schedule_; }
   const PointerMapDeque* pointer_maps() const { return &pointer_maps_; }
-  Zone* zone() const { return graph_->zone(); }
+  Zone* zone() const { return zone_; }
 
-  // Used by the code generator while adding instructions.
-  int AddInstruction(Instruction* instr, BasicBlock* block);
-  void StartBlock(BasicBlock* block);
-  void EndBlock(BasicBlock* block);
+  // Used by the instruction selector while adding instructions.
+  int AddInstruction(Instruction* instr);
+  void StartBlock(BasicBlock::RpoNumber rpo);
+  void EndBlock(BasicBlock::RpoNumber rpo);
 
-  void AddConstant(int virtual_register, Constant constant) {
+  int AddConstant(int virtual_register, Constant constant) {
+    // TODO(titzer): allow RPO numbers as constants?
+    DCHECK(constant.type() != Constant::kRpoNumber);
+    DCHECK(virtual_register >= 0 && virtual_register < next_virtual_register_);
     DCHECK(constants_.find(virtual_register) == constants_.end());
     constants_.insert(std::make_pair(virtual_register, constant));
+    return virtual_register;
   }
   Constant GetConstant(int virtual_register) const {
     ConstantMap::const_iterator it = constants_.find(virtual_register);
@@ -884,8 +1023,8 @@
     return it->second;
   }
 
-  typedef ConstantDeque Immediates;
-  const Immediates& immediates() const { return immediates_; }
+  typedef ZoneVector<Constant> Immediates;
+  Immediates& immediates() { return immediates_; }
 
   int AddImmediate(Constant constant) {
     int index = static_cast<int>(immediates_.size());
@@ -912,26 +1051,43 @@
   FrameStateDescriptor* GetFrameStateDescriptor(StateId deoptimization_id);
   int GetFrameStateDescriptorCount();
 
+  BasicBlock::RpoNumber InputRpo(Instruction* instr, size_t index) {
+    InstructionOperand* operand = instr->InputAt(index);
+    Constant constant = operand->IsImmediate() ? GetImmediate(operand->index())
+                                               : GetConstant(operand->index());
+    return constant.ToRpoNumber();
+  }
+
  private:
-  friend OStream& operator<<(OStream& os, const InstructionSequence& code);
+  friend std::ostream& operator<<(std::ostream& os,
+                                  const PrintableInstructionSequence& code);
 
   typedef std::set<int, std::less<int>, ZoneIntAllocator> VirtualRegisterSet;
 
-  Graph* graph_;
-  Linkage* linkage_;
-  Schedule* schedule_;
+  Zone* const zone_;
+  InstructionBlocks* const instruction_blocks_;
+  IntVector block_starts_;
   ConstantMap constants_;
-  ConstantDeque immediates_;
+  Immediates immediates_;
   InstructionDeque instructions_;
   int next_virtual_register_;
   PointerMapDeque pointer_maps_;
   VirtualRegisterSet doubles_;
   VirtualRegisterSet references_;
-  Frame frame_;
   DeoptimizationVector deoptimization_entries_;
+
+  DISALLOW_COPY_AND_ASSIGN(InstructionSequence);
 };
 
-OStream& operator<<(OStream& os, const InstructionSequence& code);
+
+struct PrintableInstructionSequence {
+  const RegisterConfiguration* register_configuration_;
+  const InstructionSequence* sequence_;
+};
+
+
+std::ostream& operator<<(std::ostream& os,
+                         const PrintableInstructionSequence& code);
 
 }  // namespace compiler
 }  // namespace internal
diff --git a/src/compiler/js-builtin-reducer-unittest.cc b/src/compiler/js-builtin-reducer-unittest.cc
deleted file mode 100644
index 51561d0..0000000
--- a/src/compiler/js-builtin-reducer-unittest.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/graph-unittest.h"
-#include "src/compiler/js-builtin-reducer.h"
-#include "src/compiler/js-graph.h"
-#include "src/compiler/node-properties-inl.h"
-#include "src/compiler/typer.h"
-#include "testing/gmock-support.h"
-
-using testing::Capture;
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-class JSBuiltinReducerTest : public GraphTest {
- public:
-  JSBuiltinReducerTest() : javascript_(zone()) {}
-
- protected:
-  Reduction Reduce(Node* node) {
-    Typer typer(zone());
-    MachineOperatorBuilder machine;
-    JSGraph jsgraph(graph(), common(), javascript(), &typer, &machine);
-    JSBuiltinReducer reducer(&jsgraph);
-    return reducer.Reduce(node);
-  }
-
-  Node* Parameter(Type* t, int32_t index = 0) {
-    Node* n = graph()->NewNode(common()->Parameter(index), graph()->start());
-    NodeProperties::SetBounds(n, Bounds(Type::None(), t));
-    return n;
-  }
-
-  Node* UndefinedConstant() {
-    return HeapConstant(
-        Unique<HeapObject>::CreateImmovable(factory()->undefined_value()));
-  }
-
-  JSOperatorBuilder* javascript() { return &javascript_; }
-
- private:
-  JSOperatorBuilder javascript_;
-};
-
-
-namespace {
-
-// TODO(mstarzinger): Find a common place and unify with test-js-typed-lowering.
-Type* const kNumberTypes[] = {
-    Type::UnsignedSmall(),   Type::OtherSignedSmall(), Type::OtherUnsigned31(),
-    Type::OtherUnsigned32(), Type::OtherSigned32(),    Type::SignedSmall(),
-    Type::Signed32(),        Type::Unsigned32(),       Type::Integral32(),
-    Type::MinusZero(),       Type::NaN(),              Type::OtherNumber(),
-    Type::OrderedNumber(),   Type::Number()};
-
-}  // namespace
-
-
-// -----------------------------------------------------------------------------
-// Math.sqrt
-
-
-TEST_F(JSBuiltinReducerTest, MathSqrt) {
-  Handle<JSFunction> f(isolate()->context()->math_sqrt_fun());
-
-  TRACED_FOREACH(Type*, t0, kNumberTypes) {
-    Node* p0 = Parameter(t0, 0);
-    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
-    Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS),
-                                  fun, UndefinedConstant(), p0);
-    Reduction r = Reduce(call);
-
-    ASSERT_TRUE(r.Changed());
-    EXPECT_THAT(r.replacement(), IsFloat64Sqrt(p0));
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// Math.max
-
-
-TEST_F(JSBuiltinReducerTest, MathMax0) {
-  Handle<JSFunction> f(isolate()->context()->math_max_fun());
-
-  Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
-  Node* call = graph()->NewNode(javascript()->Call(2, NO_CALL_FUNCTION_FLAGS),
-                                fun, UndefinedConstant());
-  Reduction r = Reduce(call);
-
-  ASSERT_TRUE(r.Changed());
-  EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY));
-}
-
-
-TEST_F(JSBuiltinReducerTest, MathMax1) {
-  Handle<JSFunction> f(isolate()->context()->math_max_fun());
-
-  TRACED_FOREACH(Type*, t0, kNumberTypes) {
-    Node* p0 = Parameter(t0, 0);
-    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
-    Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS),
-                                  fun, UndefinedConstant(), p0);
-    Reduction r = Reduce(call);
-
-    ASSERT_TRUE(r.Changed());
-    EXPECT_THAT(r.replacement(), p0);
-  }
-}
-
-
-TEST_F(JSBuiltinReducerTest, MathMax2) {
-  Handle<JSFunction> f(isolate()->context()->math_max_fun());
-
-  TRACED_FOREACH(Type*, t0, kNumberTypes) {
-    TRACED_FOREACH(Type*, t1, kNumberTypes) {
-      Node* p0 = Parameter(t0, 0);
-      Node* p1 = Parameter(t1, 1);
-      Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
-      Node* call =
-          graph()->NewNode(javascript()->Call(4, NO_CALL_FUNCTION_FLAGS), fun,
-                           UndefinedConstant(), p0, p1);
-      Reduction r = Reduce(call);
-
-      if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
-        Capture<Node*> branch;
-        ASSERT_TRUE(r.Changed());
-        EXPECT_THAT(
-            r.replacement(),
-            IsPhi(kMachNone, p1, p0,
-                  IsMerge(IsIfTrue(CaptureEq(&branch)),
-                          IsIfFalse(AllOf(CaptureEq(&branch),
-                                          IsBranch(IsNumberLessThan(p0, p1),
-                                                   graph()->start()))))));
-      } else {
-        ASSERT_FALSE(r.Changed());
-        EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
-      }
-    }
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// Math.imul
-
-
-TEST_F(JSBuiltinReducerTest, MathImul) {
-  Handle<JSFunction> f(isolate()->context()->math_imul_fun());
-
-  TRACED_FOREACH(Type*, t0, kNumberTypes) {
-    TRACED_FOREACH(Type*, t1, kNumberTypes) {
-      Node* p0 = Parameter(t0, 0);
-      Node* p1 = Parameter(t1, 1);
-      Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
-      Node* call =
-          graph()->NewNode(javascript()->Call(4, NO_CALL_FUNCTION_FLAGS), fun,
-                           UndefinedConstant(), p0, p1);
-      Reduction r = Reduce(call);
-
-      if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
-        ASSERT_TRUE(r.Changed());
-        EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1));
-      } else {
-        ASSERT_FALSE(r.Changed());
-        EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
-      }
-    }
-  }
-}
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc
index c57ac33..263b0fe 100644
--- a/src/compiler/js-builtin-reducer.cc
+++ b/src/compiler/js-builtin-reducer.cc
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "src/compiler/diamond.h"
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/js-builtin-reducer.h"
+#include "src/compiler/js-graph.h"
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/types.h"
@@ -80,7 +82,7 @@
   int GetJSCallArity() {
     DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode());
     // Skip first (i.e. callee) and second (i.e. receiver) operand.
-    return OperatorProperties::GetValueInputCount(node_->op()) - 2;
+    return node_->op()->ValueInputCount() - 2;
   }
 
   Node* GetJSCallInput(int index) {
@@ -95,6 +97,30 @@
 };
 
 
+JSBuiltinReducer::JSBuiltinReducer(JSGraph* jsgraph)
+    : jsgraph_(jsgraph), simplified_(jsgraph->zone()) {}
+
+
+// ECMA-262, section 15.8.2.1.
+Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) {
+  JSCallReduction r(node);
+  if (r.InputsMatchOne(Type::Unsigned32())) {
+    // Math.abs(a:uint32) -> a
+    return Replace(r.left());
+  }
+  if (r.InputsMatchOne(Type::Number())) {
+    // Math.abs(a:number) -> (a > 0 ? a : 0 - a)
+    Node* const value = r.left();
+    Node* const zero = jsgraph()->ZeroConstant();
+    return Replace(graph()->NewNode(
+        common()->Select(kMachNone),
+        graph()->NewNode(simplified()->NumberLessThan(), zero, value), value,
+        graph()->NewNode(simplified()->NumberSubtract(), zero, value)));
+  }
+  return NoChange();
+}
+
+
 // ECMA-262, section 15.8.2.17.
 Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) {
   JSCallReduction r(node);
@@ -122,16 +148,11 @@
     // Math.max(a:int32, b:int32, ...)
     Node* value = r.GetJSCallInput(0);
     for (int i = 1; i < r.GetJSCallArity(); i++) {
-      Node* p = r.GetJSCallInput(i);
-      Node* control = graph()->start();
-      Node* tag = graph()->NewNode(simplified()->NumberLessThan(), value, p);
-
-      Node* branch = graph()->NewNode(common()->Branch(), tag, control);
-      Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-      Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
-      Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-
-      value = graph()->NewNode(common()->Phi(kMachNone, 2), p, value, merge);
+      Node* const input = r.GetJSCallInput(i);
+      value = graph()->NewNode(
+          common()->Select(kMachNone),
+          graph()->NewNode(simplified()->NumberLessThan(), input, value), input,
+          value);
     }
     return Replace(value);
   }
@@ -151,24 +172,84 @@
 }
 
 
+// ES6 draft 08-24-14, section 20.2.2.17.
+Reduction JSBuiltinReducer::ReduceMathFround(Node* node) {
+  JSCallReduction r(node);
+  if (r.InputsMatchOne(Type::Number())) {
+    // Math.fround(a:number) -> TruncateFloat64ToFloat32(a)
+    Node* value =
+        graph()->NewNode(machine()->TruncateFloat64ToFloat32(), r.left());
+    return Replace(value);
+  }
+  return NoChange();
+}
+
+
+// ES6 draft 10-14-14, section 20.2.2.16.
+Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) {
+  if (!machine()->HasFloat64Floor()) return NoChange();
+  JSCallReduction r(node);
+  if (r.InputsMatchOne(Type::Number())) {
+    // Math.floor(a:number) -> Float64Floor(a)
+    Node* value = graph()->NewNode(machine()->Float64Floor(), r.left());
+    return Replace(value);
+  }
+  return NoChange();
+}
+
+
+// ES6 draft 10-14-14, section 20.2.2.10.
+Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) {
+  if (!machine()->HasFloat64Ceil()) return NoChange();
+  JSCallReduction r(node);
+  if (r.InputsMatchOne(Type::Number())) {
+    // Math.ceil(a:number) -> Float64Ceil(a)
+    Node* value = graph()->NewNode(machine()->Float64Ceil(), r.left());
+    return Replace(value);
+  }
+  return NoChange();
+}
+
+
 Reduction JSBuiltinReducer::Reduce(Node* node) {
   JSCallReduction r(node);
 
   // Dispatch according to the BuiltinFunctionId if present.
   if (!r.HasBuiltinFunctionId()) return NoChange();
   switch (r.GetBuiltinFunctionId()) {
+    case kMathAbs:
+      return ReplaceWithPureReduction(node, ReduceMathAbs(node));
     case kMathSqrt:
       return ReplaceWithPureReduction(node, ReduceMathSqrt(node));
     case kMathMax:
       return ReplaceWithPureReduction(node, ReduceMathMax(node));
     case kMathImul:
       return ReplaceWithPureReduction(node, ReduceMathImul(node));
+    case kMathFround:
+      return ReplaceWithPureReduction(node, ReduceMathFround(node));
+    case kMathFloor:
+      return ReplaceWithPureReduction(node, ReduceMathFloor(node));
+    case kMathCeil:
+      return ReplaceWithPureReduction(node, ReduceMathCeil(node));
     default:
       break;
   }
   return NoChange();
 }
 
+
+Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); }
+
+
+CommonOperatorBuilder* JSBuiltinReducer::common() const {
+  return jsgraph()->common();
+}
+
+
+MachineOperatorBuilder* JSBuiltinReducer::machine() const {
+  return jsgraph()->machine();
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
diff --git a/src/compiler/js-builtin-reducer.h b/src/compiler/js-builtin-reducer.h
index 13927f6..ac6f266 100644
--- a/src/compiler/js-builtin-reducer.h
+++ b/src/compiler/js-builtin-reducer.h
@@ -6,33 +6,39 @@
 #define V8_COMPILER_JS_BUILTIN_REDUCER_H_
 
 #include "src/compiler/graph-reducer.h"
-#include "src/compiler/js-graph.h"
-#include "src/compiler/machine-operator.h"
-#include "src/compiler/node.h"
 #include "src/compiler/simplified-operator.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
+// Forward declarations.
+class CommonOperatorBuilder;
+class JSGraph;
+class MachineOperatorBuilder;
+
+
 class JSBuiltinReducer FINAL : public Reducer {
  public:
-  explicit JSBuiltinReducer(JSGraph* jsgraph)
-      : jsgraph_(jsgraph), simplified_(jsgraph->zone()) {}
-  virtual ~JSBuiltinReducer() {}
+  explicit JSBuiltinReducer(JSGraph* jsgraph);
+  ~JSBuiltinReducer() FINAL {}
 
-  virtual Reduction Reduce(Node* node) OVERRIDE;
+  Reduction Reduce(Node* node) FINAL;
 
  private:
-  JSGraph* jsgraph() const { return jsgraph_; }
-  Graph* graph() const { return jsgraph_->graph(); }
-  CommonOperatorBuilder* common() const { return jsgraph_->common(); }
-  MachineOperatorBuilder* machine() const { return jsgraph_->machine(); }
-  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
-
+  Reduction ReduceMathAbs(Node* node);
   Reduction ReduceMathSqrt(Node* node);
   Reduction ReduceMathMax(Node* node);
   Reduction ReduceMathImul(Node* node);
+  Reduction ReduceMathFround(Node* node);
+  Reduction ReduceMathFloor(Node* node);
+  Reduction ReduceMathCeil(Node* node);
+
+  JSGraph* jsgraph() const { return jsgraph_; }
+  Graph* graph() const;
+  CommonOperatorBuilder* common() const;
+  MachineOperatorBuilder* machine() const;
+  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
 
   JSGraph* jsgraph_;
   SimplifiedOperatorBuilder simplified_;
diff --git a/src/compiler/js-context-specialization.cc b/src/compiler/js-context-specialization.cc
index cd8932b..a700b47 100644
--- a/src/compiler/js-context-specialization.cc
+++ b/src/compiler/js-context-specialization.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node-inl.h"
-#include "src/compiler/graph-inl.h"
 #include "src/compiler/js-context-specialization.h"
+
+#include "src/compiler.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph-inl.h"
 #include "src/compiler/js-operator.h"
-#include "src/compiler/node-aux-data-inl.h"
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties-inl.h"
 
@@ -15,46 +15,19 @@
 namespace internal {
 namespace compiler {
 
-class ContextSpecializationVisitor : public NullNodeVisitor {
- public:
-  explicit ContextSpecializationVisitor(JSContextSpecializer* spec)
-      : spec_(spec) {}
-
-  GenericGraphVisit::Control Post(Node* node) {
-    switch (node->opcode()) {
-      case IrOpcode::kJSLoadContext: {
-        Reduction r = spec_->ReduceJSLoadContext(node);
-        if (r.Changed() && r.replacement() != node) {
-          NodeProperties::ReplaceWithValue(node, r.replacement());
-          node->RemoveAllInputs();
-        }
-        break;
-      }
-      case IrOpcode::kJSStoreContext: {
-        Reduction r = spec_->ReduceJSStoreContext(node);
-        if (r.Changed() && r.replacement() != node) {
-          NodeProperties::ReplaceWithValue(node, r.replacement());
-          node->RemoveAllInputs();
-        }
-        break;
-      }
-      default:
-        break;
-    }
-    return GenericGraphVisit::CONTINUE;
+Reduction JSContextSpecializer::Reduce(Node* node) {
+  if (node == context_) {
+    Node* constant = jsgraph_->Constant(info_->context());
+    NodeProperties::ReplaceWithValue(node, constant);
+    return Replace(constant);
   }
-
- private:
-  JSContextSpecializer* spec_;
-};
-
-
-void JSContextSpecializer::SpecializeToContext() {
-  NodeProperties::ReplaceWithValue(context_,
-                                   jsgraph_->Constant(info_->context()));
-
-  ContextSpecializationVisitor visitor(this);
-  jsgraph_->graph()->VisitNodeInputsFromEnd(&visitor);
+  if (node->opcode() == IrOpcode::kJSLoadContext) {
+    return ReduceJSLoadContext(node);
+  }
+  if (node->opcode() == IrOpcode::kJSStoreContext) {
+    return ReduceJSStoreContext(node);
+  }
+  return NoChange();
 }
 
 
@@ -64,14 +37,14 @@
   HeapObjectMatcher<Context> m(NodeProperties::GetValueInput(node, 0));
   // If the context is not constant, no reduction can occur.
   if (!m.HasValue()) {
-    return Reducer::NoChange();
+    return NoChange();
   }
 
-  ContextAccess access = OpParameter<ContextAccess>(node);
+  const ContextAccess& access = ContextAccessOf(node->op());
 
   // Find the right parent context.
   Context* context = *m.Value().handle();
-  for (int i = access.depth(); i > 0; --i) {
+  for (size_t i = access.depth(); i > 0; --i) {
     context = context->previous();
   }
 
@@ -79,30 +52,32 @@
   if (!access.immutable()) {
     // The access does not have to look up a parent, nothing to fold.
     if (access.depth() == 0) {
-      return Reducer::NoChange();
+      return NoChange();
     }
     const Operator* op = jsgraph_->javascript()->LoadContext(
         0, access.index(), access.immutable());
     node->set_op(op);
     Handle<Object> context_handle = Handle<Object>(context, info_->isolate());
     node->ReplaceInput(0, jsgraph_->Constant(context_handle));
-    return Reducer::Changed(node);
+    return Changed(node);
   }
-  Handle<Object> value =
-      Handle<Object>(context->get(access.index()), info_->isolate());
+  Handle<Object> value = Handle<Object>(
+      context->get(static_cast<int>(access.index())), info_->isolate());
 
   // Even though the context slot is immutable, the context might have escaped
   // before the function to which it belongs has initialized the slot.
   // We must be conservative and check if the value in the slot is currently the
   // hole or undefined. If it is neither of these, then it must be initialized.
   if (value->IsUndefined() || value->IsTheHole()) {
-    return Reducer::NoChange();
+    return NoChange();
   }
 
   // Success. The context load can be replaced with the constant.
   // TODO(titzer): record the specialization for sharing code across multiple
   // contexts that have the same value in the corresponding context slot.
-  return Reducer::Replace(jsgraph_->Constant(value));
+  Node* constant = jsgraph_->Constant(value);
+  NodeProperties::ReplaceWithValue(node, constant);
+  return Replace(constant);
 }
 
 
@@ -112,19 +87,19 @@
   HeapObjectMatcher<Context> m(NodeProperties::GetValueInput(node, 0));
   // If the context is not constant, no reduction can occur.
   if (!m.HasValue()) {
-    return Reducer::NoChange();
+    return NoChange();
   }
 
-  ContextAccess access = OpParameter<ContextAccess>(node);
+  const ContextAccess& access = ContextAccessOf(node->op());
 
   // The access does not have to look up a parent, nothing to fold.
   if (access.depth() == 0) {
-    return Reducer::NoChange();
+    return NoChange();
   }
 
   // Find the right parent context.
   Context* context = *m.Value().handle();
-  for (int i = access.depth(); i > 0; --i) {
+  for (size_t i = access.depth(); i > 0; --i) {
     context = context->previous();
   }
 
@@ -133,7 +108,7 @@
   Handle<Object> new_context_handle = Handle<Object>(context, info_->isolate());
   node->ReplaceInput(0, jsgraph_->Constant(new_context_handle));
 
-  return Reducer::Changed(node);
+  return Changed(node);
 }
 
 }  // namespace compiler
diff --git a/src/compiler/js-context-specialization.h b/src/compiler/js-context-specialization.h
index b8b50ed..298d3a3 100644
--- a/src/compiler/js-context-specialization.h
+++ b/src/compiler/js-context-specialization.h
@@ -16,12 +16,14 @@
 
 // Specializes a given JSGraph to a given context, potentially constant folding
 // some {LoadContext} nodes or strength reducing some {StoreContext} nodes.
-class JSContextSpecializer {
+class JSContextSpecializer : public Reducer {
  public:
   JSContextSpecializer(CompilationInfo* info, JSGraph* jsgraph, Node* context)
       : info_(info), jsgraph_(jsgraph), context_(context) {}
 
-  void SpecializeToContext();
+  Reduction Reduce(Node* node) OVERRIDE;
+
+  // Visible for unit testing.
   Reduction ReduceJSLoadContext(Node* node);
   Reduction ReduceJSStoreContext(Node* node);
 
diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc
index 300604e..4886442 100644
--- a/src/compiler/js-generic-lowering.cc
+++ b/src/compiler/js-generic-lowering.cc
@@ -9,6 +9,7 @@
 #include "src/compiler/js-generic-lowering.h"
 #include "src/compiler/machine-operator.h"
 #include "src/compiler/node-aux-data-inl.h"
+#include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/unique.h"
 
@@ -19,7 +20,7 @@
 JSGenericLowering::JSGenericLowering(CompilationInfo* info, JSGraph* jsgraph)
     : info_(info),
       jsgraph_(jsgraph),
-      linkage_(new (jsgraph->zone()) Linkage(info)) {}
+      linkage_(new (jsgraph->zone()) Linkage(jsgraph->zone(), info)) {}
 
 
 void JSGenericLowering::PatchOperator(Node* node, const Operator* op) {
@@ -32,40 +33,25 @@
 }
 
 
-Node* JSGenericLowering::SmiConstant(int32_t immediate) {
-  return jsgraph()->SmiConstant(immediate);
-}
-
-
-Node* JSGenericLowering::Int32Constant(int immediate) {
-  return jsgraph()->Int32Constant(immediate);
-}
-
-
-Node* JSGenericLowering::CodeConstant(Handle<Code> code) {
-  return jsgraph()->HeapConstant(code);
-}
-
-
-Node* JSGenericLowering::FunctionConstant(Handle<JSFunction> function) {
-  return jsgraph()->HeapConstant(function);
-}
-
-
-Node* JSGenericLowering::ExternalConstant(ExternalReference ref) {
-  return jsgraph()->ExternalConstant(ref);
-}
-
-
 Reduction JSGenericLowering::Reduce(Node* node) {
   switch (node->opcode()) {
-#define DECLARE_CASE(x) \
-  case IrOpcode::k##x:  \
-    Lower##x(node);     \
-    break;
-    DECLARE_CASE(Branch)
+#define DECLARE_CASE(x)  \
+    case IrOpcode::k##x: \
+      Lower##x(node);    \
+      break;
     JS_OP_LIST(DECLARE_CASE)
 #undef DECLARE_CASE
+    case IrOpcode::kBranch:
+      // TODO(mstarzinger): If typing is enabled then simplified lowering will
+      // have inserted the correct ChangeBoolToBit, otherwise we need to perform
+      // poor-man's representation inference here and insert manual change.
+      if (!info()->is_typing_enabled()) {
+        Node* test = graph()->NewNode(machine()->WordEqual(), node->InputAt(0),
+                                      jsgraph()->TrueConstant());
+        node->ReplaceInput(0, test);
+        break;
+      }
+      // Fall-through.
     default:
       // Nothing to see.
       return NoChange();
@@ -93,18 +79,18 @@
 #undef REPLACE_BINARY_OP_IC_CALL
 
 
-#define REPLACE_COMPARE_IC_CALL(op, token, pure)  \
+#define REPLACE_COMPARE_IC_CALL(op, token)        \
   void JSGenericLowering::Lower##op(Node* node) { \
-    ReplaceWithCompareIC(node, token, pure);      \
+    ReplaceWithCompareIC(node, token);            \
   }
-REPLACE_COMPARE_IC_CALL(JSEqual, Token::EQ, false)
-REPLACE_COMPARE_IC_CALL(JSNotEqual, Token::NE, false)
-REPLACE_COMPARE_IC_CALL(JSStrictEqual, Token::EQ_STRICT, true)
-REPLACE_COMPARE_IC_CALL(JSStrictNotEqual, Token::NE_STRICT, true)
-REPLACE_COMPARE_IC_CALL(JSLessThan, Token::LT, false)
-REPLACE_COMPARE_IC_CALL(JSGreaterThan, Token::GT, false)
-REPLACE_COMPARE_IC_CALL(JSLessThanOrEqual, Token::LTE, false)
-REPLACE_COMPARE_IC_CALL(JSGreaterThanOrEqual, Token::GTE, false)
+REPLACE_COMPARE_IC_CALL(JSEqual, Token::EQ)
+REPLACE_COMPARE_IC_CALL(JSNotEqual, Token::NE)
+REPLACE_COMPARE_IC_CALL(JSStrictEqual, Token::EQ_STRICT)
+REPLACE_COMPARE_IC_CALL(JSStrictNotEqual, Token::NE_STRICT)
+REPLACE_COMPARE_IC_CALL(JSLessThan, Token::LT)
+REPLACE_COMPARE_IC_CALL(JSGreaterThan, Token::GT)
+REPLACE_COMPARE_IC_CALL(JSLessThanOrEqual, Token::LTE)
+REPLACE_COMPARE_IC_CALL(JSGreaterThanOrEqual, Token::GTE)
 #undef REPLACE_COMPARE_IC_CALL
 
 
@@ -119,7 +105,7 @@
 REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext)
 REPLACE_RUNTIME_CALL(JSCreateBlockContext, Runtime::kPushBlockContext)
 REPLACE_RUNTIME_CALL(JSCreateModuleContext, Runtime::kPushModuleContext)
-REPLACE_RUNTIME_CALL(JSCreateGlobalContext, Runtime::kAbort)
+REPLACE_RUNTIME_CALL(JSCreateScriptContext, Runtime::kAbort)
 #undef REPLACE_RUNTIME
 
 
@@ -140,8 +126,7 @@
 }
 
 
-void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token,
-                                             bool pure) {
+void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token) {
   Callable callable = CodeFactory::CompareIC(isolate(), token);
   bool has_frame_state = OperatorProperties::HasFrameStateInput(node->op());
   CallDescriptor* desc_compare = linkage()->GetStubCallDescriptor(
@@ -149,11 +134,11 @@
       CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node));
   NodeVector inputs(zone());
   inputs.reserve(node->InputCount() + 1);
-  inputs.push_back(CodeConstant(callable.code()));
+  inputs.push_back(jsgraph()->HeapConstant(callable.code()));
   inputs.push_back(NodeProperties::GetValueInput(node, 0));
   inputs.push_back(NodeProperties::GetValueInput(node, 1));
   inputs.push_back(NodeProperties::GetContextInput(node));
-  if (pure) {
+  if (node->op()->HasProperty(Operator::kPure)) {
     // A pure (strict) comparison doesn't have an effect, control or frame
     // state.  But for the graph, we need to add control and effect inputs.
     DCHECK(!has_frame_state);
@@ -172,7 +157,7 @@
                        static_cast<int>(inputs.size()), &inputs.front());
 
   node->ReplaceInput(0, compare);
-  node->ReplaceInput(1, SmiConstant(token));
+  node->ReplaceInput(1, jsgraph()->SmiConstant(token));
 
   if (has_frame_state) {
     // Remove the frame state from inputs.
@@ -185,9 +170,10 @@
 
 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
                                             CallDescriptor::Flags flags) {
+  Operator::Properties properties = node->op()->properties();
   CallDescriptor* desc = linkage()->GetStubCallDescriptor(
-      callable.descriptor(), 0, flags | FlagsForNode(node));
-  Node* stub_code = CodeConstant(callable.code());
+      callable.descriptor(), 0, flags | FlagsForNode(node), properties);
+  Node* stub_code = jsgraph()->HeapConstant(callable.code());
   PatchInsertInput(node, 0, stub_code);
   PatchOperator(node, common()->Call(desc));
 }
@@ -196,16 +182,17 @@
 void JSGenericLowering::ReplaceWithBuiltinCall(Node* node,
                                                Builtins::JavaScript id,
                                                int nargs) {
+  Operator::Properties properties = node->op()->properties();
   Callable callable =
       CodeFactory::CallFunction(isolate(), nargs - 1, NO_CALL_FUNCTION_FLAGS);
-  CallDescriptor* desc =
-      linkage()->GetStubCallDescriptor(callable.descriptor(), nargs);
+  CallDescriptor* desc = linkage()->GetStubCallDescriptor(
+      callable.descriptor(), nargs, FlagsForNode(node), properties);
   // TODO(mstarzinger): Accessing the builtins object this way prevents sharing
   // of code across native contexts. Fix this by loading from given context.
   Handle<JSFunction> function(
       JSFunction::cast(info()->context()->builtins()->javascript_builtin(id)));
-  Node* stub_code = CodeConstant(callable.code());
-  Node* function_node = FunctionConstant(function);
+  Node* stub_code = jsgraph()->HeapConstant(callable.code());
+  Node* function_node = jsgraph()->HeapConstant(function);
   PatchInsertInput(node, 0, stub_code);
   PatchInsertInput(node, 1, function_node);
   PatchOperator(node, common()->Call(desc));
@@ -220,30 +207,15 @@
   int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
   CallDescriptor* desc =
       linkage()->GetRuntimeCallDescriptor(f, nargs, properties);
-  Node* ref = ExternalConstant(ExternalReference(f, isolate()));
-  Node* arity = Int32Constant(nargs);
-  if (!centrystub_constant_.is_set()) {
-    centrystub_constant_.set(CodeConstant(CEntryStub(isolate(), 1).GetCode()));
-  }
-  PatchInsertInput(node, 0, centrystub_constant_.get());
+  Node* ref = jsgraph()->ExternalConstant(ExternalReference(f, isolate()));
+  Node* arity = jsgraph()->Int32Constant(nargs);
+  PatchInsertInput(node, 0, jsgraph()->CEntryStubConstant(fun->result_size));
   PatchInsertInput(node, nargs + 1, ref);
   PatchInsertInput(node, nargs + 2, arity);
   PatchOperator(node, common()->Call(desc));
 }
 
 
-void JSGenericLowering::LowerBranch(Node* node) {
-  if (!info()->is_typing_enabled()) {
-    // TODO(mstarzinger): If typing is enabled then simplified lowering will
-    // have inserted the correct ChangeBoolToBit, otherwise we need to perform
-    // poor-man's representation inference here and insert manual change.
-    Node* test = graph()->NewNode(machine()->WordEqual(), node->InputAt(0),
-                                  jsgraph()->TrueConstant());
-    node->ReplaceInput(0, test);
-  }
-}
-
-
 void JSGenericLowering::LowerJSUnaryNot(Node* node) {
   Callable callable = CodeFactory::ToBoolean(
       isolate(), ToBooleanStub::RESULT_AS_INVERSE_ODDBALL);
@@ -260,7 +232,7 @@
 
 void JSGenericLowering::LowerJSToNumber(Node* node) {
   Callable callable = CodeFactory::ToNumber(isolate());
-  ReplaceWithStubCall(node, callable, CallDescriptor::kNoFlags);
+  ReplaceWithStubCall(node, callable, FlagsForNode(node));
 }
 
 
@@ -275,15 +247,25 @@
 
 
 void JSGenericLowering::LowerJSLoadProperty(Node* node) {
-  Callable callable = CodeFactory::KeyedLoadIC(isolate());
+  const LoadPropertyParameters& p = LoadPropertyParametersOf(node->op());
+  Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate());
+  if (FLAG_vector_ics) {
+    PatchInsertInput(node, 2, jsgraph()->SmiConstant(p.feedback().index()));
+    PatchInsertInput(node, 3, jsgraph()->HeapConstant(p.feedback().vector()));
+  }
   ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
 }
 
 
 void JSGenericLowering::LowerJSLoadNamed(Node* node) {
-  LoadNamedParameters p = OpParameter<LoadNamedParameters>(node);
-  Callable callable = CodeFactory::LoadIC(isolate(), p.contextual_mode);
-  PatchInsertInput(node, 1, jsgraph()->HeapConstant(p.name));
+  const LoadNamedParameters& p = LoadNamedParametersOf(node->op());
+  Callable callable =
+      CodeFactory::LoadICInOptimizedCode(isolate(), p.contextual_mode());
+  PatchInsertInput(node, 1, jsgraph()->HeapConstant(p.name()));
+  if (FLAG_vector_ics) {
+    PatchInsertInput(node, 2, jsgraph()->SmiConstant(p.feedback().index()));
+    PatchInsertInput(node, 3, jsgraph()->HeapConstant(p.feedback().vector()));
+  }
   ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
 }
 
@@ -296,16 +278,16 @@
 
 
 void JSGenericLowering::LowerJSStoreNamed(Node* node) {
-  StoreNamedParameters params = OpParameter<StoreNamedParameters>(node);
-  Callable callable = CodeFactory::StoreIC(isolate(), params.strict_mode);
-  PatchInsertInput(node, 1, jsgraph()->HeapConstant(params.name));
+  const StoreNamedParameters& p = StoreNamedParametersOf(node->op());
+  Callable callable = CodeFactory::StoreIC(isolate(), p.strict_mode());
+  PatchInsertInput(node, 1, jsgraph()->HeapConstant(p.name()));
   ReplaceWithStubCall(node, callable, CallDescriptor::kPatchableCallSite);
 }
 
 
 void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
   StrictMode strict_mode = OpParameter<StrictMode>(node);
-  PatchInsertInput(node, 2, SmiConstant(strict_mode));
+  PatchInsertInput(node, 2, jsgraph()->SmiConstant(strict_mode));
   ReplaceWithBuiltinCall(node, Builtins::DELETE, 3);
 }
 
@@ -321,44 +303,46 @@
       InstanceofStub::kArgsInRegisters);
   InstanceofStub stub(isolate(), flags);
   CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
-  CallDescriptor* desc = linkage()->GetStubCallDescriptor(d, 0);
-  Node* stub_code = CodeConstant(stub.GetCode());
+  CallDescriptor* desc =
+      linkage()->GetStubCallDescriptor(d, 0, FlagsForNode(node));
+  Node* stub_code = jsgraph()->HeapConstant(stub.GetCode());
   PatchInsertInput(node, 0, stub_code);
   PatchOperator(node, common()->Call(desc));
 }
 
 
 void JSGenericLowering::LowerJSLoadContext(Node* node) {
-  ContextAccess access = OpParameter<ContextAccess>(node);
-  // TODO(mstarzinger): Use simplified operators instead of machine operators
-  // here so that load/store optimization can be applied afterwards.
-  for (int i = 0; i < access.depth(); ++i) {
+  const ContextAccess& access = ContextAccessOf(node->op());
+  for (size_t i = 0; i < access.depth(); ++i) {
     node->ReplaceInput(
-        0, graph()->NewNode(
-               machine()->Load(kMachAnyTagged),
-               NodeProperties::GetValueInput(node, 0),
-               Int32Constant(Context::SlotOffset(Context::PREVIOUS_INDEX)),
-               NodeProperties::GetEffectInput(node)));
+        0, graph()->NewNode(machine()->Load(kMachAnyTagged),
+                            NodeProperties::GetValueInput(node, 0),
+                            jsgraph()->Int32Constant(
+                                Context::SlotOffset(Context::PREVIOUS_INDEX)),
+                            NodeProperties::GetEffectInput(node),
+                            graph()->start()));
   }
-  node->ReplaceInput(1, Int32Constant(Context::SlotOffset(access.index())));
+  node->ReplaceInput(1, jsgraph()->Int32Constant(Context::SlotOffset(
+                            static_cast<int>(access.index()))));
+  node->AppendInput(zone(), graph()->start());
   PatchOperator(node, machine()->Load(kMachAnyTagged));
 }
 
 
 void JSGenericLowering::LowerJSStoreContext(Node* node) {
-  ContextAccess access = OpParameter<ContextAccess>(node);
-  // TODO(mstarzinger): Use simplified operators instead of machine operators
-  // here so that load/store optimization can be applied afterwards.
-  for (int i = 0; i < access.depth(); ++i) {
+  const ContextAccess& access = ContextAccessOf(node->op());
+  for (size_t i = 0; i < access.depth(); ++i) {
     node->ReplaceInput(
-        0, graph()->NewNode(
-               machine()->Load(kMachAnyTagged),
-               NodeProperties::GetValueInput(node, 0),
-               Int32Constant(Context::SlotOffset(Context::PREVIOUS_INDEX)),
-               NodeProperties::GetEffectInput(node)));
+        0, graph()->NewNode(machine()->Load(kMachAnyTagged),
+                            NodeProperties::GetValueInput(node, 0),
+                            jsgraph()->Int32Constant(
+                                Context::SlotOffset(Context::PREVIOUS_INDEX)),
+                            NodeProperties::GetEffectInput(node),
+                            graph()->start()));
   }
   node->ReplaceInput(2, NodeProperties::GetValueInput(node, 1));
-  node->ReplaceInput(1, Int32Constant(Context::SlotOffset(access.index())));
+  node->ReplaceInput(1, jsgraph()->Int32Constant(Context::SlotOffset(
+                            static_cast<int>(access.index()))));
   PatchOperator(node, machine()->Store(StoreRepresentation(kMachAnyTagged,
                                                            kFullWriteBarrier)));
 }
@@ -370,32 +354,73 @@
   CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
   CallDescriptor* desc =
       linkage()->GetStubCallDescriptor(d, arity, FlagsForNode(node));
-  Node* stub_code = CodeConstant(stub.GetCode());
+  Node* stub_code = jsgraph()->HeapConstant(stub.GetCode());
   Node* construct = NodeProperties::GetValueInput(node, 0);
   PatchInsertInput(node, 0, stub_code);
-  PatchInsertInput(node, 1, Int32Constant(arity - 1));
+  PatchInsertInput(node, 1, jsgraph()->Int32Constant(arity - 1));
   PatchInsertInput(node, 2, construct);
   PatchInsertInput(node, 3, jsgraph()->UndefinedConstant());
   PatchOperator(node, common()->Call(desc));
 }
 
 
+bool JSGenericLowering::TryLowerDirectJSCall(Node* node) {
+  // Lower to a direct call to a constant JSFunction if legal.
+  const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
+  int arg_count = static_cast<int>(p.arity() - 2);
+
+  // Check the function is a constant and is really a JSFunction.
+  HeapObjectMatcher<Object> function_const(node->InputAt(0));
+  if (!function_const.HasValue()) return false;  // not a constant.
+  Handle<Object> func = function_const.Value().handle();
+  if (!func->IsJSFunction()) return false;  // not a function.
+  Handle<JSFunction> function = Handle<JSFunction>::cast(func);
+  if (arg_count != function->shared()->formal_parameter_count()) return false;
+
+  // Check the receiver doesn't need to be wrapped.
+  Node* receiver = node->InputAt(1);
+  if (!NodeProperties::IsTyped(receiver)) return false;
+  Type* ok_receiver = Type::Union(Type::Undefined(), Type::Receiver(), zone());
+  if (!NodeProperties::GetBounds(receiver).upper->Is(ok_receiver)) return false;
+
+  int index = NodeProperties::FirstContextIndex(node);
+
+  // TODO(titzer): total hack to share function context constants.
+  // Remove this when the JSGraph canonicalizes heap constants.
+  Node* context = node->InputAt(index);
+  HeapObjectMatcher<Context> context_const(context);
+  if (!context_const.HasValue() ||
+      *(context_const.Value().handle()) != function->context()) {
+    context = jsgraph()->HeapConstant(Handle<Context>(function->context()));
+  }
+  node->ReplaceInput(index, context);
+  CallDescriptor* desc = linkage()->GetJSCallDescriptor(
+      1 + arg_count, jsgraph()->zone(), FlagsForNode(node));
+  PatchOperator(node, common()->Call(desc));
+  return true;
+}
+
+
 void JSGenericLowering::LowerJSCallFunction(Node* node) {
-  CallParameters p = OpParameter<CallParameters>(node);
-  CallFunctionStub stub(isolate(), p.arity - 2, p.flags);
+  // Fast case: call function directly.
+  if (TryLowerDirectJSCall(node)) return;
+
+  // General case: CallFunctionStub.
+  const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
+  int arg_count = static_cast<int>(p.arity() - 2);
+  CallFunctionStub stub(isolate(), arg_count, p.flags());
   CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
-  CallDescriptor* desc =
-      linkage()->GetStubCallDescriptor(d, p.arity - 1, FlagsForNode(node));
-  Node* stub_code = CodeConstant(stub.GetCode());
+  CallDescriptor* desc = linkage()->GetStubCallDescriptor(
+      d, static_cast<int>(p.arity() - 1), FlagsForNode(node));
+  Node* stub_code = jsgraph()->HeapConstant(stub.GetCode());
   PatchInsertInput(node, 0, stub_code);
   PatchOperator(node, common()->Call(desc));
 }
 
 
 void JSGenericLowering::LowerJSCallRuntime(Node* node) {
-  Runtime::FunctionId function = OpParameter<Runtime::FunctionId>(node);
-  int arity = OperatorProperties::GetValueInputCount(node->op());
-  ReplaceWithRuntimeCall(node, function, arity);
+  const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
+  ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
 }
 
 }  // namespace compiler
diff --git a/src/compiler/js-generic-lowering.h b/src/compiler/js-generic-lowering.h
index 400f806..f626338 100644
--- a/src/compiler/js-generic-lowering.h
+++ b/src/compiler/js-generic-lowering.h
@@ -5,13 +5,12 @@
 #ifndef V8_COMPILER_JS_GENERIC_LOWERING_H_
 #define V8_COMPILER_JS_GENERIC_LOWERING_H_
 
-#include "src/v8.h"
-
 #include "src/allocation.h"
 #include "src/code-factory.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/graph-reducer.h"
 #include "src/compiler/js-graph.h"
+#include "src/compiler/linkage.h"
 #include "src/compiler/opcodes.h"
 
 namespace v8 {
@@ -23,37 +22,34 @@
 class MachineOperatorBuilder;
 class Linkage;
 
+
 // Lowers JS-level operators to runtime and IC calls in the "generic" case.
-class JSGenericLowering : public Reducer {
+class JSGenericLowering FINAL : public Reducer {
  public:
   JSGenericLowering(CompilationInfo* info, JSGraph* graph);
-  virtual ~JSGenericLowering() {}
+  ~JSGenericLowering() FINAL {}
 
-  virtual Reduction Reduce(Node* node);
+  Reduction Reduce(Node* node) FINAL;
 
  protected:
 #define DECLARE_LOWER(x) void Lower##x(Node* node);
   // Dispatched depending on opcode.
-  ALL_OP_LIST(DECLARE_LOWER)
+  JS_OP_LIST(DECLARE_LOWER)
 #undef DECLARE_LOWER
 
-  // Helpers to create new constant nodes.
-  Node* SmiConstant(int immediate);
-  Node* Int32Constant(int immediate);
-  Node* CodeConstant(Handle<Code> code);
-  Node* FunctionConstant(Handle<JSFunction> function);
-  Node* ExternalConstant(ExternalReference ref);
-
   // Helpers to patch existing nodes in the graph.
   void PatchOperator(Node* node, const Operator* new_op);
   void PatchInsertInput(Node* node, int index, Node* input);
 
   // Helpers to replace existing nodes with a generic call.
-  void ReplaceWithCompareIC(Node* node, Token::Value token, bool pure);
+  void ReplaceWithCompareIC(Node* node, Token::Value token);
   void ReplaceWithStubCall(Node* node, Callable c, CallDescriptor::Flags flags);
   void ReplaceWithBuiltinCall(Node* node, Builtins::JavaScript id, int args);
   void ReplaceWithRuntimeCall(Node* node, Runtime::FunctionId f, int args = -1);
 
+  // Helper for optimization of JSCallFunction.
+  bool TryLowerDirectJSCall(Node* node);
+
   Zone* zone() const { return graph()->zone(); }
   Isolate* isolate() const { return zone()->isolate(); }
   JSGraph* jsgraph() const { return jsgraph_; }
@@ -67,7 +63,6 @@
   CompilationInfo* info_;
   JSGraph* jsgraph_;
   Linkage* linkage_;
-  SetOncePointer<Node> centrystub_constant_;
 };
 
 }  // namespace compiler
diff --git a/src/compiler/js-graph.cc b/src/compiler/js-graph.cc
index 1309531..7759ba1 100644
--- a/src/compiler/js-graph.cc
+++ b/src/compiler/js-graph.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "src/code-stubs.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/typer.h"
@@ -10,25 +11,22 @@
 namespace internal {
 namespace compiler {
 
-Node* JSGraph::ImmovableHeapConstant(Handle<Object> object) {
-  Unique<Object> unique = Unique<Object>::CreateImmovable(object);
-  return NewNode(common()->HeapConstant(unique));
+Node* JSGraph::ImmovableHeapConstant(Handle<HeapObject> object) {
+  Unique<HeapObject> unique = Unique<HeapObject>::CreateImmovable(object);
+  return graph()->NewNode(common()->HeapConstant(unique));
 }
 
 
-Node* JSGraph::NewNode(const Operator* op) {
-  Node* node = graph()->NewNode(op);
-  typer_->Init(node);
-  return node;
-}
-
-
-Node* JSGraph::CEntryStubConstant() {
-  if (!c_entry_stub_constant_.is_set()) {
-    c_entry_stub_constant_.set(
-        ImmovableHeapConstant(CEntryStub(isolate(), 1).GetCode()));
+Node* JSGraph::CEntryStubConstant(int result_size) {
+  if (result_size == 1) {
+    if (!c_entry_stub_constant_.is_set()) {
+      c_entry_stub_constant_.set(
+          ImmovableHeapConstant(CEntryStub(isolate(), 1).GetCode()));
+    }
+    return c_entry_stub_constant_.get();
   }
-  return c_entry_stub_constant_.get();
+
+  return ImmovableHeapConstant(CEntryStub(isolate(), result_size).GetCode());
 }
 
 
@@ -93,13 +91,13 @@
 }
 
 
-Node* JSGraph::HeapConstant(Unique<Object> value) {
+Node* JSGraph::HeapConstant(Unique<HeapObject> value) {
   // TODO(turbofan): canonicalize heap constants using Unique<T>
-  return NewNode(common()->HeapConstant(value));
+  return graph()->NewNode(common()->HeapConstant(value));
 }
 
 
-Node* JSGraph::HeapConstant(Handle<Object> value) {
+Node* JSGraph::HeapConstant(Handle<HeapObject> value) {
   // TODO(titzer): We could also match against the addresses of immortable
   // immovables here, even without access to the heap, thus always
   // canonicalizing references to them.
@@ -107,7 +105,8 @@
   // TODO(turbofan): This is a work-around to make Unique::HashCode() work for
   // value numbering. We need some sane way to compute a unique hash code for
   // arbitrary handles here.
-  Unique<Object> unique(reinterpret_cast<Address>(*value.location()), value);
+  Unique<HeapObject> unique(reinterpret_cast<Address>(*value.location()),
+                            value);
   return HeapConstant(unique);
 }
 
@@ -128,7 +127,7 @@
   } else if (value->IsTheHole()) {
     return TheHoleConstant();
   } else {
-    return HeapConstant(value);
+    return HeapConstant(Handle<HeapObject>::cast(value));
   }
 }
 
@@ -150,7 +149,16 @@
 Node* JSGraph::Int32Constant(int32_t value) {
   Node** loc = cache_.FindInt32Constant(value);
   if (*loc == NULL) {
-    *loc = NewNode(common()->Int32Constant(value));
+    *loc = graph()->NewNode(common()->Int32Constant(value));
+  }
+  return *loc;
+}
+
+
+Node* JSGraph::Int64Constant(int64_t value) {
+  Node** loc = cache_.FindInt64Constant(value);
+  if (*loc == NULL) {
+    *loc = graph()->NewNode(common()->Int64Constant(value));
   }
   return *loc;
 }
@@ -159,7 +167,16 @@
 Node* JSGraph::NumberConstant(double value) {
   Node** loc = cache_.FindNumberConstant(value);
   if (*loc == NULL) {
-    *loc = NewNode(common()->NumberConstant(value));
+    *loc = graph()->NewNode(common()->NumberConstant(value));
+  }
+  return *loc;
+}
+
+
+Node* JSGraph::Float32Constant(float value) {
+  Node** loc = cache_.FindFloat32Constant(value);
+  if (*loc == NULL) {
+    *loc = graph()->NewNode(common()->Float32Constant(value));
   }
   return *loc;
 }
@@ -168,7 +185,7 @@
 Node* JSGraph::Float64Constant(double value) {
   Node** loc = cache_.FindFloat64Constant(value);
   if (*loc == NULL) {
-    *loc = NewNode(common()->Float64Constant(value));
+    *loc = graph()->NewNode(common()->Float64Constant(value));
   }
   return *loc;
 }
@@ -177,10 +194,23 @@
 Node* JSGraph::ExternalConstant(ExternalReference reference) {
   Node** loc = cache_.FindExternalConstant(reference);
   if (*loc == NULL) {
-    *loc = NewNode(common()->ExternalConstant(reference));
+    *loc = graph()->NewNode(common()->ExternalConstant(reference));
   }
   return *loc;
 }
+
+
+void JSGraph::GetCachedNodes(NodeVector* nodes) {
+  cache_.GetCachedNodes(nodes);
+  SetOncePointer<Node>* ptrs[] = {
+      &c_entry_stub_constant_, &undefined_constant_, &the_hole_constant_,
+      &true_constant_,         &false_constant_,     &null_constant_,
+      &zero_constant_,         &one_constant_,       &nan_constant_};
+  for (size_t i = 0; i < arraysize(ptrs); i++) {
+    if (ptrs[i]->is_set()) nodes->push_back(ptrs[i]->get());
+  }
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
diff --git a/src/compiler/js-graph.h b/src/compiler/js-graph.h
index 2b2dfd1..040a745 100644
--- a/src/compiler/js-graph.h
+++ b/src/compiler/js-graph.h
@@ -24,17 +24,15 @@
 class JSGraph : public ZoneObject {
  public:
   JSGraph(Graph* graph, CommonOperatorBuilder* common,
-          JSOperatorBuilder* javascript, Typer* typer,
-          MachineOperatorBuilder* machine)
+          JSOperatorBuilder* javascript, MachineOperatorBuilder* machine)
       : graph_(graph),
         common_(common),
         javascript_(javascript),
-        typer_(typer),
         machine_(machine),
         cache_(zone()) {}
 
   // Canonicalized global constants.
-  Node* CEntryStubConstant();
+  Node* CEntryStubConstant(int result_size);
   Node* UndefinedConstant();
   Node* TheHoleConstant();
   Node* TrueConstant();
@@ -46,11 +44,11 @@
 
   // Creates a HeapConstant node, possibly canonicalized, without inspecting the
   // object.
-  Node* HeapConstant(Unique<Object> value);
+  Node* HeapConstant(Unique<HeapObject> value);
 
   // Creates a HeapConstant node, possibly canonicalized, and may access the
   // heap to inspect the object.
-  Node* HeapConstant(Handle<Object> value);
+  Node* HeapConstant(Handle<HeapObject> value);
 
   // Creates a Constant node of the appropriate type for the given object.
   // Accesses the heap to inspect the object and determine whether one of the
@@ -69,6 +67,33 @@
     return Int32Constant(bit_cast<int32_t>(value));
   }
 
+  // Creates a HeapConstant node for either true or false.
+  Node* BooleanConstant(bool is_true) {
+    return is_true ? TrueConstant() : FalseConstant();
+  }
+
+  // Creates a Int64Constant node, usually canonicalized.
+  Node* Int64Constant(int64_t value);
+  Node* Uint64Constant(uint64_t value) {
+    return Int64Constant(bit_cast<int64_t>(value));
+  }
+
+  // Creates a Int32Constant/Int64Constant node, depending on the word size of
+  // the target machine.
+  // TODO(turbofan): Code using Int32Constant/Int64Constant to store pointer
+  // constants is probably not serializable.
+  Node* IntPtrConstant(intptr_t value) {
+    return machine()->Is32() ? Int32Constant(static_cast<int32_t>(value))
+                             : Int64Constant(static_cast<int64_t>(value));
+  }
+  template <typename T>
+  Node* PointerConstant(T* value) {
+    return IntPtrConstant(bit_cast<intptr_t>(value));
+  }
+
+  // Creates a Float32Constant node, usually canonicalized.
+  Node* Float32Constant(float value);
+
   // Creates a Float64Constant node, usually canonicalized.
   Node* Float64Constant(double value);
 
@@ -80,20 +105,27 @@
     return Constant(immediate);
   }
 
+  // Creates a dummy Constant node, used to satisfy calling conventions of
+  // stubs and runtime functions that do not require a context.
+  Node* NoContextConstant() { return ZeroConstant(); }
+
   JSOperatorBuilder* javascript() { return javascript_; }
   CommonOperatorBuilder* common() { return common_; }
   MachineOperatorBuilder* machine() { return machine_; }
   Graph* graph() { return graph_; }
   Zone* zone() { return graph()->zone(); }
   Isolate* isolate() { return zone()->isolate(); }
+  Factory* factory() { return isolate()->factory(); }
+
+  void GetCachedNodes(NodeVector* nodes);
 
  private:
   Graph* graph_;
   CommonOperatorBuilder* common_;
   JSOperatorBuilder* javascript_;
-  Typer* typer_;
   MachineOperatorBuilder* machine_;
 
+  // TODO(titzer): make this into a simple array.
   SetOncePointer<Node> c_entry_stub_constant_;
   SetOncePointer<Node> undefined_constant_;
   SetOncePointer<Node> the_hole_constant_;
@@ -106,11 +138,10 @@
 
   CommonNodeCache cache_;
 
-  Node* ImmovableHeapConstant(Handle<Object> value);
+  Node* ImmovableHeapConstant(Handle<HeapObject> value);
   Node* NumberConstant(double value);
-  Node* NewNode(const Operator* op);
 
-  Factory* factory() { return isolate()->factory(); }
+  DISALLOW_COPY_AND_ASSIGN(JSGraph);
 };
 
 }  // namespace compiler
diff --git a/src/compiler/js-inlining.cc b/src/compiler/js-inlining.cc
index af02145..d143382 100644
--- a/src/compiler/js-inlining.cc
+++ b/src/compiler/js-inlining.cc
@@ -2,13 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "src/ast.h"
+#include "src/ast-numbering.h"
 #include "src/compiler/access-builder.h"
 #include "src/compiler/ast-graph-builder.h"
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/graph-visualizer.h"
 #include "src/compiler/js-inlining.h"
+#include "src/compiler/js-intrinsic-builder.h"
 #include "src/compiler/js-operator.h"
 #include "src/compiler/node-aux-data-inl.h"
 #include "src/compiler/node-matchers.h"
@@ -29,15 +31,19 @@
  public:
   explicit InlinerVisitor(JSInliner* inliner) : inliner_(inliner) {}
 
-  GenericGraphVisit::Control Post(Node* node) {
+  void Post(Node* node) {
     switch (node->opcode()) {
       case IrOpcode::kJSCallFunction:
-        inliner_->TryInlineCall(node);
+        inliner_->TryInlineJSCall(node);
+        break;
+      case IrOpcode::kJSCallRuntime:
+        if (FLAG_turbo_inlining_intrinsics) {
+          inliner_->TryInlineRuntimeCall(node);
+        }
         break;
       default:
         break;
     }
-    return GenericGraphVisit::CONTINUE;
   }
 
  private:
@@ -51,16 +57,6 @@
 }
 
 
-// TODO(sigurds) Find a home for this function and reuse it everywhere (esp. in
-// test cases, where similar code is currently duplicated).
-static void Parse(Handle<JSFunction> function, CompilationInfoWithZone* info) {
-  CHECK(Parser::Parse(info));
-  CHECK(Rewriter::Rewrite(info));
-  CHECK(Scope::Analyze(info));
-  CHECK(Compiler::EnsureDeoptimizationSupport(info));
-}
-
-
 // A facade on a JSFunction's graph to facilitate inlining. It assumes the
 // that the function graph has only one return statement, and provides
 // {UnifyReturn} to convert a function graph to that end.
@@ -90,7 +86,7 @@
   }
 
   // Counts JSFunction, Receiver, arguments, context but not effect, control.
-  size_t total_parameters() { return start_->op()->OutputCount(); }
+  size_t total_parameters() { return start_->op()->ValueOutputCount(); }
 
   // Counts only formal parameters.
   size_t formal_parameters() {
@@ -121,8 +117,7 @@
   }
   DCHECK_EQ(IrOpcode::kMerge, final_merge->opcode());
 
-  int predecessors =
-      OperatorProperties::GetControlInputCount(final_merge->op());
+  int predecessors = final_merge->op()->ControlInputCount();
 
   const Operator* op_phi = jsgraph->common()->Phi(kMachAnyTagged, predecessors);
   const Operator* op_ephi = jsgraph->common()->EffectPhi(predecessors);
@@ -131,19 +126,17 @@
   NodeVector effects(jsgraph->zone());
   // Iterate over all control flow predecessors,
   // which must be return statements.
-  InputIter iter = final_merge->inputs().begin();
-  while (iter != final_merge->inputs().end()) {
-    Node* input = *iter;
+  for (Edge edge : final_merge->input_edges()) {
+    Node* input = edge.to();
     switch (input->opcode()) {
       case IrOpcode::kReturn:
         values.push_back(NodeProperties::GetValueInput(input, 0));
         effects.push_back(NodeProperties::GetEffectInput(input));
-        iter.UpdateToAndIncrement(NodeProperties::GetControlInput(input));
+        edge.UpdateTo(NodeProperties::GetControlInput(input));
         input->RemoveAllInputs();
         break;
       default:
         UNREACHABLE();
-        ++iter;
         break;
     }
   }
@@ -167,14 +160,13 @@
         source_graph_(source_graph),
         target_graph_(target_graph),
         temp_zone_(temp_zone),
-        sentinel_op_(IrOpcode::kDead, Operator::kNoProperties, 0, 0,
-                     "sentinel") {}
+        sentinel_op_(IrOpcode::kDead, Operator::kNoProperties, "sentinel", 0, 0,
+                     0, 0, 0, 0) {}
 
-  GenericGraphVisit::Control Post(Node* original) {
+  void Post(Node* original) {
     NodeVector inputs(temp_zone_);
-    for (InputIter it = original->inputs().begin();
-         it != original->inputs().end(); ++it) {
-      inputs.push_back(GetCopy(*it));
+    for (Node* const node : original->inputs()) {
+      inputs.push_back(GetCopy(node));
     }
 
     // Reuse the operator in the copy. This assumes that op lives in a zone
@@ -183,7 +175,6 @@
         target_graph_->NewNode(original->op(), static_cast<int>(inputs.size()),
                                (inputs.empty() ? NULL : &inputs.front()));
     copies_[original->id()] = copy;
-    return GenericGraphVisit::CONTINUE;
   }
 
   Node* GetCopy(Node* original) {
@@ -214,11 +205,10 @@
   }
 
   Node* GetSentinel(Node* original) {
-    Node* sentinel = sentinels_[original->id()];
-    if (sentinel == NULL) {
-      sentinel = target_graph_->NewNode(&sentinel_op_);
+    if (sentinels_[original->id()] == NULL) {
+      sentinels_[original->id()] = target_graph_->NewNode(&sentinel_op_);
     }
-    return sentinel;
+    return sentinels_[original->id()];
   }
 
   NodeVector copies_;
@@ -226,7 +216,7 @@
   Graph* source_graph_;
   Graph* target_graph_;
   Zone* temp_zone_;
-  SimpleOperator sentinel_op_;
+  Operator sentinel_op_;
 };
 
 
@@ -241,43 +231,41 @@
   Node* context = jsgraph->graph()->NewNode(
       simplified.LoadField(AccessBuilder::ForJSFunctionContext()),
       NodeProperties::GetValueInput(call, 0),
-      NodeProperties::GetEffectInput(call));
+      NodeProperties::GetEffectInput(call), control);
 
   // Context is last argument.
   int inlinee_context_index = static_cast<int>(total_parameters()) - 1;
   // {inliner_inputs} counts JSFunction, Receiver, arguments, but not
   // context, effect, control.
-  int inliner_inputs = OperatorProperties::GetValueInputCount(call->op());
+  int inliner_inputs = call->op()->ValueInputCount();
   // Iterate over all uses of the start node.
-  UseIter iter = start_->uses().begin();
-  while (iter != start_->uses().end()) {
-    Node* use = *iter;
+  for (Edge edge : start_->use_edges()) {
+    Node* use = edge.from();
     switch (use->opcode()) {
       case IrOpcode::kParameter: {
         int index = 1 + OpParameter<int>(use->op());
         if (index < inliner_inputs && index < inlinee_context_index) {
           // There is an input from the call, and the index is a value
           // projection but not the context, so rewire the input.
-          NodeProperties::ReplaceWithValue(*iter, call->InputAt(index));
+          NodeProperties::ReplaceWithValue(use, call->InputAt(index));
         } else if (index == inlinee_context_index) {
           // This is the context projection, rewire it to the context from the
           // JSFunction object.
-          NodeProperties::ReplaceWithValue(*iter, context);
+          NodeProperties::ReplaceWithValue(use, context);
         } else if (index < inlinee_context_index) {
           // Call has fewer arguments than required, fill with undefined.
-          NodeProperties::ReplaceWithValue(*iter, jsgraph->UndefinedConstant());
+          NodeProperties::ReplaceWithValue(use, jsgraph->UndefinedConstant());
         } else {
           // We got too many arguments, discard for now.
           // TODO(sigurds): Fix to treat arguments array correctly.
         }
-        ++iter;
         break;
       }
       default:
-        if (NodeProperties::IsEffectEdge(iter.edge())) {
-          iter.UpdateToAndIncrement(context);
-        } else if (NodeProperties::IsControlEdge(iter.edge())) {
-          iter.UpdateToAndIncrement(control);
+        if (NodeProperties::IsEffectEdge(edge)) {
+          edge.UpdateTo(context);
+        } else if (NodeProperties::IsControlEdge(edge)) {
+          edge.UpdateTo(control);
         } else {
           UNREACHABLE();
         }
@@ -285,22 +273,9 @@
     }
   }
 
-  // Iterate over all uses of the call node.
-  iter = call->uses().begin();
-  while (iter != call->uses().end()) {
-    if (NodeProperties::IsEffectEdge(iter.edge())) {
-      iter.UpdateToAndIncrement(effect_output());
-    } else if (NodeProperties::IsControlEdge(iter.edge())) {
-      UNREACHABLE();
-    } else {
-      DCHECK(NodeProperties::IsValueEdge(iter.edge()));
-      iter.UpdateToAndIncrement(value_output());
-    }
-  }
+  NodeProperties::ReplaceWithValue(call, value_output(), effect_output());
   call->RemoveAllInputs();
   DCHECK_EQ(0, call->UseCount());
-  // TODO(sigurds) Remove this once we copy.
-  unique_return()->RemoveAllInputs();
 }
 
 
@@ -323,7 +298,7 @@
 
   size_t formal_arguments() {
     // {value_inputs} includes jsfunction and receiver.
-    size_t value_inputs = OperatorProperties::GetValueInputCount(call_->op());
+    size_t value_inputs = call_->op()->ValueInputCount();
     DCHECK_GE(call_->InputCount(), 2);
     return value_inputs - 2;
   }
@@ -348,9 +323,9 @@
 Node* JSInliner::CreateArgumentsAdaptorFrameState(JSCallFunctionAccessor* call,
                                                   Handle<JSFunction> jsfunction,
                                                   Zone* temp_zone) {
-  const Operator* op =
-      jsgraph_->common()->FrameState(FrameStateType::ARGUMENTS_ADAPTOR,
-                                     BailoutId(-1), kIgnoreOutput, jsfunction);
+  const Operator* op = jsgraph_->common()->FrameState(
+      FrameStateType::ARGUMENTS_ADAPTOR, BailoutId(-1),
+      OutputFrameStateCombine::Ignore(), jsfunction);
   const Operator* op0 = jsgraph_->common()->StateValues(0);
   Node* node0 = jsgraph_->graph()->NewNode(op0);
   NodeVector params(temp_zone);
@@ -368,7 +343,7 @@
 }
 
 
-void JSInliner::TryInlineCall(Node* call_node) {
+void JSInliner::TryInlineJSCall(Node* call_node) {
   JSCallFunctionAccessor call(call_node);
 
   HeapObjectMatcher<JSFunction> match(call.jsfunction());
@@ -389,9 +364,11 @@
   }
 
   CompilationInfoWithZone info(function);
-  Parse(function, &info);
+  // TODO(wingo): ParseAndAnalyze can fail due to stack overflow.
+  CHECK(Compiler::ParseAndAnalyze(&info));
+  CHECK(Compiler::EnsureDeoptimizationSupport(&info));
 
-  if (info.scope()->arguments() != NULL) {
+  if (info.scope()->arguments() != NULL && info.strict_mode() != STRICT) {
     // For now do not inline functions that use their arguments array.
     SmartArrayPointer<char> name = function->shared()->DebugName()->ToCString();
     if (FLAG_trace_turbo_inlining) {
@@ -410,11 +387,10 @@
   }
 
   Graph graph(info.zone());
-  Typer typer(info.zone());
-  JSGraph jsgraph(&graph, jsgraph_->common(), jsgraph_->javascript(), &typer,
+  JSGraph jsgraph(&graph, jsgraph_->common(), jsgraph_->javascript(),
                   jsgraph_->machine());
 
-  AstGraphBuilder graph_builder(&info, &jsgraph);
+  AstGraphBuilder graph_builder(local_zone_, &info, &jsgraph);
   graph_builder.CreateGraph();
   Inlinee::UnifyReturn(&jsgraph);
 
@@ -423,24 +399,91 @@
 
   Inlinee inlinee(visitor.GetCopy(graph.start()), visitor.GetCopy(graph.end()));
 
-  Node* outer_frame_state = call.frame_state();
-  // Insert argument adaptor frame if required.
-  if (call.formal_arguments() != inlinee.formal_parameters()) {
-    outer_frame_state =
-        CreateArgumentsAdaptorFrameState(&call, function, info.zone());
-  }
+  if (FLAG_turbo_deoptimization) {
+    Node* outer_frame_state = call.frame_state();
+    // Insert argument adaptor frame if required.
+    if (call.formal_arguments() != inlinee.formal_parameters()) {
+      outer_frame_state =
+          CreateArgumentsAdaptorFrameState(&call, function, info.zone());
+    }
 
-  for (NodeVectorConstIter it = visitor.copies().begin();
-       it != visitor.copies().end(); ++it) {
-    Node* node = *it;
-    if (node != NULL && node->opcode() == IrOpcode::kFrameState) {
-      AddClosureToFrameState(node, function);
-      NodeProperties::ReplaceFrameStateInput(node, outer_frame_state);
+    for (NodeVectorConstIter it = visitor.copies().begin();
+         it != visitor.copies().end(); ++it) {
+      Node* node = *it;
+      if (node != NULL && node->opcode() == IrOpcode::kFrameState) {
+        AddClosureToFrameState(node, function);
+        NodeProperties::ReplaceFrameStateInput(node, outer_frame_state);
+      }
     }
   }
 
   inlinee.InlineAtCall(jsgraph_, call_node);
 }
+
+
+class JSCallRuntimeAccessor {
+ public:
+  explicit JSCallRuntimeAccessor(Node* call) : call_(call) {
+    DCHECK_EQ(IrOpcode::kJSCallRuntime, call->opcode());
+  }
+
+  Node* formal_argument(size_t index) {
+    DCHECK(index < formal_arguments());
+    return call_->InputAt(static_cast<int>(index));
+  }
+
+  size_t formal_arguments() {
+    size_t value_inputs = call_->op()->ValueInputCount();
+    return value_inputs;
+  }
+
+  Node* frame_state() const {
+    return NodeProperties::GetFrameStateInput(call_);
+  }
+  Node* context() const { return NodeProperties::GetContextInput(call_); }
+  Node* control() const { return NodeProperties::GetControlInput(call_); }
+  Node* effect() const { return NodeProperties::GetEffectInput(call_); }
+
+  const Runtime::Function* function() const {
+    return Runtime::FunctionForId(CallRuntimeParametersOf(call_->op()).id());
+  }
+
+  NodeVector inputs(Zone* zone) const {
+    NodeVector inputs(zone);
+    for (Node* const node : call_->inputs()) {
+      inputs.push_back(node);
+    }
+    return inputs;
+  }
+
+ private:
+  Node* call_;
+};
+
+
+void JSInliner::TryInlineRuntimeCall(Node* call_node) {
+  JSCallRuntimeAccessor call(call_node);
+  const Runtime::Function* f = call.function();
+
+  if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) {
+    return;
+  }
+
+  JSIntrinsicBuilder intrinsic_builder(jsgraph_);
+
+  ResultAndEffect r = intrinsic_builder.BuildGraphFor(
+      f->function_id, call.inputs(jsgraph_->zone()));
+
+  if (r.first != NULL) {
+    if (FLAG_trace_turbo_inlining) {
+      PrintF("Inlining %s into %s\n", f->name,
+             info_->shared_info()->DebugName()->ToCString().get());
+    }
+    NodeProperties::ReplaceWithValue(call_node, r.first, r.second);
+    call_node->RemoveAllInputs();
+    DCHECK_EQ(0, call_node->UseCount());
+  }
+}
 }
 }
 }  // namespace v8::internal::compiler
diff --git a/src/compiler/js-inlining.h b/src/compiler/js-inlining.h
index f135170..eef29d6 100644
--- a/src/compiler/js-inlining.h
+++ b/src/compiler/js-inlining.h
@@ -16,14 +16,16 @@
 
 class JSInliner {
  public:
-  JSInliner(CompilationInfo* info, JSGraph* jsgraph)
-      : info_(info), jsgraph_(jsgraph) {}
+  JSInliner(Zone* local_zone, CompilationInfo* info, JSGraph* jsgraph)
+      : local_zone_(local_zone), info_(info), jsgraph_(jsgraph) {}
 
   void Inline();
-  void TryInlineCall(Node* node);
+  void TryInlineJSCall(Node* node);
+  void TryInlineRuntimeCall(Node* node);
 
  private:
   friend class InlinerVisitor;
+  Zone* local_zone_;
   CompilationInfo* info_;
   JSGraph* jsgraph_;
 
diff --git a/src/compiler/js-intrinsic-builder.cc b/src/compiler/js-intrinsic-builder.cc
new file mode 100644
index 0000000..80b6968
--- /dev/null
+++ b/src/compiler/js-intrinsic-builder.cc
@@ -0,0 +1,140 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/diamond.h"
+#include "src/compiler/js-intrinsic-builder.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/simplified-operator.h"
+
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+ResultAndEffect JSIntrinsicBuilder::BuildGraphFor(Runtime::FunctionId id,
+                                                  const NodeVector& arguments) {
+  switch (id) {
+    case Runtime::kInlineIsSmi:
+      return BuildGraphFor_IsSmi(arguments);
+    case Runtime::kInlineIsNonNegativeSmi:
+      return BuildGraphFor_IsNonNegativeSmi(arguments);
+    case Runtime::kInlineIsArray:
+      return BuildMapCheck(arguments[0], arguments[2], JS_ARRAY_TYPE);
+    case Runtime::kInlineIsRegExp:
+      return BuildMapCheck(arguments[0], arguments[2], JS_REGEXP_TYPE);
+    case Runtime::kInlineIsFunction:
+      return BuildMapCheck(arguments[0], arguments[2], JS_FUNCTION_TYPE);
+    case Runtime::kInlineValueOf:
+      return BuildGraphFor_ValueOf(arguments);
+    default:
+      break;
+  }
+  return ResultAndEffect();
+}
+
+ResultAndEffect JSIntrinsicBuilder::BuildGraphFor_IsSmi(
+    const NodeVector& arguments) {
+  Node* object = arguments[0];
+  SimplifiedOperatorBuilder simplified(jsgraph_->zone());
+  Node* condition = graph()->NewNode(simplified.ObjectIsSmi(), object);
+
+  return ResultAndEffect(condition, arguments[2]);
+}
+
+
+ResultAndEffect JSIntrinsicBuilder::BuildGraphFor_IsNonNegativeSmi(
+    const NodeVector& arguments) {
+  Node* object = arguments[0];
+  SimplifiedOperatorBuilder simplified(jsgraph_->zone());
+  Node* condition =
+      graph()->NewNode(simplified.ObjectIsNonNegativeSmi(), object);
+
+  return ResultAndEffect(condition, arguments[2]);
+}
+
+
+/*
+ * if (_isSmi(object)) {
+ *   return false
+ * } else {
+ *   return %_GetMapInstanceType(object) == map_type
+ * }
+ */
+ResultAndEffect JSIntrinsicBuilder::BuildMapCheck(Node* object, Node* effect,
+                                                  InstanceType map_type) {
+  SimplifiedOperatorBuilder simplified(jsgraph_->zone());
+
+  Node* is_smi = graph()->NewNode(simplified.ObjectIsSmi(), object);
+  Diamond d(graph(), common(), is_smi);
+
+  Node* map = graph()->NewNode(simplified.LoadField(AccessBuilder::ForMap()),
+                               object, effect, d.if_false);
+
+  Node* instance_type = graph()->NewNode(
+      simplified.LoadField(AccessBuilder::ForMapInstanceType()), map, map,
+      d.if_false);
+
+  Node* has_map_type =
+      graph()->NewNode(jsgraph_->machine()->Word32Equal(), instance_type,
+                       jsgraph_->Int32Constant(map_type));
+
+  Node* phi = d.Phi(static_cast<MachineType>(kTypeBool | kRepTagged),
+                    jsgraph_->FalseConstant(), has_map_type);
+
+  Node* ephi = d.EffectPhi(effect, instance_type);
+
+  return ResultAndEffect(phi, ephi);
+}
+
+
+/*
+ * if (%_isSmi(object)) {
+ *   return object;
+ * } else if (%_GetMapInstanceType(object) == JS_VALUE_TYPE) {
+ *   return %_LoadValueField(object);
+ * } else {
+ *   return object;
+ * }
+ */
+ResultAndEffect JSIntrinsicBuilder::BuildGraphFor_ValueOf(
+    const NodeVector& arguments) {
+  Node* object = arguments[0];
+  Node* effect = arguments[2];
+  SimplifiedOperatorBuilder simplified(jsgraph_->zone());
+
+  Node* is_smi = graph()->NewNode(simplified.ObjectIsSmi(), object);
+
+  Diamond if_is_smi(graph(), common(), is_smi);
+
+  Node* map = graph()->NewNode(simplified.LoadField(AccessBuilder::ForMap()),
+                               object, effect, if_is_smi.if_false);
+
+  Node* instance_type = graph()->NewNode(
+      simplified.LoadField(AccessBuilder::ForMapInstanceType()), map, map,
+      if_is_smi.if_false);
+
+  Node* is_value =
+      graph()->NewNode(jsgraph_->machine()->Word32Equal(), instance_type,
+                       jsgraph_->Constant(JS_VALUE_TYPE));
+
+  Diamond if_is_value(graph(), common(), is_value);
+  if_is_value.Nest(if_is_smi, false);
+
+  Node* value =
+      graph()->NewNode(simplified.LoadField(AccessBuilder::ForValue()), object,
+                       instance_type, if_is_value.if_true);
+
+  Node* phi_is_value = if_is_value.Phi(kTypeAny, value, object);
+
+  Node* phi = if_is_smi.Phi(kTypeAny, object, phi_is_value);
+
+  Node* ephi = if_is_smi.EffectPhi(effect, instance_type);
+
+  return ResultAndEffect(phi, ephi);
+}
+}
+}
+}  // namespace v8::internal::compiler
diff --git a/src/compiler/js-intrinsic-builder.h b/src/compiler/js-intrinsic-builder.h
new file mode 100644
index 0000000..9336be6
--- /dev/null
+++ b/src/compiler/js-intrinsic-builder.h
@@ -0,0 +1,40 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_JS_INTRINSIC_BUILDER_H_
+#define V8_COMPILER_JS_INTRINSIC_BUILDER_H_
+
+#include "src/compiler/js-graph.h"
+#include "src/v8.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+typedef std::pair<Node*, Node*> ResultAndEffect;
+
+class JSIntrinsicBuilder {
+ public:
+  explicit JSIntrinsicBuilder(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
+
+  ResultAndEffect BuildGraphFor(Runtime::FunctionId id,
+                                const NodeVector& arguments);
+
+ private:
+  ResultAndEffect BuildMapCheck(Node* object, Node* effect,
+                                InstanceType map_type);
+  ResultAndEffect BuildGraphFor_IsSmi(const NodeVector& arguments);
+  ResultAndEffect BuildGraphFor_IsNonNegativeSmi(const NodeVector& arguments);
+  ResultAndEffect BuildGraphFor_ValueOf(const NodeVector& arguments);
+
+
+  Graph* graph() const { return jsgraph_->graph(); }
+  CommonOperatorBuilder* common() const { return jsgraph_->common(); }
+  JSGraph* jsgraph_;
+};
+}
+}
+}  // namespace v8::internal::compiler
+
+#endif  // V8_COMPILER_JS_INTRINSIC_BUILDER_H_
diff --git a/src/compiler/js-operator.cc b/src/compiler/js-operator.cc
new file mode 100644
index 0000000..aa76a3b
--- /dev/null
+++ b/src/compiler/js-operator.cc
@@ -0,0 +1,411 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/js-operator.h"
+
+#include <limits>
+
+#include "src/base/lazy-instance.h"
+#include "src/compiler/opcodes.h"
+#include "src/compiler/operator.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+bool operator==(CallFunctionParameters const& lhs,
+                CallFunctionParameters const& rhs) {
+  return lhs.arity() == rhs.arity() && lhs.flags() == rhs.flags();
+}
+
+
+bool operator!=(CallFunctionParameters const& lhs,
+                CallFunctionParameters const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(CallFunctionParameters const& p) {
+  return base::hash_combine(p.arity(), p.flags());
+}
+
+
+std::ostream& operator<<(std::ostream& os, CallFunctionParameters const& p) {
+  return os << p.arity() << ", " << p.flags();
+}
+
+
+const CallFunctionParameters& CallFunctionParametersOf(const Operator* op) {
+  DCHECK_EQ(IrOpcode::kJSCallFunction, op->opcode());
+  return OpParameter<CallFunctionParameters>(op);
+}
+
+
+bool operator==(CallRuntimeParameters const& lhs,
+                CallRuntimeParameters const& rhs) {
+  return lhs.id() == rhs.id() && lhs.arity() == rhs.arity();
+}
+
+
+bool operator!=(CallRuntimeParameters const& lhs,
+                CallRuntimeParameters const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(CallRuntimeParameters const& p) {
+  return base::hash_combine(p.id(), p.arity());
+}
+
+
+std::ostream& operator<<(std::ostream& os, CallRuntimeParameters const& p) {
+  return os << p.id() << ", " << p.arity();
+}
+
+
+const CallRuntimeParameters& CallRuntimeParametersOf(const Operator* op) {
+  DCHECK_EQ(IrOpcode::kJSCallRuntime, op->opcode());
+  return OpParameter<CallRuntimeParameters>(op);
+}
+
+
+ContextAccess::ContextAccess(size_t depth, size_t index, bool immutable)
+    : immutable_(immutable),
+      depth_(static_cast<uint16_t>(depth)),
+      index_(static_cast<uint32_t>(index)) {
+  DCHECK(depth <= std::numeric_limits<uint16_t>::max());
+  DCHECK(index <= std::numeric_limits<uint32_t>::max());
+}
+
+
+bool operator==(ContextAccess const& lhs, ContextAccess const& rhs) {
+  return lhs.depth() == rhs.depth() && lhs.index() == rhs.index() &&
+         lhs.immutable() == rhs.immutable();
+}
+
+
+bool operator!=(ContextAccess const& lhs, ContextAccess const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(ContextAccess const& access) {
+  return base::hash_combine(access.depth(), access.index(), access.immutable());
+}
+
+
+std::ostream& operator<<(std::ostream& os, ContextAccess const& access) {
+  return os << access.depth() << ", " << access.index() << ", "
+            << access.immutable();
+}
+
+
+ContextAccess const& ContextAccessOf(Operator const* op) {
+  DCHECK(op->opcode() == IrOpcode::kJSLoadContext ||
+         op->opcode() == IrOpcode::kJSStoreContext);
+  return OpParameter<ContextAccess>(op);
+}
+
+
+bool operator==(VectorSlotPair const& lhs, VectorSlotPair const& rhs) {
+  return lhs.slot().ToInt() == rhs.slot().ToInt() &&
+         lhs.vector().is_identical_to(rhs.vector());
+}
+
+
+size_t hash_value(VectorSlotPair const& p) {
+  // TODO(mvstanton): include the vector in the hash.
+  base::hash<int> h;
+  return h(p.slot().ToInt());
+}
+
+
+bool operator==(LoadNamedParameters const& lhs,
+                LoadNamedParameters const& rhs) {
+  return lhs.name() == rhs.name() &&
+         lhs.contextual_mode() == rhs.contextual_mode() &&
+         lhs.feedback() == rhs.feedback();
+}
+
+
+bool operator!=(LoadNamedParameters const& lhs,
+                LoadNamedParameters const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(LoadNamedParameters const& p) {
+  return base::hash_combine(p.name(), p.contextual_mode(), p.feedback());
+}
+
+
+std::ostream& operator<<(std::ostream& os, LoadNamedParameters const& p) {
+  return os << Brief(*p.name().handle()) << ", " << p.contextual_mode();
+}
+
+
+std::ostream& operator<<(std::ostream& os, LoadPropertyParameters const& p) {
+  // Nothing special to print.
+  return os;
+}
+
+
+bool operator==(LoadPropertyParameters const& lhs,
+                LoadPropertyParameters const& rhs) {
+  return lhs.feedback() == rhs.feedback();
+}
+
+
+bool operator!=(LoadPropertyParameters const& lhs,
+                LoadPropertyParameters const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+const LoadPropertyParameters& LoadPropertyParametersOf(const Operator* op) {
+  DCHECK_EQ(IrOpcode::kJSLoadProperty, op->opcode());
+  return OpParameter<LoadPropertyParameters>(op);
+}
+
+
+size_t hash_value(LoadPropertyParameters const& p) {
+  return hash_value(p.feedback());
+}
+
+
+const LoadNamedParameters& LoadNamedParametersOf(const Operator* op) {
+  DCHECK_EQ(IrOpcode::kJSLoadNamed, op->opcode());
+  return OpParameter<LoadNamedParameters>(op);
+}
+
+
+bool operator==(StoreNamedParameters const& lhs,
+                StoreNamedParameters const& rhs) {
+  return lhs.strict_mode() == rhs.strict_mode() && lhs.name() == rhs.name();
+}
+
+
+bool operator!=(StoreNamedParameters const& lhs,
+                StoreNamedParameters const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(StoreNamedParameters const& p) {
+  return base::hash_combine(p.strict_mode(), p.name());
+}
+
+
+std::ostream& operator<<(std::ostream& os, StoreNamedParameters const& p) {
+  return os << p.strict_mode() << ", " << Brief(*p.name().handle());
+}
+
+
+const StoreNamedParameters& StoreNamedParametersOf(const Operator* op) {
+  DCHECK_EQ(IrOpcode::kJSStoreNamed, op->opcode());
+  return OpParameter<StoreNamedParameters>(op);
+}
+
+
+#define CACHED_OP_LIST(V)                                 \
+  V(Equal, Operator::kNoProperties, 2, 1)                 \
+  V(NotEqual, Operator::kNoProperties, 2, 1)              \
+  V(StrictEqual, Operator::kPure, 2, 1)                   \
+  V(StrictNotEqual, Operator::kPure, 2, 1)                \
+  V(LessThan, Operator::kNoProperties, 2, 1)              \
+  V(GreaterThan, Operator::kNoProperties, 2, 1)           \
+  V(LessThanOrEqual, Operator::kNoProperties, 2, 1)       \
+  V(GreaterThanOrEqual, Operator::kNoProperties, 2, 1)    \
+  V(BitwiseOr, Operator::kNoProperties, 2, 1)             \
+  V(BitwiseXor, Operator::kNoProperties, 2, 1)            \
+  V(BitwiseAnd, Operator::kNoProperties, 2, 1)            \
+  V(ShiftLeft, Operator::kNoProperties, 2, 1)             \
+  V(ShiftRight, Operator::kNoProperties, 2, 1)            \
+  V(ShiftRightLogical, Operator::kNoProperties, 2, 1)     \
+  V(Add, Operator::kNoProperties, 2, 1)                   \
+  V(Subtract, Operator::kNoProperties, 2, 1)              \
+  V(Multiply, Operator::kNoProperties, 2, 1)              \
+  V(Divide, Operator::kNoProperties, 2, 1)                \
+  V(Modulus, Operator::kNoProperties, 2, 1)               \
+  V(UnaryNot, Operator::kPure, 1, 1)                      \
+  V(ToBoolean, Operator::kPure, 1, 1)                     \
+  V(ToNumber, Operator::kNoProperties, 1, 1)              \
+  V(ToString, Operator::kNoProperties, 1, 1)              \
+  V(ToName, Operator::kNoProperties, 1, 1)                \
+  V(ToObject, Operator::kNoProperties, 1, 1)              \
+  V(Yield, Operator::kNoProperties, 1, 1)                 \
+  V(Create, Operator::kEliminatable, 0, 1)                \
+  V(HasProperty, Operator::kNoProperties, 2, 1)           \
+  V(TypeOf, Operator::kPure, 1, 1)                        \
+  V(InstanceOf, Operator::kNoProperties, 2, 1)            \
+  V(Debugger, Operator::kNoProperties, 0, 0)              \
+  V(CreateFunctionContext, Operator::kNoProperties, 1, 1) \
+  V(CreateWithContext, Operator::kNoProperties, 2, 1)     \
+  V(CreateBlockContext, Operator::kNoProperties, 2, 1)    \
+  V(CreateModuleContext, Operator::kNoProperties, 2, 1)   \
+  V(CreateScriptContext, Operator::kNoProperties, 2, 1)
+
+
+struct JSOperatorGlobalCache FINAL {
+#define CACHED(Name, properties, value_input_count, value_output_count)  \
+  struct Name##Operator FINAL : public Operator {                        \
+    Name##Operator()                                                     \
+        : Operator(IrOpcode::kJS##Name, properties, "JS" #Name,          \
+                   value_input_count, Operator::ZeroIfPure(properties),  \
+                   Operator::ZeroIfPure(properties), value_output_count, \
+                   Operator::ZeroIfPure(properties), 0) {}               \
+  };                                                                     \
+  Name##Operator k##Name##Operator;
+  CACHED_OP_LIST(CACHED)
+#undef CACHED
+
+  template <StrictMode kStrictMode>
+  struct StorePropertyOperator FINAL : public Operator1<StrictMode> {
+    StorePropertyOperator()
+        : Operator1<StrictMode>(IrOpcode::kJSStoreProperty,
+                                Operator::kNoProperties, "JSStoreProperty", 3,
+                                1, 1, 0, 1, 0, kStrictMode) {}
+  };
+  StorePropertyOperator<SLOPPY> kStorePropertySloppyOperator;
+  StorePropertyOperator<STRICT> kStorePropertyStrictOperator;
+};
+
+
+static base::LazyInstance<JSOperatorGlobalCache>::type kCache =
+    LAZY_INSTANCE_INITIALIZER;
+
+
+JSOperatorBuilder::JSOperatorBuilder(Zone* zone)
+    : cache_(kCache.Get()), zone_(zone) {}
+
+
+#define CACHED(Name, properties, value_input_count, value_output_count) \
+  const Operator* JSOperatorBuilder::Name() {                           \
+    return &cache_.k##Name##Operator;                                   \
+  }
+CACHED_OP_LIST(CACHED)
+#undef CACHED
+
+
+const Operator* JSOperatorBuilder::CallFunction(size_t arity,
+                                                CallFunctionFlags flags) {
+  CallFunctionParameters parameters(arity, flags);
+  return new (zone()) Operator1<CallFunctionParameters>(   // --
+      IrOpcode::kJSCallFunction, Operator::kNoProperties,  // opcode
+      "JSCallFunction",                                    // name
+      parameters.arity(), 1, 1, 1, 1, 0,                   // inputs/outputs
+      parameters);                                         // parameter
+}
+
+
+const Operator* JSOperatorBuilder::CallRuntime(Runtime::FunctionId id,
+                                               size_t arity) {
+  CallRuntimeParameters parameters(id, arity);
+  const Runtime::Function* f = Runtime::FunctionForId(parameters.id());
+  DCHECK(f->nargs == -1 || f->nargs == static_cast<int>(parameters.arity()));
+  return new (zone()) Operator1<CallRuntimeParameters>(   // --
+      IrOpcode::kJSCallRuntime, Operator::kNoProperties,  // opcode
+      "JSCallRuntime",                                    // name
+      parameters.arity(), 1, 1, f->result_size, 1, 0,     // inputs/outputs
+      parameters);                                        // parameter
+}
+
+
+const Operator* JSOperatorBuilder::CallConstruct(int arguments) {
+  return new (zone()) Operator1<int>(                       // --
+      IrOpcode::kJSCallConstruct, Operator::kNoProperties,  // opcode
+      "JSCallConstruct",                                    // name
+      arguments, 1, 1, 1, 1, 0,                             // counts
+      arguments);                                           // parameter
+}
+
+
+const Operator* JSOperatorBuilder::LoadNamed(const Unique<Name>& name,
+                                             const VectorSlotPair& feedback,
+                                             ContextualMode contextual_mode) {
+  LoadNamedParameters parameters(name, feedback, contextual_mode);
+  return new (zone()) Operator1<LoadNamedParameters>(   // --
+      IrOpcode::kJSLoadNamed, Operator::kNoProperties,  // opcode
+      "JSLoadNamed",                                    // name
+      1, 1, 1, 1, 1, 0,                                 // counts
+      parameters);                                      // parameter
+}
+
+
+const Operator* JSOperatorBuilder::LoadProperty(
+    const VectorSlotPair& feedback) {
+  LoadPropertyParameters parameters(feedback);
+  return new (zone()) Operator1<LoadPropertyParameters>(   // --
+      IrOpcode::kJSLoadProperty, Operator::kNoProperties,  // opcode
+      "JSLoadProperty",                                    // name
+      2, 1, 1, 1, 1, 0,                                    // counts
+      parameters);                                         // parameter
+}
+
+
+const Operator* JSOperatorBuilder::StoreProperty(StrictMode strict_mode) {
+  switch (strict_mode) {
+    case SLOPPY:
+      return &cache_.kStorePropertySloppyOperator;
+    case STRICT:
+      return &cache_.kStorePropertyStrictOperator;
+  }
+  UNREACHABLE();
+  return nullptr;
+}
+
+
+const Operator* JSOperatorBuilder::StoreNamed(StrictMode strict_mode,
+                                              const Unique<Name>& name) {
+  StoreNamedParameters parameters(strict_mode, name);
+  return new (zone()) Operator1<StoreNamedParameters>(   // --
+      IrOpcode::kJSStoreNamed, Operator::kNoProperties,  // opcode
+      "JSStoreNamed",                                    // name
+      2, 1, 1, 0, 1, 0,                                  // counts
+      parameters);                                       // parameter
+}
+
+
+const Operator* JSOperatorBuilder::DeleteProperty(StrictMode strict_mode) {
+  return new (zone()) Operator1<StrictMode>(                 // --
+      IrOpcode::kJSDeleteProperty, Operator::kNoProperties,  // opcode
+      "JSDeleteProperty",                                    // name
+      2, 1, 1, 1, 1, 0,                                      // counts
+      strict_mode);                                          // parameter
+}
+
+
+const Operator* JSOperatorBuilder::LoadContext(size_t depth, size_t index,
+                                               bool immutable) {
+  ContextAccess access(depth, index, immutable);
+  return new (zone()) Operator1<ContextAccess>(      // --
+      IrOpcode::kJSLoadContext, Operator::kNoWrite,  // opcode
+      "JSLoadContext",                               // name
+      1, 1, 0, 1, 1, 0,                              // counts
+      access);                                       // parameter
+}
+
+
+const Operator* JSOperatorBuilder::StoreContext(size_t depth, size_t index) {
+  ContextAccess access(depth, index, false);
+  return new (zone()) Operator1<ContextAccess>(      // --
+      IrOpcode::kJSStoreContext, Operator::kNoRead,  // opcode
+      "JSStoreContext",                              // name
+      2, 1, 1, 0, 1, 0,                              // counts
+      access);                                       // parameter
+}
+
+
+const Operator* JSOperatorBuilder::CreateCatchContext(
+    const Unique<String>& name) {
+  return new (zone()) Operator1<Unique<String>>(                 // --
+      IrOpcode::kJSCreateCatchContext, Operator::kNoProperties,  // opcode
+      "JSCreateCatchContext",                                    // name
+      1, 1, 1, 1, 1, 0,                                          // counts
+      name);                                                     // parameter
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/js-operator.h b/src/compiler/js-operator.h
index b95467f..e716a8e 100644
--- a/src/compiler/js-operator.h
+++ b/src/compiler/js-operator.h
@@ -5,28 +5,77 @@
 #ifndef V8_COMPILER_JS_OPERATOR_H_
 #define V8_COMPILER_JS_OPERATOR_H_
 
-#include "src/compiler/linkage.h"
-#include "src/compiler/opcodes.h"
-#include "src/compiler/operator.h"
+#include "src/runtime/runtime.h"
 #include "src/unique.h"
-#include "src/zone.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
+// Forward declarations.
+class Operator;
+struct JSOperatorGlobalCache;
+
+
+// Defines the arity and the call flags for a JavaScript function call. This is
+// used as a parameter by JSCallFunction operators.
+class CallFunctionParameters FINAL {
+ public:
+  CallFunctionParameters(size_t arity, CallFunctionFlags flags)
+      : arity_(arity), flags_(flags) {}
+
+  size_t arity() const { return arity_; }
+  CallFunctionFlags flags() const { return flags_; }
+
+ private:
+  const size_t arity_;
+  const CallFunctionFlags flags_;
+};
+
+bool operator==(CallFunctionParameters const&, CallFunctionParameters const&);
+bool operator!=(CallFunctionParameters const&, CallFunctionParameters const&);
+
+size_t hash_value(CallFunctionParameters const&);
+
+std::ostream& operator<<(std::ostream&, CallFunctionParameters const&);
+
+const CallFunctionParameters& CallFunctionParametersOf(const Operator* op);
+
+
+// Defines the arity and the ID for a runtime function call. This is used as a
+// parameter by JSCallRuntime operators.
+class CallRuntimeParameters FINAL {
+ public:
+  CallRuntimeParameters(Runtime::FunctionId id, size_t arity)
+      : id_(id), arity_(arity) {}
+
+  Runtime::FunctionId id() const { return id_; }
+  size_t arity() const { return arity_; }
+
+ private:
+  const Runtime::FunctionId id_;
+  const size_t arity_;
+};
+
+bool operator==(CallRuntimeParameters const&, CallRuntimeParameters const&);
+bool operator!=(CallRuntimeParameters const&, CallRuntimeParameters const&);
+
+size_t hash_value(CallRuntimeParameters const&);
+
+std::ostream& operator<<(std::ostream&, CallRuntimeParameters const&);
+
+const CallRuntimeParameters& CallRuntimeParametersOf(const Operator* op);
+
+
 // Defines the location of a context slot relative to a specific scope. This is
 // used as a parameter by JSLoadContext and JSStoreContext operators and allows
 // accessing a context-allocated variable without keeping track of the scope.
-class ContextAccess {
+class ContextAccess FINAL {
  public:
-  ContextAccess(int depth, int index, bool immutable)
-      : immutable_(immutable), depth_(depth), index_(index) {
-    DCHECK(0 <= depth && depth <= kMaxUInt16);
-    DCHECK(0 <= index && static_cast<uint32_t>(index) <= kMaxUInt32);
-  }
-  int depth() const { return depth_; }
-  int index() const { return index_; }
+  ContextAccess(size_t depth, size_t index, bool immutable);
+
+  size_t depth() const { return depth_; }
+  size_t index() const { return index_; }
   bool immutable() const { return immutable_; }
 
  private:
@@ -37,193 +86,188 @@
   const uint32_t index_;
 };
 
-// Defines the property being loaded from an object by a named load. This is
-// used as a parameter by JSLoadNamed operators.
-struct LoadNamedParameters {
-  Unique<Name> name;
-  ContextualMode contextual_mode;
+bool operator==(ContextAccess const&, ContextAccess const&);
+bool operator!=(ContextAccess const&, ContextAccess const&);
+
+size_t hash_value(ContextAccess const&);
+
+std::ostream& operator<<(std::ostream&, ContextAccess const&);
+
+ContextAccess const& ContextAccessOf(Operator const*);
+
+
+class VectorSlotPair {
+ public:
+  VectorSlotPair(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
+      : vector_(vector), slot_(slot) {}
+
+  Handle<TypeFeedbackVector> vector() const { return vector_; }
+  FeedbackVectorICSlot slot() const { return slot_; }
+
+  int index() const { return vector_->GetIndex(slot_); }
+
+ private:
+  const Handle<TypeFeedbackVector> vector_;
+  const FeedbackVectorICSlot slot_;
 };
 
-// Defines the arity and the call flags for a JavaScript function call. This is
-// used as a parameter by JSCall operators.
-struct CallParameters {
-  int arity;
-  CallFunctionFlags flags;
+
+bool operator==(VectorSlotPair const& lhs, VectorSlotPair const& rhs);
+
+
+// Defines the property being loaded from an object by a named load. This is
+// used as a parameter by JSLoadNamed operators.
+class LoadNamedParameters FINAL {
+ public:
+  LoadNamedParameters(const Unique<Name>& name, const VectorSlotPair& feedback,
+                      ContextualMode contextual_mode)
+      : name_(name), contextual_mode_(contextual_mode), feedback_(feedback) {}
+
+  const Unique<Name>& name() const { return name_; }
+  ContextualMode contextual_mode() const { return contextual_mode_; }
+
+  const VectorSlotPair& feedback() const { return feedback_; }
+
+ private:
+  const Unique<Name> name_;
+  const ContextualMode contextual_mode_;
+  const VectorSlotPair feedback_;
 };
 
+bool operator==(LoadNamedParameters const&, LoadNamedParameters const&);
+bool operator!=(LoadNamedParameters const&, LoadNamedParameters const&);
+
+size_t hash_value(LoadNamedParameters const&);
+
+std::ostream& operator<<(std::ostream&, LoadNamedParameters const&);
+
+const LoadNamedParameters& LoadNamedParametersOf(const Operator* op);
+
+
+// Defines the property being loaded from an object. This is
+// used as a parameter by JSLoadProperty operators.
+class LoadPropertyParameters FINAL {
+ public:
+  explicit LoadPropertyParameters(const VectorSlotPair& feedback)
+      : feedback_(feedback) {}
+
+  const VectorSlotPair& feedback() const { return feedback_; }
+
+ private:
+  const VectorSlotPair feedback_;
+};
+
+bool operator==(LoadPropertyParameters const&, LoadPropertyParameters const&);
+bool operator!=(LoadPropertyParameters const&, LoadPropertyParameters const&);
+
+size_t hash_value(LoadPropertyParameters const&);
+
+std::ostream& operator<<(std::ostream&, LoadPropertyParameters const&);
+
+const LoadPropertyParameters& LoadPropertyParametersOf(const Operator* op);
+
+
 // Defines the property being stored to an object by a named store. This is
 // used as a parameter by JSStoreNamed operators.
-struct StoreNamedParameters {
-  StrictMode strict_mode;
-  Unique<Name> name;
+class StoreNamedParameters FINAL {
+ public:
+  StoreNamedParameters(StrictMode strict_mode, const Unique<Name>& name)
+      : strict_mode_(strict_mode), name_(name) {}
+
+  StrictMode strict_mode() const { return strict_mode_; }
+  const Unique<Name>& name() const { return name_; }
+
+ private:
+  const StrictMode strict_mode_;
+  const Unique<Name> name_;
 };
 
+bool operator==(StoreNamedParameters const&, StoreNamedParameters const&);
+bool operator!=(StoreNamedParameters const&, StoreNamedParameters const&);
+
+size_t hash_value(StoreNamedParameters const&);
+
+std::ostream& operator<<(std::ostream&, StoreNamedParameters const&);
+
+const StoreNamedParameters& StoreNamedParametersOf(const Operator* op);
+
+
 // Interface for building JavaScript-level operators, e.g. directly from the
 // AST. Most operators have no parameters, thus can be globally shared for all
 // graphs.
-class JSOperatorBuilder {
+class JSOperatorBuilder FINAL : public ZoneObject {
  public:
-  explicit JSOperatorBuilder(Zone* zone) : zone_(zone) {}
+  explicit JSOperatorBuilder(Zone* zone);
 
-#define SIMPLE(name, properties, inputs, outputs) \
-  return new (zone_)                              \
-      SimpleOperator(IrOpcode::k##name, properties, inputs, outputs, #name);
+  const Operator* Equal();
+  const Operator* NotEqual();
+  const Operator* StrictEqual();
+  const Operator* StrictNotEqual();
+  const Operator* LessThan();
+  const Operator* GreaterThan();
+  const Operator* LessThanOrEqual();
+  const Operator* GreaterThanOrEqual();
+  const Operator* BitwiseOr();
+  const Operator* BitwiseXor();
+  const Operator* BitwiseAnd();
+  const Operator* ShiftLeft();
+  const Operator* ShiftRight();
+  const Operator* ShiftRightLogical();
+  const Operator* Add();
+  const Operator* Subtract();
+  const Operator* Multiply();
+  const Operator* Divide();
+  const Operator* Modulus();
 
-#define NOPROPS(name, inputs, outputs) \
-  SIMPLE(name, Operator::kNoProperties, inputs, outputs)
+  const Operator* UnaryNot();
+  const Operator* ToBoolean();
+  const Operator* ToNumber();
+  const Operator* ToString();
+  const Operator* ToName();
+  const Operator* ToObject();
+  const Operator* Yield();
 
-#define OP1(name, ptype, pname, properties, inputs, outputs)                 \
-  return new (zone_) Operator1<ptype>(IrOpcode::k##name, properties, inputs, \
-                                      outputs, #name, pname)
+  const Operator* Create();
 
-#define BINOP(name) NOPROPS(name, 2, 1)
-#define UNOP(name) NOPROPS(name, 1, 1)
+  const Operator* CallFunction(size_t arity, CallFunctionFlags flags);
+  const Operator* CallRuntime(Runtime::FunctionId id, size_t arity);
 
-#define PURE_BINOP(name) SIMPLE(name, Operator::kPure, 2, 1)
+  const Operator* CallConstruct(int arguments);
 
-  const Operator* Equal() { BINOP(JSEqual); }
-  const Operator* NotEqual() { BINOP(JSNotEqual); }
-  const Operator* StrictEqual() { PURE_BINOP(JSStrictEqual); }
-  const Operator* StrictNotEqual() { PURE_BINOP(JSStrictNotEqual); }
-  const Operator* LessThan() { BINOP(JSLessThan); }
-  const Operator* GreaterThan() { BINOP(JSGreaterThan); }
-  const Operator* LessThanOrEqual() { BINOP(JSLessThanOrEqual); }
-  const Operator* GreaterThanOrEqual() { BINOP(JSGreaterThanOrEqual); }
-  const Operator* BitwiseOr() { BINOP(JSBitwiseOr); }
-  const Operator* BitwiseXor() { BINOP(JSBitwiseXor); }
-  const Operator* BitwiseAnd() { BINOP(JSBitwiseAnd); }
-  const Operator* ShiftLeft() { BINOP(JSShiftLeft); }
-  const Operator* ShiftRight() { BINOP(JSShiftRight); }
-  const Operator* ShiftRightLogical() { BINOP(JSShiftRightLogical); }
-  const Operator* Add() { BINOP(JSAdd); }
-  const Operator* Subtract() { BINOP(JSSubtract); }
-  const Operator* Multiply() { BINOP(JSMultiply); }
-  const Operator* Divide() { BINOP(JSDivide); }
-  const Operator* Modulus() { BINOP(JSModulus); }
+  const Operator* LoadProperty(const VectorSlotPair& feedback);
+  const Operator* LoadNamed(const Unique<Name>& name,
+                            const VectorSlotPair& feedback,
+                            ContextualMode contextual_mode = NOT_CONTEXTUAL);
 
-  const Operator* UnaryNot() { UNOP(JSUnaryNot); }
-  const Operator* ToBoolean() { UNOP(JSToBoolean); }
-  const Operator* ToNumber() { UNOP(JSToNumber); }
-  const Operator* ToString() { UNOP(JSToString); }
-  const Operator* ToName() { UNOP(JSToName); }
-  const Operator* ToObject() { UNOP(JSToObject); }
-  const Operator* Yield() { UNOP(JSYield); }
+  const Operator* StoreProperty(StrictMode strict_mode);
+  const Operator* StoreNamed(StrictMode strict_mode, const Unique<Name>& name);
 
-  const Operator* Create() { SIMPLE(JSCreate, Operator::kEliminatable, 0, 1); }
+  const Operator* DeleteProperty(StrictMode strict_mode);
 
-  const Operator* Call(int arguments, CallFunctionFlags flags) {
-    CallParameters parameters = {arguments, flags};
-    OP1(JSCallFunction, CallParameters, parameters, Operator::kNoProperties,
-        arguments, 1);
-  }
+  const Operator* HasProperty();
 
-  const Operator* CallNew(int arguments) {
-    return new (zone_)
-        Operator1<int>(IrOpcode::kJSCallConstruct, Operator::kNoProperties,
-                       arguments, 1, "JSCallConstruct", arguments);
-  }
+  const Operator* LoadContext(size_t depth, size_t index, bool immutable);
+  const Operator* StoreContext(size_t depth, size_t index);
 
-  const Operator* LoadProperty() { BINOP(JSLoadProperty); }
-  const Operator* LoadNamed(Unique<Name> name,
-                            ContextualMode contextual_mode = NOT_CONTEXTUAL) {
-    LoadNamedParameters parameters = {name, contextual_mode};
-    OP1(JSLoadNamed, LoadNamedParameters, parameters, Operator::kNoProperties,
-        1, 1);
-  }
-
-  const Operator* StoreProperty(StrictMode strict_mode) {
-    OP1(JSStoreProperty, StrictMode, strict_mode, Operator::kNoProperties, 3,
-        0);
-  }
-
-  const Operator* StoreNamed(StrictMode strict_mode, Unique<Name> name) {
-    StoreNamedParameters parameters = {strict_mode, name};
-    OP1(JSStoreNamed, StoreNamedParameters, parameters, Operator::kNoProperties,
-        2, 0);
-  }
-
-  const Operator* DeleteProperty(StrictMode strict_mode) {
-    OP1(JSDeleteProperty, StrictMode, strict_mode, Operator::kNoProperties, 2,
-        1);
-  }
-
-  const Operator* HasProperty() { NOPROPS(JSHasProperty, 2, 1); }
-
-  const Operator* LoadContext(uint16_t depth, uint32_t index, bool immutable) {
-    ContextAccess access(depth, index, immutable);
-    OP1(JSLoadContext, ContextAccess, access,
-        Operator::kEliminatable | Operator::kNoWrite, 1, 1);
-  }
-  const Operator* StoreContext(uint16_t depth, uint32_t index) {
-    ContextAccess access(depth, index, false);
-    OP1(JSStoreContext, ContextAccess, access, Operator::kNoProperties, 2, 0);
-  }
-
-  const Operator* TypeOf() { SIMPLE(JSTypeOf, Operator::kPure, 1, 1); }
-  const Operator* InstanceOf() { NOPROPS(JSInstanceOf, 2, 1); }
-  const Operator* Debugger() { NOPROPS(JSDebugger, 0, 0); }
+  const Operator* TypeOf();
+  const Operator* InstanceOf();
+  const Operator* Debugger();
 
   // TODO(titzer): nail down the static parts of each of these context flavors.
-  const Operator* CreateFunctionContext() {
-    NOPROPS(JSCreateFunctionContext, 1, 1);
-  }
-  const Operator* CreateCatchContext(Unique<String> name) {
-    OP1(JSCreateCatchContext, Unique<String>, name, Operator::kNoProperties, 1,
-        1);
-  }
-  const Operator* CreateWithContext() { NOPROPS(JSCreateWithContext, 2, 1); }
-  const Operator* CreateBlockContext() { NOPROPS(JSCreateBlockContext, 2, 1); }
-  const Operator* CreateModuleContext() {
-    NOPROPS(JSCreateModuleContext, 2, 1);
-  }
-  const Operator* CreateGlobalContext() {
-    NOPROPS(JSCreateGlobalContext, 2, 1);
-  }
-
-  const Operator* Runtime(Runtime::FunctionId function, int arguments) {
-    const Runtime::Function* f = Runtime::FunctionForId(function);
-    DCHECK(f->nargs == -1 || f->nargs == arguments);
-    OP1(JSCallRuntime, Runtime::FunctionId, function, Operator::kNoProperties,
-        arguments, f->result_size);
-  }
-
-#undef SIMPLE
-#undef NOPROPS
-#undef OP1
-#undef BINOP
-#undef UNOP
+  const Operator* CreateFunctionContext();
+  const Operator* CreateCatchContext(const Unique<String>& name);
+  const Operator* CreateWithContext();
+  const Operator* CreateBlockContext();
+  const Operator* CreateModuleContext();
+  const Operator* CreateScriptContext();
 
  private:
-  Zone* zone_;
-};
+  Zone* zone() const { return zone_; }
 
-// Specialization for static parameters of type {ContextAccess}.
-template <>
-struct StaticParameterTraits<ContextAccess> {
-  static OStream& PrintTo(OStream& os, ContextAccess val) {  // NOLINT
-    return os << val.depth() << "," << val.index()
-              << (val.immutable() ? ",imm" : "");
-  }
-  static int HashCode(ContextAccess val) {
-    return (val.depth() << 16) | (val.index() & 0xffff);
-  }
-  static bool Equals(ContextAccess a, ContextAccess b) {
-    return a.immutable() == b.immutable() && a.depth() == b.depth() &&
-           a.index() == b.index();
-  }
-};
+  const JSOperatorGlobalCache& cache_;
+  Zone* const zone_;
 
-// Specialization for static parameters of type {Runtime::FunctionId}.
-template <>
-struct StaticParameterTraits<Runtime::FunctionId> {
-  static OStream& PrintTo(OStream& os, Runtime::FunctionId val) {  // NOLINT
-    const Runtime::Function* f = Runtime::FunctionForId(val);
-    return os << (f->name ? f->name : "?Runtime?");
-  }
-  static int HashCode(Runtime::FunctionId val) { return static_cast<int>(val); }
-  static bool Equals(Runtime::FunctionId a, Runtime::FunctionId b) {
-    return a == b;
-  }
+  DISALLOW_COPY_AND_ASSIGN(JSOperatorBuilder);
 };
 
 }  // namespace compiler
diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc
index be12534..7618375 100644
--- a/src/compiler/js-typed-lowering.cc
+++ b/src/compiler/js-typed-lowering.cc
@@ -4,9 +4,10 @@
 
 #include "src/compiler/access-builder.h"
 #include "src/compiler/graph-inl.h"
-#include "src/compiler/js-builtin-reducer.h"
+#include "src/compiler/js-graph.h"
 #include "src/compiler/js-typed-lowering.h"
 #include "src/compiler/node-aux-data-inl.h"
+#include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/types.h"
 
@@ -17,7 +18,6 @@
 // TODO(turbofan): js-typed-lowering improvements possible
 // - immediately put in type bounds for all new nodes
 // - relax effects from generic but not-side-effecting operations
-// - relax effects for ToNumber(mixed)
 
 
 // Relax the effects of {node} by immediately replacing effect uses of {node}
@@ -29,7 +29,32 @@
 }
 
 
-JSTypedLowering::~JSTypedLowering() {}
+JSTypedLowering::JSTypedLowering(JSGraph* jsgraph, Zone* zone)
+    : jsgraph_(jsgraph), simplified_(graph()->zone()), conversions_(zone) {
+  Handle<Object> zero = factory()->NewNumber(0.0);
+  Handle<Object> one = factory()->NewNumber(1.0);
+  zero_range_ = Type::Range(zero, zero, graph()->zone());
+  one_range_ = Type::Range(one, one, graph()->zone());
+  Handle<Object> thirtyone = factory()->NewNumber(31.0);
+  zero_thirtyone_range_ = Type::Range(zero, thirtyone, graph()->zone());
+  // TODO(jarin): Can we have a correctification of the stupid type system?
+  // These stupid work-arounds are just stupid!
+  shifted_int32_ranges_[0] = Type::Signed32();
+  if (SmiValuesAre31Bits()) {
+    shifted_int32_ranges_[1] = Type::SignedSmall();
+    for (size_t k = 2; k < arraysize(shifted_int32_ranges_); ++k) {
+      Handle<Object> min = factory()->NewNumber(kMinInt / (1 << k));
+      Handle<Object> max = factory()->NewNumber(kMaxInt / (1 << k));
+      shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
+    }
+  } else {
+    for (size_t k = 1; k < arraysize(shifted_int32_ranges_); ++k) {
+      Handle<Object> min = factory()->NewNumber(kMinInt / (1 << k));
+      Handle<Object> max = factory()->NewNumber(kMaxInt / (1 << k));
+      shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
+    }
+  }
+}
 
 
 Reduction JSTypedLowering::ReplaceEagerly(Node* old, Node* node) {
@@ -42,7 +67,7 @@
 // JSOperator. This class manages the rewriting of context, control, and effect
 // dependencies during lowering of a binop and contains numerous helper
 // functions for matching the types of inputs to an operation.
-class JSBinopReduction {
+class JSBinopReduction FINAL {
  public:
   JSBinopReduction(JSTypedLowering* lowering, Node* node)
       : lowering_(lowering),
@@ -55,9 +80,10 @@
     node_->ReplaceInput(1, ConvertToNumber(right()));
   }
 
-  void ConvertInputsToInt32(bool left_signed, bool right_signed) {
-    node_->ReplaceInput(0, ConvertToI32(left_signed, left()));
-    node_->ReplaceInput(1, ConvertToI32(right_signed, right()));
+  void ConvertInputsToUI32(Signedness left_signedness,
+                           Signedness right_signedness) {
+    node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
+    node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness));
   }
 
   void ConvertInputsToString() {
@@ -66,11 +92,15 @@
   }
 
   // Convert inputs for bitwise shift operation (ES5 spec 11.7).
-  void ConvertInputsForShift(bool left_signed) {
-    node_->ReplaceInput(0, ConvertToI32(left_signed, left()));
-    Node* rnum = ConvertToI32(false, right());
-    node_->ReplaceInput(1, graph()->NewNode(machine()->Word32And(), rnum,
-                                            jsgraph()->Int32Constant(0x1F)));
+  void ConvertInputsForShift(Signedness left_signedness) {
+    node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
+    Node* rnum = ConvertToUI32(right(), kUnsigned);
+    Type* rnum_type = NodeProperties::GetBounds(rnum).upper;
+    if (!rnum_type->Is(lowering_->zero_thirtyone_range_)) {
+      rnum = graph()->NewNode(machine()->Word32And(), rnum,
+                              jsgraph()->Int32Constant(0x1F));
+    }
+    node_->ReplaceInput(1, rnum);
   }
 
   void SwapInputs() {
@@ -83,14 +113,15 @@
 
   // Remove all effect and control inputs and outputs to this node and change
   // to the pure operator {op}, possibly inserting a boolean inversion.
-  Reduction ChangeToPureOperator(const Operator* op, bool invert = false) {
-    DCHECK_EQ(0, OperatorProperties::GetEffectInputCount(op));
+  Reduction ChangeToPureOperator(const Operator* op, bool invert = false,
+                                 Type* type = Type::Any()) {
+    DCHECK_EQ(0, op->EffectInputCount());
     DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
-    DCHECK_EQ(0, OperatorProperties::GetControlInputCount(op));
-    DCHECK_EQ(2, OperatorProperties::GetValueInputCount(op));
+    DCHECK_EQ(0, op->ControlInputCount());
+    DCHECK_EQ(2, op->ValueInputCount());
 
     // Remove the effects from the node, if any, and update its effect usages.
-    if (OperatorProperties::GetEffectInputCount(node_->op()) > 0) {
+    if (node_->op()->EffectInputCount() > 0) {
       RelaxEffects(node_);
     }
     // Remove the inputs corresponding to context, effect, and control.
@@ -98,17 +129,26 @@
     // Finally, update the operator to the new one.
     node_->set_op(op);
 
+    // TODO(jarin): Replace the explicit typing hack with a call to some method
+    // that encapsulates changing the operator and re-typing.
+    Bounds const bounds = NodeProperties::GetBounds(node_);
+    NodeProperties::SetBounds(node_, Bounds::NarrowUpper(bounds, type, zone()));
+
     if (invert) {
       // Insert an boolean not to invert the value.
       Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
       node_->ReplaceUses(value);
       // Note: ReplaceUses() smashes all uses, so smash it back here.
       value->ReplaceInput(0, node_);
-      return lowering_->ReplaceWith(value);
+      return lowering_->Replace(value);
     }
     return lowering_->Changed(node_);
   }
 
+  Reduction ChangeToPureOperator(const Operator* op, Type* type) {
+    return ChangeToPureOperator(op, false, type);
+  }
+
   bool OneInputIs(Type* t) { return left_type_->Is(t) || right_type_->Is(t); }
 
   bool BothInputsAre(Type* t) {
@@ -132,10 +172,11 @@
   Type* right_type() { return right_type_; }
 
   SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
-  Graph* graph() { return lowering_->graph(); }
+  Graph* graph() const { return lowering_->graph(); }
   JSGraph* jsgraph() { return lowering_->jsgraph(); }
   JSOperatorBuilder* javascript() { return lowering_->javascript(); }
   MachineOperatorBuilder* machine() { return lowering_->machine(); }
+  Zone* zone() const { return graph()->zone(); }
 
  private:
   JSTypedLowering* lowering_;  // The containing lowering instance.
@@ -154,65 +195,30 @@
   }
 
   Node* ConvertToNumber(Node* node) {
-    // Avoid introducing too many eager ToNumber() operations.
-    Reduction reduced = lowering_->ReduceJSToNumberInput(node);
-    if (reduced.Changed()) return reduced.replacement();
+    if (NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())) {
+      return lowering_->ConvertToNumber(node);
+    }
     Node* n = graph()->NewNode(javascript()->ToNumber(), node, context(),
                                effect(), control());
     update_effect(n);
     return n;
   }
 
-  // Try to narrowing a double or number operation to an Int32 operation.
-  bool TryNarrowingToI32(Type* type, Node* node) {
-    switch (node->opcode()) {
-      case IrOpcode::kFloat64Add:
-      case IrOpcode::kNumberAdd: {
-        JSBinopReduction r(lowering_, node);
-        if (r.BothInputsAre(Type::Integral32())) {
-          node->set_op(lowering_->machine()->Int32Add());
-          // TODO(titzer): narrow bounds instead of overwriting.
-          NodeProperties::SetBounds(node, Bounds(type));
-          return true;
-        }
-      }
-      case IrOpcode::kFloat64Sub:
-      case IrOpcode::kNumberSubtract: {
-        JSBinopReduction r(lowering_, node);
-        if (r.BothInputsAre(Type::Integral32())) {
-          node->set_op(lowering_->machine()->Int32Sub());
-          // TODO(titzer): narrow bounds instead of overwriting.
-          NodeProperties::SetBounds(node, Bounds(type));
-          return true;
-        }
-      }
-      default:
-        return false;
-    }
-  }
-
-  Node* ConvertToI32(bool is_signed, Node* node) {
-    Type* type = is_signed ? Type::Signed32() : Type::Unsigned32();
-    if (node->OwnedBy(node_)) {
-      // If this node {node_} has the only edge to {node}, then try narrowing
-      // its operation to an Int32 add or subtract.
-      if (TryNarrowingToI32(type, node)) return node;
-    } else {
-      // Otherwise, {node} has multiple uses. Leave it as is and let the
-      // further lowering passes deal with it, which use a full backwards
-      // fixpoint.
-    }
-
+  Node* ConvertToUI32(Node* node, Signedness signedness) {
     // Avoid introducing too many eager NumberToXXnt32() operations.
     node = ConvertToNumber(node);
-    Type* input_type = NodeProperties::GetBounds(node).upper;
-
-    if (input_type->Is(type)) return node;  // already in the value range.
-
-    const Operator* op = is_signed ? simplified()->NumberToInt32()
-                                   : simplified()->NumberToUint32();
-    Node* n = graph()->NewNode(op, node);
-    return n;
+    Type* type = NodeProperties::GetBounds(node).upper;
+    if (signedness == kSigned) {
+      if (!type->Is(Type::Signed32())) {
+        node = graph()->NewNode(simplified()->NumberToInt32(), node);
+      }
+    } else {
+      DCHECK_EQ(kUnsigned, signedness);
+      if (!type->Is(Type::Unsigned32())) {
+        node = graph()->NewNode(simplified()->NumberToUint32(), node);
+      }
+    }
+    return node;
   }
 
   void update_effect(Node* effect) {
@@ -225,15 +231,24 @@
   JSBinopReduction r(this, node);
   if (r.BothInputsAre(Type::Number())) {
     // JSAdd(x:number, y:number) => NumberAdd(x, y)
-    return r.ChangeToPureOperator(simplified()->NumberAdd());
+    return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
   }
-  Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone());
-  if (r.NeitherInputCanBe(maybe_string)) {
+  if (r.BothInputsAre(Type::Primitive()) &&
+      r.NeitherInputCanBe(Type::StringOrReceiver())) {
     // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
     r.ConvertInputsToNumber();
-    return r.ChangeToPureOperator(simplified()->NumberAdd());
+    return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
   }
 #if 0
+  // TODO(turbofan): General ToNumber disabled for now because:
+  //   a) The inserted ToNumber operation screws up observability of valueOf.
+  //   b) Deoptimization at ToNumber doesn't have corresponding bailout id.
+  Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone());
+  if (r.NeitherInputCanBe(maybe_string)) {
+    ...
+  }
+#endif
+#if 0
   // TODO(turbofan): Lowering of StringAdd is disabled for now because:
   //   a) The inserted ToString operation screws up valueOf vs. toString order.
   //   b) Deoptimization at ToString doesn't have corresponding bailout id.
@@ -250,9 +265,48 @@
 }
 
 
+Reduction JSTypedLowering::ReduceJSBitwiseOr(Node* node) {
+  JSBinopReduction r(this, node);
+  if (r.BothInputsAre(Type::Primitive()) || r.OneInputIs(zero_range_)) {
+    // TODO(jarin): Propagate frame state input from non-primitive input node to
+    // JSToNumber node.
+    // TODO(titzer): some Smi bitwise operations don't really require going
+    // all the way to int32, which can save tagging/untagging for some
+    // operations
+    // on some platforms.
+    // TODO(turbofan): make this heuristic configurable for code size.
+    r.ConvertInputsToUI32(kSigned, kSigned);
+    return r.ChangeToPureOperator(machine()->Word32Or(), Type::Integral32());
+  }
+  return NoChange();
+}
+
+
+Reduction JSTypedLowering::ReduceJSMultiply(Node* node) {
+  JSBinopReduction r(this, node);
+  if (r.BothInputsAre(Type::Primitive()) || r.OneInputIs(one_range_)) {
+    // TODO(jarin): Propagate frame state input from non-primitive input node to
+    // JSToNumber node.
+    r.ConvertInputsToNumber();
+    return r.ChangeToPureOperator(simplified()->NumberMultiply(),
+                                  Type::Number());
+  }
+  // TODO(turbofan): relax/remove the effects of this operator in other cases.
+  return NoChange();
+}
+
+
 Reduction JSTypedLowering::ReduceNumberBinop(Node* node,
                                              const Operator* numberOp) {
   JSBinopReduction r(this, node);
+  if (r.BothInputsAre(Type::Primitive())) {
+    r.ConvertInputsToNumber();
+    return r.ChangeToPureOperator(numberOp, Type::Number());
+  }
+#if 0
+  // TODO(turbofan): General ToNumber disabled for now because:
+  //   a) The inserted ToNumber operation screws up observability of valueOf.
+  //   b) Deoptimization at ToNumber doesn't have corresponding bailout id.
   if (r.OneInputIs(Type::Primitive())) {
     // If at least one input is a primitive, then insert appropriate conversions
     // to number and reduce this operator to the given numeric one.
@@ -260,29 +314,36 @@
     r.ConvertInputsToNumber();
     return r.ChangeToPureOperator(numberOp);
   }
+#endif
   // TODO(turbofan): relax/remove the effects of this operator in other cases.
   return NoChange();
 }
 
 
-Reduction JSTypedLowering::ReduceI32Binop(Node* node, bool left_signed,
-                                          bool right_signed,
-                                          const Operator* intOp) {
+Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
   JSBinopReduction r(this, node);
-  // TODO(titzer): some Smi bitwise operations don't really require going
-  // all the way to int32, which can save tagging/untagging for some operations
-  // on some platforms.
-  // TODO(turbofan): make this heuristic configurable for code size.
-  r.ConvertInputsToInt32(left_signed, right_signed);
-  return r.ChangeToPureOperator(intOp);
+  if (r.BothInputsAre(Type::Primitive())) {
+    // TODO(titzer): some Smi bitwise operations don't really require going
+    // all the way to int32, which can save tagging/untagging for some
+    // operations
+    // on some platforms.
+    // TODO(turbofan): make this heuristic configurable for code size.
+    r.ConvertInputsToUI32(kSigned, kSigned);
+    return r.ChangeToPureOperator(intOp, Type::Integral32());
+  }
+  return NoChange();
 }
 
 
-Reduction JSTypedLowering::ReduceI32Shift(Node* node, bool left_signed,
-                                          const Operator* shift_op) {
+Reduction JSTypedLowering::ReduceUI32Shift(Node* node,
+                                           Signedness left_signedness,
+                                           const Operator* shift_op) {
   JSBinopReduction r(this, node);
-  r.ConvertInputsForShift(left_signed);
-  return r.ChangeToPureOperator(shift_op);
+  if (r.BothInputsAre(Type::Primitive())) {
+    r.ConvertInputsForShift(left_signedness);
+    return r.ChangeToPureOperator(shift_op, Type::Integral32());
+  }
+  return NoChange();
 }
 
 
@@ -311,9 +372,18 @@
     }
     return r.ChangeToPureOperator(stringOp);
   }
+#if 0
+  // TODO(turbofan): General ToNumber disabled for now because:
+  //   a) The inserted ToNumber operation screws up observability of valueOf.
+  //   b) Deoptimization at ToNumber doesn't have corresponding bailout id.
   Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone());
   if (r.OneInputCannotBe(maybe_string)) {
     // If one input cannot be a string, then emit a number comparison.
+    ...
+  }
+#endif
+  if (r.BothInputsAre(Type::Primitive()) &&
+      r.OneInputCannotBe(Type::StringOrReceiver())) {
     const Operator* less_than;
     const Operator* less_than_or_equal;
     if (r.BothInputsAre(Type::Unsigned32())) {
@@ -379,16 +449,14 @@
   if (r.left() == r.right()) {
     // x === x is always true if x != NaN
     if (!r.left_type()->Maybe(Type::NaN())) {
-      return ReplaceEagerly(node, invert ? jsgraph()->FalseConstant()
-                                         : jsgraph()->TrueConstant());
+      return ReplaceEagerly(node, jsgraph()->BooleanConstant(!invert));
     }
   }
-  if (!r.left_type()->Maybe(r.right_type())) {
-    // Type intersection is empty; === is always false unless both
-    // inputs could be strings (one internalized and one not).
-    if (r.OneInputCannotBe(Type::String())) {
-      return ReplaceEagerly(node, invert ? jsgraph()->TrueConstant()
-                                         : jsgraph()->FalseConstant());
+  if (r.OneInputCannotBe(Type::NumberOrString())) {
+    // For values with canonical representation (i.e. not string nor number) an
+    // empty type intersection means the values cannot be strictly equal.
+    if (!r.left_type()->Maybe(r.right_type())) {
+      return ReplaceEagerly(node, jsgraph()->BooleanConstant(invert));
     }
   }
   if (r.OneInputIs(Type::Undefined())) {
@@ -422,16 +490,47 @@
 }
 
 
+Reduction JSTypedLowering::ReduceJSUnaryNot(Node* node) {
+  Node* input = node->InputAt(0);
+  Type* input_type = NodeProperties::GetBounds(input).upper;
+  if (input_type->Is(Type::Boolean())) {
+    // JSUnaryNot(x:boolean,context) => BooleanNot(x)
+    node->set_op(simplified()->BooleanNot());
+    node->TrimInputCount(1);
+    return Changed(node);
+  }
+  // JSUnaryNot(x,context) => BooleanNot(AnyToBoolean(x))
+  node->set_op(simplified()->BooleanNot());
+  node->ReplaceInput(0, graph()->NewNode(simplified()->AnyToBoolean(), input));
+  node->TrimInputCount(1);
+  return Changed(node);
+}
+
+
+Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
+  Node* input = node->InputAt(0);
+  Type* input_type = NodeProperties::GetBounds(input).upper;
+  if (input_type->Is(Type::Boolean())) {
+    // JSToBoolean(x:boolean,context) => x
+    return Replace(input);
+  }
+  // JSToBoolean(x,context) => AnyToBoolean(x)
+  node->set_op(simplified()->AnyToBoolean());
+  node->TrimInputCount(1);
+  return Changed(node);
+}
+
+
 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
   if (input->opcode() == IrOpcode::kJSToNumber) {
     // Recursively try to reduce the input first.
-    Reduction result = ReduceJSToNumberInput(input->InputAt(0));
-    if (result.Changed()) {
-      RelaxEffects(input);
-      return result;
-    }
+    Reduction result = ReduceJSToNumber(input);
+    if (result.Changed()) return result;
     return Changed(input);  // JSToNumber(JSToNumber(x)) => JSToNumber(x)
   }
+  // Check if we have a cached conversion.
+  Node* conversion = FindConversion<IrOpcode::kJSToNumber>(input);
+  if (conversion) return Replace(conversion);
   Type* input_type = NodeProperties::GetBounds(input).upper;
   if (input_type->Is(Type::Number())) {
     // JSToNumber(x:number) => x
@@ -439,30 +538,113 @@
   }
   if (input_type->Is(Type::Undefined())) {
     // JSToNumber(undefined) => #NaN
-    return ReplaceWith(jsgraph()->NaNConstant());
+    return Replace(jsgraph()->NaNConstant());
   }
   if (input_type->Is(Type::Null())) {
     // JSToNumber(null) => #0
-    return ReplaceWith(jsgraph()->ZeroConstant());
+    return Replace(jsgraph()->ZeroConstant());
   }
   if (input_type->Is(Type::Boolean())) {
     // JSToNumber(x:boolean) => BooleanToNumber(x)
-    return ReplaceWith(
-        graph()->NewNode(simplified()->BooleanToNumber(), input));
+    return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input));
   }
   // TODO(turbofan): js-typed-lowering of ToNumber(x:string)
   return NoChange();
 }
 
 
+Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
+  // Try to reduce the input first.
+  Node* const input = node->InputAt(0);
+  Reduction reduction = ReduceJSToNumberInput(input);
+  if (reduction.Changed()) {
+    NodeProperties::ReplaceWithValue(node, reduction.replacement());
+    return reduction;
+  }
+  Type* const input_type = NodeProperties::GetBounds(input).upper;
+  if (input_type->Is(Type::PlainPrimitive())) {
+    if (input->opcode() == IrOpcode::kPhi) {
+      // JSToNumber(phi(x1,...,xn,control):plain-primitive,context)
+      //   => phi(JSToNumber(x1,no-context),
+      //          ...,
+      //          JSToNumber(xn,no-context),control)
+      int const input_count = input->InputCount() - 1;
+      Node* const control = input->InputAt(input_count);
+      DCHECK_LE(0, input_count);
+      DCHECK(NodeProperties::IsControl(control));
+      DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number()));
+      DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number()));
+      RelaxEffects(node);
+      node->set_op(common()->Phi(kMachAnyTagged, input_count));
+      for (int i = 0; i < input_count; ++i) {
+        // We must be very careful not to introduce cycles when pushing
+        // operations into phis. It is safe for {value}, since it appears
+        // as input to the phi that we are replacing, but it's not safe
+        // to simply reuse the context of the {node}. However, ToNumber()
+        // does not require a context anyways, so it's safe to discard it
+        // here and pass the dummy context.
+        Node* const value = ConvertToNumber(input->InputAt(i));
+        if (i < node->InputCount()) {
+          node->ReplaceInput(i, value);
+        } else {
+          node->AppendInput(graph()->zone(), value);
+        }
+      }
+      if (input_count < node->InputCount()) {
+        node->ReplaceInput(input_count, control);
+      } else {
+        node->AppendInput(graph()->zone(), control);
+      }
+      node->TrimInputCount(input_count + 1);
+      return Changed(node);
+    }
+    if (input->opcode() == IrOpcode::kSelect) {
+      // JSToNumber(select(c,x1,x2):plain-primitive,context)
+      //   => select(c,JSToNumber(x1,no-context),JSToNumber(x2,no-context))
+      int const input_count = input->InputCount();
+      BranchHint const input_hint = SelectParametersOf(input->op()).hint();
+      DCHECK_EQ(3, input_count);
+      DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number()));
+      DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number()));
+      RelaxEffects(node);
+      node->set_op(common()->Select(kMachAnyTagged, input_hint));
+      node->ReplaceInput(0, input->InputAt(0));
+      for (int i = 1; i < input_count; ++i) {
+        // We must be very careful not to introduce cycles when pushing
+        // operations into selects. It is safe for {value}, since it appears
+        // as input to the select that we are replacing, but it's not safe
+        // to simply reuse the context of the {node}. However, ToNumber()
+        // does not require a context anyways, so it's safe to discard it
+        // here and pass the dummy context.
+        Node* const value = ConvertToNumber(input->InputAt(i));
+        node->ReplaceInput(i, value);
+      }
+      node->TrimInputCount(input_count);
+      return Changed(node);
+    }
+    // Remember this conversion.
+    InsertConversion(node);
+    if (node->InputAt(1) != jsgraph()->NoContextConstant() ||
+        node->InputAt(2) != graph()->start() ||
+        node->InputAt(3) != graph()->start()) {
+      // JSToNumber(x:plain-primitive,context,effect,control)
+      //   => JSToNumber(x,no-context,start,start)
+      RelaxEffects(node);
+      node->ReplaceInput(1, jsgraph()->NoContextConstant());
+      node->ReplaceInput(2, graph()->start());
+      node->ReplaceInput(3, graph()->start());
+      return Changed(node);
+    }
+  }
+  return NoChange();
+}
+
+
 Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
   if (input->opcode() == IrOpcode::kJSToString) {
     // Recursively try to reduce the input first.
-    Reduction result = ReduceJSToStringInput(input->InputAt(0));
-    if (result.Changed()) {
-      RelaxEffects(input);
-      return result;
-    }
+    Reduction result = ReduceJSToString(input);
+    if (result.Changed()) return result;
     return Changed(input);  // JSToString(JSToString(x)) => JSToString(x)
   }
   Type* input_type = NodeProperties::GetBounds(input).upper;
@@ -470,12 +652,10 @@
     return Changed(input);  // JSToString(x:string) => x
   }
   if (input_type->Is(Type::Undefined())) {
-    return ReplaceWith(jsgraph()->HeapConstant(
-        graph()->zone()->isolate()->factory()->undefined_string()));
+    return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
   }
   if (input_type->Is(Type::Null())) {
-    return ReplaceWith(jsgraph()->HeapConstant(
-        graph()->zone()->isolate()->factory()->null_string()));
+    return Replace(jsgraph()->HeapConstant(factory()->null_string()));
   }
   // TODO(turbofan): js-typed-lowering of ToString(x:boolean)
   // TODO(turbofan): js-typed-lowering of ToString(x:number)
@@ -483,44 +663,14 @@
 }
 
 
-Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) {
-  if (input->opcode() == IrOpcode::kJSToBoolean) {
-    // Recursively try to reduce the input first.
-    Reduction result = ReduceJSToBooleanInput(input->InputAt(0));
-    if (result.Changed()) {
-      RelaxEffects(input);
-      return result;
-    }
-    return Changed(input);  // JSToBoolean(JSToBoolean(x)) => JSToBoolean(x)
+Reduction JSTypedLowering::ReduceJSToString(Node* node) {
+  // Try to reduce the input first.
+  Node* const input = node->InputAt(0);
+  Reduction reduction = ReduceJSToStringInput(input);
+  if (reduction.Changed()) {
+    NodeProperties::ReplaceWithValue(node, reduction.replacement());
+    return reduction;
   }
-  Type* input_type = NodeProperties::GetBounds(input).upper;
-  if (input_type->Is(Type::Boolean())) {
-    return Changed(input);  // JSToBoolean(x:boolean) => x
-  }
-  if (input_type->Is(Type::Undefined())) {
-    // JSToBoolean(undefined) => #false
-    return ReplaceWith(jsgraph()->FalseConstant());
-  }
-  if (input_type->Is(Type::Null())) {
-    // JSToBoolean(null) => #false
-    return ReplaceWith(jsgraph()->FalseConstant());
-  }
-  if (input_type->Is(Type::DetectableReceiver())) {
-    // JSToBoolean(x:detectable) => #true
-    return ReplaceWith(jsgraph()->TrueConstant());
-  }
-  if (input_type->Is(Type::Undetectable())) {
-    // JSToBoolean(x:undetectable) => #false
-    return ReplaceWith(jsgraph()->FalseConstant());
-  }
-  if (input_type->Is(Type::OrderedNumber())) {
-    // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0))
-    Node* cmp = graph()->NewNode(simplified()->NumberEqual(), input,
-                                 jsgraph()->ZeroConstant());
-    Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp);
-    return ReplaceWith(inv);
-  }
-  // TODO(turbofan): js-typed-lowering of ToBoolean(string)
   return NoChange();
 }
 
@@ -529,37 +679,40 @@
   Node* key = NodeProperties::GetValueInput(node, 1);
   Node* base = NodeProperties::GetValueInput(node, 0);
   Type* key_type = NodeProperties::GetBounds(key).upper;
-  Type* base_type = NodeProperties::GetBounds(base).upper;
   // TODO(mstarzinger): This lowering is not correct if:
-  //   a) The typed array turns external (i.e. MaterializeArrayBuffer)
-  //   b) The typed array or it's buffer is neutered.
-  //   c) The index is out of bounds.
-  if (base_type->IsConstant() && key_type->Is(Type::Integral32()) &&
-      base_type->AsConstant()->Value()->IsJSTypedArray()) {
-    // JSLoadProperty(typed-array, int32)
-    JSTypedArray* array = JSTypedArray::cast(*base_type->AsConstant()->Value());
-    ElementsKind elements_kind = array->map()->elements_kind();
-    ExternalArrayType type = array->type();
-    uint32_t length;
-    CHECK(array->length()->ToUint32(&length));
-    ElementAccess element_access;
-    Node* elements = graph()->NewNode(
-        simplified()->LoadField(AccessBuilder::ForJSObjectElements()), base,
-        NodeProperties::GetEffectInput(node));
-    if (IsExternalArrayElementsKind(elements_kind)) {
-      elements = graph()->NewNode(
-          simplified()->LoadField(AccessBuilder::ForExternalArrayPointer()),
-          elements, NodeProperties::GetEffectInput(node));
-      element_access = AccessBuilder::ForTypedArrayElement(type, true);
-    } else {
-      DCHECK(IsFixedTypedArrayElementsKind(elements_kind));
-      element_access = AccessBuilder::ForTypedArrayElement(type, false);
+  //   a) The typed array or it's buffer is neutered.
+  HeapObjectMatcher<Object> mbase(base);
+  if (mbase.HasValue() && mbase.Value().handle()->IsJSTypedArray()) {
+    Handle<JSTypedArray> const array =
+        Handle<JSTypedArray>::cast(mbase.Value().handle());
+    array->GetBuffer()->set_is_neuterable(false);
+    BufferAccess const access(array->type());
+    size_t const k = ElementSizeLog2Of(access.machine_type());
+    double const byte_length = array->byte_length()->Number();
+    CHECK_LT(k, arraysize(shifted_int32_ranges_));
+    if (IsExternalArrayElementsKind(array->map()->elements_kind()) &&
+        key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
+      // JSLoadProperty(typed-array, int32)
+      Handle<ExternalArray> elements =
+          Handle<ExternalArray>::cast(handle(array->elements()));
+      Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
+      Node* length = jsgraph()->Constant(byte_length);
+      Node* effect = NodeProperties::GetEffectInput(node);
+      Node* control = NodeProperties::GetControlInput(node);
+      // Check if we can avoid the bounds check.
+      if (key_type->Min() >= 0 && key_type->Max() < array->length()->Number()) {
+        Node* load = graph()->NewNode(
+            simplified()->LoadElement(
+                AccessBuilder::ForTypedArrayElement(array->type(), true)),
+            buffer, key, effect, control);
+        return ReplaceEagerly(node, load);
+      }
+      // Compute byte offset.
+      Node* offset = Word32Shl(key, static_cast<int>(k));
+      Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer,
+                                    offset, length, effect, control);
+      return ReplaceEagerly(node, load);
     }
-    Node* value =
-        graph()->NewNode(simplified()->LoadElement(element_access), elements,
-                         key, jsgraph()->Uint32Constant(length),
-                         NodeProperties::GetEffectInput(node));
-    return ReplaceEagerly(node, value);
   }
   return NoChange();
 }
@@ -570,65 +723,151 @@
   Node* base = NodeProperties::GetValueInput(node, 0);
   Node* value = NodeProperties::GetValueInput(node, 2);
   Type* key_type = NodeProperties::GetBounds(key).upper;
-  Type* base_type = NodeProperties::GetBounds(base).upper;
+  Type* value_type = NodeProperties::GetBounds(value).upper;
   // TODO(mstarzinger): This lowering is not correct if:
-  //   a) The typed array turns external (i.e. MaterializeArrayBuffer)
-  //   b) The typed array or it's buffer is neutered.
-  if (key_type->Is(Type::Integral32()) && base_type->IsConstant() &&
-      base_type->AsConstant()->Value()->IsJSTypedArray()) {
-    // JSStoreProperty(typed-array, int32, value)
-    JSTypedArray* array = JSTypedArray::cast(*base_type->AsConstant()->Value());
-    ElementsKind elements_kind = array->map()->elements_kind();
-    ExternalArrayType type = array->type();
-    uint32_t length;
-    CHECK(array->length()->ToUint32(&length));
-    ElementAccess element_access;
-    Node* elements = graph()->NewNode(
-        simplified()->LoadField(AccessBuilder::ForJSObjectElements()), base,
-        NodeProperties::GetEffectInput(node));
-    if (IsExternalArrayElementsKind(elements_kind)) {
-      elements = graph()->NewNode(
-          simplified()->LoadField(AccessBuilder::ForExternalArrayPointer()),
-          elements, NodeProperties::GetEffectInput(node));
-      element_access = AccessBuilder::ForTypedArrayElement(type, true);
-    } else {
-      DCHECK(IsFixedTypedArrayElementsKind(elements_kind));
-      element_access = AccessBuilder::ForTypedArrayElement(type, false);
+  //   a) The typed array or its buffer is neutered.
+  HeapObjectMatcher<Object> mbase(base);
+  if (mbase.HasValue() && mbase.Value().handle()->IsJSTypedArray()) {
+    Handle<JSTypedArray> const array =
+        Handle<JSTypedArray>::cast(mbase.Value().handle());
+    array->GetBuffer()->set_is_neuterable(false);
+    BufferAccess const access(array->type());
+    size_t const k = ElementSizeLog2Of(access.machine_type());
+    double const byte_length = array->byte_length()->Number();
+    CHECK_LT(k, arraysize(shifted_int32_ranges_));
+    if (IsExternalArrayElementsKind(array->map()->elements_kind()) &&
+        access.external_array_type() != kExternalUint8ClampedArray &&
+        key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
+      // JSLoadProperty(typed-array, int32)
+      Handle<ExternalArray> elements =
+          Handle<ExternalArray>::cast(handle(array->elements()));
+      Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
+      Node* length = jsgraph()->Constant(byte_length);
+      Node* context = NodeProperties::GetContextInput(node);
+      Node* effect = NodeProperties::GetEffectInput(node);
+      Node* control = NodeProperties::GetControlInput(node);
+      // Convert to a number first.
+      if (!value_type->Is(Type::Number())) {
+        Reduction number_reduction = ReduceJSToNumberInput(value);
+        if (number_reduction.Changed()) {
+          value = number_reduction.replacement();
+        } else {
+          value = effect = graph()->NewNode(javascript()->ToNumber(), value,
+                                            context, effect, control);
+        }
+      }
+      // For integer-typed arrays, convert to the integer type.
+      if (TypeOf(access.machine_type()) == kTypeInt32 &&
+          !value_type->Is(Type::Signed32())) {
+        value = graph()->NewNode(simplified()->NumberToInt32(), value);
+      } else if (TypeOf(access.machine_type()) == kTypeUint32 &&
+                 !value_type->Is(Type::Unsigned32())) {
+        value = graph()->NewNode(simplified()->NumberToUint32(), value);
+      }
+      // Check if we can avoid the bounds check.
+      if (key_type->Min() >= 0 && key_type->Max() < array->length()->Number()) {
+        node->set_op(simplified()->StoreElement(
+            AccessBuilder::ForTypedArrayElement(array->type(), true)));
+        node->ReplaceInput(0, buffer);
+        DCHECK_EQ(key, node->InputAt(1));
+        node->ReplaceInput(2, value);
+        node->ReplaceInput(3, effect);
+        node->ReplaceInput(4, control);
+        node->TrimInputCount(5);
+        return Changed(node);
+      }
+      // Compute byte offset.
+      Node* offset = Word32Shl(key, static_cast<int>(k));
+      // Turn into a StoreBuffer operation.
+      node->set_op(simplified()->StoreBuffer(access));
+      node->ReplaceInput(0, buffer);
+      node->ReplaceInput(1, offset);
+      node->ReplaceInput(2, length);
+      node->ReplaceInput(3, value);
+      node->ReplaceInput(4, effect);
+      DCHECK_EQ(control, node->InputAt(5));
+      DCHECK_EQ(6, node->InputCount());
+      return Changed(node);
     }
-
-    Node* check = graph()->NewNode(machine()->Uint32LessThan(), key,
-                                   jsgraph()->Uint32Constant(length));
-    Node* branch = graph()->NewNode(common()->Branch(), check,
-                                    NodeProperties::GetControlInput(node));
-
-    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-    Node* store =
-        graph()->NewNode(simplified()->StoreElement(element_access), elements,
-                         key, jsgraph()->Uint32Constant(length), value,
-                         NodeProperties::GetEffectInput(node), if_true);
-
-    Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
-
-    Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-    Node* phi = graph()->NewNode(common()->EffectPhi(2), store,
-                                 NodeProperties::GetEffectInput(node), merge);
-
-    return ReplaceWith(phi);
   }
   return NoChange();
 }
 
 
-static Reduction ReplaceWithReduction(Node* node, Reduction reduction) {
-  if (reduction.Changed()) {
-    NodeProperties::ReplaceWithValue(node, reduction.replacement());
-    return reduction;
+Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
+  DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
+  ContextAccess const& access = ContextAccessOf(node->op());
+  Node* const effect = NodeProperties::GetEffectInput(node);
+  Node* const control = graph()->start();
+  for (size_t i = 0; i < access.depth(); ++i) {
+    node->ReplaceInput(
+        0, graph()->NewNode(
+               simplified()->LoadField(
+                   AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
+               NodeProperties::GetValueInput(node, 0), effect, control));
   }
-  return Reducer::NoChange();
+  node->set_op(
+      simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
+  node->ReplaceInput(1, effect);
+  node->ReplaceInput(2, control);
+  DCHECK_EQ(3, node->InputCount());
+  return Changed(node);
+}
+
+
+Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
+  DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
+  ContextAccess const& access = ContextAccessOf(node->op());
+  Node* const effect = NodeProperties::GetEffectInput(node);
+  Node* const control = graph()->start();
+  for (size_t i = 0; i < access.depth(); ++i) {
+    node->ReplaceInput(
+        0, graph()->NewNode(
+               simplified()->LoadField(
+                   AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
+               NodeProperties::GetValueInput(node, 0), effect, control));
+  }
+  node->set_op(
+      simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
+  node->RemoveInput(2);
+  DCHECK_EQ(4, node->InputCount());
+  return Changed(node);
 }
 
 
 Reduction JSTypedLowering::Reduce(Node* node) {
+  // Check if the output type is a singleton.  In that case we already know the
+  // result value and can simply replace the node if it's eliminable.
+  if (NodeProperties::IsTyped(node) &&
+      !IrOpcode::IsLeafOpcode(node->opcode()) &&
+      node->op()->HasProperty(Operator::kEliminatable)) {
+    Type* upper = NodeProperties::GetBounds(node).upper;
+    if (upper->IsConstant()) {
+      Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value());
+      NodeProperties::ReplaceWithValue(node, replacement);
+      return Changed(replacement);
+    } else if (upper->Is(Type::MinusZero())) {
+      Node* replacement = jsgraph()->Constant(factory()->minus_zero_value());
+      NodeProperties::ReplaceWithValue(node, replacement);
+      return Changed(replacement);
+    } else if (upper->Is(Type::NaN())) {
+      Node* replacement = jsgraph()->NaNConstant();
+      NodeProperties::ReplaceWithValue(node, replacement);
+      return Changed(replacement);
+    } else if (upper->Is(Type::Null())) {
+      Node* replacement = jsgraph()->NullConstant();
+      NodeProperties::ReplaceWithValue(node, replacement);
+      return Changed(replacement);
+    } else if (upper->Is(Type::PlainNumber()) && upper->Min() == upper->Max()) {
+      Node* replacement = jsgraph()->Constant(upper->Min());
+      NodeProperties::ReplaceWithValue(node, replacement);
+      return Changed(replacement);
+    } else if (upper->Is(Type::Undefined())) {
+      Node* replacement = jsgraph()->UndefinedConstant();
+      NodeProperties::ReplaceWithValue(node, replacement);
+      return Changed(replacement);
+    }
+  }
   switch (node->opcode()) {
     case IrOpcode::kJSEqual:
       return ReduceJSEqual(node, false);
@@ -644,67 +883,113 @@
     case IrOpcode::kJSGreaterThanOrEqual:
       return ReduceJSComparison(node);
     case IrOpcode::kJSBitwiseOr:
-      return ReduceI32Binop(node, true, true, machine()->Word32Or());
+      return ReduceJSBitwiseOr(node);
     case IrOpcode::kJSBitwiseXor:
-      return ReduceI32Binop(node, true, true, machine()->Word32Xor());
+      return ReduceInt32Binop(node, machine()->Word32Xor());
     case IrOpcode::kJSBitwiseAnd:
-      return ReduceI32Binop(node, true, true, machine()->Word32And());
+      return ReduceInt32Binop(node, machine()->Word32And());
     case IrOpcode::kJSShiftLeft:
-      return ReduceI32Shift(node, true, machine()->Word32Shl());
+      return ReduceUI32Shift(node, kSigned, machine()->Word32Shl());
     case IrOpcode::kJSShiftRight:
-      return ReduceI32Shift(node, true, machine()->Word32Sar());
+      return ReduceUI32Shift(node, kSigned, machine()->Word32Sar());
     case IrOpcode::kJSShiftRightLogical:
-      return ReduceI32Shift(node, false, machine()->Word32Shr());
+      return ReduceUI32Shift(node, kUnsigned, machine()->Word32Shr());
     case IrOpcode::kJSAdd:
       return ReduceJSAdd(node);
     case IrOpcode::kJSSubtract:
       return ReduceNumberBinop(node, simplified()->NumberSubtract());
     case IrOpcode::kJSMultiply:
-      return ReduceNumberBinop(node, simplified()->NumberMultiply());
+      return ReduceJSMultiply(node);
     case IrOpcode::kJSDivide:
       return ReduceNumberBinop(node, simplified()->NumberDivide());
     case IrOpcode::kJSModulus:
       return ReduceNumberBinop(node, simplified()->NumberModulus());
-    case IrOpcode::kJSUnaryNot: {
-      Reduction result = ReduceJSToBooleanInput(node->InputAt(0));
-      Node* value;
-      if (result.Changed()) {
-        // JSUnaryNot(x:boolean) => BooleanNot(x)
-        value =
-            graph()->NewNode(simplified()->BooleanNot(), result.replacement());
-        NodeProperties::ReplaceWithValue(node, value);
-        return Changed(value);
-      } else {
-        // JSUnaryNot(x) => BooleanNot(JSToBoolean(x))
-        value = graph()->NewNode(simplified()->BooleanNot(), node);
-        node->set_op(javascript()->ToBoolean());
-        NodeProperties::ReplaceWithValue(node, value, node);
-        // Note: ReplaceUses() smashes all uses, so smash it back here.
-        value->ReplaceInput(0, node);
-        return Changed(node);
-      }
-    }
+    case IrOpcode::kJSUnaryNot:
+      return ReduceJSUnaryNot(node);
     case IrOpcode::kJSToBoolean:
-      return ReplaceWithReduction(node,
-                                  ReduceJSToBooleanInput(node->InputAt(0)));
+      return ReduceJSToBoolean(node);
     case IrOpcode::kJSToNumber:
-      return ReplaceWithReduction(node,
-                                  ReduceJSToNumberInput(node->InputAt(0)));
+      return ReduceJSToNumber(node);
     case IrOpcode::kJSToString:
-      return ReplaceWithReduction(node,
-                                  ReduceJSToStringInput(node->InputAt(0)));
+      return ReduceJSToString(node);
     case IrOpcode::kJSLoadProperty:
       return ReduceJSLoadProperty(node);
     case IrOpcode::kJSStoreProperty:
       return ReduceJSStoreProperty(node);
-    case IrOpcode::kJSCallFunction:
-      return JSBuiltinReducer(jsgraph()).Reduce(node);
+    case IrOpcode::kJSLoadContext:
+      return ReduceJSLoadContext(node);
+    case IrOpcode::kJSStoreContext:
+      return ReduceJSStoreContext(node);
     default:
       break;
   }
   return NoChange();
 }
 
+
+Node* JSTypedLowering::ConvertToNumber(Node* input) {
+  DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive()));
+  // Avoid inserting too many eager ToNumber() operations.
+  Reduction const reduction = ReduceJSToNumberInput(input);
+  if (reduction.Changed()) return reduction.replacement();
+  Node* const conversion = graph()->NewNode(javascript()->ToNumber(), input,
+                                            jsgraph()->NoContextConstant(),
+                                            graph()->start(), graph()->start());
+  InsertConversion(conversion);
+  return conversion;
+}
+
+
+template <IrOpcode::Value kOpcode>
+Node* JSTypedLowering::FindConversion(Node* input) {
+  size_t const input_id = input->id();
+  if (input_id < conversions_.size()) {
+    Node* const conversion = conversions_[input_id];
+    if (conversion && conversion->opcode() == kOpcode) {
+      return conversion;
+    }
+  }
+  return nullptr;
+}
+
+
+void JSTypedLowering::InsertConversion(Node* conversion) {
+  DCHECK(conversion->opcode() == IrOpcode::kJSToNumber);
+  size_t const input_id = conversion->InputAt(0)->id();
+  if (input_id >= conversions_.size()) {
+    conversions_.resize(2 * input_id + 1);
+  }
+  conversions_[input_id] = conversion;
+}
+
+
+Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) {
+  if (rhs == 0) return lhs;
+  return graph()->NewNode(machine()->Word32Shl(), lhs,
+                          jsgraph()->Int32Constant(rhs));
+}
+
+
+Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
+
+
+Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
+
+
+JSOperatorBuilder* JSTypedLowering::javascript() const {
+  return jsgraph()->javascript();
+}
+
+
+CommonOperatorBuilder* JSTypedLowering::common() const {
+  return jsgraph()->common();
+}
+
+
+MachineOperatorBuilder* JSTypedLowering::machine() const {
+  return jsgraph()->machine();
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
diff --git a/src/compiler/js-typed-lowering.h b/src/compiler/js-typed-lowering.h
index deaf1fa..838085e 100644
--- a/src/compiler/js-typed-lowering.h
+++ b/src/compiler/js-typed-lowering.h
@@ -6,55 +6,74 @@
 #define V8_COMPILER_JS_TYPED_LOWERING_H_
 
 #include "src/compiler/graph-reducer.h"
-#include "src/compiler/js-graph.h"
-#include "src/compiler/machine-operator.h"
-#include "src/compiler/node.h"
 #include "src/compiler/simplified-operator.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
+// Forward declarations.
+class CommonOperatorBuilder;
+class JSGraph;
+class JSOperatorBuilder;
+class MachineOperatorBuilder;
+
+
 // Lowers JS-level operators to simplified operators based on types.
 class JSTypedLowering FINAL : public Reducer {
  public:
-  explicit JSTypedLowering(JSGraph* jsgraph)
-      : jsgraph_(jsgraph), simplified_(jsgraph->zone()) {}
-  virtual ~JSTypedLowering();
+  JSTypedLowering(JSGraph* jsgraph, Zone* zone);
+  ~JSTypedLowering() FINAL {}
 
-  virtual Reduction Reduce(Node* node) OVERRIDE;
-
-  JSGraph* jsgraph() { return jsgraph_; }
-  Graph* graph() { return jsgraph_->graph(); }
-  Zone* zone() { return jsgraph_->zone(); }
+  Reduction Reduce(Node* node) FINAL;
 
  private:
   friend class JSBinopReduction;
 
   Reduction ReplaceEagerly(Node* old, Node* node);
-  Reduction ReplaceWith(Node* node) { return Reducer::Replace(node); }
   Reduction ReduceJSAdd(Node* node);
+  Reduction ReduceJSBitwiseOr(Node* node);
+  Reduction ReduceJSMultiply(Node* node);
   Reduction ReduceJSComparison(Node* node);
   Reduction ReduceJSLoadProperty(Node* node);
   Reduction ReduceJSStoreProperty(Node* node);
+  Reduction ReduceJSLoadContext(Node* node);
+  Reduction ReduceJSStoreContext(Node* node);
   Reduction ReduceJSEqual(Node* node, bool invert);
   Reduction ReduceJSStrictEqual(Node* node, bool invert);
+  Reduction ReduceJSUnaryNot(Node* node);
+  Reduction ReduceJSToBoolean(Node* node);
   Reduction ReduceJSToNumberInput(Node* input);
+  Reduction ReduceJSToNumber(Node* node);
   Reduction ReduceJSToStringInput(Node* input);
-  Reduction ReduceJSToBooleanInput(Node* input);
+  Reduction ReduceJSToString(Node* node);
   Reduction ReduceNumberBinop(Node* node, const Operator* numberOp);
-  Reduction ReduceI32Binop(Node* node, bool left_signed, bool right_signed,
-                           const Operator* intOp);
-  Reduction ReduceI32Shift(Node* node, bool left_signed,
-                           const Operator* shift_op);
+  Reduction ReduceInt32Binop(Node* node, const Operator* intOp);
+  Reduction ReduceUI32Shift(Node* node, Signedness left_signedness,
+                            const Operator* shift_op);
 
-  JSOperatorBuilder* javascript() { return jsgraph_->javascript(); }
-  CommonOperatorBuilder* common() { return jsgraph_->common(); }
+  Node* ConvertToNumber(Node* input);
+  template <IrOpcode::Value>
+  Node* FindConversion(Node* input);
+  void InsertConversion(Node* conversion);
+
+  Node* Word32Shl(Node* const lhs, int32_t const rhs);
+
+  Factory* factory() const;
+  Graph* graph() const;
+  JSGraph* jsgraph() const { return jsgraph_; }
+  JSOperatorBuilder* javascript() const;
+  CommonOperatorBuilder* common() const;
   SimplifiedOperatorBuilder* simplified() { return &simplified_; }
-  MachineOperatorBuilder* machine() { return jsgraph_->machine(); }
+  MachineOperatorBuilder* machine() const;
 
   JSGraph* jsgraph_;
   SimplifiedOperatorBuilder simplified_;
+  ZoneVector<Node*> conversions_;  // Cache inserted JSToXXX() conversions.
+  Type* zero_range_;
+  Type* one_range_;
+  Type* zero_thirtyone_range_;
+  Type* shifted_int32_ranges_[4];
 };
 
 }  // namespace compiler
diff --git a/src/compiler/jump-threading.cc b/src/compiler/jump-threading.cc
new file mode 100644
index 0000000..f0bb731
--- /dev/null
+++ b/src/compiler/jump-threading.cc
@@ -0,0 +1,198 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/jump-threading.h"
+#include "src/compiler/code-generator-impl.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+typedef BasicBlock::RpoNumber RpoNumber;
+
+#define TRACE(x) \
+  if (FLAG_trace_turbo_jt) PrintF x
+
+struct JumpThreadingState {
+  bool forwarded;
+  ZoneVector<RpoNumber>& result;
+  ZoneStack<RpoNumber>& stack;
+
+  void Clear(size_t count) { result.assign(count, unvisited()); }
+  void PushIfUnvisited(RpoNumber num) {
+    if (result[num.ToInt()] == unvisited()) {
+      stack.push(num);
+      result[num.ToInt()] = onstack();
+    }
+  }
+  void Forward(RpoNumber to) {
+    RpoNumber from = stack.top();
+    RpoNumber to_to = result[to.ToInt()];
+    bool pop = true;
+    if (to == from) {
+      TRACE(("  xx %d\n", from.ToInt()));
+      result[from.ToInt()] = from;
+    } else if (to_to == unvisited()) {
+      TRACE(("  fw %d -> %d (recurse)\n", from.ToInt(), to.ToInt()));
+      stack.push(to);
+      result[to.ToInt()] = onstack();
+      pop = false;  // recurse.
+    } else if (to_to == onstack()) {
+      TRACE(("  fw %d -> %d (cycle)\n", from.ToInt(), to.ToInt()));
+      result[from.ToInt()] = to;  // break the cycle.
+      forwarded = true;
+    } else {
+      TRACE(("  fw %d -> %d (forward)\n", from.ToInt(), to.ToInt()));
+      result[from.ToInt()] = to_to;  // forward the block.
+      forwarded = true;
+    }
+    if (pop) stack.pop();
+  }
+  RpoNumber unvisited() { return RpoNumber::FromInt(-1); }
+  RpoNumber onstack() { return RpoNumber::FromInt(-2); }
+};
+
+
+bool JumpThreading::ComputeForwarding(Zone* local_zone,
+                                      ZoneVector<RpoNumber>& result,
+                                      InstructionSequence* code) {
+  ZoneStack<RpoNumber> stack(local_zone);
+  JumpThreadingState state = {false, result, stack};
+  state.Clear(code->InstructionBlockCount());
+
+  // Iterate over the blocks forward, pushing the blocks onto the stack.
+  for (auto const block : code->instruction_blocks()) {
+    RpoNumber current = block->rpo_number();
+    state.PushIfUnvisited(current);
+
+    // Process the stack, which implements DFS through empty blocks.
+    while (!state.stack.empty()) {
+      InstructionBlock* block = code->InstructionBlockAt(state.stack.top());
+      // Process the instructions in a block up to a non-empty instruction.
+      TRACE(("jt [%d] B%d RPO%d\n", static_cast<int>(stack.size()),
+             block->id().ToInt(), block->rpo_number().ToInt()));
+      bool fallthru = true;
+      RpoNumber fw = block->rpo_number();
+      for (int i = block->code_start(); i < block->code_end(); ++i) {
+        Instruction* instr = code->InstructionAt(i);
+        if (instr->IsGapMoves() && GapInstruction::cast(instr)->IsRedundant()) {
+          // skip redundant gap moves.
+          TRACE(("  nop gap\n"));
+          continue;
+        } else if (instr->IsSourcePosition()) {
+          // skip source positions.
+          TRACE(("  src pos\n"));
+          continue;
+        } else if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
+          // can't skip instructions with flags continuations.
+          TRACE(("  flags\n"));
+          fallthru = false;
+        } else if (instr->IsNop()) {
+          // skip nops.
+          TRACE(("  nop\n"));
+          continue;
+        } else if (instr->arch_opcode() == kArchJmp) {
+          // try to forward the jump instruction.
+          TRACE(("  jmp\n"));
+          fw = code->InputRpo(instr, 0);
+          fallthru = false;
+        } else {
+          // can't skip other instructions.
+          TRACE(("  other\n"));
+          fallthru = false;
+        }
+        break;
+      }
+      if (fallthru) {
+        int next = 1 + block->rpo_number().ToInt();
+        if (next < code->InstructionBlockCount()) fw = RpoNumber::FromInt(next);
+      }
+      state.Forward(fw);
+    }
+  }
+
+#ifdef DEBUG
+  for (RpoNumber num : result) {
+    CHECK(num.IsValid());
+  }
+#endif
+
+  if (FLAG_trace_turbo_jt) {
+    for (int i = 0; i < static_cast<int>(result.size()); i++) {
+      TRACE(("RPO%d B%d ", i,
+             code->InstructionBlockAt(RpoNumber::FromInt(i))->id().ToInt()));
+      int to = result[i].ToInt();
+      if (i != to) {
+        TRACE(("-> B%d\n",
+               code->InstructionBlockAt(RpoNumber::FromInt(to))->id().ToInt()));
+      } else {
+        TRACE(("\n"));
+      }
+    }
+  }
+
+  return state.forwarded;
+}
+
+
+void JumpThreading::ApplyForwarding(ZoneVector<RpoNumber>& result,
+                                    InstructionSequence* code) {
+  if (!FLAG_turbo_jt) return;
+
+  Zone local_zone(code->zone()->isolate());
+  ZoneVector<bool> skip(static_cast<int>(result.size()), false, &local_zone);
+
+  // Skip empty blocks when the previous block doesn't fall through.
+  bool prev_fallthru = true;
+  for (auto const block : code->instruction_blocks()) {
+    int block_num = block->rpo_number().ToInt();
+    skip[block_num] = !prev_fallthru && result[block_num].ToInt() != block_num;
+
+    bool fallthru = true;
+    for (int i = block->code_start(); i < block->code_end(); ++i) {
+      Instruction* instr = code->InstructionAt(i);
+      if (FlagsModeField::decode(instr->opcode()) == kFlags_branch) {
+        fallthru = false;  // branches don't fall through to the next block.
+      } else if (instr->arch_opcode() == kArchJmp) {
+        if (skip[block_num]) {
+          // Overwrite a redundant jump with a nop.
+          TRACE(("jt-fw nop @%d\n", i));
+          instr->OverwriteWithNop();
+        }
+        fallthru = false;  // jumps don't fall through to the next block.
+      }
+    }
+    prev_fallthru = fallthru;
+  }
+
+  // Patch RPO immediates.
+  InstructionSequence::Immediates& immediates = code->immediates();
+  for (size_t i = 0; i < immediates.size(); i++) {
+    Constant constant = immediates[i];
+    if (constant.type() == Constant::kRpoNumber) {
+      RpoNumber rpo = constant.ToRpoNumber();
+      RpoNumber fw = result[rpo.ToInt()];
+      if (!(fw == rpo)) immediates[i] = Constant(fw);
+    }
+  }
+
+  // Recompute assembly order numbers.
+  int ao = 0;
+  for (auto const block : code->instruction_blocks()) {
+    if (!block->IsDeferred()) {
+      block->set_ao_number(RpoNumber::FromInt(ao));
+      if (!skip[block->rpo_number().ToInt()]) ao++;
+    }
+  }
+  for (auto const block : code->instruction_blocks()) {
+    if (block->IsDeferred()) {
+      block->set_ao_number(RpoNumber::FromInt(ao));
+      if (!skip[block->rpo_number().ToInt()]) ao++;
+    }
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/jump-threading.h b/src/compiler/jump-threading.h
new file mode 100644
index 0000000..b801fec
--- /dev/null
+++ b/src/compiler/jump-threading.h
@@ -0,0 +1,34 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_JUMP_THREADING_H_
+#define V8_COMPILER_JUMP_THREADING_H_
+
+#include "src/compiler/instruction.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// Forwards jumps to empty basic blocks that end with a second jump to the
+// destination of the second jump, transitively.
+class JumpThreading {
+ public:
+  // Compute the forwarding map of basic blocks to their ultimate destination.
+  // Returns {true} if there is at least one block that is forwarded.
+  static bool ComputeForwarding(Zone* local_zone,
+                                ZoneVector<BasicBlock::RpoNumber>& result,
+                                InstructionSequence* code);
+
+  // Rewrite the instructions to forward jumps and branches.
+  // May also negate some branches.
+  static void ApplyForwarding(ZoneVector<BasicBlock::RpoNumber>& forwarding,
+                              InstructionSequence* code);
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_JUMP_THREADING_H
diff --git a/src/compiler/linkage-impl.h b/src/compiler/linkage-impl.h
index c32c706..c13bd74 100644
--- a/src/compiler/linkage-impl.h
+++ b/src/compiler/linkage-impl.h
@@ -5,6 +5,8 @@
 #ifndef V8_COMPILER_LINKAGE_IMPL_H_
 #define V8_COMPILER_LINKAGE_IMPL_H_
 
+#include "src/code-stubs.h"
+
 namespace v8 {
 namespace internal {
 namespace compiler {
@@ -26,8 +28,8 @@
   }
 
   // TODO(turbofan): cache call descriptors for JSFunction calls.
-  static CallDescriptor* GetJSCallDescriptor(Zone* zone,
-                                             int js_parameter_count) {
+  static CallDescriptor* GetJSCallDescriptor(Zone* zone, int js_parameter_count,
+                                             CallDescriptor::Flags flags) {
     const size_t return_count = 1;
     const size_t context_count = 1;
     const size_t parameter_count = js_parameter_count + context_count;
@@ -54,16 +56,17 @@
     // The target for JS function calls is the JSFunction object.
     MachineType target_type = kMachAnyTagged;
     LinkageLocation target_loc = regloc(LinkageTraits::JSCallFunctionReg());
-    return new (zone) CallDescriptor(CallDescriptor::kCallJSFunction,  // kind
-                                     target_type,         // target MachineType
-                                     target_loc,          // target location
-                                     types.Build(),       // machine_sig
-                                     locations.Build(),   // location_sig
-                                     js_parameter_count,  // js_parameter_count
-                                     Operator::kNoProperties,  // properties
-                                     kNoCalleeSaved,           // callee-saved
-                                     CallDescriptor::kNeedsFrameState,  // flags
-                                     "js-call");
+    return new (zone) CallDescriptor(     // --
+        CallDescriptor::kCallJSFunction,  // kind
+        target_type,                      // target MachineType
+        target_loc,                       // target location
+        types.Build(),                    // machine_sig
+        locations.Build(),                // location_sig
+        js_parameter_count,               // js_parameter_count
+        Operator::kNoProperties,          // properties
+        kNoCalleeSaved,                   // callee-saved
+        flags,                            // flags
+        "js-call");
   }
 
 
@@ -114,23 +117,25 @@
     // The target for runtime calls is a code object.
     MachineType target_type = kMachAnyTagged;
     LinkageLocation target_loc = LinkageLocation::AnyRegister();
-    return new (zone) CallDescriptor(CallDescriptor::kCallCodeObject,  // kind
-                                     target_type,         // target MachineType
-                                     target_loc,          // target location
-                                     types.Build(),       // machine_sig
-                                     locations.Build(),   // location_sig
-                                     js_parameter_count,  // js_parameter_count
-                                     properties,          // properties
-                                     kNoCalleeSaved,      // callee-saved
-                                     flags,               // flags
-                                     function->name);     // debug name
+    return new (zone) CallDescriptor(     // --
+        CallDescriptor::kCallCodeObject,  // kind
+        target_type,                      // target MachineType
+        target_loc,                       // target location
+        types.Build(),                    // machine_sig
+        locations.Build(),                // location_sig
+        js_parameter_count,               // js_parameter_count
+        properties,                       // properties
+        kNoCalleeSaved,                   // callee-saved
+        flags,                            // flags
+        function->name);                  // debug name
   }
 
 
   // TODO(turbofan): cache call descriptors for code stub calls.
   static CallDescriptor* GetStubCallDescriptor(
-      Zone* zone, CallInterfaceDescriptor descriptor, int stack_parameter_count,
-      CallDescriptor::Flags flags) {
+      Zone* zone, const CallInterfaceDescriptor& descriptor,
+      int stack_parameter_count, CallDescriptor::Flags flags,
+      Operator::Properties properties) {
     const int register_parameter_count =
         descriptor.GetEnvironmentParameterCount();
     const int js_parameter_count =
@@ -167,16 +172,17 @@
     // The target for stub calls is a code object.
     MachineType target_type = kMachAnyTagged;
     LinkageLocation target_loc = LinkageLocation::AnyRegister();
-    return new (zone) CallDescriptor(CallDescriptor::kCallCodeObject,  // kind
-                                     target_type,         // target MachineType
-                                     target_loc,          // target location
-                                     types.Build(),       // machine_sig
-                                     locations.Build(),   // location_sig
-                                     js_parameter_count,  // js_parameter_count
-                                     Operator::kNoProperties,  // properties
-                                     kNoCalleeSaved,  // callee-saved registers
-                                     flags,           // flags
-                                     descriptor.DebugName(zone->isolate()));
+    return new (zone) CallDescriptor(     // --
+        CallDescriptor::kCallCodeObject,  // kind
+        target_type,                      // target MachineType
+        target_loc,                       // target location
+        types.Build(),                    // machine_sig
+        locations.Build(),                // location_sig
+        js_parameter_count,               // js_parameter_count
+        properties,                       // properties
+        kNoCalleeSaved,                   // callee-saved registers
+        flags,                            // flags
+        descriptor.DebugName(zone->isolate()));
   }
 
   static CallDescriptor* GetSimplifiedCDescriptor(Zone* zone,
@@ -199,15 +205,16 @@
     // The target for C calls is always an address (i.e. machine pointer).
     MachineType target_type = kMachPtr;
     LinkageLocation target_loc = LinkageLocation::AnyRegister();
-    return new (zone) CallDescriptor(CallDescriptor::kCallAddress,  // kind
-                                     target_type,        // target MachineType
-                                     target_loc,         // target location
-                                     msig,               // machine_sig
-                                     locations.Build(),  // location_sig
-                                     0,                  // js_parameter_count
-                                     Operator::kNoProperties,  // properties
-                                     LinkageTraits::CCalleeSaveRegisters(),
-                                     CallDescriptor::kNoFlags, "c-call");
+    return new (zone) CallDescriptor(  // --
+        CallDescriptor::kCallAddress,  // kind
+        target_type,                   // target MachineType
+        target_loc,                    // target location
+        msig,                          // machine_sig
+        locations.Build(),             // location_sig
+        0,                             // js_parameter_count
+        Operator::kNoProperties,       // properties
+        LinkageTraits::CCalleeSaveRegisters(), CallDescriptor::kNoFlags,
+        "c-call");
   }
 
   static LinkageLocation regloc(Register reg) {
diff --git a/src/compiler/linkage.cc b/src/compiler/linkage.cc
index 465a667..fc6b19e 100644
--- a/src/compiler/linkage.cc
+++ b/src/compiler/linkage.cc
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/compiler/linkage.h"
-
 #include "src/code-stubs.h"
 #include "src/compiler.h"
+#include "src/compiler/linkage.h"
 #include "src/compiler/node.h"
 #include "src/compiler/pipeline.h"
 #include "src/scopes.h"
@@ -15,7 +14,7 @@
 namespace compiler {
 
 
-OStream& operator<<(OStream& os, const CallDescriptor::Kind& k) {
+std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k) {
   switch (k) {
     case CallDescriptor::kCallCodeObject:
       os << "Code";
@@ -31,7 +30,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const CallDescriptor& d) {
+std::ostream& operator<<(std::ostream& os, const CallDescriptor& d) {
   // TODO(svenpanne) Output properties etc. and be less cryptic.
   return os << d.kind() << ":" << d.debug_name() << ":r" << d.ReturnCount()
             << "j" << d.JSParameterCount() << "i" << d.InputCount() << "f"
@@ -39,28 +38,33 @@
 }
 
 
-Linkage::Linkage(CompilationInfo* info) : info_(info) {
+CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
   if (info->function() != NULL) {
     // If we already have the function literal, use the number of parameters
     // plus the receiver.
-    incoming_ = GetJSCallDescriptor(1 + info->function()->parameter_count());
-  } else if (!info->closure().is_null()) {
+    return GetJSCallDescriptor(1 + info->function()->parameter_count(), zone,
+                               CallDescriptor::kNoFlags);
+  }
+  if (!info->closure().is_null()) {
     // If we are compiling a JS function, use a JS call descriptor,
     // plus the receiver.
     SharedFunctionInfo* shared = info->closure()->shared();
-    incoming_ = GetJSCallDescriptor(1 + shared->formal_parameter_count());
-  } else if (info->code_stub() != NULL) {
+    return GetJSCallDescriptor(1 + shared->formal_parameter_count(), zone,
+                               CallDescriptor::kNoFlags);
+  }
+  if (info->code_stub() != NULL) {
     // Use the code stub interface descriptor.
     CallInterfaceDescriptor descriptor =
         info->code_stub()->GetCallInterfaceDescriptor();
-    incoming_ = GetStubCallDescriptor(descriptor);
-  } else {
-    incoming_ = NULL;  // TODO(titzer): ?
+    return GetStubCallDescriptor(descriptor, 0, CallDescriptor::kNoFlags,
+                                 Operator::kNoProperties, zone);
   }
+  return NULL;  // TODO(titzer): ?
 }
 
 
-FrameOffset Linkage::GetFrameOffset(int spill_slot, Frame* frame, int extra) {
+FrameOffset Linkage::GetFrameOffset(int spill_slot, Frame* frame,
+                                    int extra) const {
   if (frame->GetSpillSlotCount() > 0 || incoming_->IsJSFunctionCall() ||
       incoming_->kind() == CallDescriptor::kCallAddress) {
     int offset;
@@ -87,24 +91,24 @@
 }
 
 
-CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count) {
-  return GetJSCallDescriptor(parameter_count, this->info_->zone());
+CallDescriptor* Linkage::GetJSCallDescriptor(
+    int parameter_count, CallDescriptor::Flags flags) const {
+  return GetJSCallDescriptor(parameter_count, zone_, flags);
 }
 
 
 CallDescriptor* Linkage::GetRuntimeCallDescriptor(
     Runtime::FunctionId function, int parameter_count,
-    Operator::Properties properties) {
-  return GetRuntimeCallDescriptor(function, parameter_count, properties,
-                                  this->info_->zone());
+    Operator::Properties properties) const {
+  return GetRuntimeCallDescriptor(function, parameter_count, properties, zone_);
 }
 
 
 CallDescriptor* Linkage::GetStubCallDescriptor(
-    CallInterfaceDescriptor descriptor, int stack_parameter_count,
-    CallDescriptor::Flags flags) {
+    const CallInterfaceDescriptor& descriptor, int stack_parameter_count,
+    CallDescriptor::Flags flags, Operator::Properties properties) const {
   return GetStubCallDescriptor(descriptor, stack_parameter_count, flags,
-                               this->info_->zone());
+                               properties, zone_);
 }
 
 
@@ -116,16 +120,98 @@
   // TODO(jarin) At the moment, we only add frame state for
   // few chosen runtime functions.
   switch (function) {
-    case Runtime::kDebugBreak:
-    case Runtime::kDebugGetLoadedScripts:
-    case Runtime::kDeoptimizeFunction:
-    case Runtime::kInlineCallFunction:
-    case Runtime::kPrepareStep:
-    case Runtime::kSetScriptBreakPoint:
-    case Runtime::kStackGuard:
+    case Runtime::kApply:
+    case Runtime::kArrayBufferNeuter:
+    case Runtime::kArrayConcat:
+    case Runtime::kBasicJSONStringify:
     case Runtime::kCheckExecutionState:
-    case Runtime::kDebugEvaluate:
     case Runtime::kCollectStackTrace:
+    case Runtime::kCompileLazy:
+    case Runtime::kCompileOptimized:
+    case Runtime::kCompileString:
+    case Runtime::kCreateObjectLiteral:
+    case Runtime::kDebugBreak:
+    case Runtime::kDataViewSetInt8:
+    case Runtime::kDataViewSetUint8:
+    case Runtime::kDataViewSetInt16:
+    case Runtime::kDataViewSetUint16:
+    case Runtime::kDataViewSetInt32:
+    case Runtime::kDataViewSetUint32:
+    case Runtime::kDataViewSetFloat32:
+    case Runtime::kDataViewSetFloat64:
+    case Runtime::kDataViewGetInt8:
+    case Runtime::kDataViewGetUint8:
+    case Runtime::kDataViewGetInt16:
+    case Runtime::kDataViewGetUint16:
+    case Runtime::kDataViewGetInt32:
+    case Runtime::kDataViewGetUint32:
+    case Runtime::kDataViewGetFloat32:
+    case Runtime::kDataViewGetFloat64:
+    case Runtime::kDebugEvaluate:
+    case Runtime::kDebugEvaluateGlobal:
+    case Runtime::kDebugGetLoadedScripts:
+    case Runtime::kDebugGetPropertyDetails:
+    case Runtime::kDebugPromiseEvent:
+    case Runtime::kDefineAccessorPropertyUnchecked:
+    case Runtime::kDefineDataPropertyUnchecked:
+    case Runtime::kDeleteProperty:
+    case Runtime::kDeoptimizeFunction:
+    case Runtime::kFunctionBindArguments:
+    case Runtime::kGetDefaultReceiver:
+    case Runtime::kGetFrameCount:
+    case Runtime::kGetOwnProperty:
+    case Runtime::kGetOwnPropertyNames:
+    case Runtime::kGetPropertyNamesFast:
+    case Runtime::kGetPrototype:
+    case Runtime::kInlineArguments:
+    case Runtime::kInlineCallFunction:
+    case Runtime::kInlineDateField:
+    case Runtime::kInlineRegExpExec:
+    case Runtime::kInternalSetPrototype:
+    case Runtime::kInterrupt:
+    case Runtime::kIsPropertyEnumerable:
+    case Runtime::kIsSloppyModeFunction:
+    case Runtime::kLiveEditGatherCompileInfo:
+    case Runtime::kLoadLookupSlot:
+    case Runtime::kLoadLookupSlotNoReferenceError:
+    case Runtime::kMaterializeRegExpLiteral:
+    case Runtime::kNewObject:
+    case Runtime::kNewObjectFromBound:
+    case Runtime::kNewObjectWithAllocationSite:
+    case Runtime::kObjectFreeze:
+    case Runtime::kOwnKeys:
+    case Runtime::kParseJson:
+    case Runtime::kPrepareStep:
+    case Runtime::kPreventExtensions:
+    case Runtime::kPromiseRejectEvent:
+    case Runtime::kPromiseRevokeReject:
+    case Runtime::kRegExpInitializeAndCompile:
+    case Runtime::kRegExpExecMultiple:
+    case Runtime::kResolvePossiblyDirectEval:
+    case Runtime::kRunMicrotasks:
+    case Runtime::kSetPrototype:
+    case Runtime::kSetScriptBreakPoint:
+    case Runtime::kSparseJoinWithSeparator:
+    case Runtime::kStackGuard:
+    case Runtime::kStoreKeyedToSuper_Sloppy:
+    case Runtime::kStoreKeyedToSuper_Strict:
+    case Runtime::kStoreToSuper_Sloppy:
+    case Runtime::kStoreToSuper_Strict:
+    case Runtime::kStoreLookupSlot:
+    case Runtime::kStringBuilderConcat:
+    case Runtime::kStringBuilderJoin:
+    case Runtime::kStringMatch:
+    case Runtime::kStringReplaceGlobalRegExpWithString:
+    case Runtime::kThrowNonMethodError:
+    case Runtime::kThrowNotDateError:
+    case Runtime::kThrowReferenceError:
+    case Runtime::kThrowUnsupportedSuperError:
+    case Runtime::kThrow:
+    case Runtime::kTypedArraySetFastCases:
+    case Runtime::kTypedArrayInitializeFromArrayLike:
+#ifdef V8_I18N_SUPPORT
+    case Runtime::kGetImplFromInitializedIntlObject:
+#endif
       return true;
     default:
       return false;
@@ -137,7 +223,8 @@
 // Provide unimplemented methods on unsupported architectures, to at least link.
 //==============================================================================
 #if !V8_TURBOFAN_BACKEND
-CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
+CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone,
+                                             CallDescriptor::Flags flags) {
   UNIMPLEMENTED();
   return NULL;
 }
@@ -152,8 +239,9 @@
 
 
 CallDescriptor* Linkage::GetStubCallDescriptor(
-    CallInterfaceDescriptor descriptor, int stack_parameter_count,
-    CallDescriptor::Flags flags, Zone* zone) {
+    const CallInterfaceDescriptor& descriptor, int stack_parameter_count,
+    CallDescriptor::Flags flags, Operator::Properties properties,
+    Zone* zone) {
   UNIMPLEMENTED();
   return NULL;
 }
diff --git a/src/compiler/linkage.h b/src/compiler/linkage.h
index c5cef5e..0ad0761 100644
--- a/src/compiler/linkage.h
+++ b/src/compiler/linkage.h
@@ -6,15 +6,16 @@
 #define V8_COMPILER_LINKAGE_H_
 
 #include "src/base/flags.h"
-#include "src/code-stubs.h"
 #include "src/compiler/frame.h"
 #include "src/compiler/machine-type.h"
-#include "src/compiler/node.h"
 #include "src/compiler/operator.h"
 #include "src/zone.h"
 
 namespace v8 {
 namespace internal {
+
+class CallInterfaceDescriptor;
+
 namespace compiler {
 
 // Describes the location for a parameter or a return value to a call.
@@ -129,22 +130,24 @@
  private:
   friend class Linkage;
 
-  Kind kind_;
-  MachineType target_type_;
-  LinkageLocation target_loc_;
-  MachineSignature* machine_sig_;
-  LocationSignature* location_sig_;
-  size_t js_param_count_;
-  Operator::Properties properties_;
-  RegList callee_saved_registers_;
-  Flags flags_;
-  const char* debug_name_;
+  const Kind kind_;
+  const MachineType target_type_;
+  const LinkageLocation target_loc_;
+  const MachineSignature* const machine_sig_;
+  const LocationSignature* const location_sig_;
+  const size_t js_param_count_;
+  const Operator::Properties properties_;
+  const RegList callee_saved_registers_;
+  const Flags flags_;
+  const char* const debug_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(CallDescriptor);
 };
 
 DEFINE_OPERATORS_FOR_FLAGS(CallDescriptor::Flags)
 
-OStream& operator<<(OStream& os, const CallDescriptor& d);
-OStream& operator<<(OStream& os, const CallDescriptor::Kind& k);
+std::ostream& operator<<(std::ostream& os, const CallDescriptor& d);
+std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k);
 
 // Defines the linkage for a compilation, including the calling conventions
 // for incoming parameters and return value(s) as well as the outgoing calling
@@ -161,28 +164,34 @@
 // Call[Runtime]    CEntryStub, arg 1, arg 2, arg 3, [...], fun, #arg, context
 class Linkage : public ZoneObject {
  public:
-  explicit Linkage(CompilationInfo* info);
-  explicit Linkage(CompilationInfo* info, CallDescriptor* incoming)
-      : info_(info), incoming_(incoming) {}
+  Linkage(Zone* zone, CompilationInfo* info)
+      : zone_(zone), incoming_(ComputeIncoming(zone, info)) {}
+  Linkage(Zone* zone, CallDescriptor* incoming)
+      : zone_(zone), incoming_(incoming) {}
+
+  static CallDescriptor* ComputeIncoming(Zone* zone, CompilationInfo* info);
 
   // The call descriptor for this compilation unit describes the locations
   // of incoming parameters and the outgoing return value(s).
-  CallDescriptor* GetIncomingDescriptor() { return incoming_; }
-  CallDescriptor* GetJSCallDescriptor(int parameter_count);
-  static CallDescriptor* GetJSCallDescriptor(int parameter_count, Zone* zone);
-  CallDescriptor* GetRuntimeCallDescriptor(Runtime::FunctionId function,
-                                           int parameter_count,
-                                           Operator::Properties properties);
+  CallDescriptor* GetIncomingDescriptor() const { return incoming_; }
+  CallDescriptor* GetJSCallDescriptor(int parameter_count,
+                                      CallDescriptor::Flags flags) const;
+  static CallDescriptor* GetJSCallDescriptor(int parameter_count, Zone* zone,
+                                             CallDescriptor::Flags flags);
+  CallDescriptor* GetRuntimeCallDescriptor(
+      Runtime::FunctionId function, int parameter_count,
+      Operator::Properties properties) const;
   static CallDescriptor* GetRuntimeCallDescriptor(
       Runtime::FunctionId function, int parameter_count,
       Operator::Properties properties, Zone* zone);
 
   CallDescriptor* GetStubCallDescriptor(
-      CallInterfaceDescriptor descriptor, int stack_parameter_count = 0,
-      CallDescriptor::Flags flags = CallDescriptor::kNoFlags);
+      const CallInterfaceDescriptor& descriptor, int stack_parameter_count = 0,
+      CallDescriptor::Flags flags = CallDescriptor::kNoFlags,
+      Operator::Properties properties = Operator::kNoProperties) const;
   static CallDescriptor* GetStubCallDescriptor(
-      CallInterfaceDescriptor descriptor, int stack_parameter_count,
-      CallDescriptor::Flags flags, Zone* zone);
+      const CallInterfaceDescriptor& descriptor, int stack_parameter_count,
+      CallDescriptor::Flags flags, Operator::Properties properties, Zone* zone);
 
   // Creates a call descriptor for simplified C calls that is appropriate
   // for the host platform. This simplified calling convention only supports
@@ -192,37 +201,37 @@
                                                   MachineSignature* sig);
 
   // Get the location of an (incoming) parameter to this function.
-  LinkageLocation GetParameterLocation(int index) {
+  LinkageLocation GetParameterLocation(int index) const {
     return incoming_->GetInputLocation(index + 1);  // + 1 to skip target.
   }
 
   // Get the machine type of an (incoming) parameter to this function.
-  MachineType GetParameterType(int index) {
+  MachineType GetParameterType(int index) const {
     return incoming_->GetInputType(index + 1);  // + 1 to skip target.
   }
 
   // Get the location where this function should place its return value.
-  LinkageLocation GetReturnLocation() {
+  LinkageLocation GetReturnLocation() const {
     return incoming_->GetReturnLocation(0);
   }
 
   // Get the machine type of this function's return value.
-  MachineType GetReturnType() { return incoming_->GetReturnType(0); }
+  MachineType GetReturnType() const { return incoming_->GetReturnType(0); }
 
   // Get the frame offset for a given spill slot. The location depends on the
   // calling convention and the specific frame layout, and may thus be
   // architecture-specific. Negative spill slots indicate arguments on the
   // caller's frame. The {extra} parameter indicates an additional offset from
   // the frame offset, e.g. to index into part of a double slot.
-  FrameOffset GetFrameOffset(int spill_slot, Frame* frame, int extra = 0);
-
-  CompilationInfo* info() const { return info_; }
+  FrameOffset GetFrameOffset(int spill_slot, Frame* frame, int extra = 0) const;
 
   static bool NeedsFrameState(Runtime::FunctionId function);
 
  private:
-  CompilationInfo* info_;
-  CallDescriptor* incoming_;
+  Zone* const zone_;
+  CallDescriptor* const incoming_;
+
+  DISALLOW_COPY_AND_ASSIGN(Linkage);
 };
 
 }  // namespace compiler
diff --git a/src/compiler/load-elimination.cc b/src/compiler/load-elimination.cc
new file mode 100644
index 0000000..fe0714e
--- /dev/null
+++ b/src/compiler/load-elimination.cc
@@ -0,0 +1,76 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/load-elimination.h"
+
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/simplified-operator.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+LoadElimination::~LoadElimination() {}
+
+
+Reduction LoadElimination::Reduce(Node* node) {
+  switch (node->opcode()) {
+    case IrOpcode::kLoadField:
+      return ReduceLoadField(node);
+    default:
+      break;
+  }
+  return NoChange();
+}
+
+
+Reduction LoadElimination::ReduceLoadField(Node* node) {
+  DCHECK_EQ(IrOpcode::kLoadField, node->opcode());
+  FieldAccess const access = FieldAccessOf(node->op());
+  Node* const object = NodeProperties::GetValueInput(node, 0);
+  for (Node* effect = NodeProperties::GetEffectInput(node);;
+       effect = NodeProperties::GetEffectInput(effect)) {
+    switch (effect->opcode()) {
+      case IrOpcode::kLoadField: {
+        if (object == NodeProperties::GetValueInput(effect, 0) &&
+            access == FieldAccessOf(effect->op())) {
+          Node* const value = effect;
+          NodeProperties::ReplaceWithValue(node, value);
+          return Replace(value);
+        }
+        break;
+      }
+      case IrOpcode::kStoreField: {
+        if (access == FieldAccessOf(effect->op())) {
+          if (object == NodeProperties::GetValueInput(effect, 0)) {
+            Node* const value = NodeProperties::GetValueInput(effect, 1);
+            NodeProperties::ReplaceWithValue(node, value);
+            return Replace(value);
+          }
+          // TODO(turbofan): Alias analysis to the rescue?
+          return NoChange();
+        }
+        break;
+      }
+      case IrOpcode::kStoreBuffer:
+      case IrOpcode::kStoreElement: {
+        // These can never interfere with field loads.
+        break;
+      }
+      default: {
+        if (!effect->op()->HasProperty(Operator::kNoWrite) ||
+            effect->op()->EffectInputCount() != 1) {
+          return NoChange();
+        }
+        break;
+      }
+    }
+  }
+  UNREACHABLE();
+  return NoChange();
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/load-elimination.h b/src/compiler/load-elimination.h
new file mode 100644
index 0000000..6917ce3
--- /dev/null
+++ b/src/compiler/load-elimination.h
@@ -0,0 +1,29 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_LOAD_ELIMINATION_H_
+#define V8_COMPILER_LOAD_ELIMINATION_H_
+
+#include "src/compiler/graph-reducer.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class LoadElimination FINAL : public Reducer {
+ public:
+  LoadElimination() {}
+  ~LoadElimination() FINAL;
+
+  Reduction Reduce(Node* node) FINAL;
+
+ private:
+  Reduction ReduceLoadField(Node* node);
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_LOAD_ELIMINATION_H_
diff --git a/src/compiler/loop-analysis.cc b/src/compiler/loop-analysis.cc
new file mode 100644
index 0000000..e1b703e
--- /dev/null
+++ b/src/compiler/loop-analysis.cc
@@ -0,0 +1,411 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/graph.h"
+#include "src/compiler/loop-analysis.h"
+#include "src/compiler/node.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/zone.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+typedef uint32_t LoopMarks;
+
+
+// TODO(titzer): don't assume entry edges have a particular index.
+// TODO(titzer): use a BitMatrix to generalize this algorithm.
+static const size_t kMaxLoops = 31;
+static const int kAssumedLoopEntryIndex = 0;  // assume loops are entered here.
+static const LoopMarks kVisited = 1;          // loop #0 is reserved.
+
+
+// Temporary information for each node during marking.
+struct NodeInfo {
+  Node* node;
+  NodeInfo* next;       // link in chaining loop members
+  LoopMarks forward;    // accumulated marks in the forward direction
+  LoopMarks backward;   // accumulated marks in the backward direction
+  LoopMarks loop_mark;  // loop mark for header nodes; encodes loop_num
+
+  bool MarkBackward(LoopMarks bw) {
+    LoopMarks prev = backward;
+    LoopMarks next = backward | bw;
+    backward = next;
+    return prev != next;
+  }
+
+  bool MarkForward(LoopMarks fw) {
+    LoopMarks prev = forward;
+    LoopMarks next = forward | fw;
+    forward = next;
+    return prev != next;
+  }
+
+  bool IsInLoop(size_t loop_num) {
+    DCHECK(loop_num > 0 && loop_num <= 31);
+    return forward & backward & (1 << loop_num);
+  }
+
+  bool IsLoopHeader() { return loop_mark != 0; }
+  bool IsInAnyLoop() { return (forward & backward) > kVisited; }
+
+  bool IsInHeaderForLoop(size_t loop_num) {
+    DCHECK(loop_num > 0);
+    return loop_mark == (kVisited | (1 << loop_num));
+  }
+};
+
+
+// Temporary loop info needed during traversal and building the loop tree.
+struct LoopInfo {
+  Node* header;
+  NodeInfo* header_list;
+  NodeInfo* body_list;
+  LoopTree::Loop* loop;
+};
+
+
+static const NodeInfo kEmptyNodeInfo = {nullptr, nullptr, 0, 0, 0};
+
+
+// Encapsulation of the loop finding algorithm.
+// -----------------------------------------------------------------------------
+// Conceptually, the contents of a loop are those nodes that are "between" the
+// loop header and the backedges of the loop. Graphs in the soup of nodes can
+// form improper cycles, so standard loop finding algorithms that work on CFGs
+// aren't sufficient. However, in valid TurboFan graphs, all cycles involve
+// either a {Loop} node or a phi. The {Loop} node itself and its accompanying
+// phis are treated together as a set referred to here as the loop header.
+// This loop finding algorithm works by traversing the graph in two directions,
+// first from nodes to their inputs, starting at {end}, then in the reverse
+// direction, from nodes to their uses, starting at loop headers.
+// 1 bit per loop per node per direction are required during the marking phase.
+// To handle nested loops correctly, the algorithm must filter some reachability
+// marks on edges into/out-of the loop header nodes.
+class LoopFinderImpl {
+ public:
+  LoopFinderImpl(Graph* graph, LoopTree* loop_tree, Zone* zone)
+      : end_(graph->end()),
+        queue_(zone),
+        queued_(graph, 2),
+        info_(graph->NodeCount(), kEmptyNodeInfo, zone),
+        loops_(zone),
+        loop_tree_(loop_tree),
+        loops_found_(0) {}
+
+  void Run() {
+    PropagateBackward();
+    PropagateForward();
+    FinishLoopTree();
+  }
+
+  void Print() {
+    // Print out the results.
+    for (NodeInfo& ni : info_) {
+      if (ni.node == nullptr) continue;
+      for (size_t i = 1; i <= loops_.size(); i++) {
+        if (ni.IsInLoop(i)) {
+          PrintF("X");
+        } else if (ni.forward & (1 << i)) {
+          PrintF("/");
+        } else if (ni.backward & (1 << i)) {
+          PrintF("\\");
+        } else {
+          PrintF(" ");
+        }
+      }
+      PrintF(" #%d:%s\n", ni.node->id(), ni.node->op()->mnemonic());
+    }
+
+    int i = 0;
+    for (LoopInfo& li : loops_) {
+      PrintF("Loop %d headed at #%d\n", i, li.header->id());
+      i++;
+    }
+
+    for (LoopTree::Loop* loop : loop_tree_->outer_loops_) {
+      PrintLoop(loop);
+    }
+  }
+
+ private:
+  Node* end_;
+  NodeDeque queue_;
+  NodeMarker<bool> queued_;
+  ZoneVector<NodeInfo> info_;
+  ZoneVector<LoopInfo> loops_;
+  LoopTree* loop_tree_;
+  size_t loops_found_;
+
+  // Propagate marks backward from loop headers.
+  void PropagateBackward() {
+    PropagateBackward(end_, kVisited);
+
+    while (!queue_.empty()) {
+      Node* node = queue_.front();
+      queue_.pop_front();
+      queued_.Set(node, false);
+
+      // Setup loop headers first.
+      if (node->opcode() == IrOpcode::kLoop) {
+        // found the loop node first.
+        CreateLoopInfo(node);
+      } else if (node->opcode() == IrOpcode::kPhi ||
+                 node->opcode() == IrOpcode::kEffectPhi) {
+        // found a phi first.
+        Node* merge = node->InputAt(node->InputCount() - 1);
+        if (merge->opcode() == IrOpcode::kLoop) CreateLoopInfo(merge);
+      }
+
+      // Propagate reachability marks backwards from this node.
+      NodeInfo& ni = info(node);
+      if (ni.IsLoopHeader()) {
+        // Handle edges from loop header nodes specially.
+        for (int i = 0; i < node->InputCount(); i++) {
+          if (i == kAssumedLoopEntryIndex) {
+            // Don't propagate the loop mark backwards on the entry edge.
+            PropagateBackward(node->InputAt(0),
+                              kVisited | (ni.backward & ~ni.loop_mark));
+          } else {
+            // Only propagate the loop mark on backedges.
+            PropagateBackward(node->InputAt(i), ni.loop_mark);
+          }
+        }
+      } else {
+        // Propagate all loop marks backwards for a normal node.
+        for (Node* const input : node->inputs()) {
+          PropagateBackward(input, ni.backward);
+        }
+      }
+    }
+  }
+
+  // Make a new loop header for the given node.
+  void CreateLoopInfo(Node* node) {
+    NodeInfo& ni = info(node);
+    if (ni.IsLoopHeader()) return;  // loop already set up.
+
+    loops_found_++;
+    size_t loop_num = loops_.size() + 1;
+    CHECK(loops_found_ <= kMaxLoops);  // TODO(titzer): don't crash.
+    // Create a new loop.
+    loops_.push_back({node, nullptr, nullptr, nullptr});
+    loop_tree_->NewLoop();
+    LoopMarks loop_mark = kVisited | (1 << loop_num);
+    ni.node = node;
+    ni.loop_mark = loop_mark;
+
+    // Setup loop mark for phis attached to loop header.
+    for (Node* use : node->uses()) {
+      if (use->opcode() == IrOpcode::kPhi ||
+          use->opcode() == IrOpcode::kEffectPhi) {
+        info(use).loop_mark = loop_mark;
+      }
+    }
+  }
+
+  // Propagate marks forward from loops.
+  void PropagateForward() {
+    for (LoopInfo& li : loops_) {
+      queued_.Set(li.header, true);
+      queue_.push_back(li.header);
+      NodeInfo& ni = info(li.header);
+      ni.forward = ni.loop_mark;
+    }
+    // Propagate forward on paths that were backward reachable from backedges.
+    while (!queue_.empty()) {
+      Node* node = queue_.front();
+      queue_.pop_front();
+      queued_.Set(node, false);
+      NodeInfo& ni = info(node);
+      for (Edge edge : node->use_edges()) {
+        Node* use = edge.from();
+        NodeInfo& ui = info(use);
+        if (IsBackedge(use, ui, edge)) continue;  // skip backedges.
+        LoopMarks both = ni.forward & ui.backward;
+        if (ui.MarkForward(both) && !queued_.Get(use)) {
+          queued_.Set(use, true);
+          queue_.push_back(use);
+        }
+      }
+    }
+  }
+
+  bool IsBackedge(Node* use, NodeInfo& ui, Edge& edge) {
+    // TODO(titzer): checking for backedges here is ugly.
+    if (!ui.IsLoopHeader()) return false;
+    if (edge.index() == kAssumedLoopEntryIndex) return false;
+    if (use->opcode() == IrOpcode::kPhi ||
+        use->opcode() == IrOpcode::kEffectPhi) {
+      return !NodeProperties::IsControlEdge(edge);
+    }
+    return true;
+  }
+
+  NodeInfo& info(Node* node) {
+    NodeInfo& i = info_[node->id()];
+    if (i.node == nullptr) i.node = node;
+    return i;
+  }
+
+  void PropagateBackward(Node* node, LoopMarks marks) {
+    if (info(node).MarkBackward(marks) && !queued_.Get(node)) {
+      queue_.push_back(node);
+      queued_.Set(node, true);
+    }
+  }
+
+  void FinishLoopTree() {
+    // Degenerate cases.
+    if (loops_.size() == 0) return;
+    if (loops_.size() == 1) return FinishSingleLoop();
+
+    for (size_t i = 1; i <= loops_.size(); i++) ConnectLoopTree(i);
+
+    size_t count = 0;
+    // Place the node into the innermost nested loop of which it is a member.
+    for (NodeInfo& ni : info_) {
+      if (ni.node == nullptr || !ni.IsInAnyLoop()) continue;
+
+      LoopInfo* innermost = nullptr;
+      size_t index = 0;
+      for (size_t i = 1; i <= loops_.size(); i++) {
+        if (ni.IsInLoop(i)) {
+          LoopInfo* loop = &loops_[i - 1];
+          if (innermost == nullptr ||
+              loop->loop->depth_ > innermost->loop->depth_) {
+            innermost = loop;
+            index = i;
+          }
+        }
+      }
+      if (ni.IsInHeaderForLoop(index)) {
+        ni.next = innermost->header_list;
+        innermost->header_list = &ni;
+      } else {
+        ni.next = innermost->body_list;
+        innermost->body_list = &ni;
+      }
+      count++;
+    }
+
+    // Serialize the node lists for loops into the loop tree.
+    loop_tree_->loop_nodes_.reserve(count);
+    for (LoopTree::Loop* loop : loop_tree_->outer_loops_) {
+      SerializeLoop(loop);
+    }
+  }
+
+  // Handle the simpler case of a single loop (no checks for nesting necessary).
+  void FinishSingleLoop() {
+    DCHECK(loops_.size() == 1);
+    DCHECK(loop_tree_->all_loops_.size() == 1);
+
+    // Place nodes into the loop header and body.
+    LoopInfo* li = &loops_[0];
+    li->loop = &loop_tree_->all_loops_[0];
+    loop_tree_->SetParent(nullptr, li->loop);
+    size_t count = 0;
+    for (NodeInfo& ni : info_) {
+      if (ni.node == nullptr || !ni.IsInAnyLoop()) continue;
+      DCHECK(ni.IsInLoop(1));
+      if (ni.IsInHeaderForLoop(1)) {
+        ni.next = li->header_list;
+        li->header_list = &ni;
+      } else {
+        ni.next = li->body_list;
+        li->body_list = &ni;
+      }
+      count++;
+    }
+
+    // Serialize the node lists for the loop into the loop tree.
+    loop_tree_->loop_nodes_.reserve(count);
+    SerializeLoop(li->loop);
+  }
+
+  // Recursively serialize the list of header nodes and body nodes
+  // so that nested loops occupy nested intervals.
+  void SerializeLoop(LoopTree::Loop* loop) {
+    size_t loop_num = loop_tree_->LoopNum(loop);
+    LoopInfo& li = loops_[loop_num - 1];
+
+    // Serialize the header.
+    loop->header_start_ = static_cast<int>(loop_tree_->loop_nodes_.size());
+    for (NodeInfo* ni = li.header_list; ni != nullptr; ni = ni->next) {
+      loop_tree_->loop_nodes_.push_back(ni->node);
+      // TODO(titzer): lift loop count restriction.
+      loop_tree_->node_to_loop_num_[ni->node->id()] =
+          static_cast<uint8_t>(loop_num);
+    }
+
+    // Serialize the body.
+    loop->body_start_ = static_cast<int>(loop_tree_->loop_nodes_.size());
+    for (NodeInfo* ni = li.body_list; ni != nullptr; ni = ni->next) {
+      loop_tree_->loop_nodes_.push_back(ni->node);
+      // TODO(titzer): lift loop count restriction.
+      loop_tree_->node_to_loop_num_[ni->node->id()] =
+          static_cast<uint8_t>(loop_num);
+    }
+
+    // Serialize nested loops.
+    for (LoopTree::Loop* child : loop->children_) SerializeLoop(child);
+
+    loop->body_end_ = static_cast<int>(loop_tree_->loop_nodes_.size());
+  }
+
+  // Connect the LoopTree loops to their parents recursively.
+  LoopTree::Loop* ConnectLoopTree(size_t loop_num) {
+    LoopInfo& li = loops_[loop_num - 1];
+    if (li.loop != nullptr) return li.loop;
+
+    NodeInfo& ni = info(li.header);
+    LoopTree::Loop* parent = nullptr;
+    for (size_t i = 1; i <= loops_.size(); i++) {
+      if (i == loop_num) continue;
+      if (ni.IsInLoop(i)) {
+        // recursively create potential parent loops first.
+        LoopTree::Loop* upper = ConnectLoopTree(i);
+        if (parent == nullptr || upper->depth_ > parent->depth_) {
+          parent = upper;
+        }
+      }
+    }
+    li.loop = &loop_tree_->all_loops_[loop_num - 1];
+    loop_tree_->SetParent(parent, li.loop);
+    return li.loop;
+  }
+
+  void PrintLoop(LoopTree::Loop* loop) {
+    for (int i = 0; i < loop->depth_; i++) PrintF("  ");
+    PrintF("Loop depth = %d ", loop->depth_);
+    int i = loop->header_start_;
+    while (i < loop->body_start_) {
+      PrintF(" H#%d", loop_tree_->loop_nodes_[i++]->id());
+    }
+    while (i < loop->body_end_) {
+      PrintF(" B#%d", loop_tree_->loop_nodes_[i++]->id());
+    }
+    PrintF("\n");
+    for (LoopTree::Loop* child : loop->children_) PrintLoop(child);
+  }
+};
+
+
+LoopTree* LoopFinder::BuildLoopTree(Graph* graph, Zone* zone) {
+  LoopTree* loop_tree =
+      new (graph->zone()) LoopTree(graph->NodeCount(), graph->zone());
+  LoopFinderImpl finder(graph, loop_tree, zone);
+  finder.Run();
+  if (FLAG_trace_turbo_graph) {
+    finder.Print();
+  }
+  return loop_tree;
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/loop-analysis.h b/src/compiler/loop-analysis.h
new file mode 100644
index 0000000..8c8d19a
--- /dev/null
+++ b/src/compiler/loop-analysis.h
@@ -0,0 +1,135 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_LOOP_ANALYSIS_H_
+#define V8_COMPILER_LOOP_ANALYSIS_H_
+
+#include "src/base/iterator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/node.h"
+#include "src/zone-containers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class LoopFinderImpl;
+
+typedef base::iterator_range<Node**> NodeRange;
+
+// Represents a tree of loops in a graph.
+class LoopTree : public ZoneObject {
+ public:
+  LoopTree(size_t num_nodes, Zone* zone)
+      : zone_(zone),
+        outer_loops_(zone),
+        all_loops_(zone),
+        node_to_loop_num_(static_cast<int>(num_nodes), 0, zone),
+        loop_nodes_(zone) {}
+
+  // Represents a loop in the tree of loops, including the header nodes,
+  // the body, and any nested loops.
+  class Loop {
+   public:
+    Loop* parent() const { return parent_; }
+    const ZoneVector<Loop*>& children() const { return children_; }
+    size_t HeaderSize() const { return body_start_ - header_start_; }
+    size_t BodySize() const { return body_end_ - body_start_; }
+    size_t TotalSize() const { return body_end_ - header_start_; }
+
+   private:
+    friend class LoopTree;
+    friend class LoopFinderImpl;
+
+    explicit Loop(Zone* zone)
+        : parent_(nullptr),
+          depth_(0),
+          children_(zone),
+          header_start_(-1),
+          body_start_(-1),
+          body_end_(-1) {}
+    Loop* parent_;
+    int depth_;
+    ZoneVector<Loop*> children_;
+    int header_start_;
+    int body_start_;
+    int body_end_;
+  };
+
+  // Return the innermost nested loop, if any, that contains {node}.
+  Loop* ContainingLoop(Node* node) {
+    if (node->id() >= static_cast<int>(node_to_loop_num_.size()))
+      return nullptr;
+    uint8_t num = node_to_loop_num_[node->id()];
+    return num > 0 ? &all_loops_[num - 1] : nullptr;
+  }
+
+  // Check if the {loop} contains the {node}, either directly or by containing
+  // a nested loop that contains {node}.
+  bool Contains(Loop* loop, Node* node) {
+    for (Loop* c = ContainingLoop(node); c != nullptr; c = c->parent_) {
+      if (c == loop) return true;
+    }
+    return false;
+  }
+
+  // Return the list of outer loops.
+  const ZoneVector<Loop*>& outer_loops() const { return outer_loops_; }
+
+  // Return the unique loop number for a given loop. Loop numbers start at {1}.
+  int LoopNum(Loop* loop) const {
+    return 1 + static_cast<int>(loop - &all_loops_[0]);
+  }
+
+  // Return a range which can iterate over the header nodes of {loop}.
+  NodeRange HeaderNodes(Loop* loop) {
+    return NodeRange(&loop_nodes_[0] + loop->header_start_,
+                     &loop_nodes_[0] + loop->body_start_);
+  }
+
+  // Return a range which can iterate over the body nodes of {loop}.
+  NodeRange BodyNodes(Loop* loop) {
+    return NodeRange(&loop_nodes_[0] + loop->body_start_,
+                     &loop_nodes_[0] + loop->body_end_);
+  }
+
+ private:
+  friend class LoopFinderImpl;
+
+  Loop* NewLoop() {
+    all_loops_.push_back(Loop(zone_));
+    Loop* result = &all_loops_.back();
+    return result;
+  }
+
+  void SetParent(Loop* parent, Loop* child) {
+    if (parent != nullptr) {
+      parent->children_.push_back(child);
+      child->parent_ = parent;
+      child->depth_ = parent->depth_ + 1;
+    } else {
+      outer_loops_.push_back(child);
+    }
+  }
+
+  Zone* zone_;
+  ZoneVector<Loop*> outer_loops_;
+  ZoneVector<Loop> all_loops_;
+  // TODO(titzer): lift loop count restriction.
+  ZoneVector<uint8_t> node_to_loop_num_;
+  ZoneVector<Node*> loop_nodes_;
+};
+
+
+class LoopFinder {
+ public:
+  // Build a loop tree for the entire graph.
+  static LoopTree* BuildLoopTree(Graph* graph, Zone* temp_zone);
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_LOOP_ANALYSIS_H_
diff --git a/src/compiler/machine-operator-reducer-unittest.cc b/src/compiler/machine-operator-reducer-unittest.cc
deleted file mode 100644
index f3073ab..0000000
--- a/src/compiler/machine-operator-reducer-unittest.cc
+++ /dev/null
@@ -1,616 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/base/bits.h"
-#include "src/compiler/graph-unittest.h"
-#include "src/compiler/js-graph.h"
-#include "src/compiler/machine-operator-reducer.h"
-#include "src/compiler/typer.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-class MachineOperatorReducerTest : public GraphTest {
- public:
-  explicit MachineOperatorReducerTest(int num_parameters = 2)
-      : GraphTest(num_parameters) {}
-
- protected:
-  Reduction Reduce(Node* node) {
-    Typer typer(zone());
-    JSOperatorBuilder javascript(zone());
-    JSGraph jsgraph(graph(), common(), &javascript, &typer, &machine_);
-    MachineOperatorReducer reducer(&jsgraph);
-    return reducer.Reduce(node);
-  }
-
-  MachineOperatorBuilder* machine() { return &machine_; }
-
- private:
-  MachineOperatorBuilder machine_;
-};
-
-
-template <typename T>
-class MachineOperatorReducerTestWithParam
-    : public MachineOperatorReducerTest,
-      public ::testing::WithParamInterface<T> {
- public:
-  explicit MachineOperatorReducerTestWithParam(int num_parameters = 2)
-      : MachineOperatorReducerTest(num_parameters) {}
-  virtual ~MachineOperatorReducerTestWithParam() {}
-};
-
-
-namespace {
-
-static const float kFloat32Values[] = {
-    -std::numeric_limits<float>::infinity(), -2.70497e+38f, -1.4698e+37f,
-    -1.22813e+35f,                           -1.20555e+35f, -1.34584e+34f,
-    -1.0079e+32f,                            -6.49364e+26f, -3.06077e+25f,
-    -1.46821e+25f,                           -1.17658e+23f, -1.9617e+22f,
-    -2.7357e+20f,                            -1.48708e+13f, -1.89633e+12f,
-    -4.66622e+11f,                           -2.22581e+11f, -1.45381e+10f,
-    -1.3956e+09f,                            -1.32951e+09f, -1.30721e+09f,
-    -1.19756e+09f,                           -9.26822e+08f, -6.35647e+08f,
-    -4.00037e+08f,                           -1.81227e+08f, -5.09256e+07f,
-    -964300.0f,                              -192446.0f,    -28455.0f,
-    -27194.0f,                               -26401.0f,     -20575.0f,
-    -17069.0f,                               -9167.0f,      -960.178f,
-    -113.0f,                                 -62.0f,        -15.0f,
-    -7.0f,                                   -0.0256635f,   -4.60374e-07f,
-    -3.63759e-10f,                           -4.30175e-14f, -5.27385e-15f,
-    -1.48084e-15f,                           -1.05755e-19f, -3.2995e-21f,
-    -1.67354e-23f,                           -1.11885e-23f, -1.78506e-30f,
-    -5.07594e-31f,                           -3.65799e-31f, -1.43718e-34f,
-    -1.27126e-38f,                           -0.0f,         0.0f,
-    1.17549e-38f,                            1.56657e-37f,  4.08512e-29f,
-    3.31357e-28f,                            6.25073e-22f,  4.1723e-13f,
-    1.44343e-09f,                            5.27004e-08f,  9.48298e-08f,
-    5.57888e-07f,                            4.89988e-05f,  0.244326f,
-    12.4895f,                                19.0f,         47.0f,
-    106.0f,                                  538.324f,      564.536f,
-    819.124f,                                7048.0f,       12611.0f,
-    19878.0f,                                20309.0f,      797056.0f,
-    1.77219e+09f,                            1.51116e+11f,  4.18193e+13f,
-    3.59167e+16f,                            3.38211e+19f,  2.67488e+20f,
-    1.78831e+21f,                            9.20914e+21f,  8.35654e+23f,
-    1.4495e+24f,                             5.94015e+25f,  4.43608e+30f,
-    2.44502e+33f,                            2.61152e+33f,  1.38178e+37f,
-    1.71306e+37f,                            3.31899e+38f,  3.40282e+38f,
-    std::numeric_limits<float>::infinity()};
-
-
-static const double kFloat64Values[] = {
-    -V8_INFINITY,  -4.23878e+275, -5.82632e+265, -6.60355e+220, -6.26172e+212,
-    -2.56222e+211, -4.82408e+201, -1.84106e+157, -1.63662e+127, -1.55772e+100,
-    -1.67813e+72,  -2.3382e+55,   -3.179e+30,    -1.441e+09,    -1.0647e+09,
-    -7.99361e+08,  -5.77375e+08,  -2.20984e+08,  -32757,        -13171,
-    -9970,         -3984,         -107,          -105,          -92,
-    -77,           -61,           -0.000208163,  -1.86685e-06,  -1.17296e-10,
-    -9.26358e-11,  -5.08004e-60,  -1.74753e-65,  -1.06561e-71,  -5.67879e-79,
-    -5.78459e-130, -2.90989e-171, -7.15489e-243, -3.76242e-252, -1.05639e-263,
-    -4.40497e-267, -2.19666e-273, -4.9998e-276,  -5.59821e-278, -2.03855e-282,
-    -5.99335e-283, -7.17554e-284, -3.11744e-309, -0.0,          0.0,
-    2.22507e-308,  1.30127e-270,  7.62898e-260,  4.00313e-249,  3.16829e-233,
-    1.85244e-228,  2.03544e-129,  1.35126e-110,  1.01182e-106,  5.26333e-94,
-    1.35292e-90,   2.85394e-83,   1.78323e-77,   5.4967e-57,    1.03207e-25,
-    4.57401e-25,   1.58738e-05,   2,             125,           2310,
-    9636,          14802,         17168,         28945,         29305,
-    4.81336e+07,   1.41207e+08,   4.65962e+08,   1.40499e+09,   2.12648e+09,
-    8.80006e+30,   1.4446e+45,    1.12164e+54,   2.48188e+89,   6.71121e+102,
-    3.074e+112,    4.9699e+152,   5.58383e+166,  4.30654e+172,  7.08824e+185,
-    9.6586e+214,   2.028e+223,    6.63277e+243,  1.56192e+261,  1.23202e+269,
-    5.72883e+289,  8.5798e+290,   1.40256e+294,  1.79769e+308,  V8_INFINITY};
-
-
-static const int32_t kInt32Values[] = {
-    -2147483647 - 1, -1914954528, -1698749618, -1578693386, -1577976073,
-    -1573998034,     -1529085059, -1499540537, -1299205097, -1090814845,
-    -938186388,      -806828902,  -750927650,  -520676892,  -513661538,
-    -453036354,      -433622833,  -282638793,  -28375,      -27788,
-    -22770,          -18806,      -14173,      -11956,      -11200,
-    -10212,          -8160,       -3751,       -2758,       -1522,
-    -121,            -120,        -118,        -117,        -106,
-    -84,             -80,         -74,         -59,         -52,
-    -48,             -39,         -35,         -17,         -11,
-    -10,             -9,          -7,          -5,          0,
-    9,               12,          17,          23,          29,
-    31,              33,          35,          40,          47,
-    55,              56,          62,          64,          67,
-    68,              69,          74,          79,          84,
-    89,              90,          97,          104,         118,
-    124,             126,         127,         7278,        17787,
-    24136,           24202,       25570,       26680,       30242,
-    32399,           420886487,   642166225,   821912648,   822577803,
-    851385718,       1212241078,  1411419304,  1589626102,  1596437184,
-    1876245816,      1954730266,  2008792749,  2045320228,  2147483647};
-
-
-static const int64_t kInt64Values[] = {
-    V8_INT64_C(-9223372036854775807) - 1, V8_INT64_C(-8974392461363618006),
-    V8_INT64_C(-8874367046689588135),     V8_INT64_C(-8269197512118230839),
-    V8_INT64_C(-8146091527100606733),     V8_INT64_C(-7550917981466150848),
-    V8_INT64_C(-7216590251577894337),     V8_INT64_C(-6464086891160048440),
-    V8_INT64_C(-6365616494908257190),     V8_INT64_C(-6305630541365849726),
-    V8_INT64_C(-5982222642272245453),     V8_INT64_C(-5510103099058504169),
-    V8_INT64_C(-5496838675802432701),     V8_INT64_C(-4047626578868642657),
-    V8_INT64_C(-4033755046900164544),     V8_INT64_C(-3554299241457877041),
-    V8_INT64_C(-2482258764588614470),     V8_INT64_C(-1688515425526875335),
-    V8_INT64_C(-924784137176548532),      V8_INT64_C(-725316567157391307),
-    V8_INT64_C(-439022654781092241),      V8_INT64_C(-105545757668917080),
-    V8_INT64_C(-2088319373),              V8_INT64_C(-2073699916),
-    V8_INT64_C(-1844949911),              V8_INT64_C(-1831090548),
-    V8_INT64_C(-1756711933),              V8_INT64_C(-1559409497),
-    V8_INT64_C(-1281179700),              V8_INT64_C(-1211513985),
-    V8_INT64_C(-1182371520),              V8_INT64_C(-785934753),
-    V8_INT64_C(-767480697),               V8_INT64_C(-705745662),
-    V8_INT64_C(-514362436),               V8_INT64_C(-459916580),
-    V8_INT64_C(-312328082),               V8_INT64_C(-302949707),
-    V8_INT64_C(-285499304),               V8_INT64_C(-125701262),
-    V8_INT64_C(-95139843),                V8_INT64_C(-32768),
-    V8_INT64_C(-27542),                   V8_INT64_C(-23600),
-    V8_INT64_C(-18582),                   V8_INT64_C(-17770),
-    V8_INT64_C(-9086),                    V8_INT64_C(-9010),
-    V8_INT64_C(-8244),                    V8_INT64_C(-2890),
-    V8_INT64_C(-103),                     V8_INT64_C(-34),
-    V8_INT64_C(-27),                      V8_INT64_C(-25),
-    V8_INT64_C(-9),                       V8_INT64_C(-7),
-    V8_INT64_C(0),                        V8_INT64_C(2),
-    V8_INT64_C(38),                       V8_INT64_C(58),
-    V8_INT64_C(65),                       V8_INT64_C(93),
-    V8_INT64_C(111),                      V8_INT64_C(1003),
-    V8_INT64_C(1267),                     V8_INT64_C(12797),
-    V8_INT64_C(23122),                    V8_INT64_C(28200),
-    V8_INT64_C(30888),                    V8_INT64_C(42648848),
-    V8_INT64_C(116836693),                V8_INT64_C(263003643),
-    V8_INT64_C(571039860),                V8_INT64_C(1079398689),
-    V8_INT64_C(1145196402),               V8_INT64_C(1184846321),
-    V8_INT64_C(1758281648),               V8_INT64_C(1859991374),
-    V8_INT64_C(1960251588),               V8_INT64_C(2042443199),
-    V8_INT64_C(296220586027987448),       V8_INT64_C(1015494173071134726),
-    V8_INT64_C(1151237951914455318),      V8_INT64_C(1331941174616854174),
-    V8_INT64_C(2022020418667972654),      V8_INT64_C(2450251424374977035),
-    V8_INT64_C(3668393562685561486),      V8_INT64_C(4858229301215502171),
-    V8_INT64_C(4919426235170669383),      V8_INT64_C(5034286595330341762),
-    V8_INT64_C(5055797915536941182),      V8_INT64_C(6072389716149252074),
-    V8_INT64_C(6185309910199801210),      V8_INT64_C(6297328311011094138),
-    V8_INT64_C(6932372858072165827),      V8_INT64_C(8483640924987737210),
-    V8_INT64_C(8663764179455849203),      V8_INT64_C(8877197042645298254),
-    V8_INT64_C(8901543506779157333),      V8_INT64_C(9223372036854775807)};
-
-
-static const uint32_t kUint32Values[] = {
-    0x00000000, 0x00000001, 0xffffffff, 0x1b09788b, 0x04c5fce8, 0xcc0de5bf,
-    0x273a798e, 0x187937a3, 0xece3af83, 0x5495a16b, 0x0b668ecc, 0x11223344,
-    0x0000009e, 0x00000043, 0x0000af73, 0x0000116b, 0x00658ecc, 0x002b3b4c,
-    0x88776655, 0x70000000, 0x07200000, 0x7fffffff, 0x56123761, 0x7fffff00,
-    0x761c4761, 0x80000000, 0x88888888, 0xa0000000, 0xdddddddd, 0xe0000000,
-    0xeeeeeeee, 0xfffffffd, 0xf0000000, 0x007fffff, 0x003fffff, 0x001fffff,
-    0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff, 0x0000ffff, 0x00007fff,
-    0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff};
-
-}  // namespace
-
-
-// -----------------------------------------------------------------------------
-// Unary operators
-
-
-namespace {
-
-struct UnaryOperator {
-  const Operator* (MachineOperatorBuilder::*constructor)();
-  const char* constructor_name;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const UnaryOperator& unop) {
-  return os << unop.constructor_name;
-}
-
-
-static const UnaryOperator kUnaryOperators[] = {
-    {&MachineOperatorBuilder::ChangeInt32ToFloat64, "ChangeInt32ToFloat64"},
-    {&MachineOperatorBuilder::ChangeUint32ToFloat64, "ChangeUint32ToFloat64"},
-    {&MachineOperatorBuilder::ChangeFloat64ToInt32, "ChangeFloat64ToInt32"},
-    {&MachineOperatorBuilder::ChangeFloat64ToUint32, "ChangeFloat64ToUint32"},
-    {&MachineOperatorBuilder::ChangeInt32ToInt64, "ChangeInt32ToInt64"},
-    {&MachineOperatorBuilder::ChangeUint32ToUint64, "ChangeUint32ToUint64"},
-    {&MachineOperatorBuilder::TruncateFloat64ToInt32, "TruncateFloat64ToInt32"},
-    {&MachineOperatorBuilder::TruncateInt64ToInt32, "TruncateInt64ToInt32"}};
-
-}  // namespace
-
-
-typedef MachineOperatorReducerTestWithParam<UnaryOperator>
-    MachineUnaryOperatorReducerTest;
-
-
-TEST_P(MachineUnaryOperatorReducerTest, Parameter) {
-  const UnaryOperator unop = GetParam();
-  Reduction reduction =
-      Reduce(graph()->NewNode((machine()->*unop.constructor)(), Parameter(0)));
-  EXPECT_FALSE(reduction.Changed());
-}
-
-
-INSTANTIATE_TEST_CASE_P(MachineOperatorReducerTest,
-                        MachineUnaryOperatorReducerTest,
-                        ::testing::ValuesIn(kUnaryOperators));
-
-
-// -----------------------------------------------------------------------------
-// ChangeFloat64ToFloat32
-
-
-TEST_F(MachineOperatorReducerTest, ChangeFloat64ToFloat32WithConstant) {
-  TRACED_FOREACH(float, x, kFloat32Values) {
-    Reduction reduction = Reduce(graph()->NewNode(
-        machine()->ChangeFloat32ToFloat64(), Float32Constant(x)));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(), IsFloat64Constant(x));
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// ChangeFloat64ToInt32
-
-
-TEST_F(MachineOperatorReducerTest,
-       ChangeFloat64ToInt32WithChangeInt32ToFloat64) {
-  Node* value = Parameter(0);
-  Reduction reduction = Reduce(graph()->NewNode(
-      machine()->ChangeFloat64ToInt32(),
-      graph()->NewNode(machine()->ChangeInt32ToFloat64(), value)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_EQ(value, reduction.replacement());
-}
-
-
-TEST_F(MachineOperatorReducerTest, ChangeFloat64ToInt32WithConstant) {
-  TRACED_FOREACH(int32_t, x, kInt32Values) {
-    Reduction reduction = Reduce(graph()->NewNode(
-        machine()->ChangeFloat64ToInt32(), Float64Constant(FastI2D(x))));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(), IsInt32Constant(x));
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// ChangeFloat64ToUint32
-
-
-TEST_F(MachineOperatorReducerTest,
-       ChangeFloat64ToUint32WithChangeUint32ToFloat64) {
-  Node* value = Parameter(0);
-  Reduction reduction = Reduce(graph()->NewNode(
-      machine()->ChangeFloat64ToUint32(),
-      graph()->NewNode(machine()->ChangeUint32ToFloat64(), value)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_EQ(value, reduction.replacement());
-}
-
-
-TEST_F(MachineOperatorReducerTest, ChangeFloat64ToUint32WithConstant) {
-  TRACED_FOREACH(uint32_t, x, kUint32Values) {
-    Reduction reduction = Reduce(graph()->NewNode(
-        machine()->ChangeFloat64ToUint32(), Float64Constant(FastUI2D(x))));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(), IsInt32Constant(bit_cast<int32_t>(x)));
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// ChangeInt32ToFloat64
-
-
-TEST_F(MachineOperatorReducerTest, ChangeInt32ToFloat64WithConstant) {
-  TRACED_FOREACH(int32_t, x, kInt32Values) {
-    Reduction reduction = Reduce(
-        graph()->NewNode(machine()->ChangeInt32ToFloat64(), Int32Constant(x)));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(), IsFloat64Constant(FastI2D(x)));
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// ChangeInt32ToInt64
-
-
-TEST_F(MachineOperatorReducerTest, ChangeInt32ToInt64WithConstant) {
-  TRACED_FOREACH(int32_t, x, kInt32Values) {
-    Reduction reduction = Reduce(
-        graph()->NewNode(machine()->ChangeInt32ToInt64(), Int32Constant(x)));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(), IsInt64Constant(x));
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// ChangeUint32ToFloat64
-
-
-TEST_F(MachineOperatorReducerTest, ChangeUint32ToFloat64WithConstant) {
-  TRACED_FOREACH(uint32_t, x, kUint32Values) {
-    Reduction reduction =
-        Reduce(graph()->NewNode(machine()->ChangeUint32ToFloat64(),
-                                Int32Constant(bit_cast<int32_t>(x))));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(), IsFloat64Constant(FastUI2D(x)));
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// ChangeUint32ToUint64
-
-
-TEST_F(MachineOperatorReducerTest, ChangeUint32ToUint64WithConstant) {
-  TRACED_FOREACH(uint32_t, x, kUint32Values) {
-    Reduction reduction =
-        Reduce(graph()->NewNode(machine()->ChangeUint32ToUint64(),
-                                Int32Constant(bit_cast<int32_t>(x))));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(),
-                IsInt64Constant(bit_cast<int64_t>(static_cast<uint64_t>(x))));
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// TruncateFloat64ToFloat32
-
-
-TEST_F(MachineOperatorReducerTest,
-       TruncateFloat64ToFloat32WithChangeFloat32ToFloat64) {
-  Node* value = Parameter(0);
-  Reduction reduction = Reduce(graph()->NewNode(
-      machine()->TruncateFloat64ToFloat32(),
-      graph()->NewNode(machine()->ChangeFloat32ToFloat64(), value)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_EQ(value, reduction.replacement());
-}
-
-
-TEST_F(MachineOperatorReducerTest, TruncateFloat64ToFloat32WithConstant) {
-  TRACED_FOREACH(double, x, kFloat64Values) {
-    Reduction reduction = Reduce(graph()->NewNode(
-        machine()->TruncateFloat64ToFloat32(), Float64Constant(x)));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(), IsFloat32Constant(DoubleToFloat32(x)));
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// TruncateFloat64ToInt32
-
-
-TEST_F(MachineOperatorReducerTest,
-       TruncateFloat64ToInt32WithChangeInt32ToFloat64) {
-  Node* value = Parameter(0);
-  Reduction reduction = Reduce(graph()->NewNode(
-      machine()->TruncateFloat64ToInt32(),
-      graph()->NewNode(machine()->ChangeInt32ToFloat64(), value)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_EQ(value, reduction.replacement());
-}
-
-
-TEST_F(MachineOperatorReducerTest, TruncateFloat64ToInt32WithConstant) {
-  TRACED_FOREACH(double, x, kFloat64Values) {
-    Reduction reduction = Reduce(graph()->NewNode(
-        machine()->TruncateFloat64ToInt32(), Float64Constant(x)));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(), IsInt32Constant(DoubleToInt32(x)));
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// TruncateInt64ToInt32
-
-
-TEST_F(MachineOperatorReducerTest, TruncateInt64ToInt32WithChangeInt32ToInt64) {
-  Node* value = Parameter(0);
-  Reduction reduction = Reduce(graph()->NewNode(
-      machine()->TruncateInt64ToInt32(),
-      graph()->NewNode(machine()->ChangeInt32ToInt64(), value)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_EQ(value, reduction.replacement());
-}
-
-
-TEST_F(MachineOperatorReducerTest, TruncateInt64ToInt32WithConstant) {
-  TRACED_FOREACH(int64_t, x, kInt64Values) {
-    Reduction reduction = Reduce(
-        graph()->NewNode(machine()->TruncateInt64ToInt32(), Int64Constant(x)));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(),
-                IsInt32Constant(bit_cast<int32_t>(
-                    static_cast<uint32_t>(bit_cast<uint64_t>(x)))));
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// Word32Ror
-
-
-TEST_F(MachineOperatorReducerTest, ReduceToWord32RorWithParameters) {
-  Node* value = Parameter(0);
-  Node* shift = Parameter(1);
-  Node* shl = graph()->NewNode(machine()->Word32Shl(), value, shift);
-  Node* shr = graph()->NewNode(
-      machine()->Word32Shr(), value,
-      graph()->NewNode(machine()->Int32Sub(), Int32Constant(32), shift));
-
-  // (x << y) | (x >> (32 - y)) => x ror y
-  Node* node1 = graph()->NewNode(machine()->Word32Or(), shl, shr);
-  Reduction reduction1 = Reduce(node1);
-  EXPECT_TRUE(reduction1.Changed());
-  EXPECT_EQ(reduction1.replacement(), node1);
-  EXPECT_THAT(reduction1.replacement(), IsWord32Ror(value, shift));
-
-  // (x >> (32 - y)) | (x << y) => x ror y
-  Node* node2 = graph()->NewNode(machine()->Word32Or(), shr, shl);
-  Reduction reduction2 = Reduce(node2);
-  EXPECT_TRUE(reduction2.Changed());
-  EXPECT_EQ(reduction2.replacement(), node2);
-  EXPECT_THAT(reduction2.replacement(), IsWord32Ror(value, shift));
-}
-
-
-TEST_F(MachineOperatorReducerTest, ReduceToWord32RorWithConstant) {
-  Node* value = Parameter(0);
-  TRACED_FORRANGE(int32_t, k, 0, 31) {
-    Node* shl =
-        graph()->NewNode(machine()->Word32Shl(), value, Int32Constant(k));
-    Node* shr =
-        graph()->NewNode(machine()->Word32Shr(), value, Int32Constant(32 - k));
-
-    // (x << K) | (x >> ((32 - K) - y)) => x ror K
-    Node* node1 = graph()->NewNode(machine()->Word32Or(), shl, shr);
-    Reduction reduction1 = Reduce(node1);
-    EXPECT_TRUE(reduction1.Changed());
-    EXPECT_EQ(reduction1.replacement(), node1);
-    EXPECT_THAT(reduction1.replacement(),
-                IsWord32Ror(value, IsInt32Constant(k)));
-
-    // (x >> (32 - K)) | (x << K) => x ror K
-    Node* node2 = graph()->NewNode(machine()->Word32Or(), shr, shl);
-    Reduction reduction2 = Reduce(node2);
-    EXPECT_TRUE(reduction2.Changed());
-    EXPECT_EQ(reduction2.replacement(), node2);
-    EXPECT_THAT(reduction2.replacement(),
-                IsWord32Ror(value, IsInt32Constant(k)));
-  }
-}
-
-
-TEST_F(MachineOperatorReducerTest, Word32RorWithZeroShift) {
-  Node* value = Parameter(0);
-  Node* node =
-      graph()->NewNode(machine()->Word32Ror(), value, Int32Constant(0));
-  Reduction reduction = Reduce(node);
-  EXPECT_TRUE(reduction.Changed());
-  EXPECT_EQ(reduction.replacement(), value);
-}
-
-
-TEST_F(MachineOperatorReducerTest, Word32RorWithConstants) {
-  TRACED_FOREACH(int32_t, x, kUint32Values) {
-    TRACED_FORRANGE(int32_t, y, 0, 31) {
-      Node* node = graph()->NewNode(machine()->Word32Ror(), Int32Constant(x),
-                                    Int32Constant(y));
-      Reduction reduction = Reduce(node);
-      EXPECT_TRUE(reduction.Changed());
-      EXPECT_THAT(reduction.replacement(),
-                  IsInt32Constant(base::bits::RotateRight32(x, y)));
-    }
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// Int32AddWithOverflow
-
-
-TEST_F(MachineOperatorReducerTest, Int32AddWithOverflowWithZero) {
-  Node* p0 = Parameter(0);
-  {
-    Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(),
-                                 Int32Constant(0), p0);
-
-    Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
-    ASSERT_TRUE(r.Changed());
-    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
-
-    r = Reduce(graph()->NewNode(common()->Projection(0), add));
-    ASSERT_TRUE(r.Changed());
-    EXPECT_EQ(p0, r.replacement());
-  }
-  {
-    Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), p0,
-                                 Int32Constant(0));
-
-    Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
-    ASSERT_TRUE(r.Changed());
-    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
-
-    r = Reduce(graph()->NewNode(common()->Projection(0), add));
-    ASSERT_TRUE(r.Changed());
-    EXPECT_EQ(p0, r.replacement());
-  }
-}
-
-
-TEST_F(MachineOperatorReducerTest, Int32AddWithOverflowWithConstant) {
-  TRACED_FOREACH(int32_t, x, kInt32Values) {
-    TRACED_FOREACH(int32_t, y, kInt32Values) {
-      int32_t z;
-      Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(),
-                                   Int32Constant(x), Int32Constant(y));
-
-      Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
-      ASSERT_TRUE(r.Changed());
-      EXPECT_THAT(r.replacement(),
-                  IsInt32Constant(base::bits::SignedAddOverflow32(x, y, &z)));
-
-      r = Reduce(graph()->NewNode(common()->Projection(0), add));
-      ASSERT_TRUE(r.Changed());
-      EXPECT_THAT(r.replacement(), IsInt32Constant(z));
-    }
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// Int32SubWithOverflow
-
-
-TEST_F(MachineOperatorReducerTest, Int32SubWithOverflowWithZero) {
-  Node* p0 = Parameter(0);
-  Node* add =
-      graph()->NewNode(machine()->Int32SubWithOverflow(), p0, Int32Constant(0));
-
-  Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
-  ASSERT_TRUE(r.Changed());
-  EXPECT_THAT(r.replacement(), IsInt32Constant(0));
-
-  r = Reduce(graph()->NewNode(common()->Projection(0), add));
-  ASSERT_TRUE(r.Changed());
-  EXPECT_EQ(p0, r.replacement());
-}
-
-
-TEST_F(MachineOperatorReducerTest, Int32SubWithOverflowWithConstant) {
-  TRACED_FOREACH(int32_t, x, kInt32Values) {
-    TRACED_FOREACH(int32_t, y, kInt32Values) {
-      int32_t z;
-      Node* add = graph()->NewNode(machine()->Int32SubWithOverflow(),
-                                   Int32Constant(x), Int32Constant(y));
-
-      Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
-      ASSERT_TRUE(r.Changed());
-      EXPECT_THAT(r.replacement(),
-                  IsInt32Constant(base::bits::SignedSubOverflow32(x, y, &z)));
-
-      r = Reduce(graph()->NewNode(common()->Projection(0), add));
-      ASSERT_TRUE(r.Changed());
-      EXPECT_THAT(r.replacement(), IsInt32Constant(z));
-    }
-  }
-}
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/machine-operator-reducer.cc b/src/compiler/machine-operator-reducer.cc
index 9328547..c3e45a1 100644
--- a/src/compiler/machine-operator-reducer.cc
+++ b/src/compiler/machine-operator-reducer.cc
@@ -5,7 +5,9 @@
 #include "src/compiler/machine-operator-reducer.h"
 
 #include "src/base/bits.h"
-#include "src/compiler/generic-node-inl.h"
+#include "src/base/division-by-constant.h"
+#include "src/codegen.h"
+#include "src/compiler/diamond.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/node-matchers.h"
@@ -41,81 +43,90 @@
 }
 
 
+Node* MachineOperatorReducer::Word32And(Node* lhs, Node* rhs) {
+  Node* const node = graph()->NewNode(machine()->Word32And(), lhs, rhs);
+  Reduction const reduction = ReduceWord32And(node);
+  return reduction.Changed() ? reduction.replacement() : node;
+}
+
+
+Node* MachineOperatorReducer::Word32Sar(Node* lhs, uint32_t rhs) {
+  if (rhs == 0) return lhs;
+  return graph()->NewNode(machine()->Word32Sar(), lhs, Uint32Constant(rhs));
+}
+
+
+Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) {
+  if (rhs == 0) return lhs;
+  return graph()->NewNode(machine()->Word32Shr(), lhs, Uint32Constant(rhs));
+}
+
+
+Node* MachineOperatorReducer::Word32Equal(Node* lhs, Node* rhs) {
+  return graph()->NewNode(machine()->Word32Equal(), lhs, rhs);
+}
+
+
+Node* MachineOperatorReducer::Int32Add(Node* lhs, Node* rhs) {
+  Node* const node = graph()->NewNode(machine()->Int32Add(), lhs, rhs);
+  Reduction const reduction = ReduceInt32Add(node);
+  return reduction.Changed() ? reduction.replacement() : node;
+}
+
+
+Node* MachineOperatorReducer::Int32Sub(Node* lhs, Node* rhs) {
+  return graph()->NewNode(machine()->Int32Sub(), lhs, rhs);
+}
+
+
+Node* MachineOperatorReducer::Int32Mul(Node* lhs, Node* rhs) {
+  return graph()->NewNode(machine()->Int32Mul(), lhs, rhs);
+}
+
+
+Node* MachineOperatorReducer::Int32Div(Node* dividend, int32_t divisor) {
+  DCHECK_NE(0, divisor);
+  DCHECK_NE(std::numeric_limits<int32_t>::min(), divisor);
+  base::MagicNumbersForDivision<uint32_t> const mag =
+      base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
+  Node* quotient = graph()->NewNode(machine()->Int32MulHigh(), dividend,
+                                    Uint32Constant(mag.multiplier));
+  if (divisor > 0 && bit_cast<int32_t>(mag.multiplier) < 0) {
+    quotient = Int32Add(quotient, dividend);
+  } else if (divisor < 0 && bit_cast<int32_t>(mag.multiplier) > 0) {
+    quotient = Int32Sub(quotient, dividend);
+  }
+  return Int32Add(Word32Sar(quotient, mag.shift), Word32Shr(dividend, 31));
+}
+
+
+Node* MachineOperatorReducer::Uint32Div(Node* dividend, uint32_t divisor) {
+  DCHECK_LT(0, divisor);
+  base::MagicNumbersForDivision<uint32_t> const mag =
+      base::UnsignedDivisionByConstant(bit_cast<uint32_t>(divisor));
+  Node* quotient = graph()->NewNode(machine()->Uint32MulHigh(), dividend,
+                                    Uint32Constant(mag.multiplier));
+  if (mag.add) {
+    DCHECK_LE(1, mag.shift);
+    quotient = Word32Shr(
+        Int32Add(Word32Shr(Int32Sub(dividend, quotient), 1), quotient),
+        mag.shift - 1);
+  } else {
+    quotient = Word32Shr(quotient, mag.shift);
+  }
+  return quotient;
+}
+
+
 // Perform constant folding and strength reduction on machine operators.
 Reduction MachineOperatorReducer::Reduce(Node* node) {
   switch (node->opcode()) {
     case IrOpcode::kProjection:
       return ReduceProjection(OpParameter<size_t>(node), node->InputAt(0));
-    case IrOpcode::kWord32And: {
-      Int32BinopMatcher m(node);
-      if (m.right().Is(0)) return Replace(m.right().node());  // x & 0  => 0
-      if (m.right().Is(-1)) return Replace(m.left().node());  // x & -1 => x
-      if (m.IsFoldable()) {                                   // K & K  => K
-        return ReplaceInt32(m.left().Value() & m.right().Value());
-      }
-      if (m.LeftEqualsRight()) return Replace(m.left().node());  // x & x => x
-      break;
-    }
-    case IrOpcode::kWord32Or: {
-      Int32BinopMatcher m(node);
-      if (m.right().Is(0)) return Replace(m.left().node());    // x | 0  => x
-      if (m.right().Is(-1)) return Replace(m.right().node());  // x | -1 => -1
-      if (m.IsFoldable()) {                                    // K | K  => K
-        return ReplaceInt32(m.left().Value() | m.right().Value());
-      }
-      if (m.LeftEqualsRight()) return Replace(m.left().node());  // x | x => x
-      if (m.left().IsWord32Shl() && m.right().IsWord32Shr()) {
-        Int32BinopMatcher mleft(m.left().node());
-        Int32BinopMatcher mright(m.right().node());
-        if (mleft.left().node() == mright.left().node()) {
-          // (x << y) | (x >> (32 - y)) => x ror y
-          if (mright.right().IsInt32Sub()) {
-            Int32BinopMatcher mrightright(mright.right().node());
-            if (mrightright.left().Is(32) &&
-                mrightright.right().node() == mleft.right().node()) {
-              node->set_op(machine()->Word32Ror());
-              node->ReplaceInput(0, mleft.left().node());
-              node->ReplaceInput(1, mleft.right().node());
-              return Changed(node);
-            }
-          }
-          // (x << K) | (x >> (32 - K)) => x ror K
-          if (mleft.right().IsInRange(0, 31) &&
-              mright.right().Is(32 - mleft.right().Value())) {
-            node->set_op(machine()->Word32Ror());
-            node->ReplaceInput(0, mleft.left().node());
-            node->ReplaceInput(1, mleft.right().node());
-            return Changed(node);
-          }
-        }
-      }
-      if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) {
-        // (x >> (32 - y)) | (x << y)  => x ror y
-        Int32BinopMatcher mleft(m.left().node());
-        Int32BinopMatcher mright(m.right().node());
-        if (mleft.left().node() == mright.left().node()) {
-          if (mleft.right().IsInt32Sub()) {
-            Int32BinopMatcher mleftright(mleft.right().node());
-            if (mleftright.left().Is(32) &&
-                mleftright.right().node() == mright.right().node()) {
-              node->set_op(machine()->Word32Ror());
-              node->ReplaceInput(0, mright.left().node());
-              node->ReplaceInput(1, mright.right().node());
-              return Changed(node);
-            }
-          }
-          // (x >> (32 - K)) | (x << K) => x ror K
-          if (mright.right().IsInRange(0, 31) &&
-              mleft.right().Is(32 - mright.right().Value())) {
-            node->set_op(machine()->Word32Ror());
-            node->ReplaceInput(0, mright.left().node());
-            node->ReplaceInput(1, mright.right().node());
-            return Changed(node);
-          }
-        }
-      }
-      break;
-    }
+    case IrOpcode::kWord32And:
+      return ReduceWord32And(node);
+    case IrOpcode::kWord32Or:
+      return ReduceWord32Or(node);
     case IrOpcode::kWord32Xor: {
       Int32BinopMatcher m(node);
       if (m.right().Is(0)) return Replace(m.left().node());  // x ^ 0 => x
@@ -123,23 +134,23 @@
         return ReplaceInt32(m.left().Value() ^ m.right().Value());
       }
       if (m.LeftEqualsRight()) return ReplaceInt32(0);  // x ^ x => 0
-      break;
-    }
-    case IrOpcode::kWord32Shl: {
-      Int32BinopMatcher m(node);
-      if (m.right().Is(0)) return Replace(m.left().node());  // x << 0 => x
-      if (m.IsFoldable()) {                                  // K << K => K
-        return ReplaceInt32(m.left().Value() << m.right().Value());
+      if (m.left().IsWord32Xor() && m.right().Is(-1)) {
+        Int32BinopMatcher mleft(m.left().node());
+        if (mleft.right().Is(-1)) {  // (x ^ -1) ^ -1 => x
+          return Replace(mleft.left().node());
+        }
       }
       break;
     }
+    case IrOpcode::kWord32Shl:
+      return ReduceWord32Shl(node);
     case IrOpcode::kWord32Shr: {
       Uint32BinopMatcher m(node);
       if (m.right().Is(0)) return Replace(m.left().node());  // x >>> 0 => x
       if (m.IsFoldable()) {                                  // K >>> K => K
         return ReplaceInt32(m.left().Value() >> m.right().Value());
       }
-      break;
+      return ReduceWord32Shifts(node);
     }
     case IrOpcode::kWord32Sar: {
       Int32BinopMatcher m(node);
@@ -147,7 +158,22 @@
       if (m.IsFoldable()) {                                  // K >> K => K
         return ReplaceInt32(m.left().Value() >> m.right().Value());
       }
-      break;
+      if (m.left().IsWord32Shl()) {
+        Int32BinopMatcher mleft(m.left().node());
+        if (mleft.left().IsLoad()) {
+          LoadRepresentation const rep =
+              OpParameter<LoadRepresentation>(mleft.left().node());
+          if (m.right().Is(24) && mleft.right().Is(24) && rep == kMachInt8) {
+            // Load[kMachInt8] << 24 >> 24 => Load[kMachInt8]
+            return Replace(mleft.left().node());
+          }
+          if (m.right().Is(16) && mleft.right().Is(16) && rep == kMachInt16) {
+            // Load[kMachInt16] << 16 >> 16 => Load[kMachInt8]
+            return Replace(mleft.left().node());
+          }
+        }
+      }
+      return ReduceWord32Shifts(node);
     }
     case IrOpcode::kWord32Ror: {
       Int32BinopMatcher m(node);
@@ -173,15 +199,23 @@
       if (m.LeftEqualsRight()) return ReplaceBool(true);  // x == x => true
       break;
     }
-    case IrOpcode::kInt32Add: {
-      Int32BinopMatcher m(node);
-      if (m.right().Is(0)) return Replace(m.left().node());  // x + 0 => x
-      if (m.IsFoldable()) {                                  // K + K => K
-        return ReplaceInt32(static_cast<uint32_t>(m.left().Value()) +
-                            static_cast<uint32_t>(m.right().Value()));
+    case IrOpcode::kWord64Equal: {
+      Int64BinopMatcher m(node);
+      if (m.IsFoldable()) {  // K == K => K
+        return ReplaceBool(m.left().Value() == m.right().Value());
       }
+      if (m.left().IsInt64Sub() && m.right().Is(0)) {  // x - y == 0 => x == y
+        Int64BinopMatcher msub(m.left().node());
+        node->ReplaceInput(0, msub.left().node());
+        node->ReplaceInput(1, msub.right().node());
+        return Changed(node);
+      }
+      // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares
+      if (m.LeftEqualsRight()) return ReplaceBool(true);  // x == x => true
       break;
     }
+    case IrOpcode::kInt32Add:
+      return ReduceInt32Add(node);
     case IrOpcode::kInt32Sub: {
       Int32BinopMatcher m(node);
       if (m.right().Is(0)) return Replace(m.left().node());  // x - 0 => x
@@ -208,74 +242,19 @@
       if (m.right().IsPowerOf2()) {  // x * 2^n => x << n
         node->set_op(machine()->Word32Shl());
         node->ReplaceInput(1, Int32Constant(WhichPowerOf2(m.right().Value())));
-        return Changed(node);
+        Reduction reduction = ReduceWord32Shl(node);
+        return reduction.Changed() ? reduction : Changed(node);
       }
       break;
     }
-    case IrOpcode::kInt32Div: {
-      Int32BinopMatcher m(node);
-      if (m.right().Is(1)) return Replace(m.left().node());  // x / 1 => x
-      // TODO(turbofan): if (m.left().Is(0))
-      // TODO(turbofan): if (m.right().IsPowerOf2())
-      // TODO(turbofan): if (m.right().Is(0))
-      // TODO(turbofan): if (m.LeftEqualsRight())
-      if (m.IsFoldable() && !m.right().Is(0)) {  // K / K => K
-        if (m.right().Is(-1)) return ReplaceInt32(-m.left().Value());
-        return ReplaceInt32(m.left().Value() / m.right().Value());
-      }
-      if (m.right().Is(-1)) {  // x / -1 => 0 - x
-        node->set_op(machine()->Int32Sub());
-        node->ReplaceInput(0, Int32Constant(0));
-        node->ReplaceInput(1, m.left().node());
-        return Changed(node);
-      }
-      break;
-    }
-    case IrOpcode::kInt32UDiv: {
-      Uint32BinopMatcher m(node);
-      if (m.right().Is(1)) return Replace(m.left().node());  // x / 1 => x
-      // TODO(turbofan): if (m.left().Is(0))
-      // TODO(turbofan): if (m.right().Is(0))
-      // TODO(turbofan): if (m.LeftEqualsRight())
-      if (m.IsFoldable() && !m.right().Is(0)) {  // K / K => K
-        return ReplaceInt32(m.left().Value() / m.right().Value());
-      }
-      if (m.right().IsPowerOf2()) {  // x / 2^n => x >> n
-        node->set_op(machine()->Word32Shr());
-        node->ReplaceInput(1, Int32Constant(WhichPowerOf2(m.right().Value())));
-        return Changed(node);
-      }
-      break;
-    }
-    case IrOpcode::kInt32Mod: {
-      Int32BinopMatcher m(node);
-      if (m.right().Is(1)) return ReplaceInt32(0);   // x % 1  => 0
-      if (m.right().Is(-1)) return ReplaceInt32(0);  // x % -1 => 0
-      // TODO(turbofan): if (m.left().Is(0))
-      // TODO(turbofan): if (m.right().IsPowerOf2())
-      // TODO(turbofan): if (m.right().Is(0))
-      // TODO(turbofan): if (m.LeftEqualsRight())
-      if (m.IsFoldable() && !m.right().Is(0)) {  // K % K => K
-        return ReplaceInt32(m.left().Value() % m.right().Value());
-      }
-      break;
-    }
-    case IrOpcode::kInt32UMod: {
-      Uint32BinopMatcher m(node);
-      if (m.right().Is(1)) return ReplaceInt32(0);  // x % 1 => 0
-      // TODO(turbofan): if (m.left().Is(0))
-      // TODO(turbofan): if (m.right().Is(0))
-      // TODO(turbofan): if (m.LeftEqualsRight())
-      if (m.IsFoldable() && !m.right().Is(0)) {  // K % K => K
-        return ReplaceInt32(m.left().Value() % m.right().Value());
-      }
-      if (m.right().IsPowerOf2()) {  // x % 2^n => x & 2^n-1
-        node->set_op(machine()->Word32And());
-        node->ReplaceInput(1, Int32Constant(m.right().Value() - 1));
-        return Changed(node);
-      }
-      break;
-    }
+    case IrOpcode::kInt32Div:
+      return ReduceInt32Div(node);
+    case IrOpcode::kUint32Div:
+      return ReduceUint32Div(node);
+    case IrOpcode::kInt32Mod:
+      return ReduceInt32Mod(node);
+    case IrOpcode::kUint32Mod:
+      return ReduceUint32Mod(node);
     case IrOpcode::kInt32LessThan: {
       Int32BinopMatcher m(node);
       if (m.IsFoldable()) {  // K < K => K
@@ -324,6 +303,21 @@
         return ReplaceBool(m.left().Value() < m.right().Value());
       }
       if (m.LeftEqualsRight()) return ReplaceBool(false);  // x < x => false
+      if (m.left().IsWord32Sar() && m.right().HasValue()) {
+        Int32BinopMatcher mleft(m.left().node());
+        if (mleft.right().HasValue()) {
+          // (x >> K) < C => x < (C << K)
+          // when C < (M >> K)
+          const uint32_t c = m.right().Value();
+          const uint32_t k = mleft.right().Value() & 0x1f;
+          if (c < static_cast<uint32_t>(kMaxInt >> k)) {
+            node->ReplaceInput(0, mleft.left().node());
+            node->ReplaceInput(1, Uint32Constant(c << k));
+            return Changed(node);
+          }
+          // TODO(turbofan): else the comparison is always true.
+        }
+      }
       break;
     }
     case IrOpcode::kUint32LessThanOrEqual: {
@@ -338,6 +332,9 @@
     }
     case IrOpcode::kFloat64Add: {
       Float64BinopMatcher m(node);
+      if (m.right().IsNaN()) {  // x + NaN => NaN
+        return Replace(m.right().node());
+      }
       if (m.IsFoldable()) {  // K + K => K
         return ReplaceFloat64(m.left().Value() + m.right().Value());
       }
@@ -345,6 +342,15 @@
     }
     case IrOpcode::kFloat64Sub: {
       Float64BinopMatcher m(node);
+      if (m.right().Is(0) && (Double(m.right().Value()).Sign() > 0)) {
+        return Replace(m.left().node());  // x - 0 => x
+      }
+      if (m.right().IsNaN()) {  // x - NaN => NaN
+        return Replace(m.right().node());
+      }
+      if (m.left().IsNaN()) {  // NaN - x => NaN
+        return Replace(m.left().node());
+      }
       if (m.IsFoldable()) {  // K - K => K
         return ReplaceFloat64(m.left().Value() - m.right().Value());
       }
@@ -352,6 +358,12 @@
     }
     case IrOpcode::kFloat64Mul: {
       Float64BinopMatcher m(node);
+      if (m.right().Is(-1)) {  // x * -1.0 => -0.0 - x
+        node->set_op(machine()->Float64Sub());
+        node->ReplaceInput(0, Float64Constant(-0.0));
+        node->ReplaceInput(1, m.left().node());
+        return Changed(node);
+      }
       if (m.right().Is(1)) return Replace(m.left().node());  // x * 1.0 => x
       if (m.right().IsNaN()) {                               // x * NaN => NaN
         return Replace(m.right().node());
@@ -377,6 +389,9 @@
     }
     case IrOpcode::kFloat64Mod: {
       Float64BinopMatcher m(node);
+      if (m.right().Is(0)) {  // x % 0 => NaN
+        return ReplaceFloat64(base::OS::nan_value());
+      }
       if (m.right().IsNaN()) {  // x % NaN => NaN
         return Replace(m.right().node());
       }
@@ -425,12 +440,8 @@
       if (m.HasValue()) return ReplaceInt64(static_cast<uint64_t>(m.Value()));
       break;
     }
-    case IrOpcode::kTruncateFloat64ToInt32: {
-      Float64Matcher m(node->InputAt(0));
-      if (m.HasValue()) return ReplaceInt32(DoubleToInt32(m.Value()));
-      if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
-      break;
-    }
+    case IrOpcode::kTruncateFloat64ToInt32:
+      return ReduceTruncateFloat64ToInt32(node);
     case IrOpcode::kTruncateInt64ToInt32: {
       Int64Matcher m(node->InputAt(0));
       if (m.HasValue()) return ReplaceInt32(static_cast<int32_t>(m.Value()));
@@ -443,6 +454,227 @@
       if (m.IsChangeFloat32ToFloat64()) return Replace(m.node()->InputAt(0));
       break;
     }
+    case IrOpcode::kStore:
+      return ReduceStore(node);
+    default:
+      break;
+  }
+  return NoChange();
+}
+
+
+Reduction MachineOperatorReducer::ReduceInt32Add(Node* node) {
+  DCHECK_EQ(IrOpcode::kInt32Add, node->opcode());
+  Int32BinopMatcher m(node);
+  if (m.right().Is(0)) return Replace(m.left().node());  // x + 0 => x
+  if (m.IsFoldable()) {                                  // K + K => K
+    return ReplaceUint32(bit_cast<uint32_t>(m.left().Value()) +
+                         bit_cast<uint32_t>(m.right().Value()));
+  }
+  return NoChange();
+}
+
+
+Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
+  Int32BinopMatcher m(node);
+  if (m.left().Is(0)) return Replace(m.left().node());    // 0 / x => 0
+  if (m.right().Is(0)) return Replace(m.right().node());  // x / 0 => 0
+  if (m.right().Is(1)) return Replace(m.left().node());   // x / 1 => x
+  if (m.IsFoldable()) {                                   // K / K => K
+    return ReplaceInt32(
+        base::bits::SignedDiv32(m.left().Value(), m.right().Value()));
+  }
+  if (m.LeftEqualsRight()) {  // x / x => x != 0
+    Node* const zero = Int32Constant(0);
+    return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
+  }
+  if (m.right().Is(-1)) {  // x / -1 => 0 - x
+    node->set_op(machine()->Int32Sub());
+    node->ReplaceInput(0, Int32Constant(0));
+    node->ReplaceInput(1, m.left().node());
+    node->TrimInputCount(2);
+    return Changed(node);
+  }
+  if (m.right().HasValue()) {
+    int32_t const divisor = m.right().Value();
+    Node* const dividend = m.left().node();
+    Node* quotient = dividend;
+    if (base::bits::IsPowerOfTwo32(Abs(divisor))) {
+      uint32_t const shift = WhichPowerOf2Abs(divisor);
+      DCHECK_NE(0, shift);
+      if (shift > 1) {
+        quotient = Word32Sar(quotient, 31);
+      }
+      quotient = Int32Add(Word32Shr(quotient, 32u - shift), dividend);
+      quotient = Word32Sar(quotient, shift);
+    } else {
+      quotient = Int32Div(quotient, Abs(divisor));
+    }
+    if (divisor < 0) {
+      node->set_op(machine()->Int32Sub());
+      node->ReplaceInput(0, Int32Constant(0));
+      node->ReplaceInput(1, quotient);
+      node->TrimInputCount(2);
+      return Changed(node);
+    }
+    return Replace(quotient);
+  }
+  return NoChange();
+}
+
+
+Reduction MachineOperatorReducer::ReduceUint32Div(Node* node) {
+  Uint32BinopMatcher m(node);
+  if (m.left().Is(0)) return Replace(m.left().node());    // 0 / x => 0
+  if (m.right().Is(0)) return Replace(m.right().node());  // x / 0 => 0
+  if (m.right().Is(1)) return Replace(m.left().node());   // x / 1 => x
+  if (m.IsFoldable()) {                                   // K / K => K
+    return ReplaceUint32(
+        base::bits::UnsignedDiv32(m.left().Value(), m.right().Value()));
+  }
+  if (m.LeftEqualsRight()) {  // x / x => x != 0
+    Node* const zero = Int32Constant(0);
+    return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
+  }
+  if (m.right().HasValue()) {
+    Node* const dividend = m.left().node();
+    uint32_t const divisor = m.right().Value();
+    if (base::bits::IsPowerOfTwo32(divisor)) {  // x / 2^n => x >> n
+      node->set_op(machine()->Word32Shr());
+      node->ReplaceInput(1, Uint32Constant(WhichPowerOf2(m.right().Value())));
+      node->TrimInputCount(2);
+      return Changed(node);
+    } else {
+      return Replace(Uint32Div(dividend, divisor));
+    }
+  }
+  return NoChange();
+}
+
+
+Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
+  Int32BinopMatcher m(node);
+  if (m.left().Is(0)) return Replace(m.left().node());    // 0 % x  => 0
+  if (m.right().Is(0)) return Replace(m.right().node());  // x % 0  => 0
+  if (m.right().Is(1)) return ReplaceInt32(0);            // x % 1  => 0
+  if (m.right().Is(-1)) return ReplaceInt32(0);           // x % -1 => 0
+  if (m.LeftEqualsRight()) return ReplaceInt32(0);        // x % x  => 0
+  if (m.IsFoldable()) {                                   // K % K => K
+    return ReplaceInt32(
+        base::bits::SignedMod32(m.left().Value(), m.right().Value()));
+  }
+  if (m.right().HasValue()) {
+    Node* const dividend = m.left().node();
+    int32_t const divisor = Abs(m.right().Value());
+    if (base::bits::IsPowerOfTwo32(divisor)) {
+      uint32_t const mask = divisor - 1;
+      Node* const zero = Int32Constant(0);
+      node->set_op(common()->Select(kMachInt32, BranchHint::kFalse));
+      node->ReplaceInput(
+          0, graph()->NewNode(machine()->Int32LessThan(), dividend, zero));
+      node->ReplaceInput(
+          1, Int32Sub(zero, Word32And(Int32Sub(zero, dividend), mask)));
+      node->ReplaceInput(2, Word32And(dividend, mask));
+    } else {
+      Node* quotient = Int32Div(dividend, divisor);
+      node->set_op(machine()->Int32Sub());
+      DCHECK_EQ(dividend, node->InputAt(0));
+      node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor)));
+      node->TrimInputCount(2);
+    }
+    return Changed(node);
+  }
+  return NoChange();
+}
+
+
+Reduction MachineOperatorReducer::ReduceUint32Mod(Node* node) {
+  Uint32BinopMatcher m(node);
+  if (m.left().Is(0)) return Replace(m.left().node());    // 0 % x => 0
+  if (m.right().Is(0)) return Replace(m.right().node());  // x % 0 => 0
+  if (m.right().Is(1)) return ReplaceUint32(0);           // x % 1 => 0
+  if (m.LeftEqualsRight()) return ReplaceInt32(0);        // x % x  => 0
+  if (m.IsFoldable()) {                                   // K % K => K
+    return ReplaceUint32(
+        base::bits::UnsignedMod32(m.left().Value(), m.right().Value()));
+  }
+  if (m.right().HasValue()) {
+    Node* const dividend = m.left().node();
+    uint32_t const divisor = m.right().Value();
+    if (base::bits::IsPowerOfTwo32(divisor)) {  // x % 2^n => x & 2^n-1
+      node->set_op(machine()->Word32And());
+      node->ReplaceInput(1, Uint32Constant(m.right().Value() - 1));
+    } else {
+      Node* quotient = Uint32Div(dividend, divisor);
+      node->set_op(machine()->Int32Sub());
+      DCHECK_EQ(dividend, node->InputAt(0));
+      node->ReplaceInput(1, Int32Mul(quotient, Uint32Constant(divisor)));
+    }
+    node->TrimInputCount(2);
+    return Changed(node);
+  }
+  return NoChange();
+}
+
+
+Reduction MachineOperatorReducer::ReduceTruncateFloat64ToInt32(Node* node) {
+  Float64Matcher m(node->InputAt(0));
+  if (m.HasValue()) return ReplaceInt32(DoubleToInt32(m.Value()));
+  if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
+  if (m.IsPhi()) {
+    Node* const phi = m.node();
+    DCHECK_EQ(kRepFloat64, RepresentationOf(OpParameter<MachineType>(phi)));
+    if (phi->OwnedBy(node)) {
+      // TruncateFloat64ToInt32(Phi[Float64](x1,...,xn))
+      //   => Phi[Int32](TruncateFloat64ToInt32(x1),
+      //                 ...,
+      //                 TruncateFloat64ToInt32(xn))
+      const int value_input_count = phi->InputCount() - 1;
+      for (int i = 0; i < value_input_count; ++i) {
+        Node* input = graph()->NewNode(machine()->TruncateFloat64ToInt32(),
+                                       phi->InputAt(i));
+        // TODO(bmeurer): Reschedule input for reduction once we have Revisit()
+        // instead of recursing into ReduceTruncateFloat64ToInt32() here.
+        Reduction reduction = ReduceTruncateFloat64ToInt32(input);
+        if (reduction.Changed()) input = reduction.replacement();
+        phi->ReplaceInput(i, input);
+      }
+      phi->set_op(common()->Phi(kMachInt32, value_input_count));
+      return Replace(phi);
+    }
+  }
+  return NoChange();
+}
+
+
+Reduction MachineOperatorReducer::ReduceStore(Node* node) {
+  MachineType const rep =
+      RepresentationOf(StoreRepresentationOf(node->op()).machine_type());
+  Node* const value = node->InputAt(2);
+  switch (value->opcode()) {
+    case IrOpcode::kWord32And: {
+      Uint32BinopMatcher m(value);
+      if (m.right().HasValue() &&
+          ((rep == kRepWord8 && (m.right().Value() & 0xff) == 0xff) ||
+           (rep == kRepWord16 && (m.right().Value() & 0xffff) == 0xffff))) {
+        node->ReplaceInput(2, m.left().node());
+        return Changed(node);
+      }
+      break;
+    }
+    case IrOpcode::kWord32Sar: {
+      Int32BinopMatcher m(value);
+      if (m.left().IsWord32Shl() &&
+          ((rep == kRepWord8 && m.right().IsInRange(1, 24)) ||
+           (rep == kRepWord16 && m.right().IsInRange(1, 16)))) {
+        Int32BinopMatcher mleft(m.left().node());
+        if (mleft.right().Is(m.right().Value())) {
+          node->ReplaceInput(2, mleft.left().node());
+          return Changed(node);
+        }
+      }
+      break;
+    }
     default:
       break;
   }
@@ -487,6 +719,192 @@
 }
 
 
+Reduction MachineOperatorReducer::ReduceWord32Shifts(Node* node) {
+  DCHECK((node->opcode() == IrOpcode::kWord32Shl) ||
+         (node->opcode() == IrOpcode::kWord32Shr) ||
+         (node->opcode() == IrOpcode::kWord32Sar));
+  if (machine()->Word32ShiftIsSafe()) {
+    // Remove the explicit 'and' with 0x1f if the shift provided by the machine
+    // instruction matches that required by JavaScript.
+    Int32BinopMatcher m(node);
+    if (m.right().IsWord32And()) {
+      Int32BinopMatcher mright(m.right().node());
+      if (mright.right().Is(0x1f)) {
+        node->ReplaceInput(1, mright.left().node());
+        return Changed(node);
+      }
+    }
+  }
+  return NoChange();
+}
+
+
+Reduction MachineOperatorReducer::ReduceWord32Shl(Node* node) {
+  DCHECK_EQ(IrOpcode::kWord32Shl, node->opcode());
+  Int32BinopMatcher m(node);
+  if (m.right().Is(0)) return Replace(m.left().node());  // x << 0 => x
+  if (m.IsFoldable()) {                                  // K << K => K
+    return ReplaceInt32(m.left().Value() << m.right().Value());
+  }
+  if (m.right().IsInRange(1, 31)) {
+    // (x >>> K) << K => x & ~(2^K - 1)
+    // (x >> K) << K => x & ~(2^K - 1)
+    if (m.left().IsWord32Sar() || m.left().IsWord32Shr()) {
+      Int32BinopMatcher mleft(m.left().node());
+      if (mleft.right().Is(m.right().Value())) {
+        node->set_op(machine()->Word32And());
+        node->ReplaceInput(0, mleft.left().node());
+        node->ReplaceInput(1,
+                           Uint32Constant(~((1U << m.right().Value()) - 1U)));
+        Reduction reduction = ReduceWord32And(node);
+        return reduction.Changed() ? reduction : Changed(node);
+      }
+    }
+  }
+  return ReduceWord32Shifts(node);
+}
+
+
+Reduction MachineOperatorReducer::ReduceWord32And(Node* node) {
+  DCHECK_EQ(IrOpcode::kWord32And, node->opcode());
+  Int32BinopMatcher m(node);
+  if (m.right().Is(0)) return Replace(m.right().node());  // x & 0  => 0
+  if (m.right().Is(-1)) return Replace(m.left().node());  // x & -1 => x
+  if (m.IsFoldable()) {                                   // K & K  => K
+    return ReplaceInt32(m.left().Value() & m.right().Value());
+  }
+  if (m.LeftEqualsRight()) return Replace(m.left().node());  // x & x => x
+  if (m.left().IsWord32And() && m.right().HasValue()) {
+    Int32BinopMatcher mleft(m.left().node());
+    if (mleft.right().HasValue()) {  // (x & K) & K => x & K
+      node->ReplaceInput(0, mleft.left().node());
+      node->ReplaceInput(
+          1, Int32Constant(m.right().Value() & mleft.right().Value()));
+      Reduction const reduction = ReduceWord32And(node);
+      return reduction.Changed() ? reduction : Changed(node);
+    }
+  }
+  if (m.left().IsInt32Add() && m.right().IsNegativePowerOf2()) {
+    Int32BinopMatcher mleft(m.left().node());
+    if (mleft.right().HasValue() &&
+        (mleft.right().Value() & m.right().Value()) == mleft.right().Value()) {
+      // (x + (K << L)) & (-1 << L) => (x & (-1 << L)) + (K << L)
+      node->set_op(machine()->Int32Add());
+      node->ReplaceInput(0, Word32And(mleft.left().node(), m.right().node()));
+      node->ReplaceInput(1, mleft.right().node());
+      Reduction const reduction = ReduceInt32Add(node);
+      return reduction.Changed() ? reduction : Changed(node);
+    }
+    if (mleft.left().IsInt32Mul()) {
+      Int32BinopMatcher mleftleft(mleft.left().node());
+      if (mleftleft.right().IsMultipleOf(-m.right().Value())) {
+        // (y * (K << L) + x) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
+        node->set_op(machine()->Int32Add());
+        node->ReplaceInput(0,
+                           Word32And(mleft.right().node(), m.right().node()));
+        node->ReplaceInput(1, mleftleft.node());
+        Reduction const reduction = ReduceInt32Add(node);
+        return reduction.Changed() ? reduction : Changed(node);
+      }
+    }
+    if (mleft.right().IsInt32Mul()) {
+      Int32BinopMatcher mleftright(mleft.right().node());
+      if (mleftright.right().IsMultipleOf(-m.right().Value())) {
+        // (x + y * (K << L)) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
+        node->set_op(machine()->Int32Add());
+        node->ReplaceInput(0, Word32And(mleft.left().node(), m.right().node()));
+        node->ReplaceInput(1, mleftright.node());
+        Reduction const reduction = ReduceInt32Add(node);
+        return reduction.Changed() ? reduction : Changed(node);
+      }
+    }
+    if (mleft.left().IsWord32Shl()) {
+      Int32BinopMatcher mleftleft(mleft.left().node());
+      if (mleftleft.right().Is(
+              base::bits::CountTrailingZeros32(m.right().Value()))) {
+        // (y << L + x) & (-1 << L) => (x & (-1 << L)) + y << L
+        node->set_op(machine()->Int32Add());
+        node->ReplaceInput(0,
+                           Word32And(mleft.right().node(), m.right().node()));
+        node->ReplaceInput(1, mleftleft.node());
+        Reduction const reduction = ReduceInt32Add(node);
+        return reduction.Changed() ? reduction : Changed(node);
+      }
+    }
+    if (mleft.right().IsWord32Shl()) {
+      Int32BinopMatcher mleftright(mleft.right().node());
+      if (mleftright.right().Is(
+              base::bits::CountTrailingZeros32(m.right().Value()))) {
+        // (x + y << L) & (-1 << L) => (x & (-1 << L)) + y << L
+        node->set_op(machine()->Int32Add());
+        node->ReplaceInput(0, Word32And(mleft.left().node(), m.right().node()));
+        node->ReplaceInput(1, mleftright.node());
+        Reduction const reduction = ReduceInt32Add(node);
+        return reduction.Changed() ? reduction : Changed(node);
+      }
+    }
+  }
+  return NoChange();
+}
+
+
+Reduction MachineOperatorReducer::ReduceWord32Or(Node* node) {
+  DCHECK_EQ(IrOpcode::kWord32Or, node->opcode());
+  Int32BinopMatcher m(node);
+  if (m.right().Is(0)) return Replace(m.left().node());    // x | 0  => x
+  if (m.right().Is(-1)) return Replace(m.right().node());  // x | -1 => -1
+  if (m.IsFoldable()) {                                    // K | K  => K
+    return ReplaceInt32(m.left().Value() | m.right().Value());
+  }
+  if (m.LeftEqualsRight()) return Replace(m.left().node());  // x | x => x
+
+  Node* shl = NULL;
+  Node* shr = NULL;
+  // Recognize rotation, we are matching either:
+  //  * x << y | x >>> (32 - y) => x ror (32 - y), i.e  x rol y
+  //  * x << (32 - y) | x >>> y => x ror y
+  // as well as their commuted form.
+  if (m.left().IsWord32Shl() && m.right().IsWord32Shr()) {
+    shl = m.left().node();
+    shr = m.right().node();
+  } else if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) {
+    shl = m.right().node();
+    shr = m.left().node();
+  } else {
+    return NoChange();
+  }
+
+  Int32BinopMatcher mshl(shl);
+  Int32BinopMatcher mshr(shr);
+  if (mshl.left().node() != mshr.left().node()) return NoChange();
+
+  if (mshl.right().HasValue() && mshr.right().HasValue()) {
+    // Case where y is a constant.
+    if (mshl.right().Value() + mshr.right().Value() != 32) return NoChange();
+  } else {
+    Node* sub = NULL;
+    Node* y = NULL;
+    if (mshl.right().IsInt32Sub()) {
+      sub = mshl.right().node();
+      y = mshr.right().node();
+    } else if (mshr.right().IsInt32Sub()) {
+      sub = mshr.right().node();
+      y = mshl.right().node();
+    } else {
+      return NoChange();
+    }
+
+    Int32BinopMatcher msub(sub);
+    if (!msub.left().Is(32) || msub.right().node() != y) return NoChange();
+  }
+
+  node->set_op(machine()->Word32Ror());
+  node->ReplaceInput(0, mshl.left().node());
+  node->ReplaceInput(1, mshr.right().node());
+  return Changed(node);
+}
+
+
 CommonOperatorBuilder* MachineOperatorReducer::common() const {
   return jsgraph()->common();
 }
diff --git a/src/compiler/machine-operator-reducer.h b/src/compiler/machine-operator-reducer.h
index c79ceae..8200abb 100644
--- a/src/compiler/machine-operator-reducer.h
+++ b/src/compiler/machine-operator-reducer.h
@@ -24,13 +24,28 @@
   explicit MachineOperatorReducer(JSGraph* jsgraph);
   ~MachineOperatorReducer();
 
-  virtual Reduction Reduce(Node* node) OVERRIDE;
+  Reduction Reduce(Node* node) OVERRIDE;
 
  private:
   Node* Float32Constant(volatile float value);
   Node* Float64Constant(volatile double value);
   Node* Int32Constant(int32_t value);
   Node* Int64Constant(int64_t value);
+  Node* Uint32Constant(uint32_t value) {
+    return Int32Constant(bit_cast<uint32_t>(value));
+  }
+  Node* Word32And(Node* lhs, Node* rhs);
+  Node* Word32And(Node* lhs, uint32_t rhs) {
+    return Word32And(lhs, Uint32Constant(rhs));
+  }
+  Node* Word32Sar(Node* lhs, uint32_t rhs);
+  Node* Word32Shr(Node* lhs, uint32_t rhs);
+  Node* Word32Equal(Node* lhs, Node* rhs);
+  Node* Int32Add(Node* lhs, Node* rhs);
+  Node* Int32Sub(Node* lhs, Node* rhs);
+  Node* Int32Mul(Node* lhs, Node* rhs);
+  Node* Int32Div(Node* dividend, int32_t divisor);
+  Node* Uint32Div(Node* dividend, uint32_t divisor);
 
   Reduction ReplaceBool(bool value) { return ReplaceInt32(value ? 1 : 0); }
   Reduction ReplaceFloat32(volatile float value) {
@@ -42,11 +57,25 @@
   Reduction ReplaceInt32(int32_t value) {
     return Replace(Int32Constant(value));
   }
+  Reduction ReplaceUint32(uint32_t value) {
+    return Replace(Uint32Constant(value));
+  }
   Reduction ReplaceInt64(int64_t value) {
     return Replace(Int64Constant(value));
   }
 
+  Reduction ReduceInt32Add(Node* node);
+  Reduction ReduceInt32Div(Node* node);
+  Reduction ReduceUint32Div(Node* node);
+  Reduction ReduceInt32Mod(Node* node);
+  Reduction ReduceUint32Mod(Node* node);
+  Reduction ReduceTruncateFloat64ToInt32(Node* node);
+  Reduction ReduceStore(Node* node);
   Reduction ReduceProjection(size_t index, Node* node);
+  Reduction ReduceWord32Shifts(Node* node);
+  Reduction ReduceWord32Shl(Node* node);
+  Reduction ReduceWord32And(Node* node);
+  Reduction ReduceWord32Or(Node* node);
 
   Graph* graph() const;
   JSGraph* jsgraph() const { return jsgraph_; }
diff --git a/src/compiler/machine-operator-unittest.cc b/src/compiler/machine-operator-unittest.cc
deleted file mode 100644
index cb93ce7..0000000
--- a/src/compiler/machine-operator-unittest.cc
+++ /dev/null
@@ -1,325 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/machine-operator.h"
-#include "src/compiler/operator-properties-inl.h"
-#include "testing/gtest-support.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-#if GTEST_HAS_COMBINE
-
-// TODO(bmeurer): Find a new home for these.
-inline std::ostream& operator<<(std::ostream& os, const MachineType& type) {
-  OStringStream ost;
-  ost << type;
-  return os << ost.c_str();
-}
-inline std::ostream& operator<<(std::ostream& os,
-                         const WriteBarrierKind& write_barrier_kind) {
-  OStringStream ost;
-  ost << write_barrier_kind;
-  return os << ost.c_str();
-}
-
-
-template <typename T>
-class MachineOperatorTestWithParam
-    : public ::testing::TestWithParam< ::testing::tuple<MachineType, T> > {
- protected:
-  MachineType type() const { return ::testing::get<0>(B::GetParam()); }
-  const T& GetParam() const { return ::testing::get<1>(B::GetParam()); }
-
- private:
-  typedef ::testing::TestWithParam< ::testing::tuple<MachineType, T> > B;
-};
-
-
-namespace {
-
-const MachineType kMachineReps[] = {kRepWord32, kRepWord64};
-
-
-const MachineType kMachineTypes[] = {
-    kMachFloat32, kMachFloat64,   kMachInt8,   kMachUint8,  kMachInt16,
-    kMachUint16,  kMachInt32,     kMachUint32, kMachInt64,  kMachUint64,
-    kMachPtr,     kMachAnyTagged, kRepBit,     kRepWord8,   kRepWord16,
-    kRepWord32,   kRepWord64,     kRepFloat32, kRepFloat64, kRepTagged};
-
-}  // namespace
-
-
-// -----------------------------------------------------------------------------
-// Load operator.
-
-
-typedef MachineOperatorTestWithParam<LoadRepresentation>
-    MachineLoadOperatorTest;
-
-
-TEST_P(MachineLoadOperatorTest, InstancesAreGloballyShared) {
-  MachineOperatorBuilder machine1(type());
-  MachineOperatorBuilder machine2(type());
-  EXPECT_EQ(machine1.Load(GetParam()), machine2.Load(GetParam()));
-}
-
-
-TEST_P(MachineLoadOperatorTest, NumberOfInputsAndOutputs) {
-  MachineOperatorBuilder machine(type());
-  const Operator* op = machine.Load(GetParam());
-
-  EXPECT_EQ(2, OperatorProperties::GetValueInputCount(op));
-  EXPECT_EQ(1, OperatorProperties::GetEffectInputCount(op));
-  EXPECT_EQ(0, OperatorProperties::GetControlInputCount(op));
-  EXPECT_EQ(3, OperatorProperties::GetTotalInputCount(op));
-
-  EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
-  EXPECT_EQ(1, OperatorProperties::GetEffectOutputCount(op));
-  EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
-}
-
-
-TEST_P(MachineLoadOperatorTest, OpcodeIsCorrect) {
-  MachineOperatorBuilder machine(type());
-  EXPECT_EQ(IrOpcode::kLoad, machine.Load(GetParam())->opcode());
-}
-
-
-TEST_P(MachineLoadOperatorTest, ParameterIsCorrect) {
-  MachineOperatorBuilder machine(type());
-  EXPECT_EQ(GetParam(),
-            OpParameter<LoadRepresentation>(machine.Load(GetParam())));
-}
-
-
-INSTANTIATE_TEST_CASE_P(MachineOperatorTest, MachineLoadOperatorTest,
-                        ::testing::Combine(::testing::ValuesIn(kMachineReps),
-                                           ::testing::ValuesIn(kMachineTypes)));
-
-
-// -----------------------------------------------------------------------------
-// Store operator.
-
-
-class MachineStoreOperatorTest
-    : public MachineOperatorTestWithParam<
-          ::testing::tuple<MachineType, WriteBarrierKind> > {
- protected:
-  StoreRepresentation GetParam() const {
-    return StoreRepresentation(
-        ::testing::get<0>(MachineOperatorTestWithParam<
-            ::testing::tuple<MachineType, WriteBarrierKind> >::GetParam()),
-        ::testing::get<1>(MachineOperatorTestWithParam<
-            ::testing::tuple<MachineType, WriteBarrierKind> >::GetParam()));
-  }
-};
-
-
-TEST_P(MachineStoreOperatorTest, InstancesAreGloballyShared) {
-  MachineOperatorBuilder machine1(type());
-  MachineOperatorBuilder machine2(type());
-  EXPECT_EQ(machine1.Store(GetParam()), machine2.Store(GetParam()));
-}
-
-
-TEST_P(MachineStoreOperatorTest, NumberOfInputsAndOutputs) {
-  MachineOperatorBuilder machine(type());
-  const Operator* op = machine.Store(GetParam());
-
-  EXPECT_EQ(3, OperatorProperties::GetValueInputCount(op));
-  EXPECT_EQ(1, OperatorProperties::GetEffectInputCount(op));
-  EXPECT_EQ(1, OperatorProperties::GetControlInputCount(op));
-  EXPECT_EQ(5, OperatorProperties::GetTotalInputCount(op));
-
-  EXPECT_EQ(0, OperatorProperties::GetValueOutputCount(op));
-  EXPECT_EQ(1, OperatorProperties::GetEffectOutputCount(op));
-  EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
-}
-
-
-TEST_P(MachineStoreOperatorTest, OpcodeIsCorrect) {
-  MachineOperatorBuilder machine(type());
-  EXPECT_EQ(IrOpcode::kStore, machine.Store(GetParam())->opcode());
-}
-
-
-TEST_P(MachineStoreOperatorTest, ParameterIsCorrect) {
-  MachineOperatorBuilder machine(type());
-  EXPECT_EQ(GetParam(),
-            OpParameter<StoreRepresentation>(machine.Store(GetParam())));
-}
-
-
-INSTANTIATE_TEST_CASE_P(
-    MachineOperatorTest, MachineStoreOperatorTest,
-    ::testing::Combine(
-        ::testing::ValuesIn(kMachineReps),
-        ::testing::Combine(::testing::ValuesIn(kMachineTypes),
-                           ::testing::Values(kNoWriteBarrier,
-                                             kFullWriteBarrier))));
-
-
-// -----------------------------------------------------------------------------
-// Pure operators.
-
-
-namespace {
-
-struct PureOperator {
-  const Operator* (MachineOperatorBuilder::*constructor)();
-  IrOpcode::Value opcode;
-  int value_input_count;
-  int value_output_count;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const PureOperator& pop) {
-  return os << IrOpcode::Mnemonic(pop.opcode);
-}
-
-
-const PureOperator kPureOperators[] = {
-#define PURE(Name, input_count, output_count)                      \
-  {                                                                \
-    &MachineOperatorBuilder::Name, IrOpcode::k##Name, input_count, \
-        output_count                                               \
-  }
-    PURE(Word32And, 2, 1),                PURE(Word32Or, 2, 1),
-    PURE(Word32Xor, 2, 1),                PURE(Word32Shl, 2, 1),
-    PURE(Word32Shr, 2, 1),                PURE(Word32Sar, 2, 1),
-    PURE(Word32Ror, 2, 1),                PURE(Word32Equal, 2, 1),
-    PURE(Word64And, 2, 1),                PURE(Word64Or, 2, 1),
-    PURE(Word64Xor, 2, 1),                PURE(Word64Shl, 2, 1),
-    PURE(Word64Shr, 2, 1),                PURE(Word64Sar, 2, 1),
-    PURE(Word64Ror, 2, 1),                PURE(Word64Equal, 2, 1),
-    PURE(Int32Add, 2, 1),                 PURE(Int32AddWithOverflow, 2, 2),
-    PURE(Int32Sub, 2, 1),                 PURE(Int32SubWithOverflow, 2, 2),
-    PURE(Int32Mul, 2, 1),                 PURE(Int32Div, 2, 1),
-    PURE(Int32UDiv, 2, 1),                PURE(Int32Mod, 2, 1),
-    PURE(Int32UMod, 2, 1),                PURE(Int32LessThan, 2, 1),
-    PURE(Int32LessThanOrEqual, 2, 1),     PURE(Uint32LessThan, 2, 1),
-    PURE(Uint32LessThanOrEqual, 2, 1),    PURE(Int64Add, 2, 1),
-    PURE(Int64Sub, 2, 1),                 PURE(Int64Mul, 2, 1),
-    PURE(Int64Div, 2, 1),                 PURE(Int64UDiv, 2, 1),
-    PURE(Int64Mod, 2, 1),                 PURE(Int64UMod, 2, 1),
-    PURE(Int64LessThan, 2, 1),            PURE(Int64LessThanOrEqual, 2, 1),
-    PURE(ChangeFloat32ToFloat64, 1, 1),   PURE(ChangeFloat64ToInt32, 1, 1),
-    PURE(ChangeFloat64ToUint32, 1, 1),    PURE(ChangeInt32ToInt64, 1, 1),
-    PURE(ChangeUint32ToFloat64, 1, 1),    PURE(ChangeUint32ToUint64, 1, 1),
-    PURE(TruncateFloat64ToFloat32, 1, 1), PURE(TruncateFloat64ToInt32, 1, 1),
-    PURE(TruncateInt64ToInt32, 1, 1),     PURE(Float64Add, 2, 1),
-    PURE(Float64Sub, 2, 1),               PURE(Float64Mul, 2, 1),
-    PURE(Float64Div, 2, 1),               PURE(Float64Mod, 2, 1),
-    PURE(Float64Sqrt, 1, 1),              PURE(Float64Equal, 2, 1),
-    PURE(Float64LessThan, 2, 1),          PURE(Float64LessThanOrEqual, 2, 1)
-#undef PURE
-};
-
-
-typedef MachineOperatorTestWithParam<PureOperator> MachinePureOperatorTest;
-
-}  // namespace
-
-
-TEST_P(MachinePureOperatorTest, InstancesAreGloballyShared) {
-  const PureOperator& pop = GetParam();
-  MachineOperatorBuilder machine1(type());
-  MachineOperatorBuilder machine2(type());
-  EXPECT_EQ((machine1.*pop.constructor)(), (machine2.*pop.constructor)());
-}
-
-
-TEST_P(MachinePureOperatorTest, NumberOfInputsAndOutputs) {
-  MachineOperatorBuilder machine(type());
-  const PureOperator& pop = GetParam();
-  const Operator* op = (machine.*pop.constructor)();
-
-  EXPECT_EQ(pop.value_input_count, OperatorProperties::GetValueInputCount(op));
-  EXPECT_EQ(0, OperatorProperties::GetEffectInputCount(op));
-  EXPECT_EQ(0, OperatorProperties::GetControlInputCount(op));
-  EXPECT_EQ(pop.value_input_count, OperatorProperties::GetTotalInputCount(op));
-
-  EXPECT_EQ(pop.value_output_count,
-            OperatorProperties::GetValueOutputCount(op));
-  EXPECT_EQ(0, OperatorProperties::GetEffectOutputCount(op));
-  EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
-}
-
-
-TEST_P(MachinePureOperatorTest, MarkedAsPure) {
-  MachineOperatorBuilder machine(type());
-  const PureOperator& pop = GetParam();
-  const Operator* op = (machine.*pop.constructor)();
-  EXPECT_TRUE(op->HasProperty(Operator::kPure));
-}
-
-
-TEST_P(MachinePureOperatorTest, OpcodeIsCorrect) {
-  MachineOperatorBuilder machine(type());
-  const PureOperator& pop = GetParam();
-  const Operator* op = (machine.*pop.constructor)();
-  EXPECT_EQ(pop.opcode, op->opcode());
-}
-
-
-INSTANTIATE_TEST_CASE_P(
-    MachineOperatorTest, MachinePureOperatorTest,
-    ::testing::Combine(::testing::ValuesIn(kMachineReps),
-                       ::testing::ValuesIn(kPureOperators)));
-
-#endif  // GTEST_HAS_COMBINE
-
-
-// -----------------------------------------------------------------------------
-// Pseudo operators.
-
-
-TEST(MachineOperatorTest, PseudoOperatorsWhenWordSizeIs32Bit) {
-  MachineOperatorBuilder machine(kRepWord32);
-  EXPECT_EQ(machine.Word32And(), machine.WordAnd());
-  EXPECT_EQ(machine.Word32Or(), machine.WordOr());
-  EXPECT_EQ(machine.Word32Xor(), machine.WordXor());
-  EXPECT_EQ(machine.Word32Shl(), machine.WordShl());
-  EXPECT_EQ(machine.Word32Shr(), machine.WordShr());
-  EXPECT_EQ(machine.Word32Sar(), machine.WordSar());
-  EXPECT_EQ(machine.Word32Ror(), machine.WordRor());
-  EXPECT_EQ(machine.Word32Equal(), machine.WordEqual());
-  EXPECT_EQ(machine.Int32Add(), machine.IntAdd());
-  EXPECT_EQ(machine.Int32Sub(), machine.IntSub());
-  EXPECT_EQ(machine.Int32Mul(), machine.IntMul());
-  EXPECT_EQ(machine.Int32Div(), machine.IntDiv());
-  EXPECT_EQ(machine.Int32UDiv(), machine.IntUDiv());
-  EXPECT_EQ(machine.Int32Mod(), machine.IntMod());
-  EXPECT_EQ(machine.Int32UMod(), machine.IntUMod());
-  EXPECT_EQ(machine.Int32LessThan(), machine.IntLessThan());
-  EXPECT_EQ(machine.Int32LessThanOrEqual(), machine.IntLessThanOrEqual());
-}
-
-
-TEST(MachineOperatorTest, PseudoOperatorsWhenWordSizeIs64Bit) {
-  MachineOperatorBuilder machine(kRepWord64);
-  EXPECT_EQ(machine.Word64And(), machine.WordAnd());
-  EXPECT_EQ(machine.Word64Or(), machine.WordOr());
-  EXPECT_EQ(machine.Word64Xor(), machine.WordXor());
-  EXPECT_EQ(machine.Word64Shl(), machine.WordShl());
-  EXPECT_EQ(machine.Word64Shr(), machine.WordShr());
-  EXPECT_EQ(machine.Word64Sar(), machine.WordSar());
-  EXPECT_EQ(machine.Word64Ror(), machine.WordRor());
-  EXPECT_EQ(machine.Word64Equal(), machine.WordEqual());
-  EXPECT_EQ(machine.Int64Add(), machine.IntAdd());
-  EXPECT_EQ(machine.Int64Sub(), machine.IntSub());
-  EXPECT_EQ(machine.Int64Mul(), machine.IntMul());
-  EXPECT_EQ(machine.Int64Div(), machine.IntDiv());
-  EXPECT_EQ(machine.Int64UDiv(), machine.IntUDiv());
-  EXPECT_EQ(machine.Int64Mod(), machine.IntMod());
-  EXPECT_EQ(machine.Int64UMod(), machine.IntUMod());
-  EXPECT_EQ(machine.Int64LessThan(), machine.IntLessThan());
-  EXPECT_EQ(machine.Int64LessThanOrEqual(), machine.IntLessThanOrEqual());
-}
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/machine-operator.cc b/src/compiler/machine-operator.cc
index 2f30bd2..eb034e9 100644
--- a/src/compiler/machine-operator.cc
+++ b/src/compiler/machine-operator.cc
@@ -7,13 +7,15 @@
 #include "src/base/lazy-instance.h"
 #include "src/compiler/opcodes.h"
 #include "src/compiler/operator.h"
+#include "src/v8.h"
+#include "src/zone-inl.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
-OStream& operator<<(OStream& os, const WriteBarrierKind& write_barrier_kind) {
-  switch (write_barrier_kind) {
+std::ostream& operator<<(std::ostream& os, WriteBarrierKind kind) {
+  switch (kind) {
     case kNoWriteBarrier:
       return os << "NoWriteBarrier";
     case kFullWriteBarrier:
@@ -24,98 +26,113 @@
 }
 
 
-OStream& operator<<(OStream& os, const StoreRepresentation& rep) {
+bool operator==(StoreRepresentation lhs, StoreRepresentation rhs) {
+  return lhs.machine_type() == rhs.machine_type() &&
+         lhs.write_barrier_kind() == rhs.write_barrier_kind();
+}
+
+
+bool operator!=(StoreRepresentation lhs, StoreRepresentation rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(StoreRepresentation rep) {
+  return base::hash_combine(rep.machine_type(), rep.write_barrier_kind());
+}
+
+
+std::ostream& operator<<(std::ostream& os, StoreRepresentation rep) {
   return os << "(" << rep.machine_type() << " : " << rep.write_barrier_kind()
             << ")";
 }
 
 
-template <>
-struct StaticParameterTraits<StoreRepresentation> {
-  static OStream& PrintTo(OStream& os, const StoreRepresentation& rep) {
-    return os << rep;
-  }
-  static int HashCode(const StoreRepresentation& rep) {
-    return rep.machine_type() + rep.write_barrier_kind();
-  }
-  static bool Equals(const StoreRepresentation& rep1,
-                     const StoreRepresentation& rep2) {
-    return rep1 == rep2;
-  }
-};
+StoreRepresentation const& StoreRepresentationOf(Operator const* op) {
+  DCHECK_EQ(IrOpcode::kStore, op->opcode());
+  return OpParameter<StoreRepresentation>(op);
+}
 
 
-template <>
-struct StaticParameterTraits<LoadRepresentation> {
-  static OStream& PrintTo(OStream& os, LoadRepresentation type) {  // NOLINT
-    return os << type;
-  }
-  static int HashCode(LoadRepresentation type) { return type; }
-  static bool Equals(LoadRepresentation lhs, LoadRepresentation rhs) {
-    return lhs == rhs;
-  }
-};
+CheckedLoadRepresentation CheckedLoadRepresentationOf(Operator const* op) {
+  DCHECK_EQ(IrOpcode::kCheckedLoad, op->opcode());
+  return OpParameter<CheckedLoadRepresentation>(op);
+}
+
+
+CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
+  DCHECK_EQ(IrOpcode::kCheckedStore, op->opcode());
+  return OpParameter<CheckedStoreRepresentation>(op);
+}
 
 
 #define PURE_OP_LIST(V)                                                       \
-  V(Word32And, Operator::kAssociative | Operator::kCommutative, 2, 1)         \
-  V(Word32Or, Operator::kAssociative | Operator::kCommutative, 2, 1)          \
-  V(Word32Xor, Operator::kAssociative | Operator::kCommutative, 2, 1)         \
-  V(Word32Shl, Operator::kNoProperties, 2, 1)                                 \
-  V(Word32Shr, Operator::kNoProperties, 2, 1)                                 \
-  V(Word32Sar, Operator::kNoProperties, 2, 1)                                 \
-  V(Word32Ror, Operator::kNoProperties, 2, 1)                                 \
-  V(Word32Equal, Operator::kCommutative, 2, 1)                                \
-  V(Word64And, Operator::kAssociative | Operator::kCommutative, 2, 1)         \
-  V(Word64Or, Operator::kAssociative | Operator::kCommutative, 2, 1)          \
-  V(Word64Xor, Operator::kAssociative | Operator::kCommutative, 2, 1)         \
-  V(Word64Shl, Operator::kNoProperties, 2, 1)                                 \
-  V(Word64Shr, Operator::kNoProperties, 2, 1)                                 \
-  V(Word64Sar, Operator::kNoProperties, 2, 1)                                 \
-  V(Word64Ror, Operator::kNoProperties, 2, 1)                                 \
-  V(Word64Equal, Operator::kCommutative, 2, 1)                                \
-  V(Int32Add, Operator::kAssociative | Operator::kCommutative, 2, 1)          \
+  V(Word32And, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)      \
+  V(Word32Or, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)       \
+  V(Word32Xor, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)      \
+  V(Word32Shl, Operator::kNoProperties, 2, 0, 1)                              \
+  V(Word32Shr, Operator::kNoProperties, 2, 0, 1)                              \
+  V(Word32Sar, Operator::kNoProperties, 2, 0, 1)                              \
+  V(Word32Ror, Operator::kNoProperties, 2, 0, 1)                              \
+  V(Word32Equal, Operator::kCommutative, 2, 0, 1)                             \
+  V(Word64And, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)      \
+  V(Word64Or, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)       \
+  V(Word64Xor, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)      \
+  V(Word64Shl, Operator::kNoProperties, 2, 0, 1)                              \
+  V(Word64Shr, Operator::kNoProperties, 2, 0, 1)                              \
+  V(Word64Sar, Operator::kNoProperties, 2, 0, 1)                              \
+  V(Word64Ror, Operator::kNoProperties, 2, 0, 1)                              \
+  V(Word64Equal, Operator::kCommutative, 2, 0, 1)                             \
+  V(Int32Add, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)       \
   V(Int32AddWithOverflow, Operator::kAssociative | Operator::kCommutative, 2, \
-    2)                                                                        \
-  V(Int32Sub, Operator::kNoProperties, 2, 1)                                  \
-  V(Int32SubWithOverflow, Operator::kNoProperties, 2, 2)                      \
-  V(Int32Mul, Operator::kAssociative | Operator::kCommutative, 2, 1)          \
-  V(Int32Div, Operator::kNoProperties, 2, 1)                                  \
-  V(Int32UDiv, Operator::kNoProperties, 2, 1)                                 \
-  V(Int32Mod, Operator::kNoProperties, 2, 1)                                  \
-  V(Int32UMod, Operator::kNoProperties, 2, 1)                                 \
-  V(Int32LessThan, Operator::kNoProperties, 2, 1)                             \
-  V(Int32LessThanOrEqual, Operator::kNoProperties, 2, 1)                      \
-  V(Uint32LessThan, Operator::kNoProperties, 2, 1)                            \
-  V(Uint32LessThanOrEqual, Operator::kNoProperties, 2, 1)                     \
-  V(Int64Add, Operator::kAssociative | Operator::kCommutative, 2, 1)          \
-  V(Int64Sub, Operator::kNoProperties, 2, 1)                                  \
-  V(Int64Mul, Operator::kAssociative | Operator::kCommutative, 2, 1)          \
-  V(Int64Div, Operator::kNoProperties, 2, 1)                                  \
-  V(Int64UDiv, Operator::kNoProperties, 2, 1)                                 \
-  V(Int64Mod, Operator::kNoProperties, 2, 1)                                  \
-  V(Int64UMod, Operator::kNoProperties, 2, 1)                                 \
-  V(Int64LessThan, Operator::kNoProperties, 2, 1)                             \
-  V(Int64LessThanOrEqual, Operator::kNoProperties, 2, 1)                      \
-  V(ChangeFloat32ToFloat64, Operator::kNoProperties, 1, 1)                    \
-  V(ChangeFloat64ToInt32, Operator::kNoProperties, 1, 1)                      \
-  V(ChangeFloat64ToUint32, Operator::kNoProperties, 1, 1)                     \
-  V(ChangeInt32ToFloat64, Operator::kNoProperties, 1, 1)                      \
-  V(ChangeInt32ToInt64, Operator::kNoProperties, 1, 1)                        \
-  V(ChangeUint32ToFloat64, Operator::kNoProperties, 1, 1)                     \
-  V(ChangeUint32ToUint64, Operator::kNoProperties, 1, 1)                      \
-  V(TruncateFloat64ToFloat32, Operator::kNoProperties, 1, 1)                  \
-  V(TruncateFloat64ToInt32, Operator::kNoProperties, 1, 1)                    \
-  V(TruncateInt64ToInt32, Operator::kNoProperties, 1, 1)                      \
-  V(Float64Add, Operator::kCommutative, 2, 1)                                 \
-  V(Float64Sub, Operator::kNoProperties, 2, 1)                                \
-  V(Float64Mul, Operator::kCommutative, 2, 1)                                 \
-  V(Float64Div, Operator::kNoProperties, 2, 1)                                \
-  V(Float64Mod, Operator::kNoProperties, 2, 1)                                \
-  V(Float64Sqrt, Operator::kNoProperties, 1, 1)                               \
-  V(Float64Equal, Operator::kCommutative, 2, 1)                               \
-  V(Float64LessThan, Operator::kNoProperties, 2, 1)                           \
-  V(Float64LessThanOrEqual, Operator::kNoProperties, 2, 1)
+    0, 2)                                                                     \
+  V(Int32Sub, Operator::kNoProperties, 2, 0, 1)                               \
+  V(Int32SubWithOverflow, Operator::kNoProperties, 2, 0, 2)                   \
+  V(Int32Mul, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)       \
+  V(Int32MulHigh, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)   \
+  V(Int32Div, Operator::kNoProperties, 2, 1, 1)                               \
+  V(Int32Mod, Operator::kNoProperties, 2, 1, 1)                               \
+  V(Int32LessThan, Operator::kNoProperties, 2, 0, 1)                          \
+  V(Int32LessThanOrEqual, Operator::kNoProperties, 2, 0, 1)                   \
+  V(Uint32Div, Operator::kNoProperties, 2, 1, 1)                              \
+  V(Uint32LessThan, Operator::kNoProperties, 2, 0, 1)                         \
+  V(Uint32LessThanOrEqual, Operator::kNoProperties, 2, 0, 1)                  \
+  V(Uint32Mod, Operator::kNoProperties, 2, 1, 1)                              \
+  V(Uint32MulHigh, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)  \
+  V(Int64Add, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)       \
+  V(Int64Sub, Operator::kNoProperties, 2, 0, 1)                               \
+  V(Int64Mul, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)       \
+  V(Int64Div, Operator::kNoProperties, 2, 0, 1)                               \
+  V(Int64Mod, Operator::kNoProperties, 2, 0, 1)                               \
+  V(Int64LessThan, Operator::kNoProperties, 2, 0, 1)                          \
+  V(Int64LessThanOrEqual, Operator::kNoProperties, 2, 0, 1)                   \
+  V(Uint64Div, Operator::kNoProperties, 2, 0, 1)                              \
+  V(Uint64LessThan, Operator::kNoProperties, 2, 0, 1)                         \
+  V(Uint64Mod, Operator::kNoProperties, 2, 0, 1)                              \
+  V(ChangeFloat32ToFloat64, Operator::kNoProperties, 1, 0, 1)                 \
+  V(ChangeFloat64ToInt32, Operator::kNoProperties, 1, 0, 1)                   \
+  V(ChangeFloat64ToUint32, Operator::kNoProperties, 1, 0, 1)                  \
+  V(ChangeInt32ToFloat64, Operator::kNoProperties, 1, 0, 1)                   \
+  V(ChangeInt32ToInt64, Operator::kNoProperties, 1, 0, 1)                     \
+  V(ChangeUint32ToFloat64, Operator::kNoProperties, 1, 0, 1)                  \
+  V(ChangeUint32ToUint64, Operator::kNoProperties, 1, 0, 1)                   \
+  V(TruncateFloat64ToFloat32, Operator::kNoProperties, 1, 0, 1)               \
+  V(TruncateFloat64ToInt32, Operator::kNoProperties, 1, 0, 1)                 \
+  V(TruncateInt64ToInt32, Operator::kNoProperties, 1, 0, 1)                   \
+  V(Float64Add, Operator::kCommutative, 2, 0, 1)                              \
+  V(Float64Sub, Operator::kNoProperties, 2, 0, 1)                             \
+  V(Float64Mul, Operator::kCommutative, 2, 0, 1)                              \
+  V(Float64Div, Operator::kNoProperties, 2, 0, 1)                             \
+  V(Float64Mod, Operator::kNoProperties, 2, 0, 1)                             \
+  V(Float64Sqrt, Operator::kNoProperties, 1, 0, 1)                            \
+  V(Float64Ceil, Operator::kNoProperties, 1, 0, 1)                            \
+  V(Float64Floor, Operator::kNoProperties, 1, 0, 1)                           \
+  V(Float64RoundTruncate, Operator::kNoProperties, 1, 0, 1)                   \
+  V(Float64RoundTiesAway, Operator::kNoProperties, 1, 0, 1)                   \
+  V(Float64Equal, Operator::kCommutative, 2, 0, 1)                            \
+  V(Float64LessThan, Operator::kNoProperties, 2, 0, 1)                        \
+  V(Float64LessThanOrEqual, Operator::kNoProperties, 2, 0, 1)                 \
+  V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1)
 
 
 #define MACHINE_TYPE_LIST(V) \
@@ -140,64 +157,85 @@
   V(RepTagged)
 
 
-struct MachineOperatorBuilderImpl {
-#define PURE(Name, properties, input_count, output_count)                 \
-  struct Name##Operator FINAL : public SimpleOperator {                   \
-    Name##Operator()                                                      \
-        : SimpleOperator(IrOpcode::k##Name, Operator::kPure | properties, \
-                         input_count, output_count, #Name) {}             \
-  };                                                                      \
+struct MachineOperatorGlobalCache {
+#define PURE(Name, properties, value_input_count, control_input_count,         \
+             output_count)                                                     \
+  struct Name##Operator FINAL : public Operator {                              \
+    Name##Operator()                                                           \
+        : Operator(IrOpcode::k##Name, Operator::kPure | properties, #Name,     \
+                   value_input_count, 0, control_input_count, output_count, 0, \
+                   0) {}                                                       \
+  };                                                                           \
   Name##Operator k##Name;
   PURE_OP_LIST(PURE)
 #undef PURE
 
-#define LOAD(Type)                                                            \
-  struct Load##Type##Operator FINAL : public Operator1<LoadRepresentation> {  \
-    Load##Type##Operator()                                                    \
-        : Operator1<LoadRepresentation>(                                      \
-              IrOpcode::kLoad, Operator::kNoThrow | Operator::kNoWrite, 2, 1, \
-              "Load", k##Type) {}                                             \
-  };                                                                          \
-  Load##Type##Operator k##Load##Type;
+#define LOAD(Type)                                                             \
+  struct Load##Type##Operator FINAL : public Operator1<LoadRepresentation> {   \
+    Load##Type##Operator()                                                     \
+        : Operator1<LoadRepresentation>(                                       \
+              IrOpcode::kLoad, Operator::kNoThrow | Operator::kNoWrite,        \
+              "Load", 2, 1, 1, 1, 1, 0, k##Type) {}                            \
+  };                                                                           \
+  struct CheckedLoad##Type##Operator FINAL                                     \
+      : public Operator1<CheckedLoadRepresentation> {                          \
+    CheckedLoad##Type##Operator()                                              \
+        : Operator1<CheckedLoadRepresentation>(                                \
+              IrOpcode::kCheckedLoad, Operator::kNoThrow | Operator::kNoWrite, \
+              "CheckedLoad", 3, 1, 1, 1, 1, 0, k##Type) {}                     \
+  };                                                                           \
+  Load##Type##Operator kLoad##Type;                                            \
+  CheckedLoad##Type##Operator kCheckedLoad##Type;
   MACHINE_TYPE_LIST(LOAD)
 #undef LOAD
 
-#define STORE(Type)                                                           \
-  struct Store##Type##Operator : public Operator1<StoreRepresentation> {      \
-    explicit Store##Type##Operator(WriteBarrierKind write_barrier_kind)       \
-        : Operator1<StoreRepresentation>(                                     \
-              IrOpcode::kStore, Operator::kNoRead | Operator::kNoThrow, 3, 0, \
-              "Store", StoreRepresentation(k##Type, write_barrier_kind)) {}   \
-  };                                                                          \
-  struct Store##Type##NoWriteBarrier##Operator FINAL                          \
-      : public Store##Type##Operator {                                        \
-    Store##Type##NoWriteBarrier##Operator()                                   \
-        : Store##Type##Operator(kNoWriteBarrier) {}                           \
-  };                                                                          \
-  struct Store##Type##FullWriteBarrier##Operator FINAL                        \
-      : public Store##Type##Operator {                                        \
-    Store##Type##FullWriteBarrier##Operator()                                 \
-        : Store##Type##Operator(kFullWriteBarrier) {}                         \
-  };                                                                          \
-  Store##Type##NoWriteBarrier##Operator k##Store##Type##NoWriteBarrier;       \
-  Store##Type##FullWriteBarrier##Operator k##Store##Type##FullWriteBarrier;
+#define STORE(Type)                                                            \
+  struct Store##Type##Operator : public Operator1<StoreRepresentation> {       \
+    explicit Store##Type##Operator(WriteBarrierKind write_barrier_kind)        \
+        : Operator1<StoreRepresentation>(                                      \
+              IrOpcode::kStore, Operator::kNoRead | Operator::kNoThrow,        \
+              "Store", 3, 1, 1, 0, 1, 0,                                       \
+              StoreRepresentation(k##Type, write_barrier_kind)) {}             \
+  };                                                                           \
+  struct Store##Type##NoWriteBarrier##Operator FINAL                           \
+      : public Store##Type##Operator {                                         \
+    Store##Type##NoWriteBarrier##Operator()                                    \
+        : Store##Type##Operator(kNoWriteBarrier) {}                            \
+  };                                                                           \
+  struct Store##Type##FullWriteBarrier##Operator FINAL                         \
+      : public Store##Type##Operator {                                         \
+    Store##Type##FullWriteBarrier##Operator()                                  \
+        : Store##Type##Operator(kFullWriteBarrier) {}                          \
+  };                                                                           \
+  struct CheckedStore##Type##Operator FINAL                                    \
+      : public Operator1<CheckedStoreRepresentation> {                         \
+    CheckedStore##Type##Operator()                                             \
+        : Operator1<CheckedStoreRepresentation>(                               \
+              IrOpcode::kCheckedStore, Operator::kNoRead | Operator::kNoThrow, \
+              "CheckedStore", 4, 1, 1, 0, 1, 0, k##Type) {}                    \
+  };                                                                           \
+  Store##Type##NoWriteBarrier##Operator kStore##Type##NoWriteBarrier;          \
+  Store##Type##FullWriteBarrier##Operator kStore##Type##FullWriteBarrier;      \
+  CheckedStore##Type##Operator kCheckedStore##Type;
   MACHINE_TYPE_LIST(STORE)
 #undef STORE
 };
 
 
-static base::LazyInstance<MachineOperatorBuilderImpl>::type kImpl =
+static base::LazyInstance<MachineOperatorGlobalCache>::type kCache =
     LAZY_INSTANCE_INITIALIZER;
 
 
-MachineOperatorBuilder::MachineOperatorBuilder(MachineType word)
-    : impl_(kImpl.Get()), word_(word) {
+MachineOperatorBuilder::MachineOperatorBuilder(Zone* zone, MachineType word,
+                                               Flags flags)
+    : zone_(zone), cache_(kCache.Get()), word_(word), flags_(flags) {
   DCHECK(word == kRepWord32 || word == kRepWord64);
 }
 
 
-#define PURE(Name, properties, input_count, output_count) \
-  const Operator* MachineOperatorBuilder::Name() { return &impl_.k##Name; }
+#define PURE(Name, properties, value_input_count, control_input_count, \
+             output_count)                                             \
+  const Operator* MachineOperatorBuilder::Name() { return &cache_.k##Name; }
 PURE_OP_LIST(PURE)
 #undef PURE
 
@@ -206,28 +244,29 @@
   switch (rep) {
 #define LOAD(Type) \
   case k##Type:    \
-    return &impl_.k##Load##Type;
+    return &cache_.kLoad##Type;
     MACHINE_TYPE_LIST(LOAD)
 #undef LOAD
-
     default:
       break;
   }
-  UNREACHABLE();
-  return NULL;
+  // Uncached.
+  return new (zone_) Operator1<LoadRepresentation>(  // --
+      IrOpcode::kLoad, Operator::kNoThrow | Operator::kNoWrite, "Load", 2, 1, 1,
+      1, 1, 0, rep);
 }
 
 
 const Operator* MachineOperatorBuilder::Store(StoreRepresentation rep) {
   switch (rep.machine_type()) {
-#define STORE(Type)                                     \
-  case k##Type:                                         \
-    switch (rep.write_barrier_kind()) {                 \
-      case kNoWriteBarrier:                             \
-        return &impl_.k##Store##Type##NoWriteBarrier;   \
-      case kFullWriteBarrier:                           \
-        return &impl_.k##Store##Type##FullWriteBarrier; \
-    }                                                   \
+#define STORE(Type)                                      \
+  case k##Type:                                          \
+    switch (rep.write_barrier_kind()) {                  \
+      case kNoWriteBarrier:                              \
+        return &cache_.k##Store##Type##NoWriteBarrier;   \
+      case kFullWriteBarrier:                            \
+        return &cache_.k##Store##Type##FullWriteBarrier; \
+    }                                                    \
     break;
     MACHINE_TYPE_LIST(STORE)
 #undef STORE
@@ -235,8 +274,46 @@
     default:
       break;
   }
-  UNREACHABLE();
-  return NULL;
+  // Uncached.
+  return new (zone_) Operator1<StoreRepresentation>(  // --
+      IrOpcode::kStore, Operator::kNoRead | Operator::kNoThrow, "Store", 3, 1,
+      1, 0, 1, 0, rep);
+}
+
+
+const Operator* MachineOperatorBuilder::CheckedLoad(
+    CheckedLoadRepresentation rep) {
+  switch (rep) {
+#define LOAD(Type) \
+  case k##Type:    \
+    return &cache_.kCheckedLoad##Type;
+    MACHINE_TYPE_LIST(LOAD)
+#undef LOAD
+    default:
+      break;
+  }
+  // Uncached.
+  return new (zone_) Operator1<CheckedLoadRepresentation>(
+      IrOpcode::kCheckedLoad, Operator::kNoThrow | Operator::kNoWrite,
+      "CheckedLoad", 3, 1, 1, 1, 1, 0, rep);
+}
+
+
+const Operator* MachineOperatorBuilder::CheckedStore(
+    CheckedStoreRepresentation rep) {
+  switch (rep) {
+#define STORE(Type) \
+  case k##Type:     \
+    return &cache_.kCheckedStore##Type;
+    MACHINE_TYPE_LIST(STORE)
+#undef STORE
+    default:
+      break;
+  }
+  // Uncached.
+  return new (zone_) Operator1<CheckedStoreRepresentation>(
+      IrOpcode::kCheckedStore, Operator::kNoRead | Operator::kNoThrow,
+      "CheckedStore", 4, 1, 1, 0, 1, 0, rep);
 }
 
 }  // namespace compiler
diff --git a/src/compiler/machine-operator.h b/src/compiler/machine-operator.h
index 92c8ac4..42f3130 100644
--- a/src/compiler/machine-operator.h
+++ b/src/compiler/machine-operator.h
@@ -5,6 +5,7 @@
 #ifndef V8_COMPILER_MACHINE_OPERATOR_H_
 #define V8_COMPILER_MACHINE_OPERATOR_H_
 
+#include "src/base/flags.h"
 #include "src/compiler/machine-type.h"
 
 namespace v8 {
@@ -12,21 +13,22 @@
 namespace compiler {
 
 // Forward declarations.
-struct MachineOperatorBuilderImpl;
+struct MachineOperatorGlobalCache;
 class Operator;
 
 
 // Supported write barrier modes.
 enum WriteBarrierKind { kNoWriteBarrier, kFullWriteBarrier };
 
-OStream& operator<<(OStream& os, const WriteBarrierKind& write_barrier_kind);
+std::ostream& operator<<(std::ostream& os, WriteBarrierKind);
 
 
+// A Load needs a MachineType.
 typedef MachineType LoadRepresentation;
 
 
-// A Store needs a MachineType and a WriteBarrierKind
-// in order to emit the correct write barrier.
+// A Store needs a MachineType and a WriteBarrierKind in order to emit the
+// correct write barrier.
 class StoreRepresentation FINAL {
  public:
   StoreRepresentation(MachineType machine_type,
@@ -41,26 +43,49 @@
   WriteBarrierKind write_barrier_kind_;
 };
 
-inline bool operator==(const StoreRepresentation& rep1,
-                       const StoreRepresentation& rep2) {
-  return rep1.machine_type() == rep2.machine_type() &&
-         rep1.write_barrier_kind() == rep2.write_barrier_kind();
-}
+bool operator==(StoreRepresentation, StoreRepresentation);
+bool operator!=(StoreRepresentation, StoreRepresentation);
 
-inline bool operator!=(const StoreRepresentation& rep1,
-                       const StoreRepresentation& rep2) {
-  return !(rep1 == rep2);
-}
+size_t hash_value(StoreRepresentation);
 
-OStream& operator<<(OStream& os, const StoreRepresentation& rep);
+std::ostream& operator<<(std::ostream&, StoreRepresentation);
+
+StoreRepresentation const& StoreRepresentationOf(Operator const*);
+
+
+// A CheckedLoad needs a MachineType.
+typedef MachineType CheckedLoadRepresentation;
+
+CheckedLoadRepresentation CheckedLoadRepresentationOf(Operator const*);
+
+
+// A CheckedStore needs a MachineType.
+typedef MachineType CheckedStoreRepresentation;
+
+CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const*);
 
 
 // Interface for building machine-level operators. These operators are
 // machine-level but machine-independent and thus define a language suitable
 // for generating code to run on architectures such as ia32, x64, arm, etc.
-class MachineOperatorBuilder FINAL {
+class MachineOperatorBuilder FINAL : public ZoneObject {
  public:
-  explicit MachineOperatorBuilder(MachineType word = kMachPtr);
+  // Flags that specify which operations are available. This is useful
+  // for operations that are unsupported by some back-ends.
+  enum Flag {
+    kNoFlags = 0u,
+    kFloat64Floor = 1u << 0,
+    kFloat64Ceil = 1u << 1,
+    kFloat64RoundTruncate = 1u << 2,
+    kFloat64RoundTiesAway = 1u << 3,
+    kInt32DivIsSafe = 1u << 4,
+    kUint32DivIsSafe = 1u << 5,
+    kWord32ShiftIsSafe = 1u << 6
+  };
+  typedef base::Flags<Flag, unsigned> Flags;
+
+  explicit MachineOperatorBuilder(Zone* zone, MachineType word = kMachPtr,
+                                  Flags supportedOperators = kNoFlags);
 
   const Operator* Word32And();
   const Operator* Word32Or();
@@ -70,6 +95,7 @@
   const Operator* Word32Sar();
   const Operator* Word32Ror();
   const Operator* Word32Equal();
+  bool Word32ShiftIsSafe() const { return flags_ & kWord32ShiftIsSafe; }
 
   const Operator* Word64And();
   const Operator* Word64Or();
@@ -85,24 +111,29 @@
   const Operator* Int32Sub();
   const Operator* Int32SubWithOverflow();
   const Operator* Int32Mul();
+  const Operator* Int32MulHigh();
   const Operator* Int32Div();
-  const Operator* Int32UDiv();
   const Operator* Int32Mod();
-  const Operator* Int32UMod();
   const Operator* Int32LessThan();
   const Operator* Int32LessThanOrEqual();
+  const Operator* Uint32Div();
   const Operator* Uint32LessThan();
   const Operator* Uint32LessThanOrEqual();
+  const Operator* Uint32Mod();
+  const Operator* Uint32MulHigh();
+  bool Int32DivIsSafe() const { return flags_ & kInt32DivIsSafe; }
+  bool Uint32DivIsSafe() const { return flags_ & kUint32DivIsSafe; }
 
   const Operator* Int64Add();
   const Operator* Int64Sub();
   const Operator* Int64Mul();
   const Operator* Int64Div();
-  const Operator* Int64UDiv();
   const Operator* Int64Mod();
-  const Operator* Int64UMod();
   const Operator* Int64LessThan();
   const Operator* Int64LessThanOrEqual();
+  const Operator* Uint64Div();
+  const Operator* Uint64LessThan();
+  const Operator* Uint64Mod();
 
   // These operators change the representation of numbers while preserving the
   // value of the number. Narrowing operators assume the input is representable
@@ -136,12 +167,30 @@
   const Operator* Float64LessThan();
   const Operator* Float64LessThanOrEqual();
 
+  // Floating point rounding.
+  const Operator* Float64Floor();
+  const Operator* Float64Ceil();
+  const Operator* Float64RoundTruncate();
+  const Operator* Float64RoundTiesAway();
+  bool HasFloat64Floor() { return flags_ & kFloat64Floor; }
+  bool HasFloat64Ceil() { return flags_ & kFloat64Ceil; }
+  bool HasFloat64RoundTruncate() { return flags_ & kFloat64RoundTruncate; }
+  bool HasFloat64RoundTiesAway() { return flags_ & kFloat64RoundTiesAway; }
+
   // load [base + index]
   const Operator* Load(LoadRepresentation rep);
 
   // store [base + index], value
   const Operator* Store(StoreRepresentation rep);
 
+  // Access to the machine stack.
+  const Operator* LoadStackPointer();
+
+  // checked-load heap, index, length
+  const Operator* CheckedLoad(CheckedLoadRepresentation);
+  // checked-store heap, index, length, value
+  const Operator* CheckedStore(CheckedStoreRepresentation);
+
   // Target machine word-size assumed by this builder.
   bool Is32() const { return word() == kRepWord32; }
   bool Is64() const { return word() == kRepWord64; }
@@ -162,11 +211,12 @@
   V(Int, Sub)             \
   V(Int, Mul)             \
   V(Int, Div)             \
-  V(Int, UDiv)            \
   V(Int, Mod)             \
-  V(Int, UMod)            \
   V(Int, LessThan)        \
-  V(Int, LessThanOrEqual)
+  V(Int, LessThanOrEqual) \
+  V(Uint, Div)            \
+  V(Uint, LessThan)       \
+  V(Uint, Mod)
 #define PSEUDO_OP(Prefix, Suffix)                                \
   const Operator* Prefix##Suffix() {                             \
     return Is32() ? Prefix##32##Suffix() : Prefix##64##Suffix(); \
@@ -176,10 +226,17 @@
 #undef PSEUDO_OP_LIST
 
  private:
-  const MachineOperatorBuilderImpl& impl_;
+  Zone* zone_;
+  const MachineOperatorGlobalCache& cache_;
   const MachineType word_;
+  const Flags flags_;
+
+  DISALLOW_COPY_AND_ASSIGN(MachineOperatorBuilder);
 };
 
+
+DEFINE_OPERATORS_FOR_FLAGS(MachineOperatorBuilder::Flags)
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
diff --git a/src/compiler/machine-type.cc b/src/compiler/machine-type.cc
index 94aa124..7475a03 100644
--- a/src/compiler/machine-type.cc
+++ b/src/compiler/machine-type.cc
@@ -17,7 +17,7 @@
   }
 
 
-OStream& operator<<(OStream& os, const MachineType& type) {
+std::ostream& operator<<(std::ostream& os, const MachineType& type) {
   bool before = false;
   PRINT(kRepBit);
   PRINT(kRepWord8);
diff --git a/src/compiler/machine-type.h b/src/compiler/machine-type.h
index 88b482c..4c51a9f 100644
--- a/src/compiler/machine-type.h
+++ b/src/compiler/machine-type.h
@@ -5,15 +5,14 @@
 #ifndef V8_COMPILER_MACHINE_TYPE_H_
 #define V8_COMPILER_MACHINE_TYPE_H_
 
+#include <iosfwd>
+
 #include "src/base/bits.h"
 #include "src/globals.h"
 #include "src/zone.h"
 
 namespace v8 {
 namespace internal {
-
-class OStream;
-
 namespace compiler {
 
 // Machine-level types and representations.
@@ -40,6 +39,7 @@
 
   // Machine types.
   kMachNone = 0,
+  kMachBool = kRepBit | kTypeBool,
   kMachFloat32 = kRepFloat32 | kTypeNumber,
   kMachFloat64 = kRepFloat64 | kTypeNumber,
   kMachInt8 = kRepWord8 | kTypeInt32,
@@ -50,11 +50,13 @@
   kMachUint32 = kRepWord32 | kTypeUint32,
   kMachInt64 = kRepWord64 | kTypeInt64,
   kMachUint64 = kRepWord64 | kTypeUint64,
+  kMachIntPtr = (kPointerSize == 4) ? kMachInt32 : kMachInt64,
+  kMachUintPtr = (kPointerSize == 4) ? kMachUint32 : kMachUint64,
   kMachPtr = (kPointerSize == 4) ? kRepWord32 : kRepWord64,
   kMachAnyTagged = kRepTagged | kTypeAny
 };
 
-OStream& operator<<(OStream& os, const MachineType& type);
+std::ostream& operator<<(std::ostream& os, const MachineType& type);
 
 typedef uint16_t MachineTypeUnion;
 
@@ -79,26 +81,34 @@
   return static_cast<MachineType>(result);
 }
 
-// Gets the element size in bytes of the machine type.
-inline int ElementSizeOf(MachineType machine_type) {
+// Gets the log2 of the element size in bytes of the machine type.
+inline int ElementSizeLog2Of(MachineType machine_type) {
   switch (RepresentationOf(machine_type)) {
     case kRepBit:
     case kRepWord8:
-      return 1;
+      return 0;
     case kRepWord16:
-      return 2;
+      return 1;
     case kRepWord32:
     case kRepFloat32:
-      return 4;
+      return 2;
     case kRepWord64:
     case kRepFloat64:
-      return 8;
+      return 3;
     case kRepTagged:
-      return kPointerSize;
+      return kPointerSizeLog2;
     default:
-      UNREACHABLE();
-      return kPointerSize;
+      break;
   }
+  UNREACHABLE();
+  return -1;
+}
+
+// Gets the element size in bytes of the machine type.
+inline int ElementSizeOf(MachineType machine_type) {
+  const int shift = ElementSizeLog2Of(machine_type);
+  DCHECK_NE(-1, shift);
+  return 1 << shift;
 }
 
 // Describes the inputs and outputs of a function or call.
diff --git a/src/compiler/mips/OWNERS b/src/compiler/mips/OWNERS
new file mode 100644
index 0000000..5508ba6
--- /dev/null
+++ b/src/compiler/mips/OWNERS
@@ -0,0 +1,5 @@
+paul.lind@imgtec.com
+gergely.kis@imgtec.com
+akos.palfi@imgtec.com
+balazs.kilvady@imgtec.com
+dusan.milosavljevic@imgtec.com
diff --git a/src/compiler/mips/code-generator-mips.cc b/src/compiler/mips/code-generator-mips.cc
new file mode 100644
index 0000000..dd92837
--- /dev/null
+++ b/src/compiler/mips/code-generator-mips.cc
@@ -0,0 +1,1185 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/code-generator.h"
+#include "src/compiler/code-generator-impl.h"
+#include "src/compiler/gap-resolver.h"
+#include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/mips/macro-assembler-mips.h"
+#include "src/scopes.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+#define __ masm()->
+
+
+// TODO(plind): Possibly avoid using these lithium names.
+#define kScratchReg kLithiumScratchReg
+#define kCompareReg kLithiumScratchReg2
+#define kScratchReg2 kLithiumScratchReg2
+#define kScratchDoubleReg kLithiumScratchDouble
+
+
+// TODO(plind): consider renaming these macros.
+#define TRACE_MSG(msg)                                                      \
+  PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \
+         __LINE__)
+
+#define TRACE_UNIMPL()                                                       \
+  PrintF("UNIMPLEMENTED code_generator_mips: %s at line %d\n", __FUNCTION__, \
+         __LINE__)
+
+
+// Adds Mips-specific methods to convert InstructionOperands.
+class MipsOperandConverter FINAL : public InstructionOperandConverter {
+ public:
+  MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
+      : InstructionOperandConverter(gen, instr) {}
+
+  FloatRegister OutputSingleRegister(int index = 0) {
+    return ToSingleRegister(instr_->OutputAt(index));
+  }
+
+  FloatRegister InputSingleRegister(int index) {
+    return ToSingleRegister(instr_->InputAt(index));
+  }
+
+  FloatRegister ToSingleRegister(InstructionOperand* op) {
+    // Single (Float) and Double register namespace is same on MIPS,
+    // both are typedefs of FPURegister.
+    return ToDoubleRegister(op);
+  }
+
+  Operand InputImmediate(int index) {
+    Constant constant = ToConstant(instr_->InputAt(index));
+    switch (constant.type()) {
+      case Constant::kInt32:
+        return Operand(constant.ToInt32());
+      case Constant::kFloat32:
+        return Operand(
+            isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
+      case Constant::kFloat64:
+        return Operand(
+            isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
+      case Constant::kInt64:
+      case Constant::kExternalReference:
+      case Constant::kHeapObject:
+        // TODO(plind): Maybe we should handle ExtRef & HeapObj here?
+        //    maybe not done on arm due to const pool ??
+        break;
+      case Constant::kRpoNumber:
+        UNREACHABLE();  // TODO(titzer): RPO immediates on mips?
+        break;
+    }
+    UNREACHABLE();
+    return Operand(zero_reg);
+  }
+
+  Operand InputOperand(int index) {
+    InstructionOperand* op = instr_->InputAt(index);
+    if (op->IsRegister()) {
+      return Operand(ToRegister(op));
+    }
+    return InputImmediate(index);
+  }
+
+  MemOperand MemoryOperand(int* first_index) {
+    const int index = *first_index;
+    switch (AddressingModeField::decode(instr_->opcode())) {
+      case kMode_None:
+        break;
+      case kMode_MRI:
+        *first_index += 2;
+        return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
+      case kMode_MRR:
+        // TODO(plind): r6 address mode, to be implemented ...
+        UNREACHABLE();
+    }
+    UNREACHABLE();
+    return MemOperand(no_reg);
+  }
+
+  MemOperand MemoryOperand(int index = 0) { return MemoryOperand(&index); }
+
+  MemOperand ToMemOperand(InstructionOperand* op) const {
+    DCHECK(op != NULL);
+    DCHECK(!op->IsRegister());
+    DCHECK(!op->IsDoubleRegister());
+    DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
+    // The linkage computes where all spill slots are located.
+    FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
+    return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
+  }
+};
+
+
+static inline bool HasRegisterInput(Instruction* instr, int index) {
+  return instr->InputAt(index)->IsRegister();
+}
+
+
+namespace {
+
+class OutOfLineLoadSingle FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL {
+    __ Move(result_, std::numeric_limits<float>::quiet_NaN());
+  }
+
+ private:
+  FloatRegister const result_;
+};
+
+
+class OutOfLineLoadDouble FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadDouble(CodeGenerator* gen, DoubleRegister result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL {
+    __ Move(result_, std::numeric_limits<double>::quiet_NaN());
+  }
+
+ private:
+  DoubleRegister const result_;
+};
+
+
+class OutOfLineLoadInteger FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadInteger(CodeGenerator* gen, Register result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL { __ mov(result_, zero_reg); }
+
+ private:
+  Register const result_;
+};
+
+
+class OutOfLineRound : public OutOfLineCode {
+ public:
+  OutOfLineRound(CodeGenerator* gen, DoubleRegister result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL {
+    // Handle rounding to zero case where sign has to be preserved.
+    // High bits of double input already in kScratchReg.
+    __ srl(at, kScratchReg, 31);
+    __ sll(at, at, 31);
+    __ Mthc1(at, result_);
+  }
+
+ private:
+  DoubleRegister const result_;
+};
+
+
+class OutOfLineTruncate FINAL : public OutOfLineRound {
+ public:
+  OutOfLineTruncate(CodeGenerator* gen, DoubleRegister result)
+      : OutOfLineRound(gen, result) {}
+};
+
+
+class OutOfLineFloor FINAL : public OutOfLineRound {
+ public:
+  OutOfLineFloor(CodeGenerator* gen, DoubleRegister result)
+      : OutOfLineRound(gen, result) {}
+};
+
+
+class OutOfLineCeil FINAL : public OutOfLineRound {
+ public:
+  OutOfLineCeil(CodeGenerator* gen, DoubleRegister result)
+      : OutOfLineRound(gen, result) {}
+};
+
+}  // namespace
+
+
+#define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr)                         \
+  do {                                                                        \
+    auto result = i.Output##width##Register();                                \
+    auto ool = new (zone()) OutOfLineLoad##width(this, result);               \
+    if (instr->InputAt(0)->IsRegister()) {                                    \
+      auto offset = i.InputRegister(0);                                       \
+      __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
+      __ addu(at, i.InputRegister(2), offset);                                \
+      __ asm_instr(result, MemOperand(at, 0));                                \
+    } else {                                                                  \
+      auto offset = i.InputOperand(0).immediate();                            \
+      __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset));       \
+      __ asm_instr(result, MemOperand(i.InputRegister(2), offset));           \
+    }                                                                         \
+    __ bind(ool->exit());                                                     \
+  } while (0)
+
+
+#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                              \
+  do {                                                                        \
+    auto result = i.OutputRegister();                                         \
+    auto ool = new (zone()) OutOfLineLoadInteger(this, result);               \
+    if (instr->InputAt(0)->IsRegister()) {                                    \
+      auto offset = i.InputRegister(0);                                       \
+      __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
+      __ addu(at, i.InputRegister(2), offset);                                \
+      __ asm_instr(result, MemOperand(at, 0));                                \
+    } else {                                                                  \
+      auto offset = i.InputOperand(0).immediate();                            \
+      __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset));       \
+      __ asm_instr(result, MemOperand(i.InputRegister(2), offset));           \
+    }                                                                         \
+    __ bind(ool->exit());                                                     \
+  } while (0)
+
+
+#define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr)                 \
+  do {                                                                 \
+    Label done;                                                        \
+    if (instr->InputAt(0)->IsRegister()) {                             \
+      auto offset = i.InputRegister(0);                                \
+      auto value = i.Input##width##Register(2);                        \
+      __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
+      __ addu(at, i.InputRegister(3), offset);                         \
+      __ asm_instr(value, MemOperand(at, 0));                          \
+    } else {                                                           \
+      auto offset = i.InputOperand(0).immediate();                     \
+      auto value = i.Input##width##Register(2);                        \
+      __ Branch(&done, ls, i.InputRegister(1), Operand(offset));       \
+      __ asm_instr(value, MemOperand(i.InputRegister(3), offset));     \
+    }                                                                  \
+    __ bind(&done);                                                    \
+  } while (0)
+
+
+#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)                      \
+  do {                                                                 \
+    Label done;                                                        \
+    if (instr->InputAt(0)->IsRegister()) {                             \
+      auto offset = i.InputRegister(0);                                \
+      auto value = i.InputRegister(2);                                 \
+      __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
+      __ addu(at, i.InputRegister(3), offset);                         \
+      __ asm_instr(value, MemOperand(at, 0));                          \
+    } else {                                                           \
+      auto offset = i.InputOperand(0).immediate();                     \
+      auto value = i.InputRegister(2);                                 \
+      __ Branch(&done, ls, i.InputRegister(1), Operand(offset));       \
+      __ asm_instr(value, MemOperand(i.InputRegister(3), offset));     \
+    }                                                                  \
+    __ bind(&done);                                                    \
+  } while (0)
+
+
+#define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(asm_instr, operation)                  \
+  do {                                                                         \
+    auto ool =                                                                 \
+        new (zone()) OutOfLine##operation(this, i.OutputDoubleRegister());     \
+    Label done;                                                                \
+    __ Mfhc1(kScratchReg, i.InputDoubleRegister(0));                           \
+    __ Ext(at, kScratchReg, HeapNumber::kExponentShift,                        \
+           HeapNumber::kExponentBits);                                         \
+    __ Branch(USE_DELAY_SLOT, &done, hs, at,                                   \
+              Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits)); \
+    __ mov_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));              \
+    __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));          \
+    __ Move(at, kScratchReg2, i.OutputDoubleRegister());                       \
+    __ or_(at, at, kScratchReg2);                                              \
+    __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg));        \
+    __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister());            \
+    __ bind(ool->exit());                                                      \
+    __ bind(&done);                                                            \
+  } while (0)
+
+
+// Assembles an instruction after register allocation, producing machine code.
+void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
+  MipsOperandConverter i(this, instr);
+  InstructionCode opcode = instr->opcode();
+
+  switch (ArchOpcodeField::decode(opcode)) {
+    case kArchCallCodeObject: {
+      EnsureSpaceForLazyDeopt();
+      if (instr->InputAt(0)->IsImmediate()) {
+        __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
+                RelocInfo::CODE_TARGET);
+      } else {
+        __ addiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
+        __ Call(at);
+      }
+      AddSafepointAndDeopt(instr);
+      break;
+    }
+    case kArchCallJSFunction: {
+      EnsureSpaceForLazyDeopt();
+      Register func = i.InputRegister(0);
+      if (FLAG_debug_code) {
+        // Check the function's context matches the context argument.
+        __ lw(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
+        __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
+      }
+
+      __ lw(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
+      __ Call(at);
+      AddSafepointAndDeopt(instr);
+      break;
+    }
+    case kArchJmp:
+      AssembleArchJump(i.InputRpo(0));
+      break;
+    case kArchNop:
+      // don't emit code for nops.
+      break;
+    case kArchRet:
+      AssembleReturn();
+      break;
+    case kArchStackPointer:
+      __ mov(i.OutputRegister(), sp);
+      break;
+    case kArchTruncateDoubleToI:
+      __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
+      break;
+    case kMipsAdd:
+      __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMipsAddOvf:
+      __ AdduAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0),
+                                 i.InputOperand(1), kCompareReg, kScratchReg);
+      break;
+    case kMipsSub:
+      __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMipsSubOvf:
+      __ SubuAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0),
+                                 i.InputOperand(1), kCompareReg, kScratchReg);
+      break;
+    case kMipsMul:
+      __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMipsMulHigh:
+      __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMipsMulHighU:
+      __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMipsDiv:
+      __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMipsDivU:
+      __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMipsMod:
+      __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMipsModU:
+      __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMipsAnd:
+      __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMipsOr:
+      __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMipsXor:
+      __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMipsShl:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      } else {
+        int32_t imm = i.InputOperand(1).immediate();
+        __ sll(i.OutputRegister(), i.InputRegister(0), imm);
+      }
+      break;
+    case kMipsShr:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      } else {
+        int32_t imm = i.InputOperand(1).immediate();
+        __ srl(i.OutputRegister(), i.InputRegister(0), imm);
+      }
+      break;
+    case kMipsSar:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      } else {
+        int32_t imm = i.InputOperand(1).immediate();
+        __ sra(i.OutputRegister(), i.InputRegister(0), imm);
+      }
+      break;
+    case kMipsRor:
+      __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMipsTst:
+      // Pseudo-instruction used for tst/branch. No opcode emitted here.
+      break;
+    case kMipsCmp:
+      // Pseudo-instruction used for cmp/branch. No opcode emitted here.
+      break;
+    case kMipsMov:
+      // TODO(plind): Should we combine mov/li like this, or use separate instr?
+      //    - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
+      if (HasRegisterInput(instr, 0)) {
+        __ mov(i.OutputRegister(), i.InputRegister(0));
+      } else {
+        __ li(i.OutputRegister(), i.InputOperand(0));
+      }
+      break;
+
+    case kMipsCmpD:
+      // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
+      break;
+    case kMipsAddD:
+      // TODO(plind): add special case: combine mult & add.
+      __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+               i.InputDoubleRegister(1));
+      break;
+    case kMipsSubD:
+      __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+               i.InputDoubleRegister(1));
+      break;
+    case kMipsMulD:
+      // TODO(plind): add special case: right op is -1.0, see arm port.
+      __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+               i.InputDoubleRegister(1));
+      break;
+    case kMipsDivD:
+      __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+               i.InputDoubleRegister(1));
+      break;
+    case kMipsModD: {
+      // TODO(bmeurer): We should really get rid of this special instruction,
+      // and generate a CallAddress instruction instead.
+      FrameScope scope(masm(), StackFrame::MANUAL);
+      __ PrepareCallCFunction(0, 2, kScratchReg);
+      __ MovToFloatParameters(i.InputDoubleRegister(0),
+                              i.InputDoubleRegister(1));
+      __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
+                       0, 2);
+      // Move the result in the double result register.
+      __ MovFromFloatResult(i.OutputDoubleRegister());
+      break;
+    }
+    case kMipsFloat64Floor: {
+      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(floor_l_d, Floor);
+      break;
+    }
+    case kMipsFloat64Ceil: {
+      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil_l_d, Ceil);
+      break;
+    }
+    case kMipsFloat64RoundTruncate: {
+      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(trunc_l_d, Truncate);
+      break;
+    }
+    case kMipsSqrtD: {
+      __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
+      break;
+    }
+    case kMipsCvtSD: {
+      __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0));
+      break;
+    }
+    case kMipsCvtDS: {
+      __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
+      break;
+    }
+    case kMipsCvtDW: {
+      FPURegister scratch = kScratchDoubleReg;
+      __ mtc1(i.InputRegister(0), scratch);
+      __ cvt_d_w(i.OutputDoubleRegister(), scratch);
+      break;
+    }
+    case kMipsCvtDUw: {
+      FPURegister scratch = kScratchDoubleReg;
+      __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch);
+      break;
+    }
+    case kMipsTruncWD: {
+      FPURegister scratch = kScratchDoubleReg;
+      // Other arches use round to zero here, so we follow.
+      __ trunc_w_d(scratch, i.InputDoubleRegister(0));
+      __ mfc1(i.OutputRegister(), scratch);
+      break;
+    }
+    case kMipsTruncUwD: {
+      FPURegister scratch = kScratchDoubleReg;
+      // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
+      __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
+      break;
+    }
+    // ... more basic instructions ...
+
+    case kMipsLbu:
+      __ lbu(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kMipsLb:
+      __ lb(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kMipsSb:
+      __ sb(i.InputRegister(2), i.MemoryOperand());
+      break;
+    case kMipsLhu:
+      __ lhu(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kMipsLh:
+      __ lh(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kMipsSh:
+      __ sh(i.InputRegister(2), i.MemoryOperand());
+      break;
+    case kMipsLw:
+      __ lw(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kMipsSw:
+      __ sw(i.InputRegister(2), i.MemoryOperand());
+      break;
+    case kMipsLwc1: {
+      __ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
+      break;
+    }
+    case kMipsSwc1: {
+      int index = 0;
+      MemOperand operand = i.MemoryOperand(&index);
+      __ swc1(i.InputSingleRegister(index), operand);
+      break;
+    }
+    case kMipsLdc1:
+      __ ldc1(i.OutputDoubleRegister(), i.MemoryOperand());
+      break;
+    case kMipsSdc1:
+      __ sdc1(i.InputDoubleRegister(2), i.MemoryOperand());
+      break;
+    case kMipsPush:
+      __ Push(i.InputRegister(0));
+      break;
+    case kMipsStackClaim: {
+      int words = MiscField::decode(instr->opcode());
+      __ Subu(sp, sp, Operand(words << kPointerSizeLog2));
+      break;
+    }
+    case kMipsStoreToStackSlot: {
+      int slot = MiscField::decode(instr->opcode());
+      __ sw(i.InputRegister(0), MemOperand(sp, slot << kPointerSizeLog2));
+      break;
+    }
+    case kMipsStoreWriteBarrier: {
+      Register object = i.InputRegister(0);
+      Register index = i.InputRegister(1);
+      Register value = i.InputRegister(2);
+      __ addu(index, object, index);
+      __ sw(value, MemOperand(index));
+      SaveFPRegsMode mode =
+          frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
+      RAStatus ra_status = kRAHasNotBeenSaved;
+      __ RecordWrite(object, index, value, ra_status, mode);
+      break;
+    }
+    case kCheckedLoadInt8:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(lb);
+      break;
+    case kCheckedLoadUint8:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(lbu);
+      break;
+    case kCheckedLoadInt16:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(lh);
+      break;
+    case kCheckedLoadUint16:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(lhu);
+      break;
+    case kCheckedLoadWord32:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(lw);
+      break;
+    case kCheckedLoadFloat32:
+      ASSEMBLE_CHECKED_LOAD_FLOAT(Single, lwc1);
+      break;
+    case kCheckedLoadFloat64:
+      ASSEMBLE_CHECKED_LOAD_FLOAT(Double, ldc1);
+      break;
+    case kCheckedStoreWord8:
+      ASSEMBLE_CHECKED_STORE_INTEGER(sb);
+      break;
+    case kCheckedStoreWord16:
+      ASSEMBLE_CHECKED_STORE_INTEGER(sh);
+      break;
+    case kCheckedStoreWord32:
+      ASSEMBLE_CHECKED_STORE_INTEGER(sw);
+      break;
+    case kCheckedStoreFloat32:
+      ASSEMBLE_CHECKED_STORE_FLOAT(Single, swc1);
+      break;
+    case kCheckedStoreFloat64:
+      ASSEMBLE_CHECKED_STORE_FLOAT(Double, sdc1);
+      break;
+  }
+}
+
+
+#define UNSUPPORTED_COND(opcode, condition)                                  \
+  OFStream out(stdout);                                                      \
+  out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \
+  UNIMPLEMENTED();
+
+// Assembles branches after an instruction.
+void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
+  MipsOperandConverter i(this, instr);
+  Label* tlabel = branch->true_label;
+  Label* flabel = branch->false_label;
+  Condition cc = kNoCondition;
+
+  // MIPS does not have condition code flags, so compare and branch are
+  // implemented differently than on the other arch's. The compare operations
+  // emit mips pseudo-instructions, which are handled here by branch
+  // instructions that do the actual comparison. Essential that the input
+  // registers to compare pseudo-op are not modified before this branch op, as
+  // they are tested here.
+  // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were
+  //    not separated by other instructions.
+
+  if (instr->arch_opcode() == kMipsTst) {
+    switch (branch->condition) {
+      case kNotEqual:
+        cc = ne;
+        break;
+      case kEqual:
+        cc = eq;
+        break;
+      default:
+        UNSUPPORTED_COND(kMipsTst, branch->condition);
+        break;
+    }
+    __ And(at, i.InputRegister(0), i.InputOperand(1));
+    __ Branch(tlabel, cc, at, Operand(zero_reg));
+
+  } else if (instr->arch_opcode() == kMipsAddOvf ||
+             instr->arch_opcode() == kMipsSubOvf) {
+    // kMipsAddOvf, SubOvf emit negative result to 'kCompareReg' on overflow.
+    switch (branch->condition) {
+      case kOverflow:
+        cc = lt;
+        break;
+      case kNotOverflow:
+        cc = ge;
+        break;
+      default:
+        UNSUPPORTED_COND(kMipsAddOvf, branch->condition);
+        break;
+    }
+    __ Branch(tlabel, cc, kCompareReg, Operand(zero_reg));
+
+  } else if (instr->arch_opcode() == kMipsCmp) {
+    switch (branch->condition) {
+      case kEqual:
+        cc = eq;
+        break;
+      case kNotEqual:
+        cc = ne;
+        break;
+      case kSignedLessThan:
+        cc = lt;
+        break;
+      case kSignedGreaterThanOrEqual:
+        cc = ge;
+        break;
+      case kSignedLessThanOrEqual:
+        cc = le;
+        break;
+      case kSignedGreaterThan:
+        cc = gt;
+        break;
+      case kUnsignedLessThan:
+        cc = lo;
+        break;
+      case kUnsignedGreaterThanOrEqual:
+        cc = hs;
+        break;
+      case kUnsignedLessThanOrEqual:
+        cc = ls;
+        break;
+      case kUnsignedGreaterThan:
+        cc = hi;
+        break;
+      default:
+        UNSUPPORTED_COND(kMipsCmp, branch->condition);
+        break;
+    }
+    __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
+
+    if (!branch->fallthru) __ Branch(flabel);  // no fallthru to flabel.
+
+  } else if (instr->arch_opcode() == kMipsCmpD) {
+    // TODO(dusmil) optimize unordered checks to use fewer instructions
+    // even if we have to unfold BranchF macro.
+    Label* nan = flabel;
+    switch (branch->condition) {
+      case kUnorderedEqual:
+        cc = eq;
+        break;
+      case kUnorderedNotEqual:
+        cc = ne;
+        nan = tlabel;
+        break;
+      case kUnorderedLessThan:
+        cc = lt;
+        break;
+      case kUnorderedGreaterThanOrEqual:
+        cc = ge;
+        nan = tlabel;
+        break;
+      case kUnorderedLessThanOrEqual:
+        cc = le;
+        break;
+      case kUnorderedGreaterThan:
+        cc = gt;
+        nan = tlabel;
+        break;
+      default:
+        UNSUPPORTED_COND(kMipsCmpD, branch->condition);
+        break;
+    }
+    __ BranchF(tlabel, nan, cc, i.InputDoubleRegister(0),
+               i.InputDoubleRegister(1));
+
+    if (!branch->fallthru) __ Branch(flabel);  // no fallthru to flabel.
+
+  } else {
+    PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
+           instr->arch_opcode());
+    UNIMPLEMENTED();
+  }
+}
+
+
+void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+  if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
+}
+
+
+// Assembles boolean materializations after an instruction.
+void CodeGenerator::AssembleArchBoolean(Instruction* instr,
+                                        FlagsCondition condition) {
+  MipsOperandConverter i(this, instr);
+  Label done;
+
+  // Materialize a full 32-bit 1 or 0 value. The result register is always the
+  // last output of the instruction.
+  Label false_value;
+  DCHECK_NE(0, instr->OutputCount());
+  Register result = i.OutputRegister(instr->OutputCount() - 1);
+  Condition cc = kNoCondition;
+
+  // MIPS does not have condition code flags, so compare and branch are
+  // implemented differently than on the other arch's. The compare operations
+  // emit mips psuedo-instructions, which are checked and handled here.
+
+  // For materializations, we use delay slot to set the result true, and
+  // in the false case, where we fall thru the branch, we reset the result
+  // false.
+
+  // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were
+  //    not separated by other instructions.
+  if (instr->arch_opcode() == kMipsTst) {
+    switch (condition) {
+      case kNotEqual:
+        cc = ne;
+        break;
+      case kEqual:
+        cc = eq;
+        break;
+      default:
+        UNSUPPORTED_COND(kMipsTst, condition);
+        break;
+    }
+    __ And(at, i.InputRegister(0), i.InputOperand(1));
+    __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg));
+    __ li(result, Operand(1));  // In delay slot.
+
+  } else if (instr->arch_opcode() == kMipsAddOvf ||
+             instr->arch_opcode() == kMipsSubOvf) {
+    // kMipsAddOvf, SubOvf emits negative result to 'kCompareReg' on overflow.
+    switch (condition) {
+      case kOverflow:
+        cc = lt;
+        break;
+      case kNotOverflow:
+        cc = ge;
+        break;
+      default:
+        UNSUPPORTED_COND(kMipsAddOvf, condition);
+        break;
+    }
+    __ Branch(USE_DELAY_SLOT, &done, cc, kCompareReg, Operand(zero_reg));
+    __ li(result, Operand(1));  // In delay slot.
+
+
+  } else if (instr->arch_opcode() == kMipsCmp) {
+    Register left = i.InputRegister(0);
+    Operand right = i.InputOperand(1);
+    switch (condition) {
+      case kEqual:
+        cc = eq;
+        break;
+      case kNotEqual:
+        cc = ne;
+        break;
+      case kSignedLessThan:
+        cc = lt;
+        break;
+      case kSignedGreaterThanOrEqual:
+        cc = ge;
+        break;
+      case kSignedLessThanOrEqual:
+        cc = le;
+        break;
+      case kSignedGreaterThan:
+        cc = gt;
+        break;
+      case kUnsignedLessThan:
+        cc = lo;
+        break;
+      case kUnsignedGreaterThanOrEqual:
+        cc = hs;
+        break;
+      case kUnsignedLessThanOrEqual:
+        cc = ls;
+        break;
+      case kUnsignedGreaterThan:
+        cc = hi;
+        break;
+      default:
+        UNSUPPORTED_COND(kMipsCmp, condition);
+        break;
+    }
+    __ Branch(USE_DELAY_SLOT, &done, cc, left, right);
+    __ li(result, Operand(1));  // In delay slot.
+
+  } else if (instr->arch_opcode() == kMipsCmpD) {
+    FPURegister left = i.InputDoubleRegister(0);
+    FPURegister right = i.InputDoubleRegister(1);
+    // TODO(plind): Provide NaN-testing macro-asm function without need for
+    // BranchF.
+    FPURegister dummy1 = f0;
+    FPURegister dummy2 = f2;
+    switch (condition) {
+      case kUnorderedEqual:
+        // TODO(plind):  improve the NaN testing throughout this function.
+        __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2);
+        cc = eq;
+        break;
+      case kUnorderedNotEqual:
+        __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2);
+        __ li(result, Operand(1));  // In delay slot - returns 1 on NaN.
+        cc = ne;
+        break;
+      case kUnorderedLessThan:
+        __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2);
+        cc = lt;
+        break;
+      case kUnorderedGreaterThanOrEqual:
+        __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2);
+        __ li(result, Operand(1));  // In delay slot - returns 1 on NaN.
+        cc = ge;
+        break;
+      case kUnorderedLessThanOrEqual:
+        __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2);
+        cc = le;
+        break;
+      case kUnorderedGreaterThan:
+        __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2);
+        __ li(result, Operand(1));  // In delay slot - returns 1 on NaN.
+        cc = gt;
+        break;
+      default:
+        UNSUPPORTED_COND(kMipsCmp, condition);
+        break;
+    }
+    __ BranchF(USE_DELAY_SLOT, &done, NULL, cc, left, right);
+    __ li(result, Operand(1));  // In delay slot - branch taken returns 1.
+                                // Fall-thru (branch not taken) returns 0.
+
+  } else {
+    PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n",
+           instr->arch_opcode());
+    TRACE_UNIMPL();
+    UNIMPLEMENTED();
+  }
+  // Fallthru case is the false materialization.
+  __ bind(&false_value);
+  __ li(result, Operand(0));
+  __ bind(&done);
+}
+
+
+void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
+  Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
+      isolate(), deoptimization_id, Deoptimizer::LAZY);
+  __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
+}
+
+
+void CodeGenerator::AssemblePrologue() {
+  CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
+  if (descriptor->kind() == CallDescriptor::kCallAddress) {
+    __ Push(ra, fp);
+    __ mov(fp, sp);
+    const RegList saves = descriptor->CalleeSavedRegisters();
+    if (saves != 0) {  // Save callee-saved registers.
+      // TODO(plind): make callee save size const, possibly DCHECK it.
+      int register_save_area_size = 0;
+      for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
+        if (!((1 << i) & saves)) continue;
+        register_save_area_size += kPointerSize;
+      }
+      frame()->SetRegisterSaveAreaSize(register_save_area_size);
+      __ MultiPush(saves);
+    }
+  } else if (descriptor->IsJSFunctionCall()) {
+    CompilationInfo* info = this->info();
+    __ Prologue(info->IsCodePreAgingActive());
+    frame()->SetRegisterSaveAreaSize(
+        StandardFrameConstants::kFixedFrameSizeFromFp);
+  } else {
+    __ StubPrologue();
+    frame()->SetRegisterSaveAreaSize(
+        StandardFrameConstants::kFixedFrameSizeFromFp);
+  }
+  int stack_slots = frame()->GetSpillSlotCount();
+  if (stack_slots > 0) {
+    __ Subu(sp, sp, Operand(stack_slots * kPointerSize));
+  }
+}
+
+
+void CodeGenerator::AssembleReturn() {
+  CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
+  if (descriptor->kind() == CallDescriptor::kCallAddress) {
+    if (frame()->GetRegisterSaveAreaSize() > 0) {
+      // Remove this frame's spill slots first.
+      int stack_slots = frame()->GetSpillSlotCount();
+      if (stack_slots > 0) {
+        __ Addu(sp, sp, Operand(stack_slots * kPointerSize));
+      }
+      // Restore registers.
+      const RegList saves = descriptor->CalleeSavedRegisters();
+      if (saves != 0) {
+        __ MultiPop(saves);
+      }
+    }
+    __ mov(sp, fp);
+    __ Pop(ra, fp);
+    __ Ret();
+  } else {
+    __ mov(sp, fp);
+    __ Pop(ra, fp);
+    int pop_count = descriptor->IsJSFunctionCall()
+                        ? static_cast<int>(descriptor->JSParameterCount())
+                        : 0;
+    __ DropAndRet(pop_count);
+  }
+}
+
+
+void CodeGenerator::AssembleMove(InstructionOperand* source,
+                                 InstructionOperand* destination) {
+  MipsOperandConverter g(this, NULL);
+  // Dispatch on the source and destination operand kinds.  Not all
+  // combinations are possible.
+  if (source->IsRegister()) {
+    DCHECK(destination->IsRegister() || destination->IsStackSlot());
+    Register src = g.ToRegister(source);
+    if (destination->IsRegister()) {
+      __ mov(g.ToRegister(destination), src);
+    } else {
+      __ sw(src, g.ToMemOperand(destination));
+    }
+  } else if (source->IsStackSlot()) {
+    DCHECK(destination->IsRegister() || destination->IsStackSlot());
+    MemOperand src = g.ToMemOperand(source);
+    if (destination->IsRegister()) {
+      __ lw(g.ToRegister(destination), src);
+    } else {
+      Register temp = kScratchReg;
+      __ lw(temp, src);
+      __ sw(temp, g.ToMemOperand(destination));
+    }
+  } else if (source->IsConstant()) {
+    Constant src = g.ToConstant(source);
+    if (destination->IsRegister() || destination->IsStackSlot()) {
+      Register dst =
+          destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
+      switch (src.type()) {
+        case Constant::kInt32:
+          __ li(dst, Operand(src.ToInt32()));
+          break;
+        case Constant::kFloat32:
+          __ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
+          break;
+        case Constant::kInt64:
+          UNREACHABLE();
+          break;
+        case Constant::kFloat64:
+          __ li(dst, isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
+          break;
+        case Constant::kExternalReference:
+          __ li(dst, Operand(src.ToExternalReference()));
+          break;
+        case Constant::kHeapObject:
+          __ li(dst, src.ToHeapObject());
+          break;
+        case Constant::kRpoNumber:
+          UNREACHABLE();  // TODO(titzer): loading RPO numbers on mips.
+          break;
+      }
+      if (destination->IsStackSlot()) __ sw(dst, g.ToMemOperand(destination));
+    } else if (src.type() == Constant::kFloat32) {
+      if (destination->IsDoubleStackSlot()) {
+        MemOperand dst = g.ToMemOperand(destination);
+        __ li(at, Operand(bit_cast<int32_t>(src.ToFloat32())));
+        __ sw(at, dst);
+      } else {
+        FloatRegister dst = g.ToSingleRegister(destination);
+        __ Move(dst, src.ToFloat32());
+      }
+    } else {
+      DCHECK_EQ(Constant::kFloat64, src.type());
+      DoubleRegister dst = destination->IsDoubleRegister()
+                               ? g.ToDoubleRegister(destination)
+                               : kScratchDoubleReg;
+      __ Move(dst, src.ToFloat64());
+      if (destination->IsDoubleStackSlot()) {
+        __ sdc1(dst, g.ToMemOperand(destination));
+      }
+    }
+  } else if (source->IsDoubleRegister()) {
+    FPURegister src = g.ToDoubleRegister(source);
+    if (destination->IsDoubleRegister()) {
+      FPURegister dst = g.ToDoubleRegister(destination);
+      __ Move(dst, src);
+    } else {
+      DCHECK(destination->IsDoubleStackSlot());
+      __ sdc1(src, g.ToMemOperand(destination));
+    }
+  } else if (source->IsDoubleStackSlot()) {
+    DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
+    MemOperand src = g.ToMemOperand(source);
+    if (destination->IsDoubleRegister()) {
+      __ ldc1(g.ToDoubleRegister(destination), src);
+    } else {
+      FPURegister temp = kScratchDoubleReg;
+      __ ldc1(temp, src);
+      __ sdc1(temp, g.ToMemOperand(destination));
+    }
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+void CodeGenerator::AssembleSwap(InstructionOperand* source,
+                                 InstructionOperand* destination) {
+  MipsOperandConverter g(this, NULL);
+  // Dispatch on the source and destination operand kinds.  Not all
+  // combinations are possible.
+  if (source->IsRegister()) {
+    // Register-register.
+    Register temp = kScratchReg;
+    Register src = g.ToRegister(source);
+    if (destination->IsRegister()) {
+      Register dst = g.ToRegister(destination);
+      __ Move(temp, src);
+      __ Move(src, dst);
+      __ Move(dst, temp);
+    } else {
+      DCHECK(destination->IsStackSlot());
+      MemOperand dst = g.ToMemOperand(destination);
+      __ mov(temp, src);
+      __ lw(src, dst);
+      __ sw(temp, dst);
+    }
+  } else if (source->IsStackSlot()) {
+    DCHECK(destination->IsStackSlot());
+    Register temp_0 = kScratchReg;
+    Register temp_1 = kCompareReg;
+    MemOperand src = g.ToMemOperand(source);
+    MemOperand dst = g.ToMemOperand(destination);
+    __ lw(temp_0, src);
+    __ lw(temp_1, dst);
+    __ sw(temp_0, dst);
+    __ sw(temp_1, src);
+  } else if (source->IsDoubleRegister()) {
+    FPURegister temp = kScratchDoubleReg;
+    FPURegister src = g.ToDoubleRegister(source);
+    if (destination->IsDoubleRegister()) {
+      FPURegister dst = g.ToDoubleRegister(destination);
+      __ Move(temp, src);
+      __ Move(src, dst);
+      __ Move(dst, temp);
+    } else {
+      DCHECK(destination->IsDoubleStackSlot());
+      MemOperand dst = g.ToMemOperand(destination);
+      __ Move(temp, src);
+      __ ldc1(src, dst);
+      __ sdc1(temp, dst);
+    }
+  } else if (source->IsDoubleStackSlot()) {
+    DCHECK(destination->IsDoubleStackSlot());
+    Register temp_0 = kScratchReg;
+    FPURegister temp_1 = kScratchDoubleReg;
+    MemOperand src0 = g.ToMemOperand(source);
+    MemOperand src1(src0.rm(), src0.offset() + kPointerSize);
+    MemOperand dst0 = g.ToMemOperand(destination);
+    MemOperand dst1(dst0.rm(), dst0.offset() + kPointerSize);
+    __ ldc1(temp_1, dst0);  // Save destination in temp_1.
+    __ lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
+    __ sw(temp_0, dst0);
+    __ lw(temp_0, src1);
+    __ sw(temp_0, dst1);
+    __ sdc1(temp_1, src0);
+  } else {
+    // No other combinations are possible.
+    UNREACHABLE();
+  }
+}
+
+
+void CodeGenerator::AddNopForSmiCodeInlining() {
+  // Unused on 32-bit ARM. Still exists on 64-bit arm.
+  // TODO(plind): Unclear when this is called now. Understand, fix if needed.
+  __ nop();  // Maybe PROPERTY_ACCESS_INLINED?
+}
+
+
+void CodeGenerator::EnsureSpaceForLazyDeopt() {
+  int space_needed = Deoptimizer::patch_size();
+  if (!info()->IsStub()) {
+    // Ensure that we have enough space after the previous lazy-bailout
+    // instruction for patching the code here.
+    int current_pc = masm()->pc_offset();
+    if (current_pc < last_lazy_deopt_pc_ + space_needed) {
+      // Block tramoline pool emission for duration of padding.
+      v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
+          masm());
+      int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
+      DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
+      while (padding_size > 0) {
+        __ nop();
+        padding_size -= v8::internal::Assembler::kInstrSize;
+      }
+    }
+  }
+  MarkLazyDeoptSite();
+}
+
+#undef __
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/mips/instruction-codes-mips.h b/src/compiler/mips/instruction-codes-mips.h
new file mode 100644
index 0000000..3aa508f
--- /dev/null
+++ b/src/compiler/mips/instruction-codes-mips.h
@@ -0,0 +1,93 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_MIPS_INSTRUCTION_CODES_MIPS_H_
+#define V8_COMPILER_MIPS_INSTRUCTION_CODES_MIPS_H_
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// MIPS-specific opcodes that specify which assembly sequence to emit.
+// Most opcodes specify a single instruction.
+#define TARGET_ARCH_OPCODE_LIST(V) \
+  V(MipsAdd)                       \
+  V(MipsAddOvf)                    \
+  V(MipsSub)                       \
+  V(MipsSubOvf)                    \
+  V(MipsMul)                       \
+  V(MipsMulHigh)                   \
+  V(MipsMulHighU)                  \
+  V(MipsDiv)                       \
+  V(MipsDivU)                      \
+  V(MipsMod)                       \
+  V(MipsModU)                      \
+  V(MipsAnd)                       \
+  V(MipsOr)                        \
+  V(MipsXor)                       \
+  V(MipsShl)                       \
+  V(MipsShr)                       \
+  V(MipsSar)                       \
+  V(MipsRor)                       \
+  V(MipsMov)                       \
+  V(MipsTst)                       \
+  V(MipsCmp)                       \
+  V(MipsCmpD)                      \
+  V(MipsAddD)                      \
+  V(MipsSubD)                      \
+  V(MipsMulD)                      \
+  V(MipsDivD)                      \
+  V(MipsModD)                      \
+  V(MipsSqrtD)                     \
+  V(MipsFloat64Floor)              \
+  V(MipsFloat64Ceil)               \
+  V(MipsFloat64RoundTruncate)      \
+  V(MipsCvtSD)                     \
+  V(MipsCvtDS)                     \
+  V(MipsTruncWD)                   \
+  V(MipsTruncUwD)                  \
+  V(MipsCvtDW)                     \
+  V(MipsCvtDUw)                    \
+  V(MipsLb)                        \
+  V(MipsLbu)                       \
+  V(MipsSb)                        \
+  V(MipsLh)                        \
+  V(MipsLhu)                       \
+  V(MipsSh)                        \
+  V(MipsLw)                        \
+  V(MipsSw)                        \
+  V(MipsLwc1)                      \
+  V(MipsSwc1)                      \
+  V(MipsLdc1)                      \
+  V(MipsSdc1)                      \
+  V(MipsPush)                      \
+  V(MipsStoreToStackSlot)          \
+  V(MipsStackClaim)                \
+  V(MipsStoreWriteBarrier)
+
+
+// Addressing modes represent the "shape" of inputs to an instruction.
+// Many instructions support multiple addressing modes. Addressing modes
+// are encoded into the InstructionCode of the instruction and tell the
+// code generator after register allocation which assembler method to call.
+//
+// We use the following local notation for addressing modes:
+//
+// R = register
+// O = register or stack slot
+// D = double register
+// I = immediate (handle, external, int32)
+// MRI = [register + immediate]
+// MRR = [register + register]
+// TODO(plind): Add the new r6 address modes.
+#define TARGET_ADDRESSING_MODE_LIST(V) \
+  V(MRI) /* [%r0 + K] */               \
+  V(MRR) /* [%r0 + %r1] */
+
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_MIPS_INSTRUCTION_CODES_MIPS_H_
diff --git a/src/compiler/mips/instruction-selector-mips.cc b/src/compiler/mips/instruction-selector-mips.cc
new file mode 100644
index 0000000..5e8e3b1
--- /dev/null
+++ b/src/compiler/mips/instruction-selector-mips.cc
@@ -0,0 +1,831 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/bits.h"
+#include "src/compiler/instruction-selector-impl.h"
+#include "src/compiler/node-matchers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+#define TRACE_UNIMPL() \
+  PrintF("UNIMPLEMENTED instr_sel: %s at line %d\n", __FUNCTION__, __LINE__)
+
+#define TRACE() PrintF("instr_sel: %s at line %d\n", __FUNCTION__, __LINE__)
+
+
+// Adds Mips-specific methods for generating InstructionOperands.
+class MipsOperandGenerator FINAL : public OperandGenerator {
+ public:
+  explicit MipsOperandGenerator(InstructionSelector* selector)
+      : OperandGenerator(selector) {}
+
+  InstructionOperand* UseOperand(Node* node, InstructionCode opcode) {
+    if (CanBeImmediate(node, opcode)) {
+      return UseImmediate(node);
+    }
+    return UseRegister(node);
+  }
+
+  bool CanBeImmediate(Node* node, InstructionCode opcode) {
+    Int32Matcher m(node);
+    if (!m.HasValue()) return false;
+    int32_t value = m.Value();
+    switch (ArchOpcodeField::decode(opcode)) {
+      case kMipsShl:
+      case kMipsSar:
+      case kMipsShr:
+        return is_uint5(value);
+      case kMipsXor:
+        return is_uint16(value);
+      case kMipsLdc1:
+      case kMipsSdc1:
+      case kCheckedLoadFloat32:
+      case kCheckedLoadFloat64:
+      case kCheckedStoreFloat32:
+      case kCheckedStoreFloat64:
+        return is_int16(value + kIntSize);
+      default:
+        return is_int16(value);
+    }
+  }
+
+ private:
+  bool ImmediateFitsAddrMode1Instruction(int32_t imm) const {
+    TRACE_UNIMPL();
+    return false;
+  }
+};
+
+
+static void VisitRRR(InstructionSelector* selector, ArchOpcode opcode,
+                     Node* node) {
+  MipsOperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsRegister(node),
+                 g.UseRegister(node->InputAt(0)),
+                 g.UseRegister(node->InputAt(1)));
+}
+
+
+static void VisitRR(InstructionSelector* selector, ArchOpcode opcode,
+                    Node* node) {
+  MipsOperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsRegister(node),
+                 g.UseRegister(node->InputAt(0)));
+}
+
+
+static void VisitRRO(InstructionSelector* selector, ArchOpcode opcode,
+                     Node* node) {
+  MipsOperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsRegister(node),
+                 g.UseRegister(node->InputAt(0)),
+                 g.UseOperand(node->InputAt(1), opcode));
+}
+
+
+static void VisitBinop(InstructionSelector* selector, Node* node,
+                       InstructionCode opcode, FlagsContinuation* cont) {
+  MipsOperandGenerator g(selector);
+  Int32BinopMatcher m(node);
+  InstructionOperand* inputs[4];
+  size_t input_count = 0;
+  InstructionOperand* outputs[2];
+  size_t output_count = 0;
+
+  inputs[input_count++] = g.UseRegister(m.left().node());
+  inputs[input_count++] = g.UseOperand(m.right().node(), opcode);
+
+  if (cont->IsBranch()) {
+    inputs[input_count++] = g.Label(cont->true_block());
+    inputs[input_count++] = g.Label(cont->false_block());
+  }
+
+  outputs[output_count++] = g.DefineAsRegister(node);
+  if (cont->IsSet()) {
+    outputs[output_count++] = g.DefineAsRegister(cont->result());
+  }
+
+  DCHECK_NE(0, input_count);
+  DCHECK_NE(0, output_count);
+  DCHECK_GE(arraysize(inputs), input_count);
+  DCHECK_GE(arraysize(outputs), output_count);
+
+  Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
+                                      outputs, input_count, inputs);
+  if (cont->IsBranch()) instr->MarkAsControl();
+}
+
+
+static void VisitBinop(InstructionSelector* selector, Node* node,
+                       InstructionCode opcode) {
+  FlagsContinuation cont;
+  VisitBinop(selector, node, opcode, &cont);
+}
+
+
+void InstructionSelector::VisitLoad(Node* node) {
+  MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
+  MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
+  MipsOperandGenerator g(this);
+  Node* base = node->InputAt(0);
+  Node* index = node->InputAt(1);
+
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepFloat32:
+      opcode = kMipsLwc1;
+      break;
+    case kRepFloat64:
+      opcode = kMipsLdc1;
+      break;
+    case kRepBit:  // Fall through.
+    case kRepWord8:
+      opcode = typ == kTypeUint32 ? kMipsLbu : kMipsLb;
+      break;
+    case kRepWord16:
+      opcode = typ == kTypeUint32 ? kMipsLhu : kMipsLh;
+      break;
+    case kRepTagged:  // Fall through.
+    case kRepWord32:
+      opcode = kMipsLw;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+
+  if (g.CanBeImmediate(index, opcode)) {
+    Emit(opcode | AddressingModeField::encode(kMode_MRI),
+         g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
+  } else {
+    InstructionOperand* addr_reg = g.TempRegister();
+    Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
+         g.UseRegister(index), g.UseRegister(base));
+    // Emit desired load opcode, using temp addr_reg.
+    Emit(opcode | AddressingModeField::encode(kMode_MRI),
+         g.DefineAsRegister(node), addr_reg, g.TempImmediate(0));
+  }
+}
+
+
+void InstructionSelector::VisitStore(Node* node) {
+  MipsOperandGenerator g(this);
+  Node* base = node->InputAt(0);
+  Node* index = node->InputAt(1);
+  Node* value = node->InputAt(2);
+
+  StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
+  MachineType rep = RepresentationOf(store_rep.machine_type());
+  if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
+    DCHECK(rep == kRepTagged);
+    // TODO(dcarney): refactor RecordWrite function to take temp registers
+    //                and pass them here instead of using fixed regs
+    // TODO(dcarney): handle immediate indices.
+    InstructionOperand* temps[] = {g.TempRegister(t1), g.TempRegister(t2)};
+    Emit(kMipsStoreWriteBarrier, NULL, g.UseFixed(base, t0),
+         g.UseFixed(index, t1), g.UseFixed(value, t2), arraysize(temps), temps);
+    return;
+  }
+  DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
+
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepFloat32:
+      opcode = kMipsSwc1;
+      break;
+    case kRepFloat64:
+      opcode = kMipsSdc1;
+      break;
+    case kRepBit:  // Fall through.
+    case kRepWord8:
+      opcode = kMipsSb;
+      break;
+    case kRepWord16:
+      opcode = kMipsSh;
+      break;
+    case kRepTagged:  // Fall through.
+    case kRepWord32:
+      opcode = kMipsSw;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+
+  if (g.CanBeImmediate(index, opcode)) {
+    Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
+         g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
+  } else {
+    InstructionOperand* addr_reg = g.TempRegister();
+    Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg,
+         g.UseRegister(index), g.UseRegister(base));
+    // Emit desired store opcode, using temp addr_reg.
+    Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, addr_reg,
+         g.TempImmediate(0), g.UseRegister(value));
+  }
+}
+
+
+void InstructionSelector::VisitWord32And(Node* node) {
+  VisitBinop(this, node, kMipsAnd);
+}
+
+
+void InstructionSelector::VisitWord32Or(Node* node) {
+  VisitBinop(this, node, kMipsOr);
+}
+
+
+void InstructionSelector::VisitWord32Xor(Node* node) {
+  VisitBinop(this, node, kMipsXor);
+}
+
+
+void InstructionSelector::VisitWord32Shl(Node* node) {
+  VisitRRO(this, kMipsShl, node);
+}
+
+
+void InstructionSelector::VisitWord32Shr(Node* node) {
+  VisitRRO(this, kMipsShr, node);
+}
+
+
+void InstructionSelector::VisitWord32Sar(Node* node) {
+  VisitRRO(this, kMipsSar, node);
+}
+
+
+void InstructionSelector::VisitWord32Ror(Node* node) {
+  VisitRRO(this, kMipsRor, node);
+}
+
+
+void InstructionSelector::VisitInt32Add(Node* node) {
+  MipsOperandGenerator g(this);
+
+  // TODO(plind): Consider multiply & add optimization from arm port.
+  VisitBinop(this, node, kMipsAdd);
+}
+
+
+void InstructionSelector::VisitInt32Sub(Node* node) {
+  VisitBinop(this, node, kMipsSub);
+}
+
+
+void InstructionSelector::VisitInt32Mul(Node* node) {
+  MipsOperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  if (m.right().HasValue() && m.right().Value() > 0) {
+    int32_t value = m.right().Value();
+    if (base::bits::IsPowerOfTwo32(value)) {
+      Emit(kMipsShl | AddressingModeField::encode(kMode_None),
+           g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+           g.TempImmediate(WhichPowerOf2(value)));
+      return;
+    }
+    if (base::bits::IsPowerOfTwo32(value - 1)) {
+      InstructionOperand* temp = g.TempRegister();
+      Emit(kMipsShl | AddressingModeField::encode(kMode_None), temp,
+           g.UseRegister(m.left().node()),
+           g.TempImmediate(WhichPowerOf2(value - 1)));
+      Emit(kMipsAdd | AddressingModeField::encode(kMode_None),
+           g.DefineAsRegister(node), g.UseRegister(m.left().node()), temp);
+      return;
+    }
+    if (base::bits::IsPowerOfTwo32(value + 1)) {
+      InstructionOperand* temp = g.TempRegister();
+      Emit(kMipsShl | AddressingModeField::encode(kMode_None), temp,
+           g.UseRegister(m.left().node()),
+           g.TempImmediate(WhichPowerOf2(value + 1)));
+      Emit(kMipsSub | AddressingModeField::encode(kMode_None),
+           g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
+      return;
+    }
+  }
+  Emit(kMipsMul, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  MipsOperandGenerator g(this);
+  Emit(kMipsMulHigh, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
+       g.UseRegister(node->InputAt(1)));
+}
+
+
+void InstructionSelector::VisitUint32MulHigh(Node* node) {
+  MipsOperandGenerator g(this);
+  Emit(kMipsMulHighU, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
+       g.UseRegister(node->InputAt(1)));
+}
+
+
+void InstructionSelector::VisitInt32Div(Node* node) {
+  MipsOperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  Emit(kMipsDiv, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitUint32Div(Node* node) {
+  MipsOperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  Emit(kMipsDivU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitInt32Mod(Node* node) {
+  MipsOperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  Emit(kMipsMod, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitUint32Mod(Node* node) {
+  MipsOperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  Emit(kMipsModU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
+  MipsOperandGenerator g(this);
+  Emit(kMipsCvtDS, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
+  MipsOperandGenerator g(this);
+  Emit(kMipsCvtDW, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
+  MipsOperandGenerator g(this);
+  Emit(kMipsCvtDUw, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
+  MipsOperandGenerator g(this);
+  Emit(kMipsTruncWD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
+  MipsOperandGenerator g(this);
+  Emit(kMipsTruncUwD, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
+  MipsOperandGenerator g(this);
+  Emit(kMipsCvtSD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64Add(Node* node) {
+  VisitRRR(this, kMipsAddD, node);
+}
+
+
+void InstructionSelector::VisitFloat64Sub(Node* node) {
+  VisitRRR(this, kMipsSubD, node);
+}
+
+
+void InstructionSelector::VisitFloat64Mul(Node* node) {
+  VisitRRR(this, kMipsMulD, node);
+}
+
+
+void InstructionSelector::VisitFloat64Div(Node* node) {
+  VisitRRR(this, kMipsDivD, node);
+}
+
+
+void InstructionSelector::VisitFloat64Mod(Node* node) {
+  MipsOperandGenerator g(this);
+  Emit(kMipsModD, g.DefineAsFixed(node, f0), g.UseFixed(node->InputAt(0), f12),
+       g.UseFixed(node->InputAt(1), f14))->MarkAsCall();
+}
+
+
+void InstructionSelector::VisitFloat64Sqrt(Node* node) {
+  MipsOperandGenerator g(this);
+  Emit(kMipsSqrtD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64Floor(Node* node) {
+  VisitRR(this, kMipsFloat64Floor, node);
+}
+
+
+void InstructionSelector::VisitFloat64Ceil(Node* node) {
+  VisitRR(this, kMipsFloat64Ceil, node);
+}
+
+
+void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
+  VisitRR(this, kMipsFloat64RoundTruncate, node);
+}
+
+
+void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
+  UNREACHABLE();
+}
+
+
+void InstructionSelector::VisitCall(Node* node) {
+  MipsOperandGenerator g(this);
+  const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
+
+  FrameStateDescriptor* frame_state_descriptor = NULL;
+  if (descriptor->NeedsFrameState()) {
+    frame_state_descriptor =
+        GetFrameStateDescriptor(node->InputAt(descriptor->InputCount()));
+  }
+
+  CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
+
+  // Compute InstructionOperands for inputs and outputs.
+  InitializeCallBuffer(node, &buffer, true, false);
+  // Possibly align stack here for functions.
+  int push_count = buffer.pushed_nodes.size();
+  if (push_count > 0) {
+    Emit(kMipsStackClaim | MiscField::encode(push_count), NULL);
+  }
+  int slot = buffer.pushed_nodes.size() - 1;
+  for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
+       input != buffer.pushed_nodes.rend(); input++) {
+    Emit(kMipsStoreToStackSlot | MiscField::encode(slot), NULL,
+         g.UseRegister(*input));
+    slot--;
+  }
+
+  // Select the appropriate opcode based on the call type.
+  InstructionCode opcode;
+  switch (descriptor->kind()) {
+    case CallDescriptor::kCallCodeObject: {
+      opcode = kArchCallCodeObject;
+      break;
+    }
+    case CallDescriptor::kCallJSFunction:
+      opcode = kArchCallJSFunction;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+  opcode |= MiscField::encode(descriptor->flags());
+
+  // Emit the call instruction.
+  InstructionOperand** first_output =
+      buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL;
+  Instruction* call_instr =
+      Emit(opcode, buffer.outputs.size(), first_output,
+           buffer.instruction_args.size(), &buffer.instruction_args.front());
+  call_instr->MarkAsCall();
+}
+
+
+void InstructionSelector::VisitCheckedLoad(Node* node) {
+  MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+  MachineType typ = TypeOf(OpParameter<MachineType>(node));
+  MipsOperandGenerator g(this);
+  Node* const buffer = node->InputAt(0);
+  Node* const offset = node->InputAt(1);
+  Node* const length = node->InputAt(2);
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepWord8:
+      opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8;
+      break;
+    case kRepWord16:
+      opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16;
+      break;
+    case kRepWord32:
+      opcode = kCheckedLoadWord32;
+      break;
+    case kRepFloat32:
+      opcode = kCheckedLoadFloat32;
+      break;
+    case kRepFloat64:
+      opcode = kCheckedLoadFloat64;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+  InstructionOperand* offset_operand = g.CanBeImmediate(offset, opcode)
+                                           ? g.UseImmediate(offset)
+                                           : g.UseRegister(offset);
+
+  InstructionOperand* length_operand =
+      (!g.CanBeImmediate(offset, opcode)) ? g.CanBeImmediate(length, opcode)
+      ? g.UseImmediate(length)
+      : g.UseRegister(length)
+      : g.UseRegister(length);
+
+  Emit(opcode | AddressingModeField::encode(kMode_MRI),
+       g.DefineAsRegister(node), offset_operand, length_operand,
+       g.UseRegister(buffer));
+}
+
+
+void InstructionSelector::VisitCheckedStore(Node* node) {
+  MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+  MipsOperandGenerator g(this);
+  Node* const buffer = node->InputAt(0);
+  Node* const offset = node->InputAt(1);
+  Node* const length = node->InputAt(2);
+  Node* const value = node->InputAt(3);
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepWord8:
+      opcode = kCheckedStoreWord8;
+      break;
+    case kRepWord16:
+      opcode = kCheckedStoreWord16;
+      break;
+    case kRepWord32:
+      opcode = kCheckedStoreWord32;
+      break;
+    case kRepFloat32:
+      opcode = kCheckedStoreFloat32;
+      break;
+    case kRepFloat64:
+      opcode = kCheckedStoreFloat64;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+  InstructionOperand* offset_operand = g.CanBeImmediate(offset, opcode)
+                                           ? g.UseImmediate(offset)
+                                           : g.UseRegister(offset);
+
+  InstructionOperand* length_operand =
+      (!g.CanBeImmediate(offset, opcode)) ? g.CanBeImmediate(length, opcode)
+      ? g.UseImmediate(length)
+      : g.UseRegister(length)
+      : g.UseRegister(length);
+
+  Emit(opcode | AddressingModeField::encode(kMode_MRI), nullptr, offset_operand,
+       length_operand, g.UseRegister(value), g.UseRegister(buffer));
+}
+
+
+namespace {
+
+// Shared routine for multiple compare operations.
+static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
+                         InstructionOperand* left, InstructionOperand* right,
+                         FlagsContinuation* cont) {
+  MipsOperandGenerator g(selector);
+  opcode = cont->Encode(opcode);
+  if (cont->IsBranch()) {
+    selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
+                   g.Label(cont->false_block()))->MarkAsControl();
+  } else {
+    DCHECK(cont->IsSet());
+    // TODO(plind): Revisit and test this path.
+    selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
+  }
+}
+
+
+// Shared routine for multiple float compare operations.
+void VisitFloat64Compare(InstructionSelector* selector, Node* node,
+                         FlagsContinuation* cont) {
+  MipsOperandGenerator g(selector);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  VisitCompare(selector, kMipsCmpD, g.UseRegister(left), g.UseRegister(right),
+               cont);
+}
+
+
+// Shared routine for multiple word compare operations.
+void VisitWordCompare(InstructionSelector* selector, Node* node,
+                      InstructionCode opcode, FlagsContinuation* cont,
+                      bool commutative) {
+  MipsOperandGenerator g(selector);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+
+  // Match immediates on left or right side of comparison.
+  if (g.CanBeImmediate(right, opcode)) {
+    VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
+                 cont);
+  } else if (g.CanBeImmediate(left, opcode)) {
+    if (!commutative) cont->Commute();
+    VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
+                 cont);
+  } else {
+    VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
+                 cont);
+  }
+}
+
+
+void VisitWordCompare(InstructionSelector* selector, Node* node,
+                      FlagsContinuation* cont) {
+  VisitWordCompare(selector, node, kMipsCmp, cont, false);
+}
+
+}  // namespace
+
+
+// Shared routine for word comparisons against zero.
+void VisitWordCompareZero(InstructionSelector* selector, Node* user,
+                          Node* value, FlagsContinuation* cont) {
+  while (selector->CanCover(user, value)) {
+    switch (value->opcode()) {
+      case IrOpcode::kWord32Equal: {
+        // Combine with comparisons against 0 by simply inverting the
+        // continuation.
+        Int32BinopMatcher m(value);
+        if (m.right().Is(0)) {
+          user = value;
+          value = m.left().node();
+          cont->Negate();
+          continue;
+        }
+        cont->OverwriteAndNegateIfEqual(kEqual);
+        return VisitWordCompare(selector, value, cont);
+      }
+      case IrOpcode::kInt32LessThan:
+        cont->OverwriteAndNegateIfEqual(kSignedLessThan);
+        return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kInt32LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
+        return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kUint32LessThan:
+        cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
+        return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kUint32LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
+        return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kFloat64Equal:
+        cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
+        return VisitFloat64Compare(selector, value, cont);
+      case IrOpcode::kFloat64LessThan:
+        cont->OverwriteAndNegateIfEqual(kUnorderedLessThan);
+        return VisitFloat64Compare(selector, value, cont);
+      case IrOpcode::kFloat64LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual);
+        return VisitFloat64Compare(selector, value, cont);
+      case IrOpcode::kProjection:
+        // Check if this is the overflow output projection of an
+        // <Operation>WithOverflow node.
+        if (OpParameter<size_t>(value) == 1u) {
+          // We cannot combine the <Operation>WithOverflow with this branch
+          // unless the 0th projection (the use of the actual value of the
+          // <Operation> is either NULL, which means there's no use of the
+          // actual value, or was already defined, which means it is scheduled
+          // *AFTER* this branch).
+          Node* const node = value->InputAt(0);
+          Node* const result = node->FindProjection(0);
+          if (!result || selector->IsDefined(result)) {
+            switch (node->opcode()) {
+              case IrOpcode::kInt32AddWithOverflow:
+                cont->OverwriteAndNegateIfEqual(kOverflow);
+                return VisitBinop(selector, node, kMipsAddOvf, cont);
+              case IrOpcode::kInt32SubWithOverflow:
+                cont->OverwriteAndNegateIfEqual(kOverflow);
+                return VisitBinop(selector, node, kMipsSubOvf, cont);
+              default:
+                break;
+            }
+          }
+        }
+        break;
+      case IrOpcode::kWord32And:
+        return VisitWordCompare(selector, value, kMipsTst, cont, true);
+      default:
+        break;
+    }
+    break;
+  }
+
+  // Continuation could not be combined with a compare, emit compare against 0.
+  MipsOperandGenerator g(selector);
+  InstructionCode const opcode = cont->Encode(kMipsCmp);
+  InstructionOperand* const value_operand = g.UseRegister(value);
+  if (cont->IsBranch()) {
+    selector->Emit(opcode, nullptr, value_operand, g.TempImmediate(0),
+                   g.Label(cont->true_block()),
+                   g.Label(cont->false_block()))->MarkAsControl();
+  } else {
+    selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
+                   g.TempImmediate(0));
+  }
+}
+
+
+void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
+                                      BasicBlock* fbranch) {
+  FlagsContinuation cont(kNotEqual, tbranch, fbranch);
+  VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
+}
+
+
+void InstructionSelector::VisitWord32Equal(Node* const node) {
+  FlagsContinuation cont(kEqual, node);
+  Int32BinopMatcher m(node);
+  if (m.right().Is(0)) {
+    return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
+  }
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32LessThan(Node* node) {
+  FlagsContinuation cont(kSignedLessThan, node);
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kSignedLessThanOrEqual, node);
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitUint32LessThan(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThan, node);
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
+  VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
+  if (Node* ovf = node->FindProjection(1)) {
+    FlagsContinuation cont(kOverflow, ovf);
+    return VisitBinop(this, node, kMipsAddOvf, &cont);
+  }
+  FlagsContinuation cont;
+  VisitBinop(this, node, kMipsAddOvf, &cont);
+}
+
+
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+  if (Node* ovf = node->FindProjection(1)) {
+    FlagsContinuation cont(kOverflow, ovf);
+    return VisitBinop(this, node, kMipsSubOvf, &cont);
+  }
+  FlagsContinuation cont;
+  VisitBinop(this, node, kMipsSubOvf, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64Equal(Node* node) {
+  FlagsContinuation cont(kUnorderedEqual, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64LessThan(Node* node) {
+  FlagsContinuation cont(kUnorderedLessThan, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnorderedLessThanOrEqual, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+// static
+MachineOperatorBuilder::Flags
+InstructionSelector::SupportedMachineOperatorFlags() {
+  if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    return MachineOperatorBuilder::kFloat64Floor |
+           MachineOperatorBuilder::kFloat64Ceil |
+           MachineOperatorBuilder::kFloat64RoundTruncate;
+  }
+  return MachineOperatorBuilder::kNoFlags;
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/mips/linkage-mips.cc b/src/compiler/mips/linkage-mips.cc
new file mode 100644
index 0000000..2b314a2
--- /dev/null
+++ b/src/compiler/mips/linkage-mips.cc
@@ -0,0 +1,67 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/assembler.h"
+#include "src/code-stubs.h"
+#include "src/compiler/linkage.h"
+#include "src/compiler/linkage-impl.h"
+#include "src/zone.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+struct MipsLinkageHelperTraits {
+  static Register ReturnValueReg() { return v0; }
+  static Register ReturnValue2Reg() { return v1; }
+  static Register JSCallFunctionReg() { return a1; }
+  static Register ContextReg() { return cp; }
+  static Register RuntimeCallFunctionReg() { return a1; }
+  static Register RuntimeCallArgCountReg() { return a0; }
+  static RegList CCalleeSaveRegisters() {
+    return s0.bit() | s1.bit() | s2.bit() | s3.bit() | s4.bit() | s5.bit() |
+           s6.bit() | s7.bit();
+  }
+  static Register CRegisterParameter(int i) {
+    static Register register_parameters[] = {a0, a1, a2, a3};
+    return register_parameters[i];
+  }
+  static int CRegisterParametersLength() { return 4; }
+};
+
+
+typedef LinkageHelper<MipsLinkageHelperTraits> LH;
+
+CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone,
+                                             CallDescriptor::Flags flags) {
+  return LH::GetJSCallDescriptor(zone, parameter_count, flags);
+}
+
+
+CallDescriptor* Linkage::GetRuntimeCallDescriptor(
+    Runtime::FunctionId function, int parameter_count,
+    Operator::Properties properties, Zone* zone) {
+  return LH::GetRuntimeCallDescriptor(zone, function, parameter_count,
+                                      properties);
+}
+
+
+CallDescriptor* Linkage::GetStubCallDescriptor(
+    const CallInterfaceDescriptor& descriptor, int stack_parameter_count,
+    CallDescriptor::Flags flags, Operator::Properties properties, Zone* zone) {
+  return LH::GetStubCallDescriptor(zone, descriptor, stack_parameter_count,
+                                   flags, properties);
+}
+
+
+CallDescriptor* Linkage::GetSimplifiedCDescriptor(Zone* zone,
+                                                  MachineSignature* sig) {
+  return LH::GetSimplifiedCDescriptor(zone, sig);
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/mips64/OWNERS b/src/compiler/mips64/OWNERS
new file mode 100644
index 0000000..5508ba6
--- /dev/null
+++ b/src/compiler/mips64/OWNERS
@@ -0,0 +1,5 @@
+paul.lind@imgtec.com
+gergely.kis@imgtec.com
+akos.palfi@imgtec.com
+balazs.kilvady@imgtec.com
+dusan.milosavljevic@imgtec.com
diff --git a/src/compiler/mips64/code-generator-mips64.cc b/src/compiler/mips64/code-generator-mips64.cc
new file mode 100644
index 0000000..dee7705
--- /dev/null
+++ b/src/compiler/mips64/code-generator-mips64.cc
@@ -0,0 +1,1444 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/code-generator.h"
+#include "src/compiler/code-generator-impl.h"
+#include "src/compiler/gap-resolver.h"
+#include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/mips/macro-assembler-mips.h"
+#include "src/scopes.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+#define __ masm()->
+
+
+// TODO(plind): Possibly avoid using these lithium names.
+#define kScratchReg kLithiumScratchReg
+#define kScratchReg2 kLithiumScratchReg2
+#define kScratchDoubleReg kLithiumScratchDouble
+
+
+// TODO(plind): consider renaming these macros.
+#define TRACE_MSG(msg)                                                      \
+  PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \
+         __LINE__)
+
+#define TRACE_UNIMPL()                                                       \
+  PrintF("UNIMPLEMENTED code_generator_mips: %s at line %d\n", __FUNCTION__, \
+         __LINE__)
+
+
+// Adds Mips-specific methods to convert InstructionOperands.
+class MipsOperandConverter FINAL : public InstructionOperandConverter {
+ public:
+  MipsOperandConverter(CodeGenerator* gen, Instruction* instr)
+      : InstructionOperandConverter(gen, instr) {}
+
+  FloatRegister OutputSingleRegister(int index = 0) {
+    return ToSingleRegister(instr_->OutputAt(index));
+  }
+
+  FloatRegister InputSingleRegister(int index) {
+    return ToSingleRegister(instr_->InputAt(index));
+  }
+
+  FloatRegister ToSingleRegister(InstructionOperand* op) {
+    // Single (Float) and Double register namespace is same on MIPS,
+    // both are typedefs of FPURegister.
+    return ToDoubleRegister(op);
+  }
+
+  Operand InputImmediate(int index) {
+    Constant constant = ToConstant(instr_->InputAt(index));
+    switch (constant.type()) {
+      case Constant::kInt32:
+        return Operand(constant.ToInt32());
+      case Constant::kInt64:
+        return Operand(constant.ToInt64());
+      case Constant::kFloat32:
+        return Operand(
+            isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
+      case Constant::kFloat64:
+        return Operand(
+            isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
+      case Constant::kExternalReference:
+      case Constant::kHeapObject:
+        // TODO(plind): Maybe we should handle ExtRef & HeapObj here?
+        //    maybe not done on arm due to const pool ??
+        break;
+      case Constant::kRpoNumber:
+        UNREACHABLE();  // TODO(titzer): RPO immediates on mips?
+        break;
+    }
+    UNREACHABLE();
+    return Operand(zero_reg);
+  }
+
+  Operand InputOperand(int index) {
+    InstructionOperand* op = instr_->InputAt(index);
+    if (op->IsRegister()) {
+      return Operand(ToRegister(op));
+    }
+    return InputImmediate(index);
+  }
+
+  MemOperand MemoryOperand(int* first_index) {
+    const int index = *first_index;
+    switch (AddressingModeField::decode(instr_->opcode())) {
+      case kMode_None:
+        break;
+      case kMode_MRI:
+        *first_index += 2;
+        return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
+      case kMode_MRR:
+        // TODO(plind): r6 address mode, to be implemented ...
+        UNREACHABLE();
+    }
+    UNREACHABLE();
+    return MemOperand(no_reg);
+  }
+
+  MemOperand MemoryOperand(int index = 0) { return MemoryOperand(&index); }
+
+  MemOperand ToMemOperand(InstructionOperand* op) const {
+    DCHECK(op != NULL);
+    DCHECK(!op->IsRegister());
+    DCHECK(!op->IsDoubleRegister());
+    DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
+    // The linkage computes where all spill slots are located.
+    FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
+    return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
+  }
+};
+
+
+static inline bool HasRegisterInput(Instruction* instr, int index) {
+  return instr->InputAt(index)->IsRegister();
+}
+
+
+namespace {
+
+class OutOfLineLoadSingle FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL {
+    __ Move(result_, std::numeric_limits<float>::quiet_NaN());
+  }
+
+ private:
+  FloatRegister const result_;
+};
+
+
+class OutOfLineLoadDouble FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadDouble(CodeGenerator* gen, DoubleRegister result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL {
+    __ Move(result_, std::numeric_limits<double>::quiet_NaN());
+  }
+
+ private:
+  DoubleRegister const result_;
+};
+
+
+class OutOfLineLoadInteger FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadInteger(CodeGenerator* gen, Register result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL { __ mov(result_, zero_reg); }
+
+ private:
+  Register const result_;
+};
+
+
+class OutOfLineRound : public OutOfLineCode {
+ public:
+  OutOfLineRound(CodeGenerator* gen, DoubleRegister result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL {
+    // Handle rounding to zero case where sign has to be preserved.
+    // High bits of double input already in kScratchReg.
+    __ dsrl(at, kScratchReg, 31);
+    __ dsll(at, at, 31);
+    __ mthc1(at, result_);
+  }
+
+ private:
+  DoubleRegister const result_;
+};
+
+
+class OutOfLineTruncate FINAL : public OutOfLineRound {
+ public:
+  OutOfLineTruncate(CodeGenerator* gen, DoubleRegister result)
+      : OutOfLineRound(gen, result) {}
+};
+
+
+class OutOfLineFloor FINAL : public OutOfLineRound {
+ public:
+  OutOfLineFloor(CodeGenerator* gen, DoubleRegister result)
+      : OutOfLineRound(gen, result) {}
+};
+
+
+class OutOfLineCeil FINAL : public OutOfLineRound {
+ public:
+  OutOfLineCeil(CodeGenerator* gen, DoubleRegister result)
+      : OutOfLineRound(gen, result) {}
+};
+
+
+}  // namespace
+
+
+#define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr)                         \
+  do {                                                                        \
+    auto result = i.Output##width##Register();                                \
+    auto ool = new (zone()) OutOfLineLoad##width(this, result);               \
+    if (instr->InputAt(0)->IsRegister()) {                                    \
+      auto offset = i.InputRegister(0);                                       \
+      __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
+      __ Daddu(at, i.InputRegister(2), offset);                               \
+      __ asm_instr(result, MemOperand(at, 0));                                \
+    } else {                                                                  \
+      auto offset = i.InputOperand(0).immediate();                            \
+      __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset));       \
+      __ asm_instr(result, MemOperand(i.InputRegister(2), offset));           \
+    }                                                                         \
+    __ bind(ool->exit());                                                     \
+  } while (0)
+
+
+#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                              \
+  do {                                                                        \
+    auto result = i.OutputRegister();                                         \
+    auto ool = new (zone()) OutOfLineLoadInteger(this, result);               \
+    if (instr->InputAt(0)->IsRegister()) {                                    \
+      auto offset = i.InputRegister(0);                                       \
+      __ Branch(USE_DELAY_SLOT, ool->entry(), hs, offset, i.InputOperand(1)); \
+      __ Daddu(at, i.InputRegister(2), offset);                               \
+      __ asm_instr(result, MemOperand(at, 0));                                \
+    } else {                                                                  \
+      auto offset = i.InputOperand(0).immediate();                            \
+      __ Branch(ool->entry(), ls, i.InputRegister(1), Operand(offset));       \
+      __ asm_instr(result, MemOperand(i.InputRegister(2), offset));           \
+    }                                                                         \
+    __ bind(ool->exit());                                                     \
+  } while (0)
+
+
+#define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr)                 \
+  do {                                                                 \
+    Label done;                                                        \
+    if (instr->InputAt(0)->IsRegister()) {                             \
+      auto offset = i.InputRegister(0);                                \
+      auto value = i.Input##width##Register(2);                        \
+      __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
+      __ Daddu(at, i.InputRegister(3), offset);                        \
+      __ asm_instr(value, MemOperand(at, 0));                          \
+    } else {                                                           \
+      auto offset = i.InputOperand(0).immediate();                     \
+      auto value = i.Input##width##Register(2);                        \
+      __ Branch(&done, ls, i.InputRegister(1), Operand(offset));       \
+      __ asm_instr(value, MemOperand(i.InputRegister(3), offset));     \
+    }                                                                  \
+    __ bind(&done);                                                    \
+  } while (0)
+
+
+#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)                      \
+  do {                                                                 \
+    Label done;                                                        \
+    if (instr->InputAt(0)->IsRegister()) {                             \
+      auto offset = i.InputRegister(0);                                \
+      auto value = i.InputRegister(2);                                 \
+      __ Branch(USE_DELAY_SLOT, &done, hs, offset, i.InputOperand(1)); \
+      __ Daddu(at, i.InputRegister(3), offset);                        \
+      __ asm_instr(value, MemOperand(at, 0));                          \
+    } else {                                                           \
+      auto offset = i.InputOperand(0).immediate();                     \
+      auto value = i.InputRegister(2);                                 \
+      __ Branch(&done, ls, i.InputRegister(1), Operand(offset));       \
+      __ asm_instr(value, MemOperand(i.InputRegister(3), offset));     \
+    }                                                                  \
+    __ bind(&done);                                                    \
+  } while (0)
+
+
+#define ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(asm_instr, operation)                  \
+  do {                                                                         \
+    auto ool =                                                                 \
+        new (zone()) OutOfLine##operation(this, i.OutputDoubleRegister());     \
+    Label done;                                                                \
+    __ mfhc1(kScratchReg, i.InputDoubleRegister(0));                           \
+    __ Ext(at, kScratchReg, HeapNumber::kExponentShift,                        \
+           HeapNumber::kExponentBits);                                         \
+    __ Branch(USE_DELAY_SLOT, &done, hs, at,                                   \
+              Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits)); \
+    __ mov_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));              \
+    __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));          \
+    __ dmfc1(at, i.OutputDoubleRegister());                                    \
+    __ Branch(USE_DELAY_SLOT, ool->entry(), eq, at, Operand(zero_reg));        \
+    __ cvt_d_l(i.OutputDoubleRegister(), i.OutputDoubleRegister());            \
+    __ bind(ool->exit());                                                      \
+    __ bind(&done);                                                            \
+  } while (0)
+
+
+// Assembles an instruction after register allocation, producing machine code.
+void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
+  MipsOperandConverter i(this, instr);
+  InstructionCode opcode = instr->opcode();
+
+  switch (ArchOpcodeField::decode(opcode)) {
+    case kArchCallCodeObject: {
+      EnsureSpaceForLazyDeopt();
+      if (instr->InputAt(0)->IsImmediate()) {
+        __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
+                RelocInfo::CODE_TARGET);
+      } else {
+        __ daddiu(at, i.InputRegister(0), Code::kHeaderSize - kHeapObjectTag);
+        __ Call(at);
+      }
+      AddSafepointAndDeopt(instr);
+      break;
+    }
+    case kArchCallJSFunction: {
+      EnsureSpaceForLazyDeopt();
+      Register func = i.InputRegister(0);
+      if (FLAG_debug_code) {
+        // Check the function's context matches the context argument.
+        __ ld(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
+        __ Assert(eq, kWrongFunctionContext, cp, Operand(kScratchReg));
+      }
+
+      __ ld(at, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
+      __ Call(at);
+      AddSafepointAndDeopt(instr);
+      break;
+    }
+    case kArchJmp:
+      AssembleArchJump(i.InputRpo(0));
+      break;
+    case kArchNop:
+      // don't emit code for nops.
+      break;
+    case kArchRet:
+      AssembleReturn();
+      break;
+    case kArchStackPointer:
+      __ mov(i.OutputRegister(), sp);
+      break;
+    case kArchTruncateDoubleToI:
+      __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
+      break;
+    case kMips64Add:
+      __ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64Dadd:
+      __ Daddu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64Sub:
+      __ Subu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64Dsub:
+      __ Dsubu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64Mul:
+      __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64MulHigh:
+      __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64MulHighU:
+      __ Mulhu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64Div:
+      __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64DivU:
+      __ Divu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64Mod:
+      __ Mod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64ModU:
+      __ Modu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64Dmul:
+      __ Dmul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64Ddiv:
+      __ Ddiv(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64DdivU:
+      __ Ddivu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64Dmod:
+      __ Dmod(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64DmodU:
+      __ Dmodu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+      __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64And:
+      __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64Or:
+      __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64Xor:
+      __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64Shl:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      } else {
+        int32_t imm = i.InputOperand(1).immediate();
+        __ sll(i.OutputRegister(), i.InputRegister(0), imm);
+      }
+      break;
+    case kMips64Shr:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ srlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      } else {
+        int32_t imm = i.InputOperand(1).immediate();
+        __ srl(i.OutputRegister(), i.InputRegister(0), imm);
+      }
+      break;
+    case kMips64Sar:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ srav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      } else {
+        int32_t imm = i.InputOperand(1).immediate();
+        __ sra(i.OutputRegister(), i.InputRegister(0), imm);
+      }
+      break;
+    case kMips64Ext:
+      __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
+             i.InputInt8(2));
+      break;
+    case kMips64Dext:
+      __ Dext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
+              i.InputInt8(2));
+      break;
+    case kMips64Dshl:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ dsllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      } else {
+        int32_t imm = i.InputOperand(1).immediate();
+        if (imm < 32) {
+          __ dsll(i.OutputRegister(), i.InputRegister(0), imm);
+        } else {
+          __ dsll32(i.OutputRegister(), i.InputRegister(0), imm - 32);
+        }
+      }
+      break;
+    case kMips64Dshr:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ dsrlv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      } else {
+        int32_t imm = i.InputOperand(1).immediate();
+        if (imm < 32) {
+          __ dsrl(i.OutputRegister(), i.InputRegister(0), imm);
+        } else {
+          __ dsrl32(i.OutputRegister(), i.InputRegister(0), imm - 32);
+        }
+      }
+      break;
+    case kMips64Dsar:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ dsrav(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      } else {
+        int32_t imm = i.InputOperand(1).immediate();
+        if (imm < 32) {
+          __ dsra(i.OutputRegister(), i.InputRegister(0), imm);
+        } else {
+          __ dsra32(i.OutputRegister(), i.InputRegister(0), imm - 32);
+        }
+      }
+      break;
+    case kMips64Ror:
+      __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64Dror:
+      __ Dror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kMips64Tst:
+    case kMips64Tst32:
+      // Pseudo-instruction used for cmp/branch. No opcode emitted here.
+      break;
+    case kMips64Cmp:
+    case kMips64Cmp32:
+      // Pseudo-instruction used for cmp/branch. No opcode emitted here.
+      break;
+    case kMips64Mov:
+      // TODO(plind): Should we combine mov/li like this, or use separate instr?
+      //    - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
+      if (HasRegisterInput(instr, 0)) {
+        __ mov(i.OutputRegister(), i.InputRegister(0));
+      } else {
+        __ li(i.OutputRegister(), i.InputOperand(0));
+      }
+      break;
+
+    case kMips64CmpD:
+      // Psuedo-instruction used for FP cmp/branch. No opcode emitted here.
+      break;
+    case kMips64AddD:
+      // TODO(plind): add special case: combine mult & add.
+      __ add_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+               i.InputDoubleRegister(1));
+      break;
+    case kMips64SubD:
+      __ sub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+               i.InputDoubleRegister(1));
+      break;
+    case kMips64MulD:
+      // TODO(plind): add special case: right op is -1.0, see arm port.
+      __ mul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+               i.InputDoubleRegister(1));
+      break;
+    case kMips64DivD:
+      __ div_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+               i.InputDoubleRegister(1));
+      break;
+    case kMips64ModD: {
+      // TODO(bmeurer): We should really get rid of this special instruction,
+      // and generate a CallAddress instruction instead.
+      FrameScope scope(masm(), StackFrame::MANUAL);
+      __ PrepareCallCFunction(0, 2, kScratchReg);
+      __ MovToFloatParameters(i.InputDoubleRegister(0),
+                              i.InputDoubleRegister(1));
+      __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
+                       0, 2);
+      // Move the result in the double result register.
+      __ MovFromFloatResult(i.OutputDoubleRegister());
+      break;
+    }
+    case kMips64Float64Floor: {
+      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(floor_l_d, Floor);
+      break;
+    }
+    case kMips64Float64Ceil: {
+      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(ceil_l_d, Ceil);
+      break;
+    }
+    case kMips64Float64RoundTruncate: {
+      ASSEMBLE_ROUND_DOUBLE_TO_DOUBLE(trunc_l_d, Truncate);
+      break;
+    }
+    case kMips64SqrtD: {
+      __ sqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
+      break;
+    }
+    case kMips64CvtSD: {
+      __ cvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0));
+      break;
+    }
+    case kMips64CvtDS: {
+      __ cvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
+      break;
+    }
+    case kMips64CvtDW: {
+      FPURegister scratch = kScratchDoubleReg;
+      __ mtc1(i.InputRegister(0), scratch);
+      __ cvt_d_w(i.OutputDoubleRegister(), scratch);
+      break;
+    }
+    case kMips64CvtDUw: {
+      FPURegister scratch = kScratchDoubleReg;
+      __ Cvt_d_uw(i.OutputDoubleRegister(), i.InputRegister(0), scratch);
+      break;
+    }
+    case kMips64TruncWD: {
+      FPURegister scratch = kScratchDoubleReg;
+      // Other arches use round to zero here, so we follow.
+      __ trunc_w_d(scratch, i.InputDoubleRegister(0));
+      __ mfc1(i.OutputRegister(), scratch);
+      break;
+    }
+    case kMips64TruncUwD: {
+      FPURegister scratch = kScratchDoubleReg;
+      // TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
+      __ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
+      break;
+    }
+    // ... more basic instructions ...
+
+    case kMips64Lbu:
+      __ lbu(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kMips64Lb:
+      __ lb(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kMips64Sb:
+      __ sb(i.InputRegister(2), i.MemoryOperand());
+      break;
+    case kMips64Lhu:
+      __ lhu(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kMips64Lh:
+      __ lh(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kMips64Sh:
+      __ sh(i.InputRegister(2), i.MemoryOperand());
+      break;
+    case kMips64Lw:
+      __ lw(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kMips64Ld:
+      __ ld(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kMips64Sw:
+      __ sw(i.InputRegister(2), i.MemoryOperand());
+      break;
+    case kMips64Sd:
+      __ sd(i.InputRegister(2), i.MemoryOperand());
+      break;
+    case kMips64Lwc1: {
+      __ lwc1(i.OutputSingleRegister(), i.MemoryOperand());
+      break;
+    }
+    case kMips64Swc1: {
+      int index = 0;
+      MemOperand operand = i.MemoryOperand(&index);
+      __ swc1(i.InputSingleRegister(index), operand);
+      break;
+    }
+    case kMips64Ldc1:
+      __ ldc1(i.OutputDoubleRegister(), i.MemoryOperand());
+      break;
+    case kMips64Sdc1:
+      __ sdc1(i.InputDoubleRegister(2), i.MemoryOperand());
+      break;
+    case kMips64Push:
+      __ Push(i.InputRegister(0));
+      break;
+    case kMips64StackClaim: {
+      int words = MiscField::decode(instr->opcode());
+      __ Dsubu(sp, sp, Operand(words << kPointerSizeLog2));
+      break;
+    }
+    case kMips64StoreToStackSlot: {
+      int slot = MiscField::decode(instr->opcode());
+      __ sd(i.InputRegister(0), MemOperand(sp, slot << kPointerSizeLog2));
+      break;
+    }
+    case kMips64StoreWriteBarrier: {
+      Register object = i.InputRegister(0);
+      Register index = i.InputRegister(1);
+      Register value = i.InputRegister(2);
+      __ daddu(index, object, index);
+      __ sd(value, MemOperand(index));
+      SaveFPRegsMode mode =
+          frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
+      RAStatus ra_status = kRAHasNotBeenSaved;
+      __ RecordWrite(object, index, value, ra_status, mode);
+      break;
+    }
+    case kCheckedLoadInt8:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(lb);
+      break;
+    case kCheckedLoadUint8:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(lbu);
+      break;
+    case kCheckedLoadInt16:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(lh);
+      break;
+    case kCheckedLoadUint16:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(lhu);
+      break;
+    case kCheckedLoadWord32:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(lw);
+      break;
+    case kCheckedLoadFloat32:
+      ASSEMBLE_CHECKED_LOAD_FLOAT(Single, lwc1);
+      break;
+    case kCheckedLoadFloat64:
+      ASSEMBLE_CHECKED_LOAD_FLOAT(Double, ldc1);
+      break;
+    case kCheckedStoreWord8:
+      ASSEMBLE_CHECKED_STORE_INTEGER(sb);
+      break;
+    case kCheckedStoreWord16:
+      ASSEMBLE_CHECKED_STORE_INTEGER(sh);
+      break;
+    case kCheckedStoreWord32:
+      ASSEMBLE_CHECKED_STORE_INTEGER(sw);
+      break;
+    case kCheckedStoreFloat32:
+      ASSEMBLE_CHECKED_STORE_FLOAT(Single, swc1);
+      break;
+    case kCheckedStoreFloat64:
+      ASSEMBLE_CHECKED_STORE_FLOAT(Double, sdc1);
+      break;
+  }
+}
+
+
+#define UNSUPPORTED_COND(opcode, condition)                                  \
+  OFStream out(stdout);                                                      \
+  out << "Unsupported " << #opcode << " condition: \"" << condition << "\""; \
+  UNIMPLEMENTED();
+
+// Assembles branches after an instruction.
+void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
+  MipsOperandConverter i(this, instr);
+  Label* tlabel = branch->true_label;
+  Label* flabel = branch->false_label;
+  Condition cc = kNoCondition;
+
+  // MIPS does not have condition code flags, so compare and branch are
+  // implemented differently than on the other arch's. The compare operations
+  // emit mips psuedo-instructions, which are handled here by branch
+  // instructions that do the actual comparison. Essential that the input
+  // registers to compare psuedo-op are not modified before this branch op, as
+  // they are tested here.
+  // TODO(plind): Add CHECK() to ensure that test/cmp and this branch were
+  //    not separated by other instructions.
+
+  if (instr->arch_opcode() == kMips64Tst) {
+    switch (branch->condition) {
+      case kNotEqual:
+        cc = ne;
+        break;
+      case kEqual:
+        cc = eq;
+        break;
+      default:
+        UNSUPPORTED_COND(kMips64Tst, branch->condition);
+        break;
+    }
+    __ And(at, i.InputRegister(0), i.InputOperand(1));
+    __ Branch(tlabel, cc, at, Operand(zero_reg));
+  } else if (instr->arch_opcode() == kMips64Tst32) {
+    switch (branch->condition) {
+      case kNotEqual:
+        cc = ne;
+        break;
+      case kEqual:
+        cc = eq;
+        break;
+      default:
+        UNSUPPORTED_COND(kMips64Tst32, branch->condition);
+        break;
+    }
+    // Zero-extend registers on MIPS64 only 64-bit operand
+    // branch and compare op. is available.
+    // This is a disadvantage to perform 32-bit operation on MIPS64.
+    // Try to force globally in front-end Word64 representation to be preferred
+    // for MIPS64 even for Word32.
+    __ And(at, i.InputRegister(0), i.InputOperand(1));
+    __ Dext(at, at, 0, 32);
+    __ Branch(tlabel, cc, at, Operand(zero_reg));
+  } else if (instr->arch_opcode() == kMips64Dadd ||
+             instr->arch_opcode() == kMips64Dsub) {
+    switch (branch->condition) {
+      case kOverflow:
+        cc = ne;
+        break;
+      case kNotOverflow:
+        cc = eq;
+        break;
+      default:
+        UNSUPPORTED_COND(kMips64Dadd, branch->condition);
+        break;
+    }
+
+    __ dsra32(kScratchReg, i.OutputRegister(), 0);
+    __ sra(at, i.OutputRegister(), 31);
+    __ Branch(tlabel, cc, at, Operand(kScratchReg));
+  } else if (instr->arch_opcode() == kMips64Cmp) {
+    switch (branch->condition) {
+      case kEqual:
+        cc = eq;
+        break;
+      case kNotEqual:
+        cc = ne;
+        break;
+      case kSignedLessThan:
+        cc = lt;
+        break;
+      case kSignedGreaterThanOrEqual:
+        cc = ge;
+        break;
+      case kSignedLessThanOrEqual:
+        cc = le;
+        break;
+      case kSignedGreaterThan:
+        cc = gt;
+        break;
+      case kUnsignedLessThan:
+        cc = lo;
+        break;
+      case kUnsignedGreaterThanOrEqual:
+        cc = hs;
+        break;
+      case kUnsignedLessThanOrEqual:
+        cc = ls;
+        break;
+      case kUnsignedGreaterThan:
+        cc = hi;
+        break;
+      default:
+        UNSUPPORTED_COND(kMips64Cmp, branch->condition);
+        break;
+    }
+    __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
+
+    if (!branch->fallthru) __ Branch(flabel);  // no fallthru to flabel.
+
+  } else if (instr->arch_opcode() == kMips64Cmp32) {
+    switch (branch->condition) {
+      case kEqual:
+        cc = eq;
+        break;
+      case kNotEqual:
+        cc = ne;
+        break;
+      case kSignedLessThan:
+        cc = lt;
+        break;
+      case kSignedGreaterThanOrEqual:
+        cc = ge;
+        break;
+      case kSignedLessThanOrEqual:
+        cc = le;
+        break;
+      case kSignedGreaterThan:
+        cc = gt;
+        break;
+      case kUnsignedLessThan:
+        cc = lo;
+        break;
+      case kUnsignedGreaterThanOrEqual:
+        cc = hs;
+        break;
+      case kUnsignedLessThanOrEqual:
+        cc = ls;
+        break;
+      case kUnsignedGreaterThan:
+        cc = hi;
+        break;
+      default:
+        UNSUPPORTED_COND(kMips64Cmp32, branch->condition);
+        break;
+    }
+
+    switch (branch->condition) {
+      case kEqual:
+      case kNotEqual:
+      case kSignedLessThan:
+      case kSignedGreaterThanOrEqual:
+      case kSignedLessThanOrEqual:
+      case kSignedGreaterThan:
+        // Sign-extend registers on MIPS64 only 64-bit operand
+        // branch and compare op. is available.
+        __ sll(i.InputRegister(0), i.InputRegister(0), 0);
+        if (instr->InputAt(1)->IsRegister()) {
+          __ sll(i.InputRegister(1), i.InputRegister(1), 0);
+        }
+        break;
+      case kUnsignedLessThan:
+      case kUnsignedGreaterThanOrEqual:
+      case kUnsignedLessThanOrEqual:
+      case kUnsignedGreaterThan:
+        // Zero-extend registers on MIPS64 only 64-bit operand
+        // branch and compare op. is available.
+        __ Dext(i.InputRegister(0), i.InputRegister(0), 0, 32);
+        if (instr->InputAt(1)->IsRegister()) {
+          __ Dext(i.InputRegister(1), i.InputRegister(1), 0, 32);
+        }
+        break;
+      default:
+        UNSUPPORTED_COND(kMips64Cmp, branch->condition);
+        break;
+    }
+    __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
+
+    if (!branch->fallthru) __ Branch(flabel);  // no fallthru to flabel.
+  } else if (instr->arch_opcode() == kMips64CmpD) {
+    // TODO(dusmil) optimize unordered checks to use less instructions
+    // even if we have to unfold BranchF macro.
+    Label* nan = flabel;
+    switch (branch->condition) {
+      case kUnorderedEqual:
+        cc = eq;
+        break;
+      case kUnorderedNotEqual:
+        cc = ne;
+        nan = tlabel;
+        break;
+      case kUnorderedLessThan:
+        cc = lt;
+        break;
+      case kUnorderedGreaterThanOrEqual:
+        cc = ge;
+        nan = tlabel;
+        break;
+      case kUnorderedLessThanOrEqual:
+        cc = le;
+        break;
+      case kUnorderedGreaterThan:
+        cc = gt;
+        nan = tlabel;
+        break;
+      default:
+        UNSUPPORTED_COND(kMips64CmpD, branch->condition);
+        break;
+    }
+    __ BranchF(tlabel, nan, cc, i.InputDoubleRegister(0),
+               i.InputDoubleRegister(1));
+
+    if (!branch->fallthru) __ Branch(flabel);  // no fallthru to flabel.
+  } else {
+    PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
+           instr->arch_opcode());
+    UNIMPLEMENTED();
+  }
+}
+
+
+void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+  if (!IsNextInAssemblyOrder(target)) __ Branch(GetLabel(target));
+}
+
+
+// Assembles boolean materializations after an instruction.
+void CodeGenerator::AssembleArchBoolean(Instruction* instr,
+                                        FlagsCondition condition) {
+  MipsOperandConverter i(this, instr);
+  Label done;
+
+  // Materialize a full 32-bit 1 or 0 value. The result register is always the
+  // last output of the instruction.
+  Label false_value;
+  DCHECK_NE(0, instr->OutputCount());
+  Register result = i.OutputRegister(instr->OutputCount() - 1);
+  Condition cc = kNoCondition;
+
+  // MIPS does not have condition code flags, so compare and branch are
+  // implemented differently than on the other arch's. The compare operations
+  // emit mips pseudo-instructions, which are checked and handled here.
+
+  // For materializations, we use delay slot to set the result true, and
+  // in the false case, where we fall through the branch, we reset the result
+  // false.
+
+  if (instr->arch_opcode() == kMips64Tst) {
+    switch (condition) {
+      case kNotEqual:
+        cc = ne;
+        break;
+      case kEqual:
+        cc = eq;
+        break;
+      default:
+        UNSUPPORTED_COND(kMips64Tst, condition);
+        break;
+    }
+    __ And(at, i.InputRegister(0), i.InputOperand(1));
+    __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg));
+    __ li(result, Operand(1));  // In delay slot.
+  } else if (instr->arch_opcode() == kMips64Tst32) {
+    switch (condition) {
+      case kNotEqual:
+        cc = ne;
+        break;
+      case kEqual:
+        cc = eq;
+        break;
+      default:
+        UNSUPPORTED_COND(kMips64Tst, condition);
+        break;
+    }
+    // Zero-extend register on MIPS64 only 64-bit operand
+    // branch and compare op. is available.
+    __ And(at, i.InputRegister(0), i.InputOperand(1));
+    __ Dext(at, at, 0, 32);
+    __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg));
+    __ li(result, Operand(1));  // In delay slot.
+  } else if (instr->arch_opcode() == kMips64Dadd ||
+             instr->arch_opcode() == kMips64Dsub) {
+    switch (condition) {
+      case kOverflow:
+        cc = ne;
+        break;
+      case kNotOverflow:
+        cc = eq;
+        break;
+      default:
+        UNSUPPORTED_COND(kMips64DAdd, condition);
+        break;
+    }
+    __ dsra32(kScratchReg, i.OutputRegister(), 0);
+    __ sra(at, i.OutputRegister(), 31);
+    __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(kScratchReg));
+    __ li(result, Operand(1));  // In delay slot.
+  } else if (instr->arch_opcode() == kMips64Cmp) {
+    Register left = i.InputRegister(0);
+    Operand right = i.InputOperand(1);
+    switch (condition) {
+      case kEqual:
+        cc = eq;
+        break;
+      case kNotEqual:
+        cc = ne;
+        break;
+      case kSignedLessThan:
+        cc = lt;
+        break;
+      case kSignedGreaterThanOrEqual:
+        cc = ge;
+        break;
+      case kSignedLessThanOrEqual:
+        cc = le;
+        break;
+      case kSignedGreaterThan:
+        cc = gt;
+        break;
+      case kUnsignedLessThan:
+        cc = lo;
+        break;
+      case kUnsignedGreaterThanOrEqual:
+        cc = hs;
+        break;
+      case kUnsignedLessThanOrEqual:
+        cc = ls;
+        break;
+      case kUnsignedGreaterThan:
+        cc = hi;
+        break;
+      default:
+        UNSUPPORTED_COND(kMips64Cmp, condition);
+        break;
+    }
+    __ Branch(USE_DELAY_SLOT, &done, cc, left, right);
+    __ li(result, Operand(1));  // In delay slot.
+  } else if (instr->arch_opcode() == kMips64Cmp32) {
+    Register left = i.InputRegister(0);
+    Operand right = i.InputOperand(1);
+    switch (condition) {
+      case kEqual:
+        cc = eq;
+        break;
+      case kNotEqual:
+        cc = ne;
+        break;
+      case kSignedLessThan:
+        cc = lt;
+        break;
+      case kSignedGreaterThanOrEqual:
+        cc = ge;
+        break;
+      case kSignedLessThanOrEqual:
+        cc = le;
+        break;
+      case kSignedGreaterThan:
+        cc = gt;
+        break;
+      case kUnsignedLessThan:
+        cc = lo;
+        break;
+      case kUnsignedGreaterThanOrEqual:
+        cc = hs;
+        break;
+      case kUnsignedLessThanOrEqual:
+        cc = ls;
+        break;
+      case kUnsignedGreaterThan:
+        cc = hi;
+        break;
+      default:
+        UNSUPPORTED_COND(kMips64Cmp, condition);
+        break;
+    }
+
+    switch (condition) {
+      case kEqual:
+      case kNotEqual:
+      case kSignedLessThan:
+      case kSignedGreaterThanOrEqual:
+      case kSignedLessThanOrEqual:
+      case kSignedGreaterThan:
+        // Sign-extend registers on MIPS64 only 64-bit operand
+        // branch and compare op. is available.
+        __ sll(left, left, 0);
+        if (instr->InputAt(1)->IsRegister()) {
+          __ sll(i.InputRegister(1), i.InputRegister(1), 0);
+        }
+        break;
+      case kUnsignedLessThan:
+      case kUnsignedGreaterThanOrEqual:
+      case kUnsignedLessThanOrEqual:
+      case kUnsignedGreaterThan:
+        // Zero-extend registers on MIPS64 only 64-bit operand
+        // branch and compare op. is available.
+        __ Dext(left, left, 0, 32);
+        if (instr->InputAt(1)->IsRegister()) {
+          __ Dext(i.InputRegister(1), i.InputRegister(1), 0, 32);
+        }
+        break;
+      default:
+        UNSUPPORTED_COND(kMips64Cmp32, condition);
+        break;
+    }
+    __ Branch(USE_DELAY_SLOT, &done, cc, left, right);
+    __ li(result, Operand(1));  // In delay slot.
+  } else if (instr->arch_opcode() == kMips64CmpD) {
+    FPURegister left = i.InputDoubleRegister(0);
+    FPURegister right = i.InputDoubleRegister(1);
+    // TODO(plind): Provide NaN-testing macro-asm function without need for
+    // BranchF.
+    FPURegister dummy1 = f0;
+    FPURegister dummy2 = f2;
+    switch (condition) {
+      case kUnorderedEqual:
+        // TODO(plind):  improve the NaN testing throughout this function.
+        __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2);
+        cc = eq;
+        break;
+      case kUnorderedNotEqual:
+        __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2);
+        __ li(result, Operand(1));  // In delay slot - returns 1 on NaN.
+        cc = ne;
+        break;
+      case kUnorderedLessThan:
+        __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2);
+        cc = lt;
+        break;
+      case kUnorderedGreaterThanOrEqual:
+        __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2);
+        __ li(result, Operand(1));  // In delay slot - returns 1 on NaN.
+        cc = ge;
+        break;
+      case kUnorderedLessThanOrEqual:
+        __ BranchF(NULL, &false_value, kNoCondition, dummy1, dummy2);
+        cc = le;
+        break;
+      case kUnorderedGreaterThan:
+        __ BranchF(USE_DELAY_SLOT, NULL, &done, kNoCondition, dummy1, dummy2);
+        __ li(result, Operand(1));  // In delay slot - returns 1 on NaN.
+        cc = gt;
+        break;
+      default:
+        UNSUPPORTED_COND(kMips64Cmp, condition);
+        break;
+    }
+    __ BranchF(USE_DELAY_SLOT, &done, NULL, cc, left, right);
+    __ li(result, Operand(1));  // In delay slot - branch taken returns 1.
+                                // Fall-thru (branch not taken) returns 0.
+
+  } else {
+    PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n",
+           instr->arch_opcode());
+    TRACE_UNIMPL();
+    UNIMPLEMENTED();
+  }
+  // Fallthru case is the false materialization.
+  __ bind(&false_value);
+  __ li(result, Operand(static_cast<int64_t>(0)));
+  __ bind(&done);
+}
+
+
+void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
+  Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
+      isolate(), deoptimization_id, Deoptimizer::LAZY);
+  __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
+}
+
+
+void CodeGenerator::AssemblePrologue() {
+  CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
+  if (descriptor->kind() == CallDescriptor::kCallAddress) {
+    __ Push(ra, fp);
+    __ mov(fp, sp);
+    const RegList saves = descriptor->CalleeSavedRegisters();
+    if (saves != 0) {  // Save callee-saved registers.
+      // TODO(plind): make callee save size const, possibly DCHECK it.
+      int register_save_area_size = 0;
+      for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
+        if (!((1 << i) & saves)) continue;
+        register_save_area_size += kPointerSize;
+      }
+      frame()->SetRegisterSaveAreaSize(register_save_area_size);
+      __ MultiPush(saves);
+    }
+  } else if (descriptor->IsJSFunctionCall()) {
+    CompilationInfo* info = this->info();
+    __ Prologue(info->IsCodePreAgingActive());
+    frame()->SetRegisterSaveAreaSize(
+        StandardFrameConstants::kFixedFrameSizeFromFp);
+
+    // Sloppy mode functions and builtins need to replace the receiver with the
+    // global proxy when called as functions (without an explicit receiver
+    // object).
+    // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
+    if (info->strict_mode() == SLOPPY && !info->is_native()) {
+      Label ok;
+      // +2 for return address and saved frame pointer.
+      int receiver_slot = info->scope()->num_parameters() + 2;
+      __ ld(a2, MemOperand(fp, receiver_slot * kPointerSize));
+      __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
+      __ Branch(&ok, ne, a2, Operand(at));
+
+      __ ld(a2, GlobalObjectOperand());
+      __ ld(a2, FieldMemOperand(a2, GlobalObject::kGlobalProxyOffset));
+      __ sd(a2, MemOperand(fp, receiver_slot * kPointerSize));
+      __ bind(&ok);
+    }
+  } else {
+    __ StubPrologue();
+    frame()->SetRegisterSaveAreaSize(
+        StandardFrameConstants::kFixedFrameSizeFromFp);
+  }
+  int stack_slots = frame()->GetSpillSlotCount();
+  if (stack_slots > 0) {
+    __ Dsubu(sp, sp, Operand(stack_slots * kPointerSize));
+  }
+}
+
+
+void CodeGenerator::AssembleReturn() {
+  CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
+  if (descriptor->kind() == CallDescriptor::kCallAddress) {
+    if (frame()->GetRegisterSaveAreaSize() > 0) {
+      // Remove this frame's spill slots first.
+      int stack_slots = frame()->GetSpillSlotCount();
+      if (stack_slots > 0) {
+        __ Daddu(sp, sp, Operand(stack_slots * kPointerSize));
+      }
+      // Restore registers.
+      const RegList saves = descriptor->CalleeSavedRegisters();
+      if (saves != 0) {
+        __ MultiPop(saves);
+      }
+    }
+    __ mov(sp, fp);
+    __ Pop(ra, fp);
+    __ Ret();
+  } else {
+    __ mov(sp, fp);
+    __ Pop(ra, fp);
+    int pop_count = descriptor->IsJSFunctionCall()
+                        ? static_cast<int>(descriptor->JSParameterCount())
+                        : 0;
+    __ DropAndRet(pop_count);
+  }
+}
+
+
+void CodeGenerator::AssembleMove(InstructionOperand* source,
+                                 InstructionOperand* destination) {
+  MipsOperandConverter g(this, NULL);
+  // Dispatch on the source and destination operand kinds.  Not all
+  // combinations are possible.
+  if (source->IsRegister()) {
+    DCHECK(destination->IsRegister() || destination->IsStackSlot());
+    Register src = g.ToRegister(source);
+    if (destination->IsRegister()) {
+      __ mov(g.ToRegister(destination), src);
+    } else {
+      __ sd(src, g.ToMemOperand(destination));
+    }
+  } else if (source->IsStackSlot()) {
+    DCHECK(destination->IsRegister() || destination->IsStackSlot());
+    MemOperand src = g.ToMemOperand(source);
+    if (destination->IsRegister()) {
+      __ ld(g.ToRegister(destination), src);
+    } else {
+      Register temp = kScratchReg;
+      __ ld(temp, src);
+      __ sd(temp, g.ToMemOperand(destination));
+    }
+  } else if (source->IsConstant()) {
+    Constant src = g.ToConstant(source);
+    if (destination->IsRegister() || destination->IsStackSlot()) {
+      Register dst =
+          destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
+      switch (src.type()) {
+        case Constant::kInt32:
+          __ li(dst, Operand(src.ToInt32()));
+          break;
+        case Constant::kFloat32:
+          __ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
+          break;
+        case Constant::kInt64:
+          __ li(dst, Operand(src.ToInt64()));
+          break;
+        case Constant::kFloat64:
+          __ li(dst, isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
+          break;
+        case Constant::kExternalReference:
+          __ li(dst, Operand(src.ToExternalReference()));
+          break;
+        case Constant::kHeapObject:
+          __ li(dst, src.ToHeapObject());
+          break;
+        case Constant::kRpoNumber:
+          UNREACHABLE();  // TODO(titzer): loading RPO numbers on mips64.
+          break;
+      }
+      if (destination->IsStackSlot()) __ sd(dst, g.ToMemOperand(destination));
+    } else if (src.type() == Constant::kFloat32) {
+      if (destination->IsDoubleStackSlot()) {
+        MemOperand dst = g.ToMemOperand(destination);
+        __ li(at, Operand(bit_cast<int32_t>(src.ToFloat32())));
+        __ sw(at, dst);
+      } else {
+        FloatRegister dst = g.ToSingleRegister(destination);
+        __ Move(dst, src.ToFloat32());
+      }
+    } else {
+      DCHECK_EQ(Constant::kFloat64, src.type());
+      DoubleRegister dst = destination->IsDoubleRegister()
+                               ? g.ToDoubleRegister(destination)
+                               : kScratchDoubleReg;
+      __ Move(dst, src.ToFloat64());
+      if (destination->IsDoubleStackSlot()) {
+        __ sdc1(dst, g.ToMemOperand(destination));
+      }
+    }
+  } else if (source->IsDoubleRegister()) {
+    FPURegister src = g.ToDoubleRegister(source);
+    if (destination->IsDoubleRegister()) {
+      FPURegister dst = g.ToDoubleRegister(destination);
+      __ Move(dst, src);
+    } else {
+      DCHECK(destination->IsDoubleStackSlot());
+      __ sdc1(src, g.ToMemOperand(destination));
+    }
+  } else if (source->IsDoubleStackSlot()) {
+    DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
+    MemOperand src = g.ToMemOperand(source);
+    if (destination->IsDoubleRegister()) {
+      __ ldc1(g.ToDoubleRegister(destination), src);
+    } else {
+      FPURegister temp = kScratchDoubleReg;
+      __ ldc1(temp, src);
+      __ sdc1(temp, g.ToMemOperand(destination));
+    }
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+void CodeGenerator::AssembleSwap(InstructionOperand* source,
+                                 InstructionOperand* destination) {
+  MipsOperandConverter g(this, NULL);
+  // Dispatch on the source and destination operand kinds.  Not all
+  // combinations are possible.
+  if (source->IsRegister()) {
+    // Register-register.
+    Register temp = kScratchReg;
+    Register src = g.ToRegister(source);
+    if (destination->IsRegister()) {
+      Register dst = g.ToRegister(destination);
+      __ Move(temp, src);
+      __ Move(src, dst);
+      __ Move(dst, temp);
+    } else {
+      DCHECK(destination->IsStackSlot());
+      MemOperand dst = g.ToMemOperand(destination);
+      __ mov(temp, src);
+      __ ld(src, dst);
+      __ sd(temp, dst);
+    }
+  } else if (source->IsStackSlot()) {
+    DCHECK(destination->IsStackSlot());
+    Register temp_0 = kScratchReg;
+    Register temp_1 = kScratchReg2;
+    MemOperand src = g.ToMemOperand(source);
+    MemOperand dst = g.ToMemOperand(destination);
+    __ ld(temp_0, src);
+    __ ld(temp_1, dst);
+    __ sd(temp_0, dst);
+    __ sd(temp_1, src);
+  } else if (source->IsDoubleRegister()) {
+    FPURegister temp = kScratchDoubleReg;
+    FPURegister src = g.ToDoubleRegister(source);
+    if (destination->IsDoubleRegister()) {
+      FPURegister dst = g.ToDoubleRegister(destination);
+      __ Move(temp, src);
+      __ Move(src, dst);
+      __ Move(dst, temp);
+    } else {
+      DCHECK(destination->IsDoubleStackSlot());
+      MemOperand dst = g.ToMemOperand(destination);
+      __ Move(temp, src);
+      __ ldc1(src, dst);
+      __ sdc1(temp, dst);
+    }
+  } else if (source->IsDoubleStackSlot()) {
+    DCHECK(destination->IsDoubleStackSlot());
+    Register temp_0 = kScratchReg;
+    FPURegister temp_1 = kScratchDoubleReg;
+    MemOperand src0 = g.ToMemOperand(source);
+    MemOperand src1(src0.rm(), src0.offset() + kPointerSize);
+    MemOperand dst0 = g.ToMemOperand(destination);
+    MemOperand dst1(dst0.rm(), dst0.offset() + kPointerSize);
+    __ ldc1(temp_1, dst0);  // Save destination in temp_1.
+    __ lw(temp_0, src0);    // Then use temp_0 to copy source to destination.
+    __ sw(temp_0, dst0);
+    __ lw(temp_0, src1);
+    __ sw(temp_0, dst1);
+    __ sdc1(temp_1, src0);
+  } else {
+    // No other combinations are possible.
+    UNREACHABLE();
+  }
+}
+
+
+void CodeGenerator::AddNopForSmiCodeInlining() {
+  // Unused on 32-bit ARM. Still exists on 64-bit arm.
+  // TODO(plind): Unclear when this is called now. Understand, fix if needed.
+  __ nop();  // Maybe PROPERTY_ACCESS_INLINED?
+}
+
+
+void CodeGenerator::EnsureSpaceForLazyDeopt() {
+  int space_needed = Deoptimizer::patch_size();
+  if (!info()->IsStub()) {
+    // Ensure that we have enough space after the previous lazy-bailout
+    // instruction for patching the code here.
+    int current_pc = masm()->pc_offset();
+    if (current_pc < last_lazy_deopt_pc_ + space_needed) {
+      // Block tramoline pool emission for duration of padding.
+      v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
+          masm());
+      int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
+      DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
+      while (padding_size > 0) {
+        __ nop();
+        padding_size -= v8::internal::Assembler::kInstrSize;
+      }
+    }
+  }
+  MarkLazyDeoptSite();
+}
+
+#undef __
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/mips64/instruction-codes-mips64.h b/src/compiler/mips64/instruction-codes-mips64.h
new file mode 100644
index 0000000..dd019f9
--- /dev/null
+++ b/src/compiler/mips64/instruction-codes-mips64.h
@@ -0,0 +1,108 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_MIPS_INSTRUCTION_CODES_MIPS_H_
+#define V8_COMPILER_MIPS_INSTRUCTION_CODES_MIPS_H_
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// MIPS64-specific opcodes that specify which assembly sequence to emit.
+// Most opcodes specify a single instruction.
+#define TARGET_ARCH_OPCODE_LIST(V) \
+  V(Mips64Add)                     \
+  V(Mips64Dadd)                    \
+  V(Mips64Sub)                     \
+  V(Mips64Dsub)                    \
+  V(Mips64Mul)                     \
+  V(Mips64MulHigh)                 \
+  V(Mips64MulHighU)                \
+  V(Mips64Dmul)                    \
+  V(Mips64Div)                     \
+  V(Mips64Ddiv)                    \
+  V(Mips64DivU)                    \
+  V(Mips64DdivU)                   \
+  V(Mips64Mod)                     \
+  V(Mips64Dmod)                    \
+  V(Mips64ModU)                    \
+  V(Mips64DmodU)                   \
+  V(Mips64And)                     \
+  V(Mips64Or)                      \
+  V(Mips64Xor)                     \
+  V(Mips64Shl)                     \
+  V(Mips64Shr)                     \
+  V(Mips64Sar)                     \
+  V(Mips64Ext)                     \
+  V(Mips64Dext)                    \
+  V(Mips64Dshl)                    \
+  V(Mips64Dshr)                    \
+  V(Mips64Dsar)                    \
+  V(Mips64Ror)                     \
+  V(Mips64Dror)                    \
+  V(Mips64Mov)                     \
+  V(Mips64Tst)                     \
+  V(Mips64Tst32)                   \
+  V(Mips64Cmp)                     \
+  V(Mips64Cmp32)                   \
+  V(Mips64CmpD)                    \
+  V(Mips64AddD)                    \
+  V(Mips64SubD)                    \
+  V(Mips64MulD)                    \
+  V(Mips64DivD)                    \
+  V(Mips64ModD)                    \
+  V(Mips64SqrtD)                   \
+  V(Mips64Float64Floor)            \
+  V(Mips64Float64Ceil)             \
+  V(Mips64Float64RoundTruncate)    \
+  V(Mips64CvtSD)                   \
+  V(Mips64CvtDS)                   \
+  V(Mips64TruncWD)                 \
+  V(Mips64TruncUwD)                \
+  V(Mips64CvtDW)                   \
+  V(Mips64CvtDUw)                  \
+  V(Mips64Lb)                      \
+  V(Mips64Lbu)                     \
+  V(Mips64Sb)                      \
+  V(Mips64Lh)                      \
+  V(Mips64Lhu)                     \
+  V(Mips64Sh)                      \
+  V(Mips64Ld)                      \
+  V(Mips64Lw)                      \
+  V(Mips64Sw)                      \
+  V(Mips64Sd)                      \
+  V(Mips64Lwc1)                    \
+  V(Mips64Swc1)                    \
+  V(Mips64Ldc1)                    \
+  V(Mips64Sdc1)                    \
+  V(Mips64Push)                    \
+  V(Mips64StoreToStackSlot)        \
+  V(Mips64StackClaim)              \
+  V(Mips64StoreWriteBarrier)
+
+
+// Addressing modes represent the "shape" of inputs to an instruction.
+// Many instructions support multiple addressing modes. Addressing modes
+// are encoded into the InstructionCode of the instruction and tell the
+// code generator after register allocation which assembler method to call.
+//
+// We use the following local notation for addressing modes:
+//
+// R = register
+// O = register or stack slot
+// D = double register
+// I = immediate (handle, external, int32)
+// MRI = [register + immediate]
+// MRR = [register + register]
+// TODO(plind): Add the new r6 address modes.
+#define TARGET_ADDRESSING_MODE_LIST(V) \
+  V(MRI) /* [%r0 + K] */               \
+  V(MRR) /* [%r0 + %r1] */
+
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_MIPS_INSTRUCTION_CODES_MIPS_H_
diff --git a/src/compiler/mips64/instruction-selector-mips64.cc b/src/compiler/mips64/instruction-selector-mips64.cc
new file mode 100644
index 0000000..35ad16b
--- /dev/null
+++ b/src/compiler/mips64/instruction-selector-mips64.cc
@@ -0,0 +1,1079 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/bits.h"
+#include "src/compiler/instruction-selector-impl.h"
+#include "src/compiler/node-matchers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+#define TRACE_UNIMPL() \
+  PrintF("UNIMPLEMENTED instr_sel: %s at line %d\n", __FUNCTION__, __LINE__)
+
+#define TRACE() PrintF("instr_sel: %s at line %d\n", __FUNCTION__, __LINE__)
+
+
+// Adds Mips-specific methods for generating InstructionOperands.
+class Mips64OperandGenerator FINAL : public OperandGenerator {
+ public:
+  explicit Mips64OperandGenerator(InstructionSelector* selector)
+      : OperandGenerator(selector) {}
+
+  InstructionOperand* UseOperand(Node* node, InstructionCode opcode) {
+    if (CanBeImmediate(node, opcode)) {
+      return UseImmediate(node);
+    }
+    return UseRegister(node);
+  }
+
+  bool CanBeImmediate(Node* node, InstructionCode opcode) {
+    int64_t value;
+    if (node->opcode() == IrOpcode::kInt32Constant)
+      value = OpParameter<int32_t>(node);
+    else if (node->opcode() == IrOpcode::kInt64Constant)
+      value = OpParameter<int64_t>(node);
+    else
+      return false;
+    switch (ArchOpcodeField::decode(opcode)) {
+      case kMips64Shl:
+      case kMips64Sar:
+      case kMips64Shr:
+        return is_uint5(value);
+      case kMips64Dshl:
+      case kMips64Dsar:
+      case kMips64Dshr:
+        return is_uint6(value);
+      case kMips64Xor:
+        return is_uint16(value);
+      case kMips64Ldc1:
+      case kMips64Sdc1:
+        return is_int16(value + kIntSize);
+      default:
+        return is_int16(value);
+    }
+  }
+
+
+  bool CanBeImmediate(Node* node, InstructionCode opcode,
+                      FlagsContinuation* cont) {
+    int64_t value;
+    if (node->opcode() == IrOpcode::kInt32Constant)
+      value = OpParameter<int32_t>(node);
+    else if (node->opcode() == IrOpcode::kInt64Constant)
+      value = OpParameter<int64_t>(node);
+    else
+      return false;
+    switch (ArchOpcodeField::decode(opcode)) {
+      case kMips64Cmp32:
+        switch (cont->condition()) {
+          case kUnsignedLessThan:
+          case kUnsignedGreaterThanOrEqual:
+          case kUnsignedLessThanOrEqual:
+          case kUnsignedGreaterThan:
+            // Immediate operands for unsigned 32-bit compare operations
+            // should not be sign-extended.
+            return is_uint15(value);
+          default:
+            return false;
+        }
+      default:
+        return is_int16(value);
+    }
+  }
+
+
+ private:
+  bool ImmediateFitsAddrMode1Instruction(int32_t imm) const {
+    TRACE_UNIMPL();
+    return false;
+  }
+};
+
+
+static void VisitRR(InstructionSelector* selector, ArchOpcode opcode,
+                    Node* node) {
+  Mips64OperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsRegister(node),
+                 g.UseRegister(node->InputAt(0)));
+}
+
+
+static void VisitRRR(InstructionSelector* selector, ArchOpcode opcode,
+                     Node* node) {
+  Mips64OperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsRegister(node),
+                 g.UseRegister(node->InputAt(0)),
+                 g.UseRegister(node->InputAt(1)));
+}
+
+
+static void VisitRRO(InstructionSelector* selector, ArchOpcode opcode,
+                     Node* node) {
+  Mips64OperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsRegister(node),
+                 g.UseRegister(node->InputAt(0)),
+                 g.UseOperand(node->InputAt(1), opcode));
+}
+
+
+static void VisitBinop(InstructionSelector* selector, Node* node,
+                       InstructionCode opcode, FlagsContinuation* cont) {
+  Mips64OperandGenerator g(selector);
+  Int32BinopMatcher m(node);
+  InstructionOperand* inputs[4];
+  size_t input_count = 0;
+  InstructionOperand* outputs[2];
+  size_t output_count = 0;
+
+  inputs[input_count++] = g.UseRegister(m.left().node());
+  inputs[input_count++] = g.UseOperand(m.right().node(), opcode);
+
+  if (cont->IsBranch()) {
+    inputs[input_count++] = g.Label(cont->true_block());
+    inputs[input_count++] = g.Label(cont->false_block());
+  }
+
+  outputs[output_count++] = g.DefineAsRegister(node);
+  if (cont->IsSet()) {
+    outputs[output_count++] = g.DefineAsRegister(cont->result());
+  }
+
+  DCHECK_NE(0, input_count);
+  DCHECK_NE(0, output_count);
+  DCHECK_GE(arraysize(inputs), input_count);
+  DCHECK_GE(arraysize(outputs), output_count);
+
+  Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
+                                      outputs, input_count, inputs);
+  if (cont->IsBranch()) instr->MarkAsControl();
+}
+
+
+static void VisitBinop(InstructionSelector* selector, Node* node,
+                       InstructionCode opcode) {
+  FlagsContinuation cont;
+  VisitBinop(selector, node, opcode, &cont);
+}
+
+
+void InstructionSelector::VisitLoad(Node* node) {
+  MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
+  MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
+  Mips64OperandGenerator g(this);
+  Node* base = node->InputAt(0);
+  Node* index = node->InputAt(1);
+
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepFloat32:
+      opcode = kMips64Lwc1;
+      break;
+    case kRepFloat64:
+      opcode = kMips64Ldc1;
+      break;
+    case kRepBit:  // Fall through.
+    case kRepWord8:
+      opcode = typ == kTypeUint32 ? kMips64Lbu : kMips64Lb;
+      break;
+    case kRepWord16:
+      opcode = typ == kTypeUint32 ? kMips64Lhu : kMips64Lh;
+      break;
+    case kRepWord32:
+      opcode = kMips64Lw;
+      break;
+    case kRepTagged:  // Fall through.
+    case kRepWord64:
+      opcode = kMips64Ld;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+
+  if (g.CanBeImmediate(index, opcode)) {
+    Emit(opcode | AddressingModeField::encode(kMode_MRI),
+         g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
+  } else {
+    InstructionOperand* addr_reg = g.TempRegister();
+    Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
+         g.UseRegister(index), g.UseRegister(base));
+    // Emit desired load opcode, using temp addr_reg.
+    Emit(opcode | AddressingModeField::encode(kMode_MRI),
+         g.DefineAsRegister(node), addr_reg, g.TempImmediate(0));
+  }
+}
+
+
+void InstructionSelector::VisitStore(Node* node) {
+  Mips64OperandGenerator g(this);
+  Node* base = node->InputAt(0);
+  Node* index = node->InputAt(1);
+  Node* value = node->InputAt(2);
+
+  StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
+  MachineType rep = RepresentationOf(store_rep.machine_type());
+  if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
+    DCHECK(rep == kRepTagged);
+    // TODO(dcarney): refactor RecordWrite function to take temp registers
+    //                and pass them here instead of using fixed regs
+    // TODO(dcarney): handle immediate indices.
+    InstructionOperand* temps[] = {g.TempRegister(t1), g.TempRegister(t2)};
+    Emit(kMips64StoreWriteBarrier, NULL, g.UseFixed(base, t0),
+         g.UseFixed(index, t1), g.UseFixed(value, t2), arraysize(temps), temps);
+    return;
+  }
+  DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
+
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepFloat32:
+      opcode = kMips64Swc1;
+      break;
+    case kRepFloat64:
+      opcode = kMips64Sdc1;
+      break;
+    case kRepBit:  // Fall through.
+    case kRepWord8:
+      opcode = kMips64Sb;
+      break;
+    case kRepWord16:
+      opcode = kMips64Sh;
+      break;
+    case kRepWord32:
+      opcode = kMips64Sw;
+      break;
+    case kRepTagged:  // Fall through.
+    case kRepWord64:
+      opcode = kMips64Sd;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+
+  if (g.CanBeImmediate(index, opcode)) {
+    Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
+         g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
+  } else {
+    InstructionOperand* addr_reg = g.TempRegister();
+    Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
+         g.UseRegister(index), g.UseRegister(base));
+    // Emit desired store opcode, using temp addr_reg.
+    Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, addr_reg,
+         g.TempImmediate(0), g.UseRegister(value));
+  }
+}
+
+
+void InstructionSelector::VisitWord32And(Node* node) {
+  VisitBinop(this, node, kMips64And);
+}
+
+
+void InstructionSelector::VisitWord64And(Node* node) {
+  VisitBinop(this, node, kMips64And);
+}
+
+
+void InstructionSelector::VisitWord32Or(Node* node) {
+  VisitBinop(this, node, kMips64Or);
+}
+
+
+void InstructionSelector::VisitWord64Or(Node* node) {
+  VisitBinop(this, node, kMips64Or);
+}
+
+
+void InstructionSelector::VisitWord32Xor(Node* node) {
+  VisitBinop(this, node, kMips64Xor);
+}
+
+
+void InstructionSelector::VisitWord64Xor(Node* node) {
+  VisitBinop(this, node, kMips64Xor);
+}
+
+
+void InstructionSelector::VisitWord32Shl(Node* node) {
+  VisitRRO(this, kMips64Shl, node);
+}
+
+
+void InstructionSelector::VisitWord32Shr(Node* node) {
+  VisitRRO(this, kMips64Shr, node);
+}
+
+
+void InstructionSelector::VisitWord32Sar(Node* node) {
+  VisitRRO(this, kMips64Sar, node);
+}
+
+
+void InstructionSelector::VisitWord64Shl(Node* node) {
+  VisitRRO(this, kMips64Dshl, node);
+}
+
+
+void InstructionSelector::VisitWord64Shr(Node* node) {
+  VisitRRO(this, kMips64Dshr, node);
+}
+
+
+void InstructionSelector::VisitWord64Sar(Node* node) {
+  VisitRRO(this, kMips64Dsar, node);
+}
+
+
+void InstructionSelector::VisitWord32Ror(Node* node) {
+  VisitRRO(this, kMips64Ror, node);
+}
+
+
+void InstructionSelector::VisitWord64Ror(Node* node) {
+  VisitRRO(this, kMips64Dror, node);
+}
+
+
+void InstructionSelector::VisitInt32Add(Node* node) {
+  Mips64OperandGenerator g(this);
+  // TODO(plind): Consider multiply & add optimization from arm port.
+  VisitBinop(this, node, kMips64Add);
+}
+
+
+void InstructionSelector::VisitInt64Add(Node* node) {
+  Mips64OperandGenerator g(this);
+  // TODO(plind): Consider multiply & add optimization from arm port.
+  VisitBinop(this, node, kMips64Dadd);
+}
+
+
+void InstructionSelector::VisitInt32Sub(Node* node) {
+  VisitBinop(this, node, kMips64Sub);
+}
+
+
+void InstructionSelector::VisitInt64Sub(Node* node) {
+  VisitBinop(this, node, kMips64Dsub);
+}
+
+
+void InstructionSelector::VisitInt32Mul(Node* node) {
+  Mips64OperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  if (m.right().HasValue() && m.right().Value() > 0) {
+    int32_t value = m.right().Value();
+    if (base::bits::IsPowerOfTwo32(value)) {
+      Emit(kMips64Shl | AddressingModeField::encode(kMode_None),
+           g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+           g.TempImmediate(WhichPowerOf2(value)));
+      return;
+    }
+    if (base::bits::IsPowerOfTwo32(value - 1)) {
+      InstructionOperand* temp = g.TempRegister();
+      Emit(kMips64Shl | AddressingModeField::encode(kMode_None), temp,
+           g.UseRegister(m.left().node()),
+           g.TempImmediate(WhichPowerOf2(value - 1)));
+      Emit(kMips64Add | AddressingModeField::encode(kMode_None),
+           g.DefineAsRegister(node), g.UseRegister(m.left().node()), temp);
+      return;
+    }
+    if (base::bits::IsPowerOfTwo32(value + 1)) {
+      InstructionOperand* temp = g.TempRegister();
+      Emit(kMips64Shl | AddressingModeField::encode(kMode_None), temp,
+           g.UseRegister(m.left().node()),
+           g.TempImmediate(WhichPowerOf2(value + 1)));
+      Emit(kMips64Sub | AddressingModeField::encode(kMode_None),
+           g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
+      return;
+    }
+  }
+  Emit(kMips64Mul, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64MulHigh, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
+}
+
+
+void InstructionSelector::VisitUint32MulHigh(Node* node) {
+  Mips64OperandGenerator g(this);
+  InstructionOperand* const dmul_operand = g.TempRegister();
+  Emit(kMips64MulHighU, dmul_operand, g.UseRegister(node->InputAt(0)),
+       g.UseRegister(node->InputAt(1)));
+  Emit(kMips64Ext, g.DefineAsRegister(node), dmul_operand, g.TempImmediate(0),
+       g.TempImmediate(32));
+}
+
+
+void InstructionSelector::VisitInt64Mul(Node* node) {
+  Mips64OperandGenerator g(this);
+  Int64BinopMatcher m(node);
+  // TODO(dusmil): Add optimization for shifts larger than 32.
+  if (m.right().HasValue() && m.right().Value() > 0) {
+    int64_t value = m.right().Value();
+    if (base::bits::IsPowerOfTwo32(value)) {
+      Emit(kMips64Dshl | AddressingModeField::encode(kMode_None),
+           g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+           g.TempImmediate(WhichPowerOf2(value)));
+      return;
+    }
+    if (base::bits::IsPowerOfTwo32(value - 1)) {
+      InstructionOperand* temp = g.TempRegister();
+      Emit(kMips64Dshl | AddressingModeField::encode(kMode_None), temp,
+           g.UseRegister(m.left().node()),
+           g.TempImmediate(WhichPowerOf2(value - 1)));
+      Emit(kMips64Dadd | AddressingModeField::encode(kMode_None),
+           g.DefineAsRegister(node), g.UseRegister(m.left().node()), temp);
+      return;
+    }
+    if (base::bits::IsPowerOfTwo32(value + 1)) {
+      InstructionOperand* temp = g.TempRegister();
+      Emit(kMips64Dshl | AddressingModeField::encode(kMode_None), temp,
+           g.UseRegister(m.left().node()),
+           g.TempImmediate(WhichPowerOf2(value + 1)));
+      Emit(kMips64Dsub | AddressingModeField::encode(kMode_None),
+           g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
+      return;
+    }
+  }
+  Emit(kMips64Dmul, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitInt32Div(Node* node) {
+  Mips64OperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  Emit(kMips64Div, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitUint32Div(Node* node) {
+  Mips64OperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  Emit(kMips64DivU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitInt32Mod(Node* node) {
+  Mips64OperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  Emit(kMips64Mod, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitUint32Mod(Node* node) {
+  Mips64OperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  Emit(kMips64ModU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitInt64Div(Node* node) {
+  Mips64OperandGenerator g(this);
+  Int64BinopMatcher m(node);
+  Emit(kMips64Ddiv, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitUint64Div(Node* node) {
+  Mips64OperandGenerator g(this);
+  Int64BinopMatcher m(node);
+  Emit(kMips64DdivU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitInt64Mod(Node* node) {
+  Mips64OperandGenerator g(this);
+  Int64BinopMatcher m(node);
+  Emit(kMips64Dmod, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitUint64Mod(Node* node) {
+  Mips64OperandGenerator g(this);
+  Int64BinopMatcher m(node);
+  Emit(kMips64DmodU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+       g.UseRegister(m.right().node()));
+}
+
+
+void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64CvtDS, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64CvtDW, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64CvtDUw, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64TruncWD, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64TruncUwD, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64Shl, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
+       g.TempImmediate(0));
+}
+
+
+void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64Dext, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
+       g.TempImmediate(0), g.TempImmediate(32));
+}
+
+
+void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64Ext, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
+       g.TempImmediate(0), g.TempImmediate(32));
+}
+
+
+void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64CvtSD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64Add(Node* node) {
+  VisitRRR(this, kMips64AddD, node);
+}
+
+
+void InstructionSelector::VisitFloat64Sub(Node* node) {
+  VisitRRR(this, kMips64SubD, node);
+}
+
+
+void InstructionSelector::VisitFloat64Mul(Node* node) {
+  VisitRRR(this, kMips64MulD, node);
+}
+
+
+void InstructionSelector::VisitFloat64Div(Node* node) {
+  VisitRRR(this, kMips64DivD, node);
+}
+
+
+void InstructionSelector::VisitFloat64Mod(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64ModD, g.DefineAsFixed(node, f0),
+       g.UseFixed(node->InputAt(0), f12),
+       g.UseFixed(node->InputAt(1), f14))->MarkAsCall();
+}
+
+
+void InstructionSelector::VisitFloat64Sqrt(Node* node) {
+  Mips64OperandGenerator g(this);
+  Emit(kMips64SqrtD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64Floor(Node* node) {
+  VisitRR(this, kMips64Float64Floor, node);
+}
+
+
+void InstructionSelector::VisitFloat64Ceil(Node* node) {
+  VisitRR(this, kMips64Float64Ceil, node);
+}
+
+
+void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
+  VisitRR(this, kMips64Float64RoundTruncate, node);
+}
+
+
+void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
+  UNREACHABLE();
+}
+
+
+void InstructionSelector::VisitCall(Node* node) {
+  Mips64OperandGenerator g(this);
+  const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
+
+  FrameStateDescriptor* frame_state_descriptor = NULL;
+  if (descriptor->NeedsFrameState()) {
+    frame_state_descriptor =
+        GetFrameStateDescriptor(node->InputAt(descriptor->InputCount()));
+  }
+
+  CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
+
+  // Compute InstructionOperands for inputs and outputs.
+  InitializeCallBuffer(node, &buffer, true, false);
+
+  int push_count = buffer.pushed_nodes.size();
+  if (push_count > 0) {
+    Emit(kMips64StackClaim | MiscField::encode(push_count), NULL);
+  }
+  int slot = buffer.pushed_nodes.size() - 1;
+  for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
+       input != buffer.pushed_nodes.rend(); input++) {
+    Emit(kMips64StoreToStackSlot | MiscField::encode(slot), NULL,
+         g.UseRegister(*input));
+    slot--;
+  }
+
+  // Select the appropriate opcode based on the call type.
+  InstructionCode opcode;
+  switch (descriptor->kind()) {
+    case CallDescriptor::kCallCodeObject: {
+      opcode = kArchCallCodeObject;
+      break;
+    }
+    case CallDescriptor::kCallJSFunction:
+      opcode = kArchCallJSFunction;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+  opcode |= MiscField::encode(descriptor->flags());
+
+  // Emit the call instruction.
+  Instruction* call_instr =
+      Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(),
+           buffer.instruction_args.size(), &buffer.instruction_args.front());
+
+  call_instr->MarkAsCall();
+}
+
+
+void InstructionSelector::VisitCheckedLoad(Node* node) {
+  MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+  MachineType typ = TypeOf(OpParameter<MachineType>(node));
+  Mips64OperandGenerator g(this);
+  Node* const buffer = node->InputAt(0);
+  Node* const offset = node->InputAt(1);
+  Node* const length = node->InputAt(2);
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepWord8:
+      opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8;
+      break;
+    case kRepWord16:
+      opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16;
+      break;
+    case kRepWord32:
+      opcode = kCheckedLoadWord32;
+      break;
+    case kRepFloat32:
+      opcode = kCheckedLoadFloat32;
+      break;
+    case kRepFloat64:
+      opcode = kCheckedLoadFloat64;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+  InstructionOperand* offset_operand = g.CanBeImmediate(offset, opcode)
+                                           ? g.UseImmediate(offset)
+                                           : g.UseRegister(offset);
+
+  InstructionOperand* length_operand =
+      (!g.CanBeImmediate(offset, opcode)) ? g.CanBeImmediate(length, opcode)
+      ? g.UseImmediate(length)
+      : g.UseRegister(length)
+      : g.UseRegister(length);
+
+  Emit(opcode | AddressingModeField::encode(kMode_MRI),
+       g.DefineAsRegister(node), offset_operand, length_operand,
+       g.UseRegister(buffer));
+}
+
+
+void InstructionSelector::VisitCheckedStore(Node* node) {
+  MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+  Mips64OperandGenerator g(this);
+  Node* const buffer = node->InputAt(0);
+  Node* const offset = node->InputAt(1);
+  Node* const length = node->InputAt(2);
+  Node* const value = node->InputAt(3);
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepWord8:
+      opcode = kCheckedStoreWord8;
+      break;
+    case kRepWord16:
+      opcode = kCheckedStoreWord16;
+      break;
+    case kRepWord32:
+      opcode = kCheckedStoreWord32;
+      break;
+    case kRepFloat32:
+      opcode = kCheckedStoreFloat32;
+      break;
+    case kRepFloat64:
+      opcode = kCheckedStoreFloat64;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+  InstructionOperand* offset_operand = g.CanBeImmediate(offset, opcode)
+                                           ? g.UseImmediate(offset)
+                                           : g.UseRegister(offset);
+
+  InstructionOperand* length_operand =
+      (!g.CanBeImmediate(offset, opcode)) ? g.CanBeImmediate(length, opcode)
+      ? g.UseImmediate(length)
+      : g.UseRegister(length)
+      : g.UseRegister(length);
+
+  Emit(opcode | AddressingModeField::encode(kMode_MRI), nullptr, offset_operand,
+       length_operand, g.UseRegister(value), g.UseRegister(buffer));
+}
+
+
+namespace {
+
+// Shared routine for multiple compare operations.
+static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
+                         InstructionOperand* left, InstructionOperand* right,
+                         FlagsContinuation* cont) {
+  Mips64OperandGenerator g(selector);
+  opcode = cont->Encode(opcode);
+  if (cont->IsBranch()) {
+    selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
+                   g.Label(cont->false_block()))->MarkAsControl();
+  } else {
+    DCHECK(cont->IsSet());
+    selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
+  }
+}
+
+
+// Shared routine for multiple float compare operations.
+void VisitFloat64Compare(InstructionSelector* selector, Node* node,
+                         FlagsContinuation* cont) {
+  Mips64OperandGenerator g(selector);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  VisitCompare(selector, kMips64CmpD, g.UseRegister(left), g.UseRegister(right),
+               cont);
+}
+
+
+// Shared routine for multiple word compare operations.
+void VisitWordCompare(InstructionSelector* selector, Node* node,
+                      InstructionCode opcode, FlagsContinuation* cont,
+                      bool commutative) {
+  Mips64OperandGenerator g(selector);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+
+  // Match immediates on left or right side of comparison.
+  if (g.CanBeImmediate(right, opcode, cont)) {
+    VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
+                 cont);
+  } else if (g.CanBeImmediate(left, opcode, cont)) {
+    if (!commutative) cont->Commute();
+    VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
+                 cont);
+  } else {
+    VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
+                 cont);
+  }
+}
+
+
+void VisitWord32Compare(InstructionSelector* selector, Node* node,
+                        FlagsContinuation* cont) {
+  VisitWordCompare(selector, node, kMips64Cmp32, cont, false);
+}
+
+
+void VisitWord64Compare(InstructionSelector* selector, Node* node,
+                        FlagsContinuation* cont) {
+  VisitWordCompare(selector, node, kMips64Cmp, cont, false);
+}
+
+}  // namespace
+
+
+void EmitWordCompareZero(InstructionSelector* selector, InstructionCode opcode,
+                         Node* value, FlagsContinuation* cont) {
+  Mips64OperandGenerator g(selector);
+  opcode = cont->Encode(opcode);
+  InstructionOperand* const value_operand = g.UseRegister(value);
+  if (cont->IsBranch()) {
+    selector->Emit(opcode, nullptr, value_operand, g.TempImmediate(0),
+                   g.Label(cont->true_block()),
+                   g.Label(cont->false_block()))->MarkAsControl();
+  } else {
+    selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
+                   g.TempImmediate(0));
+  }
+}
+
+
+// Shared routine for word comparisons against zero.
+void VisitWordCompareZero(InstructionSelector* selector, Node* user,
+                          Node* value, FlagsContinuation* cont) {
+  // Initially set comparison against 0 to be 64-bit variant for branches that
+  // cannot combine.
+  InstructionCode opcode = kMips64Cmp;
+  while (selector->CanCover(user, value)) {
+    if (user->opcode() == IrOpcode::kWord32Equal) {
+      opcode = kMips64Cmp32;
+    }
+    switch (value->opcode()) {
+      case IrOpcode::kWord32Equal: {
+        // Combine with comparisons against 0 by simply inverting the
+        // continuation.
+        Int32BinopMatcher m(value);
+        if (m.right().Is(0)) {
+          user = value;
+          value = m.left().node();
+          cont->Negate();
+          opcode = kMips64Cmp32;
+          continue;
+        }
+        cont->OverwriteAndNegateIfEqual(kEqual);
+        return VisitWord32Compare(selector, value, cont);
+      }
+      case IrOpcode::kInt32LessThan:
+        cont->OverwriteAndNegateIfEqual(kSignedLessThan);
+        return VisitWord32Compare(selector, value, cont);
+      case IrOpcode::kInt32LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
+        return VisitWord32Compare(selector, value, cont);
+      case IrOpcode::kUint32LessThan:
+        cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
+        return VisitWord32Compare(selector, value, cont);
+      case IrOpcode::kUint32LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
+        return VisitWord32Compare(selector, value, cont);
+      case IrOpcode::kWord64Equal: {
+        // Combine with comparisons against 0 by simply inverting the
+        // continuation.
+        Int64BinopMatcher m(value);
+        if (m.right().Is(0)) {
+          user = value;
+          value = m.left().node();
+          cont->Negate();
+          continue;
+        }
+        cont->OverwriteAndNegateIfEqual(kEqual);
+        return VisitWord64Compare(selector, value, cont);
+      }
+      case IrOpcode::kInt64LessThan:
+        cont->OverwriteAndNegateIfEqual(kSignedLessThan);
+        return VisitWord64Compare(selector, value, cont);
+      case IrOpcode::kInt64LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
+        return VisitWord64Compare(selector, value, cont);
+      case IrOpcode::kUint64LessThan:
+        cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
+        return VisitWord64Compare(selector, value, cont);
+      case IrOpcode::kFloat64Equal:
+        cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
+        return VisitFloat64Compare(selector, value, cont);
+      case IrOpcode::kFloat64LessThan:
+        cont->OverwriteAndNegateIfEqual(kUnorderedLessThan);
+        return VisitFloat64Compare(selector, value, cont);
+      case IrOpcode::kFloat64LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual);
+        return VisitFloat64Compare(selector, value, cont);
+      case IrOpcode::kProjection:
+        // Check if this is the overflow output projection of an
+        // <Operation>WithOverflow node.
+        if (OpParameter<size_t>(value) == 1u) {
+          // We cannot combine the <Operation>WithOverflow with this branch
+          // unless the 0th projection (the use of the actual value of the
+          // <Operation> is either NULL, which means there's no use of the
+          // actual value, or was already defined, which means it is scheduled
+          // *AFTER* this branch).
+          Node* node = value->InputAt(0);
+          Node* result = node->FindProjection(0);
+          if (result == NULL || selector->IsDefined(result)) {
+            switch (node->opcode()) {
+              case IrOpcode::kInt32AddWithOverflow:
+                cont->OverwriteAndNegateIfEqual(kOverflow);
+                return VisitBinop(selector, node, kMips64Dadd, cont);
+              case IrOpcode::kInt32SubWithOverflow:
+                cont->OverwriteAndNegateIfEqual(kOverflow);
+                return VisitBinop(selector, node, kMips64Dsub, cont);
+              default:
+                break;
+            }
+          }
+        }
+        break;
+      case IrOpcode::kWord32And:
+        return VisitWordCompare(selector, value, kMips64Tst32, cont, true);
+      case IrOpcode::kWord64And:
+        return VisitWordCompare(selector, value, kMips64Tst, cont, true);
+      default:
+        break;
+    }
+    break;
+  }
+
+  // Continuation could not be combined with a compare, emit compare against 0.
+  EmitWordCompareZero(selector, opcode, value, cont);
+}
+
+
+void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
+                                      BasicBlock* fbranch) {
+  FlagsContinuation cont(kNotEqual, tbranch, fbranch);
+  VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
+}
+
+
+void InstructionSelector::VisitWord32Equal(Node* const node) {
+  FlagsContinuation cont(kEqual, node);
+  Int32BinopMatcher m(node);
+  if (m.right().Is(0)) {
+    return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
+  }
+
+  VisitWord32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32LessThan(Node* node) {
+  FlagsContinuation cont(kSignedLessThan, node);
+  VisitWord32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kSignedLessThanOrEqual, node);
+  VisitWord32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitUint32LessThan(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThan, node);
+  VisitWord32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
+  VisitWord32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
+  if (Node* ovf = node->FindProjection(1)) {
+    FlagsContinuation cont(kOverflow, ovf);
+    return VisitBinop(this, node, kMips64Dadd, &cont);
+  }
+  FlagsContinuation cont;
+  VisitBinop(this, node, kMips64Dadd, &cont);
+}
+
+
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+  if (Node* ovf = node->FindProjection(1)) {
+    FlagsContinuation cont(kOverflow, ovf);
+    return VisitBinop(this, node, kMips64Dsub, &cont);
+  }
+  FlagsContinuation cont;
+  VisitBinop(this, node, kMips64Dsub, &cont);
+}
+
+
+void InstructionSelector::VisitWord64Equal(Node* const node) {
+  FlagsContinuation cont(kEqual, node);
+  Int64BinopMatcher m(node);
+  if (m.right().Is(0)) {
+    return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
+  }
+
+  VisitWord64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt64LessThan(Node* node) {
+  FlagsContinuation cont(kSignedLessThan, node);
+  VisitWord64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kSignedLessThanOrEqual, node);
+  VisitWord64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitUint64LessThan(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThan, node);
+  VisitWord64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64Equal(Node* node) {
+  FlagsContinuation cont(kUnorderedEqual, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64LessThan(Node* node) {
+  FlagsContinuation cont(kUnorderedLessThan, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnorderedLessThanOrEqual, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+// static
+MachineOperatorBuilder::Flags
+InstructionSelector::SupportedMachineOperatorFlags() {
+  return MachineOperatorBuilder::kFloat64Floor |
+         MachineOperatorBuilder::kFloat64Ceil |
+         MachineOperatorBuilder::kFloat64RoundTruncate;
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/mips64/linkage-mips64.cc b/src/compiler/mips64/linkage-mips64.cc
new file mode 100644
index 0000000..0e1a590
--- /dev/null
+++ b/src/compiler/mips64/linkage-mips64.cc
@@ -0,0 +1,67 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/assembler.h"
+#include "src/code-stubs.h"
+#include "src/compiler/linkage.h"
+#include "src/compiler/linkage-impl.h"
+#include "src/zone.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+struct MipsLinkageHelperTraits {
+  static Register ReturnValueReg() { return v0; }
+  static Register ReturnValue2Reg() { return v1; }
+  static Register JSCallFunctionReg() { return a1; }
+  static Register ContextReg() { return cp; }
+  static Register RuntimeCallFunctionReg() { return a1; }
+  static Register RuntimeCallArgCountReg() { return a0; }
+  static RegList CCalleeSaveRegisters() {
+    return s0.bit() | s1.bit() | s2.bit() | s3.bit() | s4.bit() | s5.bit() |
+           s6.bit() | s7.bit();
+  }
+  static Register CRegisterParameter(int i) {
+    static Register register_parameters[] = {a0, a1, a2, a3, a4, a5, a6, a7};
+    return register_parameters[i];
+  }
+  static int CRegisterParametersLength() { return 8; }
+};
+
+
+typedef LinkageHelper<MipsLinkageHelperTraits> LH;
+
+CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone,
+                                             CallDescriptor::Flags flags) {
+  return LH::GetJSCallDescriptor(zone, parameter_count, flags);
+}
+
+
+CallDescriptor* Linkage::GetRuntimeCallDescriptor(
+    Runtime::FunctionId function, int parameter_count,
+    Operator::Properties properties, Zone* zone) {
+  return LH::GetRuntimeCallDescriptor(zone, function, parameter_count,
+                                      properties);
+}
+
+
+CallDescriptor* Linkage::GetStubCallDescriptor(
+    const CallInterfaceDescriptor& descriptor, int stack_parameter_count,
+    CallDescriptor::Flags flags, Operator::Properties properties, Zone* zone) {
+  return LH::GetStubCallDescriptor(zone, descriptor, stack_parameter_count,
+                                   flags, properties);
+}
+
+
+CallDescriptor* Linkage::GetSimplifiedCDescriptor(Zone* zone,
+                                                  MachineSignature* sig) {
+  return LH::GetSimplifiedCDescriptor(zone, sig);
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/move-optimizer.cc b/src/compiler/move-optimizer.cc
new file mode 100644
index 0000000..330f32f
--- /dev/null
+++ b/src/compiler/move-optimizer.cc
@@ -0,0 +1,205 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/move-optimizer.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+MoveOptimizer::MoveOptimizer(Zone* local_zone, InstructionSequence* code)
+    : local_zone_(local_zone),
+      code_(code),
+      temp_vector_0_(local_zone),
+      temp_vector_1_(local_zone) {}
+
+
+void MoveOptimizer::Run() {
+  // First smash all consecutive moves into the left most move slot.
+  for (auto* block : code()->instruction_blocks()) {
+    GapInstruction* prev_gap = nullptr;
+    for (int index = block->code_start(); index < block->code_end(); ++index) {
+      auto instr = code()->instructions()[index];
+      if (!instr->IsGapMoves()) {
+        if (instr->IsSourcePosition() || instr->IsNop()) continue;
+        FinalizeMoves(&temp_vector_0_, &temp_vector_1_, prev_gap);
+        prev_gap = nullptr;
+        continue;
+      }
+      auto gap = GapInstruction::cast(instr);
+      // Find first non-empty slot.
+      int i = GapInstruction::FIRST_INNER_POSITION;
+      for (; i <= GapInstruction::LAST_INNER_POSITION; i++) {
+        auto move = gap->parallel_moves()[i];
+        if (move == nullptr) continue;
+        auto move_ops = move->move_operands();
+        auto op = move_ops->begin();
+        for (; op != move_ops->end(); ++op) {
+          if (!op->IsRedundant()) break;
+        }
+        if (op == move_ops->end()) {
+          move_ops->Rewind(0);  // Clear this redundant move.
+        } else {
+          break;  // Found index of first non-redundant move.
+        }
+      }
+      // Nothing to do here.
+      if (i == GapInstruction::LAST_INNER_POSITION + 1) {
+        if (prev_gap != nullptr) {
+          // Slide prev_gap down so we always know where to look for it.
+          std::swap(prev_gap->parallel_moves()[0], gap->parallel_moves()[0]);
+          prev_gap = gap;
+        }
+        continue;
+      }
+      // Move the first non-empty gap to position 0.
+      std::swap(gap->parallel_moves()[0], gap->parallel_moves()[i]);
+      auto left = gap->parallel_moves()[0];
+      // Compress everything into position 0.
+      for (++i; i <= GapInstruction::LAST_INNER_POSITION; ++i) {
+        auto move = gap->parallel_moves()[i];
+        if (move == nullptr) continue;
+        CompressMoves(&temp_vector_0_, left, move);
+      }
+      if (prev_gap != nullptr) {
+        // Smash left into prev_gap, killing left.
+        auto pred_moves = prev_gap->parallel_moves()[0];
+        CompressMoves(&temp_vector_0_, pred_moves, left);
+        std::swap(prev_gap->parallel_moves()[0], gap->parallel_moves()[0]);
+      }
+      prev_gap = gap;
+    }
+    FinalizeMoves(&temp_vector_0_, &temp_vector_1_, prev_gap);
+  }
+}
+
+
+static MoveOperands* PrepareInsertAfter(ParallelMove* left, MoveOperands* move,
+                                        Zone* zone) {
+  auto move_ops = left->move_operands();
+  MoveOperands* replacement = nullptr;
+  MoveOperands* to_eliminate = nullptr;
+  for (auto curr = move_ops->begin(); curr != move_ops->end(); ++curr) {
+    if (curr->IsEliminated()) continue;
+    if (curr->destination()->Equals(move->source())) {
+      DCHECK_EQ(nullptr, replacement);
+      replacement = curr;
+      if (to_eliminate != nullptr) break;
+    } else if (curr->destination()->Equals(move->destination())) {
+      DCHECK_EQ(nullptr, to_eliminate);
+      to_eliminate = curr;
+      if (replacement != nullptr) break;
+    }
+  }
+  DCHECK(!(replacement == to_eliminate && replacement != nullptr));
+  if (replacement != nullptr) {
+    auto new_source = new (zone) InstructionOperand(
+        replacement->source()->kind(), replacement->source()->index());
+    move->set_source(new_source);
+  }
+  return to_eliminate;
+}
+
+
+void MoveOptimizer::CompressMoves(MoveOpVector* eliminated, ParallelMove* left,
+                                  ParallelMove* right) {
+  DCHECK(eliminated->empty());
+  auto move_ops = right->move_operands();
+  // Modify the right moves in place and collect moves that will be killed by
+  // merging the two gaps.
+  for (auto op = move_ops->begin(); op != move_ops->end(); ++op) {
+    if (op->IsRedundant()) continue;
+    MoveOperands* to_eliminate = PrepareInsertAfter(left, op, code_zone());
+    if (to_eliminate != nullptr) {
+      eliminated->push_back(to_eliminate);
+    }
+  }
+  // Eliminate dead moves.  Must happen before insertion of new moves as the
+  // contents of eliminated are pointers into a list.
+  for (auto to_eliminate : *eliminated) {
+    to_eliminate->Eliminate();
+  }
+  eliminated->clear();
+  // Add all possibly modified moves from right side.
+  for (auto op = move_ops->begin(); op != move_ops->end(); ++op) {
+    if (op->IsRedundant()) continue;
+    left->move_operands()->Add(*op, code_zone());
+  }
+  // Nuke right.
+  move_ops->Rewind(0);
+}
+
+
+void MoveOptimizer::FinalizeMoves(MoveOpVector* loads, MoveOpVector* new_moves,
+                                  GapInstruction* gap) {
+  DCHECK(loads->empty());
+  DCHECK(new_moves->empty());
+  if (gap == nullptr) return;
+  // Split multiple loads of the same constant or stack slot off into the second
+  // slot and keep remaining moves in the first slot.
+  auto move_ops = gap->parallel_moves()[0]->move_operands();
+  for (auto move = move_ops->begin(); move != move_ops->end(); ++move) {
+    if (move->IsRedundant()) {
+      move->Eliminate();
+      continue;
+    }
+    if (!(move->source()->IsConstant() || move->source()->IsStackSlot() ||
+          move->source()->IsDoubleStackSlot()))
+      continue;
+    // Search for existing move to this slot.
+    MoveOperands* found = nullptr;
+    for (auto load : *loads) {
+      if (load->source()->Equals(move->source())) {
+        found = load;
+        break;
+      }
+    }
+    // Not found so insert.
+    if (found == nullptr) {
+      loads->push_back(move);
+      // Replace source with copy for later use.
+      auto dest = move->destination();
+      move->set_destination(new (code_zone())
+                            InstructionOperand(dest->kind(), dest->index()));
+      continue;
+    }
+    if ((found->destination()->IsStackSlot() ||
+         found->destination()->IsDoubleStackSlot()) &&
+        !(move->destination()->IsStackSlot() ||
+          move->destination()->IsDoubleStackSlot())) {
+      // Found a better source for this load.  Smash it in place to affect other
+      // loads that have already been split.
+      InstructionOperand::Kind found_kind = found->destination()->kind();
+      int found_index = found->destination()->index();
+      auto next_dest =
+          new (code_zone()) InstructionOperand(found_kind, found_index);
+      auto dest = move->destination();
+      found->destination()->ConvertTo(dest->kind(), dest->index());
+      move->set_destination(next_dest);
+    }
+    // move from load destination.
+    move->set_source(found->destination());
+    new_moves->push_back(move);
+  }
+  loads->clear();
+  if (new_moves->empty()) return;
+  // Insert all new moves into slot 1.
+  auto slot_1 = gap->GetOrCreateParallelMove(
+      static_cast<GapInstruction::InnerPosition>(1), code_zone());
+  DCHECK(slot_1->move_operands()->is_empty());
+  slot_1->move_operands()->AddBlock(MoveOperands(nullptr, nullptr),
+                                    static_cast<int>(new_moves->size()),
+                                    code_zone());
+  auto it = slot_1->move_operands()->begin();
+  for (auto new_move : *new_moves) {
+    std::swap(*new_move, *it);
+    ++it;
+  }
+  DCHECK_EQ(it, slot_1->move_operands()->end());
+  new_moves->clear();
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/move-optimizer.h b/src/compiler/move-optimizer.h
new file mode 100644
index 0000000..bbce686
--- /dev/null
+++ b/src/compiler/move-optimizer.h
@@ -0,0 +1,44 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_MOVE_OPTIMIZER_
+#define V8_COMPILER_MOVE_OPTIMIZER_
+
+#include "src/compiler/instruction.h"
+#include "src/zone-containers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class MoveOptimizer FINAL {
+ public:
+  MoveOptimizer(Zone* local_zone, InstructionSequence* code);
+  void Run();
+
+ private:
+  typedef ZoneVector<MoveOperands*> MoveOpVector;
+
+  InstructionSequence* code() const { return code_; }
+  Zone* local_zone() const { return local_zone_; }
+  Zone* code_zone() const { return code()->zone(); }
+
+  void CompressMoves(MoveOpVector* eliminated, ParallelMove* left,
+                     ParallelMove* right);
+  void FinalizeMoves(MoveOpVector* loads, MoveOpVector* new_moves,
+                     GapInstruction* gap);
+
+  Zone* const local_zone_;
+  InstructionSequence* const code_;
+  MoveOpVector temp_vector_0_;
+  MoveOpVector temp_vector_1_;
+
+  DISALLOW_COPY_AND_ASSIGN(MoveOptimizer);
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_MOVE_OPTIMIZER_
diff --git a/src/compiler/node-aux-data-inl.h b/src/compiler/node-aux-data-inl.h
index 79f1abf..d8db4b9 100644
--- a/src/compiler/node-aux-data-inl.h
+++ b/src/compiler/node-aux-data-inl.h
@@ -29,7 +29,7 @@
 
 
 template <class T>
-T NodeAuxData<T>::Get(Node* node) {
+T NodeAuxData<T>::Get(Node* node) const {
   int id = node->id();
   if (id >= static_cast<int>(aux_data_.size())) {
     return T();
diff --git a/src/compiler/node-aux-data.h b/src/compiler/node-aux-data.h
index 7acce33..a08dc58 100644
--- a/src/compiler/node-aux-data.h
+++ b/src/compiler/node-aux-data.h
@@ -21,7 +21,7 @@
   inline explicit NodeAuxData(Zone* zone);
 
   inline void Set(Node* node, const T& data);
-  inline T Get(Node* node);
+  inline T Get(Node* node) const;
 
  private:
   ZoneVector<T> aux_data_;
diff --git a/src/compiler/node-cache.cc b/src/compiler/node-cache.cc
index 7cda167..92a3fa0 100644
--- a/src/compiler/node-cache.cc
+++ b/src/compiler/node-cache.cc
@@ -4,65 +4,51 @@
 
 #include "src/compiler/node-cache.h"
 
+#include <cstring>
+
+#include "src/zone.h"
+#include "src/zone-containers.h"
+
 namespace v8 {
 namespace internal {
 namespace compiler {
 
-#define INITIAL_SIZE 16
-#define LINEAR_PROBE 5
+namespace {
 
-template <typename Key>
-int32_t NodeCacheHash(Key key) {
-  UNIMPLEMENTED();
-  return 0;
-}
+enum { kInitialSize = 16u, kLinearProbe = 5u };
 
-template <>
-inline int32_t NodeCacheHash(int32_t key) {
-  return ComputeIntegerHash(key, 0);
-}
+}  // namespace
 
 
-template <>
-inline int32_t NodeCacheHash(int64_t key) {
-  return ComputeLongHash(key);
-}
+template <typename Key, typename Hash, typename Pred>
+struct NodeCache<Key, Hash, Pred>::Entry {
+  Key key_;
+  Node* value_;
+};
 
 
-template <>
-inline int32_t NodeCacheHash(double key) {
-  return ComputeLongHash(bit_cast<int64_t>(key));
-}
-
-
-template <>
-inline int32_t NodeCacheHash(void* key) {
-  return ComputePointerHash(key);
-}
-
-
-template <typename Key>
-bool NodeCache<Key>::Resize(Zone* zone) {
+template <typename Key, typename Hash, typename Pred>
+bool NodeCache<Key, Hash, Pred>::Resize(Zone* zone) {
   if (size_ >= max_) return false;  // Don't grow past the maximum size.
 
   // Allocate a new block of entries 4x the size.
   Entry* old_entries = entries_;
-  int old_size = size_ + LINEAR_PROBE;
-  size_ = size_ * 4;
-  int num_entries = size_ + LINEAR_PROBE;
-  entries_ = zone->NewArray<Entry>(num_entries);
+  size_t old_size = size_ + kLinearProbe;
+  size_ *= 4;
+  size_t num_entries = size_ + kLinearProbe;
+  entries_ = zone->NewArray<Entry>(static_cast<int>(num_entries));
   memset(entries_, 0, sizeof(Entry) * num_entries);
 
   // Insert the old entries into the new block.
-  for (int i = 0; i < old_size; i++) {
+  for (size_t i = 0; i < old_size; ++i) {
     Entry* old = &old_entries[i];
-    if (old->value_ != NULL) {
-      int hash = NodeCacheHash(old->key_);
-      int start = hash & (size_ - 1);
-      int end = start + LINEAR_PROBE;
-      for (int j = start; j < end; j++) {
+    if (old->value_) {
+      size_t hash = hash_(old->key_);
+      size_t start = hash & (size_ - 1);
+      size_t end = start + kLinearProbe;
+      for (size_t j = start; j < end; ++j) {
         Entry* entry = &entries_[j];
-        if (entry->value_ == NULL) {
+        if (!entry->value_) {
           entry->key_ = old->key_;
           entry->value_ = old->value_;
           break;
@@ -74,28 +60,28 @@
 }
 
 
-template <typename Key>
-Node** NodeCache<Key>::Find(Zone* zone, Key key) {
-  int32_t hash = NodeCacheHash(key);
-  if (entries_ == NULL) {
+template <typename Key, typename Hash, typename Pred>
+Node** NodeCache<Key, Hash, Pred>::Find(Zone* zone, Key key) {
+  size_t hash = hash_(key);
+  if (!entries_) {
     // Allocate the initial entries and insert the first entry.
-    int num_entries = INITIAL_SIZE + LINEAR_PROBE;
-    entries_ = zone->NewArray<Entry>(num_entries);
-    size_ = INITIAL_SIZE;
+    size_t num_entries = kInitialSize + kLinearProbe;
+    entries_ = zone->NewArray<Entry>(static_cast<int>(num_entries));
+    size_ = kInitialSize;
     memset(entries_, 0, sizeof(Entry) * num_entries);
-    Entry* entry = &entries_[hash & (INITIAL_SIZE - 1)];
+    Entry* entry = &entries_[hash & (kInitialSize - 1)];
     entry->key_ = key;
     return &entry->value_;
   }
 
-  while (true) {
+  for (;;) {
     // Search up to N entries after (linear probing).
-    int start = hash & (size_ - 1);
-    int end = start + LINEAR_PROBE;
-    for (int i = start; i < end; i++) {
+    size_t start = hash & (size_ - 1);
+    size_t end = start + kLinearProbe;
+    for (size_t i = start; i < end; i++) {
       Entry* entry = &entries_[i];
-      if (entry->key_ == key) return &entry->value_;
-      if (entry->value_ == NULL) {
+      if (pred_(entry->key_, key)) return &entry->value_;
+      if (!entry->value_) {
         entry->key_ = key;
         return &entry->value_;
       }
@@ -107,14 +93,28 @@
   // If resized to maximum and still didn't find space, overwrite an entry.
   Entry* entry = &entries_[hash & (size_ - 1)];
   entry->key_ = key;
-  entry->value_ = NULL;
+  entry->value_ = nullptr;
   return &entry->value_;
 }
 
 
-template class NodeCache<int64_t>;
+template <typename Key, typename Hash, typename Pred>
+void NodeCache<Key, Hash, Pred>::GetCachedNodes(ZoneVector<Node*>* nodes) {
+  if (entries_) {
+    for (size_t i = 0; i < size_ + kLinearProbe; i++) {
+      if (entries_[i].value_) nodes->push_back(entries_[i].value_);
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Instantiations
+
+
 template class NodeCache<int32_t>;
-template class NodeCache<void*>;
-}
-}
-}  // namespace v8::internal::compiler
+template class NodeCache<int64_t>;
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/node-cache.h b/src/compiler/node-cache.h
index 35352ea..b123922 100644
--- a/src/compiler/node-cache.h
+++ b/src/compiler/node-cache.h
@@ -5,20 +5,33 @@
 #ifndef V8_COMPILER_NODE_CACHE_H_
 #define V8_COMPILER_NODE_CACHE_H_
 
-#include "src/v8.h"
-
-#include "src/compiler/node.h"
+#include "src/base/functional.h"
+#include "src/base/macros.h"
 
 namespace v8 {
 namespace internal {
+
+// Forward declarations.
+class Zone;
+template <typename>
+class ZoneVector;
+
+
 namespace compiler {
 
+// Forward declarations.
+class Node;
+
+
 // A cache for nodes based on a key. Useful for implementing canonicalization of
 // nodes such as constants, parameters, etc.
-template <typename Key>
-class NodeCache {
+template <typename Key, typename Hash = base::hash<Key>,
+          typename Pred = std::equal_to<Key> >
+class NodeCache FINAL {
  public:
-  explicit NodeCache(int max = 256) : entries_(NULL), size_(0), max_(max) {}
+  explicit NodeCache(unsigned max = 256)
+      : entries_(nullptr), size_(0), max_(max) {}
+  ~NodeCache() {}
 
   // Search for node associated with {key} and return a pointer to a memory
   // location in this cache that stores an entry for the key. If the location
@@ -29,25 +42,34 @@
   // too full or encounters too many hash collisions.
   Node** Find(Zone* zone, Key key);
 
+  // Appends all nodes from this cache to {nodes}.
+  void GetCachedNodes(ZoneVector<Node*>* nodes);
+
  private:
-  struct Entry {
-    Key key_;
-    Node* value_;
-  };
+  struct Entry;
 
   Entry* entries_;  // lazily-allocated hash entries.
-  int32_t size_;
-  int32_t max_;
+  size_t size_;
+  size_t max_;
+  Hash hash_;
+  Pred pred_;
 
   bool Resize(Zone* zone);
+
+  DISALLOW_COPY_AND_ASSIGN(NodeCache);
 };
 
 // Various default cache types.
-typedef NodeCache<int64_t> Int64NodeCache;
 typedef NodeCache<int32_t> Int32NodeCache;
-typedef NodeCache<void*> PtrNodeCache;
-}
-}
-}  // namespace v8::internal::compiler
+typedef NodeCache<int64_t> Int64NodeCache;
+#if V8_HOST_ARCH_32_BIT
+typedef Int32NodeCache IntPtrNodeCache;
+#else
+typedef Int64NodeCache IntPtrNodeCache;
+#endif
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_NODE_CACHE_H_
diff --git a/src/compiler/node-matchers.h b/src/compiler/node-matchers.h
index e62eaee..fc11a0a 100644
--- a/src/compiler/node-matchers.h
+++ b/src/compiler/node-matchers.h
@@ -5,8 +5,11 @@
 #ifndef V8_COMPILER_NODE_MATCHERS_H_
 #define V8_COMPILER_NODE_MATCHERS_H_
 
+#include <cmath>
+
 #include "src/compiler/node.h"
 #include "src/compiler/operator.h"
+#include "src/unique.h"
 
 namespace v8 {
 namespace internal {
@@ -38,6 +41,8 @@
 // A pattern matcher for abitrary value constants.
 template <typename T, IrOpcode::Value kOpcode>
 struct ValueMatcher : public NodeMatcher {
+  typedef T ValueType;
+
   explicit ValueMatcher(Node* node)
       : NodeMatcher(node), value_(), has_value_(opcode() == kOpcode) {
     if (has_value_) {
@@ -65,21 +70,62 @@
 };
 
 
+template <>
+inline ValueMatcher<int64_t, IrOpcode::kInt64Constant>::ValueMatcher(Node* node)
+    : NodeMatcher(node), value_(), has_value_(false) {
+  if (opcode() == IrOpcode::kInt32Constant) {
+    value_ = OpParameter<int32_t>(node);
+    has_value_ = true;
+  } else if (opcode() == IrOpcode::kInt64Constant) {
+    value_ = OpParameter<int64_t>(node);
+    has_value_ = true;
+  }
+}
+
+
+template <>
+inline ValueMatcher<uint64_t, IrOpcode::kInt64Constant>::ValueMatcher(
+    Node* node)
+    : NodeMatcher(node), value_(), has_value_(false) {
+  if (opcode() == IrOpcode::kInt32Constant) {
+    value_ = OpParameter<uint32_t>(node);
+    has_value_ = true;
+  } else if (opcode() == IrOpcode::kInt64Constant) {
+    value_ = OpParameter<uint64_t>(node);
+    has_value_ = true;
+  }
+}
+
+
 // A pattern matcher for integer constants.
 template <typename T, IrOpcode::Value kOpcode>
 struct IntMatcher FINAL : public ValueMatcher<T, kOpcode> {
   explicit IntMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
 
+  bool IsMultipleOf(T n) const {
+    return this->HasValue() && (this->Value() % n) == 0;
+  }
   bool IsPowerOf2() const {
     return this->HasValue() && this->Value() > 0 &&
            (this->Value() & (this->Value() - 1)) == 0;
   }
+  bool IsNegativePowerOf2() const {
+    return this->HasValue() && this->Value() < 0 &&
+           (-this->Value() & (-this->Value() - 1)) == 0;
+  }
 };
 
 typedef IntMatcher<int32_t, IrOpcode::kInt32Constant> Int32Matcher;
 typedef IntMatcher<uint32_t, IrOpcode::kInt32Constant> Uint32Matcher;
 typedef IntMatcher<int64_t, IrOpcode::kInt64Constant> Int64Matcher;
 typedef IntMatcher<uint64_t, IrOpcode::kInt64Constant> Uint64Matcher;
+#if V8_HOST_ARCH_32_BIT
+typedef Int32Matcher IntPtrMatcher;
+typedef Uint32Matcher UintPtrMatcher;
+#else
+typedef Int64Matcher IntPtrMatcher;
+typedef Uint64Matcher UintPtrMatcher;
+#endif
 
 
 // A pattern matcher for floating point constants.
@@ -87,6 +133,9 @@
 struct FloatMatcher FINAL : public ValueMatcher<T, kOpcode> {
   explicit FloatMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
 
+  bool IsMinusZero() const {
+    return this->Is(0.0) && std::signbit(this->Value());
+  }
   bool IsNaN() const { return this->HasValue() && std::isnan(this->Value()); }
 };
 
@@ -108,11 +157,18 @@
 // right hand sides of a binary operation and can put constants on the right
 // if they appear on the left hand side of a commutative operation.
 template <typename Left, typename Right>
-struct BinopMatcher FINAL : public NodeMatcher {
+struct BinopMatcher : public NodeMatcher {
   explicit BinopMatcher(Node* node)
       : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
     if (HasProperty(Operator::kCommutative)) PutConstantOnRight();
   }
+  BinopMatcher(Node* node, bool allow_input_swap)
+      : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
+    if (allow_input_swap) PutConstantOnRight();
+  }
+
+  typedef Left LeftMatcher;
+  typedef Right RightMatcher;
 
   const Left& left() const { return left_; }
   const Right& right() const { return right_; }
@@ -120,12 +176,17 @@
   bool IsFoldable() const { return left().HasValue() && right().HasValue(); }
   bool LeftEqualsRight() const { return left().node() == right().node(); }
 
+ protected:
+  void SwapInputs() {
+    std::swap(left_, right_);
+    node()->ReplaceInput(0, left().node());
+    node()->ReplaceInput(1, right().node());
+  }
+
  private:
   void PutConstantOnRight() {
     if (left().HasValue() && !right().HasValue()) {
-      std::swap(left_, right_);
-      node()->ReplaceInput(0, left().node());
-      node()->ReplaceInput(1, right().node());
+      SwapInputs();
     }
   }
 
@@ -137,7 +198,318 @@
 typedef BinopMatcher<Uint32Matcher, Uint32Matcher> Uint32BinopMatcher;
 typedef BinopMatcher<Int64Matcher, Int64Matcher> Int64BinopMatcher;
 typedef BinopMatcher<Uint64Matcher, Uint64Matcher> Uint64BinopMatcher;
+typedef BinopMatcher<IntPtrMatcher, IntPtrMatcher> IntPtrBinopMatcher;
+typedef BinopMatcher<UintPtrMatcher, UintPtrMatcher> UintPtrBinopMatcher;
 typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher;
+typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher;
+
+
+template <class BinopMatcher, IrOpcode::Value kMulOpcode,
+          IrOpcode::Value kShiftOpcode>
+struct ScaleMatcher {
+  explicit ScaleMatcher(Node* node, bool allow_power_of_two_plus_one = false)
+      : scale_(-1), power_of_two_plus_one_(false) {
+    if (node->InputCount() < 2) return;
+    BinopMatcher m(node);
+    if (node->opcode() == kShiftOpcode) {
+      if (m.right().HasValue()) {
+        typename BinopMatcher::RightMatcher::ValueType value =
+            m.right().Value();
+        if (value >= 0 && value <= 3) {
+          scale_ = static_cast<int>(value);
+        }
+      }
+    } else if (node->opcode() == kMulOpcode) {
+      if (m.right().HasValue()) {
+        typename BinopMatcher::RightMatcher::ValueType value =
+            m.right().Value();
+        if (value == 1) {
+          scale_ = 0;
+        } else if (value == 2) {
+          scale_ = 1;
+        } else if (value == 4) {
+          scale_ = 2;
+        } else if (value == 8) {
+          scale_ = 3;
+        } else if (allow_power_of_two_plus_one) {
+          if (value == 3) {
+            scale_ = 1;
+            power_of_two_plus_one_ = true;
+          } else if (value == 5) {
+            scale_ = 2;
+            power_of_two_plus_one_ = true;
+          } else if (value == 9) {
+            scale_ = 3;
+            power_of_two_plus_one_ = true;
+          }
+        }
+      }
+    }
+  }
+
+  bool matches() const { return scale_ != -1; }
+  int scale() const { return scale_; }
+  bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
+
+ private:
+  int scale_;
+  bool power_of_two_plus_one_;
+};
+
+typedef ScaleMatcher<Int32BinopMatcher, IrOpcode::kInt32Mul,
+                     IrOpcode::kWord32Shl> Int32ScaleMatcher;
+typedef ScaleMatcher<Int64BinopMatcher, IrOpcode::kInt64Mul,
+                     IrOpcode::kWord64Shl> Int64ScaleMatcher;
+
+
+template <class BinopMatcher, IrOpcode::Value kAddOpcode,
+          IrOpcode::Value kMulOpcode, IrOpcode::Value kShiftOpcode>
+struct AddMatcher : public BinopMatcher {
+  static const IrOpcode::Value kOpcode = kAddOpcode;
+  typedef ScaleMatcher<BinopMatcher, kMulOpcode, kShiftOpcode> Matcher;
+
+  AddMatcher(Node* node, bool allow_input_swap)
+      : BinopMatcher(node, allow_input_swap),
+        scale_(-1),
+        power_of_two_plus_one_(false) {
+    Initialize(node, allow_input_swap);
+  }
+  explicit AddMatcher(Node* node)
+      : BinopMatcher(node, node->op()->HasProperty(Operator::kCommutative)),
+        scale_(-1),
+        power_of_two_plus_one_(false) {
+    Initialize(node, node->op()->HasProperty(Operator::kCommutative));
+  }
+
+  bool HasIndexInput() const { return scale_ != -1; }
+  Node* IndexInput() const {
+    DCHECK(HasIndexInput());
+    return this->left().node()->InputAt(0);
+  }
+  int scale() const {
+    DCHECK(HasIndexInput());
+    return scale_;
+  }
+  bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
+
+ private:
+  void Initialize(Node* node, bool allow_input_swap) {
+    Matcher left_matcher(this->left().node(), true);
+    if (left_matcher.matches()) {
+      scale_ = left_matcher.scale();
+      power_of_two_plus_one_ = left_matcher.power_of_two_plus_one();
+      return;
+    }
+
+    if (!allow_input_swap) {
+      return;
+    }
+
+    Matcher right_matcher(this->right().node(), true);
+    if (right_matcher.matches()) {
+      scale_ = right_matcher.scale();
+      power_of_two_plus_one_ = right_matcher.power_of_two_plus_one();
+      this->SwapInputs();
+      return;
+    }
+
+    if (this->right().opcode() == kAddOpcode &&
+        this->left().opcode() != kAddOpcode) {
+      this->SwapInputs();
+    }
+  }
+
+  int scale_;
+  bool power_of_two_plus_one_;
+};
+
+typedef AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Mul,
+                   IrOpcode::kWord32Shl> Int32AddMatcher;
+typedef AddMatcher<Int64BinopMatcher, IrOpcode::kInt64Add, IrOpcode::kInt64Mul,
+                   IrOpcode::kWord64Shl> Int64AddMatcher;
+
+
+template <class AddMatcher>
+struct BaseWithIndexAndDisplacementMatcher {
+  BaseWithIndexAndDisplacementMatcher(Node* node, bool allow_input_swap)
+      : matches_(false),
+        index_(NULL),
+        scale_(0),
+        base_(NULL),
+        displacement_(NULL) {
+    Initialize(node, allow_input_swap);
+  }
+
+  explicit BaseWithIndexAndDisplacementMatcher(Node* node)
+      : matches_(false),
+        index_(NULL),
+        scale_(0),
+        base_(NULL),
+        displacement_(NULL) {
+    Initialize(node, node->op()->HasProperty(Operator::kCommutative));
+  }
+
+  bool matches() const { return matches_; }
+  Node* index() const { return index_; }
+  int scale() const { return scale_; }
+  Node* base() const { return base_; }
+  Node* displacement() const { return displacement_; }
+
+ private:
+  bool matches_;
+  Node* index_;
+  int scale_;
+  Node* base_;
+  Node* displacement_;
+
+  void Initialize(Node* node, bool allow_input_swap) {
+    // The BaseWithIndexAndDisplacementMatcher canonicalizes the order of
+    // displacements and scale factors that are used as inputs, so instead of
+    // enumerating all possible patterns by brute force, checking for node
+    // clusters using the following templates in the following order suffices to
+    // find all of the interesting cases (S = index * scale, B = base input, D =
+    // displacement input):
+    // (S + (B + D))
+    // (S + (B + B))
+    // (S + D)
+    // (S + B)
+    // ((S + D) + B)
+    // ((S + B) + D)
+    // ((B + D) + B)
+    // ((B + B) + D)
+    // (B + D)
+    // (B + B)
+    if (node->InputCount() < 2) return;
+    AddMatcher m(node, allow_input_swap);
+    Node* left = m.left().node();
+    Node* right = m.right().node();
+    Node* displacement = NULL;
+    Node* base = NULL;
+    Node* index = NULL;
+    Node* scale_expression = NULL;
+    bool power_of_two_plus_one = false;
+    int scale = 0;
+    if (m.HasIndexInput() && left->OwnedBy(node)) {
+      index = m.IndexInput();
+      scale = m.scale();
+      scale_expression = left;
+      power_of_two_plus_one = m.power_of_two_plus_one();
+      if (right->opcode() == AddMatcher::kOpcode && right->OwnedBy(node)) {
+        AddMatcher right_matcher(right);
+        if (right_matcher.right().HasValue()) {
+          // (S + (B + D))
+          base = right_matcher.left().node();
+          displacement = right_matcher.right().node();
+        } else {
+          // (S + (B + B))
+          base = right;
+        }
+      } else if (m.right().HasValue()) {
+        // (S + D)
+        displacement = right;
+      } else {
+        // (S + B)
+        base = right;
+      }
+    } else {
+      if (left->opcode() == AddMatcher::kOpcode && left->OwnedBy(node)) {
+        AddMatcher left_matcher(left);
+        Node* left_left = left_matcher.left().node();
+        Node* left_right = left_matcher.right().node();
+        if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) {
+          if (left_matcher.right().HasValue()) {
+            // ((S + D) + B)
+            index = left_matcher.IndexInput();
+            scale = left_matcher.scale();
+            scale_expression = left_left;
+            power_of_two_plus_one = left_matcher.power_of_two_plus_one();
+            displacement = left_right;
+            base = right;
+          } else if (m.right().HasValue()) {
+            // ((S + B) + D)
+            index = left_matcher.IndexInput();
+            scale = left_matcher.scale();
+            scale_expression = left_left;
+            power_of_two_plus_one = left_matcher.power_of_two_plus_one();
+            base = left_right;
+            displacement = right;
+          } else {
+            // (B + B)
+            index = left;
+            base = right;
+          }
+        } else {
+          if (left_matcher.right().HasValue()) {
+            // ((B + D) + B)
+            index = left_left;
+            displacement = left_right;
+            base = right;
+          } else if (m.right().HasValue()) {
+            // ((B + B) + D)
+            index = left_left;
+            base = left_right;
+            displacement = right;
+          } else {
+            // (B + B)
+            index = left;
+            base = right;
+          }
+        }
+      } else {
+        if (m.right().HasValue()) {
+          // (B + D)
+          base = left;
+          displacement = right;
+        } else {
+          // (B + B)
+          base = left;
+          index = right;
+        }
+      }
+    }
+    int64_t value = 0;
+    if (displacement != NULL) {
+      switch (displacement->opcode()) {
+        case IrOpcode::kInt32Constant: {
+          value = OpParameter<int32_t>(displacement);
+          break;
+        }
+        case IrOpcode::kInt64Constant: {
+          value = OpParameter<int64_t>(displacement);
+          break;
+        }
+        default:
+          UNREACHABLE();
+          break;
+      }
+      if (value == 0) {
+        displacement = NULL;
+      }
+    }
+    if (power_of_two_plus_one) {
+      if (base != NULL) {
+        // If the scale requires explicitly using the index as the base, but a
+        // base is already part of the match, then the (1 << N + 1) scale factor
+        // can't be folded into the match and the entire index * scale
+        // calculation must be computed separately.
+        index = scale_expression;
+        scale = 0;
+      } else {
+        base = index;
+      }
+    }
+    base_ = base;
+    displacement_ = displacement;
+    index_ = index;
+    scale_ = scale;
+    matches_ = true;
+  }
+};
+
+typedef BaseWithIndexAndDisplacementMatcher<Int32AddMatcher>
+    BaseWithIndexAndDisplacement32Matcher;
+typedef BaseWithIndexAndDisplacementMatcher<Int64AddMatcher>
+    BaseWithIndexAndDisplacement64Matcher;
 
 }  // namespace compiler
 }  // namespace internal
diff --git a/src/compiler/node-properties-inl.h b/src/compiler/node-properties-inl.h
index 3f6d531..0d29614 100644
--- a/src/compiler/node-properties-inl.h
+++ b/src/compiler/node-properties-inl.h
@@ -8,11 +8,9 @@
 #include "src/v8.h"
 
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/node-properties.h"
 #include "src/compiler/opcodes.h"
 #include "src/compiler/operator.h"
-#include "src/compiler/operator-properties-inl.h"
 #include "src/compiler/operator-properties.h"
 
 namespace v8 {
@@ -44,8 +42,7 @@
 
 
 inline int NodeProperties::PastValueIndex(Node* node) {
-  return FirstValueIndex(node) +
-         OperatorProperties::GetValueInputCount(node->op());
+  return FirstValueIndex(node) + node->op()->ValueInputCount();
 }
 
 inline int NodeProperties::PastContextIndex(Node* node) {
@@ -59,13 +56,11 @@
 }
 
 inline int NodeProperties::PastEffectIndex(Node* node) {
-  return FirstEffectIndex(node) +
-         OperatorProperties::GetEffectInputCount(node->op());
+  return FirstEffectIndex(node) + node->op()->EffectInputCount();
 }
 
 inline int NodeProperties::PastControlIndex(Node* node) {
-  return FirstControlIndex(node) +
-         OperatorProperties::GetControlInputCount(node->op());
+  return FirstControlIndex(node) + node->op()->ControlInputCount();
 }
 
 
@@ -73,8 +68,7 @@
 // Input accessors.
 
 inline Node* NodeProperties::GetValueInput(Node* node, int index) {
-  DCHECK(0 <= index &&
-         index < OperatorProperties::GetValueInputCount(node->op()));
+  DCHECK(0 <= index && index < node->op()->ValueInputCount());
   return node->InputAt(FirstValueIndex(node) + index);
 }
 
@@ -89,14 +83,12 @@
 }
 
 inline Node* NodeProperties::GetEffectInput(Node* node, int index) {
-  DCHECK(0 <= index &&
-         index < OperatorProperties::GetEffectInputCount(node->op()));
+  DCHECK(0 <= index && index < node->op()->EffectInputCount());
   return node->InputAt(FirstEffectIndex(node) + index);
 }
 
 inline Node* NodeProperties::GetControlInput(Node* node, int index) {
-  DCHECK(0 <= index &&
-         index < OperatorProperties::GetControlInputCount(node->op()));
+  DCHECK(0 <= index && index < node->op()->ControlInputCount());
   return node->InputAt(FirstControlIndex(node) + index);
 }
 
@@ -108,7 +100,7 @@
 // -----------------------------------------------------------------------------
 // Edge kinds.
 
-inline bool NodeProperties::IsInputRange(Node::Edge edge, int first, int num) {
+inline bool NodeProperties::IsInputRange(Edge edge, int first, int num) {
   // TODO(titzer): edge.index() is linear time;
   // edges maybe need to be marked as value/effect/control.
   if (num == 0) return false;
@@ -116,28 +108,28 @@
   return first <= index && index < first + num;
 }
 
-inline bool NodeProperties::IsValueEdge(Node::Edge edge) {
+inline bool NodeProperties::IsValueEdge(Edge edge) {
   Node* node = edge.from();
   return IsInputRange(edge, FirstValueIndex(node),
-                      OperatorProperties::GetValueInputCount(node->op()));
+                      node->op()->ValueInputCount());
 }
 
-inline bool NodeProperties::IsContextEdge(Node::Edge edge) {
+inline bool NodeProperties::IsContextEdge(Edge edge) {
   Node* node = edge.from();
   return IsInputRange(edge, FirstContextIndex(node),
                       OperatorProperties::GetContextInputCount(node->op()));
 }
 
-inline bool NodeProperties::IsEffectEdge(Node::Edge edge) {
+inline bool NodeProperties::IsEffectEdge(Edge edge) {
   Node* node = edge.from();
   return IsInputRange(edge, FirstEffectIndex(node),
-                      OperatorProperties::GetEffectInputCount(node->op()));
+                      node->op()->EffectInputCount());
 }
 
-inline bool NodeProperties::IsControlEdge(Node::Edge edge) {
+inline bool NodeProperties::IsControlEdge(Edge edge) {
   Node* node = edge.from();
   return IsInputRange(edge, FirstControlIndex(node),
-                      OperatorProperties::GetControlInputCount(node->op()));
+                      node->op()->ControlInputCount());
 }
 
 
@@ -158,7 +150,7 @@
 
 inline void NodeProperties::ReplaceEffectInput(Node* node, Node* effect,
                                                int index) {
-  DCHECK(index < OperatorProperties::GetEffectInputCount(node->op()));
+  DCHECK(index < node->op()->EffectInputCount());
   return node->ReplaceInput(FirstEffectIndex(node) + index, effect);
 }
 
@@ -169,7 +161,7 @@
 }
 
 inline void NodeProperties::RemoveNonValueInputs(Node* node) {
-  node->TrimInputCount(OperatorProperties::GetValueInputCount(node->op()));
+  node->TrimInputCount(node->op()->ValueInputCount());
 }
 
 
@@ -177,19 +169,18 @@
 // {effect}. If {effect == NULL}, then use the effect input to {node}.
 inline void NodeProperties::ReplaceWithValue(Node* node, Node* value,
                                              Node* effect) {
-  DCHECK(!OperatorProperties::HasControlOutput(node->op()));
-  if (effect == NULL && OperatorProperties::HasEffectInput(node->op())) {
+  DCHECK(node->op()->ControlOutputCount() == 0);
+  if (effect == NULL && node->op()->EffectInputCount() > 0) {
     effect = NodeProperties::GetEffectInput(node);
   }
 
   // Requires distinguishing between value and effect edges.
-  UseIter iter = node->uses().begin();
-  while (iter != node->uses().end()) {
-    if (NodeProperties::IsEffectEdge(iter.edge())) {
+  for (Edge edge : node->use_edges()) {
+    if (NodeProperties::IsEffectEdge(edge)) {
       DCHECK_NE(NULL, effect);
-      iter = iter.UpdateToAndIncrement(effect);
+      edge.UpdateTo(effect);
     } else {
-      iter = iter.UpdateToAndIncrement(value);
+      edge.UpdateTo(value);
     }
   }
 }
@@ -198,12 +189,35 @@
 // -----------------------------------------------------------------------------
 // Type Bounds.
 
-inline Bounds NodeProperties::GetBounds(Node* node) { return node->bounds(); }
+inline bool NodeProperties::IsTyped(Node* node) {
+  Bounds bounds = node->bounds();
+  DCHECK((bounds.lower == NULL) == (bounds.upper == NULL));
+  return bounds.upper != NULL;
+}
+
+inline Bounds NodeProperties::GetBounds(Node* node) {
+  DCHECK(IsTyped(node));
+  return node->bounds();
+}
+
+inline void NodeProperties::RemoveBounds(Node* node) {
+  Bounds empty;
+  node->set_bounds(empty);
+}
 
 inline void NodeProperties::SetBounds(Node* node, Bounds b) {
+  DCHECK(b.lower != NULL && b.upper != NULL);
   node->set_bounds(b);
 }
 
+inline bool NodeProperties::AllValueInputsAreTyped(Node* node) {
+  int input_count = node->op()->ValueInputCount();
+  for (int i = 0; i < input_count; ++i) {
+    if (!IsTyped(GetValueInput(node, i))) return false;
+  }
+  return true;
+}
+
 
 }
 }
diff --git a/src/compiler/node-properties.h b/src/compiler/node-properties.h
index 94bd731..025be78 100644
--- a/src/compiler/node-properties.h
+++ b/src/compiler/node-properties.h
@@ -25,10 +25,10 @@
 
   static inline int GetFrameStateIndex(Node* node);
 
-  static inline bool IsValueEdge(Node::Edge edge);
-  static inline bool IsContextEdge(Node::Edge edge);
-  static inline bool IsEffectEdge(Node::Edge edge);
-  static inline bool IsControlEdge(Node::Edge edge);
+  static inline bool IsValueEdge(Edge edge);
+  static inline bool IsContextEdge(Edge edge);
+  static inline bool IsEffectEdge(Edge edge);
+  static inline bool IsControlEdge(Edge edge);
 
   static inline bool IsControl(Node* node);
 
@@ -40,8 +40,11 @@
   static inline void ReplaceWithValue(Node* node, Node* value,
                                       Node* effect = NULL);
 
+  static inline bool IsTyped(Node* node);
   static inline Bounds GetBounds(Node* node);
   static inline void SetBounds(Node* node, Bounds bounds);
+  static inline void RemoveBounds(Node* node);
+  static inline bool AllValueInputsAreTyped(Node* node);
 
   static inline int FirstValueIndex(Node* node);
   static inline int FirstContextIndex(Node* node);
@@ -54,7 +57,7 @@
   static inline int PastEffectIndex(Node* node);
   static inline int PastControlIndex(Node* node);
 
-  static inline bool IsInputRange(Node::Edge edge, int first, int count);
+  static inline bool IsInputRange(Edge edge, int first, int count);
 };
 
 }  // namespace compiler
diff --git a/src/compiler/node.cc b/src/compiler/node.cc
index 7df736e..8f44c24 100644
--- a/src/compiler/node.cc
+++ b/src/compiler/node.cc
@@ -4,12 +4,54 @@
 
 #include "src/compiler/node.h"
 
-#include "src/compiler/generic-node-inl.h"
+#include "src/compiler/graph.h"
+#include "src/zone.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
+Node::Node(NodeId id, int input_count, int reserved_input_count)
+    : id_(id),
+      bit_field_(InputCountField::encode(input_count) |
+                 ReservedInputCountField::encode(reserved_input_count) |
+                 HasAppendableInputsField::encode(false)),
+      first_use_(nullptr),
+      last_use_(nullptr) {
+  inputs_.static_ = reinterpret_cast<Input*>(this + 1);
+}
+
+
+Node* Node::New(Graph* graph, int input_count, Node** inputs,
+                bool has_extensible_inputs) {
+  size_t node_size = sizeof(Node);
+  int reserve_input_count = has_extensible_inputs ? kDefaultReservedInputs : 0;
+  size_t inputs_size = (input_count + reserve_input_count) * sizeof(Input);
+  size_t uses_size = input_count * sizeof(Use);
+  int size = static_cast<int>(node_size + inputs_size + uses_size);
+  Zone* zone = graph->zone();
+  void* buffer = zone->New(size);
+  Node* result =
+      new (buffer) Node(graph->NextNodeID(), input_count, reserve_input_count);
+  Input* input =
+      reinterpret_cast<Input*>(reinterpret_cast<char*>(buffer) + node_size);
+  Use* use =
+      reinterpret_cast<Use*>(reinterpret_cast<char*>(input) + inputs_size);
+
+  for (int current = 0; current < input_count; ++current) {
+    Node* to = *inputs++;
+    input->to = to;
+    input->use = use;
+    use->input_index = current;
+    use->from = result;
+    to->AppendUse(use);
+    ++use;
+    ++input;
+  }
+  return result;
+}
+
+
 void Node::Kill() {
   DCHECK_NOT_NULL(op());
   RemoveAllInputs();
@@ -42,14 +84,31 @@
 }
 
 
-OStream& operator<<(OStream& os, const Operator& op) { return op.PrintTo(os); }
+int Node::UseCount() const {
+  int use_count = 0;
+  for (const Use* use = first_use_; use; use = use->next) {
+    ++use_count;
+  }
+  return use_count;
+}
 
 
-OStream& operator<<(OStream& os, const Node& n) {
+Node* Node::UseAt(int index) const {
+  DCHECK_LE(0, index);
+  DCHECK_LT(index, UseCount());
+  Use* current = first_use_;
+  while (index-- != 0) {
+    current = current->next;
+  }
+  return current->from;
+}
+
+
+std::ostream& operator<<(std::ostream& os, const Node& n) {
   os << n.id() << ": " << *n.op();
-  if (n.op()->InputCount() != 0) {
+  if (n.InputCount() > 0) {
     os << "(";
-    for (int i = 0; i < n.op()->InputCount(); ++i) {
+    for (int i = 0; i < n.InputCount(); ++i) {
       if (i != 0) os << ", ";
       os << n.InputAt(i)->id();
     }
diff --git a/src/compiler/node.h b/src/compiler/node.h
index c3f5a53..2295b7b 100644
--- a/src/compiler/node.h
+++ b/src/compiler/node.h
@@ -9,20 +9,55 @@
 #include <set>
 #include <vector>
 
-#include "src/compiler/generic-algorithm.h"
-#include "src/compiler/generic-node.h"
+#include "src/v8.h"
+
 #include "src/compiler/opcodes.h"
 #include "src/compiler/operator.h"
 #include "src/types.h"
 #include "src/zone.h"
 #include "src/zone-allocator.h"
+#include "src/zone-containers.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
-class NodeData {
+// Forward declarations.
+class Edge;
+class Graph;
+
+
+// Marks are used during traversal of the graph to distinguish states of nodes.
+// Each node has a mark which is a monotonically increasing integer, and a
+// {NodeMarker} has a range of values that indicate states of a node.
+typedef uint32_t Mark;
+
+// NodeIds are identifying numbers for nodes that can be used to index auxiliary
+// out-of-line data associated with each node.
+typedef int NodeId;
+
+// A Node is the basic primitive of graphs. Nodes are chained together by
+// input/use chains but by default otherwise contain only an identifying number
+// which specific applications of graphs and nodes can use to index auxiliary
+// out-of-line data, especially transient data.
+//
+// In addition Nodes only contain a mutable Operator that may change during
+// compilation, e.g. during lowering passes. Other information that needs to be
+// associated with Nodes during compilation must be stored out-of-line indexed
+// by the Node's id.
+class Node FINAL {
  public:
+  void Initialize(const Operator* op) {
+    set_op(op);
+    set_mark(0);
+  }
+
+  bool IsDead() const { return InputCount() > 0 && InputAt(0) == NULL; }
+  void Kill();
+
+  void CollectProjections(ZoneVector<Node*>* projections);
+  Node* FindProjection(size_t projection_index);
+
   const Operator* op() const { return op_; }
   void set_op(const Operator* op) { op_ = op; }
 
@@ -31,44 +66,387 @@
     return static_cast<IrOpcode::Value>(op_->opcode());
   }
 
-  Bounds bounds() { return bounds_; }
+  NodeId id() const { return id_; }
+
+  int InputCount() const { return input_count(); }
+  Node* InputAt(int index) const { return GetInputRecordPtr(index)->to; }
+  inline void ReplaceInput(int index, Node* new_input);
+  inline void AppendInput(Zone* zone, Node* new_input);
+  inline void InsertInput(Zone* zone, int index, Node* new_input);
+  inline void RemoveInput(int index);
+
+  int UseCount() const;
+  Node* UseAt(int index) const;
+  inline void ReplaceUses(Node* replace_to);
+  template <class UnaryPredicate>
+  inline void ReplaceUsesIf(UnaryPredicate pred, Node* replace_to);
+  inline void RemoveAllInputs();
+
+  inline void TrimInputCount(int input_count);
+
+  class InputEdges {
+   public:
+    class iterator;
+    iterator begin() const;
+    iterator end() const;
+    bool empty() const;
+
+    explicit InputEdges(Node* node) : node_(node) {}
+
+   private:
+    Node* node_;
+  };
+
+  class Inputs {
+   public:
+    class iterator;
+    iterator begin() const;
+    iterator end() const;
+    bool empty() const;
+
+    explicit Inputs(Node* node) : node_(node) {}
+
+   private:
+    Node* node_;
+  };
+
+  Inputs inputs() { return Inputs(this); }
+  InputEdges input_edges() { return InputEdges(this); }
+
+  class UseEdges {
+   public:
+    class iterator;
+    iterator begin() const;
+    iterator end() const;
+    bool empty() const;
+
+    explicit UseEdges(Node* node) : node_(node) {}
+
+   private:
+    Node* node_;
+  };
+
+  class Uses {
+   public:
+    class iterator;
+    iterator begin() const;
+    iterator end() const;
+    bool empty() const;
+
+    explicit Uses(Node* node) : node_(node) {}
+
+   private:
+    Node* node_;
+  };
+
+  Uses uses() { return Uses(this); }
+  UseEdges use_edges() { return UseEdges(this); }
+
+  bool OwnedBy(Node* owner) const;
+
+  static Node* New(Graph* graph, int input_count, Node** inputs,
+                   bool has_extensible_inputs);
 
  protected:
-  const Operator* op_;
-  Bounds bounds_;
-  explicit NodeData(Zone* zone) : bounds_(Bounds(Type::None(zone))) {}
+  friend class Graph;
+  friend class Edge;
+
+  class Use : public ZoneObject {
+   public:
+    Node* from;
+    Use* next;
+    Use* prev;
+    int input_index;
+  };
+
+  class Input {
+   public:
+    Node* to;
+    Use* use;
+
+    void Update(Node* new_to);
+  };
+
+  void EnsureAppendableInputs(Zone* zone);
+
+  Input* GetInputRecordPtr(int index) const {
+    if (has_appendable_inputs()) {
+      return &((*inputs_.appendable_)[index]);
+    } else {
+      return &inputs_.static_[index];
+    }
+  }
+
+  inline void AppendUse(Use* use);
+  inline void RemoveUse(Use* use);
+
+  void* operator new(size_t, void* location) { return location; }
+
+ private:
+  inline Node(NodeId id, int input_count, int reserve_input_count);
+
+  typedef ZoneDeque<Input> InputDeque;
 
   friend class NodeProperties;
+  template <typename State>
+  friend class NodeMarker;
+
+  // Only NodeProperties should manipulate the bounds.
+  Bounds bounds() { return bounds_; }
   void set_bounds(Bounds b) { bounds_ = b; }
+
+  // Only NodeMarkers should manipulate the marks on nodes.
+  Mark mark() { return mark_; }
+  void set_mark(Mark mark) { mark_ = mark; }
+
+  int input_count() const { return InputCountField::decode(bit_field_); }
+  void set_input_count(int input_count) {
+    DCHECK_LE(0, input_count);
+    bit_field_ = InputCountField::update(bit_field_, input_count);
+  }
+
+  int reserved_input_count() const {
+    return ReservedInputCountField::decode(bit_field_);
+  }
+  void set_reserved_input_count(int reserved_input_count) {
+    DCHECK_LE(0, reserved_input_count);
+    bit_field_ =
+        ReservedInputCountField::update(bit_field_, reserved_input_count);
+  }
+
+  bool has_appendable_inputs() const {
+    return HasAppendableInputsField::decode(bit_field_);
+  }
+  void set_has_appendable_inputs(bool has_appendable_inputs) {
+    bit_field_ =
+        HasAppendableInputsField::update(bit_field_, has_appendable_inputs);
+  }
+
+  typedef BitField<unsigned, 0, 29> InputCountField;
+  typedef BitField<unsigned, 29, 2> ReservedInputCountField;
+  typedef BitField<unsigned, 31, 1> HasAppendableInputsField;
+  static const int kDefaultReservedInputs = ReservedInputCountField::kMax;
+
+  const Operator* op_;
+  Bounds bounds_;
+  Mark mark_;
+  NodeId id_;
+  unsigned bit_field_;
+  union {
+    // When a node is initially allocated, it uses a static buffer to hold its
+    // inputs under the assumption that the number of outputs will not increase.
+    // When the first input is appended, the static buffer is converted into a
+    // deque to allow for space-efficient growing.
+    Input* static_;
+    InputDeque* appendable_;
+  } inputs_;
+  Use* first_use_;
+  Use* last_use_;
+
+  DISALLOW_COPY_AND_ASSIGN(Node);
 };
 
-// A Node is the basic primitive of an IR graph. In addition to the members
-// inherited from Vector, Nodes only contain a mutable Operator that may change
-// during compilation, e.g. during lowering passes.  Other information that
-// needs to be associated with Nodes during compilation must be stored
-// out-of-line indexed by the Node's id.
-class Node FINAL : public GenericNode<NodeData, Node> {
+
+// An encapsulation for information associated with a single use of node as a
+// input from another node, allowing access to both the defining node and
+// the node having the input.
+class Edge {
  public:
-  Node(GenericGraphBase* graph, int input_count)
-      : GenericNode<NodeData, Node>(graph, input_count) {}
+  Node* from() const { return input_->use->from; }
+  Node* to() const { return input_->to; }
+  int index() const {
+    int index = input_->use->input_index;
+    DCHECK(index < input_->use->from->input_count());
+    return index;
+  }
 
-  void Initialize(const Operator* op) { set_op(op); }
+  bool operator==(const Edge& other) { return input_ == other.input_; }
+  bool operator!=(const Edge& other) { return !(*this == other); }
 
-  bool IsDead() const { return InputCount() > 0 && InputAt(0) == NULL; }
-  void Kill();
+  void UpdateTo(Node* new_to) { input_->Update(new_to); }
 
-  void CollectProjections(ZoneVector<Node*>* projections);
-  Node* FindProjection(size_t projection_index);
+ private:
+  friend class Node::Uses::iterator;
+  friend class Node::Inputs::iterator;
+  friend class Node::UseEdges::iterator;
+  friend class Node::InputEdges::iterator;
+
+  explicit Edge(Node::Input* input) : input_(input) {}
+
+  Node::Input* input_;
 };
 
-OStream& operator<<(OStream& os, const Node& n);
 
-typedef GenericGraphVisit::NullNodeVisitor<NodeData, Node> NullNodeVisitor;
+// A forward iterator to visit the edges for the input dependencies of a node..
+class Node::InputEdges::iterator {
+ public:
+  typedef std::forward_iterator_tag iterator_category;
+  typedef int difference_type;
+  typedef Edge value_type;
+  typedef Edge* pointer;
+  typedef Edge& reference;
+  iterator(const Node::InputEdges::iterator& other)  // NOLINT
+      : input_(other.input_) {}
+  iterator() : input_(NULL) {}
+
+  Edge operator*() const { return Edge(input_); }
+  bool operator==(const iterator& other) const { return Equals(other); }
+  bool operator!=(const iterator& other) const { return !Equals(other); }
+  iterator& operator++() {
+    DCHECK(input_ != NULL);
+    Edge edge(input_);
+    Node* from = edge.from();
+    SetInput(from, input_->use->input_index + 1);
+    return *this;
+  }
+  iterator operator++(int) {
+    iterator result(*this);
+    ++(*this);
+    return result;
+  }
+
+ private:
+  friend class Node;
+
+  explicit iterator(Node* from, int index = 0) : input_(NULL) {
+    SetInput(from, index);
+  }
+
+  bool Equals(const iterator& other) const { return other.input_ == input_; }
+  void SetInput(Node* from, int index) {
+    DCHECK(index >= 0 && index <= from->InputCount());
+    if (index < from->InputCount()) {
+      input_ = from->GetInputRecordPtr(index);
+    } else {
+      input_ = NULL;
+    }
+  }
+
+  Input* input_;
+};
+
+
+// A forward iterator to visit the inputs of a node.
+class Node::Inputs::iterator {
+ public:
+  typedef std::forward_iterator_tag iterator_category;
+  typedef int difference_type;
+  typedef Node* value_type;
+  typedef Node** pointer;
+  typedef Node*& reference;
+
+  iterator(const Node::Inputs::iterator& other)  // NOLINT
+      : iter_(other.iter_) {}
+
+  Node* operator*() const { return (*iter_).to(); }
+  bool operator==(const iterator& other) const { return Equals(other); }
+  bool operator!=(const iterator& other) const { return !Equals(other); }
+  iterator& operator++() {
+    ++iter_;
+    return *this;
+  }
+  iterator operator++(int) {
+    iterator result(*this);
+    ++(*this);
+    return result;
+  }
+
+
+ private:
+  friend class Node::Inputs;
+
+  explicit iterator(Node* node, int index) : iter_(node, index) {}
+
+  bool Equals(const iterator& other) const { return other.iter_ == iter_; }
+
+  Node::InputEdges::iterator iter_;
+};
+
+// A forward iterator to visit the uses edges of a node. The edges are returned
+// in
+// the order in which they were added as inputs.
+class Node::UseEdges::iterator {
+ public:
+  iterator(const Node::UseEdges::iterator& other)  // NOLINT
+      : current_(other.current_),
+        next_(other.next_) {}
+
+  Edge operator*() const { return Edge(CurrentInput()); }
+
+  bool operator==(const iterator& other) { return Equals(other); }
+  bool operator!=(const iterator& other) { return !Equals(other); }
+  iterator& operator++() {
+    DCHECK(current_ != NULL);
+    current_ = next_;
+    next_ = (current_ == NULL) ? NULL : current_->next;
+    return *this;
+  }
+  iterator operator++(int) {
+    iterator result(*this);
+    ++(*this);
+    return result;
+  }
+
+ private:
+  friend class Node::UseEdges;
+
+  iterator() : current_(NULL), next_(NULL) {}
+  explicit iterator(Node* node)
+      : current_(node->first_use_),
+        next_(current_ == NULL ? NULL : current_->next) {}
+
+  bool Equals(const iterator& other) const {
+    return other.current_ == current_;
+  }
+
+  Input* CurrentInput() const {
+    return current_->from->GetInputRecordPtr(current_->input_index);
+  }
+
+  Node::Use* current_;
+  Node::Use* next_;
+};
+
+
+// A forward iterator to visit the uses of a node. The uses are returned in
+// the order in which they were added as inputs.
+class Node::Uses::iterator {
+ public:
+  iterator(const Node::Uses::iterator& other)  // NOLINT
+      : current_(other.current_) {}
+
+  Node* operator*() { return current_->from; }
+
+  bool operator==(const iterator& other) { return other.current_ == current_; }
+  bool operator!=(const iterator& other) { return other.current_ != current_; }
+  iterator& operator++() {
+    DCHECK(current_ != NULL);
+    current_ = current_->next;
+    return *this;
+  }
+
+ private:
+  friend class Node::Uses;
+
+  iterator() : current_(NULL) {}
+  explicit iterator(Node* node) : current_(node->first_use_) {}
+
+  Input* CurrentInput() const {
+    return current_->from->GetInputRecordPtr(current_->input_index);
+  }
+
+  Node::Use* current_;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const Node& n);
 
 typedef std::set<Node*, std::less<Node*>, zone_allocator<Node*> > NodeSet;
 typedef NodeSet::iterator NodeSetIter;
 typedef NodeSet::reverse_iterator NodeSetRIter;
 
+typedef ZoneDeque<Node*> NodeDeque;
+
 typedef ZoneVector<Node*> NodeVector;
 typedef NodeVector::iterator NodeVectorIter;
 typedef NodeVector::const_iterator NodeVectorConstIter;
@@ -87,6 +465,195 @@
   return OpParameter<T>(node->op());
 }
 
+inline Node::InputEdges::iterator Node::InputEdges::begin() const {
+  return Node::InputEdges::iterator(this->node_, 0);
+}
+
+inline Node::InputEdges::iterator Node::InputEdges::end() const {
+  return Node::InputEdges::iterator(this->node_, this->node_->InputCount());
+}
+
+inline Node::Inputs::iterator Node::Inputs::begin() const {
+  return Node::Inputs::iterator(this->node_, 0);
+}
+
+inline Node::Inputs::iterator Node::Inputs::end() const {
+  return Node::Inputs::iterator(this->node_, this->node_->InputCount());
+}
+
+inline Node::UseEdges::iterator Node::UseEdges::begin() const {
+  return Node::UseEdges::iterator(this->node_);
+}
+
+inline Node::UseEdges::iterator Node::UseEdges::end() const {
+  return Node::UseEdges::iterator();
+}
+
+inline Node::Uses::iterator Node::Uses::begin() const {
+  return Node::Uses::iterator(this->node_);
+}
+
+inline Node::Uses::iterator Node::Uses::end() const {
+  return Node::Uses::iterator();
+}
+
+inline bool Node::InputEdges::empty() const { return begin() == end(); }
+inline bool Node::Uses::empty() const { return begin() == end(); }
+inline bool Node::UseEdges::empty() const { return begin() == end(); }
+inline bool Node::Inputs::empty() const { return begin() == end(); }
+
+inline void Node::ReplaceUses(Node* replace_to) {
+  for (Use* use = first_use_; use != NULL; use = use->next) {
+    use->from->GetInputRecordPtr(use->input_index)->to = replace_to;
+  }
+  if (replace_to->last_use_ == NULL) {
+    DCHECK_EQ(NULL, replace_to->first_use_);
+    replace_to->first_use_ = first_use_;
+    replace_to->last_use_ = last_use_;
+  } else if (first_use_ != NULL) {
+    DCHECK_NE(NULL, replace_to->first_use_);
+    replace_to->last_use_->next = first_use_;
+    first_use_->prev = replace_to->last_use_;
+    replace_to->last_use_ = last_use_;
+  }
+  first_use_ = NULL;
+  last_use_ = NULL;
+}
+
+template <class UnaryPredicate>
+inline void Node::ReplaceUsesIf(UnaryPredicate pred, Node* replace_to) {
+  for (Use* use = first_use_; use != NULL;) {
+    Use* next = use->next;
+    if (pred(use->from)) {
+      RemoveUse(use);
+      replace_to->AppendUse(use);
+      use->from->GetInputRecordPtr(use->input_index)->to = replace_to;
+    }
+    use = next;
+  }
+}
+
+inline void Node::RemoveAllInputs() {
+  for (Edge edge : input_edges()) {
+    edge.UpdateTo(NULL);
+  }
+}
+
+inline void Node::TrimInputCount(int new_input_count) {
+  if (new_input_count == input_count()) return;  // Nothing to do.
+
+  DCHECK(new_input_count < input_count());
+
+  // Update inline inputs.
+  for (int i = new_input_count; i < input_count(); i++) {
+    Node::Input* input = GetInputRecordPtr(i);
+    input->Update(NULL);
+  }
+  set_input_count(new_input_count);
+}
+
+inline void Node::ReplaceInput(int index, Node* new_to) {
+  Input* input = GetInputRecordPtr(index);
+  input->Update(new_to);
+}
+
+inline void Node::Input::Update(Node* new_to) {
+  Node* old_to = this->to;
+  if (new_to == old_to) return;  // Nothing to do.
+  // Snip out the use from where it used to be
+  if (old_to != NULL) {
+    old_to->RemoveUse(use);
+  }
+  to = new_to;
+  // And put it into the new node's use list.
+  if (new_to != NULL) {
+    new_to->AppendUse(use);
+  } else {
+    use->next = NULL;
+    use->prev = NULL;
+  }
+}
+
+inline void Node::EnsureAppendableInputs(Zone* zone) {
+  if (!has_appendable_inputs()) {
+    void* deque_buffer = zone->New(sizeof(InputDeque));
+    InputDeque* deque = new (deque_buffer) InputDeque(zone);
+    for (int i = 0; i < input_count(); ++i) {
+      deque->push_back(inputs_.static_[i]);
+    }
+    inputs_.appendable_ = deque;
+    set_has_appendable_inputs(true);
+  }
+}
+
+inline void Node::AppendInput(Zone* zone, Node* to_append) {
+  Use* new_use = new (zone) Use;
+  Input new_input;
+  new_input.to = to_append;
+  new_input.use = new_use;
+  if (reserved_input_count() > 0) {
+    DCHECK(!has_appendable_inputs());
+    set_reserved_input_count(reserved_input_count() - 1);
+    inputs_.static_[input_count()] = new_input;
+  } else {
+    EnsureAppendableInputs(zone);
+    inputs_.appendable_->push_back(new_input);
+  }
+  new_use->input_index = input_count();
+  new_use->from = this;
+  to_append->AppendUse(new_use);
+  set_input_count(input_count() + 1);
+}
+
+inline void Node::InsertInput(Zone* zone, int index, Node* to_insert) {
+  DCHECK(index >= 0 && index < InputCount());
+  // TODO(turbofan): Optimize this implementation!
+  AppendInput(zone, InputAt(InputCount() - 1));
+  for (int i = InputCount() - 1; i > index; --i) {
+    ReplaceInput(i, InputAt(i - 1));
+  }
+  ReplaceInput(index, to_insert);
+}
+
+inline void Node::RemoveInput(int index) {
+  DCHECK(index >= 0 && index < InputCount());
+  // TODO(turbofan): Optimize this implementation!
+  for (; index < InputCount() - 1; ++index) {
+    ReplaceInput(index, InputAt(index + 1));
+  }
+  TrimInputCount(InputCount() - 1);
+}
+
+inline void Node::AppendUse(Use* use) {
+  use->next = NULL;
+  use->prev = last_use_;
+  if (last_use_ == NULL) {
+    first_use_ = use;
+  } else {
+    last_use_->next = use;
+  }
+  last_use_ = use;
+}
+
+inline void Node::RemoveUse(Use* use) {
+  if (last_use_ == use) {
+    last_use_ = use->prev;
+  }
+  if (use->prev != NULL) {
+    use->prev->next = use->next;
+  } else {
+    first_use_ = use->next;
+  }
+  if (use->next != NULL) {
+    use->next->prev = use->prev;
+  }
+}
+
+inline bool Node::OwnedBy(Node* owner) const {
+  return first_use_ != NULL && first_use_->from == owner &&
+         first_use_->next == NULL;
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
diff --git a/src/compiler/opcodes.cc b/src/compiler/opcodes.cc
new file mode 100644
index 0000000..044395c
--- /dev/null
+++ b/src/compiler/opcodes.cc
@@ -0,0 +1,34 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/opcodes.h"
+
+#include <algorithm>
+
+#include "src/base/macros.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+char const* const kMnemonics[] = {
+#define DECLARE_MNEMONIC(x) #x,
+    ALL_OP_LIST(DECLARE_MNEMONIC)
+#undef DECLARE_MNEMONIC
+        "UnknownOpcode"};
+
+}  // namespace
+
+
+// static
+char const* IrOpcode::Mnemonic(Value value) {
+  size_t const n = std::max<size_t>(value, arraysize(kMnemonics) - 1);
+  return kMnemonics[n];
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h
index e210abd..d229b6d 100644
--- a/src/compiler/opcodes.h
+++ b/src/compiler/opcodes.h
@@ -7,13 +7,14 @@
 
 // Opcodes for control operators.
 #define INNER_CONTROL_OP_LIST(V) \
-  V(Dead)                  \
-  V(Loop)                  \
-  V(Branch)                \
-  V(IfTrue)                \
-  V(IfFalse)               \
-  V(Merge)                 \
-  V(Return)                \
+  V(Dead)                        \
+  V(Loop)                        \
+  V(Branch)                      \
+  V(IfTrue)                      \
+  V(IfFalse)                     \
+  V(Merge)                       \
+  V(Return)                      \
+  V(Terminate)                   \
   V(Throw)
 
 #define CONTROL_OP_LIST(V) \
@@ -32,9 +33,9 @@
   V(HeapConstant)
 
 #define INNER_OP_LIST(V) \
+  V(Select)              \
   V(Phi)                 \
   V(EffectPhi)           \
-  V(ControlEffect)       \
   V(ValueEffect)         \
   V(Finish)              \
   V(FrameState)          \
@@ -113,7 +114,7 @@
   V(JSCreateWithContext)      \
   V(JSCreateBlockContext)     \
   V(JSCreateModuleContext)    \
-  V(JSCreateGlobalContext)
+  V(JSCreateScriptContext)
 
 #define JS_OTHER_OP_LIST(V) \
   V(JSCallConstruct)        \
@@ -131,6 +132,7 @@
 
 // Opcodes for VirtuaMachine-level operators.
 #define SIMPLIFIED_OP_LIST(V) \
+  V(AnyToBoolean)             \
   V(BooleanNot)               \
   V(BooleanToNumber)          \
   V(NumberEqual)              \
@@ -157,9 +159,13 @@
   V(ChangeBoolToBit)          \
   V(ChangeBitToBool)          \
   V(LoadField)                \
+  V(LoadBuffer)               \
   V(LoadElement)              \
   V(StoreField)               \
-  V(StoreElement)
+  V(StoreBuffer)              \
+  V(StoreElement)             \
+  V(ObjectIsSmi)              \
+  V(ObjectIsNonNegativeSmi)
 
 // Opcodes for Machine-level operators.
 #define MACHINE_OP_LIST(V)    \
@@ -186,23 +192,26 @@
   V(Int32Sub)                 \
   V(Int32SubWithOverflow)     \
   V(Int32Mul)                 \
+  V(Int32MulHigh)             \
   V(Int32Div)                 \
-  V(Int32UDiv)                \
   V(Int32Mod)                 \
-  V(Int32UMod)                \
   V(Int32LessThan)            \
   V(Int32LessThanOrEqual)     \
+  V(Uint32Div)                \
   V(Uint32LessThan)           \
   V(Uint32LessThanOrEqual)    \
+  V(Uint32Mod)                \
+  V(Uint32MulHigh)            \
   V(Int64Add)                 \
   V(Int64Sub)                 \
   V(Int64Mul)                 \
   V(Int64Div)                 \
-  V(Int64UDiv)                \
   V(Int64Mod)                 \
-  V(Int64UMod)                \
   V(Int64LessThan)            \
   V(Int64LessThanOrEqual)     \
+  V(Uint64Div)                \
+  V(Uint64LessThan)           \
+  V(Uint64Mod)                \
   V(ChangeFloat32ToFloat64)   \
   V(ChangeFloat64ToInt32)     \
   V(ChangeFloat64ToUint32)    \
@@ -221,7 +230,14 @@
   V(Float64Sqrt)              \
   V(Float64Equal)             \
   V(Float64LessThan)          \
-  V(Float64LessThanOrEqual)
+  V(Float64LessThanOrEqual)   \
+  V(Float64Floor)             \
+  V(Float64Ceil)              \
+  V(Float64RoundTruncate)     \
+  V(Float64RoundTiesAway)     \
+  V(LoadStackPointer)         \
+  V(CheckedLoad)              \
+  V(CheckedStore)
 
 #define VALUE_OP_LIST(V) \
   COMMON_OP_LIST(V)      \
@@ -253,20 +269,11 @@
   };
 
   // Returns the mnemonic name of an opcode.
-  static const char* Mnemonic(Value val) {
-    switch (val) {
-#define RETURN_NAME(x) \
-  case k##x:           \
-    return #x;
-      ALL_OP_LIST(RETURN_NAME)
-#undef RETURN_NAME
-      default:
-        return "UnknownOpcode";
-    }
-  }
+  static char const* Mnemonic(Value value);
 
   static bool IsJsOpcode(Value val) {
     switch (val) {
+// TODO(turbofan): make this a range check.
 #define RETURN_NAME(x) \
   case k##x:           \
     return true;
@@ -279,6 +286,7 @@
 
   static bool IsControlOpcode(Value val) {
     switch (val) {
+// TODO(turbofan): make this a range check.
 #define RETURN_NAME(x) \
   case k##x:           \
     return true;
@@ -289,8 +297,22 @@
     }
   }
 
+  static bool IsLeafOpcode(Value val) {
+    switch (val) {
+// TODO(turbofan): make this a table lookup.
+#define RETURN_NAME(x) \
+  case k##x:           \
+    return true;
+      LEAF_OP_LIST(RETURN_NAME)
+#undef RETURN_NAME
+      default:
+        return false;
+    }
+  }
+
   static bool IsCommonOpcode(Value val) {
     switch (val) {
+// TODO(turbofan): make this a table lookup or a range check.
 #define RETURN_NAME(x) \
   case k##x:           \
     return true;
diff --git a/src/compiler/operator-properties-inl.h b/src/compiler/operator-properties-inl.h
deleted file mode 100644
index 9dae106..0000000
--- a/src/compiler/operator-properties-inl.h
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_COMPILER_OPERATOR_PROPERTIES_INL_H_
-#define V8_COMPILER_OPERATOR_PROPERTIES_INL_H_
-
-#include "src/compiler/common-operator.h"
-#include "src/compiler/js-operator.h"
-#include "src/compiler/opcodes.h"
-#include "src/compiler/operator-properties.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-inline bool OperatorProperties::HasValueInput(const Operator* op) {
-  return OperatorProperties::GetValueInputCount(op) > 0;
-}
-
-inline bool OperatorProperties::HasContextInput(const Operator* op) {
-  IrOpcode::Value opcode = static_cast<IrOpcode::Value>(op->opcode());
-  return IrOpcode::IsJsOpcode(opcode);
-}
-
-inline bool OperatorProperties::HasEffectInput(const Operator* op) {
-  return OperatorProperties::GetEffectInputCount(op) > 0;
-}
-
-inline bool OperatorProperties::HasControlInput(const Operator* op) {
-  return OperatorProperties::GetControlInputCount(op) > 0;
-}
-
-inline bool OperatorProperties::HasFrameStateInput(const Operator* op) {
-  if (!FLAG_turbo_deoptimization) {
-    return false;
-  }
-
-  switch (op->opcode()) {
-    case IrOpcode::kFrameState:
-      return true;
-    case IrOpcode::kJSCallRuntime: {
-      Runtime::FunctionId function = OpParameter<Runtime::FunctionId>(op);
-      return Linkage::NeedsFrameState(function);
-    }
-
-    // Strict equality cannot lazily deoptimize.
-    case IrOpcode::kJSStrictEqual:
-    case IrOpcode::kJSStrictNotEqual:
-      return false;
-
-    // Calls
-    case IrOpcode::kJSCallFunction:
-    case IrOpcode::kJSCallConstruct:
-
-    // Compare operations
-    case IrOpcode::kJSEqual:
-    case IrOpcode::kJSNotEqual:
-    case IrOpcode::kJSLessThan:
-    case IrOpcode::kJSGreaterThan:
-    case IrOpcode::kJSLessThanOrEqual:
-    case IrOpcode::kJSGreaterThanOrEqual:
-
-    // Binary operations
-    case IrOpcode::kJSBitwiseOr:
-    case IrOpcode::kJSBitwiseXor:
-    case IrOpcode::kJSBitwiseAnd:
-    case IrOpcode::kJSShiftLeft:
-    case IrOpcode::kJSShiftRight:
-    case IrOpcode::kJSShiftRightLogical:
-    case IrOpcode::kJSAdd:
-    case IrOpcode::kJSSubtract:
-    case IrOpcode::kJSMultiply:
-    case IrOpcode::kJSDivide:
-    case IrOpcode::kJSModulus:
-    case IrOpcode::kJSLoadProperty:
-    case IrOpcode::kJSStoreProperty:
-    case IrOpcode::kJSLoadNamed:
-    case IrOpcode::kJSStoreNamed:
-      return true;
-
-    default:
-      return false;
-  }
-}
-
-inline int OperatorProperties::GetValueInputCount(const Operator* op) {
-  return op->InputCount();
-}
-
-inline int OperatorProperties::GetContextInputCount(const Operator* op) {
-  return OperatorProperties::HasContextInput(op) ? 1 : 0;
-}
-
-inline int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
-  return OperatorProperties::HasFrameStateInput(op) ? 1 : 0;
-}
-
-inline int OperatorProperties::GetEffectInputCount(const Operator* op) {
-  if (op->opcode() == IrOpcode::kEffectPhi ||
-      op->opcode() == IrOpcode::kFinish) {
-    return OpParameter<int>(op);
-  }
-  if (op->HasProperty(Operator::kNoRead) && op->HasProperty(Operator::kNoWrite))
-    return 0;  // no effects.
-  return 1;
-}
-
-inline int OperatorProperties::GetControlInputCount(const Operator* op) {
-  switch (op->opcode()) {
-    case IrOpcode::kPhi:
-    case IrOpcode::kEffectPhi:
-    case IrOpcode::kControlEffect:
-      return 1;
-#define OPCODE_CASE(x) case IrOpcode::k##x:
-      CONTROL_OP_LIST(OPCODE_CASE)
-#undef OPCODE_CASE
-      // Control operators are Operator1<int>.
-      return OpParameter<int>(op);
-    default:
-      // Operators that have write effects must have a control
-      // dependency. Effect dependencies only ensure the correct order of
-      // write/read operations without consideration of control flow. Without an
-      // explicit control dependency writes can be float in the schedule too
-      // early along a path that shouldn't generate a side-effect.
-      return op->HasProperty(Operator::kNoWrite) ? 0 : 1;
-  }
-  return 0;
-}
-
-inline int OperatorProperties::GetTotalInputCount(const Operator* op) {
-  return GetValueInputCount(op) + GetContextInputCount(op) +
-         GetFrameStateInputCount(op) + GetEffectInputCount(op) +
-         GetControlInputCount(op);
-}
-
-// -----------------------------------------------------------------------------
-// Output properties.
-
-inline bool OperatorProperties::HasValueOutput(const Operator* op) {
-  return GetValueOutputCount(op) > 0;
-}
-
-inline bool OperatorProperties::HasEffectOutput(const Operator* op) {
-  return op->opcode() == IrOpcode::kStart ||
-         op->opcode() == IrOpcode::kControlEffect ||
-         op->opcode() == IrOpcode::kValueEffect ||
-         (op->opcode() != IrOpcode::kFinish && GetEffectInputCount(op) > 0);
-}
-
-inline bool OperatorProperties::HasControlOutput(const Operator* op) {
-  IrOpcode::Value opcode = static_cast<IrOpcode::Value>(op->opcode());
-  return (opcode != IrOpcode::kEnd && IrOpcode::IsControlOpcode(opcode));
-}
-
-
-inline int OperatorProperties::GetValueOutputCount(const Operator* op) {
-  return op->OutputCount();
-}
-
-inline int OperatorProperties::GetEffectOutputCount(const Operator* op) {
-  return HasEffectOutput(op) ? 1 : 0;
-}
-
-inline int OperatorProperties::GetControlOutputCount(const Operator* node) {
-  return node->opcode() == IrOpcode::kBranch ? 2 : HasControlOutput(node) ? 1
-                                                                          : 0;
-}
-
-
-inline bool OperatorProperties::IsBasicBlockBegin(const Operator* op) {
-  uint8_t opcode = op->opcode();
-  return opcode == IrOpcode::kStart || opcode == IrOpcode::kEnd ||
-         opcode == IrOpcode::kDead || opcode == IrOpcode::kLoop ||
-         opcode == IrOpcode::kMerge || opcode == IrOpcode::kIfTrue ||
-         opcode == IrOpcode::kIfFalse;
-}
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
-
-#endif  // V8_COMPILER_OPERATOR_PROPERTIES_INL_H_
diff --git a/src/compiler/operator-properties.cc b/src/compiler/operator-properties.cc
new file mode 100644
index 0000000..abfc5fd
--- /dev/null
+++ b/src/compiler/operator-properties.cc
@@ -0,0 +1,103 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/operator-properties.h"
+
+#include "src/compiler/js-operator.h"
+#include "src/compiler/linkage.h"
+#include "src/compiler/opcodes.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// static
+bool OperatorProperties::HasContextInput(const Operator* op) {
+  IrOpcode::Value opcode = static_cast<IrOpcode::Value>(op->opcode());
+  return IrOpcode::IsJsOpcode(opcode);
+}
+
+
+// static
+bool OperatorProperties::HasFrameStateInput(const Operator* op) {
+  if (!FLAG_turbo_deoptimization) {
+    return false;
+  }
+  switch (op->opcode()) {
+    case IrOpcode::kFrameState:
+      return true;
+    case IrOpcode::kJSCallRuntime: {
+      const CallRuntimeParameters& p = CallRuntimeParametersOf(op);
+      return Linkage::NeedsFrameState(p.id());
+    }
+
+    // Strict equality cannot lazily deoptimize.
+    case IrOpcode::kJSStrictEqual:
+    case IrOpcode::kJSStrictNotEqual:
+      return false;
+
+    // Calls
+    case IrOpcode::kJSCallFunction:
+    case IrOpcode::kJSCallConstruct:
+
+    // Compare operations
+    case IrOpcode::kJSEqual:
+    case IrOpcode::kJSGreaterThan:
+    case IrOpcode::kJSGreaterThanOrEqual:
+    case IrOpcode::kJSHasProperty:
+    case IrOpcode::kJSInstanceOf:
+    case IrOpcode::kJSLessThan:
+    case IrOpcode::kJSLessThanOrEqual:
+    case IrOpcode::kJSNotEqual:
+
+    // Binary operations
+    case IrOpcode::kJSAdd:
+    case IrOpcode::kJSBitwiseAnd:
+    case IrOpcode::kJSBitwiseOr:
+    case IrOpcode::kJSBitwiseXor:
+    case IrOpcode::kJSDivide:
+    case IrOpcode::kJSLoadNamed:
+    case IrOpcode::kJSLoadProperty:
+    case IrOpcode::kJSModulus:
+    case IrOpcode::kJSMultiply:
+    case IrOpcode::kJSShiftLeft:
+    case IrOpcode::kJSShiftRight:
+    case IrOpcode::kJSShiftRightLogical:
+    case IrOpcode::kJSStoreNamed:
+    case IrOpcode::kJSStoreProperty:
+    case IrOpcode::kJSSubtract:
+
+    // Conversions
+    case IrOpcode::kJSToObject:
+
+    // Other
+    case IrOpcode::kJSDeleteProperty:
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+
+// static
+int OperatorProperties::GetTotalInputCount(const Operator* op) {
+  return op->ValueInputCount() + GetContextInputCount(op) +
+         GetFrameStateInputCount(op) + op->EffectInputCount() +
+         op->ControlInputCount();
+}
+
+
+// static
+bool OperatorProperties::IsBasicBlockBegin(const Operator* op) {
+  Operator::Opcode const opcode = op->opcode();
+  return opcode == IrOpcode::kStart || opcode == IrOpcode::kEnd ||
+         opcode == IrOpcode::kDead || opcode == IrOpcode::kLoop ||
+         opcode == IrOpcode::kMerge || opcode == IrOpcode::kIfTrue ||
+         opcode == IrOpcode::kIfFalse;
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/operator-properties.h b/src/compiler/operator-properties.h
index 718eea0..37c9755 100644
--- a/src/compiler/operator-properties.h
+++ b/src/compiler/operator-properties.h
@@ -5,36 +5,33 @@
 #ifndef V8_COMPILER_OPERATOR_PROPERTIES_H_
 #define V8_COMPILER_OPERATOR_PROPERTIES_H_
 
+#include "src/base/macros.h"
+
 namespace v8 {
 namespace internal {
 namespace compiler {
 
+// Forward declarations.
 class Operator;
 
-class OperatorProperties {
+
+class OperatorProperties FINAL {
  public:
-  static inline bool HasValueInput(const Operator* op);
-  static inline bool HasContextInput(const Operator* op);
-  static inline bool HasEffectInput(const Operator* op);
-  static inline bool HasControlInput(const Operator* op);
-  static inline bool HasFrameStateInput(const Operator* op);
+  static bool HasContextInput(const Operator* op);
+  static bool HasFrameStateInput(const Operator* op);
 
-  static inline int GetValueInputCount(const Operator* op);
-  static inline int GetContextInputCount(const Operator* op);
-  static inline int GetEffectInputCount(const Operator* op);
-  static inline int GetControlInputCount(const Operator* op);
-  static inline int GetFrameStateInputCount(const Operator* op);
-  static inline int GetTotalInputCount(const Operator* op);
+  static int GetContextInputCount(const Operator* op) {
+    return HasContextInput(op) ? 1 : 0;
+  }
+  static int GetFrameStateInputCount(const Operator* op) {
+    return HasFrameStateInput(op) ? 1 : 0;
+  }
+  static int GetTotalInputCount(const Operator* op);
 
-  static inline bool HasValueOutput(const Operator* op);
-  static inline bool HasEffectOutput(const Operator* op);
-  static inline bool HasControlOutput(const Operator* op);
+  static bool IsBasicBlockBegin(const Operator* op);
 
-  static inline int GetValueOutputCount(const Operator* op);
-  static inline int GetEffectOutputCount(const Operator* op);
-  static inline int GetControlOutputCount(const Operator* op);
-
-  static inline bool IsBasicBlockBegin(const Operator* op);
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OperatorProperties);
 };
 
 }  // namespace compiler
diff --git a/src/compiler/operator.cc b/src/compiler/operator.cc
index 35f9c88..c8687f4 100644
--- a/src/compiler/operator.cc
+++ b/src/compiler/operator.cc
@@ -4,22 +4,41 @@
 
 #include "src/compiler/operator.h"
 
+#include <limits>
+
 namespace v8 {
 namespace internal {
 namespace compiler {
 
-Operator::~Operator() {}
+
+template <typename N>
+static inline N CheckRange(size_t val) {
+  CHECK(val <= std::numeric_limits<N>::max());
+  return static_cast<N>(val);
+}
 
 
-SimpleOperator::SimpleOperator(Opcode opcode, Properties properties,
-                               int input_count, int output_count,
-                               const char* mnemonic)
-    : Operator(opcode, properties, mnemonic),
-      input_count_(input_count),
-      output_count_(output_count) {}
+Operator::Operator(Opcode opcode, Properties properties, const char* mnemonic,
+                   size_t value_in, size_t effect_in, size_t control_in,
+                   size_t value_out, size_t effect_out, size_t control_out)
+    : opcode_(opcode),
+      properties_(properties),
+      mnemonic_(mnemonic),
+      value_in_(CheckRange<uint32_t>(value_in)),
+      effect_in_(CheckRange<uint16_t>(effect_in)),
+      control_in_(CheckRange<uint16_t>(control_in)),
+      value_out_(CheckRange<uint16_t>(value_out)),
+      effect_out_(CheckRange<uint8_t>(effect_out)),
+      control_out_(CheckRange<uint8_t>(control_out)) {}
 
 
-SimpleOperator::~SimpleOperator() {}
+std::ostream& operator<<(std::ostream& os, const Operator& op) {
+  op.PrintTo(os);
+  return os;
+}
+
+
+void Operator::PrintTo(std::ostream& os) const { os << mnemonic(); }
 
 }  // namespace compiler
 }  // namespace internal
diff --git a/src/compiler/operator.h b/src/compiler/operator.h
index 5137806..fb144ce 100644
--- a/src/compiler/operator.h
+++ b/src/compiler/operator.h
@@ -5,9 +5,11 @@
 #ifndef V8_COMPILER_OPERATOR_H_
 #define V8_COMPILER_OPERATOR_H_
 
+#include <ostream>  // NOLINT(readability/streams)
+
 #include "src/base/flags.h"
-#include "src/ostreams.h"
-#include "src/unique.h"
+#include "src/base/functional.h"
+#include "src/zone.h"
 
 namespace v8 {
 namespace internal {
@@ -47,9 +49,12 @@
   };
   typedef base::Flags<Property, uint8_t> Properties;
 
-  Operator(Opcode opcode, Properties properties, const char* mnemonic)
-      : opcode_(opcode), properties_(properties), mnemonic_(mnemonic) {}
-  virtual ~Operator();
+  // Constructor.
+  Operator(Opcode opcode, Properties properties, const char* mnemonic,
+           size_t value_in, size_t effect_in, size_t control_in,
+           size_t value_out, size_t effect_out, size_t control_out);
+
+  virtual ~Operator() {}
 
   // A small integer unique to all instances of a particular kind of operator,
   // useful for quick matching for specific kinds of operators. For fast access
@@ -63,196 +68,122 @@
   // Check if this operator equals another operator. Equivalent operators can
   // be merged, and nodes with equivalent operators and equivalent inputs
   // can be merged.
-  virtual bool Equals(const Operator* other) const = 0;
+  virtual bool Equals(const Operator* that) const {
+    return this->opcode() == that->opcode();
+  }
 
   // Compute a hashcode to speed up equivalence-set checking.
   // Equal operators should always have equal hashcodes, and unequal operators
   // should have unequal hashcodes with high probability.
-  virtual int HashCode() const = 0;
+  virtual size_t HashCode() const { return base::hash<Opcode>()(opcode()); }
 
   // Check whether this operator has the given property.
   bool HasProperty(Property property) const {
     return (properties() & property) == property;
   }
 
-  // Number of data inputs to the operator, for verifying graph structure.
-  virtual int InputCount() const = 0;
-
-  // Number of data outputs from the operator, for verifying graph structure.
-  virtual int OutputCount() const = 0;
-
   Properties properties() const { return properties_; }
 
+  // TODO(titzer): convert return values here to size_t.
+  int ValueInputCount() const { return value_in_; }
+  int EffectInputCount() const { return effect_in_; }
+  int ControlInputCount() const { return control_in_; }
+
+  int ValueOutputCount() const { return value_out_; }
+  int EffectOutputCount() const { return effect_out_; }
+  int ControlOutputCount() const { return control_out_; }
+
+  static inline size_t ZeroIfPure(Properties properties) {
+    return (properties & kPure) == kPure ? 0 : 1;
+  }
+
   // TODO(titzer): API for input and output types, for typechecking graph.
  protected:
   // Print the full operator into the given stream, including any
   // static parameters. Useful for debugging and visualizing the IR.
-  virtual OStream& PrintTo(OStream& os) const = 0;  // NOLINT
-  friend OStream& operator<<(OStream& os, const Operator& op);
+  virtual void PrintTo(std::ostream& os) const;
+  friend std::ostream& operator<<(std::ostream& os, const Operator& op);
 
  private:
   Opcode opcode_;
   Properties properties_;
   const char* mnemonic_;
+  uint32_t value_in_;
+  uint16_t effect_in_;
+  uint16_t control_in_;
+  uint16_t value_out_;
+  uint8_t effect_out_;
+  uint8_t control_out_;
 
   DISALLOW_COPY_AND_ASSIGN(Operator);
 };
 
 DEFINE_OPERATORS_FOR_FLAGS(Operator::Properties)
 
-OStream& operator<<(OStream& os, const Operator& op);
+std::ostream& operator<<(std::ostream& os, const Operator& op);
 
-// An implementation of Operator that has no static parameters. Such operators
-// have just a name, an opcode, and a fixed number of inputs and outputs.
-// They can represented by singletons and shared globally.
-class SimpleOperator : public Operator {
- public:
-  SimpleOperator(Opcode opcode, Properties properties, int input_count,
-                 int output_count, const char* mnemonic);
-  ~SimpleOperator();
-
-  virtual bool Equals(const Operator* that) const FINAL {
-    return opcode() == that->opcode();
-  }
-  virtual int HashCode() const FINAL { return opcode(); }
-  virtual int InputCount() const FINAL { return input_count_; }
-  virtual int OutputCount() const FINAL { return output_count_; }
-
- private:
-  virtual OStream& PrintTo(OStream& os) const FINAL {  // NOLINT
-    return os << mnemonic();
-  }
-
-  int input_count_;
-  int output_count_;
-
-  DISALLOW_COPY_AND_ASSIGN(SimpleOperator);
-};
-
-// Template specialization implements a kind of type class for dealing with the
-// static parameters of Operator1 automatically.
-template <typename T>
-struct StaticParameterTraits {
-  static OStream& PrintTo(OStream& os, T val) {  // NOLINT
-    return os << "??";
-  }
-  static int HashCode(T a) { return 0; }
-  static bool Equals(T a, T b) {
-    return false;  // Not every T has a ==. By default, be conservative.
-  }
-};
-
-// Specialization for static parameters of type {int}.
-template <>
-struct StaticParameterTraits<int> {
-  static OStream& PrintTo(OStream& os, int val) {  // NOLINT
-    return os << val;
-  }
-  static int HashCode(int a) { return a; }
-  static bool Equals(int a, int b) { return a == b; }
-};
-
-// Specialization for static parameters of type {double}.
-template <>
-struct StaticParameterTraits<double> {
-  static OStream& PrintTo(OStream& os, double val) {  // NOLINT
-    return os << val;
-  }
-  static int HashCode(double a) {
-    return static_cast<int>(bit_cast<int64_t>(a));
-  }
-  static bool Equals(double a, double b) {
-    return bit_cast<int64_t>(a) == bit_cast<int64_t>(b);
-  }
-};
-
-// Specialization for static parameters of type {Unique<Object>}.
-template <>
-struct StaticParameterTraits<Unique<Object> > {
-  static OStream& PrintTo(OStream& os, Unique<Object> val) {  // NOLINT
-    return os << Brief(*val.handle());
-  }
-  static int HashCode(Unique<Object> a) {
-    return static_cast<int>(a.Hashcode());
-  }
-  static bool Equals(Unique<Object> a, Unique<Object> b) { return a == b; }
-};
-
-// Specialization for static parameters of type {Unique<Name>}.
-template <>
-struct StaticParameterTraits<Unique<Name> > {
-  static OStream& PrintTo(OStream& os, Unique<Name> val) {  // NOLINT
-    return os << Brief(*val.handle());
-  }
-  static int HashCode(Unique<Name> a) { return static_cast<int>(a.Hashcode()); }
-  static bool Equals(Unique<Name> a, Unique<Name> b) { return a == b; }
-};
-
-#if DEBUG
-// Specialization for static parameters of type {Handle<Object>} to prevent any
-// direct usage of Handles in constants.
-template <>
-struct StaticParameterTraits<Handle<Object> > {
-  static OStream& PrintTo(OStream& os, Handle<Object> val) {  // NOLINT
-    UNREACHABLE();  // Should use Unique<Object> instead
-    return os;
-  }
-  static int HashCode(Handle<Object> a) {
-    UNREACHABLE();  // Should use Unique<Object> instead
-    return 0;
-  }
-  static bool Equals(Handle<Object> a, Handle<Object> b) {
-    UNREACHABLE();  // Should use Unique<Object> instead
-    return false;
-  }
-};
-#endif
 
 // A templatized implementation of Operator that has one static parameter of
-// type {T}. If a specialization of StaticParameterTraits<{T}> exists, then
-// operators of this kind can automatically be hashed, compared, and printed.
-template <typename T>
+// type {T}.
+template <typename T, typename Pred = std::equal_to<T>,
+          typename Hash = base::hash<T>>
 class Operator1 : public Operator {
  public:
-  Operator1(Opcode opcode, Properties properties, int input_count,
-            int output_count, const char* mnemonic, T parameter)
-      : Operator(opcode, properties, mnemonic),
-        input_count_(input_count),
-        output_count_(output_count),
-        parameter_(parameter) {}
+  Operator1(Opcode opcode, Properties properties, const char* mnemonic,
+            size_t value_in, size_t effect_in, size_t control_in,
+            size_t value_out, size_t effect_out, size_t control_out,
+            T parameter, Pred const& pred = Pred(), Hash const& hash = Hash())
+      : Operator(opcode, properties, mnemonic, value_in, effect_in, control_in,
+                 value_out, effect_out, control_out),
+        parameter_(parameter),
+        pred_(pred),
+        hash_(hash) {}
 
-  const T& parameter() const { return parameter_; }
+  T const& parameter() const { return parameter_; }
 
-  virtual bool Equals(const Operator* other) const OVERRIDE {
+  bool Equals(const Operator* other) const FINAL {
     if (opcode() != other->opcode()) return false;
     const Operator1<T>* that = static_cast<const Operator1<T>*>(other);
-    return StaticParameterTraits<T>::Equals(this->parameter_, that->parameter_);
+    return this->pred_(this->parameter(), that->parameter());
   }
-  virtual int HashCode() const OVERRIDE {
-    return opcode() + 33 * StaticParameterTraits<T>::HashCode(this->parameter_);
+  size_t HashCode() const FINAL {
+    return base::hash_combine(this->opcode(), this->hash_(this->parameter()));
   }
-  virtual int InputCount() const OVERRIDE { return input_count_; }
-  virtual int OutputCount() const OVERRIDE { return output_count_; }
-  virtual OStream& PrintParameter(OStream& os) const {  // NOLINT
-    return StaticParameterTraits<T>::PrintTo(os << "[", parameter_) << "]";
+  virtual void PrintParameter(std::ostream& os) const {
+    os << "[" << this->parameter() << "]";
   }
 
  protected:
-  virtual OStream& PrintTo(OStream& os) const FINAL {  // NOLINT
-    return PrintParameter(os << mnemonic());
+  void PrintTo(std::ostream& os) const FINAL {
+    os << mnemonic();
+    PrintParameter(os);
   }
 
  private:
-  int input_count_;
-  int output_count_;
-  T parameter_;
+  T const parameter_;
+  Pred const pred_;
+  Hash const hash_;
 };
 
 
 // Helper to extract parameters from Operator1<*> operator.
 template <typename T>
-static inline const T& OpParameter(const Operator* op) {
-  return reinterpret_cast<const Operator1<T>*>(op)->parameter();
+inline T const& OpParameter(const Operator* op) {
+  return static_cast<const Operator1<T>*>(op)->parameter();
+}
+
+// NOTE: We have to be careful to use the right equal/hash functions below, for
+// float/double we always use the ones operating on the bit level.
+template <>
+inline float const& OpParameter(const Operator* op) {
+  return static_cast<const Operator1<float, base::bit_equal_to<float>,
+                                     base::bit_hash<float>>*>(op)->parameter();
+}
+
+template <>
+inline double const& OpParameter(const Operator* op) {
+  return static_cast<const Operator1<double, base::bit_equal_to<double>,
+                                     base::bit_hash<double>>*>(op)->parameter();
 }
 
 }  // namespace compiler
diff --git a/src/compiler/phi-reducer.h b/src/compiler/phi-reducer.h
deleted file mode 100644
index 5870d04..0000000
--- a/src/compiler/phi-reducer.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_COMPILER_PHI_REDUCER_H_
-#define V8_COMPILER_PHI_REDUCER_H_
-
-#include "src/compiler/graph-reducer.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-// Replaces redundant phis if all the inputs are the same or the phi itself.
-class PhiReducer FINAL : public Reducer {
- public:
-  virtual Reduction Reduce(Node* node) OVERRIDE {
-    if (node->opcode() != IrOpcode::kPhi &&
-        node->opcode() != IrOpcode::kEffectPhi)
-      return NoChange();
-
-    int n = node->op()->InputCount();
-    if (n == 1) return Replace(node->InputAt(0));
-
-    Node* replacement = NULL;
-    Node::Inputs inputs = node->inputs();
-    for (InputIter it = inputs.begin(); n > 0; --n, ++it) {
-      Node* input = *it;
-      if (input != node && input != replacement) {
-        if (replacement != NULL) return NoChange();
-        replacement = input;
-      }
-    }
-    DCHECK_NE(node, replacement);
-    return Replace(replacement);
-  }
-};
-}
-}
-}  // namespace v8::internal::compiler
-
-#endif  // V8_COMPILER_PHI_REDUCER_H_
diff --git a/src/compiler/pipeline-statistics.cc b/src/compiler/pipeline-statistics.cc
new file mode 100644
index 0000000..e58c396
--- /dev/null
+++ b/src/compiler/pipeline-statistics.cc
@@ -0,0 +1,103 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler.h"
+#include "src/compiler/pipeline-statistics.h"
+#include "src/compiler/zone-pool.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+void PipelineStatistics::CommonStats::Begin(
+    PipelineStatistics* pipeline_stats) {
+  DCHECK(scope_.is_empty());
+  scope_.Reset(new ZonePool::StatsScope(pipeline_stats->zone_pool_));
+  timer_.Start();
+  outer_zone_initial_size_ = pipeline_stats->OuterZoneSize();
+  allocated_bytes_at_start_ =
+      outer_zone_initial_size_ -
+      pipeline_stats->total_stats_.outer_zone_initial_size_ +
+      pipeline_stats->zone_pool_->GetCurrentAllocatedBytes();
+}
+
+
+void PipelineStatistics::CommonStats::End(
+    PipelineStatistics* pipeline_stats,
+    CompilationStatistics::BasicStats* diff) {
+  DCHECK(!scope_.is_empty());
+  diff->function_name_ = pipeline_stats->function_name_;
+  diff->delta_ = timer_.Elapsed();
+  size_t outer_zone_diff =
+      pipeline_stats->OuterZoneSize() - outer_zone_initial_size_;
+  diff->max_allocated_bytes_ = outer_zone_diff + scope_->GetMaxAllocatedBytes();
+  diff->absolute_max_allocated_bytes_ =
+      diff->max_allocated_bytes_ + allocated_bytes_at_start_;
+  diff->total_allocated_bytes_ =
+      outer_zone_diff + scope_->GetTotalAllocatedBytes();
+  scope_.Reset(NULL);
+  timer_.Stop();
+}
+
+
+PipelineStatistics::PipelineStatistics(CompilationInfo* info,
+                                       ZonePool* zone_pool)
+    : isolate_(info->zone()->isolate()),
+      outer_zone_(info->zone()),
+      zone_pool_(zone_pool),
+      compilation_stats_(isolate_->GetTurboStatistics()),
+      source_size_(0),
+      phase_kind_name_(NULL),
+      phase_name_(NULL) {
+  if (!info->shared_info().is_null()) {
+    source_size_ = static_cast<size_t>(info->shared_info()->SourceSize());
+    SmartArrayPointer<char> name =
+        info->shared_info()->DebugName()->ToCString();
+    function_name_ = name.get();
+  }
+  total_stats_.Begin(this);
+}
+
+
+PipelineStatistics::~PipelineStatistics() {
+  if (InPhaseKind()) EndPhaseKind();
+  CompilationStatistics::BasicStats diff;
+  total_stats_.End(this, &diff);
+  compilation_stats_->RecordTotalStats(source_size_, diff);
+}
+
+
+void PipelineStatistics::BeginPhaseKind(const char* phase_kind_name) {
+  DCHECK(!InPhase());
+  if (InPhaseKind()) EndPhaseKind();
+  phase_kind_name_ = phase_kind_name;
+  phase_kind_stats_.Begin(this);
+}
+
+
+void PipelineStatistics::EndPhaseKind() {
+  DCHECK(!InPhase());
+  CompilationStatistics::BasicStats diff;
+  phase_kind_stats_.End(this, &diff);
+  compilation_stats_->RecordPhaseKindStats(phase_kind_name_, diff);
+}
+
+
+void PipelineStatistics::BeginPhase(const char* name) {
+  DCHECK(InPhaseKind());
+  phase_name_ = name;
+  phase_stats_.Begin(this);
+}
+
+
+void PipelineStatistics::EndPhase() {
+  DCHECK(InPhaseKind());
+  CompilationStatistics::BasicStats diff;
+  phase_stats_.End(this, &diff);
+  compilation_stats_->RecordPhaseStats(phase_kind_name_, phase_name_, diff);
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/pipeline-statistics.h b/src/compiler/pipeline-statistics.h
new file mode 100644
index 0000000..01cc9de
--- /dev/null
+++ b/src/compiler/pipeline-statistics.h
@@ -0,0 +1,95 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_PIPELINE_STATISTICS_H_
+#define V8_COMPILER_PIPELINE_STATISTICS_H_
+
+#include <string>
+
+#include "src/compilation-statistics.h"
+#include "src/compiler/zone-pool.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class PhaseScope;
+
+class PipelineStatistics : public Malloced {
+ public:
+  PipelineStatistics(CompilationInfo* info, ZonePool* zone_pool);
+  ~PipelineStatistics();
+
+  void BeginPhaseKind(const char* phase_kind_name);
+
+ private:
+  size_t OuterZoneSize() {
+    return static_cast<size_t>(outer_zone_->allocation_size());
+  }
+
+  class CommonStats {
+   public:
+    CommonStats() : outer_zone_initial_size_(0) {}
+
+    void Begin(PipelineStatistics* pipeline_stats);
+    void End(PipelineStatistics* pipeline_stats,
+             CompilationStatistics::BasicStats* diff);
+
+    SmartPointer<ZonePool::StatsScope> scope_;
+    base::ElapsedTimer timer_;
+    size_t outer_zone_initial_size_;
+    size_t allocated_bytes_at_start_;
+  };
+
+  bool InPhaseKind() { return !phase_kind_stats_.scope_.is_empty(); }
+  void EndPhaseKind();
+
+  friend class PhaseScope;
+  bool InPhase() { return !phase_stats_.scope_.is_empty(); }
+  void BeginPhase(const char* name);
+  void EndPhase();
+
+  Isolate* isolate_;
+  Zone* outer_zone_;
+  ZonePool* zone_pool_;
+  CompilationStatistics* compilation_stats_;
+  std::string function_name_;
+
+  // Stats for the entire compilation.
+  CommonStats total_stats_;
+  size_t source_size_;
+
+  // Stats for phase kind.
+  const char* phase_kind_name_;
+  CommonStats phase_kind_stats_;
+
+  // Stats for phase.
+  const char* phase_name_;
+  CommonStats phase_stats_;
+
+  DISALLOW_COPY_AND_ASSIGN(PipelineStatistics);
+};
+
+
+class PhaseScope {
+ public:
+  PhaseScope(PipelineStatistics* pipeline_stats, const char* name)
+      : pipeline_stats_(pipeline_stats) {
+    if (pipeline_stats_ != NULL) pipeline_stats_->BeginPhase(name);
+  }
+  ~PhaseScope() {
+    if (pipeline_stats_ != NULL) pipeline_stats_->EndPhase();
+  }
+
+ private:
+  PipelineStatistics* const pipeline_stats_;
+
+  DISALLOW_COPY_AND_ASSIGN(PhaseScope);
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif
diff --git a/src/compiler/pipeline.cc b/src/compiler/pipeline.cc
index 9889b6a..c7432c6 100644
--- a/src/compiler/pipeline.cc
+++ b/src/compiler/pipeline.cc
@@ -4,29 +4,42 @@
 
 #include "src/compiler/pipeline.h"
 
+#include <fstream>  // NOLINT(readability/streams)
+#include <sstream>
+
 #include "src/base/platform/elapsed-timer.h"
 #include "src/compiler/ast-graph-builder.h"
+#include "src/compiler/ast-loop-assignment-analyzer.h"
+#include "src/compiler/basic-block-instrumentor.h"
 #include "src/compiler/change-lowering.h"
 #include "src/compiler/code-generator.h"
+#include "src/compiler/common-operator-reducer.h"
+#include "src/compiler/control-reducer.h"
 #include "src/compiler/graph-replay.h"
 #include "src/compiler/graph-visualizer.h"
 #include "src/compiler/instruction.h"
 #include "src/compiler/instruction-selector.h"
+#include "src/compiler/js-builtin-reducer.h"
 #include "src/compiler/js-context-specialization.h"
 #include "src/compiler/js-generic-lowering.h"
 #include "src/compiler/js-inlining.h"
 #include "src/compiler/js-typed-lowering.h"
+#include "src/compiler/jump-threading.h"
+#include "src/compiler/load-elimination.h"
 #include "src/compiler/machine-operator-reducer.h"
-#include "src/compiler/phi-reducer.h"
+#include "src/compiler/move-optimizer.h"
+#include "src/compiler/pipeline-statistics.h"
 #include "src/compiler/register-allocator.h"
+#include "src/compiler/register-allocator-verifier.h"
 #include "src/compiler/schedule.h"
 #include "src/compiler/scheduler.h"
+#include "src/compiler/select-lowering.h"
 #include "src/compiler/simplified-lowering.h"
 #include "src/compiler/simplified-operator-reducer.h"
 #include "src/compiler/typer.h"
 #include "src/compiler/value-numbering-reducer.h"
 #include "src/compiler/verifier.h"
-#include "src/hydrogen.h"
+#include "src/compiler/zone-pool.h"
 #include "src/ostreams.h"
 #include "src/utils.h"
 
@@ -34,47 +47,202 @@
 namespace internal {
 namespace compiler {
 
-class PhaseStats {
+class PipelineData {
  public:
-  enum PhaseKind { CREATE_GRAPH, OPTIMIZATION, CODEGEN };
+  explicit PipelineData(ZonePool* zone_pool, CompilationInfo* info)
+      : isolate_(info->zone()->isolate()),
+        info_(info),
+        outer_zone_(nullptr),
+        zone_pool_(zone_pool),
+        pipeline_statistics_(nullptr),
+        compilation_failed_(false),
+        code_(Handle<Code>::null()),
+        graph_zone_scope_(zone_pool_),
+        graph_zone_(nullptr),
+        graph_(nullptr),
+        loop_assignment_(nullptr),
+        machine_(nullptr),
+        common_(nullptr),
+        javascript_(nullptr),
+        jsgraph_(nullptr),
+        typer_(nullptr),
+        context_node_(nullptr),
+        schedule_(nullptr),
+        instruction_zone_scope_(zone_pool_),
+        instruction_zone_(nullptr),
+        sequence_(nullptr),
+        frame_(nullptr),
+        register_allocator_(nullptr) {}
 
-  PhaseStats(CompilationInfo* info, PhaseKind kind, const char* name)
-      : info_(info),
-        kind_(kind),
-        name_(name),
-        size_(info->zone()->allocation_size()) {
-    if (FLAG_turbo_stats) {
-      timer_.Start();
-    }
+  ~PipelineData() {
+    DeleteInstructionZone();
+    DeleteGraphZone();
   }
 
-  ~PhaseStats() {
-    if (FLAG_turbo_stats) {
-      base::TimeDelta delta = timer_.Elapsed();
-      size_t bytes = info_->zone()->allocation_size() - size_;
-      HStatistics* stats = info_->isolate()->GetTStatistics();
-      stats->SaveTiming(name_, delta, static_cast<int>(bytes));
+  // For main entry point.
+  void Initialize(PipelineStatistics* pipeline_statistics) {
+    PhaseScope scope(pipeline_statistics, "init pipeline data");
+    outer_zone_ = info()->zone();
+    pipeline_statistics_ = pipeline_statistics;
+    graph_zone_ = graph_zone_scope_.zone();
+    graph_ = new (graph_zone()) Graph(graph_zone());
+    source_positions_.Reset(new SourcePositionTable(graph()));
+    machine_ = new (graph_zone()) MachineOperatorBuilder(
+        graph_zone(), kMachPtr,
+        InstructionSelector::SupportedMachineOperatorFlags());
+    common_ = new (graph_zone()) CommonOperatorBuilder(graph_zone());
+    javascript_ = new (graph_zone()) JSOperatorBuilder(graph_zone());
+    jsgraph_ =
+        new (graph_zone()) JSGraph(graph(), common(), javascript(), machine());
+    typer_.Reset(new Typer(graph(), info()->context()));
+    instruction_zone_ = instruction_zone_scope_.zone();
+  }
 
-      switch (kind_) {
-        case CREATE_GRAPH:
-          stats->IncrementCreateGraph(delta);
-          break;
-        case OPTIMIZATION:
-          stats->IncrementOptimizeGraph(delta);
-          break;
-        case CODEGEN:
-          stats->IncrementGenerateCode(delta);
-          break;
-      }
-    }
+  // For machine graph testing entry point.
+  void InitializeTorTesting(Graph* graph, Schedule* schedule) {
+    graph_ = graph;
+    source_positions_.Reset(new SourcePositionTable(graph));
+    schedule_ = schedule;
+    instruction_zone_ = instruction_zone_scope_.zone();
+  }
+
+  // For register allocation testing entry point.
+  void InitializeTorTesting(InstructionSequence* sequence) {
+    instruction_zone_ = sequence->zone();
+    sequence_ = sequence;
+  }
+
+  Isolate* isolate() const { return isolate_; }
+  CompilationInfo* info() const { return info_; }
+  ZonePool* zone_pool() const { return zone_pool_; }
+  PipelineStatistics* pipeline_statistics() { return pipeline_statistics_; }
+  bool compilation_failed() const { return compilation_failed_; }
+  void set_compilation_failed() { compilation_failed_ = true; }
+  Handle<Code> code() { return code_; }
+  void set_code(Handle<Code> code) {
+    DCHECK(code_.is_null());
+    code_ = code;
+  }
+
+  // RawMachineAssembler generally produces graphs which cannot be verified.
+  bool MayHaveUnverifiableGraph() const { return outer_zone_ == nullptr; }
+
+  Zone* graph_zone() const { return graph_zone_; }
+  Graph* graph() const { return graph_; }
+  SourcePositionTable* source_positions() const {
+    return source_positions_.get();
+  }
+  MachineOperatorBuilder* machine() const { return machine_; }
+  CommonOperatorBuilder* common() const { return common_; }
+  JSOperatorBuilder* javascript() const { return javascript_; }
+  JSGraph* jsgraph() const { return jsgraph_; }
+  Typer* typer() const { return typer_.get(); }
+
+  LoopAssignmentAnalysis* loop_assignment() const { return loop_assignment_; }
+  void set_loop_assignment(LoopAssignmentAnalysis* loop_assignment) {
+    DCHECK_EQ(nullptr, loop_assignment_);
+    loop_assignment_ = loop_assignment;
+  }
+
+  Node* context_node() const { return context_node_; }
+  void set_context_node(Node* context_node) {
+    DCHECK_EQ(nullptr, context_node_);
+    context_node_ = context_node;
+  }
+
+  Schedule* schedule() const { return schedule_; }
+  void set_schedule(Schedule* schedule) {
+    DCHECK_EQ(nullptr, schedule_);
+    schedule_ = schedule;
+  }
+
+  Zone* instruction_zone() const { return instruction_zone_; }
+  InstructionSequence* sequence() const { return sequence_; }
+  Frame* frame() const { return frame_; }
+  RegisterAllocator* register_allocator() const { return register_allocator_; }
+
+  void DeleteGraphZone() {
+    // Destroy objects with destructors first.
+    source_positions_.Reset(nullptr);
+    typer_.Reset(nullptr);
+    if (graph_zone_ == nullptr) return;
+    // Destroy zone and clear pointers.
+    graph_zone_scope_.Destroy();
+    graph_zone_ = nullptr;
+    graph_ = nullptr;
+    loop_assignment_ = nullptr;
+    machine_ = nullptr;
+    common_ = nullptr;
+    javascript_ = nullptr;
+    jsgraph_ = nullptr;
+    context_node_ = nullptr;
+    schedule_ = nullptr;
+  }
+
+  void DeleteInstructionZone() {
+    if (instruction_zone_ == nullptr) return;
+    instruction_zone_scope_.Destroy();
+    instruction_zone_ = nullptr;
+    sequence_ = nullptr;
+    frame_ = nullptr;
+    register_allocator_ = nullptr;
+  }
+
+  void InitializeInstructionSequence() {
+    DCHECK_EQ(nullptr, sequence_);
+    InstructionBlocks* instruction_blocks =
+        InstructionSequence::InstructionBlocksFor(instruction_zone(),
+                                                  schedule());
+    sequence_ = new (instruction_zone())
+        InstructionSequence(instruction_zone(), instruction_blocks);
+  }
+
+  void InitializeRegisterAllocator(Zone* local_zone,
+                                   const RegisterConfiguration* config,
+                                   const char* debug_name) {
+    DCHECK_EQ(nullptr, register_allocator_);
+    DCHECK_EQ(nullptr, frame_);
+    frame_ = new (instruction_zone()) Frame();
+    register_allocator_ = new (instruction_zone())
+        RegisterAllocator(config, local_zone, frame(), sequence(), debug_name);
   }
 
  private:
+  Isolate* isolate_;
   CompilationInfo* info_;
-  PhaseKind kind_;
-  const char* name_;
-  size_t size_;
-  base::ElapsedTimer timer_;
+  Zone* outer_zone_;
+  ZonePool* const zone_pool_;
+  PipelineStatistics* pipeline_statistics_;
+  bool compilation_failed_;
+  Handle<Code> code_;
+
+  // All objects in the following group of fields are allocated in graph_zone_.
+  // They are all set to NULL when the graph_zone_ is destroyed.
+  ZonePool::Scope graph_zone_scope_;
+  Zone* graph_zone_;
+  Graph* graph_;
+  // TODO(dcarney): make this into a ZoneObject.
+  SmartPointer<SourcePositionTable> source_positions_;
+  LoopAssignmentAnalysis* loop_assignment_;
+  MachineOperatorBuilder* machine_;
+  CommonOperatorBuilder* common_;
+  JSOperatorBuilder* javascript_;
+  JSGraph* jsgraph_;
+  // TODO(dcarney): make this into a ZoneObject.
+  SmartPointer<Typer> typer_;
+  Node* context_node_;
+  Schedule* schedule_;
+
+  // All objects in the following group of fields are allocated in
+  // instruction_zone_.  They are all set to NULL when the instruction_zone_ is
+  // destroyed.
+  ZonePool::Scope instruction_zone_scope_;
+  Zone* instruction_zone_;
+  InstructionSequence* sequence_;
+  Frame* frame_;
+  RegisterAllocator* register_allocator_;
+
+  DISALLOW_COPY_AND_ASSIGN(PipelineData);
 };
 
 
@@ -87,41 +255,46 @@
 }
 
 
-void Pipeline::VerifyAndPrintGraph(Graph* graph, const char* phase) {
-  if (FLAG_trace_turbo) {
-    char buffer[256];
-    Vector<char> filename(buffer, sizeof(buffer));
-    if (!info_->shared_info().is_null()) {
-      SmartArrayPointer<char> functionname =
-          info_->shared_info()->DebugName()->ToCString();
-      if (strlen(functionname.get()) > 0) {
-        SNPrintF(filename, "turbo-%s-%s.dot", functionname.get(), phase);
-      } else {
-        SNPrintF(filename, "turbo-%p-%s.dot", static_cast<void*>(info_), phase);
-      }
-    } else {
-      SNPrintF(filename, "turbo-none-%s.dot", phase);
-    }
-    std::replace(filename.start(), filename.start() + filename.length(), ' ',
-                 '_');
-    FILE* file = base::OS::FOpen(filename.start(), "w+");
-    OFStream of(file);
-    of << AsDOT(*graph);
-    fclose(file);
+struct TurboCfgFile : public std::ofstream {
+  explicit TurboCfgFile(Isolate* isolate)
+      : std::ofstream(isolate->GetTurboCfgFileName().c_str(),
+                      std::ios_base::app) {}
+};
 
-    OFStream os(stdout);
-    os << "-- " << phase << " graph printed to file " << filename.start()
-       << "\n";
+
+static void TraceSchedule(Schedule* schedule) {
+  if (!FLAG_trace_turbo_graph && !FLAG_trace_turbo_scheduler) return;
+  OFStream os(stdout);
+  os << "-- Schedule --------------------------------------\n" << *schedule;
+}
+
+
+static SmartArrayPointer<char> GetDebugName(CompilationInfo* info) {
+  SmartArrayPointer<char> name;
+  if (info->IsStub()) {
+    if (info->code_stub() != NULL) {
+      CodeStub::Major major_key = info->code_stub()->MajorKey();
+      const char* major_name = CodeStub::MajorName(major_key, false);
+      size_t len = strlen(major_name);
+      name.Reset(new char[len]);
+      memcpy(name.get(), major_name, len);
+    }
+  } else {
+    AllowHandleDereference allow_deref;
+    name = info->function()->debug_name()->ToCString();
   }
-  if (VerifyGraphs()) Verifier::Run(graph);
+  return name;
 }
 
 
 class AstGraphBuilderWithPositions : public AstGraphBuilder {
  public:
-  explicit AstGraphBuilderWithPositions(CompilationInfo* info, JSGraph* jsgraph,
-                                        SourcePositionTable* source_positions)
-      : AstGraphBuilder(info, jsgraph), source_positions_(source_positions) {}
+  AstGraphBuilderWithPositions(Zone* local_zone, CompilationInfo* info,
+                               JSGraph* jsgraph,
+                               LoopAssignmentAnalysis* loop_assignment,
+                               SourcePositionTable* source_positions)
+      : AstGraphBuilder(local_zone, info, jsgraph, loop_assignment),
+        source_positions_(source_positions) {}
 
   bool CreateGraph() {
     SourcePositionTable::Scope pos(source_positions_,
@@ -130,7 +303,7 @@
   }
 
 #define DEF_VISIT(type)                                               \
-  virtual void Visit##type(type* node) OVERRIDE {                  \
+  void Visit##type(type* node) OVERRIDE {                             \
     SourcePositionTable::Scope pos(source_positions_,                 \
                                    SourcePosition(node->position())); \
     AstGraphBuilder::Visit##type(node);                               \
@@ -138,220 +311,613 @@
   AST_NODE_LIST(DEF_VISIT)
 #undef DEF_VISIT
 
+  Node* GetFunctionContext() { return AstGraphBuilder::GetFunctionContext(); }
+
  private:
   SourcePositionTable* source_positions_;
 };
 
 
-static void TraceSchedule(Schedule* schedule) {
-  if (!FLAG_trace_turbo) return;
-  OFStream os(stdout);
-  os << "-- Schedule --------------------------------------\n" << *schedule;
+class PipelineRunScope {
+ public:
+  PipelineRunScope(PipelineData* data, const char* phase_name)
+      : phase_scope_(
+            phase_name == nullptr ? nullptr : data->pipeline_statistics(),
+            phase_name),
+        zone_scope_(data->zone_pool()) {}
+
+  Zone* zone() { return zone_scope_.zone(); }
+
+ private:
+  PhaseScope phase_scope_;
+  ZonePool::Scope zone_scope_;
+};
+
+
+template <typename Phase>
+void Pipeline::Run() {
+  PipelineRunScope scope(this->data_, Phase::phase_name());
+  Phase phase;
+  phase.Run(this->data_, scope.zone());
+}
+
+
+template <typename Phase, typename Arg0>
+void Pipeline::Run(Arg0 arg_0) {
+  PipelineRunScope scope(this->data_, Phase::phase_name());
+  Phase phase;
+  phase.Run(this->data_, scope.zone(), arg_0);
+}
+
+
+struct LoopAssignmentAnalysisPhase {
+  static const char* phase_name() { return "loop assignment analysis"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    AstLoopAssignmentAnalyzer analyzer(data->graph_zone(), data->info());
+    LoopAssignmentAnalysis* loop_assignment = analyzer.Analyze();
+    data->set_loop_assignment(loop_assignment);
+  }
+};
+
+
+struct GraphBuilderPhase {
+  static const char* phase_name() { return "graph builder"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    AstGraphBuilderWithPositions graph_builder(
+        temp_zone, data->info(), data->jsgraph(), data->loop_assignment(),
+        data->source_positions());
+    if (graph_builder.CreateGraph()) {
+      data->set_context_node(graph_builder.GetFunctionContext());
+    } else {
+      data->set_compilation_failed();
+    }
+  }
+};
+
+
+struct ContextSpecializerPhase {
+  static const char* phase_name() { return "context specializing"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    SourcePositionTable::Scope pos(data->source_positions(),
+                                   SourcePosition::Unknown());
+    JSContextSpecializer spec(data->info(), data->jsgraph(),
+                              data->context_node());
+    GraphReducer graph_reducer(data->graph(), temp_zone);
+    graph_reducer.AddReducer(&spec);
+    graph_reducer.ReduceGraph();
+  }
+};
+
+
+struct InliningPhase {
+  static const char* phase_name() { return "inlining"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    SourcePositionTable::Scope pos(data->source_positions(),
+                                   SourcePosition::Unknown());
+    JSInliner inliner(temp_zone, data->info(), data->jsgraph());
+    inliner.Inline();
+  }
+};
+
+
+struct TyperPhase {
+  static const char* phase_name() { return "typer"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) { data->typer()->Run(); }
+};
+
+
+struct TypedLoweringPhase {
+  static const char* phase_name() { return "typed lowering"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    SourcePositionTable::Scope pos(data->source_positions(),
+                                   SourcePosition::Unknown());
+    ValueNumberingReducer vn_reducer(temp_zone);
+    LoadElimination load_elimination;
+    JSBuiltinReducer builtin_reducer(data->jsgraph());
+    JSTypedLowering typed_lowering(data->jsgraph(), temp_zone);
+    SimplifiedOperatorReducer simple_reducer(data->jsgraph());
+    CommonOperatorReducer common_reducer;
+    GraphReducer graph_reducer(data->graph(), temp_zone);
+    graph_reducer.AddReducer(&vn_reducer);
+    graph_reducer.AddReducer(&builtin_reducer);
+    graph_reducer.AddReducer(&typed_lowering);
+    graph_reducer.AddReducer(&load_elimination);
+    graph_reducer.AddReducer(&simple_reducer);
+    graph_reducer.AddReducer(&common_reducer);
+    graph_reducer.ReduceGraph();
+  }
+};
+
+
+struct SimplifiedLoweringPhase {
+  static const char* phase_name() { return "simplified lowering"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    SourcePositionTable::Scope pos(data->source_positions(),
+                                   SourcePosition::Unknown());
+    SimplifiedLowering lowering(data->jsgraph(), temp_zone);
+    lowering.LowerAllNodes();
+    ValueNumberingReducer vn_reducer(temp_zone);
+    SimplifiedOperatorReducer simple_reducer(data->jsgraph());
+    MachineOperatorReducer machine_reducer(data->jsgraph());
+    CommonOperatorReducer common_reducer;
+    GraphReducer graph_reducer(data->graph(), temp_zone);
+    graph_reducer.AddReducer(&vn_reducer);
+    graph_reducer.AddReducer(&simple_reducer);
+    graph_reducer.AddReducer(&machine_reducer);
+    graph_reducer.AddReducer(&common_reducer);
+    graph_reducer.ReduceGraph();
+  }
+};
+
+
+struct ChangeLoweringPhase {
+  static const char* phase_name() { return "change lowering"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    SourcePositionTable::Scope pos(data->source_positions(),
+                                   SourcePosition::Unknown());
+    Linkage linkage(data->graph_zone(), data->info());
+    ValueNumberingReducer vn_reducer(temp_zone);
+    SimplifiedOperatorReducer simple_reducer(data->jsgraph());
+    ChangeLowering lowering(data->jsgraph(), &linkage);
+    MachineOperatorReducer machine_reducer(data->jsgraph());
+    CommonOperatorReducer common_reducer;
+    GraphReducer graph_reducer(data->graph(), temp_zone);
+    graph_reducer.AddReducer(&vn_reducer);
+    graph_reducer.AddReducer(&simple_reducer);
+    graph_reducer.AddReducer(&lowering);
+    graph_reducer.AddReducer(&machine_reducer);
+    graph_reducer.AddReducer(&common_reducer);
+    graph_reducer.ReduceGraph();
+  }
+};
+
+
+struct ControlReductionPhase {
+  void Run(PipelineData* data, Zone* temp_zone) {
+    SourcePositionTable::Scope pos(data->source_positions(),
+                                   SourcePosition::Unknown());
+    ControlReducer::ReduceGraph(temp_zone, data->jsgraph(), data->common());
+  }
+};
+
+
+struct EarlyControlReductionPhase : ControlReductionPhase {
+  static const char* phase_name() { return "early control reduction"; }
+};
+
+
+struct LateControlReductionPhase : ControlReductionPhase {
+  static const char* phase_name() { return "late control reduction"; }
+};
+
+
+struct GenericLoweringPhase {
+  static const char* phase_name() { return "generic lowering"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    SourcePositionTable::Scope pos(data->source_positions(),
+                                   SourcePosition::Unknown());
+    JSGenericLowering generic(data->info(), data->jsgraph());
+    SelectLowering select(data->jsgraph()->graph(), data->jsgraph()->common());
+    GraphReducer graph_reducer(data->graph(), temp_zone);
+    graph_reducer.AddReducer(&generic);
+    graph_reducer.AddReducer(&select);
+    graph_reducer.ReduceGraph();
+  }
+};
+
+
+struct ComputeSchedulePhase {
+  static const char* phase_name() { return "scheduling"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    Schedule* schedule = Scheduler::ComputeSchedule(temp_zone, data->graph());
+    TraceSchedule(schedule);
+    if (VerifyGraphs()) ScheduleVerifier::Run(schedule);
+    data->set_schedule(schedule);
+  }
+};
+
+
+struct InstructionSelectionPhase {
+  static const char* phase_name() { return "select instructions"; }
+
+  void Run(PipelineData* data, Zone* temp_zone, Linkage* linkage) {
+    InstructionSelector selector(temp_zone, data->graph(), linkage,
+                                 data->sequence(), data->schedule(),
+                                 data->source_positions());
+    selector.SelectInstructions();
+  }
+};
+
+
+struct MeetRegisterConstraintsPhase {
+  static const char* phase_name() { return "meet register constraints"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    data->register_allocator()->MeetRegisterConstraints();
+  }
+};
+
+
+struct ResolvePhisPhase {
+  static const char* phase_name() { return "resolve phis"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    data->register_allocator()->ResolvePhis();
+  }
+};
+
+
+struct BuildLiveRangesPhase {
+  static const char* phase_name() { return "build live ranges"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    data->register_allocator()->BuildLiveRanges();
+  }
+};
+
+
+struct AllocateGeneralRegistersPhase {
+  static const char* phase_name() { return "allocate general registers"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    data->register_allocator()->AllocateGeneralRegisters();
+  }
+};
+
+
+struct AllocateDoubleRegistersPhase {
+  static const char* phase_name() { return "allocate double registers"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    data->register_allocator()->AllocateDoubleRegisters();
+  }
+};
+
+
+struct ReuseSpillSlotsPhase {
+  static const char* phase_name() { return "reuse spill slots"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    data->register_allocator()->ReuseSpillSlots();
+  }
+};
+
+
+struct CommitAssignmentPhase {
+  static const char* phase_name() { return "commit assignment"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    data->register_allocator()->CommitAssignment();
+  }
+};
+
+
+struct PopulatePointerMapsPhase {
+  static const char* phase_name() { return "populate pointer maps"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    data->register_allocator()->PopulatePointerMaps();
+  }
+};
+
+
+struct ConnectRangesPhase {
+  static const char* phase_name() { return "connect ranges"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    data->register_allocator()->ConnectRanges();
+  }
+};
+
+
+struct ResolveControlFlowPhase {
+  static const char* phase_name() { return "resolve control flow"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    data->register_allocator()->ResolveControlFlow();
+  }
+};
+
+
+struct OptimizeMovesPhase {
+  static const char* phase_name() { return "optimize moves"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    MoveOptimizer move_optimizer(temp_zone, data->sequence());
+    move_optimizer.Run();
+  }
+};
+
+
+struct JumpThreadingPhase {
+  static const char* phase_name() { return "jump threading"; }
+
+  void Run(PipelineData* data, Zone* temp_zone) {
+    ZoneVector<BasicBlock::RpoNumber> result(temp_zone);
+    if (JumpThreading::ComputeForwarding(temp_zone, result, data->sequence())) {
+      JumpThreading::ApplyForwarding(result, data->sequence());
+    }
+  }
+};
+
+
+struct GenerateCodePhase {
+  static const char* phase_name() { return "generate code"; }
+
+  void Run(PipelineData* data, Zone* temp_zone, Linkage* linkage) {
+    CodeGenerator generator(data->frame(), linkage, data->sequence(),
+                            data->info());
+    data->set_code(generator.GenerateCode());
+  }
+};
+
+
+struct PrintGraphPhase {
+  static const char* phase_name() { return nullptr; }
+
+  void Run(PipelineData* data, Zone* temp_zone, const char* phase) {
+    CompilationInfo* info = data->info();
+    Graph* graph = data->graph();
+    char buffer[256];
+    Vector<char> filename(buffer, sizeof(buffer));
+    SmartArrayPointer<char> functionname;
+    if (!info->shared_info().is_null()) {
+      functionname = info->shared_info()->DebugName()->ToCString();
+      if (strlen(functionname.get()) > 0) {
+        SNPrintF(filename, "turbo-%s-%s", functionname.get(), phase);
+      } else {
+        SNPrintF(filename, "turbo-%p-%s", static_cast<void*>(info), phase);
+      }
+    } else {
+      SNPrintF(filename, "turbo-none-%s", phase);
+    }
+    std::replace(filename.start(), filename.start() + filename.length(), ' ',
+                 '_');
+
+    {  // Print dot.
+      char dot_buffer[256];
+      Vector<char> dot_filename(dot_buffer, sizeof(dot_buffer));
+      SNPrintF(dot_filename, "%s.dot", filename.start());
+      FILE* dot_file = base::OS::FOpen(dot_filename.start(), "w+");
+      if (dot_file == nullptr) return;
+      OFStream dot_of(dot_file);
+      dot_of << AsDOT(*graph);
+      fclose(dot_file);
+    }
+
+    {  // Print JSON.
+      char json_buffer[256];
+      Vector<char> json_filename(json_buffer, sizeof(json_buffer));
+      SNPrintF(json_filename, "%s.json", filename.start());
+      FILE* json_file = base::OS::FOpen(json_filename.start(), "w+");
+      if (json_file == nullptr) return;
+      OFStream json_of(json_file);
+      json_of << AsJSON(*graph);
+      fclose(json_file);
+    }
+
+    OFStream os(stdout);
+    if (FLAG_trace_turbo_graph) {  // Simple textual RPO.
+      os << "-- Graph after " << phase << " -- " << std::endl;
+      os << AsRPO(*graph);
+    }
+
+    os << "-- " << phase << " graph printed to file " << filename.start()
+       << std::endl;
+  }
+};
+
+
+struct VerifyGraphPhase {
+  static const char* phase_name() { return nullptr; }
+
+  void Run(PipelineData* data, Zone* temp_zone, const bool untyped) {
+    Verifier::Run(data->graph(), FLAG_turbo_types && !untyped
+                                     ? Verifier::TYPED
+                                     : Verifier::UNTYPED);
+  }
+};
+
+
+void Pipeline::BeginPhaseKind(const char* phase_kind_name) {
+  if (data_->pipeline_statistics() != NULL) {
+    data_->pipeline_statistics()->BeginPhaseKind(phase_kind_name);
+  }
+}
+
+
+void Pipeline::RunPrintAndVerify(const char* phase, bool untyped) {
+  if (FLAG_trace_turbo) {
+    Run<PrintGraphPhase>(phase);
+  }
+  if (VerifyGraphs()) {
+    Run<VerifyGraphPhase>(untyped);
+  }
 }
 
 
 Handle<Code> Pipeline::GenerateCode() {
+  // This list must be kept in sync with DONT_TURBOFAN_NODE in ast.cc.
   if (info()->function()->dont_optimize_reason() == kTryCatchStatement ||
       info()->function()->dont_optimize_reason() == kTryFinallyStatement ||
       // TODO(turbofan): Make ES6 for-of work and remove this bailout.
       info()->function()->dont_optimize_reason() == kForOfStatement ||
       // TODO(turbofan): Make super work and remove this bailout.
       info()->function()->dont_optimize_reason() == kSuperReference ||
+      // TODO(turbofan): Make class literals work and remove this bailout.
+      info()->function()->dont_optimize_reason() == kClassLiteral ||
       // TODO(turbofan): Make OSR work and remove this bailout.
       info()->is_osr()) {
     return Handle<Code>::null();
   }
 
-  if (FLAG_turbo_stats) isolate()->GetTStatistics()->Initialize(info_);
+  ZonePool zone_pool(isolate());
+  SmartPointer<PipelineStatistics> pipeline_statistics;
+
+  if (FLAG_turbo_stats) {
+    pipeline_statistics.Reset(new PipelineStatistics(info(), &zone_pool));
+    pipeline_statistics->BeginPhaseKind("initializing");
+  }
+
+  PipelineData data(&zone_pool, info());
+  this->data_ = &data;
+  data.Initialize(pipeline_statistics.get());
+
+  BeginPhaseKind("graph creation");
 
   if (FLAG_trace_turbo) {
     OFStream os(stdout);
     os << "---------------------------------------------------\n"
-       << "Begin compiling method "
-       << info()->function()->debug_name()->ToCString().get()
-       << " using Turbofan" << endl;
+       << "Begin compiling method " << GetDebugName(info()).get()
+       << " using Turbofan" << std::endl;
+    TurboCfgFile tcf(isolate());
+    tcf << AsC1VCompilation(info());
   }
 
-  // Build the graph.
-  Graph graph(zone());
-  SourcePositionTable source_positions(&graph);
-  source_positions.AddDecorator();
-  // TODO(turbofan): there is no need to type anything during initial graph
-  // construction.  This is currently only needed for the node cache, which the
-  // typer could sweep over later.
-  Typer typer(zone());
-  MachineOperatorBuilder machine;
-  CommonOperatorBuilder common(zone());
-  JSOperatorBuilder javascript(zone());
-  JSGraph jsgraph(&graph, &common, &javascript, &typer, &machine);
-  Node* context_node;
-  {
-    PhaseStats graph_builder_stats(info(), PhaseStats::CREATE_GRAPH,
-                                   "graph builder");
-    AstGraphBuilderWithPositions graph_builder(info(), &jsgraph,
-                                               &source_positions);
-    graph_builder.CreateGraph();
-    context_node = graph_builder.GetFunctionContext();
-  }
-  {
-    PhaseStats phi_reducer_stats(info(), PhaseStats::CREATE_GRAPH,
-                                 "phi reduction");
-    PhiReducer phi_reducer;
-    GraphReducer graph_reducer(&graph);
-    graph_reducer.AddReducer(&phi_reducer);
-    graph_reducer.ReduceGraph();
-    // TODO(mstarzinger): Running reducer once ought to be enough for everyone.
-    graph_reducer.ReduceGraph();
-    graph_reducer.ReduceGraph();
+  data.source_positions()->AddDecorator();
+
+  if (FLAG_loop_assignment_analysis) {
+    Run<LoopAssignmentAnalysisPhase>();
   }
 
-  VerifyAndPrintGraph(&graph, "Initial untyped");
+  Run<GraphBuilderPhase>();
+  if (data.compilation_failed()) return Handle<Code>::null();
+  RunPrintAndVerify("Initial untyped", true);
+
+  Run<EarlyControlReductionPhase>();
+  RunPrintAndVerify("Early Control reduced", true);
 
   if (info()->is_context_specializing()) {
-    SourcePositionTable::Scope pos(&source_positions,
-                                   SourcePosition::Unknown());
     // Specialize the code to the context as aggressively as possible.
-    JSContextSpecializer spec(info(), &jsgraph, context_node);
-    spec.SpecializeToContext();
-    VerifyAndPrintGraph(&graph, "Context specialized");
+    Run<ContextSpecializerPhase>();
+    RunPrintAndVerify("Context specialized", true);
   }
 
   if (info()->is_inlining_enabled()) {
-    SourcePositionTable::Scope pos(&source_positions,
-                                   SourcePosition::Unknown());
-    JSInliner inliner(info(), &jsgraph);
-    inliner.Inline();
-    VerifyAndPrintGraph(&graph, "Inlined");
+    Run<InliningPhase>();
+    RunPrintAndVerify("Inlined", true);
   }
 
-  // Print a replay of the initial graph.
   if (FLAG_print_turbo_replay) {
-    GraphReplayPrinter::PrintReplay(&graph);
+    // Print a replay of the initial graph.
+    GraphReplayPrinter::PrintReplay(data.graph());
   }
 
+  // Bailout here in case target architecture is not supported.
+  if (!SupportedTarget()) return Handle<Code>::null();
+
   if (info()->is_typing_enabled()) {
-    {
-      // Type the graph.
-      PhaseStats typer_stats(info(), PhaseStats::CREATE_GRAPH, "typer");
-      typer.Run(&graph, info()->context());
-      VerifyAndPrintGraph(&graph, "Typed");
-    }
-    // All new nodes must be typed.
-    typer.DecorateGraph(&graph);
-    {
-      // Lower JSOperators where we can determine types.
-      PhaseStats lowering_stats(info(), PhaseStats::CREATE_GRAPH,
-                                "typed lowering");
-      SourcePositionTable::Scope pos(&source_positions,
-                                     SourcePosition::Unknown());
-      JSTypedLowering lowering(&jsgraph);
-      GraphReducer graph_reducer(&graph);
-      graph_reducer.AddReducer(&lowering);
-      graph_reducer.ReduceGraph();
-
-      VerifyAndPrintGraph(&graph, "Lowered typed");
-    }
-    {
-      // Lower simplified operators and insert changes.
-      PhaseStats lowering_stats(info(), PhaseStats::CREATE_GRAPH,
-                                "simplified lowering");
-      SourcePositionTable::Scope pos(&source_positions,
-                                     SourcePosition::Unknown());
-      SimplifiedLowering lowering(&jsgraph);
-      lowering.LowerAllNodes();
-
-      VerifyAndPrintGraph(&graph, "Lowered simplified");
-    }
-    {
-      // Lower changes that have been inserted before.
-      PhaseStats lowering_stats(info(), PhaseStats::OPTIMIZATION,
-                                "change lowering");
-      SourcePositionTable::Scope pos(&source_positions,
-                                     SourcePosition::Unknown());
-      Linkage linkage(info());
-      // TODO(turbofan): Value numbering disabled for now.
-      // ValueNumberingReducer vn_reducer(zone());
-      SimplifiedOperatorReducer simple_reducer(&jsgraph);
-      ChangeLowering lowering(&jsgraph, &linkage);
-      MachineOperatorReducer mach_reducer(&jsgraph);
-      GraphReducer graph_reducer(&graph);
-      // TODO(titzer): Figure out if we should run all reducers at once here.
-      // graph_reducer.AddReducer(&vn_reducer);
-      graph_reducer.AddReducer(&simple_reducer);
-      graph_reducer.AddReducer(&lowering);
-      graph_reducer.AddReducer(&mach_reducer);
-      graph_reducer.ReduceGraph();
-
-      VerifyAndPrintGraph(&graph, "Lowered changes");
-    }
+    // Type the graph.
+    Run<TyperPhase>();
+    RunPrintAndVerify("Typed");
   }
 
-  Handle<Code> code = Handle<Code>::null();
-  if (SupportedTarget()) {
-    {
-      // Lower any remaining generic JSOperators.
-      PhaseStats lowering_stats(info(), PhaseStats::CREATE_GRAPH,
-                                "generic lowering");
-      SourcePositionTable::Scope pos(&source_positions,
-                                     SourcePosition::Unknown());
-      JSGenericLowering lowering(info(), &jsgraph);
-      GraphReducer graph_reducer(&graph);
-      graph_reducer.AddReducer(&lowering);
-      graph_reducer.ReduceGraph();
+  BeginPhaseKind("lowering");
 
-      VerifyAndPrintGraph(&graph, "Lowered generic");
-    }
+  if (info()->is_typing_enabled()) {
+    // Lower JSOperators where we can determine types.
+    Run<TypedLoweringPhase>();
+    RunPrintAndVerify("Lowered typed");
 
-    {
-      // Compute a schedule.
-      Schedule* schedule = ComputeSchedule(&graph);
-      // Generate optimized code.
-      PhaseStats codegen_stats(info(), PhaseStats::CODEGEN, "codegen");
-      Linkage linkage(info());
-      code = GenerateCode(&linkage, &graph, schedule, &source_positions);
-      info()->SetCode(code);
-    }
+    // Lower simplified operators and insert changes.
+    Run<SimplifiedLoweringPhase>();
+    RunPrintAndVerify("Lowered simplified");
 
-    // Print optimized code.
-    v8::internal::CodeGenerator::PrintCode(code, info());
+    // Lower changes that have been inserted before.
+    Run<ChangeLoweringPhase>();
+    // // TODO(jarin, rossberg): Remove UNTYPED once machine typing works.
+    RunPrintAndVerify("Lowered changes", true);
+
+    Run<LateControlReductionPhase>();
+    RunPrintAndVerify("Late Control reduced");
   }
 
+  // Lower any remaining generic JSOperators.
+  Run<GenericLoweringPhase>();
+  // TODO(jarin, rossberg): Remove UNTYPED once machine typing works.
+  RunPrintAndVerify("Lowered generic", true);
+
+  BeginPhaseKind("block building");
+
+  data.source_positions()->RemoveDecorator();
+
+  // Compute a schedule.
+  Run<ComputeSchedulePhase>();
+
+  {
+    // Generate optimized code.
+    Linkage linkage(data.instruction_zone(), info());
+    GenerateCode(&linkage);
+  }
+  Handle<Code> code = data.code();
+  info()->SetCode(code);
+
+  // Print optimized code.
+  v8::internal::CodeGenerator::PrintCode(code, info());
+
   if (FLAG_trace_turbo) {
     OFStream os(stdout);
-    os << "--------------------------------------------------\n"
-       << "Finished compiling method "
-       << info()->function()->debug_name()->ToCString().get()
-       << " using Turbofan" << endl;
+    os << "---------------------------------------------------\n"
+       << "Finished compiling method " << GetDebugName(info()).get()
+       << " using Turbofan" << std::endl;
   }
 
   return code;
 }
 
 
-Schedule* Pipeline::ComputeSchedule(Graph* graph) {
-  PhaseStats schedule_stats(info(), PhaseStats::CODEGEN, "scheduling");
-  Schedule* schedule = Scheduler::ComputeSchedule(graph);
-  TraceSchedule(schedule);
-  if (VerifyGraphs()) ScheduleVerifier::Run(schedule);
-  return schedule;
+Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
+                                              Graph* graph,
+                                              Schedule* schedule) {
+  CallDescriptor* call_descriptor =
+      Linkage::ComputeIncoming(info->zone(), info);
+  return GenerateCodeForTesting(info, call_descriptor, graph, schedule);
 }
 
 
-Handle<Code> Pipeline::GenerateCodeForMachineGraph(Linkage* linkage,
-                                                   Graph* graph,
-                                                   Schedule* schedule) {
-  CHECK(SupportedBackend());
-  if (schedule == NULL) {
-    VerifyAndPrintGraph(graph, "Machine");
-    schedule = ComputeSchedule(graph);
-  }
-  TraceSchedule(schedule);
+Handle<Code> Pipeline::GenerateCodeForTesting(CallDescriptor* call_descriptor,
+                                              Graph* graph,
+                                              Schedule* schedule) {
+  CompilationInfo info(graph->zone()->isolate(), graph->zone());
+  return GenerateCodeForTesting(&info, call_descriptor, graph, schedule);
+}
 
-  SourcePositionTable source_positions(graph);
-  Handle<Code> code = GenerateCode(linkage, graph, schedule, &source_positions);
+
+Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
+                                              CallDescriptor* call_descriptor,
+                                              Graph* graph,
+                                              Schedule* schedule) {
+  CHECK(SupportedBackend());
+  ZonePool zone_pool(info->isolate());
+  Pipeline pipeline(info);
+  PipelineData data(&zone_pool, info);
+  pipeline.data_ = &data;
+  data.InitializeTorTesting(graph, schedule);
+  if (schedule == NULL) {
+    // TODO(rossberg): Should this really be untyped?
+    pipeline.RunPrintAndVerify("Machine", true);
+    pipeline.Run<ComputeSchedulePhase>();
+  } else {
+    TraceSchedule(schedule);
+  }
+
+  Linkage linkage(info->zone(), call_descriptor);
+  pipeline.GenerateCode(&linkage);
+  Handle<Code> code = data.code();
+
 #if ENABLE_DISASSEMBLER
   if (!code.is_null() && FLAG_print_opt_code) {
-    CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
+    CodeTracer::Scope tracing_scope(info->isolate()->GetCodeTracer());
     OFStream os(tracing_scope.file());
     code->Disassemble("test code", os);
   }
@@ -360,51 +926,157 @@
 }
 
 
-Handle<Code> Pipeline::GenerateCode(Linkage* linkage, Graph* graph,
-                                    Schedule* schedule,
-                                    SourcePositionTable* source_positions) {
-  DCHECK_NOT_NULL(graph);
+bool Pipeline::AllocateRegistersForTesting(const RegisterConfiguration* config,
+                                           InstructionSequence* sequence,
+                                           bool run_verifier) {
+  CompilationInfo info(sequence->zone()->isolate(), sequence->zone());
+  ZonePool zone_pool(sequence->zone()->isolate());
+  PipelineData data(&zone_pool, &info);
+  data.InitializeTorTesting(sequence);
+  Pipeline pipeline(&info);
+  pipeline.data_ = &data;
+  pipeline.AllocateRegisters(config, run_verifier);
+  return !data.compilation_failed();
+}
+
+
+void Pipeline::GenerateCode(Linkage* linkage) {
+  PipelineData* data = this->data_;
+
   DCHECK_NOT_NULL(linkage);
-  DCHECK_NOT_NULL(schedule);
+  DCHECK_NOT_NULL(data->graph());
+  DCHECK_NOT_NULL(data->schedule());
   CHECK(SupportedBackend());
 
-  InstructionSequence sequence(linkage, graph, schedule);
+  BasicBlockProfiler::Data* profiler_data = NULL;
+  if (FLAG_turbo_profiling) {
+    profiler_data = BasicBlockInstrumentor::Instrument(info(), data->graph(),
+                                                       data->schedule());
+  }
+
+  data->InitializeInstructionSequence();
 
   // Select and schedule instructions covering the scheduled graph.
-  {
-    InstructionSelector selector(&sequence, source_positions);
-    selector.SelectInstructions();
+  Run<InstructionSelectionPhase>(linkage);
+
+  if (FLAG_trace_turbo && !data->MayHaveUnverifiableGraph()) {
+    TurboCfgFile tcf(isolate());
+    tcf << AsC1V("CodeGen", data->schedule(), data->source_positions(),
+                 data->sequence());
   }
 
-  if (FLAG_trace_turbo) {
-    OFStream os(stdout);
-    os << "----- Instruction sequence before register allocation -----\n"
-       << sequence;
-  }
+  data->DeleteGraphZone();
 
+  BeginPhaseKind("register allocation");
+
+  bool run_verifier = false;
+#ifdef DEBUG
+  run_verifier = true;
+#endif
   // Allocate registers.
-  {
-    int node_count = graph->NodeCount();
-    if (node_count > UnallocatedOperand::kMaxVirtualRegisters) {
-      linkage->info()->AbortOptimization(kNotEnoughVirtualRegistersForValues);
-      return Handle<Code>::null();
-    }
-    RegisterAllocator allocator(&sequence);
-    if (!allocator.Allocate()) {
-      linkage->info()->AbortOptimization(kNotEnoughVirtualRegistersRegalloc);
-      return Handle<Code>::null();
-    }
+  AllocateRegisters(RegisterConfiguration::ArchDefault(), run_verifier);
+  if (data->compilation_failed()) {
+    info()->AbortOptimization(kNotEnoughVirtualRegistersRegalloc);
+    return;
   }
 
-  if (FLAG_trace_turbo) {
+  BeginPhaseKind("code generation");
+
+  // Optimimize jumps.
+  if (FLAG_turbo_jt) {
+    Run<JumpThreadingPhase>();
+  }
+
+  // Generate final machine code.
+  Run<GenerateCodePhase>(linkage);
+
+  if (profiler_data != NULL) {
+#if ENABLE_DISASSEMBLER
+    std::ostringstream os;
+    data->code()->Disassemble(NULL, os);
+    profiler_data->SetCode(&os);
+#endif
+  }
+}
+
+
+void Pipeline::AllocateRegisters(const RegisterConfiguration* config,
+                                 bool run_verifier) {
+  PipelineData* data = this->data_;
+
+  int node_count = data->sequence()->VirtualRegisterCount();
+  if (node_count > UnallocatedOperand::kMaxVirtualRegisters) {
+    data->set_compilation_failed();
+    return;
+  }
+
+  // Don't track usage for this zone in compiler stats.
+  SmartPointer<Zone> verifier_zone;
+  RegisterAllocatorVerifier* verifier = nullptr;
+  if (run_verifier) {
+    verifier_zone.Reset(new Zone(info()->isolate()));
+    verifier = new (verifier_zone.get()) RegisterAllocatorVerifier(
+        verifier_zone.get(), config, data->sequence());
+  }
+
+  SmartArrayPointer<char> debug_name;
+#ifdef DEBUG
+  debug_name = GetDebugName(data->info());
+#endif
+
+  ZonePool::Scope zone_scope(data->zone_pool());
+  data->InitializeRegisterAllocator(zone_scope.zone(), config,
+                                    debug_name.get());
+
+  Run<MeetRegisterConstraintsPhase>();
+  Run<ResolvePhisPhase>();
+  Run<BuildLiveRangesPhase>();
+  if (FLAG_trace_turbo_graph) {
     OFStream os(stdout);
-    os << "----- Instruction sequence after register allocation -----\n"
-       << sequence;
+    PrintableInstructionSequence printable = {config, data->sequence()};
+    os << "----- Instruction sequence before register allocation -----\n"
+       << printable;
+  }
+  if (verifier != nullptr) {
+    CHECK(!data->register_allocator()->ExistsUseWithoutDefinition());
+  }
+  Run<AllocateGeneralRegistersPhase>();
+  if (!data->register_allocator()->AllocationOk()) {
+    data->set_compilation_failed();
+    return;
+  }
+  Run<AllocateDoubleRegistersPhase>();
+  if (!data->register_allocator()->AllocationOk()) {
+    data->set_compilation_failed();
+    return;
+  }
+  if (FLAG_turbo_reuse_spill_slots) {
+    Run<ReuseSpillSlotsPhase>();
+  }
+  Run<CommitAssignmentPhase>();
+  Run<PopulatePointerMapsPhase>();
+  Run<ConnectRangesPhase>();
+  Run<ResolveControlFlowPhase>();
+  if (FLAG_turbo_move_optimization) {
+    Run<OptimizeMovesPhase>();
   }
 
-  // Generate native sequence.
-  CodeGenerator generator(&sequence);
-  return generator.GenerateCode();
+  if (FLAG_trace_turbo_graph) {
+    OFStream os(stdout);
+    PrintableInstructionSequence printable = {config, data->sequence()};
+    os << "----- Instruction sequence after register allocation -----\n"
+       << printable;
+  }
+
+  if (verifier != nullptr) {
+    verifier->VerifyAssignment();
+    verifier->VerifyGapMoves();
+  }
+
+  if (FLAG_trace_turbo && !data->MayHaveUnverifiableGraph()) {
+    TurboCfgFile tcf(data->isolate());
+    tcf << AsC1VAllocator("CodeGen", data->register_allocator());
+  }
 }
 
 
diff --git a/src/compiler/pipeline.h b/src/compiler/pipeline.h
index 9f8241a..73053dc 100644
--- a/src/compiler/pipeline.h
+++ b/src/compiler/pipeline.h
@@ -17,10 +17,13 @@
 namespace compiler {
 
 // Clients of this interface shouldn't depend on lots of compiler internals.
+class CallDescriptor;
 class Graph;
-class Schedule;
-class SourcePositionTable;
+class InstructionSequence;
 class Linkage;
+class PipelineData;
+class RegisterConfiguration;
+class Schedule;
 
 class Pipeline {
  public:
@@ -29,10 +32,22 @@
   // Run the entire pipeline and generate a handle to a code object.
   Handle<Code> GenerateCode();
 
-  // Run the pipeline on a machine graph and generate code. If {schedule}
-  // is {NULL}, then compute a new schedule for code generation.
-  Handle<Code> GenerateCodeForMachineGraph(Linkage* linkage, Graph* graph,
-                                           Schedule* schedule = NULL);
+  // Run the pipeline on a machine graph and generate code. If {schedule} is
+  // {nullptr}, then compute a new schedule for code generation.
+  static Handle<Code> GenerateCodeForTesting(CompilationInfo* info,
+                                             Graph* graph,
+                                             Schedule* schedule = nullptr);
+
+  // Run the pipeline on a machine graph and generate code. If {schedule} is
+  // {nullptr}, then compute a new schedule for code generation.
+  static Handle<Code> GenerateCodeForTesting(CallDescriptor* call_descriptor,
+                                             Graph* graph,
+                                             Schedule* schedule = nullptr);
+
+  // Run just the register allocator phases.
+  static bool AllocateRegistersForTesting(const RegisterConfiguration* config,
+                                          InstructionSequence* sequence,
+                                          bool run_verifier);
 
   static inline bool SupportedBackend() { return V8_TURBOFAN_BACKEND != 0; }
   static inline bool SupportedTarget() { return V8_TURBOFAN_TARGET != 0; }
@@ -41,19 +56,31 @@
   static void TearDown();
 
  private:
+  static Handle<Code> GenerateCodeForTesting(CompilationInfo* info,
+                                             CallDescriptor* call_descriptor,
+                                             Graph* graph, Schedule* schedule);
+
   CompilationInfo* info_;
+  PipelineData* data_;
+
+  // Helpers for executing pipeline phases.
+  template <typename Phase>
+  void Run();
+  template <typename Phase, typename Arg0>
+  void Run(Arg0 arg_0);
 
   CompilationInfo* info() const { return info_; }
   Isolate* isolate() { return info_->isolate(); }
-  Zone* zone() { return info_->zone(); }
 
-  Schedule* ComputeSchedule(Graph* graph);
-  void VerifyAndPrintGraph(Graph* graph, const char* phase);
-  Handle<Code> GenerateCode(Linkage* linkage, Graph* graph, Schedule* schedule,
-                            SourcePositionTable* source_positions);
+  void BeginPhaseKind(const char* phase_kind);
+  void RunPrintAndVerify(const char* phase, bool untyped = false);
+  void GenerateCode(Linkage* linkage);
+  void AllocateRegisters(const RegisterConfiguration* config,
+                         bool run_verifier);
 };
-}
-}
-}  // namespace v8::internal::compiler
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_PIPELINE_H_
diff --git a/src/compiler/raw-machine-assembler.cc b/src/compiler/raw-machine-assembler.cc
index 7f45eb9..b93ec66 100644
--- a/src/compiler/raw-machine-assembler.cc
+++ b/src/compiler/raw-machine-assembler.cc
@@ -13,10 +13,11 @@
 
 RawMachineAssembler::RawMachineAssembler(Graph* graph,
                                          MachineSignature* machine_sig,
-                                         MachineType word)
+                                         MachineType word,
+                                         MachineOperatorBuilder::Flags flags)
     : GraphBuilder(graph),
       schedule_(new (zone()) Schedule(zone())),
-      machine_(word),
+      machine_(zone(), word, flags),
       common_(zone()),
       machine_sig_(machine_sig),
       call_descriptor_(
@@ -39,7 +40,7 @@
 Schedule* RawMachineAssembler::Export() {
   // Compute the correct codegen order.
   DCHECK(schedule_->rpo_order()->empty());
-  Scheduler::ComputeSpecialRPO(schedule_);
+  Scheduler::ComputeSpecialRPO(zone(), schedule_);
   // Invalidate MachineAssembler.
   Schedule* schedule = schedule_;
   schedule_ = NULL;
@@ -86,7 +87,8 @@
                                              CallFunctionFlags flags) {
   Callable callable = CodeFactory::CallFunction(isolate(), 0, flags);
   CallDescriptor* desc = Linkage::GetStubCallDescriptor(
-      callable.descriptor(), 1, CallDescriptor::kNeedsFrameState, zone());
+      callable.descriptor(), 1, CallDescriptor::kNeedsFrameState,
+      Operator::kNoProperties, zone());
   Node* stub_code = HeapConstant(callable.code());
   Node* call = graph()->NewNode(common()->Call(desc), stub_code, function,
                                 receiver, context, frame_state);
@@ -97,7 +99,8 @@
 
 Node* RawMachineAssembler::CallJS0(Node* function, Node* receiver,
                                    Node* context, Node* frame_state) {
-  CallDescriptor* descriptor = Linkage::GetJSCallDescriptor(1, zone());
+  CallDescriptor* descriptor =
+      Linkage::GetJSCallDescriptor(1, zone(), CallDescriptor::kNeedsFrameState);
   Node* call = graph()->NewNode(common()->Call(descriptor), function, receiver,
                                 context, frame_state);
   schedule()->AddNode(CurrentBlock(), call);
@@ -150,10 +153,10 @@
 
 
 Node* RawMachineAssembler::MakeNode(const Operator* op, int input_count,
-                                    Node** inputs) {
+                                    Node** inputs, bool incomplete) {
   DCHECK(ScheduleValid());
   DCHECK(current_block_ != NULL);
-  Node* node = graph()->NewNode(op, input_count, inputs);
+  Node* node = graph()->NewNode(op, input_count, inputs, incomplete);
   BasicBlock* block = op->opcode() == IrOpcode::kParameter ? schedule()->start()
                                                            : CurrentBlock();
   schedule()->AddNode(block, node);
diff --git a/src/compiler/raw-machine-assembler.h b/src/compiler/raw-machine-assembler.h
index a4af55a..5455814 100644
--- a/src/compiler/raw-machine-assembler.h
+++ b/src/compiler/raw-machine-assembler.h
@@ -45,8 +45,10 @@
   };
 
   RawMachineAssembler(Graph* graph, MachineSignature* machine_sig,
-                      MachineType word = kMachPtr);
-  virtual ~RawMachineAssembler() {}
+                      MachineType word = kMachPtr,
+                      MachineOperatorBuilder::Flags flags =
+                          MachineOperatorBuilder::Flag::kNoFlags);
+  ~RawMachineAssembler() OVERRIDE {}
 
   Isolate* isolate() const { return zone()->isolate(); }
   Zone* zone() const { return graph()->zone(); }
@@ -57,7 +59,7 @@
   MachineSignature* machine_sig() const { return machine_sig_; }
 
   Node* UndefinedConstant() {
-    Unique<Object> unique = Unique<Object>::CreateImmovable(
+    Unique<HeapObject> unique = Unique<HeapObject>::CreateImmovable(
         isolate()->factory()->undefined_value());
     return NewNode(common()->HeapConstant(unique));
   }
@@ -80,11 +82,14 @@
   Node* NumberConstant(double value) {
     return NewNode(common()->NumberConstant(value));
   }
+  Node* Float32Constant(float value) {
+    return NewNode(common()->Float32Constant(value));
+  }
   Node* Float64Constant(double value) {
     return NewNode(common()->Float64Constant(value));
   }
-  Node* HeapConstant(Handle<Object> object) {
-    Unique<Object> val = Unique<Object>::CreateUninitialized(object);
+  Node* HeapConstant(Handle<HeapObject> object) {
+    Unique<HeapObject> val = Unique<HeapObject>::CreateUninitialized(object);
     return NewNode(common()->HeapConstant(val));
   }
 
@@ -97,14 +102,15 @@
     return Load(rep, base, Int32Constant(0));
   }
   Node* Load(MachineType rep, Node* base, Node* index) {
-    return NewNode(machine()->Load(rep), base, index);
+    return NewNode(machine()->Load(rep), base, index, graph()->start(),
+                   graph()->start());
   }
   void Store(MachineType rep, Node* base, Node* value) {
     Store(rep, base, Int32Constant(0), value);
   }
   void Store(MachineType rep, Node* base, Node* index, Node* value) {
     NewNode(machine()->Store(StoreRepresentation(rep, kNoWriteBarrier)), base,
-            index, value);
+            index, value, graph()->start(), graph()->start());
   }
   // Arithmetic Operations.
   Node* WordAnd(Node* a, Node* b) {
@@ -222,17 +228,14 @@
   Node* Int32Mul(Node* a, Node* b) {
     return NewNode(machine()->Int32Mul(), a, b);
   }
-  Node* Int32Div(Node* a, Node* b) {
-    return NewNode(machine()->Int32Div(), a, b);
+  Node* Int32MulHigh(Node* a, Node* b) {
+    return NewNode(machine()->Int32MulHigh(), a, b);
   }
-  Node* Int32UDiv(Node* a, Node* b) {
-    return NewNode(machine()->Int32UDiv(), a, b);
+  Node* Int32Div(Node* a, Node* b) {
+    return NewNode(machine()->Int32Div(), a, b, graph()->start());
   }
   Node* Int32Mod(Node* a, Node* b) {
-    return NewNode(machine()->Int32Mod(), a, b);
-  }
-  Node* Int32UMod(Node* a, Node* b) {
-    return NewNode(machine()->Int32UMod(), a, b);
+    return NewNode(machine()->Int32Mod(), a, b, graph()->start());
   }
   Node* Int32LessThan(Node* a, Node* b) {
     return NewNode(machine()->Int32LessThan(), a, b);
@@ -240,12 +243,21 @@
   Node* Int32LessThanOrEqual(Node* a, Node* b) {
     return NewNode(machine()->Int32LessThanOrEqual(), a, b);
   }
+  Node* Uint32Div(Node* a, Node* b) {
+    return NewNode(machine()->Uint32Div(), a, b, graph()->start());
+  }
   Node* Uint32LessThan(Node* a, Node* b) {
     return NewNode(machine()->Uint32LessThan(), a, b);
   }
   Node* Uint32LessThanOrEqual(Node* a, Node* b) {
     return NewNode(machine()->Uint32LessThanOrEqual(), a, b);
   }
+  Node* Uint32Mod(Node* a, Node* b) {
+    return NewNode(machine()->Uint32Mod(), a, b, graph()->start());
+  }
+  Node* Uint32MulHigh(Node* a, Node* b) {
+    return NewNode(machine()->Uint32MulHigh(), a, b);
+  }
   Node* Int32GreaterThan(Node* a, Node* b) { return Int32LessThan(b, a); }
   Node* Int32GreaterThanOrEqual(Node* a, Node* b) {
     return Int32LessThanOrEqual(b, a);
@@ -264,15 +276,9 @@
   Node* Int64Div(Node* a, Node* b) {
     return NewNode(machine()->Int64Div(), a, b);
   }
-  Node* Int64UDiv(Node* a, Node* b) {
-    return NewNode(machine()->Int64UDiv(), a, b);
-  }
   Node* Int64Mod(Node* a, Node* b) {
     return NewNode(machine()->Int64Mod(), a, b);
   }
-  Node* Int64UMod(Node* a, Node* b) {
-    return NewNode(machine()->Int64UMod(), a, b);
-  }
   Node* Int64Neg(Node* a) { return Int64Sub(Int64Constant(0), a); }
   Node* Int64LessThan(Node* a, Node* b) {
     return NewNode(machine()->Int64LessThan(), a, b);
@@ -284,6 +290,12 @@
   Node* Int64GreaterThanOrEqual(Node* a, Node* b) {
     return Int64LessThanOrEqual(b, a);
   }
+  Node* Uint64Div(Node* a, Node* b) {
+    return NewNode(machine()->Uint64Div(), a, b);
+  }
+  Node* Uint64Mod(Node* a, Node* b) {
+    return NewNode(machine()->Uint64Mod(), a, b);
+  }
 
   // TODO(turbofan): What is this used for?
   Node* ConvertIntPtrToInt32(Node* a) {
@@ -344,6 +356,9 @@
   }
 
   // Conversions.
+  Node* ChangeFloat32ToFloat64(Node* a) {
+    return NewNode(machine()->ChangeFloat32ToFloat64(), a);
+  }
   Node* ChangeInt32ToFloat64(Node* a) {
     return NewNode(machine()->ChangeInt32ToFloat64(), a);
   }
@@ -362,12 +377,23 @@
   Node* ChangeUint32ToUint64(Node* a) {
     return NewNode(machine()->ChangeUint32ToUint64(), a);
   }
+  Node* TruncateFloat64ToFloat32(Node* a) {
+    return NewNode(machine()->TruncateFloat64ToFloat32(), a);
+  }
   Node* TruncateFloat64ToInt32(Node* a) {
     return NewNode(machine()->TruncateFloat64ToInt32(), a);
   }
   Node* TruncateInt64ToInt32(Node* a) {
     return NewNode(machine()->TruncateInt64ToInt32(), a);
   }
+  Node* Float64Floor(Node* a) { return NewNode(machine()->Float64Floor(), a); }
+  Node* Float64Ceil(Node* a) { return NewNode(machine()->Float64Ceil(), a); }
+  Node* Float64RoundTruncate(Node* a) {
+    return NewNode(machine()->Float64RoundTruncate(), a);
+  }
+  Node* Float64RoundTiesAway(Node* a) {
+    return NewNode(machine()->Float64RoundTiesAway(), a);
+  }
 
   // Parameters.
   Node* Parameter(size_t index);
@@ -404,8 +430,8 @@
   Schedule* Export();
 
  protected:
-  virtual Node* MakeNode(const Operator* op, int input_count,
-                         Node** inputs) FINAL;
+  Node* MakeNode(const Operator* op, int input_count, Node** inputs,
+                 bool incomplete) FINAL;
 
   bool ScheduleValid() { return schedule_ != NULL; }
 
diff --git a/src/compiler/register-allocator-verifier.cc b/src/compiler/register-allocator-verifier.cc
new file mode 100644
index 0000000..dabfd59
--- /dev/null
+++ b/src/compiler/register-allocator-verifier.cc
@@ -0,0 +1,460 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/instruction.h"
+#include "src/compiler/register-allocator-verifier.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+static size_t OperandCount(const Instruction* instr) {
+  return instr->InputCount() + instr->OutputCount() + instr->TempCount();
+}
+
+
+static void VerifyGapEmpty(const GapInstruction* gap) {
+  for (int i = GapInstruction::FIRST_INNER_POSITION;
+       i <= GapInstruction::LAST_INNER_POSITION; i++) {
+    GapInstruction::InnerPosition inner_pos =
+        static_cast<GapInstruction::InnerPosition>(i);
+    CHECK_EQ(NULL, gap->GetParallelMove(inner_pos));
+  }
+}
+
+
+void RegisterAllocatorVerifier::VerifyInput(
+    const OperandConstraint& constraint) {
+  CHECK_NE(kSameAsFirst, constraint.type_);
+  if (constraint.type_ != kImmediate) {
+    CHECK_NE(UnallocatedOperand::kInvalidVirtualRegister,
+             constraint.virtual_register_);
+  }
+}
+
+
+void RegisterAllocatorVerifier::VerifyTemp(
+    const OperandConstraint& constraint) {
+  CHECK_NE(kSameAsFirst, constraint.type_);
+  CHECK_NE(kImmediate, constraint.type_);
+  CHECK_NE(kConstant, constraint.type_);
+  CHECK_EQ(UnallocatedOperand::kInvalidVirtualRegister,
+           constraint.virtual_register_);
+}
+
+
+void RegisterAllocatorVerifier::VerifyOutput(
+    const OperandConstraint& constraint) {
+  CHECK_NE(kImmediate, constraint.type_);
+  CHECK_NE(UnallocatedOperand::kInvalidVirtualRegister,
+           constraint.virtual_register_);
+}
+
+
+RegisterAllocatorVerifier::RegisterAllocatorVerifier(
+    Zone* zone, const RegisterConfiguration* config,
+    const InstructionSequence* sequence)
+    : zone_(zone), config_(config), sequence_(sequence), constraints_(zone) {
+  constraints_.reserve(sequence->instructions().size());
+  // TODO(dcarney): model unique constraints.
+  // Construct OperandConstraints for all InstructionOperands, eliminating
+  // kSameAsFirst along the way.
+  for (const auto* instr : sequence->instructions()) {
+    const size_t operand_count = OperandCount(instr);
+    auto* op_constraints =
+        zone->NewArray<OperandConstraint>(static_cast<int>(operand_count));
+    size_t count = 0;
+    for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
+      BuildConstraint(instr->InputAt(i), &op_constraints[count]);
+      VerifyInput(op_constraints[count]);
+    }
+    for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
+      BuildConstraint(instr->TempAt(i), &op_constraints[count]);
+      VerifyTemp(op_constraints[count]);
+    }
+    for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
+      BuildConstraint(instr->OutputAt(i), &op_constraints[count]);
+      if (op_constraints[count].type_ == kSameAsFirst) {
+        CHECK(instr->InputCount() > 0);
+        op_constraints[count].type_ = op_constraints[0].type_;
+        op_constraints[count].value_ = op_constraints[0].value_;
+      }
+      VerifyOutput(op_constraints[count]);
+    }
+    // All gaps should be totally unallocated at this point.
+    if (instr->IsGapMoves()) {
+      CHECK(operand_count == 0);
+      VerifyGapEmpty(GapInstruction::cast(instr));
+    }
+    InstructionConstraint instr_constraint = {instr, operand_count,
+                                              op_constraints};
+    constraints()->push_back(instr_constraint);
+  }
+}
+
+
+void RegisterAllocatorVerifier::VerifyAssignment() {
+  CHECK(sequence()->instructions().size() == constraints()->size());
+  auto instr_it = sequence()->begin();
+  for (const auto& instr_constraint : *constraints()) {
+    const auto* instr = instr_constraint.instruction_;
+    const size_t operand_count = instr_constraint.operand_constaints_size_;
+    const auto* op_constraints = instr_constraint.operand_constraints_;
+    CHECK_EQ(instr, *instr_it);
+    CHECK(operand_count == OperandCount(instr));
+    size_t count = 0;
+    for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
+      CheckConstraint(instr->InputAt(i), &op_constraints[count]);
+    }
+    for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
+      CheckConstraint(instr->TempAt(i), &op_constraints[count]);
+    }
+    for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
+      CheckConstraint(instr->OutputAt(i), &op_constraints[count]);
+    }
+    ++instr_it;
+  }
+}
+
+
+void RegisterAllocatorVerifier::BuildConstraint(const InstructionOperand* op,
+                                                OperandConstraint* constraint) {
+  constraint->value_ = kMinInt;
+  constraint->virtual_register_ = UnallocatedOperand::kInvalidVirtualRegister;
+  if (op->IsConstant()) {
+    constraint->type_ = kConstant;
+    constraint->value_ = ConstantOperand::cast(op)->index();
+    constraint->virtual_register_ = constraint->value_;
+  } else if (op->IsImmediate()) {
+    constraint->type_ = kImmediate;
+    constraint->value_ = ImmediateOperand::cast(op)->index();
+  } else {
+    CHECK(op->IsUnallocated());
+    const auto* unallocated = UnallocatedOperand::cast(op);
+    int vreg = unallocated->virtual_register();
+    constraint->virtual_register_ = vreg;
+    if (unallocated->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
+      constraint->type_ = kFixedSlot;
+      constraint->value_ = unallocated->fixed_slot_index();
+    } else {
+      switch (unallocated->extended_policy()) {
+        case UnallocatedOperand::ANY:
+          CHECK(false);
+          break;
+        case UnallocatedOperand::NONE:
+          if (sequence()->IsDouble(vreg)) {
+            constraint->type_ = kNoneDouble;
+          } else {
+            constraint->type_ = kNone;
+          }
+          break;
+        case UnallocatedOperand::FIXED_REGISTER:
+          constraint->type_ = kFixedRegister;
+          constraint->value_ = unallocated->fixed_register_index();
+          break;
+        case UnallocatedOperand::FIXED_DOUBLE_REGISTER:
+          constraint->type_ = kFixedDoubleRegister;
+          constraint->value_ = unallocated->fixed_register_index();
+          break;
+        case UnallocatedOperand::MUST_HAVE_REGISTER:
+          if (sequence()->IsDouble(vreg)) {
+            constraint->type_ = kDoubleRegister;
+          } else {
+            constraint->type_ = kRegister;
+          }
+          break;
+        case UnallocatedOperand::SAME_AS_FIRST_INPUT:
+          constraint->type_ = kSameAsFirst;
+          break;
+      }
+    }
+  }
+}
+
+
+void RegisterAllocatorVerifier::CheckConstraint(
+    const InstructionOperand* op, const OperandConstraint* constraint) {
+  switch (constraint->type_) {
+    case kConstant:
+      CHECK(op->IsConstant());
+      CHECK_EQ(op->index(), constraint->value_);
+      return;
+    case kImmediate:
+      CHECK(op->IsImmediate());
+      CHECK_EQ(op->index(), constraint->value_);
+      return;
+    case kRegister:
+      CHECK(op->IsRegister());
+      return;
+    case kFixedRegister:
+      CHECK(op->IsRegister());
+      CHECK_EQ(op->index(), constraint->value_);
+      return;
+    case kDoubleRegister:
+      CHECK(op->IsDoubleRegister());
+      return;
+    case kFixedDoubleRegister:
+      CHECK(op->IsDoubleRegister());
+      CHECK_EQ(op->index(), constraint->value_);
+      return;
+    case kFixedSlot:
+      CHECK(op->IsStackSlot());
+      CHECK_EQ(op->index(), constraint->value_);
+      return;
+    case kNone:
+      CHECK(op->IsRegister() || op->IsStackSlot());
+      return;
+    case kNoneDouble:
+      CHECK(op->IsDoubleRegister() || op->IsDoubleStackSlot());
+      return;
+    case kSameAsFirst:
+      CHECK(false);
+      return;
+  }
+}
+
+
+class RegisterAllocatorVerifier::OutgoingMapping : public ZoneObject {
+ public:
+  struct OperandLess {
+    bool operator()(const InstructionOperand* a,
+                    const InstructionOperand* b) const {
+      if (a->kind() == b->kind()) return a->index() < b->index();
+      return a->kind() < b->kind();
+    }
+  };
+
+  typedef std::map<
+      const InstructionOperand*, int, OperandLess,
+      zone_allocator<std::pair<const InstructionOperand*, const int>>>
+      LocationMap;
+
+  explicit OutgoingMapping(Zone* zone)
+      : locations_(LocationMap::key_compare(),
+                   LocationMap::allocator_type(zone)),
+        predecessor_intersection_(LocationMap::key_compare(),
+                                  LocationMap::allocator_type(zone)) {}
+
+  LocationMap* locations() { return &locations_; }
+
+  void RunPhis(const InstructionSequence* sequence,
+               const InstructionBlock* block, size_t phi_index) {
+    // This operation is only valid in edge split form.
+    size_t predecessor_index = block->predecessors()[phi_index].ToSize();
+    CHECK(sequence->instruction_blocks()[predecessor_index]->SuccessorCount() ==
+          1);
+    for (const auto* phi : block->phis()) {
+      auto input = phi->inputs()[phi_index];
+      CHECK(locations()->find(input) != locations()->end());
+      auto it = locations()->find(phi->output());
+      CHECK(it != locations()->end());
+      if (input->IsConstant()) {
+        CHECK_EQ(it->second, input->index());
+      } else {
+        CHECK_EQ(it->second, phi->operands()[phi_index]);
+      }
+      it->second = phi->virtual_register();
+    }
+  }
+
+  void RunGapInstruction(Zone* zone, const GapInstruction* gap) {
+    for (int i = GapInstruction::FIRST_INNER_POSITION;
+         i <= GapInstruction::LAST_INNER_POSITION; i++) {
+      GapInstruction::InnerPosition inner_pos =
+          static_cast<GapInstruction::InnerPosition>(i);
+      const ParallelMove* move = gap->GetParallelMove(inner_pos);
+      if (move == nullptr) continue;
+      RunParallelMoves(zone, move);
+    }
+  }
+
+  void RunParallelMoves(Zone* zone, const ParallelMove* move) {
+    // Compute outgoing mappings.
+    LocationMap to_insert((LocationMap::key_compare()),
+                          LocationMap::allocator_type(zone));
+    auto* moves = move->move_operands();
+    for (auto i = moves->begin(); i != moves->end(); ++i) {
+      if (i->IsEliminated()) continue;
+      auto cur = locations()->find(i->source());
+      CHECK(cur != locations()->end());
+      to_insert.insert(std::make_pair(i->destination(), cur->second));
+    }
+    // Drop current mappings.
+    for (auto i = moves->begin(); i != moves->end(); ++i) {
+      if (i->IsEliminated()) continue;
+      auto cur = locations()->find(i->destination());
+      if (cur != locations()->end()) locations()->erase(cur);
+    }
+    // Insert new values.
+    locations()->insert(to_insert.begin(), to_insert.end());
+  }
+
+  void Map(const InstructionOperand* op, int virtual_register) {
+    locations()->insert(std::make_pair(op, virtual_register));
+  }
+
+  void Drop(const InstructionOperand* op) {
+    auto it = locations()->find(op);
+    if (it != locations()->end()) locations()->erase(it);
+  }
+
+  void DropRegisters(const RegisterConfiguration* config) {
+    for (int i = 0; i < config->num_general_registers(); ++i) {
+      InstructionOperand op(InstructionOperand::REGISTER, i);
+      Drop(&op);
+    }
+    for (int i = 0; i < config->num_double_registers(); ++i) {
+      InstructionOperand op(InstructionOperand::DOUBLE_REGISTER, i);
+      Drop(&op);
+    }
+  }
+
+  void InitializeFromFirstPredecessor(const InstructionSequence* sequence,
+                                      const OutgoingMappings* outgoing_mappings,
+                                      const InstructionBlock* block) {
+    if (block->predecessors().empty()) return;
+    size_t predecessor_index = block->predecessors()[0].ToSize();
+    CHECK(predecessor_index < block->rpo_number().ToSize());
+    auto* incoming = outgoing_mappings->at(predecessor_index);
+    if (block->PredecessorCount() > 1) {
+      // Update incoming map with phis. The remaining phis will be checked later
+      // as their mappings are not guaranteed to exist yet.
+      incoming->RunPhis(sequence, block, 0);
+    }
+    // Now initialize outgoing mapping for this block with incoming mapping.
+    CHECK(locations_.empty());
+    locations_ = incoming->locations_;
+  }
+
+  void InitializeFromIntersection() { locations_ = predecessor_intersection_; }
+
+  void InitializeIntersection(const OutgoingMapping* incoming) {
+    CHECK(predecessor_intersection_.empty());
+    predecessor_intersection_ = incoming->locations_;
+  }
+
+  void Intersect(const OutgoingMapping* other) {
+    if (predecessor_intersection_.empty()) return;
+    auto it = predecessor_intersection_.begin();
+    OperandLess less;
+    for (const auto& o : other->locations_) {
+      while (less(it->first, o.first)) {
+        ++it;
+        if (it == predecessor_intersection_.end()) return;
+      }
+      if (it->first->Equals(o.first)) {
+        if (o.second != it->second) {
+          predecessor_intersection_.erase(it++);
+        } else {
+          ++it;
+        }
+        if (it == predecessor_intersection_.end()) return;
+      }
+    }
+  }
+
+ private:
+  LocationMap locations_;
+  LocationMap predecessor_intersection_;
+
+  DISALLOW_COPY_AND_ASSIGN(OutgoingMapping);
+};
+
+
+// Verify that all gap moves move the operands for a virtual register into the
+// correct location for every instruction.
+void RegisterAllocatorVerifier::VerifyGapMoves() {
+  typedef ZoneVector<OutgoingMapping*> OutgoingMappings;
+  OutgoingMappings outgoing_mappings(
+      static_cast<int>(sequence()->instruction_blocks().size()), nullptr,
+      zone());
+  // Construct all mappings, ignoring back edges and multiple entries.
+  ConstructOutgoingMappings(&outgoing_mappings, true);
+  // Run all remaining phis and compute the intersection of all predecessor
+  // mappings.
+  for (const auto* block : sequence()->instruction_blocks()) {
+    if (block->PredecessorCount() == 0) continue;
+    const size_t block_index = block->rpo_number().ToSize();
+    auto* mapping = outgoing_mappings[block_index];
+    bool initialized = false;
+    // Walk predecessors in reverse to ensure Intersect is correctly working.
+    // If it did nothing, the second pass would do exactly what the first pass
+    // did.
+    for (size_t phi_input = block->PredecessorCount() - 1; true; --phi_input) {
+      const size_t pred_block_index = block->predecessors()[phi_input].ToSize();
+      auto* incoming = outgoing_mappings[pred_block_index];
+      if (phi_input != 0) incoming->RunPhis(sequence(), block, phi_input);
+      if (!initialized) {
+        mapping->InitializeIntersection(incoming);
+        initialized = true;
+      } else {
+        mapping->Intersect(incoming);
+      }
+      if (phi_input == 0) break;
+    }
+  }
+  // Construct all mappings again, this time using the instersection mapping
+  // above as the incoming mapping instead of the result from the first
+  // predecessor.
+  ConstructOutgoingMappings(&outgoing_mappings, false);
+}
+
+
+void RegisterAllocatorVerifier::ConstructOutgoingMappings(
+    OutgoingMappings* outgoing_mappings, bool initial_pass) {
+  // Compute the locations of all virtual registers leaving every block, using
+  // only the first predecessor as source for the input mapping.
+  for (const auto* block : sequence()->instruction_blocks()) {
+    const size_t block_index = block->rpo_number().ToSize();
+    auto* current = outgoing_mappings->at(block_index);
+    CHECK(initial_pass == (current == nullptr));
+    // Initialize current.
+    if (!initial_pass) {
+      // Skip check second time around for blocks without multiple predecessors
+      // as we have already executed this in the initial run.
+      if (block->PredecessorCount() <= 1) continue;
+      current->InitializeFromIntersection();
+    } else {
+      current = new (zone()) OutgoingMapping(zone());
+      outgoing_mappings->at(block_index) = current;
+      // Copy outgoing values from predecessor block.
+      current->InitializeFromFirstPredecessor(sequence(), outgoing_mappings,
+                                              block);
+    }
+    // Update current with gaps and operands for all instructions in block.
+    for (int instr_index = block->code_start(); instr_index < block->code_end();
+         ++instr_index) {
+      const auto& instr_constraint = constraints_[instr_index];
+      const auto* instr = instr_constraint.instruction_;
+      const auto* op_constraints = instr_constraint.operand_constraints_;
+      size_t count = 0;
+      for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
+        if (op_constraints[count].type_ == kImmediate) continue;
+        auto it = current->locations()->find(instr->InputAt(i));
+        int virtual_register = op_constraints[count].virtual_register_;
+        CHECK(it != current->locations()->end());
+        CHECK_EQ(it->second, virtual_register);
+      }
+      for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
+        current->Drop(instr->TempAt(i));
+      }
+      if (instr->IsCall()) {
+        current->DropRegisters(config());
+      }
+      for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
+        current->Drop(instr->OutputAt(i));
+        int virtual_register = op_constraints[count].virtual_register_;
+        current->Map(instr->OutputAt(i), virtual_register);
+      }
+      if (instr->IsGapMoves()) {
+        const auto* gap = GapInstruction::cast(instr);
+        current->RunGapInstruction(zone(), gap);
+      }
+    }
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/register-allocator-verifier.h b/src/compiler/register-allocator-verifier.h
new file mode 100644
index 0000000..4e35dc2
--- /dev/null
+++ b/src/compiler/register-allocator-verifier.h
@@ -0,0 +1,86 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_REGISTER_ALLOCATOR_VERIFIER_H_
+#define V8_REGISTER_ALLOCATOR_VERIFIER_H_
+
+#include "src/v8.h"
+#include "src/zone-containers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class InstructionOperand;
+class InstructionSequence;
+
+class RegisterAllocatorVerifier FINAL : public ZoneObject {
+ public:
+  RegisterAllocatorVerifier(Zone* zone, const RegisterConfiguration* config,
+                            const InstructionSequence* sequence);
+
+  void VerifyAssignment();
+  void VerifyGapMoves();
+
+ private:
+  enum ConstraintType {
+    kConstant,
+    kImmediate,
+    kRegister,
+    kFixedRegister,
+    kDoubleRegister,
+    kFixedDoubleRegister,
+    kFixedSlot,
+    kNone,
+    kNoneDouble,
+    kSameAsFirst
+  };
+
+  struct OperandConstraint {
+    ConstraintType type_;
+    int value_;  // subkind index when relevant
+    int virtual_register_;
+  };
+
+  struct InstructionConstraint {
+    const Instruction* instruction_;
+    size_t operand_constaints_size_;
+    OperandConstraint* operand_constraints_;
+  };
+
+  class OutgoingMapping;
+
+  typedef ZoneVector<InstructionConstraint> Constraints;
+  typedef ZoneVector<OutgoingMapping*> OutgoingMappings;
+
+  Zone* zone() const { return zone_; }
+  const RegisterConfiguration* config() { return config_; }
+  const InstructionSequence* sequence() const { return sequence_; }
+  Constraints* constraints() { return &constraints_; }
+
+  static void VerifyInput(const OperandConstraint& constraint);
+  static void VerifyTemp(const OperandConstraint& constraint);
+  static void VerifyOutput(const OperandConstraint& constraint);
+
+  void BuildConstraint(const InstructionOperand* op,
+                       OperandConstraint* constraint);
+  void CheckConstraint(const InstructionOperand* op,
+                       const OperandConstraint* constraint);
+
+  void ConstructOutgoingMappings(OutgoingMappings* outgoing_mappings,
+                                 bool initial_pass);
+
+  Zone* const zone_;
+  const RegisterConfiguration* config_;
+  const InstructionSequence* const sequence_;
+  Constraints constraints_;
+
+  DISALLOW_COPY_AND_ASSIGN(RegisterAllocatorVerifier);
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif
diff --git a/src/compiler/register-allocator.cc b/src/compiler/register-allocator.cc
index 972a904..9eb4a47 100644
--- a/src/compiler/register-allocator.cc
+++ b/src/compiler/register-allocator.cc
@@ -2,10 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/compiler/register-allocator.h"
-
 #include "src/compiler/linkage.h"
-#include "src/hydrogen.h"
+#include "src/compiler/register-allocator.h"
 #include "src/string-stream.h"
 
 namespace v8 {
@@ -22,15 +20,32 @@
 }
 
 
+static void TraceAlloc(const char* msg, ...) {
+  if (FLAG_trace_alloc) {
+    va_list arguments;
+    va_start(arguments, msg);
+    base::OS::VPrint(msg, arguments);
+    va_end(arguments);
+  }
+}
+
+
+static void RemoveElement(ZoneVector<LiveRange*>* v, LiveRange* range) {
+  auto it = std::find(v->begin(), v->end(), range);
+  DCHECK(it != v->end());
+  v->erase(it);
+}
+
+
 UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand,
                          InstructionOperand* hint)
     : operand_(operand),
       hint_(hint),
       pos_(pos),
-      next_(NULL),
+      next_(nullptr),
       requires_reg_(false),
       register_beneficial_(true) {
-  if (operand_ != NULL && operand_->IsUnallocated()) {
+  if (operand_ != nullptr && operand_->IsUnallocated()) {
     const UnallocatedOperand* unalloc = UnallocatedOperand::cast(operand_);
     requires_reg_ = unalloc->HasRegisterPolicy();
     register_beneficial_ = !unalloc->HasAnyPolicy();
@@ -40,7 +55,7 @@
 
 
 bool UsePosition::HasHint() const {
-  return hint_ != NULL && !hint_->IsUnallocated();
+  return hint_ != nullptr && !hint_->IsUnallocated();
 }
 
 
@@ -52,19 +67,29 @@
 
 void UseInterval::SplitAt(LifetimePosition pos, Zone* zone) {
   DCHECK(Contains(pos) && pos.Value() != start().Value());
-  UseInterval* after = new (zone) UseInterval(pos, end_);
+  auto after = new (zone) UseInterval(pos, end_);
   after->next_ = next_;
   next_ = after;
   end_ = pos;
 }
 
 
+struct LiveRange::SpillAtDefinitionList : ZoneObject {
+  SpillAtDefinitionList(int gap_index, InstructionOperand* operand,
+                        SpillAtDefinitionList* next)
+      : gap_index(gap_index), operand(operand), next(next) {}
+  const int gap_index;
+  InstructionOperand* const operand;
+  SpillAtDefinitionList* const next;
+};
+
+
 #ifdef DEBUG
 
 
 void LiveRange::Verify() const {
   UsePosition* cur = first_pos_;
-  while (cur != NULL) {
+  while (cur != nullptr) {
     DCHECK(Start().Value() <= cur->pos().Value() &&
            cur->pos().Value() <= End().Value());
     cur = cur->next();
@@ -74,7 +99,7 @@
 
 bool LiveRange::HasOverlap(UseInterval* target) const {
   UseInterval* current_interval = first_interval_;
-  while (current_interval != NULL) {
+  while (current_interval != nullptr) {
     // Intervals overlap if the start of one is contained in the other.
     if (current_interval->Contains(target->start()) ||
         target->Contains(current_interval->start())) {
@@ -96,52 +121,87 @@
       is_non_loop_phi_(false),
       kind_(UNALLOCATED_REGISTERS),
       assigned_register_(kInvalidAssignment),
-      last_interval_(NULL),
-      first_interval_(NULL),
-      first_pos_(NULL),
-      parent_(NULL),
-      next_(NULL),
-      current_interval_(NULL),
-      last_processed_use_(NULL),
-      current_hint_operand_(NULL),
-      spill_operand_(new (zone) InstructionOperand()),
-      spill_start_index_(kMaxInt) {}
+      last_interval_(nullptr),
+      first_interval_(nullptr),
+      first_pos_(nullptr),
+      parent_(nullptr),
+      next_(nullptr),
+      current_interval_(nullptr),
+      last_processed_use_(nullptr),
+      current_hint_operand_(nullptr),
+      spill_start_index_(kMaxInt),
+      spill_type_(SpillType::kNoSpillType),
+      spill_operand_(nullptr),
+      spills_at_definition_(nullptr) {}
 
 
 void LiveRange::set_assigned_register(int reg, Zone* zone) {
   DCHECK(!HasRegisterAssigned() && !IsSpilled());
   assigned_register_ = reg;
-  ConvertOperands(zone);
+  // TODO(dcarney): stop aliasing hint operands.
+  ConvertUsesToOperand(CreateAssignedOperand(zone));
 }
 
 
-void LiveRange::MakeSpilled(Zone* zone) {
+void LiveRange::MakeSpilled() {
   DCHECK(!IsSpilled());
-  DCHECK(TopLevel()->HasAllocatedSpillOperand());
+  DCHECK(!TopLevel()->HasNoSpillType());
   spilled_ = true;
   assigned_register_ = kInvalidAssignment;
-  ConvertOperands(zone);
 }
 
 
-bool LiveRange::HasAllocatedSpillOperand() const {
-  DCHECK(spill_operand_ != NULL);
-  return !spill_operand_->IsIgnored();
+void LiveRange::SpillAtDefinition(Zone* zone, int gap_index,
+                                  InstructionOperand* operand) {
+  DCHECK(HasNoSpillType());
+  spills_at_definition_ = new (zone)
+      SpillAtDefinitionList(gap_index, operand, spills_at_definition_);
+}
+
+
+void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence,
+                                         InstructionOperand* op) {
+  auto to_spill = TopLevel()->spills_at_definition_;
+  if (to_spill == nullptr) return;
+  auto zone = sequence->zone();
+  for (; to_spill != nullptr; to_spill = to_spill->next) {
+    auto gap = sequence->GapAt(to_spill->gap_index);
+    auto move = gap->GetOrCreateParallelMove(GapInstruction::START, zone);
+    move->AddMove(to_spill->operand, op, zone);
+  }
+  TopLevel()->spills_at_definition_ = nullptr;
 }
 
 
 void LiveRange::SetSpillOperand(InstructionOperand* operand) {
+  DCHECK(HasNoSpillType());
   DCHECK(!operand->IsUnallocated());
-  DCHECK(spill_operand_ != NULL);
-  DCHECK(spill_operand_->IsIgnored());
-  spill_operand_->ConvertTo(operand->kind(), operand->index());
+  spill_type_ = SpillType::kSpillOperand;
+  spill_operand_ = operand;
+}
+
+
+void LiveRange::SetSpillRange(SpillRange* spill_range) {
+  DCHECK(HasNoSpillType() || HasSpillRange());
+  DCHECK_NE(spill_range, nullptr);
+  spill_type_ = SpillType::kSpillRange;
+  spill_range_ = spill_range;
+}
+
+
+void LiveRange::CommitSpillOperand(InstructionOperand* operand) {
+  DCHECK(HasSpillRange());
+  DCHECK(!operand->IsUnallocated());
+  DCHECK(!IsChild());
+  spill_type_ = SpillType::kSpillOperand;
+  spill_operand_ = operand;
 }
 
 
 UsePosition* LiveRange::NextUsePosition(LifetimePosition start) {
   UsePosition* use_pos = last_processed_use_;
-  if (use_pos == NULL) use_pos = first_pos();
-  while (use_pos != NULL && use_pos->pos().Value() < start.Value()) {
+  if (use_pos == nullptr) use_pos = first_pos();
+  while (use_pos != nullptr && use_pos->pos().Value() < start.Value()) {
     use_pos = use_pos->next();
   }
   last_processed_use_ = use_pos;
@@ -152,7 +212,7 @@
 UsePosition* LiveRange::NextUsePositionRegisterIsBeneficial(
     LifetimePosition start) {
   UsePosition* pos = NextUsePosition(start);
-  while (pos != NULL && !pos->RegisterIsBeneficial()) {
+  while (pos != nullptr && !pos->RegisterIsBeneficial()) {
     pos = pos->next();
   }
   return pos;
@@ -161,9 +221,9 @@
 
 UsePosition* LiveRange::PreviousUsePositionRegisterIsBeneficial(
     LifetimePosition start) {
-  UsePosition* pos = first_pos();
-  UsePosition* prev = NULL;
-  while (pos != NULL && pos->pos().Value() < start.Value()) {
+  auto pos = first_pos();
+  UsePosition* prev = nullptr;
+  while (pos != nullptr && pos->pos().Value() < start.Value()) {
     if (pos->RegisterIsBeneficial()) prev = pos;
     pos = pos->next();
   }
@@ -173,7 +233,7 @@
 
 UsePosition* LiveRange::NextRegisterPosition(LifetimePosition start) {
   UsePosition* pos = NextUsePosition(start);
-  while (pos != NULL && !pos->RequiresRegister()) {
+  while (pos != nullptr && !pos->RequiresRegister()) {
     pos = pos->next();
   }
   return pos;
@@ -183,15 +243,15 @@
 bool LiveRange::CanBeSpilled(LifetimePosition pos) {
   // We cannot spill a live range that has a use requiring a register
   // at the current or the immediate next position.
-  UsePosition* use_pos = NextRegisterPosition(pos);
-  if (use_pos == NULL) return true;
+  auto use_pos = NextRegisterPosition(pos);
+  if (use_pos == nullptr) return true;
   return use_pos->pos().Value() >
          pos.NextInstruction().InstructionEnd().Value();
 }
 
 
-InstructionOperand* LiveRange::CreateAssignedOperand(Zone* zone) {
-  InstructionOperand* op = NULL;
+InstructionOperand* LiveRange::CreateAssignedOperand(Zone* zone) const {
+  InstructionOperand* op = nullptr;
   if (HasRegisterAssigned()) {
     DCHECK(!IsSpilled());
     switch (Kind()) {
@@ -204,15 +264,11 @@
       default:
         UNREACHABLE();
     }
-  } else if (IsSpilled()) {
+  } else {
+    DCHECK(IsSpilled());
     DCHECK(!HasRegisterAssigned());
     op = TopLevel()->GetSpillOperand();
     DCHECK(!op->IsUnallocated());
-  } else {
-    UnallocatedOperand* unalloc =
-        new (zone) UnallocatedOperand(UnallocatedOperand::NONE);
-    unalloc->set_virtual_register(id_);
-    op = unalloc;
   }
   return op;
 }
@@ -220,9 +276,9 @@
 
 UseInterval* LiveRange::FirstSearchIntervalForPosition(
     LifetimePosition position) const {
-  if (current_interval_ == NULL) return first_interval_;
+  if (current_interval_ == nullptr) return first_interval_;
   if (current_interval_->start().Value() > position.Value()) {
-    current_interval_ = NULL;
+    current_interval_ = nullptr;
     return first_interval_;
   }
   return current_interval_;
@@ -231,11 +287,10 @@
 
 void LiveRange::AdvanceLastProcessedMarker(
     UseInterval* to_start_of, LifetimePosition but_not_past) const {
-  if (to_start_of == NULL) return;
+  if (to_start_of == nullptr) return;
   if (to_start_of->start().Value() > but_not_past.Value()) return;
-  LifetimePosition start = current_interval_ == NULL
-                               ? LifetimePosition::Invalid()
-                               : current_interval_->start();
+  auto start = current_interval_ == nullptr ? LifetimePosition::Invalid()
+                                            : current_interval_->start();
   if (to_start_of->start().Value() > start.Value()) {
     current_interval_ = to_start_of;
   }
@@ -249,7 +304,7 @@
   // Find the last interval that ends before the position. If the
   // position is contained in one of the intervals in the chain, we
   // split that interval and use the first part.
-  UseInterval* current = FirstSearchIntervalForPosition(position);
+  auto current = FirstSearchIntervalForPosition(position);
 
   // If the split position coincides with the beginning of a use interval
   // we need to split use positons in a special way.
@@ -260,12 +315,12 @@
     current = first_interval_;
   }
 
-  while (current != NULL) {
+  while (current != nullptr) {
     if (current->Contains(position)) {
       current->SplitAt(position, zone);
       break;
     }
-    UseInterval* next = current->next();
+    auto next = current->next();
     if (next->start().Value() >= position.Value()) {
       split_at_start = (next->start().Value() == position.Value());
       break;
@@ -274,8 +329,8 @@
   }
 
   // Partition original use intervals to the two live ranges.
-  UseInterval* before = current;
-  UseInterval* after = before->next();
+  auto before = current;
+  auto after = before->next();
   result->last_interval_ =
       (last_interval_ == before)
           ? after            // Only interval in the range after split.
@@ -285,39 +340,41 @@
 
   // Find the last use position before the split and the first use
   // position after it.
-  UsePosition* use_after = first_pos_;
-  UsePosition* use_before = NULL;
+  auto use_after = first_pos_;
+  UsePosition* use_before = nullptr;
   if (split_at_start) {
     // The split position coincides with the beginning of a use interval (the
     // end of a lifetime hole). Use at this position should be attributed to
     // the split child because split child owns use interval covering it.
-    while (use_after != NULL && use_after->pos().Value() < position.Value()) {
+    while (use_after != nullptr &&
+           use_after->pos().Value() < position.Value()) {
       use_before = use_after;
       use_after = use_after->next();
     }
   } else {
-    while (use_after != NULL && use_after->pos().Value() <= position.Value()) {
+    while (use_after != nullptr &&
+           use_after->pos().Value() <= position.Value()) {
       use_before = use_after;
       use_after = use_after->next();
     }
   }
 
   // Partition original use positions to the two live ranges.
-  if (use_before != NULL) {
-    use_before->next_ = NULL;
+  if (use_before != nullptr) {
+    use_before->next_ = nullptr;
   } else {
-    first_pos_ = NULL;
+    first_pos_ = nullptr;
   }
   result->first_pos_ = use_after;
 
   // Discard cached iteration state. It might be pointing
   // to the use that no longer belongs to this live range.
-  last_processed_use_ = NULL;
-  current_interval_ = NULL;
+  last_processed_use_ = nullptr;
+  current_interval_ = nullptr;
 
   // Link the new live range in the chain before any of the other
   // ranges linked from the range before the split.
-  result->parent_ = (parent_ == NULL) ? this : parent_;
+  result->parent_ = (parent_ == nullptr) ? this : parent_;
   result->kind_ = result->parent_->kind_;
   result->next_ = next_;
   next_ = result;
@@ -339,9 +396,9 @@
   LifetimePosition other_start = other->Start();
   if (start.Value() == other_start.Value()) {
     UsePosition* pos = first_pos();
-    if (pos == NULL) return false;
+    if (pos == nullptr) return false;
     UsePosition* other_pos = other->first_pos();
-    if (other_pos == NULL) return true;
+    if (other_pos == nullptr) return true;
     return pos->pos().Value() < other_pos->pos().Value();
   }
   return start.Value() < other_start.Value();
@@ -349,9 +406,8 @@
 
 
 void LiveRange::ShortenTo(LifetimePosition start) {
-  RegisterAllocator::TraceAlloc("Shorten live range %d to [%d\n", id_,
-                                start.Value());
-  DCHECK(first_interval_ != NULL);
+  TraceAlloc("Shorten live range %d to [%d\n", id_, start.Value());
+  DCHECK(first_interval_ != nullptr);
   DCHECK(first_interval_->start().Value() <= start.Value());
   DCHECK(start.Value() < first_interval_->end().Value());
   first_interval_->set_start(start);
@@ -360,10 +416,10 @@
 
 void LiveRange::EnsureInterval(LifetimePosition start, LifetimePosition end,
                                Zone* zone) {
-  RegisterAllocator::TraceAlloc("Ensure live range %d in interval [%d %d[\n",
-                                id_, start.Value(), end.Value());
-  LifetimePosition new_end = end;
-  while (first_interval_ != NULL &&
+  TraceAlloc("Ensure live range %d in interval [%d %d[\n", id_, start.Value(),
+             end.Value());
+  auto new_end = end;
+  while (first_interval_ != nullptr &&
          first_interval_->start().Value() <= end.Value()) {
     if (first_interval_->end().Value() > end.Value()) {
       new_end = first_interval_->end();
@@ -371,10 +427,10 @@
     first_interval_ = first_interval_->next();
   }
 
-  UseInterval* new_interval = new (zone) UseInterval(start, new_end);
+  auto new_interval = new (zone) UseInterval(start, new_end);
   new_interval->next_ = first_interval_;
   first_interval_ = new_interval;
-  if (new_interval->next() == NULL) {
+  if (new_interval->next() == nullptr) {
     last_interval_ = new_interval;
   }
 }
@@ -382,17 +438,17 @@
 
 void LiveRange::AddUseInterval(LifetimePosition start, LifetimePosition end,
                                Zone* zone) {
-  RegisterAllocator::TraceAlloc("Add to live range %d interval [%d %d[\n", id_,
-                                start.Value(), end.Value());
-  if (first_interval_ == NULL) {
-    UseInterval* interval = new (zone) UseInterval(start, end);
+  TraceAlloc("Add to live range %d interval [%d %d[\n", id_, start.Value(),
+             end.Value());
+  if (first_interval_ == nullptr) {
+    auto interval = new (zone) UseInterval(start, end);
     first_interval_ = interval;
     last_interval_ = interval;
   } else {
     if (end.Value() == first_interval_->start().Value()) {
       first_interval_->set_start(start);
     } else if (end.Value() < first_interval_->start().Value()) {
-      UseInterval* interval = new (zone) UseInterval(start, end);
+      auto interval = new (zone) UseInterval(start, end);
       interval->set_next(first_interval_);
       first_interval_ = interval;
     } else {
@@ -410,19 +466,18 @@
 void LiveRange::AddUsePosition(LifetimePosition pos,
                                InstructionOperand* operand,
                                InstructionOperand* hint, Zone* zone) {
-  RegisterAllocator::TraceAlloc("Add to live range %d use position %d\n", id_,
-                                pos.Value());
-  UsePosition* use_pos = new (zone) UsePosition(pos, operand, hint);
-  UsePosition* prev_hint = NULL;
-  UsePosition* prev = NULL;
-  UsePosition* current = first_pos_;
-  while (current != NULL && current->pos().Value() < pos.Value()) {
+  TraceAlloc("Add to live range %d use position %d\n", id_, pos.Value());
+  auto use_pos = new (zone) UsePosition(pos, operand, hint);
+  UsePosition* prev_hint = nullptr;
+  UsePosition* prev = nullptr;
+  auto current = first_pos_;
+  while (current != nullptr && current->pos().Value() < pos.Value()) {
     prev_hint = current->HasHint() ? current : prev_hint;
     prev = current;
     current = current->next();
   }
 
-  if (prev == NULL) {
+  if (prev == nullptr) {
     use_pos->set_next(first_pos_);
     first_pos_ = use_pos;
   } else {
@@ -430,16 +485,15 @@
     prev->next_ = use_pos;
   }
 
-  if (prev_hint == NULL && use_pos->HasHint()) {
+  if (prev_hint == nullptr && use_pos->HasHint()) {
     current_hint_operand_ = hint;
   }
 }
 
 
-void LiveRange::ConvertOperands(Zone* zone) {
-  InstructionOperand* op = CreateAssignedOperand(zone);
-  UsePosition* use_pos = first_pos();
-  while (use_pos != NULL) {
+void LiveRange::ConvertUsesToOperand(InstructionOperand* op) {
+  auto use_pos = first_pos();
+  while (use_pos != nullptr) {
     DCHECK(Start().Value() <= use_pos->pos().Value() &&
            use_pos->pos().Value() <= End().Value());
 
@@ -462,10 +516,10 @@
 
 bool LiveRange::Covers(LifetimePosition position) {
   if (!CanCover(position)) return false;
-  UseInterval* start_search = FirstSearchIntervalForPosition(position);
-  for (UseInterval* interval = start_search; interval != NULL;
+  auto start_search = FirstSearchIntervalForPosition(position);
+  for (auto interval = start_search; interval != nullptr;
        interval = interval->next()) {
-    DCHECK(interval->next() == NULL ||
+    DCHECK(interval->next() == nullptr ||
            interval->next()->start().Value() >= interval->start().Value());
     AdvanceLastProcessedMarker(interval, position);
     if (interval->Contains(position)) return true;
@@ -476,20 +530,20 @@
 
 
 LifetimePosition LiveRange::FirstIntersection(LiveRange* other) {
-  UseInterval* b = other->first_interval();
-  if (b == NULL) return LifetimePosition::Invalid();
-  LifetimePosition advance_last_processed_up_to = b->start();
-  UseInterval* a = FirstSearchIntervalForPosition(b->start());
-  while (a != NULL && b != NULL) {
+  auto b = other->first_interval();
+  if (b == nullptr) return LifetimePosition::Invalid();
+  auto advance_last_processed_up_to = b->start();
+  auto a = FirstSearchIntervalForPosition(b->start());
+  while (a != nullptr && b != nullptr) {
     if (a->start().Value() > other->End().Value()) break;
     if (b->start().Value() > End().Value()) break;
-    LifetimePosition cur_intersection = a->Intersect(b);
+    auto cur_intersection = a->Intersect(b);
     if (cur_intersection.IsValid()) {
       return cur_intersection;
     }
     if (a->start().Value() < b->start().Value()) {
       a = a->next();
-      if (a == NULL || a->start().Value() > other->End().Value()) break;
+      if (a == nullptr || a->start().Value() > other->End().Value()) break;
       AdvanceLastProcessedMarker(a, advance_last_processed_up_to);
     } else {
       b = b->next();
@@ -499,84 +553,99 @@
 }
 
 
-RegisterAllocator::RegisterAllocator(InstructionSequence* code)
-    : zone_(code->isolate()),
+RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config,
+                                     Zone* zone, Frame* frame,
+                                     InstructionSequence* code,
+                                     const char* debug_name)
+    : local_zone_(zone),
+      frame_(frame),
       code_(code),
-      live_in_sets_(code->BasicBlockCount(), zone()),
-      live_ranges_(code->VirtualRegisterCount() * 2, zone()),
-      fixed_live_ranges_(NULL),
-      fixed_double_live_ranges_(NULL),
-      unhandled_live_ranges_(code->VirtualRegisterCount() * 2, zone()),
-      active_live_ranges_(8, zone()),
-      inactive_live_ranges_(8, zone()),
-      reusable_slots_(8, zone()),
+      debug_name_(debug_name),
+      config_(config),
+      phi_map_(PhiMap::key_compare(), PhiMap::allocator_type(local_zone())),
+      live_in_sets_(code->InstructionBlockCount(), nullptr, local_zone()),
+      live_ranges_(code->VirtualRegisterCount() * 2, nullptr, local_zone()),
+      fixed_live_ranges_(this->config()->num_general_registers(), nullptr,
+                         local_zone()),
+      fixed_double_live_ranges_(this->config()->num_double_registers(), nullptr,
+                                local_zone()),
+      unhandled_live_ranges_(local_zone()),
+      active_live_ranges_(local_zone()),
+      inactive_live_ranges_(local_zone()),
+      reusable_slots_(local_zone()),
+      spill_ranges_(local_zone()),
       mode_(UNALLOCATED_REGISTERS),
       num_registers_(-1),
-      allocation_ok_(true) {}
-
-
-void RegisterAllocator::InitializeLivenessAnalysis() {
-  // Initialize the live_in sets for each block to NULL.
-  int block_count = code()->BasicBlockCount();
-  live_in_sets_.Initialize(block_count, zone());
-  live_in_sets_.AddBlock(NULL, block_count, zone());
+      allocation_ok_(true) {
+  DCHECK(this->config()->num_general_registers() <=
+         RegisterConfiguration::kMaxGeneralRegisters);
+  DCHECK(this->config()->num_double_registers() <=
+         RegisterConfiguration::kMaxDoubleRegisters);
+  // TryAllocateFreeReg and AllocateBlockedReg assume this
+  // when allocating local arrays.
+  DCHECK(RegisterConfiguration::kMaxDoubleRegisters >=
+         this->config()->num_general_registers());
+  unhandled_live_ranges().reserve(
+      static_cast<size_t>(code->VirtualRegisterCount() * 2));
+  active_live_ranges().reserve(8);
+  inactive_live_ranges().reserve(8);
+  reusable_slots().reserve(8);
+  spill_ranges().reserve(8);
+  assigned_registers_ =
+      new (code_zone()) BitVector(config->num_general_registers(), code_zone());
+  assigned_double_registers_ = new (code_zone())
+      BitVector(config->num_aliased_double_registers(), code_zone());
+  frame->SetAllocatedRegisters(assigned_registers_);
+  frame->SetAllocatedDoubleRegisters(assigned_double_registers_);
 }
 
 
-BitVector* RegisterAllocator::ComputeLiveOut(BasicBlock* block) {
+BitVector* RegisterAllocator::ComputeLiveOut(const InstructionBlock* block) {
   // Compute live out for the given block, except not including backward
   // successor edges.
-  BitVector* live_out =
-      new (zone()) BitVector(code()->VirtualRegisterCount(), zone());
+  auto live_out = new (local_zone())
+      BitVector(code()->VirtualRegisterCount(), local_zone());
 
   // Process all successor blocks.
-  BasicBlock::Successors successors = block->successors();
-  for (BasicBlock::Successors::iterator i = successors.begin();
-       i != successors.end(); ++i) {
+  for (auto succ : block->successors()) {
     // Add values live on entry to the successor. Note the successor's
     // live_in will not be computed yet for backwards edges.
-    BasicBlock* successor = *i;
-    BitVector* live_in = live_in_sets_[successor->rpo_number_];
-    if (live_in != NULL) live_out->Union(*live_in);
+    auto live_in = live_in_sets_[succ.ToSize()];
+    if (live_in != nullptr) live_out->Union(*live_in);
 
     // All phi input operands corresponding to this successor edge are live
     // out from this block.
-    int index = successor->PredecessorIndexOf(block);
-    DCHECK(index >= 0);
-    DCHECK(index < static_cast<int>(successor->PredecessorCount()));
-    for (BasicBlock::const_iterator j = successor->begin();
-         j != successor->end(); ++j) {
-      Node* phi = *j;
-      if (phi->opcode() != IrOpcode::kPhi) continue;
-      Node* input = phi->InputAt(index);
-      live_out->Add(input->id());
+    auto successor = code()->InstructionBlockAt(succ);
+    size_t index = successor->PredecessorIndexOf(block->rpo_number());
+    DCHECK(index < successor->PredecessorCount());
+    for (auto phi : successor->phis()) {
+      live_out->Add(phi->operands()[index]);
     }
   }
-
   return live_out;
 }
 
 
-void RegisterAllocator::AddInitialIntervals(BasicBlock* block,
+void RegisterAllocator::AddInitialIntervals(const InstructionBlock* block,
                                             BitVector* live_out) {
   // Add an interval that includes the entire block to the live range for
   // each live_out value.
-  LifetimePosition start =
+  auto start =
       LifetimePosition::FromInstructionIndex(block->first_instruction_index());
-  LifetimePosition end = LifetimePosition::FromInstructionIndex(
-                             block->last_instruction_index()).NextInstruction();
+  auto end = LifetimePosition::FromInstructionIndex(
+                 block->last_instruction_index()).NextInstruction();
   BitVector::Iterator iterator(live_out);
   while (!iterator.Done()) {
     int operand_index = iterator.Current();
-    LiveRange* range = LiveRangeFor(operand_index);
-    range->AddUseInterval(start, end, zone());
+    auto range = LiveRangeFor(operand_index);
+    range->AddUseInterval(start, end, local_zone());
     iterator.Advance();
   }
 }
 
 
 int RegisterAllocator::FixedDoubleLiveRangeID(int index) {
-  return -index - 1 - Register::kMaxNumAllocatableRegisters;
+  return -index - 1 - config()->num_general_registers();
 }
 
 
@@ -598,7 +667,7 @@
   }
   if (is_tagged) {
     TraceAlloc("Fixed reg is tagged at %d\n", pos);
-    Instruction* instr = InstructionAt(pos);
+    auto instr = InstructionAt(pos);
     if (instr->HasPointerMap()) {
       instr->pointer_map()->RecordPointer(operand, code_zone());
     }
@@ -608,51 +677,52 @@
 
 
 LiveRange* RegisterAllocator::FixedLiveRangeFor(int index) {
-  DCHECK(index < Register::kMaxNumAllocatableRegisters);
-  LiveRange* result = fixed_live_ranges_[index];
-  if (result == NULL) {
+  DCHECK(index < config()->num_general_registers());
+  auto result = fixed_live_ranges()[index];
+  if (result == nullptr) {
     // TODO(titzer): add a utility method to allocate a new LiveRange:
     // The LiveRange object itself can go in this zone, but the
     // InstructionOperand needs
     // to go in the code zone, since it may survive register allocation.
-    result = new (zone()) LiveRange(FixedLiveRangeID(index), code_zone());
+    result = new (local_zone()) LiveRange(FixedLiveRangeID(index), code_zone());
     DCHECK(result->IsFixed());
     result->kind_ = GENERAL_REGISTERS;
     SetLiveRangeAssignedRegister(result, index);
-    fixed_live_ranges_[index] = result;
+    fixed_live_ranges()[index] = result;
   }
   return result;
 }
 
 
 LiveRange* RegisterAllocator::FixedDoubleLiveRangeFor(int index) {
-  DCHECK(index < DoubleRegister::NumAllocatableRegisters());
-  LiveRange* result = fixed_double_live_ranges_[index];
-  if (result == NULL) {
-    result = new (zone()) LiveRange(FixedDoubleLiveRangeID(index), code_zone());
+  DCHECK(index < config()->num_aliased_double_registers());
+  auto result = fixed_double_live_ranges()[index];
+  if (result == nullptr) {
+    result = new (local_zone())
+        LiveRange(FixedDoubleLiveRangeID(index), code_zone());
     DCHECK(result->IsFixed());
     result->kind_ = DOUBLE_REGISTERS;
     SetLiveRangeAssignedRegister(result, index);
-    fixed_double_live_ranges_[index] = result;
+    fixed_double_live_ranges()[index] = result;
   }
   return result;
 }
 
 
 LiveRange* RegisterAllocator::LiveRangeFor(int index) {
-  if (index >= live_ranges_.length()) {
-    live_ranges_.AddBlock(NULL, index - live_ranges_.length() + 1, zone());
+  if (index >= static_cast<int>(live_ranges().size())) {
+    live_ranges().resize(index + 1, nullptr);
   }
-  LiveRange* result = live_ranges_[index];
-  if (result == NULL) {
-    result = new (zone()) LiveRange(index, code_zone());
-    live_ranges_[index] = result;
+  auto result = live_ranges()[index];
+  if (result == nullptr) {
+    result = new (local_zone()) LiveRange(index, code_zone());
+    live_ranges()[index] = result;
   }
   return result;
 }
 
 
-GapInstruction* RegisterAllocator::GetLastGap(BasicBlock* block) {
+GapInstruction* RegisterAllocator::GetLastGap(const InstructionBlock* block) {
   int last_instruction = block->last_instruction_index();
   return code()->GapAt(last_instruction - 1);
 }
@@ -666,7 +736,7 @@
   } else if (operand->IsDoubleRegister()) {
     return FixedDoubleLiveRangeFor(operand->index());
   } else {
-    return NULL;
+    return nullptr;
   }
 }
 
@@ -674,20 +744,21 @@
 void RegisterAllocator::Define(LifetimePosition position,
                                InstructionOperand* operand,
                                InstructionOperand* hint) {
-  LiveRange* range = LiveRangeFor(operand);
-  if (range == NULL) return;
+  auto range = LiveRangeFor(operand);
+  if (range == nullptr) return;
 
   if (range->IsEmpty() || range->Start().Value() > position.Value()) {
     // Can happen if there is a definition without use.
-    range->AddUseInterval(position, position.NextInstruction(), zone());
-    range->AddUsePosition(position.NextInstruction(), NULL, NULL, zone());
+    range->AddUseInterval(position, position.NextInstruction(), local_zone());
+    range->AddUsePosition(position.NextInstruction(), nullptr, nullptr,
+                          local_zone());
   } else {
     range->ShortenTo(position);
   }
 
   if (operand->IsUnallocated()) {
-    UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand);
-    range->AddUsePosition(position, unalloc_operand, hint, zone());
+    auto unalloc_operand = UnallocatedOperand::cast(operand);
+    range->AddUsePosition(position, unalloc_operand, hint, local_zone());
   }
 }
 
@@ -696,48 +767,279 @@
                             LifetimePosition position,
                             InstructionOperand* operand,
                             InstructionOperand* hint) {
-  LiveRange* range = LiveRangeFor(operand);
-  if (range == NULL) return;
+  auto range = LiveRangeFor(operand);
+  if (range == nullptr) return;
   if (operand->IsUnallocated()) {
     UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand);
-    range->AddUsePosition(position, unalloc_operand, hint, zone());
+    range->AddUsePosition(position, unalloc_operand, hint, local_zone());
   }
-  range->AddUseInterval(block_start, position, zone());
+  range->AddUseInterval(block_start, position, local_zone());
 }
 
 
-void RegisterAllocator::AddConstraintsGapMove(int index,
-                                              InstructionOperand* from,
-                                              InstructionOperand* to) {
-  GapInstruction* gap = code()->GapAt(index);
-  ParallelMove* move =
-      gap->GetOrCreateParallelMove(GapInstruction::START, code_zone());
-  if (from->IsUnallocated()) {
-    const ZoneList<MoveOperands>* move_operands = move->move_operands();
-    for (int i = 0; i < move_operands->length(); ++i) {
-      MoveOperands cur = move_operands->at(i);
-      InstructionOperand* cur_to = cur.destination();
-      if (cur_to->IsUnallocated()) {
-        if (UnallocatedOperand::cast(cur_to)->virtual_register() ==
-            UnallocatedOperand::cast(from)->virtual_register()) {
-          move->AddMove(cur.source(), to, code_zone());
-          return;
-        }
-      }
-    }
-  }
+void RegisterAllocator::AddGapMove(int index,
+                                   GapInstruction::InnerPosition position,
+                                   InstructionOperand* from,
+                                   InstructionOperand* to) {
+  auto gap = code()->GapAt(index);
+  auto move = gap->GetOrCreateParallelMove(position, code_zone());
   move->AddMove(from, to, code_zone());
 }
 
 
-void RegisterAllocator::MeetRegisterConstraints(BasicBlock* block) {
+static bool AreUseIntervalsIntersecting(UseInterval* interval1,
+                                        UseInterval* interval2) {
+  while (interval1 != nullptr && interval2 != nullptr) {
+    if (interval1->start().Value() < interval2->start().Value()) {
+      if (interval1->end().Value() > interval2->start().Value()) {
+        return true;
+      }
+      interval1 = interval1->next();
+    } else {
+      if (interval2->end().Value() > interval1->start().Value()) {
+        return true;
+      }
+      interval2 = interval2->next();
+    }
+  }
+  return false;
+}
+
+
+SpillRange::SpillRange(LiveRange* range, Zone* zone) : live_ranges_(zone) {
+  auto src = range->first_interval();
+  UseInterval* result = nullptr;
+  UseInterval* node = nullptr;
+  // Copy the nodes
+  while (src != nullptr) {
+    auto new_node = new (zone) UseInterval(src->start(), src->end());
+    if (result == nullptr) {
+      result = new_node;
+    } else {
+      node->set_next(new_node);
+    }
+    node = new_node;
+    src = src->next();
+  }
+  use_interval_ = result;
+  live_ranges().push_back(range);
+  end_position_ = node->end();
+  DCHECK(!range->HasSpillRange());
+  range->SetSpillRange(this);
+}
+
+
+bool SpillRange::IsIntersectingWith(SpillRange* other) const {
+  if (this->use_interval_ == nullptr || other->use_interval_ == nullptr ||
+      this->End().Value() <= other->use_interval_->start().Value() ||
+      other->End().Value() <= this->use_interval_->start().Value()) {
+    return false;
+  }
+  return AreUseIntervalsIntersecting(use_interval_, other->use_interval_);
+}
+
+
+bool SpillRange::TryMerge(SpillRange* other) {
+  if (Kind() != other->Kind() || IsIntersectingWith(other)) return false;
+
+  auto max = LifetimePosition::MaxPosition();
+  if (End().Value() < other->End().Value() &&
+      other->End().Value() != max.Value()) {
+    end_position_ = other->End();
+  }
+  other->end_position_ = max;
+
+  MergeDisjointIntervals(other->use_interval_);
+  other->use_interval_ = nullptr;
+
+  for (auto range : other->live_ranges()) {
+    DCHECK(range->GetSpillRange() == other);
+    range->SetSpillRange(this);
+  }
+
+  live_ranges().insert(live_ranges().end(), other->live_ranges().begin(),
+                       other->live_ranges().end());
+  other->live_ranges().clear();
+
+  return true;
+}
+
+
+void SpillRange::SetOperand(InstructionOperand* op) {
+  for (auto range : live_ranges()) {
+    DCHECK(range->GetSpillRange() == this);
+    range->CommitSpillOperand(op);
+  }
+}
+
+
+void SpillRange::MergeDisjointIntervals(UseInterval* other) {
+  UseInterval* tail = nullptr;
+  auto current = use_interval_;
+  while (other != nullptr) {
+    // Make sure the 'current' list starts first
+    if (current == nullptr ||
+        current->start().Value() > other->start().Value()) {
+      std::swap(current, other);
+    }
+    // Check disjointness
+    DCHECK(other == nullptr ||
+           current->end().Value() <= other->start().Value());
+    // Append the 'current' node to the result accumulator and move forward
+    if (tail == nullptr) {
+      use_interval_ = current;
+    } else {
+      tail->set_next(current);
+    }
+    tail = current;
+    current = current->next();
+  }
+  // Other list is empty => we are done
+}
+
+
+void RegisterAllocator::ReuseSpillSlots() {
+  DCHECK(FLAG_turbo_reuse_spill_slots);
+
+  // Merge disjoint spill ranges
+  for (size_t i = 0; i < spill_ranges().size(); i++) {
+    auto range = spill_ranges()[i];
+    if (range->IsEmpty()) continue;
+    for (size_t j = i + 1; j < spill_ranges().size(); j++) {
+      auto other = spill_ranges()[j];
+      if (!other->IsEmpty()) {
+        range->TryMerge(other);
+      }
+    }
+  }
+
+  // Allocate slots for the merged spill ranges.
+  for (auto range : spill_ranges()) {
+    if (range->IsEmpty()) continue;
+    // Allocate a new operand referring to the spill slot.
+    auto kind = range->Kind();
+    int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS);
+    auto op_kind = kind == DOUBLE_REGISTERS
+                       ? InstructionOperand::DOUBLE_STACK_SLOT
+                       : InstructionOperand::STACK_SLOT;
+    auto op = new (code_zone()) InstructionOperand(op_kind, index);
+    range->SetOperand(op);
+  }
+}
+
+
+void RegisterAllocator::CommitAssignment() {
+  for (auto range : live_ranges()) {
+    if (range == nullptr || range->IsEmpty()) continue;
+    // Register assignments were committed in set_assigned_register.
+    if (range->HasRegisterAssigned()) continue;
+    auto assigned = range->CreateAssignedOperand(code_zone());
+    range->ConvertUsesToOperand(assigned);
+    if (range->IsSpilled()) {
+      range->CommitSpillsAtDefinition(code(), assigned);
+    }
+  }
+}
+
+
+SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) {
+  DCHECK(FLAG_turbo_reuse_spill_slots);
+  auto spill_range = new (local_zone()) SpillRange(range, local_zone());
+  spill_ranges().push_back(spill_range);
+  return spill_range;
+}
+
+
+bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) {
+  DCHECK(FLAG_turbo_reuse_spill_slots);
+  if (range->IsChild() || !range->is_phi()) return false;
+  DCHECK(range->HasNoSpillType());
+
+  auto lookup = phi_map_.find(range->id());
+  DCHECK(lookup != phi_map_.end());
+  auto phi = lookup->second.phi;
+  auto block = lookup->second.block;
+  // Count the number of spilled operands.
+  size_t spilled_count = 0;
+  LiveRange* first_op = nullptr;
+  for (size_t i = 0; i < phi->operands().size(); i++) {
+    int op = phi->operands()[i];
+    LiveRange* op_range = LiveRangeFor(op);
+    if (op_range->GetSpillRange() == nullptr) continue;
+    auto pred = code()->InstructionBlockAt(block->predecessors()[i]);
+    auto pred_end =
+        LifetimePosition::FromInstructionIndex(pred->last_instruction_index());
+    while (op_range != nullptr && !op_range->CanCover(pred_end)) {
+      op_range = op_range->next();
+    }
+    if (op_range != nullptr && op_range->IsSpilled()) {
+      spilled_count++;
+      if (first_op == nullptr) {
+        first_op = op_range->TopLevel();
+      }
+    }
+  }
+
+  // Only continue if more than half of the operands are spilled.
+  if (spilled_count * 2 <= phi->operands().size()) {
+    return false;
+  }
+
+  // Try to merge the spilled operands and count the number of merged spilled
+  // operands.
+  DCHECK(first_op != nullptr);
+  auto first_op_spill = first_op->GetSpillRange();
+  size_t num_merged = 1;
+  for (size_t i = 1; i < phi->operands().size(); i++) {
+    int op = phi->operands()[i];
+    auto op_range = LiveRangeFor(op);
+    auto op_spill = op_range->GetSpillRange();
+    if (op_spill != nullptr &&
+        (op_spill == first_op_spill || first_op_spill->TryMerge(op_spill))) {
+      num_merged++;
+    }
+  }
+
+  // Only continue if enough operands could be merged to the
+  // same spill slot.
+  if (num_merged * 2 <= phi->operands().size() ||
+      AreUseIntervalsIntersecting(first_op_spill->interval(),
+                                  range->first_interval())) {
+    return false;
+  }
+
+  // If the range does not need register soon, spill it to the merged
+  // spill range.
+  auto next_pos = range->Start();
+  if (code()->IsGapAt(next_pos.InstructionIndex())) {
+    next_pos = next_pos.NextInstruction();
+  }
+  auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos);
+  if (pos == nullptr) {
+    auto spill_range = AssignSpillRangeToLiveRange(range->TopLevel());
+    CHECK(first_op_spill->TryMerge(spill_range));
+    Spill(range);
+    return true;
+  } else if (pos->pos().Value() > range->Start().NextInstruction().Value()) {
+    auto spill_range = AssignSpillRangeToLiveRange(range->TopLevel());
+    CHECK(first_op_spill->TryMerge(spill_range));
+    SpillBetween(range, range->Start(), pos->pos());
+    if (!AllocationOk()) return false;
+    DCHECK(UnhandledIsSorted());
+    return true;
+  }
+  return false;
+}
+
+
+void RegisterAllocator::MeetRegisterConstraints(const InstructionBlock* block) {
   int start = block->first_instruction_index();
   int end = block->last_instruction_index();
   DCHECK_NE(-1, start);
   for (int i = start; i <= end; ++i) {
     if (code()->IsGapAt(i)) {
-      Instruction* instr = NULL;
-      Instruction* prev_instr = NULL;
+      Instruction* instr = nullptr;
+      Instruction* prev_instr = nullptr;
       if (i < end) instr = InstructionAt(i + 1);
       if (i > start) prev_instr = InstructionAt(i - 1);
       MeetConstraintsBetween(prev_instr, instr, i);
@@ -753,30 +1055,30 @@
 
 
 void RegisterAllocator::MeetRegisterConstraintsForLastInstructionInBlock(
-    BasicBlock* block) {
+    const InstructionBlock* block) {
   int end = block->last_instruction_index();
-  Instruction* last_instruction = InstructionAt(end);
+  auto last_instruction = InstructionAt(end);
   for (size_t i = 0; i < last_instruction->OutputCount(); i++) {
-    InstructionOperand* output_operand = last_instruction->OutputAt(i);
+    auto output_operand = last_instruction->OutputAt(i);
     DCHECK(!output_operand->IsConstant());
-    UnallocatedOperand* output = UnallocatedOperand::cast(output_operand);
+    auto output = UnallocatedOperand::cast(output_operand);
     int output_vreg = output->virtual_register();
-    LiveRange* range = LiveRangeFor(output_vreg);
+    auto range = LiveRangeFor(output_vreg);
     bool assigned = false;
     if (output->HasFixedPolicy()) {
       AllocateFixed(output, -1, false);
       // This value is produced on the stack, we never need to spill it.
       if (output->IsStackSlot()) {
+        DCHECK(output->index() < 0);
         range->SetSpillOperand(output);
         range->SetSpillStartIndex(end);
         assigned = true;
       }
 
-      BasicBlock::Successors successors = block->successors();
-      for (BasicBlock::Successors::iterator succ = successors.begin();
-           succ != successors.end(); ++succ) {
-        DCHECK((*succ)->PredecessorCount() == 1);
-        int gap_index = (*succ)->first_instruction_index() + 1;
+      for (auto succ : block->successors()) {
+        const InstructionBlock* successor = code()->InstructionBlockAt(succ);
+        DCHECK(successor->PredecessorCount() == 1);
+        int gap_index = successor->first_instruction_index() + 1;
         DCHECK(code()->IsGapAt(gap_index));
 
         // Create an unconstrained operand for the same virtual register
@@ -785,26 +1087,17 @@
             new (code_zone()) UnallocatedOperand(UnallocatedOperand::ANY);
         output_copy->set_virtual_register(output_vreg);
 
-        code()->AddGapMove(gap_index, output, output_copy);
+        AddGapMove(gap_index, GapInstruction::START, output, output_copy);
       }
     }
 
     if (!assigned) {
-      BasicBlock::Successors successors = block->successors();
-      for (BasicBlock::Successors::iterator succ = successors.begin();
-           succ != successors.end(); ++succ) {
-        DCHECK((*succ)->PredecessorCount() == 1);
-        int gap_index = (*succ)->first_instruction_index() + 1;
+      for (auto succ : block->successors()) {
+        const InstructionBlock* successor = code()->InstructionBlockAt(succ);
+        DCHECK(successor->PredecessorCount() == 1);
+        int gap_index = successor->first_instruction_index() + 1;
+        range->SpillAtDefinition(local_zone(), gap_index, output);
         range->SetSpillStartIndex(gap_index);
-
-        // This move to spill operand is not a real use. Liveness analysis
-        // and splitting of live ranges do not account for it.
-        // Thus it should be inserted to a lifetime position corresponding to
-        // the instruction end.
-        GapInstruction* gap = code()->GapAt(gap_index);
-        ParallelMove* move =
-            gap->GetOrCreateParallelMove(GapInstruction::BEFORE, code_zone());
-        move->AddMove(output, range->GetSpillOperand(), code_zone());
       }
     }
   }
@@ -814,10 +1107,10 @@
 void RegisterAllocator::MeetConstraintsBetween(Instruction* first,
                                                Instruction* second,
                                                int gap_index) {
-  if (first != NULL) {
+  if (first != nullptr) {
     // Handle fixed temporaries.
     for (size_t i = 0; i < first->TempCount(); i++) {
-      UnallocatedOperand* temp = UnallocatedOperand::cast(first->TempAt(i));
+      auto temp = UnallocatedOperand::cast(first->TempAt(i));
       if (temp->HasFixedPolicy()) {
         AllocateFixed(temp, gap_index - 1, false);
       }
@@ -828,66 +1121,58 @@
       InstructionOperand* output = first->OutputAt(i);
       if (output->IsConstant()) {
         int output_vreg = output->index();
-        LiveRange* range = LiveRangeFor(output_vreg);
+        auto range = LiveRangeFor(output_vreg);
         range->SetSpillStartIndex(gap_index - 1);
         range->SetSpillOperand(output);
       } else {
-        UnallocatedOperand* first_output = UnallocatedOperand::cast(output);
-        LiveRange* range = LiveRangeFor(first_output->virtual_register());
+        auto first_output = UnallocatedOperand::cast(output);
+        auto range = LiveRangeFor(first_output->virtual_register());
         bool assigned = false;
         if (first_output->HasFixedPolicy()) {
-          UnallocatedOperand* output_copy =
-              first_output->CopyUnconstrained(code_zone());
+          auto output_copy = first_output->CopyUnconstrained(code_zone());
           bool is_tagged = HasTaggedValue(first_output->virtual_register());
           AllocateFixed(first_output, gap_index, is_tagged);
 
           // This value is produced on the stack, we never need to spill it.
           if (first_output->IsStackSlot()) {
+            DCHECK(first_output->index() < 0);
             range->SetSpillOperand(first_output);
             range->SetSpillStartIndex(gap_index - 1);
             assigned = true;
           }
-          code()->AddGapMove(gap_index, first_output, output_copy);
+          AddGapMove(gap_index, GapInstruction::START, first_output,
+                     output_copy);
         }
 
         // Make sure we add a gap move for spilling (if we have not done
         // so already).
         if (!assigned) {
+          range->SpillAtDefinition(local_zone(), gap_index, first_output);
           range->SetSpillStartIndex(gap_index);
-
-          // This move to spill operand is not a real use. Liveness analysis
-          // and splitting of live ranges do not account for it.
-          // Thus it should be inserted to a lifetime position corresponding to
-          // the instruction end.
-          GapInstruction* gap = code()->GapAt(gap_index);
-          ParallelMove* move =
-              gap->GetOrCreateParallelMove(GapInstruction::BEFORE, code_zone());
-          move->AddMove(first_output, range->GetSpillOperand(), code_zone());
         }
       }
     }
   }
 
-  if (second != NULL) {
+  if (second != nullptr) {
     // Handle fixed input operands of second instruction.
     for (size_t i = 0; i < second->InputCount(); i++) {
-      InstructionOperand* input = second->InputAt(i);
+      auto input = second->InputAt(i);
       if (input->IsImmediate()) continue;  // Ignore immediates.
-      UnallocatedOperand* cur_input = UnallocatedOperand::cast(input);
+      auto cur_input = UnallocatedOperand::cast(input);
       if (cur_input->HasFixedPolicy()) {
-        UnallocatedOperand* input_copy =
-            cur_input->CopyUnconstrained(code_zone());
+        auto input_copy = cur_input->CopyUnconstrained(code_zone());
         bool is_tagged = HasTaggedValue(cur_input->virtual_register());
         AllocateFixed(cur_input, gap_index + 1, is_tagged);
-        AddConstraintsGapMove(gap_index, input_copy, cur_input);
+        AddGapMove(gap_index, GapInstruction::END, input_copy, cur_input);
       }
     }
 
     // Handle "output same as input" for second instruction.
     for (size_t i = 0; i < second->OutputCount(); i++) {
-      InstructionOperand* output = second->OutputAt(i);
+      auto output = second->OutputAt(i);
       if (!output->IsUnallocated()) continue;
-      UnallocatedOperand* second_output = UnallocatedOperand::cast(output);
+      auto second_output = UnallocatedOperand::cast(output);
       if (second_output->HasSameAsInputPolicy()) {
         DCHECK(i == 0);  // Only valid for first output.
         UnallocatedOperand* cur_input =
@@ -895,10 +1180,9 @@
         int output_vreg = second_output->virtual_register();
         int input_vreg = cur_input->virtual_register();
 
-        UnallocatedOperand* input_copy =
-            cur_input->CopyUnconstrained(code_zone());
+        auto input_copy = cur_input->CopyUnconstrained(code_zone());
         cur_input->set_virtual_register(second_output->virtual_register());
-        AddConstraintsGapMove(gap_index, input_copy, cur_input);
+        AddGapMove(gap_index, GapInstruction::END, input_copy, cur_input);
 
         if (HasTaggedValue(input_vreg) && !HasTaggedValue(output_vreg)) {
           int index = gap_index + 1;
@@ -922,7 +1206,7 @@
 
 bool RegisterAllocator::IsOutputRegisterOf(Instruction* instr, int index) {
   for (size_t i = 0; i < instr->OutputCount(); i++) {
-    InstructionOperand* output = instr->OutputAt(i);
+    auto output = instr->OutputAt(i);
     if (output->IsRegister() && output->index() == index) return true;
   }
   return false;
@@ -932,69 +1216,72 @@
 bool RegisterAllocator::IsOutputDoubleRegisterOf(Instruction* instr,
                                                  int index) {
   for (size_t i = 0; i < instr->OutputCount(); i++) {
-    InstructionOperand* output = instr->OutputAt(i);
+    auto output = instr->OutputAt(i);
     if (output->IsDoubleRegister() && output->index() == index) return true;
   }
   return false;
 }
 
 
-void RegisterAllocator::ProcessInstructions(BasicBlock* block,
+void RegisterAllocator::ProcessInstructions(const InstructionBlock* block,
                                             BitVector* live) {
   int block_start = block->first_instruction_index();
-
-  LifetimePosition block_start_position =
+  auto block_start_position =
       LifetimePosition::FromInstructionIndex(block_start);
 
   for (int index = block->last_instruction_index(); index >= block_start;
        index--) {
-    LifetimePosition curr_position =
-        LifetimePosition::FromInstructionIndex(index);
-
-    Instruction* instr = InstructionAt(index);
-    DCHECK(instr != NULL);
+    auto curr_position = LifetimePosition::FromInstructionIndex(index);
+    auto instr = InstructionAt(index);
+    DCHECK(instr != nullptr);
     if (instr->IsGapMoves()) {
       // Process the moves of the gap instruction, making their sources live.
-      GapInstruction* gap = code()->GapAt(index);
-
-      // TODO(titzer): no need to create the parallel move if it doesn't exist.
-      ParallelMove* move =
-          gap->GetOrCreateParallelMove(GapInstruction::START, code_zone());
-      const ZoneList<MoveOperands>* move_operands = move->move_operands();
-      for (int i = 0; i < move_operands->length(); ++i) {
-        MoveOperands* cur = &move_operands->at(i);
-        if (cur->IsIgnored()) continue;
-        InstructionOperand* from = cur->source();
-        InstructionOperand* to = cur->destination();
-        InstructionOperand* hint = to;
-        if (to->IsUnallocated()) {
-          int to_vreg = UnallocatedOperand::cast(to)->virtual_register();
-          LiveRange* to_range = LiveRangeFor(to_vreg);
-          if (to_range->is_phi()) {
-            if (to_range->is_non_loop_phi()) {
-              hint = to_range->current_hint_operand();
+      auto gap = code()->GapAt(index);
+      const GapInstruction::InnerPosition kPositions[] = {
+          GapInstruction::END, GapInstruction::START};
+      for (auto position : kPositions) {
+        auto move = gap->GetParallelMove(position);
+        if (move == nullptr) continue;
+        if (position == GapInstruction::END) {
+          curr_position = curr_position.InstructionEnd();
+        } else {
+          curr_position = curr_position.InstructionStart();
+        }
+        auto move_ops = move->move_operands();
+        for (auto cur = move_ops->begin(); cur != move_ops->end(); ++cur) {
+          auto from = cur->source();
+          auto to = cur->destination();
+          auto hint = to;
+          if (to->IsUnallocated()) {
+            int to_vreg = UnallocatedOperand::cast(to)->virtual_register();
+            auto to_range = LiveRangeFor(to_vreg);
+            if (to_range->is_phi()) {
+              DCHECK(!FLAG_turbo_delay_ssa_decon);
+              if (to_range->is_non_loop_phi()) {
+                hint = to_range->current_hint_operand();
+              }
+            } else {
+              if (live->Contains(to_vreg)) {
+                Define(curr_position, to, from);
+                live->Remove(to_vreg);
+              } else {
+                cur->Eliminate();
+                continue;
+              }
             }
           } else {
-            if (live->Contains(to_vreg)) {
-              Define(curr_position, to, from);
-              live->Remove(to_vreg);
-            } else {
-              cur->Eliminate();
-              continue;
-            }
+            Define(curr_position, to, from);
           }
-        } else {
-          Define(curr_position, to, from);
-        }
-        Use(block_start_position, curr_position, from, hint);
-        if (from->IsUnallocated()) {
-          live->Add(UnallocatedOperand::cast(from)->virtual_register());
+          Use(block_start_position, curr_position, from, hint);
+          if (from->IsUnallocated()) {
+            live->Add(UnallocatedOperand::cast(from)->virtual_register());
+          }
         }
       }
     } else {
       // Process output, inputs, and temps of this non-gap instruction.
       for (size_t i = 0; i < instr->OutputCount(); i++) {
-        InstructionOperand* output = instr->OutputAt(i);
+        auto output = instr->OutputAt(i);
         if (output->IsUnallocated()) {
           int out_vreg = UnallocatedOperand::cast(output)->virtual_register();
           live->Remove(out_vreg);
@@ -1002,31 +1289,31 @@
           int out_vreg = output->index();
           live->Remove(out_vreg);
         }
-        Define(curr_position, output, NULL);
+        Define(curr_position, output, nullptr);
       }
 
       if (instr->ClobbersRegisters()) {
-        for (int i = 0; i < Register::kMaxNumAllocatableRegisters; ++i) {
+        for (int i = 0; i < config()->num_general_registers(); ++i) {
           if (!IsOutputRegisterOf(instr, i)) {
-            LiveRange* range = FixedLiveRangeFor(i);
+            auto range = FixedLiveRangeFor(i);
             range->AddUseInterval(curr_position, curr_position.InstructionEnd(),
-                                  zone());
+                                  local_zone());
           }
         }
       }
 
       if (instr->ClobbersDoubleRegisters()) {
-        for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); ++i) {
+        for (int i = 0; i < config()->num_aliased_double_registers(); ++i) {
           if (!IsOutputDoubleRegisterOf(instr, i)) {
-            LiveRange* range = FixedDoubleLiveRangeFor(i);
+            auto range = FixedDoubleLiveRangeFor(i);
             range->AddUseInterval(curr_position, curr_position.InstructionEnd(),
-                                  zone());
+                                  local_zone());
           }
         }
       }
 
       for (size_t i = 0; i < instr->InputCount(); i++) {
-        InstructionOperand* input = instr->InputAt(i);
+        auto input = instr->InputAt(i);
         if (input->IsImmediate()) continue;  // Ignore immediates.
         LifetimePosition use_pos;
         if (input->IsUnallocated() &&
@@ -1036,14 +1323,14 @@
           use_pos = curr_position.InstructionEnd();
         }
 
-        Use(block_start_position, use_pos, input, NULL);
+        Use(block_start_position, use_pos, input, nullptr);
         if (input->IsUnallocated()) {
           live->Add(UnallocatedOperand::cast(input)->virtual_register());
         }
       }
 
       for (size_t i = 0; i < instr->TempCount(); i++) {
-        InstructionOperand* temp = instr->TempAt(i);
+        auto temp = instr->TempAt(i);
         if (instr->ClobbersTemps()) {
           if (temp->IsRegister()) continue;
           if (temp->IsUnallocated()) {
@@ -1053,142 +1340,58 @@
             }
           }
         }
-        Use(block_start_position, curr_position.InstructionEnd(), temp, NULL);
-        Define(curr_position, temp, NULL);
+        Use(block_start_position, curr_position.InstructionEnd(), temp,
+            nullptr);
+        Define(curr_position, temp, nullptr);
       }
     }
   }
 }
 
 
-void RegisterAllocator::ResolvePhis(BasicBlock* block) {
-  for (BasicBlock::const_iterator i = block->begin(); i != block->end(); ++i) {
-    Node* phi = *i;
-    if (phi->opcode() != IrOpcode::kPhi) continue;
-
-    UnallocatedOperand* phi_operand =
-        new (code_zone()) UnallocatedOperand(UnallocatedOperand::NONE);
-    phi_operand->set_virtual_register(phi->id());
-
-    int j = 0;
-    Node::Inputs inputs = phi->inputs();
-    for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
-         ++iter, ++j) {
-      Node* op = *iter;
-      // TODO(mstarzinger): Use a ValueInputIterator instead.
-      if (j >= block->PredecessorCount()) continue;
-      UnallocatedOperand* operand =
-          new (code_zone()) UnallocatedOperand(UnallocatedOperand::ANY);
-      operand->set_virtual_register(op->id());
-      BasicBlock* cur_block = block->PredecessorAt(j);
-      // The gap move must be added without any special processing as in
-      // the AddConstraintsGapMove.
-      code()->AddGapMove(cur_block->last_instruction_index() - 1, operand,
-                         phi_operand);
-
-      Instruction* branch = InstructionAt(cur_block->last_instruction_index());
-      DCHECK(!branch->HasPointerMap());
-      USE(branch);
+void RegisterAllocator::ResolvePhis(const InstructionBlock* block) {
+  for (auto phi : block->phis()) {
+    if (FLAG_turbo_reuse_spill_slots) {
+      auto res = phi_map_.insert(
+          std::make_pair(phi->virtual_register(), PhiMapValue(phi, block)));
+      DCHECK(res.second);
+      USE(res);
     }
-
-    LiveRange* live_range = LiveRangeFor(phi->id());
-    BlockStartInstruction* block_start = code()->GetBlockStart(block);
-    block_start->GetOrCreateParallelMove(GapInstruction::START, code_zone())
-        ->AddMove(phi_operand, live_range->GetSpillOperand(), code_zone());
-    live_range->SetSpillStartIndex(block->first_instruction_index());
-
+    auto output = phi->output();
+    int phi_vreg = phi->virtual_register();
+    if (!FLAG_turbo_delay_ssa_decon) {
+      for (size_t i = 0; i < phi->operands().size(); ++i) {
+        InstructionBlock* cur_block =
+            code()->InstructionBlockAt(block->predecessors()[i]);
+        AddGapMove(cur_block->last_instruction_index() - 1, GapInstruction::END,
+                   phi->inputs()[i], output);
+        DCHECK(!InstructionAt(cur_block->last_instruction_index())
+                    ->HasPointerMap());
+      }
+    }
+    auto live_range = LiveRangeFor(phi_vreg);
+    int gap_index = block->first_instruction_index();
+    live_range->SpillAtDefinition(local_zone(), gap_index, output);
+    live_range->SetSpillStartIndex(gap_index);
     // We use the phi-ness of some nodes in some later heuristics.
     live_range->set_is_phi(true);
-    if (!block->IsLoopHeader()) {
-      live_range->set_is_non_loop_phi(true);
-    }
+    live_range->set_is_non_loop_phi(!block->IsLoopHeader());
   }
 }
 
 
-bool RegisterAllocator::Allocate() {
-  assigned_registers_ = new (code_zone())
-      BitVector(Register::NumAllocatableRegisters(), code_zone());
-  assigned_double_registers_ = new (code_zone())
-      BitVector(DoubleRegister::NumAllocatableRegisters(), code_zone());
-  MeetRegisterConstraints();
-  if (!AllocationOk()) return false;
-  ResolvePhis();
-  BuildLiveRanges();
-  AllocateGeneralRegisters();
-  if (!AllocationOk()) return false;
-  AllocateDoubleRegisters();
-  if (!AllocationOk()) return false;
-  PopulatePointerMaps();
-  ConnectRanges();
-  ResolveControlFlow();
-  code()->frame()->SetAllocatedRegisters(assigned_registers_);
-  code()->frame()->SetAllocatedDoubleRegisters(assigned_double_registers_);
-  return true;
-}
-
-
 void RegisterAllocator::MeetRegisterConstraints() {
-  RegisterAllocatorPhase phase("L_Register constraints", this);
-  for (int i = 0; i < code()->BasicBlockCount(); ++i) {
-    MeetRegisterConstraints(code()->BlockAt(i));
-    if (!AllocationOk()) return;
+  for (auto block : code()->instruction_blocks()) {
+    MeetRegisterConstraints(block);
   }
 }
 
 
 void RegisterAllocator::ResolvePhis() {
-  RegisterAllocatorPhase phase("L_Resolve phis", this);
-
   // Process the blocks in reverse order.
-  for (int i = code()->BasicBlockCount() - 1; i >= 0; --i) {
-    ResolvePhis(code()->BlockAt(i));
-  }
-}
-
-
-void RegisterAllocator::ResolveControlFlow(LiveRange* range, BasicBlock* block,
-                                           BasicBlock* pred) {
-  LifetimePosition pred_end =
-      LifetimePosition::FromInstructionIndex(pred->last_instruction_index());
-  LifetimePosition cur_start =
-      LifetimePosition::FromInstructionIndex(block->first_instruction_index());
-  LiveRange* pred_cover = NULL;
-  LiveRange* cur_cover = NULL;
-  LiveRange* cur_range = range;
-  while (cur_range != NULL && (cur_cover == NULL || pred_cover == NULL)) {
-    if (cur_range->CanCover(cur_start)) {
-      DCHECK(cur_cover == NULL);
-      cur_cover = cur_range;
-    }
-    if (cur_range->CanCover(pred_end)) {
-      DCHECK(pred_cover == NULL);
-      pred_cover = cur_range;
-    }
-    cur_range = cur_range->next();
-  }
-
-  if (cur_cover->IsSpilled()) return;
-  DCHECK(pred_cover != NULL && cur_cover != NULL);
-  if (pred_cover != cur_cover) {
-    InstructionOperand* pred_op =
-        pred_cover->CreateAssignedOperand(code_zone());
-    InstructionOperand* cur_op = cur_cover->CreateAssignedOperand(code_zone());
-    if (!pred_op->Equals(cur_op)) {
-      GapInstruction* gap = NULL;
-      if (block->PredecessorCount() == 1) {
-        gap = code()->GapAt(block->first_instruction_index());
-      } else {
-        DCHECK(pred->SuccessorCount() == 1);
-        gap = GetLastGap(pred);
-
-        Instruction* branch = InstructionAt(pred->last_instruction_index());
-        DCHECK(!branch->HasPointerMap());
-        USE(branch);
-      }
-      gap->GetOrCreateParallelMove(GapInstruction::START, code_zone())
-          ->AddMove(pred_op, cur_op, code_zone());
-    }
+  for (auto i = code()->instruction_blocks().rbegin();
+       i != code()->instruction_blocks().rend(); ++i) {
+    ResolvePhis(*i);
   }
 }
 
@@ -1197,7 +1400,7 @@
     LifetimePosition pos) {
   int index = pos.InstructionIndex();
   if (code()->IsGapAt(index)) {
-    GapInstruction* gap = code()->GapAt(index);
+    auto gap = code()->GapAt(index);
     return gap->GetOrCreateParallelMove(
         pos.IsInstructionStart() ? GapInstruction::START : GapInstruction::END,
         code_zone());
@@ -1209,40 +1412,35 @@
 }
 
 
-BasicBlock* RegisterAllocator::GetBlock(LifetimePosition pos) {
-  return code()->GetBasicBlock(pos.InstructionIndex());
+const InstructionBlock* RegisterAllocator::GetInstructionBlock(
+    LifetimePosition pos) {
+  return code()->GetInstructionBlock(pos.InstructionIndex());
 }
 
 
 void RegisterAllocator::ConnectRanges() {
-  RegisterAllocatorPhase phase("L_Connect ranges", this);
-  for (int i = 0; i < live_ranges()->length(); ++i) {
-    LiveRange* first_range = live_ranges()->at(i);
-    if (first_range == NULL || first_range->parent() != NULL) continue;
-
-    LiveRange* second_range = first_range->next();
-    while (second_range != NULL) {
-      LifetimePosition pos = second_range->Start();
-
+  for (auto first_range : live_ranges()) {
+    if (first_range == nullptr || first_range->IsChild()) continue;
+    auto second_range = first_range->next();
+    while (second_range != nullptr) {
+      auto pos = second_range->Start();
       if (!second_range->IsSpilled()) {
         // Add gap move if the two live ranges touch and there is no block
         // boundary.
         if (first_range->End().Value() == pos.Value()) {
           bool should_insert = true;
           if (IsBlockBoundary(pos)) {
-            should_insert = CanEagerlyResolveControlFlow(GetBlock(pos));
+            should_insert =
+                CanEagerlyResolveControlFlow(GetInstructionBlock(pos));
           }
           if (should_insert) {
-            ParallelMove* move = GetConnectingParallelMove(pos);
-            InstructionOperand* prev_operand =
-                first_range->CreateAssignedOperand(code_zone());
-            InstructionOperand* cur_operand =
-                second_range->CreateAssignedOperand(code_zone());
+            auto move = GetConnectingParallelMove(pos);
+            auto prev_operand = first_range->CreateAssignedOperand(code_zone());
+            auto cur_operand = second_range->CreateAssignedOperand(code_zone());
             move->AddMove(prev_operand, cur_operand, code_zone());
           }
         }
       }
-
       first_range = second_range;
       second_range = second_range->next();
     }
@@ -1250,27 +1448,186 @@
 }
 
 
-bool RegisterAllocator::CanEagerlyResolveControlFlow(BasicBlock* block) const {
+bool RegisterAllocator::CanEagerlyResolveControlFlow(
+    const InstructionBlock* block) const {
   if (block->PredecessorCount() != 1) return false;
-  return block->PredecessorAt(0)->rpo_number_ == block->rpo_number_ - 1;
+  return block->predecessors()[0].IsNext(block->rpo_number());
 }
 
 
+namespace {
+
+class LiveRangeBound {
+ public:
+  explicit LiveRangeBound(const LiveRange* range)
+      : range_(range), start_(range->Start()), end_(range->End()) {
+    DCHECK(!range->IsEmpty());
+  }
+
+  bool CanCover(LifetimePosition position) {
+    return start_.Value() <= position.Value() &&
+           position.Value() < end_.Value();
+  }
+
+  const LiveRange* const range_;
+  const LifetimePosition start_;
+  const LifetimePosition end_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LiveRangeBound);
+};
+
+
+struct FindResult {
+  const LiveRange* cur_cover_;
+  const LiveRange* pred_cover_;
+};
+
+
+class LiveRangeBoundArray {
+ public:
+  LiveRangeBoundArray() : length_(0), start_(nullptr) {}
+
+  bool ShouldInitialize() { return start_ == nullptr; }
+
+  void Initialize(Zone* zone, const LiveRange* const range) {
+    size_t length = 0;
+    for (auto i = range; i != nullptr; i = i->next()) length++;
+    start_ = zone->NewArray<LiveRangeBound>(static_cast<int>(length));
+    length_ = length;
+    auto curr = start_;
+    for (auto i = range; i != nullptr; i = i->next(), ++curr) {
+      new (curr) LiveRangeBound(i);
+    }
+  }
+
+  LiveRangeBound* Find(const LifetimePosition position) const {
+    size_t left_index = 0;
+    size_t right_index = length_;
+    while (true) {
+      size_t current_index = left_index + (right_index - left_index) / 2;
+      DCHECK(right_index > current_index);
+      auto bound = &start_[current_index];
+      if (bound->start_.Value() <= position.Value()) {
+        if (position.Value() < bound->end_.Value()) return bound;
+        DCHECK(left_index < current_index);
+        left_index = current_index;
+      } else {
+        right_index = current_index;
+      }
+    }
+  }
+
+  LiveRangeBound* FindPred(const InstructionBlock* pred) {
+    auto pred_end =
+        LifetimePosition::FromInstructionIndex(pred->last_instruction_index());
+    return Find(pred_end);
+  }
+
+  LiveRangeBound* FindSucc(const InstructionBlock* succ) {
+    auto succ_start =
+        LifetimePosition::FromInstructionIndex(succ->first_instruction_index());
+    return Find(succ_start);
+  }
+
+  void Find(const InstructionBlock* block, const InstructionBlock* pred,
+            FindResult* result) const {
+    auto pred_end =
+        LifetimePosition::FromInstructionIndex(pred->last_instruction_index());
+    auto bound = Find(pred_end);
+    result->pred_cover_ = bound->range_;
+    auto cur_start = LifetimePosition::FromInstructionIndex(
+        block->first_instruction_index());
+    // Common case.
+    if (bound->CanCover(cur_start)) {
+      result->cur_cover_ = bound->range_;
+      return;
+    }
+    result->cur_cover_ = Find(cur_start)->range_;
+    DCHECK(result->pred_cover_ != nullptr && result->cur_cover_ != nullptr);
+  }
+
+ private:
+  size_t length_;
+  LiveRangeBound* start_;
+
+  DISALLOW_COPY_AND_ASSIGN(LiveRangeBoundArray);
+};
+
+
+class LiveRangeFinder {
+ public:
+  explicit LiveRangeFinder(const RegisterAllocator& allocator)
+      : allocator_(allocator),
+        bounds_length_(static_cast<int>(allocator.live_ranges().size())),
+        bounds_(allocator.local_zone()->NewArray<LiveRangeBoundArray>(
+            bounds_length_)) {
+    for (int i = 0; i < bounds_length_; ++i) {
+      new (&bounds_[i]) LiveRangeBoundArray();
+    }
+  }
+
+  LiveRangeBoundArray* ArrayFor(int operand_index) {
+    DCHECK(operand_index < bounds_length_);
+    auto range = allocator_.live_ranges()[operand_index];
+    DCHECK(range != nullptr && !range->IsEmpty());
+    auto array = &bounds_[operand_index];
+    if (array->ShouldInitialize()) {
+      array->Initialize(allocator_.local_zone(), range);
+    }
+    return array;
+  }
+
+ private:
+  const RegisterAllocator& allocator_;
+  const int bounds_length_;
+  LiveRangeBoundArray* const bounds_;
+
+  DISALLOW_COPY_AND_ASSIGN(LiveRangeFinder);
+};
+
+}  // namespace
+
+
 void RegisterAllocator::ResolveControlFlow() {
-  RegisterAllocatorPhase phase("L_Resolve control flow", this);
-  for (int block_id = 1; block_id < code()->BasicBlockCount(); ++block_id) {
-    BasicBlock* block = code()->BlockAt(block_id);
+  // Lazily linearize live ranges in memory for fast lookup.
+  LiveRangeFinder finder(*this);
+  for (auto block : code()->instruction_blocks()) {
     if (CanEagerlyResolveControlFlow(block)) continue;
-    BitVector* live = live_in_sets_[block->rpo_number_];
+    if (FLAG_turbo_delay_ssa_decon) {
+      // resolve phis
+      for (auto phi : block->phis()) {
+        auto* block_bound =
+            finder.ArrayFor(phi->virtual_register())->FindSucc(block);
+        auto phi_output =
+            block_bound->range_->CreateAssignedOperand(code_zone());
+        phi->output()->ConvertTo(phi_output->kind(), phi_output->index());
+        size_t pred_index = 0;
+        for (auto pred : block->predecessors()) {
+          const InstructionBlock* pred_block = code()->InstructionBlockAt(pred);
+          auto* pred_bound = finder.ArrayFor(phi->operands()[pred_index])
+                                 ->FindPred(pred_block);
+          auto pred_op = pred_bound->range_->CreateAssignedOperand(code_zone());
+          phi->inputs()[pred_index] = pred_op;
+          ResolveControlFlow(block, phi_output, pred_block, pred_op);
+          pred_index++;
+        }
+      }
+    }
+    auto live = live_in_sets_[block->rpo_number().ToInt()];
     BitVector::Iterator iterator(live);
     while (!iterator.Done()) {
-      int operand_index = iterator.Current();
-      BasicBlock::Predecessors predecessors = block->predecessors();
-      for (BasicBlock::Predecessors::iterator i = predecessors.begin();
-           i != predecessors.end(); ++i) {
-        BasicBlock* cur = *i;
-        LiveRange* cur_range = LiveRangeFor(operand_index);
-        ResolveControlFlow(cur_range, block, cur);
+      auto* array = finder.ArrayFor(iterator.Current());
+      for (auto pred : block->predecessors()) {
+        FindResult result;
+        const auto* pred_block = code()->InstructionBlockAt(pred);
+        array->Find(block, pred_block, &result);
+        if (result.cur_cover_ == result.pred_cover_ ||
+            result.cur_cover_->IsSpilled())
+          continue;
+        auto pred_op = result.pred_cover_->CreateAssignedOperand(code_zone());
+        auto cur_op = result.cur_cover_->CreateAssignedOperand(code_zone());
+        ResolveControlFlow(block, cur_op, pred_block, pred_op);
       }
       iterator.Advance();
     }
@@ -1278,14 +1635,33 @@
 }
 
 
+void RegisterAllocator::ResolveControlFlow(const InstructionBlock* block,
+                                           InstructionOperand* cur_op,
+                                           const InstructionBlock* pred,
+                                           InstructionOperand* pred_op) {
+  if (pred_op->Equals(cur_op)) return;
+  int gap_index;
+  GapInstruction::InnerPosition position;
+  if (block->PredecessorCount() == 1) {
+    gap_index = block->first_instruction_index();
+    position = GapInstruction::START;
+  } else {
+    DCHECK(pred->SuccessorCount() == 1);
+    DCHECK(!InstructionAt(pred->last_instruction_index())->HasPointerMap());
+    gap_index = pred->last_instruction_index() - 1;
+    position = GapInstruction::END;
+  }
+  AddGapMove(gap_index, position, pred_op, cur_op);
+}
+
+
 void RegisterAllocator::BuildLiveRanges() {
-  RegisterAllocatorPhase phase("L_Build live ranges", this);
-  InitializeLivenessAnalysis();
   // Process the blocks in reverse order.
-  for (int block_id = code()->BasicBlockCount() - 1; block_id >= 0;
+  for (int block_id = code()->InstructionBlockCount() - 1; block_id >= 0;
        --block_id) {
-    BasicBlock* block = code()->BlockAt(block_id);
-    BitVector* live = ComputeLiveOut(block);
+    auto block =
+        code()->InstructionBlockAt(BasicBlock::RpoNumber::FromInt(block_id));
+    auto live = ComputeLiveOut(block);
     // Initially consider all live_out values live for the entire block. We
     // will shorten these intervals if necessary.
     AddInitialIntervals(block, live);
@@ -1294,36 +1670,32 @@
     // live values.
     ProcessInstructions(block, live);
     // All phi output operands are killed by this block.
-    for (BasicBlock::const_iterator i = block->begin(); i != block->end();
-         ++i) {
-      Node* phi = *i;
-      if (phi->opcode() != IrOpcode::kPhi) continue;
-
+    for (auto phi : block->phis()) {
       // The live range interval already ends at the first instruction of the
       // block.
-      live->Remove(phi->id());
-
-      InstructionOperand* hint = NULL;
-      InstructionOperand* phi_operand = NULL;
-      GapInstruction* gap = GetLastGap(block->PredecessorAt(0));
-
-      // TODO(titzer): no need to create the parallel move if it doesn't exit.
-      ParallelMove* move =
-          gap->GetOrCreateParallelMove(GapInstruction::START, code_zone());
-      for (int j = 0; j < move->move_operands()->length(); ++j) {
-        InstructionOperand* to = move->move_operands()->at(j).destination();
-        if (to->IsUnallocated() &&
-            UnallocatedOperand::cast(to)->virtual_register() == phi->id()) {
-          hint = move->move_operands()->at(j).source();
-          phi_operand = to;
-          break;
+      int phi_vreg = phi->virtual_register();
+      live->Remove(phi_vreg);
+      if (!FLAG_turbo_delay_ssa_decon) {
+        InstructionOperand* hint = nullptr;
+        InstructionOperand* phi_operand = nullptr;
+        auto gap =
+            GetLastGap(code()->InstructionBlockAt(block->predecessors()[0]));
+        auto move =
+            gap->GetOrCreateParallelMove(GapInstruction::END, code_zone());
+        for (int j = 0; j < move->move_operands()->length(); ++j) {
+          auto to = move->move_operands()->at(j).destination();
+          if (to->IsUnallocated() &&
+              UnallocatedOperand::cast(to)->virtual_register() == phi_vreg) {
+            hint = move->move_operands()->at(j).source();
+            phi_operand = to;
+            break;
+          }
         }
+        DCHECK(hint != nullptr);
+        auto block_start = LifetimePosition::FromInstructionIndex(
+            block->first_instruction_index());
+        Define(block_start, phi_operand, hint);
       }
-      DCHECK(hint != NULL);
-
-      LifetimePosition block_start = LifetimePosition::FromInstructionIndex(
-          block->first_instruction_index());
-      Define(block_start, phi_operand, hint);
     }
 
     // Now live is live_in for this block except not including values live
@@ -1334,71 +1706,39 @@
       // Add a live range stretching from the first loop instruction to the last
       // for each value live on entry to the header.
       BitVector::Iterator iterator(live);
-      LifetimePosition start = LifetimePosition::FromInstructionIndex(
+      auto start = LifetimePosition::FromInstructionIndex(
           block->first_instruction_index());
-      int end_index =
-          code()->BlockAt(block->loop_end_)->last_instruction_index();
-      LifetimePosition end =
-          LifetimePosition::FromInstructionIndex(end_index).NextInstruction();
+      auto end = LifetimePosition::FromInstructionIndex(
+                     code()->LastLoopInstructionIndex(block)).NextInstruction();
       while (!iterator.Done()) {
         int operand_index = iterator.Current();
-        LiveRange* range = LiveRangeFor(operand_index);
-        range->EnsureInterval(start, end, zone());
+        auto range = LiveRangeFor(operand_index);
+        range->EnsureInterval(start, end, local_zone());
         iterator.Advance();
       }
-
       // Insert all values into the live in sets of all blocks in the loop.
-      for (int i = block->rpo_number_ + 1; i < block->loop_end_; ++i) {
+      for (int i = block->rpo_number().ToInt() + 1;
+           i < block->loop_end().ToInt(); ++i) {
         live_in_sets_[i]->Union(*live);
       }
     }
-
-#ifdef DEBUG
-    if (block_id == 0) {
-      BitVector::Iterator iterator(live);
-      bool found = false;
-      while (!iterator.Done()) {
-        found = true;
-        int operand_index = iterator.Current();
-        PrintF("Register allocator error: live v%d reached first block.\n",
-               operand_index);
-        LiveRange* range = LiveRangeFor(operand_index);
-        PrintF("  (first use is at %d)\n", range->first_pos()->pos().Value());
-        CompilationInfo* info = code()->linkage()->info();
-        if (info->IsStub()) {
-          if (info->code_stub() == NULL) {
-            PrintF("\n");
-          } else {
-            CodeStub::Major major_key = info->code_stub()->MajorKey();
-            PrintF("  (function: %s)\n", CodeStub::MajorName(major_key, false));
-          }
-        } else {
-          DCHECK(info->IsOptimizing());
-          AllowHandleDereference allow_deref;
-          PrintF("  (function: %s)\n",
-                 info->function()->debug_name()->ToCString().get());
-        }
-        iterator.Advance();
-      }
-      DCHECK(!found);
-    }
-#endif
   }
 
-  for (int i = 0; i < live_ranges_.length(); ++i) {
-    if (live_ranges_[i] != NULL) {
-      live_ranges_[i]->kind_ = RequiredRegisterKind(live_ranges_[i]->id());
-
-      // TODO(bmeurer): This is a horrible hack to make sure that for constant
-      // live ranges, every use requires the constant to be in a register.
-      // Without this hack, all uses with "any" policy would get the constant
-      // operand assigned.
-      LiveRange* range = live_ranges_[i];
-      if (range->HasAllocatedSpillOperand() &&
-          range->GetSpillOperand()->IsConstant()) {
-        for (UsePosition* pos = range->first_pos(); pos != NULL;
-             pos = pos->next_) {
-          pos->register_beneficial_ = true;
+  for (auto range : live_ranges()) {
+    if (range == nullptr) continue;
+    range->kind_ = RequiredRegisterKind(range->id());
+    // TODO(bmeurer): This is a horrible hack to make sure that for constant
+    // live ranges, every use requires the constant to be in a register.
+    // Without this hack, all uses with "any" policy would get the constant
+    // operand assigned.
+    if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) {
+      for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next_) {
+        pos->register_beneficial_ = true;
+        // TODO(dcarney): should the else case assert requires_reg_ == false?
+        // Can't mark phis as needing a register.
+        if (!code()
+                 ->InstructionAt(pos->pos().InstructionIndex())
+                 ->IsGapMoves()) {
           pos->requires_reg_ = true;
         }
       }
@@ -1407,12 +1747,30 @@
 }
 
 
+bool RegisterAllocator::ExistsUseWithoutDefinition() {
+  bool found = false;
+  BitVector::Iterator iterator(live_in_sets_[0]);
+  while (!iterator.Done()) {
+    found = true;
+    int operand_index = iterator.Current();
+    PrintF("Register allocator error: live v%d reached first block.\n",
+           operand_index);
+    LiveRange* range = LiveRangeFor(operand_index);
+    PrintF("  (first use is at %d)\n", range->first_pos()->pos().Value());
+    if (debug_name() == nullptr) {
+      PrintF("\n");
+    } else {
+      PrintF("  (function: %s)\n", debug_name());
+    }
+    iterator.Advance();
+  }
+  return found;
+}
+
+
 bool RegisterAllocator::SafePointsAreInOrder() const {
   int safe_point = 0;
-  const PointerMapDeque* pointer_maps = code()->pointer_maps();
-  for (PointerMapDeque::const_iterator it = pointer_maps->begin();
-       it != pointer_maps->end(); ++it) {
-    PointerMap* map = *it;
+  for (auto map : *code()->pointer_maps()) {
     if (safe_point > map->instruction_position()) return false;
     safe_point = map->instruction_position();
   }
@@ -1421,20 +1779,17 @@
 
 
 void RegisterAllocator::PopulatePointerMaps() {
-  RegisterAllocatorPhase phase("L_Populate pointer maps", this);
-
   DCHECK(SafePointsAreInOrder());
 
   // Iterate over all safe point positions and record a pointer
   // for all spilled live ranges at this point.
   int last_range_start = 0;
-  const PointerMapDeque* pointer_maps = code()->pointer_maps();
+  auto pointer_maps = code()->pointer_maps();
   PointerMapDeque::const_iterator first_it = pointer_maps->begin();
-  for (int range_idx = 0; range_idx < live_ranges()->length(); ++range_idx) {
-    LiveRange* range = live_ranges()->at(range_idx);
-    if (range == NULL) continue;
+  for (LiveRange* range : live_ranges()) {
+    if (range == nullptr) continue;
     // Iterate over the first parts of multi-part live ranges.
-    if (range->parent() != NULL) continue;
+    if (range->IsChild()) continue;
     // Skip non-reference values.
     if (!HasTaggedValue(range->id())) continue;
     // Skip empty live ranges.
@@ -1443,8 +1798,8 @@
     // Find the extent of the range and its children.
     int start = range->Start().InstructionIndex();
     int end = 0;
-    for (LiveRange* cur = range; cur != NULL; cur = cur->next()) {
-      LifetimePosition this_end = cur->End();
+    for (auto cur = range; cur != nullptr; cur = cur->next()) {
+      auto this_end = cur->End();
       if (this_end.InstructionIndex() > end) end = this_end.InstructionIndex();
       DCHECK(cur->Start().InstructionIndex() >= start);
     }
@@ -1457,14 +1812,13 @@
     // Step across all the safe points that are before the start of this range,
     // recording how far we step in order to save doing this for the next range.
     for (; first_it != pointer_maps->end(); ++first_it) {
-      PointerMap* map = *first_it;
+      auto map = *first_it;
       if (map->instruction_position() >= start) break;
     }
 
     // Step through the safe points to see whether they are in the range.
-    for (PointerMapDeque::const_iterator it = first_it;
-         it != pointer_maps->end(); ++it) {
-      PointerMap* map = *it;
+    for (auto it = first_it; it != pointer_maps->end(); ++it) {
+      auto map = *it;
       int safe_point = map->instruction_position();
 
       // The safe points are sorted so we can stop searching here.
@@ -1472,17 +1826,16 @@
 
       // Advance to the next active range that covers the current
       // safe point position.
-      LifetimePosition safe_point_pos =
-          LifetimePosition::FromInstructionIndex(safe_point);
-      LiveRange* cur = range;
-      while (cur != NULL && !cur->Covers(safe_point_pos)) {
+      auto safe_point_pos = LifetimePosition::FromInstructionIndex(safe_point);
+      auto cur = range;
+      while (cur != nullptr && !cur->Covers(safe_point_pos)) {
         cur = cur->next();
       }
-      if (cur == NULL) continue;
+      if (cur == nullptr) continue;
 
       // Check if the live range is spilled and the safe point is after
       // the spill position.
-      if (range->HasAllocatedSpillOperand() &&
+      if (range->HasSpillOperand() &&
           safe_point >= range->spill_start_index() &&
           !range->GetSpillOperand()->IsConstant()) {
         TraceAlloc("Pointer for range %d (spilled at %d) at safe point %d\n",
@@ -1505,76 +1858,73 @@
 
 
 void RegisterAllocator::AllocateGeneralRegisters() {
-  RegisterAllocatorPhase phase("L_Allocate general registers", this);
-  num_registers_ = Register::NumAllocatableRegisters();
+  num_registers_ = config()->num_general_registers();
   mode_ = GENERAL_REGISTERS;
   AllocateRegisters();
 }
 
 
 void RegisterAllocator::AllocateDoubleRegisters() {
-  RegisterAllocatorPhase phase("L_Allocate double registers", this);
-  num_registers_ = DoubleRegister::NumAllocatableRegisters();
+  num_registers_ = config()->num_aliased_double_registers();
   mode_ = DOUBLE_REGISTERS;
   AllocateRegisters();
 }
 
 
 void RegisterAllocator::AllocateRegisters() {
-  DCHECK(unhandled_live_ranges_.is_empty());
+  DCHECK(unhandled_live_ranges().empty());
 
-  for (int i = 0; i < live_ranges_.length(); ++i) {
-    if (live_ranges_[i] != NULL) {
-      if (live_ranges_[i]->Kind() == mode_) {
-        AddToUnhandledUnsorted(live_ranges_[i]);
-      }
+  for (auto range : live_ranges()) {
+    if (range == nullptr) continue;
+    if (range->Kind() == mode_) {
+      AddToUnhandledUnsorted(range);
     }
   }
   SortUnhandled();
   DCHECK(UnhandledIsSorted());
 
-  DCHECK(reusable_slots_.is_empty());
-  DCHECK(active_live_ranges_.is_empty());
-  DCHECK(inactive_live_ranges_.is_empty());
+  DCHECK(reusable_slots().empty());
+  DCHECK(active_live_ranges().empty());
+  DCHECK(inactive_live_ranges().empty());
 
   if (mode_ == DOUBLE_REGISTERS) {
-    for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); ++i) {
-      LiveRange* current = fixed_double_live_ranges_.at(i);
-      if (current != NULL) {
+    for (int i = 0; i < config()->num_aliased_double_registers(); ++i) {
+      auto current = fixed_double_live_ranges()[i];
+      if (current != nullptr) {
         AddToInactive(current);
       }
     }
   } else {
     DCHECK(mode_ == GENERAL_REGISTERS);
-    for (int i = 0; i < fixed_live_ranges_.length(); ++i) {
-      LiveRange* current = fixed_live_ranges_.at(i);
-      if (current != NULL) {
+    for (auto current : fixed_live_ranges()) {
+      if (current != nullptr) {
         AddToInactive(current);
       }
     }
   }
 
-  while (!unhandled_live_ranges_.is_empty()) {
+  while (!unhandled_live_ranges().empty()) {
     DCHECK(UnhandledIsSorted());
-    LiveRange* current = unhandled_live_ranges_.RemoveLast();
+    auto current = unhandled_live_ranges().back();
+    unhandled_live_ranges().pop_back();
     DCHECK(UnhandledIsSorted());
-    LifetimePosition position = current->Start();
+    auto position = current->Start();
 #ifdef DEBUG
     allocation_finger_ = position;
 #endif
     TraceAlloc("Processing interval %d start=%d\n", current->id(),
                position.Value());
 
-    if (current->HasAllocatedSpillOperand()) {
+    if (!current->HasNoSpillType()) {
       TraceAlloc("Live range %d already has a spill operand\n", current->id());
-      LifetimePosition next_pos = position;
+      auto next_pos = position;
       if (code()->IsGapAt(next_pos.InstructionIndex())) {
         next_pos = next_pos.NextInstruction();
       }
-      UsePosition* pos = current->NextUsePositionRegisterIsBeneficial(next_pos);
+      auto pos = current->NextUsePositionRegisterIsBeneficial(next_pos);
       // If the range already has a spill operand and it doesn't need a
       // register immediately, split it and spill the first part of the range.
-      if (pos == NULL) {
+      if (pos == nullptr) {
         Spill(current);
         continue;
       } else if (pos->pos().Value() >
@@ -1588,8 +1938,15 @@
       }
     }
 
-    for (int i = 0; i < active_live_ranges_.length(); ++i) {
-      LiveRange* cur_active = active_live_ranges_.at(i);
+    if (FLAG_turbo_reuse_spill_slots) {
+      if (TryReuseSpillForPhi(current)) {
+        continue;
+      }
+      if (!AllocationOk()) return;
+    }
+
+    for (size_t i = 0; i < active_live_ranges().size(); ++i) {
+      auto cur_active = active_live_ranges()[i];
       if (cur_active->End().Value() <= position.Value()) {
         ActiveToHandled(cur_active);
         --i;  // The live range was removed from the list of active live ranges.
@@ -1599,8 +1956,8 @@
       }
     }
 
-    for (int i = 0; i < inactive_live_ranges_.length(); ++i) {
-      LiveRange* cur_inactive = inactive_live_ranges_.at(i);
+    for (size_t i = 0; i < inactive_live_ranges().size(); ++i) {
+      auto cur_inactive = inactive_live_ranges()[i];
       if (cur_inactive->End().Value() <= position.Value()) {
         InactiveToHandled(cur_inactive);
         --i;  // Live range was removed from the list of inactive live ranges.
@@ -1623,27 +1980,17 @@
     }
   }
 
-  reusable_slots_.Rewind(0);
-  active_live_ranges_.Rewind(0);
-  inactive_live_ranges_.Rewind(0);
+  reusable_slots().clear();
+  active_live_ranges().clear();
+  inactive_live_ranges().clear();
 }
 
 
 const char* RegisterAllocator::RegisterName(int allocation_index) {
   if (mode_ == GENERAL_REGISTERS) {
-    return Register::AllocationIndexToString(allocation_index);
+    return config()->general_register_name(allocation_index);
   } else {
-    return DoubleRegister::AllocationIndexToString(allocation_index);
-  }
-}
-
-
-void RegisterAllocator::TraceAlloc(const char* msg, ...) {
-  if (FLAG_trace_alloc) {
-    va_list arguments;
-    va_start(arguments, msg);
-    base::OS::VPrint(msg, arguments);
-    va_end(arguments);
+    return config()->double_register_name(allocation_index);
   }
 }
 
@@ -1662,49 +2009,49 @@
 
 void RegisterAllocator::AddToActive(LiveRange* range) {
   TraceAlloc("Add live range %d to active\n", range->id());
-  active_live_ranges_.Add(range, zone());
+  active_live_ranges().push_back(range);
 }
 
 
 void RegisterAllocator::AddToInactive(LiveRange* range) {
   TraceAlloc("Add live range %d to inactive\n", range->id());
-  inactive_live_ranges_.Add(range, zone());
+  inactive_live_ranges().push_back(range);
 }
 
 
 void RegisterAllocator::AddToUnhandledSorted(LiveRange* range) {
-  if (range == NULL || range->IsEmpty()) return;
+  if (range == nullptr || range->IsEmpty()) return;
   DCHECK(!range->HasRegisterAssigned() && !range->IsSpilled());
   DCHECK(allocation_finger_.Value() <= range->Start().Value());
-  for (int i = unhandled_live_ranges_.length() - 1; i >= 0; --i) {
-    LiveRange* cur_range = unhandled_live_ranges_.at(i);
-    if (range->ShouldBeAllocatedBefore(cur_range)) {
-      TraceAlloc("Add live range %d to unhandled at %d\n", range->id(), i + 1);
-      unhandled_live_ranges_.InsertAt(i + 1, range, zone());
-      DCHECK(UnhandledIsSorted());
-      return;
-    }
+  for (int i = static_cast<int>(unhandled_live_ranges().size() - 1); i >= 0;
+       --i) {
+    auto cur_range = unhandled_live_ranges().at(i);
+    if (!range->ShouldBeAllocatedBefore(cur_range)) continue;
+    TraceAlloc("Add live range %d to unhandled at %d\n", range->id(), i + 1);
+    auto it = unhandled_live_ranges().begin() + (i + 1);
+    unhandled_live_ranges().insert(it, range);
+    DCHECK(UnhandledIsSorted());
+    return;
   }
   TraceAlloc("Add live range %d to unhandled at start\n", range->id());
-  unhandled_live_ranges_.InsertAt(0, range, zone());
+  unhandled_live_ranges().insert(unhandled_live_ranges().begin(), range);
   DCHECK(UnhandledIsSorted());
 }
 
 
 void RegisterAllocator::AddToUnhandledUnsorted(LiveRange* range) {
-  if (range == NULL || range->IsEmpty()) return;
+  if (range == nullptr || range->IsEmpty()) return;
   DCHECK(!range->HasRegisterAssigned() && !range->IsSpilled());
   TraceAlloc("Add live range %d to unhandled unsorted at end\n", range->id());
-  unhandled_live_ranges_.Add(range, zone());
+  unhandled_live_ranges().push_back(range);
 }
 
 
-static int UnhandledSortHelper(LiveRange* const* a, LiveRange* const* b) {
-  DCHECK(!(*a)->ShouldBeAllocatedBefore(*b) ||
-         !(*b)->ShouldBeAllocatedBefore(*a));
-  if ((*a)->ShouldBeAllocatedBefore(*b)) return 1;
-  if ((*b)->ShouldBeAllocatedBefore(*a)) return -1;
-  return (*a)->id() - (*b)->id();
+static bool UnhandledSortHelper(LiveRange* a, LiveRange* b) {
+  DCHECK(!a->ShouldBeAllocatedBefore(b) || !b->ShouldBeAllocatedBefore(a));
+  if (a->ShouldBeAllocatedBefore(b)) return false;
+  if (b->ShouldBeAllocatedBefore(a)) return true;
+  return a->id() < b->id();
 }
 
 
@@ -1713,15 +2060,16 @@
 // algorithm because it is efficient to remove elements from the end.
 void RegisterAllocator::SortUnhandled() {
   TraceAlloc("Sort unhandled\n");
-  unhandled_live_ranges_.Sort(&UnhandledSortHelper);
+  std::sort(unhandled_live_ranges().begin(), unhandled_live_ranges().end(),
+            &UnhandledSortHelper);
 }
 
 
 bool RegisterAllocator::UnhandledIsSorted() {
-  int len = unhandled_live_ranges_.length();
-  for (int i = 1; i < len; i++) {
-    LiveRange* a = unhandled_live_ranges_.at(i - 1);
-    LiveRange* b = unhandled_live_ranges_.at(i);
+  size_t len = unhandled_live_ranges().size();
+  for (size_t i = 1; i < len; i++) {
+    auto a = unhandled_live_ranges().at(i - 1);
+    auto b = unhandled_live_ranges().at(i);
     if (a->Start().Value() < b->Start().Value()) return false;
   }
   return true;
@@ -1729,95 +2077,81 @@
 
 
 void RegisterAllocator::FreeSpillSlot(LiveRange* range) {
+  DCHECK(!FLAG_turbo_reuse_spill_slots);
   // Check that we are the last range.
-  if (range->next() != NULL) return;
-
-  if (!range->TopLevel()->HasAllocatedSpillOperand()) return;
-
-  InstructionOperand* spill_operand = range->TopLevel()->GetSpillOperand();
+  if (range->next() != nullptr) return;
+  if (!range->TopLevel()->HasSpillOperand()) return;
+  auto spill_operand = range->TopLevel()->GetSpillOperand();
   if (spill_operand->IsConstant()) return;
   if (spill_operand->index() >= 0) {
-    reusable_slots_.Add(range, zone());
+    reusable_slots().push_back(range);
   }
 }
 
 
 InstructionOperand* RegisterAllocator::TryReuseSpillSlot(LiveRange* range) {
-  if (reusable_slots_.is_empty()) return NULL;
-  if (reusable_slots_.first()->End().Value() >
+  DCHECK(!FLAG_turbo_reuse_spill_slots);
+  if (reusable_slots().empty()) return nullptr;
+  if (reusable_slots().front()->End().Value() >
       range->TopLevel()->Start().Value()) {
-    return NULL;
+    return nullptr;
   }
-  InstructionOperand* result =
-      reusable_slots_.first()->TopLevel()->GetSpillOperand();
-  reusable_slots_.Remove(0);
+  auto result = reusable_slots().front()->TopLevel()->GetSpillOperand();
+  reusable_slots().erase(reusable_slots().begin());
   return result;
 }
 
 
 void RegisterAllocator::ActiveToHandled(LiveRange* range) {
-  DCHECK(active_live_ranges_.Contains(range));
-  active_live_ranges_.RemoveElement(range);
+  RemoveElement(&active_live_ranges(), range);
   TraceAlloc("Moving live range %d from active to handled\n", range->id());
-  FreeSpillSlot(range);
+  if (!FLAG_turbo_reuse_spill_slots) FreeSpillSlot(range);
 }
 
 
 void RegisterAllocator::ActiveToInactive(LiveRange* range) {
-  DCHECK(active_live_ranges_.Contains(range));
-  active_live_ranges_.RemoveElement(range);
-  inactive_live_ranges_.Add(range, zone());
+  RemoveElement(&active_live_ranges(), range);
+  inactive_live_ranges().push_back(range);
   TraceAlloc("Moving live range %d from active to inactive\n", range->id());
 }
 
 
 void RegisterAllocator::InactiveToHandled(LiveRange* range) {
-  DCHECK(inactive_live_ranges_.Contains(range));
-  inactive_live_ranges_.RemoveElement(range);
+  RemoveElement(&inactive_live_ranges(), range);
   TraceAlloc("Moving live range %d from inactive to handled\n", range->id());
-  FreeSpillSlot(range);
+  if (!FLAG_turbo_reuse_spill_slots) FreeSpillSlot(range);
 }
 
 
 void RegisterAllocator::InactiveToActive(LiveRange* range) {
-  DCHECK(inactive_live_ranges_.Contains(range));
-  inactive_live_ranges_.RemoveElement(range);
-  active_live_ranges_.Add(range, zone());
+  RemoveElement(&inactive_live_ranges(), range);
+  active_live_ranges().push_back(range);
   TraceAlloc("Moving live range %d from inactive to active\n", range->id());
 }
 
 
-// TryAllocateFreeReg and AllocateBlockedReg assume this
-// when allocating local arrays.
-STATIC_ASSERT(DoubleRegister::kMaxNumAllocatableRegisters >=
-              Register::kMaxNumAllocatableRegisters);
-
-
 bool RegisterAllocator::TryAllocateFreeReg(LiveRange* current) {
-  LifetimePosition free_until_pos[DoubleRegister::kMaxNumAllocatableRegisters];
+  LifetimePosition free_until_pos[RegisterConfiguration::kMaxDoubleRegisters];
 
   for (int i = 0; i < num_registers_; i++) {
     free_until_pos[i] = LifetimePosition::MaxPosition();
   }
 
-  for (int i = 0; i < active_live_ranges_.length(); ++i) {
-    LiveRange* cur_active = active_live_ranges_.at(i);
+  for (auto cur_active : active_live_ranges()) {
     free_until_pos[cur_active->assigned_register()] =
         LifetimePosition::FromInstructionIndex(0);
   }
 
-  for (int i = 0; i < inactive_live_ranges_.length(); ++i) {
-    LiveRange* cur_inactive = inactive_live_ranges_.at(i);
+  for (auto cur_inactive : inactive_live_ranges()) {
     DCHECK(cur_inactive->End().Value() > current->Start().Value());
-    LifetimePosition next_intersection =
-        cur_inactive->FirstIntersection(current);
+    auto next_intersection = cur_inactive->FirstIntersection(current);
     if (!next_intersection.IsValid()) continue;
     int cur_reg = cur_inactive->assigned_register();
     free_until_pos[cur_reg] = Min(free_until_pos[cur_reg], next_intersection);
   }
 
-  InstructionOperand* hint = current->FirstHint();
-  if (hint != NULL && (hint->IsRegister() || hint->IsDoubleRegister())) {
+  auto hint = current->FirstHint();
+  if (hint != nullptr && (hint->IsRegister() || hint->IsDoubleRegister())) {
     int register_index = hint->index();
     TraceAlloc(
         "Found reg hint %s (free until [%d) for live range %d (end %d[).\n",
@@ -1841,7 +2175,7 @@
     }
   }
 
-  LifetimePosition pos = free_until_pos[reg];
+  auto pos = free_until_pos[reg];
 
   if (pos.Value() <= current->Start().Value()) {
     // All registers are blocked.
@@ -1851,12 +2185,11 @@
   if (pos.Value() < current->End().Value()) {
     // Register reg is available at the range start but becomes blocked before
     // the range end. Split current at position where it becomes blocked.
-    LiveRange* tail = SplitRangeAt(current, pos);
+    auto tail = SplitRangeAt(current, pos);
     if (!AllocationOk()) return false;
     AddToUnhandledSorted(tail);
   }
 
-
   // Register reg is available at the range start and is free until
   // the range end.
   DCHECK(pos.Value() >= current->End().Value());
@@ -1869,32 +2202,30 @@
 
 
 void RegisterAllocator::AllocateBlockedReg(LiveRange* current) {
-  UsePosition* register_use = current->NextRegisterPosition(current->Start());
-  if (register_use == NULL) {
+  auto register_use = current->NextRegisterPosition(current->Start());
+  if (register_use == nullptr) {
     // There is no use in the current live range that requires a register.
     // We can just spill it.
     Spill(current);
     return;
   }
 
-
-  LifetimePosition use_pos[DoubleRegister::kMaxNumAllocatableRegisters];
-  LifetimePosition block_pos[DoubleRegister::kMaxNumAllocatableRegisters];
+  LifetimePosition use_pos[RegisterConfiguration::kMaxDoubleRegisters];
+  LifetimePosition block_pos[RegisterConfiguration::kMaxDoubleRegisters];
 
   for (int i = 0; i < num_registers_; i++) {
     use_pos[i] = block_pos[i] = LifetimePosition::MaxPosition();
   }
 
-  for (int i = 0; i < active_live_ranges_.length(); ++i) {
-    LiveRange* range = active_live_ranges_[i];
+  for (auto range : active_live_ranges()) {
     int cur_reg = range->assigned_register();
     if (range->IsFixed() || !range->CanBeSpilled(current->Start())) {
       block_pos[cur_reg] = use_pos[cur_reg] =
           LifetimePosition::FromInstructionIndex(0);
     } else {
-      UsePosition* next_use =
+      auto next_use =
           range->NextUsePositionRegisterIsBeneficial(current->Start());
-      if (next_use == NULL) {
+      if (next_use == nullptr) {
         use_pos[cur_reg] = range->End();
       } else {
         use_pos[cur_reg] = next_use->pos();
@@ -1902,10 +2233,9 @@
     }
   }
 
-  for (int i = 0; i < inactive_live_ranges_.length(); ++i) {
-    LiveRange* range = inactive_live_ranges_.at(i);
+  for (auto range : inactive_live_ranges()) {
     DCHECK(range->End().Value() > current->Start().Value());
-    LifetimePosition next_intersection = range->FirstIntersection(current);
+    auto next_intersection = range->FirstIntersection(current);
     if (!next_intersection.IsValid()) continue;
     int cur_reg = range->assigned_register();
     if (range->IsFixed()) {
@@ -1923,7 +2253,7 @@
     }
   }
 
-  LifetimePosition pos = use_pos[reg];
+  auto pos = use_pos[reg];
 
   if (pos.Value() < register_use->pos().Value()) {
     // All registers are blocked before the first use that requires a register.
@@ -1954,32 +2284,40 @@
 }
 
 
+static const InstructionBlock* GetContainingLoop(
+    const InstructionSequence* sequence, const InstructionBlock* block) {
+  auto index = block->loop_header();
+  if (!index.IsValid()) return nullptr;
+  return sequence->InstructionBlockAt(index);
+}
+
+
 LifetimePosition RegisterAllocator::FindOptimalSpillingPos(
     LiveRange* range, LifetimePosition pos) {
-  BasicBlock* block = GetBlock(pos.InstructionStart());
-  BasicBlock* loop_header =
-      block->IsLoopHeader() ? block : code()->GetContainingLoop(block);
+  auto block = GetInstructionBlock(pos.InstructionStart());
+  auto loop_header =
+      block->IsLoopHeader() ? block : GetContainingLoop(code(), block);
 
-  if (loop_header == NULL) return pos;
+  if (loop_header == nullptr) return pos;
 
-  UsePosition* prev_use = range->PreviousUsePositionRegisterIsBeneficial(pos);
+  auto prev_use = range->PreviousUsePositionRegisterIsBeneficial(pos);
 
-  while (loop_header != NULL) {
+  while (loop_header != nullptr) {
     // We are going to spill live range inside the loop.
     // If possible try to move spilling position backwards to loop header.
     // This will reduce number of memory moves on the back edge.
-    LifetimePosition loop_start = LifetimePosition::FromInstructionIndex(
+    auto loop_start = LifetimePosition::FromInstructionIndex(
         loop_header->first_instruction_index());
 
     if (range->Covers(loop_start)) {
-      if (prev_use == NULL || prev_use->pos().Value() < loop_start.Value()) {
+      if (prev_use == nullptr || prev_use->pos().Value() < loop_start.Value()) {
         // No register beneficial use inside the loop before the pos.
         pos = loop_start;
       }
     }
 
     // Try hoisting out to an outer loop.
-    loop_header = code()->GetContainingLoop(loop_header);
+    loop_header = GetContainingLoop(code(), loop_header);
   }
 
   return pos;
@@ -1989,13 +2327,13 @@
 void RegisterAllocator::SplitAndSpillIntersecting(LiveRange* current) {
   DCHECK(current->HasRegisterAssigned());
   int reg = current->assigned_register();
-  LifetimePosition split_pos = current->Start();
-  for (int i = 0; i < active_live_ranges_.length(); ++i) {
-    LiveRange* range = active_live_ranges_[i];
+  auto split_pos = current->Start();
+  for (size_t i = 0; i < active_live_ranges().size(); ++i) {
+    auto range = active_live_ranges()[i];
     if (range->assigned_register() == reg) {
-      UsePosition* next_pos = range->NextRegisterPosition(current->Start());
-      LifetimePosition spill_pos = FindOptimalSpillingPos(range, split_pos);
-      if (next_pos == NULL) {
+      auto next_pos = range->NextRegisterPosition(current->Start());
+      auto spill_pos = FindOptimalSpillingPos(range, split_pos);
+      if (next_pos == nullptr) {
         SpillAfter(range, spill_pos);
       } else {
         // When spilling between spill_pos and next_pos ensure that the range
@@ -2014,14 +2352,14 @@
     }
   }
 
-  for (int i = 0; i < inactive_live_ranges_.length(); ++i) {
-    LiveRange* range = inactive_live_ranges_[i];
+  for (size_t i = 0; i < inactive_live_ranges().size(); ++i) {
+    auto range = inactive_live_ranges()[i];
     DCHECK(range->End().Value() > current->Start().Value());
     if (range->assigned_register() == reg && !range->IsFixed()) {
       LifetimePosition next_intersection = range->FirstIntersection(current);
       if (next_intersection.IsValid()) {
         UsePosition* next_pos = range->NextRegisterPosition(current->Start());
-        if (next_pos == NULL) {
+        if (next_pos == nullptr) {
           SpillAfter(range, split_pos);
         } else {
           next_intersection = Min(next_intersection, next_pos->pos());
@@ -2055,9 +2393,9 @@
          !InstructionAt(pos.InstructionIndex())->IsControl());
 
   int vreg = GetVirtualRegister();
-  if (!AllocationOk()) return NULL;
-  LiveRange* result = LiveRangeFor(vreg);
-  range->SplitAt(pos, result, zone());
+  if (!AllocationOk()) return nullptr;
+  auto result = LiveRangeFor(vreg);
+  range->SplitAt(pos, result, local_zone());
   return result;
 }
 
@@ -2069,7 +2407,7 @@
   TraceAlloc("Splitting live range %d in position between [%d, %d]\n",
              range->id(), start.Value(), end.Value());
 
-  LifetimePosition split_pos = FindOptimalSplitPos(start, end);
+  auto split_pos = FindOptimalSplitPos(start, end);
   DCHECK(split_pos.Value() >= start.Value());
   return SplitRangeAt(range, split_pos);
 }
@@ -2084,8 +2422,8 @@
   // We have no choice
   if (start_instr == end_instr) return end;
 
-  BasicBlock* start_block = GetBlock(start);
-  BasicBlock* end_block = GetBlock(end);
+  auto start_block = GetInstructionBlock(start);
+  auto end_block = GetInstructionBlock(end);
 
   if (end_block == start_block) {
     // The interval is split in the same basic block. Split at the latest
@@ -2093,13 +2431,13 @@
     return end;
   }
 
-  BasicBlock* block = end_block;
+  auto block = end_block;
   // Find header of outermost loop.
   // TODO(titzer): fix redundancy below.
-  while (code()->GetContainingLoop(block) != NULL &&
-         code()->GetContainingLoop(block)->rpo_number_ >
-             start_block->rpo_number_) {
-    block = code()->GetContainingLoop(block);
+  while (GetContainingLoop(code(), block) != nullptr &&
+         GetContainingLoop(code(), block)->rpo_number().ToInt() >
+             start_block->rpo_number().ToInt()) {
+    block = GetContainingLoop(code(), block);
   }
 
   // We did not find any suitable outer loop. Split at the latest possible
@@ -2112,7 +2450,7 @@
 
 
 void RegisterAllocator::SpillAfter(LiveRange* range, LifetimePosition pos) {
-  LiveRange* second_part = SplitRangeAt(range, pos);
+  auto second_part = SplitRangeAt(range, pos);
   if (!AllocationOk()) return;
   Spill(second_part);
 }
@@ -2129,14 +2467,14 @@
                                           LifetimePosition until,
                                           LifetimePosition end) {
   CHECK(start.Value() < end.Value());
-  LiveRange* second_part = SplitRangeAt(range, start);
+  auto second_part = SplitRangeAt(range, start);
   if (!AllocationOk()) return;
 
   if (second_part->Start().Value() < end.Value()) {
     // The split result intersects with [start, end[.
     // Split it at position between ]start+1, end[, spill the middle part
     // and put the rest to unhandled.
-    LiveRange* third_part = SplitBetween(
+    auto third_part = SplitBetween(
         second_part, Max(second_part->Start().InstructionEnd(), until),
         end.PrevInstruction().InstructionEnd());
     if (!AllocationOk()) return;
@@ -2156,24 +2494,25 @@
 void RegisterAllocator::Spill(LiveRange* range) {
   DCHECK(!range->IsSpilled());
   TraceAlloc("Spilling live range %d\n", range->id());
-  LiveRange* first = range->TopLevel();
-
-  if (!first->HasAllocatedSpillOperand()) {
-    InstructionOperand* op = TryReuseSpillSlot(range);
-    if (op == NULL) {
-      // Allocate a new operand referring to the spill slot.
-      RegisterKind kind = range->Kind();
-      int index = code()->frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS);
-      if (kind == DOUBLE_REGISTERS) {
-        op = DoubleStackSlotOperand::Create(index, zone());
-      } else {
-        DCHECK(kind == GENERAL_REGISTERS);
-        op = StackSlotOperand::Create(index, zone());
+  auto first = range->TopLevel();
+  if (first->HasNoSpillType()) {
+    if (FLAG_turbo_reuse_spill_slots) {
+      AssignSpillRangeToLiveRange(first);
+    } else {
+      auto op = TryReuseSpillSlot(range);
+      if (op == nullptr) {
+        // Allocate a new operand referring to the spill slot.
+        RegisterKind kind = range->Kind();
+        int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS);
+        auto op_kind = kind == DOUBLE_REGISTERS
+                           ? InstructionOperand::DOUBLE_STACK_SLOT
+                           : InstructionOperand::STACK_SLOT;
+        op = new (code_zone()) InstructionOperand(op_kind, index);
       }
+      first->SetSpillOperand(op);
     }
-    first->SetSpillOperand(op);
   }
-  range->MakeSpilled(code_zone());
+  range->MakeSpilled();
 }
 
 
@@ -2184,9 +2523,8 @@
 
 
 void RegisterAllocator::Verify() const {
-  for (int i = 0; i < live_ranges()->length(); ++i) {
-    LiveRange* current = live_ranges()->at(i);
-    if (current != NULL) current->Verify();
+  for (auto current : live_ranges()) {
+    if (current != nullptr) current->Verify();
   }
 }
 
@@ -2205,28 +2543,6 @@
   range->set_assigned_register(reg, code_zone());
 }
 
-
-RegisterAllocatorPhase::RegisterAllocatorPhase(const char* name,
-                                               RegisterAllocator* allocator)
-    : CompilationPhase(name, allocator->code()->linkage()->info()),
-      allocator_(allocator) {
-  if (FLAG_turbo_stats) {
-    allocator_zone_start_allocation_size_ =
-        allocator->zone()->allocation_size();
-  }
-}
-
-
-RegisterAllocatorPhase::~RegisterAllocatorPhase() {
-  if (FLAG_turbo_stats) {
-    unsigned size = allocator_->zone()->allocation_size() -
-                    allocator_zone_start_allocation_size_;
-    isolate()->GetTStatistics()->SaveTiming(name(), base::TimeDelta(), size);
-  }
-#ifdef DEBUG
-  if (allocator_ != NULL) allocator_->Verify();
-#endif
-}
-}
-}
-}  // namespace v8::internal::compiler
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/register-allocator.h b/src/compiler/register-allocator.h
index 881ce37..b17837b 100644
--- a/src/compiler/register-allocator.h
+++ b/src/compiler/register-allocator.h
@@ -5,23 +5,11 @@
 #ifndef V8_REGISTER_ALLOCATOR_H_
 #define V8_REGISTER_ALLOCATOR_H_
 
-#include "src/allocation.h"
 #include "src/compiler/instruction.h"
-#include "src/compiler/node.h"
-#include "src/compiler/schedule.h"
-#include "src/macro-assembler.h"
-#include "src/zone.h"
+#include "src/zone-containers.h"
 
 namespace v8 {
 namespace internal {
-
-// Forward declarations.
-class BitVector;
-class InstructionOperand;
-class UnallocatedOperand;
-class ParallelMove;
-class PointerMap;
-
 namespace compiler {
 
 enum RegisterKind {
@@ -35,7 +23,7 @@
 // each instruction there are exactly two lifetime positions: the beginning and
 // the end of the instruction. Lifetime positions for different instructions are
 // disjoint.
-class LifetimePosition {
+class LifetimePosition FINAL {
  public:
   // Return the lifetime position that corresponds to the beginning of
   // the instruction with the given index.
@@ -114,10 +102,10 @@
 
 
 // Representation of the non-empty interval [start,end[.
-class UseInterval : public ZoneObject {
+class UseInterval FINAL : public ZoneObject {
  public:
   UseInterval(LifetimePosition start, LifetimePosition end)
-      : start_(start), end_(end), next_(NULL) {
+      : start_(start), end_(end), next_(nullptr) {
     DCHECK(start.Value() < end.Value());
   }
 
@@ -147,16 +135,20 @@
   LifetimePosition start_;
   LifetimePosition end_;
   UseInterval* next_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(UseInterval);
 };
 
+
 // Representation of a use position.
-class UsePosition : public ZoneObject {
+class UsePosition FINAL : public ZoneObject {
  public:
   UsePosition(LifetimePosition pos, InstructionOperand* operand,
               InstructionOperand* hint);
 
   InstructionOperand* operand() const { return operand_; }
-  bool HasOperand() const { return operand_ != NULL; }
+  bool HasOperand() const { return operand_ != nullptr; }
 
   InstructionOperand* hint() const { return hint_; }
   bool HasHint() const;
@@ -172,13 +164,18 @@
   InstructionOperand* const hint_;
   LifetimePosition const pos_;
   UsePosition* next_;
-  bool requires_reg_;
-  bool register_beneficial_;
+  bool requires_reg_ : 1;
+  bool register_beneficial_ : 1;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(UsePosition);
 };
 
+class SpillRange;
+
 // Representation of SSA values' live ranges as a collection of (continuous)
 // intervals over the instruction ordering.
-class LiveRange : public ZoneObject {
+class LiveRange FINAL : public ZoneObject {
  public:
   static const int kInvalidAssignment = 0x7fffffff;
 
@@ -187,17 +184,20 @@
   UseInterval* first_interval() const { return first_interval_; }
   UsePosition* first_pos() const { return first_pos_; }
   LiveRange* parent() const { return parent_; }
-  LiveRange* TopLevel() { return (parent_ == NULL) ? this : parent_; }
+  LiveRange* TopLevel() { return (parent_ == nullptr) ? this : parent_; }
+  const LiveRange* TopLevel() const {
+    return (parent_ == nullptr) ? this : parent_;
+  }
   LiveRange* next() const { return next_; }
-  bool IsChild() const { return parent() != NULL; }
+  bool IsChild() const { return parent() != nullptr; }
   int id() const { return id_; }
   bool IsFixed() const { return id_ < 0; }
-  bool IsEmpty() const { return first_interval() == NULL; }
-  InstructionOperand* CreateAssignedOperand(Zone* zone);
+  bool IsEmpty() const { return first_interval() == nullptr; }
+  InstructionOperand* CreateAssignedOperand(Zone* zone) const;
   int assigned_register() const { return assigned_register_; }
   int spill_start_index() const { return spill_start_index_; }
   void set_assigned_register(int reg, Zone* zone);
-  void MakeSpilled(Zone* zone);
+  void MakeSpilled();
   bool is_phi() const { return is_phi_; }
   void set_is_phi(bool is_phi) { is_phi_ = is_phi; }
   bool is_non_loop_phi() const { return is_non_loop_phi_; }
@@ -245,9 +245,9 @@
   }
   InstructionOperand* FirstHint() const {
     UsePosition* pos = first_pos_;
-    while (pos != NULL && !pos->HasHint()) pos = pos->next();
-    if (pos != NULL) return pos->hint();
-    return NULL;
+    while (pos != nullptr && !pos->HasHint()) pos = pos->next();
+    if (pos != nullptr) return pos->hint();
+    return nullptr;
   }
 
   LifetimePosition Start() const {
@@ -260,9 +260,27 @@
     return last_interval_->end();
   }
 
-  bool HasAllocatedSpillOperand() const;
-  InstructionOperand* GetSpillOperand() const { return spill_operand_; }
+  enum class SpillType { kNoSpillType, kSpillOperand, kSpillRange };
+  SpillType spill_type() const { return spill_type_; }
+  InstructionOperand* GetSpillOperand() const {
+    return spill_type_ == SpillType::kSpillOperand ? spill_operand_ : nullptr;
+  }
+  SpillRange* GetSpillRange() const {
+    return spill_type_ == SpillType::kSpillRange ? spill_range_ : nullptr;
+  }
+  bool HasNoSpillType() const { return spill_type_ == SpillType::kNoSpillType; }
+  bool HasSpillOperand() const {
+    return spill_type_ == SpillType::kSpillOperand;
+  }
+  bool HasSpillRange() const { return spill_type_ == SpillType::kSpillRange; }
+
+  void SpillAtDefinition(Zone* zone, int gap_index,
+                         InstructionOperand* operand);
   void SetSpillOperand(InstructionOperand* operand);
+  void SetSpillRange(SpillRange* spill_range);
+  void CommitSpillOperand(InstructionOperand* operand);
+  void CommitSpillsAtDefinition(InstructionSequence* sequence,
+                                InstructionOperand* operand);
 
   void SetSpillStartIndex(int start) {
     spill_start_index_ = Min(start, spill_start_index_);
@@ -289,11 +307,14 @@
 #endif
 
  private:
-  void ConvertOperands(Zone* zone);
+  struct SpillAtDefinitionList;
+
+  void ConvertUsesToOperand(InstructionOperand* op);
   UseInterval* FirstSearchIntervalForPosition(LifetimePosition position) const;
   void AdvanceLastProcessedMarker(UseInterval* to_start_of,
                                   LifetimePosition but_not_past) const;
 
+  // TODO(dcarney): pack this structure better.
   int id_;
   bool spilled_;
   bool is_phi_;
@@ -310,45 +331,96 @@
   UsePosition* last_processed_use_;
   // This is used as a cache, it's invalid outside of BuildLiveRanges.
   InstructionOperand* current_hint_operand_;
-  InstructionOperand* spill_operand_;
   int spill_start_index_;
+  SpillType spill_type_;
+  union {
+    InstructionOperand* spill_operand_;
+    SpillRange* spill_range_;
+  };
+  SpillAtDefinitionList* spills_at_definition_;
 
   friend class RegisterAllocator;  // Assigns to kind_.
+
+  DISALLOW_COPY_AND_ASSIGN(LiveRange);
 };
 
 
-class RegisterAllocator BASE_EMBEDDED {
+class SpillRange FINAL : public ZoneObject {
  public:
-  explicit RegisterAllocator(InstructionSequence* code);
+  SpillRange(LiveRange* range, Zone* zone);
 
-  static void TraceAlloc(const char* msg, ...);
+  UseInterval* interval() const { return use_interval_; }
+  RegisterKind Kind() const { return live_ranges_[0]->Kind(); }
+  bool IsEmpty() const { return live_ranges_.empty(); }
+  bool TryMerge(SpillRange* other);
+  void SetOperand(InstructionOperand* op);
 
-  // Checks whether the value of a given virtual register is a reference.
-  // TODO(titzer): rename this to IsReference.
-  bool HasTaggedValue(int virtual_register) const;
+ private:
+  LifetimePosition End() const { return end_position_; }
+  ZoneVector<LiveRange*>& live_ranges() { return live_ranges_; }
+  bool IsIntersectingWith(SpillRange* other) const;
+  // Merge intervals, making sure the use intervals are sorted
+  void MergeDisjointIntervals(UseInterval* other);
 
-  // Returns the register kind required by the given virtual register.
-  RegisterKind RequiredRegisterKind(int virtual_register) const;
+  ZoneVector<LiveRange*> live_ranges_;
+  UseInterval* use_interval_;
+  LifetimePosition end_position_;
 
-  bool Allocate();
+  DISALLOW_COPY_AND_ASSIGN(SpillRange);
+};
 
-  const ZoneList<LiveRange*>* live_ranges() const { return &live_ranges_; }
-  const Vector<LiveRange*>* fixed_live_ranges() const {
-    return &fixed_live_ranges_;
+
+class RegisterAllocator FINAL : public ZoneObject {
+ public:
+  explicit RegisterAllocator(const RegisterConfiguration* config,
+                             Zone* local_zone, Frame* frame,
+                             InstructionSequence* code,
+                             const char* debug_name = nullptr);
+
+  bool AllocationOk() { return allocation_ok_; }
+
+  const ZoneVector<LiveRange*>& live_ranges() const { return live_ranges_; }
+  const ZoneVector<LiveRange*>& fixed_live_ranges() const {
+    return fixed_live_ranges_;
   }
-  const Vector<LiveRange*>* fixed_double_live_ranges() const {
-    return &fixed_double_live_ranges_;
+  const ZoneVector<LiveRange*>& fixed_double_live_ranges() const {
+    return fixed_double_live_ranges_;
   }
-
-  inline InstructionSequence* code() const { return code_; }
-
+  InstructionSequence* code() const { return code_; }
   // This zone is for datastructures only needed during register allocation.
-  inline Zone* zone() { return &zone_; }
+  Zone* local_zone() const { return local_zone_; }
 
-  // This zone is for InstructionOperands and moves that live beyond register
-  // allocation.
-  inline Zone* code_zone() { return code()->zone(); }
+  // Phase 1 : insert moves to account for fixed register operands.
+  void MeetRegisterConstraints();
 
+  // Phase 2: deconstruct SSA by inserting moves in successors and the headers
+  // of blocks containing phis.
+  void ResolvePhis();
+
+  // Phase 3: compute liveness of all virtual register.
+  void BuildLiveRanges();
+  bool ExistsUseWithoutDefinition();
+
+  // Phase 4: compute register assignments.
+  void AllocateGeneralRegisters();
+  void AllocateDoubleRegisters();
+
+  // Phase 5: reassign spill splots for maximal reuse.
+  void ReuseSpillSlots();
+
+  // Phase 6: commit assignment.
+  void CommitAssignment();
+
+  // Phase 7: compute values for pointer maps.
+  void PopulatePointerMaps();  // TODO(titzer): rename to PopulateReferenceMaps.
+
+  // Phase 8: reconnect split ranges with moves.
+  void ConnectRanges();
+
+  // Phase 9: insert moves to connect ranges across basic blocks.
+  void ResolveControlFlow();
+
+ private:
   int GetVirtualRegister() {
     int vreg = code()->NextVirtualRegister();
     if (vreg >= UnallocatedOperand::kMaxVirtualRegisters) {
@@ -359,40 +431,40 @@
     return vreg;
   }
 
-  bool AllocationOk() { return allocation_ok_; }
+  // Checks whether the value of a given virtual register is a reference.
+  // TODO(titzer): rename this to IsReference.
+  bool HasTaggedValue(int virtual_register) const;
+
+  // Returns the register kind required by the given virtual register.
+  RegisterKind RequiredRegisterKind(int virtual_register) const;
+
+  // This zone is for InstructionOperands and moves that live beyond register
+  // allocation.
+  Zone* code_zone() const { return code()->zone(); }
+
+  BitVector* assigned_registers() { return assigned_registers_; }
+  BitVector* assigned_double_registers() { return assigned_double_registers_; }
 
 #ifdef DEBUG
   void Verify() const;
 #endif
 
-  BitVector* assigned_registers() { return assigned_registers_; }
-  BitVector* assigned_double_registers() { return assigned_double_registers_; }
-
- private:
-  void MeetRegisterConstraints();
-  void ResolvePhis();
-  void BuildLiveRanges();
-  void AllocateGeneralRegisters();
-  void AllocateDoubleRegisters();
-  void ConnectRanges();
-  void ResolveControlFlow();
-  void PopulatePointerMaps();  // TODO(titzer): rename to PopulateReferenceMaps.
   void AllocateRegisters();
-  bool CanEagerlyResolveControlFlow(BasicBlock* block) const;
-  inline bool SafePointsAreInOrder() const;
+  bool CanEagerlyResolveControlFlow(const InstructionBlock* block) const;
+  bool SafePointsAreInOrder() const;
 
   // Liveness analysis support.
-  void InitializeLivenessAnalysis();
-  BitVector* ComputeLiveOut(BasicBlock* block);
-  void AddInitialIntervals(BasicBlock* block, BitVector* live_out);
+  BitVector* ComputeLiveOut(const InstructionBlock* block);
+  void AddInitialIntervals(const InstructionBlock* block, BitVector* live_out);
   bool IsOutputRegisterOf(Instruction* instr, int index);
   bool IsOutputDoubleRegisterOf(Instruction* instr, int index);
-  void ProcessInstructions(BasicBlock* block, BitVector* live);
-  void MeetRegisterConstraints(BasicBlock* block);
+  void ProcessInstructions(const InstructionBlock* block, BitVector* live);
+  void MeetRegisterConstraints(const InstructionBlock* block);
   void MeetConstraintsBetween(Instruction* first, Instruction* second,
                               int gap_index);
-  void MeetRegisterConstraintsForLastInstructionInBlock(BasicBlock* block);
-  void ResolvePhis(BasicBlock* block);
+  void MeetRegisterConstraintsForLastInstructionInBlock(
+      const InstructionBlock* block);
+  void ResolvePhis(const InstructionBlock* block);
 
   // Helper methods for building intervals.
   InstructionOperand* AllocateFixed(UnallocatedOperand* operand, int pos,
@@ -402,8 +474,8 @@
               InstructionOperand* hint);
   void Use(LifetimePosition block_start, LifetimePosition position,
            InstructionOperand* operand, InstructionOperand* hint);
-  void AddConstraintsGapMove(int index, InstructionOperand* from,
-                             InstructionOperand* to);
+  void AddGapMove(int index, GapInstruction::InnerPosition position,
+                  InstructionOperand* from, InstructionOperand* to);
 
   // Helper methods for updating the life range lists.
   void AddToActive(LiveRange* range);
@@ -416,12 +488,14 @@
   void ActiveToInactive(LiveRange* range);
   void InactiveToHandled(LiveRange* range);
   void InactiveToActive(LiveRange* range);
-  void FreeSpillSlot(LiveRange* range);
-  InstructionOperand* TryReuseSpillSlot(LiveRange* range);
 
   // Helper methods for allocating registers.
+  bool TryReuseSpillForPhi(LiveRange* range);
   bool TryAllocateFreeReg(LiveRange* range);
   void AllocateBlockedReg(LiveRange* range);
+  SpillRange* AssignSpillRangeToLiveRange(LiveRange* range);
+  void FreeSpillSlot(LiveRange* range);
+  InstructionOperand* TryReuseSpillSlot(LiveRange* range);
 
   // Live range splitting helpers.
 
@@ -466,52 +540,84 @@
   bool IsBlockBoundary(LifetimePosition pos);
 
   // Helper methods for resolving control flow.
-  void ResolveControlFlow(LiveRange* range, BasicBlock* block,
-                          BasicBlock* pred);
+  void ResolveControlFlow(const InstructionBlock* block,
+                          InstructionOperand* cur_op,
+                          const InstructionBlock* pred,
+                          InstructionOperand* pred_op);
 
-  inline void SetLiveRangeAssignedRegister(LiveRange* range, int reg);
+  void SetLiveRangeAssignedRegister(LiveRange* range, int reg);
 
   // Return parallel move that should be used to connect ranges split at the
   // given position.
   ParallelMove* GetConnectingParallelMove(LifetimePosition pos);
 
   // Return the block which contains give lifetime position.
-  BasicBlock* GetBlock(LifetimePosition pos);
+  const InstructionBlock* GetInstructionBlock(LifetimePosition pos);
 
   // Helper methods for the fixed registers.
   int RegisterCount() const;
   static int FixedLiveRangeID(int index) { return -index - 1; }
-  static int FixedDoubleLiveRangeID(int index);
+  int FixedDoubleLiveRangeID(int index);
   LiveRange* FixedLiveRangeFor(int index);
   LiveRange* FixedDoubleLiveRangeFor(int index);
   LiveRange* LiveRangeFor(int index);
-  GapInstruction* GetLastGap(BasicBlock* block);
+  GapInstruction* GetLastGap(const InstructionBlock* block);
 
   const char* RegisterName(int allocation_index);
 
-  inline Instruction* InstructionAt(int index) {
-    return code()->InstructionAt(index);
-  }
+  Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
 
-  Zone zone_;
-  InstructionSequence* code_;
+  Frame* frame() const { return frame_; }
+  const char* debug_name() const { return debug_name_; }
+  const RegisterConfiguration* config() const { return config_; }
+  ZoneVector<LiveRange*>& live_ranges() { return live_ranges_; }
+  ZoneVector<LiveRange*>& fixed_live_ranges() { return fixed_live_ranges_; }
+  ZoneVector<LiveRange*>& fixed_double_live_ranges() {
+    return fixed_double_live_ranges_;
+  }
+  ZoneVector<LiveRange*>& unhandled_live_ranges() {
+    return unhandled_live_ranges_;
+  }
+  ZoneVector<LiveRange*>& active_live_ranges() { return active_live_ranges_; }
+  ZoneVector<LiveRange*>& inactive_live_ranges() {
+    return inactive_live_ranges_;
+  }
+  ZoneVector<LiveRange*>& reusable_slots() { return reusable_slots_; }
+  ZoneVector<SpillRange*>& spill_ranges() { return spill_ranges_; }
+
+  struct PhiMapValue {
+    PhiMapValue(PhiInstruction* phi, const InstructionBlock* block)
+        : phi(phi), block(block) {}
+    PhiInstruction* const phi;
+    const InstructionBlock* const block;
+  };
+  typedef std::map<int, PhiMapValue, std::less<int>,
+                   zone_allocator<std::pair<int, PhiMapValue>>> PhiMap;
+
+  Zone* const local_zone_;
+  Frame* const frame_;
+  InstructionSequence* const code_;
+  const char* const debug_name_;
+
+  const RegisterConfiguration* config_;
+
+  PhiMap phi_map_;
 
   // During liveness analysis keep a mapping from block id to live_in sets
   // for blocks already analyzed.
-  ZoneList<BitVector*> live_in_sets_;
+  ZoneVector<BitVector*> live_in_sets_;
 
   // Liveness analysis results.
-  ZoneList<LiveRange*> live_ranges_;
+  ZoneVector<LiveRange*> live_ranges_;
 
   // Lists of live ranges
-  EmbeddedVector<LiveRange*, Register::kMaxNumAllocatableRegisters>
-      fixed_live_ranges_;
-  EmbeddedVector<LiveRange*, DoubleRegister::kMaxNumAllocatableRegisters>
-      fixed_double_live_ranges_;
-  ZoneList<LiveRange*> unhandled_live_ranges_;
-  ZoneList<LiveRange*> active_live_ranges_;
-  ZoneList<LiveRange*> inactive_live_ranges_;
-  ZoneList<LiveRange*> reusable_slots_;
+  ZoneVector<LiveRange*> fixed_live_ranges_;
+  ZoneVector<LiveRange*> fixed_double_live_ranges_;
+  ZoneVector<LiveRange*> unhandled_live_ranges_;
+  ZoneVector<LiveRange*> active_live_ranges_;
+  ZoneVector<LiveRange*> inactive_live_ranges_;
+  ZoneVector<LiveRange*> reusable_slots_;
+  ZoneVector<SpillRange*> spill_ranges_;
 
   RegisterKind mode_;
   int num_registers_;
@@ -529,20 +635,8 @@
   DISALLOW_COPY_AND_ASSIGN(RegisterAllocator);
 };
 
-
-class RegisterAllocatorPhase : public CompilationPhase {
- public:
-  RegisterAllocatorPhase(const char* name, RegisterAllocator* allocator);
-  ~RegisterAllocatorPhase();
-
- private:
-  RegisterAllocator* allocator_;
-  unsigned allocator_zone_start_allocation_size_;
-
-  DISALLOW_COPY_AND_ASSIGN(RegisterAllocatorPhase);
-};
-}
-}
-}  // namespace v8::internal::compiler
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_REGISTER_ALLOCATOR_H_
diff --git a/src/compiler/register-configuration.cc b/src/compiler/register-configuration.cc
new file mode 100644
index 0000000..e7d8bbd
--- /dev/null
+++ b/src/compiler/register-configuration.cc
@@ -0,0 +1,68 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/register-configuration.h"
+#include "src/macro-assembler.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+STATIC_ASSERT(RegisterConfiguration::kMaxGeneralRegisters >=
+              Register::kNumRegisters);
+STATIC_ASSERT(RegisterConfiguration::kMaxDoubleRegisters >=
+              DoubleRegister::kMaxNumRegisters);
+
+class ArchDefaultRegisterConfiguration : public RegisterConfiguration {
+ public:
+  ArchDefaultRegisterConfiguration()
+      : RegisterConfiguration(Register::kMaxNumAllocatableRegisters,
+                              DoubleRegister::kMaxNumAllocatableRegisters,
+                              DoubleRegister::NumAllocatableAliasedRegisters(),
+                              general_register_name_table_,
+                              double_register_name_table_) {
+    DCHECK_EQ(Register::kMaxNumAllocatableRegisters,
+              Register::NumAllocatableRegisters());
+    for (int i = 0; i < Register::kMaxNumAllocatableRegisters; ++i) {
+      general_register_name_table_[i] = Register::AllocationIndexToString(i);
+    }
+    for (int i = 0; i < DoubleRegister::kMaxNumAllocatableRegisters; ++i) {
+      double_register_name_table_[i] =
+          DoubleRegister::AllocationIndexToString(i);
+    }
+  }
+
+  const char*
+      general_register_name_table_[Register::kMaxNumAllocatableRegisters];
+  const char*
+      double_register_name_table_[DoubleRegister::kMaxNumAllocatableRegisters];
+};
+
+
+static base::LazyInstance<ArchDefaultRegisterConfiguration>::type
+    kDefaultRegisterConfiguration = LAZY_INSTANCE_INITIALIZER;
+
+}  // namepace
+
+
+const RegisterConfiguration* RegisterConfiguration::ArchDefault() {
+  return &kDefaultRegisterConfiguration.Get();
+}
+
+RegisterConfiguration::RegisterConfiguration(
+    int num_general_registers, int num_double_registers,
+    int num_aliased_double_registers, const char* const* general_register_names,
+    const char* const* double_register_names)
+    : num_general_registers_(num_general_registers),
+      num_double_registers_(num_double_registers),
+      num_aliased_double_registers_(num_aliased_double_registers),
+      general_register_names_(general_register_names),
+      double_register_names_(double_register_names) {}
+
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/register-configuration.h b/src/compiler/register-configuration.h
new file mode 100644
index 0000000..8178ba2
--- /dev/null
+++ b/src/compiler/register-configuration.h
@@ -0,0 +1,56 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_REGISTER_CONFIGURATION_H_
+#define V8_COMPILER_REGISTER_CONFIGURATION_H_
+
+#include "src/v8.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// An architecture independent representation of the sets of registers available
+// for instruction creation.
+class RegisterConfiguration {
+ public:
+  // Architecture independent maxes.
+  static const int kMaxGeneralRegisters = 32;
+  static const int kMaxDoubleRegisters = 32;
+
+  static const RegisterConfiguration* ArchDefault();
+
+  RegisterConfiguration(int num_general_registers, int num_double_registers,
+                        int num_aliased_double_registers,
+                        const char* const* general_register_name,
+                        const char* const* double_register_name);
+
+  int num_general_registers() const { return num_general_registers_; }
+  int num_double_registers() const { return num_double_registers_; }
+  int num_aliased_double_registers() const {
+    return num_aliased_double_registers_;
+  }
+
+  const char* general_register_name(int offset) const {
+    DCHECK(offset >= 0 && offset < kMaxGeneralRegisters);
+    return general_register_names_[offset];
+  }
+  const char* double_register_name(int offset) const {
+    DCHECK(offset >= 0 && offset < kMaxDoubleRegisters);
+    return double_register_names_[offset];
+  }
+
+ private:
+  const int num_general_registers_;
+  const int num_double_registers_;
+  const int num_aliased_double_registers_;
+  const char* const* general_register_names_;
+  const char* const* double_register_names_;
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_REGISTER_CONFIGURATION_H_
diff --git a/src/compiler/representation-change.h b/src/compiler/representation-change.h
index aaa248e..8720afd 100644
--- a/src/compiler/representation-change.h
+++ b/src/compiler/representation-change.h
@@ -5,6 +5,8 @@
 #ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_
 #define V8_COMPILER_REPRESENTATION_CHANGE_H_
 
+#include <sstream>
+
 #include "src/base/bits.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/machine-operator.h"
@@ -51,10 +53,10 @@
     }
     if (use_type & kRepTagged) {
       return GetTaggedRepresentationFor(node, output_type);
+    } else if (use_type & kRepFloat32) {
+      return GetFloat32RepresentationFor(node, output_type);
     } else if (use_type & kRepFloat64) {
       return GetFloat64RepresentationFor(node, output_type);
-    } else if (use_type & kRepFloat32) {
-      return TypeError(node, output_type, use_type);  // TODO(titzer): handle
     } else if (use_type & kRepBit) {
       return GetBitRepresentationFor(node, output_type);
     } else if (use_type & rWord) {
@@ -88,6 +90,8 @@
         }
       case IrOpcode::kFloat64Constant:
         return jsgraph()->Constant(OpParameter<double>(node));
+      case IrOpcode::kFloat32Constant:
+        return jsgraph()->Constant(OpParameter<float>(node));
       default:
         break;
     }
@@ -103,6 +107,9 @@
       } else {
         return TypeError(node, output_type, kRepTagged);
       }
+    } else if (output_type & kRepFloat32) {  // float32 -> float64 -> tagged
+      node = InsertChangeFloat32ToFloat64(node);
+      op = simplified()->ChangeFloat64ToTagged();
     } else if (output_type & kRepFloat64) {
       op = simplified()->ChangeFloat64ToTagged();
     } else {
@@ -111,6 +118,52 @@
     return jsgraph()->graph()->NewNode(op, node);
   }
 
+  Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type) {
+    // Eagerly fold representation changes for constants.
+    switch (node->opcode()) {
+      case IrOpcode::kFloat64Constant:
+      case IrOpcode::kNumberConstant:
+        return jsgraph()->Float32Constant(
+            DoubleToFloat32(OpParameter<double>(node)));
+      case IrOpcode::kInt32Constant:
+        if (output_type & kTypeUint32) {
+          uint32_t value = OpParameter<uint32_t>(node);
+          return jsgraph()->Float32Constant(static_cast<float>(value));
+        } else {
+          int32_t value = OpParameter<int32_t>(node);
+          return jsgraph()->Float32Constant(static_cast<float>(value));
+        }
+      case IrOpcode::kFloat32Constant:
+        return node;  // No change necessary.
+      default:
+        break;
+    }
+    // Select the correct X -> Float32 operator.
+    const Operator* op;
+    if (output_type & kRepBit) {
+      return TypeError(node, output_type, kRepFloat32);
+    } else if (output_type & rWord) {
+      if (output_type & kTypeUint32) {
+        op = machine()->ChangeUint32ToFloat64();
+      } else {
+        op = machine()->ChangeInt32ToFloat64();
+      }
+      // int32 -> float64 -> float32
+      node = jsgraph()->graph()->NewNode(op, node);
+      op = machine()->TruncateFloat64ToFloat32();
+    } else if (output_type & kRepTagged) {
+      op = simplified()
+               ->ChangeTaggedToFloat64();  // tagged -> float64 -> float32
+      node = jsgraph()->graph()->NewNode(op, node);
+      op = machine()->TruncateFloat64ToFloat32();
+    } else if (output_type & kRepFloat64) {
+      op = machine()->TruncateFloat64ToFloat32();
+    } else {
+      return TypeError(node, output_type, kRepFloat32);
+    }
+    return jsgraph()->graph()->NewNode(op, node);
+  }
+
   Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type) {
     // Eagerly fold representation changes for constants.
     switch (node->opcode()) {
@@ -126,6 +179,8 @@
         }
       case IrOpcode::kFloat64Constant:
         return node;  // No change necessary.
+      case IrOpcode::kFloat32Constant:
+        return jsgraph()->Float64Constant(OpParameter<float>(node));
       default:
         break;
     }
@@ -141,31 +196,68 @@
       }
     } else if (output_type & kRepTagged) {
       op = simplified()->ChangeTaggedToFloat64();
+    } else if (output_type & kRepFloat32) {
+      op = machine()->ChangeFloat32ToFloat64();
     } else {
       return TypeError(node, output_type, kRepFloat64);
     }
     return jsgraph()->graph()->NewNode(op, node);
   }
 
+  Node* MakeInt32Constant(double value) {
+    if (value < 0) {
+      DCHECK(IsInt32Double(value));
+      int32_t iv = static_cast<int32_t>(value);
+      return jsgraph()->Int32Constant(iv);
+    } else {
+      DCHECK(IsUint32Double(value));
+      int32_t iv = static_cast<int32_t>(static_cast<uint32_t>(value));
+      return jsgraph()->Int32Constant(iv);
+    }
+  }
+
+  Node* GetTruncatedWord32For(Node* node, MachineTypeUnion output_type) {
+    // Eagerly fold truncations for constants.
+    switch (node->opcode()) {
+      case IrOpcode::kInt32Constant:
+        return node;  // No change necessary.
+      case IrOpcode::kFloat32Constant:
+        return jsgraph()->Int32Constant(
+            DoubleToInt32(OpParameter<float>(node)));
+      case IrOpcode::kNumberConstant:
+      case IrOpcode::kFloat64Constant:
+        return jsgraph()->Int32Constant(
+            DoubleToInt32(OpParameter<double>(node)));
+      default:
+        break;
+    }
+    // Select the correct X -> Word32 truncation operator.
+    const Operator* op = NULL;
+    if (output_type & kRepFloat64) {
+      op = machine()->TruncateFloat64ToInt32();
+    } else if (output_type & kRepFloat32) {
+      node = InsertChangeFloat32ToFloat64(node);
+      op = machine()->TruncateFloat64ToInt32();
+    } else if (output_type & kRepTagged) {
+      node = InsertChangeTaggedToFloat64(node);
+      op = machine()->TruncateFloat64ToInt32();
+    } else {
+      return TypeError(node, output_type, kRepWord32);
+    }
+    return jsgraph()->graph()->NewNode(op, node);
+  }
+
   Node* GetWord32RepresentationFor(Node* node, MachineTypeUnion output_type,
                                    bool use_unsigned) {
     // Eagerly fold representation changes for constants.
     switch (node->opcode()) {
       case IrOpcode::kInt32Constant:
         return node;  // No change necessary.
+      case IrOpcode::kFloat32Constant:
+        return MakeInt32Constant(OpParameter<float>(node));
       case IrOpcode::kNumberConstant:
-      case IrOpcode::kFloat64Constant: {
-        double value = OpParameter<double>(node);
-        if (value < 0) {
-          DCHECK(IsInt32Double(value));
-          int32_t iv = static_cast<int32_t>(value);
-          return jsgraph()->Int32Constant(iv);
-        } else {
-          DCHECK(IsUint32Double(value));
-          int32_t iv = static_cast<int32_t>(static_cast<uint32_t>(value));
-          return jsgraph()->Int32Constant(iv);
-        }
-      }
+      case IrOpcode::kFloat64Constant:
+        return MakeInt32Constant(OpParameter<double>(node));
       default:
         break;
     }
@@ -177,6 +269,13 @@
       } else {
         op = machine()->ChangeFloat64ToInt32();
       }
+    } else if (output_type & kRepFloat32) {
+      node = InsertChangeFloat32ToFloat64(node);  // float32 -> float64 -> int32
+      if (output_type & kTypeUint32 || use_unsigned) {
+        op = machine()->ChangeFloat64ToUint32();
+      } else {
+        op = machine()->ChangeFloat64ToInt32();
+      }
     } else if (output_type & kRepTagged) {
       if (output_type & kTypeUint32 || use_unsigned) {
         op = simplified()->ChangeTaggedToUint32();
@@ -195,7 +294,14 @@
       case IrOpcode::kInt32Constant: {
         int32_t value = OpParameter<int32_t>(node);
         if (value == 0 || value == 1) return node;
-        return jsgraph()->OneConstant();  // value != 0
+        return jsgraph()->Int32Constant(1);  // value != 0
+      }
+      case IrOpcode::kNumberConstant: {
+        double value = OpParameter<double>(node);
+        if (std::isnan(value) || value == 0.0) {
+          return jsgraph()->Int32Constant(0);
+        }
+        return jsgraph()->Int32Constant(1);
       }
       case IrOpcode::kHeapConstant: {
         Handle<Object> handle = OpParameter<Unique<Object> >(node).handle();
@@ -262,9 +368,9 @@
       case IrOpcode::kNumberMultiply:
         return machine()->Int32Mul();
       case IrOpcode::kNumberDivide:
-        return machine()->Int32UDiv();
+        return machine()->Uint32Div();
       case IrOpcode::kNumberModulus:
-        return machine()->Int32UMod();
+        return machine()->Uint32Mod();
       case IrOpcode::kNumberEqual:
         return machine()->Word32Equal();
       case IrOpcode::kNumberLessThan:
@@ -333,28 +439,39 @@
                   MachineTypeUnion use) {
     type_error_ = true;
     if (!testing_type_errors_) {
-      OStringStream out_str;
+      std::ostringstream out_str;
       out_str << static_cast<MachineType>(output_type);
 
-      OStringStream use_str;
+      std::ostringstream use_str;
       use_str << static_cast<MachineType>(use);
 
       V8_Fatal(__FILE__, __LINE__,
                "RepresentationChangerError: node #%d:%s of "
                "%s cannot be changed to %s",
-               node->id(), node->op()->mnemonic(), out_str.c_str(),
-               use_str.c_str());
+               node->id(), node->op()->mnemonic(), out_str.str().c_str(),
+               use_str.str().c_str());
     }
     return node;
   }
 
+  Node* InsertChangeFloat32ToFloat64(Node* node) {
+    return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(),
+                                       node);
+  }
+
+  Node* InsertChangeTaggedToFloat64(Node* node) {
+    return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
+                                       node);
+  }
+
   JSGraph* jsgraph() { return jsgraph_; }
   Isolate* isolate() { return isolate_; }
   SimplifiedOperatorBuilder* simplified() { return simplified_; }
   MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
 };
-}
-}
-}  // namespace v8::internal::compiler
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_REPRESENTATION_CHANGE_H_
diff --git a/src/compiler/schedule.cc b/src/compiler/schedule.cc
index a3b5ed3..30bfbc8 100644
--- a/src/compiler/schedule.cc
+++ b/src/compiler/schedule.cc
@@ -12,17 +12,86 @@
 namespace internal {
 namespace compiler {
 
-OStream& operator<<(OStream& os, const BasicBlockData::Control& c) {
+BasicBlock::BasicBlock(Zone* zone, Id id)
+    : loop_number_(-1),
+      rpo_number_(-1),
+      deferred_(false),
+      dominator_depth_(-1),
+      dominator_(NULL),
+      rpo_next_(NULL),
+      loop_header_(NULL),
+      loop_end_(NULL),
+      loop_depth_(0),
+      control_(kNone),
+      control_input_(NULL),
+      nodes_(zone),
+      successors_(zone),
+      predecessors_(zone),
+      id_(id) {}
+
+
+bool BasicBlock::LoopContains(BasicBlock* block) const {
+  // RPO numbers must be initialized.
+  DCHECK(rpo_number_ >= 0);
+  DCHECK(block->rpo_number_ >= 0);
+  if (loop_end_ == NULL) return false;  // This is not a loop.
+  return block->rpo_number_ >= rpo_number_ &&
+         block->rpo_number_ < loop_end_->rpo_number_;
+}
+
+
+void BasicBlock::AddSuccessor(BasicBlock* successor) {
+  successors_.push_back(successor);
+}
+
+
+void BasicBlock::AddPredecessor(BasicBlock* predecessor) {
+  predecessors_.push_back(predecessor);
+}
+
+
+void BasicBlock::AddNode(Node* node) { nodes_.push_back(node); }
+
+
+void BasicBlock::set_control(Control control) {
+  control_ = control;
+}
+
+
+void BasicBlock::set_control_input(Node* control_input) {
+  control_input_ = control_input;
+}
+
+
+void BasicBlock::set_loop_depth(int32_t loop_depth) {
+  loop_depth_ = loop_depth;
+}
+
+
+void BasicBlock::set_rpo_number(int32_t rpo_number) {
+  rpo_number_ = rpo_number;
+}
+
+
+void BasicBlock::set_loop_end(BasicBlock* loop_end) { loop_end_ = loop_end; }
+
+
+void BasicBlock::set_loop_header(BasicBlock* loop_header) {
+  loop_header_ = loop_header;
+}
+
+
+std::ostream& operator<<(std::ostream& os, const BasicBlock::Control& c) {
   switch (c) {
-    case BasicBlockData::kNone:
+    case BasicBlock::kNone:
       return os << "none";
-    case BasicBlockData::kGoto:
+    case BasicBlock::kGoto:
       return os << "goto";
-    case BasicBlockData::kBranch:
+    case BasicBlock::kBranch:
       return os << "branch";
-    case BasicBlockData::kReturn:
+    case BasicBlock::kReturn:
       return os << "return";
-    case BasicBlockData::kThrow:
+    case BasicBlock::kThrow:
       return os << "throw";
   }
   UNREACHABLE();
@@ -30,17 +99,181 @@
 }
 
 
-OStream& operator<<(OStream& os, const Schedule& s) {
+std::ostream& operator<<(std::ostream& os, const BasicBlock::Id& id) {
+  return os << id.ToSize();
+}
+
+
+std::ostream& operator<<(std::ostream& os, const BasicBlock::RpoNumber& rpo) {
+  return os << rpo.ToSize();
+}
+
+
+Schedule::Schedule(Zone* zone, size_t node_count_hint)
+    : zone_(zone),
+      all_blocks_(zone),
+      nodeid_to_block_(zone),
+      rpo_order_(zone),
+      start_(NewBasicBlock()),
+      end_(NewBasicBlock()) {
+  nodeid_to_block_.reserve(node_count_hint);
+}
+
+
+BasicBlock* Schedule::block(Node* node) const {
+  if (node->id() < static_cast<NodeId>(nodeid_to_block_.size())) {
+    return nodeid_to_block_[node->id()];
+  }
+  return NULL;
+}
+
+
+bool Schedule::IsScheduled(Node* node) {
+  int length = static_cast<int>(nodeid_to_block_.size());
+  if (node->id() >= length) return false;
+  return nodeid_to_block_[node->id()] != NULL;
+}
+
+
+BasicBlock* Schedule::GetBlockById(BasicBlock::Id block_id) {
+  DCHECK(block_id.ToSize() < all_blocks_.size());
+  return all_blocks_[block_id.ToSize()];
+}
+
+
+bool Schedule::SameBasicBlock(Node* a, Node* b) const {
+  BasicBlock* block = this->block(a);
+  return block != NULL && block == this->block(b);
+}
+
+
+BasicBlock* Schedule::NewBasicBlock() {
+  BasicBlock* block = new (zone_)
+      BasicBlock(zone_, BasicBlock::Id::FromSize(all_blocks_.size()));
+  all_blocks_.push_back(block);
+  return block;
+}
+
+
+void Schedule::PlanNode(BasicBlock* block, Node* node) {
+  if (FLAG_trace_turbo_scheduler) {
+    OFStream os(stdout);
+    os << "Planning #" << node->id() << ":" << node->op()->mnemonic()
+       << " for future add to B" << block->id() << "\n";
+  }
+  DCHECK(this->block(node) == NULL);
+  SetBlockForNode(block, node);
+}
+
+
+void Schedule::AddNode(BasicBlock* block, Node* node) {
+  if (FLAG_trace_turbo_scheduler) {
+    OFStream os(stdout);
+    os << "Adding #" << node->id() << ":" << node->op()->mnemonic() << " to B"
+       << block->id() << "\n";
+  }
+  DCHECK(this->block(node) == NULL || this->block(node) == block);
+  block->AddNode(node);
+  SetBlockForNode(block, node);
+}
+
+
+void Schedule::AddGoto(BasicBlock* block, BasicBlock* succ) {
+  DCHECK(block->control() == BasicBlock::kNone);
+  block->set_control(BasicBlock::kGoto);
+  AddSuccessor(block, succ);
+}
+
+
+void Schedule::AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock,
+                         BasicBlock* fblock) {
+  DCHECK(block->control() == BasicBlock::kNone);
+  DCHECK(branch->opcode() == IrOpcode::kBranch);
+  block->set_control(BasicBlock::kBranch);
+  AddSuccessor(block, tblock);
+  AddSuccessor(block, fblock);
+  SetControlInput(block, branch);
+}
+
+
+void Schedule::AddReturn(BasicBlock* block, Node* input) {
+  DCHECK(block->control() == BasicBlock::kNone);
+  block->set_control(BasicBlock::kReturn);
+  SetControlInput(block, input);
+  if (block != end()) AddSuccessor(block, end());
+}
+
+
+void Schedule::AddThrow(BasicBlock* block, Node* input) {
+  DCHECK(block->control() == BasicBlock::kNone);
+  block->set_control(BasicBlock::kThrow);
+  SetControlInput(block, input);
+  if (block != end()) AddSuccessor(block, end());
+}
+
+
+void Schedule::InsertBranch(BasicBlock* block, BasicBlock* end, Node* branch,
+                            BasicBlock* tblock, BasicBlock* fblock) {
+  DCHECK(block->control() != BasicBlock::kNone);
+  DCHECK(end->control() == BasicBlock::kNone);
+  end->set_control(block->control());
+  block->set_control(BasicBlock::kBranch);
+  MoveSuccessors(block, end);
+  AddSuccessor(block, tblock);
+  AddSuccessor(block, fblock);
+  if (block->control_input() != NULL) {
+    SetControlInput(end, block->control_input());
+  }
+  SetControlInput(block, branch);
+}
+
+
+void Schedule::AddSuccessor(BasicBlock* block, BasicBlock* succ) {
+  block->AddSuccessor(succ);
+  succ->AddPredecessor(block);
+}
+
+
+void Schedule::MoveSuccessors(BasicBlock* from, BasicBlock* to) {
+  for (BasicBlock::Predecessors::iterator i = from->successors_begin();
+       i != from->successors_end(); ++i) {
+    BasicBlock* succ = *i;
+    to->AddSuccessor(succ);
+    for (BasicBlock::Predecessors::iterator j = succ->predecessors_begin();
+         j != succ->predecessors_end(); ++j) {
+      if (*j == from) *j = to;
+    }
+  }
+  from->ClearSuccessors();
+}
+
+
+void Schedule::SetControlInput(BasicBlock* block, Node* node) {
+  block->set_control_input(node);
+  SetBlockForNode(block, node);
+}
+
+
+void Schedule::SetBlockForNode(BasicBlock* block, Node* node) {
+  int length = static_cast<int>(nodeid_to_block_.size());
+  if (node->id() >= length) {
+    nodeid_to_block_.resize(node->id() + 1);
+  }
+  nodeid_to_block_[node->id()] = block;
+}
+
+
+std::ostream& operator<<(std::ostream& os, const Schedule& s) {
   // TODO(svenpanne) Const-correct the RPO stuff/iterators.
   BasicBlockVector* rpo = const_cast<Schedule*>(&s)->rpo_order();
   for (BasicBlockVectorIter i = rpo->begin(); i != rpo->end(); ++i) {
     BasicBlock* block = *i;
     os << "--- BLOCK B" << block->id();
+    if (block->deferred()) os << " (deferred)";
     if (block->PredecessorCount() != 0) os << " <- ";
-    BasicBlock::Predecessors predecessors = block->predecessors();
     bool comma = false;
-    for (BasicBlock::Predecessors::iterator j = predecessors.begin();
-         j != predecessors.end(); ++j) {
+    for (BasicBlock::Predecessors::iterator j = block->predecessors_begin();
+         j != block->predecessors_end(); ++j) {
       if (comma) os << ", ";
       comma = true;
       os << "B" << (*j)->id();
@@ -50,7 +283,7 @@
          ++j) {
       Node* node = *j;
       os << "  " << *node;
-      if (!NodeProperties::IsControl(node)) {
+      if (NodeProperties::IsTyped(node)) {
         Bounds bounds = NodeProperties::GetBounds(node);
         os << " : ";
         bounds.lower->PrintTo(os);
@@ -61,19 +294,18 @@
       }
       os << "\n";
     }
-    BasicBlock::Control control = block->control_;
+    BasicBlock::Control control = block->control();
     if (control != BasicBlock::kNone) {
       os << "  ";
-      if (block->control_input_ != NULL) {
-        os << *block->control_input_;
+      if (block->control_input() != NULL) {
+        os << *block->control_input();
       } else {
         os << "Goto";
       }
       os << " -> ";
-      BasicBlock::Successors successors = block->successors();
       comma = false;
-      for (BasicBlock::Successors::iterator j = successors.begin();
-           j != successors.end(); ++j) {
+      for (BasicBlock::Successors::iterator j = block->successors_begin();
+           j != block->successors_end(); ++j) {
         if (comma) os << ", ";
         comma = true;
         os << "B" << (*j)->id();
@@ -83,6 +315,7 @@
   }
   return os;
 }
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
diff --git a/src/compiler/schedule.h b/src/compiler/schedule.h
index 070691e..0bba689 100644
--- a/src/compiler/schedule.h
+++ b/src/compiler/schedule.h
@@ -5,14 +5,11 @@
 #ifndef V8_COMPILER_SCHEDULE_H_
 #define V8_COMPILER_SCHEDULE_H_
 
+#include <iosfwd>
 #include <vector>
 
 #include "src/v8.h"
 
-#include "src/compiler/generic-algorithm.h"
-#include "src/compiler/generic-graph.h"
-#include "src/compiler/generic-node.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/node.h"
 #include "src/compiler/opcodes.h"
 #include "src/zone.h"
@@ -22,11 +19,15 @@
 namespace compiler {
 
 class BasicBlock;
+class BasicBlockInstrumentor;
 class Graph;
 class ConstructScheduleData;
 class CodeGenerator;  // Because of a namespace bug in clang.
 
-class BasicBlockData {
+// A basic block contains an ordered list of nodes and ends with a control
+// node. Note that if a basic block has phis, then all phis must appear as the
+// first nodes in the block.
+class BasicBlock FINAL : public ZoneObject {
  public:
   // Possible control nodes that can end a block.
   enum Control {
@@ -37,94 +38,83 @@
     kThrow    // Throw an exception.
   };
 
-  int32_t rpo_number_;       // special RPO number of the block.
-  BasicBlock* dominator_;    // Immediate dominator of the block.
-  BasicBlock* loop_header_;  // Pointer to dominating loop header basic block,
-                             // NULL if none. For loop headers, this points to
-                             // enclosing loop header.
-  int32_t loop_depth_;       // loop nesting, 0 is top-level
-  int32_t loop_end_;         // end of the loop, if this block is a loop header.
-  int32_t code_start_;       // start index of arch-specific code.
-  int32_t code_end_;         // end index of arch-specific code.
-  bool deferred_;            // {true} if this block is considered the slow
-                             // path.
-  Control control_;          // Control at the end of the block.
-  Node* control_input_;      // Input value for control.
-  NodeVector nodes_;         // nodes of this block in forward order.
+  class Id {
+   public:
+    int ToInt() const { return static_cast<int>(index_); }
+    size_t ToSize() const { return index_; }
+    static Id FromSize(size_t index) { return Id(index); }
+    static Id FromInt(int index) { return Id(static_cast<size_t>(index)); }
 
-  explicit BasicBlockData(Zone* zone)
-      : rpo_number_(-1),
-        dominator_(NULL),
-        loop_header_(NULL),
-        loop_depth_(0),
-        loop_end_(-1),
-        code_start_(-1),
-        code_end_(-1),
-        deferred_(false),
-        control_(kNone),
-        control_input_(NULL),
-        nodes_(zone) {}
+   private:
+    explicit Id(size_t index) : index_(index) {}
+    size_t index_;
+  };
 
-  inline bool IsLoopHeader() const { return loop_end_ >= 0; }
-  inline bool LoopContains(BasicBlockData* block) const {
-    // RPO numbers must be initialized.
-    DCHECK(rpo_number_ >= 0);
-    DCHECK(block->rpo_number_ >= 0);
-    if (loop_end_ < 0) return false;  // This is not a loop.
-    return block->rpo_number_ >= rpo_number_ && block->rpo_number_ < loop_end_;
-  }
-  int first_instruction_index() {
-    DCHECK(code_start_ >= 0);
-    DCHECK(code_end_ > 0);
-    DCHECK(code_end_ >= code_start_);
-    return code_start_;
-  }
-  int last_instruction_index() {
-    DCHECK(code_start_ >= 0);
-    DCHECK(code_end_ > 0);
-    DCHECK(code_end_ >= code_start_);
-    return code_end_ - 1;
-  }
-};
-
-OStream& operator<<(OStream& os, const BasicBlockData::Control& c);
-
-// A basic block contains an ordered list of nodes and ends with a control
-// node. Note that if a basic block has phis, then all phis must appear as the
-// first nodes in the block.
-class BasicBlock FINAL : public GenericNode<BasicBlockData, BasicBlock> {
- public:
-  BasicBlock(GenericGraphBase* graph, int input_count)
-      : GenericNode<BasicBlockData, BasicBlock>(graph, input_count) {}
-
-  typedef Uses Successors;
-  typedef Inputs Predecessors;
-
-  Successors successors() { return static_cast<Successors>(uses()); }
-  Predecessors predecessors() { return static_cast<Predecessors>(inputs()); }
-
-  int PredecessorCount() { return InputCount(); }
-  BasicBlock* PredecessorAt(int index) { return InputAt(index); }
-
-  int SuccessorCount() { return UseCount(); }
-  BasicBlock* SuccessorAt(int index) { return UseAt(index); }
-
-  int PredecessorIndexOf(BasicBlock* predecessor) {
-    BasicBlock::Predecessors predecessors = this->predecessors();
-    for (BasicBlock::Predecessors::iterator i = predecessors.begin();
-         i != predecessors.end(); ++i) {
-      if (*i == predecessor) return i.index();
+  static const int kInvalidRpoNumber = -1;
+  class RpoNumber FINAL {
+   public:
+    int ToInt() const {
+      DCHECK(IsValid());
+      return index_;
     }
-    return -1;
-  }
+    size_t ToSize() const {
+      DCHECK(IsValid());
+      return static_cast<size_t>(index_);
+    }
+    bool IsValid() const { return index_ >= 0; }
+    static RpoNumber FromInt(int index) { return RpoNumber(index); }
+    static RpoNumber Invalid() { return RpoNumber(kInvalidRpoNumber); }
 
-  inline BasicBlock* loop_header() {
-    return static_cast<BasicBlock*>(loop_header_);
+    bool IsNext(const RpoNumber other) const {
+      DCHECK(IsValid());
+      return other.index_ == this->index_ + 1;
+    }
+
+    bool operator==(RpoNumber other) const {
+      return this->index_ == other.index_;
+    }
+
+   private:
+    explicit RpoNumber(int32_t index) : index_(index) {}
+    int32_t index_;
+  };
+
+  BasicBlock(Zone* zone, Id id);
+
+  Id id() const { return id_; }
+
+  // Predecessors and successors.
+  typedef ZoneVector<BasicBlock*> Predecessors;
+  Predecessors::iterator predecessors_begin() { return predecessors_.begin(); }
+  Predecessors::iterator predecessors_end() { return predecessors_.end(); }
+  Predecessors::const_iterator predecessors_begin() const {
+    return predecessors_.begin();
   }
-  inline BasicBlock* ContainingLoop() {
-    if (IsLoopHeader()) return this;
-    return static_cast<BasicBlock*>(loop_header_);
+  Predecessors::const_iterator predecessors_end() const {
+    return predecessors_.end();
   }
+  size_t PredecessorCount() const { return predecessors_.size(); }
+  BasicBlock* PredecessorAt(size_t index) { return predecessors_[index]; }
+  void ClearPredecessors() { predecessors_.clear(); }
+  void AddPredecessor(BasicBlock* predecessor);
+
+  typedef ZoneVector<BasicBlock*> Successors;
+  Successors::iterator successors_begin() { return successors_.begin(); }
+  Successors::iterator successors_end() { return successors_.end(); }
+  Successors::const_iterator successors_begin() const {
+    return successors_.begin();
+  }
+  Successors::const_iterator successors_end() const {
+    return successors_.end();
+  }
+  size_t SuccessorCount() const { return successors_.size(); }
+  BasicBlock* SuccessorAt(size_t index) { return successors_[index]; }
+  void ClearSuccessors() { successors_.clear(); }
+  void AddSuccessor(BasicBlock* successor);
+
+  // Nodes in the basic block.
+  Node* NodeAt(size_t index) { return nodes_[index]; }
+  size_t NodeCount() const { return nodes_.size(); }
 
   typedef NodeVector::iterator iterator;
   iterator begin() { return nodes_.begin(); }
@@ -138,12 +128,79 @@
   reverse_iterator rbegin() { return nodes_.rbegin(); }
   reverse_iterator rend() { return nodes_.rend(); }
 
+  void AddNode(Node* node);
+  template <class InputIterator>
+  void InsertNodes(iterator insertion_point, InputIterator insertion_start,
+                   InputIterator insertion_end) {
+    nodes_.insert(insertion_point, insertion_start, insertion_end);
+  }
+
+  // Accessors.
+  Control control() const { return control_; }
+  void set_control(Control control);
+
+  Node* control_input() const { return control_input_; }
+  void set_control_input(Node* control_input);
+
+  bool deferred() const { return deferred_; }
+  void set_deferred(bool deferred) { deferred_ = deferred; }
+
+  int32_t dominator_depth() const { return dominator_depth_; }
+  void set_dominator_depth(int32_t depth) { dominator_depth_ = depth; }
+
+  BasicBlock* dominator() const { return dominator_; }
+  void set_dominator(BasicBlock* dominator) { dominator_ = dominator; }
+
+  BasicBlock* rpo_next() const { return rpo_next_; }
+  void set_rpo_next(BasicBlock* rpo_next) { rpo_next_ = rpo_next; }
+
+  BasicBlock* loop_header() const { return loop_header_; }
+  void set_loop_header(BasicBlock* loop_header);
+
+  BasicBlock* loop_end() const { return loop_end_; }
+  void set_loop_end(BasicBlock* loop_end);
+
+  int32_t loop_depth() const { return loop_depth_; }
+  void set_loop_depth(int32_t loop_depth);
+
+  int32_t loop_number() const { return loop_number_; }
+  void set_loop_number(int32_t loop_number) { loop_number_ = loop_number; }
+
+  RpoNumber GetRpoNumber() const { return RpoNumber::FromInt(rpo_number_); }
+  int32_t rpo_number() const { return rpo_number_; }
+  void set_rpo_number(int32_t rpo_number);
+
+  // Loop membership helpers.
+  inline bool IsLoopHeader() const { return loop_end_ != NULL; }
+  bool LoopContains(BasicBlock* block) const;
+
  private:
+  int32_t loop_number_;      // loop number of the block.
+  int32_t rpo_number_;       // special RPO number of the block.
+  bool deferred_;            // true if the block contains deferred code.
+  int32_t dominator_depth_;  // Depth within the dominator tree.
+  BasicBlock* dominator_;    // Immediate dominator of the block.
+  BasicBlock* rpo_next_;     // Link to next block in special RPO order.
+  BasicBlock* loop_header_;  // Pointer to dominating loop header basic block,
+                             // NULL if none. For loop headers, this points to
+                             // enclosing loop header.
+  BasicBlock* loop_end_;     // end of the loop, if this block is a loop header.
+  int32_t loop_depth_;       // loop nesting, 0 is top-level
+
+  Control control_;          // Control at the end of the block.
+  Node* control_input_;      // Input value for control.
+  NodeVector nodes_;         // nodes of this block in forward order.
+
+  Successors successors_;
+  Predecessors predecessors_;
+  Id id_;
+
   DISALLOW_COPY_AND_ASSIGN(BasicBlock);
 };
 
-typedef GenericGraphVisit::NullNodeVisitor<BasicBlockData, BasicBlock>
-    NullBasicBlockVisitor;
+std::ostream& operator<<(std::ostream& os, const BasicBlock::Control& c);
+std::ostream& operator<<(std::ostream& os, const BasicBlock::Id& id);
+std::ostream& operator<<(std::ostream& os, const BasicBlock::RpoNumber& rpo);
 
 typedef ZoneVector<BasicBlock*> BasicBlockVector;
 typedef BasicBlockVector::iterator BasicBlockVectorIter;
@@ -153,154 +210,86 @@
 // and ordering them within basic blocks. Prior to computing a schedule,
 // a graph has no notion of control flow ordering other than that induced
 // by the graph's dependencies. A schedule is required to generate code.
-class Schedule : public GenericGraph<BasicBlock> {
+class Schedule FINAL : public ZoneObject {
  public:
-  explicit Schedule(Zone* zone)
-      : GenericGraph<BasicBlock>(zone),
-        zone_(zone),
-        all_blocks_(zone),
-        nodeid_to_block_(zone),
-        rpo_order_(zone) {
-    SetStart(NewBasicBlock());  // entry.
-    SetEnd(NewBasicBlock());    // exit.
-  }
+  explicit Schedule(Zone* zone, size_t node_count_hint = 0);
 
   // Return the block which contains {node}, if any.
-  BasicBlock* block(Node* node) const {
-    if (node->id() < static_cast<NodeId>(nodeid_to_block_.size())) {
-      return nodeid_to_block_[node->id()];
-    }
-    return NULL;
-  }
+  BasicBlock* block(Node* node) const;
 
-  bool IsScheduled(Node* node) {
-    int length = static_cast<int>(nodeid_to_block_.size());
-    if (node->id() >= length) return false;
-    return nodeid_to_block_[node->id()] != NULL;
-  }
+  bool IsScheduled(Node* node);
+  BasicBlock* GetBlockById(BasicBlock::Id block_id);
 
-  BasicBlock* GetBlockById(int block_id) { return all_blocks_[block_id]; }
-
-  int BasicBlockCount() const { return NodeCount(); }
-  int RpoBlockCount() const { return static_cast<int>(rpo_order_.size()); }
-
-  typedef ContainerPointerWrapper<BasicBlockVector> BasicBlocks;
-
-  // Return a list of all the blocks in the schedule, in arbitrary order.
-  BasicBlocks all_blocks() { return BasicBlocks(&all_blocks_); }
+  size_t BasicBlockCount() const { return all_blocks_.size(); }
+  size_t RpoBlockCount() const { return rpo_order_.size(); }
 
   // Check if nodes {a} and {b} are in the same block.
-  inline bool SameBasicBlock(Node* a, Node* b) const {
-    BasicBlock* block = this->block(a);
-    return block != NULL && block == this->block(b);
-  }
+  bool SameBasicBlock(Node* a, Node* b) const;
 
   // BasicBlock building: create a new block.
-  inline BasicBlock* NewBasicBlock() {
-    BasicBlock* block =
-        BasicBlock::New(this, 0, static_cast<BasicBlock**>(NULL));
-    all_blocks_.push_back(block);
-    return block;
-  }
+  BasicBlock* NewBasicBlock();
 
   // BasicBlock building: records that a node will later be added to a block but
   // doesn't actually add the node to the block.
-  inline void PlanNode(BasicBlock* block, Node* node) {
-    if (FLAG_trace_turbo_scheduler) {
-      PrintF("Planning #%d:%s for future add to B%d\n", node->id(),
-             node->op()->mnemonic(), block->id());
-    }
-    DCHECK(this->block(node) == NULL);
-    SetBlockForNode(block, node);
-  }
+  void PlanNode(BasicBlock* block, Node* node);
 
   // BasicBlock building: add a node to the end of the block.
-  inline void AddNode(BasicBlock* block, Node* node) {
-    if (FLAG_trace_turbo_scheduler) {
-      PrintF("Adding #%d:%s to B%d\n", node->id(), node->op()->mnemonic(),
-             block->id());
-    }
-    DCHECK(this->block(node) == NULL || this->block(node) == block);
-    block->nodes_.push_back(node);
-    SetBlockForNode(block, node);
-  }
+  void AddNode(BasicBlock* block, Node* node);
 
   // BasicBlock building: add a goto to the end of {block}.
-  void AddGoto(BasicBlock* block, BasicBlock* succ) {
-    DCHECK(block->control_ == BasicBlock::kNone);
-    block->control_ = BasicBlock::kGoto;
-    AddSuccessor(block, succ);
-  }
+  void AddGoto(BasicBlock* block, BasicBlock* succ);
 
   // BasicBlock building: add a branch at the end of {block}.
   void AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock,
-                 BasicBlock* fblock) {
-    DCHECK(block->control_ == BasicBlock::kNone);
-    DCHECK(branch->opcode() == IrOpcode::kBranch);
-    block->control_ = BasicBlock::kBranch;
-    AddSuccessor(block, tblock);
-    AddSuccessor(block, fblock);
-    SetControlInput(block, branch);
-    if (branch->opcode() == IrOpcode::kBranch) {
-      // TODO(titzer): require a Branch node here. (sloppy tests).
-      SetBlockForNode(block, branch);
-    }
-  }
+                 BasicBlock* fblock);
 
   // BasicBlock building: add a return at the end of {block}.
-  void AddReturn(BasicBlock* block, Node* input) {
-    DCHECK(block->control_ == BasicBlock::kNone);
-    block->control_ = BasicBlock::kReturn;
-    SetControlInput(block, input);
-    if (block != end()) AddSuccessor(block, end());
-    if (input->opcode() == IrOpcode::kReturn) {
-      // TODO(titzer): require a Return node here. (sloppy tests).
-      SetBlockForNode(block, input);
-    }
-  }
+  void AddReturn(BasicBlock* block, Node* input);
 
   // BasicBlock building: add a throw at the end of {block}.
-  void AddThrow(BasicBlock* block, Node* input) {
-    DCHECK(block->control_ == BasicBlock::kNone);
-    block->control_ = BasicBlock::kThrow;
-    SetControlInput(block, input);
-    if (block != end()) AddSuccessor(block, end());
-  }
+  void AddThrow(BasicBlock* block, Node* input);
 
-  friend class Scheduler;
-  friend class CodeGenerator;
+  // BasicBlock mutation: insert a branch into the end of {block}.
+  void InsertBranch(BasicBlock* block, BasicBlock* end, Node* branch,
+                    BasicBlock* tblock, BasicBlock* fblock);
 
-  void AddSuccessor(BasicBlock* block, BasicBlock* succ) {
-    succ->AppendInput(zone_, block);
+  // Exposed publicly for testing only.
+  void AddSuccessorForTesting(BasicBlock* block, BasicBlock* succ) {
+    return AddSuccessor(block, succ);
   }
 
   BasicBlockVector* rpo_order() { return &rpo_order_; }
+  const BasicBlockVector* rpo_order() const { return &rpo_order_; }
+
+  BasicBlock* start() { return start_; }
+  BasicBlock* end() { return end_; }
+
+  Zone* zone() const { return zone_; }
 
  private:
-  friend class ScheduleVisualizer;
+  friend class Scheduler;
+  friend class BasicBlockInstrumentor;
 
-  void SetControlInput(BasicBlock* block, Node* node) {
-    block->control_input_ = node;
-    SetBlockForNode(block, node);
-  }
+  void AddSuccessor(BasicBlock* block, BasicBlock* succ);
+  void MoveSuccessors(BasicBlock* from, BasicBlock* to);
 
-  void SetBlockForNode(BasicBlock* block, Node* node) {
-    int length = static_cast<int>(nodeid_to_block_.size());
-    if (node->id() >= length) {
-      nodeid_to_block_.resize(node->id() + 1);
-    }
-    nodeid_to_block_[node->id()] = block;
-  }
+  void SetControlInput(BasicBlock* block, Node* node);
+  void SetBlockForNode(BasicBlock* block, Node* node);
 
   Zone* zone_;
   BasicBlockVector all_blocks_;           // All basic blocks in the schedule.
   BasicBlockVector nodeid_to_block_;      // Map from node to containing block.
   BasicBlockVector rpo_order_;            // Reverse-post-order block list.
+  BasicBlock* start_;
+  BasicBlock* end_;
+
+  DISALLOW_COPY_AND_ASSIGN(Schedule);
 };
 
-OStream& operator<<(OStream& os, const Schedule& s);
-}
-}
-}  // namespace v8::internal::compiler
+std::ostream& operator<<(std::ostream& os, const Schedule& s);
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_SCHEDULE_H_
diff --git a/src/compiler/scheduler.cc b/src/compiler/scheduler.cc
index 4029950..f12c631 100644
--- a/src/compiler/scheduler.cc
+++ b/src/compiler/scheduler.cc
@@ -7,12 +7,13 @@
 
 #include "src/compiler/scheduler.h"
 
+#include "src/bit-vector.h"
+#include "src/compiler/control-equivalence.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/node.h"
 #include "src/compiler/node-properties.h"
 #include "src/compiler/node-properties-inl.h"
-#include "src/data-flow.h"
 
 namespace v8 {
 namespace internal {
@@ -28,30 +29,225 @@
 }
 
 
-// Internal class to build a control flow graph (i.e the basic blocks and edges
-// between them within a Schedule) from the node graph.
-// Visits the control edges of the graph backwards from end in order to find
-// the connected control subgraph, needed for scheduling.
-class CFGBuilder {
- public:
-  Scheduler* scheduler_;
-  Schedule* schedule_;
-  ZoneQueue<Node*> queue_;
-  NodeVector control_;
+Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule)
+    : zone_(zone),
+      graph_(graph),
+      schedule_(schedule),
+      scheduled_nodes_(zone),
+      schedule_root_nodes_(zone),
+      schedule_queue_(zone),
+      node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone) {}
 
+
+Schedule* Scheduler::ComputeSchedule(Zone* zone, Graph* graph) {
+  Schedule* schedule = new (graph->zone())
+      Schedule(graph->zone(), static_cast<size_t>(graph->NodeCount()));
+  Scheduler scheduler(zone, graph, schedule);
+
+  scheduler.BuildCFG();
+  scheduler.ComputeSpecialRPONumbering();
+  scheduler.GenerateImmediateDominatorTree();
+
+  scheduler.PrepareUses();
+  scheduler.ScheduleEarly();
+  scheduler.ScheduleLate();
+
+  scheduler.SealFinalSchedule();
+
+  return schedule;
+}
+
+
+Scheduler::SchedulerData Scheduler::DefaultSchedulerData() {
+  SchedulerData def = {schedule_->start(), 0, kUnknown};
+  return def;
+}
+
+
+Scheduler::SchedulerData* Scheduler::GetData(Node* node) {
+  DCHECK(node->id() < static_cast<int>(node_data_.size()));
+  return &node_data_[node->id()];
+}
+
+
+Scheduler::Placement Scheduler::GetPlacement(Node* node) {
+  SchedulerData* data = GetData(node);
+  if (data->placement_ == kUnknown) {  // Compute placement, once, on demand.
+    switch (node->opcode()) {
+      case IrOpcode::kParameter:
+        // Parameters are always fixed to the start node.
+        data->placement_ = kFixed;
+        break;
+      case IrOpcode::kPhi:
+      case IrOpcode::kEffectPhi: {
+        // Phis and effect phis are fixed if their control inputs are, whereas
+        // otherwise they are coupled to a floating control node.
+        Placement p = GetPlacement(NodeProperties::GetControlInput(node));
+        data->placement_ = (p == kFixed ? kFixed : kCoupled);
+        break;
+      }
+#define DEFINE_CONTROL_CASE(V) case IrOpcode::k##V:
+      CONTROL_OP_LIST(DEFINE_CONTROL_CASE)
+#undef DEFINE_CONTROL_CASE
+      {
+        // Control nodes that were not control-reachable from end may float.
+        data->placement_ = kSchedulable;
+        break;
+      }
+      default:
+        data->placement_ = kSchedulable;
+        break;
+    }
+  }
+  return data->placement_;
+}
+
+
+void Scheduler::UpdatePlacement(Node* node, Placement placement) {
+  SchedulerData* data = GetData(node);
+  if (data->placement_ != kUnknown) {  // Trap on mutation, not initialization.
+    switch (node->opcode()) {
+      case IrOpcode::kParameter:
+        // Parameters are fixed once and for all.
+        UNREACHABLE();
+        break;
+      case IrOpcode::kPhi:
+      case IrOpcode::kEffectPhi: {
+        // Phis and effect phis are coupled to their respective blocks.
+        DCHECK_EQ(Scheduler::kCoupled, data->placement_);
+        DCHECK_EQ(Scheduler::kFixed, placement);
+        Node* control = NodeProperties::GetControlInput(node);
+        BasicBlock* block = schedule_->block(control);
+        schedule_->AddNode(block, node);
+        break;
+      }
+#define DEFINE_CONTROL_CASE(V) case IrOpcode::k##V:
+      CONTROL_OP_LIST(DEFINE_CONTROL_CASE)
+#undef DEFINE_CONTROL_CASE
+      {
+        // Control nodes force coupled uses to be placed.
+        Node::Uses uses = node->uses();
+        for (Node::Uses::iterator i = uses.begin(); i != uses.end(); ++i) {
+          if (GetPlacement(*i) == Scheduler::kCoupled) {
+            DCHECK_EQ(node, NodeProperties::GetControlInput(*i));
+            UpdatePlacement(*i, placement);
+          }
+        }
+        break;
+      }
+      default:
+        DCHECK_EQ(Scheduler::kSchedulable, data->placement_);
+        DCHECK_EQ(Scheduler::kScheduled, placement);
+        break;
+    }
+    // Reduce the use count of the node's inputs to potentially make them
+    // schedulable. If all the uses of a node have been scheduled, then the node
+    // itself can be scheduled.
+    for (Edge const edge : node->input_edges()) {
+      DecrementUnscheduledUseCount(edge.to(), edge.index(), edge.from());
+    }
+  }
+  data->placement_ = placement;
+}
+
+
+bool Scheduler::IsCoupledControlEdge(Node* node, int index) {
+  return GetPlacement(node) == kCoupled &&
+         NodeProperties::FirstControlIndex(node) == index;
+}
+
+
+void Scheduler::IncrementUnscheduledUseCount(Node* node, int index,
+                                             Node* from) {
+  // Make sure that control edges from coupled nodes are not counted.
+  if (IsCoupledControlEdge(from, index)) return;
+
+  // Tracking use counts for fixed nodes is useless.
+  if (GetPlacement(node) == kFixed) return;
+
+  // Use count for coupled nodes is summed up on their control.
+  if (GetPlacement(node) == kCoupled) {
+    Node* control = NodeProperties::GetControlInput(node);
+    return IncrementUnscheduledUseCount(control, index, from);
+  }
+
+  ++(GetData(node)->unscheduled_count_);
+  if (FLAG_trace_turbo_scheduler) {
+    Trace("  Use count of #%d:%s (used by #%d:%s)++ = %d\n", node->id(),
+          node->op()->mnemonic(), from->id(), from->op()->mnemonic(),
+          GetData(node)->unscheduled_count_);
+  }
+}
+
+
+void Scheduler::DecrementUnscheduledUseCount(Node* node, int index,
+                                             Node* from) {
+  // Make sure that control edges from coupled nodes are not counted.
+  if (IsCoupledControlEdge(from, index)) return;
+
+  // Tracking use counts for fixed nodes is useless.
+  if (GetPlacement(node) == kFixed) return;
+
+  // Use count for coupled nodes is summed up on their control.
+  if (GetPlacement(node) == kCoupled) {
+    Node* control = NodeProperties::GetControlInput(node);
+    return DecrementUnscheduledUseCount(control, index, from);
+  }
+
+  DCHECK(GetData(node)->unscheduled_count_ > 0);
+  --(GetData(node)->unscheduled_count_);
+  if (FLAG_trace_turbo_scheduler) {
+    Trace("  Use count of #%d:%s (used by #%d:%s)-- = %d\n", node->id(),
+          node->op()->mnemonic(), from->id(), from->op()->mnemonic(),
+          GetData(node)->unscheduled_count_);
+  }
+  if (GetData(node)->unscheduled_count_ == 0) {
+    Trace("    newly eligible #%d:%s\n", node->id(), node->op()->mnemonic());
+    schedule_queue_.push(node);
+  }
+}
+
+
+BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
+  while (b1 != b2) {
+    int32_t b1_depth = b1->dominator_depth();
+    int32_t b2_depth = b2->dominator_depth();
+    if (b1_depth < b2_depth) {
+      b2 = b2->dominator();
+    } else {
+      b1 = b1->dominator();
+    }
+  }
+  return b1;
+}
+
+
+// -----------------------------------------------------------------------------
+// Phase 1: Build control-flow graph.
+
+
+// Internal class to build a control flow graph (i.e the basic blocks and edges
+// between them within a Schedule) from the node graph. Visits control edges of
+// the graph backwards from an end node in order to find the connected control
+// subgraph, needed for scheduling.
+class CFGBuilder : public ZoneObject {
+ public:
   CFGBuilder(Zone* zone, Scheduler* scheduler)
       : scheduler_(scheduler),
         schedule_(scheduler->schedule_),
+        queued_(scheduler->graph_, 2),
         queue_(zone),
-        control_(zone) {}
+        control_(zone),
+        component_entry_(NULL),
+        component_start_(NULL),
+        component_end_(NULL) {}
 
   // Run the control flow graph construction algorithm by walking the graph
   // backwards from end through control edges, building and connecting the
   // basic blocks for control nodes.
   void Run() {
-    Graph* graph = scheduler_->graph_;
-    FixNode(schedule_->start(), graph->start());
-    Queue(graph->end());
+    ResetDataStructures();
+    Queue(scheduler_->graph_->end());
 
     while (!queue_.empty()) {  // Breadth-first backwards traversal.
       Node* node = queue_.front();
@@ -65,33 +261,82 @@
     for (NodeVector::iterator i = control_.begin(); i != control_.end(); ++i) {
       ConnectBlocks(*i);  // Connect block to its predecessor/successors.
     }
-
-    FixNode(schedule_->end(), graph->end());
   }
 
+  // Run the control flow graph construction for a minimal control-connected
+  // component ending in {exit} and merge that component into an existing
+  // control flow graph at the bottom of {block}.
+  void Run(BasicBlock* block, Node* exit) {
+    ResetDataStructures();
+    Queue(exit);
+
+    component_entry_ = NULL;
+    component_start_ = block;
+    component_end_ = schedule_->block(exit);
+    scheduler_->equivalence_->Run(exit);
+    while (!queue_.empty()) {  // Breadth-first backwards traversal.
+      Node* node = queue_.front();
+      queue_.pop();
+
+      // Use control dependence equivalence to find a canonical single-entry
+      // single-exit region that makes up a minimal component to be scheduled.
+      if (IsSingleEntrySingleExitRegion(node, exit)) {
+        Trace("Found SESE at #%d:%s\n", node->id(), node->op()->mnemonic());
+        DCHECK_EQ(NULL, component_entry_);
+        component_entry_ = node;
+        continue;
+      }
+
+      int max = NodeProperties::PastControlIndex(node);
+      for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) {
+        Queue(node->InputAt(i));
+      }
+    }
+    DCHECK_NE(NULL, component_entry_);
+
+    for (NodeVector::iterator i = control_.begin(); i != control_.end(); ++i) {
+      ConnectBlocks(*i);  // Connect block to its predecessor/successors.
+    }
+  }
+
+ private:
+  // TODO(mstarzinger): Only for Scheduler::FuseFloatingControl.
+  friend class Scheduler;
+
   void FixNode(BasicBlock* block, Node* node) {
     schedule_->AddNode(block, node);
-    scheduler_->GetData(node)->is_connected_control_ = true;
-    scheduler_->GetData(node)->placement_ = Scheduler::kFixed;
+    scheduler_->UpdatePlacement(node, Scheduler::kFixed);
   }
 
   void Queue(Node* node) {
-    // Mark the connected control nodes as they queued.
-    Scheduler::SchedulerData* data = scheduler_->GetData(node);
-    if (!data->is_connected_control_) {
+    // Mark the connected control nodes as they are queued.
+    if (!queued_.Get(node)) {
       BuildBlocks(node);
       queue_.push(node);
+      queued_.Set(node, true);
       control_.push_back(node);
-      data->is_connected_control_ = true;
     }
   }
 
   void BuildBlocks(Node* node) {
     switch (node->opcode()) {
+      case IrOpcode::kEnd:
+        FixNode(schedule_->end(), node);
+        break;
+      case IrOpcode::kStart:
+        FixNode(schedule_->start(), node);
+        break;
       case IrOpcode::kLoop:
       case IrOpcode::kMerge:
         BuildBlockForNode(node);
         break;
+      case IrOpcode::kTerminate: {
+        // Put Terminate in the loop to which it refers.
+        Node* loop = NodeProperties::GetControlInput(node);
+        BasicBlock* block = BuildBlockForNode(loop);
+        FixNode(block, node);
+        break;
+      }
       case IrOpcode::kBranch:
         BuildBlocksForSuccessors(node, IrOpcode::kIfTrue, IrOpcode::kIfFalse);
         break;
@@ -107,11 +352,11 @@
         ConnectMerge(node);
         break;
       case IrOpcode::kBranch:
-        scheduler_->schedule_root_nodes_.push_back(node);
+        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
         ConnectBranch(node);
         break;
       case IrOpcode::kReturn:
-        scheduler_->schedule_root_nodes_.push_back(node);
+        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
         ConnectReturn(node);
         break;
       default:
@@ -119,13 +364,15 @@
     }
   }
 
-  void BuildBlockForNode(Node* node) {
-    if (schedule_->block(node) == NULL) {
-      BasicBlock* block = schedule_->NewBasicBlock();
-      Trace("Create block B%d for #%d:%s\n", block->id(), node->id(),
+  BasicBlock* BuildBlockForNode(Node* node) {
+    BasicBlock* block = schedule_->block(node);
+    if (block == NULL) {
+      block = schedule_->NewBasicBlock();
+      Trace("Create block B%d for #%d:%s\n", block->id().ToInt(), node->id(),
             node->op()->mnemonic());
       FixNode(block, node);
     }
+    return block;
   }
 
   void BuildBlocksForSuccessors(Node* node, IrOpcode::Value a,
@@ -144,14 +391,14 @@
                                    IrOpcode::Value false_opcode) {
     buffer[0] = NULL;
     buffer[1] = NULL;
-    for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) {
-      if ((*i)->opcode() == true_opcode) {
+    for (Node* use : node->uses()) {
+      if (use->opcode() == true_opcode) {
         DCHECK_EQ(NULL, buffer[0]);
-        buffer[0] = *i;
+        buffer[0] = use;
       }
-      if ((*i)->opcode() == false_opcode) {
+      if (use->opcode() == false_opcode) {
         DCHECK_EQ(NULL, buffer[1]);
-        buffer[1] = *i;
+        buffer[1] = use;
       }
     }
     DCHECK_NE(NULL, buffer[0]);
@@ -168,33 +415,51 @@
   }
 
   void ConnectBranch(Node* branch) {
-    Node* branch_block_node = NodeProperties::GetControlInput(branch);
-    BasicBlock* branch_block = schedule_->block(branch_block_node);
-    DCHECK(branch_block != NULL);
-
     BasicBlock* successor_blocks[2];
     CollectSuccessorBlocks(branch, successor_blocks, IrOpcode::kIfTrue,
                            IrOpcode::kIfFalse);
 
-    TraceConnect(branch, branch_block, successor_blocks[0]);
-    TraceConnect(branch, branch_block, successor_blocks[1]);
+    // Consider branch hints.
+    switch (BranchHintOf(branch->op())) {
+      case BranchHint::kNone:
+        break;
+      case BranchHint::kTrue:
+        successor_blocks[1]->set_deferred(true);
+        break;
+      case BranchHint::kFalse:
+        successor_blocks[0]->set_deferred(true);
+        break;
+    }
 
-    schedule_->AddBranch(branch_block, branch, successor_blocks[0],
-                         successor_blocks[1]);
+    if (branch == component_entry_) {
+      TraceConnect(branch, component_start_, successor_blocks[0]);
+      TraceConnect(branch, component_start_, successor_blocks[1]);
+      schedule_->InsertBranch(component_start_, component_end_, branch,
+                              successor_blocks[0], successor_blocks[1]);
+    } else {
+      Node* branch_block_node = NodeProperties::GetControlInput(branch);
+      BasicBlock* branch_block = schedule_->block(branch_block_node);
+      DCHECK(branch_block != NULL);
+
+      TraceConnect(branch, branch_block, successor_blocks[0]);
+      TraceConnect(branch, branch_block, successor_blocks[1]);
+      schedule_->AddBranch(branch_block, branch, successor_blocks[0],
+                           successor_blocks[1]);
+    }
   }
 
   void ConnectMerge(Node* merge) {
+    // Don't connect the special merge at the end to its predecessors.
+    if (IsFinalMerge(merge)) return;
+
     BasicBlock* block = schedule_->block(merge);
     DCHECK(block != NULL);
     // For all of the merge's control inputs, add a goto at the end to the
     // merge's basic block.
-    for (InputIter j = merge->inputs().begin(); j != merge->inputs().end();
-         ++j) {
-      BasicBlock* predecessor_block = schedule_->block(*j);
-      if ((*j)->opcode() != IrOpcode::kReturn) {
-        TraceConnect(merge, predecessor_block, block);
-        schedule_->AddGoto(predecessor_block, block);
-      }
+    for (Node* const input : merge->inputs()) {
+      BasicBlock* predecessor_block = schedule_->block(input);
+      TraceConnect(merge, predecessor_block, block);
+      schedule_->AddGoto(predecessor_block, block);
     }
   }
 
@@ -209,713 +474,59 @@
     DCHECK_NE(NULL, block);
     if (succ == NULL) {
       Trace("Connect #%d:%s, B%d -> end\n", node->id(), node->op()->mnemonic(),
-            block->id());
+            block->id().ToInt());
     } else {
       Trace("Connect #%d:%s, B%d -> B%d\n", node->id(), node->op()->mnemonic(),
-            block->id(), succ->id());
+            block->id().ToInt(), succ->id().ToInt());
     }
   }
+
+  bool IsFinalMerge(Node* node) {
+    return (node->opcode() == IrOpcode::kMerge &&
+            node == scheduler_->graph_->end()->InputAt(0));
+  }
+
+  bool IsSingleEntrySingleExitRegion(Node* entry, Node* exit) const {
+    size_t entry_class = scheduler_->equivalence_->ClassOf(entry);
+    size_t exit_class = scheduler_->equivalence_->ClassOf(exit);
+    return entry != exit && entry_class == exit_class;
+  }
+
+  void ResetDataStructures() {
+    control_.clear();
+    DCHECK(queue_.empty());
+    DCHECK(control_.empty());
+  }
+
+  Scheduler* scheduler_;
+  Schedule* schedule_;
+  NodeMarker<bool> queued_;      // Mark indicating whether node is queued.
+  ZoneQueue<Node*> queue_;       // Queue used for breadth-first traversal.
+  NodeVector control_;           // List of encountered control nodes.
+  Node* component_entry_;        // Component single-entry node.
+  BasicBlock* component_start_;  // Component single-entry block.
+  BasicBlock* component_end_;    // Component single-exit block.
 };
 
 
-Scheduler::SchedulerData Scheduler::DefaultSchedulerData() {
-  SchedulerData def = {0, 0, false, false, kUnknown};
-  return def;
-}
-
-
-Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule)
-    : zone_(zone),
-      graph_(graph),
-      schedule_(schedule),
-      scheduled_nodes_(zone),
-      schedule_root_nodes_(zone),
-      node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone),
-      has_floating_control_(false) {}
-
-
-Schedule* Scheduler::ComputeSchedule(Graph* graph) {
-  Schedule* schedule;
-  bool had_floating_control = false;
-  do {
-    Zone tmp_zone(graph->zone()->isolate());
-    schedule = new (graph->zone()) Schedule(graph->zone());
-    Scheduler scheduler(&tmp_zone, graph, schedule);
-
-    scheduler.BuildCFG();
-
-    Scheduler::ComputeSpecialRPO(schedule);
-    scheduler.GenerateImmediateDominatorTree();
-
-    scheduler.PrepareUses();
-    scheduler.ScheduleEarly();
-    scheduler.ScheduleLate();
-
-    had_floating_control = scheduler.ConnectFloatingControl();
-  } while (had_floating_control);
-
-  return schedule;
-}
-
-
-Scheduler::Placement Scheduler::GetPlacement(Node* node) {
-  SchedulerData* data = GetData(node);
-  if (data->placement_ == kUnknown) {  // Compute placement, once, on demand.
-    switch (node->opcode()) {
-      case IrOpcode::kParameter:
-        // Parameters are always fixed to the start node.
-        data->placement_ = kFixed;
-        break;
-      case IrOpcode::kPhi:
-      case IrOpcode::kEffectPhi: {
-        // Phis and effect phis are fixed if their control inputs are.
-        data->placement_ = GetPlacement(NodeProperties::GetControlInput(node));
-        break;
-      }
-#define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V:
-        CONTROL_OP_LIST(DEFINE_FLOATING_CONTROL_CASE)
-#undef DEFINE_FLOATING_CONTROL_CASE
-        {
-          // Control nodes that were not control-reachable from end may float.
-          data->placement_ = kSchedulable;
-          if (!data->is_connected_control_) {
-            data->is_floating_control_ = true;
-            has_floating_control_ = true;
-            Trace("Floating control found: #%d:%s\n", node->id(),
-                  node->op()->mnemonic());
-          }
-          break;
-        }
-      default:
-        data->placement_ = kSchedulable;
-        break;
-    }
-  }
-  return data->placement_;
-}
-
-
 void Scheduler::BuildCFG() {
-  Trace("---------------- CREATING CFG ------------------\n");
-  CFGBuilder cfg_builder(zone_, this);
-  cfg_builder.Run();
+  Trace("--- CREATING CFG -------------------------------------------\n");
+
+  // Instantiate a new control equivalence algorithm for the graph.
+  equivalence_ = new (zone_) ControlEquivalence(zone_, graph_);
+
+  // Build a control-flow graph for the main control-connected component that
+  // is being spanned by the graph's start and end nodes.
+  control_flow_builder_ = new (zone_) CFGBuilder(zone_, this);
+  control_flow_builder_->Run();
+
   // Initialize per-block data.
   scheduled_nodes_.resize(schedule_->BasicBlockCount(), NodeVector(zone_));
 }
 
 
-BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
-  while (b1 != b2) {
-    int b1_rpo = GetRPONumber(b1);
-    int b2_rpo = GetRPONumber(b2);
-    DCHECK(b1_rpo != b2_rpo);
-    if (b1_rpo < b2_rpo) {
-      b2 = b2->dominator_;
-    } else {
-      b1 = b1->dominator_;
-    }
-  }
-  return b1;
-}
-
-
-void Scheduler::GenerateImmediateDominatorTree() {
-  // Build the dominator graph.  TODO(danno): consider using Lengauer & Tarjan's
-  // if this becomes really slow.
-  Trace("------------ IMMEDIATE BLOCK DOMINATORS -----------\n");
-  for (size_t i = 0; i < schedule_->rpo_order_.size(); i++) {
-    BasicBlock* current_rpo = schedule_->rpo_order_[i];
-    if (current_rpo != schedule_->start()) {
-      BasicBlock::Predecessors::iterator current_pred =
-          current_rpo->predecessors().begin();
-      BasicBlock::Predecessors::iterator end =
-          current_rpo->predecessors().end();
-      DCHECK(current_pred != end);
-      BasicBlock* dominator = *current_pred;
-      ++current_pred;
-      // For multiple predecessors, walk up the rpo ordering until a common
-      // dominator is found.
-      int current_rpo_pos = GetRPONumber(current_rpo);
-      while (current_pred != end) {
-        // Don't examine backwards edges
-        BasicBlock* pred = *current_pred;
-        if (GetRPONumber(pred) < current_rpo_pos) {
-          dominator = GetCommonDominator(dominator, *current_pred);
-        }
-        ++current_pred;
-      }
-      current_rpo->dominator_ = dominator;
-      Trace("Block %d's idom is %d\n", current_rpo->id(), dominator->id());
-    }
-  }
-}
-
-
-class ScheduleEarlyNodeVisitor : public NullNodeVisitor {
- public:
-  explicit ScheduleEarlyNodeVisitor(Scheduler* scheduler)
-      : has_changed_rpo_constraints_(true),
-        scheduler_(scheduler),
-        schedule_(scheduler->schedule_) {}
-
-  GenericGraphVisit::Control Pre(Node* node) {
-    int max_rpo = 0;
-    // Fixed nodes already know their schedule early position.
-    if (scheduler_->GetPlacement(node) == Scheduler::kFixed) {
-      BasicBlock* block = schedule_->block(node);
-      DCHECK(block != NULL);
-      max_rpo = block->rpo_number_;
-      if (scheduler_->GetData(node)->minimum_rpo_ != max_rpo) {
-        has_changed_rpo_constraints_ = true;
-      }
-      scheduler_->GetData(node)->minimum_rpo_ = max_rpo;
-      Trace("Preschedule #%d:%s minimum_rpo = %d\n", node->id(),
-            node->op()->mnemonic(), max_rpo);
-    }
-    return GenericGraphVisit::CONTINUE;
-  }
-
-  GenericGraphVisit::Control Post(Node* node) {
-    int max_rpo = 0;
-    // Otherwise, the minimum rpo for the node is the max of all of the inputs.
-    if (scheduler_->GetPlacement(node) != Scheduler::kFixed) {
-      for (InputIter i = node->inputs().begin(); i != node->inputs().end();
-           ++i) {
-        int control_rpo = scheduler_->GetData(*i)->minimum_rpo_;
-        if (control_rpo > max_rpo) {
-          max_rpo = control_rpo;
-        }
-      }
-      if (scheduler_->GetData(node)->minimum_rpo_ != max_rpo) {
-        has_changed_rpo_constraints_ = true;
-      }
-      scheduler_->GetData(node)->minimum_rpo_ = max_rpo;
-      Trace("Postschedule #%d:%s minimum_rpo = %d\n", node->id(),
-            node->op()->mnemonic(), max_rpo);
-    }
-    return GenericGraphVisit::CONTINUE;
-  }
-
-  // TODO(mstarzinger): Dirty hack to unblock others, schedule early should be
-  // rewritten to use a pre-order traversal from the start instead.
-  bool has_changed_rpo_constraints_;
-
- private:
-  Scheduler* scheduler_;
-  Schedule* schedule_;
-};
-
-
-void Scheduler::ScheduleEarly() {
-  Trace("------------------- SCHEDULE EARLY ----------------\n");
-
-  int fixpoint_count = 0;
-  ScheduleEarlyNodeVisitor visitor(this);
-  while (visitor.has_changed_rpo_constraints_) {
-    visitor.has_changed_rpo_constraints_ = false;
-    graph_->VisitNodeInputsFromEnd(&visitor);
-    fixpoint_count++;
-  }
-
-  Trace("It took %d iterations to determine fixpoint\n", fixpoint_count);
-}
-
-
-class PrepareUsesVisitor : public NullNodeVisitor {
- public:
-  explicit PrepareUsesVisitor(Scheduler* scheduler)
-      : scheduler_(scheduler), schedule_(scheduler->schedule_) {}
-
-  GenericGraphVisit::Control Pre(Node* node) {
-    if (scheduler_->GetPlacement(node) == Scheduler::kFixed) {
-      // Fixed nodes are always roots for schedule late.
-      scheduler_->schedule_root_nodes_.push_back(node);
-      if (!schedule_->IsScheduled(node)) {
-        // Make sure root nodes are scheduled in their respective blocks.
-        Trace("  Scheduling fixed position node #%d:%s\n", node->id(),
-              node->op()->mnemonic());
-        IrOpcode::Value opcode = node->opcode();
-        BasicBlock* block =
-            opcode == IrOpcode::kParameter
-                ? schedule_->start()
-                : schedule_->block(NodeProperties::GetControlInput(node));
-        DCHECK(block != NULL);
-        schedule_->AddNode(block, node);
-      }
-    }
-
-    return GenericGraphVisit::CONTINUE;
-  }
-
-  void PostEdge(Node* from, int index, Node* to) {
-    // If the edge is from an unscheduled node, then tally it in the use count
-    // for all of its inputs. The same criterion will be used in ScheduleLate
-    // for decrementing use counts.
-    if (!schedule_->IsScheduled(from)) {
-      DCHECK_NE(Scheduler::kFixed, scheduler_->GetPlacement(from));
-      ++(scheduler_->GetData(to)->unscheduled_count_);
-      Trace("  Use count of #%d:%s (used by #%d:%s)++ = %d\n", to->id(),
-            to->op()->mnemonic(), from->id(), from->op()->mnemonic(),
-            scheduler_->GetData(to)->unscheduled_count_);
-    }
-  }
-
- private:
-  Scheduler* scheduler_;
-  Schedule* schedule_;
-};
-
-
-void Scheduler::PrepareUses() {
-  Trace("------------------- PREPARE USES ------------------\n");
-  // Count the uses of every node, it will be used to ensure that all of a
-  // node's uses are scheduled before the node itself.
-  PrepareUsesVisitor prepare_uses(this);
-  graph_->VisitNodeInputsFromEnd(&prepare_uses);
-}
-
-
-class ScheduleLateNodeVisitor : public NullNodeVisitor {
- public:
-  explicit ScheduleLateNodeVisitor(Scheduler* scheduler)
-      : scheduler_(scheduler), schedule_(scheduler_->schedule_) {}
-
-  GenericGraphVisit::Control Pre(Node* node) {
-    // Don't schedule nodes that are already scheduled.
-    if (schedule_->IsScheduled(node)) {
-      return GenericGraphVisit::CONTINUE;
-    }
-    Scheduler::SchedulerData* data = scheduler_->GetData(node);
-    DCHECK_EQ(Scheduler::kSchedulable, data->placement_);
-
-    // If all the uses of a node have been scheduled, then the node itself can
-    // be scheduled.
-    bool eligible = data->unscheduled_count_ == 0;
-    Trace("Testing for schedule eligibility for #%d:%s = %s\n", node->id(),
-          node->op()->mnemonic(), eligible ? "true" : "false");
-    if (!eligible) return GenericGraphVisit::DEFER;
-
-    // Determine the dominating block for all of the uses of this node. It is
-    // the latest block that this node can be scheduled in.
-    BasicBlock* block = NULL;
-    for (Node::Uses::iterator i = node->uses().begin(); i != node->uses().end();
-         ++i) {
-      BasicBlock* use_block = GetBlockForUse(i.edge());
-      block = block == NULL ? use_block : use_block == NULL
-                                              ? block
-                                              : scheduler_->GetCommonDominator(
-                                                    block, use_block);
-    }
-    DCHECK(block != NULL);
-
-    int min_rpo = data->minimum_rpo_;
-    Trace(
-        "Schedule late conservative for #%d:%s is B%d at loop depth %d, "
-        "minimum_rpo = %d\n",
-        node->id(), node->op()->mnemonic(), block->id(), block->loop_depth_,
-        min_rpo);
-    // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively
-    // into enclosing loop pre-headers until they would preceed their
-    // ScheduleEarly position.
-    BasicBlock* hoist_block = block;
-    while (hoist_block != NULL && hoist_block->rpo_number_ >= min_rpo) {
-      if (hoist_block->loop_depth_ < block->loop_depth_) {
-        block = hoist_block;
-        Trace("  hoisting #%d:%s to block %d\n", node->id(),
-              node->op()->mnemonic(), block->id());
-      }
-      // Try to hoist to the pre-header of the loop header.
-      hoist_block = hoist_block->loop_header();
-      if (hoist_block != NULL) {
-        BasicBlock* pre_header = hoist_block->dominator_;
-        DCHECK(pre_header == NULL ||
-               *hoist_block->predecessors().begin() == pre_header);
-        Trace(
-            "  hoist to pre-header B%d of loop header B%d, depth would be %d\n",
-            pre_header->id(), hoist_block->id(), pre_header->loop_depth_);
-        hoist_block = pre_header;
-      }
-    }
-
-    ScheduleNode(block, node);
-
-    return GenericGraphVisit::CONTINUE;
-  }
-
- private:
-  BasicBlock* GetBlockForUse(Node::Edge edge) {
-    Node* use = edge.from();
-    IrOpcode::Value opcode = use->opcode();
-    if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) {
-      // If the use is from a fixed (i.e. non-floating) phi, use the block
-      // of the corresponding control input to the merge.
-      int index = edge.index();
-      if (scheduler_->GetPlacement(use) == Scheduler::kFixed) {
-        Trace("  input@%d into a fixed phi #%d:%s\n", index, use->id(),
-              use->op()->mnemonic());
-        Node* merge = NodeProperties::GetControlInput(use, 0);
-        opcode = merge->opcode();
-        DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop);
-        use = NodeProperties::GetControlInput(merge, index);
-      }
-    }
-    BasicBlock* result = schedule_->block(use);
-    if (result == NULL) return NULL;
-    Trace("  must dominate use #%d:%s in B%d\n", use->id(),
-          use->op()->mnemonic(), result->id());
-    return result;
-  }
-
-  void ScheduleNode(BasicBlock* block, Node* node) {
-    schedule_->PlanNode(block, node);
-    scheduler_->scheduled_nodes_[block->id()].push_back(node);
-
-    // Reduce the use count of the node's inputs to potentially make them
-    // schedulable.
-    for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) {
-      Scheduler::SchedulerData* data = scheduler_->GetData(*i);
-      DCHECK(data->unscheduled_count_ > 0);
-      --data->unscheduled_count_;
-      if (FLAG_trace_turbo_scheduler) {
-        Trace("  Use count for #%d:%s (used by #%d:%s)-- = %d\n", (*i)->id(),
-              (*i)->op()->mnemonic(), i.edge().from()->id(),
-              i.edge().from()->op()->mnemonic(), data->unscheduled_count_);
-        if (data->unscheduled_count_ == 0) {
-          Trace("  newly eligible #%d:%s\n", (*i)->id(),
-                (*i)->op()->mnemonic());
-        }
-      }
-    }
-  }
-
-  Scheduler* scheduler_;
-  Schedule* schedule_;
-};
-
-
-void Scheduler::ScheduleLate() {
-  Trace("------------------- SCHEDULE LATE -----------------\n");
-  if (FLAG_trace_turbo_scheduler) {
-    Trace("roots: ");
-    for (NodeVectorIter i = schedule_root_nodes_.begin();
-         i != schedule_root_nodes_.end(); ++i) {
-      Trace("#%d:%s ", (*i)->id(), (*i)->op()->mnemonic());
-    }
-    Trace("\n");
-  }
-
-  // Schedule: Places nodes in dominator block of all their uses.
-  ScheduleLateNodeVisitor schedule_late_visitor(this);
-
-  {
-    Zone zone(zone_->isolate());
-    GenericGraphVisit::Visit<ScheduleLateNodeVisitor,
-                             NodeInputIterationTraits<Node> >(
-        graph_, &zone, schedule_root_nodes_.begin(), schedule_root_nodes_.end(),
-        &schedule_late_visitor);
-  }
-
-  // Add collected nodes for basic blocks to their blocks in the right order.
-  int block_num = 0;
-  for (NodeVectorVectorIter i = scheduled_nodes_.begin();
-       i != scheduled_nodes_.end(); ++i) {
-    for (NodeVectorRIter j = i->rbegin(); j != i->rend(); ++j) {
-      schedule_->AddNode(schedule_->all_blocks_.at(block_num), *j);
-    }
-    block_num++;
-  }
-}
-
-
-bool Scheduler::ConnectFloatingControl() {
-  if (!has_floating_control_) return false;
-
-  Trace("Connecting floating control...\n");
-
-  // Process blocks and instructions backwards to find and connect floating
-  // control nodes into the control graph according to the block they were
-  // scheduled into.
-  int max = static_cast<int>(schedule_->rpo_order()->size());
-  for (int i = max - 1; i >= 0; i--) {
-    BasicBlock* block = schedule_->rpo_order()->at(i);
-    // TODO(titzer): we place at most one floating control structure per
-    // basic block because scheduling currently can interleave phis from
-    // one subgraph with the merges from another subgraph.
-    bool one_placed = false;
-    for (int j = static_cast<int>(block->nodes_.size()) - 1; j >= 0; j--) {
-      Node* node = block->nodes_[j];
-      SchedulerData* data = GetData(node);
-      if (data->is_floating_control_ && !data->is_connected_control_ &&
-          !one_placed) {
-        Trace("  Floating control #%d:%s was scheduled in B%d\n", node->id(),
-              node->op()->mnemonic(), block->id());
-        ConnectFloatingControlSubgraph(block, node);
-        one_placed = true;
-      }
-    }
-  }
-
-  return true;
-}
-
-
-void Scheduler::ConnectFloatingControlSubgraph(BasicBlock* block, Node* end) {
-  Node* block_start = block->nodes_[0];
-  DCHECK(IrOpcode::IsControlOpcode(block_start->opcode()));
-  // Find the current "control successor" of the node that starts the block
-  // by searching the control uses for a control input edge from a connected
-  // control node.
-  Node* control_succ = NULL;
-  for (UseIter i = block_start->uses().begin(); i != block_start->uses().end();
-       ++i) {
-    Node::Edge edge = i.edge();
-    if (NodeProperties::IsControlEdge(edge) &&
-        GetData(edge.from())->is_connected_control_) {
-      DCHECK_EQ(NULL, control_succ);
-      control_succ = edge.from();
-      control_succ->ReplaceInput(edge.index(), end);
-    }
-  }
-  DCHECK_NE(NULL, control_succ);
-  Trace("  Inserting floating control end %d:%s between %d:%s -> %d:%s\n",
-        end->id(), end->op()->mnemonic(), control_succ->id(),
-        control_succ->op()->mnemonic(), block_start->id(),
-        block_start->op()->mnemonic());
-
-  // Find the "start" node of the control subgraph, which should be the
-  // unique node that is itself floating control but has a control input that
-  // is not floating.
-  Node* start = NULL;
-  ZoneQueue<Node*> queue(zone_);
-  queue.push(end);
-  GetData(end)->is_connected_control_ = true;
-  while (!queue.empty()) {
-    Node* node = queue.front();
-    queue.pop();
-    Trace("  Search #%d:%s for control subgraph start\n", node->id(),
-          node->op()->mnemonic());
-    int max = NodeProperties::PastControlIndex(node);
-    for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) {
-      Node* input = node->InputAt(i);
-      SchedulerData* data = GetData(input);
-      if (data->is_floating_control_) {
-        // {input} is floating control.
-        if (!data->is_connected_control_) {
-          // First time seeing {input} during this traversal, queue it.
-          queue.push(input);
-          data->is_connected_control_ = true;
-        }
-      } else {
-        // Otherwise, {node} is the start node, because it is floating control
-        // but is connected to {input} that is not floating control.
-        DCHECK_EQ(NULL, start);  // There can be only one.
-        start = node;
-      }
-    }
-  }
-
-  DCHECK_NE(NULL, start);
-  start->ReplaceInput(NodeProperties::FirstControlIndex(start), block_start);
-
-  Trace("  Connecting floating control start %d:%s to %d:%s\n", start->id(),
-        start->op()->mnemonic(), block_start->id(),
-        block_start->op()->mnemonic());
-}
-
-
-// Numbering for BasicBlockData.rpo_number_ for this block traversal:
-static const int kBlockOnStack = -2;
-static const int kBlockVisited1 = -3;
-static const int kBlockVisited2 = -4;
-static const int kBlockUnvisited1 = -1;
-static const int kBlockUnvisited2 = kBlockVisited1;
-
-struct SpecialRPOStackFrame {
-  BasicBlock* block;
-  int index;
-};
-
-struct BlockList {
-  BasicBlock* block;
-  BlockList* next;
-
-  BlockList* Add(Zone* zone, BasicBlock* b) {
-    BlockList* list = static_cast<BlockList*>(zone->New(sizeof(BlockList)));
-    list->block = b;
-    list->next = this;
-    return list;
-  }
-
-  void Serialize(BasicBlockVector* final_order) {
-    for (BlockList* l = this; l != NULL; l = l->next) {
-      l->block->rpo_number_ = static_cast<int>(final_order->size());
-      final_order->push_back(l->block);
-    }
-  }
-};
-
-struct LoopInfo {
-  BasicBlock* header;
-  ZoneList<BasicBlock*>* outgoing;
-  BitVector* members;
-  LoopInfo* prev;
-  BlockList* end;
-  BlockList* start;
-
-  void AddOutgoing(Zone* zone, BasicBlock* block) {
-    if (outgoing == NULL) outgoing = new (zone) ZoneList<BasicBlock*>(2, zone);
-    outgoing->Add(block, zone);
-  }
-};
-
-
-static int Push(SpecialRPOStackFrame* stack, int depth, BasicBlock* child,
-                int unvisited) {
-  if (child->rpo_number_ == unvisited) {
-    stack[depth].block = child;
-    stack[depth].index = 0;
-    child->rpo_number_ = kBlockOnStack;
-    return depth + 1;
-  }
-  return depth;
-}
-
-
-// Computes loop membership from the backedges of the control flow graph.
-static LoopInfo* ComputeLoopInfo(
-    Zone* zone, SpecialRPOStackFrame* queue, int num_loops, int num_blocks,
-    ZoneList<std::pair<BasicBlock*, int> >* backedges) {
-  LoopInfo* loops = zone->NewArray<LoopInfo>(num_loops);
-  memset(loops, 0, num_loops * sizeof(LoopInfo));
-
-  // Compute loop membership starting from backedges.
-  // O(max(loop_depth) * max(|loop|)
-  for (int i = 0; i < backedges->length(); i++) {
-    BasicBlock* member = backedges->at(i).first;
-    BasicBlock* header = member->SuccessorAt(backedges->at(i).second);
-    int loop_num = header->loop_end_;
-    if (loops[loop_num].header == NULL) {
-      loops[loop_num].header = header;
-      loops[loop_num].members = new (zone) BitVector(num_blocks, zone);
-    }
-
-    int queue_length = 0;
-    if (member != header) {
-      // As long as the header doesn't have a backedge to itself,
-      // Push the member onto the queue and process its predecessors.
-      if (!loops[loop_num].members->Contains(member->id())) {
-        loops[loop_num].members->Add(member->id());
-      }
-      queue[queue_length++].block = member;
-    }
-
-    // Propagate loop membership backwards. All predecessors of M up to the
-    // loop header H are members of the loop too. O(|blocks between M and H|).
-    while (queue_length > 0) {
-      BasicBlock* block = queue[--queue_length].block;
-      for (int i = 0; i < block->PredecessorCount(); i++) {
-        BasicBlock* pred = block->PredecessorAt(i);
-        if (pred != header) {
-          if (!loops[loop_num].members->Contains(pred->id())) {
-            loops[loop_num].members->Add(pred->id());
-            queue[queue_length++].block = pred;
-          }
-        }
-      }
-    }
-  }
-  return loops;
-}
-
-
-#if DEBUG
-static void PrintRPO(int num_loops, LoopInfo* loops, BasicBlockVector* order) {
-  PrintF("-- RPO with %d loops ", num_loops);
-  if (num_loops > 0) {
-    PrintF("(");
-    for (int i = 0; i < num_loops; i++) {
-      if (i > 0) PrintF(" ");
-      PrintF("B%d", loops[i].header->id());
-    }
-    PrintF(") ");
-  }
-  PrintF("-- \n");
-
-  for (int i = 0; i < static_cast<int>(order->size()); i++) {
-    BasicBlock* block = (*order)[i];
-    int bid = block->id();
-    PrintF("%5d:", i);
-    for (int i = 0; i < num_loops; i++) {
-      bool membership = loops[i].members->Contains(bid);
-      bool range = loops[i].header->LoopContains(block);
-      PrintF(membership ? " |" : "  ");
-      PrintF(range ? "x" : " ");
-    }
-    PrintF("  B%d: ", bid);
-    if (block->loop_end_ >= 0) {
-      PrintF(" range: [%d, %d)", block->rpo_number_, block->loop_end_);
-    }
-    PrintF("\n");
-  }
-}
-
-
-static void VerifySpecialRPO(int num_loops, LoopInfo* loops,
-                             BasicBlockVector* order) {
-  DCHECK(order->size() > 0);
-  DCHECK((*order)[0]->id() == 0);  // entry should be first.
-
-  for (int i = 0; i < num_loops; i++) {
-    LoopInfo* loop = &loops[i];
-    BasicBlock* header = loop->header;
-
-    DCHECK(header != NULL);
-    DCHECK(header->rpo_number_ >= 0);
-    DCHECK(header->rpo_number_ < static_cast<int>(order->size()));
-    DCHECK(header->loop_end_ >= 0);
-    DCHECK(header->loop_end_ <= static_cast<int>(order->size()));
-    DCHECK(header->loop_end_ > header->rpo_number_);
-
-    // Verify the start ... end list relationship.
-    int links = 0;
-    BlockList* l = loop->start;
-    DCHECK(l != NULL && l->block == header);
-    bool end_found;
-    while (true) {
-      if (l == NULL || l == loop->end) {
-        end_found = (loop->end == l);
-        break;
-      }
-      // The list should be in same order as the final result.
-      DCHECK(l->block->rpo_number_ == links + loop->header->rpo_number_);
-      links++;
-      l = l->next;
-      DCHECK(links < static_cast<int>(2 * order->size()));  // cycle?
-    }
-    DCHECK(links > 0);
-    DCHECK(links == (header->loop_end_ - header->rpo_number_));
-    DCHECK(end_found);
-
-    // Check the contiguousness of loops.
-    int count = 0;
-    for (int j = 0; j < static_cast<int>(order->size()); j++) {
-      BasicBlock* block = order->at(j);
-      DCHECK(block->rpo_number_ == j);
-      if (j < header->rpo_number_ || j >= header->loop_end_) {
-        DCHECK(!loop->members->Contains(block->id()));
-      } else {
-        if (block == header) {
-          DCHECK(!loop->members->Contains(block->id()));
-        } else {
-          DCHECK(loop->members->Contains(block->id()));
-        }
-        count++;
-      }
-    }
-    DCHECK(links == count);
-  }
-}
-#endif  // DEBUG
+// -----------------------------------------------------------------------------
+// Phase 2: Compute special RPO and dominator tree.
 
 
 // Compute the special reverse-post-order block ordering, which is essentially
@@ -928,198 +539,945 @@
 //    headed at A.
 // 2. All loops are contiguous in the order (i.e. no intervening blocks that
 //    do not belong to the loop.)
-// Note a simple RPO traversal satisfies (1) but not (3).
-BasicBlockVector* Scheduler::ComputeSpecialRPO(Schedule* schedule) {
-  Zone tmp_zone(schedule->zone()->isolate());
-  Zone* zone = &tmp_zone;
-  Trace("------------- COMPUTING SPECIAL RPO ---------------\n");
-  // RPO should not have been computed for this schedule yet.
-  CHECK_EQ(kBlockUnvisited1, schedule->start()->rpo_number_);
-  CHECK_EQ(0, static_cast<int>(schedule->rpo_order_.size()));
+// Note a simple RPO traversal satisfies (1) but not (2).
+class SpecialRPONumberer : public ZoneObject {
+ public:
+  SpecialRPONumberer(Zone* zone, Schedule* schedule)
+      : zone_(zone),
+        schedule_(schedule),
+        order_(NULL),
+        beyond_end_(NULL),
+        loops_(zone),
+        backedges_(zone),
+        stack_(zone),
+        previous_block_count_(0) {}
 
-  // Perform an iterative RPO traversal using an explicit stack,
-  // recording backedges that form cycles. O(|B|).
-  ZoneList<std::pair<BasicBlock*, int> > backedges(1, zone);
-  SpecialRPOStackFrame* stack =
-      zone->NewArray<SpecialRPOStackFrame>(schedule->BasicBlockCount());
-  BasicBlock* entry = schedule->start();
-  BlockList* order = NULL;
-  int stack_depth = Push(stack, 0, entry, kBlockUnvisited1);
-  int num_loops = 0;
-
-  while (stack_depth > 0) {
-    int current = stack_depth - 1;
-    SpecialRPOStackFrame* frame = stack + current;
-
-    if (frame->index < frame->block->SuccessorCount()) {
-      // Process the next successor.
-      BasicBlock* succ = frame->block->SuccessorAt(frame->index++);
-      if (succ->rpo_number_ == kBlockVisited1) continue;
-      if (succ->rpo_number_ == kBlockOnStack) {
-        // The successor is on the stack, so this is a backedge (cycle).
-        backedges.Add(
-            std::pair<BasicBlock*, int>(frame->block, frame->index - 1), zone);
-        if (succ->loop_end_ < 0) {
-          // Assign a new loop number to the header if it doesn't have one.
-          succ->loop_end_ = num_loops++;
-        }
-      } else {
-        // Push the successor onto the stack.
-        DCHECK(succ->rpo_number_ == kBlockUnvisited1);
-        stack_depth = Push(stack, stack_depth, succ, kBlockUnvisited1);
-      }
-    } else {
-      // Finished with all successors; pop the stack and add the block.
-      order = order->Add(zone, frame->block);
-      frame->block->rpo_number_ = kBlockVisited1;
-      stack_depth--;
-    }
+  // Computes the special reverse-post-order for the main control flow graph,
+  // that is for the graph spanned between the schedule's start and end blocks.
+  void ComputeSpecialRPO() {
+    DCHECK(schedule_->end()->SuccessorCount() == 0);
+    DCHECK_EQ(NULL, order_);  // Main order does not exist yet.
+    ComputeAndInsertSpecialRPO(schedule_->start(), schedule_->end());
   }
 
-  // If no loops were encountered, then the order we computed was correct.
-  LoopInfo* loops = NULL;
-  if (num_loops != 0) {
-    // Otherwise, compute the loop information from the backedges in order
-    // to perform a traversal that groups loop bodies together.
-    loops = ComputeLoopInfo(zone, stack, num_loops, schedule->BasicBlockCount(),
-                            &backedges);
+  // Computes the special reverse-post-order for a partial control flow graph,
+  // that is for the graph spanned between the given {entry} and {end} blocks,
+  // then updates the existing ordering with this new information.
+  void UpdateSpecialRPO(BasicBlock* entry, BasicBlock* end) {
+    DCHECK_NE(NULL, order_);  // Main order to be updated is present.
+    ComputeAndInsertSpecialRPO(entry, end);
+  }
 
-    // Initialize the "loop stack". Note the entry could be a loop header.
-    LoopInfo* loop = entry->IsLoopHeader() ? &loops[entry->loop_end_] : NULL;
-    order = NULL;
+  // Serialize the previously computed order as a special reverse-post-order
+  // numbering for basic blocks into the final schedule.
+  void SerializeRPOIntoSchedule() {
+    int32_t number = 0;
+    for (BasicBlock* b = order_; b != NULL; b = b->rpo_next()) {
+      b->set_rpo_number(number++);
+      schedule_->rpo_order()->push_back(b);
+    }
+    BeyondEndSentinel()->set_rpo_number(number);
+  }
 
-    // Perform an iterative post-order traversal, visiting loop bodies before
-    // edges that lead out of loops. Visits each block once, but linking loop
-    // sections together is linear in the loop size, so overall is
-    // O(|B| + max(loop_depth) * max(|loop|))
-    stack_depth = Push(stack, 0, entry, kBlockUnvisited2);
-    while (stack_depth > 0) {
-      SpecialRPOStackFrame* frame = stack + (stack_depth - 1);
-      BasicBlock* block = frame->block;
-      BasicBlock* succ = NULL;
+  // Print and verify the special reverse-post-order.
+  void PrintAndVerifySpecialRPO() {
+#if DEBUG
+    if (FLAG_trace_turbo_scheduler) PrintRPO();
+    VerifySpecialRPO();
+#endif
+  }
 
-      if (frame->index < block->SuccessorCount()) {
-        // Process the next normal successor.
-        succ = block->SuccessorAt(frame->index++);
-      } else if (block->IsLoopHeader()) {
-        // Process additional outgoing edges from the loop header.
-        if (block->rpo_number_ == kBlockOnStack) {
-          // Finish the loop body the first time the header is left on the
-          // stack.
-          DCHECK(loop != NULL && loop->header == block);
-          loop->start = order->Add(zone, block);
-          order = loop->end;
-          block->rpo_number_ = kBlockVisited2;
-          // Pop the loop stack and continue visiting outgoing edges within the
-          // the context of the outer loop, if any.
-          loop = loop->prev;
-          // We leave the loop header on the stack; the rest of this iteration
-          // and later iterations will go through its outgoing edges list.
-        }
+ private:
+  typedef std::pair<BasicBlock*, size_t> Backedge;
 
-        // Use the next outgoing edge if there are any.
-        int outgoing_index = frame->index - block->SuccessorCount();
-        LoopInfo* info = &loops[block->loop_end_];
-        DCHECK(loop != info);
-        if (info->outgoing != NULL &&
-            outgoing_index < info->outgoing->length()) {
-          succ = info->outgoing->at(outgoing_index);
-          frame->index++;
-        }
+  // Numbering for BasicBlock::rpo_number for this block traversal:
+  static const int kBlockOnStack = -2;
+  static const int kBlockVisited1 = -3;
+  static const int kBlockVisited2 = -4;
+  static const int kBlockUnvisited1 = -1;
+  static const int kBlockUnvisited2 = kBlockVisited1;
+
+  struct SpecialRPOStackFrame {
+    BasicBlock* block;
+    size_t index;
+  };
+
+  struct LoopInfo {
+    BasicBlock* header;
+    ZoneList<BasicBlock*>* outgoing;
+    BitVector* members;
+    LoopInfo* prev;
+    BasicBlock* end;
+    BasicBlock* start;
+
+    void AddOutgoing(Zone* zone, BasicBlock* block) {
+      if (outgoing == NULL) {
+        outgoing = new (zone) ZoneList<BasicBlock*>(2, zone);
       }
+      outgoing->Add(block, zone);
+    }
+  };
 
-      if (succ != NULL) {
+  int Push(ZoneVector<SpecialRPOStackFrame>& stack, int depth,
+           BasicBlock* child, int unvisited) {
+    if (child->rpo_number() == unvisited) {
+      stack[depth].block = child;
+      stack[depth].index = 0;
+      child->set_rpo_number(kBlockOnStack);
+      return depth + 1;
+    }
+    return depth;
+  }
+
+  BasicBlock* PushFront(BasicBlock* head, BasicBlock* block) {
+    block->set_rpo_next(head);
+    return block;
+  }
+
+  static int GetLoopNumber(BasicBlock* block) { return block->loop_number(); }
+  static void SetLoopNumber(BasicBlock* block, int loop_number) {
+    return block->set_loop_number(loop_number);
+  }
+  static bool HasLoopNumber(BasicBlock* block) {
+    return block->loop_number() >= 0;
+  }
+
+  // TODO(mstarzinger): We only need this special sentinel because some tests
+  // use the schedule's end block in actual control flow (e.g. with end having
+  // successors). Once this has been cleaned up we can use the end block here.
+  BasicBlock* BeyondEndSentinel() {
+    if (beyond_end_ == NULL) {
+      BasicBlock::Id id = BasicBlock::Id::FromInt(-1);
+      beyond_end_ = new (schedule_->zone()) BasicBlock(schedule_->zone(), id);
+    }
+    return beyond_end_;
+  }
+
+  // Compute special RPO for the control flow graph between {entry} and {end},
+  // mutating any existing order so that the result is still valid.
+  void ComputeAndInsertSpecialRPO(BasicBlock* entry, BasicBlock* end) {
+    // RPO should not have been serialized for this schedule yet.
+    CHECK_EQ(kBlockUnvisited1, schedule_->start()->loop_number());
+    CHECK_EQ(kBlockUnvisited1, schedule_->start()->rpo_number());
+    CHECK_EQ(0, static_cast<int>(schedule_->rpo_order()->size()));
+
+    // Find correct insertion point within existing order.
+    BasicBlock* insertion_point = entry->rpo_next();
+    BasicBlock* order = insertion_point;
+
+    // Perform an iterative RPO traversal using an explicit stack,
+    // recording backedges that form cycles. O(|B|).
+    DCHECK_LT(previous_block_count_, schedule_->BasicBlockCount());
+    stack_.resize(schedule_->BasicBlockCount() - previous_block_count_);
+    previous_block_count_ = schedule_->BasicBlockCount();
+    int stack_depth = Push(stack_, 0, entry, kBlockUnvisited1);
+    int num_loops = static_cast<int>(loops_.size());
+
+    while (stack_depth > 0) {
+      int current = stack_depth - 1;
+      SpecialRPOStackFrame* frame = &stack_[current];
+
+      if (frame->block != end &&
+          frame->index < frame->block->SuccessorCount()) {
         // Process the next successor.
-        if (succ->rpo_number_ == kBlockOnStack) continue;
-        if (succ->rpo_number_ == kBlockVisited2) continue;
-        DCHECK(succ->rpo_number_ == kBlockUnvisited2);
-        if (loop != NULL && !loop->members->Contains(succ->id())) {
-          // The successor is not in the current loop or any nested loop.
-          // Add it to the outgoing edges of this loop and visit it later.
-          loop->AddOutgoing(zone, succ);
+        BasicBlock* succ = frame->block->SuccessorAt(frame->index++);
+        if (succ->rpo_number() == kBlockVisited1) continue;
+        if (succ->rpo_number() == kBlockOnStack) {
+          // The successor is on the stack, so this is a backedge (cycle).
+          backedges_.push_back(Backedge(frame->block, frame->index - 1));
+          if (!HasLoopNumber(succ)) {
+            // Assign a new loop number to the header if it doesn't have one.
+            SetLoopNumber(succ, num_loops++);
+          }
         } else {
           // Push the successor onto the stack.
-          stack_depth = Push(stack, stack_depth, succ, kBlockUnvisited2);
-          if (succ->IsLoopHeader()) {
-            // Push the inner loop onto the loop stack.
-            DCHECK(succ->loop_end_ >= 0 && succ->loop_end_ < num_loops);
-            LoopInfo* next = &loops[succ->loop_end_];
-            next->end = order;
-            next->prev = loop;
-            loop = next;
-          }
+          DCHECK(succ->rpo_number() == kBlockUnvisited1);
+          stack_depth = Push(stack_, stack_depth, succ, kBlockUnvisited1);
         }
       } else {
-        // Finished with all successors of the current block.
-        if (block->IsLoopHeader()) {
-          // If we are going to pop a loop header, then add its entire body.
-          LoopInfo* info = &loops[block->loop_end_];
-          for (BlockList* l = info->start; true; l = l->next) {
-            if (l->next == info->end) {
-              l->next = order;
-              info->end = order;
-              break;
-            }
-          }
-          order = info->start;
-        } else {
-          // Pop a single node off the stack and add it to the order.
-          order = order->Add(zone, block);
-          block->rpo_number_ = kBlockVisited2;
-        }
+        // Finished with all successors; pop the stack and add the block.
+        order = PushFront(order, frame->block);
+        frame->block->set_rpo_number(kBlockVisited1);
         stack_depth--;
       }
     }
-  }
 
-  // Construct the final order from the list.
-  BasicBlockVector* final_order = &schedule->rpo_order_;
-  order->Serialize(final_order);
+    // If no loops were encountered, then the order we computed was correct.
+    if (num_loops > static_cast<int>(loops_.size())) {
+      // Otherwise, compute the loop information from the backedges in order
+      // to perform a traversal that groups loop bodies together.
+      ComputeLoopInfo(stack_, num_loops, &backedges_);
 
-  // Compute the correct loop header for every block and set the correct loop
-  // ends.
-  LoopInfo* current_loop = NULL;
-  BasicBlock* current_header = NULL;
-  int loop_depth = 0;
-  for (BasicBlockVectorIter i = final_order->begin(); i != final_order->end();
-       ++i) {
-    BasicBlock* current = *i;
-    current->loop_header_ = current_header;
-    if (current->IsLoopHeader()) {
-      loop_depth++;
-      current_loop = &loops[current->loop_end_];
-      BlockList* end = current_loop->end;
-      current->loop_end_ = end == NULL ? static_cast<int>(final_order->size())
-                                       : end->block->rpo_number_;
-      current_header = current_loop->header;
-      Trace("B%d is a loop header, increment loop depth to %d\n", current->id(),
-            loop_depth);
-    } else {
-      while (current_header != NULL &&
-             current->rpo_number_ >= current_header->loop_end_) {
+      // Initialize the "loop stack". Note the entry could be a loop header.
+      LoopInfo* loop =
+          HasLoopNumber(entry) ? &loops_[GetLoopNumber(entry)] : NULL;
+      order = insertion_point;
+
+      // Perform an iterative post-order traversal, visiting loop bodies before
+      // edges that lead out of loops. Visits each block once, but linking loop
+      // sections together is linear in the loop size, so overall is
+      // O(|B| + max(loop_depth) * max(|loop|))
+      stack_depth = Push(stack_, 0, entry, kBlockUnvisited2);
+      while (stack_depth > 0) {
+        SpecialRPOStackFrame* frame = &stack_[stack_depth - 1];
+        BasicBlock* block = frame->block;
+        BasicBlock* succ = NULL;
+
+        if (block != end && frame->index < block->SuccessorCount()) {
+          // Process the next normal successor.
+          succ = block->SuccessorAt(frame->index++);
+        } else if (HasLoopNumber(block)) {
+          // Process additional outgoing edges from the loop header.
+          if (block->rpo_number() == kBlockOnStack) {
+            // Finish the loop body the first time the header is left on the
+            // stack.
+            DCHECK(loop != NULL && loop->header == block);
+            loop->start = PushFront(order, block);
+            order = loop->end;
+            block->set_rpo_number(kBlockVisited2);
+            // Pop the loop stack and continue visiting outgoing edges within
+            // the context of the outer loop, if any.
+            loop = loop->prev;
+            // We leave the loop header on the stack; the rest of this iteration
+            // and later iterations will go through its outgoing edges list.
+          }
+
+          // Use the next outgoing edge if there are any.
+          int outgoing_index =
+              static_cast<int>(frame->index - block->SuccessorCount());
+          LoopInfo* info = &loops_[GetLoopNumber(block)];
+          DCHECK(loop != info);
+          if (block != entry && info->outgoing != NULL &&
+              outgoing_index < info->outgoing->length()) {
+            succ = info->outgoing->at(outgoing_index);
+            frame->index++;
+          }
+        }
+
+        if (succ != NULL) {
+          // Process the next successor.
+          if (succ->rpo_number() == kBlockOnStack) continue;
+          if (succ->rpo_number() == kBlockVisited2) continue;
+          DCHECK(succ->rpo_number() == kBlockUnvisited2);
+          if (loop != NULL && !loop->members->Contains(succ->id().ToInt())) {
+            // The successor is not in the current loop or any nested loop.
+            // Add it to the outgoing edges of this loop and visit it later.
+            loop->AddOutgoing(zone_, succ);
+          } else {
+            // Push the successor onto the stack.
+            stack_depth = Push(stack_, stack_depth, succ, kBlockUnvisited2);
+            if (HasLoopNumber(succ)) {
+              // Push the inner loop onto the loop stack.
+              DCHECK(GetLoopNumber(succ) < num_loops);
+              LoopInfo* next = &loops_[GetLoopNumber(succ)];
+              next->end = order;
+              next->prev = loop;
+              loop = next;
+            }
+          }
+        } else {
+          // Finished with all successors of the current block.
+          if (HasLoopNumber(block)) {
+            // If we are going to pop a loop header, then add its entire body.
+            LoopInfo* info = &loops_[GetLoopNumber(block)];
+            for (BasicBlock* b = info->start; true; b = b->rpo_next()) {
+              if (b->rpo_next() == info->end) {
+                b->set_rpo_next(order);
+                info->end = order;
+                break;
+              }
+            }
+            order = info->start;
+          } else {
+            // Pop a single node off the stack and add it to the order.
+            order = PushFront(order, block);
+            block->set_rpo_number(kBlockVisited2);
+          }
+          stack_depth--;
+        }
+      }
+    }
+
+    // Publish new order the first time.
+    if (order_ == NULL) order_ = order;
+
+    // Compute the correct loop headers and set the correct loop ends.
+    LoopInfo* current_loop = NULL;
+    BasicBlock* current_header = entry->loop_header();
+    int32_t loop_depth = entry->loop_depth();
+    if (entry->IsLoopHeader()) --loop_depth;  // Entry might be a loop header.
+    for (BasicBlock* b = order; b != insertion_point; b = b->rpo_next()) {
+      BasicBlock* current = b;
+
+      // Reset BasicBlock::rpo_number again.
+      current->set_rpo_number(kBlockUnvisited1);
+
+      // Finish the previous loop(s) if we just exited them.
+      while (current_header != NULL && current == current_header->loop_end()) {
         DCHECK(current_header->IsLoopHeader());
         DCHECK(current_loop != NULL);
         current_loop = current_loop->prev;
         current_header = current_loop == NULL ? NULL : current_loop->header;
         --loop_depth;
       }
+      current->set_loop_header(current_header);
+
+      // Push a new loop onto the stack if this loop is a loop header.
+      if (HasLoopNumber(current)) {
+        ++loop_depth;
+        current_loop = &loops_[GetLoopNumber(current)];
+        BasicBlock* end = current_loop->end;
+        current->set_loop_end(end == NULL ? BeyondEndSentinel() : end);
+        current_header = current_loop->header;
+        Trace("B%d is a loop header, increment loop depth to %d\n",
+              current->id().ToInt(), loop_depth);
+      }
+
+      current->set_loop_depth(loop_depth);
+
+      if (current->loop_header() == NULL) {
+        Trace("B%d is not in a loop (depth == %d)\n", current->id().ToInt(),
+              current->loop_depth());
+      } else {
+        Trace("B%d has loop header B%d, (depth == %d)\n", current->id().ToInt(),
+              current->loop_header()->id().ToInt(), current->loop_depth());
+      }
     }
-    current->loop_depth_ = loop_depth;
-    if (current->loop_header_ == NULL) {
-      Trace("B%d is not in a loop (depth == %d)\n", current->id(),
-            current->loop_depth_);
-    } else {
-      Trace("B%d has loop header B%d, (depth == %d)\n", current->id(),
-            current->loop_header_->id(), current->loop_depth_);
+  }
+
+  // Computes loop membership from the backedges of the control flow graph.
+  void ComputeLoopInfo(ZoneVector<SpecialRPOStackFrame>& queue,
+                       size_t num_loops, ZoneVector<Backedge>* backedges) {
+    // Extend existing loop membership vectors.
+    for (LoopInfo& loop : loops_) {
+      BitVector* new_members = new (zone_)
+          BitVector(static_cast<int>(schedule_->BasicBlockCount()), zone_);
+      new_members->CopyFrom(*loop.members);
+      loop.members = new_members;
+    }
+
+    // Extend loop information vector.
+    loops_.resize(num_loops, LoopInfo());
+
+    // Compute loop membership starting from backedges.
+    // O(max(loop_depth) * max(|loop|)
+    for (size_t i = 0; i < backedges->size(); i++) {
+      BasicBlock* member = backedges->at(i).first;
+      BasicBlock* header = member->SuccessorAt(backedges->at(i).second);
+      size_t loop_num = GetLoopNumber(header);
+      if (loops_[loop_num].header == NULL) {
+        loops_[loop_num].header = header;
+        loops_[loop_num].members = new (zone_)
+            BitVector(static_cast<int>(schedule_->BasicBlockCount()), zone_);
+      }
+
+      int queue_length = 0;
+      if (member != header) {
+        // As long as the header doesn't have a backedge to itself,
+        // Push the member onto the queue and process its predecessors.
+        if (!loops_[loop_num].members->Contains(member->id().ToInt())) {
+          loops_[loop_num].members->Add(member->id().ToInt());
+        }
+        queue[queue_length++].block = member;
+      }
+
+      // Propagate loop membership backwards. All predecessors of M up to the
+      // loop header H are members of the loop too. O(|blocks between M and H|).
+      while (queue_length > 0) {
+        BasicBlock* block = queue[--queue_length].block;
+        for (size_t i = 0; i < block->PredecessorCount(); i++) {
+          BasicBlock* pred = block->PredecessorAt(i);
+          if (pred != header) {
+            if (!loops_[loop_num].members->Contains(pred->id().ToInt())) {
+              loops_[loop_num].members->Add(pred->id().ToInt());
+              queue[queue_length++].block = pred;
+            }
+          }
+        }
+      }
     }
   }
 
 #if DEBUG
-  if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order);
-  VerifySpecialRPO(num_loops, loops, final_order);
+  void PrintRPO() {
+    OFStream os(stdout);
+    os << "RPO with " << loops_.size() << " loops";
+    if (loops_.size() > 0) {
+      os << " (";
+      for (size_t i = 0; i < loops_.size(); i++) {
+        if (i > 0) os << " ";
+        os << "B" << loops_[i].header->id();
+      }
+      os << ")";
+    }
+    os << ":\n";
+
+    for (BasicBlock* block = order_; block != NULL; block = block->rpo_next()) {
+      BasicBlock::Id bid = block->id();
+      // TODO(jarin,svenpanne): Add formatting here once we have support for
+      // that in streams (we want an equivalent of PrintF("%5d:", x) here).
+      os << "  " << block->rpo_number() << ":";
+      for (size_t i = 0; i < loops_.size(); i++) {
+        bool range = loops_[i].header->LoopContains(block);
+        bool membership = loops_[i].header != block && range;
+        os << (membership ? " |" : "  ");
+        os << (range ? "x" : " ");
+      }
+      os << "  B" << bid << ": ";
+      if (block->loop_end() != NULL) {
+        os << " range: [" << block->rpo_number() << ", "
+           << block->loop_end()->rpo_number() << ")";
+      }
+      if (block->loop_header() != NULL) {
+        os << " header: B" << block->loop_header()->id();
+      }
+      if (block->loop_depth() > 0) {
+        os << " depth: " << block->loop_depth();
+      }
+      os << "\n";
+    }
+  }
+
+  void VerifySpecialRPO() {
+    BasicBlockVector* order = schedule_->rpo_order();
+    DCHECK(order->size() > 0);
+    DCHECK((*order)[0]->id().ToInt() == 0);  // entry should be first.
+
+    for (size_t i = 0; i < loops_.size(); i++) {
+      LoopInfo* loop = &loops_[i];
+      BasicBlock* header = loop->header;
+      BasicBlock* end = header->loop_end();
+
+      DCHECK(header != NULL);
+      DCHECK(header->rpo_number() >= 0);
+      DCHECK(header->rpo_number() < static_cast<int>(order->size()));
+      DCHECK(end != NULL);
+      DCHECK(end->rpo_number() <= static_cast<int>(order->size()));
+      DCHECK(end->rpo_number() > header->rpo_number());
+      DCHECK(header->loop_header() != header);
+
+      // Verify the start ... end list relationship.
+      int links = 0;
+      BasicBlock* block = loop->start;
+      DCHECK_EQ(header, block);
+      bool end_found;
+      while (true) {
+        if (block == NULL || block == loop->end) {
+          end_found = (loop->end == block);
+          break;
+        }
+        // The list should be in same order as the final result.
+        DCHECK(block->rpo_number() == links + header->rpo_number());
+        links++;
+        block = block->rpo_next();
+        DCHECK(links < static_cast<int>(2 * order->size()));  // cycle?
+      }
+      DCHECK(links > 0);
+      DCHECK(links == end->rpo_number() - header->rpo_number());
+      DCHECK(end_found);
+
+      // Check loop depth of the header.
+      int loop_depth = 0;
+      for (LoopInfo* outer = loop; outer != NULL; outer = outer->prev) {
+        loop_depth++;
+      }
+      DCHECK_EQ(loop_depth, header->loop_depth());
+
+      // Check the contiguousness of loops.
+      int count = 0;
+      for (int j = 0; j < static_cast<int>(order->size()); j++) {
+        BasicBlock* block = order->at(j);
+        DCHECK(block->rpo_number() == j);
+        if (j < header->rpo_number() || j >= end->rpo_number()) {
+          DCHECK(!header->LoopContains(block));
+        } else {
+          DCHECK(header->LoopContains(block));
+          DCHECK_GE(block->loop_depth(), loop_depth);
+          count++;
+        }
+      }
+      DCHECK(links == count);
+    }
+  }
+#endif  // DEBUG
+
+  Zone* zone_;
+  Schedule* schedule_;
+  BasicBlock* order_;
+  BasicBlock* beyond_end_;
+  ZoneVector<LoopInfo> loops_;
+  ZoneVector<Backedge> backedges_;
+  ZoneVector<SpecialRPOStackFrame> stack_;
+  size_t previous_block_count_;
+};
+
+
+BasicBlockVector* Scheduler::ComputeSpecialRPO(Zone* zone, Schedule* schedule) {
+  SpecialRPONumberer numberer(zone, schedule);
+  numberer.ComputeSpecialRPO();
+  numberer.SerializeRPOIntoSchedule();
+  numberer.PrintAndVerifySpecialRPO();
+  return schedule->rpo_order();
+}
+
+
+void Scheduler::ComputeSpecialRPONumbering() {
+  Trace("--- COMPUTING SPECIAL RPO ----------------------------------\n");
+
+  // Compute the special reverse-post-order for basic blocks.
+  special_rpo_ = new (zone_) SpecialRPONumberer(zone_, schedule_);
+  special_rpo_->ComputeSpecialRPO();
+}
+
+
+void Scheduler::PropagateImmediateDominators(BasicBlock* block) {
+  for (/*nop*/; block != NULL; block = block->rpo_next()) {
+    BasicBlock::Predecessors::iterator pred = block->predecessors_begin();
+    BasicBlock::Predecessors::iterator end = block->predecessors_end();
+    DCHECK(pred != end);  // All blocks except start have predecessors.
+    BasicBlock* dominator = *pred;
+    // For multiple predecessors, walk up the dominator tree until a common
+    // dominator is found. Visitation order guarantees that all predecessors
+    // except for backwards edges have been visited.
+    for (++pred; pred != end; ++pred) {
+      // Don't examine backwards edges.
+      if ((*pred)->dominator_depth() < 0) continue;
+      dominator = GetCommonDominator(dominator, *pred);
+    }
+    block->set_dominator(dominator);
+    block->set_dominator_depth(dominator->dominator_depth() + 1);
+    // Propagate "deferredness" of the dominator.
+    if (dominator->deferred()) block->set_deferred(true);
+    Trace("Block B%d's idom is B%d, depth = %d\n", block->id().ToInt(),
+          dominator->id().ToInt(), block->dominator_depth());
+  }
+}
+
+
+void Scheduler::GenerateImmediateDominatorTree() {
+  Trace("--- IMMEDIATE BLOCK DOMINATORS -----------------------------\n");
+
+  // Seed start block to be the first dominator.
+  schedule_->start()->set_dominator_depth(0);
+
+  // Build the block dominator tree resulting from the above seed.
+  PropagateImmediateDominators(schedule_->start()->rpo_next());
+}
+
+
+// -----------------------------------------------------------------------------
+// Phase 3: Prepare use counts for nodes.
+
+
+class PrepareUsesVisitor : public NullNodeVisitor {
+ public:
+  explicit PrepareUsesVisitor(Scheduler* scheduler)
+      : scheduler_(scheduler), schedule_(scheduler->schedule_) {}
+
+  void Pre(Node* node) {
+    if (scheduler_->GetPlacement(node) == Scheduler::kFixed) {
+      // Fixed nodes are always roots for schedule late.
+      scheduler_->schedule_root_nodes_.push_back(node);
+      if (!schedule_->IsScheduled(node)) {
+        // Make sure root nodes are scheduled in their respective blocks.
+        Trace("Scheduling fixed position node #%d:%s\n", node->id(),
+              node->op()->mnemonic());
+        IrOpcode::Value opcode = node->opcode();
+        BasicBlock* block =
+            opcode == IrOpcode::kParameter
+                ? schedule_->start()
+                : schedule_->block(NodeProperties::GetControlInput(node));
+        DCHECK(block != NULL);
+        schedule_->AddNode(block, node);
+      }
+    }
+  }
+
+  void PostEdge(Node* from, int index, Node* to) {
+    // If the edge is from an unscheduled node, then tally it in the use count
+    // for all of its inputs. The same criterion will be used in ScheduleLate
+    // for decrementing use counts.
+    if (!schedule_->IsScheduled(from)) {
+      DCHECK_NE(Scheduler::kFixed, scheduler_->GetPlacement(from));
+      scheduler_->IncrementUnscheduledUseCount(to, index, from);
+    }
+  }
+
+ private:
+  Scheduler* scheduler_;
+  Schedule* schedule_;
+};
+
+
+void Scheduler::PrepareUses() {
+  Trace("--- PREPARE USES -------------------------------------------\n");
+
+  // Count the uses of every node, it will be used to ensure that all of a
+  // node's uses are scheduled before the node itself.
+  PrepareUsesVisitor prepare_uses(this);
+  graph_->VisitNodeInputsFromEnd(&prepare_uses);
+}
+
+
+// -----------------------------------------------------------------------------
+// Phase 4: Schedule nodes early.
+
+
+class ScheduleEarlyNodeVisitor {
+ public:
+  ScheduleEarlyNodeVisitor(Zone* zone, Scheduler* scheduler)
+      : scheduler_(scheduler), schedule_(scheduler->schedule_), queue_(zone) {}
+
+  // Run the schedule early algorithm on a set of fixed root nodes.
+  void Run(NodeVector* roots) {
+    for (NodeVectorIter i = roots->begin(); i != roots->end(); ++i) {
+      queue_.push(*i);
+      while (!queue_.empty()) {
+        VisitNode(queue_.front());
+        queue_.pop();
+      }
+    }
+  }
+
+ private:
+  // Visits one node from the queue and propagates its current schedule early
+  // position to all uses. This in turn might push more nodes onto the queue.
+  void VisitNode(Node* node) {
+    Scheduler::SchedulerData* data = scheduler_->GetData(node);
+
+    // Fixed nodes already know their schedule early position.
+    if (scheduler_->GetPlacement(node) == Scheduler::kFixed) {
+      data->minimum_block_ = schedule_->block(node);
+      Trace("Fixing #%d:%s minimum_block = B%d, dominator_depth = %d\n",
+            node->id(), node->op()->mnemonic(),
+            data->minimum_block_->id().ToInt(),
+            data->minimum_block_->dominator_depth());
+    }
+
+    // No need to propagate unconstrained schedule early positions.
+    if (data->minimum_block_ == schedule_->start()) return;
+
+    // Propagate schedule early position.
+    DCHECK(data->minimum_block_ != NULL);
+    Node::Uses uses = node->uses();
+    for (Node::Uses::iterator i = uses.begin(); i != uses.end(); ++i) {
+      PropagateMinimumPositionToNode(data->minimum_block_, *i);
+    }
+  }
+
+  // Propagates {block} as another minimum position into the given {node}. This
+  // has the net effect of computing the minimum dominator block of {node} that
+  // still post-dominates all inputs to {node} when the queue is processed.
+  void PropagateMinimumPositionToNode(BasicBlock* block, Node* node) {
+    Scheduler::SchedulerData* data = scheduler_->GetData(node);
+
+    // No need to propagate to fixed node, it's guaranteed to be a root.
+    if (scheduler_->GetPlacement(node) == Scheduler::kFixed) return;
+
+    // Coupled nodes influence schedule early position of their control.
+    if (scheduler_->GetPlacement(node) == Scheduler::kCoupled) {
+      Node* control = NodeProperties::GetControlInput(node);
+      PropagateMinimumPositionToNode(block, control);
+    }
+
+    // Propagate new position if it is deeper down the dominator tree than the
+    // current. Note that all inputs need to have minimum block position inside
+    // the dominator chain of {node}'s minimum block position.
+    DCHECK(InsideSameDominatorChain(block, data->minimum_block_));
+    if (block->dominator_depth() > data->minimum_block_->dominator_depth()) {
+      data->minimum_block_ = block;
+      queue_.push(node);
+      Trace("Propagating #%d:%s minimum_block = B%d, dominator_depth = %d\n",
+            node->id(), node->op()->mnemonic(),
+            data->minimum_block_->id().ToInt(),
+            data->minimum_block_->dominator_depth());
+    }
+  }
+
+#if DEBUG
+  bool InsideSameDominatorChain(BasicBlock* b1, BasicBlock* b2) {
+    BasicBlock* dominator = scheduler_->GetCommonDominator(b1, b2);
+    return dominator == b1 || dominator == b2;
+  }
 #endif
-  return final_order;
+
+  Scheduler* scheduler_;
+  Schedule* schedule_;
+  ZoneQueue<Node*> queue_;
+};
+
+
+void Scheduler::ScheduleEarly() {
+  Trace("--- SCHEDULE EARLY -----------------------------------------\n");
+  if (FLAG_trace_turbo_scheduler) {
+    Trace("roots: ");
+    for (Node* node : schedule_root_nodes_) {
+      Trace("#%d:%s ", node->id(), node->op()->mnemonic());
+    }
+    Trace("\n");
+  }
+
+  // Compute the minimum block for each node thereby determining the earliest
+  // position each node could be placed within a valid schedule.
+  ScheduleEarlyNodeVisitor schedule_early_visitor(zone_, this);
+  schedule_early_visitor.Run(&schedule_root_nodes_);
 }
+
+
+// -----------------------------------------------------------------------------
+// Phase 5: Schedule nodes late.
+
+
+class ScheduleLateNodeVisitor {
+ public:
+  ScheduleLateNodeVisitor(Zone* zone, Scheduler* scheduler)
+      : scheduler_(scheduler), schedule_(scheduler_->schedule_) {}
+
+  // Run the schedule late algorithm on a set of fixed root nodes.
+  void Run(NodeVector* roots) {
+    for (NodeVectorIter i = roots->begin(); i != roots->end(); ++i) {
+      ProcessQueue(*i);
+    }
+  }
+
+ private:
+  void ProcessQueue(Node* root) {
+    ZoneQueue<Node*>* queue = &(scheduler_->schedule_queue_);
+    for (Node* node : root->inputs()) {
+      // Don't schedule coupled nodes on their own.
+      if (scheduler_->GetPlacement(node) == Scheduler::kCoupled) {
+        node = NodeProperties::GetControlInput(node);
+      }
+
+      // Test schedulability condition by looking at unscheduled use count.
+      if (scheduler_->GetData(node)->unscheduled_count_ != 0) continue;
+
+      queue->push(node);
+      while (!queue->empty()) {
+        VisitNode(queue->front());
+        queue->pop();
+      }
+    }
+  }
+
+  // Visits one node from the queue of schedulable nodes and determines its
+  // schedule late position. Also hoists nodes out of loops to find a more
+  // optimal scheduling position.
+  void VisitNode(Node* node) {
+    DCHECK_EQ(0, scheduler_->GetData(node)->unscheduled_count_);
+
+    // Don't schedule nodes that are already scheduled.
+    if (schedule_->IsScheduled(node)) return;
+    DCHECK_EQ(Scheduler::kSchedulable, scheduler_->GetPlacement(node));
+
+    // Determine the dominating block for all of the uses of this node. It is
+    // the latest block that this node can be scheduled in.
+    Trace("Scheduling #%d:%s\n", node->id(), node->op()->mnemonic());
+    BasicBlock* block = GetCommonDominatorOfUses(node);
+    DCHECK_NOT_NULL(block);
+
+    // The schedule early block dominates the schedule late block.
+    BasicBlock* min_block = scheduler_->GetData(node)->minimum_block_;
+    DCHECK_EQ(min_block, scheduler_->GetCommonDominator(block, min_block));
+    Trace("Schedule late of #%d:%s is B%d at loop depth %d, minimum = B%d\n",
+          node->id(), node->op()->mnemonic(), block->id().ToInt(),
+          block->loop_depth(), min_block->id().ToInt());
+
+    // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively
+    // into enclosing loop pre-headers until they would preceed their schedule
+    // early position.
+    BasicBlock* hoist_block = GetPreHeader(block);
+    while (hoist_block != NULL &&
+           hoist_block->dominator_depth() >= min_block->dominator_depth()) {
+      Trace("  hoisting #%d:%s to block B%d\n", node->id(),
+            node->op()->mnemonic(), hoist_block->id().ToInt());
+      DCHECK_LT(hoist_block->loop_depth(), block->loop_depth());
+      block = hoist_block;
+      hoist_block = GetPreHeader(hoist_block);
+    }
+
+    // Schedule the node or a floating control structure.
+    if (NodeProperties::IsControl(node)) {
+      ScheduleFloatingControl(block, node);
+    } else {
+      ScheduleNode(block, node);
+    }
+  }
+
+  BasicBlock* GetPreHeader(BasicBlock* block) {
+    if (block->IsLoopHeader()) {
+      return block->dominator();
+    } else if (block->loop_header() != NULL) {
+      return block->loop_header()->dominator();
+    } else {
+      return NULL;
+    }
+  }
+
+  BasicBlock* GetCommonDominatorOfUses(Node* node) {
+    BasicBlock* block = NULL;
+    for (Edge edge : node->use_edges()) {
+      BasicBlock* use_block = GetBlockForUse(edge);
+      block = block == NULL ? use_block : use_block == NULL
+                                              ? block
+                                              : scheduler_->GetCommonDominator(
+                                                    block, use_block);
+    }
+    return block;
+  }
+
+  BasicBlock* GetBlockForUse(Edge edge) {
+    Node* use = edge.from();
+    IrOpcode::Value opcode = use->opcode();
+    if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) {
+      // If the use is from a coupled (i.e. floating) phi, compute the common
+      // dominator of its uses. This will not recurse more than one level.
+      if (scheduler_->GetPlacement(use) == Scheduler::kCoupled) {
+        Trace("  inspecting uses of coupled #%d:%s\n", use->id(),
+              use->op()->mnemonic());
+        DCHECK_EQ(edge.to(), NodeProperties::GetControlInput(use));
+        return GetCommonDominatorOfUses(use);
+      }
+      // If the use is from a fixed (i.e. non-floating) phi, use the block
+      // of the corresponding control input to the merge.
+      if (scheduler_->GetPlacement(use) == Scheduler::kFixed) {
+        Trace("  input@%d into a fixed phi #%d:%s\n", edge.index(), use->id(),
+              use->op()->mnemonic());
+        Node* merge = NodeProperties::GetControlInput(use, 0);
+        opcode = merge->opcode();
+        DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop);
+        use = NodeProperties::GetControlInput(merge, edge.index());
+      }
+    }
+    BasicBlock* result = schedule_->block(use);
+    if (result == NULL) return NULL;
+    Trace("  must dominate use #%d:%s in B%d\n", use->id(),
+          use->op()->mnemonic(), result->id().ToInt());
+    return result;
+  }
+
+  void ScheduleFloatingControl(BasicBlock* block, Node* node) {
+    scheduler_->FuseFloatingControl(block, node);
+  }
+
+  void ScheduleNode(BasicBlock* block, Node* node) {
+    schedule_->PlanNode(block, node);
+    scheduler_->scheduled_nodes_[block->id().ToSize()].push_back(node);
+    scheduler_->UpdatePlacement(node, Scheduler::kScheduled);
+  }
+
+  Scheduler* scheduler_;
+  Schedule* schedule_;
+};
+
+
+void Scheduler::ScheduleLate() {
+  Trace("--- SCHEDULE LATE ------------------------------------------\n");
+  if (FLAG_trace_turbo_scheduler) {
+    Trace("roots: ");
+    for (Node* node : schedule_root_nodes_) {
+      Trace("#%d:%s ", node->id(), node->op()->mnemonic());
+    }
+    Trace("\n");
+  }
+
+  // Schedule: Places nodes in dominator block of all their uses.
+  ScheduleLateNodeVisitor schedule_late_visitor(zone_, this);
+  schedule_late_visitor.Run(&schedule_root_nodes_);
 }
+
+
+// -----------------------------------------------------------------------------
+// Phase 6: Seal the final schedule.
+
+
+void Scheduler::SealFinalSchedule() {
+  Trace("--- SEAL FINAL SCHEDULE ------------------------------------\n");
+
+  // Serialize the assembly order and reverse-post-order numbering.
+  special_rpo_->SerializeRPOIntoSchedule();
+  special_rpo_->PrintAndVerifySpecialRPO();
+
+  // Add collected nodes for basic blocks to their blocks in the right order.
+  int block_num = 0;
+  for (NodeVector& nodes : scheduled_nodes_) {
+    BasicBlock::Id id = BasicBlock::Id::FromInt(block_num++);
+    BasicBlock* block = schedule_->GetBlockById(id);
+    for (NodeVectorRIter i = nodes.rbegin(); i != nodes.rend(); ++i) {
+      schedule_->AddNode(block, *i);
+    }
+  }
 }
-}  // namespace v8::internal::compiler
+
+
+// -----------------------------------------------------------------------------
+
+
+void Scheduler::FuseFloatingControl(BasicBlock* block, Node* node) {
+  Trace("--- FUSE FLOATING CONTROL ----------------------------------\n");
+  if (FLAG_trace_turbo_scheduler) {
+    OFStream os(stdout);
+    os << "Schedule before control flow fusion:\n" << *schedule_;
+  }
+
+  // Iterate on phase 1: Build control-flow graph.
+  control_flow_builder_->Run(block, node);
+
+  // Iterate on phase 2: Compute special RPO and dominator tree.
+  special_rpo_->UpdateSpecialRPO(block, schedule_->block(node));
+  // TODO(mstarzinger): Currently "iterate on" means "re-run". Fix that.
+  for (BasicBlock* b = block->rpo_next(); b != NULL; b = b->rpo_next()) {
+    b->set_dominator_depth(-1);
+    b->set_dominator(NULL);
+  }
+  PropagateImmediateDominators(block->rpo_next());
+
+  // Iterate on phase 4: Schedule nodes early.
+  // TODO(mstarzinger): The following loop gathering the propagation roots is a
+  // temporary solution and should be merged into the rest of the scheduler as
+  // soon as the approach settled for all floating loops.
+  NodeVector propagation_roots(control_flow_builder_->control_);
+  for (Node* node : control_flow_builder_->control_) {
+    for (Node* use : node->uses()) {
+      if (use->opcode() == IrOpcode::kPhi ||
+          use->opcode() == IrOpcode::kEffectPhi) {
+        propagation_roots.push_back(use);
+      }
+    }
+  }
+  if (FLAG_trace_turbo_scheduler) {
+    Trace("propagation roots: ");
+    for (Node* node : propagation_roots) {
+      Trace("#%d:%s ", node->id(), node->op()->mnemonic());
+    }
+    Trace("\n");
+  }
+  ScheduleEarlyNodeVisitor schedule_early_visitor(zone_, this);
+  schedule_early_visitor.Run(&propagation_roots);
+
+  // Move previously planned nodes.
+  // TODO(mstarzinger): Improve that by supporting bulk moves.
+  scheduled_nodes_.resize(schedule_->BasicBlockCount(), NodeVector(zone_));
+  MovePlannedNodes(block, schedule_->block(node));
+
+  if (FLAG_trace_turbo_scheduler) {
+    OFStream os(stdout);
+    os << "Schedule after control flow fusion:\n" << *schedule_;
+  }
+}
+
+
+void Scheduler::MovePlannedNodes(BasicBlock* from, BasicBlock* to) {
+  Trace("Move planned nodes from B%d to B%d\n", from->id().ToInt(),
+        to->id().ToInt());
+  NodeVector* nodes = &(scheduled_nodes_[from->id().ToSize()]);
+  for (NodeVectorIter i = nodes->begin(); i != nodes->end(); ++i) {
+    schedule_->SetBlockForNode(to, *i);
+    scheduled_nodes_[to->id().ToSize()].push_back(*i);
+  }
+  nodes->clear();
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/scheduler.h b/src/compiler/scheduler.h
index b21662f..9da0b6d 100644
--- a/src/compiler/scheduler.h
+++ b/src/compiler/scheduler.h
@@ -9,89 +9,106 @@
 
 #include "src/compiler/opcodes.h"
 #include "src/compiler/schedule.h"
+#include "src/compiler/zone-pool.h"
 #include "src/zone-containers.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
+class CFGBuilder;
+class ControlEquivalence;
+class SpecialRPONumberer;
+
 // Computes a schedule from a graph, placing nodes into basic blocks and
 // ordering the basic blocks in the special RPO order.
 class Scheduler {
  public:
-  // The complete scheduling algorithm.
-  // Create a new schedule and place all nodes from the graph into it.
-  static Schedule* ComputeSchedule(Graph* graph);
+  // The complete scheduling algorithm. Creates a new schedule and places all
+  // nodes from the graph into it.
+  static Schedule* ComputeSchedule(Zone* zone, Graph* graph);
 
   // Compute the RPO of blocks in an existing schedule.
-  static BasicBlockVector* ComputeSpecialRPO(Schedule* schedule);
-
-  // (Exposed for testing only)
-  // Build and connect the CFG for a node graph, but don't schedule nodes.
-  static void ComputeCFG(Graph* graph, Schedule* schedule);
+  static BasicBlockVector* ComputeSpecialRPO(Zone* zone, Schedule* schedule);
 
  private:
-  enum Placement { kUnknown, kSchedulable, kFixed };
+  // Placement of a node changes during scheduling. The placement state
+  // transitions over time while the scheduler is choosing a position:
+  //
+  //                   +---------------------+-----+----> kFixed
+  //                  /                     /     /
+  //    kUnknown ----+------> kCoupled ----+     /
+  //                  \                         /
+  //                   +----> kSchedulable ----+--------> kScheduled
+  //
+  // 1) GetPlacement(): kUnknown -> kCoupled|kSchedulable|kFixed
+  // 2) UpdatePlacement(): kCoupled|kSchedulable -> kFixed|kScheduled
+  enum Placement { kUnknown, kSchedulable, kFixed, kCoupled, kScheduled };
 
   // Per-node data tracked during scheduling.
   struct SchedulerData {
+    BasicBlock* minimum_block_;  // Minimum legal RPO placement.
     int unscheduled_count_;      // Number of unscheduled uses of this node.
-    int minimum_rpo_;            // Minimum legal RPO placement.
-    bool is_connected_control_;  // {true} if control-connected to the end node.
-    bool is_floating_control_;   // {true} if control, but not control-connected
-                                 // to the end node.
-    Placement placement_ : 3;    // Whether the node is fixed, schedulable,
-                                 // or not yet known.
+    Placement placement_;        // Whether the node is fixed, schedulable,
+                                 // coupled to another node, or not yet known.
   };
 
   Zone* zone_;
   Graph* graph_;
   Schedule* schedule_;
-  NodeVectorVector scheduled_nodes_;
-  NodeVector schedule_root_nodes_;
-  ZoneVector<SchedulerData> node_data_;
-  bool has_floating_control_;
+  NodeVectorVector scheduled_nodes_;     // Per-block list of nodes in reverse.
+  NodeVector schedule_root_nodes_;       // Fixed root nodes seed the worklist.
+  ZoneQueue<Node*> schedule_queue_;      // Worklist of schedulable nodes.
+  ZoneVector<SchedulerData> node_data_;  // Per-node data for all nodes.
+  CFGBuilder* control_flow_builder_;     // Builds basic blocks for controls.
+  SpecialRPONumberer* special_rpo_;      // Special RPO numbering of blocks.
+  ControlEquivalence* equivalence_;      // Control dependence equivalence.
 
   Scheduler(Zone* zone, Graph* graph, Schedule* schedule);
 
-  SchedulerData DefaultSchedulerData();
-
-  SchedulerData* GetData(Node* node) {
-    DCHECK(node->id() < static_cast<int>(node_data_.size()));
-    return &node_data_[node->id()];
-  }
-
-  void BuildCFG();
+  inline SchedulerData DefaultSchedulerData();
+  inline SchedulerData* GetData(Node* node);
 
   Placement GetPlacement(Node* node);
+  void UpdatePlacement(Node* node, Placement placement);
 
-  int GetRPONumber(BasicBlock* block) {
-    DCHECK(block->rpo_number_ >= 0 &&
-           block->rpo_number_ < static_cast<int>(schedule_->rpo_order_.size()));
-    DCHECK(schedule_->rpo_order_[block->rpo_number_] == block);
-    return block->rpo_number_;
-  }
+  inline bool IsCoupledControlEdge(Node* node, int index);
+  void IncrementUnscheduledUseCount(Node* node, int index, Node* from);
+  void DecrementUnscheduledUseCount(Node* node, int index, Node* from);
 
-  void GenerateImmediateDominatorTree();
   BasicBlock* GetCommonDominator(BasicBlock* b1, BasicBlock* b2);
+  void PropagateImmediateDominators(BasicBlock* block);
 
+  // Phase 1: Build control-flow graph.
   friend class CFGBuilder;
+  void BuildCFG();
 
-  friend class ScheduleEarlyNodeVisitor;
-  void ScheduleEarly();
+  // Phase 2: Compute special RPO and dominator tree.
+  friend class SpecialRPONumberer;
+  void ComputeSpecialRPONumbering();
+  void GenerateImmediateDominatorTree();
 
+  // Phase 3: Prepare use counts for nodes.
   friend class PrepareUsesVisitor;
   void PrepareUses();
 
+  // Phase 4: Schedule nodes early.
+  friend class ScheduleEarlyNodeVisitor;
+  void ScheduleEarly();
+
+  // Phase 5: Schedule nodes late.
   friend class ScheduleLateNodeVisitor;
   void ScheduleLate();
 
-  bool ConnectFloatingControl();
+  // Phase 6: Seal the final schedule.
+  void SealFinalSchedule();
 
-  void ConnectFloatingControlSubgraph(BasicBlock* block, Node* node);
+  void FuseFloatingControl(BasicBlock* block, Node* node);
+  void MovePlannedNodes(BasicBlock* from, BasicBlock* to);
 };
-}
-}
-}  // namespace v8::internal::compiler
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_SCHEDULER_H_
diff --git a/src/compiler/select-lowering.cc b/src/compiler/select-lowering.cc
new file mode 100644
index 0000000..edecf58
--- /dev/null
+++ b/src/compiler/select-lowering.cc
@@ -0,0 +1,86 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/select-lowering.h"
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/diamond.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/node.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+SelectLowering::SelectLowering(Graph* graph, CommonOperatorBuilder* common)
+    : common_(common),
+      graph_(graph),
+      merges_(Merges::key_compare(), Merges::allocator_type(graph->zone())) {}
+
+
+SelectLowering::~SelectLowering() {}
+
+
+Reduction SelectLowering::Reduce(Node* node) {
+  if (node->opcode() != IrOpcode::kSelect) return NoChange();
+  SelectParameters const p = SelectParametersOf(node->op());
+
+  Node* cond = node->InputAt(0);
+  Node* vthen = node->InputAt(1);
+  Node* velse = node->InputAt(2);
+  Node* merge = nullptr;
+
+  // Check if we already have a diamond for this condition.
+  auto range = merges_.equal_range(cond);
+  for (auto i = range.first;; ++i) {
+    if (i == range.second) {
+      // Create a new diamond for this condition and remember its merge node.
+      Diamond d(graph(), common(), cond, p.hint());
+      merges_.insert(std::make_pair(cond, d.merge));
+      merge = d.merge;
+      break;
+    }
+
+    // If the diamond is reachable from the Select, merging them would result in
+    // an unschedulable graph, so we cannot reuse the diamond in that case.
+    merge = i->second;
+    if (!ReachableFrom(merge, node)) {
+      break;
+    }
+  }
+
+  // Create a Phi hanging off the previously determined merge.
+  node->set_op(common()->Phi(p.type(), 2));
+  node->ReplaceInput(0, vthen);
+  node->ReplaceInput(1, velse);
+  node->ReplaceInput(2, merge);
+  return Changed(node);
+}
+
+
+bool SelectLowering::ReachableFrom(Node* const sink, Node* const source) {
+  // TODO(turbofan): This is probably horribly expensive, and it should be moved
+  // into node.h or somewhere else?!
+  Zone zone(graph()->zone()->isolate());
+  std::queue<Node*, NodeDeque> queue((NodeDeque(&zone)));
+  BoolVector visited(graph()->NodeCount(), false, &zone);
+  queue.push(source);
+  visited[source->id()] = true;
+  while (!queue.empty()) {
+    Node* current = queue.front();
+    if (current == sink) return true;
+    queue.pop();
+    for (auto input : current->inputs()) {
+      if (!visited[input->id()]) {
+        queue.push(input);
+        visited[input->id()] = true;
+      }
+    }
+  }
+  return false;
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/select-lowering.h b/src/compiler/select-lowering.h
new file mode 100644
index 0000000..05ea0e0
--- /dev/null
+++ b/src/compiler/select-lowering.h
@@ -0,0 +1,48 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_SELECT_LOWERING_H_
+#define V8_COMPILER_SELECT_LOWERING_H_
+
+#include <map>
+
+#include "src/compiler/graph-reducer.h"
+#include "src/zone-allocator.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// Forward declarations.
+class CommonOperatorBuilder;
+class Graph;
+
+
+// Lowers Select nodes to diamonds.
+class SelectLowering FINAL : public Reducer {
+ public:
+  SelectLowering(Graph* graph, CommonOperatorBuilder* common);
+  ~SelectLowering();
+
+  Reduction Reduce(Node* node) OVERRIDE;
+
+ private:
+  typedef std::multimap<Node*, Node*, std::less<Node*>,
+                        zone_allocator<std::pair<Node* const, Node*>>> Merges;
+
+  bool ReachableFrom(Node* const sink, Node* const source);
+
+  CommonOperatorBuilder* common() const { return common_; }
+  Graph* graph() const { return graph_; }
+
+  CommonOperatorBuilder* common_;
+  Graph* graph_;
+  Merges merges_;
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_SELECT_LOWERING_H_
diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc
index f794525..1461709 100644
--- a/src/compiler/simplified-lowering.cc
+++ b/src/compiler/simplified-lowering.cc
@@ -4,10 +4,15 @@
 
 #include "src/compiler/simplified-lowering.h"
 
+#include <limits>
+
 #include "src/base/bits.h"
 #include "src/code-factory.h"
 #include "src/compiler/common-operator.h"
+#include "src/compiler/diamond.h"
 #include "src/compiler/graph-inl.h"
+#include "src/compiler/linkage.h"
+#include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/representation-change.h"
 #include "src/compiler/simplified-lowering.h"
@@ -66,11 +71,18 @@
         info_(zone->NewArray<NodeInfo>(count_)),
         nodes_(zone),
         replacements_(zone),
-        contains_js_nodes_(false),
         phase_(PROPAGATE),
         changer_(changer),
         queue_(zone) {
     memset(info_, 0, sizeof(NodeInfo) * count_);
+
+    Factory* f = zone->isolate()->factory();
+    safe_bit_range_ =
+        Type::Union(Type::Boolean(),
+                    Type::Range(f->NewNumber(0), f->NewNumber(1), zone), zone);
+    safe_int_additive_range_ =
+        Type::Range(f->NewNumber(-std::pow(2.0, 52.0)),
+                    f->NewNumber(std::pow(2.0, 52.0)), zone);
   }
 
   void Run(SimplifiedLowering* lowering) {
@@ -164,6 +176,30 @@
            NodeProperties::GetBounds(node->InputAt(1)).upper->Is(type);
   }
 
+  void ProcessTruncateWord32Input(Node* node, int index, MachineTypeUnion use) {
+    Node* input = node->InputAt(index);
+    if (phase_ == PROPAGATE) {
+      // In the propagate phase, propagate the usage information backward.
+      Enqueue(input, use);
+    } else {
+      // In the change phase, insert a change before the use if necessary.
+      MachineTypeUnion output = GetInfo(input)->output;
+      if ((output & (kRepBit | kRepWord8 | kRepWord16 | kRepWord32)) == 0) {
+        // Output representation doesn't match usage.
+        TRACE(("  truncate-to-int32: #%d:%s(@%d #%d:%s) ", node->id(),
+               node->op()->mnemonic(), index, input->id(),
+               input->op()->mnemonic()));
+        TRACE((" from "));
+        PrintInfo(output);
+        TRACE((" to "));
+        PrintInfo(use);
+        TRACE(("\n"));
+        Node* n = changer_->GetTruncatedWord32For(input, output);
+        node->ReplaceInput(index, n);
+      }
+    }
+  }
+
   void ProcessInput(Node* node, int index, MachineTypeUnion use) {
     Node* input = node->InputAt(index);
     if (phase_ == PROPAGATE) {
@@ -206,22 +242,19 @@
   // context, effect, and control inputs, assuming that value inputs should have
   // {kRepTagged} representation and can observe all output values {kTypeAny}.
   void VisitInputs(Node* node) {
-    InputIter i = node->inputs().begin();
-    for (int j = OperatorProperties::GetValueInputCount(node->op()); j > 0;
-         ++i, j--) {
-      ProcessInput(node, i.index(), kMachAnyTagged);  // Value inputs
+    auto i = node->input_edges().begin();
+    for (int j = node->op()->ValueInputCount(); j > 0; ++i, j--) {
+      ProcessInput(node, (*i).index(), kMachAnyTagged);  // Value inputs
     }
     for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0;
          ++i, j--) {
-      ProcessInput(node, i.index(), kMachAnyTagged);  // Context inputs
+      ProcessInput(node, (*i).index(), kMachAnyTagged);  // Context inputs
     }
-    for (int j = OperatorProperties::GetEffectInputCount(node->op()); j > 0;
-         ++i, j--) {
-      Enqueue(*i);  // Effect inputs: just visit
+    for (int j = node->op()->EffectInputCount(); j > 0; ++i, j--) {
+      Enqueue((*i).to());  // Effect inputs: just visit
     }
-    for (int j = OperatorProperties::GetControlInputCount(node->op()); j > 0;
-         ++i, j--) {
-      Enqueue(*i);  // Control inputs: just visit
+    for (int j = node->op()->ControlInputCount(); j > 0; ++i, j--) {
+      Enqueue((*i).to());  // Control inputs: just visit
     }
     SetOutput(node, kMachAnyTagged);
   }
@@ -267,60 +300,83 @@
   void VisitInt64Cmp(Node* node) { VisitBinop(node, kMachInt64, kRepBit); }
   void VisitUint64Cmp(Node* node) { VisitBinop(node, kMachUint64, kRepBit); }
 
-  // Helper for handling phis.
-  void VisitPhi(Node* node, MachineTypeUnion use,
-                SimplifiedLowering* lowering) {
-    // First, propagate the usage information to inputs of the phi.
-    if (!lower()) {
-      int values = OperatorProperties::GetValueInputCount(node->op());
-      // Propagate {use} of the phi to value inputs, and 0 to control.
-      Node::Inputs inputs = node->inputs();
-      for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
-           ++iter, --values) {
-        // TODO(titzer): it'd be nice to have distinguished edge kinds here.
-        ProcessInput(node, iter.index(), values > 0 ? use : 0);
-      }
-    }
-    // Phis adapt to whatever output representation their uses demand,
-    // pushing representation changes to their inputs.
-    MachineTypeUnion use_rep = GetUseInfo(node) & kRepMask;
-    MachineTypeUnion use_type = GetUseInfo(node) & kTypeMask;
-    MachineTypeUnion rep = 0;
-    if (use_rep & kRepTagged) {
-      rep = kRepTagged;  // Tagged overrides everything.
-    } else if (use_rep & kRepFloat64) {
-      rep = kRepFloat64;
-    } else if (use_rep & kRepWord64) {
-      rep = kRepWord64;
-    } else if (use_rep & kRepWord32) {
-      rep = kRepWord32;
-    } else if (use_rep & kRepBit) {
-      rep = kRepBit;
-    } else {
-      // There was no representation associated with any of the uses.
-      // TODO(titzer): Select the best rep using phi's type, not the usage type?
-      if (use_type & kTypeAny) {
-        rep = kRepTagged;
-      } else if (use_type & kTypeNumber) {
-        rep = kRepFloat64;
-      } else if (use_type & kTypeInt64 || use_type & kTypeUint64) {
-        rep = kRepWord64;
-      } else if (use_type & kTypeInt32 || use_type & kTypeUint32) {
-        rep = kRepWord32;
-      } else if (use_type & kTypeBool) {
-        rep = kRepBit;
-      } else {
-        UNREACHABLE();  // should have at least a usage type!
-      }
-    }
-    // Preserve the usage type, but set the representation.
+  // Infer representation for phi-like nodes.
+  MachineType GetRepresentationForPhi(Node* node, MachineTypeUnion use) {
+    // Phis adapt to the output representation their uses demand.
     Type* upper = NodeProperties::GetBounds(node).upper;
-    MachineTypeUnion output_type = rep | changer_->TypeFromUpperBound(upper);
+    if ((use & kRepMask) == kRepTagged) {
+      // only tagged uses.
+      return kRepTagged;
+    } else if (upper->Is(Type::Integral32())) {
+      // Integer within [-2^31, 2^32[ range.
+      if ((use & kRepMask) == kRepFloat64) {
+        // only float64 uses.
+        return kRepFloat64;
+      } else if (upper->Is(Type::Signed32()) || upper->Is(Type::Unsigned32())) {
+        // multiple uses, but we are within 32 bits range => pick kRepWord32.
+        return kRepWord32;
+      } else if ((use & kRepMask) == kRepWord32 ||
+                 (use & kTypeMask) == kTypeInt32 ||
+                 (use & kTypeMask) == kTypeUint32) {
+        // We only use 32 bits or we use the result consistently.
+        return kRepWord32;
+      } else {
+        return kRepFloat64;
+      }
+    } else if (IsSafeBitOperand(node)) {
+      // multiple uses => pick kRepBit.
+      return kRepBit;
+    } else if (upper->Is(Type::Number())) {
+      // multiple uses => pick kRepFloat64.
+      return kRepFloat64;
+    }
+    return kRepTagged;
+  }
+
+  // Helper for handling selects.
+  void VisitSelect(Node* node, MachineTypeUnion use,
+                   SimplifiedLowering* lowering) {
+    ProcessInput(node, 0, kRepBit);
+    MachineType output = GetRepresentationForPhi(node, use);
+
+    Type* upper = NodeProperties::GetBounds(node).upper;
+    MachineType output_type =
+        static_cast<MachineType>(changer_->TypeFromUpperBound(upper) | output);
     SetOutput(node, output_type);
 
     if (lower()) {
-      int values = OperatorProperties::GetValueInputCount(node->op());
+      // Update the select operator.
+      SelectParameters p = SelectParametersOf(node->op());
+      MachineType type = static_cast<MachineType>(output_type);
+      if (type != p.type()) {
+        node->set_op(lowering->common()->Select(type, p.hint()));
+      }
 
+      // Convert inputs to the output representation of this select.
+      ProcessInput(node, 1, output_type);
+      ProcessInput(node, 2, output_type);
+    } else {
+      // Propagate {use} of the select to value inputs.
+      MachineType use_type =
+          static_cast<MachineType>((use & kTypeMask) | output);
+      ProcessInput(node, 1, use_type);
+      ProcessInput(node, 2, use_type);
+    }
+  }
+
+  // Helper for handling phis.
+  void VisitPhi(Node* node, MachineTypeUnion use,
+                SimplifiedLowering* lowering) {
+    MachineType output = GetRepresentationForPhi(node, use);
+
+    Type* upper = NodeProperties::GetBounds(node).upper;
+    MachineType output_type =
+        static_cast<MachineType>(changer_->TypeFromUpperBound(upper) | output);
+    SetOutput(node, output_type);
+
+    int values = node->op()->ValueInputCount();
+
+    if (lower()) {
       // Update the phi operator.
       MachineType type = static_cast<MachineType>(output_type);
       if (type != OpParameter<MachineType>(node)) {
@@ -328,11 +384,19 @@
       }
 
       // Convert inputs to the output representation of this phi.
-      Node::Inputs inputs = node->inputs();
-      for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
-           ++iter, --values) {
+      for (Edge const edge : node->input_edges()) {
         // TODO(titzer): it'd be nice to have distinguished edge kinds here.
-        ProcessInput(node, iter.index(), values > 0 ? output_type : 0);
+        ProcessInput(node, edge.index(), values > 0 ? output_type : 0);
+        values--;
+      }
+    } else {
+      // Propagate {use} of the phi to value inputs, and 0 to control.
+      MachineType use_type =
+          static_cast<MachineType>((use & kTypeMask) | output);
+      for (Edge const edge : node->input_edges()) {
+        // TODO(titzer): it'd be nice to have distinguished edge kinds here.
+        ProcessInput(node, edge.index(), values > 0 ? use_type : 0);
+        values--;
       }
     }
   }
@@ -349,13 +413,55 @@
     return changer_->Float64OperatorFor(node->opcode());
   }
 
-  static MachineType AssumeImplicitFloat32Change(MachineType type) {
-    // TODO(titzer): Assume loads of float32 change representation to float64.
-    // Fix this with full support for float32 representations.
-    if (type & kRepFloat32) {
-      return static_cast<MachineType>((type & ~kRepFloat32) | kRepFloat64);
-    }
-    return type;
+  bool CanLowerToInt32Binop(Node* node, MachineTypeUnion use) {
+    return BothInputsAre(node, Type::Signed32()) && !CanObserveNonInt32(use);
+  }
+
+  bool IsSafeBitOperand(Node* node) {
+    Type* type = NodeProperties::GetBounds(node).upper;
+    return type->Is(safe_bit_range_);
+  }
+
+  bool IsSafeIntAdditiveOperand(Node* node) {
+    Type* type = NodeProperties::GetBounds(node).upper;
+    // TODO(jarin): Unfortunately, bitset types are not subtypes of larger
+    // range types, so we have to explicitly check for Integral32 here
+    // (in addition to the safe integer range). Once we fix subtyping for
+    // ranges, we should simplify this.
+    return type->Is(safe_int_additive_range_) || type->Is(Type::Integral32());
+  }
+
+  bool CanLowerToInt32AdditiveBinop(Node* node, MachineTypeUnion use) {
+    return IsSafeIntAdditiveOperand(node->InputAt(0)) &&
+           IsSafeIntAdditiveOperand(node->InputAt(1)) &&
+           !CanObserveNonInt32(use);
+  }
+
+  bool CanLowerToUint32Binop(Node* node, MachineTypeUnion use) {
+    return BothInputsAre(node, Type::Unsigned32()) && !CanObserveNonUint32(use);
+  }
+
+  bool CanLowerToUint32AdditiveBinop(Node* node, MachineTypeUnion use) {
+    return IsSafeIntAdditiveOperand(node->InputAt(0)) &&
+           IsSafeIntAdditiveOperand(node->InputAt(1)) &&
+           !CanObserveNonUint32(use);
+  }
+
+  bool CanObserveNonInt32(MachineTypeUnion use) {
+    return (use & (kTypeUint32 | kTypeNumber | kTypeAny)) != 0;
+  }
+
+  bool CanObserveMinusZero(MachineTypeUnion use) {
+    // TODO(turbofan): technically Uint32 cannot observe minus zero either.
+    return (use & (kTypeUint32 | kTypeNumber | kTypeAny)) != 0;
+  }
+
+  bool CanObserveNaN(MachineTypeUnion use) {
+    return (use & (kTypeNumber | kTypeAny)) != 0;
+  }
+
+  bool CanObserveNonUint32(MachineTypeUnion use) {
+    return (use & (kTypeInt32 | kTypeNumber | kTypeAny)) != 0;
   }
 
   // Dispatching routine for visiting the node {node} with the usage {use}.
@@ -401,6 +507,8 @@
         ProcessInput(node, 0, kRepBit);
         Enqueue(NodeProperties::GetControlInput(node, 0));
         break;
+      case IrOpcode::kSelect:
+        return VisitSelect(node, use, lowering);
       case IrOpcode::kPhi:
         return VisitPhi(node, use, lowering);
 
@@ -415,19 +523,40 @@
 #define DEFINE_JS_CASE(x) case IrOpcode::k##x:
         JS_OP_LIST(DEFINE_JS_CASE)
 #undef DEFINE_JS_CASE
-        contains_js_nodes_ = true;
         VisitInputs(node);
         return SetOutput(node, kRepTagged);
 
       //------------------------------------------------------------------
       // Simplified operators.
       //------------------------------------------------------------------
+      case IrOpcode::kAnyToBoolean: {
+        if (IsSafeBitOperand(node->InputAt(0))) {
+          VisitUnop(node, kRepBit, kRepBit);
+          if (lower()) DeferReplacement(node, node->InputAt(0));
+        } else {
+          VisitUnop(node, kMachAnyTagged, kTypeBool | kRepTagged);
+          if (lower()) {
+            // AnyToBoolean(x) => Call(ToBooleanStub, x, no-context)
+            Operator::Properties properties = node->op()->properties();
+            Callable callable = CodeFactory::ToBoolean(
+                jsgraph_->isolate(), ToBooleanStub::RESULT_AS_ODDBALL);
+            CallDescriptor::Flags flags = CallDescriptor::kPatchableCallSite;
+            CallDescriptor* desc = Linkage::GetStubCallDescriptor(
+                callable.descriptor(), 0, flags, properties, jsgraph_->zone());
+            node->set_op(jsgraph_->common()->Call(desc));
+            node->InsertInput(jsgraph_->zone(), 0,
+                              jsgraph_->HeapConstant(callable.code()));
+            node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
+          }
+        }
+        break;
+      }
       case IrOpcode::kBooleanNot: {
         if (lower()) {
           MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
           if (input & kRepBit) {
-            // BooleanNot(x: kRepBit) => WordEqual(x, #0)
-            node->set_op(lowering->machine()->WordEqual());
+            // BooleanNot(x: kRepBit) => Word32Equal(x, #0)
+            node->set_op(lowering->machine()->Word32Equal());
             node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
           } else {
             // BooleanNot(x: kRepTagged) => WordEqual(x, #false)
@@ -482,16 +611,26 @@
       case IrOpcode::kNumberSubtract: {
         // Add and subtract reduce to Int32Add/Sub if the inputs
         // are already integers and all uses are truncating.
-        if (BothInputsAre(node, Type::Signed32()) &&
-            (use & (kTypeUint32 | kTypeNumber | kTypeAny)) == 0) {
+        if (CanLowerToInt32Binop(node, use)) {
           // => signed Int32Add/Sub
           VisitInt32Binop(node);
           if (lower()) node->set_op(Int32Op(node));
-        } else if (BothInputsAre(node, Type::Unsigned32()) &&
-                   (use & (kTypeInt32 | kTypeNumber | kTypeAny)) == 0) {
+        } else if (CanLowerToInt32AdditiveBinop(node, use)) {
+          // => signed Int32Add/Sub, truncating inputs
+          ProcessTruncateWord32Input(node, 0, kTypeInt32);
+          ProcessTruncateWord32Input(node, 1, kTypeInt32);
+          SetOutput(node, kMachInt32);
+          if (lower()) node->set_op(Int32Op(node));
+        } else if (CanLowerToUint32Binop(node, use)) {
           // => unsigned Int32Add/Sub
           VisitUint32Binop(node);
           if (lower()) node->set_op(Uint32Op(node));
+        } else if (CanLowerToUint32AdditiveBinop(node, use)) {
+          // => signed Int32Add/Sub, truncating inputs
+          ProcessTruncateWord32Input(node, 0, kTypeUint32);
+          ProcessTruncateWord32Input(node, 1, kTypeUint32);
+          SetOutput(node, kMachUint32);
+          if (lower()) node->set_op(Uint32Op(node));
         } else {
           // => Float64Add/Sub
           VisitFloat64Binop(node);
@@ -499,54 +638,110 @@
         }
         break;
       }
-      case IrOpcode::kNumberMultiply:
-      case IrOpcode::kNumberDivide:
+      case IrOpcode::kNumberMultiply: {
+        NumberMatcher right(node->InputAt(1));
+        if (right.IsInRange(-1048576, 1048576)) {  // must fit double mantissa.
+          if (CanLowerToInt32Binop(node, use)) {
+            // => signed Int32Mul
+            VisitInt32Binop(node);
+            if (lower()) node->set_op(Int32Op(node));
+            break;
+          }
+        }
+        // => Float64Mul
+        VisitFloat64Binop(node);
+        if (lower()) node->set_op(Float64Op(node));
+        break;
+      }
+      case IrOpcode::kNumberDivide: {
+        if (CanLowerToInt32Binop(node, use)) {
+          // => signed Int32Div
+          VisitInt32Binop(node);
+          if (lower()) DeferReplacement(node, lowering->Int32Div(node));
+          break;
+        }
+        if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
+          // => unsigned Uint32Div
+          VisitUint32Binop(node);
+          if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
+          break;
+        }
+        // => Float64Div
+        VisitFloat64Binop(node);
+        if (lower()) node->set_op(Float64Op(node));
+        break;
+      }
       case IrOpcode::kNumberModulus: {
-        // Float64Mul/Div/Mod
+        if (CanLowerToInt32Binop(node, use)) {
+          // => signed Int32Mod
+          VisitInt32Binop(node);
+          if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
+          break;
+        }
+        if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
+          // => unsigned Uint32Mod
+          VisitUint32Binop(node);
+          if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
+          break;
+        }
+        // => Float64Mod
         VisitFloat64Binop(node);
         if (lower()) node->set_op(Float64Op(node));
         break;
       }
       case IrOpcode::kNumberToInt32: {
         MachineTypeUnion use_rep = use & kRepMask;
-        if (lower()) {
-          MachineTypeUnion in = GetInfo(node->InputAt(0))->output;
-          if ((in & kTypeMask) == kTypeInt32 || (in & kRepMask) == kRepWord32) {
-            // If the input has type int32, or is already a word32, just change
-            // representation if necessary.
-            VisitUnop(node, kTypeInt32 | use_rep, kTypeInt32 | use_rep);
-            DeferReplacement(node, node->InputAt(0));
-          } else {
-            // Require the input in float64 format and perform truncation.
-            // TODO(turbofan): avoid a truncation with a smi check.
-            VisitUnop(node, kTypeInt32 | kRepFloat64, kTypeInt32 | kRepWord32);
-            node->set_op(lowering->machine()->TruncateFloat64ToInt32());
-          }
+        Node* input = node->InputAt(0);
+        Type* in_upper = NodeProperties::GetBounds(input).upper;
+        MachineTypeUnion in = GetInfo(input)->output;
+        if (in_upper->Is(Type::Signed32())) {
+          // If the input has type int32, pass through representation.
+          VisitUnop(node, kTypeInt32 | use_rep, kTypeInt32 | use_rep);
+          if (lower()) DeferReplacement(node, node->InputAt(0));
+        } else if ((in & kTypeMask) == kTypeUint32 ||
+                   in_upper->Is(Type::Unsigned32())) {
+          // Just change representation if necessary.
+          VisitUnop(node, kTypeUint32 | kRepWord32, kTypeInt32 | kRepWord32);
+          if (lower()) DeferReplacement(node, node->InputAt(0));
+        } else if ((in & kTypeMask) == kTypeInt32 ||
+                   (in & kRepMask) == kRepWord32) {
+          // Just change representation if necessary.
+          VisitUnop(node, kTypeInt32 | kRepWord32, kTypeInt32 | kRepWord32);
+          if (lower()) DeferReplacement(node, node->InputAt(0));
         } else {
-          // Propagate a type to the input, but pass through representation.
-          VisitUnop(node, kTypeInt32, kTypeInt32 | use_rep);
+          // Require the input in float64 format and perform truncation.
+          // TODO(turbofan): avoid a truncation with a smi check.
+          VisitUnop(node, kTypeInt32 | kRepFloat64, kTypeInt32 | kRepWord32);
+          if (lower())
+            node->set_op(lowering->machine()->TruncateFloat64ToInt32());
         }
         break;
       }
       case IrOpcode::kNumberToUint32: {
         MachineTypeUnion use_rep = use & kRepMask;
-        if (lower()) {
-          MachineTypeUnion in = GetInfo(node->InputAt(0))->output;
-          if ((in & kTypeMask) == kTypeUint32 ||
-              (in & kRepMask) == kRepWord32) {
-            // The input has type int32, just change representation.
-            VisitUnop(node, kTypeUint32 | use_rep, kTypeUint32 | use_rep);
-            DeferReplacement(node, node->InputAt(0));
-          } else {
-            // Require the input in float64 format to perform truncation.
-            // TODO(turbofan): avoid the truncation with a smi check.
-            VisitUnop(node, kTypeUint32 | kRepFloat64,
-                      kTypeUint32 | kRepWord32);
-            node->set_op(lowering->machine()->TruncateFloat64ToInt32());
-          }
+        Node* input = node->InputAt(0);
+        Type* in_upper = NodeProperties::GetBounds(input).upper;
+        MachineTypeUnion in = GetInfo(input)->output;
+        if (in_upper->Is(Type::Unsigned32())) {
+          // If the input has type uint32, pass through representation.
+          VisitUnop(node, kTypeUint32 | use_rep, kTypeUint32 | use_rep);
+          if (lower()) DeferReplacement(node, node->InputAt(0));
+        } else if ((in & kTypeMask) == kTypeUint32 ||
+                   in_upper->Is(Type::Unsigned32())) {
+          // Just change representation if necessary.
+          VisitUnop(node, kTypeUint32 | kRepWord32, kTypeUint32 | kRepWord32);
+          if (lower()) DeferReplacement(node, node->InputAt(0));
+        } else if ((in & kTypeMask) == kTypeInt32 ||
+                   (in & kRepMask) == kRepWord32) {
+          // Just change representation if necessary.
+          VisitUnop(node, kTypeInt32 | kRepWord32, kTypeUint32 | kRepWord32);
+          if (lower()) DeferReplacement(node, node->InputAt(0));
         } else {
-          // Propagate a type to the input, but pass through representation.
-          VisitUnop(node, kTypeUint32, kTypeUint32 | use_rep);
+          // Require the input in float64 format and perform truncation.
+          // TODO(turbofan): avoid a truncation with a smi check.
+          VisitUnop(node, kTypeUint32 | kRepFloat64, kTypeUint32 | kRepWord32);
+          if (lower())
+            node->set_op(lowering->machine()->TruncateFloat64ToInt32());
         }
         break;
       }
@@ -579,47 +774,115 @@
         FieldAccess access = FieldAccessOf(node->op());
         ProcessInput(node, 0, changer_->TypeForBasePointer(access));
         ProcessRemainingInputs(node, 1);
-        SetOutput(node, AssumeImplicitFloat32Change(access.machine_type));
+        SetOutput(node, access.machine_type);
         if (lower()) lowering->DoLoadField(node);
         break;
       }
       case IrOpcode::kStoreField: {
         FieldAccess access = FieldAccessOf(node->op());
         ProcessInput(node, 0, changer_->TypeForBasePointer(access));
-        ProcessInput(node, 1, AssumeImplicitFloat32Change(access.machine_type));
+        ProcessInput(node, 1, access.machine_type);
         ProcessRemainingInputs(node, 2);
         SetOutput(node, 0);
         if (lower()) lowering->DoStoreField(node);
         break;
       }
-      case IrOpcode::kLoadElement: {
-        ElementAccess access = ElementAccessOf(node->op());
-        ProcessInput(node, 0, changer_->TypeForBasePointer(access));
-        ProcessInput(node, 1, kMachInt32);  // element index
+      case IrOpcode::kLoadBuffer: {
+        BufferAccess access = BufferAccessOf(node->op());
+        ProcessInput(node, 0, kMachPtr);    // buffer
+        ProcessInput(node, 1, kMachInt32);  // offset
         ProcessInput(node, 2, kMachInt32);  // length
         ProcessRemainingInputs(node, 3);
-        SetOutput(node, AssumeImplicitFloat32Change(access.machine_type));
+        // Tagged overrides everything if we have to do a typed array bounds
+        // check, because we may need to return undefined then.
+        MachineType output_type;
+        if (use & kRepTagged) {
+          output_type = kMachAnyTagged;
+        } else if (use & kRepFloat64) {
+          if (access.machine_type() & kRepFloat32) {
+            output_type = access.machine_type();
+          } else {
+            output_type = kMachFloat64;
+          }
+        } else if (use & kRepFloat32) {
+          output_type = kMachFloat32;
+        } else {
+          output_type = access.machine_type();
+        }
+        SetOutput(node, output_type);
+        if (lower()) lowering->DoLoadBuffer(node, output_type, changer_);
+        break;
+      }
+      case IrOpcode::kStoreBuffer: {
+        BufferAccess access = BufferAccessOf(node->op());
+        ProcessInput(node, 0, kMachPtr);               // buffer
+        ProcessInput(node, 1, kMachInt32);             // offset
+        ProcessInput(node, 2, kMachInt32);             // length
+        ProcessInput(node, 3, access.machine_type());  // value
+        ProcessRemainingInputs(node, 4);
+        SetOutput(node, 0);
+        if (lower()) lowering->DoStoreBuffer(node);
+        break;
+      }
+      case IrOpcode::kLoadElement: {
+        ElementAccess access = ElementAccessOf(node->op());
+        ProcessInput(node, 0, changer_->TypeForBasePointer(access));  // base
+        ProcessInput(node, 1, kMachInt32);                            // index
+        ProcessRemainingInputs(node, 2);
+        SetOutput(node, access.machine_type);
         if (lower()) lowering->DoLoadElement(node);
         break;
       }
       case IrOpcode::kStoreElement: {
         ElementAccess access = ElementAccessOf(node->op());
-        ProcessInput(node, 0, changer_->TypeForBasePointer(access));
-        ProcessInput(node, 1, kMachInt32);  // element index
-        ProcessInput(node, 2, kMachInt32);  // length
-        ProcessInput(node, 3, AssumeImplicitFloat32Change(access.machine_type));
-        ProcessRemainingInputs(node, 4);
+        ProcessInput(node, 0, changer_->TypeForBasePointer(access));  // base
+        ProcessInput(node, 1, kMachInt32);                            // index
+        ProcessInput(node, 2, access.machine_type);                   // value
+        ProcessRemainingInputs(node, 3);
         SetOutput(node, 0);
         if (lower()) lowering->DoStoreElement(node);
         break;
       }
+      case IrOpcode::kObjectIsSmi: {
+        ProcessInput(node, 0, kMachAnyTagged);
+        SetOutput(node, kRepBit | kTypeBool);
+        if (lower()) {
+          Node* is_tagged = jsgraph_->graph()->NewNode(
+              jsgraph_->machine()->WordAnd(), node->InputAt(0),
+              jsgraph_->Int32Constant(static_cast<int>(kSmiTagMask)));
+          Node* is_smi = jsgraph_->graph()->NewNode(
+              jsgraph_->machine()->WordEqual(), is_tagged,
+              jsgraph_->Int32Constant(kSmiTag));
+          DeferReplacement(node, is_smi);
+        }
+        break;
+      }
+      case IrOpcode::kObjectIsNonNegativeSmi: {
+        ProcessInput(node, 0, kMachAnyTagged);
+        SetOutput(node, kRepBit | kTypeBool);
+        if (lower()) {
+          Node* is_tagged = jsgraph_->graph()->NewNode(
+              jsgraph_->machine()->WordAnd(), node->InputAt(0),
+              jsgraph_->Int32Constant(static_cast<int>(kSmiTagMask)));
+          Node* is_smi = jsgraph_->graph()->NewNode(
+              jsgraph_->machine()->WordEqual(), is_tagged,
+              jsgraph_->Int32Constant(kSmiTag));
+          Node* is_non_neg = jsgraph_->graph()->NewNode(
+              jsgraph_->machine()->IntLessThanOrEqual(),
+              jsgraph_->Int32Constant(0), node->InputAt(0));
+          Node* is_non_neg_smi = jsgraph_->graph()->NewNode(
+              jsgraph_->machine()->Word32And(), is_smi, is_non_neg);
+          DeferReplacement(node, is_non_neg_smi);
+        }
+        break;
+      }
 
       //------------------------------------------------------------------
       // Machine-level operators.
       //------------------------------------------------------------------
       case IrOpcode::kLoad: {
         // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
-        MachineType tBase = kRepTagged;
+        MachineTypeUnion tBase = kRepTagged | kMachPtr;
         LoadRepresentation rep = OpParameter<LoadRepresentation>(node);
         ProcessInput(node, 0, tBase);   // pointer or object
         ProcessInput(node, 1, kMachInt32);  // index
@@ -629,7 +892,7 @@
       }
       case IrOpcode::kStore: {
         // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
-        MachineType tBase = kRepTagged;
+        MachineTypeUnion tBase = kRepTagged | kMachPtr;
         StoreRepresentation rep = OpParameter<StoreRepresentation>(node);
         ProcessInput(node, 0, tBase);   // pointer or object
         ProcessInput(node, 1, kMachInt32);  // index
@@ -640,7 +903,7 @@
       }
       case IrOpcode::kWord32Shr:
         // We output unsigned int32 for shift right because JavaScript.
-        return VisitBinop(node, kRepWord32, kRepWord32 | kTypeUint32);
+        return VisitBinop(node, kMachUint32, kMachUint32);
       case IrOpcode::kWord32And:
       case IrOpcode::kWord32Or:
       case IrOpcode::kWord32Xor:
@@ -656,11 +919,13 @@
       case IrOpcode::kInt32Add:
       case IrOpcode::kInt32Sub:
       case IrOpcode::kInt32Mul:
+      case IrOpcode::kInt32MulHigh:
       case IrOpcode::kInt32Div:
       case IrOpcode::kInt32Mod:
         return VisitInt32Binop(node);
-      case IrOpcode::kInt32UDiv:
-      case IrOpcode::kInt32UMod:
+      case IrOpcode::kUint32Div:
+      case IrOpcode::kUint32Mod:
+      case IrOpcode::kUint32MulHigh:
         return VisitUint32Binop(node);
       case IrOpcode::kInt32LessThan:
       case IrOpcode::kInt32LessThanOrEqual:
@@ -680,8 +945,11 @@
       case IrOpcode::kInt64LessThanOrEqual:
         return VisitInt64Cmp(node);
 
-      case IrOpcode::kInt64UDiv:
-      case IrOpcode::kInt64UMod:
+      case IrOpcode::kUint64LessThan:
+        return VisitUint64Cmp(node);
+
+      case IrOpcode::kUint64Div:
+      case IrOpcode::kUint64Mod:
         return VisitUint64Binop(node);
 
       case IrOpcode::kWord64And:
@@ -700,11 +968,17 @@
       case IrOpcode::kChangeUint32ToUint64:
         return VisitUnop(node, kTypeUint32 | kRepWord32,
                          kTypeUint32 | kRepWord64);
+      case IrOpcode::kTruncateFloat64ToFloat32:
+        return VisitUnop(node, kTypeNumber | kRepFloat64,
+                         kTypeNumber | kRepFloat32);
       case IrOpcode::kTruncateInt64ToInt32:
         // TODO(titzer): Is kTypeInt32 correct here?
         return VisitUnop(node, kTypeInt32 | kRepWord64,
                          kTypeInt32 | kRepWord32);
 
+      case IrOpcode::kChangeFloat32ToFloat64:
+        return VisitUnop(node, kTypeNumber | kRepFloat32,
+                         kTypeNumber | kRepFloat64);
       case IrOpcode::kChangeInt32ToFloat64:
         return VisitUnop(node, kTypeInt32 | kRepWord32,
                          kTypeInt32 | kRepFloat64);
@@ -725,11 +999,23 @@
       case IrOpcode::kFloat64Mod:
         return VisitFloat64Binop(node);
       case IrOpcode::kFloat64Sqrt:
+      case IrOpcode::kFloat64Floor:
+      case IrOpcode::kFloat64Ceil:
+      case IrOpcode::kFloat64RoundTruncate:
+      case IrOpcode::kFloat64RoundTiesAway:
         return VisitUnop(node, kMachFloat64, kMachFloat64);
       case IrOpcode::kFloat64Equal:
       case IrOpcode::kFloat64LessThan:
       case IrOpcode::kFloat64LessThanOrEqual:
         return VisitFloat64Cmp(node);
+      case IrOpcode::kLoadStackPointer:
+        return VisitLeaf(node, kMachPtr);
+      case IrOpcode::kStateValues:
+        for (int i = 0; i < node->InputCount(); i++) {
+          ProcessInput(node, i, kTypeAny);
+        }
+        SetOutput(node, kMachAnyTagged);
+        break;
       default:
         VisitInputs(node);
         break;
@@ -737,6 +1023,11 @@
   }
 
   void DeferReplacement(Node* node, Node* replacement) {
+    if (FLAG_trace_representation) {
+      TRACE(("defer replacement #%d:%s with #%d:%s\n", node->id(),
+             node->op()->mnemonic(), replacement->id(),
+             replacement->op()->mnemonic()));
+    }
     if (replacement->id() < count_) {
       // Replace with a previously existing node eagerly.
       node->ReplaceUses(replacement);
@@ -770,10 +1061,11 @@
   NodeInfo* info_;                  // node id -> usage information
   NodeVector nodes_;                // collected nodes
   NodeVector replacements_;         // replacements to be done after lowering
-  bool contains_js_nodes_;          // {true} if a JS operator was seen
   Phase phase_;                     // current phase of algorithm
   RepresentationChanger* changer_;  // for inserting representation changes
   ZoneQueue<Node*> queue_;          // queue for traversing the graph
+  Type* safe_bit_range_;
+  Type* safe_int_additive_range_;
 
   NodeInfo* GetInfo(Node* node) {
     DCHECK(node->id() >= 0);
@@ -797,7 +1089,7 @@
   SimplifiedOperatorBuilder simplified(graph()->zone());
   RepresentationChanger changer(jsgraph(), &simplified,
                                 graph()->zone()->isolate());
-  RepresentationSelector selector(jsgraph(), zone(), &changer);
+  RepresentationSelector selector(jsgraph(), zone_, &changer);
   selector.Run(this);
 }
 
@@ -837,8 +1129,8 @@
 void SimplifiedLowering::DoLoadField(Node* node) {
   const FieldAccess& access = FieldAccessOf(node->op());
   node->set_op(machine()->Load(access.machine_type));
-  Node* offset = jsgraph()->Int32Constant(access.offset - access.tag());
-  node->InsertInput(zone(), 1, offset);
+  Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag());
+  node->InsertInput(graph()->zone(), 1, offset);
 }
 
 
@@ -848,22 +1140,96 @@
       access.base_is_tagged, access.machine_type, access.type);
   node->set_op(
       machine()->Store(StoreRepresentation(access.machine_type, kind)));
-  Node* offset = jsgraph()->Int32Constant(access.offset - access.tag());
-  node->InsertInput(zone(), 1, offset);
+  Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag());
+  node->InsertInput(graph()->zone(), 1, offset);
 }
 
 
 Node* SimplifiedLowering::ComputeIndex(const ElementAccess& access,
-                                       Node* index) {
-  int element_size = ElementSizeOf(access.machine_type);
-  if (element_size != 1) {
-    index = graph()->NewNode(machine()->Int32Mul(),
-                             jsgraph()->Int32Constant(element_size), index);
+                                       Node* const key) {
+  Node* index = key;
+  const int element_size_shift = ElementSizeLog2Of(access.machine_type);
+  if (element_size_shift) {
+    index = graph()->NewNode(machine()->Word32Shl(), index,
+                             jsgraph()->Int32Constant(element_size_shift));
   }
-  int fixed_offset = access.header_size - access.tag();
-  if (fixed_offset == 0) return index;
-  return graph()->NewNode(machine()->Int32Add(), index,
-                          jsgraph()->Int32Constant(fixed_offset));
+  const int fixed_offset = access.header_size - access.tag();
+  if (fixed_offset) {
+    index = graph()->NewNode(machine()->Int32Add(), index,
+                             jsgraph()->Int32Constant(fixed_offset));
+  }
+  if (machine()->Is64()) {
+    // TODO(turbofan): This is probably only correct for typed arrays, and only
+    // if the typed arrays are at most 2GiB in size, which happens to match
+    // exactly our current situation.
+    index = graph()->NewNode(machine()->ChangeUint32ToUint64(), index);
+  }
+  return index;
+}
+
+
+void SimplifiedLowering::DoLoadBuffer(Node* node, MachineType output_type,
+                                      RepresentationChanger* changer) {
+  DCHECK_EQ(IrOpcode::kLoadBuffer, node->opcode());
+  DCHECK_NE(kMachNone, RepresentationOf(output_type));
+  MachineType const type = BufferAccessOf(node->op()).machine_type();
+  if (output_type != type) {
+    Node* const buffer = node->InputAt(0);
+    Node* const offset = node->InputAt(1);
+    Node* const length = node->InputAt(2);
+    Node* const effect = node->InputAt(3);
+    Node* const control = node->InputAt(4);
+    Node* const index =
+        machine()->Is64()
+            ? graph()->NewNode(machine()->ChangeUint32ToUint64(), offset)
+            : offset;
+
+    Node* check = graph()->NewNode(machine()->Uint32LessThan(), offset, length);
+    Node* branch =
+        graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
+
+    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+    Node* etrue =
+        graph()->NewNode(machine()->Load(type), buffer, index, effect, if_true);
+    Node* vtrue = changer->GetRepresentationFor(etrue, type, output_type);
+
+    Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+    Node* efalse = effect;
+    Node* vfalse;
+    if (output_type & kRepTagged) {
+      vfalse = jsgraph()->UndefinedConstant();
+    } else if (output_type & kRepFloat64) {
+      vfalse =
+          jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
+    } else if (output_type & kRepFloat32) {
+      vfalse =
+          jsgraph()->Float32Constant(std::numeric_limits<float>::quiet_NaN());
+    } else {
+      vfalse = jsgraph()->Int32Constant(0);
+    }
+
+    Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+    Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
+
+    // Replace effect uses of {node} with the {ephi}.
+    NodeProperties::ReplaceWithValue(node, node, ephi);
+
+    // Turn the {node} into a Phi.
+    node->set_op(common()->Phi(output_type, 2));
+    node->ReplaceInput(0, vtrue);
+    node->ReplaceInput(1, vfalse);
+    node->ReplaceInput(2, merge);
+    node->TrimInputCount(3);
+  } else {
+    node->set_op(machine()->CheckedLoad(type));
+  }
+}
+
+
+void SimplifiedLowering::DoStoreBuffer(Node* node) {
+  DCHECK_EQ(IrOpcode::kStoreBuffer, node->opcode());
+  MachineType const type = BufferAccessOf(node->op()).machine_type();
+  node->set_op(machine()->CheckedStore(type));
 }
 
 
@@ -871,32 +1237,32 @@
   const ElementAccess& access = ElementAccessOf(node->op());
   node->set_op(machine()->Load(access.machine_type));
   node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
-  node->RemoveInput(2);
 }
 
 
 void SimplifiedLowering::DoStoreElement(Node* node) {
   const ElementAccess& access = ElementAccessOf(node->op());
-  WriteBarrierKind kind = ComputeWriteBarrierKind(
-      access.base_is_tagged, access.machine_type, access.type);
-  node->set_op(
-      machine()->Store(StoreRepresentation(access.machine_type, kind)));
+  node->set_op(machine()->Store(StoreRepresentation(
+      access.machine_type,
+      ComputeWriteBarrierKind(access.base_is_tagged, access.machine_type,
+                              access.type))));
   node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
-  node->RemoveInput(2);
 }
 
 
 void SimplifiedLowering::DoStringAdd(Node* node) {
+  Operator::Properties properties = node->op()->properties();
   Callable callable = CodeFactory::StringAdd(
       zone()->isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
   CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
-  CallDescriptor* desc =
-      Linkage::GetStubCallDescriptor(callable.descriptor(), 0, flags, zone());
+  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
+      callable.descriptor(), 0, flags, properties, zone());
   node->set_op(common()->Call(desc));
-  node->InsertInput(zone(), 0, jsgraph()->HeapConstant(callable.code()));
-  node->AppendInput(zone(), jsgraph()->UndefinedConstant());
-  node->AppendInput(zone(), graph()->start());
-  node->AppendInput(zone(), graph()->start());
+  node->InsertInput(graph()->zone(), 0,
+                    jsgraph()->HeapConstant(callable.code()));
+  node->AppendInput(graph()->zone(), jsgraph()->UndefinedConstant());
+  node->AppendInput(graph()->zone(), graph()->start());
+  node->AppendInput(graph()->zone(), graph()->start());
 }
 
 
@@ -919,6 +1285,213 @@
 }
 
 
+Node* SimplifiedLowering::Int32Div(Node* const node) {
+  Int32BinopMatcher m(node);
+  Node* const zero = jsgraph()->Int32Constant(0);
+  Node* const lhs = m.left().node();
+  Node* const rhs = m.right().node();
+
+  if (m.right().Is(-1)) {
+    return graph()->NewNode(machine()->Int32Sub(), zero, lhs);
+  } else if (m.right().Is(0)) {
+    return rhs;
+  } else if (machine()->Int32DivIsSafe() || m.right().HasValue()) {
+    return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
+  }
+
+  Diamond if_zero(graph(), common(),
+                  graph()->NewNode(machine()->Word32Equal(), rhs, zero),
+                  BranchHint::kFalse);
+
+  Diamond if_minus_one(graph(), common(),
+                       graph()->NewNode(machine()->Word32Equal(), rhs,
+                                        jsgraph()->Int32Constant(-1)),
+                       BranchHint::kFalse);
+  if_minus_one.Nest(if_zero, false);
+  Node* sub = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
+  Node* div =
+      graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_minus_one.if_false);
+
+  return if_zero.Phi(kMachInt32, zero, if_minus_one.Phi(kMachInt32, sub, div));
+}
+
+
+Node* SimplifiedLowering::Int32Mod(Node* const node) {
+  Int32BinopMatcher m(node);
+  Node* const zero = jsgraph()->Int32Constant(0);
+  Node* const minus_one = jsgraph()->Int32Constant(-1);
+  Node* const lhs = m.left().node();
+  Node* const rhs = m.right().node();
+
+  if (m.right().Is(-1) || m.right().Is(0)) {
+    return zero;
+  } else if (m.right().HasValue()) {
+    return graph()->NewNode(machine()->Int32Mod(), lhs, rhs, graph()->start());
+  }
+
+  // General case for signed integer modulus, with optimization for (unknown)
+  // power of 2 right hand side.
+  //
+  //   if 0 < rhs then
+  //     msk = rhs - 1
+  //     if rhs & msk != 0 then
+  //       lhs % rhs
+  //     else
+  //       if lhs < 0 then
+  //         -(-lhs & msk)
+  //       else
+  //         lhs & msk
+  //   else
+  //     if rhs < -1 then
+  //       lhs % rhs
+  //     else
+  //       zero
+  //
+  // Note: We do not use the Diamond helper class here, because it really hurts
+  // readability with nested diamonds.
+  const Operator* const merge_op = common()->Merge(2);
+  const Operator* const phi_op = common()->Phi(kMachInt32, 2);
+
+  Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
+  Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
+                                   graph()->start());
+
+  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+  Node* true0;
+  {
+    Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
+
+    Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
+    Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
+
+    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+    Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
+
+    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+    Node* false1;
+    {
+      Node* check2 = graph()->NewNode(machine()->Int32LessThan(), lhs, zero);
+      Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
+                                       check2, if_false1);
+
+      Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
+      Node* true2 = graph()->NewNode(
+          machine()->Int32Sub(), zero,
+          graph()->NewNode(machine()->Word32And(),
+                           graph()->NewNode(machine()->Int32Sub(), zero, lhs),
+                           msk));
+
+      Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
+      Node* false2 = graph()->NewNode(machine()->Word32And(), lhs, msk);
+
+      if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
+      false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
+    }
+
+    if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
+    true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
+  }
+
+  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
+  Node* false0;
+  {
+    Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
+    Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
+                                     check1, if_false0);
+
+    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+    Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
+
+    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+    Node* false1 = zero;
+
+    if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
+    false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
+  }
+
+  Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
+  return graph()->NewNode(phi_op, true0, false0, merge0);
+}
+
+
+Node* SimplifiedLowering::Uint32Div(Node* const node) {
+  Uint32BinopMatcher m(node);
+  Node* const zero = jsgraph()->Uint32Constant(0);
+  Node* const lhs = m.left().node();
+  Node* const rhs = m.right().node();
+
+  if (m.right().Is(0)) {
+    return zero;
+  } else if (machine()->Uint32DivIsSafe() || m.right().HasValue()) {
+    return graph()->NewNode(machine()->Uint32Div(), lhs, rhs, graph()->start());
+  }
+
+  Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
+  Diamond d(graph(), common(), check, BranchHint::kFalse);
+  Node* div = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, d.if_false);
+  return d.Phi(kMachUint32, zero, div);
+}
+
+
+Node* SimplifiedLowering::Uint32Mod(Node* const node) {
+  Uint32BinopMatcher m(node);
+  Node* const minus_one = jsgraph()->Int32Constant(-1);
+  Node* const zero = jsgraph()->Uint32Constant(0);
+  Node* const lhs = m.left().node();
+  Node* const rhs = m.right().node();
+
+  if (m.right().Is(0)) {
+    return zero;
+  } else if (m.right().HasValue()) {
+    return graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, graph()->start());
+  }
+
+  // General case for unsigned integer modulus, with optimization for (unknown)
+  // power of 2 right hand side.
+  //
+  //   if rhs then
+  //     msk = rhs - 1
+  //     if rhs & msk != 0 then
+  //       lhs % rhs
+  //     else
+  //       lhs & msk
+  //   else
+  //     zero
+  //
+  // Note: We do not use the Diamond helper class here, because it really hurts
+  // readability with nested diamonds.
+  const Operator* const merge_op = common()->Merge(2);
+  const Operator* const phi_op = common()->Phi(kMachInt32, 2);
+
+  Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), rhs,
+                                   graph()->start());
+
+  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+  Node* true0;
+  {
+    Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
+
+    Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
+    Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
+
+    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+    Node* true1 = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, if_true1);
+
+    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+    Node* false1 = graph()->NewNode(machine()->Word32And(), lhs, msk);
+
+    if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
+    true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
+  }
+
+  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
+  Node* false0 = zero;
+
+  Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
+  return graph()->NewNode(phi_op, true0, false0, merge0);
+}
+
+
 void SimplifiedLowering::DoStringEqual(Node* node) {
   node->set_op(machine()->WordEqual());
   node->ReplaceInput(0, StringComparison(node, false));
@@ -939,7 +1512,6 @@
   node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
 }
 
-
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
diff --git a/src/compiler/simplified-lowering.h b/src/compiler/simplified-lowering.h
index 2ba7e3b..b21cf21 100644
--- a/src/compiler/simplified-lowering.h
+++ b/src/compiler/simplified-lowering.h
@@ -14,16 +14,26 @@
 namespace internal {
 namespace compiler {
 
-class SimplifiedLowering {
+// Forward declarations.
+class RepresentationChanger;
+
+
+class SimplifiedLowering FINAL {
  public:
-  explicit SimplifiedLowering(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
-  virtual ~SimplifiedLowering() {}
+  SimplifiedLowering(JSGraph* jsgraph, Zone* zone)
+      : jsgraph_(jsgraph), zone_(zone) {}
+  ~SimplifiedLowering() {}
 
   void LowerAllNodes();
 
   // TODO(titzer): These are exposed for direct testing. Use a friend class.
   void DoLoadField(Node* node);
   void DoStoreField(Node* node);
+  // TODO(turbofan): The output_type can be removed once the result of the
+  // representation analysis is stored in the node bounds.
+  void DoLoadBuffer(Node* node, MachineType output_type,
+                    RepresentationChanger* changer);
+  void DoStoreBuffer(Node* node);
   void DoLoadElement(Node* node);
   void DoStoreElement(Node* node);
   void DoStringAdd(Node* node);
@@ -32,14 +42,19 @@
   void DoStringLessThanOrEqual(Node* node);
 
  private:
-  JSGraph* jsgraph_;
+  JSGraph* const jsgraph_;
+  Zone* const zone_;
 
   Node* SmiTag(Node* node);
   Node* IsTagged(Node* node);
   Node* Untag(Node* node);
   Node* OffsetMinusTagConstant(int32_t offset);
-  Node* ComputeIndex(const ElementAccess& access, Node* index);
+  Node* ComputeIndex(const ElementAccess& access, Node* const key);
   Node* StringComparison(Node* node, bool requires_ordering);
+  Node* Int32Div(Node* const node);
+  Node* Int32Mod(Node* const node);
+  Node* Uint32Div(Node* const node);
+  Node* Uint32Mod(Node* const node);
 
   friend class RepresentationSelector;
 
diff --git a/src/compiler/simplified-operator-reducer-unittest.cc b/src/compiler/simplified-operator-reducer-unittest.cc
deleted file mode 100644
index 739264e..0000000
--- a/src/compiler/simplified-operator-reducer-unittest.cc
+++ /dev/null
@@ -1,483 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/graph-unittest.h"
-#include "src/compiler/js-graph.h"
-#include "src/compiler/simplified-operator.h"
-#include "src/compiler/simplified-operator-reducer.h"
-#include "src/compiler/typer.h"
-#include "src/conversions.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-class SimplifiedOperatorReducerTest : public GraphTest {
- public:
-  explicit SimplifiedOperatorReducerTest(int num_parameters = 1)
-      : GraphTest(num_parameters), simplified_(zone()) {}
-  virtual ~SimplifiedOperatorReducerTest() {}
-
- protected:
-  Reduction Reduce(Node* node) {
-    Typer typer(zone());
-    MachineOperatorBuilder machine;
-    JSOperatorBuilder javascript(zone());
-    JSGraph jsgraph(graph(), common(), &javascript, &typer, &machine);
-    SimplifiedOperatorReducer reducer(&jsgraph);
-    return reducer.Reduce(node);
-  }
-
-  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
-
- private:
-  SimplifiedOperatorBuilder simplified_;
-};
-
-
-template <typename T>
-class SimplifiedOperatorReducerTestWithParam
-    : public SimplifiedOperatorReducerTest,
-      public ::testing::WithParamInterface<T> {
- public:
-  explicit SimplifiedOperatorReducerTestWithParam(int num_parameters = 1)
-      : SimplifiedOperatorReducerTest(num_parameters) {}
-  virtual ~SimplifiedOperatorReducerTestWithParam() {}
-};
-
-
-namespace {
-
-static const double kFloat64Values[] = {
-    -V8_INFINITY,  -6.52696e+290, -1.05768e+290, -5.34203e+268, -1.01997e+268,
-    -8.22758e+266, -1.58402e+261, -5.15246e+241, -5.92107e+226, -1.21477e+226,
-    -1.67913e+188, -1.6257e+184,  -2.60043e+170, -2.52941e+168, -3.06033e+116,
-    -4.56201e+52,  -3.56788e+50,  -9.9066e+38,   -3.07261e+31,  -2.1271e+09,
-    -1.91489e+09,  -1.73053e+09,  -9.30675e+08,  -26030,        -20453,
-    -15790,        -11699,        -111,          -97,           -78,
-    -63,           -58,           -1.53858e-06,  -2.98914e-12,  -1.14741e-39,
-    -8.20347e-57,  -1.48932e-59,  -3.17692e-66,  -8.93103e-81,  -3.91337e-83,
-    -6.0489e-92,   -8.83291e-113, -4.28266e-117, -1.92058e-178, -2.0567e-192,
-    -1.68167e-194, -1.51841e-214, -3.98738e-234, -7.31851e-242, -2.21875e-253,
-    -1.11612e-293, -0.0,          0.0,           2.22507e-308,  1.06526e-307,
-    4.16643e-227,  6.76624e-223,  2.0432e-197,   3.16254e-184,  1.37315e-173,
-    2.88603e-172,  1.54155e-99,   4.42923e-81,   1.40539e-73,   5.4462e-73,
-    1.24064e-58,   3.11167e-58,   2.75826e-39,   0.143815,      58,
-    67,            601,           7941,          11644,         13697,
-    25680,         29882,         1.32165e+08,   1.62439e+08,   4.16837e+08,
-    9.59097e+08,   1.32491e+09,   1.8728e+09,    1.0672e+17,    2.69606e+46,
-    1.98285e+79,   1.0098e+82,    7.93064e+88,   3.67444e+121,  9.36506e+123,
-    7.27954e+162,  3.05316e+168,  1.16171e+175,  1.64771e+189,  1.1622e+202,
-    2.00748e+239,  2.51778e+244,  3.90282e+306,  1.79769e+308,  V8_INFINITY};
-
-
-static const int32_t kInt32Values[] = {
-    -2147483647 - 1, -2104508227, -2103151830, -1435284490, -1378926425,
-    -1318814539,     -1289388009, -1287537572, -1279026536, -1241605942,
-    -1226046939,     -941837148,  -779818051,  -413830641,  -245798087,
-    -184657557,      -127145950,  -105483328,  -32325,      -26653,
-    -23858,          -23834,      -22363,      -19858,      -19044,
-    -18744,          -15528,      -5309,       -3372,       -2093,
-    -104,            -98,         -97,         -93,         -84,
-    -80,             -78,         -76,         -72,         -58,
-    -57,             -56,         -55,         -45,         -40,
-    -34,             -32,         -25,         -24,         -5,
-    -2,              0,           3,           10,          24,
-    34,              42,          46,          47,          48,
-    52,              56,          64,          65,          71,
-    76,              79,          81,          82,          97,
-    102,             103,         104,         106,         107,
-    109,             116,         122,         3653,        4485,
-    12405,           16504,       26262,       28704,       29755,
-    30554,           16476817,    605431957,   832401070,   873617242,
-    914205764,       1062628108,  1087581664,  1488498068,  1534668023,
-    1661587028,      1696896187,  1866841746,  2032089723,  2147483647};
-
-
-static const uint32_t kUint32Values[] = {
-    0x0,        0x5,        0x8,        0xc,        0xd,        0x26,
-    0x28,       0x29,       0x30,       0x34,       0x3e,       0x42,
-    0x50,       0x5b,       0x63,       0x71,       0x77,       0x7c,
-    0x83,       0x88,       0x96,       0x9c,       0xa3,       0xfa,
-    0x7a7,      0x165d,     0x234d,     0x3acb,     0x43a5,     0x4573,
-    0x5b4f,     0x5f14,     0x6996,     0x6c6e,     0x7289,     0x7b9a,
-    0x7bc9,     0x86bb,     0xa839,     0xaa41,     0xb03b,     0xc942,
-    0xce68,     0xcf4c,     0xd3ad,     0xdea3,     0xe90c,     0xed86,
-    0xfba5,     0x172dcc6,  0x114d8fc1, 0x182d6c9d, 0x1b1e3fad, 0x1db033bf,
-    0x1e1de755, 0x1f625c80, 0x28f6cf00, 0x2acb6a94, 0x2c20240e, 0x2f0fe54e,
-    0x31863a7c, 0x33325474, 0x3532fae3, 0x3bab82ea, 0x4c4b83a2, 0x4cd93d1e,
-    0x4f7331d4, 0x5491b09b, 0x57cc6ff9, 0x60d3b4dc, 0x653f5904, 0x690ae256,
-    0x69fe3276, 0x6bebf0ba, 0x6e2c69a3, 0x73b84ff7, 0x7b3a1924, 0x7ed032d9,
-    0x84dd734b, 0x8552ea53, 0x8680754f, 0x8e9660eb, 0x94fe2b9c, 0x972d30cf,
-    0x9b98c482, 0xb158667e, 0xb432932c, 0xb5b70989, 0xb669971a, 0xb7c359d1,
-    0xbeb15c0d, 0xc171c53d, 0xc743dd38, 0xc8e2af50, 0xc98e2df0, 0xd9d1cdf9,
-    0xdcc91049, 0xe46f396d, 0xee991950, 0xef64e521, 0xf7aeefc9, 0xffffffff};
-
-
-MATCHER(IsNaN, std::string(negation ? "isn't" : "is") + " NaN") {
-  return std::isnan(arg);
-}
-
-}  // namespace
-
-
-// -----------------------------------------------------------------------------
-// Unary operators
-
-
-namespace {
-
-struct UnaryOperator {
-  const Operator* (SimplifiedOperatorBuilder::*constructor)();
-  const char* constructor_name;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const UnaryOperator& unop) {
-  return os << unop.constructor_name;
-}
-
-
-static const UnaryOperator kUnaryOperators[] = {
-    {&SimplifiedOperatorBuilder::BooleanNot, "BooleanNot"},
-    {&SimplifiedOperatorBuilder::ChangeBitToBool, "ChangeBitToBool"},
-    {&SimplifiedOperatorBuilder::ChangeBoolToBit, "ChangeBoolToBit"},
-    {&SimplifiedOperatorBuilder::ChangeFloat64ToTagged,
-     "ChangeFloat64ToTagged"},
-    {&SimplifiedOperatorBuilder::ChangeInt32ToTagged, "ChangeInt32ToTagged"},
-    {&SimplifiedOperatorBuilder::ChangeTaggedToFloat64,
-     "ChangeTaggedToFloat64"},
-    {&SimplifiedOperatorBuilder::ChangeTaggedToInt32, "ChangeTaggedToInt32"},
-    {&SimplifiedOperatorBuilder::ChangeTaggedToUint32, "ChangeTaggedToUint32"},
-    {&SimplifiedOperatorBuilder::ChangeUint32ToTagged, "ChangeUint32ToTagged"}};
-
-}  // namespace
-
-
-typedef SimplifiedOperatorReducerTestWithParam<UnaryOperator>
-    SimplifiedUnaryOperatorTest;
-
-
-TEST_P(SimplifiedUnaryOperatorTest, Parameter) {
-  const UnaryOperator& unop = GetParam();
-  Reduction reduction = Reduce(
-      graph()->NewNode((simplified()->*unop.constructor)(), Parameter(0)));
-  EXPECT_FALSE(reduction.Changed());
-}
-
-
-INSTANTIATE_TEST_CASE_P(SimplifiedOperatorReducerTest,
-                        SimplifiedUnaryOperatorTest,
-                        ::testing::ValuesIn(kUnaryOperators));
-
-
-// -----------------------------------------------------------------------------
-// BooleanNot
-
-
-TEST_F(SimplifiedOperatorReducerTest, BooleanNotWithBooleanNot) {
-  Node* param0 = Parameter(0);
-  Reduction reduction = Reduce(
-      graph()->NewNode(simplified()->BooleanNot(),
-                       graph()->NewNode(simplified()->BooleanNot(), param0)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_EQ(param0, reduction.replacement());
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, BooleanNotWithFalseConstant) {
-  Reduction reduction0 =
-      Reduce(graph()->NewNode(simplified()->BooleanNot(), FalseConstant()));
-  ASSERT_TRUE(reduction0.Changed());
-  EXPECT_THAT(reduction0.replacement(), IsTrueConstant());
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, BooleanNotWithTrueConstant) {
-  Reduction reduction1 =
-      Reduce(graph()->NewNode(simplified()->BooleanNot(), TrueConstant()));
-  ASSERT_TRUE(reduction1.Changed());
-  EXPECT_THAT(reduction1.replacement(), IsFalseConstant());
-}
-
-
-// -----------------------------------------------------------------------------
-// ChangeBoolToBit
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeBitToBoolWithChangeBoolToBit) {
-  Node* param0 = Parameter(0);
-  Reduction reduction = Reduce(graph()->NewNode(
-      simplified()->ChangeBitToBool(),
-      graph()->NewNode(simplified()->ChangeBoolToBit(), param0)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_EQ(param0, reduction.replacement());
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeBitToBoolWithZeroConstant) {
-  Reduction reduction = Reduce(
-      graph()->NewNode(simplified()->ChangeBitToBool(), Int32Constant(0)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_THAT(reduction.replacement(), IsFalseConstant());
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeBitToBoolWithOneConstant) {
-  Reduction reduction = Reduce(
-      graph()->NewNode(simplified()->ChangeBitToBool(), Int32Constant(1)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_THAT(reduction.replacement(), IsTrueConstant());
-}
-
-
-// -----------------------------------------------------------------------------
-// ChangeBoolToBit
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeBoolToBitWithFalseConstant) {
-  Reduction reduction = Reduce(
-      graph()->NewNode(simplified()->ChangeBoolToBit(), FalseConstant()));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeBoolToBitWithTrueConstant) {
-  Reduction reduction =
-      Reduce(graph()->NewNode(simplified()->ChangeBoolToBit(), TrueConstant()));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_THAT(reduction.replacement(), IsInt32Constant(1));
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeBoolToBitWithChangeBitToBool) {
-  Node* param0 = Parameter(0);
-  Reduction reduction = Reduce(graph()->NewNode(
-      simplified()->ChangeBoolToBit(),
-      graph()->NewNode(simplified()->ChangeBitToBool(), param0)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_EQ(param0, reduction.replacement());
-}
-
-
-// -----------------------------------------------------------------------------
-// ChangeFloat64ToTagged
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeFloat64ToTaggedWithConstant) {
-  TRACED_FOREACH(double, n, kFloat64Values) {
-    Reduction reduction = Reduce(graph()->NewNode(
-        simplified()->ChangeFloat64ToTagged(), Float64Constant(n)));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(), IsNumberConstant(n));
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// ChangeInt32ToTagged
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeInt32ToTaggedWithConstant) {
-  TRACED_FOREACH(int32_t, n, kInt32Values) {
-    Reduction reduction = Reduce(graph()->NewNode(
-        simplified()->ChangeInt32ToTagged(), Int32Constant(n)));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(), IsNumberConstant(FastI2D(n)));
-  }
-}
-
-
-// -----------------------------------------------------------------------------
-// ChangeTaggedToFloat64
-
-
-TEST_F(SimplifiedOperatorReducerTest,
-       ChangeTaggedToFloat64WithChangeFloat64ToTagged) {
-  Node* param0 = Parameter(0);
-  Reduction reduction = Reduce(graph()->NewNode(
-      simplified()->ChangeTaggedToFloat64(),
-      graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_EQ(param0, reduction.replacement());
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest,
-       ChangeTaggedToFloat64WithChangeInt32ToTagged) {
-  Node* param0 = Parameter(0);
-  Reduction reduction = Reduce(graph()->NewNode(
-      simplified()->ChangeTaggedToFloat64(),
-      graph()->NewNode(simplified()->ChangeInt32ToTagged(), param0)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_THAT(reduction.replacement(), IsChangeInt32ToFloat64(param0));
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest,
-       ChangeTaggedToFloat64WithChangeUint32ToTagged) {
-  Node* param0 = Parameter(0);
-  Reduction reduction = Reduce(graph()->NewNode(
-      simplified()->ChangeTaggedToFloat64(),
-      graph()->NewNode(simplified()->ChangeUint32ToTagged(), param0)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_THAT(reduction.replacement(), IsChangeUint32ToFloat64(param0));
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithConstant) {
-  TRACED_FOREACH(double, n, kFloat64Values) {
-    Reduction reduction = Reduce(graph()->NewNode(
-        simplified()->ChangeTaggedToFloat64(), NumberConstant(n)));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(), IsFloat64Constant(n));
-  }
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithNaNConstant1) {
-  Reduction reduction =
-      Reduce(graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
-                              NumberConstant(-base::OS::nan_value())));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_THAT(reduction.replacement(), IsFloat64Constant(IsNaN()));
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithNaNConstant2) {
-  Reduction reduction =
-      Reduce(graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
-                              NumberConstant(base::OS::nan_value())));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_THAT(reduction.replacement(), IsFloat64Constant(IsNaN()));
-}
-
-
-// -----------------------------------------------------------------------------
-// ChangeTaggedToInt32
-
-
-TEST_F(SimplifiedOperatorReducerTest,
-       ChangeTaggedToInt32WithChangeFloat64ToTagged) {
-  Node* param0 = Parameter(0);
-  Reduction reduction = Reduce(graph()->NewNode(
-      simplified()->ChangeTaggedToInt32(),
-      graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_THAT(reduction.replacement(), IsChangeFloat64ToInt32(param0));
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest,
-       ChangeTaggedToInt32WithChangeInt32ToTagged) {
-  Node* param0 = Parameter(0);
-  Reduction reduction = Reduce(graph()->NewNode(
-      simplified()->ChangeTaggedToInt32(),
-      graph()->NewNode(simplified()->ChangeInt32ToTagged(), param0)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_EQ(param0, reduction.replacement());
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToInt32WithConstant) {
-  TRACED_FOREACH(double, n, kFloat64Values) {
-    Reduction reduction = Reduce(graph()->NewNode(
-        simplified()->ChangeTaggedToInt32(), NumberConstant(n)));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(), IsInt32Constant(DoubleToInt32(n)));
-  }
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToInt32WithNaNConstant1) {
-  Reduction reduction =
-      Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(),
-                              NumberConstant(-base::OS::nan_value())));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToInt32WithNaNConstant2) {
-  Reduction reduction =
-      Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(),
-                              NumberConstant(base::OS::nan_value())));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
-}
-
-
-// -----------------------------------------------------------------------------
-// ChangeTaggedToUint32
-
-
-TEST_F(SimplifiedOperatorReducerTest,
-       ChangeTaggedToUint32WithChangeFloat64ToTagged) {
-  Node* param0 = Parameter(0);
-  Reduction reduction = Reduce(graph()->NewNode(
-      simplified()->ChangeTaggedToUint32(),
-      graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_THAT(reduction.replacement(), IsChangeFloat64ToUint32(param0));
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest,
-       ChangeTaggedToUint32WithChangeUint32ToTagged) {
-  Node* param0 = Parameter(0);
-  Reduction reduction = Reduce(graph()->NewNode(
-      simplified()->ChangeTaggedToUint32(),
-      graph()->NewNode(simplified()->ChangeUint32ToTagged(), param0)));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_EQ(param0, reduction.replacement());
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToUint32WithConstant) {
-  TRACED_FOREACH(double, n, kFloat64Values) {
-    Reduction reduction = Reduce(graph()->NewNode(
-        simplified()->ChangeTaggedToUint32(), NumberConstant(n)));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(),
-                IsInt32Constant(bit_cast<int32_t>(DoubleToUint32(n))));
-  }
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToUint32WithNaNConstant1) {
-  Reduction reduction =
-      Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(),
-                              NumberConstant(-base::OS::nan_value())));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
-}
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToUint32WithNaNConstant2) {
-  Reduction reduction =
-      Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(),
-                              NumberConstant(base::OS::nan_value())));
-  ASSERT_TRUE(reduction.Changed());
-  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
-}
-
-
-// -----------------------------------------------------------------------------
-// ChangeUint32ToTagged
-
-
-TEST_F(SimplifiedOperatorReducerTest, ChangeUint32ToTagged) {
-  TRACED_FOREACH(uint32_t, n, kUint32Values) {
-    Reduction reduction =
-        Reduce(graph()->NewNode(simplified()->ChangeUint32ToTagged(),
-                                Int32Constant(bit_cast<int32_t>(n))));
-    ASSERT_TRUE(reduction.Changed());
-    EXPECT_THAT(reduction.replacement(), IsNumberConstant(FastUI2D(n)));
-  }
-}
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/simplified-operator-reducer.cc b/src/compiler/simplified-operator-reducer.cc
index f6181ea..9d45e5b 100644
--- a/src/compiler/simplified-operator-reducer.cc
+++ b/src/compiler/simplified-operator-reducer.cc
@@ -2,21 +2,29 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/compiler/generic-node-inl.h"
+#include "src/compiler/simplified-operator-reducer.h"
+
+#include "src/compiler/access-builder.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/machine-operator.h"
 #include "src/compiler/node-matchers.h"
-#include "src/compiler/simplified-operator-reducer.h"
+#include "src/compiler/node-properties-inl.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
+SimplifiedOperatorReducer::SimplifiedOperatorReducer(JSGraph* jsgraph)
+    : jsgraph_(jsgraph), simplified_(jsgraph->zone()) {}
+
+
 SimplifiedOperatorReducer::~SimplifiedOperatorReducer() {}
 
 
 Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
   switch (node->opcode()) {
+    case IrOpcode::kAnyToBoolean:
+      return ReduceAnyToBoolean(node);
     case IrOpcode::kBooleanNot: {
       HeapObjectMatcher<HeapObject> m(node->InputAt(0));
       if (m.Is(Unique<HeapObject>::CreateImmovable(factory()->false_value()))) {
@@ -102,8 +110,36 @@
 }
 
 
+Reduction SimplifiedOperatorReducer::ReduceAnyToBoolean(Node* node) {
+  Node* const input = NodeProperties::GetValueInput(node, 0);
+  Type* const input_type = NodeProperties::GetBounds(input).upper;
+  if (input_type->Is(Type::Boolean())) {
+    // AnyToBoolean(x:boolean) => x
+    return Replace(input);
+  }
+  if (input_type->Is(Type::OrderedNumber())) {
+    // AnyToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0))
+    Node* compare = graph()->NewNode(simplified()->NumberEqual(), input,
+                                     jsgraph()->ZeroConstant());
+    return Change(node, simplified()->BooleanNot(), compare);
+  }
+  if (input_type->Is(Type::String())) {
+    // AnyToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0))
+    FieldAccess const access = AccessBuilder::ForStringLength();
+    Node* length = graph()->NewNode(simplified()->LoadField(access), input,
+                                    graph()->start(), graph()->start());
+    Node* compare = graph()->NewNode(simplified()->NumberEqual(), length,
+                                     jsgraph()->ZeroConstant());
+    return Change(node, simplified()->BooleanNot(), compare);
+  }
+  return NoChange();
+}
+
+
 Reduction SimplifiedOperatorReducer::Change(Node* node, const Operator* op,
                                             Node* a) {
+  DCHECK_EQ(node->InputCount(), OperatorProperties::GetTotalInputCount(op));
+  DCHECK_LE(1, node->InputCount());
   node->set_op(op);
   node->ReplaceInput(0, a);
   return Changed(node);
@@ -138,6 +174,11 @@
 }
 
 
+CommonOperatorBuilder* SimplifiedOperatorReducer::common() const {
+  return jsgraph()->common();
+}
+
+
 MachineOperatorBuilder* SimplifiedOperatorReducer::machine() const {
   return jsgraph()->machine();
 }
diff --git a/src/compiler/simplified-operator-reducer.h b/src/compiler/simplified-operator-reducer.h
index 32f49ad..1e565b8 100644
--- a/src/compiler/simplified-operator-reducer.h
+++ b/src/compiler/simplified-operator-reducer.h
@@ -6,6 +6,7 @@
 #define V8_COMPILER_SIMPLIFIED_OPERATOR_REDUCER_H_
 
 #include "src/compiler/graph-reducer.h"
+#include "src/compiler/simplified-operator.h"
 
 namespace v8 {
 namespace internal {
@@ -16,17 +17,20 @@
 namespace compiler {
 
 // Forward declarations.
+class CommonOperatorBuilder;
 class JSGraph;
 class MachineOperatorBuilder;
 
 class SimplifiedOperatorReducer FINAL : public Reducer {
  public:
-  explicit SimplifiedOperatorReducer(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
-  virtual ~SimplifiedOperatorReducer();
+  explicit SimplifiedOperatorReducer(JSGraph* jsgraph);
+  ~SimplifiedOperatorReducer() FINAL;
 
-  virtual Reduction Reduce(Node* node) OVERRIDE;
+  Reduction Reduce(Node* node) FINAL;
 
  private:
+  Reduction ReduceAnyToBoolean(Node* node);
+
   Reduction Change(Node* node, const Operator* op, Node* a);
   Reduction ReplaceFloat64(double value);
   Reduction ReplaceInt32(int32_t value);
@@ -39,9 +43,12 @@
   Graph* graph() const;
   Factory* factory() const;
   JSGraph* jsgraph() const { return jsgraph_; }
+  CommonOperatorBuilder* common() const;
   MachineOperatorBuilder* machine() const;
+  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
 
   JSGraph* jsgraph_;
+  SimplifiedOperatorBuilder simplified_;
 
   DISALLOW_COPY_AND_ASSIGN(SimplifiedOperatorReducer);
 };
diff --git a/src/compiler/simplified-operator-unittest.cc b/src/compiler/simplified-operator-unittest.cc
deleted file mode 100644
index 4014f24..0000000
--- a/src/compiler/simplified-operator-unittest.cc
+++ /dev/null
@@ -1,222 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/simplified-operator.h"
-
-#include "src/compiler/operator-properties-inl.h"
-#include "src/test/test-utils.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-// TODO(bmeurer): Drop once we use std::ostream instead of our OStream.
-inline std::ostream& operator<<(std::ostream& os, const ElementAccess& access) {
-  OStringStream ost;
-  ost << access;
-  return os << ost.c_str();
-}
-
-
-// -----------------------------------------------------------------------------
-// Pure operators.
-
-
-namespace {
-
-struct PureOperator {
-  const Operator* (SimplifiedOperatorBuilder::*constructor)();
-  IrOpcode::Value opcode;
-  Operator::Properties properties;
-  int value_input_count;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const PureOperator& pop) {
-  return os << IrOpcode::Mnemonic(pop.opcode);
-}
-
-
-const PureOperator kPureOperators[] = {
-#define PURE(Name, properties, input_count)              \
-  {                                                      \
-    &SimplifiedOperatorBuilder::Name, IrOpcode::k##Name, \
-        Operator::kPure | properties, input_count        \
-  }
-    PURE(BooleanNot, Operator::kNoProperties, 1),
-    PURE(NumberEqual, Operator::kCommutative, 2),
-    PURE(NumberLessThan, Operator::kNoProperties, 2),
-    PURE(NumberLessThanOrEqual, Operator::kNoProperties, 2),
-    PURE(NumberAdd, Operator::kCommutative, 2),
-    PURE(NumberSubtract, Operator::kNoProperties, 2),
-    PURE(NumberMultiply, Operator::kCommutative, 2),
-    PURE(NumberDivide, Operator::kNoProperties, 2),
-    PURE(NumberModulus, Operator::kNoProperties, 2),
-    PURE(NumberToInt32, Operator::kNoProperties, 1),
-    PURE(NumberToUint32, Operator::kNoProperties, 1),
-    PURE(StringEqual, Operator::kCommutative, 2),
-    PURE(StringLessThan, Operator::kNoProperties, 2),
-    PURE(StringLessThanOrEqual, Operator::kNoProperties, 2),
-    PURE(StringAdd, Operator::kNoProperties, 2),
-    PURE(ChangeTaggedToInt32, Operator::kNoProperties, 1),
-    PURE(ChangeTaggedToUint32, Operator::kNoProperties, 1),
-    PURE(ChangeTaggedToFloat64, Operator::kNoProperties, 1),
-    PURE(ChangeInt32ToTagged, Operator::kNoProperties, 1),
-    PURE(ChangeUint32ToTagged, Operator::kNoProperties, 1),
-    PURE(ChangeFloat64ToTagged, Operator::kNoProperties, 1),
-    PURE(ChangeBoolToBit, Operator::kNoProperties, 1),
-    PURE(ChangeBitToBool, Operator::kNoProperties, 1)
-#undef PURE
-};
-
-}  // namespace
-
-
-class SimplifiedPureOperatorTest
-    : public TestWithZone,
-      public ::testing::WithParamInterface<PureOperator> {};
-
-
-TEST_P(SimplifiedPureOperatorTest, InstancesAreGloballyShared) {
-  const PureOperator& pop = GetParam();
-  SimplifiedOperatorBuilder simplified1(zone());
-  SimplifiedOperatorBuilder simplified2(zone());
-  EXPECT_EQ((simplified1.*pop.constructor)(), (simplified2.*pop.constructor)());
-}
-
-
-TEST_P(SimplifiedPureOperatorTest, NumberOfInputsAndOutputs) {
-  SimplifiedOperatorBuilder simplified(zone());
-  const PureOperator& pop = GetParam();
-  const Operator* op = (simplified.*pop.constructor)();
-
-  EXPECT_EQ(pop.value_input_count, OperatorProperties::GetValueInputCount(op));
-  EXPECT_EQ(0, OperatorProperties::GetEffectInputCount(op));
-  EXPECT_EQ(0, OperatorProperties::GetControlInputCount(op));
-  EXPECT_EQ(pop.value_input_count, OperatorProperties::GetTotalInputCount(op));
-
-  EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
-  EXPECT_EQ(0, OperatorProperties::GetEffectOutputCount(op));
-  EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
-}
-
-
-TEST_P(SimplifiedPureOperatorTest, OpcodeIsCorrect) {
-  SimplifiedOperatorBuilder simplified(zone());
-  const PureOperator& pop = GetParam();
-  const Operator* op = (simplified.*pop.constructor)();
-  EXPECT_EQ(pop.opcode, op->opcode());
-}
-
-
-TEST_P(SimplifiedPureOperatorTest, Properties) {
-  SimplifiedOperatorBuilder simplified(zone());
-  const PureOperator& pop = GetParam();
-  const Operator* op = (simplified.*pop.constructor)();
-  EXPECT_EQ(pop.properties, op->properties() & pop.properties);
-}
-
-INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, SimplifiedPureOperatorTest,
-                        ::testing::ValuesIn(kPureOperators));
-
-
-// -----------------------------------------------------------------------------
-// Element access operators.
-
-namespace {
-
-const ElementAccess kElementAccesses[] = {
-    {kTaggedBase, FixedArray::kHeaderSize, Type::Any(), kMachAnyTagged},
-    {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
-     kMachInt8},
-    {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
-     kMachInt16},
-    {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
-     kMachInt32},
-    {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
-     kMachUint8},
-    {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
-     kMachUint16},
-    {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
-     kMachUint32},
-    {kUntaggedBase, 0, Type::Signed32(), kMachInt8},
-    {kUntaggedBase, 0, Type::Unsigned32(), kMachUint8},
-    {kUntaggedBase, 0, Type::Signed32(), kMachInt16},
-    {kUntaggedBase, 0, Type::Unsigned32(), kMachUint16},
-    {kUntaggedBase, 0, Type::Signed32(), kMachInt32},
-    {kUntaggedBase, 0, Type::Unsigned32(), kMachUint32},
-    {kUntaggedBase, 0, Type::Number(), kRepFloat32},
-    {kUntaggedBase, 0, Type::Number(), kRepFloat64},
-    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
-     kMachInt8},
-    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
-     kMachUint8},
-    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
-     kMachInt16},
-    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
-     kMachUint16},
-    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
-     kMachInt32},
-    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
-     kMachUint32},
-    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
-     kRepFloat32},
-    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
-     kRepFloat64}};
-
-}  // namespace
-
-
-class SimplifiedElementAccessOperatorTest
-    : public TestWithZone,
-      public ::testing::WithParamInterface<ElementAccess> {};
-
-
-TEST_P(SimplifiedElementAccessOperatorTest, LoadElement) {
-  SimplifiedOperatorBuilder simplified(zone());
-  const ElementAccess& access = GetParam();
-  const Operator* op = simplified.LoadElement(access);
-
-  EXPECT_EQ(IrOpcode::kLoadElement, op->opcode());
-  EXPECT_EQ(Operator::kNoThrow | Operator::kNoWrite, op->properties());
-  EXPECT_EQ(access, ElementAccessOf(op));
-
-  EXPECT_EQ(3, OperatorProperties::GetValueInputCount(op));
-  EXPECT_EQ(1, OperatorProperties::GetEffectInputCount(op));
-  EXPECT_EQ(0, OperatorProperties::GetControlInputCount(op));
-  EXPECT_EQ(4, OperatorProperties::GetTotalInputCount(op));
-
-  EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
-  EXPECT_EQ(1, OperatorProperties::GetEffectOutputCount(op));
-  EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
-}
-
-
-TEST_P(SimplifiedElementAccessOperatorTest, StoreElement) {
-  SimplifiedOperatorBuilder simplified(zone());
-  const ElementAccess& access = GetParam();
-  const Operator* op = simplified.StoreElement(access);
-
-  EXPECT_EQ(IrOpcode::kStoreElement, op->opcode());
-  EXPECT_EQ(Operator::kNoRead | Operator::kNoThrow, op->properties());
-  EXPECT_EQ(access, ElementAccessOf(op));
-
-  EXPECT_EQ(4, OperatorProperties::GetValueInputCount(op));
-  EXPECT_EQ(1, OperatorProperties::GetEffectInputCount(op));
-  EXPECT_EQ(1, OperatorProperties::GetControlInputCount(op));
-  EXPECT_EQ(6, OperatorProperties::GetTotalInputCount(op));
-
-  EXPECT_EQ(0, OperatorProperties::GetValueOutputCount(op));
-  EXPECT_EQ(1, OperatorProperties::GetEffectOutputCount(op));
-  EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
-}
-
-
-INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest,
-                        SimplifiedElementAccessOperatorTest,
-                        ::testing::ValuesIn(kElementAccesses));
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/simplified-operator.cc b/src/compiler/simplified-operator.cc
index 642ffc7..9d88d12 100644
--- a/src/compiler/simplified-operator.cc
+++ b/src/compiler/simplified-operator.cc
@@ -13,7 +13,7 @@
 namespace internal {
 namespace compiler {
 
-OStream& operator<<(OStream& os, BaseTaggedness base_taggedness) {
+std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) {
   switch (base_taggedness) {
     case kUntaggedBase:
       return os << "untagged base";
@@ -25,9 +25,99 @@
 }
 
 
+MachineType BufferAccess::machine_type() const {
+  switch (external_array_type_) {
+    case kExternalUint8Array:
+    case kExternalUint8ClampedArray:
+      return kMachUint8;
+    case kExternalInt8Array:
+      return kMachInt8;
+    case kExternalUint16Array:
+      return kMachUint16;
+    case kExternalInt16Array:
+      return kMachInt16;
+    case kExternalUint32Array:
+      return kMachUint32;
+    case kExternalInt32Array:
+      return kMachInt32;
+    case kExternalFloat32Array:
+      return kMachFloat32;
+    case kExternalFloat64Array:
+      return kMachFloat64;
+  }
+  UNREACHABLE();
+  return kMachNone;
+}
+
+
+bool operator==(BufferAccess lhs, BufferAccess rhs) {
+  return lhs.external_array_type() == rhs.external_array_type();
+}
+
+
+bool operator!=(BufferAccess lhs, BufferAccess rhs) { return !(lhs == rhs); }
+
+
+size_t hash_value(BufferAccess access) {
+  return base::hash<ExternalArrayType>()(access.external_array_type());
+}
+
+
+std::ostream& operator<<(std::ostream& os, BufferAccess access) {
+  switch (access.external_array_type()) {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+  case kExternal##Type##Array:                          \
+    return os << #Type;
+    TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+  }
+  UNREACHABLE();
+  return os;
+}
+
+
+BufferAccess const BufferAccessOf(const Operator* op) {
+  DCHECK(op->opcode() == IrOpcode::kLoadBuffer ||
+         op->opcode() == IrOpcode::kStoreBuffer);
+  return OpParameter<BufferAccess>(op);
+}
+
+
+bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) {
+  return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset &&
+         lhs.machine_type == rhs.machine_type;
+}
+
+
+bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(FieldAccess const& access) {
+  return base::hash_combine(access.base_is_tagged, access.offset,
+                            access.machine_type);
+}
+
+
+std::ostream& operator<<(std::ostream& os, FieldAccess const& access) {
+  os << "[" << access.base_is_tagged << ", " << access.offset << ", ";
+#ifdef OBJECT_PRINT
+  Handle<Name> name;
+  if (access.name.ToHandle(&name)) {
+    name->Print(os);
+    os << ", ";
+  }
+#endif
+  access.type->PrintTo(os);
+  os << ", " << access.machine_type << "]";
+  return os;
+}
+
+
 bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) {
   return lhs.base_is_tagged == rhs.base_is_tagged &&
-         lhs.header_size == rhs.header_size && lhs.type == rhs.type &&
+         lhs.header_size == rhs.header_size &&
          lhs.machine_type == rhs.machine_type;
 }
 
@@ -37,10 +127,16 @@
 }
 
 
-OStream& operator<<(OStream& os, ElementAccess const& access) {
-  os << "[" << access.base_is_tagged << ", " << access.header_size << ", ";
+size_t hash_value(ElementAccess const& access) {
+  return base::hash_combine(access.base_is_tagged, access.header_size,
+                            access.machine_type);
+}
+
+
+std::ostream& operator<<(std::ostream& os, ElementAccess const& access) {
+  os << access.base_is_tagged << ", " << access.header_size << ", ";
   access.type->PrintTo(os);
-  os << ", " << access.machine_type << "]";
+  os << ", " << access.machine_type;
   return os;
 }
 
@@ -61,41 +157,8 @@
 }
 
 
-// Specialization for static parameters of type {FieldAccess}.
-template <>
-struct StaticParameterTraits<FieldAccess> {
-  static OStream& PrintTo(OStream& os, const FieldAccess& val) {
-    return os << val.offset;
-  }
-  static int HashCode(const FieldAccess& val) {
-    return (val.offset < 16) | (val.machine_type & 0xffff);
-  }
-  static bool Equals(const FieldAccess& lhs, const FieldAccess& rhs) {
-    return lhs.base_is_tagged == rhs.base_is_tagged &&
-           lhs.offset == rhs.offset && lhs.machine_type == rhs.machine_type &&
-           lhs.type->Is(rhs.type);
-  }
-};
-
-
-// Specialization for static parameters of type {ElementAccess}.
-template <>
-struct StaticParameterTraits<ElementAccess> {
-  static OStream& PrintTo(OStream& os, const ElementAccess& access) {
-    return os << access;
-  }
-  static int HashCode(const ElementAccess& access) {
-    return (access.header_size < 16) | (access.machine_type & 0xffff);
-  }
-  static bool Equals(const ElementAccess& lhs, const ElementAccess& rhs) {
-    return lhs.base_is_tagged == rhs.base_is_tagged &&
-           lhs.header_size == rhs.header_size &&
-           lhs.machine_type == rhs.machine_type && lhs.type->Is(rhs.type);
-  }
-};
-
-
 #define PURE_OP_LIST(V)                                \
+  V(AnyToBoolean, Operator::kNoProperties, 1)          \
   V(BooleanNot, Operator::kNoProperties, 1)            \
   V(BooleanToNumber, Operator::kNoProperties, 1)       \
   V(NumberEqual, Operator::kCommutative, 2)            \
@@ -119,56 +182,106 @@
   V(ChangeUint32ToTagged, Operator::kNoProperties, 1)  \
   V(ChangeFloat64ToTagged, Operator::kNoProperties, 1) \
   V(ChangeBoolToBit, Operator::kNoProperties, 1)       \
-  V(ChangeBitToBool, Operator::kNoProperties, 1)
+  V(ChangeBitToBool, Operator::kNoProperties, 1)       \
+  V(ObjectIsSmi, Operator::kNoProperties, 1)           \
+  V(ObjectIsNonNegativeSmi, Operator::kNoProperties, 1)
 
 
-#define ACCESS_OP_LIST(V)                                 \
-  V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1)     \
-  V(StoreField, FieldAccess, Operator::kNoRead, 2, 0)     \
-  V(LoadElement, ElementAccess, Operator::kNoWrite, 3, 1) \
-  V(StoreElement, ElementAccess, Operator::kNoRead, 4, 0)
-
-
-struct SimplifiedOperatorBuilderImpl FINAL {
-#define PURE(Name, properties, input_count)                               \
-  struct Name##Operator FINAL : public SimpleOperator {                   \
-    Name##Operator()                                                      \
-        : SimpleOperator(IrOpcode::k##Name, Operator::kPure | properties, \
-                         input_count, 1, #Name) {}                        \
-  };                                                                      \
+struct SimplifiedOperatorGlobalCache FINAL {
+#define PURE(Name, properties, input_count)                                \
+  struct Name##Operator FINAL : public Operator {                          \
+    Name##Operator()                                                       \
+        : Operator(IrOpcode::k##Name, Operator::kPure | properties, #Name, \
+                   input_count, 0, 0, 1, 0, 0) {}                          \
+  };                                                                       \
   Name##Operator k##Name;
   PURE_OP_LIST(PURE)
 #undef PURE
+
+#define BUFFER_ACCESS(Type, type, TYPE, ctype, size)                          \
+  struct LoadBuffer##Type##Operator FINAL : public Operator1<BufferAccess> {  \
+    LoadBuffer##Type##Operator()                                              \
+        : Operator1<BufferAccess>(IrOpcode::kLoadBuffer,                      \
+                                  Operator::kNoThrow | Operator::kNoWrite,    \
+                                  "LoadBuffer", 3, 1, 1, 1, 1, 0,             \
+                                  BufferAccess(kExternal##Type##Array)) {}    \
+  };                                                                          \
+  struct StoreBuffer##Type##Operator FINAL : public Operator1<BufferAccess> { \
+    StoreBuffer##Type##Operator()                                             \
+        : Operator1<BufferAccess>(IrOpcode::kStoreBuffer,                     \
+                                  Operator::kNoRead | Operator::kNoThrow,     \
+                                  "StoreBuffer", 4, 1, 1, 0, 1, 0,            \
+                                  BufferAccess(kExternal##Type##Array)) {}    \
+  };                                                                          \
+  LoadBuffer##Type##Operator kLoadBuffer##Type;                               \
+  StoreBuffer##Type##Operator kStoreBuffer##Type;
+  TYPED_ARRAYS(BUFFER_ACCESS)
+#undef BUFFER_ACCESS
 };
 
 
-static base::LazyInstance<SimplifiedOperatorBuilderImpl>::type kImpl =
+static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache =
     LAZY_INSTANCE_INITIALIZER;
 
 
 SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone)
-    : impl_(kImpl.Get()), zone_(zone) {}
+    : cache_(kCache.Get()), zone_(zone) {}
 
 
 #define PURE(Name, properties, input_count) \
-  const Operator* SimplifiedOperatorBuilder::Name() { return &impl_.k##Name; }
+  const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; }
 PURE_OP_LIST(PURE)
 #undef PURE
 
 
 const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) {
   // TODO(titzer): What about the type parameter?
-  return new (zone()) SimpleOperator(IrOpcode::kReferenceEqual,
-                                     Operator::kCommutative | Operator::kPure,
-                                     2, 1, "ReferenceEqual");
+  return new (zone()) Operator(IrOpcode::kReferenceEqual,
+                               Operator::kCommutative | Operator::kPure,
+                               "ReferenceEqual", 2, 0, 0, 1, 0, 0);
 }
 
 
-#define ACCESS(Name, Type, properties, input_count, output_count)           \
-  const Operator* SimplifiedOperatorBuilder::Name(const Type& access) {     \
-    return new (zone())                                                     \
-        Operator1<Type>(IrOpcode::k##Name, Operator::kNoThrow | properties, \
-                        input_count, output_count, #Name, access);          \
+const Operator* SimplifiedOperatorBuilder::LoadBuffer(BufferAccess access) {
+  switch (access.external_array_type()) {
+#define LOAD_BUFFER(Type, type, TYPE, ctype, size) \
+  case kExternal##Type##Array:                     \
+    return &cache_.kLoadBuffer##Type;
+    TYPED_ARRAYS(LOAD_BUFFER)
+#undef LOAD_BUFFER
+  }
+  UNREACHABLE();
+  return nullptr;
+}
+
+
+const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) {
+  switch (access.external_array_type()) {
+#define STORE_BUFFER(Type, type, TYPE, ctype, size) \
+  case kExternal##Type##Array:                      \
+    return &cache_.kStoreBuffer##Type;
+    TYPED_ARRAYS(STORE_BUFFER)
+#undef STORE_BUFFER
+  }
+  UNREACHABLE();
+  return nullptr;
+}
+
+
+#define ACCESS_OP_LIST(V)                                    \
+  V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1)     \
+  V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0)     \
+  V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \
+  V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0)
+
+
+#define ACCESS(Name, Type, properties, value_input_count, control_input_count, \
+               output_count)                                                   \
+  const Operator* SimplifiedOperatorBuilder::Name(const Type& access) {        \
+    return new (zone())                                                        \
+        Operator1<Type>(IrOpcode::k##Name, Operator::kNoThrow | properties,    \
+                        #Name, value_input_count, 1, control_input_count,      \
+                        output_count, 1, 0, access);                           \
   }
 ACCESS_OP_LIST(ACCESS)
 #undef ACCESS
diff --git a/src/compiler/simplified-operator.h b/src/compiler/simplified-operator.h
index 32f0e8b..22664fa 100644
--- a/src/compiler/simplified-operator.h
+++ b/src/compiler/simplified-operator.h
@@ -5,6 +5,8 @@
 #ifndef V8_COMPILER_SIMPLIFIED_OPERATOR_H_
 #define V8_COMPILER_SIMPLIFIED_OPERATOR_H_
 
+#include <iosfwd>
+
 #include "src/compiler/machine-type.h"
 #include "src/handles.h"
 
@@ -23,12 +25,36 @@
 
 // Forward declarations.
 class Operator;
-struct SimplifiedOperatorBuilderImpl;
+struct SimplifiedOperatorGlobalCache;
 
 
 enum BaseTaggedness { kUntaggedBase, kTaggedBase };
 
-OStream& operator<<(OStream&, BaseTaggedness);
+std::ostream& operator<<(std::ostream&, BaseTaggedness);
+
+
+// An access descriptor for loads/stores of array buffers.
+class BufferAccess FINAL {
+ public:
+  explicit BufferAccess(ExternalArrayType external_array_type)
+      : external_array_type_(external_array_type) {}
+
+  ExternalArrayType external_array_type() const { return external_array_type_; }
+  MachineType machine_type() const;
+
+ private:
+  ExternalArrayType const external_array_type_;
+};
+
+bool operator==(BufferAccess, BufferAccess);
+bool operator!=(BufferAccess, BufferAccess);
+
+size_t hash_value(BufferAccess);
+
+std::ostream& operator<<(std::ostream&, BufferAccess);
+
+BufferAccess const BufferAccessOf(const Operator* op) WARN_UNUSED_RESULT;
+
 
 // An access descriptor for loads/stores of fixed structures like field
 // accesses of heap objects. Accesses from either tagged or untagged base
@@ -36,13 +62,22 @@
 struct FieldAccess {
   BaseTaggedness base_is_tagged;  // specifies if the base pointer is tagged.
   int offset;                     // offset of the field, without tag.
-  Handle<Name> name;              // debugging only.
+  MaybeHandle<Name> name;         // debugging only.
   Type* type;                     // type of the field.
   MachineType machine_type;       // machine type of the field.
 
   int tag() const { return base_is_tagged == kTaggedBase ? kHeapObjectTag : 0; }
 };
 
+bool operator==(FieldAccess const&, FieldAccess const&);
+bool operator!=(FieldAccess const&, FieldAccess const&);
+
+size_t hash_value(FieldAccess const&);
+
+std::ostream& operator<<(std::ostream&, FieldAccess const&);
+
+FieldAccess const& FieldAccessOf(const Operator* op) WARN_UNUSED_RESULT;
+
 
 // An access descriptor for loads/stores of indexed structures like characters
 // in strings or off-heap backing stores. Accesses from either tagged or
@@ -57,18 +92,14 @@
   int tag() const { return base_is_tagged == kTaggedBase ? kHeapObjectTag : 0; }
 };
 
-bool operator==(ElementAccess const& lhs, ElementAccess const& rhs);
-bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs);
+bool operator==(ElementAccess const&, ElementAccess const&);
+bool operator!=(ElementAccess const&, ElementAccess const&);
 
-OStream& operator<<(OStream&, ElementAccess const&);
+size_t hash_value(ElementAccess const&);
 
+std::ostream& operator<<(std::ostream&, ElementAccess const&);
 
-// If the accessed object is not a heap object, add this to the header_size.
-static const int kNonHeapObjectHeaderSize = kHeapObjectTag;
-
-
-const FieldAccess& FieldAccessOf(const Operator* op) WARN_UNUSED_RESULT;
-const ElementAccess& ElementAccessOf(const Operator* op) WARN_UNUSED_RESULT;
+ElementAccess const& ElementAccessOf(const Operator* op) WARN_UNUSED_RESULT;
 
 
 // Interface for building simplified operators, which represent the
@@ -97,6 +128,8 @@
  public:
   explicit SimplifiedOperatorBuilder(Zone* zone);
 
+  const Operator* AnyToBoolean();
+
   const Operator* BooleanNot();
   const Operator* BooleanToNumber();
 
@@ -127,8 +160,17 @@
   const Operator* ChangeBoolToBit();
   const Operator* ChangeBitToBool();
 
-  const Operator* LoadField(const FieldAccess&);
-  const Operator* StoreField(const FieldAccess&);
+  const Operator* ObjectIsSmi();
+  const Operator* ObjectIsNonNegativeSmi();
+
+  const Operator* LoadField(FieldAccess const&);
+  const Operator* StoreField(FieldAccess const&);
+
+  // load-buffer buffer, offset, length
+  const Operator* LoadBuffer(BufferAccess);
+
+  // store-buffer buffer, offset, length, value
+  const Operator* StoreBuffer(BufferAccess);
 
   // load-element [base + index], length
   const Operator* LoadElement(ElementAccess const&);
@@ -139,7 +181,7 @@
  private:
   Zone* zone() const { return zone_; }
 
-  const SimplifiedOperatorBuilderImpl& impl_;
+  const SimplifiedOperatorGlobalCache& cache_;
   Zone* const zone_;
 
   DISALLOW_COPY_AND_ASSIGN(SimplifiedOperatorBuilder);
diff --git a/src/compiler/source-position.cc b/src/compiler/source-position.cc
index 1178390..9e21ae4 100644
--- a/src/compiler/source-position.cc
+++ b/src/compiler/source-position.cc
@@ -10,12 +10,12 @@
 namespace internal {
 namespace compiler {
 
-class SourcePositionTable::Decorator : public GraphDecorator {
+class SourcePositionTable::Decorator FINAL : public GraphDecorator {
  public:
   explicit Decorator(SourcePositionTable* source_positions)
       : source_positions_(source_positions) {}
 
-  virtual void Decorate(Node* node) {
+  void Decorate(Node* node) FINAL {
     DCHECK(!source_positions_->current_position_.IsInvalid());
     source_positions_->table_.Set(node, source_positions_->current_position_);
   }
@@ -46,7 +46,7 @@
 }
 
 
-SourcePosition SourcePositionTable::GetSourcePosition(Node* node) {
+SourcePosition SourcePositionTable::GetSourcePosition(Node* node) const {
   return table_.Get(node);
 }
 
diff --git a/src/compiler/source-position.h b/src/compiler/source-position.h
index 778f067..390a17d 100644
--- a/src/compiler/source-position.h
+++ b/src/compiler/source-position.h
@@ -79,7 +79,7 @@
   void AddDecorator();
   void RemoveDecorator();
 
-  SourcePosition GetSourcePosition(Node* node);
+  SourcePosition GetSourcePosition(Node* node) const;
 
  private:
   class Decorator;
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
index bfecdef..137829e 100644
--- a/src/compiler/typer.cc
+++ b/src/compiler/typer.cc
@@ -2,7 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "src/bootstrapper.h"
 #include "src/compiler/graph-inl.h"
+#include "src/compiler/graph-reducer.h"
 #include "src/compiler/js-operator.h"
 #include "src/compiler/node.h"
 #include "src/compiler/node-properties-inl.h"
@@ -14,64 +16,270 @@
 namespace internal {
 namespace compiler {
 
-Typer::Typer(Zone* zone) : zone_(zone) {
-  Type* number = Type::Number(zone);
-  Type* signed32 = Type::Signed32(zone);
-  Type* unsigned32 = Type::Unsigned32(zone);
-  Type* integral32 = Type::Integral32(zone);
-  Type* object = Type::Object(zone);
-  Type* undefined = Type::Undefined(zone);
+#define NATIVE_TYPES(V) \
+  V(Int8)               \
+  V(Uint8)              \
+  V(Int16)              \
+  V(Uint16)             \
+  V(Int32)              \
+  V(Uint32)             \
+  V(Float32)            \
+  V(Float64)
+
+enum LazyCachedType {
+  kNumberFunc0,
+  kNumberFunc1,
+  kNumberFunc2,
+  kImulFunc,
+  kClz32Func,
+  kArrayBufferFunc,
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+  k##Type, k##Type##Array, k##Type##ArrayFunc,
+  TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+      kNumLazyCachedTypes
+};
+
+
+// Constructs and caches types lazily.
+// TODO(turbofan): these types could be globally cached or cached per isolate.
+class LazyTypeCache FINAL : public ZoneObject {
+ public:
+  explicit LazyTypeCache(Zone* zone) : zone_(zone) {
+    memset(cache_, 0, sizeof(cache_));
+  }
+
+  inline Type* Get(LazyCachedType type) {
+    int index = static_cast<int>(type);
+    DCHECK(index < kNumLazyCachedTypes);
+    if (cache_[index] == NULL) cache_[index] = Create(type);
+    return cache_[index];
+  }
+
+ private:
+  Type* Create(LazyCachedType type) {
+    switch (type) {
+      case kInt8:
+        return CreateNative(CreateRange<int8_t>(), Type::UntaggedSigned8());
+      case kUint8:
+        return CreateNative(CreateRange<uint8_t>(), Type::UntaggedUnsigned8());
+      case kInt16:
+        return CreateNative(CreateRange<int16_t>(), Type::UntaggedSigned16());
+      case kUint16:
+        return CreateNative(CreateRange<uint16_t>(),
+                            Type::UntaggedUnsigned16());
+      case kInt32:
+        return CreateNative(Type::Signed32(), Type::UntaggedSigned32());
+      case kUint32:
+        return CreateNative(Type::Unsigned32(), Type::UntaggedUnsigned32());
+      case kFloat32:
+        return CreateNative(Type::Number(), Type::UntaggedFloat32());
+      case kFloat64:
+        return CreateNative(Type::Number(), Type::UntaggedFloat64());
+      case kUint8Clamped:
+        return Get(kUint8);
+      case kNumberFunc0:
+        return Type::Function(Type::Number(), zone());
+      case kNumberFunc1:
+        return Type::Function(Type::Number(), Type::Number(), zone());
+      case kNumberFunc2:
+        return Type::Function(Type::Number(), Type::Number(), Type::Number(),
+                              zone());
+      case kImulFunc:
+        return Type::Function(Type::Signed32(), Type::Integral32(),
+                              Type::Integral32(), zone());
+      case kClz32Func:
+        return Type::Function(CreateRange(0, 32), Type::Number(), zone());
+      case kArrayBufferFunc:
+        return Type::Function(Type::Object(zone()), Type::Unsigned32(), zone());
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+  case k##Type##Array:                                  \
+    return CreateArray(Get(k##Type));                   \
+  case k##Type##ArrayFunc:                              \
+    return CreateArrayFunction(Get(k##Type##Array));
+        TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+      case kNumLazyCachedTypes:
+        break;
+    }
+    UNREACHABLE();
+    return NULL;
+  }
+
+  Type* CreateArray(Type* element) const {
+    return Type::Array(element, zone());
+  }
+
+  Type* CreateArrayFunction(Type* array) const {
+    Type* arg1 = Type::Union(Type::Unsigned32(), Type::Object(), zone());
+    Type* arg2 = Type::Union(Type::Unsigned32(), Type::Undefined(), zone());
+    Type* arg3 = arg2;
+    return Type::Function(array, arg1, arg2, arg3, zone());
+  }
+
+  Type* CreateNative(Type* semantic, Type* representation) const {
+    return Type::Intersect(semantic, representation, zone());
+  }
+
+  template <typename T>
+  Type* CreateRange() const {
+    return CreateRange(std::numeric_limits<T>::min(),
+                       std::numeric_limits<T>::max());
+  }
+
+  Type* CreateRange(double min, double max) const {
+    return Type::Range(factory()->NewNumber(min), factory()->NewNumber(max),
+                       zone());
+  }
+
+  Factory* factory() const { return isolate()->factory(); }
+  Isolate* isolate() const { return zone()->isolate(); }
+  Zone* zone() const { return zone_; }
+
+  Type* cache_[kNumLazyCachedTypes];
+  Zone* zone_;
+};
+
+
+class Typer::Decorator FINAL : public GraphDecorator {
+ public:
+  explicit Decorator(Typer* typer) : typer_(typer) {}
+  void Decorate(Node* node) FINAL;
+
+ private:
+  Typer* typer_;
+};
+
+
+Typer::Typer(Graph* graph, MaybeHandle<Context> context)
+    : graph_(graph),
+      context_(context),
+      decorator_(NULL),
+      cache_(new (graph->zone()) LazyTypeCache(graph->zone())),
+      weaken_min_limits_(graph->zone()),
+      weaken_max_limits_(graph->zone()) {
+  Zone* zone = this->zone();
+  Factory* f = zone->isolate()->factory();
+
+  Handle<Object> zero = f->NewNumber(0);
+  Handle<Object> one = f->NewNumber(1);
+  Handle<Object> infinity = f->NewNumber(+V8_INFINITY);
+  Handle<Object> minusinfinity = f->NewNumber(-V8_INFINITY);
+
+  Type* number = Type::Number();
+  Type* signed32 = Type::Signed32();
+  Type* unsigned32 = Type::Unsigned32();
+  Type* nan_or_minuszero = Type::Union(Type::NaN(), Type::MinusZero(), zone);
+  Type* truncating_to_zero =
+      Type::Union(Type::Union(Type::Constant(infinity, zone),
+                              Type::Constant(minusinfinity, zone), zone),
+                  nan_or_minuszero, zone);
+
+  boolean_or_number = Type::Union(Type::Boolean(), Type::Number(), zone);
+  undefined_or_null = Type::Union(Type::Undefined(), Type::Null(), zone);
+  undefined_or_number = Type::Union(Type::Undefined(), Type::Number(), zone);
+  singleton_false = Type::Constant(f->false_value(), zone);
+  singleton_true = Type::Constant(f->true_value(), zone);
+  singleton_zero = Type::Range(zero, zero, zone);
+  singleton_one = Type::Range(one, one, zone);
+  zero_or_one = Type::Union(singleton_zero, singleton_one, zone);
+  zeroish = Type::Union(singleton_zero, nan_or_minuszero, zone);
+  signed32ish = Type::Union(signed32, truncating_to_zero, zone);
+  unsigned32ish = Type::Union(unsigned32, truncating_to_zero, zone);
+  falsish = Type::Union(Type::Undetectable(),
+                        Type::Union(Type::Union(singleton_false, zeroish, zone),
+                                    undefined_or_null, zone),
+                        zone);
+  truish = Type::Union(
+      singleton_true,
+      Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone), zone);
+  integer = Type::Range(minusinfinity, infinity, zone);
+  weakint = Type::Union(integer, nan_or_minuszero, zone);
+
   number_fun0_ = Type::Function(number, zone);
   number_fun1_ = Type::Function(number, number, zone);
   number_fun2_ = Type::Function(number, number, number, zone);
-  imul_fun_ = Type::Function(signed32, integral32, integral32, zone);
 
-#define NATIVE_TYPE(sem, rep) \
-  Type::Intersect(Type::sem(zone), Type::rep(zone), zone)
-  // TODO(rossberg): Use range types for more precision, once we have them.
-  Type* int8 = NATIVE_TYPE(SignedSmall, UntaggedInt8);
-  Type* int16 = NATIVE_TYPE(SignedSmall, UntaggedInt16);
-  Type* int32 = NATIVE_TYPE(Signed32, UntaggedInt32);
-  Type* uint8 = NATIVE_TYPE(UnsignedSmall, UntaggedInt8);
-  Type* uint16 = NATIVE_TYPE(UnsignedSmall, UntaggedInt16);
-  Type* uint32 = NATIVE_TYPE(Unsigned32, UntaggedInt32);
-  Type* float32 = NATIVE_TYPE(Number, UntaggedFloat32);
-  Type* float64 = NATIVE_TYPE(Number, UntaggedFloat64);
-#undef NATIVE_TYPE
-  Type* buffer = Type::Buffer(zone);
-  Type* int8_array = Type::Array(int8, zone);
-  Type* int16_array = Type::Array(int16, zone);
-  Type* int32_array = Type::Array(int32, zone);
-  Type* uint8_array = Type::Array(uint8, zone);
-  Type* uint16_array = Type::Array(uint16, zone);
-  Type* uint32_array = Type::Array(uint32, zone);
-  Type* float32_array = Type::Array(float32, zone);
-  Type* float64_array = Type::Array(float64, zone);
-  Type* arg1 = Type::Union(unsigned32, object, zone);
-  Type* arg2 = Type::Union(unsigned32, undefined, zone);
-  Type* arg3 = arg2;
-  array_buffer_fun_ = Type::Function(buffer, unsigned32, zone);
-  int8_array_fun_ = Type::Function(int8_array, arg1, arg2, arg3, zone);
-  int16_array_fun_ = Type::Function(int16_array, arg1, arg2, arg3, zone);
-  int32_array_fun_ = Type::Function(int32_array, arg1, arg2, arg3, zone);
-  uint8_array_fun_ = Type::Function(uint8_array, arg1, arg2, arg3, zone);
-  uint16_array_fun_ = Type::Function(uint16_array, arg1, arg2, arg3, zone);
-  uint32_array_fun_ = Type::Function(uint32_array, arg1, arg2, arg3, zone);
-  float32_array_fun_ = Type::Function(float32_array, arg1, arg2, arg3, zone);
-  float64_array_fun_ = Type::Function(float64_array, arg1, arg2, arg3, zone);
+  weakint_fun1_ = Type::Function(weakint, number, zone);
+  random_fun_ = Type::Function(Type::OrderedNumber(), zone);
+
+  const int limits_count = 20;
+
+  weaken_min_limits_.reserve(limits_count + 1);
+  weaken_max_limits_.reserve(limits_count + 1);
+
+  double limit = 1 << 30;
+  weaken_min_limits_.push_back(f->NewNumber(0));
+  weaken_max_limits_.push_back(f->NewNumber(0));
+  for (int i = 0; i < limits_count; i++) {
+    weaken_min_limits_.push_back(f->NewNumber(-limit));
+    weaken_max_limits_.push_back(f->NewNumber(limit - 1));
+    limit *= 2;
+  }
+
+  decorator_ = new (zone) Decorator(this);
+  graph_->AddDecorator(decorator_);
 }
 
 
-class Typer::Visitor : public NullNodeVisitor {
+Typer::~Typer() {
+  graph_->RemoveDecorator(decorator_);
+}
+
+
+class Typer::Visitor : public Reducer {
  public:
-  Visitor(Typer* typer, MaybeHandle<Context> context)
-      : typer_(typer), context_(context) {}
+  explicit Visitor(Typer* typer) : typer_(typer) {}
+
+  Reduction Reduce(Node* node) OVERRIDE {
+    if (node->op()->ValueOutputCount() == 0) return NoChange();
+    switch (node->opcode()) {
+#define DECLARE_CASE(x) \
+  case IrOpcode::k##x:  \
+    return UpdateBounds(node, TypeBinaryOp(node, x##Typer));
+      JS_SIMPLE_BINOP_LIST(DECLARE_CASE)
+#undef DECLARE_CASE
+
+#define DECLARE_CASE(x) \
+  case IrOpcode::k##x:  \
+    return UpdateBounds(node, Type##x(node));
+      DECLARE_CASE(Start)
+      // VALUE_OP_LIST without JS_SIMPLE_BINOP_LIST:
+      COMMON_OP_LIST(DECLARE_CASE)
+      SIMPLIFIED_OP_LIST(DECLARE_CASE)
+      MACHINE_OP_LIST(DECLARE_CASE)
+      JS_SIMPLE_UNOP_LIST(DECLARE_CASE)
+      JS_OBJECT_OP_LIST(DECLARE_CASE)
+      JS_CONTEXT_OP_LIST(DECLARE_CASE)
+      JS_OTHER_OP_LIST(DECLARE_CASE)
+#undef DECLARE_CASE
+
+#define DECLARE_CASE(x) case IrOpcode::k##x:
+      DECLARE_CASE(End)
+      INNER_CONTROL_OP_LIST(DECLARE_CASE)
+#undef DECLARE_CASE
+      break;
+    }
+    return NoChange();
+  }
 
   Bounds TypeNode(Node* node) {
     switch (node->opcode()) {
+#define DECLARE_CASE(x) \
+      case IrOpcode::k##x: return TypeBinaryOp(node, x##Typer);
+      JS_SIMPLE_BINOP_LIST(DECLARE_CASE)
+#undef DECLARE_CASE
+
 #define DECLARE_CASE(x) case IrOpcode::k##x: return Type##x(node);
       DECLARE_CASE(Start)
-      VALUE_OP_LIST(DECLARE_CASE)
+      // VALUE_OP_LIST without JS_SIMPLE_BINOP_LIST:
+      COMMON_OP_LIST(DECLARE_CASE)
+      SIMPLIFIED_OP_LIST(DECLARE_CASE)
+      MACHINE_OP_LIST(DECLARE_CASE)
+      JS_SIMPLE_UNOP_LIST(DECLARE_CASE)
+      JS_OBJECT_OP_LIST(DECLARE_CASE)
+      JS_CONTEXT_OP_LIST(DECLARE_CASE)
+      JS_OTHER_OP_LIST(DECLARE_CASE)
 #undef DECLARE_CASE
 
 #define DECLARE_CASE(x) case IrOpcode::k##x:
@@ -86,142 +294,288 @@
 
   Type* TypeConstant(Handle<Object> value);
 
- protected:
+ private:
+  Typer* typer_;
+  MaybeHandle<Context> context_;
+
 #define DECLARE_METHOD(x) inline Bounds Type##x(Node* node);
   DECLARE_METHOD(Start)
   VALUE_OP_LIST(DECLARE_METHOD)
 #undef DECLARE_METHOD
 
-  Bounds OperandType(Node* node, int i) {
-    return NodeProperties::GetBounds(NodeProperties::GetValueInput(node, i));
+  Bounds BoundsOrNone(Node* node) {
+    return NodeProperties::IsTyped(node) ? NodeProperties::GetBounds(node)
+                                         : Bounds(Type::None());
   }
 
-  Type* ContextType(Node* node) {
-    Bounds result =
-        NodeProperties::GetBounds(NodeProperties::GetContextInput(node));
+  Bounds Operand(Node* node, int i) {
+    Node* operand_node = NodeProperties::GetValueInput(node, i);
+    return BoundsOrNone(operand_node);
+  }
+
+  Bounds ContextOperand(Node* node) {
+    Bounds result = BoundsOrNone(NodeProperties::GetContextInput(node));
     DCHECK(result.upper->Maybe(Type::Internal()));
     // TODO(rossberg): More precisely, instead of the above assertion, we should
     // back-propagate the constraint that it has to be a subtype of Internal.
-    return result.upper;
+    return result;
   }
 
+  Type* Weaken(Type* current_type, Type* previous_type);
+
   Zone* zone() { return typer_->zone(); }
   Isolate* isolate() { return typer_->isolate(); }
-  MaybeHandle<Context> context() { return context_; }
+  Graph* graph() { return typer_->graph(); }
+  MaybeHandle<Context> context() { return typer_->context(); }
 
- private:
-  Typer* typer_;
-  MaybeHandle<Context> context_;
+  typedef Type* (*UnaryTyperFun)(Type*, Typer* t);
+  typedef Type* (*BinaryTyperFun)(Type*, Type*, Typer* t);
+
+  Bounds TypeUnaryOp(Node* node, UnaryTyperFun);
+  Bounds TypeBinaryOp(Node* node, BinaryTyperFun);
+
+  static Type* Invert(Type*, Typer*);
+  static Type* FalsifyUndefined(Type*, Typer*);
+  static Type* Rangify(Type*, Typer*);
+
+  static Type* ToPrimitive(Type*, Typer*);
+  static Type* ToBoolean(Type*, Typer*);
+  static Type* ToNumber(Type*, Typer*);
+  static Type* ToString(Type*, Typer*);
+  static Type* NumberToInt32(Type*, Typer*);
+  static Type* NumberToUint32(Type*, Typer*);
+
+  static Type* JSAddRanger(Type::RangeType*, Type::RangeType*, Typer*);
+  static Type* JSSubtractRanger(Type::RangeType*, Type::RangeType*, Typer*);
+  static Type* JSMultiplyRanger(Type::RangeType*, Type::RangeType*, Typer*);
+  static Type* JSDivideRanger(Type::RangeType*, Type::RangeType*, Typer*);
+  static Type* JSModulusRanger(Type::RangeType*, Type::RangeType*, Typer*);
+
+  static Type* JSCompareTyper(Type*, Type*, Typer*);
+
+#define DECLARE_METHOD(x) static Type* x##Typer(Type*, Type*, Typer*);
+  JS_SIMPLE_BINOP_LIST(DECLARE_METHOD)
+#undef DECLARE_METHOD
+
+  static Type* JSUnaryNotTyper(Type*, Typer*);
+  static Type* JSLoadPropertyTyper(Type*, Type*, Typer*);
+  static Type* JSCallFunctionTyper(Type*, Typer*);
+
+  Reduction UpdateBounds(Node* node, Bounds current) {
+    if (NodeProperties::IsTyped(node)) {
+      // Widen the bounds of a previously typed node.
+      Bounds previous = NodeProperties::GetBounds(node);
+      // Speed up termination in the presence of range types:
+      current.upper = Weaken(current.upper, previous.upper);
+      current.lower = Weaken(current.lower, previous.lower);
+
+      // Types should not get less precise.
+      DCHECK(previous.lower->Is(current.lower));
+      DCHECK(previous.upper->Is(current.upper));
+
+      NodeProperties::SetBounds(node, current);
+      if (!(previous.Narrows(current) && current.Narrows(previous))) {
+        // If something changed, revisit all uses.
+        return Changed(node);
+      }
+      return NoChange();
+    } else {
+      // No previous type, simply update the bounds.
+      NodeProperties::SetBounds(node, current);
+      return Changed(node);
+    }
+  }
 };
 
 
-class Typer::RunVisitor : public Typer::Visitor {
- public:
-  RunVisitor(Typer* typer, MaybeHandle<Context> context)
-      : Visitor(typer, context),
-        redo(NodeSet::key_compare(), NodeSet::allocator_type(typer->zone())) {}
-
-  GenericGraphVisit::Control Post(Node* node) {
-    if (OperatorProperties::HasValueOutput(node->op())) {
-      Bounds bounds = TypeNode(node);
-      NodeProperties::SetBounds(node, bounds);
-      // Remember incompletely typed nodes for least fixpoint iteration.
-      int arity = OperatorProperties::GetValueInputCount(node->op());
-      for (int i = 0; i < arity; ++i) {
-        // TODO(rossberg): change once IsTyped is available.
-        // if (!NodeProperties::IsTyped(NodeProperties::GetValueInput(node, i)))
-        if (OperandType(node, i).upper->Is(Type::None())) {
-          redo.insert(node);
-          break;
+void Typer::Run() {
+  {
+    // TODO(titzer): this is a hack. Reset types for interior nodes first.
+    NodeDeque deque(zone());
+    NodeMarker<bool> marked(graph(), 2);
+    deque.push_front(graph()->end());
+    marked.Set(graph()->end(), true);
+    while (!deque.empty()) {
+      Node* node = deque.front();
+      deque.pop_front();
+      // TODO(titzer): there shouldn't be a need to retype constants.
+      if (node->op()->ValueOutputCount() > 0)
+        NodeProperties::RemoveBounds(node);
+      for (Node* input : node->inputs()) {
+        if (!marked.Get(input)) {
+          marked.Set(input, true);
+          deque.push_back(input);
         }
       }
     }
-    return GenericGraphVisit::CONTINUE;
   }
 
-  NodeSet redo;
-};
+  Visitor visitor(this);
+  GraphReducer graph_reducer(graph(), zone());
+  graph_reducer.AddReducer(&visitor);
+  graph_reducer.ReduceGraph();
+}
 
 
-class Typer::NarrowVisitor : public Typer::Visitor {
- public:
-  NarrowVisitor(Typer* typer, MaybeHandle<Context> context)
-      : Visitor(typer, context) {}
-
-  GenericGraphVisit::Control Pre(Node* node) {
-    if (OperatorProperties::HasValueOutput(node->op())) {
-      Bounds previous = NodeProperties::GetBounds(node);
-      Bounds bounds = TypeNode(node);
-      NodeProperties::SetBounds(node, Bounds::Both(bounds, previous, zone()));
-      DCHECK(bounds.Narrows(previous));
-      // Stop when nothing changed (but allow re-entry in case it does later).
-      return previous.Narrows(bounds)
-          ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER;
-    } else {
-      return GenericGraphVisit::SKIP;
+void Typer::Decorator::Decorate(Node* node) {
+  if (node->op()->ValueOutputCount() > 0) {
+    // Only eagerly type-decorate nodes with known input types.
+    // Other cases will generally require a proper fixpoint iteration with Run.
+    bool is_typed = NodeProperties::IsTyped(node);
+    if (is_typed || NodeProperties::AllValueInputsAreTyped(node)) {
+      Visitor typing(typer_);
+      Bounds bounds = typing.TypeNode(node);
+      if (is_typed) {
+        bounds =
+          Bounds::Both(bounds, NodeProperties::GetBounds(node), typer_->zone());
+      }
+      NodeProperties::SetBounds(node, bounds);
     }
   }
-
-  GenericGraphVisit::Control Post(Node* node) {
-    return GenericGraphVisit::REENTER;
-  }
-};
-
-
-class Typer::WidenVisitor : public Typer::Visitor {
- public:
-  WidenVisitor(Typer* typer, MaybeHandle<Context> context)
-      : Visitor(typer, context) {}
-
-  GenericGraphVisit::Control Pre(Node* node) {
-    if (OperatorProperties::HasValueOutput(node->op())) {
-      Bounds previous = NodeProperties::GetBounds(node);
-      Bounds bounds = TypeNode(node);
-      DCHECK(previous.lower->Is(bounds.lower));
-      DCHECK(previous.upper->Is(bounds.upper));
-      NodeProperties::SetBounds(node, bounds);  // TODO(rossberg): Either?
-      // Stop when nothing changed (but allow re-entry in case it does later).
-      return bounds.Narrows(previous)
-          ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER;
-    } else {
-      return GenericGraphVisit::SKIP;
-    }
-  }
-
-  GenericGraphVisit::Control Post(Node* node) {
-    return GenericGraphVisit::REENTER;
-  }
-};
-
-
-void Typer::Run(Graph* graph, MaybeHandle<Context> context) {
-  RunVisitor typing(this, context);
-  graph->VisitNodeInputsFromEnd(&typing);
-  // Find least fixpoint.
-  for (NodeSetIter i = typing.redo.begin(); i != typing.redo.end(); ++i) {
-    Widen(graph, *i, context);
-  }
 }
 
 
-void Typer::Narrow(Graph* graph, Node* start, MaybeHandle<Context> context) {
-  NarrowVisitor typing(this, context);
-  graph->VisitNodeUsesFrom(start, &typing);
+// -----------------------------------------------------------------------------
+
+// Helper functions that lift a function f on types to a function on bounds,
+// and uses that to type the given node.  Note that f is never called with None
+// as an argument.
+
+
+Bounds Typer::Visitor::TypeUnaryOp(Node* node, UnaryTyperFun f) {
+  Bounds input = Operand(node, 0);
+  Type* upper = input.upper->Is(Type::None())
+      ? Type::None()
+      : f(input.upper, typer_);
+  Type* lower = input.lower->Is(Type::None())
+      ? Type::None()
+      : (input.lower == input.upper || upper->IsConstant())
+      ? upper  // TODO(neis): Extend this to Range(x,x), NaN, MinusZero, ...?
+      : f(input.lower, typer_);
+  // TODO(neis): Figure out what to do with lower bound.
+  return Bounds(lower, upper);
 }
 
 
-void Typer::Widen(Graph* graph, Node* start, MaybeHandle<Context> context) {
-  WidenVisitor typing(this, context);
-  graph->VisitNodeUsesFrom(start, &typing);
+Bounds Typer::Visitor::TypeBinaryOp(Node* node, BinaryTyperFun f) {
+  Bounds left = Operand(node, 0);
+  Bounds right = Operand(node, 1);
+  Type* upper = left.upper->Is(Type::None()) || right.upper->Is(Type::None())
+      ? Type::None()
+      : f(left.upper, right.upper, typer_);
+  Type* lower = left.lower->Is(Type::None()) || right.lower->Is(Type::None())
+      ? Type::None()
+      : ((left.lower == left.upper && right.lower == right.upper) ||
+         upper->IsConstant())
+      ? upper
+      : f(left.lower, right.lower, typer_);
+  // TODO(neis): Figure out what to do with lower bound.
+  return Bounds(lower, upper);
 }
 
 
-void Typer::Init(Node* node) {
-  if (OperatorProperties::HasValueOutput(node->op())) {
-    Visitor typing(this, MaybeHandle<Context>());
-    Bounds bounds = typing.TypeNode(node);
-    NodeProperties::SetBounds(node, bounds);
+Type* Typer::Visitor::Invert(Type* type, Typer* t) {
+  if (type->Is(t->singleton_false)) return t->singleton_true;
+  if (type->Is(t->singleton_true)) return t->singleton_false;
+  return type;
+}
+
+
+Type* Typer::Visitor::FalsifyUndefined(Type* type, Typer* t) {
+  if (type->Is(Type::Undefined())) return t->singleton_false;
+  return type;
+}
+
+
+Type* Typer::Visitor::Rangify(Type* type, Typer* t) {
+  if (type->IsRange()) return type;        // Shortcut.
+  if (!type->Is(t->integer) && !type->Is(Type::Integral32())) {
+    return type;  // Give up on non-integer types.
   }
+  double min = type->Min();
+  double max = type->Max();
+  // Handle the degenerate case of empty bitset types (such as
+  // OtherUnsigned31 and OtherSigned32 on 64-bit architectures).
+  if (std::isnan(min)) {
+    DCHECK(std::isnan(max));
+    return type;
+  }
+  Factory* f = t->isolate()->factory();
+  return Type::Range(f->NewNumber(min), f->NewNumber(max), t->zone());
+}
+
+
+// Type conversion.
+
+
+Type* Typer::Visitor::ToPrimitive(Type* type, Typer* t) {
+  if (type->Is(Type::Primitive()) && !type->Maybe(Type::Receiver())) {
+    return type;
+  }
+  return Type::Primitive();
+}
+
+
+Type* Typer::Visitor::ToBoolean(Type* type, Typer* t) {
+  if (type->Is(Type::Boolean())) return type;
+  if (type->Is(t->falsish)) return t->singleton_false;
+  if (type->Is(t->truish)) return t->singleton_true;
+  if (type->Is(Type::PlainNumber()) && (type->Max() < 0 || 0 < type->Min())) {
+    return t->singleton_true;  // Ruled out nan, -0 and +0.
+  }
+  return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::ToNumber(Type* type, Typer* t) {
+  if (type->Is(Type::Number())) return type;
+  if (type->Is(Type::Null())) return t->singleton_zero;
+  if (type->Is(Type::Undefined())) return Type::NaN();
+  if (type->Is(t->undefined_or_null)) {
+    return Type::Union(Type::NaN(), t->singleton_zero, t->zone());
+  }
+  if (type->Is(t->undefined_or_number)) {
+    return Type::Union(Type::Intersect(type, Type::Number(), t->zone()),
+                       Type::NaN(), t->zone());
+  }
+  if (type->Is(t->singleton_false)) return t->singleton_zero;
+  if (type->Is(t->singleton_true)) return t->singleton_one;
+  if (type->Is(Type::Boolean())) return t->zero_or_one;
+  if (type->Is(t->boolean_or_number)) {
+    return Type::Union(Type::Intersect(type, Type::Number(), t->zone()),
+                       t->zero_or_one, t->zone());
+  }
+  return Type::Number();
+}
+
+
+Type* Typer::Visitor::ToString(Type* type, Typer* t) {
+  if (type->Is(Type::String())) return type;
+  return Type::String();
+}
+
+
+Type* Typer::Visitor::NumberToInt32(Type* type, Typer* t) {
+  // TODO(neis): DCHECK(type->Is(Type::Number()));
+  if (type->Is(Type::Signed32())) return type;
+  if (type->Is(t->zeroish)) return t->singleton_zero;
+  if (type->Is(t->signed32ish)) {
+    return Type::Intersect(Type::Union(type, t->singleton_zero, t->zone()),
+                           Type::Signed32(), t->zone());
+  }
+  return Type::Signed32();
+}
+
+
+Type* Typer::Visitor::NumberToUint32(Type* type, Typer* t) {
+  // TODO(neis): DCHECK(type->Is(Type::Number()));
+  if (type->Is(Type::Unsigned32())) return type;
+  if (type->Is(t->zeroish)) return t->singleton_zero;
+  if (type->Is(t->unsigned32ish)) {
+    return Type::Intersect(Type::Union(type, t->singleton_zero, t->zone()),
+                           Type::Unsigned32(), t->zone());
+  }
+  return Type::Unsigned32();
 }
 
 
@@ -230,64 +584,75 @@
 
 // Control operators.
 
+
 Bounds Typer::Visitor::TypeStart(Node* node) {
-  return Bounds(Type::Internal(zone()));
+  return Bounds(Type::None(zone()), Type::Internal(zone()));
 }
 
 
 // Common operators.
 
+
 Bounds Typer::Visitor::TypeParameter(Node* node) {
   return Bounds::Unbounded(zone());
 }
 
 
 Bounds Typer::Visitor::TypeInt32Constant(Node* node) {
-  // TODO(titzer): only call Type::Of() if the type is not already known.
-  return Bounds(Type::Of(OpParameter<int32_t>(node), zone()));
+  Factory* f = isolate()->factory();
+  Handle<Object> number = f->NewNumber(OpParameter<int32_t>(node));
+  return Bounds(Type::Intersect(
+      Type::Range(number, number, zone()), Type::UntaggedSigned32(), zone()));
 }
 
 
 Bounds Typer::Visitor::TypeInt64Constant(Node* node) {
-  // TODO(titzer): only call Type::Of() if the type is not already known.
-  return Bounds(
-      Type::Of(static_cast<double>(OpParameter<int64_t>(node)), zone()));
+  // TODO(rossberg): This actually seems to be a PointerConstant so far...
+  return Bounds(Type::Internal());  // TODO(rossberg): Add int64 bitset type?
 }
 
 
 Bounds Typer::Visitor::TypeFloat32Constant(Node* node) {
-  // TODO(titzer): only call Type::Of() if the type is not already known.
-  return Bounds(Type::Of(OpParameter<float>(node), zone()));
+  return Bounds(Type::Intersect(
+      Type::Of(OpParameter<float>(node), zone()),
+      Type::UntaggedFloat32(), zone()));
 }
 
 
 Bounds Typer::Visitor::TypeFloat64Constant(Node* node) {
-  // TODO(titzer): only call Type::Of() if the type is not already known.
-  return Bounds(Type::Of(OpParameter<double>(node), zone()));
+  return Bounds(Type::Intersect(
+      Type::Of(OpParameter<double>(node), zone()),
+      Type::UntaggedFloat64(), zone()));
 }
 
 
 Bounds Typer::Visitor::TypeNumberConstant(Node* node) {
-  // TODO(titzer): only call Type::Of() if the type is not already known.
-  return Bounds(Type::Of(OpParameter<double>(node), zone()));
+  Factory* f = isolate()->factory();
+  return Bounds(Type::Constant(
+      f->NewNumber(OpParameter<double>(node)), zone()));
 }
 
 
 Bounds Typer::Visitor::TypeHeapConstant(Node* node) {
-  return Bounds(TypeConstant(OpParameter<Unique<Object> >(node).handle()));
+  return Bounds(TypeConstant(OpParameter<Unique<HeapObject> >(node).handle()));
 }
 
 
 Bounds Typer::Visitor::TypeExternalConstant(Node* node) {
-  return Bounds(Type::Internal(zone()));
+  return Bounds(Type::None(zone()), Type::Internal(zone()));
+}
+
+
+Bounds Typer::Visitor::TypeSelect(Node* node) {
+  return Bounds::Either(Operand(node, 1), Operand(node, 2), zone());
 }
 
 
 Bounds Typer::Visitor::TypePhi(Node* node) {
-  int arity = OperatorProperties::GetValueInputCount(node->op());
-  Bounds bounds = OperandType(node, 0);
+  int arity = node->op()->ValueInputCount();
+  Bounds bounds = Operand(node, 0);
   for (int i = 1; i < arity; ++i) {
-    bounds = Bounds::Either(bounds, OperandType(node, i), zone());
+    bounds = Bounds::Either(bounds, Operand(node, i), zone());
   }
   return bounds;
 }
@@ -299,12 +664,6 @@
 }
 
 
-Bounds Typer::Visitor::TypeControlEffect(Node* node) {
-  UNREACHABLE();
-  return Bounds();
-}
-
-
 Bounds Typer::Visitor::TypeValueEffect(Node* node) {
   UNREACHABLE();
   return Bounds();
@@ -312,18 +671,18 @@
 
 
 Bounds Typer::Visitor::TypeFinish(Node* node) {
-  return OperandType(node, 0);
+  return Operand(node, 0);
 }
 
 
 Bounds Typer::Visitor::TypeFrameState(Node* node) {
   // TODO(rossberg): Ideally FrameState wouldn't have a value output.
-  return Bounds(Type::Internal(zone()));
+  return Bounds(Type::None(zone()), Type::Internal(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeStateValues(Node* node) {
-  return Bounds(Type::Internal(zone()));
+  return Bounds(Type::None(zone()), Type::Internal(zone()));
 }
 
 
@@ -340,159 +699,541 @@
 
 // JS comparison operators.
 
-#define DEFINE_METHOD(x)                       \
-  Bounds Typer::Visitor::Type##x(Node* node) { \
-    return Bounds(Type::Boolean(zone()));      \
+
+Type* Typer::Visitor::JSEqualTyper(Type* lhs, Type* rhs, Typer* t) {
+  if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return t->singleton_false;
+  if (lhs->Is(t->undefined_or_null) && rhs->Is(t->undefined_or_null)) {
+    return t->singleton_true;
   }
-JS_COMPARE_BINOP_LIST(DEFINE_METHOD)
-#undef DEFINE_METHOD
+  if (lhs->Is(Type::Number()) && rhs->Is(Type::Number()) &&
+      (lhs->Max() < rhs->Min() || lhs->Min() > rhs->Max())) {
+      return t->singleton_false;
+  }
+  if (lhs->IsConstant() && rhs->Is(lhs)) {
+    // Types are equal and are inhabited only by a single semantic value,
+    // which is not nan due to the earlier check.
+    // TODO(neis): Extend this to Range(x,x), MinusZero, ...?
+    return t->singleton_true;
+  }
+  return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::JSNotEqualTyper(Type* lhs, Type* rhs, Typer* t) {
+  return Invert(JSEqualTyper(lhs, rhs, t), t);
+}
+
+
+static Type* JSType(Type* type) {
+  if (type->Is(Type::Boolean())) return Type::Boolean();
+  if (type->Is(Type::String())) return Type::String();
+  if (type->Is(Type::Number())) return Type::Number();
+  if (type->Is(Type::Undefined())) return Type::Undefined();
+  if (type->Is(Type::Null())) return Type::Null();
+  if (type->Is(Type::Symbol())) return Type::Symbol();
+  if (type->Is(Type::Receiver())) return Type::Receiver();  // JS "Object"
+  return Type::Any();
+}
+
+
+Type* Typer::Visitor::JSStrictEqualTyper(Type* lhs, Type* rhs, Typer* t) {
+  if (!JSType(lhs)->Maybe(JSType(rhs))) return t->singleton_false;
+  if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return t->singleton_false;
+  if (lhs->Is(Type::Number()) && rhs->Is(Type::Number()) &&
+      (lhs->Max() < rhs->Min() || lhs->Min() > rhs->Max())) {
+      return t->singleton_false;
+  }
+  if (lhs->IsConstant() && rhs->Is(lhs)) {
+    // Types are equal and are inhabited only by a single semantic value,
+    // which is not nan due to the earlier check.
+    return t->singleton_true;
+  }
+  return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::JSStrictNotEqualTyper(Type* lhs, Type* rhs, Typer* t) {
+  return Invert(JSStrictEqualTyper(lhs, rhs, t), t);
+}
+
+
+// The EcmaScript specification defines the four relational comparison operators
+// (<, <=, >=, >) with the help of a single abstract one.  It behaves like <
+// but returns undefined when the inputs cannot be compared.
+// We implement the typing analogously.
+Type* Typer::Visitor::JSCompareTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = ToPrimitive(lhs, t);
+  rhs = ToPrimitive(rhs, t);
+  if (lhs->Maybe(Type::String()) && rhs->Maybe(Type::String())) {
+    return Type::Boolean();
+  }
+  lhs = ToNumber(lhs, t);
+  rhs = ToNumber(rhs, t);
+  if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::Undefined();
+  if (lhs->IsConstant() && rhs->Is(lhs)) {
+    // Types are equal and are inhabited only by a single semantic value,
+    // which is not NaN due to the previous check.
+    return t->singleton_false;
+  }
+  if (lhs->Min() >= rhs->Max()) return t->singleton_false;
+  if (lhs->Max() < rhs->Min() &&
+      !lhs->Maybe(Type::NaN()) && !rhs->Maybe(Type::NaN())) {
+    return t->singleton_true;
+  }
+  return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::JSLessThanTyper(Type* lhs, Type* rhs, Typer* t) {
+  return FalsifyUndefined(JSCompareTyper(lhs, rhs, t), t);
+}
+
+
+Type* Typer::Visitor::JSGreaterThanTyper(Type* lhs, Type* rhs, Typer* t) {
+  return FalsifyUndefined(JSCompareTyper(rhs, lhs, t), t);
+}
+
+
+Type* Typer::Visitor::JSLessThanOrEqualTyper(Type* lhs, Type* rhs, Typer* t) {
+  return FalsifyUndefined(Invert(JSCompareTyper(rhs, lhs, t), t), t);
+}
+
+
+Type* Typer::Visitor::JSGreaterThanOrEqualTyper(
+    Type* lhs, Type* rhs, Typer* t) {
+  return FalsifyUndefined(Invert(JSCompareTyper(lhs, rhs, t), t), t);
+}
 
 
 // JS bitwise operators.
 
-Bounds Typer::Visitor::TypeJSBitwiseOr(Node* node) {
-  Bounds left = OperandType(node, 0);
-  Bounds right = OperandType(node, 1);
-  Type* upper = Type::Union(left.upper, right.upper, zone());
-  if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone());
-  Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone());
-  return Bounds(lower, upper);
+
+Type* Typer::Visitor::JSBitwiseOrTyper(Type* lhs, Type* rhs, Typer* t) {
+  Factory* f = t->isolate()->factory();
+  lhs = NumberToInt32(ToNumber(lhs, t), t);
+  rhs = NumberToInt32(ToNumber(rhs, t), t);
+  double lmin = lhs->Min();
+  double rmin = rhs->Min();
+  double lmax = lhs->Max();
+  double rmax = rhs->Max();
+  // Or-ing any two values results in a value no smaller than their minimum.
+  // Even no smaller than their maximum if both values are non-negative.
+  double min =
+      lmin >= 0 && rmin >= 0 ? std::max(lmin, rmin) : std::min(lmin, rmin);
+  double max = Type::Signed32()->Max();
+
+  // Or-ing with 0 is essentially a conversion to int32.
+  if (rmin == 0 && rmax == 0) {
+    min = lmin;
+    max = lmax;
+  }
+  if (lmin == 0 && lmax == 0) {
+    min = rmin;
+    max = rmax;
+  }
+
+  if (lmax < 0 || rmax < 0) {
+    // Or-ing two values of which at least one is negative results in a negative
+    // value.
+    max = std::min(max, -1.0);
+  }
+  return Type::Range(f->NewNumber(min), f->NewNumber(max), t->zone());
+  // TODO(neis): Be precise for singleton inputs, here and elsewhere.
 }
 
 
-Bounds Typer::Visitor::TypeJSBitwiseAnd(Node* node) {
-  Bounds left = OperandType(node, 0);
-  Bounds right = OperandType(node, 1);
-  Type* upper = Type::Union(left.upper, right.upper, zone());
-  if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone());
-  Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone());
-  return Bounds(lower, upper);
+Type* Typer::Visitor::JSBitwiseAndTyper(Type* lhs, Type* rhs, Typer* t) {
+  Factory* f = t->isolate()->factory();
+  lhs = NumberToInt32(ToNumber(lhs, t), t);
+  rhs = NumberToInt32(ToNumber(rhs, t), t);
+  double lmin = lhs->Min();
+  double rmin = rhs->Min();
+  double lmax = lhs->Max();
+  double rmax = rhs->Max();
+  double min = Type::Signed32()->Min();
+  // And-ing any two values results in a value no larger than their maximum.
+  // Even no larger than their minimum if both values are non-negative.
+  double max =
+      lmin >= 0 && rmin >= 0 ? std::min(lmax, rmax) : std::max(lmax, rmax);
+  // And-ing with a non-negative value x causes the result to be between
+  // zero and x.
+  if (lmin >= 0) {
+    min = 0;
+    max = std::min(max, lmax);
+  }
+  if (rmin >= 0) {
+    min = 0;
+    max = std::min(max, rmax);
+  }
+  return Type::Range(f->NewNumber(min), f->NewNumber(max), t->zone());
 }
 
 
-Bounds Typer::Visitor::TypeJSBitwiseXor(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()));
+Type* Typer::Visitor::JSBitwiseXorTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = NumberToInt32(ToNumber(lhs, t), t);
+  rhs = NumberToInt32(ToNumber(rhs, t), t);
+  double lmin = lhs->Min();
+  double rmin = rhs->Min();
+  double lmax = lhs->Max();
+  double rmax = rhs->Max();
+  if ((lmin >= 0 && rmin >= 0) || (lmax < 0 && rmax < 0)) {
+    // Xor-ing negative or non-negative values results in a non-negative value.
+    return Type::NonNegativeSigned32();
+  }
+  if ((lmax < 0 && rmin >= 0) || (lmin >= 0 && rmax < 0)) {
+    // Xor-ing a negative and a non-negative value results in a negative value.
+    // TODO(jarin) Use a range here.
+    return Type::NegativeSigned32();
+  }
+  return Type::Signed32();
 }
 
 
-Bounds Typer::Visitor::TypeJSShiftLeft(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()));
+Type* Typer::Visitor::JSShiftLeftTyper(Type* lhs, Type* rhs, Typer* t) {
+  return Type::Signed32();
 }
 
 
-Bounds Typer::Visitor::TypeJSShiftRight(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()));
+Type* Typer::Visitor::JSShiftRightTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = NumberToInt32(ToNumber(lhs, t), t);
+  rhs = NumberToUint32(ToNumber(rhs, t), t);
+  double min = kMinInt;
+  double max = kMaxInt;
+  if (lhs->Min() >= 0) {
+    // Right-shifting a non-negative value cannot make it negative, nor larger.
+    min = std::max(min, 0.0);
+    max = std::min(max, lhs->Max());
+  }
+  if (lhs->Max() < 0) {
+    // Right-shifting a negative value cannot make it non-negative, nor smaller.
+    min = std::max(min, lhs->Min());
+    max = std::min(max, -1.0);
+  }
+  if (rhs->Min() > 0 && rhs->Max() <= 31) {
+    // Right-shifting by a positive value yields a small integer value.
+    double shift_min = kMinInt >> static_cast<int>(rhs->Min());
+    double shift_max = kMaxInt >> static_cast<int>(rhs->Min());
+    min = std::max(min, shift_min);
+    max = std::min(max, shift_max);
+  }
+  // TODO(jarin) Ideally, the following micro-optimization should be performed
+  // by the type constructor.
+  if (max != Type::Signed32()->Max() || min != Type::Signed32()->Min()) {
+    Factory* f = t->isolate()->factory();
+    return Type::Range(f->NewNumber(min), f->NewNumber(max), t->zone());
+  }
+  return Type::Signed32();
 }
 
 
-Bounds Typer::Visitor::TypeJSShiftRightLogical(Node* node) {
-  return Bounds(Type::UnsignedSmall(zone()), Type::Unsigned32(zone()));
+Type* Typer::Visitor::JSShiftRightLogicalTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = NumberToUint32(ToNumber(lhs, t), t);
+  Factory* f = t->isolate()->factory();
+  // Logical right-shifting any value cannot make it larger.
+  Handle<Object> min = f->NewNumber(0);
+  Handle<Object> max = f->NewNumber(lhs->Max());
+  return Type::Range(min, max, t->zone());
 }
 
 
 // JS arithmetic operators.
 
-Bounds Typer::Visitor::TypeJSAdd(Node* node) {
-  Bounds left = OperandType(node, 0);
-  Bounds right = OperandType(node, 1);
-  Type* lower =
-      left.lower->Is(Type::None()) || right.lower->Is(Type::None()) ?
-          Type::None(zone()) :
-      left.lower->Is(Type::Number()) && right.lower->Is(Type::Number()) ?
-          Type::SignedSmall(zone()) :
-      left.lower->Is(Type::String()) || right.lower->Is(Type::String()) ?
-          Type::String(zone()) : Type::None(zone());
-  Type* upper =
-      left.upper->Is(Type::None()) && right.upper->Is(Type::None()) ?
-          Type::None(zone()) :
-      left.upper->Is(Type::Number()) && right.upper->Is(Type::Number()) ?
-          Type::Number(zone()) :
-      left.upper->Is(Type::String()) || right.upper->Is(Type::String()) ?
-          Type::String(zone()) : Type::NumberOrString(zone());
-  return Bounds(lower, upper);
+
+// Returns the array's least element, ignoring NaN.
+// There must be at least one non-NaN element.
+// Any -0 is converted to 0.
+static double array_min(double a[], size_t n) {
+  DCHECK(n != 0);
+  double x = +V8_INFINITY;
+  for (size_t i = 0; i < n; ++i) {
+    if (!std::isnan(a[i])) {
+      x = std::min(a[i], x);
+    }
+  }
+  DCHECK(!std::isnan(x));
+  return x == 0 ? 0 : x;  // -0 -> 0
 }
 
 
-Bounds Typer::Visitor::TypeJSSubtract(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
+// Returns the array's greatest element, ignoring NaN.
+// There must be at least one non-NaN element.
+// Any -0 is converted to 0.
+static double array_max(double a[], size_t n) {
+  DCHECK(n != 0);
+  double x = -V8_INFINITY;
+  for (size_t i = 0; i < n; ++i) {
+    if (!std::isnan(a[i])) {
+      x = std::max(a[i], x);
+    }
+  }
+  DCHECK(!std::isnan(x));
+  return x == 0 ? 0 : x;  // -0 -> 0
 }
 
 
-Bounds Typer::Visitor::TypeJSMultiply(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
+Type* Typer::Visitor::JSAddRanger(Type::RangeType* lhs, Type::RangeType* rhs,
+                                  Typer* t) {
+  double results[4];
+  results[0] = lhs->Min()->Number() + rhs->Min()->Number();
+  results[1] = lhs->Min()->Number() + rhs->Max()->Number();
+  results[2] = lhs->Max()->Number() + rhs->Min()->Number();
+  results[3] = lhs->Max()->Number() + rhs->Max()->Number();
+  // Since none of the inputs can be -0, the result cannot be -0 either.
+  // However, it can be nan (the sum of two infinities of opposite sign).
+  // On the other hand, if none of the "results" above is nan, then the actual
+  // result cannot be nan either.
+  int nans = 0;
+  for (int i = 0; i < 4; ++i) {
+    if (std::isnan(results[i])) ++nans;
+  }
+  if (nans == 4) return Type::NaN();  // [-inf..-inf] + [inf..inf] or vice versa
+  Factory* f = t->isolate()->factory();
+  Type* range = Type::Range(f->NewNumber(array_min(results, 4)),
+                            f->NewNumber(array_max(results, 4)), t->zone());
+  return nans == 0 ? range : Type::Union(range, Type::NaN(), t->zone());
+  // Examples:
+  //   [-inf, -inf] + [+inf, +inf] = NaN
+  //   [-inf, -inf] + [n, +inf] = [-inf, -inf] \/ NaN
+  //   [-inf, +inf] + [n, +inf] = [-inf, +inf] \/ NaN
+  //   [-inf, m] + [n, +inf] = [-inf, +inf] \/ NaN
 }
 
 
-Bounds Typer::Visitor::TypeJSDivide(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
+Type* Typer::Visitor::JSAddTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = ToPrimitive(lhs, t);
+  rhs = ToPrimitive(rhs, t);
+  if (lhs->Maybe(Type::String()) || rhs->Maybe(Type::String())) {
+    if (lhs->Is(Type::String()) || rhs->Is(Type::String())) {
+      return Type::String();
+    } else {
+      return Type::NumberOrString();
+    }
+  }
+  lhs = Rangify(ToNumber(lhs, t), t);
+  rhs = Rangify(ToNumber(rhs, t), t);
+  if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN();
+  if (lhs->IsRange() && rhs->IsRange()) {
+    return JSAddRanger(lhs->AsRange(), rhs->AsRange(), t);
+  }
+  // TODO(neis): Deal with numeric bitsets here and elsewhere.
+  return Type::Number();
 }
 
 
-Bounds Typer::Visitor::TypeJSModulus(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
+Type* Typer::Visitor::JSSubtractRanger(Type::RangeType* lhs,
+                                       Type::RangeType* rhs, Typer* t) {
+  double results[4];
+  results[0] = lhs->Min()->Number() - rhs->Min()->Number();
+  results[1] = lhs->Min()->Number() - rhs->Max()->Number();
+  results[2] = lhs->Max()->Number() - rhs->Min()->Number();
+  results[3] = lhs->Max()->Number() - rhs->Max()->Number();
+  // Since none of the inputs can be -0, the result cannot be -0.
+  // However, it can be nan (the subtraction of two infinities of same sign).
+  // On the other hand, if none of the "results" above is nan, then the actual
+  // result cannot be nan either.
+  int nans = 0;
+  for (int i = 0; i < 4; ++i) {
+    if (std::isnan(results[i])) ++nans;
+  }
+  if (nans == 4) return Type::NaN();  // [inf..inf] - [inf..inf] (all same sign)
+  Factory* f = t->isolate()->factory();
+  Type* range = Type::Range(f->NewNumber(array_min(results, 4)),
+                            f->NewNumber(array_max(results, 4)), t->zone());
+  return nans == 0 ? range : Type::Union(range, Type::NaN(), t->zone());
+  // Examples:
+  //   [-inf, +inf] - [-inf, +inf] = [-inf, +inf] \/ NaN
+  //   [-inf, -inf] - [-inf, -inf] = NaN
+  //   [-inf, -inf] - [n, +inf] = [-inf, -inf] \/ NaN
+  //   [m, +inf] - [-inf, n] = [-inf, +inf] \/ NaN
+}
+
+
+Type* Typer::Visitor::JSSubtractTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = Rangify(ToNumber(lhs, t), t);
+  rhs = Rangify(ToNumber(rhs, t), t);
+  if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN();
+  if (lhs->IsRange() && rhs->IsRange()) {
+    return JSSubtractRanger(lhs->AsRange(), rhs->AsRange(), t);
+  }
+  return Type::Number();
+}
+
+
+Type* Typer::Visitor::JSMultiplyRanger(Type::RangeType* lhs,
+                                       Type::RangeType* rhs, Typer* t) {
+  double results[4];
+  double lmin = lhs->Min()->Number();
+  double lmax = lhs->Max()->Number();
+  double rmin = rhs->Min()->Number();
+  double rmax = rhs->Max()->Number();
+  results[0] = lmin * rmin;
+  results[1] = lmin * rmax;
+  results[2] = lmax * rmin;
+  results[3] = lmax * rmax;
+  // If the result may be nan, we give up on calculating a precise type, because
+  // the discontinuity makes it too complicated.  Note that even if none of the
+  // "results" above is nan, the actual result may still be, so we have to do a
+  // different check:
+  bool maybe_nan = (lhs->Maybe(t->singleton_zero) &&
+                    (rmin == -V8_INFINITY || rmax == +V8_INFINITY)) ||
+                   (rhs->Maybe(t->singleton_zero) &&
+                    (lmin == -V8_INFINITY || lmax == +V8_INFINITY));
+  if (maybe_nan) return t->weakint;  // Giving up.
+  bool maybe_minuszero = (lhs->Maybe(t->singleton_zero) && rmin < 0) ||
+                         (rhs->Maybe(t->singleton_zero) && lmin < 0);
+  Factory* f = t->isolate()->factory();
+  Type* range = Type::Range(f->NewNumber(array_min(results, 4)),
+                            f->NewNumber(array_max(results, 4)), t->zone());
+  return maybe_minuszero ? Type::Union(range, Type::MinusZero(), t->zone())
+                         : range;
+}
+
+
+Type* Typer::Visitor::JSMultiplyTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = Rangify(ToNumber(lhs, t), t);
+  rhs = Rangify(ToNumber(rhs, t), t);
+  if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN();
+  if (lhs->IsRange() && rhs->IsRange()) {
+    return JSMultiplyRanger(lhs->AsRange(), rhs->AsRange(), t);
+  }
+  return Type::Number();
+}
+
+
+Type* Typer::Visitor::JSDivideTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = ToNumber(lhs, t);
+  rhs = ToNumber(rhs, t);
+  if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN();
+  // Division is tricky, so all we do is try ruling out nan.
+  // TODO(neis): try ruling out -0 as well?
+  bool maybe_nan =
+      lhs->Maybe(Type::NaN()) || rhs->Maybe(t->zeroish) ||
+      ((lhs->Min() == -V8_INFINITY || lhs->Max() == +V8_INFINITY) &&
+       (rhs->Min() == -V8_INFINITY || rhs->Max() == +V8_INFINITY));
+  return maybe_nan ? Type::Number() : Type::OrderedNumber();
+}
+
+
+Type* Typer::Visitor::JSModulusRanger(Type::RangeType* lhs,
+                                      Type::RangeType* rhs, Typer* t) {
+  double lmin = lhs->Min()->Number();
+  double lmax = lhs->Max()->Number();
+  double rmin = rhs->Min()->Number();
+  double rmax = rhs->Max()->Number();
+
+  double labs = std::max(std::abs(lmin), std::abs(lmax));
+  double rabs = std::max(std::abs(rmin), std::abs(rmax)) - 1;
+  double abs = std::min(labs, rabs);
+  bool maybe_minus_zero = false;
+  double omin = 0;
+  double omax = 0;
+  if (lmin >= 0) {  // {lhs} positive.
+    omin = 0;
+    omax = abs;
+  } else if (lmax <= 0) {  // {lhs} negative.
+    omin = 0 - abs;
+    omax = 0;
+    maybe_minus_zero = true;
+  } else {
+    omin = 0 - abs;
+    omax = abs;
+    maybe_minus_zero = true;
+  }
+
+  Factory* f = t->isolate()->factory();
+  Type* result = Type::Range(f->NewNumber(omin), f->NewNumber(omax), t->zone());
+  if (maybe_minus_zero)
+    result = Type::Union(result, Type::MinusZero(), t->zone());
+  return result;
+}
+
+
+Type* Typer::Visitor::JSModulusTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = ToNumber(lhs, t);
+  rhs = ToNumber(rhs, t);
+  if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN();
+
+  if (lhs->Maybe(Type::NaN()) || rhs->Maybe(t->zeroish) ||
+      lhs->Min() == -V8_INFINITY || lhs->Max() == +V8_INFINITY) {
+    // Result maybe NaN.
+    return Type::Number();
+  }
+
+  lhs = Rangify(lhs, t);
+  rhs = Rangify(rhs, t);
+  if (lhs->IsRange() && rhs->IsRange()) {
+    return JSModulusRanger(lhs->AsRange(), rhs->AsRange(), t);
+  }
+  return Type::OrderedNumber();
 }
 
 
 // JS unary operators.
 
+
+Type* Typer::Visitor::JSUnaryNotTyper(Type* type, Typer* t) {
+  return Invert(ToBoolean(type, t), t);
+}
+
+
 Bounds Typer::Visitor::TypeJSUnaryNot(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return TypeUnaryOp(node, JSUnaryNotTyper);
 }
 
 
 Bounds Typer::Visitor::TypeJSTypeOf(Node* node) {
-  return Bounds(Type::InternalizedString(zone()));
+  return Bounds(Type::None(zone()), Type::InternalizedString(zone()));
 }
 
 
 // JS conversion operators.
 
+
 Bounds Typer::Visitor::TypeJSToBoolean(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return TypeUnaryOp(node, ToBoolean);
 }
 
 
 Bounds Typer::Visitor::TypeJSToNumber(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
+  return TypeUnaryOp(node, ToNumber);
 }
 
 
 Bounds Typer::Visitor::TypeJSToString(Node* node) {
-  return Bounds(Type::None(zone()), Type::String(zone()));
+  return TypeUnaryOp(node, ToString);
 }
 
 
 Bounds Typer::Visitor::TypeJSToName(Node* node) {
-  return Bounds(Type::None(zone()), Type::Name(zone()));
+  return Bounds(Type::None(), Type::Name());
 }
 
 
 Bounds Typer::Visitor::TypeJSToObject(Node* node) {
-  return Bounds(Type::None(zone()), Type::Receiver(zone()));
+  return Bounds(Type::None(), Type::Receiver());
 }
 
 
 // JS object operators.
 
+
 Bounds Typer::Visitor::TypeJSCreate(Node* node) {
-  return Bounds(Type::None(zone()), Type::Object(zone()));
+  return Bounds(Type::None(), Type::Object());
+}
+
+
+Type* Typer::Visitor::JSLoadPropertyTyper(Type* object, Type* name, Typer* t) {
+  // TODO(rossberg): Use range types and sized array types to filter undefined.
+  if (object->IsArray() && name->Is(Type::Integral32())) {
+    return Type::Union(
+        object->AsArray()->Element(), Type::Undefined(), t->zone());
+  }
+  return Type::Any();
 }
 
 
 Bounds Typer::Visitor::TypeJSLoadProperty(Node* node) {
-  Bounds object = OperandType(node, 0);
-  Bounds name = OperandType(node, 1);
-  Bounds result = Bounds::Unbounded(zone());
-  // TODO(rossberg): Use range types and sized array types to filter undefined.
-  if (object.lower->IsArray() && name.lower->Is(Type::Integral32())) {
-    result.lower = Type::Union(
-        object.lower->AsArray()->Element(), Type::Undefined(zone()), zone());
-  }
-  if (object.upper->IsArray() && name.upper->Is(Type::Integral32())) {
-    result.upper = Type::Union(
-        object.upper->AsArray()->Element(),  Type::Undefined(zone()), zone());
-  }
-  return result;
+  return TypeBinaryOp(node, JSLoadPropertyTyper);
 }
 
 
@@ -501,6 +1242,52 @@
 }
 
 
+// Returns a somewhat larger range if we previously assigned
+// a (smaller) range to this node. This is used  to speed up
+// the fixpoint calculation in case there appears to be a loop
+// in the graph. In the current implementation, we are
+// increasing the limits to the closest power of two.
+Type* Typer::Visitor::Weaken(Type* current_type, Type* previous_type) {
+  Type::RangeType* previous = previous_type->GetRange();
+  Type::RangeType* current = current_type->GetRange();
+  if (previous != NULL && current != NULL) {
+    double current_min = current->Min()->Number();
+    Handle<Object> new_min = current->Min();
+
+    // Find the closest lower entry in the list of allowed
+    // minima (or negative infinity if there is no such entry).
+    if (current_min != previous->Min()->Number()) {
+      new_min = typer_->integer->AsRange()->Min();
+      for (const auto val : typer_->weaken_min_limits_) {
+        if (val->Number() <= current_min) {
+          new_min = val;
+          break;
+        }
+      }
+    }
+
+    double current_max = current->Max()->Number();
+    Handle<Object> new_max = current->Max();
+    // Find the closest greater entry in the list of allowed
+    // maxima (or infinity if there is no such entry).
+    if (current_max != previous->Max()->Number()) {
+      new_max = typer_->integer->AsRange()->Max();
+      for (const auto val : typer_->weaken_max_limits_) {
+        if (val->Number() >= current_max) {
+          new_max = val;
+          break;
+        }
+      }
+    }
+
+    return Type::Union(current_type,
+                       Type::Range(new_min, new_max, typer_->zone()),
+                       typer_->zone());
+  }
+  return current_type;
+}
+
+
 Bounds Typer::Visitor::TypeJSStoreProperty(Node* node) {
   UNREACHABLE();
   return Bounds();
@@ -514,30 +1301,36 @@
 
 
 Bounds Typer::Visitor::TypeJSDeleteProperty(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::None(zone()), Type::Boolean(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeJSHasProperty(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::None(zone()), Type::Boolean(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeJSInstanceOf(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::None(zone()), Type::Boolean(zone()));
 }
 
 
 // JS context operators.
 
+
 Bounds Typer::Visitor::TypeJSLoadContext(Node* node) {
-  Bounds outer = OperandType(node, 0);
-  DCHECK(outer.upper->Maybe(Type::Internal()));
+  Bounds outer = Operand(node, 0);
+  Type* context_type = outer.upper;
+  if (context_type->Is(Type::None())) {
+    // Upper bound of context is not yet known.
+    return Bounds(Type::None(), Type::Any());
+  }
+
+  DCHECK(context_type->Maybe(Type::Internal()));
   // TODO(rossberg): More precisely, instead of the above assertion, we should
   // back-propagate the constraint that it has to be a subtype of Internal.
 
   ContextAccess access = OpParameter<ContextAccess>(node);
-  Type* context_type = outer.upper;
   MaybeHandle<Context> context;
   if (context_type->IsConstant()) {
     context = Handle<Context>::cast(context_type->AsConstant()->Value());
@@ -547,7 +1340,7 @@
   // bound.
   // TODO(rossberg): Could use scope info to fix upper bounds for constant
   // bindings if we know that this code is never shared.
-  for (int i = access.depth(); i > 0; --i) {
+  for (size_t i = access.depth(); i > 0; --i) {
     if (context_type->IsContext()) {
       context_type = context_type->AsContext()->Outer();
       if (context_type->IsConstant()) {
@@ -561,9 +1354,10 @@
     return Bounds::Unbounded(zone());
   } else {
     Handle<Object> value =
-        handle(context.ToHandleChecked()->get(access.index()), isolate());
+        handle(context.ToHandleChecked()->get(static_cast<int>(access.index())),
+               isolate());
     Type* lower = TypeConstant(value);
-    return Bounds(lower, Type::Any(zone()));
+    return Bounds(lower, Type::Any());
   }
 }
 
@@ -575,61 +1369,62 @@
 
 
 Bounds Typer::Visitor::TypeJSCreateFunctionContext(Node* node) {
-  Type* outer = ContextType(node);
-  return Bounds(Type::Context(outer, zone()));
+  Bounds outer = ContextOperand(node);
+  return Bounds(Type::Context(outer.upper, zone()));
 }
 
 
 Bounds Typer::Visitor::TypeJSCreateCatchContext(Node* node) {
-  Type* outer = ContextType(node);
-  return Bounds(Type::Context(outer, zone()));
+  Bounds outer = ContextOperand(node);
+  return Bounds(Type::Context(outer.upper, zone()));
 }
 
 
 Bounds Typer::Visitor::TypeJSCreateWithContext(Node* node) {
-  Type* outer = ContextType(node);
-  return Bounds(Type::Context(outer, zone()));
+  Bounds outer = ContextOperand(node);
+  return Bounds(Type::Context(outer.upper, zone()));
 }
 
 
 Bounds Typer::Visitor::TypeJSCreateBlockContext(Node* node) {
-  Type* outer = ContextType(node);
-  return Bounds(Type::Context(outer, zone()));
+  Bounds outer = ContextOperand(node);
+  return Bounds(Type::Context(outer.upper, zone()));
 }
 
 
 Bounds Typer::Visitor::TypeJSCreateModuleContext(Node* node) {
   // TODO(rossberg): this is probably incorrect
-  Type* outer = ContextType(node);
-  return Bounds(Type::Context(outer, zone()));
+  Bounds outer = ContextOperand(node);
+  return Bounds(Type::Context(outer.upper, zone()));
 }
 
 
-Bounds Typer::Visitor::TypeJSCreateGlobalContext(Node* node) {
-  Type* outer = ContextType(node);
-  return Bounds(Type::Context(outer, zone()));
+Bounds Typer::Visitor::TypeJSCreateScriptContext(Node* node) {
+  Bounds outer = ContextOperand(node);
+  return Bounds(Type::Context(outer.upper, zone()));
 }
 
 
 // JS other operators.
 
+
 Bounds Typer::Visitor::TypeJSYield(Node* node) {
   return Bounds::Unbounded(zone());
 }
 
 
 Bounds Typer::Visitor::TypeJSCallConstruct(Node* node) {
-  return Bounds(Type::None(zone()), Type::Receiver(zone()));
+  return Bounds(Type::None(), Type::Receiver());
+}
+
+
+Type* Typer::Visitor::JSCallFunctionTyper(Type* fun, Typer* t) {
+  return fun->IsFunction() ? fun->AsFunction()->Result() : Type::Any();
 }
 
 
 Bounds Typer::Visitor::TypeJSCallFunction(Node* node) {
-  Bounds fun = OperandType(node, 0);
-  Type* lower = fun.lower->IsFunction()
-      ? fun.lower->AsFunction()->Result() : Type::None(zone());
-  Type* upper = fun.upper->IsFunction()
-      ? fun.upper->AsFunction()->Result() : Type::Any(zone());
-  return Bounds(lower, upper);
+  return TypeUnaryOp(node, JSCallFunctionTyper);  // We ignore argument types.
 }
 
 
@@ -645,143 +1440,177 @@
 
 // Simplified operators.
 
+
+Bounds Typer::Visitor::TypeAnyToBoolean(Node* node) {
+  return TypeUnaryOp(node, ToBoolean);
+}
+
+
 Bounds Typer::Visitor::TypeBooleanNot(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::None(zone()), Type::Boolean(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeBooleanToNumber(Node* node) {
-  return Bounds(Type::Number(zone()));
+  return Bounds(Type::None(zone()), typer_->zero_or_one);
 }
 
 
 Bounds Typer::Visitor::TypeNumberEqual(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::None(zone()), Type::Boolean(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeNumberLessThan(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::None(zone()), Type::Boolean(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeNumberLessThanOrEqual(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::None(zone()), Type::Boolean(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeNumberAdd(Node* node) {
-  return Bounds(Type::Number(zone()));
+  return Bounds(Type::None(zone()), Type::Number(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeNumberSubtract(Node* node) {
-  return Bounds(Type::Number(zone()));
+  return Bounds(Type::None(zone()), Type::Number(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeNumberMultiply(Node* node) {
-  return Bounds(Type::Number(zone()));
+  return Bounds(Type::None(zone()), Type::Number(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeNumberDivide(Node* node) {
-  return Bounds(Type::Number(zone()));
+  return Bounds(Type::None(zone()), Type::Number(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeNumberModulus(Node* node) {
-  return Bounds(Type::Number(zone()));
+  return Bounds(Type::None(zone()), Type::Number(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeNumberToInt32(Node* node) {
-  Bounds arg = OperandType(node, 0);
-  Type* s32 = Type::Signed32(zone());
-  Type* lower = arg.lower->Is(s32) ? arg.lower : s32;
-  Type* upper = arg.upper->Is(s32) ? arg.upper : s32;
-  return Bounds(lower, upper);
+  return TypeUnaryOp(node, NumberToInt32);
 }
 
 
 Bounds Typer::Visitor::TypeNumberToUint32(Node* node) {
-  Bounds arg = OperandType(node, 0);
-  Type* u32 = Type::Unsigned32(zone());
-  Type* lower = arg.lower->Is(u32) ? arg.lower : u32;
-  Type* upper = arg.upper->Is(u32) ? arg.upper : u32;
-  return Bounds(lower, upper);
+  return TypeUnaryOp(node, NumberToUint32);
 }
 
 
 Bounds Typer::Visitor::TypeReferenceEqual(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::None(zone()), Type::Boolean(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeStringEqual(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::None(zone()), Type::Boolean(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeStringLessThan(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::None(zone()), Type::Boolean(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeStringLessThanOrEqual(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::None(zone()), Type::Boolean(zone()));
 }
 
 
 Bounds Typer::Visitor::TypeStringAdd(Node* node) {
-  return Bounds(Type::String(zone()));
+  return Bounds(Type::None(zone()), Type::String(zone()));
+}
+
+
+static Type* ChangeRepresentation(Type* type, Type* rep, Zone* zone) {
+  // TODO(neis): Enable when expressible.
+  /*
+  return Type::Union(
+      Type::Intersect(type, Type::Semantic(), zone),
+      Type::Intersect(rep, Type::Representation(), zone), zone);
+  */
+  return type;
 }
 
 
 Bounds Typer::Visitor::TypeChangeTaggedToInt32(Node* node) {
-  // TODO(titzer): type is type of input, representation is Word32.
-  return Bounds(Type::Integral32());
+  Bounds arg = Operand(node, 0);
+  // TODO(neis): DCHECK(arg.upper->Is(Type::Signed32()));
+  return Bounds(
+      ChangeRepresentation(arg.lower, Type::UntaggedSigned32(), zone()),
+      ChangeRepresentation(arg.upper, Type::UntaggedSigned32(), zone()));
 }
 
 
 Bounds Typer::Visitor::TypeChangeTaggedToUint32(Node* node) {
-  return Bounds(Type::Integral32());  // TODO(titzer): add appropriate rep
+  Bounds arg = Operand(node, 0);
+  // TODO(neis): DCHECK(arg.upper->Is(Type::Unsigned32()));
+  return Bounds(
+      ChangeRepresentation(arg.lower, Type::UntaggedUnsigned32(), zone()),
+      ChangeRepresentation(arg.upper, Type::UntaggedUnsigned32(), zone()));
 }
 
 
 Bounds Typer::Visitor::TypeChangeTaggedToFloat64(Node* node) {
-  // TODO(titzer): type is type of input, representation is Float64.
-  return Bounds(Type::Number());
+  Bounds arg = Operand(node, 0);
+  // TODO(neis): DCHECK(arg.upper->Is(Type::Number()));
+  return Bounds(
+      ChangeRepresentation(arg.lower, Type::UntaggedFloat64(), zone()),
+      ChangeRepresentation(arg.upper, Type::UntaggedFloat64(), zone()));
 }
 
 
 Bounds Typer::Visitor::TypeChangeInt32ToTagged(Node* node) {
-  // TODO(titzer): type is type of input, representation is Tagged.
-  return Bounds(Type::Integral32());
+  Bounds arg = Operand(node, 0);
+  // TODO(neis): DCHECK(arg.upper->Is(Type::Signed32()));
+  return Bounds(
+      ChangeRepresentation(arg.lower, Type::Tagged(), zone()),
+      ChangeRepresentation(arg.upper, Type::Tagged(), zone()));
 }
 
 
 Bounds Typer::Visitor::TypeChangeUint32ToTagged(Node* node) {
-  // TODO(titzer): type is type of input, representation is Tagged.
-  return Bounds(Type::Unsigned32());
+  Bounds arg = Operand(node, 0);
+  // TODO(neis): DCHECK(arg.upper->Is(Type::Unsigned32()));
+  return Bounds(
+      ChangeRepresentation(arg.lower, Type::Tagged(), zone()),
+      ChangeRepresentation(arg.upper, Type::Tagged(), zone()));
 }
 
 
 Bounds Typer::Visitor::TypeChangeFloat64ToTagged(Node* node) {
-  // TODO(titzer): type is type of input, representation is Tagged.
-  return Bounds(Type::Number());
+  Bounds arg = Operand(node, 0);
+  // TODO(neis): CHECK(arg.upper->Is(Type::Number()));
+  return Bounds(
+      ChangeRepresentation(arg.lower, Type::Tagged(), zone()),
+      ChangeRepresentation(arg.upper, Type::Tagged(), zone()));
 }
 
 
 Bounds Typer::Visitor::TypeChangeBoolToBit(Node* node) {
-  // TODO(titzer): type is type of input, representation is Bit.
-  return Bounds(Type::Boolean());
+  Bounds arg = Operand(node, 0);
+  // TODO(neis): DCHECK(arg.upper->Is(Type::Boolean()));
+  return Bounds(
+      ChangeRepresentation(arg.lower, Type::UntaggedBit(), zone()),
+      ChangeRepresentation(arg.upper, Type::UntaggedBit(), zone()));
 }
 
 
 Bounds Typer::Visitor::TypeChangeBitToBool(Node* node) {
-  // TODO(titzer): type is type of input, representation is Tagged.
-  return Bounds(Type::Boolean());
+  Bounds arg = Operand(node, 0);
+  // TODO(neis): DCHECK(arg.upper->Is(Type::Boolean()));
+  return Bounds(
+      ChangeRepresentation(arg.lower, Type::TaggedPointer(), zone()),
+      ChangeRepresentation(arg.upper, Type::TaggedPointer(), zone()));
 }
 
 
@@ -790,6 +1619,21 @@
 }
 
 
+Bounds Typer::Visitor::TypeLoadBuffer(Node* node) {
+  // TODO(bmeurer): This typing is not yet correct. Since we can still access
+  // out of bounds, the type in the general case has to include Undefined.
+  switch (BufferAccessOf(node->op()).external_array_type()) {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+  case kExternal##Type##Array:                          \
+    return Bounds(typer_->cache_->Get(k##Type));
+    TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+  }
+  UNREACHABLE();
+  return Bounds();
+}
+
+
 Bounds Typer::Visitor::TypeLoadElement(Node* node) {
   return Bounds(ElementAccessOf(node->op()).type);
 }
@@ -801,104 +1645,465 @@
 }
 
 
+Bounds Typer::Visitor::TypeStoreBuffer(Node* node) {
+  UNREACHABLE();
+  return Bounds();
+}
+
+
 Bounds Typer::Visitor::TypeStoreElement(Node* node) {
   UNREACHABLE();
   return Bounds();
 }
 
 
+Bounds Typer::Visitor::TypeObjectIsSmi(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeObjectIsNonNegativeSmi(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
 // Machine operators.
 
-// TODO(rossberg): implement
-#define DEFINE_METHOD(x) \
-    Bounds Typer::Visitor::Type##x(Node* node) { return Bounds(Type::None()); }
-MACHINE_OP_LIST(DEFINE_METHOD)
-#undef DEFINE_METHOD
+Bounds Typer::Visitor::TypeLoad(Node* node) {
+  return Bounds::Unbounded(zone());
+}
+
+
+Bounds Typer::Visitor::TypeStore(Node* node) {
+  UNREACHABLE();
+  return Bounds();
+}
+
+
+Bounds Typer::Visitor::TypeWord32And(Node* node) {
+  return Bounds(Type::Integral32());
+}
+
+
+Bounds Typer::Visitor::TypeWord32Or(Node* node) {
+  return Bounds(Type::Integral32());
+}
+
+
+Bounds Typer::Visitor::TypeWord32Xor(Node* node) {
+  return Bounds(Type::Integral32());
+}
+
+
+Bounds Typer::Visitor::TypeWord32Shl(Node* node) {
+  return Bounds(Type::Integral32());
+}
+
+
+Bounds Typer::Visitor::TypeWord32Shr(Node* node) {
+  return Bounds(Type::Integral32());
+}
+
+
+Bounds Typer::Visitor::TypeWord32Sar(Node* node) {
+  return Bounds(Type::Integral32());
+}
+
+
+Bounds Typer::Visitor::TypeWord32Ror(Node* node) {
+  return Bounds(Type::Integral32());
+}
+
+
+Bounds Typer::Visitor::TypeWord32Equal(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeWord64And(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeWord64Or(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeWord64Xor(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeWord64Shl(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeWord64Shr(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeWord64Sar(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeWord64Ror(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeWord64Equal(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeInt32Add(Node* node) {
+  return Bounds(Type::Integral32());
+}
+
+
+Bounds Typer::Visitor::TypeInt32AddWithOverflow(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeInt32Sub(Node* node) {
+  return Bounds(Type::Integral32());
+}
+
+
+Bounds Typer::Visitor::TypeInt32SubWithOverflow(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeInt32Mul(Node* node) {
+  return Bounds(Type::Integral32());
+}
+
+
+Bounds Typer::Visitor::TypeInt32MulHigh(Node* node) {
+  return Bounds(Type::Signed32());
+}
+
+
+Bounds Typer::Visitor::TypeInt32Div(Node* node) {
+  return Bounds(Type::Integral32());
+}
+
+
+Bounds Typer::Visitor::TypeInt32Mod(Node* node) {
+  return Bounds(Type::Integral32());
+}
+
+
+Bounds Typer::Visitor::TypeInt32LessThan(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeInt32LessThanOrEqual(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeUint32Div(Node* node) {
+  return Bounds(Type::Unsigned32());
+}
+
+
+Bounds Typer::Visitor::TypeUint32LessThan(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeUint32LessThanOrEqual(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeUint32Mod(Node* node) {
+  return Bounds(Type::Unsigned32());
+}
+
+
+Bounds Typer::Visitor::TypeUint32MulHigh(Node* node) {
+  return Bounds(Type::Unsigned32());
+}
+
+
+Bounds Typer::Visitor::TypeInt64Add(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeInt64Sub(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeInt64Mul(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeInt64Div(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeInt64Mod(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeInt64LessThan(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeInt64LessThanOrEqual(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeUint64Div(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeUint64LessThan(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeUint64Mod(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeChangeFloat32ToFloat64(Node* node) {
+  return Bounds(Type::Intersect(
+      Type::Number(), Type::UntaggedFloat64(), zone()));
+}
+
+
+Bounds Typer::Visitor::TypeChangeFloat64ToInt32(Node* node) {
+  return Bounds(Type::Intersect(
+      Type::Signed32(), Type::UntaggedSigned32(), zone()));
+}
+
+
+Bounds Typer::Visitor::TypeChangeFloat64ToUint32(Node* node) {
+  return Bounds(Type::Intersect(
+      Type::Unsigned32(), Type::UntaggedUnsigned32(), zone()));
+}
+
+
+Bounds Typer::Visitor::TypeChangeInt32ToFloat64(Node* node) {
+  return Bounds(Type::Intersect(
+      Type::Signed32(), Type::UntaggedFloat64(), zone()));
+}
+
+
+Bounds Typer::Visitor::TypeChangeInt32ToInt64(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeChangeUint32ToFloat64(Node* node) {
+  return Bounds(Type::Intersect(
+      Type::Unsigned32(), Type::UntaggedFloat64(), zone()));
+}
+
+
+Bounds Typer::Visitor::TypeChangeUint32ToUint64(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeTruncateFloat64ToFloat32(Node* node) {
+  return Bounds(Type::Intersect(
+      Type::Number(), Type::UntaggedFloat32(), zone()));
+}
+
+
+Bounds Typer::Visitor::TypeTruncateFloat64ToInt32(Node* node) {
+  return Bounds(Type::Intersect(
+      Type::Signed32(), Type::UntaggedSigned32(), zone()));
+}
+
+
+Bounds Typer::Visitor::TypeTruncateInt64ToInt32(Node* node) {
+  return Bounds(Type::Intersect(
+      Type::Signed32(), Type::UntaggedSigned32(), zone()));
+}
+
+
+Bounds Typer::Visitor::TypeFloat64Add(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64Sub(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64Mul(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64Div(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64Mod(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64Sqrt(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64Equal(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64LessThan(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64LessThanOrEqual(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64Floor(Node* node) {
+  // TODO(sigurds): We could have a tighter bound here.
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64Ceil(Node* node) {
+  // TODO(sigurds): We could have a tighter bound here.
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64RoundTruncate(Node* node) {
+  // TODO(sigurds): We could have a tighter bound here.
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64RoundTiesAway(Node* node) {
+  // TODO(sigurds): We could have a tighter bound here.
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeLoadStackPointer(Node* node) {
+  return Bounds(Type::Internal());
+}
+
+
+Bounds Typer::Visitor::TypeCheckedLoad(Node* node) {
+  return Bounds::Unbounded(zone());
+}
+
+
+Bounds Typer::Visitor::TypeCheckedStore(Node* node) {
+  UNREACHABLE();
+  return Bounds();
+}
 
 
 // Heap constants.
 
+
 Type* Typer::Visitor::TypeConstant(Handle<Object> value) {
-  if (value->IsJSFunction() && JSFunction::cast(*value)->IsBuiltin() &&
-      !context().is_null()) {
-    Handle<Context> native =
-        handle(context().ToHandleChecked()->native_context(), isolate());
-    if (*value == native->math_abs_fun()) {
-      return typer_->number_fun1_;  // TODO(rossberg): can't express overloading
-    } else if (*value == native->math_acos_fun()) {
-      return typer_->number_fun1_;
-    } else if (*value == native->math_asin_fun()) {
-      return typer_->number_fun1_;
-    } else if (*value == native->math_atan_fun()) {
-      return typer_->number_fun1_;
-    } else if (*value == native->math_atan2_fun()) {
-      return typer_->number_fun2_;
-    } else if (*value == native->math_ceil_fun()) {
-      return typer_->number_fun1_;
-    } else if (*value == native->math_cos_fun()) {
-      return typer_->number_fun1_;
-    } else if (*value == native->math_exp_fun()) {
-      return typer_->number_fun1_;
-    } else if (*value == native->math_floor_fun()) {
-      return typer_->number_fun1_;
-    } else if (*value == native->math_imul_fun()) {
-      return typer_->imul_fun_;
-    } else if (*value == native->math_log_fun()) {
-      return typer_->number_fun1_;
-    } else if (*value == native->math_pow_fun()) {
-      return typer_->number_fun2_;
-    } else if (*value == native->math_random_fun()) {
-      return typer_->number_fun0_;
-    } else if (*value == native->math_round_fun()) {
-      return typer_->number_fun1_;
-    } else if (*value == native->math_sin_fun()) {
-      return typer_->number_fun1_;
-    } else if (*value == native->math_sqrt_fun()) {
-      return typer_->number_fun1_;
-    } else if (*value == native->math_tan_fun()) {
-      return typer_->number_fun1_;
-    } else if (*value == native->array_buffer_fun()) {
-      return typer_->array_buffer_fun_;
-    } else if (*value == native->int8_array_fun()) {
-      return typer_->int8_array_fun_;
-    } else if (*value == native->int16_array_fun()) {
-      return typer_->int16_array_fun_;
-    } else if (*value == native->int32_array_fun()) {
-      return typer_->int32_array_fun_;
-    } else if (*value == native->uint8_array_fun()) {
-      return typer_->uint8_array_fun_;
-    } else if (*value == native->uint16_array_fun()) {
-      return typer_->uint16_array_fun_;
-    } else if (*value == native->uint32_array_fun()) {
-      return typer_->uint32_array_fun_;
-    } else if (*value == native->float32_array_fun()) {
-      return typer_->float32_array_fun_;
-    } else if (*value == native->float64_array_fun()) {
-      return typer_->float64_array_fun_;
+  if (value->IsJSFunction()) {
+    if (JSFunction::cast(*value)->shared()->HasBuiltinFunctionId()) {
+      switch (JSFunction::cast(*value)->shared()->builtin_function_id()) {
+        case kMathRandom:
+          return typer_->random_fun_;
+        case kMathFloor:
+          return typer_->weakint_fun1_;
+        case kMathRound:
+          return typer_->weakint_fun1_;
+        case kMathCeil:
+          return typer_->weakint_fun1_;
+        // Unary math functions.
+        case kMathAbs:  // TODO(rossberg): can't express overloading
+        case kMathLog:
+        case kMathExp:
+        case kMathSqrt:
+        case kMathCos:
+        case kMathSin:
+        case kMathTan:
+        case kMathAcos:
+        case kMathAsin:
+        case kMathAtan:
+        case kMathFround:
+          return typer_->cache_->Get(kNumberFunc1);
+        // Binary math functions.
+        case kMathAtan2:
+        case kMathPow:
+        case kMathMax:
+        case kMathMin:
+          return typer_->cache_->Get(kNumberFunc2);
+        case kMathImul:
+          return typer_->cache_->Get(kImulFunc);
+        case kMathClz32:
+          return typer_->cache_->Get(kClz32Func);
+        default:
+          break;
+      }
+    } else if (JSFunction::cast(*value)->IsBuiltin() && !context().is_null()) {
+      Handle<Context> native =
+          handle(context().ToHandleChecked()->native_context(), isolate());
+      if (*value == native->array_buffer_fun()) {
+        return typer_->cache_->Get(kArrayBufferFunc);
+      } else if (*value == native->int8_array_fun()) {
+        return typer_->cache_->Get(kInt8ArrayFunc);
+      } else if (*value == native->int16_array_fun()) {
+        return typer_->cache_->Get(kInt16ArrayFunc);
+      } else if (*value == native->int32_array_fun()) {
+        return typer_->cache_->Get(kInt32ArrayFunc);
+      } else if (*value == native->uint8_array_fun()) {
+        return typer_->cache_->Get(kUint8ArrayFunc);
+      } else if (*value == native->uint16_array_fun()) {
+        return typer_->cache_->Get(kUint16ArrayFunc);
+      } else if (*value == native->uint32_array_fun()) {
+        return typer_->cache_->Get(kUint32ArrayFunc);
+      } else if (*value == native->float32_array_fun()) {
+        return typer_->cache_->Get(kFloat32ArrayFunc);
+      } else if (*value == native->float64_array_fun()) {
+        return typer_->cache_->Get(kFloat64ArrayFunc);
+      }
+    }
+  } else if (value->IsJSTypedArray()) {
+    switch (JSTypedArray::cast(*value)->type()) {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+  case kExternal##Type##Array:                          \
+    return typer_->cache_->Get(k##Type##Array);
+      TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
     }
   }
   return Type::Constant(value, zone());
 }
 
-
-namespace {
-
-class TyperDecorator : public GraphDecorator {
- public:
-  explicit TyperDecorator(Typer* typer) : typer_(typer) {}
-  virtual void Decorate(Node* node) { typer_->Init(node); }
-
- private:
-  Typer* typer_;
-};
-
-}
-
-
-void Typer::DecorateGraph(Graph* graph) {
-  graph->AddDecorator(new (zone()) TyperDecorator(this));
-}
-
-}
-}
-}  // namespace v8::internal::compiler
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/typer.h b/src/compiler/typer.h
index 2957e4b..b65a9a5 100644
--- a/src/compiler/typer.h
+++ b/src/compiler/typer.h
@@ -15,43 +15,62 @@
 namespace internal {
 namespace compiler {
 
+// Forward declarations.
+class LazyTypeCache;
+
+
 class Typer {
  public:
-  explicit Typer(Zone* zone);
+  explicit Typer(Graph* graph, MaybeHandle<Context> context);
+  ~Typer();
 
-  void Init(Node* node);
-  void Run(Graph* graph, MaybeHandle<Context> context);
-  void Narrow(Graph* graph, Node* node, MaybeHandle<Context> context);
-  void Widen(Graph* graph, Node* node, MaybeHandle<Context> context);
+  void Run();
 
-  void DecorateGraph(Graph* graph);
-
-  Zone* zone() { return zone_; }
-  Isolate* isolate() { return zone_->isolate(); }
+  Graph* graph() { return graph_; }
+  MaybeHandle<Context> context() { return context_; }
+  Zone* zone() { return graph_->zone(); }
+  Isolate* isolate() { return zone()->isolate(); }
 
  private:
   class Visitor;
-  class RunVisitor;
-  class NarrowVisitor;
-  class WidenVisitor;
+  class Decorator;
+
+  Graph* graph_;
+  MaybeHandle<Context> context_;
+  Decorator* decorator_;
 
   Zone* zone_;
+  Type* boolean_or_number;
+  Type* undefined_or_null;
+  Type* undefined_or_number;
+  Type* negative_signed32;
+  Type* non_negative_signed32;
+  Type* singleton_false;
+  Type* singleton_true;
+  Type* singleton_zero;
+  Type* singleton_one;
+  Type* zero_or_one;
+  Type* zeroish;
+  Type* signed32ish;
+  Type* unsigned32ish;
+  Type* falsish;
+  Type* truish;
+  Type* integer;
+  Type* weakint;
   Type* number_fun0_;
   Type* number_fun1_;
   Type* number_fun2_;
-  Type* imul_fun_;
-  Type* array_buffer_fun_;
-  Type* int8_array_fun_;
-  Type* int16_array_fun_;
-  Type* int32_array_fun_;
-  Type* uint8_array_fun_;
-  Type* uint16_array_fun_;
-  Type* uint32_array_fun_;
-  Type* float32_array_fun_;
-  Type* float64_array_fun_;
+  Type* weakint_fun1_;
+  Type* random_fun_;
+  LazyTypeCache* cache_;
+
+  ZoneVector<Handle<Object> > weaken_min_limits_;
+  ZoneVector<Handle<Object> > weaken_max_limits_;
+  DISALLOW_COPY_AND_ASSIGN(Typer);
 };
-}
-}
-}  // namespace v8::internal::compiler
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_COMPILER_TYPER_H_
diff --git a/src/compiler/value-numbering-reducer-unittest.cc b/src/compiler/value-numbering-reducer-unittest.cc
deleted file mode 100644
index 8db6458..0000000
--- a/src/compiler/value-numbering-reducer-unittest.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <limits>
-
-#include "src/compiler/graph.h"
-#include "src/compiler/value-numbering-reducer.h"
-#include "src/test/test-utils.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-namespace {
-
-const SimpleOperator kOp0(0, Operator::kNoProperties, 0, 1, "op0");
-const SimpleOperator kOp1(1, Operator::kNoProperties, 1, 1, "op1");
-
-}  // namespace
-
-
-class ValueNumberingReducerTest : public TestWithZone {
- public:
-  ValueNumberingReducerTest() : graph_(zone()), reducer_(zone()) {}
-
- protected:
-  Reduction Reduce(Node* node) { return reducer_.Reduce(node); }
-
-  Graph* graph() { return &graph_; }
-
- private:
-  Graph graph_;
-  ValueNumberingReducer reducer_;
-};
-
-
-TEST_F(ValueNumberingReducerTest, AllInputsAreChecked) {
-  Node* na = graph()->NewNode(&kOp0);
-  Node* nb = graph()->NewNode(&kOp0);
-  Node* n1 = graph()->NewNode(&kOp0, na);
-  Node* n2 = graph()->NewNode(&kOp0, nb);
-  EXPECT_FALSE(Reduce(n1).Changed());
-  EXPECT_FALSE(Reduce(n2).Changed());
-}
-
-
-TEST_F(ValueNumberingReducerTest, DeadNodesAreNeverReturned) {
-  Node* n0 = graph()->NewNode(&kOp0);
-  Node* n1 = graph()->NewNode(&kOp1, n0);
-  EXPECT_FALSE(Reduce(n1).Changed());
-  n1->Kill();
-  EXPECT_FALSE(Reduce(graph()->NewNode(&kOp1, n0)).Changed());
-}
-
-
-TEST_F(ValueNumberingReducerTest, OperatorEqualityNotIdentity) {
-  static const size_t kMaxInputCount = 16;
-  Node* inputs[kMaxInputCount];
-  for (size_t i = 0; i < arraysize(inputs); ++i) {
-    Operator::Opcode opcode = static_cast<Operator::Opcode>(
-        std::numeric_limits<Operator::Opcode>::max() - i);
-    inputs[i] = graph()->NewNode(new (zone()) SimpleOperator(
-        opcode, Operator::kNoProperties, 0, 1, "Operator"));
-  }
-  TRACED_FORRANGE(size_t, input_count, 0, arraysize(inputs)) {
-    const SimpleOperator op1(static_cast<Operator::Opcode>(input_count),
-                             Operator::kNoProperties,
-                             static_cast<int>(input_count), 1, "op");
-    Node* n1 = graph()->NewNode(&op1, static_cast<int>(input_count), inputs);
-    Reduction r1 = Reduce(n1);
-    EXPECT_FALSE(r1.Changed());
-
-    const SimpleOperator op2(static_cast<Operator::Opcode>(input_count),
-                             Operator::kNoProperties,
-                             static_cast<int>(input_count), 1, "op");
-    Node* n2 = graph()->NewNode(&op2, static_cast<int>(input_count), inputs);
-    Reduction r2 = Reduce(n2);
-    EXPECT_TRUE(r2.Changed());
-    EXPECT_EQ(n1, r2.replacement());
-  }
-}
-
-
-TEST_F(ValueNumberingReducerTest, SubsequentReductionsYieldTheSameNode) {
-  static const size_t kMaxInputCount = 16;
-  Node* inputs[kMaxInputCount];
-  for (size_t i = 0; i < arraysize(inputs); ++i) {
-    Operator::Opcode opcode = static_cast<Operator::Opcode>(
-        std::numeric_limits<Operator::Opcode>::max() - i);
-    inputs[i] = graph()->NewNode(new (zone()) SimpleOperator(
-        opcode, Operator::kNoProperties, 0, 1, "Operator"));
-  }
-  TRACED_FORRANGE(size_t, input_count, 0, arraysize(inputs)) {
-    const SimpleOperator op1(1, Operator::kNoProperties,
-                             static_cast<int>(input_count), 1, "op1");
-    Node* n = graph()->NewNode(&op1, static_cast<int>(input_count), inputs);
-    Reduction r = Reduce(n);
-    EXPECT_FALSE(r.Changed());
-
-    r = Reduce(graph()->NewNode(&op1, static_cast<int>(input_count), inputs));
-    ASSERT_TRUE(r.Changed());
-    EXPECT_EQ(n, r.replacement());
-
-    r = Reduce(graph()->NewNode(&op1, static_cast<int>(input_count), inputs));
-    ASSERT_TRUE(r.Changed());
-    EXPECT_EQ(n, r.replacement());
-  }
-}
-
-
-TEST_F(ValueNumberingReducerTest, WontReplaceNodeWithItself) {
-  Node* n = graph()->NewNode(&kOp0);
-  EXPECT_FALSE(Reduce(n).Changed());
-  EXPECT_FALSE(Reduce(n).Changed());
-}
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/value-numbering-reducer.cc b/src/compiler/value-numbering-reducer.cc
index 595a4f3..734b3e8 100644
--- a/src/compiler/value-numbering-reducer.cc
+++ b/src/compiler/value-numbering-reducer.cc
@@ -4,6 +4,9 @@
 
 #include "src/compiler/value-numbering-reducer.h"
 
+#include <cstring>
+
+#include "src/base/functional.h"
 #include "src/compiler/node.h"
 
 namespace v8 {
@@ -12,7 +15,13 @@
 
 namespace {
 
-size_t HashCode(Node* node) { return node->op()->HashCode(); }
+size_t HashCode(Node* node) {
+  size_t h = base::hash_combine(node->op()->HashCode(), node->InputCount());
+  for (int j = 0; j < node->InputCount(); ++j) {
+    h = base::hash_combine(h, node->InputAt(j)->id());
+  }
+  return h;
+}
 
 
 bool Equals(Node* a, Node* b) {
@@ -33,40 +42,121 @@
 }  // namespace
 
 
-class ValueNumberingReducer::Entry FINAL : public ZoneObject {
- public:
-  Entry(Node* node, Entry* next) : node_(node), next_(next) {}
-
-  Node* node() const { return node_; }
-  Entry* next() const { return next_; }
-
- private:
-  Node* node_;
-  Entry* next_;
-};
-
-
-ValueNumberingReducer::ValueNumberingReducer(Zone* zone) : zone_(zone) {
-  for (size_t i = 0; i < arraysize(buckets_); ++i) {
-    buckets_[i] = NULL;
-  }
-}
+ValueNumberingReducer::ValueNumberingReducer(Zone* zone)
+    : entries_(nullptr), capacity_(0), size_(0), zone_(zone) {}
 
 
 ValueNumberingReducer::~ValueNumberingReducer() {}
 
 
 Reduction ValueNumberingReducer::Reduce(Node* node) {
-  Entry** head = &buckets_[HashCode(node) % arraysize(buckets_)];
-  for (Entry* entry = *head; entry; entry = entry->next()) {
-    if (entry->node()->IsDead()) continue;
-    if (entry->node() == node) return NoChange();
-    if (Equals(node, entry->node())) {
-      return Replace(entry->node());
+  if (!node->op()->HasProperty(Operator::kEliminatable)) return NoChange();
+
+  const size_t hash = HashCode(node);
+  if (!entries_) {
+    DCHECK(size_ == 0);
+    DCHECK(capacity_ == 0);
+    // Allocate the initial entries and insert the first entry.
+    capacity_ = kInitialCapacity;
+    entries_ = zone()->NewArray<Node*>(kInitialCapacity);
+    memset(entries_, 0, sizeof(*entries_) * kInitialCapacity);
+    entries_[hash & (kInitialCapacity - 1)] = node;
+    size_ = 1;
+    return NoChange();
+  }
+
+  DCHECK(size_ < capacity_);
+  DCHECK(size_ * kCapacityToSizeRatio < capacity_);
+
+  const size_t mask = capacity_ - 1;
+  size_t dead = capacity_;
+
+  for (size_t i = hash & mask;; i = (i + 1) & mask) {
+    Node* entry = entries_[i];
+    if (!entry) {
+      if (dead != capacity_) {
+        // Reuse dead entry that we discovered on the way.
+        entries_[dead] = node;
+      } else {
+        // Have to insert a new entry.
+        entries_[i] = node;
+        size_++;
+
+        // Resize to keep load factor below 1/kCapacityToSizeRatio.
+        if (size_ * kCapacityToSizeRatio >= capacity_) Grow();
+      }
+      DCHECK(size_ * kCapacityToSizeRatio < capacity_);
+      return NoChange();
+    }
+
+    if (entry == node) {
+      // We need to check for a certain class of collisions here. Imagine the
+      // following scenario:
+      //
+      //  1. We insert node1 with op1 and certain inputs at index i.
+      //  2. We insert node2 with op2 and certain inputs at index i+1.
+      //  3. Some other reducer changes node1 to op2 and the inputs from node2.
+      //
+      // Now we are called again to reduce node1, and we would return NoChange
+      // in this case because we find node1 first, but what we should actually
+      // do is return Replace(node2) instead.
+      for (size_t j = (i + 1) & mask;; j = (j + 1) & mask) {
+        Node* entry = entries_[j];
+        if (!entry) {
+          // No collision, {node} is fine.
+          return NoChange();
+        }
+        if (entry->IsDead()) {
+          continue;
+        }
+        if (Equals(entry, node)) {
+          // Overwrite the colliding entry with the actual entry.
+          entries_[i] = entry;
+          return Replace(entry);
+        }
+      }
+    }
+
+    // Skip dead entries, but remember their indices so we can reuse them.
+    if (entry->IsDead()) {
+      dead = i;
+      continue;
+    }
+    if (Equals(entry, node)) {
+      return Replace(entry);
     }
   }
-  *head = new (zone()) Entry(node, *head);
-  return NoChange();
+}
+
+
+void ValueNumberingReducer::Grow() {
+  // Allocate a new block of entries kCapacityToSizeRatio times the previous
+  // capacity.
+  Node** const old_entries = entries_;
+  size_t const old_capacity = capacity_;
+  capacity_ *= kCapacityToSizeRatio;
+  entries_ = zone()->NewArray<Node*>(static_cast<int>(capacity_));
+  memset(entries_, 0, sizeof(*entries_) * capacity_);
+  size_ = 0;
+  size_t const mask = capacity_ - 1;
+
+  // Insert the old entries into the new block (skipping dead nodes).
+  for (size_t i = 0; i < old_capacity; ++i) {
+    Node* const old_entry = old_entries[i];
+    if (!old_entry || old_entry->IsDead()) continue;
+    for (size_t j = HashCode(old_entry) & mask;; j = (j + 1) & mask) {
+      Node* const entry = entries_[j];
+      if (entry == old_entry) {
+        // Skip duplicate of the old entry.
+        break;
+      }
+      if (!entry) {
+        entries_[j] = old_entry;
+        size_++;
+        break;
+      }
+    }
+  }
 }
 
 }  // namespace compiler
diff --git a/src/compiler/value-numbering-reducer.h b/src/compiler/value-numbering-reducer.h
index 0d67e5d..546226c 100644
--- a/src/compiler/value-numbering-reducer.h
+++ b/src/compiler/value-numbering-reducer.h
@@ -16,16 +16,17 @@
   explicit ValueNumberingReducer(Zone* zone);
   ~ValueNumberingReducer();
 
-  virtual Reduction Reduce(Node* node) OVERRIDE;
+  Reduction Reduce(Node* node) OVERRIDE;
 
  private:
+  enum { kInitialCapacity = 256u, kCapacityToSizeRatio = 2u };
+
+  void Grow();
   Zone* zone() const { return zone_; }
 
-  // TODO(turbofan): We currently use separate chaining with linked lists here,
-  // we may want to replace that with a more sophisticated data structure at
-  // some point in the future.
-  class Entry;
-  Entry* buckets_[117u];
+  Node** entries_;
+  size_t capacity_;
+  size_t size_;
   Zone* zone_;
 };
 
diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc
index 23cec7a..693b414 100644
--- a/src/compiler/verifier.cc
+++ b/src/compiler/verifier.cc
@@ -6,10 +6,11 @@
 
 #include <deque>
 #include <queue>
+#include <sstream>
+#include <string>
 
+#include "src/bit-vector.h"
 #include "src/compiler/generic-algorithm.h"
-#include "src/compiler/generic-node-inl.h"
-#include "src/compiler/generic-node.h"
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/node.h"
@@ -18,7 +19,8 @@
 #include "src/compiler/opcodes.h"
 #include "src/compiler/operator.h"
 #include "src/compiler/schedule.h"
-#include "src/data-flow.h"
+#include "src/compiler/simplified-operator.h"
+#include "src/ostreams.h"
 
 namespace v8 {
 namespace internal {
@@ -45,28 +47,84 @@
 
 class Verifier::Visitor : public NullNodeVisitor {
  public:
-  explicit Visitor(Zone* zone)
-      : reached_from_start(NodeSet::key_compare(),
-                           NodeSet::allocator_type(zone)),
-        reached_from_end(NodeSet::key_compare(),
-                         NodeSet::allocator_type(zone)) {}
+  Visitor(Zone* z, Typing typed) : zone(z), typing(typed) {}
 
   // Fulfills the PreNodeCallback interface.
-  GenericGraphVisit::Control Pre(Node* node);
+  void Pre(Node* node);
 
-  bool from_start;
-  NodeSet reached_from_start;
-  NodeSet reached_from_end;
+  Zone* zone;
+  Typing typing;
+
+ private:
+  // TODO(rossberg): Get rid of these once we got rid of NodeProperties.
+  Bounds bounds(Node* node) { return NodeProperties::GetBounds(node); }
+  Node* ValueInput(Node* node, int i = 0) {
+    return NodeProperties::GetValueInput(node, i);
+  }
+  FieldAccess Field(Node* node) {
+    DCHECK(node->opcode() == IrOpcode::kLoadField ||
+           node->opcode() == IrOpcode::kStoreField);
+    return OpParameter<FieldAccess>(node);
+  }
+  ElementAccess Element(Node* node) {
+    DCHECK(node->opcode() == IrOpcode::kLoadElement ||
+           node->opcode() == IrOpcode::kStoreElement);
+    return OpParameter<ElementAccess>(node);
+  }
+  void CheckNotTyped(Node* node) {
+    if (NodeProperties::IsTyped(node)) {
+      std::ostringstream str;
+      str << "TypeError: node #" << node->opcode() << ":"
+          << node->op()->mnemonic() << " should never have a type";
+      V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+    }
+  }
+  void CheckUpperIs(Node* node, Type* type) {
+    if (typing == TYPED && !bounds(node).upper->Is(type)) {
+      std::ostringstream str;
+      str << "TypeError: node #" << node->opcode() << ":"
+          << node->op()->mnemonic() << " upper bound ";
+      bounds(node).upper->PrintTo(str);
+      str << " is not ";
+      type->PrintTo(str);
+      V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+    }
+  }
+  void CheckUpperMaybe(Node* node, Type* type) {
+    if (typing == TYPED && !bounds(node).upper->Maybe(type)) {
+      std::ostringstream str;
+      str << "TypeError: node #" << node->opcode() << ":"
+          << node->op()->mnemonic() << " upper bound ";
+      bounds(node).upper->PrintTo(str);
+      str << " must intersect ";
+      type->PrintTo(str);
+      V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+    }
+  }
+  void CheckValueInputIs(Node* node, int i, Type* type) {
+    Node* input = ValueInput(node, i);
+    if (typing == TYPED && !bounds(input).upper->Is(type)) {
+      std::ostringstream str;
+      str << "TypeError: node #" << node->opcode() << ":"
+          << node->op()->mnemonic() << "(input @" << i << " = "
+          << input->opcode() << ":" << input->op()->mnemonic()
+          << ") upper bound ";
+      bounds(input).upper->PrintTo(str);
+      str << " is not ";
+      type->PrintTo(str);
+      V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+    }
+  }
 };
 
 
-GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
-  int value_count = OperatorProperties::GetValueInputCount(node->op());
+void Verifier::Visitor::Pre(Node* node) {
+  int value_count = node->op()->ValueInputCount();
   int context_count = OperatorProperties::GetContextInputCount(node->op());
   int frame_state_count =
       OperatorProperties::GetFrameStateInputCount(node->op());
-  int effect_count = OperatorProperties::GetEffectInputCount(node->op());
-  int control_count = OperatorProperties::GetControlInputCount(node->op());
+  int effect_count = node->op()->EffectInputCount();
+  int control_count = node->op()->ControlInputCount();
 
   // Verify number of inputs matches up.
   int input_count = value_count + context_count + frame_state_count +
@@ -87,7 +145,7 @@
   // Verify all value inputs actually produce a value.
   for (int i = 0; i < value_count; ++i) {
     Node* value = NodeProperties::GetValueInput(node, i);
-    CHECK(OperatorProperties::HasValueOutput(value->op()));
+    CHECK(value->op()->ValueOutputCount() > 0);
     CHECK(IsDefUseChainLinkPresent(value, node));
     CHECK(IsUseDefChainLinkPresent(value, node));
   }
@@ -95,7 +153,7 @@
   // Verify all context inputs are value nodes.
   for (int i = 0; i < context_count; ++i) {
     Node* context = NodeProperties::GetContextInput(node);
-    CHECK(OperatorProperties::HasValueOutput(context->op()));
+    CHECK(context->op()->ValueOutputCount() > 0);
     CHECK(IsDefUseChainLinkPresent(context, node));
     CHECK(IsUseDefChainLinkPresent(context, node));
   }
@@ -103,7 +161,7 @@
   // Verify all effect inputs actually have an effect.
   for (int i = 0; i < effect_count; ++i) {
     Node* effect = NodeProperties::GetEffectInput(node);
-    CHECK(OperatorProperties::HasEffectOutput(effect->op()));
+    CHECK(effect->op()->EffectOutputCount() > 0);
     CHECK(IsDefUseChainLinkPresent(effect, node));
     CHECK(IsUseDefChainLinkPresent(effect, node));
   }
@@ -111,18 +169,18 @@
   // Verify all control inputs are control nodes.
   for (int i = 0; i < control_count; ++i) {
     Node* control = NodeProperties::GetControlInput(node, i);
-    CHECK(OperatorProperties::HasControlOutput(control->op()));
+    CHECK(control->op()->ControlOutputCount() > 0);
     CHECK(IsDefUseChainLinkPresent(control, node));
     CHECK(IsUseDefChainLinkPresent(control, node));
   }
 
   // Verify all successors are projections if multiple value outputs exist.
-  if (OperatorProperties::GetValueOutputCount(node->op()) > 1) {
-    Node::Uses uses = node->uses();
-    for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
-      CHECK(!NodeProperties::IsValueEdge(it.edge()) ||
-            (*it)->opcode() == IrOpcode::kProjection ||
-            (*it)->opcode() == IrOpcode::kParameter);
+  if (node->op()->ValueOutputCount() > 1) {
+    for (Edge edge : node->use_edges()) {
+      Node* use = edge.from();
+      CHECK(!NodeProperties::IsValueEdge(edge) ||
+            use->opcode() == IrOpcode::kProjection ||
+            use->opcode() == IrOpcode::kParameter);
     }
   }
 
@@ -130,12 +188,17 @@
     case IrOpcode::kStart:
       // Start has no inputs.
       CHECK_EQ(0, input_count);
+      // Type is a tuple.
+      // TODO(rossberg): Multiple outputs are currently typed as Internal.
+      CheckUpperIs(node, Type::Internal());
       break;
     case IrOpcode::kEnd:
       // End has no outputs.
-      CHECK(!OperatorProperties::HasValueOutput(node->op()));
-      CHECK(!OperatorProperties::HasEffectOutput(node->op()));
-      CHECK(!OperatorProperties::HasControlOutput(node->op()));
+      CHECK(node->op()->ValueOutputCount() == 0);
+      CHECK(node->op()->EffectOutputCount() == 0);
+      CHECK(node->op()->ControlOutputCount() == 0);
+      // Type is empty.
+      CheckNotTyped(node);
       break;
     case IrOpcode::kDead:
       // Dead is never connected to the graph.
@@ -143,31 +206,50 @@
     case IrOpcode::kBranch: {
       // Branch uses are IfTrue and IfFalse.
       Node::Uses uses = node->uses();
-      bool got_true = false, got_false = false;
+      int count_true = 0, count_false = 0;
       for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
-        CHECK(((*it)->opcode() == IrOpcode::kIfTrue && !got_true) ||
-              ((*it)->opcode() == IrOpcode::kIfFalse && !got_false));
-        if ((*it)->opcode() == IrOpcode::kIfTrue) got_true = true;
-        if ((*it)->opcode() == IrOpcode::kIfFalse) got_false = true;
+        CHECK((*it)->opcode() == IrOpcode::kIfTrue ||
+              (*it)->opcode() == IrOpcode::kIfFalse);
+        if ((*it)->opcode() == IrOpcode::kIfTrue) ++count_true;
+        if ((*it)->opcode() == IrOpcode::kIfFalse) ++count_false;
       }
-      // TODO(rossberg): Currently fails for various tests.
-      // CHECK(got_true && got_false);
+      CHECK(count_true == 1 && count_false == 1);
+      // Type is empty.
+      CheckNotTyped(node);
       break;
     }
     case IrOpcode::kIfTrue:
     case IrOpcode::kIfFalse:
       CHECK_EQ(IrOpcode::kBranch,
                NodeProperties::GetControlInput(node, 0)->opcode());
+      // Type is empty.
+      CheckNotTyped(node);
       break;
     case IrOpcode::kLoop:
     case IrOpcode::kMerge:
+      CHECK_EQ(control_count, input_count);
+      // Type is empty.
+      CheckNotTyped(node);
       break;
     case IrOpcode::kReturn:
       // TODO(rossberg): check successor is End
+      // Type is empty.
+      CheckNotTyped(node);
       break;
     case IrOpcode::kThrow:
       // TODO(rossberg): what are the constraints on these?
+      // Type is empty.
+      CheckNotTyped(node);
       break;
+    case IrOpcode::kTerminate:
+      // Type is empty.
+      CheckNotTyped(node);
+      CHECK_EQ(1, control_count);
+      CHECK_EQ(input_count, 1 + effect_count);
+      break;
+
+    // Common operators
+    // ----------------
     case IrOpcode::kParameter: {
       // Parameters have the start node as inputs.
       CHECK_EQ(1, input_count);
@@ -177,95 +259,522 @@
       int index = OpParameter<int>(node);
       Node* input = NodeProperties::GetValueInput(node, 0);
       // Currently, parameter indices start at -1 instead of 0.
-      CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index + 1);
+      CHECK_GT(input->op()->ValueOutputCount(), index + 1);
+      // Type can be anything.
+      CheckUpperIs(node, Type::Any());
       break;
     }
-    case IrOpcode::kInt32Constant:
+    case IrOpcode::kInt32Constant:  // TODO(rossberg): rename Word32Constant?
+      // Constants have no inputs.
+      CHECK_EQ(0, input_count);
+      // Type is a 32 bit integer, signed or unsigned.
+      CheckUpperIs(node, Type::Integral32());
+      break;
     case IrOpcode::kInt64Constant:
+      // Constants have no inputs.
+      CHECK_EQ(0, input_count);
+      // Type is internal.
+      // TODO(rossberg): Introduce proper Int64 type.
+      CheckUpperIs(node, Type::Internal());
+      break;
+    case IrOpcode::kFloat32Constant:
     case IrOpcode::kFloat64Constant:
-    case IrOpcode::kExternalConstant:
     case IrOpcode::kNumberConstant:
+      // Constants have no inputs.
+      CHECK_EQ(0, input_count);
+      // Type is a number.
+      CheckUpperIs(node, Type::Number());
+      break;
     case IrOpcode::kHeapConstant:
       // Constants have no inputs.
       CHECK_EQ(0, input_count);
+      // Type can be anything represented as a heap pointer.
+      CheckUpperIs(node, Type::TaggedPointer());
       break;
+    case IrOpcode::kExternalConstant:
+      // Constants have no inputs.
+      CHECK_EQ(0, input_count);
+      // Type is considered internal.
+      CheckUpperIs(node, Type::Internal());
+      break;
+    case IrOpcode::kProjection: {
+      // Projection has an input that produces enough values.
+      int index = static_cast<int>(OpParameter<size_t>(node->op()));
+      Node* input = NodeProperties::GetValueInput(node, 0);
+      CHECK_GT(input->op()->ValueOutputCount(), index);
+      // Type can be anything.
+      // TODO(rossberg): Introduce tuple types for this.
+      // TODO(titzer): Convince rossberg not to.
+      CheckUpperIs(node, Type::Any());
+      break;
+    }
+    case IrOpcode::kSelect: {
+      CHECK_EQ(0, effect_count);
+      CHECK_EQ(0, control_count);
+      CHECK_EQ(3, value_count);
+      break;
+    }
     case IrOpcode::kPhi: {
       // Phi input count matches parent control node.
+      CHECK_EQ(0, effect_count);
       CHECK_EQ(1, control_count);
       Node* control = NodeProperties::GetControlInput(node, 0);
-      CHECK_EQ(value_count,
-               OperatorProperties::GetControlInputCount(control->op()));
+      CHECK_EQ(value_count, control->op()->ControlInputCount());
+      CHECK_EQ(input_count, 1 + value_count);
+      // Type must be subsumed by all input types.
+      // TODO(rossberg): for now at least, narrowing does not really hold.
+      /*
+      for (int i = 0; i < value_count; ++i) {
+        // TODO(rossberg, jarin): Figure out what to do about lower bounds.
+        // CHECK(bounds(node).lower->Is(bounds(ValueInput(node, i)).lower));
+        CHECK(bounds(ValueInput(node, i)).upper->Is(bounds(node).upper));
+      }
+      */
       break;
     }
     case IrOpcode::kEffectPhi: {
       // EffectPhi input count matches parent control node.
+      CHECK_EQ(0, value_count);
       CHECK_EQ(1, control_count);
       Node* control = NodeProperties::GetControlInput(node, 0);
-      CHECK_EQ(effect_count,
-               OperatorProperties::GetControlInputCount(control->op()));
+      CHECK_EQ(effect_count, control->op()->ControlInputCount());
+      CHECK_EQ(input_count, 1 + effect_count);
+      break;
+    }
+    case IrOpcode::kValueEffect:
+      // TODO(rossberg): what are the constraints on these?
+      break;
+    case IrOpcode::kFinish: {
+      // TODO(rossberg): what are the constraints on these?
+      // Type must be subsumed by input type.
+      if (typing == TYPED) {
+        CHECK(bounds(ValueInput(node)).lower->Is(bounds(node).lower));
+        CHECK(bounds(ValueInput(node)).upper->Is(bounds(node).upper));
+      }
       break;
     }
     case IrOpcode::kFrameState:
       // TODO(jarin): what are the constraints on these?
       break;
+    case IrOpcode::kStateValues:
+      // TODO(jarin): what are the constraints on these?
+      break;
     case IrOpcode::kCall:
       // TODO(rossberg): what are the constraints on these?
       break;
-    case IrOpcode::kProjection: {
-      // Projection has an input that produces enough values.
-      size_t index = OpParameter<size_t>(node);
-      Node* input = NodeProperties::GetValueInput(node, 0);
-      CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()),
-               static_cast<int>(index));
+
+    // JavaScript operators
+    // --------------------
+    case IrOpcode::kJSEqual:
+    case IrOpcode::kJSNotEqual:
+    case IrOpcode::kJSStrictEqual:
+    case IrOpcode::kJSStrictNotEqual:
+    case IrOpcode::kJSLessThan:
+    case IrOpcode::kJSGreaterThan:
+    case IrOpcode::kJSLessThanOrEqual:
+    case IrOpcode::kJSGreaterThanOrEqual:
+    case IrOpcode::kJSUnaryNot:
+      // Type is Boolean.
+      CheckUpperIs(node, Type::Boolean());
+      break;
+
+    case IrOpcode::kJSBitwiseOr:
+    case IrOpcode::kJSBitwiseXor:
+    case IrOpcode::kJSBitwiseAnd:
+    case IrOpcode::kJSShiftLeft:
+    case IrOpcode::kJSShiftRight:
+    case IrOpcode::kJSShiftRightLogical:
+      // Type is 32 bit integral.
+      CheckUpperIs(node, Type::Integral32());
+      break;
+    case IrOpcode::kJSAdd:
+      // Type is Number or String.
+      CheckUpperIs(node, Type::NumberOrString());
+      break;
+    case IrOpcode::kJSSubtract:
+    case IrOpcode::kJSMultiply:
+    case IrOpcode::kJSDivide:
+    case IrOpcode::kJSModulus:
+      // Type is Number.
+      CheckUpperIs(node, Type::Number());
+      break;
+
+    case IrOpcode::kJSToBoolean:
+      // Type is Boolean.
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kJSToNumber:
+      // Type is Number.
+      CheckUpperIs(node, Type::Number());
+      break;
+    case IrOpcode::kJSToString:
+      // Type is String.
+      CheckUpperIs(node, Type::String());
+      break;
+    case IrOpcode::kJSToName:
+      // Type is Name.
+      CheckUpperIs(node, Type::Name());
+      break;
+    case IrOpcode::kJSToObject:
+      // Type is Receiver.
+      CheckUpperIs(node, Type::Receiver());
+      break;
+
+    case IrOpcode::kJSCreate:
+      // Type is Object.
+      CheckUpperIs(node, Type::Object());
+      break;
+    case IrOpcode::kJSLoadProperty:
+    case IrOpcode::kJSLoadNamed:
+      // Type can be anything.
+      CheckUpperIs(node, Type::Any());
+      break;
+    case IrOpcode::kJSStoreProperty:
+    case IrOpcode::kJSStoreNamed:
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kJSDeleteProperty:
+    case IrOpcode::kJSHasProperty:
+    case IrOpcode::kJSInstanceOf:
+      // Type is Boolean.
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kJSTypeOf:
+      // Type is String.
+      CheckUpperIs(node, Type::String());
+      break;
+
+    case IrOpcode::kJSLoadContext:
+      // Type can be anything.
+      CheckUpperIs(node, Type::Any());
+      break;
+    case IrOpcode::kJSStoreContext:
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kJSCreateFunctionContext:
+    case IrOpcode::kJSCreateCatchContext:
+    case IrOpcode::kJSCreateWithContext:
+    case IrOpcode::kJSCreateBlockContext:
+    case IrOpcode::kJSCreateModuleContext:
+    case IrOpcode::kJSCreateScriptContext: {
+      // Type is Context, and operand is Internal.
+      Node* context = NodeProperties::GetContextInput(node);
+      // TODO(rossberg): This should really be Is(Internal), but the typer
+      // currently can't do backwards propagation.
+      CheckUpperMaybe(context, Type::Internal());
+      if (typing == TYPED) CHECK(bounds(node).upper->IsContext());
       break;
     }
-    default:
-      // TODO(rossberg): Check other node kinds.
+
+    case IrOpcode::kJSCallConstruct:
+      // Type is Receiver.
+      CheckUpperIs(node, Type::Receiver());
+      break;
+    case IrOpcode::kJSCallFunction:
+    case IrOpcode::kJSCallRuntime:
+    case IrOpcode::kJSYield:
+    case IrOpcode::kJSDebugger:
+      // Type can be anything.
+      CheckUpperIs(node, Type::Any());
+      break;
+
+    // Simplified operators
+    // -------------------------------
+    case IrOpcode::kAnyToBoolean:
+      // Type is Boolean.
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kBooleanNot:
+      // Boolean -> Boolean
+      CheckValueInputIs(node, 0, Type::Boolean());
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kBooleanToNumber:
+      // Boolean -> Number
+      CheckValueInputIs(node, 0, Type::Boolean());
+      CheckUpperIs(node, Type::Number());
+      break;
+    case IrOpcode::kNumberEqual:
+    case IrOpcode::kNumberLessThan:
+    case IrOpcode::kNumberLessThanOrEqual:
+      // (Number, Number) -> Boolean
+      CheckValueInputIs(node, 0, Type::Number());
+      CheckValueInputIs(node, 1, Type::Number());
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kNumberAdd:
+    case IrOpcode::kNumberSubtract:
+    case IrOpcode::kNumberMultiply:
+    case IrOpcode::kNumberDivide:
+    case IrOpcode::kNumberModulus:
+      // (Number, Number) -> Number
+      CheckValueInputIs(node, 0, Type::Number());
+      CheckValueInputIs(node, 1, Type::Number());
+      // TODO(rossberg): activate once we retype after opcode changes.
+      // CheckUpperIs(node, Type::Number());
+      break;
+    case IrOpcode::kNumberToInt32:
+      // Number -> Signed32
+      CheckValueInputIs(node, 0, Type::Number());
+      CheckUpperIs(node, Type::Signed32());
+      break;
+    case IrOpcode::kNumberToUint32:
+      // Number -> Unsigned32
+      CheckValueInputIs(node, 0, Type::Number());
+      CheckUpperIs(node, Type::Unsigned32());
+      break;
+    case IrOpcode::kStringEqual:
+    case IrOpcode::kStringLessThan:
+    case IrOpcode::kStringLessThanOrEqual:
+      // (String, String) -> Boolean
+      CheckValueInputIs(node, 0, Type::String());
+      CheckValueInputIs(node, 1, Type::String());
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kStringAdd:
+      // (String, String) -> String
+      CheckValueInputIs(node, 0, Type::String());
+      CheckValueInputIs(node, 1, Type::String());
+      CheckUpperIs(node, Type::String());
+      break;
+    case IrOpcode::kReferenceEqual: {
+      // (Unique, Any) -> Boolean  and
+      // (Any, Unique) -> Boolean
+      if (typing == TYPED) {
+        CHECK(bounds(ValueInput(node, 0)).upper->Is(Type::Unique()) ||
+              bounds(ValueInput(node, 1)).upper->Is(Type::Unique()));
+      }
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    }
+    case IrOpcode::kObjectIsSmi:
+      CheckValueInputIs(node, 0, Type::Any());
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kObjectIsNonNegativeSmi:
+      CheckValueInputIs(node, 0, Type::Any());
+      CheckUpperIs(node, Type::Boolean());
+      break;
+
+    case IrOpcode::kChangeTaggedToInt32: {
+      // Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from = Type::Intersect(Type::Signed32(), Type::Tagged());
+      // Type* to = Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeTaggedToUint32: {
+      // Unsigned32 /\ Tagged -> Unsigned32 /\ UntaggedInt32
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from = Type::Intersect(Type::Unsigned32(), Type::Tagged());
+      // Type* to =Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeTaggedToFloat64: {
+      // Number /\ Tagged -> Number /\ UntaggedFloat64
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from = Type::Intersect(Type::Number(), Type::Tagged());
+      // Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeInt32ToTagged: {
+      // Signed32 /\ UntaggedInt32 -> Signed32 /\ Tagged
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from =Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
+      // Type* to = Type::Intersect(Type::Signed32(), Type::Tagged());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeUint32ToTagged: {
+      // Unsigned32 /\ UntaggedInt32 -> Unsigned32 /\ Tagged
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from=Type::Intersect(Type::Unsigned32(),Type::UntaggedInt32());
+      // Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeFloat64ToTagged: {
+      // Number /\ UntaggedFloat64 -> Number /\ Tagged
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from =Type::Intersect(Type::Number(), Type::UntaggedFloat64());
+      // Type* to = Type::Intersect(Type::Number(), Type::Tagged());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeBoolToBit: {
+      // Boolean /\ TaggedPtr -> Boolean /\ UntaggedInt1
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
+      // Type* to = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeBitToBool: {
+      // Boolean /\ UntaggedInt1 -> Boolean /\ TaggedPtr
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
+      // Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+
+    case IrOpcode::kLoadField:
+      // Object -> fieldtype
+      // TODO(rossberg): activate once machine ops are typed.
+      // CheckValueInputIs(node, 0, Type::Object());
+      // CheckUpperIs(node, Field(node).type));
+      break;
+    case IrOpcode::kLoadBuffer:
+      break;
+    case IrOpcode::kLoadElement:
+      // Object -> elementtype
+      // TODO(rossberg): activate once machine ops are typed.
+      // CheckValueInputIs(node, 0, Type::Object());
+      // CheckUpperIs(node, Element(node).type));
+      break;
+    case IrOpcode::kStoreField:
+      // (Object, fieldtype) -> _|_
+      // TODO(rossberg): activate once machine ops are typed.
+      // CheckValueInputIs(node, 0, Type::Object());
+      // CheckValueInputIs(node, 1, Field(node).type));
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kStoreBuffer:
+      break;
+    case IrOpcode::kStoreElement:
+      // (Object, elementtype) -> _|_
+      // TODO(rossberg): activate once machine ops are typed.
+      // CheckValueInputIs(node, 0, Type::Object());
+      // CheckValueInputIs(node, 1, Element(node).type));
+      CheckNotTyped(node);
+      break;
+
+    // Machine operators
+    // -----------------------
+    case IrOpcode::kLoad:
+    case IrOpcode::kStore:
+    case IrOpcode::kWord32And:
+    case IrOpcode::kWord32Or:
+    case IrOpcode::kWord32Xor:
+    case IrOpcode::kWord32Shl:
+    case IrOpcode::kWord32Shr:
+    case IrOpcode::kWord32Sar:
+    case IrOpcode::kWord32Ror:
+    case IrOpcode::kWord32Equal:
+    case IrOpcode::kWord64And:
+    case IrOpcode::kWord64Or:
+    case IrOpcode::kWord64Xor:
+    case IrOpcode::kWord64Shl:
+    case IrOpcode::kWord64Shr:
+    case IrOpcode::kWord64Sar:
+    case IrOpcode::kWord64Ror:
+    case IrOpcode::kWord64Equal:
+    case IrOpcode::kInt32Add:
+    case IrOpcode::kInt32AddWithOverflow:
+    case IrOpcode::kInt32Sub:
+    case IrOpcode::kInt32SubWithOverflow:
+    case IrOpcode::kInt32Mul:
+    case IrOpcode::kInt32MulHigh:
+    case IrOpcode::kInt32Div:
+    case IrOpcode::kInt32Mod:
+    case IrOpcode::kInt32LessThan:
+    case IrOpcode::kInt32LessThanOrEqual:
+    case IrOpcode::kUint32Div:
+    case IrOpcode::kUint32Mod:
+    case IrOpcode::kUint32MulHigh:
+    case IrOpcode::kUint32LessThan:
+    case IrOpcode::kUint32LessThanOrEqual:
+    case IrOpcode::kInt64Add:
+    case IrOpcode::kInt64Sub:
+    case IrOpcode::kInt64Mul:
+    case IrOpcode::kInt64Div:
+    case IrOpcode::kInt64Mod:
+    case IrOpcode::kInt64LessThan:
+    case IrOpcode::kInt64LessThanOrEqual:
+    case IrOpcode::kUint64Div:
+    case IrOpcode::kUint64Mod:
+    case IrOpcode::kUint64LessThan:
+    case IrOpcode::kFloat64Add:
+    case IrOpcode::kFloat64Sub:
+    case IrOpcode::kFloat64Mul:
+    case IrOpcode::kFloat64Div:
+    case IrOpcode::kFloat64Mod:
+    case IrOpcode::kFloat64Sqrt:
+    case IrOpcode::kFloat64Floor:
+    case IrOpcode::kFloat64Ceil:
+    case IrOpcode::kFloat64RoundTruncate:
+    case IrOpcode::kFloat64RoundTiesAway:
+    case IrOpcode::kFloat64Equal:
+    case IrOpcode::kFloat64LessThan:
+    case IrOpcode::kFloat64LessThanOrEqual:
+    case IrOpcode::kTruncateInt64ToInt32:
+    case IrOpcode::kTruncateFloat64ToFloat32:
+    case IrOpcode::kTruncateFloat64ToInt32:
+    case IrOpcode::kChangeInt32ToInt64:
+    case IrOpcode::kChangeUint32ToUint64:
+    case IrOpcode::kChangeInt32ToFloat64:
+    case IrOpcode::kChangeUint32ToFloat64:
+    case IrOpcode::kChangeFloat32ToFloat64:
+    case IrOpcode::kChangeFloat64ToInt32:
+    case IrOpcode::kChangeFloat64ToUint32:
+    case IrOpcode::kLoadStackPointer:
+    case IrOpcode::kCheckedLoad:
+    case IrOpcode::kCheckedStore:
+      // TODO(rossberg): Check.
       break;
   }
-
-  if (from_start) {
-    reached_from_start.insert(node);
-  } else {
-    reached_from_end.insert(node);
-  }
-
-  return GenericGraphVisit::CONTINUE;
 }
 
 
-void Verifier::Run(Graph* graph) {
-  Visitor visitor(graph->zone());
-
+void Verifier::Run(Graph* graph, Typing typing) {
+  Visitor visitor(graph->zone(), typing);
   CHECK_NE(NULL, graph->start());
-  visitor.from_start = true;
-  graph->VisitNodeUsesFromStart(&visitor);
   CHECK_NE(NULL, graph->end());
-  visitor.from_start = false;
   graph->VisitNodeInputsFromEnd(&visitor);
-
-  // All control nodes reachable from end are reachable from start.
-  for (NodeSet::iterator it = visitor.reached_from_end.begin();
-       it != visitor.reached_from_end.end(); ++it) {
-    CHECK(!NodeProperties::IsControl(*it) ||
-          visitor.reached_from_start.count(*it));
-  }
 }
 
 
+// -----------------------------------------------------------------------------
+
 static bool HasDominatingDef(Schedule* schedule, Node* node,
                              BasicBlock* container, BasicBlock* use_block,
                              int use_pos) {
   BasicBlock* block = use_block;
   while (true) {
     while (use_pos >= 0) {
-      if (block->nodes_[use_pos] == node) return true;
+      if (block->NodeAt(use_pos) == node) return true;
       use_pos--;
     }
-    block = block->dominator_;
+    block = block->dominator();
     if (block == NULL) break;
-    use_pos = static_cast<int>(block->nodes_.size()) - 1;
-    if (node == block->control_input_) return true;
+    use_pos = static_cast<int>(block->NodeCount()) - 1;
+    if (node == block->control_input()) return true;
+  }
+  return false;
+}
+
+
+static bool Dominates(Schedule* schedule, Node* dominator, Node* dominatee) {
+  BasicBlock* dom = schedule->block(dominator);
+  BasicBlock* sub = schedule->block(dominatee);
+  while (sub != NULL) {
+    if (sub == dom) {
+      return true;
+    }
+    sub = sub->dominator();
   }
   return false;
 }
@@ -273,123 +782,146 @@
 
 static void CheckInputsDominate(Schedule* schedule, BasicBlock* block,
                                 Node* node, int use_pos) {
-  for (int j = OperatorProperties::GetValueInputCount(node->op()) - 1; j >= 0;
-       j--) {
+  for (int j = node->op()->ValueInputCount() - 1; j >= 0; j--) {
     BasicBlock* use_block = block;
     if (node->opcode() == IrOpcode::kPhi) {
       use_block = use_block->PredecessorAt(j);
-      use_pos = static_cast<int>(use_block->nodes_.size()) - 1;
+      use_pos = static_cast<int>(use_block->NodeCount()) - 1;
     }
     Node* input = node->InputAt(j);
     if (!HasDominatingDef(schedule, node->InputAt(j), block, use_block,
                           use_pos)) {
       V8_Fatal(__FILE__, __LINE__,
                "Node #%d:%s in B%d is not dominated by input@%d #%d:%s",
-               node->id(), node->op()->mnemonic(), block->id(), j, input->id(),
-               input->op()->mnemonic());
+               node->id(), node->op()->mnemonic(), block->id().ToInt(), j,
+               input->id(), input->op()->mnemonic());
+    }
+  }
+  // Ensure that nodes are dominated by their control inputs;
+  // kEnd is an exception, as unreachable blocks resulting from kMerge
+  // are not in the RPO.
+  if (node->op()->ControlInputCount() == 1 &&
+      node->opcode() != IrOpcode::kEnd) {
+    Node* ctl = NodeProperties::GetControlInput(node);
+    if (!Dominates(schedule, ctl, node)) {
+      V8_Fatal(__FILE__, __LINE__,
+               "Node #%d:%s in B%d is not dominated by control input #%d:%s",
+               node->id(), node->op()->mnemonic(), block->id(), ctl->id(),
+               ctl->op()->mnemonic());
     }
   }
 }
 
 
 void ScheduleVerifier::Run(Schedule* schedule) {
-  const int count = schedule->BasicBlockCount();
+  const size_t count = schedule->BasicBlockCount();
   Zone tmp_zone(schedule->zone()->isolate());
   Zone* zone = &tmp_zone;
   BasicBlock* start = schedule->start();
   BasicBlockVector* rpo_order = schedule->rpo_order();
 
   // Verify the RPO order contains only blocks from this schedule.
-  CHECK_GE(count, static_cast<int>(rpo_order->size()));
+  CHECK_GE(count, rpo_order->size());
   for (BasicBlockVector::iterator b = rpo_order->begin(); b != rpo_order->end();
        ++b) {
     CHECK_EQ((*b), schedule->GetBlockById((*b)->id()));
+    // All predecessors and successors should be in rpo and in this schedule.
+    for (BasicBlock::Predecessors::iterator j = (*b)->predecessors_begin();
+         j != (*b)->predecessors_end(); ++j) {
+      CHECK_GE((*j)->rpo_number(), 0);
+      CHECK_EQ((*j), schedule->GetBlockById((*j)->id()));
+    }
+    for (BasicBlock::Successors::iterator j = (*b)->successors_begin();
+         j != (*b)->successors_end(); ++j) {
+      CHECK_GE((*j)->rpo_number(), 0);
+      CHECK_EQ((*j), schedule->GetBlockById((*j)->id()));
+    }
   }
 
   // Verify RPO numbers of blocks.
   CHECK_EQ(start, rpo_order->at(0));  // Start should be first.
   for (size_t b = 0; b < rpo_order->size(); b++) {
     BasicBlock* block = rpo_order->at(b);
-    CHECK_EQ(static_cast<int>(b), block->rpo_number_);
-    BasicBlock* dom = block->dominator_;
+    CHECK_EQ(static_cast<int>(b), block->rpo_number());
+    BasicBlock* dom = block->dominator();
     if (b == 0) {
       // All blocks except start should have a dominator.
       CHECK_EQ(NULL, dom);
     } else {
       // Check that the immediate dominator appears somewhere before the block.
       CHECK_NE(NULL, dom);
-      CHECK_LT(dom->rpo_number_, block->rpo_number_);
+      CHECK_LT(dom->rpo_number(), block->rpo_number());
     }
   }
 
   // Verify that all blocks reachable from start are in the RPO.
-  BoolVector marked(count, false, zone);
+  BoolVector marked(static_cast<int>(count), false, zone);
   {
     ZoneQueue<BasicBlock*> queue(zone);
     queue.push(start);
-    marked[start->id()] = true;
+    marked[start->id().ToSize()] = true;
     while (!queue.empty()) {
       BasicBlock* block = queue.front();
       queue.pop();
-      for (int s = 0; s < block->SuccessorCount(); s++) {
+      for (size_t s = 0; s < block->SuccessorCount(); s++) {
         BasicBlock* succ = block->SuccessorAt(s);
-        if (!marked[succ->id()]) {
-          marked[succ->id()] = true;
+        if (!marked[succ->id().ToSize()]) {
+          marked[succ->id().ToSize()] = true;
           queue.push(succ);
         }
       }
     }
   }
   // Verify marked blocks are in the RPO.
-  for (int i = 0; i < count; i++) {
-    BasicBlock* block = schedule->GetBlockById(i);
+  for (size_t i = 0; i < count; i++) {
+    BasicBlock* block = schedule->GetBlockById(BasicBlock::Id::FromSize(i));
     if (marked[i]) {
-      CHECK_GE(block->rpo_number_, 0);
-      CHECK_EQ(block, rpo_order->at(block->rpo_number_));
+      CHECK_GE(block->rpo_number(), 0);
+      CHECK_EQ(block, rpo_order->at(block->rpo_number()));
     }
   }
   // Verify RPO blocks are marked.
   for (size_t b = 0; b < rpo_order->size(); b++) {
-    CHECK(marked[rpo_order->at(b)->id()]);
+    CHECK(marked[rpo_order->at(b)->id().ToSize()]);
   }
 
   {
     // Verify the dominance relation.
-    ZoneList<BitVector*> dominators(count, zone);
-    dominators.Initialize(count, zone);
-    dominators.AddBlock(NULL, count, zone);
+    ZoneVector<BitVector*> dominators(zone);
+    dominators.resize(count, NULL);
 
     // Compute a set of all the nodes that dominate a given node by using
     // a forward fixpoint. O(n^2).
     ZoneQueue<BasicBlock*> queue(zone);
     queue.push(start);
-    dominators[start->id()] = new (zone) BitVector(count, zone);
+    dominators[start->id().ToSize()] =
+        new (zone) BitVector(static_cast<int>(count), zone);
     while (!queue.empty()) {
       BasicBlock* block = queue.front();
       queue.pop();
-      BitVector* block_doms = dominators[block->id()];
-      BasicBlock* idom = block->dominator_;
-      if (idom != NULL && !block_doms->Contains(idom->id())) {
+      BitVector* block_doms = dominators[block->id().ToSize()];
+      BasicBlock* idom = block->dominator();
+      if (idom != NULL && !block_doms->Contains(idom->id().ToInt())) {
         V8_Fatal(__FILE__, __LINE__, "Block B%d is not dominated by B%d",
-                 block->id(), idom->id());
+                 block->id().ToInt(), idom->id().ToInt());
       }
-      for (int s = 0; s < block->SuccessorCount(); s++) {
+      for (size_t s = 0; s < block->SuccessorCount(); s++) {
         BasicBlock* succ = block->SuccessorAt(s);
-        BitVector* succ_doms = dominators[succ->id()];
+        BitVector* succ_doms = dominators[succ->id().ToSize()];
 
         if (succ_doms == NULL) {
           // First time visiting the node. S.doms = B U B.doms
-          succ_doms = new (zone) BitVector(count, zone);
+          succ_doms = new (zone) BitVector(static_cast<int>(count), zone);
           succ_doms->CopyFrom(*block_doms);
-          succ_doms->Add(block->id());
-          dominators[succ->id()] = succ_doms;
+          succ_doms->Add(block->id().ToInt());
+          dominators[succ->id().ToSize()] = succ_doms;
           queue.push(succ);
         } else {
           // Nth time visiting the successor. S.doms = S.doms ^ (B U B.doms)
-          bool had = succ_doms->Contains(block->id());
-          if (had) succ_doms->Remove(block->id());
+          bool had = succ_doms->Contains(block->id().ToInt());
+          if (had) succ_doms->Remove(block->id().ToInt());
           if (succ_doms->IntersectIsChanged(*block_doms)) queue.push(succ);
-          if (had) succ_doms->Add(block->id());
+          if (had) succ_doms->Add(block->id().ToInt());
         }
       }
     }
@@ -398,16 +930,18 @@
     for (BasicBlockVector::iterator b = rpo_order->begin();
          b != rpo_order->end(); ++b) {
       BasicBlock* block = *b;
-      BasicBlock* idom = block->dominator_;
+      BasicBlock* idom = block->dominator();
       if (idom == NULL) continue;
-      BitVector* block_doms = dominators[block->id()];
+      BitVector* block_doms = dominators[block->id().ToSize()];
 
       for (BitVector::Iterator it(block_doms); !it.Done(); it.Advance()) {
-        BasicBlock* dom = schedule->GetBlockById(it.Current());
-        if (dom != idom && !dominators[idom->id()]->Contains(dom->id())) {
+        BasicBlock* dom =
+            schedule->GetBlockById(BasicBlock::Id::FromInt(it.Current()));
+        if (dom != idom &&
+            !dominators[idom->id().ToSize()]->Contains(dom->id().ToInt())) {
           V8_Fatal(__FILE__, __LINE__,
-                   "Block B%d is not immediately dominated by B%d", block->id(),
-                   idom->id());
+                   "Block B%d is not immediately dominated by B%d",
+                   block->id().ToInt(), idom->id().ToInt());
         }
       }
     }
@@ -421,8 +955,7 @@
       if (phi->opcode() != IrOpcode::kPhi) continue;
       // TODO(titzer): Nasty special case. Phis from RawMachineAssembler
       // schedules don't have control inputs.
-      if (phi->InputCount() >
-          OperatorProperties::GetValueInputCount(phi->op())) {
+      if (phi->InputCount() > phi->op()->ValueInputCount()) {
         Node* control = NodeProperties::GetControlInput(phi);
         CHECK(control->opcode() == IrOpcode::kMerge ||
               control->opcode() == IrOpcode::kLoop);
@@ -437,15 +970,15 @@
     BasicBlock* block = *b;
 
     // Check inputs to control for this block.
-    Node* control = block->control_input_;
+    Node* control = block->control_input();
     if (control != NULL) {
       CHECK_EQ(block, schedule->block(control));
       CheckInputsDominate(schedule, block, control,
-                          static_cast<int>(block->nodes_.size()) - 1);
+                          static_cast<int>(block->NodeCount()) - 1);
     }
     // Check inputs for all nodes in the block.
-    for (size_t i = 0; i < block->nodes_.size(); i++) {
-      Node* node = block->nodes_[i];
+    for (size_t i = 0; i < block->NodeCount(); i++) {
+      Node* node = block->NodeAt(i);
       CheckInputsDominate(schedule, block, node, static_cast<int>(i) - 1);
     }
   }
diff --git a/src/compiler/verifier.h b/src/compiler/verifier.h
index b5c028e..67b7ba6 100644
--- a/src/compiler/verifier.h
+++ b/src/compiler/verifier.h
@@ -18,7 +18,9 @@
 // each node, etc.
 class Verifier {
  public:
-  static void Run(Graph* graph);
+  enum Typing { TYPED, UNTYPED };
+
+  static void Run(Graph* graph, Typing typing = TYPED);
 
  private:
   class Visitor;
diff --git a/src/compiler/x64/code-generator-x64.cc b/src/compiler/x64/code-generator-x64.cc
index f71d3bf..0480f9d 100644
--- a/src/compiler/x64/code-generator-x64.cc
+++ b/src/compiler/x64/code-generator-x64.cc
@@ -19,186 +19,487 @@
 #define __ masm()->
 
 
-// TODO(turbofan): Cleanup these hacks.
-enum Immediate64Type { kImm64Value, kImm64Handle, kImm64Reference };
-
-
-struct Immediate64 {
-  uint64_t value;
-  Handle<Object> handle;
-  ExternalReference reference;
-  Immediate64Type type;
-};
-
-
-enum RegisterOrOperandType { kRegister, kDoubleRegister, kOperand };
-
-
-struct RegisterOrOperand {
-  RegisterOrOperand() : operand(no_reg, 0) {}
-  Register reg;
-  DoubleRegister double_reg;
-  Operand operand;
-  RegisterOrOperandType type;
-};
-
-
 // Adds X64 specific methods for decoding operands.
 class X64OperandConverter : public InstructionOperandConverter {
  public:
   X64OperandConverter(CodeGenerator* gen, Instruction* instr)
       : InstructionOperandConverter(gen, instr) {}
 
-  RegisterOrOperand InputRegisterOrOperand(int index) {
-    return ToRegisterOrOperand(instr_->InputAt(index));
-  }
-
   Immediate InputImmediate(int index) {
     return ToImmediate(instr_->InputAt(index));
   }
 
-  RegisterOrOperand OutputRegisterOrOperand() {
-    return ToRegisterOrOperand(instr_->Output());
-  }
+  Operand InputOperand(int index) { return ToOperand(instr_->InputAt(index)); }
 
-  Immediate64 InputImmediate64(int index) {
-    return ToImmediate64(instr_->InputAt(index));
-  }
-
-  Immediate64 ToImmediate64(InstructionOperand* operand) {
-    Constant constant = ToConstant(operand);
-    Immediate64 immediate;
-    immediate.value = 0xbeefdeaddeefbeed;
-    immediate.type = kImm64Value;
-    switch (constant.type()) {
-      case Constant::kInt32:
-      case Constant::kInt64:
-        immediate.value = constant.ToInt64();
-        return immediate;
-      case Constant::kFloat64:
-        immediate.type = kImm64Handle;
-        immediate.handle =
-            isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED);
-        return immediate;
-      case Constant::kExternalReference:
-        immediate.type = kImm64Reference;
-        immediate.reference = constant.ToExternalReference();
-        return immediate;
-      case Constant::kHeapObject:
-        immediate.type = kImm64Handle;
-        immediate.handle = constant.ToHeapObject();
-        return immediate;
-    }
-    UNREACHABLE();
-    return immediate;
-  }
+  Operand OutputOperand() { return ToOperand(instr_->Output()); }
 
   Immediate ToImmediate(InstructionOperand* operand) {
-    Constant constant = ToConstant(operand);
-    switch (constant.type()) {
-      case Constant::kInt32:
-        return Immediate(constant.ToInt32());
-      case Constant::kInt64:
-      case Constant::kFloat64:
-      case Constant::kExternalReference:
-      case Constant::kHeapObject:
-        break;
-    }
-    UNREACHABLE();
-    return Immediate(-1);
+    return Immediate(ToConstant(operand).ToInt32());
   }
 
   Operand ToOperand(InstructionOperand* op, int extra = 0) {
-    RegisterOrOperand result = ToRegisterOrOperand(op, extra);
-    DCHECK_EQ(kOperand, result.type);
-    return result.operand;
-  }
-
-  RegisterOrOperand ToRegisterOrOperand(InstructionOperand* op, int extra = 0) {
-    RegisterOrOperand result;
-    if (op->IsRegister()) {
-      DCHECK(extra == 0);
-      result.type = kRegister;
-      result.reg = ToRegister(op);
-      return result;
-    } else if (op->IsDoubleRegister()) {
-      DCHECK(extra == 0);
-      DCHECK(extra == 0);
-      result.type = kDoubleRegister;
-      result.double_reg = ToDoubleRegister(op);
-      return result;
-    }
-
     DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
-
-    result.type = kOperand;
     // The linkage computes where all spill slots are located.
     FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), extra);
-    result.operand =
-        Operand(offset.from_stack_pointer() ? rsp : rbp, offset.offset());
-    return result;
+    return Operand(offset.from_stack_pointer() ? rsp : rbp, offset.offset());
   }
 
-  Operand MemoryOperand(int* first_input) {
-    const int offset = *first_input;
-    switch (AddressingModeField::decode(instr_->opcode())) {
-      case kMode_MR1I: {
-        *first_input += 2;
-        Register index = InputRegister(offset + 1);
-        return Operand(InputRegister(offset + 0), index, times_1,
-                       0);  // TODO(dcarney): K != 0
+  static int NextOffset(int* offset) {
+    int i = *offset;
+    (*offset)++;
+    return i;
+  }
+
+  static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) {
+    STATIC_ASSERT(0 == static_cast<int>(times_1));
+    STATIC_ASSERT(1 == static_cast<int>(times_2));
+    STATIC_ASSERT(2 == static_cast<int>(times_4));
+    STATIC_ASSERT(3 == static_cast<int>(times_8));
+    int scale = static_cast<int>(mode - one);
+    DCHECK(scale >= 0 && scale < 4);
+    return static_cast<ScaleFactor>(scale);
+  }
+
+  Operand MemoryOperand(int* offset) {
+    AddressingMode mode = AddressingModeField::decode(instr_->opcode());
+    switch (mode) {
+      case kMode_MR: {
+        Register base = InputRegister(NextOffset(offset));
+        int32_t disp = 0;
+        return Operand(base, disp);
       }
-      case kMode_MRI:
-        *first_input += 2;
-        return Operand(InputRegister(offset + 0), InputInt32(offset + 1));
-      default:
+      case kMode_MRI: {
+        Register base = InputRegister(NextOffset(offset));
+        int32_t disp = InputInt32(NextOffset(offset));
+        return Operand(base, disp);
+      }
+      case kMode_MR1:
+      case kMode_MR2:
+      case kMode_MR4:
+      case kMode_MR8: {
+        Register base = InputRegister(NextOffset(offset));
+        Register index = InputRegister(NextOffset(offset));
+        ScaleFactor scale = ScaleFor(kMode_MR1, mode);
+        int32_t disp = 0;
+        return Operand(base, index, scale, disp);
+      }
+      case kMode_MR1I:
+      case kMode_MR2I:
+      case kMode_MR4I:
+      case kMode_MR8I: {
+        Register base = InputRegister(NextOffset(offset));
+        Register index = InputRegister(NextOffset(offset));
+        ScaleFactor scale = ScaleFor(kMode_MR1I, mode);
+        int32_t disp = InputInt32(NextOffset(offset));
+        return Operand(base, index, scale, disp);
+      }
+      case kMode_M1: {
+        Register base = InputRegister(NextOffset(offset));
+        int32_t disp = 0;
+        return Operand(base, disp);
+      }
+      case kMode_M2:
+        UNREACHABLE();  // Should use kModeMR with more compact encoding instead
+        return Operand(no_reg, 0);
+      case kMode_M4:
+      case kMode_M8: {
+        Register index = InputRegister(NextOffset(offset));
+        ScaleFactor scale = ScaleFor(kMode_M1, mode);
+        int32_t disp = 0;
+        return Operand(index, scale, disp);
+      }
+      case kMode_M1I:
+      case kMode_M2I:
+      case kMode_M4I:
+      case kMode_M8I: {
+        Register index = InputRegister(NextOffset(offset));
+        ScaleFactor scale = ScaleFor(kMode_M1I, mode);
+        int32_t disp = InputInt32(NextOffset(offset));
+        return Operand(index, scale, disp);
+      }
+      case kMode_None:
         UNREACHABLE();
         return Operand(no_reg, 0);
     }
+    UNREACHABLE();
+    return Operand(no_reg, 0);
   }
 
-  Operand MemoryOperand() {
-    int first_input = 0;
+  Operand MemoryOperand(int first_input = 0) {
     return MemoryOperand(&first_input);
   }
 };
 
 
-static bool HasImmediateInput(Instruction* instr, int index) {
+namespace {
+
+bool HasImmediateInput(Instruction* instr, int index) {
   return instr->InputAt(index)->IsImmediate();
 }
 
 
-#define ASSEMBLE_BINOP(asm_instr)                            \
-  do {                                                       \
-    if (HasImmediateInput(instr, 1)) {                       \
-      RegisterOrOperand input = i.InputRegisterOrOperand(0); \
-      if (input.type == kRegister) {                         \
-        __ asm_instr(input.reg, i.InputImmediate(1));        \
-      } else {                                               \
-        __ asm_instr(input.operand, i.InputImmediate(1));    \
-      }                                                      \
-    } else {                                                 \
-      RegisterOrOperand input = i.InputRegisterOrOperand(1); \
-      if (input.type == kRegister) {                         \
-        __ asm_instr(i.InputRegister(0), input.reg);         \
-      } else {                                               \
-        __ asm_instr(i.InputRegister(0), input.operand);     \
-      }                                                      \
-    }                                                        \
+class OutOfLineLoadZero FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadZero(CodeGenerator* gen, Register result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL { __ xorl(result_, result_); }
+
+ private:
+  Register const result_;
+};
+
+
+class OutOfLineLoadNaN FINAL : public OutOfLineCode {
+ public:
+  OutOfLineLoadNaN(CodeGenerator* gen, XMMRegister result)
+      : OutOfLineCode(gen), result_(result) {}
+
+  void Generate() FINAL { __ pcmpeqd(result_, result_); }
+
+ private:
+  XMMRegister const result_;
+};
+
+
+class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
+ public:
+  OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result,
+                             XMMRegister input)
+      : OutOfLineCode(gen), result_(result), input_(input) {}
+
+  void Generate() FINAL {
+    __ subp(rsp, Immediate(kDoubleSize));
+    __ movsd(MemOperand(rsp, 0), input_);
+    __ SlowTruncateToI(result_, rsp, 0);
+    __ addp(rsp, Immediate(kDoubleSize));
+  }
+
+ private:
+  Register const result_;
+  XMMRegister const input_;
+};
+
+}  // namespace
+
+
+#define ASSEMBLE_UNOP(asm_instr)         \
+  do {                                   \
+    if (instr->Output()->IsRegister()) { \
+      __ asm_instr(i.OutputRegister());  \
+    } else {                             \
+      __ asm_instr(i.OutputOperand());   \
+    }                                    \
   } while (0)
 
 
-#define ASSEMBLE_SHIFT(asm_instr, width)                                 \
-  do {                                                                   \
-    if (HasImmediateInput(instr, 1)) {                                   \
-      __ asm_instr(i.OutputRegister(), Immediate(i.InputInt##width(1))); \
-    } else {                                                             \
-      __ asm_instr##_cl(i.OutputRegister());                             \
-    }                                                                    \
+#define ASSEMBLE_BINOP(asm_instr)                              \
+  do {                                                         \
+    if (HasImmediateInput(instr, 1)) {                         \
+      if (instr->InputAt(0)->IsRegister()) {                   \
+        __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
+      } else {                                                 \
+        __ asm_instr(i.InputOperand(0), i.InputImmediate(1));  \
+      }                                                        \
+    } else {                                                   \
+      if (instr->InputAt(1)->IsRegister()) {                   \
+        __ asm_instr(i.InputRegister(0), i.InputRegister(1));  \
+      } else {                                                 \
+        __ asm_instr(i.InputRegister(0), i.InputOperand(1));   \
+      }                                                        \
+    }                                                          \
   } while (0)
 
 
+#define ASSEMBLE_MULT(asm_instr)                              \
+  do {                                                        \
+    if (HasImmediateInput(instr, 1)) {                        \
+      if (instr->InputAt(0)->IsRegister()) {                  \
+        __ asm_instr(i.OutputRegister(), i.InputRegister(0),  \
+                     i.InputImmediate(1));                    \
+      } else {                                                \
+        __ asm_instr(i.OutputRegister(), i.InputOperand(0),   \
+                     i.InputImmediate(1));                    \
+      }                                                       \
+    } else {                                                  \
+      if (instr->InputAt(1)->IsRegister()) {                  \
+        __ asm_instr(i.OutputRegister(), i.InputRegister(1)); \
+      } else {                                                \
+        __ asm_instr(i.OutputRegister(), i.InputOperand(1));  \
+      }                                                       \
+    }                                                         \
+  } while (0)
+
+
+#define ASSEMBLE_SHIFT(asm_instr, width)                                   \
+  do {                                                                     \
+    if (HasImmediateInput(instr, 1)) {                                     \
+      if (instr->Output()->IsRegister()) {                                 \
+        __ asm_instr(i.OutputRegister(), Immediate(i.InputInt##width(1))); \
+      } else {                                                             \
+        __ asm_instr(i.OutputOperand(), Immediate(i.InputInt##width(1)));  \
+      }                                                                    \
+    } else {                                                               \
+      if (instr->Output()->IsRegister()) {                                 \
+        __ asm_instr##_cl(i.OutputRegister());                             \
+      } else {                                                             \
+        __ asm_instr##_cl(i.OutputOperand());                              \
+      }                                                                    \
+    }                                                                      \
+  } while (0)
+
+
+#define ASSEMBLE_DOUBLE_BINOP(asm_instr)                                \
+  do {                                                                  \
+    if (instr->InputAt(1)->IsDoubleRegister()) {                        \
+      __ asm_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1)); \
+    } else {                                                            \
+      __ asm_instr(i.InputDoubleRegister(0), i.InputOperand(1));        \
+    }                                                                   \
+  } while (0)
+
+
+#define ASSEMBLE_AVX_DOUBLE_BINOP(asm_instr)                           \
+  do {                                                                 \
+    CpuFeatureScope avx_scope(masm(), AVX);                            \
+    if (instr->InputAt(1)->IsDoubleRegister()) {                       \
+      __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
+                   i.InputDoubleRegister(1));                          \
+    } else {                                                           \
+      __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
+                   i.InputOperand(1));                                 \
+    }                                                                  \
+  } while (0)
+
+
+#define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr)                               \
+  do {                                                                       \
+    auto result = i.OutputDoubleRegister();                                  \
+    auto buffer = i.InputRegister(0);                                        \
+    auto index1 = i.InputRegister(1);                                        \
+    auto index2 = i.InputInt32(2);                                           \
+    OutOfLineCode* ool;                                                      \
+    if (instr->InputAt(3)->IsRegister()) {                                   \
+      auto length = i.InputRegister(3);                                      \
+      DCHECK_EQ(0, index2);                                                  \
+      __ cmpl(index1, length);                                               \
+      ool = new (zone()) OutOfLineLoadNaN(this, result);                     \
+    } else {                                                                 \
+      auto length = i.InputInt32(3);                                         \
+      DCHECK_LE(index2, length);                                             \
+      __ cmpq(index1, Immediate(length - index2));                           \
+      class OutOfLineLoadFloat FINAL : public OutOfLineCode {                \
+       public:                                                               \
+        OutOfLineLoadFloat(CodeGenerator* gen, XMMRegister result,           \
+                           Register buffer, Register index1, int32_t index2, \
+                           int32_t length)                                   \
+            : OutOfLineCode(gen),                                            \
+              result_(result),                                               \
+              buffer_(buffer),                                               \
+              index1_(index1),                                               \
+              index2_(index2),                                               \
+              length_(length) {}                                             \
+                                                                             \
+        void Generate() FINAL {                                              \
+          __ leal(kScratchRegister, Operand(index1_, index2_));              \
+          __ pcmpeqd(result_, result_);                                      \
+          __ cmpl(kScratchRegister, Immediate(length_));                     \
+          __ j(above_equal, exit());                                         \
+          __ asm_instr(result_,                                              \
+                       Operand(buffer_, kScratchRegister, times_1, 0));      \
+        }                                                                    \
+                                                                             \
+       private:                                                              \
+        XMMRegister const result_;                                           \
+        Register const buffer_;                                              \
+        Register const index1_;                                              \
+        int32_t const index2_;                                               \
+        int32_t const length_;                                               \
+      };                                                                     \
+      ool = new (zone())                                                     \
+          OutOfLineLoadFloat(this, result, buffer, index1, index2, length);  \
+    }                                                                        \
+    __ j(above_equal, ool->entry());                                         \
+    __ asm_instr(result, Operand(buffer, index1, times_1, index2));          \
+    __ bind(ool->exit());                                                    \
+  } while (false)
+
+
+#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)                               \
+  do {                                                                         \
+    auto result = i.OutputRegister();                                          \
+    auto buffer = i.InputRegister(0);                                          \
+    auto index1 = i.InputRegister(1);                                          \
+    auto index2 = i.InputInt32(2);                                             \
+    OutOfLineCode* ool;                                                        \
+    if (instr->InputAt(3)->IsRegister()) {                                     \
+      auto length = i.InputRegister(3);                                        \
+      DCHECK_EQ(0, index2);                                                    \
+      __ cmpl(index1, length);                                                 \
+      ool = new (zone()) OutOfLineLoadZero(this, result);                      \
+    } else {                                                                   \
+      auto length = i.InputInt32(3);                                           \
+      DCHECK_LE(index2, length);                                               \
+      __ cmpq(index1, Immediate(length - index2));                             \
+      class OutOfLineLoadInteger FINAL : public OutOfLineCode {                \
+       public:                                                                 \
+        OutOfLineLoadInteger(CodeGenerator* gen, Register result,              \
+                             Register buffer, Register index1, int32_t index2, \
+                             int32_t length)                                   \
+            : OutOfLineCode(gen),                                              \
+              result_(result),                                                 \
+              buffer_(buffer),                                                 \
+              index1_(index1),                                                 \
+              index2_(index2),                                                 \
+              length_(length) {}                                               \
+                                                                               \
+        void Generate() FINAL {                                                \
+          Label oob;                                                           \
+          __ leal(kScratchRegister, Operand(index1_, index2_));                \
+          __ cmpl(kScratchRegister, Immediate(length_));                       \
+          __ j(above_equal, &oob, Label::kNear);                               \
+          __ asm_instr(result_,                                                \
+                       Operand(buffer_, kScratchRegister, times_1, 0));        \
+          __ jmp(exit());                                                      \
+          __ bind(&oob);                                                       \
+          __ xorl(result_, result_);                                           \
+        }                                                                      \
+                                                                               \
+       private:                                                                \
+        Register const result_;                                                \
+        Register const buffer_;                                                \
+        Register const index1_;                                                \
+        int32_t const index2_;                                                 \
+        int32_t const length_;                                                 \
+      };                                                                       \
+      ool = new (zone())                                                       \
+          OutOfLineLoadInteger(this, result, buffer, index1, index2, length);  \
+    }                                                                          \
+    __ j(above_equal, ool->entry());                                           \
+    __ asm_instr(result, Operand(buffer, index1, times_1, index2));            \
+    __ bind(ool->exit());                                                      \
+  } while (false)
+
+
+#define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr)                              \
+  do {                                                                       \
+    auto buffer = i.InputRegister(0);                                        \
+    auto index1 = i.InputRegister(1);                                        \
+    auto index2 = i.InputInt32(2);                                           \
+    auto value = i.InputDoubleRegister(4);                                   \
+    if (instr->InputAt(3)->IsRegister()) {                                   \
+      auto length = i.InputRegister(3);                                      \
+      DCHECK_EQ(0, index2);                                                  \
+      Label done;                                                            \
+      __ cmpl(index1, length);                                               \
+      __ j(above_equal, &done, Label::kNear);                                \
+      __ asm_instr(Operand(buffer, index1, times_1, index2), value);         \
+      __ bind(&done);                                                        \
+    } else {                                                                 \
+      auto length = i.InputInt32(3);                                         \
+      DCHECK_LE(index2, length);                                             \
+      __ cmpq(index1, Immediate(length - index2));                           \
+      class OutOfLineStoreFloat FINAL : public OutOfLineCode {               \
+       public:                                                               \
+        OutOfLineStoreFloat(CodeGenerator* gen, Register buffer,             \
+                            Register index1, int32_t index2, int32_t length, \
+                            XMMRegister value)                               \
+            : OutOfLineCode(gen),                                            \
+              buffer_(buffer),                                               \
+              index1_(index1),                                               \
+              index2_(index2),                                               \
+              length_(length),                                               \
+              value_(value) {}                                               \
+                                                                             \
+        void Generate() FINAL {                                              \
+          __ leal(kScratchRegister, Operand(index1_, index2_));              \
+          __ cmpl(kScratchRegister, Immediate(length_));                     \
+          __ j(above_equal, exit());                                         \
+          __ asm_instr(Operand(buffer_, kScratchRegister, times_1, 0),       \
+                       value_);                                              \
+        }                                                                    \
+                                                                             \
+       private:                                                              \
+        Register const buffer_;                                              \
+        Register const index1_;                                              \
+        int32_t const index2_;                                               \
+        int32_t const length_;                                               \
+        XMMRegister const value_;                                            \
+      };                                                                     \
+      auto ool = new (zone())                                                \
+          OutOfLineStoreFloat(this, buffer, index1, index2, length, value);  \
+      __ j(above_equal, ool->entry());                                       \
+      __ asm_instr(Operand(buffer, index1, times_1, index2), value);         \
+      __ bind(ool->exit());                                                  \
+    }                                                                        \
+  } while (false)
+
+
+#define ASSEMBLE_CHECKED_STORE_INTEGER_IMPL(asm_instr, Value)                  \
+  do {                                                                         \
+    auto buffer = i.InputRegister(0);                                          \
+    auto index1 = i.InputRegister(1);                                          \
+    auto index2 = i.InputInt32(2);                                             \
+    if (instr->InputAt(3)->IsRegister()) {                                     \
+      auto length = i.InputRegister(3);                                        \
+      DCHECK_EQ(0, index2);                                                    \
+      Label done;                                                              \
+      __ cmpl(index1, length);                                                 \
+      __ j(above_equal, &done, Label::kNear);                                  \
+      __ asm_instr(Operand(buffer, index1, times_1, index2), value);           \
+      __ bind(&done);                                                          \
+    } else {                                                                   \
+      auto length = i.InputInt32(3);                                           \
+      DCHECK_LE(index2, length);                                               \
+      __ cmpq(index1, Immediate(length - index2));                             \
+      class OutOfLineStoreInteger FINAL : public OutOfLineCode {               \
+       public:                                                                 \
+        OutOfLineStoreInteger(CodeGenerator* gen, Register buffer,             \
+                              Register index1, int32_t index2, int32_t length, \
+                              Value value)                                     \
+            : OutOfLineCode(gen),                                              \
+              buffer_(buffer),                                                 \
+              index1_(index1),                                                 \
+              index2_(index2),                                                 \
+              length_(length),                                                 \
+              value_(value) {}                                                 \
+                                                                               \
+        void Generate() FINAL {                                                \
+          __ leal(kScratchRegister, Operand(index1_, index2_));                \
+          __ cmpl(kScratchRegister, Immediate(length_));                       \
+          __ j(above_equal, exit());                                           \
+          __ asm_instr(Operand(buffer_, kScratchRegister, times_1, 0),         \
+                       value_);                                                \
+        }                                                                      \
+                                                                               \
+       private:                                                                \
+        Register const buffer_;                                                \
+        Register const index1_;                                                \
+        int32_t const index2_;                                                 \
+        int32_t const length_;                                                 \
+        Value const value_;                                                    \
+      };                                                                       \
+      auto ool = new (zone())                                                  \
+          OutOfLineStoreInteger(this, buffer, index1, index2, length, value);  \
+      __ j(above_equal, ool->entry());                                         \
+      __ asm_instr(Operand(buffer, index1, times_1, index2), value);           \
+      __ bind(ool->exit());                                                    \
+    }                                                                          \
+  } while (false)
+
+
+#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)                \
+  do {                                                           \
+    if (instr->InputAt(4)->IsRegister()) {                       \
+      Register value = i.InputRegister(4);                       \
+      ASSEMBLE_CHECKED_STORE_INTEGER_IMPL(asm_instr, Register);  \
+    } else {                                                     \
+      Immediate value = i.InputImmediate(4);                     \
+      ASSEMBLE_CHECKED_STORE_INTEGER_IMPL(asm_instr, Immediate); \
+    }                                                            \
+  } while (false)
+
+
 // Assembles an instruction after register allocation, producing machine code.
 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
   X64OperandConverter i(this, instr);
@@ -230,7 +531,7 @@
       break;
     }
     case kArchJmp:
-      __ jmp(code_->GetLabel(i.InputBlock(0)));
+      AssembleArchJump(i.InputRpo(0));
       break;
     case kArchNop:
       // don't emit code for nops.
@@ -238,9 +539,19 @@
     case kArchRet:
       AssembleReturn();
       break;
-    case kArchTruncateDoubleToI:
-      __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
+    case kArchStackPointer:
+      __ movq(i.OutputRegister(), rsp);
       break;
+    case kArchTruncateDoubleToI: {
+      auto result = i.OutputRegister();
+      auto input = i.InputDoubleRegister(0);
+      auto ool = new (zone()) OutOfLineTruncateDoubleToI(this, result, input);
+      __ cvttsd2siq(result, input);
+      __ cmpq(result, Immediate(1));
+      __ j(overflow, ool->entry());
+      __ bind(ool->exit());
+      break;
+    }
     case kX64Add32:
       ASSEMBLE_BINOP(addl);
       break;
@@ -272,39 +583,23 @@
       ASSEMBLE_BINOP(testq);
       break;
     case kX64Imul32:
-      if (HasImmediateInput(instr, 1)) {
-        RegisterOrOperand input = i.InputRegisterOrOperand(0);
-        if (input.type == kRegister) {
-          __ imull(i.OutputRegister(), input.reg, i.InputImmediate(1));
-        } else {
-          __ movq(kScratchRegister, input.operand);
-          __ imull(i.OutputRegister(), kScratchRegister, i.InputImmediate(1));
-        }
-      } else {
-        RegisterOrOperand input = i.InputRegisterOrOperand(1);
-        if (input.type == kRegister) {
-          __ imull(i.OutputRegister(), input.reg);
-        } else {
-          __ imull(i.OutputRegister(), input.operand);
-        }
-      }
+      ASSEMBLE_MULT(imull);
       break;
     case kX64Imul:
-      if (HasImmediateInput(instr, 1)) {
-        RegisterOrOperand input = i.InputRegisterOrOperand(0);
-        if (input.type == kRegister) {
-          __ imulq(i.OutputRegister(), input.reg, i.InputImmediate(1));
-        } else {
-          __ movq(kScratchRegister, input.operand);
-          __ imulq(i.OutputRegister(), kScratchRegister, i.InputImmediate(1));
-        }
+      ASSEMBLE_MULT(imulq);
+      break;
+    case kX64ImulHigh32:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ imull(i.InputRegister(1));
       } else {
-        RegisterOrOperand input = i.InputRegisterOrOperand(1);
-        if (input.type == kRegister) {
-          __ imulq(i.OutputRegister(), input.reg);
-        } else {
-          __ imulq(i.OutputRegister(), input.operand);
-        }
+        __ imull(i.InputOperand(1));
+      }
+      break;
+    case kX64UmulHigh32:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ mull(i.InputRegister(1));
+      } else {
+        __ mull(i.InputOperand(1));
       }
       break;
     case kX64Idiv32:
@@ -323,42 +618,18 @@
       __ xorq(rdx, rdx);
       __ divq(i.InputRegister(1));
       break;
-    case kX64Not: {
-      RegisterOrOperand output = i.OutputRegisterOrOperand();
-      if (output.type == kRegister) {
-        __ notq(output.reg);
-      } else {
-        __ notq(output.operand);
-      }
+    case kX64Not:
+      ASSEMBLE_UNOP(notq);
       break;
-    }
-    case kX64Not32: {
-      RegisterOrOperand output = i.OutputRegisterOrOperand();
-      if (output.type == kRegister) {
-        __ notl(output.reg);
-      } else {
-        __ notl(output.operand);
-      }
+    case kX64Not32:
+      ASSEMBLE_UNOP(notl);
       break;
-    }
-    case kX64Neg: {
-      RegisterOrOperand output = i.OutputRegisterOrOperand();
-      if (output.type == kRegister) {
-        __ negq(output.reg);
-      } else {
-        __ negq(output.operand);
-      }
+    case kX64Neg:
+      ASSEMBLE_UNOP(negq);
       break;
-    }
-    case kX64Neg32: {
-      RegisterOrOperand output = i.OutputRegisterOrOperand();
-      if (output.type == kRegister) {
-        __ negl(output.reg);
-      } else {
-        __ negl(output.operand);
-      }
+    case kX64Neg32:
+      ASSEMBLE_UNOP(negl);
       break;
-    }
     case kX64Or32:
       ASSEMBLE_BINOP(orl);
       break;
@@ -395,26 +666,20 @@
     case kX64Ror:
       ASSEMBLE_SHIFT(rorq, 6);
       break;
-    case kSSEFloat64Cmp: {
-      RegisterOrOperand input = i.InputRegisterOrOperand(1);
-      if (input.type == kDoubleRegister) {
-        __ ucomisd(i.InputDoubleRegister(0), input.double_reg);
-      } else {
-        __ ucomisd(i.InputDoubleRegister(0), input.operand);
-      }
+    case kSSEFloat64Cmp:
+      ASSEMBLE_DOUBLE_BINOP(ucomisd);
       break;
-    }
     case kSSEFloat64Add:
-      __ addsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+      ASSEMBLE_DOUBLE_BINOP(addsd);
       break;
     case kSSEFloat64Sub:
-      __ subsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+      ASSEMBLE_DOUBLE_BINOP(subsd);
       break;
     case kSSEFloat64Mul:
-      __ mulsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+      ASSEMBLE_DOUBLE_BINOP(mulsd);
       break;
     case kSSEFloat64Div:
-      __ divsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+      ASSEMBLE_DOUBLE_BINOP(divsd);
       break;
     case kSSEFloat64Mod: {
       __ subq(rsp, Immediate(kDoubleSize));
@@ -431,7 +696,8 @@
       __ fprem();
       // The following 2 instruction implicitly use rax.
       __ fnstsw_ax();
-      if (CpuFeatures::IsSupported(SAHF) && masm()->IsEnabled(SAHF)) {
+      if (CpuFeatures::IsSupported(SAHF)) {
+        CpuFeatureScope sahf_scope(masm(), SAHF);
         __ sahf();
       } else {
         __ shrl(rax, Immediate(8));
@@ -447,52 +713,97 @@
       __ addq(rsp, Immediate(kDoubleSize));
       break;
     }
-    case kSSEFloat64Sqrt: {
-      RegisterOrOperand input = i.InputRegisterOrOperand(0);
-      if (input.type == kDoubleRegister) {
-        __ sqrtsd(i.OutputDoubleRegister(), input.double_reg);
+    case kSSEFloat64Sqrt:
+      if (instr->InputAt(0)->IsDoubleRegister()) {
+        __ sqrtsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       } else {
-        __ sqrtsd(i.OutputDoubleRegister(), input.operand);
+        __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0));
       }
       break;
-    }
-    case kSSEFloat64ToInt32: {
-      RegisterOrOperand input = i.InputRegisterOrOperand(0);
-      if (input.type == kDoubleRegister) {
-        __ cvttsd2si(i.OutputRegister(), input.double_reg);
-      } else {
-        __ cvttsd2si(i.OutputRegister(), input.operand);
-      }
+    case kSSEFloat64Floor: {
+      CpuFeatureScope sse_scope(masm(), SSE4_1);
+      __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                 v8::internal::Assembler::kRoundDown);
       break;
     }
+    case kSSEFloat64Ceil: {
+      CpuFeatureScope sse_scope(masm(), SSE4_1);
+      __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                 v8::internal::Assembler::kRoundUp);
+      break;
+    }
+    case kSSEFloat64RoundTruncate: {
+      CpuFeatureScope sse_scope(masm(), SSE4_1);
+      __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                 v8::internal::Assembler::kRoundToZero);
+      break;
+    }
+    case kSSECvtss2sd:
+      if (instr->InputAt(0)->IsDoubleRegister()) {
+        __ cvtss2sd(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
+      } else {
+        __ cvtss2sd(i.OutputDoubleRegister(), i.InputOperand(0));
+      }
+      break;
+    case kSSECvtsd2ss:
+      if (instr->InputAt(0)->IsDoubleRegister()) {
+        __ cvtsd2ss(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
+      } else {
+        __ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0));
+      }
+      break;
+    case kSSEFloat64ToInt32:
+      if (instr->InputAt(0)->IsDoubleRegister()) {
+        __ cvttsd2si(i.OutputRegister(), i.InputDoubleRegister(0));
+      } else {
+        __ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
+      }
+      break;
     case kSSEFloat64ToUint32: {
-      RegisterOrOperand input = i.InputRegisterOrOperand(0);
-      if (input.type == kDoubleRegister) {
-        __ cvttsd2siq(i.OutputRegister(), input.double_reg);
+      if (instr->InputAt(0)->IsDoubleRegister()) {
+        __ cvttsd2siq(i.OutputRegister(), i.InputDoubleRegister(0));
       } else {
-        __ cvttsd2siq(i.OutputRegister(), input.operand);
+        __ cvttsd2siq(i.OutputRegister(), i.InputOperand(0));
       }
-      __ andl(i.OutputRegister(), i.OutputRegister());  // clear upper bits.
-      // TODO(turbofan): generated code should not look at the upper 32 bits
-      // of the result, but those bits could escape to the outside world.
+      __ AssertZeroExtended(i.OutputRegister());
       break;
     }
-    case kSSEInt32ToFloat64: {
-      RegisterOrOperand input = i.InputRegisterOrOperand(0);
-      if (input.type == kRegister) {
-        __ cvtlsi2sd(i.OutputDoubleRegister(), input.reg);
+    case kSSEInt32ToFloat64:
+      if (instr->InputAt(0)->IsRegister()) {
+        __ cvtlsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
       } else {
-        __ cvtlsi2sd(i.OutputDoubleRegister(), input.operand);
+        __ cvtlsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
       }
       break;
-    }
-    case kSSEUint32ToFloat64: {
-      // TODO(turbofan): X64 SSE cvtqsi2sd should support operands.
-      __ cvtqsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
+    case kSSEUint32ToFloat64:
+      if (instr->InputAt(0)->IsRegister()) {
+        __ movl(kScratchRegister, i.InputRegister(0));
+      } else {
+        __ movl(kScratchRegister, i.InputOperand(0));
+      }
+      __ cvtqsi2sd(i.OutputDoubleRegister(), kScratchRegister);
       break;
-    }
+    case kAVXFloat64Add:
+      ASSEMBLE_AVX_DOUBLE_BINOP(vaddsd);
+      break;
+    case kAVXFloat64Sub:
+      ASSEMBLE_AVX_DOUBLE_BINOP(vsubsd);
+      break;
+    case kAVXFloat64Mul:
+      ASSEMBLE_AVX_DOUBLE_BINOP(vmulsd);
+      break;
+    case kAVXFloat64Div:
+      ASSEMBLE_AVX_DOUBLE_BINOP(vdivsd);
+      break;
     case kX64Movsxbl:
-      __ movsxbl(i.OutputRegister(), i.MemoryOperand());
+      if (instr->addressing_mode() != kMode_None) {
+        __ movsxbl(i.OutputRegister(), i.MemoryOperand());
+      } else if (instr->InputAt(0)->IsRegister()) {
+        __ movsxbl(i.OutputRegister(), i.InputRegister(0));
+      } else {
+        __ movsxbl(i.OutputRegister(), i.InputOperand(0));
+      }
+      __ AssertZeroExtended(i.OutputRegister());
       break;
     case kX64Movzxbl:
       __ movzxbl(i.OutputRegister(), i.MemoryOperand());
@@ -508,10 +819,18 @@
       break;
     }
     case kX64Movsxwl:
-      __ movsxwl(i.OutputRegister(), i.MemoryOperand());
+      if (instr->addressing_mode() != kMode_None) {
+        __ movsxwl(i.OutputRegister(), i.MemoryOperand());
+      } else if (instr->InputAt(0)->IsRegister()) {
+        __ movsxwl(i.OutputRegister(), i.InputRegister(0));
+      } else {
+        __ movsxwl(i.OutputRegister(), i.InputOperand(0));
+      }
+      __ AssertZeroExtended(i.OutputRegister());
       break;
     case kX64Movzxwl:
       __ movzxwl(i.OutputRegister(), i.MemoryOperand());
+      __ AssertZeroExtended(i.OutputRegister());
       break;
     case kX64Movw: {
       int index = 0;
@@ -526,15 +845,15 @@
     case kX64Movl:
       if (instr->HasOutput()) {
         if (instr->addressing_mode() == kMode_None) {
-          RegisterOrOperand input = i.InputRegisterOrOperand(0);
-          if (input.type == kRegister) {
-            __ movl(i.OutputRegister(), input.reg);
+          if (instr->InputAt(0)->IsRegister()) {
+            __ movl(i.OutputRegister(), i.InputRegister(0));
           } else {
-            __ movl(i.OutputRegister(), input.operand);
+            __ movl(i.OutputRegister(), i.InputOperand(0));
           }
         } else {
           __ movl(i.OutputRegister(), i.MemoryOperand());
         }
+        __ AssertZeroExtended(i.OutputRegister());
       } else {
         int index = 0;
         Operand operand = i.MemoryOperand(&index);
@@ -546,11 +865,10 @@
       }
       break;
     case kX64Movsxlq: {
-      RegisterOrOperand input = i.InputRegisterOrOperand(0);
-      if (input.type == kRegister) {
-        __ movsxlq(i.OutputRegister(), input.reg);
+      if (instr->InputAt(0)->IsRegister()) {
+        __ movsxlq(i.OutputRegister(), i.InputRegister(0));
       } else {
-        __ movsxlq(i.OutputRegister(), input.operand);
+        __ movsxlq(i.OutputRegister(), i.InputOperand(0));
       }
       break;
     }
@@ -570,12 +888,10 @@
     case kX64Movss:
       if (instr->HasOutput()) {
         __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
-        __ cvtss2sd(i.OutputDoubleRegister(), i.OutputDoubleRegister());
       } else {
         int index = 0;
         Operand operand = i.MemoryOperand(&index);
-        __ cvtsd2ss(xmm0, i.InputDoubleRegister(index));
-        __ movss(operand, xmm0);
+        __ movss(operand, i.InputDoubleRegister(index));
       }
       break;
     case kX64Movsd:
@@ -587,15 +903,57 @@
         __ movsd(operand, i.InputDoubleRegister(index));
       }
       break;
+    case kX64Lea32: {
+      AddressingMode mode = AddressingModeField::decode(instr->opcode());
+      // Shorten "leal" to "addl", "subl" or "shll" if the register allocation
+      // and addressing mode just happens to work out. The "addl"/"subl" forms
+      // in these cases are faster based on measurements.
+      if (i.InputRegister(0).is(i.OutputRegister())) {
+        if (mode == kMode_MRI) {
+          int32_t constant_summand = i.InputInt32(1);
+          if (constant_summand > 0) {
+            __ addl(i.OutputRegister(), Immediate(constant_summand));
+          } else if (constant_summand < 0) {
+            __ subl(i.OutputRegister(), Immediate(-constant_summand));
+          }
+        } else if (mode == kMode_MR1) {
+          if (i.InputRegister(1).is(i.OutputRegister())) {
+            __ shll(i.OutputRegister(), Immediate(1));
+          } else {
+            __ leal(i.OutputRegister(), i.MemoryOperand());
+          }
+        } else if (mode == kMode_M2) {
+          __ shll(i.OutputRegister(), Immediate(1));
+        } else if (mode == kMode_M4) {
+          __ shll(i.OutputRegister(), Immediate(2));
+        } else if (mode == kMode_M8) {
+          __ shll(i.OutputRegister(), Immediate(3));
+        } else {
+          __ leal(i.OutputRegister(), i.MemoryOperand());
+        }
+      } else {
+        __ leal(i.OutputRegister(), i.MemoryOperand());
+      }
+      __ AssertZeroExtended(i.OutputRegister());
+      break;
+    }
+    case kX64Lea:
+      __ leaq(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kX64Dec32:
+      __ decl(i.OutputRegister());
+      break;
+    case kX64Inc32:
+      __ incl(i.OutputRegister());
+      break;
     case kX64Push:
       if (HasImmediateInput(instr, 0)) {
         __ pushq(i.InputImmediate(0));
       } else {
-        RegisterOrOperand input = i.InputRegisterOrOperand(0);
-        if (input.type == kRegister) {
-          __ pushq(input.reg);
+        if (instr->InputAt(0)->IsRegister()) {
+          __ pushq(i.InputRegister(0));
         } else {
-          __ pushq(input.operand);
+          __ pushq(i.InputOperand(0));
         }
       }
       break;
@@ -606,31 +964,59 @@
       __ movsxlq(index, index);
       __ movq(Operand(object, index, times_1, 0), value);
       __ leaq(index, Operand(object, index, times_1, 0));
-      SaveFPRegsMode mode = code_->frame()->DidAllocateDoubleRegisters()
-                                ? kSaveFPRegs
-                                : kDontSaveFPRegs;
+      SaveFPRegsMode mode =
+          frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
       __ RecordWrite(object, index, value, mode);
       break;
     }
+    case kCheckedLoadInt8:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(movsxbl);
+      break;
+    case kCheckedLoadUint8:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(movzxbl);
+      break;
+    case kCheckedLoadInt16:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(movsxwl);
+      break;
+    case kCheckedLoadUint16:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(movzxwl);
+      break;
+    case kCheckedLoadWord32:
+      ASSEMBLE_CHECKED_LOAD_INTEGER(movl);
+      break;
+    case kCheckedLoadFloat32:
+      ASSEMBLE_CHECKED_LOAD_FLOAT(movss);
+      break;
+    case kCheckedLoadFloat64:
+      ASSEMBLE_CHECKED_LOAD_FLOAT(movsd);
+      break;
+    case kCheckedStoreWord8:
+      ASSEMBLE_CHECKED_STORE_INTEGER(movb);
+      break;
+    case kCheckedStoreWord16:
+      ASSEMBLE_CHECKED_STORE_INTEGER(movw);
+      break;
+    case kCheckedStoreWord32:
+      ASSEMBLE_CHECKED_STORE_INTEGER(movl);
+      break;
+    case kCheckedStoreFloat32:
+      ASSEMBLE_CHECKED_STORE_FLOAT(movss);
+      break;
+    case kCheckedStoreFloat64:
+      ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
+      break;
   }
 }
 
 
 // Assembles branches after this instruction.
-void CodeGenerator::AssembleArchBranch(Instruction* instr,
-                                       FlagsCondition condition) {
+void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
   X64OperandConverter i(this, instr);
-  Label done;
-
-  // Emit a branch. The true and false targets are always the last two inputs
-  // to the instruction.
-  BasicBlock* tblock = i.InputBlock(static_cast<int>(instr->InputCount()) - 2);
-  BasicBlock* fblock = i.InputBlock(static_cast<int>(instr->InputCount()) - 1);
-  bool fallthru = IsNextInAssemblyOrder(fblock);
-  Label* tlabel = code()->GetLabel(tblock);
-  Label* flabel = fallthru ? &done : code()->GetLabel(fblock);
-  Label::Distance flabel_distance = fallthru ? Label::kNear : Label::kFar;
-  switch (condition) {
+  Label::Distance flabel_distance =
+      branch->fallthru ? Label::kNear : Label::kFar;
+  Label* tlabel = branch->true_label;
+  Label* flabel = branch->false_label;
+  switch (branch->condition) {
     case kUnorderedEqual:
       __ j(parity_even, flabel, flabel_distance);
     // Fall through.
@@ -686,8 +1072,12 @@
       __ j(no_overflow, tlabel);
       break;
   }
-  if (!fallthru) __ jmp(flabel, flabel_distance);  // no fallthru to flabel.
-  __ bind(&done);
+  if (!branch->fallthru) __ jmp(flabel, flabel_distance);
+}
+
+
+void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+  if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target));
 }
 
 
@@ -700,7 +1090,7 @@
   // Materialize a full 64-bit 1 or 0 value. The result register is always the
   // last output of the instruction.
   Label check;
-  DCHECK_NE(0, instr->OutputCount());
+  DCHECK_NE(0, static_cast<int>(instr->OutputCount()));
   Register reg = i.OutputRegister(static_cast<int>(instr->OutputCount() - 1));
   Condition cc = no_condition;
   switch (condition) {
@@ -802,27 +1192,10 @@
       frame()->SetRegisterSaveAreaSize(register_save_area_size);
     }
   } else if (descriptor->IsJSFunctionCall()) {
-    CompilationInfo* info = linkage()->info();
+    CompilationInfo* info = this->info();
     __ Prologue(info->IsCodePreAgingActive());
     frame()->SetRegisterSaveAreaSize(
         StandardFrameConstants::kFixedFrameSizeFromFp);
-
-    // Sloppy mode functions and builtins need to replace the receiver with the
-    // global proxy when called as functions (without an explicit receiver
-    // object).
-    // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
-    if (info->strict_mode() == SLOPPY && !info->is_native()) {
-      Label ok;
-      StackArgumentsAccessor args(rbp, info->scope()->num_parameters());
-      __ movp(rcx, args.GetReceiverOperand());
-      __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
-      __ j(not_equal, &ok, Label::kNear);
-      __ movp(rcx, GlobalObjectOperand());
-      __ movp(rcx, FieldOperand(rcx, GlobalObject::kGlobalProxyOffset));
-      __ movp(args.GetReceiverOperand(), rcx);
-      __ bind(&ok);
-    }
-
   } else {
     __ StubPrologue();
     frame()->SetRegisterSaveAreaSize(
@@ -899,31 +1272,57 @@
     }
   } else if (source->IsConstant()) {
     ConstantOperand* constant_source = ConstantOperand::cast(source);
+    Constant src = g.ToConstant(constant_source);
     if (destination->IsRegister() || destination->IsStackSlot()) {
       Register dst = destination->IsRegister() ? g.ToRegister(destination)
                                                : kScratchRegister;
-      Immediate64 imm = g.ToImmediate64(constant_source);
-      switch (imm.type) {
-        case kImm64Value:
-          __ Set(dst, imm.value);
+      switch (src.type()) {
+        case Constant::kInt32:
+          // TODO(dcarney): don't need scratch in this case.
+          __ Set(dst, src.ToInt32());
           break;
-        case kImm64Reference:
-          __ Move(dst, imm.reference);
+        case Constant::kInt64:
+          __ Set(dst, src.ToInt64());
           break;
-        case kImm64Handle:
-          __ Move(dst, imm.handle);
+        case Constant::kFloat32:
+          __ Move(dst,
+                  isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
+          break;
+        case Constant::kFloat64:
+          __ Move(dst,
+                  isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
+          break;
+        case Constant::kExternalReference:
+          __ Move(dst, src.ToExternalReference());
+          break;
+        case Constant::kHeapObject:
+          __ Move(dst, src.ToHeapObject());
+          break;
+        case Constant::kRpoNumber:
+          UNREACHABLE();  // TODO(dcarney): load of labels on x64.
           break;
       }
       if (destination->IsStackSlot()) {
         __ movq(g.ToOperand(destination), kScratchRegister);
       }
-    } else {
-      __ movq(kScratchRegister,
-              bit_cast<uint64_t, double>(g.ToDouble(constant_source)));
+    } else if (src.type() == Constant::kFloat32) {
+      // TODO(turbofan): Can we do better here?
+      uint32_t src_const = bit_cast<uint32_t>(src.ToFloat32());
       if (destination->IsDoubleRegister()) {
-        __ movq(g.ToDoubleRegister(destination), kScratchRegister);
+        __ Move(g.ToDoubleRegister(destination), src_const);
       } else {
         DCHECK(destination->IsDoubleStackSlot());
+        Operand dst = g.ToOperand(destination);
+        __ movl(dst, Immediate(src_const));
+      }
+    } else {
+      DCHECK_EQ(Constant::kFloat64, src.type());
+      uint64_t src_const = bit_cast<uint64_t>(src.ToFloat64());
+      if (destination->IsDoubleRegister()) {
+        __ Move(g.ToDoubleRegister(destination), src_const);
+      } else {
+        DCHECK(destination->IsDoubleStackSlot());
+        __ movq(kScratchRegister, src_const);
         __ movq(g.ToOperand(destination), kScratchRegister);
       }
     }
@@ -985,7 +1384,7 @@
     __ movsd(xmm0, src);
     __ movsd(src, dst);
     __ movsd(dst, xmm0);
-  } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) {
+  } else if (source->IsDoubleRegister() && destination->IsDoubleStackSlot()) {
     // XMM register-memory swap.  We rely on having xmm0
     // available as a fixed scratch register.
     XMMRegister src = g.ToDoubleRegister(source);
@@ -1005,7 +1404,7 @@
 
 void CodeGenerator::EnsureSpaceForLazyDeopt() {
   int space_needed = Deoptimizer::patch_size();
-  if (!linkage()->info()->IsStub()) {
+  if (!info()->IsStub()) {
     // Ensure that we have enough space after the previous lazy-bailout
     // instruction for patching the code here.
     int current_pc = masm()->pc_offset();
diff --git a/src/compiler/x64/instruction-codes-x64.h b/src/compiler/x64/instruction-codes-x64.h
index dfad203..77e3e52 100644
--- a/src/compiler/x64/instruction-codes-x64.h
+++ b/src/compiler/x64/instruction-codes-x64.h
@@ -28,6 +28,8 @@
   V(X64Sub32)                      \
   V(X64Imul)                       \
   V(X64Imul32)                     \
+  V(X64ImulHigh32)                 \
+  V(X64UmulHigh32)                 \
   V(X64Idiv)                       \
   V(X64Idiv32)                     \
   V(X64Udiv)                       \
@@ -51,10 +53,19 @@
   V(SSEFloat64Div)                 \
   V(SSEFloat64Mod)                 \
   V(SSEFloat64Sqrt)                \
+  V(SSEFloat64Floor)               \
+  V(SSEFloat64Ceil)                \
+  V(SSEFloat64RoundTruncate)       \
+  V(SSECvtss2sd)                   \
+  V(SSECvtsd2ss)                   \
   V(SSEFloat64ToInt32)             \
   V(SSEFloat64ToUint32)            \
   V(SSEInt32ToFloat64)             \
   V(SSEUint32ToFloat64)            \
+  V(AVXFloat64Add)                 \
+  V(AVXFloat64Sub)                 \
+  V(AVXFloat64Mul)                 \
+  V(AVXFloat64Div)                 \
   V(X64Movsxbl)                    \
   V(X64Movzxbl)                    \
   V(X64Movb)                       \
@@ -66,6 +77,10 @@
   V(X64Movq)                       \
   V(X64Movsd)                      \
   V(X64Movss)                      \
+  V(X64Lea32)                      \
+  V(X64Lea)                        \
+  V(X64Dec32)                      \
+  V(X64Inc32)                      \
   V(X64Push)                       \
   V(X64StoreWriteBarrier)
 
@@ -77,22 +92,30 @@
 //
 // We use the following local notation for addressing modes:
 //
-// R = register
-// O = register or stack slot
-// D = double register
-// I = immediate (handle, external, int32)
-// MR = [register]
-// MI = [immediate]
-// MRN = [register + register * N in {1, 2, 4, 8}]
-// MRI = [register + immediate]
-// MRNI = [register + register * N in {1, 2, 4, 8} + immediate]
+// M = memory operand
+// R = base register
+// N = index register * N for N in {1, 2, 4, 8}
+// I = immediate displacement (32-bit signed integer)
+
 #define TARGET_ADDRESSING_MODE_LIST(V) \
-  V(MR)   /* [%r1] */                  \
-  V(MRI)  /* [%r1 + K] */              \
-  V(MR1I) /* [%r1 + %r2 + K] */        \
+  V(MR)   /* [%r1            ] */      \
+  V(MRI)  /* [%r1         + K] */      \
+  V(MR1)  /* [%r1 + %r2*1    ] */      \
+  V(MR2)  /* [%r1 + %r2*2    ] */      \
+  V(MR4)  /* [%r1 + %r2*4    ] */      \
+  V(MR8)  /* [%r1 + %r2*8    ] */      \
+  V(MR1I) /* [%r1 + %r2*1 + K] */      \
   V(MR2I) /* [%r1 + %r2*2 + K] */      \
-  V(MR4I) /* [%r1 + %r2*4 + K] */      \
-  V(MR8I) /* [%r1 + %r2*8 + K] */
+  V(MR4I) /* [%r1 + %r2*3 + K] */      \
+  V(MR8I) /* [%r1 + %r2*4 + K] */      \
+  V(M1)   /* [      %r2*1    ] */      \
+  V(M2)   /* [      %r2*2    ] */      \
+  V(M4)   /* [      %r2*4    ] */      \
+  V(M8)   /* [      %r2*8    ] */      \
+  V(M1I)  /* [      %r2*1 + K] */      \
+  V(M2I)  /* [      %r2*2 + K] */      \
+  V(M4I)  /* [      %r2*4 + K] */      \
+  V(M8I)  /* [      %r2*8 + K] */
 
 }  // namespace compiler
 }  // namespace internal
diff --git a/src/compiler/x64/instruction-selector-x64-unittest.cc b/src/compiler/x64/instruction-selector-x64-unittest.cc
deleted file mode 100644
index 22f0bce..0000000
--- a/src/compiler/x64/instruction-selector-x64-unittest.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/instruction-selector-unittest.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-// -----------------------------------------------------------------------------
-// Conversions.
-
-
-TEST_F(InstructionSelectorTest, ChangeInt32ToInt64WithParameter) {
-  StreamBuilder m(this, kMachInt64, kMachInt32);
-  m.Return(m.ChangeInt32ToInt64(m.Parameter(0)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kX64Movsxlq, s[0]->arch_opcode());
-}
-
-
-TEST_F(InstructionSelectorTest, ChangeUint32ToUint64WithParameter) {
-  StreamBuilder m(this, kMachUint64, kMachUint32);
-  m.Return(m.ChangeUint32ToUint64(m.Parameter(0)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
-}
-
-
-TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithParameter) {
-  StreamBuilder m(this, kMachInt32, kMachInt64);
-  m.Return(m.TruncateInt64ToInt32(m.Parameter(0)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
-}
-
-
-// -----------------------------------------------------------------------------
-// Loads and stores
-
-namespace {
-
-struct MemoryAccess {
-  MachineType type;
-  ArchOpcode load_opcode;
-  ArchOpcode store_opcode;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
-  OStringStream ost;
-  ost << memacc.type;
-  return os << ost.c_str();
-}
-
-
-static const MemoryAccess kMemoryAccesses[] = {
-    {kMachInt8, kX64Movsxbl, kX64Movb},
-    {kMachUint8, kX64Movzxbl, kX64Movb},
-    {kMachInt16, kX64Movsxwl, kX64Movw},
-    {kMachUint16, kX64Movzxwl, kX64Movw},
-    {kMachInt32, kX64Movl, kX64Movl},
-    {kMachUint32, kX64Movl, kX64Movl},
-    {kMachInt64, kX64Movq, kX64Movq},
-    {kMachUint64, kX64Movq, kX64Movq},
-    {kMachFloat32, kX64Movss, kX64Movss},
-    {kMachFloat64, kX64Movsd, kX64Movsd}};
-
-}  // namespace
-
-
-typedef InstructionSelectorTestWithParam<MemoryAccess>
-    InstructionSelectorMemoryAccessTest;
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
-  const MemoryAccess memacc = GetParam();
-  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
-  m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(2U, s[0]->InputCount());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
-  const MemoryAccess memacc = GetParam();
-  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
-  m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
-  m.Return(m.Int32Constant(0));
-  Stream s = m.Build();
-  ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
-  EXPECT_EQ(3U, s[0]->InputCount());
-  EXPECT_EQ(0U, s[0]->OutputCount());
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
-                        InstructionSelectorMemoryAccessTest,
-                        ::testing::ValuesIn(kMemoryAccesses));
-
-}  // namespace compiler
-}  // namespace internal
-}  // namespace v8
diff --git a/src/compiler/x64/instruction-selector-x64.cc b/src/compiler/x64/instruction-selector-x64.cc
index 5fe7bad..aba480d 100644
--- a/src/compiler/x64/instruction-selector-x64.cc
+++ b/src/compiler/x64/instruction-selector-x64.cc
@@ -20,37 +20,86 @@
                                            Register::ToAllocationIndex(reg));
   }
 
-  InstructionOperand* UseByteRegister(Node* node) {
-    // TODO(dcarney): relax constraint.
-    return UseFixed(node, rdx);
-  }
-
-  InstructionOperand* UseImmediate64(Node* node) { return UseImmediate(node); }
-
   bool CanBeImmediate(Node* node) {
     switch (node->opcode()) {
       case IrOpcode::kInt32Constant:
         return true;
+      case IrOpcode::kInt64Constant: {
+        const int64_t value = OpParameter<int64_t>(node);
+        return value == static_cast<int64_t>(static_cast<int32_t>(value));
+      }
       default:
         return false;
     }
   }
 
-  bool CanBeImmediate64(Node* node) {
-    switch (node->opcode()) {
-      case IrOpcode::kInt32Constant:
-        return true;
-      case IrOpcode::kNumberConstant:
-        return true;
-      case IrOpcode::kHeapConstant: {
-        // Constants in new space cannot be used as immediates in V8 because
-        // the GC does not scan code objects when collecting the new generation.
-        Unique<HeapObject> value = OpParameter<Unique<HeapObject> >(node);
-        return !isolate()->heap()->InNewSpace(*value.handle());
+  AddressingMode GenerateMemoryOperandInputs(Node* index, int scale_exponent,
+                                             Node* base, Node* displacement,
+                                             InstructionOperand* inputs[],
+                                             size_t* input_count) {
+    AddressingMode mode = kMode_MRI;
+    if (base != NULL) {
+      inputs[(*input_count)++] = UseRegister(base);
+      if (index != NULL) {
+        DCHECK(scale_exponent >= 0 && scale_exponent <= 3);
+        inputs[(*input_count)++] = UseRegister(index);
+        if (displacement != NULL) {
+          inputs[(*input_count)++] = UseImmediate(displacement);
+          static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I,
+                                                       kMode_MR4I, kMode_MR8I};
+          mode = kMRnI_modes[scale_exponent];
+        } else {
+          static const AddressingMode kMRn_modes[] = {kMode_MR1, kMode_MR2,
+                                                      kMode_MR4, kMode_MR8};
+          mode = kMRn_modes[scale_exponent];
+        }
+      } else {
+        if (displacement == NULL) {
+          mode = kMode_MR;
+        } else {
+          inputs[(*input_count)++] = UseImmediate(displacement);
+          mode = kMode_MRI;
+        }
       }
-      default:
-        return false;
+    } else {
+      DCHECK(index != NULL);
+      DCHECK(scale_exponent >= 0 && scale_exponent <= 3);
+      inputs[(*input_count)++] = UseRegister(index);
+      if (displacement != NULL) {
+        inputs[(*input_count)++] = UseImmediate(displacement);
+        static const AddressingMode kMnI_modes[] = {kMode_MRI, kMode_M2I,
+                                                    kMode_M4I, kMode_M8I};
+        mode = kMnI_modes[scale_exponent];
+      } else {
+        static const AddressingMode kMn_modes[] = {kMode_MR, kMode_MR1,
+                                                   kMode_M4, kMode_M8};
+        mode = kMn_modes[scale_exponent];
+        if (mode == kMode_MR1) {
+          // [%r1 + %r1*1] has a smaller encoding than [%r1*2+0]
+          inputs[(*input_count)++] = UseRegister(index);
+        }
+      }
     }
+    return mode;
+  }
+
+  AddressingMode GetEffectiveAddressMemoryOperand(Node* operand,
+                                                  InstructionOperand* inputs[],
+                                                  size_t* input_count) {
+    BaseWithIndexAndDisplacement64Matcher m(operand, true);
+    DCHECK(m.matches());
+    if ((m.displacement() == NULL || CanBeImmediate(m.displacement()))) {
+      return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(),
+                                         m.displacement(), inputs, input_count);
+    } else {
+      inputs[(*input_count)++] = UseRegister(operand->InputAt(0));
+      inputs[(*input_count)++] = UseRegister(operand->InputAt(1));
+      return kMode_MR1;
+    }
+  }
+
+  bool CanBeBetterLeftOperand(Node* node) const {
+    return !selector()->IsLive(node);
   }
 };
 
@@ -59,11 +108,8 @@
   MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
   MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
   X64OperandGenerator g(this);
-  Node* base = node->InputAt(0);
-  Node* index = node->InputAt(1);
 
   ArchOpcode opcode;
-  // TODO(titzer): signed/unsigned small loads
   switch (rep) {
     case kRepFloat32:
       opcode = kX64Movss;
@@ -89,18 +135,15 @@
       UNREACHABLE();
       return;
   }
-  if (g.CanBeImmediate(base)) {
-    // load [#base + %index]
-    Emit(opcode | AddressingModeField::encode(kMode_MRI),
-         g.DefineAsRegister(node), g.UseRegister(index), g.UseImmediate(base));
-  } else if (g.CanBeImmediate(index)) {  // load [%base + #index]
-    Emit(opcode | AddressingModeField::encode(kMode_MRI),
-         g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
-  } else {  // load [%base + %index + K]
-    Emit(opcode | AddressingModeField::encode(kMode_MR1I),
-         g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
-  }
-  // TODO(turbofan): addressing modes [r+r*{2,4,8}+K]
+
+  InstructionOperand* outputs[1];
+  outputs[0] = g.DefineAsRegister(node);
+  InstructionOperand* inputs[3];
+  size_t input_count = 0;
+  AddressingMode mode =
+      g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
+  InstructionCode code = opcode | AddressingModeField::encode(mode);
+  Emit(code, 1, outputs, input_count, inputs);
 }
 
 
@@ -124,14 +167,6 @@
     return;
   }
   DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
-  InstructionOperand* val;
-  if (g.CanBeImmediate(value)) {
-    val = g.UseImmediate(value);
-  } else if (rep == kRepWord8 || rep == kRepBit) {
-    val = g.UseByteRegister(value);
-  } else {
-    val = g.UseRegister(value);
-  }
   ArchOpcode opcode;
   switch (rep) {
     case kRepFloat32:
@@ -158,18 +193,112 @@
       UNREACHABLE();
       return;
   }
-  if (g.CanBeImmediate(base)) {
-    // store [#base + %index], %|#value
-    Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
-         g.UseRegister(index), g.UseImmediate(base), val);
-  } else if (g.CanBeImmediate(index)) {  // store [%base + #index], %|#value
-    Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
-         g.UseRegister(base), g.UseImmediate(index), val);
-  } else {  // store [%base + %index], %|#value
-    Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL,
-         g.UseRegister(base), g.UseRegister(index), val);
+  InstructionOperand* inputs[4];
+  size_t input_count = 0;
+  AddressingMode mode =
+      g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count);
+  InstructionCode code = opcode | AddressingModeField::encode(mode);
+  InstructionOperand* value_operand =
+      g.CanBeImmediate(value) ? g.UseImmediate(value) : g.UseRegister(value);
+  inputs[input_count++] = value_operand;
+  Emit(code, 0, static_cast<InstructionOperand**>(NULL), input_count, inputs);
+}
+
+
+void InstructionSelector::VisitCheckedLoad(Node* node) {
+  MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+  MachineType typ = TypeOf(OpParameter<MachineType>(node));
+  X64OperandGenerator g(this);
+  Node* const buffer = node->InputAt(0);
+  Node* const offset = node->InputAt(1);
+  Node* const length = node->InputAt(2);
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepWord8:
+      opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8;
+      break;
+    case kRepWord16:
+      opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16;
+      break;
+    case kRepWord32:
+      opcode = kCheckedLoadWord32;
+      break;
+    case kRepFloat32:
+      opcode = kCheckedLoadFloat32;
+      break;
+    case kRepFloat64:
+      opcode = kCheckedLoadFloat64;
+      break;
+    default:
+      UNREACHABLE();
+      return;
   }
-  // TODO(turbofan): addressing modes [r+r*{2,4,8}+K]
+  if (offset->opcode() == IrOpcode::kInt32Add && CanCover(node, offset)) {
+    Int32Matcher mlength(length);
+    Int32BinopMatcher moffset(offset);
+    if (mlength.HasValue() && moffset.right().HasValue() &&
+        moffset.right().Value() >= 0 &&
+        mlength.Value() >= moffset.right().Value()) {
+      Emit(opcode, g.DefineAsRegister(node), g.UseRegister(buffer),
+           g.UseRegister(moffset.left().node()),
+           g.UseImmediate(moffset.right().node()), g.UseImmediate(length));
+      return;
+    }
+  }
+  InstructionOperand* length_operand =
+      g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
+  Emit(opcode, g.DefineAsRegister(node), g.UseRegister(buffer),
+       g.UseRegister(offset), g.TempImmediate(0), length_operand);
+}
+
+
+void InstructionSelector::VisitCheckedStore(Node* node) {
+  MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+  X64OperandGenerator g(this);
+  Node* const buffer = node->InputAt(0);
+  Node* const offset = node->InputAt(1);
+  Node* const length = node->InputAt(2);
+  Node* const value = node->InputAt(3);
+  ArchOpcode opcode;
+  switch (rep) {
+    case kRepWord8:
+      opcode = kCheckedStoreWord8;
+      break;
+    case kRepWord16:
+      opcode = kCheckedStoreWord16;
+      break;
+    case kRepWord32:
+      opcode = kCheckedStoreWord32;
+      break;
+    case kRepFloat32:
+      opcode = kCheckedStoreFloat32;
+      break;
+    case kRepFloat64:
+      opcode = kCheckedStoreFloat64;
+      break;
+    default:
+      UNREACHABLE();
+      return;
+  }
+  InstructionOperand* value_operand =
+      g.CanBeImmediate(value) ? g.UseImmediate(value) : g.UseRegister(value);
+  if (offset->opcode() == IrOpcode::kInt32Add && CanCover(node, offset)) {
+    Int32Matcher mlength(length);
+    Int32BinopMatcher moffset(offset);
+    if (mlength.HasValue() && moffset.right().HasValue() &&
+        moffset.right().Value() >= 0 &&
+        mlength.Value() >= moffset.right().Value()) {
+      Emit(opcode, nullptr, g.UseRegister(buffer),
+           g.UseRegister(moffset.left().node()),
+           g.UseImmediate(moffset.right().node()), g.UseImmediate(length),
+           value_operand);
+      return;
+    }
+  }
+  InstructionOperand* length_operand =
+      g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length);
+  Emit(opcode, nullptr, g.UseRegister(buffer), g.UseRegister(offset),
+       g.TempImmediate(0), length_operand, value_operand);
 }
 
 
@@ -178,20 +307,35 @@
                        InstructionCode opcode, FlagsContinuation* cont) {
   X64OperandGenerator g(selector);
   Int32BinopMatcher m(node);
+  Node* left = m.left().node();
+  Node* right = m.right().node();
   InstructionOperand* inputs[4];
   size_t input_count = 0;
   InstructionOperand* outputs[2];
   size_t output_count = 0;
 
   // TODO(turbofan): match complex addressing modes.
-  // TODO(turbofan): if commutative, pick the non-live-in operand as the left as
-  // this might be the last use and therefore its register can be reused.
-  if (g.CanBeImmediate(m.right().node())) {
-    inputs[input_count++] = g.Use(m.left().node());
-    inputs[input_count++] = g.UseImmediate(m.right().node());
+  if (left == right) {
+    // If both inputs refer to the same operand, enforce allocating a register
+    // for both of them to ensure that we don't end up generating code like
+    // this:
+    //
+    //   mov rax, [rbp-0x10]
+    //   add rax, [rbp-0x10]
+    //   jo label
+    InstructionOperand* const input = g.UseRegister(left);
+    inputs[input_count++] = input;
+    inputs[input_count++] = input;
+  } else if (g.CanBeImmediate(right)) {
+    inputs[input_count++] = g.UseRegister(left);
+    inputs[input_count++] = g.UseImmediate(right);
   } else {
-    inputs[input_count++] = g.UseRegister(m.left().node());
-    inputs[input_count++] = g.Use(m.right().node());
+    if (node->op()->HasProperty(Operator::kCommutative) &&
+        g.CanBeBetterLeftOperand(right)) {
+      std::swap(left, right);
+    }
+    inputs[input_count++] = g.UseRegister(left);
+    inputs[input_count++] = g.Use(right);
   }
 
   if (cont->IsBranch()) {
@@ -204,8 +348,8 @@
     outputs[output_count++] = g.DefineAsRegister(cont->result());
   }
 
-  DCHECK_NE(0, input_count);
-  DCHECK_NE(0, output_count);
+  DCHECK_NE(0, static_cast<int>(input_count));
+  DCHECK_NE(0, static_cast<int>(output_count));
   DCHECK_GE(arraysize(inputs), input_count);
   DCHECK_GE(arraysize(outputs), output_count);
 
@@ -247,7 +391,7 @@
   X64OperandGenerator g(this);
   Uint32BinopMatcher m(node);
   if (m.right().Is(-1)) {
-    Emit(kX64Not32, g.DefineSameAsFirst(node), g.Use(m.left().node()));
+    Emit(kX64Not32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()));
   } else {
     VisitBinop(this, node, kX64Xor32);
   }
@@ -258,33 +402,28 @@
   X64OperandGenerator g(this);
   Uint64BinopMatcher m(node);
   if (m.right().Is(-1)) {
-    Emit(kX64Not, g.DefineSameAsFirst(node), g.Use(m.left().node()));
+    Emit(kX64Not, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()));
   } else {
     VisitBinop(this, node, kX64Xor);
   }
 }
 
 
+namespace {
+
 // Shared routine for multiple 32-bit shift operations.
 // TODO(bmeurer): Merge this with VisitWord64Shift using template magic?
-static void VisitWord32Shift(InstructionSelector* selector, Node* node,
-                             ArchOpcode opcode) {
+void VisitWord32Shift(InstructionSelector* selector, Node* node,
+                      ArchOpcode opcode) {
   X64OperandGenerator g(selector);
-  Node* left = node->InputAt(0);
-  Node* right = node->InputAt(1);
+  Int32BinopMatcher m(node);
+  Node* left = m.left().node();
+  Node* right = m.right().node();
 
-  // TODO(turbofan): assembler only supports some addressing modes for shifts.
   if (g.CanBeImmediate(right)) {
     selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
                    g.UseImmediate(right));
   } else {
-    Int32BinopMatcher m(node);
-    if (m.right().IsWord32And()) {
-      Int32BinopMatcher mright(right);
-      if (mright.right().Is(0x1F)) {
-        right = mright.left().node();
-      }
-    }
     selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
                    g.UseFixed(right, rcx));
   }
@@ -293,18 +432,17 @@
 
 // Shared routine for multiple 64-bit shift operations.
 // TODO(bmeurer): Merge this with VisitWord32Shift using template magic?
-static void VisitWord64Shift(InstructionSelector* selector, Node* node,
-                             ArchOpcode opcode) {
+void VisitWord64Shift(InstructionSelector* selector, Node* node,
+                      ArchOpcode opcode) {
   X64OperandGenerator g(selector);
-  Node* left = node->InputAt(0);
-  Node* right = node->InputAt(1);
+  Int64BinopMatcher m(node);
+  Node* left = m.left().node();
+  Node* right = m.right().node();
 
-  // TODO(turbofan): assembler only supports some addressing modes for shifts.
   if (g.CanBeImmediate(right)) {
     selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
                    g.UseImmediate(right));
   } else {
-    Int64BinopMatcher m(node);
     if (m.right().IsWord64And()) {
       Int64BinopMatcher mright(right);
       if (mright.right().Is(0x3F)) {
@@ -317,12 +455,54 @@
 }
 
 
+void EmitLea(InstructionSelector* selector, InstructionCode opcode,
+             Node* result, Node* index, int scale, Node* base,
+             Node* displacement) {
+  X64OperandGenerator g(selector);
+
+  InstructionOperand* inputs[4];
+  size_t input_count = 0;
+  AddressingMode mode = g.GenerateMemoryOperandInputs(
+      index, scale, base, displacement, inputs, &input_count);
+
+  DCHECK_NE(0, static_cast<int>(input_count));
+  DCHECK_GE(arraysize(inputs), input_count);
+
+  InstructionOperand* outputs[1];
+  outputs[0] = g.DefineAsRegister(result);
+
+  opcode = AddressingModeField::encode(mode) | opcode;
+
+  selector->Emit(opcode, 1, outputs, input_count, inputs);
+}
+
+}  // namespace
+
+
 void InstructionSelector::VisitWord32Shl(Node* node) {
+  Int32ScaleMatcher m(node, true);
+  if (m.matches()) {
+    Node* index = node->InputAt(0);
+    Node* base = m.power_of_two_plus_one() ? index : NULL;
+    EmitLea(this, kX64Lea32, node, index, m.scale(), base, NULL);
+    return;
+  }
   VisitWord32Shift(this, node, kX64Shl32);
 }
 
 
 void InstructionSelector::VisitWord64Shl(Node* node) {
+  X64OperandGenerator g(this);
+  Int64BinopMatcher m(node);
+  if ((m.left().IsChangeInt32ToInt64() || m.left().IsChangeUint32ToUint64()) &&
+      m.right().IsInRange(32, 63)) {
+    // There's no need to sign/zero-extend to 64-bit if we shift out the upper
+    // 32 bits anyway.
+    Emit(kX64Shl, g.DefineSameAsFirst(node),
+         g.UseRegister(m.left().node()->InputAt(0)),
+         g.UseImmediate(m.right().node()));
+    return;
+  }
   VisitWord64Shift(this, node, kX64Shl);
 }
 
@@ -338,6 +518,18 @@
 
 
 void InstructionSelector::VisitWord32Sar(Node* node) {
+  X64OperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  if (CanCover(m.node(), m.left().node()) && m.left().IsWord32Shl()) {
+    Int32BinopMatcher mleft(m.left().node());
+    if (mleft.right().Is(16) && m.right().Is(16)) {
+      Emit(kX64Movsxwl, g.DefineAsRegister(node), g.Use(mleft.left().node()));
+      return;
+    } else if (mleft.right().Is(24) && m.right().Is(24)) {
+      Emit(kX64Movsxbl, g.DefineAsRegister(node), g.Use(mleft.left().node()));
+      return;
+    }
+  }
   VisitWord32Shift(this, node, kX64Sar32);
 }
 
@@ -358,6 +550,18 @@
 
 
 void InstructionSelector::VisitInt32Add(Node* node) {
+  X64OperandGenerator g(this);
+
+  // Try to match the Add to a leal pattern
+  BaseWithIndexAndDisplacement32Matcher m(node);
+  if (m.matches() &&
+      (m.displacement() == NULL || g.CanBeImmediate(m.displacement()))) {
+    EmitLea(this, kX64Lea32, node, m.index(), m.scale(), m.base(),
+            m.displacement());
+    return;
+  }
+
+  // No leal pattern match, use addl
   VisitBinop(this, node, kX64Add32);
 }
 
@@ -371,8 +575,16 @@
   X64OperandGenerator g(this);
   Int32BinopMatcher m(node);
   if (m.left().Is(0)) {
-    Emit(kX64Neg32, g.DefineSameAsFirst(node), g.Use(m.right().node()));
+    Emit(kX64Neg32, g.DefineSameAsFirst(node), g.UseRegister(m.right().node()));
   } else {
+    if (m.right().HasValue() && g.CanBeImmediate(m.right().node())) {
+      // Turn subtractions of constant values into immediate "leal" instructions
+      // by negating the value.
+      Emit(kX64Lea32 | AddressingModeField::encode(kMode_MRI),
+           g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+           g.TempImmediate(-m.right().Value()));
+      return;
+    }
     VisitBinop(this, node, kX64Sub32);
   }
 }
@@ -382,33 +594,75 @@
   X64OperandGenerator g(this);
   Int64BinopMatcher m(node);
   if (m.left().Is(0)) {
-    Emit(kX64Neg, g.DefineSameAsFirst(node), g.Use(m.right().node()));
+    Emit(kX64Neg, g.DefineSameAsFirst(node), g.UseRegister(m.right().node()));
   } else {
     VisitBinop(this, node, kX64Sub);
   }
 }
 
 
-static void VisitMul(InstructionSelector* selector, Node* node,
-                     ArchOpcode opcode) {
+namespace {
+
+void VisitMul(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
   X64OperandGenerator g(selector);
-  Node* left = node->InputAt(0);
-  Node* right = node->InputAt(1);
+  Int32BinopMatcher m(node);
+  Node* left = m.left().node();
+  Node* right = m.right().node();
   if (g.CanBeImmediate(right)) {
     selector->Emit(opcode, g.DefineAsRegister(node), g.Use(left),
                    g.UseImmediate(right));
-  } else if (g.CanBeImmediate(left)) {
-    selector->Emit(opcode, g.DefineAsRegister(node), g.Use(right),
-                   g.UseImmediate(left));
   } else {
-    // TODO(turbofan): select better left operand.
+    if (g.CanBeBetterLeftOperand(right)) {
+      std::swap(left, right);
+    }
     selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
                    g.Use(right));
   }
 }
 
 
+void VisitMulHigh(InstructionSelector* selector, Node* node,
+                  ArchOpcode opcode) {
+  X64OperandGenerator g(selector);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  if (selector->IsLive(left) && !selector->IsLive(right)) {
+    std::swap(left, right);
+  }
+  // TODO(turbofan): We use UseUniqueRegister here to improve register
+  // allocation.
+  selector->Emit(opcode, g.DefineAsFixed(node, rdx), g.UseFixed(left, rax),
+                 g.UseUniqueRegister(right));
+}
+
+
+void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
+  X64OperandGenerator g(selector);
+  InstructionOperand* temps[] = {g.TempRegister(rdx)};
+  selector->Emit(
+      opcode, g.DefineAsFixed(node, rax), g.UseFixed(node->InputAt(0), rax),
+      g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
+}
+
+
+void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
+  X64OperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsFixed(node, rdx),
+                 g.UseFixed(node->InputAt(0), rax),
+                 g.UseUniqueRegister(node->InputAt(1)));
+}
+
+}  // namespace
+
+
 void InstructionSelector::VisitInt32Mul(Node* node) {
+  Int32ScaleMatcher m(node, true);
+  if (m.matches()) {
+    Node* index = node->InputAt(0);
+    Node* base = m.power_of_two_plus_one() ? index : NULL;
+    EmitLea(this, kX64Lea32, node, index, m.scale(), base, NULL);
+    return;
+  }
   VisitMul(this, node, kX64Imul32);
 }
 
@@ -418,13 +672,8 @@
 }
 
 
-static void VisitDiv(InstructionSelector* selector, Node* node,
-                     ArchOpcode opcode) {
-  X64OperandGenerator g(selector);
-  InstructionOperand* temps[] = {g.TempRegister(rdx)};
-  selector->Emit(
-      opcode, g.DefineAsFixed(node, rax), g.UseFixed(node->InputAt(0), rax),
-      g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  VisitMulHigh(this, node, kX64ImulHigh32);
 }
 
 
@@ -438,26 +687,16 @@
 }
 
 
-void InstructionSelector::VisitInt32UDiv(Node* node) {
+void InstructionSelector::VisitUint32Div(Node* node) {
   VisitDiv(this, node, kX64Udiv32);
 }
 
 
-void InstructionSelector::VisitInt64UDiv(Node* node) {
+void InstructionSelector::VisitUint64Div(Node* node) {
   VisitDiv(this, node, kX64Udiv);
 }
 
 
-static void VisitMod(InstructionSelector* selector, Node* node,
-                     ArchOpcode opcode) {
-  X64OperandGenerator g(selector);
-  InstructionOperand* temps[] = {g.TempRegister(rax), g.TempRegister(rdx)};
-  selector->Emit(
-      opcode, g.DefineAsFixed(node, rdx), g.UseFixed(node->InputAt(0), rax),
-      g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
-}
-
-
 void InstructionSelector::VisitInt32Mod(Node* node) {
   VisitMod(this, node, kX64Idiv32);
 }
@@ -468,16 +707,27 @@
 }
 
 
-void InstructionSelector::VisitInt32UMod(Node* node) {
+void InstructionSelector::VisitUint32Mod(Node* node) {
   VisitMod(this, node, kX64Udiv32);
 }
 
 
-void InstructionSelector::VisitInt64UMod(Node* node) {
+void InstructionSelector::VisitUint64Mod(Node* node) {
   VisitMod(this, node, kX64Udiv);
 }
 
 
+void InstructionSelector::VisitUint32MulHigh(Node* node) {
+  VisitMulHigh(this, node, kX64UmulHigh32);
+}
+
+
+void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
+  X64OperandGenerator g(this);
+  Emit(kSSECvtss2sd, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
   X64OperandGenerator g(this);
   Emit(kSSEInt32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
@@ -486,9 +736,7 @@
 
 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
   X64OperandGenerator g(this);
-  // TODO(turbofan): X64 SSE cvtqsi2sd should support operands.
-  Emit(kSSEUint32ToFloat64, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  Emit(kSSEUint32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
 }
 
 
@@ -512,41 +760,115 @@
 
 void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
   X64OperandGenerator g(this);
-  Emit(kX64Movl, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+  Node* value = node->InputAt(0);
+  switch (value->opcode()) {
+    case IrOpcode::kWord32And:
+    case IrOpcode::kWord32Or:
+    case IrOpcode::kWord32Xor:
+    case IrOpcode::kWord32Shl:
+    case IrOpcode::kWord32Shr:
+    case IrOpcode::kWord32Sar:
+    case IrOpcode::kWord32Ror:
+    case IrOpcode::kWord32Equal:
+    case IrOpcode::kInt32Add:
+    case IrOpcode::kInt32Sub:
+    case IrOpcode::kInt32Mul:
+    case IrOpcode::kInt32MulHigh:
+    case IrOpcode::kInt32Div:
+    case IrOpcode::kInt32LessThan:
+    case IrOpcode::kInt32LessThanOrEqual:
+    case IrOpcode::kInt32Mod:
+    case IrOpcode::kUint32Div:
+    case IrOpcode::kUint32LessThan:
+    case IrOpcode::kUint32LessThanOrEqual:
+    case IrOpcode::kUint32Mod:
+    case IrOpcode::kUint32MulHigh: {
+      // These 32-bit operations implicitly zero-extend to 64-bit on x64, so the
+      // zero-extension is a no-op.
+      Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
+      return;
+    }
+    default:
+      break;
+  }
+  Emit(kX64Movl, g.DefineAsRegister(node), g.Use(value));
+}
+
+
+void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
+  X64OperandGenerator g(this);
+  Emit(kSSECvtsd2ss, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
 }
 
 
 void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
   X64OperandGenerator g(this);
-  Emit(kX64Movl, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+  Node* value = node->InputAt(0);
+  if (CanCover(node, value)) {
+    switch (value->opcode()) {
+      case IrOpcode::kWord64Sar:
+      case IrOpcode::kWord64Shr: {
+        Int64BinopMatcher m(value);
+        if (m.right().Is(32)) {
+          Emit(kX64Shr, g.DefineSameAsFirst(node),
+               g.UseRegister(m.left().node()), g.TempImmediate(32));
+          return;
+        }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  Emit(kX64Movl, g.DefineAsRegister(node), g.Use(value));
 }
 
 
 void InstructionSelector::VisitFloat64Add(Node* node) {
   X64OperandGenerator g(this);
-  Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
-       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
+  if (IsSupported(AVX)) {
+    Emit(kAVXFloat64Add, g.DefineAsRegister(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  } else {
+    Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  }
 }
 
 
 void InstructionSelector::VisitFloat64Sub(Node* node) {
   X64OperandGenerator g(this);
-  Emit(kSSEFloat64Sub, g.DefineSameAsFirst(node),
-       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
+  if (IsSupported(AVX)) {
+    Emit(kAVXFloat64Sub, g.DefineAsRegister(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  } else {
+    Emit(kSSEFloat64Sub, g.DefineSameAsFirst(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  }
 }
 
 
 void InstructionSelector::VisitFloat64Mul(Node* node) {
   X64OperandGenerator g(this);
-  Emit(kSSEFloat64Mul, g.DefineSameAsFirst(node),
-       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
+  if (IsSupported(AVX)) {
+    Emit(kAVXFloat64Mul, g.DefineAsRegister(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  } else {
+    Emit(kSSEFloat64Mul, g.DefineSameAsFirst(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  }
 }
 
 
 void InstructionSelector::VisitFloat64Div(Node* node) {
   X64OperandGenerator g(this);
-  Emit(kSSEFloat64Div, g.DefineSameAsFirst(node),
-       g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
+  if (IsSupported(AVX)) {
+    Emit(kAVXFloat64Div, g.DefineAsRegister(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  } else {
+    Emit(kSSEFloat64Div, g.DefineSameAsFirst(node),
+         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+  }
 }
 
 
@@ -565,123 +887,56 @@
 }
 
 
-void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
-                                                    FlagsContinuation* cont) {
-  VisitBinop(this, node, kX64Add32, cont);
-}
+namespace {
 
-
-void InstructionSelector::VisitInt32SubWithOverflow(Node* node,
-                                                    FlagsContinuation* cont) {
-  VisitBinop(this, node, kX64Sub32, cont);
-}
-
-
-// Shared routine for multiple compare operations.
-static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
-                         InstructionOperand* left, InstructionOperand* right,
-                         FlagsContinuation* cont) {
+void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
+                    Node* node) {
   X64OperandGenerator g(selector);
-  opcode = cont->Encode(opcode);
-  if (cont->IsBranch()) {
-    selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
-                   g.Label(cont->false_block()))->MarkAsControl();
-  } else {
-    DCHECK(cont->IsSet());
-    selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
-  }
+  selector->Emit(opcode, g.DefineAsRegister(node),
+                 g.UseRegister(node->InputAt(0)));
+}
+
+}  // namespace
+
+
+void InstructionSelector::VisitFloat64Floor(Node* node) {
+  DCHECK(CpuFeatures::IsSupported(SSE4_1));
+  VisitRRFloat64(this, kSSEFloat64Floor, node);
 }
 
 
-// Shared routine for multiple word compare operations.
-static void VisitWordCompare(InstructionSelector* selector, Node* node,
-                             InstructionCode opcode, FlagsContinuation* cont,
-                             bool commutative) {
-  X64OperandGenerator g(selector);
-  Node* left = node->InputAt(0);
-  Node* right = node->InputAt(1);
-
-  // Match immediates on left or right side of comparison.
-  if (g.CanBeImmediate(right)) {
-    VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont);
-  } else if (g.CanBeImmediate(left)) {
-    if (!commutative) cont->Commute();
-    VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont);
-  } else {
-    VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
-  }
+void InstructionSelector::VisitFloat64Ceil(Node* node) {
+  DCHECK(CpuFeatures::IsSupported(SSE4_1));
+  VisitRRFloat64(this, kSSEFloat64Ceil, node);
 }
 
 
-void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) {
-  switch (node->opcode()) {
-    case IrOpcode::kInt32Sub:
-      return VisitWordCompare(this, node, kX64Cmp32, cont, false);
-    case IrOpcode::kWord32And:
-      return VisitWordCompare(this, node, kX64Test32, cont, true);
-    default:
-      break;
-  }
+void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
+  DCHECK(CpuFeatures::IsSupported(SSE4_1));
+  VisitRRFloat64(this, kSSEFloat64RoundTruncate, node);
+}
 
+
+void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
+  UNREACHABLE();
+}
+
+
+void InstructionSelector::VisitCall(Node* node) {
   X64OperandGenerator g(this);
-  VisitCompare(this, kX64Test32, g.Use(node), g.TempImmediate(-1), cont);
-}
-
-
-void InstructionSelector::VisitWord64Test(Node* node, FlagsContinuation* cont) {
-  switch (node->opcode()) {
-    case IrOpcode::kInt64Sub:
-      return VisitWordCompare(this, node, kX64Cmp, cont, false);
-    case IrOpcode::kWord64And:
-      return VisitWordCompare(this, node, kX64Test, cont, true);
-    default:
-      break;
-  }
-
-  X64OperandGenerator g(this);
-  VisitCompare(this, kX64Test, g.Use(node), g.TempImmediate(-1), cont);
-}
-
-
-void InstructionSelector::VisitWord32Compare(Node* node,
-                                             FlagsContinuation* cont) {
-  VisitWordCompare(this, node, kX64Cmp32, cont, false);
-}
-
-
-void InstructionSelector::VisitWord64Compare(Node* node,
-                                             FlagsContinuation* cont) {
-  VisitWordCompare(this, node, kX64Cmp, cont, false);
-}
-
-
-void InstructionSelector::VisitFloat64Compare(Node* node,
-                                              FlagsContinuation* cont) {
-  X64OperandGenerator g(this);
-  Node* left = node->InputAt(0);
-  Node* right = node->InputAt(1);
-  VisitCompare(this, kSSEFloat64Cmp, g.UseRegister(left), g.Use(right), cont);
-}
-
-
-void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
-                                    BasicBlock* deoptimization) {
-  X64OperandGenerator g(this);
-  CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call);
+  const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
 
   FrameStateDescriptor* frame_state_descriptor = NULL;
   if (descriptor->NeedsFrameState()) {
     frame_state_descriptor = GetFrameStateDescriptor(
-        call->InputAt(static_cast<int>(descriptor->InputCount())));
+        node->InputAt(static_cast<int>(descriptor->InputCount())));
   }
 
   CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
 
   // Compute InstructionOperands for inputs and outputs.
-  InitializeCallBuffer(call, &buffer, true, true);
+  InitializeCallBuffer(node, &buffer, true, true);
 
-  // TODO(dcarney): stack alignment for c calls.
-  // TODO(dcarney): shadow space on window for c calls.
   // Push any stack arguments.
   for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
        input != buffer.pushed_nodes.rend(); input++) {
@@ -707,17 +962,358 @@
   opcode |= MiscField::encode(descriptor->flags());
 
   // Emit the call instruction.
+  InstructionOperand** first_output =
+      buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL;
   Instruction* call_instr =
-      Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(),
+      Emit(opcode, buffer.outputs.size(), first_output,
            buffer.instruction_args.size(), &buffer.instruction_args.front());
-
   call_instr->MarkAsCall();
-  if (deoptimization != NULL) {
-    DCHECK(continuation != NULL);
-    call_instr->MarkAsControl();
+}
+
+
+// Shared routine for multiple compare operations.
+static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
+                         InstructionOperand* left, InstructionOperand* right,
+                         FlagsContinuation* cont) {
+  X64OperandGenerator g(selector);
+  opcode = cont->Encode(opcode);
+  if (cont->IsBranch()) {
+    selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
+                   g.Label(cont->false_block()))->MarkAsControl();
+  } else {
+    DCHECK(cont->IsSet());
+    selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
   }
 }
 
+
+// Shared routine for multiple compare operations.
+static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
+                         Node* left, Node* right, FlagsContinuation* cont,
+                         bool commutative) {
+  X64OperandGenerator g(selector);
+  if (commutative && g.CanBeBetterLeftOperand(right)) {
+    std::swap(left, right);
+  }
+  VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
+}
+
+
+// Shared routine for multiple word compare operations.
+static void VisitWordCompare(InstructionSelector* selector, Node* node,
+                             InstructionCode opcode, FlagsContinuation* cont) {
+  X64OperandGenerator g(selector);
+  Node* const left = node->InputAt(0);
+  Node* const right = node->InputAt(1);
+
+  // Match immediates on left or right side of comparison.
+  if (g.CanBeImmediate(right)) {
+    VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont);
+  } else if (g.CanBeImmediate(left)) {
+    if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
+    VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont);
+  } else {
+    VisitCompare(selector, opcode, left, right, cont,
+                 node->op()->HasProperty(Operator::kCommutative));
+  }
+}
+
+
+// Shared routine for comparison with zero.
+static void VisitCompareZero(InstructionSelector* selector, Node* node,
+                             InstructionCode opcode, FlagsContinuation* cont) {
+  X64OperandGenerator g(selector);
+  VisitCompare(selector, opcode, g.Use(node), g.TempImmediate(0), cont);
+}
+
+
+// Shared routine for multiple float64 compare operations.
+static void VisitFloat64Compare(InstructionSelector* selector, Node* node,
+                                FlagsContinuation* cont) {
+  VisitCompare(selector, kSSEFloat64Cmp, node->InputAt(0), node->InputAt(1),
+               cont, node->op()->HasProperty(Operator::kCommutative));
+}
+
+
+void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
+                                      BasicBlock* fbranch) {
+  X64OperandGenerator g(this);
+  Node* user = branch;
+  Node* value = branch->InputAt(0);
+
+  FlagsContinuation cont(kNotEqual, tbranch, fbranch);
+
+  // Try to combine with comparisons against 0 by simply inverting the branch.
+  while (CanCover(user, value)) {
+    if (value->opcode() == IrOpcode::kWord32Equal) {
+      Int32BinopMatcher m(value);
+      if (m.right().Is(0)) {
+        user = value;
+        value = m.left().node();
+        cont.Negate();
+      } else {
+        break;
+      }
+    } else if (value->opcode() == IrOpcode::kWord64Equal) {
+      Int64BinopMatcher m(value);
+      if (m.right().Is(0)) {
+        user = value;
+        value = m.left().node();
+        cont.Negate();
+      } else {
+        break;
+      }
+    } else {
+      break;
+    }
+  }
+
+  // Try to combine the branch with a comparison.
+  if (CanCover(user, value)) {
+    switch (value->opcode()) {
+      case IrOpcode::kWord32Equal:
+        cont.OverwriteAndNegateIfEqual(kEqual);
+        return VisitWordCompare(this, value, kX64Cmp32, &cont);
+      case IrOpcode::kInt32LessThan:
+        cont.OverwriteAndNegateIfEqual(kSignedLessThan);
+        return VisitWordCompare(this, value, kX64Cmp32, &cont);
+      case IrOpcode::kInt32LessThanOrEqual:
+        cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
+        return VisitWordCompare(this, value, kX64Cmp32, &cont);
+      case IrOpcode::kUint32LessThan:
+        cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
+        return VisitWordCompare(this, value, kX64Cmp32, &cont);
+      case IrOpcode::kUint32LessThanOrEqual:
+        cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
+        return VisitWordCompare(this, value, kX64Cmp32, &cont);
+      case IrOpcode::kWord64Equal:
+        cont.OverwriteAndNegateIfEqual(kEqual);
+        return VisitWordCompare(this, value, kX64Cmp, &cont);
+      case IrOpcode::kInt64LessThan:
+        cont.OverwriteAndNegateIfEqual(kSignedLessThan);
+        return VisitWordCompare(this, value, kX64Cmp, &cont);
+      case IrOpcode::kInt64LessThanOrEqual:
+        cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
+        return VisitWordCompare(this, value, kX64Cmp, &cont);
+      case IrOpcode::kUint64LessThan:
+        cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
+        return VisitWordCompare(this, value, kX64Cmp, &cont);
+      case IrOpcode::kFloat64Equal:
+        cont.OverwriteAndNegateIfEqual(kUnorderedEqual);
+        return VisitFloat64Compare(this, value, &cont);
+      case IrOpcode::kFloat64LessThan:
+        cont.OverwriteAndNegateIfEqual(kUnorderedLessThan);
+        return VisitFloat64Compare(this, value, &cont);
+      case IrOpcode::kFloat64LessThanOrEqual:
+        cont.OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual);
+        return VisitFloat64Compare(this, value, &cont);
+      case IrOpcode::kProjection:
+        // Check if this is the overflow output projection of an
+        // <Operation>WithOverflow node.
+        if (OpParameter<size_t>(value) == 1u) {
+          // We cannot combine the <Operation>WithOverflow with this branch
+          // unless the 0th projection (the use of the actual value of the
+          // <Operation> is either NULL, which means there's no use of the
+          // actual value, or was already defined, which means it is scheduled
+          // *AFTER* this branch).
+          Node* node = value->InputAt(0);
+          Node* result = node->FindProjection(0);
+          if (result == NULL || IsDefined(result)) {
+            switch (node->opcode()) {
+              case IrOpcode::kInt32AddWithOverflow:
+                cont.OverwriteAndNegateIfEqual(kOverflow);
+                return VisitBinop(this, node, kX64Add32, &cont);
+              case IrOpcode::kInt32SubWithOverflow:
+                cont.OverwriteAndNegateIfEqual(kOverflow);
+                return VisitBinop(this, node, kX64Sub32, &cont);
+              default:
+                break;
+            }
+          }
+        }
+        break;
+      case IrOpcode::kInt32Sub:
+        return VisitWordCompare(this, value, kX64Cmp32, &cont);
+      case IrOpcode::kInt64Sub:
+        return VisitWordCompare(this, value, kX64Cmp, &cont);
+      case IrOpcode::kWord32And:
+        return VisitWordCompare(this, value, kX64Test32, &cont);
+      case IrOpcode::kWord64And:
+        return VisitWordCompare(this, value, kX64Test, &cont);
+      default:
+        break;
+    }
+  }
+
+  // Branch could not be combined with a compare, emit compare against 0.
+  VisitCompareZero(this, value, kX64Cmp32, &cont);
+}
+
+
+void InstructionSelector::VisitWord32Equal(Node* const node) {
+  Node* user = node;
+  FlagsContinuation cont(kEqual, node);
+  Int32BinopMatcher m(user);
+  if (m.right().Is(0)) {
+    Node* value = m.left().node();
+
+    // Try to combine with comparisons against 0 by simply inverting the branch.
+    while (CanCover(user, value) && value->opcode() == IrOpcode::kWord32Equal) {
+      Int32BinopMatcher m(value);
+      if (m.right().Is(0)) {
+        user = value;
+        value = m.left().node();
+        cont.Negate();
+      } else {
+        break;
+      }
+    }
+
+    // Try to combine the branch with a comparison.
+    if (CanCover(user, value)) {
+      switch (value->opcode()) {
+        case IrOpcode::kInt32Sub:
+          return VisitWordCompare(this, value, kX64Cmp32, &cont);
+        case IrOpcode::kWord32And:
+          return VisitWordCompare(this, value, kX64Test32, &cont);
+        default:
+          break;
+      }
+    }
+    return VisitCompareZero(this, value, kX64Cmp32, &cont);
+  }
+  VisitWordCompare(this, node, kX64Cmp32, &cont);
+}
+
+
+void InstructionSelector::VisitInt32LessThan(Node* node) {
+  FlagsContinuation cont(kSignedLessThan, node);
+  VisitWordCompare(this, node, kX64Cmp32, &cont);
+}
+
+
+void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kSignedLessThanOrEqual, node);
+  VisitWordCompare(this, node, kX64Cmp32, &cont);
+}
+
+
+void InstructionSelector::VisitUint32LessThan(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThan, node);
+  VisitWordCompare(this, node, kX64Cmp32, &cont);
+}
+
+
+void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
+  VisitWordCompare(this, node, kX64Cmp32, &cont);
+}
+
+
+void InstructionSelector::VisitWord64Equal(Node* const node) {
+  Node* user = node;
+  FlagsContinuation cont(kEqual, node);
+  Int64BinopMatcher m(user);
+  if (m.right().Is(0)) {
+    Node* value = m.left().node();
+
+    // Try to combine with comparisons against 0 by simply inverting the branch.
+    while (CanCover(user, value) && value->opcode() == IrOpcode::kWord64Equal) {
+      Int64BinopMatcher m(value);
+      if (m.right().Is(0)) {
+        user = value;
+        value = m.left().node();
+        cont.Negate();
+      } else {
+        break;
+      }
+    }
+
+    // Try to combine the branch with a comparison.
+    if (CanCover(user, value)) {
+      switch (value->opcode()) {
+        case IrOpcode::kInt64Sub:
+          return VisitWordCompare(this, value, kX64Cmp, &cont);
+        case IrOpcode::kWord64And:
+          return VisitWordCompare(this, value, kX64Test, &cont);
+        default:
+          break;
+      }
+    }
+    return VisitCompareZero(this, value, kX64Cmp, &cont);
+  }
+  VisitWordCompare(this, node, kX64Cmp, &cont);
+}
+
+
+void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
+  if (Node* ovf = node->FindProjection(1)) {
+    FlagsContinuation cont(kOverflow, ovf);
+    VisitBinop(this, node, kX64Add32, &cont);
+  }
+  FlagsContinuation cont;
+  VisitBinop(this, node, kX64Add32, &cont);
+}
+
+
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+  if (Node* ovf = node->FindProjection(1)) {
+    FlagsContinuation cont(kOverflow, ovf);
+    return VisitBinop(this, node, kX64Sub32, &cont);
+  }
+  FlagsContinuation cont;
+  VisitBinop(this, node, kX64Sub32, &cont);
+}
+
+
+void InstructionSelector::VisitInt64LessThan(Node* node) {
+  FlagsContinuation cont(kSignedLessThan, node);
+  VisitWordCompare(this, node, kX64Cmp, &cont);
+}
+
+
+void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kSignedLessThanOrEqual, node);
+  VisitWordCompare(this, node, kX64Cmp, &cont);
+}
+
+
+void InstructionSelector::VisitUint64LessThan(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThan, node);
+  VisitWordCompare(this, node, kX64Cmp, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64Equal(Node* node) {
+  FlagsContinuation cont(kUnorderedEqual, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64LessThan(Node* node) {
+  FlagsContinuation cont(kUnorderedLessThan, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnorderedLessThanOrEqual, node);
+  VisitFloat64Compare(this, node, &cont);
+}
+
+
+// static
+MachineOperatorBuilder::Flags
+InstructionSelector::SupportedMachineOperatorFlags() {
+  if (CpuFeatures::IsSupported(SSE4_1)) {
+    return MachineOperatorBuilder::kFloat64Floor |
+           MachineOperatorBuilder::kFloat64Ceil |
+           MachineOperatorBuilder::kFloat64RoundTruncate |
+           MachineOperatorBuilder::kWord32ShiftIsSafe;
+  }
+  return MachineOperatorBuilder::kNoFlags;
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
diff --git a/src/compiler/x64/linkage-x64.cc b/src/compiler/x64/linkage-x64.cc
index 8175bc6..0b76cc7 100644
--- a/src/compiler/x64/linkage-x64.cc
+++ b/src/compiler/x64/linkage-x64.cc
@@ -49,8 +49,9 @@
 
 typedef LinkageHelper<X64LinkageHelperTraits> LH;
 
-CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
-  return LH::GetJSCallDescriptor(zone, parameter_count);
+CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone,
+                                             CallDescriptor::Flags flags) {
+  return LH::GetJSCallDescriptor(zone, parameter_count, flags);
 }
 
 
@@ -63,10 +64,10 @@
 
 
 CallDescriptor* Linkage::GetStubCallDescriptor(
-    CallInterfaceDescriptor descriptor, int stack_parameter_count,
-    CallDescriptor::Flags flags, Zone* zone) {
+    const CallInterfaceDescriptor& descriptor, int stack_parameter_count,
+    CallDescriptor::Flags flags, Operator::Properties properties, Zone* zone) {
   return LH::GetStubCallDescriptor(zone, descriptor, stack_parameter_count,
-                                   flags);
+                                   flags, properties);
 }
 
 
diff --git a/src/compiler/zone-pool.cc b/src/compiler/zone-pool.cc
new file mode 100644
index 0000000..179988d
--- /dev/null
+++ b/src/compiler/zone-pool.cc
@@ -0,0 +1,140 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/zone-pool.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+ZonePool::StatsScope::StatsScope(ZonePool* zone_pool)
+    : zone_pool_(zone_pool),
+      total_allocated_bytes_at_start_(zone_pool->GetTotalAllocatedBytes()),
+      max_allocated_bytes_(0) {
+  zone_pool_->stats_.push_back(this);
+  for (auto zone : zone_pool_->used_) {
+    size_t size = static_cast<size_t>(zone->allocation_size());
+    std::pair<InitialValues::iterator, bool> res =
+        initial_values_.insert(std::make_pair(zone, size));
+    USE(res);
+    DCHECK(res.second);
+  }
+}
+
+
+ZonePool::StatsScope::~StatsScope() {
+  DCHECK_EQ(zone_pool_->stats_.back(), this);
+  zone_pool_->stats_.pop_back();
+}
+
+
+size_t ZonePool::StatsScope::GetMaxAllocatedBytes() {
+  return std::max(max_allocated_bytes_, GetCurrentAllocatedBytes());
+}
+
+
+size_t ZonePool::StatsScope::GetCurrentAllocatedBytes() {
+  size_t total = 0;
+  for (Zone* zone : zone_pool_->used_) {
+    total += static_cast<size_t>(zone->allocation_size());
+    // Adjust for initial values.
+    InitialValues::iterator it = initial_values_.find(zone);
+    if (it != initial_values_.end()) {
+      total -= it->second;
+    }
+  }
+  return total;
+}
+
+
+size_t ZonePool::StatsScope::GetTotalAllocatedBytes() {
+  return zone_pool_->GetTotalAllocatedBytes() - total_allocated_bytes_at_start_;
+}
+
+
+void ZonePool::StatsScope::ZoneReturned(Zone* zone) {
+  size_t current_total = GetCurrentAllocatedBytes();
+  // Update max.
+  max_allocated_bytes_ = std::max(max_allocated_bytes_, current_total);
+  // Drop zone from initial value map.
+  InitialValues::iterator it = initial_values_.find(zone);
+  if (it != initial_values_.end()) {
+    initial_values_.erase(it);
+  }
+}
+
+
+ZonePool::ZonePool(Isolate* isolate)
+    : isolate_(isolate), max_allocated_bytes_(0), total_deleted_bytes_(0) {}
+
+
+ZonePool::~ZonePool() {
+  DCHECK(used_.empty());
+  DCHECK(stats_.empty());
+  for (Zone* zone : unused_) {
+    delete zone;
+  }
+}
+
+
+size_t ZonePool::GetMaxAllocatedBytes() {
+  return std::max(max_allocated_bytes_, GetCurrentAllocatedBytes());
+}
+
+
+size_t ZonePool::GetCurrentAllocatedBytes() {
+  size_t total = 0;
+  for (Zone* zone : used_) {
+    total += static_cast<size_t>(zone->allocation_size());
+  }
+  return total;
+}
+
+
+size_t ZonePool::GetTotalAllocatedBytes() {
+  return total_deleted_bytes_ + GetCurrentAllocatedBytes();
+}
+
+
+Zone* ZonePool::NewEmptyZone() {
+  Zone* zone;
+  // Grab a zone from pool if possible.
+  if (!unused_.empty()) {
+    zone = unused_.back();
+    unused_.pop_back();
+  } else {
+    zone = new Zone(isolate_);
+  }
+  used_.push_back(zone);
+  DCHECK_EQ(0, zone->allocation_size());
+  return zone;
+}
+
+
+void ZonePool::ReturnZone(Zone* zone) {
+  size_t current_total = GetCurrentAllocatedBytes();
+  // Update max.
+  max_allocated_bytes_ = std::max(max_allocated_bytes_, current_total);
+  // Update stats.
+  for (auto stat_scope : stats_) {
+    stat_scope->ZoneReturned(zone);
+  }
+  // Remove from used.
+  Used::iterator it = std::find(used_.begin(), used_.end(), zone);
+  DCHECK(it != used_.end());
+  used_.erase(it);
+  total_deleted_bytes_ += static_cast<size_t>(zone->allocation_size());
+  // Delete zone or clear and stash on unused_.
+  if (unused_.size() >= kMaxUnusedSize) {
+    delete zone;
+  } else {
+    zone->DeleteAll();
+    DCHECK_EQ(0, zone->allocation_size());
+    unused_.push_back(zone);
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/zone-pool.h b/src/compiler/zone-pool.h
new file mode 100644
index 0000000..8b43265
--- /dev/null
+++ b/src/compiler/zone-pool.h
@@ -0,0 +1,93 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_ZONE_POOL_H_
+#define V8_COMPILER_ZONE_POOL_H_
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "src/v8.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class ZonePool FINAL {
+ public:
+  class Scope FINAL {
+   public:
+    explicit Scope(ZonePool* zone_pool) : zone_pool_(zone_pool), zone_(NULL) {}
+    ~Scope() { Destroy(); }
+
+    Zone* zone() {
+      if (zone_ == NULL) zone_ = zone_pool_->NewEmptyZone();
+      return zone_;
+    }
+    void Destroy() {
+      if (zone_ != NULL) zone_pool_->ReturnZone(zone_);
+      zone_ = NULL;
+    }
+
+   private:
+    ZonePool* const zone_pool_;
+    Zone* zone_;
+    DISALLOW_COPY_AND_ASSIGN(Scope);
+  };
+
+  class StatsScope FINAL {
+   public:
+    explicit StatsScope(ZonePool* zone_pool);
+    ~StatsScope();
+
+    size_t GetMaxAllocatedBytes();
+    size_t GetCurrentAllocatedBytes();
+    size_t GetTotalAllocatedBytes();
+
+   private:
+    friend class ZonePool;
+    void ZoneReturned(Zone* zone);
+
+    typedef std::map<Zone*, size_t> InitialValues;
+
+    ZonePool* const zone_pool_;
+    InitialValues initial_values_;
+    size_t total_allocated_bytes_at_start_;
+    size_t max_allocated_bytes_;
+
+    DISALLOW_COPY_AND_ASSIGN(StatsScope);
+  };
+
+  explicit ZonePool(Isolate* isolate);
+  ~ZonePool();
+
+  size_t GetMaxAllocatedBytes();
+  size_t GetTotalAllocatedBytes();
+  size_t GetCurrentAllocatedBytes();
+
+ private:
+  Zone* NewEmptyZone();
+  void ReturnZone(Zone* zone);
+
+  static const size_t kMaxUnusedSize = 3;
+  typedef std::vector<Zone*> Unused;
+  typedef std::vector<Zone*> Used;
+  typedef std::vector<StatsScope*> Stats;
+
+  Isolate* const isolate_;
+  Unused unused_;
+  Used used_;
+  Stats stats_;
+  size_t max_allocated_bytes_;
+  size_t total_deleted_bytes_;
+
+  DISALLOW_COPY_AND_ASSIGN(ZonePool);
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif
diff --git a/src/contexts.cc b/src/contexts.cc
index 30c474d..57490a1 100644
--- a/src/contexts.cc
+++ b/src/contexts.cc
@@ -11,9 +11,52 @@
 namespace v8 {
 namespace internal {
 
+
+Handle<ScriptContextTable> ScriptContextTable::Extend(
+    Handle<ScriptContextTable> table, Handle<Context> script_context) {
+  Handle<ScriptContextTable> result;
+  int used = table->used();
+  int length = table->length();
+  CHECK(used >= 0 && length > 0 && used < length);
+  if (used + 1 == length) {
+    CHECK(length < Smi::kMaxValue / 2);
+    result = Handle<ScriptContextTable>::cast(
+        FixedArray::CopySize(table, length * 2));
+  } else {
+    result = table;
+  }
+  result->set_used(used + 1);
+
+  DCHECK(script_context->IsScriptContext());
+  result->set(used + 1, *script_context);
+  return result;
+}
+
+
+bool ScriptContextTable::Lookup(Handle<ScriptContextTable> table,
+                                Handle<String> name, LookupResult* result) {
+  for (int i = 0; i < table->used(); i++) {
+    Handle<Context> context = GetContext(table, i);
+    DCHECK(context->IsScriptContext());
+    Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
+    int slot_index = ScopeInfo::ContextSlotIndex(
+        scope_info, name, &result->mode, &result->init_flag,
+        &result->maybe_assigned_flag);
+
+    if (slot_index >= 0) {
+      result->context_index = i;
+      result->slot_index = slot_index;
+      return true;
+    }
+  }
+  return false;
+}
+
+
 Context* Context::declaration_context() {
   Context* current = this;
-  while (!current->IsFunctionContext() && !current->IsNativeContext()) {
+  while (!current->IsFunctionContext() && !current->IsNativeContext() &&
+         !current->IsScriptContext()) {
     current = current->previous();
     DCHECK(current->closure() == closure());
   }
@@ -32,9 +75,9 @@
 }
 
 
-Context* Context::global_context() {
+Context* Context::script_context() {
   Context* current = this;
-  while (!current->IsGlobalContext()) {
+  while (!current->IsScriptContext()) {
     current = current->previous();
   }
   return current;
@@ -82,8 +125,7 @@
   DCHECK(attrs.has_value || isolate->has_pending_exception());
   if (!attrs.has_value || attrs.value == ABSENT) return attrs;
 
-  Handle<Symbol> unscopables_symbol(
-      isolate->native_context()->unscopables_symbol(), isolate);
+  Handle<Symbol> unscopables_symbol = isolate->factory()->unscopables_symbol();
   Handle<Object> receiver = it->GetReceiver();
   Handle<Object> unscopables;
   MaybeHandle<Object> maybe_unscopables =
@@ -92,16 +134,64 @@
     return Maybe<PropertyAttributes>();
   }
   if (!unscopables->IsSpecObject()) return attrs;
-  Maybe<bool> blacklist = JSReceiver::HasProperty(
-      Handle<JSReceiver>::cast(unscopables), it->name());
-  if (!blacklist.has_value) {
+  Handle<Object> blacklist;
+  MaybeHandle<Object> maybe_blacklist =
+      Object::GetProperty(unscopables, it->name());
+  if (!maybe_blacklist.ToHandle(&blacklist)) {
     DCHECK(isolate->has_pending_exception());
     return Maybe<PropertyAttributes>();
   }
-  if (blacklist.value) return maybe(ABSENT);
+  if (!blacklist->IsUndefined()) return maybe(ABSENT);
   return attrs;
 }
 
+static void GetAttributesAndBindingFlags(VariableMode mode,
+                                         InitializationFlag init_flag,
+                                         PropertyAttributes* attributes,
+                                         BindingFlags* binding_flags) {
+  switch (mode) {
+    case INTERNAL:  // Fall through.
+    case VAR:
+      *attributes = NONE;
+      *binding_flags = MUTABLE_IS_INITIALIZED;
+      break;
+    case LET:
+      *attributes = NONE;
+      *binding_flags = (init_flag == kNeedsInitialization)
+                           ? MUTABLE_CHECK_INITIALIZED
+                           : MUTABLE_IS_INITIALIZED;
+      break;
+    case CONST_LEGACY:
+      *attributes = READ_ONLY;
+      *binding_flags = (init_flag == kNeedsInitialization)
+                           ? IMMUTABLE_CHECK_INITIALIZED
+                           : IMMUTABLE_IS_INITIALIZED;
+      break;
+    case CONST:
+      *attributes = READ_ONLY;
+      *binding_flags = (init_flag == kNeedsInitialization)
+                           ? IMMUTABLE_CHECK_INITIALIZED_HARMONY
+                           : IMMUTABLE_IS_INITIALIZED_HARMONY;
+      break;
+    case MODULE:
+      *attributes = READ_ONLY;
+      *binding_flags = IMMUTABLE_IS_INITIALIZED_HARMONY;
+      break;
+    case DYNAMIC:
+    case DYNAMIC_GLOBAL:
+    case DYNAMIC_LOCAL:
+    case TEMPORARY:
+      // Note: Fixed context slots are statically allocated by the compiler.
+      // Statically allocated variables always have a statically known mode,
+      // which is the mode with which they were declared when added to the
+      // scope. Thus, the DYNAMIC mode (which corresponds to dynamically
+      // declared variables that were introduced through declaration nodes)
+      // must not appear here.
+      UNREACHABLE();
+      break;
+  }
+}
+
 
 Handle<Object> Context::Lookup(Handle<String> name,
                                ContextLookupFlags flags,
@@ -125,16 +215,42 @@
   do {
     if (FLAG_trace_contexts) {
       PrintF(" - looking in context %p", reinterpret_cast<void*>(*context));
+      if (context->IsScriptContext()) PrintF(" (script context)");
       if (context->IsNativeContext()) PrintF(" (native context)");
       PrintF("\n");
     }
 
+
     // 1. Check global objects, subjects of with, and extension objects.
     if (context->IsNativeContext() ||
         context->IsWithContext() ||
         (context->IsFunctionContext() && context->has_extension())) {
       Handle<JSReceiver> object(
           JSReceiver::cast(context->extension()), isolate);
+
+      if (context->IsNativeContext()) {
+        if (FLAG_trace_contexts) {
+          PrintF(" - trying other script contexts\n");
+        }
+        // Try other script contexts.
+        Handle<ScriptContextTable> script_contexts(
+            context->global_object()->native_context()->script_context_table());
+        ScriptContextTable::LookupResult r;
+        if (ScriptContextTable::Lookup(script_contexts, name, &r)) {
+          if (FLAG_trace_contexts) {
+            Handle<Context> c = ScriptContextTable::GetContext(script_contexts,
+                                                               r.context_index);
+            PrintF("=> found property in script context %d: %p\n",
+                   r.context_index, reinterpret_cast<void*>(*c));
+          }
+          *index = r.slot_index;
+          GetAttributesAndBindingFlags(r.mode, r.init_flag, attributes,
+                                       binding_flags);
+          return ScriptContextTable::GetContext(script_contexts,
+                                                r.context_index);
+        }
+      }
+
       // Context extension objects needs to behave as if they have no
       // prototype.  So even if we want to follow prototype chains, we need
       // to only do a local lookup for context extension objects.
@@ -163,7 +279,8 @@
     }
 
     // 2. Check the context proper if it has slots.
-    if (context->IsFunctionContext() || context->IsBlockContext()) {
+    if (context->IsFunctionContext() || context->IsBlockContext() ||
+        (FLAG_harmony_scoping && context->IsScriptContext())) {
       // Use serialized scope information of functions and blocks to search
       // for the context index.
       Handle<ScopeInfo> scope_info;
@@ -188,45 +305,8 @@
                  slot_index, mode);
         }
         *index = slot_index;
-        // Note: Fixed context slots are statically allocated by the compiler.
-        // Statically allocated variables always have a statically known mode,
-        // which is the mode with which they were declared when added to the
-        // scope. Thus, the DYNAMIC mode (which corresponds to dynamically
-        // declared variables that were introduced through declaration nodes)
-        // must not appear here.
-        switch (mode) {
-          case INTERNAL:  // Fall through.
-          case VAR:
-            *attributes = NONE;
-            *binding_flags = MUTABLE_IS_INITIALIZED;
-            break;
-          case LET:
-            *attributes = NONE;
-            *binding_flags = (init_flag == kNeedsInitialization)
-                ? MUTABLE_CHECK_INITIALIZED : MUTABLE_IS_INITIALIZED;
-            break;
-          case CONST_LEGACY:
-            *attributes = READ_ONLY;
-            *binding_flags = (init_flag == kNeedsInitialization)
-                ? IMMUTABLE_CHECK_INITIALIZED : IMMUTABLE_IS_INITIALIZED;
-            break;
-          case CONST:
-            *attributes = READ_ONLY;
-            *binding_flags = (init_flag == kNeedsInitialization)
-                ? IMMUTABLE_CHECK_INITIALIZED_HARMONY :
-                IMMUTABLE_IS_INITIALIZED_HARMONY;
-            break;
-          case MODULE:
-            *attributes = READ_ONLY;
-            *binding_flags = IMMUTABLE_IS_INITIALIZED_HARMONY;
-            break;
-          case DYNAMIC:
-          case DYNAMIC_GLOBAL:
-          case DYNAMIC_LOCAL:
-          case TEMPORARY:
-            UNREACHABLE();
-            break;
-        }
+        GetAttributesAndBindingFlags(mode, init_flag, attributes,
+                                     binding_flags);
         return context;
       }
 
@@ -401,7 +481,7 @@
   if (child->GetIsolate()->bootstrapper()->IsActive()) return true;
   if (!object->IsContext()) return false;
   Context* context = Context::cast(object);
-  return context->IsNativeContext() || context->IsGlobalContext() ||
+  return context->IsNativeContext() || context->IsScriptContext() ||
          context->IsModuleContext() || !child->IsModuleContext();
 }
 
diff --git a/src/contexts.h b/src/contexts.h
index ac25e48..cd3ff14 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -98,28 +98,10 @@
   V(TO_INTEGER_FUN_INDEX, JSFunction, to_integer_fun)                          \
   V(TO_UINT32_FUN_INDEX, JSFunction, to_uint32_fun)                            \
   V(TO_INT32_FUN_INDEX, JSFunction, to_int32_fun)                              \
+  V(TO_LENGTH_FUN_INDEX, JSFunction, to_length_fun)                            \
   V(GLOBAL_EVAL_FUN_INDEX, JSFunction, global_eval_fun)                        \
   V(INSTANTIATE_FUN_INDEX, JSFunction, instantiate_fun)                        \
   V(CONFIGURE_INSTANCE_FUN_INDEX, JSFunction, configure_instance_fun)          \
-  V(MATH_ABS_FUN_INDEX, JSFunction, math_abs_fun)                              \
-  V(MATH_ACOS_FUN_INDEX, JSFunction, math_acos_fun)                            \
-  V(MATH_ASIN_FUN_INDEX, JSFunction, math_asin_fun)                            \
-  V(MATH_ATAN_FUN_INDEX, JSFunction, math_atan_fun)                            \
-  V(MATH_ATAN2_FUN_INDEX, JSFunction, math_atan2_fun)                          \
-  V(MATH_CEIL_FUN_INDEX, JSFunction, math_ceil_fun)                            \
-  V(MATH_COS_FUN_INDEX, JSFunction, math_cos_fun)                              \
-  V(MATH_EXP_FUN_INDEX, JSFunction, math_exp_fun)                              \
-  V(MATH_FLOOR_FUN_INDEX, JSFunction, math_floor_fun)                          \
-  V(MATH_IMUL_FUN_INDEX, JSFunction, math_imul_fun)                            \
-  V(MATH_LOG_FUN_INDEX, JSFunction, math_log_fun)                              \
-  V(MATH_MAX_FUN_INDEX, JSFunction, math_max_fun)                              \
-  V(MATH_MIN_FUN_INDEX, JSFunction, math_min_fun)                              \
-  V(MATH_POW_FUN_INDEX, JSFunction, math_pow_fun)                              \
-  V(MATH_RANDOM_FUN_INDEX, JSFunction, math_random_fun)                        \
-  V(MATH_ROUND_FUN_INDEX, JSFunction, math_round_fun)                          \
-  V(MATH_SIN_FUN_INDEX, JSFunction, math_sin_fun)                              \
-  V(MATH_SQRT_FUN_INDEX, JSFunction, math_sqrt_fun)                            \
-  V(MATH_TAN_FUN_INDEX, JSFunction, math_tan_fun)                              \
   V(ARRAY_BUFFER_FUN_INDEX, JSFunction, array_buffer_fun)                      \
   V(UINT8_ARRAY_FUN_INDEX, JSFunction, uint8_array_fun)                        \
   V(INT8_ARRAY_FUN_INDEX, JSFunction, int8_array_fun)                          \
@@ -200,9 +182,63 @@
   V(ITERATOR_RESULT_MAP_INDEX, Map, iterator_result_map)                       \
   V(MAP_ITERATOR_MAP_INDEX, Map, map_iterator_map)                             \
   V(SET_ITERATOR_MAP_INDEX, Map, set_iterator_map)                             \
-  V(ITERATOR_SYMBOL_INDEX, Symbol, iterator_symbol)                            \
-  V(UNSCOPABLES_SYMBOL_INDEX, Symbol, unscopables_symbol)                      \
-  V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator)
+  V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator)            \
+  V(SCRIPT_CONTEXT_TABLE_INDEX, ScriptContextTable, script_context_table)
+
+
+// A table of all script contexts. Every loaded top-level script with top-level
+// lexical declarations contributes its ScriptContext into this table.
+//
+// The table is a fixed array, its first slot is the current used count and
+// the subsequent slots 1..used contain ScriptContexts.
+class ScriptContextTable : public FixedArray {
+ public:
+  // Conversions.
+  static ScriptContextTable* cast(Object* context) {
+    DCHECK(context->IsScriptContextTable());
+    return reinterpret_cast<ScriptContextTable*>(context);
+  }
+
+  struct LookupResult {
+    int context_index;
+    int slot_index;
+    VariableMode mode;
+    InitializationFlag init_flag;
+    MaybeAssignedFlag maybe_assigned_flag;
+  };
+
+  int used() const { return Smi::cast(get(kUsedSlot))->value(); }
+
+  void set_used(int used) { set(kUsedSlot, Smi::FromInt(used)); }
+
+  static Handle<Context> GetContext(Handle<ScriptContextTable> table, int i) {
+    DCHECK(i < table->used());
+    return Handle<Context>::cast(FixedArray::get(table, i + 1));
+  }
+
+  // Lookup a variable `name` in a ScriptContextTable.
+  // If it returns true, the variable is found and `result` contains
+  // valid information about its location.
+  // If it returns false, `result` is untouched.
+  MUST_USE_RESULT
+  static bool Lookup(Handle<ScriptContextTable> table, Handle<String> name,
+                     LookupResult* result);
+
+  MUST_USE_RESULT
+  static Handle<ScriptContextTable> Extend(Handle<ScriptContextTable> table,
+                                           Handle<Context> script_context);
+
+  static int GetContextOffset(int context_index) {
+    return kFirstContextOffset + context_index * kPointerSize;
+  }
+
+ private:
+  static const int kUsedSlot = 0;
+  static const int kFirstContextOffset =
+      FixedArray::kHeaderSize + (kUsedSlot + 1) * kPointerSize;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ScriptContextTable);
+};
 
 // JSFunctions are pairs (context, function code), sometimes also called
 // closures. A Context object is used to represent function contexts and
@@ -247,7 +283,9 @@
 // properties.
 //
 // Finally, with Harmony scoping, the JSFunction representing a top level
-// script will have the GlobalContext rather than a FunctionContext.
+// script will have the ScriptContext rather than a FunctionContext.
+// Script contexts from all top-level scripts are gathered in
+// ScriptContextTable.
 
 class Context: public FixedArray {
  public:
@@ -312,25 +350,6 @@
     GLOBAL_EVAL_FUN_INDEX,
     INSTANTIATE_FUN_INDEX,
     CONFIGURE_INSTANCE_FUN_INDEX,
-    MATH_ABS_FUN_INDEX,
-    MATH_ACOS_FUN_INDEX,
-    MATH_ASIN_FUN_INDEX,
-    MATH_ATAN_FUN_INDEX,
-    MATH_ATAN2_FUN_INDEX,
-    MATH_CEIL_FUN_INDEX,
-    MATH_COS_FUN_INDEX,
-    MATH_EXP_FUN_INDEX,
-    MATH_FLOOR_FUN_INDEX,
-    MATH_IMUL_FUN_INDEX,
-    MATH_LOG_FUN_INDEX,
-    MATH_MAX_FUN_INDEX,
-    MATH_MIN_FUN_INDEX,
-    MATH_POW_FUN_INDEX,
-    MATH_RANDOM_FUN_INDEX,
-    MATH_ROUND_FUN_INDEX,
-    MATH_SIN_FUN_INDEX,
-    MATH_SQRT_FUN_INDEX,
-    MATH_TAN_FUN_INDEX,
     ARRAY_BUFFER_FUN_INDEX,
     UINT8_ARRAY_FUN_INDEX,
     INT8_ARRAY_FUN_INDEX,
@@ -395,16 +414,16 @@
     ITERATOR_RESULT_MAP_INDEX,
     MAP_ITERATOR_MAP_INDEX,
     SET_ITERATOR_MAP_INDEX,
-    ITERATOR_SYMBOL_INDEX,
-    UNSCOPABLES_SYMBOL_INDEX,
     ARRAY_VALUES_ITERATOR_INDEX,
+    SCRIPT_CONTEXT_TABLE_INDEX,
+    MAP_CACHE_INDEX,
+    TO_LENGTH_FUN_INDEX,
 
     // Properties from here are treated as weak references by the full GC.
     // Scavenge treats them as strong references.
     OPTIMIZED_FUNCTIONS_LIST,  // Weak.
     OPTIMIZED_CODE_LIST,       // Weak.
     DEOPTIMIZED_CODE_LIST,     // Weak.
-    MAP_CACHE_INDEX,           // Weak.
     NEXT_CONTEXT_LINK,         // Weak.
 
     // Total number of slots.
@@ -450,8 +469,8 @@
   // The builtins object.
   JSBuiltinsObject* builtins();
 
-  // Get the innermost global context by traversing the context chain.
-  Context* global_context();
+  // Get the script context by traversing the context chain.
+  Context* script_context();
 
   // Compute the native context by traversing the context chain.
   Context* native_context();
@@ -483,9 +502,9 @@
     Map* map = this->map();
     return map == map->GetHeap()->module_context_map();
   }
-  bool IsGlobalContext() {
+  bool IsScriptContext() {
     Map* map = this->map();
-    return map == map->GetHeap()->global_context_map();
+    return map == map->GetHeap()->script_context_map();
   }
 
   bool HasSameSecurityTokenAs(Context* that) {
diff --git a/src/conversions.cc b/src/conversions.cc
index 8b77623..663f4e8 100644
--- a/src/conversions.cc
+++ b/src/conversions.cc
@@ -483,19 +483,21 @@
 }
 
 
-double StringToDouble(UnicodeCache* unicode_cache,
-                      String* string,
-                      int flags,
-                      double empty_string_val) {
-  DisallowHeapAllocation no_gc;
-  String::FlatContent flat = string->GetFlatContent();
-  // ECMA-262 section 15.1.2.3, empty string is NaN
-  if (flat.IsOneByte()) {
-    return StringToDouble(
-        unicode_cache, flat.ToOneByteVector(), flags, empty_string_val);
-  } else {
-    return StringToDouble(
-        unicode_cache, flat.ToUC16Vector(), flags, empty_string_val);
+double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
+                      int flags, double empty_string_val) {
+  Handle<String> flattened = String::Flatten(string);
+  {
+    DisallowHeapAllocation no_gc;
+    String::FlatContent flat = flattened->GetFlatContent();
+    DCHECK(flat.IsFlat());
+    // ECMA-262 section 15.1.2.3, empty string is NaN
+    if (flat.IsOneByte()) {
+      return StringToDouble(unicode_cache, flat.ToOneByteVector(), flags,
+                            empty_string_val);
+    } else {
+      return StringToDouble(unicode_cache, flat.ToUC16Vector(), flags,
+                            empty_string_val);
+    }
   }
 }
 
diff --git a/src/conversions.h b/src/conversions.h
index 6a28b5f..5afd4e1 100644
--- a/src/conversions.h
+++ b/src/conversions.h
@@ -198,10 +198,8 @@
 }
 
 
-double StringToDouble(UnicodeCache* unicode_cache,
-                      String* string,
-                      int flags,
-                      double empty_string_val = 0.0);
+double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
+                      int flags, double empty_string_val = 0.0);
 
 
 inline bool TryNumberToSize(Isolate* isolate,
diff --git a/src/counters.cc b/src/counters.cc
index a8dcc0b..972bd68 100644
--- a/src/counters.cc
+++ b/src/counters.cc
@@ -7,6 +7,7 @@
 #include "src/base/platform/platform.h"
 #include "src/counters.h"
 #include "src/isolate.h"
+#include "src/log-inl.h"
 
 namespace v8 {
 namespace internal {
@@ -39,7 +40,7 @@
   if (Enabled()) {
     timer_.Start();
   }
-  isolate()->event_logger()(name(), Logger::START);
+  Logger::CallEventLogger(isolate(), name(), Logger::START, true);
 }
 
 
@@ -50,7 +51,7 @@
     AddSample(static_cast<int>(timer_.Elapsed().InMilliseconds()));
     timer_.Stop();
   }
-  isolate()->event_logger()(name(), Logger::END);
+  Logger::CallEventLogger(isolate(), name(), Logger::END, true);
 }
 
 
diff --git a/src/counters.h b/src/counters.h
index 651cf54..41107cf 100644
--- a/src/counters.h
+++ b/src/counters.h
@@ -489,7 +489,6 @@
   SC(for_in, V8.ForIn)                                                         \
   SC(enum_cache_hits, V8.EnumCacheHits)                                        \
   SC(enum_cache_misses, V8.EnumCacheMisses)                                    \
-  SC(zone_segment_bytes, V8.ZoneSegmentBytes)                                  \
   SC(fast_new_closure_total, V8.FastNewClosureTotal)                           \
   SC(fast_new_closure_try_optimized, V8.FastNewClosureTryOptimized)            \
   SC(fast_new_closure_install_optimized, V8.FastNewClosureInstallOptimized)    \
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index 68a565c..456770b 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -20,17 +20,16 @@
 static const int kProfilerStackSize = 64 * KB;
 
 
-ProfilerEventsProcessor::ProfilerEventsProcessor(
-    ProfileGenerator* generator,
-    Sampler* sampler,
-    base::TimeDelta period)
+ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator,
+                                                 Sampler* sampler,
+                                                 base::TimeDelta period)
     : Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)),
       generator_(generator),
       sampler_(sampler),
-      running_(true),
+      running_(1),
       period_(period),
-      last_code_event_id_(0), last_processed_code_event_id_(0) {
-}
+      last_code_event_id_(0),
+      last_processed_code_event_id_(0) {}
 
 
 void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) {
@@ -49,14 +48,13 @@
     regs.fp = frame->fp();
     regs.pc = frame->pc();
   }
-  record.sample.Init(isolate, regs);
+  record.sample.Init(isolate, regs, TickSample::kSkipCEntryFrame);
   ticks_from_vm_buffer_.Enqueue(record);
 }
 
 
 void ProfilerEventsProcessor::StopSynchronously() {
-  if (!running_) return;
-  running_ = false;
+  if (!base::NoBarrier_AtomicExchange(&running_, 0)) return;
   Join();
 }
 
@@ -107,7 +105,7 @@
 
 
 void ProfilerEventsProcessor::Run() {
-  while (running_) {
+  while (!!base::NoBarrier_Load(&running_)) {
     base::ElapsedTimer timer;
     timer.Start();
     // Keep processing existing events until we need to do next sample.
@@ -201,7 +199,10 @@
   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
   rec->start = code->address();
-  rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name));
+  rec->entry = profiles_->NewCodeEntry(
+      tag, profiles_->GetFunctionName(name), CodeEntry::kEmptyNamePrefix,
+      CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
+      CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
   rec->size = code->ExecutableSize();
   rec->shared = NULL;
   processor_->Enqueue(evt_rec);
@@ -215,7 +216,10 @@
   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
   rec->start = code->address();
-  rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name));
+  rec->entry = profiles_->NewCodeEntry(
+      tag, profiles_->GetFunctionName(name), CodeEntry::kEmptyNamePrefix,
+      CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
+      CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
   rec->size = code->ExecutableSize();
   rec->shared = NULL;
   processor_->Enqueue(evt_rec);
@@ -231,7 +235,9 @@
   rec->start = code->address();
   rec->entry = profiles_->NewCodeEntry(
       tag, profiles_->GetFunctionName(shared->DebugName()),
-      CodeEntry::kEmptyNamePrefix, profiles_->GetName(script_name));
+      CodeEntry::kEmptyNamePrefix, profiles_->GetName(script_name),
+      CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo,
+      NULL, code->instruction_start());
   if (info) {
     rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
   }
@@ -240,7 +246,7 @@
     Script* script = Script::cast(shared->script());
     rec->entry->set_script_id(script->id()->value());
     rec->entry->set_bailout_reason(
-        GetBailoutReason(shared->DisableOptimizationReason()));
+        GetBailoutReason(shared->disable_optimization_reason()));
   }
   rec->size = code->ExecutableSize();
   rec->shared = shared->address();
@@ -256,20 +262,34 @@
   CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
   rec->start = code->address();
+  Script* script = Script::cast(shared->script());
+  JITLineInfoTable* line_table = NULL;
+  if (script) {
+    line_table = new JITLineInfoTable();
+    for (RelocIterator it(code); !it.done(); it.next()) {
+      RelocInfo::Mode mode = it.rinfo()->rmode();
+      if (RelocInfo::IsPosition(mode)) {
+        int position = static_cast<int>(it.rinfo()->data());
+        if (position >= 0) {
+          int pc_offset = static_cast<int>(it.rinfo()->pc() - code->address());
+          int line_number = script->GetLineNumber(position);
+          line_table->SetPosition(pc_offset, line_number + 1);
+        }
+      }
+    }
+  }
   rec->entry = profiles_->NewCodeEntry(
       tag, profiles_->GetFunctionName(shared->DebugName()),
       CodeEntry::kEmptyNamePrefix, profiles_->GetName(script_name), line,
-      column);
+      column, line_table, code->instruction_start());
   if (info) {
     rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
   }
-  DCHECK(Script::cast(shared->script()));
-  Script* script = Script::cast(shared->script());
   rec->entry->set_script_id(script->id()->value());
   rec->size = code->ExecutableSize();
   rec->shared = shared->address();
   rec->entry->set_bailout_reason(
-      GetBailoutReason(shared->DisableOptimizationReason()));
+      GetBailoutReason(shared->disable_optimization_reason()));
   processor_->Enqueue(evt_rec);
 }
 
@@ -282,9 +302,9 @@
   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
   rec->start = code->address();
   rec->entry = profiles_->NewCodeEntry(
-      tag,
-      profiles_->GetName(args_count),
-      "args_count: ");
+      tag, profiles_->GetName(args_count), "args_count: ",
+      CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
+      CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
   rec->size = code->ExecutableSize();
   rec->shared = NULL;
   processor_->Enqueue(evt_rec);
@@ -304,7 +324,7 @@
   CodeEventsContainer evt_rec(CodeEventRecord::CODE_DISABLE_OPT);
   CodeDisableOptEventRecord* rec = &evt_rec.CodeDisableOptEventRecord_;
   rec->start = code->address();
-  rec->bailout_reason = GetBailoutReason(shared->DisableOptimizationReason());
+  rec->bailout_reason = GetBailoutReason(shared->disable_optimization_reason());
   processor_->Enqueue(evt_rec);
 }
 
@@ -344,9 +364,9 @@
   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
   rec->start = code->address();
   rec->entry = profiles_->NewCodeEntry(
-      Logger::REG_EXP_TAG,
-      profiles_->GetName(source),
-      "RegExp: ");
+      Logger::REG_EXP_TAG, profiles_->GetName(source), "RegExp: ",
+      CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
+      CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
   rec->size = code->ExecutableSize();
   processor_->Enqueue(evt_rec);
 }
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index c1e75a1..4dc5643 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -132,7 +132,7 @@
   // Thread control.
   virtual void Run();
   void StopSynchronously();
-  INLINE(bool running()) { return running_; }
+  INLINE(bool running()) { return !!base::NoBarrier_Load(&running_); }
   void Enqueue(const CodeEventsContainer& event);
 
   // Puts current stack into tick sample events buffer.
@@ -163,7 +163,7 @@
 
   ProfileGenerator* generator_;
   Sampler* sampler_;
-  bool running_;
+  base::Atomic32 running_;
   // Sampling period in microseconds.
   const base::TimeDelta period_;
   UnboundQueue<CodeEventsContainer> events_buffer_;
diff --git a/src/d8-debug.cc b/src/d8-debug.cc
index 71e006c..7032415 100644
--- a/src/d8-debug.cc
+++ b/src/d8-debug.cc
@@ -124,7 +124,7 @@
       printf("%s\n", *text_str);
     }
     running = response_details->Get(String::NewFromUtf8(isolate, "running"))
-                  ->ToBoolean()
+                  ->ToBoolean(isolate)
                   ->Value();
   }
 }
diff --git a/src/d8.cc b/src/d8.cc
index 9db7744..7157cb8 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -8,10 +8,6 @@
 #define V8_SHARED
 #endif
 
-#ifdef COMPRESS_STARTUP_DATA_BZ2
-#include <bzlib.h>
-#endif
-
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
@@ -46,6 +42,7 @@
 #include "src/base/logging.h"
 #include "src/base/platform/platform.h"
 #include "src/base/sys-info.h"
+#include "src/basic-block-profiler.h"
 #include "src/d8-debug.h"
 #include "src/debug.h"
 #include "src/natives.h"
@@ -176,33 +173,77 @@
 }
 
 
+ScriptCompiler::CachedData* CompileForCachedData(
+    Local<String> source, Local<Value> name,
+    ScriptCompiler::CompileOptions compile_options) {
+  int source_length = source->Length();
+  uint16_t* source_buffer = new uint16_t[source_length];
+  source->Write(source_buffer, 0, source_length);
+  int name_length = 0;
+  uint16_t* name_buffer = NULL;
+  if (name->IsString()) {
+    Local<String> name_string = Local<String>::Cast(name);
+    name_length = name_string->Length();
+    name_buffer = new uint16_t[name_length];
+    name_string->Write(name_buffer, 0, name_length);
+  }
+  Isolate* temp_isolate = Isolate::New();
+  ScriptCompiler::CachedData* result = NULL;
+  {
+    Isolate::Scope isolate_scope(temp_isolate);
+    HandleScope handle_scope(temp_isolate);
+    Context::Scope context_scope(Context::New(temp_isolate));
+    Local<String> source_copy = v8::String::NewFromTwoByte(
+        temp_isolate, source_buffer, v8::String::kNormalString, source_length);
+    Local<Value> name_copy;
+    if (name_buffer) {
+      name_copy = v8::String::NewFromTwoByte(
+          temp_isolate, name_buffer, v8::String::kNormalString, name_length);
+    } else {
+      name_copy = v8::Undefined(temp_isolate);
+    }
+    ScriptCompiler::Source script_source(source_copy, ScriptOrigin(name_copy));
+    ScriptCompiler::CompileUnbound(temp_isolate, &script_source,
+                                   compile_options);
+    if (script_source.GetCachedData()) {
+      int length = script_source.GetCachedData()->length;
+      uint8_t* cache = new uint8_t[length];
+      memcpy(cache, script_source.GetCachedData()->data, length);
+      result = new ScriptCompiler::CachedData(
+          cache, length, ScriptCompiler::CachedData::BufferOwned);
+    }
+  }
+  temp_isolate->Dispose();
+  delete[] source_buffer;
+  delete[] name_buffer;
+  return result;
+}
+
+
 // Compile a string within the current v8 context.
 Local<UnboundScript> Shell::CompileString(
     Isolate* isolate, Local<String> source, Local<Value> name,
-    v8::ScriptCompiler::CompileOptions compile_options) {
+    ScriptCompiler::CompileOptions compile_options) {
   ScriptOrigin origin(name);
-  ScriptCompiler::Source script_source(source, origin);
-  Local<UnboundScript> script =
-      ScriptCompiler::CompileUnbound(isolate, &script_source, compile_options);
-
-  // Was caching requested & successful? Then compile again, now with cache.
-  if (script_source.GetCachedData()) {
-    if (compile_options == ScriptCompiler::kProduceCodeCache) {
-      compile_options = ScriptCompiler::kConsumeCodeCache;
-    } else if (compile_options == ScriptCompiler::kProduceParserCache) {
-      compile_options = ScriptCompiler::kConsumeParserCache;
-    } else {
-      DCHECK(false);  // A new compile option?
-    }
-    ScriptCompiler::Source cached_source(
-        source, origin, new v8::ScriptCompiler::CachedData(
-                            script_source.GetCachedData()->data,
-                            script_source.GetCachedData()->length,
-                            v8::ScriptCompiler::CachedData::BufferNotOwned));
-    script = ScriptCompiler::CompileUnbound(isolate, &cached_source,
-                                            compile_options);
+  if (compile_options == ScriptCompiler::kNoCompileOptions) {
+    ScriptCompiler::Source script_source(source, origin);
+    return ScriptCompiler::CompileUnbound(isolate, &script_source,
+                                          compile_options);
   }
-  return script;
+
+  ScriptCompiler::CachedData* data =
+      CompileForCachedData(source, name, compile_options);
+  ScriptCompiler::Source cached_source(source, origin, data);
+  if (compile_options == ScriptCompiler::kProduceCodeCache) {
+    compile_options = ScriptCompiler::kConsumeCodeCache;
+  } else if (compile_options == ScriptCompiler::kProduceParserCache) {
+    compile_options = ScriptCompiler::kConsumeParserCache;
+  } else {
+    DCHECK(false);  // A new compile option?
+  }
+  if (data == NULL) compile_options = ScriptCompiler::kNoCompileOptions;
+  return ScriptCompiler::CompileUnbound(isolate, &cached_source,
+                                        compile_options);
 }
 
 
@@ -365,7 +406,7 @@
     Throw(args.GetIsolate(), "Invalid argument");
     return;
   }
-  int index = data->RealmFind(args[0]->ToObject()->CreationContext());
+  int index = data->RealmFind(args[0]->ToObject(isolate)->CreationContext());
   if (index == -1) return;
   args.GetReturnValue().Set(index);
 }
@@ -435,7 +476,7 @@
     Throw(args.GetIsolate(), "Invalid argument");
     return;
   }
-  ScriptCompiler::Source script_source(args[1]->ToString());
+  ScriptCompiler::Source script_source(args[1]->ToString(isolate));
   Handle<UnboundScript> script = ScriptCompiler::CompileUnbound(
       isolate, &script_source);
   if (script.IsEmpty()) return;
@@ -481,7 +522,7 @@
 
     // Explicitly catch potential exceptions in toString().
     v8::TryCatch try_catch;
-    Handle<String> str_obj = args[i]->ToString();
+    Handle<String> str_obj = args[i]->ToString(args.GetIsolate());
     if (try_catch.HasCaught()) {
       try_catch.ReThrow();
       return;
@@ -572,7 +613,7 @@
 
 void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
   int exit_code = args[0]->Int32Value();
-  OnExit();
+  OnExit(args.GetIsolate());
   exit(exit_code);
 }
 
@@ -810,7 +851,7 @@
   // Run the d8 shell utility script in the utility context
   int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
   i::Vector<const char> shell_source =
-      i::NativesCollection<i::D8>::GetRawScriptSource(source_index);
+      i::NativesCollection<i::D8>::GetScriptSource(source_index);
   i::Vector<const char> shell_source_name =
       i::NativesCollection<i::D8>::GetScriptName(source_index);
   Handle<String> source =
@@ -838,34 +879,6 @@
 #endif  // !V8_SHARED
 
 
-#ifdef COMPRESS_STARTUP_DATA_BZ2
-class BZip2Decompressor : public v8::StartupDataDecompressor {
- public:
-  virtual ~BZip2Decompressor() { }
-
- protected:
-  virtual int DecompressData(char* raw_data,
-                             int* raw_data_size,
-                             const char* compressed_data,
-                             int compressed_data_size) {
-    DCHECK_EQ(v8::StartupData::kBZip2,
-              v8::V8::GetCompressedStartupDataAlgorithm());
-    unsigned int decompressed_size = *raw_data_size;
-    int result =
-        BZ2_bzBuffToBuffDecompress(raw_data,
-                                   &decompressed_size,
-                                   const_cast<char*>(compressed_data),
-                                   compressed_data_size,
-                                   0, 1);
-    if (result == BZ_OK) {
-      *raw_data_size = decompressed_size;
-    }
-    return result;
-  }
-};
-#endif
-
-
 Handle<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
   Handle<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
   global_template->Set(String::NewFromUtf8(isolate, "print"),
@@ -922,15 +935,6 @@
 
 
 void Shell::Initialize(Isolate* isolate) {
-#ifdef COMPRESS_STARTUP_DATA_BZ2
-  BZip2Decompressor startup_data_decompressor;
-  int bz2_result = startup_data_decompressor.Decompress();
-  if (bz2_result != BZ_OK) {
-    fprintf(stderr, "bzip error code: %d\n", bz2_result);
-    Exit(1);
-  }
-#endif
-
 #ifndef V8_SHARED
   Shell::counter_map_ = new CounterMap();
   // Set up counters
@@ -1009,10 +1013,11 @@
 #endif  // !V8_SHARED
 
 
-void Shell::OnExit() {
+void Shell::OnExit(v8::Isolate* isolate) {
   LineEditor* line_editor = LineEditor::Get();
   if (line_editor) line_editor->Close();
 #ifndef V8_SHARED
+  reinterpret_cast<i::Isolate*>(isolate)->DumpAndResetCompilationStats();
   if (i::FLAG_dump_counters) {
     int number_of_counters = 0;
     for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
@@ -1534,25 +1539,30 @@
 
 class MockArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
  public:
-  virtual void* Allocate(size_t) OVERRIDE {
-    return malloc(0);
-  }
-  virtual void* AllocateUninitialized(size_t length) OVERRIDE {
-    return malloc(0);
-  }
-  virtual void Free(void* p, size_t) OVERRIDE {
-    free(p);
-  }
+  void* Allocate(size_t) OVERRIDE { return malloc(0); }
+  void* AllocateUninitialized(size_t length) OVERRIDE { return malloc(0); }
+  void Free(void* p, size_t) OVERRIDE { free(p); }
 };
 
 
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
 class StartupDataHandler {
  public:
-  StartupDataHandler(const char* natives_blob,
+  StartupDataHandler(const char* exec_path, const char* natives_blob,
                      const char* snapshot_blob) {
-    Load(natives_blob, &natives_, v8::V8::SetNativesDataBlob);
-    Load(snapshot_blob, &snapshot_, v8::V8::SetSnapshotDataBlob);
+    // If we have (at least one) explicitly given blob, use those.
+    // If not, use the default blob locations next to the d8 binary.
+    if (natives_blob || snapshot_blob) {
+      LoadFromFiles(natives_blob, snapshot_blob);
+    } else {
+      char* natives;
+      char* snapshot;
+      LoadFromFiles(RelativePath(&natives, exec_path, "natives_blob.bin"),
+                    RelativePath(&snapshot, exec_path, "snapshot_blob.bin"));
+
+      free(natives);
+      free(snapshot);
+    }
   }
 
   ~StartupDataHandler() {
@@ -1561,11 +1571,32 @@
   }
 
  private:
+  static char* RelativePath(char** buffer, const char* exec_path,
+                            const char* name) {
+    DCHECK(exec_path);
+    const char* last_slash = strrchr(exec_path, '/');
+    if (last_slash) {
+      int after_slash = last_slash - exec_path + 1;
+      int name_length = static_cast<int>(strlen(name));
+      *buffer =
+          reinterpret_cast<char*>(calloc(after_slash + name_length + 1, 1));
+      strncpy(*buffer, exec_path, after_slash);
+      strncat(*buffer, name, name_length);
+    } else {
+      *buffer = strdup(name);
+    }
+    return *buffer;
+  }
+
+  void LoadFromFiles(const char* natives_blob, const char* snapshot_blob) {
+    Load(natives_blob, &natives_, v8::V8::SetNativesDataBlob);
+    Load(snapshot_blob, &snapshot_, v8::V8::SetSnapshotDataBlob);
+  }
+
   void Load(const char* blob_file,
             v8::StartupData* startup_data,
             void (*setter_fn)(v8::StartupData*)) {
     startup_data->data = NULL;
-    startup_data->compressed_size = 0;
     startup_data->raw_size = 0;
 
     if (!blob_file)
@@ -1580,13 +1611,12 @@
     rewind(file);
 
     startup_data->data = new char[startup_data->raw_size];
-    startup_data->compressed_size = fread(
-        const_cast<char*>(startup_data->data), 1, startup_data->raw_size,
-        file);
+    int read_size =
+        static_cast<int>(fread(const_cast<char*>(startup_data->data), 1,
+                               startup_data->raw_size, file));
     fclose(file);
 
-    if (startup_data->raw_size == startup_data->compressed_size)
-      (*setter_fn)(startup_data);
+    if (startup_data->raw_size == read_size) (*setter_fn)(startup_data);
   }
 
   v8::StartupData natives_;
@@ -1621,9 +1651,11 @@
   v8::V8::InitializePlatform(platform);
   v8::V8::Initialize();
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
-  StartupDataHandler startup_data(options.natives_blob, options.snapshot_blob);
+  StartupDataHandler startup_data(argv[0], options.natives_blob,
+                                  options.snapshot_blob);
 #endif
   SetFlagsFromString("--trace-hydrogen-file=hydrogen.cfg");
+  SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg");
   SetFlagsFromString("--redirect-code-traces-to=code.asm");
   ShellArrayBufferAllocator array_buffer_allocator;
   MockArrayBufferAllocator mock_arraybuffer_allocator;
@@ -1640,7 +1672,7 @@
   }
 #endif
 #ifdef ENABLE_VTUNE_JIT_INTERFACE
-  vTune::InitializeVtuneForV8(create_params);
+  create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
 #endif
 #ifndef V8_SHARED
   create_params.constraints.ConfigureDefaults(
@@ -1700,13 +1732,20 @@
       RunShell(isolate);
     }
   }
+  OnExit(isolate);
+#ifndef V8_SHARED
+  // Dump basic block profiling data.
+  if (i::BasicBlockProfiler* profiler =
+          reinterpret_cast<i::Isolate*>(isolate)->basic_block_profiler()) {
+    i::OFStream os(stdout);
+    os << *profiler;
+  }
+#endif  // !V8_SHARED
   isolate->Dispose();
   V8::Dispose();
   V8::ShutdownPlatform();
   delete platform;
 
-  OnExit();
-
   return result;
 }
 
diff --git a/src/d8.gyp b/src/d8.gyp
index a084979..e536584 100644
--- a/src/d8.gyp
+++ b/src/d8.gyp
@@ -129,7 +129,6 @@
             '../tools/js2c.py',
             '<@(_outputs)',
             'D8',
-            'off',  # compress startup data
             '<@(js_files)'
           ],
         },
diff --git a/src/d8.h b/src/d8.h
index 44ee09a..caa5a0a 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -263,7 +263,7 @@
   static int RunMain(Isolate* isolate, int argc, char* argv[]);
   static int Main(int argc, char* argv[]);
   static void Exit(int exit_code);
-  static void OnExit();
+  static void OnExit(Isolate* isolate);
 
 #ifndef V8_SHARED
   static Handle<Array> GetCompletions(Isolate* isolate,
diff --git a/src/data-flow.cc b/src/data-flow.cc
deleted file mode 100644
index bd92ea0..0000000
--- a/src/data-flow.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/data-flow.h"
-
-#include "src/base/bits.h"
-#include "src/scopes.h"
-
-namespace v8 {
-namespace internal {
-
-#ifdef DEBUG
-void BitVector::Print() {
-  bool first = true;
-  PrintF("{");
-  for (int i = 0; i < length(); i++) {
-    if (Contains(i)) {
-      if (!first) PrintF(",");
-      first = false;
-      PrintF("%d", i);
-    }
-  }
-  PrintF("}");
-}
-#endif
-
-
-void BitVector::Iterator::Advance() {
-  current_++;
-  uint32_t val = current_value_;
-  while (val == 0) {
-    current_index_++;
-    if (Done()) return;
-    val = target_->data_[current_index_];
-    current_ = current_index_ << 5;
-  }
-  val = SkipZeroBytes(val);
-  val = SkipZeroBits(val);
-  current_value_ = val >> 1;
-}
-
-
-int BitVector::Count() const {
-  int count = 0;
-  for (int i = 0; i < data_length_; i++) {
-    int data = data_[i];
-    if (data != 0) count += base::bits::CountPopulation32(data);
-  }
-  return count;
-}
-
-}  // namespace internal
-}  // namespace v8
diff --git a/src/data-flow.h b/src/data-flow.h
deleted file mode 100644
index bfd238d..0000000
--- a/src/data-flow.h
+++ /dev/null
@@ -1,252 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_DATAFLOW_H_
-#define V8_DATAFLOW_H_
-
-#include "src/v8.h"
-
-#include "src/allocation.h"
-#include "src/ast.h"
-#include "src/compiler.h"
-#include "src/zone-inl.h"
-
-namespace v8 {
-namespace internal {
-
-class BitVector: public ZoneObject {
- public:
-  // Iterator for the elements of this BitVector.
-  class Iterator BASE_EMBEDDED {
-   public:
-    explicit Iterator(BitVector* target)
-        : target_(target),
-          current_index_(0),
-          current_value_(target->data_[0]),
-          current_(-1) {
-      DCHECK(target->data_length_ > 0);
-      Advance();
-    }
-    ~Iterator() { }
-
-    bool Done() const { return current_index_ >= target_->data_length_; }
-    void Advance();
-
-    int Current() const {
-      DCHECK(!Done());
-      return current_;
-    }
-
-   private:
-    uint32_t SkipZeroBytes(uint32_t val) {
-      while ((val & 0xFF) == 0) {
-        val >>= 8;
-        current_ += 8;
-      }
-      return val;
-    }
-    uint32_t SkipZeroBits(uint32_t val) {
-      while ((val & 0x1) == 0) {
-        val >>= 1;
-        current_++;
-      }
-      return val;
-    }
-
-    BitVector* target_;
-    int current_index_;
-    uint32_t current_value_;
-    int current_;
-
-    friend class BitVector;
-  };
-
-  BitVector(int length, Zone* zone)
-      : length_(length),
-        data_length_(SizeFor(length)),
-        data_(zone->NewArray<uint32_t>(data_length_)) {
-    DCHECK(length > 0);
-    Clear();
-  }
-
-  BitVector(const BitVector& other, Zone* zone)
-      : length_(other.length()),
-        data_length_(SizeFor(length_)),
-        data_(zone->NewArray<uint32_t>(data_length_)) {
-    CopyFrom(other);
-  }
-
-  static int SizeFor(int length) {
-    return 1 + ((length - 1) / 32);
-  }
-
-  BitVector& operator=(const BitVector& rhs) {
-    if (this != &rhs) CopyFrom(rhs);
-    return *this;
-  }
-
-  void CopyFrom(const BitVector& other) {
-    DCHECK(other.length() <= length());
-    for (int i = 0; i < other.data_length_; i++) {
-      data_[i] = other.data_[i];
-    }
-    for (int i = other.data_length_; i < data_length_; i++) {
-      data_[i] = 0;
-    }
-  }
-
-  bool Contains(int i) const {
-    DCHECK(i >= 0 && i < length());
-    uint32_t block = data_[i / 32];
-    return (block & (1U << (i % 32))) != 0;
-  }
-
-  void Add(int i) {
-    DCHECK(i >= 0 && i < length());
-    data_[i / 32] |= (1U << (i % 32));
-  }
-
-  void Remove(int i) {
-    DCHECK(i >= 0 && i < length());
-    data_[i / 32] &= ~(1U << (i % 32));
-  }
-
-  void Union(const BitVector& other) {
-    DCHECK(other.length() == length());
-    for (int i = 0; i < data_length_; i++) {
-      data_[i] |= other.data_[i];
-    }
-  }
-
-  bool UnionIsChanged(const BitVector& other) {
-    DCHECK(other.length() == length());
-    bool changed = false;
-    for (int i = 0; i < data_length_; i++) {
-      uint32_t old_data = data_[i];
-      data_[i] |= other.data_[i];
-      if (data_[i] != old_data) changed = true;
-    }
-    return changed;
-  }
-
-  void Intersect(const BitVector& other) {
-    DCHECK(other.length() == length());
-    for (int i = 0; i < data_length_; i++) {
-      data_[i] &= other.data_[i];
-    }
-  }
-
-  bool IntersectIsChanged(const BitVector& other) {
-    DCHECK(other.length() == length());
-    bool changed = false;
-    for (int i = 0; i < data_length_; i++) {
-      uint32_t old_data = data_[i];
-      data_[i] &= other.data_[i];
-      if (data_[i] != old_data) changed = true;
-    }
-    return changed;
-  }
-
-  void Subtract(const BitVector& other) {
-    DCHECK(other.length() == length());
-    for (int i = 0; i < data_length_; i++) {
-      data_[i] &= ~other.data_[i];
-    }
-  }
-
-  void Clear() {
-    for (int i = 0; i < data_length_; i++) {
-      data_[i] = 0;
-    }
-  }
-
-  bool IsEmpty() const {
-    for (int i = 0; i < data_length_; i++) {
-      if (data_[i] != 0) return false;
-    }
-    return true;
-  }
-
-  bool Equals(const BitVector& other) {
-    for (int i = 0; i < data_length_; i++) {
-      if (data_[i] != other.data_[i]) return false;
-    }
-    return true;
-  }
-
-  int Count() const;
-
-  int length() const { return length_; }
-
-#ifdef DEBUG
-  void Print();
-#endif
-
- private:
-  int length_;
-  int data_length_;
-  uint32_t* data_;
-};
-
-
-class GrowableBitVector BASE_EMBEDDED {
- public:
-  class Iterator BASE_EMBEDDED {
-   public:
-    Iterator(const GrowableBitVector* target, Zone* zone)
-        : it_(target->bits_ == NULL
-              ? new(zone) BitVector(1, zone)
-              : target->bits_) { }
-    bool Done() const { return it_.Done(); }
-    void Advance() { it_.Advance(); }
-    int Current() const { return it_.Current(); }
-   private:
-    BitVector::Iterator it_;
-  };
-
-  GrowableBitVector() : bits_(NULL) { }
-  GrowableBitVector(int length, Zone* zone)
-      : bits_(new(zone) BitVector(length, zone)) { }
-
-  bool Contains(int value) const {
-    if (!InBitsRange(value)) return false;
-    return bits_->Contains(value);
-  }
-
-  void Add(int value, Zone* zone) {
-    EnsureCapacity(value, zone);
-    bits_->Add(value);
-  }
-
-  void Union(const GrowableBitVector& other, Zone* zone) {
-    for (Iterator it(&other, zone); !it.Done(); it.Advance()) {
-      Add(it.Current(), zone);
-    }
-  }
-
-  void Clear() { if (bits_ != NULL) bits_->Clear(); }
-
- private:
-  static const int kInitialLength = 1024;
-
-  bool InBitsRange(int value) const {
-    return bits_ != NULL && bits_->length() > value;
-  }
-
-  void EnsureCapacity(int value, Zone* zone) {
-    if (InBitsRange(value)) return;
-    int new_length = bits_ == NULL ? kInitialLength : bits_->length();
-    while (new_length <= value) new_length *= 2;
-    BitVector* new_bits = new(zone) BitVector(new_length, zone);
-    if (bits_ != NULL) new_bits->CopyFrom(*bits_);
-    bits_ = new_bits;
-  }
-
-  BitVector* bits_;
-};
-
-}  // namespace internal
-}  // namespace v8
-
-#endif  // V8_DATAFLOW_H_
diff --git a/src/debug-debugger.js b/src/debug-debugger.js
index a1468a0..c24b478 100644
--- a/src/debug-debugger.js
+++ b/src/debug-debugger.js
@@ -1,6 +1,7 @@
 // Copyright 2012 the V8 project authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+"use strict";
 
 // Default number of frames to include in the response to backtrace request.
 var kDefaultBacktraceLength = 10;
@@ -33,7 +34,8 @@
                      StepNext: 1,
                      StepIn: 2,
                      StepMin: 3,
-                     StepInMin: 4 };
+                     StepInMin: 4,
+                     StepFrame: 5 };
 
 // The different types of scripts matching enum ScriptType in objects.h.
 Debug.ScriptType = { Native: 0,
@@ -431,7 +433,7 @@
   if (IS_NULL(position)) return;
 
   // Create a break point object and set the break point.
-  break_point = MakeBreakPoint(position, this);
+  var break_point = MakeBreakPoint(position, this);
   break_point.setIgnoreCount(this.ignoreCount());
   var actual_position = %SetScriptBreakPoint(script, position,
                                              this.position_alignment_,
@@ -671,7 +673,7 @@
                                                     condition, enabled,
                                                     opt_position_alignment)
 {
-  break_point = MakeBreakPoint(position);
+  var break_point = MakeBreakPoint(position);
   break_point.setCondition(condition);
   if (!enabled) {
     break_point.disable();
@@ -738,7 +740,7 @@
 
 Debug.clearAllBreakPoints = function() {
   for (var i = 0; i < break_points.length; i++) {
-    break_point = break_points[i];
+    var break_point = break_points[i];
     %ClearBreakPoint(break_point);
   }
   break_points = [];
@@ -1885,7 +1887,7 @@
   // Get the frame for which the scope or scopes are requested.
   // With no frameNumber argument use the currently selected frame.
   if (scope_description && !IS_UNDEFINED(scope_description.frameNumber)) {
-    frame_index = scope_description.frameNumber;
+    var frame_index = scope_description.frameNumber;
     if (frame_index < 0 || this.exec_state_.frameCount() <= frame_index) {
       throw new Error('Invalid frame number');
     }
@@ -1970,7 +1972,7 @@
     var value_mirror = LookupMirror(value_description.handle);
     if (!value_mirror) {
       throw new Error("Failed to resolve value by handle, ' #" +
-          mapping.handle + "# not found");
+          value_description.handle + "# not found");
     }
     return value_mirror.value();
   } else if ("stringDescription" in value_description) {
@@ -2125,7 +2127,7 @@
 
   // Set 'includeSource' option for script lookup.
   if (!IS_UNDEFINED(request.arguments.includeSource)) {
-    includeSource = %ToBoolean(request.arguments.includeSource);
+    var includeSource = %ToBoolean(request.arguments.includeSource);
     response.setOption('includeSource', includeSource);
   }
 
diff --git a/src/debug.cc b/src/debug.cc
index f0e7796..cdcb0a7 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -40,6 +40,7 @@
       live_edit_enabled_(true),  // TODO(yangguo): set to false by default.
       has_break_points_(false),
       break_disabled_(false),
+      in_debug_event_listener_(false),
       break_on_exception_(false),
       break_on_uncaught_exception_(false),
       script_cache_(NULL),
@@ -120,21 +121,37 @@
       DCHECK(statement_position_ >= 0);
     }
 
-    if (IsDebugBreakSlot()) {
-      // There is always a possible break point at a debug break slot.
+    // Check for break at return.
+    if (RelocInfo::IsJSReturn(rmode())) {
+      // Set the positions to the end of the function.
+      if (debug_info_->shared()->HasSourceCode()) {
+        position_ = debug_info_->shared()->end_position() -
+                    debug_info_->shared()->start_position() - 1;
+      } else {
+        position_ = 0;
+      }
+      statement_position_ = position_;
       break_point_++;
       return;
-    } else if (RelocInfo::IsCodeTarget(rmode())) {
+    }
+
+    if (RelocInfo::IsCodeTarget(rmode())) {
       // Check for breakable code target. Look in the original code as setting
       // break points can cause the code targets in the running (debugged) code
       // to be of a different kind than in the original code.
       Address target = original_rinfo()->target_address();
       Code* code = Code::GetCodeFromTargetAddress(target);
-      if ((code->is_inline_cache_stub() &&
-           !code->is_binary_op_stub() &&
-           !code->is_compare_ic_stub() &&
-           !code->is_to_boolean_ic_stub()) ||
-          RelocInfo::IsConstructCall(rmode())) {
+
+      if (RelocInfo::IsConstructCall(rmode()) || code->is_call_stub()) {
+        break_point_++;
+        return;
+      }
+
+      // Skip below if we only want locations for calls and returns.
+      if (type_ == CALLS_AND_RETURNS) continue;
+
+      if ((code->is_inline_cache_stub() && !code->is_binary_op_stub() &&
+           !code->is_compare_ic_stub() && !code->is_to_boolean_ic_stub())) {
         break_point_++;
         return;
       }
@@ -157,16 +174,8 @@
       }
     }
 
-    // Check for break at return.
-    if (RelocInfo::IsJSReturn(rmode())) {
-      // Set the positions to the end of the function.
-      if (debug_info_->shared()->HasSourceCode()) {
-        position_ = debug_info_->shared()->end_position() -
-                    debug_info_->shared()->start_position() - 1;
-      } else {
-        position_ = 0;
-      }
-      statement_position_ = position_;
+    if (IsDebugBreakSlot() && type_ != CALLS_AND_RETURNS) {
+      // There is always a possible break point at a debug break slot.
       break_point_++;
       return;
     }
@@ -563,7 +572,8 @@
   thread_local_.step_into_fp_ = 0;
   thread_local_.step_out_fp_ = 0;
   // TODO(isolates): frames_are_dropped_?
-  thread_local_.current_debug_scope_ = NULL;
+  base::NoBarrier_Store(&thread_local_.current_debug_scope_,
+                        static_cast<base::AtomicWord>(0));
   thread_local_.restarter_frame_function_pointer_ = NULL;
 }
 
@@ -593,10 +603,7 @@
   Heap* heap = isolate_->heap();
   HandleScope scope(isolate_);
 
-  // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
-  // rid of all the cached script wrappers and the second gets rid of the
-  // scripts which are no longer referenced.
-  heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "ScriptCache");
+  // Perform a GC to get rid of all unreferenced scripts.
   heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "ScriptCache");
 
   // Scan heap for Script objects.
@@ -688,18 +695,11 @@
 }
 
 
-void Debug::HandleWeakDebugInfo(
-    const v8::WeakCallbackData<v8::Value, void>& data) {
+void Debug::HandlePhantomDebugInfo(
+    const v8::PhantomCallbackData<DebugInfoListNode>& data) {
   Debug* debug = reinterpret_cast<Isolate*>(data.GetIsolate())->debug();
-  DebugInfoListNode* node =
-      reinterpret_cast<DebugInfoListNode*>(data.GetParameter());
-  // We need to clear all breakpoints associated with the function to restore
-  // original code and avoid patching the code twice later because
-  // the function will live in the heap until next gc, and can be found by
-  // Debug::FindSharedFunctionInfoInScript.
-  BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
-  it.ClearAllDebugBreak();
-  debug->RemoveDebugInfo(node->debug_info());
+  DebugInfoListNode* node = data.GetParameter();
+  debug->RemoveDebugInfo(node);
 #ifdef DEBUG
   for (DebugInfoListNode* n = debug->debug_info_list_;
        n != NULL;
@@ -714,9 +714,10 @@
   // Globalize the request debug info object and make it weak.
   GlobalHandles* global_handles = debug_info->GetIsolate()->global_handles();
   debug_info_ = Handle<DebugInfo>::cast(global_handles->Create(debug_info));
-  GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
-                          this,
-                          Debug::HandleWeakDebugInfo);
+  typedef PhantomCallbackData<void>::Callback Callback;
+  GlobalHandles::MakePhantom(
+      reinterpret_cast<Object**>(debug_info_.location()), this,
+      reinterpret_cast<Callback>(Debug::HandlePhantomDebugInfo));
 }
 
 
@@ -872,7 +873,7 @@
   LiveEdit::InitializeThreadLocal(this);
 
   // Just continue if breaks are disabled or debugger cannot be loaded.
-  if (break_disabled_) return;
+  if (break_disabled()) return;
 
   // Enter the debugger.
   DebugScope debug_scope(this);
@@ -1095,7 +1096,7 @@
   it.FindBreakLocationFromPosition(*source_position, STATEMENT_ALIGNED);
   it.SetBreakPoint(break_point_object);
 
-  *source_position = it.position();
+  *source_position = it.statement_position();
 
   // At least one active break point now.
   return debug_info->GetBreakPointCount() > 0;
@@ -1139,7 +1140,10 @@
   it.FindBreakLocationFromPosition(position, alignment);
   it.SetBreakPoint(break_point_object);
 
-  *source_position = it.position() + shared->start_position();
+  position = (alignment == STATEMENT_ALIGNED) ? it.statement_position()
+                                              : it.position();
+
+  *source_position = position + shared->start_position();
 
   // At least one active break point now.
   DCHECK(debug_info->GetBreakPointCount() > 0);
@@ -1168,7 +1172,7 @@
       // If there are no more break points left remove the debug info for this
       // function.
       if (debug_info->GetBreakPointCount() == 0) {
-        RemoveDebugInfo(debug_info);
+        RemoveDebugInfoAndClearFromShared(debug_info);
       }
 
       return;
@@ -1189,12 +1193,16 @@
 
   // Remove all debug info.
   while (debug_info_list_ != NULL) {
-    RemoveDebugInfo(debug_info_list_->debug_info());
+    RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info());
   }
 }
 
 
-void Debug::FloodWithOneShot(Handle<JSFunction> function) {
+void Debug::FloodWithOneShot(Handle<JSFunction> function,
+                             BreakLocatorType type) {
+  // Do not ever break in native functions.
+  if (function->IsFromNativeScript()) return;
+
   PrepareForBreakPoints();
 
   // Make sure the function is compiled and has set up the debug info.
@@ -1205,7 +1213,7 @@
   }
 
   // Flood the function with break points.
-  BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
+  BreakLocationIterator it(GetDebugInfo(shared), type);
   while (!it.Done()) {
     it.SetOneShot();
     it.Next();
@@ -1221,7 +1229,48 @@
   if (!bindee.is_null() && bindee->IsJSFunction() &&
       !JSFunction::cast(*bindee)->IsFromNativeScript()) {
     Handle<JSFunction> bindee_function(JSFunction::cast(*bindee));
-    Debug::FloodWithOneShot(bindee_function);
+    FloodWithOneShotGeneric(bindee_function);
+  }
+}
+
+
+void Debug::FloodDefaultConstructorWithOneShot(Handle<JSFunction> function) {
+  DCHECK(function->shared()->is_default_constructor());
+  // Instead of stepping into the function we directly step into the super class
+  // constructor.
+  Isolate* isolate = function->GetIsolate();
+  PrototypeIterator iter(isolate, function);
+  Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
+  if (!proto->IsJSFunction()) return;  // Object.prototype
+  Handle<JSFunction> function_proto = Handle<JSFunction>::cast(proto);
+  FloodWithOneShotGeneric(function_proto);
+}
+
+
+void Debug::FloodWithOneShotGeneric(Handle<JSFunction> function,
+                                    Handle<Object> holder) {
+  if (function->shared()->bound()) {
+    FloodBoundFunctionWithOneShot(function);
+  } else if (function->shared()->is_default_constructor()) {
+    FloodDefaultConstructorWithOneShot(function);
+  } else {
+    Isolate* isolate = function->GetIsolate();
+    // Don't allow step into functions in the native context.
+    if (function->shared()->code() ==
+            isolate->builtins()->builtin(Builtins::kFunctionApply) ||
+        function->shared()->code() ==
+            isolate->builtins()->builtin(Builtins::kFunctionCall)) {
+      // Handle function.apply and function.call separately to flood the
+      // function to be called and not the code for Builtins::FunctionApply or
+      // Builtins::FunctionCall. The receiver of call/apply is the target
+      // function.
+      if (!holder.is_null() && holder->IsJSFunction()) {
+        Handle<JSFunction> js_function = Handle<JSFunction>::cast(holder);
+        FloodWithOneShotGeneric(js_function);
+      }
+    } else {
+      FloodWithOneShot(function);
+    }
   }
 }
 
@@ -1262,17 +1311,6 @@
 }
 
 
-bool Debug::PromiseHasRejectHandler(Handle<JSObject> promise) {
-  Handle<JSFunction> fun = Handle<JSFunction>::cast(
-      JSObject::GetDataProperty(isolate_->js_builtins_object(),
-                                isolate_->factory()->NewStringFromStaticChars(
-                                    "PromiseHasRejectHandler")));
-  Handle<Object> result =
-      Execution::Call(isolate_, fun, promise, 0, NULL).ToHandleChecked();
-  return result->IsTrue();
-}
-
-
 void Debug::PrepareStep(StepAction step_action,
                         int step_count,
                         StackFrame::Id frame_id) {
@@ -1312,7 +1350,7 @@
   FloodHandlerWithOneShot();
 
   // If the function on the top frame is unresolved perform step out. This will
-  // be the case when calling unknown functions and having the debugger stopped
+  // be the case when calling unknown function and having the debugger stopped
   // in an unhandled exception.
   if (!frame->function()->IsJSFunction()) {
     // Step out: Find the calling JavaScript frame and flood it with
@@ -1370,7 +1408,7 @@
       if ((maybe_call_function_stub->kind() == Code::STUB &&
            CodeStub::GetMajorKey(maybe_call_function_stub) ==
                CodeStub::CallFunction) ||
-          maybe_call_function_stub->kind() == Code::CALL_IC) {
+          maybe_call_function_stub->is_call_stub()) {
         // Save reference to the code as we may need it to find out arguments
         // count for 'step in' later.
         call_function_stub = Handle<Code>(maybe_call_function_stub);
@@ -1411,7 +1449,9 @@
     // Step next or step min.
 
     // Fill the current function with one-shot break points.
-    FloodWithOneShot(function);
+    // If we are stepping into another frame, only fill calls and returns.
+    FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS
+                                                        : ALL_BREAK_LOCATIONS);
 
     // Remember source position and frame to handle step next.
     thread_local_.last_statement_position_ =
@@ -1469,13 +1509,7 @@
 
       if (fun->IsJSFunction()) {
         Handle<JSFunction> js_function(JSFunction::cast(fun));
-        if (js_function->shared()->bound()) {
-          Debug::FloodBoundFunctionWithOneShot(js_function);
-        } else if (!js_function->IsFromNativeScript()) {
-          // Don't step into builtins.
-          // It will also compile target function if it's not compiled yet.
-          FloodWithOneShot(js_function);
-        }
+        FloodWithOneShotGeneric(js_function);
       }
     }
 
@@ -1483,7 +1517,9 @@
     // a call target as the function called might be a native function for
     // which step in will not stop. It also prepares for stepping in
     // getters/setters.
-    FloodWithOneShot(function);
+    // If we are stepping into another frame, only fill calls and returns.
+    FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS
+                                                        : ALL_BREAK_LOCATIONS);
 
     if (is_load_or_store) {
       // Remember source position and frame to handle step in getter/setter. If
@@ -1512,15 +1548,20 @@
                              JavaScriptFrame* frame) {
   // StepNext and StepOut shouldn't bring us deeper in code, so last frame
   // shouldn't be a parent of current frame.
-  if (thread_local_.last_step_action_ == StepNext ||
-      thread_local_.last_step_action_ == StepOut) {
+  StepAction step_action = thread_local_.last_step_action_;
+
+  if (step_action == StepNext || step_action == StepOut) {
     if (frame->fp() < thread_local_.last_fp_) return true;
   }
 
+  // We stepped into a new frame if the frame pointer changed.
+  if (step_action == StepFrame) {
+    return frame->UnpaddedFP() == thread_local_.last_fp_;
+  }
+
   // If the step last action was step next or step in make sure that a new
   // statement is hit.
-  if (thread_local_.last_step_action_ == StepNext ||
-      thread_local_.last_step_action_ == StepIn) {
+  if (step_action == StepNext || step_action == StepIn) {
     // Never continue if returning from function.
     if (break_location_iterator->IsExit()) return false;
 
@@ -1568,17 +1609,14 @@
       BreakPointInfo* break_point_info =
           BreakPointInfo::cast(debug_info->break_points()->get(i));
       if (break_point_info->GetBreakPointCount() > 0) {
-        Smi* position;
+        Smi* position = NULL;
         switch (position_alignment) {
-        case STATEMENT_ALIGNED:
-          position = break_point_info->statement_position();
-          break;
-        case BREAK_POSITION_ALIGNED:
-          position = break_point_info->source_position();
-          break;
-        default:
-          UNREACHABLE();
-          position = break_point_info->statement_position();
+          case STATEMENT_ALIGNED:
+            position = break_point_info->statement_position();
+            break;
+          case BREAK_POSITION_ALIGNED:
+            position = break_point_info->source_position();
+            break;
         }
 
         locations->set(count++, position);
@@ -1590,10 +1628,13 @@
 
 
 // Handle stepping into a function.
-void Debug::HandleStepIn(Handle<JSFunction> function,
-                         Handle<Object> holder,
-                         Address fp,
-                         bool is_constructor) {
+void Debug::HandleStepIn(Handle<Object> function_obj, Handle<Object> holder,
+                         Address fp, bool is_constructor) {
+  // Flood getter/setter if we either step in or step to another frame.
+  bool step_frame = thread_local_.last_step_action_ == StepFrame;
+  if (!StepInActive() && !step_frame) return;
+  if (!function_obj->IsJSFunction()) return;
+  Handle<JSFunction> function = Handle<JSFunction>::cast(function_obj);
   Isolate* isolate = function->GetIsolate();
   // If the frame pointer is not supplied by the caller find it.
   if (fp == 0) {
@@ -1608,34 +1649,9 @@
   }
 
   // Flood the function with one-shot break points if it is called from where
-  // step into was requested.
-  if (fp == thread_local_.step_into_fp_) {
-    if (function->shared()->bound()) {
-      // Handle Function.prototype.bind
-      Debug::FloodBoundFunctionWithOneShot(function);
-    } else if (!function->IsFromNativeScript()) {
-      // Don't allow step into functions in the native context.
-      if (function->shared()->code() ==
-          isolate->builtins()->builtin(Builtins::kFunctionApply) ||
-          function->shared()->code() ==
-          isolate->builtins()->builtin(Builtins::kFunctionCall)) {
-        // Handle function.apply and function.call separately to flood the
-        // function to be called and not the code for Builtins::FunctionApply or
-        // Builtins::FunctionCall. The receiver of call/apply is the target
-        // function.
-        if (!holder.is_null() && holder->IsJSFunction()) {
-          Handle<JSFunction> js_function = Handle<JSFunction>::cast(holder);
-          if (!js_function->IsFromNativeScript()) {
-            Debug::FloodWithOneShot(js_function);
-          } else if (js_function->shared()->bound()) {
-            // Handle Function.prototype.bind
-            Debug::FloodBoundFunctionWithOneShot(js_function);
-          }
-        }
-      } else {
-        Debug::FloodWithOneShot(function);
-      }
-    }
+  // step into was requested, or when stepping into a new frame.
+  if (fp == thread_local_.step_into_fp_ || step_frame) {
+    FloodWithOneShotGeneric(function, holder);
   }
 }
 
@@ -1904,6 +1920,23 @@
 }
 
 
+static bool SkipSharedFunctionInfo(SharedFunctionInfo* shared,
+                                   Object* active_code_marker) {
+  if (!shared->allows_lazy_compilation()) return true;
+  if (!shared->script()->IsScript()) return true;
+  Object* script = shared->script();
+  if (!script->IsScript()) return true;
+  if (Script::cast(script)->type()->value() == Script::TYPE_NATIVE) return true;
+  Code* shared_code = shared->code();
+  return shared_code->gc_metadata() == active_code_marker;
+}
+
+
+static inline bool HasDebugBreakSlots(Code* code) {
+  return code->kind() == Code::FUNCTION && code->has_debug_break_slots();
+}
+
+
 void Debug::PrepareForBreakPoints() {
   // If preparing for the first break point make sure to deoptimize all
   // functions as debugging does not work with optimized code.
@@ -1969,35 +2002,28 @@
         if (obj->IsJSFunction()) {
           JSFunction* function = JSFunction::cast(obj);
           SharedFunctionInfo* shared = function->shared();
-
-          if (!shared->allows_lazy_compilation()) continue;
-          if (!shared->script()->IsScript()) continue;
-          if (function->IsFromNativeScript()) continue;
-          if (shared->code()->gc_metadata() == active_code_marker) continue;
-
+          if (SkipSharedFunctionInfo(shared, active_code_marker)) continue;
           if (shared->is_generator()) {
             generator_functions.Add(Handle<JSFunction>(function, isolate_));
             continue;
           }
-
+          if (HasDebugBreakSlots(function->code())) continue;
+          Code* fallback = HasDebugBreakSlots(shared->code()) ? shared->code()
+                                                              : *lazy_compile;
           Code::Kind kind = function->code()->kind();
-          if (kind == Code::FUNCTION &&
-              !function->code()->has_debug_break_slots()) {
-            function->ReplaceCode(*lazy_compile);
-            function->shared()->ReplaceCode(*lazy_compile);
-          } else if (kind == Code::BUILTIN &&
-              (function->IsInOptimizationQueue() ||
-               function->IsMarkedForOptimization() ||
-               function->IsMarkedForConcurrentOptimization())) {
-            // Abort in-flight compilation.
-            Code* shared_code = function->shared()->code();
-            if (shared_code->kind() == Code::FUNCTION &&
-                shared_code->has_debug_break_slots()) {
-              function->ReplaceCode(shared_code);
-            } else {
-              function->ReplaceCode(*lazy_compile);
-              function->shared()->ReplaceCode(*lazy_compile);
-            }
+          if (kind == Code::FUNCTION ||
+              (kind == Code::BUILTIN &&  // Abort in-flight compilation.
+               (function->IsInOptimizationQueue() ||
+                function->IsMarkedForOptimization() ||
+                function->IsMarkedForConcurrentOptimization()))) {
+            function->ReplaceCode(fallback);
+          }
+          if (kind == Code::OPTIMIZED_FUNCTION) {
+            // Optimized code can only get here if DeoptimizeAll did not
+            // deoptimize turbo fan code.
+            DCHECK(!FLAG_turbo_deoptimization);
+            DCHECK(function->code()->is_turbofanned());
+            function->ReplaceCode(fallback);
           }
         } else if (obj->IsJSGeneratorObject()) {
           JSGeneratorObject* gen = JSGeneratorObject::cast(obj);
@@ -2017,6 +2043,12 @@
           gen->set_continuation(code_offset);
 
           suspended_generators.Add(Handle<JSGeneratorObject>(gen, isolate_));
+        } else if (obj->IsSharedFunctionInfo()) {
+          SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
+          if (SkipSharedFunctionInfo(shared, active_code_marker)) continue;
+          if (shared->is_generator()) continue;
+          if (HasDebugBreakSlots(shared->code())) continue;
+          shared->ReplaceCode(*lazy_compile);
         }
       }
 
@@ -2089,7 +2121,10 @@
   Heap* heap = isolate_->heap();
   while (!done) {
     { // Extra scope for iterator.
-      HeapIterator iterator(heap);
+      // If lazy compilation is off, we won't have duplicate shared function
+      // infos that need to be filtered.
+      HeapIterator iterator(heap, FLAG_lazy ? HeapIterator::kNoFiltering
+                                            : HeapIterator::kFilterUnreachable);
       for (HeapObject* obj = iterator.next();
            obj != NULL; obj = iterator.next()) {
         bool found_next_candidate = false;
@@ -2205,27 +2240,29 @@
 }
 
 
-void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
+void Debug::RemoveDebugInfo(DebugInfoListNode* prev, DebugInfoListNode* node) {
+  // Unlink from list. If prev is NULL we are looking at the first element.
+  if (prev == NULL) {
+    debug_info_list_ = node->next();
+  } else {
+    prev->set_next(node->next());
+  }
+  delete node;
+
+  // If there are no more debug info objects there are not more break
+  // points.
+  has_break_points_ = debug_info_list_ != NULL;
+}
+
+
+void Debug::RemoveDebugInfo(DebugInfo** debug_info) {
   DCHECK(debug_info_list_ != NULL);
   // Run through the debug info objects to find this one and remove it.
   DebugInfoListNode* prev = NULL;
   DebugInfoListNode* current = debug_info_list_;
   while (current != NULL) {
-    if (*current->debug_info() == *debug_info) {
-      // Unlink from list. If prev is NULL we are looking at the first element.
-      if (prev == NULL) {
-        debug_info_list_ = current->next();
-      } else {
-        prev->set_next(current->next());
-      }
-      current->debug_info()->shared()->set_debug_info(
-              isolate_->heap()->undefined_value());
-      delete current;
-
-      // If there are no more debug info objects there are not more break
-      // points.
-      has_break_points_ = debug_info_list_ != NULL;
-
+    if (current->debug_info().location() == debug_info) {
+      RemoveDebugInfo(prev, current);
       return;
     }
     // Move to next in list.
@@ -2236,6 +2273,34 @@
 }
 
 
+void Debug::RemoveDebugInfo(DebugInfoListNode* node) {
+  DCHECK(debug_info_list_ != NULL);
+  // Run through the debug info objects to find this one and remove it.
+  DebugInfoListNode* prev = NULL;
+  DebugInfoListNode* current = debug_info_list_;
+  while (current != NULL) {
+    if (current == node) {
+      RemoveDebugInfo(prev, node);
+      return;
+    }
+    // Move to next in list.
+    prev = current;
+    current = current->next();
+  }
+  UNREACHABLE();
+}
+
+
+void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) {
+  HandleScope scope(isolate_);
+  Handle<SharedFunctionInfo> shared(debug_info->shared());
+
+  RemoveDebugInfo(debug_info.location());
+
+  shared->set_debug_info(isolate_->heap()->undefined_value());
+}
+
+
 void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
   after_break_target_ = NULL;
 
@@ -2330,7 +2395,7 @@
   HandleScope scope(isolate_);
 
   // If there are no break points this cannot be break at return, as
-  // the debugger statement and stack guard bebug break cannot be at
+  // the debugger statement and stack guard debug break cannot be at
   // return.
   if (!has_break_points_) {
     return false;
@@ -2521,14 +2586,37 @@
 void Debug::OnPromiseReject(Handle<JSObject> promise, Handle<Object> value) {
   if (in_debug_scope() || ignore_events()) return;
   HandleScope scope(isolate_);
-  OnException(value, false, promise);
+  // Check whether the promise has been marked as having triggered a message.
+  Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol();
+  if (JSObject::GetDataProperty(promise, key)->IsUndefined()) {
+    OnException(value, false, promise);
+  }
+}
+
+
+MaybeHandle<Object> Debug::PromiseHasUserDefinedRejectHandler(
+    Handle<JSObject> promise) {
+  Handle<JSFunction> fun = Handle<JSFunction>::cast(
+      JSObject::GetDataProperty(isolate_->js_builtins_object(),
+                                isolate_->factory()->NewStringFromStaticChars(
+                                    "PromiseHasUserDefinedRejectHandler")));
+  return Execution::Call(isolate_, fun, promise, 0, NULL);
 }
 
 
 void Debug::OnException(Handle<Object> exception, bool uncaught,
                         Handle<Object> promise) {
-  if (promise->IsJSObject()) {
-    uncaught |= !PromiseHasRejectHandler(Handle<JSObject>::cast(promise));
+  if (!uncaught && promise->IsJSObject()) {
+    Handle<JSObject> jspromise = Handle<JSObject>::cast(promise);
+    // Mark the promise as already having triggered a message.
+    Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol();
+    JSObject::SetProperty(jspromise, key, key, STRICT).Assert();
+    // Check whether the promise reject is considered an uncaught exception.
+    Handle<Object> has_reject_handler;
+    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+        isolate_, has_reject_handler,
+        PromiseHasUserDefinedRejectHandler(jspromise), /* void */);
+    uncaught = has_reject_handler->IsFalse();
   }
   // Bail out if exception breaks are not active
   if (uncaught) {
@@ -2560,8 +2648,12 @@
 
 
 void Debug::OnCompileError(Handle<Script> script) {
-  // No more to do if not debugging.
-  if (in_debug_scope() || ignore_events()) return;
+  if (ignore_events()) return;
+
+  if (in_debug_scope()) {
+    ProcessCompileEventInDebugScope(v8::CompileError, script);
+    return;
+  }
 
   HandleScope scope(isolate_);
   DebugScope debug_scope(this);
@@ -2622,8 +2714,12 @@
   // Add the newly compiled script to the script cache.
   if (script_cache_ != NULL) script_cache_->Add(script);
 
-  // No more to do if not debugging.
-  if (in_debug_scope() || ignore_events()) return;
+  if (ignore_events()) return;
+
+  if (in_debug_scope()) {
+    ProcessCompileEventInDebugScope(v8::AfterCompile, script);
+    return;
+  }
 
   HandleScope scope(isolate_);
   DebugScope debug_scope(this);
@@ -2749,6 +2845,8 @@
                               Handle<Object> exec_state,
                               Handle<Object> event_data,
                               v8::Debug::ClientData* client_data) {
+  bool previous = in_debug_event_listener_;
+  in_debug_event_listener_ = true;
   if (event_listener_->IsForeign()) {
     // Invoke the C debug event listener.
     v8::Debug::EventCallback callback =
@@ -2772,6 +2870,28 @@
     Execution::TryCall(Handle<JSFunction>::cast(event_listener_),
                        global, arraysize(argv), argv);
   }
+  in_debug_event_listener_ = previous;
+}
+
+
+void Debug::ProcessCompileEventInDebugScope(v8::DebugEvent event,
+                                            Handle<Script> script) {
+  if (event_listener_.is_null()) return;
+
+  SuppressDebug while_processing(this);
+  DebugScope debug_scope(this);
+  if (debug_scope.failed()) return;
+
+  Handle<Object> event_data;
+  // Bail out and don't call debugger if exception.
+  if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return;
+
+  // Create the execution state.
+  Handle<Object> exec_state;
+  // Bail out and don't call debugger if exception.
+  if (!MakeExecutionState().ToHandle(&exec_state)) return;
+
+  CallEventCallback(event, exec_state, event_data, NULL);
 }
 
 
@@ -3025,7 +3145,7 @@
   // Ignore debug break during bootstrapping.
   if (isolate_->bootstrapper()->IsActive()) return;
   // Just continue if breaks are disabled.
-  if (break_disabled_) return;
+  if (break_disabled()) return;
   // Ignore debug break if debugger is not active.
   if (!is_active()) return;
 
@@ -3077,7 +3197,8 @@
       no_termination_exceptons_(debug_->isolate_,
                                 StackGuard::TERMINATE_EXECUTION) {
   // Link recursive debugger entry.
-  debug_->thread_local_.current_debug_scope_ = this;
+  base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_,
+                        reinterpret_cast<base::AtomicWord>(this));
 
   // Store the previous break id and frame id.
   break_id_ = debug_->break_id();
@@ -3114,7 +3235,8 @@
   }
 
   // Leaving this debugger entry.
-  debug_->thread_local_.current_debug_scope_ = prev_;
+  base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_,
+                        reinterpret_cast<base::AtomicWord>(prev_));
 
   // Restore to the previous break state.
   debug_->thread_local_.break_frame_id_ = break_frame_id_;
@@ -3225,7 +3347,7 @@
 v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
   Isolate* isolate = event_data_->GetIsolate();
   v8::Handle<v8::Context> context = GetDebugEventContext(isolate);
-  // Isolate::context() may be NULL when "script collected" event occures.
+  // Isolate::context() may be NULL when "script collected" event occurs.
   DCHECK(!context.IsEmpty());
   return context;
 }
diff --git a/src/debug.h b/src/debug.h
index a5119d0..0ec9024 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -8,6 +8,7 @@
 #include "src/allocation.h"
 #include "src/arguments.h"
 #include "src/assembler.h"
+#include "src/base/atomicops.h"
 #include "src/base/platform/platform.h"
 #include "src/execution.h"
 #include "src/factory.h"
@@ -31,13 +32,14 @@
 // Step actions. NOTE: These values are in macros.py as well.
 enum StepAction {
   StepNone = -1,  // Stepping not prepared.
-  StepOut = 0,   // Step out of the current function.
-  StepNext = 1,  // Step to the next statement in the current function.
-  StepIn = 2,    // Step into new functions invoked or the next statement
-                 // in the current function.
-  StepMin = 3,   // Perform a minimum step in the current function.
-  StepInMin = 4  // Step into new functions invoked or perform a minimum step
-                 // in the current function.
+  StepOut = 0,    // Step out of the current function.
+  StepNext = 1,   // Step to the next statement in the current function.
+  StepIn = 2,     // Step into new functions invoked or the next statement
+                  // in the current function.
+  StepMin = 3,    // Perform a minimum step in the current function.
+  StepInMin = 4,  // Step into new functions invoked or perform a minimum step
+                  // in the current function.
+  StepFrame = 5   // Step into a new frame or return to previous frame.
 };
 
 
@@ -48,10 +50,11 @@
 };
 
 
-// Type of exception break. NOTE: These values are in macros.py as well.
+// Type of exception break.
 enum BreakLocatorType {
   ALL_BREAK_LOCATIONS = 0,
-  SOURCE_BREAK_LOCATIONS = 1
+  SOURCE_BREAK_LOCATIONS = 1,
+  CALLS_AND_RETURNS = 2
 };
 
 
@@ -384,8 +387,12 @@
                               BreakPositionAlignment alignment);
   void ClearBreakPoint(Handle<Object> break_point_object);
   void ClearAllBreakPoints();
-  void FloodWithOneShot(Handle<JSFunction> function);
+  void FloodWithOneShot(Handle<JSFunction> function,
+                        BreakLocatorType type = ALL_BREAK_LOCATIONS);
   void FloodBoundFunctionWithOneShot(Handle<JSFunction> function);
+  void FloodDefaultConstructorWithOneShot(Handle<JSFunction> function);
+  void FloodWithOneShotGeneric(Handle<JSFunction> function,
+                               Handle<Object> holder = Handle<Object>());
   void FloodHandlerWithOneShot();
   void ChangeBreakOnException(ExceptionBreakType type, bool enable);
   bool IsBreakOnException(ExceptionBreakType type);
@@ -400,10 +407,8 @@
   bool StepNextContinue(BreakLocationIterator* break_location_iterator,
                         JavaScriptFrame* frame);
   bool StepInActive() { return thread_local_.step_into_fp_ != 0; }
-  void HandleStepIn(Handle<JSFunction> function,
-                    Handle<Object> holder,
-                    Address fp,
-                    bool is_constructor);
+  void HandleStepIn(Handle<Object> function_obj, Handle<Object> holder,
+                    Address fp, bool is_constructor);
   bool StepOutActive() { return thread_local_.step_out_fp_ != 0; }
 
   // Purge all code objects that have no debug break slots.
@@ -442,8 +447,8 @@
                              Object** restarter_frame_function_pointer);
 
   // Passed to MakeWeak.
-  static void HandleWeakDebugInfo(
-      const v8::WeakCallbackData<v8::Value, void>& data);
+  static void HandlePhantomDebugInfo(
+      const PhantomCallbackData<DebugInfoListNode>& data);
 
   // Threading support.
   char* ArchiveDebug(char* to);
@@ -454,8 +459,15 @@
   // Record function from which eval was called.
   static void RecordEvalCaller(Handle<Script> script);
 
+  bool CheckExecutionState(int id) {
+    return !debug_context().is_null() && break_id() != 0 && break_id() == id;
+  }
+
   // Flags and states.
-  DebugScope* debugger_entry() { return thread_local_.current_debug_scope_; }
+  DebugScope* debugger_entry() {
+    return reinterpret_cast<DebugScope*>(
+        base::NoBarrier_Load(&thread_local_.current_debug_scope_));
+  }
   inline Handle<Context> debug_context() { return debug_context_; }
   void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; }
   bool live_edit_enabled() const {
@@ -466,7 +478,7 @@
   inline bool is_loaded() const { return !debug_context_.is_null(); }
   inline bool has_break_points() const { return has_break_points_; }
   inline bool in_debug_scope() const {
-    return thread_local_.current_debug_scope_ != NULL;
+    return !!base::NoBarrier_Load(&thread_local_.current_debug_scope_);
   }
   void set_disable_break(bool v) { break_disabled_ = v; }
 
@@ -491,6 +503,8 @@
     return reinterpret_cast<Address>(&thread_local_.step_into_fp_);
   }
 
+  StepAction last_step_action() { return thread_local_.last_step_action_; }
+
  private:
   explicit Debug(Isolate* isolate);
 
@@ -503,6 +517,9 @@
   // Check whether there are commands in the command queue.
   inline bool has_commands() const { return !command_queue_.IsEmpty(); }
   inline bool ignore_events() const { return is_suppressed_ || !is_active_; }
+  inline bool break_disabled() const {
+    return break_disabled_ || in_debug_event_listener_;
+  }
 
   void OnException(Handle<Object> exception, bool uncaught,
                    Handle<Object> promise);
@@ -529,13 +546,15 @@
   // Mirror cache handling.
   void ClearMirrorCache();
 
-  // Returns a promise if the pushed try-catch handler matches the current one.
-  bool PromiseHasRejectHandler(Handle<JSObject> promise);
+  MaybeHandle<Object> PromiseHasUserDefinedRejectHandler(
+      Handle<JSObject> promise);
 
   void CallEventCallback(v8::DebugEvent event,
                          Handle<Object> exec_state,
                          Handle<Object> event_data,
                          v8::Debug::ClientData* client_data);
+  void ProcessCompileEventInDebugScope(v8::DebugEvent event,
+                                       Handle<Script> script);
   void ProcessDebugEvent(v8::DebugEvent event,
                          Handle<JSObject> event_data,
                          bool auto_continue);
@@ -551,8 +570,10 @@
   void ClearStepIn();
   void ActivateStepOut(StackFrame* frame);
   void ClearStepNext();
-  // Returns whether the compile succeeded.
-  void RemoveDebugInfo(Handle<DebugInfo> debug_info);
+  void RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info);
+  void RemoveDebugInfo(DebugInfo** debug_info);
+  void RemoveDebugInfo(DebugInfoListNode* node);
+  void RemoveDebugInfo(DebugInfoListNode* prev, DebugInfoListNode* node);
   Handle<Object> CheckBreakPoints(Handle<Object> break_point);
   bool CheckBreakPoint(Handle<Object> break_point_object);
 
@@ -580,6 +601,7 @@
   bool live_edit_enabled_;
   bool has_break_points_;
   bool break_disabled_;
+  bool in_debug_event_listener_;
   bool break_on_exception_;
   bool break_on_uncaught_exception_;
 
@@ -595,7 +617,7 @@
   class ThreadLocal {
    public:
     // Top debugger entry.
-    DebugScope* current_debug_scope_;
+    base::AtomicWord current_debug_scope_;
 
     // Counter for generating next break id.
     int break_count_;
@@ -615,7 +637,7 @@
     // Number of steps left to perform before debug event.
     int step_count_;
 
-    // Frame pointer from last step next action.
+    // Frame pointer from last step next or step frame action.
     Address last_fp_;
 
     // Number of queued steps left to perform before debug event.
@@ -690,14 +712,21 @@
 class DisableBreak BASE_EMBEDDED {
  public:
   explicit DisableBreak(Debug* debug, bool disable_break)
-    : debug_(debug), old_state_(debug->break_disabled_) {
+      : debug_(debug),
+        previous_break_disabled_(debug->break_disabled_),
+        previous_in_debug_event_listener_(debug->in_debug_event_listener_) {
     debug_->break_disabled_ = disable_break;
+    debug_->in_debug_event_listener_ = disable_break;
   }
-  ~DisableBreak() { debug_->break_disabled_ = old_state_; }
+  ~DisableBreak() {
+    debug_->break_disabled_ = previous_break_disabled_;
+    debug_->in_debug_event_listener_ = previous_in_debug_event_listener_;
+  }
 
  private:
   Debug* debug_;
-  bool old_state_;
+  bool previous_break_disabled_;
+  bool previous_in_debug_event_listener_;
   DISALLOW_COPY_AND_ASSIGN(DisableBreak);
 };
 
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index dd274ed..748f95e 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -637,7 +637,7 @@
 
 void Deoptimizer::PrintFunctionName() {
   if (function_->IsJSFunction()) {
-    function_->PrintName(trace_scope_->file());
+    function_->ShortPrint(trace_scope_->file());
   } else {
     PrintF(trace_scope_->file(),
            "%s", Code::Kind2String(compiled_code_->kind()));
@@ -693,8 +693,7 @@
   DeoptimizerData* data = isolate->deoptimizer_data();
   MemoryChunk* base = data->deopt_entry_code_[type];
   Address start = base->area_start();
-  if (base == NULL ||
-      addr < start ||
+  if (addr < start ||
       addr >= start + (kMaxNumberOfEntries * table_entry_size_)) {
     return kNotDeoptimizationEntry;
   }
@@ -719,7 +718,7 @@
   OFStream os(stderr);
   os << "[couldn't find pc offset for node=" << id.ToInt() << "]\n"
      << "[method: " << shared->DebugName()->ToCString().get() << "]\n"
-     << "[source:\n" << SourceCodeOf(shared) << "\n]" << endl;
+     << "[source:\n" << SourceCodeOf(shared) << "\n]" << std::endl;
 
   FATAL("unable to find pc offset during deoptimization");
   return -1;
@@ -762,10 +761,8 @@
 
   if (trace_scope_ != NULL) {
     timer.Start();
-    PrintF(trace_scope_->file(),
-           "[deoptimizing (DEOPT %s): begin 0x%08" V8PRIxPTR " ",
-           MessageFor(bailout_type_),
-           reinterpret_cast<intptr_t>(function_));
+    PrintF(trace_scope_->file(), "[deoptimizing (DEOPT %s): begin ",
+           MessageFor(bailout_type_));
     PrintFunctionName();
     PrintF(trace_scope_->file(),
            " (opt #%d) @%d, FP to SP delta: %d]\n",
@@ -851,11 +848,8 @@
   if (trace_scope_ != NULL) {
     double ms = timer.Elapsed().InMillisecondsF();
     int index = output_count_ - 1;  // Index of the topmost frame.
-    JSFunction* function = output_[index]->GetFunction();
-    PrintF(trace_scope_->file(),
-           "[deoptimizing (%s): end 0x%08" V8PRIxPTR " ",
-           MessageFor(bailout_type_),
-           reinterpret_cast<intptr_t>(function));
+    PrintF(trace_scope_->file(), "[deoptimizing (%s): end ",
+           MessageFor(bailout_type_));
     PrintFunctionName();
     PrintF(trace_scope_->file(),
            " @%d => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s,"
diff --git a/src/disassembler.cc b/src/disassembler.cc
index d9448ce..bedff45 100644
--- a/src/disassembler.cc
+++ b/src/disassembler.cc
@@ -19,21 +19,6 @@
 
 #ifdef ENABLE_DISASSEMBLER
 
-void Disassembler::Dump(FILE* f, byte* begin, byte* end) {
-  for (byte* pc = begin; pc < end; pc++) {
-    if (f == NULL) {
-      PrintF("%" V8PRIxPTR "  %4" V8PRIdPTR "  %02x\n",
-             reinterpret_cast<intptr_t>(pc),
-             pc - begin,
-             *pc);
-    } else {
-      PrintF(f, "%" V8PRIxPTR "  %4" V8PRIdPTR "  %02x\n",
-             reinterpret_cast<uintptr_t>(pc), pc - begin, *pc);
-    }
-  }
-}
-
-
 class V8NameConverter: public disasm::NameConverter {
  public:
   explicit V8NameConverter(Code* code) : code_(code) {}
@@ -74,12 +59,8 @@
 }
 
 
-static void DumpBuffer(FILE* f, StringBuilder* out) {
-  if (f == NULL) {
-    PrintF("%s\n", out->Finalize());
-  } else {
-    PrintF(f, "%s\n", out->Finalize());
-  }
+static void DumpBuffer(std::ostream* os, StringBuilder* out) {
+  (*os) << out->Finalize() << std::endl;
   out->Reset();
 }
 
@@ -87,11 +68,8 @@
 static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength;
 static const int kRelocInfoPosition = 57;
 
-static int DecodeIt(Isolate* isolate,
-                    FILE* f,
-                    const V8NameConverter& converter,
-                    byte* begin,
-                    byte* end) {
+static int DecodeIt(Isolate* isolate, std::ostream* os,
+                    const V8NameConverter& converter, byte* begin, byte* end) {
   SealHandleScope shs(isolate);
   DisallowHeapAllocation no_alloc;
   ExternalReferenceEncoder ref_encoder(isolate);
@@ -164,7 +142,7 @@
     // Comments.
     for (int i = 0; i < comments.length(); i++) {
       out.AddFormatted("                  %s", comments[i]);
-      DumpBuffer(f, &out);
+      DumpBuffer(os, &out);
     }
 
     // Instruction address and instruction offset.
@@ -184,7 +162,7 @@
         out.AddPadding(' ', kRelocInfoPosition - out.position());
       } else {
         // Additional reloc infos are printed on separate lines.
-        DumpBuffer(f, &out);
+        DumpBuffer(os, &out);
         out.AddPadding(' ', kRelocInfoPosition);
       }
 
@@ -278,7 +256,7 @@
         out.AddFormatted("    ;; %s", RelocInfo::RelocModeName(rmode));
       }
     }
-    DumpBuffer(f, &out);
+    DumpBuffer(os, &out);
   }
 
   // Emit comments following the last instruction (if any).
@@ -287,7 +265,7 @@
       if (RelocInfo::IsComment(it->rinfo()->rmode())) {
         out.AddFormatted("                  %s",
                          reinterpret_cast<const char*>(it->rinfo()->data()));
-        DumpBuffer(f, &out);
+        DumpBuffer(os, &out);
       }
     }
   }
@@ -297,40 +275,19 @@
 }
 
 
-int Disassembler::Decode(Isolate* isolate, FILE* f, byte* begin, byte* end) {
-  V8NameConverter defaultConverter(NULL);
-  return DecodeIt(isolate, f, defaultConverter, begin, end);
-}
-
-
-// Called by Code::CodePrint.
-void Disassembler::Decode(FILE* f, Code* code) {
-  Isolate* isolate = code->GetIsolate();
-  int decode_size = code->is_crankshafted()
-      ? static_cast<int>(code->safepoint_table_offset())
-      : code->instruction_size();
-  // If there might be a back edge table, stop before reaching it.
-  if (code->kind() == Code::FUNCTION) {
-    decode_size =
-        Min(decode_size, static_cast<int>(code->back_edge_table_offset()));
-  }
-
-  byte* begin = code->instruction_start();
-  byte* end = begin + decode_size;
+int Disassembler::Decode(Isolate* isolate, std::ostream* os, byte* begin,
+                         byte* end, Code* code) {
   V8NameConverter v8NameConverter(code);
-  DecodeIt(isolate, f, v8NameConverter, begin, end);
+  return DecodeIt(isolate, os, v8NameConverter, begin, end);
 }
 
 #else  // ENABLE_DISASSEMBLER
 
-void Disassembler::Dump(FILE* f, byte* begin, byte* end) {}
-int Disassembler::Decode(Isolate* isolate, FILE* f, byte* begin, byte* end) {
+int Disassembler::Decode(Isolate* isolate, std::ostream* os, byte* begin,
+                         byte* end, Code* code) {
   return 0;
 }
 
-
-void Disassembler::Decode(FILE* f, Code* code) {}
-
 #endif  // ENABLE_DISASSEMBLER
 
 } }  // namespace v8::internal
diff --git a/src/disassembler.h b/src/disassembler.h
index f65f538..32e48c4 100644
--- a/src/disassembler.h
+++ b/src/disassembler.h
@@ -12,22 +12,12 @@
 
 class Disassembler : public AllStatic {
  public:
-  // Print the bytes in the interval [begin, end) into f.
-  static void Dump(FILE* f, byte* begin, byte* end);
-
   // Decode instructions in the the interval [begin, end) and print the
-  // code into f. Returns the number of bytes disassembled or 1 if no
+  // code into os. Returns the number of bytes disassembled or 1 if no
   // instruction could be decoded.
-  static int Decode(Isolate* isolate, FILE* f, byte* begin, byte* end);
-
-  // Decode instructions in code.
-  static void Decode(FILE* f, Code* code);
- private:
-  // Decode instruction at pc and print disassembled instruction into f.
-  // Returns the instruction length in bytes, or 1 if the instruction could
-  // not be decoded.  The number of characters written is written into
-  // the out parameter char_count.
-  static int Decode(FILE* f, byte* pc, int* char_count);
+  // the code object is used for name resolution and may be null.
+  static int Decode(Isolate* isolate, std::ostream* os, byte* begin, byte* end,
+                    Code* code = NULL);
 };
 
 } }  // namespace v8::internal
diff --git a/src/diy-fp.cc b/src/diy-fp.cc
index cdad2a8..b705df0 100644
--- a/src/diy-fp.cc
+++ b/src/diy-fp.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "include/v8stdint.h"
+#include <stdint.h>
 #include "src/base/logging.h"
 #include "src/diy-fp.h"
 #include "src/globals.h"
diff --git a/src/dtoa.cc b/src/dtoa.cc
index f39b0b0..fc02aca 100644
--- a/src/dtoa.cc
+++ b/src/dtoa.cc
@@ -4,7 +4,6 @@
 
 #include <cmath>
 
-#include "include/v8stdint.h"
 #include "src/base/logging.h"
 #include "src/utils.h"
 
diff --git a/src/elements.cc b/src/elements.cc
index e2127c4..4e9a052 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -247,15 +247,18 @@
 }
 
 
-static void CopyDoubleToObjectElements(Handle<FixedArrayBase> from_base,
+// NOTE: this method violates the handlified function signature convention:
+// raw pointer parameters in the function that allocates.
+// See ElementsAccessorBase::CopyElements() for details.
+static void CopyDoubleToObjectElements(FixedArrayBase* from_base,
                                        uint32_t from_start,
-                                       Handle<FixedArrayBase> to_base,
-                                       ElementsKind to_kind,
-                                       uint32_t to_start,
+                                       FixedArrayBase* to_base,
+                                       ElementsKind to_kind, uint32_t to_start,
                                        int raw_copy_size) {
   DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
   int copy_size = raw_copy_size;
   if (raw_copy_size < 0) {
+    DisallowHeapAllocation no_allocation;
     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
     copy_size = Min(from_base->length() - from_start,
@@ -268,7 +271,7 @@
       int length = to_base->length() - start;
       if (length > 0) {
         Heap* heap = from_base->GetHeap();
-        MemsetPointer(FixedArray::cast(*to_base)->data_start() + start,
+        MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
                       heap->the_hole_value(), length);
       }
     }
@@ -276,9 +279,12 @@
   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
          (copy_size + static_cast<int>(from_start)) <= from_base->length());
   if (copy_size == 0) return;
+
+  // From here on, the code below could actually allocate. Therefore the raw
+  // values are wrapped into handles.
   Isolate* isolate = from_base->GetIsolate();
-  Handle<FixedDoubleArray> from = Handle<FixedDoubleArray>::cast(from_base);
-  Handle<FixedArray> to = Handle<FixedArray>::cast(to_base);
+  Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate);
+  Handle<FixedArray> to(FixedArray::cast(to_base), isolate);
   for (int i = 0; i < copy_size; ++i) {
     HandleScope scope(isolate);
     if (IsFastSmiElementsKind(to_kind)) {
@@ -554,9 +560,7 @@
   typedef ElementsTraitsParam ElementsTraits;
   typedef typename ElementsTraitsParam::BackingStore BackingStore;
 
-  virtual ElementsKind kind() const FINAL OVERRIDE {
-    return ElementsTraits::Kind;
-  }
+  ElementsKind kind() const FINAL { return ElementsTraits::Kind; }
 
   static void ValidateContents(Handle<JSObject> holder, int length) {
   }
@@ -578,7 +582,7 @@
     ElementsAccessorSubclass::ValidateContents(holder, length);
   }
 
-  virtual void Validate(Handle<JSObject> holder) FINAL OVERRIDE {
+  void Validate(Handle<JSObject> holder) FINAL {
     DisallowHeapAllocation no_gc;
     ElementsAccessorSubclass::ValidateImpl(holder);
   }
@@ -591,20 +595,16 @@
         receiver, holder, key, backing_store) != ABSENT;
   }
 
-  virtual bool HasElement(
-      Handle<Object> receiver,
-      Handle<JSObject> holder,
-      uint32_t key,
-      Handle<FixedArrayBase> backing_store) FINAL OVERRIDE {
+  virtual bool HasElement(Handle<Object> receiver, Handle<JSObject> holder,
+                          uint32_t key,
+                          Handle<FixedArrayBase> backing_store) FINAL {
     return ElementsAccessorSubclass::HasElementImpl(
         receiver, holder, key, backing_store);
   }
 
   MUST_USE_RESULT virtual MaybeHandle<Object> Get(
-      Handle<Object> receiver,
-      Handle<JSObject> holder,
-      uint32_t key,
-      Handle<FixedArrayBase> backing_store) FINAL OVERRIDE {
+      Handle<Object> receiver, Handle<JSObject> holder, uint32_t key,
+      Handle<FixedArrayBase> backing_store) FINAL {
     if (!IsExternalArrayElementsKind(ElementsTraits::Kind) &&
         FLAG_trace_js_array_abuse) {
       CheckArrayAbuse(holder, "elements read", key);
@@ -632,10 +632,8 @@
   }
 
   MUST_USE_RESULT virtual PropertyAttributes GetAttributes(
-      Handle<Object> receiver,
-      Handle<JSObject> holder,
-      uint32_t key,
-      Handle<FixedArrayBase> backing_store) FINAL OVERRIDE {
+      Handle<Object> receiver, Handle<JSObject> holder, uint32_t key,
+      Handle<FixedArrayBase> backing_store) FINAL {
     return ElementsAccessorSubclass::GetAttributesImpl(
         receiver, holder, key, backing_store);
   }
@@ -654,10 +652,8 @@
   }
 
   MUST_USE_RESULT virtual MaybeHandle<AccessorPair> GetAccessorPair(
-      Handle<Object> receiver,
-      Handle<JSObject> holder,
-      uint32_t key,
-      Handle<FixedArrayBase> backing_store) FINAL OVERRIDE {
+      Handle<Object> receiver, Handle<JSObject> holder, uint32_t key,
+      Handle<FixedArrayBase> backing_store) FINAL {
     return ElementsAccessorSubclass::GetAccessorPairImpl(
         receiver, holder, key, backing_store);
   }
@@ -671,8 +667,7 @@
   }
 
   MUST_USE_RESULT virtual MaybeHandle<Object> SetLength(
-      Handle<JSArray> array,
-      Handle<Object> length) FINAL OVERRIDE {
+      Handle<JSArray> array, Handle<Object> length) FINAL {
     return ElementsAccessorSubclass::SetLengthImpl(
         array, length, handle(array->elements()));
   }
@@ -682,10 +677,8 @@
       Handle<Object> length,
       Handle<FixedArrayBase> backing_store);
 
-  virtual void SetCapacityAndLength(
-      Handle<JSArray> array,
-      int capacity,
-      int length) FINAL OVERRIDE {
+  virtual void SetCapacityAndLength(Handle<JSArray> array, int capacity,
+                                    int length) FINAL {
     ElementsAccessorSubclass::
         SetFastElementsCapacityAndLength(array, capacity, length);
   }
@@ -702,36 +695,31 @@
       uint32_t key,
       JSReceiver::DeleteMode mode) OVERRIDE = 0;
 
-  static void CopyElementsImpl(Handle<FixedArrayBase> from,
-                               uint32_t from_start,
-                               Handle<FixedArrayBase> to,
-                               ElementsKind from_kind,
-                               uint32_t to_start,
-                               int packed_size,
+  static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
+                               FixedArrayBase* to, ElementsKind from_kind,
+                               uint32_t to_start, int packed_size,
                                int copy_size) {
     UNREACHABLE();
   }
 
-  virtual void CopyElements(
-      Handle<FixedArrayBase> from,
-      uint32_t from_start,
-      ElementsKind from_kind,
-      Handle<FixedArrayBase> to,
-      uint32_t to_start,
-      int copy_size) FINAL OVERRIDE {
+  virtual void CopyElements(Handle<FixedArrayBase> from, uint32_t from_start,
+                            ElementsKind from_kind, Handle<FixedArrayBase> to,
+                            uint32_t to_start, int copy_size) FINAL {
     DCHECK(!from.is_null());
-    ElementsAccessorSubclass::CopyElementsImpl(
-        from, from_start, to, from_kind, to_start, kPackedSizeNotKnown,
-        copy_size);
+    // NOTE: the ElementsAccessorSubclass::CopyElementsImpl() methods
+    // violate the handlified function signature convention:
+    // raw pointer parameters in the function that allocates. This is done
+    // intentionally to avoid ArrayConcat() builtin performance degradation.
+    // See the comment in another ElementsAccessorBase::CopyElements() for
+    // details.
+    ElementsAccessorSubclass::CopyElementsImpl(*from, from_start, *to,
+                                               from_kind, to_start,
+                                               kPackedSizeNotKnown, copy_size);
   }
 
-  virtual void CopyElements(
-      JSObject* from_holder,
-      uint32_t from_start,
-      ElementsKind from_kind,
-      Handle<FixedArrayBase> to,
-      uint32_t to_start,
-      int copy_size) FINAL OVERRIDE {
+  virtual void CopyElements(JSObject* from_holder, uint32_t from_start,
+                            ElementsKind from_kind, Handle<FixedArrayBase> to,
+                            uint32_t to_start, int copy_size) FINAL {
     int packed_size = kPackedSizeNotKnown;
     bool is_packed = IsFastPackedElementsKind(from_kind) &&
         from_holder->IsJSArray();
@@ -742,16 +730,23 @@
         packed_size = copy_size;
       }
     }
-    Handle<FixedArrayBase> from(from_holder->elements());
+    FixedArrayBase* from = from_holder->elements();
+    // NOTE: the ElementsAccessorSubclass::CopyElementsImpl() methods
+    // violate the handlified function signature convention:
+    // raw pointer parameters in the function that allocates. This is done
+    // intentionally to avoid ArrayConcat() builtin performance degradation.
+    //
+    // Details: The idea is that allocations actually happen only in case of
+    // copying from object with fast double elements to object with object
+    // elements. In all the other cases there are no allocations performed and
+    // handle creation causes noticeable performance degradation of the builtin.
     ElementsAccessorSubclass::CopyElementsImpl(
-        from, from_start, to, from_kind, to_start, packed_size, copy_size);
+        from, from_start, *to, from_kind, to_start, packed_size, copy_size);
   }
 
   virtual MaybeHandle<FixedArray> AddElementsToFixedArray(
-      Handle<Object> receiver,
-      Handle<JSObject> holder,
-      Handle<FixedArray> to,
-      Handle<FixedArrayBase> from) FINAL OVERRIDE {
+      Handle<Object> receiver, Handle<JSObject> holder, Handle<FixedArray> to,
+      Handle<FixedArrayBase> from, FixedArray::KeyFilter filter) FINAL {
     int len0 = to->length();
 #ifdef ENABLE_SLOW_DCHECKS
     if (FLAG_enable_slow_asserts) {
@@ -781,6 +776,9 @@
             FixedArray);
 
         DCHECK(!value->IsTheHole());
+        if (filter == FixedArray::NON_SYMBOL_KEYS && value->IsSymbol()) {
+          continue;
+        }
         if (!HasKey(to, value)) {
           extra++;
         }
@@ -814,6 +812,9 @@
             isolate, value,
             ElementsAccessorSubclass::GetImpl(receiver, holder, key, from),
             FixedArray);
+        if (filter == FixedArray::NON_SYMBOL_KEYS && value->IsSymbol()) {
+          continue;
+        }
         if (!value->IsTheHole() && !HasKey(to, value)) {
           result->set(len0 + index, *value);
           index++;
@@ -829,8 +830,7 @@
     return backing_store->length();
   }
 
-  virtual uint32_t GetCapacity(Handle<FixedArrayBase> backing_store)
-      FINAL OVERRIDE {
+  uint32_t GetCapacity(Handle<FixedArrayBase> backing_store) FINAL {
     return ElementsAccessorSubclass::GetCapacityImpl(backing_store);
   }
 
@@ -840,7 +840,7 @@
   }
 
   virtual uint32_t GetKeyForIndex(Handle<FixedArrayBase> backing_store,
-                                  uint32_t index) FINAL OVERRIDE {
+                                  uint32_t index) FINAL {
     return ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, index);
   }
 
@@ -974,10 +974,8 @@
     return isolate->factory()->true_value();
   }
 
-  virtual MaybeHandle<Object> Delete(
-      Handle<JSObject> obj,
-      uint32_t key,
-      JSReceiver::DeleteMode mode) FINAL OVERRIDE {
+  virtual MaybeHandle<Object> Delete(Handle<JSObject> obj, uint32_t key,
+                                     JSReceiver::DeleteMode mode) FINAL {
     return DeleteCommon(obj, key, mode);
   }
 
@@ -1018,7 +1016,7 @@
 };
 
 
-static inline ElementsKind ElementsKindForArray(Handle<FixedArrayBase> array) {
+static inline ElementsKind ElementsKindForArray(FixedArrayBase* array) {
   switch (array->map()->instance_type()) {
     case FIXED_ARRAY_TYPE:
       if (array->IsDictionary()) {
@@ -1054,38 +1052,42 @@
       : FastElementsAccessor<FastElementsAccessorSubclass,
                              KindTraits>(name) {}
 
-  static void CopyElementsImpl(Handle<FixedArrayBase> from,
-                               uint32_t from_start,
-                               Handle<FixedArrayBase> to,
-                               ElementsKind from_kind,
-                               uint32_t to_start,
-                               int packed_size,
+  // NOTE: this method violates the handlified function signature convention:
+  // raw pointer parameters in the function that allocates.
+  // See ElementsAccessor::CopyElements() for details.
+  // This method could actually allocate if copying from double elements to
+  // object elements.
+  static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
+                               FixedArrayBase* to, ElementsKind from_kind,
+                               uint32_t to_start, int packed_size,
                                int copy_size) {
+    DisallowHeapAllocation no_gc;
     ElementsKind to_kind = KindTraits::Kind;
     switch (from_kind) {
       case FAST_SMI_ELEMENTS:
       case FAST_HOLEY_SMI_ELEMENTS:
       case FAST_ELEMENTS:
       case FAST_HOLEY_ELEMENTS:
-        CopyObjectToObjectElements(*from, from_kind, from_start, *to, to_kind,
+        CopyObjectToObjectElements(from, from_kind, from_start, to, to_kind,
                                    to_start, copy_size);
         break;
       case FAST_DOUBLE_ELEMENTS:
-      case FAST_HOLEY_DOUBLE_ELEMENTS:
+      case FAST_HOLEY_DOUBLE_ELEMENTS: {
+        AllowHeapAllocation allow_allocation;
         CopyDoubleToObjectElements(
             from, from_start, to, to_kind, to_start, copy_size);
         break;
+      }
       case DICTIONARY_ELEMENTS:
-        CopyDictionaryToObjectElements(*from, from_start, *to, to_kind,
-                                       to_start, copy_size);
+        CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start,
+                                       copy_size);
         break;
       case SLOPPY_ARGUMENTS_ELEMENTS: {
         // TODO(verwaest): This is a temporary hack to support extending
         // SLOPPY_ARGUMENTS_ELEMENTS in SetFastElementsCapacityAndLength.
         // This case should be UNREACHABLE().
-        Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(from);
-        Handle<FixedArrayBase> arguments(
-            FixedArrayBase::cast(parameter_map->get(1)));
+        FixedArray* parameter_map = FixedArray::cast(from);
+        FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
         ElementsKind from_kind = ElementsKindForArray(arguments);
         CopyElementsImpl(arguments, from_start, to, from_kind,
                          to_start, packed_size, copy_size);
@@ -1179,31 +1181,29 @@
   }
 
  protected:
-  static void CopyElementsImpl(Handle<FixedArrayBase> from,
-                               uint32_t from_start,
-                               Handle<FixedArrayBase> to,
-                               ElementsKind from_kind,
-                               uint32_t to_start,
-                               int packed_size,
+  static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
+                               FixedArrayBase* to, ElementsKind from_kind,
+                               uint32_t to_start, int packed_size,
                                int copy_size) {
+    DisallowHeapAllocation no_allocation;
     switch (from_kind) {
       case FAST_SMI_ELEMENTS:
-        CopyPackedSmiToDoubleElements(*from, from_start, *to, to_start,
+        CopyPackedSmiToDoubleElements(from, from_start, to, to_start,
                                       packed_size, copy_size);
         break;
       case FAST_HOLEY_SMI_ELEMENTS:
-        CopySmiToDoubleElements(*from, from_start, *to, to_start, copy_size);
+        CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
         break;
       case FAST_DOUBLE_ELEMENTS:
       case FAST_HOLEY_DOUBLE_ELEMENTS:
-        CopyDoubleToDoubleElements(*from, from_start, *to, to_start, copy_size);
+        CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
         break;
       case FAST_ELEMENTS:
       case FAST_HOLEY_ELEMENTS:
-        CopyObjectToDoubleElements(*from, from_start, *to, to_start, copy_size);
+        CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
         break;
       case DICTIONARY_ELEMENTS:
-        CopyDictionaryToDoubleElements(*from, from_start, *to, to_start,
+        CopyDictionaryToDoubleElements(from, from_start, to, to_start,
                                        copy_size);
         break;
       case SLOPPY_ARGUMENTS_ELEMENTS:
@@ -1298,9 +1298,7 @@
   }
 
   MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
-      Handle<JSObject> obj,
-      uint32_t key,
-      JSReceiver::DeleteMode mode) FINAL OVERRIDE {
+      Handle<JSObject> obj, uint32_t key, JSReceiver::DeleteMode mode) FINAL {
     // External arrays always ignore deletes.
     return obj->GetIsolate()->factory()->true_value();
   }
@@ -1439,12 +1437,9 @@
     return isolate->factory()->true_value();
   }
 
-  static void CopyElementsImpl(Handle<FixedArrayBase> from,
-                               uint32_t from_start,
-                               Handle<FixedArrayBase> to,
-                               ElementsKind from_kind,
-                               uint32_t to_start,
-                               int packed_size,
+  static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
+                               FixedArrayBase* to, ElementsKind from_kind,
+                               uint32_t to_start, int packed_size,
                                int copy_size) {
     UNREACHABLE();
   }
@@ -1455,9 +1450,7 @@
                                     ElementsKindTraits<DICTIONARY_ELEMENTS> >;
 
   MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
-      Handle<JSObject> obj,
-      uint32_t key,
-      JSReceiver::DeleteMode mode) FINAL OVERRIDE {
+      Handle<JSObject> obj, uint32_t key, JSReceiver::DeleteMode mode) FINAL {
     return DeleteCommon(obj, key, mode);
   }
 
@@ -1629,9 +1622,7 @@
   }
 
   MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
-      Handle<JSObject> obj,
-      uint32_t key,
-      JSReceiver::DeleteMode mode) FINAL OVERRIDE {
+      Handle<JSObject> obj, uint32_t key, JSReceiver::DeleteMode mode) FINAL {
     Isolate* isolate = obj->GetIsolate();
     Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
     Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
@@ -1654,12 +1645,9 @@
     return isolate->factory()->true_value();
   }
 
-  static void CopyElementsImpl(Handle<FixedArrayBase> from,
-                               uint32_t from_start,
-                               Handle<FixedArrayBase> to,
-                               ElementsKind from_kind,
-                               uint32_t to_start,
-                               int packed_size,
+  static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
+                               FixedArrayBase* to, ElementsKind from_kind,
+                               uint32_t to_start, int packed_size,
                                int copy_size) {
     UNREACHABLE();
   }
@@ -1715,7 +1703,7 @@
 
 
 ElementsAccessor* ElementsAccessor::ForArray(Handle<FixedArrayBase> array) {
-  return elements_accessors_[ElementsKindForArray(array)];
+  return elements_accessors_[ElementsKindForArray(*array)];
 }
 
 
diff --git a/src/elements.h b/src/elements.h
index d0bddf9..05354ea 100644
--- a/src/elements.h
+++ b/src/elements.h
@@ -146,9 +146,10 @@
       uint32_t destination_start,
       int copy_size) = 0;
 
-  // TODO(ishell): Keeping |source_holder| parameter in a non-handlified form
-  // helps avoiding ArrayConcat() builtin performance degradation.
-  // Revisit this later.
+  // NOTE: this method violates the handlified function signature convention:
+  // raw pointer parameter |source_holder| in the function that allocates.
+  // This is done intentionally to avoid ArrayConcat() builtin performance
+  // degradation.
   virtual void CopyElements(
       JSObject* source_holder,
       uint32_t source_start,
@@ -166,22 +167,19 @@
   }
 
   MUST_USE_RESULT virtual MaybeHandle<FixedArray> AddElementsToFixedArray(
-      Handle<Object> receiver,
-      Handle<JSObject> holder,
-      Handle<FixedArray> to,
-      Handle<FixedArrayBase> from) = 0;
+      Handle<Object> receiver, Handle<JSObject> holder, Handle<FixedArray> to,
+      Handle<FixedArrayBase> from, FixedArray::KeyFilter filter) = 0;
 
   MUST_USE_RESULT inline MaybeHandle<FixedArray> AddElementsToFixedArray(
-      Handle<Object> receiver,
-      Handle<JSObject> holder,
-      Handle<FixedArray> to) {
-    return AddElementsToFixedArray(
-        receiver, holder, to, handle(holder->elements()));
+      Handle<Object> receiver, Handle<JSObject> holder, Handle<FixedArray> to,
+      FixedArray::KeyFilter filter) {
+    return AddElementsToFixedArray(receiver, holder, to,
+                                   handle(holder->elements()), filter);
   }
 
   // Returns a shared ElementsAccessor for the specified ElementsKind.
   static ElementsAccessor* ForKind(ElementsKind elements_kind) {
-    DCHECK(elements_kind < kElementsKindCount);
+    DCHECK(static_cast<int>(elements_kind) < kElementsKindCount);
     return elements_accessors_[elements_kind];
   }
 
diff --git a/src/execution.cc b/src/execution.cc
index 7aa4f33..a85effd 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -34,6 +34,17 @@
 }
 
 
+static void PrintDeserializedCodeInfo(Handle<JSFunction> function) {
+  if (function->code() == function->shared()->code() &&
+      function->shared()->deserialized()) {
+    PrintF("Running deserialized script ");
+    Object* script = function->shared()->script();
+    if (script->IsScript()) Script::cast(script)->name()->ShortPrint();
+    PrintF("\n");
+  }
+}
+
+
 MUST_USE_RESULT static MaybeHandle<Object> Invoke(
     bool is_construct,
     Handle<JSFunction> function,
@@ -87,6 +98,7 @@
     JSFunction* func = *function;
     Object* recv = *receiver;
     Object*** argv = reinterpret_cast<Object***>(args);
+    if (FLAG_profile_deserialization) PrintDeserializedCodeInfo(function);
     value =
         CALL_GENERATED_CODE(stub_entry, function_entry, func, recv, argc, argv);
   }
@@ -533,6 +545,12 @@
 }
 
 
+MaybeHandle<Object> Execution::ToLength(
+    Isolate* isolate, Handle<Object> obj) {
+  RETURN_NATIVE_CALL(to_length, { obj });
+}
+
+
 MaybeHandle<Object> Execution::NewDate(Isolate* isolate, double time) {
   Handle<Object> time_obj = isolate->factory()->NewNumber(time);
   RETURN_NATIVE_CALL(create_date, { time_obj });
@@ -695,8 +713,8 @@
   }
 
   if (CheckAndClearInterrupt(API_INTERRUPT)) {
-    // Callback must be invoked outside of ExecusionAccess lock.
-    isolate_->InvokeApiInterruptCallback();
+    // Callbacks must be invoked outside of ExecusionAccess lock.
+    isolate_->InvokeApiInterruptCallbacks();
   }
 
   isolate_->counters()->stack_interrupts()->Increment();
diff --git a/src/execution.h b/src/execution.h
index 89175cd..ae263bd 100644
--- a/src/execution.h
+++ b/src/execution.h
@@ -69,6 +69,11 @@
   MUST_USE_RESULT static MaybeHandle<Object> ToUint32(
       Isolate* isolate, Handle<Object> obj);
 
+
+  // ES6, draft 10-14-14, section 7.1.15
+  MUST_USE_RESULT static MaybeHandle<Object> ToLength(
+      Isolate* isolate, Handle<Object> obj);
+
   // ECMA-262 9.8
   MUST_USE_RESULT static MaybeHandle<Object> ToString(
       Isolate* isolate, Handle<Object> obj);
diff --git a/src/extensions/statistics-extension.cc b/src/extensions/statistics-extension.cc
index 6f63245..bb5ee33 100644
--- a/src/extensions/statistics-extension.cc
+++ b/src/extensions/statistics-extension.cc
@@ -53,7 +53,8 @@
   Heap* heap = isolate->heap();
 
   if (args.Length() > 0) {  // GC if first argument evaluates to true.
-    if (args[0]->IsBoolean() && args[0]->ToBoolean()->Value()) {
+    if (args[0]->IsBoolean() &&
+        args[0]->ToBoolean(args.GetIsolate())->Value()) {
       heap->CollectAllGarbage(Heap::kNoGCFlags, "counters extension");
     }
   }
diff --git a/src/factory.cc b/src/factory.cc
index 45a79c1..ba62341 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -139,12 +139,12 @@
 
 
 Handle<OrderedHashSet> Factory::NewOrderedHashSet() {
-  return OrderedHashSet::Allocate(isolate(), 4);
+  return OrderedHashSet::Allocate(isolate(), OrderedHashSet::kMinCapacity);
 }
 
 
 Handle<OrderedHashMap> Factory::NewOrderedHashMap() {
-  return OrderedHashMap::Allocate(isolate(), 4);
+  return OrderedHashMap::Allocate(isolate(), OrderedHashMap::kMinCapacity);
 }
 
 
@@ -693,21 +693,31 @@
 }
 
 
-Handle<Context> Factory::NewGlobalContext(Handle<JSFunction> function,
+Handle<Context> Factory::NewScriptContext(Handle<JSFunction> function,
                                           Handle<ScopeInfo> scope_info) {
   Handle<FixedArray> array =
       NewFixedArray(scope_info->ContextLength(), TENURED);
-  array->set_map_no_write_barrier(*global_context_map());
+  array->set_map_no_write_barrier(*script_context_map());
   Handle<Context> context = Handle<Context>::cast(array);
   context->set_closure(*function);
   context->set_previous(function->context());
   context->set_extension(*scope_info);
   context->set_global_object(function->context()->global_object());
-  DCHECK(context->IsGlobalContext());
+  DCHECK(context->IsScriptContext());
   return context;
 }
 
 
+Handle<ScriptContextTable> Factory::NewScriptContextTable() {
+  Handle<FixedArray> array = NewFixedArray(1);
+  array->set_map_no_write_barrier(*script_context_table_map());
+  Handle<ScriptContextTable> context_table =
+      Handle<ScriptContextTable>::cast(array);
+  context_table->set_used(0);
+  return context_table;
+}
+
+
 Handle<Context> Factory::NewModuleContext(Handle<ScopeInfo> scope_info) {
   Handle<FixedArray> array =
       NewFixedArray(scope_info->ContextLength(), TENURED);
@@ -792,6 +802,7 @@
       Handle<CodeCache>::cast(NewStruct(CODE_CACHE_TYPE));
   code_cache->set_default_cache(*empty_fixed_array(), SKIP_WRITE_BARRIER);
   code_cache->set_normal_type_cache(*undefined_value(), SKIP_WRITE_BARRIER);
+  code_cache->set_weak_cell_cache(*undefined_value(), SKIP_WRITE_BARRIER);
   return code_cache;
 }
 
@@ -837,7 +848,6 @@
   heap->set_last_script_id(Smi::FromInt(id));
 
   // Create and initialize script object.
-  Handle<Foreign> wrapper = NewForeign(0, TENURED);
   Handle<Script> script = Handle<Script>::cast(NewStruct(SCRIPT_TYPE));
   script->set_source(*source);
   script->set_name(heap->undefined_value());
@@ -846,7 +856,7 @@
   script->set_column_offset(Smi::FromInt(0));
   script->set_context_data(heap->undefined_value());
   script->set_type(Smi::FromInt(Script::TYPE_NORMAL));
-  script->set_wrapper(*wrapper);
+  script->set_wrapper(heap->undefined_value());
   script->set_line_ends(heap->undefined_value());
   script->set_eval_from_shared(heap->undefined_value());
   script->set_eval_from_instructions_offset(Smi::FromInt(0));
@@ -931,6 +941,13 @@
 }
 
 
+Handle<WeakCell> Factory::NewWeakCell(Handle<HeapObject> value) {
+  AllowDeferredHandleDereference convert_to_cell;
+  CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->AllocateWeakCell(*value),
+                     WeakCell);
+}
+
+
 Handle<AllocationSite> Factory::NewAllocationSite() {
   Handle<Map> map = allocation_site_map();
   Handle<AllocationSite> site = New<AllocationSite>(map, OLD_POINTER_SPACE);
@@ -1018,7 +1035,7 @@
   // patterns is faster than using fpclassify() et al.
   if (IsMinusZero(value)) return NewHeapNumber(-0.0, IMMUTABLE, pretenure);
 
-  int int_value = FastD2I(value);
+  int int_value = FastD2IChecked(value);
   if (value == int_value && Smi::IsValid(int_value)) {
     return handle(Smi::FromInt(int_value), isolate());
   }
@@ -1292,20 +1309,25 @@
 }
 
 
-Handle<JSFunction> Factory::NewFunction(Handle<String> name,
-                                        Handle<Code> code,
+Handle<JSFunction> Factory::NewFunction(Handle<String> name, Handle<Code> code,
                                         Handle<Object> prototype,
-                                        InstanceType type,
-                                        int instance_size,
-                                        bool read_only_prototype) {
+                                        InstanceType type, int instance_size,
+                                        bool read_only_prototype,
+                                        bool install_constructor) {
   // Allocate the function
   Handle<JSFunction> function = NewFunction(
       name, code, prototype, read_only_prototype);
 
-  Handle<Map> initial_map = NewMap(
-      type, instance_size, GetInitialFastElementsKind());
-  if (prototype->IsTheHole() && !function->shared()->is_generator()) {
-    prototype = NewFunctionPrototype(function);
+  ElementsKind elements_kind =
+      type == JS_ARRAY_TYPE ? FAST_SMI_ELEMENTS : FAST_HOLEY_SMI_ELEMENTS;
+  Handle<Map> initial_map = NewMap(type, instance_size, elements_kind);
+  if (!function->shared()->is_generator()) {
+    if (prototype->IsTheHole()) {
+      prototype = NewFunctionPrototype(function);
+    } else if (install_constructor) {
+      JSObject::AddProperty(Handle<JSObject>::cast(prototype),
+                            constructor_string(), function, DONT_ENUM);
+    }
   }
 
   JSFunction::SetInitialMap(function, initial_map,
@@ -1351,6 +1373,14 @@
 }
 
 
+static bool ShouldOptimizeNewClosure(Isolate* isolate,
+                                     Handle<SharedFunctionInfo> info) {
+  return isolate->use_crankshaft() && !info->is_toplevel() &&
+         info->is_compiled() && info->allows_lazy_compilation() &&
+         !info->optimization_disabled() && !isolate->DebuggerHasBreakPoints();
+}
+
+
 Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
     Handle<SharedFunctionInfo> info,
     Handle<Context> context,
@@ -1388,13 +1418,7 @@
     return result;
   }
 
-  if (isolate()->use_crankshaft() &&
-      FLAG_always_opt &&
-      result->is_compiled() &&
-      !info->is_toplevel() &&
-      info->allows_lazy_compilation() &&
-      !info->optimization_disabled() &&
-      !isolate()->DebuggerHasBreakPoints()) {
+  if (FLAG_always_opt && ShouldOptimizeNewClosure(isolate(), info)) {
     result->MarkForOptimization();
   }
   return result;
@@ -1568,7 +1592,7 @@
   for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
     PropertyDetails details = descs->GetDetails(i);
     DCHECK(details.type() == CALLBACKS);  // Only accessors are expected.
-    PropertyDetails d = PropertyDetails(details.attributes(), CALLBACKS, i + 1);
+    PropertyDetails d(details.attributes(), CALLBACKS, i + 1);
     Handle<Name> name(descs->GetKey(i));
     Handle<Object> value(descs->GetCallbacksObject(i), isolate());
     Handle<PropertyCell> cell = NewPropertyCell(value);
@@ -1658,6 +1682,7 @@
     return;
   }
 
+  HandleScope inner_scope(isolate());
   Handle<FixedArrayBase> elms;
   ElementsKind elements_kind = array->GetElementsKind();
   if (IsFastDoubleElementsKind(elements_kind)) {
@@ -1715,8 +1740,51 @@
 }
 
 
-static JSFunction* GetTypedArrayFun(ExternalArrayType type,
-                                    Isolate* isolate) {
+Handle<JSMapIterator> Factory::NewJSMapIterator() {
+  Handle<Map> map(isolate()->native_context()->map_iterator_map());
+  CALL_HEAP_FUNCTION(isolate(),
+                     isolate()->heap()->AllocateJSObjectFromMap(*map),
+                     JSMapIterator);
+}
+
+
+Handle<JSSetIterator> Factory::NewJSSetIterator() {
+  Handle<Map> map(isolate()->native_context()->set_iterator_map());
+  CALL_HEAP_FUNCTION(isolate(),
+                     isolate()->heap()->AllocateJSObjectFromMap(*map),
+                     JSSetIterator);
+}
+
+
+namespace {
+
+ElementsKind GetExternalArrayElementsKind(ExternalArrayType type) {
+  switch (type) {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+  case kExternal##Type##Array:                          \
+    return EXTERNAL_##TYPE##_ELEMENTS;
+    TYPED_ARRAYS(TYPED_ARRAY_CASE)
+  }
+  UNREACHABLE();
+  return FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND;
+#undef TYPED_ARRAY_CASE
+}
+
+
+size_t GetExternalArrayElementSize(ExternalArrayType type) {
+  switch (type) {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+  case kExternal##Type##Array:                          \
+    return size;
+    TYPED_ARRAYS(TYPED_ARRAY_CASE)
+  }
+  UNREACHABLE();
+  return 0;
+#undef TYPED_ARRAY_CASE
+}
+
+
+JSFunction* GetTypedArrayFun(ExternalArrayType type, Isolate* isolate) {
   Context* native_context = isolate->context()->native_context();
   switch (type) {
 #define TYPED_ARRAY_FUN(Type, type, TYPE, ctype, size)                        \
@@ -1733,6 +1801,31 @@
 }
 
 
+void SetupArrayBufferView(i::Isolate* isolate,
+                          i::Handle<i::JSArrayBufferView> obj,
+                          i::Handle<i::JSArrayBuffer> buffer,
+                          size_t byte_offset, size_t byte_length) {
+  DCHECK(byte_offset + byte_length <=
+         static_cast<size_t>(buffer->byte_length()->Number()));
+
+  obj->set_buffer(*buffer);
+
+  obj->set_weak_next(buffer->weak_first_view());
+  buffer->set_weak_first_view(*obj);
+
+  i::Handle<i::Object> byte_offset_object =
+      isolate->factory()->NewNumberFromSize(byte_offset);
+  obj->set_byte_offset(*byte_offset_object);
+
+  i::Handle<i::Object> byte_length_object =
+      isolate->factory()->NewNumberFromSize(byte_length);
+  obj->set_byte_length(*byte_length_object);
+}
+
+
+}  // namespace
+
+
 Handle<JSTypedArray> Factory::NewJSTypedArray(ExternalArrayType type) {
   Handle<JSFunction> typed_array_fun_handle(GetTypedArrayFun(type, isolate()));
 
@@ -1743,13 +1836,50 @@
 }
 
 
+Handle<JSTypedArray> Factory::NewJSTypedArray(ExternalArrayType type,
+                                              Handle<JSArrayBuffer> buffer,
+                                              size_t byte_offset,
+                                              size_t length) {
+  Handle<JSTypedArray> obj = NewJSTypedArray(type);
+
+  size_t element_size = GetExternalArrayElementSize(type);
+  ElementsKind elements_kind = GetExternalArrayElementsKind(type);
+
+  CHECK(byte_offset % element_size == 0);
+
+  CHECK(length <= (std::numeric_limits<size_t>::max() / element_size));
+  CHECK(length <= static_cast<size_t>(Smi::kMaxValue));
+  size_t byte_length = length * element_size;
+  SetupArrayBufferView(isolate(), obj, buffer, byte_offset, byte_length);
+
+  Handle<Object> length_object = NewNumberFromSize(length);
+  obj->set_length(*length_object);
+
+  Handle<ExternalArray> elements = NewExternalArray(
+      static_cast<int>(length), type,
+      static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
+  Handle<Map> map = JSObject::GetElementsTransitionMap(obj, elements_kind);
+  JSObject::SetMapAndElements(obj, map, elements);
+  return obj;
+}
+
+
+Handle<JSDataView> Factory::NewJSDataView(Handle<JSArrayBuffer> buffer,
+                                          size_t byte_offset,
+                                          size_t byte_length) {
+  Handle<JSDataView> obj = NewJSDataView();
+  SetupArrayBufferView(isolate(), obj, buffer, byte_offset, byte_length);
+  return obj;
+}
+
+
 Handle<JSProxy> Factory::NewJSProxy(Handle<Object> handler,
                                     Handle<Object> prototype) {
   // Allocate map.
   // TODO(rossberg): Once we optimize proxies, think about a scheme to share
   // maps. Will probably depend on the identity of the handler object, too.
   Handle<Map> map = NewMap(JS_PROXY_TYPE, JSProxy::kSize);
-  map->set_prototype(*prototype);
+  map->SetPrototype(prototype);
 
   // Allocate the proxy object.
   Handle<JSProxy> result = New<JSProxy>(map, NEW_SPACE);
@@ -1768,7 +1898,7 @@
   // TODO(rossberg): Once we optimize proxies, think about a scheme to share
   // maps. Will probably depend on the identity of the handler object, too.
   Handle<Map> map = NewMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
-  map->set_prototype(*prototype);
+  map->SetPrototype(prototype);
 
   // Allocate the proxy object.
   Handle<JSFunctionProxy> result = New<JSFunctionProxy>(map, NEW_SPACE);
@@ -1793,7 +1923,7 @@
   int size_difference = proxy->map()->instance_size() - map->instance_size();
   DCHECK(size_difference >= 0);
 
-  map->set_prototype(proxy->map()->prototype());
+  map->SetPrototype(handle(proxy->map()->prototype(), proxy->GetIsolate()));
 
   // Allocate the backing storage for the properties.
   int prop_size = map->InitialPropertiesLength();
@@ -1886,20 +2016,9 @@
 }
 
 
-Handle<TypeFeedbackVector> Factory::NewTypeFeedbackVector(int slot_count) {
-  // Ensure we can skip the write barrier
-  DCHECK_EQ(isolate()->heap()->uninitialized_symbol(),
-            *TypeFeedbackVector::UninitializedSentinel(isolate()));
-
-  if (slot_count == 0) {
-    return Handle<TypeFeedbackVector>::cast(empty_fixed_array());
-  }
-
-  CALL_HEAP_FUNCTION(isolate(),
-                     isolate()->heap()->AllocateFixedArrayWithFiller(
-                         slot_count, TENURED,
-                         *TypeFeedbackVector::UninitializedSentinel(isolate())),
-                     TypeFeedbackVector);
+Handle<TypeFeedbackVector> Factory::NewTypeFeedbackVector(
+    const FeedbackVectorSpec& spec) {
+  return TypeFeedbackVector::Allocate(isolate(), spec);
 }
 
 
@@ -1974,8 +2093,13 @@
   share->set_script(*undefined_value(), SKIP_WRITE_BARRIER);
   share->set_debug_info(*undefined_value(), SKIP_WRITE_BARRIER);
   share->set_inferred_name(*empty_string(), SKIP_WRITE_BARRIER);
-  Handle<TypeFeedbackVector> feedback_vector = NewTypeFeedbackVector(0);
+  FeedbackVectorSpec empty_spec;
+  Handle<TypeFeedbackVector> feedback_vector =
+      NewTypeFeedbackVector(empty_spec);
   share->set_feedback_vector(*feedback_vector, SKIP_WRITE_BARRIER);
+#if TRACE_MAPS
+  share->set_unique_id(isolate()->GetNextUniqueSharedFunctionInfoId());
+#endif
   share->set_profiler_ticks(0);
   share->set_ast_node_count(0);
   share->set_counters(0);
@@ -2033,7 +2157,7 @@
       // cache in the snapshot to keep  boot-time memory usage down.
       // If we expand the number string cache already while creating
       // the snapshot then that didn't work out.
-      DCHECK(!isolate()->serializer_enabled() || FLAG_extra_code != NULL);
+      DCHECK(!isolate()->serializer_enabled());
       Handle<FixedArray> new_cache = NewFixedArray(full_size, TENURED);
       isolate()->heap()->set_number_string_cache(*new_cache);
       return;
@@ -2164,8 +2288,8 @@
         break;
     }
 
-    result = NewFunction(empty_string(), code, prototype, type,
-                         instance_size, obj->read_only_prototype());
+    result = NewFunction(empty_string(), code, prototype, type, instance_size,
+                         obj->read_only_prototype(), true);
   }
 
   result->shared()->set_length(obj->length());
@@ -2185,19 +2309,13 @@
     return result;
   }
 
-  if (prototype->IsTheHole()) {
 #ifdef DEBUG
-    LookupIterator it(handle(JSObject::cast(result->prototype())),
-                      constructor_string(),
-                      LookupIterator::OWN_SKIP_INTERCEPTOR);
-    MaybeHandle<Object> maybe_prop = Object::GetProperty(&it);
-    DCHECK(it.IsFound());
-    DCHECK(maybe_prop.ToHandleChecked().is_identical_to(result));
+  LookupIterator it(handle(JSObject::cast(result->prototype())),
+                    constructor_string(), LookupIterator::OWN_SKIP_INTERCEPTOR);
+  MaybeHandle<Object> maybe_prop = Object::GetProperty(&it);
+  DCHECK(it.IsFound());
+  DCHECK(maybe_prop.ToHandleChecked().is_identical_to(result));
 #endif
-  } else {
-    JSObject::AddProperty(handle(JSObject::cast(result->prototype())),
-                          constructor_string(), result, DONT_ENUM);
-  }
 
   // Down from here is only valid for API functions that can be used as a
   // constructor (don't set the "remove prototype" flag).
@@ -2306,35 +2424,42 @@
 }
 
 
-Handle<MapCache> Factory::AddToMapCache(Handle<Context> context,
-                                        Handle<FixedArray> keys,
-                                        Handle<Map> map) {
-  Handle<MapCache> map_cache = handle(MapCache::cast(context->map_cache()));
-  Handle<MapCache> result = MapCache::Put(map_cache, keys, map);
-  context->set_map_cache(*result);
-  return result;
-}
-
-
 Handle<Map> Factory::ObjectLiteralMapFromCache(Handle<Context> context,
-                                               Handle<FixedArray> keys) {
+                                               int number_of_properties,
+                                               bool* is_result_from_cache) {
+  const int kMapCacheSize = 128;
+
+  if (number_of_properties > kMapCacheSize) {
+    *is_result_from_cache = false;
+    return Map::Create(isolate(), number_of_properties);
+  }
+  *is_result_from_cache = true;
+  if (number_of_properties == 0) {
+    // Reuse the initial map of the Object function if the literal has no
+    // predeclared properties.
+    return handle(context->object_function()->initial_map(), isolate());
+  }
+  int cache_index = number_of_properties - 1;
   if (context->map_cache()->IsUndefined()) {
     // Allocate the new map cache for the native context.
-    Handle<MapCache> new_cache = MapCache::New(isolate(), 24);
+    Handle<FixedArray> new_cache = NewFixedArray(kMapCacheSize, TENURED);
     context->set_map_cache(*new_cache);
   }
   // Check to see whether there is a matching element in the cache.
-  Handle<MapCache> cache =
-      Handle<MapCache>(MapCache::cast(context->map_cache()));
-  Handle<Object> result = Handle<Object>(cache->Lookup(*keys), isolate());
-  if (result->IsMap()) return Handle<Map>::cast(result);
-  int length = keys->length();
-  // Create a new map and add it to the cache. Reuse the initial map of the
-  // Object function if the literal has no predeclared properties.
-  Handle<Map> map = length == 0
-                        ? handle(context->object_function()->initial_map())
-                        : Map::Create(isolate(), length);
-  AddToMapCache(context, keys, map);
+  Handle<FixedArray> cache(FixedArray::cast(context->map_cache()));
+  {
+    Object* result = cache->get(cache_index);
+    if (result->IsWeakCell()) {
+      WeakCell* cell = WeakCell::cast(result);
+      if (!cell->cleared()) {
+        return handle(Map::cast(cell->value()), isolate());
+      }
+    }
+  }
+  // Create a new map and add it to the cache.
+  Handle<Map> map = Map::Create(isolate(), number_of_properties);
+  Handle<WeakCell> cell = NewWeakCell(map);
+  cache->set(cache_index, *cell);
   return map;
 }
 
@@ -2353,6 +2478,7 @@
   regexp->set_data(*store);
 }
 
+
 void Factory::SetRegExpIrregexpData(Handle<JSRegExp> regexp,
                                     JSRegExp::Type type,
                                     Handle<String> source,
@@ -2374,7 +2500,6 @@
 }
 
 
-
 MaybeHandle<FunctionTemplateInfo> Factory::ConfigureInstance(
     Handle<FunctionTemplateInfo> desc, Handle<JSObject> instance) {
   // Configure the instance by adding the properties specified by the
diff --git a/src/factory.h b/src/factory.h
index 24b490c..24a6647 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -10,8 +10,9 @@
 namespace v8 {
 namespace internal {
 
-// Interface for handle based allocation.
+class FeedbackVectorSpec;
 
+// Interface for handle based allocation.
 class Factory FINAL {
  public:
   Handle<Oddball> NewOddball(Handle<Map> map,
@@ -225,10 +226,13 @@
   // Create a global (but otherwise uninitialized) context.
   Handle<Context> NewNativeContext();
 
-  // Create a global context.
-  Handle<Context> NewGlobalContext(Handle<JSFunction> function,
+  // Create a script context.
+  Handle<Context> NewScriptContext(Handle<JSFunction> function,
                                    Handle<ScopeInfo> scope_info);
 
+  // Create an empty script context table.
+  Handle<ScriptContextTable> NewScriptContextTable();
+
   // Create a module context.
   Handle<Context> NewModuleContext(Handle<ScopeInfo> scope_info);
 
@@ -296,6 +300,8 @@
 
   Handle<PropertyCell> NewPropertyCell(Handle<Object> value);
 
+  Handle<WeakCell> NewWeakCell(Handle<HeapObject> value);
+
   // Allocate a tenured AllocationSite. It's payload is null.
   Handle<AllocationSite> NewAllocationSite();
 
@@ -434,7 +440,18 @@
 
   Handle<JSTypedArray> NewJSTypedArray(ExternalArrayType type);
 
+  // Creates a new JSTypedArray with the specified buffer.
+  Handle<JSTypedArray> NewJSTypedArray(ExternalArrayType type,
+                                       Handle<JSArrayBuffer> buffer,
+                                       size_t byte_offset, size_t length);
+
   Handle<JSDataView> NewJSDataView();
+  Handle<JSDataView> NewJSDataView(Handle<JSArrayBuffer> buffer,
+                                   size_t byte_offset, size_t byte_length);
+
+  // TODO(aandrey): Maybe these should take table, index and kind arguments.
+  Handle<JSMapIterator> NewJSMapIterator();
+  Handle<JSSetIterator> NewJSSetIterator();
 
   // Allocates a Harmony proxy.
   Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);
@@ -469,12 +486,11 @@
       Handle<Context> context,
       PretenureFlag pretenure = TENURED);
 
-  Handle<JSFunction> NewFunction(Handle<String> name,
-                                 Handle<Code> code,
-                                 Handle<Object> prototype,
-                                 InstanceType type,
+  Handle<JSFunction> NewFunction(Handle<String> name, Handle<Code> code,
+                                 Handle<Object> prototype, InstanceType type,
                                  int instance_size,
-                                 bool read_only_prototype = false);
+                                 bool read_only_prototype = false,
+                                 bool install_constructor = false);
   Handle<JSFunction> NewFunction(Handle<String> name,
                                  Handle<Code> code,
                                  InstanceType type,
@@ -588,6 +604,22 @@
   INTERNALIZED_STRING_LIST(STRING_ACCESSOR)
 #undef STRING_ACCESSOR
 
+#define SYMBOL_ACCESSOR(name)                                   \
+  inline Handle<Symbol> name() {                                \
+    return Handle<Symbol>(bit_cast<Symbol**>(                   \
+        &isolate()->heap()->roots_[Heap::k##name##RootIndex])); \
+  }
+  PRIVATE_SYMBOL_LIST(SYMBOL_ACCESSOR)
+#undef SYMBOL_ACCESSOR
+
+#define SYMBOL_ACCESSOR(name, varname, description)             \
+  inline Handle<Symbol> name() {                                \
+    return Handle<Symbol>(bit_cast<Symbol**>(                   \
+        &isolate()->heap()->roots_[Heap::k##name##RootIndex])); \
+  }
+  PUBLIC_SYMBOL_LIST(SYMBOL_ACCESSOR)
+#undef SYMBOL_ACCESSOR
+
   inline void set_string_table(Handle<StringTable> table) {
     isolate()->heap()->set_string_table(*table);
   }
@@ -605,7 +637,8 @@
                                                    MaybeHandle<Code> code);
 
   // Allocate a new type feedback vector
-  Handle<TypeFeedbackVector> NewTypeFeedbackVector(int slot_count);
+  Handle<TypeFeedbackVector> NewTypeFeedbackVector(
+      const FeedbackVectorSpec& spec);
 
   // Allocates a new JSMessageObject object.
   Handle<JSMessageObject> NewJSMessageObject(
@@ -618,10 +651,11 @@
 
   Handle<DebugInfo> NewDebugInfo(Handle<SharedFunctionInfo> shared);
 
-  // Return a map using the map cache in the native context.
-  // The key the an ordered set of property names.
+  // Return a map for given number of properties using the map cache in the
+  // native context.
   Handle<Map> ObjectLiteralMapFromCache(Handle<Context> context,
-                                        Handle<FixedArray> keys);
+                                        int number_of_properties,
+                                        bool* is_result_from_cache);
 
   // Creates a new FixedArray that holds the data associated with the
   // atom regexp and stores it in the regexp.
@@ -664,14 +698,6 @@
   // Creates a code object that is not yet fully initialized yet.
   inline Handle<Code> NewCodeRaw(int object_size, bool immovable);
 
-  // Create a new map cache.
-  Handle<MapCache> NewMapCache(int at_least_space_for);
-
-  // Update the map cache in the native context with (keys, map)
-  Handle<MapCache> AddToMapCache(Handle<Context> context,
-                                 Handle<FixedArray> keys,
-                                 Handle<Map> map);
-
   // Attempt to find the number in a small cache.  If we finds it, return
   // the string representation of the number.  Otherwise return undefined.
   Handle<Object> GetNumberStringCache(Handle<Object> number);
diff --git a/src/fast-dtoa.cc b/src/fast-dtoa.cc
index 13b0463..d6edddc 100644
--- a/src/fast-dtoa.cc
+++ b/src/fast-dtoa.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "include/v8stdint.h"
+#include <stdint.h>
 #include "src/base/logging.h"
 #include "src/utils.h"
 
diff --git a/src/feedback-slots.h b/src/feedback-slots.h
deleted file mode 100644
index 9951fc8..0000000
--- a/src/feedback-slots.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_FEEDBACK_SLOTS_H_
-#define V8_FEEDBACK_SLOTS_H_
-
-#include "src/v8.h"
-
-#include "src/isolate.h"
-
-namespace v8 {
-namespace internal {
-
-class FeedbackSlotInterface {
- public:
-  static const int kInvalidFeedbackSlot = -1;
-
-  virtual ~FeedbackSlotInterface() {}
-
-  virtual int ComputeFeedbackSlotCount() = 0;
-  virtual void SetFirstFeedbackSlot(int slot) = 0;
-};
-
-} }  // namespace v8::internal
-
-#endif  // V8_FEEDBACK_SLOTS_H_
diff --git a/src/field-index.h b/src/field-index.h
index 2558529..76b1116 100644
--- a/src/field-index.h
+++ b/src/field-index.h
@@ -34,6 +34,8 @@
     return IsInObjectBits::decode(bit_field_);
   }
 
+  bool is_hidden_field() const { return IsHiddenField::decode(bit_field_); }
+
   bool is_double() const {
     return IsDoubleBits::decode(bit_field_);
   }
@@ -55,7 +57,7 @@
   // Zero-based from the first inobject property. Overflows to out-of-object
   // properties.
   int property_index() const {
-    DCHECK(!IsHiddenField::decode(bit_field_));
+    DCHECK(!is_hidden_field());
     int result = index() - first_inobject_property_offset() / kPointerSize;
     if (!is_inobject()) {
       result += InObjectPropertyBits::decode(bit_field_);
@@ -86,7 +88,7 @@
   explicit FieldIndex(int bit_field) : bit_field_(bit_field) {}
 
   int first_inobject_property_offset() const {
-    DCHECK(!IsHiddenField::decode(bit_field_));
+    DCHECK(!is_hidden_field());
     return FirstInobjectPropertyOffsetBits::decode(bit_field_);
   }
 
diff --git a/src/fixed-dtoa.cc b/src/fixed-dtoa.cc
index 56fe9ab..7856b13 100644
--- a/src/fixed-dtoa.cc
+++ b/src/fixed-dtoa.cc
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <stdint.h>
+
 #include <cmath>
 
-#include "include/v8stdint.h"
 #include "src/base/logging.h"
 #include "src/utils.h"
 
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 49f0714..348a52e 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -16,6 +16,9 @@
 #define DEFINE_NEG_IMPLICATION(whenflag, thenflag)          \
   DEFINE_VALUE_IMPLICATION(whenflag, thenflag, false)
 
+#define DEFINE_NEG_NEG_IMPLICATION(whenflag, thenflag) \
+  DEFINE_NEG_VALUE_IMPLICATION(whenflag, thenflag, false)
+
 // We want to declare the names of the variables for the header file.  Normally
 // this will just be an extern declaration, but for a readonly flag we let the
 // compiler make better optimizations by giving it the value.
@@ -54,6 +57,9 @@
 #define DEFINE_VALUE_IMPLICATION(whenflag, thenflag, value) \
   if (FLAG_##whenflag) FLAG_##thenflag = value;
 
+#define DEFINE_NEG_VALUE_IMPLICATION(whenflag, thenflag, value) \
+  if (!FLAG_##whenflag) FLAG_##thenflag = value;
+
 #else
 #error No mode supplied when including flags.defs
 #endif
@@ -75,6 +81,10 @@
 #define DEFINE_VALUE_IMPLICATION(whenflag, thenflag, value)
 #endif
 
+#ifndef DEFINE_NEG_VALUE_IMPLICATION
+#define DEFINE_NEG_VALUE_IMPLICATION(whenflag, thenflag, value)
+#endif
+
 #define COMMA ,
 
 #ifdef FLAG_MODE_DECLARE
@@ -114,6 +124,11 @@
 #else
 #define ENABLE_ARMV7_DEFAULT false
 #endif
+#if (defined CAN_USE_ARMV8_INSTRUCTIONS) || !(defined ARM_TEST_NO_FEATURE_PROBE)
+#define ENABLE_ARMV8_DEFAULT true
+#else
+#define ENABLE_ARMV8_DEFAULT false
+#endif
 #if (defined CAN_USE_VFP32DREGS) || !(defined ARM_TEST_NO_FEATURE_PROBE)
 #define ENABLE_32DREGS_DEFAULT true
 #else
@@ -126,6 +141,8 @@
 #endif
 
 #define DEFINE_BOOL(nam, def, cmt) FLAG(BOOL, bool, nam, def, cmt)
+#define DEFINE_BOOL_READONLY(nam, def, cmt) \
+  FLAG_READONLY(BOOL, bool, nam, def, cmt)
 #define DEFINE_MAYBE_BOOL(nam, cmt) \
   FLAG(MAYBE_BOOL, MaybeBoolFlag, nam, {false COMMA false}, cmt)
 #define DEFINE_INT(nam, def, cmt) FLAG(INT, int, nam, def, cmt)
@@ -147,45 +164,71 @@
 
 // Flags for language modes and experimental language features.
 DEFINE_BOOL(use_strict, false, "enforce strict mode")
-DEFINE_BOOL(es_staging, false, "enable upcoming ES6+ features")
 
-DEFINE_BOOL(harmony_scoping, false, "enable harmony block scoping")
-DEFINE_BOOL(harmony_modules, false,
-            "enable harmony modules (implies block scoping)")
-DEFINE_BOOL(harmony_proxies, false, "enable harmony proxies")
-DEFINE_BOOL(harmony_numeric_literals, false,
-            "enable harmony numeric literals (0o77, 0b11)")
-DEFINE_BOOL(harmony_strings, false, "enable harmony string")
-DEFINE_BOOL(harmony_arrays, false, "enable harmony arrays")
-DEFINE_BOOL(harmony_arrow_functions, false, "enable harmony arrow functions")
-DEFINE_BOOL(harmony_classes, false, "enable harmony classes")
-DEFINE_BOOL(harmony_object_literals, false,
-            "enable harmony object literal extensions")
-DEFINE_BOOL(harmony_regexps, false, "enable regexp-related harmony features")
-DEFINE_BOOL(harmony, false, "enable all harmony features (except proxies)")
+DEFINE_BOOL(es_staging, false, "enable all completed harmony features")
+DEFINE_BOOL(harmony, false, "enable all completed harmony features")
+DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony fetaures")
+DEFINE_IMPLICATION(harmony, es_staging)
+DEFINE_IMPLICATION(es_staging, harmony)
 
-DEFINE_IMPLICATION(harmony, harmony_scoping)
-DEFINE_IMPLICATION(harmony, harmony_modules)
-// TODO(rossberg): Reenable when problems are sorted out.
-// DEFINE_IMPLICATION(harmony, harmony_proxies)
-DEFINE_IMPLICATION(harmony, harmony_numeric_literals)
-DEFINE_IMPLICATION(harmony, harmony_strings)
-DEFINE_IMPLICATION(harmony, harmony_arrays)
-DEFINE_IMPLICATION(harmony, harmony_arrow_functions)
-DEFINE_IMPLICATION(harmony, harmony_classes)
-DEFINE_IMPLICATION(harmony, harmony_object_literals)
-DEFINE_IMPLICATION(harmony, harmony_regexps)
+// Features that are still work in progress (behind individual flags).
+#define HARMONY_INPROGRESS(V)                                             \
+  V(harmony_modules, "harmony modules (implies block scoping)")           \
+  V(harmony_arrays, "harmony array methods")                              \
+  V(harmony_array_includes, "harmony Array.prototype.includes")           \
+  V(harmony_regexps, "harmony regular expression extensions")             \
+  V(harmony_arrow_functions, "harmony arrow functions")                   \
+  V(harmony_proxies, "harmony proxies")                                   \
+  V(harmony_sloppy, "harmony features in sloppy mode")                    \
+  V(harmony_unicode, "harmony unicode escapes")
+
+// Features that are complete (but still behind --harmony/es-staging flag).
+#define HARMONY_STAGED(V)                                                 \
+  V(harmony_tostring, "harmony toString")                                 \
+  V(harmony_classes,                                                      \
+    "harmony classes (implies block scoping & object literal extension)") \
+  V(harmony_object_literals, "harmony object literal extensions")
+
+// Features that are shipping (turned on by default, but internal flag remains).
+#define HARMONY_SHIPPING(V)                                               \
+  V(harmony_numeric_literals, "harmony numeric literals")                 \
+  V(harmony_strings, "harmony string methods")                            \
+  V(harmony_scoping, "harmony block scoping")                             \
+  V(harmony_templates, "harmony template literals")
+
+// Once a shipping feature has proved stable in the wild, it will be dropped
+// from HARMONY_SHIPPING, all occurrences of the FLAG_ variable are removed,
+// and associated tests are moved from the harmony directory to the appropriate
+// esN directory.
+
+
+#define FLAG_INPROGRESS_FEATURES(id, description) \
+  DEFINE_BOOL(id, false, "enable " #description " (in progress)")
+HARMONY_INPROGRESS(FLAG_INPROGRESS_FEATURES)
+#undef FLAG_INPROGRESS_FEATURES
+
+#define FLAG_STAGED_FEATURES(id, description) \
+  DEFINE_BOOL(id, false, "enable " #description) \
+  DEFINE_IMPLICATION(es_staging, id)
+HARMONY_STAGED(FLAG_STAGED_FEATURES)
+#undef FLAG_STAGED_FEATURES
+
+#define FLAG_SHIPPING_FEATURES(id, description) \
+  DEFINE_BOOL(id, true, "enable " #description) \
+  DEFINE_NEG_NEG_IMPLICATION(harmony_shipping, id)
+HARMONY_SHIPPING(FLAG_SHIPPING_FEATURES)
+#undef FLAG_SHIPPING_FEATURES
+
+
+// Feature dependencies.
 DEFINE_IMPLICATION(harmony_modules, harmony_scoping)
 DEFINE_IMPLICATION(harmony_classes, harmony_scoping)
 DEFINE_IMPLICATION(harmony_classes, harmony_object_literals)
 
-DEFINE_IMPLICATION(harmony, es_staging)
 
 // Flags for experimental implementation features.
 DEFINE_BOOL(compiled_keyed_generic_loads, false,
             "use optimizing compiler to generate keyed generic load stubs")
-DEFINE_BOOL(clever_optimizations, true,
-            "Optimize object size, Array shift, DOM strings and string +")
 // TODO(hpayer): We will remove this flag as soon as we have pretenuring
 // support for specific allocation sites.
 DEFINE_BOOL(pretenuring_call_new, false, "pretenure call new")
@@ -307,12 +350,13 @@
            "maximum number of escape analysis fix-point iterations")
 
 DEFINE_BOOL(optimize_for_in, true, "optimize functions containing for-in loops")
-DEFINE_BOOL(opt_safe_uint32_operations, true,
-            "allow uint32 values on optimize frames if they are used only in "
-            "safe operations")
 
 DEFINE_BOOL(concurrent_recompilation, true,
             "optimizing hot functions asynchronously on a separate thread")
+DEFINE_BOOL(job_based_recompilation, false,
+            "post tasks to v8::Platform instead of using a thread for "
+            "concurrent recompilation")
+DEFINE_IMPLICATION(job_based_recompilation, concurrent_recompilation)
 DEFINE_BOOL(trace_concurrent_recompilation, false,
             "track concurrent recompilation")
 DEFINE_INT(concurrent_recompilation_queue_length, 8,
@@ -331,24 +375,39 @@
 // Flags for TurboFan.
 DEFINE_STRING(turbo_filter, "~", "optimization filter for TurboFan compiler")
 DEFINE_BOOL(trace_turbo, false, "trace generated TurboFan IR")
-DEFINE_BOOL(trace_turbo_types, true, "trace generated TurboFan types")
-DEFINE_BOOL(trace_turbo_scheduler, false, "trace generated TurboFan scheduler")
-DEFINE_BOOL(turbo_asm, false, "enable TurboFan for asm.js code")
+DEFINE_BOOL(trace_turbo_graph, false, "trace generated TurboFan graphs")
+DEFINE_IMPLICATION(trace_turbo_graph, trace_turbo)
+DEFINE_STRING(trace_turbo_cfg_file, NULL,
+              "trace turbo cfg graph (for C1 visualizer) to a given file name")
+DEFINE_BOOL(trace_turbo_types, true, "trace TurboFan's types")
+DEFINE_BOOL(trace_turbo_scheduler, false, "trace TurboFan's scheduler")
+DEFINE_BOOL(trace_turbo_reduction, false, "trace TurboFan's various reducers")
+DEFINE_BOOL(trace_turbo_jt, false, "trace TurboFan's jump threading")
+DEFINE_BOOL(turbo_asm, true, "enable TurboFan for asm.js code")
 DEFINE_BOOL(turbo_verify, false, "verify TurboFan graphs at each phase")
 DEFINE_BOOL(turbo_stats, false, "print TurboFan statistics")
-#if V8_TURBOFAN_BACKEND
 DEFINE_BOOL(turbo_types, true, "use typed lowering in TurboFan")
-#else
-DEFINE_BOOL(turbo_types, false, "use typed lowering in TurboFan")
-#endif
 DEFINE_BOOL(turbo_source_positions, false,
             "track source code positions when building TurboFan IR")
 DEFINE_BOOL(context_specialization, false,
             "enable context specialization in TurboFan")
 DEFINE_BOOL(turbo_deoptimization, false, "enable deoptimization in TurboFan")
 DEFINE_BOOL(turbo_inlining, false, "enable inlining in TurboFan")
+DEFINE_BOOL(turbo_inlining_intrinsics, false,
+            "enable inlining of intrinsics in TurboFan")
 DEFINE_BOOL(trace_turbo_inlining, false, "trace TurboFan inlining")
+DEFINE_BOOL(loop_assignment_analysis, true, "perform loop assignment analysis")
+DEFINE_IMPLICATION(turbo_inlining_intrinsics, turbo_inlining)
 DEFINE_IMPLICATION(turbo_inlining, turbo_types)
+DEFINE_BOOL(turbo_profiling, false, "enable profiling in TurboFan")
+// TODO(dcarney): this is just for experimentation, remove when default.
+DEFINE_BOOL(turbo_reuse_spill_slots, true, "reuse spill slots in TurboFan")
+// TODO(dcarney): this is just for experimentation, remove when default.
+DEFINE_BOOL(turbo_delay_ssa_decon, false,
+            "delay ssa deconstruction in TurboFan register allocator")
+// TODO(dcarney): this is just for debugging, remove eventually.
+DEFINE_BOOL(turbo_move_optimization, true, "optimize gap moves in TurboFan")
+DEFINE_BOOL(turbo_jt, true, "enable jump threading")
 
 DEFINE_INT(typed_array_max_size_in_heap, 64,
            "threshold for in-heap typed array")
@@ -375,10 +434,14 @@
             "enable use of SSE4.1 instructions if available")
 DEFINE_BOOL(enable_sahf, true,
             "enable use of SAHF instruction if available (X64 only)")
+DEFINE_BOOL(enable_avx, true, "enable use of AVX instructions if available")
+DEFINE_BOOL(enable_fma3, true, "enable use of FMA3 instructions if available")
 DEFINE_BOOL(enable_vfp3, ENABLE_VFP3_DEFAULT,
             "enable use of VFP3 instructions if available")
 DEFINE_BOOL(enable_armv7, ENABLE_ARMV7_DEFAULT,
             "enable use of ARMv7 instructions if available (ARM only)")
+DEFINE_BOOL(enable_armv8, ENABLE_ARMV8_DEFAULT,
+            "enable use of ARMv8 instructions if available (ARM 32-bit only)")
 DEFINE_BOOL(enable_neon, ENABLE_NEON_DEFAULT,
             "enable use of NEON instructions if available (ARM only)")
 DEFINE_BOOL(enable_sudiv, true,
@@ -397,11 +460,6 @@
 DEFINE_BOOL(force_long_branches, false,
             "force all emitted branches to be in long mode (MIPS only)")
 
-// cpu-arm64.cc
-DEFINE_BOOL(enable_always_align_csp, true,
-            "enable alignment of csp to 16 bytes on platforms which prefer "
-            "the register to always be aligned (ARM64 only)")
-
 // bootstrapper.cc
 DEFINE_STRING(expose_natives_as, NULL, "expose natives in global object")
 DEFINE_STRING(expose_debug_as, NULL, "expose debug in global object")
@@ -440,8 +498,9 @@
 DEFINE_BOOL(trace_stub_failures, false,
             "trace deoptimization of generated code stubs")
 
-DEFINE_BOOL(serialize_toplevel, false, "enable caching of toplevel scripts")
-DEFINE_BOOL(trace_code_serializer, false, "trace code serializer")
+DEFINE_BOOL(serialize_toplevel, true, "enable caching of toplevel scripts")
+DEFINE_BOOL(serialize_inner, true, "enable caching of inner functions")
+DEFINE_BOOL(trace_serializer, false, "print code serializer trace")
 
 // compiler.cc
 DEFINE_INT(min_preparse_length, 1024,
@@ -487,10 +546,17 @@
 DEFINE_INT(min_semi_space_size, 0,
            "min size of a semi-space (in MBytes), the new space consists of two"
            "semi-spaces")
+DEFINE_INT(target_semi_space_size, 0,
+           "target size of a semi-space (in MBytes) before triggering a GC")
 DEFINE_INT(max_semi_space_size, 0,
            "max size of a semi-space (in MBytes), the new space consists of two"
            "semi-spaces")
+DEFINE_INT(semi_space_growth_factor, 2, "factor by which to grow the new space")
+DEFINE_BOOL(experimental_new_space_growth_heuristic, false,
+            "Grow the new space based on the percentage of survivors instead "
+            "of their absolute value.")
 DEFINE_INT(max_old_space_size, 0, "max size of the old space (in Mbytes)")
+DEFINE_INT(initial_old_space_size, 0, "initial old space size (in Mbytes)")
 DEFINE_INT(max_executable_size, 0, "max size of executable memory (in Mbytes)")
 DEFINE_BOOL(gc_global, false, "always perform global GCs")
 DEFINE_INT(gc_interval, -1, "garbage collect after <n> allocations")
@@ -503,6 +569,8 @@
             "do not print trace line after scavenger collection")
 DEFINE_BOOL(trace_idle_notification, false,
             "print one trace line following each idle notification")
+DEFINE_BOOL(trace_idle_notification_verbose, false,
+            "prints the heap state used by the idle notification")
 DEFINE_BOOL(print_cumulative_gc_stat, false,
             "print cumulative GC statistics in name=value format on exit")
 DEFINE_BOOL(print_max_heap_committed, false,
@@ -514,8 +582,6 @@
             "report fragmentation for old pointer and data pages")
 DEFINE_BOOL(collect_maps, true,
             "garbage collect maps from which no objects can be reached")
-DEFINE_BOOL(weak_embedded_maps_in_ic, true,
-            "make maps embedded in inline cache stubs")
 DEFINE_BOOL(weak_embedded_maps_in_optimized_code, true,
             "make maps embedded in optimized code weak")
 DEFINE_BOOL(weak_embedded_objects_in_optimized_code, true,
@@ -530,15 +596,11 @@
             "old code (required for code flushing)")
 DEFINE_BOOL(incremental_marking, true, "use incremental marking")
 DEFINE_BOOL(incremental_marking_steps, true, "do incremental marking steps")
+DEFINE_BOOL(concurrent_sweeping, true, "use concurrent sweeping")
 DEFINE_BOOL(trace_incremental_marking, false,
             "trace progress of the incremental marking")
 DEFINE_BOOL(track_gc_object_stats, false,
             "track object counts and memory usage")
-DEFINE_BOOL(parallel_sweeping, false, "enable parallel sweeping")
-DEFINE_BOOL(concurrent_sweeping, true, "enable concurrent sweeping")
-DEFINE_INT(sweeper_threads, 0,
-           "number of parallel and concurrent sweeping threads")
-DEFINE_BOOL(job_based_sweeping, true, "enable job based sweeping")
 #ifdef VERIFY_HEAP
 DEFINE_BOOL(verify_heap, false, "verify heap pointers before and after GC")
 #endif
@@ -581,7 +643,13 @@
            "(0, the default, means to use system random).")
 
 // objects.cc
+DEFINE_BOOL(trace_weak_arrays, false, "trace WeakFixedArray usage")
+DEFINE_BOOL(track_prototype_users, false,
+            "keep track of which maps refer to a given prototype object")
 DEFINE_BOOL(use_verbose_printer, true, "allows verbose printing")
+#if TRACE_MAPS
+DEFINE_BOOL(trace_maps, false, "trace map creation")
+#endif
 
 // parser.cc
 DEFINE_BOOL(allow_natives_syntax, false, "allow natives syntax")
@@ -647,18 +715,8 @@
 #endif
 
 // mksnapshot.cc
-DEFINE_STRING(extra_code, NULL,
-              "A filename with extra code to be included in"
-              " the snapshot (mksnapshot only)")
-DEFINE_STRING(raw_file, NULL,
-              "A file to write the raw snapshot bytes to. "
-              "(mksnapshot only)")
-DEFINE_STRING(raw_context_file, NULL,
-              "A file to write the raw context "
-              "snapshot bytes to. (mksnapshot only)")
 DEFINE_STRING(startup_blob, NULL,
-              "Write V8 startup blob file. "
-              "(mksnapshot only)")
+              "Write V8 startup blob file. (mksnapshot only)")
 
 // code-stubs-hydrogen.cc
 DEFINE_BOOL(profile_hydrogen_code_stub_compilation, false,
@@ -668,7 +726,6 @@
 DEFINE_NEG_IMPLICATION(predictable, concurrent_recompilation)
 DEFINE_NEG_IMPLICATION(predictable, concurrent_osr)
 DEFINE_NEG_IMPLICATION(predictable, concurrent_sweeping)
-DEFINE_NEG_IMPLICATION(predictable, parallel_sweeping)
 
 
 //
@@ -739,8 +796,6 @@
 DEFINE_BOOL(gc_verbose, false, "print stuff during garbage collection")
 DEFINE_BOOL(heap_stats, false, "report heap statistics before and after GC")
 DEFINE_BOOL(code_stats, false, "report code statistics after GC")
-DEFINE_BOOL(verify_native_context_separation, false,
-            "verify that code holds on to at most one native context after GC")
 DEFINE_BOOL(print_handles, false, "report handles after GC")
 DEFINE_BOOL(print_global_handles, false, "report global handles after GC")
 
@@ -911,10 +966,15 @@
 #undef FLAG
 #define FLAG FLAG_READONLY
 
-// assembler-arm.h
+// assembler.h
 DEFINE_BOOL(enable_ool_constant_pool, V8_OOL_CONSTANT_POOL,
             "enable use of out-of-line constant pools (ARM only)")
 
+DEFINE_BOOL(unbox_double_fields, V8_DOUBLE_FIELDS_UNBOXING,
+            "enable in-object double fields unboxing (64-bit only)")
+DEFINE_IMPLICATION(unbox_double_fields, track_double_fields)
+
+
 // Cleanup...
 #undef FLAG_FULL
 #undef FLAG_READONLY
@@ -929,6 +989,7 @@
 #undef DEFINE_ARGS
 #undef DEFINE_IMPLICATION
 #undef DEFINE_NEG_IMPLICATION
+#undef DEFINE_NEG_VALUE_IMPLICATION
 #undef DEFINE_VALUE_IMPLICATION
 #undef DEFINE_ALIAS_BOOL
 #undef DEFINE_ALIAS_INT
diff --git a/src/flags.cc b/src/flags.cc
index 98f21ef..5e33bda 100644
--- a/src/flags.cc
+++ b/src/flags.cc
@@ -2,12 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <ctype.h>
-#include <stdlib.h>
+#include <cctype>
+#include <cstdlib>
+#include <sstream>
 
 #include "src/v8.h"
 
 #include "src/assembler.h"
+#include "src/base/functional.h"
 #include "src/base/platform/platform.h"
 #include "src/ostreams.h"
 
@@ -181,7 +183,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const Flag& flag) {  // NOLINT
+std::ostream& operator<<(std::ostream& os, const Flag& flag) {  // NOLINT
   switch (flag.type()) {
     case Flag::TYPE_BOOL:
       os << (*flag.bool_variable() ? "true" : "false");
@@ -231,21 +233,21 @@
       }
       {
         bool disabled = f->type() == Flag::TYPE_BOOL && !*f->bool_variable();
-        OStringStream os;
+        std::ostringstream os;
         os << (disabled ? "--no" : "--") << f->name();
-        args->Add(StrDup(os.c_str()));
+        args->Add(StrDup(os.str().c_str()));
       }
       if (f->type() != Flag::TYPE_BOOL) {
-        OStringStream os;
+        std::ostringstream os;
         os << *f;
-        args->Add(StrDup(os.c_str()));
+        args->Add(StrDup(os.str().c_str()));
       }
     }
   }
   if (args_flag != NULL) {
-    OStringStream os;
+    std::ostringstream os;
     os << "--" << args_flag->name();
-    args->Add(StrDup(os.c_str()));
+    args->Add(StrDup(os.str().c_str()));
     JSArguments jsargs = *args_flag->args_variable();
     for (int j = 0; j < jsargs.argc; j++) {
       args->Add(StrDup(jsargs[j]));
@@ -548,4 +550,18 @@
 #undef FLAG_MODE_DEFINE_IMPLICATIONS
 }
 
+
+uint32_t FlagList::Hash() {
+  std::ostringstream modified_args_as_string;
+  for (size_t i = 0; i < num_flags; ++i) {
+    Flag* current = &flags[i];
+    if (!current->IsDefault()) {
+      modified_args_as_string << i;
+      modified_args_as_string << *current;
+    }
+  }
+  std::string args(modified_args_as_string.str());
+  return static_cast<uint32_t>(
+      base::hash_range(args.c_str(), args.c_str() + args.length()));
+}
 } }  // namespace v8::internal
diff --git a/src/flags.h b/src/flags.h
index 78522ff..9ec5d30 100644
--- a/src/flags.h
+++ b/src/flags.h
@@ -57,6 +57,9 @@
 
   // Set flags as consequence of being implied by another flag.
   static void EnforceFlagImplications();
+
+  // Hash of current flags (to quickly determine flag changes).
+  static uint32_t Hash();
 };
 
 } }  // namespace v8::internal
diff --git a/src/frames-inl.h b/src/frames-inl.h
index 9241a44..d7f2f75 100644
--- a/src/frames-inl.h
+++ b/src/frames-inl.h
@@ -76,13 +76,13 @@
 
 
 inline StackHandler::Kind StackHandler::kind() const {
-  const int offset = StackHandlerConstants::kStateOffset;
+  const int offset = StackHandlerConstants::kStateIntOffset;
   return KindField::decode(Memory::unsigned_at(address() + offset));
 }
 
 
 inline unsigned StackHandler::index() const {
-  const int offset = StackHandlerConstants::kStateOffset;
+  const int offset = StackHandlerConstants::kStateIntOffset;
   return IndexField::decode(Memory::unsigned_at(address() + offset));
 }
 
diff --git a/src/frames.cc b/src/frames.cc
index f116fd2..0ba8ea0 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "src/frames.h"
+
+#include <sstream>
+
 #include "src/v8.h"
 
 #include "src/ast.h"
@@ -1288,12 +1292,12 @@
 
   // Print details about the function.
   if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
-    OStringStream os;
+    std::ostringstream os;
     SharedFunctionInfo* shared = function->shared();
     os << "--------- s o u r c e   c o d e ---------\n"
        << SourceCodeOf(shared, FLAG_max_stack_trace_source_length)
        << "\n-----------------------------------------\n";
-    accumulator->Add(os.c_str());
+    accumulator->Add(os.str().c_str());
   }
 
   accumulator->Add("}\n\n");
diff --git a/src/frames.h b/src/frames.h
index f7e60ae..03d53dd 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -71,6 +71,11 @@
   static const int kNextOffset     = 0 * kPointerSize;
   static const int kCodeOffset     = 1 * kPointerSize;
   static const int kStateOffset    = 2 * kPointerSize;
+#if V8_TARGET_LITTLE_ENDIAN || !V8_HOST_ARCH_64_BIT
+  static const int kStateIntOffset = kStateOffset;
+#else
+  static const int kStateIntOffset = kStateOffset + kIntSize;
+#endif
   static const int kContextOffset  = 3 * kPointerSize;
   static const int kFPOffset       = 4 * kPointerSize;
 
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index 35d51d9..cb8f4aa 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -4,6 +4,8 @@
 
 #include "src/v8.h"
 
+#include "src/ast.h"
+#include "src/ast-numbering.h"
 #include "src/code-factory.h"
 #include "src/codegen.h"
 #include "src/compiler.h"
@@ -134,21 +136,19 @@
 
 
 void BreakableStatementChecker::VisitForStatement(ForStatement* stmt) {
-  // Mark for statements breakable if the condition expression is.
-  if (stmt->cond() != NULL) {
-    Visit(stmt->cond());
-  }
+  // We set positions for both init and condition, if they exist.
+  if (stmt->cond() != NULL || stmt->init() != NULL) is_breakable_ = true;
 }
 
 
 void BreakableStatementChecker::VisitForInStatement(ForInStatement* stmt) {
-  // Mark for in statements breakable if the enumerable expression is.
-  Visit(stmt->enumerable());
+  // For-in is breakable because we set the position for the enumerable.
+  is_breakable_ = true;
 }
 
 
 void BreakableStatementChecker::VisitForOfStatement(ForOfStatement* stmt) {
-  // For-of is breakable because of the next() call.
+  // For-of is breakable because we set the position for the next() call.
   is_breakable_ = true;
 }
 
@@ -306,6 +306,9 @@
 
   TimerEventScope<TimerEventCompileFullCode> timer(info->isolate());
 
+  // Ensure that the feedback vector is large enough.
+  info->EnsureFeedbackVector();
+
   Handle<Script> script = info->script();
   if (!script->IsUndefined() && !script->source()->IsUndefined()) {
     int len = String::cast(script->source())->length();
@@ -335,6 +338,7 @@
   cgen.PopulateDeoptimizationData(code);
   cgen.PopulateTypeFeedbackInfo(code);
   code->set_has_deoptimization_support(info->HasDeoptimizationSupport());
+  code->set_has_reloc_info_for_serialization(info->will_serialize());
   code->set_handler_table(*cgen.handler_table());
   code->set_compiled_optimizable(info->IsOptimizable());
   code->set_allow_osr_at_loop_nesting_level(0);
@@ -344,6 +348,11 @@
   info->SetCode(code);
   void* line_info = masm.positions_recorder()->DetachJITHandlerData();
   LOG_CODE_EVENT(isolate, CodeEndLinePosInfoRecordEvent(*code, line_info));
+
+#ifdef DEBUG
+  // Check that no context-specific object has been embedded.
+  code->VerifyEmbeddedObjectsInFullCode();
+#endif  // DEBUG
   return true;
 }
 
@@ -365,12 +374,24 @@
 }
 
 
-void FullCodeGenerator::EnsureSlotContainsAllocationSite(int slot) {
-  Handle<FixedArray> vector = FeedbackVector();
-  if (!vector->get(slot)->IsAllocationSite()) {
+void FullCodeGenerator::EnsureSlotContainsAllocationSite(
+    FeedbackVectorSlot slot) {
+  Handle<TypeFeedbackVector> vector = FeedbackVector();
+  if (!vector->Get(slot)->IsAllocationSite()) {
     Handle<AllocationSite> allocation_site =
         isolate()->factory()->NewAllocationSite();
-    vector->set(slot, *allocation_site);
+    vector->Set(slot, *allocation_site);
+  }
+}
+
+
+void FullCodeGenerator::EnsureSlotContainsAllocationSite(
+    FeedbackVectorICSlot slot) {
+  Handle<TypeFeedbackVector> vector = FeedbackVector();
+  if (!vector->Get(slot)->IsAllocationSite()) {
+    Handle<AllocationSite> allocation_site =
+        isolate()->factory()->NewAllocationSite();
+    vector->Set(slot, *allocation_site);
   }
 }
 
@@ -584,7 +605,7 @@
 
 
 void FullCodeGenerator::AllocateModules(ZoneList<Declaration*>* declarations) {
-  DCHECK(scope_->is_global_scope());
+  DCHECK(scope_->is_script_scope());
 
   for (int i = 0; i < declarations->length(); i++) {
     ModuleDeclaration* declaration = declarations->at(i)->AsModuleDeclaration();
@@ -625,8 +646,8 @@
 // modules themselves, however, are simple data properties.)
 //
 // All modules have a _hosting_ scope/context, which (currently) is the
-// (innermost) enclosing global scope. To deal with recursion, nested modules
-// are hosted by the same scope as global ones.
+// enclosing script scope. To deal with recursion, nested modules are hosted
+// by the same scope as global ones.
 //
 // For every (global or nested) module literal, the hosting context has an
 // internal slot that points directly to the respective module context. This
@@ -656,7 +677,7 @@
 //
 // To deal with arbitrary recursion and aliases between modules,
 // they are created and initialized in several stages. Each stage applies to
-// all modules in the hosting global scope, including nested ones.
+// all modules in the hosting script scope, including nested ones.
 //
 // 1. Allocate: for each module _literal_, allocate the module contexts and
 //    respective instance object and wire them up. This happens in the
@@ -691,7 +712,7 @@
     // This is a scope hosting modules. Allocate a descriptor array to pass
     // to the runtime for initialization.
     Comment cmnt(masm_, "[ Allocate modules");
-    DCHECK(scope_->is_global_scope());
+    DCHECK(scope_->is_script_scope());
     modules_ =
         isolate()->factory()->NewFixedArray(scope_->num_modules(), TENURED);
     module_index_ = 0;
@@ -1053,41 +1074,12 @@
   NestedBlock nested_block(this, stmt);
   SetStatementPosition(stmt);
 
-  Scope* saved_scope = scope();
-  // Push a block context when entering a block with block scoped variables.
-  if (stmt->scope() == NULL) {
-    PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
-  } else {
-    scope_ = stmt->scope();
-    DCHECK(!scope_->is_module_scope());
-    { Comment cmnt(masm_, "[ Extend block context");
-      __ Push(scope_->GetScopeInfo());
-      PushFunctionArgumentForContextAllocation();
-      __ CallRuntime(Runtime::kPushBlockContext, 2);
-
-      // Replace the context stored in the frame.
-      StoreToFrameField(StandardFrameConstants::kContextOffset,
-                        context_register());
-      PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
-    }
-    { Comment cmnt(masm_, "[ Declarations");
-      VisitDeclarations(scope_->declarations());
-      PrepareForBailoutForId(stmt->DeclsId(), NO_REGISTERS);
-    }
+  {
+    EnterBlockScopeIfNeeded block_scope_state(
+        this, stmt->scope(), stmt->EntryId(), stmt->DeclsId(), stmt->ExitId());
+    VisitStatements(stmt->statements());
+    __ bind(nested_block.break_label());
   }
-
-  VisitStatements(stmt->statements());
-  scope_ = saved_scope;
-  __ bind(nested_block.break_label());
-
-  // Pop block context if necessary.
-  if (stmt->scope() != NULL) {
-    LoadContextField(context_register(), Context::PREVIOUS_INDEX);
-    // Update local stack frame context field.
-    StoreToFrameField(StandardFrameConstants::kContextOffset,
-                      context_register());
-  }
-  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
 }
 
 
@@ -1326,6 +1318,7 @@
   SetStatementPosition(stmt);
 
   if (stmt->init() != NULL) {
+    SetStatementPosition(stmt->init());
     Visit(stmt->init());
   }
 
@@ -1340,6 +1333,7 @@
   PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS);
   __ bind(loop_statement.continue_label());
   if (stmt->next() != NULL) {
+    SetStatementPosition(stmt->next());
     Visit(stmt->next());
   }
 
@@ -1352,6 +1346,7 @@
 
   __ bind(&test);
   if (stmt->cond() != NULL) {
+    SetExpressionPosition(stmt->cond());
     VisitForControl(stmt->cond(),
                     &body,
                     loop_statement.break_label(),
@@ -1366,6 +1361,47 @@
 }
 
 
+void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
+  Comment cmnt(masm_, "[ ForOfStatement");
+  SetStatementPosition(stmt);
+
+  Iteration loop_statement(this, stmt);
+  increment_loop_depth();
+
+  // var iterator = iterable[Symbol.iterator]();
+  VisitForEffect(stmt->assign_iterator());
+
+  // Loop entry.
+  __ bind(loop_statement.continue_label());
+
+  // result = iterator.next()
+  SetExpressionPosition(stmt->next_result());
+  VisitForEffect(stmt->next_result());
+
+  // if (result.done) break;
+  Label result_not_done;
+  VisitForControl(stmt->result_done(), loop_statement.break_label(),
+                  &result_not_done, &result_not_done);
+  __ bind(&result_not_done);
+
+  // each = result.value
+  VisitForEffect(stmt->assign_each());
+
+  // Generate code for the body of the loop.
+  Visit(stmt->body());
+
+  // Check stack before looping.
+  PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
+  EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
+  __ jmp(loop_statement.continue_label());
+
+  // Exit and decrement the loop depth.
+  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
+  __ bind(loop_statement.break_label());
+  decrement_loop_depth();
+}
+
+
 void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
   Comment cmnt(masm_, "[ TryCatchStatement");
   SetStatementPosition(stmt);
@@ -1541,13 +1577,43 @@
 }
 
 
-void FullCodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
-  // TODO(arv): Implement
+void FullCodeGenerator::VisitClassLiteral(ClassLiteral* lit) {
   Comment cmnt(masm_, "[ ClassLiteral");
-  if (expr->extends() != NULL) {
-    VisitForEffect(expr->extends());
+
+  {
+    EnterBlockScopeIfNeeded block_scope_state(
+        this, lit->scope(), BailoutId::None(), BailoutId::None(),
+        BailoutId::None());
+
+    if (lit->raw_name() != NULL) {
+      __ Push(lit->name());
+    } else {
+      __ Push(isolate()->factory()->undefined_value());
+    }
+
+    if (lit->extends() != NULL) {
+      VisitForStackValue(lit->extends());
+    } else {
+      __ Push(isolate()->factory()->the_hole_value());
+    }
+
+    VisitForStackValue(lit->constructor());
+
+    __ Push(script());
+    __ Push(Smi::FromInt(lit->start_position()));
+    __ Push(Smi::FromInt(lit->end_position()));
+
+    __ CallRuntime(Runtime::kDefineClass, 6);
+    EmitClassDefineProperties(lit);
+
+    if (lit->scope() != NULL) {
+      DCHECK_NOT_NULL(lit->class_variable_proxy());
+      EmitVariableAssignment(lit->class_variable_proxy()->var(),
+                             Token::INIT_CONST);
+    }
   }
-  context()->Plug(isolate()->factory()->undefined_value());
+
+  context()->Plug(result_register());
 }
 
 
@@ -1713,6 +1779,49 @@
 #endif  // DEBUG
 
 
+FullCodeGenerator::EnterBlockScopeIfNeeded::EnterBlockScopeIfNeeded(
+    FullCodeGenerator* codegen, Scope* scope, BailoutId entry_id,
+    BailoutId declarations_id, BailoutId exit_id)
+    : codegen_(codegen), scope_(scope), exit_id_(exit_id) {
+  saved_scope_ = codegen_->scope();
+
+  if (scope == NULL) {
+    codegen_->PrepareForBailoutForId(entry_id, NO_REGISTERS);
+  } else {
+    codegen_->scope_ = scope;
+    {
+      Comment cmnt(masm(), "[ Extend block context");
+      __ Push(scope->GetScopeInfo());
+      codegen_->PushFunctionArgumentForContextAllocation();
+      __ CallRuntime(Runtime::kPushBlockContext, 2);
+
+      // Replace the context stored in the frame.
+      codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset,
+                                  codegen_->context_register());
+      codegen_->PrepareForBailoutForId(entry_id, NO_REGISTERS);
+    }
+    {
+      Comment cmnt(masm(), "[ Declarations");
+      codegen_->VisitDeclarations(scope->declarations());
+      codegen_->PrepareForBailoutForId(declarations_id, NO_REGISTERS);
+    }
+  }
+}
+
+
+FullCodeGenerator::EnterBlockScopeIfNeeded::~EnterBlockScopeIfNeeded() {
+  if (scope_ != NULL) {
+    codegen_->LoadContextField(codegen_->context_register(),
+                               Context::PREVIOUS_INDEX);
+    // Update local stack frame context field.
+    codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset,
+                                codegen_->context_register());
+  }
+  codegen_->PrepareForBailoutForId(exit_id_, NO_REGISTERS);
+  codegen_->scope_ = saved_scope_;
+}
+
+
 #undef __
 
 
diff --git a/src/full-codegen.h b/src/full-codegen.h
index 71e1b60..1439942 100644
--- a/src/full-codegen.h
+++ b/src/full-codegen.h
@@ -10,10 +10,10 @@
 #include "src/allocation.h"
 #include "src/assert-scope.h"
 #include "src/ast.h"
+#include "src/bit-vector.h"
 #include "src/code-stubs.h"
 #include "src/codegen.h"
 #include "src/compiler.h"
-#include "src/data-flow.h"
 #include "src/globals.h"
 #include "src/objects.h"
 
@@ -40,7 +40,7 @@
 
  private:
   // AST node visit functions.
-#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node) OVERRIDE;
   AST_NODE_LIST(DECLARE_VISIT)
 #undef DECLARE_VISIT
 
@@ -392,7 +392,7 @@
 
   void VisitInDuplicateContext(Expression* expr);
 
-  void VisitDeclarations(ZoneList<Declaration*>* declarations);
+  void VisitDeclarations(ZoneList<Declaration*>* declarations) OVERRIDE;
   void DeclareModules(Handle<FixedArray> descriptions);
   void DeclareGlobals(Handle<FixedArray> pairs);
   int DeclareGlobalsFlags();
@@ -429,10 +429,21 @@
 
   // Feedback slot support. The feedback vector will be cleared during gc and
   // collected by the type-feedback oracle.
-  Handle<FixedArray> FeedbackVector() {
+  Handle<TypeFeedbackVector> FeedbackVector() const {
     return info_->feedback_vector();
   }
-  void EnsureSlotContainsAllocationSite(int slot);
+  void EnsureSlotContainsAllocationSite(FeedbackVectorSlot slot);
+  void EnsureSlotContainsAllocationSite(FeedbackVectorICSlot slot);
+
+  // Returns a smi for the index into the FixedArray that backs the feedback
+  // vector
+  Smi* SmiFromSlot(FeedbackVectorSlot slot) const {
+    return Smi::FromInt(FeedbackVector()->GetIndex(slot));
+  }
+
+  Smi* SmiFromSlot(FeedbackVectorICSlot slot) const {
+    return Smi::FromInt(FeedbackVector()->GetIndex(slot));
+  }
 
   // Record a call's return site offset, used to rebuild the frame if the
   // called function was inlined at the site.
@@ -479,6 +490,7 @@
   void EmitCallWithLoadIC(Call* expr);
   void EmitSuperCallWithLoadIC(Call* expr);
   void EmitKeyedCallWithLoadIC(Call* expr, Expression* key);
+  void EmitKeyedSuperCallWithLoadIC(Call* expr);
 
   // Platform-specific code for inline runtime calls.
   InlineFunctionGenerator FindInlineFunctionGenerator(Runtime::FunctionId id);
@@ -517,16 +529,45 @@
 
   // Platform-specific support for compiling assignments.
 
+  // Left-hand side can only be a property, a global or a (parameter or local)
+  // slot.
+  enum LhsKind {
+    VARIABLE,
+    NAMED_PROPERTY,
+    KEYED_PROPERTY,
+    NAMED_SUPER_PROPERTY,
+    KEYED_SUPER_PROPERTY
+  };
+
+  static LhsKind GetAssignType(Property* property) {
+    if (property == NULL) return VARIABLE;
+    bool super_access = property->IsSuperAccess();
+    return (property->key()->IsPropertyName())
+               ? (super_access ? NAMED_SUPER_PROPERTY : NAMED_PROPERTY)
+               : (super_access ? KEYED_SUPER_PROPERTY : KEYED_PROPERTY);
+  }
+
   // Load a value from a named property.
   // The receiver is left on the stack by the IC.
   void EmitNamedPropertyLoad(Property* expr);
 
+  // Load a value from super.named property.
+  // Expect receiver ('this' value) and home_object on the stack.
   void EmitNamedSuperPropertyLoad(Property* expr);
 
+  // Load a value from super[keyed] property.
+  // Expect receiver ('this' value), home_object and key on the stack.
+  void EmitKeyedSuperPropertyLoad(Property* expr);
+
   // Load a value from a keyed property.
   // The receiver and the key is left on the stack by the IC.
   void EmitKeyedPropertyLoad(Property* expr);
 
+  // Adds the properties to the class (function) object and to its prototype.
+  // Expects the class (function) in the accumulator. The class (function) is
+  // in the accumulator after installing all the properties.
+  void EmitClassDefineProperties(ClassLiteral* lit);
+
   // Apply the compound assignment operator. Expects the left operand on top
   // of the stack and the right one in the accumulator.
   void EmitBinaryOp(BinaryOperation* expr,
@@ -545,6 +586,19 @@
   // is expected in the accumulator.
   void EmitAssignment(Expression* expr);
 
+  // Shall an error be thrown if assignment with 'op' operation is perfomed
+  // on this variable in given language mode?
+  static bool IsSignallingAssignmentToConst(Variable* var, Token::Value op,
+                                            StrictMode strict_mode) {
+    if (var->mode() == CONST) return op != Token::INIT_CONST;
+
+    if (var->mode() == CONST_LEGACY) {
+      return strict_mode == STRICT && op != Token::INIT_CONST_LEGACY;
+    }
+
+    return false;
+  }
+
   // Complete a variable assignment.  The right-hand-side value is expected
   // in the accumulator.
   void EmitVariableAssignment(Variable* var,
@@ -558,6 +612,14 @@
   // of the stack and the right-hand-side value in the accumulator.
   void EmitNamedPropertyAssignment(Assignment* expr);
 
+  // Complete a super named property assignment. The right-hand-side value
+  // is expected in accumulator.
+  void EmitNamedSuperPropertyStore(Property* prop);
+
+  // Complete a super named property assignment. The right-hand-side value
+  // is expected in accumulator.
+  void EmitKeyedSuperPropertyStore(Property* prop);
+
   // Complete a keyed property assignment.  The receiver and key are
   // expected on top of the stack and the right-hand-side value in the
   // accumulator.
@@ -565,6 +627,17 @@
 
   void EmitLoadHomeObject(SuperReference* expr);
 
+  static bool NeedsHomeObject(Expression* expr) {
+    return FunctionLiteral::NeedsHomeObject(expr);
+  }
+
+  // Adds the [[HomeObject]] to |initializer| if it is a FunctionLiteral.
+  // The value of the initializer is expected to be at the top of the stack.
+  // |offset| is the offset in the stack where the home object can be found.
+  void EmitSetHomeObjectIfNeeded(Expression* initializer, int offset);
+
+  void EmitLoadSuperConstructor(SuperReference* expr);
+
   void CallIC(Handle<Code> code,
               TypeFeedbackId id = TypeFeedbackId::None());
 
@@ -619,7 +692,7 @@
   void PushFunctionArgumentForContextAllocation();
 
   // AST node visit functions.
-#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node) OVERRIDE;
   AST_NODE_LIST(DECLARE_VISIT)
 #undef DECLARE_VISIT
 
@@ -822,6 +895,22 @@
     virtual bool IsEffect() const { return true; }
   };
 
+  class EnterBlockScopeIfNeeded {
+   public:
+    EnterBlockScopeIfNeeded(FullCodeGenerator* codegen, Scope* scope,
+                            BailoutId entry_id, BailoutId declarations_id,
+                            BailoutId exit_id);
+    ~EnterBlockScopeIfNeeded();
+
+   private:
+    MacroAssembler* masm() const { return codegen_->masm(); }
+
+    FullCodeGenerator* codegen_;
+    Scope* scope_;
+    Scope* saved_scope_;
+    BailoutId exit_id_;
+  };
+
   MacroAssembler* masm_;
   CompilationInfo* info_;
   Scope* scope_;
diff --git a/src/gdb-jit.cc b/src/gdb-jit.cc
index 776c662..a19fb51 100644
--- a/src/gdb-jit.cc
+++ b/src/gdb-jit.cc
@@ -1842,7 +1842,7 @@
   void __gdb_print_v8_object(Object* object) {
     OFStream os(stdout);
     object->Print(os);
-    os << flush;
+    os << std::flush;
   }
 #endif
 }
diff --git a/src/generator.js b/src/generator.js
index 72e64dc..9ab7dcb 100644
--- a/src/generator.js
+++ b/src/generator.js
@@ -20,8 +20,23 @@
                         ['[Generator].prototype.next', this]);
   }
 
-  if (DEBUG_IS_ACTIVE) %DebugPrepareStepInIfStepping(this);
-  return %_GeneratorNext(this, value);
+  var continuation = %GeneratorGetContinuation(this);
+  if (continuation > 0) {
+    // Generator is suspended.
+    if (DEBUG_IS_ACTIVE) %DebugPrepareStepInIfStepping(this);
+    try {
+      return %_GeneratorNext(this, value);
+    } catch (e) {
+      %GeneratorClose(this);
+      throw e;
+    }
+  } else if (continuation == 0) {
+    // Generator is already closed.
+    return { value: void 0, done: true };
+  } else {
+    // Generator is running.
+    throw MakeTypeError('generator_running', []);
+  }
 }
 
 function GeneratorObjectThrow(exn) {
@@ -30,7 +45,22 @@
                         ['[Generator].prototype.throw', this]);
   }
 
-  return %_GeneratorThrow(this, exn);
+  var continuation = %GeneratorGetContinuation(this);
+  if (continuation > 0) {
+    // Generator is suspended.
+    try {
+      return %_GeneratorThrow(this, exn);
+    } catch (e) {
+      %GeneratorClose(this);
+      throw e;
+    }
+  } else if (continuation == 0) {
+    // Generator is already closed.
+    throw exn;
+  } else {
+    // Generator is running.
+    throw MakeTypeError('generator_running', []);
+  }
 }
 
 function GeneratorObjectIterator() {
@@ -44,13 +74,7 @@
 }
 
 function GeneratorFunctionConstructor(arg1) {  // length == 1
-  var source = NewFunctionString(arguments, 'function*');
-  var global_proxy = %GlobalProxy(global);
-  // Compile the string in the constructor and not a helper so that errors
-  // appear to come from here.
-  var f = %_CallFunction(global_proxy, %CompileString(source, true));
-  %FunctionMarkNameShouldPrintAsAnonymous(f);
-  return f;
+  return NewFunctionFromString(arguments, 'function*');
 }
 
 
@@ -73,11 +97,15 @@
   %AddNamedProperty(GeneratorObjectPrototype, symbolIterator,
       GeneratorObjectIterator, DONT_ENUM | DONT_DELETE | READ_ONLY);
   %AddNamedProperty(GeneratorObjectPrototype, "constructor",
-      GeneratorFunctionPrototype, DONT_ENUM | DONT_DELETE | READ_ONLY);
+      GeneratorFunctionPrototype, DONT_ENUM | READ_ONLY);
+  %AddNamedProperty(GeneratorObjectPrototype,
+      symbolToStringTag, "Generator", DONT_ENUM | READ_ONLY);
   %InternalSetPrototype(GeneratorFunctionPrototype, $Function.prototype);
+  %AddNamedProperty(GeneratorFunctionPrototype,
+      symbolToStringTag, "GeneratorFunction", DONT_ENUM | READ_ONLY);
   %SetCode(GeneratorFunctionPrototype, GeneratorFunctionPrototypeConstructor);
   %AddNamedProperty(GeneratorFunctionPrototype, "constructor",
-      GeneratorFunction, DONT_ENUM | DONT_DELETE | READ_ONLY);
+      GeneratorFunction, DONT_ENUM | READ_ONLY);
   %InternalSetPrototype(GeneratorFunction, $Function);
   %SetCode(GeneratorFunction, GeneratorFunctionConstructor);
 }
diff --git a/src/global-handles.cc b/src/global-handles.cc
index 282ca2d..4f744d6 100644
--- a/src/global-handles.cc
+++ b/src/global-handles.cc
@@ -30,10 +30,11 @@
   // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
   enum State {
     FREE = 0,
-    NORMAL,     // Normal global handle.
-    WEAK,       // Flagged as weak but not yet finalized.
-    PENDING,    // Has been recognized as only reachable by weak handles.
-    NEAR_DEATH  // Callback has informed the handle is near death.
+    NORMAL,      // Normal global handle.
+    WEAK,        // Flagged as weak but not yet finalized.
+    PENDING,     // Has been recognized as only reachable by weak handles.
+    NEAR_DEATH,  // Callback has informed the handle is near death.
+    NUMBER_OF_NODE_STATES
   };
 
   // Maps handle location (slot) to the containing node.
@@ -92,8 +93,14 @@
     IncreaseBlockUses();
   }
 
+  void Zap() {
+    DCHECK(IsInUse());
+    // Zap the values for eager trapping.
+    object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
+  }
+
   void Release() {
-    DCHECK(state() != FREE);
+    DCHECK(IsInUse());
     set_state(FREE);
     // Zap the values for eager trapping.
     object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
@@ -146,6 +153,13 @@
     flags_ = IsInNewSpaceList::update(flags_, v);
   }
 
+  WeaknessType weakness_type() const {
+    return NodeWeaknessType::decode(flags_);
+  }
+  void set_weakness_type(WeaknessType weakness_type) {
+    flags_ = NodeWeaknessType::update(flags_, weakness_type);
+  }
+
   bool IsNearDeath() const {
     // Check for PENDING to ensure correct answer when processing callbacks.
     return state() == PENDING || state() == NEAR_DEATH;
@@ -153,6 +167,8 @@
 
   bool IsWeak() const { return state() == WEAK; }
 
+  bool IsInUse() const { return state() != FREE; }
+
   bool IsRetainer() const { return state() != FREE; }
 
   bool IsStrongRetainer() const { return state() == NORMAL; }
@@ -168,12 +184,12 @@
 
   // Independent flag accessors.
   void MarkIndependent() {
-    DCHECK(state() != FREE);
+    DCHECK(IsInUse());
     set_independent(true);
   }
 
   void MarkPartiallyDependent() {
-    DCHECK(state() != FREE);
+    DCHECK(IsInUse());
     if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) {
       set_partially_dependent(true);
     }
@@ -186,14 +202,39 @@
 
   // Callback parameter accessors.
   void set_parameter(void* parameter) {
-    DCHECK(state() != FREE);
+    DCHECK(IsInUse());
+    DCHECK(weakness_type() == NORMAL_WEAK || weakness_type() == PHANTOM_WEAK);
     parameter_or_next_free_.parameter = parameter;
   }
   void* parameter() const {
-    DCHECK(state() != FREE);
+    DCHECK(IsInUse());
     return parameter_or_next_free_.parameter;
   }
 
+  void set_internal_fields(int internal_field_index1,
+                           int internal_field_index2) {
+    DCHECK(weakness_type() == INTERNAL_FIELDS_WEAK);
+    // These are stored in an int16_t.
+    DCHECK(internal_field_index1 < 1 << 16);
+    DCHECK(internal_field_index1 >= -(1 << 16));
+    DCHECK(internal_field_index2 < 1 << 16);
+    DCHECK(internal_field_index2 >= -(1 << 16));
+    parameter_or_next_free_.internal_field_indeces.internal_field1 =
+        static_cast<int16_t>(internal_field_index1);
+    parameter_or_next_free_.internal_field_indeces.internal_field2 =
+        static_cast<int16_t>(internal_field_index2);
+  }
+
+  int internal_field1() const {
+    DCHECK(weakness_type() == INTERNAL_FIELDS_WEAK);
+    return parameter_or_next_free_.internal_field_indeces.internal_field1;
+  }
+
+  int internal_field2() const {
+    DCHECK(weakness_type() == INTERNAL_FIELDS_WEAK);
+    return parameter_or_next_free_.internal_field_indeces.internal_field2;
+  }
+
   // Accessors for next free node in the free list.
   Node* next_free() {
     DCHECK(state() == FREE);
@@ -206,49 +247,126 @@
 
   void MakeWeak(void* parameter, WeakCallback weak_callback) {
     DCHECK(weak_callback != NULL);
-    DCHECK(state() != FREE);
+    DCHECK(IsInUse());
     CHECK(object_ != NULL);
     set_state(WEAK);
+    set_weakness_type(NORMAL_WEAK);
     set_parameter(parameter);
     weak_callback_ = weak_callback;
   }
 
+  void MakePhantom(void* parameter,
+                   PhantomCallbackData<void>::Callback phantom_callback,
+                   int16_t internal_field_index1,
+                   int16_t internal_field_index2) {
+    DCHECK(phantom_callback != NULL);
+    DCHECK(IsInUse());
+    CHECK(object_ != NULL);
+    set_state(WEAK);
+    if (parameter == NULL) {
+      set_weakness_type(INTERNAL_FIELDS_WEAK);
+      set_internal_fields(internal_field_index1, internal_field_index2);
+    } else {
+      DCHECK(internal_field_index1 == v8::Object::kNoInternalFieldIndex);
+      DCHECK(internal_field_index2 == v8::Object::kNoInternalFieldIndex);
+      set_weakness_type(PHANTOM_WEAK);
+      set_parameter(parameter);
+    }
+    weak_callback_ = reinterpret_cast<WeakCallback>(phantom_callback);
+  }
+
   void* ClearWeakness() {
-    DCHECK(state() != FREE);
+    DCHECK(IsInUse());
     void* p = parameter();
     set_state(NORMAL);
     set_parameter(NULL);
     return p;
   }
 
+  void CollectPhantomCallbackData(
+      Isolate* isolate, List<PendingPhantomCallback>* pending_phantom_callbacks,
+      List<PendingInternalFieldsCallback>* pending_internal_fields_callbacks) {
+    if (state() != Node::PENDING) return;
+    bool do_release = true;
+    if (weak_callback_ != NULL) {
+      if (weakness_type() == NORMAL_WEAK) return;
+
+      v8::Isolate* api_isolate = reinterpret_cast<v8::Isolate*>(isolate);
+
+      if (weakness_type() == PHANTOM_WEAK) {
+        // Phantom weak pointer case. Zap with harmless value.
+        DCHECK(*location() == Smi::FromInt(0));
+        typedef PhantomCallbackData<void> Data;
+
+        Data data(api_isolate, parameter());
+        Data::Callback callback =
+            reinterpret_cast<Data::Callback>(weak_callback_);
+
+        pending_phantom_callbacks->Add(
+            PendingPhantomCallback(this, data, callback));
+
+        // Postpone the release of the handle. The embedder can't use the
+        // handle (it's zapped), but it may be using the location, and we
+        // don't want to confuse things by reusing that.
+        do_release = false;
+      } else {
+        DCHECK(weakness_type() == INTERNAL_FIELDS_WEAK);
+        typedef InternalFieldsCallbackData<void, void> Data;
+
+        // Phantom weak pointer case, passing internal fields instead of
+        // parameter. Don't use a handle here during GC, because it will
+        // create a handle pointing to a dying object, which can confuse
+        // the next GC.
+        JSObject* jsobject = reinterpret_cast<JSObject*>(object());
+        DCHECK(jsobject->IsJSObject());
+        Data data(api_isolate, jsobject->GetInternalField(internal_field1()),
+                  jsobject->GetInternalField(internal_field2()));
+        Data::Callback callback =
+            reinterpret_cast<Data::Callback>(weak_callback_);
+
+        // In the future, we want to delay the callback. In that case we will
+        // zap when we queue up, to stop the C++ side accessing the dead V8
+        // object, but we will call Release only after the callback (allowing
+        // the node to be reused).
+        pending_internal_fields_callbacks->Add(
+            PendingInternalFieldsCallback(data, callback));
+      }
+    }
+    // TODO(erikcorry): At the moment the callbacks are not postponed much,
+    // but if we really postpone them until after the mutator has run, we
+    // need to divide things up, so that an early callback clears the handle,
+    // while a later one destroys the objects involved, possibley triggering
+    // some work when decremented ref counts hit zero.
+    if (do_release) Release();
+  }
+
   bool PostGarbageCollectionProcessing(Isolate* isolate) {
     if (state() != Node::PENDING) return false;
     if (weak_callback_ == NULL) {
       Release();
       return false;
     }
-    void* par = parameter();
     set_state(NEAR_DEATH);
-    set_parameter(NULL);
 
+    // Check that we are not passing a finalized external string to
+    // the callback.
+    DCHECK(!object_->IsExternalOneByteString() ||
+           ExternalOneByteString::cast(object_)->resource() != NULL);
+    DCHECK(!object_->IsExternalTwoByteString() ||
+           ExternalTwoByteString::cast(object_)->resource() != NULL);
+    // Leaving V8.
+    VMState<EXTERNAL> vmstate(isolate);
+    HandleScope handle_scope(isolate);
+    if (weakness_type() == PHANTOM_WEAK) return false;
+    DCHECK(weakness_type() == NORMAL_WEAK);
     Object** object = location();
-    {
-      // Check that we are not passing a finalized external string to
-      // the callback.
-      DCHECK(!object_->IsExternalOneByteString() ||
-             ExternalOneByteString::cast(object_)->resource() != NULL);
-      DCHECK(!object_->IsExternalTwoByteString() ||
-             ExternalTwoByteString::cast(object_)->resource() != NULL);
-      // Leaving V8.
-      VMState<EXTERNAL> state(isolate);
-      HandleScope handle_scope(isolate);
-      Handle<Object> handle(*object, isolate);
-      v8::WeakCallbackData<v8::Value, void> data(
-          reinterpret_cast<v8::Isolate*>(isolate),
-          v8::Utils::ToLocal(handle),
-          par);
-      weak_callback_(data);
-    }
+    Handle<Object> handle(*object, isolate);
+    v8::WeakCallbackData<v8::Value, void> data(
+        reinterpret_cast<v8::Isolate*>(isolate), parameter(),
+        v8::Utils::ToLocal(handle));
+    set_parameter(NULL);
+    weak_callback_(data);
+
     // Absence of explicit cleanup or revival of weak handle
     // in most of the cases would lead to memory leak.
     CHECK(state() != NEAR_DEATH);
@@ -277,10 +395,11 @@
 
   // This stores three flags (independent, partially_dependent and
   // in_new_space_list) and a State.
-  class NodeState:            public BitField<State, 0, 4> {};
-  class IsIndependent:        public BitField<bool,  4, 1> {};
-  class IsPartiallyDependent: public BitField<bool,  5, 1> {};
-  class IsInNewSpaceList:     public BitField<bool,  6, 1> {};
+  class NodeState : public BitField<State, 0, 3> {};
+  class IsIndependent : public BitField<bool, 3, 1> {};
+  class IsPartiallyDependent : public BitField<bool, 4, 1> {};
+  class IsInNewSpaceList : public BitField<bool, 5, 1> {};
+  class NodeWeaknessType : public BitField<WeaknessType, 6, 2> {};
 
   uint8_t flags_;
 
@@ -291,6 +410,10 @@
   // the free list link.
   union {
     void* parameter;
+    struct {
+      int16_t internal_field1;
+      int16_t internal_field2;
+    } internal_field_indeces;
     Node* next_free;
   } parameter_or_next_free_;
 
@@ -475,13 +598,42 @@
 }
 
 
-void GlobalHandles::MakeWeak(Object** location,
-                             void* parameter,
+void GlobalHandles::MakeWeak(Object** location, void* parameter,
                              WeakCallback weak_callback) {
   Node::FromLocation(location)->MakeWeak(parameter, weak_callback);
 }
 
 
+typedef PhantomCallbackData<void>::Callback GenericCallback;
+
+
+void GlobalHandles::MakePhantom(
+    Object** location,
+    v8::InternalFieldsCallbackData<void, void>::Callback phantom_callback,
+    int16_t internal_field_index1, int16_t internal_field_index2) {
+  Node::FromLocation(location)
+      ->MakePhantom(NULL, reinterpret_cast<GenericCallback>(phantom_callback),
+                    internal_field_index1, internal_field_index2);
+}
+
+
+void GlobalHandles::MakePhantom(Object** location, void* parameter,
+                                GenericCallback phantom_callback) {
+  Node::FromLocation(location)->MakePhantom(parameter, phantom_callback,
+                                            v8::Object::kNoInternalFieldIndex,
+                                            v8::Object::kNoInternalFieldIndex);
+}
+
+
+void GlobalHandles::CollectPhantomCallbackData() {
+  for (NodeIterator it(this); !it.done(); it.Advance()) {
+    Node* node = it.node();
+    node->CollectPhantomCallbackData(isolate(), &pending_phantom_callbacks_,
+                                     &pending_internal_fields_callbacks_);
+  }
+}
+
+
 void* GlobalHandles::ClearWeakness(Object** location) {
   return Node::FromLocation(location)->ClearWeakness();
 }
@@ -514,7 +666,32 @@
 
 void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
   for (NodeIterator it(this); !it.done(); it.Advance()) {
-    if (it.node()->IsWeakRetainer()) v->VisitPointer(it.node()->location());
+    Node* node = it.node();
+    if (node->IsWeakRetainer()) {
+      // Weakness type can be normal, phantom or internal fields.
+      // For normal weakness we mark through the handle so that
+      // the object and things reachable from it are available
+      // to the callback.
+      // In the case of phantom we can zap the object handle now
+      // and we won't need it, so we don't need to mark through it.
+      // In the internal fields case we will need the internal
+      // fields, so we can't zap the handle, but we don't need to
+      // mark through it, because it will die in this GC round.
+      if (node->state() == Node::PENDING) {
+        if (node->weakness_type() == PHANTOM_WEAK) {
+          *(node->location()) = Smi::FromInt(0);
+        } else if (node->weakness_type() == NORMAL_WEAK) {
+          v->VisitPointer(node->location());
+        } else {
+          DCHECK(node->weakness_type() == INTERNAL_FIELDS_WEAK);
+        }
+      } else {
+        // Node is not pending, so that means the object survived.  We still
+        // need to visit the pointer in case the object moved, eg. because of
+        // compaction.
+        v->VisitPointer(node->location());
+      }
+    }
   }
 }
 
@@ -559,7 +736,20 @@
     DCHECK(node->is_in_new_space_list());
     if ((node->is_independent() || node->is_partially_dependent()) &&
         node->IsWeakRetainer()) {
-      v->VisitPointer(node->location());
+      if (node->weakness_type() == PHANTOM_WEAK) {
+        *(node->location()) = Smi::FromInt(0);
+      } else if (node->weakness_type() == NORMAL_WEAK) {
+        v->VisitPointer(node->location());
+      } else {
+        DCHECK(node->weakness_type() == INTERNAL_FIELDS_WEAK);
+        // For this case we only need to trace if it's alive: The tracing of
+        // something that is already alive is just to get the pointer updated
+        // to the new location of the object).
+        DCHECK(node->state() != Node::NEAR_DEATH);
+        if (node->state() != Node::PENDING) {
+          v->VisitPointer(node->location());
+        }
+      }
     }
   }
 }
@@ -611,63 +801,66 @@
 }
 
 
-int GlobalHandles::PostGarbageCollectionProcessing(
-    GarbageCollector collector) {
-  // Process weak global handle callbacks. This must be done after the
-  // GC is completely done, because the callbacks may invoke arbitrary
-  // API functions.
-  DCHECK(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
-  const int initial_post_gc_processing_count = ++post_gc_processing_count_;
+int GlobalHandles::PostScavengeProcessing(
+    const int initial_post_gc_processing_count) {
   int freed_nodes = 0;
-  if (collector == SCAVENGER) {
-    for (int i = 0; i < new_space_nodes_.length(); ++i) {
-      Node* node = new_space_nodes_[i];
-      DCHECK(node->is_in_new_space_list());
-      if (!node->IsRetainer()) {
-        // Free nodes do not have weak callbacks. Do not use them to compute
-        // the freed_nodes.
-        continue;
-      }
-      // Skip dependent handles. Their weak callbacks might expect to be
-      // called between two global garbage collection callbacks which
-      // are not called for minor collections.
-      if (!node->is_independent() && !node->is_partially_dependent()) {
-        continue;
-      }
-      node->clear_partially_dependent();
-      if (node->PostGarbageCollectionProcessing(isolate_)) {
-        if (initial_post_gc_processing_count != post_gc_processing_count_) {
-          // Weak callback triggered another GC and another round of
-          // PostGarbageCollection processing.  The current node might
-          // have been deleted in that round, so we need to bail out (or
-          // restart the processing).
-          return freed_nodes;
-        }
-      }
-      if (!node->IsRetainer()) {
-        freed_nodes++;
+  for (int i = 0; i < new_space_nodes_.length(); ++i) {
+    Node* node = new_space_nodes_[i];
+    DCHECK(node->is_in_new_space_list());
+    if (!node->IsRetainer()) {
+      // Free nodes do not have weak callbacks. Do not use them to compute
+      // the freed_nodes.
+      continue;
+    }
+    // Skip dependent handles. Their weak callbacks might expect to be
+    // called between two global garbage collection callbacks which
+    // are not called for minor collections.
+    if (!node->is_independent() && !node->is_partially_dependent()) {
+      continue;
+    }
+    node->clear_partially_dependent();
+    if (node->PostGarbageCollectionProcessing(isolate_)) {
+      if (initial_post_gc_processing_count != post_gc_processing_count_) {
+        // Weak callback triggered another GC and another round of
+        // PostGarbageCollection processing.  The current node might
+        // have been deleted in that round, so we need to bail out (or
+        // restart the processing).
+        return freed_nodes;
       }
     }
-  } else {
-    for (NodeIterator it(this); !it.done(); it.Advance()) {
-      if (!it.node()->IsRetainer()) {
-        // Free nodes do not have weak callbacks. Do not use them to compute
-        // the freed_nodes.
-        continue;
-      }
-      it.node()->clear_partially_dependent();
-      if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
-        if (initial_post_gc_processing_count != post_gc_processing_count_) {
-          // See the comment above.
-          return freed_nodes;
-        }
-      }
-      if (!it.node()->IsRetainer()) {
-        freed_nodes++;
-      }
+    if (!node->IsRetainer()) {
+      freed_nodes++;
     }
   }
-  // Update the list of new space nodes.
+  return freed_nodes;
+}
+
+
+int GlobalHandles::PostMarkSweepProcessing(
+    const int initial_post_gc_processing_count) {
+  int freed_nodes = 0;
+  for (NodeIterator it(this); !it.done(); it.Advance()) {
+    if (!it.node()->IsRetainer()) {
+      // Free nodes do not have weak callbacks. Do not use them to compute
+      // the freed_nodes.
+      continue;
+    }
+    it.node()->clear_partially_dependent();
+    if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
+      if (initial_post_gc_processing_count != post_gc_processing_count_) {
+        // See the comment above.
+        return freed_nodes;
+      }
+    }
+    if (!it.node()->IsRetainer()) {
+      freed_nodes++;
+    }
+  }
+  return freed_nodes;
+}
+
+
+void GlobalHandles::UpdateListOfNewSpaceNodes() {
   int last = 0;
   for (int i = 0; i < new_space_nodes_.length(); ++i) {
     Node* node = new_space_nodes_[i];
@@ -686,10 +879,59 @@
     }
   }
   new_space_nodes_.Rewind(last);
+}
+
+
+int GlobalHandles::DispatchPendingPhantomCallbacks() {
+  int freed_nodes = 0;
+  while (pending_phantom_callbacks_.length() != 0) {
+    PendingPhantomCallback callback = pending_phantom_callbacks_.RemoveLast();
+    callback.invoke();
+    freed_nodes++;
+  }
+  while (pending_internal_fields_callbacks_.length() != 0) {
+    PendingInternalFieldsCallback callback =
+        pending_internal_fields_callbacks_.RemoveLast();
+    callback.invoke();
+    freed_nodes++;
+  }
   return freed_nodes;
 }
 
 
+int GlobalHandles::PostGarbageCollectionProcessing(GarbageCollector collector) {
+  // Process weak global handle callbacks. This must be done after the
+  // GC is completely done, because the callbacks may invoke arbitrary
+  // API functions.
+  DCHECK(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
+  const int initial_post_gc_processing_count = ++post_gc_processing_count_;
+  int freed_nodes = 0;
+  if (collector == SCAVENGER) {
+    freed_nodes = PostScavengeProcessing(initial_post_gc_processing_count);
+  } else {
+    freed_nodes = PostMarkSweepProcessing(initial_post_gc_processing_count);
+  }
+  if (initial_post_gc_processing_count != post_gc_processing_count_) {
+    // If the callbacks caused a nested GC, then return.  See comment in
+    // PostScavengeProcessing.
+    return freed_nodes;
+  }
+  freed_nodes += DispatchPendingPhantomCallbacks();
+  if (initial_post_gc_processing_count == post_gc_processing_count_) {
+    UpdateListOfNewSpaceNodes();
+  }
+  return freed_nodes;
+}
+
+
+void GlobalHandles::PendingPhantomCallback::invoke() {
+  if (node_->state() == Node::FREE) return;
+  DCHECK(node_->state() == Node::NEAR_DEATH);
+  callback_(data_);
+  if (node_->state() != Node::FREE) node_->Release();
+}
+
+
 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
   for (NodeIterator it(this); !it.done(); it.Advance()) {
     if (it.node()->IsStrongRetainer()) {
diff --git a/src/global-handles.h b/src/global-handles.h
index a06cba0..b3756d0 100644
--- a/src/global-handles.h
+++ b/src/global-handles.h
@@ -97,6 +97,13 @@
 };
 
 
+enum WeaknessType {
+  NORMAL_WEAK,          // Embedder gets a handle to the dying object.
+  PHANTOM_WEAK,         // Embedder gets the parameter they passed in earlier.
+  INTERNAL_FIELDS_WEAK  // Embedder gets 2 internal fields from dying object.
+};
+
+
 class GlobalHandles {
  public:
   ~GlobalHandles();
@@ -112,16 +119,35 @@
 
   typedef WeakCallbackData<v8::Value, void>::Callback WeakCallback;
 
+  // For a phantom weak reference, the callback does not have access to the
+  // dying object.  Phantom weak references are preferred because they allow
+  // memory to be reclaimed in one GC cycle rather than two.  However, for
+  // historical reasons the default is non-phantom.
+  enum PhantomState { Nonphantom, Phantom };
+
   // Make the global handle weak and set the callback parameter for the
   // handle.  When the garbage collector recognizes that only weak global
-  // handles point to an object the handles are cleared and the callback
-  // function is invoked (for each handle) with the handle and corresponding
-  // parameter as arguments.  Note: cleared means set to Smi::FromInt(0). The
-  // reason is that Smi::FromInt(0) does not change during garage collection.
-  static void MakeWeak(Object** location,
-                       void* parameter,
+  // handles point to an object the callback function is invoked (for each
+  // handle) with the handle and corresponding parameter as arguments.  By
+  // default the handle still contains a pointer to the object that is being
+  // collected.  For this reason the object is not collected until the next
+  // GC.  For a phantom weak handle the handle is cleared (set to a Smi)
+  // before the callback is invoked, but the handle can still be identified
+  // in the callback by using the location() of the handle.
+  static void MakeWeak(Object** location, void* parameter,
                        WeakCallback weak_callback);
 
+  // It would be nice to template this one, but it's really hard to get
+  // the template instantiator to work right if you do.
+  static void MakePhantom(Object** location, void* parameter,
+                          PhantomCallbackData<void>::Callback weak_callback);
+
+  static void MakePhantom(
+      Object** location,
+      v8::InternalFieldsCallbackData<void, void>::Callback weak_callback,
+      int16_t internal_field_index1,
+      int16_t internal_field_index2 = v8::Object::kNoInternalFieldIndex);
+
   void RecordStats(HeapStats* stats);
 
   // Returns the current number of weak handles.
@@ -136,6 +162,10 @@
     return number_of_global_handles_;
   }
 
+  // Collect up data for the weak handle callbacks after GC has completed, but
+  // before memory is reclaimed.
+  void CollectPhantomCallbackData();
+
   // Clear the weakness of a global handle.
   static void* ClearWeakness(Object** location);
 
@@ -261,10 +291,18 @@
   // don't assign any initial capacity.
   static const int kObjectGroupConnectionsCapacity = 20;
 
+  // Helpers for PostGarbageCollectionProcessing.
+  int PostScavengeProcessing(int initial_post_gc_processing_count);
+  int PostMarkSweepProcessing(int initial_post_gc_processing_count);
+  int DispatchPendingPhantomCallbacks();
+  void UpdateListOfNewSpaceNodes();
+
   // Internal node structures.
   class Node;
   class NodeBlock;
   class NodeIterator;
+  class PendingPhantomCallback;
+  class PendingInternalFieldsCallback;
 
   Isolate* isolate_;
 
@@ -297,12 +335,46 @@
   List<ObjectGroupRetainerInfo> retainer_infos_;
   List<ObjectGroupConnection> implicit_ref_connections_;
 
+  List<PendingPhantomCallback> pending_phantom_callbacks_;
+  List<PendingInternalFieldsCallback> pending_internal_fields_callbacks_;
+
   friend class Isolate;
 
   DISALLOW_COPY_AND_ASSIGN(GlobalHandles);
 };
 
 
+class GlobalHandles::PendingPhantomCallback {
+ public:
+  typedef PhantomCallbackData<void> Data;
+  PendingPhantomCallback(Node* node, Data data, Data::Callback callback)
+      : node_(node), data_(data), callback_(callback) {}
+
+  void invoke();
+
+  Node* node() { return node_; }
+
+ private:
+  Node* node_;
+  Data data_;
+  Data::Callback callback_;
+};
+
+
+class GlobalHandles::PendingInternalFieldsCallback {
+ public:
+  typedef InternalFieldsCallbackData<void, void> Data;
+  PendingInternalFieldsCallback(Data data, Data::Callback callback)
+      : data_(data), callback_(callback) {}
+
+  void invoke() { callback_(data_); }
+
+ private:
+  Data data_;
+  Data::Callback callback_;
+};
+
+
 class EternalHandles {
  public:
   enum SingletonHandle {
diff --git a/src/globals.h b/src/globals.h
index 609ab88..52ec2aa 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -5,7 +5,8 @@
 #ifndef V8_GLOBALS_H_
 #define V8_GLOBALS_H_
 
-#include "include/v8stdint.h"
+#include <stddef.h>
+#include <stdint.h>
 
 #include "src/base/build_config.h"
 #include "src/base/logging.h"
@@ -25,13 +26,14 @@
 # define V8_INFINITY INFINITY
 #endif
 
-#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM || \
-    V8_TARGET_ARCH_ARM64
+#if V8_TARGET_ARCH_IA32 || (V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_32_BIT) || \
+    V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_MIPS ||     \
+    V8_TARGET_ARCH_MIPS64
 #define V8_TURBOFAN_BACKEND 1
 #else
 #define V8_TURBOFAN_BACKEND 0
 #endif
-#if V8_TURBOFAN_BACKEND && !(V8_OS_WIN && V8_TARGET_ARCH_X64)
+#if V8_TURBOFAN_BACKEND
 #define V8_TURBOFAN_TARGET 1
 #else
 #define V8_TURBOFAN_TARGET 0
@@ -80,23 +82,14 @@
 #endif
 
 
-// Support for alternative bool type. This is only enabled if the code is
-// compiled with USE_MYBOOL defined. This catches some nasty type bugs.
-// For instance, 'bool b = "false";' results in b == true! This is a hidden
-// source of bugs.
-// However, redefining the bool type does have some negative impact on some
-// platforms. It gives rise to compiler warnings (i.e. with
-// MSVC) in the API header files when mixing code that uses the standard
-// bool with code that uses the redefined version.
-// This does not actually belong in the platform code, but needs to be
-// defined here because the platform code uses bool, and platform.h is
-// include very early in the main include file.
-
-#ifdef USE_MYBOOL
-typedef unsigned int __my_bool__;
-#define bool __my_bool__  // use 'indirection' to avoid name clashes
+// Determine whether double field unboxing feature is enabled.
+#if (V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64)
+#define V8_DOUBLE_FIELDS_UNBOXING 0
+#else
+#define V8_DOUBLE_FIELDS_UNBOXING 0
 #endif
 
+
 typedef uint8_t byte;
 typedef byte* Address;
 
@@ -143,6 +136,13 @@
 const uintptr_t kUintptrAllBitsSet = V8_UINT64_C(0xFFFFFFFFFFFFFFFF);
 const bool kRequiresCodeRange = true;
 const size_t kMaximalCodeRangeSize = 512 * MB;
+#if V8_OS_WIN
+const size_t kMinimumCodeRangeSize = 4 * MB;
+const size_t kReservedCodeRangePages = 1;
+#else
+const size_t kMinimumCodeRangeSize = 3 * MB;
+const size_t kReservedCodeRangePages = 0;
+#endif
 #else
 const int kPointerSizeLog2 = 2;
 const intptr_t kIntptrSignBit = 0x80000000;
@@ -151,9 +151,13 @@
 // x32 port also requires code range.
 const bool kRequiresCodeRange = true;
 const size_t kMaximalCodeRangeSize = 256 * MB;
+const size_t kMinimumCodeRangeSize = 3 * MB;
+const size_t kReservedCodeRangePages = 0;
 #else
 const bool kRequiresCodeRange = false;
 const size_t kMaximalCodeRangeSize = 0 * MB;
+const size_t kMinimumCodeRangeSize = 0 * MB;
+const size_t kReservedCodeRangePages = 0;
 #endif
 #endif
 
@@ -276,6 +280,7 @@
 #endif
 
 const int kCodeZapValue = 0xbadc0de;
+const uint32_t kPhantomReferenceZap = 0xca11bac;
 
 // On Intel architecture, cache line size is 64 bytes.
 // On ARM it may be less (32 bytes), but as far this constant is
@@ -339,8 +344,10 @@
 template <typename Config, class Allocator = FreeStoreAllocationPolicy>
     class SplayTree;
 class String;
+class Symbol;
 class Name;
 class Struct;
+class Symbol;
 class Variable;
 class RelocInfo;
 class Deserializer;
@@ -355,6 +362,7 @@
 
 // NOTE: SpaceIterator depends on AllocationSpace enumeration values being
 // consecutive.
+// Keep this enum in sync with the ObjectSpace enum in v8.h
 enum AllocationSpace {
   NEW_SPACE,            // Semispaces collected with copying collector.
   OLD_POINTER_SPACE,    // May contain pointers to new space.
@@ -364,7 +372,6 @@
   CELL_SPACE,           // Only and all cell objects.
   PROPERTY_CELL_SPACE,  // Only and all global property cell objects.
   LO_SPACE,             // Promoted large objects.
-  INVALID_SPACE,        // Only used in AllocationResult to signal success.
 
   FIRST_SPACE = NEW_SPACE,
   LAST_SPACE = LO_SPACE,
@@ -547,22 +554,6 @@
 };
 
 
-// Logging and profiling.  A StateTag represents a possible state of
-// the VM. The logger maintains a stack of these. Creating a VMState
-// object enters a state by pushing on the stack, and destroying a
-// VMState object leaves a state by popping the current state from the
-// stack.
-
-enum StateTag {
-  JS,
-  GC,
-  COMPILER,
-  OTHER,
-  EXTERNAL,
-  IDLE
-};
-
-
 // -----------------------------------------------------------------------------
 // Macros
 
@@ -609,28 +600,32 @@
 
 // CPU feature flags.
 enum CpuFeature {
-    // x86
-    SSE4_1,
-    SSE3,
-    SAHF,
-    // ARM
-    VFP3,
-    ARMv7,
-    SUDIV,
-    MLS,
-    UNALIGNED_ACCESSES,
-    MOVW_MOVT_IMMEDIATE_LOADS,
-    VFP32DREGS,
-    NEON,
-    // MIPS, MIPS64
-    FPU,
-    FP64FPU,
-    MIPSr1,
-    MIPSr2,
-    MIPSr6,
-    // ARM64
-    ALWAYS_ALIGN_CSP,
-    NUMBER_OF_CPU_FEATURES
+  // x86
+  SSE4_1,
+  SSE3,
+  SAHF,
+  AVX,
+  FMA3,
+  // ARM
+  VFP3,
+  ARMv7,
+  ARMv8,
+  SUDIV,
+  MLS,
+  UNALIGNED_ACCESSES,
+  MOVW_MOVT_IMMEDIATE_LOADS,
+  VFP32DREGS,
+  NEON,
+  // MIPS, MIPS64
+  FPU,
+  FP64FPU,
+  MIPSr1,
+  MIPSr2,
+  MIPSr6,
+  // ARM64
+  ALWAYS_ALIGN_CSP,
+  COHERENT_CACHE,
+  NUMBER_OF_CPU_FEATURES
 };
 
 
@@ -646,10 +641,11 @@
   EVAL_SCOPE,      // The top-level scope for an eval source.
   FUNCTION_SCOPE,  // The top-level scope for a function.
   MODULE_SCOPE,    // The scope introduced by a module literal
-  GLOBAL_SCOPE,    // The top-level scope for a program or a top-level eval.
+  SCRIPT_SCOPE,    // The top-level scope for a script or a top-level eval.
   CATCH_SCOPE,     // The scope introduced by catch.
   BLOCK_SCOPE,     // The scope introduced by a new block.
-  WITH_SCOPE       // The scope introduced by with.
+  WITH_SCOPE,      // The scope introduced by with.
+  ARROW_SCOPE      // The top-level scope for an arrow function literal.
 };
 
 
@@ -777,7 +773,8 @@
   kArrowFunction = 1,
   kGeneratorFunction = 2,
   kConciseMethod = 4,
-  kConciseGeneratorMethod = kGeneratorFunction | kConciseMethod
+  kConciseGeneratorMethod = kGeneratorFunction | kConciseMethod,
+  kDefaultConstructor = 8
 };
 
 
@@ -786,7 +783,8 @@
          kind == FunctionKind::kArrowFunction ||
          kind == FunctionKind::kGeneratorFunction ||
          kind == FunctionKind::kConciseMethod ||
-         kind == FunctionKind::kConciseGeneratorMethod;
+         kind == FunctionKind::kConciseGeneratorMethod ||
+         kind == FunctionKind::kDefaultConstructor;
 }
 
 
@@ -806,6 +804,14 @@
   DCHECK(IsValidFunctionKind(kind));
   return kind & FunctionKind::kConciseMethod;
 }
+
+
+inline bool IsDefaultConstructor(FunctionKind kind) {
+  DCHECK(IsValidFunctionKind(kind));
+  return kind & FunctionKind::kDefaultConstructor;
+}
+
+
 } }  // namespace v8::internal
 
 namespace i = v8::internal;
diff --git a/src/handles.h b/src/handles.h
index 577e83a..eb57f0e 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -53,7 +53,8 @@
   }
 
   // Convert to a Handle with a type that can be upcasted to.
-  template <class S> INLINE(bool ToHandle(Handle<S>* out)) {
+  template <class S>
+  V8_INLINE bool ToHandle(Handle<S>* out) const {
     if (location_ == NULL) {
       *out = Handle<T>::null();
       return false;
diff --git a/src/harmony-array-includes.js b/src/harmony-array-includes.js
new file mode 100644
index 0000000..d1a7790
--- /dev/null
+++ b/src/harmony-array-includes.js
@@ -0,0 +1,61 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+'use strict';
+
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $Array = global.Array;
+
+// -------------------------------------------------------------------
+
+// Proposed for ES7
+// https://github.com/tc39/Array.prototype.includes
+// 6e3b78c927aeda20b9d40e81303f9d44596cd904
+function ArrayIncludes(searchElement, fromIndex) {
+  var array = ToObject(this);
+  var len = ToLength(array.length);
+
+  if (len === 0) {
+    return false;
+  }
+
+  var n = ToInteger(fromIndex);
+
+  var k;
+  if (n >= 0) {
+    k = n;
+  } else {
+    k = len + n;
+    if (k < 0) {
+      k = 0;
+    }
+  }
+
+  while (k < len) {
+    var elementK = array[k];
+    if (SameValueZero(searchElement, elementK)) {
+      return true;
+    }
+
+    ++k;
+  }
+
+  return false;
+}
+
+// -------------------------------------------------------------------
+
+function HarmonyArrayIncludesExtendArrayPrototype() {
+  %CheckIsBootstrapping();
+
+  %FunctionSetLength(ArrayIncludes, 1);
+
+  // Set up the non-enumerable functions on the Array prototype object.
+  InstallFunctions($Array.prototype, DONT_ENUM, $Array(
+    "includes", ArrayIncludes
+  ));
+}
+
+HarmonyArrayIncludesExtendArrayPrototype();
diff --git a/src/harmony-array.js b/src/harmony-array.js
index 88b878f..5d1262a 100644
--- a/src/harmony-array.js
+++ b/src/harmony-array.js
@@ -26,16 +26,18 @@
     thisArg = %_Arguments(1);
   }
 
+  var needs_wrapper = false;
   if (IS_NULL_OR_UNDEFINED(thisArg)) {
     thisArg = %GetDefaultReceiver(predicate) || thisArg;
-  } else if (!IS_SPEC_OBJECT(thisArg) && %IsSloppyModeFunction(predicate)) {
-    thisArg = ToObject(thisArg);
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(predicate, thisArg);
   }
 
   for (var i = 0; i < length; i++) {
     if (i in array) {
       var element = array[i];
-      if (%_CallFunction(thisArg, element, i, array, predicate)) {
+      var newThisArg = needs_wrapper ? ToObject(thisArg) : thisArg;
+      if (%_CallFunction(newThisArg, element, i, array, predicate)) {
         return element;
       }
     }
@@ -61,16 +63,18 @@
     thisArg = %_Arguments(1);
   }
 
+  var needs_wrapper = false;
   if (IS_NULL_OR_UNDEFINED(thisArg)) {
     thisArg = %GetDefaultReceiver(predicate) || thisArg;
-  } else if (!IS_SPEC_OBJECT(thisArg) && %IsSloppyModeFunction(predicate)) {
-    thisArg = ToObject(thisArg);
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(predicate, thisArg);
   }
 
   for (var i = 0; i < length; i++) {
     if (i in array) {
       var element = array[i];
-      if (%_CallFunction(thisArg, element, i, array, predicate)) {
+      var newThisArg = needs_wrapper ? ToObject(thisArg) : thisArg;
+      if (%_CallFunction(newThisArg, element, i, array, predicate)) {
         return i;
       }
     }
@@ -123,6 +127,56 @@
   return array;
 }
 
+// ES6, draft 10-14-14, section 22.1.2.1
+function ArrayFrom(arrayLike, mapfn, receiver) {
+  var items = ToObject(arrayLike);
+  var mapping = !IS_UNDEFINED(mapfn);
+
+  if (mapping) {
+    if (!IS_SPEC_FUNCTION(mapfn)) {
+      throw MakeTypeError('called_non_callable', [ mapfn ]);
+    } else if (IS_NULL_OR_UNDEFINED(receiver)) {
+      receiver = %GetDefaultReceiver(mapfn) || receiver;
+    } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(mapfn)) {
+      receiver = ToObject(receiver);
+    }
+  }
+
+  var iterable = ToIterable(items);
+  var k;
+  var result;
+  var mappedValue;
+  var nextValue;
+
+  if (!IS_UNDEFINED(iterable)) {
+    result = IS_SPEC_FUNCTION(this) && this.prototype ? new this() : [];
+
+    k = 0;
+    for (nextValue of items) {
+      if (mapping) mappedValue = %_CallFunction(receiver, nextValue, k, mapfn);
+      else mappedValue = nextValue;
+      %AddElement(result, k++, mappedValue, NONE);
+    }
+
+    result.length = k;
+    return result;
+  } else {
+    var len = ToLength(items.length);
+    result = IS_SPEC_FUNCTION(this) && this.prototype ? new this(len) :
+        new $Array(len);
+
+    for (k = 0; k < len; ++k) {
+      nextValue = items[k];
+      if (mapping) mappedValue = %_CallFunction(receiver, nextValue, k, mapfn);
+      else mappedValue = nextValue;
+      %AddElement(result, k, mappedValue, NONE);
+    }
+
+    result.length = k;
+    return result;
+  }
+}
+
 // ES6, draft 05-22-14, section 22.1.2.3
 function ArrayOf() {
   var length = %_ArgumentsLength();
@@ -138,11 +192,25 @@
 
 // -------------------------------------------------------------------
 
+function HarmonyArrayExtendSymbolPrototype() {
+  %CheckIsBootstrapping();
+
+  InstallConstants($Symbol, $Array(
+    // TODO(dslomov, caitp): Move to symbol.js when shipping
+   "isConcatSpreadable", symbolIsConcatSpreadable
+  ));
+}
+
+HarmonyArrayExtendSymbolPrototype();
+
 function HarmonyArrayExtendArrayPrototype() {
   %CheckIsBootstrapping();
 
+  %FunctionSetLength(ArrayFrom, 1);
+
   // Set up non-enumerable functions on the Array object.
   InstallFunctions($Array, DONT_ENUM, $Array(
+    "from", ArrayFrom,
     "of", ArrayOf
   ));
 
diff --git a/src/harmony-classes.js b/src/harmony-classes.js
index b6605a9..ac06758 100644
--- a/src/harmony-classes.js
+++ b/src/harmony-classes.js
@@ -7,26 +7,29 @@
 // var $Function = global.Function;
 // var $Array = global.Array;
 
+"use strict";
 
-(function() {
-  function FunctionToMethod(homeObject) {
-    if (!IS_SPEC_FUNCTION(this)) {
-      throw MakeTypeError('toMethod_non_function',
-                          [%ToString(this), typeof this]);
+function FunctionToMethod(homeObject) {
+  if (!IS_SPEC_FUNCTION(this)) {
+    throw MakeTypeError('toMethod_non_function',
+                        [%ToString(this), typeof this]);
 
-    }
-
-    if (!IS_SPEC_OBJECT(homeObject)) {
-      throw MakeTypeError('toMethod_non_object',
-                          [%ToString(homeObject)]);
-    }
-
-    return %ToMethod(this, homeObject);
   }
 
+  if (!IS_SPEC_OBJECT(homeObject)) {
+    throw MakeTypeError('toMethod_non_object',
+                        [%ToString(homeObject)]);
+  }
+
+  return %ToMethod(this, homeObject);
+}
+
+function SetupHarmonyClasses() {
   %CheckIsBootstrapping();
 
   InstallFunctions($Function.prototype, DONT_ENUM, $Array(
       "toMethod", FunctionToMethod
   ));
-}());
+}
+
+SetupHarmonyClasses();
diff --git a/src/harmony-regexp.js b/src/harmony-regexp.js
new file mode 100644
index 0000000..a1b32ab
--- /dev/null
+++ b/src/harmony-regexp.js
@@ -0,0 +1,35 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+'use strict';
+
+var $RegExp = global.RegExp;
+
+// -------------------------------------------------------------------
+
+// ES6 draft 12-06-13, section 21.2.5.3
+// + https://bugs.ecmascript.org/show_bug.cgi?id=3423
+function RegExpGetFlags() {
+  if (!IS_SPEC_OBJECT(this)) {
+    throw MakeTypeError('flags_getter_non_object',
+                        [%ToString(this)]);
+  }
+  var result = '';
+  if (this.global) result += 'g';
+  if (this.ignoreCase) result += 'i';
+  if (this.multiline) result += 'm';
+  if (this.unicode) result += 'u';
+  if (this.sticky) result += 'y';
+  return result;
+}
+
+function ExtendRegExpPrototype() {
+  %CheckIsBootstrapping();
+
+  %DefineAccessorPropertyUnchecked($RegExp.prototype, 'flags', RegExpGetFlags,
+                                   null, DONT_ENUM);
+  %SetNativeFlag(RegExpGetFlags);
+}
+
+ExtendRegExpPrototype();
diff --git a/src/harmony-string.js b/src/harmony-string.js
index ae13745..6bbe139 100644
--- a/src/harmony-string.js
+++ b/src/harmony-string.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-'use strict';
+"use strict";
 
 // This file relies on the fact that the following declaration has been made
 // in runtime.js:
@@ -17,16 +17,19 @@
 
   var s = TO_STRING_INLINE(this);
   var n = ToInteger(count);
-  if (n < 0 || !NUMBER_IS_FINITE(n)) {
+  // The maximum string length is stored in a smi, so a longer repeat
+  // must result in a range error.
+  if (n < 0 || n > %_MaxSmi()) {
     throw MakeRangeError("invalid_count_value", []);
   }
 
-  var elements = new InternalArray(n);
-  for (var i = 0; i < n; i++) {
-    elements[i] = s;
+  var r = "";
+  while (true) {
+    if (n & 1) r += s;
+    n >>= 1;
+    if (n === 0) return r;
+    s += s;
   }
-
-  return %StringBuilderConcat(elements, n, "");
 }
 
 
@@ -92,14 +95,14 @@
 
 
 // ES6 draft 04-05-14, section 21.1.3.6
-function StringContains(searchString /* position */) {  // length == 1
-  CHECK_OBJECT_COERCIBLE(this, "String.prototype.contains");
+function StringIncludes(searchString /* position */) {  // length == 1
+  CHECK_OBJECT_COERCIBLE(this, "String.prototype.includes");
 
   var s = TO_STRING_INLINE(this);
 
   if (IS_REGEXP(searchString)) {
     throw MakeTypeError("first_argument_not_regexp",
-                        ["String.prototype.contains"]);
+                        ["String.prototype.includes"]);
   }
 
   var ss = TO_STRING_INLINE(searchString);
@@ -181,7 +184,7 @@
   // Set up the non-enumerable functions on the String prototype object.
   InstallFunctions($String.prototype, DONT_ENUM, $Array(
     "codePointAt", StringCodePointAt,
-    "contains", StringContains,
+    "includes", StringIncludes,
     "endsWith", StringEndsWith,
     "repeat", StringRepeat,
     "startsWith", StringStartsWith
diff --git a/src/harmony-templates.js b/src/harmony-templates.js
new file mode 100644
index 0000000..254f434
--- /dev/null
+++ b/src/harmony-templates.js
@@ -0,0 +1,94 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+"use strict";
+
+var callSiteCache = new $Map;
+
+function SameCallSiteElements(rawStrings, other) {
+  var length = rawStrings.length;
+  var other = other.raw;
+
+  if (length !== other.length) return false;
+
+  for (var i = 0; i < length; ++i) {
+    if (rawStrings[i] !== other[i]) return false;
+  }
+
+  return true;
+}
+
+
+function GetCachedCallSite(siteObj, hash) {
+  var obj = %MapGet(callSiteCache, hash);
+
+  if (IS_UNDEFINED(obj)) return;
+
+  var length = obj.length;
+  for (var i = 0; i < length; ++i) {
+    if (SameCallSiteElements(siteObj, obj[i])) return obj[i];
+  }
+}
+
+
+function SetCachedCallSite(siteObj, hash) {
+  var obj = %MapGet(callSiteCache, hash);
+  var array;
+
+  if (IS_UNDEFINED(obj)) {
+    array = new InternalArray(1);
+    array[0] = siteObj;
+    %MapSet(callSiteCache, hash, array);
+  } else {
+    obj.push(siteObj);
+  }
+
+  return siteObj;
+}
+
+
+function GetTemplateCallSite(siteObj, rawStrings, hash) {
+  var cached = GetCachedCallSite(rawStrings, hash);
+
+  if (!IS_UNDEFINED(cached)) return cached;
+
+  %AddNamedProperty(siteObj, "raw", %ObjectFreeze(rawStrings),
+      READ_ONLY | DONT_ENUM | DONT_DELETE);
+
+  return SetCachedCallSite(%ObjectFreeze(siteObj), hash);
+}
+
+
+// ES6 Draft 10-14-2014, section 21.1.2.4
+function StringRaw(callSite) {
+  // TODO(caitp): Use rest parameters when implemented
+  var numberOfSubstitutions = %_ArgumentsLength();
+  var cooked = ToObject(callSite);
+  var raw = ToObject(cooked.raw);
+  var literalSegments = ToLength(raw.length);
+  if (literalSegments <= 0) return "";
+
+  var result = ToString(raw[0]);
+
+  for (var i = 1; i < literalSegments; ++i) {
+    if (i < numberOfSubstitutions) {
+      result += ToString(%_Arguments(i));
+    }
+    result += ToString(raw[i]);
+  }
+
+  return result;
+}
+
+
+function ExtendStringForTemplates() {
+  %CheckIsBootstrapping();
+
+  // Set up the non-enumerable functions on the String object.
+  InstallFunctions($String, DONT_ENUM, $Array(
+    "raw", StringRaw
+  ));
+}
+
+ExtendStringForTemplates();
diff --git a/src/harmony-tostring.js b/src/harmony-tostring.js
new file mode 100644
index 0000000..0336456
--- /dev/null
+++ b/src/harmony-tostring.js
@@ -0,0 +1,72 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+"use strict";
+
+// This file relies on the fact that the following declaration has been made
+// in runtime.js and symbol.js:
+// var $Object = global.Object;
+// var $Symbol = global.Symbol;
+
+var kBuiltinStringTags = {
+  "__proto__": null,
+  "Arguments": true,
+  "Array": true,
+  "Boolean": true,
+  "Date": true,
+  "Error": true,
+  "Function": true,
+  "Number": true,
+  "RegExp": true,
+  "String": true
+};
+
+DefaultObjectToString = ObjectToStringHarmony;
+// ES6 draft 08-24-14, section 19.1.3.6
+function ObjectToStringHarmony() {
+  if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
+  if (IS_NULL(this)) return "[object Null]";
+  var O = ToObject(this);
+  var builtinTag = %_ClassOf(O);
+  var tag = O[symbolToStringTag];
+  if (IS_UNDEFINED(tag)) {
+    tag = builtinTag;
+  } else if (!IS_STRING(tag)) {
+    return "[object ???]"
+  } else if (tag !== builtinTag && kBuiltinStringTags[tag]) {
+    return "[object ~" + tag + "]";
+  }
+  return "[object " + tag + "]";
+}
+
+function HarmonyToStringExtendSymbolPrototype() {
+  %CheckIsBootstrapping();
+
+  InstallConstants($Symbol, $Array(
+    // TODO(dslomov, caitp): Move to symbol.js when shipping
+   "toStringTag", symbolToStringTag
+  ));
+}
+
+HarmonyToStringExtendSymbolPrototype();
+
+function HarmonyToStringExtendObjectPrototype() {
+  %CheckIsBootstrapping();
+
+  // Can't use InstallFunctions() because will fail in Debug mode.
+  // Emulate InstallFunctions() here.
+  %FunctionSetName(ObjectToStringHarmony, "toString");
+  %FunctionRemovePrototype(ObjectToStringHarmony);
+  %SetNativeFlag(ObjectToStringHarmony);
+
+  // Set up the non-enumerable functions on the Array prototype object.
+  var desc = ToPropertyDescriptor({
+    value: ObjectToStringHarmony
+  });
+  DefineOwnProperty($Object.prototype, "toString", desc, false);
+
+  %ToFastProperties($Object.prototype);
+}
+
+HarmonyToStringExtendObjectPrototype();
diff --git a/src/harmony-typedarray.js b/src/harmony-typedarray.js
new file mode 100644
index 0000000..c2eb452
--- /dev/null
+++ b/src/harmony-typedarray.js
@@ -0,0 +1,95 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+"use strict";
+
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $Array = global.Array;
+
+// -------------------------------------------------------------------
+
+macro TYPED_ARRAYS(FUNCTION)
+// arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
+FUNCTION(1, Uint8Array, 1)
+FUNCTION(2, Int8Array, 1)
+FUNCTION(3, Uint16Array, 2)
+FUNCTION(4, Int16Array, 2)
+FUNCTION(5, Uint32Array, 4)
+FUNCTION(6, Int32Array, 4)
+FUNCTION(7, Float32Array, 4)
+FUNCTION(8, Float64Array, 8)
+FUNCTION(9, Uint8ClampedArray, 1)
+endmacro
+
+
+macro TYPED_ARRAY_HARMONY_ADDITIONS(ARRAY_ID, NAME, ELEMENT_SIZE)
+
+// ES6 draft 08-24-14, section 22.2.3.12
+function NAMEForEach(f /* thisArg */) {  // length == 1
+  if (!%IsTypedArray(this)) {
+    throw MakeTypeError('not_typed_array', []);
+  }
+  if (!IS_SPEC_FUNCTION(f)) {
+    throw MakeTypeError('called_non_callable', [ f ]);
+  }
+
+  var length = %_TypedArrayGetLength(this);
+  var receiver;
+
+  if (%_ArgumentsLength() > 1) {
+    receiver = %_Arguments(1);
+  }
+
+  var needs_wrapper = false;
+  if (IS_NULL_OR_UNDEFINED(receiver)) {
+    receiver = %GetDefaultReceiver(f) || receiver;
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
+  }
+
+  var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
+  for (var i = 0; i < length; i++) {
+    var element = this[i];
+    // Prepare break slots for debugger step in.
+    if (stepping) %DebugPrepareStepInIfStepping(f);
+    var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+    %_CallFunction(new_receiver, TO_OBJECT_INLINE(element), i, this, f);
+  }
+}
+
+// ES6 draft 08-24-14, section 22.2.2.2
+function NAMEOf() {  // length == 0
+  var length = %_ArgumentsLength();
+  var array = new this(length);
+  for (var i = 0; i < length; i++) {
+    array[i] = %_Arguments(i);
+  }
+  return array;
+}
+
+endmacro
+
+TYPED_ARRAYS(TYPED_ARRAY_HARMONY_ADDITIONS)
+
+
+function HarmonyTypedArrayExtendPrototypes() {
+macro EXTEND_TYPED_ARRAY(ARRAY_ID, NAME, ELEMENT_SIZE)
+  %CheckIsBootstrapping();
+
+  // Set up non-enumerable functions on the object.
+  InstallFunctions(global.NAME, DONT_ENUM | DONT_DELETE | READ_ONLY, $Array(
+    "of", NAMEOf
+  ));
+
+  // Set up non-enumerable functions on the prototype object.
+  InstallFunctions(global.NAME.prototype, DONT_ENUM, $Array(
+    "forEach", NAMEForEach
+  ));
+endmacro
+
+  TYPED_ARRAYS(EXTEND_TYPED_ARRAY)
+}
+
+HarmonyTypedArrayExtendPrototypes();
diff --git a/src/heap-snapshot-generator-inl.h b/src/heap-snapshot-generator-inl.h
index 3f7e622..ad95776 100644
--- a/src/heap-snapshot-generator-inl.h
+++ b/src/heap-snapshot-generator-inl.h
@@ -12,7 +12,7 @@
 
 
 HeapEntry* HeapGraphEdge::from() const {
-  return &snapshot()->entries()[from_index_];
+  return &snapshot()->entries()[from_index()];
 }
 
 
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
index 4a4c914..196eb13 100644
--- a/src/heap-snapshot-generator.cc
+++ b/src/heap-snapshot-generator.cc
@@ -18,8 +18,7 @@
 
 
 HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to)
-    : type_(type),
-      from_index_(from),
+    : bit_field_(TypeField::encode(type) | FromIndexField::encode(from)),
       to_index_(to),
       name_(name) {
   DCHECK(type == kContextVariable
@@ -31,8 +30,7 @@
 
 
 HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to)
-    : type_(type),
-      from_index_(from),
+    : bit_field_(TypeField::encode(type) | FromIndexField::encode(from)),
       to_index_(to),
       index_(index) {
   DCHECK(type == kElement || type == kHidden);
@@ -1169,13 +1167,10 @@
                          "native_context", global_obj->native_context(),
                          GlobalObject::kNativeContextOffset);
     SetInternalReference(global_obj, entry,
-                         "global_context", global_obj->global_context(),
-                         GlobalObject::kGlobalContextOffset);
-    SetInternalReference(global_obj, entry,
                          "global_proxy", global_obj->global_proxy(),
                          GlobalObject::kGlobalProxyOffset);
     STATIC_ASSERT(GlobalObject::kHeaderSize - JSObject::kHeaderSize ==
-                 4 * kPointerSize);
+                 3 * kPointerSize);
   } else if (obj->IsJSArrayBufferView()) {
     JSArrayBufferView* view = JSArrayBufferView::cast(obj);
     SetInternalReference(view, entry, "buffer", view->buffer(),
@@ -1284,7 +1279,7 @@
                   Context::FIRST_WEAK_SLOT);
     STATIC_ASSERT(Context::NEXT_CONTEXT_LINK + 1 ==
                   Context::NATIVE_CONTEXT_SLOTS);
-    STATIC_ASSERT(Context::FIRST_WEAK_SLOT + 5 ==
+    STATIC_ASSERT(Context::FIRST_WEAK_SLOT + 4 ==
                   Context::NATIVE_CONTEXT_SLOTS);
   }
 }
@@ -1631,53 +1626,32 @@
     DescriptorArray* descs = js_obj->map()->instance_descriptors();
     int real_size = js_obj->map()->NumberOfOwnDescriptors();
     for (int i = 0; i < real_size; i++) {
-      switch (descs->GetType(i)) {
-        case FIELD: {
-          Representation r = descs->GetDetails(i).representation();
+      PropertyDetails details = descs->GetDetails(i);
+      switch (details.location()) {
+        case IN_OBJECT: {
+          Representation r = details.representation();
           if (r.IsSmi() || r.IsDouble()) break;
-          int index = descs->GetFieldIndex(i);
 
           Name* k = descs->GetKey(i);
-          if (index < js_obj->map()->inobject_properties()) {
-            Object* value = js_obj->InObjectPropertyAt(index);
-            if (k != heap_->hidden_string()) {
-              SetPropertyReference(
-                  js_obj, entry,
-                  k, value,
-                  NULL,
-                  js_obj->GetInObjectPropertyOffset(index));
-            } else {
-              TagObject(value, "(hidden properties)");
-              SetInternalReference(
-                  js_obj, entry,
-                  "hidden_properties", value,
-                  js_obj->GetInObjectPropertyOffset(index));
-            }
+          FieldIndex field_index = FieldIndex::ForDescriptor(js_obj->map(), i);
+          Object* value = js_obj->RawFastPropertyAt(field_index);
+          int field_offset =
+              field_index.is_inobject() ? field_index.offset() : -1;
+
+          if (k != heap_->hidden_string()) {
+            SetDataOrAccessorPropertyReference(details.kind(), js_obj, entry, k,
+                                               value, NULL, field_offset);
           } else {
-            FieldIndex field_index =
-                FieldIndex::ForDescriptor(js_obj->map(), i);
-            Object* value = js_obj->RawFastPropertyAt(field_index);
-            if (k != heap_->hidden_string()) {
-              SetPropertyReference(js_obj, entry, k, value);
-            } else {
-              TagObject(value, "(hidden properties)");
-              SetInternalReference(js_obj, entry, "hidden_properties", value);
-            }
+            TagObject(value, "(hidden properties)");
+            SetInternalReference(js_obj, entry, "hidden_properties", value,
+                                 field_offset);
           }
           break;
         }
-        case CONSTANT:
-          SetPropertyReference(
-              js_obj, entry,
-              descs->GetKey(i), descs->GetConstant(i));
-          break;
-        case CALLBACKS:
-          ExtractAccessorPairProperty(
-              js_obj, entry,
-              descs->GetKey(i), descs->GetValue(i));
-          break;
-        case NORMAL:  // only in slow mode
-          UNREACHABLE();
+        case IN_DESCRIPTOR:
+          SetDataOrAccessorPropertyReference(details.kind(), js_obj, entry,
+                                             descs->GetKey(i),
+                                             descs->GetValue(i));
           break;
       }
     }
@@ -1697,27 +1671,30 @@
           SetInternalReference(js_obj, entry, "hidden_properties", value);
           continue;
         }
-        if (ExtractAccessorPairProperty(js_obj, entry, k, value)) continue;
-        SetPropertyReference(js_obj, entry, String::cast(k), value);
+        PropertyDetails details = dictionary->DetailsAt(i);
+        SetDataOrAccessorPropertyReference(details.kind(), js_obj, entry,
+                                           Name::cast(k), value);
       }
     }
   }
 }
 
 
-bool V8HeapExplorer::ExtractAccessorPairProperty(
-    JSObject* js_obj, int entry, Object* key, Object* callback_obj) {
-  if (!callback_obj->IsAccessorPair()) return false;
+void V8HeapExplorer::ExtractAccessorPairProperty(JSObject* js_obj, int entry,
+                                                 Name* key,
+                                                 Object* callback_obj,
+                                                 int field_offset) {
+  if (!callback_obj->IsAccessorPair()) return;
   AccessorPair* accessors = AccessorPair::cast(callback_obj);
+  SetPropertyReference(js_obj, entry, key, accessors, NULL, field_offset);
   Object* getter = accessors->getter();
   if (!getter->IsOddball()) {
-    SetPropertyReference(js_obj, entry, String::cast(key), getter, "get %s");
+    SetPropertyReference(js_obj, entry, key, getter, "get %s");
   }
   Object* setter = accessors->setter();
   if (!setter->IsOddball()) {
-    SetPropertyReference(js_obj, entry, String::cast(key), setter, "set %s");
+    SetPropertyReference(js_obj, entry, key, setter, "set %s");
   }
-  return true;
 }
 
 
@@ -2056,6 +2033,20 @@
 }
 
 
+void V8HeapExplorer::SetDataOrAccessorPropertyReference(
+    PropertyKind kind, JSObject* parent_obj, int parent_entry,
+    Name* reference_name, Object* child_obj, const char* name_format_string,
+    int field_offset) {
+  if (kind == ACCESSOR) {
+    ExtractAccessorPairProperty(parent_obj, parent_entry, reference_name,
+                                child_obj, field_offset);
+  } else {
+    SetPropertyReference(parent_obj, parent_entry, reference_name, child_obj,
+                         name_format_string, field_offset);
+  }
+}
+
+
 void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
                                           int parent_entry,
                                           Name* reference_name,
@@ -2164,6 +2155,12 @@
 #define STRING_NAME(name, str) NAME_ENTRY(name)
     INTERNALIZED_STRING_LIST(STRING_NAME)
 #undef STRING_NAME
+#define SYMBOL_NAME(name) NAME_ENTRY(name)
+    PRIVATE_SYMBOL_LIST(SYMBOL_NAME)
+#undef SYMBOL_NAME
+#define SYMBOL_NAME(name, varname, description) NAME_ENTRY(name)
+    PUBLIC_SYMBOL_LIST(SYMBOL_NAME)
+#undef SYMBOL_NAME
 #undef NAME_ENTRY
     CHECK(!strong_gc_subroot_names_.is_empty());
   }
@@ -2297,7 +2294,6 @@
     : isolate_(snapshot->profiler()->heap_object_map()->heap()->isolate()),
       snapshot_(snapshot),
       names_(snapshot_->profiler()->names()),
-      progress_(progress),
       embedder_queried_(false),
       objects_by_info_(RetainedInfosMatch),
       native_groups_(StringsMatch),
diff --git a/src/heap-snapshot-generator.h b/src/heap-snapshot-generator.h
index 3e4ce71..8aef437 100644
--- a/src/heap-snapshot-generator.h
+++ b/src/heap-snapshot-generator.h
@@ -28,22 +28,18 @@
     kWeak = v8::HeapGraphEdge::kWeak
   };
 
-  HeapGraphEdge() { }
   HeapGraphEdge(Type type, const char* name, int from, int to);
   HeapGraphEdge(Type type, int index, int from, int to);
   void ReplaceToIndexWithEntry(HeapSnapshot* snapshot);
 
-  Type type() const { return static_cast<Type>(type_); }
+  Type type() const { return TypeField::decode(bit_field_); }
   int index() const {
-    DCHECK(type_ == kElement || type_ == kHidden);
+    DCHECK(type() == kElement || type() == kHidden);
     return index_;
   }
   const char* name() const {
-    DCHECK(type_ == kContextVariable
-        || type_ == kProperty
-        || type_ == kInternal
-        || type_ == kShortcut
-        || type_ == kWeak);
+    DCHECK(type() == kContextVariable || type() == kProperty ||
+           type() == kInternal || type() == kShortcut || type() == kWeak);
     return name_;
   }
   INLINE(HeapEntry* from() const);
@@ -51,9 +47,11 @@
 
  private:
   INLINE(HeapSnapshot* snapshot() const);
+  int from_index() const { return FromIndexField::decode(bit_field_); }
 
-  unsigned type_ : 3;
-  int from_index_ : 29;
+  class TypeField : public BitField<Type, 0, 3> {};
+  class FromIndexField : public BitField<int, 3, 29> {};
+  uint32_t bit_field_;
   union {
     // During entries population |to_index_| is used for storing the index,
     // afterwards it is replaced with a pointer to the entry.
@@ -176,7 +174,6 @@
   void FillChildren();
 
   void Print(int max_depth);
-  void PrintEntriesSize();
 
  private:
   HeapEntry* AddRootEntry();
@@ -332,7 +329,6 @@
                  v8::HeapProfiler::ObjectNameResolver* resolver);
   virtual ~V8HeapExplorer();
   virtual HeapEntry* AllocateEntry(HeapThing ptr);
-  void AddRootEntries(SnapshotFiller* filler);
   int EstimateObjectsCount(HeapIterator* iterator);
   bool IterateAndExtractReferences(SnapshotFiller* filler);
   void TagGlobalObjects();
@@ -385,8 +381,8 @@
   void ExtractFixedArrayReferences(int entry, FixedArray* array);
   void ExtractClosureReferences(JSObject* js_obj, int entry);
   void ExtractPropertyReferences(JSObject* js_obj, int entry);
-  bool ExtractAccessorPairProperty(JSObject* js_obj, int entry,
-                                   Object* key, Object* callback_obj);
+  void ExtractAccessorPairProperty(JSObject* js_obj, int entry, Name* key,
+                                   Object* callback_obj, int field_offset = -1);
   void ExtractElementReferences(JSObject* js_obj, int entry);
   void ExtractInternalReferences(JSObject* js_obj, int entry);
 
@@ -434,6 +430,12 @@
                             Object* child,
                             const char* name_format_string = NULL,
                             int field_offset = -1);
+  void SetDataOrAccessorPropertyReference(PropertyKind kind,
+                                          JSObject* parent_obj, int parent,
+                                          Name* reference_name, Object* child,
+                                          const char* name_format_string = NULL,
+                                          int field_offset = -1);
+
   void SetUserGlobalReference(Object* user_global);
   void SetRootGcRootsReference();
   void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
@@ -473,7 +475,6 @@
   NativeObjectsExplorer(HeapSnapshot* snapshot,
                         SnapshottingProgressReportingInterface* progress);
   virtual ~NativeObjectsExplorer();
-  void AddRootEntries(SnapshotFiller* filler);
   int EstimateObjectsCount();
   bool IterateAndExtractReferences(SnapshotFiller* filler);
 
@@ -506,7 +507,6 @@
   Isolate* isolate_;
   HeapSnapshot* snapshot_;
   StringsStorage* names_;
-  SnapshottingProgressReportingInterface* progress_;
   bool embedder_queried_;
   HeapObjectsSet in_groups_;
   // RetainedObjectInfo* -> List<HeapObject*>*
diff --git a/src/heap/gc-idle-time-handler-unittest.cc b/src/heap/gc-idle-time-handler-unittest.cc
deleted file mode 100644
index b4f2f74..0000000
--- a/src/heap/gc-idle-time-handler-unittest.cc
+++ /dev/null
@@ -1,348 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <limits>
-
-#include "src/heap/gc-idle-time-handler.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace v8 {
-namespace internal {
-
-namespace {
-
-class GCIdleTimeHandlerTest : public ::testing::Test {
- public:
-  GCIdleTimeHandlerTest() {}
-  virtual ~GCIdleTimeHandlerTest() {}
-
-  GCIdleTimeHandler* handler() { return &handler_; }
-
-  GCIdleTimeHandler::HeapState DefaultHeapState() {
-    GCIdleTimeHandler::HeapState result;
-    result.contexts_disposed = 0;
-    result.size_of_objects = kSizeOfObjects;
-    result.incremental_marking_stopped = false;
-    result.can_start_incremental_marking = true;
-    result.sweeping_in_progress = false;
-    result.mark_compact_speed_in_bytes_per_ms = kMarkCompactSpeed;
-    result.incremental_marking_speed_in_bytes_per_ms = kMarkingSpeed;
-    result.scavenge_speed_in_bytes_per_ms = kScavengeSpeed;
-    result.available_new_space_memory = kNewSpaceCapacity;
-    result.new_space_capacity = kNewSpaceCapacity;
-    result.new_space_allocation_throughput_in_bytes_per_ms =
-        kNewSpaceAllocationThroughput;
-    return result;
-  }
-
-  static const size_t kSizeOfObjects = 100 * MB;
-  static const size_t kMarkCompactSpeed = 200 * KB;
-  static const size_t kMarkingSpeed = 200 * KB;
-  static const size_t kScavengeSpeed = 100 * KB;
-  static const size_t kNewSpaceCapacity = 1 * MB;
-  static const size_t kNewSpaceAllocationThroughput = 10 * KB;
-
- private:
-  GCIdleTimeHandler handler_;
-};
-
-}  // namespace
-
-
-TEST(GCIdleTimeHandler, EstimateMarkingStepSizeInitial) {
-  size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(1, 0);
-  EXPECT_EQ(
-      static_cast<size_t>(GCIdleTimeHandler::kInitialConservativeMarkingSpeed *
-                          GCIdleTimeHandler::kConservativeTimeRatio),
-      step_size);
-}
-
-
-TEST(GCIdleTimeHandler, EstimateMarkingStepSizeNonZero) {
-  size_t marking_speed_in_bytes_per_millisecond = 100;
-  size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
-      1, marking_speed_in_bytes_per_millisecond);
-  EXPECT_EQ(static_cast<size_t>(marking_speed_in_bytes_per_millisecond *
-                                GCIdleTimeHandler::kConservativeTimeRatio),
-            step_size);
-}
-
-
-TEST(GCIdleTimeHandler, EstimateMarkingStepSizeOverflow1) {
-  size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
-      10, std::numeric_limits<size_t>::max());
-  EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize),
-            step_size);
-}
-
-
-TEST(GCIdleTimeHandler, EstimateMarkingStepSizeOverflow2) {
-  size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
-      std::numeric_limits<size_t>::max(), 10);
-  EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize),
-            step_size);
-}
-
-
-TEST(GCIdleTimeHandler, EstimateMarkCompactTimeInitial) {
-  size_t size = 100 * MB;
-  size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, 0);
-  EXPECT_EQ(size / GCIdleTimeHandler::kInitialConservativeMarkCompactSpeed,
-            time);
-}
-
-
-TEST(GCIdleTimeHandler, EstimateMarkCompactTimeNonZero) {
-  size_t size = 100 * MB;
-  size_t speed = 1 * MB;
-  size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, speed);
-  EXPECT_EQ(size / speed, time);
-}
-
-
-TEST(GCIdleTimeHandler, EstimateMarkCompactTimeMax) {
-  size_t size = std::numeric_limits<size_t>::max();
-  size_t speed = 1;
-  size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, speed);
-  EXPECT_EQ(GCIdleTimeHandler::kMaxMarkCompactTimeInMs, time);
-}
-
-
-TEST(GCIdleTimeHandler, EstimateScavengeTimeInitial) {
-  size_t size = 1 * MB;
-  size_t time = GCIdleTimeHandler::EstimateScavengeTime(size, 0);
-  EXPECT_EQ(size / GCIdleTimeHandler::kInitialConservativeScavengeSpeed, time);
-}
-
-
-TEST(GCIdleTimeHandler, EstimateScavengeTimeNonZero) {
-  size_t size = 1 * MB;
-  size_t speed = 1 * MB;
-  size_t time = GCIdleTimeHandler::EstimateScavengeTime(size, speed);
-  EXPECT_EQ(size / speed, time);
-}
-
-
-TEST(GCIdleTimeHandler, ScavangeMayHappenSoonInitial) {
-  size_t available = 100 * KB;
-  EXPECT_FALSE(GCIdleTimeHandler::ScavangeMayHappenSoon(available, 0));
-}
-
-
-TEST(GCIdleTimeHandler, ScavangeMayHappenSoonNonZeroFalse) {
-  size_t available = (GCIdleTimeHandler::kMaxFrameRenderingIdleTime + 1) * KB;
-  size_t speed = 1 * KB;
-  EXPECT_FALSE(GCIdleTimeHandler::ScavangeMayHappenSoon(available, speed));
-}
-
-
-TEST(GCIdleTimeHandler, ScavangeMayHappenSoonNonZeroTrue) {
-  size_t available = GCIdleTimeHandler::kMaxFrameRenderingIdleTime * KB;
-  size_t speed = 1 * KB;
-  EXPECT_TRUE(GCIdleTimeHandler::ScavangeMayHappenSoon(available, speed));
-}
-
-
-TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeLargeIdleTime) {
-  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
-  heap_state.contexts_disposed = 1;
-  heap_state.incremental_marking_stopped = true;
-  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
-  int idle_time_ms =
-      static_cast<int>((heap_state.size_of_objects + speed - 1) / speed);
-  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DO_FULL_GC, action.type);
-}
-
-
-TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) {
-  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
-  heap_state.contexts_disposed = 1;
-  heap_state.incremental_marking_stopped = true;
-  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
-  int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed - 1);
-  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
-}
-
-
-TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) {
-  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
-  heap_state.contexts_disposed = 1;
-  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
-  int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed - 1);
-  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
-}
-
-
-TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) {
-  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
-  size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms;
-  int idle_time_ms = 10;
-  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
-  EXPECT_GT(speed * static_cast<size_t>(idle_time_ms),
-            static_cast<size_t>(action.parameter));
-  EXPECT_LT(0, action.parameter);
-}
-
-
-TEST_F(GCIdleTimeHandlerTest, IncrementalMarking2) {
-  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
-  heap_state.incremental_marking_stopped = true;
-  size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms;
-  int idle_time_ms = 10;
-  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
-  EXPECT_GT(speed * static_cast<size_t>(idle_time_ms),
-            static_cast<size_t>(action.parameter));
-  EXPECT_LT(0, action.parameter);
-}
-
-
-TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) {
-  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
-  heap_state.incremental_marking_stopped = true;
-  heap_state.can_start_incremental_marking = false;
-  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
-  int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed - 1);
-  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DO_NOTHING, action.type);
-}
-
-
-TEST_F(GCIdleTimeHandlerTest, StopEventually1) {
-  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
-  heap_state.incremental_marking_stopped = true;
-  heap_state.can_start_incremental_marking = false;
-  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
-  int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed + 1);
-  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
-    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-    EXPECT_EQ(DO_FULL_GC, action.type);
-    handler()->NotifyIdleMarkCompact();
-  }
-  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DONE, action.type);
-}
-
-
-TEST_F(GCIdleTimeHandlerTest, StopEventually2) {
-  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
-  int idle_time_ms = 10;
-  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
-    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-    EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
-    // In this case we emulate incremental marking steps that finish with a
-    // full gc.
-    handler()->NotifyIdleMarkCompact();
-  }
-  heap_state.can_start_incremental_marking = false;
-  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DONE, action.type);
-}
-
-
-TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop1) {
-  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
-  heap_state.incremental_marking_stopped = true;
-  heap_state.can_start_incremental_marking = false;
-  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
-  int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed + 1);
-  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
-    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-    EXPECT_EQ(DO_FULL_GC, action.type);
-    handler()->NotifyIdleMarkCompact();
-  }
-  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DONE, action.type);
-  // Emulate mutator work.
-  for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
-    handler()->NotifyScavenge();
-  }
-  action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DO_FULL_GC, action.type);
-}
-
-
-TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop2) {
-  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
-  int idle_time_ms = 10;
-  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
-    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-    if (action.type == DONE) break;
-    EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
-    // In this case we try to emulate incremental marking steps the finish with
-    // a full gc.
-    handler()->NotifyIdleMarkCompact();
-  }
-  heap_state.can_start_incremental_marking = false;
-  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DONE, action.type);
-  // Emulate mutator work.
-  for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
-    handler()->NotifyScavenge();
-  }
-  heap_state.can_start_incremental_marking = true;
-  action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
-}
-
-
-TEST_F(GCIdleTimeHandlerTest, Scavenge) {
-  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
-  int idle_time_ms = 10;
-  heap_state.available_new_space_memory =
-      kNewSpaceAllocationThroughput * idle_time_ms;
-  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DO_SCAVENGE, action.type);
-}
-
-
-TEST_F(GCIdleTimeHandlerTest, ScavengeAndDone) {
-  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
-  int idle_time_ms = 10;
-  heap_state.can_start_incremental_marking = false;
-  heap_state.incremental_marking_stopped = true;
-  heap_state.available_new_space_memory =
-      kNewSpaceAllocationThroughput * idle_time_ms;
-  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DO_SCAVENGE, action.type);
-  heap_state.available_new_space_memory = kNewSpaceCapacity;
-  action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DO_NOTHING, action.type);
-}
-
-
-TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeNothingToDo) {
-  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
-  int idle_time_ms = 0;
-  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-  EXPECT_EQ(DO_NOTHING, action.type);
-}
-
-
-TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeDoNothingButStartIdleRound) {
-  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
-  int idle_time_ms = 10;
-  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
-    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-    if (action.type == DONE) break;
-    EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
-    // In this case we try to emulate incremental marking steps the finish with
-    // a full gc.
-    handler()->NotifyIdleMarkCompact();
-  }
-  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
-  // Emulate mutator work.
-  for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
-    handler()->NotifyScavenge();
-  }
-  action = handler()->Compute(0, heap_state);
-  EXPECT_EQ(DO_NOTHING, action.type);
-}
-
-}  // namespace internal
-}  // namespace v8
diff --git a/src/heap/gc-idle-time-handler.cc b/src/heap/gc-idle-time-handler.cc
index b9a99b2..ff2a559 100644
--- a/src/heap/gc-idle-time-handler.cc
+++ b/src/heap/gc-idle-time-handler.cc
@@ -11,9 +11,11 @@
 
 const double GCIdleTimeHandler::kConservativeTimeRatio = 0.9;
 const size_t GCIdleTimeHandler::kMaxMarkCompactTimeInMs = 1000;
+const size_t GCIdleTimeHandler::kMaxFinalIncrementalMarkCompactTimeInMs = 1000;
 const size_t GCIdleTimeHandler::kMinTimeForFinalizeSweeping = 100;
 const int GCIdleTimeHandler::kMaxMarkCompactsInIdleRound = 7;
 const int GCIdleTimeHandler::kIdleScavengeThreshold = 5;
+const double GCIdleTimeHandler::kHighContextDisposalRate = 100;
 
 
 void GCIdleTimeAction::Print() {
@@ -25,7 +27,11 @@
       PrintF("no action");
       break;
     case DO_INCREMENTAL_MARKING:
-      PrintF("incremental marking with step %" V8_PTR_PREFIX "d", parameter);
+      PrintF("incremental marking with step %" V8_PTR_PREFIX "d / ms",
+             parameter);
+      if (additional_work) {
+        PrintF("; finalized marking");
+      }
       break;
     case DO_SCAVENGE:
       PrintF("scavenge");
@@ -40,6 +46,25 @@
 }
 
 
+void GCIdleTimeHandler::HeapState::Print() {
+  PrintF("contexts_disposed=%d ", contexts_disposed);
+  PrintF("contexts_disposal_rate=%f ", contexts_disposal_rate);
+  PrintF("size_of_objects=%" V8_PTR_PREFIX "d ", size_of_objects);
+  PrintF("incremental_marking_stopped=%d ", incremental_marking_stopped);
+  PrintF("can_start_incremental_marking=%d ", can_start_incremental_marking);
+  PrintF("sweeping_in_progress=%d ", sweeping_in_progress);
+  PrintF("mark_compact_speed=%" V8_PTR_PREFIX "d ",
+         mark_compact_speed_in_bytes_per_ms);
+  PrintF("incremental_marking_speed=%" V8_PTR_PREFIX "d ",
+         incremental_marking_speed_in_bytes_per_ms);
+  PrintF("scavenge_speed=%" V8_PTR_PREFIX "d ", scavenge_speed_in_bytes_per_ms);
+  PrintF("new_space_size=%" V8_PTR_PREFIX "d ", used_new_space_size);
+  PrintF("new_space_capacity=%" V8_PTR_PREFIX "d ", new_space_capacity);
+  PrintF("new_space_allocation_throughput=%" V8_PTR_PREFIX "d",
+         new_space_allocation_throughput_in_bytes_per_ms);
+}
+
+
 size_t GCIdleTimeHandler::EstimateMarkingStepSize(
     size_t idle_time_in_ms, size_t marking_speed_in_bytes_per_ms) {
   DCHECK(idle_time_in_ms > 0);
@@ -63,6 +88,8 @@
 
 size_t GCIdleTimeHandler::EstimateMarkCompactTime(
     size_t size_of_objects, size_t mark_compact_speed_in_bytes_per_ms) {
+  // TODO(hpayer): Be more precise about the type of mark-compact event. It
+  // makes a huge difference if compaction is happening.
   if (mark_compact_speed_in_bytes_per_ms == 0) {
     mark_compact_speed_in_bytes_per_ms = kInitialConservativeMarkCompactSpeed;
   }
@@ -71,73 +98,137 @@
 }
 
 
-size_t GCIdleTimeHandler::EstimateScavengeTime(
-    size_t new_space_size, size_t scavenge_speed_in_bytes_per_ms) {
-  if (scavenge_speed_in_bytes_per_ms == 0) {
-    scavenge_speed_in_bytes_per_ms = kInitialConservativeScavengeSpeed;
+size_t GCIdleTimeHandler::EstimateFinalIncrementalMarkCompactTime(
+    size_t size_of_objects,
+    size_t final_incremental_mark_compact_speed_in_bytes_per_ms) {
+  if (final_incremental_mark_compact_speed_in_bytes_per_ms == 0) {
+    final_incremental_mark_compact_speed_in_bytes_per_ms =
+        kInitialConservativeFinalIncrementalMarkCompactSpeed;
   }
-  return new_space_size / scavenge_speed_in_bytes_per_ms;
+  size_t result =
+      size_of_objects / final_incremental_mark_compact_speed_in_bytes_per_ms;
+  return Min(result, kMaxFinalIncrementalMarkCompactTimeInMs);
 }
 
 
-bool GCIdleTimeHandler::ScavangeMayHappenSoon(
-    size_t available_new_space_memory,
+bool GCIdleTimeHandler::ShouldDoScavenge(
+    size_t idle_time_in_ms, size_t new_space_size, size_t used_new_space_size,
+    size_t scavenge_speed_in_bytes_per_ms,
     size_t new_space_allocation_throughput_in_bytes_per_ms) {
-  if (available_new_space_memory <=
-      new_space_allocation_throughput_in_bytes_per_ms *
-          kMaxFrameRenderingIdleTime) {
-    return true;
+  size_t new_space_allocation_limit =
+      kMaxFrameRenderingIdleTime * scavenge_speed_in_bytes_per_ms;
+
+  // If the limit is larger than the new space size, then scavenging used to be
+  // really fast. We can take advantage of the whole new space.
+  if (new_space_allocation_limit > new_space_size) {
+    new_space_allocation_limit = new_space_size;
+  }
+
+  // We do not know the allocation throughput before the first Scavenge.
+  // TODO(hpayer): Estimate allocation throughput before the first Scavenge.
+  if (new_space_allocation_throughput_in_bytes_per_ms == 0) {
+    new_space_allocation_limit =
+        static_cast<size_t>(new_space_size * kConservativeTimeRatio);
+  } else {
+    // We have to trigger scavenge before we reach the end of new space.
+    new_space_allocation_limit -=
+        new_space_allocation_throughput_in_bytes_per_ms *
+        kMaxFrameRenderingIdleTime;
+  }
+
+  if (scavenge_speed_in_bytes_per_ms == 0) {
+    scavenge_speed_in_bytes_per_ms = kInitialConservativeScavengeSpeed;
+  }
+
+  if (new_space_allocation_limit <= used_new_space_size) {
+    if (used_new_space_size / scavenge_speed_in_bytes_per_ms <=
+        idle_time_in_ms) {
+      return true;
+    }
   }
   return false;
 }
 
 
+bool GCIdleTimeHandler::ShouldDoMarkCompact(
+    size_t idle_time_in_ms, size_t size_of_objects,
+    size_t mark_compact_speed_in_bytes_per_ms) {
+  return idle_time_in_ms >=
+         EstimateMarkCompactTime(size_of_objects,
+                                 mark_compact_speed_in_bytes_per_ms);
+}
+
+
+bool GCIdleTimeHandler::ShouldDoContextDisposalMarkCompact(
+    int contexts_disposed, double contexts_disposal_rate) {
+  return contexts_disposed > 0 && contexts_disposal_rate > 0 &&
+         contexts_disposal_rate < kHighContextDisposalRate;
+}
+
+
+bool GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact(
+    size_t idle_time_in_ms, size_t size_of_objects,
+    size_t final_incremental_mark_compact_speed_in_bytes_per_ms) {
+  return idle_time_in_ms >=
+         EstimateFinalIncrementalMarkCompactTime(
+             size_of_objects,
+             final_incremental_mark_compact_speed_in_bytes_per_ms);
+}
+
+
 // The following logic is implemented by the controller:
-// (1) If the new space is almost full and we can effort a Scavenge, then a
-// Scavenge is performed.
-// (2) If there is currently no MarkCompact idle round going on, we start a
-// new idle round if enough garbage was created or we received a context
-// disposal event. Otherwise we do not perform garbage collection to keep
-// system utilization low.
-// (3) If incremental marking is done, we perform a full garbage collection
-// if context was disposed or if we are allowed to still do full garbage
-// collections during this idle round or if we are not allowed to start
-// incremental marking. Otherwise we do not perform garbage collection to
-// keep system utilization low.
-// (4) If sweeping is in progress and we received a large enough idle time
+// (1) If we don't have any idle time, do nothing, unless a context was
+// disposed, incremental marking is stopped, and the heap is small. Then do
+// a full GC.
+// (2) If the new space is almost full and we can affort a Scavenge or if the
+// next Scavenge will very likely take long, then a Scavenge is performed.
+// (3) If there is currently no MarkCompact idle round going on, we start a
+// new idle round if enough garbage was created. Otherwise we do not perform
+// garbage collection to keep system utilization low.
+// (4) If incremental marking is done, we perform a full garbage collection
+// if  we are allowed to still do full garbage collections during this idle
+// round or if we are not allowed to start incremental marking. Otherwise we
+// do not perform garbage collection to keep system utilization low.
+// (5) If sweeping is in progress and we received a large enough idle time
 // request, we finalize sweeping here.
-// (5) If incremental marking is in progress, we perform a marking step. Note,
+// (6) If incremental marking is in progress, we perform a marking step. Note,
 // that this currently may trigger a full garbage collection.
-GCIdleTimeAction GCIdleTimeHandler::Compute(size_t idle_time_in_ms,
+GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms,
                                             HeapState heap_state) {
-  if (idle_time_in_ms <= kMaxFrameRenderingIdleTime &&
-      ScavangeMayHappenSoon(
-          heap_state.available_new_space_memory,
-          heap_state.new_space_allocation_throughput_in_bytes_per_ms) &&
-      idle_time_in_ms >=
-          EstimateScavengeTime(heap_state.new_space_capacity,
-                               heap_state.scavenge_speed_in_bytes_per_ms)) {
+  if (static_cast<int>(idle_time_in_ms) <= 0) {
+    if (heap_state.contexts_disposed > 0) {
+      StartIdleRound();
+    }
+    if (heap_state.incremental_marking_stopped) {
+      if (ShouldDoContextDisposalMarkCompact(
+              heap_state.contexts_disposed,
+              heap_state.contexts_disposal_rate)) {
+        return GCIdleTimeAction::FullGC();
+      }
+    }
+    return GCIdleTimeAction::Nothing();
+  }
+
+  if (ShouldDoScavenge(
+          static_cast<size_t>(idle_time_in_ms), heap_state.new_space_capacity,
+          heap_state.used_new_space_size,
+          heap_state.scavenge_speed_in_bytes_per_ms,
+          heap_state.new_space_allocation_throughput_in_bytes_per_ms)) {
     return GCIdleTimeAction::Scavenge();
   }
+
   if (IsMarkCompactIdleRoundFinished()) {
-    if (EnoughGarbageSinceLastIdleRound() || heap_state.contexts_disposed > 0) {
+    if (EnoughGarbageSinceLastIdleRound()) {
       StartIdleRound();
     } else {
       return GCIdleTimeAction::Done();
     }
   }
 
-  if (idle_time_in_ms == 0) {
-    return GCIdleTimeAction::Nothing();
-  }
-
   if (heap_state.incremental_marking_stopped) {
-    size_t estimated_time_in_ms =
-        EstimateMarkCompactTime(heap_state.size_of_objects,
-                                heap_state.mark_compact_speed_in_bytes_per_ms);
-    if (idle_time_in_ms >= estimated_time_in_ms ||
-        (heap_state.size_of_objects < kSmallHeapSize &&
-         heap_state.contexts_disposed > 0)) {
+    if (ShouldDoMarkCompact(static_cast<size_t>(idle_time_in_ms),
+                            heap_state.size_of_objects,
+                            heap_state.mark_compact_speed_in_bytes_per_ms)) {
       // If there are no more than two GCs left in this idle round and we are
       // allowed to do a full GC, then make those GCs full in order to compact
       // the code space.
@@ -145,10 +236,9 @@
       // can get rid of this special case and always start incremental marking.
       int remaining_mark_sweeps =
           kMaxMarkCompactsInIdleRound - mark_compacts_since_idle_round_started_;
-      if (heap_state.contexts_disposed > 0 ||
-          (idle_time_in_ms > kMaxFrameRenderingIdleTime &&
-           (remaining_mark_sweeps <= 2 ||
-            !heap_state.can_start_incremental_marking))) {
+      if (static_cast<size_t>(idle_time_in_ms) > kMaxFrameRenderingIdleTime &&
+          (remaining_mark_sweeps <= 2 ||
+           !heap_state.can_start_incremental_marking)) {
         return GCIdleTimeAction::FullGC();
       }
     }
@@ -158,7 +248,7 @@
   }
   // TODO(hpayer): Estimate finalize sweeping time.
   if (heap_state.sweeping_in_progress &&
-      idle_time_in_ms >= kMinTimeForFinalizeSweeping) {
+      static_cast<size_t>(idle_time_in_ms) >= kMinTimeForFinalizeSweeping) {
     return GCIdleTimeAction::FinalizeSweeping();
   }
 
@@ -167,7 +257,8 @@
     return GCIdleTimeAction::Nothing();
   }
   size_t step_size = EstimateMarkingStepSize(
-      idle_time_in_ms, heap_state.incremental_marking_speed_in_bytes_per_ms);
+      static_cast<size_t>(kIncrementalMarkingStepTimeInMs),
+      heap_state.incremental_marking_speed_in_bytes_per_ms);
   return GCIdleTimeAction::IncrementalMarking(step_size);
 }
 }
diff --git a/src/heap/gc-idle-time-handler.h b/src/heap/gc-idle-time-handler.h
index daab616..4dd190b 100644
--- a/src/heap/gc-idle-time-handler.h
+++ b/src/heap/gc-idle-time-handler.h
@@ -26,6 +26,7 @@
     GCIdleTimeAction result;
     result.type = DONE;
     result.parameter = 0;
+    result.additional_work = false;
     return result;
   }
 
@@ -33,6 +34,7 @@
     GCIdleTimeAction result;
     result.type = DO_NOTHING;
     result.parameter = 0;
+    result.additional_work = false;
     return result;
   }
 
@@ -40,6 +42,7 @@
     GCIdleTimeAction result;
     result.type = DO_INCREMENTAL_MARKING;
     result.parameter = step_size;
+    result.additional_work = false;
     return result;
   }
 
@@ -47,6 +50,7 @@
     GCIdleTimeAction result;
     result.type = DO_SCAVENGE;
     result.parameter = 0;
+    result.additional_work = false;
     return result;
   }
 
@@ -54,6 +58,7 @@
     GCIdleTimeAction result;
     result.type = DO_FULL_GC;
     result.parameter = 0;
+    result.additional_work = false;
     return result;
   }
 
@@ -61,6 +66,7 @@
     GCIdleTimeAction result;
     result.type = DO_FINALIZE_SWEEPING;
     result.parameter = 0;
+    result.additional_work = false;
     return result;
   }
 
@@ -68,6 +74,7 @@
 
   GCIdleTimeActionType type;
   intptr_t parameter;
+  bool additional_work;
 };
 
 
@@ -92,9 +99,18 @@
   // conservative lower bound for the mark-compact speed.
   static const size_t kInitialConservativeMarkCompactSpeed = 2 * MB;
 
+  // If we haven't recorded any final incremental mark-compact events yet, we
+  // use conservative lower bound for the mark-compact speed.
+  static const size_t kInitialConservativeFinalIncrementalMarkCompactSpeed =
+      2 * MB;
+
   // Maximum mark-compact time returned by EstimateMarkCompactTime.
   static const size_t kMaxMarkCompactTimeInMs;
 
+  // Maximum final incremental mark-compact time returned by
+  // EstimateFinalIncrementalMarkCompactTime.
+  static const size_t kMaxFinalIncrementalMarkCompactTimeInMs;
+
   // Minimum time to finalize sweeping phase. The main thread may wait for
   // sweeper threads.
   static const size_t kMinTimeForFinalizeSweeping;
@@ -106,31 +122,34 @@
   // Number of scavenges that will trigger start of new idle round.
   static const int kIdleScavengeThreshold;
 
-  // Heap size threshold below which we prefer mark-compact over incremental
-  // step.
-  static const size_t kSmallHeapSize = 4 * kPointerSize * MB;
-
   // That is the maximum idle time we will have during frame rendering.
   static const size_t kMaxFrameRenderingIdleTime = 16;
 
-  // If less than that much memory is left in the new space, we consider it
-  // as almost full and force a new space collection earlier in the idle time.
-  static const size_t kNewSpaceAlmostFullTreshold = 100 * KB;
-
   // If we haven't recorded any scavenger events yet, we use a conservative
   // lower bound for the scavenger speed.
   static const size_t kInitialConservativeScavengeSpeed = 100 * KB;
 
-  struct HeapState {
+  // If contexts are disposed at a higher rate a full gc is triggered.
+  static const double kHighContextDisposalRate;
+
+  // Incremental marking step time.
+  static const size_t kIncrementalMarkingStepTimeInMs = 1;
+
+  class HeapState {
+   public:
+    void Print();
+
     int contexts_disposed;
+    double contexts_disposal_rate;
     size_t size_of_objects;
     bool incremental_marking_stopped;
     bool can_start_incremental_marking;
     bool sweeping_in_progress;
     size_t mark_compact_speed_in_bytes_per_ms;
     size_t incremental_marking_speed_in_bytes_per_ms;
+    size_t final_incremental_mark_compact_speed_in_bytes_per_ms;
     size_t scavenge_speed_in_bytes_per_ms;
-    size_t available_new_space_memory;
+    size_t used_new_space_size;
     size_t new_space_capacity;
     size_t new_space_allocation_throughput_in_bytes_per_ms;
   };
@@ -139,7 +158,7 @@
       : mark_compacts_since_idle_round_started_(0),
         scavenges_since_last_idle_round_(0) {}
 
-  GCIdleTimeAction Compute(size_t idle_time_in_ms, HeapState heap_state);
+  GCIdleTimeAction Compute(double idle_time_in_ms, HeapState heap_state);
 
   void NotifyIdleMarkCompact() {
     if (mark_compacts_since_idle_round_started_ < kMaxMarkCompactsInIdleRound) {
@@ -159,11 +178,23 @@
   static size_t EstimateMarkCompactTime(
       size_t size_of_objects, size_t mark_compact_speed_in_bytes_per_ms);
 
-  static size_t EstimateScavengeTime(size_t new_space_size,
-                                     size_t scavenger_speed_in_bytes_per_ms);
+  static size_t EstimateFinalIncrementalMarkCompactTime(
+      size_t size_of_objects, size_t mark_compact_speed_in_bytes_per_ms);
 
-  static bool ScavangeMayHappenSoon(
-      size_t available_new_space_memory,
+  static bool ShouldDoMarkCompact(size_t idle_time_in_ms,
+                                  size_t size_of_objects,
+                                  size_t mark_compact_speed_in_bytes_per_ms);
+
+  static bool ShouldDoContextDisposalMarkCompact(int context_disposed,
+                                                 double contexts_disposal_rate);
+
+  static bool ShouldDoFinalIncrementalMarkCompact(
+      size_t idle_time_in_ms, size_t size_of_objects,
+      size_t final_incremental_mark_compact_speed_in_bytes_per_ms);
+
+  static bool ShouldDoScavenge(
+      size_t idle_time_in_ms, size_t new_space_size, size_t used_new_space_size,
+      size_t scavenger_speed_in_bytes_per_ms,
       size_t new_space_allocation_throughput_in_bytes_per_ms);
 
  private:
diff --git a/src/heap/gc-tracer.cc b/src/heap/gc-tracer.cc
index 8a40b53..a35872d 100644
--- a/src/heap/gc-tracer.cc
+++ b/src/heap/gc-tracer.cc
@@ -26,6 +26,16 @@
 }
 
 
+GCTracer::ContextDisposalEvent::ContextDisposalEvent(double time) {
+  time_ = time;
+}
+
+
+GCTracer::SurvivalEvent::SurvivalEvent(double survival_rate) {
+  survival_rate_ = survival_rate;
+}
+
+
 GCTracer::Event::Event(Type type, const char* gc_reason,
                        const char* collector_reason)
     : type(type),
@@ -63,6 +73,7 @@
         return "Scavenge";
       }
     case MARK_COMPACTOR:
+    case INCREMENTAL_MARK_COMPACTOR:
       if (short_name) {
         return "ms";
       } else {
@@ -88,15 +99,19 @@
       longest_incremental_marking_step_(0.0),
       cumulative_marking_duration_(0.0),
       cumulative_sweeping_duration_(0.0),
-      new_space_top_after_gc_(0) {
+      new_space_top_after_gc_(0),
+      start_counter_(0) {
   current_ = Event(Event::START, NULL, NULL);
   current_.end_time = base::OS::TimeCurrentMillis();
-  previous_ = previous_mark_compactor_event_ = current_;
+  previous_ = previous_incremental_mark_compactor_event_ = current_;
 }
 
 
 void GCTracer::Start(GarbageCollector collector, const char* gc_reason,
                      const char* collector_reason) {
+  start_counter_++;
+  if (start_counter_ != 1) return;
+
   previous_ = current_;
   double start_time = base::OS::TimeCurrentMillis();
   if (new_space_top_after_gc_ != 0) {
@@ -105,13 +120,18 @@
         reinterpret_cast<intptr_t>((heap_->new_space()->top()) -
                                    new_space_top_after_gc_));
   }
-  if (current_.type == Event::MARK_COMPACTOR)
-    previous_mark_compactor_event_ = current_;
+  if (current_.type == Event::INCREMENTAL_MARK_COMPACTOR)
+    previous_incremental_mark_compactor_event_ = current_;
 
   if (collector == SCAVENGER) {
     current_ = Event(Event::SCAVENGER, gc_reason, collector_reason);
-  } else {
-    current_ = Event(Event::MARK_COMPACTOR, gc_reason, collector_reason);
+  } else if (collector == MARK_COMPACTOR) {
+    if (heap_->incremental_marking()->WasActivated()) {
+      current_ =
+          Event(Event::INCREMENTAL_MARK_COMPACTOR, gc_reason, collector_reason);
+    } else {
+      current_ = Event(Event::MARK_COMPACTOR, gc_reason, collector_reason);
+    }
   }
 
   current_.start_time = start_time;
@@ -137,7 +157,23 @@
 }
 
 
-void GCTracer::Stop() {
+void GCTracer::Stop(GarbageCollector collector) {
+  start_counter_--;
+  if (start_counter_ != 0) {
+    if (FLAG_trace_gc) {
+      PrintF("[Finished reentrant %s during %s.]\n",
+             collector == SCAVENGER ? "Scavenge" : "Mark-sweep",
+             current_.TypeName(false));
+    }
+    return;
+  }
+
+  DCHECK(start_counter_ >= 0);
+  DCHECK((collector == SCAVENGER && current_.type == Event::SCAVENGER) ||
+         (collector == MARK_COMPACTOR &&
+          (current_.type == Event::MARK_COMPACTOR ||
+           current_.type == Event::INCREMENTAL_MARK_COMPACTOR)));
+
   current_.end_time = base::OS::TimeCurrentMillis();
   current_.end_object_size = heap_->SizeOfObjects();
   current_.end_memory_size = heap_->isolate()->memory_allocator()->Size();
@@ -159,21 +195,30 @@
         current_.cumulative_pure_incremental_marking_duration -
         previous_.cumulative_pure_incremental_marking_duration;
     scavenger_events_.push_front(current_);
-  } else {
+  } else if (current_.type == Event::INCREMENTAL_MARK_COMPACTOR) {
     current_.incremental_marking_steps =
         current_.cumulative_incremental_marking_steps -
-        previous_mark_compactor_event_.cumulative_incremental_marking_steps;
+        previous_incremental_mark_compactor_event_
+            .cumulative_incremental_marking_steps;
     current_.incremental_marking_bytes =
         current_.cumulative_incremental_marking_bytes -
-        previous_mark_compactor_event_.cumulative_incremental_marking_bytes;
+        previous_incremental_mark_compactor_event_
+            .cumulative_incremental_marking_bytes;
     current_.incremental_marking_duration =
         current_.cumulative_incremental_marking_duration -
-        previous_mark_compactor_event_.cumulative_incremental_marking_duration;
+        previous_incremental_mark_compactor_event_
+            .cumulative_incremental_marking_duration;
     current_.pure_incremental_marking_duration =
         current_.cumulative_pure_incremental_marking_duration -
-        previous_mark_compactor_event_
+        previous_incremental_mark_compactor_event_
             .cumulative_pure_incremental_marking_duration;
     longest_incremental_marking_step_ = 0.0;
+    incremental_mark_compactor_events_.push_front(current_);
+  } else {
+    DCHECK(current_.incremental_marking_bytes == 0);
+    DCHECK(current_.incremental_marking_duration == 0);
+    DCHECK(current_.pure_incremental_marking_duration == 0);
+    DCHECK(longest_incremental_marking_step_ == 0.0);
     mark_compactor_events_.push_front(current_);
   }
 
@@ -207,6 +252,16 @@
 }
 
 
+void GCTracer::AddContextDisposalTime(double time) {
+  context_disposal_events_.push_front(ContextDisposalEvent(time));
+}
+
+
+void GCTracer::AddSurvivalRate(double survival_rate) {
+  survival_events_.push_front(SurvivalEvent(survival_rate));
+}
+
+
 void GCTracer::AddIncrementalMarkingStep(double duration, intptr_t bytes) {
   cumulative_incremental_marking_steps_++;
   cumulative_incremental_marking_bytes_ += bytes;
@@ -294,6 +349,7 @@
          current_.scopes[Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED]);
   PrintF("misc_compaction=%.1f ",
          current_.scopes[Scope::MC_UPDATE_MISC_POINTERS]);
+  PrintF("weak_closure=%.1f ", current_.scopes[Scope::MC_WEAKCLOSURE]);
   PrintF("weakcollection_process=%.1f ",
          current_.scopes[Scope::MC_WEAKCOLLECTION_PROCESS]);
   PrintF("weakcollection_clear=%.1f ",
@@ -315,10 +371,13 @@
   PrintF("nodes_died_in_new=%d ", heap_->nodes_died_in_new_space_);
   PrintF("nodes_copied_in_new=%d ", heap_->nodes_copied_in_new_space_);
   PrintF("nodes_promoted=%d ", heap_->nodes_promoted_);
+  PrintF("promotion_ratio=%.1f%% ", heap_->promotion_ratio_);
   PrintF("promotion_rate=%.1f%% ", heap_->promotion_rate_);
   PrintF("semi_space_copy_rate=%.1f%% ", heap_->semi_space_copied_rate_);
+  PrintF("average_survival_rate%.1f%% ", AverageSurvivalRate());
   PrintF("new_space_allocation_throughput=%" V8_PTR_PREFIX "d ",
          NewSpaceAllocationThroughputInBytesPerMillisecond());
+  PrintF("context_disposal_rate=%.1f ", ContextDisposalRateInMilliseconds());
 
   if (current_.type == Event::SCAVENGER) {
     PrintF("steps_count=%d ", current_.incremental_marking_steps);
@@ -370,15 +429,15 @@
 
   // We haven't completed an entire round of incremental marking, yet.
   // Use data from GCTracer instead of data from event buffers.
-  if (mark_compactor_events_.empty()) {
+  if (incremental_mark_compactor_events_.empty()) {
     return cumulative_incremental_marking_duration_ /
            cumulative_incremental_marking_steps_;
   }
 
   int steps = 0;
   double durations = 0.0;
-  EventBuffer::const_iterator iter = mark_compactor_events_.begin();
-  while (iter != mark_compactor_events_.end()) {
+  EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin();
+  while (iter != incremental_mark_compactor_events_.end()) {
     steps += iter->incremental_marking_steps;
     durations += iter->incremental_marking_duration;
     ++iter;
@@ -393,11 +452,12 @@
 double GCTracer::MaxIncrementalMarkingDuration() const {
   // We haven't completed an entire round of incremental marking, yet.
   // Use data from GCTracer instead of data from event buffers.
-  if (mark_compactor_events_.empty()) return longest_incremental_marking_step_;
+  if (incremental_mark_compactor_events_.empty())
+    return longest_incremental_marking_step_;
 
   double max_duration = 0.0;
-  EventBuffer::const_iterator iter = mark_compactor_events_.begin();
-  while (iter != mark_compactor_events_.end())
+  EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin();
+  while (iter != incremental_mark_compactor_events_.end())
     max_duration = Max(iter->longest_incremental_marking_step, max_duration);
 
   return max_duration;
@@ -409,15 +469,15 @@
 
   // We haven't completed an entire round of incremental marking, yet.
   // Use data from GCTracer instead of data from event buffers.
-  if (mark_compactor_events_.empty()) {
+  if (incremental_mark_compactor_events_.empty()) {
     return static_cast<intptr_t>(cumulative_incremental_marking_bytes_ /
                                  cumulative_pure_incremental_marking_duration_);
   }
 
   intptr_t bytes = 0;
   double durations = 0.0;
-  EventBuffer::const_iterator iter = mark_compactor_events_.begin();
-  while (iter != mark_compactor_events_.end()) {
+  EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin();
+  while (iter != incremental_mark_compactor_events_.end()) {
     bytes += iter->incremental_marking_bytes;
     durations += iter->pure_incremental_marking_duration;
     ++iter;
@@ -451,8 +511,24 @@
   EventBuffer::const_iterator iter = mark_compactor_events_.begin();
   while (iter != mark_compactor_events_.end()) {
     bytes += iter->start_object_size;
-    durations += iter->end_time - iter->start_time +
-                 iter->pure_incremental_marking_duration;
+    durations += iter->end_time - iter->start_time;
+    ++iter;
+  }
+
+  if (durations == 0.0) return 0;
+
+  return static_cast<intptr_t>(bytes / durations);
+}
+
+
+intptr_t GCTracer::FinalIncrementalMarkCompactSpeedInBytesPerMillisecond()
+    const {
+  intptr_t bytes = 0;
+  double durations = 0.0;
+  EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin();
+  while (iter != incremental_mark_compactor_events_.end()) {
+    bytes += iter->start_object_size;
+    durations += iter->end_time - iter->start_time;
     ++iter;
   }
 
@@ -476,5 +552,43 @@
 
   return static_cast<intptr_t>(bytes / durations);
 }
+
+
+double GCTracer::ContextDisposalRateInMilliseconds() const {
+  if (context_disposal_events_.size() < kRingBufferMaxSize) return 0.0;
+
+  double begin = base::OS::TimeCurrentMillis();
+  double end = 0.0;
+  ContextDisposalEventBuffer::const_iterator iter =
+      context_disposal_events_.begin();
+  while (iter != context_disposal_events_.end()) {
+    end = iter->time_;
+    ++iter;
+  }
+
+  return (begin - end) / context_disposal_events_.size();
+}
+
+
+double GCTracer::AverageSurvivalRate() const {
+  if (survival_events_.size() == 0) return 0.0;
+
+  double sum_of_rates = 0.0;
+  SurvivalEventBuffer::const_iterator iter = survival_events_.begin();
+  while (iter != survival_events_.end()) {
+    sum_of_rates += iter->survival_rate_;
+    ++iter;
+  }
+
+  return sum_of_rates / static_cast<double>(survival_events_.size());
+}
+
+
+bool GCTracer::SurvivalEventsRecorded() const {
+  return survival_events_.size() > 0;
+}
+
+
+void GCTracer::ResetSurvivalEvents() { survival_events_.reset(); }
 }
 }  // namespace v8::internal
diff --git a/src/heap/gc-tracer.h b/src/heap/gc-tracer.h
index 4e70f07..528eb52 100644
--- a/src/heap/gc-tracer.h
+++ b/src/heap/gc-tracer.h
@@ -71,6 +71,11 @@
     elements_[begin_] = element;
   }
 
+  void reset() {
+    begin_ = 0;
+    end_ = 0;
+  }
+
  private:
   T elements_[MAX_SIZE + 1];
   size_t begin_;
@@ -103,6 +108,7 @@
       MC_UPDATE_POINTERS_TO_EVACUATED,
       MC_UPDATE_POINTERS_BETWEEN_EVACUATED,
       MC_UPDATE_MISC_POINTERS,
+      MC_WEAKCLOSURE,
       MC_WEAKCOLLECTION_PROCESS,
       MC_WEAKCOLLECTION_CLEAR,
       MC_WEAKCOLLECTION_ABORT,
@@ -145,9 +151,38 @@
     intptr_t allocation_in_bytes_;
   };
 
+
+  class ContextDisposalEvent {
+   public:
+    // Default constructor leaves the event uninitialized.
+    ContextDisposalEvent() {}
+
+    explicit ContextDisposalEvent(double time);
+
+    // Time when context disposal event happened.
+    double time_;
+  };
+
+
+  class SurvivalEvent {
+   public:
+    // Default constructor leaves the event uninitialized.
+    SurvivalEvent() {}
+
+    explicit SurvivalEvent(double survival_rate);
+
+    double survival_rate_;
+  };
+
+
   class Event {
    public:
-    enum Type { SCAVENGER = 0, MARK_COMPACTOR = 1, START = 2 };
+    enum Type {
+      SCAVENGER = 0,
+      MARK_COMPACTOR = 1,
+      INCREMENTAL_MARK_COMPACTOR = 2,
+      START = 3
+    };
 
     // Default constructor leaves the event uninitialized.
     Event() {}
@@ -198,7 +233,8 @@
 
     // Incremental marking steps since
     // - last event for SCAVENGER events
-    // - last MARK_COMPACTOR event for MARK_COMPACTOR events
+    // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
+    // events
     int incremental_marking_steps;
 
     // Bytes marked since creation of tracer (value at start of event).
@@ -206,7 +242,8 @@
 
     // Bytes marked since
     // - last event for SCAVENGER events
-    // - last MARK_COMPACTOR event for MARK_COMPACTOR events
+    // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
+    // events
     intptr_t incremental_marking_bytes;
 
     // Cumulative duration of incremental marking steps since creation of
@@ -215,7 +252,8 @@
 
     // Duration of incremental marking steps since
     // - last event for SCAVENGER events
-    // - last MARK_COMPACTOR event for MARK_COMPACTOR events
+    // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
+    // events
     double incremental_marking_duration;
 
     // Cumulative pure duration of incremental marking steps since creation of
@@ -224,7 +262,8 @@
 
     // Duration of pure incremental marking steps since
     // - last event for SCAVENGER events
-    // - last MARK_COMPACTOR event for MARK_COMPACTOR events
+    // - last INCREMENTAL_MARK_COMPACTOR event for INCREMENTAL_MARK_COMPACTOR
+    // events
     double pure_incremental_marking_duration;
 
     // Longest incremental marking step since start of marking.
@@ -235,12 +274,17 @@
     double scopes[Scope::NUMBER_OF_SCOPES];
   };
 
-  static const int kRingBufferMaxSize = 10;
+  static const size_t kRingBufferMaxSize = 10;
 
   typedef RingBuffer<Event, kRingBufferMaxSize> EventBuffer;
 
   typedef RingBuffer<AllocationEvent, kRingBufferMaxSize> AllocationEventBuffer;
 
+  typedef RingBuffer<ContextDisposalEvent, kRingBufferMaxSize>
+      ContextDisposalEventBuffer;
+
+  typedef RingBuffer<SurvivalEvent, kRingBufferMaxSize> SurvivalEventBuffer;
+
   explicit GCTracer(Heap* heap);
 
   // Start collecting data.
@@ -248,11 +292,15 @@
              const char* collector_reason);
 
   // Stop collecting data and print results.
-  void Stop();
+  void Stop(GarbageCollector collector);
 
   // Log an allocation throughput event.
   void AddNewSpaceAllocationTime(double duration, intptr_t allocation_in_bytes);
 
+  void AddContextDisposalTime(double time);
+
+  void AddSurvivalRate(double survival_rate);
+
   // Log an incremental marking step.
   void AddIncrementalMarkingStep(double duration, intptr_t bytes);
 
@@ -298,6 +346,12 @@
     return MaxDuration(mark_compactor_events_);
   }
 
+  // Compute the mean duration of the last incremental mark compactor
+  // events. Returns 0 if no events have been recorded.
+  double MeanIncrementalMarkCompactorDuration() const {
+    return MeanDuration(incremental_mark_compactor_events_);
+  }
+
   // Compute the mean step duration of the last incremental marking round.
   // Returns 0 if no incremental marking round has been completed.
   double MeanIncrementalMarkingDuration() const;
@@ -314,14 +368,36 @@
   // Returns 0 if no events have been recorded.
   intptr_t ScavengeSpeedInBytesPerMillisecond() const;
 
-  // Compute the max mark-sweep speed in bytes/millisecond.
+  // Compute the average mark-sweep speed in bytes/millisecond.
   // Returns 0 if no events have been recorded.
   intptr_t MarkCompactSpeedInBytesPerMillisecond() const;
 
+  // Compute the average incremental mark-sweep finalize speed in
+  // bytes/millisecond.
+  // Returns 0 if no events have been recorded.
+  intptr_t FinalIncrementalMarkCompactSpeedInBytesPerMillisecond() const;
+
   // Allocation throughput in the new space in bytes/millisecond.
   // Returns 0 if no events have been recorded.
   intptr_t NewSpaceAllocationThroughputInBytesPerMillisecond() const;
 
+  // Computes the context disposal rate in milliseconds. It takes the time
+  // frame of the first recorded context disposal to the current time and
+  // divides it by the number of recorded events.
+  // Returns 0 if no events have been recorded.
+  double ContextDisposalRateInMilliseconds() const;
+
+  // Computes the average survival rate based on the last recorded survival
+  // events.
+  // Returns 0 if no events have been recorded.
+  double AverageSurvivalRate() const;
+
+  // Returns true if at least one survival event was recorded.
+  bool SurvivalEventsRecorded() const;
+
+  // Discard all recorded survival events.
+  void ResetSurvivalEvents();
+
  private:
   // Print one detailed trace line in name=value format.
   // TODO(ernstm): Move to Heap.
@@ -337,6 +413,16 @@
   // Compute the max duration of the events in the given ring buffer.
   double MaxDuration(const EventBuffer& events) const;
 
+  void ClearMarkCompactStatistics() {
+    cumulative_incremental_marking_steps_ = 0;
+    cumulative_incremental_marking_bytes_ = 0;
+    cumulative_incremental_marking_duration_ = 0;
+    cumulative_pure_incremental_marking_duration_ = 0;
+    longest_incremental_marking_step_ = 0;
+    cumulative_marking_duration_ = 0;
+    cumulative_sweeping_duration_ = 0;
+  }
+
   // Pointer to the heap that owns this tracer.
   Heap* heap_;
 
@@ -347,8 +433,8 @@
   // Previous tracer event.
   Event previous_;
 
-  // Previous MARK_COMPACTOR event.
-  Event previous_mark_compactor_event_;
+  // Previous INCREMENTAL_MARK_COMPACTOR event.
+  Event previous_incremental_mark_compactor_event_;
 
   // RingBuffers for SCAVENGER events.
   EventBuffer scavenger_events_;
@@ -356,9 +442,18 @@
   // RingBuffers for MARK_COMPACTOR events.
   EventBuffer mark_compactor_events_;
 
+  // RingBuffers for INCREMENTAL_MARK_COMPACTOR events.
+  EventBuffer incremental_mark_compactor_events_;
+
   // RingBuffer for allocation events.
   AllocationEventBuffer allocation_events_;
 
+  // RingBuffer for context disposal events.
+  ContextDisposalEventBuffer context_disposal_events_;
+
+  // RingBuffer for survival events.
+  SurvivalEventBuffer survival_events_;
+
   // Cumulative number of incremental marking steps since creation of tracer.
   int cumulative_incremental_marking_steps_;
 
@@ -393,6 +488,9 @@
   // collection.
   intptr_t new_space_top_after_gc_;
 
+  // Counts how many tracers were started without stopping.
+  int start_counter_;
+
   DISALLOW_COPY_AND_ASSIGN(GCTracer);
 };
 }
diff --git a/src/heap/heap-inl.h b/src/heap/heap-inl.h
index e658224..549ecbc 100644
--- a/src/heap/heap-inl.h
+++ b/src/heap/heap-inl.h
@@ -458,8 +458,6 @@
     case PROPERTY_CELL_SPACE:
     case LO_SPACE:
       return false;
-    case INVALID_SPACE:
-      break;
   }
   UNREACHABLE();
   return false;
@@ -589,7 +587,7 @@
 Isolate* Heap::isolate() {
   return reinterpret_cast<Isolate*>(
       reinterpret_cast<intptr_t>(this) -
-      reinterpret_cast<size_t>(reinterpret_cast<Isolate*>(4)->heap()) + 4);
+      reinterpret_cast<size_t>(reinterpret_cast<Isolate*>(16)->heap()) + 16);
 }
 
 
@@ -699,7 +697,7 @@
 
 
 void Heap::ClearInstanceofCache() {
-  set_instanceof_cache_function(the_hole_value());
+  set_instanceof_cache_function(Smi::FromInt(0));
 }
 
 
@@ -709,8 +707,8 @@
 
 
 void Heap::CompletelyClearInstanceofCache() {
-  set_instanceof_cache_map(the_hole_value());
-  set_instanceof_cache_function(the_hole_value());
+  set_instanceof_cache_map(Smi::FromInt(0));
+  set_instanceof_cache_function(Smi::FromInt(0));
 }
 
 
diff --git a/src/heap/heap.cc b/src/heap/heap.cc
index dfe60fe..0b817e4 100644
--- a/src/heap/heap.cc
+++ b/src/heap/heap.cc
@@ -28,6 +28,7 @@
 #include "src/natives.h"
 #include "src/runtime-profiler.h"
 #include "src/scopeinfo.h"
+#include "src/serialize.h"
 #include "src/snapshot.h"
 #include "src/utils.h"
 #include "src/v8threads.h"
@@ -60,7 +61,10 @@
       reserved_semispace_size_(8 * (kPointerSize / 4) * MB),
       max_semi_space_size_(8 * (kPointerSize / 4) * MB),
       initial_semispace_size_(Page::kPageSize),
+      target_semispace_size_(Page::kPageSize),
       max_old_generation_size_(700ul * (kPointerSize / 4) * MB),
+      initial_old_generation_size_(max_old_generation_size_ / 2),
+      old_generation_size_configured_(false),
       max_executable_size_(256ul * (kPointerSize / 4) * MB),
       // Variables set based on semispace_size_ and old_generation_size_ in
       // ConfigureHeap.
@@ -68,6 +72,7 @@
       // generation can be aligned to its size.
       maximum_committed_(0),
       survived_since_last_expansion_(0),
+      survived_last_scavenge_(0),
       sweep_generation_(0),
       always_allocate_scope_depth_(0),
       contexts_disposed_(0),
@@ -94,7 +99,7 @@
 #ifdef DEBUG
       allocation_timeout_(0),
 #endif  // DEBUG
-      old_generation_allocation_limit_(kMinimumOldGenerationAllocationLimit),
+      old_generation_allocation_limit_(initial_old_generation_size_),
       old_gen_exhausted_(false),
       inline_allocation_disabled_(false),
       store_buffer_rebuilder_(store_buffer()),
@@ -104,8 +109,9 @@
       tracer_(this),
       high_survival_rate_period_length_(0),
       promoted_objects_size_(0),
-      promotion_rate_(0),
+      promotion_ratio_(0),
       semi_space_copied_object_size_(0),
+      previous_semi_space_copied_object_size_(0),
       semi_space_copied_rate_(0),
       nodes_died_in_new_space_(0),
       nodes_copied_in_new_space_(0),
@@ -117,6 +123,7 @@
       min_in_mutator_(kMaxInt),
       marking_time_(0.0),
       sweeping_time_(0.0),
+      last_idle_notification_time_(0.0),
       mark_compact_collector_(this),
       store_buffer_(this),
       marking_(this),
@@ -133,7 +140,8 @@
       configured_(false),
       external_string_table_(this),
       chunks_queued_for_free_(NULL),
-      gc_callbacks_depth_(0) {
+      gc_callbacks_depth_(0),
+      deserialization_complete_(false) {
 // Allow build-time customization of the max semispace size. Building
 // V8 with snapshots and a non-default max semispace size is much
 // easier if you can define it as part of the build environment.
@@ -149,6 +157,7 @@
   set_array_buffers_list(Smi::FromInt(0));
   set_allocation_sites_list(Smi::FromInt(0));
   set_encountered_weak_collections(Smi::FromInt(0));
+  set_encountered_weak_cells(Smi::FromInt(0));
   // Put a dummy entry in the remembered pages so we can find the list the
   // minidump even if there are no real unmapped pages.
   RememberUnmappedPage(NULL, false);
@@ -427,6 +436,7 @@
 
   // Reset GC statistics.
   promoted_objects_size_ = 0;
+  previous_semi_space_copied_object_size_ = semi_space_copied_object_size_;
   semi_space_copied_object_size_ = 0;
   nodes_died_in_new_space_ = 0;
   nodes_copied_in_new_space_ = 0;
@@ -763,7 +773,6 @@
   mark_compact_collector()->SetFlags(kNoGCFlags);
   new_space_.Shrink();
   UncommitFromSpace();
-  incremental_marking()->UncommitMarkingDeque();
 }
 
 
@@ -840,7 +849,7 @@
     }
 
     GarbageCollectionEpilogue();
-    tracer()->Stop();
+    tracer()->Stop(collector);
   }
 
   // Start incremental marking for the next cycle. The heap snapshot
@@ -854,13 +863,18 @@
 }
 
 
-int Heap::NotifyContextDisposed() {
+int Heap::NotifyContextDisposed(bool dependant_context) {
+  if (!dependant_context) {
+    tracer()->ResetSurvivalEvents();
+    old_generation_size_configured_ = false;
+  }
   if (isolate()->concurrent_recompilation_enabled()) {
     // Flush the queued recompilation tasks.
     isolate()->optimizing_compiler_thread()->Flush();
   }
   flush_monomorphic_ics_ = true;
   AgeInlineCaches();
+  tracer()->AddContextDisposalTime(base::OS::TimeCurrentMillis());
   return ++contexts_disposed_;
 }
 
@@ -917,47 +931,61 @@
 }
 
 
-void Heap::ReserveSpace(int* sizes, Address* locations_out) {
+bool Heap::ReserveSpace(Reservation* reservations) {
   bool gc_performed = true;
   int counter = 0;
   static const int kThreshold = 20;
   while (gc_performed && counter++ < kThreshold) {
     gc_performed = false;
-    DCHECK(NEW_SPACE == FIRST_PAGED_SPACE - 1);
-    for (int space = NEW_SPACE; space <= LAST_PAGED_SPACE; space++) {
-      if (sizes[space] != 0) {
-        AllocationResult allocation;
-        if (space == NEW_SPACE) {
-          allocation = new_space()->AllocateRaw(sizes[space]);
-        } else {
-          allocation = paged_space(space)->AllocateRaw(sizes[space]);
-        }
-        FreeListNode* node;
-        if (!allocation.To(&node)) {
+    for (int space = NEW_SPACE; space < Serializer::kNumberOfSpaces; space++) {
+      Reservation* reservation = &reservations[space];
+      DCHECK_LE(1, reservation->length());
+      if (reservation->at(0).size == 0) continue;
+      bool perform_gc = false;
+      if (space == LO_SPACE) {
+        DCHECK_EQ(1, reservation->length());
+        perform_gc = !lo_space()->CanAllocateSize(reservation->at(0).size);
+      } else {
+        for (auto& chunk : *reservation) {
+          AllocationResult allocation;
+          int size = chunk.size;
+          DCHECK_LE(size, MemoryAllocator::PageAreaSize(
+                              static_cast<AllocationSpace>(space)));
           if (space == NEW_SPACE) {
-            Heap::CollectGarbage(NEW_SPACE,
-                                 "failed to reserve space in the new space");
+            allocation = new_space()->AllocateRaw(size);
           } else {
-            AbortIncrementalMarkingAndCollectGarbage(
-                this, static_cast<AllocationSpace>(space),
-                "failed to reserve space in paged space");
+            allocation = paged_space(space)->AllocateRaw(size);
           }
-          gc_performed = true;
-          break;
-        } else {
-          // Mark with a free list node, in case we have a GC before
-          // deserializing.
-          node->set_size(this, sizes[space]);
-          locations_out[space] = node->address();
+          FreeListNode* node;
+          if (allocation.To(&node)) {
+            // Mark with a free list node, in case we have a GC before
+            // deserializing.
+            node->set_size(this, size);
+            DCHECK(space < Serializer::kNumberOfPreallocatedSpaces);
+            chunk.start = node->address();
+            chunk.end = node->address() + size;
+          } else {
+            perform_gc = true;
+            break;
+          }
         }
       }
+      if (perform_gc) {
+        if (space == NEW_SPACE) {
+          Heap::CollectGarbage(NEW_SPACE,
+                               "failed to reserve space in the new space");
+        } else {
+          AbortIncrementalMarkingAndCollectGarbage(
+              this, static_cast<AllocationSpace>(space),
+              "failed to reserve space in paged or large object space");
+        }
+        gc_performed = true;
+        break;  // Abort for-loop over spaces and retry.
+      }
     }
   }
 
-  if (gc_performed) {
-    // Failed to reserve the space after several attempts.
-    V8::FatalProcessOutOfMemory("Heap::ReserveSpace");
-  }
+  return !gc_performed;
 }
 
 
@@ -1016,14 +1044,23 @@
 void Heap::UpdateSurvivalStatistics(int start_new_space_size) {
   if (start_new_space_size == 0) return;
 
-  promotion_rate_ = (static_cast<double>(promoted_objects_size_) /
-                     static_cast<double>(start_new_space_size) * 100);
+  promotion_ratio_ = (static_cast<double>(promoted_objects_size_) /
+                      static_cast<double>(start_new_space_size) * 100);
+
+  if (previous_semi_space_copied_object_size_ > 0) {
+    promotion_rate_ =
+        (static_cast<double>(promoted_objects_size_) /
+         static_cast<double>(previous_semi_space_copied_object_size_) * 100);
+  } else {
+    promotion_rate_ = 0;
+  }
 
   semi_space_copied_rate_ =
       (static_cast<double>(semi_space_copied_object_size_) /
        static_cast<double>(start_new_space_size) * 100);
 
-  double survival_rate = promotion_rate_ + semi_space_copied_rate_;
+  double survival_rate = promotion_ratio_ + semi_space_copied_rate_;
+  tracer()->AddSurvivalRate(survival_rate);
 
   if (survival_rate > kYoungSurvivalRateHighThreshold) {
     high_survival_rate_period_length_++;
@@ -1081,11 +1118,13 @@
     old_generation_allocation_limit_ =
         OldGenerationAllocationLimit(PromotedSpaceSizeOfObjects(), 0);
     old_gen_exhausted_ = false;
+    old_generation_size_configured_ = true;
   } else {
     Scavenge();
   }
 
   UpdateSurvivalStatistics(start_new_space_size);
+  ConfigureInitialOldGenerationSize();
 
   isolate_->counters()->objs_since_last_young()->Set(0);
 
@@ -1113,6 +1152,9 @@
         amount_of_external_allocated_memory_;
     old_generation_allocation_limit_ = OldGenerationAllocationLimit(
         PromotedSpaceSizeOfObjects(), freed_global_handles);
+    // We finished a marking cycle. We can uncommit the marking deque until
+    // we start marking again.
+    mark_compact_collector_.UncommitMarkingDeque();
   }
 
   {
@@ -1187,15 +1229,22 @@
 
   LOG(isolate_, ResourceEvent("markcompact", "end"));
 
+  MarkCompactEpilogue();
+
+  if (FLAG_allocation_site_pretenuring) {
+    EvaluateOldSpaceLocalPretenuring(size_of_objects_before_gc);
+  }
+}
+
+
+void Heap::MarkCompactEpilogue() {
   gc_state_ = NOT_IN_GC;
 
   isolate_->counters()->objs_since_last_full()->Set(0);
 
   flush_monomorphic_ics_ = false;
 
-  if (FLAG_allocation_site_pretenuring) {
-    EvaluateOldSpaceLocalPretenuring(size_of_objects_before_gc);
-  }
+  incremental_marking()->Epilogue();
 }
 
 
@@ -1282,11 +1331,18 @@
 
 
 void Heap::CheckNewSpaceExpansionCriteria() {
-  if (new_space_.TotalCapacity() < new_space_.MaximumCapacity() &&
-      survived_since_last_expansion_ > new_space_.TotalCapacity()) {
-    // Grow the size of new space if there is room to grow, enough data
-    // has survived scavenge since the last expansion and we are not in
-    // high promotion mode.
+  if (FLAG_experimental_new_space_growth_heuristic) {
+    if (new_space_.TotalCapacity() < new_space_.MaximumCapacity() &&
+        survived_last_scavenge_ * 100 / new_space_.TotalCapacity() >= 10) {
+      // Grow the size of new space if there is room to grow, and more than 10%
+      // have survived the last scavenge.
+      new_space_.Grow();
+      survived_since_last_expansion_ = 0;
+    }
+  } else if (new_space_.TotalCapacity() < new_space_.MaximumCapacity() &&
+             survived_since_last_expansion_ > new_space_.TotalCapacity()) {
+    // Grow the size of new space if there is room to grow, and enough data
+    // has survived scavenge since the last expansion.
     new_space_.Grow();
     survived_since_last_expansion_ = 0;
   }
@@ -1383,6 +1439,10 @@
   while (head_start != head_end) {
     int size = static_cast<int>(*(head_start++));
     HeapObject* obj = reinterpret_cast<HeapObject*>(*(head_start++));
+    // New space allocation in SemiSpaceCopyObject marked the region
+    // overlapping with promotion queue as uninitialized.
+    MSAN_MEMORY_IS_INITIALIZED(&size, sizeof(size));
+    MSAN_MEMORY_IS_INITIALIZED(&obj, sizeof(obj));
     emergency_stack_->Add(Entry(obj, size));
   }
   rear_ = head_end;
@@ -1501,6 +1561,8 @@
 
   // Copy objects reachable from the encountered weak collections list.
   scavenge_visitor.VisitPointer(&encountered_weak_collections_);
+  // Copy objects reachable from the encountered weak cells.
+  scavenge_visitor.VisitPointer(&encountered_weak_cells_);
 
   // Copy objects reachable from the code flushing candidates list.
   MarkCompactCollector* collector = mark_compact_collector();
@@ -1517,9 +1579,10 @@
   isolate()->global_handles()->RemoveObjectGroups();
   isolate()->global_handles()->RemoveImplicitRefGroups();
 
-  isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
+  isolate()->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
       &IsUnscavengedHeapObject);
-  isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots(
+
+  isolate()->global_handles()->IterateNewSpaceWeakIndependentRoots(
       &scavenge_visitor);
   new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
 
@@ -1624,6 +1687,10 @@
   // TODO(mvstanton): AllocationSites only need to be processed during
   // MARK_COMPACT, as they live in old space. Verify and address.
   ProcessAllocationSites(retainer);
+  // Collects callback info for handles that are pending (about to be
+  // collected) and either phantom or internal-fields.  Releases the global
+  // handles.  See also PostGarbageCollectionProcessing.
+  isolate()->global_handles()->CollectPhantomCallbackData();
 }
 
 
@@ -1763,12 +1830,32 @@
         promotion_queue()->remove(&target, &size);
 
         // Promoted object might be already partially visited
-        // during old space pointer iteration. Thus we search specificly
+        // during old space pointer iteration. Thus we search specifically
         // for pointers to from semispace instead of looking for pointers
         // to new space.
         DCHECK(!target->IsMap());
-        IterateAndMarkPointersToFromSpace(
-            target->address(), target->address() + size, &ScavengeObject);
+        Address obj_address = target->address();
+#if V8_DOUBLE_FIELDS_UNBOXING
+        LayoutDescriptorHelper helper(target->map());
+        bool has_only_tagged_fields = helper.all_fields_tagged();
+
+        if (!has_only_tagged_fields) {
+          for (int offset = 0; offset < size;) {
+            int end_of_region_offset;
+            if (helper.IsTagged(offset, size, &end_of_region_offset)) {
+              IterateAndMarkPointersToFromSpace(
+                  obj_address + offset, obj_address + end_of_region_offset,
+                  &ScavengeObject);
+            }
+            offset = end_of_region_offset;
+          }
+        } else {
+#endif
+          IterateAndMarkPointersToFromSpace(obj_address, obj_address + size,
+                                            &ScavengeObject);
+#if V8_DOUBLE_FIELDS_UNBOXING
+        }
+#endif
       }
     }
 
@@ -1804,6 +1891,11 @@
 }
 
 
+HeapObject* Heap::DoubleAlignForDeserialization(HeapObject* object, int size) {
+  return EnsureDoubleAligned(this, object, size);
+}
+
+
 enum LoggingAndProfiling {
   LOGGING_AND_PROFILING_ENABLED,
   LOGGING_AND_PROFILING_DISABLED
@@ -2014,7 +2106,17 @@
       // Order is important: slot might be inside of the target if target
       // was allocated over a dead object and slot comes from the store
       // buffer.
-      *slot = target;
+
+      // Unfortunately, the allocation can also write over the slot if the slot
+      // was in free space and the allocation wrote free list data (such as the
+      // free list map or entry size) over the slot.  We guard against this by
+      // checking that the slot still points to the object being moved.  This
+      // should be sufficient because neither the free list map nor the free
+      // list entry size should look like a new space pointer (the former is an
+      // old space pointer, the latter is word-aligned).
+      if (*slot == object) {
+        *slot = target;
+      }
       MigrateObject(heap, object, target, object_size);
 
       if (object_contents == POINTER_OBJECT) {
@@ -2263,6 +2365,17 @@
 }
 
 
+void Heap::ConfigureInitialOldGenerationSize() {
+  if (!old_generation_size_configured_ && tracer()->SurvivalEventsRecorded()) {
+    old_generation_allocation_limit_ =
+        Max(kMinimumOldGenerationAllocationLimit,
+            static_cast<intptr_t>(
+                static_cast<double>(initial_old_generation_size_) *
+                (tracer()->AverageSurvivalRate() / 100)));
+  }
+}
+
+
 AllocationResult Heap::AllocatePartialMap(InstanceType instance_type,
                                           int instance_size) {
   Object* result;
@@ -2273,15 +2386,21 @@
   reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map());
   reinterpret_cast<Map*>(result)->set_instance_type(instance_type);
   reinterpret_cast<Map*>(result)->set_instance_size(instance_size);
+  // Initialize to only containing tagged fields.
   reinterpret_cast<Map*>(result)->set_visitor_id(
-      StaticVisitorBase::GetVisitorId(instance_type, instance_size));
+      StaticVisitorBase::GetVisitorId(instance_type, instance_size, false));
+  if (FLAG_unbox_double_fields) {
+    reinterpret_cast<Map*>(result)
+        ->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
+  }
   reinterpret_cast<Map*>(result)->set_inobject_properties(0);
   reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0);
   reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
   reinterpret_cast<Map*>(result)->set_bit_field(0);
   reinterpret_cast<Map*>(result)->set_bit_field2(0);
   int bit_field3 = Map::EnumLengthBits::encode(kInvalidEnumCacheSentinel) |
-                   Map::OwnsDescriptors::encode(true);
+                   Map::OwnsDescriptors::encode(true) |
+                   Map::Counter::encode(Map::kRetainingCounterStart);
   reinterpret_cast<Map*>(result)->set_bit_field3(bit_field3);
   return result;
 }
@@ -2297,8 +2416,6 @@
   result->set_map_no_write_barrier(meta_map());
   Map* map = Map::cast(result);
   map->set_instance_type(instance_type);
-  map->set_visitor_id(
-      StaticVisitorBase::GetVisitorId(instance_type, instance_size));
   map->set_prototype(null_value(), SKIP_WRITE_BARRIER);
   map->set_constructor(null_value(), SKIP_WRITE_BARRIER);
   map->set_instance_size(instance_size);
@@ -2310,10 +2427,17 @@
   map->init_back_pointer(undefined_value());
   map->set_unused_property_fields(0);
   map->set_instance_descriptors(empty_descriptor_array());
+  if (FLAG_unbox_double_fields) {
+    map->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
+  }
+  // Must be called only after |instance_type|, |instance_size| and
+  // |layout_descriptor| are set.
+  map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
   map->set_bit_field(0);
   map->set_bit_field2(1 << Map::kIsExtensible);
   int bit_field3 = Map::EnumLengthBits::encode(kInvalidEnumCacheSentinel) |
-                   Map::OwnsDescriptors::encode(true);
+                   Map::OwnsDescriptors::encode(true) |
+                   Map::Counter::encode(Map::kRetainingCounterStart);
   map->set_bit_field3(bit_field3);
   map->set_elements_kind(elements_kind);
 
@@ -2436,28 +2560,46 @@
   meta_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
   meta_map()->init_back_pointer(undefined_value());
   meta_map()->set_instance_descriptors(empty_descriptor_array());
+  if (FLAG_unbox_double_fields) {
+    meta_map()->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
+  }
 
   fixed_array_map()->set_code_cache(empty_fixed_array());
   fixed_array_map()->set_dependent_code(
       DependentCode::cast(empty_fixed_array()));
   fixed_array_map()->init_back_pointer(undefined_value());
   fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
+  if (FLAG_unbox_double_fields) {
+    fixed_array_map()->set_layout_descriptor(
+        LayoutDescriptor::FastPointerLayout());
+  }
 
   undefined_map()->set_code_cache(empty_fixed_array());
   undefined_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
   undefined_map()->init_back_pointer(undefined_value());
   undefined_map()->set_instance_descriptors(empty_descriptor_array());
+  if (FLAG_unbox_double_fields) {
+    undefined_map()->set_layout_descriptor(
+        LayoutDescriptor::FastPointerLayout());
+  }
 
   null_map()->set_code_cache(empty_fixed_array());
   null_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
   null_map()->init_back_pointer(undefined_value());
   null_map()->set_instance_descriptors(empty_descriptor_array());
+  if (FLAG_unbox_double_fields) {
+    null_map()->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
+  }
 
   constant_pool_array_map()->set_code_cache(empty_fixed_array());
   constant_pool_array_map()->set_dependent_code(
       DependentCode::cast(empty_fixed_array()));
   constant_pool_array_map()->init_back_pointer(undefined_value());
   constant_pool_array_map()->set_instance_descriptors(empty_descriptor_array());
+  if (FLAG_unbox_double_fields) {
+    constant_pool_array_map()->set_layout_descriptor(
+        LayoutDescriptor::FastPointerLayout());
+  }
 
   // Fix prototype object for existing maps.
   meta_map()->set_prototype(null_value());
@@ -2517,6 +2659,13 @@
       roots_[entry.index] = map;
     }
 
+    {  // Create a separate external one byte string map for native sources.
+      AllocationResult allocation = AllocateMap(EXTERNAL_ONE_BYTE_STRING_TYPE,
+                                                ExternalOneByteString::kSize);
+      if (!allocation.To(&obj)) return false;
+      set_native_source_string_map(Map::cast(obj));
+    }
+
     ALLOCATE_VARSIZE_MAP(STRING_TYPE, undetectable_string)
     undetectable_string_map()->set_is_undetectable();
 
@@ -2546,6 +2695,7 @@
 
     ALLOCATE_MAP(CELL_TYPE, Cell::kSize, cell)
     ALLOCATE_MAP(PROPERTY_CELL_TYPE, PropertyCell::kSize, global_property_cell)
+    ALLOCATE_MAP(WEAK_CELL_TYPE, WeakCell::kSize, weak_cell)
     ALLOCATE_MAP(FILLER_TYPE, kPointerSize, one_pointer_filler)
     ALLOCATE_MAP(FILLER_TYPE, 2 * kPointerSize, two_pointer_filler)
 
@@ -2565,7 +2715,8 @@
     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, with_context)
     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, block_context)
     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, module_context)
-    ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, global_context)
+    ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, script_context)
+    ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, script_context_table)
 
     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, native_context)
     native_context_map()->set_dictionary_map(true);
@@ -2672,6 +2823,22 @@
 }
 
 
+AllocationResult Heap::AllocateWeakCell(HeapObject* value) {
+  int size = WeakCell::kSize;
+  STATIC_ASSERT(WeakCell::kSize <= Page::kMaxRegularHeapObjectSize);
+  HeapObject* result;
+  {
+    AllocationResult allocation =
+        AllocateRaw(size, OLD_POINTER_SPACE, OLD_POINTER_SPACE);
+    if (!allocation.To(&result)) return allocation;
+  }
+  result->set_map_no_write_barrier(weak_cell_map());
+  WeakCell::cast(result)->initialize(value);
+  WeakCell::cast(result)->set_next(undefined_value(), SKIP_WRITE_BARRIER);
+  return result;
+}
+
+
 void Heap::CreateApiObjects() {
   HandleScope scope(isolate());
   Factory* factory = isolate()->factory();
@@ -2825,6 +2992,26 @@
   set_instanceof_cache_map(Smi::FromInt(0));
   set_instanceof_cache_answer(Smi::FromInt(0));
 
+  {
+    HandleScope scope(isolate());
+#define SYMBOL_INIT(name)                               \
+  Handle<Symbol> name = factory->NewPrivateOwnSymbol(); \
+  roots_[k##name##RootIndex] = *name;
+    PRIVATE_SYMBOL_LIST(SYMBOL_INIT)
+#undef SYMBOL_INIT
+  }
+
+  {
+    HandleScope scope(isolate());
+#define SYMBOL_INIT(name, varname, description)                             \
+  Handle<Symbol> name = factory->NewSymbol();                               \
+  Handle<String> name##d = factory->NewStringFromStaticChars(#description); \
+  name->set_name(*name##d);                                                 \
+  roots_[k##name##RootIndex] = *name;
+    PUBLIC_SYMBOL_LIST(SYMBOL_INIT)
+#undef SYMBOL_INIT
+  }
+
   CreateFixedStubs();
 
   // Allocate the dictionary of intrinsic function names.
@@ -2853,7 +3040,7 @@
   set_undefined_cell(*factory->NewCell(factory->undefined_value()));
 
   // The symbol registry is initialized lazily.
-  set_symbol_registry(undefined_value());
+  set_symbol_registry(Smi::FromInt(0));
 
   // Allocate object to hold object observation state.
   set_observation_state(*factory->NewJSObjectFromMap(
@@ -2863,19 +3050,6 @@
   // Number of queued microtasks stored in Isolate::pending_microtask_count().
   set_microtask_queue(empty_fixed_array());
 
-  set_detailed_stack_trace_symbol(*factory->NewPrivateOwnSymbol());
-  set_elements_transition_symbol(*factory->NewPrivateOwnSymbol());
-  set_frozen_symbol(*factory->NewPrivateOwnSymbol());
-  set_megamorphic_symbol(*factory->NewPrivateOwnSymbol());
-  set_premonomorphic_symbol(*factory->NewPrivateOwnSymbol());
-  set_generic_symbol(*factory->NewPrivateOwnSymbol());
-  set_nonexistent_symbol(*factory->NewPrivateOwnSymbol());
-  set_normal_ic_symbol(*factory->NewPrivateOwnSymbol());
-  set_observed_symbol(*factory->NewPrivateOwnSymbol());
-  set_stack_trace_symbol(*factory->NewPrivateOwnSymbol());
-  set_uninitialized_symbol(*factory->NewPrivateOwnSymbol());
-  set_home_object_symbol(*factory->NewPrivateOwnSymbol());
-
   Handle<SeededNumberDictionary> slow_element_dictionary =
       SeededNumberDictionary::New(isolate(), 0, TENURED);
   slow_element_dictionary->set_requires_slow_elements();
@@ -3681,12 +3855,14 @@
 
 
 AllocationResult Heap::CopyJSObject(JSObject* source, AllocationSite* site) {
-  // Never used to copy functions.  If functions need to be copied we
-  // have to be careful to clear the literals array.
-  SLOW_DCHECK(!source->IsJSFunction());
-
   // Make the clone.
   Map* map = source->map();
+
+  // We can only clone normal objects or arrays. Copying anything else
+  // will break invariants.
+  CHECK(map->instance_type() == JS_OBJECT_TYPE ||
+        map->instance_type() == JS_ARRAY_TYPE);
+
   int object_size = map->instance_size();
   HeapObject* clone;
 
@@ -4276,13 +4452,18 @@
 }
 
 
-void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) {
-  incremental_marking()->Step(step_size,
-                              IncrementalMarking::NO_GC_VIA_STACK_GUARD, true);
-
-  if (incremental_marking()->IsComplete()) {
-    IdleMarkCompact("idle notification: finalize incremental");
+bool Heap::TryFinalizeIdleIncrementalMarking(
+    double idle_time_in_ms, size_t size_of_objects,
+    size_t final_incremental_mark_compact_speed_in_bytes_per_ms) {
+  if (incremental_marking()->IsComplete() ||
+      (mark_compact_collector_.marking_deque()->IsEmpty() &&
+       gc_idle_time_handler_.ShouldDoFinalIncrementalMarkCompact(
+           static_cast<size_t>(idle_time_in_ms), size_of_objects,
+           final_incremental_mark_compact_speed_in_bytes_per_ms))) {
+    CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental");
+    return true;
   }
+  return false;
 }
 
 
@@ -4292,56 +4473,91 @@
 }
 
 
+static double MonotonicallyIncreasingTimeInMs() {
+  return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() *
+         static_cast<double>(base::Time::kMillisecondsPerSecond);
+}
+
+
 bool Heap::IdleNotification(int idle_time_in_ms) {
-  // If incremental marking is off, we do not perform idle notification.
-  if (!FLAG_incremental_marking) return true;
-  base::ElapsedTimer timer;
-  timer.Start();
-  isolate()->counters()->gc_idle_time_allotted_in_ms()->AddSample(
-      idle_time_in_ms);
+  return IdleNotification(
+      V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() +
+      (static_cast<double>(idle_time_in_ms) /
+       static_cast<double>(base::Time::kMillisecondsPerSecond)));
+}
+
+
+bool Heap::IdleNotification(double deadline_in_seconds) {
+  double deadline_in_ms =
+      deadline_in_seconds *
+      static_cast<double>(base::Time::kMillisecondsPerSecond);
   HistogramTimerScope idle_notification_scope(
       isolate_->counters()->gc_idle_notification());
 
   GCIdleTimeHandler::HeapState heap_state;
   heap_state.contexts_disposed = contexts_disposed_;
+  heap_state.contexts_disposal_rate =
+      tracer()->ContextDisposalRateInMilliseconds();
   heap_state.size_of_objects = static_cast<size_t>(SizeOfObjects());
   heap_state.incremental_marking_stopped = incremental_marking()->IsStopped();
   // TODO(ulan): Start incremental marking only for large heaps.
   heap_state.can_start_incremental_marking =
-      incremental_marking()->ShouldActivate();
+      incremental_marking()->ShouldActivate() && FLAG_incremental_marking;
   heap_state.sweeping_in_progress =
       mark_compact_collector()->sweeping_in_progress();
   heap_state.mark_compact_speed_in_bytes_per_ms =
       static_cast<size_t>(tracer()->MarkCompactSpeedInBytesPerMillisecond());
   heap_state.incremental_marking_speed_in_bytes_per_ms = static_cast<size_t>(
       tracer()->IncrementalMarkingSpeedInBytesPerMillisecond());
+  heap_state.final_incremental_mark_compact_speed_in_bytes_per_ms =
+      static_cast<size_t>(
+          tracer()->FinalIncrementalMarkCompactSpeedInBytesPerMillisecond());
   heap_state.scavenge_speed_in_bytes_per_ms =
       static_cast<size_t>(tracer()->ScavengeSpeedInBytesPerMillisecond());
-  heap_state.available_new_space_memory = new_space_.Available();
+  heap_state.used_new_space_size = new_space_.Size();
   heap_state.new_space_capacity = new_space_.Capacity();
   heap_state.new_space_allocation_throughput_in_bytes_per_ms =
       static_cast<size_t>(
           tracer()->NewSpaceAllocationThroughputInBytesPerMillisecond());
 
+  double idle_time_in_ms = deadline_in_ms - MonotonicallyIncreasingTimeInMs();
   GCIdleTimeAction action =
       gc_idle_time_handler_.Compute(idle_time_in_ms, heap_state);
+  isolate()->counters()->gc_idle_time_allotted_in_ms()->AddSample(
+      static_cast<int>(idle_time_in_ms));
 
   bool result = false;
   switch (action.type) {
     case DONE:
       result = true;
       break;
-    case DO_INCREMENTAL_MARKING:
+    case DO_INCREMENTAL_MARKING: {
       if (incremental_marking()->IsStopped()) {
         incremental_marking()->Start();
       }
-      AdvanceIdleIncrementalMarking(action.parameter);
+      double remaining_idle_time_in_ms = 0.0;
+      do {
+        incremental_marking()->Step(
+            action.parameter, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
+            IncrementalMarking::FORCE_MARKING,
+            IncrementalMarking::DO_NOT_FORCE_COMPLETION);
+        remaining_idle_time_in_ms =
+            deadline_in_ms - MonotonicallyIncreasingTimeInMs();
+      } while (remaining_idle_time_in_ms >=
+                   2.0 * GCIdleTimeHandler::kIncrementalMarkingStepTimeInMs &&
+               !incremental_marking()->IsComplete() &&
+               !mark_compact_collector_.marking_deque()->IsEmpty());
+      if (remaining_idle_time_in_ms > 0.0) {
+        action.additional_work = TryFinalizeIdleIncrementalMarking(
+            remaining_idle_time_in_ms, heap_state.size_of_objects,
+            heap_state.final_incremental_mark_compact_speed_in_bytes_per_ms);
+      }
       break;
+    }
     case DO_FULL_GC: {
-      HistogramTimerScope scope(isolate_->counters()->gc_context());
       if (contexts_disposed_) {
-        CollectAllGarbage(kReduceMemoryFootprintMask,
-                          "idle notification: contexts disposed");
+        HistogramTimerScope scope(isolate_->counters()->gc_context());
+        CollectAllGarbage(kNoGCFlags, "idle notification: contexts disposed");
         gc_idle_time_handler_.NotifyIdleMarkCompact();
         gc_count_at_last_idle_gc_ = gc_count_;
       } else {
@@ -4359,20 +4575,35 @@
       break;
   }
 
-  int actual_time_ms = static_cast<int>(timer.Elapsed().InMilliseconds());
-  if (actual_time_ms <= idle_time_in_ms) {
-    isolate()->counters()->gc_idle_time_limit_undershot()->AddSample(
-        idle_time_in_ms - actual_time_ms);
+  double current_time = MonotonicallyIncreasingTimeInMs();
+  last_idle_notification_time_ = current_time;
+  double deadline_difference = deadline_in_ms - current_time;
+
+  if (deadline_difference >= 0) {
+    if (action.type != DONE && action.type != DO_NOTHING) {
+      isolate()->counters()->gc_idle_time_limit_undershot()->AddSample(
+          static_cast<int>(deadline_difference));
+    }
   } else {
     isolate()->counters()->gc_idle_time_limit_overshot()->AddSample(
-        actual_time_ms - idle_time_in_ms);
+        static_cast<int>(-deadline_difference));
   }
 
-  if (FLAG_trace_idle_notification) {
-    PrintF("Idle notification: requested idle time %d ms, actual time %d ms [",
-           idle_time_in_ms, actual_time_ms);
+  if ((FLAG_trace_idle_notification && action.type > DO_NOTHING) ||
+      FLAG_trace_idle_notification_verbose) {
+    PrintF(
+        "Idle notification: requested idle time %.2f ms, used idle time %.2f "
+        "ms, deadline usage %.2f ms [",
+        idle_time_in_ms, idle_time_in_ms - deadline_difference,
+        deadline_difference);
     action.Print();
-    PrintF("]\n");
+    PrintF("]");
+    if (FLAG_trace_idle_notification_verbose) {
+      PrintF("[");
+      heap_state.Print();
+      PrintF("]");
+    }
+    PrintF("\n");
   }
 
   contexts_disposed_ = 0;
@@ -4380,6 +4611,13 @@
 }
 
 
+bool Heap::RecentIdleNotificationHappened() {
+  return (last_idle_notification_time_ +
+          GCIdleTimeHandler::kMaxFrameRenderingIdleTime) >
+         MonotonicallyIncreasingTimeInMs();
+}
+
+
 #ifdef DEBUG
 
 void Heap::Print() {
@@ -4482,14 +4720,25 @@
       return property_cell_space_->Contains(addr);
     case LO_SPACE:
       return lo_space_->SlowContains(addr);
-    case INVALID_SPACE:
-      break;
   }
   UNREACHABLE();
   return false;
 }
 
 
+bool Heap::RootIsImmortalImmovable(int root_index) {
+  switch (root_index) {
+#define CASE(name)               \
+  case Heap::k##name##RootIndex: \
+    return true;
+    IMMORTAL_IMMOVABLE_ROOT_LIST(CASE);
+#undef CASE
+    default:
+      return false;
+  }
+}
+
+
 #ifdef VERIFY_HEAP
 void Heap::Verify() {
   CHECK(HasBeenSetUp());
@@ -4893,9 +5142,9 @@
       initial_semispace_size_ = max_semi_space_size_;
       if (FLAG_trace_gc) {
         PrintPID(
-            "Min semi-space size cannot be more than the maximum"
+            "Min semi-space size cannot be more than the maximum "
             "semi-space size of %d MB\n",
-            max_semi_space_size_);
+            max_semi_space_size_ / MB);
       }
     } else {
       initial_semispace_size_ = initial_semispace_size;
@@ -4904,12 +5153,48 @@
 
   initial_semispace_size_ = Min(initial_semispace_size_, max_semi_space_size_);
 
+  if (FLAG_target_semi_space_size > 0) {
+    int target_semispace_size = FLAG_target_semi_space_size * MB;
+    if (target_semispace_size < initial_semispace_size_) {
+      target_semispace_size_ = initial_semispace_size_;
+      if (FLAG_trace_gc) {
+        PrintPID(
+            "Target semi-space size cannot be less than the minimum "
+            "semi-space size of %d MB\n",
+            initial_semispace_size_ / MB);
+      }
+    } else if (target_semispace_size > max_semi_space_size_) {
+      target_semispace_size_ = max_semi_space_size_;
+      if (FLAG_trace_gc) {
+        PrintPID(
+            "Target semi-space size cannot be less than the maximum "
+            "semi-space size of %d MB\n",
+            max_semi_space_size_ / MB);
+      }
+    } else {
+      target_semispace_size_ = target_semispace_size;
+    }
+  }
+
+  target_semispace_size_ = Max(initial_semispace_size_, target_semispace_size_);
+
+  if (FLAG_semi_space_growth_factor < 2) {
+    FLAG_semi_space_growth_factor = 2;
+  }
+
   // The old generation is paged and needs at least one page for each space.
   int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1;
   max_old_generation_size_ =
       Max(static_cast<intptr_t>(paged_space_count * Page::kPageSize),
           max_old_generation_size_);
 
+  if (FLAG_initial_old_space_size > 0) {
+    initial_old_generation_size_ = FLAG_initial_old_space_size * MB;
+  } else {
+    initial_old_generation_size_ = max_old_generation_size_ / 2;
+  }
+  old_generation_allocation_limit_ = initial_old_generation_size_;
+
   // We rely on being able to allocate new arrays in paged spaces.
   DCHECK(Page::kMaxRegularHeapObjectSize >=
          (JSArray::kSize +
@@ -5185,6 +5470,9 @@
 }
 
 
+void Heap::NotifyDeserializationComplete() { deserialization_complete_ = true; }
+
+
 void Heap::TearDown() {
 #ifdef VERIFY_HEAP
   if (FLAG_verify_heap) {
@@ -5202,7 +5490,7 @@
     PrintF("total_gc_time=%.1f ", total_gc_time_ms_);
     PrintF("min_in_mutator=%.1f ", get_min_in_mutator());
     PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ", get_max_alive_after_gc());
-    PrintF("total_marking_time=%.1f ", tracer_.cumulative_sweeping_duration());
+    PrintF("total_marking_time=%.1f ", tracer_.cumulative_marking_duration());
     PrintF("total_sweeping_time=%.1f ", tracer_.cumulative_sweeping_duration());
     PrintF("\n\n");
   }
@@ -5289,7 +5577,6 @@
   }
 
   store_buffer()->TearDown();
-  incremental_marking()->TearDown();
 
   isolate_->memory_allocator()->TearDown();
 }
diff --git a/src/heap/heap.gyp b/src/heap/heap.gyp
deleted file mode 100644
index 2970eb8..0000000
--- a/src/heap/heap.gyp
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright 2014 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  'variables': {
-    'v8_code': 1,
-  },
-  'includes': ['../../build/toolchain.gypi', '../../build/features.gypi'],
-  'targets': [
-    {
-      'target_name': 'heap-unittests',
-      'type': 'executable',
-      'dependencies': [
-        '../../testing/gtest.gyp:gtest',
-        '../../testing/gtest.gyp:gtest_main',
-        '../../tools/gyp/v8.gyp:v8_libplatform',
-      ],
-      'include_dirs': [
-        '../..',
-      ],
-      'sources': [  ### gcmole(all) ###
-        'gc-idle-time-handler-unittest.cc',
-      ],
-      'conditions': [
-        ['component=="shared_library"', {
-          # heap-unittests can't be built against a shared library, so we
-          # need to depend on the underlying static target in that case.
-          'conditions': [
-            ['v8_use_snapshot=="true"', {
-              'dependencies': ['../../tools/gyp/v8.gyp:v8_snapshot'],
-            },
-            {
-              'dependencies': [
-                '../../tools/gyp/v8.gyp:v8_nosnapshot',
-              ],
-            }],
-          ],
-        }, {
-          'dependencies': ['../../tools/gyp/v8.gyp:v8'],
-        }],
-        ['os_posix == 1', {
-          # TODO(svenpanne): This is a temporary work-around to fix the warnings
-          # that show up because we use -std=gnu++0x instead of -std=c++11.
-          'cflags!': [
-            '-pedantic',
-          ],
-        }],
-      ],
-    },
-  ],
-}
diff --git a/src/heap/heap.h b/src/heap/heap.h
index c9d0f31..e6ccf2e 100644
--- a/src/heap/heap.h
+++ b/src/heap/heap.h
@@ -52,6 +52,7 @@
   V(Map, fixed_cow_array_map, FixedCOWArrayMap)                                \
   V(Map, fixed_double_array_map, FixedDoubleArrayMap)                          \
   V(Map, constant_pool_array_map, ConstantPoolArrayMap)                        \
+  V(Map, weak_cell_map, WeakCellMap)                                           \
   V(Oddball, no_interceptor_result_sentinel, NoInterceptorResultSentinel)      \
   V(Map, hash_table_map, HashTableMap)                                         \
   V(Map, ordered_hash_table_map, OrderedHashTableMap)                          \
@@ -83,6 +84,7 @@
   V(Map, external_string_with_one_byte_data_map,                               \
     ExternalStringWithOneByteDataMap)                                          \
   V(Map, external_one_byte_string_map, ExternalOneByteStringMap)               \
+  V(Map, native_source_string_map, NativeSourceStringMap)                      \
   V(Map, short_external_string_map, ShortExternalStringMap)                    \
   V(Map, short_external_string_with_one_byte_data_map,                         \
     ShortExternalStringWithOneByteDataMap)                                     \
@@ -146,7 +148,8 @@
   V(Map, with_context_map, WithContextMap)                                     \
   V(Map, block_context_map, BlockContextMap)                                   \
   V(Map, module_context_map, ModuleContextMap)                                 \
-  V(Map, global_context_map, GlobalContextMap)                                 \
+  V(Map, script_context_map, ScriptContextMap)                                 \
+  V(Map, script_context_table_map, ScriptContextTableMap)                      \
   V(Map, undefined_map, UndefinedMap)                                          \
   V(Map, the_hole_map, TheHoleMap)                                             \
   V(Map, null_map, NullMap)                                                    \
@@ -175,20 +178,8 @@
   V(JSObject, observation_state, ObservationState)                             \
   V(Map, external_map, ExternalMap)                                            \
   V(Object, symbol_registry, SymbolRegistry)                                   \
-  V(Symbol, frozen_symbol, FrozenSymbol)                                       \
-  V(Symbol, nonexistent_symbol, NonExistentSymbol)                             \
-  V(Symbol, elements_transition_symbol, ElementsTransitionSymbol)              \
   V(SeededNumberDictionary, empty_slow_element_dictionary,                     \
     EmptySlowElementDictionary)                                                \
-  V(Symbol, observed_symbol, ObservedSymbol)                                   \
-  V(Symbol, uninitialized_symbol, UninitializedSymbol)                         \
-  V(Symbol, megamorphic_symbol, MegamorphicSymbol)                             \
-  V(Symbol, premonomorphic_symbol, PremonomorphicSymbol)                       \
-  V(Symbol, generic_symbol, GenericSymbol)                                     \
-  V(Symbol, stack_trace_symbol, StackTraceSymbol)                              \
-  V(Symbol, detailed_stack_trace_symbol, DetailedStackTraceSymbol)             \
-  V(Symbol, normal_ic_symbol, NormalICSymbol)                                  \
-  V(Symbol, home_object_symbol, HomeObjectSymbol)                              \
   V(FixedArray, materialized_objects, MaterializedObjects)                     \
   V(FixedArray, allocation_sites_scratchpad, AllocationSitesScratchpad)        \
   V(FixedArray, microtask_queue, MicrotaskQueue)
@@ -208,134 +199,171 @@
   SMI_ROOT_LIST(V)    \
   V(StringTable, string_table, StringTable)
 
-// Heap roots that are known to be immortal immovable, for which we can safely
-// skip write barriers.
-#define IMMORTAL_IMMOVABLE_ROOT_LIST(V) \
-  V(byte_array_map)                     \
-  V(free_space_map)                     \
-  V(one_pointer_filler_map)             \
-  V(two_pointer_filler_map)             \
-  V(undefined_value)                    \
-  V(the_hole_value)                     \
-  V(null_value)                         \
-  V(true_value)                         \
-  V(false_value)                        \
-  V(uninitialized_value)                \
-  V(cell_map)                           \
-  V(global_property_cell_map)           \
-  V(shared_function_info_map)           \
-  V(meta_map)                           \
-  V(heap_number_map)                    \
-  V(mutable_heap_number_map)            \
-  V(native_context_map)                 \
-  V(fixed_array_map)                    \
-  V(code_map)                           \
-  V(scope_info_map)                     \
-  V(fixed_cow_array_map)                \
-  V(fixed_double_array_map)             \
-  V(constant_pool_array_map)            \
-  V(no_interceptor_result_sentinel)     \
-  V(hash_table_map)                     \
-  V(ordered_hash_table_map)             \
-  V(empty_fixed_array)                  \
-  V(empty_byte_array)                   \
-  V(empty_descriptor_array)             \
-  V(empty_constant_pool_array)          \
-  V(arguments_marker)                   \
-  V(symbol_map)                         \
-  V(sloppy_arguments_elements_map)      \
-  V(function_context_map)               \
-  V(catch_context_map)                  \
-  V(with_context_map)                   \
-  V(block_context_map)                  \
-  V(module_context_map)                 \
-  V(global_context_map)                 \
-  V(undefined_map)                      \
-  V(the_hole_map)                       \
-  V(null_map)                           \
-  V(boolean_map)                        \
-  V(uninitialized_map)                  \
-  V(message_object_map)                 \
-  V(foreign_map)                        \
-  V(neander_map)
+#define INTERNALIZED_STRING_LIST(V)                        \
+  V(Object_string, "Object")                               \
+  V(proto_string, "__proto__")                             \
+  V(arguments_string, "arguments")                         \
+  V(Arguments_string, "Arguments")                         \
+  V(caller_string, "caller")                               \
+  V(boolean_string, "boolean")                             \
+  V(Boolean_string, "Boolean")                             \
+  V(callee_string, "callee")                               \
+  V(constructor_string, "constructor")                     \
+  V(dot_result_string, ".result")                          \
+  V(eval_string, "eval")                                   \
+  V(empty_string, "")                                      \
+  V(function_string, "function")                           \
+  V(Function_string, "Function")                           \
+  V(length_string, "length")                               \
+  V(name_string, "name")                                   \
+  V(null_string, "null")                                   \
+  V(number_string, "number")                               \
+  V(Number_string, "Number")                               \
+  V(nan_string, "NaN")                                     \
+  V(source_string, "source")                               \
+  V(source_url_string, "source_url")                       \
+  V(source_mapping_url_string, "source_mapping_url")       \
+  V(global_string, "global")                               \
+  V(ignore_case_string, "ignoreCase")                      \
+  V(multiline_string, "multiline")                         \
+  V(sticky_string, "sticky")                               \
+  V(harmony_regexps_string, "harmony_regexps")             \
+  V(input_string, "input")                                 \
+  V(index_string, "index")                                 \
+  V(last_index_string, "lastIndex")                        \
+  V(object_string, "object")                               \
+  V(prototype_string, "prototype")                         \
+  V(string_string, "string")                               \
+  V(String_string, "String")                               \
+  V(symbol_string, "symbol")                               \
+  V(Symbol_string, "Symbol")                               \
+  V(Map_string, "Map")                                     \
+  V(Set_string, "Set")                                     \
+  V(WeakMap_string, "WeakMap")                             \
+  V(WeakSet_string, "WeakSet")                             \
+  V(for_string, "for")                                     \
+  V(for_api_string, "for_api")                             \
+  V(for_intern_string, "for_intern")                       \
+  V(private_api_string, "private_api")                     \
+  V(private_intern_string, "private_intern")               \
+  V(Date_string, "Date")                                   \
+  V(char_at_string, "CharAt")                              \
+  V(undefined_string, "undefined")                         \
+  V(value_of_string, "valueOf")                            \
+  V(stack_string, "stack")                                 \
+  V(toJSON_string, "toJSON")                               \
+  V(KeyedLoadMonomorphic_string, "KeyedLoadMonomorphic")   \
+  V(KeyedStoreMonomorphic_string, "KeyedStoreMonomorphic") \
+  V(stack_overflow_string, "kStackOverflowBoilerplate")    \
+  V(illegal_access_string, "illegal access")               \
+  V(cell_value_string, "%cell_value")                      \
+  V(illegal_argument_string, "illegal argument")           \
+  V(identity_hash_string, "v8::IdentityHash")              \
+  V(closure_string, "(closure)")                           \
+  V(dot_string, ".")                                       \
+  V(compare_ic_string, "==")                               \
+  V(strict_compare_ic_string, "===")                       \
+  V(infinity_string, "Infinity")                           \
+  V(minus_infinity_string, "-Infinity")                    \
+  V(query_colon_string, "(?:)")                            \
+  V(Generator_string, "Generator")                         \
+  V(throw_string, "throw")                                 \
+  V(done_string, "done")                                   \
+  V(value_string, "value")                                 \
+  V(next_string, "next")                                   \
+  V(byte_length_string, "byteLength")                      \
+  V(byte_offset_string, "byteOffset")                      \
+  V(minus_zero_string, "-0")                               \
+  V(Array_string, "Array")                                 \
+  V(Error_string, "Error")                                 \
+  V(RegExp_string, "RegExp")
 
-#define INTERNALIZED_STRING_LIST(V)                                \
-  V(Object_string, "Object")                                       \
-  V(proto_string, "__proto__")                                     \
-  V(arguments_string, "arguments")                                 \
-  V(Arguments_string, "Arguments")                                 \
-  V(caller_string, "caller")                                       \
-  V(boolean_string, "boolean")                                     \
-  V(Boolean_string, "Boolean")                                     \
-  V(callee_string, "callee")                                       \
-  V(constructor_string, "constructor")                             \
-  V(dot_result_string, ".result")                                  \
-  V(dot_for_string, ".for.")                                       \
-  V(eval_string, "eval")                                           \
-  V(empty_string, "")                                              \
-  V(function_string, "function")                                   \
-  V(Function_string, "Function")                                   \
-  V(length_string, "length")                                       \
-  V(name_string, "name")                                           \
-  V(null_string, "null")                                           \
-  V(number_string, "number")                                       \
-  V(Number_string, "Number")                                       \
-  V(nan_string, "NaN")                                             \
-  V(source_string, "source")                                       \
-  V(source_url_string, "source_url")                               \
-  V(source_mapping_url_string, "source_mapping_url")               \
-  V(global_string, "global")                                       \
-  V(ignore_case_string, "ignoreCase")                              \
-  V(multiline_string, "multiline")                                 \
-  V(sticky_string, "sticky")                                       \
-  V(harmony_regexps_string, "harmony_regexps")                     \
-  V(input_string, "input")                                         \
-  V(index_string, "index")                                         \
-  V(last_index_string, "lastIndex")                                \
-  V(object_string, "object")                                       \
-  V(prototype_string, "prototype")                                 \
-  V(string_string, "string")                                       \
-  V(String_string, "String")                                       \
-  V(symbol_string, "symbol")                                       \
-  V(Symbol_string, "Symbol")                                       \
-  V(Map_string, "Map")                                             \
-  V(Set_string, "Set")                                             \
-  V(WeakMap_string, "WeakMap")                                     \
-  V(WeakSet_string, "WeakSet")                                     \
-  V(for_string, "for")                                             \
-  V(for_api_string, "for_api")                                     \
-  V(for_intern_string, "for_intern")                               \
-  V(private_api_string, "private_api")                             \
-  V(private_intern_string, "private_intern")                       \
-  V(Date_string, "Date")                                           \
-  V(char_at_string, "CharAt")                                      \
-  V(undefined_string, "undefined")                                 \
-  V(value_of_string, "valueOf")                                    \
-  V(stack_string, "stack")                                         \
-  V(toJSON_string, "toJSON")                                       \
-  V(KeyedLoadMonomorphic_string, "KeyedLoadMonomorphic")           \
-  V(KeyedStoreMonomorphic_string, "KeyedStoreMonomorphic")         \
-  V(stack_overflow_string, "kStackOverflowBoilerplate")            \
-  V(illegal_access_string, "illegal access")                       \
-  V(cell_value_string, "%cell_value")                              \
-  V(illegal_argument_string, "illegal argument")                   \
-  V(identity_hash_string, "v8::IdentityHash")                      \
-  V(closure_string, "(closure)")                                   \
-  V(dot_string, ".")                                               \
-  V(compare_ic_string, "==")                                       \
-  V(strict_compare_ic_string, "===")                               \
-  V(infinity_string, "Infinity")                                   \
-  V(minus_infinity_string, "-Infinity")                            \
-  V(query_colon_string, "(?:)")                                    \
-  V(Generator_string, "Generator")                                 \
-  V(throw_string, "throw")                                         \
-  V(done_string, "done")                                           \
-  V(value_string, "value")                                         \
-  V(next_string, "next")                                           \
-  V(byte_length_string, "byteLength")                              \
-  V(byte_offset_string, "byteOffset")                              \
-  V(intl_initialized_marker_string, "v8::intl_initialized_marker") \
-  V(intl_impl_object_string, "v8::intl_object")
+#define PRIVATE_SYMBOL_LIST(V)      \
+  V(nonextensible_symbol)           \
+  V(sealed_symbol)                  \
+  V(frozen_symbol)                  \
+  V(nonexistent_symbol)             \
+  V(elements_transition_symbol)     \
+  V(prototype_users_symbol)         \
+  V(observed_symbol)                \
+  V(uninitialized_symbol)           \
+  V(megamorphic_symbol)             \
+  V(premonomorphic_symbol)          \
+  V(generic_symbol)                 \
+  V(stack_trace_symbol)             \
+  V(detailed_stack_trace_symbol)    \
+  V(normal_ic_symbol)               \
+  V(home_object_symbol)             \
+  V(intl_initialized_marker_symbol) \
+  V(intl_impl_object_symbol)        \
+  V(promise_debug_marker_symbol)    \
+  V(promise_has_handler_symbol)     \
+  V(class_script_symbol)            \
+  V(class_start_position_symbol)    \
+  V(class_end_position_symbol)
+
+#define PUBLIC_SYMBOL_LIST(V)                                    \
+  V(has_instance_symbol, symbolHasInstance, Symbol.hasInstance)  \
+  V(is_concat_spreadable_symbol, symbolIsConcatSpreadable,       \
+    Symbol.isConcatSpreadable)                                   \
+  V(is_regexp_symbol, symbolIsRegExp, Symbol.isRegExp)           \
+  V(iterator_symbol, symbolIterator, Symbol.iterator)            \
+  V(to_string_tag_symbol, symbolToStringTag, Symbol.toStringTag) \
+  V(unscopables_symbol, symbolUnscopables, Symbol.unscopables)
+
+// Heap roots that are known to be immortal immovable, for which we can safely
+// skip write barriers. This list is not complete and has omissions.
+#define IMMORTAL_IMMOVABLE_ROOT_LIST(V) \
+  V(ByteArrayMap)                       \
+  V(FreeSpaceMap)                       \
+  V(OnePointerFillerMap)                \
+  V(TwoPointerFillerMap)                \
+  V(UndefinedValue)                     \
+  V(TheHoleValue)                       \
+  V(NullValue)                          \
+  V(TrueValue)                          \
+  V(FalseValue)                         \
+  V(UninitializedValue)                 \
+  V(CellMap)                            \
+  V(GlobalPropertyCellMap)              \
+  V(SharedFunctionInfoMap)              \
+  V(MetaMap)                            \
+  V(HeapNumberMap)                      \
+  V(MutableHeapNumberMap)               \
+  V(NativeContextMap)                   \
+  V(FixedArrayMap)                      \
+  V(CodeMap)                            \
+  V(ScopeInfoMap)                       \
+  V(FixedCOWArrayMap)                   \
+  V(FixedDoubleArrayMap)                \
+  V(ConstantPoolArrayMap)               \
+  V(WeakCellMap)                        \
+  V(NoInterceptorResultSentinel)        \
+  V(HashTableMap)                       \
+  V(OrderedHashTableMap)                \
+  V(EmptyFixedArray)                    \
+  V(EmptyByteArray)                     \
+  V(EmptyDescriptorArray)               \
+  V(EmptyConstantPoolArray)             \
+  V(ArgumentsMarker)                    \
+  V(SymbolMap)                          \
+  V(SloppyArgumentsElementsMap)         \
+  V(FunctionContextMap)                 \
+  V(CatchContextMap)                    \
+  V(WithContextMap)                     \
+  V(BlockContextMap)                    \
+  V(ModuleContextMap)                   \
+  V(ScriptContextMap)                   \
+  V(UndefinedMap)                       \
+  V(TheHoleMap)                         \
+  V(NullMap)                            \
+  V(BooleanMap)                         \
+  V(UninitializedMap)                   \
+  V(ArgumentsMarkerMap)                 \
+  V(JSMessageObjectMap)                 \
+  V(ForeignMap)                         \
+  V(NeanderMap)                         \
+  PRIVATE_SYMBOL_LIST(V)
 
 // Forward declarations.
 class HeapStats;
@@ -538,6 +566,10 @@
   // jslimit_/real_jslimit_ variable in the StackGuard.
   void SetStackLimits();
 
+  // Notifies the heap that is ok to start marking or other activities that
+  // should not happen during deserialization.
+  void NotifyDeserializationComplete();
+
   // Returns whether SetUp has been called.
   bool HasBeenSetUp();
 
@@ -552,6 +584,7 @@
   int MaxSemiSpaceSize() { return max_semi_space_size_; }
   int ReservedSemiSpaceSize() { return reserved_semispace_size_; }
   int InitialSemiSpaceSize() { return initial_semispace_size_; }
+  int TargetSemiSpaceSize() { return target_semispace_size_; }
   intptr_t MaxOldGenerationSize() { return max_old_generation_size_; }
   intptr_t MaxExecutableSize() { return max_executable_size_; }
 
@@ -734,7 +767,7 @@
   bool IsHeapIterable();
 
   // Notify the heap that a context has been disposed.
-  int NotifyContextDisposed();
+  int NotifyContextDisposed(bool dependant_context);
 
   inline void increment_scan_on_scavenge_pages() {
     scan_on_scavenge_pages_++;
@@ -783,6 +816,16 @@
   INTERNALIZED_STRING_LIST(STRING_ACCESSOR)
 #undef STRING_ACCESSOR
 
+#define SYMBOL_ACCESSOR(name) \
+  Symbol* name() { return Symbol::cast(roots_[k##name##RootIndex]); }
+  PRIVATE_SYMBOL_LIST(SYMBOL_ACCESSOR)
+#undef SYMBOL_ACCESSOR
+
+#define SYMBOL_ACCESSOR(name, varname, description) \
+  Symbol* name() { return Symbol::cast(roots_[k##name##RootIndex]); }
+  PUBLIC_SYMBOL_LIST(SYMBOL_ACCESSOR)
+#undef SYMBOL_ACCESSOR
+
   // The hidden_string is special because it is the empty string, but does
   // not match the empty string.
   String* hidden_string() { return hidden_string_; }
@@ -812,6 +855,11 @@
     return encountered_weak_collections_;
   }
 
+  void set_encountered_weak_cells(Object* weak_cell) {
+    encountered_weak_cells_ = weak_cell;
+  }
+  Object* encountered_weak_cells() const { return encountered_weak_cells_; }
+
   // Number of mark-sweeps.
   unsigned int ms_count() { return ms_count_; }
 
@@ -899,6 +947,8 @@
     return reinterpret_cast<Address*>(&roots_[kStoreBufferTopRootIndex]);
   }
 
+  static bool RootIsImmortalImmovable(int root_index);
+
 #ifdef VERIFY_HEAP
   // Verify the heap is in its normal state before or after a GC.
   void Verify();
@@ -985,7 +1035,16 @@
 
   // Support for partial snapshots.  After calling this we have a linear
   // space to write objects in each space.
-  void ReserveSpace(int* sizes, Address* addresses);
+  struct Chunk {
+    uint32_t size;
+    Address start;
+    Address end;
+  };
+
+  typedef List<Chunk> Reservation;
+
+  // Returns false if not able to reserve.
+  bool ReserveSpace(Reservation* reservations);
 
   //
   // Support for the API.
@@ -1048,6 +1107,7 @@
   void DisableInlineAllocation();
 
   // Implements the corresponding V8 API function.
+  bool IdleNotification(double deadline_in_seconds);
   bool IdleNotification(int idle_time_in_ms);
 
   // Declare all the root indices.  This defines the root list order.
@@ -1060,6 +1120,14 @@
     INTERNALIZED_STRING_LIST(STRING_INDEX_DECLARATION)
 #undef STRING_DECLARATION
 
+#define SYMBOL_INDEX_DECLARATION(name) k##name##RootIndex,
+    PRIVATE_SYMBOL_LIST(SYMBOL_INDEX_DECLARATION)
+#undef SYMBOL_INDEX_DECLARATION
+
+#define SYMBOL_INDEX_DECLARATION(name, varname, description) k##name##RootIndex,
+    PUBLIC_SYMBOL_LIST(SYMBOL_INDEX_DECLARATION)
+#undef SYMBOL_INDEX_DECLARATION
+
 // Utility type maps
 #define DECLARE_STRUCT_MAP(NAME, Name, name) k##Name##MapRootIndex,
     STRUCT_LIST(DECLARE_STRUCT_MAP)
@@ -1074,6 +1142,8 @@
     kSmiRootsStart = kStringTableRootIndex + 1
   };
 
+  Object* root(RootListIndex index) { return roots_[index]; }
+
   STATIC_ASSERT(kUndefinedValueRootIndex ==
                 Internals::kUndefinedValueRootIndex);
   STATIC_ASSERT(kNullValueRootIndex == Internals::kNullValueRootIndex);
@@ -1129,6 +1199,7 @@
 
   inline void IncrementYoungSurvivorsCounter(int survived) {
     DCHECK(survived >= 0);
+    survived_last_scavenge_ = survived;
     survived_since_last_expansion_ += survived;
   }
 
@@ -1227,6 +1298,8 @@
 
   int gc_count() const { return gc_count_; }
 
+  bool RecentIdleNotificationHappened();
+
   // Completely clear the Instanceof cache (to stop it keeping objects alive
   // around a GC).
   inline void CompletelyClearInstanceofCache();
@@ -1364,6 +1437,8 @@
   inline void OnMoveEvent(HeapObject* target, HeapObject* source,
                           int size_in_bytes);
 
+  bool deserialization_complete() const { return deserialization_complete_; }
+
  protected:
   // Methods made available to tests.
 
@@ -1429,7 +1504,10 @@
   int reserved_semispace_size_;
   int max_semi_space_size_;
   int initial_semispace_size_;
+  int target_semispace_size_;
   intptr_t max_old_generation_size_;
+  intptr_t initial_old_generation_size_;
+  bool old_generation_size_configured_;
   intptr_t max_executable_size_;
   intptr_t maximum_committed_;
 
@@ -1437,6 +1515,9 @@
   // scavenge since last new space expansion.
   int survived_since_last_expansion_;
 
+  // ... and since the last scavenge.
+  int survived_last_scavenge_;
+
   // For keeping track on when to flush RegExp code.
   int sweep_generation_;
 
@@ -1536,6 +1617,8 @@
   // contains Smi(0) while marking is not active.
   Object* encountered_weak_collections_;
 
+  Object* encountered_weak_cells_;
+
   StoreBufferRebuilder store_buffer_rebuilder_;
 
   struct StringTypeTable {
@@ -1655,6 +1738,8 @@
     return (pretenure == TENURED) ? preferred_old_space : NEW_SPACE;
   }
 
+  HeapObject* DoubleAlignForDeserialization(HeapObject* object, int size);
+
   // Allocate an uninitialized object.  The memory is non-executable if the
   // hardware and OS allow.  This is the single choke-point for allocations
   // performed by the runtime and should not be bypassed (to extend this to
@@ -1816,6 +1901,8 @@
   // Allocate a tenured JS global property cell initialized with the hole.
   MUST_USE_RESULT AllocationResult AllocatePropertyCell();
 
+  MUST_USE_RESULT AllocationResult AllocateWeakCell(HeapObject* value);
+
   // Allocates a new utility object in the old generation.
   MUST_USE_RESULT AllocationResult AllocateStruct(InstanceType type);
 
@@ -1854,6 +1941,7 @@
 
   // Code to be run before and after mark-compact.
   void MarkCompactPrologue();
+  void MarkCompactEpilogue();
 
   void ProcessNativeContexts(WeakObjectRetainer* retainer);
   void ProcessArrayBuffers(WeakObjectRetainer* retainer);
@@ -1907,8 +1995,10 @@
 
   int high_survival_rate_period_length_;
   intptr_t promoted_objects_size_;
+  double promotion_ratio_;
   double promotion_rate_;
   intptr_t semi_space_copied_object_size_;
+  intptr_t previous_semi_space_copied_object_size_;
   double semi_space_copied_rate_;
   int nodes_died_in_new_space_;
   int nodes_copied_in_new_space_;
@@ -1924,11 +2014,15 @@
   // Re-visit incremental marking heuristics.
   bool IsHighSurvivalRate() { return high_survival_rate_period_length_ > 0; }
 
+  void ConfigureInitialOldGenerationSize();
+
   void SelectScavengingVisitorsTable();
 
   void IdleMarkCompact(const char* message);
 
-  void AdvanceIdleIncrementalMarking(intptr_t step_size);
+  bool TryFinalizeIdleIncrementalMarking(
+      double idle_time_in_ms, size_t size_of_objects,
+      size_t mark_compact_speed_in_bytes_per_ms);
 
   bool WorthActivatingIncrementalMarking();
 
@@ -1975,6 +2069,9 @@
   // Cumulative GC time spent in sweeping
   double sweeping_time_;
 
+  // Last time an idle notification happened
+  double last_idle_notification_time_;
+
   MarkCompactCollector mark_compact_collector_;
 
   StoreBuffer store_buffer_;
@@ -2022,7 +2119,10 @@
 
   int gc_callbacks_depth_;
 
+  bool deserialization_complete_;
+
   friend class AlwaysAllocateScope;
+  friend class Deserializer;
   friend class Factory;
   friend class GCCallbacksScope;
   friend class GCTracer;
diff --git a/src/heap/incremental-marking-inl.h b/src/heap/incremental-marking-inl.h
index 5258c5c..496e02d 100644
--- a/src/heap/incremental-marking-inl.h
+++ b/src/heap/incremental-marking-inl.h
@@ -103,13 +103,13 @@
     }
   }
 
-  marking_deque_.UnshiftGrey(obj);
+  heap_->mark_compact_collector()->marking_deque()->UnshiftGrey(obj);
 }
 
 
 void IncrementalMarking::WhiteToGreyAndPush(HeapObject* obj, MarkBit mark_bit) {
   Marking::WhiteToGrey(mark_bit);
-  marking_deque_.PushGrey(obj);
+  heap_->mark_compact_collector()->marking_deque()->PushGrey(obj);
 }
 }
 }  // namespace v8::internal
diff --git a/src/heap/incremental-marking.cc b/src/heap/incremental-marking.cc
index d72423a..aadd17c 100644
--- a/src/heap/incremental-marking.cc
+++ b/src/heap/incremental-marking.cc
@@ -19,19 +19,16 @@
 IncrementalMarking::IncrementalMarking(Heap* heap)
     : heap_(heap),
       state_(STOPPED),
-      marking_deque_memory_(NULL),
-      marking_deque_memory_committed_(false),
       steps_count_(0),
       old_generation_space_available_at_start_of_incremental_(0),
       old_generation_space_used_at_start_of_incremental_(0),
       should_hurry_(false),
       marking_speed_(0),
       allocated_(0),
+      idle_marking_delay_counter_(0),
       no_marking_scope_depth_(0),
-      unscanned_bytes_of_large_object_(0) {}
-
-
-void IncrementalMarking::TearDown() { delete marking_deque_memory_; }
+      unscanned_bytes_of_large_object_(0),
+      was_activated_(false) {}
 
 
 void IncrementalMarking::RecordWriteSlow(HeapObject* obj, Object** slot,
@@ -194,11 +191,12 @@
                                 HeapObject::RawField(object, end_offset));
         start_offset = end_offset;
         end_offset = Min(object_size, end_offset + kProgressBarScanningChunk);
-        scan_until_end = heap->incremental_marking()->marking_deque()->IsFull();
+        scan_until_end =
+            heap->mark_compact_collector()->marking_deque()->IsFull();
       } while (scan_until_end && start_offset < object_size);
       chunk->set_progress_bar(start_offset);
       if (start_offset < object_size) {
-        heap->incremental_marking()->marking_deque()->UnshiftGrey(object);
+        heap->mark_compact_collector()->marking_deque()->UnshiftGrey(object);
         heap->incremental_marking()->NotifyIncompleteScanOfObject(
             object_size - (start_offset - already_scanned_offset));
       }
@@ -426,6 +424,9 @@
 }
 
 
+bool IncrementalMarking::WasActivated() { return was_activated_; }
+
+
 bool IncrementalMarking::WorthActivating() {
 #ifndef DEBUG
   static const intptr_t kActivationThreshold = 8 * MB;
@@ -439,8 +440,8 @@
   // 3) when we are currently not serializing or deserializing the heap.
   return FLAG_incremental_marking && FLAG_incremental_marking_steps &&
          heap_->gc_state() == Heap::NOT_IN_GC &&
+         heap_->deserialization_complete() &&
          !heap_->isolate()->serializer_enabled() &&
-         heap_->isolate()->IsInitialized() &&
          heap_->PromotedSpaceSizeOfObjects() > kActivationThreshold;
 }
 
@@ -481,32 +482,6 @@
 }
 
 
-void IncrementalMarking::EnsureMarkingDequeIsCommitted() {
-  if (marking_deque_memory_ == NULL) {
-    marking_deque_memory_ = new base::VirtualMemory(4 * MB);
-  }
-  if (!marking_deque_memory_committed_) {
-    bool success = marking_deque_memory_->Commit(
-        reinterpret_cast<Address>(marking_deque_memory_->address()),
-        marking_deque_memory_->size(),
-        false);  // Not executable.
-    CHECK(success);
-    marking_deque_memory_committed_ = true;
-  }
-}
-
-
-void IncrementalMarking::UncommitMarkingDeque() {
-  if (state_ == STOPPED && marking_deque_memory_committed_) {
-    bool success = marking_deque_memory_->Uncommit(
-        reinterpret_cast<Address>(marking_deque_memory_->address()),
-        marking_deque_memory_->size());
-    CHECK(success);
-    marking_deque_memory_committed_ = false;
-  }
-}
-
-
 void IncrementalMarking::Start(CompactionFlag flag) {
   if (FLAG_trace_incremental_marking) {
     PrintF("[IncrementalMarking] Start\n");
@@ -516,10 +491,11 @@
   DCHECK(state_ == STOPPED);
   DCHECK(heap_->gc_state() == Heap::NOT_IN_GC);
   DCHECK(!heap_->isolate()->serializer_enabled());
-  DCHECK(heap_->isolate()->IsInitialized());
 
   ResetStepCounters();
 
+  was_activated_ = true;
+
   if (!heap_->mark_compact_collector()->sweeping_in_progress()) {
     StartMarking(flag);
   } else {
@@ -550,13 +526,7 @@
 
   PatchIncrementalMarkingRecordWriteStubs(heap_, mode);
 
-  EnsureMarkingDequeIsCommitted();
-
-  // Initialize marking stack.
-  Address addr = static_cast<Address>(marking_deque_memory_->address());
-  size_t size = marking_deque_memory_->size();
-  if (FLAG_force_marking_deque_overflows) size = 64 * kPointerSize;
-  marking_deque_.Initialize(addr, addr + size);
+  heap_->mark_compact_collector()->EnsureMarkingDequeIsCommittedAndInitialize();
 
   ActivateIncrementalWriteBarrier();
 
@@ -602,10 +572,12 @@
 void IncrementalMarking::UpdateMarkingDequeAfterScavenge() {
   if (!IsMarking()) return;
 
-  int current = marking_deque_.bottom();
-  int mask = marking_deque_.mask();
-  int limit = marking_deque_.top();
-  HeapObject** array = marking_deque_.array();
+  MarkingDeque* marking_deque =
+      heap_->mark_compact_collector()->marking_deque();
+  int current = marking_deque->bottom();
+  int mask = marking_deque->mask();
+  int limit = marking_deque->top();
+  HeapObject** array = marking_deque->array();
   int new_top = current;
 
   Map* filler_map = heap_->one_pointer_filler_map();
@@ -620,7 +592,7 @@
         HeapObject* dest = map_word.ToForwardingAddress();
         array[new_top] = dest;
         new_top = ((new_top + 1) & mask);
-        DCHECK(new_top != marking_deque_.bottom());
+        DCHECK(new_top != marking_deque->bottom());
 #ifdef DEBUG
         MarkBit mark_bit = Marking::MarkBitFrom(obj);
         DCHECK(Marking::IsGrey(mark_bit) ||
@@ -632,7 +604,7 @@
       // stack when we perform in place array shift.
       array[new_top] = obj;
       new_top = ((new_top + 1) & mask);
-      DCHECK(new_top != marking_deque_.bottom());
+      DCHECK(new_top != marking_deque->bottom());
 #ifdef DEBUG
       MarkBit mark_bit = Marking::MarkBitFrom(obj);
       MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
@@ -643,7 +615,7 @@
 #endif
     }
   }
-  marking_deque_.set_top(new_top);
+  marking_deque->set_top(new_top);
 }
 
 
@@ -670,8 +642,10 @@
 intptr_t IncrementalMarking::ProcessMarkingDeque(intptr_t bytes_to_process) {
   intptr_t bytes_processed = 0;
   Map* filler_map = heap_->one_pointer_filler_map();
-  while (!marking_deque_.IsEmpty() && bytes_processed < bytes_to_process) {
-    HeapObject* obj = marking_deque_.Pop();
+  MarkingDeque* marking_deque =
+      heap_->mark_compact_collector()->marking_deque();
+  while (!marking_deque->IsEmpty() && bytes_processed < bytes_to_process) {
+    HeapObject* obj = marking_deque->Pop();
 
     // Explicitly skip one word fillers. Incremental markbit patterns are
     // correct only for objects that occupy at least two words.
@@ -692,8 +666,10 @@
 
 void IncrementalMarking::ProcessMarkingDeque() {
   Map* filler_map = heap_->one_pointer_filler_map();
-  while (!marking_deque_.IsEmpty()) {
-    HeapObject* obj = marking_deque_.Pop();
+  MarkingDeque* marking_deque =
+      heap_->mark_compact_collector()->marking_deque();
+  while (!marking_deque->IsEmpty()) {
+    HeapObject* obj = marking_deque->Pop();
 
     // Explicitly skip one word fillers. Incremental markbit patterns are
     // correct only for objects that occupy at least two words.
@@ -793,7 +769,7 @@
   PatchIncrementalMarkingRecordWriteStubs(heap_,
                                           RecordWriteStub::STORE_BUFFER_ONLY);
   DeactivateIncrementalWriteBarrier();
-  DCHECK(marking_deque_.IsEmpty());
+  DCHECK(heap_->mark_compact_collector()->marking_deque()->IsEmpty());
   heap_->isolate()->stack_guard()->ClearGC();
 }
 
@@ -815,6 +791,9 @@
 }
 
 
+void IncrementalMarking::Epilogue() { was_activated_ = false; }
+
+
 void IncrementalMarking::OldSpaceStep(intptr_t allocated) {
   if (IsStopped() && ShouldActivate()) {
     // TODO(hpayer): Let's play safe for now, but compaction should be
@@ -892,24 +871,33 @@
 }
 
 
-void IncrementalMarking::Step(intptr_t allocated_bytes, CompletionAction action,
-                              bool force_marking) {
+intptr_t IncrementalMarking::Step(intptr_t allocated_bytes,
+                                  CompletionAction action,
+                                  ForceMarkingAction marking,
+                                  ForceCompletionAction completion) {
   if (heap_->gc_state() != Heap::NOT_IN_GC || !FLAG_incremental_marking ||
       !FLAG_incremental_marking_steps ||
       (state_ != SWEEPING && state_ != MARKING)) {
-    return;
+    return 0;
   }
 
   allocated_ += allocated_bytes;
 
-  if (!force_marking && allocated_ < kAllocatedThreshold &&
+  if (marking == DO_NOT_FORCE_MARKING && allocated_ < kAllocatedThreshold &&
       write_barriers_invoked_since_last_step_ <
           kWriteBarriersInvokedThreshold) {
-    return;
+    return 0;
   }
 
-  if (state_ == MARKING && no_marking_scope_depth_ > 0) return;
+  // If an idle notification happened recently, we delay marking steps.
+  if (marking == DO_NOT_FORCE_MARKING &&
+      heap_->RecentIdleNotificationHappened()) {
+    return 0;
+  }
 
+  if (state_ == MARKING && no_marking_scope_depth_ > 0) return 0;
+
+  intptr_t bytes_processed = 0;
   {
     HistogramTimerScope incremental_marking_scope(
         heap_->isolate()->counters()->gc_incremental_marking());
@@ -930,11 +918,11 @@
     write_barriers_invoked_since_last_step_ = 0;
 
     bytes_scanned_ += bytes_to_process;
-    intptr_t bytes_processed = 0;
 
     if (state_ == SWEEPING) {
       if (heap_->mark_compact_collector()->sweeping_in_progress() &&
-          heap_->mark_compact_collector()->IsSweepingCompleted()) {
+          (heap_->mark_compact_collector()->IsSweepingCompleted() ||
+           !FLAG_concurrent_sweeping)) {
         heap_->mark_compact_collector()->EnsureSweepingCompleted();
       }
       if (!heap_->mark_compact_collector()->sweeping_in_progress()) {
@@ -943,7 +931,14 @@
       }
     } else if (state_ == MARKING) {
       bytes_processed = ProcessMarkingDeque(bytes_to_process);
-      if (marking_deque_.IsEmpty()) MarkingComplete(action);
+      if (heap_->mark_compact_collector()->marking_deque()->IsEmpty()) {
+        if (completion == FORCE_COMPLETION ||
+            IsIdleMarkingDelayCounterLimitReached()) {
+          MarkingComplete(action);
+        } else {
+          IncrementIdleMarkingDelayCounter();
+        }
+      }
     }
 
     steps_count_++;
@@ -959,6 +954,7 @@
     // process the marking deque.
     heap_->tracer()->AddIncrementalMarkingStep(duration, bytes_processed);
   }
+  return bytes_processed;
 }
 
 
@@ -978,5 +974,20 @@
 int64_t IncrementalMarking::SpaceLeftInOldSpace() {
   return heap_->MaxOldGenerationSize() - heap_->PromotedSpaceSizeOfObjects();
 }
+
+
+bool IncrementalMarking::IsIdleMarkingDelayCounterLimitReached() {
+  return idle_marking_delay_counter_ > kMaxIdleMarkingDelayCounter;
+}
+
+
+void IncrementalMarking::IncrementIdleMarkingDelayCounter() {
+  idle_marking_delay_counter_++;
+}
+
+
+void IncrementalMarking::ClearIdleMarkingDelayCounter() {
+  idle_marking_delay_counter_ = 0;
+}
 }
 }  // namespace v8::internal
diff --git a/src/heap/incremental-marking.h b/src/heap/incremental-marking.h
index e4a8e97..56c5a24 100644
--- a/src/heap/incremental-marking.h
+++ b/src/heap/incremental-marking.h
@@ -20,12 +20,14 @@
 
   enum CompletionAction { GC_VIA_STACK_GUARD, NO_GC_VIA_STACK_GUARD };
 
+  enum ForceMarkingAction { FORCE_MARKING, DO_NOT_FORCE_MARKING };
+
+  enum ForceCompletionAction { FORCE_COMPLETION, DO_NOT_FORCE_COMPLETION };
+
   explicit IncrementalMarking(Heap* heap);
 
   static void Initialize();
 
-  void TearDown();
-
   State state() {
     DCHECK(state_ == STOPPED || FLAG_incremental_marking);
     return state_;
@@ -46,6 +48,8 @@
 
   bool ShouldActivate();
 
+  bool WasActivated();
+
   enum CompactionFlag { ALLOW_COMPACTION, PREVENT_COMPACTION };
 
   void Start(CompactionFlag flag = ALLOW_COMPACTION);
@@ -64,6 +68,8 @@
 
   void MarkingComplete(CompletionAction action);
 
+  void Epilogue();
+
   // It's hard to know how much work the incremental marker should do to make
   // progress in the face of the mutator creating new work for it.  We start
   // of at a moderate rate of work and gradually increase the speed of the
@@ -83,10 +89,15 @@
   static const intptr_t kMarkingSpeedAccelleration = 2;
   static const intptr_t kMaxMarkingSpeed = 1000;
 
+  // This is the upper bound for how many times we allow finalization of
+  // incremental marking to be postponed.
+  static const size_t kMaxIdleMarkingDelayCounter = 3;
+
   void OldSpaceStep(intptr_t allocated);
 
-  void Step(intptr_t allocated, CompletionAction action,
-            bool force_marking = false);
+  intptr_t Step(intptr_t allocated, CompletionAction action,
+                ForceMarkingAction marking = DO_NOT_FORCE_MARKING,
+                ForceCompletionAction completion = FORCE_COMPLETION);
 
   inline void RestartIfNotMarking() {
     if (state_ == COMPLETE) {
@@ -135,8 +146,6 @@
     SetNewSpacePageFlags(chunk, IsMarking());
   }
 
-  MarkingDeque* marking_deque() { return &marking_deque_; }
-
   bool IsCompacting() { return IsMarking() && is_compacting_; }
 
   void ActivateGeneratedStub(Code* stub);
@@ -159,12 +168,14 @@
 
   void LeaveNoMarkingScope() { no_marking_scope_depth_--; }
 
-  void UncommitMarkingDeque();
-
   void NotifyIncompleteScanOfObject(int unscanned_bytes) {
     unscanned_bytes_of_large_object_ = unscanned_bytes;
   }
 
+  void ClearIdleMarkingDelayCounter();
+
+  bool IsIdleMarkingDelayCounterLimitReached();
+
  private:
   int64_t SpaceLeftInOldSpace();
 
@@ -187,23 +198,19 @@
 
   static void SetNewSpacePageFlags(NewSpacePage* chunk, bool is_marking);
 
-  void EnsureMarkingDequeIsCommitted();
-
   INLINE(void ProcessMarkingDeque());
 
   INLINE(intptr_t ProcessMarkingDeque(intptr_t bytes_to_process));
 
   INLINE(void VisitObject(Map* map, HeapObject* obj, int size));
 
+  void IncrementIdleMarkingDelayCounter();
+
   Heap* heap_;
 
   State state_;
   bool is_compacting_;
 
-  base::VirtualMemory* marking_deque_memory_;
-  bool marking_deque_memory_committed_;
-  MarkingDeque marking_deque_;
-
   int steps_count_;
   int64_t old_generation_space_available_at_start_of_incremental_;
   int64_t old_generation_space_used_at_start_of_incremental_;
@@ -213,11 +220,14 @@
   intptr_t bytes_scanned_;
   intptr_t allocated_;
   intptr_t write_barriers_invoked_since_last_step_;
+  size_t idle_marking_delay_counter_;
 
   int no_marking_scope_depth_;
 
   int unscanned_bytes_of_large_object_;
 
+  bool was_activated_;
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(IncrementalMarking);
 };
 }
diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc
index 9f9a658..c9a310a 100644
--- a/src/heap/mark-compact.cc
+++ b/src/heap/mark-compact.cc
@@ -18,7 +18,6 @@
 #include "src/heap/objects-visiting.h"
 #include "src/heap/objects-visiting-inl.h"
 #include "src/heap/spaces-inl.h"
-#include "src/heap/sweeper-thread.h"
 #include "src/heap-profiler.h"
 #include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
@@ -48,9 +47,11 @@
       was_marked_incrementally_(false),
       sweeping_in_progress_(false),
       pending_sweeper_jobs_semaphore_(0),
-      sequential_sweeping_(false),
+      evacuation_(false),
       migration_slots_buffer_(NULL),
       heap_(heap),
+      marking_deque_memory_(NULL),
+      marking_deque_memory_committed_(false),
       code_flusher_(NULL),
       have_code_to_deoptimize_(false) {
 }
@@ -228,110 +229,16 @@
 #endif  // VERIFY_HEAP
 
 
-#ifdef DEBUG
-class VerifyNativeContextSeparationVisitor : public ObjectVisitor {
- public:
-  VerifyNativeContextSeparationVisitor() : current_native_context_(NULL) {}
-
-  void VisitPointers(Object** start, Object** end) {
-    for (Object** current = start; current < end; current++) {
-      if ((*current)->IsHeapObject()) {
-        HeapObject* object = HeapObject::cast(*current);
-        if (object->IsString()) continue;
-        switch (object->map()->instance_type()) {
-          case JS_FUNCTION_TYPE:
-            CheckContext(JSFunction::cast(object)->context());
-            break;
-          case JS_GLOBAL_PROXY_TYPE:
-            CheckContext(JSGlobalProxy::cast(object)->native_context());
-            break;
-          case JS_GLOBAL_OBJECT_TYPE:
-          case JS_BUILTINS_OBJECT_TYPE:
-            CheckContext(GlobalObject::cast(object)->native_context());
-            break;
-          case JS_ARRAY_TYPE:
-          case JS_DATE_TYPE:
-          case JS_OBJECT_TYPE:
-          case JS_REGEXP_TYPE:
-            VisitPointer(HeapObject::RawField(object, JSObject::kMapOffset));
-            break;
-          case MAP_TYPE:
-            VisitPointer(HeapObject::RawField(object, Map::kPrototypeOffset));
-            VisitPointer(HeapObject::RawField(object, Map::kConstructorOffset));
-            break;
-          case FIXED_ARRAY_TYPE:
-            if (object->IsContext()) {
-              CheckContext(object);
-            } else {
-              FixedArray* array = FixedArray::cast(object);
-              int length = array->length();
-              // Set array length to zero to prevent cycles while iterating
-              // over array bodies, this is easier than intrusive marking.
-              array->set_length(0);
-              array->IterateBody(FIXED_ARRAY_TYPE, FixedArray::SizeFor(length),
-                                 this);
-              array->set_length(length);
-            }
-            break;
-          case CELL_TYPE:
-          case JS_PROXY_TYPE:
-          case JS_VALUE_TYPE:
-          case TYPE_FEEDBACK_INFO_TYPE:
-            object->Iterate(this);
-            break;
-          case DECLARED_ACCESSOR_INFO_TYPE:
-          case EXECUTABLE_ACCESSOR_INFO_TYPE:
-          case BYTE_ARRAY_TYPE:
-          case CALL_HANDLER_INFO_TYPE:
-          case CODE_TYPE:
-          case FIXED_DOUBLE_ARRAY_TYPE:
-          case HEAP_NUMBER_TYPE:
-          case MUTABLE_HEAP_NUMBER_TYPE:
-          case INTERCEPTOR_INFO_TYPE:
-          case ODDBALL_TYPE:
-          case SCRIPT_TYPE:
-          case SHARED_FUNCTION_INFO_TYPE:
-            break;
-          default:
-            UNREACHABLE();
-        }
-      }
-    }
-  }
-
- private:
-  void CheckContext(Object* context) {
-    if (!context->IsContext()) return;
-    Context* native_context = Context::cast(context)->native_context();
-    if (current_native_context_ == NULL) {
-      current_native_context_ = native_context;
-    } else {
-      CHECK_EQ(current_native_context_, native_context);
-    }
-  }
-
-  Context* current_native_context_;
-};
-
-
-static void VerifyNativeContextSeparation(Heap* heap) {
-  HeapObjectIterator it(heap->code_space());
-
-  for (Object* object = it.Next(); object != NULL; object = it.Next()) {
-    VerifyNativeContextSeparationVisitor visitor;
-    Code::cast(object)->CodeIterateBody(&visitor);
-  }
-}
-#endif
-
-
 void MarkCompactCollector::SetUp() {
   free_list_old_data_space_.Reset(new FreeList(heap_->old_data_space()));
   free_list_old_pointer_space_.Reset(new FreeList(heap_->old_pointer_space()));
 }
 
 
-void MarkCompactCollector::TearDown() { AbortCompaction(); }
+void MarkCompactCollector::TearDown() {
+  AbortCompaction();
+  delete marking_deque_memory_;
+}
 
 
 void MarkCompactCollector::AddEvacuationCandidate(Page* p) {
@@ -396,8 +303,14 @@
 
   if (FLAG_collect_maps) ClearNonLiveReferences();
 
+  ProcessAndClearWeakCells();
+
   ClearWeakCollections();
 
+  heap_->set_encountered_weak_cells(Smi::FromInt(0));
+
+  isolate()->global_handles()->CollectPhantomCallbackData();
+
 #ifdef VERIFY_HEAP
   if (FLAG_verify_heap) {
     VerifyMarking(heap_);
@@ -406,12 +319,6 @@
 
   SweepSpaces();
 
-#ifdef DEBUG
-  if (FLAG_verify_native_context_separation) {
-    VerifyNativeContextSeparation(heap_);
-  }
-#endif
-
 #ifdef VERIFY_HEAP
   if (heap()->weak_embedded_objects_verification_enabled()) {
     VerifyWeakEmbeddedObjectsInCode();
@@ -478,7 +385,7 @@
   for (HeapObject* obj = code_iterator.Next(); obj != NULL;
        obj = code_iterator.Next()) {
     Code* code = Code::cast(obj);
-    if (!code->is_optimized_code() && !code->is_weak_stub()) continue;
+    if (!code->is_optimized_code()) continue;
     if (WillBeDeoptimized(code)) continue;
     code->VerifyEmbeddedObjectsDependency();
   }
@@ -541,7 +448,7 @@
 
  private:
   // v8::Task overrides.
-  virtual void Run() OVERRIDE {
+  void Run() OVERRIDE {
     heap_->mark_compact_collector()->SweepInParallel(space_, 0);
     heap_->mark_compact_collector()->pending_sweeper_jobs_semaphore_.Signal();
   }
@@ -556,37 +463,26 @@
 void MarkCompactCollector::StartSweeperThreads() {
   DCHECK(free_list_old_pointer_space_.get()->IsEmpty());
   DCHECK(free_list_old_data_space_.get()->IsEmpty());
-  sweeping_in_progress_ = true;
-  for (int i = 0; i < isolate()->num_sweeper_threads(); i++) {
-    isolate()->sweeper_threads()[i]->StartSweeping();
-  }
-  if (FLAG_job_based_sweeping) {
-    V8::GetCurrentPlatform()->CallOnBackgroundThread(
-        new SweeperTask(heap(), heap()->old_data_space()),
-        v8::Platform::kShortRunningTask);
-    V8::GetCurrentPlatform()->CallOnBackgroundThread(
-        new SweeperTask(heap(), heap()->old_pointer_space()),
-        v8::Platform::kShortRunningTask);
-  }
+  V8::GetCurrentPlatform()->CallOnBackgroundThread(
+      new SweeperTask(heap(), heap()->old_data_space()),
+      v8::Platform::kShortRunningTask);
+  V8::GetCurrentPlatform()->CallOnBackgroundThread(
+      new SweeperTask(heap(), heap()->old_pointer_space()),
+      v8::Platform::kShortRunningTask);
 }
 
 
 void MarkCompactCollector::EnsureSweepingCompleted() {
   DCHECK(sweeping_in_progress_ == true);
 
-  // If sweeping is not completed, we try to complete it here. If we do not
-  // have sweeper threads we have to complete since we do not have a good
-  // indicator for a swept space in that case.
-  if (!AreSweeperThreadsActivated() || !IsSweepingCompleted()) {
+  // If sweeping is not completed or not running at all, we try to complete it
+  // here.
+  if (!FLAG_concurrent_sweeping || !IsSweepingCompleted()) {
     SweepInParallel(heap()->paged_space(OLD_DATA_SPACE), 0);
     SweepInParallel(heap()->paged_space(OLD_POINTER_SPACE), 0);
   }
-
-  for (int i = 0; i < isolate()->num_sweeper_threads(); i++) {
-    isolate()->sweeper_threads()[i]->WaitForSweeperThread();
-  }
-  if (FLAG_job_based_sweeping) {
-    // Wait twice for both jobs.
+  // Wait twice for both jobs.
+  if (FLAG_concurrent_sweeping) {
     pending_sweeper_jobs_semaphore_.Wait();
     pending_sweeper_jobs_semaphore_.Wait();
   }
@@ -598,7 +494,7 @@
   heap()->paged_space(OLD_POINTER_SPACE)->ResetUnsweptFreeBytes();
 
 #ifdef VERIFY_HEAP
-  if (FLAG_verify_heap) {
+  if (FLAG_verify_heap && !evacuation()) {
     VerifyEvacuation(heap_);
   }
 #endif
@@ -606,20 +502,11 @@
 
 
 bool MarkCompactCollector::IsSweepingCompleted() {
-  for (int i = 0; i < isolate()->num_sweeper_threads(); i++) {
-    if (!isolate()->sweeper_threads()[i]->SweepingCompleted()) {
-      return false;
-    }
+  if (!pending_sweeper_jobs_semaphore_.WaitFor(
+          base::TimeDelta::FromSeconds(0))) {
+    return false;
   }
-
-  if (FLAG_job_based_sweeping) {
-    if (!pending_sweeper_jobs_semaphore_.WaitFor(
-            base::TimeDelta::FromSeconds(0))) {
-      return false;
-    }
-    pending_sweeper_jobs_semaphore_.Signal();
-  }
-
+  pending_sweeper_jobs_semaphore_.Signal();
   return true;
 }
 
@@ -643,11 +530,6 @@
 }
 
 
-bool MarkCompactCollector::AreSweeperThreadsActivated() {
-  return isolate()->sweeper_threads() != NULL || FLAG_job_based_sweeping;
-}
-
-
 void Marking::TransferMark(Address old_start, Address new_start) {
   // This is only used when resizing an object.
   DCHECK(MemoryChunk::FromAddress(old_start) ==
@@ -952,6 +834,7 @@
     heap()->incremental_marking()->Abort();
     ClearMarkbits();
     AbortWeakCollections();
+    AbortWeakCells();
     AbortCompaction();
     was_marked_incrementally_ = false;
   }
@@ -992,6 +875,8 @@
     Deoptimizer::DeoptimizeMarkedCode(isolate());
     have_code_to_deoptimize_ = false;
   }
+
+  heap_->incremental_marking()->ClearIdleMarkingDelayCounter();
 }
 
 
@@ -1328,7 +1213,6 @@
   // except the maps for the object and its possible substrings might be
   // marked.
   HeapObject* object = HeapObject::cast(*p);
-  if (!FLAG_clever_optimizations) return object;
   Map* map = object->map();
   InstanceType type = map->instance_type();
   if (!IsShortcutCandidate(type)) return object;
@@ -2132,13 +2016,18 @@
 // After: the marking stack is empty, and all objects reachable from the
 // marking stack have been marked, or are overflowed in the heap.
 void MarkCompactCollector::EmptyMarkingDeque() {
+  Map* filler_map = heap_->one_pointer_filler_map();
   while (!marking_deque_.IsEmpty()) {
     HeapObject* object = marking_deque_.Pop();
+    // Explicitly skip one word fillers. Incremental markbit patterns are
+    // correct only for objects that occupy at least two words.
+    Map* map = object->map();
+    if (map == filler_map) continue;
+
     DCHECK(object->IsHeapObject());
     DCHECK(heap()->Contains(object));
-    DCHECK(Marking::IsBlack(Marking::MarkBitFrom(object)));
+    DCHECK(!Marking::IsWhite(Marking::MarkBitFrom(object)));
 
-    Map* map = object->map();
     MarkBit map_mark = Marking::MarkBitFrom(map);
     MarkObject(map, map_mark);
 
@@ -2201,13 +2090,16 @@
 
 // Mark all objects reachable (transitively) from objects on the marking
 // stack including references only considered in the atomic marking pause.
-void MarkCompactCollector::ProcessEphemeralMarking(ObjectVisitor* visitor) {
+void MarkCompactCollector::ProcessEphemeralMarking(
+    ObjectVisitor* visitor, bool only_process_harmony_weak_collections) {
   bool work_to_do = true;
-  DCHECK(marking_deque_.IsEmpty());
+  DCHECK(marking_deque_.IsEmpty() && !marking_deque_.overflowed());
   while (work_to_do) {
-    isolate()->global_handles()->IterateObjectGroups(
-        visitor, &IsUnmarkedHeapObjectWithHeap);
-    MarkImplicitRefGroups();
+    if (!only_process_harmony_weak_collections) {
+      isolate()->global_handles()->IterateObjectGroups(
+          visitor, &IsUnmarkedHeapObjectWithHeap);
+      MarkImplicitRefGroups();
+    }
     ProcessWeakCollections();
     work_to_do = !marking_deque_.IsEmpty();
     ProcessMarkingDeque();
@@ -2233,6 +2125,43 @@
 }
 
 
+void MarkCompactCollector::EnsureMarkingDequeIsCommittedAndInitialize() {
+  if (marking_deque_memory_ == NULL) {
+    marking_deque_memory_ = new base::VirtualMemory(4 * MB);
+  }
+  if (!marking_deque_memory_committed_) {
+    bool success = marking_deque_memory_->Commit(
+        reinterpret_cast<Address>(marking_deque_memory_->address()),
+        marking_deque_memory_->size(),
+        false);  // Not executable.
+    CHECK(success);
+    marking_deque_memory_committed_ = true;
+    InitializeMarkingDeque();
+  }
+}
+
+
+void MarkCompactCollector::InitializeMarkingDeque() {
+  if (marking_deque_memory_committed_) {
+    Address addr = static_cast<Address>(marking_deque_memory_->address());
+    size_t size = marking_deque_memory_->size();
+    if (FLAG_force_marking_deque_overflows) size = 64 * kPointerSize;
+    marking_deque_.Initialize(addr, addr + size);
+  }
+}
+
+
+void MarkCompactCollector::UncommitMarkingDeque() {
+  if (marking_deque_memory_committed_) {
+    bool success = marking_deque_memory_->Uncommit(
+        reinterpret_cast<Address>(marking_deque_memory_->address()),
+        marking_deque_memory_->size());
+    CHECK(success);
+    marking_deque_memory_committed_ = false;
+  }
+}
+
+
 void MarkCompactCollector::MarkLiveObjects() {
   GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_MARK);
   double start_time = 0.0;
@@ -2244,42 +2173,21 @@
   // with the C stack limit check.
   PostponeInterruptsScope postpone(isolate());
 
-  bool incremental_marking_overflowed = false;
   IncrementalMarking* incremental_marking = heap_->incremental_marking();
   if (was_marked_incrementally_) {
-    // Finalize the incremental marking and check whether we had an overflow.
-    // Both markers use grey color to mark overflowed objects so
-    // non-incremental marker can deal with them as if overflow
-    // occured during normal marking.
-    // But incremental marker uses a separate marking deque
-    // so we have to explicitly copy its overflow state.
     incremental_marking->Finalize();
-    incremental_marking_overflowed =
-        incremental_marking->marking_deque()->overflowed();
-    incremental_marking->marking_deque()->ClearOverflowed();
   } else {
     // Abort any pending incremental activities e.g. incremental sweeping.
     incremental_marking->Abort();
+    InitializeMarkingDeque();
   }
 
 #ifdef DEBUG
   DCHECK(state_ == PREPARE_GC);
   state_ = MARK_LIVE_OBJECTS;
 #endif
-  // The to space contains live objects, a page in from space is used as a
-  // marking stack.
-  Address marking_deque_start = heap()->new_space()->FromSpacePageLow();
-  Address marking_deque_end = heap()->new_space()->FromSpacePageHigh();
-  if (FLAG_force_marking_deque_overflows) {
-    marking_deque_end = marking_deque_start + 64 * kPointerSize;
-  }
-  marking_deque_.Initialize(marking_deque_start, marking_deque_end);
-  DCHECK(!marking_deque_.overflowed());
 
-  if (incremental_marking_overflowed) {
-    // There are overflowed objects left in the heap after incremental marking.
-    marking_deque_.SetOverflowed();
-  }
+  EnsureMarkingDequeIsCommittedAndInitialize();
 
   PrepareForCodeFlushing();
 
@@ -2316,30 +2224,35 @@
 
   ProcessTopOptimizedFrame(&root_visitor);
 
-  // The objects reachable from the roots are marked, yet unreachable
-  // objects are unmarked.  Mark objects reachable due to host
-  // application specific logic or through Harmony weak maps.
-  ProcessEphemeralMarking(&root_visitor);
+  {
+    GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_WEAKCLOSURE);
 
-  // The objects reachable from the roots, weak maps or object groups
-  // are marked, yet unreachable objects are unmarked.  Mark objects
-  // reachable only from weak global handles.
-  //
-  // First we identify nonlive weak handles and mark them as pending
-  // destruction.
-  heap()->isolate()->global_handles()->IdentifyWeakHandles(
-      &IsUnmarkedHeapObject);
-  // Then we mark the objects and process the transitive closure.
-  heap()->isolate()->global_handles()->IterateWeakRoots(&root_visitor);
-  while (marking_deque_.overflowed()) {
-    RefillMarkingDeque();
-    EmptyMarkingDeque();
+    // The objects reachable from the roots are marked, yet unreachable
+    // objects are unmarked.  Mark objects reachable due to host
+    // application specific logic or through Harmony weak maps.
+    ProcessEphemeralMarking(&root_visitor, false);
+
+    // The objects reachable from the roots, weak maps or object groups
+    // are marked. Objects pointed to only by weak global handles cannot be
+    // immediately reclaimed. Instead, we have to mark them as pending and mark
+    // objects reachable from them.
+    //
+    // First we identify nonlive weak handles and mark them as pending
+    // destruction.
+    heap()->isolate()->global_handles()->IdentifyWeakHandles(
+        &IsUnmarkedHeapObject);
+    // Then we mark the objects.
+    heap()->isolate()->global_handles()->IterateWeakRoots(&root_visitor);
+    ProcessMarkingDeque();
+
+    // Repeat Harmony weak maps marking to mark unmarked objects reachable from
+    // the weak roots we just marked as pending destruction.
+    //
+    // We only process harmony collections, as all object groups have been fully
+    // processed and no weakly reachable node can discover new objects groups.
+    ProcessEphemeralMarking(&root_visitor, true);
   }
 
-  // Repeat host application specific and Harmony weak maps marking to
-  // mark unmarked objects reachable from the weak roots.
-  ProcessEphemeralMarking(&root_visitor);
-
   AfterMarking();
 
   if (FLAG_print_cumulative_gc_stat) {
@@ -2349,12 +2262,6 @@
 
 
 void MarkCompactCollector::AfterMarking() {
-  // Object literal map caches reference strings (cache keys) and maps
-  // (cache values). At this point still useful maps have already been
-  // marked. Mark the keys for the alive values before we process the
-  // string table.
-  ProcessMapCaches();
-
   // Prune the string table removing all strings only pointed to by the
   // string table.  Cannot use string_table() here because the string
   // table is marked.
@@ -2391,57 +2298,6 @@
 }
 
 
-void MarkCompactCollector::ProcessMapCaches() {
-  Object* raw_context = heap()->native_contexts_list();
-  while (raw_context != heap()->undefined_value()) {
-    Context* context = reinterpret_cast<Context*>(raw_context);
-    if (IsMarked(context)) {
-      HeapObject* raw_map_cache =
-          HeapObject::cast(context->get(Context::MAP_CACHE_INDEX));
-      // A map cache may be reachable from the stack. In this case
-      // it's already transitively marked and it's too late to clean
-      // up its parts.
-      if (!IsMarked(raw_map_cache) &&
-          raw_map_cache != heap()->undefined_value()) {
-        MapCache* map_cache = reinterpret_cast<MapCache*>(raw_map_cache);
-        int existing_elements = map_cache->NumberOfElements();
-        int used_elements = 0;
-        for (int i = MapCache::kElementsStartIndex; i < map_cache->length();
-             i += MapCache::kEntrySize) {
-          Object* raw_key = map_cache->get(i);
-          if (raw_key == heap()->undefined_value() ||
-              raw_key == heap()->the_hole_value())
-            continue;
-          STATIC_ASSERT(MapCache::kEntrySize == 2);
-          Object* raw_map = map_cache->get(i + 1);
-          if (raw_map->IsHeapObject() && IsMarked(raw_map)) {
-            ++used_elements;
-          } else {
-            // Delete useless entries with unmarked maps.
-            DCHECK(raw_map->IsMap());
-            map_cache->set_the_hole(i);
-            map_cache->set_the_hole(i + 1);
-          }
-        }
-        if (used_elements == 0) {
-          context->set(Context::MAP_CACHE_INDEX, heap()->undefined_value());
-        } else {
-          // Note: we don't actually shrink the cache here to avoid
-          // extra complexity during GC. We rely on subsequent cache
-          // usages (EnsureCapacity) to do this.
-          map_cache->ElementsRemoved(existing_elements - used_elements);
-          MarkBit map_cache_markbit = Marking::MarkBitFrom(map_cache);
-          MarkObject(map_cache, map_cache_markbit);
-        }
-      }
-    }
-    // Move to next element in the list.
-    raw_context = context->get(Context::NEXT_CONTEXT_LINK);
-  }
-  ProcessMarkingDeque();
-}
-
-
 void MarkCompactCollector::ClearNonLiveReferences() {
   // Iterate over the map space, setting map transitions that go from
   // a marked map to an unmarked map to null transitions.  This action
@@ -2639,13 +2495,14 @@
 
   // Note that we never eliminate a transition array, though we might right-trim
   // such that number_of_transitions() == 0. If this assumption changes,
-  // TransitionArray::CopyInsert() will need to deal with the case that a
-  // transition array disappeared during GC.
-  int trim = t->number_of_transitions() - transition_index;
+  // TransitionArray::Insert() will need to deal with the case that a transition
+  // array disappeared during GC.
+  int trim = t->number_of_transitions_storage() - transition_index;
   if (trim > 0) {
     heap_->RightTrimFixedArray<Heap::FROM_GC>(
         t, t->IsSimpleTransition() ? trim
                                    : trim * TransitionArray::kTransitionSize);
+    t->SetNumberOfTransitions(transition_index);
   }
   DCHECK(map->HasTransitionArray());
 }
@@ -2688,34 +2545,12 @@
 }
 
 
-void MarkCompactCollector::ClearDependentICList(Object* head) {
-  Object* current = head;
-  Object* undefined = heap()->undefined_value();
-  while (current != undefined) {
-    Code* code = Code::cast(current);
-    if (IsMarked(code)) {
-      DCHECK(code->is_weak_stub());
-      IC::InvalidateMaps(code);
-    }
-    current = code->next_code_link();
-    code->set_next_code_link(undefined);
-  }
-}
-
-
 void MarkCompactCollector::ClearDependentCode(DependentCode* entries) {
   DisallowHeapAllocation no_allocation;
   DependentCode::GroupStartIndexes starts(entries);
   int number_of_entries = starts.number_of_entries();
   if (number_of_entries == 0) return;
-  int g = DependentCode::kWeakICGroup;
-  if (starts.at(g) != starts.at(g + 1)) {
-    int i = starts.at(g);
-    DCHECK(i + 1 == starts.at(g + 1));
-    Object* head = entries->object_at(i);
-    ClearDependentICList(head);
-  }
-  g = DependentCode::kWeakCodeGroup;
+  int g = DependentCode::kWeakCodeGroup;
   for (int i = starts.at(g); i < starts.at(g + 1); i++) {
     // If the entry is compilation info then the map must be alive,
     // and ClearDependentCode shouldn't be called.
@@ -2737,34 +2572,17 @@
 int MarkCompactCollector::ClearNonLiveDependentCodeInGroup(
     DependentCode* entries, int group, int start, int end, int new_start) {
   int survived = 0;
-  if (group == DependentCode::kWeakICGroup) {
-    // Dependent weak IC stubs form a linked list and only the head is stored
-    // in the dependent code array.
-    if (start != end) {
-      DCHECK(start + 1 == end);
-      Object* old_head = entries->object_at(start);
-      MarkCompactWeakObjectRetainer retainer;
-      Object* head = VisitWeakList<Code>(heap(), old_head, &retainer);
-      entries->set_object_at(new_start, head);
-      Object** slot = entries->slot_at(new_start);
-      RecordSlot(slot, slot, head);
-      // We do not compact this group even if the head is undefined,
-      // more dependent ICs are likely to be added later.
-      survived = 1;
-    }
-  } else {
-    for (int i = start; i < end; i++) {
-      Object* obj = entries->object_at(i);
-      DCHECK(obj->IsCode() || IsMarked(obj));
-      if (IsMarked(obj) &&
-          (!obj->IsCode() || !WillBeDeoptimized(Code::cast(obj)))) {
-        if (new_start + survived != i) {
-          entries->set_object_at(new_start + survived, obj);
-        }
-        Object** slot = entries->slot_at(new_start + survived);
-        RecordSlot(slot, slot, obj);
-        survived++;
+  for (int i = start; i < end; i++) {
+    Object* obj = entries->object_at(i);
+    DCHECK(obj->IsCode() || IsMarked(obj));
+    if (IsMarked(obj) &&
+        (!obj->IsCode() || !WillBeDeoptimized(Code::cast(obj)))) {
+      if (new_start + survived != i) {
+        entries->set_object_at(new_start + survived, obj);
       }
+      Object** slot = entries->slot_at(new_start + survived);
+      RecordSlot(slot, slot, obj);
+      survived++;
     }
   }
   entries->set_number_of_entries(
@@ -2857,6 +2675,39 @@
 }
 
 
+void MarkCompactCollector::ProcessAndClearWeakCells() {
+  HeapObject* undefined = heap()->undefined_value();
+  Object* weak_cell_obj = heap()->encountered_weak_cells();
+  while (weak_cell_obj != Smi::FromInt(0)) {
+    WeakCell* weak_cell = reinterpret_cast<WeakCell*>(weak_cell_obj);
+    // We do not insert cleared weak cells into the list, so the value
+    // cannot be a Smi here.
+    HeapObject* value = HeapObject::cast(weak_cell->value());
+    if (!MarkCompactCollector::IsMarked(value)) {
+      weak_cell->clear();
+    } else {
+      Object** slot = HeapObject::RawField(weak_cell, WeakCell::kValueOffset);
+      heap()->mark_compact_collector()->RecordSlot(slot, slot, value);
+    }
+    weak_cell_obj = weak_cell->next();
+    weak_cell->set_next(undefined, SKIP_WRITE_BARRIER);
+  }
+  heap()->set_encountered_weak_cells(Smi::FromInt(0));
+}
+
+
+void MarkCompactCollector::AbortWeakCells() {
+  Object* undefined = heap()->undefined_value();
+  Object* weak_cell_obj = heap()->encountered_weak_cells();
+  while (weak_cell_obj != Smi::FromInt(0)) {
+    WeakCell* weak_cell = reinterpret_cast<WeakCell*>(weak_cell_obj);
+    weak_cell_obj = weak_cell->next();
+    weak_cell->set_next(undefined, SKIP_WRITE_BARRIER);
+  }
+  heap()->set_encountered_weak_cells(Smi::FromInt(0));
+}
+
+
 void MarkCompactCollector::RecordMigratedSlot(Object* value, Address slot) {
   if (heap_->InNewSpace(value)) {
     heap_->store_buffer()->Mark(slot);
@@ -2868,7 +2719,7 @@
 }
 
 
-// We scavange new space simultaneously with sweeping. This is done in two
+// We scavenge new space simultaneously with sweeping. This is done in two
 // passes.
 //
 // The first pass migrates all alive objects from one semispace to another or
@@ -2893,12 +2744,24 @@
     Address dst_slot = dst_addr;
     DCHECK(IsAligned(size, kPointerSize));
 
+    bool may_contain_raw_values = src->MayContainRawValues();
+#if V8_DOUBLE_FIELDS_UNBOXING
+    LayoutDescriptorHelper helper(src->map());
+    bool has_only_tagged_fields = helper.all_fields_tagged();
+#endif
     for (int remaining = size / kPointerSize; remaining > 0; remaining--) {
       Object* value = Memory::Object_at(src_slot);
 
       Memory::Object_at(dst_slot) = value;
 
-      if (!src->MayContainRawValues()) {
+#if V8_DOUBLE_FIELDS_UNBOXING
+      if (!may_contain_raw_values &&
+          (has_only_tagged_fields ||
+           helper.IsTagged(static_cast<int>(src_slot - src_addr))))
+#else
+      if (!may_contain_raw_values)
+#endif
+      {
         RecordMigratedSlot(value, dst_slot);
       }
 
@@ -3011,7 +2874,8 @@
   }
 
   static inline void UpdateSlot(Heap* heap, Object** slot) {
-    Object* obj = *slot;
+    Object* obj = reinterpret_cast<Object*>(
+        base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
 
     if (!obj->IsHeapObject()) return;
 
@@ -3022,7 +2886,10 @@
       DCHECK(heap->InFromSpace(heap_obj) ||
              MarkCompactCollector::IsOnEvacuationCandidate(heap_obj));
       HeapObject* target = map_word.ToForwardingAddress();
-      *slot = target;
+      base::NoBarrier_CompareAndSwap(
+          reinterpret_cast<base::AtomicWord*>(slot),
+          reinterpret_cast<base::AtomicWord>(obj),
+          reinterpret_cast<base::AtomicWord>(target));
       DCHECK(!heap->InFromSpace(target) &&
              !MarkCompactCollector::IsOnEvacuationCandidate(target));
     }
@@ -3185,6 +3052,11 @@
       // have an emergency page and the space still has room for that.
       if (space->HasEmergencyMemory() && space->CanExpand()) {
         EvacuateLiveObjectsFromPage(p);
+        // Unlink the page from the list of pages here. We must not iterate
+        // over that page later (e.g. when scan on scavenge pages are
+        // processed). The page itself will be freed later and is still
+        // reachable from the evacuation candidates list.
+        p->Unlink();
       } else {
         // Without room for expansion evacuation is not guaranteed to succeed.
         // Pessimistically abandon unevacuated pages.
@@ -3339,7 +3211,7 @@
       }
       HeapObject* live_object = HeapObject::FromAddress(free_end);
       DCHECK(Marking::IsBlack(Marking::MarkBitFrom(live_object)));
-      Map* map = live_object->map();
+      Map* map = live_object->synchronized_map();
       int size = live_object->SizeFromMap(map);
       if (sweeping_mode == SWEEP_AND_VISIT_LIVE_OBJECTS) {
         live_object->IterateBody(map->instance_type(), size, v);
@@ -3519,6 +3391,7 @@
   {
     GCTracer::Scope gc_scope(heap()->tracer(),
                              GCTracer::Scope::MC_EVACUATE_PAGES);
+    EvacuationScope evacuation_scope(this);
     EvacuatePages();
   }
 
@@ -4194,7 +4067,6 @@
 
     switch (sweeper) {
       case CONCURRENT_SWEEPING:
-      case PARALLEL_SWEEPING:
         if (!parallel_sweeping_active) {
           if (FLAG_gc_verbose) {
             PrintF("Sweeping 0x%" V8PRIxPTR ".\n",
@@ -4245,18 +4117,6 @@
 }
 
 
-static bool ShouldStartSweeperThreads(MarkCompactCollector::SweeperType type) {
-  return type == MarkCompactCollector::PARALLEL_SWEEPING ||
-         type == MarkCompactCollector::CONCURRENT_SWEEPING;
-}
-
-
-static bool ShouldWaitForSweeperThreads(
-    MarkCompactCollector::SweeperType type) {
-  return type == MarkCompactCollector::PARALLEL_SWEEPING;
-}
-
-
 void MarkCompactCollector::SweepSpaces() {
   GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_SWEEP);
   double start_time = 0.0;
@@ -4267,10 +4127,6 @@
 #ifdef DEBUG
   state_ = SWEEP_SPACES;
 #endif
-  SweeperType how_to_sweep = CONCURRENT_SWEEPING;
-  if (FLAG_parallel_sweeping) how_to_sweep = PARALLEL_SWEEPING;
-  if (FLAG_concurrent_sweeping) how_to_sweep = CONCURRENT_SWEEPING;
-
   MoveEvacuationCandidatesToEndOfPagesList();
 
   // Noncompacting collections simply sweep the spaces to clear the mark
@@ -4282,18 +4138,13 @@
     GCTracer::Scope sweep_scope(heap()->tracer(),
                                 GCTracer::Scope::MC_SWEEP_OLDSPACE);
     {
-      SequentialSweepingScope scope(this);
-      SweepSpace(heap()->old_pointer_space(), how_to_sweep);
-      SweepSpace(heap()->old_data_space(), how_to_sweep);
+      SweepSpace(heap()->old_pointer_space(), CONCURRENT_SWEEPING);
+      SweepSpace(heap()->old_data_space(), CONCURRENT_SWEEPING);
     }
-
-    if (ShouldStartSweeperThreads(how_to_sweep)) {
+    sweeping_in_progress_ = true;
+    if (FLAG_concurrent_sweeping) {
       StartSweeperThreads();
     }
-
-    if (ShouldWaitForSweeperThreads(how_to_sweep)) {
-      EnsureSweepingCompleted();
-    }
   }
   RemoveDeadInvalidatedCode();
 
@@ -4326,6 +4177,10 @@
 
   // Deallocate evacuated candidate pages.
   ReleaseEvacuationCandidates();
+  CodeRange* code_range = heap()->isolate()->code_range();
+  if (code_range != NULL && code_range->valid()) {
+    code_range->ReserveEmergencyBlock();
+  }
 
   if (FLAG_print_cumulative_gc_stat) {
     heap_->tracer()->AddSweepingTime(base::OS::TimeCurrentMillis() -
diff --git a/src/heap/mark-compact.h b/src/heap/mark-compact.h
index c5087b4..e26e06c 100644
--- a/src/heap/mark-compact.h
+++ b/src/heap/mark-compact.h
@@ -547,7 +547,6 @@
   void EnableCodeFlushing(bool enable);
 
   enum SweeperType {
-    PARALLEL_SWEEPING,
     CONCURRENT_SWEEPING,
     SEQUENTIAL_SWEEPING
   };
@@ -641,16 +640,12 @@
 
   void RefillFreeList(PagedSpace* space);
 
-  bool AreSweeperThreadsActivated();
-
   // Checks if sweeping is in progress right now on any space.
   bool sweeping_in_progress() { return sweeping_in_progress_; }
 
-  void set_sequential_sweeping(bool sequential_sweeping) {
-    sequential_sweeping_ = sequential_sweeping;
-  }
+  void set_evacuation(bool evacuation) { evacuation_ = evacuation; }
 
-  bool sequential_sweeping() const { return sequential_sweeping_; }
+  bool evacuation() const { return evacuation_; }
 
   // Mark the global table which maps weak objects to dependent code without
   // marking its contents.
@@ -660,6 +655,14 @@
   // to artificially keep AllocationSites alive for a time.
   void MarkAllocationSite(AllocationSite* site);
 
+  MarkingDeque* marking_deque() { return &marking_deque_; }
+
+  void EnsureMarkingDequeIsCommittedAndInitialize();
+
+  void InitializeMarkingDeque();
+
+  void UncommitMarkingDeque();
+
  private:
   class SweeperTask;
 
@@ -705,7 +708,7 @@
 
   base::Semaphore pending_sweeper_jobs_semaphore_;
 
-  bool sequential_sweeping_;
+  bool evacuation_;
 
   SlotsBufferAllocator slots_buffer_allocator_;
 
@@ -769,7 +772,8 @@
   //    - Processing of objects reachable through Harmony WeakMaps.
   //    - Objects reachable due to host application logic like object groups
   //      or implicit references' groups.
-  void ProcessEphemeralMarking(ObjectVisitor* visitor);
+  void ProcessEphemeralMarking(ObjectVisitor* visitor,
+                               bool only_process_harmony_weak_collections);
 
   // If the call-site of the top optimized code was not prepared for
   // deoptimization, then treat the maps in the code as strong pointers,
@@ -787,10 +791,6 @@
   // flag on the marking stack.
   void RefillMarkingDeque();
 
-  // After reachable maps have been marked process per context object
-  // literal map caches removing unmarked entries.
-  void ProcessMapCaches();
-
   // Callback function for telling whether the object *p is an unmarked
   // heap object.
   static bool IsUnmarkedHeapObject(Object** p);
@@ -808,7 +808,6 @@
   void TrimEnumCache(Map* map, DescriptorArray* descriptors);
 
   void ClearDependentCode(DependentCode* dependent_code);
-  void ClearDependentICList(Object* head);
   void ClearNonLiveDependentCode(DependentCode* dependent_code);
   int ClearNonLiveDependentCodeInGroup(DependentCode* dependent_code, int group,
                                        int start, int end, int new_start);
@@ -827,6 +826,10 @@
   // collections when incremental marking is aborted.
   void AbortWeakCollections();
 
+
+  void ProcessAndClearWeakCells();
+  void AbortWeakCells();
+
   // -----------------------------------------------------------------------
   // Phase 2: Sweeping to clear mark bits and free non-live objects for
   // a non-compacting collection.
@@ -880,6 +883,8 @@
 #endif
 
   Heap* heap_;
+  base::VirtualMemory* marking_deque_memory_;
+  bool marking_deque_memory_committed_;
   MarkingDeque marking_deque_;
   CodeFlusher* code_flusher_;
   bool have_code_to_deoptimize_;
@@ -935,14 +940,14 @@
 };
 
 
-class SequentialSweepingScope BASE_EMBEDDED {
+class EvacuationScope BASE_EMBEDDED {
  public:
-  explicit SequentialSweepingScope(MarkCompactCollector* collector)
+  explicit EvacuationScope(MarkCompactCollector* collector)
       : collector_(collector) {
-    collector_->set_sequential_sweeping(true);
+    collector_->set_evacuation(true);
   }
 
-  ~SequentialSweepingScope() { collector_->set_sequential_sweeping(false); }
+  ~EvacuationScope() { collector_->set_evacuation(false); }
 
  private:
   MarkCompactCollector* collector_;
diff --git a/src/heap/objects-visiting-inl.h b/src/heap/objects-visiting-inl.h
index d220118..e6334f3 100644
--- a/src/heap/objects-visiting-inl.h
+++ b/src/heap/objects-visiting-inl.h
@@ -191,6 +191,8 @@
 
   table_.Register(kVisitPropertyCell, &VisitPropertyCell);
 
+  table_.Register(kVisitWeakCell, &VisitWeakCell);
+
   table_.template RegisterSpecializations<DataObjectVisitor, kVisitDataObject,
                                           kVisitDataObjectGeneric>();
 
@@ -260,12 +262,10 @@
   // when they might be keeping a Context alive, or when the heap is about
   // to be serialized.
   if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub() &&
-      (target->ic_state() == MEGAMORPHIC || target->ic_state() == GENERIC ||
-       target->ic_state() == POLYMORPHIC ||
-       (heap->flush_monomorphic_ics() && !target->is_weak_stub()) ||
+      !target->is_call_stub() &&
+      ((heap->flush_monomorphic_ics() && !target->embeds_maps_weakly()) ||
        heap->isolate()->serializer_enabled() ||
-       target->ic_age() != heap->global_ic_age() ||
-       target->is_invalidated_weak_stub())) {
+       target->ic_age() != heap->global_ic_age())) {
     ICUtility::Clear(heap->isolate(), rinfo->pc(),
                      rinfo->host()->constant_pool());
     target = Code::GetCodeFromTargetAddress(rinfo->target_address());
@@ -350,6 +350,22 @@
 
 
 template <typename StaticVisitor>
+void StaticMarkingVisitor<StaticVisitor>::VisitWeakCell(Map* map,
+                                                        HeapObject* object) {
+  Heap* heap = map->GetHeap();
+  WeakCell* weak_cell = reinterpret_cast<WeakCell*>(object);
+  Object* undefined = heap->undefined_value();
+  // Enqueue weak cell in linked list of encountered weak collections.
+  // We can ignore weak cells with cleared values because they will always
+  // contain smi zero.
+  if (weak_cell->next() == undefined && !weak_cell->cleared()) {
+    weak_cell->set_next(heap->encountered_weak_cells());
+    heap->set_encountered_weak_cells(weak_cell);
+  }
+}
+
+
+template <typename StaticVisitor>
 void StaticMarkingVisitor<StaticVisitor>::VisitAllocationSite(
     Map* map, HeapObject* object) {
   Heap* heap = map->GetHeap();
@@ -491,10 +507,7 @@
     bool is_weak_object =
         (array->get_weak_object_state() ==
              ConstantPoolArray::WEAK_OBJECTS_IN_OPTIMIZED_CODE &&
-         Code::IsWeakObjectInOptimizedCode(object)) ||
-        (array->get_weak_object_state() ==
-             ConstantPoolArray::WEAK_OBJECTS_IN_IC &&
-         Code::IsWeakObjectInIC(object));
+         Code::IsWeakObjectInOptimizedCode(object));
     if (!is_weak_object) {
       StaticVisitor::MarkObject(heap, object);
     }
diff --git a/src/heap/objects-visiting.cc b/src/heap/objects-visiting.cc
index a0fc231..20d92de 100644
--- a/src/heap/objects-visiting.cc
+++ b/src/heap/objects-visiting.cc
@@ -11,7 +11,7 @@
 
 
 StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
-    int instance_type, int instance_size) {
+    int instance_type, int instance_size, bool has_unboxed_fields) {
   if (instance_type < FIRST_NONSTRING_TYPE) {
     switch (instance_type & kStringRepresentationMask) {
       case kSeqStringTag:
@@ -33,7 +33,7 @@
 
       case kExternalStringTag:
         return GetVisitorIdForSize(kVisitDataObject, kVisitDataObjectGeneric,
-                                   instance_size);
+                                   instance_size, has_unboxed_fields);
     }
     UNREACHABLE();
   }
@@ -69,13 +69,16 @@
     case PROPERTY_CELL_TYPE:
       return kVisitPropertyCell;
 
+    case WEAK_CELL_TYPE:
+      return kVisitWeakCell;
+
     case JS_SET_TYPE:
       return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
-                                 JSSet::kSize);
+                                 JSSet::kSize, has_unboxed_fields);
 
     case JS_MAP_TYPE:
       return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
-                                 JSMap::kSize);
+                                 JSMap::kSize, has_unboxed_fields);
 
     case JS_WEAK_MAP_TYPE:
     case JS_WEAK_SET_TYPE:
@@ -89,15 +92,15 @@
 
     case JS_PROXY_TYPE:
       return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
-                                 JSProxy::kSize);
+                                 JSProxy::kSize, has_unboxed_fields);
 
     case JS_FUNCTION_PROXY_TYPE:
       return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
-                                 JSFunctionProxy::kSize);
+                                 JSFunctionProxy::kSize, has_unboxed_fields);
 
     case FOREIGN_TYPE:
       return GetVisitorIdForSize(kVisitDataObject, kVisitDataObjectGeneric,
-                                 Foreign::kSize);
+                                 Foreign::kSize, has_unboxed_fields);
 
     case SYMBOL_TYPE:
       return kVisitSymbol;
@@ -128,7 +131,7 @@
     case JS_SET_ITERATOR_TYPE:
     case JS_MAP_ITERATOR_TYPE:
       return GetVisitorIdForSize(kVisitJSObject, kVisitJSObjectGeneric,
-                                 instance_size);
+                                 instance_size, has_unboxed_fields);
 
     case JS_FUNCTION_TYPE:
       return kVisitJSFunction;
@@ -140,7 +143,7 @@
 
       TYPED_ARRAYS(EXTERNAL_ARRAY_CASE)
       return GetVisitorIdForSize(kVisitDataObject, kVisitDataObjectGeneric,
-                                 instance_size);
+                                 instance_size, has_unboxed_fields);
 #undef EXTERNAL_ARRAY_CASE
 
     case FIXED_UINT8_ARRAY_TYPE:
@@ -164,7 +167,7 @@
       }
 
       return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
-                                 instance_size);
+                                 instance_size, has_unboxed_fields);
 
     default:
       UNREACHABLE();
diff --git a/src/heap/objects-visiting.h b/src/heap/objects-visiting.h
index 919a800..a442867 100644
--- a/src/heap/objects-visiting.h
+++ b/src/heap/objects-visiting.h
@@ -6,6 +6,7 @@
 #define V8_OBJECTS_VISITING_H_
 
 #include "src/allocation.h"
+#include "src/layout-descriptor.h"
 
 // This file provides base classes and auxiliary methods for defining
 // static object visitors used during GC.
@@ -71,6 +72,7 @@
   V(Map)                   \
   V(Cell)                  \
   V(PropertyCell)          \
+  V(WeakCell)              \
   V(SharedFunctionInfo)    \
   V(JSFunction)            \
   V(JSWeakCollection)      \
@@ -104,26 +106,35 @@
 
   // Determine which specialized visitor should be used for given instance type
   // and instance type.
-  static VisitorId GetVisitorId(int instance_type, int instance_size);
+  static VisitorId GetVisitorId(int instance_type, int instance_size,
+                                bool has_unboxed_fields);
 
+  // Determine which specialized visitor should be used for given map.
   static VisitorId GetVisitorId(Map* map) {
-    return GetVisitorId(map->instance_type(), map->instance_size());
+    return GetVisitorId(
+        map->instance_type(), map->instance_size(),
+        FLAG_unbox_double_fields && !map->HasFastPointerLayout());
   }
 
   // For visitors that allow specialization by size calculate VisitorId based
   // on size, base visitor id and generic visitor id.
   static VisitorId GetVisitorIdForSize(VisitorId base, VisitorId generic,
-                                       int object_size) {
+                                       int object_size,
+                                       bool has_unboxed_fields) {
     DCHECK((base == kVisitDataObject) || (base == kVisitStruct) ||
            (base == kVisitJSObject));
     DCHECK(IsAligned(object_size, kPointerSize));
     DCHECK(kMinObjectSizeInWords * kPointerSize <= object_size);
     DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
+    DCHECK(!has_unboxed_fields || (base == kVisitJSObject));
 
-    const VisitorId specialization = static_cast<VisitorId>(
-        base + (object_size >> kPointerSizeLog2) - kMinObjectSizeInWords);
+    if (has_unboxed_fields) return generic;
 
-    return Min(specialization, generic);
+    int visitor_id =
+        Min(base + (object_size >> kPointerSizeLog2) - kMinObjectSizeInWords,
+            static_cast<int>(generic));
+
+    return static_cast<VisitorId>(visitor_id);
   }
 };
 
@@ -157,7 +168,7 @@
             StaticVisitorBase::VisitorId generic, int object_size_in_words>
   void RegisterSpecialization() {
     static const int size = object_size_in_words * kPointerSize;
-    Register(StaticVisitorBase::GetVisitorIdForSize(base, generic, size),
+    Register(StaticVisitorBase::GetVisitorIdForSize(base, generic, size, false),
              &Visitor::template VisitSpecialized<size>);
   }
 
@@ -188,11 +199,43 @@
  public:
   INLINE(static void IteratePointers(Heap* heap, HeapObject* object,
                                      int start_offset, int end_offset)) {
-    Object** start_slot =
-        reinterpret_cast<Object**>(object->address() + start_offset);
-    Object** end_slot =
-        reinterpret_cast<Object**>(object->address() + end_offset);
-    StaticVisitor::VisitPointers(heap, start_slot, end_slot);
+    DCHECK(!FLAG_unbox_double_fields || object->map()->HasFastPointerLayout());
+    IterateRawPointers(heap, object, start_offset, end_offset);
+  }
+
+  INLINE(static void IterateBody(Heap* heap, HeapObject* object,
+                                 int start_offset, int end_offset)) {
+    if (!FLAG_unbox_double_fields || object->map()->HasFastPointerLayout()) {
+      IterateRawPointers(heap, object, start_offset, end_offset);
+    } else {
+      IterateBodyUsingLayoutDescriptor(heap, object, start_offset, end_offset);
+    }
+  }
+
+ private:
+  INLINE(static void IterateRawPointers(Heap* heap, HeapObject* object,
+                                        int start_offset, int end_offset)) {
+    StaticVisitor::VisitPointers(heap,
+                                 HeapObject::RawField(object, start_offset),
+                                 HeapObject::RawField(object, end_offset));
+  }
+
+  static void IterateBodyUsingLayoutDescriptor(Heap* heap, HeapObject* object,
+                                               int start_offset,
+                                               int end_offset) {
+    DCHECK(FLAG_unbox_double_fields);
+    DCHECK(IsAligned(start_offset, kPointerSize) &&
+           IsAligned(end_offset, kPointerSize));
+
+    LayoutDescriptorHelper helper(object->map());
+    DCHECK(!helper.all_fields_tagged());
+    for (int offset = start_offset; offset < end_offset;) {
+      int end_of_region_offset;
+      if (helper.IsTagged(offset, end_offset, &end_of_region_offset)) {
+        IterateRawPointers(heap, object, offset, end_of_region_offset);
+      }
+      offset = end_of_region_offset;
+    }
   }
 };
 
@@ -202,7 +245,7 @@
  public:
   INLINE(static ReturnType Visit(Map* map, HeapObject* object)) {
     int object_size = BodyDescriptor::SizeOf(map, object);
-    BodyVisitorBase<StaticVisitor>::IteratePointers(
+    BodyVisitorBase<StaticVisitor>::IterateBody(
         map->GetHeap(), object, BodyDescriptor::kStartOffset, object_size);
     return static_cast<ReturnType>(object_size);
   }
@@ -221,9 +264,9 @@
 class FixedBodyVisitor : public BodyVisitorBase<StaticVisitor> {
  public:
   INLINE(static ReturnType Visit(Map* map, HeapObject* object)) {
-    BodyVisitorBase<StaticVisitor>::IteratePointers(
-        map->GetHeap(), object, BodyDescriptor::kStartOffset,
-        BodyDescriptor::kEndOffset);
+    BodyVisitorBase<StaticVisitor>::IterateBody(map->GetHeap(), object,
+                                                BodyDescriptor::kStartOffset,
+                                                BodyDescriptor::kEndOffset);
     return static_cast<ReturnType>(BodyDescriptor::kSize);
   }
 };
@@ -362,6 +405,7 @@
   }
 
   INLINE(static void VisitPropertyCell(Map* map, HeapObject* object));
+  INLINE(static void VisitWeakCell(Map* map, HeapObject* object));
   INLINE(static void VisitCodeEntry(Heap* heap, Address entry_address));
   INLINE(static void VisitEmbeddedPointer(Heap* heap, RelocInfo* rinfo));
   INLINE(static void VisitCell(Heap* heap, RelocInfo* rinfo));
diff --git a/src/heap/spaces.cc b/src/heap/spaces.cc
index f8d340f..060052e 100644
--- a/src/heap/spaces.cc
+++ b/src/heap/spaces.cc
@@ -93,7 +93,8 @@
       code_range_(NULL),
       free_list_(0),
       allocation_list_(0),
-      current_allocation_block_index_(0) {}
+      current_allocation_block_index_(0),
+      emergency_block_() {}
 
 
 bool CodeRange::SetUp(size_t requested) {
@@ -110,6 +111,10 @@
     }
   }
 
+  if (requested <= kMinimumCodeRangeSize) {
+    requested = kMinimumCodeRangeSize;
+  }
+
   DCHECK(!kRequiresCodeRange || requested <= kMaximalCodeRangeSize);
   code_range_ = new base::VirtualMemory(requested);
   CHECK(code_range_ != NULL);
@@ -121,14 +126,27 @@
 
   // We are sure that we have mapped a block of requested addresses.
   DCHECK(code_range_->size() == requested);
-  LOG(isolate_, NewEvent("CodeRange", code_range_->address(), requested));
   Address base = reinterpret_cast<Address>(code_range_->address());
-  Address aligned_base =
-      RoundUp(reinterpret_cast<Address>(code_range_->address()),
-              MemoryChunk::kAlignment);
-  size_t size = code_range_->size() - (aligned_base - base);
+
+  // On some platforms, specifically Win64, we need to reserve some pages at
+  // the beginning of an executable space.
+  if (kReservedCodeRangePages) {
+    if (!code_range_->Commit(
+            base, kReservedCodeRangePages * base::OS::CommitPageSize(), true)) {
+      delete code_range_;
+      code_range_ = NULL;
+      return false;
+    }
+    base += kReservedCodeRangePages * base::OS::CommitPageSize();
+  }
+  Address aligned_base = RoundUp(base, MemoryChunk::kAlignment);
+  size_t size = code_range_->size() - (aligned_base - base) -
+                kReservedCodeRangePages * base::OS::CommitPageSize();
   allocation_list_.Add(FreeBlock(aligned_base, size));
   current_allocation_block_index_ = 0;
+
+  LOG(isolate_, NewEvent("CodeRange", code_range_->address(), requested));
+  ReserveEmergencyBlock();
   return true;
 }
 
@@ -187,35 +205,20 @@
                                      const size_t commit_size,
                                      size_t* allocated) {
   DCHECK(commit_size <= requested_size);
-  DCHECK(allocation_list_.length() == 0 ||
-         current_allocation_block_index_ < allocation_list_.length());
-  if (allocation_list_.length() == 0 ||
-      requested_size > allocation_list_[current_allocation_block_index_].size) {
-    // Find an allocation block large enough.
-    if (!GetNextAllocationBlock(requested_size)) return NULL;
+  FreeBlock current;
+  if (!ReserveBlock(requested_size, &current)) {
+    *allocated = 0;
+    return NULL;
   }
-  // Commit the requested memory at the start of the current allocation block.
-  size_t aligned_requested = RoundUp(requested_size, MemoryChunk::kAlignment);
-  FreeBlock current = allocation_list_[current_allocation_block_index_];
-  if (aligned_requested >= (current.size - Page::kPageSize)) {
-    // Don't leave a small free block, useless for a large object or chunk.
-    *allocated = current.size;
-  } else {
-    *allocated = aligned_requested;
-  }
+  *allocated = current.size;
   DCHECK(*allocated <= current.size);
   DCHECK(IsAddressAligned(current.start, MemoryChunk::kAlignment));
   if (!isolate_->memory_allocator()->CommitExecutableMemory(
           code_range_, current.start, commit_size, *allocated)) {
     *allocated = 0;
+    ReleaseBlock(&current);
     return NULL;
   }
-  allocation_list_[current_allocation_block_index_].start += *allocated;
-  allocation_list_[current_allocation_block_index_].size -= *allocated;
-  if (*allocated == current.size) {
-    // This block is used up, get the next one.
-    GetNextAllocationBlock(0);
-  }
   return current.start;
 }
 
@@ -245,6 +248,49 @@
 }
 
 
+bool CodeRange::ReserveBlock(const size_t requested_size, FreeBlock* block) {
+  DCHECK(allocation_list_.length() == 0 ||
+         current_allocation_block_index_ < allocation_list_.length());
+  if (allocation_list_.length() == 0 ||
+      requested_size > allocation_list_[current_allocation_block_index_].size) {
+    // Find an allocation block large enough.
+    if (!GetNextAllocationBlock(requested_size)) return false;
+  }
+  // Commit the requested memory at the start of the current allocation block.
+  size_t aligned_requested = RoundUp(requested_size, MemoryChunk::kAlignment);
+  *block = allocation_list_[current_allocation_block_index_];
+  // Don't leave a small free block, useless for a large object or chunk.
+  if (aligned_requested < (block->size - Page::kPageSize)) {
+    block->size = aligned_requested;
+  }
+  DCHECK(IsAddressAligned(block->start, MemoryChunk::kAlignment));
+  allocation_list_[current_allocation_block_index_].start += block->size;
+  allocation_list_[current_allocation_block_index_].size -= block->size;
+  return true;
+}
+
+
+void CodeRange::ReleaseBlock(const FreeBlock* block) { free_list_.Add(*block); }
+
+
+void CodeRange::ReserveEmergencyBlock() {
+  const size_t requested_size = MemoryAllocator::CodePageAreaSize();
+  if (emergency_block_.size == 0) {
+    ReserveBlock(requested_size, &emergency_block_);
+  } else {
+    DCHECK(emergency_block_.size >= requested_size);
+  }
+}
+
+
+void CodeRange::ReleaseEmergencyBlock() {
+  if (emergency_block_.size != 0) {
+    ReleaseBlock(&emergency_block_);
+    emergency_block_.size = 0;
+  }
+}
+
+
 // -----------------------------------------------------------------------------
 // MemoryAllocator
 //
@@ -877,18 +923,32 @@
 // -----------------------------------------------------------------------------
 // PagedSpace implementation
 
-PagedSpace::PagedSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id,
+STATIC_ASSERT(static_cast<ObjectSpace>(1 << AllocationSpace::NEW_SPACE) ==
+              ObjectSpace::kObjectSpaceNewSpace);
+STATIC_ASSERT(static_cast<ObjectSpace>(1
+                                       << AllocationSpace::OLD_POINTER_SPACE) ==
+              ObjectSpace::kObjectSpaceOldPointerSpace);
+STATIC_ASSERT(static_cast<ObjectSpace>(1 << AllocationSpace::OLD_DATA_SPACE) ==
+              ObjectSpace::kObjectSpaceOldDataSpace);
+STATIC_ASSERT(static_cast<ObjectSpace>(1 << AllocationSpace::CODE_SPACE) ==
+              ObjectSpace::kObjectSpaceCodeSpace);
+STATIC_ASSERT(static_cast<ObjectSpace>(1 << AllocationSpace::CELL_SPACE) ==
+              ObjectSpace::kObjectSpaceCellSpace);
+STATIC_ASSERT(
+    static_cast<ObjectSpace>(1 << AllocationSpace::PROPERTY_CELL_SPACE) ==
+    ObjectSpace::kObjectSpacePropertyCellSpace);
+STATIC_ASSERT(static_cast<ObjectSpace>(1 << AllocationSpace::MAP_SPACE) ==
+              ObjectSpace::kObjectSpaceMapSpace);
+
+
+PagedSpace::PagedSpace(Heap* heap, intptr_t max_capacity, AllocationSpace space,
                        Executability executable)
-    : Space(heap, id, executable),
+    : Space(heap, space, executable),
       free_list_(this),
       unswept_free_bytes_(0),
       end_of_unswept_pages_(NULL),
       emergency_memory_(NULL) {
-  if (id == CODE_SPACE) {
-    area_size_ = heap->isolate()->memory_allocator()->CodePageAreaSize();
-  } else {
-    area_size_ = Page::kPageSize - Page::kObjectStartOffset;
-  }
+  area_size_ = MemoryAllocator::PageAreaSize(space);
   max_capacity_ =
       (RoundDown(max_capacity, Page::kPageSize) / Page::kPageSize) * AreaSize();
   accounting_stats_.Clear();
@@ -990,7 +1050,7 @@
   int size = 0;
   switch (identity()) {
     case OLD_POINTER_SPACE:
-      size = (112 + constant_pool_delta) * kPointerSize * KB;
+      size = (128 + constant_pool_delta) * kPointerSize * KB;
       break;
     case OLD_DATA_SPACE:
       size = 192 * KB;
@@ -1082,7 +1142,12 @@
     allocation_info_.set_limit(NULL);
   }
 
-  page->Unlink();
+  // If page is still in a list, unlink it from that list.
+  if (page->next_chunk() != NULL) {
+    DCHECK(page->prev_chunk() != NULL);
+    page->Unlink();
+  }
+
   if (page->IsFlagSet(MemoryChunk::CONTAINS_ONLY_DATA)) {
     heap()->isolate()->memory_allocator()->Free(page);
   } else {
@@ -1095,6 +1160,14 @@
 
 
 void PagedSpace::CreateEmergencyMemory() {
+  if (identity() == CODE_SPACE) {
+    // Make the emergency block available to the allocator.
+    CodeRange* code_range = heap()->isolate()->code_range();
+    if (code_range != NULL && code_range->valid()) {
+      code_range->ReleaseEmergencyBlock();
+    }
+    DCHECK(MemoryAllocator::CodePageAreaSize() == AreaSize());
+  }
   emergency_memory_ = heap()->isolate()->memory_allocator()->AllocateChunk(
       AreaSize(), AreaSize(), executable(), this);
 }
@@ -1180,6 +1253,8 @@
   // this chunk must be a power of two and it must be aligned to its size.
   int initial_semispace_capacity = heap()->InitialSemiSpaceSize();
 
+  int target_semispace_capacity = heap()->TargetSemiSpaceSize();
+
   size_t size = 2 * reserved_semispace_capacity;
   Address base = heap()->isolate()->memory_allocator()->ReserveAlignedMemory(
       size, size, &reservation_);
@@ -1208,9 +1283,10 @@
   DCHECK(IsAddressAligned(chunk_base_, 2 * reserved_semispace_capacity, 0));
 
   to_space_.SetUp(chunk_base_, initial_semispace_capacity,
-                  maximum_semispace_capacity);
+                  target_semispace_capacity, maximum_semispace_capacity);
   from_space_.SetUp(chunk_base_ + reserved_semispace_capacity,
-                    initial_semispace_capacity, maximum_semispace_capacity);
+                    initial_semispace_capacity, target_semispace_capacity,
+                    maximum_semispace_capacity);
   if (!to_space_.Commit()) {
     return false;
   }
@@ -1261,7 +1337,8 @@
   // Double the semispace size but only up to maximum capacity.
   DCHECK(TotalCapacity() < MaximumCapacity());
   int new_capacity =
-      Min(MaximumCapacity(), 2 * static_cast<int>(TotalCapacity()));
+      Min(MaximumCapacity(),
+          FLAG_semi_space_growth_factor * static_cast<int>(TotalCapacity()));
   if (to_space_.GrowTo(new_capacity)) {
     // Only grow from space if we managed to grow to-space.
     if (!from_space_.GrowTo(new_capacity)) {
@@ -1270,7 +1347,7 @@
       if (!to_space_.ShrinkTo(from_space_.TotalCapacity())) {
         // We are in an inconsistent state because we could not
         // commit/uncommit memory from new space.
-        V8::FatalProcessOutOfMemory("Failed to grow new space.");
+        CHECK(false);
       }
     }
   }
@@ -1278,6 +1355,36 @@
 }
 
 
+bool NewSpace::GrowOnePage() {
+  if (TotalCapacity() == MaximumCapacity()) return false;
+  int new_capacity = static_cast<int>(TotalCapacity()) + Page::kPageSize;
+  if (to_space_.GrowTo(new_capacity)) {
+    // Only grow from space if we managed to grow to-space and the from space
+    // is actually committed.
+    if (from_space_.is_committed()) {
+      if (!from_space_.GrowTo(new_capacity)) {
+        // If we managed to grow to-space but couldn't grow from-space,
+        // attempt to shrink to-space.
+        if (!to_space_.ShrinkTo(from_space_.TotalCapacity())) {
+          // We are in an inconsistent state because we could not
+          // commit/uncommit memory from new space.
+          CHECK(false);
+        }
+        return false;
+      }
+    } else {
+      if (!from_space_.SetTotalCapacity(new_capacity)) {
+        // Can't really happen, but better safe than sorry.
+        CHECK(false);
+      }
+    }
+    DCHECK_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
+    return true;
+  }
+  return false;
+}
+
+
 void NewSpace::Shrink() {
   int new_capacity = Max(InitialTotalCapacity(), 2 * SizeAsInt());
   int rounded_new_capacity = RoundUp(new_capacity, Page::kPageSize);
@@ -1291,7 +1398,7 @@
       if (!to_space_.GrowTo(from_space_.TotalCapacity())) {
         // We are in an inconsistent state because we could not
         // commit/uncommit memory from new space.
-        V8::FatalProcessOutOfMemory("Failed to shrink new space.");
+        CHECK(false);
       }
     }
   }
@@ -1352,8 +1459,19 @@
     return false;
   }
   if (!to_space_.AdvancePage()) {
-    // Failed to get a new page in to-space.
-    return false;
+    // Check if we reached the target capacity yet. If not, try to commit a page
+    // and continue.
+    if ((to_space_.TotalCapacity() < to_space_.TargetCapacity()) &&
+        GrowOnePage()) {
+      if (!to_space_.AdvancePage()) {
+        // It doesn't make sense that we managed to commit a page, but can't use
+        // it.
+        CHECK(false);
+      }
+    } else {
+      // Failed to get a new page in to-space.
+      return false;
+    }
   }
 
   // Clear remainder of current page.
@@ -1457,7 +1575,7 @@
 // -----------------------------------------------------------------------------
 // SemiSpace implementation
 
-void SemiSpace::SetUp(Address start, int initial_capacity,
+void SemiSpace::SetUp(Address start, int initial_capacity, int target_capacity,
                       int maximum_capacity) {
   // Creates a space in the young generation. The constructor does not
   // allocate memory from the OS.  A SemiSpace is given a contiguous chunk of
@@ -1466,8 +1584,11 @@
   // space is used as the marking stack. It requires contiguous memory
   // addresses.
   DCHECK(maximum_capacity >= Page::kPageSize);
+  DCHECK(initial_capacity <= target_capacity);
+  DCHECK(target_capacity <= maximum_capacity);
   initial_total_capacity_ = RoundDown(initial_capacity, Page::kPageSize);
   total_capacity_ = initial_capacity;
+  target_capacity_ = RoundDown(target_capacity, Page::kPageSize);
   maximum_total_capacity_ = RoundDown(maximum_capacity, Page::kPageSize);
   maximum_committed_ = 0;
   committed_ = false;
@@ -1596,6 +1717,17 @@
 }
 
 
+bool SemiSpace::SetTotalCapacity(int new_capacity) {
+  CHECK(!is_committed());
+  if (new_capacity >= initial_total_capacity_ &&
+      new_capacity <= maximum_total_capacity_) {
+    total_capacity_ = new_capacity;
+    return true;
+  }
+  return false;
+}
+
+
 void SemiSpace::FlipPages(intptr_t flags, intptr_t mask) {
   anchor_.set_owner(this);
   // Fixup back-pointers to anchor. Address of anchor changes
@@ -2500,7 +2632,8 @@
 
 
 intptr_t PagedSpace::SizeOfObjects() {
-  DCHECK(heap()->mark_compact_collector()->sweeping_in_progress() ||
+  DCHECK(!FLAG_concurrent_sweeping ||
+         heap()->mark_compact_collector()->sweeping_in_progress() ||
          (unswept_free_bytes_ == 0));
   return Size() - unswept_free_bytes_ - (limit() - top());
 }
@@ -2840,9 +2973,7 @@
     return AllocationResult::Retry(identity());
   }
 
-  if (Size() + object_size > max_capacity_) {
-    return AllocationResult::Retry(identity());
-  }
+  if (!CanAllocateSize(object_size)) return AllocationResult::Retry(identity());
 
   LargePage* page = heap()->isolate()->memory_allocator()->AllocateLargePage(
       object_size, this, executable);
diff --git a/src/heap/spaces.h b/src/heap/spaces.h
index 9ecb3c4..dcd3364 100644
--- a/src/heap/spaces.h
+++ b/src/heap/spaces.h
@@ -880,6 +880,10 @@
     DCHECK(valid());
     return static_cast<Address>(code_range_->address());
   }
+  size_t size() {
+    DCHECK(valid());
+    return code_range_->size();
+  }
   bool contains(Address address) {
     if (!valid()) return false;
     Address start = static_cast<Address>(code_range_->address());
@@ -896,6 +900,9 @@
   bool UncommitRawMemory(Address start, size_t length);
   void FreeRawMemory(Address buf, size_t length);
 
+  void ReserveEmergencyBlock();
+  void ReleaseEmergencyBlock();
+
  private:
   Isolate* isolate_;
 
@@ -904,6 +911,7 @@
   // Plain old data class, just a struct plus a constructor.
   class FreeBlock {
    public:
+    FreeBlock() : start(0), size(0) {}
     FreeBlock(Address start_arg, size_t size_arg)
         : start(start_arg), size(size_arg) {
       DCHECK(IsAddressAligned(start, MemoryChunk::kAlignment));
@@ -928,6 +936,12 @@
   List<FreeBlock> allocation_list_;
   int current_allocation_block_index_;
 
+  // Emergency block guarantees that we can always allocate a page for
+  // evacuation candidates when code space is compacted. Emergency block is
+  // reserved immediately after GC and is released immedietely before
+  // allocating a page for evacuation.
+  FreeBlock emergency_block_;
+
   // Finds a block on the allocation list that contains at least the
   // requested amount of memory.  If none is found, sorts and merges
   // the existing free memory blocks, and searches again.
@@ -936,6 +950,8 @@
   // Compares the start addresses of two free blocks.
   static int CompareFreeBlockAddress(const FreeBlock* left,
                                      const FreeBlock* right);
+  bool ReserveBlock(const size_t requested_size, FreeBlock* block);
+  void ReleaseBlock(const FreeBlock* block);
 
   DISALLOW_COPY_AND_ASSIGN(CodeRange);
 };
@@ -1100,6 +1116,12 @@
     return CodePageAreaEndOffset() - CodePageAreaStartOffset();
   }
 
+  static int PageAreaSize(AllocationSpace space) {
+    DCHECK_NE(LO_SPACE, space);
+    return (space == CODE_SPACE) ? CodePageAreaSize()
+                                 : Page::kMaxRegularHeapObjectSize;
+  }
+
   MUST_USE_RESULT bool CommitExecutableMemory(base::VirtualMemory* vm,
                                               Address start, size_t commit_size,
                                               size_t reserved_size);
@@ -1604,16 +1626,19 @@
  public:
   // Implicit constructor from Object*.
   AllocationResult(Object* object)  // NOLINT
-      : object_(object),
-        retry_space_(INVALID_SPACE) {}
+      : object_(object) {
+    // AllocationResults can't return Smis, which are used to represent
+    // failure and the space to retry in.
+    CHECK(!object->IsSmi());
+  }
 
-  AllocationResult() : object_(NULL), retry_space_(INVALID_SPACE) {}
+  AllocationResult() : object_(Smi::FromInt(NEW_SPACE)) {}
 
   static inline AllocationResult Retry(AllocationSpace space = NEW_SPACE) {
     return AllocationResult(space);
   }
 
-  inline bool IsRetry() { return retry_space_ != INVALID_SPACE; }
+  inline bool IsRetry() { return object_->IsSmi(); }
 
   template <typename T>
   bool To(T** obj) {
@@ -1629,18 +1654,20 @@
 
   AllocationSpace RetrySpace() {
     DCHECK(IsRetry());
-    return retry_space_;
+    return static_cast<AllocationSpace>(Smi::cast(object_)->value());
   }
 
  private:
   explicit AllocationResult(AllocationSpace space)
-      : object_(NULL), retry_space_(space) {}
+      : object_(Smi::FromInt(static_cast<int>(space))) {}
 
   Object* object_;
-  AllocationSpace retry_space_;
 };
 
 
+STATIC_ASSERT(sizeof(AllocationResult) == kPointerSize);
+
+
 class PagedSpace : public Space {
  public:
   // Creates a space with a maximum capacity, and an id.
@@ -2071,7 +2098,8 @@
         current_page_(NULL) {}
 
   // Sets up the semispace using the given chunk.
-  void SetUp(Address start, int initial_capacity, int maximum_capacity);
+  void SetUp(Address start, int initial_capacity, int target_capacity,
+             int maximum_capacity);
 
   // Tear down the space.  Heap memory was not allocated by the space, so it
   // is not deallocated here.
@@ -2090,6 +2118,9 @@
   // semispace and less than the current capacity.
   bool ShrinkTo(int new_capacity);
 
+  // Sets the total capacity. Only possible when the space is not committed.
+  bool SetTotalCapacity(int new_capacity);
+
   // Returns the start address of the first page of the space.
   Address space_start() {
     DCHECK(anchor_.next_page() != &anchor_);
@@ -2164,6 +2195,9 @@
   // Returns the current total capacity of the semispace.
   int TotalCapacity() { return total_capacity_; }
 
+  // Returns the target for total capacity of the semispace.
+  int TargetCapacity() { return target_capacity_; }
+
   // Returns the maximum total capacity of the semispace.
   int MaximumTotalCapacity() { return maximum_total_capacity_; }
 
@@ -2192,6 +2226,7 @@
 
   // The current and maximum total capacity of the space.
   int total_capacity_;
+  int target_capacity_;
   int maximum_total_capacity_;
   int initial_total_capacity_;
 
@@ -2337,6 +2372,9 @@
   // their maximum capacity.
   void Grow();
 
+  // Grow the capacity of the semispaces by one page.
+  bool GrowOnePage();
+
   // Shrink the capacity of the semispaces.
   void Shrink();
 
@@ -2728,6 +2766,8 @@
   MUST_USE_RESULT AllocationResult
       AllocateRaw(int object_size, Executability executable);
 
+  bool CanAllocateSize(int size) { return Size() + size <= max_capacity_; }
+
   // Available bytes for objects in this space.
   inline intptr_t Available();
 
diff --git a/src/heap/store-buffer.cc b/src/heap/store-buffer.cc
index 278e9f2..aac6811 100644
--- a/src/heap/store-buffer.cc
+++ b/src/heap/store-buffer.cc
@@ -109,7 +109,9 @@
   for (Address* read = old_start_; read < old_top_; read++) {
     Address current = *read;
     if (current != previous) {
-      if (heap_->InNewSpace(*reinterpret_cast<Object**>(current))) {
+      Object* object = reinterpret_cast<Object*>(
+          base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(current)));
+      if (heap_->InNewSpace(object)) {
         *write++ = current;
       }
     }
@@ -507,11 +509,37 @@
             for (HeapObject* heap_object = iterator.Next(); heap_object != NULL;
                  heap_object = iterator.Next()) {
               // We iterate over objects that contain new space pointers only.
-              if (!heap_object->MayContainRawValues()) {
-                FindPointersToNewSpaceInRegion(
-                    heap_object->address() + HeapObject::kHeaderSize,
-                    heap_object->address() + heap_object->Size(), slot_callback,
-                    clear_maps);
+              bool may_contain_raw_values = heap_object->MayContainRawValues();
+              if (!may_contain_raw_values) {
+                Address obj_address = heap_object->address();
+                const int start_offset = HeapObject::kHeaderSize;
+                const int end_offset = heap_object->Size();
+#if V8_DOUBLE_FIELDS_UNBOXING
+                LayoutDescriptorHelper helper(heap_object->map());
+                bool has_only_tagged_fields = helper.all_fields_tagged();
+
+                if (!has_only_tagged_fields) {
+                  for (int offset = start_offset; offset < end_offset;) {
+                    int end_of_region_offset;
+                    if (helper.IsTagged(offset, end_offset,
+                                        &end_of_region_offset)) {
+                      FindPointersToNewSpaceInRegion(
+                          obj_address + offset,
+                          obj_address + end_of_region_offset, slot_callback,
+                          clear_maps);
+                    }
+                    offset = end_of_region_offset;
+                  }
+                } else {
+#endif
+                  Address start_address = obj_address + start_offset;
+                  Address end_address = obj_address + end_offset;
+                  // Object has only tagged fields.
+                  FindPointersToNewSpaceInRegion(start_address, end_address,
+                                                 slot_callback, clear_maps);
+#if V8_DOUBLE_FIELDS_UNBOXING
+                }
+#endif
               }
             }
           }
diff --git a/src/heap/sweeper-thread.cc b/src/heap/sweeper-thread.cc
deleted file mode 100644
index b0e8cea..0000000
--- a/src/heap/sweeper-thread.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/heap/sweeper-thread.h"
-
-#include "src/v8.h"
-
-#include "src/isolate.h"
-#include "src/v8threads.h"
-
-namespace v8 {
-namespace internal {
-
-static const int kSweeperThreadStackSize = 64 * KB;
-
-SweeperThread::SweeperThread(Isolate* isolate)
-    : Thread(Thread::Options("v8:SweeperThread", kSweeperThreadStackSize)),
-      isolate_(isolate),
-      heap_(isolate->heap()),
-      collector_(heap_->mark_compact_collector()),
-      start_sweeping_semaphore_(0),
-      end_sweeping_semaphore_(0),
-      stop_semaphore_(0) {
-  DCHECK(!FLAG_job_based_sweeping);
-  base::NoBarrier_Store(&stop_thread_, static_cast<base::AtomicWord>(false));
-}
-
-
-void SweeperThread::Run() {
-  Isolate::SetIsolateThreadLocals(isolate_, NULL);
-  DisallowHeapAllocation no_allocation;
-  DisallowHandleAllocation no_handles;
-  DisallowHandleDereference no_deref;
-
-  while (true) {
-    start_sweeping_semaphore_.Wait();
-
-    if (base::Acquire_Load(&stop_thread_)) {
-      stop_semaphore_.Signal();
-      return;
-    }
-
-    collector_->SweepInParallel(heap_->old_data_space(), 0);
-    collector_->SweepInParallel(heap_->old_pointer_space(), 0);
-    end_sweeping_semaphore_.Signal();
-  }
-}
-
-
-void SweeperThread::Stop() {
-  base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(true));
-  start_sweeping_semaphore_.Signal();
-  stop_semaphore_.Wait();
-  Join();
-}
-
-
-void SweeperThread::StartSweeping() { start_sweeping_semaphore_.Signal(); }
-
-
-void SweeperThread::WaitForSweeperThread() { end_sweeping_semaphore_.Wait(); }
-
-
-bool SweeperThread::SweepingCompleted() {
-  bool value = end_sweeping_semaphore_.WaitFor(base::TimeDelta::FromSeconds(0));
-  if (value) {
-    end_sweeping_semaphore_.Signal();
-  }
-  return value;
-}
-
-
-int SweeperThread::NumberOfThreads(int max_available) {
-  if (!FLAG_concurrent_sweeping && !FLAG_parallel_sweeping) return 0;
-  if (FLAG_sweeper_threads > 0) return FLAG_sweeper_threads;
-  if (FLAG_concurrent_sweeping) return max_available - 1;
-  DCHECK(FLAG_parallel_sweeping);
-  return max_available;
-}
-}
-}  // namespace v8::internal
diff --git a/src/heap/sweeper-thread.h b/src/heap/sweeper-thread.h
deleted file mode 100644
index fc6bdda..0000000
--- a/src/heap/sweeper-thread.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_HEAP_SWEEPER_THREAD_H_
-#define V8_HEAP_SWEEPER_THREAD_H_
-
-#include "src/base/atomicops.h"
-#include "src/base/platform/platform.h"
-#include "src/flags.h"
-#include "src/utils.h"
-
-#include "src/heap/spaces.h"
-
-#include "src/heap/heap.h"
-
-namespace v8 {
-namespace internal {
-
-class SweeperThread : public base::Thread {
- public:
-  explicit SweeperThread(Isolate* isolate);
-  ~SweeperThread() {}
-
-  void Run();
-  void Stop();
-  void StartSweeping();
-  void WaitForSweeperThread();
-  bool SweepingCompleted();
-
-  static int NumberOfThreads(int max_available);
-
- private:
-  Isolate* isolate_;
-  Heap* heap_;
-  MarkCompactCollector* collector_;
-  base::Semaphore start_sweeping_semaphore_;
-  base::Semaphore end_sweeping_semaphore_;
-  base::Semaphore stop_semaphore_;
-  volatile base::AtomicWord stop_thread_;
-};
-}
-}  // namespace v8::internal
-
-#endif  // V8_HEAP_SWEEPER_THREAD_H_
diff --git a/src/hydrogen-bch.cc b/src/hydrogen-bch.cc
index 5af6030..2feb158 100644
--- a/src/hydrogen-bch.cc
+++ b/src/hydrogen-bch.cc
@@ -237,14 +237,13 @@
     // constant limit we will use that instead of the induction limit.
     bool has_upper_constant_limit = true;
     int32_t upper_constant_limit =
-        check != NULL && check->HasUpperLimit() ? check->upper_limit() : 0;
+        check->HasUpperLimit() ? check->upper_limit() : 0;
     for (InductionVariableData::InductionVariableCheck* current_check = check;
          current_check != NULL;
          current_check = current_check->next()) {
       has_upper_constant_limit =
-          has_upper_constant_limit &&
-          check->HasUpperLimit() &&
-          check->upper_limit() == upper_constant_limit;
+          has_upper_constant_limit && current_check->HasUpperLimit() &&
+          current_check->upper_limit() == upper_constant_limit;
       counters()->bounds_checks_eliminated()->Increment();
       current_check->check()->set_skip_check();
     }
diff --git a/src/hydrogen-dce.cc b/src/hydrogen-dce.cc
index c55426d..360b694 100644
--- a/src/hydrogen-dce.cc
+++ b/src/hydrogen-dce.cc
@@ -39,7 +39,7 @@
   } else {
     os << "root ";
   }
-  os << " -> " << *instr << "]" << endl;
+  os << " -> " << *instr << "]" << std::endl;
 }
 
 
diff --git a/src/hydrogen-gvn.cc b/src/hydrogen-gvn.cc
index be1e17b..da986e3 100644
--- a/src/hydrogen-gvn.cc
+++ b/src/hydrogen-gvn.cc
@@ -400,7 +400,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const TrackedEffects& te) {
+std::ostream& operator<<(std::ostream& os, const TrackedEffects& te) {
   SideEffectsTracker* t = te.tracker;
   const char* separator = "";
   os << "[";
@@ -450,7 +450,7 @@
     if (FLAG_trace_gvn) {
       OFStream os(stdout);
       os << "Tracking global var [" << *cell.handle() << "] "
-         << "(mapped to index " << num_global_vars_ << ")" << endl;
+         << "(mapped to index " << num_global_vars_ << ")" << std::endl;
     }
     *index = num_global_vars_;
     global_vars_[num_global_vars_++] = cell;
@@ -472,7 +472,7 @@
     if (FLAG_trace_gvn) {
       OFStream os(stdout);
       os << "Tracking inobject field access " << access << " (mapped to index "
-         << num_inobject_fields_ << ")" << endl;
+         << num_inobject_fields_ << ")" << std::endl;
     }
     *index = num_inobject_fields_;
     inobject_fields_[num_inobject_fields_++] = access;
@@ -567,7 +567,7 @@
       if (FLAG_trace_gvn) {
         OFStream os(stdout);
         os << "Try loop invariant motion for " << *block << " changes "
-           << Print(side_effects) << endl;
+           << Print(side_effects) << std::endl;
       }
       HBasicBlock* last = block->loop_information()->GetLastBackEdge();
       for (int j = block->block_id(); j <= last->block_id(); ++j) {
@@ -586,7 +586,7 @@
   if (FLAG_trace_gvn) {
     OFStream os(stdout);
     os << "Loop invariant code motion for " << *block << " depends on "
-       << Print(loop_kills) << endl;
+       << Print(loop_kills) << std::endl;
   }
   HInstruction* instr = block->first();
   while (instr != NULL) {
@@ -599,7 +599,7 @@
         os << "Checking instruction i" << instr->id() << " ("
            << instr->Mnemonic() << ") changes " << Print(changes)
            << ", depends on " << Print(depends_on) << ". Loop changes "
-           << Print(loop_kills) << endl;
+           << Print(loop_kills) << std::endl;
       }
       bool can_hoist = !depends_on.ContainsAnyOf(loop_kills);
       if (can_hoist && !graph()->use_optimistic_licm()) {
@@ -836,7 +836,7 @@
         if (FLAG_trace_gvn) {
           OFStream os(stdout);
           os << "Instruction i" << instr->id() << " changes " << Print(changes)
-             << endl;
+             << std::endl;
         }
       }
       if (instr->CheckFlag(HValue::kUseGVN) &&
diff --git a/src/hydrogen-gvn.h b/src/hydrogen-gvn.h
index 8cdeb99..421c6cc 100644
--- a/src/hydrogen-gvn.h
+++ b/src/hydrogen-gvn.h
@@ -5,6 +5,8 @@
 #ifndef V8_HYDROGEN_GVN_H_
 #define V8_HYDROGEN_GVN_H_
 
+#include <iosfwd>
+
 #include "src/compiler.h"
 #include "src/hydrogen.h"
 #include "src/hydrogen-instructions.h"
@@ -13,8 +15,6 @@
 namespace v8 {
 namespace internal {
 
-class OStream;
-
 // This class extends GVNFlagSet with additional "special" dynamic side effects,
 // which can be used to represent side effects that cannot be expressed using
 // the GVNFlags of an HInstruction. These special side effects are tracked by a
@@ -70,7 +70,7 @@
   SideEffects ComputeDependsOn(HInstruction* instr);
 
  private:
-  friend OStream& operator<<(OStream& os, const TrackedEffects& f);
+  friend std::ostream& operator<<(std::ostream& os, const TrackedEffects& f);
   bool ComputeGlobalVar(Unique<Cell> cell, int* index);
   bool ComputeInobjectField(HObjectAccess access, int* index);
 
@@ -107,7 +107,7 @@
 };
 
 
-OStream& operator<<(OStream& os, const TrackedEffects& f);
+std::ostream& operator<<(std::ostream& os, const TrackedEffects& f);
 
 
 // Perform common subexpression elimination and loop-invariant code motion.
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index a057217..0e6a03d 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -528,10 +528,12 @@
 }
 
 
-OStream& operator<<(OStream& os, const HValue& v) { return v.PrintTo(os); }
+std::ostream& operator<<(std::ostream& os, const HValue& v) {
+  return v.PrintTo(os);
+}
 
 
-OStream& operator<<(OStream& os, const TypeOf& t) {
+std::ostream& operator<<(std::ostream& os, const TypeOf& t) {
   if (t.value->representation().IsTagged() &&
       !t.value->type().Equals(HType::Tagged()))
     return os;
@@ -539,7 +541,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const ChangesOf& c) {
+std::ostream& operator<<(std::ostream& os, const ChangesOf& c) {
   GVNFlagSet changes_flags = c.value->ChangesFlags();
   if (changes_flags.IsEmpty()) return os;
   os << " changes[";
@@ -618,7 +620,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const HSourcePosition& p) {
+std::ostream& operator<<(std::ostream& os, const HSourcePosition& p) {
   if (p.IsUnknown()) {
     return os << "<?>";
   } else if (FLAG_hydrogen_track_positions) {
@@ -629,7 +631,7 @@
 }
 
 
-OStream& HInstruction::PrintTo(OStream& os) const {  // NOLINT
+std::ostream& HInstruction::PrintTo(std::ostream& os) const {  // NOLINT
   os << Mnemonic() << " ";
   PrintDataTo(os) << ChangesOf(this) << TypeOf(this);
   if (CheckFlag(HValue::kHasNoObservableSideEffects)) os << " [noOSE]";
@@ -638,7 +640,7 @@
 }
 
 
-OStream& HInstruction::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HInstruction::PrintDataTo(std::ostream& os) const {  // NOLINT
   for (int i = 0; i < OperandCount(); ++i) {
     if (i > 0) os << " ";
     os << NameOf(OperandAt(i));
@@ -794,7 +796,6 @@
     case HValue::kCallNew:
     case HValue::kCallNewArray:
     case HValue::kCallStub:
-    case HValue::kCallWithDescriptor:
     case HValue::kCapturedObject:
     case HValue::kClassOfTestAndBranch:
     case HValue::kCompareGeneric:
@@ -861,6 +862,7 @@
     case HValue::kBranch:
     case HValue::kCallJSFunction:
     case HValue::kCallRuntime:
+    case HValue::kCallWithDescriptor:
     case HValue::kChange:
     case HValue::kCheckHeapObject:
     case HValue::kCheckInstanceType:
@@ -912,27 +914,28 @@
 }
 
 
-OStream& operator<<(OStream& os, const NameOf& v) {
+std::ostream& operator<<(std::ostream& os, const NameOf& v) {
   return os << v.value->representation().Mnemonic() << v.value->id();
 }
 
-OStream& HDummyUse::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HDummyUse::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(value());
 }
 
 
-OStream& HEnvironmentMarker::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HEnvironmentMarker::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   return os << (kind() == BIND ? "bind" : "lookup") << " var[" << index()
             << "]";
 }
 
 
-OStream& HUnaryCall::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HUnaryCall::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(value()) << " #" << argument_count();
 }
 
 
-OStream& HCallJSFunction::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HCallJSFunction::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(function()) << " #" << argument_count();
 }
 
@@ -959,7 +962,7 @@
 }
 
 
-OStream& HBinaryCall::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HBinaryCall::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(first()) << " " << NameOf(second()) << " #"
             << argument_count();
 }
@@ -1015,7 +1018,7 @@
 }
 
 
-OStream& HBoundsCheck::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HBoundsCheck::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << NameOf(index()) << " " << NameOf(length());
   if (base() != NULL && (offset() != 0 || scale() != 0)) {
     os << " base: ((";
@@ -1070,15 +1073,16 @@
 }
 
 
-OStream& HBoundsCheckBaseIndexInformation::PrintDataTo(
-    OStream& os) const {  // NOLINT
+std::ostream& HBoundsCheckBaseIndexInformation::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   // TODO(svenpanne) This 2nd base_index() looks wrong...
   return os << "base: " << NameOf(base_index())
             << ", check: " << NameOf(base_index());
 }
 
 
-OStream& HCallWithDescriptor::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HCallWithDescriptor::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   for (int i = 0; i < OperandCount(); i++) {
     os << NameOf(OperandAt(i)) << " ";
   }
@@ -1086,42 +1090,46 @@
 }
 
 
-OStream& HCallNewArray::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HCallNewArray::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << ElementsKindToString(elements_kind()) << " ";
   return HBinaryCall::PrintDataTo(os);
 }
 
 
-OStream& HCallRuntime::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HCallRuntime::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << name()->ToCString().get() << " ";
   if (save_doubles() == kSaveFPRegs) os << "[save doubles] ";
   return os << "#" << argument_count();
 }
 
 
-OStream& HClassOfTestAndBranch::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HClassOfTestAndBranch::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   return os << "class_of_test(" << NameOf(value()) << ", \""
             << class_name()->ToCString().get() << "\")";
 }
 
 
-OStream& HWrapReceiver::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HWrapReceiver::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(receiver()) << " " << NameOf(function());
 }
 
 
-OStream& HAccessArgumentsAt::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HAccessArgumentsAt::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   return os << NameOf(arguments()) << "[" << NameOf(index()) << "], length "
             << NameOf(length());
 }
 
 
-OStream& HAllocateBlockContext::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HAllocateBlockContext::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   return os << NameOf(context()) << " " << NameOf(function());
 }
 
 
-OStream& HControlInstruction::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HControlInstruction::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   os << " goto (";
   bool first_block = true;
   for (HSuccessorIterator it(this); !it.Done(); it.Advance()) {
@@ -1133,25 +1141,24 @@
 }
 
 
-OStream& HUnaryControlInstruction::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HUnaryControlInstruction::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   os << NameOf(value());
   return HControlInstruction::PrintDataTo(os);
 }
 
 
-OStream& HReturn::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HReturn::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(value()) << " (pop " << NameOf(parameter_count())
             << " values)";
 }
 
 
 Representation HBranch::observed_input_representation(int index) {
-  static const ToBooleanStub::Types tagged_types(
-      ToBooleanStub::NULL_TYPE |
-      ToBooleanStub::SPEC_OBJECT |
-      ToBooleanStub::STRING |
-      ToBooleanStub::SYMBOL);
-  if (expected_input_types_.ContainsAnyOf(tagged_types)) {
+  if (expected_input_types_.Contains(ToBooleanStub::NULL_TYPE) ||
+      expected_input_types_.Contains(ToBooleanStub::SPEC_OBJECT) ||
+      expected_input_types_.Contains(ToBooleanStub::STRING) ||
+      expected_input_types_.Contains(ToBooleanStub::SYMBOL)) {
     return Representation::Tagged();
   }
   if (expected_input_types_.Contains(ToBooleanStub::UNDEFINED)) {
@@ -1185,13 +1192,13 @@
 }
 
 
-OStream& HBranch::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HBranch::PrintDataTo(std::ostream& os) const {  // NOLINT
   return HUnaryControlInstruction::PrintDataTo(os) << " "
                                                    << expected_input_types();
 }
 
 
-OStream& HCompareMap::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HCompareMap::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << NameOf(value()) << " (" << *map().handle() << ")";
   HControlInstruction::PrintDataTo(os);
   if (known_successor_index() == 0) {
@@ -1255,17 +1262,19 @@
 }
 
 
-OStream& HUnaryMathOperation::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HUnaryMathOperation::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   return os << OpName() << " " << NameOf(value());
 }
 
 
-OStream& HUnaryOperation::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HUnaryOperation::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(value());
 }
 
 
-OStream& HHasInstanceTypeAndBranch::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HHasInstanceTypeAndBranch::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   os << NameOf(value());
   switch (from_) {
     case FIRST_JS_RECEIVER_TYPE:
@@ -1287,7 +1296,8 @@
 }
 
 
-OStream& HTypeofIsAndBranch::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HTypeofIsAndBranch::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   os << NameOf(value()) << " == " << type_literal()->ToCString().get();
   return HControlInstruction::PrintDataTo(os);
 }
@@ -1340,7 +1350,7 @@
 }
 
 
-OStream& HCheckMapValue::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HCheckMapValue::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(value()) << " " << NameOf(map());
 }
 
@@ -1356,18 +1366,19 @@
 }
 
 
-OStream& HForInPrepareMap::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HForInPrepareMap::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(enumerable());
 }
 
 
-OStream& HForInCacheArray::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HForInCacheArray::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(enumerable()) << " " << NameOf(map()) << "[" << idx_
             << "]";
 }
 
 
-OStream& HLoadFieldByIndex::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HLoadFieldByIndex::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   return os << NameOf(object()) << " " << NameOf(index());
 }
 
@@ -1504,7 +1515,7 @@
 }
 
 
-OStream& HTypeof::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HTypeof::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(value());
 }
 
@@ -1520,12 +1531,13 @@
 }
 
 
-OStream& HForceRepresentation::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HForceRepresentation::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   return os << representation().Mnemonic() << " " << NameOf(value());
 }
 
 
-OStream& HChange::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HChange::PrintDataTo(std::ostream& os) const {  // NOLINT
   HUnaryOperation::PrintDataTo(os);
   os << " " << from().Mnemonic() << " to " << to().Mnemonic();
 
@@ -1637,7 +1649,7 @@
 }
 
 
-OStream& HCheckMaps::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HCheckMaps::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << NameOf(value()) << " [" << *maps()->at(0).handle();
   for (int i = 1; i < maps()->size(); ++i) {
     os << "," << *maps()->at(i).handle();
@@ -1668,7 +1680,7 @@
 }
 
 
-OStream& HCheckValue::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HCheckValue::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(value()) << " " << Brief(*object().handle());
 }
 
@@ -1691,20 +1703,28 @@
 }
 
 
-OStream& HCheckInstanceType::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HCheckInstanceType::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   os << GetCheckName() << " ";
   return HUnaryOperation::PrintDataTo(os);
 }
 
 
-OStream& HCallStub::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HCallStub::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << CodeStub::MajorName(major_key_, false) << " ";
   return HUnaryCall::PrintDataTo(os);
 }
 
 
-OStream& HTailCallThroughMegamorphicCache::PrintDataTo(
-    OStream& os) const {  // NOLINT
+Code::Flags HTailCallThroughMegamorphicCache::flags() const {
+  Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::LOAD_IC));
+  return code_flags;
+}
+
+
+std::ostream& HTailCallThroughMegamorphicCache::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   for (int i = 0; i < OperandCount(); i++) {
     os << NameOf(OperandAt(i)) << " ";
   }
@@ -1712,7 +1732,7 @@
 }
 
 
-OStream& HUnknownOSRValue::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HUnknownOSRValue::PrintDataTo(std::ostream& os) const {  // NOLINT
   const char* type = "expression";
   if (environment_->is_local_index(index_)) type = "local";
   if (environment_->is_special_index(index_)) type = "special";
@@ -1721,7 +1741,7 @@
 }
 
 
-OStream& HInstanceOf::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HInstanceOf::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(left()) << " " << NameOf(right()) << " "
             << NameOf(context());
 }
@@ -1774,7 +1794,7 @@
 
 
 Range* HConstant::InferRange(Zone* zone) {
-  if (has_int32_value_) {
+  if (HasInteger32Value()) {
     Range* result = new(zone) Range(int32_value_, int32_value_);
     result->set_can_be_minus_zero(false);
     return result;
@@ -2196,7 +2216,7 @@
  */
 int32_t InductionVariableData::ComputeIncrement(HPhi* phi,
                                                 HValue* phi_operand) {
-  if (!phi_operand->representation().IsInteger32()) return 0;
+  if (!phi_operand->representation().IsSmiOrInteger32()) return 0;
 
   if (phi_operand->IsAdd()) {
     HAdd* operation = HAdd::cast(phi_operand);
@@ -2439,7 +2459,7 @@
 }
 
 
-OStream& HPhi::PrintTo(OStream& os) const {  // NOLINT
+std::ostream& HPhi::PrintTo(std::ostream& os) const {  // NOLINT
   os << "[";
   for (int i = 0; i < OperandCount(); ++i) {
     os << " " << NameOf(OperandAt(i)) << " ";
@@ -2571,7 +2591,7 @@
 }
 
 
-OStream& HSimulate::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HSimulate::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << "id=" << ast_id().ToInt();
   if (pop_count_ > 0) os << " pop " << pop_count_;
   if (values_.length() > 0) {
@@ -2591,7 +2611,7 @@
 
 
 void HSimulate::ReplayEnvironment(HEnvironment* env) {
-  if (done_with_replay_) return;
+  if (is_done_with_replay()) return;
   DCHECK(env != NULL);
   env->set_ast_id(ast_id());
   env->Drop(pop_count());
@@ -2603,7 +2623,7 @@
       env->Push(value);
     }
   }
-  done_with_replay_ = true;
+  set_done_with_replay();
 }
 
 
@@ -2633,7 +2653,7 @@
 }
 
 
-OStream& HCapturedObject::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HCapturedObject::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << "#" << capture_id() << " ";
   return HDematerializedObject::PrintDataTo(os);
 }
@@ -2646,49 +2666,57 @@
 }
 
 
-OStream& HEnterInlined::PrintDataTo(OStream& os) const {  // NOLINT
-  return os << function()->debug_name()->ToCString().get()
-            << ", id=" << function()->id().ToInt();
+std::ostream& HEnterInlined::PrintDataTo(std::ostream& os) const {  // NOLINT
+  return os << function()->debug_name()->ToCString().get();
 }
 
 
 static bool IsInteger32(double value) {
-  double roundtrip_value = static_cast<double>(static_cast<int32_t>(value));
-  return bit_cast<int64_t>(roundtrip_value) == bit_cast<int64_t>(value);
+  if (value >= std::numeric_limits<int32_t>::min() &&
+      value <= std::numeric_limits<int32_t>::max()) {
+    double roundtrip_value = static_cast<double>(static_cast<int32_t>(value));
+    return bit_cast<int64_t>(roundtrip_value) == bit_cast<int64_t>(value);
+  }
+  return false;
 }
 
 
 HConstant::HConstant(Handle<Object> object, Representation r)
-  : HTemplateInstruction<0>(HType::FromValue(object)),
-    object_(Unique<Object>::CreateUninitialized(object)),
-    object_map_(Handle<Map>::null()),
-    has_stable_map_value_(false),
-    has_smi_value_(false),
-    has_int32_value_(false),
-    has_double_value_(false),
-    has_external_reference_value_(false),
-    is_not_in_new_space_(true),
-    boolean_value_(object->BooleanValue()),
-    is_undetectable_(false),
-    instance_type_(kUnknownInstanceType) {
+    : HTemplateInstruction<0>(HType::FromValue(object)),
+      object_(Unique<Object>::CreateUninitialized(object)),
+      object_map_(Handle<Map>::null()),
+      bit_field_(HasStableMapValueField::encode(false) |
+                 HasSmiValueField::encode(false) |
+                 HasInt32ValueField::encode(false) |
+                 HasDoubleValueField::encode(false) |
+                 HasExternalReferenceValueField::encode(false) |
+                 IsNotInNewSpaceField::encode(true) |
+                 BooleanValueField::encode(object->BooleanValue()) |
+                 IsUndetectableField::encode(false) |
+                 InstanceTypeField::encode(kUnknownInstanceType)) {
   if (object->IsHeapObject()) {
     Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
     Isolate* isolate = heap_object->GetIsolate();
     Handle<Map> map(heap_object->map(), isolate);
-    is_not_in_new_space_ = !isolate->heap()->InNewSpace(*object);
-    instance_type_ = map->instance_type();
-    is_undetectable_ = map->is_undetectable();
+    bit_field_ = IsNotInNewSpaceField::update(
+        bit_field_, !isolate->heap()->InNewSpace(*object));
+    bit_field_ = InstanceTypeField::update(bit_field_, map->instance_type());
+    bit_field_ =
+        IsUndetectableField::update(bit_field_, map->is_undetectable());
     if (map->is_stable()) object_map_ = Unique<Map>::CreateImmovable(map);
-    has_stable_map_value_ = (instance_type_ == MAP_TYPE &&
-                             Handle<Map>::cast(heap_object)->is_stable());
+    bit_field_ = HasStableMapValueField::update(
+        bit_field_,
+        HasMapValue() && Handle<Map>::cast(heap_object)->is_stable());
   }
   if (object->IsNumber()) {
     double n = object->Number();
-    has_int32_value_ = IsInteger32(n);
+    bool has_int32_value = IsInteger32(n);
+    bit_field_ = HasInt32ValueField::update(bit_field_, has_int32_value);
     int32_value_ = DoubleToInt32(n);
-    has_smi_value_ = has_int32_value_ && Smi::IsValid(int32_value_);
+    bit_field_ = HasSmiValueField::update(
+        bit_field_, has_int32_value && Smi::IsValid(int32_value_));
     double_value_ = n;
-    has_double_value_ = true;
+    bit_field_ = HasDoubleValueField::update(bit_field_, true);
     // TODO(titzer): if this heap number is new space, tenure a new one.
   }
 
@@ -2696,112 +2724,104 @@
 }
 
 
-HConstant::HConstant(Unique<Object> object,
-                     Unique<Map> object_map,
-                     bool has_stable_map_value,
-                     Representation r,
-                     HType type,
-                     bool is_not_in_new_space,
-                     bool boolean_value,
-                     bool is_undetectable,
-                     InstanceType instance_type)
-  : HTemplateInstruction<0>(type),
-    object_(object),
-    object_map_(object_map),
-    has_stable_map_value_(has_stable_map_value),
-    has_smi_value_(false),
-    has_int32_value_(false),
-    has_double_value_(false),
-    has_external_reference_value_(false),
-    is_not_in_new_space_(is_not_in_new_space),
-    boolean_value_(boolean_value),
-    is_undetectable_(is_undetectable),
-    instance_type_(instance_type) {
+HConstant::HConstant(Unique<Object> object, Unique<Map> object_map,
+                     bool has_stable_map_value, Representation r, HType type,
+                     bool is_not_in_new_space, bool boolean_value,
+                     bool is_undetectable, InstanceType instance_type)
+    : HTemplateInstruction<0>(type),
+      object_(object),
+      object_map_(object_map),
+      bit_field_(HasStableMapValueField::encode(has_stable_map_value) |
+                 HasSmiValueField::encode(false) |
+                 HasInt32ValueField::encode(false) |
+                 HasDoubleValueField::encode(false) |
+                 HasExternalReferenceValueField::encode(false) |
+                 IsNotInNewSpaceField::encode(is_not_in_new_space) |
+                 BooleanValueField::encode(boolean_value) |
+                 IsUndetectableField::encode(is_undetectable) |
+                 InstanceTypeField::encode(instance_type)) {
   DCHECK(!object.handle().is_null());
   DCHECK(!type.IsTaggedNumber() || type.IsNone());
   Initialize(r);
 }
 
 
-HConstant::HConstant(int32_t integer_value,
-                     Representation r,
-                     bool is_not_in_new_space,
-                     Unique<Object> object)
-  : object_(object),
-    object_map_(Handle<Map>::null()),
-    has_stable_map_value_(false),
-    has_smi_value_(Smi::IsValid(integer_value)),
-    has_int32_value_(true),
-    has_double_value_(true),
-    has_external_reference_value_(false),
-    is_not_in_new_space_(is_not_in_new_space),
-    boolean_value_(integer_value != 0),
-    is_undetectable_(false),
-    int32_value_(integer_value),
-    double_value_(FastI2D(integer_value)),
-    instance_type_(kUnknownInstanceType) {
+HConstant::HConstant(int32_t integer_value, Representation r,
+                     bool is_not_in_new_space, Unique<Object> object)
+    : object_(object),
+      object_map_(Handle<Map>::null()),
+      bit_field_(HasStableMapValueField::encode(false) |
+                 HasSmiValueField::encode(Smi::IsValid(integer_value)) |
+                 HasInt32ValueField::encode(true) |
+                 HasDoubleValueField::encode(true) |
+                 HasExternalReferenceValueField::encode(false) |
+                 IsNotInNewSpaceField::encode(is_not_in_new_space) |
+                 BooleanValueField::encode(integer_value != 0) |
+                 IsUndetectableField::encode(false) |
+                 InstanceTypeField::encode(kUnknownInstanceType)),
+      int32_value_(integer_value),
+      double_value_(FastI2D(integer_value)) {
   // It's possible to create a constant with a value in Smi-range but stored
   // in a (pre-existing) HeapNumber. See crbug.com/349878.
   bool could_be_heapobject = r.IsTagged() && !object.handle().is_null();
-  bool is_smi = has_smi_value_ && !could_be_heapobject;
+  bool is_smi = HasSmiValue() && !could_be_heapobject;
   set_type(is_smi ? HType::Smi() : HType::TaggedNumber());
   Initialize(r);
 }
 
 
-HConstant::HConstant(double double_value,
-                     Representation r,
-                     bool is_not_in_new_space,
-                     Unique<Object> object)
-  : object_(object),
-    object_map_(Handle<Map>::null()),
-    has_stable_map_value_(false),
-    has_int32_value_(IsInteger32(double_value)),
-    has_double_value_(true),
-    has_external_reference_value_(false),
-    is_not_in_new_space_(is_not_in_new_space),
-    boolean_value_(double_value != 0 && !std::isnan(double_value)),
-    is_undetectable_(false),
-    int32_value_(DoubleToInt32(double_value)),
-    double_value_(double_value),
-    instance_type_(kUnknownInstanceType) {
-  has_smi_value_ = has_int32_value_ && Smi::IsValid(int32_value_);
+HConstant::HConstant(double double_value, Representation r,
+                     bool is_not_in_new_space, Unique<Object> object)
+    : object_(object),
+      object_map_(Handle<Map>::null()),
+      bit_field_(HasStableMapValueField::encode(false) |
+                 HasInt32ValueField::encode(IsInteger32(double_value)) |
+                 HasDoubleValueField::encode(true) |
+                 HasExternalReferenceValueField::encode(false) |
+                 IsNotInNewSpaceField::encode(is_not_in_new_space) |
+                 BooleanValueField::encode(double_value != 0 &&
+                                           !std::isnan(double_value)) |
+                 IsUndetectableField::encode(false) |
+                 InstanceTypeField::encode(kUnknownInstanceType)),
+      int32_value_(HasInteger32Value() ? DoubleToInt32(double_value) : 0),
+      double_value_(double_value) {
+  bit_field_ = HasSmiValueField::update(
+      bit_field_, HasInteger32Value() && Smi::IsValid(int32_value_));
   // It's possible to create a constant with a value in Smi-range but stored
   // in a (pre-existing) HeapNumber. See crbug.com/349878.
   bool could_be_heapobject = r.IsTagged() && !object.handle().is_null();
-  bool is_smi = has_smi_value_ && !could_be_heapobject;
+  bool is_smi = HasSmiValue() && !could_be_heapobject;
   set_type(is_smi ? HType::Smi() : HType::TaggedNumber());
   Initialize(r);
 }
 
 
 HConstant::HConstant(ExternalReference reference)
-  : HTemplateInstruction<0>(HType::Any()),
-    object_(Unique<Object>(Handle<Object>::null())),
-    object_map_(Handle<Map>::null()),
-    has_stable_map_value_(false),
-    has_smi_value_(false),
-    has_int32_value_(false),
-    has_double_value_(false),
-    has_external_reference_value_(true),
-    is_not_in_new_space_(true),
-    boolean_value_(true),
-    is_undetectable_(false),
-    external_reference_value_(reference),
-    instance_type_(kUnknownInstanceType) {
+    : HTemplateInstruction<0>(HType::Any()),
+      object_(Unique<Object>(Handle<Object>::null())),
+      object_map_(Handle<Map>::null()),
+      bit_field_(
+          HasStableMapValueField::encode(false) |
+          HasSmiValueField::encode(false) | HasInt32ValueField::encode(false) |
+          HasDoubleValueField::encode(false) |
+          HasExternalReferenceValueField::encode(true) |
+          IsNotInNewSpaceField::encode(true) | BooleanValueField::encode(true) |
+          IsUndetectableField::encode(false) |
+          InstanceTypeField::encode(kUnknownInstanceType)),
+      external_reference_value_(reference) {
   Initialize(Representation::External());
 }
 
 
 void HConstant::Initialize(Representation r) {
   if (r.IsNone()) {
-    if (has_smi_value_ && SmiValuesAre31Bits()) {
+    if (HasSmiValue() && SmiValuesAre31Bits()) {
       r = Representation::Smi();
-    } else if (has_int32_value_) {
+    } else if (HasInteger32Value()) {
       r = Representation::Integer32();
-    } else if (has_double_value_) {
+    } else if (HasDoubleValue()) {
       r = Representation::Double();
-    } else if (has_external_reference_value_) {
+    } else if (HasExternalReferenceValue()) {
       r = Representation::External();
     } else {
       Handle<Object> object = object_.handle();
@@ -2822,22 +2842,26 @@
     // could cause heap object checks not to get emitted.
     object_ = Unique<Object>(Handle<Object>::null());
   }
+  if (r.IsSmiOrInteger32()) {
+    // If it's not a heap object, it can't be in new space.
+    bit_field_ = IsNotInNewSpaceField::update(bit_field_, true);
+  }
   set_representation(r);
   SetFlag(kUseGVN);
 }
 
 
 bool HConstant::ImmortalImmovable() const {
-  if (has_int32_value_) {
+  if (HasInteger32Value()) {
     return false;
   }
-  if (has_double_value_) {
+  if (HasDoubleValue()) {
     if (IsSpecialDouble()) {
       return true;
     }
     return false;
   }
-  if (has_external_reference_value_) {
+  if (HasExternalReferenceValue()) {
     return false;
   }
 
@@ -2847,7 +2871,7 @@
   DCHECK(!object_.IsKnownGlobal(heap->nan_value()));
   return
 #define IMMORTAL_IMMOVABLE_ROOT(name) \
-      object_.IsKnownGlobal(heap->name()) ||
+  object_.IsKnownGlobal(heap->root(Heap::k##name##RootIndex)) ||
       IMMORTAL_IMMOVABLE_ROOT_LIST(IMMORTAL_IMMOVABLE_ROOT)
 #undef IMMORTAL_IMMOVABLE_ROOT
 #define INTERNALIZED_STRING(name, value) \
@@ -2878,44 +2902,35 @@
 
 
 HConstant* HConstant::CopyToRepresentation(Representation r, Zone* zone) const {
-  if (r.IsSmi() && !has_smi_value_) return NULL;
-  if (r.IsInteger32() && !has_int32_value_) return NULL;
-  if (r.IsDouble() && !has_double_value_) return NULL;
-  if (r.IsExternal() && !has_external_reference_value_) return NULL;
-  if (has_int32_value_) {
-    return new(zone) HConstant(int32_value_, r, is_not_in_new_space_, object_);
+  if (r.IsSmi() && !HasSmiValue()) return NULL;
+  if (r.IsInteger32() && !HasInteger32Value()) return NULL;
+  if (r.IsDouble() && !HasDoubleValue()) return NULL;
+  if (r.IsExternal() && !HasExternalReferenceValue()) return NULL;
+  if (HasInteger32Value()) {
+    return new (zone) HConstant(int32_value_, r, NotInNewSpace(), object_);
   }
-  if (has_double_value_) {
-    return new(zone) HConstant(double_value_, r, is_not_in_new_space_, object_);
+  if (HasDoubleValue()) {
+    return new (zone) HConstant(double_value_, r, NotInNewSpace(), object_);
   }
-  if (has_external_reference_value_) {
+  if (HasExternalReferenceValue()) {
     return new(zone) HConstant(external_reference_value_);
   }
   DCHECK(!object_.handle().is_null());
-  return new(zone) HConstant(object_,
-                             object_map_,
-                             has_stable_map_value_,
-                             r,
-                             type_,
-                             is_not_in_new_space_,
-                             boolean_value_,
-                             is_undetectable_,
-                             instance_type_);
+  return new (zone) HConstant(object_, object_map_, HasStableMapValue(), r,
+                              type_, NotInNewSpace(), BooleanValue(),
+                              IsUndetectable(), GetInstanceType());
 }
 
 
 Maybe<HConstant*> HConstant::CopyToTruncatedInt32(Zone* zone) {
   HConstant* res = NULL;
-  if (has_int32_value_) {
-    res = new(zone) HConstant(int32_value_,
-                              Representation::Integer32(),
-                              is_not_in_new_space_,
-                              object_);
-  } else if (has_double_value_) {
-    res = new(zone) HConstant(DoubleToInt32(double_value_),
-                              Representation::Integer32(),
-                              is_not_in_new_space_,
-                              object_);
+  if (HasInteger32Value()) {
+    res = new (zone) HConstant(int32_value_, Representation::Integer32(),
+                               NotInNewSpace(), object_);
+  } else if (HasDoubleValue()) {
+    res = new (zone)
+        HConstant(DoubleToInt32(double_value_), Representation::Integer32(),
+                  NotInNewSpace(), object_);
   }
   return Maybe<HConstant*>(res != NULL, res);
 }
@@ -2936,12 +2951,12 @@
 }
 
 
-OStream& HConstant::PrintDataTo(OStream& os) const {  // NOLINT
-  if (has_int32_value_) {
+std::ostream& HConstant::PrintDataTo(std::ostream& os) const {  // NOLINT
+  if (HasInteger32Value()) {
     os << int32_value_ << " ";
-  } else if (has_double_value_) {
+  } else if (HasDoubleValue()) {
     os << double_value_ << " ";
-  } else if (has_external_reference_value_) {
+  } else if (HasExternalReferenceValue()) {
     os << reinterpret_cast<void*>(external_reference_value_.address()) << " ";
   } else {
     // The handle() method is silently and lazily mutating the object.
@@ -2950,12 +2965,12 @@
     if (HasStableMapValue()) os << "[stable-map] ";
     if (HasObjectMap()) os << "[map " << *ObjectMap().handle() << "] ";
   }
-  if (!is_not_in_new_space_) os << "[new space] ";
+  if (!NotInNewSpace()) os << "[new space] ";
   return os;
 }
 
 
-OStream& HBinaryOperation::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HBinaryOperation::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << NameOf(left()) << " " << NameOf(right());
   if (CheckFlag(kCanOverflow)) os << " !";
   if (CheckFlag(kBailoutOnMinusZero)) os << " -0?";
@@ -3182,25 +3197,28 @@
 }
 
 
-OStream& HCompareGeneric::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HCompareGeneric::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << Token::Name(token()) << " ";
   return HBinaryOperation::PrintDataTo(os);
 }
 
 
-OStream& HStringCompareAndBranch::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HStringCompareAndBranch::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   os << Token::Name(token()) << " ";
   return HControlInstruction::PrintDataTo(os);
 }
 
 
-OStream& HCompareNumericAndBranch::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HCompareNumericAndBranch::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   os << Token::Name(token()) << " " << NameOf(left()) << " " << NameOf(right());
   return HControlInstruction::PrintDataTo(os);
 }
 
 
-OStream& HCompareObjectEqAndBranch::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HCompareObjectEqAndBranch::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   os << NameOf(left()) << " " << NameOf(right());
   return HControlInstruction::PrintDataTo(os);
 }
@@ -3340,7 +3358,7 @@
 }
 
 
-OStream& HGoto::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HGoto::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << *SuccessorAt(0);
 }
 
@@ -3384,12 +3402,12 @@
 }
 
 
-OStream& HParameter::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HParameter::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << index();
 }
 
 
-OStream& HLoadNamedField::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HLoadNamedField::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << NameOf(object()) << access_;
 
   if (maps() != NULL) {
@@ -3405,13 +3423,14 @@
 }
 
 
-OStream& HLoadNamedGeneric::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HLoadNamedGeneric::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   Handle<String> n = Handle<String>::cast(name());
   return os << NameOf(object()) << "." << n->ToCString().get();
 }
 
 
-OStream& HLoadKeyed::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HLoadKeyed::PrintDataTo(std::ostream& os) const {  // NOLINT
   if (!is_external()) {
     os << NameOf(elements());
   } else {
@@ -3499,7 +3518,8 @@
 }
 
 
-OStream& HLoadKeyedGeneric::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HLoadKeyedGeneric::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   return os << NameOf(object()) << "[" << NameOf(key()) << "]";
 }
 
@@ -3541,14 +3561,15 @@
 }
 
 
-OStream& HStoreNamedGeneric::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HStoreNamedGeneric::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   Handle<String> n = Handle<String>::cast(name());
   return os << NameOf(object()) << "." << n->ToCString().get() << " = "
             << NameOf(value());
 }
 
 
-OStream& HStoreNamedField::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HStoreNamedField::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << NameOf(object()) << access_ << " = " << NameOf(value());
   if (NeedsWriteBarrier()) os << " (write-barrier)";
   if (has_transition()) os << " (transition map " << *transition_map() << ")";
@@ -3556,7 +3577,7 @@
 }
 
 
-OStream& HStoreKeyed::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HStoreKeyed::PrintDataTo(std::ostream& os) const {  // NOLINT
   if (!is_external()) {
     os << NameOf(elements());
   } else {
@@ -3571,13 +3592,15 @@
 }
 
 
-OStream& HStoreKeyedGeneric::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HStoreKeyedGeneric::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   return os << NameOf(object()) << "[" << NameOf(key())
             << "] = " << NameOf(value());
 }
 
 
-OStream& HTransitionElementsKind::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HTransitionElementsKind::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   os << NameOf(object());
   ElementsKind from_kind = original_map().handle()->elements_kind();
   ElementsKind to_kind = transitioned_map().handle()->elements_kind();
@@ -3590,7 +3613,7 @@
 }
 
 
-OStream& HLoadGlobalCell::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HLoadGlobalCell::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << "[" << *cell().handle() << "]";
   if (details_.IsConfigurable()) os << " (configurable)";
   if (details_.IsReadOnly()) os << " (read-only)";
@@ -3608,18 +3631,20 @@
 }
 
 
-OStream& HLoadGlobalGeneric::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HLoadGlobalGeneric::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   return os << name()->ToCString().get() << " ";
 }
 
 
-OStream& HInnerAllocatedObject::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HInnerAllocatedObject::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   os << NameOf(base_object()) << " offset ";
   return offset()->PrintTo(os);
 }
 
 
-OStream& HStoreGlobalCell::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HStoreGlobalCell::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << "[" << *cell().handle() << "] = " << NameOf(value());
   if (details_.IsConfigurable()) os << " (configurable)";
   if (details_.IsReadOnly()) os << " (read-only)";
@@ -3627,12 +3652,13 @@
 }
 
 
-OStream& HLoadContextSlot::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HLoadContextSlot::PrintDataTo(std::ostream& os) const {  // NOLINT
   return os << NameOf(value()) << "[" << slot_index() << "]";
 }
 
 
-OStream& HStoreContextSlot::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HStoreContextSlot::PrintDataTo(
+    std::ostream& os) const {  // NOLINT
   return os << NameOf(context()) << "[" << slot_index()
             << "] = " << NameOf(value());
 }
@@ -3987,7 +4013,7 @@
 }
 
 
-OStream& HAllocate::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HAllocate::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << NameOf(size()) << " (";
   if (IsNewSpaceAllocation()) os << "N";
   if (IsOldPointerSpaceAllocation()) os << "P";
@@ -4096,7 +4122,7 @@
 }
 
 
-OStream& HStringAdd::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HStringAdd::PrintDataTo(std::ostream& os) const {  // NOLINT
   if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
     os << "_CheckBoth";
   } else if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_LEFT) {
@@ -4431,7 +4457,7 @@
 #undef H_CONSTANT_DOUBLE
 
 
-OStream& HBitwise::PrintDataTo(OStream& os) const {  // NOLINT
+std::ostream& HBitwise::PrintDataTo(std::ostream& os) const {  // NOLINT
   os << Token::Name(op_) << " ";
   return HBitwiseBinaryOperation::PrintDataTo(os);
 }
@@ -4475,18 +4501,24 @@
 
 void HPhi::InferRepresentation(HInferRepresentationPhase* h_infer) {
   DCHECK(CheckFlag(kFlexibleRepresentation));
-  Representation new_rep = RepresentationFromInputs();
-  UpdateRepresentation(new_rep, h_infer, "inputs");
-  new_rep = RepresentationFromUses();
+  Representation new_rep = RepresentationFromUses();
   UpdateRepresentation(new_rep, h_infer, "uses");
+  new_rep = RepresentationFromInputs();
+  UpdateRepresentation(new_rep, h_infer, "inputs");
   new_rep = RepresentationFromUseRequirements();
   UpdateRepresentation(new_rep, h_infer, "use requirements");
 }
 
 
 Representation HPhi::RepresentationFromInputs() {
-  Representation r = Representation::None();
+  bool has_type_feedback =
+      smi_non_phi_uses() + int32_non_phi_uses() + double_non_phi_uses() > 0;
+  Representation r = representation();
   for (int i = 0; i < OperandCount(); ++i) {
+    // Ignore conservative Tagged assumption of parameters if we have
+    // reason to believe that it's too conservative.
+    if (has_type_feedback && OperandAt(i)->IsParameter()) continue;
+
     r = r.generalize(OperandAt(i)->KnownOptimalRepresentation());
   }
   return r;
@@ -4627,6 +4659,14 @@
 }
 
 
+HObjectAccess HObjectAccess::ForScriptContext(int index) {
+  DCHECK(index >= 0);
+  Portion portion = kInobject;
+  int offset = ScriptContextTable::GetContextOffset(index);
+  return HObjectAccess(portion, offset, Representation::Tagged());
+}
+
+
 HObjectAccess HObjectAccess::ForJSArrayOffset(int offset) {
   DCHECK(offset >= 0);
   Portion portion = kInobject;
@@ -4746,7 +4786,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const HObjectAccess& access) {
+std::ostream& operator<<(std::ostream& os, const HObjectAccess& access) {
   os << ".";
 
   switch (access.portion()) {
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 695c629..74f2711 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -5,15 +5,16 @@
 #ifndef V8_HYDROGEN_INSTRUCTIONS_H_
 #define V8_HYDROGEN_INSTRUCTIONS_H_
 
+#include <iosfwd>
+
 #include "src/v8.h"
 
 #include "src/allocation.h"
 #include "src/base/bits.h"
+#include "src/bit-vector.h"
 #include "src/code-stubs.h"
 #include "src/conversions.h"
-#include "src/data-flow.h"
 #include "src/deoptimizer.h"
-#include "src/feedback-slots.h"
 #include "src/hydrogen-types.h"
 #include "src/small-pointer-list.h"
 #include "src/unique.h"
@@ -35,7 +36,6 @@
 class HValue;
 class LInstruction;
 class LChunkBuilder;
-class OStream;
 
 #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
   V(ArithmeticBinaryOperation)                \
@@ -190,24 +190,21 @@
   V(TypedArrayElements)
 
 
-#define DECLARE_ABSTRACT_INSTRUCTION(type)                              \
-  virtual bool Is##type() const FINAL OVERRIDE { return true; }   \
-  static H##type* cast(HValue* value) {                                 \
-    DCHECK(value->Is##type());                                          \
-    return reinterpret_cast<H##type*>(value);                           \
+#define DECLARE_ABSTRACT_INSTRUCTION(type)     \
+  bool Is##type() const FINAL { return true; } \
+  static H##type* cast(HValue* value) {        \
+    DCHECK(value->Is##type());                 \
+    return reinterpret_cast<H##type*>(value);  \
   }
 
 
-#define DECLARE_CONCRETE_INSTRUCTION(type)              \
-  virtual LInstruction* CompileToLithium(               \
-     LChunkBuilder* builder) FINAL OVERRIDE;      \
-  static H##type* cast(HValue* value) {                 \
-    DCHECK(value->Is##type());                          \
-    return reinterpret_cast<H##type*>(value);           \
-  }                                                     \
-  virtual Opcode opcode() const FINAL OVERRIDE {  \
-    return HValue::k##type;                             \
-  }
+#define DECLARE_CONCRETE_INSTRUCTION(type)                      \
+  LInstruction* CompileToLithium(LChunkBuilder* builder) FINAL; \
+  static H##type* cast(HValue* value) {                         \
+    DCHECK(value->Is##type());                                  \
+    return reinterpret_cast<H##type*>(value);                   \
+  }                                                             \
+  Opcode opcode() const FINAL { return HValue::k##type; }
 
 
 enum PropertyAccessType { LOAD, STORE };
@@ -467,7 +464,7 @@
 };
 
 
-OStream& operator<<(OStream& os, const HSourcePosition& p);
+std::ostream& operator<<(std::ostream& os, const HSourcePosition& p);
 
 
 class HValue : public ZoneObject {
@@ -770,7 +767,7 @@
   virtual void FinalizeUniqueness() { }
 
   // Printing support.
-  virtual OStream& PrintTo(OStream& os) const = 0;  // NOLINT
+  virtual std::ostream& PrintTo(std::ostream& os) const = 0;  // NOLINT
 
   const char* Mnemonic() const;
 
@@ -887,7 +884,7 @@
     result.Remove(kOsrEntries);
     return result;
   }
-  friend OStream& operator<<(OStream& os, const ChangesOf& v);
+  friend std::ostream& operator<<(std::ostream& os, const ChangesOf& v);
 
   // A flag mask of all side effects that can make observable changes in
   // an executing program (i.e. are not safe to repeat, move or remove);
@@ -948,10 +945,10 @@
 };
 
 
-OStream& operator<<(OStream& os, const HValue& v);
-OStream& operator<<(OStream& os, const NameOf& v);
-OStream& operator<<(OStream& os, const TypeOf& v);
-OStream& operator<<(OStream& os, const ChangesOf& v);
+std::ostream& operator<<(std::ostream& os, const HValue& v);
+std::ostream& operator<<(std::ostream& os, const NameOf& v);
+std::ostream& operator<<(std::ostream& os, const TypeOf& v);
+std::ostream& operator<<(std::ostream& os, const ChangesOf& v);
 
 
 #define DECLARE_INSTRUCTION_FACTORY_P0(I)                                      \
@@ -1147,8 +1144,8 @@
   HInstruction* next() const { return next_; }
   HInstruction* previous() const { return previous_; }
 
-  virtual OStream& PrintTo(OStream& os) const OVERRIDE;  // NOLINT
-  virtual OStream& PrintDataTo(OStream& os) const;          // NOLINT
+  std::ostream& PrintTo(std::ostream& os) const OVERRIDE;          // NOLINT
+  virtual std::ostream& PrintDataTo(std::ostream& os) const;       // NOLINT
 
   bool IsLinked() const { return block() != NULL; }
   void Unlink();
@@ -1168,7 +1165,7 @@
   }
 
   // The position is a write-once variable.
-  virtual HSourcePosition position() const OVERRIDE {
+  HSourcePosition position() const OVERRIDE {
     return HSourcePosition(position_.position());
   }
   bool has_position() const {
@@ -1180,7 +1177,7 @@
     position_.set_position(position);
   }
 
-  virtual HSourcePosition operand_position(int index) const OVERRIDE {
+  HSourcePosition operand_position(int index) const OVERRIDE {
     const HSourcePosition pos = position_.operand_position(index);
     return pos.IsUnknown() ? position() : pos;
   }
@@ -1197,7 +1194,7 @@
   virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
 
 #ifdef DEBUG
-  virtual void Verify() OVERRIDE;
+  void Verify() OVERRIDE;
 #endif
 
   bool CanDeoptimize();
@@ -1215,7 +1212,7 @@
     SetDependsOnFlag(kOsrEntries);
   }
 
-  virtual void DeleteFromGraph() OVERRIDE { Unlink(); }
+  void DeleteFromGraph() OVERRIDE { Unlink(); }
 
  private:
   void InitializeAsFirst(HBasicBlock* block) {
@@ -1234,18 +1231,14 @@
 template<int V>
 class HTemplateInstruction : public HInstruction {
  public:
-  virtual int OperandCount() const FINAL OVERRIDE { return V; }
-  virtual HValue* OperandAt(int i) const FINAL OVERRIDE {
-    return inputs_[i];
-  }
+  int OperandCount() const FINAL { return V; }
+  HValue* OperandAt(int i) const FINAL { return inputs_[i]; }
 
  protected:
   explicit HTemplateInstruction(HType type = HType::Tagged())
       : HInstruction(type) {}
 
-  virtual void InternalSetOperandAt(int i, HValue* value) FINAL OVERRIDE {
-    inputs_[i] = value;
-  }
+  void InternalSetOperandAt(int i, HValue* value) FINAL { inputs_[i] = value; }
 
  private:
   EmbeddedContainer<HValue*, V> inputs_;
@@ -1258,7 +1251,7 @@
   virtual int SuccessorCount() const = 0;
   virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0;
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   virtual bool KnownSuccessorBlock(HBasicBlock** block) {
     *block = NULL;
@@ -1323,7 +1316,7 @@
 
 class HBlockEntry FINAL : public HTemplateInstruction<0> {
  public:
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
@@ -1343,12 +1336,12 @@
 
   HValue* value() const { return OperandAt(0); }
 
-  virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(DummyUse);
 };
@@ -1359,7 +1352,7 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
@@ -1373,16 +1366,16 @@
     SetSuccessorAt(0, target);
   }
 
-  virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
+  bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
     *block = FirstSuccessor();
     return true;
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(Goto)
 };
@@ -1398,12 +1391,12 @@
     return new(zone) HDeoptimize(reason, type, unreachable_continuation);
   }
 
-  virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
+  bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
     *block = NULL;
     return true;
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
@@ -1435,7 +1428,7 @@
     SetSuccessorAt(1, false_target);
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   HValue* value() const { return OperandAt(0); }
 };
@@ -1450,14 +1443,14 @@
                                  ToBooleanStub::Types,
                                  HBasicBlock*, HBasicBlock*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
-  virtual Representation observed_input_representation(int index) OVERRIDE;
+  Representation observed_input_representation(int index) OVERRIDE;
 
-  virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
+  bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   ToBooleanStub::Types expected_input_types() const {
     return expected_input_types_;
@@ -1485,7 +1478,7 @@
   DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>,
                                  HBasicBlock*, HBasicBlock*);
 
-  virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
+  bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
     if (known_successor_index() != kNoKnownSuccessorIndex) {
       *block = SuccessorAt(known_successor_index());
       return true;
@@ -1494,40 +1487,51 @@
     return false;
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   static const int kNoKnownSuccessorIndex = -1;
-  int known_successor_index() const { return known_successor_index_; }
-  void set_known_successor_index(int known_successor_index) {
-    known_successor_index_ = known_successor_index;
+  int known_successor_index() const {
+    return KnownSuccessorIndexField::decode(bit_field_) -
+           kInternalKnownSuccessorOffset;
+  }
+  void set_known_successor_index(int index) {
+    DCHECK(index >= 0 - kInternalKnownSuccessorOffset);
+    bit_field_ = KnownSuccessorIndexField::update(
+        bit_field_, index + kInternalKnownSuccessorOffset);
   }
 
   Unique<Map> map() const { return map_; }
-  bool map_is_stable() const { return map_is_stable_; }
+  bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
   DECLARE_CONCRETE_INSTRUCTION(CompareMap)
 
  protected:
-  virtual int RedefinedOperandIndex() { return 0; }
+  int RedefinedOperandIndex() OVERRIDE { return 0; }
 
  private:
-  HCompareMap(HValue* value,
-              Handle<Map> map,
-              HBasicBlock* true_target = NULL,
+  HCompareMap(HValue* value, Handle<Map> map, HBasicBlock* true_target = NULL,
               HBasicBlock* false_target = NULL)
       : HUnaryControlInstruction(value, true_target, false_target),
-        known_successor_index_(kNoKnownSuccessorIndex),
-        map_is_stable_(map->is_stable()),
+        bit_field_(KnownSuccessorIndexField::encode(
+                       kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset) |
+                   MapIsStableField::encode(map->is_stable())),
         map_(Unique<Map>::CreateImmovable(map)) {
     set_representation(Representation::Tagged());
   }
 
-  int known_successor_index_ : 31;
-  bool map_is_stable_ : 1;
+  // BitFields can only store unsigned values, so use an offset.
+  // Adding kInternalKnownSuccessorOffset must yield an unsigned value.
+  static const int kInternalKnownSuccessorOffset = 1;
+  STATIC_ASSERT(kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset >= 0);
+
+  class KnownSuccessorIndexField : public BitField<int, 0, 31> {};
+  class MapIsStableField : public BitField<bool, 31, 1> {};
+
+  uint32_t bit_field_;
   Unique<Map> map_;
 };
 
@@ -1538,14 +1542,14 @@
     return new(zone) HContext();
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
   DECLARE_CONCRETE_INSTRUCTION(Context)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   HContext() {
@@ -1553,7 +1557,7 @@
     SetFlag(kUseGVN);
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 };
 
 
@@ -1562,13 +1566,13 @@
   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*);
   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     // TODO(titzer): require an Int32 input for faster returns.
     if (index == 2) return Representation::Smi();
     return Representation::Tagged();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   HValue* value() const { return OperandAt(0); }
   HValue* context() const { return OperandAt(1); }
@@ -1589,7 +1593,7 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
@@ -1611,7 +1615,7 @@
   }
 
   HValue* value() const { return OperandAt(0); }
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 };
 
 
@@ -1619,7 +1623,7 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
@@ -1637,11 +1641,16 @@
 
   HValue* value() const { return OperandAt(0); }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation observed_input_representation(int index) OVERRIDE {
+    // We haven't actually *observed* this, but it's closer to the truth
+    // than 'None'.
+    return representation();  // Same as the output representation.
+  }
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return representation();  // Same as the output representation.
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
 
@@ -1683,29 +1692,29 @@
     return CheckUsesForFlag(kAllowUndefinedAsNaN);
   }
 
-  virtual HType CalculateInferredType() OVERRIDE;
-  virtual HValue* Canonicalize() OVERRIDE;
+  HType CalculateInferredType() OVERRIDE;
+  HValue* Canonicalize() OVERRIDE;
 
   Representation from() const { return value()->representation(); }
   Representation to() const { return representation(); }
   bool deoptimize_on_minus_zero() const {
     return CheckFlag(kBailoutOnMinusZero);
   }
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return from();
   }
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(Change)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
-  virtual bool IsDeletable() const OVERRIDE {
+  bool IsDeletable() const OVERRIDE {
     return !from().IsTagged() || value()->type().IsSmi();
   }
 };
@@ -1715,14 +1724,14 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
   DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   explicit HClampToUint8(HValue* value)
@@ -1732,7 +1741,7 @@
     SetFlag(kUseGVN);
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 };
 
 
@@ -1741,7 +1750,7 @@
   enum Bits { HIGH, LOW };
   DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Double();
   }
 
@@ -1750,7 +1759,7 @@
   Bits bits() { return bits_; }
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits();
   }
 
@@ -1761,7 +1770,7 @@
     SetFlag(kUseGVN);
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 
   Bits bits_;
 };
@@ -1771,7 +1780,7 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Integer32();
   }
 
@@ -1781,7 +1790,7 @@
   HValue* lo() { return OperandAt(1); }
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   explicit HConstructDouble(HValue* hi, HValue* lo) {
@@ -1791,7 +1800,7 @@
     SetOperandAt(1, lo);
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 };
 
 
@@ -1803,20 +1812,18 @@
 
 class HSimulate FINAL : public HInstruction {
  public:
-  HSimulate(BailoutId ast_id,
-            int pop_count,
-            Zone* zone,
+  HSimulate(BailoutId ast_id, int pop_count, Zone* zone,
             RemovableSimulate removable)
       : ast_id_(ast_id),
         pop_count_(pop_count),
         values_(2, zone),
         assigned_indexes_(2, zone),
         zone_(zone),
-        removable_(removable),
-        done_with_replay_(false) {}
+        bit_field_(RemovableField::encode(removable) |
+                   DoneWithReplayField::encode(false)) {}
   ~HSimulate() {}
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   bool HasAstId() const { return !ast_id_.IsNone(); }
   BailoutId ast_id() const { return ast_id_; }
@@ -1846,18 +1853,18 @@
     }
     return -1;
   }
-  virtual int OperandCount() const OVERRIDE { return values_.length(); }
-  virtual HValue* OperandAt(int index) const OVERRIDE {
-    return values_[index];
-  }
+  int OperandCount() const OVERRIDE { return values_.length(); }
+  HValue* OperandAt(int index) const OVERRIDE { return values_[index]; }
 
-  virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
   void MergeWith(ZoneList<HSimulate*>* list);
-  bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; }
+  bool is_candidate_for_removal() {
+    return RemovableField::decode(bit_field_) == REMOVABLE_SIMULATE;
+  }
 
   // Replay effects of this instruction on the given environment.
   void ReplayEnvironment(HEnvironment* env);
@@ -1865,13 +1872,13 @@
   DECLARE_CONCRETE_INSTRUCTION(Simulate)
 
 #ifdef DEBUG
-  virtual void Verify() OVERRIDE;
+  void Verify() OVERRIDE;
   void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
   Handle<JSFunction> closure() const { return closure_; }
 #endif
 
  protected:
-  virtual void InternalSetOperandAt(int index, HValue* value) OVERRIDE {
+  void InternalSetOperandAt(int index, HValue* value) OVERRIDE {
     values_[index] = value;
   }
 
@@ -1891,13 +1898,22 @@
     }
     return false;
   }
+  bool is_done_with_replay() const {
+    return DoneWithReplayField::decode(bit_field_);
+  }
+  void set_done_with_replay() {
+    bit_field_ = DoneWithReplayField::update(bit_field_, true);
+  }
+
+  class RemovableField : public BitField<RemovableSimulate, 0, 1> {};
+  class DoneWithReplayField : public BitField<bool, 1, 1> {};
+
   BailoutId ast_id_;
   int pop_count_;
   ZoneList<HValue*> values_;
   ZoneList<int> assigned_indexes_;
   Zone* zone_;
-  RemovableSimulate removable_ : 2;
-  bool done_with_replay_ : 1;
+  uint32_t bit_field_;
 
 #ifdef DEBUG
   Handle<JSFunction> closure_;
@@ -1918,11 +1934,11 @@
     next_simulate_ = simulate;
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
 #ifdef DEBUG
   void set_closure(Handle<JSFunction> closure) {
@@ -1960,7 +1976,7 @@
 
   HValue* context() { return OperandAt(0); }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -2015,7 +2031,7 @@
   void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone);
   ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   Handle<JSFunction> closure() const { return closure_; }
   HConstant* closure_context() const { return closure_context_; }
@@ -2026,7 +2042,7 @@
   InliningKind inlining_kind() const { return inlining_kind_; }
   BailoutId ReturnId() const { return return_id_; }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
@@ -2072,11 +2088,11 @@
       : entry_(entry),
         drop_count_(drop_count) { }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
-  virtual int argument_delta() const OVERRIDE {
+  int argument_delta() const OVERRIDE {
     return entry_->arguments_pushed() ? -drop_count_ : 0;
   }
 
@@ -2123,28 +2139,22 @@
     return instr;
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual int argument_delta() const OVERRIDE { return inputs_.length(); }
+  int argument_delta() const OVERRIDE { return inputs_.length(); }
   HValue* argument(int i) { return OperandAt(i); }
 
-  virtual int OperandCount() const FINAL OVERRIDE {
-    return inputs_.length();
-  }
-  virtual HValue* OperandAt(int i) const FINAL OVERRIDE {
-    return inputs_[i];
-  }
+  int OperandCount() const FINAL { return inputs_.length(); }
+  HValue* OperandAt(int i) const FINAL { return inputs_[i]; }
 
   void AddInput(HValue* value);
 
   DECLARE_CONCRETE_INSTRUCTION(PushArguments)
 
  protected:
-  virtual void InternalSetOperandAt(int i, HValue* value) FINAL OVERRIDE {
-    inputs_[i] = value;
-  }
+  void InternalSetOperandAt(int i, HValue* value) FINAL { inputs_[i] = value; }
 
  private:
   explicit HPushArguments(Zone* zone)
@@ -2160,14 +2170,14 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
   DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   HThisFunction() {
@@ -2175,7 +2185,7 @@
     SetFlag(kUseGVN);
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 };
 
 
@@ -2191,7 +2201,7 @@
 
   DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -2220,17 +2230,13 @@
     this->SetAllSideEffects();
   }
 
-  virtual HType CalculateInferredType() FINAL OVERRIDE {
-    return HType::Tagged();
-  }
+  HType CalculateInferredType() FINAL { return HType::Tagged(); }
 
   virtual int argument_count() const {
     return argument_count_;
   }
 
-  virtual int argument_delta() const OVERRIDE {
-    return -argument_count();
-  }
+  int argument_delta() const OVERRIDE { return -argument_count(); }
 
  private:
   int argument_count_;
@@ -2244,12 +2250,11 @@
     SetOperandAt(0, value);
   }
 
-  virtual Representation RequiredInputRepresentation(
-      int index) FINAL OVERRIDE {
+  Representation RequiredInputRepresentation(int index) FINAL {
     return Representation::Tagged();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   HValue* value() const { return OperandAt(0); }
 };
@@ -2263,10 +2268,9 @@
     SetOperandAt(1, second);
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(
-      int index) FINAL OVERRIDE {
+  Representation RequiredInputRepresentation(int index) FINAL {
     return Representation::Tagged();
   }
 
@@ -2285,19 +2289,16 @@
 
   HValue* function() const { return OperandAt(0); }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(
-      int index) FINAL OVERRIDE {
+  Representation RequiredInputRepresentation(int index) FINAL {
     DCHECK(index == 0);
     return Representation::Tagged();
   }
 
   bool pass_argument_count() const { return pass_argument_count_; }
 
-  virtual bool HasStackCheck() FINAL OVERRIDE {
-    return has_stack_check_;
-  }
+  bool HasStackCheck() FINAL { return has_stack_check_; }
 
   DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)
 
@@ -2318,27 +2319,26 @@
 };
 
 
+enum CallMode { NORMAL_CALL, TAIL_CALL };
+
+
 class HCallWithDescriptor FINAL : public HInstruction {
  public:
   static HCallWithDescriptor* New(Zone* zone, HValue* context, HValue* target,
                                   int argument_count,
                                   CallInterfaceDescriptor descriptor,
-                                  const Vector<HValue*>& operands) {
+                                  const Vector<HValue*>& operands,
+                                  CallMode call_mode = NORMAL_CALL) {
     DCHECK(operands.length() == descriptor.GetEnvironmentLength());
-    HCallWithDescriptor* res = new (zone)
-        HCallWithDescriptor(target, argument_count, descriptor, operands, zone);
+    HCallWithDescriptor* res = new (zone) HCallWithDescriptor(
+        target, argument_count, descriptor, operands, call_mode, zone);
     return res;
   }
 
-  virtual int OperandCount() const FINAL OVERRIDE {
-    return values_.length();
-  }
-  virtual HValue* OperandAt(int index) const FINAL OVERRIDE {
-    return values_[index];
-  }
+  int OperandCount() const FINAL { return values_.length(); }
+  HValue* OperandAt(int index) const FINAL { return values_[index]; }
 
-  virtual Representation RequiredInputRepresentation(
-      int index) FINAL OVERRIDE {
+  Representation RequiredInputRepresentation(int index) FINAL {
     if (index == 0) {
       return Representation::Tagged();
     } else {
@@ -2350,17 +2350,15 @@
 
   DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
 
-  virtual HType CalculateInferredType() FINAL OVERRIDE {
-    return HType::Tagged();
-  }
+  HType CalculateInferredType() FINAL { return HType::Tagged(); }
+
+  bool IsTailCall() const { return call_mode_ == TAIL_CALL; }
 
   virtual int argument_count() const {
     return argument_count_;
   }
 
-  virtual int argument_delta() const OVERRIDE {
-    return -argument_count_;
-  }
+  int argument_delta() const OVERRIDE { return -argument_count_; }
 
   CallInterfaceDescriptor descriptor() const { return descriptor_; }
 
@@ -2368,16 +2366,20 @@
     return OperandAt(0);
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
  private:
   // The argument count includes the receiver.
   HCallWithDescriptor(HValue* target, int argument_count,
                       CallInterfaceDescriptor descriptor,
-                      const Vector<HValue*>& operands, Zone* zone)
+                      const Vector<HValue*>& operands, CallMode call_mode,
+                      Zone* zone)
       : descriptor_(descriptor),
-        values_(descriptor.GetEnvironmentLength() + 1, zone) {
-    argument_count_ = argument_count;
+        values_(descriptor.GetEnvironmentLength() + 1, zone),
+        argument_count_(argument_count),
+        call_mode_(call_mode) {
+    // We can only tail call without any stack arguments.
+    DCHECK(call_mode != TAIL_CALL || argument_count == 0);
     AddOperand(target, zone);
     for (int i = 0; i < operands.length(); i++) {
       AddOperand(operands[i], zone);
@@ -2391,14 +2393,14 @@
     SetOperandAt(values_.length() - 1, v);
   }
 
-  void InternalSetOperandAt(int index,
-                            HValue* value) FINAL OVERRIDE {
+  void InternalSetOperandAt(int index, HValue* value) FINAL {
     values_[index] = value;
   }
 
   CallInterfaceDescriptor descriptor_;
   ZoneList<HValue*> values_;
   int argument_count_;
+  CallMode call_mode_;
 };
 
 
@@ -2433,9 +2435,7 @@
   Handle<JSFunction> known_function() { return known_function_; }
   int formal_parameter_count() const { return formal_parameter_count_; }
 
-  virtual bool HasStackCheck() FINAL OVERRIDE {
-    return has_stack_check_;
-  }
+  bool HasStackCheck() FINAL { return has_stack_check_; }
 
   DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
 
@@ -2463,7 +2463,7 @@
 
   DECLARE_CONCRETE_INSTRUCTION(CallFunction)
 
-  virtual int argument_delta() const OVERRIDE { return -argument_count(); }
+  int argument_delta() const OVERRIDE { return -argument_count(); }
 
  private:
   HCallFunction(HValue* context,
@@ -2501,7 +2501,7 @@
   HValue* context() { return first(); }
   HValue* constructor() { return second(); }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   ElementsKind elements_kind() const { return elements_kind_; }
 
@@ -2524,7 +2524,7 @@
                                               const Runtime::Function*,
                                               int);
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   HValue* context() { return OperandAt(0); }
   const Runtime::Function* function() const { return c_function_; }
@@ -2534,7 +2534,7 @@
     save_doubles_ = save_doubles;
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -2560,14 +2560,14 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
   DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   explicit HMapEnumLength(HValue* value)
@@ -2577,7 +2577,7 @@
     SetDependsOnFlag(kMaps);
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 };
 
 
@@ -2591,9 +2591,9 @@
   HValue* context() const { return OperandAt(0); }
   HValue* value() const { return OperandAt(1); }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     if (index == 0) {
       return Representation::Tagged();
     } else {
@@ -2617,11 +2617,11 @@
     }
   }
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
-  virtual HValue* Canonicalize() OVERRIDE;
-  virtual Representation RepresentationFromUses() OVERRIDE;
-  virtual Representation RepresentationFromInputs() OVERRIDE;
+  HValue* Canonicalize() OVERRIDE;
+  Representation RepresentationFromUses() OVERRIDE;
+  Representation RepresentationFromInputs() OVERRIDE;
 
   BuiltinFunctionId op() const { return op_; }
   const char* OpName() const;
@@ -2629,7 +2629,7 @@
   DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
     return op_ == b->op();
   }
@@ -2681,7 +2681,7 @@
     SetFlag(kAllowUndefinedAsNaN);
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 
   HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
   HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
@@ -2695,7 +2695,7 @@
   DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
   DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
@@ -2704,7 +2704,7 @@
   DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     HLoadRoot* b = HLoadRoot::cast(other);
     return index_ == b->index_;
   }
@@ -2716,9 +2716,10 @@
     // TODO(bmeurer): We'll need kDependsOnRoots once we add the
     // corresponding HStoreRoot instruction.
     SetDependsOnFlag(kCalls);
+    set_representation(Representation::Tagged());
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 
   const Heap::RootListIndex index_;
 };
@@ -2741,27 +2742,29 @@
     return new(zone) HCheckMaps(value, maps, typecheck);
   }
 
-  bool IsStabilityCheck() const { return is_stability_check_; }
+  bool IsStabilityCheck() const {
+    return IsStabilityCheckField::decode(bit_field_);
+  }
   void MarkAsStabilityCheck() {
-    maps_are_stable_ = true;
-    has_migration_target_ = false;
-    is_stability_check_ = true;
+    bit_field_ = MapsAreStableField::encode(true) |
+                 HasMigrationTargetField::encode(false) |
+                 IsStabilityCheckField::encode(true);
     ClearChangesFlag(kNewSpacePromotion);
     ClearDependsOnFlag(kElementsKind);
     ClearDependsOnFlag(kMaps);
   }
 
-  virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual HType CalculateInferredType() OVERRIDE {
+  HType CalculateInferredType() OVERRIDE {
     if (value()->type().IsHeapObject()) return value()->type();
     return HType::HeapObject();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   HValue* value() const { return OperandAt(0); }
   HValue* typecheck() const { return OperandAt(1); }
@@ -2769,11 +2772,15 @@
   const UniqueSet<Map>* maps() const { return maps_; }
   void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
 
-  bool maps_are_stable() const { return maps_are_stable_; }
+  bool maps_are_stable() const {
+    return MapsAreStableField::decode(bit_field_);
+  }
 
-  bool HasMigrationTarget() const { return has_migration_target_; }
+  bool HasMigrationTarget() const {
+    return HasMigrationTargetField::decode(bit_field_);
+  }
 
-  virtual HValue* Canonicalize() OVERRIDE;
+  HValue* Canonicalize() OVERRIDE;
 
   static HCheckMaps* CreateAndInsertAfter(Zone* zone,
                                           HValue* value,
@@ -2795,17 +2802,19 @@
   DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     return this->maps()->Equals(HCheckMaps::cast(other)->maps());
   }
 
-  virtual int RedefinedOperandIndex() { return 0; }
+  int RedefinedOperandIndex() OVERRIDE { return 0; }
 
  private:
   HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
-      : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
-        has_migration_target_(false), is_stability_check_(false),
-        maps_are_stable_(maps_are_stable) {
+      : HTemplateInstruction<2>(HType::HeapObject()),
+        maps_(maps),
+        bit_field_(HasMigrationTargetField::encode(false) |
+                   IsStabilityCheckField::encode(false) |
+                   MapsAreStableField::encode(maps_are_stable)) {
     DCHECK_NE(0, maps->size());
     SetOperandAt(0, value);
     // Use the object value for the dependency.
@@ -2817,9 +2826,11 @@
   }
 
   HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
-      : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
-        has_migration_target_(false), is_stability_check_(false),
-        maps_are_stable_(true) {
+      : HTemplateInstruction<2>(HType::HeapObject()),
+        maps_(maps),
+        bit_field_(HasMigrationTargetField::encode(false) |
+                   IsStabilityCheckField::encode(false) |
+                   MapsAreStableField::encode(true)) {
     DCHECK_NE(0, maps->size());
     SetOperandAt(0, value);
     // Use the object value for the dependency if NULL is passed.
@@ -2830,16 +2841,22 @@
     SetDependsOnFlag(kElementsKind);
     for (int i = 0; i < maps->size(); ++i) {
       Handle<Map> map = maps->at(i).handle();
-      if (map->is_migration_target()) has_migration_target_ = true;
-      if (!map->is_stable()) maps_are_stable_ = false;
+      if (map->is_migration_target()) {
+        bit_field_ = HasMigrationTargetField::update(bit_field_, true);
+      }
+      if (!map->is_stable()) {
+        bit_field_ = MapsAreStableField::update(bit_field_, false);
+      }
     }
-    if (has_migration_target_) SetChangesFlag(kNewSpacePromotion);
+    if (HasMigrationTarget()) SetChangesFlag(kNewSpacePromotion);
   }
 
+  class HasMigrationTargetField : public BitField<bool, 0, 1> {};
+  class IsStabilityCheckField : public BitField<bool, 1, 1> {};
+  class MapsAreStableField : public BitField<bool, 2, 1> {};
+
   const UniqueSet<Map>* maps_;
-  bool has_migration_target_ : 1;
-  bool is_stability_check_ : 1;
-  bool maps_are_stable_ : 1;
+  uint32_t bit_field_;
 };
 
 
@@ -2862,19 +2879,19 @@
     return new(zone) HCheckValue(value, target, object_in_new_space);
   }
 
-  virtual void FinalizeUniqueness() OVERRIDE {
+  void FinalizeUniqueness() OVERRIDE {
     object_ = Unique<HeapObject>(object_.handle());
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual HValue* Canonicalize() OVERRIDE;
+  HValue* Canonicalize() OVERRIDE;
 
 #ifdef DEBUG
-  virtual void Verify() OVERRIDE;
+  void Verify() OVERRIDE;
 #endif
 
   Unique<HeapObject> object() const { return object_; }
@@ -2883,7 +2900,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CheckValue)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     HCheckValue* b = HCheckValue::cast(other);
     return object_ == b->object_;
   }
@@ -2915,13 +2932,13 @@
 
   DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual HType CalculateInferredType() OVERRIDE {
+  HType CalculateInferredType() OVERRIDE {
     switch (check_) {
       case IS_SPEC_OBJECT: return HType::JSObject();
       case IS_JS_ARRAY: return HType::JSArray();
@@ -2932,7 +2949,7 @@
     return HType::Tagged();
   }
 
-  virtual HValue* Canonicalize() OVERRIDE;
+  HValue* Canonicalize() OVERRIDE;
 
   bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
   void GetCheckInterval(InstanceType* first, InstanceType* last);
@@ -2946,12 +2963,12 @@
   // TODO(ager): It could be nice to allow the ommision of instance
   // type checks if we have already performed an instance type check
   // with a larger range.
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     HCheckInstanceType* b = HCheckInstanceType::cast(other);
     return check_ == b->check_;
   }
 
-  virtual int RedefinedOperandIndex() { return 0; }
+  int RedefinedOperandIndex() OVERRIDE { return 0; }
 
  private:
   const char* GetCheckName() const;
@@ -2970,11 +2987,11 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual HValue* Canonicalize() OVERRIDE {
+  HValue* Canonicalize() OVERRIDE {
     HType value_type = value()->type();
     if (value_type.IsSmi()) {
       return NULL;
@@ -2985,7 +3002,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
@@ -2999,28 +3016,28 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
 
-  virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual HType CalculateInferredType() OVERRIDE {
+  HType CalculateInferredType() OVERRIDE {
     if (value()->type().IsHeapObject()) return value()->type();
     return HType::HeapObject();
   }
 
 #ifdef DEBUG
-  virtual void Verify() OVERRIDE;
+  void Verify() OVERRIDE;
 #endif
 
-  virtual HValue* Canonicalize() OVERRIDE {
+  HValue* Canonicalize() OVERRIDE {
     return value()->type().IsHeapObject() ? NULL : this;
   }
 
   DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
@@ -3266,22 +3283,20 @@
     SetFlag(kAllowUndefinedAsNaN);
   }
 
-  virtual Representation RepresentationFromInputs() OVERRIDE;
+  Representation RepresentationFromInputs() OVERRIDE;
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
   virtual void InferRepresentation(
       HInferRepresentationPhase* h_infer) OVERRIDE;
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return representation();
   }
-  virtual Representation KnownOptimalRepresentation() OVERRIDE {
+  Representation KnownOptimalRepresentation() OVERRIDE {
     return representation();
   }
-  virtual HType CalculateInferredType() OVERRIDE;
-  virtual int OperandCount() const OVERRIDE { return inputs_.length(); }
-  virtual HValue* OperandAt(int index) const OVERRIDE {
-    return inputs_[index];
-  }
+  HType CalculateInferredType() OVERRIDE;
+  int OperandCount() const OVERRIDE { return inputs_.length(); }
+  HValue* OperandAt(int index) const OVERRIDE { return inputs_[index]; }
   HValue* GetRedundantReplacement();
   void AddInput(HValue* value);
   bool HasRealUses();
@@ -3289,7 +3304,7 @@
   bool IsReceiver() const { return merged_index_ == 0; }
   bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
 
-  virtual HSourcePosition position() const OVERRIDE;
+  HSourcePosition position() const OVERRIDE;
 
   int merged_index() const { return merged_index_; }
 
@@ -3308,10 +3323,10 @@
     induction_variable_data_ = InductionVariableData::ExaminePhi(this);
   }
 
-  virtual OStream& PrintTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
 #ifdef DEBUG
-  virtual void Verify() OVERRIDE;
+  void Verify() OVERRIDE;
 #endif
 
   void InitRealUses(int id);
@@ -3348,7 +3363,7 @@
     DCHECK(value->IsPhi());
     return reinterpret_cast<HPhi*>(value);
   }
-  virtual Opcode opcode() const OVERRIDE { return HValue::kPhi; }
+  Opcode opcode() const OVERRIDE { return HValue::kPhi; }
 
   void SimplifyConstantInputs();
 
@@ -3356,8 +3371,8 @@
   static const int kInvalidMergedIndex = -1;
 
  protected:
-  virtual void DeleteFromGraph() OVERRIDE;
-  virtual void InternalSetOperandAt(int index, HValue* value) OVERRIDE {
+  void DeleteFromGraph() OVERRIDE;
+  void InternalSetOperandAt(int index, HValue* value) OVERRIDE {
     inputs_[index] = value;
   }
 
@@ -3371,7 +3386,7 @@
   InductionVariableData* induction_variable_data_;
 
   // TODO(titzer): we can't eliminate the receiver for generating backtraces
-  virtual bool IsDeletable() const OVERRIDE { return !IsReceiver(); }
+  bool IsDeletable() const OVERRIDE { return !IsReceiver(); }
 };
 
 
@@ -3380,24 +3395,16 @@
  public:
   HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
 
-  virtual int OperandCount() const FINAL OVERRIDE {
-    return values_.length();
-  }
-  virtual HValue* OperandAt(int index) const FINAL OVERRIDE {
-    return values_[index];
-  }
+  int OperandCount() const FINAL { return values_.length(); }
+  HValue* OperandAt(int index) const FINAL { return values_[index]; }
 
-  virtual bool HasEscapingOperandAt(int index) FINAL OVERRIDE {
-    return false;
-  }
-  virtual Representation RequiredInputRepresentation(
-      int index) FINAL OVERRIDE {
+  bool HasEscapingOperandAt(int index) FINAL { return false; }
+  Representation RequiredInputRepresentation(int index) FINAL {
     return Representation::None();
   }
 
  protected:
-  virtual void InternalSetOperandAt(int index,
-                                    HValue* value) FINAL OVERRIDE {
+  void InternalSetOperandAt(int index, HValue* value) FINAL {
     values_[index] = value;
   }
 
@@ -3460,7 +3467,7 @@
   // Replay effects of this instruction on the given environment.
   void ReplayEnvironment(HEnvironment* env);
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
 
@@ -3470,7 +3477,7 @@
   // Note that we cannot DCE captured objects as they are used to replay
   // the environment. This method is here as an explicit reminder.
   // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
-  virtual bool IsDeletable() const FINAL OVERRIDE { return false; }
+  bool IsDeletable() const FINAL { return false; }
 };
 
 
@@ -3491,7 +3498,7 @@
         zone, context, value, representation));
   }
 
-  virtual Handle<Map> GetMonomorphicJSObjectMap() OVERRIDE {
+  Handle<Map> GetMonomorphicJSObjectMap() OVERRIDE {
     Handle<Object> object = object_.handle();
     if (!object.is_null() && object->IsHeapObject()) {
       return v8::internal::handle(HeapObject::cast(*object)->map());
@@ -3536,36 +3543,33 @@
           isolate->factory()->NewNumber(double_value_, TENURED));
     }
     AllowDeferredHandleDereference smi_check;
-    DCHECK(has_int32_value_ || !object_.handle()->IsSmi());
+    DCHECK(HasInteger32Value() || !object_.handle()->IsSmi());
     return object_.handle();
   }
 
   bool IsSpecialDouble() const {
-    return has_double_value_ &&
+    return HasDoubleValue() &&
            (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) ||
             FixedDoubleArray::is_the_hole_nan(double_value_) ||
             std::isnan(double_value_));
   }
 
   bool NotInNewSpace() const {
-    return is_not_in_new_space_;
+    return IsNotInNewSpaceField::decode(bit_field_);
   }
 
   bool ImmortalImmovable() const;
 
   bool IsCell() const {
-    return instance_type_ == CELL_TYPE || instance_type_ == PROPERTY_CELL_TYPE;
+    InstanceType instance_type = GetInstanceType();
+    return instance_type == CELL_TYPE || instance_type == PROPERTY_CELL_TYPE;
   }
 
-  bool IsMap() const {
-    return instance_type_ == MAP_TYPE;
-  }
-
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
-  virtual Representation KnownOptimalRepresentation() OVERRIDE {
+  Representation KnownOptimalRepresentation() OVERRIDE {
     if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi();
     if (HasInteger32Value()) return Representation::Integer32();
     if (HasNumberValue()) return Representation::Double();
@@ -3573,18 +3577,22 @@
     return Representation::Tagged();
   }
 
-  virtual bool EmitAtUses() OVERRIDE;
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  bool EmitAtUses() OVERRIDE;
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
   HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
   Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
   Maybe<HConstant*> CopyToTruncatedNumber(Zone* zone);
-  bool HasInteger32Value() const { return has_int32_value_; }
+  bool HasInteger32Value() const {
+    return HasInt32ValueField::decode(bit_field_);
+  }
   int32_t Integer32Value() const {
     DCHECK(HasInteger32Value());
     return int32_value_;
   }
-  bool HasSmiValue() const { return has_smi_value_; }
-  bool HasDoubleValue() const { return has_double_value_; }
+  bool HasSmiValue() const { return HasSmiValueField::decode(bit_field_); }
+  bool HasDoubleValue() const {
+    return HasDoubleValueField::decode(bit_field_);
+  }
   double DoubleValue() const {
     DCHECK(HasDoubleValue());
     return double_value_;
@@ -3596,7 +3604,7 @@
     return object_.IsInitialized() &&
            object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
   }
-  bool HasNumberValue() const { return has_double_value_; }
+  bool HasNumberValue() const { return HasDoubleValue(); }
   int32_t NumberValueAsInteger32() const {
     DCHECK(HasNumberValue());
     // Irrespective of whether a numeric HConstant can be safely
@@ -3605,38 +3613,42 @@
     return int32_value_;
   }
   bool HasStringValue() const {
-    if (has_double_value_ || has_int32_value_) return false;
+    if (HasNumberValue()) return false;
     DCHECK(!object_.handle().is_null());
-    return instance_type_ < FIRST_NONSTRING_TYPE;
+    return GetInstanceType() < FIRST_NONSTRING_TYPE;
   }
   Handle<String> StringValue() const {
     DCHECK(HasStringValue());
     return Handle<String>::cast(object_.handle());
   }
   bool HasInternalizedStringValue() const {
-    return HasStringValue() && StringShape(instance_type_).IsInternalized();
+    return HasStringValue() && StringShape(GetInstanceType()).IsInternalized();
   }
 
   bool HasExternalReferenceValue() const {
-    return has_external_reference_value_;
+    return HasExternalReferenceValueField::decode(bit_field_);
   }
   ExternalReference ExternalReferenceValue() const {
     return external_reference_value_;
   }
 
   bool HasBooleanValue() const { return type_.IsBoolean(); }
-  bool BooleanValue() const { return boolean_value_; }
-  bool IsUndetectable() const { return is_undetectable_; }
-  InstanceType GetInstanceType() const { return instance_type_; }
+  bool BooleanValue() const { return BooleanValueField::decode(bit_field_); }
+  bool IsUndetectable() const {
+    return IsUndetectableField::decode(bit_field_);
+  }
+  InstanceType GetInstanceType() const {
+    return InstanceTypeField::decode(bit_field_);
+  }
 
-  bool HasMapValue() const { return instance_type_ == MAP_TYPE; }
+  bool HasMapValue() const { return GetInstanceType() == MAP_TYPE; }
   Unique<Map> MapValue() const {
     DCHECK(HasMapValue());
     return Unique<Map>::cast(GetUnique());
   }
   bool HasStableMapValue() const {
-    DCHECK(HasMapValue() || !has_stable_map_value_);
-    return has_stable_map_value_;
+    DCHECK(HasMapValue() || !HasStableMapValueField::decode(bit_field_));
+    return HasStableMapValueField::decode(bit_field_);
   }
 
   bool HasObjectMap() const { return !object_map_.IsNull(); }
@@ -3645,12 +3657,12 @@
     return object_map_;
   }
 
-  virtual intptr_t Hashcode() OVERRIDE {
-    if (has_int32_value_) {
+  intptr_t Hashcode() OVERRIDE {
+    if (HasInteger32Value()) {
       return static_cast<intptr_t>(int32_value_);
-    } else if (has_double_value_) {
+    } else if (HasDoubleValue()) {
       return static_cast<intptr_t>(bit_cast<int64_t>(double_value_));
-    } else if (has_external_reference_value_) {
+    } else if (HasExternalReferenceValue()) {
       return reinterpret_cast<intptr_t>(external_reference_value_.address());
     } else {
       DCHECK(!object_.handle().is_null());
@@ -3658,8 +3670,8 @@
     }
   }
 
-  virtual void FinalizeUniqueness() OVERRIDE {
-    if (!has_double_value_ && !has_external_reference_value_) {
+  void FinalizeUniqueness() OVERRIDE {
+    if (!HasDoubleValue() && !HasExternalReferenceValue()) {
       DCHECK(!object_.handle().is_null());
       object_ = Unique<Object>(object_.handle());
     }
@@ -3673,23 +3685,23 @@
     return object_.IsInitialized() && object_ == other;
   }
 
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     HConstant* other_constant = HConstant::cast(other);
-    if (has_int32_value_) {
-      return other_constant->has_int32_value_ &&
-          int32_value_ == other_constant->int32_value_;
-    } else if (has_double_value_) {
-      return other_constant->has_double_value_ &&
+    if (HasInteger32Value()) {
+      return other_constant->HasInteger32Value() &&
+             int32_value_ == other_constant->int32_value_;
+    } else if (HasDoubleValue()) {
+      return other_constant->HasDoubleValue() &&
              bit_cast<int64_t>(double_value_) ==
                  bit_cast<int64_t>(other_constant->double_value_);
-    } else if (has_external_reference_value_) {
-      return other_constant->has_external_reference_value_ &&
-          external_reference_value_ ==
-          other_constant->external_reference_value_;
+    } else if (HasExternalReferenceValue()) {
+      return other_constant->HasExternalReferenceValue() &&
+             external_reference_value_ ==
+                 other_constant->external_reference_value_;
     } else {
-      if (other_constant->has_int32_value_ ||
-          other_constant->has_double_value_ ||
-          other_constant->has_external_reference_value_) {
+      if (other_constant->HasInteger32Value() ||
+          other_constant->HasDoubleValue() ||
+          other_constant->HasExternalReferenceValue()) {
         return false;
       }
       DCHECK(!object_.handle().is_null());
@@ -3698,13 +3710,13 @@
   }
 
 #ifdef DEBUG
-  virtual void Verify() OVERRIDE { }
+  void Verify() OVERRIDE {}
 #endif
 
   DECLARE_CONCRETE_INSTRUCTION(Constant)
 
  protected:
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
  private:
   friend class HGraph;
@@ -3732,7 +3744,26 @@
 
   void Initialize(Representation r);
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
+
+  // If object_ is a map, this indicates whether the map is stable.
+  class HasStableMapValueField : public BitField<bool, 0, 1> {};
+
+  // We store the HConstant in the most specific form safely possible.
+  // These flags tell us if the respective member fields hold valid, safe
+  // representations of the constant. More specific flags imply more general
+  // flags, but not the converse (i.e. smi => int32 => double).
+  class HasSmiValueField : public BitField<bool, 1, 1> {};
+  class HasInt32ValueField : public BitField<bool, 2, 1> {};
+  class HasDoubleValueField : public BitField<bool, 3, 1> {};
+
+  class HasExternalReferenceValueField : public BitField<bool, 4, 1> {};
+  class IsNotInNewSpaceField : public BitField<bool, 5, 1> {};
+  class BooleanValueField : public BitField<bool, 6, 1> {};
+  class IsUndetectableField : public BitField<bool, 7, 1> {};
+
+  static const InstanceType kUnknownInstanceType = FILLER_TYPE;
+  class InstanceTypeField : public BitField<InstanceType, 8, 8> {};
 
   // If this is a numerical constant, object_ either points to the
   // HeapObject the constant originated from or is null.  If the
@@ -3743,27 +3774,11 @@
   // If object_ is a heap object, this points to the stable map of the object.
   Unique<Map> object_map_;
 
-  // If object_ is a map, this indicates whether the map is stable.
-  bool has_stable_map_value_ : 1;
+  uint32_t bit_field_;
 
-  // We store the HConstant in the most specific form safely possible.
-  // The two flags, has_int32_value_ and has_double_value_ tell us if
-  // int32_value_ and double_value_ hold valid, safe representations
-  // of the constant.  has_int32_value_ implies has_double_value_ but
-  // not the converse.
-  bool has_smi_value_ : 1;
-  bool has_int32_value_ : 1;
-  bool has_double_value_ : 1;
-  bool has_external_reference_value_ : 1;
-  bool is_not_in_new_space_ : 1;
-  bool boolean_value_ : 1;
-  bool is_undetectable_: 1;
   int32_t int32_value_;
   double double_value_;
   ExternalReference external_reference_value_;
-
-  static const InstanceType kUnknownInstanceType = FILLER_TYPE;
-  InstanceType instance_type_;
 };
 
 
@@ -3817,7 +3832,7 @@
     observed_output_representation_ = observed;
   }
 
-  virtual Representation observed_input_representation(int index) OVERRIDE {
+  Representation observed_input_representation(int index) OVERRIDE {
     if (index == 0) return Representation::Tagged();
     return observed_input_representation_[index - 1];
   }
@@ -3832,15 +3847,15 @@
 
   virtual void InferRepresentation(
       HInferRepresentationPhase* h_infer) OVERRIDE;
-  virtual Representation RepresentationFromInputs() OVERRIDE;
+  Representation RepresentationFromInputs() OVERRIDE;
   Representation RepresentationFromOutput();
-  virtual void AssumeRepresentation(Representation r) OVERRIDE;
+  void AssumeRepresentation(Representation r) OVERRIDE;
 
   virtual bool IsCommutative() const { return false; }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     if (index == 0) return Representation::Tagged();
     return representation();
   }
@@ -3875,18 +3890,18 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
 
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
   HValue* receiver() const { return OperandAt(0); }
   HValue* function() const { return OperandAt(1); }
 
-  virtual HValue* Canonicalize() OVERRIDE;
+  HValue* Canonicalize() OVERRIDE;
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
   bool known_function() const { return known_function_; }
 
   DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
@@ -3910,7 +3925,7 @@
   DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*,
                                  HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     // The length is untagged, all other inputs are tagged.
     return (index == 2)
         ? Representation::Integer32()
@@ -3945,14 +3960,14 @@
 
   DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
   bool from_inlined() const { return from_inlined_; }
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
@@ -3962,7 +3977,7 @@
     SetFlag(kUseGVN);
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 
   bool from_inlined_;
 };
@@ -3972,14 +3987,14 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
   DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
@@ -3987,7 +4002,7 @@
     SetFlag(kUseGVN);
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 };
 
 
@@ -3995,9 +4010,9 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     // The arguments elements is considered tagged.
     return index == 0
         ? Representation::Tagged()
@@ -4019,7 +4034,7 @@
     SetOperandAt(2, index);
   }
 
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 };
 
 
@@ -4055,11 +4070,11 @@
     }
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return representation();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
   virtual void InferRepresentation(
       HInferRepresentationPhase* h_infer) OVERRIDE;
 
@@ -4068,19 +4083,17 @@
   bool allow_equality() const { return allow_equality_; }
   void set_allow_equality(bool v) { allow_equality_ = v; }
 
-  virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
-  virtual bool IsPurelyInformativeDefinition() OVERRIDE {
-    return skip_check();
-  }
+  int RedefinedOperandIndex() OVERRIDE { return 0; }
+  bool IsPurelyInformativeDefinition() OVERRIDE { return skip_check(); }
 
   DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
 
  protected:
   friend class HBoundsCheckBaseIndexInformation;
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
   bool skip_check_;
   HValue* base_;
   int offset_;
@@ -4102,9 +4115,7 @@
     SetFlag(kUseGVN);
   }
 
-  virtual bool IsDeletable() const OVERRIDE {
-    return skip_check() && !FLAG_debug_code;
-  }
+  bool IsDeletable() const OVERRIDE { return skip_check() && !FLAG_debug_code; }
 };
 
 
@@ -4126,14 +4137,14 @@
 
   DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return representation();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
-  virtual bool IsPurelyInformativeDefinition() OVERRIDE { return true; }
+  int RedefinedOperandIndex() OVERRIDE { return 0; }
+  bool IsPurelyInformativeDefinition() OVERRIDE { return true; }
 };
 
 
@@ -4148,7 +4159,7 @@
     SetAllSideEffects();
   }
 
-  virtual void RepresentationChanged(Representation to) OVERRIDE {
+  void RepresentationChanged(Representation to) OVERRIDE {
     if (to.IsTagged() &&
         (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
       SetAllSideEffects();
@@ -4168,13 +4179,14 @@
     HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
   }
 
-  virtual Representation observed_input_representation(int index) OVERRIDE {
+  Representation observed_input_representation(int index) OVERRIDE {
     Representation r = HBinaryOperation::observed_input_representation(index);
     if (r.IsDouble()) return Representation::Integer32();
     return r;
   }
 
-  virtual void initialize_output_representation(Representation observed) {
+  virtual void initialize_output_representation(
+      Representation observed) OVERRIDE {
     if (observed.IsDouble()) observed = Representation::Integer32();
     HBinaryOperation::initialize_output_representation(observed);
   }
@@ -4182,7 +4194,7 @@
   DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
 
  private:
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 };
 
 
@@ -4195,7 +4207,7 @@
   DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
@@ -4210,9 +4222,9 @@
     SetFlag(kAllowUndefinedAsNaN);
   }
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 };
 
 
@@ -4225,7 +4237,7 @@
     SetFlag(kAllowUndefinedAsNaN);
   }
 
-  virtual void RepresentationChanged(Representation to) OVERRIDE {
+  void RepresentationChanged(Representation to) OVERRIDE {
     if (to.IsTagged() &&
         (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
       SetAllSideEffects();
@@ -4240,7 +4252,7 @@
   DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
 
  private:
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 };
 
 
@@ -4249,14 +4261,14 @@
   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCompareGeneric, HValue*,
                                               HValue*, Token::Value);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return index == 0
         ? Representation::Tagged()
         : representation();
   }
 
   Token::Value token() const { return token_; }
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
 
@@ -4297,16 +4309,16 @@
   virtual void InferRepresentation(
       HInferRepresentationPhase* h_infer) OVERRIDE;
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return representation();
   }
-  virtual Representation observed_input_representation(int index) OVERRIDE {
+  Representation observed_input_representation(int index) OVERRIDE {
     return observed_input_representation_[index];
   }
 
-  virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
+  bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   void SetOperandPositions(Zone* zone,
                            HSourcePosition left_pos,
@@ -4346,7 +4358,7 @@
   virtual void InferRepresentation(
       HInferRepresentationPhase* h_infer) OVERRIDE;
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return representation();
   }
 
@@ -4370,11 +4382,11 @@
   virtual void InferRepresentation(
       HInferRepresentationPhase* h_infer) OVERRIDE;
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return representation();
   }
 
-  virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
+  bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
 
@@ -4391,7 +4403,7 @@
   DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
                                  HBasicBlock*, HBasicBlock*);
 
-  virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
+  bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
 
   static const int kNoKnownSuccessorIndex = -1;
   int known_successor_index() const { return known_successor_index_; }
@@ -4402,13 +4414,13 @@
   HValue* left() const { return OperandAt(0); }
   HValue* right() const { return OperandAt(1); }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual Representation observed_input_representation(int index) OVERRIDE {
+  Representation observed_input_representation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -4436,11 +4448,11 @@
   DECLARE_INSTRUCTION_FACTORY_P3(HIsObjectAndBranch, HValue*,
                                  HBasicBlock*, HBasicBlock*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
+  bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
 
@@ -4458,11 +4470,11 @@
   DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
                                  HBasicBlock*, HBasicBlock*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
+  bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
 
   static const int kNoKnownSuccessorIndex = -1;
   int known_successor_index() const { return known_successor_index_; }
@@ -4473,14 +4485,15 @@
   DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
 
  protected:
-  virtual int RedefinedOperandIndex() { return 0; }
+  int RedefinedOperandIndex() OVERRIDE { return 0; }
 
  private:
-  HIsStringAndBranch(HValue* value,
-                     HBasicBlock* true_target = NULL,
+  HIsStringAndBranch(HValue* value, HBasicBlock* true_target = NULL,
                      HBasicBlock* false_target = NULL)
-    : HUnaryControlInstruction(value, true_target, false_target),
-      known_successor_index_(kNoKnownSuccessorIndex) { }
+      : HUnaryControlInstruction(value, true_target, false_target),
+        known_successor_index_(kNoKnownSuccessorIndex) {
+    set_representation(Representation::Tagged());
+  }
 
   int known_successor_index_;
 };
@@ -4494,13 +4507,13 @@
 
   DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
-  virtual int RedefinedOperandIndex() { return 0; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
+  int RedefinedOperandIndex() OVERRIDE { return 0; }
 
  private:
   HIsSmiAndBranch(HValue* value,
@@ -4518,11 +4531,11 @@
   DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
                                  HBasicBlock*, HBasicBlock*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
+  bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
 
@@ -4546,9 +4559,9 @@
   HValue* right() { return OperandAt(2); }
   Token::Value token() const { return token_; }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -4580,7 +4593,7 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
@@ -4600,13 +4613,13 @@
   InstanceType from() { return from_; }
   InstanceType to() { return to_; }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
+  bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
 
@@ -4627,7 +4640,7 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -4642,14 +4655,14 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
   DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
@@ -4657,7 +4670,7 @@
     SetFlag(kUseGVN);
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 };
 
 
@@ -4668,11 +4681,11 @@
 
   DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   Handle<String> class_name() const { return class_name_; }
 
@@ -4690,17 +4703,17 @@
   DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
 
   Handle<String> type_literal() const { return type_literal_.handle(); }
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
-  virtual bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
+  bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
 
-  virtual void FinalizeUniqueness() OVERRIDE {
+  void FinalizeUniqueness() OVERRIDE {
     type_literal_ = Unique<String>(type_literal_.handle());
   }
 
@@ -4717,11 +4730,11 @@
  public:
   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
 
@@ -4744,7 +4757,7 @@
   HValue* left() { return OperandAt(1); }
   Handle<JSFunction> function() { return function_; }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -4775,19 +4788,19 @@
   HValue* left() { return OperandAt(0); }
   HValue* right() const { return OperandAt(1); }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return index == 0
       ? Representation::Double()
       : Representation::None();
   }
-  virtual Representation observed_input_representation(int index) OVERRIDE {
+  Representation observed_input_representation(int index) OVERRIDE {
     return RequiredInputRepresentation(index);
   }
 
   DECLARE_CONCRETE_INSTRUCTION(Power)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   HPower(HValue* left, HValue* right) {
@@ -4798,7 +4811,7 @@
     SetChangesFlag(kNewSpacePromotion);
   }
 
-  virtual bool IsDeletable() const OVERRIDE {
+  bool IsDeletable() const OVERRIDE {
     return !right()->representation().IsTagged();
   }
 };
@@ -4814,13 +4827,13 @@
   // Add is only commutative if two integer values are added and not if two
   // tagged values are added (because it might be a String concatenation).
   // We also do not commute (pointer + offset).
-  virtual bool IsCommutative() const OVERRIDE {
+  bool IsCommutative() const OVERRIDE {
     return !representation().IsTagged() && !representation().IsExternal();
   }
 
-  virtual HValue* Canonicalize() OVERRIDE;
+  HValue* Canonicalize() OVERRIDE;
 
-  virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
+  bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
     if (left()->IsInteger32Constant()) {
       decomposition->Apply(right(), left()->GetInteger32Constant());
       return true;
@@ -4832,7 +4845,7 @@
     }
   }
 
-  virtual void RepresentationChanged(Representation to) OVERRIDE {
+  void RepresentationChanged(Representation to) OVERRIDE {
     if (to.IsTagged() &&
         (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
          left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
@@ -4848,16 +4861,16 @@
     }
   }
 
-  virtual Representation RepresentationFromInputs() OVERRIDE;
+  Representation RepresentationFromInputs() OVERRIDE;
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE;
+  Representation RequiredInputRepresentation(int index) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(Add)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
  private:
   HAdd(HValue* context, HValue* left, HValue* right)
@@ -4874,9 +4887,9 @@
                            HValue* left,
                            HValue* right);
 
-  virtual HValue* Canonicalize() OVERRIDE;
+  HValue* Canonicalize() OVERRIDE;
 
-  virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
+  bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
     if (right()->IsInteger32Constant()) {
       decomposition->Apply(left(), -right()->GetInteger32Constant());
       return true;
@@ -4888,9 +4901,9 @@
   DECLARE_CONCRETE_INSTRUCTION(Sub)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
  private:
   HSub(HValue* context, HValue* left, HValue* right)
@@ -4920,12 +4933,10 @@
     return mul;
   }
 
-  virtual HValue* Canonicalize() OVERRIDE;
+  HValue* Canonicalize() OVERRIDE;
 
   // Only commutative if it is certain that not two objects are multiplicated.
-  virtual bool IsCommutative() const OVERRIDE {
-    return !representation().IsTagged();
-  }
+  bool IsCommutative() const OVERRIDE { return !representation().IsTagged(); }
 
   virtual void UpdateRepresentation(Representation new_rep,
                                     HInferRepresentationPhase* h_infer,
@@ -4938,9 +4949,9 @@
   DECLARE_CONCRETE_INSTRUCTION(Mul)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
  private:
   HMul(HValue* context, HValue* left, HValue* right)
@@ -4957,7 +4968,7 @@
                            HValue* left,
                            HValue* right);
 
-  virtual HValue* Canonicalize() OVERRIDE;
+  HValue* Canonicalize() OVERRIDE;
 
   virtual void UpdateRepresentation(Representation new_rep,
                                     HInferRepresentationPhase* h_infer,
@@ -4969,9 +4980,9 @@
   DECLARE_CONCRETE_INSTRUCTION(Mod)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
  private:
   HMod(HValue* context,
@@ -4991,7 +5002,7 @@
                            HValue* left,
                            HValue* right);
 
-  virtual HValue* Canonicalize() OVERRIDE;
+  HValue* Canonicalize() OVERRIDE;
 
   virtual void UpdateRepresentation(Representation new_rep,
                                     HInferRepresentationPhase* h_infer,
@@ -5003,9 +5014,9 @@
   DECLARE_CONCRETE_INSTRUCTION(Div)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
  private:
   HDiv(HValue* context, HValue* left, HValue* right)
@@ -5026,14 +5037,14 @@
                            HValue* right,
                            Operation op);
 
-  virtual Representation observed_input_representation(int index) OVERRIDE {
+  Representation observed_input_representation(int index) OVERRIDE {
     return RequiredInputRepresentation(index);
   }
 
   virtual void InferRepresentation(
       HInferRepresentationPhase* h_infer) OVERRIDE;
 
-  virtual Representation RepresentationFromInputs() OVERRIDE {
+  Representation RepresentationFromInputs() OVERRIDE {
     Representation left_rep = left()->representation();
     Representation right_rep = right()->representation();
     Representation result = Representation::Smi();
@@ -5043,19 +5054,19 @@
     return result;
   }
 
-  virtual bool IsCommutative() const OVERRIDE { return true; }
+  bool IsCommutative() const OVERRIDE { return true; }
 
   Operation operation() { return operation_; }
 
   DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     return other->IsMathMinMax() &&
         HMathMinMax::cast(other)->operation_ == operation_;
   }
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
  private:
   HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
@@ -5076,20 +5087,20 @@
 
   Token::Value op() const { return op_; }
 
-  virtual bool IsCommutative() const OVERRIDE { return true; }
+  bool IsCommutative() const OVERRIDE { return true; }
 
-  virtual HValue* Canonicalize() OVERRIDE;
+  HValue* Canonicalize() OVERRIDE;
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(Bitwise)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     return op() == HBitwise::cast(other)->op();
   }
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
  private:
   HBitwise(HValue* context,
@@ -5135,7 +5146,7 @@
                            HValue* left,
                            HValue* right);
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
   virtual void UpdateRepresentation(Representation new_rep,
                                     HInferRepresentationPhase* h_infer,
@@ -5151,7 +5162,7 @@
   DECLARE_CONCRETE_INSTRUCTION(Shl)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   HShl(HValue* context, HValue* left, HValue* right)
@@ -5166,7 +5177,7 @@
                            HValue* left,
                            HValue* right);
 
-  virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
+  bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
     if (right()->IsInteger32Constant()) {
       if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
         // This is intended to look for HAdd and HSub, to handle compounds
@@ -5178,7 +5189,7 @@
     return false;
   }
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
   virtual void UpdateRepresentation(Representation new_rep,
                                     HInferRepresentationPhase* h_infer,
@@ -5190,7 +5201,7 @@
   DECLARE_CONCRETE_INSTRUCTION(Shr)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   HShr(HValue* context, HValue* left, HValue* right)
@@ -5205,7 +5216,7 @@
                            HValue* left,
                            HValue* right);
 
-  virtual bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
+  bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
     if (right()->IsInteger32Constant()) {
       if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
         // This is intended to look for HAdd and HSub, to handle compounds
@@ -5217,7 +5228,7 @@
     return false;
   }
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
   virtual void UpdateRepresentation(Representation new_rep,
                                     HInferRepresentationPhase* h_infer,
@@ -5229,7 +5240,7 @@
   DECLARE_CONCRETE_INSTRUCTION(Sar)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   HSar(HValue* context, HValue* left, HValue* right)
@@ -5256,7 +5267,7 @@
   DECLARE_CONCRETE_INSTRUCTION(Ror)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   HRor(HValue* context, HValue* left, HValue* right)
@@ -5272,7 +5283,7 @@
 
   BailoutId ast_id() const { return ast_id_; }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
@@ -5303,12 +5314,18 @@
   unsigned index() const { return index_; }
   ParameterKind kind() const { return kind_; }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
+  Representation KnownOptimalRepresentation() OVERRIDE {
+    // If a parameter is an input to a phi, that phi should not
+    // choose any more optimistic representation than Tagged.
+    return Representation::Tagged();
+  }
+
   DECLARE_CONCRETE_INSTRUCTION(Parameter)
 
  private:
@@ -5339,7 +5356,7 @@
 
   HValue* context() { return value(); }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(CallStub)
 
@@ -5353,34 +5370,90 @@
 };
 
 
-class HTailCallThroughMegamorphicCache FINAL : public HTemplateInstruction<3> {
+class HTailCallThroughMegamorphicCache FINAL : public HInstruction {
  public:
-  DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HTailCallThroughMegamorphicCache,
-                                              HValue*, HValue*, Code::Flags);
+  enum Flags {
+    NONE = 0,
+    CALLED_FROM_KEYED_LOAD = 1 << 0,
+    PERFORM_MISS_ONLY = 1 << 1
+  };
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  static Flags ComputeFlags(bool called_from_keyed_load,
+                            bool perform_miss_only) {
+    Flags flags = NONE;
+    if (called_from_keyed_load) {
+      flags = static_cast<Flags>(flags | CALLED_FROM_KEYED_LOAD);
+    }
+    if (perform_miss_only) {
+      flags = static_cast<Flags>(flags | PERFORM_MISS_ONLY);
+    }
+    return flags;
+  }
+
+  DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(
+      HTailCallThroughMegamorphicCache, HValue*, HValue*, HValue*, HValue*,
+      HTailCallThroughMegamorphicCache::Flags);
+
+  DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HTailCallThroughMegamorphicCache,
+                                              HValue*, HValue*);
+
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
+  virtual int OperandCount() const FINAL OVERRIDE {
+    return FLAG_vector_ics ? 5 : 3;
+  }
+  virtual HValue* OperandAt(int i) const FINAL OVERRIDE { return inputs_[i]; }
+
   HValue* context() const { return OperandAt(0); }
   HValue* receiver() const { return OperandAt(1); }
   HValue* name() const { return OperandAt(2); }
-  Code::Flags flags() const { return flags_; }
+  HValue* slot() const {
+    DCHECK(FLAG_vector_ics);
+    return OperandAt(3);
+  }
+  HValue* vector() const {
+    DCHECK(FLAG_vector_ics);
+    return OperandAt(4);
+  }
+  Code::Flags flags() const;
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  bool is_keyed_load() const { return flags_ & CALLED_FROM_KEYED_LOAD; }
+  bool is_just_miss() const { return flags_ & PERFORM_MISS_ONLY; }
+
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache)
 
+ protected:
+  virtual void InternalSetOperandAt(int i, HValue* value) FINAL OVERRIDE {
+    inputs_[i] = value;
+  }
+
  private:
   HTailCallThroughMegamorphicCache(HValue* context, HValue* receiver,
-                                   HValue* name, Code::Flags flags)
+                                   HValue* name, HValue* slot, HValue* vector,
+                                   Flags flags)
       : flags_(flags) {
+    DCHECK(FLAG_vector_ics);
+    SetOperandAt(0, context);
+    SetOperandAt(1, receiver);
+    SetOperandAt(2, name);
+    SetOperandAt(3, slot);
+    SetOperandAt(4, vector);
+  }
+
+  HTailCallThroughMegamorphicCache(HValue* context, HValue* receiver,
+                                   HValue* name)
+      : flags_(NONE) {
     SetOperandAt(0, context);
     SetOperandAt(1, receiver);
     SetOperandAt(2, name);
   }
 
-  Code::Flags flags_;
+  EmbeddedContainer<HValue*, 5> inputs_;
+  Flags flags_;
 };
 
 
@@ -5388,9 +5461,9 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
 
-  virtual OStream& PrintDataTo(OStream& os) const;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
@@ -5399,7 +5472,7 @@
   HEnvironment *environment() { return environment_; }
   int index() { return index_; }
 
-  virtual Representation KnownOptimalRepresentation() OVERRIDE {
+  Representation KnownOptimalRepresentation() OVERRIDE {
     if (incoming_value_ == NULL) return Representation::None();
     return incoming_value_->KnownOptimalRepresentation();
   }
@@ -5428,24 +5501,20 @@
   Unique<Cell> cell() const { return cell_; }
   bool RequiresHoleCheck() const;
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual intptr_t Hashcode() OVERRIDE {
-    return cell_.Hashcode();
-  }
+  intptr_t Hashcode() OVERRIDE { return cell_.Hashcode(); }
 
-  virtual void FinalizeUniqueness() OVERRIDE {
-    cell_ = Unique<Cell>(cell_.handle());
-  }
+  void FinalizeUniqueness() OVERRIDE { cell_ = Unique<Cell>(cell_.handle()); }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::None();
   }
 
   DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     return cell_ == HLoadGlobalCell::cast(other)->cell_;
   }
 
@@ -5457,7 +5526,7 @@
     SetDependsOnFlag(kGlobalVars);
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
+  bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
 
   Unique<Cell> cell_;
   PropertyDetails details_;
@@ -5473,21 +5542,21 @@
   HValue* global_object() { return OperandAt(1); }
   Handle<String> name() const { return name_; }
   bool for_typeof() const { return for_typeof_; }
-  int slot() const {
-    DCHECK(FLAG_vector_ics &&
-           slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
-    return slot_;
+  FeedbackVectorICSlot slot() const { return slot_; }
+  Handle<TypeFeedbackVector> feedback_vector() const {
+    return feedback_vector_;
   }
-  Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
-  void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
+  bool HasVectorAndSlot() const { return FLAG_vector_ics; }
+  void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
+                        FeedbackVectorICSlot slot) {
     DCHECK(FLAG_vector_ics);
     feedback_vector_ = vector;
     slot_ = slot;
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -5496,8 +5565,9 @@
  private:
   HLoadGlobalGeneric(HValue* context, HValue* global_object,
                      Handle<String> name, bool for_typeof)
-      : name_(name), for_typeof_(for_typeof),
-        slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
+      : name_(name),
+        for_typeof_(for_typeof),
+        slot_(FeedbackVectorICSlot::Invalid()) {
     SetOperandAt(0, context);
     SetOperandAt(1, global_object);
     set_representation(Representation::Tagged());
@@ -5506,8 +5576,8 @@
 
   Handle<String> name_;
   bool for_typeof_;
-  Handle<FixedArray> feedback_vector_;
-  int slot_;
+  Handle<TypeFeedbackVector> feedback_vector_;
+  FeedbackVectorICSlot slot_;
 };
 
 
@@ -5544,7 +5614,7 @@
     size_upper_bound_ = value;
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     if (index == 0) {
       return Representation::Tagged();
     } else {
@@ -5552,7 +5622,7 @@
     }
   }
 
-  virtual Handle<Map> GetMonomorphicJSObjectMap() OVERRIDE {
+  Handle<Map> GetMonomorphicJSObjectMap() OVERRIDE {
     return known_initial_map_;
   }
 
@@ -5595,7 +5665,7 @@
   virtual bool HandleSideEffectDominator(GVNFlag side_effect,
                                          HValue* dominator) OVERRIDE;
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(Allocate)
 
@@ -5708,7 +5778,7 @@
     return new(zone) HStoreCodeEntry(function, code);
   }
 
-  virtual Representation RequiredInputRepresentation(int index) {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -5738,11 +5808,11 @@
   HValue* base_object() const { return OperandAt(0); }
   HValue* offset() const { return OperandAt(1); }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return index == 0 ? Representation::Tagged() : Representation::Integer32();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
 
@@ -5833,14 +5903,14 @@
     return StoringValueNeedsWriteBarrier(value());
   }
 
-  virtual void FinalizeUniqueness() OVERRIDE {
+  void FinalizeUniqueness() OVERRIDE {
     cell_ = Unique<PropertyCell>(cell_.handle());
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell)
 
@@ -5892,22 +5962,22 @@
     return mode_ != kNoCheck;
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     HLoadContextSlot* b = HLoadContextSlot::cast(other);
     return (slot_index() == b->slot_index());
   }
 
  private:
-  virtual bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
+  bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
 
   int slot_index_;
   Mode mode_;
@@ -5949,11 +6019,11 @@
     return mode_ != kNoCheck;
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
 
@@ -6123,6 +6193,10 @@
     return HObjectAccess(kMaps, JSObject::kMapOffset);
   }
 
+  static HObjectAccess ForPrototype() {
+    return HObjectAccess(kMaps, Map::kPrototypeOffset);
+  }
+
   static HObjectAccess ForMapAsInteger32() {
     return HObjectAccess(kMaps, JSObject::kMapOffset,
                          Representation::Integer32());
@@ -6182,6 +6256,10 @@
     return HObjectAccess(kInobject, Cell::kValueOffset);
   }
 
+  static HObjectAccess ForWeakCellValue() {
+    return HObjectAccess(kInobject, WeakCell::kValueOffset);
+  }
+
   static HObjectAccess ForAllocationMementoSite() {
     return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
   }
@@ -6220,6 +6298,8 @@
 
   static HObjectAccess ForContextSlot(int index);
 
+  static HObjectAccess ForScriptContext(int index);
+
   // Create an access to the backing store of an object.
   static HObjectAccess ForBackingStoreOffset(int offset,
       Representation representation = Representation::Tagged());
@@ -6281,6 +6361,51 @@
     return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset);
   }
 
+  static HObjectAccess ForJSCollectionTable() {
+    return HObjectAccess::ForObservableJSObjectOffset(
+        JSCollection::kTableOffset);
+  }
+
+  template <typename CollectionType>
+  static HObjectAccess ForOrderedHashTableNumberOfBuckets() {
+    return HObjectAccess(kInobject, CollectionType::kNumberOfBucketsOffset,
+                         Representation::Smi());
+  }
+
+  template <typename CollectionType>
+  static HObjectAccess ForOrderedHashTableNumberOfElements() {
+    return HObjectAccess(kInobject, CollectionType::kNumberOfElementsOffset,
+                         Representation::Smi());
+  }
+
+  template <typename CollectionType>
+  static HObjectAccess ForOrderedHashTableNumberOfDeletedElements() {
+    return HObjectAccess(kInobject,
+                         CollectionType::kNumberOfDeletedElementsOffset,
+                         Representation::Smi());
+  }
+
+  template <typename CollectionType>
+  static HObjectAccess ForOrderedHashTableNextTable() {
+    return HObjectAccess(kInobject, CollectionType::kNextTableOffset);
+  }
+
+  template <typename CollectionType>
+  static HObjectAccess ForOrderedHashTableBucket(int bucket) {
+    return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
+                                        (bucket * kPointerSize),
+                         Representation::Smi());
+  }
+
+  // Access into the data table of an OrderedHashTable with a
+  // known-at-compile-time bucket count.
+  template <typename CollectionType, int kBucketCount>
+  static HObjectAccess ForOrderedHashTableDataTableIndex(int index) {
+    return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
+                                        (kBucketCount * kPointerSize) +
+                                        (index * kPointerSize));
+  }
+
   inline bool Equals(HObjectAccess that) const {
     return value_ == that.value_;  // portion and offset must match
   }
@@ -6336,7 +6461,8 @@
   friend class HLoadNamedField;
   friend class HStoreNamedField;
   friend class SideEffectsTracker;
-  friend OStream& operator<<(OStream& os, const HObjectAccess& access);
+  friend std::ostream& operator<<(std::ostream& os,
+                                  const HObjectAccess& access);
 
   inline Portion portion() const {
     return PortionField::decode(value_);
@@ -6344,7 +6470,7 @@
 };
 
 
-OStream& operator<<(OStream& os, const HObjectAccess& access);
+std::ostream& operator<<(std::ostream& os, const HObjectAccess& access);
 
 
 class HLoadNamedField FINAL : public HTemplateInstruction<2> {
@@ -6367,19 +6493,21 @@
 
   const UniqueSet<Map>* maps() const { return maps_; }
 
-  virtual bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
-  virtual bool HasOutOfBoundsAccess(int size) OVERRIDE {
+  bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
+  bool HasOutOfBoundsAccess(int size) OVERRIDE {
     return !access().IsInobject() || access().offset() >= size;
   }
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
-    if (index == 0 && access().IsExternalMemory()) {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
+    if (index == 0) {
       // object must be external in case of external memory access
-      return Representation::External();
+      return access().IsExternalMemory() ? Representation::External()
+                                         : Representation::Tagged();
     }
-    return Representation::Tagged();
+    DCHECK(index == 1);
+    return Representation::None();
   }
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  Range* InferRange(Zone* zone) OVERRIDE;
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   bool CanBeReplacedWith(HValue* other) const {
     if (!CheckFlag(HValue::kCantBeReplaced)) return false;
@@ -6395,7 +6523,7 @@
   DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     HLoadNamedField* that = HLoadNamedField::cast(other);
     if (!this->access_.Equals(that->access_)) return false;
     if (this->maps_ == that->maps_) return true;
@@ -6459,7 +6587,7 @@
     access.SetGVNFlags(this, LOAD);
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 
   HObjectAccess access_;
   const UniqueSet<Map>* maps_;
@@ -6475,30 +6603,29 @@
   HValue* object() const { return OperandAt(1); }
   Handle<Object> name() const { return name_; }
 
-  int slot() const {
-    DCHECK(FLAG_vector_ics &&
-           slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
-    return slot_;
+  FeedbackVectorICSlot slot() const { return slot_; }
+  Handle<TypeFeedbackVector> feedback_vector() const {
+    return feedback_vector_;
   }
-  Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
-  void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
+  bool HasVectorAndSlot() const { return FLAG_vector_ics; }
+  void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
+                        FeedbackVectorICSlot slot) {
     DCHECK(FLAG_vector_ics);
     feedback_vector_ = vector;
     slot_ = slot;
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
 
  private:
   HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
-      : name_(name),
-        slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
+      : name_(name), slot_(FeedbackVectorICSlot::Invalid()) {
     SetOperandAt(0, context);
     SetOperandAt(1, object);
     set_representation(Representation::Tagged());
@@ -6506,8 +6633,8 @@
   }
 
   Handle<Object> name_;
-  Handle<FixedArray> feedback_vector_;
-  int slot_;
+  Handle<TypeFeedbackVector> feedback_vector_;
+  FeedbackVectorICSlot slot_;
 };
 
 
@@ -6517,14 +6644,14 @@
 
   HValue* function() { return OperandAt(0); }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
   DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   explicit HLoadFunctionPrototype(HValue* function)
@@ -6588,21 +6715,23 @@
   }
   bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
   uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); }
-  bool TryIncreaseBaseOffset(uint32_t increase_by_value);
-  HValue* GetKey() { return key(); }
-  void SetKey(HValue* key) { SetOperandAt(1, key); }
-  bool IsDehoisted() const { return IsDehoistedField::decode(bit_field_); }
-  void SetDehoisted(bool is_dehoisted) {
+  bool TryIncreaseBaseOffset(uint32_t increase_by_value) OVERRIDE;
+  HValue* GetKey() OVERRIDE { return key(); }
+  void SetKey(HValue* key) OVERRIDE { SetOperandAt(1, key); }
+  bool IsDehoisted() const OVERRIDE {
+    return IsDehoistedField::decode(bit_field_);
+  }
+  void SetDehoisted(bool is_dehoisted) OVERRIDE {
     bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
   }
-  virtual ElementsKind elements_kind() const OVERRIDE {
+  ElementsKind elements_kind() const OVERRIDE {
     return ElementsKindField::decode(bit_field_);
   }
   LoadKeyedHoleMode hole_mode() const {
     return HoleModeField::decode(bit_field_);
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     // kind_fast:                 tagged[int32] (none)
     // kind_double:               tagged[int32] (none)
     // kind_fixed_typed_array:    tagged[int32] (none)
@@ -6618,27 +6747,26 @@
     return Representation::None();
   }
 
-  virtual Representation observed_input_representation(int index) OVERRIDE {
+  Representation observed_input_representation(int index) OVERRIDE {
     return RequiredInputRepresentation(index);
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   bool UsesMustHandleHole() const;
   bool AllUsesCanTreatHoleAsNaN() const;
   bool RequiresHoleCheck() const;
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE;
+  Range* InferRange(Zone* zone) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     if (!other->IsLoadKeyed()) return false;
     HLoadKeyed* other_load = HLoadKeyed::cast(other);
 
-    if (IsDehoisted() && base_offset() != other_load->base_offset())
-      return false;
+    if (base_offset() != other_load->base_offset()) return false;
     return elements_kind() == other_load->elements_kind();
   }
 
@@ -6710,9 +6838,7 @@
     SetFlag(kUseGVN);
   }
 
-  virtual bool IsDeletable() const OVERRIDE {
-    return !RequiresHoleCheck();
-  }
+  bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
 
   // Establish some checks around our packed fields
   enum LoadKeyedBits {
@@ -6727,8 +6853,8 @@
     kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
   };
 
-  STATIC_ASSERT((kBitsForElementsKind + kBitsForBaseOffset +
-                 kBitsForIsDehoisted) <= sizeof(uint32_t)*8);
+  STATIC_ASSERT((kBitsForElementsKind + kBitsForHoleMode + kBitsForBaseOffset +
+                 kBitsForIsDehoisted) <= sizeof(uint32_t) * 8);
   STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
   class ElementsKindField:
     public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
@@ -6753,32 +6879,32 @@
   HValue* object() const { return OperandAt(0); }
   HValue* key() const { return OperandAt(1); }
   HValue* context() const { return OperandAt(2); }
-  int slot() const {
-    DCHECK(FLAG_vector_ics &&
-           slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
-    return slot_;
+  FeedbackVectorICSlot slot() const { return slot_; }
+  Handle<TypeFeedbackVector> feedback_vector() const {
+    return feedback_vector_;
   }
-  Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
-  void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
+  bool HasVectorAndSlot() const { return FLAG_vector_ics; }
+  void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
+                        FeedbackVectorICSlot slot) {
     DCHECK(FLAG_vector_ics);
     feedback_vector_ = vector;
     slot_ = slot;
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     // tagged[tagged]
     return Representation::Tagged();
   }
 
-  virtual HValue* Canonicalize() OVERRIDE;
+  HValue* Canonicalize() OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
 
  private:
   HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key)
-      : slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
+      : slot_(FeedbackVectorICSlot::Invalid()) {
     set_representation(Representation::Tagged());
     SetOperandAt(0, obj);
     SetOperandAt(1, key);
@@ -6786,8 +6912,8 @@
     SetAllSideEffects();
   }
 
-  Handle<FixedArray> feedback_vector_;
-  int slot_;
+  Handle<TypeFeedbackVector> feedback_vector_;
+  FeedbackVectorICSlot slot_;
 };
 
 
@@ -6811,13 +6937,11 @@
 
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
 
-  virtual bool HasEscapingOperandAt(int index) OVERRIDE {
-    return index == 1;
-  }
-  virtual bool HasOutOfBoundsAccess(int size) OVERRIDE {
+  bool HasEscapingOperandAt(int index) OVERRIDE { return index == 1; }
+  bool HasOutOfBoundsAccess(int size) OVERRIDE {
     return !access().IsInobject() || access().offset() >= size;
   }
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     if (index == 0 && access().IsExternalMemory()) {
       // object must be external in case of external memory access
       return Representation::External();
@@ -6831,7 +6955,8 @@
       } else if (field_representation().IsDouble()) {
         return field_representation();
       } else if (field_representation().IsSmi()) {
-        if (SmiValuesAre32Bits() && store_mode_ == STORE_TO_INITIALIZED_ENTRY) {
+        if (SmiValuesAre32Bits() &&
+            store_mode() == STORE_TO_INITIALIZED_ENTRY) {
           return Representation::Integer32();
         }
         return field_representation();
@@ -6848,7 +6973,7 @@
     dominator_ = dominator;
     return false;
   }
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   HValue* object() const { return OperandAt(0); }
   HValue* value() const { return OperandAt(1); }
@@ -6856,8 +6981,10 @@
 
   HObjectAccess access() const { return access_; }
   HValue* dominator() const { return dominator_; }
-  bool has_transition() const { return has_transition_; }
-  StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
+  bool has_transition() const { return HasTransitionField::decode(bit_field_); }
+  StoreFieldOrKeyedMode store_mode() const {
+    return StoreModeField::decode(bit_field_);
+  }
 
   Handle<Map> transition_map() const {
     if (has_transition()) {
@@ -6871,12 +6998,14 @@
   void SetTransition(HConstant* transition) {
     DCHECK(!has_transition());  // Only set once.
     SetOperandAt(2, transition);
-    has_transition_ = true;
+    bit_field_ = HasTransitionField::update(bit_field_, true);
     SetChangesFlag(kMaps);
   }
 
   bool NeedsWriteBarrier() const {
-    DCHECK(!field_representation().IsDouble() || !has_transition());
+    DCHECK(!field_representation().IsDouble() ||
+           (FLAG_unbox_double_fields && access_.IsInobject()) ||
+           !has_transition());
     if (field_representation().IsDouble()) return false;
     if (field_representation().IsSmi()) return false;
     if (field_representation().IsInteger32()) return false;
@@ -6922,14 +7051,12 @@
   }
 
  private:
-  HStoreNamedField(HValue* obj,
-                   HObjectAccess access,
-                   HValue* val,
+  HStoreNamedField(HValue* obj, HObjectAccess access, HValue* val,
                    StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
       : access_(access),
         dominator_(NULL),
-        has_transition_(false),
-        store_mode_(store_mode) {
+        bit_field_(HasTransitionField::encode(false) |
+                   StoreModeField::encode(store_mode)) {
     // Stores to a non existing in-object property are allowed only to the
     // newly allocated objects (via HAllocate or HInnerAllocatedObject).
     DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
@@ -6940,10 +7067,12 @@
     access.SetGVNFlags(this, STORE);
   }
 
+  class HasTransitionField : public BitField<bool, 0, 1> {};
+  class StoreModeField : public BitField<StoreFieldOrKeyedMode, 1, 1> {};
+
   HObjectAccess access_;
   HValue* dominator_;
-  bool has_transition_ : 1;
-  StoreFieldOrKeyedMode store_mode_ : 1;
+  uint32_t bit_field_;
 };
 
 
@@ -6958,9 +7087,9 @@
   Handle<String> name() const { return name_; }
   StrictMode strict_mode() const { return strict_mode_; }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -6995,7 +7124,7 @@
   DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*,
                                  ElementsKind, StoreFieldOrKeyedMode, int);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     // kind_fast:               tagged[int32] = tagged
     // kind_double:             tagged[int32] = double
     // kind_smi   :             tagged[int32] = smi
@@ -7010,7 +7139,7 @@
     }
 
     DCHECK_EQ(index, 2);
-    return RequiredValueRepresentation(elements_kind_, store_mode_);
+    return RequiredValueRepresentation(elements_kind(), store_mode());
   }
 
   static Representation RequiredValueRepresentation(
@@ -7046,12 +7175,13 @@
     return is_external() || is_fixed_typed_array();
   }
 
-  virtual Representation observed_input_representation(int index) OVERRIDE {
+  Representation observed_input_representation(int index) OVERRIDE {
     if (index < 2) return RequiredInputRepresentation(index);
     if (IsUninitialized()) {
       return Representation::None();
     }
-    Representation r = RequiredValueRepresentation(elements_kind_, store_mode_);
+    Representation r =
+        RequiredValueRepresentation(elements_kind(), store_mode());
     // For fast object elements kinds, don't assume anything.
     if (r.IsTagged()) return Representation::None();
     return r;
@@ -7060,20 +7190,26 @@
   HValue* elements() const { return OperandAt(0); }
   HValue* key() const { return OperandAt(1); }
   HValue* value() const { return OperandAt(2); }
-  bool value_is_smi() const {
-    return IsFastSmiElementsKind(elements_kind_);
+  bool value_is_smi() const { return IsFastSmiElementsKind(elements_kind()); }
+  StoreFieldOrKeyedMode store_mode() const {
+    return StoreModeField::decode(bit_field_);
   }
-  StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
-  ElementsKind elements_kind() const { return elements_kind_; }
+  ElementsKind elements_kind() const OVERRIDE {
+    return ElementsKindField::decode(bit_field_);
+  }
   uint32_t base_offset() const { return base_offset_; }
-  bool TryIncreaseBaseOffset(uint32_t increase_by_value);
-  HValue* GetKey() { return key(); }
-  void SetKey(HValue* key) { SetOperandAt(1, key); }
-  bool IsDehoisted() const { return is_dehoisted_; }
-  void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
-  bool IsUninitialized() { return is_uninitialized_; }
+  bool TryIncreaseBaseOffset(uint32_t increase_by_value) OVERRIDE;
+  HValue* GetKey() OVERRIDE { return key(); }
+  void SetKey(HValue* key) OVERRIDE { SetOperandAt(1, key); }
+  bool IsDehoisted() const OVERRIDE {
+    return IsDehoistedField::decode(bit_field_);
+  }
+  void SetDehoisted(bool is_dehoisted) OVERRIDE {
+    bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
+  }
+  bool IsUninitialized() { return IsUninitializedField::decode(bit_field_); }
   void SetUninitialized(bool is_uninitialized) {
-    is_uninitialized_ = is_uninitialized;
+    bit_field_ = IsUninitializedField::update(bit_field_, is_uninitialized);
   }
 
   bool IsConstantHoleStore() {
@@ -7104,23 +7240,22 @@
 
   bool NeedsCanonicalization();
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
 
  private:
-  HStoreKeyed(HValue* obj, HValue* key, HValue* val,
-              ElementsKind elements_kind,
+  HStoreKeyed(HValue* obj, HValue* key, HValue* val, ElementsKind elements_kind,
               StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
               int offset = kDefaultKeyedHeaderOffsetSentinel)
-      : elements_kind_(elements_kind),
-      base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
-          ? GetDefaultHeaderSizeForElementsKind(elements_kind)
-          : offset),
-      is_dehoisted_(false),
-      is_uninitialized_(false),
-      store_mode_(store_mode),
-      dominator_(NULL) {
+      : base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
+                         ? GetDefaultHeaderSizeForElementsKind(elements_kind)
+                         : offset),
+        bit_field_(IsDehoistedField::encode(false) |
+                   IsUninitializedField::encode(false) |
+                   StoreModeField::encode(store_mode) |
+                   ElementsKindField::encode(elements_kind)),
+        dominator_(NULL) {
     SetOperandAt(0, obj);
     SetOperandAt(1, key);
     SetOperandAt(2, val);
@@ -7152,11 +7287,13 @@
     }
   }
 
-  ElementsKind elements_kind_;
+  class IsDehoistedField : public BitField<bool, 0, 1> {};
+  class IsUninitializedField : public BitField<bool, 1, 1> {};
+  class StoreModeField : public BitField<StoreFieldOrKeyedMode, 2, 1> {};
+  class ElementsKindField : public BitField<ElementsKind, 3, 5> {};
+
   uint32_t base_offset_;
-  bool is_dehoisted_ : 1;
-  bool is_uninitialized_ : 1;
-  StoreFieldOrKeyedMode store_mode_: 1;
+  uint32_t bit_field_;
   HValue* dominator_;
 };
 
@@ -7172,12 +7309,12 @@
   HValue* context() const { return OperandAt(3); }
   StrictMode strict_mode() const { return strict_mode_; }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     // tagged[tagged] = tagged
     return Representation::Tagged();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric)
 
@@ -7210,7 +7347,7 @@
                                              original_map, transitioned_map);
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -7221,18 +7358,18 @@
   ElementsKind from_kind() const { return from_kind_; }
   ElementsKind to_kind() const { return to_kind_; }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
     return original_map_ == instr->original_map_ &&
            transitioned_map_ == instr->transitioned_map_;
   }
 
-  virtual int RedefinedOperandIndex() { return 0; }
+  int RedefinedOperandIndex() OVERRIDE { return 0; }
 
  private:
   HTransitionElementsKind(HValue* context,
@@ -7275,16 +7412,16 @@
   StringAddFlags flags() const { return flags_; }
   PretenureFlag pretenure_flag() const { return pretenure_flag_; }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(StringAdd)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     return flags_ == HStringAdd::cast(other)->flags_ &&
         pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
   }
@@ -7312,7 +7449,7 @@
   }
 
   // No side-effects except possible allocation:
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 
   const StringAddFlags flags_;
   const PretenureFlag pretenure_flag_;
@@ -7325,7 +7462,7 @@
                                               HValue*,
                                               HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     // The index is supposed to be Integer32.
     return index == 2
         ? Representation::Integer32()
@@ -7339,9 +7476,9 @@
   DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE {
+  Range* InferRange(Zone* zone) OVERRIDE {
     return new(zone) Range(0, String::kMaxUtf16CodeUnit);
   }
 
@@ -7358,7 +7495,7 @@
   }
 
   // No side effects: runtime function assumes string + number inputs.
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 };
 
 
@@ -7368,7 +7505,7 @@
                            HValue* context,
                            HValue* char_code);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return index == 0
         ? Representation::Tagged()
         : Representation::Integer32();
@@ -7377,7 +7514,7 @@
   HValue* context() const { return OperandAt(0); }
   HValue* value() const { return OperandAt(1); }
 
-  virtual bool DataEquals(HValue* other) OVERRIDE { return true; }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
   DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
 
@@ -7391,7 +7528,7 @@
     SetChangesFlag(kNewSpacePromotion);
   }
 
-  virtual bool IsDeletable() const OVERRIDE {
+  bool IsDeletable() const OVERRIDE {
     return !value()->ToNumberCanBeObserved();
   }
 };
@@ -7418,7 +7555,7 @@
   }
 
  private:
-  virtual bool IsDeletable() const FINAL OVERRIDE { return true; }
+  bool IsDeletable() const FINAL { return true; }
 
   int literal_index_;
   int depth_;
@@ -7439,7 +7576,7 @@
   Handle<String> pattern() { return pattern_; }
   Handle<String> flags() { return flags_; }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -7473,42 +7610,47 @@
                                               bool);
   HValue* context() { return OperandAt(0); }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
   DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
 
   Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
-  bool pretenure() const { return pretenure_; }
-  bool has_no_literals() const { return has_no_literals_; }
-  bool is_arrow() const { return IsArrowFunction(kind_); }
-  bool is_generator() const { return IsGeneratorFunction(kind_); }
-  bool is_concise_method() const { return IsConciseMethod(kind_); }
-  FunctionKind kind() const { return kind_; }
-  StrictMode strict_mode() const { return strict_mode_; }
+  bool pretenure() const { return PretenureField::decode(bit_field_); }
+  bool has_no_literals() const {
+    return HasNoLiteralsField::decode(bit_field_);
+  }
+  bool is_arrow() const { return IsArrowFunction(kind()); }
+  bool is_generator() const { return IsGeneratorFunction(kind()); }
+  bool is_concise_method() const { return IsConciseMethod(kind()); }
+  bool is_default_constructor() const { return IsDefaultConstructor(kind()); }
+  FunctionKind kind() const { return FunctionKindField::decode(bit_field_); }
+  StrictMode strict_mode() const { return StrictModeField::decode(bit_field_); }
 
  private:
   HFunctionLiteral(HValue* context, Handle<SharedFunctionInfo> shared,
                    bool pretenure)
       : HTemplateInstruction<1>(HType::JSObject()),
         shared_info_(shared),
-        kind_(shared->kind()),
-        pretenure_(pretenure),
-        has_no_literals_(shared->num_literals() == 0),
-        strict_mode_(shared->strict_mode()) {
+        bit_field_(FunctionKindField::encode(shared->kind()) |
+                   PretenureField::encode(pretenure) |
+                   HasNoLiteralsField::encode(shared->num_literals() == 0) |
+                   StrictModeField::encode(shared->strict_mode())) {
     SetOperandAt(0, context);
     set_representation(Representation::Tagged());
     SetChangesFlag(kNewSpacePromotion);
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
+
+  class FunctionKindField : public BitField<FunctionKind, 0, 4> {};
+  class PretenureField : public BitField<bool, 5, 1> {};
+  class HasNoLiteralsField : public BitField<bool, 6, 1> {};
+  class StrictModeField : public BitField<StrictMode, 7, 1> {};
 
   Handle<SharedFunctionInfo> shared_info_;
-  FunctionKind kind_;
-  bool pretenure_ : 1;
-  bool has_no_literals_ : 1;
-  StrictMode strict_mode_;
+  uint32_t bit_field_;
 };
 
 
@@ -7519,9 +7661,9 @@
   HValue* context() const { return OperandAt(0); }
   HValue* value() const { return OperandAt(1); }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -7534,7 +7676,7 @@
     set_representation(Representation::Tagged());
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 };
 
 
@@ -7542,7 +7684,7 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -7561,7 +7703,7 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -7582,7 +7724,7 @@
 #endif
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 };
 
 
@@ -7592,7 +7734,7 @@
 
   Smi* index() const { return index_; }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -7616,7 +7758,7 @@
                            HValue* string,
                            HValue* index);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return (index == 0) ? Representation::Tagged()
                         : Representation::Integer32();
   }
@@ -7628,11 +7770,11 @@
   DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar)
 
  protected:
-  virtual bool DataEquals(HValue* other) OVERRIDE {
+  bool DataEquals(HValue* other) OVERRIDE {
     return encoding() == HSeqStringGetChar::cast(other)->encoding();
   }
 
-  virtual Range* InferRange(Zone* zone) OVERRIDE {
+  Range* InferRange(Zone* zone) OVERRIDE {
     if (encoding() == String::ONE_BYTE_ENCODING) {
       return new(zone) Range(0, String::kMaxOneByteCharCode);
     } else {
@@ -7652,7 +7794,7 @@
     SetDependsOnFlag(kStringChars);
   }
 
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 
   String::Encoding encoding_;
 };
@@ -7670,7 +7812,7 @@
   HValue* index() { return OperandAt(2); }
   HValue* value() { return OperandAt(3); }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return (index <= 1) ? Representation::Tagged()
                         : Representation::Integer32();
   }
@@ -7699,13 +7841,13 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual HType CalculateInferredType() OVERRIDE {
+  HType CalculateInferredType() OVERRIDE {
     if (value()->type().IsHeapObject()) return value()->type();
     return HType::HeapObject();
   }
@@ -7713,16 +7855,14 @@
   HValue* value() const { return OperandAt(0); }
   HValue* map() const { return OperandAt(1); }
 
-  virtual HValue* Canonicalize() OVERRIDE;
+  HValue* Canonicalize() OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(CheckMapValue)
 
  protected:
-  virtual int RedefinedOperandIndex() { return 0; }
+  int RedefinedOperandIndex() OVERRIDE { return 0; }
 
-  virtual bool DataEquals(HValue* other) OVERRIDE {
-    return true;
-  }
+  bool DataEquals(HValue* other) OVERRIDE { return true; }
 
  private:
   HCheckMapValue(HValue* value, HValue* map)
@@ -7741,18 +7881,16 @@
  public:
   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
   HValue* context() const { return OperandAt(0); }
   HValue* enumerable() const { return OperandAt(1); }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual HType CalculateInferredType() OVERRIDE {
-    return HType::Tagged();
-  }
+  HType CalculateInferredType() OVERRIDE { return HType::Tagged(); }
 
   DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
 
@@ -7771,7 +7909,7 @@
  public:
   DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int);
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -7787,11 +7925,9 @@
     index_cache_ = index_cache;
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual HType CalculateInferredType() OVERRIDE {
-    return HType::Tagged();
-  }
+  HType CalculateInferredType() OVERRIDE { return HType::Tagged(); }
 
   DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
 
@@ -7821,7 +7957,7 @@
     set_representation(Representation::Tagged());
   }
 
-  virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     if (index == 1) {
       return Representation::Smi();
     } else {
@@ -7832,16 +7968,14 @@
   HValue* object() const { return OperandAt(0); }
   HValue* index() const { return OperandAt(1); }
 
-  virtual OStream& PrintDataTo(OStream& os) const OVERRIDE;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
-  virtual HType CalculateInferredType() OVERRIDE {
-    return HType::Tagged();
-  }
+  HType CalculateInferredType() OVERRIDE { return HType::Tagged(); }
 
   DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
 
  private:
-  virtual bool IsDeletable() const OVERRIDE { return true; }
+  bool IsDeletable() const OVERRIDE { return true; }
 };
 
 
@@ -7851,7 +7985,7 @@
 
   HValue* context() { return OperandAt(0); }
 
-  virtual Representation RequiredInputRepresentation(int index) {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
@@ -7873,11 +8007,11 @@
   HValue* function() const { return OperandAt(1); }
   Handle<ScopeInfo> scope_info() const { return scope_info_; }
 
-  virtual Representation RequiredInputRepresentation(int index) {
+  Representation RequiredInputRepresentation(int index) OVERRIDE {
     return Representation::Tagged();
   }
 
-  virtual OStream& PrintDataTo(OStream& os) const;  // NOLINT
+  std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE;  // NOLINT
 
   DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext)
 
diff --git a/src/hydrogen-removable-simulates.cc b/src/hydrogen-removable-simulates.cc
index a28021d..73d7a8e 100644
--- a/src/hydrogen-removable-simulates.cc
+++ b/src/hydrogen-removable-simulates.cc
@@ -53,6 +53,13 @@
       FlushSimulates();
       return this;
     }
+    if (instr->IsCapturedObject()) {
+      // Do not merge simulates across captured objects - captured objects
+      // change environments during environment replay, and such changes
+      // would not be reflected in the simulate.
+      FlushSimulates();
+      return this;
+    }
     // Skip the non-simulates and the first simulate.
     if (!instr->IsSimulate()) return this;
     if (first_) {
diff --git a/src/hydrogen-representation-changes.cc b/src/hydrogen-representation-changes.cc
index ebb03b5..bfc8271 100644
--- a/src/hydrogen-representation-changes.cc
+++ b/src/hydrogen-representation-changes.cc
@@ -63,7 +63,17 @@
 void HRepresentationChangesPhase::InsertRepresentationChangesForValue(
     HValue* value) {
   Representation r = value->representation();
-  if (r.IsNone()) return;
+  if (r.IsNone()) {
+#ifdef DEBUG
+    for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
+      HValue* use_value = it.value();
+      int use_index = it.index();
+      Representation req = use_value->RequiredInputRepresentation(use_index);
+      DCHECK(req.IsNone());
+    }
+#endif
+    return;
+  }
   if (value->HasNoUses()) {
     if (value->IsForceRepresentation()) value->DeleteAndReplaceWith(NULL);
     return;
diff --git a/src/hydrogen-types.cc b/src/hydrogen-types.cc
index 87047a2..a05e30f 100644
--- a/src/hydrogen-types.cc
+++ b/src/hydrogen-types.cc
@@ -56,7 +56,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const HType& t) {
+std::ostream& operator<<(std::ostream& os, const HType& t) {
   // Note: The c1visualizer syntax for locals allows only a sequence of the
   // following characters: A-Za-z0-9_-|:
   switch (t.kind_) {
diff --git a/src/hydrogen-types.h b/src/hydrogen-types.h
index a42cba5..70870dd 100644
--- a/src/hydrogen-types.h
+++ b/src/hydrogen-types.h
@@ -6,6 +6,7 @@
 #define HYDROGEN_TYPES_H_
 
 #include <climits>
+#include <iosfwd>
 
 #include "src/base/macros.h"
 
@@ -15,7 +16,6 @@
 // Forward declarations.
 template <typename T> class Handle;
 class Object;
-class OStream;
 
 #define HTYPE_LIST(V)                                 \
   V(Any, 0x0)              /* 0000 0000 0000 0000 */  \
@@ -65,7 +65,7 @@
   static HType FromType(typename T::TypeHandle type) WARN_UNUSED_RESULT;
   static HType FromValue(Handle<Object> value) WARN_UNUSED_RESULT;
 
-  friend OStream& operator<<(OStream& os, const HType& t);
+  friend std::ostream& operator<<(std::ostream& os, const HType& t);
 
  private:
   enum Kind {
@@ -84,7 +84,7 @@
 };
 
 
-OStream& operator<<(OStream& os, const HType& t);
+std::ostream& operator<<(std::ostream& os, const HType& t);
 } }  // namespace v8::internal
 
 #endif  // HYDROGEN_TYPES_H_
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 37ee2e4..a684311 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -4,14 +4,13 @@
 
 #include "src/hydrogen.h"
 
-#include <algorithm>
+#include <sstream>
 
 #include "src/v8.h"
 
 #include "src/allocation-site-scopes.h"
-#include "src/codegen.h"
+#include "src/ast-numbering.h"
 #include "src/full-codegen.h"
-#include "src/hashmap.h"
 #include "src/hydrogen-bce.h"
 #include "src/hydrogen-bch.h"
 #include "src/hydrogen-canonicalize.h"
@@ -40,9 +39,8 @@
 #include "src/ic/ic-inl.h"
 #include "src/lithium-allocator.h"
 #include "src/parser.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 #include "src/scopeinfo.h"
-#include "src/scopes.h"
 #include "src/typing.h"
 
 #if V8_TARGET_ARCH_IA32
@@ -147,7 +145,7 @@
       entry->set_position(position);
     } else {
       DCHECK(!FLAG_hydrogen_track_positions ||
-             !graph()->info()->IsOptimizing());
+             !graph()->info()->IsOptimizing() || instr->IsAbnormalExit());
     }
     first_ = last_ = entry;
   }
@@ -1219,8 +1217,8 @@
 void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) {
   if (FLAG_native_code_counters && counter->Enabled()) {
     HValue* reference = Add<HConstant>(ExternalReference(counter));
-    HValue* old_value = Add<HLoadNamedField>(
-        reference, static_cast<HValue*>(NULL), HObjectAccess::ForCounter());
+    HValue* old_value =
+        Add<HLoadNamedField>(reference, nullptr, HObjectAccess::ForCounter());
     HValue* new_value = AddUncasted<HAdd>(old_value, graph()->GetConstant1());
     new_value->ClearFlag(HValue::kCanOverflow);  // Ignore counter overflow
     Add<HStoreNamedField>(reference, HObjectAccess::ForCounter(),
@@ -1254,11 +1252,10 @@
 
 
 HValue* HGraphBuilder::BuildGetElementsKind(HValue* object) {
-  HValue* map = Add<HLoadNamedField>(object, static_cast<HValue*>(NULL),
-                                     HObjectAccess::ForMap());
+  HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap());
 
-  HValue* bit_field2 = Add<HLoadNamedField>(map, static_cast<HValue*>(NULL),
-                                            HObjectAccess::ForMapBitField2());
+  HValue* bit_field2 =
+      Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2());
   return BuildDecodeField<Map::ElementsKindBits>(bit_field2);
 }
 
@@ -1417,10 +1414,11 @@
 
     HInstruction* elements_length = AddLoadFixedArrayLength(elements);
 
-    HInstruction* array_length = is_jsarray
-        ? Add<HLoadNamedField>(object, static_cast<HValue*>(NULL),
-                               HObjectAccess::ForArrayLength(from_kind))
-        : elements_length;
+    HInstruction* array_length =
+        is_jsarray
+            ? Add<HLoadNamedField>(object, nullptr,
+                                   HObjectAccess::ForArrayLength(from_kind))
+            : elements_length;
 
     BuildGrowElementsCapacity(object, elements, from_kind, to_kind,
                               array_length, elements_length);
@@ -1438,14 +1436,14 @@
   Add<HCheckHeapObject>(receiver);
 
   // Get the map of the receiver.
-  HValue* map = Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL),
-                                     HObjectAccess::ForMap());
+  HValue* map =
+      Add<HLoadNamedField>(receiver, nullptr, HObjectAccess::ForMap());
 
   // Check the instance type and if an access check is needed, this can be
   // done with a single load, since both bytes are adjacent in the map.
   HObjectAccess access(HObjectAccess::ForMapInstanceTypeAndBitField());
   HValue* instance_type_and_bit_field =
-      Add<HLoadNamedField>(map, static_cast<HValue*>(NULL), access);
+      Add<HLoadNamedField>(map, nullptr, access);
 
   HValue* mask = Add<HConstant>(0x00FF | (bit_field_mask << 8));
   HValue* and_result = AddUncasted<HBitwise>(Token::BIT_AND,
@@ -1474,11 +1472,9 @@
   }
   key_smi_if.Else();
   {
-    HValue* map = Add<HLoadNamedField>(key, static_cast<HValue*>(NULL),
-                                       HObjectAccess::ForMap());
+    HValue* map = Add<HLoadNamedField>(key, nullptr, HObjectAccess::ForMap());
     HValue* instance_type =
-        Add<HLoadNamedField>(map, static_cast<HValue*>(NULL),
-                             HObjectAccess::ForMapInstanceType());
+        Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType());
 
     // Non-unique string, check for a string with a hash code that is actually
     // an index.
@@ -1510,9 +1506,8 @@
       {
         // String: check whether the String is a String of an index. If it is,
         // extract the index value from the hash.
-        HValue* hash =
-            Add<HLoadNamedField>(key, static_cast<HValue*>(NULL),
-                                 HObjectAccess::ForNameHashField());
+        HValue* hash = Add<HLoadNamedField>(key, nullptr,
+                                            HObjectAccess::ForNameHashField());
         HValue* not_index_mask = Add<HConstant>(static_cast<int>(
             String::kContainsCachedArrayIndexMask));
 
@@ -1571,11 +1566,10 @@
 void HGraphBuilder::BuildNonGlobalObjectCheck(HValue* receiver) {
   // Get the the instance type of the receiver, and make sure that it is
   // not one of the global object types.
-  HValue* map = Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL),
-                                     HObjectAccess::ForMap());
+  HValue* map =
+      Add<HLoadNamedField>(receiver, nullptr, HObjectAccess::ForMap());
   HValue* instance_type =
-    Add<HLoadNamedField>(map, static_cast<HValue*>(NULL),
-                         HObjectAccess::ForMapInstanceType());
+      Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType());
   STATIC_ASSERT(JS_BUILTINS_OBJECT_TYPE == JS_GLOBAL_OBJECT_TYPE + 1);
   HValue* min_global_type = Add<HConstant>(JS_GLOBAL_OBJECT_TYPE);
   HValue* max_global_type = Add<HConstant>(JS_BUILTINS_OBJECT_TYPE);
@@ -1597,11 +1591,9 @@
     HValue* object,
     HIfContinuation* continuation) {
   HValue* properties = Add<HLoadNamedField>(
-      object, static_cast<HValue*>(NULL),
-      HObjectAccess::ForPropertiesPointer());
+      object, nullptr, HObjectAccess::ForPropertiesPointer());
   HValue* properties_map =
-      Add<HLoadNamedField>(properties, static_cast<HValue*>(NULL),
-                           HObjectAccess::ForMap());
+      Add<HLoadNamedField>(properties, nullptr, HObjectAccess::ForMap());
   HValue* hash_map = Add<HLoadRoot>(Heap::kHashTableMapRootIndex);
   IfBuilder builder(this);
   builder.If<HCompareObjectEqAndBranch>(properties_map, hash_map);
@@ -1614,13 +1606,11 @@
   // Load the map of the receiver, compute the keyed lookup cache hash
   // based on 32 bits of the map pointer and the string hash.
   HValue* object_map =
-      Add<HLoadNamedField>(object, static_cast<HValue*>(NULL),
-                           HObjectAccess::ForMapAsInteger32());
+      Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMapAsInteger32());
   HValue* shifted_map = AddUncasted<HShr>(
       object_map, Add<HConstant>(KeyedLookupCache::kMapHashShift));
   HValue* string_hash =
-      Add<HLoadNamedField>(key, static_cast<HValue*>(NULL),
-                           HObjectAccess::ForStringHashField());
+      Add<HLoadNamedField>(key, nullptr, HObjectAccess::ForStringHashField());
   HValue* shifted_hash = AddUncasted<HShr>(
       string_hash, Add<HConstant>(String::kHashShift));
   HValue* xor_result = AddUncasted<HBitwise>(Token::BIT_XOR, shifted_map,
@@ -1668,11 +1658,9 @@
                                                            HValue* elements,
                                                            HValue* key,
                                                            HValue* hash) {
-  HValue* capacity = Add<HLoadKeyed>(
-      elements,
-      Add<HConstant>(NameDictionary::kCapacityIndex),
-      static_cast<HValue*>(NULL),
-      FAST_ELEMENTS);
+  HValue* capacity =
+      Add<HLoadKeyed>(elements, Add<HConstant>(NameDictionary::kCapacityIndex),
+                      nullptr, FAST_ELEMENTS);
 
   HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1());
   mask->ChangeRepresentation(Representation::Integer32());
@@ -1702,8 +1690,8 @@
       AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset));
   key_index->ClearFlag(HValue::kCanOverflow);
 
-  HValue* candidate_key = Add<HLoadKeyed>(
-      elements, key_index, static_cast<HValue*>(NULL), FAST_ELEMENTS);
+  HValue* candidate_key =
+      Add<HLoadKeyed>(elements, key_index, nullptr, FAST_ELEMENTS);
   IfBuilder if_undefined(this);
   if_undefined.If<HCompareObjectEqAndBranch>(candidate_key,
                                              graph()->GetConstantUndefined());
@@ -1729,8 +1717,8 @@
         if_update_with_internalized.IfNot<HIsSmiAndBranch>(candidate_key);
     if_update_with_internalized.And();
     HValue* map = AddLoadMap(candidate_key, smi_check);
-    HValue* instance_type = Add<HLoadNamedField>(
-        map, static_cast<HValue*>(NULL), HObjectAccess::ForMapInstanceType());
+    HValue* instance_type =
+        Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType());
     HValue* not_internalized_bit = AddUncasted<HBitwise>(
         Token::BIT_AND, instance_type,
         Add<HConstant>(static_cast<int>(kIsNotInternalizedMask)));
@@ -1757,8 +1745,8 @@
     HValue* details_index =
         AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset + 2));
     details_index->ClearFlag(HValue::kCanOverflow);
-    HValue* details = Add<HLoadKeyed>(
-        elements, details_index, static_cast<HValue*>(NULL), FAST_ELEMENTS);
+    HValue* details =
+        Add<HLoadKeyed>(elements, details_index, nullptr, FAST_ELEMENTS);
     int details_mask = PropertyDetails::TypeField::kMask |
                        PropertyDetails::DeletedField::kMask;
     details = AddUncasted<HBitwise>(Token::BIT_AND, details,
@@ -1770,8 +1758,7 @@
     HValue* result_index =
         AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset + 1));
     result_index->ClearFlag(HValue::kCanOverflow);
-    Push(Add<HLoadKeyed>(elements, result_index, static_cast<HValue*>(NULL),
-                         FAST_ELEMENTS));
+    Push(Add<HLoadKeyed>(elements, result_index, nullptr, FAST_ELEMENTS));
     details_compare.Else();
     Add<HPushArguments>(receiver, key);
     Push(Add<HCallRuntime>(isolate()->factory()->empty_string(),
@@ -1823,15 +1810,14 @@
 
   // Initialize the JSRegExpResult header.
   HValue* global_object = Add<HLoadNamedField>(
-      context(), static_cast<HValue*>(NULL),
+      context(), nullptr,
       HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
   HValue* native_context = Add<HLoadNamedField>(
-      global_object, static_cast<HValue*>(NULL),
-      HObjectAccess::ForGlobalObjectNativeContext());
+      global_object, nullptr, HObjectAccess::ForGlobalObjectNativeContext());
   Add<HStoreNamedField>(
       result, HObjectAccess::ForMap(),
       Add<HLoadNamedField>(
-          native_context, static_cast<HValue*>(NULL),
+          native_context, nullptr,
           HObjectAccess::ForContextSlot(Context::REGEXP_RESULT_MAP_INDEX)));
   HConstant* empty_fixed_array =
       Add<HConstant>(isolate()->factory()->empty_fixed_array());
@@ -1910,8 +1896,7 @@
 
     // Load the key.
     HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1());
-    HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
-                                  static_cast<HValue*>(NULL),
+    HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, nullptr,
                                   FAST_ELEMENTS, ALLOW_RETURN_HOLE);
 
     // Check if object == key.
@@ -1947,8 +1932,7 @@
 
         // Load the key.
         HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1());
-        HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
-                                      static_cast<HValue*>(NULL),
+        HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, nullptr,
                                       FAST_ELEMENTS, ALLOW_RETURN_HOLE);
 
         // Check if the key is a heap number and compare it with the object.
@@ -2001,8 +1985,7 @@
     // Load the value in case of cache hit.
     HValue* key_index = Pop();
     HValue* value_index = AddUncasted<HAdd>(key_index, graph()->GetConstant1());
-    Push(Add<HLoadKeyed>(number_string_cache, value_index,
-                         static_cast<HValue*>(NULL),
+    Push(Add<HLoadKeyed>(number_string_cache, value_index, nullptr,
                          FAST_ELEMENTS, ALLOW_RETURN_HOLE));
   }
   if_found.Else();
@@ -2442,8 +2425,7 @@
     HValue* backing_store;
     if (IsExternalArrayElementsKind(elements_kind)) {
       backing_store = Add<HLoadNamedField>(
-          elements, static_cast<HValue*>(NULL),
-          HObjectAccess::ForExternalArrayExternalPointer());
+          elements, nullptr, HObjectAccess::ForExternalArrayExternalPointer());
     } else {
       backing_store = elements;
     }
@@ -2626,16 +2608,15 @@
 }
 
 
-HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader(
-    ElementsKind kind,
-    HValue* capacity) {
+HValue* HGraphBuilder::BuildAllocateAndInitializeArray(ElementsKind kind,
+                                                       HValue* capacity) {
   // The HForceRepresentation is to prevent possible deopt on int-smi
   // conversion after allocation but before the new object fields are set.
   capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
   HValue* size_in_bytes = BuildCalculateElementsSize(kind, capacity);
-  HValue* new_elements = BuildAllocateElements(kind, size_in_bytes);
-  BuildInitializeElementsHeader(new_elements, kind, capacity);
-  return new_elements;
+  HValue* new_array = BuildAllocateElements(kind, size_in_bytes);
+  BuildInitializeElementsHeader(new_array, kind, capacity);
+  return new_array;
 }
 
 
@@ -2690,9 +2671,8 @@
   DCHECK(val == NULL);
   HLoadKeyed* load = Add<HLoadKeyed>(
       elements, checked_key, dependency, elements_kind, load_mode);
-  if (FLAG_opt_safe_uint32_operations &&
-      (elements_kind == EXTERNAL_UINT32_ELEMENTS ||
-       elements_kind == UINT32_ELEMENTS)) {
+  if (elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+      elements_kind == UINT32_ELEMENTS) {
     graph()->RecordUint32Instruction(load);
   }
   return load;
@@ -2754,8 +2734,8 @@
           (Page::kMaxRegularHeapObjectSize - FixedArray::kHeaderSize) >>
           ElementsKindToShiftSize(new_kind)));
 
-  HValue* new_elements = BuildAllocateElementsAndInitializeElementsHeader(
-      new_kind, new_capacity);
+  HValue* new_elements =
+      BuildAllocateAndInitializeArray(new_kind, new_capacity);
 
   BuildCopyElements(elements, kind, new_elements,
                     new_kind, length, new_capacity);
@@ -2789,12 +2769,6 @@
     }
   }
 
-  // Since we're about to store a hole value, the store instruction below must
-  // assume an elements kind that supports heap object values.
-  if (IsFastSmiOrObjectElementsKind(elements_kind)) {
-    elements_kind = FAST_HOLEY_ELEMENTS;
-  }
-
   if (initial_capacity >= 0) {
     for (int i = 0; i < initial_capacity; i++) {
       HInstruction* key = Add<HConstant>(i);
@@ -2832,10 +2806,39 @@
       ? Add<HConstant>(factory->the_hole_value())
       : Add<HConstant>(nan_double);
 
+  // Since we're about to store a hole value, the store instruction below must
+  // assume an elements kind that supports heap object values.
+  if (IsFastSmiOrObjectElementsKind(elements_kind)) {
+    elements_kind = FAST_HOLEY_ELEMENTS;
+  }
+
   BuildFillElementsWithValue(elements, elements_kind, from, to, hole);
 }
 
 
+void HGraphBuilder::BuildCopyProperties(HValue* from_properties,
+                                        HValue* to_properties, HValue* length,
+                                        HValue* capacity) {
+  ElementsKind kind = FAST_ELEMENTS;
+
+  BuildFillElementsWithValue(to_properties, kind, length, capacity,
+                             graph()->GetConstantUndefined());
+
+  LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
+
+  HValue* key = builder.BeginBody(length, graph()->GetConstant0(), Token::GT);
+
+  key = AddUncasted<HSub>(key, graph()->GetConstant1());
+  key->ClearFlag(HValue::kCanOverflow);
+
+  HValue* element = Add<HLoadKeyed>(from_properties, key, nullptr, kind);
+
+  Add<HStoreKeyed>(to_properties, key, element, kind);
+
+  builder.EndBody();
+}
+
+
 void HGraphBuilder::BuildCopyElements(HValue* from_elements,
                                       ElementsKind from_elements_kind,
                                       HValue* to_elements,
@@ -2868,8 +2871,7 @@
     for (int i = 0; i < constant_capacity; i++) {
       HValue* key_constant = Add<HConstant>(i);
       HInstruction* value = Add<HLoadKeyed>(from_elements, key_constant,
-                                            static_cast<HValue*>(NULL),
-                                            from_elements_kind);
+                                            nullptr, from_elements_kind);
       Add<HStoreKeyed>(to_elements, key_constant, value, to_elements_kind);
     }
   } else {
@@ -2879,10 +2881,6 @@
                                 length, NULL);
     }
 
-    if (capacity == NULL) {
-      capacity = AddLoadFixedArrayLength(to_elements);
-    }
-
     LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
 
     HValue* key = builder.BeginBody(length, graph()->GetConstant0(),
@@ -2891,10 +2889,8 @@
     key = AddUncasted<HSub>(key, graph()->GetConstant1());
     key->ClearFlag(HValue::kCanOverflow);
 
-    HValue* element = Add<HLoadKeyed>(from_elements, key,
-                                      static_cast<HValue*>(NULL),
-                                      from_elements_kind,
-                                      ALLOW_RETURN_HOLE);
+    HValue* element = Add<HLoadKeyed>(from_elements, key, nullptr,
+                                      from_elements_kind, ALLOW_RETURN_HOLE);
 
     ElementsKind kind = (IsHoleyElementsKind(from_elements_kind) &&
                          IsFastSmiElementsKind(to_elements_kind))
@@ -3005,9 +3001,9 @@
   // Copy the elements array header.
   for (int i = 0; i < FixedArrayBase::kHeaderSize; i += kPointerSize) {
     HObjectAccess access = HObjectAccess::ForFixedArrayHeader(i);
-    Add<HStoreNamedField>(elements, access,
-        Add<HLoadNamedField>(boilerplate_elements,
-                             static_cast<HValue*>(NULL), access));
+    Add<HStoreNamedField>(
+        elements, access,
+        Add<HLoadNamedField>(boilerplate_elements, nullptr, access));
   }
 
   // And the result of the length
@@ -3020,10 +3016,9 @@
 }
 
 
-void HGraphBuilder::BuildCompareNil(
-    HValue* value,
-    Type* type,
-    HIfContinuation* continuation) {
+void HGraphBuilder::BuildCompareNil(HValue* value, Type* type,
+                                    HIfContinuation* continuation,
+                                    MapEmbedding map_embedding) {
   IfBuilder if_nil(this);
   bool some_case_handled = false;
   bool some_case_missing = false;
@@ -3062,7 +3057,21 @@
       // the monomorphic map when the code is used as a template to generate a
       // new IC. For optimized functions, there is no sentinel map, the map
       // emitted below is the actual monomorphic map.
-      Add<HCheckMaps>(value, type->Classes().Current());
+      if (map_embedding == kEmbedMapsViaWeakCells) {
+        HValue* cell =
+            Add<HConstant>(Map::WeakCellForMap(type->Classes().Current()));
+        HValue* expected_map = Add<HLoadNamedField>(
+            cell, nullptr, HObjectAccess::ForWeakCellValue());
+        HValue* map =
+            Add<HLoadNamedField>(value, nullptr, HObjectAccess::ForMap());
+        IfBuilder map_check(this);
+        map_check.IfNot<HCompareObjectEqAndBranch>(expected_map, map);
+        map_check.ThenDeopt("Unknown map");
+        map_check.End();
+      } else {
+        DCHECK(map_embedding == kEmbedMapsDirectly);
+        Add<HCheckMaps>(value, type->Classes().Current());
+      }
     } else {
       if_nil.Deopt("Too many undetectable types");
     }
@@ -3086,10 +3095,10 @@
       HObjectAccess::ForAllocationMementoSite(),
       allocation_site);
   if (FLAG_allocation_site_pretenuring) {
-    HValue* memento_create_count = Add<HLoadNamedField>(
-        allocation_site, static_cast<HValue*>(NULL),
-        HObjectAccess::ForAllocationSiteOffset(
-            AllocationSite::kPretenureCreateCountOffset));
+    HValue* memento_create_count =
+        Add<HLoadNamedField>(allocation_site, nullptr,
+                             HObjectAccess::ForAllocationSiteOffset(
+                                 AllocationSite::kPretenureCreateCountOffset));
     memento_create_count = AddUncasted<HAdd>(
         memento_create_count, graph()->GetConstant1());
     // This smi value is reset to zero after every gc, overflow isn't a problem
@@ -3103,29 +3112,36 @@
 
 
 HInstruction* HGraphBuilder::BuildGetNativeContext(HValue* closure) {
-  // Get the global context, then the native context
-  HInstruction* context =
-      Add<HLoadNamedField>(closure, static_cast<HValue*>(NULL),
-                           HObjectAccess::ForFunctionContextPointer());
+  // Get the global object, then the native context
+  HInstruction* context = Add<HLoadNamedField>(
+      closure, nullptr, HObjectAccess::ForFunctionContextPointer());
   HInstruction* global_object = Add<HLoadNamedField>(
-      context, static_cast<HValue*>(NULL),
+      context, nullptr,
       HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
   HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset(
       GlobalObject::kNativeContextOffset);
-  return Add<HLoadNamedField>(
-      global_object, static_cast<HValue*>(NULL), access);
+  return Add<HLoadNamedField>(global_object, nullptr, access);
+}
+
+
+HInstruction* HGraphBuilder::BuildGetScriptContext(int context_index) {
+  HValue* native_context = BuildGetNativeContext();
+  HValue* script_context_table = Add<HLoadNamedField>(
+      native_context, nullptr,
+      HObjectAccess::ForContextSlot(Context::SCRIPT_CONTEXT_TABLE_INDEX));
+  return Add<HLoadNamedField>(script_context_table, nullptr,
+                              HObjectAccess::ForScriptContext(context_index));
 }
 
 
 HInstruction* HGraphBuilder::BuildGetNativeContext() {
-  // Get the global context, then the native context
+  // Get the global object, then the native context
   HValue* global_object = Add<HLoadNamedField>(
-      context(), static_cast<HValue*>(NULL),
+      context(), nullptr,
       HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
-  return Add<HLoadNamedField>(
-      global_object, static_cast<HValue*>(NULL),
-      HObjectAccess::ForObservableJSObjectOffset(
-          GlobalObject::kNativeContextOffset));
+  return Add<HLoadNamedField>(global_object, nullptr,
+                              HObjectAccess::ForObservableJSObjectOffset(
+                                  GlobalObject::kNativeContextOffset));
 }
 
 
@@ -3133,8 +3149,7 @@
   HInstruction* native_context = BuildGetNativeContext();
   HInstruction* index =
       Add<HConstant>(static_cast<int32_t>(Context::ARRAY_FUNCTION_INDEX));
-  return Add<HLoadKeyed>(
-      native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS);
+  return Add<HLoadKeyed>(native_context, index, nullptr, FAST_ELEMENTS);
 }
 
 
@@ -3179,8 +3194,8 @@
     // No need for a context lookup if the kind_ matches the initial
     // map, because we can just load the map in that case.
     HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap();
-    return builder()->Add<HLoadNamedField>(
-        constructor_function_, static_cast<HValue*>(NULL), access);
+    return builder()->Add<HLoadNamedField>(constructor_function_, nullptr,
+                                           access);
   }
 
   // TODO(mvstanton): we should always have a constructor function if we
@@ -3192,21 +3207,21 @@
   HInstruction* index = builder()->Add<HConstant>(
       static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX));
 
-  HInstruction* map_array = builder()->Add<HLoadKeyed>(
-      native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS);
+  HInstruction* map_array =
+      builder()->Add<HLoadKeyed>(native_context, index, nullptr, FAST_ELEMENTS);
 
   HInstruction* kind_index = builder()->Add<HConstant>(kind_);
 
-  return builder()->Add<HLoadKeyed>(
-      map_array, kind_index, static_cast<HValue*>(NULL), FAST_ELEMENTS);
+  return builder()->Add<HLoadKeyed>(map_array, kind_index, nullptr,
+                                    FAST_ELEMENTS);
 }
 
 
 HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() {
   // Find the map near the constructor function
   HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap();
-  return builder()->Add<HLoadNamedField>(
-      constructor_function_, static_cast<HValue*>(NULL), access);
+  return builder()->Add<HLoadNamedField>(constructor_function_, nullptr,
+                                         access);
 }
 
 
@@ -3305,16 +3320,14 @@
 
 HValue* HGraphBuilder::AddLoadJSBuiltin(Builtins::JavaScript builtin) {
   HValue* global_object = Add<HLoadNamedField>(
-      context(), static_cast<HValue*>(NULL),
+      context(), nullptr,
       HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
   HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset(
       GlobalObject::kBuiltinsOffset);
-  HValue* builtins = Add<HLoadNamedField>(
-      global_object, static_cast<HValue*>(NULL), access);
+  HValue* builtins = Add<HLoadNamedField>(global_object, nullptr, access);
   HObjectAccess function_access = HObjectAccess::ForObservableJSObjectOffset(
           JSBuiltinsObject::OffsetOfFunctionWithId(builtin));
-  return Add<HLoadNamedField>(
-      builtins, static_cast<HValue*>(NULL), function_access);
+  return Add<HLoadNamedField>(builtins, nullptr, function_access);
 }
 
 
@@ -3330,7 +3343,7 @@
   // This is not initialized in the initializer list because the
   // constructor for the initial state relies on function_state_ == NULL
   // to know it's the initial state.
-  function_state_= &initial_function_state_;
+  function_state_ = &initial_function_state_;
   InitializeAstVisitor(info->zone());
   if (FLAG_hydrogen_track_positions) {
     SetSourcePosition(info->shared_info()->start_position());
@@ -3408,7 +3421,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const HBasicBlock& b) {
+std::ostream& operator<<(std::ostream& os, const HBasicBlock& b) {
   return os << "B" << b.block_id();
 }
 
@@ -3431,8 +3444,9 @@
       maximum_environment_size_(0),
       no_side_effects_scope_count_(0),
       disallow_adding_new_values_(false),
-      next_inline_id_(0),
-      inlined_functions_(5, info->zone()) {
+      inlined_functions_(FLAG_hydrogen_track_positions ? 5 : 0, info->zone()),
+      inlining_id_to_function_id_(FLAG_hydrogen_track_positions ? 5 : 0,
+                                  info->zone()) {
   if (info->IsStub()) {
     CallInterfaceDescriptor descriptor =
         info->code_stub()->GetCallInterfaceDescriptor();
@@ -3492,9 +3506,7 @@
         os << "--- FUNCTION SOURCE (" << shared->DebugName()->ToCString().get()
            << ") id{" << info()->optimization_id() << "," << id << "} ---\n";
         {
-          ConsStringIteratorOp op;
           StringCharacterStream stream(String::cast(script->source()),
-                                       &op,
                                        shared->start_position());
           // fun->end_position() points to the last character in the stream. We
           // need to compensate by adding one to calculate the length.
@@ -3512,14 +3524,15 @@
     }
   }
 
-  int inline_id = next_inline_id_++;
+  int inline_id = inlining_id_to_function_id_.length();
+  inlining_id_to_function_id_.Add(id, zone());
 
   if (inline_id != 0) {
     CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
     OFStream os(tracing_scope.file());
     os << "INLINE (" << shared->DebugName()->ToCString().get() << ") id{"
        << info()->optimization_id() << "," << id << "} AS " << inline_id
-       << " AT " << position << endl;
+       << " AT " << position << std::endl;
   }
 
   return inline_id;
@@ -3531,8 +3544,8 @@
     return pos.raw();
   }
 
-  return inlined_functions_[pos.inlining_id()].start_position() +
-      pos.position();
+  const int id = inlining_id_to_function_id_[pos.inlining_id()];
+  return inlined_functions_[id].start_position() + pos.position();
 }
 
 
@@ -4024,8 +4037,12 @@
 void ValueContext::ReturnValue(HValue* value) {
   // The value is tracked in the bailout environment, and communicated
   // through the environment as the result of the expression.
-  if (!arguments_allowed() && value->CheckFlag(HValue::kIsArguments)) {
-    owner()->Bailout(kBadValueContextForArgumentsValue);
+  if (value->CheckFlag(HValue::kIsArguments)) {
+    if (flag_ == ARGUMENTS_FAKED) {
+      value = owner()->graph()->GetConstantUndefined();
+    } else if (!arguments_allowed()) {
+      owner()->Bailout(kBadValueContextForArgumentsValue);
+    }
   }
   owner()->Push(value);
 }
@@ -4251,20 +4268,16 @@
 }
 
 
+void HOptimizedGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs,
+                                              ArgumentsAllowedFlag flag) {
+  for (int i = 0; i < exprs->length(); ++i) {
+    CHECK_ALIVE(VisitForValue(exprs->at(i), flag));
+  }
+}
+
+
 bool HOptimizedGraphBuilder::BuildGraph() {
-  if (current_info()->function()->is_generator()) {
-    Bailout(kFunctionIsAGenerator);
-    return false;
-  }
   Scope* scope = current_info()->scope();
-  if (scope->HasIllegalRedeclaration()) {
-    Bailout(kFunctionWithIllegalRedeclaration);
-    return false;
-  }
-  if (scope->calls_eval()) {
-    Bailout(kFunctionCallsEval);
-    return false;
-  }
   SetUpScope(scope);
 
   // Add an edge to the body entry.  This is warty: the graph's start
@@ -4384,7 +4397,7 @@
   // Must be performed before canonicalization to ensure that Canonicalize
   // will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with
   // zero.
-  if (FLAG_opt_safe_uint32_operations) Run<HUint32AnalysisPhase>();
+  Run<HUint32AnalysisPhase>();
 
   if (FLAG_use_canonicalizing) Run<HCanonicalizePhase>();
 
@@ -4500,10 +4513,6 @@
   // Handle the arguments and arguments shadow variables specially (they do
   // not have declarations).
   if (scope->arguments() != NULL) {
-    if (!scope->arguments()->IsStackAllocated()) {
-      return Bailout(kContextAllocatedArguments);
-    }
-
     environment()->Bind(scope->arguments(),
                         graph()->GetArgumentsObject());
   }
@@ -4539,7 +4548,7 @@
       Scope* declaration_scope = scope->DeclarationScope();
       HInstruction* function;
       HValue* outer_context = environment()->context();
-      if (declaration_scope->is_global_scope() ||
+      if (declaration_scope->is_script_scope() ||
           declaration_scope->is_eval_scope()) {
         function = new(zone()) HLoadContextSlot(
             outer_context, Context::CLOSURE_INDEX, HLoadContextSlot::kNoCheck);
@@ -4551,11 +4560,11 @@
       HInstruction* inner_context = Add<HAllocateBlockContext>(
           outer_context, function, scope->GetScopeInfo());
       HInstruction* instr = Add<HStoreFrameContext>(inner_context);
+      set_scope(scope);
+      environment()->BindContext(inner_context);
       if (instr->HasObservableSideEffects()) {
         AddSimulate(stmt->EntryId(), REMOVABLE_SIMULATE);
       }
-      set_scope(scope);
-      environment()->BindContext(inner_context);
       VisitDeclarations(scope->declarations());
       AddSimulate(stmt->DeclsId(), REMOVABLE_SIMULATE);
     }
@@ -4565,14 +4574,14 @@
   if (scope != NULL && current_block() != NULL) {
     HValue* inner_context = environment()->context();
     HValue* outer_context = Add<HLoadNamedField>(
-        inner_context, static_cast<HValue*>(NULL),
+        inner_context, nullptr,
         HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
 
     HInstruction* instr = Add<HStoreFrameContext>(outer_context);
+    environment()->BindContext(outer_context);
     if (instr->HasObservableSideEffects()) {
       AddSimulate(stmt->ExitId(), REMOVABLE_SIMULATE);
     }
-    environment()->BindContext(outer_context);
   }
   HBasicBlock* break_block = break_info.break_block();
   if (break_block != NULL) {
@@ -4696,7 +4705,7 @@
   if (context_pop_count > 0) {
     while (context_pop_count-- > 0) {
       HInstruction* context_instruction = Add<HLoadNamedField>(
-          context, static_cast<HValue*>(NULL),
+          context, nullptr,
           HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
       context = context_instruction;
     }
@@ -4728,7 +4737,7 @@
   if (context_pop_count > 0) {
     while (context_pop_count-- > 0) {
       HInstruction* context_instruction = Add<HLoadNamedField>(
-          context, static_cast<HValue*>(NULL),
+          context, nullptr,
           HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
       context = context_instruction;
     }
@@ -5328,7 +5337,7 @@
   int length = scope()->ContextChainLength(var->scope());
   while (length-- > 0) {
     context = Add<HLoadNamedField>(
-        context, static_cast<HValue*>(NULL),
+        context, nullptr,
         HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
   }
   return context;
@@ -5360,6 +5369,22 @@
       }
 
       Handle<GlobalObject> global(current_info()->global_object());
+
+      if (FLAG_harmony_scoping) {
+        Handle<ScriptContextTable> script_contexts(
+            global->native_context()->script_context_table());
+        ScriptContextTable::LookupResult lookup;
+        if (ScriptContextTable::Lookup(script_contexts, variable->name(),
+                                       &lookup)) {
+          Handle<Context> script_context = ScriptContextTable::GetContext(
+              script_contexts, lookup.context_index);
+          HInstruction* result = New<HLoadNamedField>(
+              Add<HConstant>(script_context), nullptr,
+              HObjectAccess::ForContextSlot(lookup.slot_index));
+          return ast_context()->ReturnInstruction(result, expr->id());
+        }
+      }
+
       LookupIterator it(global, variable->name(),
                         LookupIterator::OWN_SKIP_INTERCEPTOR);
       GlobalPropertyAccess type = LookupGlobalProperty(variable, &it, LOAD);
@@ -5382,7 +5407,7 @@
         }
       } else {
         HValue* global_object = Add<HLoadNamedField>(
-            context(), static_cast<HValue*>(NULL),
+            context(), nullptr,
             HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
         HLoadGlobalGeneric* instr =
             New<HLoadGlobalGeneric>(global_object,
@@ -5487,7 +5512,7 @@
   Handle<FixedArrayBase> elements(boilerplate->elements());
   if (elements->length() > 0 &&
       elements->map() != isolate->heap()->fixed_cow_array_map()) {
-    if (boilerplate->HasFastObjectElements()) {
+    if (boilerplate->HasFastSmiOrObjectElements()) {
       Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
       int length = elements->length();
       for (int i = 0; i < length; i++) {
@@ -5517,9 +5542,11 @@
     for (int i = 0; i < limit; i++) {
       PropertyDetails details = descriptors->GetDetails(i);
       if (details.type() != FIELD) continue;
-      int index = descriptors->GetFieldIndex(i);
       if ((*max_properties)-- == 0) return false;
-      Handle<Object> value(boilerplate->InObjectPropertyAt(index), isolate);
+      FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
+      if (boilerplate->IsUnboxedDoubleField(field_index)) continue;
+      Handle<Object> value(boilerplate->RawFastPropertyAt(field_index),
+                           isolate);
       if (value->IsJSObject()) {
         Handle<JSObject> value_object = Handle<JSObject>::cast(value);
         if (!IsFastLiteral(value_object,
@@ -5603,10 +5630,23 @@
         DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
         // Fall through.
       case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             CHECK_ALIVE(VisitForValue(value));
             HValue* value = Pop();
+
+            // Add [[HomeObject]] to function literals.
+            if (FunctionLiteral::NeedsHomeObject(property->value())) {
+              Handle<Symbol> sym = isolate()->factory()->home_object_symbol();
+              HInstruction* store_home = BuildKeyedGeneric(
+                  STORE, NULL, value, Add<HConstant>(sym), literal);
+              AddInstruction(store_home);
+              DCHECK(store_home->HasObservableSideEffects());
+              Add<HSimulate>(property->value()->id(), REMOVABLE_SIMULATE);
+            }
+
             Handle<Map> map = property->GetReceiverType();
             Handle<String> name = property->key()->AsPropertyName();
             HInstruction* store;
@@ -5628,9 +5668,8 @@
               }
             }
             AddInstruction(store);
-            if (store->HasObservableSideEffects()) {
-              Add<HSimulate>(key->id(), REMOVABLE_SIMULATE);
-            }
+            DCHECK(store->HasObservableSideEffects());
+            Add<HSimulate>(key->id(), REMOVABLE_SIMULATE);
           } else {
             CHECK_ALIVE(VisitForEffect(value));
           }
@@ -5734,17 +5773,13 @@
                         Add<HConstant>(constants),
                         Add<HConstant>(flags));
 
-    // TODO(mvstanton): Consider a flag to turn off creation of any
-    // AllocationMementos for this call: we are in crankshaft and should have
-    // learned enough about transition behavior to stop emitting mementos.
     Runtime::FunctionId function_id = Runtime::kCreateArrayLiteral;
     literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
                                 Runtime::FunctionForId(function_id),
                                 4);
 
-    // De-opt if elements kind changed from boilerplate_elements_kind.
-    Handle<Map> map = Handle<Map>(boilerplate_object->map(), isolate());
-    literal = Add<HCheckMaps>(literal, map);
+    // Register to deopt if the boilerplate ElementsKind changes.
+    AllocationSite::RegisterForDeoptOnTransitionChange(site, top_info());
   }
 
   // The array is expected in the bailout environment during computation
@@ -5820,10 +5855,11 @@
   }
 
   HObjectAccess access = info->access();
-  if (access.representation().IsDouble()) {
+  if (access.representation().IsDouble() &&
+      (!FLAG_unbox_double_fields || !access.IsInobject())) {
     // Load the heap number.
     checked_object = Add<HLoadNamedField>(
-        checked_object, static_cast<HValue*>(NULL),
+        checked_object, nullptr,
         access.WithRepresentation(Representation::Tagged()));
     // Load the double value from it.
     access = HObjectAccess::ForHeapNumberValue();
@@ -5852,7 +5888,8 @@
   HObjectAccess field_access = info->access();
 
   HStoreNamedField *instr;
-  if (field_access.representation().IsDouble()) {
+  if (field_access.representation().IsDouble() &&
+      (!FLAG_unbox_double_fields || !field_access.IsInobject())) {
     HObjectAccess heap_number_access =
         field_access.WithRepresentation(Representation::Tagged());
     if (transition_to_field) {
@@ -5874,8 +5911,8 @@
                                     heap_number);
     } else {
       // Already holds a HeapNumber; load the box and write its value field.
-      HInstruction* heap_number = Add<HLoadNamedField>(
-          checked_object, static_cast<HValue*>(NULL), heap_number_access);
+      HInstruction* heap_number =
+          Add<HLoadNamedField>(checked_object, nullptr, heap_number_access);
       instr = New<HStoreNamedField>(heap_number,
                                     HObjectAccess::ForHeapNumberValue(),
                                     value, STORE_TO_INITIALIZED_ENTRY);
@@ -6096,7 +6133,7 @@
 
   if (IsAccessor()) return true;
   Handle<Map> map = this->map();
-  map->LookupTransition(NULL, *name_, &lookup_);
+  map->LookupTransition(NULL, *name_, NONE, &lookup_);
   if (lookup_.IsTransitionToField() && map->unused_property_fields() > 0) {
     // Construct the object field access.
     int descriptor = transition()->LastAdded();
@@ -6289,7 +6326,7 @@
   HControlInstruction* smi_check = NULL;
   handled_string = false;
 
-  for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
+  for (i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
     PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name);
     if (info.type()->Is(Type::String())) {
       if (handled_string) continue;
@@ -6367,7 +6404,7 @@
   // know about and do not want to handle ones we've never seen.  Otherwise
   // use a generic IC.
   if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
-    FinishExitWithHardDeoptimization("Uknown map in polymorphic access");
+    FinishExitWithHardDeoptimization("Unknown map in polymorphic access");
   } else {
     HInstruction* instr = BuildNamedGeneric(access_type, expr, object, name,
                                             value);
@@ -6484,6 +6521,27 @@
     HValue* value,
     BailoutId ast_id) {
   Handle<GlobalObject> global(current_info()->global_object());
+
+  if (FLAG_harmony_scoping) {
+    Handle<ScriptContextTable> script_contexts(
+        global->native_context()->script_context_table());
+    ScriptContextTable::LookupResult lookup;
+    if (ScriptContextTable::Lookup(script_contexts, var->name(), &lookup)) {
+      if (lookup.mode == CONST) {
+        return Bailout(kNonInitializerAssignmentToConst);
+      }
+      Handle<Context> script_context =
+          ScriptContextTable::GetContext(script_contexts, lookup.context_index);
+      HStoreNamedField* instr = Add<HStoreNamedField>(
+          Add<HConstant>(script_context),
+          HObjectAccess::ForContextSlot(lookup.slot_index), value);
+      USE(instr);
+      DCHECK(instr->HasObservableSideEffects());
+      Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
+      return;
+    }
+  }
+
   LookupIterator it(global, var->name(), LookupIterator::OWN_SKIP_INTERCEPTOR);
   GlobalPropertyAccess type = LookupGlobalProperty(var, &it, STORE);
   if (type == kUseCell) {
@@ -6518,7 +6576,7 @@
     }
   } else {
     HValue* global_object = Add<HLoadNamedField>(
-        context(), static_cast<HValue*>(NULL),
+        context(), nullptr,
         HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
     HStoreNamedGeneric* instr =
         Add<HStoreNamedGeneric>(global_object, var->name(),
@@ -6560,6 +6618,9 @@
         if (var->mode() == CONST_LEGACY)  {
           return Bailout(kUnsupportedConstCompoundAssignment);
         }
+        if (var->mode() == CONST) {
+          return Bailout(kNonInitializerAssignmentToConst);
+        }
         BindIfLive(var, Top());
         break;
 
@@ -6586,9 +6647,7 @@
             mode = HStoreContextSlot::kCheckDeoptimize;
             break;
           case CONST:
-            // This case is checked statically so no need to
-            // perform checks here
-            UNREACHABLE();
+            return Bailout(kNonInitializerAssignmentToConst);
           case CONST_LEGACY:
             return ast_context()->ReturnValue(Pop());
           default:
@@ -6801,9 +6860,8 @@
     }
   }
   return Add<HLoadNamedField>(
-      Add<HLoadNamedField>(string, static_cast<HValue*>(NULL),
-                           HObjectAccess::ForMap()),
-      static_cast<HValue*>(NULL), HObjectAccess::ForMapInstanceType());
+      Add<HLoadNamedField>(string, nullptr, HObjectAccess::ForMap()), nullptr,
+      HObjectAccess::ForMapInstanceType());
 }
 
 
@@ -6814,7 +6872,7 @@
       return Add<HConstant>(c_string->StringValue()->length());
     }
   }
-  return Add<HLoadNamedField>(string, static_cast<HValue*>(NULL),
+  return Add<HLoadNamedField>(string, nullptr,
                               HObjectAccess::ForStringLength());
 }
 
@@ -6835,9 +6893,10 @@
     if (FLAG_vector_ics) {
       Handle<SharedFunctionInfo> current_shared =
           function_state()->compilation_info()->shared_info();
-      result->SetVectorAndSlot(
-          handle(current_shared->feedback_vector(), isolate()),
-          expr->AsProperty()->PropertyFeedbackSlot());
+      Handle<TypeFeedbackVector> vector =
+          handle(current_shared->feedback_vector(), isolate());
+      FeedbackVectorICSlot slot = expr->AsProperty()->PropertyFeedbackSlot();
+      result->SetVectorAndSlot(vector, slot);
     }
     return result;
   } else {
@@ -6858,9 +6917,10 @@
     if (FLAG_vector_ics) {
       Handle<SharedFunctionInfo> current_shared =
           function_state()->compilation_info()->shared_info();
-      result->SetVectorAndSlot(
-          handle(current_shared->feedback_vector(), isolate()),
-          expr->AsProperty()->PropertyFeedbackSlot());
+      Handle<TypeFeedbackVector> vector =
+          handle(current_shared->feedback_vector(), isolate());
+      FeedbackVectorICSlot slot = expr->AsProperty()->PropertyFeedbackSlot();
+      result->SetVectorAndSlot(vector, slot);
     }
     return result;
   } else {
@@ -6923,6 +6983,12 @@
 }
 
 
+static bool CanInlineElementAccess(Handle<Map> map) {
+  return map->IsJSObjectMap() && !map->has_slow_elements_kind() &&
+         !map->has_indexed_interceptor();
+}
+
+
 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad(
     HValue* object,
     HValue* key,
@@ -6940,7 +7006,7 @@
   Handle<Map> most_general_consolidated_map;
   for (int i = 0; i < maps->length(); ++i) {
     Handle<Map> map = maps->at(i);
-    if (!map->IsJSObjectMap()) return NULL;
+    if (!CanInlineElementAccess(map)) return NULL;
     // Don't allow mixing of JSArrays with JSObjects.
     if (map->instance_type() == JS_ARRAY_TYPE) {
       if (has_non_js_array_access) return NULL;
@@ -7016,8 +7082,11 @@
   MapHandleList possible_transitioned_maps(maps->length());
   for (int i = 0; i < maps->length(); ++i) {
     Handle<Map> map = maps->at(i);
+    // Loads from strings or loads with a mix of string and non-string maps
+    // shouldn't be handled polymorphically.
+    DCHECK(access_type != LOAD || !map->IsStringMap());
     ElementsKind elements_kind = map->elements_kind();
-    if (IsFastElementsKind(elements_kind) &&
+    if (CanInlineElementAccess(map) && IsFastElementsKind(elements_kind) &&
         elements_kind != GetInitialFastElementsKind()) {
       possible_transitioned_maps.Add(map);
     }
@@ -7058,8 +7127,7 @@
   if (untransitionable_maps.length() == 1) {
     Handle<Map> untransitionable_map = untransitionable_maps[0];
     HInstruction* instr = NULL;
-    if (untransitionable_map->has_slow_elements_kind() ||
-        !untransitionable_map->IsJSObjectMap()) {
+    if (!CanInlineElementAccess(untransitionable_map)) {
       instr = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key,
                                                val));
     } else {
@@ -7075,7 +7143,6 @@
 
   for (int i = 0; i < untransitionable_maps.length(); ++i) {
     Handle<Map> map = untransitionable_maps[i];
-    if (!map->IsJSObjectMap()) continue;
     ElementsKind elements_kind = map->elements_kind();
     HBasicBlock* this_map = graph()->CreateBasicBlock();
     HBasicBlock* other_map = graph()->CreateBasicBlock();
@@ -7085,7 +7152,7 @@
 
     set_current_block(this_map);
     HInstruction* access = NULL;
-    if (IsDictionaryElementsKind(elements_kind)) {
+    if (!CanInlineElementAccess(map)) {
       access = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key,
                                                 val));
     } else {
@@ -7129,7 +7196,9 @@
     HValue* obj, HValue* key, HValue* val, Expression* expr, BailoutId ast_id,
     BailoutId return_id, PropertyAccessType access_type,
     bool* has_side_effects) {
-  if (key->ActualValue()->IsConstant()) {
+  // TODO(mvstanton): This optimization causes trouble for vector-based
+  // KeyedLoadICs, turn it off for now.
+  if (!FLAG_vector_ics && key->ActualValue()->IsConstant()) {
     Handle<Object> constant =
         HConstant::cast(key->ActualValue())->handle(isolate());
     uint32_t array_index;
@@ -7159,8 +7228,14 @@
   bool monomorphic = ComputeReceiverTypes(expr, obj, &types, zone());
 
   bool force_generic = false;
-  if (access_type == STORE &&
-      (monomorphic || (types != NULL && !types->is_empty()))) {
+  if (expr->GetKeyType() == PROPERTY) {
+    // Non-Generic accesses assume that elements are being accessed, and will
+    // deopt for non-index keys, which the IC knows will occur.
+    // TODO(jkummerow): Consider adding proper support for property accesses.
+    force_generic = true;
+    monomorphic = false;
+  } else if (access_type == STORE &&
+             (monomorphic || (types != NULL && !types->is_empty()))) {
     // Stores can't be mono/polymorphic if their prototype chain has dictionary
     // elements. However a receiver map that has dictionary elements itself
     // should be left to normal mono/poly behavior (the other maps may benefit
@@ -7173,11 +7248,24 @@
         break;
       }
     }
+  } else if (access_type == LOAD && !monomorphic &&
+             (types != NULL && !types->is_empty())) {
+    // Polymorphic loads have to go generic if any of the maps are strings.
+    // If some, but not all of the maps are strings, we should go generic
+    // because polymorphic access wants to key on ElementsKind and isn't
+    // compatible with strings.
+    for (int i = 0; i < types->length(); i++) {
+      Handle<Map> current_map = types->at(i);
+      if (current_map->IsStringMap()) {
+        force_generic = true;
+        break;
+      }
+    }
   }
 
   if (monomorphic) {
     Handle<Map> map = types->first();
-    if (map->has_slow_elements_kind() || !map->IsJSObjectMap()) {
+    if (!CanInlineElementAccess(map)) {
       instr = AddInstruction(BuildKeyedGeneric(access_type, expr, obj, key,
                                                val));
     } else {
@@ -7475,8 +7563,7 @@
   } else {
     HValue* param_count_value = Add<HConstant>(formal_parameter_count);
     HValue* context = Add<HLoadNamedField>(
-        target, static_cast<HValue*>(NULL),
-        HObjectAccess::ForFunctionContextPointer());
+        target, nullptr, HObjectAccess::ForFunctionContextPointer());
     return NewArgumentAdaptorCall(target, context,
         argument_count, param_count_value);
   }
@@ -7743,7 +7830,7 @@
     TraceInline(target, caller, "target not inlineable");
     return kNotInlinable;
   }
-  if (target_shared->DisableOptimizationReason() != kNoReason) {
+  if (target_shared->disable_optimization_reason() != kNoReason) {
     TraceInline(target, caller, "target contains unsupported syntax [early]");
     return kNotInlinable;
   }
@@ -7807,7 +7894,7 @@
   // step, but don't transfer ownership to target_info.
   target_info.SetAstValueFactory(top_info()->ast_value_factory(), false);
   Handle<SharedFunctionInfo> target_shared(target->shared());
-  if (!Parser::Parse(&target_info) || !Scope::Analyze(&target_info)) {
+  if (!Compiler::ParseAndAnalyze(&target_info)) {
     if (target_info.isolate()->has_pending_exception()) {
       // Parse or scope error, never optimize this function.
       SetStackOverflow();
@@ -7843,13 +7930,6 @@
       TraceInline(target, caller, "target uses arguments object");
       return false;
     }
-
-    if (!function->scope()->arguments()->IsStackAllocated()) {
-      TraceInline(target,
-                  caller,
-                  "target uses non-stackallocated arguments object");
-      return false;
-    }
   }
 
   // All declarations must be inlineable.
@@ -8085,9 +8165,9 @@
 }
 
 
-bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function,
-                                            Call* expr,
-                                            int arguments_count) {
+bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function,
+                                                   Call* expr,
+                                                   int arguments_count) {
   return TryInline(function,
                    arguments_count,
                    NULL,
@@ -8139,13 +8219,22 @@
 
 
 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
-    Call* expr,
-    HValue* receiver,
-    Handle<Map> receiver_map) {
+    Call* expr, Handle<JSFunction> function, Handle<Map> receiver_map,
+    int args_count_no_receiver) {
+  if (!function->shared()->HasBuiltinFunctionId()) return false;
+  BuiltinFunctionId id = function->shared()->builtin_function_id();
+  int argument_count = args_count_no_receiver + 1;  // Plus receiver.
+
+  if (receiver_map.is_null()) {
+    HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver);
+    if (receiver->IsConstant() &&
+        HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) {
+      receiver_map =
+          handle(Handle<HeapObject>::cast(
+                     HConstant::cast(receiver)->handle(isolate()))->map());
+    }
+  }
   // Try to inline calls like Math.* as operations in the calling function.
-  if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
-  BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
-  int argument_count = expr->arguments()->length() + 1;  // Plus receiver.
   switch (id) {
     case kStringCharCodeAt:
     case kStringCharAt:
@@ -8250,19 +8339,20 @@
       if (receiver_map.is_null()) return false;
       if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
       ElementsKind elements_kind = receiver_map->elements_kind();
+      if (JSArray::IsReadOnlyLengthDescriptor(receiver_map)) return false;
       if (!IsFastElementsKind(elements_kind)) return false;
       if (receiver_map->is_observed()) return false;
       if (!receiver_map->is_extensible()) return false;
 
-      Drop(expr->arguments()->length());
+      Drop(args_count_no_receiver);
       HValue* result;
       HValue* reduced_length;
       HValue* receiver = Pop();
 
       HValue* checked_object = AddCheckMap(receiver, receiver_map);
-      HValue* length = Add<HLoadNamedField>(
-          checked_object, static_cast<HValue*>(NULL),
-          HObjectAccess::ForArrayLength(elements_kind));
+      HValue* length =
+          Add<HLoadNamedField>(checked_object, nullptr,
+                               HObjectAccess::ForArrayLength(elements_kind));
 
       Drop(1);  // Function.
 
@@ -8330,7 +8420,7 @@
       Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
       BuildCheckPrototypeMaps(prototype, Handle<JSObject>());
 
-      const int argc = expr->arguments()->length();
+      const int argc = args_count_no_receiver;
       if (argc != 1) return false;
 
       HValue* value_to_push = Pop();
@@ -8343,8 +8433,8 @@
       {
         NoObservableSideEffectsScope scope(this);
 
-        length = Add<HLoadNamedField>(array, static_cast<HValue*>(NULL),
-          HObjectAccess::ForArrayLength(elements_kind));
+        length = Add<HLoadNamedField>(
+            array, nullptr, HObjectAccess::ForArrayLength(elements_kind));
 
         new_size = AddUncasted<HAdd>(length, graph()->GetConstant1());
 
@@ -8367,6 +8457,7 @@
       if (receiver_map.is_null()) return false;
       if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
       ElementsKind kind = receiver_map->elements_kind();
+      if (JSArray::IsReadOnlyLengthDescriptor(receiver_map)) return false;
       if (!IsFastElementsKind(kind)) return false;
       if (receiver_map->is_observed()) return false;
       if (!receiver_map->is_extensible()) return false;
@@ -8387,7 +8478,7 @@
       // Threshold for fast inlined Array.shift().
       HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16));
 
-      Drop(expr->arguments()->length());
+      Drop(args_count_no_receiver);
       HValue* receiver = Pop();
       HValue* function = Pop();
       HValue* result;
@@ -8396,8 +8487,7 @@
         NoObservableSideEffectsScope scope(this);
 
         HValue* length = Add<HLoadNamedField>(
-            receiver, static_cast<HValue*>(NULL),
-            HObjectAccess::ForArrayLength(kind));
+            receiver, nullptr, HObjectAccess::ForArrayLength(kind));
 
         IfBuilder if_lengthiszero(this);
         HValue* lengthiszero = if_lengthiszero.If<HCompareNumericAndBranch>(
@@ -8439,10 +8529,12 @@
                   graph()->GetConstant0(), new_length, Token::LT);
               HValue* key = AddUncasted<HAdd>(new_key, graph()->GetConstant1());
               key->ClearFlag(HValue::kCanOverflow);
+              ElementsKind copy_kind =
+                  kind == FAST_HOLEY_SMI_ELEMENTS ? FAST_HOLEY_ELEMENTS : kind;
               HValue* element = AddUncasted<HLoadKeyed>(
-                  elements, key, lengthiszero, kind, ALLOW_RETURN_HOLE);
-              HStoreKeyed* store = Add<HStoreKeyed>(
-                  elements, new_key, element, kind);
+                  elements, key, lengthiszero, copy_kind, ALLOW_RETURN_HOLE);
+              HStoreKeyed* store =
+                  Add<HStoreKeyed>(elements, new_key, element, copy_kind);
               store->SetFlag(HValue::kAllowUndefinedAsNaN);
             }
             loop.EndBody();
@@ -8693,7 +8785,47 @@
 }
 
 
-bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
+void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, HValue* function,
+                                                int arguments_count) {
+  Handle<JSFunction> known_function;
+  int args_count_no_receiver = arguments_count - 1;
+  if (function->IsConstant() &&
+      HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
+    HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver);
+    Handle<Map> receiver_map;
+    if (receiver->IsConstant() &&
+        HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) {
+      receiver_map =
+          handle(Handle<HeapObject>::cast(
+                     HConstant::cast(receiver)->handle(isolate()))->map());
+    }
+
+    known_function =
+        Handle<JSFunction>::cast(HConstant::cast(function)->handle(isolate()));
+    if (TryInlineBuiltinMethodCall(expr, known_function, receiver_map,
+                                   args_count_no_receiver)) {
+      if (FLAG_trace_inlining) {
+        PrintF("Inlining builtin ");
+        known_function->ShortPrint();
+        PrintF("\n");
+      }
+      return;
+    }
+
+    if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) {
+      return;
+    }
+  }
+
+  PushArgumentsFromEnvironment(arguments_count);
+  HInvokeFunction* call =
+      New<HInvokeFunction>(function, known_function, arguments_count);
+  Drop(1);  // Function
+  ast_context()->ReturnInstruction(call, expr->id());
+}
+
+
+bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) {
   DCHECK(expr->expression()->IsProperty());
 
   if (!expr->IsMonomorphic()) {
@@ -8701,27 +8833,40 @@
   }
   Handle<Map> function_map = expr->GetReceiverTypes()->first();
   if (function_map->instance_type() != JS_FUNCTION_TYPE ||
-      !expr->target()->shared()->HasBuiltinFunctionId() ||
-      expr->target()->shared()->builtin_function_id() != kFunctionApply) {
+      !expr->target()->shared()->HasBuiltinFunctionId()) {
     return false;
   }
 
-  if (current_info()->scope()->arguments() == NULL) return false;
+  switch (expr->target()->shared()->builtin_function_id()) {
+    case kFunctionCall: {
+      if (expr->arguments()->length() == 0) return false;
+      BuildFunctionCall(expr);
+      return true;
+    }
+    case kFunctionApply: {
+      // For .apply, only the pattern f.apply(receiver, arguments)
+      // is supported.
+      if (current_info()->scope()->arguments() == NULL) return false;
 
+      if (!CanBeFunctionApplyArguments(expr)) return false;
+
+      BuildFunctionApply(expr);
+      return true;
+    }
+    default: { return false; }
+  }
+  UNREACHABLE();
+}
+
+
+void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) {
   ZoneList<Expression*>* args = expr->arguments();
-  if (args->length() != 2) return false;
-
-  VariableProxy* arg_two = args->at(1)->AsVariableProxy();
-  if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
-  HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
-  if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
-
-  // Found pattern f.apply(receiver, arguments).
-  CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true);
+  CHECK_ALIVE(VisitForValue(args->at(0)));
   HValue* receiver = Pop();  // receiver
   HValue* function = Pop();  // f
   Drop(1);  // apply
 
+  Handle<Map> function_map = expr->GetReceiverTypes()->first();
   HValue* checked_function = AddCheckMap(function, function_map);
 
   if (function_state()->outer() == NULL) {
@@ -8733,7 +8878,6 @@
                                                 length,
                                                 elements);
     ast_context()->ReturnInstruction(result, expr->id());
-    return true;
   } else {
     // We are inside inlined function and we know exactly what is inside
     // arguments object. But we need to be able to materialize at deopt.
@@ -8747,26 +8891,36 @@
     for (int i = 1; i < arguments_count; i++) {
       Push(arguments_values->at(i));
     }
-
-    Handle<JSFunction> known_function;
-    if (function->IsConstant() &&
-        HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
-      known_function = Handle<JSFunction>::cast(
-          HConstant::cast(function)->handle(isolate()));
-      int args_count = arguments_count - 1;  // Excluding receiver.
-      if (TryInlineApply(known_function, expr, args_count)) return true;
-    }
-
-    PushArgumentsFromEnvironment(arguments_count);
-    HInvokeFunction* call = New<HInvokeFunction>(
-        function, known_function, arguments_count);
-    Drop(1);  // Function.
-    ast_context()->ReturnInstruction(call, expr->id());
-    return true;
+    HandleIndirectCall(expr, function, arguments_count);
   }
 }
 
 
+// f.call(...)
+void HOptimizedGraphBuilder::BuildFunctionCall(Call* expr) {
+  HValue* function = Top();  // f
+  Handle<Map> function_map = expr->GetReceiverTypes()->first();
+  HValue* checked_function = AddCheckMap(function, function_map);
+
+  // f and call are on the stack in the unoptimized code
+  // during evaluation of the arguments.
+  CHECK_ALIVE(VisitExpressions(expr->arguments()));
+
+  int args_length = expr->arguments()->length();
+  int receiver_index = args_length - 1;
+  // Patch the receiver.
+  HValue* receiver = BuildWrapReceiver(
+      environment()->ExpressionStackAt(receiver_index), checked_function);
+  environment()->SetExpressionStackAt(receiver_index, receiver);
+
+  // Call must not be on the stack from now on.
+  int call_index = args_length + 1;
+  environment()->RemoveExpressionStackAt(call_index);
+
+  HandleIndirectCall(expr, function, args_length);
+}
+
+
 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function,
                                                     Handle<JSFunction> target) {
   SharedFunctionInfo* shared = target->shared();
@@ -8840,9 +8994,8 @@
     LoopBuilder loop(this, context(), direction);
     {
       HValue* index = loop.BeginBody(initial, terminating, token);
-      HValue* element = AddUncasted<HLoadKeyed>(
-          elements, index, static_cast<HValue*>(NULL),
-          kind, ALLOW_RETURN_HOLE);
+      HValue* element = AddUncasted<HLoadKeyed>(elements, index, nullptr, kind,
+                                                ALLOW_RETURN_HOLE);
       IfBuilder if_issame(this);
       if_issame.If<HCompareNumericAndBranch>(element, search_element,
                                              Token::EQ_STRICT);
@@ -8863,9 +9016,8 @@
       LoopBuilder loop(this, context(), direction);
       {
         HValue* index = loop.BeginBody(initial, terminating, token);
-        HValue* element = AddUncasted<HLoadKeyed>(
-            elements, index, static_cast<HValue*>(NULL),
-            kind, ALLOW_RETURN_HOLE);
+        HValue* element = AddUncasted<HLoadKeyed>(elements, index, nullptr,
+                                                  kind, ALLOW_RETURN_HOLE);
         IfBuilder if_issame(this);
         if_issame.If<HIsStringAndBranch>(element);
         if_issame.AndIf<HStringCompareAndBranch>(
@@ -8894,9 +9046,8 @@
         LoopBuilder loop(this, context(), direction);
         {
           HValue* index = loop.BeginBody(initial, terminating, token);
-          HValue* element = AddUncasted<HLoadKeyed>(
-              elements, index, static_cast<HValue*>(NULL),
-              kind, ALLOW_RETURN_HOLE);
+          HValue* element = AddUncasted<HLoadKeyed>(elements, index, nullptr,
+                                                    kind, ALLOW_RETURN_HOLE);
 
           IfBuilder if_element_isnumber(this);
           if_element_isnumber.If<HIsSmiAndBranch>(element);
@@ -8927,9 +9078,8 @@
         LoopBuilder loop(this, context(), direction);
         {
           HValue* index = loop.BeginBody(initial, terminating, token);
-          HValue* element = AddUncasted<HLoadKeyed>(
-              elements, index, static_cast<HValue*>(NULL),
-              kind, ALLOW_RETURN_HOLE);
+          HValue* element = AddUncasted<HLoadKeyed>(elements, index, nullptr,
+                                                    kind, ALLOW_RETURN_HOLE);
           IfBuilder if_issame(this);
           if_issame.If<HCompareObjectEqAndBranch>(
               element, search_element);
@@ -8982,6 +9132,17 @@
 }
 
 
+bool HOptimizedGraphBuilder::CanBeFunctionApplyArguments(Call* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  if (args->length() != 2) return false;
+  VariableProxy* arg_two = args->at(1)->AsVariableProxy();
+  if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
+  HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
+  if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
+  return true;
+}
+
+
 void HOptimizedGraphBuilder::VisitCall(Call* expr) {
   DCHECK(!HasStackOverflow());
   DCHECK(current_block() != NULL);
@@ -9018,22 +9179,24 @@
 
     if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
 
-    // Push the function under the receiver.
-    environment()->SetExpressionStackAt(0, function);
 
-    Push(receiver);
 
     if (function->IsConstant() &&
         HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
+      // Push the function under the receiver.
+      environment()->SetExpressionStackAt(0, function);
+      Push(receiver);
+
       Handle<JSFunction> known_function = Handle<JSFunction>::cast(
           HConstant::cast(function)->handle(isolate()));
       expr->set_target(known_function);
 
-      if (TryCallApply(expr)) return;
+      if (TryIndirectCall(expr)) return;
       CHECK_ALIVE(VisitExpressions(expr->arguments()));
 
       Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>();
-      if (TryInlineBuiltinMethodCall(expr, receiver, map)) {
+      if (TryInlineBuiltinMethodCall(expr, known_function, map,
+                                     expr->arguments()->length())) {
         if (FLAG_trace_inlining) {
           PrintF("Inlining builtin ");
           known_function->ShortPrint();
@@ -9059,7 +9222,20 @@
       }
 
     } else {
-      CHECK_ALIVE(VisitExpressions(expr->arguments()));
+      ArgumentsAllowedFlag arguments_flag = ARGUMENTS_NOT_ALLOWED;
+      if (CanBeFunctionApplyArguments(expr) && expr->is_uninitialized()) {
+        // We have to use EAGER deoptimization here because Deoptimizer::SOFT
+        // gets ignored by the always-opt flag, which leads to incorrect code.
+        Add<HDeoptimize>("Insufficient type feedback for call with arguments",
+                         Deoptimizer::EAGER);
+        arguments_flag = ARGUMENTS_FAKED;
+      }
+
+      // Push the function under the receiver.
+      environment()->SetExpressionStackAt(0, function);
+      Push(receiver);
+
+      CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag));
       CallFunctionFlags flags = receiver->type().IsJSObject()
           ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD;
       call = New<HCallFunction>(function, argument_count, flags);
@@ -9087,7 +9263,6 @@
                         LookupIterator::OWN_SKIP_INTERCEPTOR);
       GlobalPropertyAccess type = LookupGlobalProperty(var, &it, LOAD);
       if (type == kUseCell) {
-        Handle<GlobalObject> global(current_info()->global_object());
         known_global_function = expr->ComputeGlobalTarget(global, &it);
       }
       if (known_global_function) {
@@ -9173,8 +9348,7 @@
   HValue* constructor = environment()->ExpressionStackAt(argument_count);
 
   // Register on the site for deoptimization if the transition feedback changes.
-  AllocationSite::AddDependentCompilationInfo(
-      site, AllocationSite::TRANSITIONS, top_info());
+  AllocationSite::RegisterForDeoptOnTransitionChange(site, top_info());
   ElementsKind kind = site->GetElementsKind();
   HInstruction* site_instruction = Add<HConstant>(site);
 
@@ -9304,9 +9478,8 @@
         Handle<AllocationSite> allocation_site = expr->allocation_site();
         allocation_mode = HAllocationMode(allocation_site);
         // Take a dependency on allocation site.
-        AllocationSite::AddDependentCompilationInfo(allocation_site,
-                                                    AllocationSite::TENURING,
-                                                    top_info());
+        AllocationSite::RegisterForDeoptOnTenureChange(allocation_site,
+                                                       top_info());
       }
     }
 
@@ -9427,11 +9600,9 @@
         HObjectAccess::ForJSArrayBufferViewBuffer(), buffer);
     HObjectAccess weak_first_view_access =
         HObjectAccess::ForJSArrayBufferWeakFirstView();
-    Add<HStoreNamedField>(obj,
-        HObjectAccess::ForJSArrayBufferViewWeakNext(),
-        Add<HLoadNamedField>(buffer,
-                             static_cast<HValue*>(NULL),
-                             weak_first_view_access));
+    Add<HStoreNamedField>(
+        obj, HObjectAccess::ForJSArrayBufferViewWeakNext(),
+        Add<HLoadNamedField>(buffer, nullptr, weak_first_view_access));
     Add<HStoreNamedField>(buffer, weak_first_view_access, obj);
   } else {
     Add<HStoreNamedField>(
@@ -9511,8 +9682,7 @@
       HObjectAccess::ForFixedArrayLength(), length);
 
   HValue* backing_store = Add<HLoadNamedField>(
-      buffer, static_cast<HValue*>(NULL),
-      HObjectAccess::ForJSArrayBufferBackingStore());
+      buffer, nullptr, HObjectAccess::ForJSArrayBufferBackingStore());
 
   HValue* typed_array_start;
   if (is_zero_byte_offset) {
@@ -9730,9 +9900,7 @@
   CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
   HValue* buffer = Pop();
   HInstruction* result = New<HLoadNamedField>(
-    buffer,
-    static_cast<HValue*>(NULL),
-    HObjectAccess::ForJSArrayBufferByteLength());
+      buffer, nullptr, HObjectAccess::ForJSArrayBufferByteLength());
   return ast_context()->ReturnInstruction(result, expr->id());
 }
 
@@ -9743,9 +9911,7 @@
   CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
   HValue* buffer = Pop();
   HInstruction* result = New<HLoadNamedField>(
-    buffer,
-    static_cast<HValue*>(NULL),
-    HObjectAccess::ForJSArrayBufferViewByteLength());
+      buffer, nullptr, HObjectAccess::ForJSArrayBufferViewByteLength());
   return ast_context()->ReturnInstruction(result, expr->id());
 }
 
@@ -9756,9 +9922,7 @@
   CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
   HValue* buffer = Pop();
   HInstruction* result = New<HLoadNamedField>(
-    buffer,
-    static_cast<HValue*>(NULL),
-    HObjectAccess::ForJSArrayBufferViewByteOffset());
+      buffer, nullptr, HObjectAccess::ForJSArrayBufferViewByteOffset());
   return ast_context()->ReturnInstruction(result, expr->id());
 }
 
@@ -9769,9 +9933,7 @@
   CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
   HValue* buffer = Pop();
   HInstruction* result = New<HLoadNamedField>(
-    buffer,
-    static_cast<HValue*>(NULL),
-    HObjectAccess::ForJSTypedArrayLength());
+      buffer, nullptr, HObjectAccess::ForJSTypedArrayLength());
   return ast_context()->ReturnInstruction(result, expr->id());
 }
 
@@ -10004,6 +10166,9 @@
     if (var->mode() == CONST_LEGACY)  {
       return Bailout(kUnsupportedCountOperationWithConst);
     }
+    if (var->mode() == CONST) {
+      return Bailout(kNonInitializerAssignmentToConst);
+    }
     // Argument of the count operation is a variable, not a property.
     DCHECK(prop == NULL);
     CHECK_ALIVE(VisitForValue(target));
@@ -10153,7 +10318,7 @@
       !ShiftAmountsAllowReplaceByRotate(shr->right(), shl->right())) {
     return false;
   }
-  *operand= shr->left();
+  *operand = shr->left();
   *shift_amount = shr->right();
   return true;
 }
@@ -10349,8 +10514,7 @@
     if (!allocation_mode.feedback_site().is_null()) {
       DCHECK(!graph()->info()->IsStub());
       Handle<AllocationSite> site(allocation_mode.feedback_site());
-      AllocationSite::AddDependentCompilationInfo(
-          site, AllocationSite::TENURING, top_info());
+      AllocationSite::RegisterForDeoptOnTenureChange(site, top_info());
     }
 
     // Inline the string addition into the stub when creating allocation
@@ -10441,8 +10605,7 @@
         break;
       case Token::SHR:
         instr = AddUncasted<HShr>(left, right);
-        if (FLAG_opt_safe_uint32_operations && instr->IsShr() &&
-            CanBeZero(right)) {
+        if (instr->IsShr() && CanBeZero(right)) {
           graph()->RecordUint32Instruction(instr);
         }
         break;
@@ -10946,13 +11109,14 @@
       boilerplate_object->map()->instance_size());
 
   PretenureFlag pretenure_flag = NOT_TENURED;
+  Handle<AllocationSite> site(site_context->current());
   if (FLAG_allocation_site_pretenuring) {
     pretenure_flag = site_context->current()->GetPretenureMode();
-    Handle<AllocationSite> site(site_context->current());
-    AllocationSite::AddDependentCompilationInfo(
-        site, AllocationSite::TENURING, top_info());
+    AllocationSite::RegisterForDeoptOnTenureChange(site, top_info());
   }
 
+  AllocationSite::RegisterForDeoptOnTransitionChange(site, top_info());
+
   HInstruction* object = Add<HAllocate>(object_size_constant, type,
       pretenure_flag, instance_type, site_context->current());
 
@@ -11069,18 +11233,27 @@
     PropertyDetails details = descriptors->GetDetails(i);
     if (details.type() != FIELD) continue;
     copied_fields++;
-    int index = descriptors->GetFieldIndex(i);
-    int property_offset = boilerplate_object->GetInObjectPropertyOffset(index);
+    FieldIndex field_index = FieldIndex::ForDescriptor(*boilerplate_map, i);
+
+
+    int property_offset = field_index.offset();
     Handle<Name> name(descriptors->GetKey(i));
-    Handle<Object> value =
-        Handle<Object>(boilerplate_object->InObjectPropertyAt(index),
-        isolate());
 
     // The access for the store depends on the type of the boilerplate.
     HObjectAccess access = boilerplate_object->IsJSArray() ?
         HObjectAccess::ForJSArrayOffset(property_offset) :
         HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset);
 
+    if (boilerplate_object->IsUnboxedDoubleField(field_index)) {
+      CHECK(!boilerplate_object->IsJSArray());
+      double value = boilerplate_object->RawFastDoublePropertyAt(field_index);
+      access = access.WithRepresentation(Representation::Double());
+      Add<HStoreNamedField>(object, access, Add<HConstant>(value));
+      continue;
+    }
+    Handle<Object> value(boilerplate_object->RawFastPropertyAt(field_index),
+                         isolate());
+
     if (value->IsJSObject()) {
       Handle<JSObject> value_object = Handle<JSObject>::cast(value);
       Handle<AllocationSite> current_site = site_context->EnterNewScope();
@@ -11167,10 +11340,8 @@
   int elements_length = elements->length();
   for (int i = 0; i < elements_length; i++) {
     HValue* key_constant = Add<HConstant>(i);
-    HInstruction* value_instruction =
-        Add<HLoadKeyed>(boilerplate_elements, key_constant,
-                        static_cast<HValue*>(NULL), kind,
-                        ALLOW_RETURN_HOLE);
+    HInstruction* value_instruction = Add<HLoadKeyed>(
+        boilerplate_elements, key_constant, nullptr, kind, ALLOW_RETURN_HOLE);
     HInstruction* store = Add<HStoreKeyed>(object_elements, key_constant,
                                            value_instruction, kind);
     store->SetFlag(HValue::kAllowUndefinedAsNaN);
@@ -11197,11 +11368,13 @@
       site_context->ExitScope(current_site, value_object);
       Add<HStoreKeyed>(object_elements, key_constant, result, kind);
     } else {
+      ElementsKind copy_kind =
+          kind == FAST_HOLEY_SMI_ELEMENTS ? FAST_HOLEY_ELEMENTS : kind;
       HInstruction* value_instruction =
-          Add<HLoadKeyed>(boilerplate_elements, key_constant,
-                          static_cast<HValue*>(NULL), kind,
-                          ALLOW_RETURN_HOLE);
-      Add<HStoreKeyed>(object_elements, key_constant, value_instruction, kind);
+          Add<HLoadKeyed>(boilerplate_elements, key_constant, nullptr,
+                          copy_kind, ALLOW_RETURN_HOLE);
+      Add<HStoreKeyed>(object_elements, key_constant, value_instruction,
+                       copy_kind);
     }
   }
 }
@@ -11440,6 +11613,58 @@
 }
 
 
+void HOptimizedGraphBuilder::GenerateIsJSProxy(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* value = Pop();
+  HIfContinuation continuation;
+  IfBuilder if_proxy(this);
+
+  HValue* smicheck = if_proxy.IfNot<HIsSmiAndBranch>(value);
+  if_proxy.And();
+  HValue* map = Add<HLoadNamedField>(value, smicheck, HObjectAccess::ForMap());
+  HValue* instance_type =
+      Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType());
+  if_proxy.If<HCompareNumericAndBranch>(
+      instance_type, Add<HConstant>(FIRST_JS_PROXY_TYPE), Token::GTE);
+  if_proxy.And();
+  if_proxy.If<HCompareNumericAndBranch>(
+      instance_type, Add<HConstant>(LAST_JS_PROXY_TYPE), Token::LTE);
+
+  if_proxy.CaptureContinuation(&continuation);
+  return ast_context()->ReturnContinuation(&continuation, call->id());
+}
+
+
+void HOptimizedGraphBuilder::GenerateHasFastPackedElements(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* object = Pop();
+  HIfContinuation continuation(graph()->CreateBasicBlock(),
+                               graph()->CreateBasicBlock());
+  IfBuilder if_not_smi(this);
+  if_not_smi.IfNot<HIsSmiAndBranch>(object);
+  if_not_smi.Then();
+  {
+    NoObservableSideEffectsScope no_effects(this);
+
+    IfBuilder if_fast_packed(this);
+    HValue* elements_kind = BuildGetElementsKind(object);
+    if_fast_packed.If<HCompareNumericAndBranch>(
+        elements_kind, Add<HConstant>(FAST_SMI_ELEMENTS), Token::EQ);
+    if_fast_packed.Or();
+    if_fast_packed.If<HCompareNumericAndBranch>(
+        elements_kind, Add<HConstant>(FAST_ELEMENTS), Token::EQ);
+    if_fast_packed.Or();
+    if_fast_packed.If<HCompareNumericAndBranch>(
+        elements_kind, Add<HConstant>(FAST_DOUBLE_ELEMENTS), Token::EQ);
+    if_fast_packed.JoinContinuation(&continuation);
+  }
+  if_not_smi.JoinContinuation(&continuation);
+  return ast_context()->ReturnContinuation(&continuation, call->id());
+}
+
+
 void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
   return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi);
 }
@@ -11860,6 +12085,650 @@
 }
 
 
+HValue* HOptimizedGraphBuilder::BuildOrderedHashTableHashToBucket(
+    HValue* hash, HValue* num_buckets) {
+  HValue* mask = AddUncasted<HSub>(num_buckets, graph()->GetConstant1());
+  mask->ChangeRepresentation(Representation::Integer32());
+  mask->ClearFlag(HValue::kCanOverflow);
+  return AddUncasted<HBitwise>(Token::BIT_AND, hash, mask);
+}
+
+
+template <typename CollectionType>
+HValue* HOptimizedGraphBuilder::BuildOrderedHashTableHashToEntry(
+    HValue* table, HValue* hash, HValue* num_buckets) {
+  HValue* bucket = BuildOrderedHashTableHashToBucket(hash, num_buckets);
+  HValue* entry_index = AddUncasted<HAdd>(
+      bucket, Add<HConstant>(CollectionType::kHashTableStartIndex));
+  entry_index->ClearFlag(HValue::kCanOverflow);
+  HValue* entry = Add<HLoadKeyed>(table, entry_index, nullptr, FAST_ELEMENTS);
+  entry->set_type(HType::Smi());
+  return entry;
+}
+
+
+template <typename CollectionType>
+HValue* HOptimizedGraphBuilder::BuildOrderedHashTableEntryToIndex(
+    HValue* entry, HValue* num_buckets) {
+  HValue* index =
+      AddUncasted<HMul>(entry, Add<HConstant>(CollectionType::kEntrySize));
+  index->ClearFlag(HValue::kCanOverflow);
+  index = AddUncasted<HAdd>(index, num_buckets);
+  index->ClearFlag(HValue::kCanOverflow);
+  index = AddUncasted<HAdd>(
+      index, Add<HConstant>(CollectionType::kHashTableStartIndex));
+  index->ClearFlag(HValue::kCanOverflow);
+  return index;
+}
+
+
+template <typename CollectionType>
+HValue* HOptimizedGraphBuilder::BuildOrderedHashTableFindEntry(HValue* table,
+                                                               HValue* key,
+                                                               HValue* hash) {
+  HValue* num_buckets = Add<HLoadNamedField>(
+      table, nullptr,
+      HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>());
+
+  HValue* entry = BuildOrderedHashTableHashToEntry<CollectionType>(table, hash,
+                                                                   num_buckets);
+
+  Push(entry);
+
+  LoopBuilder loop(this);
+  loop.BeginBody(1);
+
+  entry = Pop();
+
+  {
+    IfBuilder if_not_found(this);
+    if_not_found.If<HCompareNumericAndBranch>(
+        entry, Add<HConstant>(CollectionType::kNotFound), Token::EQ);
+    if_not_found.Then();
+    Push(entry);
+    loop.Break();
+  }
+
+  HValue* key_index =
+      BuildOrderedHashTableEntryToIndex<CollectionType>(entry, num_buckets);
+  HValue* candidate_key =
+      Add<HLoadKeyed>(table, key_index, nullptr, FAST_ELEMENTS);
+
+  {
+    IfBuilder if_keys_equal(this);
+    if_keys_equal.If<HIsStringAndBranch>(candidate_key);
+    if_keys_equal.AndIf<HStringCompareAndBranch>(candidate_key, key,
+                                                 Token::EQ_STRICT);
+    if_keys_equal.Then();
+    Push(key_index);
+    loop.Break();
+  }
+
+  // BuildChainAt
+  HValue* chain_index = AddUncasted<HAdd>(
+      key_index, Add<HConstant>(CollectionType::kChainOffset));
+  chain_index->ClearFlag(HValue::kCanOverflow);
+  entry = Add<HLoadKeyed>(table, chain_index, nullptr, FAST_ELEMENTS);
+  entry->set_type(HType::Smi());
+  Push(entry);
+
+  loop.EndBody();
+
+  return Pop();
+}
+
+
+void HOptimizedGraphBuilder::GenerateMapGet(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 2);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
+  HValue* key = Pop();
+  HValue* receiver = Pop();
+
+  NoObservableSideEffectsScope no_effects(this);
+
+  HIfContinuation continuation;
+  HValue* hash =
+      BuildStringHashLoadIfIsStringAndHashComputed(key, &continuation);
+  {
+    IfBuilder string_checker(this, &continuation);
+    string_checker.Then();
+    {
+      HValue* table = Add<HLoadNamedField>(
+          receiver, nullptr, HObjectAccess::ForJSCollectionTable());
+      HValue* key_index =
+          BuildOrderedHashTableFindEntry<OrderedHashMap>(table, key, hash);
+      IfBuilder if_found(this);
+      if_found.If<HCompareNumericAndBranch>(
+          key_index, Add<HConstant>(OrderedHashMap::kNotFound), Token::NE);
+      if_found.Then();
+      {
+        HValue* value_index = AddUncasted<HAdd>(
+            key_index, Add<HConstant>(OrderedHashMap::kValueOffset));
+        value_index->ClearFlag(HValue::kCanOverflow);
+        Push(Add<HLoadKeyed>(table, value_index, nullptr, FAST_ELEMENTS));
+      }
+      if_found.Else();
+      Push(graph()->GetConstantUndefined());
+      if_found.End();
+    }
+    string_checker.Else();
+    {
+      Add<HPushArguments>(receiver, key);
+      Push(Add<HCallRuntime>(call->name(),
+                             Runtime::FunctionForId(Runtime::kMapGet), 2));
+    }
+  }
+
+  return ast_context()->ReturnValue(Pop());
+}
+
+
+HValue* HOptimizedGraphBuilder::BuildStringHashLoadIfIsStringAndHashComputed(
+    HValue* object, HIfContinuation* continuation) {
+  IfBuilder string_checker(this);
+  string_checker.If<HIsStringAndBranch>(object);
+  string_checker.And();
+  HValue* hash = Add<HLoadNamedField>(object, nullptr,
+                                      HObjectAccess::ForStringHashField());
+  HValue* hash_not_computed_mask = Add<HConstant>(String::kHashNotComputedMask);
+  HValue* hash_computed_test =
+      AddUncasted<HBitwise>(Token::BIT_AND, hash, hash_not_computed_mask);
+  string_checker.If<HCompareNumericAndBranch>(
+      hash_computed_test, graph()->GetConstant0(), Token::EQ);
+  string_checker.Then();
+  HValue* shifted_hash =
+      AddUncasted<HShr>(hash, Add<HConstant>(String::kHashShift));
+  string_checker.CaptureContinuation(continuation);
+  return shifted_hash;
+}
+
+
+template <typename CollectionType>
+void HOptimizedGraphBuilder::BuildJSCollectionHas(
+    CallRuntime* call, const Runtime::Function* c_function) {
+  DCHECK(call->arguments()->length() == 2);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
+  HValue* key = Pop();
+  HValue* receiver = Pop();
+
+  NoObservableSideEffectsScope no_effects(this);
+
+  HIfContinuation continuation;
+  HValue* hash =
+      BuildStringHashLoadIfIsStringAndHashComputed(key, &continuation);
+  {
+    IfBuilder string_checker(this, &continuation);
+    string_checker.Then();
+    {
+      HValue* table = Add<HLoadNamedField>(
+          receiver, nullptr, HObjectAccess::ForJSCollectionTable());
+      HValue* key_index =
+          BuildOrderedHashTableFindEntry<CollectionType>(table, key, hash);
+      {
+        IfBuilder if_found(this);
+        if_found.If<HCompareNumericAndBranch>(
+            key_index, Add<HConstant>(CollectionType::kNotFound), Token::NE);
+        if_found.Then();
+        Push(graph()->GetConstantTrue());
+        if_found.Else();
+        Push(graph()->GetConstantFalse());
+      }
+    }
+    string_checker.Else();
+    {
+      Add<HPushArguments>(receiver, key);
+      Push(Add<HCallRuntime>(call->name(), c_function, 2));
+    }
+  }
+
+  return ast_context()->ReturnValue(Pop());
+}
+
+
+void HOptimizedGraphBuilder::GenerateMapHas(CallRuntime* call) {
+  BuildJSCollectionHas<OrderedHashMap>(
+      call, Runtime::FunctionForId(Runtime::kMapHas));
+}
+
+
+void HOptimizedGraphBuilder::GenerateSetHas(CallRuntime* call) {
+  BuildJSCollectionHas<OrderedHashSet>(
+      call, Runtime::FunctionForId(Runtime::kSetHas));
+}
+
+
+template <typename CollectionType>
+HValue* HOptimizedGraphBuilder::BuildOrderedHashTableAddEntry(
+    HValue* table, HValue* key, HValue* hash,
+    HIfContinuation* join_continuation) {
+  HValue* num_buckets = Add<HLoadNamedField>(
+      table, nullptr,
+      HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>());
+  HValue* capacity = AddUncasted<HMul>(
+      num_buckets, Add<HConstant>(CollectionType::kLoadFactor));
+  capacity->ClearFlag(HValue::kCanOverflow);
+  HValue* num_elements = Add<HLoadNamedField>(
+      table, nullptr,
+      HObjectAccess::ForOrderedHashTableNumberOfElements<CollectionType>());
+  HValue* num_deleted = Add<HLoadNamedField>(
+      table, nullptr, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
+                          CollectionType>());
+  HValue* used = AddUncasted<HAdd>(num_elements, num_deleted);
+  used->ClearFlag(HValue::kCanOverflow);
+  IfBuilder if_space_available(this);
+  if_space_available.If<HCompareNumericAndBranch>(capacity, used, Token::GT);
+  if_space_available.Then();
+  HValue* bucket = BuildOrderedHashTableHashToBucket(hash, num_buckets);
+  HValue* entry = used;
+  HValue* key_index =
+      BuildOrderedHashTableEntryToIndex<CollectionType>(entry, num_buckets);
+
+  HValue* bucket_index = AddUncasted<HAdd>(
+      bucket, Add<HConstant>(CollectionType::kHashTableStartIndex));
+  bucket_index->ClearFlag(HValue::kCanOverflow);
+  HValue* chain_entry =
+      Add<HLoadKeyed>(table, bucket_index, nullptr, FAST_ELEMENTS);
+  chain_entry->set_type(HType::Smi());
+
+  HValue* chain_index = AddUncasted<HAdd>(
+      key_index, Add<HConstant>(CollectionType::kChainOffset));
+  chain_index->ClearFlag(HValue::kCanOverflow);
+
+  Add<HStoreKeyed>(table, bucket_index, entry, FAST_ELEMENTS);
+  Add<HStoreKeyed>(table, chain_index, chain_entry, FAST_ELEMENTS);
+  Add<HStoreKeyed>(table, key_index, key, FAST_ELEMENTS);
+
+  HValue* new_num_elements =
+      AddUncasted<HAdd>(num_elements, graph()->GetConstant1());
+  new_num_elements->ClearFlag(HValue::kCanOverflow);
+  Add<HStoreNamedField>(
+      table,
+      HObjectAccess::ForOrderedHashTableNumberOfElements<CollectionType>(),
+      new_num_elements);
+  if_space_available.JoinContinuation(join_continuation);
+  return key_index;
+}
+
+
+void HOptimizedGraphBuilder::GenerateMapSet(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 3);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
+  HValue* value = Pop();
+  HValue* key = Pop();
+  HValue* receiver = Pop();
+
+  NoObservableSideEffectsScope no_effects(this);
+
+  HIfContinuation return_or_call_runtime_continuation(
+      graph()->CreateBasicBlock(), graph()->CreateBasicBlock());
+  HIfContinuation got_string_hash;
+  HValue* hash =
+      BuildStringHashLoadIfIsStringAndHashComputed(key, &got_string_hash);
+  IfBuilder string_checker(this, &got_string_hash);
+  string_checker.Then();
+  {
+    HValue* table = Add<HLoadNamedField>(receiver, nullptr,
+                                         HObjectAccess::ForJSCollectionTable());
+    HValue* key_index =
+        BuildOrderedHashTableFindEntry<OrderedHashMap>(table, key, hash);
+    {
+      IfBuilder if_found(this);
+      if_found.If<HCompareNumericAndBranch>(
+          key_index, Add<HConstant>(OrderedHashMap::kNotFound), Token::NE);
+      if_found.Then();
+      {
+        HValue* value_index = AddUncasted<HAdd>(
+            key_index, Add<HConstant>(OrderedHashMap::kValueOffset));
+        value_index->ClearFlag(HValue::kCanOverflow);
+        Add<HStoreKeyed>(table, value_index, value, FAST_ELEMENTS);
+      }
+      if_found.Else();
+      {
+        HIfContinuation did_add(graph()->CreateBasicBlock(),
+                                graph()->CreateBasicBlock());
+        HValue* key_index = BuildOrderedHashTableAddEntry<OrderedHashMap>(
+            table, key, hash, &did_add);
+        IfBuilder if_did_add(this, &did_add);
+        if_did_add.Then();
+        {
+          HValue* value_index = AddUncasted<HAdd>(
+              key_index, Add<HConstant>(OrderedHashMap::kValueOffset));
+          value_index->ClearFlag(HValue::kCanOverflow);
+          Add<HStoreKeyed>(table, value_index, value, FAST_ELEMENTS);
+        }
+        if_did_add.JoinContinuation(&return_or_call_runtime_continuation);
+      }
+    }
+  }
+  string_checker.JoinContinuation(&return_or_call_runtime_continuation);
+
+  {
+    IfBuilder return_or_call_runtime(this,
+                                     &return_or_call_runtime_continuation);
+    return_or_call_runtime.Then();
+    Push(receiver);
+    return_or_call_runtime.Else();
+    Add<HPushArguments>(receiver, key, value);
+    Push(Add<HCallRuntime>(call->name(),
+                           Runtime::FunctionForId(Runtime::kMapSet), 3));
+  }
+
+  return ast_context()->ReturnValue(Pop());
+}
+
+
+void HOptimizedGraphBuilder::GenerateSetAdd(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 2);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
+  HValue* key = Pop();
+  HValue* receiver = Pop();
+
+  NoObservableSideEffectsScope no_effects(this);
+
+  HIfContinuation return_or_call_runtime_continuation(
+      graph()->CreateBasicBlock(), graph()->CreateBasicBlock());
+  HIfContinuation got_string_hash;
+  HValue* hash =
+      BuildStringHashLoadIfIsStringAndHashComputed(key, &got_string_hash);
+  IfBuilder string_checker(this, &got_string_hash);
+  string_checker.Then();
+  {
+    HValue* table = Add<HLoadNamedField>(receiver, nullptr,
+                                         HObjectAccess::ForJSCollectionTable());
+    HValue* key_index =
+        BuildOrderedHashTableFindEntry<OrderedHashSet>(table, key, hash);
+    {
+      IfBuilder if_not_found(this);
+      if_not_found.If<HCompareNumericAndBranch>(
+          key_index, Add<HConstant>(OrderedHashSet::kNotFound), Token::EQ);
+      if_not_found.Then();
+      BuildOrderedHashTableAddEntry<OrderedHashSet>(
+          table, key, hash, &return_or_call_runtime_continuation);
+    }
+  }
+  string_checker.JoinContinuation(&return_or_call_runtime_continuation);
+
+  {
+    IfBuilder return_or_call_runtime(this,
+                                     &return_or_call_runtime_continuation);
+    return_or_call_runtime.Then();
+    Push(receiver);
+    return_or_call_runtime.Else();
+    Add<HPushArguments>(receiver, key);
+    Push(Add<HCallRuntime>(call->name(),
+                           Runtime::FunctionForId(Runtime::kSetAdd), 2));
+  }
+
+  return ast_context()->ReturnValue(Pop());
+}
+
+
+template <typename CollectionType>
+void HOptimizedGraphBuilder::BuildJSCollectionDelete(
+    CallRuntime* call, const Runtime::Function* c_function) {
+  DCHECK(call->arguments()->length() == 2);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
+  HValue* key = Pop();
+  HValue* receiver = Pop();
+
+  NoObservableSideEffectsScope no_effects(this);
+
+  HIfContinuation return_or_call_runtime_continuation(
+      graph()->CreateBasicBlock(), graph()->CreateBasicBlock());
+  HIfContinuation got_string_hash;
+  HValue* hash =
+      BuildStringHashLoadIfIsStringAndHashComputed(key, &got_string_hash);
+  IfBuilder string_checker(this, &got_string_hash);
+  string_checker.Then();
+  {
+    HValue* table = Add<HLoadNamedField>(receiver, nullptr,
+                                         HObjectAccess::ForJSCollectionTable());
+    HValue* key_index =
+        BuildOrderedHashTableFindEntry<CollectionType>(table, key, hash);
+    {
+      IfBuilder if_found(this);
+      if_found.If<HCompareNumericAndBranch>(
+          key_index, Add<HConstant>(CollectionType::kNotFound), Token::NE);
+      if_found.Then();
+      {
+        // If we're removing an element, we might need to shrink.
+        // If we do need to shrink, we'll be bailing out to the runtime.
+        HValue* num_elements = Add<HLoadNamedField>(
+            table, nullptr, HObjectAccess::ForOrderedHashTableNumberOfElements<
+                                CollectionType>());
+        num_elements = AddUncasted<HSub>(num_elements, graph()->GetConstant1());
+        num_elements->ClearFlag(HValue::kCanOverflow);
+
+        HValue* num_buckets = Add<HLoadNamedField>(
+            table, nullptr, HObjectAccess::ForOrderedHashTableNumberOfBuckets<
+                                CollectionType>());
+        // threshold is capacity >> 2; we simplify this to num_buckets >> 1
+        // since kLoadFactor is 2.
+        STATIC_ASSERT(CollectionType::kLoadFactor == 2);
+        HValue* threshold =
+            AddUncasted<HShr>(num_buckets, graph()->GetConstant1());
+
+        IfBuilder if_need_not_shrink(this);
+        if_need_not_shrink.If<HCompareNumericAndBranch>(num_elements, threshold,
+                                                        Token::GTE);
+        if_need_not_shrink.Then();
+        {
+          Add<HStoreKeyed>(table, key_index, graph()->GetConstantHole(),
+                           FAST_ELEMENTS);
+
+          // For maps, also need to clear the value.
+          if (CollectionType::kChainOffset > 1) {
+            HValue* value_index =
+                AddUncasted<HAdd>(key_index, graph()->GetConstant1());
+            value_index->ClearFlag(HValue::kCanOverflow);
+            Add<HStoreKeyed>(table, value_index, graph()->GetConstantHole(),
+                             FAST_ELEMENTS);
+          }
+          STATIC_ASSERT(CollectionType::kChainOffset <= 2);
+
+          HValue* num_deleted = Add<HLoadNamedField>(
+              table, nullptr,
+              HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
+                  CollectionType>());
+          num_deleted = AddUncasted<HAdd>(num_deleted, graph()->GetConstant1());
+          num_deleted->ClearFlag(HValue::kCanOverflow);
+          Add<HStoreNamedField>(
+              table, HObjectAccess::ForOrderedHashTableNumberOfElements<
+                         CollectionType>(),
+              num_elements);
+          Add<HStoreNamedField>(
+              table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
+                         CollectionType>(),
+              num_deleted);
+          Push(graph()->GetConstantTrue());
+        }
+        if_need_not_shrink.JoinContinuation(
+            &return_or_call_runtime_continuation);
+      }
+      if_found.Else();
+      {
+        // Not found, so we're done.
+        Push(graph()->GetConstantFalse());
+      }
+    }
+  }
+  string_checker.JoinContinuation(&return_or_call_runtime_continuation);
+
+  {
+    IfBuilder return_or_call_runtime(this,
+                                     &return_or_call_runtime_continuation);
+    return_or_call_runtime.Then();
+    return_or_call_runtime.Else();
+    Add<HPushArguments>(receiver, key);
+    Push(Add<HCallRuntime>(call->name(), c_function, 2));
+  }
+
+  return ast_context()->ReturnValue(Pop());
+}
+
+
+void HOptimizedGraphBuilder::GenerateMapDelete(CallRuntime* call) {
+  BuildJSCollectionDelete<OrderedHashMap>(
+      call, Runtime::FunctionForId(Runtime::kMapDelete));
+}
+
+
+void HOptimizedGraphBuilder::GenerateSetDelete(CallRuntime* call) {
+  BuildJSCollectionDelete<OrderedHashSet>(
+      call, Runtime::FunctionForId(Runtime::kSetDelete));
+}
+
+
+void HOptimizedGraphBuilder::GenerateSetGetSize(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* receiver = Pop();
+  HValue* table = Add<HLoadNamedField>(receiver, nullptr,
+                                       HObjectAccess::ForJSCollectionTable());
+  HInstruction* result = New<HLoadNamedField>(
+      table, nullptr,
+      HObjectAccess::ForOrderedHashTableNumberOfElements<OrderedHashSet>());
+  return ast_context()->ReturnInstruction(result, call->id());
+}
+
+
+void HOptimizedGraphBuilder::GenerateMapGetSize(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* receiver = Pop();
+  HValue* table = Add<HLoadNamedField>(receiver, nullptr,
+                                       HObjectAccess::ForJSCollectionTable());
+  HInstruction* result = New<HLoadNamedField>(
+      table, nullptr,
+      HObjectAccess::ForOrderedHashTableNumberOfElements<OrderedHashMap>());
+  return ast_context()->ReturnInstruction(result, call->id());
+}
+
+
+template <typename CollectionType>
+HValue* HOptimizedGraphBuilder::BuildAllocateOrderedHashTable() {
+  static const int kCapacity = CollectionType::kMinCapacity;
+  static const int kBucketCount = kCapacity / CollectionType::kLoadFactor;
+  static const int kFixedArrayLength = CollectionType::kHashTableStartIndex +
+                                       kBucketCount +
+                                       (kCapacity * CollectionType::kEntrySize);
+  static const int kSizeInBytes =
+      FixedArray::kHeaderSize + (kFixedArrayLength * kPointerSize);
+
+  // Allocate the table and add the proper map.
+  HValue* table =
+      Add<HAllocate>(Add<HConstant>(kSizeInBytes), HType::HeapObject(),
+                     NOT_TENURED, FIXED_ARRAY_TYPE);
+  AddStoreMapConstant(table, isolate()->factory()->ordered_hash_table_map());
+
+  // Initialize the FixedArray...
+  HValue* length = Add<HConstant>(kFixedArrayLength);
+  Add<HStoreNamedField>(table, HObjectAccess::ForFixedArrayLength(), length);
+
+  // ...and the OrderedHashTable fields.
+  Add<HStoreNamedField>(
+      table,
+      HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>(),
+      Add<HConstant>(kBucketCount));
+  Add<HStoreNamedField>(
+      table,
+      HObjectAccess::ForOrderedHashTableNumberOfElements<CollectionType>(),
+      graph()->GetConstant0());
+  Add<HStoreNamedField>(
+      table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
+                 CollectionType>(),
+      graph()->GetConstant0());
+
+  // Fill the buckets with kNotFound.
+  HValue* not_found = Add<HConstant>(CollectionType::kNotFound);
+  for (int i = 0; i < kBucketCount; ++i) {
+    Add<HStoreNamedField>(
+        table, HObjectAccess::ForOrderedHashTableBucket<CollectionType>(i),
+        not_found);
+  }
+
+  // Fill the data table with undefined.
+  HValue* undefined = graph()->GetConstantUndefined();
+  for (int i = 0; i < (kCapacity * CollectionType::kEntrySize); ++i) {
+    Add<HStoreNamedField>(table,
+                          HObjectAccess::ForOrderedHashTableDataTableIndex<
+                              CollectionType, kBucketCount>(i),
+                          undefined);
+  }
+
+  return table;
+}
+
+
+void HOptimizedGraphBuilder::GenerateSetInitialize(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* receiver = Pop();
+
+  NoObservableSideEffectsScope no_effects(this);
+  HValue* table = BuildAllocateOrderedHashTable<OrderedHashSet>();
+  Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(), table);
+  return ast_context()->ReturnValue(receiver);
+}
+
+
+void HOptimizedGraphBuilder::GenerateMapInitialize(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* receiver = Pop();
+
+  NoObservableSideEffectsScope no_effects(this);
+  HValue* table = BuildAllocateOrderedHashTable<OrderedHashMap>();
+  Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(), table);
+  return ast_context()->ReturnValue(receiver);
+}
+
+
+template <typename CollectionType>
+void HOptimizedGraphBuilder::BuildOrderedHashTableClear(HValue* receiver) {
+  HValue* old_table = Add<HLoadNamedField>(
+      receiver, nullptr, HObjectAccess::ForJSCollectionTable());
+  HValue* new_table = BuildAllocateOrderedHashTable<CollectionType>();
+  Add<HStoreNamedField>(
+      old_table, HObjectAccess::ForOrderedHashTableNextTable<CollectionType>(),
+      new_table);
+  Add<HStoreNamedField>(
+      old_table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
+                     CollectionType>(),
+      Add<HConstant>(CollectionType::kClearedTableSentinel));
+  Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(),
+                        new_table);
+}
+
+
+void HOptimizedGraphBuilder::GenerateSetClear(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* receiver = Pop();
+
+  NoObservableSideEffectsScope no_effects(this);
+  BuildOrderedHashTableClear<OrderedHashSet>(receiver);
+  return ast_context()->ReturnValue(graph()->GetConstantUndefined());
+}
+
+
+void HOptimizedGraphBuilder::GenerateMapClear(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* receiver = Pop();
+
+  NoObservableSideEffectsScope no_effects(this);
+  BuildOrderedHashTableClear<OrderedHashMap>(receiver);
+  return ast_context()->ReturnValue(graph()->GetConstantUndefined());
+}
+
+
 void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
   DCHECK(call->arguments()->length() == 1);
   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
@@ -11896,12 +12765,59 @@
   DCHECK(call->arguments()->length() == 0);
   HValue* ref =
       Add<HConstant>(ExternalReference::debug_is_active_address(isolate()));
-  HValue* value = Add<HLoadNamedField>(
-      ref, static_cast<HValue*>(NULL), HObjectAccess::ForExternalUInteger8());
+  HValue* value =
+      Add<HLoadNamedField>(ref, nullptr, HObjectAccess::ForExternalUInteger8());
   return ast_context()->ReturnValue(value);
 }
 
 
+void HOptimizedGraphBuilder::GenerateGetPrototype(CallRuntime* call) {
+  DCHECK(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* object = Pop();
+
+  NoObservableSideEffectsScope no_effects(this);
+
+  HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap());
+  HValue* bit_field =
+      Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField());
+  HValue* is_access_check_needed_mask =
+      Add<HConstant>(1 << Map::kIsAccessCheckNeeded);
+  HValue* is_access_check_needed_test = AddUncasted<HBitwise>(
+      Token::BIT_AND, bit_field, is_access_check_needed_mask);
+
+  HValue* proto =
+      Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForPrototype());
+  HValue* proto_map =
+      Add<HLoadNamedField>(proto, nullptr, HObjectAccess::ForMap());
+  HValue* proto_bit_field =
+      Add<HLoadNamedField>(proto_map, nullptr, HObjectAccess::ForMapBitField());
+  HValue* is_hidden_prototype_mask =
+      Add<HConstant>(1 << Map::kIsHiddenPrototype);
+  HValue* is_hidden_prototype_test = AddUncasted<HBitwise>(
+      Token::BIT_AND, proto_bit_field, is_hidden_prototype_mask);
+
+  {
+    IfBuilder needs_runtime(this);
+    needs_runtime.If<HCompareNumericAndBranch>(
+        is_access_check_needed_test, graph()->GetConstant0(), Token::NE);
+    needs_runtime.OrIf<HCompareNumericAndBranch>(
+        is_hidden_prototype_test, graph()->GetConstant0(), Token::NE);
+
+    needs_runtime.Then();
+    {
+      Add<HPushArguments>(object);
+      Push(Add<HCallRuntime>(
+          call->name(), Runtime::FunctionForId(Runtime::kGetPrototype), 1));
+    }
+
+    needs_runtime.Else();
+    Push(proto);
+  }
+  return ast_context()->ReturnValue(Pop());
+}
+
+
 #undef CHECK_BAILOUT
 #undef CHECK_ALIVE
 
@@ -12071,6 +12987,18 @@
 }
 
 
+HValue* HEnvironment::RemoveExpressionStackAt(int index_from_top) {
+  int count = index_from_top + 1;
+  int index = values_.length() - count;
+  DCHECK(HasExpressionAt(index));
+  // Simulate popping 'count' elements and then
+  // pushing 'count - 1' elements back.
+  pop_count_ += Max(count - push_count_, 0);
+  push_count_ = Max(push_count_ - count, 0) + (count - 1);
+  return values_.Remove(index);
+}
+
+
 void HEnvironment::Drop(int count) {
   for (int i = 0; i < count; ++i) {
     Pop();
@@ -12170,7 +13098,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const HEnvironment& env) {
+std::ostream& operator<<(std::ostream& os, const HEnvironment& env) {
   for (int i = 0; i < env.length(); i++) {
     if (i == 0) os << "parameters\n";
     if (i == env.parameter_count()) os << "specials\n";
@@ -12302,9 +13230,9 @@
       for (int j = 0; j < total; ++j) {
         HPhi* phi = current->phis()->at(j);
         PrintIndent();
-        OStringStream os;
+        std::ostringstream os;
         os << phi->merged_index() << " " << NameOf(phi) << " " << *phi << "\n";
-        trace_.Add(os.c_str());
+        trace_.Add(os.str().c_str());
       }
     }
 
@@ -12314,7 +13242,7 @@
         HInstruction* instruction = it.Current();
         int uses = instruction->UseCount();
         PrintIndent();
-        OStringStream os;
+        std::ostringstream os;
         os << "0 " << uses << " " << NameOf(instruction) << " " << *instruction;
         if (FLAG_hydrogen_track_positions &&
             instruction->has_position() &&
@@ -12325,7 +13253,7 @@
           os << pos.position();
         }
         os << " <|@\n";
-        trace_.Add(os.c_str());
+        trace_.Add(os.str().c_str());
       }
     }
 
@@ -12343,9 +13271,9 @@
             trace_.Add("%d ",
                        LifetimePosition::FromInstructionIndex(i).Value());
             linstr->PrintTo(&trace_);
-            OStringStream os;
+            std::ostringstream os;
             os << " [hir:" << NameOf(linstr->hydrogen_value()) << "] <|@\n";
-            trace_.Add(os.c_str());
+            trace_.Add(os.str().c_str());
           }
         }
       }
@@ -12445,15 +13373,14 @@
 }
 
 
-void HStatistics::Print(const char* stats_name) {
+void HStatistics::Print() {
   PrintF(
       "\n"
       "----------------------------------------"
       "----------------------------------------\n"
-      "--- %s timing results:\n"
+      "--- Hydrogen timing results:\n"
       "----------------------------------------"
-      "----------------------------------------\n",
-      stats_name);
+      "----------------------------------------\n");
   base::TimeDelta sum;
   for (int i = 0; i < times_.length(); ++i) {
     sum += times_[i];
@@ -12492,9 +13419,10 @@
   double normalized_time =  source_size_in_kb > 0
       ? total.InMillisecondsF() / source_size_in_kb
       : 0;
-  double normalized_size_in_kb = source_size_in_kb > 0
-      ? total_size_ / 1024 / source_size_in_kb
-      : 0;
+  double normalized_size_in_kb =
+      source_size_in_kb > 0
+          ? static_cast<double>(total_size_) / 1024 / source_size_in_kb
+          : 0;
   PrintF("%33s %8.3f ms           %7.3f kB allocated\n",
          "Average per kB source", normalized_time, normalized_size_in_kb);
 }
diff --git a/src/hydrogen.h b/src/hydrogen.h
index d507643..c1ed797 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -215,7 +215,7 @@
 };
 
 
-OStream& operator<<(OStream& os, const HBasicBlock& b);
+std::ostream& operator<<(std::ostream& os, const HBasicBlock& b);
 
 
 class HPredecessorIterator FINAL BASE_EMBEDDED {
@@ -315,7 +315,6 @@
   HEnvironment* start_environment() const { return start_environment_; }
 
   void FinalizeUniqueness();
-  bool ProcessArgumentsObject();
   void OrderBlocks();
   void AssignDominators();
   void RestoreActualValues();
@@ -479,8 +478,6 @@
     phase.Run();
   }
 
-  void EliminateRedundantBoundsChecksUsingInductionVariables();
-
   Isolate* isolate_;
   int next_block_id_;
   HBasicBlock* entry_block_;
@@ -527,8 +524,8 @@
     int start_position_;
   };
 
-  int next_inline_id_;
   ZoneList<InlinedFunctionInfo> inlined_functions_;
+  ZoneList<int> inlining_id_to_function_id_;
 
   DISALLOW_COPY_AND_ASSIGN(HGraph);
 };
@@ -645,6 +642,7 @@
   }
 
   void SetExpressionStackAt(int index_from_top, HValue* value);
+  HValue* RemoveExpressionStackAt(int index_from_top);
 
   HEnvironment* Copy() const;
   HEnvironment* CopyWithoutHistory() const;
@@ -743,14 +741,15 @@
 };
 
 
-OStream& operator<<(OStream& os, const HEnvironment& env);
+std::ostream& operator<<(std::ostream& os, const HEnvironment& env);
 
 
 class HOptimizedGraphBuilder;
 
 enum ArgumentsAllowedFlag {
   ARGUMENTS_NOT_ALLOWED,
-  ARGUMENTS_ALLOWED
+  ARGUMENTS_ALLOWED,
+  ARGUMENTS_FAKED
 };
 
 
@@ -820,7 +819,7 @@
   }
   virtual ~EffectContext();
 
-  virtual void ReturnValue(HValue* value) OVERRIDE;
+  void ReturnValue(HValue* value) OVERRIDE;
   virtual void ReturnInstruction(HInstruction* instr,
                                  BailoutId ast_id) OVERRIDE;
   virtual void ReturnControl(HControlInstruction* instr,
@@ -837,7 +836,7 @@
   }
   virtual ~ValueContext();
 
-  virtual void ReturnValue(HValue* value) OVERRIDE;
+  void ReturnValue(HValue* value) OVERRIDE;
   virtual void ReturnInstruction(HInstruction* instr,
                                  BailoutId ast_id) OVERRIDE;
   virtual void ReturnControl(HControlInstruction* instr,
@@ -864,7 +863,7 @@
         if_false_(if_false) {
   }
 
-  virtual void ReturnValue(HValue* value) OVERRIDE;
+  void ReturnValue(HValue* value) OVERRIDE;
   virtual void ReturnInstruction(HInstruction* instr,
                                  BailoutId ast_id) OVERRIDE;
   virtual void ReturnControl(HControlInstruction* instr,
@@ -1805,8 +1804,9 @@
                                      ElementsKind kind,
                                      HValue* capacity);
 
-  HValue* BuildAllocateElementsAndInitializeElementsHeader(ElementsKind kind,
-                                                           HValue* capacity);
+  // Build allocation and header initialization code for respective successor
+  // of FixedArrayBase.
+  HValue* BuildAllocateAndInitializeArray(ElementsKind kind, HValue* capacity);
 
   // |array| must have been allocated with enough room for
   // 1) the JSArray and 2) an AllocationMemento if mode requires it.
@@ -1838,6 +1838,9 @@
                                  HValue* from,
                                  HValue* to);
 
+  void BuildCopyProperties(HValue* from_properties, HValue* to_properties,
+                           HValue* length, HValue* capacity);
+
   void BuildCopyElements(HValue* from_elements,
                          ElementsKind from_elements_kind,
                          HValue* to_elements,
@@ -1861,10 +1864,10 @@
 
   HValue* BuildElementIndexHash(HValue* index);
 
-  void BuildCompareNil(
-      HValue* value,
-      Type* type,
-      HIfContinuation* continuation);
+  enum MapEmbedding { kEmbedMapsDirectly, kEmbedMapsViaWeakCells };
+
+  void BuildCompareNil(HValue* value, Type* type, HIfContinuation* continuation,
+                       MapEmbedding map_embedding = kEmbedMapsDirectly);
 
   void BuildCreateAllocationMemento(HValue* previous_object,
                                     HValue* previous_object_size,
@@ -1876,6 +1879,7 @@
 
   HInstruction* BuildGetNativeContext(HValue* closure);
   HInstruction* BuildGetNativeContext();
+  HInstruction* BuildGetScriptContext(int context_index);
   HInstruction* BuildGetArrayFunction();
 
  protected:
@@ -2104,13 +2108,13 @@
 
   explicit HOptimizedGraphBuilder(CompilationInfo* info);
 
-  virtual bool BuildGraph() OVERRIDE;
+  bool BuildGraph() OVERRIDE;
 
   // Simple accessors.
   BreakAndContinueScope* break_scope() const { return break_scope_; }
   void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
 
-  HValue* context() { return environment()->context(); }
+  HValue* context() OVERRIDE { return environment()->context(); }
 
   HOsrBuilder* osr() const { return osr_; }
 
@@ -2122,7 +2126,7 @@
 
   FunctionState* function_state() const { return function_state_; }
 
-  void VisitDeclarations(ZoneList<Declaration*>* declarations);
+  void VisitDeclarations(ZoneList<Declaration*>* declarations) OVERRIDE;
 
   void* operator new(size_t size, Zone* zone) {
     return zone->New(static_cast<int>(size));
@@ -2200,7 +2204,6 @@
   void VisitLogicalExpression(BinaryOperation* expr);
   void VisitArithmeticExpression(BinaryOperation* expr);
 
-  bool PreProcessOsrEntry(IterationStatement* statement);
   void VisitLoopBody(IterationStatement* stmt,
                      HBasicBlock* loop_entry);
 
@@ -2255,7 +2258,6 @@
 #endif
     }
   }
-
   HValue* LookupAndMakeLive(Variable* var) {
     HEnvironment* env = environment();
     int index = env->IndexFor(var);
@@ -2283,7 +2285,9 @@
                        HBasicBlock* false_block);
 
   // Visit a list of expressions from left to right, each in a value context.
-  void VisitExpressions(ZoneList<Expression*>* exprs);
+  void VisitExpressions(ZoneList<Expression*>* exprs) OVERRIDE;
+  void VisitExpressions(ZoneList<Expression*>* exprs,
+                        ArgumentsAllowedFlag flag);
 
   // Remove the arguments from the bailout environment and emit instructions
   // to push them as outgoing parameters.
@@ -2291,7 +2295,7 @@
   void PushArgumentsFromEnvironment(int count);
 
   void SetUpScope(Scope* scope);
-  virtual void VisitStatements(ZoneList<Statement*>* statements) OVERRIDE;
+  void VisitStatements(ZoneList<Statement*>* statements) OVERRIDE;
 
 #define DECLARE_VISIT(type) virtual void Visit##type(type* node) OVERRIDE;
   AST_NODE_LIST(DECLARE_VISIT)
@@ -2311,8 +2315,13 @@
   void EnsureArgumentsArePushedForAccess();
   bool TryArgumentsAccess(Property* expr);
 
-  // Try to optimize fun.apply(receiver, arguments) pattern.
-  bool TryCallApply(Call* expr);
+  // Shared code for .call and .apply optimizations.
+  void HandleIndirectCall(Call* expr, HValue* function, int arguments_count);
+  // Try to optimize indirect calls such as fun.apply(receiver, arguments)
+  // or fun.call(...).
+  bool TryIndirectCall(Call* expr);
+  void BuildFunctionApply(Call* expr);
+  void BuildFunctionCall(Call* expr);
 
   bool TryHandleArrayCall(Call* expr, HValue* function);
   bool TryHandleArrayCallNew(CallNew* expr, HValue* function);
@@ -2348,12 +2357,11 @@
                        BailoutId id,
                        BailoutId assignment_id,
                        HValue* implicit_return_value);
-  bool TryInlineApply(Handle<JSFunction> function,
-                      Call* expr,
-                      int arguments_count);
-  bool TryInlineBuiltinMethodCall(Call* expr,
-                                  HValue* receiver,
-                                  Handle<Map> receiver_map);
+  bool TryInlineIndirectCall(Handle<JSFunction> function, Call* expr,
+                             int arguments_count);
+  bool TryInlineBuiltinMethodCall(Call* expr, Handle<JSFunction> function,
+                                  Handle<Map> receiver_map,
+                                  int args_count_no_receiver);
   bool TryInlineBuiltinFunctionCall(Call* expr);
   enum ApiCallType {
     kCallApiFunction,
@@ -2409,6 +2417,33 @@
       ElementsKind fixed_elements_kind,
       HValue* byte_length, HValue* length);
 
+  // TODO(adamk): Move all OrderedHashTable functions to their own class.
+  HValue* BuildOrderedHashTableHashToBucket(HValue* hash, HValue* num_buckets);
+  template <typename CollectionType>
+  HValue* BuildOrderedHashTableHashToEntry(HValue* table, HValue* hash,
+                                           HValue* num_buckets);
+  template <typename CollectionType>
+  HValue* BuildOrderedHashTableEntryToIndex(HValue* entry, HValue* num_buckets);
+  template <typename CollectionType>
+  HValue* BuildOrderedHashTableFindEntry(HValue* table, HValue* key,
+                                         HValue* hash);
+  template <typename CollectionType>
+  HValue* BuildOrderedHashTableAddEntry(HValue* table, HValue* key,
+                                        HValue* hash,
+                                        HIfContinuation* join_continuation);
+  template <typename CollectionType>
+  HValue* BuildAllocateOrderedHashTable();
+  template <typename CollectionType>
+  void BuildOrderedHashTableClear(HValue* receiver);
+  template <typename CollectionType>
+  void BuildJSCollectionDelete(CallRuntime* call,
+                               const Runtime::Function* c_function);
+  template <typename CollectionType>
+  void BuildJSCollectionHas(CallRuntime* call,
+                            const Runtime::Function* c_function);
+  HValue* BuildStringHashLoadIfIsStringAndHashComputed(
+      HValue* object, HIfContinuation* continuation);
+
   Handle<JSFunction> array_function() {
     return handle(isolate()->native_context()->array_function());
   }
@@ -2713,6 +2748,8 @@
   HInstruction* BuildCallConstantFunction(Handle<JSFunction> target,
                                           int argument_count);
 
+  bool CanBeFunctionApplyArguments(Call* expr);
+
   // The translation state of the currently-being-translated function.
   FunctionState* function_state_;
 
@@ -2755,7 +2792,7 @@
         source_size_(0) { }
 
   void Initialize(CompilationInfo* info);
-  void Print(const char* stats_name);
+  void Print();
   void SaveTiming(const char* name, base::TimeDelta time, unsigned size);
 
   void IncrementFullCodeGen(base::TimeDelta full_code_gen) {
diff --git a/src/i18n.cc b/src/i18n.cc
index cae3a32..69fa9ca 100644
--- a/src/i18n.cc
+++ b/src/i18n.cc
@@ -631,6 +631,8 @@
     return NULL;
   }
 
+  isolate->CountUsage(v8::Isolate::UseCounterFeature::kBreakIterator);
+
   return break_iterator;
 }
 
@@ -702,6 +704,10 @@
     icu::Locale no_extension_locale(icu_locale.getBaseName());
     date_format = CreateICUDateFormat(isolate, no_extension_locale, options);
 
+    if (!date_format) {
+      FATAL("Failed to create ICU date format, are ICU data files missing?");
+    }
+
     // Set resolved settings (pattern, numbering system, calendar).
     SetResolvedDateSettings(
         isolate, no_extension_locale, date_format, resolved);
@@ -778,6 +784,10 @@
     number_format = CreateICUNumberFormat(
         isolate, no_extension_locale, options);
 
+    if (!number_format) {
+      FATAL("Failed to create ICU number format, are ICU data files missing?");
+    }
+
     // Set resolved settings (pattern, numbering system).
     SetResolvedNumberSettings(
         isolate, no_extension_locale, number_format, resolved);
@@ -837,6 +847,10 @@
     icu::Locale no_extension_locale(icu_locale.getBaseName());
     collator = CreateICUCollator(isolate, no_extension_locale, options);
 
+    if (!collator) {
+      FATAL("Failed to create ICU collator, are ICU data files missing?");
+    }
+
     // Set resolved settings (pattern, numbering system).
     SetResolvedCollatorSettings(
         isolate, no_extension_locale, collator, resolved);
@@ -896,6 +910,10 @@
     break_iterator = CreateICUBreakIterator(
         isolate, no_extension_locale, options);
 
+    if (!break_iterator) {
+      FATAL("Failed to create ICU break iterator, are ICU data files missing?");
+    }
+
     // Set resolved settings (locale).
     SetResolvedBreakIteratorSettings(
         isolate, no_extension_locale, break_iterator, resolved);
diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc
index d16eea1..168a196 100644
--- a/src/ia32/assembler-ia32.cc
+++ b/src/ia32/assembler-ia32.cc
@@ -34,7 +34,11 @@
 // significantly by Google Inc.
 // Copyright 2012 the V8 project authors. All rights reserved.
 
-#include "src/v8.h"
+#include "src/ia32/assembler-ia32.h"
+
+#if V8_OS_MACOSX
+#include <sys/sysctl.h>
+#endif
 
 #if V8_TARGET_ARCH_IA32
 
@@ -42,7 +46,7 @@
 #include "src/base/cpu.h"
 #include "src/disassembler.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
+#include "src/v8.h"
 
 namespace v8 {
 namespace internal {
@@ -50,6 +54,29 @@
 // -----------------------------------------------------------------------------
 // Implementation of CpuFeatures
 
+namespace {
+
+bool EnableAVX() {
+#if V8_OS_MACOSX
+  // Mac OS X 10.9 has a bug where AVX transitions were indeed being caused by
+  // ISRs, so we detect Mac OS X 10.9 here and disable AVX in that case.
+  char buffer[128];
+  size_t buffer_size = arraysize(buffer);
+  int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
+  if (sysctl(ctl_name, 2, buffer, &buffer_size, nullptr, 0) != 0) {
+    V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version");
+  }
+  // The buffer now contains a string of the form XX.YY.ZZ, where
+  // XX is the major kernel version component. 13.x.x (Mavericks) is
+  // affected by this bug, so disable AVX there.
+  if (memcmp(buffer, "13.", 3) == 0) return false;
+#endif  // V8_OS_MACOSX
+  return FLAG_enable_avx;
+}
+
+}  // namespace
+
+
 void CpuFeatures::ProbeImpl(bool cross_compile) {
   base::CPU cpu;
   CHECK(cpu.has_sse2());  // SSE2 support is mandatory.
@@ -60,11 +87,17 @@
 
   if (cpu.has_sse41() && FLAG_enable_sse4_1) supported_ |= 1u << SSE4_1;
   if (cpu.has_sse3() && FLAG_enable_sse3) supported_ |= 1u << SSE3;
+  if (cpu.has_avx() && EnableAVX()) supported_ |= 1u << AVX;
+  if (cpu.has_fma3() && FLAG_enable_fma3) supported_ |= 1u << FMA3;
 }
 
 
 void CpuFeatures::PrintTarget() { }
-void CpuFeatures::PrintFeatures() { }
+void CpuFeatures::PrintFeatures() {
+  printf("SSE3=%d SSE4_1=%d AVX=%d FMA3=%d\n", CpuFeatures::IsSupported(SSE3),
+         CpuFeatures::IsSupported(SSE4_1), CpuFeatures::IsSupported(AVX),
+         CpuFeatures::IsSupported(FMA3));
+}
 
 
 // -----------------------------------------------------------------------------
@@ -457,11 +490,11 @@
 }
 
 
-void Assembler::mov_b(const Operand& dst, int8_t imm8) {
+void Assembler::mov_b(const Operand& dst, const Immediate& src) {
   EnsureSpace ensure_space(this);
   EMIT(0xC6);
   emit_operand(eax, dst);
-  EMIT(imm8);
+  EMIT(static_cast<int8_t>(src.x_));
 }
 
 
@@ -489,13 +522,13 @@
 }
 
 
-void Assembler::mov_w(const Operand& dst, int16_t imm16) {
+void Assembler::mov_w(const Operand& dst, const Immediate& src) {
   EnsureSpace ensure_space(this);
   EMIT(0x66);
   EMIT(0xC7);
   emit_operand(eax, dst);
-  EMIT(static_cast<int8_t>(imm16 & 0xff));
-  EMIT(static_cast<int8_t>(imm16 >> 8));
+  EMIT(static_cast<int8_t>(src.x_ & 0xff));
+  EMIT(static_cast<int8_t>(src.x_ >> 8));
 }
 
 
@@ -982,24 +1015,24 @@
 }
 
 
-void Assembler::ror(Register dst, uint8_t imm8) {
+void Assembler::ror(const Operand& dst, uint8_t imm8) {
   EnsureSpace ensure_space(this);
   DCHECK(is_uint5(imm8));  // illegal shift count
   if (imm8 == 1) {
     EMIT(0xD1);
-    EMIT(0xC8 | dst.code());
+    emit_operand(ecx, dst);
   } else {
     EMIT(0xC1);
-    EMIT(0xC8 | dst.code());
+    emit_operand(ecx, dst);
     EMIT(imm8);
   }
 }
 
 
-void Assembler::ror_cl(Register dst) {
+void Assembler::ror_cl(const Operand& dst) {
   EnsureSpace ensure_space(this);
   EMIT(0xD3);
-  EMIT(0xC8 | dst.code());
+  emit_operand(ecx, dst);
 }
 
 
@@ -1951,7 +1984,7 @@
 }
 
 
-void Assembler::cvtss2sd(XMMRegister dst, XMMRegister src) {
+void Assembler::cvtss2sd(XMMRegister dst, const Operand& src) {
   EnsureSpace ensure_space(this);
   EMIT(0xF3);
   EMIT(0x0F);
@@ -1960,7 +1993,7 @@
 }
 
 
-void Assembler::cvtsd2ss(XMMRegister dst, XMMRegister src) {
+void Assembler::cvtsd2ss(XMMRegister dst, const Operand& src) {
   EnsureSpace ensure_space(this);
   EMIT(0xF2);
   EMIT(0x0F);
@@ -1969,15 +2002,6 @@
 }
 
 
-void Assembler::addsd(XMMRegister dst, XMMRegister src) {
-  EnsureSpace ensure_space(this);
-  EMIT(0xF2);
-  EMIT(0x0F);
-  EMIT(0x58);
-  emit_sse_operand(dst, src);
-}
-
-
 void Assembler::addsd(XMMRegister dst, const Operand& src) {
   EnsureSpace ensure_space(this);
   EMIT(0xF2);
@@ -1987,15 +2011,6 @@
 }
 
 
-void Assembler::mulsd(XMMRegister dst, XMMRegister src) {
-  EnsureSpace ensure_space(this);
-  EMIT(0xF2);
-  EMIT(0x0F);
-  EMIT(0x59);
-  emit_sse_operand(dst, src);
-}
-
-
 void Assembler::mulsd(XMMRegister dst, const Operand& src) {
   EnsureSpace ensure_space(this);
   EMIT(0xF2);
@@ -2005,15 +2020,6 @@
 }
 
 
-void Assembler::subsd(XMMRegister dst, XMMRegister src) {
-  EnsureSpace ensure_space(this);
-  EMIT(0xF2);
-  EMIT(0x0F);
-  EMIT(0x5C);
-  emit_sse_operand(dst, src);
-}
-
-
 void Assembler::subsd(XMMRegister dst, const Operand& src) {
   EnsureSpace ensure_space(this);
   EMIT(0xF2);
@@ -2023,7 +2029,7 @@
 }
 
 
-void Assembler::divsd(XMMRegister dst, XMMRegister src) {
+void Assembler::divsd(XMMRegister dst, const Operand& src) {
   EnsureSpace ensure_space(this);
   EMIT(0xF2);
   EMIT(0x0F);
@@ -2097,15 +2103,6 @@
 }
 
 
-void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) {
-  EnsureSpace ensure_space(this);
-  EMIT(0xF2);
-  EMIT(0x0F);
-  EMIT(0x51);
-  emit_sse_operand(dst, src);
-}
-
-
 void Assembler::sqrtsd(XMMRegister dst, const Operand& src) {
   EnsureSpace ensure_space(this);
   EMIT(0xF2);
@@ -2381,6 +2378,26 @@
 }
 
 
+void Assembler::pslld(XMMRegister reg, int8_t shift) {
+  EnsureSpace ensure_space(this);
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x72);
+  emit_sse_operand(esi, reg);  // esi == 6
+  EMIT(shift);
+}
+
+
+void Assembler::psrld(XMMRegister reg, int8_t shift) {
+  EnsureSpace ensure_space(this);
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x72);
+  emit_sse_operand(edx, reg);  // edx == 2
+  EMIT(shift);
+}
+
+
 void Assembler::psllq(XMMRegister reg, int8_t shift) {
   EnsureSpace ensure_space(this);
   EMIT(0x66);
@@ -2453,6 +2470,81 @@
 }
 
 
+void Assembler::addss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xF3);
+  EMIT(0x0F);
+  EMIT(0x58);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::subss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xF3);
+  EMIT(0x0F);
+  EMIT(0x5C);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::mulss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xF3);
+  EMIT(0x0F);
+  EMIT(0x59);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::divss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xF3);
+  EMIT(0x0F);
+  EMIT(0x5E);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::ucomiss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0x0f);
+  EMIT(0x2e);
+  emit_sse_operand(dst, src);
+}
+
+
+// AVX instructions
+void Assembler::vfmasd(byte op, XMMRegister dst, XMMRegister src1,
+                       const Operand& src2) {
+  DCHECK(IsEnabled(FMA3));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(src1, kLIG, k66, k0F38, kW1);
+  EMIT(op);
+  emit_sse_operand(dst, src2);
+}
+
+
+void Assembler::vfmass(byte op, XMMRegister dst, XMMRegister src1,
+                       const Operand& src2) {
+  DCHECK(IsEnabled(FMA3));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(src1, kLIG, k66, k0F38, kW0);
+  EMIT(op);
+  emit_sse_operand(dst, src2);
+}
+
+
+void Assembler::vsd(byte op, XMMRegister dst, XMMRegister src1,
+                    const Operand& src2) {
+  DCHECK(IsEnabled(AVX));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(src1, kLIG, kF2, k0F, kWIG);
+  EMIT(op);
+  emit_sse_operand(dst, src2);
+}
+
+
 void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
   Register ireg = { reg.code() };
   emit_operand(ireg, adr);
@@ -2474,8 +2566,16 @@
 }
 
 
-void Assembler::Print() {
-  Disassembler::Decode(isolate(), stdout, buffer_, pc_);
+void Assembler::emit_vex_prefix(XMMRegister vreg, VectorLength l, SIMDPrefix pp,
+                                LeadingOpcode mm, VexW w) {
+  if (mm != k0F || w != kW0) {
+    EMIT(0xc4);
+    EMIT(0xc0 | mm);
+    EMIT(w | ((~vreg.code() & 0xf) << 3) | l | pp);
+  } else {
+    EMIT(0xc5);
+    EMIT(((~vreg.code()) << 3) | l | pp);
+  }
 }
 
 
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index 8175778..b913f7a 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -148,6 +148,11 @@
     return kMaxNumAllocatableRegisters;
   }
 
+  // TODO(turbofan): Proper support for float32.
+  static int NumAllocatableAliasedRegisters() {
+    return NumAllocatableRegisters();
+  }
+
   static int ToAllocationIndex(XMMRegister reg) {
     DCHECK(reg.code() != 0);
     return reg.code() - 1;
@@ -614,12 +619,14 @@
   void mov_b(Register dst, Register src) { mov_b(dst, Operand(src)); }
   void mov_b(Register dst, const Operand& src);
   void mov_b(Register dst, int8_t imm8) { mov_b(Operand(dst), imm8); }
-  void mov_b(const Operand& dst, int8_t imm8);
+  void mov_b(const Operand& dst, int8_t src) { mov_b(dst, Immediate(src)); }
+  void mov_b(const Operand& dst, const Immediate& src);
   void mov_b(const Operand& dst, Register src);
 
   void mov_w(Register dst, const Operand& src);
+  void mov_w(const Operand& dst, int16_t src) { mov_w(dst, Immediate(src)); }
+  void mov_w(const Operand& dst, const Immediate& src);
   void mov_w(const Operand& dst, Register src);
-  void mov_w(const Operand& dst, int16_t imm16);
 
   void mov(Register dst, int32_t imm32);
   void mov(Register dst, const Immediate& x);
@@ -735,8 +742,11 @@
 
   void rcl(Register dst, uint8_t imm8);
   void rcr(Register dst, uint8_t imm8);
-  void ror(Register dst, uint8_t imm8);
-  void ror_cl(Register dst);
+
+  void ror(Register dst, uint8_t imm8) { ror(Operand(dst), imm8); }
+  void ror(const Operand& dst, uint8_t imm8);
+  void ror_cl(Register dst) { ror_cl(Operand(dst)); }
+  void ror_cl(const Operand& dst);
 
   void sar(Register dst, uint8_t imm8) { sar(Operand(dst), imm8); }
   void sar(const Operand& dst, uint8_t imm8);
@@ -918,6 +928,17 @@
   void cpuid();
 
   // SSE instructions
+  void addss(XMMRegister dst, XMMRegister src) { addss(dst, Operand(src)); }
+  void addss(XMMRegister dst, const Operand& src);
+  void subss(XMMRegister dst, XMMRegister src) { subss(dst, Operand(src)); }
+  void subss(XMMRegister dst, const Operand& src);
+  void mulss(XMMRegister dst, XMMRegister src) { mulss(dst, Operand(src)); }
+  void mulss(XMMRegister dst, const Operand& src);
+  void divss(XMMRegister dst, XMMRegister src) { divss(dst, Operand(src)); }
+  void divss(XMMRegister dst, const Operand& src);
+
+  void ucomiss(XMMRegister dst, XMMRegister src) { ucomiss(dst, Operand(src)); }
+  void ucomiss(XMMRegister dst, const Operand& src);
   void movaps(XMMRegister dst, XMMRegister src);
   void shufps(XMMRegister dst, XMMRegister src, byte imm8);
 
@@ -950,18 +971,24 @@
 
   void cvtsi2sd(XMMRegister dst, Register src) { cvtsi2sd(dst, Operand(src)); }
   void cvtsi2sd(XMMRegister dst, const Operand& src);
-  void cvtss2sd(XMMRegister dst, XMMRegister src);
-  void cvtsd2ss(XMMRegister dst, XMMRegister src);
-
-  void addsd(XMMRegister dst, XMMRegister src);
+  void cvtss2sd(XMMRegister dst, const Operand& src);
+  void cvtss2sd(XMMRegister dst, XMMRegister src) {
+    cvtss2sd(dst, Operand(src));
+  }
+  void cvtsd2ss(XMMRegister dst, const Operand& src);
+  void cvtsd2ss(XMMRegister dst, XMMRegister src) {
+    cvtsd2ss(dst, Operand(src));
+  }
+  void addsd(XMMRegister dst, XMMRegister src) { addsd(dst, Operand(src)); }
   void addsd(XMMRegister dst, const Operand& src);
-  void subsd(XMMRegister dst, XMMRegister src);
+  void subsd(XMMRegister dst, XMMRegister src) { subsd(dst, Operand(src)); }
   void subsd(XMMRegister dst, const Operand& src);
-  void mulsd(XMMRegister dst, XMMRegister src);
+  void mulsd(XMMRegister dst, XMMRegister src) { mulsd(dst, Operand(src)); }
   void mulsd(XMMRegister dst, const Operand& src);
-  void divsd(XMMRegister dst, XMMRegister src);
+  void divsd(XMMRegister dst, XMMRegister src) { divsd(dst, Operand(src)); }
+  void divsd(XMMRegister dst, const Operand& src);
   void xorpd(XMMRegister dst, XMMRegister src);
-  void sqrtsd(XMMRegister dst, XMMRegister src);
+  void sqrtsd(XMMRegister dst, XMMRegister src) { sqrtsd(dst, Operand(src)); }
   void sqrtsd(XMMRegister dst, const Operand& src);
 
   void andpd(XMMRegister dst, XMMRegister src);
@@ -1016,6 +1043,8 @@
   void por(XMMRegister dst, XMMRegister src);
   void ptest(XMMRegister dst, XMMRegister src);
 
+  void pslld(XMMRegister reg, int8_t shift);
+  void psrld(XMMRegister reg, int8_t shift);
   void psllq(XMMRegister reg, int8_t shift);
   void psllq(XMMRegister dst, XMMRegister src);
   void psrlq(XMMRegister reg, int8_t shift);
@@ -1033,15 +1062,188 @@
   // Parallel XMM operations.
   void movntdqa(XMMRegister dst, const Operand& src);
   void movntdq(const Operand& dst, XMMRegister src);
+
+  // AVX instructions
+  void vfmadd132sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmadd132sd(dst, src1, Operand(src2));
+  }
+  void vfmadd213sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmadd213sd(dst, src1, Operand(src2));
+  }
+  void vfmadd231sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmadd231sd(dst, src1, Operand(src2));
+  }
+  void vfmadd132sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0x99, dst, src1, src2);
+  }
+  void vfmadd213sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xa9, dst, src1, src2);
+  }
+  void vfmadd231sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xb9, dst, src1, src2);
+  }
+  void vfmsub132sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmsub132sd(dst, src1, Operand(src2));
+  }
+  void vfmsub213sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmsub213sd(dst, src1, Operand(src2));
+  }
+  void vfmsub231sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmsub231sd(dst, src1, Operand(src2));
+  }
+  void vfmsub132sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0x9b, dst, src1, src2);
+  }
+  void vfmsub213sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xab, dst, src1, src2);
+  }
+  void vfmsub231sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xbb, dst, src1, src2);
+  }
+  void vfnmadd132sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfnmadd132sd(dst, src1, Operand(src2));
+  }
+  void vfnmadd213sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfnmadd213sd(dst, src1, Operand(src2));
+  }
+  void vfnmadd231sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfnmadd231sd(dst, src1, Operand(src2));
+  }
+  void vfnmadd132sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0x9d, dst, src1, src2);
+  }
+  void vfnmadd213sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xad, dst, src1, src2);
+  }
+  void vfnmadd231sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xbd, dst, src1, src2);
+  }
+  void vfnmsub132sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfnmsub132sd(dst, src1, Operand(src2));
+  }
+  void vfnmsub213sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfnmsub213sd(dst, src1, Operand(src2));
+  }
+  void vfnmsub231sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfnmsub231sd(dst, src1, Operand(src2));
+  }
+  void vfnmsub132sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0x9f, dst, src1, src2);
+  }
+  void vfnmsub213sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xaf, dst, src1, src2);
+  }
+  void vfnmsub231sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xbf, dst, src1, src2);
+  }
+  void vfmasd(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);
+
+  void vfmadd132ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmadd132ss(dst, src1, Operand(src2));
+  }
+  void vfmadd213ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmadd213ss(dst, src1, Operand(src2));
+  }
+  void vfmadd231ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmadd231ss(dst, src1, Operand(src2));
+  }
+  void vfmadd132ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0x99, dst, src1, src2);
+  }
+  void vfmadd213ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xa9, dst, src1, src2);
+  }
+  void vfmadd231ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xb9, dst, src1, src2);
+  }
+  void vfmsub132ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmsub132ss(dst, src1, Operand(src2));
+  }
+  void vfmsub213ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmsub213ss(dst, src1, Operand(src2));
+  }
+  void vfmsub231ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmsub231ss(dst, src1, Operand(src2));
+  }
+  void vfmsub132ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0x9b, dst, src1, src2);
+  }
+  void vfmsub213ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xab, dst, src1, src2);
+  }
+  void vfmsub231ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xbb, dst, src1, src2);
+  }
+  void vfnmadd132ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfnmadd132ss(dst, src1, Operand(src2));
+  }
+  void vfnmadd213ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfnmadd213ss(dst, src1, Operand(src2));
+  }
+  void vfnmadd231ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfnmadd231ss(dst, src1, Operand(src2));
+  }
+  void vfnmadd132ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0x9d, dst, src1, src2);
+  }
+  void vfnmadd213ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xad, dst, src1, src2);
+  }
+  void vfnmadd231ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xbd, dst, src1, src2);
+  }
+  void vfnmsub132ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfnmsub132ss(dst, src1, Operand(src2));
+  }
+  void vfnmsub213ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfnmsub213ss(dst, src1, Operand(src2));
+  }
+  void vfnmsub231ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfnmsub231ss(dst, src1, Operand(src2));
+  }
+  void vfnmsub132ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0x9f, dst, src1, src2);
+  }
+  void vfnmsub213ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xaf, dst, src1, src2);
+  }
+  void vfnmsub231ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xbf, dst, src1, src2);
+  }
+  void vfmass(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);
+
+  void vaddsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vaddsd(dst, src1, Operand(src2));
+  }
+  void vaddsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vsd(0x58, dst, src1, src2);
+  }
+  void vsubsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vsubsd(dst, src1, Operand(src2));
+  }
+  void vsubsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vsd(0x5c, dst, src1, src2);
+  }
+  void vmulsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vmulsd(dst, src1, Operand(src2));
+  }
+  void vmulsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vsd(0x59, dst, src1, src2);
+  }
+  void vdivsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vdivsd(dst, src1, Operand(src2));
+  }
+  void vdivsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vsd(0x5e, dst, src1, src2);
+  }
+  void vsd(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);
+
   // Prefetch src position into cache level.
   // Level 1, 2 or 3 specifies CPU cache level. Level 0 specifies a
   // non-temporal
   void prefetch(const Operand& src, int level);
   // TODO(lrn): Need SFENCE for movnt?
 
-  // Debugging
-  void Print();
-
   // Check the code size generated from label to here.
   int SizeOfCodeGeneratedSince(Label* label) {
     return pc_offset() - label->pos();
@@ -1139,6 +1341,14 @@
 
   void emit_farith(int b1, int b2, int i);
 
+  // Emit vex prefix
+  enum SIMDPrefix { kNone = 0x0, k66 = 0x1, kF3 = 0x2, kF2 = 0x3 };
+  enum VectorLength { kL128 = 0x0, kL256 = 0x4, kLIG = kL128 };
+  enum VexW { kW0 = 0x0, kW1 = 0x80, kWIG = kW0 };
+  enum LeadingOpcode { k0F = 0x1, k0F38 = 0x2, k0F3A = 0x2 };
+  inline void emit_vex_prefix(XMMRegister v, VectorLength l, SIMDPrefix pp,
+                              LeadingOpcode m, VexW w);
+
   // labels
   void print(Label* L);
   void bind_to(Label* L, int pos);
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index c24e77f..5767489 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -160,18 +160,17 @@
       if (!is_api_function) {
         Label allocate;
         // The code below relies on these assumptions.
-        STATIC_ASSERT(JSFunction::kNoSlackTracking == 0);
-        STATIC_ASSERT(Map::ConstructionCount::kShift +
-                      Map::ConstructionCount::kSize == 32);
+        STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32);
         // Check if slack tracking is enabled.
         __ mov(esi, FieldOperand(eax, Map::kBitField3Offset));
-        __ shr(esi, Map::ConstructionCount::kShift);
-        __ j(zero, &allocate);  // JSFunction::kNoSlackTracking
+        __ shr(esi, Map::Counter::kShift);
+        __ cmp(esi, Map::kSlackTrackingCounterEnd);
+        __ j(less, &allocate);
         // Decrease generous allocation count.
         __ sub(FieldOperand(eax, Map::kBitField3Offset),
-               Immediate(1 << Map::ConstructionCount::kShift));
+               Immediate(1 << Map::Counter::kShift));
 
-        __ cmp(esi, JSFunction::kFinishSlackTracking);
+        __ cmp(esi, Map::kSlackTrackingCounterEnd);
         __ j(not_equal, &allocate);
 
         __ push(eax);
@@ -182,7 +181,7 @@
 
         __ pop(edi);
         __ pop(eax);
-        __ xor_(esi, esi);  // JSFunction::kNoSlackTracking
+        __ mov(esi, Map::kSlackTrackingCounterEnd - 1);
 
         __ bind(&allocate);
       }
@@ -219,8 +218,8 @@
         Label no_inobject_slack_tracking;
 
         // Check if slack tracking is enabled.
-        __ cmp(esi, JSFunction::kNoSlackTracking);
-        __ j(equal, &no_inobject_slack_tracking);
+        __ cmp(esi, Map::kSlackTrackingCounterEnd);
+        __ j(less, &no_inobject_slack_tracking);
 
         // Allocate object with a slack.
         __ movzx_b(esi,
@@ -1002,17 +1001,21 @@
     __ bind(&loop);
     __ mov(receiver, Operand(ebp, kArgumentsOffset));  // load arguments
 
-    // Use inline caching to speed up access to arguments.
     if (FLAG_vector_ics) {
-      __ mov(VectorLoadICDescriptor::SlotRegister(),
-             Immediate(Smi::FromInt(0)));
+      // TODO(mvstanton): Vector-based ics need additional infrastructure to
+      // be embedded here. For now, just call the runtime.
+      __ push(receiver);
+      __ push(key);
+      __ CallRuntime(Runtime::kGetProperty, 2);
+    } else {
+      // Use inline caching to speed up access to arguments.
+      Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code();
+      __ call(ic, RelocInfo::CODE_TARGET);
+      // It is important that we do not have a test instruction after the
+      // call.  A test instruction after the call is used to indicate that
+      // we have generated an inline version of the keyed load.  In this
+      // case, we know that we are not generating a test instruction next.
     }
-    Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code();
-    __ call(ic, RelocInfo::CODE_TARGET);
-    // It is important that we do not have a test instruction after the
-    // call.  A test instruction after the call is used to indicate that
-    // we have generated an inline version of the keyed load.  In this
-    // case, we know that we are not generating a test instruction next.
 
     // Push the nth argument.
     __ push(eax);
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 4e14b69..b75ae3a 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -15,7 +15,7 @@
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -652,9 +652,20 @@
 void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
   Label miss;
   Register receiver = LoadDescriptor::ReceiverRegister();
+  if (FLAG_vector_ics) {
+    // With careful management, we won't have to save slot and vector on
+    // the stack. Simply handle the possibly missing case first.
+    // TODO(mvstanton): this code can be more efficient.
+    __ cmp(FieldOperand(receiver, JSFunction::kPrototypeOrInitialMapOffset),
+           Immediate(isolate()->factory()->the_hole_value()));
+    __ j(equal, &miss);
+    __ TryGetFunctionPrototype(receiver, eax, ebx, &miss);
+    __ ret(0);
+  } else {
+    NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, eax,
+                                                            ebx, &miss);
+  }
 
-  NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, eax,
-                                                          ebx, &miss);
   __ bind(&miss);
   PropertyAccessCompiler::TailCallBuiltin(
       masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
@@ -691,6 +702,41 @@
 }
 
 
+void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
+  // Return address is on the stack.
+  Label miss;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register index = LoadDescriptor::NameRegister();
+  Register scratch = edi;
+  DCHECK(!scratch.is(receiver) && !scratch.is(index));
+  Register result = eax;
+  DCHECK(!result.is(scratch));
+  DCHECK(!FLAG_vector_ics ||
+         (!scratch.is(VectorLoadICDescriptor::VectorRegister()) &&
+          result.is(VectorLoadICDescriptor::SlotRegister())));
+
+  // StringCharAtGenerator doesn't use the result register until it's passed
+  // the different miss possibilities. If it did, we would have a conflict
+  // when FLAG_vector_ics is true.
+  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
+                                          &miss,  // When not a string.
+                                          &miss,  // When not a number.
+                                          &miss,  // When index out of range.
+                                          STRING_INDEX_IS_ARRAY_INDEX,
+                                          RECEIVER_IS_STRING);
+  char_at_generator.GenerateFast(masm);
+  __ ret(0);
+
+  StubRuntimeCallHelper call_helper;
+  char_at_generator.GenerateSlow(masm, call_helper);
+
+  __ bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
   // The key is in edx and the parameter count is in eax.
   DCHECK(edx.is(ArgumentsAccessReadDescriptor::index()));
@@ -2185,6 +2231,10 @@
   // edi - function
   // edx - slot id
   Isolate* isolate = masm->isolate();
+  const int with_types_offset =
+      FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
+  const int generic_offset =
+      FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
   Label slow, non_function, wrap, cont;
   Label have_js_function;
@@ -2224,28 +2274,66 @@
   }
 
   __ bind(&extra_checks_or_miss);
-  Label miss;
+  Label uninitialized, miss;
 
   __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size,
                            FixedArray::kHeaderSize));
   __ cmp(ecx, Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
   __ j(equal, &slow_start);
-  __ cmp(ecx, Immediate(TypeFeedbackVector::UninitializedSentinel(isolate)));
-  __ j(equal, &miss);
 
-  if (!FLAG_trace_ic) {
-    // We are going megamorphic. If the feedback is a JSFunction, it is fine
-    // to handle it here. More complex cases are dealt with in the runtime.
-    __ AssertNotSmi(ecx);
-    __ CmpObjectType(ecx, JS_FUNCTION_TYPE, ecx);
-    __ j(not_equal, &miss);
-    __ mov(FieldOperand(ebx, edx, times_half_pointer_size,
-                        FixedArray::kHeaderSize),
-           Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
-    __ jmp(&slow_start);
+  // The following cases attempt to handle MISS cases without going to the
+  // runtime.
+  if (FLAG_trace_ic) {
+    __ jmp(&miss);
   }
 
-  // We are here because tracing is on or we are going monomorphic.
+  __ cmp(ecx, Immediate(TypeFeedbackVector::UninitializedSentinel(isolate)));
+  __ j(equal, &uninitialized);
+
+  // We are going megamorphic. If the feedback is a JSFunction, it is fine
+  // to handle it here. More complex cases are dealt with in the runtime.
+  __ AssertNotSmi(ecx);
+  __ CmpObjectType(ecx, JS_FUNCTION_TYPE, ecx);
+  __ j(not_equal, &miss);
+  __ mov(
+      FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize),
+      Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
+  // We have to update statistics for runtime profiling.
+  __ sub(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1)));
+  __ add(FieldOperand(ebx, generic_offset), Immediate(Smi::FromInt(1)));
+  __ jmp(&slow_start);
+
+  __ bind(&uninitialized);
+
+  // We are going monomorphic, provided we actually have a JSFunction.
+  __ JumpIfSmi(edi, &miss);
+
+  // Goto miss case if we do not have a function.
+  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
+  __ j(not_equal, &miss);
+
+  // Make sure the function is not the Array() function, which requires special
+  // behavior on MISS.
+  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx);
+  __ cmp(edi, ecx);
+  __ j(equal, &miss);
+
+  // Update stats.
+  __ add(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1)));
+
+  // Store the function.
+  __ mov(
+      FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize),
+      edi);
+
+  // Update the write barrier.
+  __ mov(eax, edi);
+  __ RecordWriteArray(ebx, eax, edx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+  __ jmp(&have_js_function);
+
+  // We are here because tracing is on or we encountered a MISS case we can't
+  // handle here.
   __ bind(&miss);
   GenerateMiss(masm);
 
@@ -2747,14 +2835,16 @@
 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
   // If the receiver is a smi trigger the non-string case.
   STATIC_ASSERT(kSmiTag == 0);
-  __ JumpIfSmi(object_, receiver_not_string_);
+  if (check_mode_ == RECEIVER_IS_UNKNOWN) {
+    __ JumpIfSmi(object_, receiver_not_string_);
 
-  // Fetch the instance type of the receiver into result register.
-  __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
-  __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
-  // If the receiver is not a string trigger the non-string case.
-  __ test(result_, Immediate(kIsNotStringMask));
-  __ j(not_zero, receiver_not_string_);
+    // Fetch the instance type of the receiver into result register.
+    __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
+    __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
+    // If the receiver is not a string trigger the non-string case.
+    __ test(result_, Immediate(kIsNotStringMask));
+    __ j(not_zero, receiver_not_string_);
+  }
 
   // If the index is non-smi trigger the non-smi case.
   STATIC_ASSERT(kSmiTag == 0);
@@ -3126,14 +3216,61 @@
   // ebx: instance type
   // ecx: sub string length (smi)
   // edx: from index (smi)
-  StringCharAtGenerator generator(
-      eax, edx, ecx, eax, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
+  StringCharAtGenerator generator(eax, edx, ecx, eax, &runtime, &runtime,
+                                  &runtime, STRING_INDEX_IS_NUMBER,
+                                  RECEIVER_IS_STRING);
   generator.GenerateFast(masm);
   __ ret(3 * kPointerSize);
   generator.SkipSlow(masm, &runtime);
 }
 
 
+void ToNumberStub::Generate(MacroAssembler* masm) {
+  // The ToNumber stub takes one argument in eax.
+  Label not_smi;
+  __ JumpIfNotSmi(eax, &not_smi, Label::kNear);
+  __ Ret();
+  __ bind(&not_smi);
+
+  Label not_heap_number;
+  __ CompareMap(eax, masm->isolate()->factory()->heap_number_map());
+  __ j(not_equal, &not_heap_number, Label::kNear);
+  __ Ret();
+  __ bind(&not_heap_number);
+
+  Label not_string, slow_string;
+  __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edi);
+  // eax: object
+  // edi: object map
+  __ j(above_equal, &not_string, Label::kNear);
+  // Check if string has a cached array index.
+  __ test(FieldOperand(eax, String::kHashFieldOffset),
+          Immediate(String::kContainsCachedArrayIndexMask));
+  __ j(not_zero, &slow_string, Label::kNear);
+  __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
+  __ IndexFromHash(eax, eax);
+  __ Ret();
+  __ bind(&slow_string);
+  __ pop(ecx);   // Pop return address.
+  __ push(eax);  // Push argument.
+  __ push(ecx);  // Push return address.
+  __ TailCallRuntime(Runtime::kStringToNumber, 1, 1);
+  __ bind(&not_string);
+
+  Label not_oddball;
+  __ CmpInstanceType(edi, ODDBALL_TYPE);
+  __ j(not_equal, &not_oddball, Label::kNear);
+  __ mov(eax, FieldOperand(eax, Oddball::kToNumberOffset));
+  __ Ret();
+  __ bind(&not_oddball);
+
+  __ pop(ecx);   // Pop return address.
+  __ push(eax);  // Push argument.
+  __ push(ecx);  // Push return address.
+  __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
+}
+
+
 void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm,
                                                    Register left,
                                                    Register right,
diff --git a/src/ia32/code-stubs-ia32.h b/src/ia32/code-stubs-ia32.h
index eabb5a5..0b12fd0 100644
--- a/src/ia32/code-stubs-ia32.h
+++ b/src/ia32/code-stubs-ia32.h
@@ -76,7 +76,7 @@
                                      Register r0,
                                      Register r1);
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
  private:
   static const int kInlinedProbes = 4;
@@ -142,7 +142,7 @@
     INCREMENTAL_COMPACTION
   };
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
   static const byte kTwoByteNopInstruction = 0x3c;  // Cmpb al, #imm8.
   static const byte kTwoByteJumpInstruction = 0xeb;  // Jmp #imm8.
@@ -339,9 +339,9 @@
     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
   };
 
-  virtual inline Major MajorKey() const FINAL OVERRIDE { return RecordWrite; }
+  inline Major MajorKey() const FINAL { return RecordWrite; }
 
-  virtual void Generate(MacroAssembler* masm) OVERRIDE;
+  void Generate(MacroAssembler* masm) OVERRIDE;
   void GenerateIncremental(MacroAssembler* masm, Mode mode);
   void CheckNeedsToInformIncrementalMarker(
       MacroAssembler* masm,
@@ -349,7 +349,7 @@
       Mode mode);
   void InformIncrementalMarker(MacroAssembler* masm);
 
-  void Activate(Code* code) {
+  void Activate(Code* code) OVERRIDE {
     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
   }
 
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index 52cf72b..083f5db 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -720,6 +720,19 @@
   __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx);
   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
 
+  // Allocating heap numbers in the loop below can fail and cause a jump to
+  // gc_required. We can't leave a partly initialized FixedArray behind,
+  // so pessimistically fill it with holes now.
+  Label initialization_loop, initialization_loop_entry;
+  __ jmp(&initialization_loop_entry, Label::kNear);
+  __ bind(&initialization_loop);
+  __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize),
+         masm->isolate()->factory()->the_hole_value());
+  __ bind(&initialization_loop_entry);
+  __ sub(ebx, Immediate(Smi::FromInt(1)));
+  __ j(not_sign, &initialization_loop);
+
+  __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
   __ jmp(&entry);
 
   // ebx: target map
diff --git a/src/ia32/debug-ia32.cc b/src/ia32/debug-ia32.cc
index 4331b08..34b33b2 100644
--- a/src/ia32/debug-ia32.cc
+++ b/src/ia32/debug-ia32.cc
@@ -182,7 +182,11 @@
   // Register state for IC load call (from ic-ia32.cc).
   Register receiver = LoadDescriptor::ReceiverRegister();
   Register name = LoadDescriptor::NameRegister();
-  Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit(), 0, false);
+  RegList regs = receiver.bit() | name.bit();
+  if (FLAG_vector_ics) {
+    regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
+  }
+  Generate_DebugBreakCallHelper(masm, regs, 0, false);
 }
 
 
diff --git a/src/ia32/deoptimizer-ia32.cc b/src/ia32/deoptimizer-ia32.cc
index f40e23c..e451fcc 100644
--- a/src/ia32/deoptimizer-ia32.cc
+++ b/src/ia32/deoptimizer-ia32.cc
@@ -27,7 +27,7 @@
   HandleScope scope(isolate);
 
   // Compute the size of relocation information needed for the code
-  // patching in Deoptimizer::DeoptimizeFunction.
+  // patching in Deoptimizer::PatchCodeForDeoptimization below.
   int min_reloc_size = 0;
   int prev_pc_offset = 0;
   DeoptimizationInputData* deopt_data =
diff --git a/src/ia32/disasm-ia32.cc b/src/ia32/disasm-ia32.cc
index 22c2a55..bf88f69 100644
--- a/src/ia32/disasm-ia32.cc
+++ b/src/ia32/disasm-ia32.cc
@@ -246,6 +246,9 @@
   DisassemblerIA32(const NameConverter& converter,
                    bool abort_on_unimplemented = true)
       : converter_(converter),
+        vex_byte0_(0),
+        vex_byte1_(0),
+        vex_byte2_(0),
         instruction_table_(InstructionTable::get_instance()),
         tmp_buffer_pos_(0),
         abort_on_unimplemented_(abort_on_unimplemented) {
@@ -260,6 +263,9 @@
 
  private:
   const NameConverter& converter_;
+  byte vex_byte0_;  // 0xc4 or 0xc5
+  byte vex_byte1_;
+  byte vex_byte2_;  // only for 3 bytes vex prefix
   InstructionTable* instruction_table_;
   v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
   unsigned int tmp_buffer_pos_;
@@ -287,6 +293,57 @@
     kSAR = 7
   };
 
+  bool vex_128() {
+    DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
+    byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
+    return (checked & 4) != 1;
+  }
+
+  bool vex_66() {
+    DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
+    byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
+    return (checked & 3) == 1;
+  }
+
+  bool vex_f3() {
+    DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
+    byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
+    return (checked & 3) == 2;
+  }
+
+  bool vex_f2() {
+    DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
+    byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
+    return (checked & 3) == 3;
+  }
+
+  bool vex_w() {
+    if (vex_byte0_ == 0xc5) return false;
+    return (vex_byte2_ & 0x80) != 0;
+  }
+
+  bool vex_0f() {
+    if (vex_byte0_ == 0xc5) return true;
+    return (vex_byte1_ & 3) == 1;
+  }
+
+  bool vex_0f38() {
+    if (vex_byte0_ == 0xc5) return false;
+    return (vex_byte1_ & 3) == 2;
+  }
+
+  bool vex_0f3a() {
+    if (vex_byte0_ == 0xc5) return false;
+    return (vex_byte1_ & 3) == 3;
+  }
+
+  int vex_vreg() {
+    DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
+    byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
+    return ~(checked >> 3) & 0xf;
+  }
+
+  char float_size_code() { return "sd"[vex_w()]; }
 
   const char* NameOfCPURegister(int reg) const {
     return converter_.NameOfCPURegister(reg);
@@ -340,6 +397,7 @@
   int FPUInstruction(byte* data);
   int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
   int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
+  int AVXInstruction(byte* data);
   void AppendToBuffer(const char* format, ...);
 
 
@@ -679,6 +737,111 @@
 }
 
 
+int DisassemblerIA32::AVXInstruction(byte* data) {
+  byte opcode = *data;
+  byte* current = data + 1;
+  if (vex_66() && vex_0f38()) {
+    int mod, regop, rm, vvvv = vex_vreg();
+    get_modrm(*current, &mod, &regop, &rm);
+    switch (opcode) {
+      case 0x99:
+        AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xa9:
+        AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xb9:
+        AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x9b:
+        AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xab:
+        AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xbb:
+        AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x9d:
+        AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xad:
+        AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xbd:
+        AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x9f:
+        AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xaf:
+        AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xbf:
+        AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      default:
+        UnimplementedInstruction();
+    }
+  } else if (vex_f2() && vex_0f()) {
+    int mod, regop, rm, vvvv = vex_vreg();
+    get_modrm(*current, &mod, &regop, &rm);
+    switch (opcode) {
+      case 0x58:
+        AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x59:
+        AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x5c:
+        AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x5e:
+        AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      default:
+        UnimplementedInstruction();
+    }
+  } else {
+    UnimplementedInstruction();
+  }
+
+  return static_cast<int>(current - data);
+}
+
+
 // Returns number of bytes used, including *data.
 int DisassemblerIA32::FPUInstruction(byte* data) {
   byte escape_opcode = *data;
@@ -903,65 +1066,81 @@
   } else if (*data == 0x2E /*cs*/) {
     branch_hint = "predicted not taken";
     data++;
+  } else if (*data == 0xC4 && *(data + 1) >= 0xc0) {
+    vex_byte0_ = *data;
+    vex_byte1_ = *(data + 1);
+    vex_byte2_ = *(data + 2);
+    data += 3;
+  } else if (*data == 0xC5 && *(data + 1) >= 0xc0) {
+    vex_byte0_ = *data;
+    vex_byte1_ = *(data + 1);
+    data += 2;
   }
+
   bool processed = true;  // Will be set to false if the current instruction
                           // is not in 'instructions' table.
-  const InstructionDesc& idesc = instruction_table_->Get(*data);
-  switch (idesc.type) {
-    case ZERO_OPERANDS_INSTR:
-      AppendToBuffer(idesc.mnem);
-      data++;
-      break;
+  // Decode AVX instructions.
+  if (vex_byte0_ != 0) {
+    data += AVXInstruction(data);
+  } else {
+    const InstructionDesc& idesc = instruction_table_->Get(*data);
+    switch (idesc.type) {
+      case ZERO_OPERANDS_INSTR:
+        AppendToBuffer(idesc.mnem);
+        data++;
+        break;
 
-    case TWO_OPERANDS_INSTR:
-      data++;
-      data += PrintOperands(idesc.mnem, idesc.op_order_, data);
-      break;
+      case TWO_OPERANDS_INSTR:
+        data++;
+        data += PrintOperands(idesc.mnem, idesc.op_order_, data);
+        break;
 
-    case JUMP_CONDITIONAL_SHORT_INSTR:
-      data += JumpConditionalShort(data, branch_hint);
-      break;
+      case JUMP_CONDITIONAL_SHORT_INSTR:
+        data += JumpConditionalShort(data, branch_hint);
+        break;
 
-    case REGISTER_INSTR:
-      AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
-      data++;
-      break;
+      case REGISTER_INSTR:
+        AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
+        data++;
+        break;
 
-    case MOVE_REG_INSTR: {
-      byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
-      AppendToBuffer("mov %s,%s",
-                     NameOfCPURegister(*data & 0x07),
-                     NameOfAddress(addr));
-      data += 5;
-      break;
+      case MOVE_REG_INSTR: {
+        byte* addr =
+            reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
+        AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
+                       NameOfAddress(addr));
+        data += 5;
+        break;
+      }
+
+      case CALL_JUMP_INSTR: {
+        byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
+        AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
+        data += 5;
+        break;
+      }
+
+      case SHORT_IMMEDIATE_INSTR: {
+        byte* addr =
+            reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
+        AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
+        data += 5;
+        break;
+      }
+
+      case BYTE_IMMEDIATE_INSTR: {
+        AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
+        data += 2;
+        break;
+      }
+
+      case NO_INSTR:
+        processed = false;
+        break;
+
+      default:
+        UNIMPLEMENTED();  // This type is not implemented.
     }
-
-    case CALL_JUMP_INSTR: {
-      byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
-      AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
-      data += 5;
-      break;
-    }
-
-    case SHORT_IMMEDIATE_INSTR: {
-      byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
-      AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
-      data += 5;
-      break;
-    }
-
-    case BYTE_IMMEDIATE_INSTR: {
-      AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
-      data += 2;
-      break;
-    }
-
-    case NO_INSTR:
-      processed = false;
-      break;
-
-    default:
-      UNIMPLEMENTED();  // This type is not implemented.
   }
   //----------------------------
   if (!processed) {
@@ -1047,6 +1226,12 @@
                            NameOfXMMRegister(regop),
                            NameOfXMMRegister(rm));
             data++;
+          } else if (f0byte == 0x2e) {
+            data += 2;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
+            data += PrintRightXMMOperand(data);
           } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
             const char* const pseudo_op[] = {
               "rcpps",
@@ -1386,6 +1571,15 @@
                            NameOfXMMRegister(regop),
                            NameOfXMMRegister(rm));
             data++;
+          } else if (*data == 0x72) {
+            data++;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            int8_t imm8 = static_cast<int8_t>(data[1]);
+            DCHECK(regop == esi || regop == edx);
+            AppendToBuffer("%s %s,%d", (regop == esi) ? "pslld" : "psrld",
+                           NameOfXMMRegister(rm), static_cast<int>(imm8));
+            data += 2;
           } else if (*data == 0x73) {
             data++;
             int mod, regop, rm;
@@ -1608,12 +1802,36 @@
             get_modrm(*data, &mod, &regop, &rm);
             AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
             data += PrintRightXMMOperand(data);
+          } else if (b2 == 0x58) {
+            data += 3;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
+            data += PrintRightXMMOperand(data);
+          } else if (b2 == 0x59) {
+            data += 3;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            AppendToBuffer("mulss %s,", NameOfXMMRegister(regop));
+            data += PrintRightXMMOperand(data);
           } else if (b2 == 0x5A) {
             data += 3;
             int mod, regop, rm;
             get_modrm(*data, &mod, &regop, &rm);
             AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
             data += PrintRightXMMOperand(data);
+          } else if (b2 == 0x5c) {
+            data += 3;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            AppendToBuffer("subss %s,", NameOfXMMRegister(regop));
+            data += PrintRightXMMOperand(data);
+          } else if (b2 == 0x5e) {
+            data += 3;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            AppendToBuffer("divss %s,", NameOfXMMRegister(regop));
+            data += PrintRightXMMOperand(data);
           } else if (b2 == 0x6F) {
             data += 3;
             int mod, regop, rm;
@@ -1681,17 +1899,17 @@
 //------------------------------------------------------------------------------
 
 
-static const char* cpu_regs[8] = {
+static const char* const cpu_regs[8] = {
   "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
 };
 
 
-static const char* byte_cpu_regs[8] = {
+static const char* const byte_cpu_regs[8] = {
   "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
 };
 
 
-static const char* xmm_regs[8] = {
+static const char* const xmm_regs[8] = {
   "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
 };
 
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 661d301..1ba4095 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -188,10 +188,10 @@
     Comment cmnt(masm_, "[ Allocate context");
     bool need_write_barrier = true;
     // Argument to NewContext is the function, which is still in edi.
-    if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
+    if (FLAG_harmony_scoping && info->scope()->is_script_scope()) {
       __ push(edi);
       __ Push(info->scope()->GetScopeInfo());
-      __ CallRuntime(Runtime::kNewGlobalContext, 2);
+      __ CallRuntime(Runtime::kNewScriptContext, 2);
     } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
       FastNewContextStub stub(isolate(), heap_slots);
       __ CallStub(&stub);
@@ -872,7 +872,7 @@
   EmitDebugCheckDeclarationContext(variable);
 
   // Load instance object.
-  __ LoadContext(eax, scope_->ContextChainLength(scope_->GlobalScope()));
+  __ LoadContext(eax, scope_->ContextChainLength(scope_->ScriptScope()));
   __ mov(eax, ContextOperand(eax, variable->interface()->Index()));
   __ mov(eax, ContextOperand(eax, Context::EXTENSION_INDEX));
 
@@ -1035,7 +1035,7 @@
 
 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
   Comment cmnt(masm_, "[ ForInStatement");
-  int slot = stmt->ForInFeedbackSlot();
+  FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
 
   SetStatementPosition(stmt);
 
@@ -1045,6 +1045,7 @@
 
   // Get the object to enumerate over. If the object is null or undefined, skip
   // over the loop.  See ECMA-262 version 5, section 12.6.4.
+  SetExpressionPosition(stmt->enumerable());
   VisitForAccumulatorValue(stmt->enumerable());
   __ cmp(eax, isolate()->factory()->undefined_value());
   __ j(equal, &exit);
@@ -1062,6 +1063,7 @@
   __ push(eax);
   __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
   __ bind(&done_convert);
+  PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
   __ push(eax);
 
   // Check for proxies.
@@ -1083,6 +1085,7 @@
   __ bind(&call_runtime);
   __ push(eax);
   __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
+  PrepareForBailoutForId(stmt->EnumId(), TOS_REG);
   __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
          isolate()->factory()->meta_map());
   __ j(not_equal, &fixed_array);
@@ -1117,7 +1120,8 @@
 
   // No need for a write barrier, we are storing a Smi in the feedback vector.
   __ LoadHeapObject(ebx, FeedbackVector());
-  __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(slot)),
+  int vector_index = FeedbackVector()->GetIndex(slot);
+  __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(vector_index)),
          Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate())));
 
   __ mov(ebx, Immediate(Smi::FromInt(1)));  // Smi indicates slow check
@@ -1136,6 +1140,8 @@
   // Generate code for doing the condition check.
   PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
   __ bind(&loop);
+  SetExpressionPosition(stmt->each());
+
   __ mov(eax, Operand(esp, 0 * kPointerSize));  // Get the current index.
   __ cmp(eax, Operand(esp, 1 * kPointerSize));  // Compare to the array length.
   __ j(above_equal, loop_statement.break_label());
@@ -1202,48 +1208,6 @@
 }
 
 
-void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
-  Comment cmnt(masm_, "[ ForOfStatement");
-  SetStatementPosition(stmt);
-
-  Iteration loop_statement(this, stmt);
-  increment_loop_depth();
-
-  // var iterator = iterable[Symbol.iterator]();
-  VisitForEffect(stmt->assign_iterator());
-
-  // Loop entry.
-  __ bind(loop_statement.continue_label());
-
-  // result = iterator.next()
-  VisitForEffect(stmt->next_result());
-
-  // if (result.done) break;
-  Label result_not_done;
-  VisitForControl(stmt->result_done(),
-                  loop_statement.break_label(),
-                  &result_not_done,
-                  &result_not_done);
-  __ bind(&result_not_done);
-
-  // each = result.value
-  VisitForEffect(stmt->assign_each());
-
-  // Generate code for the body of the loop.
-  Visit(stmt->body());
-
-  // Check stack before looping.
-  PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
-  EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
-  __ jmp(loop_statement.continue_label());
-
-  // Exit and decrement the loop depth.
-  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
-  __ bind(loop_statement.break_label());
-  decrement_loop_depth();
-}
-
-
 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
                                        bool pretenure) {
   // Use the fast case closure allocation code that allocates in new
@@ -1287,7 +1251,13 @@
   Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
   __ mov(LoadDescriptor::NameRegister(), home_object_symbol);
 
-  CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  if (FLAG_vector_ics) {
+    __ mov(VectorLoadICDescriptor::SlotRegister(),
+           Immediate(SmiFromSlot(expr->HomeObjectFeedbackSlot())));
+    CallLoadIC(NOT_CONTEXTUAL);
+  } else {
+    CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  }
 
   __ cmp(eax, isolate()->factory()->undefined_value());
   Label done;
@@ -1297,6 +1267,19 @@
 }
 
 
+void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
+                                                  int offset) {
+  if (NeedsHomeObject(initializer)) {
+    __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
+    __ mov(StoreDescriptor::NameRegister(),
+           Immediate(isolate()->factory()->home_object_symbol()));
+    __ mov(StoreDescriptor::ValueRegister(),
+           Operand(esp, offset * kPointerSize));
+    CallStoreIC();
+  }
+}
+
+
 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
                                                       TypeofState typeof_state,
                                                       Label* slow) {
@@ -1351,7 +1334,7 @@
   __ mov(LoadDescriptor::NameRegister(), proxy->var()->name());
   if (FLAG_vector_ics) {
     __ mov(VectorLoadICDescriptor::SlotRegister(),
-           Immediate(Smi::FromInt(proxy->VariableFeedbackSlot())));
+           Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
   }
 
   ContextualMode mode = (typeof_state == INSIDE_TYPEOF)
@@ -1438,7 +1421,7 @@
       __ mov(LoadDescriptor::NameRegister(), var->name());
       if (FLAG_vector_ics) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
-               Immediate(Smi::FromInt(proxy->VariableFeedbackSlot())));
+               Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
       }
       CallLoadIC(CONTEXTUAL);
       context()->Plug(eax);
@@ -1622,6 +1605,7 @@
     FastCloneShallowObjectStub stub(isolate(), properties_count);
     __ CallStub(&stub);
   }
+  PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
 
   // If result_saved is true the result is on top of the stack.  If
   // result_saved is false the result is in eax.
@@ -1650,6 +1634,8 @@
         DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
         // Fall through.
       case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             VisitForAccumulatorValue(value);
@@ -1658,6 +1644,14 @@
             __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
             CallStoreIC(key->LiteralFeedbackId());
             PrepareForBailoutForId(key->id(), NO_REGISTERS);
+
+            if (NeedsHomeObject(value)) {
+              __ mov(StoreDescriptor::ReceiverRegister(), eax);
+              __ mov(StoreDescriptor::NameRegister(),
+                     Immediate(isolate()->factory()->home_object_symbol()));
+              __ mov(StoreDescriptor::ValueRegister(), Operand(esp, 0));
+              CallStoreIC();
+            }
           } else {
             VisitForEffect(value);
           }
@@ -1667,6 +1661,7 @@
         VisitForStackValue(key);
         VisitForStackValue(value);
         if (property->emit_store()) {
+          EmitSetHomeObjectIfNeeded(value, 2);
           __ push(Immediate(Smi::FromInt(SLOPPY)));  // Strict mode
           __ CallRuntime(Runtime::kSetProperty, 4);
         } else {
@@ -1677,7 +1672,7 @@
         __ push(Operand(esp, 0));  // Duplicate receiver.
         VisitForStackValue(value);
         if (property->emit_store()) {
-          __ CallRuntime(Runtime::kSetPrototype, 2);
+          __ CallRuntime(Runtime::kInternalSetPrototype, 2);
         } else {
           __ Drop(2);
         }
@@ -1699,7 +1694,9 @@
     __ push(Operand(esp, 0));  // Duplicate receiver.
     VisitForStackValue(it->first);
     EmitAccessor(it->second->getter);
+    EmitSetHomeObjectIfNeeded(it->second->getter, 2);
     EmitAccessor(it->second->setter);
+    EmitSetHomeObjectIfNeeded(it->second->setter, 3);
     __ push(Immediate(Smi::FromInt(NONE)));
     __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
   }
@@ -1814,22 +1811,23 @@
 
   Comment cmnt(masm_, "[ Assignment");
 
-  // Left-hand side can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* property = expr->target()->AsProperty();
-  if (property != NULL) {
-    assign_type = (property->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(property);
 
   // Evaluate LHS expression.
   switch (assign_type) {
     case VARIABLE:
       // Nothing to do here.
       break;
+    case NAMED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ push(result_register());
+      if (expr->is_compound()) {
+        __ push(MemOperand(esp, kPointerSize));
+        __ push(result_register());
+      }
+      break;
     case NAMED_PROPERTY:
       if (expr->is_compound()) {
         // We need the receiver both on the stack and in the register.
@@ -1839,6 +1837,18 @@
         VisitForStackValue(property->obj());
       }
       break;
+    case KEYED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForAccumulatorValue(property->key());
+      __ Push(result_register());
+      if (expr->is_compound()) {
+        __ push(MemOperand(esp, 2 * kPointerSize));
+        __ push(MemOperand(esp, 2 * kPointerSize));
+        __ push(result_register());
+      }
+      break;
     case KEYED_PROPERTY: {
       if (expr->is_compound()) {
         VisitForStackValue(property->obj());
@@ -1863,10 +1873,18 @@
           EmitVariableLoad(expr->target()->AsVariableProxy());
           PrepareForBailout(expr->target(), TOS_REG);
           break;
+        case NAMED_SUPER_PROPERTY:
+          EmitNamedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
         case NAMED_PROPERTY:
           EmitNamedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
           break;
+        case KEYED_SUPER_PROPERTY:
+          EmitKeyedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
         case KEYED_PROPERTY:
           EmitKeyedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
@@ -1912,6 +1930,14 @@
     case NAMED_PROPERTY:
       EmitNamedPropertyAssignment(expr);
       break;
+    case NAMED_SUPER_PROPERTY:
+      EmitNamedSuperPropertyStore(property);
+      context()->Plug(result_register());
+      break;
+    case KEYED_SUPER_PROPERTY:
+      EmitKeyedSuperPropertyStore(property);
+      context()->Plug(result_register());
+      break;
     case KEYED_PROPERTY:
       EmitKeyedPropertyAssignment(expr);
       break;
@@ -2044,7 +2070,7 @@
       __ mov(load_receiver, Operand(esp, kPointerSize));
       if (FLAG_vector_ics) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
-               Immediate(Smi::FromInt(expr->KeyedLoadFeedbackSlot())));
+               Immediate(SmiFromSlot(expr->KeyedLoadFeedbackSlot())));
       }
       Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
       CallIC(ic, TypeFeedbackId::None());
@@ -2064,7 +2090,7 @@
              isolate()->factory()->done_string());       // "done"
       if (FLAG_vector_ics) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
-               Immediate(Smi::FromInt(expr->DoneFeedbackSlot())));
+               Immediate(SmiFromSlot(expr->DoneFeedbackSlot())));
       }
       CallLoadIC(NOT_CONTEXTUAL);                        // result.done in eax
       Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
@@ -2078,7 +2104,7 @@
              isolate()->factory()->value_string());       // "value"
       if (FLAG_vector_ics) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
-               Immediate(Smi::FromInt(expr->ValueFeedbackSlot())));
+               Immediate(SmiFromSlot(expr->ValueFeedbackSlot())));
       }
       CallLoadIC(NOT_CONTEXTUAL);                         // result.value in eax
       context()->DropAndPlug(2, eax);                     // drop iter and g
@@ -2099,15 +2125,6 @@
   VisitForAccumulatorValue(value);
   __ pop(ebx);
 
-  // Check generator state.
-  Label wrong_state, closed_state, done;
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
-  __ cmp(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset),
-         Immediate(Smi::FromInt(0)));
-  __ j(equal, &closed_state);
-  __ j(less, &wrong_state);
-
   // Load suspended function and context.
   __ mov(esi, FieldOperand(ebx, JSGeneratorObject::kContextOffset));
   __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
@@ -2129,7 +2146,7 @@
 
   // Enter a new JavaScript frame, and initialize its slots as they were when
   // the generator was suspended.
-  Label resume_frame;
+  Label resume_frame, done;
   __ bind(&push_frame);
   __ call(&resume_frame);
   __ jmp(&done);
@@ -2176,25 +2193,6 @@
   // Not reached: the runtime call returns elsewhere.
   __ Abort(kGeneratorFailedToResume);
 
-  // Reach here when generator is closed.
-  __ bind(&closed_state);
-  if (resume_mode == JSGeneratorObject::NEXT) {
-    // Return completed iterator result when generator is closed.
-    __ push(Immediate(isolate()->factory()->undefined_value()));
-    // Pop value from top-of-stack slot; box result into result register.
-    EmitCreateIteratorResult(true);
-  } else {
-    // Throw the provided value.
-    __ push(eax);
-    __ CallRuntime(Runtime::kThrow, 1);
-  }
-  __ jmp(&done);
-
-  // Throw error if we attempt to operate on a running generator.
-  __ bind(&wrong_state);
-  __ push(ebx);
-  __ CallRuntime(Runtime::kThrowGeneratorStateError, 1);
-
   __ bind(&done);
   context()->Plug(result_register());
 }
@@ -2204,22 +2202,25 @@
   Label gc_required;
   Label allocated;
 
-  Handle<Map> map(isolate()->native_context()->iterator_result_map());
+  const int instance_size = 5 * kPointerSize;
+  DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
+            instance_size);
 
-  __ Allocate(map->instance_size(), eax, ecx, edx, &gc_required, TAG_OBJECT);
+  __ Allocate(instance_size, eax, ecx, edx, &gc_required, TAG_OBJECT);
   __ jmp(&allocated);
 
   __ bind(&gc_required);
-  __ Push(Smi::FromInt(map->instance_size()));
+  __ Push(Smi::FromInt(instance_size));
   __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
   __ mov(context_register(),
          Operand(ebp, StandardFrameConstants::kContextOffset));
 
   __ bind(&allocated);
-  __ mov(ebx, map);
+  __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
+  __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset));
+  __ mov(ebx, ContextOperand(ebx, Context::ITERATOR_RESULT_MAP_INDEX));
   __ pop(ecx);
   __ mov(edx, isolate()->factory()->ToBoolean(done));
-  DCHECK_EQ(map->instance_size(), 5 * kPointerSize);
   __ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
   __ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
          isolate()->factory()->empty_fixed_array());
@@ -2239,10 +2240,12 @@
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
   DCHECK(!key->value()->IsSmi());
+  DCHECK(!prop->IsSuperAccess());
+
   __ mov(LoadDescriptor::NameRegister(), Immediate(key->value()));
   if (FLAG_vector_ics) {
     __ mov(VectorLoadICDescriptor::SlotRegister(),
-           Immediate(Smi::FromInt(prop->PropertyFeedbackSlot())));
+           Immediate(SmiFromSlot(prop->PropertyFeedbackSlot())));
     CallLoadIC(NOT_CONTEXTUAL);
   } else {
     CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
@@ -2251,15 +2254,12 @@
 
 
 void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object.
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
   DCHECK(!key->value()->IsSmi());
   DCHECK(prop->IsSuperAccess());
 
-  SuperReference* super_ref = prop->obj()->AsSuperReference();
-  EmitLoadHomeObject(super_ref);
-  __ push(eax);
-  VisitForStackValue(super_ref->this_var());
   __ push(Immediate(key->value()));
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 }
@@ -2270,7 +2270,7 @@
   Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
   if (FLAG_vector_ics) {
     __ mov(VectorLoadICDescriptor::SlotRegister(),
-           Immediate(Smi::FromInt(prop->PropertyFeedbackSlot())));
+           Immediate(SmiFromSlot(prop->PropertyFeedbackSlot())));
     CallIC(ic);
   } else {
     CallIC(ic, prop->PropertyFeedbackId());
@@ -2278,6 +2278,14 @@
 }
 
 
+void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object, key.
+  SetSourcePosition(prop->position());
+
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+}
+
+
 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
                                               Token::Value op,
                                               OverwriteMode mode,
@@ -2373,6 +2381,61 @@
 }
 
 
+void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
+  // Constructor is in eax.
+  DCHECK(lit != NULL);
+  __ push(eax);
+
+  // No access check is needed here since the constructor is created by the
+  // class literal.
+  Register scratch = ebx;
+  __ mov(scratch, FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset));
+  __ Push(scratch);
+
+  for (int i = 0; i < lit->properties()->length(); i++) {
+    ObjectLiteral::Property* property = lit->properties()->at(i);
+    Literal* key = property->key()->AsLiteral();
+    Expression* value = property->value();
+    DCHECK(key != NULL);
+
+    if (property->is_static()) {
+      __ push(Operand(esp, kPointerSize));  // constructor
+    } else {
+      __ push(Operand(esp, 0));  // prototype
+    }
+    VisitForStackValue(key);
+    VisitForStackValue(value);
+    EmitSetHomeObjectIfNeeded(value, 2);
+
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT:
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+      case ObjectLiteral::Property::COMPUTED:
+      case ObjectLiteral::Property::PROTOTYPE:
+        __ CallRuntime(Runtime::kDefineClassMethod, 3);
+        break;
+
+      case ObjectLiteral::Property::GETTER:
+        __ CallRuntime(Runtime::kDefineClassGetter, 3);
+        break;
+
+      case ObjectLiteral::Property::SETTER:
+        __ CallRuntime(Runtime::kDefineClassSetter, 3);
+        break;
+
+      default:
+        UNREACHABLE();
+    }
+  }
+
+  // prototype
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+
+  // constructor
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+}
+
+
 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
                                      Token::Value op,
                                      OverwriteMode mode) {
@@ -2388,16 +2451,8 @@
 void FullCodeGenerator::EmitAssignment(Expression* expr) {
   DCHECK(expr->IsValidReferenceExpression());
 
-  // Left-hand side can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* prop = expr->AsProperty();
-  if (prop != NULL) {
-    assign_type = (prop->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(prop);
 
   switch (assign_type) {
     case VARIABLE: {
@@ -2416,6 +2471,42 @@
       CallStoreIC();
       break;
     }
+    case NAMED_SUPER_PROPERTY: {
+      __ push(eax);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      // stack: value, this; eax: home_object
+      Register scratch = ecx;
+      Register scratch2 = edx;
+      __ mov(scratch, result_register());               // home_object
+      __ mov(eax, MemOperand(esp, kPointerSize));       // value
+      __ mov(scratch2, MemOperand(esp, 0));             // this
+      __ mov(MemOperand(esp, kPointerSize), scratch2);  // this
+      __ mov(MemOperand(esp, 0), scratch);              // home_object
+      // stack: this, home_object. eax: value
+      EmitNamedSuperPropertyStore(prop);
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      __ push(eax);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      __ push(result_register());
+      VisitForAccumulatorValue(prop->key());
+      Register scratch = ecx;
+      Register scratch2 = edx;
+      __ mov(scratch2, MemOperand(esp, 2 * kPointerSize));  // value
+      // stack: value, this, home_object; eax: key, edx: value
+      __ mov(scratch, MemOperand(esp, kPointerSize));  // this
+      __ mov(MemOperand(esp, 2 * kPointerSize), scratch);
+      __ mov(scratch, MemOperand(esp, 0));  // home_object
+      __ mov(MemOperand(esp, kPointerSize), scratch);
+      __ mov(MemOperand(esp, 0), eax);
+      __ mov(eax, scratch2);
+      // stack: this, home_object, key; eax: value.
+      EmitKeyedSuperPropertyStore(prop);
+      break;
+    }
     case KEYED_PROPERTY: {
       __ push(eax);  // Preserve value.
       VisitForStackValue(prop->obj());
@@ -2484,7 +2575,6 @@
     __ CallRuntime(Runtime::kThrowReferenceError, 1);
     __ bind(&assign);
     EmitStoreToStackLocalOrContextSlot(var, location);
-
   } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
     if (var->IsLookupSlot()) {
       // Assignment to var.
@@ -2506,8 +2596,9 @@
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
+  } else if (IsSignallingAssignmentToConst(var, op, strict_mode())) {
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
   }
-  // Non-initializing assignments to consts are ignored.
 }
 
 
@@ -2530,6 +2621,34 @@
 }
 
 
+void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // eax : value
+  // stack : receiver ('this'), home_object
+  DCHECK(prop != NULL);
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(key != NULL);
+
+  __ push(Immediate(key->value()));
+  __ push(eax);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
+                                          : Runtime::kStoreToSuper_Sloppy),
+                 4);
+}
+
+
+void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // eax : value
+  // stack : receiver ('this'), home_object, key
+
+  __ push(eax);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict
+                                          : Runtime::kStoreKeyedToSuper_Sloppy),
+                 4);
+}
+
+
 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
   // Assignment to a property, using a keyed store IC.
   // eax               : value
@@ -2559,16 +2678,27 @@
       __ Move(LoadDescriptor::ReceiverRegister(), result_register());
       EmitNamedPropertyLoad(expr);
     } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ push(result_register());
       EmitNamedSuperPropertyLoad(expr);
     }
     PrepareForBailoutForId(expr->LoadId(), TOS_REG);
     context()->Plug(eax);
   } else {
-    VisitForStackValue(expr->obj());
-    VisitForAccumulatorValue(expr->key());
-    __ pop(LoadDescriptor::ReceiverRegister());                  // Object.
-    __ Move(LoadDescriptor::NameRegister(), result_register());  // Key.
-    EmitKeyedPropertyLoad(expr);
+    if (!expr->IsSuperAccess()) {
+      VisitForStackValue(expr->obj());
+      VisitForAccumulatorValue(expr->key());
+      __ pop(LoadDescriptor::ReceiverRegister());                  // Object.
+      __ Move(LoadDescriptor::NameRegister(), result_register());  // Key.
+      EmitKeyedPropertyLoad(expr);
+    } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ push(result_register());
+      VisitForStackValue(expr->key());
+      EmitKeyedSuperPropertyLoad(expr);
+    }
     context()->Plug(eax);
   }
 }
@@ -2627,14 +2757,14 @@
   __ push(eax);
   VisitForAccumulatorValue(super_ref->this_var());
   __ push(eax);
-  __ push(Operand(esp, kPointerSize));
   __ push(eax);
+  __ push(Operand(esp, kPointerSize * 2));
   __ push(Immediate(key->value()));
   // Stack here:
   //  - home_object
   //  - this (receiver)
-  //  - home_object <-- LoadFromSuper will pop here and below.
-  //  - this (receiver)
+  //  - this (receiver) <-- LoadFromSuper will pop here and below.
+  //  - home_object
   //  - key
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 
@@ -2671,6 +2801,40 @@
 }
 
 
+void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
+  Expression* callee = expr->expression();
+  DCHECK(callee->IsProperty());
+  Property* prop = callee->AsProperty();
+  DCHECK(prop->IsSuperAccess());
+
+  SetSourcePosition(prop->position());
+  // Load the function from the receiver.
+  SuperReference* super_ref = callee->AsProperty()->obj()->AsSuperReference();
+  EmitLoadHomeObject(super_ref);
+  __ push(eax);
+  VisitForAccumulatorValue(super_ref->this_var());
+  __ push(eax);
+  __ push(eax);
+  __ push(Operand(esp, kPointerSize * 2));
+  VisitForStackValue(prop->key());
+  // Stack here:
+  //  - home_object
+  //  - this (receiver)
+  //  - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
+  //  - home_object
+  //  - key
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+
+  // Replace home_object with target function.
+  __ mov(Operand(esp, kPointerSize), eax);
+
+  // Stack here:
+  // - target function
+  // - this (receiver)
+  EmitCall(expr, CallICState::METHOD);
+}
+
+
 void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
   // Load the arguments.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2685,7 +2849,7 @@
   SetSourcePosition(expr->position());
   Handle<Code> ic = CallIC::initialize_stub(
       isolate(), arg_count, call_type);
-  __ Move(edx, Immediate(Smi::FromInt(expr->CallFeedbackSlot())));
+  __ Move(edx, Immediate(SmiFromSlot(expr->CallFeedbackSlot())));
   __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
   // Don't assign a type feedback id to the IC, since type feedback is provided
   // by the vector above.
@@ -2723,6 +2887,13 @@
 }
 
 
+void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
+  DCHECK(super_ref != NULL);
+  __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+  __ CallRuntime(Runtime::kGetPrototype, 1);
+}
+
+
 void FullCodeGenerator::VisitCall(Call* expr) {
 #ifdef DEBUG
   // We want to verify that RecordJSReturnSite gets called on all paths
@@ -2758,6 +2929,8 @@
       // edx (receiver). Touch up the stack with the right values.
       __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
       __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
+
+      PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
     }
     // Record source position for debugger.
     SetSourcePosition(expr->position());
@@ -2789,6 +2962,7 @@
     __ CallRuntime(Runtime::kLoadLookupSlot, 2);
     __ push(eax);  // Function.
     __ push(edx);  // Receiver.
+    PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
 
     // If fast case code has been generated, emit code to push the function
     // and receiver and have the slow path jump around this code.
@@ -2811,9 +2985,12 @@
   } else if (call_type == Call::PROPERTY_CALL) {
     Property* property = callee->AsProperty();
     bool is_named_call = property->key()->IsPropertyName();
-    // super.x() is handled in EmitCallWithLoadIC.
-    if (property->IsSuperAccess() && is_named_call) {
-      EmitSuperCallWithLoadIC(expr);
+    if (property->IsSuperAccess()) {
+      if (is_named_call) {
+        EmitSuperCallWithLoadIC(expr);
+      } else {
+        EmitKeyedSuperCallWithLoadIC(expr);
+      }
     } else {
       {
         PreservePositionScope scope(masm()->positions_recorder());
@@ -2825,6 +3002,12 @@
         EmitKeyedCallWithLoadIC(expr, property->key());
       }
     }
+  } else if (call_type == Call::SUPER_CALL) {
+    SuperReference* super_ref = callee->AsSuperReference();
+    EmitLoadSuperConstructor(super_ref);
+    __ push(result_register());
+    VisitForStackValue(super_ref->this_var());
+    EmitCall(expr, CallICState::METHOD);
   } else {
     DCHECK(call_type == Call::OTHER_CALL);
     // Call to an arbitrary expression not handled specially above.
@@ -2852,7 +3035,12 @@
   // Push constructor on the stack.  If it's not a function it's used as
   // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
   // ignored.
-  VisitForStackValue(expr->expression());
+  if (expr->expression()->IsSuperReference()) {
+    EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
+    __ push(result_register());
+  } else {
+    VisitForStackValue(expr->expression());
+  }
 
   // Push the arguments ("left-to-right") on the stack.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2872,12 +3060,12 @@
   // Record call targets in unoptimized code.
   if (FLAG_pretenuring_call_new) {
     EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
-    DCHECK(expr->AllocationSiteFeedbackSlot() ==
-           expr->CallNewFeedbackSlot() + 1);
+    DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
+           expr->CallNewFeedbackSlot().ToInt() + 1);
   }
 
   __ LoadHeapObject(ebx, FeedbackVector());
-  __ mov(edx, Immediate(Smi::FromInt(expr->CallNewFeedbackSlot())));
+  __ mov(edx, Immediate(SmiFromSlot(expr->CallNewFeedbackSlot())));
 
   CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
   __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
@@ -3191,6 +3379,31 @@
 }
 
 
+void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ JumpIfSmi(eax, if_false);
+  Register map = ebx;
+  __ mov(map, FieldOperand(eax, HeapObject::kMapOffset));
+  __ CmpInstanceType(map, FIRST_JS_PROXY_TYPE);
+  __ j(less, if_false);
+  __ CmpInstanceType(map, LAST_JS_PROXY_TYPE);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(less_equal, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
 
 void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
   DCHECK(expr->arguments()->length() == 0);
@@ -4129,7 +4342,7 @@
     __ mov(LoadDescriptor::NameRegister(), Immediate(expr->name()));
     if (FLAG_vector_ics) {
       __ mov(VectorLoadICDescriptor::SlotRegister(),
-             Immediate(Smi::FromInt(expr->CallRuntimeFeedbackSlot())));
+             Immediate(SmiFromSlot(expr->CallRuntimeFeedbackSlot())));
       CallLoadIC(NOT_CONTEXTUAL);
     } else {
       CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
@@ -4290,17 +4503,8 @@
   Comment cmnt(masm_, "[ CountOperation");
   SetSourcePosition(expr->position());
 
-  // Expression can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* prop = expr->expression()->AsProperty();
-  // In case of a property we use the uninitialized expression context
-  // of the key to detect a named property.
-  if (prop != NULL) {
-    assign_type =
-        (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(prop);
 
   // Evaluate expression and get value.
   if (assign_type == VARIABLE) {
@@ -4312,18 +4516,50 @@
     if (expr->is_postfix() && !context()->IsEffect()) {
       __ push(Immediate(Smi::FromInt(0)));
     }
-    if (assign_type == NAMED_PROPERTY) {
-      // Put the object both on the stack and in the register.
-      VisitForStackValue(prop->obj());
-      __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
-      EmitNamedPropertyLoad(prop);
-    } else {
-      VisitForStackValue(prop->obj());
-      VisitForStackValue(prop->key());
-      __ mov(LoadDescriptor::ReceiverRegister(),
-             Operand(esp, kPointerSize));                       // Object.
-      __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0));  // Key.
-      EmitKeyedPropertyLoad(prop);
+    switch (assign_type) {
+      case NAMED_PROPERTY: {
+        // Put the object both on the stack and in the register.
+        VisitForStackValue(prop->obj());
+        __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
+        EmitNamedPropertyLoad(prop);
+        break;
+      }
+
+      case NAMED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        __ push(result_register());
+        __ push(MemOperand(esp, kPointerSize));
+        __ push(result_register());
+        EmitNamedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        __ push(result_register());
+        VisitForAccumulatorValue(prop->key());
+        __ push(result_register());
+        __ push(MemOperand(esp, 2 * kPointerSize));
+        __ push(MemOperand(esp, 2 * kPointerSize));
+        __ push(result_register());
+        EmitKeyedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_PROPERTY: {
+        VisitForStackValue(prop->obj());
+        VisitForStackValue(prop->key());
+        __ mov(LoadDescriptor::ReceiverRegister(),
+               Operand(esp, kPointerSize));                       // Object.
+        __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0));  // Key.
+        EmitKeyedPropertyLoad(prop);
+        break;
+      }
+
+      case VARIABLE:
+        UNREACHABLE();
     }
   }
 
@@ -4355,9 +4591,15 @@
           case NAMED_PROPERTY:
             __ mov(Operand(esp, kPointerSize), eax);
             break;
+          case NAMED_SUPER_PROPERTY:
+            __ mov(Operand(esp, 2 * kPointerSize), eax);
+            break;
           case KEYED_PROPERTY:
             __ mov(Operand(esp, 2 * kPointerSize), eax);
             break;
+          case KEYED_SUPER_PROPERTY:
+            __ mov(Operand(esp, 3 * kPointerSize), eax);
+            break;
         }
       }
     }
@@ -4393,9 +4635,15 @@
         case NAMED_PROPERTY:
           __ mov(Operand(esp, kPointerSize), eax);
           break;
+        case NAMED_SUPER_PROPERTY:
+          __ mov(Operand(esp, 2 * kPointerSize), eax);
+          break;
         case KEYED_PROPERTY:
           __ mov(Operand(esp, 2 * kPointerSize), eax);
           break;
+        case KEYED_SUPER_PROPERTY:
+          __ mov(Operand(esp, 3 * kPointerSize), eax);
+          break;
       }
     }
   }
@@ -4452,6 +4700,28 @@
       }
       break;
     }
+    case NAMED_SUPER_PROPERTY: {
+      EmitNamedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(eax);
+      }
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      EmitKeyedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(eax);
+      }
+      break;
+    }
     case KEYED_PROPERTY: {
       __ pop(StoreDescriptor::NameRegister());
       __ pop(StoreDescriptor::ReceiverRegister());
@@ -4484,7 +4754,7 @@
     __ mov(LoadDescriptor::NameRegister(), Immediate(proxy->name()));
     if (FLAG_vector_ics) {
       __ mov(VectorLoadICDescriptor::SlotRegister(),
-             Immediate(Smi::FromInt(proxy->VariableFeedbackSlot())));
+             Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
     }
     // Use a regular load, not a contextual load, to avoid a reference
     // error.
@@ -4719,7 +4989,7 @@
 
 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
   Scope* declaration_scope = scope()->DeclarationScope();
-  if (declaration_scope->is_global_scope() ||
+  if (declaration_scope->is_script_scope() ||
       declaration_scope->is_module_scope()) {
     // Contexts nested in the native context have a canonical empty function
     // as their closure, not the anonymous closure containing the global
diff --git a/src/ia32/interface-descriptors-ia32.cc b/src/ia32/interface-descriptors-ia32.cc
index 3a0d526..6c77ef8 100644
--- a/src/ia32/interface-descriptors-ia32.cc
+++ b/src/ia32/interface-descriptors-ia32.cc
@@ -29,6 +29,9 @@
 const Register StoreDescriptor::ValueRegister() { return eax; }
 
 
+const Register StoreTransitionDescriptor::MapRegister() { return ebx; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() {
   return ebx;
 }
@@ -152,6 +155,15 @@
 }
 
 
+void AllocateHeapNumberDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // register state
+  // esi -- context
+  Register registers[] = {esi};
+  data->Initialize(arraysize(registers), registers, nullptr);
+}
+
+
 void ArrayConstructorConstantArgCountDescriptor::Initialize(
     CallInterfaceDescriptorData* data) {
   // register state
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 1d7c8c1..03a0d8a 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -31,9 +31,9 @@
         deopt_mode_(mode) {}
   virtual ~SafepointGenerator() {}
 
-  virtual void BeforeCall(int call_size) const OVERRIDE {}
+  void BeforeCall(int call_size) const OVERRIDE {}
 
-  virtual void AfterCall() const OVERRIDE {
+  void AfterCall() const OVERRIDE {
     codegen_->RecordSafepoint(pointers_, deopt_mode_);
   }
 
@@ -2627,10 +2627,10 @@
     DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
                                   LInstanceOfKnownGlobal* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
     Label* map_check() { return &map_check_; }
    private:
     LInstanceOfKnownGlobal* instr_;
@@ -2753,6 +2753,7 @@
     }
     __ Ret((parameter_count + extra_value_count) * kPointerSize, ecx);
   } else {
+    DCHECK(info()->IsStub());  // Functions would need to drop one more value.
     Register reg = ToRegister(instr->parameter_count());
     // The argument count parameter is a smi
     __ SmiUntag(reg);
@@ -2770,6 +2771,7 @@
     if (dynamic_frame_alignment) {
       __ inc(reg);  // 1 more for alignment
     }
+
     __ shl(reg, kPointerSizeLog2);
     __ add(esp, reg);
     __ jmp(return_addr_reg);
@@ -2828,13 +2830,18 @@
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
-  Register vector = ToRegister(instr->temp_vector());
-  DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
-  __ mov(vector, instr->hydrogen()->feedback_vector());
+  Register vector_register = ToRegister(instr->temp_vector());
+  Register slot_register = VectorLoadICDescriptor::SlotRegister();
+  DCHECK(vector_register.is(VectorLoadICDescriptor::VectorRegister()));
+  DCHECK(slot_register.is(eax));
+
+  AllowDeferredHandleDereference vector_structure_check;
+  Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+  __ mov(vector_register, vector);
   // No need to allocate this register.
-  DCHECK(VectorLoadICDescriptor::SlotRegister().is(eax));
-  __ mov(VectorLoadICDescriptor::SlotRegister(),
-         Immediate(Smi::FromInt(instr->hydrogen()->slot())));
+  FeedbackVectorICSlot slot = instr->hydrogen()->slot();
+  int index = vector->GetIndex(slot);
+  __ mov(slot_register, Immediate(Smi::FromInt(index)));
 }
 
 
@@ -2849,7 +2856,7 @@
     EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
   }
   ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), mode).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -2985,7 +2992,8 @@
   if (FLAG_vector_ics) {
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic =
+      CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3211,7 +3219,7 @@
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
+  Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3447,45 +3455,81 @@
   Register name = ToRegister(instr->name());
   DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
   DCHECK(name.is(LoadDescriptor::NameRegister()));
+  Register slot = FLAG_vector_ics ? ToRegister(instr->slot()) : no_reg;
+  Register vector = FLAG_vector_ics ? ToRegister(instr->vector()) : no_reg;
 
   Register scratch = ebx;
-  Register extra = eax;
+  Register extra = edi;
+  DCHECK(!extra.is(slot) && !extra.is(vector));
   DCHECK(!scratch.is(receiver) && !scratch.is(name));
   DCHECK(!extra.is(receiver) && !extra.is(name));
 
   // Important for the tail-call.
   bool must_teardown_frame = NeedsEagerFrame();
 
-  // The probe will tail call to a handler if found.
-  isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
-                                         must_teardown_frame, receiver, name,
-                                         scratch, extra);
+  if (!instr->hydrogen()->is_just_miss()) {
+    if (FLAG_vector_ics) {
+      __ push(slot);
+      __ push(vector);
+    }
+
+    // The probe will tail call to a handler if found.
+    // If --vector-ics is on, then it knows to pop the two args first.
+    DCHECK(!instr->hydrogen()->is_keyed_load());
+    isolate()->stub_cache()->GenerateProbe(
+        masm(), Code::LOAD_IC, instr->hydrogen()->flags(), must_teardown_frame,
+        receiver, name, scratch, extra);
+
+    if (FLAG_vector_ics) {
+      __ pop(vector);
+      __ pop(slot);
+    }
+  }
 
   // Tail call to miss if we ended up here.
   if (must_teardown_frame) __ leave();
-  LoadIC::GenerateMiss(masm());
+  if (instr->hydrogen()->is_keyed_load()) {
+    KeyedLoadIC::GenerateMiss(masm());
+  } else {
+    LoadIC::GenerateMiss(masm());
+  }
 }
 
 
 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
   DCHECK(ToRegister(instr->result()).is(eax));
 
-  LPointerMap* pointers = instr->pointer_map();
-  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+  if (instr->hydrogen()->IsTailCall()) {
+    if (NeedsEagerFrame()) __ leave();
 
-  if (instr->target()->IsConstantOperand()) {
-    LConstantOperand* target = LConstantOperand::cast(instr->target());
-    Handle<Code> code = Handle<Code>::cast(ToHandle(target));
-    generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
-    __ call(code, RelocInfo::CODE_TARGET);
+    if (instr->target()->IsConstantOperand()) {
+      LConstantOperand* target = LConstantOperand::cast(instr->target());
+      Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+      __ jmp(code, RelocInfo::CODE_TARGET);
+    } else {
+      DCHECK(instr->target()->IsRegister());
+      Register target = ToRegister(instr->target());
+      __ add(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
+      __ jmp(target);
+    }
   } else {
-    DCHECK(instr->target()->IsRegister());
-    Register target = ToRegister(instr->target());
-    generator.BeforeCall(__ CallSize(Operand(target)));
-    __ add(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
-    __ call(target);
+    LPointerMap* pointers = instr->pointer_map();
+    SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+
+    if (instr->target()->IsConstantOperand()) {
+      LConstantOperand* target = LConstantOperand::cast(instr->target());
+      Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+      generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
+      __ call(code, RelocInfo::CODE_TARGET);
+    } else {
+      DCHECK(instr->target()->IsRegister());
+      Register target = ToRegister(instr->target());
+      generator.BeforeCall(__ CallSize(Operand(target)));
+      __ add(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
+      __ call(target);
+    }
+    generator.AfterCall();
   }
-  generator.AfterCall();
 }
 
 
@@ -3581,10 +3625,11 @@
     DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
                                     LMathAbs* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LMathAbs* instr_;
   };
@@ -4335,10 +4380,9 @@
     DeferredStringCharCodeAt(LCodeGen* codegen,
                              LStringCharCodeAt* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredStringCharCodeAt(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredStringCharCodeAt(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStringCharCodeAt* instr_;
   };
@@ -4393,10 +4437,11 @@
     DeferredStringCharFromCode(LCodeGen* codegen,
                                LStringCharFromCode* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredStringCharFromCode(instr_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStringCharFromCode* instr_;
   };
@@ -4471,11 +4516,12 @@
     DeferredNumberTagI(LCodeGen* codegen,
                        LNumberTagI* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredNumberTagIU(
           instr_, instr_->value(), instr_->temp(), SIGNED_INT32);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagI* instr_;
   };
@@ -4497,11 +4543,12 @@
    public:
     DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredNumberTagIU(
           instr_, instr_->value(), instr_->temp(), UNSIGNED_INT32);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagU* instr_;
   };
@@ -4579,10 +4626,9 @@
    public:
     DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredNumberTagD(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredNumberTagD(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagD* instr_;
   };
@@ -4779,10 +4825,9 @@
    public:
     DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredTaggedToI(instr_, done());
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredTaggedToI(instr_, done()); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LTaggedToI* instr_;
   };
@@ -4983,11 +5028,12 @@
         : LDeferredCode(codegen), instr_(instr), object_(object) {
       SetExit(check_maps());
     }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredInstanceMigration(instr_, object_);
     }
     Label* check_maps() { return &check_maps_; }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LCheckMaps* instr_;
     Label check_maps_;
@@ -5124,10 +5170,9 @@
    public:
     DeferredAllocate(LCodeGen* codegen,  LAllocate* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredAllocate(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredAllocate(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LAllocate* instr_;
   };
@@ -5490,10 +5535,9 @@
    public:
     DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredStackCheck(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredStackCheck(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStackCheck* instr_;
   };
@@ -5640,10 +5684,11 @@
           object_(object),
           index_(index) {
     }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredLoadMutableDouble(instr_, object_, index_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LLoadFieldByIndex* instr_;
     Register object_;
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 3ed6623..3be2fc4 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <sstream>
+
 #include "src/v8.h"
 
 #if V8_TARGET_ARCH_IA32
@@ -365,9 +367,9 @@
 
 void LStoreNamedField::PrintDataTo(StringStream* stream) {
   object()->PrintTo(stream);
-  OStringStream os;
+  std::ostringstream os;
   os << hydrogen()->access() << " <- ";
-  stream->Add(os.c_str());
+  stream->Add(os.str().c_str());
   value()->PrintTo(stream);
 }
 
@@ -737,11 +739,7 @@
     // Shift operations can only deoptimize if we do a logical shift by 0 and
     // the result cannot be truncated to int32.
     if (op == Token::SHR && constant_value == 0) {
-      if (FLAG_opt_safe_uint32_operations) {
-        does_deopt = !instr->CheckFlag(HInstruction::kUint32);
-      } else {
-        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32);
-      }
+      does_deopt = !instr->CheckFlag(HInstruction::kUint32);
     }
 
     LInstruction* result =
@@ -1140,9 +1138,17 @@
       UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
   LOperand* name_register =
       UseFixed(instr->name(), LoadDescriptor::NameRegister());
+  LOperand* slot = NULL;
+  LOperand* vector = NULL;
+  if (FLAG_vector_ics) {
+    slot = UseFixed(instr->slot(), VectorLoadICDescriptor::SlotRegister());
+    vector =
+        UseFixed(instr->vector(), VectorLoadICDescriptor::VectorRegister());
+  }
+
   // Not marked as call. It can't deoptimize, and it never returns.
   return new (zone()) LTailCallThroughMegamorphicCache(
-      context, receiver_register, name_register);
+      context, receiver_register, name_register, slot, vector);
 }
 
 
@@ -2117,7 +2123,7 @@
   LOperand* global_object =
       UseFixed(instr->global_object(), LoadDescriptor::ReceiverRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
 
@@ -2178,7 +2184,7 @@
   LOperand* object =
       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
   LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(
@@ -2243,7 +2249,7 @@
       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
   LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
   LLoadKeyedGeneric* result =
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 75fed82..49eba66 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -167,17 +167,13 @@
   V(WrapReceiver)
 
 
-#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)                        \
-  virtual Opcode opcode() const FINAL OVERRIDE {                      \
-    return LInstruction::k##type;                                           \
-  }                                                                         \
-  virtual void CompileToNative(LCodeGen* generator) FINAL OVERRIDE;   \
-  virtual const char* Mnemonic() const FINAL OVERRIDE {               \
-    return mnemonic;                                                        \
-  }                                                                         \
-  static L##type* cast(LInstruction* instr) {                               \
-    DCHECK(instr->Is##type());                                              \
-    return reinterpret_cast<L##type*>(instr);                               \
+#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)            \
+  Opcode opcode() const FINAL { return LInstruction::k##type; } \
+  void CompileToNative(LCodeGen* generator) FINAL;              \
+  const char* Mnemonic() const FINAL { return mnemonic; }       \
+  static L##type* cast(LInstruction* instr) {                   \
+    DCHECK(instr->Is##type());                                  \
+    return reinterpret_cast<L##type*>(instr);                   \
   }
 
 
@@ -292,11 +288,9 @@
  public:
   // Allow 0 or 1 output operands.
   STATIC_ASSERT(R == 0 || R == 1);
-  virtual bool HasResult() const FINAL OVERRIDE {
-    return R != 0 && result() != NULL;
-  }
+  bool HasResult() const FINAL { return R != 0 && result() != NULL; }
   void set_result(LOperand* operand) { results_[0] = operand; }
-  LOperand* result() const { return results_[0]; }
+  LOperand* result() const OVERRIDE { return results_[0]; }
 
  protected:
   EmbeddedContainer<LOperand*, R> results_;
@@ -314,11 +308,11 @@
 
  private:
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return I; }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return I; }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return T; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return temps_[i]; }
+  int TempCount() FINAL { return T; }
+  LOperand* TempAt(int i) FINAL { return temps_[i]; }
 };
 
 
@@ -332,8 +326,8 @@
   }
 
   // Can't use the DECLARE-macro here because of sub-classes.
-  virtual bool IsGap() const FINAL OVERRIDE { return true; }
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsGap() const FINAL { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   static LGap* cast(LInstruction* instr) {
     DCHECK(instr->IsGap());
     return reinterpret_cast<LGap*>(instr);
@@ -373,7 +367,7 @@
  public:
   explicit LInstructionGap(HBasicBlock* block) : LGap(block) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
     return !IsRedundant();
   }
 
@@ -385,13 +379,13 @@
  public:
   explicit LGoto(HBasicBlock* block) : block_(block) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
   DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
-  virtual bool IsControl() const OVERRIDE { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsControl() const OVERRIDE { return true; }
 
   int block_id() const { return block_->block_id(); }
-  virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
+  bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
     return false;
   }
 
@@ -426,7 +420,7 @@
 
 class LDeoptimize FINAL : public LTemplateInstruction<0, 0, 0> {
  public:
-  virtual bool IsControl() const OVERRIDE { return true; }
+  bool IsControl() const OVERRIDE { return true; }
   DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
   DECLARE_HYDROGEN_ACCESSOR(Deoptimize)
 };
@@ -437,12 +431,10 @@
   explicit LLabel(HBasicBlock* block)
       : LGap(block), replacement_(NULL) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(Label, "label")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int block_id() const { return block()->block_id(); }
   bool is_loop_header() const { return block()->IsLoopHeader(); }
@@ -460,9 +452,7 @@
 
 class LParameter FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter")
 };
 
@@ -481,19 +471,23 @@
 
 
 class LTailCallThroughMegamorphicCache FINAL
-    : public LTemplateInstruction<0, 3, 0> {
+    : public LTemplateInstruction<0, 5, 0> {
  public:
-  explicit LTailCallThroughMegamorphicCache(LOperand* context,
-                                            LOperand* receiver,
-                                            LOperand* name) {
+  LTailCallThroughMegamorphicCache(LOperand* context, LOperand* receiver,
+                                   LOperand* name, LOperand* slot,
+                                   LOperand* vector) {
     inputs_[0] = context;
     inputs_[1] = receiver;
     inputs_[2] = name;
+    inputs_[3] = slot;
+    inputs_[4] = vector;
   }
 
   LOperand* context() { return inputs_[0]; }
   LOperand* receiver() { return inputs_[1]; }
   LOperand* name() { return inputs_[2]; }
+  LOperand* slot() { return inputs_[3]; }
+  LOperand* vector() { return inputs_[4]; }
 
   DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
                                "tail-call-through-megamorphic-cache")
@@ -503,9 +497,7 @@
 
 class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown-osr-value")
 };
 
@@ -515,7 +507,7 @@
  public:
   LControlInstruction() : false_label_(NULL), true_label_(NULL) { }
 
-  virtual bool IsControl() const FINAL OVERRIDE { return true; }
+  bool IsControl() const FINAL { return true; }
 
   int SuccessorCount() { return hydrogen()->SuccessorCount(); }
   HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); }
@@ -608,7 +600,7 @@
 
   DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -857,7 +849,7 @@
     return hydrogen()->representation().IsDouble();
   }
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1038,7 +1030,7 @@
 
   DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1055,7 +1047,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1070,7 +1062,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1088,7 +1080,7 @@
                                "is-undetectable-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1108,7 +1100,7 @@
                                "string-compare-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Token::Value op() const { return hydrogen()->token(); }
 };
@@ -1128,7 +1120,7 @@
                                "has-instance-type-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1157,7 +1149,7 @@
   DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch,
                                "has-cached-array-index-and-branch")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1190,7 +1182,7 @@
                                "class-of-test-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1391,7 +1383,7 @@
   DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
   DECLARE_HYDROGEN_ACCESSOR(Branch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1542,11 +1534,9 @@
 
   Token::Value op() const { return op_; }
 
-  virtual Opcode opcode() const OVERRIDE {
-    return LInstruction::kArithmeticD;
-  }
-  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
-  virtual const char* Mnemonic() const OVERRIDE;
+  Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticD; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
 
  private:
   Token::Value op_;
@@ -1569,11 +1559,9 @@
   LOperand* left() { return inputs_[1]; }
   LOperand* right() { return inputs_[2]; }
 
-  virtual Opcode opcode() const OVERRIDE {
-    return LInstruction::kArithmeticT;
-  }
-  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
-  virtual const char* Mnemonic() const OVERRIDE;
+  Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticT; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
 
   Token::Value op() const { return op_; }
 
@@ -1686,7 +1674,7 @@
   DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
   DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   uint32_t base_offset() const { return hydrogen()->base_offset(); }
   bool key_is_smi() {
     return hydrogen()->key()->representation().IsTagged();
@@ -1784,7 +1772,7 @@
 
   int slot_index() { return hydrogen()->slot_index(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1805,7 +1793,7 @@
 
   int slot_index() { return hydrogen()->slot_index(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1844,7 +1832,7 @@
   LOperand* function() { return inputs_[0]; }
   LOperand* code_object() { return inputs_[1]; }
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry, "store-code-entry")
   DECLARE_HYDROGEN_ACCESSOR(StoreCodeEntry)
@@ -1861,7 +1849,7 @@
   LOperand* base_object() const { return inputs_[0]; }
   LOperand* offset() const { return inputs_[1]; }
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object")
 };
@@ -1905,7 +1893,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallJSFunction, "call-js-function")
   DECLARE_HYDROGEN_ACCESSOR(CallJSFunction)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1927,18 +1915,18 @@
  private:
   DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 
   ZoneList<LOperand*> inputs_;
 
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return inputs_.length(); }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return inputs_.length(); }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return 0; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return NULL; }
+  int TempCount() FINAL { return 0; }
+  LOperand* TempAt(int i) FINAL { return NULL; }
 };
 
 
@@ -1955,7 +1943,7 @@
   DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function")
   DECLARE_HYDROGEN_ACCESSOR(InvokeFunction)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1991,7 +1979,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
   DECLARE_HYDROGEN_ACCESSOR(CallNew)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -2010,7 +1998,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
   DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -2027,7 +2015,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
   DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
 
-  virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
+  bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
     return save_doubles() == kDontSaveFPRegs;
   }
 
@@ -2219,7 +2207,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
   DECLARE_HYDROGEN_ACCESSOR(StoreNamedField)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -2238,7 +2226,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
   DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   Handle<Object> name() const { return hydrogen()->name(); }
   StrictMode strict_mode() { return hydrogen()->strict_mode(); }
 };
@@ -2269,7 +2257,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed")
   DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   uint32_t base_offset() const { return hydrogen()->base_offset(); }
   bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
 };
@@ -2295,7 +2283,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
   DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   StrictMode strict_mode() { return hydrogen()->strict_mode(); }
 };
@@ -2322,7 +2310,7 @@
                                "transition-elements-kind")
   DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Handle<Map> original_map() { return hydrogen()->original_map().handle(); }
   Handle<Map> transitioned_map() {
@@ -2612,15 +2600,13 @@
 
   Handle<String> type_literal() { return hydrogen()->type_literal(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
 class LOsrEntry FINAL : public LTemplateInstruction<0, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry")
 };
 
@@ -2829,7 +2815,7 @@
 
   // An input operand in register, stack slot or a constant operand.
   // Will not be moved to a register even if one is freely available.
-  virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE;
+  MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE;
 
   // Temporary operand that must be in a register.
   MUST_USE_RESULT LUnallocated* TempRegister();
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 7480a6f..38259d7 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -13,7 +13,7 @@
 #include "src/cpu-profiler.h"
 #include "src/debug.h"
 #include "src/isolate-inl.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 #include "src/serialize.h"
 
 namespace v8 {
@@ -345,12 +345,10 @@
 }
 
 
-void MacroAssembler::LoadUint32(XMMRegister dst,
-                                Register src) {
+void MacroAssembler::LoadUint32(XMMRegister dst, const Operand& src) {
   Label done;
   cmp(src, Immediate(0));
-  ExternalReference uint32_bias =
-        ExternalReference::address_of_uint32_bias();
+  ExternalReference uint32_bias = ExternalReference::address_of_uint32_bias();
   Cvtsi2sd(dst, src);
   j(not_sign, &done, Label::kNear);
   addsd(dst, Operand::StaticVariable(uint32_bias));
@@ -742,16 +740,16 @@
 }
 
 
-void MacroAssembler::DispatchMap(Register obj,
-                                 Register unused,
-                                 Handle<Map> map,
-                                 Handle<Code> success,
-                                 SmiCheckType smi_check_type) {
+void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
+                                     Register scratch2, Handle<WeakCell> cell,
+                                     Handle<Code> success,
+                                     SmiCheckType smi_check_type) {
   Label fail;
   if (smi_check_type == DO_SMI_CHECK) {
     JumpIfSmi(obj, &fail);
   }
-  cmp(FieldOperand(obj, HeapObject::kMapOffset), Immediate(map));
+  mov(scratch1, FieldOperand(obj, HeapObject::kMapOffset));
+  CmpWeakValue(scratch1, cell, scratch2);
   j(equal, success);
 
   bind(&fail);
@@ -898,6 +896,13 @@
 }
 
 
+void MacroAssembler::EnterFrame(StackFrame::Type type,
+                                bool load_constant_pool_pointer_reg) {
+  // Out-of-line constant pool not implemented on ia32.
+  UNREACHABLE();
+}
+
+
 void MacroAssembler::EnterFrame(StackFrame::Type type) {
   push(ebp);
   mov(ebp, esp);
@@ -937,8 +942,10 @@
   // Save the frame pointer and the context in top.
   ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate());
   ExternalReference context_address(Isolate::kContextAddress, isolate());
+  ExternalReference c_function_address(Isolate::kCFunctionAddress, isolate());
   mov(Operand::StaticVariable(c_entry_fp_address), ebp);
   mov(Operand::StaticVariable(context_address), esi);
+  mov(Operand::StaticVariable(c_function_address), ebx);
 }
 
 
@@ -1349,10 +1356,10 @@
   }
 
   bind(&done);
-  // Check that the value is a normal propety.
+  // Check that the value is a field property.
   const int kDetailsOffset =
       SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
-  DCHECK_EQ(NORMAL, 0);
+  DCHECK_EQ(FIELD, 0);
   test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
        Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
   j(not_zero, miss);
@@ -2573,6 +2580,21 @@
 }
 
 
+void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
+                                  Register scratch) {
+  mov(scratch, cell);
+  cmp(value, FieldOperand(scratch, WeakCell::kValueOffset));
+}
+
+
+void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
+                                   Label* miss) {
+  mov(value, cell);
+  mov(value, FieldOperand(value, WeakCell::kValueOffset));
+  JumpIfSmi(value, miss);
+}
+
+
 void MacroAssembler::Ret() {
   ret(0);
 }
@@ -2618,18 +2640,65 @@
 }
 
 
-void MacroAssembler::Move(XMMRegister dst, double val) {
-  // TODO(titzer): recognize double constants with ExternalReferences.
-  uint64_t int_val = bit_cast<uint64_t, double>(val);
-  if (int_val == 0) {
-    xorps(dst, dst);
+void MacroAssembler::Move(XMMRegister dst, uint32_t src) {
+  if (src == 0) {
+    pxor(dst, dst);
   } else {
-    int32_t lower = static_cast<int32_t>(int_val);
-    int32_t upper = static_cast<int32_t>(int_val >> kBitsPerInt);
-    push(Immediate(upper));
-    push(Immediate(lower));
-    movsd(dst, Operand(esp, 0));
-    add(esp, Immediate(kDoubleSize));
+    unsigned cnt = base::bits::CountPopulation32(src);
+    unsigned nlz = base::bits::CountLeadingZeros32(src);
+    unsigned ntz = base::bits::CountTrailingZeros32(src);
+    if (nlz + cnt + ntz == 32) {
+      pcmpeqd(dst, dst);
+      if (ntz == 0) {
+        psrld(dst, 32 - cnt);
+      } else {
+        pslld(dst, 32 - cnt);
+        if (nlz != 0) psrld(dst, nlz);
+      }
+    } else {
+      push(eax);
+      mov(eax, Immediate(src));
+      movd(dst, Operand(eax));
+      pop(eax);
+    }
+  }
+}
+
+
+void MacroAssembler::Move(XMMRegister dst, uint64_t src) {
+  uint32_t lower = static_cast<uint32_t>(src);
+  uint32_t upper = static_cast<uint32_t>(src >> 32);
+  if (upper == 0) {
+    Move(dst, lower);
+  } else {
+    unsigned cnt = base::bits::CountPopulation64(src);
+    unsigned nlz = base::bits::CountLeadingZeros64(src);
+    unsigned ntz = base::bits::CountTrailingZeros64(src);
+    if (nlz + cnt + ntz == 64) {
+      pcmpeqd(dst, dst);
+      if (ntz == 0) {
+        psrlq(dst, 64 - cnt);
+      } else {
+        psllq(dst, 64 - cnt);
+        if (nlz != 0) psrlq(dst, nlz);
+      }
+    } else if (lower == 0) {
+      Move(dst, upper);
+      psllq(dst, 32);
+    } else if (CpuFeatures::IsSupported(SSE4_1)) {
+      CpuFeatureScope scope(this, SSE4_1);
+      push(eax);
+      Move(eax, Immediate(lower));
+      movd(dst, Operand(eax));
+      Move(eax, Immediate(upper));
+      pinsrd(dst, Operand(eax), 1);
+      pop(eax);
+    } else {
+      push(Immediate(upper));
+      push(Immediate(lower));
+      movsd(dst, Operand(esp, 0));
+      add(esp, Immediate(kDoubleSize));
+    }
   }
 }
 
@@ -3103,18 +3172,6 @@
 }
 
 
-void MacroAssembler::CheckMapDeprecated(Handle<Map> map,
-                                        Register scratch,
-                                        Label* if_deprecated) {
-  if (map->CanBeDeprecated()) {
-    mov(scratch, map);
-    mov(scratch, FieldOperand(scratch, Map::kBitField3Offset));
-    and_(scratch, Immediate(Map::Deprecated::kMask));
-    j(not_zero, if_deprecated);
-  }
-}
-
-
 void MacroAssembler::JumpIfBlack(Register object,
                                  Register scratch0,
                                  Register scratch1,
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index 81347e5..83f6216 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -94,10 +94,6 @@
       Label* condition_met,
       Label::Distance condition_met_distance = Label::kFar);
 
-  void CheckMapDeprecated(Handle<Map> map,
-                          Register scratch,
-                          Label* if_deprecated);
-
   // Check if object is in new space.  Jumps if the object is not in new space.
   // The register scratch can be object itself, but scratch will be clobbered.
   void JumpIfNotInNewSpace(Register object,
@@ -299,6 +295,13 @@
     }
   }
 
+  // Compare the given value and the value of weak cell.
+  void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
+
+  // Load the value of the weak cell in the value register. Branch to the given
+  // miss label if the weak cell was cleared.
+  void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
+
   // ---------------------------------------------------------------------------
   // JavaScript invokes
 
@@ -408,14 +411,12 @@
                 Label* fail,
                 SmiCheckType smi_check_type);
 
-  // Check if the map of an object is equal to a specified map and branch to a
-  // specified target if equal. Skip the smi check if not required (object is
-  // known to be a heap object)
-  void DispatchMap(Register obj,
-                   Register unused,
-                   Handle<Map> map,
-                   Handle<Code> success,
-                   SmiCheckType smi_check_type);
+  // Check if the map of an object is equal to a specified weak map and branch
+  // to a specified target if equal. Skip the smi check if not required
+  // (object is known to be a heap object)
+  void DispatchWeakMap(Register obj, Register scratch1, Register scratch2,
+                       Handle<WeakCell> cell, Handle<Code> success,
+                       SmiCheckType smi_check_type);
 
   // Check if the object in register heap_object is a string. Afterwards the
   // register map contains the object map and the register instance_type
@@ -486,7 +487,10 @@
     j(not_carry, is_smi);
   }
 
-  void LoadUint32(XMMRegister dst, Register src);
+  void LoadUint32(XMMRegister dst, Register src) {
+    LoadUint32(dst, Operand(src));
+  }
+  void LoadUint32(XMMRegister dst, const Operand& src);
 
   // Jump the register contains a smi.
   inline void JumpIfSmi(Register value,
@@ -839,7 +843,9 @@
   void Move(const Operand& dst, const Immediate& x);
 
   // Move an immediate into an XMM register.
-  void Move(XMMRegister dst, double val);
+  void Move(XMMRegister dst, uint32_t src);
+  void Move(XMMRegister dst, uint64_t src);
+  void Move(XMMRegister dst, double src) { Move(dst, bit_cast<uint64_t>(src)); }
 
   // Push a handle value.
   void Push(Handle<Object> handle) { push(Immediate(handle)); }
@@ -936,6 +942,7 @@
 
   // Activation support.
   void EnterFrame(StackFrame::Type type);
+  void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
   void LeaveFrame(StackFrame::Type type);
 
   // Expects object in eax and returns map with validated enum cache
diff --git a/src/ic/access-compiler.h b/src/ic/access-compiler.h
index 928b70b..fe4369a 100644
--- a/src/ic/access-compiler.h
+++ b/src/ic/access-compiler.h
@@ -40,7 +40,10 @@
         kind_(kind),
         cache_holder_(cache_holder),
         isolate_(isolate),
-        masm_(isolate, NULL, 256) {}
+        masm_(isolate, NULL, 256) {
+    // TODO(yangguo): remove this once we can serialize IC stubs.
+    masm_.enable_serializer();
+  }
 
   Code::Kind kind() const { return kind_; }
   CacheHolderFlag cache_holder() const { return cache_holder_; }
@@ -51,6 +54,14 @@
 
   Register receiver() const { return registers_[0]; }
   Register name() const { return registers_[1]; }
+  Register slot() const {
+    DCHECK(FLAG_vector_ics);
+    return VectorLoadICDescriptor::SlotRegister();
+  }
+  Register vector() const {
+    DCHECK(FLAG_vector_ics);
+    return VectorLoadICDescriptor::VectorRegister();
+  }
   Register scratch1() const { return registers_[2]; }
   Register scratch2() const { return registers_[3]; }
   Register scratch3() const { return registers_[4]; }
diff --git a/src/ic/arm/handler-compiler-arm.cc b/src/ic/arm/handler-compiler-arm.cc
index 5314d48..9905e4e 100644
--- a/src/ic/arm/handler-compiler-arm.cc
+++ b/src/ic/arm/handler-compiler-arm.cc
@@ -92,6 +92,28 @@
 }
 
 
+void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
+                                                Register slot) {
+  MacroAssembler* masm = this->masm();
+  __ push(vector);
+  __ push(slot);
+}
+
+
+void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
+  MacroAssembler* masm = this->masm();
+  __ pop(slot);
+  __ pop(vector);
+}
+
+
+void PropertyHandlerCompiler::DiscardVectorAndSlot() {
+  MacroAssembler* masm = this->masm();
+  // Remove vector and slot.
+  __ add(sp, sp, Operand(2 * kPointerSize));
+}
+
+
 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
     MacroAssembler* masm, Label* miss_label, Register receiver,
     Handle<Name> name, Register scratch0, Register scratch1) {
@@ -140,26 +162,16 @@
 
 
 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
-    MacroAssembler* masm, int index, Register prototype, Label* miss) {
-  Isolate* isolate = masm->isolate();
-  // Get the global function with the given index.
-  Handle<JSFunction> function(
-      JSFunction::cast(isolate->native_context()->get(index)));
-
-  // Check we're still in the same context.
-  Register scratch = prototype;
+    MacroAssembler* masm, int index, Register result, Label* miss) {
   const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX);
-  __ ldr(scratch, MemOperand(cp, offset));
-  __ ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
-  __ ldr(scratch, MemOperand(scratch, Context::SlotOffset(index)));
-  __ Move(ip, function);
-  __ cmp(ip, scratch);
-  __ b(ne, miss);
-
+  __ ldr(result, MemOperand(cp, offset));
+  __ ldr(result, FieldMemOperand(result, GlobalObject::kNativeContextOffset));
+  __ ldr(result, MemOperand(result, Context::SlotOffset(index)));
   // Load its initial map. The global functions all have initial maps.
-  __ Move(prototype, Handle<Map>(function->initial_map()));
+  __ ldr(result,
+         FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
   // Load the prototype from the initial map.
-  __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
+  __ ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
 }
 
 
@@ -326,183 +338,61 @@
 }
 
 
-// Generate StoreTransition code, value is passed in r0 register.
-// When leaving generated code after success, the receiver_reg and name_reg
-// may be clobbered.  Upon branch to miss_label, the receiver and name
-// registers have their original values.
-void NamedStoreHandlerCompiler::GenerateStoreTransition(
-    Handle<Map> transition, Handle<Name> name, Register receiver_reg,
-    Register storage_reg, Register value_reg, Register scratch1,
-    Register scratch2, Register scratch3, Label* miss_label, Label* slow) {
-  // r0 : value
-  Label exit;
-
-  int descriptor = transition->LastAdded();
-  DescriptorArray* descriptors = transition->instance_descriptors();
-  PropertyDetails details = descriptors->GetDetails(descriptor);
-  Representation representation = details.representation();
-  DCHECK(!representation.IsNone());
-
-  if (details.type() == CONSTANT) {
-    Handle<Object> constant(descriptors->GetValue(descriptor), isolate());
-    __ Move(scratch1, constant);
-    __ cmp(value_reg, scratch1);
-    __ b(ne, miss_label);
-  } else if (representation.IsSmi()) {
-    __ JumpIfNotSmi(value_reg, miss_label);
-  } else if (representation.IsHeapObject()) {
-    __ JumpIfSmi(value_reg, miss_label);
-    HeapType* field_type = descriptors->GetFieldType(descriptor);
-    HeapType::Iterator<Map> it = field_type->Classes();
-    if (!it.Done()) {
-      __ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
-      Label do_store;
-      while (true) {
-        __ CompareMap(scratch1, it.Current(), &do_store);
-        it.Advance();
-        if (it.Done()) {
-          __ b(ne, miss_label);
-          break;
-        }
-        __ b(eq, &do_store);
-      }
-      __ bind(&do_store);
-    }
-  } else if (representation.IsDouble()) {
-    Label do_store, heap_number;
-    __ LoadRoot(scratch3, Heap::kMutableHeapNumberMapRootIndex);
-    __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow,
-                          TAG_RESULT, MUTABLE);
-
-    __ JumpIfNotSmi(value_reg, &heap_number);
-    __ SmiUntag(scratch1, value_reg);
-    __ vmov(s0, scratch1);
-    __ vcvt_f64_s32(d0, s0);
-    __ jmp(&do_store);
-
-    __ bind(&heap_number);
-    __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label,
-                DONT_DO_SMI_CHECK);
-    __ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
-
-    __ bind(&do_store);
-    __ vstr(d0, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
-  }
-
-  // Stub never generated for objects that require access checks.
-  DCHECK(!transition->is_access_check_needed());
-
-  // Perform map transition for the receiver if necessary.
-  if (details.type() == FIELD &&
-      Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) {
-    // The properties must be extended before we can store the value.
-    // We jump to a runtime call that extends the properties array.
-    __ push(receiver_reg);
-    __ mov(r2, Operand(transition));
-    __ Push(r2, r0);
-    __ TailCallExternalReference(
-        ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
-                          isolate()),
-        3, 1);
-    return;
-  }
-
-  // Update the map of the object.
-  __ mov(scratch1, Operand(transition));
-  __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
-
-  // Update the write barrier for the map field.
-  __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2,
-                      kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
-
-  if (details.type() == CONSTANT) {
-    DCHECK(value_reg.is(r0));
-    __ Ret();
-    return;
-  }
-
-  int index = transition->instance_descriptors()->GetFieldIndex(
-      transition->LastAdded());
-
-  // Adjust for the number of properties stored in the object. Even in the
-  // face of a transition we can use the old map here because the size of the
-  // object and the number of in-object properties is not going to change.
-  index -= transition->inobject_properties();
-
-  // TODO(verwaest): Share this code as a code stub.
-  SmiCheck smi_check =
-      representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
-  if (index < 0) {
-    // Set the property straight into the object.
-    int offset = transition->instance_size() + (index * kPointerSize);
-    if (representation.IsDouble()) {
-      __ str(storage_reg, FieldMemOperand(receiver_reg, offset));
-    } else {
-      __ str(value_reg, FieldMemOperand(receiver_reg, offset));
-    }
-
-    if (!representation.IsSmi()) {
-      // Update the write barrier for the array address.
-      if (!representation.IsDouble()) {
-        __ mov(storage_reg, value_reg);
-      }
-      __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1,
-                          kLRHasNotBeenSaved, kDontSaveFPRegs,
-                          EMIT_REMEMBERED_SET, smi_check);
-    }
-  } else {
-    // Write to the properties array.
-    int offset = index * kPointerSize + FixedArray::kHeaderSize;
-    // Get the properties array
-    __ ldr(scratch1,
-           FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
-    if (representation.IsDouble()) {
-      __ str(storage_reg, FieldMemOperand(scratch1, offset));
-    } else {
-      __ str(value_reg, FieldMemOperand(scratch1, offset));
-    }
-
-    if (!representation.IsSmi()) {
-      // Update the write barrier for the array address.
-      if (!representation.IsDouble()) {
-        __ mov(storage_reg, value_reg);
-      }
-      __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg,
-                          kLRHasNotBeenSaved, kDontSaveFPRegs,
-                          EMIT_REMEMBERED_SET, smi_check);
-    }
-  }
-
-  // Return the value (register r0).
-  DCHECK(value_reg.is(r0));
-  __ bind(&exit);
-  __ Ret();
+void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
+  __ mov(this->name(), Operand(name));
 }
 
 
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
-                                                   Register value_reg,
-                                                   Label* miss_label) {
-  DCHECK(lookup->representation().IsHeapObject());
-  __ JumpIfSmi(value_reg, miss_label);
-  HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
-  __ ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset));
-  Label do_store;
-  while (true) {
-    __ CompareMap(scratch1(), it.Current(), &do_store);
-    it.Advance();
-    if (it.Done()) {
-      __ b(ne, miss_label);
-      break;
-    }
-    __ b(eq, &do_store);
+void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
+                                                   Register scratch,
+                                                   Label* miss) {
+  Handle<WeakCell> cell = Map::WeakCellForMap(transition);
+  Register map_reg = StoreTransitionDescriptor::MapRegister();
+  DCHECK(!map_reg.is(scratch));
+  __ LoadWeakValue(map_reg, cell, miss);
+  if (transition->CanBeDeprecated()) {
+    __ ldr(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
+    __ tst(scratch, Operand(Map::Deprecated::kMask));
+    __ b(ne, miss);
   }
-  __ bind(&do_store);
+}
 
-  StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
-                      lookup->representation());
-  GenerateTailCall(masm(), stub.GetCode());
+
+void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
+                                                      int descriptor,
+                                                      Register value_reg,
+                                                      Register scratch,
+                                                      Label* miss_label) {
+  DCHECK(!map_reg.is(scratch));
+  DCHECK(!map_reg.is(value_reg));
+  DCHECK(!value_reg.is(scratch));
+  __ LoadInstanceDescriptors(map_reg, scratch);
+  __ ldr(scratch,
+         FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
+  __ cmp(value_reg, scratch);
+  __ b(ne, miss_label);
+}
+
+
+void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type,
+                                                        Register value_reg,
+                                                        Label* miss_label) {
+  __ JumpIfSmi(value_reg, miss_label);
+  HeapType::Iterator<Map> it = field_type->Classes();
+  if (!it.Done()) {
+    __ ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset));
+    Label do_store;
+    while (true) {
+      __ CompareMap(scratch1(), it.Current(), &do_store);
+      it.Advance();
+      if (it.Done()) {
+        __ b(ne, miss_label);
+        break;
+      }
+      __ b(eq, &do_store);
+    }
+    __ bind(&do_store);
+  }
 }
 
 
@@ -558,11 +448,11 @@
       __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
     } else {
       Register map_reg = scratch1;
+      __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
       if (depth != 1 || check == CHECK_ALL_MAPS) {
-        // CheckMap implicitly loads the map of |reg| into |map_reg|.
-        __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK);
-      } else {
-        __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
+        Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+        __ CmpWeakValue(map_reg, cell, scratch2);
+        __ b(ne, miss);
       }
 
       // Check access rights to the global object.  This has to happen after
@@ -580,17 +470,7 @@
 
       reg = holder_reg;  // From now on the object will be in holder_reg.
 
-      // Two possible reasons for loading the prototype from the map:
-      // (1) Can't store references to new space in code.
-      // (2) Handler is shared for all receivers with the same prototype
-      //     map (but not necessarily the same prototype instance).
-      bool load_prototype_from_map =
-          heap()->InNewSpace(*prototype) || depth == 1;
-      if (load_prototype_from_map) {
-        __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
-      } else {
-        __ mov(reg, Operand(prototype));
-      }
+      __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
     }
 
     // Go to the next object in the prototype chain.
@@ -603,7 +483,10 @@
 
   if (depth != 0 || check == CHECK_ALL_MAPS) {
     // Check the holder map.
-    __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK);
+    __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
+    Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+    __ CmpWeakValue(scratch1, cell, scratch2);
+    __ b(ne, miss);
   }
 
   // Perform security check for access to the global object.
@@ -623,6 +506,10 @@
     Label success;
     __ b(&success);
     __ bind(miss);
+    if (IC::ICUseVector(kind())) {
+      DCHECK(kind() == Code::LOAD_IC);
+      PopVectorAndSlot();
+    }
     TailCallBuiltin(masm(), MissBuiltin(kind()));
     __ bind(&success);
   }
@@ -721,6 +608,7 @@
     } else {
       __ Push(holder_reg, this->name());
     }
+    InterceptorVectorSlotPush(holder_reg);
     // Invoke an interceptor.  Note: map checks from receiver to
     // interceptor's holder has been compiled before (see a caller
     // of this method.)
@@ -738,6 +626,7 @@
     __ Ret();
 
     __ bind(&interceptor_failed);
+    InterceptorVectorSlotPop(holder_reg);
     __ pop(this->name());
     __ pop(holder_reg);
     if (must_preserve_receiver_reg) {
@@ -767,7 +656,7 @@
 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
     Handle<JSObject> object, Handle<Name> name,
     Handle<ExecutableAccessorInfo> callback) {
-  Register holder_reg = Frontend(receiver(), name);
+  Register holder_reg = Frontend(name);
 
   __ push(receiver());  // receiver
   __ push(holder_reg);
@@ -808,11 +697,15 @@
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
   Label miss;
+  if (IC::ICUseVector(kind())) {
+    PushVectorAndSlot();
+  }
   FrontendHeader(receiver(), name, &miss);
 
   // Get the value from the cell.
   Register result = StoreDescriptor::ValueRegister();
-  __ mov(result, Operand(cell));
+  Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
+  __ LoadWeakValue(result, weak_cell, &miss);
   __ ldr(result, FieldMemOperand(result, Cell::kValueOffset));
 
   // Check for deleted property if property can actually be deleted.
@@ -824,6 +717,9 @@
 
   Counters* counters = isolate()->counters();
   __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3);
+  if (IC::ICUseVector(kind())) {
+    DiscardVectorAndSlot();
+  }
   __ Ret();
 
   FrontendFooter(name, &miss);
diff --git a/src/ic/arm/ic-arm.cc b/src/ic/arm/ic-arm.cc
index ae13161..70a5d84 100644
--- a/src/ic/arm/ic-arm.cc
+++ b/src/ic/arm/ic-arm.cc
@@ -265,18 +265,35 @@
 static const Register LoadIC_TempRegister() { return r3; }
 
 
+static void LoadIC_PushArgs(MacroAssembler* masm) {
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register name = LoadDescriptor::NameRegister();
+  if (FLAG_vector_ics) {
+    Register slot = VectorLoadICDescriptor::SlotRegister();
+    Register vector = VectorLoadICDescriptor::VectorRegister();
+
+    __ Push(receiver, name, slot, vector);
+  } else {
+    __ Push(receiver, name);
+  }
+}
+
+
 void LoadIC::GenerateMiss(MacroAssembler* masm) {
   // The return address is in lr.
   Isolate* isolate = masm->isolate();
 
-  __ IncrementCounter(isolate->counters()->load_miss(), 1, r3, r4);
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(r4, r5, VectorLoadICDescriptor::SlotRegister(),
+                     VectorLoadICDescriptor::VectorRegister()));
+  __ IncrementCounter(isolate->counters()->load_miss(), 1, r4, r5);
 
-  __ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
-  __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
+  LoadIC_PushArgs(masm);
 
   // Perform tail call to the entry.
   ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
-  __ TailCallExternalReference(ref, 2, 1);
+  int arg_count = FLAG_vector_ics ? 4 : 2;
+  __ TailCallExternalReference(ref, arg_count, 1);
 }
 
 
@@ -403,15 +420,18 @@
   // The return address is in lr.
   Isolate* isolate = masm->isolate();
 
-  __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4);
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(r4, r5, VectorLoadICDescriptor::SlotRegister(),
+                     VectorLoadICDescriptor::VectorRegister()));
+  __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r4, r5);
 
-  __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
+  LoadIC_PushArgs(masm);
 
   // Perform tail call to the entry.
   ExternalReference ref =
       ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
-
-  __ TailCallExternalReference(ref, 2, 1);
+  int arg_count = FLAG_vector_ics ? 4 : 2;
+  __ TailCallExternalReference(ref, arg_count, 1);
 }
 
 
@@ -587,32 +607,6 @@
 }
 
 
-void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
-  // Return address is in lr.
-  Label miss;
-
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register index = LoadDescriptor::NameRegister();
-  Register scratch = r3;
-  Register result = r0;
-  DCHECK(!scratch.is(receiver) && !scratch.is(index));
-
-  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
-                                          &miss,  // When not a string.
-                                          &miss,  // When not a number.
-                                          &miss,  // When index out of range.
-                                          STRING_INDEX_IS_ARRAY_INDEX);
-  char_at_generator.GenerateFast(masm);
-  __ Ret();
-
-  StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-}
-
-
 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
   // Push receiver, key and value for runtime call.
   __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
@@ -624,7 +618,7 @@
 }
 
 
-static void KeyedStoreGenerateGenericHelper(
+static void KeyedStoreGenerateMegamorphicHelper(
     MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
     KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
     Register value, Register key, Register receiver, Register receiver_map,
@@ -765,8 +759,8 @@
 }
 
 
-void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
-                                   StrictMode strict_mode) {
+void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
+                                       StrictMode strict_mode) {
   // ---------- S t a t e --------------
   //  -- r0     : value
   //  -- r1     : key
@@ -775,7 +769,7 @@
   // -----------------------------------
   Label slow, fast_object, fast_object_grow;
   Label fast_double, fast_double_grow;
-  Label array, extra, check_if_double_array;
+  Label array, extra, check_if_double_array, maybe_name_key, miss;
 
   // Register usage.
   Register value = StoreDescriptor::ValueRegister();
@@ -790,7 +784,7 @@
   // r4 and r5 are used as general scratch registers.
 
   // Check that the key is a smi.
-  __ JumpIfNotSmi(key, &slow);
+  __ JumpIfNotSmi(key, &maybe_name_key);
   // Check that the object isn't a smi.
   __ JumpIfSmi(receiver, &slow);
   // Get the map of the object.
@@ -822,6 +816,18 @@
   // r1: key.
   // r2: receiver.
   PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode);
+  // Never returns to here.
+
+  __ bind(&maybe_name_key);
+  __ ldr(r4, FieldMemOperand(key, HeapObject::kMapOffset));
+  __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
+  __ JumpIfNotUniqueNameInstanceType(r4, &slow);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::STORE_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::STORE_IC, flags, false, receiver, key, r3, r4, r5, r6);
+  // Cache miss.
+  __ b(&miss);
 
   // Extra capacity case: Check if there is extra capacity to
   // perform the store and update the length. Used for adding one
@@ -856,13 +862,16 @@
   __ cmp(key, Operand(ip));
   __ b(hs, &extra);
 
-  KeyedStoreGenerateGenericHelper(
+  KeyedStoreGenerateMegamorphicHelper(
       masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength,
       value, key, receiver, receiver_map, elements_map, elements);
-  KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
-                                  &slow, kDontCheckMap, kIncrementLength, value,
-                                  key, receiver, receiver_map, elements_map,
-                                  elements);
+  KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
+                                      &fast_double_grow, &slow, kDontCheckMap,
+                                      kIncrementLength, value, key, receiver,
+                                      receiver_map, elements_map, elements);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
 }
 
 
@@ -877,8 +886,8 @@
   Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
       Code::ComputeHandlerFlags(Code::STORE_IC));
 
-  masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver,
-                                               name, r3, r4, r5, r6);
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::STORE_IC, flags, false, receiver, name, r3, r4, r5, r6);
 
   // Cache miss: Jump to runtime.
   GenerateMiss(masm);
diff --git a/src/ic/arm/ic-compiler-arm.cc b/src/ic/arm/ic-compiler-arm.cc
index 7bef56e..b44702b 100644
--- a/src/ic/arm/ic-compiler-arm.cc
+++ b/src/ic/arm/ic-compiler-arm.cc
@@ -41,9 +41,12 @@
 
   if (check == PROPERTY &&
       (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) {
-    // In case we are compiling an IC for dictionary loads and stores, just
+    // In case we are compiling an IC for dictionary loads or stores, just
     // check whether the name is unique.
     if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) {
+      // Keyed loads with dictionaries shouldn't be here, they go generic.
+      // The DCHECK is to protect assumptions when --vector-ics is on.
+      DCHECK(kind() != Code::KEYED_LOAD_IC);
       Register tmp = scratch1();
       __ JumpIfSmi(this->name(), &miss);
       __ ldr(tmp, FieldMemOperand(this->name(), HeapObject::kMapOffset));
@@ -72,8 +75,8 @@
     Handle<Map> map = IC::TypeToMap(*type, isolate());
     if (!map->is_deprecated()) {
       number_of_handled_maps++;
-      __ mov(ip, Operand(map));
-      __ cmp(map_reg, ip);
+      Handle<WeakCell> cell = Map::WeakCellForMap(map);
+      __ CmpWeakValue(map_reg, cell, scratch2());
       if (type->Is(HeapType::Number())) {
         DCHECK(!number_case.is_unused());
         __ bind(&number_case);
@@ -100,16 +103,18 @@
   __ JumpIfSmi(receiver(), &miss);
 
   int receiver_count = receiver_maps->length();
-  __ ldr(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
+  Register map_reg = scratch1();
+  __ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
   for (int i = 0; i < receiver_count; ++i) {
-    __ mov(ip, Operand(receiver_maps->at(i)));
-    __ cmp(scratch1(), ip);
+    Handle<WeakCell> cell = Map::WeakCellForMap(receiver_maps->at(i));
+    __ CmpWeakValue(map_reg, cell, scratch2());
     if (transitioned_maps->at(i).is_null()) {
       __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq);
     } else {
       Label next_map;
       __ b(ne, &next_map);
-      __ mov(transition_map(), Operand(transitioned_maps->at(i)));
+      Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
+      __ LoadWeakValue(transition_map(), cell, &miss);
       __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, al);
       __ bind(&next_map);
     }
diff --git a/src/ic/arm/stub-cache-arm.cc b/src/ic/arm/stub-cache-arm.cc
index bc8b0fb..1d6bd30 100644
--- a/src/ic/arm/stub-cache-arm.cc
+++ b/src/ic/arm/stub-cache-arm.cc
@@ -7,7 +7,9 @@
 #if V8_TARGET_ARCH_ARM
 
 #include "src/codegen.h"
+#include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
+#include "src/interface-descriptors.h"
 
 namespace v8 {
 namespace internal {
@@ -16,7 +18,7 @@
 
 
 static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
-                       Code::Flags flags, bool leave_frame,
+                       Code::Kind ic_kind, Code::Flags flags, bool leave_frame,
                        StubCache::Table table, Register receiver, Register name,
                        // Number of the cache entry, not scaled.
                        Register offset, Register scratch, Register scratch2,
@@ -94,10 +96,11 @@
 }
 
 
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
-                              bool leave_frame, Register receiver,
-                              Register name, Register scratch, Register extra,
-                              Register extra2, Register extra3) {
+void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
+                              Code::Flags flags, bool leave_frame,
+                              Register receiver, Register name,
+                              Register scratch, Register extra, Register extra2,
+                              Register extra3) {
   Isolate* isolate = masm->isolate();
   Label miss;
 
@@ -109,15 +112,7 @@
   DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
 
   // Make sure that there are no register conflicts.
-  DCHECK(!scratch.is(receiver));
-  DCHECK(!scratch.is(name));
-  DCHECK(!extra.is(receiver));
-  DCHECK(!extra.is(name));
-  DCHECK(!extra.is(scratch));
-  DCHECK(!extra2.is(receiver));
-  DCHECK(!extra2.is(name));
-  DCHECK(!extra2.is(scratch));
-  DCHECK(!extra2.is(extra));
+  DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
 
   // Check scratch, extra and extra2 registers are valid.
   DCHECK(!scratch.is(no_reg));
@@ -125,6 +120,17 @@
   DCHECK(!extra2.is(no_reg));
   DCHECK(!extra3.is(no_reg));
 
+#ifdef DEBUG
+  // If vector-based ics are in use, ensure that scratch, extra, extra2 and
+  // extra3 don't conflict with the vector and slot registers, which need
+  // to be preserved for a handler call or miss.
+  if (IC::ICUseVector(ic_kind)) {
+    Register vector = VectorLoadICDescriptor::VectorRegister();
+    Register slot = VectorLoadICDescriptor::SlotRegister();
+    DCHECK(!AreAliased(vector, slot, scratch, extra, extra2, extra3));
+  }
+#endif
+
   Counters* counters = masm->isolate()->counters();
   __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2,
                       extra3);
@@ -147,8 +153,8 @@
   __ and_(scratch, scratch, Operand(mask));
 
   // Probe the primary table.
-  ProbeTable(isolate, masm, flags, leave_frame, kPrimary, receiver, name,
-             scratch, extra, extra2, extra3);
+  ProbeTable(isolate, masm, ic_kind, flags, leave_frame, kPrimary, receiver,
+             name, scratch, extra, extra2, extra3);
 
   // Primary miss: Compute hash for secondary probe.
   __ sub(scratch, scratch, Operand(name, LSR, kCacheIndexShift));
@@ -157,8 +163,8 @@
   __ and_(scratch, scratch, Operand(mask2));
 
   // Probe the secondary table.
-  ProbeTable(isolate, masm, flags, leave_frame, kSecondary, receiver, name,
-             scratch, extra, extra2, extra3);
+  ProbeTable(isolate, masm, ic_kind, flags, leave_frame, kSecondary, receiver,
+             name, scratch, extra, extra2, extra3);
 
   // Cache miss: Fall-through and let caller handle the miss by
   // entering the runtime system.
diff --git a/src/ic/arm64/handler-compiler-arm64.cc b/src/ic/arm64/handler-compiler-arm64.cc
index f7f82bc..1c28bf5 100644
--- a/src/ic/arm64/handler-compiler-arm64.cc
+++ b/src/ic/arm64/handler-compiler-arm64.cc
@@ -15,6 +15,27 @@
 
 #define __ ACCESS_MASM(masm)
 
+void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
+                                                Register slot) {
+  MacroAssembler* masm = this->masm();
+  __ Push(vector);
+  __ Push(slot);
+}
+
+
+void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
+  MacroAssembler* masm = this->masm();
+  __ Pop(slot);
+  __ Pop(vector);
+}
+
+
+void PropertyHandlerCompiler::DiscardVectorAndSlot() {
+  MacroAssembler* masm = this->masm();
+  // Remove vector and slot.
+  __ Drop(2);
+}
+
 
 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
     MacroAssembler* masm, Label* miss_label, Register receiver,
@@ -57,24 +78,15 @@
 
 
 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
-    MacroAssembler* masm, int index, Register prototype, Label* miss) {
-  Isolate* isolate = masm->isolate();
-  // Get the global function with the given index.
-  Handle<JSFunction> function(
-      JSFunction::cast(isolate->native_context()->get(index)));
-
-  // Check we're still in the same context.
-  Register scratch = prototype;
-  __ Ldr(scratch, GlobalObjectMemOperand());
-  __ Ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
-  __ Ldr(scratch, ContextMemOperand(scratch, index));
-  __ Cmp(scratch, Operand(function));
-  __ B(ne, miss);
-
+    MacroAssembler* masm, int index, Register result, Label* miss) {
+  __ Ldr(result, GlobalObjectMemOperand());
+  __ Ldr(result, FieldMemOperand(result, GlobalObject::kNativeContextOffset));
+  __ Ldr(result, ContextMemOperand(result, index));
   // Load its initial map. The global functions all have initial maps.
-  __ Mov(prototype, Operand(Handle<Map>(function->initial_map())));
+  __ Ldr(result,
+         FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
   // Load the prototype from the initial map.
-  __ Ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
+  __ Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
 }
 
 
@@ -315,11 +327,15 @@
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
   Label miss;
+  if (IC::ICUseVector(kind())) {
+    PushVectorAndSlot();
+  }
   FrontendHeader(receiver(), name, &miss);
 
   // Get the value from the cell.
   Register result = StoreDescriptor::ValueRegister();
-  __ Mov(result, Operand(cell));
+  Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
+  __ LoadWeakValue(result, weak_cell, &miss);
   __ Ldr(result, FieldMemOperand(result, Cell::kValueOffset));
 
   // Check for deleted property if property can actually be deleted.
@@ -329,6 +345,9 @@
 
   Counters* counters = isolate()->counters();
   __ IncrementCounter(counters->named_load_global_stub(), 1, x1, x3);
+  if (IC::ICUseVector(kind())) {
+    DiscardVectorAndSlot();
+  }
   __ Ret();
 
   FrontendFooter(name, &miss);
@@ -370,176 +389,60 @@
 }
 
 
-// Generate StoreTransition code, value is passed in x0 register.
-// When leaving generated code after success, the receiver_reg and storage_reg
-// may be clobbered. Upon branch to miss_label, the receiver and name registers
-// have their original values.
-void NamedStoreHandlerCompiler::GenerateStoreTransition(
-    Handle<Map> transition, Handle<Name> name, Register receiver_reg,
-    Register storage_reg, Register value_reg, Register scratch1,
-    Register scratch2, Register scratch3, Label* miss_label, Label* slow) {
-  Label exit;
-
-  DCHECK(!AreAliased(receiver_reg, storage_reg, value_reg, scratch1, scratch2,
-                     scratch3));
-
-  // We don't need scratch3.
-  scratch3 = NoReg;
-
-  int descriptor = transition->LastAdded();
-  DescriptorArray* descriptors = transition->instance_descriptors();
-  PropertyDetails details = descriptors->GetDetails(descriptor);
-  Representation representation = details.representation();
-  DCHECK(!representation.IsNone());
-
-  if (details.type() == CONSTANT) {
-    Handle<Object> constant(descriptors->GetValue(descriptor), isolate());
-    __ LoadObject(scratch1, constant);
-    __ Cmp(value_reg, scratch1);
-    __ B(ne, miss_label);
-  } else if (representation.IsSmi()) {
-    __ JumpIfNotSmi(value_reg, miss_label);
-  } else if (representation.IsHeapObject()) {
-    __ JumpIfSmi(value_reg, miss_label);
-    HeapType* field_type = descriptors->GetFieldType(descriptor);
-    HeapType::Iterator<Map> it = field_type->Classes();
-    if (!it.Done()) {
-      __ Ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
-      Label do_store;
-      while (true) {
-        __ CompareMap(scratch1, it.Current());
-        it.Advance();
-        if (it.Done()) {
-          __ B(ne, miss_label);
-          break;
-        }
-        __ B(eq, &do_store);
-      }
-      __ Bind(&do_store);
-    }
-  } else if (representation.IsDouble()) {
-    UseScratchRegisterScope temps(masm());
-    DoubleRegister temp_double = temps.AcquireD();
-    __ SmiUntagToDouble(temp_double, value_reg, kSpeculativeUntag);
-
-    Label do_store;
-    __ JumpIfSmi(value_reg, &do_store);
-
-    __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label,
-                DONT_DO_SMI_CHECK);
-    __ Ldr(temp_double, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
-
-    __ Bind(&do_store);
-    __ AllocateHeapNumber(storage_reg, slow, scratch1, scratch2, temp_double,
-                          NoReg, MUTABLE);
-  }
-
-  // Stub never generated for objects that require access checks.
-  DCHECK(!transition->is_access_check_needed());
-
-  // Perform map transition for the receiver if necessary.
-  if (details.type() == FIELD &&
-      Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) {
-    // The properties must be extended before we can store the value.
-    // We jump to a runtime call that extends the properties array.
-    __ Mov(scratch1, Operand(transition));
-    __ Push(receiver_reg, scratch1, value_reg);
-    __ TailCallExternalReference(
-        ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
-                          isolate()),
-        3, 1);
-    return;
-  }
-
-  // Update the map of the object.
-  __ Mov(scratch1, Operand(transition));
-  __ Str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
-
-  // Update the write barrier for the map field.
-  __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2,
-                      kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
-
-  if (details.type() == CONSTANT) {
-    DCHECK(value_reg.is(x0));
-    __ Ret();
-    return;
-  }
-
-  int index = transition->instance_descriptors()->GetFieldIndex(
-      transition->LastAdded());
-
-  // Adjust for the number of properties stored in the object. Even in the
-  // face of a transition we can use the old map here because the size of the
-  // object and the number of in-object properties is not going to change.
-  index -= transition->inobject_properties();
-
-  // TODO(verwaest): Share this code as a code stub.
-  SmiCheck smi_check =
-      representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
-  Register prop_reg = representation.IsDouble() ? storage_reg : value_reg;
-  if (index < 0) {
-    // Set the property straight into the object.
-    int offset = transition->instance_size() + (index * kPointerSize);
-    __ Str(prop_reg, FieldMemOperand(receiver_reg, offset));
-
-    if (!representation.IsSmi()) {
-      // Update the write barrier for the array address.
-      if (!representation.IsDouble()) {
-        __ Mov(storage_reg, value_reg);
-      }
-      __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1,
-                          kLRHasNotBeenSaved, kDontSaveFPRegs,
-                          EMIT_REMEMBERED_SET, smi_check);
-    }
-  } else {
-    // Write to the properties array.
-    int offset = index * kPointerSize + FixedArray::kHeaderSize;
-    // Get the properties array
-    __ Ldr(scratch1,
-           FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
-    __ Str(prop_reg, FieldMemOperand(scratch1, offset));
-
-    if (!representation.IsSmi()) {
-      // Update the write barrier for the array address.
-      if (!representation.IsDouble()) {
-        __ Mov(storage_reg, value_reg);
-      }
-      __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg,
-                          kLRHasNotBeenSaved, kDontSaveFPRegs,
-                          EMIT_REMEMBERED_SET, smi_check);
-    }
-  }
-
-  __ Bind(&exit);
-  // Return the value (register x0).
-  DCHECK(value_reg.is(x0));
-  __ Ret();
+void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
+  __ Mov(this->name(), Operand(name));
 }
 
 
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
-                                                   Register value_reg,
-                                                   Label* miss_label) {
-  DCHECK(lookup->representation().IsHeapObject());
-  __ JumpIfSmi(value_reg, miss_label);
-  HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
-  __ Ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset));
-  Label do_store;
-  while (true) {
-    __ CompareMap(scratch1(), it.Current());
-    it.Advance();
-    if (it.Done()) {
-      __ B(ne, miss_label);
-      break;
-    }
-    __ B(eq, &do_store);
+void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
+                                                   Register scratch,
+                                                   Label* miss) {
+  Handle<WeakCell> cell = Map::WeakCellForMap(transition);
+  Register map_reg = StoreTransitionDescriptor::MapRegister();
+  DCHECK(!map_reg.is(scratch));
+  __ LoadWeakValue(map_reg, cell, miss);
+  if (transition->CanBeDeprecated()) {
+    __ Ldrsw(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
+    __ TestAndBranchIfAnySet(scratch, Map::Deprecated::kMask, miss);
   }
-  __ Bind(&do_store);
+}
 
-  StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
-                      lookup->representation());
-  GenerateTailCall(masm(), stub.GetCode());
+
+void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
+                                                      int descriptor,
+                                                      Register value_reg,
+                                                      Register scratch,
+                                                      Label* miss_label) {
+  DCHECK(!map_reg.is(scratch));
+  DCHECK(!map_reg.is(value_reg));
+  DCHECK(!value_reg.is(scratch));
+  __ LoadInstanceDescriptors(map_reg, scratch);
+  __ Ldr(scratch,
+         FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
+  __ Cmp(value_reg, scratch);
+  __ B(ne, miss_label);
+}
+
+
+void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type,
+                                                        Register value_reg,
+                                                        Label* miss_label) {
+  __ JumpIfSmi(value_reg, miss_label);
+  HeapType::Iterator<Map> it = field_type->Classes();
+  if (!it.Done()) {
+    __ Ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset));
+    Label do_store;
+    while (true) {
+      __ CompareMap(scratch1(), it.Current());
+      it.Advance();
+      if (it.Done()) {
+        __ B(ne, miss_label);
+        break;
+      }
+      __ B(eq, &do_store);
+    }
+    __ Bind(&do_store);
+  }
 }
 
 
@@ -592,17 +495,13 @@
       reg = holder_reg;  // From now on the object will be in holder_reg.
       __ Ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
     } else {
-      // Two possible reasons for loading the prototype from the map:
-      // (1) Can't store references to new space in code.
-      // (2) Handler is shared for all receivers with the same prototype
-      //     map (but not necessarily the same prototype instance).
-      bool load_prototype_from_map =
-          heap()->InNewSpace(*prototype) || depth == 1;
       Register map_reg = scratch1;
       __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
 
       if (depth != 1 || check == CHECK_ALL_MAPS) {
-        __ CheckMap(map_reg, current_map, miss, DONT_DO_SMI_CHECK);
+        Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+        __ CmpWeakValue(map_reg, cell, scratch2);
+        __ B(ne, miss);
       }
 
       // Check access rights to the global object.  This has to happen after
@@ -621,11 +520,7 @@
 
       reg = holder_reg;  // From now on the object will be in holder_reg.
 
-      if (load_prototype_from_map) {
-        __ Ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
-      } else {
-        __ Mov(reg, Operand(prototype));
-      }
+      __ Ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
     }
 
     // Go to the next object in the prototype chain.
@@ -639,7 +534,10 @@
   // Check the holder map.
   if (depth != 0 || check == CHECK_ALL_MAPS) {
     // Check the holder map.
-    __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK);
+    __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
+    Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+    __ CmpWeakValue(scratch1, cell, scratch2);
+    __ B(ne, miss);
   }
 
   // Perform security check for access to the global object.
@@ -660,6 +558,10 @@
     __ B(&success);
 
     __ Bind(miss);
+    if (IC::ICUseVector(kind())) {
+      DCHECK(kind() == Code::LOAD_IC);
+      PopVectorAndSlot();
+    }
     TailCallBuiltin(masm(), MissBuiltin(kind()));
 
     __ Bind(&success);
@@ -772,6 +674,7 @@
     } else {
       __ Push(holder_reg, this->name());
     }
+    InterceptorVectorSlotPush(holder_reg);
     // Invoke an interceptor.  Note: map checks from receiver to
     // interceptor's holder has been compiled before (see a caller
     // of this method.)
@@ -788,6 +691,7 @@
     __ Ret();
 
     __ Bind(&interceptor_failed);
+    InterceptorVectorSlotPop(holder_reg);
     if (must_preserve_receiver_reg) {
       __ Pop(this->name(), holder_reg, receiver());
     } else {
@@ -818,7 +722,7 @@
     Handle<JSObject> object, Handle<Name> name,
     Handle<ExecutableAccessorInfo> callback) {
   ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreCallback");
-  Register holder_reg = Frontend(receiver(), name);
+  Register holder_reg = Frontend(name);
 
   // Stub never generated for non-global objects that require access checks.
   DCHECK(holder()->IsJSGlobalProxy() || !holder()->IsAccessCheckNeeded());
diff --git a/src/ic/arm64/ic-arm64.cc b/src/ic/arm64/ic-arm64.cc
index 76f9c24..a01015c 100644
--- a/src/ic/arm64/ic-arm64.cc
+++ b/src/ic/arm64/ic-arm64.cc
@@ -354,12 +354,23 @@
   Isolate* isolate = masm->isolate();
   ASM_LOCATION("LoadIC::GenerateMiss");
 
-  __ IncrementCounter(isolate->counters()->load_miss(), 1, x3, x4);
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(x4, x5, VectorLoadICDescriptor::SlotRegister(),
+                     VectorLoadICDescriptor::VectorRegister()));
+  __ IncrementCounter(isolate->counters()->load_miss(), 1, x4, x5);
 
   // Perform tail call to the entry.
-  __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
+  if (FLAG_vector_ics) {
+    __ Push(VectorLoadICDescriptor::ReceiverRegister(),
+            VectorLoadICDescriptor::NameRegister(),
+            VectorLoadICDescriptor::SlotRegister(),
+            VectorLoadICDescriptor::VectorRegister());
+  } else {
+    __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
+  }
   ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
-  __ TailCallExternalReference(ref, 2, 1);
+  int arg_count = FLAG_vector_ics ? 4 : 2;
+  __ TailCallExternalReference(ref, arg_count, 1);
 }
 
 
@@ -420,15 +431,25 @@
   // The return address is in lr.
   Isolate* isolate = masm->isolate();
 
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(x10, x11, VectorLoadICDescriptor::SlotRegister(),
+                     VectorLoadICDescriptor::VectorRegister()));
   __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, x10, x11);
 
-  __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
+  if (FLAG_vector_ics) {
+    __ Push(VectorLoadICDescriptor::ReceiverRegister(),
+            VectorLoadICDescriptor::NameRegister(),
+            VectorLoadICDescriptor::SlotRegister(),
+            VectorLoadICDescriptor::VectorRegister());
+  } else {
+    __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
+  }
 
   // Perform tail call to the entry.
   ExternalReference ref =
       ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
-
-  __ TailCallExternalReference(ref, 2, 1);
+  int arg_count = FLAG_vector_ics ? 4 : 2;
+  __ TailCallExternalReference(ref, arg_count, 1);
 }
 
 
@@ -627,32 +648,6 @@
 }
 
 
-void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
-  // Return address is in lr.
-  Label miss;
-
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register index = LoadDescriptor::NameRegister();
-  Register result = x0;
-  Register scratch = x3;
-  DCHECK(!scratch.is(receiver) && !scratch.is(index));
-
-  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
-                                          &miss,  // When not a string.
-                                          &miss,  // When not a number.
-                                          &miss,  // When index out of range.
-                                          STRING_INDEX_IS_ARRAY_INDEX);
-  char_at_generator.GenerateFast(masm);
-  __ Ret();
-
-  StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
-
-  __ Bind(&miss);
-  GenerateMiss(masm);
-}
-
-
 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
   ASM_LOCATION("KeyedStoreIC::GenerateMiss");
 
@@ -666,7 +661,7 @@
 }
 
 
-static void KeyedStoreGenerateGenericHelper(
+static void KeyedStoreGenerateMegamorphicHelper(
     MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
     KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
     Register value, Register key, Register receiver, Register receiver_map,
@@ -798,9 +793,9 @@
 }
 
 
-void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
-                                   StrictMode strict_mode) {
-  ASM_LOCATION("KeyedStoreIC::GenerateGeneric");
+void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
+                                       StrictMode strict_mode) {
+  ASM_LOCATION("KeyedStoreIC::GenerateMegamorphic");
   Label slow;
   Label array;
   Label fast_object;
@@ -808,6 +803,8 @@
   Label fast_object_grow;
   Label fast_double_grow;
   Label fast_double;
+  Label maybe_name_key;
+  Label miss;
 
   Register value = StoreDescriptor::ValueRegister();
   Register key = StoreDescriptor::NameRegister();
@@ -820,7 +817,7 @@
   Register elements = x4;
   Register elements_map = x5;
 
-  __ JumpIfNotSmi(key, &slow);
+  __ JumpIfNotSmi(key, &maybe_name_key);
   __ JumpIfSmi(receiver, &slow);
   __ Ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
 
@@ -853,7 +850,18 @@
   //  x1: key
   //  x2: receiver
   PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode);
+  // Never returns to here.
 
+  __ bind(&maybe_name_key);
+  __ Ldr(x10, FieldMemOperand(key, HeapObject::kMapOffset));
+  __ Ldrb(x10, FieldMemOperand(x10, Map::kInstanceTypeOffset));
+  __ JumpIfNotUniqueNameInstanceType(x10, &slow);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::STORE_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::STORE_IC, flags, false, receiver, key, x3, x4, x5, x6);
+  // Cache miss.
+  __ B(&miss);
 
   __ Bind(&extra);
   // Extra capacity case: Check if there is extra capacity to
@@ -888,13 +896,16 @@
   __ B(eq, &extra);  // We can handle the case where we are appending 1 element.
   __ B(lo, &slow);
 
-  KeyedStoreGenerateGenericHelper(
+  KeyedStoreGenerateMegamorphicHelper(
       masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength,
       value, key, receiver, receiver_map, elements_map, elements);
-  KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
-                                  &slow, kDontCheckMap, kIncrementLength, value,
-                                  key, receiver, receiver_map, elements_map,
-                                  elements);
+  KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
+                                      &fast_double_grow, &slow, kDontCheckMap,
+                                      kIncrementLength, value, key, receiver,
+                                      receiver_map, elements_map, elements);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
 }
 
 
@@ -907,8 +918,8 @@
   // Probe the stub cache.
   Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
       Code::ComputeHandlerFlags(Code::STORE_IC));
-  masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver,
-                                               name, x3, x4, x5, x6);
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::STORE_IC, flags, false, receiver, name, x3, x4, x5, x6);
 
   // Cache miss: Jump to runtime.
   GenerateMiss(masm);
diff --git a/src/ic/arm64/ic-compiler-arm64.cc b/src/ic/arm64/ic-compiler-arm64.cc
index ffc1069..a3d0d48 100644
--- a/src/ic/arm64/ic-compiler-arm64.cc
+++ b/src/ic/arm64/ic-compiler-arm64.cc
@@ -42,9 +42,12 @@
 
   if (check == PROPERTY &&
       (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) {
-    // In case we are compiling an IC for dictionary loads and stores, just
+    // In case we are compiling an IC for dictionary loads or stores, just
     // check whether the name is unique.
     if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) {
+      // Keyed loads with dictionaries shouldn't be here, they go generic.
+      // The DCHECK is to protect assumptions when --vector-ics is on.
+      DCHECK(kind() != Code::KEYED_LOAD_IC);
       Register tmp = scratch1();
       __ JumpIfSmi(this->name(), &miss);
       __ Ldr(tmp, FieldMemOperand(this->name(), HeapObject::kMapOffset));
@@ -71,8 +74,9 @@
     Handle<Map> map = IC::TypeToMap(*type, isolate());
     if (!map->is_deprecated()) {
       number_of_handled_maps++;
+      Handle<WeakCell> cell = Map::WeakCellForMap(map);
+      __ CmpWeakValue(map_reg, cell, scratch2());
       Label try_next;
-      __ Cmp(map_reg, Operand(map));
       __ B(ne, &try_next);
       if (type->Is(HeapType::Number())) {
         DCHECK(!number_case.is_unused());
@@ -104,16 +108,18 @@
   __ JumpIfSmi(receiver(), &miss);
 
   int receiver_count = receiver_maps->length();
-  __ Ldr(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
+  Register map_reg = scratch1();
+  __ Ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
   for (int i = 0; i < receiver_count; i++) {
-    __ Cmp(scratch1(), Operand(receiver_maps->at(i)));
-
+    Handle<WeakCell> cell = Map::WeakCellForMap(receiver_maps->at(i));
+    __ CmpWeakValue(map_reg, cell, scratch2());
     Label skip;
     __ B(&skip, ne);
     if (!transitioned_maps->at(i).is_null()) {
       // This argument is used by the handler stub. For example, see
       // ElementsTransitionGenerator::GenerateMapChangeElementsTransition.
-      __ Mov(transition_map(), Operand(transitioned_maps->at(i)));
+      Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
+      __ LoadWeakValue(transition_map(), cell, &miss);
     }
     __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
     __ Bind(&skip);
diff --git a/src/ic/arm64/stub-cache-arm64.cc b/src/ic/arm64/stub-cache-arm64.cc
index 4d31d49..a9c56a3 100644
--- a/src/ic/arm64/stub-cache-arm64.cc
+++ b/src/ic/arm64/stub-cache-arm64.cc
@@ -7,7 +7,9 @@
 #if V8_TARGET_ARCH_ARM64
 
 #include "src/codegen.h"
+#include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
+#include "src/interface-descriptors.h"
 
 namespace v8 {
 namespace internal {
@@ -23,7 +25,7 @@
 //
 // 'receiver', 'name' and 'offset' registers are preserved on miss.
 static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
-                       Code::Flags flags, bool leave_frame,
+                       Code::Kind ic_kind, Code::Flags flags, bool leave_frame,
                        StubCache::Table table, Register receiver, Register name,
                        Register offset, Register scratch, Register scratch2,
                        Register scratch3) {
@@ -90,10 +92,11 @@
 }
 
 
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
-                              bool leave_frame, Register receiver,
-                              Register name, Register scratch, Register extra,
-                              Register extra2, Register extra3) {
+void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
+                              Code::Flags flags, bool leave_frame,
+                              Register receiver, Register name,
+                              Register scratch, Register extra, Register extra2,
+                              Register extra3) {
   Isolate* isolate = masm->isolate();
   Label miss;
 
@@ -108,6 +111,17 @@
   DCHECK(!extra2.is(no_reg));
   DCHECK(!extra3.is(no_reg));
 
+#ifdef DEBUG
+  // If vector-based ics are in use, ensure that scratch, extra, extra2 and
+  // extra3 don't conflict with the vector and slot registers, which need
+  // to be preserved for a handler call or miss.
+  if (IC::ICUseVector(ic_kind)) {
+    Register vector = VectorLoadICDescriptor::VectorRegister();
+    Register slot = VectorLoadICDescriptor::SlotRegister();
+    DCHECK(!AreAliased(vector, slot, scratch, extra, extra2, extra3));
+  }
+#endif
+
   Counters* counters = masm->isolate()->counters();
   __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2,
                       extra3);
@@ -125,8 +139,8 @@
           CountTrailingZeros(kPrimaryTableSize, 64));
 
   // Probe the primary table.
-  ProbeTable(isolate, masm, flags, leave_frame, kPrimary, receiver, name,
-             scratch, extra, extra2, extra3);
+  ProbeTable(isolate, masm, ic_kind, flags, leave_frame, kPrimary, receiver,
+             name, scratch, extra, extra2, extra3);
 
   // Primary miss: Compute hash for secondary table.
   __ Sub(scratch, scratch, Operand(name, LSR, kCacheIndexShift));
@@ -134,8 +148,8 @@
   __ And(scratch, scratch, kSecondaryTableSize - 1);
 
   // Probe the secondary table.
-  ProbeTable(isolate, masm, flags, leave_frame, kSecondary, receiver, name,
-             scratch, extra, extra2, extra3);
+  ProbeTable(isolate, masm, ic_kind, flags, leave_frame, kSecondary, receiver,
+             name, scratch, extra, extra2, extra3);
 
   // Cache miss: Fall-through and let caller handle the miss by
   // entering the runtime system.
diff --git a/src/ic/handler-compiler.cc b/src/ic/handler-compiler.cc
index 4ed92ec..ae977c3 100644
--- a/src/ic/handler-compiler.cc
+++ b/src/ic/handler-compiler.cc
@@ -129,11 +129,17 @@
 }
 
 
-Register PropertyHandlerCompiler::Frontend(Register object_reg,
-                                           Handle<Name> name) {
+Register PropertyHandlerCompiler::Frontend(Handle<Name> name) {
   Label miss;
-  Register reg = FrontendHeader(object_reg, name, &miss);
+  if (IC::ICUseVector(kind())) {
+    PushVectorAndSlot();
+  }
+  Register reg = FrontendHeader(receiver(), name, &miss);
   FrontendFooter(name, &miss);
+  // The footer consumes the vector and slot from the stack if miss occurs.
+  if (IC::ICUseVector(kind())) {
+    DiscardVectorAndSlot();
+  }
   return reg;
 }
 
@@ -179,7 +185,7 @@
 
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name,
                                                         FieldIndex field) {
-  Register reg = Frontend(receiver(), name);
+  Register reg = Frontend(name);
   __ Move(receiver(), reg);
   LoadFieldStub stub(isolate(), field);
   GenerateTailCall(masm(), stub.GetCode());
@@ -189,7 +195,7 @@
 
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name,
                                                            int constant_index) {
-  Register reg = Frontend(receiver(), name);
+  Register reg = Frontend(name);
   __ Move(receiver(), reg);
   LoadConstantStub stub(isolate(), constant_index);
   GenerateTailCall(masm(), stub.GetCode());
@@ -200,7 +206,14 @@
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
     Handle<Name> name) {
   Label miss;
+  if (IC::ICUseVector(kind())) {
+    DCHECK(kind() == Code::LOAD_IC);
+    PushVectorAndSlot();
+  }
   NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
+  if (IC::ICUseVector(kind())) {
+    DiscardVectorAndSlot();
+  }
   GenerateLoadConstant(isolate()->factory()->undefined_value());
   FrontendFooter(name, &miss);
   return GetCode(kind(), Code::FAST, name);
@@ -209,7 +222,7 @@
 
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
     Handle<Name> name, Handle<ExecutableAccessorInfo> callback) {
-  Register reg = Frontend(receiver(), name);
+  Register reg = Frontend(name);
   GenerateLoadCallback(reg, callback);
   return GetCode(kind(), Code::FAST, name);
 }
@@ -218,7 +231,7 @@
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
     Handle<Name> name, const CallOptimization& call_optimization) {
   DCHECK(call_optimization.is_simple_api_call());
-  Frontend(receiver(), name);
+  Frontend(name);
   Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate());
   GenerateFastApiCall(masm(), call_optimization, receiver_map, receiver(),
                       scratch1(), false, 0, NULL);
@@ -226,6 +239,35 @@
 }
 
 
+void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) {
+  if (IC::ICUseVector(kind())) {
+    if (holder_reg.is(receiver())) {
+      PushVectorAndSlot();
+    } else {
+      DCHECK(holder_reg.is(scratch1()));
+      PushVectorAndSlot(scratch2(), scratch3());
+    }
+  }
+}
+
+
+void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg,
+                                                        PopMode mode) {
+  if (IC::ICUseVector(kind())) {
+    if (mode == DISCARD) {
+      DiscardVectorAndSlot();
+    } else {
+      if (holder_reg.is(receiver())) {
+        PopVectorAndSlot();
+      } else {
+        DCHECK(holder_reg.is(scratch1()));
+        PopVectorAndSlot(scratch2(), scratch3());
+      }
+    }
+  }
+}
+
+
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
     LookupIterator* it) {
   // So far the most popular follow ups for interceptor loads are FIELD and
@@ -241,7 +283,8 @@
     case LookupIterator::NOT_FOUND:
       break;
     case LookupIterator::DATA:
-      inline_followup = it->property_details().type() == FIELD;
+      inline_followup =
+          it->property_details().type() == FIELD && !it->is_dictionary_holder();
       break;
     case LookupIterator::ACCESSOR: {
       Handle<Object> accessors = it->GetAccessors();
@@ -255,7 +298,12 @@
     }
   }
 
-  Register reg = Frontend(receiver(), it->name());
+  Label miss;
+  InterceptorVectorSlotPush(receiver());
+  Register reg = FrontendHeader(receiver(), it->name(), &miss);
+  FrontendFooter(it->name(), &miss);
+  InterceptorVectorSlotPop(reg);
+
   if (inline_followup) {
     // TODO(368): Compile in the whole chain: all the interceptors in
     // prototypes and ultimate answer.
@@ -273,7 +321,13 @@
 
   set_type_for_object(holder());
   set_holder(real_named_property_holder);
-  Register reg = Frontend(interceptor_reg, it->name());
+
+  Label miss;
+  InterceptorVectorSlotPush(interceptor_reg);
+  Register reg = FrontendHeader(interceptor_reg, it->name(), &miss);
+  FrontendFooter(it->name(), &miss);
+  // We discard the vector and slot now because we don't miss below this point.
+  InterceptorVectorSlotPop(reg, DISCARD);
 
   switch (it->state()) {
     case LookupIterator::ACCESS_CHECK:
@@ -300,7 +354,7 @@
 
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
     Handle<Name> name, Handle<JSFunction> getter) {
-  Frontend(receiver(), name);
+  Frontend(name);
   GenerateLoadViaGetter(masm(), type(), receiver(), getter);
   return GetCode(kind(), Code::FAST, name);
 }
@@ -309,10 +363,7 @@
 // TODO(verwaest): Cleanup. holder() is actually the receiver.
 Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
     Handle<Map> transition, Handle<Name> name) {
-  Label miss, slow;
-
-  // Ensure no transitions to deprecated maps are followed.
-  __ CheckMapDeprecated(transition, scratch1(), &miss);
+  Label miss;
 
   // Check that we are allowed to write this.
   bool is_nonexistent = holder()->map() == transition->GetBackPointer();
@@ -331,21 +382,58 @@
     DCHECK(holder()->HasFastProperties());
   }
 
-  GenerateStoreTransition(transition, name, receiver(), this->name(), value(),
-                          scratch1(), scratch2(), scratch3(), &miss, &slow);
+  int descriptor = transition->LastAdded();
+  Handle<DescriptorArray> descriptors(transition->instance_descriptors());
+  PropertyDetails details = descriptors->GetDetails(descriptor);
+  Representation representation = details.representation();
+  DCHECK(!representation.IsNone());
+
+  // Stub is never generated for objects that require access checks.
+  DCHECK(!transition->is_access_check_needed());
+
+  // Call to respective StoreTransitionStub.
+  if (details.type() == CONSTANT) {
+    GenerateRestoreMap(transition, scratch2(), &miss);
+    DCHECK(descriptors->GetValue(descriptor)->IsJSFunction());
+    Register map_reg = StoreTransitionDescriptor::MapRegister();
+    GenerateConstantCheck(map_reg, descriptor, value(), scratch2(), &miss);
+    GenerateRestoreName(name);
+    StoreTransitionStub stub(isolate());
+    GenerateTailCall(masm(), stub.GetCode());
+
+  } else {
+    if (representation.IsHeapObject()) {
+      GenerateFieldTypeChecks(descriptors->GetFieldType(descriptor), value(),
+                              &miss);
+    }
+    StoreTransitionStub::StoreMode store_mode =
+        Map::cast(transition->GetBackPointer())->unused_property_fields() == 0
+            ? StoreTransitionStub::ExtendStorageAndStoreMapAndValue
+            : StoreTransitionStub::StoreMapAndValue;
+
+    GenerateRestoreMap(transition, scratch2(), &miss);
+    GenerateRestoreName(name);
+    StoreTransitionStub stub(isolate(),
+                             FieldIndex::ForDescriptor(*transition, descriptor),
+                             representation, store_mode);
+    GenerateTailCall(masm(), stub.GetCode());
+  }
 
   GenerateRestoreName(&miss, name);
   TailCallBuiltin(masm(), MissBuiltin(kind()));
 
-  GenerateRestoreName(&slow, name);
-  TailCallBuiltin(masm(), SlowBuiltin(kind()));
   return GetCode(kind(), Code::FAST, name);
 }
 
 
 Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) {
   Label miss;
-  GenerateStoreField(it, value(), &miss);
+  DCHECK(it->representation().IsHeapObject());
+
+  GenerateFieldTypeChecks(*it->GetFieldType(), value(), &miss);
+  StoreFieldStub stub(isolate(), it->GetFieldIndex(), it->representation());
+  GenerateTailCall(masm(), stub.GetCode());
+
   __ bind(&miss);
   TailCallBuiltin(masm(), MissBuiltin(kind()));
   return GetCode(kind(), Code::FAST, it->name());
@@ -354,7 +442,7 @@
 
 Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
     Handle<JSObject> object, Handle<Name> name, Handle<JSFunction> setter) {
-  Frontend(receiver(), name);
+  Frontend(name);
   GenerateStoreViaSetter(masm(), type(), receiver(), setter);
 
   return GetCode(kind(), Code::FAST, name);
@@ -364,7 +452,7 @@
 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
     Handle<JSObject> object, Handle<Name> name,
     const CallOptimization& call_optimization) {
-  Frontend(receiver(), name);
+  Frontend(name);
   Register values[] = {value()};
   GenerateFastApiCall(masm(), call_optimization, handle(object->map()),
                       receiver(), scratch1(), true, 1, values);
@@ -381,8 +469,8 @@
     Handle<Map> receiver_map = receiver_maps->at(i);
     Handle<Code> cached_stub;
 
-    if ((receiver_map->instance_type() & kNotStringTag) == 0) {
-      cached_stub = isolate()->builtins()->KeyedLoadIC_String();
+    if (receiver_map->IsStringMap()) {
+      cached_stub = LoadIndexedStringStub(isolate()).GetCode();
     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
       cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
     } else {
diff --git a/src/ic/handler-compiler.h b/src/ic/handler-compiler.h
index f033f3f..bed6577 100644
--- a/src/ic/handler-compiler.h
+++ b/src/ic/handler-compiler.h
@@ -38,10 +38,21 @@
 
   virtual void FrontendFooter(Handle<Name> name, Label* miss) { UNREACHABLE(); }
 
-  Register Frontend(Register object_reg, Handle<Name> name);
+  // Frontend loads from receiver(), returns holder register which may be
+  // different.
+  Register Frontend(Handle<Name> name);
   void NonexistentFrontendHeader(Handle<Name> name, Label* miss,
                                  Register scratch1, Register scratch2);
 
+  // When FLAG_vector_ics is true, handlers that have the possibility of missing
+  // will need to save and pass these to miss handlers.
+  void PushVectorAndSlot() { PushVectorAndSlot(vector(), slot()); }
+  void PushVectorAndSlot(Register vector, Register slot);
+  void PopVectorAndSlot() { PopVectorAndSlot(vector(), slot()); }
+  void PopVectorAndSlot(Register vector, Register slot);
+
+  void DiscardVectorAndSlot();
+
   // TODO(verwaest): Make non-static.
   static void GenerateFastApiCall(MacroAssembler* masm,
                                   const CallOptimization& optimization,
@@ -170,6 +181,12 @@
                             Handle<ExecutableAccessorInfo> callback);
   void GenerateLoadCallback(const CallOptimization& call_optimization,
                             Handle<Map> receiver_map);
+
+  // Helper emits no code if vector-ics are disabled.
+  void InterceptorVectorSlotPush(Register holder_reg);
+  enum PopMode { POP, DISCARD };
+  void InterceptorVectorSlotPop(Register holder_reg, PopMode mode = POP);
+
   void GenerateLoadInterceptor(Register holder_reg);
   void GenerateLoadInterceptorWithFollowup(LookupIterator* it,
                                            Register holder_reg);
@@ -230,14 +247,16 @@
   void GenerateRestoreName(Label* label, Handle<Name> name);
 
  private:
-  void GenerateStoreTransition(Handle<Map> transition, Handle<Name> name,
-                               Register receiver_reg, Register name_reg,
-                               Register value_reg, Register scratch1,
-                               Register scratch2, Register scratch3,
-                               Label* miss_label, Label* slow);
+  void GenerateRestoreName(Handle<Name> name);
+  void GenerateRestoreMap(Handle<Map> transition, Register scratch,
+                          Label* miss);
 
-  void GenerateStoreField(LookupIterator* lookup, Register value_reg,
-                          Label* miss_label);
+  void GenerateConstantCheck(Register map_reg, int descriptor,
+                             Register value_reg, Register scratch,
+                             Label* miss_label);
+
+  void GenerateFieldTypeChecks(HeapType* field_type, Register value_reg,
+                               Label* miss_label);
 
   static Builtins::Name SlowBuiltin(Code::Kind kind) {
     switch (kind) {
diff --git a/src/ic/ia32/handler-compiler-ia32.cc b/src/ic/ia32/handler-compiler-ia32.cc
index fd97154..90512e9 100644
--- a/src/ic/ia32/handler-compiler-ia32.cc
+++ b/src/ic/ia32/handler-compiler-ia32.cc
@@ -47,6 +47,28 @@
 }
 
 
+void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
+                                                Register slot) {
+  MacroAssembler* masm = this->masm();
+  __ push(vector);
+  __ push(slot);
+}
+
+
+void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
+  MacroAssembler* masm = this->masm();
+  __ pop(slot);
+  __ pop(vector);
+}
+
+
+void PropertyHandlerCompiler::DiscardVectorAndSlot() {
+  MacroAssembler* masm = this->masm();
+  // Remove vector and slot.
+  __ add(esp, Immediate(2 * kPointerSize));
+}
+
+
 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
     MacroAssembler* masm, Label* miss_label, Register receiver,
     Handle<Name> name, Register scratch0, Register scratch1) {
@@ -88,28 +110,23 @@
 
 
 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
-    MacroAssembler* masm, int index, Register prototype, Label* miss) {
-  // Get the global function with the given index.
-  Handle<JSFunction> function(
-      JSFunction::cast(masm->isolate()->native_context()->get(index)));
-  // Check we're still in the same context.
-  Register scratch = prototype;
+    MacroAssembler* masm, int index, Register result, Label* miss) {
   const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX);
-  __ mov(scratch, Operand(esi, offset));
-  __ mov(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset));
-  __ cmp(Operand(scratch, Context::SlotOffset(index)), function);
-  __ j(not_equal, miss);
-
+  __ mov(result, Operand(esi, offset));
+  __ mov(result, FieldOperand(result, GlobalObject::kNativeContextOffset));
+  __ mov(result, Operand(result, Context::SlotOffset(index)));
   // Load its initial map. The global functions all have initial maps.
-  __ Move(prototype, Immediate(Handle<Map>(function->initial_map())));
+  __ mov(result,
+         FieldOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
   // Load the prototype from the initial map.
-  __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
+  __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
 }
 
 
 void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
     MacroAssembler* masm, Register receiver, Register scratch1,
     Register scratch2, Label* miss_label) {
+  DCHECK(!FLAG_vector_ics);
   __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
   __ mov(eax, scratch1);
   __ ret(0);
@@ -329,170 +346,60 @@
 }
 
 
-// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
-// store is successful.
-void NamedStoreHandlerCompiler::GenerateStoreTransition(
-    Handle<Map> transition, Handle<Name> name, Register receiver_reg,
-    Register storage_reg, Register value_reg, Register scratch1,
-    Register scratch2, Register unused, Label* miss_label, Label* slow) {
-  int descriptor = transition->LastAdded();
-  DescriptorArray* descriptors = transition->instance_descriptors();
-  PropertyDetails details = descriptors->GetDetails(descriptor);
-  Representation representation = details.representation();
-  DCHECK(!representation.IsNone());
-
-  if (details.type() == CONSTANT) {
-    Handle<Object> constant(descriptors->GetValue(descriptor), isolate());
-    __ CmpObject(value_reg, constant);
-    __ j(not_equal, miss_label);
-  } else if (representation.IsSmi()) {
-    __ JumpIfNotSmi(value_reg, miss_label);
-  } else if (representation.IsHeapObject()) {
-    __ JumpIfSmi(value_reg, miss_label);
-    HeapType* field_type = descriptors->GetFieldType(descriptor);
-    HeapType::Iterator<Map> it = field_type->Classes();
-    if (!it.Done()) {
-      Label do_store;
-      while (true) {
-        __ CompareMap(value_reg, it.Current());
-        it.Advance();
-        if (it.Done()) {
-          __ j(not_equal, miss_label);
-          break;
-        }
-        __ j(equal, &do_store, Label::kNear);
-      }
-      __ bind(&do_store);
-    }
-  } else if (representation.IsDouble()) {
-    Label do_store, heap_number;
-    __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow, MUTABLE);
-
-    __ JumpIfNotSmi(value_reg, &heap_number);
-    __ SmiUntag(value_reg);
-    __ Cvtsi2sd(xmm0, value_reg);
-    __ SmiTag(value_reg);
-    __ jmp(&do_store);
-
-    __ bind(&heap_number);
-    __ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label,
-                DONT_DO_SMI_CHECK);
-    __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
-
-    __ bind(&do_store);
-    __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0);
-  }
-
-  // Stub never generated for objects that require access checks.
-  DCHECK(!transition->is_access_check_needed());
-
-  // Perform map transition for the receiver if necessary.
-  if (details.type() == FIELD &&
-      Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) {
-    // The properties must be extended before we can store the value.
-    // We jump to a runtime call that extends the properties array.
-    __ pop(scratch1);  // Return address.
-    __ push(receiver_reg);
-    __ push(Immediate(transition));
-    __ push(value_reg);
-    __ push(scratch1);
-    __ TailCallExternalReference(
-        ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
-                          isolate()),
-        3, 1);
-    return;
-  }
-
-  // Update the map of the object.
-  __ mov(scratch1, Immediate(transition));
-  __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
-
-  // Update the write barrier for the map field.
-  __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2,
-                      kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
-
-  if (details.type() == CONSTANT) {
-    DCHECK(value_reg.is(eax));
-    __ ret(0);
-    return;
-  }
-
-  int index = transition->instance_descriptors()->GetFieldIndex(
-      transition->LastAdded());
-
-  // Adjust for the number of properties stored in the object. Even in the
-  // face of a transition we can use the old map here because the size of the
-  // object and the number of in-object properties is not going to change.
-  index -= transition->inobject_properties();
-
-  SmiCheck smi_check =
-      representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
-  // TODO(verwaest): Share this code as a code stub.
-  if (index < 0) {
-    // Set the property straight into the object.
-    int offset = transition->instance_size() + (index * kPointerSize);
-    if (representation.IsDouble()) {
-      __ mov(FieldOperand(receiver_reg, offset), storage_reg);
-    } else {
-      __ mov(FieldOperand(receiver_reg, offset), value_reg);
-    }
-
-    if (!representation.IsSmi()) {
-      // Update the write barrier for the array address.
-      if (!representation.IsDouble()) {
-        __ mov(storage_reg, value_reg);
-      }
-      __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1,
-                          kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check);
-    }
-  } else {
-    // Write to the properties array.
-    int offset = index * kPointerSize + FixedArray::kHeaderSize;
-    // Get the properties array (optimistically).
-    __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
-    if (representation.IsDouble()) {
-      __ mov(FieldOperand(scratch1, offset), storage_reg);
-    } else {
-      __ mov(FieldOperand(scratch1, offset), value_reg);
-    }
-
-    if (!representation.IsSmi()) {
-      // Update the write barrier for the array address.
-      if (!representation.IsDouble()) {
-        __ mov(storage_reg, value_reg);
-      }
-      __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg,
-                          kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check);
-    }
-  }
-
-  // Return the value (register eax).
-  DCHECK(value_reg.is(eax));
-  __ ret(0);
+void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
+  __ mov(this->name(), Immediate(name));
 }
 
 
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
-                                                   Register value_reg,
-                                                   Label* miss_label) {
-  DCHECK(lookup->representation().IsHeapObject());
-  __ JumpIfSmi(value_reg, miss_label);
-  HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
-  Label do_store;
-  while (true) {
-    __ CompareMap(value_reg, it.Current());
-    it.Advance();
-    if (it.Done()) {
-      __ j(not_equal, miss_label);
-      break;
-    }
-    __ j(equal, &do_store, Label::kNear);
+void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
+                                                   Register scratch,
+                                                   Label* miss) {
+  Handle<WeakCell> cell = Map::WeakCellForMap(transition);
+  Register map_reg = StoreTransitionDescriptor::MapRegister();
+  DCHECK(!map_reg.is(scratch));
+  __ LoadWeakValue(map_reg, cell, miss);
+  if (transition->CanBeDeprecated()) {
+    __ mov(scratch, FieldOperand(map_reg, Map::kBitField3Offset));
+    __ and_(scratch, Immediate(Map::Deprecated::kMask));
+    __ j(not_zero, miss);
   }
-  __ bind(&do_store);
+}
 
-  StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
-                      lookup->representation());
-  GenerateTailCall(masm(), stub.GetCode());
+
+void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
+                                                      int descriptor,
+                                                      Register value_reg,
+                                                      Register scratch,
+                                                      Label* miss_label) {
+  DCHECK(!map_reg.is(scratch));
+  DCHECK(!map_reg.is(value_reg));
+  DCHECK(!value_reg.is(scratch));
+  __ LoadInstanceDescriptors(map_reg, scratch);
+  __ mov(scratch,
+         FieldOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
+  __ cmp(value_reg, scratch);
+  __ j(not_equal, miss_label);
+}
+
+
+void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type,
+                                                        Register value_reg,
+                                                        Label* miss_label) {
+  __ JumpIfSmi(value_reg, miss_label);
+  HeapType::Iterator<Map> it = field_type->Classes();
+  if (!it.Done()) {
+    Label do_store;
+    while (true) {
+      __ CompareMap(value_reg, it.Current());
+      it.Advance();
+      if (it.Done()) {
+        __ j(not_equal, miss_label);
+        break;
+      }
+      __ j(equal, &do_store, Label::kNear);
+    }
+    __ bind(&do_store);
+  }
 }
 
 
@@ -546,14 +453,12 @@
       reg = holder_reg;  // From now on the object will be in holder_reg.
       __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
     } else {
-      bool in_new_space = heap()->InNewSpace(*prototype);
-      // Two possible reasons for loading the prototype from the map:
-      // (1) Can't store references to new space in code.
-      // (2) Handler is shared for all receivers with the same prototype
-      //     map (but not necessarily the same prototype instance).
-      bool load_prototype_from_map = in_new_space || depth == 1;
+      Register map_reg = scratch1;
+      __ mov(map_reg, FieldOperand(reg, HeapObject::kMapOffset));
       if (depth != 1 || check == CHECK_ALL_MAPS) {
-        __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
+        Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+        __ CmpWeakValue(map_reg, cell, scratch2);
+        __ j(not_equal, miss);
       }
 
       // Check access rights to the global object.  This has to happen after
@@ -563,24 +468,15 @@
       // global proxy (as opposed to using slow ICs). See corresponding code
       // in LookupForRead().
       if (current_map->IsJSGlobalProxyMap()) {
-        __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
+        __ CheckAccessGlobalProxy(reg, map_reg, scratch2, miss);
+        // Restore map_reg.
+        __ mov(map_reg, FieldOperand(reg, HeapObject::kMapOffset));
       } else if (current_map->IsJSGlobalObjectMap()) {
         GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
                                   name, scratch2, miss);
       }
-
-      if (load_prototype_from_map) {
-        // Save the map in scratch1 for later.
-        __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
-      }
-
       reg = holder_reg;  // From now on the object will be in holder_reg.
-
-      if (load_prototype_from_map) {
-        __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
-      } else {
-        __ mov(reg, prototype);
-      }
+      __ mov(reg, FieldOperand(map_reg, Map::kPrototypeOffset));
     }
 
     // Go to the next object in the prototype chain.
@@ -593,7 +489,10 @@
 
   if (depth != 0 || check == CHECK_ALL_MAPS) {
     // Check the holder map.
-    __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
+    __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
+    Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+    __ CmpWeakValue(scratch1, cell, scratch2);
+    __ j(not_equal, miss);
   }
 
   // Perform security check for access to the global object.
@@ -613,6 +512,10 @@
     Label success;
     __ jmp(&success);
     __ bind(miss);
+    if (IC::ICUseVector(kind())) {
+      DCHECK(kind() == Code::LOAD_IC);
+      PopVectorAndSlot();
+    }
     TailCallBuiltin(masm(), MissBuiltin(kind()));
     __ bind(&success);
   }
@@ -712,7 +615,7 @@
     }
     __ push(holder_reg);
     __ push(this->name());
-
+    InterceptorVectorSlotPush(holder_reg);
     // Invoke an interceptor.  Note: map checks from receiver to
     // interceptor's holder has been compiled before (see a caller
     // of this method.)
@@ -736,6 +639,7 @@
       __ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue)));
     }
 
+    InterceptorVectorSlotPop(holder_reg);
     __ pop(this->name());
     __ pop(holder_reg);
     if (must_preserve_receiver_reg) {
@@ -768,7 +672,7 @@
 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
     Handle<JSObject> object, Handle<Name> name,
     Handle<ExecutableAccessorInfo> callback) {
-  Register holder_reg = Frontend(receiver(), name);
+  Register holder_reg = Frontend(name);
 
   __ pop(scratch1());  // remove the return address
   __ push(receiver());
@@ -814,16 +718,15 @@
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
   Label miss;
-
+  if (IC::ICUseVector(kind())) {
+    PushVectorAndSlot();
+  }
   FrontendHeader(receiver(), name, &miss);
   // Get the value from the cell.
   Register result = StoreDescriptor::ValueRegister();
-  if (masm()->serializer_enabled()) {
-    __ mov(result, Immediate(cell));
-    __ mov(result, FieldOperand(result, PropertyCell::kValueOffset));
-  } else {
-    __ mov(result, Operand::ForCell(cell));
-  }
+  Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
+  __ LoadWeakValue(result, weak_cell, &miss);
+  __ mov(result, FieldOperand(result, PropertyCell::kValueOffset));
 
   // Check for deleted property if property can actually be deleted.
   if (is_configurable) {
@@ -837,6 +740,9 @@
   Counters* counters = isolate()->counters();
   __ IncrementCounter(counters->named_load_global_stub(), 1);
   // The code above already loads the result into the return register.
+  if (IC::ICUseVector(kind())) {
+    DiscardVectorAndSlot();
+  }
   __ ret(0);
 
   FrontendFooter(name, &miss);
diff --git a/src/ic/ia32/ic-compiler-ia32.cc b/src/ic/ia32/ic-compiler-ia32.cc
index ac42f30..f43b641 100644
--- a/src/ic/ia32/ic-compiler-ia32.cc
+++ b/src/ic/ia32/ic-compiler-ia32.cc
@@ -44,10 +44,13 @@
   Label miss;
 
   if (check == PROPERTY &&
-      (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) {
-    // In case we are compiling an IC for dictionary loads and stores, just
+      (kind() == Code::KEYED_STORE_IC || kind() == Code::KEYED_LOAD_IC)) {
+    // In case we are compiling an IC for dictionary loads or stores, just
     // check whether the name is unique.
     if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) {
+      // Keyed loads with dictionaries shouldn't be here, they go generic.
+      // The DCHECK is to protect assumptions when --vector-ics is on.
+      DCHECK(kind() != Code::KEYED_LOAD_IC);
       Register tmp = scratch1();
       __ JumpIfSmi(this->name(), &miss);
       __ mov(tmp, FieldOperand(this->name(), HeapObject::kMapOffset));
@@ -75,7 +78,8 @@
     Handle<Map> map = IC::TypeToMap(*type, isolate());
     if (!map->is_deprecated()) {
       number_of_handled_maps++;
-      __ cmp(map_reg, map);
+      Handle<WeakCell> cell = Map::WeakCellForMap(map);
+      __ CmpWeakValue(map_reg, cell, scratch2());
       if (type->Is(HeapType::Number())) {
         DCHECK(!number_case.is_unused());
         __ bind(&number_case);
@@ -99,16 +103,19 @@
     MapHandleList* receiver_maps, CodeHandleList* handler_stubs,
     MapHandleList* transitioned_maps) {
   Label miss;
-  __ JumpIfSmi(receiver(), &miss, Label::kNear);
-  __ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
+  __ JumpIfSmi(receiver(), &miss);
+  Register map_reg = scratch1();
+  __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
   for (int i = 0; i < receiver_maps->length(); ++i) {
-    __ cmp(scratch1(), receiver_maps->at(i));
+    Handle<WeakCell> cell = Map::WeakCellForMap(receiver_maps->at(i));
+    __ CmpWeakValue(map_reg, cell, scratch2());
     if (transitioned_maps->at(i).is_null()) {
       __ j(equal, handler_stubs->at(i));
     } else {
       Label next_map;
       __ j(not_equal, &next_map, Label::kNear);
-      __ mov(transition_map(), Immediate(transitioned_maps->at(i)));
+      Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
+      __ LoadWeakValue(transition_map(), cell, &miss);
       __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
       __ bind(&next_map);
     }
diff --git a/src/ic/ia32/ic-ia32.cc b/src/ic/ia32/ic-ia32.cc
index 67247d2..9822f26 100644
--- a/src/ic/ia32/ic-ia32.cc
+++ b/src/ic/ia32/ic-ia32.cc
@@ -476,33 +476,6 @@
 }
 
 
-void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
-  // Return address is on the stack.
-  Label miss;
-
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register index = LoadDescriptor::NameRegister();
-  Register scratch = ebx;
-  DCHECK(!scratch.is(receiver) && !scratch.is(index));
-  Register result = eax;
-  DCHECK(!result.is(scratch));
-
-  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
-                                          &miss,  // When not a string.
-                                          &miss,  // When not a number.
-                                          &miss,  // When index out of range.
-                                          STRING_INDEX_IS_ARRAY_INDEX);
-  char_at_generator.GenerateFast(masm);
-  __ ret(0);
-
-  StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-}
-
-
 void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
   // Return address is on the stack.
   Label slow, notin;
@@ -534,7 +507,7 @@
 }
 
 
-static void KeyedStoreGenerateGenericHelper(
+static void KeyedStoreGenerateMegamorphicHelper(
     MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
     KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length) {
   Label transition_smi_elements;
@@ -672,12 +645,12 @@
 }
 
 
-void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
-                                   StrictMode strict_mode) {
+void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
+                                       StrictMode strict_mode) {
   // Return address is on the stack.
   Label slow, fast_object, fast_object_grow;
   Label fast_double, fast_double_grow;
-  Label array, extra, check_if_double_array;
+  Label array, extra, check_if_double_array, maybe_name_key, miss;
   Register receiver = StoreDescriptor::ReceiverRegister();
   Register key = StoreDescriptor::NameRegister();
   DCHECK(receiver.is(edx));
@@ -693,7 +666,7 @@
             1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved);
   __ j(not_zero, &slow);
   // Check that the key is a smi.
-  __ JumpIfNotSmi(key, &slow);
+  __ JumpIfNotSmi(key, &maybe_name_key);
   __ CmpInstanceType(edi, JS_ARRAY_TYPE);
   __ j(equal, &array);
   // Check that the object is some kind of JSObject.
@@ -711,6 +684,18 @@
   // Slow case: call runtime.
   __ bind(&slow);
   PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode);
+  // Never returns to here.
+
+  __ bind(&maybe_name_key);
+  __ mov(ebx, FieldOperand(key, HeapObject::kMapOffset));
+  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
+  __ JumpIfNotUniqueNameInstanceType(ebx, &slow);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::STORE_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::STORE_IC, flags, false, receiver, key, ebx, no_reg);
+  // Cache miss.
+  __ jmp(&miss);
 
   // Extra capacity case: Check if there is extra capacity to
   // perform the store and update the length. Used for adding one
@@ -749,10 +734,14 @@
   __ cmp(key, FieldOperand(receiver, JSArray::kLengthOffset));  // Compare smis.
   __ j(above_equal, &extra);
 
-  KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, &slow,
-                                  kCheckMap, kDontIncrementLength);
-  KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
-                                  &slow, kDontCheckMap, kIncrementLength);
+  KeyedStoreGenerateMegamorphicHelper(masm, &fast_object, &fast_double, &slow,
+                                      kCheckMap, kDontIncrementLength);
+  KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
+                                      &fast_double_grow, &slow, kDontCheckMap,
+                                      kIncrementLength);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
 }
 
 
@@ -778,31 +767,52 @@
 static void LoadIC_PushArgs(MacroAssembler* masm) {
   Register receiver = LoadDescriptor::ReceiverRegister();
   Register name = LoadDescriptor::NameRegister();
-  DCHECK(!ebx.is(receiver) && !ebx.is(name));
+  if (FLAG_vector_ics) {
+    Register slot = VectorLoadICDescriptor::SlotRegister();
+    Register vector = VectorLoadICDescriptor::VectorRegister();
+    DCHECK(!edi.is(receiver) && !edi.is(name) && !edi.is(slot) &&
+           !edi.is(vector));
 
-  __ pop(ebx);
-  __ push(receiver);
-  __ push(name);
-  __ push(ebx);
+    __ pop(edi);
+    __ push(receiver);
+    __ push(name);
+    __ push(slot);
+    __ push(vector);
+    __ push(edi);
+  } else {
+    DCHECK(!ebx.is(receiver) && !ebx.is(name));
+
+    __ pop(ebx);
+    __ push(receiver);
+    __ push(name);
+    __ push(ebx);
+  }
 }
 
 
 void LoadIC::GenerateMiss(MacroAssembler* masm) {
   // Return address is on the stack.
   __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
-
   LoadIC_PushArgs(masm);
 
   // Perform tail call to the entry.
   ExternalReference ref =
       ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
-  __ TailCallExternalReference(ref, 2, 1);
+  int arg_count = FLAG_vector_ics ? 4 : 2;
+  __ TailCallExternalReference(ref, arg_count, 1);
 }
 
 
 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
   // Return address is on the stack.
-  LoadIC_PushArgs(masm);
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register name = LoadDescriptor::NameRegister();
+  DCHECK(!ebx.is(receiver) && !ebx.is(name));
+
+  __ pop(ebx);
+  __ push(receiver);
+  __ push(name);
+  __ push(ebx);
 
   // Perform tail call to the entry.
   __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
@@ -818,13 +828,21 @@
   // Perform tail call to the entry.
   ExternalReference ref =
       ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
-  __ TailCallExternalReference(ref, 2, 1);
+  int arg_count = FLAG_vector_ics ? 4 : 2;
+  __ TailCallExternalReference(ref, arg_count, 1);
 }
 
 
 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
   // Return address is on the stack.
-  LoadIC_PushArgs(masm);
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register name = LoadDescriptor::NameRegister();
+  DCHECK(!ebx.is(receiver) && !ebx.is(name));
+
+  __ pop(ebx);
+  __ push(receiver);
+  __ push(name);
+  __ push(ebx);
 
   // Perform tail call to the entry.
   __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
@@ -836,7 +854,7 @@
   Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
       Code::ComputeHandlerFlags(Code::STORE_IC));
   masm->isolate()->stub_cache()->GenerateProbe(
-      masm, flags, false, StoreDescriptor::ReceiverRegister(),
+      masm, Code::STORE_IC, flags, false, StoreDescriptor::ReceiverRegister(),
       StoreDescriptor::NameRegister(), ebx, no_reg);
 
   // Cache miss: Jump to runtime.
diff --git a/src/ic/ia32/stub-cache-ia32.cc b/src/ic/ia32/stub-cache-ia32.cc
index c1f7c9a..cb560f1 100644
--- a/src/ic/ia32/stub-cache-ia32.cc
+++ b/src/ic/ia32/stub-cache-ia32.cc
@@ -7,7 +7,9 @@
 #if V8_TARGET_ARCH_IA32
 
 #include "src/codegen.h"
+#include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
+#include "src/interface-descriptors.h"
 
 namespace v8 {
 namespace internal {
@@ -16,7 +18,7 @@
 
 
 static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
-                       Code::Flags flags, bool leave_frame,
+                       Code::Kind ic_kind, Code::Flags flags, bool leave_frame,
                        StubCache::Table table, Register name, Register receiver,
                        // Number of the cache entry pointer-size scaled.
                        Register offset, Register extra) {
@@ -56,6 +58,13 @@
     }
 #endif
 
+    if (IC::ICUseVector(ic_kind)) {
+      // The vector and slot were pushed onto the stack before starting the
+      // probe, and need to be dropped before calling the handler.
+      __ pop(VectorLoadICDescriptor::VectorRegister());
+      __ pop(VectorLoadICDescriptor::SlotRegister());
+    }
+
     if (leave_frame) __ leave();
 
     // Jump to the first instruction in the code stub.
@@ -100,6 +109,17 @@
     __ pop(offset);
     __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
 
+    if (IC::ICUseVector(ic_kind)) {
+      // The vector and slot were pushed onto the stack before starting the
+      // probe, and need to be dropped before calling the handler.
+      Register vector = VectorLoadICDescriptor::VectorRegister();
+      Register slot = VectorLoadICDescriptor::SlotRegister();
+      DCHECK(!offset.is(vector) && !offset.is(slot));
+
+      __ pop(vector);
+      __ pop(slot);
+    }
+
     if (leave_frame) __ leave();
 
     // Jump to the first instruction in the code stub.
@@ -113,10 +133,11 @@
 }
 
 
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
-                              bool leave_frame, Register receiver,
-                              Register name, Register scratch, Register extra,
-                              Register extra2, Register extra3) {
+void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
+                              Code::Flags flags, bool leave_frame,
+                              Register receiver, Register name,
+                              Register scratch, Register extra, Register extra2,
+                              Register extra3) {
   Label miss;
 
   // Assert that code is valid.  The multiplying code relies on the entry size
@@ -159,8 +180,8 @@
   DCHECK(kCacheIndexShift == kPointerSizeLog2);
 
   // Probe the primary table.
-  ProbeTable(isolate(), masm, flags, leave_frame, kPrimary, name, receiver,
-             offset, extra);
+  ProbeTable(isolate(), masm, ic_kind, flags, leave_frame, kPrimary, name,
+             receiver, offset, extra);
 
   // Primary miss: Compute hash for secondary probe.
   __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
@@ -172,8 +193,8 @@
   __ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift);
 
   // Probe the secondary table.
-  ProbeTable(isolate(), masm, flags, leave_frame, kSecondary, name, receiver,
-             offset, extra);
+  ProbeTable(isolate(), masm, ic_kind, flags, leave_frame, kSecondary, name,
+             receiver, offset, extra);
 
   // Cache miss: Fall-through and let caller handle the miss by
   // entering the runtime system.
diff --git a/src/ic/ic-compiler.cc b/src/ic/ic-compiler.cc
index aeae4ba..e087acf 100644
--- a/src/ic/ic-compiler.cc
+++ b/src/ic/ic-compiler.cc
@@ -57,6 +57,16 @@
 
   CacheHolderFlag flag;
   Handle<Map> stub_holder = IC::GetICCacheHolder(*type, isolate, &flag);
+  if (kind == Code::KEYED_STORE_IC) {
+    // Always set the "property" bit.
+    extra_ic_state =
+        KeyedStoreIC::IcCheckTypeField::update(extra_ic_state, PROPERTY);
+    DCHECK(STANDARD_STORE ==
+           KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state));
+  } else if (kind == Code::KEYED_LOAD_IC) {
+    extra_ic_state = KeyedLoadIC::IcCheckTypeField::update(extra_ic_state,
+                                                           PROPERTY);
+  }
 
   Handle<Code> ic;
   // There are multiple string maps that all use the same prototype. That
@@ -68,13 +78,6 @@
     if (!ic.is_null()) return ic;
   }
 
-#ifdef DEBUG
-  if (kind == Code::KEYED_STORE_IC) {
-    DCHECK(STANDARD_STORE ==
-           KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state));
-  }
-#endif
-
   PropertyICCompiler ic_compiler(isolate, kind, extra_ic_state, flag);
   ic = ic_compiler.CompileMonomorphic(type, handler, name, PROPERTY);
 
@@ -86,16 +89,34 @@
 Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic(
     Handle<Map> receiver_map) {
   Isolate* isolate = receiver_map->GetIsolate();
+  DCHECK(KeyedLoadIC::GetKeyType(kNoExtraICState) == ELEMENT);
   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC);
   Handle<Name> name = isolate->factory()->KeyedLoadMonomorphic_string();
 
   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
 
+  Handle<Code> stub = ComputeKeyedLoadMonomorphicHandler(receiver_map);
+  PropertyICCompiler compiler(isolate, Code::KEYED_LOAD_IC);
+  Handle<Code> code =
+      compiler.CompileMonomorphic(HeapType::Class(receiver_map, isolate), stub,
+                                  isolate->factory()->empty_string(), ELEMENT);
+
+  Map::UpdateCodeCache(receiver_map, name, code);
+  return code;
+}
+
+
+Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
+    Handle<Map> receiver_map) {
+  Isolate* isolate = receiver_map->GetIsolate();
   ElementsKind elements_kind = receiver_map->elements_kind();
   Handle<Code> stub;
   if (receiver_map->has_indexed_interceptor()) {
     stub = LoadIndexedInterceptorStub(isolate).GetCode();
+  } else if (receiver_map->IsStringMap()) {
+    // We have a string.
+    stub = LoadIndexedStringStub(isolate).GetCode();
   } else if (receiver_map->has_sloppy_arguments_elements()) {
     stub = KeyedLoadSloppyArgumentsStub(isolate).GetCode();
   } else if (receiver_map->has_fast_elements() ||
@@ -107,13 +128,7 @@
   } else {
     stub = LoadDictionaryElementStub(isolate).GetCode();
   }
-  PropertyICCompiler compiler(isolate, Code::KEYED_LOAD_IC);
-  Handle<Code> code =
-      compiler.CompileMonomorphic(HeapType::Class(receiver_map, isolate), stub,
-                                  isolate->factory()->empty_string(), ELEMENT);
-
-  Map::UpdateCodeCache(receiver_map, name, code);
-  return code;
+  return stub;
 }
 
 
@@ -229,7 +244,8 @@
   }
 
   Code::FindAndReplacePattern pattern;
-  pattern.Add(isolate->factory()->meta_map(), receiver_map);
+  Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
+  pattern.Add(isolate->factory()->meta_map(), cell);
   Handle<Code> ic = stub->GetCodeCopy(pattern);
 
   if (!receiver_map->is_dictionary_map()) {
@@ -244,6 +260,7 @@
 Handle<Code> PropertyICCompiler::ComputeKeyedLoadPolymorphic(
     MapHandleList* receiver_maps) {
   Isolate* isolate = receiver_maps->at(0)->GetIsolate();
+  DCHECK(KeyedLoadIC::GetKeyType(kNoExtraICState) == ELEMENT);
   Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
   Handle<PolymorphicCodeCache> cache =
       isolate->factory()->polymorphic_code_cache();
@@ -363,7 +380,6 @@
   Code::Flags flags =
       Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder());
   Handle<Code> code = GetCodeWithFlags(flags, name);
-  IC::RegisterWeakMapDependency(code);
   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
   return code;
 }
@@ -434,7 +450,10 @@
     stub = StoreElementStub(isolate(), elements_kind).GetCode();
   }
 
-  __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
+  Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
+
+  __ DispatchWeakMap(receiver(), scratch1(), scratch2(), cell, stub,
+                     DO_SMI_CHECK);
 
   TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
 
diff --git a/src/ic/ic-compiler.h b/src/ic/ic-compiler.h
index 3b12157..dd898ae 100644
--- a/src/ic/ic-compiler.h
+++ b/src/ic/ic-compiler.h
@@ -11,9 +11,6 @@
 namespace internal {
 
 
-enum IcCheckType { ELEMENT, PROPERTY };
-
-
 class PropertyICCompiler : public PropertyAccessCompiler {
  public:
   // Finds the Code object stored in the Heap::non_monomorphic_cache().
@@ -37,6 +34,8 @@
                                          ExtraICState extra_ic_state);
 
   // Keyed
+  static Handle<Code> ComputeKeyedLoadMonomorphicHandler(
+      Handle<Map> receiver_map);
   static Handle<Code> ComputeKeyedLoadMonomorphic(Handle<Map> receiver_map);
 
   static Handle<Code> ComputeKeyedStoreMonomorphic(
diff --git a/src/ic/ic-inl.h b/src/ic/ic-inl.h
index e10fb45..58d7d46 100644
--- a/src/ic/ic-inl.h
+++ b/src/ic/ic-inl.h
@@ -96,6 +96,12 @@
 void IC::SetTargetAtAddress(Address address, Code* target,
                             ConstantPoolArray* constant_pool) {
   DCHECK(target->is_inline_cache_stub() || target->is_compare_ic_stub());
+
+  // Don't use this for load_ics when --vector-ics is turned on.
+  DCHECK(!(FLAG_vector_ics && target->is_inline_cache_stub()) ||
+         (target->kind() != Code::LOAD_IC &&
+          target->kind() != Code::KEYED_LOAD_IC));
+
   Heap* heap = target->GetHeap();
   Code* old_target = GetTargetAtAddress(address, constant_pool);
 #ifdef DEBUG
@@ -119,9 +125,6 @@
 
 
 void IC::set_target(Code* code) {
-#ifdef VERIFY_HEAP
-  code->VerifyEmbeddedObjectsDependency();
-#endif
   SetTargetAtAddress(address(), code, constant_pool());
   target_set_ = true;
 }
@@ -208,20 +211,11 @@
 }
 
 
-IC::State CallIC::FeedbackToState(Handle<TypeFeedbackVector> vector,
-                                  Handle<Smi> slot) const {
-  IC::State state = UNINITIALIZED;
-  Object* feedback = vector->get(slot->value());
-
-  if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate())) {
-    state = GENERIC;
-  } else if (feedback->IsAllocationSite() || feedback->IsJSFunction()) {
-    state = MONOMORPHIC;
-  } else {
-    CHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate()));
-  }
-
-  return state;
+inline Code* IC::get_host() {
+  return isolate()
+      ->inner_pointer_to_code_cache()
+      ->GetCacheEntry(address())
+      ->code;
 }
 }
 }  // namespace v8::internal
diff --git a/src/ic/ic-state.cc b/src/ic/ic-state.cc
index 4238a72..9c883ad 100644
--- a/src/ic/ic-state.cc
+++ b/src/ic/ic-state.cc
@@ -10,6 +10,7 @@
 namespace v8 {
 namespace internal {
 
+// static
 void ICUtility::Clear(Isolate* isolate, Address address,
                       ConstantPoolArray* constant_pool) {
   IC::Clear(isolate, address, constant_pool);
@@ -28,7 +29,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const CallICState& s) {
+std::ostream& operator<<(std::ostream& os, const CallICState& s) {
   return os << "(args(" << s.arg_count() << "), "
             << (s.call_type() == CallICState::METHOD ? "METHOD" : "FUNCTION")
             << ", ";
@@ -308,7 +309,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const BinaryOpICState& s) {
+std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s) {
   os << "(" << Token::Name(s.op_);
   if (s.mode_ == OVERWRITE_LEFT)
     os << "_ReuseLeft";
diff --git a/src/ic/ic-state.h b/src/ic/ic-state.h
index b84bdb9..72fc865 100644
--- a/src/ic/ic-state.h
+++ b/src/ic/ic-state.h
@@ -51,7 +51,7 @@
 };
 
 
-OStream& operator<<(OStream& os, const CallICState& s);
+std::ostream& operator<<(std::ostream& os, const CallICState& s);
 
 
 // Mode to overwrite BinaryExpression values.
@@ -139,7 +139,7 @@
   Isolate* isolate() const { return isolate_; }
 
  private:
-  friend OStream& operator<<(OStream& os, const BinaryOpICState& s);
+  friend std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s);
 
   enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
 
@@ -173,7 +173,7 @@
 };
 
 
-OStream& operator<<(OStream& os, const BinaryOpICState& s);
+std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s);
 
 
 class CompareICState {
diff --git a/src/ic/ic.cc b/src/ic/ic.cc
index 1f3c750..0707536 100644
--- a/src/ic/ic.cc
+++ b/src/ic/ic.cc
@@ -17,7 +17,7 @@
 #include "src/ic/ic-compiler.h"
 #include "src/ic/stub-cache.h"
 #include "src/prototype.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -89,8 +89,8 @@
 
 void IC::TraceIC(const char* type, Handle<Object> name) {
   if (FLAG_trace_ic) {
-    Code* new_target = raw_target();
-    State new_state = new_target->ic_state();
+    State new_state =
+        UseVector() ? nexus()->StateFromFeedback() : raw_target()->ic_state();
     TraceIC(type, name, state(), new_state);
   }
 }
@@ -122,7 +122,7 @@
       modifier = GetTransitionMarkModifier(
           KeyedStoreIC::GetKeyedAccessStoreMode(extra_state));
     }
-    PrintF(" (%c->%c%s)", TransitionMarkFromState(old_state),
+    PrintF(" (%c->%c%s) ", TransitionMarkFromState(old_state),
            TransitionMarkFromState(new_state), modifier);
 #ifdef OBJECT_PRINT
     OFStream os(stdout);
@@ -134,12 +134,16 @@
   }
 }
 
-#define TRACE_IC(type, name) TraceIC(type, name)
-#define TRACE_VECTOR_IC(type, name, old_state, new_state) \
-  TraceIC(type, name, old_state, new_state)
 
-IC::IC(FrameDepth depth, Isolate* isolate)
-    : isolate_(isolate), target_set_(false), target_maps_set_(false) {
+#define TRACE_IC(type, name) TraceIC(type, name)
+
+
+IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus,
+       bool for_queries_only)
+    : isolate_(isolate),
+      target_set_(false),
+      target_maps_set_(false),
+      nexus_(nexus) {
   // To improve the performance of the (much used) IC code, we unfold a few
   // levels of the stack frame iteration code. This yields a ~35% speedup when
   // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
@@ -178,8 +182,10 @@
   }
   pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
   target_ = handle(raw_target(), isolate);
-  state_ = target_->ic_state();
   kind_ = target_->kind();
+  state_ = (!for_queries_only && UseVector()) ? nexus->StateFromFeedback()
+                                              : target_->ic_state();
+  old_state_ = state_;
   extra_ic_state_ = target_->extra_ic_state();
 }
 
@@ -252,7 +258,11 @@
                                                 Handle<String> name) {
   if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
   Handle<Map> receiver_map = TypeToMap(*receiver_type(), isolate());
-  maybe_handler_ = target()->FindHandlerForMap(*receiver_map);
+  if (UseVector()) {
+    maybe_handler_ = nexus()->FindHandlerForMap(receiver_map);
+  } else {
+    maybe_handler_ = target()->FindHandlerForMap(*receiver_map);
+  }
 
   // The current map wasn't handled yet. There's no reason to stay monomorphic,
   // *unless* we're moving from a deprecated map to its replacement, or
@@ -304,7 +314,8 @@
   if (target()->is_keyed_stub()) {
     // Determine whether the failure is due to a name failure.
     if (!name->IsName()) return false;
-    Name* stub_name = target()->FindFirstName();
+    Name* stub_name =
+        UseVector() ? nexus()->FindFirstName() : target()->FindFirstName();
     if (*name != stub_name) return false;
   }
 
@@ -333,7 +344,7 @@
   // an inline cache miss for the builtins object after lazily loading
   // JavaScript builtins, we return uninitialized as the state to
   // force the inline cache back to monomorphic state.
-  if (receiver->IsJSBuiltinsObject()) state_ = UNINITIALIZED;
+  if (receiver->IsJSBuiltinsObject()) state_ = PREMONOMORPHIC;
 }
 
 
@@ -419,10 +430,34 @@
 }
 
 
+// static
+void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host,
+                               TypeFeedbackVector* vector, State old_state,
+                               State new_state) {
+  if (host->kind() != Code::FUNCTION) return;
+
+  if (FLAG_type_info_threshold > 0) {
+    int polymorphic_delta = 0;  // "Polymorphic" here includes monomorphic.
+    int generic_delta = 0;      // "Generic" here includes megamorphic.
+    ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
+                              &generic_delta);
+    vector->change_ic_with_type_info_count(polymorphic_delta);
+    vector->change_ic_generic_count(generic_delta);
+  }
+  TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
+  info->change_own_type_change_checksum();
+  host->set_profiler_ticks(0);
+  isolate->runtime_profiler()->NotifyICChanged();
+  // TODO(2029): When an optimized function is patched, it would
+  // be nice to propagate the corresponding type information to its
+  // unoptimized version for the benefit of later inlining.
+}
+
+
 void IC::PostPatching(Address address, Code* target, Code* old_target) {
   // Type vector based ICs update these statistics at a different time because
   // they don't always patch on state change.
-  if (target->kind() == Code::CALL_IC) return;
+  if (ICUseVector(target->kind())) return;
 
   Isolate* isolate = target->GetHeap()->isolate();
   State old_state = UNINITIALIZED;
@@ -439,42 +474,6 @@
 }
 
 
-void IC::RegisterWeakMapDependency(Handle<Code> stub) {
-  if (FLAG_collect_maps && FLAG_weak_embedded_maps_in_ic &&
-      stub->CanBeWeakStub()) {
-    DCHECK(!stub->is_weak_stub());
-    MapHandleList maps;
-    stub->FindAllMaps(&maps);
-    if (maps.length() == 1 && stub->IsWeakObjectInIC(*maps.at(0))) {
-      Map::AddDependentIC(maps.at(0), stub);
-      stub->mark_as_weak_stub();
-      if (FLAG_enable_ool_constant_pool) {
-        stub->constant_pool()->set_weak_object_state(
-            ConstantPoolArray::WEAK_OBJECTS_IN_IC);
-      }
-    }
-  }
-}
-
-
-void IC::InvalidateMaps(Code* stub) {
-  DCHECK(stub->is_weak_stub());
-  stub->mark_as_invalidated_weak_stub();
-  Isolate* isolate = stub->GetIsolate();
-  Heap* heap = isolate->heap();
-  Object* undefined = heap->undefined_value();
-  int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
-  for (RelocIterator it(stub, mode_mask); !it.done(); it.next()) {
-    RelocInfo::Mode mode = it.rinfo()->rmode();
-    if (mode == RelocInfo::EMBEDDED_OBJECT &&
-        it.rinfo()->target_object()->IsMap()) {
-      it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
-    }
-  }
-  CpuFeatures::FlushICache(stub->instruction_start(), stub->instruction_size());
-}
-
-
 void IC::Clear(Isolate* isolate, Address address,
                ConstantPoolArray* constant_pool) {
   Code* target = GetTargetAtAddress(address, constant_pool);
@@ -484,19 +483,20 @@
 
   switch (target->kind()) {
     case Code::LOAD_IC:
+      if (FLAG_vector_ics) return;
       return LoadIC::Clear(isolate, address, target, constant_pool);
     case Code::KEYED_LOAD_IC:
+      if (FLAG_vector_ics) return;
       return KeyedLoadIC::Clear(isolate, address, target, constant_pool);
     case Code::STORE_IC:
       return StoreIC::Clear(isolate, address, target, constant_pool);
     case Code::KEYED_STORE_IC:
       return KeyedStoreIC::Clear(isolate, address, target, constant_pool);
-    case Code::CALL_IC:
-      return CallIC::Clear(isolate, address, target, constant_pool);
     case Code::COMPARE_IC:
       return CompareIC::Clear(isolate, address, target, constant_pool);
     case Code::COMPARE_NIL_IC:
       return CompareNilIC::Clear(address, target, constant_pool);
+    case Code::CALL_IC:  // CallICs are vector-based and cleared differently.
     case Code::BINARY_OP_IC:
     case Code::TO_BOOLEAN_IC:
       // Clearing these is tricky and does not
@@ -510,7 +510,9 @@
 
 void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target,
                         ConstantPoolArray* constant_pool) {
+  DCHECK(!FLAG_vector_ics);
   if (IsCleared(target)) return;
+
   // Make sure to also clear the map used in inline fast cases.  If we
   // do not clear these maps, cached code can keep objects alive
   // through the embedded maps.
@@ -518,14 +520,33 @@
 }
 
 
-void CallIC::Clear(Isolate* isolate, Address address, Code* target,
-                   ConstantPoolArray* constant_pool) {
-  // Currently, CallIC doesn't have state changes.
+void KeyedLoadIC::Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus) {
+  if (IsCleared(nexus)) return;
+  // Make sure to also clear the map used in inline fast cases.  If we
+  // do not clear these maps, cached code can keep objects alive
+  // through the embedded maps.
+  State state = nexus->StateFromFeedback();
+  nexus->ConfigurePremonomorphic();
+  OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
+}
+
+
+void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
+  // Determine our state.
+  Object* feedback = nexus->vector()->Get(nexus->slot());
+  State state = nexus->StateFromFeedback();
+
+  if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
+    nexus->ConfigureUninitialized();
+    // The change in state must be processed.
+    OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, UNINITIALIZED);
+  }
 }
 
 
 void LoadIC::Clear(Isolate* isolate, Address address, Code* target,
                    ConstantPoolArray* constant_pool) {
+  DCHECK(!FLAG_vector_ics);
   if (IsCleared(target)) return;
   Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::LOAD_IC,
                                                       target->extra_ic_state());
@@ -533,6 +554,14 @@
 }
 
 
+void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) {
+  if (IsCleared(nexus)) return;
+  State state = nexus->StateFromFeedback();
+  nexus->ConfigurePremonomorphic();
+  OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
+}
+
+
 void StoreIC::Clear(Isolate* isolate, Address address, Code* target,
                     ConstantPoolArray* constant_pool) {
   if (IsCleared(target)) return;
@@ -583,6 +612,69 @@
 }
 
 
+void IC::ConfigureVectorState(IC::State new_state) {
+  DCHECK(UseVector());
+  if (kind() == Code::LOAD_IC) {
+    LoadICNexus* nexus = casted_nexus<LoadICNexus>();
+    if (new_state == PREMONOMORPHIC) {
+      nexus->ConfigurePremonomorphic();
+    } else if (new_state == MEGAMORPHIC) {
+      nexus->ConfigureMegamorphic();
+    } else {
+      UNREACHABLE();
+    }
+  } else if (kind() == Code::KEYED_LOAD_IC) {
+    KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
+    if (new_state == GENERIC) {
+      nexus->ConfigureGeneric();
+    } else if (new_state == PREMONOMORPHIC) {
+      nexus->ConfigurePremonomorphic();
+    } else {
+      UNREACHABLE();
+    }
+  } else {
+    UNREACHABLE();
+  }
+
+  OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
+                        new_state);
+}
+
+
+void IC::ConfigureVectorState(Handle<Name> name, Handle<HeapType> type,
+                              Handle<Code> handler) {
+  DCHECK(UseVector());
+  if (kind() == Code::LOAD_IC) {
+    LoadICNexus* nexus = casted_nexus<LoadICNexus>();
+    nexus->ConfigureMonomorphic(type, handler);
+  } else {
+    DCHECK(kind() == Code::KEYED_LOAD_IC);
+    KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
+    nexus->ConfigureMonomorphic(name, type, handler);
+  }
+
+  OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
+                        MONOMORPHIC);
+}
+
+
+void IC::ConfigureVectorState(Handle<Name> name, TypeHandleList* types,
+                              CodeHandleList* handlers) {
+  DCHECK(UseVector());
+  if (kind() == Code::LOAD_IC) {
+    LoadICNexus* nexus = casted_nexus<LoadICNexus>();
+    nexus->ConfigurePolymorphic(types, handlers);
+  } else {
+    DCHECK(kind() == Code::KEYED_LOAD_IC);
+    KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
+    nexus->ConfigurePolymorphic(name, types, handlers);
+  }
+
+  OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
+                        POLYMORPHIC);
+}
+
+
 MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
   // If the object is undefined or null it's illegal to try to get any
   // of its properties; throw a TypeError in that case.
@@ -596,7 +688,11 @@
   if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
     // Rewrite to the generic keyed load stub.
     if (FLAG_use_ic) {
-      set_target(*KeyedLoadIC::generic_stub(isolate()));
+      if (UseVector()) {
+        ConfigureVectorState(GENERIC);
+      } else {
+        set_target(*KeyedLoadIC::generic_stub(isolate()));
+      }
       TRACE_IC("LoadIC", name);
       TRACE_GENERIC_IC(isolate(), "LoadIC", "name as array index");
     }
@@ -609,6 +705,25 @@
 
   bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
 
+  if (FLAG_harmony_scoping && object->IsGlobalObject() && name->IsString()) {
+    // Look up in script context table.
+    Handle<String> str_name = Handle<String>::cast(name);
+    Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
+    Handle<ScriptContextTable> script_contexts(
+        global->native_context()->script_context_table());
+
+    ScriptContextTable::LookupResult lookup_result;
+    if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
+      if (use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) {
+        LoadScriptContextFieldStub stub(isolate(), &lookup_result);
+        PatchCache(name, stub.GetCode());
+      }
+      return FixedArray::get(ScriptContextTable::GetContext(
+                                 script_contexts, lookup_result.context_index),
+                             lookup_result.slot_index);
+    }
+  }
+
   // Named lookup in the object.
   LookupIterator it(object, name);
   LookupForRead(&it);
@@ -681,15 +796,26 @@
       number_of_types - deprecated_types - (handler_to_overwrite != -1);
 
   if (number_of_valid_types >= 4) return false;
-  if (number_of_types == 0) return false;
-  if (!target()->FindHandlers(&handlers, types.length())) return false;
+  if (number_of_types == 0 && state() != MONOMORPHIC &&
+      state() != POLYMORPHIC) {
+    return false;
+  }
+  if (UseVector()) {
+    if (!nexus()->FindHandlers(&handlers, types.length())) return false;
+  } else {
+    if (!target()->FindHandlers(&handlers, types.length())) return false;
+  }
 
   number_of_valid_types++;
   if (number_of_valid_types > 1 && target()->is_keyed_stub()) return false;
   Handle<Code> ic;
   if (number_of_valid_types == 1) {
-    ic = PropertyICCompiler::ComputeMonomorphic(kind(), name, type, code,
-                                                extra_ic_state());
+    if (UseVector()) {
+      ConfigureVectorState(name, receiver_type(), code);
+    } else {
+      ic = PropertyICCompiler::ComputeMonomorphic(kind(), name, type, code,
+                                                  extra_ic_state());
+    }
   } else {
     if (handler_to_overwrite >= 0) {
       handlers.Set(handler_to_overwrite, code);
@@ -700,11 +826,17 @@
       types.Add(type);
       handlers.Add(code);
     }
-    ic = PropertyICCompiler::ComputePolymorphic(kind(), &types, &handlers,
-                                                number_of_valid_types, name,
-                                                extra_ic_state());
+
+    if (UseVector()) {
+      ConfigureVectorState(name, &types, &handlers);
+    } else {
+      ic = PropertyICCompiler::ComputePolymorphic(kind(), &types, &handlers,
+                                                  number_of_valid_types, name,
+                                                  extra_ic_state());
+    }
   }
-  set_target(*ic);
+
+  if (!UseVector()) set_target(*ic);
   return true;
 }
 
@@ -752,9 +884,13 @@
 
 void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) {
   DCHECK(handler->is_handler());
-  Handle<Code> ic = PropertyICCompiler::ComputeMonomorphic(
-      kind(), name, receiver_type(), handler, extra_ic_state());
-  set_target(*ic);
+  if (UseVector()) {
+    ConfigureVectorState(name, receiver_type(), handler);
+  } else {
+    Handle<Code> ic = PropertyICCompiler::ComputeMonomorphic(
+        kind(), name, receiver_type(), handler, extra_ic_state());
+    set_target(*ic);
+  }
 }
 
 
@@ -795,29 +931,72 @@
     case POLYMORPHIC:
       if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) {
         if (UpdatePolymorphicIC(name, code)) break;
+        // For keyed stubs, we can't know whether old handlers were for the
+        // same key.
         CopyICToMegamorphicCache(name);
       }
-      set_target(*megamorphic_stub());
+      if (UseVector()) {
+        ConfigureVectorState(kind() == Code::KEYED_LOAD_IC ? GENERIC
+                                                           : MEGAMORPHIC);
+      } else {
+        set_target(*megamorphic_stub());
+      }
     // Fall through.
     case MEGAMORPHIC:
       UpdateMegamorphicCache(*receiver_type(), *name, *code);
+      // Indicate that we've handled this case.
+      target_set_ = true;
       break;
     case DEBUG_STUB:
       break;
     case DEFAULT:
-    case GENERIC:
       UNREACHABLE();
       break;
+    case GENERIC:
+      // The generic keyed store stub re-uses store handlers, which can miss.
+      // That's ok, no reason to do anything.
+      DCHECK(target()->kind() == Code::KEYED_STORE_IC);
+      break;
   }
 }
 
 
 Handle<Code> LoadIC::initialize_stub(Isolate* isolate,
                                      ExtraICState extra_state) {
+  if (FLAG_vector_ics) {
+    return LoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode();
+  }
+
   return PropertyICCompiler::ComputeLoad(isolate, UNINITIALIZED, extra_state);
 }
 
 
+Handle<Code> LoadIC::initialize_stub_in_optimized_code(
+    Isolate* isolate, ExtraICState extra_state) {
+  if (FLAG_vector_ics) {
+    return VectorLoadStub(isolate, LoadICState(extra_state)).GetCode();
+  }
+  return initialize_stub(isolate, extra_state);
+}
+
+
+Handle<Code> KeyedLoadIC::initialize_stub(Isolate* isolate) {
+  if (FLAG_vector_ics) {
+    return KeyedLoadICTrampolineStub(isolate).GetCode();
+  }
+
+  return isolate->builtins()->KeyedLoadIC_Initialize();
+}
+
+
+Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(Isolate* isolate) {
+  if (FLAG_vector_ics) {
+    return VectorKeyedLoadStub(isolate).GetCode();
+  }
+  return initialize_stub(isolate);
+}
+
+
 Handle<Code> LoadIC::megamorphic_stub() {
   if (kind() == Code::LOAD_IC) {
     MegamorphicLoadStub stub(isolate(), LoadICState(extra_ic_state()));
@@ -831,6 +1010,7 @@
 
 Handle<Code> LoadIC::pre_monomorphic_stub(Isolate* isolate,
                                           ExtraICState extra_state) {
+  DCHECK(!FLAG_vector_ics);
   return PropertyICCompiler::ComputeLoad(isolate, PREMONOMORPHIC, extra_state);
 }
 
@@ -860,7 +1040,11 @@
   if (state() == UNINITIALIZED) {
     // This is the first time we execute this inline cache. Set the target to
     // the pre monomorphic stub to delay setting the monomorphic state.
-    set_target(*pre_monomorphic_stub());
+    if (UseVector()) {
+      ConfigureVectorState(PREMONOMORPHIC);
+    } else {
+      set_target(*pre_monomorphic_stub());
+    }
     TRACE_IC("LoadIC", lookup->name());
     return;
   }
@@ -888,7 +1072,8 @@
 
 
 void IC::UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) {
-  if (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC) return;
+  // Megamorphic state isn't implemented for keyed loads currently.
+  if (kind() == Code::KEYED_LOAD_IC) return;
   Map* map = *TypeToMap(type, isolate());
   isolate()->stub_cache()->Set(name, map, code);
 }
@@ -1121,15 +1306,20 @@
 }
 
 
-Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
+Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
+  Handle<Code> null_handle;
   Handle<Map> receiver_map(receiver->map(), isolate());
   MapHandleList target_receiver_maps;
-  if (target().is_identical_to(string_stub())) {
-    target_receiver_maps.Add(isolate()->factory()->string_map());
-  } else {
-    TargetMaps(&target_receiver_maps);
-  }
+  TargetMaps(&target_receiver_maps);
+
+
   if (target_receiver_maps.length() == 0) {
+    if (FLAG_vector_ics) {
+      Handle<Code> handler =
+          PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map);
+      ConfigureVectorState(Handle<Name>::null(), receiver_type(), handler);
+      return null_handle;
+    }
     return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map);
   }
 
@@ -1140,9 +1330,16 @@
   // monomorphic. If this optimistic assumption is not true, the IC will
   // miss again and it will become polymorphic and support both the
   // untransitioned and transitioned maps.
-  if (state() == MONOMORPHIC && IsMoreGeneralElementsKindTransition(
-                                    target_receiver_maps.at(0)->elements_kind(),
-                                    receiver->GetElementsKind())) {
+  if (state() == MONOMORPHIC && !receiver->IsString() &&
+      IsMoreGeneralElementsKindTransition(
+          target_receiver_maps.at(0)->elements_kind(),
+          Handle<JSObject>::cast(receiver)->GetElementsKind())) {
+    if (FLAG_vector_ics) {
+      Handle<Code> handler =
+          PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map);
+      ConfigureVectorState(Handle<Name>::null(), receiver_type(), handler);
+      return null_handle;
+    }
     return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map);
   }
 
@@ -1154,6 +1351,10 @@
     // If the miss wasn't due to an unseen map, a polymorphic stub
     // won't help, use the generic stub.
     TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice");
+    if (FLAG_vector_ics) {
+      ConfigureVectorState(GENERIC);
+      return null_handle;
+    }
     return generic_stub();
   }
 
@@ -1161,9 +1362,25 @@
   // version of the IC.
   if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
     TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded");
+    if (FLAG_vector_ics) {
+      ConfigureVectorState(GENERIC);
+      return null_handle;
+    }
     return generic_stub();
   }
 
+  if (FLAG_vector_ics) {
+    CodeHandleList handlers(target_receiver_maps.length());
+    ElementHandlerCompiler compiler(isolate());
+    compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
+    TypeHandleList types(target_receiver_maps.length());
+    for (int i = 0; i < target_receiver_maps.length(); i++) {
+      types.Add(HeapType::Class(target_receiver_maps.at(i), isolate()));
+    }
+    ConfigureVectorState(Handle<Name>::null(), &types, &handlers);
+    return null_handle;
+  }
+
   return PropertyICCompiler::ComputeKeyedLoadPolymorphic(&target_receiver_maps);
 }
 
@@ -1190,22 +1407,23 @@
                                LoadIC::Load(object, Handle<Name>::cast(key)),
                                Object);
   } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
-    if (object->IsString() && key->IsNumber()) {
-      if (state() == UNINITIALIZED) stub = string_stub();
-    } else if (object->IsJSObject()) {
-      Handle<JSObject> receiver = Handle<JSObject>::cast(object);
-      if (!Object::ToSmi(isolate(), key).is_null()) {
+    if (object->IsJSObject() || (object->IsString() && key->IsNumber())) {
+      Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
+      if (object->IsString() || !Object::ToSmi(isolate(), key).is_null()) {
         stub = LoadElementStub(receiver);
       }
     }
   }
 
   if (!is_target_set()) {
-    Code* generic = *generic_stub();
-    if (*stub == generic) {
-      TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
+    if (!FLAG_vector_ics) {
+      Code* generic = *generic_stub();
+      if (*stub == generic) {
+        TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
+      }
+
+      set_target(*stub);
     }
-    set_target(*stub);
     TRACE_IC("LoadIC", key);
   }
 
@@ -1280,6 +1498,32 @@
 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
                                    Handle<Object> value,
                                    JSReceiver::StoreFromKeyed store_mode) {
+  if (FLAG_harmony_scoping && object->IsGlobalObject() && name->IsString()) {
+    // Look up in script context table.
+    Handle<String> str_name = Handle<String>::cast(name);
+    Handle<GlobalObject> global = Handle<GlobalObject>::cast(object);
+    Handle<ScriptContextTable> script_contexts(
+        global->native_context()->script_context_table());
+
+    ScriptContextTable::LookupResult lookup_result;
+    if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
+      Handle<Context> script_context = ScriptContextTable::GetContext(
+          script_contexts, lookup_result.context_index);
+      if (lookup_result.mode == CONST) {
+        return TypeError("harmony_const_assign", object, name);
+      }
+
+      if (FLAG_use_ic &&
+          StoreScriptContextFieldStub::Accepted(&lookup_result)) {
+        StoreScriptContextFieldStub stub(isolate(), &lookup_result);
+        PatchCache(name, stub.GetCode());
+      }
+
+      script_context->set(lookup_result.slot_index, *value);
+      return value;
+    }
+  }
+
   // TODO(verwaest): Let SetProperty do the migration, since storing a property
   // might deprecate the current map again, if value does not fit.
   if (MigrateDeprecated(object) || object->IsJSProxy()) {
@@ -1359,9 +1603,9 @@
   } else {
     DCHECK(kind() == Code::KEYED_STORE_IC);
     if (strict_mode() == STRICT) {
-      return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
+      return isolate()->builtins()->KeyedStoreIC_Megamorphic_Strict();
     } else {
-      return isolate()->builtins()->KeyedStoreIC_Generic();
+      return isolate()->builtins()->KeyedStoreIC_Megamorphic();
     }
   }
 }
@@ -1620,11 +1864,10 @@
     return generic_stub();
   }
 
-  // If the maximum number of receiver maps has been exceeded, use the generic
-  // version of the IC.
+  // If the maximum number of receiver maps has been exceeded, use the
+  // megamorphic version of the IC.
   if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
-    TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "max polymorph exceeded");
-    return generic_stub();
+    return megamorphic_stub();
   }
 
   // Make sure all polymorphic handlers have the same store mode, otherwise the
@@ -1807,12 +2050,12 @@
         StoreIC::Store(object, Handle<String>::cast(key), value,
                        JSReceiver::MAY_BE_STORE_FROM_KEYED),
         Object);
-    // TODO(jkummerow): Ideally we'd wrap this in "if (!is_target_set())",
-    // but doing so causes Hydrogen crashes. Needs investigation.
-    TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
-                     "unhandled internalized string key");
-    TRACE_IC("StoreIC", key);
-    set_target(*stub);
+    if (!is_target_set()) {
+      TRACE_GENERIC_IC(isolate(), "KeyedStoreIC",
+                       "unhandled internalized string key");
+      TRACE_IC("StoreIC", key);
+      set_target(*stub);
+    }
     return store_handle;
   }
 
@@ -1888,9 +2131,15 @@
 }
 
 
+// static
+void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
+                                   StrictMode strict_mode) {
+  PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode);
+}
+
+
 bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function,
-                             Handle<TypeFeedbackVector> vector,
-                             Handle<Smi> slot, const CallICState& state) {
+                             const CallICState& callic_state) {
   DCHECK(FLAG_use_ic && function->IsJSFunction());
 
   // Are we the array function?
@@ -1898,43 +2147,33 @@
       Handle<JSFunction>(isolate()->native_context()->array_function());
   if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) {
     // Alter the slot.
-    IC::State old_state = FeedbackToState(vector, slot);
-    Object* feedback = vector->get(slot->value());
-    if (!feedback->IsAllocationSite()) {
-      Handle<AllocationSite> new_site =
-          isolate()->factory()->NewAllocationSite();
-      vector->set(slot->value(), *new_site);
-    }
+    CallICNexus* nexus = casted_nexus<CallICNexus>();
+    nexus->ConfigureMonomorphicArray();
 
-    CallIC_ArrayStub stub(isolate(), state);
+    CallIC_ArrayStub stub(isolate(), callic_state);
     set_target(*stub.GetCode());
     Handle<String> name;
     if (array_function->shared()->name()->IsString()) {
       name = Handle<String>(String::cast(array_function->shared()->name()),
                             isolate());
     }
-
-    IC::State new_state = FeedbackToState(vector, slot);
-    OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true);
-    TRACE_VECTOR_IC("CallIC (custom handler)", name, old_state, new_state);
+    TRACE_IC("CallIC", name);
+    OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
+                          MONOMORPHIC);
     return true;
   }
   return false;
 }
 
 
-void CallIC::PatchMegamorphic(Handle<Object> function,
-                              Handle<TypeFeedbackVector> vector,
-                              Handle<Smi> slot) {
-  CallICState state(target()->extra_ic_state());
-  IC::State old_state = FeedbackToState(vector, slot);
+void CallIC::PatchMegamorphic(Handle<Object> function) {
+  CallICState callic_state(target()->extra_ic_state());
 
   // We are going generic.
-  vector->set(slot->value(),
-              *TypeFeedbackVector::MegamorphicSentinel(isolate()),
-              SKIP_WRITE_BARRIER);
+  CallICNexus* nexus = casted_nexus<CallICNexus>();
+  nexus->ConfigureGeneric();
 
-  CallICStub stub(isolate(), state);
+  CallICStub stub(isolate(), callic_state);
   Handle<Code> code = stub.GetCode();
   set_target(*code);
 
@@ -1944,27 +2183,24 @@
     name = handle(js_function->shared()->name(), isolate());
   }
 
-  IC::State new_state = FeedbackToState(vector, slot);
-  OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true);
-  TRACE_VECTOR_IC("CallIC", name, old_state, new_state);
+  TRACE_IC("CallIC", name);
+  OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
+                        GENERIC);
 }
 
 
-void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function,
-                        Handle<TypeFeedbackVector> vector, Handle<Smi> slot) {
-  CallICState state(target()->extra_ic_state());
-  IC::State old_state = FeedbackToState(vector, slot);
+void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function) {
+  CallICState callic_state(target()->extra_ic_state());
   Handle<Object> name = isolate()->factory()->empty_string();
-  Object* feedback = vector->get(slot->value());
+  CallICNexus* nexus = casted_nexus<CallICNexus>();
+  Object* feedback = nexus->GetFeedback();
 
   // Hand-coded MISS handling is easier if CallIC slots don't contain smis.
   DCHECK(!feedback->IsSmi());
 
   if (feedback->IsJSFunction() || !function->IsJSFunction()) {
     // We are going generic.
-    vector->set(slot->value(),
-                *TypeFeedbackVector::MegamorphicSentinel(isolate()),
-                SKIP_WRITE_BARRIER);
+    nexus->ConfigureGeneric();
   } else {
     // The feedback is either uninitialized or an allocation site.
     // It might be an allocation site because if we re-compile the full code
@@ -1976,12 +2212,11 @@
            feedback->IsAllocationSite());
 
     // Do we want to install a custom handler?
-    if (FLAG_use_ic &&
-        DoCustomHandler(receiver, function, vector, slot, state)) {
+    if (FLAG_use_ic && DoCustomHandler(receiver, function, callic_state)) {
       return;
     }
 
-    vector->set(slot->value(), *function);
+    nexus->ConfigureMonomorphic(Handle<JSFunction>::cast(function));
   }
 
   if (function->IsJSFunction()) {
@@ -1989,9 +2224,9 @@
     name = handle(js_function->shared()->name(), isolate());
   }
 
-  IC::State new_state = FeedbackToState(vector, slot);
-  OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true);
-  TRACE_VECTOR_IC("CallIC", name, old_state, new_state);
+  IC::State new_state = nexus->StateFromFeedback();
+  OnTypeFeedbackChanged(isolate(), get_host(), *vector(), state(), new_state);
+  TRACE_IC("CallIC", name);
 }
 
 
@@ -2007,12 +2242,14 @@
   TimerEventScope<TimerEventIcMiss> timer(isolate);
   HandleScope scope(isolate);
   DCHECK(args.length() == 4);
-  CallIC ic(isolate);
   Handle<Object> receiver = args.at<Object>(0);
   Handle<Object> function = args.at<Object>(1);
   Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
   Handle<Smi> slot = args.at<Smi>(3);
-  ic.HandleMiss(receiver, function, vector, slot);
+  FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
+  CallICNexus nexus(vector, vector_slot);
+  CallIC ic(isolate, &nexus);
+  ic.HandleMiss(receiver, function);
   return *function;
 }
 
@@ -2021,12 +2258,14 @@
   TimerEventScope<TimerEventIcMiss> timer(isolate);
   HandleScope scope(isolate);
   DCHECK(args.length() == 4);
-  // A miss on a custom call ic always results in going megamorphic.
-  CallIC ic(isolate);
   Handle<Object> function = args.at<Object>(1);
   Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
   Handle<Smi> slot = args.at<Smi>(3);
-  ic.PatchMegamorphic(function, vector, slot);
+  FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
+  CallICNexus nexus(vector, vector_slot);
+  // A miss on a custom call ic always results in going megamorphic.
+  CallIC ic(isolate, &nexus);
+  ic.PatchMegamorphic(function);
   return *function;
 }
 
@@ -2035,13 +2274,38 @@
 RUNTIME_FUNCTION(LoadIC_Miss) {
   TimerEventScope<TimerEventIcMiss> timer(isolate);
   HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
   Handle<Object> receiver = args.at<Object>(0);
   Handle<Name> key = args.at<Name>(1);
-  ic.UpdateState(receiver, key);
   Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+
+  if (FLAG_vector_ics) {
+    DCHECK(args.length() == 4);
+    Handle<Smi> slot = args.at<Smi>(2);
+    Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
+    FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
+    // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
+    // LoadIC miss handler if the handler misses. Since the vector Nexus is
+    // set up outside the IC, handle that here.
+    if (vector->GetKind(vector_slot) == Code::LOAD_IC) {
+      LoadICNexus nexus(vector, vector_slot);
+      LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+      ic.UpdateState(receiver, key);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                         ic.Load(receiver, key));
+    } else {
+      DCHECK(vector->GetKind(vector_slot) == Code::KEYED_LOAD_IC);
+      KeyedLoadICNexus nexus(vector, vector_slot);
+      KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+      ic.UpdateState(receiver, key);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                         ic.Load(receiver, key));
+    }
+  } else {
+    DCHECK(args.length() == 2);
+    LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
+    ic.UpdateState(receiver, key);
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+  }
   return *result;
 }
 
@@ -2050,13 +2314,26 @@
 RUNTIME_FUNCTION(KeyedLoadIC_Miss) {
   TimerEventScope<TimerEventIcMiss> timer(isolate);
   HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
   Handle<Object> receiver = args.at<Object>(0);
   Handle<Object> key = args.at<Object>(1);
-  ic.UpdateState(receiver, key);
   Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+
+  if (FLAG_vector_ics) {
+    DCHECK(args.length() == 4);
+    Handle<Smi> slot = args.at<Smi>(2);
+    Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
+    FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
+    KeyedLoadICNexus nexus(vector, vector_slot);
+    KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+    ic.UpdateState(receiver, key);
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+  } else {
+    DCHECK(args.length() == 2);
+    KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
+    ic.UpdateState(receiver, key);
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+  }
+
   return *result;
 }
 
@@ -2064,13 +2341,26 @@
 RUNTIME_FUNCTION(KeyedLoadIC_MissFromStubFailure) {
   TimerEventScope<TimerEventIcMiss> timer(isolate);
   HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
   Handle<Object> receiver = args.at<Object>(0);
   Handle<Object> key = args.at<Object>(1);
-  ic.UpdateState(receiver, key);
   Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+
+  if (FLAG_vector_ics) {
+    DCHECK(args.length() == 4);
+    Handle<Smi> slot = args.at<Smi>(2);
+    Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
+    FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
+    KeyedLoadICNexus nexus(vector, vector_slot);
+    KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
+    ic.UpdateState(receiver, key);
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+  } else {
+    DCHECK(args.length() == 2);
+    KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
+    ic.UpdateState(receiver, key);
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+  }
+
   return *result;
 }
 
@@ -2082,7 +2372,7 @@
   DCHECK(args.length() == 3);
   StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
   Handle<Object> receiver = args.at<Object>(0);
-  Handle<String> key = args.at<String>(1);
+  Handle<Name> key = args.at<Name>(1);
   ic.UpdateState(receiver, key);
   Handle<Object> result;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
@@ -2094,10 +2384,10 @@
 RUNTIME_FUNCTION(StoreIC_MissFromStubFailure) {
   TimerEventScope<TimerEventIcMiss> timer(isolate);
   HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
+  DCHECK(args.length() == 3 || args.length() == 4);
   StoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
   Handle<Object> receiver = args.at<Object>(0);
-  Handle<String> key = args.at<String>(1);
+  Handle<Name> key = args.at<Name>(1);
   ic.UpdateState(receiver, key);
   Handle<Object> result;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
@@ -2106,30 +2396,6 @@
 }
 
 
-// Extend storage is called in a store inline cache when
-// it is necessary to extend the properties array of a
-// JSObject.
-RUNTIME_FUNCTION(SharedStoreIC_ExtendStorage) {
-  TimerEventScope<TimerEventIcMiss> timer(isolate);
-  HandleScope shs(isolate);
-  DCHECK(args.length() == 3);
-
-  // Convert the parameters
-  Handle<JSObject> object = args.at<JSObject>(0);
-  Handle<Map> transition = args.at<Map>(1);
-  Handle<Object> value = args.at<Object>(2);
-
-  // Check the object has run out out property space.
-  DCHECK(object->HasFastProperties());
-  DCHECK(object->map()->unused_property_fields() == 0);
-
-  JSObject::MigrateToNewProperty(object, transition, value);
-
-  // Return the stored value.
-  return *value;
-}
-
-
 // Used from ic-<arch>.cc.
 RUNTIME_FUNCTION(KeyedStoreIC_Miss) {
   TimerEventScope<TimerEventIcMiss> timer(isolate);
@@ -2268,7 +2534,7 @@
     if (!allocation_site.is_null()) {
       os << " using allocation site " << static_cast<void*>(*allocation_site);
     }
-    os << "]" << endl;
+    os << "]" << std::endl;
   }
 
   // Patch the inlined smi code as necessary.
@@ -2544,19 +2810,17 @@
  */
 RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly) {
   DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
-  Handle<Name> name_handle =
+  Handle<Name> name =
       args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
   Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(
       NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex);
 
-  // TODO(rossberg): Support symbols in the API.
-  if (name_handle->IsSymbol())
+  if (name->IsSymbol() && !interceptor_info->can_intercept_symbols())
     return isolate->heap()->no_interceptor_result_sentinel();
-  Handle<String> name = Handle<String>::cast(name_handle);
 
   Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
-  v8::NamedPropertyGetterCallback getter =
-      FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address);
+  v8::GenericNamedPropertyGetterCallback getter =
+      FUNCTION_CAST<v8::GenericNamedPropertyGetterCallback>(getter_address);
   DCHECK(getter != NULL);
 
   Handle<JSObject> receiver =
@@ -2586,7 +2850,7 @@
   // If the load is non-contextual, just return the undefined result.
   // Note that both keyed and non-keyed loads may end up here.
   HandleScope scope(isolate);
-  LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
+  LoadIC ic(IC::NO_EXTRA_FRAME, isolate, true);
   if (ic.contextual_mode() != CONTEXTUAL) {
     return isolate->heap()->undefined_value();
   }
@@ -2634,7 +2898,7 @@
   PrototypeIterator iter(isolate, receiver,
                          PrototypeIterator::START_AT_RECEIVER);
   bool found = false;
-  while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
+  for (; !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
     Handle<Object> current = PrototypeIterator::GetCurrent(iter);
     if (current->IsJSObject() &&
         Handle<JSObject>::cast(current)->HasNamedInterceptor()) {
@@ -2660,20 +2924,48 @@
   Handle<Object> result;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
       isolate, result,
-      JSObject::GetElementWithInterceptor(receiver, receiver, index));
+      JSObject::GetElementWithInterceptor(receiver, receiver, index, true));
   return *result;
 }
 
 
-RUNTIME_FUNCTION(VectorLoadIC_MissFromStubFailure) {
-  // TODO(mvstanton): To be enabled when ICs can accept a vector and slot
-  return NULL;
-}
+RUNTIME_FUNCTION(LoadIC_MissFromStubFailure) {
+  TimerEventScope<TimerEventIcMiss> timer(isolate);
+  HandleScope scope(isolate);
+  Handle<Object> receiver = args.at<Object>(0);
+  Handle<Name> key = args.at<Name>(1);
+  Handle<Object> result;
 
+  if (FLAG_vector_ics) {
+    DCHECK(args.length() == 4);
+    Handle<Smi> slot = args.at<Smi>(2);
+    Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
+    FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
+    // A monomorphic or polymorphic KeyedLoadIC with a string key can call the
+    // LoadIC miss handler if the handler misses. Since the vector Nexus is
+    // set up outside the IC, handle that here.
+    if (vector->GetKind(vector_slot) == Code::LOAD_IC) {
+      LoadICNexus nexus(vector, vector_slot);
+      LoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
+      ic.UpdateState(receiver, key);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                         ic.Load(receiver, key));
+    } else {
+      DCHECK(vector->GetKind(vector_slot) == Code::KEYED_LOAD_IC);
+      KeyedLoadICNexus nexus(vector, vector_slot);
+      KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
+      ic.UpdateState(receiver, key);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                         ic.Load(receiver, key));
+    }
+  } else {
+    DCHECK(args.length() == 2);
+    LoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
+    ic.UpdateState(receiver, key);
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+  }
 
-RUNTIME_FUNCTION(VectorKeyedLoadIC_MissFromStubFailure) {
-  // TODO(mvstanton): To be enabled when ICs can accept a vector and slot
-  return NULL;
+  return *result;
 }
 
 
diff --git a/src/ic/ic.h b/src/ic/ic.h
index d86d2b7..541fa0c 100644
--- a/src/ic/ic.h
+++ b/src/ic/ic.h
@@ -21,7 +21,6 @@
   ICU(CallIC_Customization_Miss)       \
   ICU(StoreIC_Miss)                    \
   ICU(StoreIC_Slow)                    \
-  ICU(SharedStoreIC_ExtendStorage)     \
   ICU(KeyedStoreIC_Miss)               \
   ICU(KeyedStoreIC_Slow)               \
   /* Utilities for IC stubs. */        \
@@ -60,7 +59,8 @@
 
   // Construct the IC structure with the given number of extra
   // JavaScript frames on the stack.
-  IC(FrameDepth depth, Isolate* isolate);
+  IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL,
+     bool for_queries_only = false);
   virtual ~IC() {}
 
   State state() const { return state_; }
@@ -72,17 +72,10 @@
   bool IsNameCompatibleWithPrototypeFailure(Handle<Object> name);
   void MarkPrototypeFailure(Handle<Object> name) {
     DCHECK(IsNameCompatibleWithPrototypeFailure(name));
+    old_state_ = state_;
     state_ = PROTOTYPE_FAILURE;
   }
 
-  // If the stub contains weak maps then this function adds the stub to
-  // the dependent code array of each weak map.
-  static void RegisterWeakMapDependency(Handle<Code> stub);
-
-  // This function is called when a weak map in the stub is dying,
-  // invalidates the stub by setting maps in it to undefined.
-  static void InvalidateMaps(Code* stub);
-
   // Clear the inline cache to initial state.
   static void Clear(Isolate* isolate, Address address,
                     ConstantPoolArray* constant_pool);
@@ -114,6 +107,11 @@
     return state == UNINITIALIZED || state == PREMONOMORPHIC;
   }
 
+  static bool IsCleared(FeedbackNexus* nexus) {
+    InlineCacheState state = nexus->StateFromFeedback();
+    return state == UNINITIALIZED || state == PREMONOMORPHIC;
+  }
+
   // Utility functions to convert maps to types and back. There are two special
   // cases:
   // - The heap_number_map is used as a marker which includes heap numbers as
@@ -127,6 +125,12 @@
   static Handle<HeapType> CurrentTypeOf(Handle<Object> object,
                                         Isolate* isolate);
 
+  static bool ICUseVector(Code::Kind kind) {
+    return (FLAG_vector_ics &&
+            (kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC)) ||
+           kind == Code::CALL_IC;
+  }
+
  protected:
   // Get the call-site target; used for determining the state.
   Handle<Code> target() const { return target_; }
@@ -146,6 +150,22 @@
   inline void set_target(Code* code);
   bool is_target_set() { return target_set_; }
 
+  bool UseVector() const {
+    bool use = ICUseVector(kind());
+    // If we are supposed to use the nexus, verify the nexus is non-null.
+    DCHECK(!use || nexus_ != NULL);
+    return use;
+  }
+
+  // Configure for most states.
+  void ConfigureVectorState(IC::State new_state);
+  // Configure the vector for MONOMORPHIC.
+  void ConfigureVectorState(Handle<Name> name, Handle<HeapType> type,
+                            Handle<Code> handler);
+  // Configure the vector for POLYMORPHIC.
+  void ConfigureVectorState(Handle<Name> name, TypeHandleList* types,
+                            CodeHandleList* handlers);
+
   char TransitionMarkFromState(IC::State state);
   void TraceIC(const char* type, Handle<Object> name);
   void TraceIC(const char* type, Handle<Object> name, State old_state,
@@ -163,6 +183,10 @@
   static void OnTypeFeedbackChanged(Isolate* isolate, Address address,
                                     State old_state, State new_state,
                                     bool target_remains_ic_stub);
+  // As a vector-based IC, type feedback must be updated differently.
+  static void OnTypeFeedbackChanged(Isolate* isolate, Code* host,
+                                    TypeFeedbackVector* vector, State old_state,
+                                    State new_state);
   static void PostPatching(Address address, Code* target, Code* old_target);
 
   // Compute the handler either by compiling or by retrieving a cached version.
@@ -224,9 +248,22 @@
     return target_maps_.length() > 0 ? *target_maps_.at(0) : NULL;
   }
 
- protected:
   inline void UpdateTarget();
 
+  Handle<TypeFeedbackVector> vector() const { return nexus()->vector_handle(); }
+  FeedbackVectorICSlot slot() const { return nexus()->slot(); }
+  State saved_state() const {
+    return state() == PROTOTYPE_FAILURE ? old_state_ : state();
+  }
+
+  template <class NexusClass>
+  NexusClass* casted_nexus() {
+    return static_cast<NexusClass*>(nexus_);
+  }
+  FeedbackNexus* nexus() const { return nexus_; }
+
+  inline Code* get_host();
+
  private:
   inline Code* raw_target() const;
   inline ConstantPoolArray* constant_pool() const;
@@ -235,11 +272,15 @@
   void FindTargetMaps() {
     if (target_maps_set_) return;
     target_maps_set_ = true;
-    if (state_ == MONOMORPHIC) {
-      Map* map = target_->FindFirstMap();
-      if (map != NULL) target_maps_.Add(handle(map));
-    } else if (state_ != UNINITIALIZED && state_ != PREMONOMORPHIC) {
-      target_->FindAllMaps(&target_maps_);
+    if (UseVector()) {
+      nexus()->ExtractMaps(&target_maps_);
+    } else {
+      if (state_ == MONOMORPHIC) {
+        Map* map = target_->FindFirstMap();
+        if (map != NULL) target_maps_.Add(handle(map));
+      } else if (state_ != UNINITIALIZED && state_ != PREMONOMORPHIC) {
+        target_->FindAllMaps(&target_maps_);
+      }
     }
   }
 
@@ -261,6 +302,7 @@
   // The original code target that missed.
   Handle<Code> target_;
   bool target_set_;
+  State old_state_;  // For saving if we marked as prototype failure.
   State state_;
   Code::Kind kind_;
   Handle<HeapType> receiver_type_;
@@ -270,6 +312,8 @@
   MapHandleList target_maps_;
   bool target_maps_set_;
 
+  FeedbackNexus* nexus_;
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
 };
 
@@ -293,29 +337,24 @@
 
 class CallIC : public IC {
  public:
-  explicit CallIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
+  CallIC(Isolate* isolate, CallICNexus* nexus)
+      : IC(EXTRA_CALL_FRAME, isolate, nexus) {
+    DCHECK(nexus != NULL);
+  }
 
-  void PatchMegamorphic(Handle<Object> function,
-                        Handle<TypeFeedbackVector> vector, Handle<Smi> slot);
+  void PatchMegamorphic(Handle<Object> function);
 
-  void HandleMiss(Handle<Object> receiver, Handle<Object> function,
-                  Handle<TypeFeedbackVector> vector, Handle<Smi> slot);
+  void HandleMiss(Handle<Object> receiver, Handle<Object> function);
 
   // Returns true if a custom handler was installed.
   bool DoCustomHandler(Handle<Object> receiver, Handle<Object> function,
-                       Handle<TypeFeedbackVector> vector, Handle<Smi> slot,
-                       const CallICState& state);
+                       const CallICState& callic_state);
 
   // Code generator routines.
   static Handle<Code> initialize_stub(Isolate* isolate, int argc,
                                       CallICState::CallType call_type);
 
-  static void Clear(Isolate* isolate, Address address, Code* target,
-                    ConstantPoolArray* constant_pool);
-
- private:
-  inline IC::State FeedbackToState(Handle<TypeFeedbackVector> vector,
-                                   Handle<Smi> slot) const;
+  static void Clear(Isolate* isolate, Code* host, CallICNexus* nexus);
 };
 
 
@@ -329,7 +368,18 @@
     return LoadICState::GetContextualMode(extra_ic_state());
   }
 
-  explicit LoadIC(FrameDepth depth, Isolate* isolate) : IC(depth, isolate) {
+  LoadIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
+      : IC(depth, isolate, nexus) {
+    DCHECK(!FLAG_vector_ics || nexus != NULL);
+    DCHECK(IsLoadStub());
+  }
+
+  // TODO(mvstanton): The for_queries_only is because we have a case where we
+  // construct an IC only to gather the contextual mode, and we don't have
+  // vector/slot information. for_queries_only is a temporary hack to enable the
+  // strong DCHECK protection around vector/slot.
+  LoadIC(FrameDepth depth, Isolate* isolate, bool for_queries_only)
+      : IC(depth, isolate, NULL, for_queries_only) {
     DCHECK(IsLoadStub());
   }
 
@@ -355,10 +405,14 @@
 
   static Handle<Code> initialize_stub(Isolate* isolate,
                                       ExtraICState extra_state);
+  static Handle<Code> initialize_stub_in_optimized_code(
+      Isolate* isolate, ExtraICState extra_state);
 
   MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
                                            Handle<Name> name);
 
+  static void Clear(Isolate* isolate, Code* host, LoadICNexus* nexus);
+
  protected:
   inline void set_target(Code* code);
 
@@ -371,7 +425,7 @@
     }
   }
 
-  virtual Handle<Code> megamorphic_stub() OVERRIDE;
+  Handle<Code> megamorphic_stub() OVERRIDE;
 
   // Update the inline cache and the global stub cache based on the
   // lookup result.
@@ -379,7 +433,7 @@
 
   virtual Handle<Code> CompileHandler(LookupIterator* lookup,
                                       Handle<Object> unused,
-                                      CacheHolderFlag cache_holder);
+                                      CacheHolderFlag cache_holder) OVERRIDE;
 
  private:
   virtual Handle<Code> pre_monomorphic_stub() const;
@@ -397,8 +451,23 @@
 
 class KeyedLoadIC : public LoadIC {
  public:
-  explicit KeyedLoadIC(FrameDepth depth, Isolate* isolate)
-      : LoadIC(depth, isolate) {
+  // ExtraICState bits (building on IC)
+  class IcCheckTypeField : public BitField<IcCheckType, 1, 1> {};
+
+  static ExtraICState ComputeExtraICState(ContextualMode contextual_mode,
+                                          IcCheckType key_type) {
+    return LoadICState(contextual_mode).GetExtraICState() |
+           IcCheckTypeField::encode(key_type);
+  }
+
+  static IcCheckType GetKeyType(ExtraICState extra_state) {
+    return IcCheckTypeField::decode(extra_state);
+  }
+
+  KeyedLoadIC(FrameDepth depth, Isolate* isolate,
+              KeyedLoadICNexus* nexus = NULL)
+      : LoadIC(depth, isolate, nexus) {
+    DCHECK(!FLAG_vector_ics || nexus != NULL);
     DCHECK(target()->is_keyed_load_stub());
   }
 
@@ -413,7 +482,6 @@
     GenerateMiss(masm);
   }
   static void GenerateGeneric(MacroAssembler* masm);
-  static void GenerateString(MacroAssembler* masm);
 
   // Bit mask to be tested against bit field for the cases when
   // generic stub should go into slow case.
@@ -422,20 +490,22 @@
   static const int kSlowCaseBitFieldMask =
       (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
 
+  static Handle<Code> initialize_stub(Isolate* isolate);
+  static Handle<Code> initialize_stub_in_optimized_code(Isolate* isolate);
   static Handle<Code> generic_stub(Isolate* isolate);
   static Handle<Code> pre_monomorphic_stub(Isolate* isolate);
 
+  static void Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus);
+
  protected:
-  Handle<Code> LoadElementStub(Handle<JSObject> receiver);
+  // receiver is HeapObject because it could be a String or a JSObject
+  Handle<Code> LoadElementStub(Handle<HeapObject> receiver);
   virtual Handle<Code> pre_monomorphic_stub() const {
     return pre_monomorphic_stub(isolate());
   }
 
  private:
   Handle<Code> generic_stub() const { return generic_stub(isolate()); }
-  Handle<Code> string_stub() {
-    return isolate()->builtins()->KeyedLoadIC_String();
-  }
 
   static void Clear(Isolate* isolate, Address address, Code* target,
                     ConstantPoolArray* constant_pool);
@@ -489,7 +559,7 @@
                       JSReceiver::StoreFromKeyed store_mode);
 
  protected:
-  virtual Handle<Code> megamorphic_stub() OVERRIDE;
+  Handle<Code> megamorphic_stub() OVERRIDE;
 
   // Stub accessors.
   Handle<Code> generic_stub() const;
@@ -509,7 +579,7 @@
                     JSReceiver::StoreFromKeyed store_mode);
   virtual Handle<Code> CompileHandler(LookupIterator* lookup,
                                       Handle<Object> value,
-                                      CacheHolderFlag cache_holder);
+                                      CacheHolderFlag cache_holder) OVERRIDE;
 
  private:
   inline void set_target(Code* code);
@@ -534,10 +604,13 @@
   class ExtraICStateKeyedAccessStoreMode
       : public BitField<KeyedAccessStoreMode, 2, 4> {};  // NOLINT
 
+  class IcCheckTypeField : public BitField<IcCheckType, 6, 1> {};
+
   static ExtraICState ComputeExtraICState(StrictMode flag,
                                           KeyedAccessStoreMode mode) {
     return StrictModeState::encode(flag) |
-           ExtraICStateKeyedAccessStoreMode::encode(mode);
+           ExtraICStateKeyedAccessStoreMode::encode(mode) |
+           IcCheckTypeField::encode(ELEMENT);
   }
 
   static KeyedAccessStoreMode GetKeyedAccessStoreMode(
@@ -545,6 +618,10 @@
     return ExtraICStateKeyedAccessStoreMode::decode(extra_state);
   }
 
+  static IcCheckType GetKeyType(ExtraICState extra_state) {
+    return IcCheckTypeField::decode(extra_state);
+  }
+
   KeyedStoreIC(FrameDepth depth, Isolate* isolate) : StoreIC(depth, isolate) {
     DCHECK(target()->is_keyed_store_stub());
   }
@@ -560,6 +637,7 @@
   }
   static void GenerateMiss(MacroAssembler* masm);
   static void GenerateSlow(MacroAssembler* masm);
+  static void GenerateMegamorphic(MacroAssembler* masm, StrictMode strict_mode);
   static void GenerateGeneric(MacroAssembler* masm, StrictMode strict_mode);
   static void GenerateSloppyArguments(MacroAssembler* masm);
 
@@ -681,8 +759,7 @@
 DECLARE_RUNTIME_FUNCTION(BinaryOpIC_MissWithAllocationSite);
 DECLARE_RUNTIME_FUNCTION(CompareNilIC_Miss);
 DECLARE_RUNTIME_FUNCTION(ToBooleanIC_Miss);
-DECLARE_RUNTIME_FUNCTION(VectorLoadIC_MissFromStubFailure);
-DECLARE_RUNTIME_FUNCTION(VectorKeyedLoadIC_MissFromStubFailure);
+DECLARE_RUNTIME_FUNCTION(LoadIC_MissFromStubFailure);
 
 // Support functions for callbacks handlers.
 DECLARE_RUNTIME_FUNCTION(StoreCallbackProperty);
diff --git a/src/ic/mips/handler-compiler-mips.cc b/src/ic/mips/handler-compiler-mips.cc
index 5b4555f..75032e1 100644
--- a/src/ic/mips/handler-compiler-mips.cc
+++ b/src/ic/mips/handler-compiler-mips.cc
@@ -92,6 +92,26 @@
 }
 
 
+void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
+                                                Register slot) {
+  MacroAssembler* masm = this->masm();
+  __ Push(vector, slot);
+}
+
+
+void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
+  MacroAssembler* masm = this->masm();
+  __ Pop(vector, slot);
+}
+
+
+void PropertyHandlerCompiler::DiscardVectorAndSlot() {
+  MacroAssembler* masm = this->masm();
+  // Remove vector and slot.
+  __ Addu(sp, sp, Operand(2 * kPointerSize));
+}
+
+
 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
     MacroAssembler* masm, Label* miss_label, Register receiver,
     Handle<Name> name, Register scratch0, Register scratch1) {
@@ -138,25 +158,16 @@
 
 
 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
-    MacroAssembler* masm, int index, Register prototype, Label* miss) {
-  Isolate* isolate = masm->isolate();
-  // Get the global function with the given index.
-  Handle<JSFunction> function(
-      JSFunction::cast(isolate->native_context()->get(index)));
-
-  // Check we're still in the same context.
-  Register scratch = prototype;
+    MacroAssembler* masm, int index, Register result, Label* miss) {
   const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX);
-  __ lw(scratch, MemOperand(cp, offset));
-  __ lw(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
-  __ lw(scratch, MemOperand(scratch, Context::SlotOffset(index)));
-  __ li(at, function);
-  __ Branch(miss, ne, at, Operand(scratch));
-
+  __ lw(result, MemOperand(cp, offset));
+  __ lw(result, FieldMemOperand(result, GlobalObject::kNativeContextOffset));
+  __ lw(result, MemOperand(result, Context::SlotOffset(index)));
   // Load its initial map. The global functions all have initial maps.
-  __ li(prototype, Handle<Map>(function->initial_map()));
+  __ lw(result,
+        FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
   // Load the prototype from the initial map.
-  __ lw(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
+  __ lw(result, FieldMemOperand(result, Map::kPrototypeOffset));
 }
 
 
@@ -321,186 +332,62 @@
 }
 
 
-// Generate StoreTransition code, value is passed in a0 register.
-// After executing generated code, the receiver_reg and name_reg
-// may be clobbered.
-void NamedStoreHandlerCompiler::GenerateStoreTransition(
-    Handle<Map> transition, Handle<Name> name, Register receiver_reg,
-    Register storage_reg, Register value_reg, Register scratch1,
-    Register scratch2, Register scratch3, Label* miss_label, Label* slow) {
-  // a0 : value.
-  Label exit;
-
-  int descriptor = transition->LastAdded();
-  DescriptorArray* descriptors = transition->instance_descriptors();
-  PropertyDetails details = descriptors->GetDetails(descriptor);
-  Representation representation = details.representation();
-  DCHECK(!representation.IsNone());
-
-  if (details.type() == CONSTANT) {
-    Handle<Object> constant(descriptors->GetValue(descriptor), isolate());
-    __ li(scratch1, constant);
-    __ Branch(miss_label, ne, value_reg, Operand(scratch1));
-  } else if (representation.IsSmi()) {
-    __ JumpIfNotSmi(value_reg, miss_label);
-  } else if (representation.IsHeapObject()) {
-    __ JumpIfSmi(value_reg, miss_label);
-    HeapType* field_type = descriptors->GetFieldType(descriptor);
-    HeapType::Iterator<Map> it = field_type->Classes();
-    Handle<Map> current;
-    if (!it.Done()) {
-      __ lw(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
-      Label do_store;
-      while (true) {
-        // Do the CompareMap() directly within the Branch() functions.
-        current = it.Current();
-        it.Advance();
-        if (it.Done()) {
-          __ Branch(miss_label, ne, scratch1, Operand(current));
-          break;
-        }
-        __ Branch(&do_store, eq, scratch1, Operand(current));
-      }
-      __ bind(&do_store);
-    }
-  } else if (representation.IsDouble()) {
-    Label do_store, heap_number;
-    __ LoadRoot(scratch3, Heap::kMutableHeapNumberMapRootIndex);
-    __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow,
-                          TAG_RESULT, MUTABLE);
-
-    __ JumpIfNotSmi(value_reg, &heap_number);
-    __ SmiUntag(scratch1, value_reg);
-    __ mtc1(scratch1, f6);
-    __ cvt_d_w(f4, f6);
-    __ jmp(&do_store);
-
-    __ bind(&heap_number);
-    __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label,
-                DONT_DO_SMI_CHECK);
-    __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
-
-    __ bind(&do_store);
-    __ sdc1(f4, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
-  }
-
-  // Stub never generated for objects that require access checks.
-  DCHECK(!transition->is_access_check_needed());
-
-  // Perform map transition for the receiver if necessary.
-  if (details.type() == FIELD &&
-      Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) {
-    // The properties must be extended before we can store the value.
-    // We jump to a runtime call that extends the properties array.
-    __ push(receiver_reg);
-    __ li(a2, Operand(transition));
-    __ Push(a2, a0);
-    __ TailCallExternalReference(
-        ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
-                          isolate()),
-        3, 1);
-    return;
-  }
-
-  // Update the map of the object.
-  __ li(scratch1, Operand(transition));
-  __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
-
-  // Update the write barrier for the map field.
-  __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2,
-                      kRAHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
-
-  if (details.type() == CONSTANT) {
-    DCHECK(value_reg.is(a0));
-    __ Ret(USE_DELAY_SLOT);
-    __ mov(v0, a0);
-    return;
-  }
-
-  int index = transition->instance_descriptors()->GetFieldIndex(
-      transition->LastAdded());
-
-  // Adjust for the number of properties stored in the object. Even in the
-  // face of a transition we can use the old map here because the size of the
-  // object and the number of in-object properties is not going to change.
-  index -= transition->inobject_properties();
-
-  // TODO(verwaest): Share this code as a code stub.
-  SmiCheck smi_check =
-      representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
-  if (index < 0) {
-    // Set the property straight into the object.
-    int offset = transition->instance_size() + (index * kPointerSize);
-    if (representation.IsDouble()) {
-      __ sw(storage_reg, FieldMemOperand(receiver_reg, offset));
-    } else {
-      __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
-    }
-
-    if (!representation.IsSmi()) {
-      // Update the write barrier for the array address.
-      if (!representation.IsDouble()) {
-        __ mov(storage_reg, value_reg);
-      }
-      __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1,
-                          kRAHasNotBeenSaved, kDontSaveFPRegs,
-                          EMIT_REMEMBERED_SET, smi_check);
-    }
-  } else {
-    // Write to the properties array.
-    int offset = index * kPointerSize + FixedArray::kHeaderSize;
-    // Get the properties array
-    __ lw(scratch1, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
-    if (representation.IsDouble()) {
-      __ sw(storage_reg, FieldMemOperand(scratch1, offset));
-    } else {
-      __ sw(value_reg, FieldMemOperand(scratch1, offset));
-    }
-
-    if (!representation.IsSmi()) {
-      // Update the write barrier for the array address.
-      if (!representation.IsDouble()) {
-        __ mov(storage_reg, value_reg);
-      }
-      __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg,
-                          kRAHasNotBeenSaved, kDontSaveFPRegs,
-                          EMIT_REMEMBERED_SET, smi_check);
-    }
-  }
-
-  // Return the value (register v0).
-  DCHECK(value_reg.is(a0));
-  __ bind(&exit);
-  __ Ret(USE_DELAY_SLOT);
-  __ mov(v0, a0);
+void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
+  __ li(this->name(), Operand(name));
 }
 
 
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
-                                                   Register value_reg,
-                                                   Label* miss_label) {
-  DCHECK(lookup->representation().IsHeapObject());
-  __ JumpIfSmi(value_reg, miss_label);
-  HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
-  __ lw(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset));
-  Label do_store;
-  Handle<Map> current;
-  while (true) {
-    // Do the CompareMap() directly within the Branch() functions.
-    current = it.Current();
-    it.Advance();
-    if (it.Done()) {
-      __ Branch(miss_label, ne, scratch1(), Operand(current));
-      break;
-    }
-    __ Branch(&do_store, eq, scratch1(), Operand(current));
+void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
+                                                   Register scratch,
+                                                   Label* miss) {
+  Handle<WeakCell> cell = Map::WeakCellForMap(transition);
+  Register map_reg = StoreTransitionDescriptor::MapRegister();
+  DCHECK(!map_reg.is(scratch));
+  __ LoadWeakValue(map_reg, cell, miss);
+  if (transition->CanBeDeprecated()) {
+    __ lw(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
+    __ And(at, scratch, Operand(Map::Deprecated::kMask));
+    __ Branch(miss, ne, at, Operand(zero_reg));
   }
-  __ bind(&do_store);
+}
 
-  StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
-                      lookup->representation());
-  GenerateTailCall(masm(), stub.GetCode());
+
+void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
+                                                      int descriptor,
+                                                      Register value_reg,
+                                                      Register scratch,
+                                                      Label* miss_label) {
+  DCHECK(!map_reg.is(scratch));
+  DCHECK(!map_reg.is(value_reg));
+  DCHECK(!value_reg.is(scratch));
+  __ LoadInstanceDescriptors(map_reg, scratch);
+  __ lw(scratch,
+        FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
+  __ Branch(miss_label, ne, value_reg, Operand(scratch));
+}
+
+
+void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type,
+                                                        Register value_reg,
+                                                        Label* miss_label) {
+  __ JumpIfSmi(value_reg, miss_label);
+  HeapType::Iterator<Map> it = field_type->Classes();
+  if (!it.Done()) {
+    __ lw(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset));
+    Label do_store;
+    Handle<Map> current;
+    while (true) {
+      // Do the CompareMap() directly within the Branch() functions.
+      current = it.Current();
+      it.Advance();
+      if (it.Done()) {
+        __ Branch(miss_label, ne, scratch1(), Operand(current));
+        break;
+      }
+      __ Branch(&do_store, eq, scratch1(), Operand(current));
+    }
+    __ bind(&do_store);
+  }
 }
 
 
@@ -556,11 +443,11 @@
       __ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
     } else {
       Register map_reg = scratch1;
+      __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
       if (depth != 1 || check == CHECK_ALL_MAPS) {
-        // CheckMap implicitly loads the map of |reg| into |map_reg|.
-        __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK);
-      } else {
-        __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
+        Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+        __ GetWeakValue(scratch2, cell);
+        __ Branch(miss, ne, scratch2, Operand(map_reg));
       }
 
       // Check access rights to the global object.  This has to happen after
@@ -578,17 +465,7 @@
 
       reg = holder_reg;  // From now on the object will be in holder_reg.
 
-      // Two possible reasons for loading the prototype from the map:
-      // (1) Can't store references to new space in code.
-      // (2) Handler is shared for all receivers with the same prototype
-      //     map (but not necessarily the same prototype instance).
-      bool load_prototype_from_map =
-          heap()->InNewSpace(*prototype) || depth == 1;
-      if (load_prototype_from_map) {
-        __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
-      } else {
-        __ li(reg, Operand(prototype));
-      }
+      __ lw(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
     }
 
     // Go to the next object in the prototype chain.
@@ -601,7 +478,10 @@
 
   if (depth != 0 || check == CHECK_ALL_MAPS) {
     // Check the holder map.
-    __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK);
+    __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
+    Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+    __ GetWeakValue(scratch2, cell);
+    __ Branch(miss, ne, scratch2, Operand(scratch1));
   }
 
   // Perform security check for access to the global object.
@@ -621,6 +501,10 @@
     Label success;
     __ Branch(&success);
     __ bind(miss);
+    if (IC::ICUseVector(kind())) {
+      DCHECK(kind() == Code::LOAD_IC);
+      PopVectorAndSlot();
+    }
     TailCallBuiltin(masm(), MissBuiltin(kind()));
     __ bind(&success);
   }
@@ -722,6 +606,7 @@
     } else {
       __ Push(holder_reg, this->name());
     }
+    InterceptorVectorSlotPush(holder_reg);
     // Invoke an interceptor.  Note: map checks from receiver to
     // interceptor's holder has been compiled before (see a caller
     // of this method).
@@ -738,6 +623,7 @@
     __ Ret();
 
     __ bind(&interceptor_failed);
+    InterceptorVectorSlotPop(holder_reg);
     if (must_preserve_receiver_reg) {
       __ Pop(receiver(), holder_reg, this->name());
     } else {
@@ -767,7 +653,7 @@
 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
     Handle<JSObject> object, Handle<Name> name,
     Handle<ExecutableAccessorInfo> callback) {
-  Register holder_reg = Frontend(receiver(), name);
+  Register holder_reg = Frontend(name);
 
   __ Push(receiver(), holder_reg);  // Receiver.
   __ li(at, Operand(callback));     // Callback info.
@@ -807,12 +693,16 @@
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
   Label miss;
+  if (IC::ICUseVector(kind())) {
+    PushVectorAndSlot();
+  }
 
   FrontendHeader(receiver(), name, &miss);
 
   // Get the value from the cell.
   Register result = StoreDescriptor::ValueRegister();
-  __ li(result, Operand(cell));
+  Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
+  __ LoadWeakValue(result, weak_cell, &miss);
   __ lw(result, FieldMemOperand(result, Cell::kValueOffset));
 
   // Check for deleted property if property can actually be deleted.
@@ -823,6 +713,9 @@
 
   Counters* counters = isolate()->counters();
   __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
+  if (IC::ICUseVector(kind())) {
+    DiscardVectorAndSlot();
+  }
   __ Ret(USE_DELAY_SLOT);
   __ mov(v0, result);
 
diff --git a/src/ic/mips/ic-compiler-mips.cc b/src/ic/mips/ic-compiler-mips.cc
index c1e67f9..6169404 100644
--- a/src/ic/mips/ic-compiler-mips.cc
+++ b/src/ic/mips/ic-compiler-mips.cc
@@ -24,9 +24,12 @@
 
   if (check == PROPERTY &&
       (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) {
-    // In case we are compiling an IC for dictionary loads and stores, just
+    // In case we are compiling an IC for dictionary loads or stores, just
     // check whether the name is unique.
     if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) {
+      // Keyed loads with dictionaries shouldn't be here, they go generic.
+      // The DCHECK is to protect assumptions when --vector-ics is on.
+      DCHECK(kind() != Code::KEYED_LOAD_IC);
       Register tmp = scratch1();
       __ JumpIfSmi(this->name(), &miss);
       __ lw(tmp, FieldMemOperand(this->name(), HeapObject::kMapOffset));
@@ -57,7 +60,9 @@
       number_of_handled_maps++;
       // Check map and tail call if there's a match.
       // Separate compare from branch, to provide path for above JumpIfSmi().
-      __ Subu(match, map_reg, Operand(map));
+      Handle<WeakCell> cell = Map::WeakCellForMap(map);
+      __ GetWeakValue(match, cell);
+      __ Subu(match, match, Operand(map_reg));
       if (type->Is(HeapType::Number())) {
         DCHECK(!number_case.is_unused());
         __ bind(&number_case);
@@ -85,15 +90,20 @@
   __ JumpIfSmi(receiver(), &miss);
 
   int receiver_count = receiver_maps->length();
-  __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
+  Register map_reg = scratch1();
+  Register match = scratch2();
+  __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
   for (int i = 0; i < receiver_count; ++i) {
+    Handle<WeakCell> cell = Map::WeakCellForMap(receiver_maps->at(i));
+    __ GetWeakValue(match, cell);
     if (transitioned_maps->at(i).is_null()) {
-      __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq, scratch1(),
-              Operand(receiver_maps->at(i)));
+      __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq, match,
+              Operand(map_reg));
     } else {
       Label next_map;
-      __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i)));
-      __ li(transition_map(), Operand(transitioned_maps->at(i)));
+      __ Branch(&next_map, ne, match, Operand(map_reg));
+      Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
+      __ LoadWeakValue(transition_map(), cell, &miss);
       __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
       __ bind(&next_map);
     }
diff --git a/src/ic/mips/ic-mips.cc b/src/ic/mips/ic-mips.cc
index d97a6ba..7c8a5ea 100644
--- a/src/ic/mips/ic-mips.cc
+++ b/src/ic/mips/ic-mips.cc
@@ -272,18 +272,35 @@
 static const Register LoadIC_TempRegister() { return a3; }
 
 
+static void LoadIC_PushArgs(MacroAssembler* masm) {
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register name = LoadDescriptor::NameRegister();
+  if (FLAG_vector_ics) {
+    Register slot = VectorLoadICDescriptor::SlotRegister();
+    Register vector = VectorLoadICDescriptor::VectorRegister();
+
+    __ Push(receiver, name, slot, vector);
+  } else {
+    __ Push(receiver, name);
+  }
+}
+
+
 void LoadIC::GenerateMiss(MacroAssembler* masm) {
   // The return address is in ra.
   Isolate* isolate = masm->isolate();
 
-  __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0);
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(t0, t1, VectorLoadICDescriptor::SlotRegister(),
+                     VectorLoadICDescriptor::VectorRegister()));
+  __ IncrementCounter(isolate->counters()->load_miss(), 1, t0, t1);
 
-  __ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
-  __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
+  LoadIC_PushArgs(masm);
 
   // Perform tail call to the entry.
   ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
-  __ TailCallExternalReference(ref, 2, 1);
+  int arg_count = FLAG_vector_ics ? 4 : 2;
+  __ TailCallExternalReference(ref, arg_count, 1);
 }
 
 
@@ -412,15 +429,19 @@
   // The return address is in ra.
   Isolate* isolate = masm->isolate();
 
-  __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0);
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(t0, t1, VectorLoadICDescriptor::SlotRegister(),
+                     VectorLoadICDescriptor::VectorRegister()));
+  __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, t0, t1);
 
-  __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
+  LoadIC_PushArgs(masm);
 
   // Perform tail call to the entry.
   ExternalReference ref =
       ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
 
-  __ TailCallExternalReference(ref, 2, 1);
+  int arg_count = FLAG_vector_ics ? 4 : 2;
+  __ TailCallExternalReference(ref, arg_count, 1);
 }
 
 
@@ -594,33 +615,7 @@
 }
 
 
-void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
-  // Return address is in ra.
-  Label miss;
-
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register index = LoadDescriptor::NameRegister();
-  Register scratch = a3;
-  Register result = v0;
-  DCHECK(!scratch.is(receiver) && !scratch.is(index));
-
-  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
-                                          &miss,  // When not a string.
-                                          &miss,  // When not a number.
-                                          &miss,  // When index out of range.
-                                          STRING_INDEX_IS_ARRAY_INDEX);
-  char_at_generator.GenerateFast(masm);
-  __ Ret();
-
-  StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-}
-
-
-static void KeyedStoreGenerateGenericHelper(
+static void KeyedStoreGenerateMegamorphicHelper(
     MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
     KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
     Register value, Register key, Register receiver, Register receiver_map,
@@ -766,8 +761,8 @@
 }
 
 
-void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
-                                   StrictMode strict_mode) {
+void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
+                                       StrictMode strict_mode) {
   // ---------- S t a t e --------------
   //  -- a0     : value
   //  -- a1     : key
@@ -776,7 +771,7 @@
   // -----------------------------------
   Label slow, fast_object, fast_object_grow;
   Label fast_double, fast_double_grow;
-  Label array, extra, check_if_double_array;
+  Label array, extra, check_if_double_array, maybe_name_key, miss;
 
   // Register usage.
   Register value = StoreDescriptor::ValueRegister();
@@ -789,7 +784,7 @@
   // t0 and t1 are used as general scratch registers.
 
   // Check that the key is a smi.
-  __ JumpIfNotSmi(key, &slow);
+  __ JumpIfNotSmi(key, &maybe_name_key);
   // Check that the object isn't a smi.
   __ JumpIfSmi(receiver, &slow);
   // Get the map of the object.
@@ -819,6 +814,18 @@
   // a1: key.
   // a2: receiver.
   PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode);
+  // Never returns to here.
+
+  __ bind(&maybe_name_key);
+  __ lw(t0, FieldMemOperand(key, HeapObject::kMapOffset));
+  __ lb(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset));
+  __ JumpIfNotUniqueNameInstanceType(t0, &slow);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::STORE_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::STORE_IC, flags, false, receiver, key, a3, t0, t1, t2);
+  // Cache miss.
+  __ Branch(&miss);
 
   // Extra capacity case: Check if there is extra capacity to
   // perform the store and update the length. Used for adding one
@@ -851,13 +858,16 @@
   __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
   __ Branch(&extra, hs, key, Operand(t0));
 
-  KeyedStoreGenerateGenericHelper(
+  KeyedStoreGenerateMegamorphicHelper(
       masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength,
       value, key, receiver, receiver_map, elements_map, elements);
-  KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
-                                  &slow, kDontCheckMap, kIncrementLength, value,
-                                  key, receiver, receiver_map, elements_map,
-                                  elements);
+  KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
+                                      &fast_double_grow, &slow, kDontCheckMap,
+                                      kIncrementLength, value, key, receiver,
+                                      receiver_map, elements_map, elements);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
 }
 
 
@@ -882,8 +892,8 @@
   // Get the receiver from the stack and probe the stub cache.
   Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
       Code::ComputeHandlerFlags(Code::STORE_IC));
-  masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver,
-                                               name, a3, t0, t1, t2);
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::STORE_IC, flags, false, receiver, name, a3, t0, t1, t2);
 
   // Cache miss: Jump to runtime.
   GenerateMiss(masm);
diff --git a/src/ic/mips/stub-cache-mips.cc b/src/ic/mips/stub-cache-mips.cc
index e538712..fab66d8 100644
--- a/src/ic/mips/stub-cache-mips.cc
+++ b/src/ic/mips/stub-cache-mips.cc
@@ -7,7 +7,9 @@
 #if V8_TARGET_ARCH_MIPS
 
 #include "src/codegen.h"
+#include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
+#include "src/interface-descriptors.h"
 
 namespace v8 {
 namespace internal {
@@ -16,7 +18,7 @@
 
 
 static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
-                       Code::Flags flags, bool leave_frame,
+                       Code::Kind ic_kind, Code::Flags flags, bool leave_frame,
                        StubCache::Table table, Register receiver, Register name,
                        // Number of the cache entry, not scaled.
                        Register offset, Register scratch, Register scratch2,
@@ -90,10 +92,11 @@
 }
 
 
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
-                              bool leave_frame, Register receiver,
-                              Register name, Register scratch, Register extra,
-                              Register extra2, Register extra3) {
+void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
+                              Code::Flags flags, bool leave_frame,
+                              Register receiver, Register name,
+                              Register scratch, Register extra, Register extra2,
+                              Register extra3) {
   Isolate* isolate = masm->isolate();
   Label miss;
 
@@ -105,15 +108,7 @@
   DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
 
   // Make sure that there are no register conflicts.
-  DCHECK(!scratch.is(receiver));
-  DCHECK(!scratch.is(name));
-  DCHECK(!extra.is(receiver));
-  DCHECK(!extra.is(name));
-  DCHECK(!extra.is(scratch));
-  DCHECK(!extra2.is(receiver));
-  DCHECK(!extra2.is(name));
-  DCHECK(!extra2.is(scratch));
-  DCHECK(!extra2.is(extra));
+  DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
 
   // Check register validity.
   DCHECK(!scratch.is(no_reg));
@@ -121,6 +116,17 @@
   DCHECK(!extra2.is(no_reg));
   DCHECK(!extra3.is(no_reg));
 
+#ifdef DEBUG
+  // If vector-based ics are in use, ensure that scratch, extra, extra2 and
+  // extra3 don't conflict with the vector and slot registers, which need
+  // to be preserved for a handler call or miss.
+  if (IC::ICUseVector(ic_kind)) {
+    Register vector = VectorLoadICDescriptor::VectorRegister();
+    Register slot = VectorLoadICDescriptor::SlotRegister();
+    DCHECK(!AreAliased(vector, slot, scratch, extra, extra2, extra3));
+  }
+#endif
+
   Counters* counters = masm->isolate()->counters();
   __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2,
                       extra3);
@@ -140,8 +146,8 @@
   __ And(scratch, scratch, Operand(mask));
 
   // Probe the primary table.
-  ProbeTable(isolate, masm, flags, leave_frame, kPrimary, receiver, name,
-             scratch, extra, extra2, extra3);
+  ProbeTable(isolate, masm, ic_kind, flags, leave_frame, kPrimary, receiver,
+             name, scratch, extra, extra2, extra3);
 
   // Primary miss: Compute hash for secondary probe.
   __ srl(at, name, kCacheIndexShift);
@@ -151,8 +157,8 @@
   __ And(scratch, scratch, Operand(mask2));
 
   // Probe the secondary table.
-  ProbeTable(isolate, masm, flags, leave_frame, kSecondary, receiver, name,
-             scratch, extra, extra2, extra3);
+  ProbeTable(isolate, masm, ic_kind, flags, leave_frame, kSecondary, receiver,
+             name, scratch, extra, extra2, extra3);
 
   // Cache miss: Fall-through and let caller handle the miss by
   // entering the runtime system.
diff --git a/src/ic/mips64/handler-compiler-mips64.cc b/src/ic/mips64/handler-compiler-mips64.cc
index f44226f..d3b861b 100644
--- a/src/ic/mips64/handler-compiler-mips64.cc
+++ b/src/ic/mips64/handler-compiler-mips64.cc
@@ -92,6 +92,26 @@
 }
 
 
+void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
+                                                Register slot) {
+  MacroAssembler* masm = this->masm();
+  __ Push(vector, slot);
+}
+
+
+void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
+  MacroAssembler* masm = this->masm();
+  __ Pop(vector, slot);
+}
+
+
+void PropertyHandlerCompiler::DiscardVectorAndSlot() {
+  MacroAssembler* masm = this->masm();
+  // Remove vector and slot.
+  __ Daddu(sp, sp, Operand(2 * kPointerSize));
+}
+
+
 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
     MacroAssembler* masm, Label* miss_label, Register receiver,
     Handle<Name> name, Register scratch0, Register scratch1) {
@@ -138,25 +158,17 @@
 
 
 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
-    MacroAssembler* masm, int index, Register prototype, Label* miss) {
-  Isolate* isolate = masm->isolate();
-  // Get the global function with the given index.
-  Handle<JSFunction> function(
-      JSFunction::cast(isolate->native_context()->get(index)));
-
+    MacroAssembler* masm, int index, Register result, Label* miss) {
   // Check we're still in the same context.
-  Register scratch = prototype;
   const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX);
-  __ ld(scratch, MemOperand(cp, offset));
-  __ ld(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
-  __ ld(scratch, MemOperand(scratch, Context::SlotOffset(index)));
-  __ li(at, function);
-  __ Branch(miss, ne, at, Operand(scratch));
-
+  __ ld(result, MemOperand(cp, offset));
+  __ ld(result, FieldMemOperand(result, GlobalObject::kNativeContextOffset));
+  __ ld(result, MemOperand(result, Context::SlotOffset(index)));
   // Load its initial map. The global functions all have initial maps.
-  __ li(prototype, Handle<Map>(function->initial_map()));
+  __ ld(result,
+        FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
   // Load the prototype from the initial map.
-  __ ld(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
+  __ ld(result, FieldMemOperand(result, Map::kPrototypeOffset));
 }
 
 
@@ -321,186 +333,62 @@
 }
 
 
-// Generate StoreTransition code, value is passed in a0 register.
-// After executing generated code, the receiver_reg and name_reg
-// may be clobbered.
-void NamedStoreHandlerCompiler::GenerateStoreTransition(
-    Handle<Map> transition, Handle<Name> name, Register receiver_reg,
-    Register storage_reg, Register value_reg, Register scratch1,
-    Register scratch2, Register scratch3, Label* miss_label, Label* slow) {
-  // a0 : value.
-  Label exit;
-
-  int descriptor = transition->LastAdded();
-  DescriptorArray* descriptors = transition->instance_descriptors();
-  PropertyDetails details = descriptors->GetDetails(descriptor);
-  Representation representation = details.representation();
-  DCHECK(!representation.IsNone());
-
-  if (details.type() == CONSTANT) {
-    Handle<Object> constant(descriptors->GetValue(descriptor), isolate());
-    __ li(scratch1, constant);
-    __ Branch(miss_label, ne, value_reg, Operand(scratch1));
-  } else if (representation.IsSmi()) {
-    __ JumpIfNotSmi(value_reg, miss_label);
-  } else if (representation.IsHeapObject()) {
-    __ JumpIfSmi(value_reg, miss_label);
-    HeapType* field_type = descriptors->GetFieldType(descriptor);
-    HeapType::Iterator<Map> it = field_type->Classes();
-    Handle<Map> current;
-    if (!it.Done()) {
-      __ ld(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
-      Label do_store;
-      while (true) {
-        // Do the CompareMap() directly within the Branch() functions.
-        current = it.Current();
-        it.Advance();
-        if (it.Done()) {
-          __ Branch(miss_label, ne, scratch1, Operand(current));
-          break;
-        }
-        __ Branch(&do_store, eq, scratch1, Operand(current));
-      }
-      __ bind(&do_store);
-    }
-  } else if (representation.IsDouble()) {
-    Label do_store, heap_number;
-    __ LoadRoot(scratch3, Heap::kMutableHeapNumberMapRootIndex);
-    __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow,
-                          TAG_RESULT, MUTABLE);
-
-    __ JumpIfNotSmi(value_reg, &heap_number);
-    __ SmiUntag(scratch1, value_reg);
-    __ mtc1(scratch1, f6);
-    __ cvt_d_w(f4, f6);
-    __ jmp(&do_store);
-
-    __ bind(&heap_number);
-    __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label,
-                DONT_DO_SMI_CHECK);
-    __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
-
-    __ bind(&do_store);
-    __ sdc1(f4, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
-  }
-
-  // Stub never generated for objects that require access checks.
-  DCHECK(!transition->is_access_check_needed());
-
-  // Perform map transition for the receiver if necessary.
-  if (details.type() == FIELD &&
-      Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) {
-    // The properties must be extended before we can store the value.
-    // We jump to a runtime call that extends the properties array.
-    __ push(receiver_reg);
-    __ li(a2, Operand(transition));
-    __ Push(a2, a0);
-    __ TailCallExternalReference(
-        ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
-                          isolate()),
-        3, 1);
-    return;
-  }
-
-  // Update the map of the object.
-  __ li(scratch1, Operand(transition));
-  __ sd(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
-
-  // Update the write barrier for the map field.
-  __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2,
-                      kRAHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
-
-  if (details.type() == CONSTANT) {
-    DCHECK(value_reg.is(a0));
-    __ Ret(USE_DELAY_SLOT);
-    __ mov(v0, a0);
-    return;
-  }
-
-  int index = transition->instance_descriptors()->GetFieldIndex(
-      transition->LastAdded());
-
-  // Adjust for the number of properties stored in the object. Even in the
-  // face of a transition we can use the old map here because the size of the
-  // object and the number of in-object properties is not going to change.
-  index -= transition->inobject_properties();
-
-  // TODO(verwaest): Share this code as a code stub.
-  SmiCheck smi_check =
-      representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
-  if (index < 0) {
-    // Set the property straight into the object.
-    int offset = transition->instance_size() + (index * kPointerSize);
-    if (representation.IsDouble()) {
-      __ sd(storage_reg, FieldMemOperand(receiver_reg, offset));
-    } else {
-      __ sd(value_reg, FieldMemOperand(receiver_reg, offset));
-    }
-
-    if (!representation.IsSmi()) {
-      // Update the write barrier for the array address.
-      if (!representation.IsDouble()) {
-        __ mov(storage_reg, value_reg);
-      }
-      __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1,
-                          kRAHasNotBeenSaved, kDontSaveFPRegs,
-                          EMIT_REMEMBERED_SET, smi_check);
-    }
-  } else {
-    // Write to the properties array.
-    int offset = index * kPointerSize + FixedArray::kHeaderSize;
-    // Get the properties array
-    __ ld(scratch1, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
-    if (representation.IsDouble()) {
-      __ sd(storage_reg, FieldMemOperand(scratch1, offset));
-    } else {
-      __ sd(value_reg, FieldMemOperand(scratch1, offset));
-    }
-
-    if (!representation.IsSmi()) {
-      // Update the write barrier for the array address.
-      if (!representation.IsDouble()) {
-        __ mov(storage_reg, value_reg);
-      }
-      __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg,
-                          kRAHasNotBeenSaved, kDontSaveFPRegs,
-                          EMIT_REMEMBERED_SET, smi_check);
-    }
-  }
-
-  // Return the value (register v0).
-  DCHECK(value_reg.is(a0));
-  __ bind(&exit);
-  __ Ret(USE_DELAY_SLOT);
-  __ mov(v0, a0);
+void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
+  __ li(this->name(), Operand(name));
 }
 
 
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
-                                                   Register value_reg,
-                                                   Label* miss_label) {
-  DCHECK(lookup->representation().IsHeapObject());
-  __ JumpIfSmi(value_reg, miss_label);
-  HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
-  __ ld(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset));
-  Label do_store;
-  Handle<Map> current;
-  while (true) {
-    // Do the CompareMap() directly within the Branch() functions.
-    current = it.Current();
-    it.Advance();
-    if (it.Done()) {
-      __ Branch(miss_label, ne, scratch1(), Operand(current));
-      break;
-    }
-    __ Branch(&do_store, eq, scratch1(), Operand(current));
+void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
+                                                   Register scratch,
+                                                   Label* miss) {
+  Handle<WeakCell> cell = Map::WeakCellForMap(transition);
+  Register map_reg = StoreTransitionDescriptor::MapRegister();
+  DCHECK(!map_reg.is(scratch));
+  __ LoadWeakValue(map_reg, cell, miss);
+  if (transition->CanBeDeprecated()) {
+    __ ld(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
+    __ And(at, scratch, Operand(Map::Deprecated::kMask));
+    __ Branch(miss, ne, at, Operand(zero_reg));
   }
-  __ bind(&do_store);
+}
 
-  StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
-                      lookup->representation());
-  GenerateTailCall(masm(), stub.GetCode());
+
+void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
+                                                      int descriptor,
+                                                      Register value_reg,
+                                                      Register scratch,
+                                                      Label* miss_label) {
+  DCHECK(!map_reg.is(scratch));
+  DCHECK(!map_reg.is(value_reg));
+  DCHECK(!value_reg.is(scratch));
+  __ LoadInstanceDescriptors(map_reg, scratch);
+  __ ld(scratch,
+        FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
+  __ Branch(miss_label, ne, value_reg, Operand(scratch));
+}
+
+
+void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type,
+                                                        Register value_reg,
+                                                        Label* miss_label) {
+  __ JumpIfSmi(value_reg, miss_label);
+  HeapType::Iterator<Map> it = field_type->Classes();
+  if (!it.Done()) {
+    __ ld(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset));
+    Label do_store;
+    Handle<Map> current;
+    while (true) {
+      // Do the CompareMap() directly within the Branch() functions.
+      current = it.Current();
+      it.Advance();
+      if (it.Done()) {
+        __ Branch(miss_label, ne, scratch1(), Operand(current));
+        break;
+      }
+      __ Branch(&do_store, eq, scratch1(), Operand(current));
+    }
+    __ bind(&do_store);
+  }
 }
 
 
@@ -555,18 +443,12 @@
       reg = holder_reg;  // From now on the object will be in holder_reg.
       __ ld(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
     } else {
-      // Two possible reasons for loading the prototype from the map:
-      // (1) Can't store references to new space in code.
-      // (2) Handler is shared for all receivers with the same prototype
-      //     map (but not necessarily the same prototype instance).
-      bool load_prototype_from_map =
-          heap()->InNewSpace(*prototype) || depth == 1;
       Register map_reg = scratch1;
+      __ ld(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
       if (depth != 1 || check == CHECK_ALL_MAPS) {
-        // CheckMap implicitly loads the map of |reg| into |map_reg|.
-        __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK);
-      } else {
-        __ ld(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
+        Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+        __ GetWeakValue(scratch2, cell);
+        __ Branch(miss, ne, scratch2, Operand(map_reg));
       }
 
       // Check access rights to the global object.  This has to happen after
@@ -584,11 +466,7 @@
 
       reg = holder_reg;  // From now on the object will be in holder_reg.
 
-      if (load_prototype_from_map) {
-        __ ld(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
-      } else {
-        __ li(reg, Operand(prototype));
-      }
+      __ ld(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
     }
 
     // Go to the next object in the prototype chain.
@@ -601,7 +479,10 @@
 
   if (depth != 0 || check == CHECK_ALL_MAPS) {
     // Check the holder map.
-    __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK);
+    __ ld(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
+    Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+    __ GetWeakValue(scratch2, cell);
+    __ Branch(miss, ne, scratch2, Operand(scratch1));
   }
 
   // Perform security check for access to the global object.
@@ -621,6 +502,10 @@
     Label success;
     __ Branch(&success);
     __ bind(miss);
+    if (IC::ICUseVector(kind())) {
+      DCHECK(kind() == Code::LOAD_IC);
+      PopVectorAndSlot();
+    }
     TailCallBuiltin(masm(), MissBuiltin(kind()));
     __ bind(&success);
   }
@@ -722,6 +607,7 @@
     } else {
       __ Push(holder_reg, this->name());
     }
+    InterceptorVectorSlotPush(holder_reg);
     // Invoke an interceptor.  Note: map checks from receiver to
     // interceptor's holder has been compiled before (see a caller
     // of this method).
@@ -738,6 +624,7 @@
     __ Ret();
 
     __ bind(&interceptor_failed);
+    InterceptorVectorSlotPop(holder_reg);
     if (must_preserve_receiver_reg) {
       __ Pop(receiver(), holder_reg, this->name());
     } else {
@@ -767,7 +654,7 @@
 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
     Handle<JSObject> object, Handle<Name> name,
     Handle<ExecutableAccessorInfo> callback) {
-  Register holder_reg = Frontend(receiver(), name);
+  Register holder_reg = Frontend(name);
 
   __ Push(receiver(), holder_reg);  // Receiver.
   __ li(at, Operand(callback));     // Callback info.
@@ -807,12 +694,16 @@
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
   Label miss;
+  if (IC::ICUseVector(kind())) {
+    PushVectorAndSlot();
+  }
 
   FrontendHeader(receiver(), name, &miss);
 
   // Get the value from the cell.
   Register result = StoreDescriptor::ValueRegister();
-  __ li(result, Operand(cell));
+  Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
+  __ LoadWeakValue(result, weak_cell, &miss);
   __ ld(result, FieldMemOperand(result, Cell::kValueOffset));
 
   // Check for deleted property if property can actually be deleted.
@@ -823,6 +714,9 @@
 
   Counters* counters = isolate()->counters();
   __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
+  if (IC::ICUseVector(kind())) {
+    DiscardVectorAndSlot();
+  }
   __ Ret(USE_DELAY_SLOT);
   __ mov(v0, result);
 
diff --git a/src/ic/mips64/ic-compiler-mips64.cc b/src/ic/mips64/ic-compiler-mips64.cc
index 796ed87..7ed4492 100644
--- a/src/ic/mips64/ic-compiler-mips64.cc
+++ b/src/ic/mips64/ic-compiler-mips64.cc
@@ -24,9 +24,12 @@
 
   if (check == PROPERTY &&
       (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) {
-    // In case we are compiling an IC for dictionary loads and stores, just
+    // In case we are compiling an IC for dictionary loads or stores, just
     // check whether the name is unique.
     if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) {
+      // Keyed loads with dictionaries shouldn't be here, they go generic.
+      // The DCHECK is to protect assumptions when --vector-ics is on.
+      DCHECK(kind() != Code::KEYED_LOAD_IC);
       Register tmp = scratch1();
       __ JumpIfSmi(this->name(), &miss);
       __ ld(tmp, FieldMemOperand(this->name(), HeapObject::kMapOffset));
@@ -57,7 +60,9 @@
       number_of_handled_maps++;
       // Check map and tail call if there's a match.
       // Separate compare from branch, to provide path for above JumpIfSmi().
-      __ Dsubu(match, map_reg, Operand(map));
+      Handle<WeakCell> cell = Map::WeakCellForMap(map);
+      __ GetWeakValue(match, cell);
+      __ Dsubu(match, match, Operand(map_reg));
       if (type->Is(HeapType::Number())) {
         DCHECK(!number_case.is_unused());
         __ bind(&number_case);
@@ -85,15 +90,20 @@
   __ JumpIfSmi(receiver(), &miss);
 
   int receiver_count = receiver_maps->length();
-  __ ld(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
+  Register map_reg = scratch1();
+  Register match = scratch2();
+  __ ld(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
   for (int i = 0; i < receiver_count; ++i) {
+    Handle<WeakCell> cell = Map::WeakCellForMap(receiver_maps->at(i));
+    __ GetWeakValue(match, cell);
     if (transitioned_maps->at(i).is_null()) {
-      __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq, scratch1(),
-              Operand(receiver_maps->at(i)));
+      __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq, match,
+              Operand(map_reg));
     } else {
       Label next_map;
-      __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i)));
-      __ li(transition_map(), Operand(transitioned_maps->at(i)));
+      __ Branch(&next_map, ne, match, Operand(map_reg));
+      Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
+      __ LoadWeakValue(transition_map(), cell, &miss);
       __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET);
       __ bind(&next_map);
     }
diff --git a/src/ic/mips64/ic-mips64.cc b/src/ic/mips64/ic-mips64.cc
index a5d9fe7..7ac191c 100644
--- a/src/ic/mips64/ic-mips64.cc
+++ b/src/ic/mips64/ic-mips64.cc
@@ -270,18 +270,35 @@
 static const Register LoadIC_TempRegister() { return a3; }
 
 
+static void LoadIC_PushArgs(MacroAssembler* masm) {
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register name = LoadDescriptor::NameRegister();
+  if (FLAG_vector_ics) {
+    Register slot = VectorLoadICDescriptor::SlotRegister();
+    Register vector = VectorLoadICDescriptor::VectorRegister();
+
+    __ Push(receiver, name, slot, vector);
+  } else {
+    __ Push(receiver, name);
+  }
+}
+
+
 void LoadIC::GenerateMiss(MacroAssembler* masm) {
   // The return address is on the stack.
   Isolate* isolate = masm->isolate();
 
-  __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, a4);
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(a4, a5, VectorLoadICDescriptor::SlotRegister(),
+                     VectorLoadICDescriptor::VectorRegister()));
+  __ IncrementCounter(isolate->counters()->load_miss(), 1, a4, a5);
 
-  __ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
-  __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
+  LoadIC_PushArgs(masm);
 
   // Perform tail call to the entry.
   ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
-  __ TailCallExternalReference(ref, 2, 1);
+  int arg_count = FLAG_vector_ics ? 4 : 2;
+  __ TailCallExternalReference(ref, arg_count, 1);
 }
 
 
@@ -410,15 +427,19 @@
   // The return address is in ra.
   Isolate* isolate = masm->isolate();
 
-  __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, a4);
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(a4, a5, VectorLoadICDescriptor::SlotRegister(),
+                     VectorLoadICDescriptor::VectorRegister()));
+  __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a4, a5);
 
-  __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
+  LoadIC_PushArgs(masm);
 
   // Perform tail call to the entry.
   ExternalReference ref =
       ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
 
-  __ TailCallExternalReference(ref, 2, 1);
+  int arg_count = FLAG_vector_ics ? 4 : 2;
+  __ TailCallExternalReference(ref, arg_count, 1);
 }
 
 
@@ -599,33 +620,7 @@
 }
 
 
-void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
-  // Return address is in ra.
-  Label miss;
-
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register index = LoadDescriptor::NameRegister();
-  Register scratch = a3;
-  Register result = v0;
-  DCHECK(!scratch.is(receiver) && !scratch.is(index));
-
-  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
-                                          &miss,  // When not a string.
-                                          &miss,  // When not a number.
-                                          &miss,  // When index out of range.
-                                          STRING_INDEX_IS_ARRAY_INDEX);
-  char_at_generator.GenerateFast(masm);
-  __ Ret();
-
-  StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-}
-
-
-static void KeyedStoreGenerateGenericHelper(
+static void KeyedStoreGenerateMegamorphicHelper(
     MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
     KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
     Register value, Register key, Register receiver, Register receiver_map,
@@ -775,8 +770,8 @@
 }
 
 
-void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
-                                   StrictMode strict_mode) {
+void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
+                                       StrictMode strict_mode) {
   // ---------- S t a t e --------------
   //  -- a0     : value
   //  -- a1     : key
@@ -785,7 +780,7 @@
   // -----------------------------------
   Label slow, fast_object, fast_object_grow;
   Label fast_double, fast_double_grow;
-  Label array, extra, check_if_double_array;
+  Label array, extra, check_if_double_array, maybe_name_key, miss;
 
   // Register usage.
   Register value = StoreDescriptor::ValueRegister();
@@ -798,7 +793,7 @@
   // a4 and a5 are used as general scratch registers.
 
   // Check that the key is a smi.
-  __ JumpIfNotSmi(key, &slow);
+  __ JumpIfNotSmi(key, &maybe_name_key);
   // Check that the object isn't a smi.
   __ JumpIfSmi(receiver, &slow);
   // Get the map of the object.
@@ -828,6 +823,18 @@
   // a1: key.
   // a2: receiver.
   PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode);
+  // Never returns to here.
+
+  __ bind(&maybe_name_key);
+  __ ld(a4, FieldMemOperand(key, HeapObject::kMapOffset));
+  __ lb(a4, FieldMemOperand(a4, Map::kInstanceTypeOffset));
+  __ JumpIfNotUniqueNameInstanceType(a4, &slow);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::STORE_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::STORE_IC, flags, false, receiver, key, a3, a4, a5, a6);
+  // Cache miss.
+  __ Branch(&miss);
 
   // Extra capacity case: Check if there is extra capacity to
   // perform the store and update the length. Used for adding one
@@ -860,13 +867,16 @@
   __ ld(a4, FieldMemOperand(receiver, JSArray::kLengthOffset));
   __ Branch(&extra, hs, key, Operand(a4));
 
-  KeyedStoreGenerateGenericHelper(
+  KeyedStoreGenerateMegamorphicHelper(
       masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength,
       value, key, receiver, receiver_map, elements_map, elements);
-  KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
-                                  &slow, kDontCheckMap, kIncrementLength, value,
-                                  key, receiver, receiver_map, elements_map,
-                                  elements);
+  KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
+                                      &fast_double_grow, &slow, kDontCheckMap,
+                                      kIncrementLength, value, key, receiver,
+                                      receiver_map, elements_map, elements);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
 }
 
 
@@ -891,8 +901,8 @@
   // Get the receiver from the stack and probe the stub cache.
   Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
       Code::ComputeHandlerFlags(Code::STORE_IC));
-  masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver,
-                                               name, a3, a4, a5, a6);
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::STORE_IC, flags, false, receiver, name, a3, a4, a5, a6);
 
   // Cache miss: Jump to runtime.
   GenerateMiss(masm);
diff --git a/src/ic/mips64/stub-cache-mips64.cc b/src/ic/mips64/stub-cache-mips64.cc
index 272e5be..04883d7 100644
--- a/src/ic/mips64/stub-cache-mips64.cc
+++ b/src/ic/mips64/stub-cache-mips64.cc
@@ -7,7 +7,9 @@
 #if V8_TARGET_ARCH_MIPS64
 
 #include "src/codegen.h"
+#include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
+#include "src/interface-descriptors.h"
 
 namespace v8 {
 namespace internal {
@@ -16,7 +18,7 @@
 
 
 static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
-                       Code::Flags flags, bool leave_frame,
+                       Code::Kind ic_kind, Code::Flags flags, bool leave_frame,
                        StubCache::Table table, Register receiver, Register name,
                        // Number of the cache entry, not scaled.
                        Register offset, Register scratch, Register scratch2,
@@ -90,10 +92,11 @@
 }
 
 
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
-                              bool leave_frame, Register receiver,
-                              Register name, Register scratch, Register extra,
-                              Register extra2, Register extra3) {
+void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
+                              Code::Flags flags, bool leave_frame,
+                              Register receiver, Register name,
+                              Register scratch, Register extra, Register extra2,
+                              Register extra3) {
   Isolate* isolate = masm->isolate();
   Label miss;
 
@@ -106,15 +109,7 @@
   DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
 
   // Make sure that there are no register conflicts.
-  DCHECK(!scratch.is(receiver));
-  DCHECK(!scratch.is(name));
-  DCHECK(!extra.is(receiver));
-  DCHECK(!extra.is(name));
-  DCHECK(!extra.is(scratch));
-  DCHECK(!extra2.is(receiver));
-  DCHECK(!extra2.is(name));
-  DCHECK(!extra2.is(scratch));
-  DCHECK(!extra2.is(extra));
+  DCHECK(!AreAliased(receiver, name, scratch, extra, extra2, extra3));
 
   // Check register validity.
   DCHECK(!scratch.is(no_reg));
@@ -122,6 +117,17 @@
   DCHECK(!extra2.is(no_reg));
   DCHECK(!extra3.is(no_reg));
 
+#ifdef DEBUG
+  // If vector-based ics are in use, ensure that scratch, extra, extra2 and
+  // extra3 don't conflict with the vector and slot registers, which need
+  // to be preserved for a handler call or miss.
+  if (IC::ICUseVector(ic_kind)) {
+    Register vector = VectorLoadICDescriptor::VectorRegister();
+    Register slot = VectorLoadICDescriptor::SlotRegister();
+    DCHECK(!AreAliased(vector, slot, scratch, extra, extra2, extra3));
+  }
+#endif
+
   Counters* counters = masm->isolate()->counters();
   __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2,
                       extra3);
@@ -141,8 +147,8 @@
   __ And(scratch, scratch, Operand(mask));
 
   // Probe the primary table.
-  ProbeTable(isolate, masm, flags, leave_frame, kPrimary, receiver, name,
-             scratch, extra, extra2, extra3);
+  ProbeTable(isolate, masm, ic_kind, flags, leave_frame, kPrimary, receiver,
+             name, scratch, extra, extra2, extra3);
 
   // Primary miss: Compute hash for secondary probe.
   __ dsrl(at, name, kCacheIndexShift);
@@ -152,8 +158,8 @@
   __ And(scratch, scratch, Operand(mask2));
 
   // Probe the secondary table.
-  ProbeTable(isolate, masm, flags, leave_frame, kSecondary, receiver, name,
-             scratch, extra, extra2, extra3);
+  ProbeTable(isolate, masm, ic_kind, flags, leave_frame, kSecondary, receiver,
+             name, scratch, extra, extra2, extra3);
 
   // Cache miss: Fall-through and let caller handle the miss by
   // entering the runtime system.
diff --git a/src/ic/ppc/access-compiler-ppc.cc b/src/ic/ppc/access-compiler-ppc.cc
new file mode 100644
index 0000000..e98f517
--- /dev/null
+++ b/src/ic/ppc/access-compiler-ppc.cc
@@ -0,0 +1,46 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/ic/access-compiler.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm)
+
+
+void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm,
+                                              Handle<Code> code) {
+  __ Jump(code, RelocInfo::CODE_TARGET);
+}
+
+
+Register* PropertyAccessCompiler::load_calling_convention() {
+  // receiver, name, scratch1, scratch2, scratch3, scratch4.
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register name = LoadDescriptor::NameRegister();
+  static Register registers[] = {receiver, name, r6, r3, r7, r8};
+  return registers;
+}
+
+
+Register* PropertyAccessCompiler::store_calling_convention() {
+  // receiver, name, scratch1, scratch2, scratch3.
+  Register receiver = StoreDescriptor::ReceiverRegister();
+  Register name = StoreDescriptor::NameRegister();
+  DCHECK(r6.is(ElementTransitionAndStoreDescriptor::MapRegister()));
+  static Register registers[] = {receiver, name, r6, r7, r8};
+  return registers;
+}
+
+
+#undef __
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ic/ppc/handler-compiler-ppc.cc b/src/ic/ppc/handler-compiler-ppc.cc
new file mode 100644
index 0000000..2f29c83
--- /dev/null
+++ b/src/ic/ppc/handler-compiler-ppc.cc
@@ -0,0 +1,698 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/ic/call-optimization.h"
+#include "src/ic/handler-compiler.h"
+#include "src/ic/ic.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm)
+
+
+void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
+    MacroAssembler* masm, Handle<HeapType> type, Register receiver,
+    Handle<JSFunction> getter) {
+  // ----------- S t a t e -------------
+  //  -- r3    : receiver
+  //  -- r5    : name
+  //  -- lr    : return address
+  // -----------------------------------
+  {
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+
+    if (!getter.is_null()) {
+      // Call the JavaScript getter with the receiver on the stack.
+      if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
+        // Swap in the global receiver.
+        __ LoadP(receiver,
+                 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
+      }
+      __ push(receiver);
+      ParameterCount actual(0);
+      ParameterCount expected(getter);
+      __ InvokeFunction(getter, expected, actual, CALL_FUNCTION,
+                        NullCallWrapper());
+    } else {
+      // If we generate a global code snippet for deoptimization only, remember
+      // the place to continue after deoptimization.
+      masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
+    }
+
+    // Restore context register.
+    __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  }
+  __ Ret();
+}
+
+
+void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
+    MacroAssembler* masm, Handle<HeapType> type, Register receiver,
+    Handle<JSFunction> setter) {
+  // ----------- S t a t e -------------
+  //  -- lr    : return address
+  // -----------------------------------
+  {
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+
+    // Save value register, so we can restore it later.
+    __ push(value());
+
+    if (!setter.is_null()) {
+      // Call the JavaScript setter with receiver and value on the stack.
+      if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
+        // Swap in the global receiver.
+        __ LoadP(receiver,
+                 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
+      }
+      __ Push(receiver, value());
+      ParameterCount actual(1);
+      ParameterCount expected(setter);
+      __ InvokeFunction(setter, expected, actual, CALL_FUNCTION,
+                        NullCallWrapper());
+    } else {
+      // If we generate a global code snippet for deoptimization only, remember
+      // the place to continue after deoptimization.
+      masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
+    }
+
+    // We have to return the passed value, not the return value of the setter.
+    __ pop(r3);
+
+    // Restore context register.
+    __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  }
+  __ Ret();
+}
+
+
+void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
+    MacroAssembler* masm, Label* miss_label, Register receiver,
+    Handle<Name> name, Register scratch0, Register scratch1) {
+  DCHECK(name->IsUniqueName());
+  DCHECK(!receiver.is(scratch0));
+  Counters* counters = masm->isolate()->counters();
+  __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
+  __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
+
+  Label done;
+
+  const int kInterceptorOrAccessCheckNeededMask =
+      (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
+
+  // Bail out if the receiver has a named interceptor or requires access checks.
+  Register map = scratch1;
+  __ LoadP(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ lbz(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
+  __ andi(r0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
+  __ bne(miss_label, cr0);
+
+  // Check that receiver is a JSObject.
+  __ lbz(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  __ cmpi(scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
+  __ blt(miss_label);
+
+  // Load properties array.
+  Register properties = scratch0;
+  __ LoadP(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+  // Check that the properties array is a dictionary.
+  __ LoadP(map, FieldMemOperand(properties, HeapObject::kMapOffset));
+  Register tmp = properties;
+  __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
+  __ cmp(map, tmp);
+  __ bne(miss_label);
+
+  // Restore the temporarily used register.
+  __ LoadP(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+
+
+  NameDictionaryLookupStub::GenerateNegativeLookup(
+      masm, miss_label, &done, receiver, properties, name, scratch1);
+  __ bind(&done);
+  __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
+}
+
+
+void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
+    MacroAssembler* masm, int index, Register prototype, Label* miss) {
+  Isolate* isolate = masm->isolate();
+  // Get the global function with the given index.
+  Handle<JSFunction> function(
+      JSFunction::cast(isolate->native_context()->get(index)));
+
+  // Check we're still in the same context.
+  Register scratch = prototype;
+  const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX);
+  __ LoadP(scratch, MemOperand(cp, offset));
+  __ LoadP(scratch,
+           FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
+  __ LoadP(scratch, MemOperand(scratch, Context::SlotOffset(index)));
+  __ Move(ip, function);
+  __ cmp(ip, scratch);
+  __ bne(miss);
+
+  // Load its initial map. The global functions all have initial maps.
+  __ Move(prototype, Handle<Map>(function->initial_map()));
+  // Load the prototype from the initial map.
+  __ LoadP(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
+}
+
+
+void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
+    MacroAssembler* masm, Register receiver, Register scratch1,
+    Register scratch2, Label* miss_label) {
+  __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
+  __ mr(r3, scratch1);
+  __ Ret();
+}
+
+
+// Generate code to check that a global property cell is empty. Create
+// the property cell at compilation time if no cell exists for the
+// property.
+void PropertyHandlerCompiler::GenerateCheckPropertyCell(
+    MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
+    Register scratch, Label* miss) {
+  Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
+  DCHECK(cell->value()->IsTheHole());
+  __ mov(scratch, Operand(cell));
+  __ LoadP(scratch, FieldMemOperand(scratch, Cell::kValueOffset));
+  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+  __ cmp(scratch, ip);
+  __ bne(miss);
+}
+
+
+static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
+                                     Register holder, Register name,
+                                     Handle<JSObject> holder_obj) {
+  STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
+  STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1);
+  STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2);
+  STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3);
+  STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4);
+  __ push(name);
+  Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
+  DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor));
+  Register scratch = name;
+  __ mov(scratch, Operand(interceptor));
+  __ push(scratch);
+  __ push(receiver);
+  __ push(holder);
+}
+
+
+static void CompileCallLoadPropertyWithInterceptor(
+    MacroAssembler* masm, Register receiver, Register holder, Register name,
+    Handle<JSObject> holder_obj, IC::UtilityId id) {
+  PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
+  __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()),
+                           NamedLoadHandlerCompiler::kInterceptorArgsLength);
+}
+
+
+// Generate call to api function.
+void PropertyHandlerCompiler::GenerateFastApiCall(
+    MacroAssembler* masm, const CallOptimization& optimization,
+    Handle<Map> receiver_map, Register receiver, Register scratch_in,
+    bool is_store, int argc, Register* values) {
+  DCHECK(!receiver.is(scratch_in));
+  __ push(receiver);
+  // Write the arguments to stack frame.
+  for (int i = 0; i < argc; i++) {
+    Register arg = values[argc - 1 - i];
+    DCHECK(!receiver.is(arg));
+    DCHECK(!scratch_in.is(arg));
+    __ push(arg);
+  }
+  DCHECK(optimization.is_simple_api_call());
+
+  // Abi for CallApiFunctionStub.
+  Register callee = r3;
+  Register call_data = r7;
+  Register holder = r5;
+  Register api_function_address = r4;
+
+  // Put holder in place.
+  CallOptimization::HolderLookup holder_lookup;
+  Handle<JSObject> api_holder =
+      optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup);
+  switch (holder_lookup) {
+    case CallOptimization::kHolderIsReceiver:
+      __ Move(holder, receiver);
+      break;
+    case CallOptimization::kHolderFound:
+      __ Move(holder, api_holder);
+      break;
+    case CallOptimization::kHolderNotFound:
+      UNREACHABLE();
+      break;
+  }
+
+  Isolate* isolate = masm->isolate();
+  Handle<JSFunction> function = optimization.constant_function();
+  Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
+  Handle<Object> call_data_obj(api_call_info->data(), isolate);
+
+  // Put callee in place.
+  __ Move(callee, function);
+
+  bool call_data_undefined = false;
+  // Put call_data in place.
+  if (isolate->heap()->InNewSpace(*call_data_obj)) {
+    __ Move(call_data, api_call_info);
+    __ LoadP(call_data,
+             FieldMemOperand(call_data, CallHandlerInfo::kDataOffset));
+  } else if (call_data_obj->IsUndefined()) {
+    call_data_undefined = true;
+    __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex);
+  } else {
+    __ Move(call_data, call_data_obj);
+  }
+
+  // Put api_function_address in place.
+  Address function_address = v8::ToCData<Address>(api_call_info->callback());
+  ApiFunction fun(function_address);
+  ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
+  ExternalReference ref = ExternalReference(&fun, type, masm->isolate());
+  __ mov(api_function_address, Operand(ref));
+
+  // Jump to stub.
+  CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc);
+  __ TailCallStub(&stub);
+}
+
+
+void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
+  // Push receiver, key and value for runtime call.
+  __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
+          StoreDescriptor::ValueRegister());
+
+  // The slow case calls into the runtime to complete the store without causing
+  // an IC miss that would otherwise cause a transition to the generic stub.
+  ExternalReference ref =
+      ExternalReference(IC_Utility(IC::kStoreIC_Slow), masm->isolate());
+  __ TailCallExternalReference(ref, 3, 1);
+}
+
+
+void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
+  // Push receiver, key and value for runtime call.
+  __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
+          StoreDescriptor::ValueRegister());
+
+  // The slow case calls into the runtime to complete the store without causing
+  // an IC miss that would otherwise cause a transition to the generic stub.
+  ExternalReference ref =
+      ExternalReference(IC_Utility(IC::kKeyedStoreIC_Slow), masm->isolate());
+  __ TailCallExternalReference(ref, 3, 1);
+}
+
+
+#undef __
+#define __ ACCESS_MASM(masm())
+
+
+void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
+                                                    Handle<Name> name) {
+  if (!label->is_unused()) {
+    __ bind(label);
+    __ mov(this->name(), Operand(name));
+  }
+}
+
+
+void NamedStoreHandlerCompiler::GenerateRestoreNameAndMap(
+    Handle<Name> name, Handle<Map> transition) {
+  __ mov(this->name(), Operand(name));
+  __ mov(StoreTransitionDescriptor::MapRegister(), Operand(transition));
+}
+
+
+void NamedStoreHandlerCompiler::GenerateConstantCheck(Object* constant,
+                                                      Register value_reg,
+                                                      Label* miss_label) {
+  __ Move(scratch1(), handle(constant, isolate()));
+  __ cmp(value_reg, scratch1());
+  __ bne(miss_label);
+}
+
+
+void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type,
+                                                        Register value_reg,
+                                                        Label* miss_label) {
+  __ JumpIfSmi(value_reg, miss_label);
+  HeapType::Iterator<Map> it = field_type->Classes();
+  if (!it.Done()) {
+    __ LoadP(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset));
+    Label do_store;
+    while (true) {
+      __ CompareMap(scratch1(), it.Current(), &do_store);
+      it.Advance();
+      if (it.Done()) {
+        __ bne(miss_label);
+        break;
+      }
+      __ beq(&do_store);
+    }
+    __ bind(&do_store);
+  }
+}
+
+
+Register PropertyHandlerCompiler::CheckPrototypes(
+    Register object_reg, Register holder_reg, Register scratch1,
+    Register scratch2, Handle<Name> name, Label* miss,
+    PrototypeCheckType check) {
+  Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate()));
+
+  // Make sure there's no overlap between holder and object registers.
+  DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
+  DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
+         !scratch2.is(scratch1));
+
+  // Keep track of the current object in register reg.
+  Register reg = object_reg;
+  int depth = 0;
+
+  Handle<JSObject> current = Handle<JSObject>::null();
+  if (type()->IsConstant()) {
+    current = Handle<JSObject>::cast(type()->AsConstant()->Value());
+  }
+  Handle<JSObject> prototype = Handle<JSObject>::null();
+  Handle<Map> current_map = receiver_map;
+  Handle<Map> holder_map(holder()->map());
+  // Traverse the prototype chain and check the maps in the prototype chain for
+  // fast and global objects or do negative lookup for normal objects.
+  while (!current_map.is_identical_to(holder_map)) {
+    ++depth;
+
+    // Only global objects and objects that do not require access
+    // checks are allowed in stubs.
+    DCHECK(current_map->IsJSGlobalProxyMap() ||
+           !current_map->is_access_check_needed());
+
+    prototype = handle(JSObject::cast(current_map->prototype()));
+    if (current_map->is_dictionary_map() &&
+        !current_map->IsJSGlobalObjectMap()) {
+      DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
+      if (!name->IsUniqueName()) {
+        DCHECK(name->IsString());
+        name = factory()->InternalizeString(Handle<String>::cast(name));
+      }
+      DCHECK(current.is_null() ||
+             current->property_dictionary()->FindEntry(name) ==
+                 NameDictionary::kNotFound);
+
+      GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
+                                       scratch2);
+
+      __ LoadP(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
+      reg = holder_reg;  // From now on the object will be in holder_reg.
+      __ LoadP(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
+    } else {
+      Register map_reg = scratch1;
+      if (depth != 1 || check == CHECK_ALL_MAPS) {
+        // CheckMap implicitly loads the map of |reg| into |map_reg|.
+        __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK);
+      } else {
+        __ LoadP(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
+      }
+
+      // Check access rights to the global object.  This has to happen after
+      // the map check so that we know that the object is actually a global
+      // object.
+      // This allows us to install generated handlers for accesses to the
+      // global proxy (as opposed to using slow ICs). See corresponding code
+      // in LookupForRead().
+      if (current_map->IsJSGlobalProxyMap()) {
+        __ CheckAccessGlobalProxy(reg, scratch2, miss);
+      } else if (current_map->IsJSGlobalObjectMap()) {
+        GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
+                                  name, scratch2, miss);
+      }
+
+      reg = holder_reg;  // From now on the object will be in holder_reg.
+
+      // Two possible reasons for loading the prototype from the map:
+      // (1) Can't store references to new space in code.
+      // (2) Handler is shared for all receivers with the same prototype
+      //     map (but not necessarily the same prototype instance).
+      bool load_prototype_from_map =
+          heap()->InNewSpace(*prototype) || depth == 1;
+      if (load_prototype_from_map) {
+        __ LoadP(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
+      } else {
+        __ mov(reg, Operand(prototype));
+      }
+    }
+
+    // Go to the next object in the prototype chain.
+    current = prototype;
+    current_map = handle(current->map());
+  }
+
+  // Log the check depth.
+  LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
+
+  if (depth != 0 || check == CHECK_ALL_MAPS) {
+    // Check the holder map.
+    __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK);
+  }
+
+  // Perform security check for access to the global object.
+  DCHECK(current_map->IsJSGlobalProxyMap() ||
+         !current_map->is_access_check_needed());
+  if (current_map->IsJSGlobalProxyMap()) {
+    __ CheckAccessGlobalProxy(reg, scratch1, miss);
+  }
+
+  // Return the register containing the holder.
+  return reg;
+}
+
+
+void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
+  if (!miss->is_unused()) {
+    Label success;
+    __ b(&success);
+    __ bind(miss);
+    TailCallBuiltin(masm(), MissBuiltin(kind()));
+    __ bind(&success);
+  }
+}
+
+
+void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
+  if (!miss->is_unused()) {
+    Label success;
+    __ b(&success);
+    GenerateRestoreName(miss, name);
+    TailCallBuiltin(masm(), MissBuiltin(kind()));
+    __ bind(&success);
+  }
+}
+
+
+void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
+  // Return the constant value.
+  __ Move(r3, value);
+  __ Ret();
+}
+
+
+void NamedLoadHandlerCompiler::GenerateLoadCallback(
+    Register reg, Handle<ExecutableAccessorInfo> callback) {
+  // Build AccessorInfo::args_ list on the stack and push property name below
+  // the exit frame to make GC aware of them and store pointers to them.
+  STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
+  STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
+  STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
+  STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
+  STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
+  STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
+  STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
+  DCHECK(!scratch2().is(reg));
+  DCHECK(!scratch3().is(reg));
+  DCHECK(!scratch4().is(reg));
+  __ push(receiver());
+  if (heap()->InNewSpace(callback->data())) {
+    __ Move(scratch3(), callback);
+    __ LoadP(scratch3(),
+             FieldMemOperand(scratch3(), ExecutableAccessorInfo::kDataOffset));
+  } else {
+    __ Move(scratch3(), Handle<Object>(callback->data(), isolate()));
+  }
+  __ push(scratch3());
+  __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex);
+  __ mr(scratch4(), scratch3());
+  __ Push(scratch3(), scratch4());
+  __ mov(scratch4(), Operand(ExternalReference::isolate_address(isolate())));
+  __ Push(scratch4(), reg);
+  __ push(name());
+
+  // Abi for CallApiGetter
+  Register getter_address_reg = ApiGetterDescriptor::function_address();
+
+  Address getter_address = v8::ToCData<Address>(callback->getter());
+  ApiFunction fun(getter_address);
+  ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
+  ExternalReference ref = ExternalReference(&fun, type, isolate());
+  __ mov(getter_address_reg, Operand(ref));
+
+  CallApiGetterStub stub(isolate());
+  __ TailCallStub(&stub);
+}
+
+
+void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
+    LookupIterator* it, Register holder_reg) {
+  DCHECK(holder()->HasNamedInterceptor());
+  DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+
+  // Compile the interceptor call, followed by inline code to load the
+  // property from further up the prototype chain if the call fails.
+  // Check that the maps haven't changed.
+  DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
+
+  // Preserve the receiver register explicitly whenever it is different from the
+  // holder and it is needed should the interceptor return without any result.
+  // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
+  // case might cause a miss during the prototype check.
+  bool must_perform_prototype_check =
+      !holder().is_identical_to(it->GetHolder<JSObject>());
+  bool must_preserve_receiver_reg =
+      !receiver().is(holder_reg) &&
+      (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
+
+  // Save necessary data before invoking an interceptor.
+  // Requires a frame to make GC aware of pushed pointers.
+  {
+    FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
+    if (must_preserve_receiver_reg) {
+      __ Push(receiver(), holder_reg, this->name());
+    } else {
+      __ Push(holder_reg, this->name());
+    }
+    // Invoke an interceptor.  Note: map checks from receiver to
+    // interceptor's holder has been compiled before (see a caller
+    // of this method.)
+    CompileCallLoadPropertyWithInterceptor(
+        masm(), receiver(), holder_reg, this->name(), holder(),
+        IC::kLoadPropertyWithInterceptorOnly);
+
+    // Check if interceptor provided a value for property.  If it's
+    // the case, return immediately.
+    Label interceptor_failed;
+    __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
+    __ cmp(r3, scratch1());
+    __ beq(&interceptor_failed);
+    frame_scope.GenerateLeaveFrame();
+    __ Ret();
+
+    __ bind(&interceptor_failed);
+    __ pop(this->name());
+    __ pop(holder_reg);
+    if (must_preserve_receiver_reg) {
+      __ pop(receiver());
+    }
+    // Leave the internal frame.
+  }
+
+  GenerateLoadPostInterceptor(it, holder_reg);
+}
+
+
+void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
+  // Call the runtime system to load the interceptor.
+  DCHECK(holder()->HasNamedInterceptor());
+  DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
+  PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
+                           holder());
+
+  ExternalReference ref = ExternalReference(
+      IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
+  __ TailCallExternalReference(
+      ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
+}
+
+
+Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
+    Handle<JSObject> object, Handle<Name> name,
+    Handle<ExecutableAccessorInfo> callback) {
+  Register holder_reg = Frontend(receiver(), name);
+
+  __ Push(receiver(), holder_reg);  // receiver
+  __ mov(ip, Operand(callback));    // callback info
+  __ push(ip);
+  __ mov(ip, Operand(name));
+  __ Push(ip, value());
+
+  // Do tail-call to the runtime system.
+  ExternalReference store_callback_property =
+      ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
+  __ TailCallExternalReference(store_callback_property, 5, 1);
+
+  // Return the generated code.
+  return GetCode(kind(), Code::FAST, name);
+}
+
+
+Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
+    Handle<Name> name) {
+  __ Push(receiver(), this->name(), value());
+
+  // Do tail-call to the runtime system.
+  ExternalReference store_ic_property = ExternalReference(
+      IC_Utility(IC::kStorePropertyWithInterceptor), isolate());
+  __ TailCallExternalReference(store_ic_property, 3, 1);
+
+  // Return the generated code.
+  return GetCode(kind(), Code::FAST, name);
+}
+
+
+Register NamedStoreHandlerCompiler::value() {
+  return StoreDescriptor::ValueRegister();
+}
+
+
+Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
+    Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
+  Label miss;
+  FrontendHeader(receiver(), name, &miss);
+
+  // Get the value from the cell.
+  Register result = StoreDescriptor::ValueRegister();
+  __ mov(result, Operand(cell));
+  __ LoadP(result, FieldMemOperand(result, Cell::kValueOffset));
+
+  // Check for deleted property if property can actually be deleted.
+  if (is_configurable) {
+    __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+    __ cmp(result, ip);
+    __ beq(&miss);
+  }
+
+  Counters* counters = isolate()->counters();
+  __ IncrementCounter(counters->named_load_global_stub(), 1, r4, r6);
+  __ Ret();
+
+  FrontendFooter(name, &miss);
+
+  // Return the generated code.
+  return GetCode(kind(), Code::NORMAL, name);
+}
+
+
+#undef __
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM
diff --git a/src/ic/ppc/ic-compiler-ppc.cc b/src/ic/ppc/ic-compiler-ppc.cc
new file mode 100644
index 0000000..c868456
--- /dev/null
+++ b/src/ic/ppc/ic-compiler-ppc.cc
@@ -0,0 +1,130 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/ic/ic.h"
+#include "src/ic/ic-compiler.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm)
+
+
+void PropertyICCompiler::GenerateRuntimeSetProperty(MacroAssembler* masm,
+                                                    StrictMode strict_mode) {
+  __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
+          StoreDescriptor::ValueRegister());
+
+  __ mov(r0, Operand(Smi::FromInt(strict_mode)));
+  __ Push(r0);
+
+  // Do tail-call to runtime routine.
+  __ TailCallRuntime(Runtime::kSetProperty, 4, 1);
+}
+
+
+#undef __
+#define __ ACCESS_MASM(masm())
+
+
+Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types,
+                                                    CodeHandleList* handlers,
+                                                    Handle<Name> name,
+                                                    Code::StubType type,
+                                                    IcCheckType check) {
+  Label miss;
+
+  if (check == PROPERTY &&
+      (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) {
+    // In case we are compiling an IC for dictionary loads and stores, just
+    // check whether the name is unique.
+    if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) {
+      Register tmp = scratch1();
+      __ JumpIfSmi(this->name(), &miss);
+      __ LoadP(tmp, FieldMemOperand(this->name(), HeapObject::kMapOffset));
+      __ lbz(tmp, FieldMemOperand(tmp, Map::kInstanceTypeOffset));
+      __ JumpIfNotUniqueNameInstanceType(tmp, &miss);
+    } else {
+      __ Cmpi(this->name(), Operand(name), r0);
+      __ bne(&miss);
+    }
+  }
+
+  Label number_case;
+  Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
+  __ JumpIfSmi(receiver(), smi_target);
+
+  // Polymorphic keyed stores may use the map register
+  Register map_reg = scratch1();
+  DCHECK(kind() != Code::KEYED_STORE_IC ||
+         map_reg.is(ElementTransitionAndStoreDescriptor::MapRegister()));
+
+  int receiver_count = types->length();
+  int number_of_handled_maps = 0;
+  __ LoadP(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
+  for (int current = 0; current < receiver_count; ++current) {
+    Handle<HeapType> type = types->at(current);
+    Handle<Map> map = IC::TypeToMap(*type, isolate());
+    if (!map->is_deprecated()) {
+      number_of_handled_maps++;
+      __ mov(ip, Operand(map));
+      __ cmp(map_reg, ip);
+      if (type->Is(HeapType::Number())) {
+        DCHECK(!number_case.is_unused());
+        __ bind(&number_case);
+      }
+      __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq);
+    }
+  }
+  DCHECK(number_of_handled_maps != 0);
+
+  __ bind(&miss);
+  TailCallBuiltin(masm(), MissBuiltin(kind()));
+
+  // Return the generated code.
+  InlineCacheState state =
+      number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
+  return GetCode(kind(), type, name, state);
+}
+
+
+Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
+    MapHandleList* receiver_maps, CodeHandleList* handler_stubs,
+    MapHandleList* transitioned_maps) {
+  Label miss;
+  __ JumpIfSmi(receiver(), &miss);
+
+  int receiver_count = receiver_maps->length();
+  __ LoadP(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset));
+  for (int i = 0; i < receiver_count; ++i) {
+    __ mov(ip, Operand(receiver_maps->at(i)));
+    __ cmp(scratch1(), ip);
+    if (transitioned_maps->at(i).is_null()) {
+      __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq);
+    } else {
+      Label next_map;
+      __ bne(&next_map);
+      __ mov(transition_map(), Operand(transitioned_maps->at(i)));
+      __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, al);
+      __ bind(&next_map);
+    }
+  }
+
+  __ bind(&miss);
+  TailCallBuiltin(masm(), MissBuiltin(kind()));
+
+  // Return the generated code.
+  return GetCode(kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
+}
+
+
+#undef __
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ic/ppc/ic-ppc.cc b/src/ic/ppc/ic-ppc.cc
new file mode 100644
index 0000000..97c3e2f
--- /dev/null
+++ b/src/ic/ppc/ic-ppc.cc
@@ -0,0 +1,1047 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/codegen.h"
+#include "src/ic/ic.h"
+#include "src/ic/ic-compiler.h"
+#include "src/ic/stub-cache.h"
+
+namespace v8 {
+namespace internal {
+
+
+// ----------------------------------------------------------------------------
+// Static IC stub generators.
+//
+
+#define __ ACCESS_MASM(masm)
+
+
+static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, Register type,
+                                            Label* global_object) {
+  // Register usage:
+  //   type: holds the receiver instance type on entry.
+  __ cmpi(type, Operand(JS_GLOBAL_OBJECT_TYPE));
+  __ beq(global_object);
+  __ cmpi(type, Operand(JS_BUILTINS_OBJECT_TYPE));
+  __ beq(global_object);
+  __ cmpi(type, Operand(JS_GLOBAL_PROXY_TYPE));
+  __ beq(global_object);
+}
+
+
+// Helper function used from LoadIC GenerateNormal.
+//
+// elements: Property dictionary. It is not clobbered if a jump to the miss
+//           label is done.
+// name:     Property name. It is not clobbered if a jump to the miss label is
+//           done
+// result:   Register for the result. It is only updated if a jump to the miss
+//           label is not done. Can be the same as elements or name clobbering
+//           one of these in the case of not jumping to the miss label.
+// The two scratch registers need to be different from elements, name and
+// result.
+// The generated code assumes that the receiver has slow properties,
+// is not a global object and does not have interceptors.
+static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
+                                   Register elements, Register name,
+                                   Register result, Register scratch1,
+                                   Register scratch2) {
+  // Main use of the scratch registers.
+  // scratch1: Used as temporary and to hold the capacity of the property
+  //           dictionary.
+  // scratch2: Used as temporary.
+  Label done;
+
+  // Probe the dictionary.
+  NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
+                                                   name, scratch1, scratch2);
+
+  // If probing finds an entry check that the value is a normal
+  // property.
+  __ bind(&done);  // scratch2 == elements + 4 * index
+  const int kElementsStartOffset =
+      NameDictionary::kHeaderSize +
+      NameDictionary::kElementsStartIndex * kPointerSize;
+  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
+  __ LoadP(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
+  __ mr(r0, scratch2);
+  __ LoadSmiLiteral(scratch2, Smi::FromInt(PropertyDetails::TypeField::kMask));
+  __ and_(scratch2, scratch1, scratch2, SetRC);
+  __ bne(miss, cr0);
+  __ mr(scratch2, r0);
+
+  // Get the value at the masked, scaled index and return.
+  __ LoadP(result,
+           FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
+}
+
+
+// Helper function used from StoreIC::GenerateNormal.
+//
+// elements: Property dictionary. It is not clobbered if a jump to the miss
+//           label is done.
+// name:     Property name. It is not clobbered if a jump to the miss label is
+//           done
+// value:    The value to store.
+// The two scratch registers need to be different from elements, name and
+// result.
+// The generated code assumes that the receiver has slow properties,
+// is not a global object and does not have interceptors.
+static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
+                                    Register elements, Register name,
+                                    Register value, Register scratch1,
+                                    Register scratch2) {
+  // Main use of the scratch registers.
+  // scratch1: Used as temporary and to hold the capacity of the property
+  //           dictionary.
+  // scratch2: Used as temporary.
+  Label done;
+
+  // Probe the dictionary.
+  NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
+                                                   name, scratch1, scratch2);
+
+  // If probing finds an entry in the dictionary check that the value
+  // is a normal property that is not read only.
+  __ bind(&done);  // scratch2 == elements + 4 * index
+  const int kElementsStartOffset =
+      NameDictionary::kHeaderSize +
+      NameDictionary::kElementsStartIndex * kPointerSize;
+  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
+  int kTypeAndReadOnlyMask =
+      PropertyDetails::TypeField::kMask |
+      PropertyDetails::AttributesField::encode(READ_ONLY);
+  __ LoadP(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
+  __ mr(r0, scratch2);
+  __ LoadSmiLiteral(scratch2, Smi::FromInt(kTypeAndReadOnlyMask));
+  __ and_(scratch2, scratch1, scratch2, SetRC);
+  __ bne(miss, cr0);
+  __ mr(scratch2, r0);
+
+  // Store the value at the masked, scaled index and return.
+  const int kValueOffset = kElementsStartOffset + kPointerSize;
+  __ addi(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
+  __ StoreP(value, MemOperand(scratch2));
+
+  // Update the write barrier. Make sure not to clobber the value.
+  __ mr(scratch1, value);
+  __ RecordWrite(elements, scratch2, scratch1, kLRHasNotBeenSaved,
+                 kDontSaveFPRegs);
+}
+
+
+// Checks the receiver for special cases (value type, slow case bits).
+// Falls through for regular JS object.
+static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
+                                           Register receiver, Register map,
+                                           Register scratch,
+                                           int interceptor_bit, Label* slow) {
+  // Check that the object isn't a smi.
+  __ JumpIfSmi(receiver, slow);
+  // Get the map of the receiver.
+  __ LoadP(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  // Check bit field.
+  __ lbz(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
+  DCHECK(((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)) < 0x8000);
+  __ andi(r0, scratch,
+          Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
+  __ bne(slow, cr0);
+  // Check that the object is some kind of JS object EXCEPT JS Value type.
+  // In the case that the object is a value-wrapper object,
+  // we enter the runtime system to make sure that indexing into string
+  // objects work as intended.
+  DCHECK(JS_OBJECT_TYPE > JS_VALUE_TYPE);
+  __ lbz(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  __ cmpi(scratch, Operand(JS_OBJECT_TYPE));
+  __ blt(slow);
+}
+
+
+// Loads an indexed element from a fast case array.
+// If not_fast_array is NULL, doesn't perform the elements map check.
+static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver,
+                                  Register key, Register elements,
+                                  Register scratch1, Register scratch2,
+                                  Register result, Label* not_fast_array,
+                                  Label* out_of_range) {
+  // Register use:
+  //
+  // receiver - holds the receiver on entry.
+  //            Unchanged unless 'result' is the same register.
+  //
+  // key      - holds the smi key on entry.
+  //            Unchanged unless 'result' is the same register.
+  //
+  // elements - holds the elements of the receiver on exit.
+  //
+  // result   - holds the result on exit if the load succeeded.
+  //            Allowed to be the the same as 'receiver' or 'key'.
+  //            Unchanged on bailout so 'receiver' and 'key' can be safely
+  //            used by further computation.
+  //
+  // Scratch registers:
+  //
+  // scratch1 - used to hold elements map and elements length.
+  //            Holds the elements map if not_fast_array branch is taken.
+  //
+  // scratch2 - used to hold the loaded value.
+
+  __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  if (not_fast_array != NULL) {
+    // Check that the object is in fast mode and writable.
+    __ LoadP(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
+    __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
+    __ cmp(scratch1, ip);
+    __ bne(not_fast_array);
+  } else {
+    __ AssertFastElements(elements);
+  }
+  // Check that the key (index) is within bounds.
+  __ LoadP(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
+  __ cmpl(key, scratch1);
+  __ bge(out_of_range);
+  // Fast case: Do the load.
+  __ addi(scratch1, elements,
+          Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  // The key is a smi.
+  __ SmiToPtrArrayOffset(scratch2, key);
+  __ LoadPX(scratch2, MemOperand(scratch2, scratch1));
+  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+  __ cmp(scratch2, ip);
+  // In case the loaded value is the_hole we have to consult GetProperty
+  // to ensure the prototype chain is searched.
+  __ beq(out_of_range);
+  __ mr(result, scratch2);
+}
+
+
+// Checks whether a key is an array index string or a unique name.
+// Falls through if a key is a unique name.
+static void GenerateKeyNameCheck(MacroAssembler* masm, Register key,
+                                 Register map, Register hash,
+                                 Label* index_string, Label* not_unique) {
+  // The key is not a smi.
+  Label unique;
+  // Is it a name?
+  __ CompareObjectType(key, map, hash, LAST_UNIQUE_NAME_TYPE);
+  __ bgt(not_unique);
+  STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
+  __ beq(&unique);
+
+  // Is the string an array index, with cached numeric value?
+  __ lwz(hash, FieldMemOperand(key, Name::kHashFieldOffset));
+  __ mov(r8, Operand(Name::kContainsCachedArrayIndexMask));
+  __ and_(r0, hash, r8, SetRC);
+  __ beq(index_string, cr0);
+
+  // Is the string internalized? We know it's a string, so a single
+  // bit test is enough.
+  // map: key map
+  __ lbz(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  STATIC_ASSERT(kInternalizedTag == 0);
+  __ andi(r0, hash, Operand(kIsNotInternalizedMask));
+  __ bne(not_unique, cr0);
+
+  __ bind(&unique);
+}
+
+
+void LoadIC::GenerateNormal(MacroAssembler* masm) {
+  Register dictionary = r3;
+  DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
+  DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
+
+  Label slow;
+
+  __ LoadP(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
+                                       JSObject::kPropertiesOffset));
+  GenerateDictionaryLoad(masm, &slow, dictionary,
+                         LoadDescriptor::NameRegister(), r3, r6, r7);
+  __ Ret();
+
+  // Dictionary load failed, go slow (but don't miss).
+  __ bind(&slow);
+  GenerateRuntimeGetProperty(masm);
+}
+
+
+// A register that isn't one of the parameters to the load ic.
+static const Register LoadIC_TempRegister() { return r6; }
+
+
+void LoadIC::GenerateMiss(MacroAssembler* masm) {
+  // The return address is in lr.
+  Isolate* isolate = masm->isolate();
+
+  __ IncrementCounter(isolate->counters()->load_miss(), 1, r6, r7);
+
+  __ mr(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
+  __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
+
+  // Perform tail call to the entry.
+  ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
+  __ TailCallExternalReference(ref, 2, 1);
+}
+
+
+void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
+  // The return address is in lr.
+
+  __ mr(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
+  __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
+
+  __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
+}
+
+
+static MemOperand GenerateMappedArgumentsLookup(
+    MacroAssembler* masm, Register object, Register key, Register scratch1,
+    Register scratch2, Register scratch3, Label* unmapped_case,
+    Label* slow_case) {
+  Heap* heap = masm->isolate()->heap();
+
+  // Check that the receiver is a JSObject. Because of the map check
+  // later, we do not need to check for interceptors or whether it
+  // requires access checks.
+  __ JumpIfSmi(object, slow_case);
+  // Check that the object is some kind of JSObject.
+  __ CompareObjectType(object, scratch1, scratch2, FIRST_JS_RECEIVER_TYPE);
+  __ blt(slow_case);
+
+  // Check that the key is a positive smi.
+  __ mov(scratch1, Operand(0x80000001));
+  __ and_(r0, key, scratch1, SetRC);
+  __ bne(slow_case, cr0);
+
+  // Load the elements into scratch1 and check its map.
+  Handle<Map> arguments_map(heap->sloppy_arguments_elements_map());
+  __ LoadP(scratch1, FieldMemOperand(object, JSObject::kElementsOffset));
+  __ CheckMap(scratch1, scratch2, arguments_map, slow_case, DONT_DO_SMI_CHECK);
+
+  // Check if element is in the range of mapped arguments. If not, jump
+  // to the unmapped lookup with the parameter map in scratch1.
+  __ LoadP(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset));
+  __ SubSmiLiteral(scratch2, scratch2, Smi::FromInt(2), r0);
+  __ cmpl(key, scratch2);
+  __ bge(unmapped_case);
+
+  // Load element index and check whether it is the hole.
+  const int kOffset =
+      FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag;
+
+  __ SmiToPtrArrayOffset(scratch3, key);
+  __ addi(scratch3, scratch3, Operand(kOffset));
+
+  __ LoadPX(scratch2, MemOperand(scratch1, scratch3));
+  __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
+  __ cmp(scratch2, scratch3);
+  __ beq(unmapped_case);
+
+  // Load value from context and return it. We can reuse scratch1 because
+  // we do not jump to the unmapped lookup (which requires the parameter
+  // map in scratch1).
+  __ LoadP(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
+  __ SmiToPtrArrayOffset(scratch3, scratch2);
+  __ addi(scratch3, scratch3, Operand(Context::kHeaderSize - kHeapObjectTag));
+  return MemOperand(scratch1, scratch3);
+}
+
+
+static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
+                                                  Register key,
+                                                  Register parameter_map,
+                                                  Register scratch,
+                                                  Label* slow_case) {
+  // Element is in arguments backing store, which is referenced by the
+  // second element of the parameter_map. The parameter_map register
+  // must be loaded with the parameter map of the arguments object and is
+  // overwritten.
+  const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
+  Register backing_store = parameter_map;
+  __ LoadP(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
+  Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
+  __ CheckMap(backing_store, scratch, fixed_array_map, slow_case,
+              DONT_DO_SMI_CHECK);
+  __ LoadP(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
+  __ cmpl(key, scratch);
+  __ bge(slow_case);
+  __ SmiToPtrArrayOffset(scratch, key);
+  __ addi(scratch, scratch, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  return MemOperand(backing_store, scratch);
+}
+
+
+void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
+  Register receiver = StoreDescriptor::ReceiverRegister();
+  Register key = StoreDescriptor::NameRegister();
+  Register value = StoreDescriptor::ValueRegister();
+  DCHECK(receiver.is(r4));
+  DCHECK(key.is(r5));
+  DCHECK(value.is(r3));
+
+  Label slow, notin;
+  MemOperand mapped_location = GenerateMappedArgumentsLookup(
+      masm, receiver, key, r6, r7, r8, &notin, &slow);
+  Register mapped_base = mapped_location.ra();
+  Register mapped_offset = mapped_location.rb();
+  __ StorePX(value, mapped_location);
+  __ add(r9, mapped_base, mapped_offset);
+  __ mr(r11, value);
+  __ RecordWrite(mapped_base, r9, r11, kLRHasNotBeenSaved, kDontSaveFPRegs);
+  __ Ret();
+  __ bind(&notin);
+  // The unmapped lookup expects that the parameter map is in r6.
+  MemOperand unmapped_location =
+      GenerateUnmappedArgumentsLookup(masm, key, r6, r7, &slow);
+  Register unmapped_base = unmapped_location.ra();
+  Register unmapped_offset = unmapped_location.rb();
+  __ StorePX(value, unmapped_location);
+  __ add(r9, unmapped_base, unmapped_offset);
+  __ mr(r11, value);
+  __ RecordWrite(unmapped_base, r9, r11, kLRHasNotBeenSaved, kDontSaveFPRegs);
+  __ Ret();
+  __ bind(&slow);
+  GenerateMiss(masm);
+}
+
+
+void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
+  // The return address is in lr.
+  Isolate* isolate = masm->isolate();
+
+  __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r6, r7);
+
+  __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
+
+  // Perform tail call to the entry.
+  ExternalReference ref =
+      ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
+
+  __ TailCallExternalReference(ref, 2, 1);
+}
+
+
+void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
+  // The return address is in lr.
+
+  __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
+
+  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
+}
+
+
+void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
+  // The return address is in lr.
+  Label slow, check_name, index_smi, index_name, property_array_property;
+  Label probe_dictionary, check_number_dictionary;
+
+  Register key = LoadDescriptor::NameRegister();
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  DCHECK(key.is(r5));
+  DCHECK(receiver.is(r4));
+
+  Isolate* isolate = masm->isolate();
+
+  // Check that the key is a smi.
+  __ JumpIfNotSmi(key, &check_name);
+  __ bind(&index_smi);
+  // Now the key is known to be a smi. This place is also jumped to from below
+  // where a numeric string is converted to a smi.
+
+  GenerateKeyedLoadReceiverCheck(masm, receiver, r3, r6,
+                                 Map::kHasIndexedInterceptor, &slow);
+
+  // Check the receiver's map to see if it has fast elements.
+  __ CheckFastElements(r3, r6, &check_number_dictionary);
+
+  GenerateFastArrayLoad(masm, receiver, key, r3, r6, r7, r3, NULL, &slow);
+  __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r7, r6);
+  __ Ret();
+
+  __ bind(&check_number_dictionary);
+  __ LoadP(r7, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  __ LoadP(r6, FieldMemOperand(r7, JSObject::kMapOffset));
+
+  // Check whether the elements is a number dictionary.
+  // r6: elements map
+  // r7: elements
+  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
+  __ cmp(r6, ip);
+  __ bne(&slow);
+  __ SmiUntag(r3, key);
+  __ LoadFromNumberDictionary(&slow, r7, key, r3, r3, r6, r8);
+  __ Ret();
+
+  // Slow case, key and receiver still in r3 and r4.
+  __ bind(&slow);
+  __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), 1, r7,
+                      r6);
+  GenerateRuntimeGetProperty(masm);
+
+  __ bind(&check_name);
+  GenerateKeyNameCheck(masm, key, r3, r6, &index_name, &slow);
+
+  GenerateKeyedLoadReceiverCheck(masm, receiver, r3, r6,
+                                 Map::kHasNamedInterceptor, &slow);
+
+  // If the receiver is a fast-case object, check the keyed lookup
+  // cache. Otherwise probe the dictionary.
+  __ LoadP(r6, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+  __ LoadP(r7, FieldMemOperand(r6, HeapObject::kMapOffset));
+  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
+  __ cmp(r7, ip);
+  __ beq(&probe_dictionary);
+
+  // Load the map of the receiver, compute the keyed lookup cache hash
+  // based on 32 bits of the map pointer and the name hash.
+  __ LoadP(r3, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ srawi(r6, r3, KeyedLookupCache::kMapHashShift);
+  __ lwz(r7, FieldMemOperand(key, Name::kHashFieldOffset));
+  __ srawi(r7, r7, Name::kHashShift);
+  __ xor_(r6, r6, r7);
+  int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask;
+  __ mov(r7, Operand(mask));
+  __ and_(r6, r6, r7, LeaveRC);
+
+  // Load the key (consisting of map and unique name) from the cache and
+  // check for match.
+  Label load_in_object_property;
+  static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
+  Label hit_on_nth_entry[kEntriesPerBucket];
+  ExternalReference cache_keys =
+      ExternalReference::keyed_lookup_cache_keys(isolate);
+
+  __ mov(r7, Operand(cache_keys));
+  __ mr(r0, r5);
+  __ ShiftLeftImm(r5, r6, Operand(kPointerSizeLog2 + 1));
+  __ add(r7, r7, r5);
+  __ mr(r5, r0);
+
+  for (int i = 0; i < kEntriesPerBucket - 1; i++) {
+    Label try_next_entry;
+    // Load map and move r7 to next entry.
+    __ LoadP(r8, MemOperand(r7));
+    __ addi(r7, r7, Operand(kPointerSize * 2));
+    __ cmp(r3, r8);
+    __ bne(&try_next_entry);
+    __ LoadP(r8, MemOperand(r7, -kPointerSize));  // Load name
+    __ cmp(key, r8);
+    __ beq(&hit_on_nth_entry[i]);
+    __ bind(&try_next_entry);
+  }
+
+  // Last entry: Load map and move r7 to name.
+  __ LoadP(r8, MemOperand(r7));
+  __ addi(r7, r7, Operand(kPointerSize));
+  __ cmp(r3, r8);
+  __ bne(&slow);
+  __ LoadP(r8, MemOperand(r7));
+  __ cmp(key, r8);
+  __ bne(&slow);
+
+  // Get field offset.
+  // r3     : receiver's map
+  // r6     : lookup cache index
+  ExternalReference cache_field_offsets =
+      ExternalReference::keyed_lookup_cache_field_offsets(isolate);
+
+  // Hit on nth entry.
+  for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
+    __ bind(&hit_on_nth_entry[i]);
+    __ mov(r7, Operand(cache_field_offsets));
+    if (i != 0) {
+      __ addi(r6, r6, Operand(i));
+    }
+    __ ShiftLeftImm(r8, r6, Operand(2));
+    __ lwzx(r8, MemOperand(r8, r7));
+    __ lbz(r9, FieldMemOperand(r3, Map::kInObjectPropertiesOffset));
+    __ sub(r8, r8, r9);
+    __ cmpi(r8, Operand::Zero());
+    __ bge(&property_array_property);
+    if (i != 0) {
+      __ b(&load_in_object_property);
+    }
+  }
+
+  // Load in-object property.
+  __ bind(&load_in_object_property);
+  __ lbz(r9, FieldMemOperand(r3, Map::kInstanceSizeOffset));
+  __ add(r9, r9, r8);  // Index from start of object.
+  __ subi(receiver, receiver, Operand(kHeapObjectTag));  // Remove the heap tag.
+  __ ShiftLeftImm(r3, r9, Operand(kPointerSizeLog2));
+  __ LoadPX(r3, MemOperand(r3, receiver));
+  __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), 1,
+                      r7, r6);
+  __ Ret();
+
+  // Load property array property.
+  __ bind(&property_array_property);
+  __ LoadP(receiver, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+  __ addi(receiver, receiver,
+          Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ ShiftLeftImm(r3, r8, Operand(kPointerSizeLog2));
+  __ LoadPX(r3, MemOperand(r3, receiver));
+  __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), 1,
+                      r7, r6);
+  __ Ret();
+
+  // Do a quick inline probe of the receiver's dictionary, if it
+  // exists.
+  __ bind(&probe_dictionary);
+  // r6: elements
+  __ LoadP(r3, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ lbz(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset));
+  GenerateGlobalInstanceTypeCheck(masm, r3, &slow);
+  // Load the property to r3.
+  GenerateDictionaryLoad(masm, &slow, r6, key, r3, r8, r7);
+  __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(), 1, r7,
+                      r6);
+  __ Ret();
+
+  __ bind(&index_name);
+  __ IndexFromHash(r6, key);
+  // Now jump to the place where smi keys are handled.
+  __ b(&index_smi);
+}
+
+
+void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
+  // Push receiver, key and value for runtime call.
+  __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
+          StoreDescriptor::ValueRegister());
+
+  ExternalReference ref =
+      ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
+  __ TailCallExternalReference(ref, 3, 1);
+}
+
+
+static void KeyedStoreGenerateMegamorphicHelper(
+    MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
+    KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
+    Register value, Register key, Register receiver, Register receiver_map,
+    Register elements_map, Register elements) {
+  Label transition_smi_elements;
+  Label finish_object_store, non_double_value, transition_double_elements;
+  Label fast_double_without_map_check;
+
+  // Fast case: Do the store, could be either Object or double.
+  __ bind(fast_object);
+  Register scratch_value = r7;
+  Register address = r8;
+  if (check_map == kCheckMap) {
+    __ LoadP(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
+    __ mov(scratch_value,
+           Operand(masm->isolate()->factory()->fixed_array_map()));
+    __ cmp(elements_map, scratch_value);
+    __ bne(fast_double);
+  }
+
+  // HOLECHECK: guards "A[i] = V"
+  // We have to go to the runtime if the current value is the hole because
+  // there may be a callback on the element
+  Label holecheck_passed1;
+  __ addi(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ SmiToPtrArrayOffset(scratch_value, key);
+  __ LoadPX(scratch_value, MemOperand(address, scratch_value));
+  __ Cmpi(scratch_value, Operand(masm->isolate()->factory()->the_hole_value()),
+          r0);
+  __ bne(&holecheck_passed1);
+  __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
+                                      slow);
+
+  __ bind(&holecheck_passed1);
+
+  // Smi stores don't require further checks.
+  Label non_smi_value;
+  __ JumpIfNotSmi(value, &non_smi_value);
+
+  if (increment_length == kIncrementLength) {
+    // Add 1 to receiver->length.
+    __ AddSmiLiteral(scratch_value, key, Smi::FromInt(1), r0);
+    __ StoreP(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset),
+              r0);
+  }
+  // It's irrelevant whether array is smi-only or not when writing a smi.
+  __ addi(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ SmiToPtrArrayOffset(scratch_value, key);
+  __ StorePX(value, MemOperand(address, scratch_value));
+  __ Ret();
+
+  __ bind(&non_smi_value);
+  // Escape to elements kind transition case.
+  __ CheckFastObjectElements(receiver_map, scratch_value,
+                             &transition_smi_elements);
+
+  // Fast elements array, store the value to the elements backing store.
+  __ bind(&finish_object_store);
+  if (increment_length == kIncrementLength) {
+    // Add 1 to receiver->length.
+    __ AddSmiLiteral(scratch_value, key, Smi::FromInt(1), r0);
+    __ StoreP(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset),
+              r0);
+  }
+  __ addi(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ SmiToPtrArrayOffset(scratch_value, key);
+  __ StorePUX(value, MemOperand(address, scratch_value));
+  // Update write barrier for the elements array address.
+  __ mr(scratch_value, value);  // Preserve the value which is returned.
+  __ RecordWrite(elements, address, scratch_value, kLRHasNotBeenSaved,
+                 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+  __ Ret();
+
+  __ bind(fast_double);
+  if (check_map == kCheckMap) {
+    // Check for fast double array case. If this fails, call through to the
+    // runtime.
+    __ CompareRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex);
+    __ bne(slow);
+  }
+
+  // HOLECHECK: guards "A[i] double hole?"
+  // We have to see if the double version of the hole is present. If so
+  // go to the runtime.
+  __ addi(address, elements,
+          Operand((FixedDoubleArray::kHeaderSize + Register::kExponentOffset -
+                   kHeapObjectTag)));
+  __ SmiToDoubleArrayOffset(scratch_value, key);
+  __ lwzx(scratch_value, MemOperand(address, scratch_value));
+  __ Cmpi(scratch_value, Operand(kHoleNanUpper32), r0);
+  __ bne(&fast_double_without_map_check);
+  __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
+                                      slow);
+
+  __ bind(&fast_double_without_map_check);
+  __ StoreNumberToDoubleElements(value, key, elements, r6, d0,
+                                 &transition_double_elements);
+  if (increment_length == kIncrementLength) {
+    // Add 1 to receiver->length.
+    __ AddSmiLiteral(scratch_value, key, Smi::FromInt(1), r0);
+    __ StoreP(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset),
+              r0);
+  }
+  __ Ret();
+
+  __ bind(&transition_smi_elements);
+  // Transition the array appropriately depending on the value type.
+  __ LoadP(r7, FieldMemOperand(value, HeapObject::kMapOffset));
+  __ CompareRoot(r7, Heap::kHeapNumberMapRootIndex);
+  __ bne(&non_double_value);
+
+  // Value is a double. Transition FAST_SMI_ELEMENTS ->
+  // FAST_DOUBLE_ELEMENTS and complete the store.
+  __ LoadTransitionedArrayMapConditional(
+      FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, r7, slow);
+  AllocationSiteMode mode =
+      AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS);
+  ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value,
+                                                   receiver_map, mode, slow);
+  __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  __ b(&fast_double_without_map_check);
+
+  __ bind(&non_double_value);
+  // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
+  __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS,
+                                         receiver_map, r7, slow);
+  mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
+  ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
+      masm, receiver, key, value, receiver_map, mode, slow);
+  __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  __ b(&finish_object_store);
+
+  __ bind(&transition_double_elements);
+  // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
+  // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
+  // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
+  __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS,
+                                         receiver_map, r7, slow);
+  mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
+  ElementsTransitionGenerator::GenerateDoubleToObject(
+      masm, receiver, key, value, receiver_map, mode, slow);
+  __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  __ b(&finish_object_store);
+}
+
+
+void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
+                                       StrictMode strict_mode) {
+  // ---------- S t a t e --------------
+  //  -- r3     : value
+  //  -- r4     : key
+  //  -- r5     : receiver
+  //  -- lr     : return address
+  // -----------------------------------
+  Label slow, fast_object, fast_object_grow;
+  Label fast_double, fast_double_grow;
+  Label array, extra, check_if_double_array, maybe_name_key, miss;
+
+  // Register usage.
+  Register value = StoreDescriptor::ValueRegister();
+  Register key = StoreDescriptor::NameRegister();
+  Register receiver = StoreDescriptor::ReceiverRegister();
+  DCHECK(receiver.is(r4));
+  DCHECK(key.is(r5));
+  DCHECK(value.is(r3));
+  Register receiver_map = r6;
+  Register elements_map = r9;
+  Register elements = r10;  // Elements array of the receiver.
+  // r7 and r8 are used as general scratch registers.
+
+  // Check that the key is a smi.
+  __ JumpIfNotSmi(key, &maybe_name_key);
+  // Check that the object isn't a smi.
+  __ JumpIfSmi(receiver, &slow);
+  // Get the map of the object.
+  __ LoadP(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  // Check that the receiver does not require access checks and is not observed.
+  // The generic stub does not perform map checks or handle observed objects.
+  __ lbz(ip, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
+  __ andi(r0, ip,
+          Operand(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
+  __ bne(&slow, cr0);
+  // Check if the object is a JS array or not.
+  __ lbz(r7, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
+  __ cmpi(r7, Operand(JS_ARRAY_TYPE));
+  __ beq(&array);
+  // Check that the object is some kind of JSObject.
+  __ cmpi(r7, Operand(FIRST_JS_OBJECT_TYPE));
+  __ blt(&slow);
+
+  // Object case: Check key against length in the elements array.
+  __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  // Check array bounds. Both the key and the length of FixedArray are smis.
+  __ LoadP(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
+  __ cmpl(key, ip);
+  __ blt(&fast_object);
+
+  // Slow case, handle jump to runtime.
+  __ bind(&slow);
+  // Entry registers are intact.
+  // r3: value.
+  // r4: key.
+  // r5: receiver.
+  PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode);
+  // Never returns to here.
+
+  __ bind(&maybe_name_key);
+  __ LoadP(r7, FieldMemOperand(key, HeapObject::kMapOffset));
+  __ lbz(r7, FieldMemOperand(r7, Map::kInstanceTypeOffset));
+  __ JumpIfNotUniqueNameInstanceType(r7, &slow);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::STORE_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver,
+                                               key, r6, r7, r8, r9);
+  // Cache miss.
+  __ b(&miss);
+
+  // Extra capacity case: Check if there is extra capacity to
+  // perform the store and update the length. Used for adding one
+  // element to the array by writing to array[array.length].
+  __ bind(&extra);
+  // Condition code from comparing key and array length is still available.
+  __ bne(&slow);  // Only support writing to writing to array[array.length].
+  // Check for room in the elements backing store.
+  // Both the key and the length of FixedArray are smis.
+  __ LoadP(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
+  __ cmpl(key, ip);
+  __ bge(&slow);
+  __ LoadP(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
+  __ mov(ip, Operand(masm->isolate()->factory()->fixed_array_map()));
+  __ cmp(elements_map, ip);  // PPC - I think I can re-use ip here
+  __ bne(&check_if_double_array);
+  __ b(&fast_object_grow);
+
+  __ bind(&check_if_double_array);
+  __ mov(ip, Operand(masm->isolate()->factory()->fixed_double_array_map()));
+  __ cmp(elements_map, ip);  // PPC - another ip re-use
+  __ bne(&slow);
+  __ b(&fast_double_grow);
+
+  // Array case: Get the length and the elements array from the JS
+  // array. Check that the array is in fast mode (and writable); if it
+  // is the length is always a smi.
+  __ bind(&array);
+  __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+
+  // Check the key against the length in the array.
+  __ LoadP(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
+  __ cmpl(key, ip);
+  __ bge(&extra);
+
+  KeyedStoreGenerateMegamorphicHelper(
+      masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength,
+      value, key, receiver, receiver_map, elements_map, elements);
+  KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
+                                      &fast_double_grow, &slow, kDontCheckMap,
+                                      kIncrementLength, value, key, receiver,
+                                      receiver_map, elements_map, elements);
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
+  Register receiver = StoreDescriptor::ReceiverRegister();
+  Register name = StoreDescriptor::NameRegister();
+  DCHECK(receiver.is(r4));
+  DCHECK(name.is(r5));
+  DCHECK(StoreDescriptor::ValueRegister().is(r3));
+
+  // Get the receiver from the stack and probe the stub cache.
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::STORE_IC));
+
+  masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver,
+                                               name, r6, r7, r8, r9);
+
+  // Cache miss: Jump to runtime.
+  GenerateMiss(masm);
+}
+
+
+void StoreIC::GenerateMiss(MacroAssembler* masm) {
+  __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
+          StoreDescriptor::ValueRegister());
+
+  // Perform tail call to the entry.
+  ExternalReference ref =
+      ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
+  __ TailCallExternalReference(ref, 3, 1);
+}
+
+
+void StoreIC::GenerateNormal(MacroAssembler* masm) {
+  Label miss;
+  Register receiver = StoreDescriptor::ReceiverRegister();
+  Register name = StoreDescriptor::NameRegister();
+  Register value = StoreDescriptor::ValueRegister();
+  Register dictionary = r6;
+  DCHECK(receiver.is(r4));
+  DCHECK(name.is(r5));
+  DCHECK(value.is(r3));
+
+  __ LoadP(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+
+  GenerateDictionaryStore(masm, &miss, dictionary, name, value, r7, r8);
+  Counters* counters = masm->isolate()->counters();
+  __ IncrementCounter(counters->store_normal_hit(), 1, r7, r8);
+  __ Ret();
+
+  __ bind(&miss);
+  __ IncrementCounter(counters->store_normal_miss(), 1, r7, r8);
+  GenerateMiss(masm);
+}
+
+
+#undef __
+
+
+Condition CompareIC::ComputeCondition(Token::Value op) {
+  switch (op) {
+    case Token::EQ_STRICT:
+    case Token::EQ:
+      return eq;
+    case Token::LT:
+      return lt;
+    case Token::GT:
+      return gt;
+    case Token::LTE:
+      return le;
+    case Token::GTE:
+      return ge;
+    default:
+      UNREACHABLE();
+      return kNoCondition;
+  }
+}
+
+
+bool CompareIC::HasInlinedSmiCode(Address address) {
+  // The address of the instruction following the call.
+  Address cmp_instruction_address =
+      Assembler::return_address_from_call_start(address);
+
+  // If the instruction following the call is not a cmp rx, #yyy, nothing
+  // was inlined.
+  Instr instr = Assembler::instr_at(cmp_instruction_address);
+  return Assembler::IsCmpImmediate(instr);
+}
+
+
+//
+// This code is paired with the JumpPatchSite class in full-codegen-ppc.cc
+//
+void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
+  Address cmp_instruction_address =
+      Assembler::return_address_from_call_start(address);
+
+  // If the instruction following the call is not a cmp rx, #yyy, nothing
+  // was inlined.
+  Instr instr = Assembler::instr_at(cmp_instruction_address);
+  if (!Assembler::IsCmpImmediate(instr)) {
+    return;
+  }
+
+  // The delta to the start of the map check instruction and the
+  // condition code uses at the patched jump.
+  int delta = Assembler::GetCmpImmediateRawImmediate(instr);
+  delta += Assembler::GetCmpImmediateRegister(instr).code() * kOff16Mask;
+  // If the delta is 0 the instruction is cmp r0, #0 which also signals that
+  // nothing was inlined.
+  if (delta == 0) {
+    return;
+  }
+
+  if (FLAG_trace_ic) {
+    PrintF("[  patching ic at %p, cmp=%p, delta=%d\n", address,
+           cmp_instruction_address, delta);
+  }
+
+  Address patch_address =
+      cmp_instruction_address - delta * Instruction::kInstrSize;
+  Instr instr_at_patch = Assembler::instr_at(patch_address);
+  Instr branch_instr =
+      Assembler::instr_at(patch_address + Instruction::kInstrSize);
+  // This is patching a conditional "jump if not smi/jump if smi" site.
+  // Enabling by changing from
+  //   cmp cr0, rx, rx
+  // to
+  //  rlwinm(r0, value, 0, 31, 31, SetRC);
+  //  bc(label, BT/BF, 2)
+  // and vice-versa to be disabled again.
+  CodePatcher patcher(patch_address, 2);
+  Register reg = Assembler::GetRA(instr_at_patch);
+  if (check == ENABLE_INLINED_SMI_CHECK) {
+    DCHECK(Assembler::IsCmpRegister(instr_at_patch));
+    DCHECK_EQ(Assembler::GetRA(instr_at_patch).code(),
+              Assembler::GetRB(instr_at_patch).code());
+    patcher.masm()->TestIfSmi(reg, r0);
+  } else {
+    DCHECK(check == DISABLE_INLINED_SMI_CHECK);
+#if V8_TARGET_ARCH_PPC64
+    DCHECK(Assembler::IsRldicl(instr_at_patch));
+#else
+    DCHECK(Assembler::IsRlwinm(instr_at_patch));
+#endif
+    patcher.masm()->cmp(reg, reg, cr0);
+  }
+  DCHECK(Assembler::IsBranch(branch_instr));
+
+  // Invert the logic of the branch
+  if (Assembler::GetCondition(branch_instr) == eq) {
+    patcher.EmitCondition(ne);
+  } else {
+    DCHECK(Assembler::GetCondition(branch_instr) == ne);
+    patcher.EmitCondition(eq);
+  }
+}
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ic/ppc/stub-cache-ppc.cc b/src/ic/ppc/stub-cache-ppc.cc
new file mode 100644
index 0000000..816a2ae
--- /dev/null
+++ b/src/ic/ppc/stub-cache-ppc.cc
@@ -0,0 +1,191 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/codegen.h"
+#include "src/ic/stub-cache.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm)
+
+
+static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
+                       Code::Flags flags, bool leave_frame,
+                       StubCache::Table table, Register receiver, Register name,
+                       // Number of the cache entry, not scaled.
+                       Register offset, Register scratch, Register scratch2,
+                       Register offset_scratch) {
+  ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
+  ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
+  ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
+
+  uintptr_t key_off_addr = reinterpret_cast<uintptr_t>(key_offset.address());
+  uintptr_t value_off_addr =
+      reinterpret_cast<uintptr_t>(value_offset.address());
+  uintptr_t map_off_addr = reinterpret_cast<uintptr_t>(map_offset.address());
+
+  // Check the relative positions of the address fields.
+  DCHECK(value_off_addr > key_off_addr);
+  DCHECK((value_off_addr - key_off_addr) % 4 == 0);
+  DCHECK((value_off_addr - key_off_addr) < (256 * 4));
+  DCHECK(map_off_addr > key_off_addr);
+  DCHECK((map_off_addr - key_off_addr) % 4 == 0);
+  DCHECK((map_off_addr - key_off_addr) < (256 * 4));
+
+  Label miss;
+  Register base_addr = scratch;
+  scratch = no_reg;
+
+  // Multiply by 3 because there are 3 fields per entry (name, code, map).
+  __ ShiftLeftImm(offset_scratch, offset, Operand(1));
+  __ add(offset_scratch, offset, offset_scratch);
+
+  // Calculate the base address of the entry.
+  __ mov(base_addr, Operand(key_offset));
+  __ ShiftLeftImm(scratch2, offset_scratch, Operand(kPointerSizeLog2));
+  __ add(base_addr, base_addr, scratch2);
+
+  // Check that the key in the entry matches the name.
+  __ LoadP(ip, MemOperand(base_addr, 0));
+  __ cmp(name, ip);
+  __ bne(&miss);
+
+  // Check the map matches.
+  __ LoadP(ip, MemOperand(base_addr, map_off_addr - key_off_addr));
+  __ LoadP(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ cmp(ip, scratch2);
+  __ bne(&miss);
+
+  // Get the code entry from the cache.
+  Register code = scratch2;
+  scratch2 = no_reg;
+  __ LoadP(code, MemOperand(base_addr, value_off_addr - key_off_addr));
+
+  // Check that the flags match what we're looking for.
+  Register flags_reg = base_addr;
+  base_addr = no_reg;
+  __ lwz(flags_reg, FieldMemOperand(code, Code::kFlagsOffset));
+
+  DCHECK(!r0.is(flags_reg));
+  __ li(r0, Operand(Code::kFlagsNotUsedInLookup));
+  __ andc(flags_reg, flags_reg, r0);
+  __ mov(r0, Operand(flags));
+  __ cmpl(flags_reg, r0);
+  __ bne(&miss);
+
+#ifdef DEBUG
+  if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
+    __ b(&miss);
+  } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
+    __ b(&miss);
+  }
+#endif
+
+  if (leave_frame) __ LeaveFrame(StackFrame::INTERNAL);
+
+  // Jump to the first instruction in the code stub.
+  __ addi(r0, code, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ mtctr(r0);
+  __ bctr();
+
+  // Miss: fall through.
+  __ bind(&miss);
+}
+
+
+void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
+                              bool leave_frame, Register receiver,
+                              Register name, Register scratch, Register extra,
+                              Register extra2, Register extra3) {
+  Isolate* isolate = masm->isolate();
+  Label miss;
+
+#if V8_TARGET_ARCH_PPC64
+  // Make sure that code is valid. The multiplying code relies on the
+  // entry size being 24.
+  DCHECK(sizeof(Entry) == 24);
+#else
+  // Make sure that code is valid. The multiplying code relies on the
+  // entry size being 12.
+  DCHECK(sizeof(Entry) == 12);
+#endif
+
+  // Make sure the flags does not name a specific type.
+  DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
+
+  // Make sure that there are no register conflicts.
+  DCHECK(!scratch.is(receiver));
+  DCHECK(!scratch.is(name));
+  DCHECK(!extra.is(receiver));
+  DCHECK(!extra.is(name));
+  DCHECK(!extra.is(scratch));
+  DCHECK(!extra2.is(receiver));
+  DCHECK(!extra2.is(name));
+  DCHECK(!extra2.is(scratch));
+  DCHECK(!extra2.is(extra));
+
+  // Check scratch, extra and extra2 registers are valid.
+  DCHECK(!scratch.is(no_reg));
+  DCHECK(!extra.is(no_reg));
+  DCHECK(!extra2.is(no_reg));
+  DCHECK(!extra3.is(no_reg));
+
+  Counters* counters = masm->isolate()->counters();
+  __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2,
+                      extra3);
+
+  // Check that the receiver isn't a smi.
+  __ JumpIfSmi(receiver, &miss);
+
+  // Get the map of the receiver and compute the hash.
+  __ lwz(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
+  __ LoadP(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ add(scratch, scratch, ip);
+#if V8_TARGET_ARCH_PPC64
+  // Use only the low 32 bits of the map pointer.
+  __ rldicl(scratch, scratch, 0, 32);
+#endif
+  uint32_t mask = kPrimaryTableSize - 1;
+  // We shift out the last two bits because they are not part of the hash and
+  // they are always 01 for maps.
+  __ ShiftRightImm(scratch, scratch, Operand(kCacheIndexShift));
+  // Mask down the eor argument to the minimum to keep the immediate
+  // encodable.
+  __ xori(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask));
+  // Prefer and_ to ubfx here because ubfx takes 2 cycles.
+  __ andi(scratch, scratch, Operand(mask));
+
+  // Probe the primary table.
+  ProbeTable(isolate, masm, flags, leave_frame, kPrimary, receiver, name,
+             scratch, extra, extra2, extra3);
+
+  // Primary miss: Compute hash for secondary probe.
+  __ ShiftRightImm(extra, name, Operand(kCacheIndexShift));
+  __ sub(scratch, scratch, extra);
+  uint32_t mask2 = kSecondaryTableSize - 1;
+  __ addi(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask2));
+  __ andi(scratch, scratch, Operand(mask2));
+
+  // Probe the secondary table.
+  ProbeTable(isolate, masm, flags, leave_frame, kSecondary, receiver, name,
+             scratch, extra, extra2, extra3);
+
+  // Cache miss: Fall-through and let caller handle the miss by
+  // entering the runtime system.
+  __ bind(&miss);
+  __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, extra2,
+                      extra3);
+}
+
+
+#undef __
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ic/stub-cache.h b/src/ic/stub-cache.h
index 7aee6f1..4223b28 100644
--- a/src/ic/stub-cache.h
+++ b/src/ic/stub-cache.h
@@ -52,10 +52,10 @@
   // Arguments extra, extra2 and extra3 may be used to pass additional scratch
   // registers. Set to no_reg if not needed.
   // If leave_frame is true, then exit a frame before the tail call.
-  void GenerateProbe(MacroAssembler* masm, Code::Flags flags, bool leave_frame,
-                     Register receiver, Register name, Register scratch,
-                     Register extra, Register extra2 = no_reg,
-                     Register extra3 = no_reg);
+  void GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
+                     Code::Flags flags, bool leave_frame, Register receiver,
+                     Register name, Register scratch, Register extra,
+                     Register extra2 = no_reg, Register extra3 = no_reg);
 
   enum Table { kPrimary, kSecondary };
 
diff --git a/src/ic/x64/handler-compiler-x64.cc b/src/ic/x64/handler-compiler-x64.cc
index c4d6ecf..46fa8cc 100644
--- a/src/ic/x64/handler-compiler-x64.cc
+++ b/src/ic/x64/handler-compiler-x64.cc
@@ -15,6 +15,28 @@
 
 #define __ ACCESS_MASM(masm)
 
+void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
+                                                Register slot) {
+  MacroAssembler* masm = this->masm();
+  __ Push(vector);
+  __ Push(slot);
+}
+
+
+void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
+  MacroAssembler* masm = this->masm();
+  __ Pop(slot);
+  __ Pop(vector);
+}
+
+
+void PropertyHandlerCompiler::DiscardVectorAndSlot() {
+  MacroAssembler* masm = this->masm();
+  // Remove vector and slot.
+  __ addp(rsp, Immediate(2 * kPointerSize));
+}
+
+
 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
     MacroAssembler* masm, Label* miss_label, Register receiver,
     Handle<Name> name, Register scratch0, Register scratch1) {
@@ -56,24 +78,16 @@
 
 
 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
-    MacroAssembler* masm, int index, Register prototype, Label* miss) {
-  Isolate* isolate = masm->isolate();
-  // Get the global function with the given index.
-  Handle<JSFunction> function(
-      JSFunction::cast(isolate->native_context()->get(index)));
-
-  // Check we're still in the same context.
-  Register scratch = prototype;
+    MacroAssembler* masm, int index, Register result, Label* miss) {
   const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX);
-  __ movp(scratch, Operand(rsi, offset));
-  __ movp(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset));
-  __ Cmp(Operand(scratch, Context::SlotOffset(index)), function);
-  __ j(not_equal, miss);
-
+  __ movp(result, Operand(rsi, offset));
+  __ movp(result, FieldOperand(result, GlobalObject::kNativeContextOffset));
+  __ movp(result, Operand(result, Context::SlotOffset(index)));
   // Load its initial map. The global functions all have initial maps.
-  __ Move(prototype, Handle<Map>(function->initial_map()));
+  __ movp(result,
+          FieldOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
   // Load the prototype from the initial map.
-  __ movp(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
+  __ movp(result, FieldOperand(result, Map::kPrototypeOffset));
 }
 
 
@@ -324,169 +338,60 @@
 }
 
 
-// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
-// store is successful.
-void NamedStoreHandlerCompiler::GenerateStoreTransition(
-    Handle<Map> transition, Handle<Name> name, Register receiver_reg,
-    Register storage_reg, Register value_reg, Register scratch1,
-    Register scratch2, Register unused, Label* miss_label, Label* slow) {
-  int descriptor = transition->LastAdded();
-  DescriptorArray* descriptors = transition->instance_descriptors();
-  PropertyDetails details = descriptors->GetDetails(descriptor);
-  Representation representation = details.representation();
-  DCHECK(!representation.IsNone());
-
-  if (details.type() == CONSTANT) {
-    Handle<Object> constant(descriptors->GetValue(descriptor), isolate());
-    __ Cmp(value_reg, constant);
-    __ j(not_equal, miss_label);
-  } else if (representation.IsSmi()) {
-    __ JumpIfNotSmi(value_reg, miss_label);
-  } else if (representation.IsHeapObject()) {
-    __ JumpIfSmi(value_reg, miss_label);
-    HeapType* field_type = descriptors->GetFieldType(descriptor);
-    HeapType::Iterator<Map> it = field_type->Classes();
-    if (!it.Done()) {
-      Label do_store;
-      while (true) {
-        __ CompareMap(value_reg, it.Current());
-        it.Advance();
-        if (it.Done()) {
-          __ j(not_equal, miss_label);
-          break;
-        }
-        __ j(equal, &do_store, Label::kNear);
-      }
-      __ bind(&do_store);
-    }
-  } else if (representation.IsDouble()) {
-    Label do_store, heap_number;
-    __ AllocateHeapNumber(storage_reg, scratch1, slow, MUTABLE);
-
-    __ JumpIfNotSmi(value_reg, &heap_number);
-    __ SmiToInteger32(scratch1, value_reg);
-    __ Cvtlsi2sd(xmm0, scratch1);
-    __ jmp(&do_store);
-
-    __ bind(&heap_number);
-    __ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label,
-                DONT_DO_SMI_CHECK);
-    __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
-
-    __ bind(&do_store);
-    __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0);
-  }
-
-  // Stub never generated for objects that require access checks.
-  DCHECK(!transition->is_access_check_needed());
-
-  // Perform map transition for the receiver if necessary.
-  if (details.type() == FIELD &&
-      Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) {
-    // The properties must be extended before we can store the value.
-    // We jump to a runtime call that extends the properties array.
-    __ PopReturnAddressTo(scratch1);
-    __ Push(receiver_reg);
-    __ Push(transition);
-    __ Push(value_reg);
-    __ PushReturnAddressFrom(scratch1);
-    __ TailCallExternalReference(
-        ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
-                          isolate()),
-        3, 1);
-    return;
-  }
-
-  // Update the map of the object.
-  __ Move(scratch1, transition);
-  __ movp(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
-
-  // Update the write barrier for the map field.
-  __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2,
-                      kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
-
-  if (details.type() == CONSTANT) {
-    DCHECK(value_reg.is(rax));
-    __ ret(0);
-    return;
-  }
-
-  int index = transition->instance_descriptors()->GetFieldIndex(
-      transition->LastAdded());
-
-  // Adjust for the number of properties stored in the object. Even in the
-  // face of a transition we can use the old map here because the size of the
-  // object and the number of in-object properties is not going to change.
-  index -= transition->inobject_properties();
-
-  // TODO(verwaest): Share this code as a code stub.
-  SmiCheck smi_check =
-      representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
-  if (index < 0) {
-    // Set the property straight into the object.
-    int offset = transition->instance_size() + (index * kPointerSize);
-    if (representation.IsDouble()) {
-      __ movp(FieldOperand(receiver_reg, offset), storage_reg);
-    } else {
-      __ movp(FieldOperand(receiver_reg, offset), value_reg);
-    }
-
-    if (!representation.IsSmi()) {
-      // Update the write barrier for the array address.
-      if (!representation.IsDouble()) {
-        __ movp(storage_reg, value_reg);
-      }
-      __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1,
-                          kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check);
-    }
-  } else {
-    // Write to the properties array.
-    int offset = index * kPointerSize + FixedArray::kHeaderSize;
-    // Get the properties array (optimistically).
-    __ movp(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
-    if (representation.IsDouble()) {
-      __ movp(FieldOperand(scratch1, offset), storage_reg);
-    } else {
-      __ movp(FieldOperand(scratch1, offset), value_reg);
-    }
-
-    if (!representation.IsSmi()) {
-      // Update the write barrier for the array address.
-      if (!representation.IsDouble()) {
-        __ movp(storage_reg, value_reg);
-      }
-      __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg,
-                          kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check);
-    }
-  }
-
-  // Return the value (register rax).
-  DCHECK(value_reg.is(rax));
-  __ ret(0);
+void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
+  __ Move(this->name(), name);
 }
 
 
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
-                                                   Register value_reg,
-                                                   Label* miss_label) {
-  DCHECK(lookup->representation().IsHeapObject());
-  __ JumpIfSmi(value_reg, miss_label);
-  HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
-  Label do_store;
-  while (true) {
-    __ CompareMap(value_reg, it.Current());
-    it.Advance();
-    if (it.Done()) {
-      __ j(not_equal, miss_label);
-      break;
-    }
-    __ j(equal, &do_store, Label::kNear);
+void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
+                                                   Register scratch,
+                                                   Label* miss) {
+  Handle<WeakCell> cell = Map::WeakCellForMap(transition);
+  Register map_reg = StoreTransitionDescriptor::MapRegister();
+  DCHECK(!map_reg.is(scratch));
+  __ LoadWeakValue(map_reg, cell, miss);
+  if (transition->CanBeDeprecated()) {
+    __ movl(scratch, FieldOperand(map_reg, Map::kBitField3Offset));
+    __ andl(scratch, Immediate(Map::Deprecated::kMask));
+    __ j(not_zero, miss);
   }
-  __ bind(&do_store);
+}
 
-  StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
-                      lookup->representation());
-  GenerateTailCall(masm(), stub.GetCode());
+
+void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
+                                                      int descriptor,
+                                                      Register value_reg,
+                                                      Register scratch,
+                                                      Label* miss_label) {
+  DCHECK(!map_reg.is(scratch));
+  DCHECK(!map_reg.is(value_reg));
+  DCHECK(!value_reg.is(scratch));
+  __ LoadInstanceDescriptors(map_reg, scratch);
+  __ movp(scratch,
+          FieldOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
+  __ cmpp(value_reg, scratch);
+  __ j(not_equal, miss_label);
+}
+
+
+void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type,
+                                                        Register value_reg,
+                                                        Label* miss_label) {
+  __ JumpIfSmi(value_reg, miss_label);
+  HeapType::Iterator<Map> it = field_type->Classes();
+  if (!it.Done()) {
+    Label do_store;
+    while (true) {
+      __ CompareMap(value_reg, it.Current());
+      it.Advance();
+      if (it.Done()) {
+        __ j(not_equal, miss_label);
+        break;
+      }
+      __ j(equal, &do_store, Label::kNear);
+    }
+    __ bind(&do_store);
+  }
 }
 
 
@@ -543,18 +448,13 @@
       reg = holder_reg;  // From now on the object will be in holder_reg.
       __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
     } else {
-      bool in_new_space = heap()->InNewSpace(*prototype);
-      // Two possible reasons for loading the prototype from the map:
-      // (1) Can't store references to new space in code.
-      // (2) Handler is shared for all receivers with the same prototype
-      //     map (but not necessarily the same prototype instance).
-      bool load_prototype_from_map = in_new_space || depth == 1;
-      if (load_prototype_from_map) {
-        // Save the map in scratch1 for later.
-        __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
-      }
+      Register map_reg = scratch1;
+      __ movp(map_reg, FieldOperand(reg, HeapObject::kMapOffset));
+
       if (depth != 1 || check == CHECK_ALL_MAPS) {
-        __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
+        Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+        __ CmpWeakValue(map_reg, cell, scratch2);
+        __ j(not_equal, miss);
       }
 
       // Check access rights to the global object.  This has to happen after
@@ -571,11 +471,7 @@
       }
       reg = holder_reg;  // From now on the object will be in holder_reg.
 
-      if (load_prototype_from_map) {
-        __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
-      } else {
-        __ Move(reg, prototype);
-      }
+      __ movp(reg, FieldOperand(map_reg, Map::kPrototypeOffset));
     }
 
     // Go to the next object in the prototype chain.
@@ -587,8 +483,10 @@
   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
 
   if (depth != 0 || check == CHECK_ALL_MAPS) {
-    // Check the holder map.
-    __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
+    __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
+    Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+    __ CmpWeakValue(scratch1, cell, scratch2);
+    __ j(not_equal, miss);
   }
 
   // Perform security check for access to the global object.
@@ -608,6 +506,10 @@
     Label success;
     __ jmp(&success);
     __ bind(miss);
+    if (IC::ICUseVector(kind())) {
+      DCHECK(kind() == Code::LOAD_IC);
+      PopVectorAndSlot();
+    }
     TailCallBuiltin(masm(), MissBuiltin(kind()));
     __ bind(&success);
   }
@@ -706,6 +608,7 @@
     }
     __ Push(holder_reg);
     __ Push(this->name());
+    InterceptorVectorSlotPush(holder_reg);
 
     // Invoke an interceptor.  Note: map checks from receiver to
     // interceptor's holder has been compiled before (see a caller
@@ -723,6 +626,7 @@
     __ ret(0);
 
     __ bind(&interceptor_failed);
+    InterceptorVectorSlotPop(holder_reg);
     __ Pop(this->name());
     __ Pop(holder_reg);
     if (must_preserve_receiver_reg) {
@@ -755,7 +659,7 @@
 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
     Handle<JSObject> object, Handle<Name> name,
     Handle<ExecutableAccessorInfo> callback) {
-  Register holder_reg = Frontend(receiver(), name);
+  Register holder_reg = Frontend(name);
 
   __ PopReturnAddressTo(scratch1());
   __ Push(receiver());
@@ -801,11 +705,15 @@
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
   Label miss;
+  if (IC::ICUseVector(kind())) {
+    PushVectorAndSlot();
+  }
   FrontendHeader(receiver(), name, &miss);
 
   // Get the value from the cell.
   Register result = StoreDescriptor::ValueRegister();
-  __ Move(result, cell);
+  Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
+  __ LoadWeakValue(result, weak_cell, &miss);
   __ movp(result, FieldOperand(result, PropertyCell::kValueOffset));
 
   // Check for deleted property if property can actually be deleted.
@@ -819,6 +727,9 @@
 
   Counters* counters = isolate()->counters();
   __ IncrementCounter(counters->named_load_global_stub(), 1);
+  if (IC::ICUseVector(kind())) {
+    DiscardVectorAndSlot();
+  }
   __ ret(0);
 
   FrontendFooter(name, &miss);
diff --git a/src/ic/x64/ic-compiler-x64.cc b/src/ic/x64/ic-compiler-x64.cc
index a5848b6..5be9c46 100644
--- a/src/ic/x64/ic-compiler-x64.cc
+++ b/src/ic/x64/ic-compiler-x64.cc
@@ -42,20 +42,22 @@
     MapHandleList* receiver_maps, CodeHandleList* handler_stubs,
     MapHandleList* transitioned_maps) {
   Label miss;
-  __ JumpIfSmi(receiver(), &miss, Label::kNear);
+  __ JumpIfSmi(receiver(), &miss);
 
-  __ movp(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
+  Register map_reg = scratch1();
+  __ movp(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
   int receiver_count = receiver_maps->length();
   for (int i = 0; i < receiver_count; ++i) {
+    Handle<WeakCell> cell = Map::WeakCellForMap(receiver_maps->at(i));
     // Check map and tail call if there's a match
-    __ Cmp(scratch1(), receiver_maps->at(i));
+    __ CmpWeakValue(map_reg, cell, scratch2());
     if (transitioned_maps->at(i).is_null()) {
       __ j(equal, handler_stubs->at(i), RelocInfo::CODE_TARGET);
     } else {
       Label next_map;
       __ j(not_equal, &next_map, Label::kNear);
-      __ Move(transition_map(), transitioned_maps->at(i),
-              RelocInfo::EMBEDDED_OBJECT);
+      Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
+      __ LoadWeakValue(transition_map(), cell, &miss);
       __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
       __ bind(&next_map);
     }
@@ -79,9 +81,12 @@
 
   if (check == PROPERTY &&
       (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) {
-    // In case we are compiling an IC for dictionary loads and stores, just
+    // In case we are compiling an IC for dictionary loads or stores, just
     // check whether the name is unique.
     if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) {
+      // Keyed loads with dictionaries shouldn't be here, they go generic.
+      // The DCHECK is to protect assumptions when --vector-ics is on.
+      DCHECK(kind() != Code::KEYED_LOAD_IC);
       Register tmp = scratch1();
       __ JumpIfSmi(this->name(), &miss);
       __ movp(tmp, FieldOperand(this->name(), HeapObject::kMapOffset));
@@ -109,8 +114,9 @@
     Handle<Map> map = IC::TypeToMap(*type, isolate());
     if (!map->is_deprecated()) {
       number_of_handled_maps++;
+      Handle<WeakCell> cell = Map::WeakCellForMap(map);
       // Check map and tail call if there's a match
-      __ Cmp(map_reg, map);
+      __ CmpWeakValue(map_reg, cell, scratch2());
       if (type->Is(HeapType::Number())) {
         DCHECK(!number_case.is_unused());
         __ bind(&number_case);
diff --git a/src/ic/x64/ic-x64.cc b/src/ic/x64/ic-x64.cc
index ad79f30..2709a85 100644
--- a/src/ic/x64/ic-x64.cc
+++ b/src/ic/x64/ic-x64.cc
@@ -119,9 +119,8 @@
       NameDictionary::kElementsStartIndex * kPointerSize;
   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
   const int kTypeAndReadOnlyMask =
-      (PropertyDetails::TypeField::kMask |
-       PropertyDetails::AttributesField::encode(READ_ONLY))
-      << kSmiTagSize;
+      PropertyDetails::TypeField::kMask |
+      PropertyDetails::AttributesField::encode(READ_ONLY);
   __ Test(Operand(elements, scratch1, times_pointer_size,
                   kDetailsOffset - kHeapObjectTag),
           Smi::FromInt(kTypeAndReadOnlyMask));
@@ -403,33 +402,7 @@
 }
 
 
-void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
-  // Return address is on the stack.
-  Label miss;
-
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register index = LoadDescriptor::NameRegister();
-  Register scratch = rbx;
-  Register result = rax;
-  DCHECK(!scratch.is(receiver) && !scratch.is(index));
-
-  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
-                                          &miss,  // When not a string.
-                                          &miss,  // When not a number.
-                                          &miss,  // When index out of range.
-                                          STRING_INDEX_IS_ARRAY_INDEX);
-  char_at_generator.GenerateFast(masm);
-  __ ret(0);
-
-  StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-}
-
-
-static void KeyedStoreGenerateGenericHelper(
+static void KeyedStoreGenerateMegamorphicHelper(
     MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
     KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length) {
   Label transition_smi_elements;
@@ -566,12 +539,12 @@
 }
 
 
-void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
-                                   StrictMode strict_mode) {
+void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
+                                       StrictMode strict_mode) {
   // Return address is on the stack.
   Label slow, slow_with_tagged_index, fast_object, fast_object_grow;
   Label fast_double, fast_double_grow;
-  Label array, extra, check_if_double_array;
+  Label array, extra, check_if_double_array, maybe_name_key, miss;
   Register receiver = StoreDescriptor::ReceiverRegister();
   Register key = StoreDescriptor::NameRegister();
   DCHECK(receiver.is(rdx));
@@ -587,7 +560,7 @@
            Immediate(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
   __ j(not_zero, &slow_with_tagged_index);
   // Check that the key is a smi.
-  __ JumpIfNotSmi(key, &slow_with_tagged_index);
+  __ JumpIfNotSmi(key, &maybe_name_key);
   __ SmiToInteger32(key, key);
 
   __ CmpInstanceType(r9, JS_ARRAY_TYPE);
@@ -610,6 +583,17 @@
   PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode);
   // Never returns to here.
 
+  __ bind(&maybe_name_key);
+  __ movp(r9, FieldOperand(key, HeapObject::kMapOffset));
+  __ movzxbp(r9, FieldOperand(r9, Map::kInstanceTypeOffset));
+  __ JumpIfNotUniqueNameInstanceType(r9, &slow_with_tagged_index);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::STORE_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::STORE_IC, flags, false, receiver, key, rbx, no_reg);
+  // Cache miss.
+  __ jmp(&miss);
+
   // Extra capacity case: Check if there is extra capacity to
   // perform the store and update the length. Used for adding one
   // element to the array by writing to array[array.length].
@@ -644,10 +628,14 @@
   __ SmiCompareInteger32(FieldOperand(receiver, JSArray::kLengthOffset), key);
   __ j(below_equal, &extra);
 
-  KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, &slow,
-                                  kCheckMap, kDontIncrementLength);
-  KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
-                                  &slow, kDontCheckMap, kIncrementLength);
+  KeyedStoreGenerateMegamorphicHelper(masm, &fast_object, &fast_double, &slow,
+                                      kCheckMap, kDontIncrementLength);
+  KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
+                                      &fast_double_grow, &slow, kDontCheckMap,
+                                      kIncrementLength);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
 }
 
 
@@ -774,11 +762,30 @@
 }
 
 
-// A register that isn't one of the parameters to the load ic.
-static const Register LoadIC_TempRegister() { return rbx; }
+static void LoadIC_PushArgs(MacroAssembler* masm) {
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register name = LoadDescriptor::NameRegister();
+  if (FLAG_vector_ics) {
+    Register slot = VectorLoadICDescriptor::SlotRegister();
+    Register vector = VectorLoadICDescriptor::VectorRegister();
+    DCHECK(!rdi.is(receiver) && !rdi.is(name) && !rdi.is(slot) &&
+           !rdi.is(vector));
 
+    __ PopReturnAddressTo(rdi);
+    __ Push(receiver);
+    __ Push(name);
+    __ Push(slot);
+    __ Push(vector);
+    __ PushReturnAddressFrom(rdi);
+  } else {
+    DCHECK(!rbx.is(receiver) && !rbx.is(name));
 
-static const Register KeyedLoadIC_TempRegister() { return rbx; }
+    __ PopReturnAddressTo(rbx);
+    __ Push(receiver);
+    __ Push(name);
+    __ PushReturnAddressFrom(rbx);
+  }
+}
 
 
 void LoadIC::GenerateMiss(MacroAssembler* masm) {
@@ -787,25 +794,26 @@
   Counters* counters = masm->isolate()->counters();
   __ IncrementCounter(counters->load_miss(), 1);
 
-  __ PopReturnAddressTo(LoadIC_TempRegister());
-  __ Push(LoadDescriptor::ReceiverRegister());  // receiver
-  __ Push(LoadDescriptor::NameRegister());      // name
-  __ PushReturnAddressFrom(LoadIC_TempRegister());
+  LoadIC_PushArgs(masm);
 
   // Perform tail call to the entry.
   ExternalReference ref =
       ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
-  __ TailCallExternalReference(ref, 2, 1);
+  int arg_count = FLAG_vector_ics ? 4 : 2;
+  __ TailCallExternalReference(ref, arg_count, 1);
 }
 
 
 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
   // The return address is on the stack.
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register name = LoadDescriptor::NameRegister();
+  DCHECK(!rbx.is(receiver) && !rbx.is(name));
 
-  __ PopReturnAddressTo(LoadIC_TempRegister());
-  __ Push(LoadDescriptor::ReceiverRegister());  // receiver
-  __ Push(LoadDescriptor::NameRegister());      // name
-  __ PushReturnAddressFrom(LoadIC_TempRegister());
+  __ PopReturnAddressTo(rbx);
+  __ Push(receiver);
+  __ Push(name);
+  __ PushReturnAddressFrom(rbx);
 
   // Perform tail call to the entry.
   __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
@@ -817,25 +825,26 @@
   Counters* counters = masm->isolate()->counters();
   __ IncrementCounter(counters->keyed_load_miss(), 1);
 
-  __ PopReturnAddressTo(KeyedLoadIC_TempRegister());
-  __ Push(LoadDescriptor::ReceiverRegister());  // receiver
-  __ Push(LoadDescriptor::NameRegister());      // name
-  __ PushReturnAddressFrom(KeyedLoadIC_TempRegister());
+  LoadIC_PushArgs(masm);
 
   // Perform tail call to the entry.
   ExternalReference ref =
       ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
-  __ TailCallExternalReference(ref, 2, 1);
+  int arg_count = FLAG_vector_ics ? 4 : 2;
+  __ TailCallExternalReference(ref, arg_count, 1);
 }
 
 
 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
   // The return address is on the stack.
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register name = LoadDescriptor::NameRegister();
+  DCHECK(!rbx.is(receiver) && !rbx.is(name));
 
-  __ PopReturnAddressTo(KeyedLoadIC_TempRegister());
-  __ Push(LoadDescriptor::ReceiverRegister());  // receiver
-  __ Push(LoadDescriptor::NameRegister());      // name
-  __ PushReturnAddressFrom(KeyedLoadIC_TempRegister());
+  __ PopReturnAddressTo(rbx);
+  __ Push(receiver);
+  __ Push(name);
+  __ PushReturnAddressFrom(rbx);
 
   // Perform tail call to the entry.
   __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
@@ -849,7 +858,7 @@
   Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
       Code::ComputeHandlerFlags(Code::STORE_IC));
   masm->isolate()->stub_cache()->GenerateProbe(
-      masm, flags, false, StoreDescriptor::ReceiverRegister(),
+      masm, Code::STORE_IC, flags, false, StoreDescriptor::ReceiverRegister(),
       StoreDescriptor::NameRegister(), rbx, no_reg);
 
   // Cache miss: Jump to runtime.
diff --git a/src/ic/x64/stub-cache-x64.cc b/src/ic/x64/stub-cache-x64.cc
index a54ddca..f15635c 100644
--- a/src/ic/x64/stub-cache-x64.cc
+++ b/src/ic/x64/stub-cache-x64.cc
@@ -7,7 +7,9 @@
 #if V8_TARGET_ARCH_X64
 
 #include "src/codegen.h"
+#include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
+#include "src/interface-descriptors.h"
 
 namespace v8 {
 namespace internal {
@@ -16,7 +18,7 @@
 
 
 static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
-                       Code::Flags flags, bool leave_frame,
+                       Code::Kind ic_kind, Code::Flags flags, bool leave_frame,
                        StubCache::Table table, Register receiver, Register name,
                        // The offset is scaled by 4, based on
                        // kCacheIndexShift, which is two bits
@@ -41,14 +43,14 @@
   __ LoadAddress(kScratchRegister, key_offset);
 
   // Check that the key in the entry matches the name.
-  // Multiply entry offset by 16 to get the entry address. Since the
-  // offset register already holds the entry offset times four, multiply
-  // by a further four.
-  __ cmpl(name, Operand(kScratchRegister, offset, scale_factor, 0));
+  __ cmpp(name, Operand(kScratchRegister, offset, scale_factor, 0));
   __ j(not_equal, &miss);
 
   // Get the map entry from the cache.
   // Use key_offset + kPointerSize * 2, rather than loading map_offset.
+  DCHECK(isolate->stub_cache()->map_reference(table).address() -
+             isolate->stub_cache()->key_reference(table).address() ==
+         kPointerSize * 2);
   __ movp(kScratchRegister,
           Operand(kScratchRegister, offset, scale_factor, kPointerSize * 2));
   __ cmpp(kScratchRegister, FieldOperand(receiver, HeapObject::kMapOffset));
@@ -82,10 +84,11 @@
 }
 
 
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
-                              bool leave_frame, Register receiver,
-                              Register name, Register scratch, Register extra,
-                              Register extra2, Register extra3) {
+void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
+                              Code::Flags flags, bool leave_frame,
+                              Register receiver, Register name,
+                              Register scratch, Register extra, Register extra2,
+                              Register extra3) {
   Isolate* isolate = masm->isolate();
   Label miss;
   USE(extra);   // The register extra is not used on the X64 platform.
@@ -107,6 +110,17 @@
   DCHECK(extra2.is(no_reg));
   DCHECK(extra3.is(no_reg));
 
+#ifdef DEBUG
+  // If vector-based ics are in use, ensure that scratch doesn't conflict with
+  // the vector and slot registers, which need to be preserved for a handler
+  // call or miss.
+  if (IC::ICUseVector(ic_kind)) {
+    Register vector = VectorLoadICDescriptor::VectorRegister();
+    Register slot = VectorLoadICDescriptor::SlotRegister();
+    DCHECK(!AreAliased(vector, slot, scratch));
+  }
+#endif
+
   Counters* counters = masm->isolate()->counters();
   __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
 
@@ -123,8 +137,8 @@
   __ andp(scratch, Immediate((kPrimaryTableSize - 1) << kCacheIndexShift));
 
   // Probe the primary table.
-  ProbeTable(isolate, masm, flags, leave_frame, kPrimary, receiver, name,
-             scratch);
+  ProbeTable(isolate, masm, ic_kind, flags, leave_frame, kPrimary, receiver,
+             name, scratch);
 
   // Primary miss: Compute hash for secondary probe.
   __ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
@@ -136,8 +150,8 @@
   __ andp(scratch, Immediate((kSecondaryTableSize - 1) << kCacheIndexShift));
 
   // Probe the secondary table.
-  ProbeTable(isolate, masm, flags, leave_frame, kSecondary, receiver, name,
-             scratch);
+  ProbeTable(isolate, masm, ic_kind, flags, leave_frame, kSecondary, receiver,
+             name, scratch);
 
   // Cache miss: Fall-through and let caller handle the miss by
   // entering the runtime system.
diff --git a/src/ic/x87/handler-compiler-x87.cc b/src/ic/x87/handler-compiler-x87.cc
index e706998..2ff3595 100644
--- a/src/ic/x87/handler-compiler-x87.cc
+++ b/src/ic/x87/handler-compiler-x87.cc
@@ -47,6 +47,28 @@
 }
 
 
+void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
+                                                Register slot) {
+  MacroAssembler* masm = this->masm();
+  __ push(vector);
+  __ push(slot);
+}
+
+
+void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
+  MacroAssembler* masm = this->masm();
+  __ pop(slot);
+  __ pop(vector);
+}
+
+
+void PropertyHandlerCompiler::DiscardVectorAndSlot() {
+  MacroAssembler* masm = this->masm();
+  // Remove vector and slot.
+  __ add(esp, Immediate(2 * kPointerSize));
+}
+
+
 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
     MacroAssembler* masm, Label* miss_label, Register receiver,
     Handle<Name> name, Register scratch0, Register scratch1) {
@@ -88,28 +110,23 @@
 
 
 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
-    MacroAssembler* masm, int index, Register prototype, Label* miss) {
-  // Get the global function with the given index.
-  Handle<JSFunction> function(
-      JSFunction::cast(masm->isolate()->native_context()->get(index)));
-  // Check we're still in the same context.
-  Register scratch = prototype;
+    MacroAssembler* masm, int index, Register result, Label* miss) {
   const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX);
-  __ mov(scratch, Operand(esi, offset));
-  __ mov(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset));
-  __ cmp(Operand(scratch, Context::SlotOffset(index)), function);
-  __ j(not_equal, miss);
-
+  __ mov(result, Operand(esi, offset));
+  __ mov(result, FieldOperand(result, GlobalObject::kNativeContextOffset));
+  __ mov(result, Operand(result, Context::SlotOffset(index)));
   // Load its initial map. The global functions all have initial maps.
-  __ Move(prototype, Immediate(Handle<Map>(function->initial_map())));
+  __ mov(result,
+         FieldOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
   // Load the prototype from the initial map.
-  __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
+  __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
 }
 
 
 void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
     MacroAssembler* masm, Register receiver, Register scratch1,
     Register scratch2, Label* miss_label) {
+  DCHECK(!FLAG_vector_ics);
   __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
   __ mov(eax, scratch1);
   __ ret(0);
@@ -329,172 +346,60 @@
 }
 
 
-// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
-// store is successful.
-void NamedStoreHandlerCompiler::GenerateStoreTransition(
-    Handle<Map> transition, Handle<Name> name, Register receiver_reg,
-    Register storage_reg, Register value_reg, Register scratch1,
-    Register scratch2, Register unused, Label* miss_label, Label* slow) {
-  int descriptor = transition->LastAdded();
-  DescriptorArray* descriptors = transition->instance_descriptors();
-  PropertyDetails details = descriptors->GetDetails(descriptor);
-  Representation representation = details.representation();
-  DCHECK(!representation.IsNone());
-
-  if (details.type() == CONSTANT) {
-    Handle<Object> constant(descriptors->GetValue(descriptor), isolate());
-    __ CmpObject(value_reg, constant);
-    __ j(not_equal, miss_label);
-  } else if (representation.IsSmi()) {
-    __ JumpIfNotSmi(value_reg, miss_label);
-  } else if (representation.IsHeapObject()) {
-    __ JumpIfSmi(value_reg, miss_label);
-    HeapType* field_type = descriptors->GetFieldType(descriptor);
-    HeapType::Iterator<Map> it = field_type->Classes();
-    if (!it.Done()) {
-      Label do_store;
-      while (true) {
-        __ CompareMap(value_reg, it.Current());
-        it.Advance();
-        if (it.Done()) {
-          __ j(not_equal, miss_label);
-          break;
-        }
-        __ j(equal, &do_store, Label::kNear);
-      }
-      __ bind(&do_store);
-    }
-  } else if (representation.IsDouble()) {
-    Label do_store, heap_number;
-    __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow, MUTABLE);
-
-    __ JumpIfNotSmi(value_reg, &heap_number);
-    __ SmiUntag(value_reg);
-    __ push(value_reg);
-    __ fild_s(Operand(esp, 0));
-    __ pop(value_reg);
-    __ SmiTag(value_reg);
-    __ jmp(&do_store);
-
-    __ bind(&heap_number);
-    __ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label,
-                DONT_DO_SMI_CHECK);
-    __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
-
-    __ bind(&do_store);
-    __ fstp_d(FieldOperand(storage_reg, HeapNumber::kValueOffset));
-  }
-
-  // Stub never generated for objects that require access checks.
-  DCHECK(!transition->is_access_check_needed());
-
-  // Perform map transition for the receiver if necessary.
-  if (details.type() == FIELD &&
-      Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) {
-    // The properties must be extended before we can store the value.
-    // We jump to a runtime call that extends the properties array.
-    __ pop(scratch1);  // Return address.
-    __ push(receiver_reg);
-    __ push(Immediate(transition));
-    __ push(value_reg);
-    __ push(scratch1);
-    __ TailCallExternalReference(
-        ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
-                          isolate()),
-        3, 1);
-    return;
-  }
-
-  // Update the map of the object.
-  __ mov(scratch1, Immediate(transition));
-  __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
-
-  // Update the write barrier for the map field.
-  __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2,
-                      kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
-
-  if (details.type() == CONSTANT) {
-    DCHECK(value_reg.is(eax));
-    __ ret(0);
-    return;
-  }
-
-  int index = transition->instance_descriptors()->GetFieldIndex(
-      transition->LastAdded());
-
-  // Adjust for the number of properties stored in the object. Even in the
-  // face of a transition we can use the old map here because the size of the
-  // object and the number of in-object properties is not going to change.
-  index -= transition->inobject_properties();
-
-  SmiCheck smi_check =
-      representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
-  // TODO(verwaest): Share this code as a code stub.
-  if (index < 0) {
-    // Set the property straight into the object.
-    int offset = transition->instance_size() + (index * kPointerSize);
-    if (representation.IsDouble()) {
-      __ mov(FieldOperand(receiver_reg, offset), storage_reg);
-    } else {
-      __ mov(FieldOperand(receiver_reg, offset), value_reg);
-    }
-
-    if (!representation.IsSmi()) {
-      // Update the write barrier for the array address.
-      if (!representation.IsDouble()) {
-        __ mov(storage_reg, value_reg);
-      }
-      __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1,
-                          kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check);
-    }
-  } else {
-    // Write to the properties array.
-    int offset = index * kPointerSize + FixedArray::kHeaderSize;
-    // Get the properties array (optimistically).
-    __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
-    if (representation.IsDouble()) {
-      __ mov(FieldOperand(scratch1, offset), storage_reg);
-    } else {
-      __ mov(FieldOperand(scratch1, offset), value_reg);
-    }
-
-    if (!representation.IsSmi()) {
-      // Update the write barrier for the array address.
-      if (!representation.IsDouble()) {
-        __ mov(storage_reg, value_reg);
-      }
-      __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg,
-                          kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check);
-    }
-  }
-
-  // Return the value (register eax).
-  DCHECK(value_reg.is(eax));
-  __ ret(0);
+void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
+  __ mov(this->name(), Immediate(name));
 }
 
 
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
-                                                   Register value_reg,
-                                                   Label* miss_label) {
-  DCHECK(lookup->representation().IsHeapObject());
-  __ JumpIfSmi(value_reg, miss_label);
-  HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
-  Label do_store;
-  while (true) {
-    __ CompareMap(value_reg, it.Current());
-    it.Advance();
-    if (it.Done()) {
-      __ j(not_equal, miss_label);
-      break;
-    }
-    __ j(equal, &do_store, Label::kNear);
+void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
+                                                   Register scratch,
+                                                   Label* miss) {
+  Handle<WeakCell> cell = Map::WeakCellForMap(transition);
+  Register map_reg = StoreTransitionDescriptor::MapRegister();
+  DCHECK(!map_reg.is(scratch));
+  __ LoadWeakValue(map_reg, cell, miss);
+  if (transition->CanBeDeprecated()) {
+    __ mov(scratch, FieldOperand(map_reg, Map::kBitField3Offset));
+    __ and_(scratch, Immediate(Map::Deprecated::kMask));
+    __ j(not_zero, miss);
   }
-  __ bind(&do_store);
+}
 
-  StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
-                      lookup->representation());
-  GenerateTailCall(masm(), stub.GetCode());
+
+void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
+                                                      int descriptor,
+                                                      Register value_reg,
+                                                      Register scratch,
+                                                      Label* miss_label) {
+  DCHECK(!map_reg.is(scratch));
+  DCHECK(!map_reg.is(value_reg));
+  DCHECK(!value_reg.is(scratch));
+  __ LoadInstanceDescriptors(map_reg, scratch);
+  __ mov(scratch,
+         FieldOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
+  __ cmp(value_reg, scratch);
+  __ j(not_equal, miss_label);
+}
+
+
+void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(HeapType* field_type,
+                                                        Register value_reg,
+                                                        Label* miss_label) {
+  __ JumpIfSmi(value_reg, miss_label);
+  HeapType::Iterator<Map> it = field_type->Classes();
+  if (!it.Done()) {
+    Label do_store;
+    while (true) {
+      __ CompareMap(value_reg, it.Current());
+      it.Advance();
+      if (it.Done()) {
+        __ j(not_equal, miss_label);
+        break;
+      }
+      __ j(equal, &do_store, Label::kNear);
+    }
+    __ bind(&do_store);
+  }
 }
 
 
@@ -548,14 +453,12 @@
       reg = holder_reg;  // From now on the object will be in holder_reg.
       __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
     } else {
-      bool in_new_space = heap()->InNewSpace(*prototype);
-      // Two possible reasons for loading the prototype from the map:
-      // (1) Can't store references to new space in code.
-      // (2) Handler is shared for all receivers with the same prototype
-      //     map (but not necessarily the same prototype instance).
-      bool load_prototype_from_map = in_new_space || depth == 1;
+      Register map_reg = scratch1;
+      __ mov(map_reg, FieldOperand(reg, HeapObject::kMapOffset));
       if (depth != 1 || check == CHECK_ALL_MAPS) {
-        __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
+        Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+        __ CmpWeakValue(map_reg, cell, scratch2);
+        __ j(not_equal, miss);
       }
 
       // Check access rights to the global object.  This has to happen after
@@ -565,24 +468,15 @@
       // global proxy (as opposed to using slow ICs). See corresponding code
       // in LookupForRead().
       if (current_map->IsJSGlobalProxyMap()) {
-        __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
+        __ CheckAccessGlobalProxy(reg, map_reg, scratch2, miss);
+        // Restore map_reg.
+        __ mov(map_reg, FieldOperand(reg, HeapObject::kMapOffset));
       } else if (current_map->IsJSGlobalObjectMap()) {
         GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
                                   name, scratch2, miss);
       }
-
-      if (load_prototype_from_map) {
-        // Save the map in scratch1 for later.
-        __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
-      }
-
       reg = holder_reg;  // From now on the object will be in holder_reg.
-
-      if (load_prototype_from_map) {
-        __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
-      } else {
-        __ mov(reg, prototype);
-      }
+      __ mov(reg, FieldOperand(map_reg, Map::kPrototypeOffset));
     }
 
     // Go to the next object in the prototype chain.
@@ -595,7 +489,10 @@
 
   if (depth != 0 || check == CHECK_ALL_MAPS) {
     // Check the holder map.
-    __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
+    __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
+    Handle<WeakCell> cell = Map::WeakCellForMap(current_map);
+    __ CmpWeakValue(scratch1, cell, scratch2);
+    __ j(not_equal, miss);
   }
 
   // Perform security check for access to the global object.
@@ -615,6 +512,10 @@
     Label success;
     __ jmp(&success);
     __ bind(miss);
+    if (IC::ICUseVector(kind())) {
+      DCHECK(kind() == Code::LOAD_IC);
+      PopVectorAndSlot();
+    }
     TailCallBuiltin(masm(), MissBuiltin(kind()));
     __ bind(&success);
   }
@@ -714,7 +615,7 @@
     }
     __ push(holder_reg);
     __ push(this->name());
-
+    InterceptorVectorSlotPush(holder_reg);
     // Invoke an interceptor.  Note: map checks from receiver to
     // interceptor's holder has been compiled before (see a caller
     // of this method.)
@@ -738,6 +639,7 @@
       __ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue)));
     }
 
+    InterceptorVectorSlotPop(holder_reg);
     __ pop(this->name());
     __ pop(holder_reg);
     if (must_preserve_receiver_reg) {
@@ -770,7 +672,7 @@
 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
     Handle<JSObject> object, Handle<Name> name,
     Handle<ExecutableAccessorInfo> callback) {
-  Register holder_reg = Frontend(receiver(), name);
+  Register holder_reg = Frontend(name);
 
   __ pop(scratch1());  // remove the return address
   __ push(receiver());
@@ -816,16 +718,15 @@
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
   Label miss;
-
+  if (IC::ICUseVector(kind())) {
+    PushVectorAndSlot();
+  }
   FrontendHeader(receiver(), name, &miss);
   // Get the value from the cell.
   Register result = StoreDescriptor::ValueRegister();
-  if (masm()->serializer_enabled()) {
-    __ mov(result, Immediate(cell));
-    __ mov(result, FieldOperand(result, PropertyCell::kValueOffset));
-  } else {
-    __ mov(result, Operand::ForCell(cell));
-  }
+  Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
+  __ LoadWeakValue(result, weak_cell, &miss);
+  __ mov(result, FieldOperand(result, PropertyCell::kValueOffset));
 
   // Check for deleted property if property can actually be deleted.
   if (is_configurable) {
@@ -839,6 +740,9 @@
   Counters* counters = isolate()->counters();
   __ IncrementCounter(counters->named_load_global_stub(), 1);
   // The code above already loads the result into the return register.
+  if (IC::ICUseVector(kind())) {
+    DiscardVectorAndSlot();
+  }
   __ ret(0);
 
   FrontendFooter(name, &miss);
diff --git a/src/ic/x87/ic-compiler-x87.cc b/src/ic/x87/ic-compiler-x87.cc
index 20b47e7..89bd937 100644
--- a/src/ic/x87/ic-compiler-x87.cc
+++ b/src/ic/x87/ic-compiler-x87.cc
@@ -44,10 +44,13 @@
   Label miss;
 
   if (check == PROPERTY &&
-      (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) {
-    // In case we are compiling an IC for dictionary loads and stores, just
+      (kind() == Code::KEYED_STORE_IC || kind() == Code::KEYED_LOAD_IC)) {
+    // In case we are compiling an IC for dictionary loads or stores, just
     // check whether the name is unique.
     if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) {
+      // Keyed loads with dictionaries shouldn't be here, they go generic.
+      // The DCHECK is to protect assumptions when --vector-ics is on.
+      DCHECK(kind() != Code::KEYED_LOAD_IC);
       Register tmp = scratch1();
       __ JumpIfSmi(this->name(), &miss);
       __ mov(tmp, FieldOperand(this->name(), HeapObject::kMapOffset));
@@ -75,7 +78,8 @@
     Handle<Map> map = IC::TypeToMap(*type, isolate());
     if (!map->is_deprecated()) {
       number_of_handled_maps++;
-      __ cmp(map_reg, map);
+      Handle<WeakCell> cell = Map::WeakCellForMap(map);
+      __ CmpWeakValue(map_reg, cell, scratch2());
       if (type->Is(HeapType::Number())) {
         DCHECK(!number_case.is_unused());
         __ bind(&number_case);
@@ -100,15 +104,18 @@
     MapHandleList* transitioned_maps) {
   Label miss;
   __ JumpIfSmi(receiver(), &miss, Label::kNear);
-  __ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
+  Register map_reg = scratch1();
+  __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
   for (int i = 0; i < receiver_maps->length(); ++i) {
-    __ cmp(scratch1(), receiver_maps->at(i));
+    Handle<WeakCell> cell = Map::WeakCellForMap(receiver_maps->at(i));
+    __ CmpWeakValue(map_reg, cell, scratch2());
     if (transitioned_maps->at(i).is_null()) {
       __ j(equal, handler_stubs->at(i));
     } else {
       Label next_map;
       __ j(not_equal, &next_map, Label::kNear);
-      __ mov(transition_map(), Immediate(transitioned_maps->at(i)));
+      Handle<WeakCell> cell = Map::WeakCellForMap(transitioned_maps->at(i));
+      __ LoadWeakValue(transition_map(), cell, &miss);
       __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
       __ bind(&next_map);
     }
diff --git a/src/ic/x87/ic-x87.cc b/src/ic/x87/ic-x87.cc
index 9c090c5..1004ac0 100644
--- a/src/ic/x87/ic-x87.cc
+++ b/src/ic/x87/ic-x87.cc
@@ -478,33 +478,6 @@
 }
 
 
-void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
-  // Return address is on the stack.
-  Label miss;
-
-  Register receiver = LoadDescriptor::ReceiverRegister();
-  Register index = LoadDescriptor::NameRegister();
-  Register scratch = ebx;
-  DCHECK(!scratch.is(receiver) && !scratch.is(index));
-  Register result = eax;
-  DCHECK(!result.is(scratch));
-
-  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
-                                          &miss,  // When not a string.
-                                          &miss,  // When not a number.
-                                          &miss,  // When index out of range.
-                                          STRING_INDEX_IS_ARRAY_INDEX);
-  char_at_generator.GenerateFast(masm);
-  __ ret(0);
-
-  StubRuntimeCallHelper call_helper;
-  char_at_generator.GenerateSlow(masm, call_helper);
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-}
-
-
 void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
   // Return address is on the stack.
   Label slow, notin;
@@ -536,7 +509,7 @@
 }
 
 
-static void KeyedStoreGenerateGenericHelper(
+static void KeyedStoreGenerateMegamorphicHelper(
     MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
     KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length) {
   Label transition_smi_elements;
@@ -674,12 +647,12 @@
 }
 
 
-void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
-                                   StrictMode strict_mode) {
+void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
+                                       StrictMode strict_mode) {
   // Return address is on the stack.
   Label slow, fast_object, fast_object_grow;
   Label fast_double, fast_double_grow;
-  Label array, extra, check_if_double_array;
+  Label array, extra, check_if_double_array, maybe_name_key, miss;
   Register receiver = StoreDescriptor::ReceiverRegister();
   Register key = StoreDescriptor::NameRegister();
   DCHECK(receiver.is(edx));
@@ -695,7 +668,7 @@
             1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved);
   __ j(not_zero, &slow);
   // Check that the key is a smi.
-  __ JumpIfNotSmi(key, &slow);
+  __ JumpIfNotSmi(key, &maybe_name_key);
   __ CmpInstanceType(edi, JS_ARRAY_TYPE);
   __ j(equal, &array);
   // Check that the object is some kind of JSObject.
@@ -713,6 +686,18 @@
   // Slow case: call runtime.
   __ bind(&slow);
   PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode);
+  // Never returns to here.
+
+  __ bind(&maybe_name_key);
+  __ mov(ebx, FieldOperand(key, HeapObject::kMapOffset));
+  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
+  __ JumpIfNotUniqueNameInstanceType(ebx, &slow);
+  Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+      Code::ComputeHandlerFlags(Code::STORE_IC));
+  masm->isolate()->stub_cache()->GenerateProbe(
+      masm, Code::STORE_IC, flags, false, receiver, key, ebx, no_reg);
+  // Cache miss.
+  __ jmp(&miss);
 
   // Extra capacity case: Check if there is extra capacity to
   // perform the store and update the length. Used for adding one
@@ -751,10 +736,14 @@
   __ cmp(key, FieldOperand(receiver, JSArray::kLengthOffset));  // Compare smis.
   __ j(above_equal, &extra);
 
-  KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, &slow,
-                                  kCheckMap, kDontIncrementLength);
-  KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
-                                  &slow, kDontCheckMap, kIncrementLength);
+  KeyedStoreGenerateMegamorphicHelper(masm, &fast_object, &fast_double, &slow,
+                                      kCheckMap, kDontIncrementLength);
+  KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
+                                      &fast_double_grow, &slow, kDontCheckMap,
+                                      kIncrementLength);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
 }
 
 
@@ -780,31 +769,52 @@
 static void LoadIC_PushArgs(MacroAssembler* masm) {
   Register receiver = LoadDescriptor::ReceiverRegister();
   Register name = LoadDescriptor::NameRegister();
-  DCHECK(!ebx.is(receiver) && !ebx.is(name));
+  if (FLAG_vector_ics) {
+    Register slot = VectorLoadICDescriptor::SlotRegister();
+    Register vector = VectorLoadICDescriptor::VectorRegister();
+    DCHECK(!edi.is(receiver) && !edi.is(name) && !edi.is(slot) &&
+           !edi.is(vector));
 
-  __ pop(ebx);
-  __ push(receiver);
-  __ push(name);
-  __ push(ebx);
+    __ pop(edi);
+    __ push(receiver);
+    __ push(name);
+    __ push(slot);
+    __ push(vector);
+    __ push(edi);
+  } else {
+    DCHECK(!ebx.is(receiver) && !ebx.is(name));
+
+    __ pop(ebx);
+    __ push(receiver);
+    __ push(name);
+    __ push(ebx);
+  }
 }
 
 
 void LoadIC::GenerateMiss(MacroAssembler* masm) {
   // Return address is on the stack.
   __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
-
   LoadIC_PushArgs(masm);
 
   // Perform tail call to the entry.
   ExternalReference ref =
       ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
-  __ TailCallExternalReference(ref, 2, 1);
+  int arg_count = FLAG_vector_ics ? 4 : 2;
+  __ TailCallExternalReference(ref, arg_count, 1);
 }
 
 
 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
   // Return address is on the stack.
-  LoadIC_PushArgs(masm);
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register name = LoadDescriptor::NameRegister();
+  DCHECK(!ebx.is(receiver) && !ebx.is(name));
+
+  __ pop(ebx);
+  __ push(receiver);
+  __ push(name);
+  __ push(ebx);
 
   // Perform tail call to the entry.
   __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
@@ -820,13 +830,21 @@
   // Perform tail call to the entry.
   ExternalReference ref =
       ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
-  __ TailCallExternalReference(ref, 2, 1);
+  int arg_count = FLAG_vector_ics ? 4 : 2;
+  __ TailCallExternalReference(ref, arg_count, 1);
 }
 
 
 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
   // Return address is on the stack.
-  LoadIC_PushArgs(masm);
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register name = LoadDescriptor::NameRegister();
+  DCHECK(!ebx.is(receiver) && !ebx.is(name));
+
+  __ pop(ebx);
+  __ push(receiver);
+  __ push(name);
+  __ push(ebx);
 
   // Perform tail call to the entry.
   __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
@@ -838,7 +856,7 @@
   Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
       Code::ComputeHandlerFlags(Code::STORE_IC));
   masm->isolate()->stub_cache()->GenerateProbe(
-      masm, flags, false, StoreDescriptor::ReceiverRegister(),
+      masm, Code::STORE_IC, flags, false, StoreDescriptor::ReceiverRegister(),
       StoreDescriptor::NameRegister(), ebx, no_reg);
 
   // Cache miss: Jump to runtime.
diff --git a/src/ic/x87/stub-cache-x87.cc b/src/ic/x87/stub-cache-x87.cc
index 0291ef3..be456ce 100644
--- a/src/ic/x87/stub-cache-x87.cc
+++ b/src/ic/x87/stub-cache-x87.cc
@@ -7,7 +7,9 @@
 #if V8_TARGET_ARCH_X87
 
 #include "src/codegen.h"
+#include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
+#include "src/interface-descriptors.h"
 
 namespace v8 {
 namespace internal {
@@ -16,7 +18,7 @@
 
 
 static void ProbeTable(Isolate* isolate, MacroAssembler* masm,
-                       Code::Flags flags, bool leave_frame,
+                       Code::Kind ic_kind, Code::Flags flags, bool leave_frame,
                        StubCache::Table table, Register name, Register receiver,
                        // Number of the cache entry pointer-size scaled.
                        Register offset, Register extra) {
@@ -56,6 +58,13 @@
     }
 #endif
 
+    if (IC::ICUseVector(ic_kind)) {
+      // The vector and slot were pushed onto the stack before starting the
+      // probe, and need to be dropped before calling the handler.
+      __ pop(VectorLoadICDescriptor::VectorRegister());
+      __ pop(VectorLoadICDescriptor::SlotRegister());
+    }
+
     if (leave_frame) __ leave();
 
     // Jump to the first instruction in the code stub.
@@ -100,6 +109,18 @@
     __ pop(offset);
     __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
 
+    if (IC::ICUseVector(ic_kind)) {
+      // The vector and slot were pushed onto the stack before starting the
+      // probe, and need to be dropped before calling the handler.
+      Register vector = VectorLoadICDescriptor::VectorRegister();
+      Register slot = VectorLoadICDescriptor::SlotRegister();
+      DCHECK(!offset.is(vector) && !offset.is(slot));
+
+      __ pop(vector);
+      __ pop(slot);
+    }
+
+
     if (leave_frame) __ leave();
 
     // Jump to the first instruction in the code stub.
@@ -113,10 +134,11 @@
 }
 
 
-void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags,
-                              bool leave_frame, Register receiver,
-                              Register name, Register scratch, Register extra,
-                              Register extra2, Register extra3) {
+void StubCache::GenerateProbe(MacroAssembler* masm, Code::Kind ic_kind,
+                              Code::Flags flags, bool leave_frame,
+                              Register receiver, Register name,
+                              Register scratch, Register extra, Register extra2,
+                              Register extra3) {
   Label miss;
 
   // Assert that code is valid.  The multiplying code relies on the entry size
@@ -159,8 +181,8 @@
   DCHECK(kCacheIndexShift == kPointerSizeLog2);
 
   // Probe the primary table.
-  ProbeTable(isolate(), masm, flags, leave_frame, kPrimary, name, receiver,
-             offset, extra);
+  ProbeTable(isolate(), masm, ic_kind, flags, leave_frame, kPrimary, name,
+             receiver, offset, extra);
 
   // Primary miss: Compute hash for secondary probe.
   __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
@@ -172,8 +194,8 @@
   __ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift);
 
   // Probe the secondary table.
-  ProbeTable(isolate(), masm, flags, leave_frame, kSecondary, name, receiver,
-             offset, extra);
+  ProbeTable(isolate(), masm, ic_kind, flags, leave_frame, kSecondary, name,
+             receiver, offset, extra);
 
   // Cache miss: Fall-through and let caller handle the miss by
   // entering the runtime system.
diff --git a/src/interface-descriptors.cc b/src/interface-descriptors.cc
index 62d7105..b1ebc3f 100644
--- a/src/interface-descriptors.cc
+++ b/src/interface-descriptors.cc
@@ -42,7 +42,7 @@
 }
 
 
-const char* CallInterfaceDescriptor::DebugName(Isolate* isolate) {
+const char* CallInterfaceDescriptor::DebugName(Isolate* isolate) const {
   CallInterfaceDescriptorData* start = isolate->call_descriptor_data(0);
   size_t index = data_ - start;
   DCHECK(index < CallDescriptors::NUMBER_OF_DESCRIPTORS);
@@ -74,6 +74,13 @@
 }
 
 
+void StoreTransitionDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {ContextRegister(), ReceiverRegister(), NameRegister(),
+                          ValueRegister(), MapRegister()};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
 void ElementTransitionAndStoreDescriptor::Initialize(
     CallInterfaceDescriptorData* data) {
   Register registers[] = {ContextRegister(), ValueRegister(), MapRegister(),
diff --git a/src/interface-descriptors.h b/src/interface-descriptors.h
index b773c91..5d02e84 100644
--- a/src/interface-descriptors.h
+++ b/src/interface-descriptors.h
@@ -16,6 +16,7 @@
 #define INTERFACE_DESCRIPTOR_LIST(V)          \
   V(Load)                                     \
   V(Store)                                    \
+  V(StoreTransition)                          \
   V(ElementTransitionAndStore)                \
   V(Instanceof)                               \
   V(VectorLoadICTrampoline)                   \
@@ -32,6 +33,7 @@
   V(CallConstruct)                            \
   V(RegExpConstructResult)                    \
   V(TransitionElementsKind)                   \
+  V(AllocateHeapNumber)                       \
   V(ArrayConstructorConstantArgCount)         \
   V(ArrayConstructor)                         \
   V(InternalArrayConstructorConstantArgCount) \
@@ -162,7 +164,7 @@
 
   static const Register ContextRegister();
 
-  const char* DebugName(Isolate* isolate);
+  const char* DebugName(Isolate* isolate) const;
 
  protected:
   const CallInterfaceDescriptorData* data() const { return data_; }
@@ -213,6 +215,22 @@
 };
 
 
+class StoreTransitionDescriptor : public StoreDescriptor {
+ public:
+  DECLARE_DESCRIPTOR(StoreTransitionDescriptor, StoreDescriptor)
+
+  // Extends StoreDescriptor with Map parameter.
+  enum ParameterIndices {
+    kReceiverIndex,
+    kNameIndex,
+    kValueIndex,
+    kMapIndex,
+    kParameterCount
+  };
+  static const Register MapRegister();
+};
+
+
 class ElementTransitionAndStoreDescriptor : public StoreDescriptor {
  public:
   DECLARE_DESCRIPTOR(ElementTransitionAndStoreDescriptor, StoreDescriptor)
@@ -329,6 +347,12 @@
 };
 
 
+class AllocateHeapNumberDescriptor : public CallInterfaceDescriptor {
+ public:
+  DECLARE_DESCRIPTOR(AllocateHeapNumberDescriptor, CallInterfaceDescriptor)
+};
+
+
 class ArrayConstructorConstantArgCountDescriptor
     : public CallInterfaceDescriptor {
  public:
diff --git a/src/interface.cc b/src/interface.cc
index 62169f5..a45804c 100644
--- a/src/interface.cc
+++ b/src/interface.cc
@@ -6,23 +6,64 @@
 
 #include "src/interface.h"
 
+#include "src/base/lazy-instance.h"
+
 namespace v8 {
 namespace internal {
 
+// ---------------------------------------------------------------------------
+// Initialization.
+
+struct Interface::Cache {
+  template<int flags>
+  struct Create {
+    static void Construct(Interface* ptr) { ::new (ptr) Interface(flags); }
+  };
+  typedef Create<VALUE + FROZEN> ValueCreate;
+  typedef Create<VALUE + CONST + FROZEN> ConstCreate;
+
+  static base::LazyInstance<Interface, ValueCreate>::type value_interface;
+  static base::LazyInstance<Interface, ConstCreate>::type const_interface;
+};
+
+
+base::LazyInstance<Interface, Interface::Cache::ValueCreate>::type
+    Interface::Cache::value_interface = LAZY_INSTANCE_INITIALIZER;
+
+base::LazyInstance<Interface, Interface::Cache::ConstCreate>::type
+    Interface::Cache::const_interface = LAZY_INSTANCE_INITIALIZER;
+
+
+Interface* Interface::NewValue() {
+  return Cache::value_interface.Pointer();  // Cached.
+}
+
+
+Interface* Interface::NewConst() {
+  return Cache::const_interface.Pointer();  // Cached.
+}
+
+
+// ---------------------------------------------------------------------------
+// Lookup.
+
 Interface* Interface::Lookup(Handle<String> name, Zone* zone) {
   DCHECK(IsModule());
   ZoneHashMap* map = Chase()->exports_;
-  if (map == NULL) return NULL;
+  if (map == nullptr) return nullptr;
   ZoneAllocationPolicy allocator(zone);
-  ZoneHashMap::Entry* p = map->Lookup(name.location(), name->Hash(), false,
-                                      allocator);
-  if (p == NULL) return NULL;
+  ZoneHashMap::Entry* p =
+      map->Lookup(name.location(), name->Hash(), false, allocator);
+  if (p == nullptr) return nullptr;
   DCHECK(*static_cast<String**>(p->key) == *name);
-  DCHECK(p->value != NULL);
+  DCHECK(p->value != nullptr);
   return static_cast<Interface*>(p->value);
 }
 
 
+// ---------------------------------------------------------------------------
+// Addition.
+
 #ifdef DEBUG
 // Current nesting depth for debug output.
 class Nesting {
@@ -48,9 +89,9 @@
     PrintF("%*s# Adding...\n", Nesting::current(), "");
     PrintF("%*sthis = ", Nesting::current(), "");
     this->Print(Nesting::current());
-    const AstRawString* symbol = static_cast<const AstRawString*>(name);
-    PrintF("%*s%.*s : ", Nesting::current(), "", symbol->length(),
-           symbol->raw_data());
+    const AstRawString* raw = static_cast<const AstRawString*>(name);
+    PrintF("%*s%.*s : ", Nesting::current(), "",
+           raw->length(), raw->raw_data());
     interface->Print(Nesting::current());
   }
 #endif
@@ -58,7 +99,7 @@
   ZoneHashMap** map = &Chase()->exports_;
   ZoneAllocationPolicy allocator(zone);
 
-  if (*map == NULL) {
+  if (*map == nullptr) {
     *map = new(zone->New(sizeof(ZoneHashMap)))
         ZoneHashMap(ZoneHashMap::PointersMatch,
                     ZoneHashMap::kDefaultHashMapCapacity, allocator);
@@ -66,10 +107,10 @@
 
   ZoneHashMap::Entry* p =
       (*map)->Lookup(const_cast<void*>(name), hash, !IsFrozen(), allocator);
-  if (p == NULL) {
+  if (p == nullptr) {
     // This didn't have name but was frozen already, that's an error.
     *ok = false;
-  } else if (p->value == NULL) {
+  } else if (p->value == nullptr) {
     p->value = interface;
   } else {
 #ifdef DEBUG
@@ -88,11 +129,14 @@
 }
 
 
+// ---------------------------------------------------------------------------
+// Unification.
+
 void Interface::Unify(Interface* that, Zone* zone, bool* ok) {
   if (this->forward_) return this->Chase()->Unify(that, zone, ok);
   if (that->forward_) return this->Unify(that->Chase(), zone, ok);
-  DCHECK(this->forward_ == NULL);
-  DCHECK(that->forward_ == NULL);
+  DCHECK(this->forward_ == nullptr);
+  DCHECK(that->forward_ == nullptr);
 
   *ok = true;
   if (this == that) return;
@@ -118,7 +162,7 @@
 #endif
 
   // Merge the smaller interface into the larger, for performance.
-  if (this->exports_ != NULL && (that->exports_ == NULL ||
+  if (this->exports_ != nullptr && (that->exports_ == nullptr ||
       this->exports_->occupancy() >= that->exports_->occupancy())) {
     this->DoUnify(that, ok, zone);
   } else {
@@ -138,8 +182,8 @@
 
 
 void Interface::DoUnify(Interface* that, bool* ok, Zone* zone) {
-  DCHECK(this->forward_ == NULL);
-  DCHECK(that->forward_ == NULL);
+  DCHECK(this->forward_ == nullptr);
+  DCHECK(that->forward_ == nullptr);
   DCHECK(!this->IsValue());
   DCHECK(!that->IsValue());
   DCHECK(this->index_ == -1);
@@ -152,8 +196,8 @@
 
   // Try to merge all members from that into this.
   ZoneHashMap* map = that->exports_;
-  if (map != NULL) {
-    for (ZoneHashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
+  if (map != nullptr) {
+    for (ZoneHashMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) {
       this->DoAdd(p->key, p->hash, static_cast<Interface*>(p->value), zone, ok);
       if (!*ok) return;
     }
@@ -161,8 +205,8 @@
 
   // If the new interface is larger than that's, then there were members in
   // 'this' which 'that' didn't have. If 'that' was frozen that is an error.
-  int this_size = this->exports_ == NULL ? 0 : this->exports_->occupancy();
-  int that_size = map == NULL ? 0 : map->occupancy();
+  int this_size = this->exports_ == nullptr ? 0 : this->exports_->occupancy();
+  int that_size = map == nullptr ? 0 : map->occupancy();
   if (that->IsFrozen() && this_size > that_size) {
     *ok = false;
     return;
@@ -174,14 +218,19 @@
 }
 
 
+// ---------------------------------------------------------------------------
+// Printing.
+
 #ifdef DEBUG
 void Interface::Print(int n) {
   int n0 = n > 0 ? n : 0;
 
   if (FLAG_print_interface_details) {
     PrintF("%p", static_cast<void*>(this));
-    for (Interface* link = this->forward_; link != NULL; link = link->forward_)
+    for (Interface* link = this->forward_; link != nullptr;
+        link = link->forward_) {
       PrintF("->%p", static_cast<void*>(link));
+    }
     PrintF(" ");
   }
 
@@ -194,14 +243,15 @@
   } else if (IsModule()) {
     PrintF("module %d %s{", Index(), IsFrozen() ? "" : "(unresolved) ");
     ZoneHashMap* map = Chase()->exports_;
-    if (map == NULL || map->occupancy() == 0) {
+    if (map == nullptr || map->occupancy() == 0) {
       PrintF("}\n");
     } else if (n < 0 || n0 >= 2 * FLAG_print_interface_depth) {
       // Avoid infinite recursion on cyclic types.
       PrintF("...}\n");
     } else {
       PrintF("\n");
-      for (ZoneHashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
+      for (ZoneHashMap::Entry* p = map->Start();
+           p != nullptr; p = map->Next(p)) {
         String* name = *static_cast<String**>(p->key);
         Interface* interface = static_cast<Interface*>(p->value);
         PrintF("%*s%s : ", n0 + 2, "", name->ToAsciiArray());
diff --git a/src/interface.h b/src/interface.h
index 598d038..1843f47 100644
--- a/src/interface.h
+++ b/src/interface.h
@@ -41,15 +41,9 @@
     return new(zone) Interface(NONE);
   }
 
-  static Interface* NewValue() {
-    static Interface value_interface(VALUE + FROZEN);  // Cached.
-    return &value_interface;
-  }
+  static Interface* NewValue();
 
-  static Interface* NewConst() {
-    static Interface value_interface(VALUE + CONST + FROZEN);  // Cached.
-    return &value_interface;
-  }
+  static Interface* NewConst();
 
   static Interface* NewModule(Zone* zone) {
     return new(zone) Interface(MODULE);
@@ -129,7 +123,7 @@
     return exports ? exports->occupancy() : 0;
   }
 
-  // The context slot in the hosting global context pointing to this module.
+  // The context slot in the hosting script context pointing to this module.
   int Index() {
     DCHECK(IsModule() && IsFrozen());
     return Chase()->index_;
@@ -178,6 +172,8 @@
   // ---------------------------------------------------------------------------
   // Implementation.
  private:
+  struct Cache;
+
   enum Flags {    // All flags are monotonic
     NONE = 0,
     VALUE = 1,    // This type describes a value
diff --git a/src/isolate.cc b/src/isolate.cc
index c6a8b81..b24182b 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -4,20 +4,24 @@
 
 #include <stdlib.h>
 
+#include <fstream>  // NOLINT(readability/streams)
+#include <sstream>
+
 #include "src/v8.h"
 
 #include "src/ast.h"
 #include "src/base/platform/platform.h"
 #include "src/base/sys-info.h"
 #include "src/base/utils/random-number-generator.h"
+#include "src/basic-block-profiler.h"
 #include "src/bootstrapper.h"
 #include "src/codegen.h"
 #include "src/compilation-cache.h"
+#include "src/compilation-statistics.h"
 #include "src/cpu-profiler.h"
 #include "src/debug.h"
 #include "src/deoptimizer.h"
 #include "src/heap/spaces.h"
-#include "src/heap/sweeper-thread.h"
 #include "src/heap-profiler.h"
 #include "src/hydrogen.h"
 #include "src/ic/stub-cache.h"
@@ -64,6 +68,7 @@
 
 void ThreadLocalTop::InitializeInternal() {
   c_entry_fp_ = 0;
+  c_function_ = 0;
   handler_ = 0;
 #ifdef USE_SIMULATOR
   simulator_ = NULL;
@@ -110,12 +115,12 @@
 base::Thread::LocalStorageKey Isolate::isolate_key_;
 base::Thread::LocalStorageKey Isolate::thread_id_key_;
 base::Thread::LocalStorageKey Isolate::per_isolate_thread_data_key_;
-#ifdef DEBUG
-base::Thread::LocalStorageKey PerThreadAssertScopeBase::thread_local_key;
-#endif  // DEBUG
 base::LazyMutex Isolate::thread_data_table_mutex_ = LAZY_MUTEX_INITIALIZER;
 Isolate::ThreadDataTable* Isolate::thread_data_table_ = NULL;
 base::Atomic32 Isolate::isolate_counter_ = 0;
+#if DEBUG
+base::Atomic32 Isolate::isolate_key_created_ = 0;
+#endif
 
 Isolate::PerIsolateThreadData*
     Isolate::FindOrAllocatePerThreadDataForThisThread() {
@@ -155,12 +160,11 @@
   base::LockGuard<base::Mutex> lock_guard(thread_data_table_mutex_.Pointer());
   CHECK(thread_data_table_ == NULL);
   isolate_key_ = base::Thread::CreateThreadLocalKey();
+#if DEBUG
+  base::NoBarrier_Store(&isolate_key_created_, 1);
+#endif
   thread_id_key_ = base::Thread::CreateThreadLocalKey();
   per_isolate_thread_data_key_ = base::Thread::CreateThreadLocalKey();
-#ifdef DEBUG
-  PerThreadAssertScopeBase::thread_local_key =
-      base::Thread::CreateThreadLocalKey();
-#endif  // DEBUG
   thread_data_table_ = new Isolate::ThreadDataTable();
 }
 
@@ -393,7 +397,6 @@
       }
       DCHECK(cursor + 4 <= elements->length());
 
-
       Handle<Code> code = frames[i].code();
       Handle<Smi> offset(Smi::FromInt(frames[i].offset()), this);
       // The stack trace API should not expose receivers and function
@@ -442,30 +445,198 @@
 }
 
 
+Handle<JSArray> Isolate::GetDetailedStackTrace(Handle<JSObject> error_object) {
+  Handle<Name> key_detailed = factory()->detailed_stack_trace_symbol();
+  Handle<Object> stack_trace =
+      JSObject::GetDataProperty(error_object, key_detailed);
+  if (stack_trace->IsJSArray()) return Handle<JSArray>::cast(stack_trace);
+
+  if (!capture_stack_trace_for_uncaught_exceptions_) return Handle<JSArray>();
+
+  // Try to get details from simple stack trace.
+  Handle<JSArray> detailed_stack_trace =
+      GetDetailedFromSimpleStackTrace(error_object);
+  if (!detailed_stack_trace.is_null()) {
+    // Save the detailed stack since the simple one might be withdrawn later.
+    JSObject::SetProperty(error_object, key_detailed, detailed_stack_trace,
+                          STRICT).Assert();
+  }
+  return detailed_stack_trace;
+}
+
+
+class CaptureStackTraceHelper {
+ public:
+  CaptureStackTraceHelper(Isolate* isolate,
+                          StackTrace::StackTraceOptions options)
+      : isolate_(isolate) {
+    if (options & StackTrace::kColumnOffset) {
+      column_key_ =
+          factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("column"));
+    }
+    if (options & StackTrace::kLineNumber) {
+      line_key_ =
+          factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("lineNumber"));
+    }
+    if (options & StackTrace::kScriptId) {
+      script_id_key_ =
+          factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("scriptId"));
+    }
+    if (options & StackTrace::kScriptName) {
+      script_name_key_ =
+          factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("scriptName"));
+    }
+    if (options & StackTrace::kScriptNameOrSourceURL) {
+      script_name_or_source_url_key_ = factory()->InternalizeOneByteString(
+          STATIC_CHAR_VECTOR("scriptNameOrSourceURL"));
+    }
+    if (options & StackTrace::kFunctionName) {
+      function_key_ = factory()->InternalizeOneByteString(
+          STATIC_CHAR_VECTOR("functionName"));
+    }
+    if (options & StackTrace::kIsEval) {
+      eval_key_ =
+          factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("isEval"));
+    }
+    if (options & StackTrace::kIsConstructor) {
+      constructor_key_ = factory()->InternalizeOneByteString(
+          STATIC_CHAR_VECTOR("isConstructor"));
+    }
+  }
+
+  Handle<JSObject> NewStackFrameObject(Handle<JSFunction> fun,
+                                       Handle<Code> code, Address pc,
+                                       bool is_constructor) {
+    Handle<JSObject> stack_frame =
+        factory()->NewJSObject(isolate_->object_function());
+
+    Handle<Script> script(Script::cast(fun->shared()->script()));
+
+    if (!line_key_.is_null()) {
+      int script_line_offset = script->line_offset()->value();
+      int position = code->SourcePosition(pc);
+      int line_number = Script::GetLineNumber(script, position);
+      // line_number is already shifted by the script_line_offset.
+      int relative_line_number = line_number - script_line_offset;
+      if (!column_key_.is_null() && relative_line_number >= 0) {
+        Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
+        int start = (relative_line_number == 0) ? 0 :
+            Smi::cast(line_ends->get(relative_line_number - 1))->value() + 1;
+        int column_offset = position - start;
+        if (relative_line_number == 0) {
+          // For the case where the code is on the same line as the script
+          // tag.
+          column_offset += script->column_offset()->value();
+        }
+        JSObject::AddProperty(stack_frame, column_key_,
+                              handle(Smi::FromInt(column_offset + 1), isolate_),
+                              NONE);
+      }
+      JSObject::AddProperty(stack_frame, line_key_,
+                            handle(Smi::FromInt(line_number + 1), isolate_),
+                            NONE);
+    }
+
+    if (!script_id_key_.is_null()) {
+      JSObject::AddProperty(stack_frame, script_id_key_,
+                            handle(script->id(), isolate_), NONE);
+    }
+
+    if (!script_name_key_.is_null()) {
+      JSObject::AddProperty(stack_frame, script_name_key_,
+                            handle(script->name(), isolate_), NONE);
+    }
+
+    if (!script_name_or_source_url_key_.is_null()) {
+      Handle<Object> result = Script::GetNameOrSourceURL(script);
+      JSObject::AddProperty(stack_frame, script_name_or_source_url_key_, result,
+                            NONE);
+    }
+
+    if (!function_key_.is_null()) {
+      Handle<Object> fun_name(fun->shared()->DebugName(), isolate_);
+      JSObject::AddProperty(stack_frame, function_key_, fun_name, NONE);
+    }
+
+    if (!eval_key_.is_null()) {
+      Handle<Object> is_eval = factory()->ToBoolean(
+          script->compilation_type() == Script::COMPILATION_TYPE_EVAL);
+      JSObject::AddProperty(stack_frame, eval_key_, is_eval, NONE);
+    }
+
+    if (!constructor_key_.is_null()) {
+      Handle<Object> is_constructor_obj = factory()->ToBoolean(is_constructor);
+      JSObject::AddProperty(stack_frame, constructor_key_, is_constructor_obj,
+                            NONE);
+    }
+
+    return stack_frame;
+  }
+
+ private:
+  inline Factory* factory() { return isolate_->factory(); }
+
+  Isolate* isolate_;
+  Handle<String> column_key_;
+  Handle<String> line_key_;
+  Handle<String> script_id_key_;
+  Handle<String> script_name_key_;
+  Handle<String> script_name_or_source_url_key_;
+  Handle<String> function_key_;
+  Handle<String> eval_key_;
+  Handle<String> constructor_key_;
+};
+
+
+Handle<JSArray> Isolate::GetDetailedFromSimpleStackTrace(
+    Handle<JSObject> error_object) {
+  Handle<Name> key = factory()->stack_trace_symbol();
+  Handle<Object> property = JSObject::GetDataProperty(error_object, key);
+  if (!property->IsJSArray()) return Handle<JSArray>();
+  Handle<JSArray> simple_stack_trace = Handle<JSArray>::cast(property);
+
+  CaptureStackTraceHelper helper(this,
+                                 stack_trace_for_uncaught_exceptions_options_);
+
+  int frames_seen = 0;
+  Handle<FixedArray> elements(FixedArray::cast(simple_stack_trace->elements()));
+  int elements_limit = Smi::cast(simple_stack_trace->length())->value();
+
+  int frame_limit = stack_trace_for_uncaught_exceptions_frame_limit_;
+  if (frame_limit < 0) frame_limit = (elements_limit - 1) / 4;
+
+  Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit);
+  for (int i = 1; i < elements_limit && frames_seen < frame_limit; i += 4) {
+    Handle<Object> recv = handle(elements->get(i), this);
+    Handle<JSFunction> fun =
+        handle(JSFunction::cast(elements->get(i + 1)), this);
+    Handle<Code> code = handle(Code::cast(elements->get(i + 2)), this);
+    Handle<Smi> offset = handle(Smi::cast(elements->get(i + 3)), this);
+    Address pc = code->address() + offset->value();
+    bool is_constructor =
+        recv->IsJSObject() &&
+        Handle<JSObject>::cast(recv)->map()->constructor() == *fun;
+
+    Handle<JSObject> stack_frame =
+        helper.NewStackFrameObject(fun, code, pc, is_constructor);
+
+    FixedArray::cast(stack_trace->elements())->set(frames_seen, *stack_frame);
+    frames_seen++;
+  }
+
+  stack_trace->set_length(Smi::FromInt(frames_seen));
+  return stack_trace;
+}
+
+
 Handle<JSArray> Isolate::CaptureCurrentStackTrace(
     int frame_limit, StackTrace::StackTraceOptions options) {
+  CaptureStackTraceHelper helper(this, options);
+
   // Ensure no negative values.
   int limit = Max(frame_limit, 0);
   Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit);
 
-  Handle<String> column_key =
-      factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("column"));
-  Handle<String> line_key =
-      factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("lineNumber"));
-  Handle<String> script_id_key =
-      factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("scriptId"));
-  Handle<String> script_name_key =
-      factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("scriptName"));
-  Handle<String> script_name_or_source_url_key =
-      factory()->InternalizeOneByteString(
-          STATIC_CHAR_VECTOR("scriptNameOrSourceURL"));
-  Handle<String> function_key =
-      factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("functionName"));
-  Handle<String> eval_key =
-      factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("isEval"));
-  Handle<String> constructor_key =
-      factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("isConstructor"));
-
   StackTraceFrameIterator it(this);
   int frames_seen = 0;
   while (!it.done() && (frames_seen < limit)) {
@@ -480,70 +651,8 @@
       if (!(options & StackTrace::kExposeFramesAcrossSecurityOrigins) &&
           !this->context()->HasSameSecurityTokenAs(fun->context())) continue;
 
-      // Create a JSObject to hold the information for the StackFrame.
-      Handle<JSObject> stack_frame = factory()->NewJSObject(object_function());
-
-      Handle<Script> script(Script::cast(fun->shared()->script()));
-
-      if (options & StackTrace::kLineNumber) {
-        int script_line_offset = script->line_offset()->value();
-        int position = frames[i].code()->SourcePosition(frames[i].pc());
-        int line_number = Script::GetLineNumber(script, position);
-        // line_number is already shifted by the script_line_offset.
-        int relative_line_number = line_number - script_line_offset;
-        if (options & StackTrace::kColumnOffset && relative_line_number >= 0) {
-          Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
-          int start = (relative_line_number == 0) ? 0 :
-              Smi::cast(line_ends->get(relative_line_number - 1))->value() + 1;
-          int column_offset = position - start;
-          if (relative_line_number == 0) {
-            // For the case where the code is on the same line as the script
-            // tag.
-            column_offset += script->column_offset()->value();
-          }
-          JSObject::AddProperty(
-              stack_frame, column_key,
-              handle(Smi::FromInt(column_offset + 1), this), NONE);
-        }
-       JSObject::AddProperty(
-            stack_frame, line_key,
-            handle(Smi::FromInt(line_number + 1), this), NONE);
-      }
-
-      if (options & StackTrace::kScriptId) {
-        JSObject::AddProperty(
-            stack_frame, script_id_key, handle(script->id(), this), NONE);
-      }
-
-      if (options & StackTrace::kScriptName) {
-        JSObject::AddProperty(
-            stack_frame, script_name_key, handle(script->name(), this), NONE);
-      }
-
-      if (options & StackTrace::kScriptNameOrSourceURL) {
-        Handle<Object> result = Script::GetNameOrSourceURL(script);
-        JSObject::AddProperty(
-            stack_frame, script_name_or_source_url_key, result, NONE);
-      }
-
-      if (options & StackTrace::kFunctionName) {
-        Handle<Object> fun_name(fun->shared()->DebugName(), this);
-        JSObject::AddProperty(stack_frame, function_key, fun_name, NONE);
-      }
-
-      if (options & StackTrace::kIsEval) {
-        Handle<Object> is_eval =
-            script->compilation_type() == Script::COMPILATION_TYPE_EVAL ?
-                factory()->true_value() : factory()->false_value();
-        JSObject::AddProperty(stack_frame, eval_key, is_eval, NONE);
-      }
-
-      if (options & StackTrace::kIsConstructor) {
-        Handle<Object> is_constructor = (frames[i].is_constructor()) ?
-            factory()->true_value() : factory()->false_value();
-        JSObject::AddProperty(
-            stack_frame, constructor_key, is_constructor, NONE);
-      }
+      Handle<JSObject> stack_frame = helper.NewStackFrameObject(
+          fun, frames[i].code(), frames[i].pc(), frames[i].is_constructor());
 
       FixedArray::cast(stack_trace->elements())->set(frames_seen, *stack_frame);
       frames_seen++;
@@ -591,13 +700,6 @@
 
 
 void Isolate::PrintStack(StringStream* accumulator) {
-  if (!IsInitialized()) {
-    accumulator->Add(
-        "\n==== JS stack trace is not available =======================\n\n");
-    accumulator->Add(
-        "\n==== Isolate for the thread is not initialized =============\n\n");
-    return;
-  }
   // The MentionedObjectCache is not GC-proof at the moment.
   DisallowHeapAllocation no_gc;
   DCHECK(StringStream::IsMentionedObjectCacheClear(this));
@@ -700,14 +802,26 @@
 }
 
 
+bool Isolate::IsInternallyUsedPropertyName(Handle<Object> name) {
+  return name.is_identical_to(factory()->hidden_string()) ||
+         name.is_identical_to(factory()->prototype_users_symbol());
+}
+
+
+bool Isolate::IsInternallyUsedPropertyName(Object* name) {
+  return name == heap()->hidden_string() ||
+         name == heap()->prototype_users_symbol();
+}
+
+
 bool Isolate::MayNamedAccess(Handle<JSObject> receiver,
                              Handle<Object> key,
                              v8::AccessType type) {
   DCHECK(receiver->IsJSGlobalProxy() || receiver->IsAccessCheckNeeded());
 
-  // Skip checks for hidden properties access.  Note, we do not
+  // Skip checks for internally used properties. Note, we do not
   // require existence of a context in this case.
-  if (key.is_identical_to(factory()->hidden_string())) return true;
+  if (IsInternallyUsedPropertyName(key)) return true;
 
   // Check for compatibility between the security tokens in the
   // current lexical context and the accessed object.
@@ -815,22 +929,26 @@
 }
 
 
-void Isolate::InvokeApiInterruptCallback() {
-  // Note: callback below should be called outside of execution access lock.
-  InterruptCallback callback = NULL;
-  void* data = NULL;
-  {
-    ExecutionAccess access(this);
-    callback = api_interrupt_callback_;
-    data = api_interrupt_callback_data_;
-    api_interrupt_callback_ = NULL;
-    api_interrupt_callback_data_ = NULL;
-  }
+void Isolate::RequestInterrupt(InterruptCallback callback, void* data) {
+  ExecutionAccess access(this);
+  api_interrupts_queue_.push(InterruptEntry(callback, data));
+  stack_guard()->RequestApiInterrupt();
+}
 
-  if (callback != NULL) {
+
+void Isolate::InvokeApiInterruptCallbacks() {
+  // Note: callback below should be called outside of execution access lock.
+  while (true) {
+    InterruptEntry entry;
+    {
+      ExecutionAccess access(this);
+      if (api_interrupts_queue_.empty()) return;
+      entry = api_interrupts_queue_.front();
+      api_interrupts_queue_.pop();
+    }
     VMState<EXTERNAL> state(this);
     HandleScope handle_scope(this);
-    callback(reinterpret_cast<v8::Isolate*>(this), data);
+    entry.first(reinterpret_cast<v8::Isolate*>(this), entry.second);
   }
 }
 
@@ -921,9 +1039,7 @@
     // Advance to the next JavaScript frame and determine if the
     // current frame is the top-level frame.
     it.Advance();
-    Handle<Object> is_top_level = it.done()
-        ? factory()->true_value()
-        : factory()->false_value();
+    Handle<Object> is_top_level = factory()->ToBoolean(it.done());
     // Generate and print stack trace line.
     Handle<String> line =
         Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level);
@@ -953,6 +1069,41 @@
 }
 
 
+bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target,
+                                            Handle<Object> exception) {
+  *target = MessageLocation(Handle<Script>(heap_.empty_script()), -1, -1);
+
+  if (!exception->IsJSObject()) return false;
+  Handle<Name> key = factory()->stack_trace_symbol();
+  Handle<Object> property =
+      JSObject::GetDataProperty(Handle<JSObject>::cast(exception), key);
+  if (!property->IsJSArray()) return false;
+  Handle<JSArray> simple_stack_trace = Handle<JSArray>::cast(property);
+
+  Handle<FixedArray> elements(FixedArray::cast(simple_stack_trace->elements()));
+  int elements_limit = Smi::cast(simple_stack_trace->length())->value();
+
+  for (int i = 1; i < elements_limit; i += 4) {
+    Handle<JSFunction> fun =
+        handle(JSFunction::cast(elements->get(i + 1)), this);
+    if (fun->IsFromNativeScript()) continue;
+    Handle<Code> code = handle(Code::cast(elements->get(i + 2)), this);
+    Handle<Smi> offset = handle(Smi::cast(elements->get(i + 3)), this);
+    Address pc = code->address() + offset->value();
+
+    Object* script = fun->shared()->script();
+    if (script->IsScript() &&
+        !(Script::cast(script)->source()->IsUndefined())) {
+      int pos = code->SourcePosition(pc);
+      Handle<Script> casted_script(Script::cast(script));
+      *target = MessageLocation(casted_script, pos, pos + 1);
+      return true;
+    }
+  }
+  return false;
+}
+
+
 bool Isolate::ShouldReportException(bool* can_be_caught_externally,
                                     bool catchable_by_javascript) {
   // Find the top-most try-catch handler.
@@ -984,6 +1135,8 @@
 }
 
 
+// Traverse prototype chain to find out whether the object is derived from
+// the Error object.
 bool Isolate::IsErrorObject(Handle<Object> obj) {
   if (!obj->IsJSObject()) return false;
 
@@ -1006,6 +1159,98 @@
 
 static int fatal_exception_depth = 0;
 
+
+Handle<JSMessageObject> Isolate::CreateMessage(Handle<Object> exception,
+                                               MessageLocation* location) {
+  Handle<JSArray> stack_trace_object;
+  MessageLocation potential_computed_location;
+  if (capture_stack_trace_for_uncaught_exceptions_) {
+    if (IsErrorObject(exception)) {
+      // We fetch the stack trace that corresponds to this error object.
+      // If the lookup fails, the exception is probably not a valid Error
+      // object. In that case, we fall through and capture the stack trace
+      // at this throw site.
+      stack_trace_object =
+          GetDetailedStackTrace(Handle<JSObject>::cast(exception));
+    }
+    if (stack_trace_object.is_null()) {
+      // Not an error object, we capture stack and location at throw site.
+      stack_trace_object = CaptureCurrentStackTrace(
+          stack_trace_for_uncaught_exceptions_frame_limit_,
+          stack_trace_for_uncaught_exceptions_options_);
+    }
+  }
+  if (!location) {
+    if (!ComputeLocationFromStackTrace(&potential_computed_location,
+                                       exception)) {
+      ComputeLocation(&potential_computed_location);
+    }
+    location = &potential_computed_location;
+  }
+
+  // If the exception argument is a custom object, turn it into a string
+  // before throwing as uncaught exception.  Note that the pending
+  // exception object to be set later must not be turned into a string.
+  if (exception->IsJSObject() && !IsErrorObject(exception)) {
+    MaybeHandle<Object> maybe_exception =
+        Execution::ToDetailString(this, exception);
+    if (!maybe_exception.ToHandle(&exception)) {
+      exception =
+          factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("exception"));
+    }
+  }
+  return MessageHandler::MakeMessageObject(this, "uncaught_exception", location,
+                                           HandleVector<Object>(&exception, 1),
+                                           stack_trace_object);
+}
+
+
+void ReportBootstrappingException(Handle<Object> exception,
+                                  MessageLocation* location) {
+  base::OS::PrintError("Exception thrown during bootstrapping\n");
+  if (location == NULL || location->script().is_null()) return;
+  // We are bootstrapping and caught an error where the location is set
+  // and we have a script for the location.
+  // In this case we could have an extension (or an internal error
+  // somewhere) and we print out the line number at which the error occured
+  // to the console for easier debugging.
+  int line_number =
+      location->script()->GetLineNumber(location->start_pos()) + 1;
+  if (exception->IsString() && location->script()->name()->IsString()) {
+    base::OS::PrintError(
+        "Extension or internal compilation error: %s in %s at line %d.\n",
+        String::cast(*exception)->ToCString().get(),
+        String::cast(location->script()->name())->ToCString().get(),
+        line_number);
+  } else if (location->script()->name()->IsString()) {
+    base::OS::PrintError(
+        "Extension or internal compilation error in %s at line %d.\n",
+        String::cast(location->script()->name())->ToCString().get(),
+        line_number);
+  } else {
+    base::OS::PrintError("Extension or internal compilation error.\n");
+  }
+#ifdef OBJECT_PRINT
+  // Since comments and empty lines have been stripped from the source of
+  // builtins, print the actual source here so that line numbers match.
+  if (location->script()->source()->IsString()) {
+    Handle<String> src(String::cast(location->script()->source()));
+    PrintF("Failing script:\n");
+    int len = src->length();
+    int line_number = 1;
+    PrintF("%5d: ", line_number);
+    for (int i = 0; i < len; i++) {
+      uint16_t character = src->Get(i);
+      PrintF("%c", character);
+      if (character == '\n' && i < len - 2) {
+        PrintF("%5d: ", ++line_number);
+      }
+    }
+  }
+#endif
+}
+
+
 void Isolate::DoThrow(Object* exception, MessageLocation* location) {
   DCHECK(!has_pending_exception());
 
@@ -1020,7 +1265,6 @@
   bool report_exception = catchable_by_javascript && should_report_exception;
   bool try_catch_needs_message =
       can_be_caught_externally && try_catch_handler()->capture_message_;
-  bool bootstrapping = bootstrapper()->IsActive();
   bool rethrowing_message = thread_local_top()->rethrowing_message_;
 
   thread_local_top()->rethrowing_message_ = false;
@@ -1038,113 +1282,32 @@
       ComputeLocation(&potential_computed_location);
       location = &potential_computed_location;
     }
-    // It's not safe to try to make message objects or collect stack traces
-    // while the bootstrapper is active since the infrastructure may not have
-    // been properly initialized.
-    if (!bootstrapping) {
-      Handle<JSArray> stack_trace_object;
-      if (capture_stack_trace_for_uncaught_exceptions_) {
-        if (IsErrorObject(exception_handle)) {
-          // We fetch the stack trace that corresponds to this error object.
-          Handle<Name> key = factory()->detailed_stack_trace_symbol();
-          // Look up as own property.  If the lookup fails, the exception is
-          // probably not a valid Error object.  In that case, we fall through
-          // and capture the stack trace at this throw site.
-          LookupIterator lookup(exception_handle, key,
-                                LookupIterator::OWN_SKIP_INTERCEPTOR);
-          Handle<Object> stack_trace_property;
-          if (Object::GetProperty(&lookup).ToHandle(&stack_trace_property) &&
-              stack_trace_property->IsJSArray()) {
-            stack_trace_object = Handle<JSArray>::cast(stack_trace_property);
-          }
-        }
-        if (stack_trace_object.is_null()) {
-          // Not an error object, we capture at throw site.
-          stack_trace_object = CaptureCurrentStackTrace(
-              stack_trace_for_uncaught_exceptions_frame_limit_,
-              stack_trace_for_uncaught_exceptions_options_);
-        }
-      }
 
-      Handle<Object> exception_arg = exception_handle;
-      // If the exception argument is a custom object, turn it into a string
-      // before throwing as uncaught exception.  Note that the pending
-      // exception object to be set later must not be turned into a string.
-      if (exception_arg->IsJSObject() && !IsErrorObject(exception_arg)) {
-        MaybeHandle<Object> maybe_exception =
-            Execution::ToDetailString(this, exception_arg);
-        if (!maybe_exception.ToHandle(&exception_arg)) {
-          exception_arg = factory()->InternalizeOneByteString(
-              STATIC_CHAR_VECTOR("exception"));
-        }
-      }
-      Handle<Object> message_obj = MessageHandler::MakeMessageObject(
-          this,
-          "uncaught_exception",
-          location,
-          HandleVector<Object>(&exception_arg, 1),
-          stack_trace_object);
+    if (bootstrapper()->IsActive()) {
+      // It's not safe to try to make message objects or collect stack traces
+      // while the bootstrapper is active since the infrastructure may not have
+      // been properly initialized.
+      ReportBootstrappingException(exception_handle, location);
+    } else {
+      Handle<Object> message_obj = CreateMessage(exception_handle, location);
+
       thread_local_top()->pending_message_obj_ = *message_obj;
-      if (location != NULL) {
-        thread_local_top()->pending_message_script_ = *location->script();
-        thread_local_top()->pending_message_start_pos_ = location->start_pos();
-        thread_local_top()->pending_message_end_pos_ = location->end_pos();
-      }
+      thread_local_top()->pending_message_script_ = *location->script();
+      thread_local_top()->pending_message_start_pos_ = location->start_pos();
+      thread_local_top()->pending_message_end_pos_ = location->end_pos();
 
       // If the abort-on-uncaught-exception flag is specified, abort on any
       // exception not caught by JavaScript, even when an external handler is
       // present.  This flag is intended for use by JavaScript developers, so
       // print a user-friendly stack trace (not an internal one).
-      if (fatal_exception_depth == 0 &&
-          FLAG_abort_on_uncaught_exception &&
+      if (fatal_exception_depth == 0 && FLAG_abort_on_uncaught_exception &&
           (report_exception || can_be_caught_externally)) {
         fatal_exception_depth++;
-        PrintF(stderr,
-               "%s\n\nFROM\n",
+        PrintF(stderr, "%s\n\nFROM\n",
                MessageHandler::GetLocalizedMessage(this, message_obj).get());
         PrintCurrentStackTrace(stderr);
         base::OS::Abort();
       }
-    } else if (location != NULL && !location->script().is_null()) {
-      // We are bootstrapping and caught an error where the location is set
-      // and we have a script for the location.
-      // In this case we could have an extension (or an internal error
-      // somewhere) and we print out the line number at which the error occured
-      // to the console for easier debugging.
-      int line_number =
-          location->script()->GetLineNumber(location->start_pos()) + 1;
-      if (exception->IsString() && location->script()->name()->IsString()) {
-        base::OS::PrintError(
-            "Extension or internal compilation error: %s in %s at line %d.\n",
-            String::cast(exception)->ToCString().get(),
-            String::cast(location->script()->name())->ToCString().get(),
-            line_number);
-      } else if (location->script()->name()->IsString()) {
-        base::OS::PrintError(
-            "Extension or internal compilation error in %s at line %d.\n",
-            String::cast(location->script()->name())->ToCString().get(),
-            line_number);
-      } else {
-        base::OS::PrintError("Extension or internal compilation error.\n");
-      }
-#ifdef OBJECT_PRINT
-      // Since comments and empty lines have been stripped from the source of
-      // builtins, print the actual source here so that line numbers match.
-      if (location->script()->source()->IsString()) {
-        Handle<String> src(String::cast(location->script()->source()));
-        PrintF("Failing script:\n");
-        int len = src->length();
-        int line_number = 1;
-        PrintF("%5d: ", line_number);
-        for (int i = 0; i < len; i++) {
-          uint16_t character = src->Get(i);
-          PrintF("%c", character);
-          if (character == '\n' && i < len - 2) {
-            PrintF("%5d: ", ++line_number);
-          }
-        }
-      }
-#endif
     }
   }
 
@@ -1234,7 +1397,6 @@
 
   if (thread_local_top_.pending_exception_ != heap()->termination_exception() &&
       thread_local_top_.has_pending_message_ &&
-      !thread_local_top_.pending_message_obj_->IsTheHole() &&
       !thread_local_top_.pending_message_obj_->IsTheHole()) {
     Handle<Script> script(
         Script::cast(thread_local_top_.pending_message_script_));
@@ -1320,8 +1482,6 @@
   StackHandler* handler = StackHandler::FromAddress(Isolate::handler(tltop));
   do {
     if (handler == promise_try) {
-      // Mark the pushed try-catch handler to prevent a later duplicate event
-      // triggered with the following reject.
       return tltop->promise_on_stack_->promise();
     }
     handler = handler->next();
@@ -1347,11 +1507,6 @@
 }
 
 
-Handle<Context> Isolate::global_context() {
-  return handle(context()->global_object()->global_context());
-}
-
-
 Handle<Context> Isolate::GetCallingNativeContext() {
   JavaScriptFrameIterator it(this);
   if (debug_->in_debug_scope()) {
@@ -1464,9 +1619,8 @@
 #endif
 
 
-Isolate::Isolate()
+Isolate::Isolate(bool enable_serializer)
     : embedder_data_(),
-      state_(UNINITIALIZED),
       entry_stack_(NULL),
       stack_trace_nesting_level_(0),
       incomplete_message_(NULL),
@@ -1492,7 +1646,6 @@
       unicode_cache_(NULL),
       runtime_zone_(this),
       inner_pointer_to_code_cache_(NULL),
-      write_iterator_(NULL),
       global_handles_(NULL),
       eternal_handles_(NULL),
       thread_manager_(NULL),
@@ -1504,7 +1657,7 @@
       // TODO(bmeurer) Initialized lazily because it depends on flags; can
       // be fixed once the default isolate cleanup is done.
       random_number_generator_(NULL),
-      serializer_enabled_(false),
+      serializer_enabled_(enable_serializer),
       has_fatal_error_(false),
       initialized_from_snapshot_(false),
       cpu_profiler_(NULL),
@@ -1512,11 +1665,13 @@
       function_entry_hook_(NULL),
       deferred_handles_head_(NULL),
       optimizing_compiler_thread_(NULL),
-      sweeper_thread_(NULL),
-      num_sweeper_threads_(0),
       stress_deopt_count_(0),
       next_optimization_id_(0),
-      use_counter_callback_(NULL) {
+#if TRACE_MAPS
+      next_unique_sfi_id_(0),
+#endif
+      use_counter_callback_(NULL),
+      basic_block_profiler_(NULL) {
   {
     base::LockGuard<base::Mutex> lock_guard(thread_data_table_mutex_.Pointer());
     CHECK(thread_data_table_);
@@ -1594,63 +1749,52 @@
 
 
 void Isolate::Deinit() {
-  if (state_ == INITIALIZED) {
-    TRACE_ISOLATE(deinit);
+  TRACE_ISOLATE(deinit);
 
-    debug()->Unload();
+  debug()->Unload();
 
-    FreeThreadResources();
+  FreeThreadResources();
 
-    if (concurrent_recompilation_enabled()) {
-      optimizing_compiler_thread_->Stop();
-      delete optimizing_compiler_thread_;
-      optimizing_compiler_thread_ = NULL;
-    }
-
-    for (int i = 0; i < num_sweeper_threads_; i++) {
-      sweeper_thread_[i]->Stop();
-      delete sweeper_thread_[i];
-      sweeper_thread_[i] = NULL;
-    }
-    delete[] sweeper_thread_;
-    sweeper_thread_ = NULL;
-
-    if (FLAG_job_based_sweeping &&
-        heap_.mark_compact_collector()->sweeping_in_progress()) {
-      heap_.mark_compact_collector()->EnsureSweepingCompleted();
-    }
-
-    if (FLAG_turbo_stats) GetTStatistics()->Print("TurboFan");
-    if (FLAG_hydrogen_stats) GetHStatistics()->Print("Hydrogen");
-
-    if (FLAG_print_deopt_stress) {
-      PrintF(stdout, "=== Stress deopt counter: %u\n", stress_deopt_count_);
-    }
-
-    // We must stop the logger before we tear down other components.
-    Sampler* sampler = logger_->sampler();
-    if (sampler && sampler->IsActive()) sampler->Stop();
-
-    delete deoptimizer_data_;
-    deoptimizer_data_ = NULL;
-    builtins_.TearDown();
-    bootstrapper_->TearDown();
-
-    if (runtime_profiler_ != NULL) {
-      delete runtime_profiler_;
-      runtime_profiler_ = NULL;
-    }
-    heap_.TearDown();
-    logger_->TearDown();
-
-    delete heap_profiler_;
-    heap_profiler_ = NULL;
-    delete cpu_profiler_;
-    cpu_profiler_ = NULL;
-
-    // The default isolate is re-initializable due to legacy API.
-    state_ = UNINITIALIZED;
+  if (concurrent_recompilation_enabled()) {
+    optimizing_compiler_thread_->Stop();
+    delete optimizing_compiler_thread_;
+    optimizing_compiler_thread_ = NULL;
   }
+
+  if (heap_.mark_compact_collector()->sweeping_in_progress()) {
+    heap_.mark_compact_collector()->EnsureSweepingCompleted();
+  }
+
+  DumpAndResetCompilationStats();
+
+  if (FLAG_print_deopt_stress) {
+    PrintF(stdout, "=== Stress deopt counter: %u\n", stress_deopt_count_);
+  }
+
+  // We must stop the logger before we tear down other components.
+  Sampler* sampler = logger_->sampler();
+  if (sampler && sampler->IsActive()) sampler->Stop();
+
+  delete deoptimizer_data_;
+  deoptimizer_data_ = NULL;
+  builtins_.TearDown();
+  bootstrapper_->TearDown();
+
+  if (runtime_profiler_ != NULL) {
+    delete runtime_profiler_;
+    runtime_profiler_ = NULL;
+  }
+
+  delete basic_block_profiler_;
+  basic_block_profiler_ = NULL;
+
+  heap_.TearDown();
+  logger_->TearDown();
+
+  delete heap_profiler_;
+  heap_profiler_ = NULL;
+  delete cpu_profiler_;
+  cpu_profiler_ = NULL;
 }
 
 
@@ -1737,8 +1881,6 @@
   bootstrapper_ = NULL;
   delete inner_pointer_to_code_cache_;
   inner_pointer_to_code_cache_ = NULL;
-  delete write_iterator_;
-  write_iterator_ = NULL;
 
   delete thread_manager_;
   thread_manager_ = NULL;
@@ -1827,7 +1969,6 @@
 
 
 bool Isolate::Init(Deserializer* des) {
-  DCHECK(state_ != INITIALIZED);
   TRACE_ISOLATE(init);
 
   stress_deopt_count_ = FLAG_deopt_every_n_times;
@@ -1865,7 +2006,6 @@
   descriptor_lookup_cache_ = new DescriptorLookupCache();
   unicode_cache_ = new UnicodeCache();
   inner_pointer_to_code_cache_ = new InnerPointerToCodeCache(this);
-  write_iterator_ = new ConsStringIteratorOp();
   global_handles_ = new GlobalHandles(this);
   eternal_handles_ = new EternalHandles();
   bootstrapper_ = new Bootstrapper(this);
@@ -1927,9 +2067,7 @@
   builtins_.SetUp(this, create_heap_objects);
 
   if (FLAG_log_internal_timer_events) {
-    set_event_logger(Logger::DefaultTimerEventsLogger);
-  } else {
-    set_event_logger(Logger::EmptyTimerEventsLogger);
+    set_event_logger(Logger::DefaultEventLoggerSentinel);
   }
 
   // Set default value if not yet set.
@@ -1941,11 +2079,6 @@
         Max(Min(base::SysInfo::NumberOfProcessors(), 4), 1);
   }
 
-  if (!FLAG_job_based_sweeping) {
-    num_sweeper_threads_ =
-        SweeperThread::NumberOfThreads(max_available_threads_);
-  }
-
   if (FLAG_trace_hydrogen || FLAG_trace_hydrogen_stubs) {
     PrintF("Concurrent recompilation has been disabled for tracing.\n");
   } else if (OptimizingCompilerThread::Enabled(max_available_threads_)) {
@@ -1953,13 +2086,9 @@
     optimizing_compiler_thread_->Start();
   }
 
-  if (num_sweeper_threads_ > 0) {
-    sweeper_thread_ = new SweeperThread*[num_sweeper_threads_];
-    for (int i = 0; i < num_sweeper_threads_; i++) {
-      sweeper_thread_[i] = new SweeperThread(this);
-      sweeper_thread_[i]->Start();
-    }
-  }
+  // Initialize runtime profiler before deserialization, because collections may
+  // occur, clearing/updating ICs.
+  runtime_profiler_ = new RuntimeProfiler(this);
 
   // If we are deserializing, read the state into the now-empty heap.
   if (!create_heap_objects) {
@@ -1979,7 +2108,10 @@
   // Quiet the heap NaN if needed on target platform.
   if (!create_heap_objects) Assembler::QuietNaN(heap_.nan_value());
 
-  runtime_profiler_ = new RuntimeProfiler(this);
+  if (FLAG_trace_turbo) {
+    // Create an empty file.
+    std::ofstream(GetTurboCfgFileName().c_str(), std::ios_base::trunc);
+  }
 
   // If we are deserializing, log non-function code objects and compiled
   // functions found in the snapshot.
@@ -2006,9 +2138,10 @@
                heap_.amount_of_external_allocated_memory_at_last_global_gc_)),
            Internals::kAmountOfExternalAllocatedMemoryAtLastGlobalGCOffset);
 
-  state_ = INITIALIZED;
   time_millis_at_init_ = base::OS::TimeCurrentMillis();
 
+  heap_.NotifyDeserializationComplete();
+
   if (!create_heap_objects) {
     // Now that the heap is consistent, it's OK to generate the code for the
     // deopt entry table that might have been referred to by optimized code in
@@ -2031,6 +2164,8 @@
 
   initialized_from_snapshot_ = (des != NULL);
 
+  if (!FLAG_inline_new) heap_.DisableInlineAllocation();
+
   return true;
 }
 
@@ -2134,15 +2269,29 @@
 }
 
 
+void Isolate::DumpAndResetCompilationStats() {
+  if (turbo_statistics() != nullptr) {
+    OFStream os(stdout);
+    os << *turbo_statistics() << std::endl;
+  }
+  if (hstatistics() != nullptr) hstatistics()->Print();
+  delete turbo_statistics_;
+  turbo_statistics_ = nullptr;
+  delete hstatistics_;
+  hstatistics_ = nullptr;
+}
+
+
 HStatistics* Isolate::GetHStatistics() {
   if (hstatistics() == NULL) set_hstatistics(new HStatistics());
   return hstatistics();
 }
 
 
-HStatistics* Isolate::GetTStatistics() {
-  if (tstatistics() == NULL) set_tstatistics(new HStatistics());
-  return tstatistics();
+CompilationStatistics* Isolate::GetTurboStatistics() {
+  if (turbo_statistics() == NULL)
+    set_turbo_statistics(new CompilationStatistics());
+  return turbo_statistics();
 }
 
 
@@ -2227,18 +2376,18 @@
 
 
 Handle<JSObject> Isolate::GetSymbolRegistry() {
-  if (heap()->symbol_registry()->IsUndefined()) {
+  if (heap()->symbol_registry()->IsSmi()) {
     Handle<Map> map = factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
     Handle<JSObject> registry = factory()->NewJSObjectFromMap(map);
     heap()->set_symbol_registry(*registry);
 
-    static const char* nested[] = {
-      "for", "for_api", "for_intern", "keyFor", "private_api", "private_intern"
-    };
+    static const char* nested[] = {"for", "for_api", "keyFor", "private_api",
+                                   "private_intern"};
     for (unsigned i = 0; i < arraysize(nested); ++i) {
       Handle<String> name = factory()->InternalizeUtf8String(nested[i]);
       Handle<JSObject> obj = factory()->NewJSObjectFromMap(map);
-      JSObject::NormalizeProperties(obj, KEEP_INOBJECT_PROPERTIES, 8);
+      JSObject::NormalizeProperties(obj, KEEP_INOBJECT_PROPERTIES, 8,
+                                    "SetupSymbolRegistry");
       JSObject::SetProperty(registry, name, obj, STRICT).Assert();
     }
   }
@@ -2279,6 +2428,25 @@
 }
 
 
+void Isolate::SetPromiseRejectCallback(PromiseRejectCallback callback) {
+  promise_reject_callback_ = callback;
+}
+
+
+void Isolate::ReportPromiseReject(Handle<JSObject> promise,
+                                  Handle<Object> value,
+                                  v8::PromiseRejectEvent event) {
+  if (promise_reject_callback_ == NULL) return;
+  Handle<JSArray> stack_trace;
+  if (event == v8::kPromiseRejectWithNoHandler && value->IsJSObject()) {
+    stack_trace = GetDetailedStackTrace(Handle<JSObject>::cast(value));
+  }
+  promise_reject_callback_(v8::PromiseRejectMessage(
+      v8::Utils::PromiseToLocal(promise), event, v8::Utils::ToLocal(value),
+      v8::Utils::StackTraceToLocal(stack_trace)));
+}
+
+
 void Isolate::EnqueueMicrotask(Handle<Object> microtask) {
   DCHECK(microtask->IsJSFunction() || microtask->IsCallHandlerInfo());
   Handle<FixedArray> queue(heap()->microtask_queue(), this);
@@ -2363,6 +2531,25 @@
 }
 
 
+BasicBlockProfiler* Isolate::GetOrCreateBasicBlockProfiler() {
+  if (basic_block_profiler_ == NULL) {
+    basic_block_profiler_ = new BasicBlockProfiler();
+  }
+  return basic_block_profiler_;
+}
+
+
+std::string Isolate::GetTurboCfgFileName() {
+  if (FLAG_trace_turbo_cfg_file == NULL) {
+    std::ostringstream os;
+    os << "turbo-" << base::OS::GetCurrentProcessId() << "-" << id() << ".cfg";
+    return os.str();
+  } else {
+    return FLAG_trace_turbo_cfg_file;
+  }
+}
+
+
 bool StackLimitCheck::JsHasOverflowed() const {
   StackGuard* stack_guard = isolate_->stack_guard();
 #ifdef USE_SIMULATOR
diff --git a/src/isolate.h b/src/isolate.h
index 24d4b08..42a814a 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -5,6 +5,7 @@
 #ifndef V8_ISOLATE_H_
 #define V8_ISOLATE_H_
 
+#include <queue>
 #include "include/v8-debug.h"
 #include "src/allocation.h"
 #include "src/assert-scope.h"
@@ -20,7 +21,7 @@
 #include "src/heap/heap.h"
 #include "src/optimizing-compiler-thread.h"
 #include "src/regexp-stack.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 #include "src/runtime-profiler.h"
 #include "src/zone.h"
 
@@ -32,6 +33,7 @@
 
 namespace internal {
 
+class BasicBlockProfiler;
 class Bootstrapper;
 class CallInterfaceDescriptorData;
 class CodeGenerator;
@@ -39,7 +41,7 @@
 class CodeStubDescriptor;
 class CodeTracer;
 class CompilationCache;
-class ConsStringIteratorOp;
+class CompilationStatistics;
 class ContextSlotCache;
 class Counters;
 class CpuFeatures;
@@ -168,6 +170,7 @@
 #define FOR_EACH_ISOLATE_ADDRESS_NAME(C)                \
   C(Handler, handler)                                   \
   C(CEntryFP, c_entry_fp)                               \
+  C(CFunction, c_function)                              \
   C(Context, context)                                   \
   C(PendingException, pending_exception)                \
   C(ExternalCaughtException, external_caught_exception) \
@@ -178,7 +181,12 @@
 class ThreadId {
  public:
   // Creates an invalid ThreadId.
-  ThreadId() : id_(kInvalidId) {}
+  ThreadId() { base::NoBarrier_Store(&id_, kInvalidId); }
+
+  ThreadId& operator=(const ThreadId& other) {
+    base::NoBarrier_Store(&id_, base::NoBarrier_Load(&other.id_));
+    return *this;
+  }
 
   // Returns ThreadId for current thread.
   static ThreadId Current() { return ThreadId(GetCurrentThreadId()); }
@@ -188,17 +196,17 @@
 
   // Compares ThreadIds for equality.
   INLINE(bool Equals(const ThreadId& other) const) {
-    return id_ == other.id_;
+    return base::NoBarrier_Load(&id_) == base::NoBarrier_Load(&other.id_);
   }
 
   // Checks whether this ThreadId refers to any thread.
   INLINE(bool IsValid() const) {
-    return id_ != kInvalidId;
+    return base::NoBarrier_Load(&id_) != kInvalidId;
   }
 
   // Converts ThreadId to an integer representation
   // (required for public API: V8::V8::GetCurrentThreadId).
-  int ToInteger() const { return id_; }
+  int ToInteger() const { return static_cast<int>(base::NoBarrier_Load(&id_)); }
 
   // Converts ThreadId to an integer representation
   // (required for public API: V8::V8::TerminateExecution).
@@ -207,13 +215,13 @@
  private:
   static const int kInvalidId = -1;
 
-  explicit ThreadId(int id) : id_(id) {}
+  explicit ThreadId(int id) { base::NoBarrier_Store(&id_, id); }
 
   static int AllocateThreadId();
 
   static int GetCurrentThreadId();
 
-  int id_;
+  base::Atomic32 id_;
 
   static base::Atomic32 highest_thread_id_;
 
@@ -282,6 +290,7 @@
   // Stack.
   Address c_entry_fp_;  // the frame pointer of the top c entry frame
   Address handler_;   // try-blocks are chained through the stack
+  Address c_function_;  // C function that was called at c entry.
 
   // Throwing an exception may cause a Promise rejection.  For this purpose
   // we keep track of a stack of nested promises and the corresponding
@@ -376,14 +385,13 @@
   V(int, pending_microtask_count, 0)                                           \
   V(bool, autorun_microtasks, true)                                            \
   V(HStatistics*, hstatistics, NULL)                                           \
-  V(HStatistics*, tstatistics, NULL)                                           \
+  V(CompilationStatistics*, turbo_statistics, NULL)                            \
   V(HTracer*, htracer, NULL)                                                   \
   V(CodeTracer*, code_tracer, NULL)                                            \
   V(bool, fp_stubs_generated, false)                                           \
   V(int, max_available_threads, 0)                                             \
   V(uint32_t, per_isolate_assert_data, 0xFFFFFFFFu)                            \
-  V(InterruptCallback, api_interrupt_callback, NULL)                           \
-  V(void*, api_interrupt_callback_data, NULL)                                  \
+  V(PromiseRejectCallback, promise_reject_callback, NULL)                      \
   ISOLATE_INIT_SIMULATOR_LIST(V)
 
 #define THREAD_LOCAL_TOP_ACCESSOR(type, name)                        \
@@ -477,6 +485,7 @@
 
   // Returns the isolate inside which the current thread is running.
   INLINE(static Isolate* Current()) {
+    DCHECK(base::NoBarrier_Load(&isolate_key_created_) == 1);
     Isolate* isolate = reinterpret_cast<Isolate*>(
         base::Thread::GetExistingThreadLocal(isolate_key_));
     DCHECK(isolate != NULL);
@@ -484,6 +493,7 @@
   }
 
   INLINE(static Isolate* UncheckedCurrent()) {
+    DCHECK(base::NoBarrier_Load(&isolate_key_created_) == 1);
     return reinterpret_cast<Isolate*>(
         base::Thread::GetThreadLocal(isolate_key_));
   }
@@ -504,8 +514,6 @@
 
   bool Init(Deserializer* des);
 
-  bool IsInitialized() { return state_ == INITIALIZED; }
-
   // True if at least one thread Enter'ed this isolate.
   bool IsInUse() { return entry_stack_ != NULL; }
 
@@ -647,11 +655,15 @@
     return thread->c_entry_fp_;
   }
   static Address handler(ThreadLocalTop* thread) { return thread->handler_; }
+  Address c_function() { return thread_local_top_.c_function_; }
 
   inline Address* c_entry_fp_address() {
     return &thread_local_top_.c_entry_fp_;
   }
   inline Address* handler_address() { return &thread_local_top_.handler_; }
+  inline Address* c_function_address() {
+    return &thread_local_top_.c_function_;
+  }
 
   // Bottom JS entry.
   Address js_entry_sp() {
@@ -735,6 +747,9 @@
   void CaptureAndSetDetailedStackTrace(Handle<JSObject> error_object);
   void CaptureAndSetSimpleStackTrace(Handle<JSObject> error_object,
                                      Handle<Object> caller);
+  Handle<JSArray> GetDetailedStackTrace(Handle<JSObject> error_object);
+  Handle<JSArray> GetDetailedFromSimpleStackTrace(
+      Handle<JSObject> error_object);
 
   // Returns if the top context may access the given global object. If
   // the result is false, the pending exception is guaranteed to be
@@ -746,6 +761,8 @@
   bool MayIndexedAccess(Handle<JSObject> receiver,
                         uint32_t index,
                         v8::AccessType type);
+  bool IsInternallyUsedPropertyName(Handle<Object> name);
+  bool IsInternallyUsedPropertyName(Object* name);
 
   void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback);
   void ReportFailedAccessCheck(Handle<JSObject> receiver, v8::AccessType type);
@@ -787,13 +804,19 @@
   // Attempts to compute the current source location, storing the
   // result in the target out parameter.
   void ComputeLocation(MessageLocation* target);
+  bool ComputeLocationFromStackTrace(MessageLocation* target,
+                                     Handle<Object> exception);
+
+  Handle<JSMessageObject> CreateMessage(Handle<Object> exception,
+                                        MessageLocation* location);
 
   // Out of resource exception helpers.
   Object* StackOverflow();
   Object* TerminateExecution();
   void CancelTerminateExecution();
 
-  void InvokeApiInterruptCallback();
+  void RequestInterrupt(InterruptCallback callback, void* data);
+  void InvokeApiInterruptCallbacks();
 
   // Administration
   void Iterate(ObjectVisitor* v);
@@ -802,9 +825,8 @@
   void IterateThread(ThreadVisitor* v, char* t);
 
 
-  // Returns the current native and global context.
+  // Returns the current native context.
   Handle<Context> native_context();
-  Handle<Context> global_context();
 
   // Returns the native context of the calling JavaScript code.  That
   // is, the native context of the top-most JavaScript frame.
@@ -911,8 +933,6 @@
     return inner_pointer_to_code_cache_;
   }
 
-  ConsStringIteratorOp* write_iterator() { return write_iterator_; }
-
   GlobalHandles* global_handles() { return global_handles_; }
 
   EternalHandles* eternal_handles() { return eternal_handles_; }
@@ -929,18 +949,6 @@
     return &jsregexp_canonrange_;
   }
 
-  ConsStringIteratorOp* objects_string_compare_iterator_a() {
-    return &objects_string_compare_iterator_a_;
-  }
-
-  ConsStringIteratorOp* objects_string_compare_iterator_b() {
-    return &objects_string_compare_iterator_b_;
-  }
-
-  StaticResource<ConsStringIteratorOp>* objects_string_iterator() {
-    return &objects_string_iterator_;
-  }
-
   RuntimeState* runtime_state() { return &runtime_state_; }
 
   Builtins* builtins() { return &builtins_; }
@@ -997,12 +1005,6 @@
 
   THREAD_LOCAL_TOP_ACCESSOR(LookupResult*, top_lookup_result)
 
-  void enable_serializer() {
-    // The serializer can only be enabled before the isolate init.
-    DCHECK(state_ != INITIALIZED);
-    serializer_enabled_ = true;
-  }
-
   bool serializer_enabled() const { return serializer_enabled_; }
 
   bool IsDead() { return has_fatal_error_; }
@@ -1059,21 +1061,15 @@
     return optimizing_compiler_thread_;
   }
 
-  int num_sweeper_threads() const {
-    return num_sweeper_threads_;
-  }
-
-  SweeperThread** sweeper_threads() {
-    return sweeper_thread_;
-  }
-
   int id() const { return static_cast<int>(id_); }
 
   HStatistics* GetHStatistics();
-  HStatistics* GetTStatistics();
+  CompilationStatistics* GetTurboStatistics();
   HTracer* GetHTracer();
   CodeTracer* GetCodeTracer();
 
+  void DumpAndResetCompilationStats();
+
   FunctionEntryHook function_entry_hook() { return function_entry_hook_; }
   void set_function_entry_hook(FunctionEntryHook function_entry_hook) {
     function_entry_hook_ = function_entry_hook;
@@ -1101,31 +1097,38 @@
   void RemoveCallCompletedCallback(CallCompletedCallback callback);
   void FireCallCompletedCallback();
 
+  void SetPromiseRejectCallback(PromiseRejectCallback callback);
+  void ReportPromiseReject(Handle<JSObject> promise, Handle<Object> value,
+                           v8::PromiseRejectEvent event);
+
   void EnqueueMicrotask(Handle<Object> microtask);
   void RunMicrotasks();
 
   void SetUseCounterCallback(v8::Isolate::UseCounterCallback callback);
   void CountUsage(v8::Isolate::UseCounterFeature feature);
 
-  static Isolate* NewForTesting() { return new Isolate(); }
+  BasicBlockProfiler* GetOrCreateBasicBlockProfiler();
+  BasicBlockProfiler* basic_block_profiler() { return basic_block_profiler_; }
+
+  static Isolate* NewForTesting() { return new Isolate(false); }
+
+  std::string GetTurboCfgFileName();
+
+#if TRACE_MAPS
+  int GetNextUniqueSharedFunctionInfoId() { return next_unique_sfi_id_++; }
+#endif
 
  private:
-  Isolate();
+  explicit Isolate(bool enable_serializer);
 
   friend struct GlobalState;
   friend struct InitializeGlobalState;
 
-  enum State {
-    UNINITIALIZED,    // Some components may not have been allocated.
-    INITIALIZED       // All components are fully initialized.
-  };
-
   // These fields are accessed through the API, offsets must be kept in sync
   // with v8::internal::Internals (in include/v8.h) constants. This is also
   // verified in Isolate::Init() using runtime checks.
   void* embedder_data_[Internals::kNumIsolateDataSlots];
   Heap heap_;
-  State state_;  // Will be padded to kApiPointerSize.
 
   // The per-process lock should be acquired before the ThreadDataTable is
   // modified.
@@ -1178,6 +1181,10 @@
   // A global counter for all generated Isolates, might overflow.
   static base::Atomic32 isolate_counter_;
 
+#if DEBUG
+  static base::Atomic32 isolate_key_created_;
+#endif
+
   void Deinit();
 
   static void SetIsolateThreadLocals(Isolate* isolate,
@@ -1227,7 +1234,6 @@
   Counters* counters_;
   CodeRange* code_range_;
   base::RecursiveMutex break_access_;
-  base::Atomic32 debugger_initialized_;
   Logger* logger_;
   StackGuard stack_guard_;
   StatsTable* stats_table_;
@@ -1248,7 +1254,6 @@
   UnicodeCache* unicode_cache_;
   Zone runtime_zone_;
   InnerPointerToCodeCache* inner_pointer_to_code_cache_;
-  ConsStringIteratorOp* write_iterator_;
   GlobalHandles* global_handles_;
   EternalHandles* eternal_handles_;
   ThreadManager* thread_manager_;
@@ -1258,9 +1263,6 @@
   StringTracker* string_tracker_;
   unibrow::Mapping<unibrow::Ecma262UnCanonicalize> jsregexp_uncanonicalize_;
   unibrow::Mapping<unibrow::CanonicalizationRange> jsregexp_canonrange_;
-  ConsStringIteratorOp objects_string_compare_iterator_a_;
-  ConsStringIteratorOp objects_string_compare_iterator_b_;
-  StaticResource<ConsStringIteratorOp> objects_string_iterator_;
   unibrow::Mapping<unibrow::Ecma262Canonicalize>
       regexp_macro_assembler_canonicalize_;
   RegExpStack* regexp_stack_;
@@ -1292,6 +1294,9 @@
   HeapProfiler* heap_profiler_;
   FunctionEntryHook function_entry_hook_;
 
+  typedef std::pair<InterruptCallback, void*> InterruptEntry;
+  std::queue<InterruptEntry> api_interrupts_queue_;
+
 #define GLOBAL_BACKING_STORE(type, name, initialvalue)                         \
   type name##_;
   ISOLATE_INIT_LIST(GLOBAL_BACKING_STORE)
@@ -1315,18 +1320,21 @@
 
   DeferredHandles* deferred_handles_head_;
   OptimizingCompilerThread* optimizing_compiler_thread_;
-  SweeperThread** sweeper_thread_;
-  int num_sweeper_threads_;
 
   // Counts deopt points if deopt_every_n_times is enabled.
   unsigned int stress_deopt_count_;
 
   int next_optimization_id_;
 
+#if TRACE_MAPS
+  int next_unique_sfi_id_;
+#endif
+
   // List of callbacks when a Call completes.
   List<CallCompletedCallback> call_completed_callbacks_;
 
   v8::Isolate::UseCounterCallback use_counter_callback_;
+  BasicBlockProfiler* basic_block_profiler_;
 
   friend class ExecutionAccess;
   friend class HandleScopeImplementer;
diff --git a/src/json-parser.h b/src/json-parser.h
index 2993249..5ebbcdd 100644
--- a/src/json-parser.h
+++ b/src/json-parser.h
@@ -400,7 +400,8 @@
                            descriptor)->NowContains(value)) {
               Handle<HeapType> value_type(value->OptimalType(
                       isolate(), expected_representation));
-              Map::GeneralizeFieldType(target, descriptor, value_type);
+              Map::GeneralizeFieldType(target, descriptor,
+                                       expected_representation, value_type);
             }
             DCHECK(target->instance_descriptors()->GetFieldType(
                     descriptor)->NowContains(value));
diff --git a/src/json-stringifier.h b/src/json-stringifier.h
index f89a19f..393551d 100644
--- a/src/json-stringifier.h
+++ b/src/json-stringifier.h
@@ -8,6 +8,7 @@
 #include "src/v8.h"
 
 #include "src/conversions.h"
+#include "src/string-builder.h"
 #include "src/utils.h"
 
 namespace v8 {
@@ -24,42 +25,8 @@
       Handle<String> object));
 
  private:
-  static const int kInitialPartLength = 32;
-  static const int kMaxPartLength = 16 * 1024;
-  static const int kPartLengthGrowthFactor = 2;
-
   enum Result { UNCHANGED, SUCCESS, EXCEPTION };
 
-  void Accumulate();
-
-  void Extend();
-
-  void ChangeEncoding();
-
-  INLINE(void ShrinkCurrentPart());
-
-  template <bool is_one_byte, typename Char>
-  INLINE(void Append_(Char c));
-
-  template <bool is_one_byte, typename Char>
-  INLINE(void Append_(const Char* chars));
-
-  INLINE(void Append(uint8_t c)) {
-    if (is_one_byte_) {
-      Append_<true>(c);
-    } else {
-      Append_<false>(c);
-    }
-  }
-
-  INLINE(void AppendOneByte(const char* chars)) {
-    if (is_one_byte_) {
-      Append_<true>(reinterpret_cast<const uint8_t*>(chars));
-    } else {
-      Append_<false>(reinterpret_cast<const uint8_t*>(chars));
-    }
-  }
-
   MUST_USE_RESULT MaybeHandle<Object> ApplyToJsonFunction(
       Handle<Object> object,
       Handle<Object> key);
@@ -69,14 +36,9 @@
                           bool deferred_comma,
                           bool deferred_key);
 
-  template <typename ResultType, typename Char>
-  INLINE(static Handle<String> StringifyString_(Isolate* isolate,
-                                                Vector<Char> vector,
-                                                Handle<String> result));
-
   // Entry point to serialize the object.
   INLINE(Result SerializeObject(Handle<Object> obj)) {
-    return Serialize_<false>(obj, false, factory_->empty_string());
+    return Serialize_<false>(obj, false, factory()->empty_string());
   }
 
   // Serialize an array element.
@@ -103,9 +65,9 @@
   Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key);
 
   void SerializeDeferredKey(bool deferred_comma, Handle<Object> deferred_key) {
-    if (deferred_comma) Append(',');
+    if (deferred_comma) builder_.AppendCharacter(',');
     SerializeString(Handle<String>::cast(deferred_key));
-    Append(':');
+    builder_.AppendCharacter(':');
   }
 
   Result SerializeSmi(Smi* object);
@@ -125,42 +87,25 @@
   void SerializeString(Handle<String> object);
 
   template <typename SrcChar, typename DestChar>
-  INLINE(static int SerializeStringUnchecked_(const SrcChar* src,
-                                              DestChar* dest,
-                                              int length));
+  INLINE(static void SerializeStringUnchecked_(
+      Vector<const SrcChar> src,
+      IncrementalStringBuilder::NoExtend<DestChar>* dest));
 
-  template <bool is_one_byte, typename Char>
+  template <typename SrcChar, typename DestChar>
   INLINE(void SerializeString_(Handle<String> string));
 
   template <typename Char>
   INLINE(static bool DoNotEscape(Char c));
 
-  template <typename Char>
-  INLINE(static Vector<const Char> GetCharVector(Handle<String> string));
-
   Result StackPush(Handle<Object> object);
   void StackPop();
 
-  INLINE(Handle<String> accumulator()) {
-    return Handle<String>(String::cast(accumulator_store_->value()), isolate_);
-  }
-
-  INLINE(void set_accumulator(Handle<String> string)) {
-    return accumulator_store_->set_value(*string);
-  }
+  Factory* factory() { return isolate_->factory(); }
 
   Isolate* isolate_;
-  Factory* factory_;
-  // We use a value wrapper for the string accumulator to keep the
-  // (indirect) handle to it in the outermost handle scope.
-  Handle<JSValue> accumulator_store_;
-  Handle<String> current_part_;
+  IncrementalStringBuilder builder_;
   Handle<String> tojson_string_;
   Handle<JSArray> stack_;
-  int current_index_;
-  int part_length_;
-  bool is_one_byte_;
-  bool overflowed_;
 
   static const int kJsonEscapeTableEntrySize = 8;
   static const char* const JsonEscapeTable;
@@ -237,31 +182,16 @@
 
 
 BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
-    : isolate_(isolate),
-      current_index_(0),
-      is_one_byte_(true),
-      overflowed_(false) {
-  factory_ = isolate_->factory();
-  accumulator_store_ = Handle<JSValue>::cast(
-      Object::ToObject(isolate, factory_->empty_string()).ToHandleChecked());
-  part_length_ = kInitialPartLength;
-  current_part_ = factory_->NewRawOneByteString(part_length_).ToHandleChecked();
-  tojson_string_ = factory_->toJSON_string();
-  stack_ = factory_->NewJSArray(8);
+    : isolate_(isolate), builder_(isolate) {
+  tojson_string_ = factory()->toJSON_string();
+  stack_ = factory()->NewJSArray(8);
 }
 
 
 MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object) {
   Result result = SerializeObject(object);
-  if (result == UNCHANGED) return isolate_->factory()->undefined_value();
-  if (result == SUCCESS) {
-    ShrinkCurrentPart();
-    Accumulate();
-    if (overflowed_) {
-      THROW_NEW_ERROR(isolate_, NewInvalidStringLengthError(), Object);
-    }
-    return accumulator();
-  }
+  if (result == UNCHANGED) return factory()->undefined_value();
+  if (result == SUCCESS) return builder_.Finish();
   DCHECK(result == EXCEPTION);
   return MaybeHandle<Object>();
 }
@@ -281,58 +211,29 @@
 
   object = String::Flatten(object);
   DCHECK(object->IsFlat());
+  Handle<SeqString> result;
   if (object->IsOneByteRepresentationUnderneath()) {
-    Handle<String> result = isolate->factory()->NewRawOneByteString(
-        worst_case_length).ToHandleChecked();
-    DisallowHeapAllocation no_gc;
-    return StringifyString_<SeqOneByteString>(
-        isolate,
-        object->GetFlatContent().ToOneByteVector(),
-        result);
+    result = isolate->factory()
+                 ->NewRawOneByteString(worst_case_length)
+                 .ToHandleChecked();
+    IncrementalStringBuilder::NoExtendString<uint8_t> no_extend(
+        result, worst_case_length);
+    no_extend.Append('\"');
+    SerializeStringUnchecked_(object->GetFlatContent().ToOneByteVector(),
+                              &no_extend);
+    no_extend.Append('\"');
   } else {
-    Handle<String> result = isolate->factory()->NewRawTwoByteString(
-        worst_case_length).ToHandleChecked();
-    DisallowHeapAllocation no_gc;
-    return StringifyString_<SeqTwoByteString>(
-        isolate,
-        object->GetFlatContent().ToUC16Vector(),
-        result);
+    result = isolate->factory()
+                 ->NewRawTwoByteString(worst_case_length)
+                 .ToHandleChecked();
+    IncrementalStringBuilder::NoExtendString<uc16> no_extend(result,
+                                                             worst_case_length);
+    no_extend.Append('\"');
+    SerializeStringUnchecked_(object->GetFlatContent().ToUC16Vector(),
+                              &no_extend);
+    no_extend.Append('\"');
   }
-}
-
-
-template <typename ResultType, typename Char>
-Handle<String> BasicJsonStringifier::StringifyString_(Isolate* isolate,
-                                                      Vector<Char> vector,
-                                                      Handle<String> result) {
-  DisallowHeapAllocation no_gc;
-  int final_size = 0;
-  ResultType* dest = ResultType::cast(*result);
-  dest->Set(final_size++, '\"');
-  final_size += SerializeStringUnchecked_(vector.start(),
-                                          dest->GetChars() + 1,
-                                          vector.length());
-  dest->Set(final_size++, '\"');
-  return SeqString::Truncate(Handle<SeqString>::cast(result), final_size);
-}
-
-
-template <bool is_one_byte, typename Char>
-void BasicJsonStringifier::Append_(Char c) {
-  if (is_one_byte) {
-    SeqOneByteString::cast(*current_part_)->SeqOneByteStringSet(
-        current_index_++, c);
-  } else {
-    SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet(
-        current_index_++, c);
-  }
-  if (current_index_ == part_length_) Extend();
-}
-
-
-template <bool is_one_byte, typename Char>
-void BasicJsonStringifier::Append_(const Char* chars) {
-  for (; *chars != '\0'; chars++) Append_<is_one_byte, Char>(*chars);
+  return result;
 }
 
 
@@ -345,7 +246,7 @@
   if (!fun->IsJSFunction()) return object;
 
   // Call toJSON function.
-  if (key->IsSmi()) key = factory_->NumberToString(key);
+  if (key->IsSmi()) key = factory()->NumberToString(key);
   Handle<Object> argv[] = { key };
   HandleScope scope(isolate_);
   ASSIGN_RETURN_ON_EXCEPTION(
@@ -372,7 +273,7 @@
       if (elements->get(i) == *object) {
         AllowHeapAllocation allow_to_return_error;
         Handle<Object> error;
-        MaybeHandle<Object> maybe_error = factory_->NewTypeError(
+        MaybeHandle<Object> maybe_error = factory()->NewTypeError(
             "circular_structure", HandleVector<Object>(NULL, 0));
         if (maybe_error.ToHandle(&error)) isolate_->Throw(*error);
         return EXCEPTION;
@@ -416,15 +317,15 @@
       switch (Oddball::cast(*object)->kind()) {
         case Oddball::kFalse:
           if (deferred_string_key) SerializeDeferredKey(comma, key);
-          AppendOneByte("false");
+          builder_.AppendCString("false");
           return SUCCESS;
         case Oddball::kTrue:
           if (deferred_string_key) SerializeDeferredKey(comma, key);
-          AppendOneByte("true");
+          builder_.AppendCString("true");
           return SUCCESS;
         case Oddball::kNull:
           if (deferred_string_key) SerializeDeferredKey(comma, key);
-          AppendOneByte("null");
+          builder_.AppendCString("null");
           return SUCCESS;
         default:
           return UNCHANGED;
@@ -472,23 +373,11 @@
       EXCEPTION);
   if (result->IsUndefined()) return UNCHANGED;
   if (deferred_key) {
-    if (key->IsSmi()) key = factory_->NumberToString(key);
+    if (key->IsSmi()) key = factory()->NumberToString(key);
     SerializeDeferredKey(deferred_comma, key);
   }
 
-  Handle<String> result_string = Handle<String>::cast(result);
-  // Shrink current part, attach it to the accumulator, also attach the result
-  // string to the accumulator, and allocate a new part.
-  ShrinkCurrentPart();  // Shrink.
-  part_length_ = kInitialPartLength;  // Allocate conservatively.
-  Extend();             // Attach current part and allocate new part.
-  // Attach result string to the accumulator.
-  Handle<String> cons;
-  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-      isolate_, cons,
-      factory_->NewConsString(accumulator(), result_string),
-      EXCEPTION);
-  set_accumulator(cons);
+  builder_.AppendString(Handle<String>::cast(result));
   return SUCCESS;
 }
 
@@ -511,7 +400,7 @@
     DCHECK(class_name == isolate_->heap()->Boolean_string());
     Object* value = JSValue::cast(*object)->value();
     DCHECK(value->IsBoolean());
-    AppendOneByte(value->IsTrue() ? "true" : "false");
+    builder_.AppendCString(value->IsTrue() ? "true" : "false");
   }
   return SUCCESS;
 }
@@ -521,7 +410,7 @@
   static const int kBufferSize = 100;
   char chars[kBufferSize];
   Vector<char> buffer(chars, kBufferSize);
-  AppendOneByte(IntToCString(object->value(), buffer));
+  builder_.AppendCString(IntToCString(object->value(), buffer));
   return SUCCESS;
 }
 
@@ -529,13 +418,13 @@
 BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble(
     double number) {
   if (std::isinf(number) || std::isnan(number)) {
-    AppendOneByte("null");
+    builder_.AppendCString("null");
     return SUCCESS;
   }
   static const int kBufferSize = 100;
   char chars[kBufferSize];
   Vector<char> buffer(chars, kBufferSize);
-  AppendOneByte(DoubleToCString(number, buffer));
+  builder_.AppendCString(DoubleToCString(number, buffer));
   return SUCCESS;
 }
 
@@ -547,13 +436,13 @@
   if (stack_push != SUCCESS) return stack_push;
   uint32_t length = 0;
   CHECK(object->length()->ToArrayIndex(&length));
-  Append('[');
+  builder_.AppendCharacter('[');
   switch (object->GetElementsKind()) {
     case FAST_SMI_ELEMENTS: {
       Handle<FixedArray> elements(
           FixedArray::cast(object->elements()), isolate_);
       for (uint32_t i = 0; i < length; i++) {
-        if (i > 0) Append(',');
+        if (i > 0) builder_.AppendCharacter(',');
         SerializeSmi(Smi::cast(elements->get(i)));
       }
       break;
@@ -564,7 +453,7 @@
       Handle<FixedDoubleArray> elements(
           FixedDoubleArray::cast(object->elements()), isolate_);
       for (uint32_t i = 0; i < length; i++) {
-        if (i > 0) Append(',');
+        if (i > 0) builder_.AppendCharacter(',');
         SerializeDouble(elements->get_scalar(i));
       }
       break;
@@ -573,14 +462,14 @@
       Handle<FixedArray> elements(
           FixedArray::cast(object->elements()), isolate_);
       for (uint32_t i = 0; i < length; i++) {
-        if (i > 0) Append(',');
+        if (i > 0) builder_.AppendCharacter(',');
         Result result =
             SerializeElement(isolate_,
                              Handle<Object>(elements->get(i), isolate_),
                              i);
         if (result == SUCCESS) continue;
         if (result == UNCHANGED) {
-          AppendOneByte("null");
+          builder_.AppendCString("null");
         } else {
           return result;
         }
@@ -596,9 +485,8 @@
       break;
     }
   }
-  Append(']');
+  builder_.AppendCharacter(']');
   StackPop();
-  current_part_ = handle_scope.CloseAndEscape(current_part_);
   return SUCCESS;
 }
 
@@ -606,19 +494,19 @@
 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow(
     Handle<JSArray> object, uint32_t length) {
   for (uint32_t i = 0; i < length; i++) {
-    if (i > 0) Append(',');
+    if (i > 0) builder_.AppendCharacter(',');
     Handle<Object> element;
     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
         isolate_, element,
         Object::GetElement(isolate_, object, i),
         EXCEPTION);
     if (element->IsUndefined()) {
-      AppendOneByte("null");
+      builder_.AppendCString("null");
     } else {
       Result result = SerializeElement(isolate_, element, i);
       if (result == SUCCESS) continue;
       if (result == UNCHANGED) {
-        AppendOneByte("null");
+        builder_.AppendCString("null");
       } else {
         return result;
       }
@@ -635,7 +523,7 @@
   if (stack_push != SUCCESS) return stack_push;
   DCHECK(!object->IsJSGlobalProxy() && !object->IsGlobalObject());
 
-  Append('{');
+  builder_.AppendCharacter('{');
   bool comma = false;
 
   if (object->HasFastProperties() &&
@@ -652,8 +540,15 @@
       if (details.IsDontEnum()) continue;
       Handle<Object> property;
       if (details.type() == FIELD && *map == object->map()) {
-        property = Handle<Object>(object->RawFastPropertyAt(
-            FieldIndex::ForDescriptor(*map, i)), isolate_);
+        FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
+        Isolate* isolate = object->GetIsolate();
+        if (object->IsUnboxedDoubleField(field_index)) {
+          double value = object->RawFastDoublePropertyAt(field_index);
+          property = isolate->factory()->NewHeapNumber(value);
+
+        } else {
+          property = handle(object->RawFastPropertyAt(field_index), isolate);
+        }
       } else {
         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
             isolate_, property,
@@ -680,7 +575,7 @@
         maybe_property = Object::GetPropertyOrElement(object, key_handle);
       } else {
         DCHECK(key->IsNumber());
-        key_handle = factory_->NumberToString(Handle<Object>(key, isolate_));
+        key_handle = factory()->NumberToString(Handle<Object>(key, isolate_));
         uint32_t index;
         if (key->IsSmi()) {
           maybe_property = Object::GetElement(
@@ -700,130 +595,59 @@
     }
   }
 
-  Append('}');
+  builder_.AppendCharacter('}');
   StackPop();
-  current_part_ = handle_scope.CloseAndEscape(current_part_);
   return SUCCESS;
 }
 
 
-void BasicJsonStringifier::ShrinkCurrentPart() {
-  DCHECK(current_index_ < part_length_);
-  current_part_ = SeqString::Truncate(Handle<SeqString>::cast(current_part_),
-                                      current_index_);
-}
+template <typename SrcChar, typename DestChar>
+void BasicJsonStringifier::SerializeStringUnchecked_(
+    Vector<const SrcChar> src,
+    IncrementalStringBuilder::NoExtend<DestChar>* dest) {
+  // Assert that uc16 character is not truncated down to 8 bit.
+  // The <uc16, char> version of this method must not be called.
+  DCHECK(sizeof(DestChar) >= sizeof(SrcChar));
 
-
-void BasicJsonStringifier::Accumulate() {
-  if (accumulator()->length() + current_part_->length() > String::kMaxLength) {
-    // Screw it.  Simply set the flag and carry on.  Throw exception at the end.
-    set_accumulator(factory_->empty_string());
-    overflowed_ = true;
-  } else {
-    set_accumulator(factory_->NewConsString(accumulator(),
-                                            current_part_).ToHandleChecked());
+  for (int i = 0; i < src.length(); i++) {
+    SrcChar c = src[i];
+    if (DoNotEscape(c)) {
+      dest->Append(c);
+    } else {
+      dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
+    }
   }
 }
 
 
-void BasicJsonStringifier::Extend() {
-  Accumulate();
-  if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) {
-    part_length_ *= kPartLengthGrowthFactor;
-  }
-  if (is_one_byte_) {
-    current_part_ =
-        factory_->NewRawOneByteString(part_length_).ToHandleChecked();
-  } else {
-    current_part_ =
-        factory_->NewRawTwoByteString(part_length_).ToHandleChecked();
-  }
-  DCHECK(!current_part_.is_null());
-  current_index_ = 0;
-}
-
-
-void BasicJsonStringifier::ChangeEncoding() {
-  ShrinkCurrentPart();
-  Accumulate();
-  current_part_ =
-      factory_->NewRawTwoByteString(part_length_).ToHandleChecked();
-  DCHECK(!current_part_.is_null());
-  current_index_ = 0;
-  is_one_byte_ = false;
-}
-
-
 template <typename SrcChar, typename DestChar>
-int BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src,
-                                                    DestChar* dest,
-                                                    int length) {
-  DestChar* dest_start = dest;
-
-  // Assert that uc16 character is not truncated down to 8 bit.
-  // The <uc16, char> version of this method must not be called.
-  DCHECK(sizeof(*dest) >= sizeof(*src));
-
-  for (int i = 0; i < length; i++) {
-    SrcChar c = src[i];
-    if (DoNotEscape(c)) {
-      *(dest++) = static_cast<DestChar>(c);
-    } else {
-      const uint8_t* chars = reinterpret_cast<const uint8_t*>(
-          &JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
-      while (*chars != '\0') *(dest++) = *(chars++);
-    }
-  }
-
-  return static_cast<int>(dest - dest_start);
-}
-
-
-template <bool is_one_byte, typename Char>
 void BasicJsonStringifier::SerializeString_(Handle<String> string) {
   int length = string->length();
-  Append_<is_one_byte, char>('"');
+  builder_.Append<uint8_t, DestChar>('"');
   // We make a rough estimate to find out if the current string can be
   // serialized without allocating a new string part. The worst case length of
   // an escaped character is 6.  Shifting the remainin string length right by 3
   // is a more pessimistic estimate, but faster to calculate.
-
-  if (((part_length_ - current_index_) >> 3) > length) {
+  int worst_case_length = length << 3;
+  if (builder_.CurrentPartCanFit(worst_case_length)) {
     DisallowHeapAllocation no_gc;
-    Vector<const Char> vector = GetCharVector<Char>(string);
-    if (is_one_byte) {
-      current_index_ += SerializeStringUnchecked_(
-          vector.start(),
-          SeqOneByteString::cast(*current_part_)->GetChars() + current_index_,
-          length);
-    } else {
-      current_index_ += SerializeStringUnchecked_(
-          vector.start(),
-          SeqTwoByteString::cast(*current_part_)->GetChars() + current_index_,
-          length);
-    }
+    Vector<const SrcChar> vector = string->GetCharVector<SrcChar>();
+    IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend(
+        &builder_, worst_case_length);
+    SerializeStringUnchecked_(vector, &no_extend);
   } else {
-    String* string_location = NULL;
-    Vector<const Char> vector(NULL, 0);
-    for (int i = 0; i < length; i++) {
-      // If GC moved the string, we need to refresh the vector.
-      if (*string != string_location) {
-        DisallowHeapAllocation no_gc;
-        // This does not actually prevent the string from being relocated later.
-        vector = GetCharVector<Char>(string);
-        string_location = *string;
-      }
-      Char c = vector[i];
+    FlatStringReader reader(isolate_, string);
+    for (int i = 0; i < reader.length(); i++) {
+      SrcChar c = reader.Get<SrcChar>(i);
       if (DoNotEscape(c)) {
-        Append_<is_one_byte, Char>(c);
+        builder_.Append<SrcChar, DestChar>(c);
       } else {
-        Append_<is_one_byte, uint8_t>(reinterpret_cast<const uint8_t*>(
-            &JsonEscapeTable[c * kJsonEscapeTableEntrySize]));
+        builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
       }
     }
   }
 
-  Append_<is_one_byte, uint8_t>('"');
+  builder_.Append<uint8_t, DestChar>('"');
 }
 
 
@@ -839,37 +663,20 @@
 }
 
 
-template <>
-Vector<const uint8_t> BasicJsonStringifier::GetCharVector(
-    Handle<String> string) {
-  String::FlatContent flat = string->GetFlatContent();
-  DCHECK(flat.IsOneByte());
-  return flat.ToOneByteVector();
-}
-
-
-template <>
-Vector<const uc16> BasicJsonStringifier::GetCharVector(Handle<String> string) {
-  String::FlatContent flat = string->GetFlatContent();
-  DCHECK(flat.IsTwoByte());
-  return flat.ToUC16Vector();
-}
-
-
 void BasicJsonStringifier::SerializeString(Handle<String> object) {
   object = String::Flatten(object);
-  if (is_one_byte_) {
+  if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) {
     if (object->IsOneByteRepresentationUnderneath()) {
-      SerializeString_<true, uint8_t>(object);
+      SerializeString_<uint8_t, uint8_t>(object);
     } else {
-      ChangeEncoding();
+      builder_.ChangeEncoding();
       SerializeString(object);
     }
   } else {
     if (object->IsOneByteRepresentationUnderneath()) {
-      SerializeString_<false, uint8_t>(object);
+      SerializeString_<uint8_t, uc16>(object);
     } else {
-      SerializeString_<false, uc16>(object);
+      SerializeString_<uc16, uc16>(object);
     }
   }
 }
diff --git a/src/json.js b/src/json.js
index f767f4a..e2b7dc8 100644
--- a/src/json.js
+++ b/src/json.js
@@ -220,6 +220,8 @@
 function SetUpJSON() {
   %CheckIsBootstrapping();
 
+  %AddNamedProperty($JSON, symbolToStringTag, "JSON", READ_ONLY | DONT_ENUM);
+
   // Set up non-enumerable properties of the JSON object.
   InstallFunctions($JSON, DONT_ENUM, $Array(
     "parse", JSONParse,
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 98aca72..81ad080 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -18,8 +18,9 @@
 #include "src/regexp-macro-assembler-irregexp.h"
 #include "src/regexp-macro-assembler-tracer.h"
 #include "src/regexp-stack.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 #include "src/string-search.h"
+#include "src/unicode-decoder.h"
 
 #ifndef V8_INTERPRETED_REGEXP
 #if V8_TARGET_ARCH_IA32
@@ -57,28 +58,6 @@
 }
 
 
-static JSRegExp::Flags RegExpFlagsFromString(Handle<String> str) {
-  int flags = JSRegExp::NONE;
-  for (int i = 0; i < str->length(); i++) {
-    switch (str->Get(i)) {
-      case 'i':
-        flags |= JSRegExp::IGNORE_CASE;
-        break;
-      case 'g':
-        flags |= JSRegExp::GLOBAL;
-        break;
-      case 'm':
-        flags |= JSRegExp::MULTILINE;
-        break;
-      case 'y':
-        if (FLAG_harmony_regexps) flags |= JSRegExp::STICKY;
-        break;
-    }
-  }
-  return JSRegExp::Flags(flags);
-}
-
-
 MUST_USE_RESULT
 static inline MaybeHandle<Object> ThrowRegExpException(
     Handle<JSRegExp> re,
@@ -155,10 +134,9 @@
 
 MaybeHandle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
                                         Handle<String> pattern,
-                                        Handle<String> flag_str) {
+                                        JSRegExp::Flags flags) {
   Isolate* isolate = re->GetIsolate();
   Zone zone(isolate);
-  JSRegExp::Flags flags = RegExpFlagsFromString(flag_str);
   CompilationCache* compilation_cache = isolate->compilation_cache();
   MaybeHandle<FixedArray> maybe_cached =
       compilation_cache->LookupRegExp(pattern, flags);
@@ -1026,6 +1004,8 @@
 
   inline bool ignore_case() { return ignore_case_; }
   inline bool one_byte() { return one_byte_; }
+  inline bool optimize() { return optimize_; }
+  inline void set_optimize(bool value) { optimize_ = value; }
   FrequencyCollator* frequency_collator() { return &frequency_collator_; }
 
   int current_expansion_factor() { return current_expansion_factor_; }
@@ -1046,6 +1026,7 @@
   bool ignore_case_;
   bool one_byte_;
   bool reg_exp_too_big_;
+  bool optimize_;
   int current_expansion_factor_;
   FrequencyCollator frequency_collator_;
   Zone* zone_;
@@ -1078,6 +1059,7 @@
       ignore_case_(ignore_case),
       one_byte_(one_byte),
       reg_exp_too_big_(false),
+      optimize_(FLAG_regexp_optimization),
       current_expansion_factor_(1),
       frequency_collator_(),
       zone_(zone) {
@@ -1093,16 +1075,6 @@
     Handle<String> pattern) {
   Heap* heap = pattern->GetHeap();
 
-  bool use_slow_safe_regexp_compiler = false;
-  if (heap->total_regexp_code_generated() >
-          RegExpImpl::kRegWxpCompiledLimit &&
-      heap->isolate()->memory_allocator()->SizeExecutable() >
-          RegExpImpl::kRegExpExecutableMemoryLimit) {
-    use_slow_safe_regexp_compiler = true;
-  }
-
-  macro_assembler->set_slow_safe(use_slow_safe_regexp_compiler);
-
 #ifdef DEBUG
   if (FLAG_trace_regexp_assembler)
     macro_assembler_ = new RegExpMacroAssemblerTracer(macro_assembler);
@@ -1126,12 +1098,14 @@
   Handle<HeapObject> code = macro_assembler_->GetCode(pattern);
   heap->IncreaseTotalRegexpCodeGenerated(code->Size());
   work_list_ = NULL;
-#ifdef DEBUG
+#ifdef ENABLE_DISASSEMBLER
   if (FLAG_print_code) {
     CodeTracer::Scope trace_scope(heap->isolate()->GetCodeTracer());
     OFStream os(trace_scope.file());
     Handle<Code>::cast(code)->Disassemble(pattern->ToCString().get(), os);
   }
+#endif
+#ifdef DEBUG
   if (FLAG_trace_regexp_assembler) {
     delete macro_assembler_;
   }
@@ -2256,8 +2230,7 @@
   // We are being asked to make a non-generic version.  Keep track of how many
   // non-generic versions we generate so as not to overdo it.
   trace_count_++;
-  if (FLAG_regexp_optimization &&
-      trace_count_ < kMaxCopiesCodeGenerated &&
+  if (compiler->optimize() && trace_count_ < kMaxCopiesCodeGenerated &&
       compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) {
     return CONTINUE;
   }
@@ -4136,15 +4109,12 @@
     }
     alt_gen->expects_preload = preload->preload_is_current_;
     bool generate_full_check_inline = false;
-    if (FLAG_regexp_optimization &&
+    if (compiler->optimize() &&
         try_to_emit_quick_check_for_alternative(i == 0) &&
-        alternative.node()->EmitQuickCheck(compiler,
-                                           trace,
-                                           &new_trace,
-                                           preload->preload_has_checked_bounds_,
-                                           &alt_gen->possible_success,
-                                           &alt_gen->quick_check_details,
-                                           fall_through_on_failure)) {
+        alternative.node()->EmitQuickCheck(
+            compiler, trace, &new_trace, preload->preload_has_checked_bounds_,
+            &alt_gen->possible_success, &alt_gen->quick_check_details,
+            fall_through_on_failure)) {
       // Quick check was generated for this choice.
       preload->preload_is_current_ = true;
       preload->preload_has_checked_bounds_ = true;
@@ -4386,7 +4356,7 @@
 
 class DotPrinter: public NodeVisitor {
  public:
-  DotPrinter(OStream& os, bool ignore_case)  // NOLINT
+  DotPrinter(std::ostream& os, bool ignore_case)  // NOLINT
       : os_(os),
         ignore_case_(ignore_case) {}
   void PrintNode(const char* label, RegExpNode* node);
@@ -4398,7 +4368,7 @@
 FOR_EACH_NODE_TYPE(DECLARE_VISIT)
 #undef DECLARE_VISIT
  private:
-  OStream& os_;
+  std::ostream& os_;
   bool ignore_case_;
 };
 
@@ -4420,7 +4390,7 @@
   }
   os_ << "\"];\n";
   Visit(node);
-  os_ << "}" << endl;
+  os_ << "}" << std::endl;
 }
 
 
@@ -4439,7 +4409,7 @@
 
 class TableEntryBodyPrinter {
  public:
-  TableEntryBodyPrinter(OStream& os, ChoiceNode* choice)  // NOLINT
+  TableEntryBodyPrinter(std::ostream& os, ChoiceNode* choice)  // NOLINT
       : os_(os),
         choice_(choice) {}
   void Call(uc16 from, DispatchTable::Entry entry) {
@@ -4453,14 +4423,14 @@
   }
  private:
   ChoiceNode* choice() { return choice_; }
-  OStream& os_;
+  std::ostream& os_;
   ChoiceNode* choice_;
 };
 
 
 class TableEntryHeaderPrinter {
  public:
-  explicit TableEntryHeaderPrinter(OStream& os)  // NOLINT
+  explicit TableEntryHeaderPrinter(std::ostream& os)  // NOLINT
       : first_(true),
         os_(os) {}
   void Call(uc16 from, DispatchTable::Entry entry) {
@@ -4484,13 +4454,13 @@
 
  private:
   bool first_;
-  OStream& os_;
+  std::ostream& os_;
 };
 
 
 class AttributePrinter {
  public:
-  explicit AttributePrinter(OStream& os)  // NOLINT
+  explicit AttributePrinter(std::ostream& os)  // NOLINT
       : os_(os),
         first_(true) {}
   void PrintSeparator() {
@@ -4512,7 +4482,7 @@
   }
 
  private:
-  OStream& os_;
+  std::ostream& os_;
   bool first_;
 };
 
@@ -4681,10 +4651,10 @@
 
 class DispatchTableDumper {
  public:
-  explicit DispatchTableDumper(OStream& os) : os_(os) {}
+  explicit DispatchTableDumper(std::ostream& os) : os_(os) {}
   void Call(uc16 key, DispatchTable::Entry entry);
  private:
-  OStream& os_;
+  std::ostream& os_;
 };
 
 
@@ -4942,7 +4912,7 @@
 
   if (body_can_be_empty) {
     body_start_reg = compiler->AllocateRegister();
-  } else if (FLAG_regexp_optimization && !needs_capture_clearing) {
+  } else if (compiler->optimize() && !needs_capture_clearing) {
     // Only unroll if there are no captures and the body can't be
     // empty.
     {
@@ -6040,6 +6010,8 @@
   }
   RegExpCompiler compiler(data->capture_count, ignore_case, is_one_byte, zone);
 
+  compiler.set_optimize(!TooMuchRegExpCode(pattern));
+
   // Sample some characters from the middle of the string.
   static const int kSampleSize = 128;
 
@@ -6142,6 +6114,8 @@
   RegExpMacroAssemblerIrregexp macro_assembler(codes, zone);
 #endif  // V8_INTERPRETED_REGEXP
 
+  macro_assembler.set_slow_safe(TooMuchRegExpCode(pattern));
+
   // Inserted here, instead of in Assembler, because it depends on information
   // in the AST that isn't replicated in the Node structure.
   static const int kMaxBacksearchLimit = 1024;
@@ -6165,4 +6139,14 @@
 }
 
 
+bool RegExpEngine::TooMuchRegExpCode(Handle<String> pattern) {
+  Heap* heap = pattern->GetHeap();
+  bool too_much = pattern->length() > RegExpImpl::kRegExpTooLargeToOptimize;
+  if (heap->total_regexp_code_generated() > RegExpImpl::kRegExpCompiledLimit &&
+      heap->isolate()->memory_allocator()->SizeExecutable() >
+          RegExpImpl::kRegExpExecutableMemoryLimit) {
+    too_much = true;
+  }
+  return too_much;
+}
 }}  // namespace v8::internal
diff --git a/src/jsregexp.h b/src/jsregexp.h
index c65adea..4b84c95 100644
--- a/src/jsregexp.h
+++ b/src/jsregexp.h
@@ -46,10 +46,9 @@
   // generic data and choice of implementation - as well as what
   // the implementation wants to store in the data field.
   // Returns false if compilation fails.
-  MUST_USE_RESULT static MaybeHandle<Object> Compile(
-      Handle<JSRegExp> re,
-      Handle<String> pattern,
-      Handle<String> flags);
+  MUST_USE_RESULT static MaybeHandle<Object> Compile(Handle<JSRegExp> re,
+                                                     Handle<String> pattern,
+                                                     JSRegExp::Flags flags);
 
   // See ECMA-262 section 15.10.6.2.
   // This function calls the garbage collector if necessary.
@@ -213,7 +212,8 @@
   // total regexp code compiled including code that has subsequently been freed
   // and the total executable memory at any point.
   static const int kRegExpExecutableMemoryLimit = 16 * MB;
-  static const int kRegWxpCompiledLimit = 1 * MB;
+  static const int kRegExpCompiledLimit = 1 * MB;
+  static const int kRegExpTooLargeToOptimize = 10 * KB;
 
  private:
   static bool CompileIrregexp(Handle<JSRegExp> re,
@@ -1666,6 +1666,8 @@
                                    Handle<String> sample_subject,
                                    bool is_one_byte, Zone* zone);
 
+  static bool TooMuchRegExpCode(Handle<String> pattern);
+
   static void DotPrint(const char* label, RegExpNode* node, bool ignore_case);
 };
 
diff --git a/src/layout-descriptor-inl.h b/src/layout-descriptor-inl.h
new file mode 100644
index 0000000..3352312
--- /dev/null
+++ b/src/layout-descriptor-inl.h
@@ -0,0 +1,191 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_LAYOUT_DESCRIPTOR_INL_H_
+#define V8_LAYOUT_DESCRIPTOR_INL_H_
+
+#include "src/layout-descriptor.h"
+
+namespace v8 {
+namespace internal {
+
+LayoutDescriptor* LayoutDescriptor::FromSmi(Smi* smi) {
+  return LayoutDescriptor::cast(smi);
+}
+
+
+Handle<LayoutDescriptor> LayoutDescriptor::New(Isolate* isolate, int length) {
+  if (length <= kSmiValueSize) {
+    // The whole bit vector fits into a smi.
+    return handle(LayoutDescriptor::FromSmi(Smi::FromInt(0)), isolate);
+  }
+
+  length = (length + kNumberOfBits - 1) / kNumberOfBits;
+  DCHECK(length > 0);
+
+  if (SmiValuesAre32Bits() && (length & 1)) {
+    // On 64-bit systems if the length is odd then the half-word space would be
+    // lost anyway (due to alignment and the fact that we are allocating
+    // uint32-typed array), so we increase the length of allocated array
+    // to utilize that "lost" space which could also help to avoid layout
+    // descriptor reallocations.
+    ++length;
+  }
+  return Handle<LayoutDescriptor>::cast(
+      isolate->factory()->NewFixedTypedArray(length, kExternalUint32Array));
+}
+
+
+bool LayoutDescriptor::InobjectUnboxedField(int inobject_properties,
+                                            PropertyDetails details) {
+  if (details.type() != FIELD || !details.representation().IsDouble()) {
+    return false;
+  }
+  // We care only about in-object properties.
+  return details.field_index() < inobject_properties;
+}
+
+
+LayoutDescriptor* LayoutDescriptor::FastPointerLayout() {
+  return LayoutDescriptor::FromSmi(Smi::FromInt(0));
+}
+
+
+bool LayoutDescriptor::GetIndexes(int field_index, int* layout_word_index,
+                                  int* layout_bit_index) {
+  if (static_cast<unsigned>(field_index) >= static_cast<unsigned>(capacity())) {
+    return false;
+  }
+
+  *layout_word_index = field_index / kNumberOfBits;
+  CHECK((!IsSmi() && (*layout_word_index < length())) ||
+        (IsSmi() && (*layout_word_index < 1)));
+
+  *layout_bit_index = field_index % kNumberOfBits;
+  return true;
+}
+
+
+LayoutDescriptor* LayoutDescriptor::SetTagged(int field_index, bool tagged) {
+  int layout_word_index;
+  int layout_bit_index;
+
+  if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
+    CHECK(false);
+    return this;
+  }
+  uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
+
+  if (IsSlowLayout()) {
+    uint32_t value = get_scalar(layout_word_index);
+    if (tagged) {
+      value &= ~layout_mask;
+    } else {
+      value |= layout_mask;
+    }
+    set(layout_word_index, value);
+    return this;
+  } else {
+    uint32_t value = static_cast<uint32_t>(Smi::cast(this)->value());
+    if (tagged) {
+      value &= ~layout_mask;
+    } else {
+      value |= layout_mask;
+    }
+    return LayoutDescriptor::FromSmi(Smi::FromInt(static_cast<int>(value)));
+  }
+}
+
+
+bool LayoutDescriptor::IsTagged(int field_index) {
+  if (IsFastPointerLayout()) return true;
+
+  int layout_word_index;
+  int layout_bit_index;
+
+  if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
+    // All bits after Out of bounds queries
+    return true;
+  }
+  uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
+
+  if (IsSlowLayout()) {
+    uint32_t value = get_scalar(layout_word_index);
+    return (value & layout_mask) == 0;
+  } else {
+    uint32_t value = static_cast<uint32_t>(Smi::cast(this)->value());
+    return (value & layout_mask) == 0;
+  }
+}
+
+
+bool LayoutDescriptor::IsFastPointerLayout() {
+  return this == FastPointerLayout();
+}
+
+
+bool LayoutDescriptor::IsFastPointerLayout(Object* layout_descriptor) {
+  return layout_descriptor == FastPointerLayout();
+}
+
+
+bool LayoutDescriptor::IsSlowLayout() { return !IsSmi(); }
+
+
+int LayoutDescriptor::capacity() {
+  return IsSlowLayout() ? (length() * kNumberOfBits) : kSmiValueSize;
+}
+
+
+LayoutDescriptor* LayoutDescriptor::cast_gc_safe(Object* object) {
+  if (object->IsSmi()) {
+    // Fast mode layout descriptor.
+    return reinterpret_cast<LayoutDescriptor*>(object);
+  }
+
+  // This is a mixed descriptor which is a fixed typed array.
+  MapWord map_word = reinterpret_cast<HeapObject*>(object)->map_word();
+  if (map_word.IsForwardingAddress()) {
+    // Mark-compact has already moved layout descriptor.
+    object = map_word.ToForwardingAddress();
+  }
+  return LayoutDescriptor::cast(object);
+}
+
+
+// InobjectPropertiesHelper is a helper class for querying whether inobject
+// property at offset is Double or not.
+LayoutDescriptorHelper::LayoutDescriptorHelper(Map* map)
+    : all_fields_tagged_(true),
+      header_size_(0),
+      layout_descriptor_(LayoutDescriptor::FastPointerLayout()) {
+  if (!FLAG_unbox_double_fields) return;
+
+  layout_descriptor_ = map->layout_descriptor_gc_safe();
+  if (layout_descriptor_->IsFastPointerLayout()) {
+    return;
+  }
+
+  int inobject_properties = map->inobject_properties();
+  DCHECK(inobject_properties > 0);
+  header_size_ = map->instance_size() - (inobject_properties * kPointerSize);
+  DCHECK(header_size_ >= 0);
+
+  all_fields_tagged_ = false;
+}
+
+
+bool LayoutDescriptorHelper::IsTagged(int offset_in_bytes) {
+  DCHECK(IsAligned(offset_in_bytes, kPointerSize));
+  if (all_fields_tagged_) return true;
+  // Object headers do not contain non-tagged fields.
+  if (offset_in_bytes < header_size_) return true;
+  int field_index = (offset_in_bytes - header_size_) / kPointerSize;
+
+  return layout_descriptor_->IsTagged(field_index);
+}
+}
+}  // namespace v8::internal
+
+#endif  // V8_LAYOUT_DESCRIPTOR_INL_H_
diff --git a/src/layout-descriptor.cc b/src/layout-descriptor.cc
new file mode 100644
index 0000000..77b8ec4
--- /dev/null
+++ b/src/layout-descriptor.cc
@@ -0,0 +1,256 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sstream>
+
+#include "src/v8.h"
+
+#include "src/base/bits.h"
+#include "src/layout-descriptor.h"
+
+using v8::base::bits::CountTrailingZeros32;
+
+namespace v8 {
+namespace internal {
+
+Handle<LayoutDescriptor> LayoutDescriptor::New(
+    Handle<Map> map, Handle<DescriptorArray> descriptors, int num_descriptors) {
+  Isolate* isolate = descriptors->GetIsolate();
+  if (!FLAG_unbox_double_fields) return handle(FastPointerLayout(), isolate);
+
+  int inobject_properties = map->inobject_properties();
+  if (inobject_properties == 0) return handle(FastPointerLayout(), isolate);
+
+  DCHECK(num_descriptors <= descriptors->number_of_descriptors());
+
+  int layout_descriptor_length;
+  const int kMaxWordsPerField = kDoubleSize / kPointerSize;
+
+  if (num_descriptors <= kSmiValueSize / kMaxWordsPerField) {
+    // Even in the "worst" case (all fields are doubles) it would fit into
+    // a Smi, so no need to calculate length.
+    layout_descriptor_length = kSmiValueSize;
+
+  } else {
+    layout_descriptor_length = 0;
+
+    for (int i = 0; i < num_descriptors; i++) {
+      PropertyDetails details = descriptors->GetDetails(i);
+      if (!InobjectUnboxedField(inobject_properties, details)) continue;
+      int field_index = details.field_index();
+      int field_width_in_words = details.field_width_in_words();
+      layout_descriptor_length =
+          Max(layout_descriptor_length, field_index + field_width_in_words);
+    }
+
+    if (layout_descriptor_length == 0) {
+      // No double fields were found, use fast pointer layout.
+      return handle(FastPointerLayout(), isolate);
+    }
+  }
+  layout_descriptor_length = Min(layout_descriptor_length, inobject_properties);
+
+  // Initially, layout descriptor corresponds to an object with all fields
+  // tagged.
+  Handle<LayoutDescriptor> layout_descriptor_handle =
+      LayoutDescriptor::New(isolate, layout_descriptor_length);
+
+  DisallowHeapAllocation no_allocation;
+  LayoutDescriptor* layout_descriptor = *layout_descriptor_handle;
+
+  for (int i = 0; i < num_descriptors; i++) {
+    PropertyDetails details = descriptors->GetDetails(i);
+    if (!InobjectUnboxedField(inobject_properties, details)) continue;
+    int field_index = details.field_index();
+    layout_descriptor = layout_descriptor->SetRawData(field_index);
+    if (details.field_width_in_words() > 1) {
+      layout_descriptor = layout_descriptor->SetRawData(field_index + 1);
+    }
+  }
+  return handle(layout_descriptor, isolate);
+}
+
+
+Handle<LayoutDescriptor> LayoutDescriptor::Append(Handle<Map> map,
+                                                  PropertyDetails details) {
+  Isolate* isolate = map->GetIsolate();
+  Handle<LayoutDescriptor> layout_descriptor(map->GetLayoutDescriptor(),
+                                             isolate);
+
+  if (!InobjectUnboxedField(map->inobject_properties(), details)) {
+    return layout_descriptor;
+  }
+  int field_index = details.field_index();
+  layout_descriptor = LayoutDescriptor::EnsureCapacity(
+      isolate, layout_descriptor, field_index + details.field_width_in_words());
+
+  DisallowHeapAllocation no_allocation;
+  LayoutDescriptor* layout_desc = *layout_descriptor;
+  layout_desc = layout_desc->SetRawData(field_index);
+  if (details.field_width_in_words() > 1) {
+    layout_desc = layout_desc->SetRawData(field_index + 1);
+  }
+  return handle(layout_desc, isolate);
+}
+
+
+Handle<LayoutDescriptor> LayoutDescriptor::AppendIfFastOrUseFull(
+    Handle<Map> map, PropertyDetails details,
+    Handle<LayoutDescriptor> full_layout_descriptor) {
+  DisallowHeapAllocation no_allocation;
+  LayoutDescriptor* layout_descriptor = map->layout_descriptor();
+  if (layout_descriptor->IsSlowLayout()) {
+    return full_layout_descriptor;
+  }
+  if (!InobjectUnboxedField(map->inobject_properties(), details)) {
+    return handle(layout_descriptor, map->GetIsolate());
+  }
+  int field_index = details.field_index();
+  int new_capacity = field_index + details.field_width_in_words();
+  if (new_capacity > layout_descriptor->capacity()) {
+    // Current map's layout descriptor runs out of space, so use the full
+    // layout descriptor.
+    return full_layout_descriptor;
+  }
+
+  layout_descriptor = layout_descriptor->SetRawData(field_index);
+  if (details.field_width_in_words() > 1) {
+    layout_descriptor = layout_descriptor->SetRawData(field_index + 1);
+  }
+  return handle(layout_descriptor, map->GetIsolate());
+}
+
+
+Handle<LayoutDescriptor> LayoutDescriptor::EnsureCapacity(
+    Isolate* isolate, Handle<LayoutDescriptor> layout_descriptor,
+    int new_capacity) {
+  int old_capacity = layout_descriptor->capacity();
+  if (new_capacity <= old_capacity) {
+    // Nothing to do with layout in Smi-form.
+    return layout_descriptor;
+  }
+  Handle<LayoutDescriptor> new_layout_descriptor =
+      LayoutDescriptor::New(isolate, new_capacity);
+  DCHECK(new_layout_descriptor->IsSlowLayout());
+
+  if (layout_descriptor->IsSlowLayout()) {
+    memcpy(new_layout_descriptor->DataPtr(), layout_descriptor->DataPtr(),
+           layout_descriptor->DataSize());
+    return new_layout_descriptor;
+  } else {
+    // Fast layout.
+    uint32_t value =
+        static_cast<uint32_t>(Smi::cast(*layout_descriptor)->value());
+    new_layout_descriptor->set(0, value);
+    return new_layout_descriptor;
+  }
+}
+
+
+bool LayoutDescriptor::IsTagged(int field_index, int max_sequence_length,
+                                int* out_sequence_length) {
+  DCHECK(max_sequence_length > 0);
+  if (IsFastPointerLayout()) {
+    *out_sequence_length = max_sequence_length;
+    return true;
+  }
+
+  int layout_word_index;
+  int layout_bit_index;
+
+  if (!GetIndexes(field_index, &layout_word_index, &layout_bit_index)) {
+    // Out of bounds queries are considered tagged.
+    *out_sequence_length = max_sequence_length;
+    return true;
+  }
+  uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
+
+  uint32_t value = IsSlowLayout()
+                       ? get_scalar(layout_word_index)
+                       : static_cast<uint32_t>(Smi::cast(this)->value());
+
+  bool is_tagged = (value & layout_mask) == 0;
+  if (!is_tagged) value = ~value;  // Count set bits instead of cleared bits.
+  value = value & ~(layout_mask - 1);  // Clear bits we are not interested in.
+  int sequence_length = CountTrailingZeros32(value) - layout_bit_index;
+
+  if (layout_bit_index + sequence_length == kNumberOfBits) {
+    // This is a contiguous sequence till the end of current word, proceed
+    // counting in the subsequent words.
+    if (IsSlowLayout()) {
+      int len = length();
+      ++layout_word_index;
+      for (; layout_word_index < len; layout_word_index++) {
+        value = get_scalar(layout_word_index);
+        bool cur_is_tagged = (value & 1) == 0;
+        if (cur_is_tagged != is_tagged) break;
+        if (!is_tagged) value = ~value;  // Count set bits instead.
+        int cur_sequence_length = CountTrailingZeros32(value);
+        sequence_length += cur_sequence_length;
+        if (sequence_length >= max_sequence_length) break;
+        if (cur_sequence_length != kNumberOfBits) break;
+      }
+    }
+    if (is_tagged && (field_index + sequence_length == capacity())) {
+      // The contiguous sequence of tagged fields lasts till the end of the
+      // layout descriptor which means that all the fields starting from
+      // field_index are tagged.
+      sequence_length = std::numeric_limits<int>::max();
+    }
+  }
+  *out_sequence_length = Min(sequence_length, max_sequence_length);
+  return is_tagged;
+}
+
+
+Handle<LayoutDescriptor> LayoutDescriptor::NewForTesting(Isolate* isolate,
+                                                         int length) {
+  return New(isolate, length);
+}
+
+
+LayoutDescriptor* LayoutDescriptor::SetTaggedForTesting(int field_index,
+                                                        bool tagged) {
+  return SetTagged(field_index, tagged);
+}
+
+
+bool LayoutDescriptorHelper::IsTagged(
+    int offset_in_bytes, int end_offset,
+    int* out_end_of_contiguous_region_offset) {
+  DCHECK(IsAligned(offset_in_bytes, kPointerSize));
+  DCHECK(IsAligned(end_offset, kPointerSize));
+  DCHECK(offset_in_bytes < end_offset);
+  if (all_fields_tagged_) {
+    *out_end_of_contiguous_region_offset = end_offset;
+    DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
+    return true;
+  }
+  int max_sequence_length = (end_offset - offset_in_bytes) / kPointerSize;
+  int field_index = Max(0, (offset_in_bytes - header_size_) / kPointerSize);
+  int sequence_length;
+  bool tagged = layout_descriptor_->IsTagged(field_index, max_sequence_length,
+                                             &sequence_length);
+  DCHECK(sequence_length > 0);
+  if (offset_in_bytes < header_size_) {
+    // Object headers do not contain non-tagged fields. Check if the contiguous
+    // region continues after the header.
+    if (tagged) {
+      // First field is tagged, calculate end offset from there.
+      *out_end_of_contiguous_region_offset =
+          header_size_ + sequence_length * kPointerSize;
+
+    } else {
+      *out_end_of_contiguous_region_offset = header_size_;
+    }
+    DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
+    return true;
+  }
+  *out_end_of_contiguous_region_offset =
+      offset_in_bytes + sequence_length * kPointerSize;
+  DCHECK(offset_in_bytes < *out_end_of_contiguous_region_offset);
+  return tagged;
+}
+}
+}  // namespace v8::internal
diff --git a/src/layout-descriptor.h b/src/layout-descriptor.h
new file mode 100644
index 0000000..cc2666a
--- /dev/null
+++ b/src/layout-descriptor.h
@@ -0,0 +1,141 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_LAYOUT_DESCRIPTOR_H_
+#define V8_LAYOUT_DESCRIPTOR_H_
+
+#include <iosfwd>
+
+#include "src/objects.h"
+
+namespace v8 {
+namespace internal {
+
+// LayoutDescriptor is a bit vector defining which fields contain non-tagged
+// values. It could either be a fixed typed array (slow form) or a Smi
+// if the length fits (fast form).
+// Each bit in the layout represents a FIELD. The bits are referenced by
+// field_index which is a field number. If the bit is set then the corresponding
+// field contains a non-tagged value and therefore must be skipped by GC.
+// Otherwise the field is considered tagged. If the queried bit lays "outside"
+// of the descriptor then the field is also considered tagged.
+// Once a layout descriptor is created it is allowed only to append properties
+// to it.
+class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> {
+ public:
+  V8_INLINE bool IsTagged(int field_index);
+
+  // Queries the contiguous region of fields that are either tagged or not.
+  // Returns true if the given field is tagged or false otherwise and writes
+  // the length of the contiguous region to |out_sequence_length|.
+  // If the sequence is longer than |max_sequence_length| then
+  // |out_sequence_length| is set to |max_sequence_length|.
+  bool IsTagged(int field_index, int max_sequence_length,
+                int* out_sequence_length);
+
+  // Returns true if this is a layout of the object having only tagged fields.
+  V8_INLINE bool IsFastPointerLayout();
+  V8_INLINE static bool IsFastPointerLayout(Object* layout_descriptor);
+
+  // Returns true if the layout descriptor is in non-Smi form.
+  V8_INLINE bool IsSlowLayout();
+
+  V8_INLINE static LayoutDescriptor* cast(Object* object);
+  V8_INLINE static const LayoutDescriptor* cast(const Object* object);
+
+  V8_INLINE static LayoutDescriptor* cast_gc_safe(Object* object);
+
+  // Builds layout descriptor optimized for given |map| by |num_descriptors|
+  // elements of given descriptors array. The |map|'s descriptors could be
+  // different.
+  static Handle<LayoutDescriptor> New(Handle<Map> map,
+                                      Handle<DescriptorArray> descriptors,
+                                      int num_descriptors);
+
+  // Creates new layout descriptor by appending property with |details| to
+  // |map|'s layout descriptor.
+  static Handle<LayoutDescriptor> Append(Handle<Map> map,
+                                         PropertyDetails details);
+
+  // Creates new layout descriptor by appending property with |details| to
+  // |map|'s layout descriptor and if it is still fast then returns it.
+  // Otherwise the |full_layout_descriptor| is returned.
+  static Handle<LayoutDescriptor> AppendIfFastOrUseFull(
+      Handle<Map> map, PropertyDetails details,
+      Handle<LayoutDescriptor> full_layout_descriptor);
+
+  // Layout descriptor that corresponds to an object all fields of which are
+  // tagged (FastPointerLayout).
+  V8_INLINE static LayoutDescriptor* FastPointerLayout();
+
+#ifdef DEBUG
+  // Check that this layout descriptor corresponds to given map.
+  bool IsConsistentWithMap(Map* map);
+#endif
+
+#ifdef OBJECT_PRINT
+  // For our gdb macros, we should perhaps change these in the future.
+  void Print();
+
+  void Print(std::ostream& os);  // NOLINT
+#endif
+
+  // Capacity of layout descriptors in bits.
+  V8_INLINE int capacity();
+
+  static Handle<LayoutDescriptor> NewForTesting(Isolate* isolate, int length);
+  LayoutDescriptor* SetTaggedForTesting(int field_index, bool tagged);
+
+ private:
+  static const int kNumberOfBits = 32;
+
+  V8_INLINE static Handle<LayoutDescriptor> New(Isolate* isolate, int length);
+  V8_INLINE static LayoutDescriptor* FromSmi(Smi* smi);
+
+  V8_INLINE static bool InobjectUnboxedField(int inobject_properties,
+                                             PropertyDetails details);
+
+  static Handle<LayoutDescriptor> EnsureCapacity(
+      Isolate* isolate, Handle<LayoutDescriptor> layout_descriptor,
+      int new_capacity);
+
+  // Returns false if requested field_index is out of bounds.
+  V8_INLINE bool GetIndexes(int field_index, int* layout_word_index,
+                            int* layout_bit_index);
+
+  V8_INLINE MUST_USE_RESULT LayoutDescriptor* SetRawData(int field_index) {
+    return SetTagged(field_index, false);
+  }
+
+  V8_INLINE MUST_USE_RESULT LayoutDescriptor* SetTagged(int field_index,
+                                                        bool tagged);
+};
+
+
+// LayoutDescriptorHelper is a helper class for querying layout descriptor
+// about whether the field at given offset is tagged or not.
+class LayoutDescriptorHelper {
+ public:
+  inline explicit LayoutDescriptorHelper(Map* map);
+
+  bool all_fields_tagged() { return all_fields_tagged_; }
+  inline bool IsTagged(int offset_in_bytes);
+
+  // Queries the contiguous region of fields that are either tagged or not.
+  // Returns true if fields starting at |offset_in_bytes| are tagged or false
+  // otherwise and writes the offset of the end of the contiguous region to
+  // |out_end_of_contiguous_region_offset|. The |end_offset| value is the
+  // upper bound for |out_end_of_contiguous_region_offset|.
+  bool IsTagged(int offset_in_bytes, int end_offset,
+                int* out_end_of_contiguous_region_offset);
+
+ private:
+  bool all_fields_tagged_;
+  int header_size_;
+  LayoutDescriptor* layout_descriptor_;
+};
+}
+}  // namespace v8::internal
+
+#endif  // V8_LAYOUT_DESCRIPTOR_H_
diff --git a/src/libplatform/default-platform.cc b/src/libplatform/default-platform.cc
index b5b8571..1ac52f9 100644
--- a/src/libplatform/default-platform.cc
+++ b/src/libplatform/default-platform.cc
@@ -9,6 +9,7 @@
 
 #include "src/base/logging.h"
 #include "src/base/platform/platform.h"
+#include "src/base/platform/time.h"
 #include "src/base/sys-info.h"
 #include "src/libplatform/worker-thread.h"
 
@@ -106,4 +107,9 @@
   main_thread_queue_[isolate].push(task);
 }
 
+
+double DefaultPlatform::MonotonicallyIncreasingTime() {
+  return base::TimeTicks::HighResolutionNow().ToInternalValue() /
+         static_cast<double>(base::Time::kMicrosecondsPerSecond);
+}
 } }  // namespace v8::platform
diff --git a/src/libplatform/default-platform.h b/src/libplatform/default-platform.h
index 1efd7b2..21ba9bd 100644
--- a/src/libplatform/default-platform.h
+++ b/src/libplatform/default-platform.h
@@ -37,6 +37,7 @@
       Task* task, ExpectedRuntime expected_runtime) OVERRIDE;
   virtual void CallOnForegroundThread(v8::Isolate* isolate,
                                       Task* task) OVERRIDE;
+  double MonotonicallyIncreasingTime() OVERRIDE;
 
  private:
   static const int kMaxThreadPoolSize;
diff --git a/src/libplatform/libplatform.gyp b/src/libplatform/libplatform.gyp
deleted file mode 100644
index 4321da7..0000000
--- a/src/libplatform/libplatform.gyp
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright 2014 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  'variables': {
-    'v8_code': 1,
-  },
-  'includes': ['../../build/toolchain.gypi', '../../build/features.gypi'],
-  'targets': [
-    {
-      'target_name': 'libplatform-unittests',
-      'type': 'executable',
-      'dependencies': [
-        '../../testing/gtest.gyp:gtest',
-        '../../testing/gmock.gyp:gmock',
-        '../../testing/gmock.gyp:gmock_main',
-        '../../tools/gyp/v8.gyp:v8_libplatform',
-      ],
-      'include_dirs': [
-        '../..',
-      ],
-      'sources': [  ### gcmole(all) ###
-        'default-platform-unittest.cc',
-        'task-queue-unittest.cc',
-        'worker-thread-unittest.cc',
-      ],
-      'conditions': [
-        ['os_posix == 1', {
-          # TODO(svenpanne): This is a temporary work-around to fix the warnings
-          # that show up because we use -std=gnu++0x instead of -std=c++11.
-          'cflags!': [
-            '-pedantic',
-          ],
-        }],
-      ],
-    },
-  ],
-}
diff --git a/src/libplatform/worker-thread.h b/src/libplatform/worker-thread.h
index 67f086d..cf77e61 100644
--- a/src/libplatform/worker-thread.h
+++ b/src/libplatform/worker-thread.h
@@ -22,7 +22,7 @@
   virtual ~WorkerThread();
 
   // Thread implementation.
-  virtual void Run() OVERRIDE;
+  void Run() OVERRIDE;
 
  private:
   friend class QuitTask;
diff --git a/src/list-inl.h b/src/list-inl.h
index 60e8fab..9b122fd 100644
--- a/src/list-inl.h
+++ b/src/list-inl.h
@@ -7,6 +7,7 @@
 
 #include "src/list.h"
 
+#include "src/base/macros.h"
 #include "src/base/platform/platform.h"
 
 namespace v8 {
@@ -33,8 +34,10 @@
 void List<T, P>::AddAll(const Vector<T>& other, P alloc) {
   int result_length = length_ + other.length();
   if (capacity_ < result_length) Resize(result_length, alloc);
-  for (int i = 0; i < other.length(); i++) {
-    data_[length_ + i] = other.at(i);
+  if (base::is_fundamental<T>()) {
+    memcpy(data_ + length_, other.start(), sizeof(*data_) * other.length());
+  } else {
+    for (int i = 0; i < other.length(); i++) data_[length_ + i] = other.at(i);
   }
   length_ = result_length;
 }
diff --git a/src/list.h b/src/list.h
index ea5fd1e..c17c4ec 100644
--- a/src/list.h
+++ b/src/list.h
@@ -80,7 +80,9 @@
 
   Vector<T> ToVector() const { return Vector<T>(data_, length_); }
 
-  Vector<const T> ToConstVector() { return Vector<const T>(data_, length_); }
+  Vector<const T> ToConstVector() const {
+    return Vector<const T>(data_, length_);
+  }
 
   // Adds a copy of the given 'element' to the end of the list,
   // expanding the list if necessary.
diff --git a/src/lithium-codegen.cc b/src/lithium-codegen.cc
index ea6b83a..4534b46 100644
--- a/src/lithium-codegen.cc
+++ b/src/lithium-codegen.cc
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/v8.h"
-
 #include "src/lithium-codegen.h"
 
+#include <sstream>
+
+#include "src/v8.h"
+
 #if V8_TARGET_ARCH_IA32
 #include "src/ia32/lithium-ia32.h"  // NOLINT
 #include "src/ia32/lithium-codegen-ia32.h"  // NOLINT
@@ -148,11 +150,11 @@
 
 
 void LCodeGenBase::DeoptComment(const Deoptimizer::Reason& reason) {
-  OStringStream os;
+  std::ostringstream os;
   os << ";;; deoptimize at " << HSourcePosition(reason.raw_position) << " "
      << reason.mnemonic;
   if (reason.detail != NULL) os << ": " << reason.detail;
-  Comment("%s", os.c_str());
+  Comment("%s", os.str().c_str());
 }
 
 
diff --git a/src/lithium.cc b/src/lithium.cc
index 7d992a1..d57a2dd 100644
--- a/src/lithium.cc
+++ b/src/lithium.cc
@@ -463,8 +463,8 @@
   LOG_CODE_EVENT(info()->isolate(),
                  CodeStartLinePosInfoRecordEvent(
                      assembler.positions_recorder()));
-  // TODO(yangguo) remove this once the code serializer handles code stubs.
-  if (info()->will_serialize()) assembler.enable_serializer();
+  // Code serializer only takes unoptimized code.
+  DCHECK(!info()->will_serialize());
   LCodeGen generator(this, &assembler, info());
 
   MarkEmptyBlocks();
diff --git a/src/liveedit-debugger.js b/src/liveedit-debugger.js
index 07214f9..eaa2383 100644
--- a/src/liveedit-debugger.js
+++ b/src/liveedit-debugger.js
@@ -19,6 +19,9 @@
 // All unchanged functions have their positions updated accordingly.
 //
 // LiveEdit namespace is declared inside a single function constructor.
+
+"use strict";
+
 Debug.LiveEdit = new function() {
 
   // Forward declaration for minifier.
@@ -953,7 +956,7 @@
 
   FunctionPatchabilityStatus.SymbolName = function(code) {
     var enumeration = FunctionPatchabilityStatus;
-    for (name in enumeration) {
+    for (var name in enumeration) {
       if (enumeration[name] == code) {
         return name;
       }
diff --git a/src/liveedit.cc b/src/liveedit.cc
index a87c31b..29eaa97 100644
--- a/src/liveedit.cc
+++ b/src/liveedit.cc
@@ -607,10 +607,8 @@
 
 void FunctionInfoWrapper::SetInitialProperties(Handle<String> name,
                                                int start_position,
-                                               int end_position,
-                                               int param_num,
+                                               int end_position, int param_num,
                                                int literal_count,
-                                               int slot_count,
                                                int parent_index) {
   HandleScope scope(isolate());
   this->SetField(kFunctionNameOffset_, name);
@@ -618,7 +616,6 @@
   this->SetSmiValueField(kEndPositionOffset_, end_position);
   this->SetSmiValueField(kParamNumOffset_, param_num);
   this->SetSmiValueField(kLiteralNumOffset_, literal_count);
-  this->SetSmiValueField(kSlotNumOffset_, slot_count);
   this->SetSmiValueField(kParentIndexOffset_, parent_index);
 }
 
@@ -649,23 +646,18 @@
 }
 
 
-Handle<TypeFeedbackVector> FunctionInfoWrapper::GetFeedbackVector() {
+MaybeHandle<TypeFeedbackVector> FunctionInfoWrapper::GetFeedbackVector() {
   Handle<Object> element = this->GetField(kSharedFunctionInfoOffset_);
-  Handle<TypeFeedbackVector> result;
   if (element->IsJSValue()) {
     Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element);
     Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
     Handle<SharedFunctionInfo> shared =
         Handle<SharedFunctionInfo>::cast(raw_result);
-    result = Handle<TypeFeedbackVector>(shared->feedback_vector(), isolate());
-    CHECK_EQ(result->length(), GetSlotCount());
+    return Handle<TypeFeedbackVector>(shared->feedback_vector(), isolate());
   } else {
-    // Scripts may never have a SharedFunctionInfo created, so
-    // create a type feedback vector here.
-    int slot_count = GetSlotCount();
-    result = isolate()->factory()->NewTypeFeedbackVector(slot_count);
+    // Scripts may never have a SharedFunctionInfo created.
+    return MaybeHandle<TypeFeedbackVector>();
   }
-  return result;
 }
 
 
@@ -709,7 +701,6 @@
     info.SetInitialProperties(fun->name(), fun->start_position(),
                               fun->end_position(), fun->parameter_count(),
                               fun->materialized_literal_count(),
-                              fun->slot_count(),
                               current_parent_index_);
     current_parent_index_ = len_;
     SetElementSloppy(result_, len_, info.GetJSArray());
@@ -1202,10 +1193,12 @@
       shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info));
     }
     shared_info->DisableOptimization(kLiveEdit);
-    // Update the type feedback vector
-    Handle<TypeFeedbackVector> feedback_vector =
+    // Update the type feedback vector, if needed.
+    MaybeHandle<TypeFeedbackVector> feedback_vector =
         compile_info_wrapper.GetFeedbackVector();
-    shared_info->set_feedback_vector(*feedback_vector);
+    if (!feedback_vector.is_null()) {
+      shared_info->set_feedback_vector(*feedback_vector.ToHandleChecked());
+    }
   }
 
   if (shared_info->debug_info()->IsDebugInfo()) {
diff --git a/src/liveedit.h b/src/liveedit.h
index 53418b0..65fe1a6 100644
--- a/src/liveedit.h
+++ b/src/liveedit.h
@@ -280,12 +280,8 @@
       : JSArrayBasedStruct<FunctionInfoWrapper>(array) {
   }
 
-  void SetInitialProperties(Handle<String> name,
-                            int start_position,
-                            int end_position,
-                            int param_num,
-                            int literal_count,
-                            int slot_count,
+  void SetInitialProperties(Handle<String> name, int start_position,
+                            int end_position, int param_num, int literal_count,
                             int parent_index);
 
   void SetFunctionCode(Handle<Code> function_code,
@@ -307,7 +303,7 @@
 
   Handle<Code> GetFunctionCode();
 
-  Handle<TypeFeedbackVector> GetFeedbackVector();
+  MaybeHandle<TypeFeedbackVector> GetFeedbackVector();
 
   Handle<Object> GetCodeScopeInfo();
 
@@ -317,10 +313,6 @@
 
   int GetEndPosition() { return this->GetSmiValueField(kEndPositionOffset_); }
 
-  int GetSlotCount() {
-    return this->GetSmiValueField(kSlotNumOffset_);
-  }
-
  private:
   static const int kFunctionNameOffset_ = 0;
   static const int kStartPositionOffset_ = 1;
@@ -332,8 +324,7 @@
   static const int kParentIndexOffset_ = 7;
   static const int kSharedFunctionInfoOffset_ = 8;
   static const int kLiteralNumOffset_ = 9;
-  static const int kSlotNumOffset_ = 10;
-  static const int kSize_ = 11;
+  static const int kSize_ = 10;
 
   friend class JSArrayBasedStruct<FunctionInfoWrapper>;
 };
diff --git a/src/log-inl.h b/src/log-inl.h
index 28677ad..a96631d 100644
--- a/src/log-inl.h
+++ b/src/log-inl.h
@@ -6,6 +6,7 @@
 #define V8_LOG_INL_H_
 
 #include "src/log.h"
+#include "src/isolate.h"
 
 namespace v8 {
 namespace internal {
@@ -26,6 +27,16 @@
 }
 
 
+void Logger::CallEventLogger(Isolate* isolate, const char* name, StartEnd se,
+                             bool expose_to_api) {
+  if (isolate->event_logger() != NULL) {
+    if (isolate->event_logger() == DefaultEventLoggerSentinel) {
+      LOG(isolate, TimerEvent(se, name));
+    } else if (expose_to_api) {
+      isolate->event_logger()(name, se);
+    }
+  }
+}
 } }  // namespace v8::internal
 
 #endif  // V8_LOG_INL_H_
diff --git a/src/log-utils.cc b/src/log-utils.cc
index c94d07a..278cff1 100644
--- a/src/log-utils.cc
+++ b/src/log-utils.cc
@@ -6,6 +6,7 @@
 
 #include "src/log-utils.h"
 #include "src/string-stream.h"
+#include "src/version.h"
 
 namespace v8 {
 namespace internal {
@@ -49,6 +50,14 @@
     } else {
       OpenFile(log_file_name);
     }
+
+    if (output_handle_ != nullptr) {
+      Log::MessageBuilder msg(this);
+      msg.Append("v8-version,%d,%d,%d,%d,%d", Version::GetMajor(),
+                 Version::GetMinor(), Version::GetBuild(), Version::GetPatch(),
+                 Version::IsCandidate());
+      msg.WriteToLogFile();
+    }
   }
 }
 
diff --git a/src/log.cc b/src/log.cc
index 86f5ce0..3eede36 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -2,7 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <stdarg.h>
+#include "src/log.h"
+
+#include <cstdarg>
+#include <sstream>
 
 #include "src/v8.h"
 
@@ -13,7 +16,7 @@
 #include "src/cpu-profiler.h"
 #include "src/deoptimizer.h"
 #include "src/global-handles.h"
-#include "src/log.h"
+#include "src/log-inl.h"
 #include "src/log-utils.h"
 #include "src/macro-assembler.h"
 #include "src/perf-jit.h"
@@ -605,7 +608,7 @@
     if (paused_)
       return;
 
-    if (Succ(head_) == tail_) {
+    if (Succ(head_) == static_cast<int>(base::NoBarrier_Load(&tail_))) {
       overflow_ = true;
     } else {
       buffer_[head_] = *sample;
@@ -624,9 +627,10 @@
   // Waits for a signal and removes profiling data.
   bool Remove(TickSample* sample) {
     buffer_semaphore_.Wait();  // Wait for an element.
-    *sample = buffer_[tail_];
+    *sample = buffer_[base::NoBarrier_Load(&tail_)];
     bool result = overflow_;
-    tail_ = Succ(tail_);
+    base::NoBarrier_Store(&tail_, static_cast<base::Atomic32>(
+                                      Succ(base::NoBarrier_Load(&tail_))));
     overflow_ = false;
     return result;
   }
@@ -640,7 +644,7 @@
   static const int kBufferSize = 128;
   TickSample buffer_[kBufferSize];  // Buffer storage.
   int head_;  // Index to the buffer head.
-  int tail_;  // Index to the buffer tail.
+  base::Atomic32 tail_;             // Index to the buffer tail.
   bool overflow_;  // Tell whether a buffer overflow has occurred.
   // Sempahore used for buffer synchronization.
   base::Semaphore buffer_semaphore_;
@@ -649,7 +653,7 @@
   bool engaged_;
 
   // Tells whether worker thread should continue running.
-  bool running_;
+  base::Atomic32 running_;
 
   // Tells whether we are currently recording tick samples.
   bool paused_;
@@ -697,12 +701,13 @@
     : base::Thread(Options("v8:Profiler")),
       isolate_(isolate),
       head_(0),
-      tail_(0),
       overflow_(false),
       buffer_semaphore_(0),
       engaged_(false),
-      running_(false),
-      paused_(false) {}
+      paused_(false) {
+  base::NoBarrier_Store(&tail_, 0);
+  base::NoBarrier_Store(&running_, 0);
+}
 
 
 void Profiler::Engage() {
@@ -717,7 +722,7 @@
   }
 
   // Start thread processing the profiler buffer.
-  running_ = true;
+  base::NoBarrier_Store(&running_, 1);
   Start();
 
   // Register to get ticks.
@@ -737,7 +742,7 @@
   // Terminate the worker thread by setting running_ to false,
   // inserting a fake element in the queue and then wait for
   // the thread to terminate.
-  running_ = false;
+  base::NoBarrier_Store(&running_, 0);
   TickSample sample;
   // Reset 'paused_' flag, otherwise semaphore may not be signalled.
   resume();
@@ -751,7 +756,7 @@
 void Profiler::Run() {
   TickSample sample;
   bool overflow = Remove(&sample);
-  while (running_) {
+  while (base::NoBarrier_Load(&running_)) {
     LOG(isolate_, TickEvent(&sample, overflow));
     overflow = Remove(&sample);
   }
@@ -950,18 +955,10 @@
 }
 
 
-void Logger::DefaultTimerEventsLogger(const char* name, int se) {
-  Isolate* isolate = Isolate::Current();
-  LOG(isolate, TimerEvent(static_cast<StartEnd>(se), name));
-}
-
-
 template <class TimerEvent>
 void TimerEventScope<TimerEvent>::LogTimerEvent(Logger::StartEnd se) {
-  if (TimerEvent::expose_to_api() ||
-      isolate_->event_logger() == Logger::DefaultTimerEventsLogger) {
-    isolate_->event_logger()(TimerEvent::name(), se);
-  }
+  Logger::CallEventLogger(isolate_, TimerEvent::name(), se,
+                          TimerEvent::expose_to_api());
 }
 
 
@@ -1303,7 +1300,7 @@
   SmartArrayPointer<char> name =
       shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
   msg.Append("\"%s\",", name.get());
-  msg.Append("\"%s\"", GetBailoutReason(shared->DisableOptimizationReason()));
+  msg.Append("\"%s\"", GetBailoutReason(shared->disable_optimization_reason()));
   msg.WriteToLogFile();
 }
 
@@ -1785,13 +1782,13 @@
 }
 
 
-static void AddIsolateIdIfNeeded(OStream& os,  // NOLINT
+static void AddIsolateIdIfNeeded(std::ostream& os,  // NOLINT
                                  Isolate* isolate) {
   if (FLAG_logfile_per_isolate) os << "isolate-" << isolate << "-";
 }
 
 
-static void PrepareLogFileName(OStream& os,  // NOLINT
+static void PrepareLogFileName(std::ostream& os,  // NOLINT
                                Isolate* isolate, const char* file_name) {
   AddIsolateIdIfNeeded(os, isolate);
   for (const char* p = file_name; *p; p++) {
@@ -1836,9 +1833,9 @@
     FLAG_log_snapshot_positions = true;
   }
 
-  OStringStream log_file_name;
+  std::ostringstream log_file_name;
   PrepareLogFileName(log_file_name, isolate, FLAG_logfile);
-  log_->Initialize(log_file_name.c_str());
+  log_->Initialize(log_file_name.str().c_str());
 
 
   if (FLAG_perf_basic_prof) {
@@ -1852,7 +1849,7 @@
   }
 
   if (FLAG_ll_prof) {
-    ll_logger_ = new LowLevelLogger(log_file_name.c_str());
+    ll_logger_ = new LowLevelLogger(log_file_name.str().c_str());
     addCodeEventListener(ll_logger_);
   }
 
@@ -1862,14 +1859,14 @@
     is_logging_ = true;
   }
 
+  if (FLAG_log_internal_timer_events || FLAG_prof) timer_.Start();
+
   if (FLAG_prof) {
     profiler_ = new Profiler(isolate);
     is_logging_ = true;
     profiler_->Engage();
   }
 
-  if (FLAG_log_internal_timer_events || FLAG_prof) timer_.Start();
-
   return true;
 }
 
diff --git a/src/log.h b/src/log.h
index 51597dd..abf35f0 100644
--- a/src/log.h
+++ b/src/log.h
@@ -300,8 +300,10 @@
   static void EnterExternal(Isolate* isolate);
   static void LeaveExternal(Isolate* isolate);
 
-  static void EmptyTimerEventsLogger(const char* name, int se) {}
-  static void DefaultTimerEventsLogger(const char* name, int se);
+  static void DefaultEventLoggerSentinel(const char* name, int event) {}
+
+  INLINE(static void CallEventLogger(Isolate* isolate, const char* name,
+                                     StartEnd se, bool expose_to_api));
 
   // ==== Events logged by --log-regexp ====
   // Regexp compilation and execution events.
diff --git a/src/lookup-inl.h b/src/lookup-inl.h
index d4777a0..0c9cc91 100644
--- a/src/lookup-inl.h
+++ b/src/lookup-inl.h
@@ -63,12 +63,10 @@
         property_details_ = descriptors->GetDetails(number_);
       }
       has_property_ = true;
-      switch (property_details_.type()) {
-        case v8::internal::CONSTANT:
-        case v8::internal::FIELD:
-        case v8::internal::NORMAL:
+      switch (property_details_.kind()) {
+        case v8::internal::DATA:
           return DATA;
-        case v8::internal::CALLBACKS:
+        case v8::internal::ACCESSOR:
           return ACCESSOR;
       }
     case ACCESSOR:
diff --git a/src/lookup.cc b/src/lookup.cc
index b855abe..8088f4d 100644
--- a/src/lookup.cc
+++ b/src/lookup.cc
@@ -102,7 +102,7 @@
   DCHECK(HolderIsReceiverOrHiddenPrototype());
   Handle<JSObject> holder = GetHolder<JSObject>();
   if (holder_map_->is_dictionary_map()) {
-    PropertyDetails details(attributes, NORMAL, 0);
+    PropertyDetails details(attributes, FIELD, 0);
     JSObject::SetNormalizedProperty(holder, name(), value, details);
   } else {
     holder_map_ = Map::ReconfigureDataProperty(holder_map_, descriptor_number(),
@@ -127,7 +127,7 @@
   // observable.
   Handle<JSObject> receiver = GetStoreTarget();
 
-  if (!name().is_identical_to(isolate()->factory()->hidden_string()) &&
+  if (!isolate()->IsInternallyUsedPropertyName(name()) &&
       !receiver->map()->is_extensible()) {
     return;
   }
@@ -289,7 +289,7 @@
 }
 
 
-void LookupIterator::WriteDataValue(Handle<Object> value) {
+Handle<Object> LookupIterator::WriteDataValue(Handle<Object> value) {
   DCHECK_EQ(DATA, state_);
   Handle<JSObject> holder = GetHolder<JSObject>();
   if (holder_map_->is_dictionary_map()) {
@@ -297,7 +297,7 @@
     if (holder->IsGlobalObject()) {
       Handle<PropertyCell> cell(
           PropertyCell::cast(property_dictionary->ValueAt(dictionary_entry())));
-      PropertyCell::SetValueInferType(cell, value);
+      value = PropertyCell::SetValueInferType(cell, value);
     } else {
       property_dictionary->ValueAtPut(dictionary_entry(), *value);
     }
@@ -306,6 +306,29 @@
   } else {
     DCHECK_EQ(v8::internal::CONSTANT, property_details_.type());
   }
+  return value;
+}
+
+
+bool LookupIterator::IsSpecialNumericIndex() const {
+  if (GetStoreTarget()->IsJSTypedArray() && name()->IsString()) {
+    Handle<String> name_string = Handle<String>::cast(name());
+    if (name_string->length() > 0) {
+      double d =
+          StringToDouble(isolate()->unicode_cache(), name_string, NO_FLAGS);
+      if (!std::isnan(d)) {
+        if (String::Equals(isolate()->factory()->minus_zero_string(),
+                           name_string))
+          return true;
+
+        Factory* factory = isolate()->factory();
+        Handle<Object> num = factory->NewNumber(d);
+        Handle<String> roundtrip_string = factory->NumberToString(num);
+        if (String::Equals(name_string, roundtrip_string)) return true;
+      }
+    }
+  }
+  return false;
 }
 
 
diff --git a/src/lookup.h b/src/lookup.h
index 14ca010..a2e0d4d 100644
--- a/src/lookup.h
+++ b/src/lookup.h
@@ -46,7 +46,7 @@
                  Configuration configuration = PROTOTYPE_CHAIN)
       : configuration_(ComputeConfiguration(configuration, name)),
         state_(NOT_FOUND),
-        property_details_(NONE, NORMAL, Representation::None()),
+        property_details_(NONE, FIELD, 0),
         isolate_(name->GetIsolate()),
         name_(name),
         receiver_(receiver),
@@ -61,7 +61,7 @@
                  Configuration configuration = PROTOTYPE_CHAIN)
       : configuration_(ComputeConfiguration(configuration, name)),
         state_(NOT_FOUND),
-        property_details_(NONE, NORMAL, Representation::None()),
+        property_details_(NONE, FIELD, 0),
         isolate_(name->GetIsolate()),
         name_(name),
         holder_map_(holder->map(), isolate_),
@@ -136,7 +136,13 @@
   Handle<PropertyCell> GetPropertyCell() const;
   Handle<Object> GetAccessors() const;
   Handle<Object> GetDataValue() const;
-  void WriteDataValue(Handle<Object> value);
+  // Usually returns the value that was passed in, but may perform
+  // non-observable modifications on it, such as internalize strings.
+  Handle<Object> WriteDataValue(Handle<Object> value);
+
+  // Checks whether the receiver is an indexed exotic object
+  // and name is a special numeric index.
+  bool IsSpecialNumericIndex() const;
 
   void InternalizeName();
 
@@ -171,7 +177,8 @@
   static Configuration ComputeConfiguration(
       Configuration configuration, Handle<Name> name) {
     if (name->IsOwn()) {
-      return static_cast<Configuration>(configuration & HIDDEN);
+      return static_cast<Configuration>(configuration &
+                                        HIDDEN_SKIP_INTERCEPTOR);
     } else {
       return configuration;
     }
diff --git a/src/macro-assembler.h b/src/macro-assembler.h
index 54cebca..2501f80 100644
--- a/src/macro-assembler.h
+++ b/src/macro-assembler.h
@@ -124,6 +124,74 @@
   bool old_has_frame_;
 };
 
+class FrameAndConstantPoolScope {
+ public:
+  FrameAndConstantPoolScope(MacroAssembler* masm, StackFrame::Type type)
+      : masm_(masm),
+        type_(type),
+        old_has_frame_(masm->has_frame()),
+        old_constant_pool_available_(FLAG_enable_ool_constant_pool &&
+                                     masm->is_ool_constant_pool_available()) {
+    masm->set_has_frame(true);
+    if (FLAG_enable_ool_constant_pool) {
+      masm->set_ool_constant_pool_available(true);
+    }
+    if (type_ != StackFrame::MANUAL && type_ != StackFrame::NONE) {
+      masm->EnterFrame(type, !old_constant_pool_available_);
+    }
+  }
+
+  ~FrameAndConstantPoolScope() {
+    masm_->LeaveFrame(type_);
+    masm_->set_has_frame(old_has_frame_);
+    if (FLAG_enable_ool_constant_pool) {
+      masm_->set_ool_constant_pool_available(old_constant_pool_available_);
+    }
+  }
+
+  // Normally we generate the leave-frame code when this object goes
+  // out of scope.  Sometimes we may need to generate the code somewhere else
+  // in addition.  Calling this will achieve that, but the object stays in
+  // scope, the MacroAssembler is still marked as being in a frame scope, and
+  // the code will be generated again when it goes out of scope.
+  void GenerateLeaveFrame() {
+    DCHECK(type_ != StackFrame::MANUAL && type_ != StackFrame::NONE);
+    masm_->LeaveFrame(type_);
+  }
+
+ private:
+  MacroAssembler* masm_;
+  StackFrame::Type type_;
+  bool old_has_frame_;
+  bool old_constant_pool_available_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(FrameAndConstantPoolScope);
+};
+
+// Class for scoping the the unavailability of constant pool access.
+class ConstantPoolUnavailableScope {
+ public:
+  explicit ConstantPoolUnavailableScope(MacroAssembler* masm)
+      : masm_(masm),
+        old_constant_pool_available_(FLAG_enable_ool_constant_pool &&
+                                     masm->is_ool_constant_pool_available()) {
+    if (FLAG_enable_ool_constant_pool) {
+      masm_->set_ool_constant_pool_available(false);
+    }
+  }
+  ~ConstantPoolUnavailableScope() {
+    if (FLAG_enable_ool_constant_pool) {
+      masm_->set_ool_constant_pool_available(old_constant_pool_available_);
+    }
+  }
+
+ private:
+  MacroAssembler* masm_;
+  int old_constant_pool_available_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ConstantPoolUnavailableScope);
+};
+
 
 class AllowExternalCallThatCantCauseGC: public FrameScope {
  public:
diff --git a/src/macros.py b/src/macros.py
index b3ff0fc..1571144 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -167,6 +167,8 @@
 macro TO_OBJECT_INLINE(arg) = (IS_SPEC_OBJECT(%IS_VAR(arg)) ? arg : ToObject(arg));
 macro JSON_NUMBER_TO_STRING(arg) = ((%_IsSmi(%IS_VAR(arg)) || arg - arg == 0) ? %_NumberToString(arg) : "null");
 macro HAS_OWN_PROPERTY(obj, index) = (%_CallFunction(obj, index, ObjectHasOwnProperty));
+macro SHOULD_CREATE_WRAPPER(functionName, receiver) = (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(functionName));
+macro HAS_INDEX(array, index, is_array) = ((is_array && %_HasFastPackedElements(%IS_VAR(array))) ? (index < array.length) : (index in array));
 
 # Private names.
 # GET_PRIVATE should only be used if the property is known to exists on obj
@@ -254,7 +256,7 @@
 macro OVERRIDE_CAPTURE(override, index) = ((override)[(index)]);
 
 # PropertyDescriptor return value indices - must match
-# PropertyDescriptorIndices in runtime.cc.
+# PropertyDescriptorIndices in runtime-object.cc.
 const IS_ACCESSOR_INDEX = 0;
 const VALUE_INDEX = 1;
 const GETTER_INDEX = 2;
@@ -290,3 +292,5 @@
 
 # Check whether debug is active.
 const DEBUG_IS_ACTIVE = (%_DebugIsActive() != 0);
+macro DEBUG_IS_STEPPING(function) = (%_DebugIsActive() != 0 && %DebugCallbackSupportsStepping(function));
+macro DEBUG_PREPARE_STEP_IN_IF_STEPPING(function) = if (DEBUG_IS_STEPPING(function)) %DebugPrepareStepInIfStepping(function);
diff --git a/src/math.js b/src/math.js
index f06249d..cc478d3 100644
--- a/src/math.js
+++ b/src/math.js
@@ -144,7 +144,7 @@
 // ECMA 262 - 15.8.2.14
 var rngstate;  // Initialized to a Uint32Array during genesis.
 function MathRandom() {
-  var r0 = (MathImul(18273, rngstate[0] & 0xFFFF) + (rngstate[0] >>> 16)) | 0;
+  var r0 = (MathImul(18030, rngstate[0] & 0xFFFF) + (rngstate[0] >>> 16)) | 0;
   rngstate[0] = r0;
   var r1 = (MathImul(36969, rngstate[1] & 0xFFFF) + (rngstate[1] >>> 16)) | 0;
   rngstate[1] = r1;
@@ -227,17 +227,6 @@
   return 0.5 * MathLog((1 + x) / (1 - x));
 }
 
-// ES6 draft 09-27-13, section 20.2.2.21.
-function MathLog10(x) {
-  return MathLog(x) * 0.434294481903251828;  // log10(x) = log(x)/log(10).
-}
-
-
-// ES6 draft 09-27-13, section 20.2.2.22.
-function MathLog2(x) {
-  return MathLog(x) * 1.442695040888963407;  // log2(x) = log(x)/log(2).
-}
-
 // ES6 draft 09-27-13, section 20.2.2.17.
 function MathHypot(x, y) {  // Function length is 2.
   // We may want to introduce fast paths for two arguments and when
@@ -321,6 +310,8 @@
   %AddNamedProperty(global, "Math", $Math, DONT_ENUM);
   %FunctionSetInstanceClassName(MathConstructor, 'Math');
 
+  %AddNamedProperty($Math, symbolToStringTag, "Math", READ_ONLY | DONT_ENUM);
+
   // Set up math constants.
   InstallConstants($Math, $Array(
     // ECMA-262, section 15.8.1.1.
@@ -367,8 +358,8 @@
     "asinh", MathAsinh,
     "acosh", MathAcosh,
     "atanh", MathAtanh,
-    "log10", MathLog10,
-    "log2", MathLog2,
+    "log10", MathLog10,   // implemented by third_party/fdlibm
+    "log2", MathLog2,     // implemented by third_party/fdlibm
     "hypot", MathHypot,
     "fround", MathFroundJS,
     "clz32", MathClz32,
diff --git a/src/messages.js b/src/messages.js
index 4a71a61..39887d6 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -9,9 +9,8 @@
   cyclic_proto:                  ["Cyclic __proto__ value"],
   code_gen_from_strings:         ["%0"],
   constructor_special_method:    ["Class constructor may not be an accessor"],
-  generator_running:             ["Generator is already running"],
-  generator_finished:            ["Generator has already finished"],
   // TypeError
+  generator_running:             ["Generator is already running"],
   unexpected_token:              ["Unexpected token ", "%0"],
   unexpected_token_number:       ["Unexpected number"],
   unexpected_token_string:       ["Unexpected string"],
@@ -19,8 +18,12 @@
   unexpected_reserved:           ["Unexpected reserved word"],
   unexpected_strict_reserved:    ["Unexpected strict mode reserved word"],
   unexpected_eos:                ["Unexpected end of input"],
+  unexpected_template_string:    ["Unexpected template string"],
   malformed_regexp:              ["Invalid regular expression: /", "%0", "/: ", "%1"],
+  malformed_regexp_flags:        ["Invalid regular expression flags"],
   unterminated_regexp:           ["Invalid regular expression: missing /"],
+  unterminated_template:         ["Unterminated template literal"],
+  unterminated_template_expr:    ["Missing } in template expression"],
   regexp_flags:                  ["Cannot supply flags when constructing one RegExp from another"],
   incompatible_method_receiver:  ["Method ", "%0", " called on incompatible receiver ", "%1"],
   multiple_defaults_in_switch:   ["More than one default clause in switch statement"],
@@ -49,6 +52,7 @@
   apply_wrong_args:              ["Function.prototype.apply: Arguments list has wrong type"],
   toMethod_non_function:         ["Function.prototype.toMethod was called on ", "%0", ", which is a ", "%1", " and not a function"],
   toMethod_non_object:           ["Function.prototype.toMethod: home object ", "%0", " is not an object"],
+  flags_getter_non_object:       ["RegExp.prototype.flags getter called on non-object ", "%0"],
   invalid_in_operator_use:       ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
   instanceof_function_expected:  ["Expecting a function in instanceof check, but got ", "%0"],
   instanceof_nonobject_proto:    ["Function has non-object prototype '", "%0", "' in instanceof check"],
@@ -150,6 +154,7 @@
   too_many_variables:            ["Too many variables declared (only 4194303 allowed)"],
   strict_param_dupe:             ["Strict mode function may not have duplicate parameter names"],
   strict_octal_literal:          ["Octal literals are not allowed in strict mode."],
+  template_octal_literal:        ["Octal literals are not allowed in template strings."],
   strict_duplicate_property:     ["Duplicate data property in object literal not allowed in strict mode"],
   accessor_data_property:        ["Object literal may not have data and accessor property with the same name"],
   accessor_get_set:              ["Object literal may not have multiple get/set accessors with the same name"],
@@ -174,7 +179,12 @@
   invalid_module_path:           ["Module does not export '", "%0", "', or export is not itself a module"],
   module_type_error:             ["Module '", "%0", "' used improperly"],
   module_export_undefined:       ["Export '", "%0", "' is not defined in module"],
-  unexpected_super:              ["'super' keyword unexpected here"]
+  unexpected_super:              ["'super' keyword unexpected here"],
+  extends_value_not_a_function:  ["Class extends value ", "%0", " is not a function or null"],
+  prototype_parent_not_an_object: ["Class extends value does not have valid prototype property ", "%0"],
+  duplicate_constructor:         ["A class may only have one constructor"],
+  sloppy_lexical:                ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode"],
+  super_constructor_call:        ["A 'super' constructor call may only appear as the first statement of a function, and its arguments may not access 'this'. Other forms are not yet supported."]
 };
 
 
@@ -221,7 +231,8 @@
     return str;
   }
   if (IS_SYMBOL(obj)) return %_CallFunction(obj, SymbolToString);
-  if (IS_OBJECT(obj) && %GetDataProperty(obj, "toString") === ObjectToString) {
+  if (IS_OBJECT(obj)
+      && %GetDataProperty(obj, "toString") === DefaultObjectToString) {
     var constructor = %GetDataProperty(obj, "constructor");
     if (typeof constructor == "function") {
       var constructorName = constructor.name;
@@ -233,7 +244,8 @@
   if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
     return %_CallFunction(obj, ErrorToString);
   }
-  return %_CallFunction(obj, ObjectToString);
+
+  return %_CallFunction(obj, NoSideEffectsObjectToString);
 }
 
 // To determine whether we can safely stringify an object using ErrorToString
@@ -272,7 +284,7 @@
 
 
 function ToDetailString(obj) {
-  if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
+  if (obj != null && IS_OBJECT(obj) && obj.toString === DefaultObjectToString) {
     var constructor = obj.constructor;
     if (typeof constructor == "function") {
       var constructorName = constructor.name;
@@ -362,6 +374,23 @@
   return MakeGenericError($Error, type, args);
 }
 
+
+// The embedded versions are called from unoptimized code, with embedded
+// arguments. Those arguments cannot be arrays, which are context-dependent.
+function MakeTypeErrorEmbedded(type, arg) {
+  return MakeGenericError($TypeError, type, [arg]);
+}
+
+
+function MakeSyntaxErrorEmbedded(type, arg) {
+  return MakeGenericError($SyntaxError, type, [arg]);
+}
+
+
+function MakeReferenceErrorEmbedded(type, arg) {
+  return MakeGenericError($ReferenceError, type, [arg]);
+}
+
 /**
  * Find a line number given a specific source position.
  * @param {number} position The source position.
@@ -369,34 +398,26 @@
        else the line number.
  */
 function ScriptLineFromPosition(position) {
-  var lower = 0;
-  var upper = this.lineCount() - 1;
   var line_ends = this.line_ends;
+  var upper = line_ends.length - 1;
+  if (upper < 0) return -1;
 
   // We'll never find invalid positions so bail right away.
-  if (position > line_ends[upper]) {
-    return -1;
-  }
+  if (position > line_ends[upper]) return -1;
+  if (position <= line_ends[0]) return 0;
 
-  // This means we don't have to safe-guard indexing line_ends[i - 1].
-  if (position <= line_ends[0]) {
-    return 0;
-  }
-
-  // Binary search to find line # from position range.
-  while (upper >= 1) {
-    var i = (lower + upper) >> 1;
-
-    if (position > line_ends[i]) {
-      lower = i + 1;
-    } else if (position <= line_ends[i - 1]) {
-      upper = i - 1;
+  var lower = 1;
+  // Binary search.
+  while (true) {
+    var mid = (upper + lower) >> 1;
+    if (position <= line_ends[mid - 1]) {
+      upper = mid - 1;
+    } else if (position > line_ends[mid]){
+      lower = mid + 1;
     } else {
-      return i;
+      return mid;
     }
   }
-
-  return -1;
 }
 
 /**
@@ -1103,12 +1124,12 @@
   var constructor = receiver.constructor;
   if (!constructor) {
     return requireConstructor ? null :
-        %_CallFunction(receiver, ObjectToString);
+        %_CallFunction(receiver, NoSideEffectsObjectToString);
   }
   var constructorName = constructor.name;
   if (!constructorName) {
     return requireConstructor ? null :
-        %_CallFunction(receiver, ObjectToString);
+        %_CallFunction(receiver, NoSideEffectsObjectToString);
   }
   return constructorName;
 }
@@ -1132,7 +1153,7 @@
       if (IS_UNDEFINED(stack_trace)) {
         // Neither formatted nor structured stack trace available.
         // Look further up the prototype chain.
-        holder = %GetPrototype(holder);
+        holder = %_GetPrototype(holder);
         continue;
       }
       formatted_stack_trace = FormatStackTrace(holder, stack_trace);
@@ -1198,14 +1219,13 @@
     %AddNamedProperty(f.prototype, "name", name, DONT_ENUM);
     %SetCode(f, function(m) {
       if (%_IsConstructCall()) {
+        try { captureStackTrace(this, f); } catch (e) { }
         // Define all the expected properties directly on the error
         // object. This avoids going through getters and setters defined
         // on prototype objects.
-        %AddNamedProperty(this, 'stack', UNDEFINED, DONT_ENUM);
         if (!IS_UNDEFINED(m)) {
           %AddNamedProperty(this, 'message', ToString(m), DONT_ENUM);
         }
-        try { captureStackTrace(this, f); } catch (e) { }
       } else {
         return new f(m);
       }
@@ -1237,7 +1257,7 @@
   var current = error;
   // Climb the prototype chain until we find the holder.
   while (current && !%HasOwnProperty(current, name)) {
-    current = %GetPrototype(current);
+    current = %_GetPrototype(current);
   }
   if (IS_NULL(current)) return UNDEFINED;
   if (!IS_OBJECT(current)) return error[name];
diff --git a/src/mips/assembler-mips-inl.h b/src/mips/assembler-mips-inl.h
index 2666f6a..1cd9361 100644
--- a/src/mips/assembler-mips-inl.h
+++ b/src/mips/assembler-mips-inl.h
@@ -99,6 +99,11 @@
 }
 
 
+int DoubleRegister::NumAllocatableAliasedRegisters() {
+  return NumAllocatableRegisters();
+}
+
+
 int FPURegister::ToAllocationIndex(FPURegister reg) {
   DCHECK(reg.code() % 2 == 0);
   DCHECK(reg.code() / 2 < kMaxNumAllocatableRegisters);
diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
index f1e5dfb..d6a4f79 100644
--- a/src/mips/assembler-mips.cc
+++ b/src/mips/assembler-mips.cc
@@ -2065,6 +2065,7 @@
 
 void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
     FPURegister ft) {
+  DCHECK(IsMipsArchVariant(kMips32r2));
   GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
 }
 
diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h
index 5cdf16a..c6b12b7 100644
--- a/src/mips/assembler-mips.h
+++ b/src/mips/assembler-mips.h
@@ -222,6 +222,10 @@
 
   inline static int NumRegisters();
   inline static int NumAllocatableRegisters();
+
+  // TODO(turbofan): Proper support for float32.
+  inline static int NumAllocatableAliasedRegisters();
+
   inline static int ToAllocationIndex(FPURegister reg);
   static const char* AllocationIndexToString(int index);
 
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc
index 2813dd4..100195b 100644
--- a/src/mips/builtins-mips.cc
+++ b/src/mips/builtins-mips.cc
@@ -12,7 +12,7 @@
 #include "src/debug.h"
 #include "src/deoptimizer.h"
 #include "src/full-codegen.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 
 namespace v8 {
@@ -45,11 +45,9 @@
     DCHECK(extra_args == NO_EXTRA_ARGUMENTS);
   }
 
-  // JumpToExternalReference expects s0 to contain the number of arguments
+  // JumpToExternalReference expects a0 to contain the number of arguments
   // including the receiver and the extra arguments.
-  __ Addu(s0, a0, num_extra_args + 1);
-  __ sll(s1, s0, kPointerSizeLog2);
-  __ Subu(s1, s1, kPointerSize);
+  __ Addu(a0, a0, num_extra_args + 1);
   __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
 }
 
@@ -384,21 +382,21 @@
         MemOperand bit_field3 = FieldMemOperand(a2, Map::kBitField3Offset);
         // Check if slack tracking is enabled.
         __ lw(t0, bit_field3);
-        __ DecodeField<Map::ConstructionCount>(t2, t0);
-        __ Branch(&allocate, eq, t2, Operand(JSFunction::kNoSlackTracking));
+        __ DecodeField<Map::Counter>(t2, t0);
+        __ Branch(&allocate, lt, t2, Operand(Map::kSlackTrackingCounterEnd));
         // Decrease generous allocation count.
-        __ Subu(t0, t0, Operand(1 << Map::ConstructionCount::kShift));
-        __ Branch(USE_DELAY_SLOT,
-            &allocate, ne, t2, Operand(JSFunction::kFinishSlackTracking));
+        __ Subu(t0, t0, Operand(1 << Map::Counter::kShift));
+        __ Branch(USE_DELAY_SLOT, &allocate, ne, t2,
+                  Operand(Map::kSlackTrackingCounterEnd));
         __ sw(t0, bit_field3);  // In delay slot.
 
         __ Push(a1, a2, a1);  // a1 = Constructor.
         __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
 
         __ Pop(a1, a2);
-        // Slack tracking counter is kNoSlackTracking after runtime call.
-        DCHECK(JSFunction::kNoSlackTracking == 0);
-        __ mov(t2, zero_reg);
+        // Slack tracking counter is Map::kSlackTrackingCounterEnd after runtime
+        // call.
+        __ li(t2, Map::kSlackTrackingCounterEnd);
 
         __ bind(&allocate);
       }
@@ -445,8 +443,8 @@
         Label no_inobject_slack_tracking;
 
         // Check if slack tracking is enabled.
-        __ Branch(&no_inobject_slack_tracking,
-            eq, t2, Operand(JSFunction::kNoSlackTracking));
+        __ Branch(&no_inobject_slack_tracking, lt, t2,
+                  Operand(Map::kSlackTrackingCounterEnd));
 
         // Allocate object with a slack.
         __ lbu(a0, FieldMemOperand(a2, Map::kPreAllocatedPropertyFieldsOffset));
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index a9c10b8..97eed74 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -15,7 +15,7 @@
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -272,66 +272,6 @@
 }
 
 
-void WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(
-    Isolate* isolate) {
-  WriteInt32ToHeapNumberStub stub1(isolate, a1, v0, a2, a3);
-  WriteInt32ToHeapNumberStub stub2(isolate, a2, v0, a3, a0);
-  stub1.GetCode();
-  stub2.GetCode();
-}
-
-
-// See comment for class, this does NOT work for int32's that are in Smi range.
-void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) {
-  Label max_negative_int;
-  // the_int_ has the answer which is a signed int32 but not a Smi.
-  // We test for the special value that has a different exponent.
-  STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
-  // Test sign, and save for later conditionals.
-  __ And(sign(), the_int(), Operand(0x80000000u));
-  __ Branch(&max_negative_int, eq, the_int(), Operand(0x80000000u));
-
-  // Set up the correct exponent in scratch_.  All non-Smi int32s have the same.
-  // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased).
-  uint32_t non_smi_exponent =
-      (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
-  __ li(scratch(), Operand(non_smi_exponent));
-  // Set the sign bit in scratch_ if the value was negative.
-  __ or_(scratch(), scratch(), sign());
-  // Subtract from 0 if the value was negative.
-  __ subu(at, zero_reg, the_int());
-  __ Movn(the_int(), at, sign());
-  // We should be masking the implict first digit of the mantissa away here,
-  // but it just ends up combining harmlessly with the last digit of the
-  // exponent that happens to be 1.  The sign bit is 0 so we shift 10 to get
-  // the most significant 1 to hit the last bit of the 12 bit sign and exponent.
-  DCHECK(((1 << HeapNumber::kExponentShift) & non_smi_exponent) != 0);
-  const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
-  __ srl(at, the_int(), shift_distance);
-  __ or_(scratch(), scratch(), at);
-  __ sw(scratch(), FieldMemOperand(the_heap_number(),
-                                   HeapNumber::kExponentOffset));
-  __ sll(scratch(), the_int(), 32 - shift_distance);
-  __ Ret(USE_DELAY_SLOT);
-  __ sw(scratch(), FieldMemOperand(the_heap_number(),
-                                   HeapNumber::kMantissaOffset));
-
-  __ bind(&max_negative_int);
-  // The max negative int32 is stored as a positive number in the mantissa of
-  // a double because it uses a sign bit instead of using two's complement.
-  // The actual mantissa bits stored are all 0 because the implicit most
-  // significant 1 bit is not stored.
-  non_smi_exponent += 1 << HeapNumber::kExponentShift;
-  __ li(scratch(), Operand(HeapNumber::kSignMask | non_smi_exponent));
-  __ sw(scratch(),
-        FieldMemOperand(the_heap_number(), HeapNumber::kExponentOffset));
-  __ mov(scratch(), zero_reg);
-  __ Ret(USE_DELAY_SLOT);
-  __ sw(scratch(),
-        FieldMemOperand(the_heap_number(), HeapNumber::kMantissaOffset));
-}
-
-
 // Handle the case where the lhs and rhs are the same object.
 // Equality is almost reflexive (everything but NaN), so this is a test
 // for "identity and not NaN".
@@ -904,7 +844,6 @@
       // compile time and uses DoMathPowHalf instead.  We then skip this check
       // for non-constant cases of +/-0.5 as these hardly occur.
       Label not_plus_half;
-
       // Test for 0.5.
       __ Move(double_scratch, 0.5);
       __ BranchF(USE_DELAY_SLOT,
@@ -916,7 +855,7 @@
       // double_scratch can be overwritten in the delay slot.
       // Calculates square root of base.  Check for the special case of
       // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
-      __ Move(double_scratch, -V8_INFINITY);
+      __ Move(double_scratch, static_cast<double>(-V8_INFINITY));
       __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch);
       __ neg_d(double_result, double_scratch);
 
@@ -936,13 +875,13 @@
       // double_scratch can be overwritten in the delay slot.
       // Calculates square root of base.  Check for the special case of
       // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
-      __ Move(double_scratch, -V8_INFINITY);
+      __ Move(double_scratch, static_cast<double>(-V8_INFINITY));
       __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch);
       __ Move(double_result, kDoubleRegZero);
 
       // Add +0 to convert -0 to +0.
       __ add_d(double_scratch, double_base, kDoubleRegZero);
-      __ Move(double_result, 1);
+      __ Move(double_result, 1.);
       __ sqrt_d(double_scratch, double_scratch);
       __ div_d(double_result, double_result, double_scratch);
       __ jmp(&done);
@@ -1058,7 +997,6 @@
 
 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
   CEntryStub::GenerateAheadOfTime(isolate);
-  WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
   StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
   StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
@@ -1099,22 +1037,18 @@
 
 void CEntryStub::Generate(MacroAssembler* masm) {
   // Called from JavaScript; parameters are on stack as if calling JS function
-  // s0: number of arguments including receiver
-  // s1: size of arguments excluding receiver
-  // s2: pointer to builtin function
+  // a0: number of arguments including receiver
+  // a1: pointer to builtin function
   // fp: frame pointer    (restored after C call)
   // sp: stack pointer    (restored as callee's sp after C call)
   // cp: current context  (C callee-saved)
 
   ProfileEntryHookStub::MaybeCallEntryHook(masm);
 
-  // NOTE: s0-s2 hold the arguments of this function instead of a0-a2.
-  // The reason for this is that these arguments would need to be saved anyway
-  // so it's faster to set them up directly.
-  // See MacroAssembler::PrepareCEntryArgs and PrepareCEntryFunction.
-
   // Compute the argv pointer in a callee-saved register.
+  __ sll(s1, a0, kPointerSizeLog2);
   __ Addu(s1, sp, s1);
+  __ Subu(s1, s1, kPointerSize);
 
   // Enter the exit frame that transitions from JavaScript to C++.
   FrameScope scope(masm, StackFrame::MANUAL);
@@ -1126,7 +1060,8 @@
 
   // Prepare arguments for C routine.
   // a0 = argc
-  __ mov(a0, s0);
+  __ mov(s0, a0);
+  __ mov(s2, a1);
   // a1 = argv (set in the delay slot after find_ra below).
 
   // We are calling compiled C/C++ code. a0 and a1 hold our two arguments. We
@@ -1406,6 +1341,40 @@
 }
 
 
+void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
+  // Return address is in ra.
+  Label miss;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register index = LoadDescriptor::NameRegister();
+  Register scratch = t1;
+  Register result = v0;
+  DCHECK(!scratch.is(receiver) && !scratch.is(index));
+  DCHECK(!FLAG_vector_ics ||
+         (!scratch.is(VectorLoadICDescriptor::VectorRegister()) &&
+          result.is(VectorLoadICDescriptor::SlotRegister())));
+
+  // StringCharAtGenerator doesn't use the result register until it's passed
+  // the different miss possibilities. If it did, we would have a conflict
+  // when FLAG_vector_ics is true.
+  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
+                                          &miss,  // When not a string.
+                                          &miss,  // When not a number.
+                                          &miss,  // When index out of range.
+                                          STRING_INDEX_IS_ARRAY_INDEX,
+                                          RECEIVER_IS_STRING);
+  char_at_generator.GenerateFast(masm);
+  __ Ret();
+
+  StubRuntimeCallHelper call_helper;
+  char_at_generator.GenerateSlow(masm, call_helper);
+
+  __ bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
 // Uses registers a0 to t0.
 // Expected input (depending on whether args are in registers or on the stack):
 // * object: a0 or at sp + 1 * kPointerSize.
@@ -1417,8 +1386,6 @@
 void InstanceofStub::Generate(MacroAssembler* masm) {
   // Call site inlining and patching implies arguments in registers.
   DCHECK(HasArgsInRegisters() || !HasCallSiteInlineCheck());
-  // ReturnTrueFalse is only implemented for inlined call sites.
-  DCHECK(!ReturnTrueFalseObject() || HasCallSiteInlineCheck());
 
   // Fixed register usage throughout the stub:
   const Register object = a0;  // Object (lhs).
@@ -1443,7 +1410,7 @@
 
   // If there is a call site cache don't look in the global cache, but do the
   // real lookup and update the call site cache.
-  if (!HasCallSiteInlineCheck()) {
+  if (!HasCallSiteInlineCheck() && !ReturnTrueFalseObject()) {
     Label miss;
     __ LoadRoot(at, Heap::kInstanceofCacheFunctionRootIndex);
     __ Branch(&miss, ne, function, Operand(at));
@@ -1502,6 +1469,9 @@
   if (!HasCallSiteInlineCheck()) {
     __ mov(v0, zero_reg);
     __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex);
+    if (ReturnTrueFalseObject()) {
+      __ LoadRoot(v0, Heap::kTrueValueRootIndex);
+    }
   } else {
     // Patch the call site to return true.
     __ LoadRoot(v0, Heap::kTrueValueRootIndex);
@@ -1520,6 +1490,9 @@
   if (!HasCallSiteInlineCheck()) {
     __ li(v0, Operand(Smi::FromInt(1)));
     __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex);
+    if (ReturnTrueFalseObject()) {
+      __ LoadRoot(v0, Heap::kFalseValueRootIndex);
+    }
   } else {
     // Patch the call site to return false.
     __ LoadRoot(v0, Heap::kFalseValueRootIndex);
@@ -1543,23 +1516,33 @@
   __ Branch(&slow, ne, scratch, Operand(JS_FUNCTION_TYPE));
 
   // Null is not instance of anything.
-  __ Branch(&object_not_null,
-            ne,
-            scratch,
+  __ Branch(&object_not_null, ne, object,
             Operand(isolate()->factory()->null_value()));
-  __ li(v0, Operand(Smi::FromInt(1)));
+  if (ReturnTrueFalseObject()) {
+    __ LoadRoot(v0, Heap::kFalseValueRootIndex);
+  } else {
+    __ li(v0, Operand(Smi::FromInt(1)));
+  }
   __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
 
   __ bind(&object_not_null);
   // Smi values are not instances of anything.
   __ JumpIfNotSmi(object, &object_not_null_or_smi);
-  __ li(v0, Operand(Smi::FromInt(1)));
+  if (ReturnTrueFalseObject()) {
+    __ LoadRoot(v0, Heap::kFalseValueRootIndex);
+  } else {
+    __ li(v0, Operand(Smi::FromInt(1)));
+  }
   __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
 
   __ bind(&object_not_null_or_smi);
   // String values are not instances of anything.
   __ IsObjectJSStringType(object, scratch, &slow);
-  __ li(v0, Operand(Smi::FromInt(1)));
+  if (ReturnTrueFalseObject()) {
+    __ LoadRoot(v0, Heap::kFalseValueRootIndex);
+  } else {
+    __ li(v0, Operand(Smi::FromInt(1)));
+  }
   __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
 
   // Slow-case.  Tail call builtin.
@@ -1587,8 +1570,14 @@
 void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
   Label miss;
   Register receiver = LoadDescriptor::ReceiverRegister();
-  NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, a3,
-                                                          t0, &miss);
+  // Ensure that the vector and slot registers won't be clobbered before
+  // calling the miss handler.
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(t0, t1, VectorLoadICDescriptor::VectorRegister(),
+                     VectorLoadICDescriptor::SlotRegister()));
+
+  NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, t0,
+                                                          t1, &miss);
   __ bind(&miss);
   PropertyAccessCompiler::TailCallBuiltin(
       masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
@@ -2507,14 +2496,14 @@
 
   // A monomorphic miss (i.e, here the cache is not uninitialized) goes
   // megamorphic.
-  __ LoadRoot(at, Heap::kUninitializedSymbolRootIndex);
+  __ LoadRoot(at, Heap::kuninitialized_symbolRootIndex);
   __ Branch(&initialize, eq, t0, Operand(at));
   // MegamorphicSentinel is an immortal immovable object (undefined) so no
   // write-barrier is needed.
   __ bind(&megamorphic);
   __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
   __ Addu(t0, a2, Operand(t0));
-  __ LoadRoot(at, Heap::kMegamorphicSymbolRootIndex);
+  __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
   __ sw(at, FieldMemOperand(t0, FixedArray::kHeaderSize));
   __ jmp(&done);
 
@@ -2790,8 +2779,12 @@
 
 
 void CallICStub::Generate(MacroAssembler* masm) {
-  // r1 - function
-  // r3 - slot id (Smi)
+  // a1 - function
+  // a3 - slot id (Smi)
+  const int with_types_offset =
+      FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
+  const int generic_offset =
+      FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
   Label slow, non_function, wrap, cont;
   Label have_js_function;
@@ -2830,27 +2823,71 @@
   }
 
   __ bind(&extra_checks_or_miss);
-  Label miss;
+  Label uninitialized, miss;
 
-  __ LoadRoot(at, Heap::kMegamorphicSymbolRootIndex);
+  __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
   __ Branch(&slow_start, eq, t0, Operand(at));
-  __ LoadRoot(at, Heap::kUninitializedSymbolRootIndex);
-  __ Branch(&miss, eq, t0, Operand(at));
 
-  if (!FLAG_trace_ic) {
-    // We are going megamorphic. If the feedback is a JSFunction, it is fine
-    // to handle it here. More complex cases are dealt with in the runtime.
-    __ AssertNotSmi(t0);
-    __ GetObjectType(t0, t1, t1);
-    __ Branch(&miss, ne, t1, Operand(JS_FUNCTION_TYPE));
-    __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
-    __ Addu(t0, a2, Operand(t0));
-    __ LoadRoot(at, Heap::kMegamorphicSymbolRootIndex);
-    __ sw(at, FieldMemOperand(t0, FixedArray::kHeaderSize));
-    __ Branch(&slow_start);
+  // The following cases attempt to handle MISS cases without going to the
+  // runtime.
+  if (FLAG_trace_ic) {
+    __ Branch(&miss);
   }
 
-  // We are here because tracing is on or we are going monomorphic.
+  __ LoadRoot(at, Heap::kuninitialized_symbolRootIndex);
+  __ Branch(&uninitialized, eq, t0, Operand(at));
+
+  // We are going megamorphic. If the feedback is a JSFunction, it is fine
+  // to handle it here. More complex cases are dealt with in the runtime.
+  __ AssertNotSmi(t0);
+  __ GetObjectType(t0, t1, t1);
+  __ Branch(&miss, ne, t1, Operand(JS_FUNCTION_TYPE));
+  __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
+  __ Addu(t0, a2, Operand(t0));
+  __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
+  __ sw(at, FieldMemOperand(t0, FixedArray::kHeaderSize));
+  // We have to update statistics for runtime profiling.
+  __ lw(t0, FieldMemOperand(a2, with_types_offset));
+  __ Subu(t0, t0, Operand(Smi::FromInt(1)));
+  __ sw(t0, FieldMemOperand(a2, with_types_offset));
+  __ lw(t0, FieldMemOperand(a2, generic_offset));
+  __ Addu(t0, t0, Operand(Smi::FromInt(1)));
+  __ Branch(USE_DELAY_SLOT, &slow_start);
+  __ sw(t0, FieldMemOperand(a2, generic_offset));  // In delay slot.
+
+  __ bind(&uninitialized);
+
+  // We are going monomorphic, provided we actually have a JSFunction.
+  __ JumpIfSmi(a1, &miss);
+
+  // Goto miss case if we do not have a function.
+  __ GetObjectType(a1, t0, t0);
+  __ Branch(&miss, ne, t0, Operand(JS_FUNCTION_TYPE));
+
+  // Make sure the function is not the Array() function, which requires special
+  // behavior on MISS.
+  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, t0);
+  __ Branch(&miss, eq, a1, Operand(t0));
+
+  // Update stats.
+  __ lw(t0, FieldMemOperand(a2, with_types_offset));
+  __ Addu(t0, t0, Operand(Smi::FromInt(1)));
+  __ sw(t0, FieldMemOperand(a2, with_types_offset));
+
+  // Store the function.
+  __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
+  __ Addu(t0, a2, Operand(t0));
+  __ Addu(t0, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ sw(a1, MemOperand(t0, 0));
+
+  // Update the write barrier.
+  __ mov(t1, a1);
+  __ RecordWrite(a2, t0, t1, kRAHasNotBeenSaved, kDontSaveFPRegs,
+                 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+  __ Branch(&have_js_function);
+
+  // We are here because tracing is on or we encountered a MISS case we can't
+  // handle here.
   __ bind(&miss);
   GenerateMiss(masm);
 
@@ -2896,16 +2933,17 @@
   DCHECK(!t0.is(index_));
   DCHECK(!t0.is(result_));
   DCHECK(!t0.is(object_));
+  if (check_mode_ == RECEIVER_IS_UNKNOWN) {
+    // If the receiver is a smi trigger the non-string case.
+    __ JumpIfSmi(object_, receiver_not_string_);
 
-  // If the receiver is a smi trigger the non-string case.
-  __ JumpIfSmi(object_, receiver_not_string_);
-
-  // Fetch the instance type of the receiver into result register.
-  __ lw(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
-  __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
-  // If the receiver is not a string trigger the non-string case.
-  __ And(t0, result_, Operand(kIsNotStringMask));
-  __ Branch(receiver_not_string_, ne, t0, Operand(zero_reg));
+    // Fetch the instance type of the receiver into result register.
+    __ lw(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
+    __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
+    // If the receiver is not a string trigger the non-string case.
+    __ And(t0, result_, Operand(kIsNotStringMask));
+    __ Branch(receiver_not_string_, ne, t0, Operand(zero_reg));
+  }
 
   // If the index is non-smi trigger the non-smi case.
   __ JumpIfNotSmi(index_, &index_not_smi_);
@@ -3292,14 +3330,57 @@
   // a2: length
   // a3: from index (untagged)
   __ SmiTag(a3, a3);
-  StringCharAtGenerator generator(
-      v0, a3, a2, v0, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
+  StringCharAtGenerator generator(v0, a3, a2, v0, &runtime, &runtime, &runtime,
+                                  STRING_INDEX_IS_NUMBER, RECEIVER_IS_STRING);
   generator.GenerateFast(masm);
   __ DropAndRet(3);
   generator.SkipSlow(masm, &runtime);
 }
 
 
+void ToNumberStub::Generate(MacroAssembler* masm) {
+  // The ToNumber stub takes one argument in a0.
+  Label not_smi;
+  __ JumpIfNotSmi(a0, &not_smi);
+  __ Ret(USE_DELAY_SLOT);
+  __ mov(v0, a0);
+  __ bind(&not_smi);
+
+  Label not_heap_number;
+  __ lw(a1, FieldMemOperand(a0, HeapObject::kMapOffset));
+  __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset));
+  // a0: object
+  // a1: instance type.
+  __ Branch(&not_heap_number, ne, a1, Operand(HEAP_NUMBER_TYPE));
+  __ Ret(USE_DELAY_SLOT);
+  __ mov(v0, a0);
+  __ bind(&not_heap_number);
+
+  Label not_string, slow_string;
+  __ Branch(&not_string, hs, a1, Operand(FIRST_NONSTRING_TYPE));
+  // Check if string has a cached array index.
+  __ lw(a2, FieldMemOperand(a0, String::kHashFieldOffset));
+  __ And(at, a2, Operand(String::kContainsCachedArrayIndexMask));
+  __ Branch(&slow_string, ne, at, Operand(zero_reg));
+  __ IndexFromHash(a2, a0);
+  __ Ret(USE_DELAY_SLOT);
+  __ mov(v0, a0);
+  __ bind(&slow_string);
+  __ push(a0);  // Push argument.
+  __ TailCallRuntime(Runtime::kStringToNumber, 1, 1);
+  __ bind(&not_string);
+
+  Label not_oddball;
+  __ Branch(&not_oddball, ne, a1, Operand(ODDBALL_TYPE));
+  __ Ret(USE_DELAY_SLOT);
+  __ lw(v0, FieldMemOperand(a0, Oddball::kToNumberOffset));
+  __ bind(&not_oddball);
+
+  __ push(a0);  // Push argument.
+  __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
+}
+
+
 void StringHelper::GenerateFlatOneByteStringEquals(
     MacroAssembler* masm, Register left, Register right, Register scratch1,
     Register scratch2, Register scratch3) {
diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h
index afad32b..9796fd4 100644
--- a/src/mips/code-stubs-mips.h
+++ b/src/mips/code-stubs-mips.h
@@ -73,55 +73,6 @@
 };
 
 
-// This stub can convert a signed int32 to a heap number (double).  It does
-// not work for int32s that are in Smi range!  No GC occurs during this stub
-// so you don't have to set up the frame.
-class WriteInt32ToHeapNumberStub : public PlatformCodeStub {
- public:
-  WriteInt32ToHeapNumberStub(Isolate* isolate, Register the_int,
-                             Register the_heap_number, Register scratch,
-                             Register scratch2)
-      : PlatformCodeStub(isolate) {
-    minor_key_ = IntRegisterBits::encode(the_int.code()) |
-                 HeapNumberRegisterBits::encode(the_heap_number.code()) |
-                 ScratchRegisterBits::encode(scratch.code()) |
-                 SignRegisterBits::encode(scratch2.code());
-    DCHECK(IntRegisterBits::is_valid(the_int.code()));
-    DCHECK(HeapNumberRegisterBits::is_valid(the_heap_number.code()));
-    DCHECK(ScratchRegisterBits::is_valid(scratch.code()));
-    DCHECK(SignRegisterBits::is_valid(scratch2.code()));
-  }
-
-  static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
-
- private:
-  Register the_int() const {
-    return Register::from_code(IntRegisterBits::decode(minor_key_));
-  }
-
-  Register the_heap_number() const {
-    return Register::from_code(HeapNumberRegisterBits::decode(minor_key_));
-  }
-
-  Register scratch() const {
-    return Register::from_code(ScratchRegisterBits::decode(minor_key_));
-  }
-
-  Register sign() const {
-    return Register::from_code(SignRegisterBits::decode(minor_key_));
-  }
-
-  // Minor key encoding in 16 bits.
-  class IntRegisterBits: public BitField<int, 0, 4> {};
-  class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
-  class ScratchRegisterBits: public BitField<int, 8, 4> {};
-  class SignRegisterBits: public BitField<int, 12, 4> {};
-
-  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
-  DEFINE_PLATFORM_CODE_STUB(WriteInt32ToHeapNumber, PlatformCodeStub);
-};
-
-
 class RecordWriteStub: public PlatformCodeStub {
  public:
   RecordWriteStub(Isolate* isolate,
@@ -150,7 +101,7 @@
     INCREMENTAL_COMPACTION
   };
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
   static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
     const unsigned offset = masm->instr_at(pos) & kImm16Mask;
@@ -277,9 +228,9 @@
     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
   };
 
-  virtual inline Major MajorKey() const FINAL OVERRIDE { return RecordWrite; }
+  inline Major MajorKey() const FINAL { return RecordWrite; }
 
-  virtual void Generate(MacroAssembler* masm) OVERRIDE;
+  void Generate(MacroAssembler* masm) OVERRIDE;
   void GenerateIncremental(MacroAssembler* masm, Mode mode);
   void CheckNeedsToInformIncrementalMarker(
       MacroAssembler* masm,
@@ -287,7 +238,7 @@
       Mode mode);
   void InformIncrementalMarker(MacroAssembler* masm);
 
-  void Activate(Code* code) {
+  void Activate(Code* code) OVERRIDE {
     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
   }
 
@@ -335,7 +286,7 @@
   void GenerateCall(MacroAssembler* masm, Register target);
 
  private:
-  bool NeedsImmovableCode() { return true; }
+  bool NeedsImmovableCode() OVERRIDE { return true; }
 
   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
   DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
@@ -367,7 +318,7 @@
                                      Register r0,
                                      Register r1);
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
  private:
   static const int kInlinedProbes = 4;
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index 0ecac19..fbd4044 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -896,9 +896,23 @@
         FixedDoubleArray::kHeaderSize - kHeapObjectTag
         + Register::kExponentOffset));
   __ Addu(dst_elements, array, Operand(FixedArray::kHeaderSize));
-  __ Addu(array, array, Operand(kHeapObjectTag));
   __ sll(dst_end, dst_end, 1);
   __ Addu(dst_end, dst_elements, dst_end);
+
+  // Allocating heap numbers in the loop below can fail and cause a jump to
+  // gc_required. We can't leave a partly initialized FixedArray behind,
+  // so pessimistically fill it with holes now.
+  Label initialization_loop, initialization_loop_entry;
+  __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
+  __ Branch(&initialization_loop_entry);
+  __ bind(&initialization_loop);
+  __ sw(scratch, MemOperand(dst_elements));
+  __ Addu(dst_elements, dst_elements, Operand(kPointerSize));
+  __ bind(&initialization_loop_entry);
+  __ Branch(&initialization_loop, lt, dst_elements, Operand(dst_end));
+
+  __ Addu(dst_elements, array, Operand(FixedArray::kHeaderSize));
+  __ Addu(array, array, Operand(kHeapObjectTag));
   __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
   // Using offsetted addresses.
   // dst_elements: begin of destination FixedArray element fields, not tagged
@@ -1131,7 +1145,7 @@
   // Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1.
   DCHECK(*reinterpret_cast<double*>
          (ExternalReference::math_exp_constants(8).address()) == 1);
-  __ Move(double_scratch2, 1);
+  __ Move(double_scratch2, 1.);
   __ add_d(result, result, double_scratch2);
   __ srl(temp1, temp2, 11);
   __ Ext(temp2, temp2, 0, 11);
diff --git a/src/mips/constants-mips.h b/src/mips/constants-mips.h
index c2eb4ca..668481e 100644
--- a/src/mips/constants-mips.h
+++ b/src/mips/constants-mips.h
@@ -560,52 +560,49 @@
 // because 'NegateCondition' function flips LSB to negate condition.
 enum Condition {
   // Any value < 0 is considered no_condition.
-  kNoCondition  = -1,
-
-  overflow      =  0,
-  no_overflow   =  1,
-  Uless         =  2,
-  Ugreater_equal=  3,
-  equal         =  4,
-  not_equal     =  5,
-  Uless_equal   =  6,
-  Ugreater      =  7,
-  negative      =  8,
-  positive      =  9,
-  parity_even   = 10,
-  parity_odd    = 11,
-  less          = 12,
+  kNoCondition = -1,
+  overflow = 0,
+  no_overflow = 1,
+  Uless = 2,
+  Ugreater_equal = 3,
+  equal = 4,
+  not_equal = 5,
+  Uless_equal = 6,
+  Ugreater = 7,
+  negative = 8,
+  positive = 9,
+  parity_even = 10,
+  parity_odd = 11,
+  less = 12,
   greater_equal = 13,
-  less_equal    = 14,
-  greater       = 15,
-  ueq           = 16,  // Unordered or Equal.
-  nue           = 17,  // Not (Unordered or Equal).
-
-  cc_always     = 18,
+  less_equal = 14,
+  greater = 15,
+  ueq = 16,  // Unordered or Equal.
+  nue = 17,  // Not (Unordered or Equal).
+  cc_always = 18,
 
   // Aliases.
-  carry         = Uless,
-  not_carry     = Ugreater_equal,
-  zero          = equal,
-  eq            = equal,
-  not_zero      = not_equal,
-  ne            = not_equal,
-  nz            = not_equal,
-  sign          = negative,
-  not_sign      = positive,
-  mi            = negative,
-  pl            = positive,
-  hi            = Ugreater,
-  ls            = Uless_equal,
-  ge            = greater_equal,
-  lt            = less,
-  gt            = greater,
-  le            = less_equal,
-  hs            = Ugreater_equal,
-  lo            = Uless,
-  al            = cc_always,
-
-  cc_default    = kNoCondition
+  carry = Uless,
+  not_carry = Ugreater_equal,
+  zero = equal,
+  eq = equal,
+  not_zero = not_equal,
+  ne = not_equal,
+  nz = not_equal,
+  sign = negative,
+  not_sign = positive,
+  mi = negative,
+  pl = positive,
+  hi = Ugreater,
+  ls = Uless_equal,
+  ge = greater_equal,
+  lt = less,
+  gt = greater,
+  le = less_equal,
+  hs = Ugreater_equal,
+  lo = Uless,
+  al = cc_always,
+  cc_default = kNoCondition
 };
 
 
diff --git a/src/mips/debug-mips.cc b/src/mips/debug-mips.cc
index 96a1467..5b3591c 100644
--- a/src/mips/debug-mips.cc
+++ b/src/mips/debug-mips.cc
@@ -187,7 +187,11 @@
 void DebugCodegen::GenerateLoadICDebugBreak(MacroAssembler* masm) {
   Register receiver = LoadDescriptor::ReceiverRegister();
   Register name = LoadDescriptor::NameRegister();
-  Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit(), 0);
+  RegList regs = receiver.bit() | name.bit();
+  if (FLAG_vector_ics) {
+    regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
+  }
+  Generate_DebugBreakCallHelper(masm, regs, 0);
 }
 
 
diff --git a/src/mips/deoptimizer-mips.cc b/src/mips/deoptimizer-mips.cc
index dd9832d..e39b368 100644
--- a/src/mips/deoptimizer-mips.cc
+++ b/src/mips/deoptimizer-mips.cc
@@ -20,6 +20,12 @@
 }
 
 
+void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
+  // Empty because there is no need for relocation information for the code
+  // patching in Deoptimizer::PatchCodeForDeoptimization below.
+}
+
+
 void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
   Address code_start_address = code->instruction_start();
   // Invalidate the relocation information, as it will become invalid by the
@@ -102,9 +108,8 @@
   ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_);
   intptr_t handler = reinterpret_cast<intptr_t>(xref.address());
   int params = descriptor->GetHandlerParameterCount();
-  output_frame->SetRegister(s0.code(), params);
-  output_frame->SetRegister(s1.code(), (params - 1) * kPointerSize);
-  output_frame->SetRegister(s2.code(), handler);
+  output_frame->SetRegister(a0.code(), params);
+  output_frame->SetRegister(a1.code(), handler);
 }
 
 
diff --git a/src/mips/disasm-mips.cc b/src/mips/disasm-mips.cc
index 564627e..4f725cf 100644
--- a/src/mips/disasm-mips.cc
+++ b/src/mips/disasm-mips.cc
@@ -555,7 +555,13 @@
           }
           break;
         case S:
-          UNIMPLEMENTED_MIPS();
+          switch (instr->FunctionFieldRaw()) {
+            case CVT_D_S:
+              Format(instr, "cvt.d.s 'fd, 'fs");
+              break;
+            default:
+              UNIMPLEMENTED_MIPS();
+          }
           break;
         case W:
           switch (instr->FunctionFieldRaw()) {
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 1dbfe09..c1a8291 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -204,10 +204,10 @@
     Comment cmnt(masm_, "[ Allocate context");
     // Argument to NewContext is the function, which is still in a1.
     bool need_write_barrier = true;
-    if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
+    if (FLAG_harmony_scoping && info->scope()->is_script_scope()) {
       __ push(a1);
       __ Push(info->scope()->GetScopeInfo());
-      __ CallRuntime(Runtime::kNewGlobalContext, 2);
+      __ CallRuntime(Runtime::kNewScriptContext, 2);
     } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
       FastNewContextStub stub(isolate(), heap_slots);
       __ CallStub(&stub);
@@ -929,7 +929,7 @@
   EmitDebugCheckDeclarationContext(variable);
 
   // Load instance object.
-  __ LoadContext(a1, scope_->ContextChainLength(scope_->GlobalScope()));
+  __ LoadContext(a1, scope_->ContextChainLength(scope_->ScriptScope()));
   __ lw(a1, ContextOperand(a1, variable->interface()->Index()));
   __ lw(a1, ContextOperand(a1, Context::EXTENSION_INDEX));
 
@@ -1093,7 +1093,7 @@
 
 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
   Comment cmnt(masm_, "[ ForInStatement");
-  int slot = stmt->ForInFeedbackSlot();
+  FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
   SetStatementPosition(stmt);
 
   Label loop, exit;
@@ -1102,6 +1102,7 @@
 
   // Get the object to enumerate over. If the object is null or undefined, skip
   // over the loop.  See ECMA-262 version 5, section 12.6.4.
+  SetExpressionPosition(stmt->enumerable());
   VisitForAccumulatorValue(stmt->enumerable());
   __ mov(a0, result_register());  // Result as param to InvokeBuiltin below.
   __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
@@ -1121,6 +1122,7 @@
   __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
   __ mov(a0, v0);
   __ bind(&done_convert);
+  PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
   __ push(a0);
 
   // Check for proxies.
@@ -1145,6 +1147,7 @@
   __ bind(&call_runtime);
   __ push(a0);  // Duplicate the enumerable object on the stack.
   __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
+  PrepareForBailoutForId(stmt->EnumId(), TOS_REG);
 
   // If we got a map from the runtime call, we can do a fast
   // modification check. Otherwise, we got a fixed array, and we have
@@ -1181,7 +1184,8 @@
 
   __ li(a1, FeedbackVector());
   __ li(a2, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate())));
-  __ sw(a2, FieldMemOperand(a1, FixedArray::OffsetOfElementAt(slot)));
+  int vector_index = FeedbackVector()->GetIndex(slot);
+  __ sw(a2, FieldMemOperand(a1, FixedArray::OffsetOfElementAt(vector_index)));
 
   __ li(a1, Operand(Smi::FromInt(1)));  // Smi indicates slow check
   __ lw(a2, MemOperand(sp, 0 * kPointerSize));  // Get enumerated object
@@ -1198,6 +1202,8 @@
   // Generate code for doing the condition check.
   PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
   __ bind(&loop);
+  SetExpressionPosition(stmt->each());
+
   // Load the current count to a0, load the length to a1.
   __ lw(a0, MemOperand(sp, 0 * kPointerSize));
   __ lw(a1, MemOperand(sp, 1 * kPointerSize));
@@ -1267,48 +1273,6 @@
 }
 
 
-void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
-  Comment cmnt(masm_, "[ ForOfStatement");
-  SetStatementPosition(stmt);
-
-  Iteration loop_statement(this, stmt);
-  increment_loop_depth();
-
-  // var iterator = iterable[Symbol.iterator]();
-  VisitForEffect(stmt->assign_iterator());
-
-  // Loop entry.
-  __ bind(loop_statement.continue_label());
-
-  // result = iterator.next()
-  VisitForEffect(stmt->next_result());
-
-  // if (result.done) break;
-  Label result_not_done;
-  VisitForControl(stmt->result_done(),
-                  loop_statement.break_label(),
-                  &result_not_done,
-                  &result_not_done);
-  __ bind(&result_not_done);
-
-  // each = result.value
-  VisitForEffect(stmt->assign_each());
-
-  // Generate code for the body of the loop.
-  Visit(stmt->body());
-
-  // Check stack before looping.
-  PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
-  EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
-  __ jmp(loop_statement.continue_label());
-
-  // Exit and decrement the loop depth.
-  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
-  __ bind(loop_statement.break_label());
-  decrement_loop_depth();
-}
-
-
 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
                                        bool pretenure) {
   // Use the fast case closure allocation code that allocates in new
@@ -1351,7 +1315,13 @@
   Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
   __ li(LoadDescriptor::NameRegister(), home_object_symbol);
 
-  CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  if (FLAG_vector_ics) {
+    __ li(VectorLoadICDescriptor::SlotRegister(),
+          Operand(SmiFromSlot(expr->HomeObjectFeedbackSlot())));
+    CallLoadIC(NOT_CONTEXTUAL);
+  } else {
+    CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  }
 
   Label done;
   __ Branch(&done, ne, v0, Operand(isolate()->factory()->undefined_value()));
@@ -1360,6 +1330,19 @@
 }
 
 
+void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
+                                                  int offset) {
+  if (NeedsHomeObject(initializer)) {
+    __ lw(StoreDescriptor::ReceiverRegister(), MemOperand(sp));
+    __ li(StoreDescriptor::NameRegister(),
+          Operand(isolate()->factory()->home_object_symbol()));
+    __ lw(StoreDescriptor::ValueRegister(),
+          MemOperand(sp, offset * kPointerSize));
+    CallStoreIC();
+  }
+}
+
+
 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
                                                       TypeofState typeof_state,
                                                       Label* slow) {
@@ -1409,7 +1392,7 @@
   __ li(LoadDescriptor::NameRegister(), Operand(proxy->var()->name()));
   if (FLAG_vector_ics) {
     __ li(VectorLoadICDescriptor::SlotRegister(),
-          Operand(Smi::FromInt(proxy->VariableFeedbackSlot())));
+          Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
   }
 
   ContextualMode mode = (typeof_state == INSIDE_TYPEOF)
@@ -1498,7 +1481,7 @@
       __ li(LoadDescriptor::NameRegister(), Operand(var->name()));
       if (FLAG_vector_ics) {
         __ li(VectorLoadICDescriptor::SlotRegister(),
-              Operand(Smi::FromInt(proxy->VariableFeedbackSlot())));
+              Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
       }
       CallLoadIC(CONTEXTUAL);
       context()->Plug(v0);
@@ -1676,6 +1659,7 @@
     FastCloneShallowObjectStub stub(isolate(), properties_count);
     __ CallStub(&stub);
   }
+  PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
 
   // If result_saved is true the result is on top of the stack.  If
   // result_saved is false the result is in v0.
@@ -1704,6 +1688,8 @@
         DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
         // Fall through.
       case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             VisitForAccumulatorValue(value);
@@ -1713,6 +1699,14 @@
             __ lw(StoreDescriptor::ReceiverRegister(), MemOperand(sp));
             CallStoreIC(key->LiteralFeedbackId());
             PrepareForBailoutForId(key->id(), NO_REGISTERS);
+
+            if (NeedsHomeObject(value)) {
+              __ Move(StoreDescriptor::ReceiverRegister(), v0);
+              __ li(StoreDescriptor::NameRegister(),
+                    Operand(isolate()->factory()->home_object_symbol()));
+              __ lw(StoreDescriptor::ValueRegister(), MemOperand(sp));
+              CallStoreIC();
+            }
           } else {
             VisitForEffect(value);
           }
@@ -1724,6 +1718,7 @@
         VisitForStackValue(key);
         VisitForStackValue(value);
         if (property->emit_store()) {
+          EmitSetHomeObjectIfNeeded(value, 2);
           __ li(a0, Operand(Smi::FromInt(SLOPPY)));  // PropertyAttributes.
           __ push(a0);
           __ CallRuntime(Runtime::kSetProperty, 4);
@@ -1737,7 +1732,7 @@
         __ push(a0);
         VisitForStackValue(value);
         if (property->emit_store()) {
-          __ CallRuntime(Runtime::kSetPrototype, 2);
+          __ CallRuntime(Runtime::kInternalSetPrototype, 2);
         } else {
           __ Drop(2);
         }
@@ -1760,7 +1755,9 @@
     __ push(a0);
     VisitForStackValue(it->first);
     EmitAccessor(it->second->getter);
+    EmitSetHomeObjectIfNeeded(it->second->getter, 2);
     EmitAccessor(it->second->setter);
+    EmitSetHomeObjectIfNeeded(it->second->setter, 3);
     __ li(a0, Operand(Smi::FromInt(NONE)));
     __ push(a0);
     __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
@@ -1872,16 +1869,8 @@
 
   Comment cmnt(masm_, "[ Assignment");
 
-  // Left-hand side can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* property = expr->target()->AsProperty();
-  if (property != NULL) {
-    assign_type = (property->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(property);
 
   // Evaluate LHS expression.
   switch (assign_type) {
@@ -1897,6 +1886,30 @@
         VisitForStackValue(property->obj());
       }
       break;
+    case NAMED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Push(result_register());
+      if (expr->is_compound()) {
+        const Register scratch = a1;
+        __ lw(scratch, MemOperand(sp, kPointerSize));
+        __ Push(scratch, result_register());
+      }
+      break;
+    case KEYED_SUPER_PROPERTY: {
+      const Register scratch = a1;
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Move(scratch, result_register());
+      VisitForAccumulatorValue(property->key());
+      __ Push(scratch, result_register());
+      if (expr->is_compound()) {
+        const Register scratch1 = t0;
+        __ lw(scratch1, MemOperand(sp, 2 * kPointerSize));
+        __ Push(scratch1, scratch, result_register());
+      }
+      break;
+    }
     case KEYED_PROPERTY:
       // We need the key and receiver on both the stack and in v0 and a1.
       if (expr->is_compound()) {
@@ -1925,6 +1938,14 @@
           EmitNamedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
           break;
+        case NAMED_SUPER_PROPERTY:
+          EmitNamedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
+        case KEYED_SUPER_PROPERTY:
+          EmitKeyedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
         case KEYED_PROPERTY:
           EmitKeyedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
@@ -1971,6 +1992,14 @@
     case NAMED_PROPERTY:
       EmitNamedPropertyAssignment(expr);
       break;
+    case NAMED_SUPER_PROPERTY:
+      EmitNamedSuperPropertyStore(property);
+      context()->Plug(v0);
+      break;
+    case KEYED_SUPER_PROPERTY:
+      EmitKeyedSuperPropertyStore(property);
+      context()->Plug(v0);
+      break;
     case KEYED_PROPERTY:
       EmitKeyedPropertyAssignment(expr);
       break;
@@ -2102,7 +2131,7 @@
       __ lw(load_name, MemOperand(sp, 2 * kPointerSize));
       if (FLAG_vector_ics) {
         __ li(VectorLoadICDescriptor::SlotRegister(),
-              Operand(Smi::FromInt(expr->KeyedLoadFeedbackSlot())));
+              Operand(SmiFromSlot(expr->KeyedLoadFeedbackSlot())));
       }
       Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
       CallIC(ic, TypeFeedbackId::None());
@@ -2122,7 +2151,7 @@
       __ LoadRoot(load_name, Heap::kdone_stringRootIndex);  // "done"
       if (FLAG_vector_ics) {
         __ li(VectorLoadICDescriptor::SlotRegister(),
-              Operand(Smi::FromInt(expr->DoneFeedbackSlot())));
+              Operand(SmiFromSlot(expr->DoneFeedbackSlot())));
       }
       CallLoadIC(NOT_CONTEXTUAL);                           // v0=result.done
       __ mov(a0, v0);
@@ -2135,7 +2164,7 @@
       __ LoadRoot(load_name, Heap::kvalue_stringRootIndex);  // "value"
       if (FLAG_vector_ics) {
         __ li(VectorLoadICDescriptor::SlotRegister(),
-              Operand(Smi::FromInt(expr->ValueFeedbackSlot())));
+              Operand(SmiFromSlot(expr->ValueFeedbackSlot())));
       }
       CallLoadIC(NOT_CONTEXTUAL);                            // v0=result.value
       context()->DropAndPlug(2, v0);                         // drop iter and g
@@ -2156,14 +2185,6 @@
   VisitForAccumulatorValue(value);
   __ pop(a1);
 
-  // Check generator state.
-  Label wrong_state, closed_state, done;
-  __ lw(a3, FieldMemOperand(a1, JSGeneratorObject::kContinuationOffset));
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
-  __ Branch(&closed_state, eq, a3, Operand(zero_reg));
-  __ Branch(&wrong_state, lt, a3, Operand(zero_reg));
-
   // Load suspended function and context.
   __ lw(cp, FieldMemOperand(a1, JSGeneratorObject::kContextOffset));
   __ lw(t0, FieldMemOperand(a1, JSGeneratorObject::kFunctionOffset));
@@ -2186,7 +2207,7 @@
 
   // Enter a new JavaScript frame, and initialize its slots as they were when
   // the generator was suspended.
-  Label resume_frame;
+  Label resume_frame, done;
   __ bind(&push_frame);
   __ Call(&resume_frame);
   __ jmp(&done);
@@ -2235,26 +2256,6 @@
   // Not reached: the runtime call returns elsewhere.
   __ stop("not-reached");
 
-  // Reach here when generator is closed.
-  __ bind(&closed_state);
-  if (resume_mode == JSGeneratorObject::NEXT) {
-    // Return completed iterator result when generator is closed.
-    __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
-    __ push(a2);
-    // Pop value from top-of-stack slot; box result into result register.
-    EmitCreateIteratorResult(true);
-  } else {
-    // Throw the provided value.
-    __ push(a0);
-    __ CallRuntime(Runtime::kThrow, 1);
-  }
-  __ jmp(&done);
-
-  // Throw error if we attempt to operate on a running generator.
-  __ bind(&wrong_state);
-  __ push(a1);
-  __ CallRuntime(Runtime::kThrowGeneratorStateError, 1);
-
   __ bind(&done);
   context()->Plug(result_register());
 }
@@ -2302,11 +2303,12 @@
 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
+  DCHECK(!prop->IsSuperAccess());
 
   __ li(LoadDescriptor::NameRegister(), Operand(key->value()));
   if (FLAG_vector_ics) {
     __ li(VectorLoadICDescriptor::SlotRegister(),
-          Operand(Smi::FromInt(prop->PropertyFeedbackSlot())));
+          Operand(SmiFromSlot(prop->PropertyFeedbackSlot())));
     CallLoadIC(NOT_CONTEXTUAL);
   } else {
     CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
@@ -2315,15 +2317,12 @@
 
 
 void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object.
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
   DCHECK(!key->value()->IsSmi());
   DCHECK(prop->IsSuperAccess());
 
-  SuperReference* super_ref = prop->obj()->AsSuperReference();
-  EmitLoadHomeObject(super_ref);
-  __ Push(v0);
-  VisitForStackValue(super_ref->this_var());
   __ Push(key->value());
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 }
@@ -2334,7 +2333,7 @@
   Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
   if (FLAG_vector_ics) {
     __ li(VectorLoadICDescriptor::SlotRegister(),
-          Operand(Smi::FromInt(prop->PropertyFeedbackSlot())));
+          Operand(SmiFromSlot(prop->PropertyFeedbackSlot())));
     CallIC(ic);
   } else {
     CallIC(ic, prop->PropertyFeedbackId());
@@ -2342,6 +2341,14 @@
 }
 
 
+void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object, key.
+  SetSourcePosition(prop->position());
+
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+}
+
+
 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
                                               Token::Value op,
                                               OverwriteMode mode,
@@ -2435,6 +2442,63 @@
 }
 
 
+void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
+  // Constructor is in v0.
+  DCHECK(lit != NULL);
+  __ push(v0);
+
+  // No access check is needed here since the constructor is created by the
+  // class literal.
+  Register scratch = a1;
+  __ lw(scratch,
+        FieldMemOperand(v0, JSFunction::kPrototypeOrInitialMapOffset));
+  __ push(scratch);
+
+  for (int i = 0; i < lit->properties()->length(); i++) {
+    ObjectLiteral::Property* property = lit->properties()->at(i);
+    Literal* key = property->key()->AsLiteral();
+    Expression* value = property->value();
+    DCHECK(key != NULL);
+
+    if (property->is_static()) {
+      __ lw(scratch, MemOperand(sp, kPointerSize));  // constructor
+    } else {
+      __ lw(scratch, MemOperand(sp, 0));  // prototype
+    }
+    __ push(scratch);
+    VisitForStackValue(key);
+    VisitForStackValue(value);
+    EmitSetHomeObjectIfNeeded(value, 2);
+
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT:
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+      case ObjectLiteral::Property::COMPUTED:
+      case ObjectLiteral::Property::PROTOTYPE:
+        __ CallRuntime(Runtime::kDefineClassMethod, 3);
+        break;
+
+      case ObjectLiteral::Property::GETTER:
+        __ CallRuntime(Runtime::kDefineClassGetter, 3);
+        break;
+
+      case ObjectLiteral::Property::SETTER:
+        __ CallRuntime(Runtime::kDefineClassSetter, 3);
+        break;
+
+      default:
+        UNREACHABLE();
+    }
+  }
+
+  // prototype
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+
+  // constructor
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+}
+
+
 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
                                      Token::Value op,
                                      OverwriteMode mode) {
@@ -2451,16 +2515,8 @@
 void FullCodeGenerator::EmitAssignment(Expression* expr) {
   DCHECK(expr->IsValidReferenceExpression());
 
-  // Left-hand side can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* prop = expr->AsProperty();
-  if (prop != NULL) {
-    assign_type = (prop->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(prop);
 
   switch (assign_type) {
     case VARIABLE: {
@@ -2479,6 +2535,42 @@
       CallStoreIC();
       break;
     }
+    case NAMED_SUPER_PROPERTY: {
+      __ Push(v0);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      // stack: value, this; v0: home_object
+      Register scratch = a2;
+      Register scratch2 = a3;
+      __ mov(scratch, result_register());             // home_object
+      __ lw(v0, MemOperand(sp, kPointerSize));        // value
+      __ lw(scratch2, MemOperand(sp, 0));             // this
+      __ sw(scratch2, MemOperand(sp, kPointerSize));  // this
+      __ sw(scratch, MemOperand(sp, 0));              // home_object
+      // stack: this, home_object; v0: value
+      EmitNamedSuperPropertyStore(prop);
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      __ Push(v0);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForAccumulatorValue(prop->key());
+      Register scratch = a2;
+      Register scratch2 = a3;
+      __ lw(scratch2, MemOperand(sp, 2 * kPointerSize));  // value
+      // stack: value, this, home_object; v0: key, a3: value
+      __ lw(scratch, MemOperand(sp, kPointerSize));  // this
+      __ sw(scratch, MemOperand(sp, 2 * kPointerSize));
+      __ lw(scratch, MemOperand(sp, 0));  // home_object
+      __ sw(scratch, MemOperand(sp, kPointerSize));
+      __ sw(v0, MemOperand(sp, 0));
+      __ Move(v0, scratch2);
+      // stack: this, home_object, key; v0: value.
+      EmitKeyedSuperPropertyStore(prop);
+      break;
+    }
     case KEYED_PROPERTY: {
       __ push(result_register());  // Preserve value.
       VisitForStackValue(prop->obj());
@@ -2550,7 +2642,6 @@
     // Perform the assignment.
     __ bind(&assign);
     EmitStoreToStackLocalOrContextSlot(var, location);
-
   } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
     if (var->IsLookupSlot()) {
       // Assignment to var.
@@ -2571,8 +2662,9 @@
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
+  } else if (IsSignallingAssignmentToConst(var, op, strict_mode())) {
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
   }
-  // Non-initializing assignments to consts are ignored.
 }
 
 
@@ -2595,6 +2687,35 @@
 }
 
 
+void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // v0 : value
+  // stack : receiver ('this'), home_object
+  DCHECK(prop != NULL);
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(key != NULL);
+
+  __ Push(key->value());
+  __ Push(v0);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
+                                          : Runtime::kStoreToSuper_Sloppy),
+                 4);
+}
+
+
+void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // v0 : value
+  // stack : receiver ('this'), home_object, key
+  DCHECK(prop != NULL);
+
+  __ Push(v0);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict
+                                          : Runtime::kStoreKeyedToSuper_Sloppy),
+                 4);
+}
+
+
 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
   // Assignment to a property, using a keyed store IC.
 
@@ -2627,16 +2748,27 @@
       __ Move(LoadDescriptor::ReceiverRegister(), v0);
       EmitNamedPropertyLoad(expr);
     } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
       EmitNamedSuperPropertyLoad(expr);
     }
     PrepareForBailoutForId(expr->LoadId(), TOS_REG);
     context()->Plug(v0);
   } else {
-    VisitForStackValue(expr->obj());
-    VisitForAccumulatorValue(expr->key());
-    __ Move(LoadDescriptor::NameRegister(), v0);
-    __ pop(LoadDescriptor::ReceiverRegister());
-    EmitKeyedPropertyLoad(expr);
+    if (!expr->IsSuperAccess()) {
+      VisitForStackValue(expr->obj());
+      VisitForAccumulatorValue(expr->key());
+      __ Move(LoadDescriptor::NameRegister(), v0);
+      __ pop(LoadDescriptor::ReceiverRegister());
+      EmitKeyedPropertyLoad(expr);
+    } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForStackValue(expr->key());
+      EmitKeyedSuperPropertyLoad(expr);
+    }
     context()->Plug(v0);
   }
 }
@@ -2695,18 +2827,16 @@
   const Register scratch = a1;
   SuperReference* super_ref = prop->obj()->AsSuperReference();
   EmitLoadHomeObject(super_ref);
-  __ Push(v0);
+  __ mov(scratch, v0);
   VisitForAccumulatorValue(super_ref->this_var());
-  __ Push(v0);
-  __ lw(scratch, MemOperand(sp, kPointerSize));
-  __ Push(scratch, v0);
+  __ Push(scratch, v0, v0, scratch);
   __ Push(key->value());
 
   // Stack here:
   //  - home_object
   //  - this (receiver)
-  //  - home_object <-- LoadFromSuper will pop here and below.
-  //  - this (receiver)
+  //  - this (receiver) <-- LoadFromSuper will pop here and below.
+  //  - home_object
   //  - key
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 
@@ -2744,6 +2874,40 @@
 }
 
 
+void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
+  Expression* callee = expr->expression();
+  DCHECK(callee->IsProperty());
+  Property* prop = callee->AsProperty();
+  DCHECK(prop->IsSuperAccess());
+
+  SetSourcePosition(prop->position());
+  // Load the function from the receiver.
+  const Register scratch = a1;
+  SuperReference* super_ref = prop->obj()->AsSuperReference();
+  EmitLoadHomeObject(super_ref);
+  __ Move(scratch, v0);
+  VisitForAccumulatorValue(super_ref->this_var());
+  __ Push(scratch, v0, v0, scratch);
+  VisitForStackValue(prop->key());
+
+  // Stack here:
+  //  - home_object
+  //  - this (receiver)
+  //  - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
+  //  - home_object
+  //  - key
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+
+  // Replace home_object with target function.
+  __ sw(v0, MemOperand(sp, kPointerSize));
+
+  // Stack here:
+  // - target function
+  // - this (receiver)
+  EmitCall(expr, CallICState::METHOD);
+}
+
+
 void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
   // Load the arguments.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2758,7 +2922,7 @@
   SetSourcePosition(expr->position());
   Handle<Code> ic = CallIC::initialize_stub(
       isolate(), arg_count, call_type);
-  __ li(a3, Operand(Smi::FromInt(expr->CallFeedbackSlot())));
+  __ li(a3, Operand(SmiFromSlot(expr->CallFeedbackSlot())));
   __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
   // Don't assign a type feedback id to the IC, since type feedback is provided
   // by the vector above.
@@ -2799,6 +2963,14 @@
 }
 
 
+void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
+  DCHECK(super_ref != NULL);
+  __ lw(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ Push(a0);
+  __ CallRuntime(Runtime::kGetPrototype, 1);
+}
+
+
 void FullCodeGenerator::VisitCall(Call* expr) {
 #ifdef DEBUG
   // We want to verify that RecordJSReturnSite gets called on all paths
@@ -2838,6 +3010,8 @@
       // v1 (receiver). Touch up the stack with the right values.
       __ sw(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
       __ sw(v1, MemOperand(sp, arg_count * kPointerSize));
+
+      PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
     }
     // Record source position for debugger.
     SetSourcePosition(expr->position());
@@ -2869,6 +3043,7 @@
     __ Push(context_register(), a2);
     __ CallRuntime(Runtime::kLoadLookupSlot, 2);
     __ Push(v0, v1);  // Function, receiver.
+    PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
 
     // If fast case code has been generated, emit code to push the
     // function and receiver and have the slow path jump around this
@@ -2892,9 +3067,12 @@
   } else if (call_type == Call::PROPERTY_CALL) {
     Property* property = callee->AsProperty();
     bool is_named_call = property->key()->IsPropertyName();
-    // super.x() is handled in EmitCallWithLoadIC.
-    if (property->IsSuperAccess() && is_named_call) {
-      EmitSuperCallWithLoadIC(expr);
+    if (property->IsSuperAccess()) {
+      if (is_named_call) {
+        EmitSuperCallWithLoadIC(expr);
+      } else {
+        EmitKeyedSuperCallWithLoadIC(expr);
+      }
     } else {
       {
         PreservePositionScope scope(masm()->positions_recorder());
@@ -2906,6 +3084,12 @@
         EmitKeyedCallWithLoadIC(expr, property->key());
       }
     }
+  } else if (call_type == Call::SUPER_CALL) {
+    SuperReference* super_ref = callee->AsSuperReference();
+    EmitLoadSuperConstructor(super_ref);
+    __ Push(result_register());
+    VisitForStackValue(super_ref->this_var());
+    EmitCall(expr, CallICState::METHOD);
   } else {
     DCHECK(call_type == Call::OTHER_CALL);
     // Call to an arbitrary expression not handled specially above.
@@ -2934,7 +3118,12 @@
   // Push constructor on the stack.  If it's not a function it's used as
   // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
   // ignored.
-  VisitForStackValue(expr->expression());
+  if (expr->expression()->IsSuperReference()) {
+    EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
+    __ Push(result_register());
+  } else {
+    VisitForStackValue(expr->expression());
+  }
 
   // Push the arguments ("left-to-right") on the stack.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2954,12 +3143,12 @@
   // Record call targets in unoptimized code.
   if (FLAG_pretenuring_call_new) {
     EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
-    DCHECK(expr->AllocationSiteFeedbackSlot() ==
-           expr->CallNewFeedbackSlot() + 1);
+    DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
+           expr->CallNewFeedbackSlot().ToInt() + 1);
   }
 
   __ li(a2, FeedbackVector());
-  __ li(a3, Operand(Smi::FromInt(expr->CallNewFeedbackSlot())));
+  __ li(a3, Operand(SmiFromSlot(expr->CallNewFeedbackSlot())));
 
   CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
@@ -3274,6 +3463,32 @@
 }
 
 
+void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ JumpIfSmi(v0, if_false);
+  Register map = a1;
+  Register type_reg = a2;
+  __ GetObjectType(v0, map, type_reg);
+  __ Subu(type_reg, type_reg, Operand(FIRST_JS_PROXY_TYPE));
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(ls, type_reg, Operand(LAST_JS_PROXY_TYPE - FIRST_JS_PROXY_TYPE),
+        if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
 void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
   DCHECK(expr->arguments()->length() == 0);
 
@@ -4191,7 +4406,7 @@
     __ li(LoadDescriptor::NameRegister(), Operand(expr->name()));
     if (FLAG_vector_ics) {
       __ li(VectorLoadICDescriptor::SlotRegister(),
-            Operand(Smi::FromInt(expr->CallRuntimeFeedbackSlot())));
+            Operand(SmiFromSlot(expr->CallRuntimeFeedbackSlot())));
       CallLoadIC(NOT_CONTEXTUAL);
     } else {
       CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
@@ -4347,17 +4562,8 @@
   Comment cmnt(masm_, "[ CountOperation");
   SetSourcePosition(expr->position());
 
-  // Expression can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* prop = expr->expression()->AsProperty();
-  // In case of a property we use the uninitialized expression context
-  // of the key to detect a named property.
-  if (prop != NULL) {
-    assign_type =
-        (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(prop);
 
   // Evaluate expression and get value.
   if (assign_type == VARIABLE) {
@@ -4370,18 +4576,52 @@
       __ li(at, Operand(Smi::FromInt(0)));
       __ push(at);
     }
-    if (assign_type == NAMED_PROPERTY) {
-      // Put the object both on the stack and in the register.
-      VisitForStackValue(prop->obj());
-      __ lw(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
-      EmitNamedPropertyLoad(prop);
-    } else {
-      VisitForStackValue(prop->obj());
-      VisitForStackValue(prop->key());
-      __ lw(LoadDescriptor::ReceiverRegister(),
-            MemOperand(sp, 1 * kPointerSize));
-      __ lw(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
-      EmitKeyedPropertyLoad(prop);
+    switch (assign_type) {
+      case NAMED_PROPERTY: {
+        // Put the object both on the stack and in the register.
+        VisitForStackValue(prop->obj());
+        __ lw(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
+        EmitNamedPropertyLoad(prop);
+        break;
+      }
+
+      case NAMED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        __ Push(result_register());
+        const Register scratch = a1;
+        __ lw(scratch, MemOperand(sp, kPointerSize));
+        __ Push(scratch, result_register());
+        EmitNamedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        const Register scratch = a1;
+        const Register scratch1 = t0;
+        __ Move(scratch, result_register());
+        VisitForAccumulatorValue(prop->key());
+        __ Push(scratch, result_register());
+        __ lw(scratch1, MemOperand(sp, 2 * kPointerSize));
+        __ Push(scratch1, scratch, result_register());
+        EmitKeyedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_PROPERTY: {
+        VisitForStackValue(prop->obj());
+        VisitForStackValue(prop->key());
+        __ lw(LoadDescriptor::ReceiverRegister(),
+              MemOperand(sp, 1 * kPointerSize));
+        __ lw(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
+        EmitKeyedPropertyLoad(prop);
+        break;
+      }
+
+      case VARIABLE:
+        UNREACHABLE();
     }
   }
 
@@ -4416,9 +4656,15 @@
           case NAMED_PROPERTY:
             __ sw(v0, MemOperand(sp, kPointerSize));
             break;
+          case NAMED_SUPER_PROPERTY:
+            __ sw(v0, MemOperand(sp, 2 * kPointerSize));
+            break;
           case KEYED_PROPERTY:
             __ sw(v0, MemOperand(sp, 2 * kPointerSize));
             break;
+          case KEYED_SUPER_PROPERTY:
+            __ sw(v0, MemOperand(sp, 3 * kPointerSize));
+            break;
         }
       }
     }
@@ -4449,9 +4695,15 @@
         case NAMED_PROPERTY:
           __ sw(v0, MemOperand(sp, kPointerSize));
           break;
+        case NAMED_SUPER_PROPERTY:
+          __ sw(v0, MemOperand(sp, 2 * kPointerSize));
+          break;
         case KEYED_PROPERTY:
           __ sw(v0, MemOperand(sp, 2 * kPointerSize));
           break;
+        case KEYED_SUPER_PROPERTY:
+          __ sw(v0, MemOperand(sp, 3 * kPointerSize));
+          break;
       }
     }
   }
@@ -4507,6 +4759,28 @@
       }
       break;
     }
+    case NAMED_SUPER_PROPERTY: {
+      EmitNamedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(v0);
+      }
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      EmitKeyedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(v0);
+      }
+      break;
+    }
     case KEYED_PROPERTY: {
       __ mov(StoreDescriptor::ValueRegister(), result_register());
       __ Pop(StoreDescriptor::ReceiverRegister(),
@@ -4538,7 +4812,7 @@
     __ li(LoadDescriptor::NameRegister(), Operand(proxy->name()));
     if (FLAG_vector_ics) {
       __ li(VectorLoadICDescriptor::SlotRegister(),
-            Operand(Smi::FromInt(proxy->VariableFeedbackSlot())));
+            Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
     }
     // Use a regular load, not a contextual load, to avoid a reference
     // error.
@@ -4768,7 +5042,7 @@
 
 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
   Scope* declaration_scope = scope()->DeclarationScope();
-  if (declaration_scope->is_global_scope() ||
+  if (declaration_scope->is_script_scope() ||
       declaration_scope->is_module_scope()) {
     // Contexts nested in the native context have a canonical empty function
     // as their closure, not the anonymous closure containing the global
diff --git a/src/mips/interface-descriptors-mips.cc b/src/mips/interface-descriptors-mips.cc
index 936ce20..ecdaecf 100644
--- a/src/mips/interface-descriptors-mips.cc
+++ b/src/mips/interface-descriptors-mips.cc
@@ -29,6 +29,9 @@
 const Register StoreDescriptor::ValueRegister() { return a0; }
 
 
+const Register StoreTransitionDescriptor::MapRegister() { return a3; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() { return a3; }
 
 
@@ -149,6 +152,15 @@
 }
 
 
+void AllocateHeapNumberDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // register state
+  // cp -- context
+  Register registers[] = {cp};
+  data->Initialize(arraysize(registers), registers, nullptr);
+}
+
+
 void ArrayConstructorConstantArgCountDescriptor::Initialize(
     CallInterfaceDescriptorData* data) {
   // register state
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index 497d10f..cdc68c8 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -51,9 +51,9 @@
         deopt_mode_(mode) { }
   virtual ~SafepointGenerator() {}
 
-  virtual void BeforeCall(int call_size) const OVERRIDE {}
+  void BeforeCall(int call_size) const OVERRIDE {}
 
-  virtual void AfterCall() const OVERRIDE {
+  void AfterCall() const OVERRIDE {
     codegen_->RecordSafepoint(pointers_, deopt_mode_);
   }
 
@@ -816,8 +816,8 @@
 
 void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
                             Deoptimizer::BailoutType bailout_type,
-                            Register src1, const Operand& src2,
-                            const char* detail) {
+                            const char* detail, Register src1,
+                            const Operand& src2) {
   LEnvironment* environment = instr->environment();
   RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
   DCHECK(environment->HasBeenRegistered());
@@ -882,12 +882,12 @@
 
 
 void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
-                            Register src1, const Operand& src2,
-                            const char* detail) {
+                            const char* detail, Register src1,
+                            const Operand& src2) {
   Deoptimizer::BailoutType bailout_type = info()->IsStub()
       ? Deoptimizer::LAZY
       : Deoptimizer::EAGER;
-  DeoptimizeIf(condition, instr, bailout_type, src1, src2, detail);
+  DeoptimizeIf(condition, instr, bailout_type, detail, src1, src2);
 }
 
 
@@ -1117,7 +1117,7 @@
     __ subu(dividend, zero_reg, dividend);
     __ And(dividend, dividend, Operand(mask));
     if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
-      DeoptimizeIf(eq, instr, dividend, Operand(zero_reg));
+      DeoptimizeIf(eq, instr, "minus zero", dividend, Operand(zero_reg));
     }
     __ Branch(USE_DELAY_SLOT, &done);
     __ subu(dividend, zero_reg, dividend);
@@ -1149,7 +1149,7 @@
   if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
     Label remainder_not_zero;
     __ Branch(&remainder_not_zero, ne, result, Operand(zero_reg));
-    DeoptimizeIf(lt, instr, dividend, Operand(zero_reg));
+    DeoptimizeIf(lt, instr, "minus zero", dividend, Operand(zero_reg));
     __ bind(&remainder_not_zero);
   }
 }
@@ -1168,7 +1168,7 @@
   // Check for x % 0, we have to deopt in this case because we can't return a
   // NaN.
   if (hmod->CheckFlag(HValue::kCanBeDivByZero)) {
-    DeoptimizeIf(eq, instr, right_reg, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "division by zero", right_reg, Operand(zero_reg));
   }
 
   // Check for kMinInt % -1, div will return kMinInt, which is not what we
@@ -1177,7 +1177,7 @@
     Label no_overflow_possible;
     __ Branch(&no_overflow_possible, ne, left_reg, Operand(kMinInt));
     if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
-      DeoptimizeIf(eq, instr, right_reg, Operand(-1));
+      DeoptimizeIf(eq, instr, "minus zero", right_reg, Operand(-1));
     } else {
       __ Branch(&no_overflow_possible, ne, right_reg, Operand(-1));
       __ Branch(USE_DELAY_SLOT, &done);
@@ -1189,7 +1189,7 @@
   // If we care about -0, test if the dividend is <0 and the result is 0.
   __ Branch(&done, ge, left_reg, Operand(zero_reg));
   if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
-    DeoptimizeIf(eq, instr, result_reg, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "minus zero", result_reg, Operand(zero_reg));
   }
   __ bind(&done);
 }
@@ -1205,18 +1205,18 @@
   // Check for (0 / -x) that will produce negative zero.
   HDiv* hdiv = instr->hydrogen();
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
-    DeoptimizeIf(eq, instr, dividend, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "minus zero", dividend, Operand(zero_reg));
   }
   // Check for (kMinInt / -1).
   if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) {
-    DeoptimizeIf(eq, instr, dividend, Operand(kMinInt));
+    DeoptimizeIf(eq, instr, "overflow", dividend, Operand(kMinInt));
   }
   // Deoptimize if remainder will not be 0.
   if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
       divisor != 1 && divisor != -1) {
     int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
     __ And(at, dividend, Operand(mask));
-    DeoptimizeIf(ne, instr, at, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "lost precision", at, Operand(zero_reg));
   }
 
   if (divisor == -1) {  // Nice shortcut, not needed for correctness.
@@ -1253,7 +1253,7 @@
   // Check for (0 / -x) that will produce negative zero.
   HDiv* hdiv = instr->hydrogen();
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
-    DeoptimizeIf(eq, instr, dividend, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "minus zero", dividend, Operand(zero_reg));
   }
 
   __ TruncatingDiv(result, dividend, Abs(divisor));
@@ -1262,7 +1262,7 @@
   if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
     __ Mul(scratch0(), result, Operand(divisor));
     __ Subu(scratch0(), scratch0(), dividend);
-    DeoptimizeIf(ne, instr, scratch0(), Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "lost precision", scratch0(), Operand(zero_reg));
   }
 }
 
@@ -1281,14 +1281,14 @@
 
   // Check for x / 0.
   if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
-    DeoptimizeIf(eq, instr, divisor, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "division by zero", divisor, Operand(zero_reg));
   }
 
   // Check for (0 / -x) that will produce negative zero.
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
     Label left_not_zero;
     __ Branch(&left_not_zero, ne, dividend, Operand(zero_reg));
-    DeoptimizeIf(lt, instr, divisor, Operand(zero_reg));
+    DeoptimizeIf(lt, instr, "minus zero", divisor, Operand(zero_reg));
     __ bind(&left_not_zero);
   }
 
@@ -1297,12 +1297,12 @@
       !hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
     Label left_not_min_int;
     __ Branch(&left_not_min_int, ne, dividend, Operand(kMinInt));
-    DeoptimizeIf(eq, instr, divisor, Operand(-1));
+    DeoptimizeIf(eq, instr, "overflow", divisor, Operand(-1));
     __ bind(&left_not_min_int);
   }
 
   if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
-    DeoptimizeIf(ne, instr, remainder, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "lost precision", remainder, Operand(zero_reg));
   }
 }
 
@@ -1348,14 +1348,14 @@
 
   __ Subu(result, zero_reg, dividend);
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-    DeoptimizeIf(eq, instr, result, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "minus zero", result, Operand(zero_reg));
   }
 
   // Dividing by -1 is basically negation, unless we overflow.
   __ Xor(scratch, scratch, result);
   if (divisor == -1) {
     if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
-      DeoptimizeIf(ge, instr, scratch, Operand(zero_reg));
+      DeoptimizeIf(ge, instr, "overflow", scratch, Operand(zero_reg));
     }
     return;
   }
@@ -1390,7 +1390,7 @@
   // Check for (0 / -x) that will produce negative zero.
   HMathFloorOfDiv* hdiv = instr->hydrogen();
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
-    DeoptimizeIf(eq, instr, dividend, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "minus zero", dividend, Operand(zero_reg));
   }
 
   // Easy case: We need no dynamic check for the dividend and the flooring
@@ -1434,14 +1434,14 @@
 
   // Check for x / 0.
   if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
-    DeoptimizeIf(eq, instr, divisor, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "division by zero", divisor, Operand(zero_reg));
   }
 
   // Check for (0 / -x) that will produce negative zero.
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
     Label left_not_zero;
     __ Branch(&left_not_zero, ne, dividend, Operand(zero_reg));
-    DeoptimizeIf(lt, instr, divisor, Operand(zero_reg));
+    DeoptimizeIf(lt, instr, "minus zero", divisor, Operand(zero_reg));
     __ bind(&left_not_zero);
   }
 
@@ -1450,7 +1450,7 @@
       !hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
     Label left_not_min_int;
     __ Branch(&left_not_min_int, ne, dividend, Operand(kMinInt));
-    DeoptimizeIf(eq, instr, divisor, Operand(-1));
+    DeoptimizeIf(eq, instr, "overflow", divisor, Operand(-1));
     __ bind(&left_not_min_int);
   }
 
@@ -1481,14 +1481,14 @@
     if (bailout_on_minus_zero && (constant < 0)) {
       // The case of a null constant will be handled separately.
       // If constant is negative and left is null, the result should be -0.
-      DeoptimizeIf(eq, instr, left, Operand(zero_reg));
+      DeoptimizeIf(eq, instr, "minus zero", left, Operand(zero_reg));
     }
 
     switch (constant) {
       case -1:
         if (overflow) {
           __ SubuAndCheckForOverflow(result, zero_reg, left, scratch);
-          DeoptimizeIf(lt, instr, scratch, Operand(zero_reg));
+          DeoptimizeIf(lt, instr, "overflow", scratch, Operand(zero_reg));
         } else {
           __ Subu(result, zero_reg, left);
         }
@@ -1497,7 +1497,7 @@
         if (bailout_on_minus_zero) {
           // If left is strictly negative and the constant is null, the
           // result is -0. Deoptimize if required, otherwise return 0.
-          DeoptimizeIf(lt, instr, left, Operand(zero_reg));
+          DeoptimizeIf(lt, instr, "minus zero", left, Operand(zero_reg));
         }
         __ mov(result, zero_reg);
         break;
@@ -1549,7 +1549,7 @@
         __ Mul(scratch, result, left, right);
       }
       __ sra(at, result, 31);
-      DeoptimizeIf(ne, instr, scratch, Operand(at));
+      DeoptimizeIf(ne, instr, "overflow", scratch, Operand(at));
     } else {
       if (instr->hydrogen()->representation().IsSmi()) {
         __ SmiUntag(result, left);
@@ -1564,7 +1564,7 @@
       __ Xor(at, left, right);
       __ Branch(&done, ge, at, Operand(zero_reg));
       // Bail out if the result is minus zero.
-      DeoptimizeIf(eq, instr, result, Operand(zero_reg));
+      DeoptimizeIf(eq, instr, "minus zero", result, Operand(zero_reg));
       __ bind(&done);
     }
   }
@@ -1628,7 +1628,7 @@
       case Token::SHR:
         __ srlv(result, left, ToRegister(right_op));
         if (instr->can_deopt()) {
-          DeoptimizeIf(lt, instr, result, Operand(zero_reg));
+          DeoptimizeIf(lt, instr, "negative value", result, Operand(zero_reg));
         }
         break;
       case Token::SHL:
@@ -1663,7 +1663,7 @@
         } else {
           if (instr->can_deopt()) {
             __ And(at, left, Operand(0x80000000));
-            DeoptimizeIf(ne, instr, at, Operand(zero_reg));
+            DeoptimizeIf(ne, instr, "negative value", at, Operand(zero_reg));
           }
           __ Move(result, left);
         }
@@ -1678,7 +1678,7 @@
             } else {
               __ SmiTagCheckOverflow(result, left, scratch);
             }
-            DeoptimizeIf(lt, instr, scratch, Operand(zero_reg));
+            DeoptimizeIf(lt, instr, "overflow", scratch, Operand(zero_reg));
           } else {
             __ sll(result, left, shift_count);
           }
@@ -1726,7 +1726,7 @@
                                  ToRegister(right),
                                  overflow);  // Reg at also used as scratch.
     }
-    DeoptimizeIf(lt, instr, overflow, Operand(zero_reg));
+    DeoptimizeIf(lt, instr, "overflow", overflow, Operand(zero_reg));
   }
 }
 
@@ -1780,9 +1780,9 @@
   DCHECK(!scratch.is(object));
 
   __ SmiTst(object, at);
-  DeoptimizeIf(eq, instr, at, Operand(zero_reg));
+  DeoptimizeIf(eq, instr, "Smi", at, Operand(zero_reg));
   __ GetObjectType(object, scratch, scratch);
-  DeoptimizeIf(ne, instr, scratch, Operand(JS_DATE_TYPE));
+  DeoptimizeIf(ne, instr, "not a date object", scratch, Operand(JS_DATE_TYPE));
 
   if (index->value() == 0) {
     __ lw(result, FieldMemOperand(object, JSDate::kValueOffset));
@@ -1917,7 +1917,7 @@
                                  ToRegister(right),
                                  overflow);  // Reg at also used as scratch.
     }
-    DeoptimizeIf(lt, instr, overflow, Operand(zero_reg));
+    DeoptimizeIf(lt, instr, "overflow", overflow, Operand(zero_reg));
   }
 }
 
@@ -2178,7 +2178,7 @@
       } else if (expected.NeedsMap()) {
         // If we need a map later and have a Smi -> deopt.
         __ SmiTst(reg, at);
-        DeoptimizeIf(eq, instr, at, Operand(zero_reg));
+        DeoptimizeIf(eq, instr, "Smi", at, Operand(zero_reg));
       }
 
       const Register map = scratch0();
@@ -2234,7 +2234,8 @@
       if (!expected.IsGeneric()) {
         // We've seen something for the first time -> deopt.
         // This can only happen if we are not generic already.
-        DeoptimizeIf(al, instr, zero_reg, Operand(zero_reg));
+        DeoptimizeIf(al, instr, "unexpected object", zero_reg,
+                     Operand(zero_reg));
       }
     }
   }
@@ -2694,10 +2695,10 @@
     DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
                                   LInstanceOfKnownGlobal* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
     Label* map_check() { return &map_check_; }
 
    private:
@@ -2857,6 +2858,7 @@
       __ Addu(sp, sp, Operand(sp_delta));
     }
   } else {
+    DCHECK(info()->IsStub());  // Functions would need to drop one more value.
     Register reg = ToRegister(instr->parameter_count());
     // The argument count parameter is a smi
     __ SmiUntag(reg);
@@ -2878,7 +2880,7 @@
   __ lw(result, FieldMemOperand(at, Cell::kValueOffset));
   if (instr->hydrogen()->RequiresHoleCheck()) {
     __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(eq, instr, result, Operand(at));
+    DeoptimizeIf(eq, instr, "hole", result, Operand(at));
   }
 }
 
@@ -2886,13 +2888,18 @@
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
-  Register vector = ToRegister(instr->temp_vector());
-  DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
-  __ li(vector, instr->hydrogen()->feedback_vector());
+  Register vector_register = ToRegister(instr->temp_vector());
+  Register slot_register = VectorLoadICDescriptor::SlotRegister();
+  DCHECK(vector_register.is(VectorLoadICDescriptor::VectorRegister()));
+  DCHECK(slot_register.is(a0));
+
+  AllowDeferredHandleDereference vector_structure_check;
+  Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+  __ li(vector_register, vector);
   // No need to allocate this register.
-  DCHECK(VectorLoadICDescriptor::SlotRegister().is(a0));
-  __ li(VectorLoadICDescriptor::SlotRegister(),
-        Operand(Smi::FromInt(instr->hydrogen()->slot())));
+  FeedbackVectorICSlot slot = instr->hydrogen()->slot();
+  int index = vector->GetIndex(slot);
+  __ li(slot_register, Operand(Smi::FromInt(index)));
 }
 
 
@@ -2907,7 +2914,7 @@
     EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
   }
   ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), mode).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -2928,7 +2935,7 @@
     Register payload = ToRegister(instr->temp());
     __ lw(payload, FieldMemOperand(cell, Cell::kValueOffset));
     __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(eq, instr, payload, Operand(at));
+    DeoptimizeIf(eq, instr, "hole", payload, Operand(at));
   }
 
   // Store the value.
@@ -2947,7 +2954,7 @@
     __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
 
     if (instr->hydrogen()->DeoptimizesOnHole()) {
-      DeoptimizeIf(eq, instr, result, Operand(at));
+      DeoptimizeIf(eq, instr, "hole", result, Operand(at));
     } else {
       Label is_not_hole;
       __ Branch(&is_not_hole, ne, result, Operand(at));
@@ -2971,7 +2978,7 @@
     __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
 
     if (instr->hydrogen()->DeoptimizesOnHole()) {
-      DeoptimizeIf(eq, instr, scratch, Operand(at));
+      DeoptimizeIf(eq, instr, "hole", scratch, Operand(at));
     } else {
       __ Branch(&skip_assignment, ne, scratch, Operand(at));
     }
@@ -3034,7 +3041,8 @@
   if (FLAG_vector_ics) {
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic =
+      CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3050,7 +3058,7 @@
 
   // Check that the function has a prototype or an initial map.
   __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-  DeoptimizeIf(eq, instr, result, Operand(at));
+  DeoptimizeIf(eq, instr, "hole", result, Operand(at));
 
   // If the function does not have an initial map, we're done.
   Label done;
@@ -3186,7 +3194,8 @@
       case UINT32_ELEMENTS:
         __ lw(result, mem_operand);
         if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
-          DeoptimizeIf(Ugreater_equal, instr, result, Operand(0x80000000));
+          DeoptimizeIf(Ugreater_equal, instr, "negative value", result,
+                       Operand(0x80000000));
         }
         break;
       case FLOAT32_ELEMENTS:
@@ -3239,7 +3248,7 @@
 
   if (instr->hydrogen()->RequiresHoleCheck()) {
     __ lw(scratch, MemOperand(scratch, kHoleNanUpper32Offset));
-    DeoptimizeIf(eq, instr, scratch, Operand(kHoleNanUpper32));
+    DeoptimizeIf(eq, instr, "hole", scratch, Operand(kHoleNanUpper32));
   }
 }
 
@@ -3275,10 +3284,10 @@
   if (instr->hydrogen()->RequiresHoleCheck()) {
     if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
       __ SmiTst(result, scratch);
-      DeoptimizeIf(ne, instr, scratch, Operand(zero_reg));
+      DeoptimizeIf(ne, instr, "not a Smi", scratch, Operand(zero_reg));
     } else {
       __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
-      DeoptimizeIf(eq, instr, result, Operand(scratch));
+      DeoptimizeIf(eq, instr, "hole", result, Operand(scratch));
     }
   }
 }
@@ -3341,7 +3350,7 @@
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
+  Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3424,10 +3433,11 @@
 
   // Deoptimize if the receiver is not a JS object.
   __ SmiTst(receiver, scratch);
-  DeoptimizeIf(eq, instr, scratch, Operand(zero_reg));
+  DeoptimizeIf(eq, instr, "Smi", scratch, Operand(zero_reg));
 
   __ GetObjectType(receiver, scratch, scratch);
-  DeoptimizeIf(lt, instr, scratch, Operand(FIRST_SPEC_OBJECT_TYPE));
+  DeoptimizeIf(lt, instr, "not a JavaScript object", scratch,
+               Operand(FIRST_SPEC_OBJECT_TYPE));
 
   __ Branch(&result_in_receiver);
   __ bind(&global_object);
@@ -3462,7 +3472,8 @@
   // Copy the arguments to this function possibly from the
   // adaptor frame below it.
   const uint32_t kArgumentsLimit = 1 * KB;
-  DeoptimizeIf(hi, instr, length, Operand(kArgumentsLimit));
+  DeoptimizeIf(hi, instr, "too many arguments", length,
+               Operand(kArgumentsLimit));
 
   // Push the receiver and use the register to keep the original
   // number of arguments.
@@ -3592,7 +3603,7 @@
   // Deoptimize if not a heap number.
   __ lw(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
   __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
-  DeoptimizeIf(ne, instr, scratch, Operand(at));
+  DeoptimizeIf(ne, instr, "not a heap number", scratch, Operand(at));
 
   Label done;
   Register exponent = scratch0();
@@ -3659,7 +3670,7 @@
   __ mov(result, input);
   __ subu(result, zero_reg, input);
   // Overflow if result is still negative, i.e. 0x80000000.
-  DeoptimizeIf(lt, instr, result, Operand(zero_reg));
+  DeoptimizeIf(lt, instr, "overflow", result, Operand(zero_reg));
   __ bind(&done);
 }
 
@@ -3670,10 +3681,11 @@
    public:
     DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LMathAbs* instr_;
   };
@@ -3713,7 +3725,8 @@
                      except_flag);
 
   // Deopt if the operation did not succeed.
-  DeoptimizeIf(ne, instr, except_flag, Operand(zero_reg));
+  DeoptimizeIf(ne, instr, "lost precision or NaN", except_flag,
+               Operand(zero_reg));
 
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     // Test for -0.
@@ -3721,7 +3734,7 @@
     __ Branch(&done, ne, result, Operand(zero_reg));
     __ Mfhc1(scratch1, input);
     __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
-    DeoptimizeIf(ne, instr, scratch1, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "minus zero", scratch1, Operand(zero_reg));
     __ bind(&done);
   }
 }
@@ -3754,7 +3767,8 @@
 
   // The following conversion will not work with numbers
   // outside of ]-2^32, 2^32[.
-  DeoptimizeIf(ge, instr, scratch, Operand(HeapNumber::kExponentBias + 32));
+  DeoptimizeIf(ge, instr, "overflow", scratch,
+               Operand(HeapNumber::kExponentBias + 32));
 
   // Save the original sign for later comparison.
   __ And(scratch, result, Operand(HeapNumber::kSignMask));
@@ -3768,7 +3782,7 @@
   __ Xor(result, result, Operand(scratch));
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     // ARM uses 'mi' here, which is 'lt'
-    DeoptimizeIf(lt, instr, result, Operand(zero_reg));
+    DeoptimizeIf(lt, instr, "minus zero", result, Operand(zero_reg));
   } else {
     Label skip2;
     // ARM uses 'mi' here, which is 'lt'
@@ -3787,7 +3801,8 @@
                      double_scratch1,
                      except_flag);
 
-  DeoptimizeIf(ne, instr, except_flag, Operand(zero_reg));
+  DeoptimizeIf(ne, instr, "lost precision or NaN", except_flag,
+               Operand(zero_reg));
 
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     // Test for -0.
@@ -3795,7 +3810,7 @@
     __ bind(&check_sign_on_zero);
     __ Mfhc1(scratch, input);
     __ And(scratch, scratch, Operand(HeapNumber::kSignMask));
-    DeoptimizeIf(ne, instr, scratch, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "minus zero", scratch, Operand(zero_reg));
   }
   __ bind(&done);
 }
@@ -3827,7 +3842,7 @@
   // Math.pow(-Infinity, 0.5) == Infinity
   // Math.sqrt(-Infinity) == NaN
   Label done;
-  __ Move(temp, -V8_INFINITY);
+  __ Move(temp, static_cast<double>(-V8_INFINITY));
   __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, temp, input);
   // Set up Infinity in the delay slot.
   // result is overwritten if the branch is not taken.
@@ -3861,7 +3876,7 @@
     DCHECK(!t3.is(tagged_exponent));
     __ lw(t3, FieldMemOperand(tagged_exponent, HeapObject::kMapOffset));
     __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
-    DeoptimizeIf(ne, instr, t3, Operand(at));
+    DeoptimizeIf(ne, instr, "not a heap number", t3, Operand(at));
     __ bind(&no_deopt);
     MathPowStub stub(isolate(), MathPowStub::TAGGED);
     __ CallStub(&stub);
@@ -3936,44 +3951,73 @@
   DCHECK(receiver.is(a1));
   DCHECK(name.is(a2));
 
-  Register scratch = a3;
-  Register extra = t0;
-  Register extra2 = t1;
-  Register extra3 = t2;
+  Register scratch = t0;
+  Register extra = t1;
+  Register extra2 = t2;
+  Register extra3 = t5;
+#ifdef DEBUG
+  Register slot = FLAG_vector_ics ? ToRegister(instr->slot()) : no_reg;
+  Register vector = FLAG_vector_ics ? ToRegister(instr->vector()) : no_reg;
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(slot, vector, scratch, extra, extra2, extra3));
+#endif
 
   // Important for the tail-call.
   bool must_teardown_frame = NeedsEagerFrame();
 
-  // The probe will tail call to a handler if found.
-  isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
-                                         must_teardown_frame, receiver, name,
-                                         scratch, extra, extra2, extra3);
+  if (!instr->hydrogen()->is_just_miss()) {
+    DCHECK(!instr->hydrogen()->is_keyed_load());
+
+    // The probe will tail call to a handler if found.
+    isolate()->stub_cache()->GenerateProbe(
+        masm(), Code::LOAD_IC, instr->hydrogen()->flags(), must_teardown_frame,
+        receiver, name, scratch, extra, extra2, extra3);
+  }
 
   // Tail call to miss if we ended up here.
   if (must_teardown_frame) __ LeaveFrame(StackFrame::INTERNAL);
-  LoadIC::GenerateMiss(masm());
+  if (instr->hydrogen()->is_keyed_load()) {
+    KeyedLoadIC::GenerateMiss(masm());
+  } else {
+    LoadIC::GenerateMiss(masm());
+  }
 }
 
 
 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
   DCHECK(ToRegister(instr->result()).is(v0));
 
-  LPointerMap* pointers = instr->pointer_map();
-  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+  if (instr->hydrogen()->IsTailCall()) {
+    if (NeedsEagerFrame()) __ LeaveFrame(StackFrame::INTERNAL);
 
-  if (instr->target()->IsConstantOperand()) {
-    LConstantOperand* target = LConstantOperand::cast(instr->target());
-    Handle<Code> code = Handle<Code>::cast(ToHandle(target));
-    generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
-    __ Call(code, RelocInfo::CODE_TARGET);
+    if (instr->target()->IsConstantOperand()) {
+      LConstantOperand* target = LConstantOperand::cast(instr->target());
+      Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+      __ Jump(code, RelocInfo::CODE_TARGET);
+    } else {
+      DCHECK(instr->target()->IsRegister());
+      Register target = ToRegister(instr->target());
+      __ Addu(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
+      __ Jump(target);
+    }
   } else {
-    DCHECK(instr->target()->IsRegister());
-    Register target = ToRegister(instr->target());
-    generator.BeforeCall(__ CallSize(target));
-    __ Addu(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
-    __ Call(target);
+    LPointerMap* pointers = instr->pointer_map();
+    SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+
+    if (instr->target()->IsConstantOperand()) {
+      LConstantOperand* target = LConstantOperand::cast(instr->target());
+      Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+      generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
+      __ Call(code, RelocInfo::CODE_TARGET);
+    } else {
+      DCHECK(instr->target()->IsRegister());
+      Register target = ToRegister(instr->target());
+      generator.BeforeCall(__ CallSize(target));
+      __ Addu(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
+      __ Call(target);
+    }
+    generator.AfterCall();
   }
-  generator.AfterCall();
 }
 
 
@@ -4204,7 +4248,7 @@
     __ stop("eliminated bounds check failed");
     __ bind(&done);
   } else {
-    DeoptimizeIf(cc, instr, reg, operand);
+    DeoptimizeIf(cc, instr, "out of bounds", reg, operand);
   }
 }
 
@@ -4483,10 +4527,9 @@
    public:
     DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredStringCharCodeAt(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredStringCharCodeAt(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStringCharCodeAt* instr_;
   };
@@ -4538,10 +4581,11 @@
    public:
     DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredStringCharFromCode(instr_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStringCharFromCode* instr_;
   };
@@ -4616,14 +4660,15 @@
    public:
     DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredNumberTagIU(instr_,
                                        instr_->value(),
                                        instr_->temp1(),
                                        instr_->temp2(),
                                        SIGNED_INT32);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagI* instr_;
   };
@@ -4644,14 +4689,15 @@
    public:
     DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredNumberTagIU(instr_,
                                        instr_->value(),
                                        instr_->temp1(),
                                        instr_->temp2(),
                                        UNSIGNED_INT32);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagU* instr_;
   };
@@ -4738,10 +4784,9 @@
    public:
     DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredNumberTagD(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredNumberTagD(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagD* instr_;
   };
@@ -4797,12 +4842,12 @@
   if (hchange->CheckFlag(HValue::kCanOverflow) &&
       hchange->value()->CheckFlag(HValue::kUint32)) {
     __ And(at, input, Operand(0xc0000000));
-    DeoptimizeIf(ne, instr, at, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "overflow", at, Operand(zero_reg));
   }
   if (hchange->CheckFlag(HValue::kCanOverflow) &&
       !hchange->value()->CheckFlag(HValue::kUint32)) {
     __ SmiTagCheckOverflow(output, input, at);
-    DeoptimizeIf(lt, instr, at, Operand(zero_reg));
+    DeoptimizeIf(lt, instr, "overflow", at, Operand(zero_reg));
   } else {
     __ SmiTag(output, input);
   }
@@ -4818,7 +4863,7 @@
     // If the input is a HeapObject, value of scratch won't be zero.
     __ And(scratch, input, Operand(kHeapObjectTag));
     __ SmiUntag(result, input);
-    DeoptimizeIf(ne, instr, scratch, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "not a Smi", scratch, Operand(zero_reg));
   } else {
     __ SmiUntag(result, input);
   }
@@ -4843,7 +4888,7 @@
     if (can_convert_undefined_to_nan) {
       __ Branch(&convert, ne, scratch, Operand(at));
     } else {
-      DeoptimizeIf(ne, instr, scratch, Operand(at));
+      DeoptimizeIf(ne, instr, "not a heap number", scratch, Operand(at));
     }
     // Load heap number.
     __ ldc1(result_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset));
@@ -4851,14 +4896,16 @@
       __ mfc1(at, result_reg.low());
       __ Branch(&done, ne, at, Operand(zero_reg));
       __ Mfhc1(scratch, result_reg);
-      DeoptimizeIf(eq, instr, scratch, Operand(HeapNumber::kSignMask));
+      DeoptimizeIf(eq, instr, "minus zero", scratch,
+                   Operand(HeapNumber::kSignMask));
     }
     __ Branch(&done);
     if (can_convert_undefined_to_nan) {
       __ bind(&convert);
       // Convert undefined (and hole) to NaN.
       __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
-      DeoptimizeIf(ne, instr, input_reg, Operand(at));
+      DeoptimizeIf(ne, instr, "not a heap number/undefined", input_reg,
+                   Operand(at));
       __ LoadRoot(scratch, Heap::kNanValueRootIndex);
       __ ldc1(result_reg, FieldMemOperand(scratch, HeapNumber::kValueOffset));
       __ Branch(&done);
@@ -4922,11 +4969,12 @@
 
     __ bind(&check_false);
     __ LoadRoot(at, Heap::kFalseValueRootIndex);
-    DeoptimizeIf(ne, instr, scratch2, Operand(at), "cannot truncate");
+    DeoptimizeIf(ne, instr, "not a heap number/undefined/true/false", scratch2,
+                 Operand(at));
     __ Branch(USE_DELAY_SLOT, &done);
     __ mov(input_reg, zero_reg);  // In delay slot.
   } else {
-    DeoptimizeIf(ne, instr, scratch1, Operand(at), "not a heap number");
+    DeoptimizeIf(ne, instr, "not a heap number", scratch1, Operand(at));
 
     // Load the double value.
     __ ldc1(double_scratch,
@@ -4941,15 +4989,15 @@
                        except_flag,
                        kCheckForInexactConversion);
 
-    DeoptimizeIf(ne, instr, except_flag, Operand(zero_reg),
-                 "lost precision or NaN");
+    DeoptimizeIf(ne, instr, "lost precision or NaN", except_flag,
+                 Operand(zero_reg));
 
     if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
       __ Branch(&done, ne, input_reg, Operand(zero_reg));
 
       __ Mfhc1(scratch1, double_scratch);
       __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
-      DeoptimizeIf(ne, instr, scratch1, Operand(zero_reg), "minus zero");
+      DeoptimizeIf(ne, instr, "minus zero", scratch1, Operand(zero_reg));
     }
   }
   __ bind(&done);
@@ -4961,10 +5009,9 @@
    public:
     DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredTaggedToI(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredTaggedToI(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LTaggedToI* instr_;
   };
@@ -5026,14 +5073,15 @@
                        kCheckForInexactConversion);
 
     // Deopt if the operation did not succeed (except_flag != 0).
-    DeoptimizeIf(ne, instr, except_flag, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "lost precision or NaN", except_flag,
+                 Operand(zero_reg));
 
     if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
       Label done;
       __ Branch(&done, ne, result_reg, Operand(zero_reg));
       __ Mfhc1(scratch1, double_input);
       __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
-      DeoptimizeIf(ne, instr, scratch1, Operand(zero_reg));
+      DeoptimizeIf(ne, instr, "minus zero", scratch1, Operand(zero_reg));
       __ bind(&done);
     }
   }
@@ -5059,26 +5107,27 @@
                        kCheckForInexactConversion);
 
     // Deopt if the operation did not succeed (except_flag != 0).
-    DeoptimizeIf(ne, instr, except_flag, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "lost precision or NaN", except_flag,
+                 Operand(zero_reg));
 
     if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
       Label done;
       __ Branch(&done, ne, result_reg, Operand(zero_reg));
       __ Mfhc1(scratch1, double_input);
       __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
-      DeoptimizeIf(ne, instr, scratch1, Operand(zero_reg));
+      DeoptimizeIf(ne, instr, "minus zero", scratch1, Operand(zero_reg));
       __ bind(&done);
     }
   }
   __ SmiTagCheckOverflow(result_reg, result_reg, scratch1);
-  DeoptimizeIf(lt, instr, scratch1, Operand(zero_reg));
+  DeoptimizeIf(lt, instr, "overflow", scratch1, Operand(zero_reg));
 }
 
 
 void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
   LOperand* input = instr->value();
   __ SmiTst(ToRegister(input), at);
-  DeoptimizeIf(ne, instr, at, Operand(zero_reg));
+  DeoptimizeIf(ne, instr, "not a Smi", at, Operand(zero_reg));
 }
 
 
@@ -5086,7 +5135,7 @@
   if (!instr->hydrogen()->value()->type().IsHeapObject()) {
     LOperand* input = instr->value();
     __ SmiTst(ToRegister(input), at);
-    DeoptimizeIf(eq, instr, at, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "Smi", at, Operand(zero_reg));
   }
 }
 
@@ -5104,12 +5153,12 @@
 
     // If there is only one type in the interval check for equality.
     if (first == last) {
-      DeoptimizeIf(ne, instr, scratch, Operand(first));
+      DeoptimizeIf(ne, instr, "wrong instance type", scratch, Operand(first));
     } else {
-      DeoptimizeIf(lo, instr, scratch, Operand(first));
+      DeoptimizeIf(lo, instr, "wrong instance type", scratch, Operand(first));
       // Omit check for the last type.
       if (last != LAST_TYPE) {
-        DeoptimizeIf(hi, instr, scratch, Operand(last));
+        DeoptimizeIf(hi, instr, "wrong instance type", scratch, Operand(last));
       }
     }
   } else {
@@ -5120,10 +5169,11 @@
     if (base::bits::IsPowerOfTwo32(mask)) {
       DCHECK(tag == 0 || base::bits::IsPowerOfTwo32(tag));
       __ And(at, scratch, mask);
-      DeoptimizeIf(tag == 0 ? ne : eq, instr, at, Operand(zero_reg));
+      DeoptimizeIf(tag == 0 ? ne : eq, instr, "wrong instance type", at,
+                   Operand(zero_reg));
     } else {
       __ And(scratch, scratch, Operand(mask));
-      DeoptimizeIf(ne, instr, scratch, Operand(tag));
+      DeoptimizeIf(ne, instr, "wrong instance type", scratch, Operand(tag));
     }
   }
 }
@@ -5138,9 +5188,9 @@
     Handle<Cell> cell = isolate()->factory()->NewCell(object);
     __ li(at, Operand(Handle<Object>(cell)));
     __ lw(at, FieldMemOperand(at, Cell::kValueOffset));
-    DeoptimizeIf(ne, instr, reg, Operand(at));
+    DeoptimizeIf(ne, instr, "value mismatch", reg, Operand(at));
   } else {
-    DeoptimizeIf(ne, instr, reg, Operand(object));
+    DeoptimizeIf(ne, instr, "value mismatch", reg, Operand(object));
   }
 }
 
@@ -5156,7 +5206,7 @@
     __ StoreToSafepointRegisterSlot(v0, scratch0());
   }
   __ SmiTst(scratch0(), at);
-  DeoptimizeIf(eq, instr, at, Operand(zero_reg));
+  DeoptimizeIf(eq, instr, "instance migration failed", at, Operand(zero_reg));
 }
 
 
@@ -5167,11 +5217,12 @@
         : LDeferredCode(codegen), instr_(instr), object_(object) {
       SetExit(check_maps());
     }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredInstanceMigration(instr_, object_);
     }
     Label* check_maps() { return &check_maps_; }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LCheckMaps* instr_;
     Label check_maps_;
@@ -5209,7 +5260,7 @@
   if (instr->hydrogen()->HasMigrationTarget()) {
     __ Branch(deferred->entry(), ne, map_reg, Operand(map));
   } else {
-    DeoptimizeIf(ne, instr, map_reg, Operand(map));
+    DeoptimizeIf(ne, instr, "wrong map", map_reg, Operand(map));
   }
 
   __ bind(&success);
@@ -5247,7 +5298,8 @@
 
   // Check for undefined. Undefined is converted to zero for clamping
   // conversions.
-  DeoptimizeIf(ne, instr, input_reg, Operand(factory()->undefined_value()));
+  DeoptimizeIf(ne, instr, "not a heap number/undefined", input_reg,
+               Operand(factory()->undefined_value()));
   __ mov(result_reg, zero_reg);
   __ jmp(&done);
 
@@ -5289,10 +5341,9 @@
    public:
     DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredAllocate(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredAllocate(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LAllocate* instr_;
   };
@@ -5670,8 +5721,8 @@
     type = Deoptimizer::LAZY;
   }
 
-  DeoptimizeIf(al, instr, type, zero_reg, Operand(zero_reg),
-               instr->hydrogen()->reason());
+  DeoptimizeIf(al, instr, type, instr->hydrogen()->reason(), zero_reg,
+               Operand(zero_reg));
 }
 
 
@@ -5702,10 +5753,9 @@
    public:
     DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredStackCheck(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredStackCheck(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStackCheck* instr_;
   };
@@ -5762,18 +5812,19 @@
   Register result = ToRegister(instr->result());
   Register object = ToRegister(instr->object());
   __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
-  DeoptimizeIf(eq, instr, object, Operand(at));
+  DeoptimizeIf(eq, instr, "undefined", object, Operand(at));
 
   Register null_value = t1;
   __ LoadRoot(null_value, Heap::kNullValueRootIndex);
-  DeoptimizeIf(eq, instr, object, Operand(null_value));
+  DeoptimizeIf(eq, instr, "null", object, Operand(null_value));
 
   __ And(at, object, kSmiTagMask);
-  DeoptimizeIf(eq, instr, at, Operand(zero_reg));
+  DeoptimizeIf(eq, instr, "Smi", at, Operand(zero_reg));
 
   STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
   __ GetObjectType(object, a1, a1);
-  DeoptimizeIf(le, instr, a1, Operand(LAST_JS_PROXY_TYPE));
+  DeoptimizeIf(le, instr, "not a JavaScript object", a1,
+               Operand(LAST_JS_PROXY_TYPE));
 
   Label use_cache, call_runtime;
   DCHECK(object.is(a0));
@@ -5790,7 +5841,7 @@
   __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
   DCHECK(result.is(v0));
   __ LoadRoot(at, Heap::kMetaMapRootIndex);
-  DeoptimizeIf(ne, instr, a1, Operand(at));
+  DeoptimizeIf(ne, instr, "wrong map", a1, Operand(at));
   __ bind(&use_cache);
 }
 
@@ -5810,7 +5861,7 @@
         FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
   __ lw(result,
         FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
-  DeoptimizeIf(eq, instr, result, Operand(zero_reg));
+  DeoptimizeIf(eq, instr, "no cache", result, Operand(zero_reg));
 
   __ bind(&done);
 }
@@ -5820,7 +5871,7 @@
   Register object = ToRegister(instr->value());
   Register map = ToRegister(instr->map());
   __ lw(scratch0(), FieldMemOperand(object, HeapObject::kMapOffset));
-  DeoptimizeIf(ne, instr, map, Operand(scratch0()));
+  DeoptimizeIf(ne, instr, "wrong map", map, Operand(scratch0()));
 }
 
 
@@ -5852,10 +5903,11 @@
           object_(object),
           index_(index) {
     }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredLoadMutableDouble(instr_, result_, object_, index_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LLoadFieldByIndex* instr_;
     Register result_;
diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h
index 5402c9a..43316e4 100644
--- a/src/mips/lithium-codegen-mips.h
+++ b/src/mips/lithium-codegen-mips.h
@@ -229,14 +229,12 @@
   void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
                                             Safepoint::DeoptMode mode);
   void DeoptimizeIf(Condition condition, LInstruction* instr,
-                    Deoptimizer::BailoutType bailout_type,
+                    Deoptimizer::BailoutType bailout_type, const char* detail,
                     Register src1 = zero_reg,
-                    const Operand& src2 = Operand(zero_reg),
-                    const char* detail = NULL);
+                    const Operand& src2 = Operand(zero_reg));
   void DeoptimizeIf(Condition condition, LInstruction* instr,
-                    Register src1 = zero_reg,
-                    const Operand& src2 = Operand(zero_reg),
-                    const char* detail = NULL);
+                    const char* detail = NULL, Register src1 = zero_reg,
+                    const Operand& src2 = Operand(zero_reg));
 
   void AddToTranslation(LEnvironment* environment,
                         Translation* translation,
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 1757d92..77dea5b 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <sstream>
+
 #include "src/v8.h"
 
 #if V8_TARGET_ARCH_MIPS
@@ -323,9 +325,9 @@
 
 void LStoreNamedField::PrintDataTo(StringStream* stream) {
   object()->PrintTo(stream);
-  OStringStream os;
+  std::ostringstream os;
   os << hydrogen()->access() << " <- ";
-  stream->Add(os.c_str());
+  stream->Add(os.str().c_str());
   value()->PrintTo(stream);
 }
 
@@ -704,11 +706,7 @@
     // Shift operations can only deoptimize if we do a logical shift
     // by 0 and the result cannot be truncated to int32.
     if (op == Token::SHR && constant_value == 0) {
-      if (FLAG_opt_safe_uint32_operations) {
-        does_deopt = !instr->CheckFlag(HInstruction::kUint32);
-      } else {
-        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32);
-      }
+      does_deopt = !instr->CheckFlag(HInstruction::kUint32);
     }
 
     LInstruction* result =
@@ -1105,9 +1103,17 @@
       UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
   LOperand* name_register =
       UseFixed(instr->name(), LoadDescriptor::NameRegister());
+  LOperand* slot = NULL;
+  LOperand* vector = NULL;
+  if (FLAG_vector_ics) {
+    slot = UseFixed(instr->slot(), VectorLoadICDescriptor::SlotRegister());
+    vector =
+        UseFixed(instr->vector(), VectorLoadICDescriptor::VectorRegister());
+  }
+
   // Not marked as call. It can't deoptimize, and it never returns.
   return new (zone()) LTailCallThroughMegamorphicCache(
-      context, receiver_register, name_register);
+      context, receiver_register, name_register, slot, vector);
 }
 
 
@@ -1403,8 +1409,14 @@
   DCHECK(instr->right()->representation().Equals(instr->representation()));
   LOperand* dividend = UseRegister(instr->left());
   LOperand* divisor = UseRegister(instr->right());
-  LFlooringDivI* div = new(zone()) LFlooringDivI(dividend, divisor);
-  return AssignEnvironment(DefineAsRegister(div));
+  LInstruction* result =
+      DefineAsRegister(new (zone()) LFlooringDivI(dividend, divisor));
+  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
+      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
+      (instr->CheckFlag(HValue::kCanOverflow))) {
+    result = AssignEnvironment(result);
+  }
+  return result;
 }
 
 
@@ -1519,7 +1531,7 @@
     return DefineAsRegister(mul);
 
   } else if (instr->representation().IsDouble()) {
-    if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    if (IsMipsArchVariant(kMips32r2)) {
       if (instr->HasOneUse() && instr->uses().value()->IsAdd()) {
         HAdd* add = HAdd::cast(instr->uses().value());
         if (instr == add->left()) {
@@ -1592,7 +1604,7 @@
     LInstruction* result = DefineAsRegister(add);
     return result;
   } else if (instr->representation().IsDouble()) {
-    if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
+    if (IsMipsArchVariant(kMips32r2)) {
       if (instr->left()->IsMul())
         return DoMultiplyAdd(HMul::cast(instr->left()), instr->right());
 
@@ -2062,7 +2074,7 @@
   LOperand* global_object =
       UseFixed(instr->global_object(), LoadDescriptor::ReceiverRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
   LLoadGlobalGeneric* result =
@@ -2121,7 +2133,7 @@
   LOperand* object =
       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
 
@@ -2188,7 +2200,7 @@
       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
   LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
 
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 36e5b57..ecffef7 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -163,17 +163,13 @@
   V(UnknownOSRValue)                         \
   V(WrapReceiver)
 
-#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)                        \
-  virtual Opcode opcode() const FINAL OVERRIDE {                      \
-    return LInstruction::k##type;                                           \
-  }                                                                         \
-  virtual void CompileToNative(LCodeGen* generator) FINAL OVERRIDE;   \
-  virtual const char* Mnemonic() const FINAL OVERRIDE {               \
-    return mnemonic;                                                        \
-  }                                                                         \
-  static L##type* cast(LInstruction* instr) {                               \
-    DCHECK(instr->Is##type());                                              \
-    return reinterpret_cast<L##type*>(instr);                               \
+#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)            \
+  Opcode opcode() const FINAL { return LInstruction::k##type; } \
+  void CompileToNative(LCodeGen* generator) FINAL;              \
+  const char* Mnemonic() const FINAL { return mnemonic; }       \
+  static L##type* cast(LInstruction* instr) {                   \
+    DCHECK(instr->Is##type());                                  \
+    return reinterpret_cast<L##type*>(instr);                   \
   }
 
 
@@ -288,11 +284,9 @@
  public:
   // Allow 0 or 1 output operands.
   STATIC_ASSERT(R == 0 || R == 1);
-  virtual bool HasResult() const FINAL OVERRIDE {
-    return R != 0 && result() != NULL;
-  }
+  bool HasResult() const FINAL { return R != 0 && result() != NULL; }
   void set_result(LOperand* operand) { results_[0] = operand; }
-  LOperand* result() const { return results_[0]; }
+  LOperand* result() const OVERRIDE { return results_[0]; }
 
  protected:
   EmbeddedContainer<LOperand*, R> results_;
@@ -310,11 +304,11 @@
 
  private:
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return I; }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return I; }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return T; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return temps_[i]; }
+  int TempCount() FINAL { return T; }
+  LOperand* TempAt(int i) FINAL { return temps_[i]; }
 };
 
 
@@ -329,8 +323,8 @@
   }
 
   // Can't use the DECLARE-macro here because of sub-classes.
-  virtual bool IsGap() const FINAL OVERRIDE { return true; }
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsGap() const FINAL { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   static LGap* cast(LInstruction* instr) {
     DCHECK(instr->IsGap());
     return reinterpret_cast<LGap*>(instr);
@@ -370,7 +364,7 @@
  public:
   explicit LInstructionGap(HBasicBlock* block) : LGap(block) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
     return !IsRedundant();
   }
 
@@ -382,10 +376,10 @@
  public:
   explicit LGoto(HBasicBlock* block) : block_(block) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
   DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
-  virtual bool IsControl() const OVERRIDE { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsControl() const OVERRIDE { return true; }
 
   int block_id() const { return block_->block_id(); }
 
@@ -428,7 +422,7 @@
 
 class LDeoptimize FINAL : public LTemplateInstruction<0, 0, 0> {
  public:
-  virtual bool IsControl() const OVERRIDE { return true; }
+  bool IsControl() const OVERRIDE { return true; }
   DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
   DECLARE_HYDROGEN_ACCESSOR(Deoptimize)
 };
@@ -439,12 +433,10 @@
   explicit LLabel(HBasicBlock* block)
       : LGap(block), replacement_(NULL) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(Label, "label")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int block_id() const { return block()->block_id(); }
   bool is_loop_header() const { return block()->IsLoopHeader(); }
@@ -462,9 +454,7 @@
 
 class LParameter FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter")
 };
 
@@ -483,19 +473,23 @@
 
 
 class LTailCallThroughMegamorphicCache FINAL
-    : public LTemplateInstruction<0, 3, 0> {
+    : public LTemplateInstruction<0, 5, 0> {
  public:
-  explicit LTailCallThroughMegamorphicCache(LOperand* context,
-                                            LOperand* receiver,
-                                            LOperand* name) {
+  LTailCallThroughMegamorphicCache(LOperand* context, LOperand* receiver,
+                                   LOperand* name, LOperand* slot,
+                                   LOperand* vector) {
     inputs_[0] = context;
     inputs_[1] = receiver;
     inputs_[2] = name;
+    inputs_[3] = slot;
+    inputs_[4] = vector;
   }
 
   LOperand* context() { return inputs_[0]; }
   LOperand* receiver() { return inputs_[1]; }
   LOperand* name() { return inputs_[2]; }
+  LOperand* slot() { return inputs_[3]; }
+  LOperand* vector() { return inputs_[4]; }
 
   DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
                                "tail-call-through-megamorphic-cache")
@@ -505,9 +499,7 @@
 
 class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown-osr-value")
 };
 
@@ -517,7 +509,7 @@
  public:
   LControlInstruction() : false_label_(NULL), true_label_(NULL) { }
 
-  virtual bool IsControl() const FINAL OVERRIDE { return true; }
+  bool IsControl() const FINAL { return true; }
 
   int SuccessorCount() { return hydrogen()->SuccessorCount(); }
   HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); }
@@ -606,7 +598,7 @@
   LOperand* length() { return inputs_[1]; }
   LOperand* index() { return inputs_[2]; }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -846,7 +838,7 @@
     return hydrogen()->representation().IsDouble();
   }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1034,7 +1026,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1051,7 +1043,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1066,7 +1058,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1084,7 +1076,7 @@
                                "is-undetectable-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1106,7 +1098,7 @@
 
   Token::Value op() const { return hydrogen()->token(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1122,7 +1114,7 @@
                                "has-instance-type-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1152,7 +1144,7 @@
                                "has-cached-array-index-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1170,7 +1162,7 @@
                                "class-of-test-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1367,7 +1359,7 @@
   DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
   DECLARE_HYDROGEN_ACCESSOR(Branch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1512,11 +1504,9 @@
   LOperand* left() { return inputs_[0]; }
   LOperand* right() { return inputs_[1]; }
 
-  virtual Opcode opcode() const OVERRIDE {
-    return LInstruction::kArithmeticD;
-  }
-  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
-  virtual const char* Mnemonic() const OVERRIDE;
+  Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticD; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
 
  private:
   Token::Value op_;
@@ -1540,9 +1530,9 @@
   LOperand* right() { return inputs_[2]; }
   Token::Value op() const { return op_; }
 
-  virtual Opcode opcode() const FINAL  { return LInstruction::kArithmeticT; }
-  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
-  virtual const char* Mnemonic() const OVERRIDE;
+  Opcode opcode() const FINAL { return LInstruction::kArithmeticT; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
 
  private:
   Token::Value op_;
@@ -1651,7 +1641,7 @@
   DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
   DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   uint32_t base_offset() const { return hydrogen()->base_offset(); }
 };
 
@@ -1732,7 +1722,7 @@
 
   int slot_index() { return hydrogen()->slot_index(); }
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1751,7 +1741,7 @@
 
   int slot_index() { return hydrogen()->slot_index(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1790,7 +1780,7 @@
   LOperand* function() { return inputs_[0]; }
   LOperand* code_object() { return inputs_[1]; }
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry, "store-code-entry")
   DECLARE_HYDROGEN_ACCESSOR(StoreCodeEntry)
@@ -1807,7 +1797,7 @@
   LOperand* base_object() const { return inputs_[0]; }
   LOperand* offset() const { return inputs_[1]; }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object")
 };
@@ -1851,7 +1841,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallJSFunction, "call-js-function")
   DECLARE_HYDROGEN_ACCESSOR(CallJSFunction)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1871,11 +1861,12 @@
 
   const CallInterfaceDescriptor descriptor() { return descriptor_; }
 
- private:
-  DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
   DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+ private:
+  DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 
@@ -1883,11 +1874,11 @@
   ZoneList<LOperand*> inputs_;
 
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return inputs_.length(); }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return inputs_.length(); }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return 0; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return NULL; }
+  int TempCount() FINAL { return 0; }
+  LOperand* TempAt(int i) FINAL { return NULL; }
 };
 
 
@@ -1904,7 +1895,7 @@
   DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function")
   DECLARE_HYDROGEN_ACCESSOR(InvokeFunction)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1940,7 +1931,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
   DECLARE_HYDROGEN_ACCESSOR(CallNew)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1959,7 +1950,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
   DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1976,7 +1967,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
   DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
 
-  virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
+  bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
     return save_doubles() == kDontSaveFPRegs;
   }
 
@@ -2170,7 +2161,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
   DECLARE_HYDROGEN_ACCESSOR(StoreNamedField)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Representation representation() const {
     return hydrogen()->field_representation();
@@ -2193,7 +2184,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
   DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Handle<Object> name() const { return hydrogen()->name(); }
   StrictMode strict_mode() { return hydrogen()->strict_mode(); }
@@ -2225,7 +2216,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed")
   DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
   uint32_t base_offset() const { return hydrogen()->base_offset(); }
 };
@@ -2251,7 +2242,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
   DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   StrictMode strict_mode() { return hydrogen()->strict_mode(); }
 };
@@ -2275,7 +2266,7 @@
                                "transition-elements-kind")
   DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Handle<Map> original_map() { return hydrogen()->original_map().handle(); }
   Handle<Map> transitioned_map() {
@@ -2571,7 +2562,7 @@
 
   Handle<String> type_literal() { return hydrogen()->type_literal(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -2592,9 +2583,7 @@
  public:
   LOsrEntry() {}
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry")
 };
 
@@ -2797,7 +2786,7 @@
 
   // An input operand in register, stack slot or a constant operand.
   // Will not be moved to a register even if one is freely available.
-  virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE;
+  MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE;
 
   // Temporary operand that must be in a register.
   MUST_USE_RESULT LUnallocated* TempRegister();
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 604293b..90c3499 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -15,7 +15,7 @@
 #include "src/cpu-profiler.h"
 #include "src/debug.h"
 #include "src/isolate-inl.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -23,7 +23,8 @@
 MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size)
     : Assembler(arg_isolate, buffer, size),
       generating_stub_(false),
-      has_frame_(false) {
+      has_frame_(false),
+      has_double_zero_reg_set_(false) {
   if (isolate() != NULL) {
     code_object_ = Handle<Object>(isolate()->heap()->undefined_value(),
                                   isolate());
@@ -590,11 +591,12 @@
   }
 
   bind(&done);
-  // Check that the value is a normal property.
+  // Check that the value is a field property.
   // reg2: elements + (index * kPointerSize).
   const int kDetailsOffset =
       SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
   lw(reg1, FieldMemOperand(reg2, kDetailsOffset));
+  DCHECK_EQ(FIELD, 0);
   And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
   Branch(miss, ne, at, Operand(zero_reg));
 
@@ -739,6 +741,28 @@
 }
 
 
+void MacroAssembler::Mulhu(Register rd, Register rs, const Operand& rt) {
+  if (rt.is_reg()) {
+    if (!IsMipsArchVariant(kMips32r6)) {
+      multu(rs, rt.rm());
+      mfhi(rd);
+    } else {
+      muhu(rd, rs, rt.rm());
+    }
+  } else {
+    // li handles the relocation.
+    DCHECK(!rs.is(at));
+    li(at, rt);
+    if (!IsMipsArchVariant(kMips32r6)) {
+      multu(rs, at);
+      mfhi(rd);
+    } else {
+      muhu(rd, rs, at);
+    }
+  }
+}
+
+
 void MacroAssembler::Multu(Register rs, const Operand& rt) {
   if (rt.is_reg()) {
     multu(rs, rt.rm());
@@ -790,6 +814,28 @@
 }
 
 
+void MacroAssembler::Div(Register res, Register rs, const Operand& rt) {
+  if (rt.is_reg()) {
+    if (!IsMipsArchVariant(kMips32r6)) {
+      div(rs, rt.rm());
+      mflo(res);
+    } else {
+      div(res, rs, rt.rm());
+    }
+  } else {
+    // li handles the relocation.
+    DCHECK(!rs.is(at));
+    li(at, rt);
+    if (!IsMipsArchVariant(kMips32r6)) {
+      div(rs, at);
+      mflo(res);
+    } else {
+      div(res, rs, at);
+    }
+  }
+}
+
+
 void MacroAssembler::Mod(Register rd, Register rs, const Operand& rt) {
   if (rt.is_reg()) {
     if (!IsMipsArchVariant(kMips32r6)) {
@@ -812,6 +858,28 @@
 }
 
 
+void MacroAssembler::Modu(Register rd, Register rs, const Operand& rt) {
+  if (rt.is_reg()) {
+    if (!IsMipsArchVariant(kMips32r6)) {
+      divu(rs, rt.rm());
+      mfhi(rd);
+    } else {
+      modu(rd, rs, rt.rm());
+    }
+  } else {
+    // li handles the relocation.
+    DCHECK(!rs.is(at));
+    li(at, rt);
+    if (!IsMipsArchVariant(kMips32r6)) {
+      divu(rs, at);
+      mfhi(rd);
+    } else {
+      modu(rd, rs, at);
+    }
+  }
+}
+
+
 void MacroAssembler::Divu(Register rs, const Operand& rt) {
   if (rt.is_reg()) {
     divu(rs, rt.rm());
@@ -824,6 +892,28 @@
 }
 
 
+void MacroAssembler::Divu(Register res, Register rs, const Operand& rt) {
+  if (rt.is_reg()) {
+    if (!IsMipsArchVariant(kMips32r6)) {
+      divu(rs, rt.rm());
+      mflo(res);
+    } else {
+      divu(res, rs, rt.rm());
+    }
+  } else {
+    // li handles the relocation.
+    DCHECK(!rs.is(at));
+    li(at, rt);
+    if (!IsMipsArchVariant(kMips32r6)) {
+      divu(rs, at);
+      mflo(res);
+    } else {
+      divu(res, rs, at);
+    }
+  }
+}
+
+
 void MacroAssembler::And(Register rd, Register rs, const Operand& rt) {
   if (rt.is_reg()) {
     and_(rd, rs, rt.rm());
@@ -1459,15 +1549,20 @@
 }
 
 
+void MacroAssembler::Move(FPURegister dst, float imm) {
+  li(at, Operand(bit_cast<int32_t>(imm)));
+  mtc1(at, dst);
+}
+
+
 void MacroAssembler::Move(FPURegister dst, double imm) {
   static const DoubleRepresentation minus_zero(-0.0);
   static const DoubleRepresentation zero(0.0);
   DoubleRepresentation value_rep(imm);
   // Handle special values first.
-  bool force_load = dst.is(kDoubleRegZero);
-  if (value_rep == zero && !force_load) {
+  if (value_rep == zero && has_double_zero_reg_set_) {
     mov_d(dst, kDoubleRegZero);
-  } else if (value_rep == minus_zero && !force_load) {
+  } else if (value_rep == minus_zero && has_double_zero_reg_set_) {
     neg_d(dst, kDoubleRegZero);
   } else {
     uint32_t lo, hi;
@@ -1488,6 +1583,7 @@
     } else {
       Mthc1(zero_reg, dst);
     }
+    if (dst.is(kDoubleRegZero)) has_double_zero_reg_set_ = true;
   }
 }
 
@@ -1904,7 +2000,7 @@
       // Unsigned comparison.
       case Ugreater:
         if (r2.is(zero_reg)) {
-          bgtz(rs, offset);
+          bne(rs, zero_reg, offset);
         } else {
           sltu(scratch, r2, rs);
           bne(scratch, zero_reg, offset);
@@ -1912,7 +2008,7 @@
         break;
       case Ugreater_equal:
         if (r2.is(zero_reg)) {
-          bgez(rs, offset);
+          b(offset);
         } else {
           sltu(scratch, rs, r2);
           beq(scratch, zero_reg, offset);
@@ -1929,7 +2025,7 @@
         break;
       case Uless_equal:
         if (r2.is(zero_reg)) {
-          b(offset);
+          beq(rs, zero_reg, offset);
         } else {
           sltu(scratch, r2, rs);
           beq(scratch, zero_reg, offset);
@@ -1948,18 +2044,26 @@
         b(offset);
         break;
       case eq:
-        // We don't want any other register but scratch clobbered.
-        DCHECK(!scratch.is(rs));
-        r2 = scratch;
-        li(r2, rt);
-        beq(rs, r2, offset);
+        if (rt.imm32_ == 0) {
+          beq(rs, zero_reg, offset);
+        } else {
+          // We don't want any other register but scratch clobbered.
+          DCHECK(!scratch.is(rs));
+          r2 = scratch;
+          li(r2, rt);
+          beq(rs, r2, offset);
+        }
         break;
       case ne:
-        // We don't want any other register but scratch clobbered.
-        DCHECK(!scratch.is(rs));
-        r2 = scratch;
-        li(r2, rt);
-        bne(rs, r2, offset);
+        if (rt.imm32_ == 0) {
+          bne(rs, zero_reg, offset);
+        } else {
+          // We don't want any other register but scratch clobbered.
+          DCHECK(!scratch.is(rs));
+          r2 = scratch;
+          li(r2, rt);
+          bne(rs, r2, offset);
+        }
         break;
       // Signed comparison.
       case greater:
@@ -2011,7 +2115,7 @@
       // Unsigned comparison.
       case Ugreater:
         if (rt.imm32_ == 0) {
-          bgtz(rs, offset);
+          bne(rs, zero_reg, offset);
         } else {
           r2 = scratch;
           li(r2, rt);
@@ -2021,7 +2125,7 @@
         break;
       case Ugreater_equal:
         if (rt.imm32_ == 0) {
-          bgez(rs, offset);
+          b(offset);
         } else if (is_int16(rt.imm32_)) {
           sltiu(scratch, rs, rt.imm32_);
           beq(scratch, zero_reg, offset);
@@ -2048,7 +2152,7 @@
         break;
       case Uless_equal:
         if (rt.imm32_ == 0) {
-          b(offset);
+          beq(rs, zero_reg, offset);
         } else {
           r2 = scratch;
           li(r2, rt);
@@ -2150,7 +2254,7 @@
       case Ugreater:
         if (r2.is(zero_reg)) {
           offset = shifted_branch_offset(L, false);
-           bgtz(rs, offset);
+          bne(rs, zero_reg, offset);
         } else {
           sltu(scratch, r2, rs);
           offset = shifted_branch_offset(L, false);
@@ -2160,7 +2264,7 @@
       case Ugreater_equal:
         if (r2.is(zero_reg)) {
           offset = shifted_branch_offset(L, false);
-          bgez(rs, offset);
+          b(offset);
         } else {
           sltu(scratch, rs, r2);
           offset = shifted_branch_offset(L, false);
@@ -2180,7 +2284,7 @@
       case Uless_equal:
         if (r2.is(zero_reg)) {
           offset = shifted_branch_offset(L, false);
-          b(offset);
+          beq(rs, zero_reg, offset);
         } else {
           sltu(scratch, r2, rs);
           offset = shifted_branch_offset(L, false);
@@ -2201,18 +2305,28 @@
         b(offset);
         break;
       case eq:
-        DCHECK(!scratch.is(rs));
-        r2 = scratch;
-        li(r2, rt);
-        offset = shifted_branch_offset(L, false);
-        beq(rs, r2, offset);
+        if (rt.imm32_ == 0) {
+          offset = shifted_branch_offset(L, false);
+          beq(rs, zero_reg, offset);
+        } else {
+          DCHECK(!scratch.is(rs));
+          r2 = scratch;
+          li(r2, rt);
+          offset = shifted_branch_offset(L, false);
+          beq(rs, r2, offset);
+        }
         break;
       case ne:
-        DCHECK(!scratch.is(rs));
-        r2 = scratch;
-        li(r2, rt);
-        offset = shifted_branch_offset(L, false);
-        bne(rs, r2, offset);
+        if (rt.imm32_ == 0) {
+          offset = shifted_branch_offset(L, false);
+          bne(rs, zero_reg, offset);
+        } else {
+          DCHECK(!scratch.is(rs));
+          r2 = scratch;
+          li(r2, rt);
+          offset = shifted_branch_offset(L, false);
+          bne(rs, r2, offset);
+        }
         break;
       // Signed comparison.
       case greater:
@@ -2292,7 +2406,7 @@
       case Ugreater_equal:
         if (rt.imm32_ == 0) {
           offset = shifted_branch_offset(L, false);
-          bgez(rs, offset);
+          b(offset);
         } else if (is_int16(rt.imm32_)) {
           sltiu(scratch, rs, rt.imm32_);
           offset = shifted_branch_offset(L, false);
@@ -3884,17 +3998,17 @@
 }
 
 
-void MacroAssembler::DispatchMap(Register obj,
-                                 Register scratch,
-                                 Handle<Map> map,
-                                 Handle<Code> success,
-                                 SmiCheckType smi_check_type) {
+void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
+                                     Register scratch2, Handle<WeakCell> cell,
+                                     Handle<Code> success,
+                                     SmiCheckType smi_check_type) {
   Label fail;
   if (smi_check_type == DO_SMI_CHECK) {
     JumpIfSmi(obj, &fail);
   }
-  lw(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
-  Jump(success, RelocInfo::CODE_TARGET, eq, scratch, Operand(map));
+  lw(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset));
+  GetWeakValue(scratch2, cell);
+  Jump(success, RelocInfo::CODE_TARGET, eq, scratch1, Operand(scratch2));
   bind(&fail);
 }
 
@@ -3913,6 +4027,19 @@
 }
 
 
+void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
+  li(value, Operand(cell));
+  lw(value, FieldMemOperand(value, WeakCell::kValueOffset));
+}
+
+
+void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
+                                   Label* miss) {
+  GetWeakValue(value, cell);
+  JumpIfSmi(value, miss);
+}
+
+
 void MacroAssembler::MovFromFloatResult(DoubleRegister dst) {
   if (IsMipsSoftFloatABI) {
     if (kArchEndian == kLittle) {
@@ -4477,8 +4604,34 @@
 }
 
 
-void MacroAssembler::AdduAndCheckForOverflow(Register dst,
-                                             Register left,
+void MacroAssembler::AdduAndCheckForOverflow(Register dst, Register left,
+                                             const Operand& right,
+                                             Register overflow_dst,
+                                             Register scratch) {
+  if (right.is_reg()) {
+    AdduAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
+  } else {
+    if (dst.is(left)) {
+      mov(scratch, left);                   // Preserve left.
+      addiu(dst, left, right.immediate());  // Left is overwritten.
+      xor_(scratch, dst, scratch);          // Original left.
+      // Load right since xori takes uint16 as immediate.
+      addiu(t9, zero_reg, right.immediate());
+      xor_(overflow_dst, dst, t9);
+      and_(overflow_dst, overflow_dst, scratch);
+    } else {
+      addiu(dst, left, right.immediate());
+      xor_(overflow_dst, dst, left);
+      // Load right since xori takes uint16 as immediate.
+      addiu(t9, zero_reg, right.immediate());
+      xor_(scratch, dst, t9);
+      and_(overflow_dst, scratch, overflow_dst);
+    }
+  }
+}
+
+
+void MacroAssembler::AdduAndCheckForOverflow(Register dst, Register left,
                                              Register right,
                                              Register overflow_dst,
                                              Register scratch) {
@@ -4519,8 +4672,34 @@
 }
 
 
-void MacroAssembler::SubuAndCheckForOverflow(Register dst,
-                                             Register left,
+void MacroAssembler::SubuAndCheckForOverflow(Register dst, Register left,
+                                             const Operand& right,
+                                             Register overflow_dst,
+                                             Register scratch) {
+  if (right.is_reg()) {
+    SubuAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
+  } else {
+    if (dst.is(left)) {
+      mov(scratch, left);                      // Preserve left.
+      addiu(dst, left, -(right.immediate()));  // Left is overwritten.
+      xor_(overflow_dst, dst, scratch);        // scratch is original left.
+      // Load right since xori takes uint16 as immediate.
+      addiu(t9, zero_reg, right.immediate());
+      xor_(scratch, scratch, t9);  // scratch is original left.
+      and_(overflow_dst, scratch, overflow_dst);
+    } else {
+      addiu(dst, left, -(right.immediate()));
+      xor_(overflow_dst, dst, left);
+      // Load right since xori takes uint16 as immediate.
+      addiu(t9, zero_reg, right.immediate());
+      xor_(scratch, left, t9);
+      and_(overflow_dst, scratch, overflow_dst);
+    }
+  }
+}
+
+
+void MacroAssembler::SubuAndCheckForOverflow(Register dst, Register left,
                                              Register right,
                                              Register overflow_dst,
                                              Register scratch) {
@@ -4887,6 +5066,13 @@
 }
 
 
+void MacroAssembler::EnterFrame(StackFrame::Type type,
+                                bool load_constant_pool_pointer_reg) {
+  // Out-of-line constant pool not implemented on mips.
+  UNREACHABLE();
+}
+
+
 void MacroAssembler::EnterFrame(StackFrame::Type type) {
   addiu(sp, sp, -5 * kPointerSize);
   li(t8, Operand(Smi::FromInt(type)));
@@ -5619,18 +5805,6 @@
 }
 
 
-void MacroAssembler::CheckMapDeprecated(Handle<Map> map,
-                                        Register scratch,
-                                        Label* if_deprecated) {
-  if (map->CanBeDeprecated()) {
-    li(scratch, Operand(map));
-    lw(scratch, FieldMemOperand(scratch, Map::kBitField3Offset));
-    And(scratch, scratch, Operand(Map::Deprecated::kMask));
-    Branch(if_deprecated, ne, scratch, Operand(zero_reg));
-  }
-}
-
-
 void MacroAssembler::JumpIfBlack(Register object,
                                  Register scratch0,
                                  Register scratch1,
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index ce52986..0bc1e15 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -250,8 +250,10 @@
     Mthc1(src_high, dst);
   }
 
-  // Conditional move.
+  void Move(FPURegister dst, float imm);
   void Move(FPURegister dst, double imm);
+
+  // Conditional move.
   void Movz(Register rd, Register rs, Register rt);
   void Movn(Register rd, Register rs, Register rt);
   void Movt(Register rd, Register rs, uint16_t cc = 0);
@@ -313,10 +315,6 @@
                      Condition cc,
                      Label* condition_met);
 
-  void CheckMapDeprecated(Handle<Map> map,
-                          Register scratch,
-                          Label* if_deprecated);
-
   // Check if object is in new space.  Jumps if the object is not in new space.
   // The register scratch can be object itself, but it will be clobbered.
   void JumpIfNotInNewSpace(Register object,
@@ -587,9 +585,13 @@
   DEFINE_INSTRUCTION(Addu);
   DEFINE_INSTRUCTION(Subu);
   DEFINE_INSTRUCTION(Mul);
+  DEFINE_INSTRUCTION(Div);
+  DEFINE_INSTRUCTION(Divu);
   DEFINE_INSTRUCTION(Mod);
+  DEFINE_INSTRUCTION(Modu);
   DEFINE_INSTRUCTION(Mulh);
   DEFINE_INSTRUCTION2(Mult);
+  DEFINE_INSTRUCTION(Mulhu);
   DEFINE_INSTRUCTION2(Multu);
   DEFINE_INSTRUCTION2(Div);
   DEFINE_INSTRUCTION2(Divu);
@@ -1078,15 +1080,19 @@
                 Label* fail,
                 SmiCheckType smi_check_type);
 
-  // Check if the map of an object is equal to a specified map and branch to a
-  // specified target if equal. Skip the smi check if not required (object is
-  // known to be a heap object)
-  void DispatchMap(Register obj,
-                   Register scratch,
-                   Handle<Map> map,
-                   Handle<Code> success,
-                   SmiCheckType smi_check_type);
+  // Check if the map of an object is equal to a specified weak map and branch
+  // to a specified target if equal. Skip the smi check if not required
+  // (object is known to be a heap object)
+  void DispatchWeakMap(Register obj, Register scratch1, Register scratch2,
+                       Handle<WeakCell> cell, Handle<Code> success,
+                       SmiCheckType smi_check_type);
 
+  // Get value of the weak cell.
+  void GetWeakValue(Register value, Handle<WeakCell> cell);
+
+  // Load the value of the weak cell in the value register. Branch to the
+  // given miss label is the weak cell was cleared.
+  void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
 
   // Load and check the instance type of an object for being a string.
   // Loads the type into the second argument register.
@@ -1142,12 +1148,20 @@
                                Register overflow_dst,
                                Register scratch = at);
 
+  void AdduAndCheckForOverflow(Register dst, Register left,
+                               const Operand& right, Register overflow_dst,
+                               Register scratch = at);
+
   void SubuAndCheckForOverflow(Register dst,
                                Register left,
                                Register right,
                                Register overflow_dst,
                                Register scratch = at);
 
+  void SubuAndCheckForOverflow(Register dst, Register left,
+                               const Operand& right, Register overflow_dst,
+                               Register scratch = at);
+
   void BranchOnOverflow(Label* label,
                         Register overflow_check,
                         BranchDelaySlot bd = PROTECT) {
@@ -1172,13 +1186,10 @@
   // Runtime calls.
 
   // See comments at the beginning of CEntryStub::Generate.
-  inline void PrepareCEntryArgs(int num_args) {
-    li(s0, num_args);
-    li(s1, (num_args - 1) * kPointerSize);
-  }
+  inline void PrepareCEntryArgs(int num_args) { li(a0, num_args); }
 
   inline void PrepareCEntryFunction(const ExternalReference& ref) {
-    li(s2, Operand(ref));
+    li(a1, Operand(ref));
   }
 
 #define COND_ARGS Condition cond = al, Register rs = zero_reg, \
@@ -1555,6 +1566,7 @@
 
   // Activation support.
   void EnterFrame(StackFrame::Type type);
+  void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
   void LeaveFrame(StackFrame::Type type);
 
   // Patch the relocated value (lui/ori pair).
@@ -1657,6 +1669,7 @@
 
   bool generating_stub_;
   bool has_frame_;
+  bool has_double_zero_reg_set_;
   // This handle will be patched with the code object on installation.
   Handle<Object> code_object_;
 
diff --git a/src/mips64/assembler-mips64-inl.h b/src/mips64/assembler-mips64-inl.h
index de294ee..76dd801 100644
--- a/src/mips64/assembler-mips64-inl.h
+++ b/src/mips64/assembler-mips64-inl.h
@@ -99,6 +99,11 @@
 }
 
 
+int DoubleRegister::NumAllocatableAliasedRegisters() {
+  return NumAllocatableRegisters();
+}
+
+
 int FPURegister::ToAllocationIndex(FPURegister reg) {
   DCHECK(reg.code() % 2 == 0);
   DCHECK(reg.code() / 2 < kMaxNumAllocatableRegisters);
diff --git a/src/mips64/assembler-mips64.cc b/src/mips64/assembler-mips64.cc
index 5d51e63..b8f5821 100644
--- a/src/mips64/assembler-mips64.cc
+++ b/src/mips64/assembler-mips64.cc
@@ -2192,6 +2192,14 @@
 }
 
 
+void Assembler::dext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
+  // Should be called via MacroAssembler::Ext.
+  // Dext instr has 'rt' field as dest, and two uint5: msb, lsb.
+  DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
+  GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, DEXT);
+}
+
+
 void Assembler::pref(int32_t hint, const MemOperand& rs) {
   DCHECK(is_uint5(hint) && is_uint16(rs.offset_));
   Instr instr = PREF | (rs.rm().code() << kRsShift) | (hint << kRtShift)
diff --git a/src/mips64/assembler-mips64.h b/src/mips64/assembler-mips64.h
index 5c754f4..5ca2f3a 100644
--- a/src/mips64/assembler-mips64.h
+++ b/src/mips64/assembler-mips64.h
@@ -211,6 +211,10 @@
 
   inline static int NumRegisters();
   inline static int NumAllocatableRegisters();
+
+  // TODO(turbofan): Proper support for float32.
+  inline static int NumAllocatableAliasedRegisters();
+
   inline static int ToAllocationIndex(FPURegister reg);
   static const char* AllocationIndexToString(int index);
 
@@ -882,6 +886,7 @@
   void clz(Register rd, Register rs);
   void ins_(Register rt, Register rs, uint16_t pos, uint16_t size);
   void ext_(Register rt, Register rs, uint16_t pos, uint16_t size);
+  void dext_(Register rt, Register rs, uint16_t pos, uint16_t size);
 
   // --------Coprocessor-instructions----------------
 
diff --git a/src/mips64/builtins-mips64.cc b/src/mips64/builtins-mips64.cc
index 5bdb56c..c95ff30 100644
--- a/src/mips64/builtins-mips64.cc
+++ b/src/mips64/builtins-mips64.cc
@@ -12,7 +12,7 @@
 #include "src/debug.h"
 #include "src/deoptimizer.h"
 #include "src/full-codegen.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -44,11 +44,9 @@
     DCHECK(extra_args == NO_EXTRA_ARGUMENTS);
   }
 
-  // JumpToExternalReference expects s0 to contain the number of arguments
+  // JumpToExternalReference expects a0 to contain the number of arguments
   // including the receiver and the extra arguments.
-  __ Daddu(s0, a0, num_extra_args + 1);
-  __ dsll(s1, s0, kPointerSizeLog2);
-  __ Dsubu(s1, s1, kPointerSize);
+  __ Daddu(a0, a0, num_extra_args + 1);
   __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
 }
 
@@ -384,24 +382,22 @@
         MemOperand bit_field3 = FieldMemOperand(a2, Map::kBitField3Offset);
         // Check if slack tracking is enabled.
         __ lwu(a4, bit_field3);
-        __ DecodeField<Map::ConstructionCount>(a6, a4);
-        __ Branch(&allocate,
-                  eq,
-                  a6,
-                  Operand(static_cast<int64_t>(JSFunction::kNoSlackTracking)));
+        __ DecodeField<Map::Counter>(a6, a4);
+        __ Branch(&allocate, lt, a6,
+                  Operand(static_cast<int64_t>(Map::kSlackTrackingCounterEnd)));
         // Decrease generous allocation count.
-        __ Dsubu(a4, a4, Operand(1 << Map::ConstructionCount::kShift));
-        __ Branch(USE_DELAY_SLOT,
-            &allocate, ne, a6, Operand(JSFunction::kFinishSlackTracking));
+        __ Dsubu(a4, a4, Operand(1 << Map::Counter::kShift));
+        __ Branch(USE_DELAY_SLOT, &allocate, ne, a6,
+                  Operand(Map::kSlackTrackingCounterEnd));
         __ sw(a4, bit_field3);  // In delay slot.
 
         __ Push(a1, a2, a1);  // a1 = Constructor.
         __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
 
         __ Pop(a1, a2);
-        // Slack tracking counter is kNoSlackTracking after runtime call.
-        DCHECK(JSFunction::kNoSlackTracking == 0);
-        __ mov(a6, zero_reg);
+        // Slack tracking counter is Map::kSlackTrackingCounterEnd after runtime
+        // call.
+        __ li(a6, Map::kSlackTrackingCounterEnd);
 
         __ bind(&allocate);
       }
@@ -448,10 +444,8 @@
         Label no_inobject_slack_tracking;
 
         // Check if slack tracking is enabled.
-        __ Branch(&no_inobject_slack_tracking,
-                  eq,
-                  a6,
-                  Operand(static_cast<int64_t>(JSFunction::kNoSlackTracking)));
+        __ Branch(&no_inobject_slack_tracking, lt, a6,
+                  Operand(static_cast<int64_t>(Map::kSlackTrackingCounterEnd)));
 
         // Allocate object with a slack.
         __ lwu(a0, FieldMemOperand(a2, Map::kInstanceSizesOffset));
@@ -782,11 +776,6 @@
     // a3: argc
     // s0: argv, i.e. points to first arg
     Label loop, entry;
-    // TODO(plind): At least on simulator, argc in a3 is an int32_t with junk
-    //    in upper bits. Should fix the root cause, rather than use below
-    //    workaround to clear upper bits.
-    __ dsll32(a3, a3, 0);  // int32_t -> int64_t.
-    __ dsrl32(a3, a3, 0);
     __ dsll(a4, a3, kPointerSizeLog2);
     __ daddu(a6, s0, a4);
     __ b(&entry);
@@ -1044,7 +1033,7 @@
 
   // Load deoptimization data from the code object.
   // <deopt_data> = <code>[#deoptimization_data_offset]
-  __ Uld(a1, MemOperand(v0, Code::kDeoptimizationDataOffset - kHeapObjectTag));
+  __ ld(a1, MemOperand(v0, Code::kDeoptimizationDataOffset - kHeapObjectTag));
 
   // Load the OSR entrypoint offset from the deoptimization data.
   // <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset]
diff --git a/src/mips64/code-stubs-mips64.cc b/src/mips64/code-stubs-mips64.cc
index 60263b5..6bbd1a3 100644
--- a/src/mips64/code-stubs-mips64.cc
+++ b/src/mips64/code-stubs-mips64.cc
@@ -14,7 +14,7 @@
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -268,66 +268,6 @@
 }
 
 
-void WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(
-    Isolate* isolate) {
-  WriteInt32ToHeapNumberStub stub1(isolate, a1, v0, a2, a3);
-  WriteInt32ToHeapNumberStub stub2(isolate, a2, v0, a3, a0);
-  stub1.GetCode();
-  stub2.GetCode();
-}
-
-
-// See comment for class, this does NOT work for int32's that are in Smi range.
-void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) {
-  Label max_negative_int;
-  // the_int_ has the answer which is a signed int32 but not a Smi.
-  // We test for the special value that has a different exponent.
-  STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
-  // Test sign, and save for later conditionals.
-  __ And(sign(), the_int(), Operand(0x80000000u));
-  __ Branch(&max_negative_int, eq, the_int(), Operand(0x80000000u));
-
-  // Set up the correct exponent in scratch_.  All non-Smi int32s have the same.
-  // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased).
-  uint32_t non_smi_exponent =
-      (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
-  __ li(scratch(), Operand(non_smi_exponent));
-  // Set the sign bit in scratch_ if the value was negative.
-  __ or_(scratch(), scratch(), sign());
-  // Subtract from 0 if the value was negative.
-  __ subu(at, zero_reg, the_int());
-  __ Movn(the_int(), at, sign());
-  // We should be masking the implict first digit of the mantissa away here,
-  // but it just ends up combining harmlessly with the last digit of the
-  // exponent that happens to be 1.  The sign bit is 0 so we shift 10 to get
-  // the most significant 1 to hit the last bit of the 12 bit sign and exponent.
-  DCHECK(((1 << HeapNumber::kExponentShift) & non_smi_exponent) != 0);
-  const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
-  __ srl(at, the_int(), shift_distance);
-  __ or_(scratch(), scratch(), at);
-  __ sw(scratch(), FieldMemOperand(the_heap_number(),
-                                   HeapNumber::kExponentOffset));
-  __ sll(scratch(), the_int(), 32 - shift_distance);
-  __ Ret(USE_DELAY_SLOT);
-  __ sw(scratch(), FieldMemOperand(the_heap_number(),
-                                   HeapNumber::kMantissaOffset));
-
-  __ bind(&max_negative_int);
-  // The max negative int32 is stored as a positive number in the mantissa of
-  // a double because it uses a sign bit instead of using two's complement.
-  // The actual mantissa bits stored are all 0 because the implicit most
-  // significant 1 bit is not stored.
-  non_smi_exponent += 1 << HeapNumber::kExponentShift;
-  __ li(scratch(), Operand(HeapNumber::kSignMask | non_smi_exponent));
-  __ sw(scratch(),
-        FieldMemOperand(the_heap_number(), HeapNumber::kExponentOffset));
-  __ mov(scratch(), zero_reg);
-  __ Ret(USE_DELAY_SLOT);
-  __ sw(scratch(),
-        FieldMemOperand(the_heap_number(), HeapNumber::kMantissaOffset));
-}
-
-
 // Handle the case where the lhs and rhs are the same object.
 // Equality is almost reflexive (everything but NaN), so this is a test
 // for "identity and not NaN".
@@ -911,7 +851,7 @@
       // double_scratch can be overwritten in the delay slot.
       // Calculates square root of base.  Check for the special case of
       // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
-      __ Move(double_scratch, -V8_INFINITY);
+      __ Move(double_scratch, static_cast<double>(-V8_INFINITY));
       __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch);
       __ neg_d(double_result, double_scratch);
 
@@ -931,13 +871,13 @@
       // double_scratch can be overwritten in the delay slot.
       // Calculates square root of base.  Check for the special case of
       // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
-      __ Move(double_scratch, -V8_INFINITY);
+      __ Move(double_scratch, static_cast<double>(-V8_INFINITY));
       __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch);
       __ Move(double_result, kDoubleRegZero);
 
       // Add +0 to convert -0 to +0.
       __ add_d(double_scratch, double_base, kDoubleRegZero);
-      __ Move(double_result, 1);
+      __ Move(double_result, 1.);
       __ sqrt_d(double_scratch, double_scratch);
       __ div_d(double_result, double_result, double_scratch);
       __ jmp(&done);
@@ -1053,7 +993,6 @@
 
 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
   CEntryStub::GenerateAheadOfTime(isolate);
-  WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
   StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
   StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
@@ -1094,22 +1033,18 @@
 
 void CEntryStub::Generate(MacroAssembler* masm) {
   // Called from JavaScript; parameters are on stack as if calling JS function
-  // s0: number of arguments including receiver
-  // s1: size of arguments excluding receiver
-  // s2: pointer to builtin function
+  // a0: number of arguments including receiver
+  // a1: pointer to builtin function
   // fp: frame pointer    (restored after C call)
   // sp: stack pointer    (restored as callee's sp after C call)
   // cp: current context  (C callee-saved)
 
   ProfileEntryHookStub::MaybeCallEntryHook(masm);
 
-  // NOTE: s0-s2 hold the arguments of this function instead of a0-a2.
-  // The reason for this is that these arguments would need to be saved anyway
-  // so it's faster to set them up directly.
-  // See MacroAssembler::PrepareCEntryArgs and PrepareCEntryFunction.
-
   // Compute the argv pointer in a callee-saved register.
+  __ dsll(s1, a0, kPointerSizeLog2);
   __ Daddu(s1, sp, s1);
+  __ Dsubu(s1, s1, kPointerSize);
 
   // Enter the exit frame that transitions from JavaScript to C++.
   FrameScope scope(masm, StackFrame::MANUAL);
@@ -1121,7 +1056,8 @@
 
   // Prepare arguments for C routine.
   // a0 = argc
-  __ mov(a0, s0);
+  __ mov(s0, a0);
+  __ mov(s2, a1);
   // a1 = argv (set in the delay slot after find_ra below).
 
   // We are calling compiled C/C++ code. a0 and a1 hold our two arguments. We
@@ -1405,6 +1341,40 @@
 }
 
 
+void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
+  // Return address is in ra.
+  Label miss;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register index = LoadDescriptor::NameRegister();
+  Register scratch = a4;
+  Register result = v0;
+  DCHECK(!scratch.is(receiver) && !scratch.is(index));
+  DCHECK(!FLAG_vector_ics ||
+         (!scratch.is(VectorLoadICDescriptor::VectorRegister()) &&
+          result.is(VectorLoadICDescriptor::SlotRegister())));
+
+  // StringCharAtGenerator doesn't use the result register until it's passed
+  // the different miss possibilities. If it did, we would have a conflict
+  // when FLAG_vector_ics is true.
+  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
+                                          &miss,  // When not a string.
+                                          &miss,  // When not a number.
+                                          &miss,  // When index out of range.
+                                          STRING_INDEX_IS_ARRAY_INDEX,
+                                          RECEIVER_IS_STRING);
+  char_at_generator.GenerateFast(masm);
+  __ Ret();
+
+  StubRuntimeCallHelper call_helper;
+  char_at_generator.GenerateSlow(masm, call_helper);
+
+  __ bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
 // Uses registers a0 to a4.
 // Expected input (depending on whether args are in registers or on the stack):
 // * object: a0 or at sp + 1 * kPointerSize.
@@ -1416,8 +1386,6 @@
 void InstanceofStub::Generate(MacroAssembler* masm) {
   // Call site inlining and patching implies arguments in registers.
   DCHECK(HasArgsInRegisters() || !HasCallSiteInlineCheck());
-  // ReturnTrueFalse is only implemented for inlined call sites.
-  DCHECK(!ReturnTrueFalseObject() || HasCallSiteInlineCheck());
 
   // Fixed register usage throughout the stub:
   const Register object = a0;  // Object (lhs).
@@ -1442,7 +1410,7 @@
 
   // If there is a call site cache don't look in the global cache, but do the
   // real lookup and update the call site cache.
-  if (!HasCallSiteInlineCheck()) {
+  if (!HasCallSiteInlineCheck() && !ReturnTrueFalseObject()) {
     Label miss;
     __ LoadRoot(at, Heap::kInstanceofCacheFunctionRootIndex);
     __ Branch(&miss, ne, function, Operand(at));
@@ -1501,6 +1469,9 @@
   if (!HasCallSiteInlineCheck()) {
     __ mov(v0, zero_reg);
     __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex);
+    if (ReturnTrueFalseObject()) {
+      __ LoadRoot(v0, Heap::kTrueValueRootIndex);
+    }
   } else {
     // Patch the call site to return true.
     __ LoadRoot(v0, Heap::kTrueValueRootIndex);
@@ -1519,6 +1490,9 @@
   if (!HasCallSiteInlineCheck()) {
     __ li(v0, Operand(Smi::FromInt(1)));
     __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex);
+    if (ReturnTrueFalseObject()) {
+      __ LoadRoot(v0, Heap::kFalseValueRootIndex);
+    }
   } else {
     // Patch the call site to return false.
     __ LoadRoot(v0, Heap::kFalseValueRootIndex);
@@ -1542,23 +1516,33 @@
   __ Branch(&slow, ne, scratch, Operand(JS_FUNCTION_TYPE));
 
   // Null is not instance of anything.
-  __ Branch(&object_not_null,
-            ne,
-            scratch,
+  __ Branch(&object_not_null, ne, object,
             Operand(isolate()->factory()->null_value()));
-  __ li(v0, Operand(Smi::FromInt(1)));
+  if (ReturnTrueFalseObject()) {
+    __ LoadRoot(v0, Heap::kFalseValueRootIndex);
+  } else {
+    __ li(v0, Operand(Smi::FromInt(1)));
+  }
   __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
 
   __ bind(&object_not_null);
   // Smi values are not instances of anything.
   __ JumpIfNotSmi(object, &object_not_null_or_smi);
-  __ li(v0, Operand(Smi::FromInt(1)));
+  if (ReturnTrueFalseObject()) {
+    __ LoadRoot(v0, Heap::kFalseValueRootIndex);
+  } else {
+    __ li(v0, Operand(Smi::FromInt(1)));
+  }
   __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
 
   __ bind(&object_not_null_or_smi);
   // String values are not instances of anything.
   __ IsObjectJSStringType(object, scratch, &slow);
-  __ li(v0, Operand(Smi::FromInt(1)));
+  if (ReturnTrueFalseObject()) {
+    __ LoadRoot(v0, Heap::kFalseValueRootIndex);
+  } else {
+    __ li(v0, Operand(Smi::FromInt(1)));
+  }
   __ DropAndRet(HasArgsInRegisters() ? 0 : 2);
 
   // Slow-case.  Tail call builtin.
@@ -1586,8 +1570,14 @@
 void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
   Label miss;
   Register receiver = LoadDescriptor::ReceiverRegister();
-  NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, a3,
-                                                          a4, &miss);
+  // Ensure that the vector and slot registers won't be clobbered before
+  // calling the miss handler.
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(a4, a5, VectorLoadICDescriptor::VectorRegister(),
+                     VectorLoadICDescriptor::SlotRegister()));
+
+  NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, a4,
+                                                          a5, &miss);
   __ bind(&miss);
   PropertyAccessCompiler::TailCallBuiltin(
       masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
@@ -2539,14 +2529,14 @@
 
   // A monomorphic miss (i.e, here the cache is not uninitialized) goes
   // megamorphic.
-  __ LoadRoot(at, Heap::kUninitializedSymbolRootIndex);
+  __ LoadRoot(at, Heap::kuninitialized_symbolRootIndex);
   __ Branch(&initialize, eq, a4, Operand(at));
   // MegamorphicSentinel is an immortal immovable object (undefined) so no
   // write-barrier is needed.
   __ bind(&megamorphic);
   __ dsrl(a4, a3, 32- kPointerSizeLog2);
   __ Daddu(a4, a2, Operand(a4));
-  __ LoadRoot(at, Heap::kMegamorphicSymbolRootIndex);
+  __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
   __ sd(at, FieldMemOperand(a4, FixedArray::kHeaderSize));
   __ jmp(&done);
 
@@ -2783,14 +2773,16 @@
   DCHECK(!a4.is(object_));
 
   // If the receiver is a smi trigger the non-string case.
-  __ JumpIfSmi(object_, receiver_not_string_);
+  if (check_mode_ == RECEIVER_IS_UNKNOWN) {
+    __ JumpIfSmi(object_, receiver_not_string_);
 
-  // Fetch the instance type of the receiver into result register.
-  __ ld(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
-  __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
-  // If the receiver is not a string trigger the non-string case.
-  __ And(a4, result_, Operand(kIsNotStringMask));
-  __ Branch(receiver_not_string_, ne, a4, Operand(zero_reg));
+    // Fetch the instance type of the receiver into result register.
+    __ ld(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
+    __ lbu(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
+    // If the receiver is not a string trigger the non-string case.
+    __ And(a4, result_, Operand(kIsNotStringMask));
+    __ Branch(receiver_not_string_, ne, a4, Operand(zero_reg));
+  }
 
   // If the index is non-smi trigger the non-smi case.
   __ JumpIfNotSmi(index_, &index_not_smi_);
@@ -2864,6 +2856,10 @@
 void CallICStub::Generate(MacroAssembler* masm) {
   // a1 - function
   // a3 - slot id (Smi)
+  const int with_types_offset =
+      FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
+  const int generic_offset =
+      FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
   Label slow, non_function, wrap, cont;
   Label have_js_function;
@@ -2902,27 +2898,71 @@
   }
 
   __ bind(&extra_checks_or_miss);
-  Label miss;
+  Label uninitialized, miss;
 
-  __ LoadRoot(at, Heap::kMegamorphicSymbolRootIndex);
+  __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
   __ Branch(&slow_start, eq, a4, Operand(at));
-  __ LoadRoot(at, Heap::kUninitializedSymbolRootIndex);
-  __ Branch(&miss, eq, a4, Operand(at));
 
-  if (!FLAG_trace_ic) {
-    // We are going megamorphic. If the feedback is a JSFunction, it is fine
-    // to handle it here. More complex cases are dealt with in the runtime.
-    __ AssertNotSmi(a4);
-    __ GetObjectType(a4, a5, a5);
-    __ Branch(&miss, ne, a5, Operand(JS_FUNCTION_TYPE));
-    __ dsrl(a4, a3, 32 - kPointerSizeLog2);
-    __ Daddu(a4, a2, Operand(a4));
-    __ LoadRoot(at, Heap::kMegamorphicSymbolRootIndex);
-    __ sd(at, FieldMemOperand(a4, FixedArray::kHeaderSize));
-    __ Branch(&slow_start);
+  // The following cases attempt to handle MISS cases without going to the
+  // runtime.
+  if (FLAG_trace_ic) {
+    __ Branch(&miss);
   }
 
-  // We are here because tracing is on or we are going monomorphic.
+  __ LoadRoot(at, Heap::kuninitialized_symbolRootIndex);
+  __ Branch(&uninitialized, eq, a4, Operand(at));
+
+  // We are going megamorphic. If the feedback is a JSFunction, it is fine
+  // to handle it here. More complex cases are dealt with in the runtime.
+  __ AssertNotSmi(a4);
+  __ GetObjectType(a4, a5, a5);
+  __ Branch(&miss, ne, a5, Operand(JS_FUNCTION_TYPE));
+  __ dsrl(a4, a3, 32 - kPointerSizeLog2);
+  __ Daddu(a4, a2, Operand(a4));
+  __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
+  __ sd(at, FieldMemOperand(a4, FixedArray::kHeaderSize));
+  // We have to update statistics for runtime profiling.
+  __ ld(a4, FieldMemOperand(a2, with_types_offset));
+  __ Dsubu(a4, a4, Operand(Smi::FromInt(1)));
+  __ sd(a4, FieldMemOperand(a2, with_types_offset));
+  __ ld(a4, FieldMemOperand(a2, generic_offset));
+  __ Daddu(a4, a4, Operand(Smi::FromInt(1)));
+  __ Branch(USE_DELAY_SLOT, &slow_start);
+  __ sd(a4, FieldMemOperand(a2, generic_offset));  // In delay slot.
+
+  __ bind(&uninitialized);
+
+  // We are going monomorphic, provided we actually have a JSFunction.
+  __ JumpIfSmi(a1, &miss);
+
+  // Goto miss case if we do not have a function.
+  __ GetObjectType(a1, a4, a4);
+  __ Branch(&miss, ne, a4, Operand(JS_FUNCTION_TYPE));
+
+  // Make sure the function is not the Array() function, which requires special
+  // behavior on MISS.
+  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, a4);
+  __ Branch(&miss, eq, a1, Operand(a4));
+
+  // Update stats.
+  __ ld(a4, FieldMemOperand(a2, with_types_offset));
+  __ Daddu(a4, a4, Operand(Smi::FromInt(1)));
+  __ sd(a4, FieldMemOperand(a2, with_types_offset));
+
+  // Store the function.
+  __ dsrl(a4, a3, 32 - kPointerSizeLog2);
+  __ Daddu(a4, a2, Operand(a4));
+  __ Daddu(a4, a4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ sd(a1, MemOperand(a4, 0));
+
+  // Update the write barrier.
+  __ mov(a5, a1);
+  __ RecordWrite(a2, a4, a5, kRAHasNotBeenSaved, kDontSaveFPRegs,
+                 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+  __ Branch(&have_js_function);
+
+  // We are here because tracing is on or we encountered a MISS case we can't
+  // handle here.
   __ bind(&miss);
   GenerateMiss(masm);
 
@@ -3329,14 +3369,57 @@
   // a1: instance type
   // a2: length
   // a3: from index (untagged)
-  StringCharAtGenerator generator(
-      v0, a3, a2, v0, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
+  StringCharAtGenerator generator(v0, a3, a2, v0, &runtime, &runtime, &runtime,
+                                  STRING_INDEX_IS_NUMBER, RECEIVER_IS_STRING);
   generator.GenerateFast(masm);
   __ DropAndRet(3);
   generator.SkipSlow(masm, &runtime);
 }
 
 
+void ToNumberStub::Generate(MacroAssembler* masm) {
+  // The ToNumber stub takes one argument in a0.
+  Label not_smi;
+  __ JumpIfNotSmi(a0, &not_smi);
+  __ Ret(USE_DELAY_SLOT);
+  __ mov(v0, a0);
+  __ bind(&not_smi);
+
+  Label not_heap_number;
+  __ ld(a1, FieldMemOperand(a0, HeapObject::kMapOffset));
+  __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset));
+  // a0: object
+  // a1: instance type.
+  __ Branch(&not_heap_number, ne, a1, Operand(HEAP_NUMBER_TYPE));
+  __ Ret(USE_DELAY_SLOT);
+  __ mov(v0, a0);
+  __ bind(&not_heap_number);
+
+  Label not_string, slow_string;
+  __ Branch(&not_string, hs, a1, Operand(FIRST_NONSTRING_TYPE));
+  // Check if string has a cached array index.
+  __ ld(a2, FieldMemOperand(a0, String::kHashFieldOffset));
+  __ And(at, a2, Operand(String::kContainsCachedArrayIndexMask));
+  __ Branch(&slow_string, ne, at, Operand(zero_reg));
+  __ IndexFromHash(a2, a0);
+  __ Ret(USE_DELAY_SLOT);
+  __ mov(v0, a0);
+  __ bind(&slow_string);
+  __ push(a0);  // Push argument.
+  __ TailCallRuntime(Runtime::kStringToNumber, 1, 1);
+  __ bind(&not_string);
+
+  Label not_oddball;
+  __ Branch(&not_oddball, ne, a1, Operand(ODDBALL_TYPE));
+  __ Ret(USE_DELAY_SLOT);
+  __ ld(v0, FieldMemOperand(a0, Oddball::kToNumberOffset));
+  __ bind(&not_oddball);
+
+  __ push(a0);  // Push argument.
+  __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
+}
+
+
 void StringHelper::GenerateFlatOneByteStringEquals(
     MacroAssembler* masm, Register left, Register right, Register scratch1,
     Register scratch2, Register scratch3) {
diff --git a/src/mips64/code-stubs-mips64.h b/src/mips64/code-stubs-mips64.h
index 6c324bb..edc1bd2 100644
--- a/src/mips64/code-stubs-mips64.h
+++ b/src/mips64/code-stubs-mips64.h
@@ -73,56 +73,6 @@
   DEFINE_PLATFORM_CODE_STUB(RestoreRegistersState, PlatformCodeStub);
 };
 
-// This stub can convert a signed int32 to a heap number (double).  It does
-// not work for int32s that are in Smi range!  No GC occurs during this stub
-// so you don't have to set up the frame.
-class WriteInt32ToHeapNumberStub : public PlatformCodeStub {
- public:
-  WriteInt32ToHeapNumberStub(Isolate* isolate, Register the_int,
-                             Register the_heap_number, Register scratch,
-                             Register scratch2)
-      : PlatformCodeStub(isolate) {
-    minor_key_ = IntRegisterBits::encode(the_int.code()) |
-                 HeapNumberRegisterBits::encode(the_heap_number.code()) |
-                 ScratchRegisterBits::encode(scratch.code()) |
-                 SignRegisterBits::encode(scratch2.code());
-    DCHECK(IntRegisterBits::is_valid(the_int.code()));
-    DCHECK(HeapNumberRegisterBits::is_valid(the_heap_number.code()));
-    DCHECK(ScratchRegisterBits::is_valid(scratch.code()));
-    DCHECK(SignRegisterBits::is_valid(scratch2.code()));
-  }
-
-  static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
-
- private:
-  void Generate(MacroAssembler* masm);
-
-  Register the_int() const {
-    return Register::from_code(IntRegisterBits::decode(minor_key_));
-  }
-
-  Register the_heap_number() const {
-    return Register::from_code(HeapNumberRegisterBits::decode(minor_key_));
-  }
-
-  Register scratch() const {
-    return Register::from_code(ScratchRegisterBits::decode(minor_key_));
-  }
-
-  Register sign() const {
-    return Register::from_code(SignRegisterBits::decode(minor_key_));
-  }
-
-  // Minor key encoding in 16 bits.
-  class IntRegisterBits: public BitField<int, 0, 4> {};
-  class HeapNumberRegisterBits: public BitField<int, 4, 4> {};
-  class ScratchRegisterBits: public BitField<int, 8, 4> {};
-  class SignRegisterBits: public BitField<int, 12, 4> {};
-
-  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
-  DEFINE_CODE_STUB(WriteInt32ToHeapNumber, PlatformCodeStub);
-};
-
 
 class RecordWriteStub: public PlatformCodeStub {
  public:
@@ -152,7 +102,7 @@
     INCREMENTAL_COMPACTION
   };
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
   static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
     const unsigned offset = masm->instr_at(pos) & kImm16Mask;
@@ -279,9 +229,9 @@
     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
   };
 
-  virtual inline Major MajorKey() const FINAL OVERRIDE { return RecordWrite; }
+  inline Major MajorKey() const FINAL { return RecordWrite; }
 
-  virtual void Generate(MacroAssembler* masm) OVERRIDE;
+  void Generate(MacroAssembler* masm) OVERRIDE;
   void GenerateIncremental(MacroAssembler* masm, Mode mode);
   void CheckNeedsToInformIncrementalMarker(
       MacroAssembler* masm,
@@ -289,7 +239,7 @@
       Mode mode);
   void InformIncrementalMarker(MacroAssembler* masm);
 
-  void Activate(Code* code) {
+  void Activate(Code* code) OVERRIDE {
     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
   }
 
@@ -337,7 +287,7 @@
   void GenerateCall(MacroAssembler* masm, Register target);
 
  private:
-  bool NeedsImmovableCode() { return true; }
+  bool NeedsImmovableCode() OVERRIDE { return true; }
 
   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
   DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
@@ -369,7 +319,7 @@
                                      Register r0,
                                      Register r1);
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
  private:
   static const int kInlinedProbes = 4;
diff --git a/src/mips64/codegen-mips64.cc b/src/mips64/codegen-mips64.cc
index fb395f7..b292506 100644
--- a/src/mips64/codegen-mips64.cc
+++ b/src/mips64/codegen-mips64.cc
@@ -786,9 +786,23 @@
   __ Daddu(src_elements, src_elements,
       Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag + 4));
   __ Daddu(dst_elements, array, Operand(FixedArray::kHeaderSize));
-  __ Daddu(array, array, Operand(kHeapObjectTag));
   __ SmiScale(dst_end, dst_end, kPointerSizeLog2);
   __ Daddu(dst_end, dst_elements, dst_end);
+
+  // Allocating heap numbers in the loop below can fail and cause a jump to
+  // gc_required. We can't leave a partly initialized FixedArray behind,
+  // so pessimistically fill it with holes now.
+  Label initialization_loop, initialization_loop_entry;
+  __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
+  __ Branch(&initialization_loop_entry);
+  __ bind(&initialization_loop);
+  __ sd(scratch, MemOperand(dst_elements));
+  __ Daddu(dst_elements, dst_elements, Operand(kPointerSize));
+  __ bind(&initialization_loop_entry);
+  __ Branch(&initialization_loop, lt, dst_elements, Operand(dst_end));
+
+  __ Daddu(dst_elements, array, Operand(FixedArray::kHeaderSize));
+  __ Daddu(array, array, Operand(kHeapObjectTag));
   __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
   // Using offsetted addresses.
   // dst_elements: begin of destination FixedArray element fields, not tagged
@@ -1019,7 +1033,7 @@
   // Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1.
   DCHECK(*reinterpret_cast<double*>
          (ExternalReference::math_exp_constants(8).address()) == 1);
-  __ Move(double_scratch2, 1);
+  __ Move(double_scratch2, 1.);
   __ add_d(result, result, double_scratch2);
   __ dsrl(temp1, temp2, 11);
   __ Ext(temp2, temp2, 0, 11);
diff --git a/src/mips64/constants-mips64.cc b/src/mips64/constants-mips64.cc
index dfd6243..dd34c57 100644
--- a/src/mips64/constants-mips64.cc
+++ b/src/mips64/constants-mips64.cc
@@ -287,6 +287,7 @@
       switch (FunctionFieldRaw()) {
         case INS:
         case EXT:
+        case DEXT:
           return kRegisterType;
         default:
           return kUnsupported;
diff --git a/src/mips64/constants-mips64.h b/src/mips64/constants-mips64.h
index 521869b..d12148a 100644
--- a/src/mips64/constants-mips64.h
+++ b/src/mips64/constants-mips64.h
@@ -574,52 +574,49 @@
 // because 'NegateCondition' function flips LSB to negate condition.
 enum Condition {
   // Any value < 0 is considered no_condition.
-  kNoCondition  = -1,
-
-  overflow      =  0,
-  no_overflow   =  1,
-  Uless         =  2,
-  Ugreater_equal=  3,
-  equal         =  4,
-  not_equal     =  5,
-  Uless_equal   =  6,
-  Ugreater      =  7,
-  negative      =  8,
-  positive      =  9,
-  parity_even   = 10,
-  parity_odd    = 11,
-  less          = 12,
+  kNoCondition = -1,
+  overflow = 0,
+  no_overflow = 1,
+  Uless = 2,
+  Ugreater_equal = 3,
+  equal = 4,
+  not_equal = 5,
+  Uless_equal = 6,
+  Ugreater = 7,
+  negative = 8,
+  positive = 9,
+  parity_even = 10,
+  parity_odd = 11,
+  less = 12,
   greater_equal = 13,
-  less_equal    = 14,
-  greater       = 15,
-  ueq           = 16,  // Unordered or Equal.
-  nue           = 17,  // Not (Unordered or Equal).
-
-  cc_always     = 18,
+  less_equal = 14,
+  greater = 15,
+  ueq = 16,  // Unordered or Equal.
+  nue = 17,  // Not (Unordered or Equal).
+  cc_always = 18,
 
   // Aliases.
-  carry         = Uless,
-  not_carry     = Ugreater_equal,
-  zero          = equal,
-  eq            = equal,
-  not_zero      = not_equal,
-  ne            = not_equal,
-  nz            = not_equal,
-  sign          = negative,
-  not_sign      = positive,
-  mi            = negative,
-  pl            = positive,
-  hi            = Ugreater,
-  ls            = Uless_equal,
-  ge            = greater_equal,
-  lt            = less,
-  gt            = greater,
-  le            = less_equal,
-  hs            = Ugreater_equal,
-  lo            = Uless,
-  al            = cc_always,
-
-  cc_default    = kNoCondition
+  carry = Uless,
+  not_carry = Ugreater_equal,
+  zero = equal,
+  eq = equal,
+  not_zero = not_equal,
+  ne = not_equal,
+  nz = not_equal,
+  sign = negative,
+  not_sign = positive,
+  mi = negative,
+  pl = positive,
+  hi = Ugreater,
+  ls = Uless_equal,
+  ge = greater_equal,
+  lt = less,
+  gt = greater,
+  le = less_equal,
+  hs = Ugreater_equal,
+  lo = Uless,
+  al = cc_always,
+  cc_default = kNoCondition
 };
 
 
diff --git a/src/mips64/debug-mips64.cc b/src/mips64/debug-mips64.cc
index 831dc4e..0bb0c4a 100644
--- a/src/mips64/debug-mips64.cc
+++ b/src/mips64/debug-mips64.cc
@@ -190,7 +190,11 @@
 void DebugCodegen::GenerateLoadICDebugBreak(MacroAssembler* masm) {
   Register receiver = LoadDescriptor::ReceiverRegister();
   Register name = LoadDescriptor::NameRegister();
-  Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit(), 0);
+  RegList regs = receiver.bit() | name.bit();
+  if (FLAG_vector_ics) {
+    regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
+  }
+  Generate_DebugBreakCallHelper(masm, regs, 0);
 }
 
 
diff --git a/src/mips64/deoptimizer-mips64.cc b/src/mips64/deoptimizer-mips64.cc
index 2550b76..d7a7f05 100644
--- a/src/mips64/deoptimizer-mips64.cc
+++ b/src/mips64/deoptimizer-mips64.cc
@@ -19,6 +19,12 @@
 }
 
 
+void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
+  // Empty because there is no need for relocation information for the code
+  // patching in Deoptimizer::PatchCodeForDeoptimization below.
+}
+
+
 void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
   Address code_start_address = code->instruction_start();
   // Invalidate the relocation information, as it will become invalid by the
@@ -101,9 +107,8 @@
   ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_);
   intptr_t handler = reinterpret_cast<intptr_t>(xref.address());
   int params = descriptor->GetHandlerParameterCount();
-  output_frame->SetRegister(s0.code(), params);
-  output_frame->SetRegister(s1.code(), (params - 1) * kPointerSize);
-  output_frame->SetRegister(s2.code(), handler);
+  output_frame->SetRegister(a0.code(), params);
+  output_frame->SetRegister(a1.code(), handler);
 }
 
 
diff --git a/src/mips64/disasm-mips64.cc b/src/mips64/disasm-mips64.cc
index d47950f..3f0642d 100644
--- a/src/mips64/disasm-mips64.cc
+++ b/src/mips64/disasm-mips64.cc
@@ -963,6 +963,10 @@
           Format(instr, "ext     'rt, 'rs, 'sa, 'ss1");
           break;
         }
+        case DEXT: {
+          Format(instr, "dext    'rt, 'rs, 'sa, 'ss1");
+          break;
+        }
         default:
           UNREACHABLE();
       }
diff --git a/src/mips64/full-codegen-mips64.cc b/src/mips64/full-codegen-mips64.cc
index 8f8c376..9d4ed09 100644
--- a/src/mips64/full-codegen-mips64.cc
+++ b/src/mips64/full-codegen-mips64.cc
@@ -201,10 +201,10 @@
     Comment cmnt(masm_, "[ Allocate context");
     // Argument to NewContext is the function, which is still in a1.
     bool need_write_barrier = true;
-    if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
+    if (FLAG_harmony_scoping && info->scope()->is_script_scope()) {
       __ push(a1);
       __ Push(info->scope()->GetScopeInfo());
-      __ CallRuntime(Runtime::kNewGlobalContext, 2);
+      __ CallRuntime(Runtime::kNewScriptContext, 2);
     } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
       FastNewContextStub stub(isolate(), heap_slots);
       __ CallStub(&stub);
@@ -924,7 +924,7 @@
   EmitDebugCheckDeclarationContext(variable);
 
   // Load instance object.
-  __ LoadContext(a1, scope_->ContextChainLength(scope_->GlobalScope()));
+  __ LoadContext(a1, scope_->ContextChainLength(scope_->ScriptScope()));
   __ ld(a1, ContextOperand(a1, variable->interface()->Index()));
   __ ld(a1, ContextOperand(a1, Context::EXTENSION_INDEX));
 
@@ -1088,7 +1088,7 @@
 
 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
   Comment cmnt(masm_, "[ ForInStatement");
-  int slot = stmt->ForInFeedbackSlot();
+  FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
   SetStatementPosition(stmt);
 
   Label loop, exit;
@@ -1097,6 +1097,7 @@
 
   // Get the object to enumerate over. If the object is null or undefined, skip
   // over the loop.  See ECMA-262 version 5, section 12.6.4.
+  SetExpressionPosition(stmt->enumerable());
   VisitForAccumulatorValue(stmt->enumerable());
   __ mov(a0, result_register());  // Result as param to InvokeBuiltin below.
   __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
@@ -1116,6 +1117,7 @@
   __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
   __ mov(a0, v0);
   __ bind(&done_convert);
+  PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
   __ push(a0);
 
   // Check for proxies.
@@ -1140,6 +1142,7 @@
   __ bind(&call_runtime);
   __ push(a0);  // Duplicate the enumerable object on the stack.
   __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
+  PrepareForBailoutForId(stmt->EnumId(), TOS_REG);
 
   // If we got a map from the runtime call, we can do a fast
   // modification check. Otherwise, we got a fixed array, and we have
@@ -1176,7 +1179,8 @@
 
   __ li(a1, FeedbackVector());
   __ li(a2, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate())));
-  __ sd(a2, FieldMemOperand(a1, FixedArray::OffsetOfElementAt(slot)));
+  int vector_index = FeedbackVector()->GetIndex(slot);
+  __ sd(a2, FieldMemOperand(a1, FixedArray::OffsetOfElementAt(vector_index)));
 
   __ li(a1, Operand(Smi::FromInt(1)));  // Smi indicates slow check
   __ ld(a2, MemOperand(sp, 0 * kPointerSize));  // Get enumerated object
@@ -1193,6 +1197,8 @@
   // Generate code for doing the condition check.
   PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
   __ bind(&loop);
+  SetExpressionPosition(stmt->each());
+
   // Load the current count to a0, load the length to a1.
   __ ld(a0, MemOperand(sp, 0 * kPointerSize));
   __ ld(a1, MemOperand(sp, 1 * kPointerSize));
@@ -1262,48 +1268,6 @@
 }
 
 
-void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
-  Comment cmnt(masm_, "[ ForOfStatement");
-  SetStatementPosition(stmt);
-
-  Iteration loop_statement(this, stmt);
-  increment_loop_depth();
-
-  // var iterator = iterable[Symbol.iterator]();
-  VisitForEffect(stmt->assign_iterator());
-
-  // Loop entry.
-  __ bind(loop_statement.continue_label());
-
-  // result = iterator.next()
-  VisitForEffect(stmt->next_result());
-
-  // if (result.done) break;
-  Label result_not_done;
-  VisitForControl(stmt->result_done(),
-                  loop_statement.break_label(),
-                  &result_not_done,
-                  &result_not_done);
-  __ bind(&result_not_done);
-
-  // each = result.value
-  VisitForEffect(stmt->assign_each());
-
-  // Generate code for the body of the loop.
-  Visit(stmt->body());
-
-  // Check stack before looping.
-  PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
-  EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
-  __ jmp(loop_statement.continue_label());
-
-  // Exit and decrement the loop depth.
-  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
-  __ bind(loop_statement.break_label());
-  decrement_loop_depth();
-}
-
-
 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
                                        bool pretenure) {
   // Use the fast case closure allocation code that allocates in new
@@ -1346,7 +1310,13 @@
   Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
   __ li(LoadDescriptor::NameRegister(), home_object_symbol);
 
-  CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  if (FLAG_vector_ics) {
+    __ li(VectorLoadICDescriptor::SlotRegister(),
+          Operand(SmiFromSlot(expr->HomeObjectFeedbackSlot())));
+    CallLoadIC(NOT_CONTEXTUAL);
+  } else {
+    CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  }
 
   Label done;
   __ Branch(&done, ne, v0, Operand(isolate()->factory()->undefined_value()));
@@ -1355,6 +1325,19 @@
 }
 
 
+void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
+                                                  int offset) {
+  if (NeedsHomeObject(initializer)) {
+    __ ld(StoreDescriptor::ReceiverRegister(), MemOperand(sp));
+    __ li(StoreDescriptor::NameRegister(),
+          Operand(isolate()->factory()->home_object_symbol()));
+    __ ld(StoreDescriptor::ValueRegister(),
+          MemOperand(sp, offset * kPointerSize));
+    CallStoreIC();
+  }
+}
+
+
 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
                                                       TypeofState typeof_state,
                                                       Label* slow) {
@@ -1404,7 +1387,7 @@
   __ li(LoadDescriptor::NameRegister(), Operand(proxy->var()->name()));
   if (FLAG_vector_ics) {
     __ li(VectorLoadICDescriptor::SlotRegister(),
-          Operand(Smi::FromInt(proxy->VariableFeedbackSlot())));
+          Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
   }
 
   ContextualMode mode = (typeof_state == INSIDE_TYPEOF)
@@ -1495,7 +1478,7 @@
       __ li(LoadDescriptor::NameRegister(), Operand(var->name()));
       if (FLAG_vector_ics) {
         __ li(VectorLoadICDescriptor::SlotRegister(),
-              Operand(Smi::FromInt(proxy->VariableFeedbackSlot())));
+              Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
       }
       CallLoadIC(CONTEXTUAL);
       context()->Plug(v0);
@@ -1673,6 +1656,7 @@
     FastCloneShallowObjectStub stub(isolate(), properties_count);
     __ CallStub(&stub);
   }
+  PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
 
   // If result_saved is true the result is on top of the stack.  If
   // result_saved is false the result is in v0.
@@ -1701,6 +1685,8 @@
         DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
         // Fall through.
       case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             VisitForAccumulatorValue(value);
@@ -1710,6 +1696,14 @@
             __ ld(StoreDescriptor::ReceiverRegister(), MemOperand(sp));
             CallStoreIC(key->LiteralFeedbackId());
             PrepareForBailoutForId(key->id(), NO_REGISTERS);
+
+            if (NeedsHomeObject(value)) {
+              __ Move(StoreDescriptor::ReceiverRegister(), v0);
+              __ li(StoreDescriptor::NameRegister(),
+                    Operand(isolate()->factory()->home_object_symbol()));
+              __ ld(StoreDescriptor::ValueRegister(), MemOperand(sp));
+              CallStoreIC();
+            }
           } else {
             VisitForEffect(value);
           }
@@ -1721,6 +1715,7 @@
         VisitForStackValue(key);
         VisitForStackValue(value);
         if (property->emit_store()) {
+          EmitSetHomeObjectIfNeeded(value, 2);
           __ li(a0, Operand(Smi::FromInt(SLOPPY)));  // PropertyAttributes.
           __ push(a0);
           __ CallRuntime(Runtime::kSetProperty, 4);
@@ -1734,7 +1729,7 @@
         __ push(a0);
         VisitForStackValue(value);
         if (property->emit_store()) {
-          __ CallRuntime(Runtime::kSetPrototype, 2);
+          __ CallRuntime(Runtime::kInternalSetPrototype, 2);
         } else {
           __ Drop(2);
         }
@@ -1757,7 +1752,9 @@
     __ push(a0);
     VisitForStackValue(it->first);
     EmitAccessor(it->second->getter);
+    EmitSetHomeObjectIfNeeded(it->second->getter, 2);
     EmitAccessor(it->second->setter);
+    EmitSetHomeObjectIfNeeded(it->second->setter, 3);
     __ li(a0, Operand(Smi::FromInt(NONE)));
     __ push(a0);
     __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
@@ -1869,16 +1866,8 @@
 
   Comment cmnt(masm_, "[ Assignment");
 
-  // Left-hand side can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* property = expr->target()->AsProperty();
-  if (property != NULL) {
-    assign_type = (property->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(property);
 
   // Evaluate LHS expression.
   switch (assign_type) {
@@ -1894,6 +1883,30 @@
         VisitForStackValue(property->obj());
       }
       break;
+    case NAMED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Push(result_register());
+      if (expr->is_compound()) {
+        const Register scratch = a1;
+        __ ld(scratch, MemOperand(sp, kPointerSize));
+        __ Push(scratch, result_register());
+      }
+      break;
+    case KEYED_SUPER_PROPERTY: {
+      const Register scratch = a1;
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Move(scratch, result_register());
+      VisitForAccumulatorValue(property->key());
+      __ Push(scratch, result_register());
+      if (expr->is_compound()) {
+        const Register scratch1 = a4;
+        __ ld(scratch1, MemOperand(sp, 2 * kPointerSize));
+        __ Push(scratch1, scratch, result_register());
+      }
+      break;
+    }
     case KEYED_PROPERTY:
       // We need the key and receiver on both the stack and in v0 and a1.
       if (expr->is_compound()) {
@@ -1922,6 +1935,14 @@
           EmitNamedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
           break;
+        case NAMED_SUPER_PROPERTY:
+          EmitNamedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
+        case KEYED_SUPER_PROPERTY:
+          EmitKeyedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
         case KEYED_PROPERTY:
           EmitKeyedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
@@ -1968,6 +1989,14 @@
     case NAMED_PROPERTY:
       EmitNamedPropertyAssignment(expr);
       break;
+    case NAMED_SUPER_PROPERTY:
+      EmitNamedSuperPropertyStore(property);
+      context()->Plug(v0);
+      break;
+    case KEYED_SUPER_PROPERTY:
+      EmitKeyedSuperPropertyStore(property);
+      context()->Plug(v0);
+      break;
     case KEYED_PROPERTY:
       EmitKeyedPropertyAssignment(expr);
       break;
@@ -2097,7 +2126,7 @@
       __ ld(load_name, MemOperand(sp, 2 * kPointerSize));
       if (FLAG_vector_ics) {
         __ li(VectorLoadICDescriptor::SlotRegister(),
-              Operand(Smi::FromInt(expr->KeyedLoadFeedbackSlot())));
+              Operand(SmiFromSlot(expr->KeyedLoadFeedbackSlot())));
       }
       Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
       CallIC(ic, TypeFeedbackId::None());
@@ -2117,7 +2146,7 @@
       __ LoadRoot(load_name, Heap::kdone_stringRootIndex);  // "done"
       if (FLAG_vector_ics) {
         __ li(VectorLoadICDescriptor::SlotRegister(),
-              Operand(Smi::FromInt(expr->DoneFeedbackSlot())));
+              Operand(SmiFromSlot(expr->DoneFeedbackSlot())));
       }
       CallLoadIC(NOT_CONTEXTUAL);                           // v0=result.done
       __ mov(a0, v0);
@@ -2130,7 +2159,7 @@
       __ LoadRoot(load_name, Heap::kvalue_stringRootIndex);  // "value"
       if (FLAG_vector_ics) {
         __ li(VectorLoadICDescriptor::SlotRegister(),
-              Operand(Smi::FromInt(expr->ValueFeedbackSlot())));
+              Operand(SmiFromSlot(expr->ValueFeedbackSlot())));
       }
       CallLoadIC(NOT_CONTEXTUAL);                            // v0=result.value
       context()->DropAndPlug(2, v0);                         // drop iter and g
@@ -2151,14 +2180,6 @@
   VisitForAccumulatorValue(value);
   __ pop(a1);
 
-  // Check generator state.
-  Label wrong_state, closed_state, done;
-  __ ld(a3, FieldMemOperand(a1, JSGeneratorObject::kContinuationOffset));
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
-  __ Branch(&closed_state, eq, a3, Operand(zero_reg));
-  __ Branch(&wrong_state, lt, a3, Operand(zero_reg));
-
   // Load suspended function and context.
   __ ld(cp, FieldMemOperand(a1, JSGeneratorObject::kContextOffset));
   __ ld(a4, FieldMemOperand(a1, JSGeneratorObject::kFunctionOffset));
@@ -2183,7 +2204,7 @@
 
   // Enter a new JavaScript frame, and initialize its slots as they were when
   // the generator was suspended.
-  Label resume_frame;
+  Label resume_frame, done;
   __ bind(&push_frame);
   __ Call(&resume_frame);
   __ jmp(&done);
@@ -2232,26 +2253,6 @@
   // Not reached: the runtime call returns elsewhere.
   __ stop("not-reached");
 
-  // Reach here when generator is closed.
-  __ bind(&closed_state);
-  if (resume_mode == JSGeneratorObject::NEXT) {
-    // Return completed iterator result when generator is closed.
-    __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
-    __ push(a2);
-    // Pop value from top-of-stack slot; box result into result register.
-    EmitCreateIteratorResult(true);
-  } else {
-    // Throw the provided value.
-    __ push(a0);
-    __ CallRuntime(Runtime::kThrow, 1);
-  }
-  __ jmp(&done);
-
-  // Throw error if we attempt to operate on a running generator.
-  __ bind(&wrong_state);
-  __ push(a1);
-  __ CallRuntime(Runtime::kThrowGeneratorStateError, 1);
-
   __ bind(&done);
   context()->Plug(result_register());
 }
@@ -2304,7 +2305,7 @@
   __ li(LoadDescriptor::NameRegister(), Operand(key->value()));
   if (FLAG_vector_ics) {
     __ li(VectorLoadICDescriptor::SlotRegister(),
-          Operand(Smi::FromInt(prop->PropertyFeedbackSlot())));
+          Operand(SmiFromSlot(prop->PropertyFeedbackSlot())));
     CallLoadIC(NOT_CONTEXTUAL);
   } else {
     CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
@@ -2313,15 +2314,12 @@
 
 
 void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object.
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
   DCHECK(!key->value()->IsSmi());
   DCHECK(prop->IsSuperAccess());
 
-  SuperReference* super_ref = prop->obj()->AsSuperReference();
-  EmitLoadHomeObject(super_ref);
-  __ Push(v0);
-  VisitForStackValue(super_ref->this_var());
   __ Push(key->value());
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 }
@@ -2333,7 +2331,7 @@
   Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
   if (FLAG_vector_ics) {
     __ li(VectorLoadICDescriptor::SlotRegister(),
-          Operand(Smi::FromInt(prop->PropertyFeedbackSlot())));
+          Operand(SmiFromSlot(prop->PropertyFeedbackSlot())));
     CallIC(ic);
   } else {
     CallIC(ic, prop->PropertyFeedbackId());
@@ -2341,6 +2339,14 @@
 }
 
 
+void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object, key.
+  SetSourcePosition(prop->position());
+
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+}
+
+
 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
                                               Token::Value op,
                                               OverwriteMode mode,
@@ -2433,6 +2439,63 @@
 }
 
 
+void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
+  // Constructor is in v0.
+  DCHECK(lit != NULL);
+  __ push(v0);
+
+  // No access check is needed here since the constructor is created by the
+  // class literal.
+  Register scratch = a1;
+  __ ld(scratch,
+        FieldMemOperand(v0, JSFunction::kPrototypeOrInitialMapOffset));
+  __ push(scratch);
+
+  for (int i = 0; i < lit->properties()->length(); i++) {
+    ObjectLiteral::Property* property = lit->properties()->at(i);
+    Literal* key = property->key()->AsLiteral();
+    Expression* value = property->value();
+    DCHECK(key != NULL);
+
+    if (property->is_static()) {
+      __ ld(scratch, MemOperand(sp, kPointerSize));  // constructor
+    } else {
+      __ ld(scratch, MemOperand(sp, 0));  // prototype
+    }
+    __ push(scratch);
+    VisitForStackValue(key);
+    VisitForStackValue(value);
+    EmitSetHomeObjectIfNeeded(value, 2);
+
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT:
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+      case ObjectLiteral::Property::COMPUTED:
+      case ObjectLiteral::Property::PROTOTYPE:
+        __ CallRuntime(Runtime::kDefineClassMethod, 3);
+        break;
+
+      case ObjectLiteral::Property::GETTER:
+        __ CallRuntime(Runtime::kDefineClassGetter, 3);
+        break;
+
+      case ObjectLiteral::Property::SETTER:
+        __ CallRuntime(Runtime::kDefineClassSetter, 3);
+        break;
+
+      default:
+        UNREACHABLE();
+    }
+  }
+
+  // prototype
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+
+  // constructor
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+}
+
+
 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
                                      Token::Value op,
                                      OverwriteMode mode) {
@@ -2449,16 +2512,8 @@
 void FullCodeGenerator::EmitAssignment(Expression* expr) {
   DCHECK(expr->IsValidReferenceExpression());
 
-  // Left-hand side can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* prop = expr->AsProperty();
-  if (prop != NULL) {
-    assign_type = (prop->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(prop);
 
   switch (assign_type) {
     case VARIABLE: {
@@ -2477,6 +2532,42 @@
       CallStoreIC();
       break;
     }
+    case NAMED_SUPER_PROPERTY: {
+      __ Push(v0);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      // stack: value, this; v0: home_object
+      Register scratch = a2;
+      Register scratch2 = a3;
+      __ mov(scratch, result_register());             // home_object
+      __ ld(v0, MemOperand(sp, kPointerSize));        // value
+      __ ld(scratch2, MemOperand(sp, 0));             // this
+      __ sd(scratch2, MemOperand(sp, kPointerSize));  // this
+      __ sd(scratch, MemOperand(sp, 0));              // home_object
+      // stack: this, home_object; v0: value
+      EmitNamedSuperPropertyStore(prop);
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      __ Push(v0);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForAccumulatorValue(prop->key());
+      Register scratch = a2;
+      Register scratch2 = a3;
+      __ ld(scratch2, MemOperand(sp, 2 * kPointerSize));  // value
+      // stack: value, this, home_object; v0: key, a3: value
+      __ ld(scratch, MemOperand(sp, kPointerSize));  // this
+      __ sd(scratch, MemOperand(sp, 2 * kPointerSize));
+      __ ld(scratch, MemOperand(sp, 0));  // home_object
+      __ sd(scratch, MemOperand(sp, kPointerSize));
+      __ sd(v0, MemOperand(sp, 0));
+      __ Move(v0, scratch2);
+      // stack: this, home_object, key; v0: value.
+      EmitKeyedSuperPropertyStore(prop);
+      break;
+    }
     case KEYED_PROPERTY: {
       __ push(result_register());  // Preserve value.
       VisitForStackValue(prop->obj());
@@ -2547,7 +2638,6 @@
     // Perform the assignment.
     __ bind(&assign);
     EmitStoreToStackLocalOrContextSlot(var, location);
-
   } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
     if (var->IsLookupSlot()) {
       // Assignment to var.
@@ -2572,8 +2662,9 @@
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
+  } else if (IsSignallingAssignmentToConst(var, op, strict_mode())) {
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
   }
-  // Non-initializing assignments to consts are ignored.
 }
 
 
@@ -2596,6 +2687,35 @@
 }
 
 
+void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // v0 : value
+  // stack : receiver ('this'), home_object
+  DCHECK(prop != NULL);
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(key != NULL);
+
+  __ Push(key->value());
+  __ Push(v0);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
+                                          : Runtime::kStoreToSuper_Sloppy),
+                 4);
+}
+
+
+void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // v0 : value
+  // stack : receiver ('this'), home_object, key
+  DCHECK(prop != NULL);
+
+  __ Push(v0);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict
+                                          : Runtime::kStoreKeyedToSuper_Sloppy),
+                 4);
+}
+
+
 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
   // Assignment to a property, using a keyed store IC.
 
@@ -2628,16 +2748,27 @@
       __ Move(LoadDescriptor::ReceiverRegister(), v0);
       EmitNamedPropertyLoad(expr);
     } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
       EmitNamedSuperPropertyLoad(expr);
     }
     PrepareForBailoutForId(expr->LoadId(), TOS_REG);
     context()->Plug(v0);
   } else {
-    VisitForStackValue(expr->obj());
-    VisitForAccumulatorValue(expr->key());
-    __ Move(LoadDescriptor::NameRegister(), v0);
-    __ pop(LoadDescriptor::ReceiverRegister());
-    EmitKeyedPropertyLoad(expr);
+    if (!expr->IsSuperAccess()) {
+      VisitForStackValue(expr->obj());
+      VisitForAccumulatorValue(expr->key());
+      __ Move(LoadDescriptor::NameRegister(), v0);
+      __ pop(LoadDescriptor::ReceiverRegister());
+      EmitKeyedPropertyLoad(expr);
+    } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForStackValue(expr->key());
+      EmitKeyedSuperPropertyLoad(expr);
+    }
     context()->Plug(v0);
   }
 }
@@ -2696,18 +2827,16 @@
   const Register scratch = a1;
   SuperReference* super_ref = prop->obj()->AsSuperReference();
   EmitLoadHomeObject(super_ref);
-  __ Push(v0);
+  __ mov(scratch, v0);
   VisitForAccumulatorValue(super_ref->this_var());
-  __ Push(v0);
-  __ ld(scratch, MemOperand(sp, kPointerSize));
-  __ Push(scratch, v0);
+  __ Push(scratch, v0, v0, scratch);
   __ Push(key->value());
 
   // Stack here:
   //  - home_object
   //  - this (receiver)
-  //  - home_object <-- LoadFromSuper will pop here and below.
-  //  - this (receiver)
+  //  - this (receiver) <-- LoadFromSuper will pop here and below.
+  //  - home_object
   //  - key
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 
@@ -2745,6 +2874,40 @@
 }
 
 
+void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
+  Expression* callee = expr->expression();
+  DCHECK(callee->IsProperty());
+  Property* prop = callee->AsProperty();
+  DCHECK(prop->IsSuperAccess());
+
+  SetSourcePosition(prop->position());
+  // Load the function from the receiver.
+  const Register scratch = a1;
+  SuperReference* super_ref = prop->obj()->AsSuperReference();
+  EmitLoadHomeObject(super_ref);
+  __ Move(scratch, v0);
+  VisitForAccumulatorValue(super_ref->this_var());
+  __ Push(scratch, v0, v0, scratch);
+  VisitForStackValue(prop->key());
+
+  // Stack here:
+  //  - home_object
+  //  - this (receiver)
+  //  - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
+  //  - home_object
+  //  - key
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+
+  // Replace home_object with target function.
+  __ sd(v0, MemOperand(sp, kPointerSize));
+
+  // Stack here:
+  // - target function
+  // - this (receiver)
+  EmitCall(expr, CallICState::METHOD);
+}
+
+
 void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
   // Load the arguments.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2759,7 +2922,7 @@
   SetSourcePosition(expr->position());
   Handle<Code> ic = CallIC::initialize_stub(
       isolate(), arg_count, call_type);
-  __ li(a3, Operand(Smi::FromInt(expr->CallFeedbackSlot())));
+  __ li(a3, Operand(SmiFromSlot(expr->CallFeedbackSlot())));
   __ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
   // Don't assign a type feedback id to the IC, since type feedback is provided
   // by the vector above.
@@ -2799,6 +2962,14 @@
 }
 
 
+void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
+  DCHECK(super_ref != NULL);
+  __ ld(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ Push(a0);
+  __ CallRuntime(Runtime::kGetPrototype, 1);
+}
+
+
 void FullCodeGenerator::VisitCall(Call* expr) {
 #ifdef DEBUG
   // We want to verify that RecordJSReturnSite gets called on all paths
@@ -2838,6 +3009,8 @@
       // v1 (receiver). Touch up the stack with the right values.
       __ sd(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
       __ sd(v1, MemOperand(sp, arg_count * kPointerSize));
+
+      PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
     }
     // Record source position for debugger.
     SetSourcePosition(expr->position());
@@ -2869,6 +3042,7 @@
     __ Push(context_register(), a2);
     __ CallRuntime(Runtime::kLoadLookupSlot, 2);
     __ Push(v0, v1);  // Function, receiver.
+    PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
 
     // If fast case code has been generated, emit code to push the
     // function and receiver and have the slow path jump around this
@@ -2892,9 +3066,12 @@
   } else if (call_type == Call::PROPERTY_CALL) {
     Property* property = callee->AsProperty();
     bool is_named_call = property->key()->IsPropertyName();
-    // super.x() is handled in EmitCallWithLoadIC.
-    if (property->IsSuperAccess() && is_named_call) {
-      EmitSuperCallWithLoadIC(expr);
+    if (property->IsSuperAccess()) {
+      if (is_named_call) {
+        EmitSuperCallWithLoadIC(expr);
+      } else {
+        EmitKeyedSuperCallWithLoadIC(expr);
+      }
     } else {
       {
         PreservePositionScope scope(masm()->positions_recorder());
@@ -2906,6 +3083,12 @@
         EmitKeyedCallWithLoadIC(expr, property->key());
       }
     }
+  } else if (call_type == Call::SUPER_CALL) {
+    SuperReference* super_ref = callee->AsSuperReference();
+    EmitLoadSuperConstructor(super_ref);
+    __ Push(result_register());
+    VisitForStackValue(super_ref->this_var());
+    EmitCall(expr, CallICState::METHOD);
   } else {
     DCHECK(call_type == Call::OTHER_CALL);
     // Call to an arbitrary expression not handled specially above.
@@ -2934,7 +3117,12 @@
   // Push constructor on the stack.  If it's not a function it's used as
   // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
   // ignored.
-  VisitForStackValue(expr->expression());
+  if (expr->expression()->IsSuperReference()) {
+    EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
+    __ Push(result_register());
+  } else {
+    VisitForStackValue(expr->expression());
+  }
 
   // Push the arguments ("left-to-right") on the stack.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2953,12 +3141,12 @@
   // Record call targets in unoptimized code.
   if (FLAG_pretenuring_call_new) {
     EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
-    DCHECK(expr->AllocationSiteFeedbackSlot() ==
-           expr->CallNewFeedbackSlot() + 1);
+    DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
+           expr->CallNewFeedbackSlot().ToInt() + 1);
   }
 
   __ li(a2, FeedbackVector());
-  __ li(a3, Operand(Smi::FromInt(expr->CallNewFeedbackSlot())));
+  __ li(a3, Operand(SmiFromSlot(expr->CallNewFeedbackSlot())));
 
   CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
@@ -3274,6 +3462,32 @@
 }
 
 
+void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ JumpIfSmi(v0, if_false);
+  Register map = a1;
+  Register type_reg = a2;
+  __ GetObjectType(v0, map, type_reg);
+  __ Subu(type_reg, type_reg, Operand(FIRST_JS_PROXY_TYPE));
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(ls, type_reg, Operand(LAST_JS_PROXY_TYPE - FIRST_JS_PROXY_TYPE),
+        if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
 void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
   DCHECK(expr->arguments()->length() == 0);
 
@@ -4192,7 +4406,7 @@
     __ li(LoadDescriptor::NameRegister(), Operand(expr->name()));
     if (FLAG_vector_ics) {
       __ li(VectorLoadICDescriptor::SlotRegister(),
-            Operand(Smi::FromInt(expr->CallRuntimeFeedbackSlot())));
+            Operand(SmiFromSlot(expr->CallRuntimeFeedbackSlot())));
       CallLoadIC(NOT_CONTEXTUAL);
     } else {
       CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
@@ -4348,17 +4562,8 @@
   Comment cmnt(masm_, "[ CountOperation");
   SetSourcePosition(expr->position());
 
-  // Expression can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* prop = expr->expression()->AsProperty();
-  // In case of a property we use the uninitialized expression context
-  // of the key to detect a named property.
-  if (prop != NULL) {
-    assign_type =
-        (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(prop);
 
   // Evaluate expression and get value.
   if (assign_type == VARIABLE) {
@@ -4371,18 +4576,52 @@
       __ li(at, Operand(Smi::FromInt(0)));
       __ push(at);
     }
-    if (assign_type == NAMED_PROPERTY) {
-      // Put the object both on the stack and in the register.
-      VisitForStackValue(prop->obj());
-      __ ld(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
-      EmitNamedPropertyLoad(prop);
-    } else {
-      VisitForStackValue(prop->obj());
-      VisitForStackValue(prop->key());
-      __ ld(LoadDescriptor::ReceiverRegister(),
-            MemOperand(sp, 1 * kPointerSize));
-      __ ld(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
-      EmitKeyedPropertyLoad(prop);
+    switch (assign_type) {
+      case NAMED_PROPERTY: {
+        // Put the object both on the stack and in the register.
+        VisitForStackValue(prop->obj());
+        __ ld(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
+        EmitNamedPropertyLoad(prop);
+        break;
+      }
+
+      case NAMED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        __ Push(result_register());
+        const Register scratch = a1;
+        __ ld(scratch, MemOperand(sp, kPointerSize));
+        __ Push(scratch, result_register());
+        EmitNamedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        const Register scratch = a1;
+        const Register scratch1 = a4;
+        __ Move(scratch, result_register());
+        VisitForAccumulatorValue(prop->key());
+        __ Push(scratch, result_register());
+        __ ld(scratch1, MemOperand(sp, 2 * kPointerSize));
+        __ Push(scratch1, scratch, result_register());
+        EmitKeyedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_PROPERTY: {
+        VisitForStackValue(prop->obj());
+        VisitForStackValue(prop->key());
+        __ ld(LoadDescriptor::ReceiverRegister(),
+              MemOperand(sp, 1 * kPointerSize));
+        __ ld(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
+        EmitKeyedPropertyLoad(prop);
+        break;
+      }
+
+      case VARIABLE:
+        UNREACHABLE();
     }
   }
 
@@ -4417,9 +4656,15 @@
           case NAMED_PROPERTY:
             __ sd(v0, MemOperand(sp, kPointerSize));
             break;
+          case NAMED_SUPER_PROPERTY:
+            __ sd(v0, MemOperand(sp, 2 * kPointerSize));
+            break;
           case KEYED_PROPERTY:
             __ sd(v0, MemOperand(sp, 2 * kPointerSize));
             break;
+          case KEYED_SUPER_PROPERTY:
+            __ sd(v0, MemOperand(sp, 3 * kPointerSize));
+            break;
         }
       }
     }
@@ -4450,9 +4695,15 @@
         case NAMED_PROPERTY:
           __ sd(v0, MemOperand(sp, kPointerSize));
           break;
+        case NAMED_SUPER_PROPERTY:
+          __ sd(v0, MemOperand(sp, 2 * kPointerSize));
+          break;
         case KEYED_PROPERTY:
           __ sd(v0, MemOperand(sp, 2 * kPointerSize));
           break;
+        case KEYED_SUPER_PROPERTY:
+          __ sd(v0, MemOperand(sp, 3 * kPointerSize));
+          break;
       }
     }
   }
@@ -4508,6 +4759,28 @@
       }
       break;
     }
+    case NAMED_SUPER_PROPERTY: {
+      EmitNamedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(v0);
+      }
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      EmitKeyedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(v0);
+      }
+      break;
+    }
     case KEYED_PROPERTY: {
       __ mov(StoreDescriptor::ValueRegister(), result_register());
       __ Pop(StoreDescriptor::ReceiverRegister(),
@@ -4539,7 +4812,7 @@
     __ li(LoadDescriptor::NameRegister(), Operand(proxy->name()));
     if (FLAG_vector_ics) {
       __ li(VectorLoadICDescriptor::SlotRegister(),
-            Operand(Smi::FromInt(proxy->VariableFeedbackSlot())));
+            Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
     }
     // Use a regular load, not a contextual load, to avoid a reference
     // error.
@@ -4771,7 +5044,7 @@
 
 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
   Scope* declaration_scope = scope()->DeclarationScope();
-  if (declaration_scope->is_global_scope() ||
+  if (declaration_scope->is_script_scope() ||
       declaration_scope->is_module_scope()) {
     // Contexts nested in the native context have a canonical empty function
     // as their closure, not the anonymous closure containing the global
diff --git a/src/mips64/interface-descriptors-mips64.cc b/src/mips64/interface-descriptors-mips64.cc
index 8759bdd..44c8dff 100644
--- a/src/mips64/interface-descriptors-mips64.cc
+++ b/src/mips64/interface-descriptors-mips64.cc
@@ -29,6 +29,9 @@
 const Register StoreDescriptor::ValueRegister() { return a0; }
 
 
+const Register StoreTransitionDescriptor::MapRegister() { return a3; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() { return a3; }
 
 
@@ -149,6 +152,15 @@
 }
 
 
+void AllocateHeapNumberDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // register state
+  // cp -- context
+  Register registers[] = {cp};
+  data->Initialize(arraysize(registers), registers, nullptr);
+}
+
+
 void ArrayConstructorConstantArgCountDescriptor::Initialize(
     CallInterfaceDescriptorData* data) {
   // register state
diff --git a/src/mips64/lithium-codegen-mips64.cc b/src/mips64/lithium-codegen-mips64.cc
index 8a0a449..a817a28 100644
--- a/src/mips64/lithium-codegen-mips64.cc
+++ b/src/mips64/lithium-codegen-mips64.cc
@@ -26,9 +26,9 @@
         deopt_mode_(mode) { }
   virtual ~SafepointGenerator() {}
 
-  virtual void BeforeCall(int call_size) const OVERRIDE {}
+  void BeforeCall(int call_size) const OVERRIDE {}
 
-  virtual void AfterCall() const OVERRIDE {
+  void AfterCall() const OVERRIDE {
     codegen_->RecordSafepoint(pointers_, deopt_mode_);
   }
 
@@ -766,8 +766,8 @@
 
 void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
                             Deoptimizer::BailoutType bailout_type,
-                            Register src1, const Operand& src2,
-                            const char* detail) {
+                            const char* detail, Register src1,
+                            const Operand& src2) {
   LEnvironment* environment = instr->environment();
   RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
   DCHECK(environment->HasBeenRegistered());
@@ -832,12 +832,12 @@
 
 
 void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
-                            Register src1, const Operand& src2,
-                            const char* detail) {
+                            const char* detail, Register src1,
+                            const Operand& src2) {
   Deoptimizer::BailoutType bailout_type = info()->IsStub()
       ? Deoptimizer::LAZY
       : Deoptimizer::EAGER;
-  DeoptimizeIf(condition, instr, bailout_type, src1, src2, detail);
+  DeoptimizeIf(condition, instr, bailout_type, detail, src1, src2);
 }
 
 
@@ -1067,7 +1067,7 @@
     __ dsubu(dividend, zero_reg, dividend);
     __ And(dividend, dividend, Operand(mask));
     if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
-      DeoptimizeIf(eq, instr, dividend, Operand(zero_reg));
+      DeoptimizeIf(eq, instr, "minus zero", dividend, Operand(zero_reg));
     }
     __ Branch(USE_DELAY_SLOT, &done);
     __ dsubu(dividend, zero_reg, dividend);
@@ -1086,7 +1086,7 @@
   DCHECK(!dividend.is(result));
 
   if (divisor == 0) {
-    DeoptimizeIf(al, instr);
+    DeoptimizeIf(al, instr, "division by zero");
     return;
   }
 
@@ -1099,7 +1099,7 @@
   if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
     Label remainder_not_zero;
     __ Branch(&remainder_not_zero, ne, result, Operand(zero_reg));
-    DeoptimizeIf(lt, instr, dividend, Operand(zero_reg));
+    DeoptimizeIf(lt, instr, "minus zero", dividend, Operand(zero_reg));
     __ bind(&remainder_not_zero);
   }
 }
@@ -1118,7 +1118,7 @@
   // Check for x % 0, we have to deopt in this case because we can't return a
   // NaN.
   if (hmod->CheckFlag(HValue::kCanBeDivByZero)) {
-    DeoptimizeIf(eq, instr, right_reg, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "division by zero", right_reg, Operand(zero_reg));
   }
 
   // Check for kMinInt % -1, div will return kMinInt, which is not what we
@@ -1127,7 +1127,7 @@
     Label no_overflow_possible;
     __ Branch(&no_overflow_possible, ne, left_reg, Operand(kMinInt));
     if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
-      DeoptimizeIf(eq, instr, right_reg, Operand(-1));
+      DeoptimizeIf(eq, instr, "minus zero", right_reg, Operand(-1));
     } else {
       __ Branch(&no_overflow_possible, ne, right_reg, Operand(-1));
       __ Branch(USE_DELAY_SLOT, &done);
@@ -1140,7 +1140,7 @@
   __ Branch(&done, ge, left_reg, Operand(zero_reg));
 
   if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
-    DeoptimizeIf(eq, instr, result_reg, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "minus zero", result_reg, Operand(zero_reg));
   }
   __ bind(&done);
 }
@@ -1156,18 +1156,18 @@
   // Check for (0 / -x) that will produce negative zero.
   HDiv* hdiv = instr->hydrogen();
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
-    DeoptimizeIf(eq, instr, dividend, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "minus zero", dividend, Operand(zero_reg));
   }
   // Check for (kMinInt / -1).
   if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) {
-    DeoptimizeIf(eq, instr, dividend, Operand(kMinInt));
+    DeoptimizeIf(eq, instr, "overflow", dividend, Operand(kMinInt));
   }
   // Deoptimize if remainder will not be 0.
   if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
       divisor != 1 && divisor != -1) {
     int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
     __ And(at, dividend, Operand(mask));
-    DeoptimizeIf(ne, instr, at, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "lost precision", at, Operand(zero_reg));
   }
 
   if (divisor == -1) {  // Nice shortcut, not needed for correctness.
@@ -1197,14 +1197,14 @@
   DCHECK(!dividend.is(result));
 
   if (divisor == 0) {
-    DeoptimizeIf(al, instr);
+    DeoptimizeIf(al, instr, "division by zero");
     return;
   }
 
   // Check for (0 / -x) that will produce negative zero.
   HDiv* hdiv = instr->hydrogen();
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
-    DeoptimizeIf(eq, instr, dividend, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "minus zero", dividend, Operand(zero_reg));
   }
 
   __ TruncatingDiv(result, dividend, Abs(divisor));
@@ -1213,7 +1213,7 @@
   if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
     __ Dmul(scratch0(), result, Operand(divisor));
     __ Dsubu(scratch0(), scratch0(), dividend);
-    DeoptimizeIf(ne, instr, scratch0(), Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "lost precision", scratch0(), Operand(zero_reg));
   }
 }
 
@@ -1231,14 +1231,14 @@
 
   // Check for x / 0.
   if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
-    DeoptimizeIf(eq, instr, divisor, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "division by zero", divisor, Operand(zero_reg));
   }
 
   // Check for (0 / -x) that will produce negative zero.
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
     Label left_not_zero;
     __ Branch(&left_not_zero, ne, dividend, Operand(zero_reg));
-    DeoptimizeIf(lt, instr, divisor, Operand(zero_reg));
+    DeoptimizeIf(lt, instr, "minus zero", divisor, Operand(zero_reg));
     __ bind(&left_not_zero);
   }
 
@@ -1247,7 +1247,7 @@
       !hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
     Label left_not_min_int;
     __ Branch(&left_not_min_int, ne, dividend, Operand(kMinInt));
-    DeoptimizeIf(eq, instr, divisor, Operand(-1));
+    DeoptimizeIf(eq, instr, "overflow", divisor, Operand(-1));
     __ bind(&left_not_min_int);
   }
 
@@ -1259,7 +1259,7 @@
     } else {
       __ dmod(remainder, dividend, divisor);
     }
-    DeoptimizeIf(ne, instr, remainder, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "lost precision", remainder, Operand(zero_reg));
   }
 }
 
@@ -1304,14 +1304,14 @@
 
   __ Dsubu(result, zero_reg, dividend);
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-    DeoptimizeIf(eq, instr, result, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "minus zero", result, Operand(zero_reg));
   }
 
   __ Xor(scratch, scratch, result);
   // Dividing by -1 is basically negation, unless we overflow.
   if (divisor == -1) {
     if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
-      DeoptimizeIf(gt, instr, result, Operand(kMaxInt));
+      DeoptimizeIf(gt, instr, "overflow", result, Operand(kMaxInt));
     }
     return;
   }
@@ -1339,14 +1339,14 @@
   DCHECK(!dividend.is(result));
 
   if (divisor == 0) {
-    DeoptimizeIf(al, instr);
+    DeoptimizeIf(al, instr, "division by zero");
     return;
   }
 
   // Check for (0 / -x) that will produce negative zero.
   HMathFloorOfDiv* hdiv = instr->hydrogen();
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
-    DeoptimizeIf(eq, instr, dividend, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "minus zero", dividend, Operand(zero_reg));
   }
 
   // Easy case: We need no dynamic check for the dividend and the flooring
@@ -1390,14 +1390,14 @@
 
   // Check for x / 0.
   if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
-    DeoptimizeIf(eq, instr, divisor, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "division by zero", divisor, Operand(zero_reg));
   }
 
   // Check for (0 / -x) that will produce negative zero.
   if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
     Label left_not_zero;
     __ Branch(&left_not_zero, ne, dividend, Operand(zero_reg));
-    DeoptimizeIf(lt, instr, divisor, Operand(zero_reg));
+    DeoptimizeIf(lt, instr, "minus zero", divisor, Operand(zero_reg));
     __ bind(&left_not_zero);
   }
 
@@ -1406,7 +1406,7 @@
       !hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
     Label left_not_min_int;
     __ Branch(&left_not_min_int, ne, dividend, Operand(kMinInt));
-    DeoptimizeIf(eq, instr, divisor, Operand(-1));
+    DeoptimizeIf(eq, instr, "overflow", divisor, Operand(-1));
     __ bind(&left_not_min_int);
   }
 
@@ -1443,14 +1443,14 @@
     if (bailout_on_minus_zero && (constant < 0)) {
       // The case of a null constant will be handled separately.
       // If constant is negative and left is null, the result should be -0.
-      DeoptimizeIf(eq, instr, left, Operand(zero_reg));
+      DeoptimizeIf(eq, instr, "minus zero", left, Operand(zero_reg));
     }
 
     switch (constant) {
       case -1:
         if (overflow) {
           __ SubuAndCheckForOverflow(result, zero_reg, left, scratch);
-          DeoptimizeIf(gt, instr, scratch, Operand(kMaxInt));
+          DeoptimizeIf(gt, instr, "overflow", scratch, Operand(kMaxInt));
         } else {
           __ Dsubu(result, zero_reg, left);
         }
@@ -1459,7 +1459,7 @@
         if (bailout_on_minus_zero) {
           // If left is strictly negative and the constant is null, the
           // result is -0. Deoptimize if required, otherwise return 0.
-          DeoptimizeIf(lt, instr, left, Operand(zero_reg));
+          DeoptimizeIf(lt, instr, "minus zero", left, Operand(zero_reg));
         }
         __ mov(result, zero_reg);
         break;
@@ -1514,7 +1514,7 @@
       if (instr->hydrogen()->representation().IsSmi()) {
         __ SmiTag(result);
       }
-      DeoptimizeIf(ne, instr, scratch, Operand(at));
+      DeoptimizeIf(ne, instr, "overflow", scratch, Operand(at));
     } else {
       if (instr->hydrogen()->representation().IsSmi()) {
         __ SmiUntag(result, left);
@@ -1529,7 +1529,7 @@
       __ Xor(at, left, right);
       __ Branch(&done, ge, at, Operand(zero_reg));
       // Bail out if the result is minus zero.
-      DeoptimizeIf(eq, instr, result, Operand(zero_reg));
+      DeoptimizeIf(eq, instr, "minus zero", result, Operand(zero_reg));
       __ bind(&done);
     }
   }
@@ -1593,8 +1593,8 @@
         __ srlv(result, left, ToRegister(right_op));
         if (instr->can_deopt()) {
            // TODO(yy): (-1) >>> 0. anything else?
-          DeoptimizeIf(lt, instr, result, Operand(zero_reg));
-          DeoptimizeIf(gt, instr, result, Operand(kMaxInt));
+          DeoptimizeIf(lt, instr, "negative value", result, Operand(zero_reg));
+          DeoptimizeIf(gt, instr, "negative value", result, Operand(kMaxInt));
         }
         break;
       case Token::SHL:
@@ -1629,7 +1629,7 @@
         } else {
           if (instr->can_deopt()) {
             __ And(at, left, Operand(0x80000000));
-            DeoptimizeIf(ne, instr, at, Operand(zero_reg));
+            DeoptimizeIf(ne, instr, "negative value", at, Operand(zero_reg));
           }
           __ Move(result, left);
         }
@@ -1685,10 +1685,10 @@
                                  ToRegister(right),
                                  overflow);  // Reg at also used as scratch.
     }
-    DeoptimizeIf(lt, instr, overflow, Operand(zero_reg));
+    DeoptimizeIf(lt, instr, "overflow", overflow, Operand(zero_reg));
     if (!instr->hydrogen()->representation().IsSmi()) {
-      DeoptimizeIf(gt, instr, ToRegister(result), Operand(kMaxInt));
-      DeoptimizeIf(lt, instr, ToRegister(result), Operand(kMinInt));
+      DeoptimizeIf(gt, instr, "overflow", ToRegister(result), Operand(kMaxInt));
+      DeoptimizeIf(lt, instr, "overflow", ToRegister(result), Operand(kMinInt));
     }
   }
 }
@@ -1743,9 +1743,9 @@
   DCHECK(!scratch.is(object));
 
   __ SmiTst(object, at);
-  DeoptimizeIf(eq, instr, at, Operand(zero_reg));
+  DeoptimizeIf(eq, instr, "Smi", at, Operand(zero_reg));
   __ GetObjectType(object, scratch, scratch);
-  DeoptimizeIf(ne, instr, scratch, Operand(JS_DATE_TYPE));
+  DeoptimizeIf(ne, instr, "not a date object", scratch, Operand(JS_DATE_TYPE));
 
   if (index->value() == 0) {
     __ ld(result, FieldMemOperand(object, JSDate::kValueOffset));
@@ -1880,11 +1880,11 @@
                                  ToRegister(right),
                                  overflow);  // Reg at also used as scratch.
     }
-    DeoptimizeIf(lt, instr, overflow, Operand(zero_reg));
+    DeoptimizeIf(lt, instr, "overflow", overflow, Operand(zero_reg));
     // if not smi, it must int32.
     if (!instr->hydrogen()->representation().IsSmi()) {
-      DeoptimizeIf(gt, instr, ToRegister(result), Operand(kMaxInt));
-      DeoptimizeIf(lt, instr, ToRegister(result), Operand(kMinInt));
+      DeoptimizeIf(gt, instr, "overflow", ToRegister(result), Operand(kMaxInt));
+      DeoptimizeIf(lt, instr, "overflow", ToRegister(result), Operand(kMinInt));
     }
   }
 }
@@ -2146,7 +2146,7 @@
       } else if (expected.NeedsMap()) {
         // If we need a map later and have a Smi -> deopt.
         __ SmiTst(reg, at);
-        DeoptimizeIf(eq, instr, at, Operand(zero_reg));
+        DeoptimizeIf(eq, instr, "Smi", at, Operand(zero_reg));
       }
 
       const Register map = scratch0();
@@ -2202,7 +2202,8 @@
       if (!expected.IsGeneric()) {
         // We've seen something for the first time -> deopt.
         // This can only happen if we are not generic already.
-        DeoptimizeIf(al, instr, zero_reg, Operand(zero_reg));
+        DeoptimizeIf(al, instr, "unexpected object", zero_reg,
+                     Operand(zero_reg));
       }
     }
   }
@@ -2664,10 +2665,10 @@
     DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
                                   LInstanceOfKnownGlobal* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
     Label* map_check() { return &map_check_; }
 
    private:
@@ -2827,6 +2828,7 @@
       __ Daddu(sp, sp, Operand(sp_delta));
     }
   } else {
+    DCHECK(info()->IsStub());  // Functions would need to drop one more value.
     Register reg = ToRegister(instr->parameter_count());
     // The argument count parameter is a smi
     __ SmiUntag(reg);
@@ -2848,7 +2850,7 @@
   __ ld(result, FieldMemOperand(at, Cell::kValueOffset));
   if (instr->hydrogen()->RequiresHoleCheck()) {
     __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(eq, instr, result, Operand(at));
+    DeoptimizeIf(eq, instr, "hole", result, Operand(at));
   }
 }
 
@@ -2856,13 +2858,18 @@
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
-  Register vector = ToRegister(instr->temp_vector());
-  DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
-  __ li(vector, instr->hydrogen()->feedback_vector());
+  Register vector_register = ToRegister(instr->temp_vector());
+  Register slot_register = VectorLoadICDescriptor::SlotRegister();
+  DCHECK(vector_register.is(VectorLoadICDescriptor::VectorRegister()));
+  DCHECK(slot_register.is(a0));
+
+  AllowDeferredHandleDereference vector_structure_check;
+  Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+  __ li(vector_register, vector);
   // No need to allocate this register.
-  DCHECK(VectorLoadICDescriptor::SlotRegister().is(a0));
-  __ li(VectorLoadICDescriptor::SlotRegister(),
-        Operand(Smi::FromInt(instr->hydrogen()->slot())));
+  FeedbackVectorICSlot slot = instr->hydrogen()->slot();
+  int index = vector->GetIndex(slot);
+  __ li(slot_register, Operand(Smi::FromInt(index)));
 }
 
 
@@ -2877,7 +2884,7 @@
     EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
   }
   ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), mode).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -2898,7 +2905,7 @@
     Register payload = ToRegister(instr->temp());
     __ ld(payload, FieldMemOperand(cell, Cell::kValueOffset));
     __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(eq, instr, payload, Operand(at));
+    DeoptimizeIf(eq, instr, "hole", payload, Operand(at));
   }
 
   // Store the value.
@@ -2916,7 +2923,7 @@
     __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
 
     if (instr->hydrogen()->DeoptimizesOnHole()) {
-      DeoptimizeIf(eq, instr, result, Operand(at));
+      DeoptimizeIf(eq, instr, "hole", result, Operand(at));
     } else {
       Label is_not_hole;
       __ Branch(&is_not_hole, ne, result, Operand(at));
@@ -2940,7 +2947,7 @@
     __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
 
     if (instr->hydrogen()->DeoptimizesOnHole()) {
-      DeoptimizeIf(eq, instr, scratch, Operand(at));
+      DeoptimizeIf(eq, instr, "hole", scratch, Operand(at));
     } else {
       __ Branch(&skip_assignment, ne, scratch, Operand(at));
     }
@@ -3018,7 +3025,8 @@
   if (FLAG_vector_ics) {
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic =
+      CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3034,7 +3042,7 @@
 
   // Check that the function has a prototype or an initial map.
   __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-  DeoptimizeIf(eq, instr, result, Operand(at));
+  DeoptimizeIf(eq, instr, "hole", result, Operand(at));
 
   // If the function does not have an initial map, we're done.
   Label done;
@@ -3180,7 +3188,8 @@
       case UINT32_ELEMENTS:
         __ lw(result, mem_operand);
         if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
-          DeoptimizeIf(Ugreater_equal, instr, result, Operand(0x80000000));
+          DeoptimizeIf(Ugreater_equal, instr, "negative value", result,
+                       Operand(0x80000000));
         }
         break;
       case FLOAT32_ELEMENTS:
@@ -3240,7 +3249,7 @@
 
   if (instr->hydrogen()->RequiresHoleCheck()) {
     __ lw(scratch, MemOperand(scratch, sizeof(kHoleNanLower32)));
-    DeoptimizeIf(eq, instr, scratch, Operand(kHoleNanUpper32));
+    DeoptimizeIf(eq, instr, "hole", scratch, Operand(kHoleNanUpper32));
   }
 }
 
@@ -3294,10 +3303,10 @@
   if (hinstr->RequiresHoleCheck()) {
     if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
       __ SmiTst(result, scratch);
-      DeoptimizeIf(ne, instr, scratch, Operand(zero_reg));
+      DeoptimizeIf(ne, instr, "not a Smi", scratch, Operand(zero_reg));
     } else {
       __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
-      DeoptimizeIf(eq, instr, result, Operand(scratch));
+      DeoptimizeIf(eq, instr, "hole", result, Operand(scratch));
     }
   }
 }
@@ -3366,7 +3375,7 @@
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
+  Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3453,10 +3462,11 @@
 
   // Deoptimize if the receiver is not a JS object.
   __ SmiTst(receiver, scratch);
-  DeoptimizeIf(eq, instr, scratch, Operand(zero_reg));
+  DeoptimizeIf(eq, instr, "Smi", scratch, Operand(zero_reg));
 
   __ GetObjectType(receiver, scratch, scratch);
-  DeoptimizeIf(lt, instr, scratch, Operand(FIRST_SPEC_OBJECT_TYPE));
+  DeoptimizeIf(lt, instr, "not a JavaScript object", scratch,
+               Operand(FIRST_SPEC_OBJECT_TYPE));
   __ Branch(&result_in_receiver);
 
   __ bind(&global_object);
@@ -3491,7 +3501,8 @@
   // Copy the arguments to this function possibly from the
   // adaptor frame below it.
   const uint32_t kArgumentsLimit = 1 * KB;
-  DeoptimizeIf(hi, instr, length, Operand(kArgumentsLimit));
+  DeoptimizeIf(hi, instr, "too many arguments", length,
+               Operand(kArgumentsLimit));
 
   // Push the receiver and use the register to keep the original
   // number of arguments.
@@ -3621,7 +3632,7 @@
   // Deoptimize if not a heap number.
   __ ld(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
   __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
-  DeoptimizeIf(ne, instr, scratch, Operand(at));
+  DeoptimizeIf(ne, instr, "not a heap number", scratch, Operand(at));
 
   Label done;
   Register exponent = scratch0();
@@ -3688,7 +3699,7 @@
   __ mov(result, input);
   __ dsubu(result, zero_reg, input);
   // Overflow if result is still negative, i.e. 0x80000000.
-  DeoptimizeIf(lt, instr, result, Operand(zero_reg));
+  DeoptimizeIf(lt, instr, "overflow", result, Operand(zero_reg));
   __ bind(&done);
 }
 
@@ -3699,10 +3710,11 @@
    public:
     DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LMathAbs* instr_;
   };
@@ -3742,7 +3754,8 @@
                      except_flag);
 
   // Deopt if the operation did not succeed.
-  DeoptimizeIf(ne, instr, except_flag, Operand(zero_reg));
+  DeoptimizeIf(ne, instr, "lost precision or NaN", except_flag,
+               Operand(zero_reg));
 
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     // Test for -0.
@@ -3750,7 +3763,7 @@
     __ Branch(&done, ne, result, Operand(zero_reg));
     __ mfhc1(scratch1, input);  // Get exponent/sign bits.
     __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
-    DeoptimizeIf(ne, instr, scratch1, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "minus zero", scratch1, Operand(zero_reg));
     __ bind(&done);
   }
 }
@@ -3783,7 +3796,8 @@
 
   // The following conversion will not work with numbers
   // outside of ]-2^32, 2^32[.
-  DeoptimizeIf(ge, instr, scratch, Operand(HeapNumber::kExponentBias + 32));
+  DeoptimizeIf(ge, instr, "overflow", scratch,
+               Operand(HeapNumber::kExponentBias + 32));
 
   // Save the original sign for later comparison.
   __ And(scratch, result, Operand(HeapNumber::kSignMask));
@@ -3800,7 +3814,7 @@
   __ Xor(result, result, Operand(scratch));
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     // ARM uses 'mi' here, which is 'lt'
-    DeoptimizeIf(lt, instr, result, Operand(zero_reg));
+    DeoptimizeIf(lt, instr, "minus zero", result, Operand(zero_reg));
   } else {
     Label skip2;
     // ARM uses 'mi' here, which is 'lt'
@@ -3819,7 +3833,8 @@
                      double_scratch1,
                      except_flag);
 
-  DeoptimizeIf(ne, instr, except_flag, Operand(zero_reg));
+  DeoptimizeIf(ne, instr, "lost precision or NaN", except_flag,
+               Operand(zero_reg));
 
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     // Test for -0.
@@ -3827,7 +3842,7 @@
     __ bind(&check_sign_on_zero);
     __ mfhc1(scratch, input);  // Get exponent/sign bits.
     __ And(scratch, scratch, Operand(HeapNumber::kSignMask));
-    DeoptimizeIf(ne, instr, scratch, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "minus zero", scratch, Operand(zero_reg));
   }
   __ bind(&done);
 }
@@ -3859,7 +3874,7 @@
   // Math.pow(-Infinity, 0.5) == Infinity
   // Math.sqrt(-Infinity) == NaN
   Label done;
-  __ Move(temp, -V8_INFINITY);
+  __ Move(temp, static_cast<double>(-V8_INFINITY));
   __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, temp, input);
   // Set up Infinity in the delay slot.
   // result is overwritten if the branch is not taken.
@@ -3893,7 +3908,7 @@
     DCHECK(!a7.is(tagged_exponent));
     __ lw(a7, FieldMemOperand(tagged_exponent, HeapObject::kMapOffset));
     __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
-    DeoptimizeIf(ne, instr, a7, Operand(at));
+    DeoptimizeIf(ne, instr, "not a heap number", a7, Operand(at));
     __ bind(&no_deopt);
     MathPowStub stub(isolate(), MathPowStub::TAGGED);
     __ CallStub(&stub);
@@ -3968,44 +3983,73 @@
   DCHECK(receiver.is(a1));
   DCHECK(name.is(a2));
 
-  Register scratch = a3;
-  Register extra = a4;
-  Register extra2 = a5;
-  Register extra3 = a6;
+  Register scratch = a4;
+  Register extra = a5;
+  Register extra2 = a6;
+  Register extra3 = t1;
+#ifdef DEBUG
+  Register slot = FLAG_vector_ics ? ToRegister(instr->slot()) : no_reg;
+  Register vector = FLAG_vector_ics ? ToRegister(instr->vector()) : no_reg;
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(slot, vector, scratch, extra, extra2, extra3));
+#endif
 
   // Important for the tail-call.
   bool must_teardown_frame = NeedsEagerFrame();
 
-  // The probe will tail call to a handler if found.
-  isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
-                                         must_teardown_frame, receiver, name,
-                                         scratch, extra, extra2, extra3);
+  if (!instr->hydrogen()->is_just_miss()) {
+    DCHECK(!instr->hydrogen()->is_keyed_load());
+
+    // The probe will tail call to a handler if found.
+    isolate()->stub_cache()->GenerateProbe(
+        masm(), Code::LOAD_IC, instr->hydrogen()->flags(), must_teardown_frame,
+        receiver, name, scratch, extra, extra2, extra3);
+  }
 
   // Tail call to miss if we ended up here.
   if (must_teardown_frame) __ LeaveFrame(StackFrame::INTERNAL);
-  LoadIC::GenerateMiss(masm());
+  if (instr->hydrogen()->is_keyed_load()) {
+    KeyedLoadIC::GenerateMiss(masm());
+  } else {
+    LoadIC::GenerateMiss(masm());
+  }
 }
 
 
 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
   DCHECK(ToRegister(instr->result()).is(v0));
 
-  LPointerMap* pointers = instr->pointer_map();
-  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+  if (instr->hydrogen()->IsTailCall()) {
+    if (NeedsEagerFrame()) __ LeaveFrame(StackFrame::INTERNAL);
 
-  if (instr->target()->IsConstantOperand()) {
-    LConstantOperand* target = LConstantOperand::cast(instr->target());
-    Handle<Code> code = Handle<Code>::cast(ToHandle(target));
-    generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
-    __ Call(code, RelocInfo::CODE_TARGET);
+    if (instr->target()->IsConstantOperand()) {
+      LConstantOperand* target = LConstantOperand::cast(instr->target());
+      Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+      __ Jump(code, RelocInfo::CODE_TARGET);
+    } else {
+      DCHECK(instr->target()->IsRegister());
+      Register target = ToRegister(instr->target());
+      __ Daddu(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
+      __ Jump(target);
+    }
   } else {
-    DCHECK(instr->target()->IsRegister());
-    Register target = ToRegister(instr->target());
-    generator.BeforeCall(__ CallSize(target));
-    __ Daddu(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
-    __ Call(target);
+    LPointerMap* pointers = instr->pointer_map();
+    SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+
+    if (instr->target()->IsConstantOperand()) {
+      LConstantOperand* target = LConstantOperand::cast(instr->target());
+      Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+      generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
+      __ Call(code, RelocInfo::CODE_TARGET);
+    } else {
+      DCHECK(instr->target()->IsRegister());
+      Register target = ToRegister(instr->target());
+      generator.BeforeCall(__ CallSize(target));
+      __ Daddu(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
+      __ Call(target);
+    }
+    generator.AfterCall();
   }
-  generator.AfterCall();
 }
 
 
@@ -4235,7 +4279,7 @@
     __ stop("eliminated bounds check failed");
     __ bind(&done);
   } else {
-    DeoptimizeIf(cc, instr, reg, operand);
+    DeoptimizeIf(cc, instr, "out of bounds", reg, operand);
   }
 }
 
@@ -4526,7 +4570,7 @@
   Label no_memento_found;
   __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found,
                                      ne, &no_memento_found);
-  DeoptimizeIf(al, instr);
+  DeoptimizeIf(al, instr, "memento found");
   __ bind(&no_memento_found);
 }
 
@@ -4547,10 +4591,9 @@
    public:
     DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredStringCharCodeAt(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredStringCharCodeAt(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStringCharCodeAt* instr_;
   };
@@ -4602,10 +4645,11 @@
    public:
     DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredStringCharFromCode(instr_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStringCharFromCode* instr_;
   };
@@ -4680,14 +4724,15 @@
    public:
     DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredNumberTagIU(instr_,
                                        instr_->value(),
                                        instr_->temp1(),
                                        instr_->temp2(),
                                        UNSIGNED_INT32);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagU* instr_;
   };
@@ -4770,10 +4815,9 @@
    public:
     DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredNumberTagD(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredNumberTagD(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagD* instr_;
   };
@@ -4829,12 +4873,12 @@
   if (hchange->CheckFlag(HValue::kCanOverflow) &&
       hchange->value()->CheckFlag(HValue::kUint32)) {
     __ And(at, input, Operand(0x80000000));
-    DeoptimizeIf(ne, instr, at, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "overflow", at, Operand(zero_reg));
   }
   if (hchange->CheckFlag(HValue::kCanOverflow) &&
       !hchange->value()->CheckFlag(HValue::kUint32)) {
     __ SmiTagCheckOverflow(output, input, at);
-    DeoptimizeIf(lt, instr, at, Operand(zero_reg));
+    DeoptimizeIf(lt, instr, "overflow", at, Operand(zero_reg));
   } else {
     __ SmiTag(output, input);
   }
@@ -4850,7 +4894,7 @@
     // If the input is a HeapObject, value of scratch won't be zero.
     __ And(scratch, input, Operand(kHeapObjectTag));
     __ SmiUntag(result, input);
-    DeoptimizeIf(ne, instr, scratch, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "not a Smi", scratch, Operand(zero_reg));
   } else {
     __ SmiUntag(result, input);
   }
@@ -4875,7 +4919,7 @@
     if (can_convert_undefined_to_nan) {
       __ Branch(&convert, ne, scratch, Operand(at));
     } else {
-      DeoptimizeIf(ne, instr, scratch, Operand(at));
+      DeoptimizeIf(ne, instr, "not a heap number", scratch, Operand(at));
     }
     // Load heap number.
     __ ldc1(result_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset));
@@ -4883,14 +4927,16 @@
       __ mfc1(at, result_reg);
       __ Branch(&done, ne, at, Operand(zero_reg));
       __ mfhc1(scratch, result_reg);  // Get exponent/sign bits.
-      DeoptimizeIf(eq, instr, scratch, Operand(HeapNumber::kSignMask));
+      DeoptimizeIf(eq, instr, "minus zero", scratch,
+                   Operand(HeapNumber::kSignMask));
     }
     __ Branch(&done);
     if (can_convert_undefined_to_nan) {
       __ bind(&convert);
       // Convert undefined (and hole) to NaN.
       __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
-      DeoptimizeIf(ne, instr, input_reg, Operand(at));
+      DeoptimizeIf(ne, instr, "not a heap number/undefined", input_reg,
+                   Operand(at));
       __ LoadRoot(scratch, Heap::kNanValueRootIndex);
       __ ldc1(result_reg, FieldMemOperand(scratch, HeapNumber::kValueOffset));
       __ Branch(&done);
@@ -4954,11 +5000,12 @@
 
     __ bind(&check_false);
     __ LoadRoot(at, Heap::kFalseValueRootIndex);
-    DeoptimizeIf(ne, instr, scratch2, Operand(at), "cannot truncate");
+    DeoptimizeIf(ne, instr, "not a heap number/undefined/true/false", scratch2,
+                 Operand(at));
     __ Branch(USE_DELAY_SLOT, &done);
     __ mov(input_reg, zero_reg);  // In delay slot.
   } else {
-    DeoptimizeIf(ne, instr, scratch1, Operand(at), "not a heap number");
+    DeoptimizeIf(ne, instr, "not a heap number", scratch1, Operand(at));
 
     // Load the double value.
     __ ldc1(double_scratch,
@@ -4973,15 +5020,15 @@
                        except_flag,
                        kCheckForInexactConversion);
 
-    DeoptimizeIf(ne, instr, except_flag, Operand(zero_reg),
-                 "lost precision or NaN");
+    DeoptimizeIf(ne, instr, "lost precision or NaN", except_flag,
+                 Operand(zero_reg));
 
     if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
       __ Branch(&done, ne, input_reg, Operand(zero_reg));
 
       __ mfhc1(scratch1, double_scratch);  // Get exponent/sign bits.
       __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
-      DeoptimizeIf(ne, instr, scratch1, Operand(zero_reg), "minus zero");
+      DeoptimizeIf(ne, instr, "minus zero", scratch1, Operand(zero_reg));
     }
   }
   __ bind(&done);
@@ -4993,10 +5040,9 @@
    public:
     DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredTaggedToI(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredTaggedToI(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LTaggedToI* instr_;
   };
@@ -5058,14 +5104,15 @@
                        kCheckForInexactConversion);
 
     // Deopt if the operation did not succeed (except_flag != 0).
-    DeoptimizeIf(ne, instr, except_flag, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "lost precision or NaN", except_flag,
+                 Operand(zero_reg));
 
     if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
       Label done;
       __ Branch(&done, ne, result_reg, Operand(zero_reg));
       __ mfhc1(scratch1, double_input);  // Get exponent/sign bits.
       __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
-      DeoptimizeIf(ne, instr, scratch1, Operand(zero_reg));
+      DeoptimizeIf(ne, instr, "minus zero", scratch1, Operand(zero_reg));
       __ bind(&done);
     }
   }
@@ -5091,14 +5138,15 @@
                        kCheckForInexactConversion);
 
     // Deopt if the operation did not succeed (except_flag != 0).
-    DeoptimizeIf(ne, instr, except_flag, Operand(zero_reg));
+    DeoptimizeIf(ne, instr, "lost precision or NaN", except_flag,
+                 Operand(zero_reg));
 
     if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
       Label done;
       __ Branch(&done, ne, result_reg, Operand(zero_reg));
       __ mfhc1(scratch1, double_input);  // Get exponent/sign bits.
       __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
-      DeoptimizeIf(ne, instr, scratch1, Operand(zero_reg));
+      DeoptimizeIf(ne, instr, "minus zero", scratch1, Operand(zero_reg));
       __ bind(&done);
     }
   }
@@ -5109,7 +5157,7 @@
 void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
   LOperand* input = instr->value();
   __ SmiTst(ToRegister(input), at);
-  DeoptimizeIf(ne, instr, at, Operand(zero_reg));
+  DeoptimizeIf(ne, instr, "not a Smi", at, Operand(zero_reg));
 }
 
 
@@ -5117,7 +5165,7 @@
   if (!instr->hydrogen()->value()->type().IsHeapObject()) {
     LOperand* input = instr->value();
     __ SmiTst(ToRegister(input), at);
-    DeoptimizeIf(eq, instr, at, Operand(zero_reg));
+    DeoptimizeIf(eq, instr, "Smi", at, Operand(zero_reg));
   }
 }
 
@@ -5135,12 +5183,12 @@
 
     // If there is only one type in the interval check for equality.
     if (first == last) {
-      DeoptimizeIf(ne, instr, scratch, Operand(first));
+      DeoptimizeIf(ne, instr, "wrong instance type", scratch, Operand(first));
     } else {
-      DeoptimizeIf(lo, instr, scratch, Operand(first));
+      DeoptimizeIf(lo, instr, "wrong instance type", scratch, Operand(first));
       // Omit check for the last type.
       if (last != LAST_TYPE) {
-        DeoptimizeIf(hi, instr, scratch, Operand(last));
+        DeoptimizeIf(hi, instr, "wrong instance type", scratch, Operand(last));
       }
     }
   } else {
@@ -5151,10 +5199,11 @@
     if (base::bits::IsPowerOfTwo32(mask)) {
       DCHECK(tag == 0 || base::bits::IsPowerOfTwo32(tag));
       __ And(at, scratch, mask);
-      DeoptimizeIf(tag == 0 ? ne : eq, instr, at, Operand(zero_reg));
+      DeoptimizeIf(tag == 0 ? ne : eq, instr, "wrong instance type", at,
+                   Operand(zero_reg));
     } else {
       __ And(scratch, scratch, Operand(mask));
-      DeoptimizeIf(ne, instr, scratch, Operand(tag));
+      DeoptimizeIf(ne, instr, "wrong instance type", scratch, Operand(tag));
     }
   }
 }
@@ -5169,9 +5218,9 @@
     Handle<Cell> cell = isolate()->factory()->NewCell(object);
     __ li(at, Operand(Handle<Object>(cell)));
     __ ld(at, FieldMemOperand(at, Cell::kValueOffset));
-    DeoptimizeIf(ne, instr, reg, Operand(at));
+    DeoptimizeIf(ne, instr, "value mismatch", reg, Operand(at));
   } else {
-    DeoptimizeIf(ne, instr, reg, Operand(object));
+    DeoptimizeIf(ne, instr, "value mismatch", reg, Operand(object));
   }
 }
 
@@ -5187,7 +5236,7 @@
     __ StoreToSafepointRegisterSlot(v0, scratch0());
   }
   __ SmiTst(scratch0(), at);
-  DeoptimizeIf(eq, instr, at, Operand(zero_reg));
+  DeoptimizeIf(eq, instr, "instance migration failed", at, Operand(zero_reg));
 }
 
 
@@ -5198,11 +5247,12 @@
         : LDeferredCode(codegen), instr_(instr), object_(object) {
       SetExit(check_maps());
     }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredInstanceMigration(instr_, object_);
     }
     Label* check_maps() { return &check_maps_; }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LCheckMaps* instr_;
     Label check_maps_;
@@ -5240,7 +5290,7 @@
   if (instr->hydrogen()->HasMigrationTarget()) {
     __ Branch(deferred->entry(), ne, map_reg, Operand(map));
   } else {
-    DeoptimizeIf(ne, instr, map_reg, Operand(map));
+    DeoptimizeIf(ne, instr, "wrong map", map_reg, Operand(map));
   }
 
   __ bind(&success);
@@ -5278,7 +5328,8 @@
 
   // Check for undefined. Undefined is converted to zero for clamping
   // conversions.
-  DeoptimizeIf(ne, instr, input_reg, Operand(factory()->undefined_value()));
+  DeoptimizeIf(ne, instr, "not a heap number/undefined", input_reg,
+               Operand(factory()->undefined_value()));
   __ mov(result_reg, zero_reg);
   __ jmp(&done);
 
@@ -5320,10 +5371,9 @@
    public:
     DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredAllocate(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredAllocate(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LAllocate* instr_;
   };
@@ -5703,8 +5753,8 @@
     type = Deoptimizer::LAZY;
   }
 
-  DeoptimizeIf(al, instr, type, zero_reg, Operand(zero_reg),
-               instr->hydrogen()->reason());
+  DeoptimizeIf(al, instr, type, instr->hydrogen()->reason(), zero_reg,
+               Operand(zero_reg));
 }
 
 
@@ -5735,10 +5785,9 @@
    public:
     DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredStackCheck(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredStackCheck(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStackCheck* instr_;
   };
@@ -5795,18 +5844,19 @@
   Register result = ToRegister(instr->result());
   Register object = ToRegister(instr->object());
   __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
-  DeoptimizeIf(eq, instr, object, Operand(at));
+  DeoptimizeIf(eq, instr, "undefined", object, Operand(at));
 
   Register null_value = a5;
   __ LoadRoot(null_value, Heap::kNullValueRootIndex);
-  DeoptimizeIf(eq, instr, object, Operand(null_value));
+  DeoptimizeIf(eq, instr, "null", object, Operand(null_value));
 
   __ And(at, object, kSmiTagMask);
-  DeoptimizeIf(eq, instr, at, Operand(zero_reg));
+  DeoptimizeIf(eq, instr, "Smi", at, Operand(zero_reg));
 
   STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
   __ GetObjectType(object, a1, a1);
-  DeoptimizeIf(le, instr, a1, Operand(LAST_JS_PROXY_TYPE));
+  DeoptimizeIf(le, instr, "not a JavaScript object", a1,
+               Operand(LAST_JS_PROXY_TYPE));
 
   Label use_cache, call_runtime;
   DCHECK(object.is(a0));
@@ -5823,7 +5873,7 @@
   __ ld(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
   DCHECK(result.is(v0));
   __ LoadRoot(at, Heap::kMetaMapRootIndex);
-  DeoptimizeIf(ne, instr, a1, Operand(at));
+  DeoptimizeIf(ne, instr, "wrong map", a1, Operand(at));
   __ bind(&use_cache);
 }
 
@@ -5843,7 +5893,7 @@
         FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
   __ ld(result,
         FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
-  DeoptimizeIf(eq, instr, result, Operand(zero_reg));
+  DeoptimizeIf(eq, instr, "no cache", result, Operand(zero_reg));
 
   __ bind(&done);
 }
@@ -5853,7 +5903,7 @@
   Register object = ToRegister(instr->value());
   Register map = ToRegister(instr->map());
   __ ld(scratch0(), FieldMemOperand(object, HeapObject::kMapOffset));
-  DeoptimizeIf(ne, instr, map, Operand(scratch0()));
+  DeoptimizeIf(ne, instr, "wrong map", map, Operand(scratch0()));
 }
 
 
@@ -5885,10 +5935,11 @@
           object_(object),
           index_(index) {
     }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredLoadMutableDouble(instr_, result_, object_, index_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LLoadFieldByIndex* instr_;
     Register result_;
diff --git a/src/mips64/lithium-codegen-mips64.h b/src/mips64/lithium-codegen-mips64.h
index a4b7adb..b320dcb 100644
--- a/src/mips64/lithium-codegen-mips64.h
+++ b/src/mips64/lithium-codegen-mips64.h
@@ -230,14 +230,12 @@
   void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
                                             Safepoint::DeoptMode mode);
   void DeoptimizeIf(Condition condition, LInstruction* instr,
-                    Deoptimizer::BailoutType bailout_type,
+                    Deoptimizer::BailoutType bailout_type, const char* detail,
                     Register src1 = zero_reg,
-                    const Operand& src2 = Operand(zero_reg),
-                    const char* detail = NULL);
+                    const Operand& src2 = Operand(zero_reg));
   void DeoptimizeIf(Condition condition, LInstruction* instr,
-                    Register src1 = zero_reg,
-                    const Operand& src2 = Operand(zero_reg),
-                    const char* detail = NULL);
+                    const char* detail, Register src1 = zero_reg,
+                    const Operand& src2 = Operand(zero_reg));
 
   void AddToTranslation(LEnvironment* environment,
                         Translation* translation,
diff --git a/src/mips64/lithium-mips64.cc b/src/mips64/lithium-mips64.cc
index 4892611..a12764b 100644
--- a/src/mips64/lithium-mips64.cc
+++ b/src/mips64/lithium-mips64.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <sstream>
+
 #include "src/v8.h"
 
 #if V8_TARGET_ARCH_MIPS64
@@ -323,9 +325,9 @@
 
 void LStoreNamedField::PrintDataTo(StringStream* stream) {
   object()->PrintTo(stream);
-  OStringStream os;
+  std::ostringstream os;
   os << hydrogen()->access() << " <- ";
-  stream->Add(os.c_str());
+  stream->Add(os.str().c_str());
   value()->PrintTo(stream);
 }
 
@@ -704,11 +706,7 @@
     // Shift operations can only deoptimize if we do a logical shift
     // by 0 and the result cannot be truncated to int32.
     if (op == Token::SHR && constant_value == 0) {
-      if (FLAG_opt_safe_uint32_operations) {
-        does_deopt = !instr->CheckFlag(HInstruction::kUint32);
-      } else {
-        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32);
-      }
+      does_deopt = !instr->CheckFlag(HInstruction::kUint32);
     }
 
     LInstruction* result =
@@ -1105,9 +1103,17 @@
       UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
   LOperand* name_register =
       UseFixed(instr->name(), LoadDescriptor::NameRegister());
+  LOperand* slot = NULL;
+  LOperand* vector = NULL;
+  if (FLAG_vector_ics) {
+    slot = UseFixed(instr->slot(), VectorLoadICDescriptor::SlotRegister());
+    vector =
+        UseFixed(instr->vector(), VectorLoadICDescriptor::VectorRegister());
+  }
+
   // Not marked as call. It can't deoptimize, and it never returns.
   return new (zone()) LTailCallThroughMegamorphicCache(
-      context, receiver_register, name_register);
+      context, receiver_register, name_register, slot, vector);
 }
 
 
@@ -1404,8 +1410,14 @@
   DCHECK(instr->right()->representation().Equals(instr->representation()));
   LOperand* dividend = UseRegister(instr->left());
   LOperand* divisor = UseRegister(instr->right());
-  LFlooringDivI* div = new(zone()) LFlooringDivI(dividend, divisor);
-  return AssignEnvironment(DefineAsRegister(div));
+  LInstruction* result =
+      DefineAsRegister(new (zone()) LFlooringDivI(dividend, divisor));
+  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
+      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
+      (instr->CheckFlag(HValue::kCanOverflow))) {
+    result = AssignEnvironment(result);
+  }
+  return result;
 }
 
 
@@ -2060,7 +2072,7 @@
   LOperand* global_object =
       UseFixed(instr->global_object(), LoadDescriptor::ReceiverRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
   LLoadGlobalGeneric* result =
@@ -2119,7 +2131,7 @@
   LOperand* object =
       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
 
@@ -2187,7 +2199,7 @@
       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
   LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
 
diff --git a/src/mips64/lithium-mips64.h b/src/mips64/lithium-mips64.h
index c6257a4..b89a9c4 100644
--- a/src/mips64/lithium-mips64.h
+++ b/src/mips64/lithium-mips64.h
@@ -162,17 +162,13 @@
   V(UnknownOSRValue)                         \
   V(WrapReceiver)
 
-#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)                        \
-  virtual Opcode opcode() const FINAL OVERRIDE {                      \
-    return LInstruction::k##type;                                           \
-  }                                                                         \
-  virtual void CompileToNative(LCodeGen* generator) FINAL OVERRIDE;   \
-  virtual const char* Mnemonic() const FINAL OVERRIDE {               \
-    return mnemonic;                                                        \
-  }                                                                         \
-  static L##type* cast(LInstruction* instr) {                               \
-    DCHECK(instr->Is##type());                                              \
-    return reinterpret_cast<L##type*>(instr);                               \
+#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)            \
+  Opcode opcode() const FINAL { return LInstruction::k##type; } \
+  void CompileToNative(LCodeGen* generator) FINAL;              \
+  const char* Mnemonic() const FINAL { return mnemonic; }       \
+  static L##type* cast(LInstruction* instr) {                   \
+    DCHECK(instr->Is##type());                                  \
+    return reinterpret_cast<L##type*>(instr);                   \
   }
 
 
@@ -287,11 +283,9 @@
  public:
   // Allow 0 or 1 output operands.
   STATIC_ASSERT(R == 0 || R == 1);
-  virtual bool HasResult() const FINAL OVERRIDE {
-    return R != 0 && result() != NULL;
-  }
+  bool HasResult() const FINAL { return R != 0 && result() != NULL; }
   void set_result(LOperand* operand) { results_[0] = operand; }
-  LOperand* result() const { return results_[0]; }
+  LOperand* result() const OVERRIDE { return results_[0]; }
 
  protected:
   EmbeddedContainer<LOperand*, R> results_;
@@ -309,11 +303,11 @@
 
  private:
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return I; }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return I; }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return T; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return temps_[i]; }
+  int TempCount() FINAL { return T; }
+  LOperand* TempAt(int i) FINAL { return temps_[i]; }
 };
 
 
@@ -328,8 +322,8 @@
   }
 
   // Can't use the DECLARE-macro here because of sub-classes.
-  virtual bool IsGap() const FINAL OVERRIDE { return true; }
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsGap() const FINAL { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   static LGap* cast(LInstruction* instr) {
     DCHECK(instr->IsGap());
     return reinterpret_cast<LGap*>(instr);
@@ -369,7 +363,7 @@
  public:
   explicit LInstructionGap(HBasicBlock* block) : LGap(block) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
     return !IsRedundant();
   }
 
@@ -381,10 +375,10 @@
  public:
   explicit LGoto(HBasicBlock* block) : block_(block) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
   DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
-  virtual bool IsControl() const OVERRIDE { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsControl() const OVERRIDE { return true; }
 
   int block_id() const { return block_->block_id(); }
 
@@ -427,7 +421,7 @@
 
 class LDeoptimize FINAL : public LTemplateInstruction<0, 0, 0> {
  public:
-  virtual bool IsControl() const OVERRIDE { return true; }
+  bool IsControl() const OVERRIDE { return true; }
   DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
   DECLARE_HYDROGEN_ACCESSOR(Deoptimize)
 };
@@ -438,12 +432,10 @@
   explicit LLabel(HBasicBlock* block)
       : LGap(block), replacement_(NULL) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(Label, "label")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int block_id() const { return block()->block_id(); }
   bool is_loop_header() const { return block()->IsLoopHeader(); }
@@ -461,9 +453,7 @@
 
 class LParameter FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter")
 };
 
@@ -482,19 +472,23 @@
 
 
 class LTailCallThroughMegamorphicCache FINAL
-    : public LTemplateInstruction<0, 3, 0> {
+    : public LTemplateInstruction<0, 5, 0> {
  public:
-  explicit LTailCallThroughMegamorphicCache(LOperand* context,
-                                            LOperand* receiver,
-                                            LOperand* name) {
+  LTailCallThroughMegamorphicCache(LOperand* context, LOperand* receiver,
+                                   LOperand* name, LOperand* slot,
+                                   LOperand* vector) {
     inputs_[0] = context;
     inputs_[1] = receiver;
     inputs_[2] = name;
+    inputs_[3] = slot;
+    inputs_[4] = vector;
   }
 
   LOperand* context() { return inputs_[0]; }
   LOperand* receiver() { return inputs_[1]; }
   LOperand* name() { return inputs_[2]; }
+  LOperand* slot() { return inputs_[3]; }
+  LOperand* vector() { return inputs_[4]; }
 
   DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
                                "tail-call-through-megamorphic-cache")
@@ -504,9 +498,7 @@
 
 class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown-osr-value")
 };
 
@@ -516,7 +508,7 @@
  public:
   LControlInstruction() : false_label_(NULL), true_label_(NULL) { }
 
-  virtual bool IsControl() const FINAL OVERRIDE { return true; }
+  bool IsControl() const FINAL { return true; }
 
   int SuccessorCount() { return hydrogen()->SuccessorCount(); }
   HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); }
@@ -605,7 +597,7 @@
   LOperand* length() { return inputs_[1]; }
   LOperand* index() { return inputs_[2]; }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -845,7 +837,7 @@
     return hydrogen()->representation().IsDouble();
   }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1033,7 +1025,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1050,7 +1042,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1065,7 +1057,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1083,7 +1075,7 @@
                                "is-undetectable-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1105,7 +1097,7 @@
 
   Token::Value op() const { return hydrogen()->token(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1121,7 +1113,7 @@
                                "has-instance-type-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1151,7 +1143,7 @@
                                "has-cached-array-index-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1169,7 +1161,7 @@
                                "class-of-test-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1366,7 +1358,7 @@
   DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
   DECLARE_HYDROGEN_ACCESSOR(Branch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1511,11 +1503,9 @@
   LOperand* left() { return inputs_[0]; }
   LOperand* right() { return inputs_[1]; }
 
-  virtual Opcode opcode() const OVERRIDE {
-    return LInstruction::kArithmeticD;
-  }
-  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
-  virtual const char* Mnemonic() const OVERRIDE;
+  Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticD; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
 
  private:
   Token::Value op_;
@@ -1539,9 +1529,9 @@
   LOperand* right() { return inputs_[2]; }
   Token::Value op() const { return op_; }
 
-  virtual Opcode opcode() const FINAL  { return LInstruction::kArithmeticT; }
-  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
-  virtual const char* Mnemonic() const OVERRIDE;
+  Opcode opcode() const FINAL { return LInstruction::kArithmeticT; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
 
  private:
   Token::Value op_;
@@ -1650,7 +1640,7 @@
   DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
   DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   uint32_t base_offset() const { return hydrogen()->base_offset(); }
 };
 
@@ -1731,7 +1721,7 @@
 
   int slot_index() { return hydrogen()->slot_index(); }
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1750,7 +1740,7 @@
 
   int slot_index() { return hydrogen()->slot_index(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1789,7 +1779,7 @@
   LOperand* function() { return inputs_[0]; }
   LOperand* code_object() { return inputs_[1]; }
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry, "store-code-entry")
   DECLARE_HYDROGEN_ACCESSOR(StoreCodeEntry)
@@ -1806,7 +1796,7 @@
   LOperand* base_object() const { return inputs_[0]; }
   LOperand* offset() const { return inputs_[1]; }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object")
 };
@@ -1850,7 +1840,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallJSFunction, "call-js-function")
   DECLARE_HYDROGEN_ACCESSOR(CallJSFunction)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1870,11 +1860,12 @@
 
   const CallInterfaceDescriptor descriptor() { return descriptor_; }
 
- private:
-  DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
   DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+ private:
+  DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 
@@ -1882,11 +1873,11 @@
   ZoneList<LOperand*> inputs_;
 
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return inputs_.length(); }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return inputs_.length(); }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return 0; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return NULL; }
+  int TempCount() FINAL { return 0; }
+  LOperand* TempAt(int i) FINAL { return NULL; }
 };
 
 
@@ -1904,7 +1895,7 @@
   DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function")
   DECLARE_HYDROGEN_ACCESSOR(InvokeFunction)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1940,7 +1931,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
   DECLARE_HYDROGEN_ACCESSOR(CallNew)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1959,7 +1950,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
   DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1976,7 +1967,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
   DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
 
-  virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
+  bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
     return save_doubles() == kDontSaveFPRegs;
   }
 
@@ -2154,7 +2145,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
   DECLARE_HYDROGEN_ACCESSOR(StoreNamedField)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Representation representation() const {
     return hydrogen()->field_representation();
@@ -2177,7 +2168,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
   DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Handle<Object> name() const { return hydrogen()->name(); }
   StrictMode strict_mode() { return hydrogen()->strict_mode(); }
@@ -2209,7 +2200,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed")
   DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
   uint32_t base_offset() const { return hydrogen()->base_offset(); }
 };
@@ -2235,7 +2226,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
   DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   StrictMode strict_mode() { return hydrogen()->strict_mode(); }
 };
@@ -2259,7 +2250,7 @@
                                "transition-elements-kind")
   DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Handle<Map> original_map() { return hydrogen()->original_map().handle(); }
   Handle<Map> transitioned_map() {
@@ -2555,7 +2546,7 @@
 
   Handle<String> type_literal() { return hydrogen()->type_literal(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -2576,9 +2567,7 @@
  public:
   LOsrEntry() {}
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry")
 };
 
@@ -2781,7 +2770,7 @@
 
   // An input operand in register, stack slot or a constant operand.
   // Will not be moved to a register even if one is freely available.
-  virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE;
+  MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE;
 
   // Temporary operand that must be in a register.
   MUST_USE_RESULT LUnallocated* TempRegister();
diff --git a/src/mips64/macro-assembler-mips64.cc b/src/mips64/macro-assembler-mips64.cc
index 12d81bc..2de1c2a 100644
--- a/src/mips64/macro-assembler-mips64.cc
+++ b/src/mips64/macro-assembler-mips64.cc
@@ -14,7 +14,7 @@
 #include "src/cpu-profiler.h"
 #include "src/debug.h"
 #include "src/isolate-inl.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -22,7 +22,8 @@
 MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size)
     : Assembler(arg_isolate, buffer, size),
       generating_stub_(false),
-      has_frame_(false) {
+      has_frame_(false),
+      has_double_zero_reg_set_(false) {
   if (isolate() != NULL) {
     code_object_ = Handle<Object>(isolate()->heap()->undefined_value(),
                                   isolate());
@@ -595,11 +596,12 @@
   }
 
   bind(&done);
-  // Check that the value is a normal property.
+  // Check that the value is a field property.
   // reg2: elements + (index * kPointerSize).
   const int kDetailsOffset =
       SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
   ld(reg1, FieldMemOperand(reg2, kDetailsOffset));
+  DCHECK_EQ(FIELD, 0);
   And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
   Branch(miss, ne, at, Operand(zero_reg));
 
@@ -711,6 +713,28 @@
 }
 
 
+void MacroAssembler::Mulhu(Register rd, Register rs, const Operand& rt) {
+  if (rt.is_reg()) {
+    if (kArchVariant != kMips64r6) {
+      multu(rs, rt.rm());
+      mfhi(rd);
+    } else {
+      muhu(rd, rs, rt.rm());
+    }
+  } else {
+    // li handles the relocation.
+    DCHECK(!rs.is(at));
+    li(at, rt);
+    if (kArchVariant != kMips64r6) {
+      multu(rs, at);
+      mfhi(rd);
+    } else {
+      muhu(rd, rs, at);
+    }
+  }
+}
+
+
 void MacroAssembler::Dmul(Register rd, Register rs, const Operand& rt) {
   if (rt.is_reg()) {
     if (kArchVariant == kMips64r6) {
@@ -815,6 +839,72 @@
 }
 
 
+void MacroAssembler::Div(Register res, Register rs, const Operand& rt) {
+  if (rt.is_reg()) {
+    if (kArchVariant != kMips64r6) {
+      div(rs, rt.rm());
+      mflo(res);
+    } else {
+      div(res, rs, rt.rm());
+    }
+  } else {
+    // li handles the relocation.
+    DCHECK(!rs.is(at));
+    li(at, rt);
+    if (kArchVariant != kMips64r6) {
+      div(rs, at);
+      mflo(res);
+    } else {
+      div(res, rs, at);
+    }
+  }
+}
+
+
+void MacroAssembler::Mod(Register rd, Register rs, const Operand& rt) {
+  if (rt.is_reg()) {
+    if (kArchVariant != kMips64r6) {
+      div(rs, rt.rm());
+      mfhi(rd);
+    } else {
+      mod(rd, rs, rt.rm());
+    }
+  } else {
+    // li handles the relocation.
+    DCHECK(!rs.is(at));
+    li(at, rt);
+    if (kArchVariant != kMips64r6) {
+      div(rs, at);
+      mfhi(rd);
+    } else {
+      mod(rd, rs, at);
+    }
+  }
+}
+
+
+void MacroAssembler::Modu(Register rd, Register rs, const Operand& rt) {
+  if (rt.is_reg()) {
+    if (kArchVariant != kMips64r6) {
+      divu(rs, rt.rm());
+      mfhi(rd);
+    } else {
+      modu(rd, rs, rt.rm());
+    }
+  } else {
+    // li handles the relocation.
+    DCHECK(!rs.is(at));
+    li(at, rt);
+    if (kArchVariant != kMips64r6) {
+      divu(rs, at);
+      mfhi(rd);
+    } else {
+      modu(rd, rs, at);
+    }
+  }
+}
+
+
 void MacroAssembler::Ddiv(Register rs, const Operand& rt) {
   if (rt.is_reg()) {
     ddiv(rs, rt.rm());
@@ -864,6 +954,28 @@
 }
 
 
+void MacroAssembler::Divu(Register res, Register rs, const Operand& rt) {
+  if (rt.is_reg()) {
+    if (kArchVariant != kMips64r6) {
+      divu(rs, rt.rm());
+      mflo(res);
+    } else {
+      divu(res, rs, rt.rm());
+    }
+  } else {
+    // li handles the relocation.
+    DCHECK(!rs.is(at));
+    li(at, rt);
+    if (kArchVariant != kMips64r6) {
+      divu(rs, at);
+      mflo(res);
+    } else {
+      divu(res, rs, at);
+    }
+  }
+}
+
+
 void MacroAssembler::Ddivu(Register rs, const Operand& rt) {
   if (rt.is_reg()) {
     ddivu(rs, rt.rm());
@@ -876,6 +988,28 @@
 }
 
 
+void MacroAssembler::Ddivu(Register res, Register rs, const Operand& rt) {
+  if (rt.is_reg()) {
+    if (kArchVariant != kMips64r6) {
+      ddivu(rs, rt.rm());
+      mflo(res);
+    } else {
+      ddivu(res, rs, rt.rm());
+    }
+  } else {
+    // li handles the relocation.
+    DCHECK(!rs.is(at));
+    li(at, rt);
+    if (kArchVariant != kMips64r6) {
+      ddivu(rs, at);
+      mflo(res);
+    } else {
+      ddivu(res, rs, at);
+    }
+  }
+}
+
+
 void MacroAssembler::Dmod(Register rd, Register rs, const Operand& rt) {
   if (kArchVariant != kMips64r6) {
     if (rt.is_reg()) {
@@ -901,6 +1035,31 @@
 }
 
 
+void MacroAssembler::Dmodu(Register rd, Register rs, const Operand& rt) {
+  if (kArchVariant != kMips64r6) {
+    if (rt.is_reg()) {
+      ddivu(rs, rt.rm());
+      mfhi(rd);
+    } else {
+      // li handles the relocation.
+      DCHECK(!rs.is(at));
+      li(at, rt);
+      ddivu(rs, at);
+      mfhi(rd);
+    }
+  } else {
+    if (rt.is_reg()) {
+      dmodu(rd, rs, rt.rm());
+    } else {
+      // li handles the relocation.
+      DCHECK(!rs.is(at));
+      li(at, rt);
+      dmodu(rd, rs, at);
+    }
+  }
+}
+
+
 void MacroAssembler::And(Register rd, Register rs, const Operand& rt) {
   if (rt.is_reg()) {
     and_(rd, rs, rt.rm());
@@ -1003,27 +1162,10 @@
 
 
 void MacroAssembler::Ror(Register rd, Register rs, const Operand& rt) {
-  if (kArchVariant == kMips64r2) {
-    if (rt.is_reg()) {
-      rotrv(rd, rs, rt.rm());
-    } else {
-      rotr(rd, rs, rt.imm64_);
-    }
+  if (rt.is_reg()) {
+    rotrv(rd, rs, rt.rm());
   } else {
-    if (rt.is_reg()) {
-      subu(at, zero_reg, rt.rm());
-      sllv(at, rs, at);
-      srlv(rd, rs, rt.rm());
-      or_(rd, rd, at);
-    } else {
-      if (rt.imm64_ == 0) {
-        srl(rd, rs, 0);
-      } else {
-        srl(at, rs, rt.imm64_);
-        sll(rd, rs, (0x20 - rt.imm64_) & 0x1f);
-        or_(rd, rd, at);
-      }
-    }
+    rotr(rd, rs, rt.imm64_);
   }
 }
 
@@ -1281,6 +1423,14 @@
 }
 
 
+void MacroAssembler::Dext(Register rt, Register rs, uint16_t pos,
+                          uint16_t size) {
+  DCHECK(pos < 32);
+  DCHECK(pos + size < 33);
+  dext_(rt, rs, pos, size);
+}
+
+
 void MacroAssembler::Ins(Register rt,
                          Register rs,
                          uint16_t pos,
@@ -1567,15 +1717,20 @@
 }
 
 
+void MacroAssembler::Move(FPURegister dst, float imm) {
+  li(at, Operand(bit_cast<int32_t>(imm)));
+  mtc1(at, dst);
+}
+
+
 void MacroAssembler::Move(FPURegister dst, double imm) {
   static const DoubleRepresentation minus_zero(-0.0);
   static const DoubleRepresentation zero(0.0);
   DoubleRepresentation value_rep(imm);
   // Handle special values first.
-  bool force_load = dst.is(kDoubleRegZero);
-  if (value_rep == zero && !force_load) {
+  if (value_rep == zero && has_double_zero_reg_set_) {
     mov_d(dst, kDoubleRegZero);
-  } else if (value_rep == minus_zero && !force_load) {
+  } else if (value_rep == minus_zero && has_double_zero_reg_set_) {
     neg_d(dst, kDoubleRegZero);
   } else {
     uint32_t lo, hi;
@@ -1596,6 +1751,7 @@
     } else {
       mthc1(zero_reg, dst);
     }
+    if (dst.is(kDoubleRegZero)) has_double_zero_reg_set_ = true;
   }
 }
 
@@ -2000,18 +2156,26 @@
         b(offset);
         break;
       case eq:
-        // We don't want any other register but scratch clobbered.
-        DCHECK(!scratch.is(rs));
-        r2 = scratch;
-        li(r2, rt);
-        beq(rs, r2, offset);
+        if (rt.imm64_ == 0) {
+          beq(rs, zero_reg, offset);
+        } else {
+          // We don't want any other register but scratch clobbered.
+          DCHECK(!scratch.is(rs));
+          r2 = scratch;
+          li(r2, rt);
+          beq(rs, r2, offset);
+        }
         break;
       case ne:
-        // We don't want any other register but scratch clobbered.
-        DCHECK(!scratch.is(rs));
-        r2 = scratch;
-        li(r2, rt);
-        bne(rs, r2, offset);
+        if (rt.imm64_ == 0) {
+          bne(rs, zero_reg, offset);
+        } else {
+          // We don't want any other register but scratch clobbered.
+          DCHECK(!scratch.is(rs));
+          r2 = scratch;
+          li(r2, rt);
+          bne(rs, r2, offset);
+        }
         break;
       // Signed comparison.
       case greater:
@@ -2253,18 +2417,28 @@
         b(offset);
         break;
       case eq:
-        DCHECK(!scratch.is(rs));
-        r2 = scratch;
-        li(r2, rt);
-        offset = shifted_branch_offset(L, false);
-        beq(rs, r2, offset);
+        if (rt.imm64_ == 0) {
+          offset = shifted_branch_offset(L, false);
+          beq(rs, zero_reg, offset);
+        } else {
+          DCHECK(!scratch.is(rs));
+          r2 = scratch;
+          li(r2, rt);
+          offset = shifted_branch_offset(L, false);
+          beq(rs, r2, offset);
+        }
         break;
       case ne:
-        DCHECK(!scratch.is(rs));
-        r2 = scratch;
-        li(r2, rt);
-        offset = shifted_branch_offset(L, false);
-        bne(rs, r2, offset);
+        if (rt.imm64_ == 0) {
+          offset = shifted_branch_offset(L, false);
+          bne(rs, zero_reg, offset);
+        } else {
+          DCHECK(!scratch.is(rs));
+          r2 = scratch;
+          li(r2, rt);
+          offset = shifted_branch_offset(L, false);
+          bne(rs, r2, offset);
+        }
         break;
       // Signed comparison.
       case greater:
@@ -3091,7 +3265,7 @@
   // Compute the handler entry address and jump to it.  The handler table is
   // a fixed array of (smi-tagged) code offsets.
   // v0 = exception, a1 = code object, a2 = state.
-  Uld(a3, FieldMemOperand(a1, Code::kHandlerTableOffset));
+  ld(a3, FieldMemOperand(a1, Code::kHandlerTableOffset));
   Daddu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
   dsrl(a2, a2, StackHandler::kKindWidth);  // Handler index.
   dsll(a2, a2, kPointerSizeLog2);
@@ -3791,17 +3965,17 @@
 }
 
 
-void MacroAssembler::DispatchMap(Register obj,
-                                 Register scratch,
-                                 Handle<Map> map,
-                                 Handle<Code> success,
-                                 SmiCheckType smi_check_type) {
+void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
+                                     Register scratch2, Handle<WeakCell> cell,
+                                     Handle<Code> success,
+                                     SmiCheckType smi_check_type) {
   Label fail;
   if (smi_check_type == DO_SMI_CHECK) {
     JumpIfSmi(obj, &fail);
   }
-  ld(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
-  Jump(success, RelocInfo::CODE_TARGET, eq, scratch, Operand(map));
+  ld(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset));
+  GetWeakValue(scratch2, cell);
+  Jump(success, RelocInfo::CODE_TARGET, eq, scratch1, Operand(scratch2));
   bind(&fail);
 }
 
@@ -3820,6 +3994,19 @@
 }
 
 
+void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
+  li(value, Operand(cell));
+  ld(value, FieldMemOperand(value, WeakCell::kValueOffset));
+}
+
+
+void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
+                                   Label* miss) {
+  GetWeakValue(value, cell);
+  JumpIfSmi(value, miss);
+}
+
+
 void MacroAssembler::MovFromFloatResult(const DoubleRegister dst) {
   if (IsMipsSoftFloatABI) {
     Move(dst, v0, v1);
@@ -4367,6 +4554,33 @@
 }
 
 
+void MacroAssembler::AdduAndCheckForOverflow(Register dst, Register left,
+                                             const Operand& right,
+                                             Register overflow_dst,
+                                             Register scratch) {
+  if (right.is_reg()) {
+    AdduAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
+  } else {
+    if (dst.is(left)) {
+      mov(scratch, left);                    // Preserve left.
+      daddiu(dst, left, right.immediate());  // Left is overwritten.
+      xor_(scratch, dst, scratch);           // Original left.
+      // Load right since xori takes uint16 as immediate.
+      daddiu(t9, zero_reg, right.immediate());
+      xor_(overflow_dst, dst, t9);
+      and_(overflow_dst, overflow_dst, scratch);
+    } else {
+      daddiu(dst, left, right.immediate());
+      xor_(overflow_dst, dst, left);
+      // Load right since xori takes uint16 as immediate.
+      daddiu(t9, zero_reg, right.immediate());
+      xor_(scratch, dst, t9);
+      and_(overflow_dst, scratch, overflow_dst);
+    }
+  }
+}
+
+
 void MacroAssembler::AdduAndCheckForOverflow(Register dst,
                                              Register left,
                                              Register right,
@@ -4409,6 +4623,33 @@
 }
 
 
+void MacroAssembler::SubuAndCheckForOverflow(Register dst, Register left,
+                                             const Operand& right,
+                                             Register overflow_dst,
+                                             Register scratch) {
+  if (right.is_reg()) {
+    SubuAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
+  } else {
+    if (dst.is(left)) {
+      mov(scratch, left);                       // Preserve left.
+      daddiu(dst, left, -(right.immediate()));  // Left is overwritten.
+      xor_(overflow_dst, dst, scratch);         // scratch is original left.
+      // Load right since xori takes uint16 as immediate.
+      daddiu(t9, zero_reg, right.immediate());
+      xor_(scratch, scratch, t9);  // scratch is original left.
+      and_(overflow_dst, scratch, overflow_dst);
+    } else {
+      daddiu(dst, left, -(right.immediate()));
+      xor_(overflow_dst, dst, left);
+      // Load right since xori takes uint16 as immediate.
+      daddiu(t9, zero_reg, right.immediate());
+      xor_(scratch, left, t9);
+      and_(overflow_dst, scratch, overflow_dst);
+    }
+  }
+}
+
+
 void MacroAssembler::SubuAndCheckForOverflow(Register dst,
                                              Register left,
                                              Register right,
@@ -4779,6 +5020,13 @@
 }
 
 
+void MacroAssembler::EnterFrame(StackFrame::Type type,
+                                bool load_constant_pool_pointer_reg) {
+  // Out-of-line constant pool not implemented on mips64.
+  UNREACHABLE();
+}
+
+
 void MacroAssembler::EnterFrame(StackFrame::Type type) {
   daddiu(sp, sp, -5 * kPointerSize);
   li(t8, Operand(Smi::FromInt(type)));
@@ -5602,18 +5850,6 @@
 }
 
 
-void MacroAssembler::CheckMapDeprecated(Handle<Map> map,
-                                        Register scratch,
-                                        Label* if_deprecated) {
-  if (map->CanBeDeprecated()) {
-    li(scratch, Operand(map));
-    ld(scratch, FieldMemOperand(scratch, Map::kBitField3Offset));
-    And(scratch, scratch, Operand(Map::Deprecated::kMask));
-    Branch(if_deprecated, ne, scratch, Operand(zero_reg));
-  }
-}
-
-
 void MacroAssembler::JumpIfBlack(Register object,
                                  Register scratch0,
                                  Register scratch1,
@@ -6069,7 +6305,7 @@
   DCHECK(!result.is(at));
   base::MagicNumbersForDivision<uint32_t> mag =
   base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
-  li(at, Operand(mag.multiplier));
+  li(at, Operand(static_cast<int32_t>(mag.multiplier)));
   Mulh(result, dividend, Operand(at));
   bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
   if (divisor > 0 && neg) {
diff --git a/src/mips64/macro-assembler-mips64.h b/src/mips64/macro-assembler-mips64.h
index 2da48fb..a9e8772 100644
--- a/src/mips64/macro-assembler-mips64.h
+++ b/src/mips64/macro-assembler-mips64.h
@@ -271,8 +271,10 @@
     mthc1(src_high, dst);
   }
 
-  // Conditional move.
+  void Move(FPURegister dst, float imm);
   void Move(FPURegister dst, double imm);
+
+  // Conditional move.
   void Movz(Register rd, Register rs, Register rt);
   void Movn(Register rd, Register rs, Register rt);
   void Movt(Register rd, Register rs, uint16_t cc = 0);
@@ -334,10 +336,6 @@
                      Condition cc,
                      Label* condition_met);
 
-  void CheckMapDeprecated(Handle<Map> map,
-                          Register scratch,
-                          Label* if_deprecated);
-
   // Check if object is in new space.  Jumps if the object is not in new space.
   // The register scratch can be object itself, but it will be clobbered.
   void JumpIfNotInNewSpace(Register object,
@@ -599,12 +597,19 @@
 
   DEFINE_INSTRUCTION(Addu);
   DEFINE_INSTRUCTION(Daddu);
+  DEFINE_INSTRUCTION(Div);
+  DEFINE_INSTRUCTION(Divu);
+  DEFINE_INSTRUCTION(Ddivu);
+  DEFINE_INSTRUCTION(Mod);
+  DEFINE_INSTRUCTION(Modu);
   DEFINE_INSTRUCTION(Ddiv);
   DEFINE_INSTRUCTION(Subu);
   DEFINE_INSTRUCTION(Dsubu);
   DEFINE_INSTRUCTION(Dmod);
+  DEFINE_INSTRUCTION(Dmodu);
   DEFINE_INSTRUCTION(Mul);
   DEFINE_INSTRUCTION(Mulh);
+  DEFINE_INSTRUCTION(Mulhu);
   DEFINE_INSTRUCTION(Dmul);
   DEFINE_INSTRUCTION(Dmulh);
   DEFINE_INSTRUCTION2(Mult);
@@ -758,6 +763,7 @@
   // MIPS64 R2 instruction macro.
   void Ins(Register rt, Register rs, uint16_t pos, uint16_t size);
   void Ext(Register rt, Register rs, uint16_t pos, uint16_t size);
+  void Dext(Register rt, Register rs, uint16_t pos, uint16_t size);
 
   // ---------------------------------------------------------------------------
   // FPU macros. These do not handle special cases like NaN or +- inf.
@@ -1104,15 +1110,19 @@
                 Label* fail,
                 SmiCheckType smi_check_type);
 
-  // Check if the map of an object is equal to a specified map and branch to a
-  // specified target if equal. Skip the smi check if not required (object is
-  // known to be a heap object)
-  void DispatchMap(Register obj,
-                   Register scratch,
-                   Handle<Map> map,
-                   Handle<Code> success,
-                   SmiCheckType smi_check_type);
+  // Check if the map of an object is equal to a specified weak map and branch
+  // to a specified target if equal. Skip the smi check if not required
+  // (object is known to be a heap object)
+  void DispatchWeakMap(Register obj, Register scratch1, Register scratch2,
+                       Handle<WeakCell> cell, Handle<Code> success,
+                       SmiCheckType smi_check_type);
 
+  // Get value of the weak cell.
+  void GetWeakValue(Register value, Handle<WeakCell> cell);
+
+  // Load the value of the weak cell in the value register. Branch to the
+  // given miss label is the weak cell was cleared.
+  void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
 
   // Load and check the instance type of an object for being a string.
   // Loads the type into the second argument register.
@@ -1168,12 +1178,20 @@
                                Register overflow_dst,
                                Register scratch = at);
 
+  void AdduAndCheckForOverflow(Register dst, Register left,
+                               const Operand& right, Register overflow_dst,
+                               Register scratch = at);
+
   void SubuAndCheckForOverflow(Register dst,
                                Register left,
                                Register right,
                                Register overflow_dst,
                                Register scratch = at);
 
+  void SubuAndCheckForOverflow(Register dst, Register left,
+                               const Operand& right, Register overflow_dst,
+                               Register scratch = at);
+
   void BranchOnOverflow(Label* label,
                         Register overflow_check,
                         BranchDelaySlot bd = PROTECT) {
@@ -1198,13 +1216,10 @@
   // Runtime calls.
 
   // See comments at the beginning of CEntryStub::Generate.
-  inline void PrepareCEntryArgs(int num_args) {
-    li(s0, num_args);
-    li(s1, (num_args - 1) * kPointerSize);
-  }
+  inline void PrepareCEntryArgs(int num_args) { li(a0, num_args); }
 
   inline void PrepareCEntryFunction(const ExternalReference& ref) {
-    li(s2, Operand(ref));
+    li(a1, Operand(ref));
   }
 
 #define COND_ARGS Condition cond = al, Register rs = zero_reg, \
@@ -1617,6 +1632,7 @@
 
   // Activation support.
   void EnterFrame(StackFrame::Type type);
+  void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
   void LeaveFrame(StackFrame::Type type);
 
   // Patch the relocated value (lui/ori pair).
@@ -1719,6 +1735,7 @@
 
   bool generating_stub_;
   bool has_frame_;
+  bool has_double_zero_reg_set_;
   // This handle will be patched with the code object on installation.
   Handle<Object> code_object_;
 
diff --git a/src/mips64/simulator-mips64.cc b/src/mips64/simulator-mips64.cc
index 4c74939..9899d47 100644
--- a/src/mips64/simulator-mips64.cc
+++ b/src/mips64/simulator-mips64.cc
@@ -2080,16 +2080,15 @@
         case MFLO:
           *alu_out = get_register(LO);
           break;
-        case MULT:  // MULT == D_MUL_MUH.
-          // TODO(plind) - Unify MULT/DMULT with single set of 64-bit HI/Lo
-          // regs.
-          // TODO(plind) - make the 32-bit MULT ops conform to spec regarding
-          //   checking of 32-bit input values, and un-define operations of HW.
-          *i64hilo = static_cast<int64_t>((int32_t)rs) *
-              static_cast<int64_t>((int32_t)rt);
+        case MULT: {  // MULT == D_MUL_MUH.
+          int32_t rs_lo = static_cast<int32_t>(rs);
+          int32_t rt_lo = static_cast<int32_t>(rt);
+          *i64hilo = static_cast<int64_t>(rs_lo) * static_cast<int64_t>(rt_lo);
           break;
+        }
         case MULTU:
-          *u64hilo = static_cast<uint64_t>(rs_u) * static_cast<uint64_t>(rt_u);
+          *u64hilo = static_cast<uint64_t>(rs_u & 0xffffffff) *
+                     static_cast<uint64_t>(rt_u & 0xffffffff);
           break;
         case DMULT:  // DMULT == D_MUL_MUH.
           if (kArchVariant != kMips64r6) {
@@ -2231,7 +2230,7 @@
           // Interpret sa field as 5-bit lsb of insert.
           uint16_t lsb = sa;
           uint16_t size = msb - lsb + 1;
-          uint32_t mask = (1 << size) - 1;
+          uint64_t mask = (1ULL << size) - 1;
           *alu_out = (rt_u & ~(mask << lsb)) | ((rs_u & mask) << lsb);
           break;
         }
@@ -2241,8 +2240,18 @@
           // Interpret sa field as 5-bit lsb of extract.
           uint16_t lsb = sa;
           uint16_t size = msb + 1;
-          uint32_t mask = (1 << size) - 1;
-          *alu_out = (rs_u & (mask << lsb)) >> lsb;
+          uint64_t mask = (1ULL << size) - 1;
+          *alu_out = static_cast<int32_t>((rs_u & (mask << lsb)) >> lsb);
+          break;
+        }
+        case DEXT: {  // Mips32r2 instruction.
+          // Interpret rd field as 5-bit msb of extract.
+          uint16_t msb = rd_reg;
+          // Interpret sa field as 5-bit lsb of extract.
+          uint16_t lsb = sa;
+          uint16_t size = msb + 1;
+          uint64_t mask = (1ULL << size) - 1;
+          *alu_out = static_cast<int64_t>((rs_u & (mask << lsb)) >> lsb);
           break;
         }
         default:
@@ -2784,7 +2793,8 @@
           TraceRegWr(alu_out);
           break;
         case EXT:
-          // Ext instr leaves result in Rt, rather than Rd.
+        case DEXT:
+          // Dext/Ext instr leaves result in Rt, rather than Rd.
           set_register(rt_reg, alu_out);
           TraceRegWr(alu_out);
           break;
@@ -2816,9 +2826,9 @@
   int64_t  ft     = get_fpu_register(ft_reg);
 
   // Zero extended immediate.
-  uint32_t  oe_imm16 = 0xffff & imm16;
+  uint64_t oe_imm16 = 0xffff & imm16;
   // Sign extended immediate.
-  int32_t   se_imm16 = imm16;
+  int64_t se_imm16 = imm16;
 
   // Get current pc.
   int64_t current_pc = get_pc();
diff --git a/src/mips64/simulator-mips64.h b/src/mips64/simulator-mips64.h
index 5241554..3087dcd 100644
--- a/src/mips64/simulator-mips64.h
+++ b/src/mips64/simulator-mips64.h
@@ -436,9 +436,12 @@
 
 // When running with the simulator transition into simulated execution at this
 // point.
-#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
-    reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
-      FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
+#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4)                    \
+  reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
+      FUNCTION_ADDR(entry), 5, reinterpret_cast<int64_t*>(p0),            \
+      reinterpret_cast<int64_t*>(p1), reinterpret_cast<int64_t*>(p2),     \
+      reinterpret_cast<int64_t*>(p3), reinterpret_cast<int64_t*>(p4)))
+
 
 #ifdef MIPS_ABI_N64
 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
diff --git a/src/mirror-debugger.js b/src/mirror-debugger.js
index c36d6fd..c325e58 100644
--- a/src/mirror-debugger.js
+++ b/src/mirror-debugger.js
@@ -1,6 +1,7 @@
 // Copyright 2006-2012 the V8 project authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+"use strict";
 
 // Handle id counters.
 var next_handle_ = 0;
@@ -44,7 +45,7 @@
 
   // Look for non transient mirrors in the mirror cache.
   if (!opt_transient && mirror_cache_enabled_) {
-    for (id in mirror_cache_) {
+    for (var id in mirror_cache_) {
       mirror = mirror_cache_[id];
       if (mirror.value() === value) {
         return mirror;
@@ -85,6 +86,8 @@
     mirror = new MapMirror(value);
   } else if (IS_SET(value) || IS_WEAKSET(value)) {
     mirror = new SetMirror(value);
+  } else if (IS_MAP_ITERATOR(value) || IS_SET_ITERATOR(value)) {
+    mirror = new IteratorMirror(value);
   } else if (ObjectIsPromise(value)) {
     mirror = new PromiseMirror(value);
   } else if (IS_GENERATOR(value)) {
@@ -163,6 +166,7 @@
 var PROMISE_TYPE = 'promise';
 var MAP_TYPE = 'map';
 var SET_TYPE = 'set';
+var ITERATOR_TYPE = 'iterator';
 var GENERATOR_TYPE = 'generator';
 
 // Maximum length when sending strings through the JSON protocol.
@@ -176,9 +180,8 @@
 
 // A copy of the PropertyType enum from property-details.h
 var PropertyType = {};
-PropertyType.Normal                  = 0;
-PropertyType.Field                   = 1;
-PropertyType.Constant                = 2;
+PropertyType.Field                   = 0;
+PropertyType.Constant                = 1;
 PropertyType.Callbacks               = 3;
 
 
@@ -190,13 +193,16 @@
 PropertyAttribute.DontDelete = DONT_DELETE;
 
 
-// A copy of the scope types from runtime.cc.
+// A copy of the scope types from runtime-debug.cc.
+// NOTE: these constants should be backward-compatible, so
+// add new ones to the end of this list.
 var ScopeType = { Global: 0,
                   Local: 1,
                   With: 2,
                   Closure: 3,
                   Catch: 4,
-                  Block: 5 };
+                  Block: 5,
+                  Script: 6 };
 
 
 // Mirror hierarchy:
@@ -217,6 +223,7 @@
 //         - PromiseMirror
 //         - MapMirror
 //         - SetMirror
+//         - IteratorMirror
 //         - GeneratorMirror
 //     - PropertyMirror
 //     - InternalPropertyMirror
@@ -456,6 +463,15 @@
 
 
 /**
+ * Check whether the mirror reflects an iterator.
+ * @returns {boolean} True if the mirror reflects an iterator
+ */
+Mirror.prototype.isIterator = function() {
+  return this instanceof IteratorMirror;
+};
+
+
+/**
  * Allocate a handle id for this object.
  */
 Mirror.prototype.allocateHandle_ = function() {
@@ -906,13 +922,37 @@
       result.push(new InternalPropertyMirror("[[BoundArgs]]", boundArgs));
     }
     return result;
-  } else if (ObjectIsPromise(value)) {
-    var result = [];
-    result.push(new InternalPropertyMirror("[[PromiseStatus]]",
-                                           PromiseGetStatus_(value)));
-    result.push(new InternalPropertyMirror("[[PromiseValue]]",
-                                           PromiseGetValue_(value)));
+  } else if (IS_MAP_ITERATOR(value) || IS_SET_ITERATOR(value)) {
+    var details = IS_MAP_ITERATOR(value) ? %MapIteratorDetails(value)
+                                         : %SetIteratorDetails(value);
+    var kind;
+    switch (details[2]) {
+      case 1: kind = "keys"; break;
+      case 2: kind = "values"; break;
+      case 3: kind = "entries"; break;
+    }
+    var result = [
+      new InternalPropertyMirror("[[IteratorHasMore]]", details[0]),
+      new InternalPropertyMirror("[[IteratorIndex]]", details[1])
+    ];
+    if (kind) {
+      result.push(new InternalPropertyMirror("[[IteratorKind]]", kind));
+    }
     return result;
+  } else if (IS_GENERATOR(value)) {
+    return [
+      new InternalPropertyMirror("[[GeneratorStatus]]",
+                                 GeneratorGetStatus_(value)),
+      new InternalPropertyMirror("[[GeneratorFunction]]",
+                                 %GeneratorGetFunction(value)),
+      new InternalPropertyMirror("[[GeneratorReceiver]]",
+                                 %GeneratorGetReceiver(value))
+    ];
+  } else if (ObjectIsPromise(value)) {
+    return [
+      new InternalPropertyMirror("[[PromiseStatus]]", PromiseGetStatus_(value)),
+      new InternalPropertyMirror("[[PromiseValue]]", PromiseGetValue_(value))
+    ];
   }
   return [];
 }
@@ -1256,11 +1296,11 @@
   // Use the same text representation as in messages.js.
   var text;
   try {
-    str = %_CallFunction(this.value_, builtins.ErrorToString);
+    text = %_CallFunction(this.value_, builtins.ErrorToString);
   } catch (e) {
-    str = '#<Error>';
+    text = '#<Error>';
   }
-  return str;
+  return text;
 };
 
 
@@ -1309,13 +1349,14 @@
  * Returns an array of key/value pairs of a map.
  * This will keep keys alive for WeakMaps.
  *
+ * @param {number=} opt_limit Max elements to return.
  * @returns {Array.<Object>} Array of key/value pairs of a map.
  */
-MapMirror.prototype.entries = function() {
+MapMirror.prototype.entries = function(opt_limit) {
   var result = [];
 
   if (IS_WEAKMAP(this.value_)) {
-    var entries = %GetWeakMapEntries(this.value_);
+    var entries = %GetWeakMapEntries(this.value_, opt_limit || 0);
     for (var i = 0; i < entries.length; i += 2) {
       result.push({
         key: entries[i],
@@ -1327,7 +1368,8 @@
 
   var iter = %_CallFunction(this.value_, builtins.MapEntries);
   var next;
-  while (!(next = iter.next()).done) {
+  while ((!opt_limit || result.length < opt_limit) &&
+         !(next = iter.next()).done) {
     result.push({
       key: next.value[0],
       value: next.value[1]
@@ -1343,24 +1385,57 @@
 inherits(SetMirror, ObjectMirror);
 
 
+function IteratorGetValues_(iter, next_function, opt_limit) {
+  var result = [];
+  var next;
+  while ((!opt_limit || result.length < opt_limit) &&
+         !(next = %_CallFunction(iter, next_function)).done) {
+    result.push(next.value);
+  }
+  return result;
+}
+
+
 /**
  * Returns an array of elements of a set.
  * This will keep elements alive for WeakSets.
  *
+ * @param {number=} opt_limit Max elements to return.
  * @returns {Array.<Object>} Array of elements of a set.
  */
-SetMirror.prototype.values = function() {
+SetMirror.prototype.values = function(opt_limit) {
   if (IS_WEAKSET(this.value_)) {
-    return %GetWeakSetValues(this.value_);
+    return %GetWeakSetValues(this.value_, opt_limit || 0);
   }
 
-  var result = [];
   var iter = %_CallFunction(this.value_, builtins.SetValues);
-  var next;
-  while (!(next = iter.next()).done) {
-    result.push(next.value);
+  return IteratorGetValues_(iter, builtins.SetIteratorNextJS, opt_limit);
+};
+
+
+function IteratorMirror(value) {
+  %_CallFunction(this, value, ITERATOR_TYPE, ObjectMirror);
+}
+inherits(IteratorMirror, ObjectMirror);
+
+
+/**
+ * Returns a preview of elements of an iterator.
+ * Does not change the backing iterator state.
+ *
+ * @param {number=} opt_limit Max elements to return.
+ * @returns {Array.<Object>} Array of elements of an iterator.
+ */
+IteratorMirror.prototype.preview = function(opt_limit) {
+  if (IS_MAP_ITERATOR(this.value_)) {
+    return IteratorGetValues_(%MapIteratorClone(this.value_),
+                              builtins.MapIteratorNextJS,
+                              opt_limit);
+  } else if (IS_SET_ITERATOR(this.value_)) {
+    return IteratorGetValues_(%SetIteratorClone(this.value_),
+                              builtins.SetIteratorNextJS,
+                              opt_limit);
   }
-  return result;
 };
 
 
@@ -1376,11 +1451,16 @@
 inherits(GeneratorMirror, ObjectMirror);
 
 
-GeneratorMirror.prototype.status = function() {
-  var continuation = %GeneratorGetContinuation(this.value_);
+function GeneratorGetStatus_(value) {
+  var continuation = %GeneratorGetContinuation(value);
   if (continuation < 0) return "running";
   if (continuation == 0) return "closed";
   return "suspended";
+}
+
+
+GeneratorMirror.prototype.status = function() {
+  return GeneratorGetStatus_(this.value_);
 };
 
 
@@ -2245,11 +2325,12 @@
 
 
 ScopeMirror.prototype.scopeObject = function() {
-  // For local and closure scopes create a transient mirror as these objects are
-  // created on the fly materializing the local or closure scopes and
-  // therefore will not preserve identity.
+  // For local, closure and script scopes create a transient mirror
+  // as these objects are created on the fly materializing the local
+  // or closure scopes and therefore will not preserve identity.
   var transient = this.scopeType() == ScopeType.Local ||
-                  this.scopeType() == ScopeType.Closure;
+                  this.scopeType() == ScopeType.Closure ||
+                  this.scopeType() == ScopeType.Script;
   return MakeMirror(this.details_.object(), transient);
 };
 
@@ -2834,10 +2915,9 @@
  *    "ref":<number>}
  *
  * If the attribute for the property is PropertyAttribute.None it is not added.
- * If the propertyType for the property is PropertyType.Normal it is not added.
  * Here are a couple of examples.
  *
- *   {"name":"hello","ref":1}
+ *   {"name":"hello","propertyType":0,"ref":1}
  *   {"name":"length","attributes":7,"propertyType":3,"ref":2}
  *
  * @param {PropertyMirror} propertyMirror The property to serialize.
@@ -2854,9 +2934,7 @@
     if (propertyMirror.attributes() != PropertyAttribute.None) {
       result.attributes = propertyMirror.attributes();
     }
-    if (propertyMirror.propertyType() != PropertyType.Normal) {
-      result.propertyType = propertyMirror.propertyType();
-    }
+    result.propertyType = propertyMirror.propertyType();
     result.ref = propertyValue.handle();
   }
   return result;
diff --git a/src/misc-intrinsics.h b/src/misc-intrinsics.h
deleted file mode 100644
index 5256a29..0000000
--- a/src/misc-intrinsics.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_MISC_INTRINSICS_H_
-#define V8_MISC_INTRINSICS_H_
-
-#include "include/v8.h"
-#include "src/globals.h"
-
-namespace v8 {
-namespace internal {
-
-// Returns the index of the leading 1 bit, counting the least significant bit at
-// index 0.  (1 << IntegerLog2(x)) is a mask for the most significant bit of x.
-// Result is undefined if input is zero.
-int IntegerLog2(uint32_t value);
-
-#if defined(__GNUC__)
-
-inline int IntegerLog2(uint32_t value) {
-  return 31 - __builtin_clz(value);
-}
-
-#elif defined(_MSC_VER)
-
-#pragma intrinsic(_BitScanReverse)
-
-inline int IntegerLog2(uint32_t value) {
-  unsigned long result;             // NOLINT: MSVC intrinsic demands this type.
-  _BitScanReverse(&result, value);
-  return result;
-}
-
-#else
-
-// Default version using regular operations. Code taken from:
-// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
-inline int IntegerLog2(uint32_t value) {
-  int result, shift;
-
-  shift = (value > 0xFFFF) << 4;
-  value >>= shift;
-  result = shift;
-
-  shift = (value > 0xFF) << 3;
-  value >>= shift;
-  result |= shift;
-
-  shift = (value > 0xF) << 2;
-  value >>= shift;
-  result |= shift;
-
-  shift = (value > 0x3) << 1;
-  value >>= shift;
-  result |= shift;
-
-  result |= (value >> 1);
-
-  return result;
-}
-#endif
-
-} }  // namespace v8::internal
-
-#endif  // V8_MISC_INTRINSICS_H_
diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc
index b4a4018..988e7da 100644
--- a/src/mksnapshot.cc
+++ b/src/mksnapshot.cc
@@ -3,11 +3,8 @@
 // found in the LICENSE file.
 
 #include <errno.h>
-#include <stdio.h>
-#ifdef COMPRESS_STARTUP_DATA_BZ2
-#include <bzlib.h>
-#endif
 #include <signal.h>
+#include <stdio.h>
 
 #include "src/v8.h"
 
@@ -23,100 +20,43 @@
 
 using namespace v8;
 
-
-class Compressor {
- public:
-  virtual ~Compressor() {}
-  virtual bool Compress(i::Vector<i::byte> input) = 0;
-  virtual i::Vector<i::byte>* output() = 0;
-};
-
-
 class SnapshotWriter {
  public:
   explicit SnapshotWriter(const char* snapshot_file)
-      : fp_(GetFileDescriptorOrDie(snapshot_file))
-      , raw_file_(NULL)
-      , raw_context_file_(NULL)
-      , startup_blob_file_(NULL)
-      , compressor_(NULL) {
-  }
+      : fp_(GetFileDescriptorOrDie(snapshot_file)),
+        startup_blob_file_(NULL) {}
 
   ~SnapshotWriter() {
     fclose(fp_);
-    if (raw_file_) fclose(raw_file_);
-    if (raw_context_file_) fclose(raw_context_file_);
     if (startup_blob_file_) fclose(startup_blob_file_);
   }
 
-  void SetCompressor(Compressor* compressor) {
-    compressor_ = compressor;
-  }
-
-  void SetRawFiles(const char* raw_file, const char* raw_context_file) {
-    raw_file_ = GetFileDescriptorOrDie(raw_file);
-    raw_context_file_ = GetFileDescriptorOrDie(raw_context_file);
-  }
-
   void SetStartupBlobFile(const char* startup_blob_file) {
     if (startup_blob_file != NULL)
       startup_blob_file_ = GetFileDescriptorOrDie(startup_blob_file);
   }
 
-  void WriteSnapshot(const i::List<i::byte>& snapshot_data,
-                     const i::Serializer& serializer,
-                     const i::List<i::byte>& context_snapshot_data,
-                     const i::Serializer& context_serializer) const {
-    WriteSnapshotFile(snapshot_data, serializer,
-                      context_snapshot_data, context_serializer);
-    MaybeWriteStartupBlob(snapshot_data, serializer,
-                          context_snapshot_data, context_serializer);
+  void WriteSnapshot(v8::StartupData blob) const {
+    i::Vector<const i::byte> blob_vector(
+        reinterpret_cast<const i::byte*>(blob.data), blob.raw_size);
+    WriteSnapshotFile(blob_vector);
+    MaybeWriteStartupBlob(blob_vector);
   }
 
  private:
-  void MaybeWriteStartupBlob(const i::List<i::byte>& snapshot_data,
-                             const i::Serializer& serializer,
-                             const i::List<i::byte>& context_snapshot_data,
-                             const i::Serializer& context_serializer) const {
-    if (!startup_blob_file_)
-      return;
+  void MaybeWriteStartupBlob(const i::Vector<const i::byte>& blob) const {
+    if (!startup_blob_file_) return;
 
-    i::List<i::byte> startup_blob;
-    i::ListSnapshotSink sink(&startup_blob);
-
-    int spaces[] = {
-        i::NEW_SPACE, i::OLD_POINTER_SPACE, i::OLD_DATA_SPACE, i::CODE_SPACE,
-        i::MAP_SPACE, i::CELL_SPACE,  i::PROPERTY_CELL_SPACE
-    };
-
-    i::byte* snapshot_bytes = snapshot_data.begin();
-    sink.PutBlob(snapshot_bytes, snapshot_data.length(), "snapshot");
-    for (size_t i = 0; i < arraysize(spaces); ++i)
-      sink.PutInt(serializer.CurrentAllocationAddress(spaces[i]), "spaces");
-
-    i::byte* context_bytes = context_snapshot_data.begin();
-    sink.PutBlob(context_bytes, context_snapshot_data.length(), "context");
-    for (size_t i = 0; i < arraysize(spaces); ++i)
-      sink.PutInt(context_serializer.CurrentAllocationAddress(spaces[i]),
-                  "spaces");
-
-    size_t written = fwrite(startup_blob.begin(), 1, startup_blob.length(),
-                            startup_blob_file_);
-    if (written != (size_t)startup_blob.length()) {
+    size_t written = fwrite(blob.begin(), 1, blob.length(), startup_blob_file_);
+    if (written != static_cast<size_t>(blob.length())) {
       i::PrintF("Writing snapshot file failed.. Aborting.\n");
       exit(1);
     }
   }
 
-  void WriteSnapshotFile(const i::List<i::byte>& snapshot_data,
-                         const i::Serializer& serializer,
-                         const i::List<i::byte>& context_snapshot_data,
-                         const i::Serializer& context_serializer) const {
+  void WriteSnapshotFile(const i::Vector<const i::byte>& blob) const {
     WriteFilePrefix();
-    WriteData("", snapshot_data, raw_file_);
-    WriteData("context_", context_snapshot_data, raw_context_file_);
-    WriteMeta("context_", context_serializer);
-    WriteMeta("", serializer);
+    WriteData(blob);
     WriteFileSuffix();
   }
 
@@ -130,89 +70,29 @@
   }
 
   void WriteFileSuffix() const {
+    fprintf(fp_, "const v8::StartupData Snapshot::SnapshotBlob() {\n");
+    fprintf(fp_, "  v8::StartupData blob;\n");
+    fprintf(fp_, "  blob.data = reinterpret_cast<const char*>(blob_data);\n");
+    fprintf(fp_, "  blob.raw_size = blob_size;\n");
+    fprintf(fp_, "  return blob;\n");
+    fprintf(fp_, "}\n\n");
     fprintf(fp_, "}  // namespace internal\n");
     fprintf(fp_, "}  // namespace v8\n");
   }
 
-  void WriteData(const char* prefix, const i::List<i::byte>& source_data,
-                 FILE* raw_file) const {
-    const i::List<i::byte>* data_to_be_written = NULL;
-    i::List<i::byte> compressed_data;
-    if (!compressor_) {
-      data_to_be_written = &source_data;
-    } else if (compressor_->Compress(source_data.ToVector())) {
-      compressed_data.AddAll(*compressor_->output());
-      data_to_be_written = &compressed_data;
-    } else {
-      i::PrintF("Compression failed. Aborting.\n");
-      exit(1);
-    }
-
-    DCHECK(data_to_be_written);
-    MaybeWriteRawFile(data_to_be_written, raw_file);
-    WriteData(prefix, source_data, data_to_be_written);
-  }
-
-  void MaybeWriteRawFile(const i::List<i::byte>* data, FILE* raw_file) const {
-    if (!data || !raw_file)
-      return;
-
-    // Sanity check, whether i::List iterators truly return pointers to an
-    // internal array.
-    DCHECK(data->end() - data->begin() == data->length());
-
-    size_t written = fwrite(data->begin(), 1, data->length(), raw_file);
-    if (written != (size_t)data->length()) {
-      i::PrintF("Writing raw file failed.. Aborting.\n");
-      exit(1);
-    }
-  }
-
-  void WriteData(const char* prefix, const i::List<i::byte>& source_data,
-                 const i::List<i::byte>* data_to_be_written) const {
-    fprintf(fp_, "const byte Snapshot::%sdata_[] = {\n", prefix);
-    WriteSnapshotData(data_to_be_written);
+  void WriteData(const i::Vector<const i::byte>& blob) const {
+    fprintf(fp_, "static const byte blob_data[] = {\n");
+    WriteSnapshotData(blob);
     fprintf(fp_, "};\n");
-    fprintf(fp_, "const int Snapshot::%ssize_ = %d;\n", prefix,
-            data_to_be_written->length());
-
-    if (data_to_be_written == &source_data) {
-      fprintf(fp_, "const byte* Snapshot::%sraw_data_ = Snapshot::%sdata_;\n",
-              prefix, prefix);
-      fprintf(fp_, "const int Snapshot::%sraw_size_ = Snapshot::%ssize_;\n",
-              prefix, prefix);
-    } else {
-      fprintf(fp_, "const byte* Snapshot::%sraw_data_ = NULL;\n", prefix);
-      fprintf(fp_, "const int Snapshot::%sraw_size_ = %d;\n",
-              prefix, source_data.length());
-    }
+    fprintf(fp_, "static const int blob_size = %d;\n", blob.length());
     fprintf(fp_, "\n");
   }
 
-  void WriteMeta(const char* prefix, const i::Serializer& ser) const {
-    WriteSizeVar(ser, prefix, "new", i::NEW_SPACE);
-    WriteSizeVar(ser, prefix, "pointer", i::OLD_POINTER_SPACE);
-    WriteSizeVar(ser, prefix, "data", i::OLD_DATA_SPACE);
-    WriteSizeVar(ser, prefix, "code", i::CODE_SPACE);
-    WriteSizeVar(ser, prefix, "map", i::MAP_SPACE);
-    WriteSizeVar(ser, prefix, "cell", i::CELL_SPACE);
-    WriteSizeVar(ser, prefix, "property_cell", i::PROPERTY_CELL_SPACE);
-    fprintf(fp_, "\n");
-  }
-
-  void WriteSizeVar(const i::Serializer& ser, const char* prefix,
-                    const char* name, int space) const {
-    fprintf(fp_, "const int Snapshot::%s%s_space_used_ = %d;\n",
-            prefix, name, ser.CurrentAllocationAddress(space));
-  }
-
-  void WriteSnapshotData(const i::List<i::byte>* data) const {
-    for (int i = 0; i < data->length(); i++) {
-      if ((i & 0x1f) == 0x1f)
-        fprintf(fp_, "\n");
-      if (i > 0)
-        fprintf(fp_, ",");
-      fprintf(fp_, "%u", static_cast<unsigned char>(data->at(i)));
+  void WriteSnapshotData(const i::Vector<const i::byte>& blob) const {
+    for (int i = 0; i < blob.length(); i++) {
+      if ((i & 0x1f) == 0x1f) fprintf(fp_, "\n");
+      if (i > 0) fprintf(fp_, ",");
+      fprintf(fp_, "%u", static_cast<unsigned char>(blob.at(i)));
     }
     fprintf(fp_, "\n");
   }
@@ -227,85 +107,20 @@
   }
 
   FILE* fp_;
-  FILE* raw_file_;
-  FILE* raw_context_file_;
   FILE* startup_blob_file_;
-  Compressor* compressor_;
 };
 
 
-#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 i::Vector<char>* output() { return output_; }
-
- private:
-  i::ScopedVector<char>* output_;
-};
-
-
-class BZip2Decompressor : public StartupDataDecompressor {
- public:
-  virtual ~BZip2Decompressor() { }
-
- protected:
-  virtual int DecompressData(char* raw_data,
-                             int* raw_data_size,
-                             const char* compressed_data,
-                             int compressed_data_size) {
-    DCHECK_EQ(StartupData::kBZip2,
-              V8::GetCompressedStartupDataAlgorithm());
-    unsigned int decompressed_size = *raw_data_size;
-    int result =
-        BZ2_bzBuffToBuffDecompress(raw_data,
-                                   &decompressed_size,
-                                   const_cast<char*>(compressed_data),
-                                   compressed_data_size,
-                                   0, 1);
-    if (result == BZ_OK) {
-      *raw_data_size = decompressed_size;
-    }
-    return result;
-  }
-};
-#endif
-
-
-void DumpException(Handle<Message> message) {
-  String::Utf8Value message_string(message->Get());
-  String::Utf8Value message_line(message->GetSourceLine());
-  fprintf(stderr, "%s at line %d\n", *message_string, message->GetLineNumber());
-  fprintf(stderr, "%s\n", *message_line);
-  for (int i = 0; i <= message->GetEndColumn(); ++i) {
-    fprintf(stderr, "%c", i < message->GetStartColumn() ? ' ' : '^');
-  }
-  fprintf(stderr, "\n");
-}
-
-
 int main(int argc, char** argv) {
   // By default, log code create information in the snapshot.
   i::FLAG_log_code = true;
 
+  // Omit from the snapshot natives for features that can be turned off
+  // at runtime.
+  i::FLAG_harmony_shipping = false;
+
+  i::FLAG_logfile_per_isolate = false;
+
   // Print the usage if an error occurs when parsing the command line
   // flags or if the help flag is set.
   int result = i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
@@ -321,116 +136,15 @@
   v8::V8::InitializePlatform(platform);
   v8::V8::Initialize();
 
-#ifdef COMPRESS_STARTUP_DATA_BZ2
-  BZip2Decompressor natives_decompressor;
-  int bz2_result = natives_decompressor.Decompress();
-  if (bz2_result != BZ_OK) {
-    fprintf(stderr, "bzip error code: %d\n", bz2_result);
-    exit(1);
-  }
-#endif
-  i::FLAG_logfile_per_isolate = false;
-
-  Isolate::CreateParams params;
-  params.enable_serializer = true;
-  Isolate* isolate = v8::Isolate::New(params);
-  { Isolate::Scope isolate_scope(isolate);
-    i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
-
-    Persistent<Context> context;
-    {
-      HandleScope handle_scope(isolate);
-      context.Reset(isolate, Context::New(isolate));
-    }
-
-    if (context.IsEmpty()) {
-      fprintf(stderr,
-              "\nException thrown while compiling natives - see above.\n\n");
-      exit(1);
-    }
-    if (i::FLAG_extra_code != NULL) {
-      // Capture 100 frames if anything happens.
-      V8::SetCaptureStackTraceForUncaughtExceptions(true, 100);
-      HandleScope scope(isolate);
-      v8::Context::Scope cscope(v8::Local<v8::Context>::New(isolate, context));
-      const char* name = i::FLAG_extra_code;
-      FILE* file = base::OS::FOpen(name, "rb");
-      if (file == NULL) {
-        fprintf(stderr, "Failed to open '%s': errno %d\n", name, errno);
-        exit(1);
-      }
-
-      fseek(file, 0, SEEK_END);
-      int size = ftell(file);
-      rewind(file);
-
-      char* chars = new char[size + 1];
-      chars[size] = '\0';
-      for (int i = 0; i < size;) {
-        int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
-        if (read < 0) {
-          fprintf(stderr, "Failed to read '%s': errno %d\n", name, errno);
-          exit(1);
-        }
-        i += read;
-      }
-      fclose(file);
-      Local<String> source = String::NewFromUtf8(isolate, chars);
-      TryCatch try_catch;
-      Local<Script> script = Script::Compile(source);
-      if (try_catch.HasCaught()) {
-        fprintf(stderr, "Failure compiling '%s'\n", name);
-        DumpException(try_catch.Message());
-        exit(1);
-      }
-      script->Run();
-      if (try_catch.HasCaught()) {
-        fprintf(stderr, "Failure running '%s'\n", name);
-        DumpException(try_catch.Message());
-        exit(1);
-      }
-    }
-    // Make sure all builtin scripts are cached.
-    { HandleScope scope(isolate);
-      for (int i = 0; i < i::Natives::GetBuiltinsCount(); i++) {
-        internal_isolate->bootstrapper()->NativesSourceLookup(i);
-      }
-    }
-    // If we don't do this then we end up with a stray root pointing at the
-    // context even after we have disposed of the context.
-    internal_isolate->heap()->CollectAllGarbage(
-        i::Heap::kNoGCFlags, "mksnapshot");
-    i::Object* raw_context = *v8::Utils::OpenPersistent(context);
-    context.Reset();
-
-    // This results in a somewhat smaller snapshot, probably because it gets
-    // rid of some things that are cached between garbage collections.
-    i::List<i::byte> snapshot_data;
-    i::ListSnapshotSink snapshot_sink(&snapshot_data);
-    i::StartupSerializer ser(internal_isolate, &snapshot_sink);
-    ser.SerializeStrongReferences();
-
-    i::List<i::byte> context_data;
-    i::ListSnapshotSink contex_sink(&context_data);
-    i::PartialSerializer context_ser(internal_isolate, &ser, &contex_sink);
-    context_ser.Serialize(&raw_context);
-    ser.SerializeWeakReferences();
-
-    {
-      SnapshotWriter writer(argv[1]);
-      if (i::FLAG_raw_file && i::FLAG_raw_context_file)
-        writer.SetRawFiles(i::FLAG_raw_file, i::FLAG_raw_context_file);
-      if (i::FLAG_startup_blob)
-        writer.SetStartupBlobFile(i::FLAG_startup_blob);
-  #ifdef COMPRESS_STARTUP_DATA_BZ2
-      BZip2Compressor bzip2;
-      writer.SetCompressor(&bzip2);
-  #endif
-      writer.WriteSnapshot(snapshot_data, ser, context_data, context_ser);
-    }
+  {
+    SnapshotWriter writer(argv[1]);
+    if (i::FLAG_startup_blob) writer.SetStartupBlobFile(i::FLAG_startup_blob);
+    StartupData blob = v8::V8::CreateSnapshotDataBlob();
+    CHECK(blob.data);
+    writer.WriteSnapshot(blob);
+    delete[] blob.data;
   }
 
-  isolate->Dispose();
   V8::Dispose();
   V8::ShutdownPlatform();
   delete platform;
diff --git a/src/natives-external.cc b/src/natives-external.cc
index fc66149..e601808 100644
--- a/src/natives-external.cc
+++ b/src/natives-external.cc
@@ -10,6 +10,11 @@
 #include "src/snapshot-source-sink.h"
 #include "src/vector.h"
 
+#ifndef V8_USE_EXTERNAL_STARTUP_DATA
+#error natives-external.cc is used only for the external snapshot build.
+#endif  // V8_USE_EXTERNAL_STARTUP_DATA
+
+
 namespace v8 {
 namespace internal {
 
@@ -23,20 +28,26 @@
  */
 class NativesStore {
  public:
-  ~NativesStore() {}
+  ~NativesStore() {
+    for (int i = 0; i < native_names_.length(); i++) {
+      native_names_[i].Dispose();
+    }
+  }
 
-  int GetBuiltinsCount() { return native_names_.length(); }
+  int GetBuiltinsCount() { return native_ids_.length(); }
   int GetDebuggerCount() { return debugger_count_; }
-  Vector<const char> GetScriptName(int index) { return native_names_[index]; }
-  Vector<const char> GetRawScriptSource(int index) {
+
+  Vector<const char> GetScriptSource(int index) {
     return native_source_[index];
   }
 
-  int GetIndex(const char* name) {
-    for (int i = 0; i < native_names_.length(); ++i) {
-      int native_name_length = native_names_[i].length();
-      if ((static_cast<int>(strlen(name)) == native_name_length) &&
-          (strncmp(name, native_names_[i].start(), native_name_length) == 0)) {
+  Vector<const char> GetScriptName(int index) { return native_names_[index]; }
+
+  int GetIndex(const char* id) {
+    for (int i = 0; i < native_ids_.length(); ++i) {
+      int native_id_length = native_ids_[i].length();
+      if ((static_cast<int>(strlen(id)) == native_id_length) &&
+          (strncmp(id, native_ids_[i].start(), native_id_length) == 0)) {
         return i;
       }
     }
@@ -44,14 +55,9 @@
     return -1;
   }
 
-  int GetRawScriptsSize() {
-    DCHECK(false);  // Used for compression. Doesn't really make sense here.
-    return 0;
-  }
-
-  Vector<const byte> GetScriptsSource() {
-    DCHECK(false);  // Used for compression. Doesn't really make sense here.
-    return Vector<const byte>();
+  Vector<const char> GetScriptsSource() {
+    DCHECK(false);  // Not implemented.
+    return Vector<const char>();
   }
 
   static NativesStore* MakeFromScriptsSource(SnapshotByteSource* source) {
@@ -75,24 +81,38 @@
  private:
   NativesStore() : debugger_count_(0) {}
 
+  Vector<const char> NameFromId(const byte* id, int id_length) {
+    const char native[] = "native ";
+    const char extension[] = ".js";
+    Vector<char> name(Vector<char>::New(id_length + sizeof(native) - 1 +
+                                        sizeof(extension) - 1));
+    memcpy(name.start(), native, sizeof(native) - 1);
+    memcpy(name.start() + sizeof(native) - 1, id, id_length);
+    memcpy(name.start() + sizeof(native) - 1 + id_length, extension,
+           sizeof(extension) - 1);
+    return Vector<const char>::cast(name);
+  }
+
   bool ReadNameAndContentPair(SnapshotByteSource* bytes) {
-    const byte* name;
-    int name_length;
+    const byte* id;
+    int id_length;
     const byte* source;
     int source_length;
-    bool success = bytes->GetBlob(&name, &name_length) &&
+    bool success = bytes->GetBlob(&id, &id_length) &&
                    bytes->GetBlob(&source, &source_length);
     if (success) {
-      Vector<const char> name_vector(
-          reinterpret_cast<const char*>(name), name_length);
+      Vector<const char> id_vector(reinterpret_cast<const char*>(id),
+                                   id_length);
       Vector<const char> source_vector(
           reinterpret_cast<const char*>(source), source_length);
-      native_names_.Add(name_vector);
+      native_ids_.Add(id_vector);
       native_source_.Add(source_vector);
+      native_names_.Add(NameFromId(id, id_length));
     }
     return success;
   }
 
+  List<Vector<const char> > native_ids_;
   List<Vector<const char> > native_names_;
   List<Vector<const char> > native_source_;
   int debugger_count_;
@@ -130,9 +150,7 @@
   DCHECK(natives_blob->data);
   DCHECK(natives_blob->raw_size > 0);
 
-  SnapshotByteSource bytes(
-      reinterpret_cast<const byte*>(natives_blob->data),
-      natives_blob->raw_size);
+  SnapshotByteSource bytes(natives_blob->data, natives_blob->raw_size);
   NativesHolder<CORE>::set(NativesStore::MakeFromScriptsSource(&bytes));
   NativesHolder<EXPERIMENTAL>::set(NativesStore::MakeFromScriptsSource(&bytes));
   DCHECK(!bytes.HasMore());
@@ -160,14 +178,9 @@
   return NativesHolder<type>::get()->GetIndex(name);
 }
 
-template<NativeType type>
-int NativesCollection<type>::GetRawScriptsSize() {
-  return NativesHolder<type>::get()->GetRawScriptsSize();
-}
-
-template<NativeType type>
-Vector<const char> NativesCollection<type>::GetRawScriptSource(int index) {
-  return NativesHolder<type>::get()->GetRawScriptSource(index);
+template <NativeType type>
+Vector<const char> NativesCollection<type>::GetScriptSource(int index) {
+  return NativesHolder<type>::get()->GetScriptSource(index);
 }
 
 template<NativeType type>
@@ -175,24 +188,16 @@
   return NativesHolder<type>::get()->GetScriptName(index);
 }
 
-template<NativeType type>
-Vector<const byte> NativesCollection<type>::GetScriptsSource() {
+template <NativeType type>
+Vector<const char> NativesCollection<type>::GetScriptsSource() {
   return NativesHolder<type>::get()->GetScriptsSource();
 }
 
-template<NativeType type>
-void NativesCollection<type>::SetRawScriptsSource(
-    Vector<const char> raw_source) {
-  CHECK(false);  // Use SetNativesFromFile for this implementation.
-}
-
 
 // The compiler can't 'see' all uses of the static methods and hence
-// my chose to elide them. This we'll explicitly instantiate these.
+// my choice to elide them. This we'll explicitly instantiate these.
 template class NativesCollection<CORE>;
 template class NativesCollection<EXPERIMENTAL>;
-template class NativesCollection<D8>;
-template class NativesCollection<TEST>;
 
 }  // namespace v8::internal
 }  // namespace v8
diff --git a/src/natives.h b/src/natives.h
index 6ddedf0..7ce7213 100644
--- a/src/natives.h
+++ b/src/natives.h
@@ -12,10 +12,6 @@
 namespace v8 {
 namespace internal {
 
-typedef bool (*NativeSourceCallback)(Vector<const char> name,
-                                     Vector<const char> source,
-                                     int index);
-
 enum NativeType {
   CORE, EXPERIMENTAL, D8, TEST
 };
@@ -33,11 +29,9 @@
   // non-debugger scripts have an index in the interval [GetDebuggerCount(),
   // GetNativesCount()).
   static int GetIndex(const char* name);
-  static int GetRawScriptsSize();
-  static Vector<const char> GetRawScriptSource(int index);
+  static Vector<const char> GetScriptSource(int index);
   static Vector<const char> GetScriptName(int index);
-  static Vector<const byte> GetScriptsSource();
-  static void SetRawScriptsSource(Vector<const char> raw_source);
+  static Vector<const char> GetScriptsSource();
 };
 
 typedef NativesCollection<CORE> Natives;
diff --git a/src/object-observe.js b/src/object-observe.js
index 76f3915..01ce805 100644
--- a/src/object-observe.js
+++ b/src/object-observe.js
@@ -35,10 +35,15 @@
 
 var observationState;
 
+// We have to wait until after bootstrapping to grab a reference to the
+// observationState object, since it's not possible to serialize that
+// reference into the snapshot.
 function GetObservationStateJS() {
-  if (IS_UNDEFINED(observationState))
+  if (IS_UNDEFINED(observationState)) {
     observationState = %GetObservationState();
+  }
 
+  // TODO(adamk): Consider moving this code into heap.cc
   if (IS_UNDEFINED(observationState.callbackInfoMap)) {
     observationState.callbackInfoMap = %ObservationWeakMapCreate();
     observationState.objectInfoMap = %ObservationWeakMapCreate();
@@ -51,55 +56,6 @@
   return observationState;
 }
 
-function GetWeakMapWrapper() {
-  function MapWrapper(map) {
-    this.map_ = map;
-  };
-
-  MapWrapper.prototype = {
-    __proto__: null,
-    get: function(key) {
-      return %WeakCollectionGet(this.map_, key);
-    },
-    set: function(key, value) {
-      %WeakCollectionSet(this.map_, key, value);
-    },
-    has: function(key) {
-      return !IS_UNDEFINED(this.get(key));
-    }
-  };
-
-  return MapWrapper;
-}
-
-var contextMaps;
-
-function GetContextMaps() {
-  if (IS_UNDEFINED(contextMaps)) {
-    var map = GetWeakMapWrapper();
-    var observationState = GetObservationStateJS();
-    contextMaps = {
-      callbackInfoMap: new map(observationState.callbackInfoMap),
-      objectInfoMap: new map(observationState.objectInfoMap),
-      notifierObjectInfoMap: new map(observationState.notifierObjectInfoMap)
-    };
-  }
-
-  return contextMaps;
-}
-
-function GetCallbackInfoMap() {
-  return GetContextMaps().callbackInfoMap;
-}
-
-function GetObjectInfoMap() {
-  return GetContextMaps().objectInfoMap;
-}
-
-function GetNotifierObjectInfoMap() {
-  return GetContextMaps().notifierObjectInfoMap;
-}
-
 function GetPendingObservers() {
   return GetObservationStateJS().pendingObservers;
 }
@@ -194,9 +150,9 @@
 function ObjectInfoGetOrCreate(object) {
   var objectInfo = ObjectInfoGet(object);
   if (IS_UNDEFINED(objectInfo)) {
-    if (!%IsJSProxy(object))
+    if (!%_IsJSProxy(object)) {
       %SetIsObserved(object);
-
+    }
     objectInfo = {
       object: object,
       changeObservers: null,
@@ -204,35 +160,34 @@
       performing: null,
       performingCount: 0,
     };
-    GetObjectInfoMap().set(object, objectInfo);
+    %WeakCollectionSet(GetObservationStateJS().objectInfoMap,
+                       object, objectInfo);
   }
   return objectInfo;
 }
 
 function ObjectInfoGet(object) {
-  return GetObjectInfoMap().get(object);
+  return %WeakCollectionGet(GetObservationStateJS().objectInfoMap, object);
 }
 
 function ObjectInfoGetFromNotifier(notifier) {
-  return GetNotifierObjectInfoMap().get(notifier);
+  return %WeakCollectionGet(GetObservationStateJS().notifierObjectInfoMap,
+                            notifier);
 }
 
 function ObjectInfoGetNotifier(objectInfo) {
   if (IS_NULL(objectInfo.notifier)) {
     objectInfo.notifier = { __proto__: notifierPrototype };
-    GetNotifierObjectInfoMap().set(objectInfo.notifier, objectInfo);
+    %WeakCollectionSet(GetObservationStateJS().notifierObjectInfoMap,
+                       objectInfo.notifier, objectInfo);
   }
 
   return objectInfo.notifier;
 }
 
-function ObjectInfoGetObject(objectInfo) {
-  return objectInfo.object;
-}
-
 function ChangeObserversIsOptimized(changeObservers) {
-  return typeof changeObservers === 'function' ||
-         typeof changeObservers.callback === 'function';
+  return IS_SPEC_FUNCTION(changeObservers) ||
+         IS_SPEC_FUNCTION(changeObservers.callback);
 }
 
 // The set of observers on an object is called 'changeObservers'. The first
@@ -328,16 +283,21 @@
 // priority. When a change record must be enqueued for the callback, it
 // normalizes. When delivery clears any pending change records, it re-optimizes.
 function CallbackInfoGet(callback) {
-  return GetCallbackInfoMap().get(callback);
+  return %WeakCollectionGet(GetObservationStateJS().callbackInfoMap, callback);
+}
+
+function CallbackInfoSet(callback, callbackInfo) {
+  %WeakCollectionSet(GetObservationStateJS().callbackInfoMap,
+                     callback, callbackInfo);
 }
 
 function CallbackInfoGetOrCreate(callback) {
-  var callbackInfo = GetCallbackInfoMap().get(callback);
+  var callbackInfo = CallbackInfoGet(callback);
   if (!IS_UNDEFINED(callbackInfo))
     return callbackInfo;
 
-  var priority =  GetNextCallbackPriority();
-  GetCallbackInfoMap().set(callback, priority);
+  var priority = GetNextCallbackPriority();
+  CallbackInfoSet(callback, priority);
   return priority;
 }
 
@@ -349,12 +309,12 @@
 }
 
 function CallbackInfoNormalize(callback) {
-  var callbackInfo = GetCallbackInfoMap().get(callback);
+  var callbackInfo = CallbackInfoGet(callback);
   if (IS_NUMBER(callbackInfo)) {
     var priority = callbackInfo;
     callbackInfo = new InternalArray;
     callbackInfo.priority = priority;
-    GetCallbackInfoMap().set(callback, callbackInfo);
+    CallbackInfoSet(callback, callbackInfo);
   }
   return callbackInfo;
 }
@@ -445,8 +405,8 @@
 
   var hasType = !IS_UNDEFINED(type);
   var newRecord = hasType ?
-      { object: ObjectInfoGetObject(objectInfo), type: type } :
-      { object: ObjectInfoGetObject(objectInfo) };
+      { object: objectInfo.object, type: type } :
+      { object: objectInfo.object };
 
   for (var prop in changeRecord) {
     if (prop === 'object' || (hasType && prop === 'type')) continue;
@@ -594,24 +554,24 @@
 }
 
 function CallbackDeliverPending(callback) {
-  var callbackInfo = GetCallbackInfoMap().get(callback);
+  var callbackInfo = CallbackInfoGet(callback);
   if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo))
     return false;
 
   // Clear the pending change records from callback and return it to its
   // "optimized" state.
   var priority = callbackInfo.priority;
-  GetCallbackInfoMap().set(callback, priority);
+  CallbackInfoSet(callback, priority);
 
-  if (GetPendingObservers())
-    delete GetPendingObservers()[priority];
+  var pendingObservers = GetPendingObservers();
+  if (!IS_NULL(pendingObservers))
+    delete pendingObservers[priority];
 
+  // TODO: combine the following runtime calls for perf optimization.
   var delivered = [];
   %MoveArrayContents(callbackInfo, delivered);
+  %DeliverObservationChangeRecords(callback, delivered);
 
-  try {
-    %_CallFunction(UNDEFINED, delivered, callback);
-  } catch (ex) {}  // TODO(rossberg): perhaps log uncaught exceptions.
   return true;
 }
 
@@ -624,7 +584,7 @@
 
 function ObserveMicrotaskRunner() {
   var pendingObservers = GetPendingObservers();
-  if (pendingObservers) {
+  if (!IS_NULL(pendingObservers)) {
     SetPendingObservers(null);
     for (var i in pendingObservers) {
       CallbackDeliverPending(pendingObservers[i]);
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index a2395de..e990559 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -47,6 +47,10 @@
     return;
   }
 
+  // TODO(yangguo): Use this check once crbug/436911 has been fixed.
+  //  DCHECK(!NeedsToEnsureDoubleAlignment() ||
+  //         IsAligned(OffsetFrom(address()), kDoubleAlignment));
+
   switch (instance_type) {
     case SYMBOL_TYPE:
       Symbol::cast(this)->SymbolVerify();
@@ -125,6 +129,9 @@
     case PROPERTY_CELL_TYPE:
       PropertyCell::cast(this)->PropertyCellVerify();
       break;
+    case WEAK_CELL_TYPE:
+      WeakCell::cast(this)->WeakCellVerify();
+      break;
     case JS_ARRAY_TYPE:
       JSArray::cast(this)->JSArrayVerify();
       break;
@@ -256,14 +263,26 @@
   }
 
   if (HasFastProperties()) {
-    CHECK_EQ(map()->unused_property_fields(),
-             (map()->inobject_properties() + properties()->length() -
-              map()->NextFreePropertyIndex()));
+    int actual_unused_property_fields = map()->inobject_properties() +
+                                        properties()->length() -
+                                        map()->NextFreePropertyIndex();
+    if (map()->unused_property_fields() != actual_unused_property_fields) {
+      // This could actually happen in the middle of StoreTransitionStub
+      // when the new extended backing store is already set into the object and
+      // the allocation of the MutableHeapNumber triggers GC (in this case map
+      // is not updated yet).
+      CHECK_EQ(map()->unused_property_fields(),
+               actual_unused_property_fields - JSObject::kFieldsAdded);
+    }
     DescriptorArray* descriptors = map()->instance_descriptors();
     for (int i = 0; i < map()->NumberOfOwnDescriptors(); i++) {
       if (descriptors->GetDetails(i).type() == FIELD) {
         Representation r = descriptors->GetDetails(i).representation();
         FieldIndex index = FieldIndex::ForDescriptor(map(), i);
+        if (IsUnboxedDoubleField(index)) {
+          DCHECK(r.IsDouble());
+          continue;
+        }
         Object* value = RawFastPropertyAt(index);
         if (r.IsDouble()) DCHECK(value->IsMutableHeapNumber());
         if (value->IsUninitialized()) continue;
@@ -305,6 +324,8 @@
     SLOW_DCHECK(transitions()->IsSortedNoDuplicates());
     SLOW_DCHECK(transitions()->IsConsistentWithBackPointers(this));
   }
+  SLOW_DCHECK(!FLAG_unbox_double_fields ||
+              layout_descriptor()->IsConsistentWithMap(this));
 }
 
 
@@ -314,8 +335,7 @@
   CHECK(instance_descriptors()->IsEmpty());
   CHECK_EQ(0, pre_allocated_property_fields());
   CHECK_EQ(0, unused_property_fields());
-  CHECK_EQ(StaticVisitorBase::GetVisitorId(instance_type(), instance_size()),
-      visitor_id());
+  CHECK_EQ(StaticVisitorBase::GetVisitorId(this), visitor_id());
 }
 
 
@@ -547,7 +567,7 @@
   VerifyObjectField(JSGlobalProxy::kNativeContextOffset);
   // Make sure that this object has no properties, elements.
   CHECK_EQ(0, properties()->length());
-  CHECK(HasFastSmiElements());
+  CHECK_EQ(FAST_HOLEY_SMI_ELEMENTS, GetElementsKind());
   CHECK_EQ(0, FixedArray::cast(elements())->length());
 }
 
@@ -627,6 +647,13 @@
 }
 
 
+void WeakCell::WeakCellVerify() {
+  CHECK(IsWeakCell());
+  VerifyObjectField(kValueOffset);
+  VerifyObjectField(kNextOffset);
+}
+
+
 void Code::CodeVerify() {
   CHECK(IsAligned(reinterpret_cast<intptr_t>(instruction_start()),
                   kCodeAlignment));
@@ -657,9 +684,8 @@
     if (IsWeakObject(obj)) {
       if (obj->IsMap()) {
         Map* map = Map::cast(obj);
-        DependentCode::DependencyGroup group = is_optimized_code() ?
-            DependentCode::kWeakCodeGroup : DependentCode::kWeakICGroup;
-        CHECK(map->dependent_code()->Contains(group, this));
+        CHECK(map->dependent_code()->Contains(DependentCode::kWeakCodeGroup,
+                                              this));
       } else if (obj->IsJSObject()) {
         Object* raw_table = GetIsolate()->heap()->weak_object_to_code_table();
         WeakHashTable* table = WeakHashTable::cast(raw_table);
@@ -904,6 +930,7 @@
   VerifyPointer(deleter());
   VerifyPointer(enumerator());
   VerifyPointer(data());
+  VerifySmiField(kFlagsOffset);
 }
 
 
@@ -1146,15 +1173,13 @@
   for (int i = 0; i < number_of_descriptors(); i++) {
     Name* key = GetSortedKey(i);
     if (key == current_key) {
-      OFStream os(stdout);
-      PrintDescriptors(os);
+      Print();
       return false;
     }
     current_key = key;
     uint32_t hash = GetSortedKey(i)->Hash();
     if (hash < current) {
-      OFStream os(stdout);
-      PrintDescriptors(os);
+      Print();
       return false;
     }
     current = hash;
@@ -1163,25 +1188,58 @@
 }
 
 
+bool LayoutDescriptor::IsConsistentWithMap(Map* map) {
+  if (FLAG_unbox_double_fields) {
+    DescriptorArray* descriptors = map->instance_descriptors();
+    int nof_descriptors = map->NumberOfOwnDescriptors();
+    for (int i = 0; i < nof_descriptors; i++) {
+      PropertyDetails details = descriptors->GetDetails(i);
+      if (details.type() != FIELD) continue;
+      FieldIndex field_index = FieldIndex::ForDescriptor(map, i);
+      bool tagged_expected =
+          !field_index.is_inobject() || !details.representation().IsDouble();
+      for (int bit = 0; bit < details.field_width_in_words(); bit++) {
+        bool tagged_actual = IsTagged(details.field_index() + bit);
+        DCHECK_EQ(tagged_expected, tagged_actual);
+        if (tagged_actual != tagged_expected) return false;
+      }
+    }
+  }
+  return true;
+}
+
+
 bool TransitionArray::IsSortedNoDuplicates(int valid_entries) {
   DCHECK(valid_entries == -1);
-  Name* current_key = NULL;
-  uint32_t current = 0;
+  Name* prev_key = NULL;
+  PropertyKind prev_kind = DATA;
+  PropertyAttributes prev_attributes = NONE;
+  uint32_t prev_hash = 0;
   for (int i = 0; i < number_of_transitions(); i++) {
     Name* key = GetSortedKey(i);
-    if (key == current_key) {
-      OFStream os(stdout);
-      PrintTransitions(os);
+    uint32_t hash = key->Hash();
+    PropertyKind kind = DATA;
+    PropertyAttributes attributes = NONE;
+    if (!IsSpecialTransition(key)) {
+      Map* target = GetTarget(i);
+      PropertyDetails details = GetTargetDetails(key, target);
+      kind = details.kind();
+      attributes = details.attributes();
+    } else {
+      // Duplicate entries are not allowed for non-property transitions.
+      CHECK_NE(prev_key, key);
+    }
+
+    int cmp = CompareKeys(prev_key, prev_hash, prev_kind, prev_attributes, key,
+                          hash, kind, attributes);
+    if (cmp >= 0) {
+      Print();
       return false;
     }
-    current_key = key;
-    uint32_t hash = GetSortedKey(i)->Hash();
-    if (hash < current) {
-      OFStream os(stdout);
-      PrintTransitions(os);
-      return false;
-    }
-    current = hash;
+    prev_key = key;
+    prev_hash = hash;
+    prev_attributes = attributes;
+    prev_kind = kind;
   }
   return true;
 }
@@ -1200,6 +1258,24 @@
 }
 
 
+void Code::VerifyEmbeddedObjectsInFullCode() {
+  // Check that no context-specific object has been embedded.
+  Heap* heap = GetIsolate()->heap();
+  int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+  for (RelocIterator it(this, mask); !it.done(); it.next()) {
+    Object* obj = it.rinfo()->target_object();
+    if (obj->IsCell()) obj = Cell::cast(obj)->value();
+    if (obj->IsPropertyCell()) obj = PropertyCell::cast(obj)->value();
+    if (!obj->IsHeapObject()) continue;
+    Map* map = obj->IsMap() ? Map::cast(obj) : HeapObject::cast(obj)->map();
+    int i = 0;
+    while (map != heap->roots_array_start()[i++]) {
+      CHECK_LT(i, Heap::kStrongRootListLength);
+    }
+  }
+}
+
+
 #endif  // DEBUG
 
 } }  // namespace v8::internal
diff --git a/src/objects-inl.h b/src/objects-inl.h
index e46dd8e..fdfadb1 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -26,6 +26,7 @@
 #include "src/heap/spaces.h"
 #include "src/heap/store-buffer.h"
 #include "src/isolate.h"
+#include "src/layout-descriptor-inl.h"
 #include "src/lookup.h"
 #include "src/objects.h"
 #include "src/property.h"
@@ -56,6 +57,14 @@
 }
 
 
+int PropertyDetails::field_width_in_words() const {
+  DCHECK(type() == FIELD);
+  if (!FLAG_unbox_double_fields) return 1;
+  if (kDoubleSize == kPointerSize) return 1;
+  return representation().IsDouble() ? kDoubleSize / kPointerSize : 1;
+}
+
+
 #define TYPE_CHECKER(type, instancetype)                                \
   bool Object::Is##type() const {                                       \
   return Object::IsHeapObject() &&                                      \
@@ -464,12 +473,24 @@
 
 STATIC_ASSERT(v8::String::TWO_BYTE_ENCODING == kTwoByteStringTag);
 
+
 uc32 FlatStringReader::Get(int index) {
-  DCHECK(0 <= index && index <= length_);
   if (is_one_byte_) {
-    return static_cast<const byte*>(start_)[index];
+    return Get<uint8_t>(index);
   } else {
-    return static_cast<const uc16*>(start_)[index];
+    return Get<uc16>(index);
+  }
+}
+
+
+template <typename Char>
+Char FlatStringReader::Get(int index) {
+  DCHECK_EQ(is_one_byte_, sizeof(Char) == 1);
+  DCHECK(0 <= index && index <= length_);
+  if (sizeof(Char) == 1) {
+    return static_cast<Char>(static_cast<const uint8_t*>(start_)[index]);
+  } else {
+    return static_cast<Char>(static_cast<const uc16*>(start_)[index]);
   }
 }
 
@@ -479,11 +500,6 @@
 }
 
 
-Handle<Object> MapCacheShape::AsHandle(Isolate* isolate, HashTableKey* key) {
-  return key->AsHandle(isolate);
-}
-
-
 Handle<Object> CompilationCacheShape::AsHandle(Isolate* isolate,
                                                HashTableKey* key) {
   return key->AsHandle(isolate);
@@ -501,7 +517,7 @@
   explicit SequentialStringKey(Vector<const Char> string, uint32_t seed)
       : string_(string), hash_field_(0), seed_(seed) { }
 
-  virtual uint32_t Hash() OVERRIDE {
+  uint32_t Hash() OVERRIDE {
     hash_field_ = StringHasher::HashSequentialString<Char>(string_.start(),
                                                            string_.length(),
                                                            seed_);
@@ -512,7 +528,7 @@
   }
 
 
-  virtual uint32_t HashForObject(Object* other) OVERRIDE {
+  uint32_t HashForObject(Object* other) OVERRIDE {
     return String::cast(other)->Hash();
   }
 
@@ -527,11 +543,11 @@
   OneByteStringKey(Vector<const uint8_t> str, uint32_t seed)
       : SequentialStringKey<uint8_t>(str, seed) { }
 
-  virtual bool IsMatch(Object* string) OVERRIDE {
+  bool IsMatch(Object* string) OVERRIDE {
     return String::cast(string)->IsOneByteEqualTo(string_);
   }
 
-  virtual Handle<Object> AsHandle(Isolate* isolate) OVERRIDE;
+  Handle<Object> AsHandle(Isolate* isolate) OVERRIDE;
 };
 
 
@@ -542,7 +558,7 @@
     DCHECK(string_->IsSeqOneByteString());
   }
 
-  virtual uint32_t Hash() OVERRIDE {
+  uint32_t Hash() OVERRIDE {
     DCHECK(length_ >= 0);
     DCHECK(from_ + length_ <= string_->length());
     const uint8_t* chars = string_->GetChars() + from_;
@@ -553,12 +569,12 @@
     return result;
   }
 
-  virtual uint32_t HashForObject(Object* other) OVERRIDE {
+  uint32_t HashForObject(Object* other) OVERRIDE {
     return String::cast(other)->Hash();
   }
 
-  virtual bool IsMatch(Object* string) OVERRIDE;
-  virtual Handle<Object> AsHandle(Isolate* isolate) OVERRIDE;
+  bool IsMatch(Object* string) OVERRIDE;
+  Handle<Object> AsHandle(Isolate* isolate) OVERRIDE;
 
  private:
   Handle<SeqOneByteString> string_;
@@ -573,11 +589,11 @@
   explicit TwoByteStringKey(Vector<const uc16> str, uint32_t seed)
       : SequentialStringKey<uc16>(str, seed) { }
 
-  virtual bool IsMatch(Object* string) OVERRIDE {
+  bool IsMatch(Object* string) OVERRIDE {
     return String::cast(string)->IsTwoByteEqualTo(string_);
   }
 
-  virtual Handle<Object> AsHandle(Isolate* isolate) OVERRIDE;
+  Handle<Object> AsHandle(Isolate* isolate) OVERRIDE;
 };
 
 
@@ -587,11 +603,11 @@
   explicit Utf8StringKey(Vector<const char> string, uint32_t seed)
       : string_(string), hash_field_(0), seed_(seed) { }
 
-  virtual bool IsMatch(Object* string) OVERRIDE {
+  bool IsMatch(Object* string) OVERRIDE {
     return String::cast(string)->IsUtf8EqualTo(string_);
   }
 
-  virtual uint32_t Hash() OVERRIDE {
+  uint32_t Hash() OVERRIDE {
     if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
     hash_field_ = StringHasher::ComputeUtf8Hash(string_, seed_, &chars_);
     uint32_t result = hash_field_ >> String::kHashShift;
@@ -599,11 +615,11 @@
     return result;
   }
 
-  virtual uint32_t HashForObject(Object* other) OVERRIDE {
+  uint32_t HashForObject(Object* other) OVERRIDE {
     return String::cast(other)->Hash();
   }
 
-  virtual Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
+  Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
     if (hash_field_ == 0) Hash();
     return isolate->factory()->NewInternalizedStringFromUtf8(
         string_, chars_, hash_field_);
@@ -691,6 +707,7 @@
 TYPE_CHECKER(Map, MAP_TYPE)
 TYPE_CHECKER(FixedArray, FIXED_ARRAY_TYPE)
 TYPE_CHECKER(FixedDoubleArray, FIXED_DOUBLE_ARRAY_TYPE)
+TYPE_CHECKER(WeakFixedArray, FIXED_ARRAY_TYPE)
 TYPE_CHECKER(ConstantPoolArray, CONSTANT_POOL_ARRAY_TYPE)
 
 
@@ -704,6 +721,11 @@
 }
 
 
+bool Object::IsLayoutDescriptor() const {
+  return IsSmi() || IsFixedTypedArrayBase();
+}
+
+
 bool Object::IsTransitionArray() const {
   return IsFixedArray();
 }
@@ -756,7 +778,7 @@
       map == heap->native_context_map() ||
       map == heap->block_context_map() ||
       map == heap->module_context_map() ||
-      map == heap->global_context_map());
+      map == heap->script_context_map());
 }
 
 
@@ -767,6 +789,14 @@
 }
 
 
+bool Object::IsScriptContextTable() const {
+  if (!Object::IsHeapObject()) return false;
+  Map* map = HeapObject::cast(this)->map();
+  Heap* heap = map->GetHeap();
+  return map == heap->script_context_table_map();
+}
+
+
 bool Object::IsScopeInfo() const {
   return Object::IsHeapObject() &&
       HeapObject::cast(this)->map() ==
@@ -786,6 +816,7 @@
 TYPE_CHECKER(Oddball, ODDBALL_TYPE)
 TYPE_CHECKER(Cell, CELL_TYPE)
 TYPE_CHECKER(PropertyCell, PROPERTY_CELL_TYPE)
+TYPE_CHECKER(WeakCell, WEAK_CELL_TYPE)
 TYPE_CHECKER(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE)
 TYPE_CHECKER(JSGeneratorObject, JS_GENERATOR_OBJECT_TYPE)
 TYPE_CHECKER(JSModule, JS_MODULE_TYPE)
@@ -1121,6 +1152,19 @@
 }
 
 
+Handle<Object> Object::GetPrototypeSkipHiddenPrototypes(
+    Isolate* isolate, Handle<Object> receiver) {
+  PrototypeIterator iter(isolate, receiver);
+  while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
+    if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
+      return PrototypeIterator::GetCurrent(iter);
+    }
+    iter.Advance();
+  }
+  return PrototypeIterator::GetCurrent(iter);
+}
+
+
 MaybeHandle<Object> Object::GetPropertyOrElement(Handle<Object> object,
                                                  Handle<Name> name) {
   uint32_t index;
@@ -1621,21 +1665,6 @@
 }
 
 
-inline DependentCode::DependencyGroup AllocationSite::ToDependencyGroup(
-    Reason reason) {
-  switch (reason) {
-    case TENURING:
-      return DependentCode::kAllocationSiteTenuringChangedGroup;
-      break;
-    case TRANSITIONS:
-      return DependentCode::kAllocationSiteTransitionChangedGroup;
-      break;
-  }
-  UNREACHABLE();
-  return DependentCode::kAllocationSiteTransitionChangedGroup;
-}
-
-
 inline void AllocationSite::set_memento_found_count(int count) {
   int value = pretenure_data()->value();
   // Verify that we can count more mementos than we can possibly find in one
@@ -1870,11 +1899,11 @@
   DisallowHeapAllocation no_allocation;
   if (!map->HasTransitionArray()) return Handle<Map>::null();
   TransitionArray* transitions = map->transitions();
-  int transition = transitions->Search(*key);
+  int transition = transitions->Search(DATA, *key, NONE);
   if (transition == TransitionArray::kNotFound) return Handle<Map>::null();
-  PropertyDetails target_details = transitions->GetTargetDetails(transition);
-  if (target_details.type() != FIELD) return Handle<Map>::null();
-  if (target_details.attributes() != NONE) return Handle<Map>::null();
+  PropertyDetails details = transitions->GetTargetDetails(transition);
+  if (details.type() != FIELD) return Handle<Map>::null();
+  DCHECK_EQ(NONE, details.attributes());
   return Handle<Map>(transitions->GetTarget(transition));
 }
 
@@ -1916,6 +1945,35 @@
 }
 
 
+Object* WeakCell::value() const { return READ_FIELD(this, kValueOffset); }
+
+
+void WeakCell::clear() {
+  DCHECK(GetHeap()->gc_state() == Heap::MARK_COMPACT);
+  WRITE_FIELD(this, kValueOffset, Smi::FromInt(0));
+}
+
+
+void WeakCell::initialize(HeapObject* val) {
+  WRITE_FIELD(this, kValueOffset, val);
+  WRITE_BARRIER(GetHeap(), this, kValueOffset, val);
+}
+
+
+bool WeakCell::cleared() const { return value() == Smi::FromInt(0); }
+
+
+Object* WeakCell::next() const { return READ_FIELD(this, kNextOffset); }
+
+
+void WeakCell::set_next(Object* val, WriteBarrierMode mode) {
+  WRITE_FIELD(this, kNextOffset, val);
+  if (mode == UPDATE_WRITE_BARRIER) {
+    WRITE_BARRIER(GetHeap(), this, kNextOffset, val);
+  }
+}
+
+
 int JSObject::GetHeaderSize() {
   InstanceType type = map()->instance_type();
   // Check for the most common kind of JavaScript object before
@@ -2019,10 +2077,24 @@
 }
 
 
+bool JSObject::IsUnboxedDoubleField(FieldIndex index) {
+  if (!FLAG_unbox_double_fields) return false;
+  return map()->IsUnboxedDoubleField(index);
+}
+
+
+bool Map::IsUnboxedDoubleField(FieldIndex index) {
+  if (!FLAG_unbox_double_fields) return false;
+  if (index.is_hidden_field() || !index.is_inobject()) return false;
+  return !layout_descriptor()->IsTagged(index.property_index());
+}
+
+
 // Access fast-case object properties at index. The use of these routines
 // is needed to correctly distinguish between properties stored in-object and
 // properties stored in the properties array.
 Object* JSObject::RawFastPropertyAt(FieldIndex index) {
+  DCHECK(!IsUnboxedDoubleField(index));
   if (index.is_inobject()) {
     return READ_FIELD(this, index.offset());
   } else {
@@ -2031,7 +2103,13 @@
 }
 
 
-void JSObject::FastPropertyAtPut(FieldIndex index, Object* value) {
+double JSObject::RawFastDoublePropertyAt(FieldIndex index) {
+  DCHECK(IsUnboxedDoubleField(index));
+  return READ_DOUBLE_FIELD(this, index.offset());
+}
+
+
+void JSObject::RawFastPropertyAtPut(FieldIndex index, Object* value) {
   if (index.is_inobject()) {
     int offset = index.offset();
     WRITE_FIELD(this, offset, value);
@@ -2042,6 +2120,21 @@
 }
 
 
+void JSObject::RawFastDoublePropertyAtPut(FieldIndex index, double value) {
+  WRITE_DOUBLE_FIELD(this, index.offset(), value);
+}
+
+
+void JSObject::FastPropertyAtPut(FieldIndex index, Object* value) {
+  if (IsUnboxedDoubleField(index)) {
+    DCHECK(value->IsMutableHeapNumber());
+    RawFastDoublePropertyAtPut(index, HeapNumber::cast(value)->value());
+  } else {
+    RawFastPropertyAtPut(index, value);
+  }
+}
+
+
 int JSObject::GetInObjectPropertyOffset(int index) {
   return map()->GetInObjectPropertyOffset(index);
 }
@@ -2162,7 +2255,7 @@
 }
 
 
-Object* FixedArray::get(int index) {
+Object* FixedArray::get(int index) const {
   SLOW_DCHECK(index >= 0 && index < this->length());
   return READ_FIELD(this, kHeaderSize + index * kPointerSize);
 }
@@ -2276,6 +2369,39 @@
 }
 
 
+Object* WeakFixedArray::Get(int index) const {
+  Object* raw = FixedArray::cast(this)->get(index + kFirstIndex);
+  if (raw->IsSmi()) return raw;
+  return WeakCell::cast(raw)->value();
+}
+
+
+bool WeakFixedArray::IsEmptySlot(int index) const {
+  DCHECK(index < Length());
+  return Get(index)->IsSmi();
+}
+
+
+void WeakFixedArray::clear(int index) {
+  FixedArray::cast(this)->set(index + kFirstIndex, Smi::FromInt(0));
+}
+
+
+int WeakFixedArray::Length() const {
+  return FixedArray::cast(this)->length() - kFirstIndex;
+}
+
+
+int WeakFixedArray::last_used_index() const {
+  return Smi::cast(FixedArray::cast(this)->get(kLastUsedIndexIndex))->value();
+}
+
+
+void WeakFixedArray::set_last_used_index(int index) {
+  FixedArray::cast(this)->set(kLastUsedIndexIndex, Smi::FromInt(index));
+}
+
+
 void ConstantPoolArray::NumberOfEntries::increment(Type type) {
   DCHECK(type < NUMBER_OF_TYPES);
   element_counts_[type]++;
@@ -2622,14 +2748,14 @@
 
   // Initialize the extended layout fields.
   int extended_header_offset = get_extended_section_header_offset();
-  WRITE_INT_FIELD(this, extended_header_offset + kExtendedInt64CountOffset,
-      extended.count_of(INT64));
-  WRITE_INT_FIELD(this, extended_header_offset + kExtendedCodePtrCountOffset,
-      extended.count_of(CODE_PTR));
-  WRITE_INT_FIELD(this, extended_header_offset + kExtendedHeapPtrCountOffset,
-      extended.count_of(HEAP_PTR));
-  WRITE_INT_FIELD(this, extended_header_offset + kExtendedInt32CountOffset,
-      extended.count_of(INT32));
+  WRITE_INT32_FIELD(this, extended_header_offset + kExtendedInt64CountOffset,
+                    extended.count_of(INT64));
+  WRITE_INT32_FIELD(this, extended_header_offset + kExtendedCodePtrCountOffset,
+                    extended.count_of(CODE_PTR));
+  WRITE_INT32_FIELD(this, extended_header_offset + kExtendedHeapPtrCountOffset,
+                    extended.count_of(HEAP_PTR));
+  WRITE_INT32_FIELD(this, extended_header_offset + kExtendedInt32CountOffset,
+                    extended.count_of(INT32));
 }
 
 
@@ -2666,6 +2792,17 @@
 }
 
 
+bool HeapObject::NeedsToEnsureDoubleAlignment() {
+#ifndef V8_HOST_ARCH_64_BIT
+  return (IsFixedFloat64Array() || IsFixedDoubleArray() ||
+          IsConstantPoolArray()) &&
+         FixedArrayBase::cast(this)->length() != 0;
+#else
+  return false;
+#endif  // V8_HOST_ARCH_64_BIT
+}
+
+
 void FixedArray::set(int index,
                      Object* value,
                      WriteBarrierMode mode) {
@@ -2758,8 +2895,10 @@
 // Perform a binary search in a fixed array. Low and high are entry indices. If
 // there are three entries in this array it should be called with low=0 and
 // high=2.
-template<SearchMode search_mode, typename T>
-int BinarySearch(T* array, Name* name, int low, int high, int valid_entries) {
+template <SearchMode search_mode, typename T>
+int BinarySearch(T* array, Name* name, int low, int high, int valid_entries,
+                 int* out_insertion_index) {
+  DCHECK(search_mode == ALL_ENTRIES || out_insertion_index == NULL);
   uint32_t hash = name->Hash();
   int limit = high;
 
@@ -2780,7 +2919,13 @@
   for (; low <= limit; ++low) {
     int sort_index = array->GetSortedKeyIndex(low);
     Name* entry = array->GetKey(sort_index);
-    if (entry->Hash() != hash) break;
+    uint32_t current_hash = entry->Hash();
+    if (current_hash != hash) {
+      if (out_insertion_index != NULL) {
+        *out_insertion_index = sort_index + (current_hash > hash ? 0 : 1);
+      }
+      return T::kNotFound;
+    }
     if (entry->Equals(name)) {
       if (search_mode == ALL_ENTRIES || sort_index < valid_entries) {
         return sort_index;
@@ -2789,37 +2934,45 @@
     }
   }
 
+  if (out_insertion_index != NULL) *out_insertion_index = limit + 1;
   return T::kNotFound;
 }
 
 
 // Perform a linear search in this fixed array. len is the number of entry
 // indices that are valid.
-template<SearchMode search_mode, typename T>
-int LinearSearch(T* array, Name* name, int len, int valid_entries) {
+template <SearchMode search_mode, typename T>
+int LinearSearch(T* array, Name* name, int len, int valid_entries,
+                 int* out_insertion_index) {
   uint32_t hash = name->Hash();
   if (search_mode == ALL_ENTRIES) {
     for (int number = 0; number < len; number++) {
       int sorted_index = array->GetSortedKeyIndex(number);
       Name* entry = array->GetKey(sorted_index);
       uint32_t current_hash = entry->Hash();
-      if (current_hash > hash) break;
+      if (current_hash > hash) {
+        if (out_insertion_index != NULL) *out_insertion_index = sorted_index;
+        return T::kNotFound;
+      }
       if (current_hash == hash && entry->Equals(name)) return sorted_index;
     }
+    if (out_insertion_index != NULL) *out_insertion_index = len;
+    return T::kNotFound;
   } else {
     DCHECK(len >= valid_entries);
+    DCHECK_EQ(NULL, out_insertion_index);  // Not supported here.
     for (int number = 0; number < valid_entries; number++) {
       Name* entry = array->GetKey(number);
       uint32_t current_hash = entry->Hash();
       if (current_hash == hash && entry->Equals(name)) return number;
     }
+    return T::kNotFound;
   }
-  return T::kNotFound;
 }
 
 
-template<SearchMode search_mode, typename T>
-int Search(T* array, Name* name, int valid_entries) {
+template <SearchMode search_mode, typename T>
+int Search(T* array, Name* name, int valid_entries, int* out_insertion_index) {
   if (search_mode == VALID_ENTRIES) {
     SLOW_DCHECK(array->IsSortedNoDuplicates(valid_entries));
   } else {
@@ -2827,7 +2980,10 @@
   }
 
   int nof = array->number_of_entries();
-  if (nof == 0) return T::kNotFound;
+  if (nof == 0) {
+    if (out_insertion_index != NULL) *out_insertion_index = 0;
+    return T::kNotFound;
+  }
 
   // Fast case: do linear search for small arrays.
   const int kMaxElementsForLinearSearch = 8;
@@ -2835,16 +2991,18 @@
        nof <= kMaxElementsForLinearSearch) ||
       (search_mode == VALID_ENTRIES &&
        valid_entries <= (kMaxElementsForLinearSearch * 3))) {
-    return LinearSearch<search_mode>(array, name, nof, valid_entries);
+    return LinearSearch<search_mode>(array, name, nof, valid_entries,
+                                     out_insertion_index);
   }
 
   // Slow case: perform binary search.
-  return BinarySearch<search_mode>(array, name, 0, nof - 1, valid_entries);
+  return BinarySearch<search_mode>(array, name, 0, nof - 1, valid_entries,
+                                   out_insertion_index);
 }
 
 
 int DescriptorArray::Search(Name* name, int valid_descriptors) {
-  return internal::Search<VALID_ENTRIES>(this, name, valid_descriptors);
+  return internal::Search<VALID_ENTRIES>(this, name, valid_descriptors, NULL);
 }
 
 
@@ -2879,10 +3037,10 @@
 }
 
 
-void Map::LookupTransition(JSObject* holder,
-                           Name* name,
+void Map::LookupTransition(JSObject* holder, Name* name,
+                           PropertyAttributes attributes,
                            LookupResult* result) {
-  int transition_index = this->SearchTransition(name);
+  int transition_index = this->SearchTransition(DATA, name, attributes);
   if (transition_index == TransitionArray::kNotFound) return result->NotFound();
   result->TransitionResult(holder, this->GetTransition(transition_index));
 }
@@ -3039,8 +3197,7 @@
   NoIncrementalWriteBarrierSet(this,
                                ToValueIndex(descriptor_number),
                                *desc->GetValue());
-  NoIncrementalWriteBarrierSet(this,
-                               ToDetailsIndex(descriptor_number),
+  NoIncrementalWriteBarrierSet(this, ToDetailsIndex(descriptor_number),
                                desc->GetDetails().AsSmi());
 }
 
@@ -3215,8 +3372,8 @@
 CAST_ACCESSOR(JSValue)
 CAST_ACCESSOR(JSWeakMap)
 CAST_ACCESSOR(JSWeakSet)
+CAST_ACCESSOR(LayoutDescriptor)
 CAST_ACCESSOR(Map)
-CAST_ACCESSOR(MapCache)
 CAST_ACCESSOR(Name)
 CAST_ACCESSOR(NameDictionary)
 CAST_ACCESSOR(NormalizedMapCache)
@@ -3240,6 +3397,8 @@
 CAST_ACCESSOR(Struct)
 CAST_ACCESSOR(Symbol)
 CAST_ACCESSOR(UnseededNumberDictionary)
+CAST_ACCESSOR(WeakCell)
+CAST_ACCESSOR(WeakFixedArray)
 CAST_ACCESSOR(WeakHashTable)
 
 
@@ -3301,7 +3460,11 @@
 void Name::set_hash_field(uint32_t value) {
   WRITE_UINT32_FIELD(this, kHashFieldOffset, value);
 #if V8_HOST_ARCH_64_BIT
-  WRITE_UINT32_FIELD(this, kHashFieldOffset + kIntSize, 0);
+#if V8_TARGET_LITTLE_ENDIAN
+  WRITE_UINT32_FIELD(this, kHashFieldSlot + kIntSize, 0);
+#else
+  WRITE_UINT32_FIELD(this, kHashFieldSlot, 0);
+#endif
 #endif
 }
 
@@ -3466,6 +3629,22 @@
 }
 
 
+template <>
+inline Vector<const uint8_t> String::GetCharVector() {
+  String::FlatContent flat = GetFlatContent();
+  DCHECK(flat.IsOneByte());
+  return flat.ToOneByteVector();
+}
+
+
+template <>
+inline Vector<const uc16> String::GetCharVector() {
+  String::FlatContent flat = GetFlatContent();
+  DCHECK(flat.IsTwoByte());
+  return flat.ToUC16Vector();
+}
+
+
 uint16_t SeqOneByteString::SeqOneByteStringGet(int index) {
   DCHECK(index >= 0 && index < length());
   return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
@@ -3645,28 +3824,26 @@
 }
 
 
-int ConsStringIteratorOp::OffsetForDepth(int depth) {
-  return depth & kDepthMask;
-}
+int ConsStringIterator::OffsetForDepth(int depth) { return depth & kDepthMask; }
 
 
-void ConsStringIteratorOp::PushLeft(ConsString* string) {
+void ConsStringIterator::PushLeft(ConsString* string) {
   frames_[depth_++ & kDepthMask] = string;
 }
 
 
-void ConsStringIteratorOp::PushRight(ConsString* string) {
+void ConsStringIterator::PushRight(ConsString* string) {
   // Inplace update.
   frames_[(depth_-1) & kDepthMask] = string;
 }
 
 
-void ConsStringIteratorOp::AdjustMaximumDepth() {
+void ConsStringIterator::AdjustMaximumDepth() {
   if (depth_ > maximum_depth_) maximum_depth_ = depth_;
 }
 
 
-void ConsStringIteratorOp::Pop() {
+void ConsStringIterator::Pop() {
   DCHECK(depth_ > 0);
   DCHECK(depth_ <= maximum_depth_);
   depth_--;
@@ -3682,11 +3859,8 @@
 }
 
 
-StringCharacterStream::StringCharacterStream(String* string,
-                                             ConsStringIteratorOp* op,
-                                             int offset)
-  : is_one_byte_(false),
-    op_(op) {
+StringCharacterStream::StringCharacterStream(String* string, int offset)
+    : is_one_byte_(false) {
   Reset(string, offset);
 }
 
@@ -3695,9 +3869,9 @@
   buffer8_ = NULL;
   end_ = NULL;
   ConsString* cons_string = String::VisitFlat(this, string, offset);
-  op_->Reset(cons_string, offset);
+  iter_.Reset(cons_string, offset);
   if (cons_string != NULL) {
-    string = op_->Next(&offset);
+    string = iter_.Next(&offset);
     if (string != NULL) String::VisitFlat(this, string, offset);
   }
 }
@@ -3706,7 +3880,7 @@
 bool StringCharacterStream::HasMore() {
   if (buffer8_ != end_) return true;
   int offset;
-  String* string = op_->Next(&offset);
+  String* string = iter_.Next(&offset);
   DCHECK_EQ(offset, 0);
   if (string == NULL) return false;
   String::VisitFlat(this, string);
@@ -4125,7 +4299,8 @@
 
 template<> inline
 uint8_t FixedTypedArray<Uint8ClampedArrayTraits>::from_double(double value) {
-  if (value < 0) return 0;
+  // Handle NaNs and less than zero values which clamp to zero.
+  if (!(value > 0)) return 0;
   if (value > 0xFF) return 0xFF;
   return static_cast<uint8_t>(lrint(value));
 }
@@ -4256,6 +4431,14 @@
 }
 
 
+Handle<Map> Map::CopyInstallDescriptorsForTesting(
+    Handle<Map> map, int new_descriptor, Handle<DescriptorArray> descriptors,
+    Handle<LayoutDescriptor> layout_descriptor) {
+  return CopyInstallDescriptors(map, new_descriptor, descriptors,
+                                layout_descriptor);
+}
+
+
 int HeapObject::SizeFromMap(Map* map) {
   int instance_size = map->instance_size();
   if (instance_size != kVariableSizeSentinel) return instance_size;
@@ -4266,8 +4449,10 @@
   }
   if (instance_type == ONE_BYTE_STRING_TYPE ||
       instance_type == ONE_BYTE_INTERNALIZED_STRING_TYPE) {
+    // Strings may get concurrently truncated, hence we have to access its
+    // length synchronized.
     return SeqOneByteString::SizeFor(
-        reinterpret_cast<SeqOneByteString*>(this)->length());
+        reinterpret_cast<SeqOneByteString*>(this)->synchronized_length());
   }
   if (instance_type == BYTE_ARRAY_TYPE) {
     return reinterpret_cast<ByteArray*>(this)->ByteArraySize();
@@ -4277,8 +4462,10 @@
   }
   if (instance_type == STRING_TYPE ||
       instance_type == INTERNALIZED_STRING_TYPE) {
+    // Strings may get concurrently truncated, hence we have to access its
+    // length synchronized.
     return SeqTwoByteString::SizeFor(
-        reinterpret_cast<SeqTwoByteString*>(this)->length());
+        reinterpret_cast<SeqTwoByteString*>(this)->synchronized_length());
   }
   if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
     return FixedDoubleArray::SizeFor(
@@ -4477,34 +4664,12 @@
 }
 
 
-void Map::set_done_inobject_slack_tracking(bool value) {
-  set_bit_field3(DoneInobjectSlackTracking::update(bit_field3(), value));
+void Map::set_counter(int value) {
+  set_bit_field3(Counter::update(bit_field3(), value));
 }
 
 
-bool Map::done_inobject_slack_tracking() {
-  return DoneInobjectSlackTracking::decode(bit_field3());
-}
-
-
-void Map::set_construction_count(int value) {
-  set_bit_field3(ConstructionCount::update(bit_field3(), value));
-}
-
-
-int Map::construction_count() {
-  return ConstructionCount::decode(bit_field3());
-}
-
-
-void Map::freeze() {
-  set_bit_field3(IsFrozen::update(bit_field3(), true));
-}
-
-
-bool Map::is_frozen() {
-  return IsFrozen::decode(bit_field3());
-}
+int Map::counter() { return Counter::decode(bit_field3()); }
 
 
 void Map::mark_unstable() {
@@ -4756,6 +4921,21 @@
 }
 
 
+bool Code::has_reloc_info_for_serialization() {
+  DCHECK_EQ(FUNCTION, kind());
+  byte flags = READ_BYTE_FIELD(this, kFullCodeFlags);
+  return FullCodeFlagsHasRelocInfoForSerialization::decode(flags);
+}
+
+
+void Code::set_has_reloc_info_for_serialization(bool value) {
+  DCHECK_EQ(FUNCTION, kind());
+  byte flags = READ_BYTE_FIELD(this, kFullCodeFlags);
+  flags = FullCodeFlagsHasRelocInfoForSerialization::update(flags, value);
+  WRITE_BYTE_FIELD(this, kFullCodeFlags, flags);
+}
+
+
 int Code::allow_osr_at_loop_nesting_level() {
   DCHECK_EQ(FUNCTION, kind());
   int fields = READ_UINT32_FIELD(this, kKindSpecificFlags2Offset);
@@ -4787,13 +4967,11 @@
 
 
 int Code::builtin_index() {
-  DCHECK_EQ(BUILTIN, kind());
   return READ_INT32_FIELD(this, kKindSpecificFlags1Offset);
 }
 
 
 void Code::set_builtin_index(int index) {
-  DCHECK_EQ(BUILTIN, kind());
   WRITE_INT32_FIELD(this, kKindSpecificFlags1Offset, index);
 }
 
@@ -4890,34 +5068,6 @@
 }
 
 
-bool Code::is_weak_stub() {
-  return CanBeWeakStub() && WeakStubField::decode(
-      READ_UINT32_FIELD(this, kKindSpecificFlags1Offset));
-}
-
-
-void Code::mark_as_weak_stub() {
-  DCHECK(CanBeWeakStub());
-  int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset);
-  int updated = WeakStubField::update(previous, true);
-  WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated);
-}
-
-
-bool Code::is_invalidated_weak_stub() {
-  return is_weak_stub() && InvalidatedWeakStubField::decode(
-      READ_UINT32_FIELD(this, kKindSpecificFlags1Offset));
-}
-
-
-void Code::mark_as_invalidated_weak_stub() {
-  DCHECK(is_inline_cache_stub());
-  int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset);
-  int updated = InvalidatedWeakStubField::update(previous, true);
-  WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated);
-}
-
-
 bool Code::is_inline_cache_stub() {
   Kind kind = this->kind();
   switch (kind) {
@@ -5064,13 +5214,6 @@
 };
 
 
-bool Code::IsWeakObjectInIC(Object* object) {
-  return object->IsMap() && Map::cast(object)->CanTransition() &&
-         FLAG_collect_maps &&
-         FLAG_weak_embedded_maps_in_ic;
-}
-
-
 Object* Map::prototype() const {
   return READ_FIELD(this, kPrototypeOffset);
 }
@@ -5099,14 +5242,47 @@
 }
 
 
-void Map::InitializeDescriptors(DescriptorArray* descriptors) {
+LayoutDescriptor* Map::layout_descriptor_gc_safe() {
+  Object* layout_desc = READ_FIELD(this, kLayoutDecriptorOffset);
+  return LayoutDescriptor::cast_gc_safe(layout_desc);
+}
+
+
+bool Map::HasFastPointerLayout() const {
+  Object* layout_desc = READ_FIELD(this, kLayoutDecriptorOffset);
+  return LayoutDescriptor::IsFastPointerLayout(layout_desc);
+}
+
+
+void Map::UpdateDescriptors(DescriptorArray* descriptors,
+                            LayoutDescriptor* layout_desc) {
+  set_instance_descriptors(descriptors);
+  if (FLAG_unbox_double_fields) {
+    if (layout_descriptor()->IsSlowLayout()) {
+      set_layout_descriptor(layout_desc);
+    }
+    SLOW_DCHECK(layout_descriptor()->IsConsistentWithMap(this));
+    DCHECK(visitor_id() == StaticVisitorBase::GetVisitorId(this));
+  }
+}
+
+
+void Map::InitializeDescriptors(DescriptorArray* descriptors,
+                                LayoutDescriptor* layout_desc) {
   int len = descriptors->number_of_descriptors();
   set_instance_descriptors(descriptors);
   SetNumberOfOwnDescriptors(len);
+
+  if (FLAG_unbox_double_fields) {
+    set_layout_descriptor(layout_desc);
+    SLOW_DCHECK(layout_descriptor()->IsConsistentWithMap(this));
+    set_visitor_id(StaticVisitorBase::GetVisitorId(this));
+  }
 }
 
 
 ACCESSORS(Map, instance_descriptors, DescriptorArray, kDescriptorsOffset)
+ACCESSORS(Map, layout_descriptor, LayoutDescriptor, kLayoutDecriptorOffset)
 
 
 void Map::set_bit_field3(uint32_t bits) {
@@ -5122,18 +5298,31 @@
 }
 
 
+LayoutDescriptor* Map::GetLayoutDescriptor() {
+  return FLAG_unbox_double_fields ? layout_descriptor()
+                                  : LayoutDescriptor::FastPointerLayout();
+}
+
+
 void Map::AppendDescriptor(Descriptor* desc) {
   DescriptorArray* descriptors = instance_descriptors();
   int number_of_own_descriptors = NumberOfOwnDescriptors();
   DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors);
   descriptors->Append(desc);
   SetNumberOfOwnDescriptors(number_of_own_descriptors + 1);
+
+// This function does not support appending double field descriptors and
+// it should never try to (otherwise, layout descriptor must be updated too).
+#ifdef DEBUG
+  PropertyDetails details = desc->GetDetails();
+  CHECK(details.type() != FIELD || !details.representation().IsDouble());
+#endif
 }
 
 
 Object* Map::GetBackPointer() {
   Object* object = READ_FIELD(this, kTransitionsOrBackPointerOffset);
-  if (object->IsDescriptorArray()) {
+  if (object->IsTransitionArray()) {
     return TransitionArray::cast(object)->back_pointer_storage();
   } else {
     DCHECK(object->IsMap() || object->IsUndefined());
@@ -5154,16 +5343,16 @@
 
 
 Map* Map::elements_transition_map() {
-  int index = transitions()->Search(GetHeap()->elements_transition_symbol());
+  int index =
+      transitions()->SearchSpecial(GetHeap()->elements_transition_symbol());
   return transitions()->GetTarget(index);
 }
 
 
 bool Map::CanHaveMoreTransitions() {
   if (!HasTransitionArray()) return true;
-  return FixedArray::SizeFor(transitions()->length() +
-                             TransitionArray::kTransitionSize)
-      <= Page::kMaxRegularHeapObjectSize;
+  return transitions()->number_of_transitions() <
+         TransitionArray::kMaxNumberOfTransitions;
 }
 
 
@@ -5172,8 +5361,19 @@
 }
 
 
-int Map::SearchTransition(Name* name) {
-  if (HasTransitionArray()) return transitions()->Search(name);
+int Map::SearchSpecialTransition(Symbol* name) {
+  if (HasTransitionArray()) {
+    return transitions()->SearchSpecial(name);
+  }
+  return TransitionArray::kNotFound;
+}
+
+
+int Map::SearchTransition(PropertyKind kind, Name* name,
+                          PropertyAttributes attributes) {
+  if (HasTransitionArray()) {
+    return transitions()->Search(kind, name, attributes);
+  }
   return TransitionArray::kNotFound;
 }
 
@@ -5191,12 +5391,10 @@
     Handle<Map> map, Handle<FixedArray> proto_transitions) {
   EnsureHasTransitionArray(map);
   int old_number_of_transitions = map->NumberOfProtoTransitions();
-#ifdef DEBUG
-  if (map->HasPrototypeTransitions()) {
+  if (Heap::ShouldZapGarbage() && map->HasPrototypeTransitions()) {
     DCHECK(map->GetPrototypeTransitions() != *proto_transitions);
     map->ZapPrototypeTransitions();
   }
-#endif
   map->transitions()->SetPrototypeTransitions(*proto_transitions);
   map->SetNumberOfProtoTransitions(old_number_of_transitions);
 }
@@ -5226,9 +5424,17 @@
       Map* target = transitions()->GetTarget(i);
       if (target->instance_descriptors() == instance_descriptors()) {
         Name* key = transitions()->GetKey(i);
-        int new_target_index = transition_array->Search(key);
-        DCHECK(new_target_index != TransitionArray::kNotFound);
-        DCHECK(transition_array->GetTarget(new_target_index) == target);
+        int new_target_index;
+        if (TransitionArray::IsSpecialTransition(key)) {
+          new_target_index = transition_array->SearchSpecial(Symbol::cast(key));
+        } else {
+          PropertyDetails details =
+              TransitionArray::GetTargetDetails(key, target);
+          new_target_index = transition_array->Search(details.kind(), key,
+                                                      details.attributes());
+        }
+        DCHECK_NE(TransitionArray::kNotFound, new_target_index);
+        DCHECK_EQ(target, transition_array->GetTarget(new_target_index));
       }
     }
 #endif
@@ -5273,7 +5479,6 @@
 
 ACCESSORS(GlobalObject, builtins, JSBuiltinsObject, kBuiltinsOffset)
 ACCESSORS(GlobalObject, native_context, Context, kNativeContextOffset)
-ACCESSORS(GlobalObject, global_context, Context, kGlobalContextOffset)
 ACCESSORS(GlobalObject, global_proxy, JSObject, kGlobalProxyOffset)
 
 ACCESSORS(JSGlobalProxy, native_context, Object, kNativeContextOffset)
@@ -5309,6 +5514,10 @@
 ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset)
 ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset)
 ACCESSORS(InterceptorInfo, data, Object, kDataOffset)
+SMI_ACCESSORS(InterceptorInfo, flags, kFlagsOffset)
+BOOL_ACCESSORS(InterceptorInfo, flags, can_intercept_symbols,
+               kCanInterceptSymbolsBit)
+BOOL_ACCESSORS(InterceptorInfo, flags, all_can_read, kAllCanReadBit)
 
 ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset)
 ACCESSORS(CallHandlerInfo, data, Object, kDataOffset)
@@ -5361,7 +5570,7 @@
 ACCESSORS_TO_SMI(Script, line_offset, kLineOffsetOffset)
 ACCESSORS_TO_SMI(Script, column_offset, kColumnOffsetOffset)
 ACCESSORS(Script, context_data, Object, kContextOffset)
-ACCESSORS(Script, wrapper, Foreign, kWrapperOffset)
+ACCESSORS(Script, wrapper, HeapObject, kWrapperOffset)
 ACCESSORS_TO_SMI(Script, type, kTypeOffset)
 ACCESSORS(Script, line_ends, Object, kLineEndsOffset)
 ACCESSORS(Script, eval_from_shared, Object, kEvalFromSharedOffset)
@@ -5406,6 +5615,9 @@
 ACCESSORS(SharedFunctionInfo, construct_stub, Code, kConstructStubOffset)
 ACCESSORS(SharedFunctionInfo, feedback_vector, TypeFeedbackVector,
           kFeedbackVectorOffset)
+#if TRACE_MAPS
+SMI_ACCESSORS(SharedFunctionInfo, unique_id, kUniqueIdOffset)
+#endif
 ACCESSORS(SharedFunctionInfo, instance_class_name, Object,
           kInstanceClassNameOffset)
 ACCESSORS(SharedFunctionInfo, function_data, Object, kFunctionDataOffset)
@@ -5431,9 +5643,7 @@
 BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_toplevel,
                kIsTopLevelBit)
 
-BOOL_ACCESSORS(SharedFunctionInfo,
-               compiler_hints,
-               allows_lazy_compilation,
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, allows_lazy_compilation,
                kAllowLazyCompilation)
 BOOL_ACCESSORS(SharedFunctionInfo,
                compiler_hints,
@@ -5448,6 +5658,7 @@
                has_duplicate_parameters,
                kHasDuplicateParameters)
 BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, asm_function, kIsAsmFunction)
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, deserialized, kDeserialized)
 
 
 #if V8_HOST_ARCH_32_BIT
@@ -5472,25 +5683,30 @@
 
 #else
 
-#define PSEUDO_SMI_ACCESSORS_LO(holder, name, offset)             \
-  STATIC_ASSERT(holder::offset % kPointerSize == 0);              \
-  int holder::name() const {                                      \
-    int value = READ_INT_FIELD(this, offset);                     \
-    DCHECK(kHeapObjectTag == 1);                                  \
-    DCHECK((value & kHeapObjectTag) == 0);                        \
-    return value >> 1;                                            \
-  }                                                               \
-  void holder::set_##name(int value) {                            \
-    DCHECK(kHeapObjectTag == 1);                                  \
-    DCHECK((value & 0xC0000000) == 0xC0000000 ||                  \
-           (value & 0xC0000000) == 0x0);                          \
-    WRITE_INT_FIELD(this,                                         \
-                    offset,                                       \
-                    (value << 1) & ~kHeapObjectTag);              \
+#if V8_TARGET_LITTLE_ENDIAN
+#define PSEUDO_SMI_LO_ALIGN 0
+#define PSEUDO_SMI_HI_ALIGN kIntSize
+#else
+#define PSEUDO_SMI_LO_ALIGN kIntSize
+#define PSEUDO_SMI_HI_ALIGN 0
+#endif
+
+#define PSEUDO_SMI_ACCESSORS_LO(holder, name, offset)                          \
+  STATIC_ASSERT(holder::offset % kPointerSize == PSEUDO_SMI_LO_ALIGN);         \
+  int holder::name() const {                                                   \
+    int value = READ_INT_FIELD(this, offset);                                  \
+    DCHECK(kHeapObjectTag == 1);                                               \
+    DCHECK((value & kHeapObjectTag) == 0);                                     \
+    return value >> 1;                                                         \
+  }                                                                            \
+  void holder::set_##name(int value) {                                         \
+    DCHECK(kHeapObjectTag == 1);                                               \
+    DCHECK((value & 0xC0000000) == 0xC0000000 || (value & 0xC0000000) == 0x0); \
+    WRITE_INT_FIELD(this, offset, (value << 1) & ~kHeapObjectTag);             \
   }
 
-#define PSEUDO_SMI_ACCESSORS_HI(holder, name, offset)             \
-  STATIC_ASSERT(holder::offset % kPointerSize == kIntSize);       \
+#define PSEUDO_SMI_ACCESSORS_HI(holder, name, offset)                  \
+  STATIC_ASSERT(holder::offset % kPointerSize == PSEUDO_SMI_HI_ALIGN); \
   INT_ACCESSORS(holder, name, offset)
 
 
@@ -5577,6 +5793,10 @@
 }
 
 
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, uses_super_property,
+               kUsesSuperProperty)
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, uses_super_constructor_call,
+               kUsesSuperConstructorCall)
 BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, native, kNative)
 BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, inline_builtin,
                kInlineBuiltin)
@@ -5592,9 +5812,12 @@
 BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_generator, kIsGenerator)
 BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_concise_method,
                kIsConciseMethod)
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_default_constructor,
+               kIsDefaultConstructor)
 
 ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset)
 ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset)
+ACCESSORS(CodeCache, weak_cell_cache, Object, kWeakCellCacheOffset)
 
 ACCESSORS(PolymorphicCodeCache, cache, Object, kCacheOffset)
 
@@ -5747,10 +5970,9 @@
 }
 
 
-BailoutReason SharedFunctionInfo::DisableOptimizationReason() {
-  BailoutReason reason = static_cast<BailoutReason>(
+BailoutReason SharedFunctionInfo::disable_optimization_reason() {
+  return static_cast<BailoutReason>(
       DisabledOptimizationReasonBits::decode(opt_count_and_bailout_reason()));
-  return reason;
 }
 
 
@@ -5831,7 +6053,7 @@
 
 bool JSFunction::IsInobjectSlackTrackingInProgress() {
   return has_initial_map() &&
-      initial_map()->construction_count() != JSFunction::kNoSlackTracking;
+         initial_map()->counter() >= Map::kSlackTrackingCounterEnd;
 }
 
 
@@ -6252,6 +6474,16 @@
 }
 
 
+bool JSArrayBuffer::is_neuterable() {
+  return BooleanBit::get(flag(), kIsNeuterableBit);
+}
+
+
+void JSArrayBuffer::set_is_neuterable(bool value) {
+  set_flag(BooleanBit::set(flag(), kIsNeuterableBit, value));
+}
+
+
 ACCESSORS(JSArrayBuffer, weak_next, Object, kWeakNextOffset)
 ACCESSORS(JSArrayBuffer, weak_first_view, Object, kWeakFirstViewOffset)
 
@@ -6297,7 +6529,7 @@
 String* JSRegExp::Pattern() {
   DCHECK(this->data()->IsFixedArray());
   Object* data = this->data();
-  String* pattern= String::cast(FixedArray::cast(data)->get(kSourceIndex));
+  String* pattern = String::cast(FixedArray::cast(data)->get(kSourceIndex));
   return pattern;
 }
 
@@ -6317,7 +6549,7 @@
 
 ElementsKind JSObject::GetElementsKind() {
   ElementsKind kind = map()->elements_kind();
-#if DEBUG
+#if VERIFY_HEAP && DEBUG
   FixedArrayBase* fixed_array =
       reinterpret_cast<FixedArrayBase*>(READ_FIELD(this, kElementsOffset));
 
@@ -6509,6 +6741,30 @@
 }
 
 
+uint32_t StringHasher::ComputeRunningHash(uint32_t running_hash,
+                                          const uc16* chars, int length) {
+  DCHECK_NOT_NULL(chars);
+  DCHECK(length >= 0);
+  for (int i = 0; i < length; ++i) {
+    running_hash = AddCharacterCore(running_hash, *chars++);
+  }
+  return running_hash;
+}
+
+
+uint32_t StringHasher::ComputeRunningHashOneByte(uint32_t running_hash,
+                                                 const char* chars,
+                                                 int length) {
+  DCHECK_NOT_NULL(chars);
+  DCHECK(length >= 0);
+  for (int i = 0; i < length; ++i) {
+    uint16_t c = static_cast<uint16_t>(*chars++);
+    running_hash = AddCharacterCore(running_hash, c);
+  }
+  return running_hash;
+}
+
+
 void StringHasher::AddCharacter(uint16_t c) {
   // Use the Jenkins one-at-a-time hash function to update the hash
   // for the given character.
@@ -6574,14 +6830,8 @@
   // Nothing to do.
   if (hasher.has_trivial_hash()) return hasher.GetHashField();
   ConsString* cons_string = String::VisitFlat(&hasher, string);
-  // The string was flat.
-  if (cons_string == NULL) return hasher.GetHashField();
-  // This is a ConsString, iterate across it.
-  ConsStringIteratorOp op(cons_string);
-  int offset;
-  while (NULL != (string = op.Next(&offset))) {
-    String::VisitFlat(&hasher, string, offset);
-  }
+  if (cons_string == nullptr) return hasher.GetHashField();
+  hasher.VisitConsString(cons_string);
   return hasher.GetHashField();
 }
 
@@ -6619,7 +6869,7 @@
   DCHECK(SlowEquals(canonical));
   DCHECK(canonical->IsInternalizedString());
   DCHECK(canonical->HasHashCode());
-  WRITE_FIELD(this, kHashFieldOffset, canonical);
+  WRITE_FIELD(this, kHashFieldSlot, canonical);
   // Setting the hash field to a tagged value sets the LSB, causing the hash
   // code to be interpreted as uninitialized.  We use this fact to recognize
   // that we have a forwarded string.
@@ -6630,7 +6880,7 @@
 String* String::GetForwardedInternalizedString() {
   DCHECK(IsInternalizedString());
   if (HasHashCode()) return this;
-  String* canonical = String::cast(READ_FIELD(this, kHashFieldOffset));
+  String* canonical = String::cast(READ_FIELD(this, kHashFieldSlot));
   DCHECK(canonical->IsInternalizedString());
   DCHECK(SlowEquals(canonical));
   DCHECK(canonical->HasHashCode());
@@ -6638,11 +6888,6 @@
 }
 
 
-Object* JSReceiver::GetConstructor() {
-  return map()->constructor();
-}
-
-
 Maybe<bool> JSReceiver::HasProperty(Handle<JSReceiver> object,
                                     Handle<Name> name) {
   if (object->IsJSProxy()) {
@@ -6790,7 +7035,10 @@
 
 
 void ExecutableAccessorInfo::clear_setter() {
-  set_setter(GetIsolate()->heap()->undefined_value(), SKIP_WRITE_BARRIER);
+  auto foreign = GetIsolate()->factory()->NewForeign(
+      reinterpret_cast<v8::internal::Address>(
+          reinterpret_cast<intptr_t>(nullptr)));
+  set_setter(*foreign);
 }
 
 
@@ -6880,9 +7128,9 @@
 }
 
 
-void NameDictionary::DoGenerateNewEnumerationIndices(
+Handle<FixedArray> NameDictionary::DoGenerateNewEnumerationIndices(
     Handle<NameDictionary> dictionary) {
-  DerivedDictionary::GenerateNewEnumerationIndices(dictionary);
+  return DerivedDictionary::GenerateNewEnumerationIndices(dictionary);
 }
 
 
@@ -6952,6 +7200,14 @@
 }
 
 
+int Map::SlackForArraySize(int old_size, int size_limit) {
+  const int max_slack = size_limit - old_size;
+  CHECK(max_slack >= 0);
+  if (old_size < 4) return Min(max_slack, 1);
+  return Min(max_slack, old_size / 2);
+}
+
+
 void JSArray::EnsureSize(Handle<JSArray> array, int required_size) {
   DCHECK(array->HasFastSmiOrObjectElements());
   Handle<FixedArray> elts = handle(FixedArray::cast(array->elements()));
@@ -7158,12 +7414,36 @@
 }
 
 
+static inline void IterateBodyUsingLayoutDescriptor(HeapObject* object,
+                                                    int start_offset,
+                                                    int end_offset,
+                                                    ObjectVisitor* v) {
+  DCHECK(FLAG_unbox_double_fields);
+  DCHECK(IsAligned(start_offset, kPointerSize) &&
+         IsAligned(end_offset, kPointerSize));
+
+  LayoutDescriptorHelper helper(object->map());
+  DCHECK(!helper.all_fields_tagged());
+
+  for (int offset = start_offset; offset < end_offset; offset += kPointerSize) {
+    // Visit all tagged fields.
+    if (helper.IsTagged(offset)) {
+      v->VisitPointer(HeapObject::RawField(object, offset));
+    }
+  }
+}
+
+
 template<int start_offset, int end_offset, int size>
 void FixedBodyDescriptor<start_offset, end_offset, size>::IterateBody(
     HeapObject* obj,
     ObjectVisitor* v) {
+  if (!FLAG_unbox_double_fields || obj->map()->HasFastPointerLayout()) {
     v->VisitPointers(HeapObject::RawField(obj, start_offset),
                      HeapObject::RawField(obj, end_offset));
+  } else {
+    IterateBodyUsingLayoutDescriptor(obj, start_offset, end_offset, v);
+  }
 }
 
 
@@ -7171,8 +7451,12 @@
 void FlexibleBodyDescriptor<start_offset>::IterateBody(HeapObject* obj,
                                                        int object_size,
                                                        ObjectVisitor* v) {
-  v->VisitPointers(HeapObject::RawField(obj, start_offset),
-                   HeapObject::RawField(obj, object_size));
+  if (!FLAG_unbox_double_fields || obj->map()->HasFastPointerLayout()) {
+    v->VisitPointers(HeapObject::RawField(obj, start_offset),
+                     HeapObject::RawField(obj, object_size));
+  } else {
+    IterateBodyUsingLayoutDescriptor(obj, start_offset, object_size, v);
+  }
 }
 
 
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index d709a20..9805490 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -18,11 +18,11 @@
 void Object::Print() {
   OFStream os(stdout);
   this->Print(os);
-  os << flush;
+  os << std::flush;
 }
 
 
-void Object::Print(OStream& os) {  // NOLINT
+void Object::Print(std::ostream& os) {  // NOLINT
   if (IsSmi()) {
     Smi::cast(this)->SmiPrint(os);
   } else {
@@ -31,12 +31,12 @@
 }
 
 
-void HeapObject::PrintHeader(OStream& os, const char* id) {  // NOLINT
+void HeapObject::PrintHeader(std::ostream& os, const char* id) {  // NOLINT
   os << "" << reinterpret_cast<void*>(this) << ": [" << id << "]\n";
 }
 
 
-void HeapObject::HeapObjectPrint(OStream& os) {  // NOLINT
+void HeapObject::HeapObjectPrint(std::ostream& os) {  // NOLINT
   InstanceType instance_type = map()->instance_type();
 
   HandleScope scope(GetIsolate());
@@ -169,6 +169,9 @@
     case PROPERTY_CELL_TYPE:
       PropertyCell::cast(this)->PropertyCellPrint(os);
       break;
+    case WEAK_CELL_TYPE:
+      WeakCell::cast(this)->WeakCellPrint(os);
+      break;
     case JS_ARRAY_BUFFER_TYPE:
       JSArrayBuffer::cast(this)->JSArrayBufferPrint(os);
       break;
@@ -193,19 +196,19 @@
 }
 
 
-void ByteArray::ByteArrayPrint(OStream& os) {  // NOLINT
+void ByteArray::ByteArrayPrint(std::ostream& os) {  // NOLINT
   os << "byte array, data starts at " << GetDataStartAddress();
 }
 
 
-void FreeSpace::FreeSpacePrint(OStream& os) {  // NOLINT
+void FreeSpace::FreeSpacePrint(std::ostream& os) {  // NOLINT
   os << "free space, size " << Size();
 }
 
 
-#define EXTERNAL_ARRAY_PRINTER(Type, type, TYPE, ctype, size)           \
-  void External##Type##Array::External##Type##ArrayPrint(OStream& os) { \
-    os << "external " #type " array";                                   \
+#define EXTERNAL_ARRAY_PRINTER(Type, type, TYPE, ctype, size)                \
+  void External##Type##Array::External##Type##ArrayPrint(std::ostream& os) { \
+    os << "external " #type " array";                                        \
   }
 
 TYPED_ARRAYS(EXTERNAL_ARRAY_PRINTER)
@@ -214,12 +217,13 @@
 
 
 template <class Traits>
-void FixedTypedArray<Traits>::FixedTypedArrayPrint(OStream& os) {  // NOLINT
+void FixedTypedArray<Traits>::FixedTypedArrayPrint(
+    std::ostream& os) {  // NOLINT
   os << "fixed " << Traits::Designator();
 }
 
 
-void JSObject::PrintProperties(OStream& os) {  // NOLINT
+void JSObject::PrintProperties(std::ostream& os) {  // NOLINT
   if (HasFastProperties()) {
     DescriptorArray* descs = map()->instance_descriptors();
     for (int i = 0; i < map()->NumberOfOwnDescriptors(); i++) {
@@ -229,18 +233,24 @@
       switch (descs->GetType(i)) {
         case FIELD: {
           FieldIndex index = FieldIndex::ForDescriptor(map(), i);
-          os << Brief(RawFastPropertyAt(index)) << " (field at offset "
-             << index.property_index() << ")\n";
+          if (IsUnboxedDoubleField(index)) {
+            os << "<unboxed double> " << RawFastDoublePropertyAt(index);
+          } else {
+            os << Brief(RawFastPropertyAt(index));
+          }
+          os << " (field at offset " << index.property_index() << ")\n";
+          break;
+        }
+        case ACCESSOR_FIELD: {
+          FieldIndex index = FieldIndex::ForDescriptor(map(), i);
+          os << " (accessor at offset " << index.property_index() << ")\n";
           break;
         }
         case CONSTANT:
           os << Brief(descs->GetConstant(i)) << " (constant)\n";
           break;
         case CALLBACKS:
-          os << Brief(descs->GetCallbacksObject(i)) << " (callback)\n";
-          break;
-        case NORMAL:  // only in slow mode
-          UNREACHABLE();
+          os << Brief(descs->GetCallbacksObject(i)) << " (callbacks)\n";
           break;
       }
     }
@@ -251,7 +261,7 @@
 
 
 template <class T>
-static void DoPrintElements(OStream& os, Object* object) {  // NOLINT
+static void DoPrintElements(std::ostream& os, Object* object) {  // NOLINT
   T* p = T::cast(object);
   for (int i = 0; i < p->length(); i++) {
     os << "   " << i << ": " << p->get_scalar(i) << "\n";
@@ -259,7 +269,7 @@
 }
 
 
-void JSObject::PrintElements(OStream& os) {  // NOLINT
+void JSObject::PrintElements(std::ostream& os) {  // NOLINT
   // Don't call GetElementsKind, its validation code can cause the printer to
   // fail when debugging.
   switch (map()->elements_kind()) {
@@ -341,45 +351,7 @@
 }
 
 
-void JSObject::PrintTransitions(OStream& os) {  // NOLINT
-  if (!map()->HasTransitionArray()) return;
-  TransitionArray* transitions = map()->transitions();
-  for (int i = 0; i < transitions->number_of_transitions(); i++) {
-    Name* key = transitions->GetKey(i);
-    os << "   ";
-    key->NamePrint(os);
-    os << ": ";
-    if (key == GetHeap()->frozen_symbol()) {
-      os << " (transition to frozen)\n";
-    } else if (key == GetHeap()->elements_transition_symbol()) {
-      os << " (transition to "
-         << ElementsKindToString(transitions->GetTarget(i)->elements_kind())
-         << ")\n";
-    } else if (key == GetHeap()->observed_symbol()) {
-      os << " (transition to Object.observe)\n";
-    } else {
-      switch (transitions->GetTargetDetails(i).type()) {
-        case FIELD: {
-          os << " (transition to field)\n";
-          break;
-        }
-        case CONSTANT:
-          os << " (transition to constant)\n";
-          break;
-        case CALLBACKS:
-          os << " (transition to callback)\n";
-          break;
-        // Values below are never in the target descriptor array.
-        case NORMAL:
-          UNREACHABLE();
-          break;
-      }
-    }
-  }
-}
-
-
-void JSObject::JSObjectPrint(OStream& os) {  // NOLINT
+void JSObject::JSObjectPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSObject");
   // Don't call GetElementsKind, its validation code can cause the printer to
   // fail when debugging.
@@ -395,7 +367,7 @@
 }
 
 
-void JSModule::JSModulePrint(OStream& os) {  // NOLINT
+void JSModule::JSModulePrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSModule");
   os << " - map = " << reinterpret_cast<void*>(map()) << "\n"
      << " - context = ";
@@ -419,17 +391,20 @@
 }
 
 
-void Symbol::SymbolPrint(OStream& os) {  // NOLINT
+void Symbol::SymbolPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "Symbol");
   os << " - hash: " << Hash();
   os << "\n - name: " << Brief(name());
+  if (name()->IsUndefined()) {
+    os << " (" << PrivateSymbolToName() << ")";
+  }
   os << "\n - private: " << is_private();
   os << "\n - own: " << is_own();
   os << "\n";
 }
 
 
-void Map::MapPrint(OStream& os) {  // NOLINT
+void Map::MapPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "Map");
   os << " - type: " << TypeToString(instance_type()) << "\n";
   os << " - instance size: " << instance_size() << "\n";
@@ -438,21 +413,23 @@
   os << "\n - pre-allocated property fields: "
      << pre_allocated_property_fields() << "\n";
   os << " - unused property fields: " << unused_property_fields() << "\n";
+  if (is_deprecated()) os << " - deprecated_map\n";
+  if (is_dictionary_map()) os << " - dictionary_map\n";
+  if (is_prototype_map()) os << " - prototype_map\n";
   if (is_hidden_prototype()) os << " - hidden_prototype\n";
   if (has_named_interceptor()) os << " - named_interceptor\n";
   if (has_indexed_interceptor()) os << " - indexed_interceptor\n";
   if (is_undetectable()) os << " - undetectable\n";
   if (has_instance_call_handler()) os << " - instance_call_handler\n";
   if (is_access_check_needed()) os << " - access_check_needed\n";
-  if (is_frozen()) {
-    os << " - frozen\n";
-  } else if (!is_extensible()) {
-    os << " - sealed\n";
-  }
+  if (!is_extensible()) os << " - non-extensible\n";
   os << " - back pointer: " << Brief(GetBackPointer());
   os << "\n - instance descriptors " << (owns_descriptors() ? "(own) " : "")
      << "#" << NumberOfOwnDescriptors() << ": "
      << Brief(instance_descriptors());
+  if (FLAG_unbox_double_fields) {
+    os << "\n - layout descriptor: " << Brief(layout_descriptor());
+  }
   if (HasTransitionArray()) {
     os << "\n - transitions: " << Brief(transitions());
   }
@@ -464,20 +441,21 @@
 }
 
 
-void CodeCache::CodeCachePrint(OStream& os) {  // NOLINT
+void CodeCache::CodeCachePrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "CodeCache");
   os << "\n - default_cache: " << Brief(default_cache());
   os << "\n - normal_type_cache: " << Brief(normal_type_cache());
 }
 
 
-void PolymorphicCodeCache::PolymorphicCodeCachePrint(OStream& os) {  // NOLINT
+void PolymorphicCodeCache::PolymorphicCodeCachePrint(
+    std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "PolymorphicCodeCache");
   os << "\n - cache: " << Brief(cache());
 }
 
 
-void TypeFeedbackInfo::TypeFeedbackInfoPrint(OStream& os) {  // NOLINT
+void TypeFeedbackInfo::TypeFeedbackInfoPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "TypeFeedbackInfo");
   os << " - ic_total_count: " << ic_total_count()
      << ", ic_with_type_info_count: " << ic_with_type_info_count()
@@ -485,13 +463,14 @@
 }
 
 
-void AliasedArgumentsEntry::AliasedArgumentsEntryPrint(OStream& os) {  // NOLINT
+void AliasedArgumentsEntry::AliasedArgumentsEntryPrint(
+    std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "AliasedArgumentsEntry");
   os << "\n - aliased_context_slot: " << aliased_context_slot();
 }
 
 
-void FixedArray::FixedArrayPrint(OStream& os) {  // NOLINT
+void FixedArray::FixedArrayPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "FixedArray");
   os << " - length: " << length();
   for (int i = 0; i < length(); i++) {
@@ -501,7 +480,7 @@
 }
 
 
-void FixedDoubleArray::FixedDoubleArrayPrint(OStream& os) {  // NOLINT
+void FixedDoubleArray::FixedDoubleArrayPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "FixedDoubleArray");
   os << " - length: " << length();
   for (int i = 0; i < length(); i++) {
@@ -516,7 +495,7 @@
 }
 
 
-void ConstantPoolArray::ConstantPoolArrayPrint(OStream& os) {  // NOLINT
+void ConstantPoolArray::ConstantPoolArrayPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "ConstantPoolArray");
   os << " - length: " << length();
   for (int i = 0; i <= last_index(INT32, SMALL_SECTION); i++) {
@@ -553,13 +532,13 @@
 }
 
 
-void JSValue::JSValuePrint(OStream& os) {  // NOLINT
+void JSValue::JSValuePrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "ValueObject");
   value()->Print(os);
 }
 
 
-void JSMessageObject::JSMessageObjectPrint(OStream& os) {  // NOLINT
+void JSMessageObject::JSMessageObjectPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSMessageObject");
   os << " - type: " << Brief(type());
   os << "\n - arguments: " << Brief(arguments());
@@ -571,7 +550,7 @@
 }
 
 
-void String::StringPrint(OStream& os) {  // NOLINT
+void String::StringPrint(std::ostream& os) {  // NOLINT
   if (StringShape(this).IsInternalized()) {
     os << "#";
   } else if (StringShape(this).IsCons()) {
@@ -598,26 +577,14 @@
 }
 
 
-void Name::NamePrint(OStream& os) {  // NOLINT
-  if (IsString())
+void Name::NamePrint(std::ostream& os) {  // NOLINT
+  if (IsString()) {
     String::cast(this)->StringPrint(os);
-  else
+  } else if (IsSymbol()) {
+    Symbol::cast(this)->name()->Print(os);
+  } else {
     os << Brief(this);
-}
-
-
-// This method is only meant to be called from gdb for debugging purposes.
-// Since the string can also be in two-byte encoding, non-Latin1 characters
-// will be ignored in the output.
-char* String::ToAsciiArray() {
-  // Static so that subsequent calls frees previously allocated space.
-  // This also means that previous results will be overwritten.
-  static char* buffer = NULL;
-  if (buffer != NULL) free(buffer);
-  buffer = new char[length()+1];
-  WriteToFlat(this, reinterpret_cast<uint8_t*>(buffer), 0, length());
-  buffer[length()] = 0;
-  return buffer;
+  }
 }
 
 
@@ -626,7 +593,7 @@
 };
 
 
-void JSDate::JSDatePrint(OStream& os) {  // NOLINT
+void JSDate::JSDatePrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSDate");
   os << " - map = " << reinterpret_cast<void*>(map()) << "\n";
   os << " - value = ";
@@ -650,7 +617,7 @@
 }
 
 
-void JSProxy::JSProxyPrint(OStream& os) {  // NOLINT
+void JSProxy::JSProxyPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSProxy");
   os << " - map = " << reinterpret_cast<void*>(map()) << "\n";
   os << " - handler = ";
@@ -661,7 +628,7 @@
 }
 
 
-void JSFunctionProxy::JSFunctionProxyPrint(OStream& os) {  // NOLINT
+void JSFunctionProxy::JSFunctionProxyPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSFunctionProxy");
   os << " - map = " << reinterpret_cast<void*>(map()) << "\n";
   os << " - handler = ";
@@ -674,7 +641,7 @@
 }
 
 
-void JSSet::JSSetPrint(OStream& os) {  // NOLINT
+void JSSet::JSSetPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSSet");
   os << " - map = " << reinterpret_cast<void*>(map()) << "\n";
   os << " - table = " << Brief(table());
@@ -682,7 +649,7 @@
 }
 
 
-void JSMap::JSMapPrint(OStream& os) {  // NOLINT
+void JSMap::JSMapPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSMap");
   os << " - map = " << reinterpret_cast<void*>(map()) << "\n";
   os << " - table = " << Brief(table());
@@ -691,8 +658,9 @@
 
 
 template <class Derived, class TableType>
-void OrderedHashTableIterator<
-    Derived, TableType>::OrderedHashTableIteratorPrint(OStream& os) {  // NOLINT
+void
+OrderedHashTableIterator<Derived, TableType>::OrderedHashTableIteratorPrint(
+    std::ostream& os) {  // NOLINT
   os << " - map = " << reinterpret_cast<void*>(map()) << "\n";
   os << " - table = " << Brief(table());
   os << "\n - index = " << Brief(index());
@@ -703,27 +671,27 @@
 
 template void OrderedHashTableIterator<
     JSSetIterator,
-    OrderedHashSet>::OrderedHashTableIteratorPrint(OStream& os);  // NOLINT
+    OrderedHashSet>::OrderedHashTableIteratorPrint(std::ostream& os);  // NOLINT
 
 
 template void OrderedHashTableIterator<
     JSMapIterator,
-    OrderedHashMap>::OrderedHashTableIteratorPrint(OStream& os);  // NOLINT
+    OrderedHashMap>::OrderedHashTableIteratorPrint(std::ostream& os);  // NOLINT
 
 
-void JSSetIterator::JSSetIteratorPrint(OStream& os) {  // NOLINT
+void JSSetIterator::JSSetIteratorPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSSetIterator");
   OrderedHashTableIteratorPrint(os);
 }
 
 
-void JSMapIterator::JSMapIteratorPrint(OStream& os) {  // NOLINT
+void JSMapIterator::JSMapIteratorPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSMapIterator");
   OrderedHashTableIteratorPrint(os);
 }
 
 
-void JSWeakMap::JSWeakMapPrint(OStream& os) {  // NOLINT
+void JSWeakMap::JSWeakMapPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSWeakMap");
   os << " - map = " << reinterpret_cast<void*>(map()) << "\n";
   os << " - table = " << Brief(table());
@@ -731,7 +699,7 @@
 }
 
 
-void JSWeakSet::JSWeakSetPrint(OStream& os) {  // NOLINT
+void JSWeakSet::JSWeakSetPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSWeakSet");
   os << " - map = " << reinterpret_cast<void*>(map()) << "\n";
   os << " - table = " << Brief(table());
@@ -739,7 +707,7 @@
 }
 
 
-void JSArrayBuffer::JSArrayBufferPrint(OStream& os) {  // NOLINT
+void JSArrayBuffer::JSArrayBufferPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSArrayBuffer");
   os << " - map = " << reinterpret_cast<void*>(map()) << "\n";
   os << " - backing_store = " << backing_store() << "\n";
@@ -748,7 +716,7 @@
 }
 
 
-void JSTypedArray::JSTypedArrayPrint(OStream& os) {  // NOLINT
+void JSTypedArray::JSTypedArrayPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSTypedArray");
   os << " - map = " << reinterpret_cast<void*>(map()) << "\n";
   os << " - buffer = " << Brief(buffer());
@@ -760,7 +728,7 @@
 }
 
 
-void JSDataView::JSDataViewPrint(OStream& os) {  // NOLINT
+void JSDataView::JSDataViewPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSDataView");
   os << " - map = " << reinterpret_cast<void*>(map()) << "\n";
   os << " - buffer =" << Brief(buffer());
@@ -770,7 +738,7 @@
 }
 
 
-void JSFunction::JSFunctionPrint(OStream& os) {  // NOLINT
+void JSFunction::JSFunctionPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "Function");
   os << " - map = " << reinterpret_cast<void*>(map()) << "\n";
   os << " - initial_map = ";
@@ -791,7 +759,7 @@
 }
 
 
-void SharedFunctionInfo::SharedFunctionInfoPrint(OStream& os) {  // NOLINT
+void SharedFunctionInfo::SharedFunctionInfoPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "SharedFunctionInfo");
   os << " - name: " << Brief(name());
   os << "\n - expected_nof_properties: " << expected_nof_properties();
@@ -826,7 +794,7 @@
 }
 
 
-void JSGlobalProxy::JSGlobalProxyPrint(OStream& os) {  // NOLINT
+void JSGlobalProxy::JSGlobalProxyPrint(std::ostream& os) {  // NOLINT
   os << "global_proxy ";
   JSObjectPrint(os);
   os << "native context : " << Brief(native_context());
@@ -834,7 +802,7 @@
 }
 
 
-void JSGlobalObject::JSGlobalObjectPrint(OStream& os) {  // NOLINT
+void JSGlobalObject::JSGlobalObjectPrint(std::ostream& os) {  // NOLINT
   os << "global ";
   JSObjectPrint(os);
   os << "native context : " << Brief(native_context());
@@ -842,23 +810,33 @@
 }
 
 
-void JSBuiltinsObject::JSBuiltinsObjectPrint(OStream& os) {  // NOLINT
+void JSBuiltinsObject::JSBuiltinsObjectPrint(std::ostream& os) {  // NOLINT
   os << "builtins ";
   JSObjectPrint(os);
 }
 
 
-void Cell::CellPrint(OStream& os) {  // NOLINT
+void Cell::CellPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "Cell");
 }
 
 
-void PropertyCell::PropertyCellPrint(OStream& os) {  // NOLINT
+void PropertyCell::PropertyCellPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "PropertyCell");
 }
 
 
-void Code::CodePrint(OStream& os) {  // NOLINT
+void WeakCell::WeakCellPrint(std::ostream& os) {  // NOLINT
+  HeapObject::PrintHeader(os, "WeakCell");
+  if (cleared()) {
+    os << "\n - cleared";
+  } else {
+    os << "\n - value: " << Brief(value());
+  }
+}
+
+
+void Code::CodePrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "Code");
 #ifdef ENABLE_DISASSEMBLER
   if (FLAG_use_verbose_printer) {
@@ -868,13 +846,13 @@
 }
 
 
-void Foreign::ForeignPrint(OStream& os) {  // NOLINT
+void Foreign::ForeignPrint(std::ostream& os) {  // NOLINT
   os << "foreign address : " << foreign_address();
 }
 
 
 void ExecutableAccessorInfo::ExecutableAccessorInfoPrint(
-    OStream& os) {  // NOLINT
+    std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "ExecutableAccessorInfo");
   os << "\n - name: " << Brief(name());
   os << "\n - flag: " << Brief(flag());
@@ -885,7 +863,8 @@
 }
 
 
-void DeclaredAccessorInfo::DeclaredAccessorInfoPrint(OStream& os) {  // NOLINT
+void DeclaredAccessorInfo::DeclaredAccessorInfoPrint(
+    std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "DeclaredAccessorInfo");
   os << "\n - name: " << Brief(name());
   os << "\n - flag: " << Brief(flag());
@@ -895,21 +874,21 @@
 
 
 void DeclaredAccessorDescriptor::DeclaredAccessorDescriptorPrint(
-    OStream& os) {  // NOLINT
+    std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "DeclaredAccessorDescriptor");
   os << "\n - internal field: " << Brief(serialized_data());
   os << "\n";
 }
 
 
-void Box::BoxPrint(OStream& os) {  // NOLINT
+void Box::BoxPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "Box");
   os << "\n - value: " << Brief(value());
   os << "\n";
 }
 
 
-void AccessorPair::AccessorPairPrint(OStream& os) {  // NOLINT
+void AccessorPair::AccessorPairPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "AccessorPair");
   os << "\n - getter: " << Brief(getter());
   os << "\n - setter: " << Brief(setter());
@@ -917,7 +896,7 @@
 }
 
 
-void AccessCheckInfo::AccessCheckInfoPrint(OStream& os) {  // NOLINT
+void AccessCheckInfo::AccessCheckInfoPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "AccessCheckInfo");
   os << "\n - named_callback: " << Brief(named_callback());
   os << "\n - indexed_callback: " << Brief(indexed_callback());
@@ -926,7 +905,7 @@
 }
 
 
-void InterceptorInfo::InterceptorInfoPrint(OStream& os) {  // NOLINT
+void InterceptorInfo::InterceptorInfoPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "InterceptorInfo");
   os << "\n - getter: " << Brief(getter());
   os << "\n - setter: " << Brief(setter());
@@ -938,7 +917,7 @@
 }
 
 
-void CallHandlerInfo::CallHandlerInfoPrint(OStream& os) {  // NOLINT
+void CallHandlerInfo::CallHandlerInfoPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "CallHandlerInfo");
   os << "\n - callback: " << Brief(callback());
   os << "\n - data: " << Brief(data());
@@ -946,7 +925,8 @@
 }
 
 
-void FunctionTemplateInfo::FunctionTemplateInfoPrint(OStream& os) {  // NOLINT
+void FunctionTemplateInfo::FunctionTemplateInfoPrint(
+    std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "FunctionTemplateInfo");
   os << "\n - class name: " << Brief(class_name());
   os << "\n - tag: " << Brief(tag());
@@ -968,7 +948,7 @@
 }
 
 
-void ObjectTemplateInfo::ObjectTemplateInfoPrint(OStream& os) {  // NOLINT
+void ObjectTemplateInfo::ObjectTemplateInfoPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "ObjectTemplateInfo");
   os << " - tag: " << Brief(tag());
   os << "\n - property_list: " << Brief(property_list());
@@ -979,7 +959,7 @@
 }
 
 
-void SignatureInfo::SignatureInfoPrint(OStream& os) {  // NOLINT
+void SignatureInfo::SignatureInfoPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "SignatureInfo");
   os << "\n - receiver: " << Brief(receiver());
   os << "\n - args: " << Brief(args());
@@ -987,14 +967,14 @@
 }
 
 
-void TypeSwitchInfo::TypeSwitchInfoPrint(OStream& os) {  // NOLINT
+void TypeSwitchInfo::TypeSwitchInfoPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "TypeSwitchInfo");
   os << "\n - types: " << Brief(types());
   os << "\n";
 }
 
 
-void AllocationSite::AllocationSitePrint(OStream& os) {  // NOLINT
+void AllocationSite::AllocationSitePrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "AllocationSite");
   os << " - weak_next: " << Brief(weak_next());
   os << "\n - dependent code: " << Brief(dependent_code());
@@ -1018,7 +998,7 @@
 }
 
 
-void AllocationMemento::AllocationMementoPrint(OStream& os) {  // NOLINT
+void AllocationMemento::AllocationMementoPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "AllocationMemento");
   os << " - allocation site: ";
   if (IsValid()) {
@@ -1029,7 +1009,7 @@
 }
 
 
-void Script::ScriptPrint(OStream& os) {  // NOLINT
+void Script::ScriptPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "Script");
   os << "\n - source: " << Brief(source());
   os << "\n - name: " << Brief(name());
@@ -1048,7 +1028,7 @@
 }
 
 
-void DebugInfo::DebugInfoPrint(OStream& os) {  // NOLINT
+void DebugInfo::DebugInfoPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "DebugInfo");
   os << "\n - shared: " << Brief(shared());
   os << "\n - original_code: " << Brief(original_code());
@@ -1058,7 +1038,7 @@
 }
 
 
-void BreakPointInfo::BreakPointInfoPrint(OStream& os) {  // NOLINT
+void BreakPointInfo::BreakPointInfoPrint(std::ostream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "BreakPointInfo");
   os << "\n - code_position: " << code_position()->value();
   os << "\n - source_position: " << source_position()->value();
@@ -1068,38 +1048,37 @@
 }
 
 
-void DescriptorArray::PrintDescriptors(OStream& os) {  // NOLINT
-  os << "Descriptor array  " << number_of_descriptors() << "\n";
-  for (int i = 0; i < number_of_descriptors(); i++) {
-    Descriptor desc;
-    Get(i, &desc);
-    os << " " << i << ": " << desc;
+static void PrintBitMask(std::ostream& os, uint32_t value) {  // NOLINT
+  for (int i = 0; i < 32; i++) {
+    if ((i & 7) == 0) os << " ";
+    os << (((value & 1) == 0) ? "_" : "x");
+    value >>= 1;
   }
-  os << "\n";
 }
 
 
-void TransitionArray::PrintTransitions(OStream& os) {  // NOLINT
-  os << "Transition array  %d\n", number_of_transitions();
-  for (int i = 0; i < number_of_transitions(); i++) {
-    os << " " << i << ": ";
-    GetKey(i)->NamePrint(os);
-    os << ": ";
-    switch (GetTargetDetails(i).type()) {
-      case FIELD: {
-        os << " (transition to field)\n";
-        break;
-      }
-      case CONSTANT:
-        os << " (transition to constant)\n";
-        break;
-      case CALLBACKS:
-        os << " (transition to callback)\n";
-        break;
-      // Values below are never in the target descriptor array.
-      case NORMAL:
-        UNREACHABLE();
-        break;
+void LayoutDescriptor::Print() {
+  OFStream os(stdout);
+  this->Print(os);
+  os << std::flush;
+}
+
+
+void LayoutDescriptor::Print(std::ostream& os) {  // NOLINT
+  os << "Layout descriptor: ";
+  if (IsUninitialized()) {
+    os << "<uninitialized>";
+  } else if (IsFastPointerLayout()) {
+    os << "<all tagged>";
+  } else if (IsSmi()) {
+    os << "fast";
+    PrintBitMask(os, static_cast<uint32_t>(Smi::cast(this)->value()));
+  } else {
+    os << "slow";
+    int len = length();
+    for (int i = 0; i < len; i++) {
+      if (i > 0) os << " |";
+      PrintBitMask(os, get_scalar(i));
     }
   }
   os << "\n";
@@ -1109,4 +1088,130 @@
 #endif  // OBJECT_PRINT
 
 
+#if TRACE_MAPS
+
+
+void Name::NameShortPrint() {
+  if (this->IsString()) {
+    PrintF("%s", String::cast(this)->ToCString().get());
+  } else {
+    DCHECK(this->IsSymbol());
+    Symbol* s = Symbol::cast(this);
+    if (s->name()->IsUndefined()) {
+      PrintF("#<%s>", s->PrivateSymbolToName());
+    } else {
+      PrintF("<%s>", String::cast(s->name())->ToCString().get());
+    }
+  }
+}
+
+
+int Name::NameShortPrint(Vector<char> str) {
+  if (this->IsString()) {
+    return SNPrintF(str, "%s", String::cast(this)->ToCString().get());
+  } else {
+    DCHECK(this->IsSymbol());
+    Symbol* s = Symbol::cast(this);
+    if (s->name()->IsUndefined()) {
+      return SNPrintF(str, "#<%s>", s->PrivateSymbolToName());
+    } else {
+      return SNPrintF(str, "<%s>", String::cast(s->name())->ToCString().get());
+    }
+  }
+}
+
+
+#endif  // TRACE_MAPS
+
+
+#if defined(DEBUG) || defined(OBJECT_PRINT)
+// This method is only meant to be called from gdb for debugging purposes.
+// Since the string can also be in two-byte encoding, non-Latin1 characters
+// will be ignored in the output.
+char* String::ToAsciiArray() {
+  // Static so that subsequent calls frees previously allocated space.
+  // This also means that previous results will be overwritten.
+  static char* buffer = NULL;
+  if (buffer != NULL) delete[] buffer;
+  buffer = new char[length() + 1];
+  WriteToFlat(this, reinterpret_cast<uint8_t*>(buffer), 0, length());
+  buffer[length()] = 0;
+  return buffer;
+}
+
+
+void DescriptorArray::Print() {
+  OFStream os(stdout);
+  this->PrintDescriptors(os);
+  os << std::flush;
+}
+
+
+void DescriptorArray::PrintDescriptors(std::ostream& os) {  // NOLINT
+  HandleScope scope(GetIsolate());
+  os << "Descriptor array " << number_of_descriptors() << "\n";
+  for (int i = 0; i < number_of_descriptors(); i++) {
+    Descriptor desc;
+    Get(i, &desc);
+    os << " " << i << ": " << desc << "\n";
+  }
+  os << "\n";
+}
+
+
+void TransitionArray::Print() {
+  OFStream os(stdout);
+  this->PrintTransitions(os);
+  os << std::flush;
+}
+
+
+void TransitionArray::PrintTransitions(std::ostream& os,
+                                       bool print_header) {  // NOLINT
+  if (print_header) {
+    os << "Transition array " << number_of_transitions() << "\n";
+  }
+  for (int i = 0; i < number_of_transitions(); i++) {
+    Name* key = GetKey(i);
+    Map* target = GetTarget(i);
+    os << "   ";
+#ifdef OBJECT_PRINT
+    key->NamePrint(os);
+#else
+    key->ShortPrint(os);
+#endif
+    os << ": ";
+    if (key == GetHeap()->nonextensible_symbol()) {
+      os << " (transition to non-extensible)";
+    } else if (key == GetHeap()->sealed_symbol()) {
+      os << " (transition to sealed)";
+    } else if (key == GetHeap()->frozen_symbol()) {
+      os << " (transition to frozen)";
+    } else if (key == GetHeap()->elements_transition_symbol()) {
+      os << " (transition to " << ElementsKindToString(target->elements_kind())
+         << ")";
+    } else if (key == GetHeap()->observed_symbol()) {
+      os << " (transition to Object.observe)";
+    } else {
+      PropertyDetails details = GetTargetDetails(key, target);
+      os << " (transition to ";
+      if (details.location() == IN_DESCRIPTOR) {
+        os << "immutable ";
+      }
+      os << (details.kind() == DATA ? "data" : "accessor");
+      if (details.location() == IN_DESCRIPTOR) {
+        os << " " << Brief(GetTargetValue(i));
+      }
+      os << "), attrs: " << details.attributes();
+    }
+    os << " -> " << Brief(target) << "\n";
+  }
+}
+
+
+void JSObject::PrintTransitions(std::ostream& os) {  // NOLINT
+  if (!map()->HasTransitionArray()) return;
+  map()->transitions()->PrintTransitions(os, false);
+}
+#endif  // defined(DEBUG) || defined(OBJECT_PRINT)
 } }  // namespace v8::internal
diff --git a/src/objects.cc b/src/objects.cc
index 39d3d7c..6b64c3f 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <sstream>
+
 #include "src/v8.h"
 
 #include "src/accessors.h"
@@ -540,9 +542,8 @@
   Debug* debug = isolate->debug();
   // Handle stepping into a getter if step into is active.
   // TODO(rossberg): should this apply to getters that are function proxies?
-  if (debug->StepInActive() && getter->IsJSFunction()) {
-    debug->HandleStepIn(
-        Handle<JSFunction>::cast(getter), Handle<Object>::null(), 0, false);
+  if (debug->is_active()) {
+    debug->HandleStepIn(getter, Handle<Object>::null(), 0, false);
   }
 
   return Execution::Call(isolate, getter, receiver, 0, NULL, true);
@@ -558,9 +559,8 @@
   Debug* debug = isolate->debug();
   // Handle stepping into a setter if step into is active.
   // TODO(rossberg): should this apply to getters that are function proxies?
-  if (debug->StepInActive() && setter->IsJSFunction()) {
-    debug->HandleStepIn(
-        Handle<JSFunction>::cast(setter), Handle<Object>::null(), 0, false);
+  if (debug->is_active()) {
+    debug->HandleStepIn(setter, Handle<Object>::null(), 0, false);
   }
 
   Handle<Object> argv[] = { value };
@@ -572,12 +572,19 @@
 
 
 static bool FindAllCanReadHolder(LookupIterator* it) {
-  for (; it->IsFound(); it->Next()) {
+  // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
+  // which have already been checked.
+  DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
+         it->state() == LookupIterator::INTERCEPTOR);
+  for (it->Next(); it->IsFound(); it->Next()) {
     if (it->state() == LookupIterator::ACCESSOR) {
-      Handle<Object> accessors = it->GetAccessors();
+      auto accessors = it->GetAccessors();
       if (accessors->IsAccessorInfo()) {
         if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
       }
+    } else if (it->state() == LookupIterator::INTERCEPTOR) {
+      auto holder = it->GetHolder<JSObject>();
+      if (holder->GetNamedInterceptor()->all_can_read()) return true;
     }
   }
   return false;
@@ -587,10 +594,18 @@
 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
     LookupIterator* it) {
   Handle<JSObject> checked = it->GetHolder<JSObject>();
-  if (FindAllCanReadHolder(it)) {
-    return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
-                                   it->GetHolder<JSObject>(),
-                                   it->GetAccessors());
+  while (FindAllCanReadHolder(it)) {
+    if (it->state() == LookupIterator::ACCESSOR) {
+      return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
+                                     it->GetHolder<JSObject>(),
+                                     it->GetAccessors());
+    }
+    DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
+    auto receiver = Handle<JSObject>::cast(it->GetReceiver());
+    auto result = GetPropertyWithInterceptor(it->GetHolder<JSObject>(),
+                                             receiver, it->name());
+    if (it->isolate()->has_scheduled_exception()) break;
+    if (!result.is_null()) return result;
   }
   it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_GET);
   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
@@ -601,8 +616,16 @@
 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
     LookupIterator* it) {
   Handle<JSObject> checked = it->GetHolder<JSObject>();
-  if (FindAllCanReadHolder(it))
-    return maybe(it->property_details().attributes());
+  while (FindAllCanReadHolder(it)) {
+    if (it->state() == LookupIterator::ACCESSOR) {
+      return maybe(it->property_details().attributes());
+    }
+    DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
+    auto result = GetPropertyAttributesWithInterceptor(
+        it->GetHolder<JSObject>(), it->GetReceiver(), it->name());
+    if (it->isolate()->has_scheduled_exception()) break;
+    if (result.has_value && result.value != ABSENT) return result;
+  }
   it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS);
   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(),
                                       Maybe<PropertyAttributes>());
@@ -708,6 +731,13 @@
         // the hole value.
         Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
         DCHECK(new_map->is_dictionary_map());
+#if TRACE_MAPS
+        if (FLAG_trace_maps) {
+          PrintF("[TraceMaps: GlobalDeleteNormalized from= %p to= %p ]\n",
+                 reinterpret_cast<void*>(object->map()),
+                 reinterpret_cast<void*>(*new_map));
+        }
+#endif
         JSObject::MigrateToMap(object, new_map);
       }
       Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
@@ -729,18 +759,62 @@
 }
 
 
-bool JSObject::IsDirty() {
-  Object* cons_obj = map()->constructor();
-  if (!cons_obj->IsJSFunction())
-    return true;
-  JSFunction* fun = JSFunction::cast(cons_obj);
-  if (!fun->shared()->IsApiFunction())
-    return true;
-  // If the object is fully fast case and has the same map it was
-  // created with then no changes can have been made to it.
-  return map() != fun->initial_map()
-      || !HasFastObjectElements()
-      || !HasFastProperties();
+static MaybeHandle<JSObject> FindIndexedAllCanReadHolder(
+    Isolate* isolate, Handle<JSObject> js_object,
+    PrototypeIterator::WhereToStart where_to_start) {
+  for (PrototypeIterator iter(isolate, js_object, where_to_start);
+       !iter.IsAtEnd(); iter.Advance()) {
+    auto curr = PrototypeIterator::GetCurrent(iter);
+    if (!curr->IsJSObject()) break;
+    auto obj = Handle<JSObject>::cast(curr);
+    if (!obj->HasIndexedInterceptor()) continue;
+    if (obj->GetIndexedInterceptor()->all_can_read()) return obj;
+  }
+  return MaybeHandle<JSObject>();
+}
+
+
+MaybeHandle<Object> JSObject::GetElementWithFailedAccessCheck(
+    Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver,
+    uint32_t index) {
+  Handle<JSObject> holder = object;
+  PrototypeIterator::WhereToStart where_to_start =
+      PrototypeIterator::START_AT_RECEIVER;
+  while (true) {
+    auto all_can_read_holder =
+        FindIndexedAllCanReadHolder(isolate, holder, where_to_start);
+    if (!all_can_read_holder.ToHandle(&holder)) break;
+    auto result =
+        JSObject::GetElementWithInterceptor(holder, receiver, index, false);
+    if (isolate->has_scheduled_exception()) break;
+    if (!result.is_null()) return result;
+    where_to_start = PrototypeIterator::START_AT_PROTOTYPE;
+  }
+  isolate->ReportFailedAccessCheck(object, v8::ACCESS_GET);
+  RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
+  return isolate->factory()->undefined_value();
+}
+
+
+Maybe<PropertyAttributes> JSObject::GetElementAttributesWithFailedAccessCheck(
+    Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver,
+    uint32_t index) {
+  Handle<JSObject> holder = object;
+  PrototypeIterator::WhereToStart where_to_start =
+      PrototypeIterator::START_AT_RECEIVER;
+  while (true) {
+    auto all_can_read_holder =
+        FindIndexedAllCanReadHolder(isolate, holder, where_to_start);
+    if (!all_can_read_holder.ToHandle(&holder)) break;
+    auto result =
+        JSObject::GetElementAttributeFromInterceptor(object, receiver, index);
+    if (isolate->has_scheduled_exception()) break;
+    if (result.has_value && result.value != ABSENT) return result;
+    where_to_start = PrototypeIterator::START_AT_PROTOTYPE;
+  }
+  isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS);
+  RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
+  return maybe(ABSENT);
 }
 
 
@@ -776,14 +850,14 @@
     // Check access rights if needed.
     if (js_object->IsAccessCheckNeeded()) {
       if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
-        isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
-        RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
-        return isolate->factory()->undefined_value();
+        return JSObject::GetElementWithFailedAccessCheck(isolate, js_object,
+                                                         receiver, index);
       }
     }
 
     if (js_object->HasIndexedInterceptor()) {
-      return JSObject::GetElementWithInterceptor(js_object, receiver, index);
+      return JSObject::GetElementWithInterceptor(js_object, receiver, index,
+                                                 true);
     }
 
     if (js_object->elements() != isolate->heap()->empty_fixed_array()) {
@@ -800,6 +874,82 @@
 }
 
 
+MaybeHandle<Object> Object::SetElementWithReceiver(
+    Isolate* isolate, Handle<Object> object, Handle<Object> receiver,
+    uint32_t index, Handle<Object> value, StrictMode strict_mode) {
+  // Iterate up the prototype chain until an element is found or the null
+  // prototype is encountered.
+  bool done = false;
+  for (PrototypeIterator iter(isolate, object,
+                              object->IsJSProxy() || object->IsJSObject()
+                                  ? PrototypeIterator::START_AT_RECEIVER
+                                  : PrototypeIterator::START_AT_PROTOTYPE);
+       !iter.IsAtEnd() && !done; iter.Advance()) {
+    if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
+      // TODO(dslomov): implement.
+      isolate->ThrowIllegalOperation();
+      return MaybeHandle<Object>();
+    }
+
+    Handle<JSObject> js_object =
+        Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+
+    // Check access rights if needed.
+    if (js_object->IsAccessCheckNeeded()) {
+      if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_SET)) {
+        isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_SET);
+        RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
+        return isolate->factory()->undefined_value();
+      }
+    }
+
+    if (js_object->HasIndexedInterceptor()) {
+      Maybe<PropertyAttributes> from_interceptor =
+          JSObject::GetElementAttributeFromInterceptor(js_object, receiver,
+                                                       index);
+      if (!from_interceptor.has_value) return MaybeHandle<Object>();
+      if ((from_interceptor.value & READ_ONLY) != 0) {
+        return WriteToReadOnlyElement(isolate, receiver, index, value,
+                                      strict_mode);
+      }
+      done = from_interceptor.value != ABSENT;
+    }
+
+    if (!done &&
+        js_object->elements() != isolate->heap()->empty_fixed_array()) {
+      ElementsAccessor* accessor = js_object->GetElementsAccessor();
+      PropertyAttributes attrs =
+          accessor->GetAttributes(receiver, js_object, index);
+      if ((attrs & READ_ONLY) != 0) {
+        return WriteToReadOnlyElement(isolate, receiver, index, value,
+                                      strict_mode);
+      }
+      Handle<AccessorPair> accessor_pair;
+      if (accessor->GetAccessorPair(receiver, js_object, index)
+              .ToHandle(&accessor_pair)) {
+        return JSObject::SetElementWithCallback(receiver, accessor_pair, index,
+                                                value, js_object, strict_mode);
+      } else {
+        done = attrs != ABSENT;
+      }
+    }
+  }
+
+  if (!receiver->IsJSObject()) {
+    return WriteToReadOnlyElement(isolate, receiver, index, value, strict_mode);
+  }
+  Handle<JSObject> target = Handle<JSObject>::cast(receiver);
+  ElementsAccessor* accessor = target->GetElementsAccessor();
+  PropertyAttributes attrs = accessor->GetAttributes(receiver, target, index);
+  if ((attrs & READ_ONLY) != 0) {
+    return WriteToReadOnlyElement(isolate, receiver, index, value, strict_mode);
+  }
+  PropertyAttributes new_attrs = attrs != ABSENT ? attrs : NONE;
+  return JSObject::SetElement(target, index, value, new_attrs, strict_mode,
+                              false);
+}
+
+
 Map* Object::GetRootMap(Isolate* isolate) {
   DisallowHeapAllocation no_alloc;
   if (IsSmi()) {
@@ -909,13 +1059,16 @@
 
 
 void Object::ShortPrint(StringStream* accumulator) {
-  OStringStream os;
+  std::ostringstream os;
   os << Brief(this);
-  accumulator->Add(os.c_str());
+  accumulator->Add(os.str().c_str());
 }
 
 
-OStream& operator<<(OStream& os, const Brief& v) {
+void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
+
+
+std::ostream& operator<<(std::ostream& os, const Brief& v) {
   if (v.value->IsSmi()) {
     Smi::cast(v.value)->SmiPrint(os);
   } else {
@@ -927,7 +1080,7 @@
 }
 
 
-void Smi::SmiPrint(OStream& os) const {  // NOLINT
+void Smi::SmiPrint(std::ostream& os) const {  // NOLINT
   os << value();
 }
 
@@ -1120,8 +1273,7 @@
     return;
   }
 
-  ConsStringIteratorOp op;
-  StringCharacterStream stream(this, &op);
+  StringCharacterStream stream(this);
 
   bool truncated = false;
   if (len > kMaxShortPrintLength) {
@@ -1172,10 +1324,9 @@
 }
 
 
-void String::PrintUC16(OStream& os, int start, int end) {  // NOLINT
+void String::PrintUC16(std::ostream& os, int start, int end) {  // NOLINT
   if (end < 0) end = length();
-  ConsStringIteratorOp op;
-  StringCharacterStream stream(this, &op, start);
+  StringCharacterStream stream(this, start);
   for (int i = start; i < end && stream.HasMore(); i++) {
     os << AsUC16(stream.GetNext());
   }
@@ -1371,7 +1522,7 @@
 }
 
 
-void HeapObject::HeapObjectShortPrint(OStream& os) {  // NOLINT
+void HeapObject::HeapObjectShortPrint(std::ostream& os) {  // NOLINT
   Heap* heap = GetHeap();
   if (!heap->Contains(this)) {
     os << "!!!INVALID POINTER!!!";
@@ -1471,15 +1622,7 @@
     }
     case SYMBOL_TYPE: {
       Symbol* symbol = Symbol::cast(this);
-      os << "<Symbol: " << symbol->Hash();
-      if (!symbol->name()->IsUndefined()) {
-        os << " ";
-        HeapStringAllocator allocator;
-        StringStream accumulator(&allocator);
-        String::cast(symbol->name())->StringShortPrint(&accumulator);
-        os << accumulator.ToCString().get();
-      }
-      os << ">";
+      symbol->SymbolShortPrint(os);
       break;
     }
     case HEAP_NUMBER_TYPE: {
@@ -1519,6 +1662,14 @@
       os << accumulator.ToCString().get();
       break;
     }
+    case WEAK_CELL_TYPE: {
+      os << "WeakCell for ";
+      HeapStringAllocator allocator;
+      StringStream accumulator(&allocator);
+      WeakCell::cast(this)->value()->ShortPrint(&accumulator);
+      os << accumulator.ToCString().get();
+      break;
+    }
     default:
       os << "<Other heap object (" << map()->instance_type() << ")>";
       break;
@@ -1622,6 +1773,9 @@
     case PROPERTY_CELL_TYPE:
       PropertyCell::BodyDescriptor::IterateBody(this, v);
       break;
+    case WEAK_CELL_TYPE:
+      WeakCell::BodyDescriptor::IterateBody(this, v);
+      break;
     case SYMBOL_TYPE:
       Symbol::BodyDescriptor::IterateBody(this, v);
       break;
@@ -1668,7 +1822,7 @@
 }
 
 
-void HeapNumber::HeapNumberPrint(OStream& os) {  // NOLINT
+void HeapNumber::HeapNumberPrint(std::ostream& os) {  // NOLINT
   os << value();
 }
 
@@ -1775,7 +1929,7 @@
       // Assign an enumeration index to the property and update
       // SetNextEnumerationIndex.
       int index = dict->NextEnumerationIndex();
-      PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
+      PropertyDetails details(attributes, FIELD, index);
       dict->SetNextEnumerationIndex(index + 1);
       dict->SetEntry(entry, name, cell, details);
       return;
@@ -1784,7 +1938,7 @@
     PropertyCell::SetValueInferType(cell, value);
     value = cell;
   }
-  PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
+  PropertyDetails details(attributes, FIELD, 0);
   Handle<NameDictionary> result =
       NameDictionary::Add(dict, name, value, details);
   if (*dict != *result) object->set_properties(*result);
@@ -1806,10 +1960,10 @@
 }
 
 
-void JSObject::EnqueueChangeRecord(Handle<JSObject> object,
-                                   const char* type_str,
-                                   Handle<Name> name,
-                                   Handle<Object> old_value) {
+MaybeHandle<Object> JSObject::EnqueueChangeRecord(Handle<JSObject> object,
+                                                  const char* type_str,
+                                                  Handle<Name> name,
+                                                  Handle<Object> old_value) {
   DCHECK(!object->IsJSGlobalProxy());
   DCHECK(!object->IsJSGlobalObject());
   Isolate* isolate = object->GetIsolate();
@@ -1818,10 +1972,9 @@
   Handle<Object> args[] = { type, object, name, old_value };
   int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4;
 
-  Execution::Call(isolate,
-                  Handle<JSFunction>(isolate->observers_notify_change()),
-                  isolate->factory()->undefined_value(),
-                  argc, args).Assert();
+  return Execution::Call(isolate,
+                         Handle<JSFunction>(isolate->observers_notify_change()),
+                         isolate->factory()->undefined_value(), argc, args);
 }
 
 
@@ -1879,7 +2032,7 @@
 void Map::ConnectElementsTransition(Handle<Map> parent, Handle<Map> child) {
   Isolate* isolate = parent->GetIsolate();
   Handle<Name> name = isolate->factory()->elements_transition_symbol();
-  ConnectTransition(parent, child, name, FULL_TRANSITION);
+  ConnectTransition(parent, child, name, SPECIAL_TRANSITION);
 }
 
 
@@ -1893,7 +2046,8 @@
         // Clear out the old descriptor array to avoid problems to sharing
         // the descriptor array without using an explicit.
         old_map->InitializeDescriptors(
-            old_map->GetHeap()->empty_descriptor_array());
+            old_map->GetHeap()->empty_descriptor_array(),
+            LayoutDescriptor::FastPointerLayout());
         // Ensure that no transition was inserted for prototype migrations.
         DCHECK(!old_map->HasTransitionArray());
         DCHECK(new_map->GetBackPointer()->IsUndefined());
@@ -1952,17 +2106,21 @@
 
     if (old_map->unused_property_fields() > 0) {
       if (details.representation().IsDouble()) {
-        Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
         FieldIndex index =
             FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
-        object->FastPropertyAtPut(index, *value);
+        if (new_map->IsUnboxedDoubleField(index)) {
+          object->RawFastDoublePropertyAtPut(index, 0);
+        } else {
+          Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
+          object->RawFastPropertyAtPut(index, *value);
+        }
       }
       object->synchronized_set_map(*new_map);
       return;
     }
 
     DCHECK(number_of_fields == old_number_of_fields + 1);
-    // This migration is a transition from a map that has run out out property
+    // This migration is a transition from a map that has run out of property
     // space. Therefore it could be done by extending the backing store.
     Handle<FixedArray> old_storage = handle(object->properties(), isolate);
     Handle<FixedArray> new_storage =
@@ -2007,23 +2165,35 @@
       DCHECK(details.representation().IsTagged());
       continue;
     }
+    Representation old_representation = old_details.representation();
+    Representation representation = details.representation();
     DCHECK(old_details.type() == CONSTANT ||
            old_details.type() == FIELD);
-    Object* raw_value = old_details.type() == CONSTANT
-        ? old_descriptors->GetValue(i)
-        : object->RawFastPropertyAt(FieldIndex::ForDescriptor(*old_map, i));
-    Handle<Object> value(raw_value, isolate);
-    if (!old_details.representation().IsDouble() &&
-        details.representation().IsDouble()) {
-      if (old_details.representation().IsNone()) {
-        value = handle(Smi::FromInt(0), isolate);
+    Handle<Object> value;
+    if (old_details.type() == CONSTANT) {
+      value = handle(old_descriptors->GetValue(i), isolate);
+      DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
+    } else {
+      FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
+      if (object->IsUnboxedDoubleField(index)) {
+        double old = object->RawFastDoublePropertyAt(index);
+        value = isolate->factory()->NewHeapNumber(
+            old, representation.IsDouble() ? MUTABLE : IMMUTABLE);
+
+      } else {
+        value = handle(object->RawFastPropertyAt(index), isolate);
+        if (!old_representation.IsDouble() && representation.IsDouble()) {
+          if (old_representation.IsNone()) {
+            value = handle(Smi::FromInt(0), isolate);
+          }
+          value = Object::NewStorageFor(isolate, value, representation);
+        } else if (old_representation.IsDouble() &&
+                   !representation.IsDouble()) {
+          value = Object::WrapForRead(isolate, value, old_representation);
+        }
       }
-      value = Object::NewStorageFor(isolate, value, details.representation());
-    } else if (old_details.representation().IsDouble() &&
-               !details.representation().IsDouble()) {
-      value = Object::WrapForRead(isolate, value, old_details.representation());
     }
-    DCHECK(!(details.representation().IsDouble() && value->IsSmi()));
+    DCHECK(!(representation.IsDouble() && value->IsSmi()));
     int target_index = new_descriptors->GetFieldIndex(i) - inobject;
     if (target_index < 0) target_index += total_size;
     array->set(target_index, *value);
@@ -2051,7 +2221,16 @@
   int limit = Min(inobject, number_of_fields);
   for (int i = 0; i < limit; i++) {
     FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
-    object->FastPropertyAtPut(index, array->get(external + i));
+    Object* value = array->get(external + i);
+    // Can't use JSObject::FastPropertyAtPut() because proper map was not set
+    // yet.
+    if (new_map->IsUnboxedDoubleField(index)) {
+      DCHECK(value->IsMutableHeapNumber());
+      object->RawFastDoublePropertyAtPut(index,
+                                         HeapNumber::cast(value)->value());
+    } else {
+      object->RawFastPropertyAtPut(index, value);
+    }
   }
 
   Heap* heap = isolate->heap();
@@ -2081,17 +2260,6 @@
 }
 
 
-void JSObject::GeneralizeFieldRepresentation(Handle<JSObject> object,
-                                             int modify_index,
-                                             Representation new_representation,
-                                             Handle<HeapType> new_field_type) {
-  Handle<Map> new_map = Map::GeneralizeRepresentation(
-      handle(object->map()), modify_index, new_representation, new_field_type,
-      FORCE_FIELD);
-  MigrateToMap(object, new_map);
-}
-
-
 int Map::NumberOfFields() {
   DescriptorArray* descriptors = instance_descriptors();
   int result = 0;
@@ -2108,20 +2276,27 @@
                                                   PropertyAttributes attributes,
                                                   const char* reason) {
   Isolate* isolate = map->GetIsolate();
-  Handle<Map> new_map = Copy(map);
+  Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
+  int number_of_own_descriptors = map->NumberOfOwnDescriptors();
+  Handle<DescriptorArray> descriptors =
+      DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors);
 
-  DescriptorArray* descriptors = new_map->instance_descriptors();
-  int length = descriptors->number_of_descriptors();
-  for (int i = 0; i < length; i++) {
+  for (int i = 0; i < number_of_own_descriptors; i++) {
     descriptors->SetRepresentation(i, Representation::Tagged());
     if (descriptors->GetDetails(i).type() == FIELD) {
       descriptors->SetValue(i, HeapType::Any());
     }
   }
 
+  Handle<LayoutDescriptor> new_layout_descriptor(
+      LayoutDescriptor::FastPointerLayout(), isolate);
+  Handle<Map> new_map = CopyReplaceDescriptors(
+      map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
+      MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
+
   // Unless the instance is being migrated, ensure that modify_index is a field.
   PropertyDetails details = descriptors->GetDetails(modify_index);
-  if (store_mode == FORCE_FIELD &&
+  if (store_mode == FORCE_IN_OBJECT &&
       (details.type() != FIELD || details.attributes() != attributes)) {
     int field_index = details.type() == FIELD ? details.field_index()
                                               : new_map->NumberOfFields();
@@ -2143,12 +2318,12 @@
     HeapType* field_type = (details.type() == FIELD)
         ? map->instance_descriptors()->GetFieldType(modify_index)
         : NULL;
-    map->PrintGeneralization(stdout, reason, modify_index,
-                        new_map->NumberOfOwnDescriptors(),
-                        new_map->NumberOfOwnDescriptors(),
-                        details.type() == CONSTANT && store_mode == FORCE_FIELD,
-                        details.representation(), Representation::Tagged(),
-                        field_type, HeapType::Any());
+    map->PrintGeneralization(
+        stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
+        new_map->NumberOfOwnDescriptors(),
+        details.type() == CONSTANT && store_mode == FORCE_IN_OBJECT,
+        details.representation(), Representation::Tagged(), field_type,
+        HeapType::Any());
   }
   return new_map;
 }
@@ -2184,30 +2359,37 @@
 // Invalidates a transition target at |key|, and installs |new_descriptors| over
 // the current instance_descriptors to ensure proper sharing of descriptor
 // arrays.
-void Map::DeprecateTarget(Name* key, DescriptorArray* new_descriptors) {
+// Returns true if the transition target at given key was deprecated.
+bool Map::DeprecateTarget(PropertyKind kind, Name* key,
+                          PropertyAttributes attributes,
+                          DescriptorArray* new_descriptors,
+                          LayoutDescriptor* new_layout_descriptor) {
+  bool transition_target_deprecated = false;
   if (HasTransitionArray()) {
     TransitionArray* transitions = this->transitions();
-    int transition = transitions->Search(key);
+    int transition = transitions->Search(kind, key, attributes);
     if (transition != TransitionArray::kNotFound) {
       transitions->GetTarget(transition)->DeprecateTransitionTree();
+      transition_target_deprecated = true;
     }
   }
 
   // Don't overwrite the empty descriptor array.
-  if (NumberOfOwnDescriptors() == 0) return;
+  if (NumberOfOwnDescriptors() == 0) return transition_target_deprecated;
 
   DescriptorArray* to_replace = instance_descriptors();
   Map* current = this;
   GetHeap()->incremental_marking()->RecordWrites(to_replace);
   while (current->instance_descriptors() == to_replace) {
     current->SetEnumLength(kInvalidEnumCacheSentinel);
-    current->set_instance_descriptors(new_descriptors);
+    current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
     Object* next = current->GetBackPointer();
     if (next->IsUndefined()) break;
     current = Map::cast(next);
   }
 
   set_owns_descriptors(false);
+  return transition_target_deprecated;
 }
 
 
@@ -2234,14 +2416,15 @@
   for (int i = verbatim; i < length; i++) {
     if (!current->HasTransitionArray()) break;
     Name* name = descriptors->GetKey(i);
+    PropertyDetails details = descriptors->GetDetails(i);
     TransitionArray* transitions = current->transitions();
-    int transition = transitions->Search(name);
+    int transition =
+        transitions->Search(details.kind(), name, details.attributes());
     if (transition == TransitionArray::kNotFound) break;
 
     Map* next = transitions->GetTarget(transition);
     DescriptorArray* next_descriptors = next->instance_descriptors();
 
-    PropertyDetails details = descriptors->GetDetails(i);
     PropertyDetails next_details = next_descriptors->GetDetails(i);
     if (details.type() != next_details.type()) break;
     if (details.attributes() != next_details.attributes()) break;
@@ -2275,6 +2458,7 @@
 
 
 void Map::UpdateFieldType(int descriptor, Handle<Name> name,
+                          Representation new_representation,
                           Handle<HeapType> new_type) {
   DisallowHeapAllocation no_allocation;
   PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
@@ -2282,13 +2466,18 @@
   if (HasTransitionArray()) {
     TransitionArray* transitions = this->transitions();
     for (int i = 0; i < transitions->number_of_transitions(); ++i) {
-      transitions->GetTarget(i)->UpdateFieldType(descriptor, name, new_type);
+      transitions->GetTarget(i)
+          ->UpdateFieldType(descriptor, name, new_representation, new_type);
     }
   }
+  // It is allowed to change representation here only from None to something.
+  DCHECK(details.representation().Equals(new_representation) ||
+         details.representation().IsNone());
+
   // Skip if already updated the shared descriptor.
   if (instance_descriptors()->GetFieldType(descriptor) == *new_type) return;
   FieldDescriptor d(name, instance_descriptors()->GetFieldIndex(descriptor),
-                    new_type, details.attributes(), details.representation());
+                    new_type, details.attributes(), new_representation);
   instance_descriptors()->Replace(descriptor, &d);
 }
 
@@ -2314,15 +2503,20 @@
 
 
 // static
-void Map::GeneralizeFieldType(Handle<Map> map,
-                              int modify_index,
+void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
+                              Representation new_representation,
                               Handle<HeapType> new_field_type) {
   Isolate* isolate = map->GetIsolate();
 
   // Check if we actually need to generalize the field type at all.
-  Handle<HeapType> old_field_type(
-      map->instance_descriptors()->GetFieldType(modify_index), isolate);
-  if (new_field_type->NowIs(old_field_type)) {
+  Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
+  Representation old_representation =
+      old_descriptors->GetDetails(modify_index).representation();
+  Handle<HeapType> old_field_type(old_descriptors->GetFieldType(modify_index),
+                                  isolate);
+
+  if (old_representation.Equals(new_representation) &&
+      new_field_type->NowIs(old_field_type)) {
     DCHECK(Map::GeneralizeFieldType(old_field_type,
                                     new_field_type,
                                     isolate)->NowIs(old_field_type));
@@ -2341,7 +2535,8 @@
 
   PropertyDetails details = descriptors->GetDetails(modify_index);
   Handle<Name> name(descriptors->GetKey(modify_index));
-  field_owner->UpdateFieldType(modify_index, name, new_field_type);
+  field_owner->UpdateFieldType(modify_index, name, new_representation,
+                               new_field_type);
   field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
       isolate, DependentCode::kFieldTypeGroup);
 
@@ -2392,12 +2587,9 @@
   // modification to the object, because the default uninitialized value for
   // representation None can be overwritten by both smi and tagged values.
   // Doubles, however, would require a box allocation.
-  if (old_representation.IsNone() &&
-      !new_representation.IsNone() &&
+  if (old_representation.IsNone() && !new_representation.IsNone() &&
       !new_representation.IsDouble()) {
     DCHECK(old_details.type() == FIELD);
-    DCHECK(old_descriptors->GetFieldType(modify_index)->NowIs(
-            HeapType::None()));
     if (FLAG_trace_generalization) {
       old_map->PrintGeneralization(
           stdout, "uninitialized field",
@@ -2406,48 +2598,55 @@
           old_representation, new_representation,
           old_descriptors->GetFieldType(modify_index), *new_field_type);
     }
-    old_descriptors->SetRepresentation(modify_index, new_representation);
-    old_descriptors->SetValue(modify_index, *new_field_type);
+    Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate);
+
+    GeneralizeFieldType(field_owner, modify_index, new_representation,
+                        new_field_type);
+    DCHECK(old_descriptors->GetDetails(modify_index).representation().Equals(
+        new_representation));
+    DCHECK(old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type));
     return old_map;
   }
 
   // Check the state of the root map.
   Handle<Map> root_map(old_map->FindRootMap(), isolate);
   if (!old_map->EquivalentToForTransition(*root_map)) {
-    return CopyGeneralizeAllRepresentations(
-        old_map, modify_index, store_mode, "not equivalent");
+    return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
+                                            "GenAll_NotEquivalent");
   }
   int root_nof = root_map->NumberOfOwnDescriptors();
   if (modify_index < root_nof) {
     PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
-    if ((old_details.type() != FIELD && store_mode == FORCE_FIELD) ||
+    if ((old_details.type() != FIELD && store_mode == FORCE_IN_OBJECT) ||
         (old_details.type() == FIELD &&
          (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
           !new_representation.fits_into(old_details.representation())))) {
-      return CopyGeneralizeAllRepresentations(
-          old_map, modify_index, store_mode, "root modification");
+      return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
+                                              "GenAll_RootModification");
     }
   }
 
   Handle<Map> target_map = root_map;
   for (int i = root_nof; i < old_nof; ++i) {
-    int j = target_map->SearchTransition(old_descriptors->GetKey(i));
+    PropertyDetails old_details = old_descriptors->GetDetails(i);
+    int j = target_map->SearchTransition(old_details.kind(),
+                                         old_descriptors->GetKey(i),
+                                         old_details.attributes());
     if (j == TransitionArray::kNotFound) break;
     Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
     Handle<DescriptorArray> tmp_descriptors = handle(
         tmp_map->instance_descriptors(), isolate);
 
     // Check if target map is incompatible.
-    PropertyDetails old_details = old_descriptors->GetDetails(i);
     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
     PropertyType old_type = old_details.type();
     PropertyType tmp_type = tmp_details.type();
-    if (tmp_details.attributes() != old_details.attributes() ||
-        ((tmp_type == CALLBACKS || old_type == CALLBACKS) &&
-         (tmp_type != old_type ||
-          tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i)))) {
-      return CopyGeneralizeAllRepresentations(
-          old_map, modify_index, store_mode, "incompatible");
+    DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
+    if ((tmp_type == CALLBACKS || old_type == CALLBACKS) &&
+        (tmp_type != old_type ||
+         tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
+      return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
+                                              "GenAll_Incompatible");
     }
     Representation old_representation = old_details.representation();
     Representation tmp_representation = tmp_details.representation();
@@ -2466,7 +2665,7 @@
         old_field_type = GeneralizeFieldType(
             new_field_type, old_field_type, isolate);
       }
-      GeneralizeFieldType(tmp_map, i, old_field_type);
+      GeneralizeFieldType(tmp_map, i, tmp_representation, old_field_type);
     } else if (tmp_type == CONSTANT) {
       if (old_type != CONSTANT ||
           old_descriptors->GetConstant(i) != tmp_descriptors->GetConstant(i)) {
@@ -2484,7 +2683,7 @@
       target_map->instance_descriptors(), isolate);
   int target_nof = target_map->NumberOfOwnDescriptors();
   if (target_nof == old_nof &&
-      (store_mode != FORCE_FIELD ||
+      (store_mode != FORCE_IN_OBJECT ||
        target_descriptors->GetDetails(modify_index).type() == FIELD)) {
     DCHECK(modify_index < target_nof);
     DCHECK(new_representation.fits_into(
@@ -2497,21 +2696,23 @@
 
   // Find the last compatible target map in the transition tree.
   for (int i = target_nof; i < old_nof; ++i) {
-    int j = target_map->SearchTransition(old_descriptors->GetKey(i));
+    PropertyDetails old_details = old_descriptors->GetDetails(i);
+    int j = target_map->SearchTransition(old_details.kind(),
+                                         old_descriptors->GetKey(i),
+                                         old_details.attributes());
     if (j == TransitionArray::kNotFound) break;
     Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
     Handle<DescriptorArray> tmp_descriptors(
         tmp_map->instance_descriptors(), isolate);
 
     // Check if target map is compatible.
-    PropertyDetails old_details = old_descriptors->GetDetails(i);
     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
-    if (tmp_details.attributes() != old_details.attributes() ||
-        ((tmp_details.type() == CALLBACKS || old_details.type() == CALLBACKS) &&
-         (tmp_details.type() != old_details.type() ||
-          tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i)))) {
-      return CopyGeneralizeAllRepresentations(
-          old_map, modify_index, store_mode, "incompatible");
+    DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
+    if ((tmp_details.type() == CALLBACKS || old_details.type() == CALLBACKS) &&
+        (tmp_details.type() != old_details.type() ||
+         tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
+      return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
+                                              "GenAll_Incompatible");
     }
     target_map = tmp_map;
   }
@@ -2535,7 +2736,9 @@
   int current_offset = 0;
   for (int i = 0; i < root_nof; ++i) {
     PropertyDetails old_details = old_descriptors->GetDetails(i);
-    if (old_details.type() == FIELD) current_offset++;
+    if (old_details.type() == FIELD) {
+      current_offset += old_details.field_width_in_words();
+    }
     Descriptor d(handle(old_descriptors->GetKey(i), isolate),
                  handle(old_descriptors->GetValue(i), isolate),
                  old_details);
@@ -2555,9 +2758,8 @@
           new_representation.generalize(target_details.representation()));
     }
     DCHECK_EQ(old_details.attributes(), target_details.attributes());
-    if (old_details.type() == FIELD ||
-        target_details.type() == FIELD ||
-        (modify_index == i && store_mode == FORCE_FIELD) ||
+    if (old_details.type() == FIELD || target_details.type() == FIELD ||
+        (modify_index == i && store_mode == FORCE_IN_OBJECT) ||
         (target_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
       Handle<HeapType> old_field_type = (old_details.type() == FIELD)
           ? handle(old_descriptors->GetFieldType(i), isolate)
@@ -2573,11 +2775,10 @@
         target_field_type = GeneralizeFieldType(
             target_field_type, new_field_type, isolate);
       }
-      FieldDescriptor d(target_key,
-                        current_offset++,
-                        target_field_type,
+      FieldDescriptor d(target_key, current_offset, target_field_type,
                         target_details.attributes(),
                         target_details.representation());
+      current_offset += d.GetDetails().field_width_in_words();
       new_descriptors->Set(i, &d);
     } else {
       DCHECK_NE(FIELD, target_details.type());
@@ -2603,23 +2804,20 @@
         old_field_type = GeneralizeFieldType(
             old_field_type, new_field_type, isolate);
       }
-      FieldDescriptor d(old_key,
-                        current_offset++,
-                        old_field_type,
-                        old_details.attributes(),
-                        old_details.representation());
+      FieldDescriptor d(old_key, current_offset, old_field_type,
+                        old_details.attributes(), old_details.representation());
+      current_offset += d.GetDetails().field_width_in_words();
       new_descriptors->Set(i, &d);
     } else {
       DCHECK(old_details.type() == CONSTANT || old_details.type() == CALLBACKS);
-      if (modify_index == i && store_mode == FORCE_FIELD) {
-        FieldDescriptor d(old_key,
-                          current_offset++,
-                          GeneralizeFieldType(
-                              old_descriptors->GetValue(i)->OptimalType(
-                                  isolate, old_details.representation()),
-                              new_field_type, isolate),
-                          old_details.attributes(),
-                          old_details.representation());
+      if (modify_index == i && store_mode == FORCE_IN_OBJECT) {
+        FieldDescriptor d(
+            old_key, current_offset,
+            GeneralizeFieldType(old_descriptors->GetValue(i)->OptimalType(
+                                    isolate, old_details.representation()),
+                                new_field_type, isolate),
+            old_details.attributes(), old_details.representation());
+        current_offset += d.GetDetails().field_width_in_words();
         new_descriptors->Set(i, &d);
       } else {
         DCHECK_NE(FIELD, old_details.type());
@@ -2633,7 +2831,7 @@
 
   new_descriptors->Sort();
 
-  DCHECK(store_mode != FORCE_FIELD ||
+  DCHECK(store_mode != FORCE_IN_OBJECT ||
          new_descriptors->GetDetails(modify_index).type() == FIELD);
 
   Handle<Map> split_map(root_map->FindLastMatchMap(
@@ -2641,8 +2839,21 @@
   int split_nof = split_map->NumberOfOwnDescriptors();
   DCHECK_NE(old_nof, split_nof);
 
-  split_map->DeprecateTarget(
-      old_descriptors->GetKey(split_nof), *new_descriptors);
+  Handle<LayoutDescriptor> new_layout_descriptor =
+      LayoutDescriptor::New(split_map, new_descriptors, old_nof);
+  PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof);
+  bool transition_target_deprecated = split_map->DeprecateTarget(
+      split_prop_details.kind(), old_descriptors->GetKey(split_nof),
+      split_prop_details.attributes(), *new_descriptors,
+      *new_layout_descriptor);
+
+  // If |transition_target_deprecated| is true then the transition array
+  // already contains entry for given descriptor. This means that the transition
+  // could be inserted regardless of whether transitions array is full or not.
+  if (!transition_target_deprecated && !split_map->CanHaveMoreTransitions()) {
+    return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
+                                            "GenAll_CantHaveMoreTransitions");
+  }
 
   if (FLAG_trace_generalization) {
     PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
@@ -2657,7 +2868,7 @@
                                     isolate), isolate);
     old_map->PrintGeneralization(
         stdout, "", modify_index, split_nof, old_nof,
-        old_details.type() == CONSTANT && store_mode == FORCE_FIELD,
+        old_details.type() == CONSTANT && store_mode == FORCE_IN_OBJECT,
         old_details.representation(), new_details.representation(),
         *old_field_type, *new_field_type);
   }
@@ -2665,7 +2876,8 @@
   // Add missing transitions.
   Handle<Map> new_map = split_map;
   for (int i = split_nof; i < old_nof; ++i) {
-    new_map = CopyInstallDescriptors(new_map, i, new_descriptors);
+    new_map = CopyInstallDescriptors(new_map, i, new_descriptors,
+                                     new_layout_descriptor);
   }
   new_map->set_owns_descriptors(true);
   return new_map;
@@ -2680,7 +2892,7 @@
     if (descriptors->GetDetails(i).type() == FIELD) {
       map = GeneralizeRepresentation(map, i, Representation::Tagged(),
                                      HeapType::Any(map->GetIsolate()),
-                                     FORCE_FIELD);
+                                     FORCE_IN_OBJECT);
     }
   }
   return map;
@@ -2706,7 +2918,7 @@
   if (!map->is_deprecated()) return map;
   return GeneralizeRepresentation(map, 0, Representation::None(),
                                   HeapType::None(map->GetIsolate()),
-                                  ALLOW_AS_CONSTANT);
+                                  ALLOW_IN_DESCRIPTOR);
 }
 
 
@@ -2727,42 +2939,47 @@
 
   Map* new_map = root_map;
   for (int i = root_nof; i < old_nof; ++i) {
-    int j = new_map->SearchTransition(old_descriptors->GetKey(i));
+    PropertyDetails old_details = old_descriptors->GetDetails(i);
+    int j = new_map->SearchTransition(old_details.kind(),
+                                      old_descriptors->GetKey(i),
+                                      old_details.attributes());
     if (j == TransitionArray::kNotFound) return MaybeHandle<Map>();
     new_map = new_map->GetTransition(j);
     DescriptorArray* new_descriptors = new_map->instance_descriptors();
 
     PropertyDetails new_details = new_descriptors->GetDetails(i);
-    PropertyDetails old_details = old_descriptors->GetDetails(i);
-    if (old_details.attributes() != new_details.attributes() ||
-        !old_details.representation().fits_into(new_details.representation())) {
+    DCHECK_EQ(old_details.kind(), new_details.kind());
+    DCHECK_EQ(old_details.attributes(), new_details.attributes());
+    if (!old_details.representation().fits_into(new_details.representation())) {
       return MaybeHandle<Map>();
     }
-    PropertyType new_type = new_details.type();
-    PropertyType old_type = old_details.type();
     Object* new_value = new_descriptors->GetValue(i);
     Object* old_value = old_descriptors->GetValue(i);
-    switch (new_type) {
-      case FIELD:
-        if ((old_type == FIELD &&
-             !HeapType::cast(old_value)->NowIs(HeapType::cast(new_value))) ||
-            (old_type == CONSTANT &&
-             !HeapType::cast(new_value)->NowContains(old_value)) ||
-            (old_type == CALLBACKS &&
-             !HeapType::Any()->Is(HeapType::cast(new_value)))) {
-          return MaybeHandle<Map>();
+    switch (new_details.type()) {
+      case FIELD: {
+        PropertyType old_type = old_details.type();
+        if (old_type == FIELD) {
+          if (!HeapType::cast(old_value)->NowIs(HeapType::cast(new_value))) {
+            return MaybeHandle<Map>();
+          }
+        } else {
+          DCHECK(old_type == CONSTANT);
+          if (!HeapType::cast(new_value)->NowContains(old_value)) {
+            return MaybeHandle<Map>();
+          }
         }
         break;
+      }
+      case ACCESSOR_FIELD:
+        DCHECK(HeapType::Any()->Is(HeapType::cast(new_value)));
+        break;
 
       case CONSTANT:
       case CALLBACKS:
-        if (old_type != new_type || old_value != new_value) {
+        if (old_details.location() == IN_OBJECT || old_value != new_value) {
           return MaybeHandle<Map>();
         }
         break;
-
-      case NORMAL:
-        UNREACHABLE();
     }
   }
   if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>();
@@ -2772,22 +2989,23 @@
 
 MaybeHandle<Object> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
                                                          Handle<Object> value) {
-  // TODO(rossberg): Support symbols in the API.
-  if (it->name()->IsSymbol()) return value;
-
-  Handle<String> name_string = Handle<String>::cast(it->name());
+  Handle<Name> name = it->name();
   Handle<JSObject> holder = it->GetHolder<JSObject>();
   Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
-  if (interceptor->setter()->IsUndefined()) return MaybeHandle<Object>();
+  if (interceptor->setter()->IsUndefined() ||
+      (name->IsSymbol() && !interceptor->can_intercept_symbols())) {
+    return MaybeHandle<Object>();
+  }
 
   LOG(it->isolate(),
-      ApiNamedPropertyAccess("interceptor-named-set", *holder, *name_string));
+      ApiNamedPropertyAccess("interceptor-named-set", *holder, *name));
   PropertyCallbackArguments args(it->isolate(), interceptor->data(), *holder,
                                  *holder);
-  v8::NamedPropertySetterCallback setter =
-      v8::ToCData<v8::NamedPropertySetterCallback>(interceptor->setter());
-  v8::Handle<v8::Value> result = args.Call(
-      setter, v8::Utils::ToLocal(name_string), v8::Utils::ToLocal(value));
+  v8::GenericNamedPropertySetterCallback setter =
+      v8::ToCData<v8::GenericNamedPropertySetterCallback>(
+          interceptor->setter());
+  v8::Handle<v8::Value> result =
+      args.Call(setter, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
   if (!result.IsEmpty()) return value;
 
@@ -2807,7 +3025,8 @@
 MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
                                         Handle<Object> value,
                                         StrictMode strict_mode,
-                                        StoreFromKeyed store_mode) {
+                                        StoreFromKeyed store_mode,
+                                        StorePropertyMode data_store_mode) {
   // Make sure that the top context does not change when doing callbacks or
   // interceptor calls.
   AssertNoContextChange ncc(it->isolate());
@@ -2902,6 +3121,14 @@
                     Object);
   }
 
+  if (data_store_mode == SUPER_PROPERTY) {
+    LookupIterator own_lookup(it->GetReceiver(), it->name(),
+                              LookupIterator::OWN);
+
+    return JSObject::SetProperty(&own_lookup, value, strict_mode, store_mode,
+                                 NORMAL_PROPERTY);
+  }
+
   return AddDataProperty(it, value, NONE, strict_mode, store_mode);
 }
 
@@ -2919,8 +3146,23 @@
 }
 
 
-Handle<Object> Object::SetDataProperty(LookupIterator* it,
-                                       Handle<Object> value) {
+MaybeHandle<Object> Object::WriteToReadOnlyElement(Isolate* isolate,
+                                                   Handle<Object> receiver,
+                                                   uint32_t index,
+                                                   Handle<Object> value,
+                                                   StrictMode strict_mode) {
+  if (strict_mode != STRICT) return value;
+
+  Handle<Object> args[] = {isolate->factory()->NewNumberFromUint(index),
+                           receiver};
+  THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
+                                        HandleVector(args, arraysize(args))),
+                  Object);
+}
+
+
+MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it,
+                                            Handle<Object> value) {
   // Proxies are handled on the WithHandler path. Other non-JSObjects cannot
   // have own properties.
   Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
@@ -2931,9 +3173,8 @@
   // Old value for the observation change record.
   // Fetch before transforming the object since the encoding may become
   // incompatible with what's cached in |it|.
-  bool is_observed =
-      receiver->map()->is_observed() &&
-      !it->name().is_identical_to(it->factory()->hidden_string());
+  bool is_observed = receiver->map()->is_observed() &&
+                     !it->isolate()->IsInternallyUsedPropertyName(it->name());
   MaybeHandle<Object> maybe_old;
   if (is_observed) maybe_old = it->GetDataValue();
 
@@ -2942,12 +3183,14 @@
   it->PrepareForDataProperty(value);
 
   // Write the property value.
-  it->WriteDataValue(value);
+  value = it->WriteDataValue(value);
 
   // Send the change record if there are observers.
   if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) {
-    JSObject::EnqueueChangeRecord(receiver, "update", it->name(),
-                                  maybe_old.ToHandleChecked());
+    RETURN_ON_EXCEPTION(it->isolate(), JSObject::EnqueueChangeRecord(
+                                           receiver, "update", it->name(),
+                                           maybe_old.ToHandleChecked()),
+                        Object);
   }
 
   return value;
@@ -2971,6 +3214,10 @@
   // instead. If the prototype is Null, the proxy is detached.
   if (receiver->IsJSGlobalProxy()) return value;
 
+  // If the receiver is Indexed Exotic object (currently only typed arrays),
+  // disallow adding properties with numeric names.
+  if (it->IsSpecialNumericIndex()) return value;
+
   // Possibly migrate to the most up-to-date map that will be able to store
   // |value| under it->name() with |attributes|.
   it->PrepareTransitionToDataProperty(value, attributes, store_mode);
@@ -2992,14 +3239,16 @@
     JSObject::AddSlowProperty(receiver, it->name(), value, attributes);
   } else {
     // Write the property value.
-    it->WriteDataValue(value);
+    value = it->WriteDataValue(value);
   }
 
   // Send the change record if there are observers.
   if (receiver->map()->is_observed() &&
-      !it->name().is_identical_to(it->factory()->hidden_string())) {
-    JSObject::EnqueueChangeRecord(receiver, "add", it->name(),
-                                  it->factory()->the_hole_value());
+      !it->isolate()->IsInternallyUsedPropertyName(it->name())) {
+    RETURN_ON_EXCEPTION(it->isolate(), JSObject::EnqueueChangeRecord(
+                                           receiver, "add", it->name(),
+                                           it->factory()->the_hole_value()),
+                        Object);
   }
 
   return value;
@@ -3054,8 +3303,12 @@
   Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
       descriptors, old_size, slack);
 
+  DisallowHeapAllocation no_allocation;
+  // The descriptors are still the same, so keep the layout descriptor.
+  LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
+
   if (old_size == 0) {
-    map->set_instance_descriptors(*new_descriptors);
+    map->UpdateDescriptors(*new_descriptors, layout_descriptor);
     return;
   }
 
@@ -3077,10 +3330,10 @@
        current = walk_map->GetBackPointer()) {
     walk_map = Map::cast(current);
     if (walk_map->instance_descriptors() != *descriptors) break;
-    walk_map->set_instance_descriptors(*new_descriptors);
+    walk_map->UpdateDescriptors(*new_descriptors, layout_descriptor);
   }
 
-  map->set_instance_descriptors(*new_descriptors);
+  map->UpdateDescriptors(*new_descriptors, layout_descriptor);
 }
 
 
@@ -3280,6 +3533,21 @@
 }
 
 
+Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) {
+  Isolate* isolate = map->GetIsolate();
+  if (map->code_cache()->IsFixedArray()) {
+    return isolate->factory()->NewWeakCell(map);
+  }
+  Handle<CodeCache> code_cache(CodeCache::cast(map->code_cache()), isolate);
+  if (code_cache->weak_cell_cache()->IsWeakCell()) {
+    return Handle<WeakCell>(WeakCell::cast(code_cache->weak_cell_cache()));
+  }
+  Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
+  code_cache->set_weak_cell_cache(*weak_cell);
+  return weak_cell;
+}
+
+
 static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
                                                  ElementsKind to_kind) {
   DCHECK(IsTransitionElementsKind(map->elements_kind()));
@@ -3742,15 +4010,6 @@
 }
 
 
-void JSObject::MigrateToNewProperty(Handle<JSObject> object,
-                                    Handle<Map> map,
-                                    Handle<Object> value) {
-  JSObject::MigrateToMap(object, map);
-  if (map->GetLastDescriptorDetails().type() != FIELD) return;
-  object->WriteToField(map->LastAdded(), *value);
-}
-
-
 void JSObject::WriteToField(int descriptor, Object* value) {
   DisallowHeapAllocation no_gc;
 
@@ -3763,11 +4022,15 @@
   if (details.representation().IsDouble()) {
     // Nothing more to be done.
     if (value->IsUninitialized()) return;
-    HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index));
-    DCHECK(box->IsMutableHeapNumber());
-    box->set_value(value->Number());
+    if (IsUnboxedDoubleField(index)) {
+      RawFastDoublePropertyAtPut(index, value->Number());
+    } else {
+      HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index));
+      DCHECK(box->IsMutableHeapNumber());
+      box->set_value(value->Number());
+    }
   } else {
-    FastPropertyAtPut(index, value);
+    RawFastPropertyAtPut(index, value);
   }
 }
 
@@ -3785,7 +4048,7 @@
   DCHECK(maybe.has_value);
   DCHECK(!it.IsFound());
   DCHECK(object->map()->is_extensible() ||
-         name.is_identical_to(it.isolate()->factory()->hidden_string()));
+         it.isolate()->IsInternallyUsedPropertyName(name));
 #endif
   AddDataProperty(&it, value, attributes, STRICT,
                   CERTAINLY_NOT_STORE_FROM_KEYED).Check();
@@ -3803,7 +4066,7 @@
   DCHECK(!value->IsTheHole());
   LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
   bool is_observed = object->map()->is_observed() &&
-                     *name != it.isolate()->heap()->hidden_string();
+                     !it.isolate()->IsInternallyUsedPropertyName(name);
   for (; it.IsFound(); it.Next()) {
     switch (it.state()) {
       case LookupIterator::INTERCEPTOR:
@@ -3820,20 +4083,11 @@
 
       case LookupIterator::ACCESSOR: {
         PropertyDetails details = it.property_details();
-        Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
         // Ensure the context isn't changed after calling into accessors.
         AssertNoContextChange ncc(it.isolate());
 
         Handle<Object> accessors = it.GetAccessors();
 
-        if (is_observed && accessors->IsAccessorInfo()) {
-          ASSIGN_RETURN_ON_EXCEPTION(
-              it.isolate(), old_value,
-              GetPropertyWithAccessor(it.GetReceiver(), it.name(),
-                                      it.GetHolder<JSObject>(), accessors),
-              Object);
-        }
-
         // Special handling for ExecutableAccessorInfo, which behaves like a
         // data property.
         if (handling == DONT_FORCE_FIELD &&
@@ -3848,18 +4102,6 @@
           DCHECK(result->SameValue(*value));
 
           if (details.attributes() == attributes) {
-            // Regular property update if the attributes match.
-            if (is_observed && !old_value->SameValue(*value)) {
-              // If we are setting the prototype of a function and are
-              // observed, don't send change records because the prototype
-              // handles that itself.
-              if (!object->IsJSFunction() ||
-                  !Name::Equals(it.isolate()->factory()->prototype_string(),
-                                name) ||
-                  !Handle<JSFunction>::cast(object)->should_have_prototype()) {
-                EnqueueChangeRecord(object, "update", name, old_value);
-              }
-            }
             return value;
           }
 
@@ -3873,23 +4115,25 @@
           if (attributes & READ_ONLY) new_data->clear_setter();
           SetPropertyCallback(object, name, new_data, attributes);
           if (is_observed) {
-            if (old_value->SameValue(*value)) {
-              old_value = it.isolate()->factory()->the_hole_value();
-            }
-            EnqueueChangeRecord(object, "reconfigure", name, old_value);
+            RETURN_ON_EXCEPTION(
+                it.isolate(),
+                EnqueueChangeRecord(object, "reconfigure", name,
+                                    it.isolate()->factory()->the_hole_value()),
+                Object);
           }
           return value;
         }
 
         it.ReconfigureDataProperty(value, attributes);
         it.PrepareForDataProperty(value);
-        it.WriteDataValue(value);
+        value = it.WriteDataValue(value);
 
         if (is_observed) {
-          if (old_value->SameValue(*value)) {
-            old_value = it.isolate()->factory()->the_hole_value();
-          }
-          EnqueueChangeRecord(object, "reconfigure", name, old_value);
+          RETURN_ON_EXCEPTION(
+              it.isolate(),
+              EnqueueChangeRecord(object, "reconfigure", name,
+                                  it.isolate()->factory()->the_hole_value()),
+              Object);
         }
 
         return value;
@@ -3907,13 +4151,16 @@
 
         it.ReconfigureDataProperty(value, attributes);
         it.PrepareForDataProperty(value);
-        it.WriteDataValue(value);
+        value = it.WriteDataValue(value);
 
         if (is_observed) {
           if (old_value->SameValue(*value)) {
             old_value = it.isolate()->factory()->the_hole_value();
           }
-          EnqueueChangeRecord(object, "reconfigure", name, old_value);
+          RETURN_ON_EXCEPTION(
+              it.isolate(),
+              EnqueueChangeRecord(object, "reconfigure", name, old_value),
+              Object);
         }
 
         return value;
@@ -3930,9 +4177,6 @@
     Handle<JSObject> holder,
     Handle<Object> receiver,
     Handle<Name> name) {
-  // TODO(rossberg): Support symbols in the API.
-  if (name->IsSymbol()) return maybe(ABSENT);
-
   Isolate* isolate = holder->GetIsolate();
   HandleScope scope(isolate);
 
@@ -3941,26 +4185,29 @@
   AssertNoContextChange ncc(isolate);
 
   Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
+  if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
+    return maybe(ABSENT);
+  }
   PropertyCallbackArguments args(
       isolate, interceptor->data(), *receiver, *holder);
   if (!interceptor->query()->IsUndefined()) {
-    v8::NamedPropertyQueryCallback query =
-        v8::ToCData<v8::NamedPropertyQueryCallback>(interceptor->query());
+    v8::GenericNamedPropertyQueryCallback query =
+        v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
+            interceptor->query());
     LOG(isolate,
         ApiNamedPropertyAccess("interceptor-named-has", *holder, *name));
-    v8::Handle<v8::Integer> result =
-        args.Call(query, v8::Utils::ToLocal(Handle<String>::cast(name)));
+    v8::Handle<v8::Integer> result = args.Call(query, v8::Utils::ToLocal(name));
     if (!result.IsEmpty()) {
       DCHECK(result->IsInt32());
       return maybe(static_cast<PropertyAttributes>(result->Int32Value()));
     }
   } else if (!interceptor->getter()->IsUndefined()) {
-    v8::NamedPropertyGetterCallback getter =
-        v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
+    v8::GenericNamedPropertyGetterCallback getter =
+        v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
+            interceptor->getter());
     LOG(isolate,
         ApiNamedPropertyAccess("interceptor-named-get-has", *holder, *name));
-    v8::Handle<v8::Value> result =
-        args.Call(getter, v8::Utils::ToLocal(Handle<String>::cast(name)));
+    v8::Handle<v8::Value> result = args.Call(getter, v8::Utils::ToLocal(name));
     if (!result.IsEmpty()) return maybe(DONT_ENUM);
   }
 
@@ -4019,9 +4266,8 @@
   // Check access rights if needed.
   if (object->IsAccessCheckNeeded()) {
     if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_HAS)) {
-      isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS);
-      RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
-      return maybe(ABSENT);
+      return GetElementAttributesWithFailedAccessCheck(isolate, object,
+                                                       receiver, index);
     }
   }
 
@@ -4055,6 +4301,21 @@
   // callbacks or interceptor calls.
   AssertNoContextChange ncc(isolate);
 
+  Maybe<PropertyAttributes> from_interceptor =
+      GetElementAttributeFromInterceptor(object, receiver, index);
+  if (!from_interceptor.has_value) return Maybe<PropertyAttributes>();
+  if (from_interceptor.value != ABSENT) return maybe(from_interceptor.value);
+
+  return GetElementAttributeWithoutInterceptor(object, receiver, index,
+                                               check_prototype);
+}
+
+
+Maybe<PropertyAttributes> JSObject::GetElementAttributeFromInterceptor(
+    Handle<JSObject> object, Handle<Object> receiver, uint32_t index) {
+  Isolate* isolate = object->GetIsolate();
+  AssertNoContextChange ncc(isolate);
+
   Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
   PropertyCallbackArguments args(
       isolate, interceptor->data(), *receiver, *object);
@@ -4075,9 +4336,8 @@
     v8::Handle<v8::Value> result = args.Call(getter, index);
     if (!result.IsEmpty()) return maybe(NONE);
   }
-
-  return GetElementAttributeWithoutInterceptor(
-       object, receiver, index, check_prototype);
+  RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
+  return maybe(ABSENT);
 }
 
 
@@ -4154,11 +4414,12 @@
 
 void JSObject::NormalizeProperties(Handle<JSObject> object,
                                    PropertyNormalizationMode mode,
-                                   int expected_additional_properties) {
+                                   int expected_additional_properties,
+                                   const char* reason) {
   if (!object->HasFastProperties()) return;
 
   Handle<Map> map(object->map());
-  Handle<Map> new_map = Map::Normalize(map, mode);
+  Handle<Map> new_map = Map::Normalize(map, mode, reason);
 
   MigrateFastToSlow(object, new_map, expected_additional_properties);
 }
@@ -4190,41 +4451,45 @@
   Handle<DescriptorArray> descs(map->instance_descriptors());
   for (int i = 0; i < real_size; i++) {
     PropertyDetails details = descs->GetDetails(i);
+    Handle<Name> key(descs->GetKey(i));
     switch (details.type()) {
       case CONSTANT: {
-        Handle<Name> key(descs->GetKey(i));
         Handle<Object> value(descs->GetConstant(i), isolate);
-        PropertyDetails d = PropertyDetails(
-            details.attributes(), NORMAL, i + 1);
+        PropertyDetails d(details.attributes(), FIELD, i + 1);
         dictionary = NameDictionary::Add(dictionary, key, value, d);
         break;
       }
       case FIELD: {
-        Handle<Name> key(descs->GetKey(i));
         FieldIndex index = FieldIndex::ForDescriptor(*map, i);
-        Handle<Object> value(
-            object->RawFastPropertyAt(index), isolate);
-        if (details.representation().IsDouble()) {
-          DCHECK(value->IsMutableHeapNumber());
-          Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
-          value = isolate->factory()->NewHeapNumber(old->value());
+        Handle<Object> value;
+        if (object->IsUnboxedDoubleField(index)) {
+          double old_value = object->RawFastDoublePropertyAt(index);
+          value = isolate->factory()->NewHeapNumber(old_value);
+        } else {
+          value = handle(object->RawFastPropertyAt(index), isolate);
+          if (details.representation().IsDouble()) {
+            DCHECK(value->IsMutableHeapNumber());
+            Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
+            value = isolate->factory()->NewHeapNumber(old->value());
+          }
         }
-        PropertyDetails d =
-            PropertyDetails(details.attributes(), NORMAL, i + 1);
+        PropertyDetails d(details.attributes(), FIELD, i + 1);
+        dictionary = NameDictionary::Add(dictionary, key, value, d);
+        break;
+      }
+      case ACCESSOR_FIELD: {
+        FieldIndex index = FieldIndex::ForDescriptor(*map, i);
+        Handle<Object> value(object->RawFastPropertyAt(index), isolate);
+        PropertyDetails d(details.attributes(), CALLBACKS, i + 1);
         dictionary = NameDictionary::Add(dictionary, key, value, d);
         break;
       }
       case CALLBACKS: {
-        Handle<Name> key(descs->GetKey(i));
         Handle<Object> value(descs->GetCallbacksObject(i), isolate);
-        PropertyDetails d = PropertyDetails(
-            details.attributes(), CALLBACKS, i + 1);
+        PropertyDetails d(details.attributes(), CALLBACKS, i + 1);
         dictionary = NameDictionary::Add(dictionary, key, value, d);
         break;
       }
-      case NORMAL:
-        UNREACHABLE();
-        break;
     }
   }
 
@@ -4253,6 +4518,14 @@
 
   object->set_properties(*dictionary);
 
+  // Ensure that in-object space of slow-mode object does not contain random
+  // garbage.
+  int inobject_properties = new_map->inobject_properties();
+  for (int i = 0; i < inobject_properties; i++) {
+    FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
+    object->RawFastPropertyAtPut(index, Smi::FromInt(0));
+  }
+
   isolate->counters()->props_to_dictionary()->Increment();
 
 #ifdef DEBUG
@@ -4266,7 +4539,8 @@
 
 
 void JSObject::MigrateSlowToFast(Handle<JSObject> object,
-                                 int unused_property_fields) {
+                                 int unused_property_fields,
+                                 const char* reason) {
   if (object->HasFastProperties()) return;
   DCHECK(!object->IsGlobalObject());
   Isolate* isolate = object->GetIsolate();
@@ -4278,25 +4552,26 @@
   int number_of_elements = dictionary->NumberOfElements();
   if (number_of_elements > kMaxNumberOfDescriptors) return;
 
+  Handle<FixedArray> iteration_order;
   if (number_of_elements != dictionary->NextEnumerationIndex()) {
-    NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
+    iteration_order =
+        NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
+  } else {
+    iteration_order = NameDictionary::BuildIterationIndicesArray(dictionary);
   }
 
-  int instance_descriptor_length = 0;
+  int instance_descriptor_length = iteration_order->length();
   int number_of_fields = 0;
 
   // Compute the length of the instance descriptor.
-  int capacity = dictionary->Capacity();
-  for (int i = 0; i < capacity; i++) {
-    Object* k = dictionary->KeyAt(i);
-    if (dictionary->IsKey(k)) {
-      Object* value = dictionary->ValueAt(i);
-      PropertyType type = dictionary->DetailsAt(i).type();
-      DCHECK(type != FIELD);
-      instance_descriptor_length++;
-      if (type == NORMAL && !value->IsJSFunction()) {
-        number_of_fields += 1;
-      }
+  for (int i = 0; i < instance_descriptor_length; i++) {
+    int index = Smi::cast(iteration_order->get(i))->value();
+    DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
+
+    Object* value = dictionary->ValueAt(index);
+    PropertyType type = dictionary->DetailsAt(index).type();
+    if (type == FIELD && !value->IsJSFunction()) {
+      number_of_fields += 1;
     }
   }
 
@@ -4306,6 +4581,14 @@
   Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
   new_map->set_dictionary_map(false);
 
+#if TRACE_MAPS
+  if (FLAG_trace_maps) {
+    PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n",
+           reinterpret_cast<void*>(object->map()),
+           reinterpret_cast<void*>(*new_map), reason);
+  }
+#endif
+
   if (instance_descriptor_length == 0) {
     DisallowHeapAllocation no_gc;
     DCHECK_LE(unused_property_fields, inobject_props);
@@ -4336,59 +4619,57 @@
 
   // Fill in the instance descriptor and the fields.
   int current_offset = 0;
-  for (int i = 0; i < capacity; i++) {
-    Object* k = dictionary->KeyAt(i);
-    if (dictionary->IsKey(k)) {
-      Object* value = dictionary->ValueAt(i);
-      Handle<Name> key;
-      if (k->IsSymbol()) {
-        key = handle(Symbol::cast(k));
-      } else {
-        // Ensure the key is a unique name before writing into the
-        // instance descriptor.
-        key = factory->InternalizeString(handle(String::cast(k)));
-      }
+  for (int i = 0; i < instance_descriptor_length; i++) {
+    int index = Smi::cast(iteration_order->get(i))->value();
+    Object* k = dictionary->KeyAt(index);
+    DCHECK(dictionary->IsKey(k));
 
-      PropertyDetails details = dictionary->DetailsAt(i);
-      int enumeration_index = details.dictionary_index();
-      PropertyType type = details.type();
+    Object* value = dictionary->ValueAt(index);
+    Handle<Name> key;
+    if (k->IsSymbol()) {
+      key = handle(Symbol::cast(k));
+    } else {
+      // Ensure the key is a unique name before writing into the
+      // instance descriptor.
+      key = factory->InternalizeString(handle(String::cast(k)));
+    }
 
-      if (value->IsJSFunction()) {
-        ConstantDescriptor d(key,
-                             handle(value, isolate),
-                             details.attributes());
-        descriptors->Set(enumeration_index - 1, &d);
-      } else if (type == NORMAL) {
-        if (current_offset < inobject_props) {
-          object->InObjectPropertyAtPut(current_offset,
-                                        value,
-                                        UPDATE_WRITE_BARRIER);
-        } else {
-          int offset = current_offset - inobject_props;
-          fields->set(offset, value);
-        }
-        FieldDescriptor d(key,
-                          current_offset++,
-                          details.attributes(),
-                          // TODO(verwaest): value->OptimalRepresentation();
-                          Representation::Tagged());
-        descriptors->Set(enumeration_index - 1, &d);
-      } else if (type == CALLBACKS) {
-        CallbacksDescriptor d(key,
-                              handle(value, isolate),
-                              details.attributes());
-        descriptors->Set(enumeration_index - 1, &d);
+    PropertyDetails details = dictionary->DetailsAt(index);
+    int enumeration_index = details.dictionary_index();
+    PropertyType type = details.type();
+
+    if (value->IsJSFunction()) {
+      ConstantDescriptor d(key, handle(value, isolate), details.attributes());
+      descriptors->Set(enumeration_index - 1, &d);
+    } else if (type == FIELD) {
+      if (current_offset < inobject_props) {
+        object->InObjectPropertyAtPut(current_offset, value,
+                                      UPDATE_WRITE_BARRIER);
       } else {
-        UNREACHABLE();
+        int offset = current_offset - inobject_props;
+        fields->set(offset, value);
       }
+      FieldDescriptor d(key, current_offset, details.attributes(),
+                        // TODO(verwaest): value->OptimalRepresentation();
+                        Representation::Tagged());
+      current_offset += d.GetDetails().field_width_in_words();
+      descriptors->Set(enumeration_index - 1, &d);
+    } else if (type == CALLBACKS) {
+      CallbacksDescriptor d(key, handle(value, isolate), details.attributes());
+      descriptors->Set(enumeration_index - 1, &d);
+    } else {
+      UNREACHABLE();
     }
   }
   DCHECK(current_offset == number_of_fields);
 
   descriptors->Sort();
 
+  Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
+      new_map, descriptors, descriptors->number_of_descriptors());
+
   DisallowHeapAllocation no_gc;
-  new_map->InitializeDescriptors(*descriptors);
+  new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
   new_map->set_unused_property_fields(unused_property_fields);
 
   // Transform the object.
@@ -4436,7 +4717,7 @@
       value = handle(Handle<FixedArray>::cast(array)->get(i), isolate);
     }
     if (!value->IsTheHole()) {
-      PropertyDetails details = PropertyDetails(NONE, NORMAL, 0);
+      PropertyDetails details(NONE, FIELD, 0);
       dictionary =
           SeededNumberDictionary::AddNumberEntry(dictionary, i, value, details);
     }
@@ -4766,20 +5047,20 @@
     Handle<JSObject> holder, Handle<JSObject> receiver, Handle<Name> name) {
   Isolate* isolate = holder->GetIsolate();
 
-  // TODO(rossberg): Support symbols in the API.
-  if (name->IsSymbol()) return MaybeHandle<Object>();
-
   Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
-  if (interceptor->deleter()->IsUndefined()) return MaybeHandle<Object>();
+  if (interceptor->deleter()->IsUndefined() ||
+      (name->IsSymbol() && !interceptor->can_intercept_symbols())) {
+    return MaybeHandle<Object>();
+  }
 
-  v8::NamedPropertyDeleterCallback deleter =
-      v8::ToCData<v8::NamedPropertyDeleterCallback>(interceptor->deleter());
+  v8::GenericNamedPropertyDeleterCallback deleter =
+      v8::ToCData<v8::GenericNamedPropertyDeleterCallback>(
+          interceptor->deleter());
   LOG(isolate,
       ApiNamedPropertyAccess("interceptor-named-delete", *holder, *name));
   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
                                  *holder);
-  v8::Handle<v8::Boolean> result =
-      args.Call(deleter, v8::Utils::ToLocal(Handle<String>::cast(name)));
+  v8::Handle<v8::Boolean> result = args.Call(deleter, v8::Utils::ToLocal(name));
   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
   if (result.IsEmpty()) return MaybeHandle<Object>();
 
@@ -4890,7 +5171,9 @@
     if (!maybe.has_value) return MaybeHandle<Object>();
     if (!maybe.value) {
       Handle<String> name = factory->Uint32ToString(index);
-      EnqueueChangeRecord(object, "delete", name, old_value);
+      RETURN_ON_EXCEPTION(
+          isolate, EnqueueChangeRecord(object, "delete", name, old_value),
+          Object);
     }
   }
 
@@ -4917,7 +5200,7 @@
   LookupIterator it(object, name, config);
 
   bool is_observed = object->map()->is_observed() &&
-                     *name != it.isolate()->heap()->hidden_string();
+                     !it.isolate()->IsInternallyUsedPropertyName(name);
   Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
 
   for (; it.IsFound(); it.Next()) {
@@ -4970,13 +5253,15 @@
             !(object->IsJSGlobalProxy() && holder->IsJSGlobalObject())) {
           return it.isolate()->factory()->true_value();
         }
-        NormalizeProperties(holder, mode, 0);
+        NormalizeProperties(holder, mode, 0, "DeletingProperty");
         Handle<Object> result =
             DeleteNormalizedProperty(holder, name, delete_mode);
         ReoptimizeIfPrototype(holder);
 
         if (is_observed) {
-          EnqueueChangeRecord(object, "delete", name, old_value);
+          RETURN_ON_EXCEPTION(
+              it.isolate(),
+              EnqueueChangeRecord(object, "delete", name, old_value), Object);
         }
 
         return result;
@@ -5132,7 +5417,7 @@
     if (context->has_extension() && !context->IsCatchContext()) {
       // With harmony scoping, a JSFunction may have a global context.
       // TODO(mvstanton): walk into the ScopeInfo.
-      if (FLAG_harmony_scoping && context->IsGlobalContext()) {
+      if (FLAG_harmony_scoping && context->IsScriptContext()) {
         return false;
       }
 
@@ -5146,10 +5431,14 @@
 
 
 MaybeHandle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
-  Isolate* isolate = object->GetIsolate();
-
   if (!object->map()->is_extensible()) return object;
 
+  if (!object->HasSloppyArgumentsElements() && !object->map()->is_observed()) {
+    return PreventExtensionsWithTransition<NONE>(object);
+  }
+
+  Isolate* isolate = object->GetIsolate();
+
   if (object->IsAccessCheckNeeded() &&
       !isolate->MayNamedAccess(
           object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
@@ -5186,36 +5475,62 @@
   // Do a map transition, other objects with this map may still
   // be extensible.
   // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
-  Handle<Map> new_map = Map::Copy(handle(object->map()));
+  Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions");
 
   new_map->set_is_extensible(false);
   JSObject::MigrateToMap(object, new_map);
   DCHECK(!object->map()->is_extensible());
 
   if (object->map()->is_observed()) {
-    EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
-                        isolate->factory()->the_hole_value());
+    RETURN_ON_EXCEPTION(
+        isolate,
+        EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
+                            isolate->factory()->the_hole_value()),
+        Object);
   }
   return object;
 }
 
 
-template<typename Dictionary>
-static void FreezeDictionary(Dictionary* dictionary) {
+Handle<SeededNumberDictionary> JSObject::GetNormalizedElementDictionary(
+    Handle<JSObject> object) {
+  DCHECK(!object->elements()->IsDictionary());
+  Isolate* isolate = object->GetIsolate();
+  int length = object->IsJSArray()
+                   ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
+                   : object->elements()->length();
+  if (length > 0) {
+    int capacity = 0;
+    int used = 0;
+    object->GetElementsCapacityAndUsage(&capacity, &used);
+    Handle<SeededNumberDictionary> new_element_dictionary =
+        SeededNumberDictionary::New(isolate, used);
+
+    // Move elements to a dictionary; avoid calling NormalizeElements to avoid
+    // unnecessary transitions.
+    return CopyFastElementsToDictionary(handle(object->elements()), length,
+                                        new_element_dictionary);
+  }
+  // No existing elements, use a pre-allocated empty backing store
+  return isolate->factory()->empty_slow_element_dictionary();
+}
+
+
+template <typename Dictionary>
+static void ApplyAttributesToDictionary(Dictionary* dictionary,
+                                        const PropertyAttributes attributes) {
   int capacity = dictionary->Capacity();
   for (int i = 0; i < capacity; i++) {
     Object* k = dictionary->KeyAt(i);
     if (dictionary->IsKey(k) &&
         !(k->IsSymbol() && Symbol::cast(k)->is_private())) {
       PropertyDetails details = dictionary->DetailsAt(i);
-      int attrs = DONT_DELETE;
+      int attrs = attributes;
       // READ_ONLY is an invalid attribute for JS setters/getters.
-      if (details.type() == CALLBACKS) {
+      if ((attributes & READ_ONLY) && details.type() == CALLBACKS) {
         Object* v = dictionary->ValueAt(i);
         if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
-        if (!v->IsAccessorPair()) attrs |= READ_ONLY;
-      } else {
-        attrs |= READ_ONLY;
+        if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
       }
       details = details.CopyAddAttributes(
           static_cast<PropertyAttributes>(attrs));
@@ -5225,13 +5540,15 @@
 }
 
 
-MaybeHandle<Object> JSObject::Freeze(Handle<JSObject> object) {
-  // Freezing sloppy arguments should be handled elsewhere.
+template <PropertyAttributes attrs>
+MaybeHandle<Object> JSObject::PreventExtensionsWithTransition(
+    Handle<JSObject> object) {
+  STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
+
+  // Sealing/freezing sloppy arguments should be handled elsewhere.
   DCHECK(!object->HasSloppyArgumentsElements());
   DCHECK(!object->map()->is_observed());
 
-  if (object->map()->is_frozen()) return object;
-
   Isolate* isolate = object->GetIsolate();
   if (object->IsAccessCheckNeeded() &&
       !isolate->MayNamedAccess(
@@ -5245,10 +5562,11 @@
     PrototypeIterator iter(isolate, object);
     if (iter.IsAtEnd()) return object;
     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
-    return Freeze(Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
+    return PreventExtensionsWithTransition<attrs>(
+        Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
   }
 
-  // It's not possible to freeze objects with external array elements
+  // It's not possible to seal or freeze objects with external array elements
   if (object->HasExternalArrayElements() ||
       object->HasFixedTypedArrayElements()) {
     THROW_NEW_ERROR(isolate,
@@ -5259,54 +5577,48 @@
 
   Handle<SeededNumberDictionary> new_element_dictionary;
   if (!object->elements()->IsDictionary()) {
-    int length = object->IsJSArray()
-        ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
-        : object->elements()->length();
-    if (length > 0) {
-      int capacity = 0;
-      int used = 0;
-      object->GetElementsCapacityAndUsage(&capacity, &used);
-      new_element_dictionary = SeededNumberDictionary::New(isolate, used);
+    new_element_dictionary = GetNormalizedElementDictionary(object);
+  }
 
-      // Move elements to a dictionary; avoid calling NormalizeElements to avoid
-      // unnecessary transitions.
-      new_element_dictionary = CopyFastElementsToDictionary(
-          handle(object->elements()), length, new_element_dictionary);
-    } else {
-      // No existing elements, use a pre-allocated empty backing store
-      new_element_dictionary =
-          isolate->factory()->empty_slow_element_dictionary();
-    }
+  Handle<Symbol> transition_marker;
+  if (attrs == NONE) {
+    transition_marker = isolate->factory()->nonextensible_symbol();
+  } else if (attrs == SEALED) {
+    transition_marker = isolate->factory()->sealed_symbol();
+  } else {
+    DCHECK(attrs == FROZEN);
+    transition_marker = isolate->factory()->frozen_symbol();
   }
 
   Handle<Map> old_map(object->map(), isolate);
-  int transition_index = old_map->SearchTransition(
-      isolate->heap()->frozen_symbol());
+  int transition_index = old_map->SearchSpecialTransition(*transition_marker);
   if (transition_index != TransitionArray::kNotFound) {
     Handle<Map> transition_map(old_map->GetTransition(transition_index));
     DCHECK(transition_map->has_dictionary_elements());
-    DCHECK(transition_map->is_frozen());
     DCHECK(!transition_map->is_extensible());
     JSObject::MigrateToMap(object, transition_map);
   } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
-    // Create a new descriptor array with fully-frozen properties
-    Handle<Map> new_map = Map::CopyForFreeze(old_map);
+    // Create a new descriptor array with the appropriate property attributes
+    Handle<Map> new_map = Map::CopyForPreventExtensions(
+        old_map, attrs, transition_marker, "CopyForPreventExtensions");
     JSObject::MigrateToMap(object, new_map);
   } else {
     DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
     // Slow path: need to normalize properties for safety
-    NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
+    NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
+                        "SlowPreventExtensions");
 
     // Create a new map, since other objects with this map may be extensible.
     // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
-    Handle<Map> new_map = Map::Copy(handle(object->map()));
-    new_map->freeze();
+    Handle<Map> new_map =
+        Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
     new_map->set_is_extensible(false);
     new_map->set_elements_kind(DICTIONARY_ELEMENTS);
     JSObject::MigrateToMap(object, new_map);
 
-    // Freeze dictionary-mode properties
-    FreezeDictionary(object->property_dictionary());
+    if (attrs != NONE) {
+      ApplyAttributesToDictionary(object->property_dictionary(), attrs);
+    }
   }
 
   DCHECK(object->map()->has_dictionary_elements());
@@ -5318,14 +5630,25 @@
     SeededNumberDictionary* dictionary = object->element_dictionary();
     // Make sure we never go back to the fast case
     dictionary->set_requires_slow_elements();
-    // Freeze all elements in the dictionary
-    FreezeDictionary(dictionary);
+    if (attrs != NONE) {
+      ApplyAttributesToDictionary(dictionary, attrs);
+    }
   }
 
   return object;
 }
 
 
+MaybeHandle<Object> JSObject::Freeze(Handle<JSObject> object) {
+  return PreventExtensionsWithTransition<FROZEN>(object);
+}
+
+
+MaybeHandle<Object> JSObject::Seal(Handle<JSObject> object) {
+  return PreventExtensionsWithTransition<SEALED>(object);
+}
+
+
 void JSObject::SetObserved(Handle<JSObject> object) {
   DCHECK(!object->IsJSGlobalProxy());
   DCHECK(!object->IsJSGlobalObject());
@@ -5333,15 +5656,15 @@
   Handle<Map> new_map;
   Handle<Map> old_map(object->map(), isolate);
   DCHECK(!old_map->is_observed());
-  int transition_index = old_map->SearchTransition(
-      isolate->heap()->observed_symbol());
+  int transition_index =
+      old_map->SearchSpecialTransition(isolate->heap()->observed_symbol());
   if (transition_index != TransitionArray::kNotFound) {
     new_map = handle(old_map->GetTransition(transition_index), isolate);
     DCHECK(new_map->is_observed());
   } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
     new_map = Map::CopyForObserved(old_map);
   } else {
-    new_map = Map::Copy(old_map);
+    new_map = Map::Copy(old_map, "SlowObserved");
     new_map->set_is_observed();
   }
   JSObject::MigrateToMap(object, new_map);
@@ -5352,6 +5675,10 @@
                                         Representation representation,
                                         FieldIndex index) {
   Isolate* isolate = object->GetIsolate();
+  if (object->IsUnboxedDoubleField(index)) {
+    double value = object->RawFastDoublePropertyAt(index);
+    return isolate->factory()->NewHeapNumber(value);
+  }
   Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
   return Object::WrapForRead(isolate, raw_value, representation);
 }
@@ -5442,18 +5769,28 @@
         PropertyDetails details = descriptors->GetDetails(i);
         if (details.type() != FIELD) continue;
         FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
-        Handle<Object> value(object->RawFastPropertyAt(index), isolate);
-        if (value->IsJSObject()) {
-          ASSIGN_RETURN_ON_EXCEPTION(
-              isolate, value,
-              VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
-              JSObject);
+        if (object->IsUnboxedDoubleField(index)) {
+          if (copying) {
+            double value = object->RawFastDoublePropertyAt(index);
+            copy->RawFastDoublePropertyAtPut(index, value);
+          }
         } else {
-          Representation representation = details.representation();
-          value = Object::NewStorageFor(isolate, value, representation);
-        }
-        if (copying) {
-          copy->FastPropertyAtPut(index, *value);
+          Handle<Object> value(object->RawFastPropertyAt(index), isolate);
+          if (value->IsJSObject()) {
+            ASSIGN_RETURN_ON_EXCEPTION(
+                isolate, value,
+                VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
+                JSObject);
+            if (copying) {
+              copy->FastPropertyAtPut(index, *value);
+            }
+          } else {
+            if (copying) {
+              Representation representation = details.representation();
+              value = Object::NewStorageFor(isolate, value, representation);
+              copy->FastPropertyAtPut(index, *value);
+            }
+          }
         }
       }
     } else {
@@ -5650,16 +5987,17 @@
 
 
 int Map::NextFreePropertyIndex() {
-  int max_index = -1;
+  int free_index = 0;
   int number_of_own_descriptors = NumberOfOwnDescriptors();
   DescriptorArray* descs = instance_descriptors();
   for (int i = 0; i < number_of_own_descriptors; i++) {
-    if (descs->GetType(i) == FIELD) {
-      int current_index = descs->GetFieldIndex(i);
-      if (current_index > max_index) max_index = current_index;
+    PropertyDetails details = descs->GetDetails(i);
+    if (details.type() == FIELD) {
+      int candidate = details.field_index() + details.field_width_in_words();
+      if (candidate > free_index) free_index = candidate;
     }
   }
-  return max_index + 1;
+  return free_index;
 }
 
 
@@ -5667,7 +6005,7 @@
   int len = array->length();
   for (int i = 0; i < len; i++) {
     Object* e = array->get(i);
-    if (!(e->IsString() || e->IsNumber())) return false;
+    if (!(e->IsName() || e->IsNumber())) return false;
   }
   return true;
 }
@@ -5875,14 +6213,14 @@
         FixedArray);
     DCHECK(ContainsOnlyValidKeys(content));
 
-    // Add the property keys from the interceptor.
+    // Add the non-symbol property keys from the interceptor.
     if (current->HasNamedInterceptor()) {
       Handle<JSObject> result;
       if (JSObject::GetKeysForNamedInterceptor(
               current, object).ToHandle(&result)) {
         ASSIGN_RETURN_ON_EXCEPTION(
-            isolate, content,
-            FixedArray::AddKeysFromArrayLike(content, result),
+            isolate, content, FixedArray::AddKeysFromArrayLike(
+                                  content, result, FixedArray::NON_SYMBOL_KEYS),
             FixedArray);
       }
       DCHECK(ContainsOnlyValidKeys(content));
@@ -6058,13 +6396,20 @@
                                        ? KEEP_INOBJECT_PROPERTIES
                                        : CLEAR_INOBJECT_PROPERTIES;
   // Normalize object to make this operation simple.
-  NormalizeProperties(object, mode, 0);
+  NormalizeProperties(object, mode, 0, "SetPropertyCallback");
 
   // For the global object allocate a new map to invalidate the global inline
   // caches which have a global property cell reference directly in the code.
   if (object->IsGlobalObject()) {
     Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
     DCHECK(new_map->is_dictionary_map());
+#if TRACE_MAPS
+    if (FLAG_trace_maps) {
+      PrintF("[TraceMaps: GlobalPropertyCallback from= %p to= %p ]\n",
+             reinterpret_cast<void*>(object->map()),
+             reinterpret_cast<void*>(*new_map));
+    }
+#endif
     JSObject::MigrateToMap(object, new_map);
 
     // When running crankshaft, changing the map is not enough. We
@@ -6116,7 +6461,7 @@
 
   Handle<Object> old_value = isolate->factory()->the_hole_value();
   bool is_observed = object->map()->is_observed() &&
-                     *name != isolate->heap()->hidden_string();
+                     !isolate->IsInternallyUsedPropertyName(name);
   bool preexists = false;
   if (is_observed) {
     if (is_element) {
@@ -6167,7 +6512,8 @@
 
   if (is_observed) {
     const char* type = preexists ? "reconfigure" : "add";
-    EnqueueChangeRecord(object, type, name, old_value);
+    RETURN_ON_EXCEPTION(
+        isolate, EnqueueChangeRecord(object, type, name, old_value), Object);
   }
 
   return isolate->factory()->undefined_value();
@@ -6336,17 +6682,27 @@
   if (HasFastProperties()) {
     int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
     DescriptorArray* descs = map()->instance_descriptors();
+    bool value_is_number = value->IsNumber();
     for (int i = 0; i < number_of_own_descriptors; i++) {
       if (descs->GetType(i) == FIELD) {
-        Object* property =
-            RawFastPropertyAt(FieldIndex::ForDescriptor(map(), i));
-        if (descs->GetDetails(i).representation().IsDouble()) {
-          DCHECK(property->IsMutableHeapNumber());
-          if (value->IsNumber() && property->Number() == value->Number()) {
+        FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
+        if (IsUnboxedDoubleField(field_index)) {
+          if (value_is_number) {
+            double property = RawFastDoublePropertyAt(field_index);
+            if (property == value->Number()) {
+              return descs->GetKey(i);
+            }
+          }
+        } else {
+          Object* property = RawFastPropertyAt(field_index);
+          if (field_index.is_double()) {
+            DCHECK(property->IsMutableHeapNumber());
+            if (value_is_number && property->Number() == value->Number()) {
+              return descs->GetKey(i);
+            }
+          } else if (property == value) {
             return descs->GetKey(i);
           }
-        } else if (property == value) {
-          return descs->GetKey(i);
         }
       } else if (descs->GetType(i) == CONSTANT) {
         if (descs->GetConstant(i) == value) {
@@ -6364,7 +6720,7 @@
 Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
   Handle<Map> result = map->GetIsolate()->factory()->NewMap(
       map->instance_type(), instance_size);
-  result->set_prototype(map->prototype());
+  result->SetPrototype(handle(map->prototype(), map->GetIsolate()));
   result->set_constructor(map->constructor());
   result->set_bit_field(map->bit_field());
   result->set_bit_field2(map->bit_field2());
@@ -6377,15 +6733,14 @@
   if (!map->is_dictionary_map()) {
     new_bit_field3 = IsUnstable::update(new_bit_field3, false);
   }
-  new_bit_field3 = ConstructionCount::update(new_bit_field3,
-                                             JSFunction::kNoSlackTracking);
+  new_bit_field3 = Counter::update(new_bit_field3, kRetainingCounterStart);
   result->set_bit_field3(new_bit_field3);
   return result;
 }
 
 
-Handle<Map> Map::Normalize(Handle<Map> fast_map,
-                           PropertyNormalizationMode mode) {
+Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
+                           const char* reason) {
   DCHECK(!fast_map->is_dictionary_map());
 
   Isolate* isolate = fast_map->GetIsolate();
@@ -6424,6 +6779,13 @@
       cache->Set(fast_map, new_map);
       isolate->counters()->normalized_maps()->Increment();
     }
+#if TRACE_MAPS
+    if (FLAG_trace_maps) {
+      PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n",
+             reinterpret_cast<void*>(*fast_map),
+             reinterpret_cast<void*>(*new_map), reason);
+    }
+#endif
   }
   fast_map->NotifyLeafMapLayoutChange();
   return new_map;
@@ -6487,50 +6849,99 @@
     if (old_size == 0) {
       descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
     } else {
-      EnsureDescriptorSlack(map, old_size < 4 ? 1 : old_size / 2);
+      EnsureDescriptorSlack(
+          map, SlackForArraySize(old_size, kMaxNumberOfDescriptors));
       descriptors = handle(map->instance_descriptors());
     }
   }
 
+  Handle<LayoutDescriptor> layout_descriptor =
+      FLAG_unbox_double_fields
+          ? LayoutDescriptor::Append(map, descriptor->GetDetails())
+          : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
+
   {
     DisallowHeapAllocation no_gc;
     descriptors->Append(descriptor);
-    result->InitializeDescriptors(*descriptors);
+    result->InitializeDescriptors(*descriptors, *layout_descriptor);
   }
 
   DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
-  ConnectTransition(map, result, name, SIMPLE_TRANSITION);
+  ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
 
   return result;
 }
 
 
+#if TRACE_MAPS
+
+// static
+void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
+  if (FLAG_trace_maps) {
+    PrintF("[TraceMaps: %s from= %p to= %p name= ", what,
+           reinterpret_cast<void*>(from), reinterpret_cast<void*>(to));
+    name->NameShortPrint();
+    PrintF(" ]\n");
+  }
+}
+
+
+// static
+void Map::TraceAllTransitions(Map* map) {
+  if (!map->HasTransitionArray()) return;
+  TransitionArray* transitions = map->transitions();
+  for (int i = 0; i < transitions->number_of_transitions(); ++i) {
+    Map* target = transitions->GetTarget(i);
+    Map::TraceTransition("Transition", map, target, transitions->GetKey(i));
+    Map::TraceAllTransitions(target);
+  }
+}
+
+#endif  // TRACE_MAPS
+
+
 void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
                             Handle<Name> name, SimpleTransitionFlag flag) {
   parent->set_owns_descriptors(false);
   if (parent->is_prototype_map()) {
     DCHECK(child->is_prototype_map());
+#if TRACE_MAPS
+    Map::TraceTransition("NoTransition", *parent, *child, *name);
+#endif
   } else {
     Handle<TransitionArray> transitions =
-        TransitionArray::CopyInsert(parent, name, child, flag);
-    parent->set_transitions(*transitions);
+        TransitionArray::Insert(parent, name, child, flag);
+    if (!parent->HasTransitionArray() ||
+        *transitions != parent->transitions()) {
+      parent->set_transitions(*transitions);
+    }
     child->SetBackPointer(*parent);
+    if (child->prototype()->IsJSObject()) {
+      Handle<JSObject> proto(JSObject::cast(child->prototype()));
+      if (!child->ShouldRegisterAsPrototypeUser(proto)) {
+        JSObject::UnregisterPrototypeUser(proto, child);
+      }
+    }
+#if TRACE_MAPS
+    Map::TraceTransition("Transition", *parent, *child, *name);
+#endif
   }
 }
 
 
-Handle<Map> Map::CopyReplaceDescriptors(Handle<Map> map,
-                                        Handle<DescriptorArray> descriptors,
-                                        TransitionFlag flag,
-                                        MaybeHandle<Name> maybe_name,
-                                        SimpleTransitionFlag simple_flag) {
+Handle<Map> Map::CopyReplaceDescriptors(
+    Handle<Map> map, Handle<DescriptorArray> descriptors,
+    Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
+    MaybeHandle<Name> maybe_name, const char* reason,
+    SimpleTransitionFlag simple_flag) {
   DCHECK(descriptors->IsSortedNoDuplicates());
 
   Handle<Map> result = CopyDropDescriptors(map);
-  result->InitializeDescriptors(*descriptors);
 
   if (!map->is_prototype_map()) {
     if (flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()) {
+      result->InitializeDescriptors(*descriptors, *layout_descriptor);
+
       Handle<Name> name;
       CHECK(maybe_name.ToHandle(&name));
       ConnectTransition(map, result, name, simple_flag);
@@ -6542,8 +6953,22 @@
           descriptors->SetValue(i, HeapType::Any());
         }
       }
+      result->InitializeDescriptors(*descriptors,
+                                    LayoutDescriptor::FastPointerLayout());
     }
+  } else {
+    result->InitializeDescriptors(*descriptors, *layout_descriptor);
   }
+#if TRACE_MAPS
+  if (FLAG_trace_maps &&
+      // Mirror conditions above that did not call ConnectTransition().
+      (map->is_prototype_map() ||
+       !(flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()))) {
+    PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
+           reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
+           reason);
+  }
+#endif
 
   return result;
 }
@@ -6551,28 +6976,37 @@
 
 // Since this method is used to rewrite an existing transition tree, it can
 // always insert transitions without checking.
-Handle<Map> Map::CopyInstallDescriptors(Handle<Map> map,
-                                        int new_descriptor,
-                                        Handle<DescriptorArray> descriptors) {
+Handle<Map> Map::CopyInstallDescriptors(
+    Handle<Map> map, int new_descriptor, Handle<DescriptorArray> descriptors,
+    Handle<LayoutDescriptor> full_layout_descriptor) {
   DCHECK(descriptors->IsSortedNoDuplicates());
 
   Handle<Map> result = CopyDropDescriptors(map);
 
-  result->InitializeDescriptors(*descriptors);
+  result->set_instance_descriptors(*descriptors);
   result->SetNumberOfOwnDescriptors(new_descriptor + 1);
 
   int unused_property_fields = map->unused_property_fields();
-  if (descriptors->GetDetails(new_descriptor).type() == FIELD) {
+  PropertyDetails details = descriptors->GetDetails(new_descriptor);
+  if (details.type() == FIELD) {
     unused_property_fields = map->unused_property_fields() - 1;
     if (unused_property_fields < 0) {
       unused_property_fields += JSObject::kFieldsAdded;
     }
   }
-
   result->set_unused_property_fields(unused_property_fields);
 
+  if (FLAG_unbox_double_fields) {
+    Handle<LayoutDescriptor> layout_descriptor =
+        LayoutDescriptor::AppendIfFastOrUseFull(map, details,
+                                                full_layout_descriptor);
+    result->set_layout_descriptor(*layout_descriptor);
+    SLOW_DCHECK(result->layout_descriptor()->IsConsistentWithMap(*result));
+    result->set_visitor_id(StaticVisitorBase::GetVisitorId(*result));
+  }
+
   Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
-  ConnectTransition(map, result, name, SIMPLE_TRANSITION);
+  ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
 
   return result;
 }
@@ -6593,8 +7027,9 @@
     DCHECK(kind != map->elements_kind());
   }
 
-  bool insert_transition =
-      flag == INSERT_TRANSITION && !map->HasElementsTransition();
+  bool insert_transition = flag == INSERT_TRANSITION &&
+                           map->CanHaveMoreTransitions() &&
+                           !map->HasElementsTransition();
 
   if (insert_transition && map->owns_descriptors()) {
     // In case the map owned its own descriptors, share the descriptors and
@@ -6604,14 +7039,16 @@
     ConnectElementsTransition(map, new_map);
 
     new_map->set_elements_kind(kind);
-    new_map->InitializeDescriptors(map->instance_descriptors());
+    // The properties did not change, so reuse descriptors.
+    new_map->InitializeDescriptors(map->instance_descriptors(),
+                                   map->GetLayoutDescriptor());
     return new_map;
   }
 
   // In case the map did not own its own descriptors, a split is forced by
   // copying the map; creating a new descriptor array cell.
   // Create a new free-floating map only if we are not allowed to store it.
-  Handle<Map> new_map = Copy(map);
+  Handle<Map> new_map = Copy(map, "CopyAsElementsKind");
 
   new_map->set_elements_kind(kind);
 
@@ -6635,33 +7072,40 @@
     new_map = CopyDropDescriptors(map);
   } else {
     DCHECK(!map->is_prototype_map());
-    new_map = Copy(map);
+    new_map = Copy(map, "CopyForObserved");
   }
 
   new_map->set_is_observed();
   if (map->owns_descriptors()) {
-    new_map->InitializeDescriptors(map->instance_descriptors());
+    // The properties did not change, so reuse descriptors.
+    new_map->InitializeDescriptors(map->instance_descriptors(),
+                                   map->GetLayoutDescriptor());
   }
 
-  Handle<Name> name = isolate->factory()->observed_symbol();
-  ConnectTransition(map, new_map, name, FULL_TRANSITION);
-
+  if (map->CanHaveMoreTransitions()) {
+    Handle<Name> name = isolate->factory()->observed_symbol();
+    ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
+  }
   return new_map;
 }
 
 
-Handle<Map> Map::Copy(Handle<Map> map) {
+Handle<Map> Map::Copy(Handle<Map> map, const char* reason) {
   Handle<DescriptorArray> descriptors(map->instance_descriptors());
   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
   Handle<DescriptorArray> new_descriptors =
       DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
-  return CopyReplaceDescriptors(
-      map, new_descriptors, OMIT_TRANSITION, MaybeHandle<Name>());
+  Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
+                                                 map->GetIsolate());
+  return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
+                                OMIT_TRANSITION, MaybeHandle<Name>(), reason,
+                                SPECIAL_TRANSITION);
 }
 
 
 Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
-  Handle<Map> copy = Copy(handle(isolate->object_function()->initial_map()));
+  Handle<Map> copy =
+      Copy(handle(isolate->object_function()->initial_map()), "MapCreate");
 
   // Check that we do not overflow the instance size when adding the extra
   // inobject properties. If the instance size overflows, we allocate as many
@@ -6685,14 +7129,20 @@
 }
 
 
-Handle<Map> Map::CopyForFreeze(Handle<Map> map) {
+Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
+                                          PropertyAttributes attrs_to_add,
+                                          Handle<Symbol> transition_marker,
+                                          const char* reason) {
   int num_descriptors = map->NumberOfOwnDescriptors();
   Isolate* isolate = map->GetIsolate();
   Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
-      handle(map->instance_descriptors(), isolate), num_descriptors, FROZEN);
+      handle(map->instance_descriptors(), isolate), num_descriptors,
+      attrs_to_add);
+  Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
+                                                 isolate);
   Handle<Map> new_map = CopyReplaceDescriptors(
-      map, new_desc, INSERT_TRANSITION, isolate->factory()->frozen_symbol());
-  new_map->freeze();
+      map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
+      transition_marker, reason, SPECIAL_TRANSITION);
   new_map->set_is_extensible(false);
   new_map->set_elements_kind(DICTIONARY_ELEMENTS);
   return new_map;
@@ -6711,12 +7161,9 @@
              value->FitsRepresentation(details.representation()));
       return GetConstant(descriptor) == value;
 
+    case ACCESSOR_FIELD:
     case CALLBACKS:
       return false;
-
-    case NORMAL:
-      UNREACHABLE();
-      break;
   }
 
   UNREACHABLE();
@@ -6741,7 +7188,7 @@
   Handle<HeapType> type = value->OptimalType(isolate, representation);
 
   return GeneralizeRepresentation(map, descriptor, representation, type,
-                                  FORCE_FIELD);
+                                  FORCE_IN_OBJECT);
 }
 
 
@@ -6755,16 +7202,14 @@
   // Migrate to the newest map before storing the property.
   map = Update(map);
 
-  int index = map->SearchTransition(*name);
+  int index = map->SearchTransition(DATA, *name, attributes);
   if (index != TransitionArray::kNotFound) {
     Handle<Map> transition(map->GetTransition(index));
     int descriptor = transition->LastAdded();
 
-    // TODO(verwaest): Handle attributes better.
-    DescriptorArray* descriptors = transition->instance_descriptors();
-    if (descriptors->GetDetails(descriptor).attributes() != attributes) {
-      return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES);
-    }
+    DCHECK_EQ(attributes, transition->instance_descriptors()
+                              ->GetDetails(descriptor)
+                              .attributes());
 
     return Map::PrepareForDataProperty(transition, descriptor, value);
   }
@@ -6783,7 +7228,17 @@
 
   Handle<Map> result;
   if (!maybe_map.ToHandle(&result)) {
-    return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES);
+#if TRACE_MAPS
+    if (FLAG_trace_maps) {
+      Vector<char> name_buffer = Vector<char>::New(100);
+      name->NameShortPrint(name_buffer);
+      Vector<char> buffer = Vector<char>::New(128);
+      SNPrintF(buffer, "TooManyFastProperties %s", name_buffer.start());
+      return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, buffer.start());
+    }
+#endif
+    return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES,
+                          "TooManyFastProperties");
   }
 
   return result;
@@ -6797,8 +7252,9 @@
 
   // For now, give up on transitioning and just create a unique map.
   // TODO(verwaest/ishell): Cache transitions with different attributes.
-  return CopyGeneralizeAllRepresentations(map, descriptor, FORCE_FIELD,
-                                          attributes, "attributes mismatch");
+  return CopyGeneralizeAllRepresentations(map, descriptor, FORCE_IN_OBJECT,
+                                          attributes,
+                                          "GenAll_AttributesMismatch");
 }
 
 
@@ -6813,7 +7269,7 @@
   if (map->is_dictionary_map()) {
     // For global objects, property cells are inlined. We need to change the
     // map.
-    if (map->IsGlobalObjectMap()) return Copy(map);
+    if (map->IsGlobalObjectMap()) return Copy(map, "GlobalAccessor");
     return map;
   }
 
@@ -6824,34 +7280,24 @@
                                        ? KEEP_INOBJECT_PROPERTIES
                                        : CLEAR_INOBJECT_PROPERTIES;
 
-  int index = map->SearchTransition(*name);
+  int index = map->SearchTransition(ACCESSOR, *name, attributes);
   if (index != TransitionArray::kNotFound) {
     Handle<Map> transition(map->GetTransition(index));
     DescriptorArray* descriptors = transition->instance_descriptors();
-    // Fast path, assume that we're modifying the last added descriptor.
     int descriptor = transition->LastAdded();
-    if (descriptors->GetKey(descriptor) != *name) {
-      // If not, search for the descriptor.
-      descriptor = descriptors->SearchWithCache(*name, *transition);
-    }
+    DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
 
-    if (descriptors->GetDetails(descriptor).type() != CALLBACKS) {
-      return Map::Normalize(map, mode);
-    }
-
-    // TODO(verwaest): Handle attributes better.
-    if (descriptors->GetDetails(descriptor).attributes() != attributes) {
-      return Map::Normalize(map, mode);
-    }
+    DCHECK_EQ(ACCESSOR, descriptors->GetDetails(descriptor).kind());
+    DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
 
     Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
     if (!maybe_pair->IsAccessorPair()) {
-      return Map::Normalize(map, mode);
+      return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair");
     }
 
     Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
     if (pair->get(component) != *accessor) {
-      return Map::Normalize(map, mode);
+      return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
     }
 
     return transition;
@@ -6861,31 +7307,34 @@
   DescriptorArray* old_descriptors = map->instance_descriptors();
   int descriptor = old_descriptors->SearchWithCache(*name, *map);
   if (descriptor != DescriptorArray::kNotFound) {
+    if (descriptor != map->LastAdded()) {
+      return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
+    }
     PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
     if (old_details.type() != CALLBACKS) {
-      return Map::Normalize(map, mode);
+      return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
     }
 
     if (old_details.attributes() != attributes) {
-      return Map::Normalize(map, mode);
+      return Map::Normalize(map, mode, "AccessorsWithAttributes");
     }
 
     Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
     if (!maybe_pair->IsAccessorPair()) {
-      return Map::Normalize(map, mode);
+      return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
     }
 
     Object* current = Handle<AccessorPair>::cast(maybe_pair)->get(component);
     if (current == *accessor) return map;
 
     if (!current->IsTheHole()) {
-      return Map::Normalize(map, mode);
+      return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
     }
 
     pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
   } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
              map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
-    return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES);
+    return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors");
   } else {
     pair = isolate->factory()->NewAccessorPair();
   }
@@ -6915,8 +7364,14 @@
       descriptors, map->NumberOfOwnDescriptors(), 1);
   new_descriptors->Append(descriptor);
 
-  return CopyReplaceDescriptors(
-      map, new_descriptors, flag, descriptor->GetKey(), SIMPLE_TRANSITION);
+  Handle<LayoutDescriptor> new_layout_descriptor =
+      FLAG_unbox_double_fields
+          ? LayoutDescriptor::Append(map, descriptor->GetDetails())
+          : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
+
+  return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
+                                flag, descriptor->GetKey(), "CopyAddDescriptor",
+                                SIMPLE_PROPERTY_TRANSITION);
 }
 
 
@@ -7007,12 +7462,16 @@
       descriptors, map->NumberOfOwnDescriptors());
 
   new_descriptors->Replace(insertion_index, descriptor);
+  Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
+      map, new_descriptors, new_descriptors->number_of_descriptors());
 
   SimpleTransitionFlag simple_flag =
       (insertion_index == descriptors->number_of_descriptors() - 1)
-      ? SIMPLE_TRANSITION
-      : FULL_TRANSITION;
-  return CopyReplaceDescriptors(map, new_descriptors, flag, key, simple_flag);
+          ? SIMPLE_PROPERTY_TRANSITION
+          : PROPERTY_TRANSITION;
+  return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
+                                flag, key, "CopyReplaceDescriptor",
+                                simple_flag);
 }
 
 
@@ -7090,7 +7549,7 @@
     int value = Smi::cast(*IteratorField())->value();
     int index = -value - 1;
     int number_of_transitions = transition_array_->number_of_transitions();
-    while (index < number_of_transitions) {
+    if (index < number_of_transitions) {
       *IteratorField() = Smi::FromInt(value - 1);
       return transition_array_->GetTarget(index);
     }
@@ -7686,14 +8145,13 @@
 
 
 MaybeHandle<FixedArray> FixedArray::AddKeysFromArrayLike(
-    Handle<FixedArray> content,
-    Handle<JSObject> array) {
+    Handle<FixedArray> content, Handle<JSObject> array, KeyFilter filter) {
   DCHECK(array->IsJSArray() || array->HasSloppyArgumentsElements());
   ElementsAccessor* accessor = array->GetElementsAccessor();
   Handle<FixedArray> result;
   ASSIGN_RETURN_ON_EXCEPTION(
       array->GetIsolate(), result,
-      accessor->AddElementsToFixedArray(array, array, content),
+      accessor->AddElementsToFixedArray(array, array, content, filter),
       FixedArray);
 
 #ifdef ENABLE_SLOW_DCHECKS
@@ -7716,10 +8174,9 @@
   ASSIGN_RETURN_ON_EXCEPTION(
       first->GetIsolate(), result,
       accessor->AddElementsToFixedArray(
-          Handle<Object>::null(),     // receiver
-          Handle<JSObject>::null(),   // holder
-          first,
-          Handle<FixedArrayBase>::cast(second)),
+          Handle<Object>::null(),    // receiver
+          Handle<JSObject>::null(),  // holder
+          first, Handle<FixedArrayBase>::cast(second), ALL_KEYS),
       FixedArray);
 
 #ifdef ENABLE_SLOW_DCHECKS
@@ -7776,6 +8233,116 @@
 #endif
 
 
+// static
+void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index,
+                         Handle<HeapObject> value) {
+  DCHECK(array->IsEmptySlot(index));  // Don't overwrite anything.
+  Handle<WeakCell> cell =
+      value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value))
+                     : array->GetIsolate()->factory()->NewWeakCell(value);
+  Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell);
+  if (FLAG_trace_weak_arrays) {
+    PrintF("[WeakFixedArray: storing at index %d ]\n", index);
+  }
+  array->set_last_used_index(index);
+}
+
+
+// static
+Handle<WeakFixedArray> WeakFixedArray::Add(
+    Handle<Object> maybe_array, Handle<HeapObject> value,
+    SearchForDuplicates search_for_duplicates) {
+  Handle<WeakFixedArray> array =
+      (maybe_array.is_null() || !maybe_array->IsWeakFixedArray())
+          ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null())
+          : Handle<WeakFixedArray>::cast(maybe_array);
+
+  if (search_for_duplicates == kAddIfNotFound) {
+    for (int i = 0; i < array->Length(); ++i) {
+      if (array->Get(i) == *value) return array;
+    }
+  } else {
+#ifdef DEBUG
+    for (int i = 0; i < array->Length(); ++i) {
+      DCHECK_NE(*value, array->Get(i));
+    }
+#endif
+  }
+
+  // Try to store the new entry if there's room. Optimize for consecutive
+  // accesses.
+  int first_index = array->last_used_index();
+  for (int i = first_index;;) {
+    if (array->IsEmptySlot((i))) {
+      WeakFixedArray::Set(array, i, value);
+      return array;
+    }
+    if (FLAG_trace_weak_arrays) {
+      PrintF("[WeakFixedArray: searching for free slot]\n");
+    }
+    i = (i + 1) % array->Length();
+    if (i == first_index) break;
+  }
+
+  // No usable slot found, grow the array.
+  int new_length = array->Length() + (array->Length() >> 1) + 4;
+  Handle<WeakFixedArray> new_array =
+      Allocate(array->GetIsolate(), new_length, array);
+  if (FLAG_trace_weak_arrays) {
+    PrintF("[WeakFixedArray: growing to size %d ]\n", new_length);
+  }
+  WeakFixedArray::Set(new_array, array->Length(), value);
+  return new_array;
+}
+
+
+void WeakFixedArray::Remove(Handle<HeapObject> value) {
+  // Optimize for the most recently added element to be removed again.
+  int first_index = last_used_index();
+  for (int i = first_index;;) {
+    if (Get(i) == *value) {
+      clear(i);
+      // Users of WeakFixedArray should make sure that there are no duplicates,
+      // they can use Add(..., kAddIfNotFound) if necessary.
+      return;
+    }
+    i = (i + 1) % Length();
+    if (i == first_index) break;
+  }
+}
+
+
+// static
+Handle<WeakFixedArray> WeakFixedArray::Allocate(
+    Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) {
+  DCHECK(0 <= size);
+  Handle<FixedArray> result =
+      isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex);
+  Handle<WeakFixedArray> casted_result = Handle<WeakFixedArray>::cast(result);
+  if (initialize_from.is_null()) {
+    for (int i = 0; i < result->length(); ++i) {
+      result->set(i, Smi::FromInt(0));
+    }
+  } else {
+    DCHECK(initialize_from->Length() <= size);
+    Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from);
+    int target_index = kFirstIndex;
+    for (int source_index = kFirstIndex; source_index < raw_source->length();
+         ++source_index) {
+      // The act of allocating might have caused entries in the source array
+      // to be cleared. Copy only what's needed.
+      if (initialize_from->IsEmptySlot(source_index - kFirstIndex)) continue;
+      result->set(target_index++, raw_source->get(source_index));
+    }
+    casted_result->set_last_used_index(target_index - 1 - kFirstIndex);
+    for (; target_index < result->length(); ++target_index) {
+      result->set(target_index, Smi::FromInt(0));
+    }
+  }
+  return casted_result;
+}
+
+
 Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
                                                   int number_of_descriptors,
                                                   int slack) {
@@ -7819,8 +8386,7 @@
 }
 
 
-void DescriptorArray::CopyFrom(int index,
-                               DescriptorArray* src,
+void DescriptorArray::CopyFrom(int index, DescriptorArray* src,
                                const WhitenessWitness& witness) {
   Object* value = src->GetValue(index);
   PropertyDetails details = src->GetDetails(index);
@@ -7998,15 +8564,11 @@
   if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
     return SmartArrayPointer<char>(NULL);
   }
-  Heap* heap = GetHeap();
-
   // Negative length means the to the end of the string.
   if (length < 0) length = kMaxInt - offset;
 
   // Compute the size of the UTF-8 string. Start at the specified offset.
-  Access<ConsStringIteratorOp> op(
-      heap->isolate()->objects_string_iterator());
-  StringCharacterStream stream(this, op.value(), offset);
+  StringCharacterStream stream(this, offset);
   int character_position = offset;
   int utf8_bytes = 0;
   int last = unibrow::Utf16::kNoPreviousCharacter;
@@ -8073,11 +8635,7 @@
   if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
     return SmartArrayPointer<uc16>();
   }
-  Heap* heap = GetHeap();
-
-  Access<ConsStringIteratorOp> op(
-      heap->isolate()->objects_string_iterator());
-  StringCharacterStream stream(this, op.value());
+  StringCharacterStream stream(this);
 
   uc16* result = NewArray<uc16>(length() + 1);
 
@@ -8181,7 +8739,7 @@
 }
 
 
-void ConsStringIteratorOp::Initialize(ConsString* cons_string, int offset) {
+void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
   DCHECK(cons_string != NULL);
   root_ = cons_string;
   consumed_ = offset;
@@ -8192,7 +8750,7 @@
 }
 
 
-String* ConsStringIteratorOp::Continue(int* offset_out) {
+String* ConsStringIterator::Continue(int* offset_out) {
   DCHECK(depth_ != 0);
   DCHECK_EQ(0, *offset_out);
   bool blew_stack = StackBlown();
@@ -8210,7 +8768,7 @@
 }
 
 
-String* ConsStringIteratorOp::Search(int* offset_out) {
+String* ConsStringIterator::Search(int* offset_out) {
   ConsString* cons_string = root_;
   // Reset the stack, pushing the root string.
   depth_ = 1;
@@ -8271,7 +8829,7 @@
 }
 
 
-String* ConsStringIteratorOp::NextLeaf(bool* blew_stack) {
+String* ConsStringIterator::NextLeaf(bool* blew_stack) {
   while (true) {
     // Tree traversal complete.
     if (depth_ == 0) {
@@ -8548,15 +9106,14 @@
 class StringComparator {
   class State {
    public:
-    explicit inline State(ConsStringIteratorOp* op)
-      : op_(op), is_one_byte_(true), length_(0), buffer8_(NULL) {}
+    State() : is_one_byte_(true), length_(0), buffer8_(NULL) {}
 
-    inline void Init(String* string) {
+    void Init(String* string) {
       ConsString* cons_string = String::VisitFlat(this, string);
-      op_->Reset(cons_string);
+      iter_.Reset(cons_string);
       if (cons_string != NULL) {
         int offset;
-        string = op_->Next(&offset);
+        string = iter_.Next(&offset);
         String::VisitFlat(this, string, offset);
       }
     }
@@ -8587,13 +9144,13 @@
       }
       // Advance state.
       int offset;
-      String* next = op_->Next(&offset);
+      String* next = iter_.Next(&offset);
       DCHECK_EQ(0, offset);
       DCHECK(next != NULL);
       String::VisitFlat(this, next);
     }
 
-    ConsStringIteratorOp* const op_;
+    ConsStringIterator iter_;
     bool is_one_byte_;
     int length_;
     union {
@@ -8602,15 +9159,11 @@
     };
 
    private:
-    DISALLOW_IMPLICIT_CONSTRUCTORS(State);
+    DISALLOW_COPY_AND_ASSIGN(State);
   };
 
  public:
-  inline StringComparator(ConsStringIteratorOp* op_1,
-                          ConsStringIteratorOp* op_2)
-    : state_1_(op_1),
-      state_2_(op_2) {
-  }
+  inline StringComparator() {}
 
   template<typename Chars1, typename Chars2>
   static inline bool Equals(State* state_1, State* state_2, int to_check) {
@@ -8653,7 +9206,8 @@
  private:
   State state_1_;
   State state_2_;
-  DISALLOW_IMPLICIT_CONSTRUCTORS(StringComparator);
+
+  DISALLOW_COPY_AND_ASSIGN(StringComparator);
 };
 
 
@@ -8694,10 +9248,7 @@
     return CompareRawStringContents(str1, str2, len);
   }
 
-  Isolate* isolate = GetIsolate();
-  StringComparator comparator(isolate->objects_string_compare_iterator_a(),
-                              isolate->objects_string_compare_iterator_b());
-
+  StringComparator comparator;
   return comparator.Equals(this, other);
 }
 
@@ -8849,8 +9400,7 @@
 bool String::ComputeArrayIndex(uint32_t* index) {
   int length = this->length();
   if (length == 0 || length > kMaxArrayIndexSize) return false;
-  ConsStringIteratorOp op;
-  StringCharacterStream stream(this, &op);
+  StringCharacterStream stream(this);
   return StringToArrayIndex(&stream, index);
 }
 
@@ -8991,6 +9541,35 @@
 }
 
 
+void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
+  // Run small ConsStrings through ConsStringIterator.
+  if (cons_string->length() < 64) {
+    ConsStringIterator iter(cons_string);
+    int offset;
+    String* string;
+    while (nullptr != (string = iter.Next(&offset))) {
+      DCHECK_EQ(0, offset);
+      String::VisitFlat(this, string, 0);
+    }
+    return;
+  }
+  // Slow case.
+  const int max_length = String::kMaxHashCalcLength;
+  int length = std::min(cons_string->length(), max_length);
+  if (cons_string->HasOnlyOneByteChars()) {
+    uint8_t* buffer = new uint8_t[length];
+    String::WriteToFlat(cons_string, buffer, 0, length);
+    AddCharacters(buffer, length);
+    delete[] buffer;
+  } else {
+    uint16_t* buffer = new uint16_t[length];
+    String::WriteToFlat(cons_string, buffer, 0, length);
+    AddCharacters(buffer, length);
+    delete[] buffer;
+  }
+}
+
+
 void String::PrintOn(FILE* file) {
   int length = this->length();
   for (int i = 0; i < length; i++) {
@@ -8999,19 +9578,25 @@
 }
 
 
+inline static uint32_t ObjectAddressForHashing(Object* object) {
+  uint32_t value = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object));
+  return value & MemoryChunk::kAlignmentMask;
+}
+
+
 int Map::Hash() {
   // For performance reasons we only hash the 3 most variable fields of a map:
-  // constructor, prototype and bit_field2.
+  // constructor, prototype and bit_field2. For predictability reasons we
+  // use objects' offsets in respective pages for hashing instead of raw
+  // addresses.
 
   // Shift away the tag.
-  int hash = (static_cast<uint32_t>(
-        reinterpret_cast<uintptr_t>(constructor())) >> 2);
+  int hash = ObjectAddressForHashing(constructor()) >> 2;
 
   // XOR-ing the prototype and constructor directly yields too many zero bits
   // when the two pointers are close (which is fairly common).
-  // To avoid this we shift the prototype 4 bits relatively to the constructor.
-  hash ^= (static_cast<uint32_t>(
-        reinterpret_cast<uintptr_t>(prototype())) << 2);
+  // To avoid this we shift the prototype bits relatively to the constructor.
+  hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
 
   return hash ^ (hash >> 16) ^ bit_field2();
 }
@@ -9024,7 +9609,6 @@
     first->instance_type() == second->instance_type() &&
     first->bit_field() == second->bit_field() &&
     first->bit_field2() == second->bit_field2() &&
-    first->is_frozen() == second->is_frozen() &&
     first->has_instance_call_handler() == second->has_instance_call_handler();
 }
 
@@ -9095,22 +9679,40 @@
 
 
 void JSFunction::MarkForOptimization() {
+  Isolate* isolate = GetIsolate();
+  DCHECK(isolate->use_crankshaft());
   DCHECK(!IsOptimized());
   DCHECK(shared()->allows_lazy_compilation() ||
          code()->optimizable());
   DCHECK(!shared()->is_generator());
   set_code_no_write_barrier(
-      GetIsolate()->builtins()->builtin(Builtins::kCompileOptimized));
+      isolate->builtins()->builtin(Builtins::kCompileOptimized));
   // No write barrier required, since the builtin is part of the root set.
 }
 
 
-void JSFunction::MarkForConcurrentOptimization() {
-  DCHECK(is_compiled() || GetIsolate()->DebuggerHasBreakPoints());
+void JSFunction::AttemptConcurrentOptimization() {
+  Isolate* isolate = GetIsolate();
+  if (!isolate->concurrent_recompilation_enabled() ||
+      isolate->bootstrapper()->IsActive()) {
+    MarkForOptimization();
+    return;
+  }
+  if (isolate->concurrent_osr_enabled() &&
+      isolate->optimizing_compiler_thread()->IsQueuedForOSR(this)) {
+    // Do not attempt regular recompilation if we already queued this for OSR.
+    // TODO(yangguo): This is necessary so that we don't install optimized
+    // code on a function that is already optimized, since OSR and regular
+    // recompilation race.  This goes away as soon as OSR becomes one-shot.
+    return;
+  }
+  DCHECK(isolate->use_crankshaft());
+  DCHECK(!IsInOptimizationQueue());
+  DCHECK(is_compiled() || isolate->DebuggerHasBreakPoints());
   DCHECK(!IsOptimized());
   DCHECK(shared()->allows_lazy_compilation() || code()->optimizable());
   DCHECK(!shared()->is_generator());
-  DCHECK(GetIsolate()->concurrent_recompilation_enabled());
+  DCHECK(isolate->concurrent_recompilation_enabled());
   if (FLAG_trace_concurrent_recompilation) {
     PrintF("  ** Marking ");
     ShortPrint();
@@ -9122,24 +9724,6 @@
 }
 
 
-void JSFunction::MarkInOptimizationQueue() {
-  // We can only arrive here via the concurrent-recompilation builtin.  If
-  // break points were set, the code would point to the lazy-compile builtin.
-  DCHECK(!GetIsolate()->DebuggerHasBreakPoints());
-  DCHECK(IsMarkedForConcurrentOptimization() && !IsOptimized());
-  DCHECK(shared()->allows_lazy_compilation() || code()->optimizable());
-  DCHECK(GetIsolate()->concurrent_recompilation_enabled());
-  if (FLAG_trace_concurrent_recompilation) {
-    PrintF("  ** Queueing ");
-    ShortPrint();
-    PrintF(" for concurrent recompilation.\n");
-  }
-  set_code_no_write_barrier(
-      GetIsolate()->builtins()->builtin(Builtins::kInOptimizationQueue));
-  // No write barrier required, since the builtin is part of the root set.
-}
-
-
 Handle<JSFunction> JSFunction::CloneClosure(Handle<JSFunction> function) {
   Isolate* isolate = function->GetIsolate();
   Handle<Map> map(function->map());
@@ -9315,15 +9899,20 @@
   if (object->IsJSGlobalProxy()) return;
   if (mode == FAST_PROTOTYPE && !object->map()->is_prototype_map()) {
     // First normalize to ensure all JSFunctions are CONSTANT.
-    JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0);
+    JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
+                                  "NormalizeAsPrototype");
   }
+  bool has_just_copied_map = false;
   if (!object->HasFastProperties()) {
-    JSObject::MigrateSlowToFast(object, 0);
+    JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
+    has_just_copied_map = true;
   }
   if (mode == FAST_PROTOTYPE && object->HasFastProperties() &&
       !object->map()->is_prototype_map()) {
-    Handle<Map> new_map = Map::Copy(handle(object->map()));
-    JSObject::MigrateToMap(object, new_map);
+    if (!has_just_copied_map) {
+      Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
+      JSObject::MigrateToMap(object, new_map);
+    }
     object->map()->set_is_prototype_map(true);
   }
 }
@@ -9335,6 +9924,74 @@
 }
 
 
+void JSObject::RegisterPrototypeUser(Handle<JSObject> prototype,
+                                     Handle<HeapObject> user) {
+  DCHECK(FLAG_track_prototype_users);
+  Isolate* isolate = prototype->GetIsolate();
+  Handle<Name> symbol = isolate->factory()->prototype_users_symbol();
+
+  // Get prototype users array, create it if it doesn't exist yet.
+  Handle<Object> maybe_array =
+      JSObject::GetProperty(prototype, symbol).ToHandleChecked();
+
+  Handle<WeakFixedArray> new_array = WeakFixedArray::Add(maybe_array, user);
+  if (!maybe_array.is_identical_to(new_array)) {
+    JSObject::SetOwnPropertyIgnoreAttributes(prototype, symbol, new_array,
+                                             DONT_ENUM).Assert();
+  }
+}
+
+
+void JSObject::UnregisterPrototypeUser(Handle<JSObject> prototype,
+                                       Handle<HeapObject> user) {
+  Isolate* isolate = prototype->GetIsolate();
+  Handle<Name> symbol = isolate->factory()->prototype_users_symbol();
+
+  Handle<Object> maybe_array =
+      JSObject::GetProperty(prototype, symbol).ToHandleChecked();
+  if (!maybe_array->IsWeakFixedArray()) return;
+  Handle<WeakFixedArray>::cast(maybe_array)->Remove(user);
+}
+
+
+void Map::SetPrototype(Handle<Object> prototype,
+                       PrototypeOptimizationMode proto_mode) {
+  if (this->prototype()->IsJSObject() && FLAG_track_prototype_users) {
+    Handle<JSObject> old_prototype(JSObject::cast(this->prototype()));
+    JSObject::UnregisterPrototypeUser(old_prototype, handle(this));
+  }
+  if (prototype->IsJSObject()) {
+    Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
+    if (ShouldRegisterAsPrototypeUser(prototype_jsobj)) {
+      JSObject::RegisterPrototypeUser(prototype_jsobj, handle(this));
+    }
+    JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode);
+  }
+  WriteBarrierMode wb_mode =
+      prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
+  set_prototype(*prototype, wb_mode);
+}
+
+
+bool Map::ShouldRegisterAsPrototypeUser(Handle<JSObject> prototype) {
+  if (!FLAG_track_prototype_users) return false;
+  if (this->is_prototype_map()) return true;
+  if (this->is_dictionary_map()) return false;
+  Object* back = GetBackPointer();
+  if (!back->IsMap()) return true;
+  if (Map::cast(back)->prototype() != *prototype) return true;
+  return false;
+}
+
+
+bool Map::CanUseOptimizationsBasedOnPrototypeRegistry() {
+  if (!FLAG_track_prototype_users) return false;
+  if (this->is_prototype_map()) return true;
+  if (GetBackPointer()->IsMap()) return true;
+  return false;
+}
+
+
 Handle<Object> CacheInitialJSArrayMaps(
     Handle<Context> native_context, Handle<Map> initial_map) {
   // Replace all of the cached initial array maps in the native context with
@@ -9392,7 +10049,7 @@
       // into the initial map where it belongs.
       function->set_prototype_or_initial_map(*value);
     } else {
-      Handle<Map> new_map = Map::Copy(initial_map);
+      Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
       JSFunction::SetInitialMap(function, new_map, value);
 
       // If the function is used as the global Array function, cache the
@@ -9432,7 +10089,7 @@
     // Copy the map so this does not affect unrelated functions.
     // Remove map transitions because they point to maps with a
     // different prototype.
-    Handle<Map> new_map = Map::Copy(handle(function->map()));
+    Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype");
 
     JSObject::MigrateToMap(function, new_map);
     new_map->set_constructor(*value);
@@ -9473,13 +10130,18 @@
 
 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
                                Handle<Object> prototype) {
-  if (prototype->IsJSObject()) {
-    Handle<JSObject> js_proto = Handle<JSObject>::cast(prototype);
-    JSObject::OptimizeAsPrototype(js_proto, FAST_PROTOTYPE);
+  if (map->prototype() != *prototype) {
+    map->SetPrototype(prototype, FAST_PROTOTYPE);
   }
-  map->set_prototype(*prototype);
   function->set_prototype_or_initial_map(*map);
   map->set_constructor(*function);
+#if TRACE_MAPS
+  if (FLAG_trace_maps) {
+    PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n",
+           reinterpret_cast<void*>(*map), function->shared()->unique_id(),
+           function->shared()->DebugName()->ToCString().get());
+  }
+#endif
 }
 
 
@@ -9629,27 +10291,31 @@
 }
 
 
-int Script::GetLineNumberWithArray(int code_pos) {
+int Script::GetLineNumberWithArray(int position) {
   DisallowHeapAllocation no_allocation;
-  DCHECK(line_ends()->IsFixedArray());
-  FixedArray* line_ends_array = FixedArray::cast(line_ends());
-  int line_ends_len = line_ends_array->length();
-  if (line_ends_len == 0) return -1;
+  FixedArray* line_ends = FixedArray::cast(this->line_ends());
+  int upper = line_ends->length() - 1;
+  if (upper < 0) return -1;
+  int offset = line_offset()->value();
 
-  if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
-    return line_offset()->value();
+  if (position > Smi::cast(line_ends->get(upper))->value()) {
+    return upper + 1 + offset;
   }
+  if (position <= Smi::cast(line_ends->get(0))->value()) return offset;
 
-  int left = 0;
-  int right = line_ends_len;
-  while (int half = (right - left) / 2) {
-    if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
-      right -= half;
+  int lower = 1;
+  // Binary search.
+  while (true) {
+    int mid = (lower + upper) / 2;
+    if (position <= Smi::cast(line_ends->get(mid - 1))->value()) {
+      upper = mid - 1;
+    } else if (position > Smi::cast(line_ends->get(mid))->value()) {
+      lower = mid + 1;
     } else {
-      left += half;
+      return mid + offset;
     }
   }
-  return right + line_offset()->value();
+  return -1;
 }
 
 
@@ -9697,54 +10363,27 @@
 }
 
 
-// Wrappers for scripts are kept alive and cached in weak global
-// handles referred from foreign objects held by the scripts as long as
-// they are used. When they are not used anymore, the garbage
-// collector will call the weak callback on the global handle
-// associated with the wrapper and get rid of both the wrapper and the
-// handle.
-static void ClearWrapperCacheWeakCallback(
-    const v8::WeakCallbackData<v8::Value, void>& data) {
-  Object** location = reinterpret_cast<Object**>(data.GetParameter());
-  JSValue* wrapper = JSValue::cast(*location);
-  Script::cast(wrapper->value())->ClearWrapperCache();
-}
-
-
-void Script::ClearWrapperCache() {
-  Foreign* foreign = wrapper();
-  Object** location = reinterpret_cast<Object**>(foreign->foreign_address());
-  DCHECK_EQ(foreign->foreign_address(), reinterpret_cast<Address>(location));
-  foreign->set_foreign_address(0);
-  GlobalHandles::Destroy(location);
-  GetIsolate()->counters()->script_wrappers()->Decrement();
-}
-
-
 Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
-  if (script->wrapper()->foreign_address() != NULL) {
-    // Return a handle for the existing script wrapper from the cache.
-    return Handle<JSValue>(
-        *reinterpret_cast<JSValue**>(script->wrapper()->foreign_address()));
-  }
   Isolate* isolate = script->GetIsolate();
+  if (!script->wrapper()->IsUndefined()) {
+    Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
+    if (!cell->cleared()) {
+      // Return a handle for the existing script wrapper from the cache.
+      return handle(JSObject::cast(cell->value()));
+    }
+    // If we found an empty WeakCell, that means the script wrapper was
+    // GCed.  We are not notified directly of that, so we decrement here
+    // so that we at least don't count double for any given script.
+    isolate->counters()->script_wrappers()->Decrement();
+  }
   // Construct a new script wrapper.
   isolate->counters()->script_wrappers()->Increment();
   Handle<JSFunction> constructor = isolate->script_function();
   Handle<JSValue> result =
       Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
-
   result->set_value(*script);
-
-  // Create a new weak global handle and use it to cache the wrapper
-  // for future use. The cache will automatically be cleared by the
-  // garbage collector when it is not used anymore.
-  Handle<Object> handle = isolate->global_handles()->Create(*result);
-  GlobalHandles::MakeWeak(handle.location(),
-                          reinterpret_cast<void*>(handle.location()),
-                          &ClearWrapperCacheWeakCallback);
-  script->wrapper()->set_foreign_address(
-      reinterpret_cast<Address>(handle.location()));
+  Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result);
+  script->set_wrapper(*cell);
   return result;
 }
 
@@ -9802,7 +10441,7 @@
 
 
 // Output the source code without any allocation in the heap.
-OStream& operator<<(OStream& os, const SourceCodeOf& v) {
+std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
   const SharedFunctionInfo* s = v.value;
   // For some native functions there is no source.
   if (!s->HasSourceCode()) return os << "<No Source>";
@@ -9875,8 +10514,9 @@
   // regenerated and set on the shared function info it is marked as
   // non-optimizable if optimization is disabled for the shared
   // function info.
+  DCHECK(reason != kNoReason);
   set_optimization_disabled(true);
-  set_bailout_reason(reason);
+  set_disable_optimization_reason(reason);
   // Code should be the lazy compilation stub or else unoptimized.  If the
   // latter, disable optimization for the code too.
   DCHECK(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
@@ -9906,20 +10546,15 @@
 void JSFunction::StartInobjectSlackTracking() {
   DCHECK(has_initial_map() && !IsInobjectSlackTrackingInProgress());
 
-  if (!FLAG_clever_optimizations) return;
   Map* map = initial_map();
 
-  // Only initiate the tracking the first time.
-  if (map->done_inobject_slack_tracking()) return;
-  map->set_done_inobject_slack_tracking(true);
-
   // No tracking during the snapshot construction phase.
   Isolate* isolate = GetIsolate();
   if (isolate->serializer_enabled()) return;
 
   if (map->unused_property_fields() == 0) return;
 
-  map->set_construction_count(kGenerousAllocationCount);
+  map->set_counter(Map::kSlackTrackingCounterStart);
 }
 
 
@@ -9966,8 +10601,8 @@
   DCHECK(has_initial_map());
   Map* map = initial_map();
 
-  DCHECK(map->done_inobject_slack_tracking());
-  map->set_construction_count(kNoSlackTracking);
+  DCHECK(map->counter() >= Map::kSlackTrackingCounterEnd - 1);
+  map->set_counter(Map::kRetainingCounterStart);
 
   int slack = map->unused_property_fields();
   map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
@@ -10237,6 +10872,7 @@
   for (RelocIterator it(this, mask); !it.done(); it.next()) {
     RelocInfo* info = it.rinfo();
     Object* object = info->target_object();
+    if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
     if (object->IsHeapObject()) {
       if (HeapObject::cast(object)->map() == match_map) {
         if (--n == 0) return object;
@@ -10269,6 +10905,9 @@
     RelocInfo* info = it.rinfo();
     Object* object = info->target_object();
     if (object->IsHeapObject()) {
+      if (object->IsWeakCell()) {
+        object = HeapObject::cast(WeakCell::cast(object)->value());
+      }
       Map* map = HeapObject::cast(object)->map();
       if (map == *pattern.find_[current_pattern]) {
         info->set_target_object(*pattern.replace_[current_pattern]);
@@ -10287,6 +10926,7 @@
   for (RelocIterator it(this, mask); !it.done(); it.next()) {
     RelocInfo* info = it.rinfo();
     Object* object = info->target_object();
+    if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
     if (object->IsMap()) maps->Add(handle(Map::cast(object)));
   }
 }
@@ -10295,11 +10935,21 @@
 Code* Code::FindFirstHandler() {
   DCHECK(is_inline_cache_stub());
   DisallowHeapAllocation no_allocation;
-  int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
+  int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
+             RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+  bool skip_next_handler = false;
   for (RelocIterator it(this, mask); !it.done(); it.next()) {
     RelocInfo* info = it.rinfo();
-    Code* code = Code::GetCodeFromTargetAddress(info->target_address());
-    if (code->kind() == Code::HANDLER) return code;
+    if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
+      Object* obj = info->target_object();
+      skip_next_handler |= obj->IsWeakCell() && WeakCell::cast(obj)->cleared();
+    } else {
+      Code* code = Code::GetCodeFromTargetAddress(info->target_address());
+      if (code->kind() == Code::HANDLER) {
+        if (!skip_next_handler) return code;
+        skip_next_handler = false;
+      }
+    }
   }
   return NULL;
 }
@@ -10308,17 +10958,27 @@
 bool Code::FindHandlers(CodeHandleList* code_list, int length) {
   DCHECK(is_inline_cache_stub());
   DisallowHeapAllocation no_allocation;
-  int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
+  int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
+             RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+  bool skip_next_handler = false;
   int i = 0;
   for (RelocIterator it(this, mask); !it.done(); it.next()) {
     if (i == length) return true;
     RelocInfo* info = it.rinfo();
-    Code* code = Code::GetCodeFromTargetAddress(info->target_address());
-    // IC stubs with handlers never contain non-handler code objects before
-    // handler targets.
-    if (code->kind() != Code::HANDLER) break;
-    code_list->Add(Handle<Code>(code));
-    i++;
+    if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
+      Object* obj = info->target_object();
+      skip_next_handler |= obj->IsWeakCell() && WeakCell::cast(obj)->cleared();
+    } else {
+      Code* code = Code::GetCodeFromTargetAddress(info->target_address());
+      // IC stubs with handlers never contain non-handler code objects before
+      // handler targets.
+      if (code->kind() != Code::HANDLER) break;
+      if (!skip_next_handler) {
+        code_list->Add(Handle<Code>(code));
+        i++;
+      }
+      skip_next_handler = false;
+    }
   }
   return i == length;
 }
@@ -10333,6 +10993,7 @@
     RelocInfo* info = it.rinfo();
     if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
       Object* object = info->target_object();
+      if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
       if (object == map) return_next = true;
     } else if (return_next) {
       Code* code = Code::GetCodeFromTargetAddress(info->target_address());
@@ -10385,27 +11046,7 @@
 
 
 void SharedFunctionInfo::ClearTypeFeedbackInfo() {
-  TypeFeedbackVector* vector = feedback_vector();
-  Heap* heap = GetHeap();
-  int length = vector->length();
-
-  for (int i = 0; i < length; i++) {
-    Object* obj = vector->get(i);
-    if (obj->IsHeapObject()) {
-      InstanceType instance_type =
-          HeapObject::cast(obj)->map()->instance_type();
-      switch (instance_type) {
-        case ALLOCATION_SITE_TYPE:
-          // AllocationSites are not cleared because they do not store
-          // information that leaks.
-          break;
-          // Fall through...
-        default:
-          vector->set(i, TypeFeedbackVector::RawUninitializedSentinel(heap),
-                      SKIP_WRITE_BARRIER);
-      }
-    }
-  }
+  feedback_vector()->ClearSlots(this);
 }
 
 
@@ -10455,6 +11096,12 @@
 }
 
 
+void Code::MakeYoung(Isolate* isolate) {
+  byte* sequence = FindCodeAgeSequence();
+  if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, isolate);
+}
+
+
 void Code::MakeOlder(MarkingParity current_parity) {
   byte* sequence = FindCodeAgeSequence();
   if (sequence != NULL) {
@@ -10622,7 +11269,7 @@
 #ifdef ENABLE_DISASSEMBLER
 
 void DeoptimizationInputData::DeoptimizationInputDataPrint(
-    OStream& os) {  // NOLINT
+    std::ostream& os) {  // NOLINT
   disasm::NameConverter converter;
   int deopt_count = DeoptCount();
   os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
@@ -10783,7 +11430,7 @@
 
 
 void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
-    OStream& os) {  // NOLINT
+    std::ostream& os) {  // NOLINT
   os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints()
      << ")\n";
   if (this->DeoptPoints() == 0) return;
@@ -10831,7 +11478,7 @@
 }
 
 
-void Code::PrintExtraICState(OStream& os,  // NOLINT
+void Code::PrintExtraICState(std::ostream& os,  // NOLINT
                              Kind kind, ExtraICState extra) {
   os << "extra_ic_state = ";
   if ((kind == STORE_IC || kind == KEYED_STORE_IC) && (extra == STRICT)) {
@@ -10842,7 +11489,7 @@
 }
 
 
-void Code::Disassemble(const char* name, OStream& os) {  // NOLINT
+void Code::Disassemble(const char* name, std::ostream& os) {  // NOLINT
   os << "kind = " << Kind2String(kind()) << "\n";
   if (IsCodeStubOrIC()) {
     const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this), true);
@@ -10871,10 +11518,19 @@
   }
 
   os << "Instructions (size = " << instruction_size() << ")\n";
-  // TODO(svenpanne) The Disassembler should use streams, too!
   {
-    CodeTracer::Scope trace_scope(GetIsolate()->GetCodeTracer());
-    Disassembler::Decode(trace_scope.file(), this);
+    Isolate* isolate = GetIsolate();
+    int decode_size = is_crankshafted()
+                          ? static_cast<int>(safepoint_table_offset())
+                          : instruction_size();
+    // If there might be a back edge table, stop before reaching it.
+    if (kind() == Code::FUNCTION) {
+      decode_size =
+          Min(decode_size, static_cast<int>(back_edge_table_offset()));
+    }
+    byte* begin = instruction_start();
+    byte* end = begin + decode_size;
+    Disassembler::Decode(isolate, &os, begin, end, this);
   }
   os << "\n";
 
@@ -10894,7 +11550,7 @@
     os << "Safepoints (size = " << table.size() << ")\n";
     for (unsigned i = 0; i < table.length(); i++) {
       unsigned pc_offset = table.GetPcOffset(i);
-      os << (instruction_start() + pc_offset) << "  ";
+      os << static_cast<const void*>(instruction_start() + pc_offset) << "  ";
       // TODO(svenpanne) Add some basic formatting to our streams.
       Vector<char> buf1 = Vector<char>::New(30);
       SNPrintF(buf1, "%4d", pc_offset);
@@ -10949,6 +11605,17 @@
     it.rinfo()->Print(GetIsolate(), os);
   }
   os << "\n";
+
+#ifdef OBJECT_PRINT
+  if (FLAG_enable_ool_constant_pool) {
+    ConstantPoolArray* pool = constant_pool();
+    if (pool->length()) {
+      os << "Constant Pool\n";
+      pool->Print(os);
+      os << "\n";
+    }
+  }
+#endif
 }
 #endif  // ENABLE_DISASSEMBLER
 
@@ -11091,10 +11758,9 @@
   return true;
 }
 
-static void EnqueueSpliceRecord(Handle<JSArray> object,
-                                uint32_t index,
-                                Handle<JSArray> deleted,
-                                uint32_t add_count) {
+MUST_USE_RESULT static MaybeHandle<Object> EnqueueSpliceRecord(
+    Handle<JSArray> object, uint32_t index, Handle<JSArray> deleted,
+    uint32_t add_count) {
   Isolate* isolate = object->GetIsolate();
   HandleScope scope(isolate);
   Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index);
@@ -11104,37 +11770,33 @@
   Handle<Object> args[] =
       { object, index_object, deleted, add_count_object };
 
-  Execution::Call(isolate,
-                  Handle<JSFunction>(isolate->observers_enqueue_splice()),
-                  isolate->factory()->undefined_value(),
-                  arraysize(args),
-                  args).Assert();
+  return Execution::Call(
+      isolate, Handle<JSFunction>(isolate->observers_enqueue_splice()),
+      isolate->factory()->undefined_value(), arraysize(args), args);
 }
 
 
-static void BeginPerformSplice(Handle<JSArray> object) {
+MUST_USE_RESULT static MaybeHandle<Object> BeginPerformSplice(
+    Handle<JSArray> object) {
   Isolate* isolate = object->GetIsolate();
   HandleScope scope(isolate);
   Handle<Object> args[] = { object };
 
-  Execution::Call(isolate,
-                  Handle<JSFunction>(isolate->observers_begin_perform_splice()),
-                  isolate->factory()->undefined_value(),
-                  arraysize(args),
-                  args).Assert();
+  return Execution::Call(
+      isolate, Handle<JSFunction>(isolate->observers_begin_perform_splice()),
+      isolate->factory()->undefined_value(), arraysize(args), args);
 }
 
 
-static void EndPerformSplice(Handle<JSArray> object) {
+MUST_USE_RESULT static MaybeHandle<Object> EndPerformSplice(
+    Handle<JSArray> object) {
   Isolate* isolate = object->GetIsolate();
   HandleScope scope(isolate);
   Handle<Object> args[] = { object };
 
-  Execution::Call(isolate,
-                  Handle<JSFunction>(isolate->observers_end_perform_splice()),
-                  isolate->factory()->undefined_value(),
-                  arraysize(args),
-                  args).Assert();
+  return Execution::Call(
+      isolate, Handle<JSFunction>(isolate->observers_end_perform_splice()),
+      isolate->factory()->undefined_value(), arraysize(args), args);
 }
 
 
@@ -11198,21 +11860,26 @@
   CHECK(array->length()->ToArrayIndex(&new_length));
   if (old_length == new_length) return hresult;
 
-  BeginPerformSplice(array);
+  RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object);
 
   for (int i = 0; i < indices.length(); ++i) {
     // For deletions where the property was an accessor, old_values[i]
     // will be the hole, which instructs EnqueueChangeRecord to elide
     // the "oldValue" property.
-    JSObject::EnqueueChangeRecord(
-        array, "delete", isolate->factory()->Uint32ToString(indices[i]),
-        old_values[i]);
+    RETURN_ON_EXCEPTION(
+        isolate,
+        JSObject::EnqueueChangeRecord(
+            array, "delete", isolate->factory()->Uint32ToString(indices[i]),
+            old_values[i]),
+        Object);
   }
-  JSObject::EnqueueChangeRecord(
-      array, "update", isolate->factory()->length_string(),
-      old_length_handle);
+  RETURN_ON_EXCEPTION(isolate,
+                      JSObject::EnqueueChangeRecord(
+                          array, "update", isolate->factory()->length_string(),
+                          old_length_handle),
+                      Object);
 
-  EndPerformSplice(array);
+  RETURN_ON_EXCEPTION(isolate, EndPerformSplice(array), Object);
 
   uint32_t index = Min(old_length, new_length);
   uint32_t add_count = new_length > old_length ? new_length - old_length : 0;
@@ -11223,8 +11890,8 @@
       // Skip deletions where the property was an accessor, leaving holes
       // in the array of old values.
       if (old_values[i]->IsTheHole()) continue;
-      JSObject::SetElement(
-          deleted, indices[i] - index, old_values[i], NONE, SLOPPY).Assert();
+      JSObject::SetOwnElement(deleted, indices[i] - index, old_values[i],
+                              SLOPPY).Assert();
     }
 
     SetProperty(deleted, isolate->factory()->length_string(),
@@ -11232,7 +11899,8 @@
                 STRICT).Assert();
   }
 
-  EnqueueSpliceRecord(array, index, deleted, add_count);
+  RETURN_ON_EXCEPTION(
+      isolate, EnqueueSpliceRecord(array, index, deleted, add_count), Object);
 
   return hresult;
 }
@@ -11337,23 +12005,6 @@
 }
 
 
-// static
-void Map::AddDependentIC(Handle<Map> map,
-                         Handle<Code> stub) {
-  DCHECK(stub->next_code_link()->IsUndefined());
-  int n = map->dependent_code()->number_of_entries(DependentCode::kWeakICGroup);
-  if (n == 0) {
-    // Slow path: insert the head of the list with possible heap allocation.
-    Map::AddDependentCode(map, DependentCode::kWeakICGroup, stub);
-  } else {
-    // Fast path: link the stub to the existing head of the list without any
-    // heap allocation.
-    DCHECK(n == 1);
-    map->dependent_code()->AddToDependentICList(stub);
-  }
-}
-
-
 DependentCode::GroupStartIndexes::GroupStartIndexes(DependentCode* entries) {
   Recompute(entries);
 }
@@ -11483,22 +12134,10 @@
 }
 
 
-static bool CodeListContains(Object* head, Code* code) {
-  while (!head->IsUndefined()) {
-    if (head == code) return true;
-    head = Code::cast(head)->next_code_link();
-  }
-  return false;
-}
-
-
 bool DependentCode::Contains(DependencyGroup group, Code* code) {
   GroupStartIndexes starts(this);
   int start = starts.at(group);
   int end = starts.at(group + 1);
-  if (group == kWeakICGroup) {
-    return CodeListContains(object_at(start), code);
-  }
   for (int i = start; i < end; i++) {
     if (object_at(i) == code) return true;
   }
@@ -11555,24 +12194,6 @@
 }
 
 
-void DependentCode::AddToDependentICList(Handle<Code> stub) {
-  DisallowHeapAllocation no_heap_allocation;
-  GroupStartIndexes starts(this);
-  int i = starts.at(kWeakICGroup);
-  Object* head = object_at(i);
-  // Try to insert the stub after the head of the list to minimize number of
-  // writes to the DependentCode array, since a write to the array can make it
-  // strong if it was alread marked by incremental marker.
-  if (head->IsCode()) {
-    stub->set_next_code_link(Code::cast(head)->next_code_link());
-    Code::cast(head)->set_next_code_link(*stub);
-  } else {
-    stub->set_next_code_link(head);
-    set_object_at(i, *stub);
-  }
-}
-
-
 void DependentCode::SetMarkedForDeoptimization(Code* code,
                                                DependencyGroup group) {
   code->set_marked_for_deoptimization(true);
@@ -11591,8 +12212,6 @@
 
 const char* DependentCode::DependencyGroupName(DependencyGroup group) {
   switch (group) {
-    case kWeakICGroup:
-      return "weak-ic";
     case kWeakCodeGroup:
       return "weak-code";
     case kTransitionGroup:
@@ -11618,12 +12237,13 @@
 
 
 Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
-                                       Handle<Object> prototype) {
+                                       Handle<Object> prototype,
+                                       PrototypeOptimizationMode mode) {
   Handle<Map> new_map = GetPrototypeTransition(map, prototype);
   if (new_map.is_null()) {
-    new_map = Copy(map);
+    new_map = Copy(map, "TransitionToPrototype");
     PutPrototypeTransition(map, prototype, new_map);
-    new_map->set_prototype(*prototype);
+    new_map->SetPrototype(prototype, mode);
   }
   return new_map;
 }
@@ -11693,17 +12313,13 @@
   // Nothing to do if prototype is already set.
   if (map->prototype() == *value) return value;
 
-  if (value->IsJSObject()) {
-    PrototypeOptimizationMode mode =
-        from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
-    JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value), mode);
-  }
-
-  Handle<Map> new_map = Map::TransitionToPrototype(map, value);
+  PrototypeOptimizationMode mode =
+      from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
+  Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode);
   DCHECK(new_map->prototype() == *value);
   JSObject::MigrateToMap(real_receiver, new_map);
 
-  if (!dictionary_elements_in_chain &&
+  if (from_javascript && !dictionary_elements_in_chain &&
       new_map->DictionaryElementsInPrototypeChainOnly()) {
     // If the prototype chain didn't previously have element callbacks, then
     // KeyedStoreICs need to be cleared to ensure any that involve this
@@ -11837,13 +12453,10 @@
 }
 
 
-MaybeHandle<Object> JSObject::SetElementWithCallback(Handle<JSObject> object,
-                                                     Handle<Object> structure,
-                                                     uint32_t index,
-                                                     Handle<Object> value,
-                                                     Handle<JSObject> holder,
-                                                     StrictMode strict_mode) {
-  Isolate* isolate = object->GetIsolate();
+MaybeHandle<Object> JSObject::SetElementWithCallback(
+    Handle<Object> object, Handle<Object> structure, uint32_t index,
+    Handle<Object> value, Handle<JSObject> holder, StrictMode strict_mode) {
+  Isolate* isolate = holder->GetIsolate();
 
   // We should never get here to initialize a const with the hole
   // value since a const declaration would conflict with the setter.
@@ -11859,7 +12472,7 @@
     if (call_fun == NULL) return value;
     Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
     Handle<String> key(isolate->factory()->NumberToString(number));
-    LOG(isolate, ApiNamedPropertyAccess("store", *object, *key));
+    LOG(isolate, ApiNamedPropertyAccess("store", *holder, *key));
     PropertyCallbackArguments
         args(isolate, data->data(), *object, *holder);
     args.Call(call_fun,
@@ -12081,8 +12694,8 @@
       // is read-only (a declared const that has not been initialized).  If a
       // value is being defined we skip attribute checks completely.
       if (set_mode == DEFINE_PROPERTY) {
-        details = PropertyDetails(
-            attributes, NORMAL, details.dictionary_index());
+        details =
+            PropertyDetails(attributes, FIELD, details.dictionary_index());
         dictionary->DetailsAtPut(entry, details);
       } else if (details.IsReadOnly() && !element->IsTheHole()) {
         if (strict_mode == SLOPPY) {
@@ -12133,7 +12746,7 @@
       }
     }
 
-    PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
+    PropertyDetails details(attributes, FIELD, 0);
     Handle<SeededNumberDictionary> new_dictionary =
         SeededNumberDictionary::AddNumberEntry(dictionary, index, value,
                                                details);
@@ -12417,28 +13030,44 @@
       CHECK(old_length_handle->ToArrayIndex(&old_length));
       CHECK(new_length_handle->ToArrayIndex(&new_length));
 
-      BeginPerformSplice(Handle<JSArray>::cast(object));
-      EnqueueChangeRecord(object, "add", name, old_value);
-      EnqueueChangeRecord(object, "update", isolate->factory()->length_string(),
-                          old_length_handle);
-      EndPerformSplice(Handle<JSArray>::cast(object));
+      RETURN_ON_EXCEPTION(
+          isolate, BeginPerformSplice(Handle<JSArray>::cast(object)), Object);
+      RETURN_ON_EXCEPTION(
+          isolate, EnqueueChangeRecord(object, "add", name, old_value), Object);
+      RETURN_ON_EXCEPTION(
+          isolate, EnqueueChangeRecord(object, "update",
+                                       isolate->factory()->length_string(),
+                                       old_length_handle),
+          Object);
+      RETURN_ON_EXCEPTION(
+          isolate, EndPerformSplice(Handle<JSArray>::cast(object)), Object);
       Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
-      EnqueueSpliceRecord(Handle<JSArray>::cast(object), old_length, deleted,
-                          new_length - old_length);
+      RETURN_ON_EXCEPTION(
+          isolate,
+          EnqueueSpliceRecord(Handle<JSArray>::cast(object), old_length,
+                              deleted, new_length - old_length),
+          Object);
     } else {
-      EnqueueChangeRecord(object, "add", name, old_value);
+      RETURN_ON_EXCEPTION(
+          isolate, EnqueueChangeRecord(object, "add", name, old_value), Object);
     }
   } else if (old_value->IsTheHole()) {
-    EnqueueChangeRecord(object, "reconfigure", name, old_value);
+    RETURN_ON_EXCEPTION(
+        isolate, EnqueueChangeRecord(object, "reconfigure", name, old_value),
+        Object);
   } else {
     Handle<Object> new_value =
         Object::GetElement(isolate, object, index).ToHandleChecked();
     bool value_changed = !old_value->SameValue(*new_value);
     if (old_attributes != new_attributes) {
       if (!value_changed) old_value = isolate->factory()->the_hole_value();
-      EnqueueChangeRecord(object, "reconfigure", name, old_value);
+      RETURN_ON_EXCEPTION(
+          isolate, EnqueueChangeRecord(object, "reconfigure", name, old_value),
+          Object);
     } else if (value_changed) {
-      EnqueueChangeRecord(object, "update", name, old_value);
+      RETURN_ON_EXCEPTION(
+          isolate, EnqueueChangeRecord(object, "update", name, old_value),
+          Object);
     }
   }
 
@@ -12631,10 +13260,32 @@
 
 
 // static
-void AllocationSite::AddDependentCompilationInfo(Handle<AllocationSite> site,
-                                                 Reason reason,
-                                                 CompilationInfo* info) {
-  DependentCode::DependencyGroup group = site->ToDependencyGroup(reason);
+void AllocationSite::RegisterForDeoptOnTenureChange(Handle<AllocationSite> site,
+                                                    CompilationInfo* info) {
+  AddDependentCompilationInfo(
+      site, DependentCode::kAllocationSiteTenuringChangedGroup, info);
+}
+
+
+// static
+void AllocationSite::RegisterForDeoptOnTransitionChange(
+    Handle<AllocationSite> site, CompilationInfo* info) {
+  // Do nothing if the object doesn't have any useful element transitions left.
+  ElementsKind kind =
+      site->SitePointsToLiteral()
+          ? JSObject::cast(site->transition_info())->GetElementsKind()
+          : site->GetElementsKind();
+  if (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE) {
+    AddDependentCompilationInfo(
+        site, DependentCode::kAllocationSiteTransitionChangedGroup, info);
+  }
+}
+
+
+// static
+void AllocationSite::AddDependentCompilationInfo(
+    Handle<AllocationSite> site, DependentCode::DependencyGroup group,
+    CompilationInfo* info) {
   Handle<DependentCode> dep(site->dependent_code());
   Handle<DependentCode> codes =
       DependentCode::Insert(dep, group, info->object_wrapper());
@@ -12784,18 +13435,21 @@
 }
 
 
+bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
+  LookupIterator it(array, array->GetIsolate()->factory()->length_string(),
+                    LookupIterator::OWN_SKIP_INTERCEPTOR);
+  CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
+  CHECK(it.IsFound());
+  CHECK_EQ(LookupIterator::ACCESSOR, it.state());
+  return it.IsReadOnly();
+}
+
+
 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
                                         uint32_t index) {
   uint32_t length = 0;
   CHECK(array->length()->ToArrayIndex(&length));
-  if (length <= index) {
-    LookupIterator it(array, array->GetIsolate()->factory()->length_string(),
-                      LookupIterator::OWN_SKIP_INTERCEPTOR);
-    CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
-    CHECK(it.IsFound());
-    CHECK_EQ(LookupIterator::ACCESSOR, it.state());
-    return it.IsReadOnly();
-  }
+  if (length <= index) return HasReadOnlyLength(array);
   return false;
 }
 
@@ -12810,10 +13464,10 @@
 }
 
 
-MaybeHandle<Object> JSObject::GetElementWithInterceptor(
-    Handle<JSObject> object,
-    Handle<Object> receiver,
-    uint32_t index) {
+MaybeHandle<Object> JSObject::GetElementWithInterceptor(Handle<JSObject> object,
+                                                        Handle<Object> receiver,
+                                                        uint32_t index,
+                                                        bool check_prototype) {
   Isolate* isolate = object->GetIsolate();
 
   // Make sure that the top context does not change when doing
@@ -12838,6 +13492,8 @@
     }
   }
 
+  if (!check_prototype) return MaybeHandle<Object>();
+
   ElementsAccessor* handler = object->GetElementsAccessor();
   Handle<Object> result;
   ASSIGN_RETURN_ON_EXCEPTION(
@@ -13039,7 +13695,7 @@
 // we keep it here instead to satisfy certain compilers.
 #ifdef OBJECT_PRINT
 template <typename Derived, typename Shape, typename Key>
-void Dictionary<Derived, Shape, Key>::Print(OStream& os) {  // NOLINT
+void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) {  // NOLINT
   int capacity = DerivedHashTable::Capacity();
   for (int i = 0; i < capacity; i++) {
     Object* k = DerivedHashTable::KeyAt(i);
@@ -13050,7 +13706,7 @@
       } else {
         os << Brief(k);
       }
-      os << ": " << Brief(ValueAt(i)) << "\n";
+      os << ": " << Brief(ValueAt(i)) << " " << DetailsAt(i) << "\n";
     }
   }
 }
@@ -13099,22 +13755,21 @@
     Handle<Name> name) {
   Isolate* isolate = holder->GetIsolate();
 
-  // TODO(rossberg): Support symbols in the API.
-  if (name->IsSymbol()) return isolate->factory()->undefined_value();
-
   Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate);
-  Handle<String> name_string = Handle<String>::cast(name);
-
   if (interceptor->getter()->IsUndefined()) return MaybeHandle<Object>();
 
-  v8::NamedPropertyGetterCallback getter =
-      v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
+  if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
+    return MaybeHandle<Object>();
+  }
+
+  v8::GenericNamedPropertyGetterCallback getter =
+      v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
+          interceptor->getter());
   LOG(isolate,
       ApiNamedPropertyAccess("interceptor-named-get", *holder, *name));
   PropertyCallbackArguments
       args(isolate, interceptor->data(), *receiver, *holder);
-  v8::Handle<v8::Value> result =
-      args.Call(getter, v8::Utils::ToLocal(name_string));
+  v8::Handle<v8::Value> result = args.Call(getter, v8::Utils::ToLocal(name));
   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
   if (result.IsEmpty()) return MaybeHandle<Object>();
 
@@ -13126,7 +13781,6 @@
 
 
 // Compute the property keys from the interceptor.
-// TODO(rossberg): support symbols in API, and filter here if needed.
 MaybeHandle<JSObject> JSObject::GetKeysForNamedInterceptor(
     Handle<JSObject> object, Handle<JSReceiver> receiver) {
   Isolate* isolate = receiver->GetIsolate();
@@ -13135,8 +13789,8 @@
       args(isolate, interceptor->data(), *receiver, *object);
   v8::Handle<v8::Object> result;
   if (!interceptor->enumerator()->IsUndefined()) {
-    v8::NamedPropertyEnumeratorCallback enum_fun =
-        v8::ToCData<v8::NamedPropertyEnumeratorCallback>(
+    v8::GenericNamedPropertyEnumeratorCallback enum_fun =
+        v8::ToCData<v8::GenericNamedPropertyEnumeratorCallback>(
             interceptor->enumerator());
     LOG(isolate, ApiObjectAccess("interceptor-named-enum", *object));
     result = args.Call(enum_fun);
@@ -13524,6 +14178,31 @@
 }
 
 
+const char* Symbol::PrivateSymbolToName() const {
+  Heap* heap = GetIsolate()->heap();
+#define SYMBOL_CHECK_AND_PRINT(name) \
+  if (this == heap->name()) return #name;
+  PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
+#undef SYMBOL_CHECK_AND_PRINT
+  return "UNKNOWN";
+}
+
+
+void Symbol::SymbolShortPrint(std::ostream& os) {
+  os << "<Symbol: " << Hash();
+  if (!name()->IsUndefined()) {
+    os << " ";
+    HeapStringAllocator allocator;
+    StringStream accumulator(&allocator);
+    String::cast(name())->StringShortPrint(&accumulator);
+    os << accumulator.ToCString().get();
+  } else {
+    os << " (" << PrivateSymbolToName() << ")";
+  }
+  os << ">";
+}
+
+
 // StringSharedKeys are used as keys in the eval cache.
 class StringSharedKey : public HashTableKey {
  public:
@@ -13538,7 +14217,11 @@
 
   bool IsMatch(Object* other) OVERRIDE {
     DisallowHeapAllocation no_allocation;
-    if (!other->IsFixedArray()) return false;
+    if (!other->IsFixedArray()) {
+      if (!other->IsNumber()) return false;
+      uint32_t other_hash = static_cast<uint32_t>(other->Number());
+      return Hash() == other_hash;
+    }
     FixedArray* other_array = FixedArray::cast(other);
     SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
     if (shared != *shared_) return false;
@@ -13578,6 +14261,9 @@
 
   uint32_t HashForObject(Object* obj) OVERRIDE {
     DisallowHeapAllocation no_allocation;
+    if (obj->IsNumber()) {
+      return static_cast<uint32_t>(obj->Number());
+    }
     FixedArray* other_array = FixedArray::cast(obj);
     SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
     String* source = String::cast(other_array->get(1));
@@ -13679,17 +14365,17 @@
   explicit InternalizedStringKey(Handle<String> string)
       : string_(string) { }
 
-  virtual bool IsMatch(Object* string) OVERRIDE {
+  bool IsMatch(Object* string) OVERRIDE {
     return String::cast(string)->Equals(*string_);
   }
 
-  virtual uint32_t Hash() OVERRIDE { return string_->Hash(); }
+  uint32_t Hash() OVERRIDE { return string_->Hash(); }
 
-  virtual uint32_t HashForObject(Object* other) OVERRIDE {
+  uint32_t HashForObject(Object* other) OVERRIDE {
     return String::cast(other)->Hash();
   }
 
-  virtual Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
+  Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
     // Internalize the string if possible.
     MaybeHandle<Map> maybe_map =
         isolate->factory()->InternalizedStringMapForString(string_);
@@ -13987,8 +14673,6 @@
                          CompilationCacheShape,
                          HashTableKey*>;
 
-template class HashTable<MapCache, MapCacheShape, HashTableKey*>;
-
 template class HashTable<ObjectHashTable,
                          ObjectHashTableShape,
                          Handle<Object> >;
@@ -14078,9 +14762,13 @@
 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::Add(
     Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails);
 
-template void
-Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
-    GenerateNewEnumerationIndices(Handle<NameDictionary>);
+template Handle<FixedArray> Dictionary<
+    NameDictionary, NameDictionaryShape,
+    Handle<Name> >::BuildIterationIndicesArray(Handle<NameDictionary>);
+
+template Handle<FixedArray> Dictionary<
+    NameDictionary, NameDictionaryShape,
+    Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>);
 
 template int
 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
@@ -14120,9 +14808,11 @@
 int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
     NumberOfEnumElements();
 
-template
-int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
-    FindEntry(uint32_t);
+template bool Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
+                         uint32_t>::HasComplexElements();
+
+template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape,
+                       uint32_t>::FindEntry(uint32_t);
 
 
 Handle<Object> JSObject::PrepareSlowElementsForSort(
@@ -14189,7 +14879,7 @@
   }
 
   uint32_t result = pos;
-  PropertyDetails no_details = PropertyDetails(NONE, NORMAL, 0);
+  PropertyDetails no_details(NONE, FIELD, 0);
   while (undefs > 0) {
     if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
       // Adding an entry with the key beyond smi-range requires
@@ -14547,6 +15237,25 @@
 }
 
 
+void GlobalObject::InvalidatePropertyCell(Handle<GlobalObject> global,
+                                          Handle<Name> name) {
+  DCHECK(!global->HasFastProperties());
+  Isolate* isolate = global->GetIsolate();
+  int entry = global->property_dictionary()->FindEntry(name);
+  if (entry != NameDictionary::kNotFound) {
+    Handle<PropertyCell> cell(
+        PropertyCell::cast(global->property_dictionary()->ValueAt(entry)));
+
+    Handle<Object> value(cell->value(), isolate);
+    Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell(value);
+    global->property_dictionary()->ValueAtPut(entry, *new_cell);
+
+    Handle<Object> hole = global->GetIsolate()->factory()->the_hole_value();
+    PropertyCell::SetValueInferType(cell, hole);
+  }
+}
+
+
 Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell(
     Handle<JSGlobalObject> global,
     Handle<Name> name) {
@@ -14556,7 +15265,7 @@
     Isolate* isolate = global->GetIsolate();
     Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(
         isolate->factory()->the_hole_value());
-    PropertyDetails details(NONE, NORMAL, 0);
+    PropertyDetails details(NONE, FIELD, 0);
     details = details.AsDeleted();
     Handle<NameDictionary> dictionary = NameDictionary::Add(
         handle(global->property_dictionary()), name, cell, details);
@@ -14677,6 +15386,16 @@
 }
 
 
+void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
+                                                   int expected) {
+  Handle<StringTable> table = isolate->factory()->string_table();
+  // We need a key instance for the virtual hash function.
+  InternalizedStringKey dummy_key(Handle<String>::null());
+  table = StringTable::EnsureCapacity(table, expected, &dummy_key);
+  isolate->factory()->set_string_table(table);
+}
+
+
 Handle<String> StringTable::LookupString(Isolate* isolate,
                                          Handle<String> string) {
   InternalizedStringKey key(string);
@@ -14720,7 +15439,9 @@
                       RelocInfo::kNoPosition);
   int entry = FindEntry(&key);
   if (entry == kNotFound) return isolate->factory()->undefined_value();
-  return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
+  int index = EntryToIndex(entry);
+  if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
+  return Handle<Object>(get(index + 1), isolate);
 }
 
 
@@ -14733,6 +15454,8 @@
   StringSharedKey key(src, outer_info, strict_mode, scope_position);
   int entry = FindEntry(&key);
   if (entry == kNotFound) return isolate->factory()->undefined_value();
+  int index = EntryToIndex(entry);
+  if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
   return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
 }
 
@@ -14755,11 +15478,23 @@
   Handle<SharedFunctionInfo> shared(context->closure()->shared());
   StringSharedKey key(src, shared, FLAG_use_strict ? STRICT : SLOPPY,
                       RelocInfo::kNoPosition);
+  {
+    Handle<Object> k = key.AsHandle(isolate);
+    DisallowHeapAllocation no_allocation_scope;
+    int entry = cache->FindEntry(&key);
+    if (entry != kNotFound) {
+      cache->set(EntryToIndex(entry), *k);
+      cache->set(EntryToIndex(entry) + 1, *value);
+      return cache;
+    }
+  }
+
   cache = EnsureCapacity(cache, 1, &key);
-  Handle<Object> k = key.AsHandle(isolate);
   int entry = cache->FindInsertionEntry(key.Hash());
+  Handle<Object> k =
+      isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
   cache->set(EntryToIndex(entry), *k);
-  cache->set(EntryToIndex(entry) + 1, *value);
+  cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
   cache->ElementAdded();
   return cache;
 }
@@ -14771,11 +15506,23 @@
     int scope_position) {
   Isolate* isolate = cache->GetIsolate();
   StringSharedKey key(src, outer_info, value->strict_mode(), scope_position);
+  {
+    Handle<Object> k = key.AsHandle(isolate);
+    DisallowHeapAllocation no_allocation_scope;
+    int entry = cache->FindEntry(&key);
+    if (entry != kNotFound) {
+      cache->set(EntryToIndex(entry), *k);
+      cache->set(EntryToIndex(entry) + 1, *value);
+      return cache;
+    }
+  }
+
   cache = EnsureCapacity(cache, 1, &key);
-  Handle<Object> k = key.AsHandle(isolate);
   int entry = cache->FindInsertionEntry(key.Hash());
+  Handle<Object> k =
+      isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
   cache->set(EntryToIndex(entry), *k);
-  cache->set(EntryToIndex(entry) + 1, *value);
+  cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
   cache->ElementAdded();
   return cache;
 }
@@ -14796,6 +15543,35 @@
 }
 
 
+void CompilationCacheTable::Age() {
+  DisallowHeapAllocation no_allocation;
+  Object* the_hole_value = GetHeap()->the_hole_value();
+  for (int entry = 0, size = Capacity(); entry < size; entry++) {
+    int entry_index = EntryToIndex(entry);
+    int value_index = entry_index + 1;
+
+    if (get(entry_index)->IsNumber()) {
+      Smi* count = Smi::cast(get(value_index));
+      count = Smi::FromInt(count->value() - 1);
+      if (count->value() == 0) {
+        NoWriteBarrierSet(this, entry_index, the_hole_value);
+        NoWriteBarrierSet(this, value_index, the_hole_value);
+        ElementRemoved();
+      } else {
+        NoWriteBarrierSet(this, value_index, count);
+      }
+    } else if (get(entry_index)->IsFixedArray()) {
+      SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
+      if (info->code()->kind() != Code::FUNCTION || info->code()->IsOld()) {
+        NoWriteBarrierSet(this, entry_index, the_hole_value);
+        NoWriteBarrierSet(this, value_index, the_hole_value);
+        ElementRemoved();
+      }
+    }
+  }
+}
+
+
 void CompilationCacheTable::Remove(Object* value) {
   DisallowHeapAllocation no_allocation;
   Object* the_hole_value = GetHeap()->the_hole_value();
@@ -14846,28 +15622,6 @@
 };
 
 
-Object* MapCache::Lookup(FixedArray* array) {
-  DisallowHeapAllocation no_alloc;
-  StringsKey key(handle(array));
-  int entry = FindEntry(&key);
-  if (entry == kNotFound) return GetHeap()->undefined_value();
-  return get(EntryToIndex(entry) + 1);
-}
-
-
-Handle<MapCache> MapCache::Put(
-    Handle<MapCache> map_cache, Handle<FixedArray> array, Handle<Map> value) {
-  StringsKey key(array);
-
-  Handle<MapCache> new_cache = EnsureCapacity(map_cache, 1, &key);
-  int entry = new_cache->FindInsertionEntry(key.Hash());
-  new_cache->set(EntryToIndex(entry), *array);
-  new_cache->set(EntryToIndex(entry) + 1, *value);
-  new_cache->ElementAdded();
-  return new_cache;
-}
-
-
 template<typename Derived, typename Shape, typename Key>
 Handle<Derived> Dictionary<Derived, Shape, Key>::New(
     Isolate* isolate,
@@ -14885,56 +15639,61 @@
 }
 
 
-template<typename Derived, typename Shape, typename Key>
-void Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
+template <typename Derived, typename Shape, typename Key>
+Handle<FixedArray> Dictionary<Derived, Shape, Key>::BuildIterationIndicesArray(
     Handle<Derived> dictionary) {
   Factory* factory = dictionary->GetIsolate()->factory();
   int length = dictionary->NumberOfElements();
 
-  // Allocate and initialize iteration order array.
   Handle<FixedArray> iteration_order = factory->NewFixedArray(length);
-  for (int i = 0; i < length; i++) {
-    iteration_order->set(i, Smi::FromInt(i));
-  }
-
-  // Allocate array with enumeration order.
   Handle<FixedArray> enumeration_order = factory->NewFixedArray(length);
 
-  // Fill the enumeration order array with property details.
+  // Fill both the iteration order array and the enumeration order array
+  // with property details.
   int capacity = dictionary->Capacity();
   int pos = 0;
   for (int i = 0; i < capacity; i++) {
     if (dictionary->IsKey(dictionary->KeyAt(i))) {
       int index = dictionary->DetailsAt(i).dictionary_index();
-      enumeration_order->set(pos++, Smi::FromInt(index));
+      iteration_order->set(pos, Smi::FromInt(i));
+      enumeration_order->set(pos, Smi::FromInt(index));
+      pos++;
     }
   }
+  DCHECK(pos == length);
 
   // Sort the arrays wrt. enumeration order.
   iteration_order->SortPairs(*enumeration_order, enumeration_order->length());
+  return iteration_order;
+}
 
-  // Overwrite the enumeration_order with the enumeration indices.
+
+template <typename Derived, typename Shape, typename Key>
+Handle<FixedArray>
+Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
+    Handle<Derived> dictionary) {
+  int length = dictionary->NumberOfElements();
+
+  Handle<FixedArray> iteration_order = BuildIterationIndicesArray(dictionary);
+  DCHECK(iteration_order->length() == length);
+
+  // Iterate over the dictionary using the enumeration order and update
+  // the dictionary with new enumeration indices.
   for (int i = 0; i < length; i++) {
     int index = Smi::cast(iteration_order->get(i))->value();
-    int enum_index = PropertyDetails::kInitialIndex + i;
-    enumeration_order->set(index, Smi::FromInt(enum_index));
-  }
+    DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
 
-  // Update the dictionary with new indices.
-  capacity = dictionary->Capacity();
-  pos = 0;
-  for (int i = 0; i < capacity; i++) {
-    if (dictionary->IsKey(dictionary->KeyAt(i))) {
-      int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
-      PropertyDetails details = dictionary->DetailsAt(i);
-      PropertyDetails new_details = PropertyDetails(
-          details.attributes(), details.type(), enum_index);
-      dictionary->DetailsAtPut(i, new_details);
-    }
+    int enum_index = PropertyDetails::kInitialIndex + i;
+
+    PropertyDetails details = dictionary->DetailsAt(index);
+    PropertyDetails new_details =
+        PropertyDetails(details.attributes(), details.type(), enum_index);
+    dictionary->DetailsAtPut(index, new_details);
   }
 
   // Set the next enumeration index.
   dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
+  return iteration_order;
 }
 
 
@@ -14986,7 +15745,7 @@
 #ifdef DEBUG
   USE(Shape::AsHandle(dictionary->GetIsolate(), key));
 #endif
-  PropertyDetails details = PropertyDetails(NONE, NORMAL, 0);
+  PropertyDetails details(NONE, FIELD, 0);
 
   AddEntry(dictionary, key, value, details, dictionary->Hash(key));
   return dictionary;
@@ -15074,7 +15833,7 @@
     uint32_t key,
     Handle<Object> value) {
   SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
-  return Add(dictionary, key, value, PropertyDetails(NONE, NORMAL, 0));
+  return Add(dictionary, key, value, PropertyDetails(NONE, FIELD, 0));
 }
 
 
@@ -15154,10 +15913,26 @@
 }
 
 
-template<typename Derived, typename Shape, typename Key>
+template <typename Derived, typename Shape, typename Key>
+bool Dictionary<Derived, Shape, Key>::HasComplexElements() {
+  int capacity = DerivedHashTable::Capacity();
+  for (int i = 0; i < capacity; i++) {
+    Object* k = DerivedHashTable::KeyAt(i);
+    if (DerivedHashTable::IsKey(k) && !FilterKey(k, NONE)) {
+      PropertyDetails details = DetailsAt(i);
+      if (details.IsDeleted()) continue;
+      if (details.type() == CALLBACKS) return true;
+      PropertyAttributes attr = details.attributes();
+      if (attr & (READ_ONLY | DONT_DELETE | DONT_ENUM)) return true;
+    }
+  }
+  return false;
+}
+
+
+template <typename Derived, typename Shape, typename Key>
 void Dictionary<Derived, Shape, Key>::CopyKeysTo(
-    FixedArray* storage,
-    PropertyAttributes filter,
+    FixedArray* storage, PropertyAttributes filter,
     typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
   DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
   int capacity = DerivedHashTable::Capacity();
@@ -15448,7 +16223,7 @@
                table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
 
   table->SetNextTable(*new_table);
-  table->SetNumberOfDeletedElements(-1);
+  table->SetNumberOfDeletedElements(kClearedTableSentinel);
 
   return new_table;
 }
@@ -15693,8 +16468,7 @@
     if (index > 0) {
       int nod = table->NumberOfDeletedElements();
 
-      // When we clear the table we set the number of deleted elements to -1.
-      if (nod == -1) {
+      if (nod == TableType::kClearedTableSentinel) {
         index = 0;
       } else {
         int old_index = index;
@@ -16223,13 +16997,15 @@
 
 
 void JSArrayBuffer::Neuter() {
-  DCHECK(is_external());
+  CHECK(is_neuterable());
+  CHECK(is_external());
   set_backing_store(NULL);
   set_byte_length(Smi::FromInt(0));
 }
 
 
 void JSArrayBufferView::NeuterView() {
+  CHECK(JSArrayBuffer::cast(buffer())->is_neuterable());
   set_byte_offset(Smi::FromInt(0));
   set_byte_length(Smi::FromInt(0));
 }
@@ -16337,13 +17113,24 @@
 }
 
 
-void PropertyCell::SetValueInferType(Handle<PropertyCell> cell,
-                                     Handle<Object> value) {
+Handle<Object> PropertyCell::SetValueInferType(Handle<PropertyCell> cell,
+                                               Handle<Object> value) {
+  // Heuristic: if a small-ish string is stored in a previously uninitialized
+  // property cell, internalize it.
+  const int kMaxLengthForInternalization = 200;
+  if ((cell->type()->Is(HeapType::None()) ||
+       cell->type()->Is(HeapType::Undefined())) &&
+      value->IsString() &&
+      Handle<String>::cast(value)->length() <= kMaxLengthForInternalization) {
+    value = cell->GetIsolate()->factory()->InternalizeString(
+        Handle<String>::cast(value));
+  }
   cell->set_value(*value);
   if (!HeapType::Any()->Is(cell->type())) {
     Handle<HeapType> new_type = UpdatedType(cell, value);
     cell->set_type(*new_type);
   }
+  return value;
 }
 
 
diff --git a/src/objects.h b/src/objects.h
index 3340350..c32f9f6 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -5,6 +5,8 @@
 #ifndef V8_OBJECTS_H_
 #define V8_OBJECTS_H_
 
+#include <iosfwd>
+
 #include "src/allocation.h"
 #include "src/assert-scope.h"
 #include "src/bailout-reason.h"
@@ -18,6 +20,7 @@
 #include "src/property-details.h"
 #include "src/smart-pointers.h"
 #include "src/unicode-inl.h"
+#include "src/unicode-decoder.h"
 #include "src/zone.h"
 
 #if V8_TARGET_ARCH_ARM
@@ -84,6 +87,8 @@
 //         - JSFunctionResultCache
 //         - ScopeInfo
 //         - TransitionArray
+//         - ScriptContextTable
+//         - WeakFixedArray
 //       - FixedDoubleArray
 //       - ExternalArray
 //         - ExternalUint8ClampedArray
@@ -140,6 +145,7 @@
 //       - DebugInfo
 //       - BreakPointInfo
 //       - CodeCache
+//     - WeakCell
 //
 // Formats of Object*:
 //  Smi:        [31 bit signed int] 0
@@ -148,8 +154,6 @@
 namespace v8 {
 namespace internal {
 
-class OStream;
-
 enum KeyedAccessStoreMode {
   STANDARD_STORE,
   STORE_TRANSITION_SMI_TO_OBJECT,
@@ -231,15 +235,15 @@
 }
 
 
+enum IcCheckType { ELEMENT, PROPERTY };
+
+
 // Setter that skips the write barrier if mode is SKIP_WRITE_BARRIER.
 enum WriteBarrierMode { SKIP_WRITE_BARRIER, UPDATE_WRITE_BARRIER };
 
 
 // Indicates whether a value can be loaded as a constant.
-enum StoreMode {
-  ALLOW_AS_CONSTANT,
-  FORCE_FIELD
-};
+enum StoreMode { ALLOW_IN_DESCRIPTOR, FORCE_IN_OBJECT };
 
 
 // PropertyNormalizationMode is used to specify whether to keep
@@ -275,8 +279,9 @@
 // either extends the current map with a new property, or it modifies the
 // property that was added last to the current map.
 enum SimpleTransitionFlag {
-  SIMPLE_TRANSITION,
-  FULL_TRANSITION
+  SIMPLE_PROPERTY_TRANSITION,
+  PROPERTY_TRANSITION,
+  SPECIAL_TRANSITION
 };
 
 
@@ -421,6 +426,7 @@
   V(FIXED_DOUBLE_ARRAY_TYPE)                                    \
   V(CONSTANT_POOL_ARRAY_TYPE)                                   \
   V(SHARED_FUNCTION_INFO_TYPE)                                  \
+  V(WEAK_CELL_TYPE)                                             \
                                                                 \
   V(JS_MESSAGE_OBJECT_TYPE)                                     \
                                                                 \
@@ -717,6 +723,7 @@
   FIXED_ARRAY_TYPE,
   CONSTANT_POOL_ARRAY_TYPE,
   SHARED_FUNCTION_INFO_TYPE,
+  WEAK_CELL_TYPE,
 
   // All the following types are subtypes of JSReceiver, which corresponds to
   // objects in the JS sense. The first and the last type in this range are
@@ -845,14 +852,17 @@
 class AllocationSite;
 class AllocationSiteCreationContext;
 class AllocationSiteUsageContext;
+class ConsString;
 class DictionaryElementsAccessor;
 class ElementsAccessor;
 class FixedArrayBase;
 class GlobalObject;
-class ObjectVisitor;
+class LayoutDescriptor;
 class LookupIterator;
+class ObjectVisitor;
 class StringStream;
 class TypeFeedbackVector;
+class WeakCell;
 // We cannot just say "class HeapType;" if it is created from a template... =8-?
 template<class> class TypeImpl;
 struct HeapTypeConfig;
@@ -869,7 +879,7 @@
 #endif
 
 #ifdef OBJECT_PRINT
-#define DECLARE_PRINTER(Name) void Name##Print(OStream& os);  // NOLINT
+#define DECLARE_PRINTER(Name) void Name##Print(std::ostream& os);  // NOLINT
 #else
 #define DECLARE_PRINTER(Name)
 #endif
@@ -924,6 +934,7 @@
   V(JSContextExtensionObject)      \
   V(JSGeneratorObject)             \
   V(JSModule)                      \
+  V(LayoutDescriptor)              \
   V(Map)                           \
   V(DescriptorArray)               \
   V(TransitionArray)               \
@@ -933,8 +944,10 @@
   V(DependentCode)                 \
   V(FixedArray)                    \
   V(FixedDoubleArray)              \
+  V(WeakFixedArray)                \
   V(ConstantPoolArray)             \
   V(Context)                       \
+  V(ScriptContextTable)            \
   V(NativeContext)                 \
   V(ScopeInfo)                     \
   V(JSFunction)                    \
@@ -980,6 +993,7 @@
   V(AccessCheckNeeded)             \
   V(Cell)                          \
   V(PropertyCell)                  \
+  V(WeakCell)                      \
   V(ObjectHashTable)               \
   V(WeakHashTable)                 \
   V(OrderedHashTable)
@@ -1007,6 +1021,8 @@
     CERTAINLY_NOT_STORE_FROM_KEYED
   };
 
+  enum StorePropertyMode { NORMAL_PROPERTY, SUPER_PROPERTY };
+
   INLINE(bool IsFixedArrayBase() const);
   INLINE(bool IsExternal() const);
   INLINE(bool IsAccessorInfo() const);
@@ -1116,11 +1132,15 @@
 
   MUST_USE_RESULT static MaybeHandle<Object> SetProperty(
       LookupIterator* it, Handle<Object> value, StrictMode strict_mode,
-      StoreFromKeyed store_mode);
+      StoreFromKeyed store_mode,
+      StorePropertyMode data_store_mode = NORMAL_PROPERTY);
   MUST_USE_RESULT static MaybeHandle<Object> WriteToReadOnlyProperty(
       LookupIterator* it, Handle<Object> value, StrictMode strict_mode);
-  static Handle<Object> SetDataProperty(LookupIterator* it,
-                                        Handle<Object> value);
+  MUST_USE_RESULT static MaybeHandle<Object> WriteToReadOnlyElement(
+      Isolate* isolate, Handle<Object> receiver, uint32_t index,
+      Handle<Object> value, StrictMode strict_mode);
+  MUST_USE_RESULT static MaybeHandle<Object> SetDataProperty(
+      LookupIterator* it, Handle<Object> value);
   MUST_USE_RESULT static MaybeHandle<Object> AddDataProperty(
       LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
       StrictMode strict_mode, StoreFromKeyed store_mode);
@@ -1164,6 +1184,13 @@
       Handle<Object> receiver,
       uint32_t index);
 
+  MUST_USE_RESULT static MaybeHandle<Object> SetElementWithReceiver(
+      Isolate* isolate, Handle<Object> object, Handle<Object> receiver,
+      uint32_t index, Handle<Object> value, StrictMode strict_mode);
+
+  static inline Handle<Object> GetPrototypeSkipHiddenPrototypes(
+      Isolate* isolate, Handle<Object> receiver);
+
   // Returns the permanent hash code associated with this object. May return
   // undefined if not yet created.
   Object* GetHash();
@@ -1206,6 +1233,8 @@
   // Prints this object without details to a message accumulator.
   void ShortPrint(StringStream* accumulator);
 
+  void ShortPrint(std::ostream& os);  // NOLINT
+
   DECLARE_CAST(Object)
 
   // Layout description.
@@ -1216,7 +1245,10 @@
   void Print();
 
   // Prints this object with details.
-  void Print(OStream& os);  // NOLINT
+  void Print(std::ostream& os);  // NOLINT
+#else
+  void Print() { ShortPrint(); }
+  void Print(std::ostream& os) { ShortPrint(os); }  // NOLINT
 #endif
 
  private:
@@ -1236,7 +1268,7 @@
 };
 
 
-OStream& operator<<(OStream& os, const Brief& v);
+std::ostream& operator<<(std::ostream& os, const Brief& v);
 
 
 // Smi represents integer Numbers that can be stored in 31 bits.
@@ -1261,7 +1293,7 @@
   DECLARE_CAST(Smi)
 
   // Dispatched behavior.
-  void SmiPrint(OStream& os) const;  // NOLINT
+  void SmiPrint(std::ostream& os) const;  // NOLINT
   DECLARE_VERIFIER(Smi)
 
   static const int kMinValue =
@@ -1404,9 +1436,9 @@
       const DisallowHeapAllocation& promise);
 
   // Dispatched behavior.
-  void HeapObjectShortPrint(OStream& os);  // NOLINT
+  void HeapObjectShortPrint(std::ostream& os);  // NOLINT
 #ifdef OBJECT_PRINT
-  void PrintHeader(OStream& os, const char* id);  // NOLINT
+  void PrintHeader(std::ostream& os, const char* id);  // NOLINT
 #endif
   DECLARE_PRINTER(HeapObject)
   DECLARE_VERIFIER(HeapObject)
@@ -1419,6 +1451,8 @@
   static void VerifyHeapPointer(Object* p);
 #endif
 
+  inline bool NeedsToEnsureDoubleAlignment();
+
   // Layout description.
   // First field in a heap object is map.
   static const int kMapOffset = Object::kHeaderSize;
@@ -1493,7 +1527,7 @@
   // Dispatched behavior.
   bool HeapNumberBooleanValue();
 
-  void HeapNumberPrint(OStream& os);  // NOLINT
+  void HeapNumberPrint(std::ostream& os);  // NOLINT
   DECLARE_VERIFIER(HeapNumber)
 
   inline int get_exponent();
@@ -1618,9 +1652,6 @@
   MUST_USE_RESULT static inline Maybe<PropertyAttributes>
       GetOwnElementAttribute(Handle<JSReceiver> object, uint32_t index);
 
-  // Return the constructor function (may be Heap::null_value()).
-  inline Object* GetConstructor();
-
   // Retrieves a permanent object identity hash code. The undefined value might
   // be returned in case no hash was created yet.
   inline Object* GetIdentityHash();
@@ -1792,6 +1823,10 @@
   static void OptimizeAsPrototype(Handle<JSObject> object,
                                   PrototypeOptimizationMode mode);
   static void ReoptimizeIfPrototype(Handle<JSObject> object);
+  static void RegisterPrototypeUser(Handle<JSObject> prototype,
+                                    Handle<HeapObject> user);
+  static void UnregisterPrototypeUser(Handle<JSObject> prototype,
+                                      Handle<HeapObject> user);
 
   // Retrieve interceptors.
   InterceptorInfo* GetNamedInterceptor();
@@ -1834,10 +1869,6 @@
       Handle<Object> receiver,
       Handle<Name> name);
 
-  // Returns true if this is an instance of an api function and has
-  // been modified since it was created.  May give false positives.
-  bool IsDirty();
-
   // Accessors for hidden properties object.
   //
   // Hidden properties are not own properties of the object itself.
@@ -1912,8 +1943,7 @@
 
   // These methods do not perform access checks!
   MUST_USE_RESULT static MaybeHandle<AccessorPair> GetOwnElementAccessorPair(
-      Handle<JSObject> object,
-      uint32_t index);
+      Handle<JSObject> object, uint32_t index);
 
   MUST_USE_RESULT static MaybeHandle<Object> SetFastElement(
       Handle<JSObject> object,
@@ -1941,9 +1971,8 @@
   // Returns the index'th element.
   // The undefined object if index is out of bounds.
   MUST_USE_RESULT static MaybeHandle<Object> GetElementWithInterceptor(
-      Handle<JSObject> object,
-      Handle<Object> receiver,
-      uint32_t index);
+      Handle<JSObject> object, Handle<Object> receiver, uint32_t index,
+      bool check_prototype);
 
   enum SetFastElementsCapacitySmiMode {
     kAllowSmiElements,
@@ -2034,7 +2063,8 @@
   // an initial capacity for holding these properties.
   static void NormalizeProperties(Handle<JSObject> object,
                                   PropertyNormalizationMode mode,
-                                  int expected_additional_properties);
+                                  int expected_additional_properties,
+                                  const char* reason);
 
   // Convert and update the elements backing store to be a
   // SeededNumberDictionary dictionary.  Returns the backing after conversion.
@@ -2043,14 +2073,20 @@
 
   // Transform slow named properties to fast variants.
   static void MigrateSlowToFast(Handle<JSObject> object,
-                                int unused_property_fields);
+                                int unused_property_fields, const char* reason);
+
+  inline bool IsUnboxedDoubleField(FieldIndex index);
 
   // Access fast-case object properties at index.
   static Handle<Object> FastPropertyAt(Handle<JSObject> object,
                                        Representation representation,
                                        FieldIndex index);
   inline Object* RawFastPropertyAt(FieldIndex index);
+  inline double RawFastDoublePropertyAt(FieldIndex index);
+
   inline void FastPropertyAtPut(FieldIndex index, Object* value);
+  inline void RawFastPropertyAtPut(FieldIndex index, Object* value);
+  inline void RawFastDoublePropertyAtPut(FieldIndex index, double value);
   void WriteToField(int descriptor, Object* value);
 
   // Access to in object properties.
@@ -2081,6 +2117,9 @@
   MUST_USE_RESULT static MaybeHandle<Object> PreventExtensions(
       Handle<JSObject> object);
 
+  // ES5 Object.seal
+  MUST_USE_RESULT static MaybeHandle<Object> Seal(Handle<JSObject> object);
+
   // ES5 Object.freeze
   MUST_USE_RESULT static MaybeHandle<Object> Freeze(Handle<JSObject> object);
 
@@ -2110,9 +2149,11 @@
   DECLARE_PRINTER(JSObject)
   DECLARE_VERIFIER(JSObject)
 #ifdef OBJECT_PRINT
-  void PrintProperties(OStream& os);   // NOLINT
-  void PrintElements(OStream& os);     // NOLINT
-  void PrintTransitions(OStream& os);  // NOLINT
+  void PrintProperties(std::ostream& os);   // NOLINT
+  void PrintElements(std::ostream& os);     // NOLINT
+#endif
+#if defined(DEBUG) || defined(OBJECT_PRINT)
+  void PrintTransitions(std::ostream& os);  // NOLINT
 #endif
 
   static void PrintElementsTransition(
@@ -2201,14 +2242,9 @@
   Context* GetCreationContext();
 
   // Enqueue change record for Object.observe. May cause GC.
-  static void EnqueueChangeRecord(Handle<JSObject> object,
-                                  const char* type,
-                                  Handle<Name> name,
-                                  Handle<Object> old_value);
-
-  static void MigrateToNewProperty(Handle<JSObject> object,
-                                   Handle<Map> transition,
-                                   Handle<Object> value);
+  MUST_USE_RESULT static MaybeHandle<Object> EnqueueChangeRecord(
+      Handle<JSObject> object, const char* type, Handle<Name> name,
+      Handle<Object> old_value);
 
  private:
   friend class DictionaryElementsAccessor;
@@ -2220,11 +2256,6 @@
                                 Handle<Map> new_map,
                                 int expected_additional_properties);
 
-  static void GeneralizeFieldRepresentation(Handle<JSObject> object,
-                                            int modify_index,
-                                            Representation new_representation,
-                                            Handle<HeapType> new_field_type);
-
   static void UpdateAllocationSite(Handle<JSObject> object,
                                    ElementsKind to_kind);
 
@@ -2243,18 +2274,30 @@
       GetElementAttributeWithInterceptor(Handle<JSObject> object,
                                          Handle<JSReceiver> receiver,
                                          uint32_t index, bool continue_search);
+
+  // Queries indexed interceptor on an object for property attributes.
+  //
+  // We determine property attributes as follows:
+  // - if interceptor has a query callback, then the  property attributes are
+  //   the result of query callback for index.
+  // - otherwise if interceptor has a getter callback and it returns
+  //   non-empty value on index, then the property attributes is NONE
+  //   (property is present, and it is enumerable, configurable, writable)
+  // - otherwise there are no property attributes that can be inferred for
+  //   interceptor, and this function returns ABSENT.
+  MUST_USE_RESULT static Maybe<PropertyAttributes>
+      GetElementAttributeFromInterceptor(Handle<JSObject> object,
+                                         Handle<Object> receiver,
+                                         uint32_t index);
+
   MUST_USE_RESULT static Maybe<PropertyAttributes>
       GetElementAttributeWithoutInterceptor(Handle<JSObject> object,
                                             Handle<JSReceiver> receiver,
                                             uint32_t index,
                                             bool continue_search);
   MUST_USE_RESULT static MaybeHandle<Object> SetElementWithCallback(
-      Handle<JSObject> object,
-      Handle<Object> structure,
-      uint32_t index,
-      Handle<Object> value,
-      Handle<JSObject> holder,
-      StrictMode strict_mode);
+      Handle<Object> object, Handle<Object> structure, uint32_t index,
+      Handle<Object> value, Handle<JSObject> holder, StrictMode strict_mode);
   MUST_USE_RESULT static MaybeHandle<Object> SetElementWithInterceptor(
       Handle<JSObject> object,
       uint32_t index,
@@ -2292,6 +2335,14 @@
       Handle<Object> value,
       StrictMode strict_mode,
       bool check_prototype = true);
+  MUST_USE_RESULT static MaybeHandle<Object> GetElementWithFailedAccessCheck(
+      Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver,
+      uint32_t index);
+  MUST_USE_RESULT static Maybe<PropertyAttributes>
+  GetElementAttributesWithFailedAccessCheck(Isolate* isolate,
+                                            Handle<JSObject> object,
+                                            Handle<Object> receiver,
+                                            uint32_t index);
 
   MUST_USE_RESULT static MaybeHandle<Object> SetPropertyWithFailedAccessCheck(
       LookupIterator* it, Handle<Object> value, StrictMode strict_mode);
@@ -2366,6 +2417,15 @@
 
   static Handle<Smi> GetOrCreateIdentityHash(Handle<JSObject> object);
 
+  static Handle<SeededNumberDictionary> GetNormalizedElementDictionary(
+      Handle<JSObject> object);
+
+  // Helper for fast versions of preventExtensions, seal, and freeze.
+  // attrs is one of NONE, SEALED, or FROZEN (depending on the operation).
+  template <PropertyAttributes attrs>
+  MUST_USE_RESULT static MaybeHandle<Object> PreventExtensionsWithTransition(
+      Handle<JSObject> object);
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(JSObject);
 };
 
@@ -2399,7 +2459,7 @@
 class FixedArray: public FixedArrayBase {
  public:
   // Setter and getter for elements.
-  inline Object* get(int index);
+  inline Object* get(int index) const;
   static inline Handle<Object> get(Handle<FixedArray> array, int index);
   // Setter that uses write barrier.
   inline void set(int index, Object* value);
@@ -2431,10 +2491,12 @@
                                      int new_length,
                                      PretenureFlag pretenure = NOT_TENURED);
 
+  enum KeyFilter { ALL_KEYS, NON_SYMBOL_KEYS };
+
   // Add the elements of a JSArray to this FixedArray.
   MUST_USE_RESULT static MaybeHandle<FixedArray> AddKeysFromArrayLike(
-      Handle<FixedArray> content,
-      Handle<JSObject> array);
+      Handle<FixedArray> content, Handle<JSObject> array,
+      KeyFilter filter = ALL_KEYS);
 
   // Computes the union of keys and return the result.
   // Used for implementing "for (n in object) { }"
@@ -2559,6 +2621,45 @@
 };
 
 
+class WeakFixedArray : public FixedArray {
+ public:
+  enum SearchForDuplicates { kAlwaysAdd, kAddIfNotFound };
+
+  // If |maybe_array| is not a WeakFixedArray, a fresh one will be allocated.
+  static Handle<WeakFixedArray> Add(
+      Handle<Object> maybe_array, Handle<HeapObject> value,
+      SearchForDuplicates search_for_duplicates = kAlwaysAdd);
+
+  void Remove(Handle<HeapObject> value);
+
+  inline Object* Get(int index) const;
+  inline int Length() const;
+
+  DECLARE_CAST(WeakFixedArray)
+
+ private:
+  static const int kLastUsedIndexIndex = 0;
+  static const int kFirstIndex = 1;
+
+  static Handle<WeakFixedArray> Allocate(
+      Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from);
+
+  static void Set(Handle<WeakFixedArray> array, int index,
+                  Handle<HeapObject> value);
+  inline void clear(int index);
+  inline bool IsEmptySlot(int index) const;
+
+  inline int last_used_index() const;
+  inline void set_last_used_index(int index);
+
+  // Disallow inherited setters.
+  void set(int index, Smi* value);
+  void set(int index, Object* value);
+  void set(int index, Object* value, WriteBarrierMode mode);
+  DISALLOW_IMPLICIT_CONSTRUCTORS(WeakFixedArray);
+};
+
+
 // ConstantPoolArray describes a fixed-sized array containing constant pool
 // entries.
 //
@@ -2596,11 +2697,7 @@
 //
 class ConstantPoolArray: public HeapObject {
  public:
-  enum WeakObjectState {
-    NO_WEAK_OBJECTS,
-    WEAK_OBJECTS_IN_OPTIMIZED_CODE,
-    WEAK_OBJECTS_IN_IC
-  };
+  enum WeakObjectState { NO_WEAK_OBJECTS, WEAK_OBJECTS_IN_OPTIMIZED_CODE };
 
   enum Type {
     INT64 = 0,
@@ -2841,13 +2938,13 @@
   // get_extended_section_header_offset().
   static const int kExtendedInt64CountOffset = 0;
   static const int kExtendedCodePtrCountOffset =
-      kExtendedInt64CountOffset + kPointerSize;
+      kExtendedInt64CountOffset + kInt32Size;
   static const int kExtendedHeapPtrCountOffset =
-      kExtendedCodePtrCountOffset + kPointerSize;
+      kExtendedCodePtrCountOffset + kInt32Size;
   static const int kExtendedInt32CountOffset =
-      kExtendedHeapPtrCountOffset + kPointerSize;
+      kExtendedHeapPtrCountOffset + kInt32Size;
   static const int kExtendedFirstOffset =
-      kExtendedInt32CountOffset + kPointerSize;
+      kExtendedInt32CountOffset + kInt32Size;
 
   // Dispatched behavior.
   void ConstantPoolIterateBody(ObjectVisitor* v);
@@ -3034,9 +3131,12 @@
   static const int kDescriptorValue = 2;
   static const int kDescriptorSize = 3;
 
-#ifdef OBJECT_PRINT
+#if defined(DEBUG) || defined(OBJECT_PRINT)
+  // For our gdb macros, we should perhaps change these in the future.
+  void Print();
+
   // Print all the descriptors.
-  void PrintDescriptors(OStream& os);  // NOLINT
+  void PrintDescriptors(std::ostream& os);  // NOLINT
 #endif
 
 #ifdef DEBUG
@@ -3109,9 +3209,7 @@
 
   // Transfer a complete descriptor from the src descriptor array to this
   // descriptor array.
-  void CopyFrom(int index,
-                DescriptorArray* src,
-                const WhitenessWitness&);
+  void CopyFrom(int index, DescriptorArray* src, const WhitenessWitness&);
 
   inline void Set(int descriptor_number,
                   Descriptor* desc,
@@ -3126,12 +3224,9 @@
 
 enum SearchMode { ALL_ENTRIES, VALID_ENTRIES };
 
-template<SearchMode search_mode, typename T>
-inline int LinearSearch(T* array, Name* name, int len, int valid_entries);
-
-
-template<SearchMode search_mode, typename T>
-inline int Search(T* array, Name* name, int valid_entries = 0);
+template <SearchMode search_mode, typename T>
+inline int Search(T* array, Name* name, int valid_entries = 0,
+                  int* out_insertion_index = NULL);
 
 
 // HashTable is a subclass of FixedArray that implements a hash table
@@ -3430,6 +3525,8 @@
       uint16_t c1,
       uint16_t c2);
 
+  static void EnsureCapacityForDeserialization(Isolate* isolate, int expected);
+
   DECLARE_CAST(StringTable)
 
  private:
@@ -3440,44 +3537,6 @@
 };
 
 
-class MapCacheShape : public BaseShape<HashTableKey*> {
- public:
-  static inline bool IsMatch(HashTableKey* key, Object* value) {
-    return key->IsMatch(value);
-  }
-
-  static inline uint32_t Hash(HashTableKey* key) {
-    return key->Hash();
-  }
-
-  static inline uint32_t HashForObject(HashTableKey* key, Object* object) {
-    return key->HashForObject(object);
-  }
-
-  static inline Handle<Object> AsHandle(Isolate* isolate, HashTableKey* key);
-
-  static const int kPrefixSize = 0;
-  static const int kEntrySize = 2;
-};
-
-
-// MapCache.
-//
-// Maps keys that are a fixed array of unique names to a map.
-// Used for canonicalize maps for object literals.
-class MapCache: public HashTable<MapCache, MapCacheShape, HashTableKey*> {
- public:
-  // Find cached value for a name key, otherwise return null.
-  Object* Lookup(FixedArray* key);
-  static Handle<MapCache> Put(
-      Handle<MapCache> map_cache, Handle<FixedArray> key, Handle<Map> value);
-  DECLARE_CAST(MapCache)
-
- private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(MapCache);
-};
-
-
 template <typename Derived, typename Shape, typename Key>
 class Dictionary: public HashTable<Derived, Shape, Key> {
  protected:
@@ -3529,6 +3588,10 @@
   // Returns the number of enumerable elements in the dictionary.
   int NumberOfEnumElements();
 
+  // Returns true if the dictionary contains any elements that are non-writable,
+  // non-configurable, non-enumerable, or have getters/setters.
+  bool HasComplexElements();
+
   enum SortMode { UNSORTED, SORTED };
   // Copies keys to preallocated fixed array.
   void CopyKeysTo(FixedArray* storage,
@@ -3560,7 +3623,7 @@
   static Handle<Derived> EnsureCapacity(Handle<Derived> obj, int n, Key key);
 
 #ifdef OBJECT_PRINT
-  void Print(OStream& os);  // NOLINT
+  void Print(std::ostream& os);  // NOLINT
 #endif
   // Returns the key (slow).
   Object* SlowReverseLookup(Object* value);
@@ -3580,6 +3643,11 @@
       Handle<Object> value,
       PropertyDetails details);
 
+  // Returns iteration indices array for the |dictionary|.
+  // Values are direct indices in the |HashTable| array.
+  static Handle<FixedArray> BuildIterationIndicesArray(
+      Handle<Derived> dictionary);
+
  protected:
   // Generic at put operation.
   MUST_USE_RESULT static Handle<Derived> AtPut(
@@ -3596,7 +3664,9 @@
       uint32_t hash);
 
   // Generate new enumeration indices to avoid enumeration index overflow.
-  static void GenerateNewEnumerationIndices(Handle<Derived> dictionary);
+  // Returns iteration indices array for the |dictionary|.
+  static Handle<FixedArray> GenerateNewEnumerationIndices(
+      Handle<Derived> dictionary);
   static const int kMaxNumberKeyIndex = DerivedHashTable::kPrefixStartIndex;
   static const int kNextEnumerationIndexIndex = kMaxNumberKeyIndex + 1;
 };
@@ -3625,7 +3695,7 @@
 
   // Copies enumerable keys to preallocated fixed array.
   void CopyEnumKeysTo(FixedArray* storage);
-  inline static void DoGenerateNewEnumerationIndices(
+  inline static Handle<FixedArray> DoGenerateNewEnumerationIndices(
       Handle<NameDictionary> dictionary);
 
   // Find entry for key, otherwise return kNotFound. Optimized version of
@@ -3904,6 +3974,33 @@
   static const int kNotFound = -1;
   static const int kMinCapacity = 4;
 
+  static const int kNumberOfBucketsIndex = 0;
+  static const int kNumberOfElementsIndex = kNumberOfBucketsIndex + 1;
+  static const int kNumberOfDeletedElementsIndex = kNumberOfElementsIndex + 1;
+  static const int kHashTableStartIndex = kNumberOfDeletedElementsIndex + 1;
+  static const int kNextTableIndex = kNumberOfElementsIndex;
+
+  static const int kNumberOfBucketsOffset =
+      kHeaderSize + kNumberOfBucketsIndex * kPointerSize;
+  static const int kNumberOfElementsOffset =
+      kHeaderSize + kNumberOfElementsIndex * kPointerSize;
+  static const int kNumberOfDeletedElementsOffset =
+      kHeaderSize + kNumberOfDeletedElementsIndex * kPointerSize;
+  static const int kHashTableStartOffset =
+      kHeaderSize + kHashTableStartIndex * kPointerSize;
+  static const int kNextTableOffset =
+      kHeaderSize + kNextTableIndex * kPointerSize;
+
+  static const int kEntrySize = entrysize + 1;
+  static const int kChainOffset = entrysize;
+
+  static const int kLoadFactor = 2;
+
+  // NumberOfDeletedElements is set to kClearedTableSentinel when
+  // the table is cleared, which allows iterator transitions to
+  // optimize that case.
+  static const int kClearedTableSentinel = -1;
+
  private:
   static Handle<Derived> Rehash(Handle<Derived> table, int new_capacity);
 
@@ -3945,18 +4042,8 @@
     return set(kRemovedHolesIndex + index, Smi::FromInt(removed_index));
   }
 
-  static const int kNumberOfBucketsIndex = 0;
-  static const int kNumberOfElementsIndex = kNumberOfBucketsIndex + 1;
-  static const int kNumberOfDeletedElementsIndex = kNumberOfElementsIndex + 1;
-  static const int kHashTableStartIndex = kNumberOfDeletedElementsIndex + 1;
-
-  static const int kNextTableIndex = kNumberOfElementsIndex;
   static const int kRemovedHolesIndex = kHashTableStartIndex;
 
-  static const int kEntrySize = entrysize + 1;
-  static const int kChainOffset = entrysize;
-
-  static const int kLoadFactor = 2;
   static const int kMaxCapacity =
       (FixedArray::kMaxLength - kHashTableStartIndex)
       / (1 + (kEntrySize * kLoadFactor));
@@ -3995,7 +4082,6 @@
     return get(EntryToIndex(entry) + kValueOffset);
   }
 
- private:
   static const int kValueOffset = 1;
 };
 
@@ -4295,13 +4381,13 @@
   };
 
   // Properties of scopes.
-  class ScopeTypeField:        public BitField<ScopeType,            0, 3> {};
-  class CallsEvalField:        public BitField<bool,                 3, 1> {};
-  class StrictModeField:       public BitField<StrictMode,           4, 1> {};
-  class FunctionVariableField: public BitField<FunctionVariableInfo, 5, 2> {};
-  class FunctionVariableMode:  public BitField<VariableMode,         7, 3> {};
-  class AsmModuleField : public BitField<bool, 10, 1> {};
-  class AsmFunctionField : public BitField<bool, 11, 1> {};
+  class ScopeTypeField : public BitField<ScopeType, 0, 4> {};
+  class CallsEvalField : public BitField<bool, 4, 1> {};
+  class StrictModeField : public BitField<StrictMode, 5, 1> {};
+  class FunctionVariableField : public BitField<FunctionVariableInfo, 6, 2> {};
+  class FunctionVariableMode : public BitField<VariableMode, 8, 3> {};
+  class AsmModuleField : public BitField<bool, 11, 1> {};
+  class AsmFunctionField : public BitField<bool, 12, 1> {};
 
   // BitFields representing the encoded information for context locals in the
   // ContextLocalInfoEntries part.
@@ -4781,6 +4867,7 @@
 
 #undef FIXED_TYPED_ARRAY_TRAITS
 
+
 // DeoptimizationInputData is a fixed array used to hold the deoptimization
 // data for code generated by the Hydrogen/Lithium compiler.  It also
 // contains information about functions that were inlined.  If N different
@@ -4862,7 +4949,7 @@
   DECLARE_CAST(DeoptimizationInputData)
 
 #ifdef ENABLE_DISASSEMBLER
-  void DeoptimizationInputDataPrint(OStream& os);  // NOLINT
+  void DeoptimizationInputDataPrint(std::ostream& os);  // NOLINT
 #endif
 
  private:
@@ -4907,7 +4994,7 @@
   DECLARE_CAST(DeoptimizationOutputData)
 
 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
-  void DeoptimizationOutputDataPrint(OStream& os);  // NOLINT
+  void DeoptimizationOutputDataPrint(std::ostream& os);  // NOLINT
 #endif
 };
 
@@ -4973,9 +5060,9 @@
   // Printing
   static const char* ICState2String(InlineCacheState state);
   static const char* StubType2String(StubType type);
-  static void PrintExtraICState(OStream& os,  // NOLINT
+  static void PrintExtraICState(std::ostream& os,  // NOLINT
                                 Kind kind, ExtraICState extra);
-  void Disassemble(const char* name, OStream& os);  // NOLINT
+  void Disassemble(const char* name, std::ostream& os);  // NOLINT
 #endif  // ENABLE_DISASSEMBLER
 
   // [instruction_size]: Size of the native instructions
@@ -5054,12 +5141,7 @@
   inline bool is_to_boolean_ic_stub() { return kind() == TO_BOOLEAN_IC; }
   inline bool is_keyed_stub();
   inline bool is_optimized_code() { return kind() == OPTIMIZED_FUNCTION; }
-  inline bool is_weak_stub();
-  inline void mark_as_weak_stub();
-  inline bool is_invalidated_weak_stub();
-  inline void mark_as_invalidated_weak_stub();
-
-  inline bool CanBeWeakStub() {
+  inline bool embeds_maps_weakly() {
     Kind k = kind();
     return (k == LOAD_IC || k == STORE_IC || k == KEYED_LOAD_IC ||
             k == KEYED_STORE_IC || k == COMPARE_NIL_IC) &&
@@ -5102,6 +5184,12 @@
   inline bool is_compiled_optimizable();
   inline void set_compiled_optimizable(bool value);
 
+  // [has_reloc_info_for_serialization]: For FUNCTION kind, tells if its
+  // reloc info includes runtime and external references to support
+  // serialization/deserialization.
+  inline bool has_reloc_info_for_serialization();
+  inline void set_has_reloc_info_for_serialization(bool value);
+
   // [allow_osr_at_loop_nesting_level]: For FUNCTION kind, tells for
   // how long the function has been marked for OSR and therefore which
   // level of loop nesting we are willing to do on-stack replacement
@@ -5115,6 +5203,10 @@
   inline void set_profiler_ticks(int ticks);
 
   // [builtin_index]: For BUILTIN kind, tells which builtin index it has.
+  // For builtins, tells which builtin index it has.
+  // Note that builtins can have a code kind other than BUILTIN, which means
+  // that for arbitrary code objects, this index value may be random garbage.
+  // To verify in that case, compare the code object to the indexed builtin.
   inline int builtin_index();
   inline void set_builtin_index(int id);
 
@@ -5307,6 +5399,7 @@
   // compilation stub.
   static void MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate);
   static void MarkCodeAsExecuted(byte* sequence, Isolate* isolate);
+  void MakeYoung(Isolate* isolate);
   void MakeOlder(MarkingParity);
   static bool IsYoungSequence(Isolate* isolate, byte* sequence);
   bool IsOld();
@@ -5325,26 +5418,25 @@
   void VerifyEmbeddedObjectsDependency();
 #endif
 
-  inline bool CanContainWeakObjects() {
-    return is_optimized_code() || is_weak_stub();
-  }
+#ifdef DEBUG
+  void VerifyEmbeddedObjectsInFullCode();
+#endif  // DEBUG
+
+  inline bool CanContainWeakObjects() { return is_optimized_code(); }
 
   inline bool IsWeakObject(Object* object) {
     return (is_optimized_code() && !is_turbofanned() &&
-            IsWeakObjectInOptimizedCode(object)) ||
-           (is_weak_stub() && IsWeakObjectInIC(object));
+            IsWeakObjectInOptimizedCode(object));
   }
 
   static inline bool IsWeakObjectInOptimizedCode(Object* object);
-  static inline bool IsWeakObjectInIC(Object* object);
 
   // Max loop nesting marker used to postpose OSR. We don't take loop
   // nesting that is deeper than 5 levels into account.
   static const int kMaxLoopNestingMarker = 6;
 
   // Layout description.
-  static const int kInstructionSizeOffset = HeapObject::kHeaderSize;
-  static const int kRelocationInfoOffset = kInstructionSizeOffset + kIntSize;
+  static const int kRelocationInfoOffset = HeapObject::kHeaderSize;
   static const int kHandlerTableOffset = kRelocationInfoOffset + kPointerSize;
   static const int kDeoptimizationDataOffset =
       kHandlerTableOffset + kPointerSize;
@@ -5353,22 +5445,24 @@
       kDeoptimizationDataOffset + kPointerSize;
   static const int kNextCodeLinkOffset = kTypeFeedbackInfoOffset + kPointerSize;
   static const int kGCMetadataOffset = kNextCodeLinkOffset + kPointerSize;
-  static const int kICAgeOffset =
-      kGCMetadataOffset + kPointerSize;
+  static const int kInstructionSizeOffset = kGCMetadataOffset + kPointerSize;
+  static const int kICAgeOffset = kInstructionSizeOffset + kIntSize;
   static const int kFlagsOffset = kICAgeOffset + kIntSize;
   static const int kKindSpecificFlags1Offset = kFlagsOffset + kIntSize;
   static const int kKindSpecificFlags2Offset =
       kKindSpecificFlags1Offset + kIntSize;
   // Note: We might be able to squeeze this into the flags above.
   static const int kPrologueOffset = kKindSpecificFlags2Offset + kIntSize;
-  static const int kConstantPoolOffset = kPrologueOffset + kPointerSize;
+  static const int kConstantPoolOffset = kPrologueOffset + kIntSize;
 
-  static const int kHeaderPaddingStart = kConstantPoolOffset + kIntSize;
+  static const int kHeaderPaddingStart = kConstantPoolOffset + kPointerSize;
 
   // Add padding to align the instruction start following right after
   // the Code object header.
   static const int kHeaderSize =
       (kHeaderPaddingStart + kCodeAlignmentMask) & ~kCodeAlignmentMask;
+  // Ensure that the slot for the constant pool pointer is aligned.
+  STATIC_ASSERT((kConstantPoolOffset & kPointerAlignmentMask) == 0);
 
   // Byte offsets within kKindSpecificFlags1Offset.
   static const int kOptimizableOffset = kKindSpecificFlags1Offset;
@@ -5378,6 +5472,8 @@
       public BitField<bool, 0, 1> {};  // NOLINT
   class FullCodeFlagsHasDebugBreakSlotsField: public BitField<bool, 1, 1> {};
   class FullCodeFlagsIsCompiledOptimizable: public BitField<bool, 2, 1> {};
+  class FullCodeFlagsHasRelocInfoForSerialization
+      : public BitField<bool, 3, 1> {};
 
   static const int kProfilerTicksOffset = kFullCodeFlags + 1;
 
@@ -5395,9 +5491,7 @@
   static const int kHasFunctionCacheBit =
       kStackSlotsFirstBit + kStackSlotsBitCount;
   static const int kMarkedForDeoptimizationBit = kHasFunctionCacheBit + 1;
-  static const int kWeakStubBit = kMarkedForDeoptimizationBit + 1;
-  static const int kInvalidatedWeakStubBit = kWeakStubBit + 1;
-  static const int kIsTurbofannedBit = kInvalidatedWeakStubBit + 1;
+  static const int kIsTurbofannedBit = kMarkedForDeoptimizationBit + 1;
 
   STATIC_ASSERT(kStackSlotsFirstBit + kStackSlotsBitCount <= 32);
   STATIC_ASSERT(kIsTurbofannedBit + 1 <= 32);
@@ -5408,9 +5502,6 @@
   };  // NOLINT
   class MarkedForDeoptimizationField
       : public BitField<bool, kMarkedForDeoptimizationBit, 1> {};   // NOLINT
-  class WeakStubField : public BitField<bool, kWeakStubBit, 1> {};  // NOLINT
-  class InvalidatedWeakStubField
-      : public BitField<bool, kInvalidatedWeakStubBit, 1> {};  // NOLINT
   class IsTurbofannedField : public BitField<bool, kIsTurbofannedBit, 1> {
   };  // NOLINT
 
@@ -5492,11 +5583,6 @@
 class DependentCode: public FixedArray {
  public:
   enum DependencyGroup {
-    // Group of IC stubs that weakly embed this map and depend on being
-    // invalidated when the map is garbage collected. Dependent IC stubs form
-    // a linked list. This group stores only the head of the list. This means
-    // that the number_of_entries(kWeakICGroup) is 0 or 1.
-    kWeakICGroup,
     // Group of code that weakly embed this map and depend on being
     // deoptimized when the map is garbage collected.
     kWeakCodeGroup,
@@ -5557,7 +5643,6 @@
 
   bool MarkCodeForDeoptimization(Isolate* isolate,
                                  DependentCode::DependencyGroup group);
-  void AddToDependentICList(Handle<Code> stub);
 
   // The following low-level accessors should only be used by this class
   // and the mark compact collector.
@@ -5637,15 +5722,20 @@
   class OwnsDescriptors : public BitField<bool, 21, 1> {};
   class HasInstanceCallHandler : public BitField<bool, 22, 1> {};
   class Deprecated : public BitField<bool, 23, 1> {};
-  class IsFrozen : public BitField<bool, 24, 1> {};
-  class IsUnstable : public BitField<bool, 25, 1> {};
-  class IsMigrationTarget : public BitField<bool, 26, 1> {};
-  class DoneInobjectSlackTracking : public BitField<bool, 27, 1> {};
-  // Bit 28 is free.
+  class IsUnstable : public BitField<bool, 24, 1> {};
+  class IsMigrationTarget : public BitField<bool, 25, 1> {};
+  // Bits 26 and 27 are free.
 
   // Keep this bit field at the very end for better code in
   // Builtins::kJSConstructStubGeneric stub.
-  class ConstructionCount:          public BitField<int, 29, 3> {};
+  // This counter is used for in-object slack tracking and for map aging.
+  // The in-object slack tracking is considered enabled when the counter is
+  // in the range [kSlackTrackingCounterStart, kSlackTrackingCounterEnd].
+  class Counter : public BitField<int, 28, 4> {};
+  static const int kSlackTrackingCounterStart = 14;
+  static const int kSlackTrackingCounterEnd = 8;
+  static const int kRetainingCounterStart = kSlackTrackingCounterEnd - 1;
+  static const int kRetainingCounterEnd = 0;
 
   // Tells whether the object in the prototype property will be used
   // for instances created from this function.  If the prototype
@@ -5718,7 +5808,7 @@
   inline bool is_prototype_map();
 
   inline void set_elements_kind(ElementsKind elements_kind) {
-    DCHECK(elements_kind < kElementsKindCount);
+    DCHECK(static_cast<int>(elements_kind) < kElementsKindCount);
     DCHECK(kElementsKindCount <= (1 << Map::ElementsKindBits::kSize));
     set_bit_field2(Map::ElementsKindBits::update(bit_field2(), elements_kind));
     DCHECK(this->elements_kind() == elements_kind);
@@ -5783,7 +5873,9 @@
   inline Map* elements_transition_map();
 
   inline Map* GetTransition(int transition_index);
-  inline int SearchTransition(Name* name);
+  inline int SearchSpecialTransition(Symbol* name);
+  inline int SearchTransition(PropertyKind kind, Name* name,
+                              PropertyAttributes attributes);
   inline FixedArrayBase* GetInitialElements();
 
   DECL_ACCESSORS(transitions, TransitionArray)
@@ -5813,8 +5905,8 @@
       Handle<HeapType> type1,
       Handle<HeapType> type2,
       Isolate* isolate);
-  static void GeneralizeFieldType(Handle<Map> map,
-                                  int modify_index,
+  static void GeneralizeFieldType(Handle<Map> map, int modify_index,
+                                  Representation new_representation,
                                   Handle<HeapType> new_field_type);
   static Handle<Map> GeneralizeRepresentation(
       Handle<Map> map,
@@ -5838,7 +5930,8 @@
                                             int descriptor_number,
                                             Handle<Object> value);
 
-  static Handle<Map> Normalize(Handle<Map> map, PropertyNormalizationMode mode);
+  static Handle<Map> Normalize(Handle<Map> map, PropertyNormalizationMode mode,
+                               const char* reason);
 
   // Returns the constructor name (the name (possibly, inferred name) of the
   // function that was used to instantiate the object).
@@ -5861,13 +5954,33 @@
 
   // [prototype]: implicit prototype object.
   DECL_ACCESSORS(prototype, Object)
+  // TODO(jkummerow): make set_prototype private.
+  void SetPrototype(Handle<Object> prototype,
+                    PrototypeOptimizationMode proto_mode = FAST_PROTOTYPE);
+  bool ShouldRegisterAsPrototypeUser(Handle<JSObject> prototype);
+  bool CanUseOptimizationsBasedOnPrototypeRegistry();
 
   // [constructor]: points back to the function responsible for this map.
   DECL_ACCESSORS(constructor, Object)
 
   // [instance descriptors]: describes the object.
   DECL_ACCESSORS(instance_descriptors, DescriptorArray)
-  inline void InitializeDescriptors(DescriptorArray* descriptors);
+
+  // [layout descriptor]: describes the object layout.
+  DECL_ACCESSORS(layout_descriptor, LayoutDescriptor)
+  // |layout descriptor| accessor which can be used from GC.
+  inline LayoutDescriptor* layout_descriptor_gc_safe();
+  inline bool HasFastPointerLayout() const;
+
+  // |layout descriptor| accessor that is safe to call even when
+  // FLAG_unbox_double_fields is disabled (in this case Map does not contain
+  // |layout_descriptor| field at all).
+  inline LayoutDescriptor* GetLayoutDescriptor();
+
+  inline void UpdateDescriptors(DescriptorArray* descriptors,
+                                LayoutDescriptor* layout_descriptor);
+  inline void InitializeDescriptors(DescriptorArray* descriptors,
+                                    LayoutDescriptor* layout_descriptor);
 
   // [stub cache]: contains stubs compiled for this map.
   DECL_ACCESSORS(code_cache, Object)
@@ -5921,8 +6034,8 @@
                                Name* name,
                                LookupResult* result);
 
-  inline void LookupTransition(JSObject* holder,
-                               Name* name,
+  inline void LookupTransition(JSObject* holder, Name* name,
+                               PropertyAttributes attributes,
                                LookupResult* result);
 
   inline PropertyDetails GetLastDescriptorDetails();
@@ -5966,16 +6079,12 @@
   inline void set_owns_descriptors(bool owns_descriptors);
   inline bool has_instance_call_handler();
   inline void set_has_instance_call_handler();
-  inline void freeze();
-  inline bool is_frozen();
   inline void mark_unstable();
   inline bool is_stable();
   inline void set_migration_target(bool value);
   inline bool is_migration_target();
-  inline void set_done_inobject_slack_tracking(bool value);
-  inline bool done_inobject_slack_tracking();
-  inline void set_construction_count(int value);
-  inline int construction_count();
+  inline void set_counter(int value);
+  inline int counter();
   inline void deprecate();
   inline bool is_deprecated();
   inline bool CanBeDeprecated();
@@ -6027,7 +6136,10 @@
 
   static Handle<Map> CopyForObserved(Handle<Map> map);
 
-  static Handle<Map> CopyForFreeze(Handle<Map> map);
+  static Handle<Map> CopyForPreventExtensions(Handle<Map> map,
+                                              PropertyAttributes attrs_to_add,
+                                              Handle<Symbol> transition_marker,
+                                              const char* reason);
   // Maximal number of fast properties. Used to restrict the number of map
   // transitions to avoid an explosion in the number of maps for objects used as
   // dictionaries.
@@ -6047,7 +6159,7 @@
 
   // Returns a copy of the map, with all transitions dropped from the
   // instance descriptors.
-  static Handle<Map> Copy(Handle<Map> map);
+  static Handle<Map> Copy(Handle<Map> map, const char* reason);
   static Handle<Map> Create(Isolate* isolate, int inobject_properties);
 
   // Returns the next free property index (only valid for FAST MODE).
@@ -6082,6 +6194,8 @@
   static void AppendCallbackDescriptors(Handle<Map> map,
                                         Handle<Object> descriptors);
 
+  static inline int SlackForArraySize(int old_size, int size_limit);
+
   static void EnsureDescriptorSlack(Handle<Map> map, int slack);
 
   // Returns the found code or undefined if absent.
@@ -6122,6 +6236,7 @@
   bool IsJSObjectMap() {
     return instance_type() >= FIRST_JS_OBJECT_TYPE;
   }
+  bool IsStringMap() { return instance_type() < FIRST_NONSTRING_TYPE; }
   bool IsJSProxyMap() {
     InstanceType type = instance_type();
     return FIRST_JS_PROXY_TYPE <= type && type <= LAST_JS_PROXY_TYPE;
@@ -6146,11 +6261,11 @@
   static void AddDependentCode(Handle<Map> map,
                                DependentCode::DependencyGroup group,
                                Handle<Code> code);
-  static void AddDependentIC(Handle<Map> map,
-                             Handle<Code> stub);
 
   bool IsMapInArrayPrototypeChain();
 
+  static Handle<WeakCell> WeakCellForMap(Handle<Map> map);
+
   // Dispatched behavior.
   DECLARE_PRINTER(Map)
   DECLARE_VERIFIER(Map)
@@ -6173,10 +6288,11 @@
   // the original map.  That way we can transition to the same map if the same
   // prototype is set, rather than creating a new map every time.  The
   // transitions are in the form of a map where the keys are prototype objects
-  // and the values are the maps the are transitioned to.
+  // and the values are the maps they transition to.
   static const int kMaxCachedPrototypeTransitions = 256;
   static Handle<Map> TransitionToPrototype(Handle<Map> map,
-                                           Handle<Object> prototype);
+                                           Handle<Object> prototype,
+                                           PrototypeOptimizationMode mode);
 
   static const int kMaxPreAllocatedPropertyFields = 255;
 
@@ -6194,7 +6310,13 @@
       kConstructorOffset + kPointerSize;
   static const int kDescriptorsOffset =
       kTransitionsOrBackPointerOffset + kPointerSize;
+#if V8_DOUBLE_FIELDS_UNBOXING
+  static const int kLayoutDecriptorOffset = kDescriptorsOffset + kPointerSize;
+  static const int kCodeCacheOffset = kLayoutDecriptorOffset + kPointerSize;
+#else
+  static const int kLayoutDecriptorOffset = 1;  // Must not be ever accessed.
   static const int kCodeCacheOffset = kDescriptorsOffset + kPointerSize;
+#endif
   static const int kDependentCodeOffset = kCodeCacheOffset + kPointerSize;
   static const int kSize = kDependentCodeOffset + kPointerSize;
 
@@ -6272,6 +6394,18 @@
   // The "shared" flags of both this map and |other| are ignored.
   bool EquivalentToForNormalization(Map* other, PropertyNormalizationMode mode);
 
+  // Returns true if given field is unboxed double.
+  inline bool IsUnboxedDoubleField(FieldIndex index);
+
+#if TRACE_MAPS
+  static void TraceTransition(const char* what, Map* from, Map* to, Name* name);
+  static void TraceAllTransitions(Map* map);
+#endif
+
+  static inline Handle<Map> CopyInstallDescriptorsForTesting(
+      Handle<Map> map, int new_descriptor, Handle<DescriptorArray> descriptors,
+      Handle<LayoutDescriptor> layout_descriptor);
+
  private:
   static void ConnectElementsTransition(Handle<Map> parent, Handle<Map> child);
   static void ConnectTransition(Handle<Map> parent, Handle<Map> child,
@@ -6283,18 +6417,17 @@
                                      Handle<DescriptorArray> descriptors,
                                      Descriptor* descriptor);
   static Handle<Map> CopyInstallDescriptors(
-      Handle<Map> map,
-      int new_descriptor,
-      Handle<DescriptorArray> descriptors);
+      Handle<Map> map, int new_descriptor, Handle<DescriptorArray> descriptors,
+      Handle<LayoutDescriptor> layout_descriptor);
   static Handle<Map> CopyAddDescriptor(Handle<Map> map,
                                        Descriptor* descriptor,
                                        TransitionFlag flag);
   static Handle<Map> CopyReplaceDescriptors(
-      Handle<Map> map,
-      Handle<DescriptorArray> descriptors,
-      TransitionFlag flag,
-      MaybeHandle<Name> maybe_name,
-      SimpleTransitionFlag simple_flag = FULL_TRANSITION);
+      Handle<Map> map, Handle<DescriptorArray> descriptors,
+      Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
+      MaybeHandle<Name> maybe_name, const char* reason,
+      SimpleTransitionFlag simple_flag);
+
   static Handle<Map> CopyReplaceDescriptor(Handle<Map> map,
                                            Handle<DescriptorArray> descriptors,
                                            Descriptor* descriptor,
@@ -6322,11 +6455,15 @@
   void ZapTransitions();
 
   void DeprecateTransitionTree();
-  void DeprecateTarget(Name* key, DescriptorArray* new_descriptors);
+  bool DeprecateTarget(PropertyKind kind, Name* key,
+                       PropertyAttributes attributes,
+                       DescriptorArray* new_descriptors,
+                       LayoutDescriptor* new_layout_descriptor);
 
   Map* FindLastMatchMap(int verbatim, int length, DescriptorArray* descriptors);
 
   void UpdateFieldType(int descriptor_number, Handle<Name> name,
+                       Representation new_representation,
                        Handle<HeapType> new_type);
 
   void PrintGeneralization(FILE* file,
@@ -6428,8 +6565,8 @@
   // [context_data]: context data for the context this script was compiled in.
   DECL_ACCESSORS(context_data, Object)
 
-  // [wrapper]: the wrapper cache.
-  DECL_ACCESSORS(wrapper, Foreign)
+  // [wrapper]: the wrapper cache.  This is either undefined or a WeakCell.
+  DECL_ACCESSORS(wrapper, HeapObject)
 
   // [type]: the script type.
   DECL_ACCESSORS(type, Smi)
@@ -6491,7 +6628,6 @@
 
   // Get the JS object wrapping the given script; create it if none exists.
   static Handle<JSObject> GetWrapper(Handle<Script> script);
-  void ClearWrapperCache();
 
   // Dispatched behavior.
   DECLARE_PRINTER(Script)
@@ -6543,9 +6679,11 @@
   V(Array.prototype, pop, ArrayPop)                 \
   V(Array.prototype, shift, ArrayShift)             \
   V(Function.prototype, apply, FunctionApply)       \
+  V(Function.prototype, call, FunctionCall)         \
   V(String.prototype, charCodeAt, StringCharCodeAt) \
   V(String.prototype, charAt, StringCharAt)         \
   V(String, fromCharCode, StringFromCharCode)       \
+  V(Math, random, MathRandom)                       \
   V(Math, floor, MathFloor)                         \
   V(Math, round, MathRound)                         \
   V(Math, ceil, MathCeil)                           \
@@ -6556,6 +6694,13 @@
   V(Math, pow, MathPow)                             \
   V(Math, max, MathMax)                             \
   V(Math, min, MathMin)                             \
+  V(Math, cos, MathCos)                             \
+  V(Math, sin, MathSin)                             \
+  V(Math, tan, MathTan)                             \
+  V(Math, acos, MathAcos)                           \
+  V(Math, asin, MathAsin)                           \
+  V(Math, atan, MathAtan)                           \
+  V(Math, atan2, MathAtan2)                         \
   V(Math, imul, MathImul)                           \
   V(Math, clz32, MathClz32)                         \
   V(Math, fround, MathFround)
@@ -6657,6 +6802,13 @@
   // available.
   DECL_ACCESSORS(feedback_vector, TypeFeedbackVector)
 
+#if TRACE_MAPS
+  // [unique_id] - For --trace-maps purposes, an identifier that's persistent
+  // even if the GC moves this SharedFunctionInfo.
+  inline int unique_id() const;
+  inline void set_unique_id(int value);
+#endif
+
   // [instance class name]: class name for instances.
   DECL_ACCESSORS(instance_class_name, Object)
 
@@ -6759,6 +6911,13 @@
   // False if the function definitely does not allocate an arguments object.
   DECL_BOOLEAN_ACCESSORS(uses_arguments)
 
+  // Indicates that this function uses a super property.
+  // This is needed to set up the [[HomeObject]] on the function instance.
+  DECL_BOOLEAN_ACCESSORS(uses_super_property)
+
+  // Indicates that this function uses the super constructor.
+  DECL_BOOLEAN_ACCESSORS(uses_super_constructor_call)
+
   // True if the function has any duplicated parameter names.
   DECL_BOOLEAN_ACCESSORS(has_duplicate_parameters)
 
@@ -6803,9 +6962,15 @@
   // Indicates that this function is a concise method.
   DECL_BOOLEAN_ACCESSORS(is_concise_method)
 
+  // Indicates that this function is a default constructor.
+  DECL_BOOLEAN_ACCESSORS(is_default_constructor)
+
   // Indicates that this function is an asm function.
   DECL_BOOLEAN_ACCESSORS(asm_function)
 
+  // Indicates that the the shared function info is deserialized from cache.
+  DECL_BOOLEAN_ACCESSORS(deserialized)
+
   inline FunctionKind kind();
   inline void set_kind(FunctionKind kind);
 
@@ -6820,7 +6985,7 @@
   // shared function info.
   void DisableOptimization(BailoutReason reason);
 
-  inline BailoutReason DisableOptimizationReason();
+  inline BailoutReason disable_optimization_reason();
 
   // Lookup the bailout ID and DCHECK that it exists in the non-optimized
   // code, returns whether it asserted (i.e., always true if assertions are
@@ -6855,7 +7020,7 @@
   inline void set_opt_count_and_bailout_reason(int value);
   inline int opt_count_and_bailout_reason() const;
 
-  void set_bailout_reason(BailoutReason reason) {
+  void set_disable_optimization_reason(BailoutReason reason) {
     set_opt_count_and_bailout_reason(
         DisabledOptimizationReasonBits::update(opt_count_and_bailout_reason(),
                                                reason));
@@ -6900,10 +7065,16 @@
   static const int kInferredNameOffset = kDebugInfoOffset + kPointerSize;
   static const int kFeedbackVectorOffset =
       kInferredNameOffset + kPointerSize;
+#if TRACE_MAPS
+  static const int kUniqueIdOffset = kFeedbackVectorOffset + kPointerSize;
+  static const int kLastPointerFieldOffset = kUniqueIdOffset;
+#else
+  static const int kLastPointerFieldOffset = kFeedbackVectorOffset;
+#endif
+
 #if V8_HOST_ARCH_32_BIT
   // Smi fields.
-  static const int kLengthOffset =
-      kFeedbackVectorOffset + kPointerSize;
+  static const int kLengthOffset = kLastPointerFieldOffset + kPointerSize;
   static const int kFormalParameterCountOffset = kLengthOffset + kPointerSize;
   static const int kExpectedNofPropertiesOffset =
       kFormalParameterCountOffset + kPointerSize;
@@ -6934,12 +7105,12 @@
   // garbage collections.
   // To avoid wasting space on 64-bit architectures we use
   // the following trick: we group integer fields into pairs
-  // First integer in each pair is shifted left by 1.
-  // By doing this we guarantee that LSB of each kPointerSize aligned
-  // word is not set and thus this word cannot be treated as pointer
-  // to HeapObject during old space traversal.
-  static const int kLengthOffset =
-      kFeedbackVectorOffset + kPointerSize;
+// The least significant integer in each pair is shifted left by 1.
+// By doing this we guarantee that LSB of each kPointerSize aligned
+// word is not set and thus this word cannot be treated as pointer
+// to HeapObject during old space traversal.
+#if V8_TARGET_LITTLE_ENDIAN
+  static const int kLengthOffset = kLastPointerFieldOffset + kPointerSize;
   static const int kFormalParameterCountOffset =
       kLengthOffset + kIntSize;
 
@@ -6971,12 +7142,42 @@
   // Total size.
   static const int kSize = kProfilerTicksOffset + kIntSize;
 
-#endif
+#elif V8_TARGET_BIG_ENDIAN
+  static const int kFormalParameterCountOffset =
+      kLastPointerFieldOffset + kPointerSize;
+  static const int kLengthOffset = kFormalParameterCountOffset + kIntSize;
+
+  static const int kNumLiteralsOffset = kLengthOffset + kIntSize;
+  static const int kExpectedNofPropertiesOffset = kNumLiteralsOffset + kIntSize;
+
+  static const int kStartPositionAndTypeOffset =
+      kExpectedNofPropertiesOffset + kIntSize;
+  static const int kEndPositionOffset = kStartPositionAndTypeOffset + kIntSize;
+
+  static const int kCompilerHintsOffset = kEndPositionOffset + kIntSize;
+  static const int kFunctionTokenPositionOffset =
+      kCompilerHintsOffset + kIntSize;
+
+  static const int kCountersOffset = kFunctionTokenPositionOffset + kIntSize;
+  static const int kOptCountAndBailoutReasonOffset = kCountersOffset + kIntSize;
+
+  static const int kProfilerTicksOffset =
+      kOptCountAndBailoutReasonOffset + kIntSize;
+  static const int kAstNodeCountOffset = kProfilerTicksOffset + kIntSize;
+
+  // Total size.
+  static const int kSize = kAstNodeCountOffset + kIntSize;
+
+#else
+#error Unknown byte ordering
+#endif  // Big endian
+#endif  // 64-bit
+
 
   static const int kAlignedSize = POINTER_SIZE_ALIGN(kSize);
 
   typedef FixedBodyDescriptor<kNameOffset,
-                              kFeedbackVectorOffset + kPointerSize,
+                              kLastPointerFieldOffset + kPointerSize,
                               kSize> BodyDescriptor;
 
   // Bit positions in start_position_and_type.
@@ -6994,6 +7195,8 @@
     kOptimizationDisabled,
     kStrictModeFunction,
     kUsesArguments,
+    kUsesSuperProperty,
+    kUsesSuperConstructorCall,
     kHasDuplicateParameters,
     kNative,
     kInlineBuiltin,
@@ -7006,11 +7209,13 @@
     kIsArrow,
     kIsGenerator,
     kIsConciseMethod,
+    kIsDefaultConstructor,
     kIsAsmFunction,
+    kDeserialized,
     kCompilerHintsCount  // Pseudo entry
   };
 
-  class FunctionKindBits : public BitField<FunctionKind, kIsArrow, 3> {};
+  class FunctionKindBits : public BitField<FunctionKind, kIsArrow, 4> {};
 
   class DeoptCountBits : public BitField<int, 0, 4> {};
   class OptReenableTriesBits : public BitField<int, 4, 18> {};
@@ -7073,7 +7278,7 @@
 };
 
 
-OStream& operator<<(OStream& os, const SourceCodeOf& v);
+std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v);
 
 
 class JSGeneratorObject: public JSObject {
@@ -7215,8 +7420,7 @@
   // Mark this function for lazy recompilation. The function will be
   // recompiled the next time it is executed.
   void MarkForOptimization();
-  void MarkForConcurrentOptimization();
-  void MarkInOptimizationQueue();
+  void AttemptConcurrentOptimization();
 
   // Tells whether or not the function is already marked for lazy
   // recompilation.
@@ -7236,13 +7440,12 @@
   // Here is the algorithm to reclaim the unused inobject space:
   // - Detect the first constructor call for this JSFunction.
   //   When it happens enter the "in progress" state: initialize construction
-  //   counter in the initial_map and set the |done_inobject_slack_tracking|
-  //   flag.
+  //   counter in the initial_map.
   // - While the tracking is in progress create objects filled with
   //   one_pointer_filler_map instead of undefined_value. This way they can be
   //   resized quickly and safely.
-  // - Once enough (kGenerousAllocationCount) objects have been created
-  //   compute the 'slack' (traverse the map transition tree starting from the
+  // - Once enough objects have been created  compute the 'slack'
+  //   (traverse the map transition tree starting from the
   //   initial_map and find the lowest value of unused_property_fields).
   // - Traverse the transition tree again and decrease the instance size
   //   of every map. Existing objects will resize automatically (they are
@@ -7255,23 +7458,17 @@
   //  Important: inobject slack tracking is not attempted during the snapshot
   //  creation.
 
-  static const int kGenerousAllocationCount = Map::ConstructionCount::kMax;
-  static const int kFinishSlackTracking     = 1;
-  static const int kNoSlackTracking         = 0;
-
   // True if the initial_map is set and the object constructions countdown
   // counter is not zero.
+  static const int kGenerousAllocationCount =
+      Map::kSlackTrackingCounterStart - Map::kSlackTrackingCounterEnd + 1;
   inline bool IsInobjectSlackTrackingInProgress();
 
   // Starts the tracking.
   // Initializes object constructions countdown counter in the initial map.
-  // IsInobjectSlackTrackingInProgress is normally true after this call,
-  // except when tracking have not been started (e.g. the map has no unused
-  // properties or the snapshot is being built).
   void StartInobjectSlackTracking();
 
   // Completes the tracking.
-  // IsInobjectSlackTrackingInProgress is false after this call.
   void CompleteInobjectSlackTracking();
 
   // [literals_or_bindings]: Fixed array holding either
@@ -7443,19 +7640,18 @@
   // [native context]: the natives corresponding to this global object.
   DECL_ACCESSORS(native_context, Context)
 
-  // [global context]: the most recent (i.e. innermost) global context.
-  DECL_ACCESSORS(global_context, Context)
-
   // [global proxy]: the global proxy object of the context
   DECL_ACCESSORS(global_proxy, JSObject)
 
   DECLARE_CAST(GlobalObject)
 
+  static void InvalidatePropertyCell(Handle<GlobalObject> object,
+                                     Handle<Name> name);
+
   // Layout description.
   static const int kBuiltinsOffset = JSObject::kHeaderSize;
   static const int kNativeContextOffset = kBuiltinsOffset + kPointerSize;
-  static const int kGlobalContextOffset = kNativeContextOffset + kPointerSize;
-  static const int kGlobalProxyOffset = kGlobalContextOffset + kPointerSize;
+  static const int kGlobalProxyOffset = kNativeContextOffset + kPointerSize;
   static const int kHeaderSize = kGlobalProxyOffset + kPointerSize;
 
  private:
@@ -7815,12 +8011,11 @@
       FixedArray::kHeaderSize + kIrregexpCaptureCountIndex * kPointerSize;
 
   // In-object fields.
-  static const int kSourceFieldIndex = 0;
-  static const int kGlobalFieldIndex = 1;
-  static const int kIgnoreCaseFieldIndex = 2;
-  static const int kMultilineFieldIndex = 3;
-  static const int kLastIndexFieldIndex = 4;
-  static const int kInObjectFieldCount = 5;
+  static const int kGlobalFieldIndex = 0;
+  static const int kIgnoreCaseFieldIndex = 1;
+  static const int kMultilineFieldIndex = 2;
+  static const int kLastIndexFieldIndex = 3;
+  static const int kInObjectFieldCount = 4;
 
   // The uninitialized value for a regexp code object.
   static const int kUninitializedValue = -1;
@@ -7857,6 +8052,17 @@
 };
 
 
+// This cache is used in two different variants. For regexp caching, it simply
+// maps identifying info of the regexp to the cached regexp object. Scripts and
+// eval code only gets cached after a second probe for the code object. To do
+// so, on first "put" only a hash identifying the source is entered into the
+// cache, mapping it to a lifetime count of the hash. On each call to Age all
+// such lifetimes get reduced, and removed once they reach zero. If a second put
+// is called while such a hash is live in the cache, the hash gets replaced by
+// an actual cache entry. Age also removes stale live entries from the cache.
+// Such entries are identified by SharedFunctionInfos pointing to either the
+// recompilation stub, or to "old" code. This avoids memory leaks due to
+// premature caching of scripts and eval strings that are never needed later.
 class CompilationCacheTable: public HashTable<CompilationCacheTable,
                                               CompilationCacheShape,
                                               HashTableKey*> {
@@ -7878,6 +8084,8 @@
       Handle<CompilationCacheTable> cache, Handle<String> src,
       JSRegExp::Flags flags, Handle<FixedArray> value);
   void Remove(Object* value);
+  void Age();
+  static const int kHashGenerations = 10;
 
   DECLARE_CAST(CompilationCacheTable)
 
@@ -7890,6 +8098,7 @@
  public:
   DECL_ACCESSORS(default_cache, FixedArray)
   DECL_ACCESSORS(normal_type_cache, Object)
+  DECL_ACCESSORS(weak_cell_cache, Object)
 
   // Add the code object to the cache.
   static void Update(
@@ -7917,7 +8126,8 @@
   static const int kDefaultCacheOffset = HeapObject::kHeaderSize;
   static const int kNormalTypeCacheOffset =
       kDefaultCacheOffset + kPointerSize;
-  static const int kSize = kNormalTypeCacheOffset + kPointerSize;
+  static const int kWeakCellCacheOffset = kNormalTypeCacheOffset + kPointerSize;
+  static const int kSize = kWeakCellCacheOffset + kPointerSize;
 
  private:
   static void UpdateDefaultCache(
@@ -8048,7 +8258,6 @@
   inline void set_inlined_type_change_checksum(int checksum);
   inline bool matches_inlined_type_change_checksum(int checksum);
 
-
   DECLARE_CAST(TypeFeedbackInfo)
 
   // Dispatched behavior.
@@ -8231,14 +8440,11 @@
   static void DigestTransitionFeedback(Handle<AllocationSite> site,
                                        ElementsKind to_kind);
 
-  enum Reason {
-    TENURING,
-    TRANSITIONS
-  };
+  static void RegisterForDeoptOnTenureChange(Handle<AllocationSite> site,
+                                             CompilationInfo* info);
 
-  static void AddDependentCompilationInfo(Handle<AllocationSite> site,
-                                          Reason reason,
-                                          CompilationInfo* info);
+  static void RegisterForDeoptOnTransitionChange(Handle<AllocationSite> site,
+                                                 CompilationInfo* info);
 
   DECLARE_PRINTER(AllocationSite)
   DECLARE_VERIFIER(AllocationSite)
@@ -8270,7 +8476,10 @@
                               kSize> BodyDescriptor;
 
  private:
-  inline DependentCode::DependencyGroup ToDependencyGroup(Reason reason);
+  static void AddDependentCompilationInfo(Handle<AllocationSite> site,
+                                          DependentCode::DependencyGroup group,
+                                          CompilationInfo* info);
+
   bool PretenuringDecisionMade() {
     return pretenure_decision() != kUndecided;
   }
@@ -8363,6 +8572,11 @@
   // Reusable parts of the hashing algorithm.
   INLINE(static uint32_t AddCharacterCore(uint32_t running_hash, uint16_t c));
   INLINE(static uint32_t GetHashCore(uint32_t running_hash));
+  INLINE(static uint32_t ComputeRunningHash(uint32_t running_hash,
+                                            const uc16* chars, int length));
+  INLINE(static uint32_t ComputeRunningHashOneByte(uint32_t running_hash,
+                                                   const char* chars,
+                                                   int length));
 
  protected:
   // Returns the value to store in the hash field of a string with
@@ -8399,6 +8613,7 @@
  private:
   inline IteratingStringHasher(int len, uint32_t seed)
       : StringHasher(len, seed) {}
+  void VisitConsString(ConsString* cons_string);
   DISALLOW_COPY_AND_ASSIGN(IteratingStringHasher);
 };
 
@@ -8479,10 +8694,19 @@
   DECLARE_CAST(Name)
 
   DECLARE_PRINTER(Name)
+#if TRACE_MAPS
+  void NameShortPrint();
+  int NameShortPrint(Vector<char> str);
+#endif
 
   // Layout description.
-  static const int kHashFieldOffset = HeapObject::kHeaderSize;
-  static const int kSize = kHashFieldOffset + kPointerSize;
+  static const int kHashFieldSlot = HeapObject::kHeaderSize;
+#if V8_TARGET_LITTLE_ENDIAN || !V8_HOST_ARCH_64_BIT
+  static const int kHashFieldOffset = kHashFieldSlot;
+#else
+  static const int kHashFieldOffset = kHashFieldSlot + kIntSize;
+#endif
+  static const int kSize = kHashFieldSlot + kPointerSize;
 
   // Mask constant for checking if a name has a computed hash code
   // and if it is a string that is an array index.  The least significant bit
@@ -8568,10 +8792,18 @@
 
   typedef FixedBodyDescriptor<kNameOffset, kFlagsOffset, kSize> BodyDescriptor;
 
+  void SymbolShortPrint(std::ostream& os);
+
  private:
   static const int kPrivateBit = 0;
   static const int kOwnBit = 1;
 
+  const char* PrivateSymbolToName() const;
+
+#if TRACE_MAPS
+  friend class Name;  // For PrivateSymbolToName.
+#endif
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(Symbol);
 };
 
@@ -8672,6 +8904,9 @@
     friend class String;
   };
 
+  template <typename Char>
+  INLINE(Vector<const Char> GetCharVector());
+
   // Get and set the length of the string.
   inline int length() const;
   inline void set_length(int value);
@@ -8787,8 +9022,8 @@
 
   // Dispatched behavior.
   void StringShortPrint(StringStream* accumulator);
-  void PrintUC16(OStream& os, int start = 0, int end = -1);  // NOLINT
-#ifdef OBJECT_PRINT
+  void PrintUC16(std::ostream& os, int start = 0, int end = -1);  // NOLINT
+#if defined(DEBUG) || defined(OBJECT_PRINT)
   char* ToAsciiArray();
 #endif
   DECLARE_PRINTER(String)
@@ -9257,6 +9492,8 @@
   FlatStringReader(Isolate* isolate, Vector<const char> input);
   void PostGarbageCollection();
   inline uc32 Get(int index);
+  template <typename Char>
+  inline Char Get(int index);
   int length() { return length_; }
  private:
   String** str_;
@@ -9266,26 +9503,13 @@
 };
 
 
-// A ConsStringOp that returns null.
-// Useful when the operation to apply on a ConsString
-// requires an expensive data structure.
-class ConsStringNullOp {
- public:
-  inline ConsStringNullOp() {}
-  static inline String* Operate(String*, unsigned*, int32_t*, unsigned*);
- private:
-  DISALLOW_COPY_AND_ASSIGN(ConsStringNullOp);
-};
-
-
 // This maintains an off-stack representation of the stack frames required
 // to traverse a ConsString, allowing an entirely iterative and restartable
 // traversal of the entire string
-class ConsStringIteratorOp {
+class ConsStringIterator {
  public:
-  inline ConsStringIteratorOp() {}
-  inline explicit ConsStringIteratorOp(ConsString* cons_string,
-                                       int offset = 0) {
+  inline ConsStringIterator() {}
+  inline explicit ConsStringIterator(ConsString* cons_string, int offset = 0) {
     Reset(cons_string, offset);
   }
   inline void Reset(ConsString* cons_string, int offset = 0) {
@@ -9325,14 +9549,13 @@
   int depth_;
   int maximum_depth_;
   int consumed_;
-  DISALLOW_COPY_AND_ASSIGN(ConsStringIteratorOp);
+  DISALLOW_COPY_AND_ASSIGN(ConsStringIterator);
 };
 
 
 class StringCharacterStream {
  public:
   inline StringCharacterStream(String* string,
-                               ConsStringIteratorOp* op,
                                int offset = 0);
   inline uint16_t GetNext();
   inline bool HasMore();
@@ -9341,13 +9564,13 @@
   inline void VisitTwoByteString(const uint16_t* chars, int length);
 
  private:
+  ConsStringIterator iter_;
   bool is_one_byte_;
   union {
     const uint8_t* buffer8_;
     const uint16_t* buffer16_;
   };
   const uint8_t* end_;
-  ConsStringIteratorOp* op_;
   DISALLOW_COPY_AND_ASSIGN(StringCharacterStream);
 };
 
@@ -9467,8 +9690,10 @@
   // of the cell's current type and the value's type. If the change causes
   // a change of the type of the cell's contents, code dependent on the cell
   // will be deoptimized.
-  static void SetValueInferType(Handle<PropertyCell> cell,
-                                Handle<Object> value);
+  // Usually returns the value that was passed in, but may perform
+  // non-observable modifications on it, such as internalize strings.
+  static Handle<Object> SetValueInferType(Handle<PropertyCell> cell,
+                                          Handle<Object> value);
 
   // Computes the new type of the cell's contents for the given value, but
   // without actually modifying the 'type' field.
@@ -9506,6 +9731,37 @@
 };
 
 
+class WeakCell : public HeapObject {
+ public:
+  inline Object* value() const;
+
+  // This should not be called by anyone except GC.
+  inline void clear();
+
+  // This should not be called by anyone except allocator.
+  inline void initialize(HeapObject* value);
+
+  inline bool cleared() const;
+
+  DECL_ACCESSORS(next, Object)
+
+  DECLARE_CAST(WeakCell)
+
+  DECLARE_PRINTER(WeakCell)
+  DECLARE_VERIFIER(WeakCell)
+
+  // Layout description.
+  static const int kValueOffset = HeapObject::kHeaderSize;
+  static const int kNextOffset = kValueOffset + kPointerSize;
+  static const int kSize = kNextOffset + kPointerSize;
+
+  typedef FixedBodyDescriptor<kValueOffset, kSize, kSize> BodyDescriptor;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(WeakCell);
+};
+
+
 // The JSProxy describes EcmaScript Harmony proxies
 class JSProxy: public JSReceiver {
  public:
@@ -9712,7 +9968,7 @@
   DECL_ACCESSORS(kind, Object)
 
 #ifdef OBJECT_PRINT
-  void OrderedHashTableIteratorPrint(OStream& os);  // NOLINT
+  void OrderedHashTableIteratorPrint(std::ostream& os);  // NOLINT
 #endif
 
   static const int kTableOffset = JSObject::kHeaderSize;
@@ -9856,6 +10112,9 @@
   inline bool should_be_freed();
   inline void set_should_be_freed(bool value);
 
+  inline bool is_neuterable();
+  inline void set_is_neuterable(bool value);
+
   // [weak_next]: linked list of array buffers.
   DECL_ACCESSORS(weak_next, Object)
 
@@ -9885,6 +10144,7 @@
   // Bit position in a flag
   static const int kIsExternalBit = 0;
   static const int kShouldBeFreed = 1;
+  static const int kIsNeuterableBit = 2;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBuffer);
 };
@@ -10027,10 +10287,13 @@
                                            uint32_t index,
                                            Handle<Object> value);
 
-  static bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map);
+  static bool HasReadOnlyLength(Handle<JSArray> array);
   static bool WouldChangeReadOnlyLength(Handle<JSArray> array, uint32_t index);
   static MaybeHandle<Object> ReadOnlyLengthError(Handle<JSArray> array);
 
+  // TODO(adamk): Remove this method in favor of HasReadOnlyLength().
+  static bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map);
+
   // Initialize the array with the given capacity. The function may
   // fail due to out-of-memory situations, but only if the requested
   // capacity is non-zero.
@@ -10383,6 +10646,11 @@
   DECL_ACCESSORS(deleter, Object)
   DECL_ACCESSORS(enumerator, Object)
   DECL_ACCESSORS(data, Object)
+  DECL_BOOLEAN_ACCESSORS(can_intercept_symbols)
+  DECL_BOOLEAN_ACCESSORS(all_can_read)
+
+  inline int flags() const;
+  inline void set_flags(int flags);
 
   DECLARE_CAST(InterceptorInfo)
 
@@ -10396,7 +10664,11 @@
   static const int kDeleterOffset = kQueryOffset + kPointerSize;
   static const int kEnumeratorOffset = kDeleterOffset + kPointerSize;
   static const int kDataOffset = kEnumeratorOffset + kPointerSize;
-  static const int kSize = kDataOffset + kPointerSize;
+  static const int kFlagsOffset = kDataOffset + kPointerSize;
+  static const int kSize = kFlagsOffset + kPointerSize;
+
+  static const int kCanInterceptSymbolsBit = 0;
+  static const int kAllCanReadBit = 1;
 
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptorInfo);
diff --git a/src/optimizing-compiler-thread.cc b/src/optimizing-compiler-thread.cc
index 387e9c0..6926f47 100644
--- a/src/optimizing-compiler-thread.cc
+++ b/src/optimizing-compiler-thread.cc
@@ -15,6 +15,84 @@
 namespace v8 {
 namespace internal {
 
+namespace {
+
+void DisposeOptimizedCompileJob(OptimizedCompileJob* job,
+                                bool restore_function_code) {
+  // The recompile job is allocated in the CompilationInfo's zone.
+  CompilationInfo* info = job->info();
+  if (restore_function_code) {
+    if (info->is_osr()) {
+      if (!job->IsWaitingForInstall()) {
+        // Remove stack check that guards OSR entry on original code.
+        Handle<Code> code = info->unoptimized_code();
+        uint32_t offset = code->TranslateAstIdToPcOffset(info->osr_ast_id());
+        BackEdgeTable::RemoveStackCheck(code, offset);
+      }
+    } else {
+      Handle<JSFunction> function = info->closure();
+      function->ReplaceCode(function->shared()->code());
+    }
+  }
+  delete info;
+}
+
+}  // namespace
+
+
+class OptimizingCompilerThread::CompileTask : public v8::Task {
+ public:
+  explicit CompileTask(Isolate* isolate) : isolate_(isolate) {}
+
+  virtual ~CompileTask() {}
+
+ private:
+  // v8::Task overrides.
+  void Run() OVERRIDE {
+    DisallowHeapAllocation no_allocation;
+    DisallowHandleAllocation no_handles;
+    DisallowHandleDereference no_deref;
+
+    TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_);
+
+    OptimizingCompilerThread* thread = isolate_->optimizing_compiler_thread();
+
+    if (thread->recompilation_delay_ != 0) {
+      base::OS::Sleep(thread->recompilation_delay_);
+    }
+
+    StopFlag flag;
+    OptimizedCompileJob* job = thread->NextInput(&flag);
+
+    if (flag == CONTINUE) {
+      thread->CompileNext(job);
+    } else {
+      AllowHandleDereference allow_handle_dereference;
+      if (!job->info()->is_osr()) {
+        DisposeOptimizedCompileJob(job, true);
+      }
+    }
+    bool signal = false;
+    {
+      base::LockGuard<base::RecursiveMutex> lock(&thread->task_count_mutex_);
+      if (--thread->task_count_ == 0) {
+        if (static_cast<StopFlag>(base::Acquire_Load(&thread->stop_thread_)) ==
+            FLUSH) {
+          base::Release_Store(&thread->stop_thread_,
+                              static_cast<base::AtomicWord>(CONTINUE));
+          signal = true;
+        }
+      }
+    }
+    if (signal) thread->stop_semaphore_.Signal();
+  }
+
+  Isolate* isolate_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompileTask);
+};
+
+
 OptimizingCompilerThread::~OptimizingCompilerThread() {
   DCHECK_EQ(0, input_queue_length_);
   DeleteArray(input_queue_);
@@ -35,27 +113,30 @@
     thread_id_ = ThreadId::Current().ToInteger();
   }
 #endif
-  Isolate::SetIsolateThreadLocals(isolate_, NULL);
   DisallowHeapAllocation no_allocation;
   DisallowHandleAllocation no_handles;
   DisallowHandleDereference no_deref;
 
+  if (job_based_recompilation_) {
+    return;
+  }
+
   base::ElapsedTimer total_timer;
-  if (FLAG_trace_concurrent_recompilation) total_timer.Start();
+  if (tracing_enabled_) total_timer.Start();
 
   while (true) {
     input_queue_semaphore_.Wait();
     TimerEventScope<TimerEventRecompileConcurrent> timer(isolate_);
 
-    if (FLAG_concurrent_recompilation_delay != 0) {
-      base::OS::Sleep(FLAG_concurrent_recompilation_delay);
+    if (recompilation_delay_ != 0) {
+      base::OS::Sleep(recompilation_delay_);
     }
 
     switch (static_cast<StopFlag>(base::Acquire_Load(&stop_thread_))) {
       case CONTINUE:
         break;
       case STOP:
-        if (FLAG_trace_concurrent_recompilation) {
+        if (tracing_enabled_) {
           time_spent_total_ = total_timer.Elapsed();
         }
         stop_semaphore_.Signal();
@@ -73,30 +154,38 @@
     }
 
     base::ElapsedTimer compiling_timer;
-    if (FLAG_trace_concurrent_recompilation) compiling_timer.Start();
+    if (tracing_enabled_) compiling_timer.Start();
 
-    CompileNext();
+    CompileNext(NextInput());
 
-    if (FLAG_trace_concurrent_recompilation) {
+    if (tracing_enabled_) {
       time_spent_compiling_ += compiling_timer.Elapsed();
     }
   }
 }
 
 
-OptimizedCompileJob* OptimizingCompilerThread::NextInput() {
+OptimizedCompileJob* OptimizingCompilerThread::NextInput(StopFlag* flag) {
   base::LockGuard<base::Mutex> access_input_queue_(&input_queue_mutex_);
-  if (input_queue_length_ == 0) return NULL;
+  if (input_queue_length_ == 0) {
+    if (flag) {
+      UNREACHABLE();
+      *flag = CONTINUE;
+    }
+    return NULL;
+  }
   OptimizedCompileJob* job = input_queue_[InputQueueIndex(0)];
   DCHECK_NE(NULL, job);
   input_queue_shift_ = InputQueueIndex(1);
   input_queue_length_--;
+  if (flag) {
+    *flag = static_cast<StopFlag>(base::Acquire_Load(&stop_thread_));
+  }
   return job;
 }
 
 
-void OptimizingCompilerThread::CompileNext() {
-  OptimizedCompileJob* job = NextInput();
+void OptimizingCompilerThread::CompileNext(OptimizedCompileJob* job) {
   DCHECK_NE(NULL, job);
 
   // The function may have already been optimized by OSR.  Simply continue.
@@ -107,35 +196,17 @@
   // The function may have already been optimized by OSR.  Simply continue.
   // Use a mutex to make sure that functions marked for install
   // are always also queued.
+  if (job_based_recompilation_) output_queue_mutex_.Lock();
   output_queue_.Enqueue(job);
+  if (job_based_recompilation_) output_queue_mutex_.Unlock();
   isolate_->stack_guard()->RequestInstallCode();
 }
 
 
-static void DisposeOptimizedCompileJob(OptimizedCompileJob* job,
-                                       bool restore_function_code) {
-  // The recompile job is allocated in the CompilationInfo's zone.
-  CompilationInfo* info = job->info();
-  if (restore_function_code) {
-    if (info->is_osr()) {
-      if (!job->IsWaitingForInstall()) {
-        // Remove stack check that guards OSR entry on original code.
-        Handle<Code> code = info->unoptimized_code();
-        uint32_t offset = code->TranslateAstIdToPcOffset(info->osr_ast_id());
-        BackEdgeTable::RemoveStackCheck(code, offset);
-      }
-    } else {
-      Handle<JSFunction> function = info->closure();
-      function->ReplaceCode(function->shared()->code());
-    }
-  }
-  delete info;
-}
-
-
 void OptimizingCompilerThread::FlushInputQueue(bool restore_function_code) {
   OptimizedCompileJob* job;
   while ((job = NextInput())) {
+    DCHECK(!job_based_recompilation_);
     // This should not block, since we have one signal on the input queue
     // semaphore corresponding to each element in the input queue.
     input_queue_semaphore_.Wait();
@@ -148,6 +219,7 @@
 
 
 void OptimizingCompilerThread::FlushOutputQueue(bool restore_function_code) {
+  base::LockGuard<base::Mutex> access_output_queue_(&output_queue_mutex_);
   OptimizedCompileJob* job;
   while (output_queue_.Dequeue(&job)) {
     // OSR jobs are dealt with separately.
@@ -170,13 +242,23 @@
 
 void OptimizingCompilerThread::Flush() {
   DCHECK(!IsOptimizerThread());
-  base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(FLUSH));
-  if (FLAG_block_concurrent_recompilation) Unblock();
-  input_queue_semaphore_.Signal();
-  stop_semaphore_.Wait();
+  bool block = true;
+  if (job_based_recompilation_) {
+    base::LockGuard<base::RecursiveMutex> lock(&task_count_mutex_);
+    block = task_count_ > 0 || blocked_jobs_ > 0;
+    if (block) {
+      base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(FLUSH));
+    }
+    if (FLAG_block_concurrent_recompilation) Unblock();
+  } else {
+    base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(FLUSH));
+    if (FLAG_block_concurrent_recompilation) Unblock();
+  }
+  if (!job_based_recompilation_) input_queue_semaphore_.Signal();
+  if (block) stop_semaphore_.Wait();
   FlushOutputQueue(true);
   if (FLAG_concurrent_osr) FlushOsrBuffer(true);
-  if (FLAG_trace_concurrent_recompilation) {
+  if (tracing_enabled_) {
     PrintF("  ** Flushed concurrent recompilation queues.\n");
   }
 }
@@ -184,15 +266,25 @@
 
 void OptimizingCompilerThread::Stop() {
   DCHECK(!IsOptimizerThread());
-  base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(STOP));
-  if (FLAG_block_concurrent_recompilation) Unblock();
-  input_queue_semaphore_.Signal();
-  stop_semaphore_.Wait();
+  bool block = true;
+  if (job_based_recompilation_) {
+    base::LockGuard<base::RecursiveMutex> lock(&task_count_mutex_);
+    block = task_count_ > 0 || blocked_jobs_ > 0;
+    if (block) {
+      base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(FLUSH));
+    }
+    if (FLAG_block_concurrent_recompilation) Unblock();
+  } else {
+    base::Release_Store(&stop_thread_, static_cast<base::AtomicWord>(STOP));
+    if (FLAG_block_concurrent_recompilation) Unblock();
+  }
+  if (!job_based_recompilation_) input_queue_semaphore_.Signal();
+  if (block) stop_semaphore_.Wait();
 
-  if (FLAG_concurrent_recompilation_delay != 0) {
+  if (recompilation_delay_ != 0) {
     // At this point the optimizing compiler thread's event loop has stopped.
     // There is no need for a mutex when reading input_queue_length_.
-    while (input_queue_length_ > 0) CompileNext();
+    while (input_queue_length_ > 0) CompileNext(NextInput());
     InstallOptimizedFunctions();
   } else {
     FlushInputQueue(false);
@@ -201,13 +293,13 @@
 
   if (FLAG_concurrent_osr) FlushOsrBuffer(false);
 
-  if (FLAG_trace_concurrent_recompilation) {
+  if (tracing_enabled_) {
     double percentage = time_spent_compiling_.PercentOf(time_spent_total_);
+    if (job_based_recompilation_) percentage = 100.0;
     PrintF("  ** Compiler thread did %.2f%% useful work\n", percentage);
   }
 
-  if ((FLAG_trace_osr || FLAG_trace_concurrent_recompilation) &&
-      FLAG_concurrent_osr) {
+  if ((FLAG_trace_osr || tracing_enabled_) && FLAG_concurrent_osr) {
     PrintF("[COSR hit rate %d / %d]\n", osr_hits_, osr_attempts_);
   }
 
@@ -237,7 +329,7 @@
       BackEdgeTable::RemoveStackCheck(code, offset);
     } else {
       if (function->IsOptimized()) {
-        if (FLAG_trace_concurrent_recompilation) {
+        if (tracing_enabled_) {
           PrintF("  ** Aborting compilation for ");
           function->ShortPrint();
           PrintF(" as it has already been optimized.\n");
@@ -276,6 +368,11 @@
   }
   if (FLAG_block_concurrent_recompilation) {
     blocked_jobs_++;
+  } else if (job_based_recompilation_) {
+    base::LockGuard<base::RecursiveMutex> lock(&task_count_mutex_);
+    ++task_count_;
+    V8::GetCurrentPlatform()->CallOnBackgroundThread(
+        new CompileTask(isolate_), v8::Platform::kShortRunningTask);
   } else {
     input_queue_semaphore_.Signal();
   }
@@ -284,8 +381,17 @@
 
 void OptimizingCompilerThread::Unblock() {
   DCHECK(!IsOptimizerThread());
+  {
+    base::LockGuard<base::RecursiveMutex> lock(&task_count_mutex_);
+    task_count_ += blocked_jobs_;
+  }
   while (blocked_jobs_ > 0) {
-    input_queue_semaphore_.Signal();
+    if (job_based_recompilation_) {
+      V8::GetCurrentPlatform()->CallOnBackgroundThread(
+          new CompileTask(isolate_), v8::Platform::kShortRunningTask);
+    } else {
+      input_queue_semaphore_.Signal();
+    }
     blocked_jobs_--;
   }
 }
diff --git a/src/optimizing-compiler-thread.h b/src/optimizing-compiler-thread.h
index 6ff4f2a..3088843 100644
--- a/src/optimizing-compiler-thread.h
+++ b/src/optimizing-compiler-thread.h
@@ -35,9 +35,13 @@
         input_queue_shift_(0),
         osr_buffer_capacity_(FLAG_concurrent_recompilation_queue_length + 4),
         osr_buffer_cursor_(0),
+        task_count_(0),
         osr_hits_(0),
         osr_attempts_(0),
-        blocked_jobs_(0) {
+        blocked_jobs_(0),
+        tracing_enabled_(FLAG_trace_concurrent_recompilation),
+        job_based_recompilation_(FLAG_job_based_recompilation),
+        recompilation_delay_(FLAG_concurrent_recompilation_delay) {
     base::NoBarrier_Store(&stop_thread_,
                           static_cast<base::AtomicWord>(CONTINUE));
     input_queue_ = NewArray<OptimizedCompileJob*>(input_queue_capacity_);
@@ -84,13 +88,15 @@
 #endif
 
  private:
+  class CompileTask;
+
   enum StopFlag { CONTINUE, STOP, FLUSH };
 
   void FlushInputQueue(bool restore_function_code);
   void FlushOutputQueue(bool restore_function_code);
   void FlushOsrBuffer(bool restore_function_code);
-  void CompileNext();
-  OptimizedCompileJob* NextInput();
+  void CompileNext(OptimizedCompileJob* job);
+  OptimizedCompileJob* NextInput(StopFlag* flag = NULL);
 
   // Add a recompilation task for OSR to the cyclic buffer, awaiting OSR entry.
   // Tasks evicted from the cyclic buffer are discarded.
@@ -121,6 +127,9 @@
 
   // Queue of recompilation tasks ready to be installed (excluding OSR).
   UnboundQueue<OptimizedCompileJob*> output_queue_;
+  // Used for job based recompilation which has multiple producers on
+  // different threads.
+  base::Mutex output_queue_mutex_;
 
   // Cyclic buffer of recompilation tasks for OSR.
   OptimizedCompileJob** osr_buffer_;
@@ -131,10 +140,27 @@
   base::TimeDelta time_spent_compiling_;
   base::TimeDelta time_spent_total_;
 
+  int task_count_;
+  // TODO(jochen): This is currently a RecursiveMutex since both Flush/Stop and
+  // Unblock try to get it, but the former methods both can call Unblock. Once
+  // job based recompilation is on by default, and the dedicated thread can be
+  // removed, this should be refactored to not use a RecursiveMutex.
+  base::RecursiveMutex task_count_mutex_;
+
   int osr_hits_;
   int osr_attempts_;
 
   int blocked_jobs_;
+
+  // Copies of FLAG_trace_concurrent_recompilation,
+  // FLAG_concurrent_recompilation_delay and
+  // FLAG_job_based_recompilation that will be used from the background thread.
+  //
+  // Since flags might get modified while the background thread is running, it
+  // is not safe to access them directly.
+  bool tracing_enabled_;
+  bool job_based_recompilation_;
+  int recompilation_delay_;
 };
 
 } }  // namespace v8::internal
diff --git a/src/ostreams.cc b/src/ostreams.cc
index e927e6b..ee0474d 100644
--- a/src/ostreams.cc
+++ b/src/ostreams.cc
@@ -4,11 +4,6 @@
 
 #include "src/ostreams.h"
 
-#include <algorithm>
-#include <cmath>
-
-#include "src/base/platform/platform.h"  // For isinf/isnan with MSVC
-
 #if V8_OS_WIN
 #define snprintf sprintf_s
 #endif
@@ -16,174 +11,57 @@
 namespace v8 {
 namespace internal {
 
-// Be lazy and delegate the value=>char conversion to snprintf.
-template<class T>
-OStream& OStream::print(const char* format, T x) {
-  char buf[32];
-  int n = snprintf(buf, sizeof(buf), format, x);
-  return (n < 0) ? *this : write(buf, n);
+OFStreamBase::OFStreamBase(FILE* f) : f_(f) {}
+
+
+OFStreamBase::~OFStreamBase() {}
+
+
+OFStreamBase::int_type OFStreamBase::sync() {
+  std::fflush(f_);
+  return 0;
 }
 
 
-OStream& OStream::operator<<(short x) {  // NOLINT(runtime/int)
-  return print(hex_ ? "%hx" : "%hd", x);
+OFStreamBase::int_type OFStreamBase::overflow(int_type c) {
+  return (c != EOF) ? std::fputc(c, f_) : c;
 }
 
 
-OStream& OStream::operator<<(unsigned short x) {  // NOLINT(runtime/int)
-  return print(hex_ ? "%hx" : "%hu", x);
+OFStream::OFStream(FILE* f) : OFStreamBase(f), std::ostream(this) {
+  DCHECK_NOT_NULL(f);
 }
 
 
-OStream& OStream::operator<<(int x) {
-  return print(hex_ ? "%x" : "%d", x);
-}
+OFStream::~OFStream() {}
 
 
-OStream& OStream::operator<<(unsigned int x) {
-  return print(hex_ ? "%x" : "%u", x);
-}
-
-
-OStream& OStream::operator<<(long x) {  // NOLINT(runtime/int)
-  return print(hex_ ? "%lx" : "%ld", x);
-}
-
-
-OStream& OStream::operator<<(unsigned long x) {  // NOLINT(runtime/int)
-  return print(hex_ ? "%lx" : "%lu", x);
-}
-
-
-OStream& OStream::operator<<(long long x) {  // NOLINT(runtime/int)
-  return print(hex_ ? "%llx" : "%lld", x);
-}
-
-
-OStream& OStream::operator<<(unsigned long long x) {  // NOLINT(runtime/int)
-  return print(hex_ ? "%llx" : "%llu", x);
-}
-
-
-OStream& OStream::operator<<(double x) {
-  if (std::isinf(x)) return *this << (x < 0 ? "-inf" : "inf");
-  if (std::isnan(x)) return *this << "nan";
-  return print("%g", x);
-}
-
-
-OStream& OStream::operator<<(void* x) {
-  return print("%p", x);
-}
-
-
-OStream& OStream::operator<<(char x) {
-  return put(x);
-}
-
-
-OStream& OStream::operator<<(signed char x) {
-  return put(x);
-}
-
-
-OStream& OStream::operator<<(unsigned char x) {
-  return put(x);
-}
-
-
-OStream& OStream::dec() {
-  hex_ = false;
-  return *this;
-}
-
-
-OStream& OStream::hex() {
-  hex_ = true;
-  return *this;
-}
-
-
-OStream& flush(OStream& os) {  // NOLINT(runtime/references)
-  return os.flush();
-}
-
-
-OStream& endl(OStream& os) {  // NOLINT(runtime/references)
-  return flush(os.put('\n'));
-}
-
-
-OStream& hex(OStream& os) {  // NOLINT(runtime/references)
-  return os.hex();
-}
-
-
-OStream& dec(OStream& os) {  // NOLINT(runtime/references)
-  return os.dec();
-}
-
-
-OStringStream& OStringStream::write(const char* s, size_t n) {
-  size_t new_size = size_ + n;
-  if (new_size < size_) return *this;  // Overflow => no-op.
-  reserve(new_size + 1);
-  memcpy(data_ + size_, s, n);
-  size_ = new_size;
-  data_[size_] = '\0';
-  return *this;
-}
-
-
-OStringStream& OStringStream::flush() {
-  return *this;
-}
-
-
-void OStringStream::reserve(size_t requested_capacity) {
-  if (requested_capacity <= capacity_) return;
-  size_t new_capacity =  // Handle possible overflow by not doubling.
-      std::max(std::max(capacity_ * 2, capacity_), requested_capacity);
-  char * new_data = allocate(new_capacity);
-  memcpy(new_data, data_, size_);
-  deallocate(data_, capacity_);
-  capacity_ = new_capacity;
-  data_ = new_data;
-}
-
-
-OFStream& OFStream::write(const char* s, size_t n) {
-  if (f_) fwrite(s, n, 1, f_);
-  return *this;
-}
-
-
-OFStream& OFStream::flush() {
-  if (f_) fflush(f_);
-  return *this;
-}
-
+namespace {
 
 // Locale-independent predicates.
-static bool IsPrint(uint16_t c) { return 0x20 <= c && c <= 0x7e; }
-static bool IsSpace(uint16_t c) { return (0x9 <= c && c <= 0xd) || c == 0x20; }
-static bool IsOK(uint16_t c) { return (IsPrint(c) || IsSpace(c)) && c != '\\'; }
+bool IsPrint(uint16_t c) { return 0x20 <= c && c <= 0x7e; }
+bool IsSpace(uint16_t c) { return (0x9 <= c && c <= 0xd) || c == 0x20; }
+bool IsOK(uint16_t c) { return (IsPrint(c) || IsSpace(c)) && c != '\\'; }
 
 
-static OStream& PrintUC16(OStream& os, uint16_t c, bool (*pred)(uint16_t)) {
+std::ostream& PrintUC16(std::ostream& os, uint16_t c, bool (*pred)(uint16_t)) {
   char buf[10];
   const char* format = pred(c) ? "%c" : (c <= 0xff) ? "\\x%02x" : "\\u%04x";
   snprintf(buf, sizeof(buf), format, c);
   return os << buf;
 }
 
+}  // namespace
 
-OStream& operator<<(OStream& os, const AsReversiblyEscapedUC16& c) {
+
+std::ostream& operator<<(std::ostream& os, const AsReversiblyEscapedUC16& c) {
   return PrintUC16(os, c.value, IsOK);
 }
 
 
-OStream& operator<<(OStream& os, const AsUC16& c) {
+std::ostream& operator<<(std::ostream& os, const AsUC16& c) {
   return PrintUC16(os, c.value, IsPrint);
 }
-} }  // namespace v8::internal
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/ostreams.h b/src/ostreams.h
index 508a88d..56787f7 100644
--- a/src/ostreams.h
+++ b/src/ostreams.h
@@ -5,9 +5,11 @@
 #ifndef V8_OSTREAMS_H_
 #define V8_OSTREAMS_H_
 
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
+#include <cstddef>
+#include <cstdio>
+#include <cstring>
+#include <ostream>  // NOLINT
+#include <streambuf>
 
 #include "include/v8config.h"
 #include "src/base/macros.h"
@@ -15,104 +17,28 @@
 namespace v8 {
 namespace internal {
 
-// An abstract base class for output streams with a cut-down standard interface.
-class OStream {
- public:
-  OStream() : hex_(false) { }
-  virtual ~OStream() { }
+class OFStreamBase : public std::streambuf {
+ protected:
+  explicit OFStreamBase(FILE* f);
+  virtual ~OFStreamBase();
 
-  // For manipulators like 'os << endl' or 'os << flush', etc.
-  OStream& operator<<(OStream& (*manipulator)(OStream& os)) {
-    return manipulator(*this);
-  }
-
-  // Numeric conversions.
-  OStream& operator<<(short x);  // NOLINT(runtime/int)
-  OStream& operator<<(unsigned short x);  // NOLINT(runtime/int)
-  OStream& operator<<(int x);
-  OStream& operator<<(unsigned int x);
-  OStream& operator<<(long x);  // NOLINT(runtime/int)
-  OStream& operator<<(unsigned long x);  // NOLINT(runtime/int)
-  OStream& operator<<(long long x);  // NOLINT(runtime/int)
-  OStream& operator<<(unsigned long long x);  // NOLINT(runtime/int)
-  OStream& operator<<(double x);
-  OStream& operator<<(void* x);
-
-  // Character output.
-  OStream& operator<<(char x);
-  OStream& operator<<(signed char x);
-  OStream& operator<<(unsigned char x);
-  OStream& operator<<(const char* s) { return write(s, strlen(s)); }
-  OStream& put(char c) { return write(&c, 1); }
-
-  // Primitive format flag handling, can be extended if needed.
-  OStream& dec();
-  OStream& hex();
-
-  virtual OStream& write(const char* s, size_t n) = 0;
-  virtual OStream& flush() = 0;
-
- private:
-  template<class T> OStream& print(const char* format, T x);
-
-  bool hex_;
-
-  DISALLOW_COPY_AND_ASSIGN(OStream);
-};
-
-
-// Some manipulators.
-OStream& flush(OStream& os);  // NOLINT(runtime/references)
-OStream& endl(OStream& os);  // NOLINT(runtime/references)
-OStream& dec(OStream& os);  // NOLINT(runtime/references)
-OStream& hex(OStream& os);  // NOLINT(runtime/references)
-
-
-// An output stream writing to a character buffer.
-class OStringStream: public OStream {
- public:
-  OStringStream() : size_(0), capacity_(32), data_(allocate(capacity_)) {
-    data_[0] = '\0';
-  }
-  ~OStringStream() { deallocate(data_, capacity_); }
-
-  size_t size() const { return size_; }
-  size_t capacity() const { return capacity_; }
-  const char* data() const { return data_; }
-
-  // Internally, our character data is always 0-terminated.
-  const char* c_str() const { return data(); }
-
-  virtual OStringStream& write(const char* s, size_t n) OVERRIDE;
-  virtual OStringStream& flush() OVERRIDE;
-
- private:
-  // Primitive allocator interface, can be extracted if needed.
-  static char* allocate (size_t n) { return new char[n]; }
-  static void deallocate (char* s, size_t n) { delete[] s; }
-
-  void reserve(size_t requested_capacity);
-
-  size_t size_;
-  size_t capacity_;
-  char* data_;
-
-  DISALLOW_COPY_AND_ASSIGN(OStringStream);
-};
-
-
-// An output stream writing to a file.
-class OFStream: public OStream {
- public:
-  explicit OFStream(FILE* f) : f_(f) { }
-  virtual ~OFStream() { }
-
-  virtual OFStream& write(const char* s, size_t n) OVERRIDE;
-  virtual OFStream& flush() OVERRIDE;
+  int_type sync() FINAL;
+  int_type overflow(int_type c) FINAL;
 
  private:
   FILE* const f_;
 
+  DISALLOW_COPY_AND_ASSIGN(OFStreamBase);
+};
+
+
+// An output stream writing to a file.
+class OFStream FINAL : private virtual OFStreamBase, public std::ostream {
+ public:
+  explicit OFStream(FILE* f);
+  ~OFStream();
+
+ private:
   DISALLOW_COPY_AND_ASSIGN(OFStream);
 };
 
@@ -133,11 +59,13 @@
 // Writes the given character to the output escaping everything outside of
 // printable/space ASCII range. Additionally escapes '\' making escaping
 // reversible.
-OStream& operator<<(OStream& os, const AsReversiblyEscapedUC16& c);
+std::ostream& operator<<(std::ostream& os, const AsReversiblyEscapedUC16& c);
 
 // Writes the given character to the output escaping everything outside
 // of printable ASCII range.
-OStream& operator<<(OStream& os, const AsUC16& c);
-} }  // namespace v8::internal
+std::ostream& operator<<(std::ostream& os, const AsUC16& c);
+
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_OSTREAMS_H_
diff --git a/src/parser.cc b/src/parser.cc
index 7cef210..bfdeaa3 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -15,7 +15,7 @@
 #include "src/messages.h"
 #include "src/parser.h"
 #include "src/preparser.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 #include "src/scanner-character-streams.h"
 #include "src/scopeinfo.h"
 #include "src/string-stream.h"
@@ -111,7 +111,7 @@
   int num_terms = terms_.length();
   RegExpTree* alternative;
   if (num_terms == 0) {
-    alternative = RegExpEmpty::GetInstance();
+    alternative = new (zone()) RegExpEmpty();
   } else if (num_terms == 1) {
     alternative = terms_.last();
   } else {
@@ -126,12 +126,8 @@
 RegExpTree* RegExpBuilder::ToRegExp() {
   FlushTerms();
   int num_alternatives = alternatives_.length();
-  if (num_alternatives == 0) {
-    return RegExpEmpty::GetInstance();
-  }
-  if (num_alternatives == 1) {
-    return alternatives_.last();
-  }
+  if (num_alternatives == 0) return new (zone()) RegExpEmpty();
+  if (num_alternatives == 1) return alternatives_.last();
   return new(zone()) RegExpDisjunction(alternatives_.GetList(zone()));
 }
 
@@ -206,6 +202,7 @@
 
 
 bool ParseData::IsSane() {
+  if (!IsAligned(script_data_->length(), sizeof(unsigned))) return false;
   // Check that the header data is valid and doesn't specify
   // point to positions outside the store.
   int data_length = Length();
@@ -260,7 +257,7 @@
   } else {
     DCHECK(info_->cached_data() != NULL);
     if (compile_options() == ScriptCompiler::kConsumeParserCache) {
-      cached_parse_data_ = new ParseData(*info_->cached_data());
+      cached_parse_data_ = ParseData::FromCachedData(*info_->cached_data());
     }
   }
 }
@@ -275,6 +272,55 @@
 }
 
 
+FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
+                                            int pos, int end_pos) {
+  int materialized_literal_count = -1;
+  int expected_property_count = -1;
+  int handler_count = 0;
+  int parameter_count = 0;
+  const AstRawString* name = ast_value_factory()->empty_string();
+
+  Scope* function_scope = NewScope(scope, FUNCTION_SCOPE);
+  function_scope->SetStrictMode(STRICT);
+  // Set start and end position to the same value
+  function_scope->set_start_position(pos);
+  function_scope->set_end_position(pos);
+  ZoneList<Statement*>* body = NULL;
+
+  {
+    AstNodeFactory function_factory(ast_value_factory());
+    FunctionState function_state(&function_state_, &scope_, function_scope,
+                                 &function_factory);
+
+    body = new (zone()) ZoneList<Statement*>(1, zone());
+    if (call_super) {
+      ZoneList<Expression*>* args =
+          new (zone()) ZoneList<Expression*>(0, zone());
+      CallRuntime* call = factory()->NewCallRuntime(
+          ast_value_factory()->empty_string(),
+          Runtime::FunctionForId(Runtime::kDefaultConstructorSuperCall), args,
+          pos);
+      body->Add(factory()->NewExpressionStatement(call, pos), zone());
+      function_scope->RecordSuperConstructorCallUsage();
+    }
+
+    materialized_literal_count = function_state.materialized_literal_count();
+    expected_property_count = function_state.expected_property_count();
+    handler_count = function_state.handler_count();
+  }
+
+  FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
+      name, ast_value_factory(), function_scope, body,
+      materialized_literal_count, expected_property_count, handler_count,
+      parameter_count, FunctionLiteral::kNoDuplicateParameters,
+      FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kIsFunction,
+      FunctionLiteral::kNotParenthesized, FunctionKind::kDefaultConstructor,
+      pos);
+
+  return function_literal;
+}
+
+
 // ----------------------------------------------------------------------------
 // Target is a support class to facilitate manipulation of the
 // Parser's target_stack_ (the stack of potential 'break' and
@@ -342,25 +388,6 @@
 // ----------------------------------------------------------------------------
 // Implementation of Parser
 
-class ParserTraits::Checkpoint
-    : public ParserBase<ParserTraits>::CheckpointBase {
- public:
-  explicit Checkpoint(ParserBase<ParserTraits>* parser)
-      : CheckpointBase(parser), parser_(parser) {
-    saved_ast_node_id_gen_ = *parser_->ast_node_id_gen_;
-  }
-
-  void Restore() {
-    CheckpointBase::Restore();
-    *parser_->ast_node_id_gen_ = saved_ast_node_id_gen_;
-  }
-
- private:
-  ParserBase<ParserTraits>* parser_;
-  AstNode::IdGen saved_ast_node_id_gen_;
-};
-
-
 bool ParserTraits::IsEvalOrArguments(const AstRawString* identifier) const {
   return identifier == parser_->ast_value_factory()->eval_string() ||
          identifier == parser_->ast_value_factory()->arguments_string();
@@ -433,7 +460,7 @@
 
 bool ParserTraits::ShortcutNumericLiteralBinaryExpression(
     Expression** x, Expression* y, Token::Value op, int pos,
-    AstNodeFactory<AstConstructionVisitor>* factory) {
+    AstNodeFactory* factory) {
   if ((*x)->AsLiteral() && (*x)->AsLiteral()->raw_value()->IsNumber() &&
       y->AsLiteral() && y->AsLiteral()->raw_value()->IsNumber()) {
     double x_val = (*x)->AsLiteral()->raw_value()->AsNumber();
@@ -491,9 +518,9 @@
 }
 
 
-Expression* ParserTraits::BuildUnaryExpression(
-    Expression* expression, Token::Value op, int pos,
-    AstNodeFactory<AstConstructionVisitor>* factory) {
+Expression* ParserTraits::BuildUnaryExpression(Expression* expression,
+                                               Token::Value op, int pos,
+                                               AstNodeFactory* factory) {
   DCHECK(expression != NULL);
   if (expression->IsLiteral()) {
     const AstValue* literal = expression->AsLiteral()->raw_value();
@@ -538,7 +565,7 @@
 Expression* ParserTraits::NewThrowReferenceError(const char* message, int pos) {
   return NewThrowError(
       parser_->ast_value_factory()->make_reference_error_string(), message,
-      NULL, pos);
+      parser_->ast_value_factory()->empty_string(), pos);
 }
 
 
@@ -560,17 +587,11 @@
     const AstRawString* constructor, const char* message,
     const AstRawString* arg, int pos) {
   Zone* zone = parser_->zone();
-  int argc = arg != NULL ? 1 : 0;
   const AstRawString* type =
       parser_->ast_value_factory()->GetOneByteString(message);
-  ZoneList<const AstRawString*>* array =
-      new (zone) ZoneList<const AstRawString*>(argc, zone);
-  if (arg != NULL) {
-    array->Add(arg, zone);
-  }
   ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(2, zone);
   args->Add(parser_->factory()->NewStringLiteral(type, pos), zone);
-  args->Add(parser_->factory()->NewStringListLiteral(array, pos), zone);
+  args->Add(parser_->factory()->NewStringLiteral(arg, pos), zone);
   CallRuntime* call_constructor =
       parser_->factory()->NewCallRuntime(constructor, NULL, args, pos);
   return parser_->factory()->NewThrow(call_constructor, pos);
@@ -653,29 +674,28 @@
 }
 
 
-Expression* ParserTraits::ThisExpression(
-    Scope* scope, AstNodeFactory<AstConstructionVisitor>* factory, int pos) {
+Expression* ParserTraits::ThisExpression(Scope* scope, AstNodeFactory* factory,
+                                         int pos) {
   return factory->NewVariableProxy(scope->receiver(), pos);
 }
 
-Expression* ParserTraits::SuperReference(
-    Scope* scope, AstNodeFactory<AstConstructionVisitor>* factory, int pos) {
+Expression* ParserTraits::SuperReference(Scope* scope, AstNodeFactory* factory,
+                                         int pos) {
   return factory->NewSuperReference(
       ThisExpression(scope, factory, pos)->AsVariableProxy(),
       pos);
 }
 
-Expression* ParserTraits::ClassLiteral(
-    const AstRawString* name, Expression* extends, Expression* constructor,
-    ZoneList<ObjectLiteral::Property*>* properties, int pos,
-    AstNodeFactory<AstConstructionVisitor>* factory) {
-  return factory->NewClassLiteral(name, extends, constructor, properties, pos);
+
+Expression* ParserTraits::DefaultConstructor(bool call_super, Scope* scope,
+                                             int pos, int end_pos) {
+  return parser_->DefaultConstructor(call_super, scope, pos, end_pos);
 }
 
-Literal* ParserTraits::ExpressionFromLiteral(
-    Token::Value token, int pos,
-    Scanner* scanner,
-    AstNodeFactory<AstConstructionVisitor>* factory) {
+
+Literal* ParserTraits::ExpressionFromLiteral(Token::Value token, int pos,
+                                             Scanner* scanner,
+                                             AstNodeFactory* factory) {
   switch (token) {
     case Token::NULL_LITERAL:
       return factory->NewNullLiteral(pos);
@@ -694,9 +714,9 @@
 }
 
 
-Expression* ParserTraits::ExpressionFromIdentifier(
-    const AstRawString* name, int pos, Scope* scope,
-    AstNodeFactory<AstConstructionVisitor>* factory) {
+Expression* ParserTraits::ExpressionFromIdentifier(const AstRawString* name,
+                                                   int pos, Scope* scope,
+                                                   AstNodeFactory* factory) {
   if (parser_->fni_ != NULL) parser_->fni_->PushVariableName(name);
   // The name may refer to a module instance object, so its type is unknown.
 #ifdef DEBUG
@@ -708,19 +728,18 @@
 }
 
 
-Expression* ParserTraits::ExpressionFromString(
-    int pos, Scanner* scanner,
-    AstNodeFactory<AstConstructionVisitor>* factory) {
+Expression* ParserTraits::ExpressionFromString(int pos, Scanner* scanner,
+                                               AstNodeFactory* factory) {
   const AstRawString* symbol = GetSymbol(scanner);
   if (parser_->fni_ != NULL) parser_->fni_->PushLiteralName(symbol);
   return factory->NewStringLiteral(symbol, pos);
 }
 
 
-Expression* ParserTraits::GetIterator(
-    Expression* iterable, AstNodeFactory<AstConstructionVisitor>* factory) {
+Expression* ParserTraits::GetIterator(Expression* iterable,
+                                      AstNodeFactory* factory) {
   Expression* iterator_symbol_literal =
-      factory->NewSymbolLiteral("symbolIterator", RelocInfo::kNoPosition);
+      factory->NewSymbolLiteral("iterator_symbol", RelocInfo::kNoPosition);
   int pos = iterable->position();
   Expression* prop =
       factory->NewProperty(iterable, iterator_symbol_literal, pos);
@@ -730,8 +749,8 @@
 }
 
 
-Literal* ParserTraits::GetLiteralTheHole(
-    int position, AstNodeFactory<AstConstructionVisitor>* factory) {
+Literal* ParserTraits::GetLiteralTheHole(int position,
+                                         AstNodeFactory* factory) {
   return factory->NewTheHoleLiteral(RelocInfo::kNoPosition);
 }
 
@@ -752,10 +771,17 @@
 }
 
 
+ClassLiteral* ParserTraits::ParseClassLiteral(
+    const AstRawString* name, Scanner::Location class_name_location,
+    bool name_is_strict_reserved, int pos, bool* ok) {
+  return parser_->ParseClassLiteral(name, class_name_location,
+                                    name_is_strict_reserved, pos, ok);
+}
+
+
 Parser::Parser(CompilationInfo* info, ParseInfo* parse_info)
     : ParserBase<ParserTraits>(&scanner_, parse_info->stack_limit,
-                               info->extension(), NULL, info->zone(),
-                               info->ast_node_id_gen(), this),
+                               info->extension(), NULL, info->zone(), this),
       scanner_(parse_info->unicode_cache),
       reusable_preparser_(NULL),
       original_scope_(NULL),
@@ -769,14 +795,17 @@
       total_preparse_skipped_(0),
       pre_parse_timer_(NULL) {
   DCHECK(!script().is_null() || info->source_stream() != NULL);
-  set_allow_harmony_scoping(!info->is_native() && FLAG_harmony_scoping);
-  set_allow_modules(!info->is_native() && FLAG_harmony_modules);
-  set_allow_natives_syntax(FLAG_allow_natives_syntax || info->is_native());
   set_allow_lazy(false);  // Must be explicitly enabled.
-  set_allow_arrow_functions(FLAG_harmony_arrow_functions);
+  set_allow_natives(FLAG_allow_natives_syntax || info->is_native());
+  set_allow_harmony_scoping(!info->is_native() && FLAG_harmony_scoping);
+  set_allow_harmony_modules(!info->is_native() && FLAG_harmony_modules);
+  set_allow_harmony_arrow_functions(FLAG_harmony_arrow_functions);
   set_allow_harmony_numeric_literals(FLAG_harmony_numeric_literals);
-  set_allow_classes(FLAG_harmony_classes);
+  set_allow_harmony_classes(FLAG_harmony_classes);
   set_allow_harmony_object_literals(FLAG_harmony_object_literals);
+  set_allow_harmony_templates(FLAG_harmony_templates);
+  set_allow_harmony_sloppy(FLAG_harmony_sloppy);
+  set_allow_harmony_unicode(FLAG_harmony_unicode);
   for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
        ++feature) {
     use_counts_[feature] = 0;
@@ -807,9 +836,9 @@
   // Initialize parser state.
   CompleteParserRecorder recorder;
 
-  if (compile_options() == ScriptCompiler::kProduceParserCache) {
+  if (produce_cached_parse_data()) {
     log_ = &recorder;
-  } else if (compile_options() == ScriptCompiler::kConsumeParserCache) {
+  } else if (consume_cached_parse_data()) {
     cached_parse_data_->Initialize();
   }
 
@@ -850,7 +879,7 @@
     }
     PrintF(" - took %0.3f ms]\n", ms);
   }
-  if (compile_options() == ScriptCompiler::kProduceParserCache) {
+  if (produce_cached_parse_data()) {
     if (result != NULL) *info_->cached_data() = recorder.GetScriptData();
     log_ = NULL;
   }
@@ -865,8 +894,8 @@
 
   FunctionLiteral* result = NULL;
   {
-    *scope = NewScope(scope_, GLOBAL_SCOPE);
-    info->SetGlobalScope(*scope);
+    *scope = NewScope(scope_, SCRIPT_SCOPE);
+    info->SetScriptScope(*scope);
     if (!info->context().is_null() && !info->context()->IsNativeContext()) {
       *scope = Scope::DeserializeScopeChain(*info->context(), *scope, zone());
       // The Scope is backed up by ScopeInfo (which is in the V8 heap); this
@@ -877,26 +906,27 @@
     }
     original_scope_ = *scope;
     if (info->is_eval()) {
-      if (!(*scope)->is_global_scope() || info->strict_mode() == STRICT) {
+      if (!(*scope)->is_script_scope() || info->strict_mode() == STRICT) {
         *scope = NewScope(*scope, EVAL_SCOPE);
       }
     } else if (info->is_global()) {
-      *scope = NewScope(*scope, GLOBAL_SCOPE);
+      *scope = NewScope(*scope, SCRIPT_SCOPE);
     }
     (*scope)->set_start_position(0);
     // End position will be set by the caller.
 
     // Compute the parsing mode.
     Mode mode = (FLAG_lazy && allow_lazy()) ? PARSE_LAZILY : PARSE_EAGERLY;
-    if (allow_natives_syntax() || extension_ != NULL ||
+    if (allow_natives() || extension_ != NULL ||
         (*scope)->is_eval_scope()) {
       mode = PARSE_EAGERLY;
     }
     ParsingModeScope parsing_mode(this, mode);
 
     // Enters 'scope'.
-    FunctionState function_state(&function_state_, &scope_, *scope, zone(),
-                                 ast_value_factory(), info->ast_node_id_gen());
+    AstNodeFactory function_factory(ast_value_factory());
+    FunctionState function_state(&function_state_, &scope_, *scope,
+                                 &function_factory);
 
     scope_->SetStrictMode(info->strict_mode());
     ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
@@ -906,7 +936,7 @@
                         &ok);
 
     if (ok && strict_mode() == STRICT) {
-      CheckOctalLiteral(beg_pos, scanner()->location().end_pos, &ok);
+      CheckStrictOctalLiteral(beg_pos, scanner()->location().end_pos, &ok);
     }
 
     if (ok && allow_harmony_scoping() && strict_mode() == STRICT) {
@@ -932,9 +962,6 @@
           FunctionLiteral::kNoDuplicateParameters,
           FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kGlobalOrEval,
           FunctionLiteral::kNotParenthesized, FunctionKind::kNormalFunction, 0);
-      result->set_ast_properties(factory()->visitor()->ast_properties());
-      result->set_dont_optimize_reason(
-          factory()->visitor()->dont_optimize_reason());
     }
   }
 
@@ -1001,16 +1028,16 @@
 
   {
     // Parse the function literal.
-    Scope* scope = NewScope(scope_, GLOBAL_SCOPE);
-    info()->SetGlobalScope(scope);
+    Scope* scope = NewScope(scope_, SCRIPT_SCOPE);
+    info()->SetScriptScope(scope);
     if (!info()->closure().is_null()) {
       scope = Scope::DeserializeScopeChain(info()->closure()->context(), scope,
                                            zone());
     }
     original_scope_ = scope;
-    FunctionState function_state(&function_state_, &scope_, scope, zone(),
-                                 ast_value_factory(),
-                                 info()->ast_node_id_gen());
+    AstNodeFactory function_factory(ast_value_factory());
+    FunctionState function_state(&function_state_, &scope_, scope,
+                                 &function_factory);
     DCHECK(scope->strict_mode() == SLOPPY || info()->strict_mode() == STRICT);
     DCHECK(info()->strict_mode() == shared_info->strict_mode());
     scope->SetStrictMode(shared_info->strict_mode());
@@ -1025,6 +1052,10 @@
       Expression* expression = ParseExpression(false, &ok);
       DCHECK(expression->IsFunctionLiteral());
       result = expression->AsFunctionLiteral();
+    } else if (shared_info->is_default_constructor()) {
+      result = DefaultConstructor(shared_info->uses_super_constructor_call(),
+                                  scope, shared_info->start_position(),
+                                  shared_info->end_position());
     } else {
       result = ParseFunctionLiteral(raw_name, Scanner::Location::invalid(),
                                     false,  // Strict mode name already checked.
@@ -1100,7 +1131,7 @@
           // all over the code base, so we go with a quick-fix for now.
           // In the same manner, we have to patch the parsing mode.
           if (is_eval && !scope_->is_eval_scope()) {
-            DCHECK(scope_->is_global_scope());
+            DCHECK(scope_->is_script_scope());
             Scope* scope = NewScope(scope_, EVAL_SCOPE);
             scope->set_start_position(scope_->start_position());
             scope->set_end_position(scope_->end_position());
@@ -1734,14 +1765,9 @@
       declaration_scope->is_strict_eval_scope() ||
       declaration_scope->is_block_scope() ||
       declaration_scope->is_module_scope() ||
-      declaration_scope->is_global_scope()) {
+      declaration_scope->is_script_scope()) {
     // Declare the variable in the declaration scope.
-    // For the global scope, we have to check for collisions with earlier
-    // (i.e., enclosing) global scopes, to maintain the illusion of a single
-    // global scope.
-    var = declaration_scope->is_global_scope()
-        ? declaration_scope->Lookup(name)
-        : declaration_scope->LookupLocal(name);
+    var = declaration_scope->LookupLocal(name);
     if (var == NULL) {
       // Declare the name.
       var = declaration_scope->DeclareLocal(name, mode,
@@ -1749,10 +1775,10 @@
                                             kNotAssigned, proxy->interface());
     } else if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(var->mode())
                || ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) &&
-                   !declaration_scope->is_global_scope())) {
+                   !declaration_scope->is_script_scope())) {
       // The name was declared in this scope before; check for conflicting
       // re-declarations. We have a conflict if either of the declarations is
-      // not a var (in the global scope, we also have to ignore legacy const for
+      // not a var (in script scope, we also have to ignore legacy const for
       // compatibility). There is similar code in runtime.cc in the Declare
       // functions. The function CheckConflictingVarDeclarations checks for
       // var and let bindings from different scopes whereas this is a check for
@@ -1797,7 +1823,7 @@
   // RuntimeHidden_DeclareLookupSlot calls.
   declaration_scope->AddDeclaration(declaration);
 
-  if (mode == CONST_LEGACY && declaration_scope->is_global_scope()) {
+  if (mode == CONST_LEGACY && declaration_scope->is_script_scope()) {
     // For global const variables we bind the proxy to a variable.
     DCHECK(resolve);  // should be set by all callers
     Variable::Kind kind = Variable::NORMAL;
@@ -1936,11 +1962,11 @@
   // Even if we're not at the top-level of the global or a function
   // scope, we treat it as such and introduce the function with its
   // initial value upon entering the corresponding scope.
-  // In ES6, a function behaves as a lexical binding, except in the
-  // global scope, or the initial scope of eval or another function.
+  // In ES6, a function behaves as a lexical binding, except in
+  // a script scope, or the initial scope of eval or another function.
   VariableMode mode =
       allow_harmony_scoping() && strict_mode() == STRICT &&
-      !(scope_->is_global_scope() || scope_->is_eval_scope() ||
+      !(scope_->is_script_scope() || scope_->is_eval_scope() ||
           scope_->is_function_scope()) ? LET : VAR;
   VariableProxy* proxy = NewUnresolved(name, mode, Interface::NewValue());
   Declaration* declaration =
@@ -1967,28 +1993,31 @@
   // so rewrite it as such.
 
   Expect(Token::CLASS, CHECK_OK);
+  if (!allow_harmony_sloppy() && strict_mode() == SLOPPY) {
+    ReportMessage("sloppy_lexical");
+    *ok = false;
+    return NULL;
+  }
+
   int pos = position();
   bool is_strict_reserved = false;
   const AstRawString* name =
       ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
-  Expression* value = ParseClassLiteral(name, scanner()->location(),
-                                        is_strict_reserved, pos, CHECK_OK);
+  ClassLiteral* value = ParseClassLiteral(name, scanner()->location(),
+                                          is_strict_reserved, pos, CHECK_OK);
 
-  Block* block = factory()->NewBlock(NULL, 1, true, pos);
-  VariableMode mode = LET;
-  VariableProxy* proxy = NewUnresolved(name, mode, Interface::NewValue());
+  VariableProxy* proxy = NewUnresolved(name, LET, Interface::NewValue());
   Declaration* declaration =
-      factory()->NewVariableDeclaration(proxy, mode, scope_, pos);
+      factory()->NewVariableDeclaration(proxy, LET, scope_, pos);
   Declare(declaration, true, CHECK_OK);
+  proxy->var()->set_initializer_position(pos);
 
   Token::Value init_op = Token::INIT_LET;
   Assignment* assignment = factory()->NewAssignment(init_op, proxy, value, pos);
-  block->AddStatement(
-      factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
-      zone());
-
+  Statement* assignment_statement =
+      factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
   if (names) names->Add(name, zone());
-  return block;
+  return assignment_statement;
 }
 
 
@@ -2174,6 +2203,7 @@
   Block* block = factory()->NewBlock(NULL, 1, true, pos);
   int nvars = 0;  // the number of variables declared
   const AstRawString* name = NULL;
+  bool is_for_iteration_variable;
   do {
     if (fni_ != NULL) fni_->Enter();
 
@@ -2197,6 +2227,13 @@
     // For let/const declarations in harmony mode, we can also immediately
     // pre-resolve the proxy because it resides in the same scope as the
     // declaration.
+    is_for_iteration_variable =
+        var_context == kForStatement &&
+        (peek() == Token::IN || PeekContextualKeyword(CStrVector("of")));
+    if (is_for_iteration_variable && mode == CONST) {
+      needs_init = false;
+    }
+
     Interface* interface =
         is_const ? Interface::NewConst() : Interface::NewValue();
     VariableProxy* proxy = NewUnresolved(name, mode, interface);
@@ -2242,7 +2279,8 @@
     Expression* value = NULL;
     int pos = -1;
     // Harmony consts have non-optional initializers.
-    if (peek() == Token::ASSIGN || mode == CONST) {
+    if (peek() == Token::ASSIGN ||
+        (mode == CONST && !is_for_iteration_variable)) {
       Expect(Token::ASSIGN, CHECK_OK);
       pos = position();
       value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
@@ -2258,7 +2296,7 @@
     }
 
     // Record the end position of the initializer.
-    if (proxy->var() != NULL) {
+    if (proxy->is_resolved()) {
       proxy->var()->set_initializer_position(position());
     }
 
@@ -2285,7 +2323,7 @@
     // declaration statement has been executed. This is important in
     // browsers where the global object (window) has lots of
     // properties defined in prototype objects.
-    if (initialization_scope->is_global_scope() &&
+    if (initialization_scope->is_script_scope() &&
         !IsLexicalVariableMode(mode)) {
       // Compute the arguments for the runtime call.
       ZoneList<Expression*>* arguments =
@@ -2375,7 +2413,7 @@
 
   // If there was a single non-const declaration, return it in the output
   // parameter for possible use by for/in.
-  if (nvars == 1 && !is_const) {
+  if (nvars == 1 && (!is_const || is_for_iteration_variable)) {
     *out = name;
   }
 
@@ -2448,12 +2486,20 @@
 
   // Parsed expression statement, or the context-sensitive 'module' keyword.
   // Only expect semicolon in the former case.
+  // Also detect attempts at 'let' declarations in sloppy mode.
   if (!FLAG_harmony_modules || peek() != Token::IDENTIFIER ||
       scanner()->HasAnyLineTerminatorBeforeNext() ||
       expr->AsVariableProxy() == NULL ||
       expr->AsVariableProxy()->raw_name() !=
           ast_value_factory()->module_string() ||
       scanner()->literal_contains_escapes()) {
+    if (peek() == Token::IDENTIFIER && expr->AsVariableProxy() != NULL &&
+        expr->AsVariableProxy()->raw_name() ==
+            ast_value_factory()->let_string()) {
+      ReportMessage("sloppy_lexical", NULL);
+      *ok = false;
+      return NULL;
+    }
     ExpectSemicolon(CHECK_OK);
   }
   return factory()->NewExpressionStatement(expr, pos);
@@ -2582,7 +2628,7 @@
   }
 
   Scope* decl_scope = scope_->DeclarationScope();
-  if (decl_scope->is_global_scope() || decl_scope->is_eval_scope()) {
+  if (decl_scope->is_script_scope() || decl_scope->is_eval_scope()) {
     ReportMessageAt(loc, "illegal_return");
     *ok = false;
     return NULL;
@@ -2750,9 +2796,7 @@
     Expect(Token::RPAREN, CHECK_OK);
 
     Target target(&this->target_stack_, &catch_collector);
-    VariableMode mode =
-        allow_harmony_scoping() && strict_mode() == STRICT ? LET : VAR;
-    catch_variable = catch_scope->DeclareLocal(name, mode, kCreatedInitialized);
+    catch_variable = catch_scope->DeclareLocal(name, VAR, kCreatedInitialized);
     BlockState block_state(&scope_, catch_scope);
     catch_block = ParseBlock(NULL, CHECK_OK);
 
@@ -2886,7 +2930,7 @@
     // var iterator = subject[Symbol.iterator]();
     assign_iterator = factory()->NewAssignment(
         Token::ASSIGN, factory()->NewVariableProxy(iterator),
-        GetIterator(subject, factory()), RelocInfo::kNoPosition);
+        GetIterator(subject, factory()), subject->position());
 
     // var result = iterator.next();
     {
@@ -2897,11 +2941,11 @@
           iterator_proxy, next_literal, RelocInfo::kNoPosition);
       ZoneList<Expression*>* next_arguments =
           new(zone()) ZoneList<Expression*>(0, zone());
-      Expression* next_call = factory()->NewCall(
-          next_property, next_arguments, RelocInfo::kNoPosition);
+      Expression* next_call = factory()->NewCall(next_property, next_arguments,
+                                                 subject->position());
       Expression* result_proxy = factory()->NewVariableProxy(result);
-      next_result = factory()->NewAssignment(
-          Token::ASSIGN, result_proxy, next_call, RelocInfo::kNoPosition);
+      next_result = factory()->NewAssignment(Token::ASSIGN, result_proxy,
+                                             next_call, subject->position());
     }
 
     // result.done
@@ -2920,8 +2964,8 @@
       Expression* result_proxy = factory()->NewVariableProxy(result);
       Expression* result_value = factory()->NewProperty(
           result_proxy, value_literal, RelocInfo::kNoPosition);
-      assign_each = factory()->NewAssignment(
-          Token::ASSIGN, each, result_value, RelocInfo::kNoPosition);
+      assign_each = factory()->NewAssignment(Token::ASSIGN, each, result_value,
+                                             each->position());
     }
 
     for_of->Initialize(each, subject, body,
@@ -2946,29 +2990,33 @@
   //
   // We rewrite a for statement of the form
   //
-  //  for (let x = i; cond; next) body
+  //  labels: for (let x = i; cond; next) body
   //
   // into
   //
   //  {
-  //     let x = i;
-  //     temp_x = x;
-  //     flag = 1;
-  //     for (;;) {
-  //        let x = temp_x;
-  //        if (flag == 1) {
-  //          flag = 0;
-  //        } else {
-  //          next;
-  //        }
+  //    let x = i;
+  //    temp_x = x;
+  //    first = 1;
+  //    outer: for (;;) {
+  //      let x = temp_x;
+  //      if (first == 1) {
+  //        first = 0;
+  //      } else {
+  //        next;
+  //      }
+  //      flag = 1;
+  //      labels: for (; flag == 1; flag = 0, temp_x = x) {
   //        if (cond) {
-  //          <empty>
+  //          body
   //        } else {
-  //          break;
+  //          break outer;
   //        }
-  //        b
-  //        temp_x = x;
-  //     }
+  //      }
+  //      if (flag == 1) {
+  //        break;
+  //      }
+  //    }
   //  }
 
   DCHECK(names->length() > 0);
@@ -2977,6 +3025,8 @@
 
   Block* outer_block = factory()->NewBlock(NULL, names->length() + 3, false,
                                            RelocInfo::kNoPosition);
+
+  // Add statement: let x = i.
   outer_block->AddStatement(init, zone());
 
   const AstRawString* temp_name = ast_value_factory()->dot_for_string();
@@ -2996,24 +3046,33 @@
     temps.Add(temp, zone());
   }
 
-  Variable* flag = scope_->DeclarationScope()->NewTemporary(temp_name);
-  // Make statement: flag = 1.
-  {
-    VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+  Variable* first = NULL;
+  // Make statement: first = 1.
+  if (next) {
+    first = scope_->DeclarationScope()->NewTemporary(temp_name);
+    VariableProxy* first_proxy = factory()->NewVariableProxy(first);
     Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
     Assignment* assignment = factory()->NewAssignment(
-        Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition);
-    Statement* assignment_statement = factory()->NewExpressionStatement(
-        assignment, RelocInfo::kNoPosition);
+        Token::ASSIGN, first_proxy, const1, RelocInfo::kNoPosition);
+    Statement* assignment_statement =
+        factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
     outer_block->AddStatement(assignment_statement, zone());
   }
 
-  outer_block->AddStatement(loop, zone());
+  // Make statement: outer: for (;;)
+  // Note that we don't actually create the label, or set this loop up as an
+  // explicit break target, instead handing it directly to those nodes that
+  // need to know about it. This should be safe because we don't run any code
+  // in this function that looks up break targets.
+  ForStatement* outer_loop =
+      factory()->NewForStatement(NULL, RelocInfo::kNoPosition);
+  outer_block->AddStatement(outer_loop, zone());
+
   outer_block->set_scope(for_scope);
   scope_ = inner_scope;
 
-  Block* inner_block = factory()->NewBlock(NULL, 2 * names->length() + 3,
-                                           false, RelocInfo::kNoPosition);
+  Block* inner_block = factory()->NewBlock(NULL, names->length() + 4, false,
+                                           RelocInfo::kNoPosition);
   int pos = scanner()->location().beg_pos;
   ZoneList<Variable*> inner_vars(names->length(), zone());
 
@@ -3035,61 +3094,118 @@
     inner_block->AddStatement(assignment_statement, zone());
   }
 
-  // Make statement: if (flag == 1) { flag = 0; } else { next; }.
+  // Make statement: if (first == 1) { first = 0; } else { next; }
   if (next) {
+    DCHECK(first);
+    Expression* compare = NULL;
+    // Make compare expression: first == 1.
+    {
+      Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+      VariableProxy* first_proxy = factory()->NewVariableProxy(first);
+      compare =
+          factory()->NewCompareOperation(Token::EQ, first_proxy, const1, pos);
+    }
+    Statement* clear_first = NULL;
+    // Make statement: first = 0.
+    {
+      VariableProxy* first_proxy = factory()->NewVariableProxy(first);
+      Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
+      Assignment* assignment = factory()->NewAssignment(
+          Token::ASSIGN, first_proxy, const0, RelocInfo::kNoPosition);
+      clear_first =
+          factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+    }
+    Statement* clear_first_or_next = factory()->NewIfStatement(
+        compare, clear_first, next, RelocInfo::kNoPosition);
+    inner_block->AddStatement(clear_first_or_next, zone());
+  }
+
+  Variable* flag = scope_->DeclarationScope()->NewTemporary(temp_name);
+  // Make statement: flag = 1.
+  {
+    VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+    Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+    Assignment* assignment = factory()->NewAssignment(
+        Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition);
+    Statement* assignment_statement =
+        factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+    inner_block->AddStatement(assignment_statement, zone());
+  }
+
+  // Make cond expression for main loop: flag == 1.
+  Expression* flag_cond = NULL;
+  {
+    Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+    VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+    flag_cond =
+        factory()->NewCompareOperation(Token::EQ, flag_proxy, const1, pos);
+  }
+
+  // Create chain of expressions "flag = 0, temp_x = x, ..."
+  Statement* compound_next_statement = NULL;
+  {
+    Expression* compound_next = NULL;
+    // Make expression: flag = 0.
+    {
+      VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+      Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
+      compound_next = factory()->NewAssignment(Token::ASSIGN, flag_proxy,
+                                               const0, RelocInfo::kNoPosition);
+    }
+
+    // Make the comma-separated list of temp_x = x assignments.
+    for (int i = 0; i < names->length(); i++) {
+      VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
+      VariableProxy* proxy = factory()->NewVariableProxy(inner_vars.at(i), pos);
+      Assignment* assignment = factory()->NewAssignment(
+          Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
+      compound_next = factory()->NewBinaryOperation(
+          Token::COMMA, compound_next, assignment, RelocInfo::kNoPosition);
+    }
+
+    compound_next_statement = factory()->NewExpressionStatement(
+        compound_next, RelocInfo::kNoPosition);
+  }
+
+  // Make statement: if (cond) { body; } else { break outer; }
+  Statement* body_or_stop = body;
+  if (cond) {
+    Statement* stop =
+        factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
+    body_or_stop =
+        factory()->NewIfStatement(cond, body, stop, cond->position());
+  }
+
+  // Make statement: labels: for (; flag == 1; flag = 0, temp_x = x)
+  // Note that we re-use the original loop node, which retains it labels
+  // and ensures that any break or continue statements in body point to
+  // the right place.
+  loop->Initialize(NULL, flag_cond, compound_next_statement, body_or_stop);
+  inner_block->AddStatement(loop, zone());
+
+  // Make statement: if (flag == 1) { break; }
+  {
     Expression* compare = NULL;
     // Make compare expresion: flag == 1.
     {
       Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
       VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
-      compare = factory()->NewCompareOperation(
-          Token::EQ, flag_proxy, const1, pos);
+      compare =
+          factory()->NewCompareOperation(Token::EQ, flag_proxy, const1, pos);
     }
-    Statement* clear_flag = NULL;
-    // Make statement: flag = 0.
-    {
-      VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
-      Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
-      Assignment* assignment = factory()->NewAssignment(
-          Token::ASSIGN, flag_proxy, const0, RelocInfo::kNoPosition);
-      clear_flag = factory()->NewExpressionStatement(assignment, pos);
-    }
-    Statement* clear_flag_or_next = factory()->NewIfStatement(
-        compare, clear_flag, next, RelocInfo::kNoPosition);
-    inner_block->AddStatement(clear_flag_or_next, zone());
-  }
-
-
-  // Make statement: if (cond) { } else { break; }.
-  if (cond) {
+    Statement* stop =
+        factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
     Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
-    BreakableStatement* t = LookupBreakTarget(NULL, CHECK_OK);
-    Statement* stop = factory()->NewBreakStatement(t, RelocInfo::kNoPosition);
-    Statement* if_not_cond_break = factory()->NewIfStatement(
-        cond, empty, stop, cond->position());
-    inner_block->AddStatement(if_not_cond_break, zone());
-  }
-
-  inner_block->AddStatement(body, zone());
-
-  // For each let variable x:
-  //   make statement: temp_x = x;
-  for (int i = 0; i < names->length(); i++) {
-    VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
-    int pos = scanner()->location().end_pos;
-    VariableProxy* proxy = factory()->NewVariableProxy(inner_vars.at(i), pos);
-    Assignment* assignment = factory()->NewAssignment(
-        Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
-    Statement* assignment_statement = factory()->NewExpressionStatement(
-        assignment, RelocInfo::kNoPosition);
-    inner_block->AddStatement(assignment_statement, zone());
+    Statement* if_flag_break =
+        factory()->NewIfStatement(compare, stop, empty, RelocInfo::kNoPosition);
+    inner_block->AddStatement(if_flag_break, zone());
   }
 
   inner_scope->set_end_position(scanner()->location().end_pos);
   inner_block->set_scope(inner_scope);
   scope_ = for_scope;
 
-  loop->Initialize(NULL, NULL, NULL, inner_block);
+  outer_loop->Initialize(NULL, NULL, NULL, inner_block);
   return outer_block;
 }
 
@@ -3099,7 +3215,7 @@
   // ForStatement ::
   //   'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
 
-  int pos = peek_position();
+  int stmt_pos = peek_position();
   Statement* init = NULL;
   ZoneList<const AstRawString*> let_bindings(1, zone());
 
@@ -3111,8 +3227,10 @@
   Expect(Token::FOR, CHECK_OK);
   Expect(Token::LPAREN, CHECK_OK);
   for_scope->set_start_position(scanner()->location().beg_pos);
+  bool is_let_identifier_expression = false;
   if (peek() != Token::SEMICOLON) {
-    if (peek() == Token::VAR || peek() == Token::CONST) {
+    if (peek() == Token::VAR ||
+        (peek() == Token::CONST && strict_mode() == SLOPPY)) {
       bool is_const = peek() == Token::CONST;
       const AstRawString* name = NULL;
       VariableDeclarationProperties decl_props = kHasNoInitializers;
@@ -3121,19 +3239,20 @@
                                     CHECK_OK);
       bool accept_OF = decl_props == kHasNoInitializers;
       ForEachStatement::VisitMode mode;
+      int each_pos = position();
 
       if (name != NULL && CheckInOrOf(accept_OF, &mode)) {
         Interface* interface =
             is_const ? Interface::NewConst() : Interface::NewValue();
         ForEachStatement* loop =
-            factory()->NewForEachStatement(mode, labels, pos);
+            factory()->NewForEachStatement(mode, labels, stmt_pos);
         Target target(&this->target_stack_, loop);
 
         Expression* enumerable = ParseExpression(true, CHECK_OK);
         Expect(Token::RPAREN, CHECK_OK);
 
         VariableProxy* each =
-            scope_->NewUnresolved(factory(), name, interface);
+            scope_->NewUnresolved(factory(), name, interface, each_pos);
         Statement* body = ParseStatement(NULL, CHECK_OK);
         InitializeForEachStatement(loop, each, enumerable, body);
         Block* result =
@@ -3149,8 +3268,9 @@
       } else {
         init = variable_statement;
       }
-    } else if (peek() == Token::LET && strict_mode() == STRICT) {
-      DCHECK(allow_harmony_scoping());
+    } else if ((peek() == Token::LET || peek() == Token::CONST) &&
+               strict_mode() == STRICT) {
+      bool is_const = peek() == Token::CONST;
       const AstRawString* name = NULL;
       VariableDeclarationProperties decl_props = kHasNoInitializers;
       Block* variable_statement =
@@ -3159,17 +3279,18 @@
       bool accept_IN = name != NULL && decl_props != kHasInitializers;
       bool accept_OF = decl_props == kHasNoInitializers;
       ForEachStatement::VisitMode mode;
+      int each_pos = position();
 
       if (accept_IN && CheckInOrOf(accept_OF, &mode)) {
         // Rewrite a for-in statement of the form
         //
-        //   for (let x in e) b
+        //   for (let/const x in e) b
         //
         // into
         //
         //   <let x' be a temporary variable>
         //   for (x' in e) {
-        //     let x;
+        //     let/const x;
         //     x = x';
         //     b;
         //   }
@@ -3178,9 +3299,9 @@
         // implementing stack allocated block scoped variables.
         Variable* temp = scope_->DeclarationScope()->NewTemporary(
             ast_value_factory()->dot_for_string());
-        VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
+        VariableProxy* temp_proxy = factory()->NewVariableProxy(temp, each_pos);
         ForEachStatement* loop =
-            factory()->NewForEachStatement(mode, labels, pos);
+            factory()->NewForEachStatement(mode, labels, stmt_pos);
         Target target(&this->target_stack_, loop);
 
         // The expression does not see the loop variable.
@@ -3189,13 +3310,14 @@
         scope_ = for_scope;
         Expect(Token::RPAREN, CHECK_OK);
 
-        VariableProxy* each =
-            scope_->NewUnresolved(factory(), name, Interface::NewValue());
+        VariableProxy* each = scope_->NewUnresolved(
+            factory(), name, Interface::NewValue(), each_pos);
         Statement* body = ParseStatement(NULL, CHECK_OK);
         Block* body_block =
             factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
+        Token::Value init_op = is_const ? Token::INIT_CONST : Token::ASSIGN;
         Assignment* assignment = factory()->NewAssignment(
-            Token::ASSIGN, each, temp_proxy, RelocInfo::kNoPosition);
+            init_op, each, temp_proxy, RelocInfo::kNoPosition);
         Statement* assignment_statement = factory()->NewExpressionStatement(
             assignment, RelocInfo::kNoPosition);
         body_block->AddStatement(variable_statement, zone());
@@ -3216,14 +3338,18 @@
       Scanner::Location lhs_location = scanner()->peek_location();
       Expression* expression = ParseExpression(false, CHECK_OK);
       ForEachStatement::VisitMode mode;
-      bool accept_OF = expression->AsVariableProxy();
+      bool accept_OF = expression->IsVariableProxy();
+      is_let_identifier_expression =
+        expression->IsVariableProxy() &&
+        expression->AsVariableProxy()->raw_name() ==
+            ast_value_factory()->let_string();
 
       if (CheckInOrOf(accept_OF, &mode)) {
         expression = this->CheckAndRewriteReferenceExpression(
             expression, lhs_location, "invalid_lhs_in_for", CHECK_OK);
 
         ForEachStatement* loop =
-            factory()->NewForEachStatement(mode, labels, pos);
+            factory()->NewForEachStatement(mode, labels, stmt_pos);
         Target target(&this->target_stack_, loop);
 
         Expression* enumerable = ParseExpression(true, CHECK_OK);
@@ -3239,17 +3365,23 @@
         return loop;
 
       } else {
-        init = factory()->NewExpressionStatement(
-            expression, RelocInfo::kNoPosition);
+        init = factory()->NewExpressionStatement(expression, position());
       }
     }
   }
 
   // Standard 'for' loop
-  ForStatement* loop = factory()->NewForStatement(labels, pos);
+  ForStatement* loop = factory()->NewForStatement(labels, stmt_pos);
   Target target(&this->target_stack_, loop);
 
   // Parsed initializer at this point.
+  // Detect attempts at 'let' declarations in sloppy mode.
+  if (peek() == Token::IDENTIFIER && strict_mode() == SLOPPY &&
+      is_let_identifier_expression) {
+    ReportMessage("sloppy_lexical", NULL);
+    *ok = false;
+    return NULL;
+  }
   Expect(Token::SEMICOLON, CHECK_OK);
 
   // If there are let bindings, then condition and the next statement of the
@@ -3269,8 +3401,9 @@
 
   Statement* next = NULL;
   if (peek() != Token::RPAREN) {
+    int next_pos = position();
     Expression* exp = ParseExpression(true, CHECK_OK);
-    next = factory()->NewExpressionStatement(exp, RelocInfo::kNoPosition);
+    next = factory()->NewExpressionStatement(exp, next_pos);
   }
   Expect(Token::RPAREN, CHECK_OK);
 
@@ -3380,7 +3513,7 @@
 
   // Too many parentheses around expression:
   //   (( ... )) => ...
-  if (expression->parenthesization_level() > 1) return false;
+  if (expression->is_multi_parenthesized()) return false;
 
   // Case for a single parameter:
   //   (foo) => ...
@@ -3508,13 +3641,11 @@
   FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_
       ? FunctionLiteral::kIsParenthesized
       : FunctionLiteral::kNotParenthesized;
-  AstProperties ast_properties;
-  BailoutReason dont_optimize_reason = kNoReason;
   // Parse function body.
   {
-    FunctionState function_state(&function_state_, &scope_, scope, zone(),
-                                 ast_value_factory(),
-                                 info()->ast_node_id_gen());
+    AstNodeFactory function_factory(ast_value_factory());
+    FunctionState function_state(&function_state_, &scope_, scope,
+                                 &function_factory);
     scope_->SetScopeName(function_name);
 
     if (is_generator) {
@@ -3672,13 +3803,9 @@
                                            CHECK_OK);
     }
     if (strict_mode() == STRICT) {
-      CheckOctalLiteral(scope->start_position(),
-                        scope->end_position(),
-                        CHECK_OK);
+      CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
+                              CHECK_OK);
     }
-    ast_properties = *factory()->visitor()->ast_properties();
-    dont_optimize_reason = factory()->visitor()->dont_optimize_reason();
-
     if (allow_harmony_scoping() && strict_mode() == STRICT) {
       CheckConflictingVarDeclarations(scope, CHECK_OK);
     }
@@ -3690,8 +3817,6 @@
       num_parameters, duplicate_parameters, function_type,
       FunctionLiteral::kIsFunction, parenthesized, kind, pos);
   function_literal->set_function_token_position(function_token_pos);
-  function_literal->set_ast_properties(&ast_properties);
-  function_literal->set_dont_optimize_reason(dont_optimize_reason);
 
   if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
   return function_literal;
@@ -3702,64 +3827,66 @@
                                   int* materialized_literal_count,
                                   int* expected_property_count,
                                   bool* ok) {
+  if (produce_cached_parse_data()) CHECK(log_);
+
   int function_block_pos = position();
-  if (compile_options() == ScriptCompiler::kConsumeParserCache) {
+  if (consume_cached_parse_data() && !cached_parse_data_->rejected()) {
     // If we have cached data, we use it to skip parsing the function body. The
     // data contains the information we need to construct the lazy function.
     FunctionEntry entry =
         cached_parse_data_->GetFunctionEntry(function_block_pos);
-    // Check that cached data is valid.
-    CHECK(entry.is_valid());
-    // End position greater than end of stream is safe, and hard to check.
-    CHECK(entry.end_pos() > function_block_pos);
-    scanner()->SeekForward(entry.end_pos() - 1);
+    // Check that cached data is valid. If not, mark it as invalid (the embedder
+    // handles it). Note that end position greater than end of stream is safe,
+    // and hard to check.
+    if (entry.is_valid() && entry.end_pos() > function_block_pos) {
+      scanner()->SeekForward(entry.end_pos() - 1);
 
-    scope_->set_end_position(entry.end_pos());
-    Expect(Token::RBRACE, ok);
-    if (!*ok) {
+      scope_->set_end_position(entry.end_pos());
+      Expect(Token::RBRACE, ok);
+      if (!*ok) {
+        return;
+      }
+      total_preparse_skipped_ += scope_->end_position() - function_block_pos;
+      *materialized_literal_count = entry.literal_count();
+      *expected_property_count = entry.property_count();
+      scope_->SetStrictMode(entry.strict_mode());
       return;
     }
-    total_preparse_skipped_ += scope_->end_position() - function_block_pos;
-    *materialized_literal_count = entry.literal_count();
-    *expected_property_count = entry.property_count();
-    scope_->SetStrictMode(entry.strict_mode());
-  } else {
-    // With no cached data, we partially parse the function, without building an
-    // AST. This gathers the data needed to build a lazy function.
-    SingletonLogger logger;
-    PreParser::PreParseResult result =
-        ParseLazyFunctionBodyWithPreParser(&logger);
-    if (result == PreParser::kPreParseStackOverflow) {
-      // Propagate stack overflow.
-      set_stack_overflow();
-      *ok = false;
-      return;
-    }
-    if (logger.has_error()) {
-      ParserTraits::ReportMessageAt(
-          Scanner::Location(logger.start(), logger.end()),
-          logger.message(), logger.argument_opt(), logger.is_reference_error());
-      *ok = false;
-      return;
-    }
-    scope_->set_end_position(logger.end());
-    Expect(Token::RBRACE, ok);
-    if (!*ok) {
-      return;
-    }
-    total_preparse_skipped_ += scope_->end_position() - function_block_pos;
-    *materialized_literal_count = logger.literals();
-    *expected_property_count = logger.properties();
-    scope_->SetStrictMode(logger.strict_mode());
-    if (compile_options() == ScriptCompiler::kProduceParserCache) {
-      DCHECK(log_);
-      // Position right after terminal '}'.
-      int body_end = scanner()->location().end_pos;
-      log_->LogFunction(function_block_pos, body_end,
-                        *materialized_literal_count,
-                        *expected_property_count,
-                        scope_->strict_mode());
-    }
+    cached_parse_data_->Reject();
+  }
+  // With no cached data, we partially parse the function, without building an
+  // AST. This gathers the data needed to build a lazy function.
+  SingletonLogger logger;
+  PreParser::PreParseResult result =
+      ParseLazyFunctionBodyWithPreParser(&logger);
+  if (result == PreParser::kPreParseStackOverflow) {
+    // Propagate stack overflow.
+    set_stack_overflow();
+    *ok = false;
+    return;
+  }
+  if (logger.has_error()) {
+    ParserTraits::ReportMessageAt(
+        Scanner::Location(logger.start(), logger.end()), logger.message(),
+        logger.argument_opt(), logger.is_reference_error());
+    *ok = false;
+    return;
+  }
+  scope_->set_end_position(logger.end());
+  Expect(Token::RBRACE, ok);
+  if (!*ok) {
+    return;
+  }
+  total_preparse_skipped_ += scope_->end_position() - function_block_pos;
+  *materialized_literal_count = logger.literals();
+  *expected_property_count = logger.properties();
+  scope_->SetStrictMode(logger.strict_mode());
+  if (produce_cached_parse_data()) {
+    DCHECK(log_);
+    // Position right after terminal '}'.
+    int body_end = scanner()->location().end_pos;
+    log_->LogFunction(function_block_pos, body_end, *materialized_literal_count,
+                      *expected_property_count, scope_->strict_mode());
   }
 }
 
@@ -3834,16 +3961,20 @@
 
   if (reusable_preparser_ == NULL) {
     reusable_preparser_ = new PreParser(&scanner_, NULL, stack_limit_);
-    reusable_preparser_->set_allow_harmony_scoping(allow_harmony_scoping());
-    reusable_preparser_->set_allow_modules(allow_modules());
-    reusable_preparser_->set_allow_natives_syntax(allow_natives_syntax());
     reusable_preparser_->set_allow_lazy(true);
-    reusable_preparser_->set_allow_arrow_functions(allow_arrow_functions());
+    reusable_preparser_->set_allow_natives(allow_natives());
+    reusable_preparser_->set_allow_harmony_scoping(allow_harmony_scoping());
+    reusable_preparser_->set_allow_harmony_modules(allow_harmony_modules());
+    reusable_preparser_->set_allow_harmony_arrow_functions(
+        allow_harmony_arrow_functions());
     reusable_preparser_->set_allow_harmony_numeric_literals(
         allow_harmony_numeric_literals());
-    reusable_preparser_->set_allow_classes(allow_classes());
+    reusable_preparser_->set_allow_harmony_classes(allow_harmony_classes());
     reusable_preparser_->set_allow_harmony_object_literals(
         allow_harmony_object_literals());
+    reusable_preparser_->set_allow_harmony_templates(allow_harmony_templates());
+    reusable_preparser_->set_allow_harmony_sloppy(allow_harmony_sloppy());
+    reusable_preparser_->set_allow_harmony_unicode(allow_harmony_unicode());
   }
   PreParser::PreParseResult result =
       reusable_preparser_->PreParseLazyFunction(strict_mode(),
@@ -3856,6 +3987,90 @@
 }
 
 
+ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
+                                        Scanner::Location class_name_location,
+                                        bool name_is_strict_reserved, int pos,
+                                        bool* ok) {
+  // All parts of a ClassDeclaration and ClassExpression are strict code.
+  if (name_is_strict_reserved) {
+    ReportMessageAt(class_name_location, "unexpected_strict_reserved");
+    *ok = false;
+    return NULL;
+  }
+  if (IsEvalOrArguments(name)) {
+    ReportMessageAt(class_name_location, "strict_eval_arguments");
+    *ok = false;
+    return NULL;
+  }
+
+  Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
+  BlockState block_state(&scope_, block_scope);
+  scope_->SetStrictMode(STRICT);
+  scope_->SetScopeName(name);
+
+  VariableProxy* proxy = NULL;
+  if (name != NULL) {
+    proxy = NewUnresolved(name, CONST, Interface::NewConst());
+    Declaration* declaration =
+        factory()->NewVariableDeclaration(proxy, CONST, block_scope, pos);
+    Declare(declaration, true, CHECK_OK);
+  }
+
+  Expression* extends = NULL;
+  if (Check(Token::EXTENDS)) {
+    block_scope->set_start_position(scanner()->location().end_pos);
+    extends = ParseLeftHandSideExpression(CHECK_OK);
+  } else {
+    block_scope->set_start_position(scanner()->location().end_pos);
+  }
+
+  ZoneList<ObjectLiteral::Property*>* properties = NewPropertyList(4, zone());
+  Expression* constructor = NULL;
+  bool has_seen_constructor = false;
+
+  Expect(Token::LBRACE, CHECK_OK);
+  while (peek() != Token::RBRACE) {
+    if (Check(Token::SEMICOLON)) continue;
+    if (fni_ != NULL) fni_->Enter();
+    const bool in_class = true;
+    const bool is_static = false;
+    ObjectLiteral::Property* property = ParsePropertyDefinition(
+        NULL, in_class, is_static, &has_seen_constructor, CHECK_OK);
+
+    if (has_seen_constructor && constructor == NULL) {
+      constructor = GetPropertyValue(property);
+    } else {
+      properties->Add(property, zone());
+    }
+
+    if (fni_ != NULL) {
+      fni_->Infer();
+      fni_->Leave();
+    }
+  }
+
+  Expect(Token::RBRACE, CHECK_OK);
+  int end_pos = scanner()->location().end_pos;
+
+  if (constructor == NULL) {
+    constructor =
+        DefaultConstructor(extends != NULL, block_scope, pos, end_pos);
+  }
+
+  block_scope->set_end_position(end_pos);
+  block_scope = block_scope->FinalizeBlockScope();
+
+  if (name != NULL) {
+    DCHECK_NOT_NULL(proxy);
+    DCHECK_NOT_NULL(block_scope);
+    proxy->var()->set_initializer_position(end_pos);
+  }
+
+  return factory()->NewClassLiteral(name, block_scope, proxy, extends,
+                                    constructor, properties, pos, end_pos);
+}
+
+
 Expression* Parser::ParseV8Intrinsic(bool* ok) {
   // CallRuntime ::
   //   '%' Identifier Arguments
@@ -4107,6 +4322,9 @@
     }
   } else {
     current_ = kEndMarker;
+    // Advance so that position() points to 1-after-the-last-character. This is
+    // important so that Reset() to this position works correctly.
+    next_pos_ = in()->length() + 1;
     has_more_ = false;
   }
 }
@@ -4894,7 +5112,7 @@
   DCHECK(info()->function() == NULL);
   FunctionLiteral* result = NULL;
   pre_parse_timer_ = isolate()->counters()->pre_parse();
-  if (FLAG_trace_parse || allow_natives_syntax() || extension_ != NULL) {
+  if (FLAG_trace_parse || allow_natives() || extension_ != NULL) {
     // If intrinsics are allowed, the Parser cannot operate independent of the
     // V8 heap because of Runtime. Tell the string table to internalize strings
     // and values right after they're created.
@@ -4926,9 +5144,7 @@
   fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
 
   CompleteParserRecorder recorder;
-  if (compile_options() == ScriptCompiler::kProduceParserCache) {
-    log_ = &recorder;
-  }
+  if (produce_cached_parse_data()) log_ = &recorder;
 
   DCHECK(info()->source_stream() != NULL);
   ExternalStreamingStream stream(info()->source_stream(),
@@ -4956,9 +5172,131 @@
   // We cannot internalize on a background thread; a foreground task will take
   // care of calling Parser::Internalize just before compilation.
 
-  if (compile_options() == ScriptCompiler::kProduceParserCache) {
+  if (produce_cached_parse_data()) {
     if (result != NULL) *info_->cached_data() = recorder.GetScriptData();
     log_ = NULL;
   }
 }
+
+
+ParserTraits::TemplateLiteralState Parser::OpenTemplateLiteral(int pos) {
+  return new (zone()) ParserTraits::TemplateLiteral(zone(), pos);
+}
+
+
+void Parser::AddTemplateSpan(TemplateLiteralState* state, bool tail) {
+  int pos = scanner()->location().beg_pos;
+  int end = scanner()->location().end_pos - (tail ? 1 : 2);
+  const AstRawString* tv = scanner()->CurrentSymbol(ast_value_factory());
+  const AstRawString* trv = scanner()->CurrentRawSymbol(ast_value_factory());
+  Literal* cooked = factory()->NewStringLiteral(tv, pos);
+  Literal* raw = factory()->NewStringLiteral(trv, pos);
+  (*state)->AddTemplateSpan(cooked, raw, end, zone());
+}
+
+
+void Parser::AddTemplateExpression(TemplateLiteralState* state,
+                                   Expression* expression) {
+  (*state)->AddExpression(expression, zone());
+}
+
+
+Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start,
+                                         Expression* tag) {
+  TemplateLiteral* lit = *state;
+  int pos = lit->position();
+  const ZoneList<Expression*>* cooked_strings = lit->cooked();
+  const ZoneList<Expression*>* raw_strings = lit->raw();
+  const ZoneList<Expression*>* expressions = lit->expressions();
+  DCHECK_EQ(cooked_strings->length(), raw_strings->length());
+  DCHECK_EQ(cooked_strings->length(), expressions->length() + 1);
+
+  if (!tag) {
+    // Build tree of BinaryOps to simplify code-generation
+    Expression* expr = NULL;
+
+    if (expressions->length() == 0) {
+      // Simple case: treat as string literal
+      expr = cooked_strings->at(0);
+    } else {
+      int i;
+      Expression* cooked_str = cooked_strings->at(0);
+      expr = factory()->NewBinaryOperation(
+          Token::ADD, cooked_str, expressions->at(0), cooked_str->position());
+      for (i = 1; i < expressions->length(); ++i) {
+        cooked_str = cooked_strings->at(i);
+        expr = factory()->NewBinaryOperation(
+            Token::ADD, expr, factory()->NewBinaryOperation(
+                                  Token::ADD, cooked_str, expressions->at(i),
+                                  cooked_str->position()),
+            cooked_str->position());
+      }
+      cooked_str = cooked_strings->at(i);
+      expr = factory()->NewBinaryOperation(Token::ADD, expr, cooked_str,
+                                           cooked_str->position());
+    }
+    return expr;
+  } else {
+    uint32_t hash = ComputeTemplateLiteralHash(lit);
+
+    int cooked_idx = function_state_->NextMaterializedLiteralIndex();
+    int raw_idx = function_state_->NextMaterializedLiteralIndex();
+
+    // GetTemplateCallSite
+    ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(4, zone());
+    args->Add(factory()->NewArrayLiteral(
+                  const_cast<ZoneList<Expression*>*>(cooked_strings),
+                  cooked_idx, pos),
+              zone());
+    args->Add(
+        factory()->NewArrayLiteral(
+            const_cast<ZoneList<Expression*>*>(raw_strings), raw_idx, pos),
+        zone());
+
+    // Ensure hash is suitable as a Smi value
+    Smi* hash_obj = Smi::cast(Internals::IntToSmi(static_cast<int>(hash)));
+    args->Add(factory()->NewSmiLiteral(hash_obj->value(), pos), zone());
+
+    this->CheckPossibleEvalCall(tag, scope_);
+    Expression* call_site = factory()->NewCallRuntime(
+        ast_value_factory()->get_template_callsite_string(), NULL, args, start);
+
+    // Call TagFn
+    ZoneList<Expression*>* call_args =
+        new (zone()) ZoneList<Expression*>(expressions->length() + 1, zone());
+    call_args->Add(call_site, zone());
+    call_args->AddAll(*expressions, zone());
+    return factory()->NewCall(tag, call_args, pos);
+  }
+}
+
+
+uint32_t Parser::ComputeTemplateLiteralHash(const TemplateLiteral* lit) {
+  const ZoneList<Expression*>* raw_strings = lit->raw();
+  int total = raw_strings->length();
+  DCHECK(total);
+
+  uint32_t running_hash = 0;
+
+  for (int index = 0; index < total; ++index) {
+    if (index) {
+      running_hash = StringHasher::ComputeRunningHashOneByte(
+          running_hash, "${}", 3);
+    }
+
+    const AstRawString* raw_string =
+        raw_strings->at(index)->AsLiteral()->raw_value()->AsString();
+    if (raw_string->is_one_byte()) {
+      const char* data = reinterpret_cast<const char*>(raw_string->raw_data());
+      running_hash = StringHasher::ComputeRunningHashOneByte(
+          running_hash, data, raw_string->length());
+    } else {
+      const uc16* data = reinterpret_cast<const uc16*>(raw_string->raw_data());
+      running_hash = StringHasher::ComputeRunningHash(running_hash, data,
+                                                      raw_string->length());
+    }
+  }
+
+  return running_hash;
+}
 } }  // namespace v8::internal
diff --git a/src/parser.h b/src/parser.h
index 40886f6..219f1c4 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -23,8 +23,6 @@
 class PositionStack;
 class Target;
 
-template <typename T> class ZoneListWrapper;
-
 
 class FunctionEntry BASE_EMBEDDED {
  public:
@@ -62,10 +60,14 @@
 // Wrapper around ScriptData to provide parser-specific functionality.
 class ParseData {
  public:
-  explicit ParseData(ScriptData* script_data) : script_data_(script_data) {
-    CHECK(IsAligned(script_data->length(), sizeof(unsigned)));
-    CHECK(IsSane());
+  static ParseData* FromCachedData(ScriptData* cached_data) {
+    ParseData* pd = new ParseData(cached_data);
+    if (pd->IsSane()) return pd;
+    cached_data->Reject();
+    delete pd;
+    return NULL;
   }
+
   void Initialize();
   FunctionEntry GetFunctionEntry(int start);
   int FunctionCount();
@@ -76,7 +78,13 @@
     return reinterpret_cast<unsigned*>(const_cast<byte*>(script_data_->data()));
   }
 
+  void Reject() { script_data_->Reject(); }
+
+  bool rejected() const { return script_data_->rejected(); }
+
  private:
+  explicit ParseData(ScriptData* script_data) : script_data_(script_data) {}
+
   bool IsSane();
   unsigned Magic();
   unsigned Version();
@@ -352,6 +360,8 @@
     // Used by FunctionState and BlockState.
     typedef v8::internal::Scope Scope;
     typedef v8::internal::Scope* ScopePtr;
+    inline static Scope* ptr_to_scope(ScopePtr scope) { return scope; }
+
     typedef Variable GeneratorVariable;
     typedef v8::internal::Zone Zone;
 
@@ -371,28 +381,11 @@
     typedef ZoneList<v8::internal::Statement*>* StatementList;
 
     // For constructing objects returned by the traversing functions.
-    typedef AstNodeFactory<AstConstructionVisitor> Factory;
+    typedef AstNodeFactory Factory;
   };
 
-  class Checkpoint;
-
   explicit ParserTraits(Parser* parser) : parser_(parser) {}
 
-  // Custom operations executed when FunctionStates are created and destructed.
-  template <typename FunctionState>
-  static void SetUpFunctionState(FunctionState* function_state) {
-    function_state->saved_id_gen_ = *function_state->ast_node_id_gen_;
-    *function_state->ast_node_id_gen_ =
-        AstNode::IdGen(BailoutId::FirstUsable().ToInt());
-  }
-
-  template <typename FunctionState>
-  static void TearDownFunctionState(FunctionState* function_state) {
-    if (function_state->outer_function_state_ != NULL) {
-      *function_state->ast_node_id_gen_ = function_state->saved_id_gen_;
-    }
-  }
-
   // Helper functions for recursive descent.
   bool IsEvalOrArguments(const AstRawString* identifier) const;
   V8_INLINE bool IsFutureStrictReserved(const AstRawString* identifier) const;
@@ -419,6 +412,15 @@
     return string->AsArrayIndex(index);
   }
 
+  bool IsConstructorProperty(ObjectLiteral::Property* property) {
+    return property->key()->raw_value()->EqualsString(
+        ast_value_factory()->constructor_string());
+  }
+
+  static Expression* GetPropertyValue(ObjectLiteral::Property* property) {
+    return property->value();
+  }
+
   // Functions for encapsulating the differences between parsing and preparsing;
   // operations interleaved with the recursive descent.
   static void PushLiteralName(FuncNameInferrer* fni, const AstRawString* id) {
@@ -433,7 +435,7 @@
   static void CheckFunctionLiteralInsideTopLevelObjectLiteral(
       Scope* scope, ObjectLiteralProperty* property, bool* has_function) {
     Expression* value = property->value();
-    if (scope->DeclarationScope()->is_global_scope() &&
+    if (scope->DeclarationScope()->is_script_scope() &&
         value->AsFunctionLiteral() != NULL) {
       *has_function = true;
       value->AsFunctionLiteral()->set_pretenure();
@@ -457,9 +459,9 @@
   // Returns true if we have a binary expression between two numeric
   // literals. In that case, *x will be changed to an expression which is the
   // computed value.
-  bool ShortcutNumericLiteralBinaryExpression(
-      Expression** x, Expression* y, Token::Value op, int pos,
-      AstNodeFactory<AstConstructionVisitor>* factory);
+  bool ShortcutNumericLiteralBinaryExpression(Expression** x, Expression* y,
+                                              Token::Value op, int pos,
+                                              AstNodeFactory* factory);
 
   // Rewrites the following types of unary expressions:
   // not <literal> -> true / false
@@ -472,9 +474,8 @@
   // + foo -> foo * 1
   // - foo -> foo * (-1)
   // ~ foo -> foo ^(~0)
-  Expression* BuildUnaryExpression(
-      Expression* expression, Token::Value op, int pos,
-      AstNodeFactory<AstConstructionVisitor>* factory);
+  Expression* BuildUnaryExpression(Expression* expression, Token::Value op,
+                                   int pos, AstNodeFactory* factory);
 
   // Generate AST node that throws a ReferenceError with the given type.
   Expression* NewThrowReferenceError(const char* type, int pos);
@@ -534,37 +535,26 @@
   V8_INLINE const AstRawString* EmptyIdentifierString();
 
   // Odd-ball literal creators.
-  Literal* GetLiteralTheHole(int position,
-                             AstNodeFactory<AstConstructionVisitor>* factory);
+  Literal* GetLiteralTheHole(int position, AstNodeFactory* factory);
 
   // Producing data during the recursive descent.
   const AstRawString* GetSymbol(Scanner* scanner);
   const AstRawString* GetNextSymbol(Scanner* scanner);
   const AstRawString* GetNumberAsSymbol(Scanner* scanner);
 
-  Expression* ThisExpression(Scope* scope,
-                             AstNodeFactory<AstConstructionVisitor>* factory,
+  Expression* ThisExpression(Scope* scope, AstNodeFactory* factory,
                              int pos = RelocInfo::kNoPosition);
-  Expression* SuperReference(Scope* scope,
-                             AstNodeFactory<AstConstructionVisitor>* factory,
+  Expression* SuperReference(Scope* scope, AstNodeFactory* factory,
                              int pos = RelocInfo::kNoPosition);
-  Expression* ClassLiteral(const AstRawString* name, Expression* extends,
-                           Expression* constructor,
-                           ZoneList<ObjectLiteral::Property*>* properties,
-                           int pos,
-                           AstNodeFactory<AstConstructionVisitor>* factory);
-
-  Literal* ExpressionFromLiteral(
-      Token::Value token, int pos, Scanner* scanner,
-      AstNodeFactory<AstConstructionVisitor>* factory);
-  Expression* ExpressionFromIdentifier(
-      const AstRawString* name, int pos, Scope* scope,
-      AstNodeFactory<AstConstructionVisitor>* factory);
-  Expression* ExpressionFromString(
-      int pos, Scanner* scanner,
-      AstNodeFactory<AstConstructionVisitor>* factory);
-  Expression* GetIterator(Expression* iterable,
-                          AstNodeFactory<AstConstructionVisitor>* factory);
+  Expression* DefaultConstructor(bool call_super, Scope* scope, int pos,
+                                 int end_pos);
+  Literal* ExpressionFromLiteral(Token::Value token, int pos, Scanner* scanner,
+                                 AstNodeFactory* factory);
+  Expression* ExpressionFromIdentifier(const AstRawString* name, int pos,
+                                       Scope* scope, AstNodeFactory* factory);
+  Expression* ExpressionFromString(int pos, Scanner* scanner,
+                                   AstNodeFactory* factory);
+  Expression* GetIterator(Expression* iterable, AstNodeFactory* factory);
   ZoneList<v8::internal::Expression*>* NewExpressionList(int size, Zone* zone) {
     return new(zone) ZoneList<v8::internal::Expression*>(size, zone);
   }
@@ -595,9 +585,57 @@
   V8_INLINE ZoneList<Statement*>* ParseEagerFunctionBody(
       const AstRawString* name, int pos, Variable* fvar,
       Token::Value fvar_init_op, bool is_generator, bool* ok);
+
+  ClassLiteral* ParseClassLiteral(const AstRawString* name,
+                                  Scanner::Location class_name_location,
+                                  bool name_is_strict_reserved, int pos,
+                                  bool* ok);
+
   V8_INLINE void CheckConflictingVarDeclarations(v8::internal::Scope* scope,
                                                  bool* ok);
 
+  class TemplateLiteral : public ZoneObject {
+   public:
+    TemplateLiteral(Zone* zone, int pos)
+        : cooked_(8, zone), raw_(8, zone), expressions_(8, zone), pos_(pos) {}
+
+    const ZoneList<Expression*>* cooked() const { return &cooked_; }
+    const ZoneList<Expression*>* raw() const { return &raw_; }
+    const ZoneList<Expression*>* expressions() const { return &expressions_; }
+    int position() const { return pos_; }
+
+    void AddTemplateSpan(Literal* cooked, Literal* raw, int end, Zone* zone) {
+      DCHECK_NOT_NULL(cooked);
+      DCHECK_NOT_NULL(raw);
+      cooked_.Add(cooked, zone);
+      raw_.Add(raw, zone);
+    }
+
+    void AddExpression(Expression* expression, Zone* zone) {
+      DCHECK_NOT_NULL(expression);
+      expressions_.Add(expression, zone);
+    }
+
+   private:
+    ZoneList<Expression*> cooked_;
+    ZoneList<Expression*> raw_;
+    ZoneList<Expression*> expressions_;
+    int pos_;
+  };
+
+  typedef TemplateLiteral* TemplateLiteralState;
+
+  V8_INLINE TemplateLiteralState OpenTemplateLiteral(int pos);
+  V8_INLINE void AddTemplateSpan(TemplateLiteralState* state, bool tail);
+  V8_INLINE void AddTemplateExpression(TemplateLiteralState* state,
+                                       Expression* expression);
+  V8_INLINE Expression* CloseTemplateLiteral(TemplateLiteralState* state,
+                                             int start, Expression* tag);
+  V8_INLINE Expression* NoTemplateTag() { return NULL; }
+  V8_INLINE static bool IsTaggedTemplate(const Expression* tag) {
+    return tag != NULL;
+  }
+
  private:
   Parser* parser_;
 };
@@ -644,6 +682,7 @@
   // Handle errors detected during parsing, move statistics to Isolate,
   // internalize strings (move them to the heap).
   void Internalize();
+  void HandleSourceURLComments();
 
  private:
   friend class ParserTraits;
@@ -693,6 +732,13 @@
   ScriptCompiler::CompileOptions compile_options() const {
     return info_->compile_options();
   }
+  bool consume_cached_parse_data() const {
+    return compile_options() == ScriptCompiler::kConsumeParserCache &&
+           cached_parse_data_ != NULL;
+  }
+  bool produce_cached_parse_data() const {
+    return compile_options() == ScriptCompiler::kProduceParserCache;
+  }
   Scope* DeclarationScope(VariableMode mode) {
     return IsLexicalVariableMode(mode)
         ? scope_ : scope_->DeclarationScope();
@@ -775,6 +821,12 @@
       int function_token_position, FunctionLiteral::FunctionType type,
       FunctionLiteral::ArityRestriction arity_restriction, bool* ok);
 
+
+  ClassLiteral* ParseClassLiteral(const AstRawString* name,
+                                  Scanner::Location class_name_location,
+                                  bool name_is_strict_reserved, int pos,
+                                  bool* ok);
+
   // Magical syntax support.
   Expression* ParseV8Intrinsic(bool* ok);
 
@@ -810,6 +862,9 @@
 
   Scope* NewScope(Scope* parent, ScopeType type);
 
+  FunctionLiteral* DefaultConstructor(bool call_super, Scope* scope, int pos,
+                                      int end_pos);
+
   // Skip over a lazy function, either using cached data if we have it, or
   // by parsing the function with PreParser. Consumes the ending }.
   void SkipLazyFunctionBody(const AstRawString* function_name,
@@ -825,10 +880,16 @@
       const AstRawString* function_name, int pos, Variable* fvar,
       Token::Value fvar_init_op, bool is_generator, bool* ok);
 
-  void HandleSourceURLComments();
-
   void ThrowPendingError();
 
+  TemplateLiteralState OpenTemplateLiteral(int pos);
+  void AddTemplateSpan(TemplateLiteralState* state, bool tail);
+  void AddTemplateExpression(TemplateLiteralState* state,
+                             Expression* expression);
+  Expression* CloseTemplateLiteral(TemplateLiteralState* state, int start,
+                                   Expression* tag);
+  uint32_t ComputeTemplateLiteralHash(const TemplateLiteral* lit);
+
   Scanner scanner_;
   PreParser* reusable_preparser_;
   Scope* original_scope_;  // for ES5 function declarations in sloppy eval
@@ -855,8 +916,7 @@
 
 bool ParserTraits::IsFutureStrictReserved(
     const AstRawString* identifier) const {
-  return identifier->IsOneByteEqualTo("yield") ||
-         parser_->scanner()->IdentifierIsFutureStrictReserved(identifier);
+  return parser_->scanner()->IdentifierIsFutureStrictReserved(identifier);
 }
 
 
@@ -925,6 +985,27 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(CompileTimeValue);
 };
 
+
+ParserTraits::TemplateLiteralState ParserTraits::OpenTemplateLiteral(int pos) {
+  return parser_->OpenTemplateLiteral(pos);
+}
+
+
+void ParserTraits::AddTemplateSpan(TemplateLiteralState* state, bool tail) {
+  parser_->AddTemplateSpan(state, tail);
+}
+
+
+void ParserTraits::AddTemplateExpression(TemplateLiteralState* state,
+                                         Expression* expression) {
+  parser_->AddTemplateExpression(state, expression);
+}
+
+
+Expression* ParserTraits::CloseTemplateLiteral(TemplateLiteralState* state,
+                                               int start, Expression* tag) {
+  return parser_->CloseTemplateLiteral(state, start, tag);
+}
 } }  // namespace v8::internal
 
 #endif  // V8_PARSER_H_
diff --git a/src/ppc/assembler-ppc-inl.h b/src/ppc/assembler-ppc-inl.h
new file mode 100644
index 0000000..6779ee3
--- /dev/null
+++ b/src/ppc/assembler-ppc-inl.h
@@ -0,0 +1,593 @@
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// - Redistribution in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the
+// distribution.
+//
+// - Neither the name of Sun Microsystems or the names of contributors may
+// be used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The original source code covered by the above license above has been modified
+// significantly by Google Inc.
+// Copyright 2014 the V8 project authors. All rights reserved.
+
+#ifndef V8_PPC_ASSEMBLER_PPC_INL_H_
+#define V8_PPC_ASSEMBLER_PPC_INL_H_
+
+#include "src/ppc/assembler-ppc.h"
+
+#include "src/assembler.h"
+#include "src/debug.h"
+
+
+namespace v8 {
+namespace internal {
+
+
+bool CpuFeatures::SupportsCrankshaft() { return true; }
+
+
+void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
+#if ABI_USES_FUNCTION_DESCRIPTORS || V8_OOL_CONSTANT_POOL
+  if (RelocInfo::IsInternalReference(rmode_)) {
+    // absolute code pointer inside code object moves with the code object.
+    Assembler::RelocateInternalReference(pc_, delta, 0, icache_flush_mode);
+  }
+#endif
+  // We do not use pc relative addressing on PPC, so there is
+  // nothing else to do.
+}
+
+
+Address RelocInfo::target_address() {
+  DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
+  return Assembler::target_address_at(pc_, host_);
+}
+
+
+Address RelocInfo::target_address_address() {
+  DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) ||
+         rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE);
+
+#if V8_OOL_CONSTANT_POOL
+  if (Assembler::IsConstantPoolLoadStart(pc_)) {
+    // We return the PC for ool constant pool since this function is used by the
+    // serializerer and expects the address to reside within the code object.
+    return reinterpret_cast<Address>(pc_);
+  }
+#endif
+
+  // Read the address of the word containing the target_address in an
+  // instruction stream.
+  // The only architecture-independent user of this function is the serializer.
+  // The serializer uses it to find out how many raw bytes of instruction to
+  // output before the next target.
+  // For an instruction like LIS/ORI where the target bits are mixed into the
+  // instruction bits, the size of the target will be zero, indicating that the
+  // serializer should not step forward in memory after a target is resolved
+  // and written.
+  return reinterpret_cast<Address>(pc_);
+}
+
+
+Address RelocInfo::constant_pool_entry_address() {
+#if V8_OOL_CONSTANT_POOL
+  return Assembler::target_constant_pool_address_at(pc_,
+                                                    host_->constant_pool());
+#else
+  UNREACHABLE();
+  return NULL;
+#endif
+}
+
+
+int RelocInfo::target_address_size() { return Assembler::kSpecialTargetSize; }
+
+
+void RelocInfo::set_target_address(Address target,
+                                   WriteBarrierMode write_barrier_mode,
+                                   ICacheFlushMode icache_flush_mode) {
+  DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
+  Assembler::set_target_address_at(pc_, host_, target, icache_flush_mode);
+  if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL &&
+      IsCodeTarget(rmode_)) {
+    Object* target_code = Code::GetCodeFromTargetAddress(target);
+    host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
+        host(), this, HeapObject::cast(target_code));
+  }
+}
+
+
+Address Assembler::break_address_from_return_address(Address pc) {
+  return target_address_from_return_address(pc);
+}
+
+
+Address Assembler::target_address_from_return_address(Address pc) {
+// Returns the address of the call target from the return address that will
+// be returned to after a call.
+// Call sequence is :
+//  mov   ip, @ call address
+//  mtlr  ip
+//  blrl
+//                      @ return address
+#if V8_OOL_CONSTANT_POOL
+  if (IsConstantPoolLoadEnd(pc - 3 * kInstrSize)) {
+    return pc - (kMovInstructionsConstantPool + 2) * kInstrSize;
+  }
+#endif
+  return pc - (kMovInstructionsNoConstantPool + 2) * kInstrSize;
+}
+
+
+Address Assembler::return_address_from_call_start(Address pc) {
+#if V8_OOL_CONSTANT_POOL
+  Address load_address = pc + (kMovInstructionsConstantPool - 1) * kInstrSize;
+  if (IsConstantPoolLoadEnd(load_address))
+    return pc + (kMovInstructionsConstantPool + 2) * kInstrSize;
+#endif
+  return pc + (kMovInstructionsNoConstantPool + 2) * kInstrSize;
+}
+
+
+Object* RelocInfo::target_object() {
+  DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+  return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_));
+}
+
+
+Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
+  DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+  return Handle<Object>(
+      reinterpret_cast<Object**>(Assembler::target_address_at(pc_, host_)));
+}
+
+
+void RelocInfo::set_target_object(Object* target,
+                                  WriteBarrierMode write_barrier_mode,
+                                  ICacheFlushMode icache_flush_mode) {
+  DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+  Assembler::set_target_address_at(
+      pc_, host_, reinterpret_cast<Address>(target), icache_flush_mode);
+  if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL &&
+      target->IsHeapObject()) {
+    host()->GetHeap()->incremental_marking()->RecordWrite(
+        host(), &Memory::Object_at(pc_), HeapObject::cast(target));
+  }
+}
+
+
+Address RelocInfo::target_reference() {
+  DCHECK(rmode_ == EXTERNAL_REFERENCE);
+  return Assembler::target_address_at(pc_, host_);
+}
+
+
+Address RelocInfo::target_runtime_entry(Assembler* origin) {
+  DCHECK(IsRuntimeEntry(rmode_));
+  return target_address();
+}
+
+
+void RelocInfo::set_target_runtime_entry(Address target,
+                                         WriteBarrierMode write_barrier_mode,
+                                         ICacheFlushMode icache_flush_mode) {
+  DCHECK(IsRuntimeEntry(rmode_));
+  if (target_address() != target)
+    set_target_address(target, write_barrier_mode, icache_flush_mode);
+}
+
+
+Handle<Cell> RelocInfo::target_cell_handle() {
+  DCHECK(rmode_ == RelocInfo::CELL);
+  Address address = Memory::Address_at(pc_);
+  return Handle<Cell>(reinterpret_cast<Cell**>(address));
+}
+
+
+Cell* RelocInfo::target_cell() {
+  DCHECK(rmode_ == RelocInfo::CELL);
+  return Cell::FromValueAddress(Memory::Address_at(pc_));
+}
+
+
+void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode write_barrier_mode,
+                                ICacheFlushMode icache_flush_mode) {
+  DCHECK(rmode_ == RelocInfo::CELL);
+  Address address = cell->address() + Cell::kValueOffset;
+  Memory::Address_at(pc_) = address;
+  if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) {
+    // TODO(1550) We are passing NULL as a slot because cell can never be on
+    // evacuation candidate.
+    host()->GetHeap()->incremental_marking()->RecordWrite(host(), NULL, cell);
+  }
+}
+
+
+#if V8_OOL_CONSTANT_POOL
+static const int kNoCodeAgeInstructions = 7;
+#else
+static const int kNoCodeAgeInstructions = 6;
+#endif
+static const int kCodeAgingInstructions =
+    Assembler::kMovInstructionsNoConstantPool + 3;
+static const int kNoCodeAgeSequenceInstructions =
+    ((kNoCodeAgeInstructions >= kCodeAgingInstructions)
+         ? kNoCodeAgeInstructions
+         : kCodeAgingInstructions);
+static const int kNoCodeAgeSequenceNops =
+    (kNoCodeAgeSequenceInstructions - kNoCodeAgeInstructions);
+static const int kCodeAgingSequenceNops =
+    (kNoCodeAgeSequenceInstructions - kCodeAgingInstructions);
+static const int kCodeAgingTargetDelta = 1 * Assembler::kInstrSize;
+static const int kNoCodeAgeSequenceLength =
+    (kNoCodeAgeSequenceInstructions * Assembler::kInstrSize);
+
+
+Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
+  UNREACHABLE();  // This should never be reached on PPC.
+  return Handle<Object>();
+}
+
+
+Code* RelocInfo::code_age_stub() {
+  DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
+  return Code::GetCodeFromTargetAddress(
+      Assembler::target_address_at(pc_ + kCodeAgingTargetDelta, host_));
+}
+
+
+void RelocInfo::set_code_age_stub(Code* stub,
+                                  ICacheFlushMode icache_flush_mode) {
+  DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
+  Assembler::set_target_address_at(pc_ + kCodeAgingTargetDelta, host_,
+                                   stub->instruction_start(),
+                                   icache_flush_mode);
+}
+
+
+Address RelocInfo::call_address() {
+  DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
+         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
+  // The pc_ offset of 0 assumes patched return sequence per
+  // BreakLocationIterator::SetDebugBreakAtReturn(), or debug break
+  // slot per BreakLocationIterator::SetDebugBreakAtSlot().
+  return Assembler::target_address_at(pc_, host_);
+}
+
+
+void RelocInfo::set_call_address(Address target) {
+  DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
+         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
+  Assembler::set_target_address_at(pc_, host_, target);
+  if (host() != NULL) {
+    Object* target_code = Code::GetCodeFromTargetAddress(target);
+    host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
+        host(), this, HeapObject::cast(target_code));
+  }
+}
+
+
+Object* RelocInfo::call_object() { return *call_object_address(); }
+
+
+void RelocInfo::set_call_object(Object* target) {
+  *call_object_address() = target;
+}
+
+
+Object** RelocInfo::call_object_address() {
+  DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
+         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
+  return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize);
+}
+
+
+void RelocInfo::WipeOut() {
+  DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
+         IsRuntimeEntry(rmode_) || IsExternalReference(rmode_));
+  Assembler::set_target_address_at(pc_, host_, NULL);
+}
+
+
+bool RelocInfo::IsPatchedReturnSequence() {
+  //
+  // The patched return sequence is defined by
+  // BreakLocationIterator::SetDebugBreakAtReturn()
+  // FIXED_SEQUENCE
+
+  Instr instr0 = Assembler::instr_at(pc_);
+  Instr instr1 = Assembler::instr_at(pc_ + 1 * Assembler::kInstrSize);
+#if V8_TARGET_ARCH_PPC64
+  Instr instr3 = Assembler::instr_at(pc_ + (3 * Assembler::kInstrSize));
+  Instr instr4 = Assembler::instr_at(pc_ + (4 * Assembler::kInstrSize));
+  Instr binstr = Assembler::instr_at(pc_ + (7 * Assembler::kInstrSize));
+#else
+  Instr binstr = Assembler::instr_at(pc_ + 4 * Assembler::kInstrSize);
+#endif
+  bool patched_return =
+      ((instr0 & kOpcodeMask) == ADDIS && (instr1 & kOpcodeMask) == ORI &&
+#if V8_TARGET_ARCH_PPC64
+       (instr3 & kOpcodeMask) == ORIS && (instr4 & kOpcodeMask) == ORI &&
+#endif
+       (binstr == 0x7d821008));  // twge r2, r2
+
+  // printf("IsPatchedReturnSequence: %d\n", patched_return);
+  return patched_return;
+}
+
+
+bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
+  Instr current_instr = Assembler::instr_at(pc_);
+  return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP);
+}
+
+
+void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
+  RelocInfo::Mode mode = rmode();
+  if (mode == RelocInfo::EMBEDDED_OBJECT) {
+    visitor->VisitEmbeddedPointer(this);
+  } else if (RelocInfo::IsCodeTarget(mode)) {
+    visitor->VisitCodeTarget(this);
+  } else if (mode == RelocInfo::CELL) {
+    visitor->VisitCell(this);
+  } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
+    visitor->VisitExternalReference(this);
+  } else if (RelocInfo::IsCodeAgeSequence(mode)) {
+    visitor->VisitCodeAgeSequence(this);
+  } else if (((RelocInfo::IsJSReturn(mode) && IsPatchedReturnSequence()) ||
+              (RelocInfo::IsDebugBreakSlot(mode) &&
+               IsPatchedDebugBreakSlotSequence())) &&
+             isolate->debug()->has_break_points()) {
+    visitor->VisitDebugTarget(this);
+  } else if (IsRuntimeEntry(mode)) {
+    visitor->VisitRuntimeEntry(this);
+  }
+}
+
+
+template <typename StaticVisitor>
+void RelocInfo::Visit(Heap* heap) {
+  RelocInfo::Mode mode = rmode();
+  if (mode == RelocInfo::EMBEDDED_OBJECT) {
+    StaticVisitor::VisitEmbeddedPointer(heap, this);
+  } else if (RelocInfo::IsCodeTarget(mode)) {
+    StaticVisitor::VisitCodeTarget(heap, this);
+  } else if (mode == RelocInfo::CELL) {
+    StaticVisitor::VisitCell(heap, this);
+  } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
+    StaticVisitor::VisitExternalReference(this);
+  } else if (RelocInfo::IsCodeAgeSequence(mode)) {
+    StaticVisitor::VisitCodeAgeSequence(heap, this);
+  } else if (heap->isolate()->debug()->has_break_points() &&
+             ((RelocInfo::IsJSReturn(mode) && IsPatchedReturnSequence()) ||
+              (RelocInfo::IsDebugBreakSlot(mode) &&
+               IsPatchedDebugBreakSlotSequence()))) {
+    StaticVisitor::VisitDebugTarget(heap, this);
+  } else if (IsRuntimeEntry(mode)) {
+    StaticVisitor::VisitRuntimeEntry(this);
+  }
+}
+
+Operand::Operand(intptr_t immediate, RelocInfo::Mode rmode) {
+  rm_ = no_reg;
+  imm_ = immediate;
+  rmode_ = rmode;
+}
+
+Operand::Operand(const ExternalReference& f) {
+  rm_ = no_reg;
+  imm_ = reinterpret_cast<intptr_t>(f.address());
+  rmode_ = RelocInfo::EXTERNAL_REFERENCE;
+}
+
+Operand::Operand(Smi* value) {
+  rm_ = no_reg;
+  imm_ = reinterpret_cast<intptr_t>(value);
+  rmode_ = kRelocInfo_NONEPTR;
+}
+
+Operand::Operand(Register rm) {
+  rm_ = rm;
+  rmode_ = kRelocInfo_NONEPTR;  // PPC -why doesn't ARM do this?
+}
+
+void Assembler::CheckBuffer() {
+  if (buffer_space() <= kGap) {
+    GrowBuffer();
+  }
+}
+
+void Assembler::CheckTrampolinePoolQuick() {
+  if (pc_offset() >= next_buffer_check_) {
+    CheckTrampolinePool();
+  }
+}
+
+void Assembler::emit(Instr x) {
+  CheckBuffer();
+  *reinterpret_cast<Instr*>(pc_) = x;
+  pc_ += kInstrSize;
+  CheckTrampolinePoolQuick();
+}
+
+bool Operand::is_reg() const { return rm_.is_valid(); }
+
+
+// Fetch the 32bit value from the FIXED_SEQUENCE lis/ori
+Address Assembler::target_address_at(Address pc,
+                                     ConstantPoolArray* constant_pool) {
+  Instr instr1 = instr_at(pc);
+  Instr instr2 = instr_at(pc + kInstrSize);
+  // Interpret 2 instructions generated by lis/ori
+  if (IsLis(instr1) && IsOri(instr2)) {
+#if V8_TARGET_ARCH_PPC64
+    Instr instr4 = instr_at(pc + (3 * kInstrSize));
+    Instr instr5 = instr_at(pc + (4 * kInstrSize));
+    // Assemble the 64 bit value.
+    uint64_t hi = (static_cast<uint32_t>((instr1 & kImm16Mask) << 16) |
+                   static_cast<uint32_t>(instr2 & kImm16Mask));
+    uint64_t lo = (static_cast<uint32_t>((instr4 & kImm16Mask) << 16) |
+                   static_cast<uint32_t>(instr5 & kImm16Mask));
+    return reinterpret_cast<Address>((hi << 32) | lo);
+#else
+    // Assemble the 32 bit value.
+    return reinterpret_cast<Address>(((instr1 & kImm16Mask) << 16) |
+                                     (instr2 & kImm16Mask));
+#endif
+  }
+#if V8_OOL_CONSTANT_POOL
+  return Memory::Address_at(target_constant_pool_address_at(pc, constant_pool));
+#else
+  DCHECK(false);
+  return (Address)0;
+#endif
+}
+
+
+#if V8_OOL_CONSTANT_POOL
+bool Assembler::IsConstantPoolLoadStart(Address pc) {
+#if V8_TARGET_ARCH_PPC64
+  if (!IsLi(instr_at(pc))) return false;
+  pc += kInstrSize;
+#endif
+  return GetRA(instr_at(pc)).is(kConstantPoolRegister);
+}
+
+
+bool Assembler::IsConstantPoolLoadEnd(Address pc) {
+#if V8_TARGET_ARCH_PPC64
+  pc -= kInstrSize;
+#endif
+  return IsConstantPoolLoadStart(pc);
+}
+
+
+int Assembler::GetConstantPoolOffset(Address pc) {
+  DCHECK(IsConstantPoolLoadStart(pc));
+  Instr instr = instr_at(pc);
+  int offset = SIGN_EXT_IMM16((instr & kImm16Mask));
+  return offset;
+}
+
+
+void Assembler::SetConstantPoolOffset(Address pc, int offset) {
+  DCHECK(IsConstantPoolLoadStart(pc));
+  DCHECK(is_int16(offset));
+  Instr instr = instr_at(pc);
+  instr &= ~kImm16Mask;
+  instr |= (offset & kImm16Mask);
+  instr_at_put(pc, instr);
+}
+
+
+Address Assembler::target_constant_pool_address_at(
+    Address pc, ConstantPoolArray* constant_pool) {
+  Address addr = reinterpret_cast<Address>(constant_pool);
+  DCHECK(addr);
+  addr += GetConstantPoolOffset(pc);
+  return addr;
+}
+#endif
+
+
+// This sets the branch destination (which gets loaded at the call address).
+// This is for calls and branches within generated code.  The serializer
+// has already deserialized the mov instructions etc.
+// There is a FIXED_SEQUENCE assumption here
+void Assembler::deserialization_set_special_target_at(
+    Address instruction_payload, Code* code, Address target) {
+  set_target_address_at(instruction_payload, code, target);
+}
+
+// This code assumes the FIXED_SEQUENCE of lis/ori
+void Assembler::set_target_address_at(Address pc,
+                                      ConstantPoolArray* constant_pool,
+                                      Address target,
+                                      ICacheFlushMode icache_flush_mode) {
+  Instr instr1 = instr_at(pc);
+  Instr instr2 = instr_at(pc + kInstrSize);
+  // Interpret 2 instructions generated by lis/ori
+  if (IsLis(instr1) && IsOri(instr2)) {
+#if V8_TARGET_ARCH_PPC64
+    Instr instr4 = instr_at(pc + (3 * kInstrSize));
+    Instr instr5 = instr_at(pc + (4 * kInstrSize));
+    // Needs to be fixed up when mov changes to handle 64-bit values.
+    uint32_t* p = reinterpret_cast<uint32_t*>(pc);
+    uintptr_t itarget = reinterpret_cast<uintptr_t>(target);
+
+    instr5 &= ~kImm16Mask;
+    instr5 |= itarget & kImm16Mask;
+    itarget = itarget >> 16;
+
+    instr4 &= ~kImm16Mask;
+    instr4 |= itarget & kImm16Mask;
+    itarget = itarget >> 16;
+
+    instr2 &= ~kImm16Mask;
+    instr2 |= itarget & kImm16Mask;
+    itarget = itarget >> 16;
+
+    instr1 &= ~kImm16Mask;
+    instr1 |= itarget & kImm16Mask;
+    itarget = itarget >> 16;
+
+    *p = instr1;
+    *(p + 1) = instr2;
+    *(p + 3) = instr4;
+    *(p + 4) = instr5;
+    if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
+      CpuFeatures::FlushICache(p, 5 * kInstrSize);
+    }
+#else
+    uint32_t* p = reinterpret_cast<uint32_t*>(pc);
+    uint32_t itarget = reinterpret_cast<uint32_t>(target);
+    int lo_word = itarget & kImm16Mask;
+    int hi_word = itarget >> 16;
+    instr1 &= ~kImm16Mask;
+    instr1 |= hi_word;
+    instr2 &= ~kImm16Mask;
+    instr2 |= lo_word;
+
+    *p = instr1;
+    *(p + 1) = instr2;
+    if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
+      CpuFeatures::FlushICache(p, 2 * kInstrSize);
+    }
+#endif
+  } else {
+#if V8_OOL_CONSTANT_POOL
+    Memory::Address_at(target_constant_pool_address_at(pc, constant_pool)) =
+        target;
+#else
+    UNREACHABLE();
+#endif
+  }
+}
+}
+}  // namespace v8::internal
+
+#endif  // V8_PPC_ASSEMBLER_PPC_INL_H_
diff --git a/src/ppc/assembler-ppc.cc b/src/ppc/assembler-ppc.cc
new file mode 100644
index 0000000..4b8b165
--- /dev/null
+++ b/src/ppc/assembler-ppc.cc
@@ -0,0 +1,2493 @@
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// - Redistribution in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the
+// distribution.
+//
+// - Neither the name of Sun Microsystems or the names of contributors may
+// be used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2014 the V8 project authors. All rights reserved.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/base/bits.h"
+#include "src/base/cpu.h"
+#include "src/macro-assembler.h"
+#include "src/ppc/assembler-ppc-inl.h"
+#include "src/serialize.h"
+
+namespace v8 {
+namespace internal {
+
+// Get the CPU features enabled by the build.
+static unsigned CpuFeaturesImpliedByCompiler() {
+  unsigned answer = 0;
+  return answer;
+}
+
+
+void CpuFeatures::ProbeImpl(bool cross_compile) {
+  supported_ |= CpuFeaturesImpliedByCompiler();
+  cache_line_size_ = 128;
+
+  // Only use statically determined features for cross compile (snapshot).
+  if (cross_compile) return;
+
+// Detect whether frim instruction is supported (POWER5+)
+// For now we will just check for processors we know do not
+// support it
+#ifndef USE_SIMULATOR
+  // Probe for additional features at runtime.
+  base::CPU cpu;
+#if V8_TARGET_ARCH_PPC64
+  if (cpu.part() == base::CPU::PPC_POWER8) {
+    supported_ |= (1u << FPR_GPR_MOV);
+  }
+#endif
+  if (cpu.part() == base::CPU::PPC_POWER6 ||
+      cpu.part() == base::CPU::PPC_POWER7 ||
+      cpu.part() == base::CPU::PPC_POWER8) {
+    supported_ |= (1u << LWSYNC);
+  }
+#if V8_OS_LINUX
+  if (!(cpu.part() == base::CPU::PPC_G5 || cpu.part() == base::CPU::PPC_G4)) {
+    // Assume support
+    supported_ |= (1u << FPU);
+  }
+  if (cpu.cache_line_size() != 0) {
+    cache_line_size_ = cpu.cache_line_size();
+  }
+#elif V8_OS_AIX
+  // Assume support FP support and default cache line size
+  supported_ |= (1u << FPU);
+#endif
+#else  // Simulator
+  supported_ |= (1u << FPU);
+  supported_ |= (1u << LWSYNC);
+#if V8_TARGET_ARCH_PPC64
+  supported_ |= (1u << FPR_GPR_MOV);
+#endif
+#endif
+}
+
+
+void CpuFeatures::PrintTarget() {
+  const char* ppc_arch = NULL;
+
+#if V8_TARGET_ARCH_PPC64
+  ppc_arch = "ppc64";
+#else
+  ppc_arch = "ppc";
+#endif
+
+  printf("target %s\n", ppc_arch);
+}
+
+
+void CpuFeatures::PrintFeatures() {
+  printf("FPU=%d\n", CpuFeatures::IsSupported(FPU));
+}
+
+
+Register ToRegister(int num) {
+  DCHECK(num >= 0 && num < kNumRegisters);
+  const Register kRegisters[] = {r0,  sp,  r2,  r3,  r4,  r5,  r6,  r7,
+                                 r8,  r9,  r10, r11, ip,  r13, r14, r15,
+                                 r16, r17, r18, r19, r20, r21, r22, r23,
+                                 r24, r25, r26, r27, r28, r29, r30, fp};
+  return kRegisters[num];
+}
+
+
+const char* DoubleRegister::AllocationIndexToString(int index) {
+  DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
+  const char* const names[] = {
+      "d1",  "d2",  "d3",  "d4",  "d5",  "d6",  "d7",  "d8",  "d9",  "d10",
+      "d11", "d12", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22",
+      "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"};
+  return names[index];
+}
+
+
+// -----------------------------------------------------------------------------
+// Implementation of RelocInfo
+
+const int RelocInfo::kApplyMask = 1 << RelocInfo::INTERNAL_REFERENCE;
+
+
+bool RelocInfo::IsCodedSpecially() {
+  // The deserializer needs to know whether a pointer is specially
+  // coded.  Being specially coded on PPC means that it is a lis/ori
+  // instruction sequence or is an out of line constant pool entry,
+  // and these are always the case inside code objects.
+  return true;
+}
+
+
+bool RelocInfo::IsInConstantPool() {
+#if V8_OOL_CONSTANT_POOL
+  return Assembler::IsConstantPoolLoadStart(pc_);
+#else
+  return false;
+#endif
+}
+
+
+void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
+  // Patch the code at the current address with the supplied instructions.
+  Instr* pc = reinterpret_cast<Instr*>(pc_);
+  Instr* instr = reinterpret_cast<Instr*>(instructions);
+  for (int i = 0; i < instruction_count; i++) {
+    *(pc + i) = *(instr + i);
+  }
+
+  // Indicate that code has changed.
+  CpuFeatures::FlushICache(pc_, instruction_count * Assembler::kInstrSize);
+}
+
+
+// Patch the code at the current PC with a call to the target address.
+// Additional guard instructions can be added if required.
+void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
+  // Patch the code at the current address with a call to the target.
+  UNIMPLEMENTED();
+}
+
+
+// -----------------------------------------------------------------------------
+// Implementation of Operand and MemOperand
+// See assembler-ppc-inl.h for inlined constructors
+
+Operand::Operand(Handle<Object> handle) {
+  AllowDeferredHandleDereference using_raw_address;
+  rm_ = no_reg;
+  // Verify all Objects referred by code are NOT in new space.
+  Object* obj = *handle;
+  if (obj->IsHeapObject()) {
+    DCHECK(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj));
+    imm_ = reinterpret_cast<intptr_t>(handle.location());
+    rmode_ = RelocInfo::EMBEDDED_OBJECT;
+  } else {
+    // no relocation needed
+    imm_ = reinterpret_cast<intptr_t>(obj);
+    rmode_ = kRelocInfo_NONEPTR;
+  }
+}
+
+
+MemOperand::MemOperand(Register rn, int32_t offset) {
+  ra_ = rn;
+  rb_ = no_reg;
+  offset_ = offset;
+}
+
+
+MemOperand::MemOperand(Register ra, Register rb) {
+  ra_ = ra;
+  rb_ = rb;
+  offset_ = 0;
+}
+
+
+// -----------------------------------------------------------------------------
+// Specific instructions, constants, and masks.
+
+// Spare buffer.
+static const int kMinimalBufferSize = 4 * KB;
+
+
+Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
+    : AssemblerBase(isolate, buffer, buffer_size),
+      recorded_ast_id_(TypeFeedbackId::None()),
+#if V8_OOL_CONSTANT_POOL
+      constant_pool_builder_(),
+#endif
+      positions_recorder_(this) {
+  reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
+
+  no_trampoline_pool_before_ = 0;
+  trampoline_pool_blocked_nesting_ = 0;
+  // We leave space (kMaxBlockTrampolineSectionSize)
+  // for BlockTrampolinePoolScope buffer.
+  next_buffer_check_ =
+      FLAG_force_long_branches ? kMaxInt : kMaxCondBranchReach -
+                                               kMaxBlockTrampolineSectionSize;
+  internal_trampoline_exception_ = false;
+  last_bound_pos_ = 0;
+  trampoline_emitted_ = FLAG_force_long_branches;
+  unbound_labels_count_ = 0;
+  ClearRecordedAstId();
+}
+
+
+void Assembler::GetCode(CodeDesc* desc) {
+  // Set up code descriptor.
+  desc->buffer = buffer_;
+  desc->buffer_size = buffer_size_;
+  desc->instr_size = pc_offset();
+  desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
+  desc->origin = this;
+}
+
+
+void Assembler::Align(int m) {
+#if V8_TARGET_ARCH_PPC64
+  DCHECK(m >= 4 && base::bits::IsPowerOfTwo64(m));
+#else
+  DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
+#endif
+  while ((pc_offset() & (m - 1)) != 0) {
+    nop();
+  }
+}
+
+
+void Assembler::CodeTargetAlign() { Align(8); }
+
+
+Condition Assembler::GetCondition(Instr instr) {
+  switch (instr & kCondMask) {
+    case BT:
+      return eq;
+    case BF:
+      return ne;
+    default:
+      UNIMPLEMENTED();
+  }
+  return al;
+}
+
+
+bool Assembler::IsLis(Instr instr) {
+  return ((instr & kOpcodeMask) == ADDIS) && GetRA(instr).is(r0);
+}
+
+
+bool Assembler::IsLi(Instr instr) {
+  return ((instr & kOpcodeMask) == ADDI) && GetRA(instr).is(r0);
+}
+
+
+bool Assembler::IsAddic(Instr instr) { return (instr & kOpcodeMask) == ADDIC; }
+
+
+bool Assembler::IsOri(Instr instr) { return (instr & kOpcodeMask) == ORI; }
+
+
+bool Assembler::IsBranch(Instr instr) { return ((instr & kOpcodeMask) == BCX); }
+
+
+Register Assembler::GetRA(Instr instr) {
+  Register reg;
+  reg.code_ = Instruction::RAValue(instr);
+  return reg;
+}
+
+
+Register Assembler::GetRB(Instr instr) {
+  Register reg;
+  reg.code_ = Instruction::RBValue(instr);
+  return reg;
+}
+
+
+#if V8_TARGET_ARCH_PPC64
+// This code assumes a FIXED_SEQUENCE for 64bit loads (lis/ori)
+bool Assembler::Is64BitLoadIntoR12(Instr instr1, Instr instr2, Instr instr3,
+                                   Instr instr4, Instr instr5) {
+  // Check the instructions are indeed a five part load (into r12)
+  // 3d800000       lis     r12, 0
+  // 618c0000       ori     r12, r12, 0
+  // 798c07c6       rldicr  r12, r12, 32, 31
+  // 658c00c3       oris    r12, r12, 195
+  // 618ccd40       ori     r12, r12, 52544
+  return (((instr1 >> 16) == 0x3d80) && ((instr2 >> 16) == 0x618c) &&
+          (instr3 == 0x798c07c6) && ((instr4 >> 16) == 0x658c) &&
+          ((instr5 >> 16) == 0x618c));
+}
+#else
+// This code assumes a FIXED_SEQUENCE for 32bit loads (lis/ori)
+bool Assembler::Is32BitLoadIntoR12(Instr instr1, Instr instr2) {
+  // Check the instruction is indeed a two part load (into r12)
+  // 3d802553       lis     r12, 9555
+  // 618c5000       ori   r12, r12, 20480
+  return (((instr1 >> 16) == 0x3d80) && ((instr2 >> 16) == 0x618c));
+}
+#endif
+
+
+bool Assembler::IsCmpRegister(Instr instr) {
+  return (((instr & kOpcodeMask) == EXT2) &&
+          ((instr & kExt2OpcodeMask) == CMP));
+}
+
+
+bool Assembler::IsRlwinm(Instr instr) {
+  return ((instr & kOpcodeMask) == RLWINMX);
+}
+
+
+#if V8_TARGET_ARCH_PPC64
+bool Assembler::IsRldicl(Instr instr) {
+  return (((instr & kOpcodeMask) == EXT5) &&
+          ((instr & kExt5OpcodeMask) == RLDICL));
+}
+#endif
+
+
+bool Assembler::IsCmpImmediate(Instr instr) {
+  return ((instr & kOpcodeMask) == CMPI);
+}
+
+
+bool Assembler::IsCrSet(Instr instr) {
+  return (((instr & kOpcodeMask) == EXT1) &&
+          ((instr & kExt1OpcodeMask) == CREQV));
+}
+
+
+Register Assembler::GetCmpImmediateRegister(Instr instr) {
+  DCHECK(IsCmpImmediate(instr));
+  return GetRA(instr);
+}
+
+
+int Assembler::GetCmpImmediateRawImmediate(Instr instr) {
+  DCHECK(IsCmpImmediate(instr));
+  return instr & kOff16Mask;
+}
+
+
+// Labels refer to positions in the (to be) generated code.
+// There are bound, linked, and unused labels.
+//
+// Bound labels refer to known positions in the already
+// generated code. pos() is the position the label refers to.
+//
+// Linked labels refer to unknown positions in the code
+// to be generated; pos() is the position of the last
+// instruction using the label.
+
+
+// The link chain is terminated by a negative code position (must be aligned)
+const int kEndOfChain = -4;
+
+
+int Assembler::target_at(int pos) {
+  Instr instr = instr_at(pos);
+  // check which type of branch this is 16 or 26 bit offset
+  int opcode = instr & kOpcodeMask;
+  if (BX == opcode) {
+    int imm26 = ((instr & kImm26Mask) << 6) >> 6;
+    imm26 &= ~(kAAMask | kLKMask);  // discard AA|LK bits if present
+    if (imm26 == 0) return kEndOfChain;
+    return pos + imm26;
+  } else if (BCX == opcode) {
+    int imm16 = SIGN_EXT_IMM16((instr & kImm16Mask));
+    imm16 &= ~(kAAMask | kLKMask);  // discard AA|LK bits if present
+    if (imm16 == 0) return kEndOfChain;
+    return pos + imm16;
+  } else if ((instr & ~kImm26Mask) == 0) {
+    // Emitted link to a label, not part of a branch (regexp PushBacktrack).
+    if (instr == 0) {
+      return kEndOfChain;
+    } else {
+      int32_t imm26 = SIGN_EXT_IMM26(instr);
+      return (imm26 + pos);
+    }
+  }
+
+  PPCPORT_UNIMPLEMENTED();
+  DCHECK(false);
+  return -1;
+}
+
+
+void Assembler::target_at_put(int pos, int target_pos) {
+  Instr instr = instr_at(pos);
+  int opcode = instr & kOpcodeMask;
+
+  // check which type of branch this is 16 or 26 bit offset
+  if (BX == opcode) {
+    int imm26 = target_pos - pos;
+    DCHECK((imm26 & (kAAMask | kLKMask)) == 0);
+    instr &= ((~kImm26Mask) | kAAMask | kLKMask);
+    DCHECK(is_int26(imm26));
+    instr_at_put(pos, instr | (imm26 & kImm26Mask));
+    return;
+  } else if (BCX == opcode) {
+    int imm16 = target_pos - pos;
+    DCHECK((imm16 & (kAAMask | kLKMask)) == 0);
+    instr &= ((~kImm16Mask) | kAAMask | kLKMask);
+    DCHECK(is_int16(imm16));
+    instr_at_put(pos, instr | (imm16 & kImm16Mask));
+    return;
+  } else if ((instr & ~kImm26Mask) == 0) {
+    DCHECK(target_pos == kEndOfChain || target_pos >= 0);
+    // Emitted link to a label, not part of a branch (regexp PushBacktrack).
+    // Load the position of the label relative to the generated code object
+    // pointer in a register.
+
+    Register dst = r3;  // we assume r3 for now
+    DCHECK(IsNop(instr_at(pos + kInstrSize)));
+    uint32_t target = target_pos + (Code::kHeaderSize - kHeapObjectTag);
+    CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), 2,
+                        CodePatcher::DONT_FLUSH);
+    int target_hi = static_cast<int>(target) >> 16;
+    int target_lo = static_cast<int>(target) & 0XFFFF;
+
+    patcher.masm()->lis(dst, Operand(SIGN_EXT_IMM16(target_hi)));
+    patcher.masm()->ori(dst, dst, Operand(target_lo));
+    return;
+  }
+
+  DCHECK(false);
+}
+
+
+int Assembler::max_reach_from(int pos) {
+  Instr instr = instr_at(pos);
+  int opcode = instr & kOpcodeMask;
+
+  // check which type of branch this is 16 or 26 bit offset
+  if (BX == opcode) {
+    return 26;
+  } else if (BCX == opcode) {
+    return 16;
+  } else if ((instr & ~kImm26Mask) == 0) {
+    // Emitted label constant, not part of a branch (regexp PushBacktrack).
+    return 26;
+  }
+
+  DCHECK(false);
+  return 0;
+}
+
+
+void Assembler::bind_to(Label* L, int pos) {
+  DCHECK(0 <= pos && pos <= pc_offset());  // must have a valid binding position
+  int32_t trampoline_pos = kInvalidSlotPos;
+  if (L->is_linked() && !trampoline_emitted_) {
+    unbound_labels_count_--;
+    next_buffer_check_ += kTrampolineSlotsSize;
+  }
+
+  while (L->is_linked()) {
+    int fixup_pos = L->pos();
+    int32_t offset = pos - fixup_pos;
+    int maxReach = max_reach_from(fixup_pos);
+    next(L);  // call next before overwriting link with target at fixup_pos
+    if (is_intn(offset, maxReach) == false) {
+      if (trampoline_pos == kInvalidSlotPos) {
+        trampoline_pos = get_trampoline_entry();
+        CHECK(trampoline_pos != kInvalidSlotPos);
+        target_at_put(trampoline_pos, pos);
+      }
+      target_at_put(fixup_pos, trampoline_pos);
+    } else {
+      target_at_put(fixup_pos, pos);
+    }
+  }
+  L->bind_to(pos);
+
+  // Keep track of the last bound label so we don't eliminate any instructions
+  // before a bound label.
+  if (pos > last_bound_pos_) last_bound_pos_ = pos;
+}
+
+
+void Assembler::bind(Label* L) {
+  DCHECK(!L->is_bound());  // label can only be bound once
+  bind_to(L, pc_offset());
+}
+
+
+void Assembler::next(Label* L) {
+  DCHECK(L->is_linked());
+  int link = target_at(L->pos());
+  if (link == kEndOfChain) {
+    L->Unuse();
+  } else {
+    DCHECK(link >= 0);
+    L->link_to(link);
+  }
+}
+
+
+bool Assembler::is_near(Label* L, Condition cond) {
+  DCHECK(L->is_bound());
+  if (L->is_bound() == false) return false;
+
+  int maxReach = ((cond == al) ? 26 : 16);
+  int offset = L->pos() - pc_offset();
+
+  return is_intn(offset, maxReach);
+}
+
+
+void Assembler::a_form(Instr instr, DoubleRegister frt, DoubleRegister fra,
+                       DoubleRegister frb, RCBit r) {
+  emit(instr | frt.code() * B21 | fra.code() * B16 | frb.code() * B11 | r);
+}
+
+
+void Assembler::d_form(Instr instr, Register rt, Register ra,
+                       const intptr_t val, bool signed_disp) {
+  if (signed_disp) {
+    if (!is_int16(val)) {
+      PrintF("val = %" V8PRIdPTR ", 0x%" V8PRIxPTR "\n", val, val);
+    }
+    DCHECK(is_int16(val));
+  } else {
+    if (!is_uint16(val)) {
+      PrintF("val = %" V8PRIdPTR ", 0x%" V8PRIxPTR
+             ", is_unsigned_imm16(val)=%d, kImm16Mask=0x%x\n",
+             val, val, is_uint16(val), kImm16Mask);
+    }
+    DCHECK(is_uint16(val));
+  }
+  emit(instr | rt.code() * B21 | ra.code() * B16 | (kImm16Mask & val));
+}
+
+
+void Assembler::x_form(Instr instr, Register ra, Register rs, Register rb,
+                       RCBit r) {
+  emit(instr | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 | r);
+}
+
+
+void Assembler::xo_form(Instr instr, Register rt, Register ra, Register rb,
+                        OEBit o, RCBit r) {
+  emit(instr | rt.code() * B21 | ra.code() * B16 | rb.code() * B11 | o | r);
+}
+
+
+void Assembler::md_form(Instr instr, Register ra, Register rs, int shift,
+                        int maskbit, RCBit r) {
+  int sh0_4 = shift & 0x1f;
+  int sh5 = (shift >> 5) & 0x1;
+  int m0_4 = maskbit & 0x1f;
+  int m5 = (maskbit >> 5) & 0x1;
+
+  emit(instr | rs.code() * B21 | ra.code() * B16 | sh0_4 * B11 | m0_4 * B6 |
+       m5 * B5 | sh5 * B1 | r);
+}
+
+
+void Assembler::mds_form(Instr instr, Register ra, Register rs, Register rb,
+                         int maskbit, RCBit r) {
+  int m0_4 = maskbit & 0x1f;
+  int m5 = (maskbit >> 5) & 0x1;
+
+  emit(instr | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 | m0_4 * B6 |
+       m5 * B5 | r);
+}
+
+
+// Returns the next free trampoline entry.
+int32_t Assembler::get_trampoline_entry() {
+  int32_t trampoline_entry = kInvalidSlotPos;
+
+  if (!internal_trampoline_exception_) {
+    trampoline_entry = trampoline_.take_slot();
+
+    if (kInvalidSlotPos == trampoline_entry) {
+      internal_trampoline_exception_ = true;
+    }
+  }
+  return trampoline_entry;
+}
+
+
+int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
+  int target_pos;
+  if (L->is_bound()) {
+    target_pos = L->pos();
+  } else {
+    if (L->is_linked()) {
+      target_pos = L->pos();  // L's link
+    } else {
+      // was: target_pos = kEndOfChain;
+      // However, using branch to self to mark the first reference
+      // should avoid most instances of branch offset overflow.  See
+      // target_at() for where this is converted back to kEndOfChain.
+      target_pos = pc_offset();
+      if (!trampoline_emitted_) {
+        unbound_labels_count_++;
+        next_buffer_check_ -= kTrampolineSlotsSize;
+      }
+    }
+    L->link_to(pc_offset());
+  }
+
+  return target_pos - pc_offset();
+}
+
+
+// Branch instructions.
+
+
+void Assembler::bclr(BOfield bo, LKBit lk) {
+  positions_recorder()->WriteRecordedPositions();
+  emit(EXT1 | bo | BCLRX | lk);
+}
+
+
+void Assembler::bcctr(BOfield bo, LKBit lk) {
+  positions_recorder()->WriteRecordedPositions();
+  emit(EXT1 | bo | BCCTRX | lk);
+}
+
+
+// Pseudo op - branch to link register
+void Assembler::blr() { bclr(BA, LeaveLK); }
+
+
+// Pseudo op - branch to count register -- used for "jump"
+void Assembler::bctr() { bcctr(BA, LeaveLK); }
+
+
+void Assembler::bctrl() { bcctr(BA, SetLK); }
+
+
+void Assembler::bc(int branch_offset, BOfield bo, int condition_bit, LKBit lk) {
+  if (lk == SetLK) {
+    positions_recorder()->WriteRecordedPositions();
+  }
+  DCHECK(is_int16(branch_offset));
+  emit(BCX | bo | condition_bit * B16 | (kImm16Mask & branch_offset) | lk);
+}
+
+
+void Assembler::b(int branch_offset, LKBit lk) {
+  if (lk == SetLK) {
+    positions_recorder()->WriteRecordedPositions();
+  }
+  DCHECK((branch_offset & 3) == 0);
+  int imm26 = branch_offset;
+  DCHECK(is_int26(imm26));
+  // todo add AA and LK bits
+  emit(BX | (imm26 & kImm26Mask) | lk);
+}
+
+
+void Assembler::xori(Register dst, Register src, const Operand& imm) {
+  d_form(XORI, src, dst, imm.imm_, false);
+}
+
+
+void Assembler::xoris(Register ra, Register rs, const Operand& imm) {
+  d_form(XORIS, rs, ra, imm.imm_, false);
+}
+
+
+void Assembler::xor_(Register dst, Register src1, Register src2, RCBit rc) {
+  x_form(EXT2 | XORX, dst, src1, src2, rc);
+}
+
+
+void Assembler::cntlzw_(Register ra, Register rs, RCBit rc) {
+  x_form(EXT2 | CNTLZWX, ra, rs, r0, rc);
+}
+
+
+void Assembler::and_(Register ra, Register rs, Register rb, RCBit rc) {
+  x_form(EXT2 | ANDX, ra, rs, rb, rc);
+}
+
+
+void Assembler::rlwinm(Register ra, Register rs, int sh, int mb, int me,
+                       RCBit rc) {
+  sh &= 0x1f;
+  mb &= 0x1f;
+  me &= 0x1f;
+  emit(RLWINMX | rs.code() * B21 | ra.code() * B16 | sh * B11 | mb * B6 |
+       me << 1 | rc);
+}
+
+
+void Assembler::rlwnm(Register ra, Register rs, Register rb, int mb, int me,
+                      RCBit rc) {
+  mb &= 0x1f;
+  me &= 0x1f;
+  emit(RLWNMX | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 | mb * B6 |
+       me << 1 | rc);
+}
+
+
+void Assembler::rlwimi(Register ra, Register rs, int sh, int mb, int me,
+                       RCBit rc) {
+  sh &= 0x1f;
+  mb &= 0x1f;
+  me &= 0x1f;
+  emit(RLWIMIX | rs.code() * B21 | ra.code() * B16 | sh * B11 | mb * B6 |
+       me << 1 | rc);
+}
+
+
+void Assembler::slwi(Register dst, Register src, const Operand& val, RCBit rc) {
+  DCHECK((32 > val.imm_) && (val.imm_ >= 0));
+  rlwinm(dst, src, val.imm_, 0, 31 - val.imm_, rc);
+}
+
+
+void Assembler::srwi(Register dst, Register src, const Operand& val, RCBit rc) {
+  DCHECK((32 > val.imm_) && (val.imm_ >= 0));
+  rlwinm(dst, src, 32 - val.imm_, val.imm_, 31, rc);
+}
+
+
+void Assembler::clrrwi(Register dst, Register src, const Operand& val,
+                       RCBit rc) {
+  DCHECK((32 > val.imm_) && (val.imm_ >= 0));
+  rlwinm(dst, src, 0, 0, 31 - val.imm_, rc);
+}
+
+
+void Assembler::clrlwi(Register dst, Register src, const Operand& val,
+                       RCBit rc) {
+  DCHECK((32 > val.imm_) && (val.imm_ >= 0));
+  rlwinm(dst, src, 0, val.imm_, 31, rc);
+}
+
+
+void Assembler::srawi(Register ra, Register rs, int sh, RCBit r) {
+  emit(EXT2 | SRAWIX | rs.code() * B21 | ra.code() * B16 | sh * B11 | r);
+}
+
+
+void Assembler::srw(Register dst, Register src1, Register src2, RCBit r) {
+  x_form(EXT2 | SRWX, dst, src1, src2, r);
+}
+
+
+void Assembler::slw(Register dst, Register src1, Register src2, RCBit r) {
+  x_form(EXT2 | SLWX, dst, src1, src2, r);
+}
+
+
+void Assembler::sraw(Register ra, Register rs, Register rb, RCBit r) {
+  x_form(EXT2 | SRAW, ra, rs, rb, r);
+}
+
+
+void Assembler::rotlw(Register ra, Register rs, Register rb, RCBit r) {
+  rlwnm(ra, rs, rb, 0, 31, r);
+}
+
+
+void Assembler::rotlwi(Register ra, Register rs, int sh, RCBit r) {
+  rlwinm(ra, rs, sh, 0, 31, r);
+}
+
+
+void Assembler::rotrwi(Register ra, Register rs, int sh, RCBit r) {
+  rlwinm(ra, rs, 32 - sh, 0, 31, r);
+}
+
+
+void Assembler::subi(Register dst, Register src, const Operand& imm) {
+  addi(dst, src, Operand(-(imm.imm_)));
+}
+
+void Assembler::addc(Register dst, Register src1, Register src2, OEBit o,
+                     RCBit r) {
+  xo_form(EXT2 | ADDCX, dst, src1, src2, o, r);
+}
+
+
+void Assembler::addze(Register dst, Register src1, OEBit o, RCBit r) {
+  // a special xo_form
+  emit(EXT2 | ADDZEX | dst.code() * B21 | src1.code() * B16 | o | r);
+}
+
+
+void Assembler::sub(Register dst, Register src1, Register src2, OEBit o,
+                    RCBit r) {
+  xo_form(EXT2 | SUBFX, dst, src2, src1, o, r);
+}
+
+
+void Assembler::subfc(Register dst, Register src1, Register src2, OEBit o,
+                      RCBit r) {
+  xo_form(EXT2 | SUBFCX, dst, src2, src1, o, r);
+}
+
+
+void Assembler::subfic(Register dst, Register src, const Operand& imm) {
+  d_form(SUBFIC, dst, src, imm.imm_, true);
+}
+
+
+void Assembler::add(Register dst, Register src1, Register src2, OEBit o,
+                    RCBit r) {
+  xo_form(EXT2 | ADDX, dst, src1, src2, o, r);
+}
+
+
+// Multiply low word
+void Assembler::mullw(Register dst, Register src1, Register src2, OEBit o,
+                      RCBit r) {
+  xo_form(EXT2 | MULLW, dst, src1, src2, o, r);
+}
+
+
+// Multiply hi word
+void Assembler::mulhw(Register dst, Register src1, Register src2, OEBit o,
+                      RCBit r) {
+  xo_form(EXT2 | MULHWX, dst, src1, src2, o, r);
+}
+
+
+// Divide word
+void Assembler::divw(Register dst, Register src1, Register src2, OEBit o,
+                     RCBit r) {
+  xo_form(EXT2 | DIVW, dst, src1, src2, o, r);
+}
+
+
+void Assembler::addi(Register dst, Register src, const Operand& imm) {
+  DCHECK(!src.is(r0));  // use li instead to show intent
+  d_form(ADDI, dst, src, imm.imm_, true);
+}
+
+
+void Assembler::addis(Register dst, Register src, const Operand& imm) {
+  DCHECK(!src.is(r0));  // use lis instead to show intent
+  d_form(ADDIS, dst, src, imm.imm_, true);
+}
+
+
+void Assembler::addic(Register dst, Register src, const Operand& imm) {
+  d_form(ADDIC, dst, src, imm.imm_, true);
+}
+
+
+void Assembler::andi(Register ra, Register rs, const Operand& imm) {
+  d_form(ANDIx, rs, ra, imm.imm_, false);
+}
+
+
+void Assembler::andis(Register ra, Register rs, const Operand& imm) {
+  d_form(ANDISx, rs, ra, imm.imm_, false);
+}
+
+
+void Assembler::nor(Register dst, Register src1, Register src2, RCBit r) {
+  x_form(EXT2 | NORX, dst, src1, src2, r);
+}
+
+
+void Assembler::notx(Register dst, Register src, RCBit r) {
+  x_form(EXT2 | NORX, dst, src, src, r);
+}
+
+
+void Assembler::ori(Register ra, Register rs, const Operand& imm) {
+  d_form(ORI, rs, ra, imm.imm_, false);
+}
+
+
+void Assembler::oris(Register dst, Register src, const Operand& imm) {
+  d_form(ORIS, src, dst, imm.imm_, false);
+}
+
+
+void Assembler::orx(Register dst, Register src1, Register src2, RCBit rc) {
+  x_form(EXT2 | ORX, dst, src1, src2, rc);
+}
+
+
+void Assembler::cmpi(Register src1, const Operand& src2, CRegister cr) {
+  intptr_t imm16 = src2.imm_;
+#if V8_TARGET_ARCH_PPC64
+  int L = 1;
+#else
+  int L = 0;
+#endif
+  DCHECK(is_int16(imm16));
+  DCHECK(cr.code() >= 0 && cr.code() <= 7);
+  imm16 &= kImm16Mask;
+  emit(CMPI | cr.code() * B23 | L * B21 | src1.code() * B16 | imm16);
+}
+
+
+void Assembler::cmpli(Register src1, const Operand& src2, CRegister cr) {
+  uintptr_t uimm16 = src2.imm_;
+#if V8_TARGET_ARCH_PPC64
+  int L = 1;
+#else
+  int L = 0;
+#endif
+  DCHECK(is_uint16(uimm16));
+  DCHECK(cr.code() >= 0 && cr.code() <= 7);
+  uimm16 &= kImm16Mask;
+  emit(CMPLI | cr.code() * B23 | L * B21 | src1.code() * B16 | uimm16);
+}
+
+
+void Assembler::cmp(Register src1, Register src2, CRegister cr) {
+#if V8_TARGET_ARCH_PPC64
+  int L = 1;
+#else
+  int L = 0;
+#endif
+  DCHECK(cr.code() >= 0 && cr.code() <= 7);
+  emit(EXT2 | CMP | cr.code() * B23 | L * B21 | src1.code() * B16 |
+       src2.code() * B11);
+}
+
+
+void Assembler::cmpl(Register src1, Register src2, CRegister cr) {
+#if V8_TARGET_ARCH_PPC64
+  int L = 1;
+#else
+  int L = 0;
+#endif
+  DCHECK(cr.code() >= 0 && cr.code() <= 7);
+  emit(EXT2 | CMPL | cr.code() * B23 | L * B21 | src1.code() * B16 |
+       src2.code() * B11);
+}
+
+
+void Assembler::cmpwi(Register src1, const Operand& src2, CRegister cr) {
+  intptr_t imm16 = src2.imm_;
+  int L = 0;
+  DCHECK(is_int16(imm16));
+  DCHECK(cr.code() >= 0 && cr.code() <= 7);
+  imm16 &= kImm16Mask;
+  emit(CMPI | cr.code() * B23 | L * B21 | src1.code() * B16 | imm16);
+}
+
+
+void Assembler::cmplwi(Register src1, const Operand& src2, CRegister cr) {
+  uintptr_t uimm16 = src2.imm_;
+  int L = 0;
+  DCHECK(is_uint16(uimm16));
+  DCHECK(cr.code() >= 0 && cr.code() <= 7);
+  uimm16 &= kImm16Mask;
+  emit(CMPLI | cr.code() * B23 | L * B21 | src1.code() * B16 | uimm16);
+}
+
+
+void Assembler::cmpw(Register src1, Register src2, CRegister cr) {
+  int L = 0;
+  DCHECK(cr.code() >= 0 && cr.code() <= 7);
+  emit(EXT2 | CMP | cr.code() * B23 | L * B21 | src1.code() * B16 |
+       src2.code() * B11);
+}
+
+
+void Assembler::cmplw(Register src1, Register src2, CRegister cr) {
+  int L = 0;
+  DCHECK(cr.code() >= 0 && cr.code() <= 7);
+  emit(EXT2 | CMPL | cr.code() * B23 | L * B21 | src1.code() * B16 |
+       src2.code() * B11);
+}
+
+
+// Pseudo op - load immediate
+void Assembler::li(Register dst, const Operand& imm) {
+  d_form(ADDI, dst, r0, imm.imm_, true);
+}
+
+
+void Assembler::lis(Register dst, const Operand& imm) {
+  d_form(ADDIS, dst, r0, imm.imm_, true);
+}
+
+
+// Pseudo op - move register
+void Assembler::mr(Register dst, Register src) {
+  // actually or(dst, src, src)
+  orx(dst, src, src);
+}
+
+
+void Assembler::lbz(Register dst, const MemOperand& src) {
+  DCHECK(!src.ra_.is(r0));
+  d_form(LBZ, dst, src.ra(), src.offset(), true);
+}
+
+
+void Assembler::lbzx(Register rt, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | LBZX | rt.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::lbzux(Register rt, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | LBZUX | rt.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::lhz(Register dst, const MemOperand& src) {
+  DCHECK(!src.ra_.is(r0));
+  d_form(LHZ, dst, src.ra(), src.offset(), true);
+}
+
+
+void Assembler::lhzx(Register rt, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | LHZX | rt.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::lhzux(Register rt, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | LHZUX | rt.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::lwz(Register dst, const MemOperand& src) {
+  DCHECK(!src.ra_.is(r0));
+  d_form(LWZ, dst, src.ra(), src.offset(), true);
+}
+
+
+void Assembler::lwzu(Register dst, const MemOperand& src) {
+  DCHECK(!src.ra_.is(r0));
+  d_form(LWZU, dst, src.ra(), src.offset(), true);
+}
+
+
+void Assembler::lwzx(Register rt, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | LWZX | rt.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::lwzux(Register rt, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | LWZUX | rt.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::lwa(Register dst, const MemOperand& src) {
+#if V8_TARGET_ARCH_PPC64
+  int offset = src.offset();
+  DCHECK(!src.ra_.is(r0));
+  DCHECK(!(offset & 3) && is_int16(offset));
+  offset = kImm16Mask & offset;
+  emit(LD | dst.code() * B21 | src.ra().code() * B16 | offset | 2);
+#else
+  lwz(dst, src);
+#endif
+}
+
+
+void Assembler::stb(Register dst, const MemOperand& src) {
+  DCHECK(!src.ra_.is(r0));
+  d_form(STB, dst, src.ra(), src.offset(), true);
+}
+
+
+void Assembler::stbx(Register rs, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | STBX | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::stbux(Register rs, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | STBUX | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::sth(Register dst, const MemOperand& src) {
+  DCHECK(!src.ra_.is(r0));
+  d_form(STH, dst, src.ra(), src.offset(), true);
+}
+
+
+void Assembler::sthx(Register rs, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | STHX | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::sthux(Register rs, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | STHUX | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::stw(Register dst, const MemOperand& src) {
+  DCHECK(!src.ra_.is(r0));
+  d_form(STW, dst, src.ra(), src.offset(), true);
+}
+
+
+void Assembler::stwu(Register dst, const MemOperand& src) {
+  DCHECK(!src.ra_.is(r0));
+  d_form(STWU, dst, src.ra(), src.offset(), true);
+}
+
+
+void Assembler::stwx(Register rs, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | STWX | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::stwux(Register rs, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | STWUX | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::extsb(Register rs, Register ra, RCBit rc) {
+  emit(EXT2 | EXTSB | ra.code() * B21 | rs.code() * B16 | rc);
+}
+
+
+void Assembler::extsh(Register rs, Register ra, RCBit rc) {
+  emit(EXT2 | EXTSH | ra.code() * B21 | rs.code() * B16 | rc);
+}
+
+
+void Assembler::neg(Register rt, Register ra, OEBit o, RCBit r) {
+  emit(EXT2 | NEGX | rt.code() * B21 | ra.code() * B16 | o | r);
+}
+
+
+void Assembler::andc(Register dst, Register src1, Register src2, RCBit rc) {
+  x_form(EXT2 | ANDCX, dst, src1, src2, rc);
+}
+
+
+#if V8_TARGET_ARCH_PPC64
+// 64bit specific instructions
+void Assembler::ld(Register rd, const MemOperand& src) {
+  int offset = src.offset();
+  DCHECK(!src.ra_.is(r0));
+  DCHECK(!(offset & 3) && is_int16(offset));
+  offset = kImm16Mask & offset;
+  emit(LD | rd.code() * B21 | src.ra().code() * B16 | offset);
+}
+
+
+void Assembler::ldx(Register rd, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | LDX | rd.code() * B21 | ra.code() * B16 | rb.code() * B11);
+}
+
+
+void Assembler::ldu(Register rd, const MemOperand& src) {
+  int offset = src.offset();
+  DCHECK(!src.ra_.is(r0));
+  DCHECK(!(offset & 3) && is_int16(offset));
+  offset = kImm16Mask & offset;
+  emit(LD | rd.code() * B21 | src.ra().code() * B16 | offset | 1);
+}
+
+
+void Assembler::ldux(Register rd, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | LDUX | rd.code() * B21 | ra.code() * B16 | rb.code() * B11);
+}
+
+
+void Assembler::std(Register rs, const MemOperand& src) {
+  int offset = src.offset();
+  DCHECK(!src.ra_.is(r0));
+  DCHECK(!(offset & 3) && is_int16(offset));
+  offset = kImm16Mask & offset;
+  emit(STD | rs.code() * B21 | src.ra().code() * B16 | offset);
+}
+
+
+void Assembler::stdx(Register rs, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | STDX | rs.code() * B21 | ra.code() * B16 | rb.code() * B11);
+}
+
+
+void Assembler::stdu(Register rs, const MemOperand& src) {
+  int offset = src.offset();
+  DCHECK(!src.ra_.is(r0));
+  DCHECK(!(offset & 3) && is_int16(offset));
+  offset = kImm16Mask & offset;
+  emit(STD | rs.code() * B21 | src.ra().code() * B16 | offset | 1);
+}
+
+
+void Assembler::stdux(Register rs, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | STDUX | rs.code() * B21 | ra.code() * B16 | rb.code() * B11);
+}
+
+
+void Assembler::rldic(Register ra, Register rs, int sh, int mb, RCBit r) {
+  md_form(EXT5 | RLDIC, ra, rs, sh, mb, r);
+}
+
+
+void Assembler::rldicl(Register ra, Register rs, int sh, int mb, RCBit r) {
+  md_form(EXT5 | RLDICL, ra, rs, sh, mb, r);
+}
+
+
+void Assembler::rldcl(Register ra, Register rs, Register rb, int mb, RCBit r) {
+  mds_form(EXT5 | RLDCL, ra, rs, rb, mb, r);
+}
+
+
+void Assembler::rldicr(Register ra, Register rs, int sh, int me, RCBit r) {
+  md_form(EXT5 | RLDICR, ra, rs, sh, me, r);
+}
+
+
+void Assembler::sldi(Register dst, Register src, const Operand& val, RCBit rc) {
+  DCHECK((64 > val.imm_) && (val.imm_ >= 0));
+  rldicr(dst, src, val.imm_, 63 - val.imm_, rc);
+}
+
+
+void Assembler::srdi(Register dst, Register src, const Operand& val, RCBit rc) {
+  DCHECK((64 > val.imm_) && (val.imm_ >= 0));
+  rldicl(dst, src, 64 - val.imm_, val.imm_, rc);
+}
+
+
+void Assembler::clrrdi(Register dst, Register src, const Operand& val,
+                       RCBit rc) {
+  DCHECK((64 > val.imm_) && (val.imm_ >= 0));
+  rldicr(dst, src, 0, 63 - val.imm_, rc);
+}
+
+
+void Assembler::clrldi(Register dst, Register src, const Operand& val,
+                       RCBit rc) {
+  DCHECK((64 > val.imm_) && (val.imm_ >= 0));
+  rldicl(dst, src, 0, val.imm_, rc);
+}
+
+
+void Assembler::rldimi(Register ra, Register rs, int sh, int mb, RCBit r) {
+  md_form(EXT5 | RLDIMI, ra, rs, sh, mb, r);
+}
+
+
+void Assembler::sradi(Register ra, Register rs, int sh, RCBit r) {
+  int sh0_4 = sh & 0x1f;
+  int sh5 = (sh >> 5) & 0x1;
+
+  emit(EXT2 | SRADIX | rs.code() * B21 | ra.code() * B16 | sh0_4 * B11 |
+       sh5 * B1 | r);
+}
+
+
+void Assembler::srd(Register dst, Register src1, Register src2, RCBit r) {
+  x_form(EXT2 | SRDX, dst, src1, src2, r);
+}
+
+
+void Assembler::sld(Register dst, Register src1, Register src2, RCBit r) {
+  x_form(EXT2 | SLDX, dst, src1, src2, r);
+}
+
+
+void Assembler::srad(Register ra, Register rs, Register rb, RCBit r) {
+  x_form(EXT2 | SRAD, ra, rs, rb, r);
+}
+
+
+void Assembler::rotld(Register ra, Register rs, Register rb, RCBit r) {
+  rldcl(ra, rs, rb, 0, r);
+}
+
+
+void Assembler::rotldi(Register ra, Register rs, int sh, RCBit r) {
+  rldicl(ra, rs, sh, 0, r);
+}
+
+
+void Assembler::rotrdi(Register ra, Register rs, int sh, RCBit r) {
+  rldicl(ra, rs, 64 - sh, 0, r);
+}
+
+
+void Assembler::cntlzd_(Register ra, Register rs, RCBit rc) {
+  x_form(EXT2 | CNTLZDX, ra, rs, r0, rc);
+}
+
+
+void Assembler::extsw(Register rs, Register ra, RCBit rc) {
+  emit(EXT2 | EXTSW | ra.code() * B21 | rs.code() * B16 | rc);
+}
+
+
+void Assembler::mulld(Register dst, Register src1, Register src2, OEBit o,
+                      RCBit r) {
+  xo_form(EXT2 | MULLD, dst, src1, src2, o, r);
+}
+
+
+void Assembler::divd(Register dst, Register src1, Register src2, OEBit o,
+                     RCBit r) {
+  xo_form(EXT2 | DIVD, dst, src1, src2, o, r);
+}
+#endif
+
+
+void Assembler::fake_asm(enum FAKE_OPCODE_T fopcode) {
+  DCHECK(fopcode < fLastFaker);
+  emit(FAKE_OPCODE | FAKER_SUBOPCODE | fopcode);
+}
+
+
+void Assembler::marker_asm(int mcode) {
+  if (::v8::internal::FLAG_trace_sim_stubs) {
+    DCHECK(mcode < F_NEXT_AVAILABLE_STUB_MARKER);
+    emit(FAKE_OPCODE | MARKER_SUBOPCODE | mcode);
+  }
+}
+
+
+// Function descriptor for AIX.
+// Code address skips the function descriptor "header".
+// TOC and static chain are ignored and set to 0.
+void Assembler::function_descriptor() {
+  DCHECK(pc_offset() == 0);
+  RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
+  emit_ptr(reinterpret_cast<uintptr_t>(pc_) + 3 * kPointerSize);
+  emit_ptr(0);
+  emit_ptr(0);
+}
+
+
+#if ABI_USES_FUNCTION_DESCRIPTORS || V8_OOL_CONSTANT_POOL
+void Assembler::RelocateInternalReference(Address pc, intptr_t delta,
+                                          Address code_start,
+                                          ICacheFlushMode icache_flush_mode) {
+  DCHECK(delta || code_start);
+#if ABI_USES_FUNCTION_DESCRIPTORS
+  uintptr_t* fd = reinterpret_cast<uintptr_t*>(pc);
+  if (fd[1] == 0 && fd[2] == 0) {
+    // Function descriptor
+    if (delta) {
+      fd[0] += delta;
+    } else {
+      fd[0] = reinterpret_cast<uintptr_t>(code_start) + 3 * kPointerSize;
+    }
+    return;
+  }
+#endif
+#if V8_OOL_CONSTANT_POOL
+  // mov for LoadConstantPoolPointerRegister
+  ConstantPoolArray* constant_pool = NULL;
+  if (delta) {
+    code_start = target_address_at(pc, constant_pool) + delta;
+  }
+  set_target_address_at(pc, constant_pool, code_start, icache_flush_mode);
+#endif
+}
+
+
+int Assembler::DecodeInternalReference(Vector<char> buffer, Address pc) {
+#if ABI_USES_FUNCTION_DESCRIPTORS
+  uintptr_t* fd = reinterpret_cast<uintptr_t*>(pc);
+  if (fd[1] == 0 && fd[2] == 0) {
+    // Function descriptor
+    SNPrintF(buffer, "[%08" V8PRIxPTR ", %08" V8PRIxPTR ", %08" V8PRIxPTR
+                     "]"
+                     "   function descriptor",
+             fd[0], fd[1], fd[2]);
+    return kPointerSize * 3;
+  }
+#endif
+  return 0;
+}
+#endif
+
+
+int Assembler::instructions_required_for_mov(const Operand& x) const {
+#if V8_OOL_CONSTANT_POOL || DEBUG
+  bool canOptimize =
+      !(x.must_output_reloc_info(this) || is_trampoline_pool_blocked());
+#endif
+#if V8_OOL_CONSTANT_POOL
+  if (use_constant_pool_for_mov(x, canOptimize)) {
+    // Current usage guarantees that all constant pool references can
+    // use the same sequence.
+    return kMovInstructionsConstantPool;
+  }
+#endif
+  DCHECK(!canOptimize);
+  return kMovInstructionsNoConstantPool;
+}
+
+
+#if V8_OOL_CONSTANT_POOL
+bool Assembler::use_constant_pool_for_mov(const Operand& x,
+                                          bool canOptimize) const {
+  if (!is_ool_constant_pool_available() || is_constant_pool_full()) {
+    // If there is no constant pool available, we must use a mov
+    // immediate sequence.
+    return false;
+  }
+
+  intptr_t value = x.immediate();
+  if (canOptimize && is_int16(value)) {
+    // Prefer a single-instruction load-immediate.
+    return false;
+  }
+
+  return true;
+}
+
+
+void Assembler::EnsureSpaceFor(int space_needed) {
+  if (buffer_space() <= (kGap + space_needed)) {
+    GrowBuffer();
+  }
+}
+#endif
+
+
+bool Operand::must_output_reloc_info(const Assembler* assembler) const {
+  if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) {
+    if (assembler != NULL && assembler->predictable_code_size()) return true;
+    return assembler->serializer_enabled();
+  } else if (RelocInfo::IsNone(rmode_)) {
+    return false;
+  }
+  return true;
+}
+
+
+// Primarily used for loading constants
+// This should really move to be in macro-assembler as it
+// is really a pseudo instruction
+// Some usages of this intend for a FIXED_SEQUENCE to be used
+// Todo - break this dependency so we can optimize mov() in general
+// and only use the generic version when we require a fixed sequence
+void Assembler::mov(Register dst, const Operand& src) {
+  intptr_t value = src.immediate();
+  bool canOptimize;
+  RelocInfo rinfo(pc_, src.rmode_, value, NULL);
+
+  if (src.must_output_reloc_info(this)) {
+    RecordRelocInfo(rinfo);
+  }
+
+  canOptimize =
+      !(src.must_output_reloc_info(this) || is_trampoline_pool_blocked());
+
+#if V8_OOL_CONSTANT_POOL
+  if (use_constant_pool_for_mov(src, canOptimize)) {
+    DCHECK(is_ool_constant_pool_available());
+    ConstantPoolAddEntry(rinfo);
+#if V8_TARGET_ARCH_PPC64
+    BlockTrampolinePoolScope block_trampoline_pool(this);
+    // We are forced to use 2 instruction sequence since the constant
+    // pool pointer is tagged.
+    li(dst, Operand::Zero());
+    ldx(dst, MemOperand(kConstantPoolRegister, dst));
+#else
+    lwz(dst, MemOperand(kConstantPoolRegister, 0));
+#endif
+    return;
+  }
+#endif
+
+  if (canOptimize) {
+    if (is_int16(value)) {
+      li(dst, Operand(value));
+    } else {
+      uint16_t u16;
+#if V8_TARGET_ARCH_PPC64
+      if (is_int32(value)) {
+#endif
+        lis(dst, Operand(value >> 16));
+#if V8_TARGET_ARCH_PPC64
+      } else {
+        if (is_int48(value)) {
+          li(dst, Operand(value >> 32));
+        } else {
+          lis(dst, Operand(value >> 48));
+          u16 = ((value >> 32) & 0xffff);
+          if (u16) {
+            ori(dst, dst, Operand(u16));
+          }
+        }
+        sldi(dst, dst, Operand(32));
+        u16 = ((value >> 16) & 0xffff);
+        if (u16) {
+          oris(dst, dst, Operand(u16));
+        }
+      }
+#endif
+      u16 = (value & 0xffff);
+      if (u16) {
+        ori(dst, dst, Operand(u16));
+      }
+    }
+    return;
+  }
+
+  DCHECK(!canOptimize);
+
+  {
+    BlockTrampolinePoolScope block_trampoline_pool(this);
+#if V8_TARGET_ARCH_PPC64
+    int32_t hi_32 = static_cast<int32_t>(value >> 32);
+    int32_t lo_32 = static_cast<int32_t>(value);
+    int hi_word = static_cast<int>(hi_32 >> 16);
+    int lo_word = static_cast<int>(hi_32 & 0xffff);
+    lis(dst, Operand(SIGN_EXT_IMM16(hi_word)));
+    ori(dst, dst, Operand(lo_word));
+    sldi(dst, dst, Operand(32));
+    hi_word = static_cast<int>(((lo_32 >> 16) & 0xffff));
+    lo_word = static_cast<int>(lo_32 & 0xffff);
+    oris(dst, dst, Operand(hi_word));
+    ori(dst, dst, Operand(lo_word));
+#else
+    int hi_word = static_cast<int>(value >> 16);
+    int lo_word = static_cast<int>(value & 0xffff);
+    lis(dst, Operand(SIGN_EXT_IMM16(hi_word)));
+    ori(dst, dst, Operand(lo_word));
+#endif
+  }
+}
+
+
+void Assembler::mov_label_offset(Register dst, Label* label) {
+  if (label->is_bound()) {
+    int target = label->pos();
+    mov(dst, Operand(target + Code::kHeaderSize - kHeapObjectTag));
+  } else {
+    bool is_linked = label->is_linked();
+    // Emit the link to the label in the code stream followed by extra
+    // nop instructions.
+    DCHECK(dst.is(r3));  // target_at_put assumes r3 for now
+    int link = is_linked ? label->pos() - pc_offset() : 0;
+    label->link_to(pc_offset());
+
+    if (!is_linked && !trampoline_emitted_) {
+      unbound_labels_count_++;
+      next_buffer_check_ -= kTrampolineSlotsSize;
+    }
+
+    // When the label is bound, these instructions will be patched
+    // with a 2 instruction mov sequence that will load the
+    // destination register with the position of the label from the
+    // beginning of the code.
+    //
+    // When the label gets bound: target_at extracts the link and
+    // target_at_put patches the instructions.
+    BlockTrampolinePoolScope block_trampoline_pool(this);
+    emit(link);
+    nop();
+  }
+}
+
+
+// Special register instructions
+void Assembler::crxor(int bt, int ba, int bb) {
+  emit(EXT1 | CRXOR | bt * B21 | ba * B16 | bb * B11);
+}
+
+
+void Assembler::creqv(int bt, int ba, int bb) {
+  emit(EXT1 | CREQV | bt * B21 | ba * B16 | bb * B11);
+}
+
+
+void Assembler::mflr(Register dst) {
+  emit(EXT2 | MFSPR | dst.code() * B21 | 256 << 11);  // Ignore RC bit
+}
+
+
+void Assembler::mtlr(Register src) {
+  emit(EXT2 | MTSPR | src.code() * B21 | 256 << 11);  // Ignore RC bit
+}
+
+
+void Assembler::mtctr(Register src) {
+  emit(EXT2 | MTSPR | src.code() * B21 | 288 << 11);  // Ignore RC bit
+}
+
+
+void Assembler::mtxer(Register src) {
+  emit(EXT2 | MTSPR | src.code() * B21 | 32 << 11);
+}
+
+
+void Assembler::mcrfs(int bf, int bfa) {
+  emit(EXT4 | MCRFS | bf * B23 | bfa * B18);
+}
+
+
+void Assembler::mfcr(Register dst) { emit(EXT2 | MFCR | dst.code() * B21); }
+
+
+#if V8_TARGET_ARCH_PPC64
+void Assembler::mffprd(Register dst, DoubleRegister src) {
+  emit(EXT2 | MFVSRD | src.code() * B21 | dst.code() * B16);
+}
+
+
+void Assembler::mffprwz(Register dst, DoubleRegister src) {
+  emit(EXT2 | MFVSRWZ | src.code() * B21 | dst.code() * B16);
+}
+
+
+void Assembler::mtfprd(DoubleRegister dst, Register src) {
+  emit(EXT2 | MTVSRD | dst.code() * B21 | src.code() * B16);
+}
+
+
+void Assembler::mtfprwz(DoubleRegister dst, Register src) {
+  emit(EXT2 | MTVSRWZ | dst.code() * B21 | src.code() * B16);
+}
+
+
+void Assembler::mtfprwa(DoubleRegister dst, Register src) {
+  emit(EXT2 | MTVSRWA | dst.code() * B21 | src.code() * B16);
+}
+#endif
+
+
+// Exception-generating instructions and debugging support.
+// Stops with a non-negative code less than kNumOfWatchedStops support
+// enabling/disabling and a counter feature. See simulator-ppc.h .
+void Assembler::stop(const char* msg, Condition cond, int32_t code,
+                     CRegister cr) {
+  if (cond != al) {
+    Label skip;
+    b(NegateCondition(cond), &skip, cr);
+    bkpt(0);
+    bind(&skip);
+  } else {
+    bkpt(0);
+  }
+}
+
+
+void Assembler::bkpt(uint32_t imm16) { emit(0x7d821008); }
+
+
+void Assembler::info(const char* msg, Condition cond, int32_t code,
+                     CRegister cr) {
+  if (::v8::internal::FLAG_trace_sim_stubs) {
+    emit(0x7d9ff808);
+#if V8_TARGET_ARCH_PPC64
+    uint64_t value = reinterpret_cast<uint64_t>(msg);
+    emit(static_cast<uint32_t>(value >> 32));
+    emit(static_cast<uint32_t>(value & 0xFFFFFFFF));
+#else
+    emit(reinterpret_cast<Instr>(msg));
+#endif
+  }
+}
+
+
+void Assembler::dcbf(Register ra, Register rb) {
+  emit(EXT2 | DCBF | ra.code() * B16 | rb.code() * B11);
+}
+
+
+void Assembler::sync() { emit(EXT2 | SYNC); }
+
+
+void Assembler::lwsync() { emit(EXT2 | SYNC | 1 * B21); }
+
+
+void Assembler::icbi(Register ra, Register rb) {
+  emit(EXT2 | ICBI | ra.code() * B16 | rb.code() * B11);
+}
+
+
+void Assembler::isync() { emit(EXT1 | ISYNC); }
+
+
+// Floating point support
+
+void Assembler::lfd(const DoubleRegister frt, const MemOperand& src) {
+  int offset = src.offset();
+  Register ra = src.ra();
+  DCHECK(is_int16(offset));
+  int imm16 = offset & kImm16Mask;
+  // could be x_form instruction with some casting magic
+  emit(LFD | frt.code() * B21 | ra.code() * B16 | imm16);
+}
+
+
+void Assembler::lfdu(const DoubleRegister frt, const MemOperand& src) {
+  int offset = src.offset();
+  Register ra = src.ra();
+  DCHECK(is_int16(offset));
+  int imm16 = offset & kImm16Mask;
+  // could be x_form instruction with some casting magic
+  emit(LFDU | frt.code() * B21 | ra.code() * B16 | imm16);
+}
+
+
+void Assembler::lfdx(const DoubleRegister frt, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | LFDX | frt.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::lfdux(const DoubleRegister frt, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | LFDUX | frt.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::lfs(const DoubleRegister frt, const MemOperand& src) {
+  int offset = src.offset();
+  Register ra = src.ra();
+  DCHECK(is_int16(offset));
+  DCHECK(!ra.is(r0));
+  int imm16 = offset & kImm16Mask;
+  // could be x_form instruction with some casting magic
+  emit(LFS | frt.code() * B21 | ra.code() * B16 | imm16);
+}
+
+
+void Assembler::lfsu(const DoubleRegister frt, const MemOperand& src) {
+  int offset = src.offset();
+  Register ra = src.ra();
+  DCHECK(is_int16(offset));
+  DCHECK(!ra.is(r0));
+  int imm16 = offset & kImm16Mask;
+  // could be x_form instruction with some casting magic
+  emit(LFSU | frt.code() * B21 | ra.code() * B16 | imm16);
+}
+
+
+void Assembler::lfsx(const DoubleRegister frt, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | LFSX | frt.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::lfsux(const DoubleRegister frt, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | LFSUX | frt.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::stfd(const DoubleRegister frs, const MemOperand& src) {
+  int offset = src.offset();
+  Register ra = src.ra();
+  DCHECK(is_int16(offset));
+  DCHECK(!ra.is(r0));
+  int imm16 = offset & kImm16Mask;
+  // could be x_form instruction with some casting magic
+  emit(STFD | frs.code() * B21 | ra.code() * B16 | imm16);
+}
+
+
+void Assembler::stfdu(const DoubleRegister frs, const MemOperand& src) {
+  int offset = src.offset();
+  Register ra = src.ra();
+  DCHECK(is_int16(offset));
+  DCHECK(!ra.is(r0));
+  int imm16 = offset & kImm16Mask;
+  // could be x_form instruction with some casting magic
+  emit(STFDU | frs.code() * B21 | ra.code() * B16 | imm16);
+}
+
+
+void Assembler::stfdx(const DoubleRegister frs, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | STFDX | frs.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::stfdux(const DoubleRegister frs, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | STFDUX | frs.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::stfs(const DoubleRegister frs, const MemOperand& src) {
+  int offset = src.offset();
+  Register ra = src.ra();
+  DCHECK(is_int16(offset));
+  DCHECK(!ra.is(r0));
+  int imm16 = offset & kImm16Mask;
+  // could be x_form instruction with some casting magic
+  emit(STFS | frs.code() * B21 | ra.code() * B16 | imm16);
+}
+
+
+void Assembler::stfsu(const DoubleRegister frs, const MemOperand& src) {
+  int offset = src.offset();
+  Register ra = src.ra();
+  DCHECK(is_int16(offset));
+  DCHECK(!ra.is(r0));
+  int imm16 = offset & kImm16Mask;
+  // could be x_form instruction with some casting magic
+  emit(STFSU | frs.code() * B21 | ra.code() * B16 | imm16);
+}
+
+
+void Assembler::stfsx(const DoubleRegister frs, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | STFSX | frs.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::stfsux(const DoubleRegister frs, const MemOperand& src) {
+  Register ra = src.ra();
+  Register rb = src.rb();
+  DCHECK(!ra.is(r0));
+  emit(EXT2 | STFSUX | frs.code() * B21 | ra.code() * B16 | rb.code() * B11 |
+       LeaveRC);
+}
+
+
+void Assembler::fsub(const DoubleRegister frt, const DoubleRegister fra,
+                     const DoubleRegister frb, RCBit rc) {
+  a_form(EXT4 | FSUB, frt, fra, frb, rc);
+}
+
+
+void Assembler::fadd(const DoubleRegister frt, const DoubleRegister fra,
+                     const DoubleRegister frb, RCBit rc) {
+  a_form(EXT4 | FADD, frt, fra, frb, rc);
+}
+
+
+void Assembler::fmul(const DoubleRegister frt, const DoubleRegister fra,
+                     const DoubleRegister frc, RCBit rc) {
+  emit(EXT4 | FMUL | frt.code() * B21 | fra.code() * B16 | frc.code() * B6 |
+       rc);
+}
+
+
+void Assembler::fdiv(const DoubleRegister frt, const DoubleRegister fra,
+                     const DoubleRegister frb, RCBit rc) {
+  a_form(EXT4 | FDIV, frt, fra, frb, rc);
+}
+
+
+void Assembler::fcmpu(const DoubleRegister fra, const DoubleRegister frb,
+                      CRegister cr) {
+  DCHECK(cr.code() >= 0 && cr.code() <= 7);
+  emit(EXT4 | FCMPU | cr.code() * B23 | fra.code() * B16 | frb.code() * B11);
+}
+
+
+void Assembler::fmr(const DoubleRegister frt, const DoubleRegister frb,
+                    RCBit rc) {
+  emit(EXT4 | FMR | frt.code() * B21 | frb.code() * B11 | rc);
+}
+
+
+void Assembler::fctiwz(const DoubleRegister frt, const DoubleRegister frb) {
+  emit(EXT4 | FCTIWZ | frt.code() * B21 | frb.code() * B11);
+}
+
+
+void Assembler::fctiw(const DoubleRegister frt, const DoubleRegister frb) {
+  emit(EXT4 | FCTIW | frt.code() * B21 | frb.code() * B11);
+}
+
+
+void Assembler::frim(const DoubleRegister frt, const DoubleRegister frb) {
+  emit(EXT4 | FRIM | frt.code() * B21 | frb.code() * B11);
+}
+
+
+void Assembler::frsp(const DoubleRegister frt, const DoubleRegister frb,
+                     RCBit rc) {
+  emit(EXT4 | FRSP | frt.code() * B21 | frb.code() * B11 | rc);
+}
+
+
+void Assembler::fcfid(const DoubleRegister frt, const DoubleRegister frb,
+                      RCBit rc) {
+  emit(EXT4 | FCFID | frt.code() * B21 | frb.code() * B11 | rc);
+}
+
+
+void Assembler::fctid(const DoubleRegister frt, const DoubleRegister frb,
+                      RCBit rc) {
+  emit(EXT4 | FCTID | frt.code() * B21 | frb.code() * B11 | rc);
+}
+
+
+void Assembler::fctidz(const DoubleRegister frt, const DoubleRegister frb,
+                       RCBit rc) {
+  emit(EXT4 | FCTIDZ | frt.code() * B21 | frb.code() * B11 | rc);
+}
+
+
+void Assembler::fsel(const DoubleRegister frt, const DoubleRegister fra,
+                     const DoubleRegister frc, const DoubleRegister frb,
+                     RCBit rc) {
+  emit(EXT4 | FSEL | frt.code() * B21 | fra.code() * B16 | frb.code() * B11 |
+       frc.code() * B6 | rc);
+}
+
+
+void Assembler::fneg(const DoubleRegister frt, const DoubleRegister frb,
+                     RCBit rc) {
+  emit(EXT4 | FNEG | frt.code() * B21 | frb.code() * B11 | rc);
+}
+
+
+void Assembler::mtfsfi(int bf, int immediate, RCBit rc) {
+  emit(EXT4 | MTFSFI | bf * B23 | immediate * B12 | rc);
+}
+
+
+void Assembler::mffs(const DoubleRegister frt, RCBit rc) {
+  emit(EXT4 | MFFS | frt.code() * B21 | rc);
+}
+
+
+void Assembler::mtfsf(const DoubleRegister frb, bool L, int FLM, bool W,
+                      RCBit rc) {
+  emit(EXT4 | MTFSF | frb.code() * B11 | W * B16 | FLM * B17 | L * B25 | rc);
+}
+
+
+void Assembler::fsqrt(const DoubleRegister frt, const DoubleRegister frb,
+                      RCBit rc) {
+  emit(EXT4 | FSQRT | frt.code() * B21 | frb.code() * B11 | rc);
+}
+
+
+void Assembler::fabs(const DoubleRegister frt, const DoubleRegister frb,
+                     RCBit rc) {
+  emit(EXT4 | FABS | frt.code() * B21 | frb.code() * B11 | rc);
+}
+
+
+void Assembler::fmadd(const DoubleRegister frt, const DoubleRegister fra,
+                      const DoubleRegister frc, const DoubleRegister frb,
+                      RCBit rc) {
+  emit(EXT4 | FMADD | frt.code() * B21 | fra.code() * B16 | frb.code() * B11 |
+       frc.code() * B6 | rc);
+}
+
+
+void Assembler::fmsub(const DoubleRegister frt, const DoubleRegister fra,
+                      const DoubleRegister frc, const DoubleRegister frb,
+                      RCBit rc) {
+  emit(EXT4 | FMSUB | frt.code() * B21 | fra.code() * B16 | frb.code() * B11 |
+       frc.code() * B6 | rc);
+}
+
+
+// Pseudo instructions.
+void Assembler::nop(int type) {
+  Register reg = r0;
+  switch (type) {
+    case NON_MARKING_NOP:
+      reg = r0;
+      break;
+    case GROUP_ENDING_NOP:
+      reg = r2;
+      break;
+    case DEBUG_BREAK_NOP:
+      reg = r3;
+      break;
+    default:
+      UNIMPLEMENTED();
+  }
+
+  ori(reg, reg, Operand::Zero());
+}
+
+
+bool Assembler::IsNop(Instr instr, int type) {
+  int reg = 0;
+  switch (type) {
+    case NON_MARKING_NOP:
+      reg = 0;
+      break;
+    case GROUP_ENDING_NOP:
+      reg = 2;
+      break;
+    case DEBUG_BREAK_NOP:
+      reg = 3;
+      break;
+    default:
+      UNIMPLEMENTED();
+  }
+  return instr == (ORI | reg * B21 | reg * B16);
+}
+
+
+// Debugging.
+void Assembler::RecordJSReturn() {
+  positions_recorder()->WriteRecordedPositions();
+  CheckBuffer();
+  RecordRelocInfo(RelocInfo::JS_RETURN);
+}
+
+
+void Assembler::RecordDebugBreakSlot() {
+  positions_recorder()->WriteRecordedPositions();
+  CheckBuffer();
+  RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
+}
+
+
+void Assembler::RecordComment(const char* msg) {
+  if (FLAG_code_comments) {
+    CheckBuffer();
+    RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
+  }
+}
+
+
+void Assembler::GrowBuffer() {
+  if (!own_buffer_) FATAL("external code buffer is too small");
+
+  // Compute new buffer size.
+  CodeDesc desc;  // the new buffer
+  if (buffer_size_ < 4 * KB) {
+    desc.buffer_size = 4 * KB;
+  } else if (buffer_size_ < 1 * MB) {
+    desc.buffer_size = 2 * buffer_size_;
+  } else {
+    desc.buffer_size = buffer_size_ + 1 * MB;
+  }
+  CHECK_GT(desc.buffer_size, 0);  // no overflow
+
+  // Set up new buffer.
+  desc.buffer = NewArray<byte>(desc.buffer_size);
+
+  desc.instr_size = pc_offset();
+  desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
+
+  // Copy the data.
+  intptr_t pc_delta = desc.buffer - buffer_;
+  intptr_t rc_delta =
+      (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
+  memmove(desc.buffer, buffer_, desc.instr_size);
+  memmove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
+          desc.reloc_size);
+
+  // Switch buffers.
+  DeleteArray(buffer_);
+  buffer_ = desc.buffer;
+  buffer_size_ = desc.buffer_size;
+  pc_ += pc_delta;
+  reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
+                               reloc_info_writer.last_pc() + pc_delta);
+
+// None of our relocation types are pc relative pointing outside the code
+// buffer nor pc absolute pointing inside the code buffer, so there is no need
+// to relocate any emitted relocation entries.
+
+#if ABI_USES_FUNCTION_DESCRIPTORS || V8_OOL_CONSTANT_POOL
+  // Relocate runtime entries.
+  for (RelocIterator it(desc); !it.done(); it.next()) {
+    RelocInfo::Mode rmode = it.rinfo()->rmode();
+    if (rmode == RelocInfo::INTERNAL_REFERENCE) {
+      RelocateInternalReference(it.rinfo()->pc(), pc_delta, 0);
+    }
+  }
+#if V8_OOL_CONSTANT_POOL
+  constant_pool_builder_.Relocate(pc_delta);
+#endif
+#endif
+}
+
+
+void Assembler::db(uint8_t data) {
+  CheckBuffer();
+  *reinterpret_cast<uint8_t*>(pc_) = data;
+  pc_ += sizeof(uint8_t);
+}
+
+
+void Assembler::dd(uint32_t data) {
+  CheckBuffer();
+  *reinterpret_cast<uint32_t*>(pc_) = data;
+  pc_ += sizeof(uint32_t);
+}
+
+
+void Assembler::emit_ptr(uintptr_t data) {
+  CheckBuffer();
+  *reinterpret_cast<uintptr_t*>(pc_) = data;
+  pc_ += sizeof(uintptr_t);
+}
+
+
+void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
+  RelocInfo rinfo(pc_, rmode, data, NULL);
+  RecordRelocInfo(rinfo);
+}
+
+
+void Assembler::RecordRelocInfo(const RelocInfo& rinfo) {
+  if (rinfo.rmode() >= RelocInfo::JS_RETURN &&
+      rinfo.rmode() <= RelocInfo::DEBUG_BREAK_SLOT) {
+    // Adjust code for new modes.
+    DCHECK(RelocInfo::IsDebugBreakSlot(rinfo.rmode()) ||
+           RelocInfo::IsJSReturn(rinfo.rmode()) ||
+           RelocInfo::IsComment(rinfo.rmode()) ||
+           RelocInfo::IsPosition(rinfo.rmode()));
+  }
+  if (!RelocInfo::IsNone(rinfo.rmode())) {
+    // Don't record external references unless the heap will be serialized.
+    if (rinfo.rmode() == RelocInfo::EXTERNAL_REFERENCE) {
+      if (!serializer_enabled() && !emit_debug_code()) {
+        return;
+      }
+    }
+    DCHECK(buffer_space() >= kMaxRelocSize);  // too late to grow buffer here
+    if (rinfo.rmode() == RelocInfo::CODE_TARGET_WITH_ID) {
+      RelocInfo reloc_info_with_ast_id(rinfo.pc(), rinfo.rmode(),
+                                       RecordedAstId().ToInt(), NULL);
+      ClearRecordedAstId();
+      reloc_info_writer.Write(&reloc_info_with_ast_id);
+    } else {
+      reloc_info_writer.Write(&rinfo);
+    }
+  }
+}
+
+
+void Assembler::BlockTrampolinePoolFor(int instructions) {
+  BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
+}
+
+
+void Assembler::CheckTrampolinePool() {
+  // Some small sequences of instructions must not be broken up by the
+  // insertion of a trampoline pool; such sequences are protected by setting
+  // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
+  // which are both checked here. Also, recursive calls to CheckTrampolinePool
+  // are blocked by trampoline_pool_blocked_nesting_.
+  if ((trampoline_pool_blocked_nesting_ > 0) ||
+      (pc_offset() < no_trampoline_pool_before_)) {
+    // Emission is currently blocked; make sure we try again as soon as
+    // possible.
+    if (trampoline_pool_blocked_nesting_ > 0) {
+      next_buffer_check_ = pc_offset() + kInstrSize;
+    } else {
+      next_buffer_check_ = no_trampoline_pool_before_;
+    }
+    return;
+  }
+
+  DCHECK(!trampoline_emitted_);
+  DCHECK(unbound_labels_count_ >= 0);
+  if (unbound_labels_count_ > 0) {
+    // First we emit jump, then we emit trampoline pool.
+    {
+      BlockTrampolinePoolScope block_trampoline_pool(this);
+      Label after_pool;
+      b(&after_pool);
+
+      int pool_start = pc_offset();
+      for (int i = 0; i < unbound_labels_count_; i++) {
+        b(&after_pool);
+      }
+      bind(&after_pool);
+      trampoline_ = Trampoline(pool_start, unbound_labels_count_);
+
+      trampoline_emitted_ = true;
+      // As we are only going to emit trampoline once, we need to prevent any
+      // further emission.
+      next_buffer_check_ = kMaxInt;
+    }
+  } else {
+    // Number of branches to unbound label at this point is zero, so we can
+    // move next buffer check to maximum.
+    next_buffer_check_ =
+        pc_offset() + kMaxCondBranchReach - kMaxBlockTrampolineSectionSize;
+  }
+  return;
+}
+
+
+Handle<ConstantPoolArray> Assembler::NewConstantPool(Isolate* isolate) {
+#if V8_OOL_CONSTANT_POOL
+  return constant_pool_builder_.New(isolate);
+#else
+  // No out-of-line constant pool support.
+  DCHECK(!FLAG_enable_ool_constant_pool);
+  return isolate->factory()->empty_constant_pool_array();
+#endif
+}
+
+
+void Assembler::PopulateConstantPool(ConstantPoolArray* constant_pool) {
+#if V8_OOL_CONSTANT_POOL
+  constant_pool_builder_.Populate(this, constant_pool);
+#else
+  // No out-of-line constant pool support.
+  DCHECK(!FLAG_enable_ool_constant_pool);
+#endif
+}
+
+
+#if V8_OOL_CONSTANT_POOL
+ConstantPoolBuilder::ConstantPoolBuilder()
+    : size_(0),
+      entries_(),
+      current_section_(ConstantPoolArray::SMALL_SECTION) {}
+
+
+bool ConstantPoolBuilder::IsEmpty() { return entries_.size() == 0; }
+
+
+ConstantPoolArray::Type ConstantPoolBuilder::GetConstantPoolType(
+    RelocInfo::Mode rmode) {
+#if V8_TARGET_ARCH_PPC64
+  // We don't support 32-bit entries at this time.
+  if (!RelocInfo::IsGCRelocMode(rmode)) {
+    return ConstantPoolArray::INT64;
+#else
+  if (rmode == RelocInfo::NONE64) {
+    return ConstantPoolArray::INT64;
+  } else if (!RelocInfo::IsGCRelocMode(rmode)) {
+    return ConstantPoolArray::INT32;
+#endif
+  } else if (RelocInfo::IsCodeTarget(rmode)) {
+    return ConstantPoolArray::CODE_PTR;
+  } else {
+    DCHECK(RelocInfo::IsGCRelocMode(rmode) && !RelocInfo::IsCodeTarget(rmode));
+    return ConstantPoolArray::HEAP_PTR;
+  }
+}
+
+
+ConstantPoolArray::LayoutSection ConstantPoolBuilder::AddEntry(
+    Assembler* assm, const RelocInfo& rinfo) {
+  RelocInfo::Mode rmode = rinfo.rmode();
+  DCHECK(rmode != RelocInfo::COMMENT && rmode != RelocInfo::POSITION &&
+         rmode != RelocInfo::STATEMENT_POSITION &&
+         rmode != RelocInfo::CONST_POOL);
+
+  // Try to merge entries which won't be patched.
+  int merged_index = -1;
+  ConstantPoolArray::LayoutSection entry_section = current_section_;
+  if (RelocInfo::IsNone(rmode) ||
+      (!assm->serializer_enabled() && (rmode >= RelocInfo::CELL))) {
+    size_t i;
+    std::vector<ConstantPoolEntry>::const_iterator it;
+    for (it = entries_.begin(), i = 0; it != entries_.end(); it++, i++) {
+      if (RelocInfo::IsEqual(rinfo, it->rinfo_)) {
+        // Merge with found entry.
+        merged_index = i;
+        entry_section = entries_[i].section_;
+        break;
+      }
+    }
+  }
+  DCHECK(entry_section <= current_section_);
+  entries_.push_back(ConstantPoolEntry(rinfo, entry_section, merged_index));
+
+  if (merged_index == -1) {
+    // Not merged, so update the appropriate count.
+    number_of_entries_[entry_section].increment(GetConstantPoolType(rmode));
+  }
+
+  // Check if we still have room for another entry in the small section
+  // given the limitations of the header's layout fields.
+  if (current_section_ == ConstantPoolArray::SMALL_SECTION) {
+    size_ = ConstantPoolArray::SizeFor(*small_entries());
+    if (!is_uint12(size_)) {
+      current_section_ = ConstantPoolArray::EXTENDED_SECTION;
+    }
+  } else {
+    size_ = ConstantPoolArray::SizeForExtended(*small_entries(),
+                                               *extended_entries());
+  }
+
+  return entry_section;
+}
+
+
+void ConstantPoolBuilder::Relocate(intptr_t pc_delta) {
+  for (std::vector<ConstantPoolEntry>::iterator entry = entries_.begin();
+       entry != entries_.end(); entry++) {
+    DCHECK(entry->rinfo_.rmode() != RelocInfo::JS_RETURN);
+    entry->rinfo_.set_pc(entry->rinfo_.pc() + pc_delta);
+  }
+}
+
+
+Handle<ConstantPoolArray> ConstantPoolBuilder::New(Isolate* isolate) {
+  if (IsEmpty()) {
+    return isolate->factory()->empty_constant_pool_array();
+  } else if (extended_entries()->is_empty()) {
+    return isolate->factory()->NewConstantPoolArray(*small_entries());
+  } else {
+    DCHECK(current_section_ == ConstantPoolArray::EXTENDED_SECTION);
+    return isolate->factory()->NewExtendedConstantPoolArray(
+        *small_entries(), *extended_entries());
+  }
+}
+
+
+void ConstantPoolBuilder::Populate(Assembler* assm,
+                                   ConstantPoolArray* constant_pool) {
+  DCHECK_EQ(extended_entries()->is_empty(),
+            !constant_pool->is_extended_layout());
+  DCHECK(small_entries()->equals(ConstantPoolArray::NumberOfEntries(
+      constant_pool, ConstantPoolArray::SMALL_SECTION)));
+  if (constant_pool->is_extended_layout()) {
+    DCHECK(extended_entries()->equals(ConstantPoolArray::NumberOfEntries(
+        constant_pool, ConstantPoolArray::EXTENDED_SECTION)));
+  }
+
+  // Set up initial offsets.
+  int offsets[ConstantPoolArray::NUMBER_OF_LAYOUT_SECTIONS]
+             [ConstantPoolArray::NUMBER_OF_TYPES];
+  for (int section = 0; section <= constant_pool->final_section(); section++) {
+    int section_start = (section == ConstantPoolArray::EXTENDED_SECTION)
+                            ? small_entries()->total_count()
+                            : 0;
+    for (int i = 0; i < ConstantPoolArray::NUMBER_OF_TYPES; i++) {
+      ConstantPoolArray::Type type = static_cast<ConstantPoolArray::Type>(i);
+      if (number_of_entries_[section].count_of(type) != 0) {
+        offsets[section][type] = constant_pool->OffsetOfElementAt(
+            number_of_entries_[section].base_of(type) + section_start);
+      }
+    }
+  }
+
+  for (std::vector<ConstantPoolEntry>::iterator entry = entries_.begin();
+       entry != entries_.end(); entry++) {
+    RelocInfo rinfo = entry->rinfo_;
+    RelocInfo::Mode rmode = entry->rinfo_.rmode();
+    ConstantPoolArray::Type type = GetConstantPoolType(rmode);
+
+    // Update constant pool if necessary and get the entry's offset.
+    int offset;
+    if (entry->merged_index_ == -1) {
+      offset = offsets[entry->section_][type];
+      offsets[entry->section_][type] += ConstantPoolArray::entry_size(type);
+      if (type == ConstantPoolArray::INT64) {
+#if V8_TARGET_ARCH_PPC64
+        constant_pool->set_at_offset(offset, rinfo.data());
+#else
+        constant_pool->set_at_offset(offset, rinfo.data64());
+      } else if (type == ConstantPoolArray::INT32) {
+        constant_pool->set_at_offset(offset,
+                                     static_cast<int32_t>(rinfo.data()));
+#endif
+      } else if (type == ConstantPoolArray::CODE_PTR) {
+        constant_pool->set_at_offset(offset,
+                                     reinterpret_cast<Address>(rinfo.data()));
+      } else {
+        DCHECK(type == ConstantPoolArray::HEAP_PTR);
+        constant_pool->set_at_offset(offset,
+                                     reinterpret_cast<Object*>(rinfo.data()));
+      }
+      offset -= kHeapObjectTag;
+      entry->merged_index_ = offset;  // Stash offset for merged entries.
+    } else {
+      DCHECK(entry->merged_index_ < (entry - entries_.begin()));
+      offset = entries_[entry->merged_index_].merged_index_;
+    }
+
+    // Patch load instruction with correct offset.
+    Assembler::SetConstantPoolOffset(rinfo.pc(), offset);
+  }
+}
+#endif
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ppc/assembler-ppc.h b/src/ppc/assembler-ppc.h
new file mode 100644
index 0000000..2b112d6
--- /dev/null
+++ b/src/ppc/assembler-ppc.h
@@ -0,0 +1,1493 @@
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// - Redistribution in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the
+// distribution.
+//
+// - Neither the name of Sun Microsystems or the names of contributors may
+// be used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2014 the V8 project authors. All rights reserved.
+
+// A light-weight PPC Assembler
+// Generates user mode instructions for the PPC architecture up
+
+#ifndef V8_PPC_ASSEMBLER_PPC_H_
+#define V8_PPC_ASSEMBLER_PPC_H_
+
+#include <stdio.h>
+#include <vector>
+
+#include "src/assembler.h"
+#include "src/ppc/constants-ppc.h"
+#include "src/serialize.h"
+
+#define ABI_USES_FUNCTION_DESCRIPTORS \
+  (V8_HOST_ARCH_PPC && (V8_OS_AIX ||    \
+                      (V8_TARGET_ARCH_PPC64 && V8_TARGET_BIG_ENDIAN)))
+
+#define ABI_PASSES_HANDLES_IN_REGS \
+  (!V8_HOST_ARCH_PPC || V8_OS_AIX || V8_TARGET_ARCH_PPC64)
+
+#define ABI_RETURNS_HANDLES_IN_REGS \
+  (!V8_HOST_ARCH_PPC || V8_TARGET_LITTLE_ENDIAN)
+
+#define ABI_RETURNS_OBJECT_PAIRS_IN_REGS \
+  (!V8_HOST_ARCH_PPC || V8_TARGET_LITTLE_ENDIAN)
+
+#define ABI_TOC_ADDRESSABILITY_VIA_IP \
+  (V8_HOST_ARCH_PPC && V8_TARGET_ARCH_PPC64 && V8_TARGET_LITTLE_ENDIAN)
+
+#if !V8_HOST_ARCH_PPC || V8_OS_AIX || V8_TARGET_ARCH_PPC64
+#define ABI_TOC_REGISTER kRegister_r2_Code
+#else
+#define ABI_TOC_REGISTER kRegister_r13_Code
+#endif
+
+#define INSTR_AND_DATA_CACHE_COHERENCY LWSYNC
+
+namespace v8 {
+namespace internal {
+
+// CPU Registers.
+//
+// 1) We would prefer to use an enum, but enum values are assignment-
+// compatible with int, which has caused code-generation bugs.
+//
+// 2) We would prefer to use a class instead of a struct but we don't like
+// the register initialization to depend on the particular initialization
+// order (which appears to be different on OS X, Linux, and Windows for the
+// installed versions of C++ we tried). Using a struct permits C-style
+// "initialization". Also, the Register objects cannot be const as this
+// forces initialization stubs in MSVC, making us dependent on initialization
+// order.
+//
+// 3) By not using an enum, we are possibly preventing the compiler from
+// doing certain constant folds, which may significantly reduce the
+// code generated for some assembly instructions (because they boil down
+// to a few constants). If this is a problem, we could change the code
+// such that we use an enum in optimized mode, and the struct in debug
+// mode. This way we get the compile-time error checking in debug mode
+// and best performance in optimized code.
+
+// Core register
+struct Register {
+  static const int kNumRegisters = 32;
+  static const int kSizeInBytes = kPointerSize;
+
+#if V8_TARGET_LITTLE_ENDIAN
+  static const int kMantissaOffset = 0;
+  static const int kExponentOffset = 4;
+#else
+  static const int kMantissaOffset = 4;
+  static const int kExponentOffset = 0;
+#endif
+
+  static const int kAllocatableLowRangeBegin = 3;
+  static const int kAllocatableLowRangeEnd = 10;
+  static const int kAllocatableHighRangeBegin = 14;
+#if V8_OOL_CONSTANT_POOL
+  static const int kAllocatableHighRangeEnd = 27;
+#else
+  static const int kAllocatableHighRangeEnd = 28;
+#endif
+  static const int kAllocatableContext = 30;
+
+  static const int kNumAllocatableLow =
+      kAllocatableLowRangeEnd - kAllocatableLowRangeBegin + 1;
+  static const int kNumAllocatableHigh =
+      kAllocatableHighRangeEnd - kAllocatableHighRangeBegin + 1;
+  static const int kMaxNumAllocatableRegisters =
+      kNumAllocatableLow + kNumAllocatableHigh + 1;  // cp
+
+  static int NumAllocatableRegisters() { return kMaxNumAllocatableRegisters; }
+
+  static int ToAllocationIndex(Register reg) {
+    int index;
+    int code = reg.code();
+    if (code == kAllocatableContext) {
+      // Context is the last index
+      index = NumAllocatableRegisters() - 1;
+    } else if (code <= kAllocatableLowRangeEnd) {
+      // low range
+      index = code - kAllocatableLowRangeBegin;
+    } else {
+      // high range
+      index = code - kAllocatableHighRangeBegin + kNumAllocatableLow;
+    }
+    DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
+    return index;
+  }
+
+  static Register FromAllocationIndex(int index) {
+    DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
+    // Last index is always the 'cp' register.
+    if (index == kMaxNumAllocatableRegisters - 1) {
+      return from_code(kAllocatableContext);
+    }
+    return (index < kNumAllocatableLow)
+               ? from_code(index + kAllocatableLowRangeBegin)
+               : from_code(index - kNumAllocatableLow +
+                           kAllocatableHighRangeBegin);
+  }
+
+  static const char* AllocationIndexToString(int index) {
+    DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
+    const char* const names[] = {
+      "r3",
+      "r4",
+      "r5",
+      "r6",
+      "r7",
+      "r8",
+      "r9",
+      "r10",
+      "r14",
+      "r15",
+      "r16",
+      "r17",
+      "r18",
+      "r19",
+      "r20",
+      "r21",
+      "r22",
+      "r23",
+      "r24",
+      "r25",
+      "r26",
+      "r27",
+#if !V8_OOL_CONSTANT_POOL
+      "r28",
+#endif
+      "cp",
+    };
+    return names[index];
+  }
+
+  static Register from_code(int code) {
+    Register r = {code};
+    return r;
+  }
+
+  bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
+  bool is(Register reg) const { return code_ == reg.code_; }
+  int code() const {
+    DCHECK(is_valid());
+    return code_;
+  }
+  int bit() const {
+    DCHECK(is_valid());
+    return 1 << code_;
+  }
+
+  void set_code(int code) {
+    code_ = code;
+    DCHECK(is_valid());
+  }
+
+  // Unfortunately we can't make this private in a struct.
+  int code_;
+};
+
+// These constants are used in several locations, including static initializers
+const int kRegister_no_reg_Code = -1;
+const int kRegister_r0_Code = 0;  // general scratch
+const int kRegister_sp_Code = 1;  // stack pointer
+const int kRegister_r2_Code = 2;  // special on PowerPC
+const int kRegister_r3_Code = 3;
+const int kRegister_r4_Code = 4;
+const int kRegister_r5_Code = 5;
+const int kRegister_r6_Code = 6;
+const int kRegister_r7_Code = 7;
+const int kRegister_r8_Code = 8;
+const int kRegister_r9_Code = 9;
+const int kRegister_r10_Code = 10;
+const int kRegister_r11_Code = 11;  // lithium scratch
+const int kRegister_ip_Code = 12;   // ip (general scratch)
+const int kRegister_r13_Code = 13;  // special on PowerPC
+const int kRegister_r14_Code = 14;
+const int kRegister_r15_Code = 15;
+
+const int kRegister_r16_Code = 16;
+const int kRegister_r17_Code = 17;
+const int kRegister_r18_Code = 18;
+const int kRegister_r19_Code = 19;
+const int kRegister_r20_Code = 20;
+const int kRegister_r21_Code = 21;
+const int kRegister_r22_Code = 22;
+const int kRegister_r23_Code = 23;
+const int kRegister_r24_Code = 24;
+const int kRegister_r25_Code = 25;
+const int kRegister_r26_Code = 26;
+const int kRegister_r27_Code = 27;
+const int kRegister_r28_Code = 28;  // constant pool pointer
+const int kRegister_r29_Code = 29;  // roots array pointer
+const int kRegister_r30_Code = 30;  // context pointer
+const int kRegister_fp_Code = 31;   // frame pointer
+
+const Register no_reg = {kRegister_no_reg_Code};
+
+const Register r0 = {kRegister_r0_Code};
+const Register sp = {kRegister_sp_Code};
+const Register r2 = {kRegister_r2_Code};
+const Register r3 = {kRegister_r3_Code};
+const Register r4 = {kRegister_r4_Code};
+const Register r5 = {kRegister_r5_Code};
+const Register r6 = {kRegister_r6_Code};
+const Register r7 = {kRegister_r7_Code};
+const Register r8 = {kRegister_r8_Code};
+const Register r9 = {kRegister_r9_Code};
+const Register r10 = {kRegister_r10_Code};
+const Register r11 = {kRegister_r11_Code};
+const Register ip = {kRegister_ip_Code};
+const Register r13 = {kRegister_r13_Code};
+const Register r14 = {kRegister_r14_Code};
+const Register r15 = {kRegister_r15_Code};
+
+const Register r16 = {kRegister_r16_Code};
+const Register r17 = {kRegister_r17_Code};
+const Register r18 = {kRegister_r18_Code};
+const Register r19 = {kRegister_r19_Code};
+const Register r20 = {kRegister_r20_Code};
+const Register r21 = {kRegister_r21_Code};
+const Register r22 = {kRegister_r22_Code};
+const Register r23 = {kRegister_r23_Code};
+const Register r24 = {kRegister_r24_Code};
+const Register r25 = {kRegister_r25_Code};
+const Register r26 = {kRegister_r26_Code};
+const Register r27 = {kRegister_r27_Code};
+const Register r28 = {kRegister_r28_Code};
+const Register r29 = {kRegister_r29_Code};
+const Register r30 = {kRegister_r30_Code};
+const Register fp = {kRegister_fp_Code};
+
+// Give alias names to registers
+const Register cp = {kRegister_r30_Code};  // JavaScript context pointer
+const Register kRootRegister = {kRegister_r29_Code};  // Roots array pointer.
+#if V8_OOL_CONSTANT_POOL
+const Register kConstantPoolRegister = {kRegister_r28_Code};  // Constant pool
+#endif
+
+// Double word FP register.
+struct DoubleRegister {
+  static const int kNumRegisters = 32;
+  static const int kMaxNumRegisters = kNumRegisters;
+  static const int kNumVolatileRegisters = 14;  // d0-d13
+  static const int kSizeInBytes = 8;
+
+  static const int kAllocatableLowRangeBegin = 1;
+  static const int kAllocatableLowRangeEnd = 12;
+  static const int kAllocatableHighRangeBegin = 15;
+  static const int kAllocatableHighRangeEnd = 31;
+
+  static const int kNumAllocatableLow =
+      kAllocatableLowRangeEnd - kAllocatableLowRangeBegin + 1;
+  static const int kNumAllocatableHigh =
+      kAllocatableHighRangeEnd - kAllocatableHighRangeBegin + 1;
+  static const int kMaxNumAllocatableRegisters =
+      kNumAllocatableLow + kNumAllocatableHigh;
+  static int NumAllocatableRegisters() { return kMaxNumAllocatableRegisters; }
+
+  // TODO(turbofan)
+  inline static int NumAllocatableAliasedRegisters() {
+    return NumAllocatableRegisters();
+  }
+
+  static int ToAllocationIndex(DoubleRegister reg) {
+    int code = reg.code();
+    int index = (code <= kAllocatableLowRangeEnd)
+                    ? code - kAllocatableLowRangeBegin
+                    : code - kAllocatableHighRangeBegin + kNumAllocatableLow;
+    DCHECK(index < kMaxNumAllocatableRegisters);
+    return index;
+  }
+
+  static DoubleRegister FromAllocationIndex(int index) {
+    DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
+    return (index < kNumAllocatableLow)
+               ? from_code(index + kAllocatableLowRangeBegin)
+               : from_code(index - kNumAllocatableLow +
+                           kAllocatableHighRangeBegin);
+  }
+
+  static const char* AllocationIndexToString(int index);
+
+  static DoubleRegister from_code(int code) {
+    DoubleRegister r = {code};
+    return r;
+  }
+
+  bool is_valid() const { return 0 <= code_ && code_ < kMaxNumRegisters; }
+  bool is(DoubleRegister reg) const { return code_ == reg.code_; }
+
+  int code() const {
+    DCHECK(is_valid());
+    return code_;
+  }
+  int bit() const {
+    DCHECK(is_valid());
+    return 1 << code_;
+  }
+  void split_code(int* vm, int* m) const {
+    DCHECK(is_valid());
+    *m = (code_ & 0x10) >> 4;
+    *vm = code_ & 0x0F;
+  }
+
+  int code_;
+};
+
+
+const DoubleRegister no_dreg = {-1};
+const DoubleRegister d0 = {0};
+const DoubleRegister d1 = {1};
+const DoubleRegister d2 = {2};
+const DoubleRegister d3 = {3};
+const DoubleRegister d4 = {4};
+const DoubleRegister d5 = {5};
+const DoubleRegister d6 = {6};
+const DoubleRegister d7 = {7};
+const DoubleRegister d8 = {8};
+const DoubleRegister d9 = {9};
+const DoubleRegister d10 = {10};
+const DoubleRegister d11 = {11};
+const DoubleRegister d12 = {12};
+const DoubleRegister d13 = {13};
+const DoubleRegister d14 = {14};
+const DoubleRegister d15 = {15};
+const DoubleRegister d16 = {16};
+const DoubleRegister d17 = {17};
+const DoubleRegister d18 = {18};
+const DoubleRegister d19 = {19};
+const DoubleRegister d20 = {20};
+const DoubleRegister d21 = {21};
+const DoubleRegister d22 = {22};
+const DoubleRegister d23 = {23};
+const DoubleRegister d24 = {24};
+const DoubleRegister d25 = {25};
+const DoubleRegister d26 = {26};
+const DoubleRegister d27 = {27};
+const DoubleRegister d28 = {28};
+const DoubleRegister d29 = {29};
+const DoubleRegister d30 = {30};
+const DoubleRegister d31 = {31};
+
+// Aliases for double registers.  Defined using #define instead of
+// "static const DoubleRegister&" because Clang complains otherwise when a
+// compilation unit that includes this header doesn't use the variables.
+#define kFirstCalleeSavedDoubleReg d14
+#define kLastCalleeSavedDoubleReg d31
+#define kDoubleRegZero d14
+#define kScratchDoubleReg d13
+
+Register ToRegister(int num);
+
+// Coprocessor register
+struct CRegister {
+  bool is_valid() const { return 0 <= code_ && code_ < 16; }
+  bool is(CRegister creg) const { return code_ == creg.code_; }
+  int code() const {
+    DCHECK(is_valid());
+    return code_;
+  }
+  int bit() const {
+    DCHECK(is_valid());
+    return 1 << code_;
+  }
+
+  // Unfortunately we can't make this private in a struct.
+  int code_;
+};
+
+
+const CRegister no_creg = {-1};
+
+const CRegister cr0 = {0};
+const CRegister cr1 = {1};
+const CRegister cr2 = {2};
+const CRegister cr3 = {3};
+const CRegister cr4 = {4};
+const CRegister cr5 = {5};
+const CRegister cr6 = {6};
+const CRegister cr7 = {7};
+const CRegister cr8 = {8};
+const CRegister cr9 = {9};
+const CRegister cr10 = {10};
+const CRegister cr11 = {11};
+const CRegister cr12 = {12};
+const CRegister cr13 = {13};
+const CRegister cr14 = {14};
+const CRegister cr15 = {15};
+
+// -----------------------------------------------------------------------------
+// Machine instruction Operands
+
+#if V8_TARGET_ARCH_PPC64
+const RelocInfo::Mode kRelocInfo_NONEPTR = RelocInfo::NONE64;
+#else
+const RelocInfo::Mode kRelocInfo_NONEPTR = RelocInfo::NONE32;
+#endif
+
+// Class Operand represents a shifter operand in data processing instructions
+class Operand BASE_EMBEDDED {
+ public:
+  // immediate
+  INLINE(explicit Operand(intptr_t immediate,
+                          RelocInfo::Mode rmode = kRelocInfo_NONEPTR));
+  INLINE(static Operand Zero()) { return Operand(static_cast<intptr_t>(0)); }
+  INLINE(explicit Operand(const ExternalReference& f));
+  explicit Operand(Handle<Object> handle);
+  INLINE(explicit Operand(Smi* value));
+
+  // rm
+  INLINE(explicit Operand(Register rm));
+
+  // Return true if this is a register operand.
+  INLINE(bool is_reg() const);
+
+  // For mov.  Return the number of actual instructions required to
+  // load the operand into a register.  This can be anywhere from
+  // one (constant pool small section) to five instructions (full
+  // 64-bit sequence).
+  //
+  // The value returned is only valid as long as no entries are added to the
+  // constant pool between this call and the actual instruction being emitted.
+  bool must_output_reloc_info(const Assembler* assembler) const;
+
+  inline intptr_t immediate() const {
+    DCHECK(!rm_.is_valid());
+    return imm_;
+  }
+
+  Register rm() const { return rm_; }
+
+ private:
+  Register rm_;
+  intptr_t imm_;  // valid if rm_ == no_reg
+  RelocInfo::Mode rmode_;
+
+  friend class Assembler;
+  friend class MacroAssembler;
+};
+
+
+// Class MemOperand represents a memory operand in load and store instructions
+// On PowerPC we have base register + 16bit signed value
+// Alternatively we can have a 16bit signed value immediate
+class MemOperand BASE_EMBEDDED {
+ public:
+  explicit MemOperand(Register rn, int32_t offset = 0);
+
+  explicit MemOperand(Register ra, Register rb);
+
+  int32_t offset() const {
+    DCHECK(rb_.is(no_reg));
+    return offset_;
+  }
+
+  // PowerPC - base register
+  Register ra() const {
+    DCHECK(!ra_.is(no_reg));
+    return ra_;
+  }
+
+  Register rb() const {
+    DCHECK(offset_ == 0 && !rb_.is(no_reg));
+    return rb_;
+  }
+
+ private:
+  Register ra_;     // base
+  int32_t offset_;  // offset
+  Register rb_;     // index
+
+  friend class Assembler;
+};
+
+
+#if V8_OOL_CONSTANT_POOL
+// Class used to build a constant pool.
+class ConstantPoolBuilder BASE_EMBEDDED {
+ public:
+  ConstantPoolBuilder();
+  ConstantPoolArray::LayoutSection AddEntry(Assembler* assm,
+                                            const RelocInfo& rinfo);
+  void Relocate(intptr_t pc_delta);
+  bool IsEmpty();
+  Handle<ConstantPoolArray> New(Isolate* isolate);
+  void Populate(Assembler* assm, ConstantPoolArray* constant_pool);
+
+  inline ConstantPoolArray::LayoutSection current_section() const {
+    return current_section_;
+  }
+
+  // Rather than increasing the capacity of the ConstantPoolArray's
+  // small section to match the longer (16-bit) reach of PPC's load
+  // instruction (at the expense of a larger header to describe the
+  // layout), the PPC implementation utilizes the extended section to
+  // satisfy that reach.  I.e. all entries (regardless of their
+  // section) are reachable with a single load instruction.
+  //
+  // This implementation does not support an unlimited constant pool
+  // size (which would require a multi-instruction sequence).  [See
+  // ARM commit e27ab337 for a reference on the changes required to
+  // support the longer instruction sequence.]  Note, however, that
+  // going down that path will necessarily generate that longer
+  // sequence for all extended section accesses since the placement of
+  // a given entry within the section is not known at the time of
+  // code generation.
+  //
+  // TODO(mbrandy): Determine whether there is a benefit to supporting
+  // the longer sequence given that nops could be used for those
+  // entries which are reachable with a single instruction.
+  inline bool is_full() const { return !is_int16(size_); }
+
+  inline ConstantPoolArray::NumberOfEntries* number_of_entries(
+      ConstantPoolArray::LayoutSection section) {
+    return &number_of_entries_[section];
+  }
+
+  inline ConstantPoolArray::NumberOfEntries* small_entries() {
+    return number_of_entries(ConstantPoolArray::SMALL_SECTION);
+  }
+
+  inline ConstantPoolArray::NumberOfEntries* extended_entries() {
+    return number_of_entries(ConstantPoolArray::EXTENDED_SECTION);
+  }
+
+ private:
+  struct ConstantPoolEntry {
+    ConstantPoolEntry(RelocInfo rinfo, ConstantPoolArray::LayoutSection section,
+                      int merged_index)
+        : rinfo_(rinfo), section_(section), merged_index_(merged_index) {}
+
+    RelocInfo rinfo_;
+    ConstantPoolArray::LayoutSection section_;
+    int merged_index_;
+  };
+
+  ConstantPoolArray::Type GetConstantPoolType(RelocInfo::Mode rmode);
+
+  uint32_t size_;
+  std::vector<ConstantPoolEntry> entries_;
+  ConstantPoolArray::LayoutSection current_section_;
+  ConstantPoolArray::NumberOfEntries number_of_entries_[2];
+};
+#endif
+
+
+class Assembler : public AssemblerBase {
+ public:
+  // Create an assembler. Instructions and relocation information are emitted
+  // into a buffer, with the instructions starting from the beginning and the
+  // relocation information starting from the end of the buffer. See CodeDesc
+  // for a detailed comment on the layout (globals.h).
+  //
+  // If the provided buffer is NULL, the assembler allocates and grows its own
+  // buffer, and buffer_size determines the initial buffer size. The buffer is
+  // owned by the assembler and deallocated upon destruction of the assembler.
+  //
+  // If the provided buffer is not NULL, the assembler uses the provided buffer
+  // for code generation and assumes its size to be buffer_size. If the buffer
+  // is too small, a fatal error occurs. No deallocation of the buffer is done
+  // upon destruction of the assembler.
+  Assembler(Isolate* isolate, void* buffer, int buffer_size);
+  virtual ~Assembler() {}
+
+  // GetCode emits any pending (non-emitted) code and fills the descriptor
+  // desc. GetCode() is idempotent; it returns the same result if no other
+  // Assembler functions are invoked in between GetCode() calls.
+  void GetCode(CodeDesc* desc);
+
+  // Label operations & relative jumps (PPUM Appendix D)
+  //
+  // Takes a branch opcode (cc) and a label (L) and generates
+  // either a backward branch or a forward branch and links it
+  // to the label fixup chain. Usage:
+  //
+  // Label L;    // unbound label
+  // j(cc, &L);  // forward branch to unbound label
+  // bind(&L);   // bind label to the current pc
+  // j(cc, &L);  // backward branch to bound label
+  // bind(&L);   // illegal: a label may be bound only once
+  //
+  // Note: The same Label can be used for forward and backward branches
+  // but it may be bound only once.
+
+  void bind(Label* L);  // binds an unbound label L to the current code position
+  // Determines if Label is bound and near enough so that a single
+  // branch instruction can be used to reach it.
+  bool is_near(Label* L, Condition cond);
+
+  // Returns the branch offset to the given label from the current code position
+  // Links the label to the current position if it is still unbound
+  // Manages the jump elimination optimization if the second parameter is true.
+  int branch_offset(Label* L, bool jump_elimination_allowed);
+
+  // Puts a labels target address at the given position.
+  // The high 8 bits are set to zero.
+  void label_at_put(Label* L, int at_offset);
+
+#if V8_OOL_CONSTANT_POOL
+  INLINE(static bool IsConstantPoolLoadStart(Address pc));
+  INLINE(static bool IsConstantPoolLoadEnd(Address pc));
+  INLINE(static int GetConstantPoolOffset(Address pc));
+  INLINE(static void SetConstantPoolOffset(Address pc, int offset));
+
+  // Return the address in the constant pool of the code target address used by
+  // the branch/call instruction at pc, or the object in a mov.
+  INLINE(static Address target_constant_pool_address_at(
+      Address pc, ConstantPoolArray* constant_pool));
+#endif
+
+  // Read/Modify the code target address in the branch/call instruction at pc.
+  INLINE(static Address target_address_at(Address pc,
+                                          ConstantPoolArray* constant_pool));
+  INLINE(static void set_target_address_at(
+      Address pc, ConstantPoolArray* constant_pool, Address target,
+      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED));
+  INLINE(static Address target_address_at(Address pc, Code* code)) {
+    ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
+    return target_address_at(pc, constant_pool);
+  }
+  INLINE(static void set_target_address_at(
+      Address pc, Code* code, Address target,
+      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED)) {
+    ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
+    set_target_address_at(pc, constant_pool, target, icache_flush_mode);
+  }
+
+  // Return the code target address at a call site from the return address
+  // of that call in the instruction stream.
+  inline static Address target_address_from_return_address(Address pc);
+
+  // Given the address of the beginning of a call, return the address
+  // in the instruction stream that the call will return to.
+  INLINE(static Address return_address_from_call_start(Address pc));
+
+  // Return the code target address of the patch debug break slot
+  INLINE(static Address break_address_from_return_address(Address pc));
+
+  // This sets the branch destination.
+  // This is for calls and branches within generated code.
+  inline static void deserialization_set_special_target_at(
+      Address instruction_payload, Code* code, Address target);
+
+  // Size of an instruction.
+  static const int kInstrSize = sizeof(Instr);
+
+  // Here we are patching the address in the LUI/ORI instruction pair.
+  // These values are used in the serialization process and must be zero for
+  // PPC platform, as Code, Embedded Object or External-reference pointers
+  // are split across two consecutive instructions and don't exist separately
+  // in the code, so the serializer should not step forwards in memory after
+  // a target is resolved and written.
+  static const int kSpecialTargetSize = 0;
+
+// Number of instructions to load an address via a mov sequence.
+#if V8_TARGET_ARCH_PPC64
+  static const int kMovInstructionsConstantPool = 2;
+  static const int kMovInstructionsNoConstantPool = 5;
+#else
+  static const int kMovInstructionsConstantPool = 1;
+  static const int kMovInstructionsNoConstantPool = 2;
+#endif
+#if V8_OOL_CONSTANT_POOL
+  static const int kMovInstructions = kMovInstructionsConstantPool;
+#else
+  static const int kMovInstructions = kMovInstructionsNoConstantPool;
+#endif
+
+  // Distance between the instruction referring to the address of the call
+  // target and the return address.
+
+  // Call sequence is a FIXED_SEQUENCE:
+  // mov     r8, @ call address
+  // mtlr    r8
+  // blrl
+  //                      @ return address
+  static const int kCallTargetAddressOffset =
+      (kMovInstructions + 2) * kInstrSize;
+
+  // Distance between start of patched return sequence and the emitted address
+  // to jump to.
+  // Patched return sequence is a FIXED_SEQUENCE:
+  //   mov r0, <address>
+  //   mtlr r0
+  //   blrl
+  static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
+
+  // Distance between start of patched debug break slot and the emitted address
+  // to jump to.
+  // Patched debug break slot code is a FIXED_SEQUENCE:
+  //   mov r0, <address>
+  //   mtlr r0
+  //   blrl
+  static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
+
+  // This is the length of the BreakLocationIterator::SetDebugBreakAtReturn()
+  // code patch FIXED_SEQUENCE
+  static const int kJSReturnSequenceInstructions =
+      kMovInstructionsNoConstantPool + 3;
+
+  // This is the length of the code sequence from SetDebugBreakAtSlot()
+  // FIXED_SEQUENCE
+  static const int kDebugBreakSlotInstructions =
+      kMovInstructionsNoConstantPool + 2;
+  static const int kDebugBreakSlotLength =
+      kDebugBreakSlotInstructions * kInstrSize;
+
+  static inline int encode_crbit(const CRegister& cr, enum CRBit crbit) {
+    return ((cr.code() * CRWIDTH) + crbit);
+  }
+
+  // ---------------------------------------------------------------------------
+  // Code generation
+
+  // Insert the smallest number of nop instructions
+  // possible to align the pc offset to a multiple
+  // of m. m must be a power of 2 (>= 4).
+  void Align(int m);
+  // Aligns code to something that's optimal for a jump target for the platform.
+  void CodeTargetAlign();
+
+  // Branch instructions
+  void bclr(BOfield bo, LKBit lk);
+  void blr();
+  void bc(int branch_offset, BOfield bo, int condition_bit, LKBit lk = LeaveLK);
+  void b(int branch_offset, LKBit lk);
+
+  void bcctr(BOfield bo, LKBit lk);
+  void bctr();
+  void bctrl();
+
+  // Convenience branch instructions using labels
+  void b(Label* L, LKBit lk = LeaveLK) { b(branch_offset(L, false), lk); }
+
+  void bc_short(Condition cond, Label* L, CRegister cr = cr7,
+                LKBit lk = LeaveLK) {
+    DCHECK(cond != al);
+    DCHECK(cr.code() >= 0 && cr.code() <= 7);
+
+    int b_offset = branch_offset(L, false);
+
+    switch (cond) {
+      case eq:
+        bc(b_offset, BT, encode_crbit(cr, CR_EQ), lk);
+        break;
+      case ne:
+        bc(b_offset, BF, encode_crbit(cr, CR_EQ), lk);
+        break;
+      case gt:
+        bc(b_offset, BT, encode_crbit(cr, CR_GT), lk);
+        break;
+      case le:
+        bc(b_offset, BF, encode_crbit(cr, CR_GT), lk);
+        break;
+      case lt:
+        bc(b_offset, BT, encode_crbit(cr, CR_LT), lk);
+        break;
+      case ge:
+        bc(b_offset, BF, encode_crbit(cr, CR_LT), lk);
+        break;
+      case unordered:
+        bc(b_offset, BT, encode_crbit(cr, CR_FU), lk);
+        break;
+      case ordered:
+        bc(b_offset, BF, encode_crbit(cr, CR_FU), lk);
+        break;
+      case overflow:
+        bc(b_offset, BT, encode_crbit(cr, CR_SO), lk);
+        break;
+      case nooverflow:
+        bc(b_offset, BF, encode_crbit(cr, CR_SO), lk);
+        break;
+      default:
+        UNIMPLEMENTED();
+    }
+  }
+
+  void b(Condition cond, Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
+    if (cond == al) {
+      b(L, lk);
+      return;
+    }
+
+    if ((L->is_bound() && is_near(L, cond)) || !is_trampoline_emitted()) {
+      bc_short(cond, L, cr, lk);
+      return;
+    }
+
+    Label skip;
+    Condition neg_cond = NegateCondition(cond);
+    bc_short(neg_cond, &skip, cr);
+    b(L, lk);
+    bind(&skip);
+  }
+
+  void bne(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
+    b(ne, L, cr, lk);
+  }
+  void beq(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
+    b(eq, L, cr, lk);
+  }
+  void blt(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
+    b(lt, L, cr, lk);
+  }
+  void bge(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
+    b(ge, L, cr, lk);
+  }
+  void ble(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
+    b(le, L, cr, lk);
+  }
+  void bgt(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
+    b(gt, L, cr, lk);
+  }
+  void bunordered(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
+    b(unordered, L, cr, lk);
+  }
+  void bordered(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
+    b(ordered, L, cr, lk);
+  }
+  void boverflow(Label* L, CRegister cr = cr0, LKBit lk = LeaveLK) {
+    b(overflow, L, cr, lk);
+  }
+  void bnooverflow(Label* L, CRegister cr = cr0, LKBit lk = LeaveLK) {
+    b(nooverflow, L, cr, lk);
+  }
+
+  // Decrement CTR; branch if CTR != 0
+  void bdnz(Label* L, LKBit lk = LeaveLK) {
+    bc(branch_offset(L, false), DCBNZ, 0, lk);
+  }
+
+  // Data-processing instructions
+
+  void sub(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
+           RCBit r = LeaveRC);
+
+  void subfic(Register dst, Register src, const Operand& imm);
+
+  void subfc(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
+             RCBit r = LeaveRC);
+
+  void add(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
+           RCBit r = LeaveRC);
+
+  void addc(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
+            RCBit r = LeaveRC);
+
+  void addze(Register dst, Register src1, OEBit o, RCBit r);
+
+  void mullw(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
+             RCBit r = LeaveRC);
+
+  void mulhw(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
+             RCBit r = LeaveRC);
+
+  void divw(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
+            RCBit r = LeaveRC);
+
+  void addi(Register dst, Register src, const Operand& imm);
+  void addis(Register dst, Register src, const Operand& imm);
+  void addic(Register dst, Register src, const Operand& imm);
+
+  void and_(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
+  void andc(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
+  void andi(Register ra, Register rs, const Operand& imm);
+  void andis(Register ra, Register rs, const Operand& imm);
+  void nor(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
+  void notx(Register dst, Register src, RCBit r = LeaveRC);
+  void ori(Register dst, Register src, const Operand& imm);
+  void oris(Register dst, Register src, const Operand& imm);
+  void orx(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
+  void xori(Register dst, Register src, const Operand& imm);
+  void xoris(Register ra, Register rs, const Operand& imm);
+  void xor_(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
+  void cmpi(Register src1, const Operand& src2, CRegister cr = cr7);
+  void cmpli(Register src1, const Operand& src2, CRegister cr = cr7);
+  void cmpwi(Register src1, const Operand& src2, CRegister cr = cr7);
+  void cmplwi(Register src1, const Operand& src2, CRegister cr = cr7);
+  void li(Register dst, const Operand& src);
+  void lis(Register dst, const Operand& imm);
+  void mr(Register dst, Register src);
+
+  void lbz(Register dst, const MemOperand& src);
+  void lbzx(Register dst, const MemOperand& src);
+  void lbzux(Register dst, const MemOperand& src);
+  void lhz(Register dst, const MemOperand& src);
+  void lhzx(Register dst, const MemOperand& src);
+  void lhzux(Register dst, const MemOperand& src);
+  void lwz(Register dst, const MemOperand& src);
+  void lwzu(Register dst, const MemOperand& src);
+  void lwzx(Register dst, const MemOperand& src);
+  void lwzux(Register dst, const MemOperand& src);
+  void lwa(Register dst, const MemOperand& src);
+  void stb(Register dst, const MemOperand& src);
+  void stbx(Register dst, const MemOperand& src);
+  void stbux(Register dst, const MemOperand& src);
+  void sth(Register dst, const MemOperand& src);
+  void sthx(Register dst, const MemOperand& src);
+  void sthux(Register dst, const MemOperand& src);
+  void stw(Register dst, const MemOperand& src);
+  void stwu(Register dst, const MemOperand& src);
+  void stwx(Register rs, const MemOperand& src);
+  void stwux(Register rs, const MemOperand& src);
+
+  void extsb(Register rs, Register ra, RCBit r = LeaveRC);
+  void extsh(Register rs, Register ra, RCBit r = LeaveRC);
+
+  void neg(Register rt, Register ra, OEBit o = LeaveOE, RCBit c = LeaveRC);
+
+#if V8_TARGET_ARCH_PPC64
+  void ld(Register rd, const MemOperand& src);
+  void ldx(Register rd, const MemOperand& src);
+  void ldu(Register rd, const MemOperand& src);
+  void ldux(Register rd, const MemOperand& src);
+  void std(Register rs, const MemOperand& src);
+  void stdx(Register rs, const MemOperand& src);
+  void stdu(Register rs, const MemOperand& src);
+  void stdux(Register rs, const MemOperand& src);
+  void rldic(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
+  void rldicl(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
+  void rldcl(Register ra, Register rs, Register rb, int mb, RCBit r = LeaveRC);
+  void rldicr(Register dst, Register src, int sh, int me, RCBit r = LeaveRC);
+  void rldimi(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
+  void sldi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
+  void srdi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
+  void clrrdi(Register dst, Register src, const Operand& val,
+              RCBit rc = LeaveRC);
+  void clrldi(Register dst, Register src, const Operand& val,
+              RCBit rc = LeaveRC);
+  void sradi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
+  void srd(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
+  void sld(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
+  void srad(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
+  void rotld(Register ra, Register rs, Register rb, RCBit r = LeaveRC);
+  void rotldi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
+  void rotrdi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
+  void cntlzd_(Register dst, Register src, RCBit rc = LeaveRC);
+  void extsw(Register rs, Register ra, RCBit r = LeaveRC);
+  void mulld(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
+             RCBit r = LeaveRC);
+  void divd(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
+            RCBit r = LeaveRC);
+#endif
+
+  void rlwinm(Register ra, Register rs, int sh, int mb, int me,
+              RCBit rc = LeaveRC);
+  void rlwimi(Register ra, Register rs, int sh, int mb, int me,
+              RCBit rc = LeaveRC);
+  void rlwnm(Register ra, Register rs, Register rb, int mb, int me,
+             RCBit rc = LeaveRC);
+  void slwi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
+  void srwi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
+  void clrrwi(Register dst, Register src, const Operand& val,
+              RCBit rc = LeaveRC);
+  void clrlwi(Register dst, Register src, const Operand& val,
+              RCBit rc = LeaveRC);
+  void srawi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
+  void srw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
+  void slw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
+  void sraw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
+  void rotlw(Register ra, Register rs, Register rb, RCBit r = LeaveRC);
+  void rotlwi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
+  void rotrwi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
+
+  void cntlzw_(Register dst, Register src, RCBit rc = LeaveRC);
+
+  void subi(Register dst, Register src1, const Operand& src2);
+
+  void cmp(Register src1, Register src2, CRegister cr = cr7);
+  void cmpl(Register src1, Register src2, CRegister cr = cr7);
+  void cmpw(Register src1, Register src2, CRegister cr = cr7);
+  void cmplw(Register src1, Register src2, CRegister cr = cr7);
+
+  void mov(Register dst, const Operand& src);
+
+  // Load the position of the label relative to the generated code object
+  // pointer in a register.
+  void mov_label_offset(Register dst, Label* label);
+
+  // Multiply instructions
+  void mul(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
+           RCBit r = LeaveRC);
+
+  // Miscellaneous arithmetic instructions
+
+  // Special register access
+  void crxor(int bt, int ba, int bb);
+  void crclr(int bt) { crxor(bt, bt, bt); }
+  void creqv(int bt, int ba, int bb);
+  void crset(int bt) { creqv(bt, bt, bt); }
+  void mflr(Register dst);
+  void mtlr(Register src);
+  void mtctr(Register src);
+  void mtxer(Register src);
+  void mcrfs(int bf, int bfa);
+  void mfcr(Register dst);
+#if V8_TARGET_ARCH_PPC64
+  void mffprd(Register dst, DoubleRegister src);
+  void mffprwz(Register dst, DoubleRegister src);
+  void mtfprd(DoubleRegister dst, Register src);
+  void mtfprwz(DoubleRegister dst, Register src);
+  void mtfprwa(DoubleRegister dst, Register src);
+#endif
+
+  void fake_asm(enum FAKE_OPCODE_T fopcode);
+  void marker_asm(int mcode);
+  void function_descriptor();
+
+  // Exception-generating instructions and debugging support
+  void stop(const char* msg, Condition cond = al,
+            int32_t code = kDefaultStopCode, CRegister cr = cr7);
+
+  void bkpt(uint32_t imm16);  // v5 and above
+
+  // Informational messages when simulating
+  void info(const char* msg, Condition cond = al,
+            int32_t code = kDefaultStopCode, CRegister cr = cr7);
+
+  void dcbf(Register ra, Register rb);
+  void sync();
+  void lwsync();
+  void icbi(Register ra, Register rb);
+  void isync();
+
+  // Support for floating point
+  void lfd(const DoubleRegister frt, const MemOperand& src);
+  void lfdu(const DoubleRegister frt, const MemOperand& src);
+  void lfdx(const DoubleRegister frt, const MemOperand& src);
+  void lfdux(const DoubleRegister frt, const MemOperand& src);
+  void lfs(const DoubleRegister frt, const MemOperand& src);
+  void lfsu(const DoubleRegister frt, const MemOperand& src);
+  void lfsx(const DoubleRegister frt, const MemOperand& src);
+  void lfsux(const DoubleRegister frt, const MemOperand& src);
+  void stfd(const DoubleRegister frs, const MemOperand& src);
+  void stfdu(const DoubleRegister frs, const MemOperand& src);
+  void stfdx(const DoubleRegister frs, const MemOperand& src);
+  void stfdux(const DoubleRegister frs, const MemOperand& src);
+  void stfs(const DoubleRegister frs, const MemOperand& src);
+  void stfsu(const DoubleRegister frs, const MemOperand& src);
+  void stfsx(const DoubleRegister frs, const MemOperand& src);
+  void stfsux(const DoubleRegister frs, const MemOperand& src);
+
+  void fadd(const DoubleRegister frt, const DoubleRegister fra,
+            const DoubleRegister frb, RCBit rc = LeaveRC);
+  void fsub(const DoubleRegister frt, const DoubleRegister fra,
+            const DoubleRegister frb, RCBit rc = LeaveRC);
+  void fdiv(const DoubleRegister frt, const DoubleRegister fra,
+            const DoubleRegister frb, RCBit rc = LeaveRC);
+  void fmul(const DoubleRegister frt, const DoubleRegister fra,
+            const DoubleRegister frc, RCBit rc = LeaveRC);
+  void fcmpu(const DoubleRegister fra, const DoubleRegister frb,
+             CRegister cr = cr7);
+  void fmr(const DoubleRegister frt, const DoubleRegister frb,
+           RCBit rc = LeaveRC);
+  void fctiwz(const DoubleRegister frt, const DoubleRegister frb);
+  void fctiw(const DoubleRegister frt, const DoubleRegister frb);
+  void frim(const DoubleRegister frt, const DoubleRegister frb);
+  void frsp(const DoubleRegister frt, const DoubleRegister frb,
+            RCBit rc = LeaveRC);
+  void fcfid(const DoubleRegister frt, const DoubleRegister frb,
+             RCBit rc = LeaveRC);
+  void fctid(const DoubleRegister frt, const DoubleRegister frb,
+             RCBit rc = LeaveRC);
+  void fctidz(const DoubleRegister frt, const DoubleRegister frb,
+              RCBit rc = LeaveRC);
+  void fsel(const DoubleRegister frt, const DoubleRegister fra,
+            const DoubleRegister frc, const DoubleRegister frb,
+            RCBit rc = LeaveRC);
+  void fneg(const DoubleRegister frt, const DoubleRegister frb,
+            RCBit rc = LeaveRC);
+  void mtfsfi(int bf, int immediate, RCBit rc = LeaveRC);
+  void mffs(const DoubleRegister frt, RCBit rc = LeaveRC);
+  void mtfsf(const DoubleRegister frb, bool L = 1, int FLM = 0, bool W = 0,
+             RCBit rc = LeaveRC);
+  void fsqrt(const DoubleRegister frt, const DoubleRegister frb,
+             RCBit rc = LeaveRC);
+  void fabs(const DoubleRegister frt, const DoubleRegister frb,
+            RCBit rc = LeaveRC);
+  void fmadd(const DoubleRegister frt, const DoubleRegister fra,
+             const DoubleRegister frc, const DoubleRegister frb,
+             RCBit rc = LeaveRC);
+  void fmsub(const DoubleRegister frt, const DoubleRegister fra,
+             const DoubleRegister frc, const DoubleRegister frb,
+             RCBit rc = LeaveRC);
+
+  // Pseudo instructions
+
+  // Different nop operations are used by the code generator to detect certain
+  // states of the generated code.
+  enum NopMarkerTypes {
+    NON_MARKING_NOP = 0,
+    GROUP_ENDING_NOP,
+    DEBUG_BREAK_NOP,
+    // IC markers.
+    PROPERTY_ACCESS_INLINED,
+    PROPERTY_ACCESS_INLINED_CONTEXT,
+    PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
+    // Helper values.
+    LAST_CODE_MARKER,
+    FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
+  };
+
+  void nop(int type = 0);  // 0 is the default non-marking type.
+
+  void push(Register src) {
+#if V8_TARGET_ARCH_PPC64
+    stdu(src, MemOperand(sp, -kPointerSize));
+#else
+    stwu(src, MemOperand(sp, -kPointerSize));
+#endif
+  }
+
+  void pop(Register dst) {
+#if V8_TARGET_ARCH_PPC64
+    ld(dst, MemOperand(sp));
+#else
+    lwz(dst, MemOperand(sp));
+#endif
+    addi(sp, sp, Operand(kPointerSize));
+  }
+
+  void pop() { addi(sp, sp, Operand(kPointerSize)); }
+
+  // Jump unconditionally to given label.
+  void jmp(Label* L) { b(L); }
+
+  // Check the code size generated from label to here.
+  int SizeOfCodeGeneratedSince(Label* label) {
+    return pc_offset() - label->pos();
+  }
+
+  // Check the number of instructions generated from label to here.
+  int InstructionsGeneratedSince(Label* label) {
+    return SizeOfCodeGeneratedSince(label) / kInstrSize;
+  }
+
+  // Class for scoping postponing the trampoline pool generation.
+  class BlockTrampolinePoolScope {
+   public:
+    explicit BlockTrampolinePoolScope(Assembler* assem) : assem_(assem) {
+      assem_->StartBlockTrampolinePool();
+    }
+    ~BlockTrampolinePoolScope() { assem_->EndBlockTrampolinePool(); }
+
+   private:
+    Assembler* assem_;
+
+    DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope);
+  };
+
+  // Debugging
+
+  // Mark address of the ExitJSFrame code.
+  void RecordJSReturn();
+
+  // Mark address of a debug break slot.
+  void RecordDebugBreakSlot();
+
+  // Record the AST id of the CallIC being compiled, so that it can be placed
+  // in the relocation information.
+  void SetRecordedAstId(TypeFeedbackId ast_id) {
+    // Causes compiler to fail
+    // DCHECK(recorded_ast_id_.IsNone());
+    recorded_ast_id_ = ast_id;
+  }
+
+  TypeFeedbackId RecordedAstId() {
+    // Causes compiler to fail
+    // DCHECK(!recorded_ast_id_.IsNone());
+    return recorded_ast_id_;
+  }
+
+  void ClearRecordedAstId() { recorded_ast_id_ = TypeFeedbackId::None(); }
+
+  // Record a comment relocation entry that can be used by a disassembler.
+  // Use --code-comments to enable.
+  void RecordComment(const char* msg);
+
+  // Writes a single byte or word of data in the code stream.  Used
+  // for inline tables, e.g., jump-tables.
+  void db(uint8_t data);
+  void dd(uint32_t data);
+  void emit_ptr(uintptr_t data);
+
+  PositionsRecorder* positions_recorder() { return &positions_recorder_; }
+
+  // Read/patch instructions
+  Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
+  void instr_at_put(int pos, Instr instr) {
+    *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
+  }
+  static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
+  static void instr_at_put(byte* pc, Instr instr) {
+    *reinterpret_cast<Instr*>(pc) = instr;
+  }
+  static Condition GetCondition(Instr instr);
+
+  static bool IsLis(Instr instr);
+  static bool IsLi(Instr instr);
+  static bool IsAddic(Instr instr);
+  static bool IsOri(Instr instr);
+
+  static bool IsBranch(Instr instr);
+  static Register GetRA(Instr instr);
+  static Register GetRB(Instr instr);
+#if V8_TARGET_ARCH_PPC64
+  static bool Is64BitLoadIntoR12(Instr instr1, Instr instr2, Instr instr3,
+                                 Instr instr4, Instr instr5);
+#else
+  static bool Is32BitLoadIntoR12(Instr instr1, Instr instr2);
+#endif
+
+  static bool IsCmpRegister(Instr instr);
+  static bool IsCmpImmediate(Instr instr);
+  static bool IsRlwinm(Instr instr);
+#if V8_TARGET_ARCH_PPC64
+  static bool IsRldicl(Instr instr);
+#endif
+  static bool IsCrSet(Instr instr);
+  static Register GetCmpImmediateRegister(Instr instr);
+  static int GetCmpImmediateRawImmediate(Instr instr);
+  static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
+
+  // Postpone the generation of the trampoline pool for the specified number of
+  // instructions.
+  void BlockTrampolinePoolFor(int instructions);
+  void CheckTrampolinePool();
+
+  int instructions_required_for_mov(const Operand& x) const;
+
+#if V8_OOL_CONSTANT_POOL
+  // Decide between using the constant pool vs. a mov immediate sequence.
+  bool use_constant_pool_for_mov(const Operand& x, bool canOptimize) const;
+
+  // The code currently calls CheckBuffer() too often. This has the side
+  // effect of randomly growing the buffer in the middle of multi-instruction
+  // sequences.
+  // MacroAssembler::LoadConstantPoolPointerRegister() includes a relocation
+  // and multiple instructions. We cannot grow the buffer until the
+  // relocation and all of the instructions are written.
+  //
+  // This function allows outside callers to check and grow the buffer
+  void EnsureSpaceFor(int space_needed);
+#endif
+
+  // Allocate a constant pool of the correct size for the generated code.
+  Handle<ConstantPoolArray> NewConstantPool(Isolate* isolate);
+
+  // Generate the constant pool for the generated code.
+  void PopulateConstantPool(ConstantPoolArray* constant_pool);
+
+#if V8_OOL_CONSTANT_POOL
+  bool is_constant_pool_full() const {
+    return constant_pool_builder_.is_full();
+  }
+
+  bool use_extended_constant_pool() const {
+    return constant_pool_builder_.current_section() ==
+           ConstantPoolArray::EXTENDED_SECTION;
+  }
+#endif
+
+#if ABI_USES_FUNCTION_DESCRIPTORS || V8_OOL_CONSTANT_POOL
+  static void RelocateInternalReference(
+      Address pc, intptr_t delta, Address code_start,
+      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
+  static int DecodeInternalReference(Vector<char> buffer, Address pc);
+#endif
+
+ protected:
+  // Relocation for a type-recording IC has the AST id added to it.  This
+  // member variable is a way to pass the information from the call site to
+  // the relocation info.
+  TypeFeedbackId recorded_ast_id_;
+
+  int buffer_space() const { return reloc_info_writer.pos() - pc_; }
+
+  // Decode branch instruction at pos and return branch target pos
+  int target_at(int pos);
+
+  // Patch branch instruction at pos to branch to given branch target pos
+  void target_at_put(int pos, int target_pos);
+
+  // Record reloc info for current pc_
+  void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
+  void RecordRelocInfo(const RelocInfo& rinfo);
+#if V8_OOL_CONSTANT_POOL
+  ConstantPoolArray::LayoutSection ConstantPoolAddEntry(
+      const RelocInfo& rinfo) {
+    return constant_pool_builder_.AddEntry(this, rinfo);
+  }
+#endif
+
+  // Block the emission of the trampoline pool before pc_offset.
+  void BlockTrampolinePoolBefore(int pc_offset) {
+    if (no_trampoline_pool_before_ < pc_offset)
+      no_trampoline_pool_before_ = pc_offset;
+  }
+
+  void StartBlockTrampolinePool() { trampoline_pool_blocked_nesting_++; }
+
+  void EndBlockTrampolinePool() { trampoline_pool_blocked_nesting_--; }
+
+  bool is_trampoline_pool_blocked() const {
+    return trampoline_pool_blocked_nesting_ > 0;
+  }
+
+  bool has_exception() const { return internal_trampoline_exception_; }
+
+  bool is_trampoline_emitted() const { return trampoline_emitted_; }
+
+#if V8_OOL_CONSTANT_POOL
+  void set_constant_pool_available(bool available) {
+    constant_pool_available_ = available;
+  }
+#endif
+
+ private:
+  // Code generation
+  // The relocation writer's position is at least kGap bytes below the end of
+  // the generated instructions. This is so that multi-instruction sequences do
+  // not have to check for overflow. The same is true for writes of large
+  // relocation info entries.
+  static const int kGap = 32;
+
+  // Repeated checking whether the trampoline pool should be emitted is rather
+  // expensive. By default we only check again once a number of instructions
+  // has been generated.
+  int next_buffer_check_;  // pc offset of next buffer check.
+
+  // Emission of the trampoline pool may be blocked in some code sequences.
+  int trampoline_pool_blocked_nesting_;  // Block emission if this is not zero.
+  int no_trampoline_pool_before_;  // Block emission before this pc offset.
+
+  // Relocation info generation
+  // Each relocation is encoded as a variable size value
+  static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
+  RelocInfoWriter reloc_info_writer;
+
+  // The bound position, before this we cannot do instruction elimination.
+  int last_bound_pos_;
+
+#if V8_OOL_CONSTANT_POOL
+  ConstantPoolBuilder constant_pool_builder_;
+#endif
+
+  // Code emission
+  inline void CheckBuffer();
+  void GrowBuffer();
+  inline void emit(Instr x);
+  inline void CheckTrampolinePoolQuick();
+
+  // Instruction generation
+  void a_form(Instr instr, DoubleRegister frt, DoubleRegister fra,
+              DoubleRegister frb, RCBit r);
+  void d_form(Instr instr, Register rt, Register ra, const intptr_t val,
+              bool signed_disp);
+  void x_form(Instr instr, Register ra, Register rs, Register rb, RCBit r);
+  void xo_form(Instr instr, Register rt, Register ra, Register rb, OEBit o,
+               RCBit r);
+  void md_form(Instr instr, Register ra, Register rs, int shift, int maskbit,
+               RCBit r);
+  void mds_form(Instr instr, Register ra, Register rs, Register rb, int maskbit,
+                RCBit r);
+
+  // Labels
+  void print(Label* L);
+  int max_reach_from(int pos);
+  void bind_to(Label* L, int pos);
+  void next(Label* L);
+
+  class Trampoline {
+   public:
+    Trampoline() {
+      next_slot_ = 0;
+      free_slot_count_ = 0;
+    }
+    Trampoline(int start, int slot_count) {
+      next_slot_ = start;
+      free_slot_count_ = slot_count;
+    }
+    int take_slot() {
+      int trampoline_slot = kInvalidSlotPos;
+      if (free_slot_count_ <= 0) {
+        // We have run out of space on trampolines.
+        // Make sure we fail in debug mode, so we become aware of each case
+        // when this happens.
+        DCHECK(0);
+        // Internal exception will be caught.
+      } else {
+        trampoline_slot = next_slot_;
+        free_slot_count_--;
+        next_slot_ += kTrampolineSlotsSize;
+      }
+      return trampoline_slot;
+    }
+
+   private:
+    int next_slot_;
+    int free_slot_count_;
+  };
+
+  int32_t get_trampoline_entry();
+  int unbound_labels_count_;
+  // If trampoline is emitted, generated code is becoming large. As
+  // this is already a slow case which can possibly break our code
+  // generation for the extreme case, we use this information to
+  // trigger different mode of branch instruction generation, where we
+  // no longer use a single branch instruction.
+  bool trampoline_emitted_;
+  static const int kTrampolineSlotsSize = kInstrSize;
+  static const int kMaxCondBranchReach = (1 << (16 - 1)) - 1;
+  static const int kMaxBlockTrampolineSectionSize = 64 * kInstrSize;
+  static const int kInvalidSlotPos = -1;
+
+  Trampoline trampoline_;
+  bool internal_trampoline_exception_;
+
+  friend class RegExpMacroAssemblerPPC;
+  friend class RelocInfo;
+  friend class CodePatcher;
+  friend class BlockTrampolinePoolScope;
+  PositionsRecorder positions_recorder_;
+  friend class PositionsRecorder;
+  friend class EnsureSpace;
+};
+
+
+class EnsureSpace BASE_EMBEDDED {
+ public:
+  explicit EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); }
+};
+}
+}  // namespace v8::internal
+
+#endif  // V8_PPC_ASSEMBLER_PPC_H_
diff --git a/src/ppc/builtins-ppc.cc b/src/ppc/builtins-ppc.cc
new file mode 100644
index 0000000..7817fcd
--- /dev/null
+++ b/src/ppc/builtins-ppc.cc
@@ -0,0 +1,1615 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/codegen.h"
+#include "src/debug.h"
+#include "src/deoptimizer.h"
+#include "src/full-codegen.h"
+#include "src/runtime/runtime.h"
+
+namespace v8 {
+namespace internal {
+
+
+#define __ ACCESS_MASM(masm)
+
+
+void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id,
+                                BuiltinExtraArguments extra_args) {
+  // ----------- S t a t e -------------
+  //  -- r3                 : number of arguments excluding receiver
+  //  -- r4                 : called function (only guaranteed when
+  //                          extra_args requires it)
+  //  -- cp                 : context
+  //  -- sp[0]              : last argument
+  //  -- ...
+  //  -- sp[4 * (argc - 1)] : first argument (argc == r0)
+  //  -- sp[4 * argc]       : receiver
+  // -----------------------------------
+
+  // Insert extra arguments.
+  int num_extra_args = 0;
+  if (extra_args == NEEDS_CALLED_FUNCTION) {
+    num_extra_args = 1;
+    __ push(r4);
+  } else {
+    DCHECK(extra_args == NO_EXTRA_ARGUMENTS);
+  }
+
+  // JumpToExternalReference expects r0 to contain the number of arguments
+  // including the receiver and the extra arguments.
+  __ addi(r3, r3, Operand(num_extra_args + 1));
+  __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
+}
+
+
+// Load the built-in InternalArray function from the current context.
+static void GenerateLoadInternalArrayFunction(MacroAssembler* masm,
+                                              Register result) {
+  // Load the native context.
+
+  __ LoadP(result,
+           MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
+  __ LoadP(result, FieldMemOperand(result, GlobalObject::kNativeContextOffset));
+  // Load the InternalArray function from the native context.
+  __ LoadP(result,
+           MemOperand(result, Context::SlotOffset(
+                                  Context::INTERNAL_ARRAY_FUNCTION_INDEX)));
+}
+
+
+// Load the built-in Array function from the current context.
+static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
+  // Load the native context.
+
+  __ LoadP(result,
+           MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
+  __ LoadP(result, FieldMemOperand(result, GlobalObject::kNativeContextOffset));
+  // Load the Array function from the native context.
+  __ LoadP(
+      result,
+      MemOperand(result, Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
+}
+
+
+void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r3     : number of arguments
+  //  -- lr     : return address
+  //  -- sp[...]: constructor arguments
+  // -----------------------------------
+  Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
+
+  // Get the InternalArray function.
+  GenerateLoadInternalArrayFunction(masm, r4);
+
+  if (FLAG_debug_code) {
+    // Initial map for the builtin InternalArray functions should be maps.
+    __ LoadP(r5, FieldMemOperand(r4, JSFunction::kPrototypeOrInitialMapOffset));
+    __ TestIfSmi(r5, r0);
+    __ Assert(ne, kUnexpectedInitialMapForInternalArrayFunction, cr0);
+    __ CompareObjectType(r5, r6, r7, MAP_TYPE);
+    __ Assert(eq, kUnexpectedInitialMapForInternalArrayFunction);
+  }
+
+  // Run the native code for the InternalArray function called as a normal
+  // function.
+  // tail call a stub
+  InternalArrayConstructorStub stub(masm->isolate());
+  __ TailCallStub(&stub);
+}
+
+
+void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r3     : number of arguments
+  //  -- lr     : return address
+  //  -- sp[...]: constructor arguments
+  // -----------------------------------
+  Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
+
+  // Get the Array function.
+  GenerateLoadArrayFunction(masm, r4);
+
+  if (FLAG_debug_code) {
+    // Initial map for the builtin Array functions should be maps.
+    __ LoadP(r5, FieldMemOperand(r4, JSFunction::kPrototypeOrInitialMapOffset));
+    __ TestIfSmi(r5, r0);
+    __ Assert(ne, kUnexpectedInitialMapForArrayFunction, cr0);
+    __ CompareObjectType(r5, r6, r7, MAP_TYPE);
+    __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
+  }
+
+  // Run the native code for the Array function called as a normal function.
+  // tail call a stub
+  __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
+  ArrayConstructorStub stub(masm->isolate());
+  __ TailCallStub(&stub);
+}
+
+
+void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r3                     : number of arguments
+  //  -- r4                     : constructor function
+  //  -- lr                     : return address
+  //  -- sp[(argc - n - 1) * 4] : arg[n] (zero based)
+  //  -- sp[argc * 4]           : receiver
+  // -----------------------------------
+  Counters* counters = masm->isolate()->counters();
+  __ IncrementCounter(counters->string_ctor_calls(), 1, r5, r6);
+
+  Register function = r4;
+  if (FLAG_debug_code) {
+    __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, r5);
+    __ cmp(function, r5);
+    __ Assert(eq, kUnexpectedStringFunction);
+  }
+
+  // Load the first arguments in r3 and get rid of the rest.
+  Label no_arguments;
+  __ cmpi(r3, Operand::Zero());
+  __ beq(&no_arguments);
+  // First args = sp[(argc - 1) * 4].
+  __ subi(r3, r3, Operand(1));
+  __ ShiftLeftImm(r3, r3, Operand(kPointerSizeLog2));
+  __ add(sp, sp, r3);
+  __ LoadP(r3, MemOperand(sp));
+  // sp now point to args[0], drop args[0] + receiver.
+  __ Drop(2);
+
+  Register argument = r5;
+  Label not_cached, argument_is_string;
+  __ LookupNumberStringCache(r3,        // Input.
+                             argument,  // Result.
+                             r6,        // Scratch.
+                             r7,        // Scratch.
+                             r8,        // Scratch.
+                             &not_cached);
+  __ IncrementCounter(counters->string_ctor_cached_number(), 1, r6, r7);
+  __ bind(&argument_is_string);
+
+  // ----------- S t a t e -------------
+  //  -- r5     : argument converted to string
+  //  -- r4     : constructor function
+  //  -- lr     : return address
+  // -----------------------------------
+
+  Label gc_required;
+  __ Allocate(JSValue::kSize,
+              r3,  // Result.
+              r6,  // Scratch.
+              r7,  // Scratch.
+              &gc_required, TAG_OBJECT);
+
+  // Initialising the String Object.
+  Register map = r6;
+  __ LoadGlobalFunctionInitialMap(function, map, r7);
+  if (FLAG_debug_code) {
+    __ lbz(r7, FieldMemOperand(map, Map::kInstanceSizeOffset));
+    __ cmpi(r7, Operand(JSValue::kSize >> kPointerSizeLog2));
+    __ Assert(eq, kUnexpectedStringWrapperInstanceSize);
+    __ lbz(r7, FieldMemOperand(map, Map::kUnusedPropertyFieldsOffset));
+    __ cmpi(r7, Operand::Zero());
+    __ Assert(eq, kUnexpectedUnusedPropertiesOfStringWrapper);
+  }
+  __ StoreP(map, FieldMemOperand(r3, HeapObject::kMapOffset), r0);
+
+  __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
+  __ StoreP(r6, FieldMemOperand(r3, JSObject::kPropertiesOffset), r0);
+  __ StoreP(r6, FieldMemOperand(r3, JSObject::kElementsOffset), r0);
+
+  __ StoreP(argument, FieldMemOperand(r3, JSValue::kValueOffset), r0);
+
+  // Ensure the object is fully initialized.
+  STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
+
+  __ Ret();
+
+  // The argument was not found in the number to string cache. Check
+  // if it's a string already before calling the conversion builtin.
+  Label convert_argument;
+  __ bind(&not_cached);
+  __ JumpIfSmi(r3, &convert_argument);
+
+  // Is it a String?
+  __ LoadP(r5, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ lbz(r6, FieldMemOperand(r5, Map::kInstanceTypeOffset));
+  STATIC_ASSERT(kNotStringTag != 0);
+  __ andi(r0, r6, Operand(kIsNotStringMask));
+  __ bne(&convert_argument, cr0);
+  __ mr(argument, r3);
+  __ IncrementCounter(counters->string_ctor_conversions(), 1, r6, r7);
+  __ b(&argument_is_string);
+
+  // Invoke the conversion builtin and put the result into r5.
+  __ bind(&convert_argument);
+  __ push(function);  // Preserve the function.
+  __ IncrementCounter(counters->string_ctor_conversions(), 1, r6, r7);
+  {
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    __ push(r3);
+    __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
+  }
+  __ pop(function);
+  __ mr(argument, r3);
+  __ b(&argument_is_string);
+
+  // Load the empty string into r5, remove the receiver from the
+  // stack, and jump back to the case where the argument is a string.
+  __ bind(&no_arguments);
+  __ LoadRoot(argument, Heap::kempty_stringRootIndex);
+  __ Drop(1);
+  __ b(&argument_is_string);
+
+  // At this point the argument is already a string. Call runtime to
+  // create a string wrapper.
+  __ bind(&gc_required);
+  __ IncrementCounter(counters->string_ctor_gc_required(), 1, r6, r7);
+  {
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    __ push(argument);
+    __ CallRuntime(Runtime::kNewStringWrapper, 1);
+  }
+  __ Ret();
+}
+
+
+static void CallRuntimePassFunction(MacroAssembler* masm,
+                                    Runtime::FunctionId function_id) {
+  FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+  // Push a copy of the function onto the stack.
+  // Push function as parameter to the runtime call.
+  __ Push(r4, r4);
+
+  __ CallRuntime(function_id, 1);
+  // Restore reciever.
+  __ Pop(r4);
+}
+
+
+static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
+  __ LoadP(ip, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
+  __ LoadP(ip, FieldMemOperand(ip, SharedFunctionInfo::kCodeOffset));
+  __ addi(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ JumpToJSEntry(ip);
+}
+
+
+static void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
+  __ addi(ip, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ JumpToJSEntry(ip);
+}
+
+
+void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
+  // Checking whether the queued function is ready for install is optional,
+  // since we come across interrupts and stack checks elsewhere.  However,
+  // not checking may delay installing ready functions, and always checking
+  // would be quite expensive.  A good compromise is to first check against
+  // stack limit as a cue for an interrupt signal.
+  Label ok;
+  __ LoadRoot(ip, Heap::kStackLimitRootIndex);
+  __ cmpl(sp, ip);
+  __ bge(&ok);
+
+  CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode);
+  GenerateTailCallToReturnedCode(masm);
+
+  __ bind(&ok);
+  GenerateTailCallToSharedCode(masm);
+}
+
+
+static void Generate_JSConstructStubHelper(MacroAssembler* masm,
+                                           bool is_api_function,
+                                           bool create_memento) {
+  // ----------- S t a t e -------------
+  //  -- r3     : number of arguments
+  //  -- r4     : constructor function
+  //  -- r5     : allocation site or undefined
+  //  -- lr     : return address
+  //  -- sp[...]: constructor arguments
+  // -----------------------------------
+
+  // Should never create mementos for api functions.
+  DCHECK(!is_api_function || !create_memento);
+
+  Isolate* isolate = masm->isolate();
+
+  // Enter a construct frame.
+  {
+    FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT);
+
+    if (create_memento) {
+      __ AssertUndefinedOrAllocationSite(r5, r6);
+      __ push(r5);
+    }
+
+    // Preserve the two incoming parameters on the stack.
+    __ SmiTag(r3);
+    __ push(r3);  // Smi-tagged arguments count.
+    __ push(r4);  // Constructor function.
+
+    // Try to allocate the object without transitioning into C code. If any of
+    // the preconditions is not met, the code bails out to the runtime call.
+    Label rt_call, allocated;
+    if (FLAG_inline_new) {
+      Label undo_allocation;
+      ExternalReference debug_step_in_fp =
+          ExternalReference::debug_step_in_fp_address(isolate);
+      __ mov(r5, Operand(debug_step_in_fp));
+      __ LoadP(r5, MemOperand(r5));
+      __ cmpi(r5, Operand::Zero());
+      __ bne(&rt_call);
+
+      // Load the initial map and verify that it is in fact a map.
+      // r4: constructor function
+      __ LoadP(r5,
+               FieldMemOperand(r4, JSFunction::kPrototypeOrInitialMapOffset));
+      __ JumpIfSmi(r5, &rt_call);
+      __ CompareObjectType(r5, r6, r7, MAP_TYPE);
+      __ bne(&rt_call);
+
+      // Check that the constructor is not constructing a JSFunction (see
+      // comments in Runtime_NewObject in runtime.cc). In which case the
+      // initial map's instance type would be JS_FUNCTION_TYPE.
+      // r4: constructor function
+      // r5: initial map
+      __ CompareInstanceType(r5, r6, JS_FUNCTION_TYPE);
+      __ beq(&rt_call);
+
+      if (!is_api_function) {
+        Label allocate;
+        MemOperand bit_field3 = FieldMemOperand(r5, Map::kBitField3Offset);
+        // Check if slack tracking is enabled.
+        __ lwz(r7, bit_field3);
+        __ DecodeField<Map::ConstructionCount>(r11, r7);
+        STATIC_ASSERT(JSFunction::kNoSlackTracking == 0);
+        __ cmpi(r11, Operand::Zero());  // JSFunction::kNoSlackTracking
+        __ beq(&allocate);
+        // Decrease generous allocation count.
+        __ Add(r7, r7, -(1 << Map::ConstructionCount::kShift), r0);
+        __ stw(r7, bit_field3);
+        __ cmpi(r11, Operand(JSFunction::kFinishSlackTracking));
+        __ bne(&allocate);
+
+        __ push(r4);
+
+        __ Push(r5, r4);  // r4 = constructor
+        __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
+
+        __ Pop(r4, r5);
+
+        __ bind(&allocate);
+      }
+
+      // Now allocate the JSObject on the heap.
+      // r4: constructor function
+      // r5: initial map
+      __ lbz(r6, FieldMemOperand(r5, Map::kInstanceSizeOffset));
+      if (create_memento) {
+        __ addi(r6, r6, Operand(AllocationMemento::kSize / kPointerSize));
+      }
+
+      __ Allocate(r6, r7, r8, r9, &rt_call, SIZE_IN_WORDS);
+
+      // Allocated the JSObject, now initialize the fields. Map is set to
+      // initial map and properties and elements are set to empty fixed array.
+      // r4: constructor function
+      // r5: initial map
+      // r6: object size (not including memento if create_memento)
+      // r7: JSObject (not tagged)
+      __ LoadRoot(r9, Heap::kEmptyFixedArrayRootIndex);
+      __ mr(r8, r7);
+      __ StoreP(r5, MemOperand(r8, JSObject::kMapOffset));
+      __ StoreP(r9, MemOperand(r8, JSObject::kPropertiesOffset));
+      __ StoreP(r9, MemOperand(r8, JSObject::kElementsOffset));
+      __ addi(r8, r8, Operand(JSObject::kElementsOffset + kPointerSize));
+
+      __ ShiftLeftImm(r9, r6, Operand(kPointerSizeLog2));
+      __ add(r9, r7, r9);  // End of object.
+
+      // Fill all the in-object properties with the appropriate filler.
+      // r4: constructor function
+      // r5: initial map
+      // r6: object size (in words, including memento if create_memento)
+      // r7: JSObject (not tagged)
+      // r8: First in-object property of JSObject (not tagged)
+      // r9: End of object
+      DCHECK_EQ(3 * kPointerSize, JSObject::kHeaderSize);
+      __ LoadRoot(r10, Heap::kUndefinedValueRootIndex);
+
+      if (!is_api_function) {
+        Label no_inobject_slack_tracking;
+
+        // Check if slack tracking is enabled.
+        STATIC_ASSERT(JSFunction::kNoSlackTracking == 0);
+        __ cmpi(r11, Operand::Zero());  // JSFunction::kNoSlackTracking
+        __ beq(&no_inobject_slack_tracking);
+
+        // Allocate object with a slack.
+        __ lbz(r3, FieldMemOperand(r5, Map::kPreAllocatedPropertyFieldsOffset));
+        if (FLAG_debug_code) {
+          __ ShiftLeftImm(r0, r3, Operand(kPointerSizeLog2));
+          __ add(r0, r8, r0);
+          // r0: offset of first field after pre-allocated fields
+          __ cmp(r0, r9);
+          __ Assert(le, kUnexpectedNumberOfPreAllocatedPropertyFields);
+        }
+        {
+          Label done;
+          __ cmpi(r3, Operand::Zero());
+          __ beq(&done);
+          __ InitializeNFieldsWithFiller(r8, r3, r10);
+          __ bind(&done);
+        }
+        // To allow for truncation.
+        __ LoadRoot(r10, Heap::kOnePointerFillerMapRootIndex);
+        // Fill the remaining fields with one pointer filler map.
+
+        __ bind(&no_inobject_slack_tracking);
+      }
+
+      if (create_memento) {
+        __ subi(r3, r9, Operand(AllocationMemento::kSize));
+        __ InitializeFieldsWithFiller(r8, r3, r10);
+
+        // Fill in memento fields.
+        // r8: points to the allocated but uninitialized memento.
+        __ LoadRoot(r10, Heap::kAllocationMementoMapRootIndex);
+        __ StoreP(r10, MemOperand(r8, AllocationMemento::kMapOffset));
+        // Load the AllocationSite
+        __ LoadP(r10, MemOperand(sp, 2 * kPointerSize));
+        __ StoreP(r10,
+                  MemOperand(r8, AllocationMemento::kAllocationSiteOffset));
+        __ addi(r8, r8, Operand(AllocationMemento::kAllocationSiteOffset +
+                                kPointerSize));
+      } else {
+        __ InitializeFieldsWithFiller(r8, r9, r10);
+      }
+
+      // Add the object tag to make the JSObject real, so that we can continue
+      // and jump into the continuation code at any time from now on. Any
+      // failures need to undo the allocation, so that the heap is in a
+      // consistent state and verifiable.
+      __ addi(r7, r7, Operand(kHeapObjectTag));
+
+      // Check if a non-empty properties array is needed. Continue with
+      // allocated object if not fall through to runtime call if it is.
+      // r4: constructor function
+      // r7: JSObject
+      // r8: start of next object (not tagged)
+      __ lbz(r6, FieldMemOperand(r5, Map::kUnusedPropertyFieldsOffset));
+      // The field instance sizes contains both pre-allocated property fields
+      // and in-object properties.
+      __ lbz(r0, FieldMemOperand(r5, Map::kPreAllocatedPropertyFieldsOffset));
+      __ add(r6, r6, r0);
+      __ lbz(r0, FieldMemOperand(r5, Map::kInObjectPropertiesOffset));
+      __ sub(r6, r6, r0, LeaveOE, SetRC);
+
+      // Done if no extra properties are to be allocated.
+      __ beq(&allocated, cr0);
+      __ Assert(ge, kPropertyAllocationCountFailed, cr0);
+
+      // Scale the number of elements by pointer size and add the header for
+      // FixedArrays to the start of the next object calculation from above.
+      // r4: constructor
+      // r6: number of elements in properties array
+      // r7: JSObject
+      // r8: start of next object
+      __ addi(r3, r6, Operand(FixedArray::kHeaderSize / kPointerSize));
+      __ Allocate(
+          r3, r8, r9, r5, &undo_allocation,
+          static_cast<AllocationFlags>(RESULT_CONTAINS_TOP | SIZE_IN_WORDS));
+
+      // Initialize the FixedArray.
+      // r4: constructor
+      // r6: number of elements in properties array
+      // r7: JSObject
+      // r8: FixedArray (not tagged)
+      __ LoadRoot(r9, Heap::kFixedArrayMapRootIndex);
+      __ mr(r5, r8);
+      DCHECK_EQ(0 * kPointerSize, JSObject::kMapOffset);
+      __ StoreP(r9, MemOperand(r5));
+      DCHECK_EQ(1 * kPointerSize, FixedArray::kLengthOffset);
+      __ SmiTag(r3, r6);
+      __ StoreP(r3, MemOperand(r5, kPointerSize));
+      __ addi(r5, r5, Operand(2 * kPointerSize));
+
+      // Initialize the fields to undefined.
+      // r4: constructor function
+      // r5: First element of FixedArray (not tagged)
+      // r6: number of elements in properties array
+      // r7: JSObject
+      // r8: FixedArray (not tagged)
+      DCHECK_EQ(2 * kPointerSize, FixedArray::kHeaderSize);
+      {
+        Label done;
+        __ cmpi(r6, Operand::Zero());
+        __ beq(&done);
+        if (!is_api_function || create_memento) {
+          __ LoadRoot(r10, Heap::kUndefinedValueRootIndex);
+        } else if (FLAG_debug_code) {
+          __ LoadRoot(r11, Heap::kUndefinedValueRootIndex);
+          __ cmp(r10, r11);
+          __ Assert(eq, kUndefinedValueNotLoaded);
+        }
+        __ InitializeNFieldsWithFiller(r5, r6, r10);
+        __ bind(&done);
+      }
+
+      // Store the initialized FixedArray into the properties field of
+      // the JSObject
+      // r4: constructor function
+      // r7: JSObject
+      // r8: FixedArray (not tagged)
+      __ addi(r8, r8, Operand(kHeapObjectTag));  // Add the heap tag.
+      __ StoreP(r8, FieldMemOperand(r7, JSObject::kPropertiesOffset), r0);
+
+      // Continue with JSObject being successfully allocated
+      // r4: constructor function
+      // r7: JSObject
+      __ b(&allocated);
+
+      // Undo the setting of the new top so that the heap is verifiable. For
+      // example, the map's unused properties potentially do not match the
+      // allocated objects unused properties.
+      // r7: JSObject (previous new top)
+      __ bind(&undo_allocation);
+      __ UndoAllocationInNewSpace(r7, r8);
+    }
+
+    // Allocate the new receiver object using the runtime call.
+    // r4: constructor function
+    __ bind(&rt_call);
+    if (create_memento) {
+      // Get the cell or allocation site.
+      __ LoadP(r5, MemOperand(sp, 2 * kPointerSize));
+      __ push(r5);
+    }
+
+    __ push(r4);  // argument for Runtime_NewObject
+    if (create_memento) {
+      __ CallRuntime(Runtime::kNewObjectWithAllocationSite, 2);
+    } else {
+      __ CallRuntime(Runtime::kNewObject, 1);
+    }
+    __ mr(r7, r3);
+
+    // If we ended up using the runtime, and we want a memento, then the
+    // runtime call made it for us, and we shouldn't do create count
+    // increment.
+    Label count_incremented;
+    if (create_memento) {
+      __ b(&count_incremented);
+    }
+
+    // Receiver for constructor call allocated.
+    // r7: JSObject
+    __ bind(&allocated);
+
+    if (create_memento) {
+      __ LoadP(r5, MemOperand(sp, kPointerSize * 2));
+      __ LoadRoot(r8, Heap::kUndefinedValueRootIndex);
+      __ cmp(r5, r8);
+      __ beq(&count_incremented);
+      // r5 is an AllocationSite. We are creating a memento from it, so we
+      // need to increment the memento create count.
+      __ LoadP(
+          r6, FieldMemOperand(r5, AllocationSite::kPretenureCreateCountOffset));
+      __ AddSmiLiteral(r6, r6, Smi::FromInt(1), r0);
+      __ StoreP(
+          r6, FieldMemOperand(r5, AllocationSite::kPretenureCreateCountOffset),
+          r0);
+      __ bind(&count_incremented);
+    }
+
+    __ Push(r7, r7);
+
+    // Reload the number of arguments and the constructor from the stack.
+    // sp[0]: receiver
+    // sp[1]: receiver
+    // sp[2]: constructor function
+    // sp[3]: number of arguments (smi-tagged)
+    __ LoadP(r4, MemOperand(sp, 2 * kPointerSize));
+    __ LoadP(r6, MemOperand(sp, 3 * kPointerSize));
+
+    // Set up pointer to last argument.
+    __ addi(r5, fp, Operand(StandardFrameConstants::kCallerSPOffset));
+
+    // Set up number of arguments for function call below
+    __ SmiUntag(r3, r6);
+
+    // Copy arguments and receiver to the expression stack.
+    // r3: number of arguments
+    // r4: constructor function
+    // r5: address of last argument (caller sp)
+    // r6: number of arguments (smi-tagged)
+    // sp[0]: receiver
+    // sp[1]: receiver
+    // sp[2]: constructor function
+    // sp[3]: number of arguments (smi-tagged)
+    Label loop, no_args;
+    __ cmpi(r3, Operand::Zero());
+    __ beq(&no_args);
+    __ ShiftLeftImm(ip, r3, Operand(kPointerSizeLog2));
+    __ mtctr(r3);
+    __ bind(&loop);
+    __ subi(ip, ip, Operand(kPointerSize));
+    __ LoadPX(r0, MemOperand(r5, ip));
+    __ push(r0);
+    __ bdnz(&loop);
+    __ bind(&no_args);
+
+    // Call the function.
+    // r3: number of arguments
+    // r4: constructor function
+    if (is_api_function) {
+      __ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
+      Handle<Code> code = masm->isolate()->builtins()->HandleApiCallConstruct();
+      __ Call(code, RelocInfo::CODE_TARGET);
+    } else {
+      ParameterCount actual(r3);
+      __ InvokeFunction(r4, actual, CALL_FUNCTION, NullCallWrapper());
+    }
+
+    // Store offset of return address for deoptimizer.
+    if (!is_api_function) {
+      masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
+    }
+
+    // Restore context from the frame.
+    // r3: result
+    // sp[0]: receiver
+    // sp[1]: constructor function
+    // sp[2]: number of arguments (smi-tagged)
+    __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+
+    // If the result is an object (in the ECMA sense), we should get rid
+    // of the receiver and use the result; see ECMA-262 section 13.2.2-7
+    // on page 74.
+    Label use_receiver, exit;
+
+    // If the result is a smi, it is *not* an object in the ECMA sense.
+    // r3: result
+    // sp[0]: receiver (newly allocated object)
+    // sp[1]: constructor function
+    // sp[2]: number of arguments (smi-tagged)
+    __ JumpIfSmi(r3, &use_receiver);
+
+    // If the type of the result (stored in its map) is less than
+    // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
+    __ CompareObjectType(r3, r4, r6, FIRST_SPEC_OBJECT_TYPE);
+    __ bge(&exit);
+
+    // Throw away the result of the constructor invocation and use the
+    // on-stack receiver as the result.
+    __ bind(&use_receiver);
+    __ LoadP(r3, MemOperand(sp));
+
+    // Remove receiver from the stack, remove caller arguments, and
+    // return.
+    __ bind(&exit);
+    // r3: result
+    // sp[0]: receiver (newly allocated object)
+    // sp[1]: constructor function
+    // sp[2]: number of arguments (smi-tagged)
+    __ LoadP(r4, MemOperand(sp, 2 * kPointerSize));
+
+    // Leave construct frame.
+  }
+
+  __ SmiToPtrArrayOffset(r4, r4);
+  __ add(sp, sp, r4);
+  __ addi(sp, sp, Operand(kPointerSize));
+  __ IncrementCounter(isolate->counters()->constructed_objects(), 1, r4, r5);
+  __ blr();
+}
+
+
+void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
+  Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new);
+}
+
+
+void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
+  Generate_JSConstructStubHelper(masm, true, false);
+}
+
+
+static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
+                                             bool is_construct) {
+  // Called from Generate_JS_Entry
+  // r3: code entry
+  // r4: function
+  // r5: receiver
+  // r6: argc
+  // r7: argv
+  // r0,r8-r9, cp may be clobbered
+  ProfileEntryHookStub::MaybeCallEntryHook(masm);
+
+  // Clear the context before we push it when entering the internal frame.
+  __ li(cp, Operand::Zero());
+
+  // Enter an internal frame.
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    // Set up the context from the function argument.
+    __ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
+
+    __ InitializeRootRegister();
+
+    // Push the function and the receiver onto the stack.
+    __ push(r4);
+    __ push(r5);
+
+    // Copy arguments to the stack in a loop.
+    // r4: function
+    // r6: argc
+    // r7: argv, i.e. points to first arg
+    Label loop, entry;
+    __ ShiftLeftImm(r0, r6, Operand(kPointerSizeLog2));
+    __ add(r5, r7, r0);
+    // r5 points past last arg.
+    __ b(&entry);
+    __ bind(&loop);
+    __ LoadP(r8, MemOperand(r7));  // read next parameter
+    __ addi(r7, r7, Operand(kPointerSize));
+    __ LoadP(r0, MemOperand(r8));  // dereference handle
+    __ push(r0);                   // push parameter
+    __ bind(&entry);
+    __ cmp(r7, r5);
+    __ bne(&loop);
+
+    // Initialize all JavaScript callee-saved registers, since they will be seen
+    // by the garbage collector as part of handlers.
+    __ LoadRoot(r7, Heap::kUndefinedValueRootIndex);
+    __ mr(r14, r7);
+    __ mr(r15, r7);
+    __ mr(r16, r7);
+    __ mr(r17, r7);
+
+    // Invoke the code and pass argc as r3.
+    __ mr(r3, r6);
+    if (is_construct) {
+      // No type feedback cell is available
+      __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
+      CallConstructStub stub(masm->isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
+      __ CallStub(&stub);
+    } else {
+      ParameterCount actual(r3);
+      __ InvokeFunction(r4, actual, CALL_FUNCTION, NullCallWrapper());
+    }
+    // Exit the JS frame and remove the parameters (except function), and
+    // return.
+  }
+  __ blr();
+
+  // r3: result
+}
+
+
+void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
+  Generate_JSEntryTrampolineHelper(masm, false);
+}
+
+
+void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
+  Generate_JSEntryTrampolineHelper(masm, true);
+}
+
+
+void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
+  CallRuntimePassFunction(masm, Runtime::kCompileLazy);
+  GenerateTailCallToReturnedCode(masm);
+}
+
+
+static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
+  FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+  // Push a copy of the function onto the stack.
+  // Push function as parameter to the runtime call.
+  __ Push(r4, r4);
+  // Whether to compile in a background thread.
+  __ Push(masm->isolate()->factory()->ToBoolean(concurrent));
+
+  __ CallRuntime(Runtime::kCompileOptimized, 2);
+  // Restore receiver.
+  __ pop(r4);
+}
+
+
+void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
+  CallCompileOptimized(masm, false);
+  GenerateTailCallToReturnedCode(masm);
+}
+
+
+void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
+  CallCompileOptimized(masm, true);
+  GenerateTailCallToReturnedCode(masm);
+}
+
+
+static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
+  // For now, we are relying on the fact that make_code_young doesn't do any
+  // garbage collection which allows us to save/restore the registers without
+  // worrying about which of them contain pointers. We also don't build an
+  // internal frame to make the code faster, since we shouldn't have to do stack
+  // crawls in MakeCodeYoung. This seems a bit fragile.
+
+  // Point r3 at the start of the PlatformCodeAge sequence.
+  __ mr(r3, ip);
+
+  // The following registers must be saved and restored when calling through to
+  // the runtime:
+  //   r3 - contains return address (beginning of patch sequence)
+  //   r4 - isolate
+  //   lr - return address
+  FrameScope scope(masm, StackFrame::MANUAL);
+  __ mflr(r0);
+  __ MultiPush(r0.bit() | r3.bit() | r4.bit() | fp.bit());
+  __ PrepareCallCFunction(2, 0, r5);
+  __ mov(r4, Operand(ExternalReference::isolate_address(masm->isolate())));
+  __ CallCFunction(
+      ExternalReference::get_make_code_young_function(masm->isolate()), 2);
+  __ MultiPop(r0.bit() | r3.bit() | r4.bit() | fp.bit());
+  __ mtlr(r0);
+  __ mr(ip, r3);
+  __ Jump(ip);
+}
+
+#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C)                  \
+  void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
+      MacroAssembler* masm) {                                 \
+    GenerateMakeCodeYoungAgainCommon(masm);                   \
+  }                                                           \
+  void Builtins::Generate_Make##C##CodeYoungAgainOddMarking(  \
+      MacroAssembler* masm) {                                 \
+    GenerateMakeCodeYoungAgainCommon(masm);                   \
+  }
+CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
+#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
+
+
+void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
+  // For now, we are relying on the fact that make_code_young doesn't do any
+  // garbage collection which allows us to save/restore the registers without
+  // worrying about which of them contain pointers. We also don't build an
+  // internal frame to make the code faster, since we shouldn't have to do stack
+  // crawls in MakeCodeYoung. This seems a bit fragile.
+
+  // Point r3 at the start of the PlatformCodeAge sequence.
+  __ mr(r3, ip);
+
+  // The following registers must be saved and restored when calling through to
+  // the runtime:
+  //   r3 - contains return address (beginning of patch sequence)
+  //   r4 - isolate
+  //   lr - return address
+  FrameScope scope(masm, StackFrame::MANUAL);
+  __ mflr(r0);
+  __ MultiPush(r0.bit() | r3.bit() | r4.bit() | fp.bit());
+  __ PrepareCallCFunction(2, 0, r5);
+  __ mov(r4, Operand(ExternalReference::isolate_address(masm->isolate())));
+  __ CallCFunction(
+      ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
+      2);
+  __ MultiPop(r0.bit() | r3.bit() | r4.bit() | fp.bit());
+  __ mtlr(r0);
+  __ mr(ip, r3);
+
+  // Perform prologue operations usually performed by the young code stub.
+  __ PushFixedFrame(r4);
+  __ addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+
+  // Jump to point after the code-age stub.
+  __ addi(r3, ip, Operand(kNoCodeAgeSequenceLength));
+  __ Jump(r3);
+}
+
+
+void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
+  GenerateMakeCodeYoungAgainCommon(masm);
+}
+
+
+static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
+                                             SaveFPRegsMode save_doubles) {
+  {
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+
+    // Preserve registers across notification, this is important for compiled
+    // stubs that tail call the runtime on deopts passing their parameters in
+    // registers.
+    __ MultiPush(kJSCallerSaved | kCalleeSaved);
+    // Pass the function and deoptimization type to the runtime system.
+    __ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles);
+    __ MultiPop(kJSCallerSaved | kCalleeSaved);
+  }
+
+  __ addi(sp, sp, Operand(kPointerSize));  // Ignore state
+  __ blr();                                // Jump to miss handler
+}
+
+
+void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
+  Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
+}
+
+
+void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
+  Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
+}
+
+
+static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
+                                             Deoptimizer::BailoutType type) {
+  {
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    // Pass the function and deoptimization type to the runtime system.
+    __ LoadSmiLiteral(r3, Smi::FromInt(static_cast<int>(type)));
+    __ push(r3);
+    __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
+  }
+
+  // Get the full codegen state from the stack and untag it -> r9.
+  __ LoadP(r9, MemOperand(sp, 0 * kPointerSize));
+  __ SmiUntag(r9);
+  // Switch on the state.
+  Label with_tos_register, unknown_state;
+  __ cmpi(r9, Operand(FullCodeGenerator::NO_REGISTERS));
+  __ bne(&with_tos_register);
+  __ addi(sp, sp, Operand(1 * kPointerSize));  // Remove state.
+  __ Ret();
+
+  __ bind(&with_tos_register);
+  __ LoadP(r3, MemOperand(sp, 1 * kPointerSize));
+  __ cmpi(r9, Operand(FullCodeGenerator::TOS_REG));
+  __ bne(&unknown_state);
+  __ addi(sp, sp, Operand(2 * kPointerSize));  // Remove state.
+  __ Ret();
+
+  __ bind(&unknown_state);
+  __ stop("no cases left");
+}
+
+
+void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
+  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
+}
+
+
+void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
+  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
+}
+
+
+void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
+  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
+}
+
+
+void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
+  // Lookup the function in the JavaScript frame.
+  __ LoadP(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  {
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    // Pass function as argument.
+    __ push(r3);
+    __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
+  }
+
+  // If the code object is null, just return to the unoptimized code.
+  Label skip;
+  __ CmpSmiLiteral(r3, Smi::FromInt(0), r0);
+  __ bne(&skip);
+  __ Ret();
+
+  __ bind(&skip);
+
+  // Load deoptimization data from the code object.
+  // <deopt_data> = <code>[#deoptimization_data_offset]
+  __ LoadP(r4, FieldMemOperand(r3, Code::kDeoptimizationDataOffset));
+
+#if V8_OOL_CONSTANT_POOL
+  {
+    ConstantPoolUnavailableScope constant_pool_unavailable(masm);
+    __ LoadP(kConstantPoolRegister,
+             FieldMemOperand(r3, Code::kConstantPoolOffset));
+#endif
+
+    // Load the OSR entrypoint offset from the deoptimization data.
+    // <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset]
+    __ LoadP(r4, FieldMemOperand(
+                     r4, FixedArray::OffsetOfElementAt(
+                             DeoptimizationInputData::kOsrPcOffsetIndex)));
+    __ SmiUntag(r4);
+
+    // Compute the target address = code_obj + header_size + osr_offset
+    // <entry_addr> = <code_obj> + #header_size + <osr_offset>
+    __ add(r3, r3, r4);
+    __ addi(r0, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
+    __ mtlr(r0);
+
+    // And "return" to the OSR entry point of the function.
+    __ Ret();
+#if V8_OOL_CONSTANT_POOL
+  }
+#endif
+}
+
+
+void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
+  // We check the stack limit as indicator that recompilation might be done.
+  Label ok;
+  __ LoadRoot(ip, Heap::kStackLimitRootIndex);
+  __ cmpl(sp, ip);
+  __ bge(&ok);
+  {
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    __ CallRuntime(Runtime::kStackGuard, 0);
+  }
+  __ Jump(masm->isolate()->builtins()->OnStackReplacement(),
+          RelocInfo::CODE_TARGET);
+
+  __ bind(&ok);
+  __ Ret();
+}
+
+
+void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
+  // 1. Make sure we have at least one argument.
+  // r3: actual number of arguments
+  {
+    Label done;
+    __ cmpi(r3, Operand::Zero());
+    __ bne(&done);
+    __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
+    __ push(r5);
+    __ addi(r3, r3, Operand(1));
+    __ bind(&done);
+  }
+
+  // 2. Get the function to call (passed as receiver) from the stack, check
+  //    if it is a function.
+  // r3: actual number of arguments
+  Label slow, non_function;
+  __ ShiftLeftImm(r4, r3, Operand(kPointerSizeLog2));
+  __ add(r4, sp, r4);
+  __ LoadP(r4, MemOperand(r4));
+  __ JumpIfSmi(r4, &non_function);
+  __ CompareObjectType(r4, r5, r5, JS_FUNCTION_TYPE);
+  __ bne(&slow);
+
+  // 3a. Patch the first argument if necessary when calling a function.
+  // r3: actual number of arguments
+  // r4: function
+  Label shift_arguments;
+  __ li(r7, Operand::Zero());  // indicate regular JS_FUNCTION
+  {
+    Label convert_to_object, use_global_proxy, patch_receiver;
+    // Change context eagerly in case we need the global receiver.
+    __ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
+
+    // Do not transform the receiver for strict mode functions.
+    __ LoadP(r5, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
+    __ lwz(r6, FieldMemOperand(r5, SharedFunctionInfo::kCompilerHintsOffset));
+    __ TestBit(r6,
+#if V8_TARGET_ARCH_PPC64
+               SharedFunctionInfo::kStrictModeFunction,
+#else
+               SharedFunctionInfo::kStrictModeFunction + kSmiTagSize,
+#endif
+               r0);
+    __ bne(&shift_arguments, cr0);
+
+    // Do not transform the receiver for native (Compilerhints already in r6).
+    __ TestBit(r6,
+#if V8_TARGET_ARCH_PPC64
+               SharedFunctionInfo::kNative,
+#else
+               SharedFunctionInfo::kNative + kSmiTagSize,
+#endif
+               r0);
+    __ bne(&shift_arguments, cr0);
+
+    // Compute the receiver in sloppy mode.
+    __ ShiftLeftImm(ip, r3, Operand(kPointerSizeLog2));
+    __ add(r5, sp, ip);
+    __ LoadP(r5, MemOperand(r5, -kPointerSize));
+    // r3: actual number of arguments
+    // r4: function
+    // r5: first argument
+    __ JumpIfSmi(r5, &convert_to_object);
+
+    __ LoadRoot(r6, Heap::kUndefinedValueRootIndex);
+    __ cmp(r5, r6);
+    __ beq(&use_global_proxy);
+    __ LoadRoot(r6, Heap::kNullValueRootIndex);
+    __ cmp(r5, r6);
+    __ beq(&use_global_proxy);
+
+    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
+    __ CompareObjectType(r5, r6, r6, FIRST_SPEC_OBJECT_TYPE);
+    __ bge(&shift_arguments);
+
+    __ bind(&convert_to_object);
+
+    {
+      // Enter an internal frame in order to preserve argument count.
+      FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+      __ SmiTag(r3);
+      __ Push(r3, r5);
+      __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
+      __ mr(r5, r3);
+
+      __ pop(r3);
+      __ SmiUntag(r3);
+
+      // Exit the internal frame.
+    }
+
+    // Restore the function to r4, and the flag to r7.
+    __ ShiftLeftImm(r7, r3, Operand(kPointerSizeLog2));
+    __ add(r7, sp, r7);
+    __ LoadP(r4, MemOperand(r7));
+    __ li(r7, Operand::Zero());
+    __ b(&patch_receiver);
+
+    __ bind(&use_global_proxy);
+    __ LoadP(r5, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
+    __ LoadP(r5, FieldMemOperand(r5, GlobalObject::kGlobalProxyOffset));
+
+    __ bind(&patch_receiver);
+    __ ShiftLeftImm(ip, r3, Operand(kPointerSizeLog2));
+    __ add(r6, sp, ip);
+    __ StoreP(r5, MemOperand(r6, -kPointerSize));
+
+    __ b(&shift_arguments);
+  }
+
+  // 3b. Check for function proxy.
+  __ bind(&slow);
+  __ li(r7, Operand(1, RelocInfo::NONE32));  // indicate function proxy
+  __ cmpi(r5, Operand(JS_FUNCTION_PROXY_TYPE));
+  __ beq(&shift_arguments);
+  __ bind(&non_function);
+  __ li(r7, Operand(2, RelocInfo::NONE32));  // indicate non-function
+
+  // 3c. Patch the first argument when calling a non-function.  The
+  //     CALL_NON_FUNCTION builtin expects the non-function callee as
+  //     receiver, so overwrite the first argument which will ultimately
+  //     become the receiver.
+  // r3: actual number of arguments
+  // r4: function
+  // r7: call type (0: JS function, 1: function proxy, 2: non-function)
+  __ ShiftLeftImm(ip, r3, Operand(kPointerSizeLog2));
+  __ add(r5, sp, ip);
+  __ StoreP(r4, MemOperand(r5, -kPointerSize));
+
+  // 4. Shift arguments and return address one slot down on the stack
+  //    (overwriting the original receiver).  Adjust argument count to make
+  //    the original first argument the new receiver.
+  // r3: actual number of arguments
+  // r4: function
+  // r7: call type (0: JS function, 1: function proxy, 2: non-function)
+  __ bind(&shift_arguments);
+  {
+    Label loop;
+    // Calculate the copy start address (destination). Copy end address is sp.
+    __ ShiftLeftImm(ip, r3, Operand(kPointerSizeLog2));
+    __ add(r5, sp, ip);
+
+    __ bind(&loop);
+    __ LoadP(ip, MemOperand(r5, -kPointerSize));
+    __ StoreP(ip, MemOperand(r5));
+    __ subi(r5, r5, Operand(kPointerSize));
+    __ cmp(r5, sp);
+    __ bne(&loop);
+    // Adjust the actual number of arguments and remove the top element
+    // (which is a copy of the last argument).
+    __ subi(r3, r3, Operand(1));
+    __ pop();
+  }
+
+  // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
+  //     or a function proxy via CALL_FUNCTION_PROXY.
+  // r3: actual number of arguments
+  // r4: function
+  // r7: call type (0: JS function, 1: function proxy, 2: non-function)
+  {
+    Label function, non_proxy;
+    __ cmpi(r7, Operand::Zero());
+    __ beq(&function);
+    // Expected number of arguments is 0 for CALL_NON_FUNCTION.
+    __ li(r5, Operand::Zero());
+    __ cmpi(r7, Operand(1));
+    __ bne(&non_proxy);
+
+    __ push(r4);  // re-add proxy object as additional argument
+    __ addi(r3, r3, Operand(1));
+    __ GetBuiltinFunction(r4, Builtins::CALL_FUNCTION_PROXY);
+    __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+            RelocInfo::CODE_TARGET);
+
+    __ bind(&non_proxy);
+    __ GetBuiltinFunction(r4, Builtins::CALL_NON_FUNCTION);
+    __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+            RelocInfo::CODE_TARGET);
+    __ bind(&function);
+  }
+
+  // 5b. Get the code to call from the function and check that the number of
+  //     expected arguments matches what we're providing.  If so, jump
+  //     (tail-call) to the code in register edx without checking arguments.
+  // r3: actual number of arguments
+  // r4: function
+  __ LoadP(r6, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
+  __ LoadWordArith(
+      r5, FieldMemOperand(r6, SharedFunctionInfo::kFormalParameterCountOffset));
+#if !V8_TARGET_ARCH_PPC64
+  __ SmiUntag(r5);
+#endif
+  __ cmp(r5, r3);  // Check formal and actual parameter counts.
+  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+          RelocInfo::CODE_TARGET, ne);
+
+  __ LoadP(ip, FieldMemOperand(r4, JSFunction::kCodeEntryOffset));
+  ParameterCount expected(0);
+  __ InvokeCode(ip, expected, expected, JUMP_FUNCTION, NullCallWrapper());
+}
+
+
+void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+  const int kIndexOffset =
+      StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
+  const int kLimitOffset =
+      StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
+  const int kArgsOffset = 2 * kPointerSize;
+  const int kRecvOffset = 3 * kPointerSize;
+  const int kFunctionOffset = 4 * kPointerSize;
+
+  {
+    FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL);
+
+    __ LoadP(r3, MemOperand(fp, kFunctionOffset));  // get the function
+    __ push(r3);
+    __ LoadP(r3, MemOperand(fp, kArgsOffset));  // get the args array
+    __ push(r3);
+    __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
+
+    // Check the stack for overflow. We are not trying to catch
+    // interruptions (e.g. debug break and preemption) here, so the "real stack
+    // limit" is checked.
+    Label okay;
+    __ LoadRoot(r5, Heap::kRealStackLimitRootIndex);
+    // Make r5 the space we have left. The stack might already be overflowed
+    // here which will cause r5 to become negative.
+    __ sub(r5, sp, r5);
+    // Check if the arguments will overflow the stack.
+    __ SmiToPtrArrayOffset(r0, r3);
+    __ cmp(r5, r0);
+    __ bgt(&okay);  // Signed comparison.
+
+    // Out of stack space.
+    __ LoadP(r4, MemOperand(fp, kFunctionOffset));
+    __ Push(r4, r3);
+    __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+    // End of stack check.
+
+    // Push current limit and index.
+    __ bind(&okay);
+    __ li(r4, Operand::Zero());
+    __ Push(r3, r4);  // limit and initial index.
+
+    // Get the receiver.
+    __ LoadP(r3, MemOperand(fp, kRecvOffset));
+
+    // Check that the function is a JS function (otherwise it must be a proxy).
+    Label push_receiver;
+    __ LoadP(r4, MemOperand(fp, kFunctionOffset));
+    __ CompareObjectType(r4, r5, r5, JS_FUNCTION_TYPE);
+    __ bne(&push_receiver);
+
+    // Change context eagerly to get the right global object if necessary.
+    __ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
+    // Load the shared function info while the function is still in r4.
+    __ LoadP(r5, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
+
+    // Compute the receiver.
+    // Do not transform the receiver for strict mode functions.
+    Label call_to_object, use_global_proxy;
+    __ lwz(r5, FieldMemOperand(r5, SharedFunctionInfo::kCompilerHintsOffset));
+    __ TestBit(r5,
+#if V8_TARGET_ARCH_PPC64
+               SharedFunctionInfo::kStrictModeFunction,
+#else
+               SharedFunctionInfo::kStrictModeFunction + kSmiTagSize,
+#endif
+               r0);
+    __ bne(&push_receiver, cr0);
+
+    // Do not transform the receiver for strict mode functions.
+    __ TestBit(r5,
+#if V8_TARGET_ARCH_PPC64
+               SharedFunctionInfo::kNative,
+#else
+               SharedFunctionInfo::kNative + kSmiTagSize,
+#endif
+               r0);
+    __ bne(&push_receiver, cr0);
+
+    // Compute the receiver in sloppy mode.
+    __ JumpIfSmi(r3, &call_to_object);
+    __ LoadRoot(r4, Heap::kNullValueRootIndex);
+    __ cmp(r3, r4);
+    __ beq(&use_global_proxy);
+    __ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
+    __ cmp(r3, r4);
+    __ beq(&use_global_proxy);
+
+    // Check if the receiver is already a JavaScript object.
+    // r3: receiver
+    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
+    __ CompareObjectType(r3, r4, r4, FIRST_SPEC_OBJECT_TYPE);
+    __ bge(&push_receiver);
+
+    // Convert the receiver to a regular object.
+    // r3: receiver
+    __ bind(&call_to_object);
+    __ push(r3);
+    __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
+    __ b(&push_receiver);
+
+    __ bind(&use_global_proxy);
+    __ LoadP(r3, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
+    __ LoadP(r3, FieldMemOperand(r3, GlobalObject::kGlobalProxyOffset));
+
+    // Push the receiver.
+    // r3: receiver
+    __ bind(&push_receiver);
+    __ push(r3);
+
+    // Copy all arguments from the array to the stack.
+    Label entry, loop;
+    __ LoadP(r3, MemOperand(fp, kIndexOffset));
+    __ b(&entry);
+
+    // Load the current argument from the arguments array and push it to the
+    // stack.
+    // r3: current argument index
+    __ bind(&loop);
+    __ LoadP(r4, MemOperand(fp, kArgsOffset));
+    __ Push(r4, r3);
+
+    // Call the runtime to access the property in the arguments array.
+    __ CallRuntime(Runtime::kGetProperty, 2);
+    __ push(r3);
+
+    // Use inline caching to access the arguments.
+    __ LoadP(r3, MemOperand(fp, kIndexOffset));
+    __ AddSmiLiteral(r3, r3, Smi::FromInt(1), r0);
+    __ StoreP(r3, MemOperand(fp, kIndexOffset));
+
+    // Test if the copy loop has finished copying all the elements from the
+    // arguments object.
+    __ bind(&entry);
+    __ LoadP(r4, MemOperand(fp, kLimitOffset));
+    __ cmp(r3, r4);
+    __ bne(&loop);
+
+    // Call the function.
+    Label call_proxy;
+    ParameterCount actual(r3);
+    __ SmiUntag(r3);
+    __ LoadP(r4, MemOperand(fp, kFunctionOffset));
+    __ CompareObjectType(r4, r5, r5, JS_FUNCTION_TYPE);
+    __ bne(&call_proxy);
+    __ InvokeFunction(r4, actual, CALL_FUNCTION, NullCallWrapper());
+
+    __ LeaveFrame(StackFrame::INTERNAL, 3 * kPointerSize);
+    __ blr();
+
+    // Call the function proxy.
+    __ bind(&call_proxy);
+    __ push(r4);  // add function proxy as last argument
+    __ addi(r3, r3, Operand(1));
+    __ li(r5, Operand::Zero());
+    __ GetBuiltinFunction(r4, Builtins::CALL_FUNCTION_PROXY);
+    __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+            RelocInfo::CODE_TARGET);
+
+    // Tear down the internal frame and remove function, receiver and args.
+  }
+  __ addi(sp, sp, Operand(3 * kPointerSize));
+  __ blr();
+}
+
+
+static void ArgumentAdaptorStackCheck(MacroAssembler* masm,
+                                      Label* stack_overflow) {
+  // ----------- S t a t e -------------
+  //  -- r3 : actual number of arguments
+  //  -- r4 : function (passed through to callee)
+  //  -- r5 : expected number of arguments
+  // -----------------------------------
+  // Check the stack for overflow. We are not trying to catch
+  // interruptions (e.g. debug break and preemption) here, so the "real stack
+  // limit" is checked.
+  __ LoadRoot(r8, Heap::kRealStackLimitRootIndex);
+  // Make r8 the space we have left. The stack might already be overflowed
+  // here which will cause r8 to become negative.
+  __ sub(r8, sp, r8);
+  // Check if the arguments will overflow the stack.
+  __ ShiftLeftImm(r0, r5, Operand(kPointerSizeLog2));
+  __ cmp(r8, r0);
+  __ ble(stack_overflow);  // Signed comparison.
+}
+
+
+static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
+  __ SmiTag(r3);
+  __ LoadSmiLiteral(r7, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+  __ mflr(r0);
+  __ push(r0);
+#if V8_OOL_CONSTANT_POOL
+  __ Push(fp, kConstantPoolRegister, r7, r4, r3);
+#else
+  __ Push(fp, r7, r4, r3);
+#endif
+  __ addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp +
+                          kPointerSize));
+}
+
+
+static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r3 : result being passed through
+  // -----------------------------------
+  // Get the number of arguments passed (as a smi), tear down the frame and
+  // then tear down the parameters.
+  __ LoadP(r4, MemOperand(fp, -(StandardFrameConstants::kFixedFrameSizeFromFp +
+                                kPointerSize)));
+  int stack_adjustment = kPointerSize;  // adjust for receiver
+  __ LeaveFrame(StackFrame::ARGUMENTS_ADAPTOR, stack_adjustment);
+  __ SmiToPtrArrayOffset(r0, r4);
+  __ add(sp, sp, r0);
+}
+
+
+void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r3 : actual number of arguments
+  //  -- r4 : function (passed through to callee)
+  //  -- r5 : expected number of arguments
+  // -----------------------------------
+
+  Label stack_overflow;
+  ArgumentAdaptorStackCheck(masm, &stack_overflow);
+  Label invoke, dont_adapt_arguments;
+
+  Label enough, too_few;
+  __ LoadP(ip, FieldMemOperand(r4, JSFunction::kCodeEntryOffset));
+  __ cmp(r3, r5);
+  __ blt(&too_few);
+  __ cmpi(r5, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
+  __ beq(&dont_adapt_arguments);
+
+  {  // Enough parameters: actual >= expected
+    __ bind(&enough);
+    EnterArgumentsAdaptorFrame(masm);
+
+    // Calculate copy start address into r3 and copy end address into r5.
+    // r3: actual number of arguments as a smi
+    // r4: function
+    // r5: expected number of arguments
+    // ip: code entry to call
+    __ SmiToPtrArrayOffset(r3, r3);
+    __ add(r3, r3, fp);
+    // adjust for return address and receiver
+    __ addi(r3, r3, Operand(2 * kPointerSize));
+    __ ShiftLeftImm(r5, r5, Operand(kPointerSizeLog2));
+    __ sub(r5, r3, r5);
+
+    // Copy the arguments (including the receiver) to the new stack frame.
+    // r3: copy start address
+    // r4: function
+    // r5: copy end address
+    // ip: code entry to call
+
+    Label copy;
+    __ bind(&copy);
+    __ LoadP(r0, MemOperand(r3, 0));
+    __ push(r0);
+    __ cmp(r3, r5);  // Compare before moving to next argument.
+    __ subi(r3, r3, Operand(kPointerSize));
+    __ bne(&copy);
+
+    __ b(&invoke);
+  }
+
+  {  // Too few parameters: Actual < expected
+    __ bind(&too_few);
+    EnterArgumentsAdaptorFrame(masm);
+
+    // Calculate copy start address into r0 and copy end address is fp.
+    // r3: actual number of arguments as a smi
+    // r4: function
+    // r5: expected number of arguments
+    // ip: code entry to call
+    __ SmiToPtrArrayOffset(r3, r3);
+    __ add(r3, r3, fp);
+
+    // Copy the arguments (including the receiver) to the new stack frame.
+    // r3: copy start address
+    // r4: function
+    // r5: expected number of arguments
+    // ip: code entry to call
+    Label copy;
+    __ bind(&copy);
+    // Adjust load for return address and receiver.
+    __ LoadP(r0, MemOperand(r3, 2 * kPointerSize));
+    __ push(r0);
+    __ cmp(r3, fp);  // Compare before moving to next argument.
+    __ subi(r3, r3, Operand(kPointerSize));
+    __ bne(&copy);
+
+    // Fill the remaining expected arguments with undefined.
+    // r4: function
+    // r5: expected number of arguments
+    // ip: code entry to call
+    __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
+    __ ShiftLeftImm(r5, r5, Operand(kPointerSizeLog2));
+    __ sub(r5, fp, r5);
+    // Adjust for frame.
+    __ subi(r5, r5, Operand(StandardFrameConstants::kFixedFrameSizeFromFp +
+                            2 * kPointerSize));
+
+    Label fill;
+    __ bind(&fill);
+    __ push(r0);
+    __ cmp(sp, r5);
+    __ bne(&fill);
+  }
+
+  // Call the entry point.
+  __ bind(&invoke);
+  __ CallJSEntry(ip);
+
+  // Store offset of return address for deoptimizer.
+  masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
+
+  // Exit frame and return.
+  LeaveArgumentsAdaptorFrame(masm);
+  __ blr();
+
+
+  // -------------------------------------------
+  // Dont adapt arguments.
+  // -------------------------------------------
+  __ bind(&dont_adapt_arguments);
+  __ JumpToJSEntry(ip);
+
+  __ bind(&stack_overflow);
+  {
+    FrameScope frame(masm, StackFrame::MANUAL);
+    EnterArgumentsAdaptorFrame(masm);
+    __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+    __ bkpt(0);
+  }
+}
+
+
+#undef __
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ppc/code-stubs-ppc.cc b/src/ppc/code-stubs-ppc.cc
new file mode 100644
index 0000000..3e84a21
--- /dev/null
+++ b/src/ppc/code-stubs-ppc.cc
@@ -0,0 +1,4893 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/base/bits.h"
+#include "src/bootstrapper.h"
+#include "src/code-stubs.h"
+#include "src/codegen.h"
+#include "src/ic/handler-compiler.h"
+#include "src/ic/ic.h"
+#include "src/isolate.h"
+#include "src/jsregexp.h"
+#include "src/regexp-macro-assembler.h"
+#include "src/runtime/runtime.h"
+
+namespace v8 {
+namespace internal {
+
+
+static void InitializeArrayConstructorDescriptor(
+    Isolate* isolate, CodeStubDescriptor* descriptor,
+    int constant_stack_parameter_count) {
+  Address deopt_handler =
+      Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
+
+  if (constant_stack_parameter_count == 0) {
+    descriptor->Initialize(deopt_handler, constant_stack_parameter_count,
+                           JS_FUNCTION_STUB_MODE);
+  } else {
+    descriptor->Initialize(r3, deopt_handler, constant_stack_parameter_count,
+                           JS_FUNCTION_STUB_MODE, PASS_ARGUMENTS);
+  }
+}
+
+
+static void InitializeInternalArrayConstructorDescriptor(
+    Isolate* isolate, CodeStubDescriptor* descriptor,
+    int constant_stack_parameter_count) {
+  Address deopt_handler =
+      Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
+
+  if (constant_stack_parameter_count == 0) {
+    descriptor->Initialize(deopt_handler, constant_stack_parameter_count,
+                           JS_FUNCTION_STUB_MODE);
+  } else {
+    descriptor->Initialize(r3, deopt_handler, constant_stack_parameter_count,
+                           JS_FUNCTION_STUB_MODE, PASS_ARGUMENTS);
+  }
+}
+
+
+void ArrayNoArgumentConstructorStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  InitializeArrayConstructorDescriptor(isolate(), descriptor, 0);
+}
+
+
+void ArraySingleArgumentConstructorStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  InitializeArrayConstructorDescriptor(isolate(), descriptor, 1);
+}
+
+
+void ArrayNArgumentsConstructorStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  InitializeArrayConstructorDescriptor(isolate(), descriptor, -1);
+}
+
+
+void InternalArrayNoArgumentConstructorStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 0);
+}
+
+
+void InternalArraySingleArgumentConstructorStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 1);
+}
+
+
+void InternalArrayNArgumentsConstructorStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, -1);
+}
+
+
+#define __ ACCESS_MASM(masm)
+
+
+static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
+                                          Condition cond);
+static void EmitSmiNonsmiComparison(MacroAssembler* masm, Register lhs,
+                                    Register rhs, Label* lhs_not_nan,
+                                    Label* slow, bool strict);
+static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, Register lhs,
+                                           Register rhs);
+
+
+void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm,
+                                               ExternalReference miss) {
+  // Update the static counter each time a new code stub is generated.
+  isolate()->counters()->code_stubs()->Increment();
+
+  CallInterfaceDescriptor descriptor = GetCallInterfaceDescriptor();
+  int param_count = descriptor.GetEnvironmentParameterCount();
+  {
+    // Call the runtime system in a fresh internal frame.
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    DCHECK(param_count == 0 ||
+           r3.is(descriptor.GetEnvironmentParameterRegister(param_count - 1)));
+    // Push arguments
+    for (int i = 0; i < param_count; ++i) {
+      __ push(descriptor.GetEnvironmentParameterRegister(i));
+    }
+    __ CallExternalReference(miss, param_count);
+  }
+
+  __ Ret();
+}
+
+
+void DoubleToIStub::Generate(MacroAssembler* masm) {
+  Label out_of_range, only_low, negate, done, fastpath_done;
+  Register input_reg = source();
+  Register result_reg = destination();
+  DCHECK(is_truncating());
+
+  int double_offset = offset();
+
+  // Immediate values for this stub fit in instructions, so it's safe to use ip.
+  Register scratch = GetRegisterThatIsNotOneOf(input_reg, result_reg);
+  Register scratch_low =
+      GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch);
+  Register scratch_high =
+      GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch, scratch_low);
+  DoubleRegister double_scratch = kScratchDoubleReg;
+
+  __ push(scratch);
+  // Account for saved regs if input is sp.
+  if (input_reg.is(sp)) double_offset += kPointerSize;
+
+  if (!skip_fastpath()) {
+    // Load double input.
+    __ lfd(double_scratch, MemOperand(input_reg, double_offset));
+
+    // Do fast-path convert from double to int.
+    __ ConvertDoubleToInt64(double_scratch,
+#if !V8_TARGET_ARCH_PPC64
+                            scratch,
+#endif
+                            result_reg, d0);
+
+// Test for overflow
+#if V8_TARGET_ARCH_PPC64
+    __ TestIfInt32(result_reg, scratch, r0);
+#else
+    __ TestIfInt32(scratch, result_reg, r0);
+#endif
+    __ beq(&fastpath_done);
+  }
+
+  __ Push(scratch_high, scratch_low);
+  // Account for saved regs if input is sp.
+  if (input_reg.is(sp)) double_offset += 2 * kPointerSize;
+
+  __ lwz(scratch_high,
+         MemOperand(input_reg, double_offset + Register::kExponentOffset));
+  __ lwz(scratch_low,
+         MemOperand(input_reg, double_offset + Register::kMantissaOffset));
+
+  __ ExtractBitMask(scratch, scratch_high, HeapNumber::kExponentMask);
+  // Load scratch with exponent - 1. This is faster than loading
+  // with exponent because Bias + 1 = 1024 which is a *PPC* immediate value.
+  STATIC_ASSERT(HeapNumber::kExponentBias + 1 == 1024);
+  __ subi(scratch, scratch, Operand(HeapNumber::kExponentBias + 1));
+  // If exponent is greater than or equal to 84, the 32 less significant
+  // bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits),
+  // the result is 0.
+  // Compare exponent with 84 (compare exponent - 1 with 83).
+  __ cmpi(scratch, Operand(83));
+  __ bge(&out_of_range);
+
+  // If we reach this code, 31 <= exponent <= 83.
+  // So, we don't have to handle cases where 0 <= exponent <= 20 for
+  // which we would need to shift right the high part of the mantissa.
+  // Scratch contains exponent - 1.
+  // Load scratch with 52 - exponent (load with 51 - (exponent - 1)).
+  __ subfic(scratch, scratch, Operand(51));
+  __ cmpi(scratch, Operand::Zero());
+  __ ble(&only_low);
+  // 21 <= exponent <= 51, shift scratch_low and scratch_high
+  // to generate the result.
+  __ srw(scratch_low, scratch_low, scratch);
+  // Scratch contains: 52 - exponent.
+  // We needs: exponent - 20.
+  // So we use: 32 - scratch = 32 - 52 + exponent = exponent - 20.
+  __ subfic(scratch, scratch, Operand(32));
+  __ ExtractBitMask(result_reg, scratch_high, HeapNumber::kMantissaMask);
+  // Set the implicit 1 before the mantissa part in scratch_high.
+  STATIC_ASSERT(HeapNumber::kMantissaBitsInTopWord >= 16);
+  __ oris(result_reg, result_reg,
+          Operand(1 << ((HeapNumber::kMantissaBitsInTopWord) - 16)));
+  __ slw(r0, result_reg, scratch);
+  __ orx(result_reg, scratch_low, r0);
+  __ b(&negate);
+
+  __ bind(&out_of_range);
+  __ mov(result_reg, Operand::Zero());
+  __ b(&done);
+
+  __ bind(&only_low);
+  // 52 <= exponent <= 83, shift only scratch_low.
+  // On entry, scratch contains: 52 - exponent.
+  __ neg(scratch, scratch);
+  __ slw(result_reg, scratch_low, scratch);
+
+  __ bind(&negate);
+  // If input was positive, scratch_high ASR 31 equals 0 and
+  // scratch_high LSR 31 equals zero.
+  // New result = (result eor 0) + 0 = result.
+  // If the input was negative, we have to negate the result.
+  // Input_high ASR 31 equals 0xffffffff and scratch_high LSR 31 equals 1.
+  // New result = (result eor 0xffffffff) + 1 = 0 - result.
+  __ srawi(r0, scratch_high, 31);
+#if V8_TARGET_ARCH_PPC64
+  __ srdi(r0, r0, Operand(32));
+#endif
+  __ xor_(result_reg, result_reg, r0);
+  __ srwi(r0, scratch_high, Operand(31));
+  __ add(result_reg, result_reg, r0);
+
+  __ bind(&done);
+  __ Pop(scratch_high, scratch_low);
+
+  __ bind(&fastpath_done);
+  __ pop(scratch);
+
+  __ Ret();
+}
+
+
+// Handle the case where the lhs and rhs are the same object.
+// Equality is almost reflexive (everything but NaN), so this is a test
+// for "identity and not NaN".
+static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
+                                          Condition cond) {
+  Label not_identical;
+  Label heap_number, return_equal;
+  __ cmp(r3, r4);
+  __ bne(&not_identical);
+
+  // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
+  // so we do the second best thing - test it ourselves.
+  // They are both equal and they are not both Smis so both of them are not
+  // Smis.  If it's not a heap number, then return equal.
+  if (cond == lt || cond == gt) {
+    __ CompareObjectType(r3, r7, r7, FIRST_SPEC_OBJECT_TYPE);
+    __ bge(slow);
+  } else {
+    __ CompareObjectType(r3, r7, r7, HEAP_NUMBER_TYPE);
+    __ beq(&heap_number);
+    // Comparing JS objects with <=, >= is complicated.
+    if (cond != eq) {
+      __ cmpi(r7, Operand(FIRST_SPEC_OBJECT_TYPE));
+      __ bge(slow);
+      // Normally here we fall through to return_equal, but undefined is
+      // special: (undefined == undefined) == true, but
+      // (undefined <= undefined) == false!  See ECMAScript 11.8.5.
+      if (cond == le || cond == ge) {
+        __ cmpi(r7, Operand(ODDBALL_TYPE));
+        __ bne(&return_equal);
+        __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
+        __ cmp(r3, r5);
+        __ bne(&return_equal);
+        if (cond == le) {
+          // undefined <= undefined should fail.
+          __ li(r3, Operand(GREATER));
+        } else {
+          // undefined >= undefined should fail.
+          __ li(r3, Operand(LESS));
+        }
+        __ Ret();
+      }
+    }
+  }
+
+  __ bind(&return_equal);
+  if (cond == lt) {
+    __ li(r3, Operand(GREATER));  // Things aren't less than themselves.
+  } else if (cond == gt) {
+    __ li(r3, Operand(LESS));  // Things aren't greater than themselves.
+  } else {
+    __ li(r3, Operand(EQUAL));  // Things are <=, >=, ==, === themselves.
+  }
+  __ Ret();
+
+  // For less and greater we don't have to check for NaN since the result of
+  // x < x is false regardless.  For the others here is some code to check
+  // for NaN.
+  if (cond != lt && cond != gt) {
+    __ bind(&heap_number);
+    // It is a heap number, so return non-equal if it's NaN and equal if it's
+    // not NaN.
+
+    // The representation of NaN values has all exponent bits (52..62) set,
+    // and not all mantissa bits (0..51) clear.
+    // Read top bits of double representation (second word of value).
+    __ lwz(r5, FieldMemOperand(r3, HeapNumber::kExponentOffset));
+    // Test that exponent bits are all set.
+    STATIC_ASSERT(HeapNumber::kExponentMask == 0x7ff00000u);
+    __ ExtractBitMask(r6, r5, HeapNumber::kExponentMask);
+    __ cmpli(r6, Operand(0x7ff));
+    __ bne(&return_equal);
+
+    // Shift out flag and all exponent bits, retaining only mantissa.
+    __ slwi(r5, r5, Operand(HeapNumber::kNonMantissaBitsInTopWord));
+    // Or with all low-bits of mantissa.
+    __ lwz(r6, FieldMemOperand(r3, HeapNumber::kMantissaOffset));
+    __ orx(r3, r6, r5);
+    __ cmpi(r3, Operand::Zero());
+    // For equal we already have the right value in r3:  Return zero (equal)
+    // if all bits in mantissa are zero (it's an Infinity) and non-zero if
+    // not (it's a NaN).  For <= and >= we need to load r0 with the failing
+    // value if it's a NaN.
+    if (cond != eq) {
+      Label not_equal;
+      __ bne(&not_equal);
+      // All-zero means Infinity means equal.
+      __ Ret();
+      __ bind(&not_equal);
+      if (cond == le) {
+        __ li(r3, Operand(GREATER));  // NaN <= NaN should fail.
+      } else {
+        __ li(r3, Operand(LESS));  // NaN >= NaN should fail.
+      }
+    }
+    __ Ret();
+  }
+  // No fall through here.
+
+  __ bind(&not_identical);
+}
+
+
+// See comment at call site.
+static void EmitSmiNonsmiComparison(MacroAssembler* masm, Register lhs,
+                                    Register rhs, Label* lhs_not_nan,
+                                    Label* slow, bool strict) {
+  DCHECK((lhs.is(r3) && rhs.is(r4)) || (lhs.is(r4) && rhs.is(r3)));
+
+  Label rhs_is_smi;
+  __ JumpIfSmi(rhs, &rhs_is_smi);
+
+  // Lhs is a Smi.  Check whether the rhs is a heap number.
+  __ CompareObjectType(rhs, r6, r7, HEAP_NUMBER_TYPE);
+  if (strict) {
+    // If rhs is not a number and lhs is a Smi then strict equality cannot
+    // succeed.  Return non-equal
+    // If rhs is r3 then there is already a non zero value in it.
+    Label skip;
+    __ beq(&skip);
+    if (!rhs.is(r3)) {
+      __ mov(r3, Operand(NOT_EQUAL));
+    }
+    __ Ret();
+    __ bind(&skip);
+  } else {
+    // Smi compared non-strictly with a non-Smi non-heap-number.  Call
+    // the runtime.
+    __ bne(slow);
+  }
+
+  // Lhs is a smi, rhs is a number.
+  // Convert lhs to a double in d7.
+  __ SmiToDouble(d7, lhs);
+  // Load the double from rhs, tagged HeapNumber r3, to d6.
+  __ lfd(d6, FieldMemOperand(rhs, HeapNumber::kValueOffset));
+
+  // We now have both loaded as doubles but we can skip the lhs nan check
+  // since it's a smi.
+  __ b(lhs_not_nan);
+
+  __ bind(&rhs_is_smi);
+  // Rhs is a smi.  Check whether the non-smi lhs is a heap number.
+  __ CompareObjectType(lhs, r7, r7, HEAP_NUMBER_TYPE);
+  if (strict) {
+    // If lhs is not a number and rhs is a smi then strict equality cannot
+    // succeed.  Return non-equal.
+    // If lhs is r3 then there is already a non zero value in it.
+    Label skip;
+    __ beq(&skip);
+    if (!lhs.is(r3)) {
+      __ mov(r3, Operand(NOT_EQUAL));
+    }
+    __ Ret();
+    __ bind(&skip);
+  } else {
+    // Smi compared non-strictly with a non-smi non-heap-number.  Call
+    // the runtime.
+    __ bne(slow);
+  }
+
+  // Rhs is a smi, lhs is a heap number.
+  // Load the double from lhs, tagged HeapNumber r4, to d7.
+  __ lfd(d7, FieldMemOperand(lhs, HeapNumber::kValueOffset));
+  // Convert rhs to a double in d6.
+  __ SmiToDouble(d6, rhs);
+  // Fall through to both_loaded_as_doubles.
+}
+
+
+// See comment at call site.
+static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, Register lhs,
+                                           Register rhs) {
+  DCHECK((lhs.is(r3) && rhs.is(r4)) || (lhs.is(r4) && rhs.is(r3)));
+
+  // If either operand is a JS object or an oddball value, then they are
+  // not equal since their pointers are different.
+  // There is no test for undetectability in strict equality.
+  STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
+  Label first_non_object;
+  // Get the type of the first operand into r5 and compare it with
+  // FIRST_SPEC_OBJECT_TYPE.
+  __ CompareObjectType(rhs, r5, r5, FIRST_SPEC_OBJECT_TYPE);
+  __ blt(&first_non_object);
+
+  // Return non-zero (r3 is not zero)
+  Label return_not_equal;
+  __ bind(&return_not_equal);
+  __ Ret();
+
+  __ bind(&first_non_object);
+  // Check for oddballs: true, false, null, undefined.
+  __ cmpi(r5, Operand(ODDBALL_TYPE));
+  __ beq(&return_not_equal);
+
+  __ CompareObjectType(lhs, r6, r6, FIRST_SPEC_OBJECT_TYPE);
+  __ bge(&return_not_equal);
+
+  // Check for oddballs: true, false, null, undefined.
+  __ cmpi(r6, Operand(ODDBALL_TYPE));
+  __ beq(&return_not_equal);
+
+  // Now that we have the types we might as well check for
+  // internalized-internalized.
+  STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
+  __ orx(r5, r5, r6);
+  __ andi(r0, r5, Operand(kIsNotStringMask | kIsNotInternalizedMask));
+  __ beq(&return_not_equal, cr0);
+}
+
+
+// See comment at call site.
+static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, Register lhs,
+                                       Register rhs,
+                                       Label* both_loaded_as_doubles,
+                                       Label* not_heap_numbers, Label* slow) {
+  DCHECK((lhs.is(r3) && rhs.is(r4)) || (lhs.is(r4) && rhs.is(r3)));
+
+  __ CompareObjectType(rhs, r6, r5, HEAP_NUMBER_TYPE);
+  __ bne(not_heap_numbers);
+  __ LoadP(r5, FieldMemOperand(lhs, HeapObject::kMapOffset));
+  __ cmp(r5, r6);
+  __ bne(slow);  // First was a heap number, second wasn't.  Go slow case.
+
+  // Both are heap numbers.  Load them up then jump to the code we have
+  // for that.
+  __ lfd(d6, FieldMemOperand(rhs, HeapNumber::kValueOffset));
+  __ lfd(d7, FieldMemOperand(lhs, HeapNumber::kValueOffset));
+
+  __ b(both_loaded_as_doubles);
+}
+
+
+// Fast negative check for internalized-to-internalized equality.
+static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm,
+                                                     Register lhs, Register rhs,
+                                                     Label* possible_strings,
+                                                     Label* not_both_strings) {
+  DCHECK((lhs.is(r3) && rhs.is(r4)) || (lhs.is(r4) && rhs.is(r3)));
+
+  // r5 is object type of rhs.
+  Label object_test;
+  STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
+  __ andi(r0, r5, Operand(kIsNotStringMask));
+  __ bne(&object_test, cr0);
+  __ andi(r0, r5, Operand(kIsNotInternalizedMask));
+  __ bne(possible_strings, cr0);
+  __ CompareObjectType(lhs, r6, r6, FIRST_NONSTRING_TYPE);
+  __ bge(not_both_strings);
+  __ andi(r0, r6, Operand(kIsNotInternalizedMask));
+  __ bne(possible_strings, cr0);
+
+  // Both are internalized.  We already checked they weren't the same pointer
+  // so they are not equal.
+  __ li(r3, Operand(NOT_EQUAL));
+  __ Ret();
+
+  __ bind(&object_test);
+  __ cmpi(r5, Operand(FIRST_SPEC_OBJECT_TYPE));
+  __ blt(not_both_strings);
+  __ CompareObjectType(lhs, r5, r6, FIRST_SPEC_OBJECT_TYPE);
+  __ blt(not_both_strings);
+  // If both objects are undetectable, they are equal. Otherwise, they
+  // are not equal, since they are different objects and an object is not
+  // equal to undefined.
+  __ LoadP(r6, FieldMemOperand(rhs, HeapObject::kMapOffset));
+  __ lbz(r5, FieldMemOperand(r5, Map::kBitFieldOffset));
+  __ lbz(r6, FieldMemOperand(r6, Map::kBitFieldOffset));
+  __ and_(r3, r5, r6);
+  __ andi(r3, r3, Operand(1 << Map::kIsUndetectable));
+  __ xori(r3, r3, Operand(1 << Map::kIsUndetectable));
+  __ Ret();
+}
+
+
+static void CompareICStub_CheckInputType(MacroAssembler* masm, Register input,
+                                         Register scratch,
+                                         CompareICState::State expected,
+                                         Label* fail) {
+  Label ok;
+  if (expected == CompareICState::SMI) {
+    __ JumpIfNotSmi(input, fail);
+  } else if (expected == CompareICState::NUMBER) {
+    __ JumpIfSmi(input, &ok);
+    __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail,
+                DONT_DO_SMI_CHECK);
+  }
+  // We could be strict about internalized/non-internalized here, but as long as
+  // hydrogen doesn't care, the stub doesn't have to care either.
+  __ bind(&ok);
+}
+
+
+// On entry r4 and r5 are the values to be compared.
+// On exit r3 is 0, positive or negative to indicate the result of
+// the comparison.
+void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
+  Register lhs = r4;
+  Register rhs = r3;
+  Condition cc = GetCondition();
+
+  Label miss;
+  CompareICStub_CheckInputType(masm, lhs, r5, left(), &miss);
+  CompareICStub_CheckInputType(masm, rhs, r6, right(), &miss);
+
+  Label slow;  // Call builtin.
+  Label not_smis, both_loaded_as_doubles, lhs_not_nan;
+
+  Label not_two_smis, smi_done;
+  __ orx(r5, r4, r3);
+  __ JumpIfNotSmi(r5, &not_two_smis);
+  __ SmiUntag(r4);
+  __ SmiUntag(r3);
+  __ sub(r3, r4, r3);
+  __ Ret();
+  __ bind(&not_two_smis);
+
+  // NOTICE! This code is only reached after a smi-fast-case check, so
+  // it is certain that at least one operand isn't a smi.
+
+  // Handle the case where the objects are identical.  Either returns the answer
+  // or goes to slow.  Only falls through if the objects were not identical.
+  EmitIdenticalObjectComparison(masm, &slow, cc);
+
+  // If either is a Smi (we know that not both are), then they can only
+  // be strictly equal if the other is a HeapNumber.
+  STATIC_ASSERT(kSmiTag == 0);
+  DCHECK_EQ(0, Smi::FromInt(0));
+  __ and_(r5, lhs, rhs);
+  __ JumpIfNotSmi(r5, &not_smis);
+  // One operand is a smi.  EmitSmiNonsmiComparison generates code that can:
+  // 1) Return the answer.
+  // 2) Go to slow.
+  // 3) Fall through to both_loaded_as_doubles.
+  // 4) Jump to lhs_not_nan.
+  // In cases 3 and 4 we have found out we were dealing with a number-number
+  // comparison.  The double values of the numbers have been loaded
+  // into d7 and d6.
+  EmitSmiNonsmiComparison(masm, lhs, rhs, &lhs_not_nan, &slow, strict());
+
+  __ bind(&both_loaded_as_doubles);
+  // The arguments have been converted to doubles and stored in d6 and d7
+  __ bind(&lhs_not_nan);
+  Label no_nan;
+  __ fcmpu(d7, d6);
+
+  Label nan, equal, less_than;
+  __ bunordered(&nan);
+  __ beq(&equal);
+  __ blt(&less_than);
+  __ li(r3, Operand(GREATER));
+  __ Ret();
+  __ bind(&equal);
+  __ li(r3, Operand(EQUAL));
+  __ Ret();
+  __ bind(&less_than);
+  __ li(r3, Operand(LESS));
+  __ Ret();
+
+  __ bind(&nan);
+  // If one of the sides was a NaN then the v flag is set.  Load r3 with
+  // whatever it takes to make the comparison fail, since comparisons with NaN
+  // always fail.
+  if (cc == lt || cc == le) {
+    __ li(r3, Operand(GREATER));
+  } else {
+    __ li(r3, Operand(LESS));
+  }
+  __ Ret();
+
+  __ bind(&not_smis);
+  // At this point we know we are dealing with two different objects,
+  // and neither of them is a Smi.  The objects are in rhs_ and lhs_.
+  if (strict()) {
+    // This returns non-equal for some object types, or falls through if it
+    // was not lucky.
+    EmitStrictTwoHeapObjectCompare(masm, lhs, rhs);
+  }
+
+  Label check_for_internalized_strings;
+  Label flat_string_check;
+  // Check for heap-number-heap-number comparison.  Can jump to slow case,
+  // or load both doubles into r3, r4, r5, r6 and jump to the code that handles
+  // that case.  If the inputs are not doubles then jumps to
+  // check_for_internalized_strings.
+  // In this case r5 will contain the type of rhs_.  Never falls through.
+  EmitCheckForTwoHeapNumbers(masm, lhs, rhs, &both_loaded_as_doubles,
+                             &check_for_internalized_strings,
+                             &flat_string_check);
+
+  __ bind(&check_for_internalized_strings);
+  // In the strict case the EmitStrictTwoHeapObjectCompare already took care of
+  // internalized strings.
+  if (cc == eq && !strict()) {
+    // Returns an answer for two internalized strings or two detectable objects.
+    // Otherwise jumps to string case or not both strings case.
+    // Assumes that r5 is the type of rhs_ on entry.
+    EmitCheckForInternalizedStringsOrObjects(masm, lhs, rhs, &flat_string_check,
+                                             &slow);
+  }
+
+  // Check for both being sequential one-byte strings,
+  // and inline if that is the case.
+  __ bind(&flat_string_check);
+
+  __ JumpIfNonSmisNotBothSequentialOneByteStrings(lhs, rhs, r5, r6, &slow);
+
+  __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, r5,
+                      r6);
+  if (cc == eq) {
+    StringHelper::GenerateFlatOneByteStringEquals(masm, lhs, rhs, r5, r6);
+  } else {
+    StringHelper::GenerateCompareFlatOneByteStrings(masm, lhs, rhs, r5, r6, r7);
+  }
+  // Never falls through to here.
+
+  __ bind(&slow);
+
+  __ Push(lhs, rhs);
+  // Figure out which native to call and setup the arguments.
+  Builtins::JavaScript native;
+  if (cc == eq) {
+    native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+  } else {
+    native = Builtins::COMPARE;
+    int ncr;  // NaN compare result
+    if (cc == lt || cc == le) {
+      ncr = GREATER;
+    } else {
+      DCHECK(cc == gt || cc == ge);  // remaining cases
+      ncr = LESS;
+    }
+    __ LoadSmiLiteral(r3, Smi::FromInt(ncr));
+    __ push(r3);
+  }
+
+  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
+  // tagged as a small integer.
+  __ InvokeBuiltin(native, JUMP_FUNCTION);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
+  // We don't allow a GC during a store buffer overflow so there is no need to
+  // store the registers in any particular way, but we do have to store and
+  // restore them.
+  __ mflr(r0);
+  __ MultiPush(kJSCallerSaved | r0.bit());
+  if (save_doubles()) {
+    __ SaveFPRegs(sp, 0, DoubleRegister::kNumVolatileRegisters);
+  }
+  const int argument_count = 1;
+  const int fp_argument_count = 0;
+  const Register scratch = r4;
+
+  AllowExternalCallThatCantCauseGC scope(masm);
+  __ PrepareCallCFunction(argument_count, fp_argument_count, scratch);
+  __ mov(r3, Operand(ExternalReference::isolate_address(isolate())));
+  __ CallCFunction(ExternalReference::store_buffer_overflow_function(isolate()),
+                   argument_count);
+  if (save_doubles()) {
+    __ RestoreFPRegs(sp, 0, DoubleRegister::kNumVolatileRegisters);
+  }
+  __ MultiPop(kJSCallerSaved | r0.bit());
+  __ mtlr(r0);
+  __ Ret();
+}
+
+
+void StoreRegistersStateStub::Generate(MacroAssembler* masm) {
+  __ PushSafepointRegisters();
+  __ blr();
+}
+
+
+void RestoreRegistersStateStub::Generate(MacroAssembler* masm) {
+  __ PopSafepointRegisters();
+  __ blr();
+}
+
+
+void MathPowStub::Generate(MacroAssembler* masm) {
+  const Register base = r4;
+  const Register exponent = MathPowTaggedDescriptor::exponent();
+  DCHECK(exponent.is(r5));
+  const Register heapnumbermap = r8;
+  const Register heapnumber = r3;
+  const DoubleRegister double_base = d1;
+  const DoubleRegister double_exponent = d2;
+  const DoubleRegister double_result = d3;
+  const DoubleRegister double_scratch = d0;
+  const Register scratch = r11;
+  const Register scratch2 = r10;
+
+  Label call_runtime, done, int_exponent;
+  if (exponent_type() == ON_STACK) {
+    Label base_is_smi, unpack_exponent;
+    // The exponent and base are supplied as arguments on the stack.
+    // This can only happen if the stub is called from non-optimized code.
+    // Load input parameters from stack to double registers.
+    __ LoadP(base, MemOperand(sp, 1 * kPointerSize));
+    __ LoadP(exponent, MemOperand(sp, 0 * kPointerSize));
+
+    __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex);
+
+    __ UntagAndJumpIfSmi(scratch, base, &base_is_smi);
+    __ LoadP(scratch, FieldMemOperand(base, JSObject::kMapOffset));
+    __ cmp(scratch, heapnumbermap);
+    __ bne(&call_runtime);
+
+    __ lfd(double_base, FieldMemOperand(base, HeapNumber::kValueOffset));
+    __ b(&unpack_exponent);
+
+    __ bind(&base_is_smi);
+    __ ConvertIntToDouble(scratch, double_base);
+    __ bind(&unpack_exponent);
+
+    __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent);
+    __ LoadP(scratch, FieldMemOperand(exponent, JSObject::kMapOffset));
+    __ cmp(scratch, heapnumbermap);
+    __ bne(&call_runtime);
+
+    __ lfd(double_exponent,
+           FieldMemOperand(exponent, HeapNumber::kValueOffset));
+  } else if (exponent_type() == TAGGED) {
+    // Base is already in double_base.
+    __ UntagAndJumpIfSmi(scratch, exponent, &int_exponent);
+
+    __ lfd(double_exponent,
+           FieldMemOperand(exponent, HeapNumber::kValueOffset));
+  }
+
+  if (exponent_type() != INTEGER) {
+    // Detect integer exponents stored as double.
+    __ TryDoubleToInt32Exact(scratch, double_exponent, scratch2,
+                             double_scratch);
+    __ beq(&int_exponent);
+
+    if (exponent_type() == ON_STACK) {
+      // Detect square root case.  Crankshaft detects constant +/-0.5 at
+      // compile time and uses DoMathPowHalf instead.  We then skip this check
+      // for non-constant cases of +/-0.5 as these hardly occur.
+      Label not_plus_half, not_minus_inf1, not_minus_inf2;
+
+      // Test for 0.5.
+      __ LoadDoubleLiteral(double_scratch, 0.5, scratch);
+      __ fcmpu(double_exponent, double_scratch);
+      __ bne(&not_plus_half);
+
+      // Calculates square root of base.  Check for the special case of
+      // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
+      __ LoadDoubleLiteral(double_scratch, -V8_INFINITY, scratch);
+      __ fcmpu(double_base, double_scratch);
+      __ bne(&not_minus_inf1);
+      __ fneg(double_result, double_scratch);
+      __ b(&done);
+      __ bind(&not_minus_inf1);
+
+      // Add +0 to convert -0 to +0.
+      __ fadd(double_scratch, double_base, kDoubleRegZero);
+      __ fsqrt(double_result, double_scratch);
+      __ b(&done);
+
+      __ bind(&not_plus_half);
+      __ LoadDoubleLiteral(double_scratch, -0.5, scratch);
+      __ fcmpu(double_exponent, double_scratch);
+      __ bne(&call_runtime);
+
+      // Calculates square root of base.  Check for the special case of
+      // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
+      __ LoadDoubleLiteral(double_scratch, -V8_INFINITY, scratch);
+      __ fcmpu(double_base, double_scratch);
+      __ bne(&not_minus_inf2);
+      __ fmr(double_result, kDoubleRegZero);
+      __ b(&done);
+      __ bind(&not_minus_inf2);
+
+      // Add +0 to convert -0 to +0.
+      __ fadd(double_scratch, double_base, kDoubleRegZero);
+      __ LoadDoubleLiteral(double_result, 1.0, scratch);
+      __ fsqrt(double_scratch, double_scratch);
+      __ fdiv(double_result, double_result, double_scratch);
+      __ b(&done);
+    }
+
+    __ mflr(r0);
+    __ push(r0);
+    {
+      AllowExternalCallThatCantCauseGC scope(masm);
+      __ PrepareCallCFunction(0, 2, scratch);
+      __ MovToFloatParameters(double_base, double_exponent);
+      __ CallCFunction(
+          ExternalReference::power_double_double_function(isolate()), 0, 2);
+    }
+    __ pop(r0);
+    __ mtlr(r0);
+    __ MovFromFloatResult(double_result);
+    __ b(&done);
+  }
+
+  // Calculate power with integer exponent.
+  __ bind(&int_exponent);
+
+  // Get two copies of exponent in the registers scratch and exponent.
+  if (exponent_type() == INTEGER) {
+    __ mr(scratch, exponent);
+  } else {
+    // Exponent has previously been stored into scratch as untagged integer.
+    __ mr(exponent, scratch);
+  }
+  __ fmr(double_scratch, double_base);  // Back up base.
+  __ li(scratch2, Operand(1));
+  __ ConvertIntToDouble(scratch2, double_result);
+
+  // Get absolute value of exponent.
+  Label positive_exponent;
+  __ cmpi(scratch, Operand::Zero());
+  __ bge(&positive_exponent);
+  __ neg(scratch, scratch);
+  __ bind(&positive_exponent);
+
+  Label while_true, no_carry, loop_end;
+  __ bind(&while_true);
+  __ andi(scratch2, scratch, Operand(1));
+  __ beq(&no_carry, cr0);
+  __ fmul(double_result, double_result, double_scratch);
+  __ bind(&no_carry);
+  __ ShiftRightArithImm(scratch, scratch, 1, SetRC);
+  __ beq(&loop_end, cr0);
+  __ fmul(double_scratch, double_scratch, double_scratch);
+  __ b(&while_true);
+  __ bind(&loop_end);
+
+  __ cmpi(exponent, Operand::Zero());
+  __ bge(&done);
+
+  __ li(scratch2, Operand(1));
+  __ ConvertIntToDouble(scratch2, double_scratch);
+  __ fdiv(double_result, double_scratch, double_result);
+  // Test whether result is zero.  Bail out to check for subnormal result.
+  // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
+  __ fcmpu(double_result, kDoubleRegZero);
+  __ bne(&done);
+  // double_exponent may not containe the exponent value if the input was a
+  // smi.  We set it with exponent value before bailing out.
+  __ ConvertIntToDouble(exponent, double_exponent);
+
+  // Returning or bailing out.
+  Counters* counters = isolate()->counters();
+  if (exponent_type() == ON_STACK) {
+    // The arguments are still on the stack.
+    __ bind(&call_runtime);
+    __ TailCallRuntime(Runtime::kMathPowRT, 2, 1);
+
+    // The stub is called from non-optimized code, which expects the result
+    // as heap number in exponent.
+    __ bind(&done);
+    __ AllocateHeapNumber(heapnumber, scratch, scratch2, heapnumbermap,
+                          &call_runtime);
+    __ stfd(double_result,
+            FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
+    DCHECK(heapnumber.is(r3));
+    __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
+    __ Ret(2);
+  } else {
+    __ mflr(r0);
+    __ push(r0);
+    {
+      AllowExternalCallThatCantCauseGC scope(masm);
+      __ PrepareCallCFunction(0, 2, scratch);
+      __ MovToFloatParameters(double_base, double_exponent);
+      __ CallCFunction(
+          ExternalReference::power_double_double_function(isolate()), 0, 2);
+    }
+    __ pop(r0);
+    __ mtlr(r0);
+    __ MovFromFloatResult(double_result);
+
+    __ bind(&done);
+    __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
+    __ Ret();
+  }
+}
+
+
+bool CEntryStub::NeedsImmovableCode() { return true; }
+
+
+void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
+  CEntryStub::GenerateAheadOfTime(isolate);
+  //  WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
+  StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
+  StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
+  ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
+  CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
+  BinaryOpICStub::GenerateAheadOfTime(isolate);
+  StoreRegistersStateStub::GenerateAheadOfTime(isolate);
+  RestoreRegistersStateStub::GenerateAheadOfTime(isolate);
+  BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
+}
+
+
+void StoreRegistersStateStub::GenerateAheadOfTime(Isolate* isolate) {
+  StoreRegistersStateStub stub(isolate);
+  stub.GetCode();
+}
+
+
+void RestoreRegistersStateStub::GenerateAheadOfTime(Isolate* isolate) {
+  RestoreRegistersStateStub stub(isolate);
+  stub.GetCode();
+}
+
+
+void CodeStub::GenerateFPStubs(Isolate* isolate) {
+  // Generate if not already in cache.
+  SaveFPRegsMode mode = kSaveFPRegs;
+  CEntryStub(isolate, 1, mode).GetCode();
+  StoreBufferOverflowStub(isolate, mode).GetCode();
+  isolate->set_fp_stubs_generated(true);
+}
+
+
+void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
+  CEntryStub stub(isolate, 1, kDontSaveFPRegs);
+  stub.GetCode();
+}
+
+
+void CEntryStub::Generate(MacroAssembler* masm) {
+  // Called from JavaScript; parameters are on stack as if calling JS function.
+  // r3: number of arguments including receiver
+  // r4: pointer to builtin function
+  // fp: frame pointer  (restored after C call)
+  // sp: stack pointer  (restored as callee's sp after C call)
+  // cp: current context  (C callee-saved)
+
+  ProfileEntryHookStub::MaybeCallEntryHook(masm);
+
+  __ mr(r15, r4);
+
+  // Compute the argv pointer.
+  __ ShiftLeftImm(r4, r3, Operand(kPointerSizeLog2));
+  __ add(r4, r4, sp);
+  __ subi(r4, r4, Operand(kPointerSize));
+
+  // Enter the exit frame that transitions from JavaScript to C++.
+  FrameScope scope(masm, StackFrame::MANUAL);
+
+  // Need at least one extra slot for return address location.
+  int arg_stack_space = 1;
+
+// PPC LINUX ABI:
+#if V8_TARGET_ARCH_PPC64 && !ABI_RETURNS_OBJECT_PAIRS_IN_REGS
+  // Pass buffer for return value on stack if necessary
+  if (result_size() > 1) {
+    DCHECK_EQ(2, result_size());
+    arg_stack_space += 2;
+  }
+#endif
+
+  __ EnterExitFrame(save_doubles(), arg_stack_space);
+
+  // Store a copy of argc in callee-saved registers for later.
+  __ mr(r14, r3);
+
+  // r3, r14: number of arguments including receiver  (C callee-saved)
+  // r4: pointer to the first argument
+  // r15: pointer to builtin function  (C callee-saved)
+
+  // Result returned in registers or stack, depending on result size and ABI.
+
+  Register isolate_reg = r5;
+#if V8_TARGET_ARCH_PPC64 && !ABI_RETURNS_OBJECT_PAIRS_IN_REGS
+  if (result_size() > 1) {
+    // The return value is 16-byte non-scalar value.
+    // Use frame storage reserved by calling function to pass return
+    // buffer as implicit first argument.
+    __ mr(r5, r4);
+    __ mr(r4, r3);
+    __ addi(r3, sp, Operand((kStackFrameExtraParamSlot + 1) * kPointerSize));
+    isolate_reg = r6;
+  }
+#endif
+
+  // Call C built-in.
+  __ mov(isolate_reg, Operand(ExternalReference::isolate_address(isolate())));
+
+#if ABI_USES_FUNCTION_DESCRIPTORS && !defined(USE_SIMULATOR)
+  // Native AIX/PPC64 Linux use a function descriptor.
+  __ LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(r15, kPointerSize));
+  __ LoadP(ip, MemOperand(r15, 0));  // Instruction address
+  Register target = ip;
+#elif ABI_TOC_ADDRESSABILITY_VIA_IP
+  __ Move(ip, r15);
+  Register target = ip;
+#else
+  Register target = r15;
+#endif
+
+  // To let the GC traverse the return address of the exit frames, we need to
+  // know where the return address is. The CEntryStub is unmovable, so
+  // we can store the address on the stack to be able to find it again and
+  // we never have to restore it, because it will not change.
+  // Compute the return address in lr to return to after the jump below. Pc is
+  // already at '+ 8' from the current instruction but return is after three
+  // instructions so add another 4 to pc to get the return address.
+  {
+    Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
+    Label here;
+    __ b(&here, SetLK);
+    __ bind(&here);
+    __ mflr(r8);
+
+    // Constant used below is dependent on size of Call() macro instructions
+    __ addi(r0, r8, Operand(20));
+
+    __ StoreP(r0, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize));
+    __ Call(target);
+  }
+
+#if V8_TARGET_ARCH_PPC64 && !ABI_RETURNS_OBJECT_PAIRS_IN_REGS
+  // If return value is on the stack, pop it to registers.
+  if (result_size() > 1) {
+    __ LoadP(r4, MemOperand(r3, kPointerSize));
+    __ LoadP(r3, MemOperand(r3));
+  }
+#endif
+
+  // Runtime functions should not return 'the hole'.  Allowing it to escape may
+  // lead to crashes in the IC code later.
+  if (FLAG_debug_code) {
+    Label okay;
+    __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
+    __ bne(&okay);
+    __ stop("The hole escaped");
+    __ bind(&okay);
+  }
+
+  // Check result for exception sentinel.
+  Label exception_returned;
+  __ CompareRoot(r3, Heap::kExceptionRootIndex);
+  __ beq(&exception_returned);
+
+  ExternalReference pending_exception_address(Isolate::kPendingExceptionAddress,
+                                              isolate());
+
+  // Check that there is no pending exception, otherwise we
+  // should have returned the exception sentinel.
+  if (FLAG_debug_code) {
+    Label okay;
+    __ mov(r5, Operand(pending_exception_address));
+    __ LoadP(r5, MemOperand(r5));
+    __ CompareRoot(r5, Heap::kTheHoleValueRootIndex);
+    // Cannot use check here as it attempts to generate call into runtime.
+    __ beq(&okay);
+    __ stop("Unexpected pending exception");
+    __ bind(&okay);
+  }
+
+  // Exit C frame and return.
+  // r3:r4: result
+  // sp: stack pointer
+  // fp: frame pointer
+  // r14: still holds argc (callee-saved).
+  __ LeaveExitFrame(save_doubles(), r14, true);
+  __ blr();
+
+  // Handling of exception.
+  __ bind(&exception_returned);
+
+  // Retrieve the pending exception.
+  __ mov(r5, Operand(pending_exception_address));
+  __ LoadP(r3, MemOperand(r5));
+
+  // Clear the pending exception.
+  __ LoadRoot(r6, Heap::kTheHoleValueRootIndex);
+  __ StoreP(r6, MemOperand(r5));
+
+  // Special handling of termination exceptions which are uncatchable
+  // by javascript code.
+  Label throw_termination_exception;
+  __ CompareRoot(r3, Heap::kTerminationExceptionRootIndex);
+  __ beq(&throw_termination_exception);
+
+  // Handle normal exception.
+  __ Throw(r3);
+
+  __ bind(&throw_termination_exception);
+  __ ThrowUncatchable(r3);
+}
+
+
+void JSEntryStub::Generate(MacroAssembler* masm) {
+  // r3: code entry
+  // r4: function
+  // r5: receiver
+  // r6: argc
+  // [sp+0]: argv
+
+  Label invoke, handler_entry, exit;
+
+// Called from C
+#if ABI_USES_FUNCTION_DESCRIPTORS
+  __ function_descriptor();
+#endif
+
+  ProfileEntryHookStub::MaybeCallEntryHook(masm);
+
+  // PPC LINUX ABI:
+  // preserve LR in pre-reserved slot in caller's frame
+  __ mflr(r0);
+  __ StoreP(r0, MemOperand(sp, kStackFrameLRSlot * kPointerSize));
+
+  // Save callee saved registers on the stack.
+  __ MultiPush(kCalleeSaved);
+
+  // Floating point regs FPR0 - FRP13 are volatile
+  // FPR14-FPR31 are non-volatile, but sub-calls will save them for us
+
+  //  int offset_to_argv = kPointerSize * 22; // matches (22*4) above
+  //  __ lwz(r7, MemOperand(sp, offset_to_argv));
+
+  // Push a frame with special values setup to mark it as an entry frame.
+  // r3: code entry
+  // r4: function
+  // r5: receiver
+  // r6: argc
+  // r7: argv
+  __ li(r0, Operand(-1));  // Push a bad frame pointer to fail if it is used.
+  __ push(r0);
+#if V8_OOL_CONSTANT_POOL
+  __ mov(kConstantPoolRegister,
+         Operand(isolate()->factory()->empty_constant_pool_array()));
+  __ push(kConstantPoolRegister);
+#endif
+  int marker = type();
+  __ LoadSmiLiteral(r0, Smi::FromInt(marker));
+  __ push(r0);
+  __ push(r0);
+  // Save copies of the top frame descriptor on the stack.
+  __ mov(r8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
+  __ LoadP(r0, MemOperand(r8));
+  __ push(r0);
+
+  // Set up frame pointer for the frame to be pushed.
+  __ addi(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
+
+  // If this is the outermost JS call, set js_entry_sp value.
+  Label non_outermost_js;
+  ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate());
+  __ mov(r8, Operand(ExternalReference(js_entry_sp)));
+  __ LoadP(r9, MemOperand(r8));
+  __ cmpi(r9, Operand::Zero());
+  __ bne(&non_outermost_js);
+  __ StoreP(fp, MemOperand(r8));
+  __ LoadSmiLiteral(ip, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME));
+  Label cont;
+  __ b(&cont);
+  __ bind(&non_outermost_js);
+  __ LoadSmiLiteral(ip, Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME));
+  __ bind(&cont);
+  __ push(ip);  // frame-type
+
+  // Jump to a faked try block that does the invoke, with a faked catch
+  // block that sets the pending exception.
+  __ b(&invoke);
+
+  __ bind(&handler_entry);
+  handler_offset_ = handler_entry.pos();
+  // Caught exception: Store result (exception) in the pending exception
+  // field in the JSEnv and return a failure sentinel.  Coming in here the
+  // fp will be invalid because the PushTryHandler below sets it to 0 to
+  // signal the existence of the JSEntry frame.
+  __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
+                                       isolate())));
+
+  __ StoreP(r3, MemOperand(ip));
+  __ LoadRoot(r3, Heap::kExceptionRootIndex);
+  __ b(&exit);
+
+  // Invoke: Link this frame into the handler chain.  There's only one
+  // handler block in this code object, so its index is 0.
+  __ bind(&invoke);
+  // Must preserve r0-r4, r5-r7 are available. (needs update for PPC)
+  __ PushTryHandler(StackHandler::JS_ENTRY, 0);
+  // If an exception not caught by another handler occurs, this handler
+  // returns control to the code after the b(&invoke) above, which
+  // restores all kCalleeSaved registers (including cp and fp) to their
+  // saved values before returning a failure to C.
+
+  // Clear any pending exceptions.
+  __ mov(r8, Operand(isolate()->factory()->the_hole_value()));
+  __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
+                                       isolate())));
+  __ StoreP(r8, MemOperand(ip));
+
+  // Invoke the function by calling through JS entry trampoline builtin.
+  // Notice that we cannot store a reference to the trampoline code directly in
+  // this stub, because runtime stubs are not traversed when doing GC.
+
+  // Expected registers by Builtins::JSEntryTrampoline
+  // r3: code entry
+  // r4: function
+  // r5: receiver
+  // r6: argc
+  // r7: argv
+  if (type() == StackFrame::ENTRY_CONSTRUCT) {
+    ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
+                                      isolate());
+    __ mov(ip, Operand(construct_entry));
+  } else {
+    ExternalReference entry(Builtins::kJSEntryTrampoline, isolate());
+    __ mov(ip, Operand(entry));
+  }
+  __ LoadP(ip, MemOperand(ip));  // deref address
+
+  // Branch and link to JSEntryTrampoline.
+  // the address points to the start of the code object, skip the header
+  __ addi(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ mtctr(ip);
+  __ bctrl();  // make the call
+
+  // Unlink this frame from the handler chain.
+  __ PopTryHandler();
+
+  __ bind(&exit);  // r3 holds result
+  // Check if the current stack frame is marked as the outermost JS frame.
+  Label non_outermost_js_2;
+  __ pop(r8);
+  __ CmpSmiLiteral(r8, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME), r0);
+  __ bne(&non_outermost_js_2);
+  __ mov(r9, Operand::Zero());
+  __ mov(r8, Operand(ExternalReference(js_entry_sp)));
+  __ StoreP(r9, MemOperand(r8));
+  __ bind(&non_outermost_js_2);
+
+  // Restore the top frame descriptors from the stack.
+  __ pop(r6);
+  __ mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
+  __ StoreP(r6, MemOperand(ip));
+
+  // Reset the stack to the callee saved registers.
+  __ addi(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
+
+// Restore callee-saved registers and return.
+#ifdef DEBUG
+  if (FLAG_debug_code) {
+    Label here;
+    __ b(&here, SetLK);
+    __ bind(&here);
+  }
+#endif
+
+  __ MultiPop(kCalleeSaved);
+
+  __ LoadP(r0, MemOperand(sp, kStackFrameLRSlot * kPointerSize));
+  __ mtctr(r0);
+  __ bctr();
+}
+
+
+// Uses registers r3 to r7.
+// Expected input (depending on whether args are in registers or on the stack):
+// * object: r3 or at sp + 1 * kPointerSize.
+// * function: r4 or at sp.
+//
+// An inlined call site may have been generated before calling this stub.
+// In this case the offset to the inline site to patch is passed in r8.
+// (See LCodeGen::DoInstanceOfKnownGlobal)
+void InstanceofStub::Generate(MacroAssembler* masm) {
+  // Call site inlining and patching implies arguments in registers.
+  DCHECK(HasArgsInRegisters() || !HasCallSiteInlineCheck());
+
+  // Fixed register usage throughout the stub:
+  const Register object = r3;     // Object (lhs).
+  Register map = r6;              // Map of the object.
+  const Register function = r4;   // Function (rhs).
+  const Register prototype = r7;  // Prototype of the function.
+  const Register inline_site = r9;
+  const Register scratch = r5;
+  Register scratch3 = no_reg;
+
+// delta = mov + unaligned LoadP + cmp + bne
+#if V8_TARGET_ARCH_PPC64
+  const int32_t kDeltaToLoadBoolResult =
+      (Assembler::kMovInstructions + 4) * Assembler::kInstrSize;
+#else
+  const int32_t kDeltaToLoadBoolResult =
+      (Assembler::kMovInstructions + 3) * Assembler::kInstrSize;
+#endif
+
+  Label slow, loop, is_instance, is_not_instance, not_js_object;
+
+  if (!HasArgsInRegisters()) {
+    __ LoadP(object, MemOperand(sp, 1 * kPointerSize));
+    __ LoadP(function, MemOperand(sp, 0));
+  }
+
+  // Check that the left hand is a JS object and load map.
+  __ JumpIfSmi(object, &not_js_object);
+  __ IsObjectJSObjectType(object, map, scratch, &not_js_object);
+
+  // If there is a call site cache don't look in the global cache, but do the
+  // real lookup and update the call site cache.
+  if (!HasCallSiteInlineCheck() && !ReturnTrueFalseObject()) {
+    Label miss;
+    __ CompareRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
+    __ bne(&miss);
+    __ CompareRoot(map, Heap::kInstanceofCacheMapRootIndex);
+    __ bne(&miss);
+    __ LoadRoot(r3, Heap::kInstanceofCacheAnswerRootIndex);
+    __ Ret(HasArgsInRegisters() ? 0 : 2);
+
+    __ bind(&miss);
+  }
+
+  // Get the prototype of the function.
+  __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true);
+
+  // Check that the function prototype is a JS object.
+  __ JumpIfSmi(prototype, &slow);
+  __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
+
+  // Update the global instanceof or call site inlined cache with the current
+  // map and function. The cached answer will be set when it is known below.
+  if (!HasCallSiteInlineCheck()) {
+    __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
+    __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex);
+  } else {
+    DCHECK(HasArgsInRegisters());
+    // Patch the (relocated) inlined map check.
+
+    // The offset was stored in r8
+    //   (See LCodeGen::DoDeferredLInstanceOfKnownGlobal).
+    const Register offset = r8;
+    __ mflr(inline_site);
+    __ sub(inline_site, inline_site, offset);
+    // Get the map location in r8 and patch it.
+    __ GetRelocatedValue(inline_site, offset, scratch);
+    __ StoreP(map, FieldMemOperand(offset, Cell::kValueOffset), r0);
+  }
+
+  // Register mapping: r6 is object map and r7 is function prototype.
+  // Get prototype of object into r5.
+  __ LoadP(scratch, FieldMemOperand(map, Map::kPrototypeOffset));
+
+  // We don't need map any more. Use it as a scratch register.
+  scratch3 = map;
+  map = no_reg;
+
+  // Loop through the prototype chain looking for the function prototype.
+  __ LoadRoot(scratch3, Heap::kNullValueRootIndex);
+  __ bind(&loop);
+  __ cmp(scratch, prototype);
+  __ beq(&is_instance);
+  __ cmp(scratch, scratch3);
+  __ beq(&is_not_instance);
+  __ LoadP(scratch, FieldMemOperand(scratch, HeapObject::kMapOffset));
+  __ LoadP(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset));
+  __ b(&loop);
+  Factory* factory = isolate()->factory();
+
+  __ bind(&is_instance);
+  if (!HasCallSiteInlineCheck()) {
+    __ LoadSmiLiteral(r3, Smi::FromInt(0));
+    __ StoreRoot(r3, Heap::kInstanceofCacheAnswerRootIndex);
+    if (ReturnTrueFalseObject()) {
+      __ Move(r3, factory->true_value());
+    }
+  } else {
+    // Patch the call site to return true.
+    __ LoadRoot(r3, Heap::kTrueValueRootIndex);
+    __ addi(inline_site, inline_site, Operand(kDeltaToLoadBoolResult));
+    // Get the boolean result location in scratch and patch it.
+    __ SetRelocatedValue(inline_site, scratch, r3);
+
+    if (!ReturnTrueFalseObject()) {
+      __ LoadSmiLiteral(r3, Smi::FromInt(0));
+    }
+  }
+  __ Ret(HasArgsInRegisters() ? 0 : 2);
+
+  __ bind(&is_not_instance);
+  if (!HasCallSiteInlineCheck()) {
+    __ LoadSmiLiteral(r3, Smi::FromInt(1));
+    __ StoreRoot(r3, Heap::kInstanceofCacheAnswerRootIndex);
+    if (ReturnTrueFalseObject()) {
+      __ Move(r3, factory->false_value());
+    }
+  } else {
+    // Patch the call site to return false.
+    __ LoadRoot(r3, Heap::kFalseValueRootIndex);
+    __ addi(inline_site, inline_site, Operand(kDeltaToLoadBoolResult));
+    // Get the boolean result location in scratch and patch it.
+    __ SetRelocatedValue(inline_site, scratch, r3);
+
+    if (!ReturnTrueFalseObject()) {
+      __ LoadSmiLiteral(r3, Smi::FromInt(1));
+    }
+  }
+  __ Ret(HasArgsInRegisters() ? 0 : 2);
+
+  Label object_not_null, object_not_null_or_smi;
+  __ bind(&not_js_object);
+  // Before null, smi and string value checks, check that the rhs is a function
+  // as for a non-function rhs an exception needs to be thrown.
+  __ JumpIfSmi(function, &slow);
+  __ CompareObjectType(function, scratch3, scratch, JS_FUNCTION_TYPE);
+  __ bne(&slow);
+
+  // Null is not instance of anything.
+  __ Cmpi(object, Operand(isolate()->factory()->null_value()), r0);
+  __ bne(&object_not_null);
+  if (ReturnTrueFalseObject()) {
+    __ Move(r3, factory->false_value());
+  } else {
+    __ LoadSmiLiteral(r3, Smi::FromInt(1));
+  }
+  __ Ret(HasArgsInRegisters() ? 0 : 2);
+
+  __ bind(&object_not_null);
+  // Smi values are not instances of anything.
+  __ JumpIfNotSmi(object, &object_not_null_or_smi);
+  if (ReturnTrueFalseObject()) {
+    __ Move(r3, factory->false_value());
+  } else {
+    __ LoadSmiLiteral(r3, Smi::FromInt(1));
+  }
+  __ Ret(HasArgsInRegisters() ? 0 : 2);
+
+  __ bind(&object_not_null_or_smi);
+  // String values are not instances of anything.
+  __ IsObjectJSStringType(object, scratch, &slow);
+  if (ReturnTrueFalseObject()) {
+    __ Move(r3, factory->false_value());
+  } else {
+    __ LoadSmiLiteral(r3, Smi::FromInt(1));
+  }
+  __ Ret(HasArgsInRegisters() ? 0 : 2);
+
+  // Slow-case.  Tail call builtin.
+  __ bind(&slow);
+  if (!ReturnTrueFalseObject()) {
+    if (HasArgsInRegisters()) {
+      __ Push(r3, r4);
+    }
+    __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
+  } else {
+    {
+      FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+      __ Push(r3, r4);
+      __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
+    }
+    Label true_value, done;
+    __ cmpi(r3, Operand::Zero());
+    __ beq(&true_value);
+
+    __ LoadRoot(r3, Heap::kFalseValueRootIndex);
+    __ b(&done);
+
+    __ bind(&true_value);
+    __ LoadRoot(r3, Heap::kTrueValueRootIndex);
+
+    __ bind(&done);
+    __ Ret(HasArgsInRegisters() ? 0 : 2);
+  }
+}
+
+
+void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
+  Label miss;
+  Register receiver = LoadDescriptor::ReceiverRegister();
+
+  NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, r6,
+                                                          r7, &miss);
+  __ bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
+}
+
+
+void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
+  // Return address is in lr.
+  Label miss;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register index = LoadDescriptor::NameRegister();
+  Register scratch = r6;
+  Register result = r3;
+  DCHECK(!scratch.is(receiver) && !scratch.is(index));
+
+  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
+                                          &miss,  // When not a string.
+                                          &miss,  // When not a number.
+                                          &miss,  // When index out of range.
+                                          STRING_INDEX_IS_ARRAY_INDEX,
+                                          RECEIVER_IS_STRING);
+  char_at_generator.GenerateFast(masm);
+  __ Ret();
+
+  StubRuntimeCallHelper call_helper;
+  char_at_generator.GenerateSlow(masm, call_helper);
+
+  __ bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
+void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
+  // The displacement is the offset of the last parameter (if any)
+  // relative to the frame pointer.
+  const int kDisplacement =
+      StandardFrameConstants::kCallerSPOffset - kPointerSize;
+  DCHECK(r4.is(ArgumentsAccessReadDescriptor::index()));
+  DCHECK(r3.is(ArgumentsAccessReadDescriptor::parameter_count()));
+
+  // Check that the key is a smi.
+  Label slow;
+  __ JumpIfNotSmi(r4, &slow);
+
+  // Check if the calling frame is an arguments adaptor frame.
+  Label adaptor;
+  __ LoadP(r5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ LoadP(r6, MemOperand(r5, StandardFrameConstants::kContextOffset));
+  STATIC_ASSERT(StackFrame::ARGUMENTS_ADAPTOR < 0x3fffu);
+  __ CmpSmiLiteral(r6, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
+  __ beq(&adaptor);
+
+  // Check index against formal parameters count limit passed in
+  // through register r3. Use unsigned comparison to get negative
+  // check for free.
+  __ cmpl(r4, r3);
+  __ bge(&slow);
+
+  // Read the argument from the stack and return it.
+  __ sub(r6, r3, r4);
+  __ SmiToPtrArrayOffset(r6, r6);
+  __ add(r6, fp, r6);
+  __ LoadP(r3, MemOperand(r6, kDisplacement));
+  __ blr();
+
+  // Arguments adaptor case: Check index against actual arguments
+  // limit found in the arguments adaptor frame. Use unsigned
+  // comparison to get negative check for free.
+  __ bind(&adaptor);
+  __ LoadP(r3, MemOperand(r5, ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ cmpl(r4, r3);
+  __ bge(&slow);
+
+  // Read the argument from the adaptor frame and return it.
+  __ sub(r6, r3, r4);
+  __ SmiToPtrArrayOffset(r6, r6);
+  __ add(r6, r5, r6);
+  __ LoadP(r3, MemOperand(r6, kDisplacement));
+  __ blr();
+
+  // Slow-case: Handle non-smi or out-of-bounds access to arguments
+  // by calling the runtime system.
+  __ bind(&slow);
+  __ push(r4);
+  __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
+}
+
+
+void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
+  // sp[0] : number of parameters
+  // sp[1] : receiver displacement
+  // sp[2] : function
+
+  // Check if the calling frame is an arguments adaptor frame.
+  Label runtime;
+  __ LoadP(r6, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ LoadP(r5, MemOperand(r6, StandardFrameConstants::kContextOffset));
+  STATIC_ASSERT(StackFrame::ARGUMENTS_ADAPTOR < 0x3fffu);
+  __ CmpSmiLiteral(r5, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
+  __ bne(&runtime);
+
+  // Patch the arguments.length and the parameters pointer in the current frame.
+  __ LoadP(r5, MemOperand(r6, ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ StoreP(r5, MemOperand(sp, 0 * kPointerSize));
+  __ SmiToPtrArrayOffset(r5, r5);
+  __ add(r6, r6, r5);
+  __ addi(r6, r6, Operand(StandardFrameConstants::kCallerSPOffset));
+  __ StoreP(r6, MemOperand(sp, 1 * kPointerSize));
+
+  __ bind(&runtime);
+  __ TailCallRuntime(Runtime::kNewSloppyArguments, 3, 1);
+}
+
+
+void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
+  // Stack layout:
+  //  sp[0] : number of parameters (tagged)
+  //  sp[1] : address of receiver argument
+  //  sp[2] : function
+  // Registers used over whole function:
+  //  r9 : allocated object (tagged)
+  //  r11 : mapped parameter count (tagged)
+
+  __ LoadP(r4, MemOperand(sp, 0 * kPointerSize));
+  // r4 = parameter count (tagged)
+
+  // Check if the calling frame is an arguments adaptor frame.
+  Label runtime;
+  Label adaptor_frame, try_allocate;
+  __ LoadP(r6, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ LoadP(r5, MemOperand(r6, StandardFrameConstants::kContextOffset));
+  STATIC_ASSERT(StackFrame::ARGUMENTS_ADAPTOR < 0x3fffu);
+  __ CmpSmiLiteral(r5, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
+  __ beq(&adaptor_frame);
+
+  // No adaptor, parameter count = argument count.
+  __ mr(r5, r4);
+  __ b(&try_allocate);
+
+  // We have an adaptor frame. Patch the parameters pointer.
+  __ bind(&adaptor_frame);
+  __ LoadP(r5, MemOperand(r6, ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ SmiToPtrArrayOffset(r7, r5);
+  __ add(r6, r6, r7);
+  __ addi(r6, r6, Operand(StandardFrameConstants::kCallerSPOffset));
+  __ StoreP(r6, MemOperand(sp, 1 * kPointerSize));
+
+  // r4 = parameter count (tagged)
+  // r5 = argument count (tagged)
+  // Compute the mapped parameter count = min(r4, r5) in r4.
+  Label skip;
+  __ cmp(r4, r5);
+  __ blt(&skip);
+  __ mr(r4, r5);
+  __ bind(&skip);
+
+  __ bind(&try_allocate);
+
+  // Compute the sizes of backing store, parameter map, and arguments object.
+  // 1. Parameter map, has 2 extra words containing context and backing store.
+  const int kParameterMapHeaderSize =
+      FixedArray::kHeaderSize + 2 * kPointerSize;
+  // If there are no mapped parameters, we do not need the parameter_map.
+  Label skip2, skip3;
+  __ CmpSmiLiteral(r4, Smi::FromInt(0), r0);
+  __ bne(&skip2);
+  __ li(r11, Operand::Zero());
+  __ b(&skip3);
+  __ bind(&skip2);
+  __ SmiToPtrArrayOffset(r11, r4);
+  __ addi(r11, r11, Operand(kParameterMapHeaderSize));
+  __ bind(&skip3);
+
+  // 2. Backing store.
+  __ SmiToPtrArrayOffset(r7, r5);
+  __ add(r11, r11, r7);
+  __ addi(r11, r11, Operand(FixedArray::kHeaderSize));
+
+  // 3. Arguments object.
+  __ addi(r11, r11, Operand(Heap::kSloppyArgumentsObjectSize));
+
+  // Do the allocation of all three objects in one go.
+  __ Allocate(r11, r3, r6, r7, &runtime, TAG_OBJECT);
+
+  // r3 = address of new object(s) (tagged)
+  // r5 = argument count (smi-tagged)
+  // Get the arguments boilerplate from the current native context into r4.
+  const int kNormalOffset =
+      Context::SlotOffset(Context::SLOPPY_ARGUMENTS_MAP_INDEX);
+  const int kAliasedOffset =
+      Context::SlotOffset(Context::ALIASED_ARGUMENTS_MAP_INDEX);
+
+  __ LoadP(r7,
+           MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
+  __ LoadP(r7, FieldMemOperand(r7, GlobalObject::kNativeContextOffset));
+  Label skip4, skip5;
+  __ cmpi(r4, Operand::Zero());
+  __ bne(&skip4);
+  __ LoadP(r7, MemOperand(r7, kNormalOffset));
+  __ b(&skip5);
+  __ bind(&skip4);
+  __ LoadP(r7, MemOperand(r7, kAliasedOffset));
+  __ bind(&skip5);
+
+  // r3 = address of new object (tagged)
+  // r4 = mapped parameter count (tagged)
+  // r5 = argument count (smi-tagged)
+  // r7 = address of arguments map (tagged)
+  __ StoreP(r7, FieldMemOperand(r3, JSObject::kMapOffset), r0);
+  __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
+  __ StoreP(r6, FieldMemOperand(r3, JSObject::kPropertiesOffset), r0);
+  __ StoreP(r6, FieldMemOperand(r3, JSObject::kElementsOffset), r0);
+
+  // Set up the callee in-object property.
+  STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
+  __ LoadP(r6, MemOperand(sp, 2 * kPointerSize));
+  __ AssertNotSmi(r6);
+  const int kCalleeOffset =
+      JSObject::kHeaderSize + Heap::kArgumentsCalleeIndex * kPointerSize;
+  __ StoreP(r6, FieldMemOperand(r3, kCalleeOffset), r0);
+
+  // Use the length (smi tagged) and set that as an in-object property too.
+  __ AssertSmi(r5);
+  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
+  const int kLengthOffset =
+      JSObject::kHeaderSize + Heap::kArgumentsLengthIndex * kPointerSize;
+  __ StoreP(r5, FieldMemOperand(r3, kLengthOffset), r0);
+
+  // Set up the elements pointer in the allocated arguments object.
+  // If we allocated a parameter map, r7 will point there, otherwise
+  // it will point to the backing store.
+  __ addi(r7, r3, Operand(Heap::kSloppyArgumentsObjectSize));
+  __ StoreP(r7, FieldMemOperand(r3, JSObject::kElementsOffset), r0);
+
+  // r3 = address of new object (tagged)
+  // r4 = mapped parameter count (tagged)
+  // r5 = argument count (tagged)
+  // r7 = address of parameter map or backing store (tagged)
+  // Initialize parameter map. If there are no mapped arguments, we're done.
+  Label skip_parameter_map, skip6;
+  __ CmpSmiLiteral(r4, Smi::FromInt(0), r0);
+  __ bne(&skip6);
+  // Move backing store address to r6, because it is
+  // expected there when filling in the unmapped arguments.
+  __ mr(r6, r7);
+  __ b(&skip_parameter_map);
+  __ bind(&skip6);
+
+  __ LoadRoot(r9, Heap::kSloppyArgumentsElementsMapRootIndex);
+  __ StoreP(r9, FieldMemOperand(r7, FixedArray::kMapOffset), r0);
+  __ AddSmiLiteral(r9, r4, Smi::FromInt(2), r0);
+  __ StoreP(r9, FieldMemOperand(r7, FixedArray::kLengthOffset), r0);
+  __ StoreP(cp, FieldMemOperand(r7, FixedArray::kHeaderSize + 0 * kPointerSize),
+            r0);
+  __ SmiToPtrArrayOffset(r9, r4);
+  __ add(r9, r7, r9);
+  __ addi(r9, r9, Operand(kParameterMapHeaderSize));
+  __ StoreP(r9, FieldMemOperand(r7, FixedArray::kHeaderSize + 1 * kPointerSize),
+            r0);
+
+  // Copy the parameter slots and the holes in the arguments.
+  // We need to fill in mapped_parameter_count slots. They index the context,
+  // where parameters are stored in reverse order, at
+  //   MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
+  // The mapped parameter thus need to get indices
+  //   MIN_CONTEXT_SLOTS+parameter_count-1 ..
+  //       MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
+  // We loop from right to left.
+  Label parameters_loop, parameters_test;
+  __ mr(r9, r4);
+  __ LoadP(r11, MemOperand(sp, 0 * kPointerSize));
+  __ AddSmiLiteral(r11, r11, Smi::FromInt(Context::MIN_CONTEXT_SLOTS), r0);
+  __ sub(r11, r11, r4);
+  __ LoadRoot(r10, Heap::kTheHoleValueRootIndex);
+  __ SmiToPtrArrayOffset(r6, r9);
+  __ add(r6, r7, r6);
+  __ addi(r6, r6, Operand(kParameterMapHeaderSize));
+
+  // r9 = loop variable (tagged)
+  // r4 = mapping index (tagged)
+  // r6 = address of backing store (tagged)
+  // r7 = address of parameter map (tagged)
+  // r8 = temporary scratch (a.o., for address calculation)
+  // r10 = the hole value
+  __ b(&parameters_test);
+
+  __ bind(&parameters_loop);
+  __ SubSmiLiteral(r9, r9, Smi::FromInt(1), r0);
+  __ SmiToPtrArrayOffset(r8, r9);
+  __ addi(r8, r8, Operand(kParameterMapHeaderSize - kHeapObjectTag));
+  __ StorePX(r11, MemOperand(r8, r7));
+  __ subi(r8, r8, Operand(kParameterMapHeaderSize - FixedArray::kHeaderSize));
+  __ StorePX(r10, MemOperand(r8, r6));
+  __ AddSmiLiteral(r11, r11, Smi::FromInt(1), r0);
+  __ bind(&parameters_test);
+  __ CmpSmiLiteral(r9, Smi::FromInt(0), r0);
+  __ bne(&parameters_loop);
+
+  __ bind(&skip_parameter_map);
+  // r5 = argument count (tagged)
+  // r6 = address of backing store (tagged)
+  // r8 = scratch
+  // Copy arguments header and remaining slots (if there are any).
+  __ LoadRoot(r8, Heap::kFixedArrayMapRootIndex);
+  __ StoreP(r8, FieldMemOperand(r6, FixedArray::kMapOffset), r0);
+  __ StoreP(r5, FieldMemOperand(r6, FixedArray::kLengthOffset), r0);
+
+  Label arguments_loop, arguments_test;
+  __ mr(r11, r4);
+  __ LoadP(r7, MemOperand(sp, 1 * kPointerSize));
+  __ SmiToPtrArrayOffset(r8, r11);
+  __ sub(r7, r7, r8);
+  __ b(&arguments_test);
+
+  __ bind(&arguments_loop);
+  __ subi(r7, r7, Operand(kPointerSize));
+  __ LoadP(r9, MemOperand(r7, 0));
+  __ SmiToPtrArrayOffset(r8, r11);
+  __ add(r8, r6, r8);
+  __ StoreP(r9, FieldMemOperand(r8, FixedArray::kHeaderSize), r0);
+  __ AddSmiLiteral(r11, r11, Smi::FromInt(1), r0);
+
+  __ bind(&arguments_test);
+  __ cmp(r11, r5);
+  __ blt(&arguments_loop);
+
+  // Return and remove the on-stack parameters.
+  __ addi(sp, sp, Operand(3 * kPointerSize));
+  __ Ret();
+
+  // Do the runtime call to allocate the arguments object.
+  // r5 = argument count (tagged)
+  __ bind(&runtime);
+  __ StoreP(r5, MemOperand(sp, 0 * kPointerSize));  // Patch argument count.
+  __ TailCallRuntime(Runtime::kNewSloppyArguments, 3, 1);
+}
+
+
+void LoadIndexedInterceptorStub::Generate(MacroAssembler* masm) {
+  // Return address is in lr.
+  Label slow;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register key = LoadDescriptor::NameRegister();
+
+  // Check that the key is an array index, that is Uint32.
+  __ TestIfPositiveSmi(key, r0);
+  __ bne(&slow, cr0);
+
+  // Everything is fine, call runtime.
+  __ Push(receiver, key);  // Receiver, key.
+
+  // Perform tail call to the entry.
+  __ TailCallExternalReference(
+      ExternalReference(IC_Utility(IC::kLoadElementWithInterceptor),
+                        masm->isolate()),
+      2, 1);
+
+  __ bind(&slow);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
+void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
+  // sp[0] : number of parameters
+  // sp[4] : receiver displacement
+  // sp[8] : function
+  // Check if the calling frame is an arguments adaptor frame.
+  Label adaptor_frame, try_allocate, runtime;
+  __ LoadP(r5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ LoadP(r6, MemOperand(r5, StandardFrameConstants::kContextOffset));
+  STATIC_ASSERT(StackFrame::ARGUMENTS_ADAPTOR < 0x3fffu);
+  __ CmpSmiLiteral(r6, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
+  __ beq(&adaptor_frame);
+
+  // Get the length from the frame.
+  __ LoadP(r4, MemOperand(sp, 0));
+  __ b(&try_allocate);
+
+  // Patch the arguments.length and the parameters pointer.
+  __ bind(&adaptor_frame);
+  __ LoadP(r4, MemOperand(r5, ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ StoreP(r4, MemOperand(sp, 0));
+  __ SmiToPtrArrayOffset(r6, r4);
+  __ add(r6, r5, r6);
+  __ addi(r6, r6, Operand(StandardFrameConstants::kCallerSPOffset));
+  __ StoreP(r6, MemOperand(sp, 1 * kPointerSize));
+
+  // Try the new space allocation. Start out with computing the size
+  // of the arguments object and the elements array in words.
+  Label add_arguments_object;
+  __ bind(&try_allocate);
+  __ cmpi(r4, Operand::Zero());
+  __ beq(&add_arguments_object);
+  __ SmiUntag(r4);
+  __ addi(r4, r4, Operand(FixedArray::kHeaderSize / kPointerSize));
+  __ bind(&add_arguments_object);
+  __ addi(r4, r4, Operand(Heap::kStrictArgumentsObjectSize / kPointerSize));
+
+  // Do the allocation of both objects in one go.
+  __ Allocate(r4, r3, r5, r6, &runtime,
+              static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
+
+  // Get the arguments boilerplate from the current native context.
+  __ LoadP(r7,
+           MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
+  __ LoadP(r7, FieldMemOperand(r7, GlobalObject::kNativeContextOffset));
+  __ LoadP(
+      r7,
+      MemOperand(r7, Context::SlotOffset(Context::STRICT_ARGUMENTS_MAP_INDEX)));
+
+  __ StoreP(r7, FieldMemOperand(r3, JSObject::kMapOffset), r0);
+  __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex);
+  __ StoreP(r6, FieldMemOperand(r3, JSObject::kPropertiesOffset), r0);
+  __ StoreP(r6, FieldMemOperand(r3, JSObject::kElementsOffset), r0);
+
+  // Get the length (smi tagged) and set that as an in-object property too.
+  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
+  __ LoadP(r4, MemOperand(sp, 0 * kPointerSize));
+  __ AssertSmi(r4);
+  __ StoreP(r4,
+            FieldMemOperand(r3, JSObject::kHeaderSize +
+                                    Heap::kArgumentsLengthIndex * kPointerSize),
+            r0);
+
+  // If there are no actual arguments, we're done.
+  Label done;
+  __ cmpi(r4, Operand::Zero());
+  __ beq(&done);
+
+  // Get the parameters pointer from the stack.
+  __ LoadP(r5, MemOperand(sp, 1 * kPointerSize));
+
+  // Set up the elements pointer in the allocated arguments object and
+  // initialize the header in the elements fixed array.
+  __ addi(r7, r3, Operand(Heap::kStrictArgumentsObjectSize));
+  __ StoreP(r7, FieldMemOperand(r3, JSObject::kElementsOffset), r0);
+  __ LoadRoot(r6, Heap::kFixedArrayMapRootIndex);
+  __ StoreP(r6, FieldMemOperand(r7, FixedArray::kMapOffset), r0);
+  __ StoreP(r4, FieldMemOperand(r7, FixedArray::kLengthOffset), r0);
+  // Untag the length for the loop.
+  __ SmiUntag(r4);
+
+  // Copy the fixed array slots.
+  Label loop;
+  // Set up r7 to point just prior to the first array slot.
+  __ addi(r7, r7,
+          Operand(FixedArray::kHeaderSize - kHeapObjectTag - kPointerSize));
+  __ mtctr(r4);
+  __ bind(&loop);
+  // Pre-decrement r5 with kPointerSize on each iteration.
+  // Pre-decrement in order to skip receiver.
+  __ LoadPU(r6, MemOperand(r5, -kPointerSize));
+  // Pre-increment r7 with kPointerSize on each iteration.
+  __ StorePU(r6, MemOperand(r7, kPointerSize));
+  __ bdnz(&loop);
+
+  // Return and remove the on-stack parameters.
+  __ bind(&done);
+  __ addi(sp, sp, Operand(3 * kPointerSize));
+  __ Ret();
+
+  // Do the runtime call to allocate the arguments object.
+  __ bind(&runtime);
+  __ TailCallRuntime(Runtime::kNewStrictArguments, 3, 1);
+}
+
+
+void RegExpExecStub::Generate(MacroAssembler* masm) {
+// Just jump directly to runtime if native RegExp is not selected at compile
+// time or if regexp entry in generated code is turned off runtime switch or
+// at compilation.
+#ifdef V8_INTERPRETED_REGEXP
+  __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
+#else  // V8_INTERPRETED_REGEXP
+
+  // Stack frame on entry.
+  //  sp[0]: last_match_info (expected JSArray)
+  //  sp[4]: previous index
+  //  sp[8]: subject string
+  //  sp[12]: JSRegExp object
+
+  const int kLastMatchInfoOffset = 0 * kPointerSize;
+  const int kPreviousIndexOffset = 1 * kPointerSize;
+  const int kSubjectOffset = 2 * kPointerSize;
+  const int kJSRegExpOffset = 3 * kPointerSize;
+
+  Label runtime, br_over, encoding_type_UC16;
+
+  // Allocation of registers for this function. These are in callee save
+  // registers and will be preserved by the call to the native RegExp code, as
+  // this code is called using the normal C calling convention. When calling
+  // directly from generated code the native RegExp code will not do a GC and
+  // therefore the content of these registers are safe to use after the call.
+  Register subject = r14;
+  Register regexp_data = r15;
+  Register last_match_info_elements = r16;
+  Register code = r17;
+
+  // Ensure register assigments are consistent with callee save masks
+  DCHECK(subject.bit() & kCalleeSaved);
+  DCHECK(regexp_data.bit() & kCalleeSaved);
+  DCHECK(last_match_info_elements.bit() & kCalleeSaved);
+  DCHECK(code.bit() & kCalleeSaved);
+
+  // Ensure that a RegExp stack is allocated.
+  ExternalReference address_of_regexp_stack_memory_address =
+      ExternalReference::address_of_regexp_stack_memory_address(isolate());
+  ExternalReference address_of_regexp_stack_memory_size =
+      ExternalReference::address_of_regexp_stack_memory_size(isolate());
+  __ mov(r3, Operand(address_of_regexp_stack_memory_size));
+  __ LoadP(r3, MemOperand(r3, 0));
+  __ cmpi(r3, Operand::Zero());
+  __ beq(&runtime);
+
+  // Check that the first argument is a JSRegExp object.
+  __ LoadP(r3, MemOperand(sp, kJSRegExpOffset));
+  __ JumpIfSmi(r3, &runtime);
+  __ CompareObjectType(r3, r4, r4, JS_REGEXP_TYPE);
+  __ bne(&runtime);
+
+  // Check that the RegExp has been compiled (data contains a fixed array).
+  __ LoadP(regexp_data, FieldMemOperand(r3, JSRegExp::kDataOffset));
+  if (FLAG_debug_code) {
+    __ TestIfSmi(regexp_data, r0);
+    __ Check(ne, kUnexpectedTypeForRegExpDataFixedArrayExpected, cr0);
+    __ CompareObjectType(regexp_data, r3, r3, FIXED_ARRAY_TYPE);
+    __ Check(eq, kUnexpectedTypeForRegExpDataFixedArrayExpected);
+  }
+
+  // regexp_data: RegExp data (FixedArray)
+  // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
+  __ LoadP(r3, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset));
+  // DCHECK(Smi::FromInt(JSRegExp::IRREGEXP) < (char *)0xffffu);
+  __ CmpSmiLiteral(r3, Smi::FromInt(JSRegExp::IRREGEXP), r0);
+  __ bne(&runtime);
+
+  // regexp_data: RegExp data (FixedArray)
+  // Check that the number of captures fit in the static offsets vector buffer.
+  __ LoadP(r5,
+           FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset));
+  // Check (number_of_captures + 1) * 2 <= offsets vector size
+  // Or          number_of_captures * 2 <= offsets vector size - 2
+  // SmiToShortArrayOffset accomplishes the multiplication by 2 and
+  // SmiUntag (which is a nop for 32-bit).
+  __ SmiToShortArrayOffset(r5, r5);
+  STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
+  __ cmpli(r5, Operand(Isolate::kJSRegexpStaticOffsetsVectorSize - 2));
+  __ bgt(&runtime);
+
+  // Reset offset for possibly sliced string.
+  __ li(r11, Operand::Zero());
+  __ LoadP(subject, MemOperand(sp, kSubjectOffset));
+  __ JumpIfSmi(subject, &runtime);
+  __ mr(r6, subject);  // Make a copy of the original subject string.
+  __ LoadP(r3, FieldMemOperand(subject, HeapObject::kMapOffset));
+  __ lbz(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset));
+  // subject: subject string
+  // r6: subject string
+  // r3: subject string instance type
+  // regexp_data: RegExp data (FixedArray)
+  // Handle subject string according to its encoding and representation:
+  // (1) Sequential string?  If yes, go to (5).
+  // (2) Anything but sequential or cons?  If yes, go to (6).
+  // (3) Cons string.  If the string is flat, replace subject with first string.
+  //     Otherwise bailout.
+  // (4) Is subject external?  If yes, go to (7).
+  // (5) Sequential string.  Load regexp code according to encoding.
+  // (E) Carry on.
+  /// [...]
+
+  // Deferred code at the end of the stub:
+  // (6) Not a long external string?  If yes, go to (8).
+  // (7) External string.  Make it, offset-wise, look like a sequential string.
+  //     Go to (5).
+  // (8) Short external string or not a string?  If yes, bail out to runtime.
+  // (9) Sliced string.  Replace subject with parent.  Go to (4).
+
+  Label seq_string /* 5 */, external_string /* 7 */, check_underlying /* 4 */,
+      not_seq_nor_cons /* 6 */, not_long_external /* 8 */;
+
+  // (1) Sequential string?  If yes, go to (5).
+  STATIC_ASSERT((kIsNotStringMask | kStringRepresentationMask |
+                 kShortExternalStringMask) == 0x93);
+  __ andi(r4, r3, Operand(kIsNotStringMask | kStringRepresentationMask |
+                          kShortExternalStringMask));
+  STATIC_ASSERT((kStringTag | kSeqStringTag) == 0);
+  __ beq(&seq_string, cr0);  // Go to (5).
+
+  // (2) Anything but sequential or cons?  If yes, go to (6).
+  STATIC_ASSERT(kConsStringTag < kExternalStringTag);
+  STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
+  STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
+  STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
+  STATIC_ASSERT(kExternalStringTag < 0xffffu);
+  __ cmpi(r4, Operand(kExternalStringTag));
+  __ bge(&not_seq_nor_cons);  // Go to (6).
+
+  // (3) Cons string.  Check that it's flat.
+  // Replace subject with first string and reload instance type.
+  __ LoadP(r3, FieldMemOperand(subject, ConsString::kSecondOffset));
+  __ CompareRoot(r3, Heap::kempty_stringRootIndex);
+  __ bne(&runtime);
+  __ LoadP(subject, FieldMemOperand(subject, ConsString::kFirstOffset));
+
+  // (4) Is subject external?  If yes, go to (7).
+  __ bind(&check_underlying);
+  __ LoadP(r3, FieldMemOperand(subject, HeapObject::kMapOffset));
+  __ lbz(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset));
+  STATIC_ASSERT(kSeqStringTag == 0);
+  STATIC_ASSERT(kStringRepresentationMask == 3);
+  __ andi(r0, r3, Operand(kStringRepresentationMask));
+  // The underlying external string is never a short external string.
+  STATIC_ASSERT(ExternalString::kMaxShortLength < ConsString::kMinLength);
+  STATIC_ASSERT(ExternalString::kMaxShortLength < SlicedString::kMinLength);
+  __ bne(&external_string, cr0);  // Go to (7).
+
+  // (5) Sequential string.  Load regexp code according to encoding.
+  __ bind(&seq_string);
+  // subject: sequential subject string (or look-alike, external string)
+  // r6: original subject string
+  // Load previous index and check range before r6 is overwritten.  We have to
+  // use r6 instead of subject here because subject might have been only made
+  // to look like a sequential string when it actually is an external string.
+  __ LoadP(r4, MemOperand(sp, kPreviousIndexOffset));
+  __ JumpIfNotSmi(r4, &runtime);
+  __ LoadP(r6, FieldMemOperand(r6, String::kLengthOffset));
+  __ cmpl(r6, r4);
+  __ ble(&runtime);
+  __ SmiUntag(r4);
+
+  STATIC_ASSERT(4 == kOneByteStringTag);
+  STATIC_ASSERT(kTwoByteStringTag == 0);
+  STATIC_ASSERT(kStringEncodingMask == 4);
+  __ ExtractBitMask(r6, r3, kStringEncodingMask, SetRC);
+  __ beq(&encoding_type_UC16, cr0);
+  __ LoadP(code,
+           FieldMemOperand(regexp_data, JSRegExp::kDataOneByteCodeOffset));
+  __ b(&br_over);
+  __ bind(&encoding_type_UC16);
+  __ LoadP(code, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset));
+  __ bind(&br_over);
+
+  // (E) Carry on.  String handling is done.
+  // code: irregexp code
+  // Check that the irregexp code has been generated for the actual string
+  // encoding. If it has, the field contains a code object otherwise it contains
+  // a smi (code flushing support).
+  __ JumpIfSmi(code, &runtime);
+
+  // r4: previous index
+  // r6: encoding of subject string (1 if one_byte, 0 if two_byte);
+  // code: Address of generated regexp code
+  // subject: Subject string
+  // regexp_data: RegExp data (FixedArray)
+  // All checks done. Now push arguments for native regexp code.
+  __ IncrementCounter(isolate()->counters()->regexp_entry_native(), 1, r3, r5);
+
+  // Isolates: note we add an additional parameter here (isolate pointer).
+  const int kRegExpExecuteArguments = 10;
+  const int kParameterRegisters = 8;
+  __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters);
+
+  // Stack pointer now points to cell where return address is to be written.
+  // Arguments are before that on the stack or in registers.
+
+  // Argument 10 (in stack parameter area): Pass current isolate address.
+  __ mov(r3, Operand(ExternalReference::isolate_address(isolate())));
+  __ StoreP(r3, MemOperand(sp, (kStackFrameExtraParamSlot + 1) * kPointerSize));
+
+  // Argument 9 is a dummy that reserves the space used for
+  // the return address added by the ExitFrame in native calls.
+
+  // Argument 8 (r10): Indicate that this is a direct call from JavaScript.
+  __ li(r10, Operand(1));
+
+  // Argument 7 (r9): Start (high end) of backtracking stack memory area.
+  __ mov(r3, Operand(address_of_regexp_stack_memory_address));
+  __ LoadP(r3, MemOperand(r3, 0));
+  __ mov(r5, Operand(address_of_regexp_stack_memory_size));
+  __ LoadP(r5, MemOperand(r5, 0));
+  __ add(r9, r3, r5);
+
+  // Argument 6 (r8): Set the number of capture registers to zero to force
+  // global egexps to behave as non-global.  This does not affect non-global
+  // regexps.
+  __ li(r8, Operand::Zero());
+
+  // Argument 5 (r7): static offsets vector buffer.
+  __ mov(
+      r7,
+      Operand(ExternalReference::address_of_static_offsets_vector(isolate())));
+
+  // For arguments 4 (r6) and 3 (r5) get string length, calculate start of data
+  // and calculate the shift of the index (0 for one-byte and 1 for two-byte).
+  __ addi(r18, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag));
+  __ xori(r6, r6, Operand(1));
+  // Load the length from the original subject string from the previous stack
+  // frame. Therefore we have to use fp, which points exactly to two pointer
+  // sizes below the previous sp. (Because creating a new stack frame pushes
+  // the previous fp onto the stack and moves up sp by 2 * kPointerSize.)
+  __ LoadP(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
+  // If slice offset is not 0, load the length from the original sliced string.
+  // Argument 4, r6: End of string data
+  // Argument 3, r5: Start of string data
+  // Prepare start and end index of the input.
+  __ ShiftLeft_(r11, r11, r6);
+  __ add(r11, r18, r11);
+  __ ShiftLeft_(r5, r4, r6);
+  __ add(r5, r11, r5);
+
+  __ LoadP(r18, FieldMemOperand(subject, String::kLengthOffset));
+  __ SmiUntag(r18);
+  __ ShiftLeft_(r6, r18, r6);
+  __ add(r6, r11, r6);
+
+  // Argument 2 (r4): Previous index.
+  // Already there
+
+  // Argument 1 (r3): Subject string.
+  __ mr(r3, subject);
+
+  // Locate the code entry and call it.
+  __ addi(code, code, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+
+#if ABI_USES_FUNCTION_DESCRIPTORS && defined(USE_SIMULATOR)
+  // Even Simulated AIX/PPC64 Linux uses a function descriptor for the
+  // RegExp routine.  Extract the instruction address here since
+  // DirectCEntryStub::GenerateCall will not do it for calls out to
+  // what it thinks is C code compiled for the simulator/host
+  // platform.
+  __ LoadP(code, MemOperand(code, 0));  // Instruction address
+#endif
+
+  DirectCEntryStub stub(isolate());
+  stub.GenerateCall(masm, code);
+
+  __ LeaveExitFrame(false, no_reg, true);
+
+  // r3: result
+  // subject: subject string (callee saved)
+  // regexp_data: RegExp data (callee saved)
+  // last_match_info_elements: Last match info elements (callee saved)
+  // Check the result.
+  Label success;
+  __ cmpi(r3, Operand(1));
+  // We expect exactly one result since we force the called regexp to behave
+  // as non-global.
+  __ beq(&success);
+  Label failure;
+  __ cmpi(r3, Operand(NativeRegExpMacroAssembler::FAILURE));
+  __ beq(&failure);
+  __ cmpi(r3, Operand(NativeRegExpMacroAssembler::EXCEPTION));
+  // If not exception it can only be retry. Handle that in the runtime system.
+  __ bne(&runtime);
+  // Result must now be exception. If there is no pending exception already a
+  // stack overflow (on the backtrack stack) was detected in RegExp code but
+  // haven't created the exception yet. Handle that in the runtime system.
+  // TODO(592): Rerunning the RegExp to get the stack overflow exception.
+  __ mov(r4, Operand(isolate()->factory()->the_hole_value()));
+  __ mov(r5, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
+                                       isolate())));
+  __ LoadP(r3, MemOperand(r5, 0));
+  __ cmp(r3, r4);
+  __ beq(&runtime);
+
+  __ StoreP(r4, MemOperand(r5, 0));  // Clear pending exception.
+
+  // Check if the exception is a termination. If so, throw as uncatchable.
+  __ CompareRoot(r3, Heap::kTerminationExceptionRootIndex);
+
+  Label termination_exception;
+  __ beq(&termination_exception);
+
+  __ Throw(r3);
+
+  __ bind(&termination_exception);
+  __ ThrowUncatchable(r3);
+
+  __ bind(&failure);
+  // For failure and exception return null.
+  __ mov(r3, Operand(isolate()->factory()->null_value()));
+  __ addi(sp, sp, Operand(4 * kPointerSize));
+  __ Ret();
+
+  // Process the result from the native regexp code.
+  __ bind(&success);
+  __ LoadP(r4,
+           FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset));
+  // Calculate number of capture registers (number_of_captures + 1) * 2.
+  // SmiToShortArrayOffset accomplishes the multiplication by 2 and
+  // SmiUntag (which is a nop for 32-bit).
+  __ SmiToShortArrayOffset(r4, r4);
+  __ addi(r4, r4, Operand(2));
+
+  __ LoadP(r3, MemOperand(sp, kLastMatchInfoOffset));
+  __ JumpIfSmi(r3, &runtime);
+  __ CompareObjectType(r3, r5, r5, JS_ARRAY_TYPE);
+  __ bne(&runtime);
+  // Check that the JSArray is in fast case.
+  __ LoadP(last_match_info_elements,
+           FieldMemOperand(r3, JSArray::kElementsOffset));
+  __ LoadP(r3,
+           FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset));
+  __ CompareRoot(r3, Heap::kFixedArrayMapRootIndex);
+  __ bne(&runtime);
+  // Check that the last match info has space for the capture registers and the
+  // additional information.
+  __ LoadP(
+      r3, FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset));
+  __ addi(r5, r4, Operand(RegExpImpl::kLastMatchOverhead));
+  __ SmiUntag(r0, r3);
+  __ cmp(r5, r0);
+  __ bgt(&runtime);
+
+  // r4: number of capture registers
+  // subject: subject string
+  // Store the capture count.
+  __ SmiTag(r5, r4);
+  __ StoreP(r5, FieldMemOperand(last_match_info_elements,
+                                RegExpImpl::kLastCaptureCountOffset),
+            r0);
+  // Store last subject and last input.
+  __ StoreP(subject, FieldMemOperand(last_match_info_elements,
+                                     RegExpImpl::kLastSubjectOffset),
+            r0);
+  __ mr(r5, subject);
+  __ RecordWriteField(last_match_info_elements, RegExpImpl::kLastSubjectOffset,
+                      subject, r10, kLRHasNotBeenSaved, kDontSaveFPRegs);
+  __ mr(subject, r5);
+  __ StoreP(subject, FieldMemOperand(last_match_info_elements,
+                                     RegExpImpl::kLastInputOffset),
+            r0);
+  __ RecordWriteField(last_match_info_elements, RegExpImpl::kLastInputOffset,
+                      subject, r10, kLRHasNotBeenSaved, kDontSaveFPRegs);
+
+  // Get the static offsets vector filled by the native regexp code.
+  ExternalReference address_of_static_offsets_vector =
+      ExternalReference::address_of_static_offsets_vector(isolate());
+  __ mov(r5, Operand(address_of_static_offsets_vector));
+
+  // r4: number of capture registers
+  // r5: offsets vector
+  Label next_capture;
+  // Capture register counter starts from number of capture registers and
+  // counts down until wraping after zero.
+  __ addi(
+      r3, last_match_info_elements,
+      Operand(RegExpImpl::kFirstCaptureOffset - kHeapObjectTag - kPointerSize));
+  __ addi(r5, r5, Operand(-kIntSize));  // bias down for lwzu
+  __ mtctr(r4);
+  __ bind(&next_capture);
+  // Read the value from the static offsets vector buffer.
+  __ lwzu(r6, MemOperand(r5, kIntSize));
+  // Store the smi value in the last match info.
+  __ SmiTag(r6);
+  __ StorePU(r6, MemOperand(r3, kPointerSize));
+  __ bdnz(&next_capture);
+
+  // Return last match info.
+  __ LoadP(r3, MemOperand(sp, kLastMatchInfoOffset));
+  __ addi(sp, sp, Operand(4 * kPointerSize));
+  __ Ret();
+
+  // Do the runtime call to execute the regexp.
+  __ bind(&runtime);
+  __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
+
+  // Deferred code for string handling.
+  // (6) Not a long external string?  If yes, go to (8).
+  __ bind(&not_seq_nor_cons);
+  // Compare flags are still set.
+  __ bgt(&not_long_external);  // Go to (8).
+
+  // (7) External string.  Make it, offset-wise, look like a sequential string.
+  __ bind(&external_string);
+  __ LoadP(r3, FieldMemOperand(subject, HeapObject::kMapOffset));
+  __ lbz(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset));
+  if (FLAG_debug_code) {
+    // Assert that we do not have a cons or slice (indirect strings) here.
+    // Sequential strings have already been ruled out.
+    STATIC_ASSERT(kIsIndirectStringMask == 1);
+    __ andi(r0, r3, Operand(kIsIndirectStringMask));
+    __ Assert(eq, kExternalStringExpectedButNotFound, cr0);
+  }
+  __ LoadP(subject,
+           FieldMemOperand(subject, ExternalString::kResourceDataOffset));
+  // Move the pointer so that offset-wise, it looks like a sequential string.
+  STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
+  __ subi(subject, subject,
+          Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
+  __ b(&seq_string);  // Go to (5).
+
+  // (8) Short external string or not a string?  If yes, bail out to runtime.
+  __ bind(&not_long_external);
+  STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag != 0);
+  __ andi(r0, r4, Operand(kIsNotStringMask | kShortExternalStringMask));
+  __ bne(&runtime, cr0);
+
+  // (9) Sliced string.  Replace subject with parent.  Go to (4).
+  // Load offset into r11 and replace subject string with parent.
+  __ LoadP(r11, FieldMemOperand(subject, SlicedString::kOffsetOffset));
+  __ SmiUntag(r11);
+  __ LoadP(subject, FieldMemOperand(subject, SlicedString::kParentOffset));
+  __ b(&check_underlying);  // Go to (4).
+#endif  // V8_INTERPRETED_REGEXP
+}
+
+
+static void GenerateRecordCallTarget(MacroAssembler* masm) {
+  // Cache the called function in a feedback vector slot.  Cache states
+  // are uninitialized, monomorphic (indicated by a JSFunction), and
+  // megamorphic.
+  // r3 : number of arguments to the construct function
+  // r4 : the function to call
+  // r5 : Feedback vector
+  // r6 : slot in feedback vector (Smi)
+  Label initialize, done, miss, megamorphic, not_array_function;
+
+  DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()),
+            masm->isolate()->heap()->megamorphic_symbol());
+  DCHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(masm->isolate()),
+            masm->isolate()->heap()->uninitialized_symbol());
+
+  // Load the cache state into r7.
+  __ SmiToPtrArrayOffset(r7, r6);
+  __ add(r7, r5, r7);
+  __ LoadP(r7, FieldMemOperand(r7, FixedArray::kHeaderSize));
+
+  // A monomorphic cache hit or an already megamorphic state: invoke the
+  // function without changing the state.
+  __ cmp(r7, r4);
+  __ b(eq, &done);
+
+  if (!FLAG_pretenuring_call_new) {
+    // If we came here, we need to see if we are the array function.
+    // If we didn't have a matching function, and we didn't find the megamorph
+    // sentinel, then we have in the slot either some other function or an
+    // AllocationSite. Do a map check on the object in ecx.
+    __ LoadP(r8, FieldMemOperand(r7, 0));
+    __ CompareRoot(r8, Heap::kAllocationSiteMapRootIndex);
+    __ bne(&miss);
+
+    // Make sure the function is the Array() function
+    __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, r7);
+    __ cmp(r4, r7);
+    __ bne(&megamorphic);
+    __ b(&done);
+  }
+
+  __ bind(&miss);
+
+  // A monomorphic miss (i.e, here the cache is not uninitialized) goes
+  // megamorphic.
+  __ CompareRoot(r7, Heap::kuninitialized_symbolRootIndex);
+  __ beq(&initialize);
+  // MegamorphicSentinel is an immortal immovable object (undefined) so no
+  // write-barrier is needed.
+  __ bind(&megamorphic);
+  __ SmiToPtrArrayOffset(r7, r6);
+  __ add(r7, r5, r7);
+  __ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex);
+  __ StoreP(ip, FieldMemOperand(r7, FixedArray::kHeaderSize), r0);
+  __ jmp(&done);
+
+  // An uninitialized cache is patched with the function
+  __ bind(&initialize);
+
+  if (!FLAG_pretenuring_call_new) {
+    // Make sure the function is the Array() function.
+    __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, r7);
+    __ cmp(r4, r7);
+    __ bne(&not_array_function);
+
+    // The target function is the Array constructor,
+    // Create an AllocationSite if we don't already have it, store it in the
+    // slot.
+    {
+      FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+
+      // Arguments register must be smi-tagged to call out.
+      __ SmiTag(r3);
+      __ Push(r6, r5, r4, r3);
+
+      CreateAllocationSiteStub create_stub(masm->isolate());
+      __ CallStub(&create_stub);
+
+      __ Pop(r6, r5, r4, r3);
+      __ SmiUntag(r3);
+    }
+    __ b(&done);
+
+    __ bind(&not_array_function);
+  }
+
+  __ SmiToPtrArrayOffset(r7, r6);
+  __ add(r7, r5, r7);
+  __ addi(r7, r7, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ StoreP(r4, MemOperand(r7, 0));
+
+  __ Push(r7, r5, r4);
+  __ RecordWrite(r5, r7, r4, kLRHasNotBeenSaved, kDontSaveFPRegs,
+                 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+  __ Pop(r7, r5, r4);
+
+  __ bind(&done);
+}
+
+
+static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) {
+  // Do not transform the receiver for strict mode functions and natives.
+  __ LoadP(r6, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
+  __ lwz(r7, FieldMemOperand(r6, SharedFunctionInfo::kCompilerHintsOffset));
+  __ TestBit(r7,
+#if V8_TARGET_ARCH_PPC64
+             SharedFunctionInfo::kStrictModeFunction,
+#else
+             SharedFunctionInfo::kStrictModeFunction + kSmiTagSize,
+#endif
+             r0);
+  __ bne(cont, cr0);
+
+  // Do not transform the receiver for native.
+  __ TestBit(r7,
+#if V8_TARGET_ARCH_PPC64
+             SharedFunctionInfo::kNative,
+#else
+             SharedFunctionInfo::kNative + kSmiTagSize,
+#endif
+             r0);
+  __ bne(cont, cr0);
+}
+
+
+static void EmitSlowCase(MacroAssembler* masm, int argc, Label* non_function) {
+  // Check for function proxy.
+  STATIC_ASSERT(JS_FUNCTION_PROXY_TYPE < 0xffffu);
+  __ cmpi(r7, Operand(JS_FUNCTION_PROXY_TYPE));
+  __ bne(non_function);
+  __ push(r4);  // put proxy as additional argument
+  __ li(r3, Operand(argc + 1));
+  __ li(r5, Operand::Zero());
+  __ GetBuiltinFunction(r4, Builtins::CALL_FUNCTION_PROXY);
+  {
+    Handle<Code> adaptor =
+        masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
+    __ Jump(adaptor, RelocInfo::CODE_TARGET);
+  }
+
+  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
+  // of the original receiver from the call site).
+  __ bind(non_function);
+  __ StoreP(r4, MemOperand(sp, argc * kPointerSize), r0);
+  __ li(r3, Operand(argc));  // Set up the number of arguments.
+  __ li(r5, Operand::Zero());
+  __ GetBuiltinFunction(r4, Builtins::CALL_NON_FUNCTION);
+  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+          RelocInfo::CODE_TARGET);
+}
+
+
+static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
+  // Wrap the receiver and patch it back onto the stack.
+  {
+    FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL);
+    __ Push(r4, r6);
+    __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
+    __ pop(r4);
+  }
+  __ StoreP(r3, MemOperand(sp, argc * kPointerSize), r0);
+  __ b(cont);
+}
+
+
+static void CallFunctionNoFeedback(MacroAssembler* masm, int argc,
+                                   bool needs_checks, bool call_as_method) {
+  // r4 : the function to call
+  Label slow, non_function, wrap, cont;
+
+  if (needs_checks) {
+    // Check that the function is really a JavaScript function.
+    // r4: pushed function (to be verified)
+    __ JumpIfSmi(r4, &non_function);
+
+    // Goto slow case if we do not have a function.
+    __ CompareObjectType(r4, r7, r7, JS_FUNCTION_TYPE);
+    __ bne(&slow);
+  }
+
+  // Fast-case: Invoke the function now.
+  // r4: pushed function
+  ParameterCount actual(argc);
+
+  if (call_as_method) {
+    if (needs_checks) {
+      EmitContinueIfStrictOrNative(masm, &cont);
+    }
+
+    // Compute the receiver in sloppy mode.
+    __ LoadP(r6, MemOperand(sp, argc * kPointerSize), r0);
+
+    if (needs_checks) {
+      __ JumpIfSmi(r6, &wrap);
+      __ CompareObjectType(r6, r7, r7, FIRST_SPEC_OBJECT_TYPE);
+      __ blt(&wrap);
+    } else {
+      __ b(&wrap);
+    }
+
+    __ bind(&cont);
+  }
+
+  __ InvokeFunction(r4, actual, JUMP_FUNCTION, NullCallWrapper());
+
+  if (needs_checks) {
+    // Slow-case: Non-function called.
+    __ bind(&slow);
+    EmitSlowCase(masm, argc, &non_function);
+  }
+
+  if (call_as_method) {
+    __ bind(&wrap);
+    EmitWrapCase(masm, argc, &cont);
+  }
+}
+
+
+void CallFunctionStub::Generate(MacroAssembler* masm) {
+  CallFunctionNoFeedback(masm, argc(), NeedsChecks(), CallAsMethod());
+}
+
+
+void CallConstructStub::Generate(MacroAssembler* masm) {
+  // r3 : number of arguments
+  // r4 : the function to call
+  // r5 : feedback vector
+  // r6 : (only if r5 is not the megamorphic symbol) slot in feedback
+  //      vector (Smi)
+  Label slow, non_function_call;
+
+  // Check that the function is not a smi.
+  __ JumpIfSmi(r4, &non_function_call);
+  // Check that the function is a JSFunction.
+  __ CompareObjectType(r4, r7, r7, JS_FUNCTION_TYPE);
+  __ bne(&slow);
+
+  if (RecordCallTarget()) {
+    GenerateRecordCallTarget(masm);
+
+    __ SmiToPtrArrayOffset(r8, r6);
+    __ add(r8, r5, r8);
+    if (FLAG_pretenuring_call_new) {
+      // Put the AllocationSite from the feedback vector into r5.
+      // By adding kPointerSize we encode that we know the AllocationSite
+      // entry is at the feedback vector slot given by r6 + 1.
+      __ LoadP(r5, FieldMemOperand(r8, FixedArray::kHeaderSize + kPointerSize));
+    } else {
+      Label feedback_register_initialized;
+      // Put the AllocationSite from the feedback vector into r5, or undefined.
+      __ LoadP(r5, FieldMemOperand(r8, FixedArray::kHeaderSize));
+      __ LoadP(r8, FieldMemOperand(r5, AllocationSite::kMapOffset));
+      __ CompareRoot(r8, Heap::kAllocationSiteMapRootIndex);
+      __ beq(&feedback_register_initialized);
+      __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
+      __ bind(&feedback_register_initialized);
+    }
+
+    __ AssertUndefinedOrAllocationSite(r5, r8);
+  }
+
+  // Jump to the function-specific construct stub.
+  Register jmp_reg = r7;
+  __ LoadP(jmp_reg, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
+  __ LoadP(jmp_reg,
+           FieldMemOperand(jmp_reg, SharedFunctionInfo::kConstructStubOffset));
+  __ addi(ip, jmp_reg, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ JumpToJSEntry(ip);
+
+  // r3: number of arguments
+  // r4: called object
+  // r7: object type
+  Label do_call;
+  __ bind(&slow);
+  STATIC_ASSERT(JS_FUNCTION_PROXY_TYPE < 0xffffu);
+  __ cmpi(r7, Operand(JS_FUNCTION_PROXY_TYPE));
+  __ bne(&non_function_call);
+  __ GetBuiltinFunction(r4, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
+  __ b(&do_call);
+
+  __ bind(&non_function_call);
+  __ GetBuiltinFunction(r4, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
+  __ bind(&do_call);
+  // Set expected number of arguments to zero (not changing r3).
+  __ li(r5, Operand::Zero());
+  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+          RelocInfo::CODE_TARGET);
+}
+
+
+static void EmitLoadTypeFeedbackVector(MacroAssembler* masm, Register vector) {
+  __ LoadP(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ LoadP(vector,
+           FieldMemOperand(vector, JSFunction::kSharedFunctionInfoOffset));
+  __ LoadP(vector,
+           FieldMemOperand(vector, SharedFunctionInfo::kFeedbackVectorOffset));
+}
+
+
+void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
+  // r4 - function
+  // r6 - slot id
+  Label miss;
+  int argc = arg_count();
+  ParameterCount actual(argc);
+
+  EmitLoadTypeFeedbackVector(masm, r5);
+
+  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, r7);
+  __ cmp(r4, r7);
+  __ bne(&miss);
+
+  __ mov(r3, Operand(arg_count()));
+  __ SmiToPtrArrayOffset(r7, r6);
+  __ add(r7, r5, r7);
+  __ LoadP(r7, FieldMemOperand(r7, FixedArray::kHeaderSize));
+
+  // Verify that r7 contains an AllocationSite
+  __ LoadP(r8, FieldMemOperand(r7, HeapObject::kMapOffset));
+  __ CompareRoot(r8, Heap::kAllocationSiteMapRootIndex);
+  __ bne(&miss);
+
+  __ mr(r5, r7);
+  ArrayConstructorStub stub(masm->isolate(), arg_count());
+  __ TailCallStub(&stub);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+
+  // The slow case, we need this no matter what to complete a call after a miss.
+  CallFunctionNoFeedback(masm, arg_count(), true, CallAsMethod());
+
+  // Unreachable.
+  __ stop("Unexpected code address");
+}
+
+
+void CallICStub::Generate(MacroAssembler* masm) {
+  // r4 - function
+  // r6 - slot id (Smi)
+  Label extra_checks_or_miss, slow_start;
+  Label slow, non_function, wrap, cont;
+  Label have_js_function;
+  int argc = arg_count();
+  ParameterCount actual(argc);
+
+  EmitLoadTypeFeedbackVector(masm, r5);
+
+  // The checks. First, does r4 match the recorded monomorphic target?
+  __ SmiToPtrArrayOffset(r7, r6);
+  __ add(r7, r5, r7);
+  __ LoadP(r7, FieldMemOperand(r7, FixedArray::kHeaderSize));
+  __ cmp(r4, r7);
+  __ bne(&extra_checks_or_miss);
+
+  __ bind(&have_js_function);
+  if (CallAsMethod()) {
+    EmitContinueIfStrictOrNative(masm, &cont);
+    // Compute the receiver in sloppy mode.
+    __ LoadP(r6, MemOperand(sp, argc * kPointerSize), r0);
+
+    __ JumpIfSmi(r6, &wrap);
+    __ CompareObjectType(r6, r7, r7, FIRST_SPEC_OBJECT_TYPE);
+    __ blt(&wrap);
+
+    __ bind(&cont);
+  }
+
+  __ InvokeFunction(r4, actual, JUMP_FUNCTION, NullCallWrapper());
+
+  __ bind(&slow);
+  EmitSlowCase(masm, argc, &non_function);
+
+  if (CallAsMethod()) {
+    __ bind(&wrap);
+    EmitWrapCase(masm, argc, &cont);
+  }
+
+  __ bind(&extra_checks_or_miss);
+  Label miss;
+
+  __ CompareRoot(r7, Heap::kmegamorphic_symbolRootIndex);
+  __ beq(&slow_start);
+  __ CompareRoot(r7, Heap::kuninitialized_symbolRootIndex);
+  __ beq(&miss);
+
+  if (!FLAG_trace_ic) {
+    // We are going megamorphic. If the feedback is a JSFunction, it is fine
+    // to handle it here. More complex cases are dealt with in the runtime.
+    __ AssertNotSmi(r7);
+    __ CompareObjectType(r7, r8, r8, JS_FUNCTION_TYPE);
+    __ bne(&miss);
+    __ SmiToPtrArrayOffset(r7, r6);
+    __ add(r7, r5, r7);
+    __ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex);
+    __ StoreP(ip, FieldMemOperand(r7, FixedArray::kHeaderSize), r0);
+    // We have to update statistics for runtime profiling.
+    const int with_types_offset =
+        FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
+    __ LoadP(r7, FieldMemOperand(r5, with_types_offset));
+    __ SubSmiLiteral(r7, r7, Smi::FromInt(1), r0);
+    __ StoreP(r7, FieldMemOperand(r5, with_types_offset), r0);
+    const int generic_offset =
+        FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
+    __ LoadP(r7, FieldMemOperand(r5, generic_offset));
+    __ AddSmiLiteral(r7, r7, Smi::FromInt(1), r0);
+    __ StoreP(r7, FieldMemOperand(r5, generic_offset), r0);
+    __ jmp(&slow_start);
+  }
+
+  // We are here because tracing is on or we are going monomorphic.
+  __ bind(&miss);
+  GenerateMiss(masm);
+
+  // the slow case
+  __ bind(&slow_start);
+  // Check that the function is really a JavaScript function.
+  // r4: pushed function (to be verified)
+  __ JumpIfSmi(r4, &non_function);
+
+  // Goto slow case if we do not have a function.
+  __ CompareObjectType(r4, r7, r7, JS_FUNCTION_TYPE);
+  __ bne(&slow);
+  __ b(&have_js_function);
+}
+
+
+void CallICStub::GenerateMiss(MacroAssembler* masm) {
+  // Get the receiver of the function from the stack; 1 ~ return address.
+  __ LoadP(r7, MemOperand(sp, (arg_count() + 1) * kPointerSize), r0);
+
+  {
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+
+    // Push the receiver and the function and feedback info.
+    __ Push(r7, r4, r5, r6);
+
+    // Call the entry.
+    IC::UtilityId id = GetICState() == DEFAULT ? IC::kCallIC_Miss
+                                               : IC::kCallIC_Customization_Miss;
+
+    ExternalReference miss = ExternalReference(IC_Utility(id), masm->isolate());
+    __ CallExternalReference(miss, 4);
+
+    // Move result to r4 and exit the internal frame.
+    __ mr(r4, r3);
+  }
+}
+
+
+// StringCharCodeAtGenerator
+void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
+  // If the receiver is a smi trigger the non-string case.
+  if (check_mode_ == RECEIVER_IS_UNKNOWN) {
+    __ JumpIfSmi(object_, receiver_not_string_);
+
+    // Fetch the instance type of the receiver into result register.
+    __ LoadP(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
+    __ lbz(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
+    // If the receiver is not a string trigger the non-string case.
+    __ andi(r0, result_, Operand(kIsNotStringMask));
+    __ bne(receiver_not_string_, cr0);
+  }
+
+  // If the index is non-smi trigger the non-smi case.
+  __ JumpIfNotSmi(index_, &index_not_smi_);
+  __ bind(&got_smi_index_);
+
+  // Check for index out of range.
+  __ LoadP(ip, FieldMemOperand(object_, String::kLengthOffset));
+  __ cmpl(ip, index_);
+  __ ble(index_out_of_range_);
+
+  __ SmiUntag(index_);
+
+  StringCharLoadGenerator::Generate(masm, object_, index_, result_,
+                                    &call_runtime_);
+
+  __ SmiTag(result_);
+  __ bind(&exit_);
+}
+
+
+void StringCharCodeAtGenerator::GenerateSlow(
+    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
+  __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
+
+  // Index is not a smi.
+  __ bind(&index_not_smi_);
+  // If index is a heap number, try converting it to an integer.
+  __ CheckMap(index_, result_, Heap::kHeapNumberMapRootIndex, index_not_number_,
+              DONT_DO_SMI_CHECK);
+  call_helper.BeforeCall(masm);
+  __ push(object_);
+  __ push(index_);  // Consumed by runtime conversion function.
+  if (index_flags_ == STRING_INDEX_IS_NUMBER) {
+    __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
+  } else {
+    DCHECK(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
+    // NumberToSmi discards numbers that are not exact integers.
+    __ CallRuntime(Runtime::kNumberToSmi, 1);
+  }
+  // Save the conversion result before the pop instructions below
+  // have a chance to overwrite it.
+  __ Move(index_, r3);
+  __ pop(object_);
+  // Reload the instance type.
+  __ LoadP(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
+  __ lbz(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
+  call_helper.AfterCall(masm);
+  // If index is still not a smi, it must be out of range.
+  __ JumpIfNotSmi(index_, index_out_of_range_);
+  // Otherwise, return to the fast path.
+  __ b(&got_smi_index_);
+
+  // Call runtime. We get here when the receiver is a string and the
+  // index is a number, but the code of getting the actual character
+  // is too complex (e.g., when the string needs to be flattened).
+  __ bind(&call_runtime_);
+  call_helper.BeforeCall(masm);
+  __ SmiTag(index_);
+  __ Push(object_, index_);
+  __ CallRuntime(Runtime::kStringCharCodeAtRT, 2);
+  __ Move(result_, r3);
+  call_helper.AfterCall(masm);
+  __ b(&exit_);
+
+  __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
+}
+
+
+// -------------------------------------------------------------------------
+// StringCharFromCodeGenerator
+
+void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
+  // Fast case of Heap::LookupSingleCharacterStringFromCode.
+  DCHECK(base::bits::IsPowerOfTwo32(String::kMaxOneByteCharCode + 1));
+  __ LoadSmiLiteral(r0, Smi::FromInt(~String::kMaxOneByteCharCode));
+  __ ori(r0, r0, Operand(kSmiTagMask));
+  __ and_(r0, code_, r0);
+  __ cmpi(r0, Operand::Zero());
+  __ bne(&slow_case_);
+
+  __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
+  // At this point code register contains smi tagged one-byte char code.
+  __ mr(r0, code_);
+  __ SmiToPtrArrayOffset(code_, code_);
+  __ add(result_, result_, code_);
+  __ mr(code_, r0);
+  __ LoadP(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
+  __ CompareRoot(result_, Heap::kUndefinedValueRootIndex);
+  __ beq(&slow_case_);
+  __ bind(&exit_);
+}
+
+
+void StringCharFromCodeGenerator::GenerateSlow(
+    MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
+  __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
+
+  __ bind(&slow_case_);
+  call_helper.BeforeCall(masm);
+  __ push(code_);
+  __ CallRuntime(Runtime::kCharFromCode, 1);
+  __ Move(result_, r3);
+  call_helper.AfterCall(masm);
+  __ b(&exit_);
+
+  __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
+}
+
+
+enum CopyCharactersFlags { COPY_ONE_BYTE = 1, DEST_ALWAYS_ALIGNED = 2 };
+
+
+void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, Register dest,
+                                          Register src, Register count,
+                                          Register scratch,
+                                          String::Encoding encoding) {
+  if (FLAG_debug_code) {
+    // Check that destination is word aligned.
+    __ andi(r0, dest, Operand(kPointerAlignmentMask));
+    __ Check(eq, kDestinationOfCopyNotAligned, cr0);
+  }
+
+  // Nothing to do for zero characters.
+  Label done;
+  if (encoding == String::TWO_BYTE_ENCODING) {
+    // double the length
+    __ add(count, count, count, LeaveOE, SetRC);
+    __ beq(&done, cr0);
+  } else {
+    __ cmpi(count, Operand::Zero());
+    __ beq(&done);
+  }
+
+  // Copy count bytes from src to dst.
+  Label byte_loop;
+  __ mtctr(count);
+  __ bind(&byte_loop);
+  __ lbz(scratch, MemOperand(src));
+  __ addi(src, src, Operand(1));
+  __ stb(scratch, MemOperand(dest));
+  __ addi(dest, dest, Operand(1));
+  __ bdnz(&byte_loop);
+
+  __ bind(&done);
+}
+
+
+void SubStringStub::Generate(MacroAssembler* masm) {
+  Label runtime;
+
+  // Stack frame on entry.
+  //  lr: return address
+  //  sp[0]: to
+  //  sp[4]: from
+  //  sp[8]: string
+
+  // This stub is called from the native-call %_SubString(...), so
+  // nothing can be assumed about the arguments. It is tested that:
+  //  "string" is a sequential string,
+  //  both "from" and "to" are smis, and
+  //  0 <= from <= to <= string.length.
+  // If any of these assumptions fail, we call the runtime system.
+
+  const int kToOffset = 0 * kPointerSize;
+  const int kFromOffset = 1 * kPointerSize;
+  const int kStringOffset = 2 * kPointerSize;
+
+  __ LoadP(r5, MemOperand(sp, kToOffset));
+  __ LoadP(r6, MemOperand(sp, kFromOffset));
+
+  // If either to or from had the smi tag bit set, then fail to generic runtime
+  __ JumpIfNotSmi(r5, &runtime);
+  __ JumpIfNotSmi(r6, &runtime);
+  __ SmiUntag(r5);
+  __ SmiUntag(r6, SetRC);
+  // Both r5 and r6 are untagged integers.
+
+  // We want to bailout to runtime here if From is negative.
+  __ blt(&runtime, cr0);  // From < 0.
+
+  __ cmpl(r6, r5);
+  __ bgt(&runtime);  // Fail if from > to.
+  __ sub(r5, r5, r6);
+
+  // Make sure first argument is a string.
+  __ LoadP(r3, MemOperand(sp, kStringOffset));
+  __ JumpIfSmi(r3, &runtime);
+  Condition is_string = masm->IsObjectStringType(r3, r4);
+  __ b(NegateCondition(is_string), &runtime, cr0);
+
+  Label single_char;
+  __ cmpi(r5, Operand(1));
+  __ b(eq, &single_char);
+
+  // Short-cut for the case of trivial substring.
+  Label return_r3;
+  // r3: original string
+  // r5: result string length
+  __ LoadP(r7, FieldMemOperand(r3, String::kLengthOffset));
+  __ SmiUntag(r0, r7);
+  __ cmpl(r5, r0);
+  // Return original string.
+  __ beq(&return_r3);
+  // Longer than original string's length or negative: unsafe arguments.
+  __ bgt(&runtime);
+  // Shorter than original string's length: an actual substring.
+
+  // Deal with different string types: update the index if necessary
+  // and put the underlying string into r8.
+  // r3: original string
+  // r4: instance type
+  // r5: length
+  // r6: from index (untagged)
+  Label underlying_unpacked, sliced_string, seq_or_external_string;
+  // If the string is not indirect, it can only be sequential or external.
+  STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
+  STATIC_ASSERT(kIsIndirectStringMask != 0);
+  __ andi(r0, r4, Operand(kIsIndirectStringMask));
+  __ beq(&seq_or_external_string, cr0);
+
+  __ andi(r0, r4, Operand(kSlicedNotConsMask));
+  __ bne(&sliced_string, cr0);
+  // Cons string.  Check whether it is flat, then fetch first part.
+  __ LoadP(r8, FieldMemOperand(r3, ConsString::kSecondOffset));
+  __ CompareRoot(r8, Heap::kempty_stringRootIndex);
+  __ bne(&runtime);
+  __ LoadP(r8, FieldMemOperand(r3, ConsString::kFirstOffset));
+  // Update instance type.
+  __ LoadP(r4, FieldMemOperand(r8, HeapObject::kMapOffset));
+  __ lbz(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
+  __ b(&underlying_unpacked);
+
+  __ bind(&sliced_string);
+  // Sliced string.  Fetch parent and correct start index by offset.
+  __ LoadP(r8, FieldMemOperand(r3, SlicedString::kParentOffset));
+  __ LoadP(r7, FieldMemOperand(r3, SlicedString::kOffsetOffset));
+  __ SmiUntag(r4, r7);
+  __ add(r6, r6, r4);  // Add offset to index.
+  // Update instance type.
+  __ LoadP(r4, FieldMemOperand(r8, HeapObject::kMapOffset));
+  __ lbz(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
+  __ b(&underlying_unpacked);
+
+  __ bind(&seq_or_external_string);
+  // Sequential or external string.  Just move string to the expected register.
+  __ mr(r8, r3);
+
+  __ bind(&underlying_unpacked);
+
+  if (FLAG_string_slices) {
+    Label copy_routine;
+    // r8: underlying subject string
+    // r4: instance type of underlying subject string
+    // r5: length
+    // r6: adjusted start index (untagged)
+    __ cmpi(r5, Operand(SlicedString::kMinLength));
+    // Short slice.  Copy instead of slicing.
+    __ blt(&copy_routine);
+    // Allocate new sliced string.  At this point we do not reload the instance
+    // type including the string encoding because we simply rely on the info
+    // provided by the original string.  It does not matter if the original
+    // string's encoding is wrong because we always have to recheck encoding of
+    // the newly created string's parent anyways due to externalized strings.
+    Label two_byte_slice, set_slice_header;
+    STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
+    STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+    __ andi(r0, r4, Operand(kStringEncodingMask));
+    __ beq(&two_byte_slice, cr0);
+    __ AllocateOneByteSlicedString(r3, r5, r9, r10, &runtime);
+    __ b(&set_slice_header);
+    __ bind(&two_byte_slice);
+    __ AllocateTwoByteSlicedString(r3, r5, r9, r10, &runtime);
+    __ bind(&set_slice_header);
+    __ SmiTag(r6);
+    __ StoreP(r8, FieldMemOperand(r3, SlicedString::kParentOffset), r0);
+    __ StoreP(r6, FieldMemOperand(r3, SlicedString::kOffsetOffset), r0);
+    __ b(&return_r3);
+
+    __ bind(&copy_routine);
+  }
+
+  // r8: underlying subject string
+  // r4: instance type of underlying subject string
+  // r5: length
+  // r6: adjusted start index (untagged)
+  Label two_byte_sequential, sequential_string, allocate_result;
+  STATIC_ASSERT(kExternalStringTag != 0);
+  STATIC_ASSERT(kSeqStringTag == 0);
+  __ andi(r0, r4, Operand(kExternalStringTag));
+  __ beq(&sequential_string, cr0);
+
+  // Handle external string.
+  // Rule out short external strings.
+  STATIC_ASSERT(kShortExternalStringTag != 0);
+  __ andi(r0, r4, Operand(kShortExternalStringTag));
+  __ bne(&runtime, cr0);
+  __ LoadP(r8, FieldMemOperand(r8, ExternalString::kResourceDataOffset));
+  // r8 already points to the first character of underlying string.
+  __ b(&allocate_result);
+
+  __ bind(&sequential_string);
+  // Locate first character of underlying subject string.
+  STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
+  __ addi(r8, r8, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
+
+  __ bind(&allocate_result);
+  // Sequential acii string.  Allocate the result.
+  STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0);
+  __ andi(r0, r4, Operand(kStringEncodingMask));
+  __ beq(&two_byte_sequential, cr0);
+
+  // Allocate and copy the resulting one-byte string.
+  __ AllocateOneByteString(r3, r5, r7, r9, r10, &runtime);
+
+  // Locate first character of substring to copy.
+  __ add(r8, r8, r6);
+  // Locate first character of result.
+  __ addi(r4, r3, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
+
+  // r3: result string
+  // r4: first character of result string
+  // r5: result string length
+  // r8: first character of substring to copy
+  STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
+  StringHelper::GenerateCopyCharacters(masm, r4, r8, r5, r6,
+                                       String::ONE_BYTE_ENCODING);
+  __ b(&return_r3);
+
+  // Allocate and copy the resulting two-byte string.
+  __ bind(&two_byte_sequential);
+  __ AllocateTwoByteString(r3, r5, r7, r9, r10, &runtime);
+
+  // Locate first character of substring to copy.
+  __ ShiftLeftImm(r4, r6, Operand(1));
+  __ add(r8, r8, r4);
+  // Locate first character of result.
+  __ addi(r4, r3, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
+
+  // r3: result string.
+  // r4: first character of result.
+  // r5: result length.
+  // r8: first character of substring to copy.
+  STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
+  StringHelper::GenerateCopyCharacters(masm, r4, r8, r5, r6,
+                                       String::TWO_BYTE_ENCODING);
+
+  __ bind(&return_r3);
+  Counters* counters = isolate()->counters();
+  __ IncrementCounter(counters->sub_string_native(), 1, r6, r7);
+  __ Drop(3);
+  __ Ret();
+
+  // Just jump to runtime to create the sub string.
+  __ bind(&runtime);
+  __ TailCallRuntime(Runtime::kSubString, 3, 1);
+
+  __ bind(&single_char);
+  // r3: original string
+  // r4: instance type
+  // r5: length
+  // r6: from index (untagged)
+  __ SmiTag(r6, r6);
+  StringCharAtGenerator generator(r3, r6, r5, r3, &runtime, &runtime, &runtime,
+                                  STRING_INDEX_IS_NUMBER, RECEIVER_IS_STRING);
+  generator.GenerateFast(masm);
+  __ Drop(3);
+  __ Ret();
+  generator.SkipSlow(masm, &runtime);
+}
+
+
+void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm,
+                                                   Register left,
+                                                   Register right,
+                                                   Register scratch1,
+                                                   Register scratch2) {
+  Register length = scratch1;
+
+  // Compare lengths.
+  Label strings_not_equal, check_zero_length;
+  __ LoadP(length, FieldMemOperand(left, String::kLengthOffset));
+  __ LoadP(scratch2, FieldMemOperand(right, String::kLengthOffset));
+  __ cmp(length, scratch2);
+  __ beq(&check_zero_length);
+  __ bind(&strings_not_equal);
+  __ LoadSmiLiteral(r3, Smi::FromInt(NOT_EQUAL));
+  __ Ret();
+
+  // Check if the length is zero.
+  Label compare_chars;
+  __ bind(&check_zero_length);
+  STATIC_ASSERT(kSmiTag == 0);
+  __ cmpi(length, Operand::Zero());
+  __ bne(&compare_chars);
+  __ LoadSmiLiteral(r3, Smi::FromInt(EQUAL));
+  __ Ret();
+
+  // Compare characters.
+  __ bind(&compare_chars);
+  GenerateOneByteCharsCompareLoop(masm, left, right, length, scratch2,
+                                  &strings_not_equal);
+
+  // Characters are equal.
+  __ LoadSmiLiteral(r3, Smi::FromInt(EQUAL));
+  __ Ret();
+}
+
+
+void StringHelper::GenerateCompareFlatOneByteStrings(
+    MacroAssembler* masm, Register left, Register right, Register scratch1,
+    Register scratch2, Register scratch3) {
+  Label skip, result_not_equal, compare_lengths;
+  // Find minimum length and length difference.
+  __ LoadP(scratch1, FieldMemOperand(left, String::kLengthOffset));
+  __ LoadP(scratch2, FieldMemOperand(right, String::kLengthOffset));
+  __ sub(scratch3, scratch1, scratch2, LeaveOE, SetRC);
+  Register length_delta = scratch3;
+  __ ble(&skip, cr0);
+  __ mr(scratch1, scratch2);
+  __ bind(&skip);
+  Register min_length = scratch1;
+  STATIC_ASSERT(kSmiTag == 0);
+  __ cmpi(min_length, Operand::Zero());
+  __ beq(&compare_lengths);
+
+  // Compare loop.
+  GenerateOneByteCharsCompareLoop(masm, left, right, min_length, scratch2,
+                                  &result_not_equal);
+
+  // Compare lengths - strings up to min-length are equal.
+  __ bind(&compare_lengths);
+  DCHECK(Smi::FromInt(EQUAL) == static_cast<Smi*>(0));
+  // Use length_delta as result if it's zero.
+  __ mr(r3, length_delta);
+  __ cmpi(r3, Operand::Zero());
+  __ bind(&result_not_equal);
+  // Conditionally update the result based either on length_delta or
+  // the last comparion performed in the loop above.
+  Label less_equal, equal;
+  __ ble(&less_equal);
+  __ LoadSmiLiteral(r3, Smi::FromInt(GREATER));
+  __ Ret();
+  __ bind(&less_equal);
+  __ beq(&equal);
+  __ LoadSmiLiteral(r3, Smi::FromInt(LESS));
+  __ bind(&equal);
+  __ Ret();
+}
+
+
+void StringHelper::GenerateOneByteCharsCompareLoop(
+    MacroAssembler* masm, Register left, Register right, Register length,
+    Register scratch1, Label* chars_not_equal) {
+  // Change index to run from -length to -1 by adding length to string
+  // start. This means that loop ends when index reaches zero, which
+  // doesn't need an additional compare.
+  __ SmiUntag(length);
+  __ addi(scratch1, length,
+          Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
+  __ add(left, left, scratch1);
+  __ add(right, right, scratch1);
+  __ subfic(length, length, Operand::Zero());
+  Register index = length;  // index = -length;
+
+  // Compare loop.
+  Label loop;
+  __ bind(&loop);
+  __ lbzx(scratch1, MemOperand(left, index));
+  __ lbzx(r0, MemOperand(right, index));
+  __ cmp(scratch1, r0);
+  __ bne(chars_not_equal);
+  __ addi(index, index, Operand(1));
+  __ cmpi(index, Operand::Zero());
+  __ bne(&loop);
+}
+
+
+void StringCompareStub::Generate(MacroAssembler* masm) {
+  Label runtime;
+
+  Counters* counters = isolate()->counters();
+
+  // Stack frame on entry.
+  //  sp[0]: right string
+  //  sp[4]: left string
+  __ LoadP(r3, MemOperand(sp));  // Load right in r3, left in r4.
+  __ LoadP(r4, MemOperand(sp, kPointerSize));
+
+  Label not_same;
+  __ cmp(r3, r4);
+  __ bne(&not_same);
+  STATIC_ASSERT(EQUAL == 0);
+  STATIC_ASSERT(kSmiTag == 0);
+  __ LoadSmiLiteral(r3, Smi::FromInt(EQUAL));
+  __ IncrementCounter(counters->string_compare_native(), 1, r4, r5);
+  __ addi(sp, sp, Operand(2 * kPointerSize));
+  __ Ret();
+
+  __ bind(&not_same);
+
+  // Check that both objects are sequential one-byte strings.
+  __ JumpIfNotBothSequentialOneByteStrings(r4, r3, r5, r6, &runtime);
+
+  // Compare flat one-byte strings natively. Remove arguments from stack first.
+  __ IncrementCounter(counters->string_compare_native(), 1, r5, r6);
+  __ addi(sp, sp, Operand(2 * kPointerSize));
+  StringHelper::GenerateCompareFlatOneByteStrings(masm, r4, r3, r5, r6, r7);
+
+  // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
+  // tagged as a small integer.
+  __ bind(&runtime);
+  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+}
+
+
+void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r4    : left
+  //  -- r3    : right
+  //  -- lr    : return address
+  // -----------------------------------
+
+  // Load r5 with the allocation site.  We stick an undefined dummy value here
+  // and replace it with the real allocation site later when we instantiate this
+  // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
+  __ Move(r5, handle(isolate()->heap()->undefined_value()));
+
+  // Make sure that we actually patched the allocation site.
+  if (FLAG_debug_code) {
+    __ TestIfSmi(r5, r0);
+    __ Assert(ne, kExpectedAllocationSite, cr0);
+    __ push(r5);
+    __ LoadP(r5, FieldMemOperand(r5, HeapObject::kMapOffset));
+    __ LoadRoot(ip, Heap::kAllocationSiteMapRootIndex);
+    __ cmp(r5, ip);
+    __ pop(r5);
+    __ Assert(eq, kExpectedAllocationSite);
+  }
+
+  // Tail call into the stub that handles binary operations with allocation
+  // sites.
+  BinaryOpWithAllocationSiteStub stub(isolate(), state());
+  __ TailCallStub(&stub);
+}
+
+
+void CompareICStub::GenerateSmis(MacroAssembler* masm) {
+  DCHECK(state() == CompareICState::SMI);
+  Label miss;
+  __ orx(r5, r4, r3);
+  __ JumpIfNotSmi(r5, &miss);
+
+  if (GetCondition() == eq) {
+    // For equality we do not care about the sign of the result.
+    // __ sub(r3, r3, r4, SetCC);
+    __ sub(r3, r3, r4);
+  } else {
+    // Untag before subtracting to avoid handling overflow.
+    __ SmiUntag(r4);
+    __ SmiUntag(r3);
+    __ sub(r3, r4, r3);
+  }
+  __ Ret();
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
+  DCHECK(state() == CompareICState::NUMBER);
+
+  Label generic_stub;
+  Label unordered, maybe_undefined1, maybe_undefined2;
+  Label miss;
+  Label equal, less_than;
+
+  if (left() == CompareICState::SMI) {
+    __ JumpIfNotSmi(r4, &miss);
+  }
+  if (right() == CompareICState::SMI) {
+    __ JumpIfNotSmi(r3, &miss);
+  }
+
+  // Inlining the double comparison and falling back to the general compare
+  // stub if NaN is involved.
+  // Load left and right operand.
+  Label done, left, left_smi, right_smi;
+  __ JumpIfSmi(r3, &right_smi);
+  __ CheckMap(r3, r5, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
+              DONT_DO_SMI_CHECK);
+  __ lfd(d1, FieldMemOperand(r3, HeapNumber::kValueOffset));
+  __ b(&left);
+  __ bind(&right_smi);
+  __ SmiToDouble(d1, r3);
+
+  __ bind(&left);
+  __ JumpIfSmi(r4, &left_smi);
+  __ CheckMap(r4, r5, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
+              DONT_DO_SMI_CHECK);
+  __ lfd(d0, FieldMemOperand(r4, HeapNumber::kValueOffset));
+  __ b(&done);
+  __ bind(&left_smi);
+  __ SmiToDouble(d0, r4);
+
+  __ bind(&done);
+
+  // Compare operands
+  __ fcmpu(d0, d1);
+
+  // Don't base result on status bits when a NaN is involved.
+  __ bunordered(&unordered);
+
+  // Return a result of -1, 0, or 1, based on status bits.
+  __ beq(&equal);
+  __ blt(&less_than);
+  //  assume greater than
+  __ li(r3, Operand(GREATER));
+  __ Ret();
+  __ bind(&equal);
+  __ li(r3, Operand(EQUAL));
+  __ Ret();
+  __ bind(&less_than);
+  __ li(r3, Operand(LESS));
+  __ Ret();
+
+  __ bind(&unordered);
+  __ bind(&generic_stub);
+  CompareICStub stub(isolate(), op(), CompareICState::GENERIC,
+                     CompareICState::GENERIC, CompareICState::GENERIC);
+  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+
+  __ bind(&maybe_undefined1);
+  if (Token::IsOrderedRelationalCompareOp(op())) {
+    __ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
+    __ bne(&miss);
+    __ JumpIfSmi(r4, &unordered);
+    __ CompareObjectType(r4, r5, r5, HEAP_NUMBER_TYPE);
+    __ bne(&maybe_undefined2);
+    __ b(&unordered);
+  }
+
+  __ bind(&maybe_undefined2);
+  if (Token::IsOrderedRelationalCompareOp(op())) {
+    __ CompareRoot(r4, Heap::kUndefinedValueRootIndex);
+    __ beq(&unordered);
+  }
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void CompareICStub::GenerateInternalizedStrings(MacroAssembler* masm) {
+  DCHECK(state() == CompareICState::INTERNALIZED_STRING);
+  Label miss, not_equal;
+
+  // Registers containing left and right operands respectively.
+  Register left = r4;
+  Register right = r3;
+  Register tmp1 = r5;
+  Register tmp2 = r6;
+
+  // Check that both operands are heap objects.
+  __ JumpIfEitherSmi(left, right, &miss);
+
+  // Check that both operands are symbols.
+  __ LoadP(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
+  __ LoadP(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
+  __ lbz(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
+  __ lbz(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
+  STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
+  __ orx(tmp1, tmp1, tmp2);
+  __ andi(r0, tmp1, Operand(kIsNotStringMask | kIsNotInternalizedMask));
+  __ bne(&miss, cr0);
+
+  // Internalized strings are compared by identity.
+  __ cmp(left, right);
+  __ bne(&not_equal);
+  // Make sure r3 is non-zero. At this point input operands are
+  // guaranteed to be non-zero.
+  DCHECK(right.is(r3));
+  STATIC_ASSERT(EQUAL == 0);
+  STATIC_ASSERT(kSmiTag == 0);
+  __ LoadSmiLiteral(r3, Smi::FromInt(EQUAL));
+  __ bind(&not_equal);
+  __ Ret();
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void CompareICStub::GenerateUniqueNames(MacroAssembler* masm) {
+  DCHECK(state() == CompareICState::UNIQUE_NAME);
+  DCHECK(GetCondition() == eq);
+  Label miss;
+
+  // Registers containing left and right operands respectively.
+  Register left = r4;
+  Register right = r3;
+  Register tmp1 = r5;
+  Register tmp2 = r6;
+
+  // Check that both operands are heap objects.
+  __ JumpIfEitherSmi(left, right, &miss);
+
+  // Check that both operands are unique names. This leaves the instance
+  // types loaded in tmp1 and tmp2.
+  __ LoadP(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
+  __ LoadP(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
+  __ lbz(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
+  __ lbz(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
+
+  __ JumpIfNotUniqueNameInstanceType(tmp1, &miss);
+  __ JumpIfNotUniqueNameInstanceType(tmp2, &miss);
+
+  // Unique names are compared by identity.
+  __ cmp(left, right);
+  __ bne(&miss);
+  // Make sure r3 is non-zero. At this point input operands are
+  // guaranteed to be non-zero.
+  DCHECK(right.is(r3));
+  STATIC_ASSERT(EQUAL == 0);
+  STATIC_ASSERT(kSmiTag == 0);
+  __ LoadSmiLiteral(r3, Smi::FromInt(EQUAL));
+  __ Ret();
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void CompareICStub::GenerateStrings(MacroAssembler* masm) {
+  DCHECK(state() == CompareICState::STRING);
+  Label miss, not_identical, is_symbol;
+
+  bool equality = Token::IsEqualityOp(op());
+
+  // Registers containing left and right operands respectively.
+  Register left = r4;
+  Register right = r3;
+  Register tmp1 = r5;
+  Register tmp2 = r6;
+  Register tmp3 = r7;
+  Register tmp4 = r8;
+
+  // Check that both operands are heap objects.
+  __ JumpIfEitherSmi(left, right, &miss);
+
+  // Check that both operands are strings. This leaves the instance
+  // types loaded in tmp1 and tmp2.
+  __ LoadP(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
+  __ LoadP(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
+  __ lbz(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
+  __ lbz(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
+  STATIC_ASSERT(kNotStringTag != 0);
+  __ orx(tmp3, tmp1, tmp2);
+  __ andi(r0, tmp3, Operand(kIsNotStringMask));
+  __ bne(&miss, cr0);
+
+  // Fast check for identical strings.
+  __ cmp(left, right);
+  STATIC_ASSERT(EQUAL == 0);
+  STATIC_ASSERT(kSmiTag == 0);
+  __ bne(&not_identical);
+  __ LoadSmiLiteral(r3, Smi::FromInt(EQUAL));
+  __ Ret();
+  __ bind(&not_identical);
+
+  // Handle not identical strings.
+
+  // Check that both strings are internalized strings. If they are, we're done
+  // because we already know they are not identical. We know they are both
+  // strings.
+  if (equality) {
+    DCHECK(GetCondition() == eq);
+    STATIC_ASSERT(kInternalizedTag == 0);
+    __ orx(tmp3, tmp1, tmp2);
+    __ andi(r0, tmp3, Operand(kIsNotInternalizedMask));
+    __ bne(&is_symbol, cr0);
+    // Make sure r3 is non-zero. At this point input operands are
+    // guaranteed to be non-zero.
+    DCHECK(right.is(r3));
+    __ Ret();
+    __ bind(&is_symbol);
+  }
+
+  // Check that both strings are sequential one-byte.
+  Label runtime;
+  __ JumpIfBothInstanceTypesAreNotSequentialOneByte(tmp1, tmp2, tmp3, tmp4,
+                                                    &runtime);
+
+  // Compare flat one-byte strings. Returns when done.
+  if (equality) {
+    StringHelper::GenerateFlatOneByteStringEquals(masm, left, right, tmp1,
+                                                  tmp2);
+  } else {
+    StringHelper::GenerateCompareFlatOneByteStrings(masm, left, right, tmp1,
+                                                    tmp2, tmp3);
+  }
+
+  // Handle more complex cases in runtime.
+  __ bind(&runtime);
+  __ Push(left, right);
+  if (equality) {
+    __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
+  } else {
+    __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+  }
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void CompareICStub::GenerateObjects(MacroAssembler* masm) {
+  DCHECK(state() == CompareICState::OBJECT);
+  Label miss;
+  __ and_(r5, r4, r3);
+  __ JumpIfSmi(r5, &miss);
+
+  __ CompareObjectType(r3, r5, r5, JS_OBJECT_TYPE);
+  __ bne(&miss);
+  __ CompareObjectType(r4, r5, r5, JS_OBJECT_TYPE);
+  __ bne(&miss);
+
+  DCHECK(GetCondition() == eq);
+  __ sub(r3, r3, r4);
+  __ Ret();
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void CompareICStub::GenerateKnownObjects(MacroAssembler* masm) {
+  Label miss;
+  __ and_(r5, r4, r3);
+  __ JumpIfSmi(r5, &miss);
+  __ LoadP(r5, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ LoadP(r6, FieldMemOperand(r4, HeapObject::kMapOffset));
+  __ Cmpi(r5, Operand(known_map_), r0);
+  __ bne(&miss);
+  __ Cmpi(r6, Operand(known_map_), r0);
+  __ bne(&miss);
+
+  __ sub(r3, r3, r4);
+  __ Ret();
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void CompareICStub::GenerateMiss(MacroAssembler* masm) {
+  {
+    // Call the runtime system in a fresh internal frame.
+    ExternalReference miss =
+        ExternalReference(IC_Utility(IC::kCompareIC_Miss), isolate());
+
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+    __ Push(r4, r3);
+    __ Push(r4, r3);
+    __ LoadSmiLiteral(r0, Smi::FromInt(op()));
+    __ push(r0);
+    __ CallExternalReference(miss, 3);
+    // Compute the entry point of the rewritten stub.
+    __ addi(r5, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
+    // Restore registers.
+    __ Pop(r4, r3);
+  }
+
+  __ JumpToJSEntry(r5);
+}
+
+
+// This stub is paired with DirectCEntryStub::GenerateCall
+void DirectCEntryStub::Generate(MacroAssembler* masm) {
+  // Place the return address on the stack, making the call
+  // GC safe. The RegExp backend also relies on this.
+  __ mflr(r0);
+  __ StoreP(r0, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize));
+  __ Call(ip);  // Call the C++ function.
+  __ LoadP(r0, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize));
+  __ mtlr(r0);
+  __ blr();
+}
+
+
+void DirectCEntryStub::GenerateCall(MacroAssembler* masm, Register target) {
+#if ABI_USES_FUNCTION_DESCRIPTORS && !defined(USE_SIMULATOR)
+  // Native AIX/PPC64 Linux use a function descriptor.
+  __ LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(target, kPointerSize));
+  __ LoadP(ip, MemOperand(target, 0));  // Instruction address
+#else
+  // ip needs to be set for DirectCEentryStub::Generate, and also
+  // for ABI_TOC_ADDRESSABILITY_VIA_IP.
+  __ Move(ip, target);
+#endif
+
+  intptr_t code = reinterpret_cast<intptr_t>(GetCode().location());
+  __ mov(r0, Operand(code, RelocInfo::CODE_TARGET));
+  __ Call(r0);  // Call the stub.
+}
+
+
+void NameDictionaryLookupStub::GenerateNegativeLookup(
+    MacroAssembler* masm, Label* miss, Label* done, Register receiver,
+    Register properties, Handle<Name> name, Register scratch0) {
+  DCHECK(name->IsUniqueName());
+  // If names of slots in range from 1 to kProbes - 1 for the hash value are
+  // not equal to the name and kProbes-th slot is not used (its name is the
+  // undefined value), it guarantees the hash table doesn't contain the
+  // property. It's true even if some slots represent deleted properties
+  // (their names are the hole value).
+  for (int i = 0; i < kInlinedProbes; i++) {
+    // scratch0 points to properties hash.
+    // Compute the masked index: (hash + i + i * i) & mask.
+    Register index = scratch0;
+    // Capacity is smi 2^n.
+    __ LoadP(index, FieldMemOperand(properties, kCapacityOffset));
+    __ subi(index, index, Operand(1));
+    __ LoadSmiLiteral(
+        ip, Smi::FromInt(name->Hash() + NameDictionary::GetProbeOffset(i)));
+    __ and_(index, index, ip);
+
+    // Scale the index by multiplying by the entry size.
+    DCHECK(NameDictionary::kEntrySize == 3);
+    __ ShiftLeftImm(ip, index, Operand(1));
+    __ add(index, index, ip);  // index *= 3.
+
+    Register entity_name = scratch0;
+    // Having undefined at this place means the name is not contained.
+    Register tmp = properties;
+    __ SmiToPtrArrayOffset(ip, index);
+    __ add(tmp, properties, ip);
+    __ LoadP(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
+
+    DCHECK(!tmp.is(entity_name));
+    __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex);
+    __ cmp(entity_name, tmp);
+    __ beq(done);
+
+    // Load the hole ready for use below:
+    __ LoadRoot(tmp, Heap::kTheHoleValueRootIndex);
+
+    // Stop if found the property.
+    __ Cmpi(entity_name, Operand(Handle<Name>(name)), r0);
+    __ beq(miss);
+
+    Label good;
+    __ cmp(entity_name, tmp);
+    __ beq(&good);
+
+    // Check if the entry name is not a unique name.
+    __ LoadP(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
+    __ lbz(entity_name, FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
+    __ JumpIfNotUniqueNameInstanceType(entity_name, miss);
+    __ bind(&good);
+
+    // Restore the properties.
+    __ LoadP(properties,
+             FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+  }
+
+  const int spill_mask = (r0.bit() | r9.bit() | r8.bit() | r7.bit() | r6.bit() |
+                          r5.bit() | r4.bit() | r3.bit());
+
+  __ mflr(r0);
+  __ MultiPush(spill_mask);
+
+  __ LoadP(r3, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+  __ mov(r4, Operand(Handle<Name>(name)));
+  NameDictionaryLookupStub stub(masm->isolate(), NEGATIVE_LOOKUP);
+  __ CallStub(&stub);
+  __ cmpi(r3, Operand::Zero());
+
+  __ MultiPop(spill_mask);  // MultiPop does not touch condition flags
+  __ mtlr(r0);
+
+  __ beq(done);
+  __ bne(miss);
+}
+
+
+// Probe the name dictionary in the |elements| register. Jump to the
+// |done| label if a property with the given name is found. Jump to
+// the |miss| label otherwise.
+// If lookup was successful |scratch2| will be equal to elements + 4 * index.
+void NameDictionaryLookupStub::GeneratePositiveLookup(
+    MacroAssembler* masm, Label* miss, Label* done, Register elements,
+    Register name, Register scratch1, Register scratch2) {
+  DCHECK(!elements.is(scratch1));
+  DCHECK(!elements.is(scratch2));
+  DCHECK(!name.is(scratch1));
+  DCHECK(!name.is(scratch2));
+
+  __ AssertName(name);
+
+  // Compute the capacity mask.
+  __ LoadP(scratch1, FieldMemOperand(elements, kCapacityOffset));
+  __ SmiUntag(scratch1);  // convert smi to int
+  __ subi(scratch1, scratch1, Operand(1));
+
+  // Generate an unrolled loop that performs a few probes before
+  // giving up. Measurements done on Gmail indicate that 2 probes
+  // cover ~93% of loads from dictionaries.
+  for (int i = 0; i < kInlinedProbes; i++) {
+    // Compute the masked index: (hash + i + i * i) & mask.
+    __ lwz(scratch2, FieldMemOperand(name, Name::kHashFieldOffset));
+    if (i > 0) {
+      // Add the probe offset (i + i * i) left shifted to avoid right shifting
+      // the hash in a separate instruction. The value hash + i + i * i is right
+      // shifted in the following and instruction.
+      DCHECK(NameDictionary::GetProbeOffset(i) <
+             1 << (32 - Name::kHashFieldOffset));
+      __ addi(scratch2, scratch2,
+              Operand(NameDictionary::GetProbeOffset(i) << Name::kHashShift));
+    }
+    __ srwi(scratch2, scratch2, Operand(Name::kHashShift));
+    __ and_(scratch2, scratch1, scratch2);
+
+    // Scale the index by multiplying by the element size.
+    DCHECK(NameDictionary::kEntrySize == 3);
+    // scratch2 = scratch2 * 3.
+    __ ShiftLeftImm(ip, scratch2, Operand(1));
+    __ add(scratch2, scratch2, ip);
+
+    // Check if the key is identical to the name.
+    __ ShiftLeftImm(ip, scratch2, Operand(kPointerSizeLog2));
+    __ add(scratch2, elements, ip);
+    __ LoadP(ip, FieldMemOperand(scratch2, kElementsStartOffset));
+    __ cmp(name, ip);
+    __ beq(done);
+  }
+
+  const int spill_mask = (r0.bit() | r9.bit() | r8.bit() | r7.bit() | r6.bit() |
+                          r5.bit() | r4.bit() | r3.bit()) &
+                         ~(scratch1.bit() | scratch2.bit());
+
+  __ mflr(r0);
+  __ MultiPush(spill_mask);
+  if (name.is(r3)) {
+    DCHECK(!elements.is(r4));
+    __ mr(r4, name);
+    __ mr(r3, elements);
+  } else {
+    __ mr(r3, elements);
+    __ mr(r4, name);
+  }
+  NameDictionaryLookupStub stub(masm->isolate(), POSITIVE_LOOKUP);
+  __ CallStub(&stub);
+  __ cmpi(r3, Operand::Zero());
+  __ mr(scratch2, r5);
+  __ MultiPop(spill_mask);
+  __ mtlr(r0);
+
+  __ bne(done);
+  __ beq(miss);
+}
+
+
+void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
+  // This stub overrides SometimesSetsUpAFrame() to return false.  That means
+  // we cannot call anything that could cause a GC from this stub.
+  // Registers:
+  //  result: NameDictionary to probe
+  //  r4: key
+  //  dictionary: NameDictionary to probe.
+  //  index: will hold an index of entry if lookup is successful.
+  //         might alias with result_.
+  // Returns:
+  //  result_ is zero if lookup failed, non zero otherwise.
+
+  Register result = r3;
+  Register dictionary = r3;
+  Register key = r4;
+  Register index = r5;
+  Register mask = r6;
+  Register hash = r7;
+  Register undefined = r8;
+  Register entry_key = r9;
+  Register scratch = r9;
+
+  Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
+
+  __ LoadP(mask, FieldMemOperand(dictionary, kCapacityOffset));
+  __ SmiUntag(mask);
+  __ subi(mask, mask, Operand(1));
+
+  __ lwz(hash, FieldMemOperand(key, Name::kHashFieldOffset));
+
+  __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
+
+  for (int i = kInlinedProbes; i < kTotalProbes; i++) {
+    // Compute the masked index: (hash + i + i * i) & mask.
+    // Capacity is smi 2^n.
+    if (i > 0) {
+      // Add the probe offset (i + i * i) left shifted to avoid right shifting
+      // the hash in a separate instruction. The value hash + i + i * i is right
+      // shifted in the following and instruction.
+      DCHECK(NameDictionary::GetProbeOffset(i) <
+             1 << (32 - Name::kHashFieldOffset));
+      __ addi(index, hash,
+              Operand(NameDictionary::GetProbeOffset(i) << Name::kHashShift));
+    } else {
+      __ mr(index, hash);
+    }
+    __ srwi(r0, index, Operand(Name::kHashShift));
+    __ and_(index, mask, r0);
+
+    // Scale the index by multiplying by the entry size.
+    DCHECK(NameDictionary::kEntrySize == 3);
+    __ ShiftLeftImm(scratch, index, Operand(1));
+    __ add(index, index, scratch);  // index *= 3.
+
+    DCHECK_EQ(kSmiTagSize, 1);
+    __ ShiftLeftImm(scratch, index, Operand(kPointerSizeLog2));
+    __ add(index, dictionary, scratch);
+    __ LoadP(entry_key, FieldMemOperand(index, kElementsStartOffset));
+
+    // Having undefined at this place means the name is not contained.
+    __ cmp(entry_key, undefined);
+    __ beq(&not_in_dictionary);
+
+    // Stop if found the property.
+    __ cmp(entry_key, key);
+    __ beq(&in_dictionary);
+
+    if (i != kTotalProbes - 1 && mode() == NEGATIVE_LOOKUP) {
+      // Check if the entry name is not a unique name.
+      __ LoadP(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset));
+      __ lbz(entry_key, FieldMemOperand(entry_key, Map::kInstanceTypeOffset));
+      __ JumpIfNotUniqueNameInstanceType(entry_key, &maybe_in_dictionary);
+    }
+  }
+
+  __ bind(&maybe_in_dictionary);
+  // If we are doing negative lookup then probing failure should be
+  // treated as a lookup success. For positive lookup probing failure
+  // should be treated as lookup failure.
+  if (mode() == POSITIVE_LOOKUP) {
+    __ li(result, Operand::Zero());
+    __ Ret();
+  }
+
+  __ bind(&in_dictionary);
+  __ li(result, Operand(1));
+  __ Ret();
+
+  __ bind(&not_in_dictionary);
+  __ li(result, Operand::Zero());
+  __ Ret();
+}
+
+
+void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
+    Isolate* isolate) {
+  StoreBufferOverflowStub stub1(isolate, kDontSaveFPRegs);
+  stub1.GetCode();
+  // Hydrogen code stubs need stub2 at snapshot time.
+  StoreBufferOverflowStub stub2(isolate, kSaveFPRegs);
+  stub2.GetCode();
+}
+
+
+// Takes the input in 3 registers: address_ value_ and object_.  A pointer to
+// the value has just been written into the object, now this stub makes sure
+// we keep the GC informed.  The word in the object where the value has been
+// written is in the address register.
+void RecordWriteStub::Generate(MacroAssembler* masm) {
+  Label skip_to_incremental_noncompacting;
+  Label skip_to_incremental_compacting;
+
+  // The first two branch instructions are generated with labels so as to
+  // get the offset fixed up correctly by the bind(Label*) call.  We patch
+  // it back and forth between branch condition True and False
+  // when we start and stop incremental heap marking.
+  // See RecordWriteStub::Patch for details.
+
+  // Clear the bit, branch on True for NOP action initially
+  __ crclr(Assembler::encode_crbit(cr2, CR_LT));
+  __ blt(&skip_to_incremental_noncompacting, cr2);
+  __ blt(&skip_to_incremental_compacting, cr2);
+
+  if (remembered_set_action() == EMIT_REMEMBERED_SET) {
+    __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
+                           MacroAssembler::kReturnAtEnd);
+  }
+  __ Ret();
+
+  __ bind(&skip_to_incremental_noncompacting);
+  GenerateIncremental(masm, INCREMENTAL);
+
+  __ bind(&skip_to_incremental_compacting);
+  GenerateIncremental(masm, INCREMENTAL_COMPACTION);
+
+  // Initial mode of the stub is expected to be STORE_BUFFER_ONLY.
+  // Will be checked in IncrementalMarking::ActivateGeneratedStub.
+  // patching not required on PPC as the initial path is effectively NOP
+}
+
+
+void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
+  regs_.Save(masm);
+
+  if (remembered_set_action() == EMIT_REMEMBERED_SET) {
+    Label dont_need_remembered_set;
+
+    __ LoadP(regs_.scratch0(), MemOperand(regs_.address(), 0));
+    __ JumpIfNotInNewSpace(regs_.scratch0(),  // Value.
+                           regs_.scratch0(), &dont_need_remembered_set);
+
+    __ CheckPageFlag(regs_.object(), regs_.scratch0(),
+                     1 << MemoryChunk::SCAN_ON_SCAVENGE, ne,
+                     &dont_need_remembered_set);
+
+    // First notify the incremental marker if necessary, then update the
+    // remembered set.
+    CheckNeedsToInformIncrementalMarker(
+        masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode);
+    InformIncrementalMarker(masm);
+    regs_.Restore(masm);
+    __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
+                           MacroAssembler::kReturnAtEnd);
+
+    __ bind(&dont_need_remembered_set);
+  }
+
+  CheckNeedsToInformIncrementalMarker(
+      masm, kReturnOnNoNeedToInformIncrementalMarker, mode);
+  InformIncrementalMarker(masm);
+  regs_.Restore(masm);
+  __ Ret();
+}
+
+
+void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) {
+  regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode());
+  int argument_count = 3;
+  __ PrepareCallCFunction(argument_count, regs_.scratch0());
+  Register address =
+      r3.is(regs_.address()) ? regs_.scratch0() : regs_.address();
+  DCHECK(!address.is(regs_.object()));
+  DCHECK(!address.is(r3));
+  __ mr(address, regs_.address());
+  __ mr(r3, regs_.object());
+  __ mr(r4, address);
+  __ mov(r5, Operand(ExternalReference::isolate_address(isolate())));
+
+  AllowExternalCallThatCantCauseGC scope(masm);
+  __ CallCFunction(
+      ExternalReference::incremental_marking_record_write_function(isolate()),
+      argument_count);
+  regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode());
+}
+
+
+void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
+    MacroAssembler* masm, OnNoNeedToInformIncrementalMarker on_no_need,
+    Mode mode) {
+  Label on_black;
+  Label need_incremental;
+  Label need_incremental_pop_scratch;
+
+  DCHECK((~Page::kPageAlignmentMask & 0xffff) == 0);
+  __ lis(r0, Operand((~Page::kPageAlignmentMask >> 16)));
+  __ and_(regs_.scratch0(), regs_.object(), r0);
+  __ LoadP(
+      regs_.scratch1(),
+      MemOperand(regs_.scratch0(), MemoryChunk::kWriteBarrierCounterOffset));
+  __ subi(regs_.scratch1(), regs_.scratch1(), Operand(1));
+  __ StoreP(
+      regs_.scratch1(),
+      MemOperand(regs_.scratch0(), MemoryChunk::kWriteBarrierCounterOffset));
+  __ cmpi(regs_.scratch1(), Operand::Zero());  // PPC, we could do better here
+  __ blt(&need_incremental);
+
+  // Let's look at the color of the object:  If it is not black we don't have
+  // to inform the incremental marker.
+  __ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black);
+
+  regs_.Restore(masm);
+  if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
+    __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
+                           MacroAssembler::kReturnAtEnd);
+  } else {
+    __ Ret();
+  }
+
+  __ bind(&on_black);
+
+  // Get the value from the slot.
+  __ LoadP(regs_.scratch0(), MemOperand(regs_.address(), 0));
+
+  if (mode == INCREMENTAL_COMPACTION) {
+    Label ensure_not_white;
+
+    __ CheckPageFlag(regs_.scratch0(),  // Contains value.
+                     regs_.scratch1(),  // Scratch.
+                     MemoryChunk::kEvacuationCandidateMask, eq,
+                     &ensure_not_white);
+
+    __ CheckPageFlag(regs_.object(),
+                     regs_.scratch1(),  // Scratch.
+                     MemoryChunk::kSkipEvacuationSlotsRecordingMask, eq,
+                     &need_incremental);
+
+    __ bind(&ensure_not_white);
+  }
+
+  // We need extra registers for this, so we push the object and the address
+  // register temporarily.
+  __ Push(regs_.object(), regs_.address());
+  __ EnsureNotWhite(regs_.scratch0(),  // The value.
+                    regs_.scratch1(),  // Scratch.
+                    regs_.object(),    // Scratch.
+                    regs_.address(),   // Scratch.
+                    &need_incremental_pop_scratch);
+  __ Pop(regs_.object(), regs_.address());
+
+  regs_.Restore(masm);
+  if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
+    __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
+                           MacroAssembler::kReturnAtEnd);
+  } else {
+    __ Ret();
+  }
+
+  __ bind(&need_incremental_pop_scratch);
+  __ Pop(regs_.object(), regs_.address());
+
+  __ bind(&need_incremental);
+
+  // Fall through when we need to inform the incremental marker.
+}
+
+
+void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r3    : element value to store
+  //  -- r6    : element index as smi
+  //  -- sp[0] : array literal index in function as smi
+  //  -- sp[4] : array literal
+  // clobbers r3, r5, r7
+  // -----------------------------------
+
+  Label element_done;
+  Label double_elements;
+  Label smi_element;
+  Label slow_elements;
+  Label fast_elements;
+
+  // Get array literal index, array literal and its map.
+  __ LoadP(r7, MemOperand(sp, 0 * kPointerSize));
+  __ LoadP(r4, MemOperand(sp, 1 * kPointerSize));
+  __ LoadP(r5, FieldMemOperand(r4, JSObject::kMapOffset));
+
+  __ CheckFastElements(r5, r8, &double_elements);
+  // FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS
+  __ JumpIfSmi(r3, &smi_element);
+  __ CheckFastSmiElements(r5, r8, &fast_elements);
+
+  // Store into the array literal requires a elements transition. Call into
+  // the runtime.
+  __ bind(&slow_elements);
+  // call.
+  __ Push(r4, r6, r3);
+  __ LoadP(r8, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ LoadP(r8, FieldMemOperand(r8, JSFunction::kLiteralsOffset));
+  __ Push(r8, r7);
+  __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
+
+  // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
+  __ bind(&fast_elements);
+  __ LoadP(r8, FieldMemOperand(r4, JSObject::kElementsOffset));
+  __ SmiToPtrArrayOffset(r9, r6);
+  __ add(r9, r8, r9);
+#if V8_TARGET_ARCH_PPC64
+  // add due to offset alignment requirements of StorePU
+  __ addi(r9, r9, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ StoreP(r3, MemOperand(r9));
+#else
+  __ StorePU(r3, MemOperand(r9, FixedArray::kHeaderSize - kHeapObjectTag));
+#endif
+  // Update the write barrier for the array store.
+  __ RecordWrite(r8, r9, r3, kLRHasNotBeenSaved, kDontSaveFPRegs,
+                 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+  __ Ret();
+
+  // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS,
+  // and value is Smi.
+  __ bind(&smi_element);
+  __ LoadP(r8, FieldMemOperand(r4, JSObject::kElementsOffset));
+  __ SmiToPtrArrayOffset(r9, r6);
+  __ add(r9, r8, r9);
+  __ StoreP(r3, FieldMemOperand(r9, FixedArray::kHeaderSize), r0);
+  __ Ret();
+
+  // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
+  __ bind(&double_elements);
+  __ LoadP(r8, FieldMemOperand(r4, JSObject::kElementsOffset));
+  __ StoreNumberToDoubleElements(r3, r6, r8, r9, d0, &slow_elements);
+  __ Ret();
+}
+
+
+void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
+  CEntryStub ces(isolate(), 1, kSaveFPRegs);
+  __ Call(ces.GetCode(), RelocInfo::CODE_TARGET);
+  int parameter_count_offset =
+      StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
+  __ LoadP(r4, MemOperand(fp, parameter_count_offset));
+  if (function_mode() == JS_FUNCTION_STUB_MODE) {
+    __ addi(r4, r4, Operand(1));
+  }
+  masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
+  __ slwi(r4, r4, Operand(kPointerSizeLog2));
+  __ add(sp, sp, r4);
+  __ Ret();
+}
+
+
+void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
+  EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
+  VectorLoadStub stub(isolate(), state());
+  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+}
+
+
+void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
+  EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
+  VectorKeyedLoadStub stub(isolate());
+  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+}
+
+
+void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
+  if (masm->isolate()->function_entry_hook() != NULL) {
+    PredictableCodeSizeScope predictable(masm,
+#if V8_TARGET_ARCH_PPC64
+                                         14 * Assembler::kInstrSize);
+#else
+                                         11 * Assembler::kInstrSize);
+#endif
+    ProfileEntryHookStub stub(masm->isolate());
+    __ mflr(r0);
+    __ Push(r0, ip);
+    __ CallStub(&stub);
+    __ Pop(r0, ip);
+    __ mtlr(r0);
+  }
+}
+
+
+void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
+  // The entry hook is a "push lr, ip" instruction, followed by a call.
+  const int32_t kReturnAddressDistanceFromFunctionStart =
+      Assembler::kCallTargetAddressOffset + 3 * Assembler::kInstrSize;
+
+  // This should contain all kJSCallerSaved registers.
+  const RegList kSavedRegs = kJSCallerSaved |  // Caller saved registers.
+                             r15.bit();        // Saved stack pointer.
+
+  // We also save lr, so the count here is one higher than the mask indicates.
+  const int32_t kNumSavedRegs = kNumJSCallerSaved + 2;
+
+  // Save all caller-save registers as this may be called from anywhere.
+  __ mflr(ip);
+  __ MultiPush(kSavedRegs | ip.bit());
+
+  // Compute the function's address for the first argument.
+  __ subi(r3, ip, Operand(kReturnAddressDistanceFromFunctionStart));
+
+  // The caller's return address is two slots above the saved temporaries.
+  // Grab that for the second argument to the hook.
+  __ addi(r4, sp, Operand((kNumSavedRegs + 1) * kPointerSize));
+
+  // Align the stack if necessary.
+  int frame_alignment = masm->ActivationFrameAlignment();
+  if (frame_alignment > kPointerSize) {
+    __ mr(r15, sp);
+    DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
+    __ ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
+  }
+
+#if !defined(USE_SIMULATOR)
+  uintptr_t entry_hook =
+      reinterpret_cast<uintptr_t>(isolate()->function_entry_hook());
+  __ mov(ip, Operand(entry_hook));
+
+#if ABI_USES_FUNCTION_DESCRIPTORS
+  // Function descriptor
+  __ LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(ip, kPointerSize));
+  __ LoadP(ip, MemOperand(ip, 0));
+#elif ABI_TOC_ADDRESSABILITY_VIA_IP
+// ip set above, so nothing to do.
+#endif
+
+  // PPC LINUX ABI:
+  __ li(r0, Operand::Zero());
+  __ StorePU(r0, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize));
+#else
+  // Under the simulator we need to indirect the entry hook through a
+  // trampoline function at a known address.
+  // It additionally takes an isolate as a third parameter
+  __ mov(r5, Operand(ExternalReference::isolate_address(isolate())));
+
+  ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline));
+  __ mov(ip, Operand(ExternalReference(
+                 &dispatcher, ExternalReference::BUILTIN_CALL, isolate())));
+#endif
+  __ Call(ip);
+
+#if !defined(USE_SIMULATOR)
+  __ addi(sp, sp, Operand(kNumRequiredStackFrameSlots * kPointerSize));
+#endif
+
+  // Restore the stack pointer if needed.
+  if (frame_alignment > kPointerSize) {
+    __ mr(sp, r15);
+  }
+
+  // Also pop lr to get Ret(0).
+  __ MultiPop(kSavedRegs | ip.bit());
+  __ mtlr(ip);
+  __ Ret();
+}
+
+
+template <class T>
+static void CreateArrayDispatch(MacroAssembler* masm,
+                                AllocationSiteOverrideMode mode) {
+  if (mode == DISABLE_ALLOCATION_SITES) {
+    T stub(masm->isolate(), GetInitialFastElementsKind(), mode);
+    __ TailCallStub(&stub);
+  } else if (mode == DONT_OVERRIDE) {
+    int last_index =
+        GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
+    for (int i = 0; i <= last_index; ++i) {
+      ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
+      __ Cmpi(r6, Operand(kind), r0);
+      T stub(masm->isolate(), kind);
+      __ TailCallStub(&stub, eq);
+    }
+
+    // If we reached this point there is a problem.
+    __ Abort(kUnexpectedElementsKindInArrayConstructor);
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
+                                           AllocationSiteOverrideMode mode) {
+  // r5 - allocation site (if mode != DISABLE_ALLOCATION_SITES)
+  // r6 - kind (if mode != DISABLE_ALLOCATION_SITES)
+  // r3 - number of arguments
+  // r4 - constructor?
+  // sp[0] - last argument
+  Label normal_sequence;
+  if (mode == DONT_OVERRIDE) {
+    DCHECK(FAST_SMI_ELEMENTS == 0);
+    DCHECK(FAST_HOLEY_SMI_ELEMENTS == 1);
+    DCHECK(FAST_ELEMENTS == 2);
+    DCHECK(FAST_HOLEY_ELEMENTS == 3);
+    DCHECK(FAST_DOUBLE_ELEMENTS == 4);
+    DCHECK(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
+
+    // is the low bit set? If so, we are holey and that is good.
+    __ andi(r0, r6, Operand(1));
+    __ bne(&normal_sequence, cr0);
+  }
+
+  // look at the first argument
+  __ LoadP(r8, MemOperand(sp, 0));
+  __ cmpi(r8, Operand::Zero());
+  __ beq(&normal_sequence);
+
+  if (mode == DISABLE_ALLOCATION_SITES) {
+    ElementsKind initial = GetInitialFastElementsKind();
+    ElementsKind holey_initial = GetHoleyElementsKind(initial);
+
+    ArraySingleArgumentConstructorStub stub_holey(
+        masm->isolate(), holey_initial, DISABLE_ALLOCATION_SITES);
+    __ TailCallStub(&stub_holey);
+
+    __ bind(&normal_sequence);
+    ArraySingleArgumentConstructorStub stub(masm->isolate(), initial,
+                                            DISABLE_ALLOCATION_SITES);
+    __ TailCallStub(&stub);
+  } else if (mode == DONT_OVERRIDE) {
+    // We are going to create a holey array, but our kind is non-holey.
+    // Fix kind and retry (only if we have an allocation site in the slot).
+    __ addi(r6, r6, Operand(1));
+
+    if (FLAG_debug_code) {
+      __ LoadP(r8, FieldMemOperand(r5, 0));
+      __ CompareRoot(r8, Heap::kAllocationSiteMapRootIndex);
+      __ Assert(eq, kExpectedAllocationSite);
+    }
+
+    // Save the resulting elements kind in type info. We can't just store r6
+    // in the AllocationSite::transition_info field because elements kind is
+    // restricted to a portion of the field...upper bits need to be left alone.
+    STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
+    __ LoadP(r7, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset));
+    __ AddSmiLiteral(r7, r7, Smi::FromInt(kFastElementsKindPackedToHoley), r0);
+    __ StoreP(r7, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset),
+              r0);
+
+    __ bind(&normal_sequence);
+    int last_index =
+        GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
+    for (int i = 0; i <= last_index; ++i) {
+      ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
+      __ mov(r0, Operand(kind));
+      __ cmp(r6, r0);
+      ArraySingleArgumentConstructorStub stub(masm->isolate(), kind);
+      __ TailCallStub(&stub, eq);
+    }
+
+    // If we reached this point there is a problem.
+    __ Abort(kUnexpectedElementsKindInArrayConstructor);
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+template <class T>
+static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
+  int to_index =
+      GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
+  for (int i = 0; i <= to_index; ++i) {
+    ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
+    T stub(isolate, kind);
+    stub.GetCode();
+    if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
+      T stub1(isolate, kind, DISABLE_ALLOCATION_SITES);
+      stub1.GetCode();
+    }
+  }
+}
+
+
+void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) {
+  ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>(
+      isolate);
+  ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>(
+      isolate);
+  ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>(
+      isolate);
+}
+
+
+void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(
+    Isolate* isolate) {
+  ElementsKind kinds[2] = {FAST_ELEMENTS, FAST_HOLEY_ELEMENTS};
+  for (int i = 0; i < 2; i++) {
+    // For internal arrays we only need a few things
+    InternalArrayNoArgumentConstructorStub stubh1(isolate, kinds[i]);
+    stubh1.GetCode();
+    InternalArraySingleArgumentConstructorStub stubh2(isolate, kinds[i]);
+    stubh2.GetCode();
+    InternalArrayNArgumentsConstructorStub stubh3(isolate, kinds[i]);
+    stubh3.GetCode();
+  }
+}
+
+
+void ArrayConstructorStub::GenerateDispatchToArrayStub(
+    MacroAssembler* masm, AllocationSiteOverrideMode mode) {
+  if (argument_count() == ANY) {
+    Label not_zero_case, not_one_case;
+    __ cmpi(r3, Operand::Zero());
+    __ bne(&not_zero_case);
+    CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
+
+    __ bind(&not_zero_case);
+    __ cmpi(r3, Operand(1));
+    __ bgt(&not_one_case);
+    CreateArrayDispatchOneArgument(masm, mode);
+
+    __ bind(&not_one_case);
+    CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
+  } else if (argument_count() == NONE) {
+    CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
+  } else if (argument_count() == ONE) {
+    CreateArrayDispatchOneArgument(masm, mode);
+  } else if (argument_count() == MORE_THAN_ONE) {
+    CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+void ArrayConstructorStub::Generate(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r3 : argc (only if argument_count() == ANY)
+  //  -- r4 : constructor
+  //  -- r5 : AllocationSite or undefined
+  //  -- sp[0] : return address
+  //  -- sp[4] : last argument
+  // -----------------------------------
+
+  if (FLAG_debug_code) {
+    // The array construct code is only set for the global and natives
+    // builtin Array functions which always have maps.
+
+    // Initial map for the builtin Array function should be a map.
+    __ LoadP(r7, FieldMemOperand(r4, JSFunction::kPrototypeOrInitialMapOffset));
+    // Will both indicate a NULL and a Smi.
+    __ TestIfSmi(r7, r0);
+    __ Assert(ne, kUnexpectedInitialMapForArrayFunction, cr0);
+    __ CompareObjectType(r7, r7, r8, MAP_TYPE);
+    __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
+
+    // We should either have undefined in r5 or a valid AllocationSite
+    __ AssertUndefinedOrAllocationSite(r5, r7);
+  }
+
+  Label no_info;
+  // Get the elements kind and case on that.
+  __ CompareRoot(r5, Heap::kUndefinedValueRootIndex);
+  __ beq(&no_info);
+
+  __ LoadP(r6, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset));
+  __ SmiUntag(r6);
+  STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
+  __ And(r6, r6, Operand(AllocationSite::ElementsKindBits::kMask));
+  GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
+
+  __ bind(&no_info);
+  GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
+}
+
+
+void InternalArrayConstructorStub::GenerateCase(MacroAssembler* masm,
+                                                ElementsKind kind) {
+  __ cmpli(r3, Operand(1));
+
+  InternalArrayNoArgumentConstructorStub stub0(isolate(), kind);
+  __ TailCallStub(&stub0, lt);
+
+  InternalArrayNArgumentsConstructorStub stubN(isolate(), kind);
+  __ TailCallStub(&stubN, gt);
+
+  if (IsFastPackedElementsKind(kind)) {
+    // We might need to create a holey array
+    // look at the first argument
+    __ LoadP(r6, MemOperand(sp, 0));
+    __ cmpi(r6, Operand::Zero());
+
+    InternalArraySingleArgumentConstructorStub stub1_holey(
+        isolate(), GetHoleyElementsKind(kind));
+    __ TailCallStub(&stub1_holey, ne);
+  }
+
+  InternalArraySingleArgumentConstructorStub stub1(isolate(), kind);
+  __ TailCallStub(&stub1);
+}
+
+
+void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r3 : argc
+  //  -- r4 : constructor
+  //  -- sp[0] : return address
+  //  -- sp[4] : last argument
+  // -----------------------------------
+
+  if (FLAG_debug_code) {
+    // The array construct code is only set for the global and natives
+    // builtin Array functions which always have maps.
+
+    // Initial map for the builtin Array function should be a map.
+    __ LoadP(r6, FieldMemOperand(r4, JSFunction::kPrototypeOrInitialMapOffset));
+    // Will both indicate a NULL and a Smi.
+    __ TestIfSmi(r6, r0);
+    __ Assert(ne, kUnexpectedInitialMapForArrayFunction, cr0);
+    __ CompareObjectType(r6, r6, r7, MAP_TYPE);
+    __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
+  }
+
+  // Figure out the right elements kind
+  __ LoadP(r6, FieldMemOperand(r4, JSFunction::kPrototypeOrInitialMapOffset));
+  // Load the map's "bit field 2" into |result|.
+  __ lbz(r6, FieldMemOperand(r6, Map::kBitField2Offset));
+  // Retrieve elements_kind from bit field 2.
+  __ DecodeField<Map::ElementsKindBits>(r6);
+
+  if (FLAG_debug_code) {
+    Label done;
+    __ cmpi(r6, Operand(FAST_ELEMENTS));
+    __ beq(&done);
+    __ cmpi(r6, Operand(FAST_HOLEY_ELEMENTS));
+    __ Assert(eq, kInvalidElementsKindForInternalArrayOrInternalPackedArray);
+    __ bind(&done);
+  }
+
+  Label fast_elements_case;
+  __ cmpi(r6, Operand(FAST_ELEMENTS));
+  __ beq(&fast_elements_case);
+  GenerateCase(masm, FAST_HOLEY_ELEMENTS);
+
+  __ bind(&fast_elements_case);
+  GenerateCase(masm, FAST_ELEMENTS);
+}
+
+
+void CallApiFunctionStub::Generate(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- r3                  : callee
+  //  -- r7                  : call_data
+  //  -- r5                  : holder
+  //  -- r4                  : api_function_address
+  //  -- cp                  : context
+  //  --
+  //  -- sp[0]               : last argument
+  //  -- ...
+  //  -- sp[(argc - 1)* 4]   : first argument
+  //  -- sp[argc * 4]        : receiver
+  // -----------------------------------
+
+  Register callee = r3;
+  Register call_data = r7;
+  Register holder = r5;
+  Register api_function_address = r4;
+  Register context = cp;
+
+  int argc = this->argc();
+  bool is_store = this->is_store();
+  bool call_data_undefined = this->call_data_undefined();
+
+  typedef FunctionCallbackArguments FCA;
+
+  STATIC_ASSERT(FCA::kContextSaveIndex == 6);
+  STATIC_ASSERT(FCA::kCalleeIndex == 5);
+  STATIC_ASSERT(FCA::kDataIndex == 4);
+  STATIC_ASSERT(FCA::kReturnValueOffset == 3);
+  STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
+  STATIC_ASSERT(FCA::kIsolateIndex == 1);
+  STATIC_ASSERT(FCA::kHolderIndex == 0);
+  STATIC_ASSERT(FCA::kArgsLength == 7);
+
+  // context save
+  __ push(context);
+  // load context from callee
+  __ LoadP(context, FieldMemOperand(callee, JSFunction::kContextOffset));
+
+  // callee
+  __ push(callee);
+
+  // call data
+  __ push(call_data);
+
+  Register scratch = call_data;
+  if (!call_data_undefined) {
+    __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
+  }
+  // return value
+  __ push(scratch);
+  // return value default
+  __ push(scratch);
+  // isolate
+  __ mov(scratch, Operand(ExternalReference::isolate_address(isolate())));
+  __ push(scratch);
+  // holder
+  __ push(holder);
+
+  // Prepare arguments.
+  __ mr(scratch, sp);
+
+  // Allocate the v8::Arguments structure in the arguments' space since
+  // it's not controlled by GC.
+  // PPC LINUX ABI:
+  //
+  // Create 5 extra slots on stack:
+  //    [0] space for DirectCEntryStub's LR save
+  //    [1-4] FunctionCallbackInfo
+  const int kApiStackSpace = 5;
+
+  FrameScope frame_scope(masm, StackFrame::MANUAL);
+  __ EnterExitFrame(false, kApiStackSpace);
+
+  DCHECK(!api_function_address.is(r3) && !scratch.is(r3));
+  // r3 = FunctionCallbackInfo&
+  // Arguments is after the return address.
+  __ addi(r3, sp, Operand((kStackFrameExtraParamSlot + 1) * kPointerSize));
+  // FunctionCallbackInfo::implicit_args_
+  __ StoreP(scratch, MemOperand(r3, 0 * kPointerSize));
+  // FunctionCallbackInfo::values_
+  __ addi(ip, scratch, Operand((FCA::kArgsLength - 1 + argc) * kPointerSize));
+  __ StoreP(ip, MemOperand(r3, 1 * kPointerSize));
+  // FunctionCallbackInfo::length_ = argc
+  __ li(ip, Operand(argc));
+  __ stw(ip, MemOperand(r3, 2 * kPointerSize));
+  // FunctionCallbackInfo::is_construct_call = 0
+  __ li(ip, Operand::Zero());
+  __ stw(ip, MemOperand(r3, 2 * kPointerSize + kIntSize));
+
+  const int kStackUnwindSpace = argc + FCA::kArgsLength + 1;
+  ExternalReference thunk_ref =
+      ExternalReference::invoke_function_callback(isolate());
+
+  AllowExternalCallThatCantCauseGC scope(masm);
+  MemOperand context_restore_operand(
+      fp, (2 + FCA::kContextSaveIndex) * kPointerSize);
+  // Stores return the first js argument
+  int return_value_offset = 0;
+  if (is_store) {
+    return_value_offset = 2 + FCA::kArgsLength;
+  } else {
+    return_value_offset = 2 + FCA::kReturnValueOffset;
+  }
+  MemOperand return_value_operand(fp, return_value_offset * kPointerSize);
+
+  __ CallApiFunctionAndReturn(api_function_address, thunk_ref,
+                              kStackUnwindSpace, return_value_operand,
+                              &context_restore_operand);
+}
+
+
+void CallApiGetterStub::Generate(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- sp[0]                  : name
+  //  -- sp[4 - kArgsLength*4]  : PropertyCallbackArguments object
+  //  -- ...
+  //  -- r5                     : api_function_address
+  // -----------------------------------
+
+  Register api_function_address = ApiGetterDescriptor::function_address();
+  DCHECK(api_function_address.is(r5));
+
+  __ mr(r3, sp);                               // r0 = Handle<Name>
+  __ addi(r4, r3, Operand(1 * kPointerSize));  // r4 = PCA
+
+// If ABI passes Handles (pointer-sized struct) in a register:
+//
+// Create 2 extra slots on stack:
+//    [0] space for DirectCEntryStub's LR save
+//    [1] AccessorInfo&
+//
+// Otherwise:
+//
+// Create 3 extra slots on stack:
+//    [0] space for DirectCEntryStub's LR save
+//    [1] copy of Handle (first arg)
+//    [2] AccessorInfo&
+#if ABI_PASSES_HANDLES_IN_REGS
+  const int kAccessorInfoSlot = kStackFrameExtraParamSlot + 1;
+  const int kApiStackSpace = 2;
+#else
+  const int kArg0Slot = kStackFrameExtraParamSlot + 1;
+  const int kAccessorInfoSlot = kArg0Slot + 1;
+  const int kApiStackSpace = 3;
+#endif
+
+  FrameScope frame_scope(masm, StackFrame::MANUAL);
+  __ EnterExitFrame(false, kApiStackSpace);
+
+#if !ABI_PASSES_HANDLES_IN_REGS
+  // pass 1st arg by reference
+  __ StoreP(r3, MemOperand(sp, kArg0Slot * kPointerSize));
+  __ addi(r3, sp, Operand(kArg0Slot * kPointerSize));
+#endif
+
+  // Create PropertyAccessorInfo instance on the stack above the exit frame with
+  // r4 (internal::Object** args_) as the data.
+  __ StoreP(r4, MemOperand(sp, kAccessorInfoSlot * kPointerSize));
+  // r4 = AccessorInfo&
+  __ addi(r4, sp, Operand(kAccessorInfoSlot * kPointerSize));
+
+  const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
+
+  ExternalReference thunk_ref =
+      ExternalReference::invoke_accessor_getter_callback(isolate());
+  __ CallApiFunctionAndReturn(api_function_address, thunk_ref,
+                              kStackUnwindSpace,
+                              MemOperand(fp, 6 * kPointerSize), NULL);
+}
+
+
+#undef __
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ppc/code-stubs-ppc.h b/src/ppc/code-stubs-ppc.h
new file mode 100644
index 0000000..a9d06fb
--- /dev/null
+++ b/src/ppc/code-stubs-ppc.h
@@ -0,0 +1,325 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PPC_CODE_STUBS_PPC_H_
+#define V8_PPC_CODE_STUBS_PPC_H_
+
+namespace v8 {
+namespace internal {
+
+
+void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
+
+
+class StringHelper : public AllStatic {
+ public:
+  // Generate code for copying a large number of characters. This function
+  // is allowed to spend extra time setting up conditions to make copying
+  // faster. Copying of overlapping regions is not supported.
+  // Dest register ends at the position after the last character written.
+  static void GenerateCopyCharacters(MacroAssembler* masm, Register dest,
+                                     Register src, Register count,
+                                     Register scratch,
+                                     String::Encoding encoding);
+
+  // Compares two flat one-byte strings and returns result in r0.
+  static void GenerateCompareFlatOneByteStrings(MacroAssembler* masm,
+                                                Register left, Register right,
+                                                Register scratch1,
+                                                Register scratch2,
+                                                Register scratch3);
+
+  // Compares two flat one-byte strings for equality and returns result in r0.
+  static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
+                                              Register left, Register right,
+                                              Register scratch1,
+                                              Register scratch2);
+
+ private:
+  static void GenerateOneByteCharsCompareLoop(MacroAssembler* masm,
+                                              Register left, Register right,
+                                              Register length,
+                                              Register scratch1,
+                                              Label* chars_not_equal);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
+};
+
+
+class StoreRegistersStateStub : public PlatformCodeStub {
+ public:
+  explicit StoreRegistersStateStub(Isolate* isolate)
+      : PlatformCodeStub(isolate) {}
+
+  static void GenerateAheadOfTime(Isolate* isolate);
+
+ private:
+  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
+  DEFINE_PLATFORM_CODE_STUB(StoreRegistersState, PlatformCodeStub);
+};
+
+
+class RestoreRegistersStateStub : public PlatformCodeStub {
+ public:
+  explicit RestoreRegistersStateStub(Isolate* isolate)
+      : PlatformCodeStub(isolate) {}
+
+  static void GenerateAheadOfTime(Isolate* isolate);
+
+ private:
+  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
+  DEFINE_PLATFORM_CODE_STUB(RestoreRegistersState, PlatformCodeStub);
+};
+
+
+class RecordWriteStub : public PlatformCodeStub {
+ public:
+  RecordWriteStub(Isolate* isolate, Register object, Register value,
+                  Register address, RememberedSetAction remembered_set_action,
+                  SaveFPRegsMode fp_mode)
+      : PlatformCodeStub(isolate),
+        regs_(object,   // An input reg.
+              address,  // An input reg.
+              value) {  // One scratch reg.
+    minor_key_ = ObjectBits::encode(object.code()) |
+                 ValueBits::encode(value.code()) |
+                 AddressBits::encode(address.code()) |
+                 RememberedSetActionBits::encode(remembered_set_action) |
+                 SaveFPRegsModeBits::encode(fp_mode);
+  }
+
+  RecordWriteStub(uint32_t key, Isolate* isolate)
+      : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
+
+  enum Mode { STORE_BUFFER_ONLY, INCREMENTAL, INCREMENTAL_COMPACTION };
+
+  virtual bool SometimesSetsUpAFrame() { return false; }
+
+  static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
+    // Consider adding DCHECK here to catch bad patching
+    masm->instr_at_put(pos, (masm->instr_at(pos) & ~kBOfieldMask) | BT);
+  }
+
+  static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
+    // Consider adding DCHECK here to catch bad patching
+    masm->instr_at_put(pos, (masm->instr_at(pos) & ~kBOfieldMask) | BF);
+  }
+
+  static Mode GetMode(Code* stub) {
+    Instr first_instruction =
+        Assembler::instr_at(stub->instruction_start() + Assembler::kInstrSize);
+    Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
+                                                   (Assembler::kInstrSize * 2));
+
+    // Consider adding DCHECK here to catch unexpected instruction sequence
+    if (BF == (first_instruction & kBOfieldMask)) {
+      return INCREMENTAL;
+    }
+
+    if (BF == (second_instruction & kBOfieldMask)) {
+      return INCREMENTAL_COMPACTION;
+    }
+
+    return STORE_BUFFER_ONLY;
+  }
+
+  static void Patch(Code* stub, Mode mode) {
+    MacroAssembler masm(NULL, stub->instruction_start(),
+                        stub->instruction_size());
+    switch (mode) {
+      case STORE_BUFFER_ONLY:
+        DCHECK(GetMode(stub) == INCREMENTAL ||
+               GetMode(stub) == INCREMENTAL_COMPACTION);
+
+        PatchBranchIntoNop(&masm, Assembler::kInstrSize);
+        PatchBranchIntoNop(&masm, Assembler::kInstrSize * 2);
+        break;
+      case INCREMENTAL:
+        DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
+        PatchNopIntoBranch(&masm, Assembler::kInstrSize);
+        break;
+      case INCREMENTAL_COMPACTION:
+        DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
+        PatchNopIntoBranch(&masm, Assembler::kInstrSize * 2);
+        break;
+    }
+    DCHECK(GetMode(stub) == mode);
+    CpuFeatures::FlushICache(stub->instruction_start() + Assembler::kInstrSize,
+                             2 * Assembler::kInstrSize);
+  }
+
+  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
+
+ private:
+  // This is a helper class for freeing up 3 scratch registers.  The input is
+  // two registers that must be preserved and one scratch register provided by
+  // the caller.
+  class RegisterAllocation {
+   public:
+    RegisterAllocation(Register object, Register address, Register scratch0)
+        : object_(object), address_(address), scratch0_(scratch0) {
+      DCHECK(!AreAliased(scratch0, object, address, no_reg));
+      scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
+    }
+
+    void Save(MacroAssembler* masm) {
+      DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
+      // We don't have to save scratch0_ because it was given to us as
+      // a scratch register.
+      masm->push(scratch1_);
+    }
+
+    void Restore(MacroAssembler* masm) { masm->pop(scratch1_); }
+
+    // If we have to call into C then we need to save and restore all caller-
+    // saved registers that were not already preserved.  The scratch registers
+    // will be restored by other means so we don't bother pushing them here.
+    void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
+      masm->mflr(r0);
+      masm->push(r0);
+      masm->MultiPush(kJSCallerSaved & ~scratch1_.bit());
+      if (mode == kSaveFPRegs) {
+        // Save all volatile FP registers except d0.
+        masm->SaveFPRegs(sp, 1, DoubleRegister::kNumVolatileRegisters - 1);
+      }
+    }
+
+    inline void RestoreCallerSaveRegisters(MacroAssembler* masm,
+                                           SaveFPRegsMode mode) {
+      if (mode == kSaveFPRegs) {
+        // Restore all volatile FP registers except d0.
+        masm->RestoreFPRegs(sp, 1, DoubleRegister::kNumVolatileRegisters - 1);
+      }
+      masm->MultiPop(kJSCallerSaved & ~scratch1_.bit());
+      masm->pop(r0);
+      masm->mtlr(r0);
+    }
+
+    inline Register object() { return object_; }
+    inline Register address() { return address_; }
+    inline Register scratch0() { return scratch0_; }
+    inline Register scratch1() { return scratch1_; }
+
+   private:
+    Register object_;
+    Register address_;
+    Register scratch0_;
+    Register scratch1_;
+
+    friend class RecordWriteStub;
+  };
+
+  enum OnNoNeedToInformIncrementalMarker {
+    kReturnOnNoNeedToInformIncrementalMarker,
+    kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
+  };
+
+  inline Major MajorKey() const FINAL { return RecordWrite; }
+
+  void Generate(MacroAssembler* masm) OVERRIDE;
+  void GenerateIncremental(MacroAssembler* masm, Mode mode);
+  void CheckNeedsToInformIncrementalMarker(
+      MacroAssembler* masm, OnNoNeedToInformIncrementalMarker on_no_need,
+      Mode mode);
+  void InformIncrementalMarker(MacroAssembler* masm);
+
+  void Activate(Code* code) {
+    code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
+  }
+
+  Register object() const {
+    return Register::from_code(ObjectBits::decode(minor_key_));
+  }
+
+  Register value() const {
+    return Register::from_code(ValueBits::decode(minor_key_));
+  }
+
+  Register address() const {
+    return Register::from_code(AddressBits::decode(minor_key_));
+  }
+
+  RememberedSetAction remembered_set_action() const {
+    return RememberedSetActionBits::decode(minor_key_);
+  }
+
+  SaveFPRegsMode save_fp_regs_mode() const {
+    return SaveFPRegsModeBits::decode(minor_key_);
+  }
+
+  class ObjectBits : public BitField<int, 0, 5> {};
+  class ValueBits : public BitField<int, 5, 5> {};
+  class AddressBits : public BitField<int, 10, 5> {};
+  class RememberedSetActionBits : public BitField<RememberedSetAction, 15, 1> {
+  };
+  class SaveFPRegsModeBits : public BitField<SaveFPRegsMode, 16, 1> {};
+
+  Label slow_;
+  RegisterAllocation regs_;
+
+  DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
+};
+
+
+// Trampoline stub to call into native code. To call safely into native code
+// in the presence of compacting GC (which can move code objects) we need to
+// keep the code which called into native pinned in the memory. Currently the
+// simplest approach is to generate such stub early enough so it can never be
+// moved by GC
+class DirectCEntryStub : public PlatformCodeStub {
+ public:
+  explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
+  void GenerateCall(MacroAssembler* masm, Register target);
+
+ private:
+  bool NeedsImmovableCode() { return true; }
+
+  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
+  DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
+};
+
+
+class NameDictionaryLookupStub : public PlatformCodeStub {
+ public:
+  enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
+
+  NameDictionaryLookupStub(Isolate* isolate, LookupMode mode)
+      : PlatformCodeStub(isolate) {
+    minor_key_ = LookupModeBits::encode(mode);
+  }
+
+  static void GenerateNegativeLookup(MacroAssembler* masm, Label* miss,
+                                     Label* done, Register receiver,
+                                     Register properties, Handle<Name> name,
+                                     Register scratch0);
+
+  static void GeneratePositiveLookup(MacroAssembler* masm, Label* miss,
+                                     Label* done, Register elements,
+                                     Register name, Register r0, Register r1);
+
+  virtual bool SometimesSetsUpAFrame() { return false; }
+
+ private:
+  static const int kInlinedProbes = 4;
+  static const int kTotalProbes = 20;
+
+  static const int kCapacityOffset =
+      NameDictionary::kHeaderSize +
+      NameDictionary::kCapacityIndex * kPointerSize;
+
+  static const int kElementsStartOffset =
+      NameDictionary::kHeaderSize +
+      NameDictionary::kElementsStartIndex * kPointerSize;
+
+  LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
+
+  class LookupModeBits : public BitField<LookupMode, 0, 1> {};
+
+  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
+  DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
+};
+}
+}  // namespace v8::internal
+
+#endif  // V8_PPC_CODE_STUBS_PPC_H_
diff --git a/src/ppc/codegen-ppc.cc b/src/ppc/codegen-ppc.cc
new file mode 100644
index 0000000..1074e87
--- /dev/null
+++ b/src/ppc/codegen-ppc.cc
@@ -0,0 +1,700 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/codegen.h"
+#include "src/macro-assembler.h"
+#include "src/ppc/simulator-ppc.h"
+
+namespace v8 {
+namespace internal {
+
+
+#define __ masm.
+
+
+#if defined(USE_SIMULATOR)
+byte* fast_exp_ppc_machine_code = NULL;
+double fast_exp_simulator(double x) {
+  return Simulator::current(Isolate::Current())
+      ->CallFPReturnsDouble(fast_exp_ppc_machine_code, x, 0);
+}
+#endif
+
+
+UnaryMathFunction CreateExpFunction() {
+  if (!FLAG_fast_math) return &std::exp;
+  size_t actual_size;
+  byte* buffer =
+      static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
+  if (buffer == NULL) return &std::exp;
+  ExternalReference::InitializeMathExpData();
+
+  MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
+
+  {
+    DoubleRegister input = d1;
+    DoubleRegister result = d2;
+    DoubleRegister double_scratch1 = d3;
+    DoubleRegister double_scratch2 = d4;
+    Register temp1 = r7;
+    Register temp2 = r8;
+    Register temp3 = r9;
+
+// Called from C
+#if ABI_USES_FUNCTION_DESCRIPTORS
+    __ function_descriptor();
+#endif
+
+    __ Push(temp3, temp2, temp1);
+    MathExpGenerator::EmitMathExp(&masm, input, result, double_scratch1,
+                                  double_scratch2, temp1, temp2, temp3);
+    __ Pop(temp3, temp2, temp1);
+    __ fmr(d1, result);
+    __ Ret();
+  }
+
+  CodeDesc desc;
+  masm.GetCode(&desc);
+#if !ABI_USES_FUNCTION_DESCRIPTORS
+  DCHECK(!RelocInfo::RequiresRelocation(desc));
+#endif
+
+  CpuFeatures::FlushICache(buffer, actual_size);
+  base::OS::ProtectCode(buffer, actual_size);
+
+#if !defined(USE_SIMULATOR)
+  return FUNCTION_CAST<UnaryMathFunction>(buffer);
+#else
+  fast_exp_ppc_machine_code = buffer;
+  return &fast_exp_simulator;
+#endif
+}
+
+
+UnaryMathFunction CreateSqrtFunction() {
+#if defined(USE_SIMULATOR)
+  return &std::sqrt;
+#else
+  size_t actual_size;
+  byte* buffer =
+      static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
+  if (buffer == NULL) return &std::sqrt;
+
+  MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
+
+// Called from C
+#if ABI_USES_FUNCTION_DESCRIPTORS
+  __ function_descriptor();
+#endif
+
+  __ MovFromFloatParameter(d1);
+  __ fsqrt(d1, d1);
+  __ MovToFloatResult(d1);
+  __ Ret();
+
+  CodeDesc desc;
+  masm.GetCode(&desc);
+#if !ABI_USES_FUNCTION_DESCRIPTORS
+  DCHECK(!RelocInfo::RequiresRelocation(desc));
+#endif
+
+  CpuFeatures::FlushICache(buffer, actual_size);
+  base::OS::ProtectCode(buffer, actual_size);
+  return FUNCTION_CAST<UnaryMathFunction>(buffer);
+#endif
+}
+
+#undef __
+
+
+// -------------------------------------------------------------------------
+// Platform-specific RuntimeCallHelper functions.
+
+void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
+  masm->EnterFrame(StackFrame::INTERNAL);
+  DCHECK(!masm->has_frame());
+  masm->set_has_frame(true);
+}
+
+
+void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
+  masm->LeaveFrame(StackFrame::INTERNAL);
+  DCHECK(masm->has_frame());
+  masm->set_has_frame(false);
+}
+
+
+// -------------------------------------------------------------------------
+// Code generators
+
+#define __ ACCESS_MASM(masm)
+
+void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
+    MacroAssembler* masm, Register receiver, Register key, Register value,
+    Register target_map, AllocationSiteMode mode,
+    Label* allocation_memento_found) {
+  Register scratch_elements = r7;
+  DCHECK(!AreAliased(receiver, key, value, target_map, scratch_elements));
+
+  if (mode == TRACK_ALLOCATION_SITE) {
+    DCHECK(allocation_memento_found != NULL);
+    __ JumpIfJSArrayHasAllocationMemento(receiver, scratch_elements,
+                                         allocation_memento_found);
+  }
+
+  // Set transitioned map.
+  __ StoreP(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset), r0);
+  __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, r11,
+                      kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+}
+
+
+void ElementsTransitionGenerator::GenerateSmiToDouble(
+    MacroAssembler* masm, Register receiver, Register key, Register value,
+    Register target_map, AllocationSiteMode mode, Label* fail) {
+  // lr contains the return address
+  Label loop, entry, convert_hole, gc_required, only_change_map, done;
+  Register elements = r7;
+  Register length = r8;
+  Register array = r9;
+  Register array_end = array;
+
+  // target_map parameter can be clobbered.
+  Register scratch1 = target_map;
+  Register scratch2 = r11;
+
+  // Verify input registers don't conflict with locals.
+  DCHECK(!AreAliased(receiver, key, value, target_map, elements, length, array,
+                     scratch2));
+
+  if (mode == TRACK_ALLOCATION_SITE) {
+    __ JumpIfJSArrayHasAllocationMemento(receiver, elements, fail);
+  }
+
+  // Check for empty arrays, which only require a map transition and no changes
+  // to the backing store.
+  __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  __ CompareRoot(elements, Heap::kEmptyFixedArrayRootIndex);
+  __ beq(&only_change_map);
+
+  // Preserve lr and use r17 as a temporary register.
+  __ mflr(r0);
+  __ Push(r0);
+
+  __ LoadP(length, FieldMemOperand(elements, FixedArray::kLengthOffset));
+  // length: number of elements (smi-tagged)
+
+  // Allocate new FixedDoubleArray.
+  __ SmiToDoubleArrayOffset(r17, length);
+  __ addi(r17, r17, Operand(FixedDoubleArray::kHeaderSize));
+  __ Allocate(r17, array, r10, scratch2, &gc_required, DOUBLE_ALIGNMENT);
+
+  // Set destination FixedDoubleArray's length and map.
+  __ LoadRoot(scratch2, Heap::kFixedDoubleArrayMapRootIndex);
+  __ StoreP(length, MemOperand(array, FixedDoubleArray::kLengthOffset));
+  // Update receiver's map.
+  __ StoreP(scratch2, MemOperand(array, HeapObject::kMapOffset));
+
+  __ StoreP(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset), r0);
+  __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, scratch2,
+                      kLRHasBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+  // Replace receiver's backing store with newly created FixedDoubleArray.
+  __ addi(scratch1, array, Operand(kHeapObjectTag));
+  __ StoreP(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset), r0);
+  __ RecordWriteField(receiver, JSObject::kElementsOffset, scratch1, scratch2,
+                      kLRHasBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+
+  // Prepare for conversion loop.
+  __ addi(target_map, elements,
+          Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ addi(r10, array, Operand(FixedDoubleArray::kHeaderSize));
+  __ SmiToDoubleArrayOffset(array, length);
+  __ add(array_end, r10, array);
+// Repurpose registers no longer in use.
+#if V8_TARGET_ARCH_PPC64
+  Register hole_int64 = elements;
+#else
+  Register hole_lower = elements;
+  Register hole_upper = length;
+#endif
+  // scratch1: begin of source FixedArray element fields, not tagged
+  // hole_lower: kHoleNanLower32 OR hol_int64
+  // hole_upper: kHoleNanUpper32
+  // array_end: end of destination FixedDoubleArray, not tagged
+  // scratch2: begin of FixedDoubleArray element fields, not tagged
+
+  __ b(&entry);
+
+  __ bind(&only_change_map);
+  __ StoreP(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset), r0);
+  __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, scratch2,
+                      kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+  __ b(&done);
+
+  // Call into runtime if GC is required.
+  __ bind(&gc_required);
+  __ Pop(r0);
+  __ mtlr(r0);
+  __ b(fail);
+
+  // Convert and copy elements.
+  __ bind(&loop);
+  __ LoadP(r11, MemOperand(scratch1));
+  __ addi(scratch1, scratch1, Operand(kPointerSize));
+  // r11: current element
+  __ UntagAndJumpIfNotSmi(r11, r11, &convert_hole);
+
+  // Normal smi, convert to double and store.
+  __ ConvertIntToDouble(r11, d0);
+  __ stfd(d0, MemOperand(scratch2, 0));
+  __ addi(r10, r10, Operand(8));
+
+  __ b(&entry);
+
+  // Hole found, store the-hole NaN.
+  __ bind(&convert_hole);
+  if (FLAG_debug_code) {
+    // Restore a "smi-untagged" heap object.
+    __ LoadP(r11, MemOperand(r6, -kPointerSize));
+    __ CompareRoot(r11, Heap::kTheHoleValueRootIndex);
+    __ Assert(eq, kObjectFoundInSmiOnlyArray);
+  }
+#if V8_TARGET_ARCH_PPC64
+  __ std(hole_int64, MemOperand(r10, 0));
+#else
+  __ stw(hole_upper, MemOperand(r10, Register::kExponentOffset));
+  __ stw(hole_lower, MemOperand(r10, Register::kMantissaOffset));
+#endif
+  __ addi(r10, r10, Operand(8));
+
+  __ bind(&entry);
+  __ cmp(r10, array_end);
+  __ blt(&loop);
+
+  __ Pop(r0);
+  __ mtlr(r0);
+  __ bind(&done);
+}
+
+
+void ElementsTransitionGenerator::GenerateDoubleToObject(
+    MacroAssembler* masm, Register receiver, Register key, Register value,
+    Register target_map, AllocationSiteMode mode, Label* fail) {
+  // Register lr contains the return address.
+  Label entry, loop, convert_hole, gc_required, only_change_map;
+  Register elements = r7;
+  Register array = r9;
+  Register length = r8;
+  Register scratch = r11;
+
+  // Verify input registers don't conflict with locals.
+  DCHECK(!AreAliased(receiver, key, value, target_map, elements, array, length,
+                     scratch));
+
+  if (mode == TRACK_ALLOCATION_SITE) {
+    __ JumpIfJSArrayHasAllocationMemento(receiver, elements, fail);
+  }
+
+  // Check for empty arrays, which only require a map transition and no changes
+  // to the backing store.
+  __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  __ CompareRoot(elements, Heap::kEmptyFixedArrayRootIndex);
+  __ beq(&only_change_map);
+
+  __ Push(target_map, receiver, key, value);
+  __ LoadP(length, FieldMemOperand(elements, FixedArray::kLengthOffset));
+  // elements: source FixedDoubleArray
+  // length: number of elements (smi-tagged)
+
+  // Allocate new FixedArray.
+  // Re-use value and target_map registers, as they have been saved on the
+  // stack.
+  Register array_size = value;
+  Register allocate_scratch = target_map;
+  __ li(array_size, Operand(FixedDoubleArray::kHeaderSize));
+  __ SmiToPtrArrayOffset(r0, length);
+  __ add(array_size, array_size, r0);
+  __ Allocate(array_size, array, allocate_scratch, scratch, &gc_required,
+              NO_ALLOCATION_FLAGS);
+  // array: destination FixedArray, not tagged as heap object
+  // Set destination FixedDoubleArray's length and map.
+  __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
+  __ StoreP(length, MemOperand(array, FixedDoubleArray::kLengthOffset));
+  __ StoreP(scratch, MemOperand(array, HeapObject::kMapOffset));
+  __ addi(array, array, Operand(kHeapObjectTag));
+
+  // Prepare for conversion loop.
+  Register src_elements = elements;
+  Register dst_elements = target_map;
+  Register dst_end = length;
+  Register heap_number_map = scratch;
+  __ addi(src_elements, elements,
+          Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
+  __ SmiToPtrArrayOffset(length, length);
+  __ LoadRoot(r10, Heap::kTheHoleValueRootIndex);
+
+  Label initialization_loop, loop_done;
+  __ ShiftRightImm(r0, length, Operand(kPointerSizeLog2), SetRC);
+  __ beq(&loop_done, cr0);
+
+  // Allocating heap numbers in the loop below can fail and cause a jump to
+  // gc_required. We can't leave a partly initialized FixedArray behind,
+  // so pessimistically fill it with holes now.
+  __ mtctr(r0);
+  __ addi(dst_elements, array,
+          Operand(FixedArray::kHeaderSize - kHeapObjectTag - kPointerSize));
+  __ bind(&initialization_loop);
+  __ StorePU(r10, MemOperand(dst_elements, kPointerSize));
+  __ bdnz(&initialization_loop);
+
+  __ addi(dst_elements, array,
+          Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ add(dst_end, dst_elements, length);
+  __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
+  // Using offsetted addresses in src_elements to fully take advantage of
+  // post-indexing.
+  // dst_elements: begin of destination FixedArray element fields, not tagged
+  // src_elements: begin of source FixedDoubleArray element fields,
+  //               not tagged, +4
+  // dst_end: end of destination FixedArray, not tagged
+  // array: destination FixedArray
+  // r10: the-hole pointer
+  // heap_number_map: heap number map
+  __ b(&loop);
+
+  // Call into runtime if GC is required.
+  __ bind(&gc_required);
+  __ Pop(target_map, receiver, key, value);
+  __ b(fail);
+
+  // Replace the-hole NaN with the-hole pointer.
+  __ bind(&convert_hole);
+  __ StoreP(r10, MemOperand(dst_elements));
+  __ addi(dst_elements, dst_elements, Operand(kPointerSize));
+  __ cmpl(dst_elements, dst_end);
+  __ bge(&loop_done);
+
+  __ bind(&loop);
+  Register upper_bits = key;
+  __ lwz(upper_bits, MemOperand(src_elements, Register::kExponentOffset));
+  __ addi(src_elements, src_elements, Operand(kDoubleSize));
+  // upper_bits: current element's upper 32 bit
+  // src_elements: address of next element's upper 32 bit
+  __ Cmpi(upper_bits, Operand(kHoleNanUpper32), r0);
+  __ beq(&convert_hole);
+
+  // Non-hole double, copy value into a heap number.
+  Register heap_number = receiver;
+  Register scratch2 = value;
+  __ AllocateHeapNumber(heap_number, scratch2, r11, heap_number_map,
+                        &gc_required);
+  // heap_number: new heap number
+#if V8_TARGET_ARCH_PPC64
+  __ ld(scratch2, MemOperand(src_elements, -kDoubleSize));
+  // subtract tag for std
+  __ addi(upper_bits, heap_number, Operand(-kHeapObjectTag));
+  __ std(scratch2, MemOperand(upper_bits, HeapNumber::kValueOffset));
+#else
+  __ lwz(scratch2,
+         MemOperand(src_elements, Register::kMantissaOffset - kDoubleSize));
+  __ lwz(upper_bits,
+         MemOperand(src_elements, Register::kExponentOffset - kDoubleSize));
+  __ stw(scratch2, FieldMemOperand(heap_number, HeapNumber::kMantissaOffset));
+  __ stw(upper_bits, FieldMemOperand(heap_number, HeapNumber::kExponentOffset));
+#endif
+  __ mr(scratch2, dst_elements);
+  __ StoreP(heap_number, MemOperand(dst_elements));
+  __ addi(dst_elements, dst_elements, Operand(kPointerSize));
+  __ RecordWrite(array, scratch2, heap_number, kLRHasNotBeenSaved,
+                 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+  __ b(&entry);
+
+  // Replace the-hole NaN with the-hole pointer.
+  __ bind(&convert_hole);
+  __ StoreP(r10, MemOperand(dst_elements));
+  __ addi(dst_elements, dst_elements, Operand(kPointerSize));
+
+  __ bind(&entry);
+  __ cmpl(dst_elements, dst_end);
+  __ blt(&loop);
+  __ bind(&loop_done);
+
+  __ Pop(target_map, receiver, key, value);
+  // Replace receiver's backing store with newly created and filled FixedArray.
+  __ StoreP(array, FieldMemOperand(receiver, JSObject::kElementsOffset), r0);
+  __ RecordWriteField(receiver, JSObject::kElementsOffset, array, scratch,
+                      kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+
+  __ bind(&only_change_map);
+  // Update receiver's map.
+  __ StoreP(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset), r0);
+  __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, scratch,
+                      kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+}
+
+
+// assume ip can be used as a scratch register below
+void StringCharLoadGenerator::Generate(MacroAssembler* masm, Register string,
+                                       Register index, Register result,
+                                       Label* call_runtime) {
+  // Fetch the instance type of the receiver into result register.
+  __ LoadP(result, FieldMemOperand(string, HeapObject::kMapOffset));
+  __ lbz(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
+
+  // We need special handling for indirect strings.
+  Label check_sequential;
+  __ andi(r0, result, Operand(kIsIndirectStringMask));
+  __ beq(&check_sequential, cr0);
+
+  // Dispatch on the indirect string shape: slice or cons.
+  Label cons_string;
+  __ mov(ip, Operand(kSlicedNotConsMask));
+  __ and_(r0, result, ip, SetRC);
+  __ beq(&cons_string, cr0);
+
+  // Handle slices.
+  Label indirect_string_loaded;
+  __ LoadP(result, FieldMemOperand(string, SlicedString::kOffsetOffset));
+  __ LoadP(string, FieldMemOperand(string, SlicedString::kParentOffset));
+  __ SmiUntag(ip, result);
+  __ add(index, index, ip);
+  __ b(&indirect_string_loaded);
+
+  // Handle cons strings.
+  // Check whether the right hand side is the empty string (i.e. if
+  // this is really a flat string in a cons string). If that is not
+  // the case we would rather go to the runtime system now to flatten
+  // the string.
+  __ bind(&cons_string);
+  __ LoadP(result, FieldMemOperand(string, ConsString::kSecondOffset));
+  __ CompareRoot(result, Heap::kempty_stringRootIndex);
+  __ bne(call_runtime);
+  // Get the first of the two strings and load its instance type.
+  __ LoadP(string, FieldMemOperand(string, ConsString::kFirstOffset));
+
+  __ bind(&indirect_string_loaded);
+  __ LoadP(result, FieldMemOperand(string, HeapObject::kMapOffset));
+  __ lbz(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
+
+  // Distinguish sequential and external strings. Only these two string
+  // representations can reach here (slices and flat cons strings have been
+  // reduced to the underlying sequential or external string).
+  Label external_string, check_encoding;
+  __ bind(&check_sequential);
+  STATIC_ASSERT(kSeqStringTag == 0);
+  __ andi(r0, result, Operand(kStringRepresentationMask));
+  __ bne(&external_string, cr0);
+
+  // Prepare sequential strings
+  STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
+  __ addi(string, string,
+          Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
+  __ b(&check_encoding);
+
+  // Handle external strings.
+  __ bind(&external_string);
+  if (FLAG_debug_code) {
+    // Assert that we do not have a cons or slice (indirect strings) here.
+    // Sequential strings have already been ruled out.
+    __ andi(r0, result, Operand(kIsIndirectStringMask));
+    __ Assert(eq, kExternalStringExpectedButNotFound, cr0);
+  }
+  // Rule out short external strings.
+  STATIC_ASSERT(kShortExternalStringTag != 0);
+  __ andi(r0, result, Operand(kShortExternalStringMask));
+  __ bne(call_runtime, cr0);
+  __ LoadP(string,
+           FieldMemOperand(string, ExternalString::kResourceDataOffset));
+
+  Label one_byte, done;
+  __ bind(&check_encoding);
+  STATIC_ASSERT(kTwoByteStringTag == 0);
+  __ andi(r0, result, Operand(kStringEncodingMask));
+  __ bne(&one_byte, cr0);
+  // Two-byte string.
+  __ ShiftLeftImm(result, index, Operand(1));
+  __ lhzx(result, MemOperand(string, result));
+  __ b(&done);
+  __ bind(&one_byte);
+  // One-byte string.
+  __ lbzx(result, MemOperand(string, index));
+  __ bind(&done);
+}
+
+
+static MemOperand ExpConstant(int index, Register base) {
+  return MemOperand(base, index * kDoubleSize);
+}
+
+
+void MathExpGenerator::EmitMathExp(MacroAssembler* masm, DoubleRegister input,
+                                   DoubleRegister result,
+                                   DoubleRegister double_scratch1,
+                                   DoubleRegister double_scratch2,
+                                   Register temp1, Register temp2,
+                                   Register temp3) {
+  DCHECK(!input.is(result));
+  DCHECK(!input.is(double_scratch1));
+  DCHECK(!input.is(double_scratch2));
+  DCHECK(!result.is(double_scratch1));
+  DCHECK(!result.is(double_scratch2));
+  DCHECK(!double_scratch1.is(double_scratch2));
+  DCHECK(!temp1.is(temp2));
+  DCHECK(!temp1.is(temp3));
+  DCHECK(!temp2.is(temp3));
+  DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
+  DCHECK(!masm->serializer_enabled());  // External references not serializable.
+
+  Label zero, infinity, done;
+
+  __ mov(temp3, Operand(ExternalReference::math_exp_constants(0)));
+
+  __ lfd(double_scratch1, ExpConstant(0, temp3));
+  __ fcmpu(double_scratch1, input);
+  __ fmr(result, input);
+  __ bunordered(&done);
+  __ bge(&zero);
+
+  __ lfd(double_scratch2, ExpConstant(1, temp3));
+  __ fcmpu(input, double_scratch2);
+  __ bge(&infinity);
+
+  __ lfd(double_scratch1, ExpConstant(3, temp3));
+  __ lfd(result, ExpConstant(4, temp3));
+  __ fmul(double_scratch1, double_scratch1, input);
+  __ fadd(double_scratch1, double_scratch1, result);
+  __ MovDoubleLowToInt(temp2, double_scratch1);
+  __ fsub(double_scratch1, double_scratch1, result);
+  __ lfd(result, ExpConstant(6, temp3));
+  __ lfd(double_scratch2, ExpConstant(5, temp3));
+  __ fmul(double_scratch1, double_scratch1, double_scratch2);
+  __ fsub(double_scratch1, double_scratch1, input);
+  __ fsub(result, result, double_scratch1);
+  __ fmul(double_scratch2, double_scratch1, double_scratch1);
+  __ fmul(result, result, double_scratch2);
+  __ lfd(double_scratch2, ExpConstant(7, temp3));
+  __ fmul(result, result, double_scratch2);
+  __ fsub(result, result, double_scratch1);
+  __ lfd(double_scratch2, ExpConstant(8, temp3));
+  __ fadd(result, result, double_scratch2);
+  __ srwi(temp1, temp2, Operand(11));
+  __ andi(temp2, temp2, Operand(0x7ff));
+  __ addi(temp1, temp1, Operand(0x3ff));
+
+  // Must not call ExpConstant() after overwriting temp3!
+  __ mov(temp3, Operand(ExternalReference::math_exp_log_table()));
+  __ slwi(temp2, temp2, Operand(3));
+#if V8_TARGET_ARCH_PPC64
+  __ ldx(temp2, MemOperand(temp3, temp2));
+  __ sldi(temp1, temp1, Operand(52));
+  __ orx(temp2, temp1, temp2);
+  __ MovInt64ToDouble(double_scratch1, temp2);
+#else
+  __ add(ip, temp3, temp2);
+  __ lwz(temp3, MemOperand(ip, Register::kExponentOffset));
+  __ lwz(temp2, MemOperand(ip, Register::kMantissaOffset));
+  __ slwi(temp1, temp1, Operand(20));
+  __ orx(temp3, temp1, temp3);
+  __ MovInt64ToDouble(double_scratch1, temp3, temp2);
+#endif
+
+  __ fmul(result, result, double_scratch1);
+  __ b(&done);
+
+  __ bind(&zero);
+  __ fmr(result, kDoubleRegZero);
+  __ b(&done);
+
+  __ bind(&infinity);
+  __ lfd(result, ExpConstant(2, temp3));
+
+  __ bind(&done);
+}
+
+#undef __
+
+CodeAgingHelper::CodeAgingHelper() {
+  DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength);
+  // Since patcher is a large object, allocate it dynamically when needed,
+  // to avoid overloading the stack in stress conditions.
+  // DONT_FLUSH is used because the CodeAgingHelper is initialized early in
+  // the process, before ARM simulator ICache is setup.
+  SmartPointer<CodePatcher> patcher(new CodePatcher(
+      young_sequence_.start(), young_sequence_.length() / Assembler::kInstrSize,
+      CodePatcher::DONT_FLUSH));
+  PredictableCodeSizeScope scope(patcher->masm(), young_sequence_.length());
+  patcher->masm()->PushFixedFrame(r4);
+  patcher->masm()->addi(fp, sp,
+                        Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+  for (int i = 0; i < kNoCodeAgeSequenceNops; i++) {
+    patcher->masm()->nop();
+  }
+}
+
+
+#ifdef DEBUG
+bool CodeAgingHelper::IsOld(byte* candidate) const {
+  return Assembler::IsNop(Assembler::instr_at(candidate));
+}
+#endif
+
+
+bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) {
+  bool result = isolate->code_aging_helper()->IsYoung(sequence);
+  DCHECK(result || isolate->code_aging_helper()->IsOld(sequence));
+  return result;
+}
+
+
+void Code::GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age,
+                               MarkingParity* parity) {
+  if (IsYoungSequence(isolate, sequence)) {
+    *age = kNoAgeCodeAge;
+    *parity = NO_MARKING_PARITY;
+  } else {
+    ConstantPoolArray* constant_pool = NULL;
+    Address target_address = Assembler::target_address_at(
+        sequence + kCodeAgingTargetDelta, constant_pool);
+    Code* stub = GetCodeFromTargetAddress(target_address);
+    GetCodeAgeAndParity(stub, age, parity);
+  }
+}
+
+
+void Code::PatchPlatformCodeAge(Isolate* isolate, byte* sequence, Code::Age age,
+                                MarkingParity parity) {
+  uint32_t young_length = isolate->code_aging_helper()->young_sequence_length();
+  if (age == kNoAgeCodeAge) {
+    isolate->code_aging_helper()->CopyYoungSequenceTo(sequence);
+    CpuFeatures::FlushICache(sequence, young_length);
+  } else {
+    // FIXED_SEQUENCE
+    Code* stub = GetCodeAgeStub(isolate, age, parity);
+    CodePatcher patcher(sequence, young_length / Assembler::kInstrSize);
+    Assembler::BlockTrampolinePoolScope block_trampoline_pool(patcher.masm());
+    intptr_t target = reinterpret_cast<intptr_t>(stub->instruction_start());
+    // Don't use Call -- we need to preserve ip and lr.
+    // GenerateMakeCodeYoungAgainCommon for the stub code.
+    patcher.masm()->nop();  // marker to detect sequence (see IsOld)
+    patcher.masm()->mov(r3, Operand(target));
+    patcher.masm()->Jump(r3);
+    for (int i = 0; i < kCodeAgingSequenceNops; i++) {
+      patcher.masm()->nop();
+    }
+  }
+}
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ppc/codegen-ppc.h b/src/ppc/codegen-ppc.h
new file mode 100644
index 0000000..500bf60
--- /dev/null
+++ b/src/ppc/codegen-ppc.h
@@ -0,0 +1,44 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PPC_CODEGEN_PPC_H_
+#define V8_PPC_CODEGEN_PPC_H_
+
+#include "src/ast.h"
+#include "src/macro-assembler.h"
+
+namespace v8 {
+namespace internal {
+
+
+enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
+
+
+class StringCharLoadGenerator : public AllStatic {
+ public:
+  // Generates the code for handling different string types and loading the
+  // indexed character into |result|.  We expect |index| as untagged input and
+  // |result| as untagged output.
+  static void Generate(MacroAssembler* masm, Register string, Register index,
+                       Register result, Label* call_runtime);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator);
+};
+
+class MathExpGenerator : public AllStatic {
+ public:
+  // Register input isn't modified. All other registers are clobbered.
+  static void EmitMathExp(MacroAssembler* masm, DoubleRegister input,
+                          DoubleRegister result, DoubleRegister double_scratch1,
+                          DoubleRegister double_scratch2, Register temp1,
+                          Register temp2, Register temp3);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
+};
+}
+}  // namespace v8::internal
+
+#endif  // V8_PPC_CODEGEN_PPC_H_
diff --git a/src/ppc/constants-ppc.cc b/src/ppc/constants-ppc.cc
new file mode 100644
index 0000000..f32f25a
--- /dev/null
+++ b/src/ppc/constants-ppc.cc
@@ -0,0 +1,91 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/ppc/constants-ppc.h"
+
+
+namespace v8 {
+namespace internal {
+
+// These register names are defined in a way to match the native disassembler
+// formatting. See for example the command "objdump -d <binary file>".
+const char* Registers::names_[kNumRegisters] = {
+    "r0",  "sp",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",  "r8",  "r9",  "r10",
+    "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21",
+    "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "fp"};
+
+
+// List of alias names which can be used when referring to PPC registers.
+const Registers::RegisterAlias Registers::aliases_[] = {{10, "sl"},
+                                                        {11, "r11"},
+                                                        {12, "r12"},
+                                                        {13, "r13"},
+                                                        {14, "r14"},
+                                                        {15, "r15"},
+                                                        {kNoRegister, NULL}};
+
+
+const char* Registers::Name(int reg) {
+  const char* result;
+  if ((0 <= reg) && (reg < kNumRegisters)) {
+    result = names_[reg];
+  } else {
+    result = "noreg";
+  }
+  return result;
+}
+
+
+const char* FPRegisters::names_[kNumFPRegisters] = {
+    "d0",  "d1",  "d2",  "d3",  "d4",  "d5",  "d6",  "d7",  "d8",  "d9",  "d10",
+    "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21",
+    "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"};
+
+
+const char* FPRegisters::Name(int reg) {
+  DCHECK((0 <= reg) && (reg < kNumFPRegisters));
+  return names_[reg];
+}
+
+
+int FPRegisters::Number(const char* name) {
+  for (int i = 0; i < kNumFPRegisters; i++) {
+    if (strcmp(names_[i], name) == 0) {
+      return i;
+    }
+  }
+
+  // No register with the requested name found.
+  return kNoRegister;
+}
+
+
+int Registers::Number(const char* name) {
+  // Look through the canonical names.
+  for (int i = 0; i < kNumRegisters; i++) {
+    if (strcmp(names_[i], name) == 0) {
+      return i;
+    }
+  }
+
+  // Look through the alias names.
+  int i = 0;
+  while (aliases_[i].reg != kNoRegister) {
+    if (strcmp(aliases_[i].name, name) == 0) {
+      return aliases_[i].reg;
+    }
+    i++;
+  }
+
+  // No register with the requested name found.
+  return kNoRegister;
+}
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ppc/constants-ppc.h b/src/ppc/constants-ppc.h
new file mode 100644
index 0000000..9434b8f
--- /dev/null
+++ b/src/ppc/constants-ppc.h
@@ -0,0 +1,600 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PPC_CONSTANTS_PPC_H_
+#define V8_PPC_CONSTANTS_PPC_H_
+
+namespace v8 {
+namespace internal {
+
+// Number of registers
+const int kNumRegisters = 32;
+
+// FP support.
+const int kNumFPDoubleRegisters = 32;
+const int kNumFPRegisters = kNumFPDoubleRegisters;
+
+const int kNoRegister = -1;
+
+// sign-extend the least significant 16-bits of value <imm>
+#define SIGN_EXT_IMM16(imm) ((static_cast<int>(imm) << 16) >> 16)
+
+// sign-extend the least significant 26-bits of value <imm>
+#define SIGN_EXT_IMM26(imm) ((static_cast<int>(imm) << 6) >> 6)
+
+// -----------------------------------------------------------------------------
+// Conditions.
+
+// Defines constants and accessor classes to assemble, disassemble and
+// simulate PPC instructions.
+//
+// Section references in the code refer to the "PowerPC Microprocessor
+// Family: The Programmer.s Reference Guide" from 10/95
+// https://www-01.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF778525699600741775/$file/prg.pdf
+//
+
+// Constants for specific fields are defined in their respective named enums.
+// General constants are in an anonymous enum in class Instr.
+enum Condition {
+  kNoCondition = -1,
+  eq = 0,         // Equal.
+  ne = 1,         // Not equal.
+  ge = 2,         // Greater or equal.
+  lt = 3,         // Less than.
+  gt = 4,         // Greater than.
+  le = 5,         // Less then or equal
+  unordered = 6,  // Floating-point unordered
+  ordered = 7,
+  overflow = 8,  // Summary overflow
+  nooverflow = 9,
+  al = 10  // Always.
+};
+
+
+inline Condition NegateCondition(Condition cond) {
+  DCHECK(cond != al);
+  return static_cast<Condition>(cond ^ ne);
+}
+
+
+// Commute a condition such that {a cond b == b cond' a}.
+inline Condition CommuteCondition(Condition cond) {
+  switch (cond) {
+    case lt:
+      return gt;
+    case gt:
+      return lt;
+    case ge:
+      return le;
+    case le:
+      return ge;
+    default:
+      return cond;
+  }
+}
+
+// -----------------------------------------------------------------------------
+// Instructions encoding.
+
+// Instr is merely used by the Assembler to distinguish 32bit integers
+// representing instructions from usual 32 bit values.
+// Instruction objects are pointers to 32bit values, and provide methods to
+// access the various ISA fields.
+typedef int32_t Instr;
+
+// Opcodes as defined in section 4.2 table 34 (32bit PowerPC)
+enum Opcode {
+  TWI = 3 << 26,       // Trap Word Immediate
+  MULLI = 7 << 26,     // Multiply Low Immediate
+  SUBFIC = 8 << 26,    // Subtract from Immediate Carrying
+  CMPLI = 10 << 26,    // Compare Logical Immediate
+  CMPI = 11 << 26,     // Compare Immediate
+  ADDIC = 12 << 26,    // Add Immediate Carrying
+  ADDICx = 13 << 26,   // Add Immediate Carrying and Record
+  ADDI = 14 << 26,     // Add Immediate
+  ADDIS = 15 << 26,    // Add Immediate Shifted
+  BCX = 16 << 26,      // Branch Conditional
+  SC = 17 << 26,       // System Call
+  BX = 18 << 26,       // Branch
+  EXT1 = 19 << 26,     // Extended code set 1
+  RLWIMIX = 20 << 26,  // Rotate Left Word Immediate then Mask Insert
+  RLWINMX = 21 << 26,  // Rotate Left Word Immediate then AND with Mask
+  RLWNMX = 23 << 26,   // Rotate Left Word then AND with Mask
+  ORI = 24 << 26,      // OR Immediate
+  ORIS = 25 << 26,     // OR Immediate Shifted
+  XORI = 26 << 26,     // XOR Immediate
+  XORIS = 27 << 26,    // XOR Immediate Shifted
+  ANDIx = 28 << 26,    // AND Immediate
+  ANDISx = 29 << 26,   // AND Immediate Shifted
+  EXT5 = 30 << 26,     // Extended code set 5 - 64bit only
+  EXT2 = 31 << 26,     // Extended code set 2
+  LWZ = 32 << 26,      // Load Word and Zero
+  LWZU = 33 << 26,     // Load Word with Zero Update
+  LBZ = 34 << 26,      // Load Byte and Zero
+  LBZU = 35 << 26,     // Load Byte and Zero with Update
+  STW = 36 << 26,      // Store
+  STWU = 37 << 26,     // Store Word with Update
+  STB = 38 << 26,      // Store Byte
+  STBU = 39 << 26,     // Store Byte with Update
+  LHZ = 40 << 26,      // Load Half and Zero
+  LHZU = 41 << 26,     // Load Half and Zero with Update
+  LHA = 42 << 26,      // Load Half Algebraic
+  LHAU = 43 << 26,     // Load Half Algebraic with Update
+  STH = 44 << 26,      // Store Half
+  STHU = 45 << 26,     // Store Half with Update
+  LMW = 46 << 26,      // Load Multiple Word
+  STMW = 47 << 26,     // Store Multiple Word
+  LFS = 48 << 26,      // Load Floating-Point Single
+  LFSU = 49 << 26,     // Load Floating-Point Single with Update
+  LFD = 50 << 26,      // Load Floating-Point Double
+  LFDU = 51 << 26,     // Load Floating-Point Double with Update
+  STFS = 52 << 26,     // Store Floating-Point Single
+  STFSU = 53 << 26,    // Store Floating-Point Single with Update
+  STFD = 54 << 26,     // Store Floating-Point Double
+  STFDU = 55 << 26,    // Store Floating-Point Double with Update
+  LD = 58 << 26,       // Load Double Word
+  EXT3 = 59 << 26,     // Extended code set 3
+  STD = 62 << 26,      // Store Double Word (optionally with Update)
+  EXT4 = 63 << 26      // Extended code set 4
+};
+
+// Bits 10-1
+enum OpcodeExt1 {
+  MCRF = 0 << 1,      // Move Condition Register Field
+  BCLRX = 16 << 1,    // Branch Conditional Link Register
+  CRNOR = 33 << 1,    // Condition Register NOR)
+  RFI = 50 << 1,      // Return from Interrupt
+  CRANDC = 129 << 1,  // Condition Register AND with Complement
+  ISYNC = 150 << 1,   // Instruction Synchronize
+  CRXOR = 193 << 1,   // Condition Register XOR
+  CRNAND = 225 << 1,  // Condition Register NAND
+  CRAND = 257 << 1,   // Condition Register AND
+  CREQV = 289 << 1,   // Condition Register Equivalent
+  CRORC = 417 << 1,   // Condition Register OR with Complement
+  CROR = 449 << 1,    // Condition Register OR
+  BCCTRX = 528 << 1   // Branch Conditional to Count Register
+};
+
+// Bits 9-1 or 10-1
+enum OpcodeExt2 {
+  CMP = 0 << 1,
+  TW = 4 << 1,
+  SUBFCX = 8 << 1,
+  ADDCX = 10 << 1,
+  MULHWUX = 11 << 1,
+  MFCR = 19 << 1,
+  LWARX = 20 << 1,
+  LDX = 21 << 1,
+  LWZX = 23 << 1,  // load word zero w/ x-form
+  SLWX = 24 << 1,
+  CNTLZWX = 26 << 1,
+  SLDX = 27 << 1,
+  ANDX = 28 << 1,
+  CMPL = 32 << 1,
+  SUBFX = 40 << 1,
+  MFVSRD = 51 << 1,  // Move From VSR Doubleword
+  LDUX = 53 << 1,
+  DCBST = 54 << 1,
+  LWZUX = 55 << 1,  // load word zero w/ update x-form
+  CNTLZDX = 58 << 1,
+  ANDCX = 60 << 1,
+  MULHWX = 75 << 1,
+  DCBF = 86 << 1,
+  LBZX = 87 << 1,  // load byte zero w/ x-form
+  NEGX = 104 << 1,
+  MFVSRWZ = 115 << 1,  // Move From VSR Word And Zero
+  LBZUX = 119 << 1,    // load byte zero w/ update x-form
+  NORX = 124 << 1,
+  SUBFEX = 136 << 1,
+  ADDEX = 138 << 1,
+  STDX = 149 << 1,
+  STWX = 151 << 1,    // store word w/ x-form
+  MTVSRD = 179 << 1,  // Move To VSR Doubleword
+  STDUX = 181 << 1,
+  STWUX = 183 << 1,  // store word w/ update x-form
+                     /*
+    MTCRF
+    MTMSR
+    STWCXx
+    SUBFZEX
+  */
+  ADDZEX = 202 << 1,  // Add to Zero Extended
+                      /*
+    MTSR
+  */
+  MTVSRWA = 211 << 1,  // Move To VSR Word Algebraic
+  STBX = 215 << 1,     // store byte w/ x-form
+  MULLD = 233 << 1,    // Multiply Low Double Word
+  MULLW = 235 << 1,    // Multiply Low Word
+  MTVSRWZ = 243 << 1,  // Move To VSR Word And Zero
+  STBUX = 247 << 1,    // store byte w/ update x-form
+  ADDX = 266 << 1,     // Add
+  LHZX = 279 << 1,     // load half-word zero w/ x-form
+  LHZUX = 311 << 1,    // load half-word zero w/ update x-form
+  LHAX = 343 << 1,     // load half-word algebraic w/ x-form
+  LHAUX = 375 << 1,    // load half-word algebraic w/ update x-form
+  XORX = 316 << 1,     // Exclusive OR
+  MFSPR = 339 << 1,    // Move from Special-Purpose-Register
+  STHX = 407 << 1,     // store half-word w/ x-form
+  STHUX = 439 << 1,    // store half-word w/ update x-form
+  ORX = 444 << 1,      // Or
+  MTSPR = 467 << 1,    // Move to Special-Purpose-Register
+  DIVD = 489 << 1,     // Divide Double Word
+  DIVW = 491 << 1,     // Divide Word
+
+  // Below represent bits 10-1  (any value >= 512)
+  LFSX = 535 << 1,    // load float-single w/ x-form
+  SRWX = 536 << 1,    // Shift Right Word
+  SRDX = 539 << 1,    // Shift Right Double Word
+  LFSUX = 567 << 1,   // load float-single w/ update x-form
+  SYNC = 598 << 1,    // Synchronize
+  LFDX = 599 << 1,    // load float-double w/ x-form
+  LFDUX = 631 << 1,   // load float-double w/ update X-form
+  STFSX = 663 << 1,   // store float-single w/ x-form
+  STFSUX = 695 << 1,  // store float-single w/ update x-form
+  STFDX = 727 << 1,   // store float-double w/ x-form
+  STFDUX = 759 << 1,  // store float-double w/ update x-form
+  SRAW = 792 << 1,    // Shift Right Algebraic Word
+  SRAD = 794 << 1,    // Shift Right Algebraic Double Word
+  SRAWIX = 824 << 1,  // Shift Right Algebraic Word Immediate
+  SRADIX = 413 << 2,  // Shift Right Algebraic Double Word Immediate
+  EXTSH = 922 << 1,   // Extend Sign Halfword
+  EXTSB = 954 << 1,   // Extend Sign Byte
+  ICBI = 982 << 1,    // Instruction Cache Block Invalidate
+  EXTSW = 986 << 1    // Extend Sign Word
+};
+
+// Some use Bits 10-1 and other only 5-1 for the opcode
+enum OpcodeExt4 {
+  // Bits 5-1
+  FDIV = 18 << 1,   // Floating Divide
+  FSUB = 20 << 1,   // Floating Subtract
+  FADD = 21 << 1,   // Floating Add
+  FSQRT = 22 << 1,  // Floating Square Root
+  FSEL = 23 << 1,   // Floating Select
+  FMUL = 25 << 1,   // Floating Multiply
+  FMSUB = 28 << 1,  // Floating Multiply-Subtract
+  FMADD = 29 << 1,  // Floating Multiply-Add
+
+  // Bits 10-1
+  FCMPU = 0 << 1,     // Floating Compare Unordered
+  FRSP = 12 << 1,     // Floating-Point Rounding
+  FCTIW = 14 << 1,    // Floating Convert to Integer Word X-form
+  FCTIWZ = 15 << 1,   // Floating Convert to Integer Word with Round to Zero
+  FNEG = 40 << 1,     // Floating Negate
+  MCRFS = 64 << 1,    // Move to Condition Register from FPSCR
+  FMR = 72 << 1,      // Floating Move Register
+  MTFSFI = 134 << 1,  // Move to FPSCR Field Immediate
+  FABS = 264 << 1,    // Floating Absolute Value
+  FRIM = 488 << 1,    // Floating Round to Integer Minus
+  MFFS = 583 << 1,    // move from FPSCR x-form
+  MTFSF = 711 << 1,   // move to FPSCR fields XFL-form
+  FCFID = 846 << 1,   // Floating convert from integer doubleword
+  FCTID = 814 << 1,   // Floating convert from integer doubleword
+  FCTIDZ = 815 << 1   // Floating convert from integer doubleword
+};
+
+enum OpcodeExt5 {
+  // Bits 4-2
+  RLDICL = 0 << 1,  // Rotate Left Double Word Immediate then Clear Left
+  RLDICR = 2 << 1,  // Rotate Left Double Word Immediate then Clear Right
+  RLDIC = 4 << 1,   // Rotate Left Double Word Immediate then Clear
+  RLDIMI = 6 << 1,  // Rotate Left Double Word Immediate then Mask Insert
+  // Bits 4-1
+  RLDCL = 8 << 1,  // Rotate Left Double Word then Clear Left
+  RLDCR = 9 << 1   // Rotate Left Double Word then Clear Right
+};
+
+// Instruction encoding bits and masks.
+enum {
+  // Instruction encoding bit
+  B1 = 1 << 1,
+  B4 = 1 << 4,
+  B5 = 1 << 5,
+  B7 = 1 << 7,
+  B8 = 1 << 8,
+  B9 = 1 << 9,
+  B12 = 1 << 12,
+  B18 = 1 << 18,
+  B19 = 1 << 19,
+  B20 = 1 << 20,
+  B22 = 1 << 22,
+  B23 = 1 << 23,
+  B24 = 1 << 24,
+  B25 = 1 << 25,
+  B26 = 1 << 26,
+  B27 = 1 << 27,
+  B28 = 1 << 28,
+  B6 = 1 << 6,
+  B10 = 1 << 10,
+  B11 = 1 << 11,
+  B16 = 1 << 16,
+  B17 = 1 << 17,
+  B21 = 1 << 21,
+
+  // Instruction bit masks
+  kCondMask = 0x1F << 21,
+  kOff12Mask = (1 << 12) - 1,
+  kImm24Mask = (1 << 24) - 1,
+  kOff16Mask = (1 << 16) - 1,
+  kImm16Mask = (1 << 16) - 1,
+  kImm26Mask = (1 << 26) - 1,
+  kBOfieldMask = 0x1f << 21,
+  kOpcodeMask = 0x3f << 26,
+  kExt1OpcodeMask = 0x3ff << 1,
+  kExt2OpcodeMask = 0x1f << 1,
+  kExt5OpcodeMask = 0x3 << 2,
+  kBOMask = 0x1f << 21,
+  kBIMask = 0x1F << 16,
+  kBDMask = 0x14 << 2,
+  kAAMask = 0x01 << 1,
+  kLKMask = 0x01,
+  kRCMask = 0x01,
+  kTOMask = 0x1f << 21
+};
+
+// the following is to differentiate different faked opcodes for
+// the BOGUS PPC instruction we invented (when bit 25 is 0) or to mark
+// different stub code (when bit 25 is 1)
+//   - use primary opcode 1 for undefined instruction
+//   - use bit 25 to indicate whether the opcode is for fake-arm
+//     instr or stub-marker
+//   - use the least significant 6-bit to indicate FAKE_OPCODE_T or
+//     MARKER_T
+#define FAKE_OPCODE 1 << 26
+#define MARKER_SUBOPCODE_BIT 25
+#define MARKER_SUBOPCODE 1 << MARKER_SUBOPCODE_BIT
+#define FAKER_SUBOPCODE 0 << MARKER_SUBOPCODE_BIT
+
+enum FAKE_OPCODE_T {
+  fBKPT = 14,
+  fLastFaker  // can't be more than 128 (2^^7)
+};
+#define FAKE_OPCODE_HIGH_BIT 7  // fake opcode has to fall into bit 0~7
+#define F_NEXT_AVAILABLE_STUB_MARKER 369  // must be less than 2^^9 (512)
+#define STUB_MARKER_HIGH_BIT 9  // stub marker has to fall into bit 0~9
+// -----------------------------------------------------------------------------
+// Addressing modes and instruction variants.
+
+// Overflow Exception
+enum OEBit {
+  SetOE = 1 << 10,   // Set overflow exception
+  LeaveOE = 0 << 10  // No overflow exception
+};
+
+// Record bit
+enum RCBit {   // Bit 0
+  SetRC = 1,   // LT,GT,EQ,SO
+  LeaveRC = 0  // None
+};
+
+// Link bit
+enum LKBit {   // Bit 0
+  SetLK = 1,   // Load effective address of next instruction
+  LeaveLK = 0  // No action
+};
+
+enum BOfield {        // Bits 25-21
+  DCBNZF = 0 << 21,   // Decrement CTR; branch if CTR != 0 and condition false
+  DCBEZF = 2 << 21,   // Decrement CTR; branch if CTR == 0 and condition false
+  BF = 4 << 21,       // Branch if condition false
+  DCBNZT = 8 << 21,   // Decrement CTR; branch if CTR != 0 and condition true
+  DCBEZT = 10 << 21,  // Decrement CTR; branch if CTR == 0 and condition true
+  BT = 12 << 21,      // Branch if condition true
+  DCBNZ = 16 << 21,   // Decrement CTR; branch if CTR != 0
+  DCBEZ = 18 << 21,   // Decrement CTR; branch if CTR == 0
+  BA = 20 << 21       // Branch always
+};
+
+#if V8_OS_AIX
+#undef CR_LT
+#undef CR_GT
+#undef CR_EQ
+#undef CR_SO
+#endif
+
+enum CRBit { CR_LT = 0, CR_GT = 1, CR_EQ = 2, CR_SO = 3, CR_FU = 3 };
+
+#define CRWIDTH 4
+
+// -----------------------------------------------------------------------------
+// Supervisor Call (svc) specific support.
+
+// Special Software Interrupt codes when used in the presence of the PPC
+// simulator.
+// svc (formerly swi) provides a 24bit immediate value. Use bits 22:0 for
+// standard SoftwareInterrupCode. Bit 23 is reserved for the stop feature.
+enum SoftwareInterruptCodes {
+  // transition to C code
+  kCallRtRedirected = 0x10,
+  // break point
+  kBreakpoint = 0x821008,  // bits23-0 of 0x7d821008 = twge r2, r2
+  // stop
+  kStopCode = 1 << 23,
+  // info
+  kInfo = 0x9ff808  // bits23-0 of 0x7d9ff808 = twge r31, r31
+};
+const uint32_t kStopCodeMask = kStopCode - 1;
+const uint32_t kMaxStopCode = kStopCode - 1;
+const int32_t kDefaultStopCode = -1;
+
+// FP rounding modes.
+enum FPRoundingMode {
+  RN = 0,  // Round to Nearest.
+  RZ = 1,  // Round towards zero.
+  RP = 2,  // Round towards Plus Infinity.
+  RM = 3,  // Round towards Minus Infinity.
+
+  // Aliases.
+  kRoundToNearest = RN,
+  kRoundToZero = RZ,
+  kRoundToPlusInf = RP,
+  kRoundToMinusInf = RM
+};
+
+const uint32_t kFPRoundingModeMask = 3;
+
+enum CheckForInexactConversion {
+  kCheckForInexactConversion,
+  kDontCheckForInexactConversion
+};
+
+// -----------------------------------------------------------------------------
+// Specific instructions, constants, and masks.
+// These constants are declared in assembler-arm.cc, as they use named registers
+// and other constants.
+
+
+// add(sp, sp, 4) instruction (aka Pop())
+extern const Instr kPopInstruction;
+
+// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
+// register r is not encoded.
+extern const Instr kPushRegPattern;
+
+// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r))
+// register r is not encoded.
+extern const Instr kPopRegPattern;
+
+// use TWI to indicate redirection call for simulation mode
+const Instr rtCallRedirInstr = TWI;
+
+// -----------------------------------------------------------------------------
+// Instruction abstraction.
+
+// The class Instruction enables access to individual fields defined in the PPC
+// architecture instruction set encoding.
+// Note that the Assembler uses typedef int32_t Instr.
+//
+// Example: Test whether the instruction at ptr does set the condition code
+// bits.
+//
+// bool InstructionSetsConditionCodes(byte* ptr) {
+//   Instruction* instr = Instruction::At(ptr);
+//   int type = instr->TypeValue();
+//   return ((type == 0) || (type == 1)) && instr->HasS();
+// }
+//
+class Instruction {
+ public:
+  enum { kInstrSize = 4, kInstrSizeLog2 = 2, kPCReadOffset = 8 };
+
+// Helper macro to define static accessors.
+// We use the cast to char* trick to bypass the strict anti-aliasing rules.
+#define DECLARE_STATIC_TYPED_ACCESSOR(return_type, Name) \
+  static inline return_type Name(Instr instr) {          \
+    char* temp = reinterpret_cast<char*>(&instr);        \
+    return reinterpret_cast<Instruction*>(temp)->Name(); \
+  }
+
+#define DECLARE_STATIC_ACCESSOR(Name) DECLARE_STATIC_TYPED_ACCESSOR(int, Name)
+
+  // Get the raw instruction bits.
+  inline Instr InstructionBits() const {
+    return *reinterpret_cast<const Instr*>(this);
+  }
+
+  // Set the raw instruction bits to value.
+  inline void SetInstructionBits(Instr value) {
+    *reinterpret_cast<Instr*>(this) = value;
+  }
+
+  // Read one particular bit out of the instruction bits.
+  inline int Bit(int nr) const { return (InstructionBits() >> nr) & 1; }
+
+  // Read a bit field's value out of the instruction bits.
+  inline int Bits(int hi, int lo) const {
+    return (InstructionBits() >> lo) & ((2 << (hi - lo)) - 1);
+  }
+
+  // Read a bit field out of the instruction bits.
+  inline int BitField(int hi, int lo) const {
+    return InstructionBits() & (((2 << (hi - lo)) - 1) << lo);
+  }
+
+  // Static support.
+
+  // Read one particular bit out of the instruction bits.
+  static inline int Bit(Instr instr, int nr) { return (instr >> nr) & 1; }
+
+  // Read the value of a bit field out of the instruction bits.
+  static inline int Bits(Instr instr, int hi, int lo) {
+    return (instr >> lo) & ((2 << (hi - lo)) - 1);
+  }
+
+
+  // Read a bit field out of the instruction bits.
+  static inline int BitField(Instr instr, int hi, int lo) {
+    return instr & (((2 << (hi - lo)) - 1) << lo);
+  }
+
+  inline int RSValue() const { return Bits(25, 21); }
+  inline int RTValue() const { return Bits(25, 21); }
+  inline int RAValue() const { return Bits(20, 16); }
+  DECLARE_STATIC_ACCESSOR(RAValue);
+  inline int RBValue() const { return Bits(15, 11); }
+  DECLARE_STATIC_ACCESSOR(RBValue);
+  inline int RCValue() const { return Bits(10, 6); }
+  DECLARE_STATIC_ACCESSOR(RCValue);
+
+  inline int OpcodeValue() const { return static_cast<Opcode>(Bits(31, 26)); }
+  inline Opcode OpcodeField() const {
+    return static_cast<Opcode>(BitField(24, 21));
+  }
+
+  // Fields used in Software interrupt instructions
+  inline SoftwareInterruptCodes SvcValue() const {
+    return static_cast<SoftwareInterruptCodes>(Bits(23, 0));
+  }
+
+  // Instructions are read of out a code stream. The only way to get a
+  // reference to an instruction is to convert a pointer. There is no way
+  // to allocate or create instances of class Instruction.
+  // Use the At(pc) function to create references to Instruction.
+  static Instruction* At(byte* pc) {
+    return reinterpret_cast<Instruction*>(pc);
+  }
+
+
+ private:
+  // We need to prevent the creation of instances of class Instruction.
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction);
+};
+
+
+// Helper functions for converting between register numbers and names.
+class Registers {
+ public:
+  // Return the name of the register.
+  static const char* Name(int reg);
+
+  // Lookup the register number for the name provided.
+  static int Number(const char* name);
+
+  struct RegisterAlias {
+    int reg;
+    const char* name;
+  };
+
+ private:
+  static const char* names_[kNumRegisters];
+  static const RegisterAlias aliases_[];
+};
+
+// Helper functions for converting between FP register numbers and names.
+class FPRegisters {
+ public:
+  // Return the name of the register.
+  static const char* Name(int reg);
+
+  // Lookup the register number for the name provided.
+  static int Number(const char* name);
+
+ private:
+  static const char* names_[kNumFPRegisters];
+};
+}
+}  // namespace v8::internal
+
+#endif  // V8_PPC_CONSTANTS_PPC_H_
diff --git a/src/ppc/cpu-ppc.cc b/src/ppc/cpu-ppc.cc
new file mode 100644
index 0000000..d42420c
--- /dev/null
+++ b/src/ppc/cpu-ppc.cc
@@ -0,0 +1,63 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// CPU specific code for ppc independent of OS goes here.
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/assembler.h"
+#include "src/macro-assembler.h"
+#include "src/simulator.h"  // for cache flushing.
+
+namespace v8 {
+namespace internal {
+
+void CpuFeatures::FlushICache(void* buffer, size_t size) {
+  // Nothing to do flushing no instructions.
+  if (size == 0) {
+    return;
+  }
+
+#if defined(USE_SIMULATOR)
+  // Not generating PPC instructions for C-code. This means that we are
+  // building an PPC emulator based target.  We should notify the simulator
+  // that the Icache was flushed.
+  // None of this code ends up in the snapshot so there are no issues
+  // around whether or not to generate the code when building snapshots.
+  Simulator::FlushICache(Isolate::Current()->simulator_i_cache(), buffer, size);
+#else
+
+  if (CpuFeatures::IsSupported(INSTR_AND_DATA_CACHE_COHERENCY)) {
+    __asm__ __volatile__(
+        "sync \n"
+        "icbi 0, %0  \n"
+        "isync  \n"
+        : /* no output */
+        : "r"(buffer)
+        : "memory");
+    return;
+  }
+
+  const int kCacheLineSize = CpuFeatures::cache_line_size();
+  intptr_t mask = kCacheLineSize - 1;
+  byte *start =
+      reinterpret_cast<byte *>(reinterpret_cast<intptr_t>(buffer) & ~mask);
+  byte *end = static_cast<byte *>(buffer) + size;
+  for (byte *pointer = start; pointer < end; pointer += kCacheLineSize) {
+    __asm__(
+        "dcbf 0, %0  \n"
+        "sync        \n"
+        "icbi 0, %0  \n"
+        "isync       \n"
+        : /* no output */
+        : "r"(pointer));
+  }
+
+#endif  // USE_SIMULATOR
+}
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ppc/debug-ppc.cc b/src/ppc/debug-ppc.cc
new file mode 100644
index 0000000..8106853
--- /dev/null
+++ b/src/ppc/debug-ppc.cc
@@ -0,0 +1,343 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/codegen.h"
+#include "src/debug.h"
+
+namespace v8 {
+namespace internal {
+
+bool BreakLocationIterator::IsDebugBreakAtReturn() {
+  return Debug::IsDebugBreakAtReturn(rinfo());
+}
+
+
+void BreakLocationIterator::SetDebugBreakAtReturn() {
+  // Patch the code changing the return from JS function sequence from
+  //
+  //   LeaveFrame
+  //   blr
+  //
+  // to a call to the debug break return code.
+  // this uses a FIXED_SEQUENCE to load an address constant
+  //
+  //   mov r0, <address>
+  //   mtlr r0
+  //   blrl
+  //   bkpt
+  //
+  CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
+  Assembler::BlockTrampolinePoolScope block_trampoline_pool(patcher.masm());
+  patcher.masm()->mov(
+      v8::internal::r0,
+      Operand(reinterpret_cast<intptr_t>(debug_info_->GetIsolate()
+                                             ->builtins()
+                                             ->Return_DebugBreak()
+                                             ->entry())));
+  patcher.masm()->mtctr(v8::internal::r0);
+  patcher.masm()->bctrl();
+  patcher.masm()->bkpt(0);
+}
+
+
+// Restore the JS frame exit code.
+void BreakLocationIterator::ClearDebugBreakAtReturn() {
+  rinfo()->PatchCode(original_rinfo()->pc(),
+                     Assembler::kJSReturnSequenceInstructions);
+}
+
+
+// A debug break in the frame exit code is identified by the JS frame exit code
+// having been patched with a call instruction.
+bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
+  DCHECK(RelocInfo::IsJSReturn(rinfo->rmode()));
+  return rinfo->IsPatchedReturnSequence();
+}
+
+
+bool BreakLocationIterator::IsDebugBreakAtSlot() {
+  DCHECK(IsDebugBreakSlot());
+  // Check whether the debug break slot instructions have been patched.
+  return rinfo()->IsPatchedDebugBreakSlotSequence();
+}
+
+
+void BreakLocationIterator::SetDebugBreakAtSlot() {
+  DCHECK(IsDebugBreakSlot());
+  // Patch the code changing the debug break slot code from
+  //
+  //   ori r3, r3, 0
+  //   ori r3, r3, 0
+  //   ori r3, r3, 0
+  //   ori r3, r3, 0
+  //   ori r3, r3, 0
+  //
+  // to a call to the debug break code, using a FIXED_SEQUENCE.
+  //
+  //   mov r0, <address>
+  //   mtlr r0
+  //   blrl
+  //
+  CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
+  Assembler::BlockTrampolinePoolScope block_trampoline_pool(patcher.masm());
+  patcher.masm()->mov(
+      v8::internal::r0,
+      Operand(reinterpret_cast<intptr_t>(
+          debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry())));
+  patcher.masm()->mtctr(v8::internal::r0);
+  patcher.masm()->bctrl();
+}
+
+
+void BreakLocationIterator::ClearDebugBreakAtSlot() {
+  DCHECK(IsDebugBreakSlot());
+  rinfo()->PatchCode(original_rinfo()->pc(),
+                     Assembler::kDebugBreakSlotInstructions);
+}
+
+
+#define __ ACCESS_MASM(masm)
+
+
+static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
+                                          RegList object_regs,
+                                          RegList non_object_regs) {
+  {
+    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+
+    // Load padding words on stack.
+    __ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingValue));
+    for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
+      __ push(ip);
+    }
+    __ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
+    __ push(ip);
+
+    // Store the registers containing live values on the expression stack to
+    // make sure that these are correctly updated during GC. Non object values
+    // are stored as a smi causing it to be untouched by GC.
+    DCHECK((object_regs & ~kJSCallerSaved) == 0);
+    DCHECK((non_object_regs & ~kJSCallerSaved) == 0);
+    DCHECK((object_regs & non_object_regs) == 0);
+    if ((object_regs | non_object_regs) != 0) {
+      for (int i = 0; i < kNumJSCallerSaved; i++) {
+        int r = JSCallerSavedCode(i);
+        Register reg = {r};
+        if ((non_object_regs & (1 << r)) != 0) {
+          if (FLAG_debug_code) {
+            __ TestUnsignedSmiCandidate(reg, r0);
+            __ Assert(eq, kUnableToEncodeValueAsSmi, cr0);
+          }
+          __ SmiTag(reg);
+        }
+      }
+      __ MultiPush(object_regs | non_object_regs);
+    }
+
+#ifdef DEBUG
+    __ RecordComment("// Calling from debug break to runtime - come in - over");
+#endif
+    __ mov(r3, Operand::Zero());  // no arguments
+    __ mov(r4, Operand(ExternalReference::debug_break(masm->isolate())));
+
+    CEntryStub ceb(masm->isolate(), 1);
+    __ CallStub(&ceb);
+
+    // Restore the register values from the expression stack.
+    if ((object_regs | non_object_regs) != 0) {
+      __ MultiPop(object_regs | non_object_regs);
+      for (int i = 0; i < kNumJSCallerSaved; i++) {
+        int r = JSCallerSavedCode(i);
+        Register reg = {r};
+        if ((non_object_regs & (1 << r)) != 0) {
+          __ SmiUntag(reg);
+        }
+        if (FLAG_debug_code &&
+            (((object_regs | non_object_regs) & (1 << r)) == 0)) {
+          __ mov(reg, Operand(kDebugZapValue));
+        }
+      }
+    }
+
+    // Don't bother removing padding bytes pushed on the stack
+    // as the frame is going to be restored right away.
+
+    // Leave the internal frame.
+  }
+
+  // Now that the break point has been handled, resume normal execution by
+  // jumping to the target address intended by the caller and that was
+  // overwritten by the address of DebugBreakXXX.
+  ExternalReference after_break_target =
+      ExternalReference::debug_after_break_target_address(masm->isolate());
+  __ mov(ip, Operand(after_break_target));
+  __ LoadP(ip, MemOperand(ip));
+  __ JumpToJSEntry(ip);
+}
+
+
+void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
+  // Register state for CallICStub
+  // ----------- S t a t e -------------
+  //  -- r4 : function
+  //  -- r6 : slot in feedback array (smi)
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, r4.bit() | r6.bit(), 0);
+}
+
+
+void DebugCodegen::GenerateLoadICDebugBreak(MacroAssembler* masm) {
+  // Calling convention for IC load (from ic-ppc.cc).
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register name = LoadDescriptor::NameRegister();
+  RegList regs = receiver.bit() | name.bit();
+  if (FLAG_vector_ics) {
+    regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
+  }
+  Generate_DebugBreakCallHelper(masm, regs, 0);
+}
+
+
+void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
+  // Calling convention for IC store (from ic-ppc.cc).
+  Register receiver = StoreDescriptor::ReceiverRegister();
+  Register name = StoreDescriptor::NameRegister();
+  Register value = StoreDescriptor::ValueRegister();
+  Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit() | value.bit(),
+                                0);
+}
+
+
+void DebugCodegen::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
+  // Calling convention for keyed IC load (from ic-ppc.cc).
+  GenerateLoadICDebugBreak(masm);
+}
+
+
+void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
+  // Calling convention for IC keyed store call (from ic-ppc.cc).
+  Register receiver = StoreDescriptor::ReceiverRegister();
+  Register name = StoreDescriptor::NameRegister();
+  Register value = StoreDescriptor::ValueRegister();
+  Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit() | value.bit(),
+                                0);
+}
+
+
+void DebugCodegen::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
+  // Register state for CompareNil IC
+  // ----------- S t a t e -------------
+  //  -- r3    : value
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, r3.bit(), 0);
+}
+
+
+void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
+  // In places other than IC call sites it is expected that r3 is TOS which
+  // is an object - this is not generally the case so this should be used with
+  // care.
+  Generate_DebugBreakCallHelper(masm, r3.bit(), 0);
+}
+
+
+void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
+  // Register state for CallFunctionStub (from code-stubs-ppc.cc).
+  // ----------- S t a t e -------------
+  //  -- r4 : function
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, r4.bit(), 0);
+}
+
+
+void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
+  // Calling convention for CallConstructStub (from code-stubs-ppc.cc)
+  // ----------- S t a t e -------------
+  //  -- r3     : number of arguments (not smi)
+  //  -- r4     : constructor function
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, r4.bit(), r3.bit());
+}
+
+
+void DebugCodegen::GenerateCallConstructStubRecordDebugBreak(
+    MacroAssembler* masm) {
+  // Calling convention for CallConstructStub (from code-stubs-ppc.cc)
+  // ----------- S t a t e -------------
+  //  -- r3     : number of arguments (not smi)
+  //  -- r4     : constructor function
+  //  -- r5     : feedback array
+  //  -- r6     : feedback slot (smi)
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, r4.bit() | r5.bit() | r6.bit(), r3.bit());
+}
+
+
+void DebugCodegen::GenerateSlot(MacroAssembler* masm) {
+  // Generate enough nop's to make space for a call instruction. Avoid emitting
+  // the trampoline pool in the debug break slot code.
+  Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
+  Label check_codesize;
+  __ bind(&check_codesize);
+  __ RecordDebugBreakSlot();
+  for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
+    __ nop(MacroAssembler::DEBUG_BREAK_NOP);
+  }
+  DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
+            masm->InstructionsGeneratedSince(&check_codesize));
+}
+
+
+void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
+  // In the places where a debug break slot is inserted no registers can contain
+  // object pointers.
+  Generate_DebugBreakCallHelper(masm, 0, 0);
+}
+
+
+void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
+  __ Ret();
+}
+
+
+void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
+  ExternalReference restarter_frame_function_slot =
+      ExternalReference::debug_restarter_frame_function_pointer_address(
+          masm->isolate());
+  __ mov(ip, Operand(restarter_frame_function_slot));
+  __ li(r4, Operand::Zero());
+  __ StoreP(r4, MemOperand(ip, 0));
+
+  // Load the function pointer off of our current stack frame.
+  __ LoadP(r4, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset -
+                                  kPointerSize));
+
+  // Pop return address, frame and constant pool pointer (if
+  // FLAG_enable_ool_constant_pool).
+  __ LeaveFrame(StackFrame::INTERNAL);
+
+  // Load context from the function.
+  __ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
+
+  // Get function code.
+  __ LoadP(ip, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
+  __ LoadP(ip, FieldMemOperand(ip, SharedFunctionInfo::kCodeOffset));
+  __ addi(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+  // Re-run JSFunction, r4 is function, cp is context.
+  __ Jump(ip);
+}
+
+
+const bool LiveEdit::kFrameDropperSupported = true;
+
+#undef __
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ppc/deoptimizer-ppc.cc b/src/ppc/deoptimizer-ppc.cc
new file mode 100644
index 0000000..58e9e93
--- /dev/null
+++ b/src/ppc/deoptimizer-ppc.cc
@@ -0,0 +1,359 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/codegen.h"
+#include "src/deoptimizer.h"
+#include "src/full-codegen.h"
+#include "src/safepoint-table.h"
+
+namespace v8 {
+namespace internal {
+
+const int Deoptimizer::table_entry_size_ = 8;
+
+
+int Deoptimizer::patch_size() {
+#if V8_TARGET_ARCH_PPC64
+  const int kCallInstructionSizeInWords = 7;
+#else
+  const int kCallInstructionSizeInWords = 4;
+#endif
+  return kCallInstructionSizeInWords * Assembler::kInstrSize;
+}
+
+
+void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
+  Address code_start_address = code->instruction_start();
+
+  // Invalidate the relocation information, as it will become invalid by the
+  // code patching below, and is not needed any more.
+  code->InvalidateRelocation();
+
+  if (FLAG_zap_code_space) {
+    // Fail hard and early if we enter this code object again.
+    byte* pointer = code->FindCodeAgeSequence();
+    if (pointer != NULL) {
+      pointer += kNoCodeAgeSequenceLength;
+    } else {
+      pointer = code->instruction_start();
+    }
+    CodePatcher patcher(pointer, 1);
+    patcher.masm()->bkpt(0);
+
+    DeoptimizationInputData* data =
+        DeoptimizationInputData::cast(code->deoptimization_data());
+    int osr_offset = data->OsrPcOffset()->value();
+    if (osr_offset > 0) {
+      CodePatcher osr_patcher(code->instruction_start() + osr_offset, 1);
+      osr_patcher.masm()->bkpt(0);
+    }
+  }
+
+  DeoptimizationInputData* deopt_data =
+      DeoptimizationInputData::cast(code->deoptimization_data());
+#ifdef DEBUG
+  Address prev_call_address = NULL;
+#endif
+  // For each LLazyBailout instruction insert a call to the corresponding
+  // deoptimization entry.
+  for (int i = 0; i < deopt_data->DeoptCount(); i++) {
+    if (deopt_data->Pc(i)->value() == -1) continue;
+    Address call_address = code_start_address + deopt_data->Pc(i)->value();
+    Address deopt_entry = GetDeoptimizationEntry(isolate, i, LAZY);
+    // We need calls to have a predictable size in the unoptimized code, but
+    // this is optimized code, so we don't have to have a predictable size.
+    int call_size_in_bytes = MacroAssembler::CallSizeNotPredictableCodeSize(
+        deopt_entry, kRelocInfo_NONEPTR);
+    int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize;
+    DCHECK(call_size_in_bytes % Assembler::kInstrSize == 0);
+    DCHECK(call_size_in_bytes <= patch_size());
+    CodePatcher patcher(call_address, call_size_in_words);
+    patcher.masm()->Call(deopt_entry, kRelocInfo_NONEPTR);
+    DCHECK(prev_call_address == NULL ||
+           call_address >= prev_call_address + patch_size());
+    DCHECK(call_address + patch_size() <= code->instruction_end());
+#ifdef DEBUG
+    prev_call_address = call_address;
+#endif
+  }
+}
+
+
+void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
+  // Set the register values. The values are not important as there are no
+  // callee saved registers in JavaScript frames, so all registers are
+  // spilled. Registers fp and sp are set to the correct values though.
+
+  for (int i = 0; i < Register::kNumRegisters; i++) {
+    input_->SetRegister(i, i * 4);
+  }
+  input_->SetRegister(sp.code(), reinterpret_cast<intptr_t>(frame->sp()));
+  input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp()));
+  for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) {
+    input_->SetDoubleRegister(i, 0.0);
+  }
+
+  // Fill the frame content from the actual data on the frame.
+  for (unsigned i = 0; i < input_->GetFrameSize(); i += kPointerSize) {
+    input_->SetFrameSlot(
+        i, reinterpret_cast<intptr_t>(Memory::Address_at(tos + i)));
+  }
+}
+
+
+void Deoptimizer::SetPlatformCompiledStubRegisters(
+    FrameDescription* output_frame, CodeStubDescriptor* descriptor) {
+  ApiFunction function(descriptor->deoptimization_handler());
+  ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_);
+  intptr_t handler = reinterpret_cast<intptr_t>(xref.address());
+  int params = descriptor->GetHandlerParameterCount();
+  output_frame->SetRegister(r3.code(), params);
+  output_frame->SetRegister(r4.code(), handler);
+}
+
+
+void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
+  for (int i = 0; i < DoubleRegister::kMaxNumRegisters; ++i) {
+    double double_value = input_->GetDoubleRegister(i);
+    output_frame->SetDoubleRegister(i, double_value);
+  }
+}
+
+
+bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
+  // There is no dynamic alignment padding on PPC in the input frame.
+  return false;
+}
+
+
+#define __ masm()->
+
+// This code tries to be close to ia32 code so that any changes can be
+// easily ported.
+void Deoptimizer::EntryGenerator::Generate() {
+  GeneratePrologue();
+
+  // Unlike on ARM we don't save all the registers, just the useful ones.
+  // For the rest, there are gaps on the stack, so the offsets remain the same.
+  const int kNumberOfRegisters = Register::kNumRegisters;
+
+  RegList restored_regs = kJSCallerSaved | kCalleeSaved;
+  RegList saved_regs = restored_regs | sp.bit();
+
+  const int kDoubleRegsSize =
+      kDoubleSize * DoubleRegister::kMaxNumAllocatableRegisters;
+
+  // Save all FPU registers before messing with them.
+  __ subi(sp, sp, Operand(kDoubleRegsSize));
+  for (int i = 0; i < DoubleRegister::kMaxNumAllocatableRegisters; ++i) {
+    DoubleRegister fpu_reg = DoubleRegister::FromAllocationIndex(i);
+    int offset = i * kDoubleSize;
+    __ stfd(fpu_reg, MemOperand(sp, offset));
+  }
+
+  // Push saved_regs (needed to populate FrameDescription::registers_).
+  // Leave gaps for other registers.
+  __ subi(sp, sp, Operand(kNumberOfRegisters * kPointerSize));
+  for (int16_t i = kNumberOfRegisters - 1; i >= 0; i--) {
+    if ((saved_regs & (1 << i)) != 0) {
+      __ StoreP(ToRegister(i), MemOperand(sp, kPointerSize * i));
+    }
+  }
+
+  const int kSavedRegistersAreaSize =
+      (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
+
+  // Get the bailout id from the stack.
+  __ LoadP(r5, MemOperand(sp, kSavedRegistersAreaSize));
+
+  // Get the address of the location in the code object (r6) (return
+  // address for lazy deoptimization) and compute the fp-to-sp delta in
+  // register r7.
+  __ mflr(r6);
+  // Correct one word for bailout id.
+  __ addi(r7, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
+  __ sub(r7, fp, r7);
+
+  // Allocate a new deoptimizer object.
+  // Pass six arguments in r3 to r8.
+  __ PrepareCallCFunction(6, r8);
+  __ LoadP(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ li(r4, Operand(type()));  // bailout type,
+  // r5: bailout id already loaded.
+  // r6: code address or 0 already loaded.
+  // r7: Fp-to-sp delta.
+  __ mov(r8, Operand(ExternalReference::isolate_address(isolate())));
+  // Call Deoptimizer::New().
+  {
+    AllowExternalCallThatCantCauseGC scope(masm());
+    __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6);
+  }
+
+  // Preserve "deoptimizer" object in register r3 and get the input
+  // frame descriptor pointer to r4 (deoptimizer->input_);
+  __ LoadP(r4, MemOperand(r3, Deoptimizer::input_offset()));
+
+  // Copy core registers into FrameDescription::registers_[kNumRegisters].
+  DCHECK(Register::kNumRegisters == kNumberOfRegisters);
+  for (int i = 0; i < kNumberOfRegisters; i++) {
+    int offset = (i * kPointerSize) + FrameDescription::registers_offset();
+    __ LoadP(r5, MemOperand(sp, i * kPointerSize));
+    __ StoreP(r5, MemOperand(r4, offset));
+  }
+
+  int double_regs_offset = FrameDescription::double_registers_offset();
+  // Copy VFP registers to
+  // double_registers_[DoubleRegister::kNumAllocatableRegisters]
+  for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); ++i) {
+    int dst_offset = i * kDoubleSize + double_regs_offset;
+    int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
+    __ lfd(d0, MemOperand(sp, src_offset));
+    __ stfd(d0, MemOperand(r4, dst_offset));
+  }
+
+  // Remove the bailout id and the saved registers from the stack.
+  __ addi(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
+
+  // Compute a pointer to the unwinding limit in register r5; that is
+  // the first stack slot not part of the input frame.
+  __ LoadP(r5, MemOperand(r4, FrameDescription::frame_size_offset()));
+  __ add(r5, r5, sp);
+
+  // Unwind the stack down to - but not including - the unwinding
+  // limit and copy the contents of the activation frame to the input
+  // frame description.
+  __ addi(r6, r4, Operand(FrameDescription::frame_content_offset()));
+  Label pop_loop;
+  Label pop_loop_header;
+  __ b(&pop_loop_header);
+  __ bind(&pop_loop);
+  __ pop(r7);
+  __ StoreP(r7, MemOperand(r6, 0));
+  __ addi(r6, r6, Operand(kPointerSize));
+  __ bind(&pop_loop_header);
+  __ cmp(r5, sp);
+  __ bne(&pop_loop);
+
+  // Compute the output frame in the deoptimizer.
+  __ push(r3);  // Preserve deoptimizer object across call.
+  // r3: deoptimizer object; r4: scratch.
+  __ PrepareCallCFunction(1, r4);
+  // Call Deoptimizer::ComputeOutputFrames().
+  {
+    AllowExternalCallThatCantCauseGC scope(masm());
+    __ CallCFunction(
+        ExternalReference::compute_output_frames_function(isolate()), 1);
+  }
+  __ pop(r3);  // Restore deoptimizer object (class Deoptimizer).
+
+  // Replace the current (input) frame with the output frames.
+  Label outer_push_loop, inner_push_loop, outer_loop_header, inner_loop_header;
+  // Outer loop state: r7 = current "FrameDescription** output_",
+  // r4 = one past the last FrameDescription**.
+  __ lwz(r4, MemOperand(r3, Deoptimizer::output_count_offset()));
+  __ LoadP(r7, MemOperand(r3, Deoptimizer::output_offset()));  // r7 is output_.
+  __ ShiftLeftImm(r4, r4, Operand(kPointerSizeLog2));
+  __ add(r4, r7, r4);
+  __ b(&outer_loop_header);
+
+  __ bind(&outer_push_loop);
+  // Inner loop state: r5 = current FrameDescription*, r6 = loop index.
+  __ LoadP(r5, MemOperand(r7, 0));  // output_[ix]
+  __ LoadP(r6, MemOperand(r5, FrameDescription::frame_size_offset()));
+  __ b(&inner_loop_header);
+
+  __ bind(&inner_push_loop);
+  __ addi(r6, r6, Operand(-sizeof(intptr_t)));
+  __ add(r9, r5, r6);
+  __ LoadP(r9, MemOperand(r9, FrameDescription::frame_content_offset()));
+  __ push(r9);
+
+  __ bind(&inner_loop_header);
+  __ cmpi(r6, Operand::Zero());
+  __ bne(&inner_push_loop);  // test for gt?
+
+  __ addi(r7, r7, Operand(kPointerSize));
+  __ bind(&outer_loop_header);
+  __ cmp(r7, r4);
+  __ blt(&outer_push_loop);
+
+  __ LoadP(r4, MemOperand(r3, Deoptimizer::input_offset()));
+  for (int i = 0; i < DoubleRegister::kMaxNumAllocatableRegisters; ++i) {
+    const DoubleRegister dreg = DoubleRegister::FromAllocationIndex(i);
+    int src_offset = i * kDoubleSize + double_regs_offset;
+    __ lfd(dreg, MemOperand(r4, src_offset));
+  }
+
+  // Push state, pc, and continuation from the last output frame.
+  __ LoadP(r9, MemOperand(r5, FrameDescription::state_offset()));
+  __ push(r9);
+  __ LoadP(r9, MemOperand(r5, FrameDescription::pc_offset()));
+  __ push(r9);
+  __ LoadP(r9, MemOperand(r5, FrameDescription::continuation_offset()));
+  __ push(r9);
+
+  // Restore the registers from the last output frame.
+  DCHECK(!(ip.bit() & restored_regs));
+  __ mr(ip, r5);
+  for (int i = kNumberOfRegisters - 1; i >= 0; i--) {
+    int offset = (i * kPointerSize) + FrameDescription::registers_offset();
+    if ((restored_regs & (1 << i)) != 0) {
+      __ LoadP(ToRegister(i), MemOperand(ip, offset));
+    }
+  }
+
+  __ InitializeRootRegister();
+
+  __ pop(ip);  // get continuation, leave pc on stack
+  __ pop(r0);
+  __ mtlr(r0);
+  __ Jump(ip);
+  __ stop("Unreachable.");
+}
+
+
+void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
+  Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm());
+
+  // Create a sequence of deoptimization entries.
+  // Note that registers are still live when jumping to an entry.
+  Label done;
+  for (int i = 0; i < count(); i++) {
+    int start = masm()->pc_offset();
+    USE(start);
+    __ li(ip, Operand(i));
+    __ b(&done);
+    DCHECK(masm()->pc_offset() - start == table_entry_size_);
+  }
+  __ bind(&done);
+  __ push(ip);
+}
+
+
+void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
+  SetFrameSlot(offset, value);
+}
+
+
+void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) {
+  SetFrameSlot(offset, value);
+}
+
+
+void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
+#if V8_OOL_CONSTANT_POOL
+  DCHECK(FLAG_enable_ool_constant_pool);
+  SetFrameSlot(offset, value);
+#else
+  // No out-of-line constant pool support.
+  UNREACHABLE();
+#endif
+}
+
+
+#undef __
+}
+}  // namespace v8::internal
diff --git a/src/ppc/disasm-ppc.cc b/src/ppc/disasm-ppc.cc
new file mode 100644
index 0000000..63cec8c
--- /dev/null
+++ b/src/ppc/disasm-ppc.cc
@@ -0,0 +1,1353 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A Disassembler object is used to disassemble a block of code instruction by
+// instruction. The default implementation of the NameConverter object can be
+// overriden to modify register names or to do symbol lookup on addresses.
+//
+// The example below will disassemble a block of code and print it to stdout.
+//
+//   NameConverter converter;
+//   Disassembler d(converter);
+//   for (byte* pc = begin; pc < end;) {
+//     v8::internal::EmbeddedVector<char, 256> buffer;
+//     byte* prev_pc = pc;
+//     pc += d.InstructionDecode(buffer, pc);
+//     printf("%p    %08x      %s\n",
+//            prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer);
+//   }
+//
+// The Disassembler class also has a convenience method to disassemble a block
+// of code into a FILE*, meaning that the above functionality could also be
+// achieved by just calling Disassembler::Disassemble(stdout, begin, end);
+
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/base/platform/platform.h"
+#include "src/disasm.h"
+#include "src/macro-assembler.h"
+#include "src/ppc/constants-ppc.h"
+
+
+namespace v8 {
+namespace internal {
+
+
+//------------------------------------------------------------------------------
+
+// Decoder decodes and disassembles instructions into an output buffer.
+// It uses the converter to convert register names and call destinations into
+// more informative description.
+class Decoder {
+ public:
+  Decoder(const disasm::NameConverter& converter, Vector<char> out_buffer)
+      : converter_(converter), out_buffer_(out_buffer), out_buffer_pos_(0) {
+    out_buffer_[out_buffer_pos_] = '\0';
+  }
+
+  ~Decoder() {}
+
+  // Writes one disassembled instruction into 'buffer' (0-terminated).
+  // Returns the length of the disassembled machine instruction in bytes.
+  int InstructionDecode(byte* instruction);
+
+ private:
+  // Bottleneck functions to print into the out_buffer.
+  void PrintChar(const char ch);
+  void Print(const char* str);
+
+  // Printing of common values.
+  void PrintRegister(int reg);
+  void PrintDRegister(int reg);
+  int FormatFPRegister(Instruction* instr, const char* format);
+  void PrintSoftwareInterrupt(SoftwareInterruptCodes svc);
+
+  // Handle formatting of instructions and their options.
+  int FormatRegister(Instruction* instr, const char* option);
+  int FormatOption(Instruction* instr, const char* option);
+  void Format(Instruction* instr, const char* format);
+  void Unknown(Instruction* instr);
+  void UnknownFormat(Instruction* instr, const char* opcname);
+  void MarkerFormat(Instruction* instr, const char* opcname, int id);
+
+  void DecodeExt1(Instruction* instr);
+  void DecodeExt2(Instruction* instr);
+  void DecodeExt4(Instruction* instr);
+  void DecodeExt5(Instruction* instr);
+
+  const disasm::NameConverter& converter_;
+  Vector<char> out_buffer_;
+  int out_buffer_pos_;
+
+  DISALLOW_COPY_AND_ASSIGN(Decoder);
+};
+
+
+// Support for assertions in the Decoder formatting functions.
+#define STRING_STARTS_WITH(string, compare_string) \
+  (strncmp(string, compare_string, strlen(compare_string)) == 0)
+
+
+// Append the ch to the output buffer.
+void Decoder::PrintChar(const char ch) { out_buffer_[out_buffer_pos_++] = ch; }
+
+
+// Append the str to the output buffer.
+void Decoder::Print(const char* str) {
+  char cur = *str++;
+  while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
+    PrintChar(cur);
+    cur = *str++;
+  }
+  out_buffer_[out_buffer_pos_] = 0;
+}
+
+
+// Print the register name according to the active name converter.
+void Decoder::PrintRegister(int reg) {
+  Print(converter_.NameOfCPURegister(reg));
+}
+
+
+// Print the double FP register name according to the active name converter.
+void Decoder::PrintDRegister(int reg) { Print(FPRegisters::Name(reg)); }
+
+
+// Print SoftwareInterrupt codes. Factoring this out reduces the complexity of
+// the FormatOption method.
+void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes svc) {
+  switch (svc) {
+    case kCallRtRedirected:
+      Print("call rt redirected");
+      return;
+    case kBreakpoint:
+      Print("breakpoint");
+      return;
+    default:
+      if (svc >= kStopCode) {
+        out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d - 0x%x",
+                                    svc & kStopCodeMask, svc & kStopCodeMask);
+      } else {
+        out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", svc);
+      }
+      return;
+  }
+}
+
+
+// Handle all register based formatting in this function to reduce the
+// complexity of FormatOption.
+int Decoder::FormatRegister(Instruction* instr, const char* format) {
+  DCHECK(format[0] == 'r');
+
+  if ((format[1] == 't') || (format[1] == 's')) {  // 'rt & 'rs register
+    int reg = instr->RTValue();
+    PrintRegister(reg);
+    return 2;
+  } else if (format[1] == 'a') {  // 'ra: RA register
+    int reg = instr->RAValue();
+    PrintRegister(reg);
+    return 2;
+  } else if (format[1] == 'b') {  // 'rb: RB register
+    int reg = instr->RBValue();
+    PrintRegister(reg);
+    return 2;
+  }
+
+  UNREACHABLE();
+  return -1;
+}
+
+
+// Handle all FP register based formatting in this function to reduce the
+// complexity of FormatOption.
+int Decoder::FormatFPRegister(Instruction* instr, const char* format) {
+  DCHECK(format[0] == 'D');
+
+  int retval = 2;
+  int reg = -1;
+  if (format[1] == 't') {
+    reg = instr->RTValue();
+  } else if (format[1] == 'a') {
+    reg = instr->RAValue();
+  } else if (format[1] == 'b') {
+    reg = instr->RBValue();
+  } else if (format[1] == 'c') {
+    reg = instr->RCValue();
+  } else {
+    UNREACHABLE();
+  }
+
+  PrintDRegister(reg);
+
+  return retval;
+}
+
+
+// FormatOption takes a formatting string and interprets it based on
+// the current instructions. The format string points to the first
+// character of the option string (the option escape has already been
+// consumed by the caller.)  FormatOption returns the number of
+// characters that were consumed from the formatting string.
+int Decoder::FormatOption(Instruction* instr, const char* format) {
+  switch (format[0]) {
+    case 'o': {
+      if (instr->Bit(10) == 1) {
+        Print("o");
+      }
+      return 1;
+    }
+    case '.': {
+      if (instr->Bit(0) == 1) {
+        Print(".");
+      } else {
+        Print(" ");  // ensure consistent spacing
+      }
+      return 1;
+    }
+    case 'r': {
+      return FormatRegister(instr, format);
+    }
+    case 'D': {
+      return FormatFPRegister(instr, format);
+    }
+    case 'i': {  // int16
+      int32_t value = (instr->Bits(15, 0) << 16) >> 16;
+      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+      return 5;
+    }
+    case 'u': {  // uint16
+      int32_t value = instr->Bits(15, 0);
+      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+      return 6;
+    }
+    case 'l': {
+      // Link (LK) Bit 0
+      if (instr->Bit(0) == 1) {
+        Print("l");
+      }
+      return 1;
+    }
+    case 'a': {
+      // Absolute Address Bit 1
+      if (instr->Bit(1) == 1) {
+        Print("a");
+      }
+      return 1;
+    }
+    case 't': {  // 'target: target of branch instructions
+      // target26 or target16
+      DCHECK(STRING_STARTS_WITH(format, "target"));
+      if ((format[6] == '2') && (format[7] == '6')) {
+        int off = ((instr->Bits(25, 2)) << 8) >> 6;
+        out_buffer_pos_ += SNPrintF(
+            out_buffer_ + out_buffer_pos_, "%+d -> %s", off,
+            converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off));
+        return 8;
+      } else if ((format[6] == '1') && (format[7] == '6')) {
+        int off = ((instr->Bits(15, 2)) << 18) >> 16;
+        out_buffer_pos_ += SNPrintF(
+            out_buffer_ + out_buffer_pos_, "%+d -> %s", off,
+            converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off));
+        return 8;
+      }
+      case 's': {
+        DCHECK(format[1] == 'h');
+        int32_t value = 0;
+        int32_t opcode = instr->OpcodeValue() << 26;
+        int32_t sh = instr->Bits(15, 11);
+        if (opcode == EXT5 ||
+            (opcode == EXT2 && instr->Bits(10, 2) << 2 == SRADIX)) {
+          // SH Bits 1 and 15-11 (split field)
+          value = (sh | (instr->Bit(1) << 5));
+        } else {
+          // SH Bits 15-11
+          value = (sh << 26) >> 26;
+        }
+        out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+        return 2;
+      }
+      case 'm': {
+        int32_t value = 0;
+        if (format[1] == 'e') {
+          if (instr->OpcodeValue() << 26 != EXT5) {
+            // ME Bits 10-6
+            value = (instr->Bits(10, 6) << 26) >> 26;
+          } else {
+            // ME Bits 5 and 10-6 (split field)
+            value = (instr->Bits(10, 6) | (instr->Bit(5) << 5));
+          }
+        } else if (format[1] == 'b') {
+          if (instr->OpcodeValue() << 26 != EXT5) {
+            // MB Bits 5-1
+            value = (instr->Bits(5, 1) << 26) >> 26;
+          } else {
+            // MB Bits 5 and 10-6 (split field)
+            value = (instr->Bits(10, 6) | (instr->Bit(5) << 5));
+          }
+        } else {
+          UNREACHABLE();  // bad format
+        }
+        out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+        return 2;
+      }
+    }
+#if V8_TARGET_ARCH_PPC64
+    case 'd': {  // ds value for offset
+      int32_t value = SIGN_EXT_IMM16(instr->Bits(15, 0) & ~3);
+      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
+      return 1;
+    }
+#endif
+    default: {
+      UNREACHABLE();
+      break;
+    }
+  }
+
+  UNREACHABLE();
+  return -1;
+}
+
+
+// Format takes a formatting string for a whole instruction and prints it into
+// the output buffer. All escaped options are handed to FormatOption to be
+// parsed further.
+void Decoder::Format(Instruction* instr, const char* format) {
+  char cur = *format++;
+  while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
+    if (cur == '\'') {  // Single quote is used as the formatting escape.
+      format += FormatOption(instr, format);
+    } else {
+      out_buffer_[out_buffer_pos_++] = cur;
+    }
+    cur = *format++;
+  }
+  out_buffer_[out_buffer_pos_] = '\0';
+}
+
+
+// The disassembler may end up decoding data inlined in the code. We do not want
+// it to crash if the data does not ressemble any known instruction.
+#define VERIFY(condition) \
+  if (!(condition)) {     \
+    Unknown(instr);       \
+    return;               \
+  }
+
+
+// For currently unimplemented decodings the disassembler calls Unknown(instr)
+// which will just print "unknown" of the instruction bits.
+void Decoder::Unknown(Instruction* instr) { Format(instr, "unknown"); }
+
+
+// For currently unimplemented decodings the disassembler calls
+// UnknownFormat(instr) which will just print opcode name of the
+// instruction bits.
+void Decoder::UnknownFormat(Instruction* instr, const char* name) {
+  char buffer[100];
+  snprintf(buffer, sizeof(buffer), "%s (unknown-format)", name);
+  Format(instr, buffer);
+}
+
+
+void Decoder::MarkerFormat(Instruction* instr, const char* name, int id) {
+  char buffer[100];
+  snprintf(buffer, sizeof(buffer), "%s %d", name, id);
+  Format(instr, buffer);
+}
+
+
+void Decoder::DecodeExt1(Instruction* instr) {
+  switch (instr->Bits(10, 1) << 1) {
+    case MCRF: {
+      UnknownFormat(instr, "mcrf");  // not used by V8
+      break;
+    }
+    case BCLRX: {
+      switch (instr->Bits(25, 21) << 21) {
+        case DCBNZF: {
+          UnknownFormat(instr, "bclrx-dcbnzf");
+          break;
+        }
+        case DCBEZF: {
+          UnknownFormat(instr, "bclrx-dcbezf");
+          break;
+        }
+        case BF: {
+          UnknownFormat(instr, "bclrx-bf");
+          break;
+        }
+        case DCBNZT: {
+          UnknownFormat(instr, "bclrx-dcbbzt");
+          break;
+        }
+        case DCBEZT: {
+          UnknownFormat(instr, "bclrx-dcbnezt");
+          break;
+        }
+        case BT: {
+          UnknownFormat(instr, "bclrx-bt");
+          break;
+        }
+        case DCBNZ: {
+          UnknownFormat(instr, "bclrx-dcbnz");
+          break;
+        }
+        case DCBEZ: {
+          UnknownFormat(instr, "bclrx-dcbez");  // not used by V8
+          break;
+        }
+        case BA: {
+          if (instr->Bit(0) == 1) {
+            Format(instr, "blrl");
+          } else {
+            Format(instr, "blr");
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case BCCTRX: {
+      switch (instr->Bits(25, 21) << 21) {
+        case DCBNZF: {
+          UnknownFormat(instr, "bcctrx-dcbnzf");
+          break;
+        }
+        case DCBEZF: {
+          UnknownFormat(instr, "bcctrx-dcbezf");
+          break;
+        }
+        case BF: {
+          UnknownFormat(instr, "bcctrx-bf");
+          break;
+        }
+        case DCBNZT: {
+          UnknownFormat(instr, "bcctrx-dcbnzt");
+          break;
+        }
+        case DCBEZT: {
+          UnknownFormat(instr, "bcctrx-dcbezf");
+          break;
+        }
+        case BT: {
+          UnknownFormat(instr, "bcctrx-bt");
+          break;
+        }
+        case DCBNZ: {
+          UnknownFormat(instr, "bcctrx-dcbnz");
+          break;
+        }
+        case DCBEZ: {
+          UnknownFormat(instr, "bcctrx-dcbez");
+          break;
+        }
+        case BA: {
+          if (instr->Bit(0) == 1) {
+            Format(instr, "bctrl");
+          } else {
+            Format(instr, "bctr");
+          }
+          break;
+        }
+        default: { UNREACHABLE(); }
+      }
+      break;
+    }
+    case CRNOR: {
+      Format(instr, "crnor (stuff)");
+      break;
+    }
+    case RFI: {
+      Format(instr, "rfi (stuff)");
+      break;
+    }
+    case CRANDC: {
+      Format(instr, "crandc (stuff)");
+      break;
+    }
+    case ISYNC: {
+      Format(instr, "isync (stuff)");
+      break;
+    }
+    case CRXOR: {
+      Format(instr, "crxor (stuff)");
+      break;
+    }
+    case CRNAND: {
+      UnknownFormat(instr, "crnand");
+      break;
+    }
+    case CRAND: {
+      UnknownFormat(instr, "crand");
+      break;
+    }
+    case CREQV: {
+      UnknownFormat(instr, "creqv");
+      break;
+    }
+    case CRORC: {
+      UnknownFormat(instr, "crorc");
+      break;
+    }
+    case CROR: {
+      UnknownFormat(instr, "cror");
+      break;
+    }
+    default: {
+      Unknown(instr);  // not used by V8
+    }
+  }
+}
+
+
+void Decoder::DecodeExt2(Instruction* instr) {
+  // Some encodings are 10-1 bits, handle those first
+  switch (instr->Bits(10, 1) << 1) {
+    case SRWX: {
+      Format(instr, "srw'.    'ra, 'rs, 'rb");
+      return;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case SRDX: {
+      Format(instr, "srd'.    'ra, 'rs, 'rb");
+      return;
+    }
+#endif
+    case SRAW: {
+      Format(instr, "sraw'.   'ra, 'rs, 'rb");
+      return;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case SRAD: {
+      Format(instr, "srad'.   'ra, 'rs, 'rb");
+      return;
+    }
+#endif
+    case SRAWIX: {
+      Format(instr, "srawi'.  'ra,'rs,'sh");
+      return;
+    }
+    case EXTSH: {
+      Format(instr, "extsh'.  'ra, 'rs");
+      return;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case EXTSW: {
+      Format(instr, "extsw'.  'ra, 'rs");
+      return;
+    }
+#endif
+    case EXTSB: {
+      Format(instr, "extsb'.  'ra, 'rs");
+      return;
+    }
+    case LFSX: {
+      Format(instr, "lfsx    'rt, 'ra, 'rb");
+      return;
+    }
+    case LFSUX: {
+      Format(instr, "lfsux   'rt, 'ra, 'rb");
+      return;
+    }
+    case LFDX: {
+      Format(instr, "lfdx    'rt, 'ra, 'rb");
+      return;
+    }
+    case LFDUX: {
+      Format(instr, "lfdux   'rt, 'ra, 'rb");
+      return;
+    }
+    case STFSX: {
+      Format(instr, "stfsx    'rs, 'ra, 'rb");
+      return;
+    }
+    case STFSUX: {
+      Format(instr, "stfsux   'rs, 'ra, 'rb");
+      return;
+    }
+    case STFDX: {
+      Format(instr, "stfdx    'rs, 'ra, 'rb");
+      return;
+    }
+    case STFDUX: {
+      Format(instr, "stfdux   'rs, 'ra, 'rb");
+      return;
+    }
+  }
+
+  switch (instr->Bits(10, 2) << 2) {
+    case SRADIX: {
+      Format(instr, "sradi'.  'ra,'rs,'sh");
+      return;
+    }
+  }
+
+  // ?? are all of these xo_form?
+  switch (instr->Bits(9, 1) << 1) {
+    case CMP: {
+#if V8_TARGET_ARCH_PPC64
+      if (instr->Bit(21)) {
+#endif
+        Format(instr, "cmp     'ra, 'rb");
+#if V8_TARGET_ARCH_PPC64
+      } else {
+        Format(instr, "cmpw    'ra, 'rb");
+      }
+#endif
+      break;
+    }
+    case SLWX: {
+      Format(instr, "slw'.   'ra, 'rs, 'rb");
+      break;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case SLDX: {
+      Format(instr, "sld'.   'ra, 'rs, 'rb");
+      break;
+    }
+#endif
+    case SUBFCX: {
+      Format(instr, "subfc'. 'rt, 'ra, 'rb");
+      break;
+    }
+    case ADDCX: {
+      Format(instr, "addc'.   'rt, 'ra, 'rb");
+      break;
+    }
+    case CNTLZWX: {
+      Format(instr, "cntlzw'. 'ra, 'rs");
+      break;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case CNTLZDX: {
+      Format(instr, "cntlzd'. 'ra, 'rs");
+      break;
+    }
+#endif
+    case ANDX: {
+      Format(instr, "and'.    'ra, 'rs, 'rb");
+      break;
+    }
+    case ANDCX: {
+      Format(instr, "andc'.   'ra, 'rs, 'rb");
+      break;
+    }
+    case CMPL: {
+#if V8_TARGET_ARCH_PPC64
+      if (instr->Bit(21)) {
+#endif
+        Format(instr, "cmpl    'ra, 'rb");
+#if V8_TARGET_ARCH_PPC64
+      } else {
+        Format(instr, "cmplw   'ra, 'rb");
+      }
+#endif
+      break;
+    }
+    case NEGX: {
+      Format(instr, "neg'.    'rt, 'ra");
+      break;
+    }
+    case NORX: {
+      Format(instr, "nor'.    'rt, 'ra, 'rb");
+      break;
+    }
+    case SUBFX: {
+      Format(instr, "subf'.   'rt, 'ra, 'rb");
+      break;
+    }
+    case MULHWX: {
+      Format(instr, "mulhw'o'.  'rt, 'ra, 'rb");
+      break;
+    }
+    case ADDZEX: {
+      Format(instr, "addze'.   'rt, 'ra");
+      break;
+    }
+    case MULLW: {
+      Format(instr, "mullw'o'.  'rt, 'ra, 'rb");
+      break;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case MULLD: {
+      Format(instr, "mulld'o'.  'rt, 'ra, 'rb");
+      break;
+    }
+#endif
+    case DIVW: {
+      Format(instr, "divw'o'.   'rt, 'ra, 'rb");
+      break;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case DIVD: {
+      Format(instr, "divd'o'.   'rt, 'ra, 'rb");
+      break;
+    }
+#endif
+    case ADDX: {
+      Format(instr, "add'o     'rt, 'ra, 'rb");
+      break;
+    }
+    case XORX: {
+      Format(instr, "xor'.    'ra, 'rs, 'rb");
+      break;
+    }
+    case ORX: {
+      if (instr->RTValue() == instr->RBValue()) {
+        Format(instr, "mr      'ra, 'rb");
+      } else {
+        Format(instr, "or      'ra, 'rs, 'rb");
+      }
+      break;
+    }
+    case MFSPR: {
+      int spr = instr->Bits(20, 11);
+      if (256 == spr) {
+        Format(instr, "mflr    'rt");
+      } else {
+        Format(instr, "mfspr   'rt ??");
+      }
+      break;
+    }
+    case MTSPR: {
+      int spr = instr->Bits(20, 11);
+      if (256 == spr) {
+        Format(instr, "mtlr    'rt");
+      } else if (288 == spr) {
+        Format(instr, "mtctr   'rt");
+      } else {
+        Format(instr, "mtspr   'rt ??");
+      }
+      break;
+    }
+    case MFCR: {
+      Format(instr, "mfcr    'rt");
+      break;
+    }
+    case STWX: {
+      Format(instr, "stwx    'rs, 'ra, 'rb");
+      break;
+    }
+    case STWUX: {
+      Format(instr, "stwux   'rs, 'ra, 'rb");
+      break;
+    }
+    case STBX: {
+      Format(instr, "stbx    'rs, 'ra, 'rb");
+      break;
+    }
+    case STBUX: {
+      Format(instr, "stbux   'rs, 'ra, 'rb");
+      break;
+    }
+    case STHX: {
+      Format(instr, "sthx    'rs, 'ra, 'rb");
+      break;
+    }
+    case STHUX: {
+      Format(instr, "sthux   'rs, 'ra, 'rb");
+      break;
+    }
+    case LWZX: {
+      Format(instr, "lwzx    'rt, 'ra, 'rb");
+      break;
+    }
+    case LWZUX: {
+      Format(instr, "lwzux   'rt, 'ra, 'rb");
+      break;
+    }
+    case LBZX: {
+      Format(instr, "lbzx    'rt, 'ra, 'rb");
+      break;
+    }
+    case LBZUX: {
+      Format(instr, "lbzux   'rt, 'ra, 'rb");
+      break;
+    }
+    case LHZX: {
+      Format(instr, "lhzx    'rt, 'ra, 'rb");
+      break;
+    }
+    case LHZUX: {
+      Format(instr, "lhzux   'rt, 'ra, 'rb");
+      break;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case LDX: {
+      Format(instr, "ldx     'rt, 'ra, 'rb");
+      break;
+    }
+    case LDUX: {
+      Format(instr, "ldux    'rt, 'ra, 'rb");
+      break;
+    }
+    case STDX: {
+      Format(instr, "stdx    'rt, 'ra, 'rb");
+      break;
+    }
+    case STDUX: {
+      Format(instr, "stdux   'rt, 'ra, 'rb");
+      break;
+    }
+    case MFVSRD: {
+      Format(instr, "mffprd  'ra, 'Dt");
+      break;
+    }
+    case MFVSRWZ: {
+      Format(instr, "mffprwz 'ra, 'Dt");
+      break;
+    }
+    case MTVSRD: {
+      Format(instr, "mtfprd  'Dt, 'ra");
+      break;
+    }
+    case MTVSRWA: {
+      Format(instr, "mtfprwa 'Dt, 'ra");
+      break;
+    }
+    case MTVSRWZ: {
+      Format(instr, "mtfprwz 'Dt, 'ra");
+      break;
+    }
+#endif
+    default: {
+      Unknown(instr);  // not used by V8
+    }
+  }
+}
+
+
+void Decoder::DecodeExt4(Instruction* instr) {
+  switch (instr->Bits(5, 1) << 1) {
+    case FDIV: {
+      Format(instr, "fdiv'.   'Dt, 'Da, 'Db");
+      return;
+    }
+    case FSUB: {
+      Format(instr, "fsub'.   'Dt, 'Da, 'Db");
+      return;
+    }
+    case FADD: {
+      Format(instr, "fadd'.   'Dt, 'Da, 'Db");
+      return;
+    }
+    case FSQRT: {
+      Format(instr, "fsqrt'.  'Dt, 'Db");
+      return;
+    }
+    case FSEL: {
+      Format(instr, "fsel'.   'Dt, 'Da, 'Dc, 'Db");
+      return;
+    }
+    case FMUL: {
+      Format(instr, "fmul'.   'Dt, 'Da, 'Dc");
+      return;
+    }
+    case FMSUB: {
+      Format(instr, "fmsub'.  'Dt, 'Da, 'Dc, 'Db");
+      return;
+    }
+    case FMADD: {
+      Format(instr, "fmadd'.  'Dt, 'Da, 'Dc, 'Db");
+      return;
+    }
+  }
+
+  switch (instr->Bits(10, 1) << 1) {
+    case FCMPU: {
+      Format(instr, "fcmpu   'Da, 'Db");
+      break;
+    }
+    case FRSP: {
+      Format(instr, "frsp'.   'Dt, 'Db");
+      break;
+    }
+    case FCFID: {
+      Format(instr, "fcfid'.  'Dt, 'Db");
+      break;
+    }
+    case FCTID: {
+      Format(instr, "fctid   'Dt, 'Db");
+      break;
+    }
+    case FCTIDZ: {
+      Format(instr, "fctidz  'Dt, 'Db");
+      break;
+    }
+    case FCTIW: {
+      Format(instr, "fctiw'. 'Dt, 'Db");
+      break;
+    }
+    case FCTIWZ: {
+      Format(instr, "fctiwz'. 'Dt, 'Db");
+      break;
+    }
+    case FMR: {
+      Format(instr, "fmr'.    'Dt, 'Db");
+      break;
+    }
+    case MTFSFI: {
+      Format(instr, "mtfsfi'.  ?,?");
+      break;
+    }
+    case MFFS: {
+      Format(instr, "mffs'.   'Dt");
+      break;
+    }
+    case MTFSF: {
+      Format(instr, "mtfsf'.  'Db ?,?,?");
+      break;
+    }
+    case FABS: {
+      Format(instr, "fabs'.   'Dt, 'Db");
+      break;
+    }
+    case FRIM: {
+      Format(instr, "frim    'Dt, 'Db");
+      break;
+    }
+    case FNEG: {
+      Format(instr, "fneg'.   'Dt, 'Db");
+      break;
+    }
+    default: {
+      Unknown(instr);  // not used by V8
+    }
+  }
+}
+
+
+void Decoder::DecodeExt5(Instruction* instr) {
+  switch (instr->Bits(4, 2) << 2) {
+    case RLDICL: {
+      Format(instr, "rldicl'. 'ra, 'rs, 'sh, 'mb");
+      return;
+    }
+    case RLDICR: {
+      Format(instr, "rldicr'. 'ra, 'rs, 'sh, 'me");
+      return;
+    }
+    case RLDIC: {
+      Format(instr, "rldic'.  'ra, 'rs, 'sh, 'mb");
+      return;
+    }
+    case RLDIMI: {
+      Format(instr, "rldimi'. 'ra, 'rs, 'sh, 'mb");
+      return;
+    }
+  }
+  switch (instr->Bits(4, 1) << 1) {
+    case RLDCL: {
+      Format(instr, "rldcl'.  'ra, 'rs, 'sb, 'mb");
+      return;
+    }
+  }
+  Unknown(instr);  // not used by V8
+}
+
+#undef VERIFIY
+
+// Disassemble the instruction at *instr_ptr into the output buffer.
+int Decoder::InstructionDecode(byte* instr_ptr) {
+  Instruction* instr = Instruction::At(instr_ptr);
+  // Print raw instruction bytes.
+  out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%08x       ",
+                              instr->InstructionBits());
+
+  switch (instr->OpcodeValue() << 26) {
+    case TWI: {
+      PrintSoftwareInterrupt(instr->SvcValue());
+      break;
+    }
+    case MULLI: {
+      UnknownFormat(instr, "mulli");
+      break;
+    }
+    case SUBFIC: {
+      Format(instr, "subfic  'rt, 'ra, 'int16");
+      break;
+    }
+    case CMPLI: {
+#if V8_TARGET_ARCH_PPC64
+      if (instr->Bit(21)) {
+#endif
+        Format(instr, "cmpli   'ra, 'uint16");
+#if V8_TARGET_ARCH_PPC64
+      } else {
+        Format(instr, "cmplwi  'ra, 'uint16");
+      }
+#endif
+      break;
+    }
+    case CMPI: {
+#if V8_TARGET_ARCH_PPC64
+      if (instr->Bit(21)) {
+#endif
+        Format(instr, "cmpi    'ra, 'int16");
+#if V8_TARGET_ARCH_PPC64
+      } else {
+        Format(instr, "cmpwi   'ra, 'int16");
+      }
+#endif
+      break;
+    }
+    case ADDIC: {
+      Format(instr, "addic   'rt, 'ra, 'int16");
+      break;
+    }
+    case ADDICx: {
+      UnknownFormat(instr, "addicx");
+      break;
+    }
+    case ADDI: {
+      if (instr->RAValue() == 0) {
+        // this is load immediate
+        Format(instr, "li      'rt, 'int16");
+      } else {
+        Format(instr, "addi    'rt, 'ra, 'int16");
+      }
+      break;
+    }
+    case ADDIS: {
+      if (instr->RAValue() == 0) {
+        Format(instr, "lis     'rt, 'int16");
+      } else {
+        Format(instr, "addis   'rt, 'ra, 'int16");
+      }
+      break;
+    }
+    case BCX: {
+      int bo = instr->Bits(25, 21) << 21;
+      int bi = instr->Bits(20, 16);
+      switch (bi) {
+        case 2:
+        case 30:
+          if (BT == bo) {
+            Format(instr, "beq'l'a 'target16");
+            break;
+          }
+          if (BF == bo) {
+            Format(instr, "bne'l'a 'target16");
+            break;
+          }
+          Format(instr, "bc'l'a 'target16");
+          break;
+        case 29:
+          if (BT == bo) {
+            Format(instr, "bgt'l'a 'target16");
+            break;
+          }
+          if (BF == bo) {
+            Format(instr, "ble'l'a 'target16");
+            break;
+          }
+          Format(instr, "bc'l'a 'target16");
+          break;
+        case 28:
+          if (BT == bo) {
+            Format(instr, "blt'l'a 'target16");
+            break;
+          }
+          if (BF == bo) {
+            Format(instr, "bge'l'a 'target16");
+            break;
+          }
+          Format(instr, "bc'l'a 'target16");
+          break;
+        default:
+          Format(instr, "bc'l'a 'target16");
+          break;
+      }
+      break;
+    }
+    case SC: {
+      UnknownFormat(instr, "sc");
+      break;
+    }
+    case BX: {
+      Format(instr, "b'l'a 'target26");
+      break;
+    }
+    case EXT1: {
+      DecodeExt1(instr);
+      break;
+    }
+    case RLWIMIX: {
+      Format(instr, "rlwimi'. 'ra, 'rs, 'sh, 'me, 'mb");
+      break;
+    }
+    case RLWINMX: {
+      Format(instr, "rlwinm'. 'ra, 'rs, 'sh, 'me, 'mb");
+      break;
+    }
+    case RLWNMX: {
+      Format(instr, "rlwnm'.  'ra, 'rs, 'rb, 'me, 'mb");
+      break;
+    }
+    case ORI: {
+      Format(instr, "ori     'ra, 'rs, 'uint16");
+      break;
+    }
+    case ORIS: {
+      Format(instr, "oris    'ra, 'rs, 'uint16");
+      break;
+    }
+    case XORI: {
+      Format(instr, "xori    'ra, 'rs, 'uint16");
+      break;
+    }
+    case XORIS: {
+      Format(instr, "xoris   'ra, 'rs, 'uint16");
+      break;
+    }
+    case ANDIx: {
+      Format(instr, "andi.   'ra, 'rs, 'uint16");
+      break;
+    }
+    case ANDISx: {
+      Format(instr, "andis.  'ra, 'rs, 'uint16");
+      break;
+    }
+    case EXT2: {
+      DecodeExt2(instr);
+      break;
+    }
+    case LWZ: {
+      Format(instr, "lwz     'rt, 'int16('ra)");
+      break;
+    }
+    case LWZU: {
+      Format(instr, "lwzu    'rt, 'int16('ra)");
+      break;
+    }
+    case LBZ: {
+      Format(instr, "lbz     'rt, 'int16('ra)");
+      break;
+    }
+    case LBZU: {
+      Format(instr, "lbzu    'rt, 'int16('ra)");
+      break;
+    }
+    case STW: {
+      Format(instr, "stw     'rs, 'int16('ra)");
+      break;
+    }
+    case STWU: {
+      Format(instr, "stwu    'rs, 'int16('ra)");
+      break;
+    }
+    case STB: {
+      Format(instr, "stb     'rs, 'int16('ra)");
+      break;
+    }
+    case STBU: {
+      Format(instr, "stbu    'rs, 'int16('ra)");
+      break;
+    }
+    case LHZ: {
+      Format(instr, "lhz     'rt, 'int16('ra)");
+      break;
+    }
+    case LHZU: {
+      Format(instr, "lhzu    'rt, 'int16('ra)");
+      break;
+    }
+    case LHA: {
+      Format(instr, "lha     'rt, 'int16('ra)");
+      break;
+    }
+    case LHAU: {
+      Format(instr, "lhau    'rt, 'int16('ra)");
+      break;
+    }
+    case STH: {
+      Format(instr, "sth 'rs, 'int16('ra)");
+      break;
+    }
+    case STHU: {
+      Format(instr, "sthu 'rs, 'int16('ra)");
+      break;
+    }
+    case LMW: {
+      UnknownFormat(instr, "lmw");
+      break;
+    }
+    case STMW: {
+      UnknownFormat(instr, "stmw");
+      break;
+    }
+    case LFS: {
+      Format(instr, "lfs     'Dt, 'int16('ra)");
+      break;
+    }
+    case LFSU: {
+      Format(instr, "lfsu    'Dt, 'int16('ra)");
+      break;
+    }
+    case LFD: {
+      Format(instr, "lfd     'Dt, 'int16('ra)");
+      break;
+    }
+    case LFDU: {
+      Format(instr, "lfdu    'Dt, 'int16('ra)");
+      break;
+    }
+    case STFS: {
+      Format(instr, "stfs    'Dt, 'int16('ra)");
+      break;
+    }
+    case STFSU: {
+      Format(instr, "stfsu   'Dt, 'int16('ra)");
+      break;
+    }
+    case STFD: {
+      Format(instr, "stfd    'Dt, 'int16('ra)");
+      break;
+    }
+    case STFDU: {
+      Format(instr, "stfdu   'Dt, 'int16('ra)");
+      break;
+    }
+    case EXT3:
+    case EXT4: {
+      DecodeExt4(instr);
+      break;
+    }
+    case EXT5: {
+      DecodeExt5(instr);
+      break;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case LD: {
+      switch (instr->Bits(1, 0)) {
+        case 0:
+          Format(instr, "ld      'rt, 'd('ra)");
+          break;
+        case 1:
+          Format(instr, "ldu     'rt, 'd('ra)");
+          break;
+        case 2:
+          Format(instr, "lwa     'rt, 'd('ra)");
+          break;
+      }
+      break;
+    }
+    case STD: {  // could be STD or STDU
+      if (instr->Bit(0) == 0) {
+        Format(instr, "std     'rs, 'd('ra)");
+      } else {
+        Format(instr, "stdu    'rs, 'd('ra)");
+      }
+      break;
+    }
+#endif
+
+    case FAKE_OPCODE: {
+      if (instr->Bits(MARKER_SUBOPCODE_BIT, MARKER_SUBOPCODE_BIT) == 1) {
+        int marker_code = instr->Bits(STUB_MARKER_HIGH_BIT, 0);
+        DCHECK(marker_code < F_NEXT_AVAILABLE_STUB_MARKER);
+        MarkerFormat(instr, "stub-marker ", marker_code);
+      } else {
+        int fake_opcode = instr->Bits(FAKE_OPCODE_HIGH_BIT, 0);
+        MarkerFormat(instr, "faker-opcode ", fake_opcode);
+      }
+      break;
+    }
+    default: {
+      Unknown(instr);
+      break;
+    }
+  }
+
+  return Instruction::kInstrSize;
+}
+}
+}  // namespace v8::internal
+
+
+//------------------------------------------------------------------------------
+
+namespace disasm {
+
+
+const char* NameConverter::NameOfAddress(byte* addr) const {
+  v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
+  return tmp_buffer_.start();
+}
+
+
+const char* NameConverter::NameOfConstant(byte* addr) const {
+  return NameOfAddress(addr);
+}
+
+
+const char* NameConverter::NameOfCPURegister(int reg) const {
+  return v8::internal::Registers::Name(reg);
+}
+
+const char* NameConverter::NameOfByteCPURegister(int reg) const {
+  UNREACHABLE();  // PPC does not have the concept of a byte register
+  return "nobytereg";
+}
+
+
+const char* NameConverter::NameOfXMMRegister(int reg) const {
+  UNREACHABLE();  // PPC does not have any XMM registers
+  return "noxmmreg";
+}
+
+const char* NameConverter::NameInCode(byte* addr) const {
+  // The default name converter is called for unknown code. So we will not try
+  // to access any memory.
+  return "";
+}
+
+
+//------------------------------------------------------------------------------
+
+Disassembler::Disassembler(const NameConverter& converter)
+    : converter_(converter) {}
+
+
+Disassembler::~Disassembler() {}
+
+
+int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
+                                    byte* instruction) {
+  v8::internal::Decoder d(converter_, buffer);
+  return d.InstructionDecode(instruction);
+}
+
+
+// The PPC assembler does not currently use constant pools.
+int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
+
+
+void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
+  NameConverter converter;
+  Disassembler d(converter);
+  for (byte* pc = begin; pc < end;) {
+    v8::internal::EmbeddedVector<char, 128> buffer;
+    buffer[0] = '\0';
+    byte* prev_pc = pc;
+    pc += d.InstructionDecode(buffer, pc);
+    v8::internal::PrintF(f, "%p    %08x      %s\n", prev_pc,
+                         *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
+  }
+}
+
+
+}  // namespace disasm
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ppc/frames-ppc.cc b/src/ppc/frames-ppc.cc
new file mode 100644
index 0000000..4b52882
--- /dev/null
+++ b/src/ppc/frames-ppc.cc
@@ -0,0 +1,60 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/assembler.h"
+#include "src/frames.h"
+#include "src/macro-assembler.h"
+
+#include "src/ppc/assembler-ppc.h"
+#include "src/ppc/assembler-ppc-inl.h"
+#include "src/ppc/macro-assembler-ppc.h"
+
+namespace v8 {
+namespace internal {
+
+
+Register JavaScriptFrame::fp_register() { return v8::internal::fp; }
+Register JavaScriptFrame::context_register() { return cp; }
+Register JavaScriptFrame::constant_pool_pointer_register() {
+#if V8_OOL_CONSTANT_POOL
+  DCHECK(FLAG_enable_ool_constant_pool);
+  return kConstantPoolRegister;
+#else
+  UNREACHABLE();
+  return no_reg;
+#endif
+}
+
+
+Register StubFailureTrampolineFrame::fp_register() { return v8::internal::fp; }
+Register StubFailureTrampolineFrame::context_register() { return cp; }
+Register StubFailureTrampolineFrame::constant_pool_pointer_register() {
+#if V8_OOL_CONSTANT_POOL
+  DCHECK(FLAG_enable_ool_constant_pool);
+  return kConstantPoolRegister;
+#else
+  UNREACHABLE();
+  return no_reg;
+#endif
+}
+
+
+Object*& ExitFrame::constant_pool_slot() const {
+#if V8_OOL_CONSTANT_POOL
+  DCHECK(FLAG_enable_ool_constant_pool);
+  const int offset = ExitFrameConstants::kConstantPoolOffset;
+  return Memory::Object_at(fp() + offset);
+#else
+  UNREACHABLE();
+  return Memory::Object_at(NULL);
+#endif
+}
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ppc/frames-ppc.h b/src/ppc/frames-ppc.h
new file mode 100644
index 0000000..f00fa66
--- /dev/null
+++ b/src/ppc/frames-ppc.h
@@ -0,0 +1,202 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PPC_FRAMES_PPC_H_
+#define V8_PPC_FRAMES_PPC_H_
+
+namespace v8 {
+namespace internal {
+
+
+// Register list in load/store instructions
+// Note that the bit values must match those used in actual instruction encoding
+const int kNumRegs = 32;
+
+
+// Caller-saved/arguments registers
+const RegList kJSCallerSaved = 1 << 3 |   // r3  a1
+                               1 << 4 |   // r4  a2
+                               1 << 5 |   // r5  a3
+                               1 << 6 |   // r6  a4
+                               1 << 7 |   // r7  a5
+                               1 << 8 |   // r8  a6
+                               1 << 9 |   // r9  a7
+                               1 << 10 |  // r10 a8
+                               1 << 11;
+
+const int kNumJSCallerSaved = 9;
+
+// Return the code of the n-th caller-saved register available to JavaScript
+// e.g. JSCallerSavedReg(0) returns r0.code() == 0
+int JSCallerSavedCode(int n);
+
+
+// Callee-saved registers preserved when switching from C to JavaScript
+const RegList kCalleeSaved = 1 << 14 |  // r14
+                             1 << 15 |  // r15
+                             1 << 16 |  // r16
+                             1 << 17 |  // r17
+                             1 << 18 |  // r18
+                             1 << 19 |  // r19
+                             1 << 20 |  // r20
+                             1 << 21 |  // r21
+                             1 << 22 |  // r22
+                             1 << 23 |  // r23
+                             1 << 24 |  // r24
+                             1 << 25 |  // r25
+                             1 << 26 |  // r26
+                             1 << 27 |  // r27
+                             1 << 28 |  // r28
+                             1 << 29 |  // r29
+                             1 << 30 |  // r20
+                             1 << 31;   // r31
+
+
+const int kNumCalleeSaved = 18;
+
+// Number of registers for which space is reserved in safepoints. Must be a
+// multiple of 8.
+// TODO(regis): Only 8 registers may actually be sufficient. Revisit.
+const int kNumSafepointRegisters = 32;
+
+// Define the list of registers actually saved at safepoints.
+// Note that the number of saved registers may be smaller than the reserved
+// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
+const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
+const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
+
+// The following constants describe the stack frame linkage area as
+// defined by the ABI.  Note that kNumRequiredStackFrameSlots must
+// satisfy alignment requirements (rounding up if required).
+#if V8_TARGET_ARCH_PPC64 && V8_TARGET_LITTLE_ENDIAN
+// [0] back chain
+// [1] condition register save area
+// [2] link register save area
+// [3] TOC save area
+// [4] Parameter1 save area
+// ...
+// [11] Parameter8 save area
+// [12] Parameter9 slot (if necessary)
+// ...
+const int kNumRequiredStackFrameSlots = 12;
+const int kStackFrameLRSlot = 2;
+const int kStackFrameExtraParamSlot = 12;
+#elif V8_OS_AIX || V8_TARGET_ARCH_PPC64
+// [0] back chain
+// [1] condition register save area
+// [2] link register save area
+// [3] reserved for compiler
+// [4] reserved by binder
+// [5] TOC save area
+// [6] Parameter1 save area
+// ...
+// [13] Parameter8 save area
+// [14] Parameter9 slot (if necessary)
+// ...
+#if V8_TARGET_ARCH_PPC64
+const int kNumRequiredStackFrameSlots = 14;
+#else
+const int kNumRequiredStackFrameSlots = 16;
+#endif
+const int kStackFrameLRSlot = 2;
+const int kStackFrameExtraParamSlot = 14;
+#else
+// [0] back chain
+// [1] link register save area
+// [2] Parameter9 slot (if necessary)
+// ...
+const int kNumRequiredStackFrameSlots = 4;
+const int kStackFrameLRSlot = 1;
+const int kStackFrameExtraParamSlot = 2;
+#endif
+
+// ----------------------------------------------------
+
+
+class EntryFrameConstants : public AllStatic {
+ public:
+  static const int kCallerFPOffset =
+      -(StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize);
+};
+
+
+class ExitFrameConstants : public AllStatic {
+ public:
+#if V8_OOL_CONSTANT_POOL
+  static const int kFrameSize = 3 * kPointerSize;
+  static const int kConstantPoolOffset = -3 * kPointerSize;
+#else
+  static const int kFrameSize = 2 * kPointerSize;
+  static const int kConstantPoolOffset = 0;  // Not used.
+#endif
+  static const int kCodeOffset = -2 * kPointerSize;
+  static const int kSPOffset = -1 * kPointerSize;
+
+  // The caller fields are below the frame pointer on the stack.
+  static const int kCallerFPOffset = 0 * kPointerSize;
+  // The calling JS function is below FP.
+  static const int kCallerPCOffset = 1 * kPointerSize;
+
+  // FP-relative displacement of the caller's SP.  It points just
+  // below the saved PC.
+  static const int kCallerSPDisplacement = 2 * kPointerSize;
+};
+
+
+class JavaScriptFrameConstants : public AllStatic {
+ public:
+  // FP-relative.
+  static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset;
+  static const int kLastParameterOffset = +2 * kPointerSize;
+  static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset;
+
+  // Caller SP-relative.
+  static const int kParam0Offset = -2 * kPointerSize;
+  static const int kReceiverOffset = -1 * kPointerSize;
+};
+
+
+class ArgumentsAdaptorFrameConstants : public AllStatic {
+ public:
+  // FP-relative.
+  static const int kLengthOffset = StandardFrameConstants::kExpressionsOffset;
+
+  static const int kFrameSize =
+      StandardFrameConstants::kFixedFrameSize + kPointerSize;
+};
+
+
+class ConstructFrameConstants : public AllStatic {
+ public:
+  // FP-relative.
+  static const int kImplicitReceiverOffset = -6 * kPointerSize;
+  static const int kConstructorOffset = -5 * kPointerSize;
+  static const int kLengthOffset = -4 * kPointerSize;
+  static const int kCodeOffset = StandardFrameConstants::kExpressionsOffset;
+
+  static const int kFrameSize =
+      StandardFrameConstants::kFixedFrameSize + 4 * kPointerSize;
+};
+
+
+class InternalFrameConstants : public AllStatic {
+ public:
+  // FP-relative.
+  static const int kCodeOffset = StandardFrameConstants::kExpressionsOffset;
+};
+
+
+inline Object* JavaScriptFrame::function_slot_object() const {
+  const int offset = JavaScriptFrameConstants::kFunctionOffset;
+  return Memory::Object_at(fp() + offset);
+}
+
+
+inline void StackHandler::SetFp(Address slot, Address fp) {
+  Memory::Address_at(slot) = fp;
+}
+}
+}  // namespace v8::internal
+
+#endif  // V8_PPC_FRAMES_PPC_H_
diff --git a/src/ppc/full-codegen-ppc.cc b/src/ppc/full-codegen-ppc.cc
new file mode 100644
index 0000000..1bb4f54
--- /dev/null
+++ b/src/ppc/full-codegen-ppc.cc
@@ -0,0 +1,5290 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/code-factory.h"
+#include "src/code-stubs.h"
+#include "src/codegen.h"
+#include "src/compiler.h"
+#include "src/debug.h"
+#include "src/full-codegen.h"
+#include "src/ic/ic.h"
+#include "src/isolate-inl.h"
+#include "src/parser.h"
+#include "src/scopes.h"
+
+#include "src/ppc/code-stubs-ppc.h"
+#include "src/ppc/macro-assembler-ppc.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm_)
+
+// A patch site is a location in the code which it is possible to patch. This
+// class has a number of methods to emit the code which is patchable and the
+// method EmitPatchInfo to record a marker back to the patchable code. This
+// marker is a cmpi rx, #yyy instruction, and x * 0x0000ffff + yyy (raw 16 bit
+// immediate value is used) is the delta from the pc to the first instruction of
+// the patchable code.
+// See PatchInlinedSmiCode in ic-ppc.cc for the code that patches it
+class JumpPatchSite BASE_EMBEDDED {
+ public:
+  explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
+#ifdef DEBUG
+    info_emitted_ = false;
+#endif
+  }
+
+  ~JumpPatchSite() { DCHECK(patch_site_.is_bound() == info_emitted_); }
+
+  // When initially emitting this ensure that a jump is always generated to skip
+  // the inlined smi code.
+  void EmitJumpIfNotSmi(Register reg, Label* target) {
+    DCHECK(!patch_site_.is_bound() && !info_emitted_);
+    Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
+    __ bind(&patch_site_);
+    __ cmp(reg, reg, cr0);
+    __ beq(target, cr0);  // Always taken before patched.
+  }
+
+  // When initially emitting this ensure that a jump is never generated to skip
+  // the inlined smi code.
+  void EmitJumpIfSmi(Register reg, Label* target) {
+    Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
+    DCHECK(!patch_site_.is_bound() && !info_emitted_);
+    __ bind(&patch_site_);
+    __ cmp(reg, reg, cr0);
+    __ bne(target, cr0);  // Never taken before patched.
+  }
+
+  void EmitPatchInfo() {
+    if (patch_site_.is_bound()) {
+      int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_);
+      Register reg;
+      // I believe this is using reg as the high bits of of the offset
+      reg.set_code(delta_to_patch_site / kOff16Mask);
+      __ cmpi(reg, Operand(delta_to_patch_site % kOff16Mask));
+#ifdef DEBUG
+      info_emitted_ = true;
+#endif
+    } else {
+      __ nop();  // Signals no inlined code.
+    }
+  }
+
+ private:
+  MacroAssembler* masm_;
+  Label patch_site_;
+#ifdef DEBUG
+  bool info_emitted_;
+#endif
+};
+
+
+// Generate code for a JS function.  On entry to the function the receiver
+// and arguments have been pushed on the stack left to right.  The actual
+// argument count matches the formal parameter count expected by the
+// function.
+//
+// The live registers are:
+//   o r4: the JS function object being called (i.e., ourselves)
+//   o cp: our context
+//   o fp: our caller's frame pointer (aka r31)
+//   o sp: stack pointer
+//   o lr: return address
+//   o ip: our own function entry (required by the prologue)
+//
+// The function builds a JS frame.  Please see JavaScriptFrameConstants in
+// frames-ppc.h for its layout.
+void FullCodeGenerator::Generate() {
+  CompilationInfo* info = info_;
+  handler_table_ =
+      isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
+
+  profiling_counter_ = isolate()->factory()->NewCell(
+      Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
+  SetFunctionPosition(function());
+  Comment cmnt(masm_, "[ function compiled by full code generator");
+
+  ProfileEntryHookStub::MaybeCallEntryHook(masm_);
+
+#ifdef DEBUG
+  if (strlen(FLAG_stop_at) > 0 &&
+      info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
+    __ stop("stop-at");
+  }
+#endif
+
+  // Sloppy mode functions and builtins need to replace the receiver with the
+  // global proxy when called as functions (without an explicit receiver
+  // object).
+  if (info->strict_mode() == SLOPPY && !info->is_native()) {
+    Label ok;
+    int receiver_offset = info->scope()->num_parameters() * kPointerSize;
+    __ LoadP(r5, MemOperand(sp, receiver_offset), r0);
+    __ CompareRoot(r5, Heap::kUndefinedValueRootIndex);
+    __ bne(&ok);
+
+    __ LoadP(r5, GlobalObjectOperand());
+    __ LoadP(r5, FieldMemOperand(r5, GlobalObject::kGlobalProxyOffset));
+
+    __ StoreP(r5, MemOperand(sp, receiver_offset), r0);
+
+    __ bind(&ok);
+  }
+
+  // Open a frame scope to indicate that there is a frame on the stack.  The
+  // MANUAL indicates that the scope shouldn't actually generate code to set up
+  // the frame (that is done below).
+  FrameScope frame_scope(masm_, StackFrame::MANUAL);
+  int prologue_offset = masm_->pc_offset();
+
+  if (prologue_offset) {
+    // Prologue logic requires it's starting address in ip and the
+    // corresponding offset from the function entry.
+    prologue_offset += Instruction::kInstrSize;
+    __ addi(ip, ip, Operand(prologue_offset));
+  }
+  info->set_prologue_offset(prologue_offset);
+  __ Prologue(info->IsCodePreAgingActive(), prologue_offset);
+  info->AddNoFrameRange(0, masm_->pc_offset());
+
+  {
+    Comment cmnt(masm_, "[ Allocate locals");
+    int locals_count = info->scope()->num_stack_slots();
+    // Generators allocate locals, if any, in context slots.
+    DCHECK(!info->function()->is_generator() || locals_count == 0);
+    if (locals_count > 0) {
+      if (locals_count >= 128) {
+        Label ok;
+        __ Add(ip, sp, -(locals_count * kPointerSize), r0);
+        __ LoadRoot(r5, Heap::kRealStackLimitRootIndex);
+        __ cmpl(ip, r5);
+        __ bc_short(ge, &ok);
+        __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+        __ bind(&ok);
+      }
+      __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+      int kMaxPushes = FLAG_optimize_for_size ? 4 : 32;
+      if (locals_count >= kMaxPushes) {
+        int loop_iterations = locals_count / kMaxPushes;
+        __ mov(r5, Operand(loop_iterations));
+        __ mtctr(r5);
+        Label loop_header;
+        __ bind(&loop_header);
+        // Do pushes.
+        for (int i = 0; i < kMaxPushes; i++) {
+          __ push(ip);
+        }
+        // Continue loop if not done.
+        __ bdnz(&loop_header);
+      }
+      int remaining = locals_count % kMaxPushes;
+      // Emit the remaining pushes.
+      for (int i = 0; i < remaining; i++) {
+        __ push(ip);
+      }
+    }
+  }
+
+  bool function_in_register = true;
+
+  // Possibly allocate a local context.
+  int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+  if (heap_slots > 0) {
+    // Argument to NewContext is the function, which is still in r4.
+    Comment cmnt(masm_, "[ Allocate context");
+    bool need_write_barrier = true;
+    if (FLAG_harmony_scoping && info->scope()->is_script_scope()) {
+      __ push(r4);
+      __ Push(info->scope()->GetScopeInfo());
+      __ CallRuntime(Runtime::kNewScriptContext, 2);
+    } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
+      FastNewContextStub stub(isolate(), heap_slots);
+      __ CallStub(&stub);
+      // Result of FastNewContextStub is always in new space.
+      need_write_barrier = false;
+    } else {
+      __ push(r4);
+      __ CallRuntime(Runtime::kNewFunctionContext, 1);
+    }
+    function_in_register = false;
+    // Context is returned in r3.  It replaces the context passed to us.
+    // It's saved in the stack and kept live in cp.
+    __ mr(cp, r3);
+    __ StoreP(r3, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    // Copy any necessary parameters into the context.
+    int num_parameters = info->scope()->num_parameters();
+    for (int i = 0; i < num_parameters; i++) {
+      Variable* var = scope()->parameter(i);
+      if (var->IsContextSlot()) {
+        int parameter_offset = StandardFrameConstants::kCallerSPOffset +
+                               (num_parameters - 1 - i) * kPointerSize;
+        // Load parameter from stack.
+        __ LoadP(r3, MemOperand(fp, parameter_offset), r0);
+        // Store it in the context.
+        MemOperand target = ContextOperand(cp, var->index());
+        __ StoreP(r3, target, r0);
+
+        // Update the write barrier.
+        if (need_write_barrier) {
+          __ RecordWriteContextSlot(cp, target.offset(), r3, r6,
+                                    kLRHasBeenSaved, kDontSaveFPRegs);
+        } else if (FLAG_debug_code) {
+          Label done;
+          __ JumpIfInNewSpace(cp, r3, &done);
+          __ Abort(kExpectedNewSpaceObject);
+          __ bind(&done);
+        }
+      }
+    }
+  }
+
+  Variable* arguments = scope()->arguments();
+  if (arguments != NULL) {
+    // Function uses arguments object.
+    Comment cmnt(masm_, "[ Allocate arguments object");
+    if (!function_in_register) {
+      // Load this again, if it's used by the local context below.
+      __ LoadP(r6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+    } else {
+      __ mr(r6, r4);
+    }
+    // Receiver is just before the parameters on the caller's stack.
+    int num_parameters = info->scope()->num_parameters();
+    int offset = num_parameters * kPointerSize;
+    __ addi(r5, fp, Operand(StandardFrameConstants::kCallerSPOffset + offset));
+    __ LoadSmiLiteral(r4, Smi::FromInt(num_parameters));
+    __ Push(r6, r5, r4);
+
+    // Arguments to ArgumentsAccessStub:
+    //   function, receiver address, parameter count.
+    // The stub will rewrite receiever and parameter count if the previous
+    // stack frame was an arguments adapter frame.
+    ArgumentsAccessStub::Type type;
+    if (strict_mode() == STRICT) {
+      type = ArgumentsAccessStub::NEW_STRICT;
+    } else if (function()->has_duplicate_parameters()) {
+      type = ArgumentsAccessStub::NEW_SLOPPY_SLOW;
+    } else {
+      type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
+    }
+    ArgumentsAccessStub stub(isolate(), type);
+    __ CallStub(&stub);
+
+    SetVar(arguments, r3, r4, r5);
+  }
+
+  if (FLAG_trace) {
+    __ CallRuntime(Runtime::kTraceEnter, 0);
+  }
+
+  // Visit the declarations and body unless there is an illegal
+  // redeclaration.
+  if (scope()->HasIllegalRedeclaration()) {
+    Comment cmnt(masm_, "[ Declarations");
+    scope()->VisitIllegalRedeclaration(this);
+
+  } else {
+    PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
+    {
+      Comment cmnt(masm_, "[ Declarations");
+      // For named function expressions, declare the function name as a
+      // constant.
+      if (scope()->is_function_scope() && scope()->function() != NULL) {
+        VariableDeclaration* function = scope()->function();
+        DCHECK(function->proxy()->var()->mode() == CONST ||
+               function->proxy()->var()->mode() == CONST_LEGACY);
+        DCHECK(function->proxy()->var()->location() != Variable::UNALLOCATED);
+        VisitVariableDeclaration(function);
+      }
+      VisitDeclarations(scope()->declarations());
+    }
+
+    {
+      Comment cmnt(masm_, "[ Stack check");
+      PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
+      Label ok;
+      __ LoadRoot(ip, Heap::kStackLimitRootIndex);
+      __ cmpl(sp, ip);
+      __ bc_short(ge, &ok);
+      __ Call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
+      __ bind(&ok);
+    }
+
+    {
+      Comment cmnt(masm_, "[ Body");
+      DCHECK(loop_depth() == 0);
+      VisitStatements(function()->body());
+      DCHECK(loop_depth() == 0);
+    }
+  }
+
+  // Always emit a 'return undefined' in case control fell off the end of
+  // the body.
+  {
+    Comment cmnt(masm_, "[ return <undefined>;");
+    __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
+  }
+  EmitReturnSequence();
+}
+
+
+void FullCodeGenerator::ClearAccumulator() {
+  __ LoadSmiLiteral(r3, Smi::FromInt(0));
+}
+
+
+void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
+  __ mov(r5, Operand(profiling_counter_));
+  __ LoadP(r6, FieldMemOperand(r5, Cell::kValueOffset));
+  __ SubSmiLiteral(r6, r6, Smi::FromInt(delta), r0);
+  __ StoreP(r6, FieldMemOperand(r5, Cell::kValueOffset), r0);
+}
+
+
+void FullCodeGenerator::EmitProfilingCounterReset() {
+  int reset_value = FLAG_interrupt_budget;
+  if (info_->is_debug()) {
+    // Detect debug break requests as soon as possible.
+    reset_value = FLAG_interrupt_budget >> 4;
+  }
+  __ mov(r5, Operand(profiling_counter_));
+  __ LoadSmiLiteral(r6, Smi::FromInt(reset_value));
+  __ StoreP(r6, FieldMemOperand(r5, Cell::kValueOffset), r0);
+}
+
+
+void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
+                                                Label* back_edge_target) {
+  Comment cmnt(masm_, "[ Back edge bookkeeping");
+  Label ok;
+
+  DCHECK(back_edge_target->is_bound());
+  int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target) +
+                 kCodeSizeMultiplier / 2;
+  int weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier));
+  EmitProfilingCounterDecrement(weight);
+  {
+    Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
+    // BackEdgeTable::PatchAt manipulates this sequence.
+    __ cmpi(r6, Operand::Zero());
+    __ bc_short(ge, &ok);
+    __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
+
+    // Record a mapping of this PC offset to the OSR id.  This is used to find
+    // the AST id from the unoptimized code in order to use it as a key into
+    // the deoptimization input data found in the optimized code.
+    RecordBackEdge(stmt->OsrEntryId());
+  }
+  EmitProfilingCounterReset();
+
+  __ bind(&ok);
+  PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
+  // Record a mapping of the OSR id to this PC.  This is used if the OSR
+  // entry becomes the target of a bailout.  We don't expect it to be, but
+  // we want it to work if it is.
+  PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
+}
+
+
+void FullCodeGenerator::EmitReturnSequence() {
+  Comment cmnt(masm_, "[ Return sequence");
+  if (return_label_.is_bound()) {
+    __ b(&return_label_);
+  } else {
+    __ bind(&return_label_);
+    if (FLAG_trace) {
+      // Push the return value on the stack as the parameter.
+      // Runtime::TraceExit returns its parameter in r3
+      __ push(r3);
+      __ CallRuntime(Runtime::kTraceExit, 1);
+    }
+    // Pretend that the exit is a backwards jump to the entry.
+    int weight = 1;
+    if (info_->ShouldSelfOptimize()) {
+      weight = FLAG_interrupt_budget / FLAG_self_opt_count;
+    } else {
+      int distance = masm_->pc_offset() + kCodeSizeMultiplier / 2;
+      weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier));
+    }
+    EmitProfilingCounterDecrement(weight);
+    Label ok;
+    __ cmpi(r6, Operand::Zero());
+    __ bge(&ok);
+    __ push(r3);
+    __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
+    __ pop(r3);
+    EmitProfilingCounterReset();
+    __ bind(&ok);
+
+#ifdef DEBUG
+    // Add a label for checking the size of the code used for returning.
+    Label check_exit_codesize;
+    __ bind(&check_exit_codesize);
+#endif
+    // Make sure that the constant pool is not emitted inside of the return
+    // sequence.
+    {
+      Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
+      int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize;
+      CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
+      __ RecordJSReturn();
+      int no_frame_start = __ LeaveFrame(StackFrame::JAVA_SCRIPT, sp_delta);
+#if V8_TARGET_ARCH_PPC64
+      // With 64bit we may need nop() instructions to ensure we have
+      // enough space to SetDebugBreakAtReturn()
+      if (is_int16(sp_delta)) {
+#if !V8_OOL_CONSTANT_POOL
+        masm_->nop();
+#endif
+        masm_->nop();
+      }
+#endif
+      __ blr();
+      info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
+    }
+
+#ifdef DEBUG
+    // Check that the size of the code used for returning is large enough
+    // for the debugger's requirements.
+    DCHECK(Assembler::kJSReturnSequenceInstructions <=
+           masm_->InstructionsGeneratedSince(&check_exit_codesize));
+#endif
+  }
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
+  DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
+  DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+  codegen()->GetVar(result_register(), var);
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
+  DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+  codegen()->GetVar(result_register(), var);
+  __ push(result_register());
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Variable* var) const {
+  DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+  // For simplicity we always test the accumulator register.
+  codegen()->GetVar(result_register(), var);
+  codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
+  codegen()->DoTest(this);
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+    Heap::RootListIndex index) const {
+  __ LoadRoot(result_register(), index);
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(
+    Heap::RootListIndex index) const {
+  __ LoadRoot(result_register(), index);
+  __ push(result_register());
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
+  codegen()->PrepareForBailoutBeforeSplit(condition(), true, true_label_,
+                                          false_label_);
+  if (index == Heap::kUndefinedValueRootIndex ||
+      index == Heap::kNullValueRootIndex ||
+      index == Heap::kFalseValueRootIndex) {
+    if (false_label_ != fall_through_) __ b(false_label_);
+  } else if (index == Heap::kTrueValueRootIndex) {
+    if (true_label_ != fall_through_) __ b(true_label_);
+  } else {
+    __ LoadRoot(result_register(), index);
+    codegen()->DoTest(this);
+  }
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+    Handle<Object> lit) const {
+  __ mov(result_register(), Operand(lit));
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
+  // Immediates cannot be pushed directly.
+  __ mov(result_register(), Operand(lit));
+  __ push(result_register());
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
+  codegen()->PrepareForBailoutBeforeSplit(condition(), true, true_label_,
+                                          false_label_);
+  DCHECK(!lit->IsUndetectableObject());  // There are no undetectable literals.
+  if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
+    if (false_label_ != fall_through_) __ b(false_label_);
+  } else if (lit->IsTrue() || lit->IsJSObject()) {
+    if (true_label_ != fall_through_) __ b(true_label_);
+  } else if (lit->IsString()) {
+    if (String::cast(*lit)->length() == 0) {
+      if (false_label_ != fall_through_) __ b(false_label_);
+    } else {
+      if (true_label_ != fall_through_) __ b(true_label_);
+    }
+  } else if (lit->IsSmi()) {
+    if (Smi::cast(*lit)->value() == 0) {
+      if (false_label_ != fall_through_) __ b(false_label_);
+    } else {
+      if (true_label_ != fall_through_) __ b(true_label_);
+    }
+  } else {
+    // For simplicity we always test the accumulator register.
+    __ mov(result_register(), Operand(lit));
+    codegen()->DoTest(this);
+  }
+}
+
+
+void FullCodeGenerator::EffectContext::DropAndPlug(int count,
+                                                   Register reg) const {
+  DCHECK(count > 0);
+  __ Drop(count);
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
+    int count, Register reg) const {
+  DCHECK(count > 0);
+  __ Drop(count);
+  __ Move(result_register(), reg);
+}
+
+
+void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
+                                                       Register reg) const {
+  DCHECK(count > 0);
+  if (count > 1) __ Drop(count - 1);
+  __ StoreP(reg, MemOperand(sp, 0));
+}
+
+
+void FullCodeGenerator::TestContext::DropAndPlug(int count,
+                                                 Register reg) const {
+  DCHECK(count > 0);
+  // For simplicity we always test the accumulator register.
+  __ Drop(count);
+  __ Move(result_register(), reg);
+  codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
+  codegen()->DoTest(this);
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
+                                            Label* materialize_false) const {
+  DCHECK(materialize_true == materialize_false);
+  __ bind(materialize_true);
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+    Label* materialize_true, Label* materialize_false) const {
+  Label done;
+  __ bind(materialize_true);
+  __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
+  __ b(&done);
+  __ bind(materialize_false);
+  __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
+  __ bind(&done);
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(
+    Label* materialize_true, Label* materialize_false) const {
+  Label done;
+  __ bind(materialize_true);
+  __ LoadRoot(ip, Heap::kTrueValueRootIndex);
+  __ b(&done);
+  __ bind(materialize_false);
+  __ LoadRoot(ip, Heap::kFalseValueRootIndex);
+  __ bind(&done);
+  __ push(ip);
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
+                                          Label* materialize_false) const {
+  DCHECK(materialize_true == true_label_);
+  DCHECK(materialize_false == false_label_);
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(bool flag) const {}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
+  Heap::RootListIndex value_root_index =
+      flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
+  __ LoadRoot(result_register(), value_root_index);
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
+  Heap::RootListIndex value_root_index =
+      flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
+  __ LoadRoot(ip, value_root_index);
+  __ push(ip);
+}
+
+
+void FullCodeGenerator::TestContext::Plug(bool flag) const {
+  codegen()->PrepareForBailoutBeforeSplit(condition(), true, true_label_,
+                                          false_label_);
+  if (flag) {
+    if (true_label_ != fall_through_) __ b(true_label_);
+  } else {
+    if (false_label_ != fall_through_) __ b(false_label_);
+  }
+}
+
+
+void FullCodeGenerator::DoTest(Expression* condition, Label* if_true,
+                               Label* if_false, Label* fall_through) {
+  Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
+  CallIC(ic, condition->test_id());
+  __ cmpi(result_register(), Operand::Zero());
+  Split(ne, if_true, if_false, fall_through);
+}
+
+
+void FullCodeGenerator::Split(Condition cond, Label* if_true, Label* if_false,
+                              Label* fall_through, CRegister cr) {
+  if (if_false == fall_through) {
+    __ b(cond, if_true, cr);
+  } else if (if_true == fall_through) {
+    __ b(NegateCondition(cond), if_false, cr);
+  } else {
+    __ b(cond, if_true, cr);
+    __ b(if_false);
+  }
+}
+
+
+MemOperand FullCodeGenerator::StackOperand(Variable* var) {
+  DCHECK(var->IsStackAllocated());
+  // Offset is negative because higher indexes are at lower addresses.
+  int offset = -var->index() * kPointerSize;
+  // Adjust by a (parameter or local) base offset.
+  if (var->IsParameter()) {
+    offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
+  } else {
+    offset += JavaScriptFrameConstants::kLocal0Offset;
+  }
+  return MemOperand(fp, offset);
+}
+
+
+MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
+  DCHECK(var->IsContextSlot() || var->IsStackAllocated());
+  if (var->IsContextSlot()) {
+    int context_chain_length = scope()->ContextChainLength(var->scope());
+    __ LoadContext(scratch, context_chain_length);
+    return ContextOperand(scratch, var->index());
+  } else {
+    return StackOperand(var);
+  }
+}
+
+
+void FullCodeGenerator::GetVar(Register dest, Variable* var) {
+  // Use destination as scratch.
+  MemOperand location = VarOperand(var, dest);
+  __ LoadP(dest, location, r0);
+}
+
+
+void FullCodeGenerator::SetVar(Variable* var, Register src, Register scratch0,
+                               Register scratch1) {
+  DCHECK(var->IsContextSlot() || var->IsStackAllocated());
+  DCHECK(!scratch0.is(src));
+  DCHECK(!scratch0.is(scratch1));
+  DCHECK(!scratch1.is(src));
+  MemOperand location = VarOperand(var, scratch0);
+  __ StoreP(src, location, r0);
+
+  // Emit the write barrier code if the location is in the heap.
+  if (var->IsContextSlot()) {
+    __ RecordWriteContextSlot(scratch0, location.offset(), src, scratch1,
+                              kLRHasBeenSaved, kDontSaveFPRegs);
+  }
+}
+
+
+void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
+                                                     bool should_normalize,
+                                                     Label* if_true,
+                                                     Label* if_false) {
+  // Only prepare for bailouts before splits if we're in a test
+  // context. Otherwise, we let the Visit function deal with the
+  // preparation to avoid preparing with the same AST id twice.
+  if (!context()->IsTest() || !info_->IsOptimizable()) return;
+
+  Label skip;
+  if (should_normalize) __ b(&skip);
+  PrepareForBailout(expr, TOS_REG);
+  if (should_normalize) {
+    __ LoadRoot(ip, Heap::kTrueValueRootIndex);
+    __ cmp(r3, ip);
+    Split(eq, if_true, if_false, NULL);
+    __ bind(&skip);
+  }
+}
+
+
+void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
+  // The variable in the declaration always resides in the current function
+  // context.
+  DCHECK_EQ(0, scope()->ContextChainLength(variable->scope()));
+  if (generate_debug_code_) {
+    // Check that we're not inside a with or catch context.
+    __ LoadP(r4, FieldMemOperand(cp, HeapObject::kMapOffset));
+    __ CompareRoot(r4, Heap::kWithContextMapRootIndex);
+    __ Check(ne, kDeclarationInWithContext);
+    __ CompareRoot(r4, Heap::kCatchContextMapRootIndex);
+    __ Check(ne, kDeclarationInCatchContext);
+  }
+}
+
+
+void FullCodeGenerator::VisitVariableDeclaration(
+    VariableDeclaration* declaration) {
+  // If it was not possible to allocate the variable at compile time, we
+  // need to "declare" it at runtime to make sure it actually exists in the
+  // local context.
+  VariableProxy* proxy = declaration->proxy();
+  VariableMode mode = declaration->mode();
+  Variable* variable = proxy->var();
+  bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
+  switch (variable->location()) {
+    case Variable::UNALLOCATED:
+      globals_->Add(variable->name(), zone());
+      globals_->Add(variable->binding_needs_init()
+                        ? isolate()->factory()->the_hole_value()
+                        : isolate()->factory()->undefined_value(),
+                    zone());
+      break;
+
+    case Variable::PARAMETER:
+    case Variable::LOCAL:
+      if (hole_init) {
+        Comment cmnt(masm_, "[ VariableDeclaration");
+        __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+        __ StoreP(ip, StackOperand(variable));
+      }
+      break;
+
+    case Variable::CONTEXT:
+      if (hole_init) {
+        Comment cmnt(masm_, "[ VariableDeclaration");
+        EmitDebugCheckDeclarationContext(variable);
+        __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+        __ StoreP(ip, ContextOperand(cp, variable->index()), r0);
+        // No write barrier since the_hole_value is in old space.
+        PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
+      }
+      break;
+
+    case Variable::LOOKUP: {
+      Comment cmnt(masm_, "[ VariableDeclaration");
+      __ mov(r5, Operand(variable->name()));
+      // Declaration nodes are always introduced in one of four modes.
+      DCHECK(IsDeclaredVariableMode(mode));
+      PropertyAttributes attr =
+          IsImmutableVariableMode(mode) ? READ_ONLY : NONE;
+      __ LoadSmiLiteral(r4, Smi::FromInt(attr));
+      // Push initial value, if any.
+      // Note: For variables we must not push an initial value (such as
+      // 'undefined') because we may have a (legal) redeclaration and we
+      // must not destroy the current value.
+      if (hole_init) {
+        __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
+        __ Push(cp, r5, r4, r3);
+      } else {
+        __ LoadSmiLiteral(r3, Smi::FromInt(0));  // Indicates no initial value.
+        __ Push(cp, r5, r4, r3);
+      }
+      __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
+      break;
+    }
+  }
+}
+
+
+void FullCodeGenerator::VisitFunctionDeclaration(
+    FunctionDeclaration* declaration) {
+  VariableProxy* proxy = declaration->proxy();
+  Variable* variable = proxy->var();
+  switch (variable->location()) {
+    case Variable::UNALLOCATED: {
+      globals_->Add(variable->name(), zone());
+      Handle<SharedFunctionInfo> function =
+          Compiler::BuildFunctionInfo(declaration->fun(), script(), info_);
+      // Check for stack-overflow exception.
+      if (function.is_null()) return SetStackOverflow();
+      globals_->Add(function, zone());
+      break;
+    }
+
+    case Variable::PARAMETER:
+    case Variable::LOCAL: {
+      Comment cmnt(masm_, "[ FunctionDeclaration");
+      VisitForAccumulatorValue(declaration->fun());
+      __ StoreP(result_register(), StackOperand(variable));
+      break;
+    }
+
+    case Variable::CONTEXT: {
+      Comment cmnt(masm_, "[ FunctionDeclaration");
+      EmitDebugCheckDeclarationContext(variable);
+      VisitForAccumulatorValue(declaration->fun());
+      __ StoreP(result_register(), ContextOperand(cp, variable->index()), r0);
+      int offset = Context::SlotOffset(variable->index());
+      // We know that we have written a function, which is not a smi.
+      __ RecordWriteContextSlot(cp, offset, result_register(), r5,
+                                kLRHasBeenSaved, kDontSaveFPRegs,
+                                EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+      PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
+      break;
+    }
+
+    case Variable::LOOKUP: {
+      Comment cmnt(masm_, "[ FunctionDeclaration");
+      __ mov(r5, Operand(variable->name()));
+      __ LoadSmiLiteral(r4, Smi::FromInt(NONE));
+      __ Push(cp, r5, r4);
+      // Push initial value for function declaration.
+      VisitForStackValue(declaration->fun());
+      __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
+      break;
+    }
+  }
+}
+
+
+void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
+  Variable* variable = declaration->proxy()->var();
+  DCHECK(variable->location() == Variable::CONTEXT);
+  DCHECK(variable->interface()->IsFrozen());
+
+  Comment cmnt(masm_, "[ ModuleDeclaration");
+  EmitDebugCheckDeclarationContext(variable);
+
+  // Load instance object.
+  __ LoadContext(r4, scope_->ContextChainLength(scope_->ScriptScope()));
+  __ LoadP(r4, ContextOperand(r4, variable->interface()->Index()));
+  __ LoadP(r4, ContextOperand(r4, Context::EXTENSION_INDEX));
+
+  // Assign it.
+  __ StoreP(r4, ContextOperand(cp, variable->index()), r0);
+  // We know that we have written a module, which is not a smi.
+  __ RecordWriteContextSlot(cp, Context::SlotOffset(variable->index()), r4, r6,
+                            kLRHasBeenSaved, kDontSaveFPRegs,
+                            EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+  PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS);
+
+  // Traverse into body.
+  Visit(declaration->module());
+}
+
+
+void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
+  VariableProxy* proxy = declaration->proxy();
+  Variable* variable = proxy->var();
+  switch (variable->location()) {
+    case Variable::UNALLOCATED:
+      // TODO(rossberg)
+      break;
+
+    case Variable::CONTEXT: {
+      Comment cmnt(masm_, "[ ImportDeclaration");
+      EmitDebugCheckDeclarationContext(variable);
+      // TODO(rossberg)
+      break;
+    }
+
+    case Variable::PARAMETER:
+    case Variable::LOCAL:
+    case Variable::LOOKUP:
+      UNREACHABLE();
+  }
+}
+
+
+void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
+  // TODO(rossberg)
+}
+
+
+void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
+  // Call the runtime to declare the globals.
+  // The context is the first argument.
+  __ mov(r4, Operand(pairs));
+  __ LoadSmiLiteral(r3, Smi::FromInt(DeclareGlobalsFlags()));
+  __ Push(cp, r4, r3);
+  __ CallRuntime(Runtime::kDeclareGlobals, 3);
+  // Return value is ignored.
+}
+
+
+void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
+  // Call the runtime to declare the modules.
+  __ Push(descriptions);
+  __ CallRuntime(Runtime::kDeclareModules, 1);
+  // Return value is ignored.
+}
+
+
+void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
+  Comment cmnt(masm_, "[ SwitchStatement");
+  Breakable nested_statement(this, stmt);
+  SetStatementPosition(stmt);
+
+  // Keep the switch value on the stack until a case matches.
+  VisitForStackValue(stmt->tag());
+  PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
+
+  ZoneList<CaseClause*>* clauses = stmt->cases();
+  CaseClause* default_clause = NULL;  // Can occur anywhere in the list.
+
+  Label next_test;  // Recycled for each test.
+  // Compile all the tests with branches to their bodies.
+  for (int i = 0; i < clauses->length(); i++) {
+    CaseClause* clause = clauses->at(i);
+    clause->body_target()->Unuse();
+
+    // The default is not a test, but remember it as final fall through.
+    if (clause->is_default()) {
+      default_clause = clause;
+      continue;
+    }
+
+    Comment cmnt(masm_, "[ Case comparison");
+    __ bind(&next_test);
+    next_test.Unuse();
+
+    // Compile the label expression.
+    VisitForAccumulatorValue(clause->label());
+
+    // Perform the comparison as if via '==='.
+    __ LoadP(r4, MemOperand(sp, 0));  // Switch value.
+    bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
+    JumpPatchSite patch_site(masm_);
+    if (inline_smi_code) {
+      Label slow_case;
+      __ orx(r5, r4, r3);
+      patch_site.EmitJumpIfNotSmi(r5, &slow_case);
+
+      __ cmp(r4, r3);
+      __ bne(&next_test);
+      __ Drop(1);  // Switch value is no longer needed.
+      __ b(clause->body_target());
+      __ bind(&slow_case);
+    }
+
+    // Record position before stub call for type feedback.
+    SetSourcePosition(clause->position());
+    Handle<Code> ic =
+        CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
+    CallIC(ic, clause->CompareId());
+    patch_site.EmitPatchInfo();
+
+    Label skip;
+    __ b(&skip);
+    PrepareForBailout(clause, TOS_REG);
+    __ LoadRoot(ip, Heap::kTrueValueRootIndex);
+    __ cmp(r3, ip);
+    __ bne(&next_test);
+    __ Drop(1);
+    __ b(clause->body_target());
+    __ bind(&skip);
+
+    __ cmpi(r3, Operand::Zero());
+    __ bne(&next_test);
+    __ Drop(1);  // Switch value is no longer needed.
+    __ b(clause->body_target());
+  }
+
+  // Discard the test value and jump to the default if present, otherwise to
+  // the end of the statement.
+  __ bind(&next_test);
+  __ Drop(1);  // Switch value is no longer needed.
+  if (default_clause == NULL) {
+    __ b(nested_statement.break_label());
+  } else {
+    __ b(default_clause->body_target());
+  }
+
+  // Compile all the case bodies.
+  for (int i = 0; i < clauses->length(); i++) {
+    Comment cmnt(masm_, "[ Case body");
+    CaseClause* clause = clauses->at(i);
+    __ bind(clause->body_target());
+    PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
+    VisitStatements(clause->statements());
+  }
+
+  __ bind(nested_statement.break_label());
+  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
+}
+
+
+void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
+  Comment cmnt(masm_, "[ ForInStatement");
+  FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
+  SetStatementPosition(stmt);
+
+  Label loop, exit;
+  ForIn loop_statement(this, stmt);
+  increment_loop_depth();
+
+  // Get the object to enumerate over. If the object is null or undefined, skip
+  // over the loop.  See ECMA-262 version 5, section 12.6.4.
+  VisitForAccumulatorValue(stmt->enumerable());
+  __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+  __ cmp(r3, ip);
+  __ beq(&exit);
+  Register null_value = r7;
+  __ LoadRoot(null_value, Heap::kNullValueRootIndex);
+  __ cmp(r3, null_value);
+  __ beq(&exit);
+
+  PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
+
+  // Convert the object to a JS object.
+  Label convert, done_convert;
+  __ JumpIfSmi(r3, &convert);
+  __ CompareObjectType(r3, r4, r4, FIRST_SPEC_OBJECT_TYPE);
+  __ bge(&done_convert);
+  __ bind(&convert);
+  __ push(r3);
+  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
+  __ bind(&done_convert);
+  PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
+  __ push(r3);
+
+  // Check for proxies.
+  Label call_runtime;
+  STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
+  __ CompareObjectType(r3, r4, r4, LAST_JS_PROXY_TYPE);
+  __ ble(&call_runtime);
+
+  // Check cache validity in generated code. This is a fast case for
+  // the JSObject::IsSimpleEnum cache validity checks. If we cannot
+  // guarantee cache validity, call the runtime system to check cache
+  // validity or get the property names in a fixed array.
+  __ CheckEnumCache(null_value, &call_runtime);
+
+  // The enum cache is valid.  Load the map of the object being
+  // iterated over and use the cache for the iteration.
+  Label use_cache;
+  __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ b(&use_cache);
+
+  // Get the set of properties to enumerate.
+  __ bind(&call_runtime);
+  __ push(r3);  // Duplicate the enumerable object on the stack.
+  __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
+  PrepareForBailoutForId(stmt->EnumId(), TOS_REG);
+
+  // If we got a map from the runtime call, we can do a fast
+  // modification check. Otherwise, we got a fixed array, and we have
+  // to do a slow check.
+  Label fixed_array;
+  __ LoadP(r5, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ LoadRoot(ip, Heap::kMetaMapRootIndex);
+  __ cmp(r5, ip);
+  __ bne(&fixed_array);
+
+  // We got a map in register r3. Get the enumeration cache from it.
+  Label no_descriptors;
+  __ bind(&use_cache);
+
+  __ EnumLength(r4, r3);
+  __ CmpSmiLiteral(r4, Smi::FromInt(0), r0);
+  __ beq(&no_descriptors);
+
+  __ LoadInstanceDescriptors(r3, r5);
+  __ LoadP(r5, FieldMemOperand(r5, DescriptorArray::kEnumCacheOffset));
+  __ LoadP(r5,
+           FieldMemOperand(r5, DescriptorArray::kEnumCacheBridgeCacheOffset));
+
+  // Set up the four remaining stack slots.
+  __ push(r3);  // Map.
+  __ LoadSmiLiteral(r3, Smi::FromInt(0));
+  // Push enumeration cache, enumeration cache length (as smi) and zero.
+  __ Push(r5, r4, r3);
+  __ b(&loop);
+
+  __ bind(&no_descriptors);
+  __ Drop(1);
+  __ b(&exit);
+
+  // We got a fixed array in register r3. Iterate through that.
+  Label non_proxy;
+  __ bind(&fixed_array);
+
+  __ Move(r4, FeedbackVector());
+  __ mov(r5, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate())));
+  int vector_index = FeedbackVector()->GetIndex(slot);
+  __ StoreP(
+      r5, FieldMemOperand(r4, FixedArray::OffsetOfElementAt(vector_index)), r0);
+
+  __ LoadSmiLiteral(r4, Smi::FromInt(1));          // Smi indicates slow check
+  __ LoadP(r5, MemOperand(sp, 0 * kPointerSize));  // Get enumerated object
+  STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
+  __ CompareObjectType(r5, r6, r6, LAST_JS_PROXY_TYPE);
+  __ bgt(&non_proxy);
+  __ LoadSmiLiteral(r4, Smi::FromInt(0));  // Zero indicates proxy
+  __ bind(&non_proxy);
+  __ Push(r4, r3);  // Smi and array
+  __ LoadP(r4, FieldMemOperand(r3, FixedArray::kLengthOffset));
+  __ LoadSmiLiteral(r3, Smi::FromInt(0));
+  __ Push(r4, r3);  // Fixed array length (as smi) and initial index.
+
+  // Generate code for doing the condition check.
+  PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
+  __ bind(&loop);
+  // Load the current count to r3, load the length to r4.
+  __ LoadP(r3, MemOperand(sp, 0 * kPointerSize));
+  __ LoadP(r4, MemOperand(sp, 1 * kPointerSize));
+  __ cmpl(r3, r4);  // Compare to the array length.
+  __ bge(loop_statement.break_label());
+
+  // Get the current entry of the array into register r6.
+  __ LoadP(r5, MemOperand(sp, 2 * kPointerSize));
+  __ addi(r5, r5, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ SmiToPtrArrayOffset(r6, r3);
+  __ LoadPX(r6, MemOperand(r6, r5));
+
+  // Get the expected map from the stack or a smi in the
+  // permanent slow case into register r5.
+  __ LoadP(r5, MemOperand(sp, 3 * kPointerSize));
+
+  // Check if the expected map still matches that of the enumerable.
+  // If not, we may have to filter the key.
+  Label update_each;
+  __ LoadP(r4, MemOperand(sp, 4 * kPointerSize));
+  __ LoadP(r7, FieldMemOperand(r4, HeapObject::kMapOffset));
+  __ cmp(r7, r5);
+  __ beq(&update_each);
+
+  // For proxies, no filtering is done.
+  // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
+  __ CmpSmiLiteral(r5, Smi::FromInt(0), r0);
+  __ beq(&update_each);
+
+  // Convert the entry to a string or (smi) 0 if it isn't a property
+  // any more. If the property has been removed while iterating, we
+  // just skip it.
+  __ Push(r4, r6);  // Enumerable and current entry.
+  __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
+  __ mr(r6, r3);
+  __ cmpi(r6, Operand::Zero());
+  __ beq(loop_statement.continue_label());
+
+  // Update the 'each' property or variable from the possibly filtered
+  // entry in register r6.
+  __ bind(&update_each);
+  __ mr(result_register(), r6);
+  // Perform the assignment as if via '='.
+  {
+    EffectContext context(this);
+    EmitAssignment(stmt->each());
+  }
+
+  // Generate code for the body of the loop.
+  Visit(stmt->body());
+
+  // Generate code for the going to the next element by incrementing
+  // the index (smi) stored on top of the stack.
+  __ bind(loop_statement.continue_label());
+  __ pop(r3);
+  __ AddSmiLiteral(r3, r3, Smi::FromInt(1), r0);
+  __ push(r3);
+
+  EmitBackEdgeBookkeeping(stmt, &loop);
+  __ b(&loop);
+
+  // Remove the pointers stored on the stack.
+  __ bind(loop_statement.break_label());
+  __ Drop(5);
+
+  // Exit and decrement the loop depth.
+  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
+  __ bind(&exit);
+  decrement_loop_depth();
+}
+
+
+void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
+  Comment cmnt(masm_, "[ ForOfStatement");
+  SetStatementPosition(stmt);
+
+  Iteration loop_statement(this, stmt);
+  increment_loop_depth();
+
+  // var iterator = iterable[Symbol.iterator]();
+  VisitForEffect(stmt->assign_iterator());
+
+  // Loop entry.
+  __ bind(loop_statement.continue_label());
+
+  // result = iterator.next()
+  VisitForEffect(stmt->next_result());
+
+  // if (result.done) break;
+  Label result_not_done;
+  VisitForControl(stmt->result_done(), loop_statement.break_label(),
+                  &result_not_done, &result_not_done);
+  __ bind(&result_not_done);
+
+  // each = result.value
+  VisitForEffect(stmt->assign_each());
+
+  // Generate code for the body of the loop.
+  Visit(stmt->body());
+
+  // Check stack before looping.
+  PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
+  EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
+  __ b(loop_statement.continue_label());
+
+  // Exit and decrement the loop depth.
+  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
+  __ bind(loop_statement.break_label());
+  decrement_loop_depth();
+}
+
+
+void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
+                                       bool pretenure) {
+  // Use the fast case closure allocation code that allocates in new
+  // space for nested functions that don't need literals cloning. If
+  // we're running with the --always-opt or the --prepare-always-opt
+  // flag, we need to use the runtime function so that the new function
+  // we are creating here gets a chance to have its code optimized and
+  // doesn't just get a copy of the existing unoptimized code.
+  if (!FLAG_always_opt && !FLAG_prepare_always_opt && !pretenure &&
+      scope()->is_function_scope() && info->num_literals() == 0) {
+    FastNewClosureStub stub(isolate(), info->strict_mode(), info->kind());
+    __ mov(r5, Operand(info));
+    __ CallStub(&stub);
+  } else {
+    __ mov(r3, Operand(info));
+    __ LoadRoot(
+        r4, pretenure ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex);
+    __ Push(cp, r3, r4);
+    __ CallRuntime(Runtime::kNewClosure, 3);
+  }
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
+  Comment cmnt(masm_, "[ VariableProxy");
+  EmitVariableLoad(expr);
+}
+
+
+void FullCodeGenerator::EmitLoadHomeObject(SuperReference* expr) {
+  Comment cnmt(masm_, "[ SuperReference ");
+
+  __ LoadP(LoadDescriptor::ReceiverRegister(),
+           MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+
+  Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
+  __ Move(LoadDescriptor::NameRegister(), home_object_symbol);
+
+  if (FLAG_vector_ics) {
+    __ mov(VectorLoadICDescriptor::SlotRegister(),
+           Operand(SmiFromSlot(expr->HomeObjectFeedbackSlot())));
+    CallLoadIC(NOT_CONTEXTUAL);
+  } else {
+    CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  }
+
+  __ Cmpi(r3, Operand(isolate()->factory()->undefined_value()), r0);
+  Label done;
+  __ bne(&done);
+  __ CallRuntime(Runtime::kThrowNonMethodError, 0);
+  __ bind(&done);
+}
+
+
+void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
+                                                      TypeofState typeof_state,
+                                                      Label* slow) {
+  Register current = cp;
+  Register next = r4;
+  Register temp = r5;
+
+  Scope* s = scope();
+  while (s != NULL) {
+    if (s->num_heap_slots() > 0) {
+      if (s->calls_sloppy_eval()) {
+        // Check that extension is NULL.
+        __ LoadP(temp, ContextOperand(current, Context::EXTENSION_INDEX));
+        __ cmpi(temp, Operand::Zero());
+        __ bne(slow);
+      }
+      // Load next context in chain.
+      __ LoadP(next, ContextOperand(current, Context::PREVIOUS_INDEX));
+      // Walk the rest of the chain without clobbering cp.
+      current = next;
+    }
+    // If no outer scope calls eval, we do not need to check more
+    // context extensions.
+    if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break;
+    s = s->outer_scope();
+  }
+
+  if (s->is_eval_scope()) {
+    Label loop, fast;
+    if (!current.is(next)) {
+      __ Move(next, current);
+    }
+    __ bind(&loop);
+    // Terminate at native context.
+    __ LoadP(temp, FieldMemOperand(next, HeapObject::kMapOffset));
+    __ LoadRoot(ip, Heap::kNativeContextMapRootIndex);
+    __ cmp(temp, ip);
+    __ beq(&fast);
+    // Check that extension is NULL.
+    __ LoadP(temp, ContextOperand(next, Context::EXTENSION_INDEX));
+    __ cmpi(temp, Operand::Zero());
+    __ bne(slow);
+    // Load next context in chain.
+    __ LoadP(next, ContextOperand(next, Context::PREVIOUS_INDEX));
+    __ b(&loop);
+    __ bind(&fast);
+  }
+
+  __ LoadP(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+  __ mov(LoadDescriptor::NameRegister(), Operand(proxy->var()->name()));
+  if (FLAG_vector_ics) {
+    __ mov(VectorLoadICDescriptor::SlotRegister(),
+           Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
+  }
+
+  ContextualMode mode =
+      (typeof_state == INSIDE_TYPEOF) ? NOT_CONTEXTUAL : CONTEXTUAL;
+  CallLoadIC(mode);
+}
+
+
+MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
+                                                                Label* slow) {
+  DCHECK(var->IsContextSlot());
+  Register context = cp;
+  Register next = r6;
+  Register temp = r7;
+
+  for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
+    if (s->num_heap_slots() > 0) {
+      if (s->calls_sloppy_eval()) {
+        // Check that extension is NULL.
+        __ LoadP(temp, ContextOperand(context, Context::EXTENSION_INDEX));
+        __ cmpi(temp, Operand::Zero());
+        __ bne(slow);
+      }
+      __ LoadP(next, ContextOperand(context, Context::PREVIOUS_INDEX));
+      // Walk the rest of the chain without clobbering cp.
+      context = next;
+    }
+  }
+  // Check that last extension is NULL.
+  __ LoadP(temp, ContextOperand(context, Context::EXTENSION_INDEX));
+  __ cmpi(temp, Operand::Zero());
+  __ bne(slow);
+
+  // This function is used only for loads, not stores, so it's safe to
+  // return an cp-based operand (the write barrier cannot be allowed to
+  // destroy the cp register).
+  return ContextOperand(context, var->index());
+}
+
+
+void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
+                                                  TypeofState typeof_state,
+                                                  Label* slow, Label* done) {
+  // Generate fast-case code for variables that might be shadowed by
+  // eval-introduced variables.  Eval is used a lot without
+  // introducing variables.  In those cases, we do not want to
+  // perform a runtime call for all variables in the scope
+  // containing the eval.
+  Variable* var = proxy->var();
+  if (var->mode() == DYNAMIC_GLOBAL) {
+    EmitLoadGlobalCheckExtensions(proxy, typeof_state, slow);
+    __ b(done);
+  } else if (var->mode() == DYNAMIC_LOCAL) {
+    Variable* local = var->local_if_not_shadowed();
+    __ LoadP(r3, ContextSlotOperandCheckExtensions(local, slow));
+    if (local->mode() == LET || local->mode() == CONST ||
+        local->mode() == CONST_LEGACY) {
+      __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
+      __ bne(done);
+      if (local->mode() == CONST_LEGACY) {
+        __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
+      } else {  // LET || CONST
+        __ mov(r3, Operand(var->name()));
+        __ push(r3);
+        __ CallRuntime(Runtime::kThrowReferenceError, 1);
+      }
+    }
+    __ b(done);
+  }
+}
+
+
+void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
+  // Record position before possible IC call.
+  SetSourcePosition(proxy->position());
+  Variable* var = proxy->var();
+
+  // Three cases: global variables, lookup variables, and all other types of
+  // variables.
+  switch (var->location()) {
+    case Variable::UNALLOCATED: {
+      Comment cmnt(masm_, "[ Global variable");
+      __ LoadP(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+      __ mov(LoadDescriptor::NameRegister(), Operand(var->name()));
+      if (FLAG_vector_ics) {
+        __ mov(VectorLoadICDescriptor::SlotRegister(),
+               Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
+      }
+      CallLoadIC(CONTEXTUAL);
+      context()->Plug(r3);
+      break;
+    }
+
+    case Variable::PARAMETER:
+    case Variable::LOCAL:
+    case Variable::CONTEXT: {
+      Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
+                                               : "[ Stack variable");
+      if (var->binding_needs_init()) {
+        // var->scope() may be NULL when the proxy is located in eval code and
+        // refers to a potential outside binding. Currently those bindings are
+        // always looked up dynamically, i.e. in that case
+        //     var->location() == LOOKUP.
+        // always holds.
+        DCHECK(var->scope() != NULL);
+
+        // Check if the binding really needs an initialization check. The check
+        // can be skipped in the following situation: we have a LET or CONST
+        // binding in harmony mode, both the Variable and the VariableProxy have
+        // the same declaration scope (i.e. they are both in global code, in the
+        // same function or in the same eval code) and the VariableProxy is in
+        // the source physically located after the initializer of the variable.
+        //
+        // We cannot skip any initialization checks for CONST in non-harmony
+        // mode because const variables may be declared but never initialized:
+        //   if (false) { const x; }; var y = x;
+        //
+        // The condition on the declaration scopes is a conservative check for
+        // nested functions that access a binding and are called before the
+        // binding is initialized:
+        //   function() { f(); let x = 1; function f() { x = 2; } }
+        //
+        bool skip_init_check;
+        if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
+          skip_init_check = false;
+        } else {
+          // Check that we always have valid source position.
+          DCHECK(var->initializer_position() != RelocInfo::kNoPosition);
+          DCHECK(proxy->position() != RelocInfo::kNoPosition);
+          skip_init_check = var->mode() != CONST_LEGACY &&
+                            var->initializer_position() < proxy->position();
+        }
+
+        if (!skip_init_check) {
+          Label done;
+          // Let and const need a read barrier.
+          GetVar(r3, var);
+          __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
+          __ bne(&done);
+          if (var->mode() == LET || var->mode() == CONST) {
+            // Throw a reference error when using an uninitialized let/const
+            // binding in harmony mode.
+            __ mov(r3, Operand(var->name()));
+            __ push(r3);
+            __ CallRuntime(Runtime::kThrowReferenceError, 1);
+          } else {
+            // Uninitalized const bindings outside of harmony mode are unholed.
+            DCHECK(var->mode() == CONST_LEGACY);
+            __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
+          }
+          __ bind(&done);
+          context()->Plug(r3);
+          break;
+        }
+      }
+      context()->Plug(var);
+      break;
+    }
+
+    case Variable::LOOKUP: {
+      Comment cmnt(masm_, "[ Lookup variable");
+      Label done, slow;
+      // Generate code for loading from variables potentially shadowed
+      // by eval-introduced variables.
+      EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
+      __ bind(&slow);
+      __ mov(r4, Operand(var->name()));
+      __ Push(cp, r4);  // Context and name.
+      __ CallRuntime(Runtime::kLoadLookupSlot, 2);
+      __ bind(&done);
+      context()->Plug(r3);
+    }
+  }
+}
+
+
+void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
+  Comment cmnt(masm_, "[ RegExpLiteral");
+  Label materialized;
+  // Registers will be used as follows:
+  // r8 = materialized value (RegExp literal)
+  // r7 = JS function, literals array
+  // r6 = literal index
+  // r5 = RegExp pattern
+  // r4 = RegExp flags
+  // r3 = RegExp literal clone
+  __ LoadP(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ LoadP(r7, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
+  int literal_offset =
+      FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
+  __ LoadP(r8, FieldMemOperand(r7, literal_offset), r0);
+  __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+  __ cmp(r8, ip);
+  __ bne(&materialized);
+
+  // Create regexp literal using runtime function.
+  // Result will be in r3.
+  __ LoadSmiLiteral(r6, Smi::FromInt(expr->literal_index()));
+  __ mov(r5, Operand(expr->pattern()));
+  __ mov(r4, Operand(expr->flags()));
+  __ Push(r7, r6, r5, r4);
+  __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
+  __ mr(r8, r3);
+
+  __ bind(&materialized);
+  int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
+  Label allocated, runtime_allocate;
+  __ Allocate(size, r3, r5, r6, &runtime_allocate, TAG_OBJECT);
+  __ b(&allocated);
+
+  __ bind(&runtime_allocate);
+  __ LoadSmiLiteral(r3, Smi::FromInt(size));
+  __ Push(r8, r3);
+  __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
+  __ pop(r8);
+
+  __ bind(&allocated);
+  // After this, registers are used as follows:
+  // r3: Newly allocated regexp.
+  // r8: Materialized regexp.
+  // r5: temp.
+  __ CopyFields(r3, r8, r5.bit(), size / kPointerSize);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitAccessor(Expression* expression) {
+  if (expression == NULL) {
+    __ LoadRoot(r4, Heap::kNullValueRootIndex);
+    __ push(r4);
+  } else {
+    VisitForStackValue(expression);
+  }
+}
+
+
+void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
+  Comment cmnt(masm_, "[ ObjectLiteral");
+
+  expr->BuildConstantProperties(isolate());
+  Handle<FixedArray> constant_properties = expr->constant_properties();
+  __ LoadP(r6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ LoadP(r6, FieldMemOperand(r6, JSFunction::kLiteralsOffset));
+  __ LoadSmiLiteral(r5, Smi::FromInt(expr->literal_index()));
+  __ mov(r4, Operand(constant_properties));
+  int flags = expr->fast_elements() ? ObjectLiteral::kFastElements
+                                    : ObjectLiteral::kNoFlags;
+  flags |= expr->has_function() ? ObjectLiteral::kHasFunction
+                                : ObjectLiteral::kNoFlags;
+  __ LoadSmiLiteral(r3, Smi::FromInt(flags));
+  int properties_count = constant_properties->length() / 2;
+  if (expr->may_store_doubles() || expr->depth() > 1 ||
+      masm()->serializer_enabled() || flags != ObjectLiteral::kFastElements ||
+      properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
+    __ Push(r6, r5, r4, r3);
+    __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
+  } else {
+    FastCloneShallowObjectStub stub(isolate(), properties_count);
+    __ CallStub(&stub);
+  }
+  PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
+
+  // If result_saved is true the result is on top of the stack.  If
+  // result_saved is false the result is in r3.
+  bool result_saved = false;
+
+  // Mark all computed expressions that are bound to a key that
+  // is shadowed by a later occurrence of the same key. For the
+  // marked expressions, no store code is emitted.
+  expr->CalculateEmitStore(zone());
+
+  AccessorTable accessor_table(zone());
+  for (int i = 0; i < expr->properties()->length(); i++) {
+    ObjectLiteral::Property* property = expr->properties()->at(i);
+    if (property->IsCompileTimeValue()) continue;
+
+    Literal* key = property->key();
+    Expression* value = property->value();
+    if (!result_saved) {
+      __ push(r3);  // Save result on stack
+      result_saved = true;
+    }
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT:
+        UNREACHABLE();
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+        DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
+      // Fall through.
+      case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
+        if (key->value()->IsInternalizedString()) {
+          if (property->emit_store()) {
+            VisitForAccumulatorValue(value);
+            DCHECK(StoreDescriptor::ValueRegister().is(r3));
+            __ mov(StoreDescriptor::NameRegister(), Operand(key->value()));
+            __ LoadP(StoreDescriptor::ReceiverRegister(), MemOperand(sp));
+            CallStoreIC(key->LiteralFeedbackId());
+            PrepareForBailoutForId(key->id(), NO_REGISTERS);
+          } else {
+            VisitForEffect(value);
+          }
+          break;
+        }
+        // Duplicate receiver on stack.
+        __ LoadP(r3, MemOperand(sp));
+        __ push(r3);
+        VisitForStackValue(key);
+        VisitForStackValue(value);
+        if (property->emit_store()) {
+          __ LoadSmiLiteral(r3, Smi::FromInt(SLOPPY));  // PropertyAttributes
+          __ push(r3);
+          __ CallRuntime(Runtime::kSetProperty, 4);
+        } else {
+          __ Drop(3);
+        }
+        break;
+      case ObjectLiteral::Property::PROTOTYPE:
+        // Duplicate receiver on stack.
+        __ LoadP(r3, MemOperand(sp));
+        __ push(r3);
+        VisitForStackValue(value);
+        if (property->emit_store()) {
+          __ CallRuntime(Runtime::kInternalSetPrototype, 2);
+        } else {
+          __ Drop(2);
+        }
+        break;
+      case ObjectLiteral::Property::GETTER:
+        accessor_table.lookup(key)->second->getter = value;
+        break;
+      case ObjectLiteral::Property::SETTER:
+        accessor_table.lookup(key)->second->setter = value;
+        break;
+    }
+  }
+
+  // Emit code to define accessors, using only a single call to the runtime for
+  // each pair of corresponding getters and setters.
+  for (AccessorTable::Iterator it = accessor_table.begin();
+       it != accessor_table.end(); ++it) {
+    __ LoadP(r3, MemOperand(sp));  // Duplicate receiver.
+    __ push(r3);
+    VisitForStackValue(it->first);
+    EmitAccessor(it->second->getter);
+    EmitAccessor(it->second->setter);
+    __ LoadSmiLiteral(r3, Smi::FromInt(NONE));
+    __ push(r3);
+    __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
+  }
+
+  if (expr->has_function()) {
+    DCHECK(result_saved);
+    __ LoadP(r3, MemOperand(sp));
+    __ push(r3);
+    __ CallRuntime(Runtime::kToFastProperties, 1);
+  }
+
+  if (result_saved) {
+    context()->PlugTOS();
+  } else {
+    context()->Plug(r3);
+  }
+}
+
+
+void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
+  Comment cmnt(masm_, "[ ArrayLiteral");
+
+  expr->BuildConstantElements(isolate());
+  int flags = expr->depth() == 1 ? ArrayLiteral::kShallowElements
+                                 : ArrayLiteral::kNoFlags;
+
+  ZoneList<Expression*>* subexprs = expr->values();
+  int length = subexprs->length();
+  Handle<FixedArray> constant_elements = expr->constant_elements();
+  DCHECK_EQ(2, constant_elements->length());
+  ElementsKind constant_elements_kind =
+      static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
+  bool has_fast_elements = IsFastObjectElementsKind(constant_elements_kind);
+  Handle<FixedArrayBase> constant_elements_values(
+      FixedArrayBase::cast(constant_elements->get(1)));
+
+  AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
+  if (has_fast_elements && !FLAG_allocation_site_pretenuring) {
+    // If the only customer of allocation sites is transitioning, then
+    // we can turn it off if we don't have anywhere else to transition to.
+    allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
+  }
+
+  __ LoadP(r6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ LoadP(r6, FieldMemOperand(r6, JSFunction::kLiteralsOffset));
+  __ LoadSmiLiteral(r5, Smi::FromInt(expr->literal_index()));
+  __ mov(r4, Operand(constant_elements));
+  if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) {
+    __ LoadSmiLiteral(r3, Smi::FromInt(flags));
+    __ Push(r6, r5, r4, r3);
+    __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
+  } else {
+    FastCloneShallowArrayStub stub(isolate(), allocation_site_mode);
+    __ CallStub(&stub);
+  }
+
+  bool result_saved = false;  // Is the result saved to the stack?
+
+  // Emit code to evaluate all the non-constant subexpressions and to store
+  // them into the newly cloned array.
+  for (int i = 0; i < length; i++) {
+    Expression* subexpr = subexprs->at(i);
+    // If the subexpression is a literal or a simple materialized literal it
+    // is already set in the cloned array.
+    if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
+
+    if (!result_saved) {
+      __ push(r3);
+      __ Push(Smi::FromInt(expr->literal_index()));
+      result_saved = true;
+    }
+    VisitForAccumulatorValue(subexpr);
+
+    if (IsFastObjectElementsKind(constant_elements_kind)) {
+      int offset = FixedArray::kHeaderSize + (i * kPointerSize);
+      __ LoadP(r8, MemOperand(sp, kPointerSize));  // Copy of array literal.
+      __ LoadP(r4, FieldMemOperand(r8, JSObject::kElementsOffset));
+      __ StoreP(result_register(), FieldMemOperand(r4, offset), r0);
+      // Update the write barrier for the array store.
+      __ RecordWriteField(r4, offset, result_register(), r5, kLRHasBeenSaved,
+                          kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+                          INLINE_SMI_CHECK);
+    } else {
+      __ LoadSmiLiteral(r6, Smi::FromInt(i));
+      StoreArrayLiteralElementStub stub(isolate());
+      __ CallStub(&stub);
+    }
+
+    PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
+  }
+
+  if (result_saved) {
+    __ pop();  // literal index
+    context()->PlugTOS();
+  } else {
+    context()->Plug(r3);
+  }
+}
+
+
+void FullCodeGenerator::VisitAssignment(Assignment* expr) {
+  DCHECK(expr->target()->IsValidReferenceExpression());
+
+  Comment cmnt(masm_, "[ Assignment");
+
+  Property* property = expr->target()->AsProperty();
+  LhsKind assign_type = GetAssignType(property);
+
+  // Evaluate LHS expression.
+  switch (assign_type) {
+    case VARIABLE:
+      // Nothing to do here.
+      break;
+    case NAMED_PROPERTY:
+      if (expr->is_compound()) {
+        // We need the receiver both on the stack and in the register.
+        VisitForStackValue(property->obj());
+        __ LoadP(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
+      } else {
+        VisitForStackValue(property->obj());
+      }
+      break;
+    case NAMED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Push(result_register());
+      if (expr->is_compound()) {
+        const Register scratch = r4;
+        __ LoadP(scratch, MemOperand(sp, kPointerSize));
+        __ Push(scratch, result_register());
+      }
+      break;
+    case KEYED_SUPER_PROPERTY: {
+      const Register scratch = r4;
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Move(scratch, result_register());
+      VisitForAccumulatorValue(property->key());
+      __ Push(scratch, result_register());
+      if (expr->is_compound()) {
+        const Register scratch1 = r5;
+        __ LoadP(scratch1, MemOperand(sp, 2 * kPointerSize));
+        __ Push(scratch1, scratch, result_register());
+      }
+      break;
+    }
+    case KEYED_PROPERTY:
+      if (expr->is_compound()) {
+        VisitForStackValue(property->obj());
+        VisitForStackValue(property->key());
+        __ LoadP(LoadDescriptor::ReceiverRegister(),
+                 MemOperand(sp, 1 * kPointerSize));
+        __ LoadP(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
+      } else {
+        VisitForStackValue(property->obj());
+        VisitForStackValue(property->key());
+      }
+      break;
+  }
+
+  // For compound assignments we need another deoptimization point after the
+  // variable/property load.
+  if (expr->is_compound()) {
+    {
+      AccumulatorValueContext context(this);
+      switch (assign_type) {
+        case VARIABLE:
+          EmitVariableLoad(expr->target()->AsVariableProxy());
+          PrepareForBailout(expr->target(), TOS_REG);
+          break;
+        case NAMED_PROPERTY:
+          EmitNamedPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
+        case NAMED_SUPER_PROPERTY:
+          EmitNamedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
+        case KEYED_SUPER_PROPERTY:
+          EmitKeyedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
+        case KEYED_PROPERTY:
+          EmitKeyedPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
+      }
+    }
+
+    Token::Value op = expr->binary_op();
+    __ push(r3);  // Left operand goes on the stack.
+    VisitForAccumulatorValue(expr->value());
+
+    OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
+                             ? OVERWRITE_RIGHT
+                             : NO_OVERWRITE;
+    SetSourcePosition(expr->position() + 1);
+    AccumulatorValueContext context(this);
+    if (ShouldInlineSmiCase(op)) {
+      EmitInlineSmiBinaryOp(expr->binary_operation(), op, mode, expr->target(),
+                            expr->value());
+    } else {
+      EmitBinaryOp(expr->binary_operation(), op, mode);
+    }
+
+    // Deoptimization point in case the binary operation may have side effects.
+    PrepareForBailout(expr->binary_operation(), TOS_REG);
+  } else {
+    VisitForAccumulatorValue(expr->value());
+  }
+
+  // Record source position before possible IC call.
+  SetSourcePosition(expr->position());
+
+  // Store the value.
+  switch (assign_type) {
+    case VARIABLE:
+      EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
+                             expr->op());
+      PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
+      context()->Plug(r3);
+      break;
+    case NAMED_PROPERTY:
+      EmitNamedPropertyAssignment(expr);
+      break;
+    case NAMED_SUPER_PROPERTY:
+      EmitNamedSuperPropertyStore(property);
+      context()->Plug(r3);
+      break;
+    case KEYED_SUPER_PROPERTY:
+      EmitKeyedSuperPropertyStore(property);
+      context()->Plug(r3);
+      break;
+    case KEYED_PROPERTY:
+      EmitKeyedPropertyAssignment(expr);
+      break;
+  }
+}
+
+
+void FullCodeGenerator::VisitYield(Yield* expr) {
+  Comment cmnt(masm_, "[ Yield");
+  // Evaluate yielded value first; the initial iterator definition depends on
+  // this.  It stays on the stack while we update the iterator.
+  VisitForStackValue(expr->expression());
+
+  switch (expr->yield_kind()) {
+    case Yield::kSuspend:
+      // Pop value from top-of-stack slot; box result into result register.
+      EmitCreateIteratorResult(false);
+      __ push(result_register());
+    // Fall through.
+    case Yield::kInitial: {
+      Label suspend, continuation, post_runtime, resume;
+
+      __ b(&suspend);
+
+      __ bind(&continuation);
+      __ b(&resume);
+
+      __ bind(&suspend);
+      VisitForAccumulatorValue(expr->generator_object());
+      DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
+      __ LoadSmiLiteral(r4, Smi::FromInt(continuation.pos()));
+      __ StoreP(r4, FieldMemOperand(r3, JSGeneratorObject::kContinuationOffset),
+                r0);
+      __ StoreP(cp, FieldMemOperand(r3, JSGeneratorObject::kContextOffset), r0);
+      __ mr(r4, cp);
+      __ RecordWriteField(r3, JSGeneratorObject::kContextOffset, r4, r5,
+                          kLRHasBeenSaved, kDontSaveFPRegs);
+      __ addi(r4, fp, Operand(StandardFrameConstants::kExpressionsOffset));
+      __ cmp(sp, r4);
+      __ beq(&post_runtime);
+      __ push(r3);  // generator object
+      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+      __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+      __ bind(&post_runtime);
+      __ pop(result_register());
+      EmitReturnSequence();
+
+      __ bind(&resume);
+      context()->Plug(result_register());
+      break;
+    }
+
+    case Yield::kFinal: {
+      VisitForAccumulatorValue(expr->generator_object());
+      __ LoadSmiLiteral(r4, Smi::FromInt(JSGeneratorObject::kGeneratorClosed));
+      __ StoreP(r4, FieldMemOperand(result_register(),
+                                    JSGeneratorObject::kContinuationOffset),
+                r0);
+      // Pop value from top-of-stack slot, box result into result register.
+      EmitCreateIteratorResult(true);
+      EmitUnwindBeforeReturn();
+      EmitReturnSequence();
+      break;
+    }
+
+    case Yield::kDelegating: {
+      VisitForStackValue(expr->generator_object());
+
+      // Initial stack layout is as follows:
+      // [sp + 1 * kPointerSize] iter
+      // [sp + 0 * kPointerSize] g
+
+      Label l_catch, l_try, l_suspend, l_continuation, l_resume;
+      Label l_next, l_call;
+      Register load_receiver = LoadDescriptor::ReceiverRegister();
+      Register load_name = LoadDescriptor::NameRegister();
+
+      // Initial send value is undefined.
+      __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
+      __ b(&l_next);
+
+      // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
+      __ bind(&l_catch);
+      handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
+      __ LoadRoot(load_name, Heap::kthrow_stringRootIndex);  // "throw"
+      __ LoadP(r6, MemOperand(sp, 1 * kPointerSize));        // iter
+      __ Push(load_name, r6, r3);  // "throw", iter, except
+      __ b(&l_call);
+
+      // try { received = %yield result }
+      // Shuffle the received result above a try handler and yield it without
+      // re-boxing.
+      __ bind(&l_try);
+      __ pop(r3);  // result
+      __ PushTryHandler(StackHandler::CATCH, expr->index());
+      const int handler_size = StackHandlerConstants::kSize;
+      __ push(r3);  // result
+      __ b(&l_suspend);
+      __ bind(&l_continuation);
+      __ b(&l_resume);
+      __ bind(&l_suspend);
+      const int generator_object_depth = kPointerSize + handler_size;
+      __ LoadP(r3, MemOperand(sp, generator_object_depth));
+      __ push(r3);  // g
+      DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
+      __ LoadSmiLiteral(r4, Smi::FromInt(l_continuation.pos()));
+      __ StoreP(r4, FieldMemOperand(r3, JSGeneratorObject::kContinuationOffset),
+                r0);
+      __ StoreP(cp, FieldMemOperand(r3, JSGeneratorObject::kContextOffset), r0);
+      __ mr(r4, cp);
+      __ RecordWriteField(r3, JSGeneratorObject::kContextOffset, r4, r5,
+                          kLRHasBeenSaved, kDontSaveFPRegs);
+      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+      __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+      __ pop(r3);  // result
+      EmitReturnSequence();
+      __ bind(&l_resume);  // received in r3
+      __ PopTryHandler();
+
+      // receiver = iter; f = 'next'; arg = received;
+      __ bind(&l_next);
+
+      __ LoadRoot(load_name, Heap::knext_stringRootIndex);  // "next"
+      __ LoadP(r6, MemOperand(sp, 1 * kPointerSize));       // iter
+      __ Push(load_name, r6, r3);  // "next", iter, received
+
+      // result = receiver[f](arg);
+      __ bind(&l_call);
+      __ LoadP(load_receiver, MemOperand(sp, kPointerSize));
+      __ LoadP(load_name, MemOperand(sp, 2 * kPointerSize));
+      if (FLAG_vector_ics) {
+        __ mov(VectorLoadICDescriptor::SlotRegister(),
+               Operand(SmiFromSlot(expr->KeyedLoadFeedbackSlot())));
+      }
+      Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
+      CallIC(ic, TypeFeedbackId::None());
+      __ mr(r4, r3);
+      __ StoreP(r4, MemOperand(sp, 2 * kPointerSize));
+      CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD);
+      __ CallStub(&stub);
+
+      __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+      __ Drop(1);  // The function is still on the stack; drop it.
+
+      // if (!result.done) goto l_try;
+      __ Move(load_receiver, r3);
+
+      __ push(load_receiver);                               // save result
+      __ LoadRoot(load_name, Heap::kdone_stringRootIndex);  // "done"
+      if (FLAG_vector_ics) {
+        __ mov(VectorLoadICDescriptor::SlotRegister(),
+               Operand(SmiFromSlot(expr->DoneFeedbackSlot())));
+      }
+      CallLoadIC(NOT_CONTEXTUAL);  // r0=result.done
+      Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
+      CallIC(bool_ic);
+      __ cmpi(r3, Operand::Zero());
+      __ beq(&l_try);
+
+      // result.value
+      __ pop(load_receiver);                                 // result
+      __ LoadRoot(load_name, Heap::kvalue_stringRootIndex);  // "value"
+      if (FLAG_vector_ics) {
+        __ mov(VectorLoadICDescriptor::SlotRegister(),
+               Operand(SmiFromSlot(expr->ValueFeedbackSlot())));
+      }
+      CallLoadIC(NOT_CONTEXTUAL);     // r3=result.value
+      context()->DropAndPlug(2, r3);  // drop iter and g
+      break;
+    }
+  }
+}
+
+
+void FullCodeGenerator::EmitGeneratorResume(
+    Expression* generator, Expression* value,
+    JSGeneratorObject::ResumeMode resume_mode) {
+  // The value stays in r3, and is ultimately read by the resumed generator, as
+  // if CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it
+  // is read to throw the value when the resumed generator is already closed.
+  // r4 will hold the generator object until the activation has been resumed.
+  VisitForStackValue(generator);
+  VisitForAccumulatorValue(value);
+  __ pop(r4);
+
+  // Check generator state.
+  Label wrong_state, closed_state, done;
+  __ LoadP(r6, FieldMemOperand(r4, JSGeneratorObject::kContinuationOffset));
+  STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
+  STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
+  __ CmpSmiLiteral(r6, Smi::FromInt(0), r0);
+  __ beq(&closed_state);
+  __ blt(&wrong_state);
+
+  // Load suspended function and context.
+  __ LoadP(cp, FieldMemOperand(r4, JSGeneratorObject::kContextOffset));
+  __ LoadP(r7, FieldMemOperand(r4, JSGeneratorObject::kFunctionOffset));
+
+  // Load receiver and store as the first argument.
+  __ LoadP(r5, FieldMemOperand(r4, JSGeneratorObject::kReceiverOffset));
+  __ push(r5);
+
+  // Push holes for the rest of the arguments to the generator function.
+  __ LoadP(r6, FieldMemOperand(r7, JSFunction::kSharedFunctionInfoOffset));
+  __ LoadWordArith(
+      r6, FieldMemOperand(r6, SharedFunctionInfo::kFormalParameterCountOffset));
+  __ LoadRoot(r5, Heap::kTheHoleValueRootIndex);
+  Label argument_loop, push_frame;
+#if V8_TARGET_ARCH_PPC64
+  __ cmpi(r6, Operand::Zero());
+  __ beq(&push_frame);
+#else
+  __ SmiUntag(r6, SetRC);
+  __ beq(&push_frame, cr0);
+#endif
+  __ mtctr(r6);
+  __ bind(&argument_loop);
+  __ push(r5);
+  __ bdnz(&argument_loop);
+
+  // Enter a new JavaScript frame, and initialize its slots as they were when
+  // the generator was suspended.
+  Label resume_frame;
+  __ bind(&push_frame);
+  __ b(&resume_frame, SetLK);
+  __ b(&done);
+  __ bind(&resume_frame);
+  // lr = return address.
+  // fp = caller's frame pointer.
+  // cp = callee's context,
+  // r7 = callee's JS function.
+  __ PushFixedFrame(r7);
+  // Adjust FP to point to saved FP.
+  __ addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+
+  // Load the operand stack size.
+  __ LoadP(r6, FieldMemOperand(r4, JSGeneratorObject::kOperandStackOffset));
+  __ LoadP(r6, FieldMemOperand(r6, FixedArray::kLengthOffset));
+  __ SmiUntag(r6, SetRC);
+
+  // If we are sending a value and there is no operand stack, we can jump back
+  // in directly.
+  Label call_resume;
+  if (resume_mode == JSGeneratorObject::NEXT) {
+    Label slow_resume;
+    __ bne(&slow_resume, cr0);
+    __ LoadP(ip, FieldMemOperand(r7, JSFunction::kCodeEntryOffset));
+#if V8_OOL_CONSTANT_POOL
+    {
+      ConstantPoolUnavailableScope constant_pool_unavailable(masm_);
+      // Load the new code object's constant pool pointer.
+      __ LoadP(kConstantPoolRegister,
+               MemOperand(ip, Code::kConstantPoolOffset - Code::kHeaderSize));
+#endif
+      __ LoadP(r5, FieldMemOperand(r4, JSGeneratorObject::kContinuationOffset));
+      __ SmiUntag(r5);
+      __ add(ip, ip, r5);
+      __ LoadSmiLiteral(r5,
+                        Smi::FromInt(JSGeneratorObject::kGeneratorExecuting));
+      __ StoreP(r5, FieldMemOperand(r4, JSGeneratorObject::kContinuationOffset),
+                r0);
+      __ Jump(ip);
+      __ bind(&slow_resume);
+#if V8_OOL_CONSTANT_POOL
+    }
+#endif
+  } else {
+    __ beq(&call_resume, cr0);
+  }
+
+  // Otherwise, we push holes for the operand stack and call the runtime to fix
+  // up the stack and the handlers.
+  Label operand_loop;
+  __ mtctr(r6);
+  __ bind(&operand_loop);
+  __ push(r5);
+  __ bdnz(&operand_loop);
+
+  __ bind(&call_resume);
+  DCHECK(!result_register().is(r4));
+  __ Push(r4, result_register());
+  __ Push(Smi::FromInt(resume_mode));
+  __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3);
+  // Not reached: the runtime call returns elsewhere.
+  __ stop("not-reached");
+
+  // Reach here when generator is closed.
+  __ bind(&closed_state);
+  if (resume_mode == JSGeneratorObject::NEXT) {
+    // Return completed iterator result when generator is closed.
+    __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
+    __ push(r5);
+    // Pop value from top-of-stack slot; box result into result register.
+    EmitCreateIteratorResult(true);
+  } else {
+    // Throw the provided value.
+    __ push(r3);
+    __ CallRuntime(Runtime::kThrow, 1);
+  }
+  __ b(&done);
+
+  // Throw error if we attempt to operate on a running generator.
+  __ bind(&wrong_state);
+  __ push(r4);
+  __ CallRuntime(Runtime::kThrowGeneratorStateError, 1);
+
+  __ bind(&done);
+  context()->Plug(result_register());
+}
+
+
+void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
+  Label gc_required;
+  Label allocated;
+
+  const int instance_size = 5 * kPointerSize;
+  DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
+            instance_size);
+
+  __ Allocate(instance_size, r3, r5, r6, &gc_required, TAG_OBJECT);
+  __ b(&allocated);
+
+  __ bind(&gc_required);
+  __ Push(Smi::FromInt(instance_size));
+  __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
+  __ LoadP(context_register(),
+           MemOperand(fp, StandardFrameConstants::kContextOffset));
+
+  __ bind(&allocated);
+  __ LoadP(r4, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
+  __ LoadP(r4, FieldMemOperand(r4, GlobalObject::kNativeContextOffset));
+  __ LoadP(r4, ContextOperand(r4, Context::ITERATOR_RESULT_MAP_INDEX));
+  __ pop(r5);
+  __ mov(r6, Operand(isolate()->factory()->ToBoolean(done)));
+  __ mov(r7, Operand(isolate()->factory()->empty_fixed_array()));
+  __ StoreP(r4, FieldMemOperand(r3, HeapObject::kMapOffset), r0);
+  __ StoreP(r7, FieldMemOperand(r3, JSObject::kPropertiesOffset), r0);
+  __ StoreP(r7, FieldMemOperand(r3, JSObject::kElementsOffset), r0);
+  __ StoreP(r5,
+            FieldMemOperand(r3, JSGeneratorObject::kResultValuePropertyOffset),
+            r0);
+  __ StoreP(r6,
+            FieldMemOperand(r3, JSGeneratorObject::kResultDonePropertyOffset),
+            r0);
+
+  // Only the value field needs a write barrier, as the other values are in the
+  // root set.
+  __ RecordWriteField(r3, JSGeneratorObject::kResultValuePropertyOffset, r5, r6,
+                      kLRHasBeenSaved, kDontSaveFPRegs);
+}
+
+
+void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
+  SetSourcePosition(prop->position());
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(!prop->IsSuperAccess());
+
+  __ mov(LoadDescriptor::NameRegister(), Operand(key->value()));
+  if (FLAG_vector_ics) {
+    __ mov(VectorLoadICDescriptor::SlotRegister(),
+           Operand(SmiFromSlot(prop->PropertyFeedbackSlot())));
+    CallLoadIC(NOT_CONTEXTUAL);
+  } else {
+    CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
+  }
+}
+
+
+void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object.
+  SetSourcePosition(prop->position());
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(!key->value()->IsSmi());
+  DCHECK(prop->IsSuperAccess());
+
+  __ Push(key->value());
+  __ CallRuntime(Runtime::kLoadFromSuper, 3);
+}
+
+
+void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
+  SetSourcePosition(prop->position());
+  Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
+  if (FLAG_vector_ics) {
+    __ mov(VectorLoadICDescriptor::SlotRegister(),
+           Operand(SmiFromSlot(prop->PropertyFeedbackSlot())));
+    CallIC(ic);
+  } else {
+    CallIC(ic, prop->PropertyFeedbackId());
+  }
+}
+
+
+void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object, key.
+  SetSourcePosition(prop->position());
+
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+}
+
+
+void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
+                                              Token::Value op,
+                                              OverwriteMode mode,
+                                              Expression* left_expr,
+                                              Expression* right_expr) {
+  Label done, smi_case, stub_call;
+
+  Register scratch1 = r5;
+  Register scratch2 = r6;
+
+  // Get the arguments.
+  Register left = r4;
+  Register right = r3;
+  __ pop(left);
+
+  // Perform combined smi check on both operands.
+  __ orx(scratch1, left, right);
+  STATIC_ASSERT(kSmiTag == 0);
+  JumpPatchSite patch_site(masm_);
+  patch_site.EmitJumpIfSmi(scratch1, &smi_case);
+
+  __ bind(&stub_call);
+  Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op, mode).code();
+  CallIC(code, expr->BinaryOperationFeedbackId());
+  patch_site.EmitPatchInfo();
+  __ b(&done);
+
+  __ bind(&smi_case);
+  // Smi case. This code works the same way as the smi-smi case in the type
+  // recording binary operation stub.
+  switch (op) {
+    case Token::SAR:
+      __ GetLeastBitsFromSmi(scratch1, right, 5);
+      __ ShiftRightArith(right, left, scratch1);
+      __ ClearRightImm(right, right, Operand(kSmiTagSize + kSmiShiftSize));
+      break;
+    case Token::SHL: {
+      __ GetLeastBitsFromSmi(scratch2, right, 5);
+#if V8_TARGET_ARCH_PPC64
+      __ ShiftLeft_(right, left, scratch2);
+#else
+      __ SmiUntag(scratch1, left);
+      __ ShiftLeft_(scratch1, scratch1, scratch2);
+      // Check that the *signed* result fits in a smi
+      __ JumpIfNotSmiCandidate(scratch1, scratch2, &stub_call);
+      __ SmiTag(right, scratch1);
+#endif
+      break;
+    }
+    case Token::SHR: {
+      __ SmiUntag(scratch1, left);
+      __ GetLeastBitsFromSmi(scratch2, right, 5);
+      __ srw(scratch1, scratch1, scratch2);
+      // Unsigned shift is not allowed to produce a negative number.
+      __ JumpIfNotUnsignedSmiCandidate(scratch1, r0, &stub_call);
+      __ SmiTag(right, scratch1);
+      break;
+    }
+    case Token::ADD: {
+      __ AddAndCheckForOverflow(scratch1, left, right, scratch2, r0);
+      __ bne(&stub_call, cr0);
+      __ mr(right, scratch1);
+      break;
+    }
+    case Token::SUB: {
+      __ SubAndCheckForOverflow(scratch1, left, right, scratch2, r0);
+      __ bne(&stub_call, cr0);
+      __ mr(right, scratch1);
+      break;
+    }
+    case Token::MUL: {
+      Label mul_zero;
+#if V8_TARGET_ARCH_PPC64
+      // Remove tag from both operands.
+      __ SmiUntag(ip, right);
+      __ SmiUntag(r0, left);
+      __ Mul(scratch1, r0, ip);
+      // Check for overflowing the smi range - no overflow if higher 33 bits of
+      // the result are identical.
+      __ TestIfInt32(scratch1, scratch2, ip);
+      __ bne(&stub_call);
+#else
+      __ SmiUntag(ip, right);
+      __ mullw(scratch1, left, ip);
+      __ mulhw(scratch2, left, ip);
+      // Check for overflowing the smi range - no overflow if higher 33 bits of
+      // the result are identical.
+      __ TestIfInt32(scratch2, scratch1, ip);
+      __ bne(&stub_call);
+#endif
+      // Go slow on zero result to handle -0.
+      __ cmpi(scratch1, Operand::Zero());
+      __ beq(&mul_zero);
+#if V8_TARGET_ARCH_PPC64
+      __ SmiTag(right, scratch1);
+#else
+      __ mr(right, scratch1);
+#endif
+      __ b(&done);
+      // We need -0 if we were multiplying a negative number with 0 to get 0.
+      // We know one of them was zero.
+      __ bind(&mul_zero);
+      __ add(scratch2, right, left);
+      __ cmpi(scratch2, Operand::Zero());
+      __ blt(&stub_call);
+      __ LoadSmiLiteral(right, Smi::FromInt(0));
+      break;
+    }
+    case Token::BIT_OR:
+      __ orx(right, left, right);
+      break;
+    case Token::BIT_AND:
+      __ and_(right, left, right);
+      break;
+    case Token::BIT_XOR:
+      __ xor_(right, left, right);
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  __ bind(&done);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
+  // Constructor is in r3.
+  DCHECK(lit != NULL);
+  __ push(r3);
+
+  // No access check is needed here since the constructor is created by the
+  // class literal.
+  Register scratch = r4;
+  __ LoadP(scratch,
+           FieldMemOperand(r3, JSFunction::kPrototypeOrInitialMapOffset));
+  __ push(scratch);
+
+  for (int i = 0; i < lit->properties()->length(); i++) {
+    ObjectLiteral::Property* property = lit->properties()->at(i);
+    Literal* key = property->key()->AsLiteral();
+    Expression* value = property->value();
+    DCHECK(key != NULL);
+
+    if (property->is_static()) {
+      __ LoadP(scratch, MemOperand(sp, kPointerSize));  // constructor
+    } else {
+      __ LoadP(scratch, MemOperand(sp, 0));  // prototype
+    }
+    __ push(scratch);
+    VisitForStackValue(key);
+    VisitForStackValue(value);
+
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT:
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+      case ObjectLiteral::Property::COMPUTED:
+      case ObjectLiteral::Property::PROTOTYPE:
+        __ CallRuntime(Runtime::kDefineClassMethod, 3);
+        break;
+
+      case ObjectLiteral::Property::GETTER:
+        __ CallRuntime(Runtime::kDefineClassGetter, 3);
+        break;
+
+      case ObjectLiteral::Property::SETTER:
+        __ CallRuntime(Runtime::kDefineClassSetter, 3);
+        break;
+
+      default:
+        UNREACHABLE();
+    }
+  }
+
+  // prototype
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+
+  // constructor
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+}
+
+
+void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op,
+                                     OverwriteMode mode) {
+  __ pop(r4);
+  Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op, mode).code();
+  JumpPatchSite patch_site(masm_);  // unbound, signals no inlined smi code.
+  CallIC(code, expr->BinaryOperationFeedbackId());
+  patch_site.EmitPatchInfo();
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitAssignment(Expression* expr) {
+  DCHECK(expr->IsValidReferenceExpression());
+
+  Property* prop = expr->AsProperty();
+  LhsKind assign_type = GetAssignType(prop);
+
+  switch (assign_type) {
+    case VARIABLE: {
+      Variable* var = expr->AsVariableProxy()->var();
+      EffectContext context(this);
+      EmitVariableAssignment(var, Token::ASSIGN);
+      break;
+    }
+    case NAMED_PROPERTY: {
+      __ push(r3);  // Preserve value.
+      VisitForAccumulatorValue(prop->obj());
+      __ Move(StoreDescriptor::ReceiverRegister(), r3);
+      __ pop(StoreDescriptor::ValueRegister());  // Restore value.
+      __ mov(StoreDescriptor::NameRegister(),
+             Operand(prop->key()->AsLiteral()->value()));
+      CallStoreIC();
+      break;
+    }
+    case NAMED_SUPER_PROPERTY: {
+      __ Push(r3);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      // stack: value, this; r3: home_object
+      Register scratch = r5;
+      Register scratch2 = r6;
+      __ mr(scratch, result_register());                  // home_object
+      __ LoadP(r3, MemOperand(sp, kPointerSize));         // value
+      __ LoadP(scratch2, MemOperand(sp, 0));              // this
+      __ StoreP(scratch2, MemOperand(sp, kPointerSize));  // this
+      __ StoreP(scratch, MemOperand(sp, 0));              // home_object
+      // stack: this, home_object; r3: value
+      EmitNamedSuperPropertyStore(prop);
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      __ Push(r3);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForAccumulatorValue(prop->key());
+      Register scratch = r5;
+      Register scratch2 = r6;
+      __ LoadP(scratch2, MemOperand(sp, 2 * kPointerSize));  // value
+      // stack: value, this, home_object; r3: key, r6: value
+      __ LoadP(scratch, MemOperand(sp, kPointerSize));  // this
+      __ StoreP(scratch, MemOperand(sp, 2 * kPointerSize));
+      __ LoadP(scratch, MemOperand(sp, 0));  // home_object
+      __ StoreP(scratch, MemOperand(sp, kPointerSize));
+      __ StoreP(r3, MemOperand(sp, 0));
+      __ Move(r3, scratch2);
+      // stack: this, home_object, key; r3: value.
+      EmitKeyedSuperPropertyStore(prop);
+      break;
+    }
+    case KEYED_PROPERTY: {
+      __ push(r3);  // Preserve value.
+      VisitForStackValue(prop->obj());
+      VisitForAccumulatorValue(prop->key());
+      __ Move(StoreDescriptor::NameRegister(), r3);
+      __ Pop(StoreDescriptor::ValueRegister(),
+             StoreDescriptor::ReceiverRegister());
+      Handle<Code> ic =
+          CodeFactory::KeyedStoreIC(isolate(), strict_mode()).code();
+      CallIC(ic);
+      break;
+    }
+  }
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
+    Variable* var, MemOperand location) {
+  __ StoreP(result_register(), location, r0);
+  if (var->IsContextSlot()) {
+    // RecordWrite may destroy all its register arguments.
+    __ mr(r6, result_register());
+    int offset = Context::SlotOffset(var->index());
+    __ RecordWriteContextSlot(r4, offset, r6, r5, kLRHasBeenSaved,
+                              kDontSaveFPRegs);
+  }
+}
+
+
+void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
+  if (var->IsUnallocated()) {
+    // Global var, const, or let.
+    __ mov(StoreDescriptor::NameRegister(), Operand(var->name()));
+    __ LoadP(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
+    CallStoreIC();
+
+  } else if (op == Token::INIT_CONST_LEGACY) {
+    // Const initializers need a write barrier.
+    DCHECK(!var->IsParameter());  // No const parameters.
+    if (var->IsLookupSlot()) {
+      __ push(r3);
+      __ mov(r3, Operand(var->name()));
+      __ Push(cp, r3);  // Context and name.
+      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
+    } else {
+      DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+      Label skip;
+      MemOperand location = VarOperand(var, r4);
+      __ LoadP(r5, location);
+      __ CompareRoot(r5, Heap::kTheHoleValueRootIndex);
+      __ bne(&skip);
+      EmitStoreToStackLocalOrContextSlot(var, location);
+      __ bind(&skip);
+    }
+
+  } else if (var->mode() == LET && op != Token::INIT_LET) {
+    // Non-initializing assignment to let variable needs a write barrier.
+    DCHECK(!var->IsLookupSlot());
+    DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+    Label assign;
+    MemOperand location = VarOperand(var, r4);
+    __ LoadP(r6, location);
+    __ CompareRoot(r6, Heap::kTheHoleValueRootIndex);
+    __ bne(&assign);
+    __ mov(r6, Operand(var->name()));
+    __ push(r6);
+    __ CallRuntime(Runtime::kThrowReferenceError, 1);
+    // Perform the assignment.
+    __ bind(&assign);
+    EmitStoreToStackLocalOrContextSlot(var, location);
+
+  } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
+    if (var->IsLookupSlot()) {
+      // Assignment to var.
+      __ push(r3);  // Value.
+      __ mov(r4, Operand(var->name()));
+      __ mov(r3, Operand(Smi::FromInt(strict_mode())));
+      __ Push(cp, r4, r3);  // Context, name, strict mode.
+      __ CallRuntime(Runtime::kStoreLookupSlot, 4);
+    } else {
+      // Assignment to var or initializing assignment to let/const in harmony
+      // mode.
+      DCHECK((var->IsStackAllocated() || var->IsContextSlot()));
+      MemOperand location = VarOperand(var, r4);
+      if (generate_debug_code_ && op == Token::INIT_LET) {
+        // Check for an uninitialized let binding.
+        __ LoadP(r5, location);
+        __ CompareRoot(r5, Heap::kTheHoleValueRootIndex);
+        __ Check(eq, kLetBindingReInitialization);
+      }
+      EmitStoreToStackLocalOrContextSlot(var, location);
+    }
+  }
+  // Non-initializing assignments to consts are ignored.
+}
+
+
+void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
+  // Assignment to a property, using a named store IC.
+  Property* prop = expr->target()->AsProperty();
+  DCHECK(prop != NULL);
+  DCHECK(prop->key()->IsLiteral());
+
+  // Record source code position before IC call.
+  SetSourcePosition(expr->position());
+  __ mov(StoreDescriptor::NameRegister(),
+         Operand(prop->key()->AsLiteral()->value()));
+  __ pop(StoreDescriptor::ReceiverRegister());
+  CallStoreIC(expr->AssignmentFeedbackId());
+
+  PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // r3 : value
+  // stack : receiver ('this'), home_object
+  DCHECK(prop != NULL);
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(key != NULL);
+
+  __ Push(key->value());
+  __ Push(r3);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
+                                          : Runtime::kStoreToSuper_Sloppy),
+                 4);
+}
+
+
+void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // r3 : value
+  // stack : receiver ('this'), home_object, key
+  DCHECK(prop != NULL);
+
+  __ Push(r3);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict
+                                          : Runtime::kStoreKeyedToSuper_Sloppy),
+                 4);
+}
+
+
+void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
+  // Assignment to a property, using a keyed store IC.
+
+  // Record source code position before IC call.
+  SetSourcePosition(expr->position());
+  __ Pop(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister());
+  DCHECK(StoreDescriptor::ValueRegister().is(r3));
+
+  Handle<Code> ic = CodeFactory::KeyedStoreIC(isolate(), strict_mode()).code();
+  CallIC(ic, expr->AssignmentFeedbackId());
+
+  PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::VisitProperty(Property* expr) {
+  Comment cmnt(masm_, "[ Property");
+  Expression* key = expr->key();
+
+  if (key->IsPropertyName()) {
+    if (!expr->IsSuperAccess()) {
+      VisitForAccumulatorValue(expr->obj());
+      __ Move(LoadDescriptor::ReceiverRegister(), r3);
+      EmitNamedPropertyLoad(expr);
+    } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
+      EmitNamedSuperPropertyLoad(expr);
+    }
+    PrepareForBailoutForId(expr->LoadId(), TOS_REG);
+    context()->Plug(r3);
+  } else {
+    if (!expr->IsSuperAccess()) {
+      VisitForStackValue(expr->obj());
+      VisitForAccumulatorValue(expr->key());
+      __ Move(LoadDescriptor::NameRegister(), r3);
+      __ pop(LoadDescriptor::ReceiverRegister());
+      EmitKeyedPropertyLoad(expr);
+    } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForStackValue(expr->key());
+      EmitKeyedSuperPropertyLoad(expr);
+    }
+    context()->Plug(r3);
+  }
+}
+
+
+void FullCodeGenerator::CallIC(Handle<Code> code, TypeFeedbackId ast_id) {
+  ic_total_count_++;
+  __ Call(code, RelocInfo::CODE_TARGET, ast_id);
+}
+
+
+// Code common for calls using the IC.
+void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
+  Expression* callee = expr->expression();
+
+  CallICState::CallType call_type =
+      callee->IsVariableProxy() ? CallICState::FUNCTION : CallICState::METHOD;
+
+  // Get the target function.
+  if (call_type == CallICState::FUNCTION) {
+    {
+      StackValueContext context(this);
+      EmitVariableLoad(callee->AsVariableProxy());
+      PrepareForBailout(callee, NO_REGISTERS);
+    }
+    // Push undefined as receiver. This is patched in the method prologue if it
+    // is a sloppy mode method.
+    __ Push(isolate()->factory()->undefined_value());
+  } else {
+    // Load the function from the receiver.
+    DCHECK(callee->IsProperty());
+    DCHECK(!callee->AsProperty()->IsSuperAccess());
+    __ LoadP(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
+    EmitNamedPropertyLoad(callee->AsProperty());
+    PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
+    // Push the target function under the receiver.
+    __ LoadP(ip, MemOperand(sp, 0));
+    __ push(ip);
+    __ StoreP(r3, MemOperand(sp, kPointerSize));
+  }
+
+  EmitCall(expr, call_type);
+}
+
+
+void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
+  Expression* callee = expr->expression();
+  DCHECK(callee->IsProperty());
+  Property* prop = callee->AsProperty();
+  DCHECK(prop->IsSuperAccess());
+
+  SetSourcePosition(prop->position());
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(!key->value()->IsSmi());
+  // Load the function from the receiver.
+  const Register scratch = r4;
+  SuperReference* super_ref = prop->obj()->AsSuperReference();
+  EmitLoadHomeObject(super_ref);
+  __ mr(scratch, r3);
+  VisitForAccumulatorValue(super_ref->this_var());
+  __ Push(scratch, r3, r3, scratch);
+  __ Push(key->value());
+
+  // Stack here:
+  //  - home_object
+  //  - this (receiver)
+  //  - this (receiver) <-- LoadFromSuper will pop here and below.
+  //  - home_object
+  //  - key
+  __ CallRuntime(Runtime::kLoadFromSuper, 3);
+
+  // Replace home_object with target function.
+  __ StoreP(r3, MemOperand(sp, kPointerSize));
+
+  // Stack here:
+  // - target function
+  // - this (receiver)
+  EmitCall(expr, CallICState::METHOD);
+}
+
+
+// Code common for calls using the IC.
+void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr, Expression* key) {
+  // Load the key.
+  VisitForAccumulatorValue(key);
+
+  Expression* callee = expr->expression();
+
+  // Load the function from the receiver.
+  DCHECK(callee->IsProperty());
+  __ LoadP(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
+  __ Move(LoadDescriptor::NameRegister(), r3);
+  EmitKeyedPropertyLoad(callee->AsProperty());
+  PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
+
+  // Push the target function under the receiver.
+  __ LoadP(ip, MemOperand(sp, 0));
+  __ push(ip);
+  __ StoreP(r3, MemOperand(sp, kPointerSize));
+
+  EmitCall(expr, CallICState::METHOD);
+}
+
+
+void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
+  Expression* callee = expr->expression();
+  DCHECK(callee->IsProperty());
+  Property* prop = callee->AsProperty();
+  DCHECK(prop->IsSuperAccess());
+
+  SetSourcePosition(prop->position());
+  // Load the function from the receiver.
+  const Register scratch = r4;
+  SuperReference* super_ref = prop->obj()->AsSuperReference();
+  EmitLoadHomeObject(super_ref);
+  __ Push(r3);
+  VisitForAccumulatorValue(super_ref->this_var());
+  __ Push(r3);
+  __ Push(r3);
+  __ LoadP(scratch, MemOperand(sp, kPointerSize * 2));
+  __ Push(scratch);
+  VisitForStackValue(prop->key());
+
+  // Stack here:
+  //  - home_object
+  //  - this (receiver)
+  //  - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
+  //  - home_object
+  //  - key
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+
+  // Replace home_object with target function.
+  __ StoreP(r3, MemOperand(sp, kPointerSize));
+
+  // Stack here:
+  // - target function
+  // - this (receiver)
+  EmitCall(expr, CallICState::METHOD);
+}
+
+
+void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
+  // Load the arguments.
+  ZoneList<Expression*>* args = expr->arguments();
+  int arg_count = args->length();
+  {
+    PreservePositionScope scope(masm()->positions_recorder());
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
+  }
+
+  // Record source position of the IC call.
+  SetSourcePosition(expr->position());
+  Handle<Code> ic = CallIC::initialize_stub(isolate(), arg_count, call_type);
+  __ LoadSmiLiteral(r6, SmiFromSlot(expr->CallFeedbackSlot()));
+  __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0);
+  // Don't assign a type feedback id to the IC, since type feedback is provided
+  // by the vector above.
+  CallIC(ic);
+
+  RecordJSReturnSite(expr);
+  // Restore context register.
+  __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  context()->DropAndPlug(1, r3);
+}
+
+
+void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
+  // r8: copy of the first argument or undefined if it doesn't exist.
+  if (arg_count > 0) {
+    __ LoadP(r8, MemOperand(sp, arg_count * kPointerSize), r0);
+  } else {
+    __ LoadRoot(r8, Heap::kUndefinedValueRootIndex);
+  }
+
+  // r7: the receiver of the enclosing function.
+  __ LoadP(r7, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+
+  // r6: the receiver of the enclosing function.
+  int receiver_offset = 2 + info_->scope()->num_parameters();
+  __ LoadP(r6, MemOperand(fp, receiver_offset * kPointerSize), r0);
+
+  // r5: strict mode.
+  __ LoadSmiLiteral(r5, Smi::FromInt(strict_mode()));
+
+  // r4: the start position of the scope the calls resides in.
+  __ LoadSmiLiteral(r4, Smi::FromInt(scope()->start_position()));
+
+  // Do the runtime call.
+  __ Push(r8, r7, r6, r5, r4);
+  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+}
+
+
+void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
+  DCHECK(super_ref != NULL);
+  __ LoadP(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ Push(r3);
+  __ CallRuntime(Runtime::kGetPrototype, 1);
+}
+
+
+void FullCodeGenerator::VisitCall(Call* expr) {
+#ifdef DEBUG
+  // We want to verify that RecordJSReturnSite gets called on all paths
+  // through this function.  Avoid early returns.
+  expr->return_is_recorded_ = false;
+#endif
+
+  Comment cmnt(masm_, "[ Call");
+  Expression* callee = expr->expression();
+  Call::CallType call_type = expr->GetCallType(isolate());
+
+  if (call_type == Call::POSSIBLY_EVAL_CALL) {
+    // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
+    // to resolve the function we need to call and the receiver of the
+    // call.  Then we call the resolved function using the given
+    // arguments.
+    ZoneList<Expression*>* args = expr->arguments();
+    int arg_count = args->length();
+
+    {
+      PreservePositionScope pos_scope(masm()->positions_recorder());
+      VisitForStackValue(callee);
+      __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
+      __ push(r5);  // Reserved receiver slot.
+
+      // Push the arguments.
+      for (int i = 0; i < arg_count; i++) {
+        VisitForStackValue(args->at(i));
+      }
+
+      // Push a copy of the function (found below the arguments) and
+      // resolve eval.
+      __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0);
+      __ push(r4);
+      EmitResolvePossiblyDirectEval(arg_count);
+
+      // The runtime call returns a pair of values in r3 (function) and
+      // r4 (receiver). Touch up the stack with the right values.
+      __ StoreP(r3, MemOperand(sp, (arg_count + 1) * kPointerSize), r0);
+      __ StoreP(r4, MemOperand(sp, arg_count * kPointerSize), r0);
+
+      PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
+    }
+
+    // Record source position for debugger.
+    SetSourcePosition(expr->position());
+    CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
+    __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0);
+    __ CallStub(&stub);
+    RecordJSReturnSite(expr);
+    // Restore context register.
+    __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    context()->DropAndPlug(1, r3);
+  } else if (call_type == Call::GLOBAL_CALL) {
+    EmitCallWithLoadIC(expr);
+
+  } else if (call_type == Call::LOOKUP_SLOT_CALL) {
+    // Call to a lookup slot (dynamically introduced variable).
+    VariableProxy* proxy = callee->AsVariableProxy();
+    Label slow, done;
+
+    {
+      PreservePositionScope scope(masm()->positions_recorder());
+      // Generate code for loading from variables potentially shadowed
+      // by eval-introduced variables.
+      EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
+    }
+
+    __ bind(&slow);
+    // Call the runtime to find the function to call (returned in r3)
+    // and the object holding it (returned in edx).
+    DCHECK(!context_register().is(r5));
+    __ mov(r5, Operand(proxy->name()));
+    __ Push(context_register(), r5);
+    __ CallRuntime(Runtime::kLoadLookupSlot, 2);
+    __ Push(r3, r4);  // Function, receiver.
+    PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
+
+    // If fast case code has been generated, emit code to push the
+    // function and receiver and have the slow path jump around this
+    // code.
+    if (done.is_linked()) {
+      Label call;
+      __ b(&call);
+      __ bind(&done);
+      // Push function.
+      __ push(r3);
+      // The receiver is implicitly the global receiver. Indicate this
+      // by passing the hole to the call function stub.
+      __ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
+      __ push(r4);
+      __ bind(&call);
+    }
+
+    // The receiver is either the global receiver or an object found
+    // by LoadContextSlot.
+    EmitCall(expr);
+  } else if (call_type == Call::PROPERTY_CALL) {
+    Property* property = callee->AsProperty();
+    bool is_named_call = property->key()->IsPropertyName();
+    if (property->IsSuperAccess()) {
+      if (is_named_call) {
+        EmitSuperCallWithLoadIC(expr);
+      } else {
+        EmitKeyedSuperCallWithLoadIC(expr);
+      }
+    } else {
+      {
+        PreservePositionScope scope(masm()->positions_recorder());
+        VisitForStackValue(property->obj());
+      }
+      if (is_named_call) {
+        EmitCallWithLoadIC(expr);
+      } else {
+        EmitKeyedCallWithLoadIC(expr, property->key());
+      }
+    }
+  } else if (call_type == Call::SUPER_CALL) {
+    SuperReference* super_ref = callee->AsSuperReference();
+    EmitLoadSuperConstructor(super_ref);
+    __ Push(result_register());
+    VisitForStackValue(super_ref->this_var());
+    EmitCall(expr, CallICState::METHOD);
+  } else {
+    DCHECK(call_type == Call::OTHER_CALL);
+    // Call to an arbitrary expression not handled specially above.
+    {
+      PreservePositionScope scope(masm()->positions_recorder());
+      VisitForStackValue(callee);
+    }
+    __ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
+    __ push(r4);
+    // Emit function call.
+    EmitCall(expr);
+  }
+
+#ifdef DEBUG
+  // RecordJSReturnSite should have been called.
+  DCHECK(expr->return_is_recorded_);
+#endif
+}
+
+
+void FullCodeGenerator::VisitCallNew(CallNew* expr) {
+  Comment cmnt(masm_, "[ CallNew");
+  // According to ECMA-262, section 11.2.2, page 44, the function
+  // expression in new calls must be evaluated before the
+  // arguments.
+
+  // Push constructor on the stack.  If it's not a function it's used as
+  // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
+  // ignored.
+  if (expr->expression()->IsSuperReference()) {
+    EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
+    __ Push(result_register());
+  } else {
+    VisitForStackValue(expr->expression());
+  }
+
+  // Push the arguments ("left-to-right") on the stack.
+  ZoneList<Expression*>* args = expr->arguments();
+  int arg_count = args->length();
+  for (int i = 0; i < arg_count; i++) {
+    VisitForStackValue(args->at(i));
+  }
+
+  // Call the construct call builtin that handles allocation and
+  // constructor invocation.
+  SetSourcePosition(expr->position());
+
+  // Load function and argument count into r4 and r3.
+  __ mov(r3, Operand(arg_count));
+  __ LoadP(r4, MemOperand(sp, arg_count * kPointerSize), r0);
+
+  // Record call targets in unoptimized code.
+  if (FLAG_pretenuring_call_new) {
+    EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
+    DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
+           expr->CallNewFeedbackSlot().ToInt() + 1);
+  }
+
+  __ Move(r5, FeedbackVector());
+  __ LoadSmiLiteral(r6, SmiFromSlot(expr->CallNewFeedbackSlot()));
+
+  CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
+  __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
+  PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  __ TestIfSmi(r3, r0);
+  Split(eq, if_true, if_false, fall_through, cr0);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  __ TestIfPositiveSmi(r3, r0);
+  Split(eq, if_true, if_false, fall_through, cr0);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ JumpIfSmi(r3, if_false);
+  __ LoadRoot(ip, Heap::kNullValueRootIndex);
+  __ cmp(r3, ip);
+  __ beq(if_true);
+  __ LoadP(r5, FieldMemOperand(r3, HeapObject::kMapOffset));
+  // Undetectable objects behave like undefined when tested with typeof.
+  __ lbz(r4, FieldMemOperand(r5, Map::kBitFieldOffset));
+  __ andi(r0, r4, Operand(1 << Map::kIsUndetectable));
+  __ bne(if_false, cr0);
+  __ lbz(r4, FieldMemOperand(r5, Map::kInstanceTypeOffset));
+  __ cmpi(r4, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+  __ blt(if_false);
+  __ cmpi(r4, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(le, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ JumpIfSmi(r3, if_false);
+  __ CompareObjectType(r3, r4, r4, FIRST_SPEC_OBJECT_TYPE);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(ge, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ JumpIfSmi(r3, if_false);
+  __ LoadP(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ lbz(r4, FieldMemOperand(r4, Map::kBitFieldOffset));
+  __ andi(r0, r4, Operand(1 << Map::kIsUndetectable));
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(ne, if_true, if_false, fall_through, cr0);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
+    CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false, skip_lookup;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ AssertNotSmi(r3);
+
+  __ LoadP(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ lbz(ip, FieldMemOperand(r4, Map::kBitField2Offset));
+  __ andi(r0, ip, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
+  __ bne(&skip_lookup, cr0);
+
+  // Check for fast case object. Generate false result for slow case object.
+  __ LoadP(r5, FieldMemOperand(r3, JSObject::kPropertiesOffset));
+  __ LoadP(r5, FieldMemOperand(r5, HeapObject::kMapOffset));
+  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
+  __ cmp(r5, ip);
+  __ beq(if_false);
+
+  // Look for valueOf name in the descriptor array, and indicate false if
+  // found. Since we omit an enumeration index check, if it is added via a
+  // transition that shares its descriptor array, this is a false positive.
+  Label entry, loop, done;
+
+  // Skip loop if no descriptors are valid.
+  __ NumberOfOwnDescriptors(r6, r4);
+  __ cmpi(r6, Operand::Zero());
+  __ beq(&done);
+
+  __ LoadInstanceDescriptors(r4, r7);
+  // r7: descriptor array.
+  // r6: valid entries in the descriptor array.
+  __ mov(ip, Operand(DescriptorArray::kDescriptorSize));
+  __ Mul(r6, r6, ip);
+  // Calculate location of the first key name.
+  __ addi(r7, r7, Operand(DescriptorArray::kFirstOffset - kHeapObjectTag));
+  // Calculate the end of the descriptor array.
+  __ mr(r5, r7);
+  __ ShiftLeftImm(ip, r6, Operand(kPointerSizeLog2));
+  __ add(r5, r5, ip);
+
+  // Loop through all the keys in the descriptor array. If one of these is the
+  // string "valueOf" the result is false.
+  // The use of ip to store the valueOf string assumes that it is not otherwise
+  // used in the loop below.
+  __ mov(ip, Operand(isolate()->factory()->value_of_string()));
+  __ b(&entry);
+  __ bind(&loop);
+  __ LoadP(r6, MemOperand(r7, 0));
+  __ cmp(r6, ip);
+  __ beq(if_false);
+  __ addi(r7, r7, Operand(DescriptorArray::kDescriptorSize * kPointerSize));
+  __ bind(&entry);
+  __ cmp(r7, r5);
+  __ bne(&loop);
+
+  __ bind(&done);
+
+  // Set the bit in the map to indicate that there is no local valueOf field.
+  __ lbz(r5, FieldMemOperand(r4, Map::kBitField2Offset));
+  __ ori(r5, r5, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
+  __ stb(r5, FieldMemOperand(r4, Map::kBitField2Offset));
+
+  __ bind(&skip_lookup);
+
+  // If a valueOf property is not found on the object check that its
+  // prototype is the un-modified String prototype. If not result is false.
+  __ LoadP(r5, FieldMemOperand(r4, Map::kPrototypeOffset));
+  __ JumpIfSmi(r5, if_false);
+  __ LoadP(r5, FieldMemOperand(r5, HeapObject::kMapOffset));
+  __ LoadP(r6, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
+  __ LoadP(r6, FieldMemOperand(r6, GlobalObject::kNativeContextOffset));
+  __ LoadP(r6,
+           ContextOperand(r6, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
+  __ cmp(r5, r6);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ JumpIfSmi(r3, if_false);
+  __ CompareObjectType(r3, r4, r5, JS_FUNCTION_TYPE);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ CheckMap(r3, r4, Heap::kHeapNumberMapRootIndex, if_false, DO_SMI_CHECK);
+#if V8_TARGET_ARCH_PPC64
+  __ LoadP(r4, FieldMemOperand(r3, HeapNumber::kValueOffset));
+  __ li(r5, Operand(1));
+  __ rotrdi(r5, r5, 1);  // r5 = 0x80000000_00000000
+  __ cmp(r4, r5);
+#else
+  __ lwz(r5, FieldMemOperand(r3, HeapNumber::kExponentOffset));
+  __ lwz(r4, FieldMemOperand(r3, HeapNumber::kMantissaOffset));
+  Label skip;
+  __ lis(r0, Operand(SIGN_EXT_IMM16(0x8000)));
+  __ cmp(r5, r0);
+  __ bne(&skip);
+  __ cmpi(r4, Operand::Zero());
+  __ bind(&skip);
+#endif
+
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ JumpIfSmi(r3, if_false);
+  __ CompareObjectType(r3, r4, r4, JS_ARRAY_TYPE);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ JumpIfSmi(r3, if_false);
+  __ CompareObjectType(r3, r4, r4, JS_REGEXP_TYPE);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ JumpIfSmi(r3, if_false);
+  Register map = r4;
+  Register type_reg = r5;
+  __ LoadP(map, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ lbz(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  __ subi(type_reg, type_reg, Operand(FIRST_JS_PROXY_TYPE));
+  __ cmpli(type_reg, Operand(LAST_JS_PROXY_TYPE - FIRST_JS_PROXY_TYPE));
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(le, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
+  DCHECK(expr->arguments()->length() == 0);
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  // Get the frame pointer for the calling frame.
+  __ LoadP(r5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+
+  // Skip the arguments adaptor frame if it exists.
+  Label check_frame_marker;
+  __ LoadP(r4, MemOperand(r5, StandardFrameConstants::kContextOffset));
+  __ CmpSmiLiteral(r4, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
+  __ bne(&check_frame_marker);
+  __ LoadP(r5, MemOperand(r5, StandardFrameConstants::kCallerFPOffset));
+
+  // Check the marker in the calling frame.
+  __ bind(&check_frame_marker);
+  __ LoadP(r4, MemOperand(r5, StandardFrameConstants::kMarkerOffset));
+  STATIC_ASSERT(StackFrame::CONSTRUCT < 0x4000);
+  __ CmpSmiLiteral(r4, Smi::FromInt(StackFrame::CONSTRUCT), r0);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 2);
+
+  // Load the two objects into registers and perform the comparison.
+  VisitForStackValue(args->at(0));
+  VisitForAccumulatorValue(args->at(1));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ pop(r4);
+  __ cmp(r3, r4);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  // ArgumentsAccessStub expects the key in edx and the formal
+  // parameter count in r3.
+  VisitForAccumulatorValue(args->at(0));
+  __ mr(r4, r3);
+  __ LoadSmiLiteral(r3, Smi::FromInt(info_->scope()->num_parameters()));
+  ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
+  __ CallStub(&stub);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
+  DCHECK(expr->arguments()->length() == 0);
+  Label exit;
+  // Get the number of formal parameters.
+  __ LoadSmiLiteral(r3, Smi::FromInt(info_->scope()->num_parameters()));
+
+  // Check if the calling frame is an arguments adaptor frame.
+  __ LoadP(r5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ LoadP(r6, MemOperand(r5, StandardFrameConstants::kContextOffset));
+  __ CmpSmiLiteral(r6, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
+  __ bne(&exit);
+
+  // Arguments adaptor case: Read the arguments length from the
+  // adaptor frame.
+  __ LoadP(r3, MemOperand(r5, ArgumentsAdaptorFrameConstants::kLengthOffset));
+
+  __ bind(&exit);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+  Label done, null, function, non_function_constructor;
+
+  VisitForAccumulatorValue(args->at(0));
+
+  // If the object is a smi, we return null.
+  __ JumpIfSmi(r3, &null);
+
+  // Check that the object is a JS object but take special care of JS
+  // functions to make sure they have 'Function' as their class.
+  // Assume that there are only two callable types, and one of them is at
+  // either end of the type range for JS object types. Saves extra comparisons.
+  STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+  __ CompareObjectType(r3, r3, r4, FIRST_SPEC_OBJECT_TYPE);
+  // Map is now in r3.
+  __ blt(&null);
+  STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                FIRST_SPEC_OBJECT_TYPE + 1);
+  __ beq(&function);
+
+  __ cmpi(r4, Operand(LAST_SPEC_OBJECT_TYPE));
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_SPEC_OBJECT_TYPE - 1);
+  __ beq(&function);
+  // Assume that there is no larger type.
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
+
+  // Check if the constructor in the map is a JS function.
+  __ LoadP(r3, FieldMemOperand(r3, Map::kConstructorOffset));
+  __ CompareObjectType(r3, r4, r4, JS_FUNCTION_TYPE);
+  __ bne(&non_function_constructor);
+
+  // r3 now contains the constructor function. Grab the
+  // instance class name from there.
+  __ LoadP(r3, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset));
+  __ LoadP(r3,
+           FieldMemOperand(r3, SharedFunctionInfo::kInstanceClassNameOffset));
+  __ b(&done);
+
+  // Functions have class 'Function'.
+  __ bind(&function);
+  __ LoadRoot(r3, Heap::kFunction_stringRootIndex);
+  __ b(&done);
+
+  // Objects with a non-function constructor have class 'Object'.
+  __ bind(&non_function_constructor);
+  __ LoadRoot(r3, Heap::kObject_stringRootIndex);
+  __ b(&done);
+
+  // Non-JS objects have class null.
+  __ bind(&null);
+  __ LoadRoot(r3, Heap::kNullValueRootIndex);
+
+  // All done.
+  __ bind(&done);
+
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
+  // Load the arguments on the stack and call the stub.
+  SubStringStub stub(isolate());
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 3);
+  VisitForStackValue(args->at(0));
+  VisitForStackValue(args->at(1));
+  VisitForStackValue(args->at(2));
+  __ CallStub(&stub);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
+  // Load the arguments on the stack and call the stub.
+  RegExpExecStub stub(isolate());
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 4);
+  VisitForStackValue(args->at(0));
+  VisitForStackValue(args->at(1));
+  VisitForStackValue(args->at(2));
+  VisitForStackValue(args->at(3));
+  __ CallStub(&stub);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+  VisitForAccumulatorValue(args->at(0));  // Load the object.
+
+  Label done;
+  // If the object is a smi return the object.
+  __ JumpIfSmi(r3, &done);
+  // If the object is not a value type, return the object.
+  __ CompareObjectType(r3, r4, r4, JS_VALUE_TYPE);
+  __ bne(&done);
+  __ LoadP(r3, FieldMemOperand(r3, JSValue::kValueOffset));
+
+  __ bind(&done);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 2);
+  DCHECK_NE(NULL, args->at(1)->AsLiteral());
+  Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->value()));
+
+  VisitForAccumulatorValue(args->at(0));  // Load the object.
+
+  Label runtime, done, not_date_object;
+  Register object = r3;
+  Register result = r3;
+  Register scratch0 = r11;
+  Register scratch1 = r4;
+
+  __ JumpIfSmi(object, &not_date_object);
+  __ CompareObjectType(object, scratch1, scratch1, JS_DATE_TYPE);
+  __ bne(&not_date_object);
+
+  if (index->value() == 0) {
+    __ LoadP(result, FieldMemOperand(object, JSDate::kValueOffset));
+    __ b(&done);
+  } else {
+    if (index->value() < JSDate::kFirstUncachedField) {
+      ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
+      __ mov(scratch1, Operand(stamp));
+      __ LoadP(scratch1, MemOperand(scratch1));
+      __ LoadP(scratch0, FieldMemOperand(object, JSDate::kCacheStampOffset));
+      __ cmp(scratch1, scratch0);
+      __ bne(&runtime);
+      __ LoadP(result,
+               FieldMemOperand(object, JSDate::kValueOffset +
+                                           kPointerSize * index->value()),
+               scratch0);
+      __ b(&done);
+    }
+    __ bind(&runtime);
+    __ PrepareCallCFunction(2, scratch1);
+    __ LoadSmiLiteral(r4, index);
+    __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
+    __ b(&done);
+  }
+
+  __ bind(&not_date_object);
+  __ CallRuntime(Runtime::kThrowNotDateError, 0);
+  __ bind(&done);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK_EQ(3, args->length());
+
+  Register string = r3;
+  Register index = r4;
+  Register value = r5;
+
+  VisitForStackValue(args->at(0));        // index
+  VisitForStackValue(args->at(1));        // value
+  VisitForAccumulatorValue(args->at(2));  // string
+  __ Pop(index, value);
+
+  if (FLAG_debug_code) {
+    __ TestIfSmi(value, r0);
+    __ Check(eq, kNonSmiValue, cr0);
+    __ TestIfSmi(index, r0);
+    __ Check(eq, kNonSmiIndex, cr0);
+    __ SmiUntag(index, index);
+    static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+    __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
+    __ SmiTag(index, index);
+  }
+
+  __ SmiUntag(value);
+  __ addi(ip, string, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
+  __ SmiToByteArrayOffset(r0, index);
+  __ stbx(value, MemOperand(ip, r0));
+  context()->Plug(string);
+}
+
+
+void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK_EQ(3, args->length());
+
+  Register string = r3;
+  Register index = r4;
+  Register value = r5;
+
+  VisitForStackValue(args->at(0));        // index
+  VisitForStackValue(args->at(1));        // value
+  VisitForAccumulatorValue(args->at(2));  // string
+  __ Pop(index, value);
+
+  if (FLAG_debug_code) {
+    __ TestIfSmi(value, r0);
+    __ Check(eq, kNonSmiValue, cr0);
+    __ TestIfSmi(index, r0);
+    __ Check(eq, kNonSmiIndex, cr0);
+    __ SmiUntag(index, index);
+    static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+    __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
+    __ SmiTag(index, index);
+  }
+
+  __ SmiUntag(value);
+  __ addi(ip, string, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
+  __ SmiToShortArrayOffset(r0, index);
+  __ sthx(value, MemOperand(ip, r0));
+  context()->Plug(string);
+}
+
+
+void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
+  // Load the arguments on the stack and call the runtime function.
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 2);
+  VisitForStackValue(args->at(0));
+  VisitForStackValue(args->at(1));
+  MathPowStub stub(isolate(), MathPowStub::ON_STACK);
+  __ CallStub(&stub);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 2);
+  VisitForStackValue(args->at(0));        // Load the object.
+  VisitForAccumulatorValue(args->at(1));  // Load the value.
+  __ pop(r4);                             // r3 = value. r4 = object.
+
+  Label done;
+  // If the object is a smi, return the value.
+  __ JumpIfSmi(r4, &done);
+
+  // If the object is not a value type, return the value.
+  __ CompareObjectType(r4, r5, r5, JS_VALUE_TYPE);
+  __ bne(&done);
+
+  // Store the value.
+  __ StoreP(r3, FieldMemOperand(r4, JSValue::kValueOffset), r0);
+  // Update the write barrier.  Save the value as it will be
+  // overwritten by the write barrier code and is needed afterward.
+  __ mr(r5, r3);
+  __ RecordWriteField(r4, JSValue::kValueOffset, r5, r6, kLRHasBeenSaved,
+                      kDontSaveFPRegs);
+
+  __ bind(&done);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK_EQ(args->length(), 1);
+  // Load the argument into r3 and call the stub.
+  VisitForAccumulatorValue(args->at(0));
+
+  NumberToStringStub stub(isolate());
+  __ CallStub(&stub);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+  VisitForAccumulatorValue(args->at(0));
+
+  Label done;
+  StringCharFromCodeGenerator generator(r3, r4);
+  generator.GenerateFast(masm_);
+  __ b(&done);
+
+  NopRuntimeCallHelper call_helper;
+  generator.GenerateSlow(masm_, call_helper);
+
+  __ bind(&done);
+  context()->Plug(r4);
+}
+
+
+void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 2);
+  VisitForStackValue(args->at(0));
+  VisitForAccumulatorValue(args->at(1));
+
+  Register object = r4;
+  Register index = r3;
+  Register result = r6;
+
+  __ pop(object);
+
+  Label need_conversion;
+  Label index_out_of_range;
+  Label done;
+  StringCharCodeAtGenerator generator(object, index, result, &need_conversion,
+                                      &need_conversion, &index_out_of_range,
+                                      STRING_INDEX_IS_NUMBER);
+  generator.GenerateFast(masm_);
+  __ b(&done);
+
+  __ bind(&index_out_of_range);
+  // When the index is out of range, the spec requires us to return
+  // NaN.
+  __ LoadRoot(result, Heap::kNanValueRootIndex);
+  __ b(&done);
+
+  __ bind(&need_conversion);
+  // Load the undefined value into the result register, which will
+  // trigger conversion.
+  __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
+  __ b(&done);
+
+  NopRuntimeCallHelper call_helper;
+  generator.GenerateSlow(masm_, call_helper);
+
+  __ bind(&done);
+  context()->Plug(result);
+}
+
+
+void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 2);
+  VisitForStackValue(args->at(0));
+  VisitForAccumulatorValue(args->at(1));
+
+  Register object = r4;
+  Register index = r3;
+  Register scratch = r6;
+  Register result = r3;
+
+  __ pop(object);
+
+  Label need_conversion;
+  Label index_out_of_range;
+  Label done;
+  StringCharAtGenerator generator(object, index, scratch, result,
+                                  &need_conversion, &need_conversion,
+                                  &index_out_of_range, STRING_INDEX_IS_NUMBER);
+  generator.GenerateFast(masm_);
+  __ b(&done);
+
+  __ bind(&index_out_of_range);
+  // When the index is out of range, the spec requires us to return
+  // the empty string.
+  __ LoadRoot(result, Heap::kempty_stringRootIndex);
+  __ b(&done);
+
+  __ bind(&need_conversion);
+  // Move smi zero into the result register, which will trigger
+  // conversion.
+  __ LoadSmiLiteral(result, Smi::FromInt(0));
+  __ b(&done);
+
+  NopRuntimeCallHelper call_helper;
+  generator.GenerateSlow(masm_, call_helper);
+
+  __ bind(&done);
+  context()->Plug(result);
+}
+
+
+void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK_EQ(2, args->length());
+  VisitForStackValue(args->at(0));
+  VisitForAccumulatorValue(args->at(1));
+
+  __ pop(r4);
+  StringAddStub stub(isolate(), STRING_ADD_CHECK_BOTH, NOT_TENURED);
+  __ CallStub(&stub);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK_EQ(2, args->length());
+  VisitForStackValue(args->at(0));
+  VisitForStackValue(args->at(1));
+
+  StringCompareStub stub(isolate());
+  __ CallStub(&stub);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() >= 2);
+
+  int arg_count = args->length() - 2;  // 2 ~ receiver and function.
+  for (int i = 0; i < arg_count + 1; i++) {
+    VisitForStackValue(args->at(i));
+  }
+  VisitForAccumulatorValue(args->last());  // Function.
+
+  Label runtime, done;
+  // Check for non-function argument (including proxy).
+  __ JumpIfSmi(r3, &runtime);
+  __ CompareObjectType(r3, r4, r4, JS_FUNCTION_TYPE);
+  __ bne(&runtime);
+
+  // InvokeFunction requires the function in r4. Move it in there.
+  __ mr(r4, result_register());
+  ParameterCount count(arg_count);
+  __ InvokeFunction(r4, count, CALL_FUNCTION, NullCallWrapper());
+  __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  __ b(&done);
+
+  __ bind(&runtime);
+  __ push(r3);
+  __ CallRuntime(Runtime::kCall, args->length());
+  __ bind(&done);
+
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
+  RegExpConstructResultStub stub(isolate());
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 3);
+  VisitForStackValue(args->at(0));
+  VisitForStackValue(args->at(1));
+  VisitForAccumulatorValue(args->at(2));
+  __ Pop(r5, r4);
+  __ CallStub(&stub);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK_EQ(2, args->length());
+  DCHECK_NE(NULL, args->at(0)->AsLiteral());
+  int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
+
+  Handle<FixedArray> jsfunction_result_caches(
+      isolate()->native_context()->jsfunction_result_caches());
+  if (jsfunction_result_caches->length() <= cache_id) {
+    __ Abort(kAttemptToUseUndefinedCache);
+    __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
+    context()->Plug(r3);
+    return;
+  }
+
+  VisitForAccumulatorValue(args->at(1));
+
+  Register key = r3;
+  Register cache = r4;
+  __ LoadP(cache, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
+  __ LoadP(cache, FieldMemOperand(cache, GlobalObject::kNativeContextOffset));
+  __ LoadP(cache,
+           ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
+  __ LoadP(cache,
+           FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id)), r0);
+
+  Label done, not_found;
+  __ LoadP(r5, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
+  // r5 now holds finger offset as a smi.
+  __ addi(r6, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  // r6 now points to the start of fixed array elements.
+  __ SmiToPtrArrayOffset(r5, r5);
+  __ LoadPUX(r5, MemOperand(r6, r5));
+  // r6 now points to the key of the pair.
+  __ cmp(key, r5);
+  __ bne(&not_found);
+
+  __ LoadP(r3, MemOperand(r6, kPointerSize));
+  __ b(&done);
+
+  __ bind(&not_found);
+  // Call runtime to perform the lookup.
+  __ Push(cache, key);
+  __ CallRuntime(Runtime::kGetFromCache, 2);
+
+  __ bind(&done);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ lwz(r3, FieldMemOperand(r3, String::kHashFieldOffset));
+  // PPC - assume ip is free
+  __ mov(ip, Operand(String::kContainsCachedArrayIndexMask));
+  __ and_(r0, r3, ip);
+  __ cmpi(r0, Operand::Zero());
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+  VisitForAccumulatorValue(args->at(0));
+
+  __ AssertString(r3);
+
+  __ lwz(r3, FieldMemOperand(r3, String::kHashFieldOffset));
+  __ IndexFromHash(r3, r3);
+
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitFastOneByteArrayJoin(CallRuntime* expr) {
+  Label bailout, done, one_char_separator, long_separator, non_trivial_array,
+      not_size_one_array, loop, empty_separator_loop, one_char_separator_loop,
+      one_char_separator_loop_entry, long_separator_loop;
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 2);
+  VisitForStackValue(args->at(1));
+  VisitForAccumulatorValue(args->at(0));
+
+  // All aliases of the same register have disjoint lifetimes.
+  Register array = r3;
+  Register elements = no_reg;  // Will be r3.
+  Register result = no_reg;    // Will be r3.
+  Register separator = r4;
+  Register array_length = r5;
+  Register result_pos = no_reg;  // Will be r5
+  Register string_length = r6;
+  Register string = r7;
+  Register element = r8;
+  Register elements_end = r9;
+  Register scratch1 = r10;
+  Register scratch2 = r11;
+
+  // Separator operand is on the stack.
+  __ pop(separator);
+
+  // Check that the array is a JSArray.
+  __ JumpIfSmi(array, &bailout);
+  __ CompareObjectType(array, scratch1, scratch2, JS_ARRAY_TYPE);
+  __ bne(&bailout);
+
+  // Check that the array has fast elements.
+  __ CheckFastElements(scratch1, scratch2, &bailout);
+
+  // If the array has length zero, return the empty string.
+  __ LoadP(array_length, FieldMemOperand(array, JSArray::kLengthOffset));
+  __ SmiUntag(array_length);
+  __ cmpi(array_length, Operand::Zero());
+  __ bne(&non_trivial_array);
+  __ LoadRoot(r3, Heap::kempty_stringRootIndex);
+  __ b(&done);
+
+  __ bind(&non_trivial_array);
+
+  // Get the FixedArray containing array's elements.
+  elements = array;
+  __ LoadP(elements, FieldMemOperand(array, JSArray::kElementsOffset));
+  array = no_reg;  // End of array's live range.
+
+  // Check that all array elements are sequential one-byte strings, and
+  // accumulate the sum of their lengths, as a smi-encoded value.
+  __ li(string_length, Operand::Zero());
+  __ addi(element, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ ShiftLeftImm(elements_end, array_length, Operand(kPointerSizeLog2));
+  __ add(elements_end, element, elements_end);
+  // Loop condition: while (element < elements_end).
+  // Live values in registers:
+  //   elements: Fixed array of strings.
+  //   array_length: Length of the fixed array of strings (not smi)
+  //   separator: Separator string
+  //   string_length: Accumulated sum of string lengths (smi).
+  //   element: Current array element.
+  //   elements_end: Array end.
+  if (generate_debug_code_) {
+    __ cmpi(array_length, Operand::Zero());
+    __ Assert(gt, kNoEmptyArraysHereInEmitFastOneByteArrayJoin);
+  }
+  __ bind(&loop);
+  __ LoadP(string, MemOperand(element));
+  __ addi(element, element, Operand(kPointerSize));
+  __ JumpIfSmi(string, &bailout);
+  __ LoadP(scratch1, FieldMemOperand(string, HeapObject::kMapOffset));
+  __ lbz(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
+  __ JumpIfInstanceTypeIsNotSequentialOneByte(scratch1, scratch2, &bailout);
+  __ LoadP(scratch1, FieldMemOperand(string, SeqOneByteString::kLengthOffset));
+
+  __ AddAndCheckForOverflow(string_length, string_length, scratch1, scratch2,
+                            r0);
+  __ BranchOnOverflow(&bailout);
+
+  __ cmp(element, elements_end);
+  __ blt(&loop);
+
+  // If array_length is 1, return elements[0], a string.
+  __ cmpi(array_length, Operand(1));
+  __ bne(&not_size_one_array);
+  __ LoadP(r3, FieldMemOperand(elements, FixedArray::kHeaderSize));
+  __ b(&done);
+
+  __ bind(&not_size_one_array);
+
+  // Live values in registers:
+  //   separator: Separator string
+  //   array_length: Length of the array.
+  //   string_length: Sum of string lengths (smi).
+  //   elements: FixedArray of strings.
+
+  // Check that the separator is a flat one-byte string.
+  __ JumpIfSmi(separator, &bailout);
+  __ LoadP(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset));
+  __ lbz(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
+  __ JumpIfInstanceTypeIsNotSequentialOneByte(scratch1, scratch2, &bailout);
+
+  // Add (separator length times array_length) - separator length to the
+  // string_length to get the length of the result string.
+  __ LoadP(scratch1,
+           FieldMemOperand(separator, SeqOneByteString::kLengthOffset));
+  __ sub(string_length, string_length, scratch1);
+#if V8_TARGET_ARCH_PPC64
+  __ SmiUntag(scratch1, scratch1);
+  __ Mul(scratch2, array_length, scratch1);
+  // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are
+  // zero.
+  __ ShiftRightImm(ip, scratch2, Operand(31), SetRC);
+  __ bne(&bailout, cr0);
+  __ SmiTag(scratch2, scratch2);
+#else
+  // array_length is not smi but the other values are, so the result is a smi
+  __ mullw(scratch2, array_length, scratch1);
+  __ mulhw(ip, array_length, scratch1);
+  // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are
+  // zero.
+  __ cmpi(ip, Operand::Zero());
+  __ bne(&bailout);
+  __ cmpwi(scratch2, Operand::Zero());
+  __ blt(&bailout);
+#endif
+
+  __ AddAndCheckForOverflow(string_length, string_length, scratch2, scratch1,
+                            r0);
+  __ BranchOnOverflow(&bailout);
+  __ SmiUntag(string_length);
+
+  // Get first element in the array to free up the elements register to be used
+  // for the result.
+  __ addi(element, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  result = elements;  // End of live range for elements.
+  elements = no_reg;
+  // Live values in registers:
+  //   element: First array element
+  //   separator: Separator string
+  //   string_length: Length of result string (not smi)
+  //   array_length: Length of the array.
+  __ AllocateOneByteString(result, string_length, scratch1, scratch2,
+                           elements_end, &bailout);
+  // Prepare for looping. Set up elements_end to end of the array. Set
+  // result_pos to the position of the result where to write the first
+  // character.
+  __ ShiftLeftImm(elements_end, array_length, Operand(kPointerSizeLog2));
+  __ add(elements_end, element, elements_end);
+  result_pos = array_length;  // End of live range for array_length.
+  array_length = no_reg;
+  __ addi(result_pos, result,
+          Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
+
+  // Check the length of the separator.
+  __ LoadP(scratch1,
+           FieldMemOperand(separator, SeqOneByteString::kLengthOffset));
+  __ CmpSmiLiteral(scratch1, Smi::FromInt(1), r0);
+  __ beq(&one_char_separator);
+  __ bgt(&long_separator);
+
+  // Empty separator case
+  __ bind(&empty_separator_loop);
+  // Live values in registers:
+  //   result_pos: the position to which we are currently copying characters.
+  //   element: Current array element.
+  //   elements_end: Array end.
+
+  // Copy next array element to the result.
+  __ LoadP(string, MemOperand(element));
+  __ addi(element, element, Operand(kPointerSize));
+  __ LoadP(string_length, FieldMemOperand(string, String::kLengthOffset));
+  __ SmiUntag(string_length);
+  __ addi(string, string,
+          Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
+  __ CopyBytes(string, result_pos, string_length, scratch1);
+  __ cmp(element, elements_end);
+  __ blt(&empty_separator_loop);  // End while (element < elements_end).
+  DCHECK(result.is(r3));
+  __ b(&done);
+
+  // One-character separator case
+  __ bind(&one_char_separator);
+  // Replace separator with its one-byte character value.
+  __ lbz(separator, FieldMemOperand(separator, SeqOneByteString::kHeaderSize));
+  // Jump into the loop after the code that copies the separator, so the first
+  // element is not preceded by a separator
+  __ b(&one_char_separator_loop_entry);
+
+  __ bind(&one_char_separator_loop);
+  // Live values in registers:
+  //   result_pos: the position to which we are currently copying characters.
+  //   element: Current array element.
+  //   elements_end: Array end.
+  //   separator: Single separator one-byte char (in lower byte).
+
+  // Copy the separator character to the result.
+  __ stb(separator, MemOperand(result_pos));
+  __ addi(result_pos, result_pos, Operand(1));
+
+  // Copy next array element to the result.
+  __ bind(&one_char_separator_loop_entry);
+  __ LoadP(string, MemOperand(element));
+  __ addi(element, element, Operand(kPointerSize));
+  __ LoadP(string_length, FieldMemOperand(string, String::kLengthOffset));
+  __ SmiUntag(string_length);
+  __ addi(string, string,
+          Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
+  __ CopyBytes(string, result_pos, string_length, scratch1);
+  __ cmpl(element, elements_end);
+  __ blt(&one_char_separator_loop);  // End while (element < elements_end).
+  DCHECK(result.is(r3));
+  __ b(&done);
+
+  // Long separator case (separator is more than one character). Entry is at the
+  // label long_separator below.
+  __ bind(&long_separator_loop);
+  // Live values in registers:
+  //   result_pos: the position to which we are currently copying characters.
+  //   element: Current array element.
+  //   elements_end: Array end.
+  //   separator: Separator string.
+
+  // Copy the separator to the result.
+  __ LoadP(string_length, FieldMemOperand(separator, String::kLengthOffset));
+  __ SmiUntag(string_length);
+  __ addi(string, separator,
+          Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
+  __ CopyBytes(string, result_pos, string_length, scratch1);
+
+  __ bind(&long_separator);
+  __ LoadP(string, MemOperand(element));
+  __ addi(element, element, Operand(kPointerSize));
+  __ LoadP(string_length, FieldMemOperand(string, String::kLengthOffset));
+  __ SmiUntag(string_length);
+  __ addi(string, string,
+          Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
+  __ CopyBytes(string, result_pos, string_length, scratch1);
+  __ cmpl(element, elements_end);
+  __ blt(&long_separator_loop);  // End while (element < elements_end).
+  DCHECK(result.is(r3));
+  __ b(&done);
+
+  __ bind(&bailout);
+  __ LoadRoot(r3, Heap::kUndefinedValueRootIndex);
+  __ bind(&done);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
+  DCHECK(expr->arguments()->length() == 0);
+  ExternalReference debug_is_active =
+      ExternalReference::debug_is_active_address(isolate());
+  __ mov(ip, Operand(debug_is_active));
+  __ lbz(r3, MemOperand(ip));
+  __ SmiTag(r3);
+  context()->Plug(r3);
+}
+
+
+void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
+  if (expr->function() != NULL &&
+      expr->function()->intrinsic_type == Runtime::INLINE) {
+    Comment cmnt(masm_, "[ InlineRuntimeCall");
+    EmitInlineRuntimeCall(expr);
+    return;
+  }
+
+  Comment cmnt(masm_, "[ CallRuntime");
+  ZoneList<Expression*>* args = expr->arguments();
+  int arg_count = args->length();
+
+  if (expr->is_jsruntime()) {
+    // Push the builtins object as the receiver.
+    Register receiver = LoadDescriptor::ReceiverRegister();
+    __ LoadP(receiver, GlobalObjectOperand());
+    __ LoadP(receiver,
+             FieldMemOperand(receiver, GlobalObject::kBuiltinsOffset));
+    __ push(receiver);
+
+    // Load the function from the receiver.
+    __ mov(LoadDescriptor::NameRegister(), Operand(expr->name()));
+    if (FLAG_vector_ics) {
+      __ mov(VectorLoadICDescriptor::SlotRegister(),
+             Operand(SmiFromSlot(expr->CallRuntimeFeedbackSlot())));
+      CallLoadIC(NOT_CONTEXTUAL);
+    } else {
+      CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
+    }
+
+    // Push the target function under the receiver.
+    __ LoadP(ip, MemOperand(sp, 0));
+    __ push(ip);
+    __ StoreP(r3, MemOperand(sp, kPointerSize));
+
+    // Push the arguments ("left-to-right").
+    int arg_count = args->length();
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
+
+    // Record source position of the IC call.
+    SetSourcePosition(expr->position());
+    CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
+    __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0);
+    __ CallStub(&stub);
+
+    // Restore context register.
+    __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+
+    context()->DropAndPlug(1, r3);
+  } else {
+    // Push the arguments ("left-to-right").
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
+
+    // Call the C runtime function.
+    __ CallRuntime(expr->function(), arg_count);
+    context()->Plug(r3);
+  }
+}
+
+
+void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
+  switch (expr->op()) {
+    case Token::DELETE: {
+      Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
+      Property* property = expr->expression()->AsProperty();
+      VariableProxy* proxy = expr->expression()->AsVariableProxy();
+
+      if (property != NULL) {
+        VisitForStackValue(property->obj());
+        VisitForStackValue(property->key());
+        __ LoadSmiLiteral(r4, Smi::FromInt(strict_mode()));
+        __ push(r4);
+        __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
+        context()->Plug(r3);
+      } else if (proxy != NULL) {
+        Variable* var = proxy->var();
+        // Delete of an unqualified identifier is disallowed in strict mode
+        // but "delete this" is allowed.
+        DCHECK(strict_mode() == SLOPPY || var->is_this());
+        if (var->IsUnallocated()) {
+          __ LoadP(r5, GlobalObjectOperand());
+          __ mov(r4, Operand(var->name()));
+          __ LoadSmiLiteral(r3, Smi::FromInt(SLOPPY));
+          __ Push(r5, r4, r3);
+          __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
+          context()->Plug(r3);
+        } else if (var->IsStackAllocated() || var->IsContextSlot()) {
+          // Result of deleting non-global, non-dynamic variables is false.
+          // The subexpression does not have side effects.
+          context()->Plug(var->is_this());
+        } else {
+          // Non-global variable.  Call the runtime to try to delete from the
+          // context where the variable was introduced.
+          DCHECK(!context_register().is(r5));
+          __ mov(r5, Operand(var->name()));
+          __ Push(context_register(), r5);
+          __ CallRuntime(Runtime::kDeleteLookupSlot, 2);
+          context()->Plug(r3);
+        }
+      } else {
+        // Result of deleting non-property, non-variable reference is true.
+        // The subexpression may have side effects.
+        VisitForEffect(expr->expression());
+        context()->Plug(true);
+      }
+      break;
+    }
+
+    case Token::VOID: {
+      Comment cmnt(masm_, "[ UnaryOperation (VOID)");
+      VisitForEffect(expr->expression());
+      context()->Plug(Heap::kUndefinedValueRootIndex);
+      break;
+    }
+
+    case Token::NOT: {
+      Comment cmnt(masm_, "[ UnaryOperation (NOT)");
+      if (context()->IsEffect()) {
+        // Unary NOT has no side effects so it's only necessary to visit the
+        // subexpression.  Match the optimizing compiler by not branching.
+        VisitForEffect(expr->expression());
+      } else if (context()->IsTest()) {
+        const TestContext* test = TestContext::cast(context());
+        // The labels are swapped for the recursive call.
+        VisitForControl(expr->expression(), test->false_label(),
+                        test->true_label(), test->fall_through());
+        context()->Plug(test->true_label(), test->false_label());
+      } else {
+        // We handle value contexts explicitly rather than simply visiting
+        // for control and plugging the control flow into the context,
+        // because we need to prepare a pair of extra administrative AST ids
+        // for the optimizing compiler.
+        DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue());
+        Label materialize_true, materialize_false, done;
+        VisitForControl(expr->expression(), &materialize_false,
+                        &materialize_true, &materialize_true);
+        __ bind(&materialize_true);
+        PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
+        __ LoadRoot(r3, Heap::kTrueValueRootIndex);
+        if (context()->IsStackValue()) __ push(r3);
+        __ b(&done);
+        __ bind(&materialize_false);
+        PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
+        __ LoadRoot(r3, Heap::kFalseValueRootIndex);
+        if (context()->IsStackValue()) __ push(r3);
+        __ bind(&done);
+      }
+      break;
+    }
+
+    case Token::TYPEOF: {
+      Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
+      {
+        StackValueContext context(this);
+        VisitForTypeofValue(expr->expression());
+      }
+      __ CallRuntime(Runtime::kTypeof, 1);
+      context()->Plug(r3);
+      break;
+    }
+
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
+  DCHECK(expr->expression()->IsValidReferenceExpression());
+
+  Comment cmnt(masm_, "[ CountOperation");
+  SetSourcePosition(expr->position());
+
+  Property* prop = expr->expression()->AsProperty();
+  LhsKind assign_type = GetAssignType(prop);
+
+  // Evaluate expression and get value.
+  if (assign_type == VARIABLE) {
+    DCHECK(expr->expression()->AsVariableProxy()->var() != NULL);
+    AccumulatorValueContext context(this);
+    EmitVariableLoad(expr->expression()->AsVariableProxy());
+  } else {
+    // Reserve space for result of postfix operation.
+    if (expr->is_postfix() && !context()->IsEffect()) {
+      __ LoadSmiLiteral(ip, Smi::FromInt(0));
+      __ push(ip);
+    }
+    switch (assign_type) {
+      case NAMED_PROPERTY: {
+        // Put the object both on the stack and in the register.
+        VisitForStackValue(prop->obj());
+        __ LoadP(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
+        EmitNamedPropertyLoad(prop);
+        break;
+      }
+
+      case NAMED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        __ Push(result_register());
+        const Register scratch = r4;
+        __ LoadP(scratch, MemOperand(sp, kPointerSize));
+        __ Push(scratch, result_register());
+        EmitNamedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        const Register scratch = r4;
+        const Register scratch1 = r5;
+        __ Move(scratch, result_register());
+        VisitForAccumulatorValue(prop->key());
+        __ Push(scratch, result_register());
+        __ LoadP(scratch1, MemOperand(sp, 2 * kPointerSize));
+        __ Push(scratch1, scratch, result_register());
+        EmitKeyedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_PROPERTY: {
+        VisitForStackValue(prop->obj());
+        VisitForStackValue(prop->key());
+        __ LoadP(LoadDescriptor::ReceiverRegister(),
+                 MemOperand(sp, 1 * kPointerSize));
+        __ LoadP(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
+        EmitKeyedPropertyLoad(prop);
+        break;
+      }
+
+      case VARIABLE:
+        UNREACHABLE();
+    }
+  }
+
+  // We need a second deoptimization point after loading the value
+  // in case evaluating the property load my have a side effect.
+  if (assign_type == VARIABLE) {
+    PrepareForBailout(expr->expression(), TOS_REG);
+  } else {
+    PrepareForBailoutForId(prop->LoadId(), TOS_REG);
+  }
+
+  // Inline smi case if we are in a loop.
+  Label stub_call, done;
+  JumpPatchSite patch_site(masm_);
+
+  int count_value = expr->op() == Token::INC ? 1 : -1;
+  if (ShouldInlineSmiCase(expr->op())) {
+    Label slow;
+    patch_site.EmitJumpIfNotSmi(r3, &slow);
+
+    // Save result for postfix expressions.
+    if (expr->is_postfix()) {
+      if (!context()->IsEffect()) {
+        // Save the result on the stack. If we have a named or keyed property
+        // we store the result under the receiver that is currently on top
+        // of the stack.
+        switch (assign_type) {
+          case VARIABLE:
+            __ push(r3);
+            break;
+          case NAMED_PROPERTY:
+            __ StoreP(r3, MemOperand(sp, kPointerSize));
+            break;
+          case NAMED_SUPER_PROPERTY:
+            __ StoreP(r3, MemOperand(sp, 2 * kPointerSize));
+            break;
+          case KEYED_PROPERTY:
+            __ StoreP(r3, MemOperand(sp, 2 * kPointerSize));
+            break;
+          case KEYED_SUPER_PROPERTY:
+            __ StoreP(r3, MemOperand(sp, 3 * kPointerSize));
+            break;
+        }
+      }
+    }
+
+    Register scratch1 = r4;
+    Register scratch2 = r5;
+    __ LoadSmiLiteral(scratch1, Smi::FromInt(count_value));
+    __ AddAndCheckForOverflow(r3, r3, scratch1, scratch2, r0);
+    __ BranchOnNoOverflow(&done);
+    // Call stub. Undo operation first.
+    __ sub(r3, r3, scratch1);
+    __ b(&stub_call);
+    __ bind(&slow);
+  }
+  ToNumberStub convert_stub(isolate());
+  __ CallStub(&convert_stub);
+
+  // Save result for postfix expressions.
+  if (expr->is_postfix()) {
+    if (!context()->IsEffect()) {
+      // Save the result on the stack. If we have a named or keyed property
+      // we store the result under the receiver that is currently on top
+      // of the stack.
+      switch (assign_type) {
+        case VARIABLE:
+          __ push(r3);
+          break;
+        case NAMED_PROPERTY:
+          __ StoreP(r3, MemOperand(sp, kPointerSize));
+          break;
+        case NAMED_SUPER_PROPERTY:
+          __ StoreP(r3, MemOperand(sp, 2 * kPointerSize));
+          break;
+        case KEYED_PROPERTY:
+          __ StoreP(r3, MemOperand(sp, 2 * kPointerSize));
+          break;
+        case KEYED_SUPER_PROPERTY:
+          __ StoreP(r3, MemOperand(sp, 3 * kPointerSize));
+          break;
+      }
+    }
+  }
+
+  __ bind(&stub_call);
+  __ mr(r4, r3);
+  __ LoadSmiLiteral(r3, Smi::FromInt(count_value));
+
+  // Record position before stub call.
+  SetSourcePosition(expr->position());
+
+  Handle<Code> code =
+      CodeFactory::BinaryOpIC(isolate(), Token::ADD, NO_OVERWRITE).code();
+  CallIC(code, expr->CountBinOpFeedbackId());
+  patch_site.EmitPatchInfo();
+  __ bind(&done);
+
+  // Store the value returned in r3.
+  switch (assign_type) {
+    case VARIABLE:
+      if (expr->is_postfix()) {
+        {
+          EffectContext context(this);
+          EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
+                                 Token::ASSIGN);
+          PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
+          context.Plug(r3);
+        }
+        // For all contexts except EffectConstant We have the result on
+        // top of the stack.
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
+                               Token::ASSIGN);
+        PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
+        context()->Plug(r3);
+      }
+      break;
+    case NAMED_PROPERTY: {
+      __ mov(StoreDescriptor::NameRegister(),
+             Operand(prop->key()->AsLiteral()->value()));
+      __ pop(StoreDescriptor::ReceiverRegister());
+      CallStoreIC(expr->CountStoreFeedbackId());
+      PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(r3);
+      }
+      break;
+    }
+    case NAMED_SUPER_PROPERTY: {
+      EmitNamedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(r3);
+      }
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      EmitKeyedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(r3);
+      }
+      break;
+    }
+    case KEYED_PROPERTY: {
+      __ Pop(StoreDescriptor::ReceiverRegister(),
+             StoreDescriptor::NameRegister());
+      Handle<Code> ic =
+          CodeFactory::KeyedStoreIC(isolate(), strict_mode()).code();
+      CallIC(ic, expr->CountStoreFeedbackId());
+      PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(r3);
+      }
+      break;
+    }
+  }
+}
+
+
+void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
+  DCHECK(!context()->IsEffect());
+  DCHECK(!context()->IsTest());
+  VariableProxy* proxy = expr->AsVariableProxy();
+  if (proxy != NULL && proxy->var()->IsUnallocated()) {
+    Comment cmnt(masm_, "[ Global variable");
+    __ LoadP(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+    __ mov(LoadDescriptor::NameRegister(), Operand(proxy->name()));
+    if (FLAG_vector_ics) {
+      __ mov(VectorLoadICDescriptor::SlotRegister(),
+             Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
+    }
+    // Use a regular load, not a contextual load, to avoid a reference
+    // error.
+    CallLoadIC(NOT_CONTEXTUAL);
+    PrepareForBailout(expr, TOS_REG);
+    context()->Plug(r3);
+  } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
+    Comment cmnt(masm_, "[ Lookup slot");
+    Label done, slow;
+
+    // Generate code for loading from variables potentially shadowed
+    // by eval-introduced variables.
+    EmitDynamicLookupFastCase(proxy, INSIDE_TYPEOF, &slow, &done);
+
+    __ bind(&slow);
+    __ mov(r3, Operand(proxy->name()));
+    __ Push(cp, r3);
+    __ CallRuntime(Runtime::kLoadLookupSlotNoReferenceError, 2);
+    PrepareForBailout(expr, TOS_REG);
+    __ bind(&done);
+
+    context()->Plug(r3);
+  } else {
+    // This expression cannot throw a reference error at the top level.
+    VisitInDuplicateContext(expr);
+  }
+}
+
+
+void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
+                                                 Expression* sub_expr,
+                                                 Handle<String> check) {
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  {
+    AccumulatorValueContext context(this);
+    VisitForTypeofValue(sub_expr);
+  }
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+
+  Factory* factory = isolate()->factory();
+  if (String::Equals(check, factory->number_string())) {
+    __ JumpIfSmi(r3, if_true);
+    __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset));
+    __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
+    __ cmp(r3, ip);
+    Split(eq, if_true, if_false, fall_through);
+  } else if (String::Equals(check, factory->string_string())) {
+    __ JumpIfSmi(r3, if_false);
+    // Check for undetectable objects => false.
+    __ CompareObjectType(r3, r3, r4, FIRST_NONSTRING_TYPE);
+    __ bge(if_false);
+    __ lbz(r4, FieldMemOperand(r3, Map::kBitFieldOffset));
+    STATIC_ASSERT((1 << Map::kIsUndetectable) < 0x8000);
+    __ andi(r0, r4, Operand(1 << Map::kIsUndetectable));
+    Split(eq, if_true, if_false, fall_through, cr0);
+  } else if (String::Equals(check, factory->symbol_string())) {
+    __ JumpIfSmi(r3, if_false);
+    __ CompareObjectType(r3, r3, r4, SYMBOL_TYPE);
+    Split(eq, if_true, if_false, fall_through);
+  } else if (String::Equals(check, factory->boolean_string())) {
+    __ CompareRoot(r3, Heap::kTrueValueRootIndex);
+    __ beq(if_true);
+    __ CompareRoot(r3, Heap::kFalseValueRootIndex);
+    Split(eq, if_true, if_false, fall_through);
+  } else if (String::Equals(check, factory->undefined_string())) {
+    __ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
+    __ beq(if_true);
+    __ JumpIfSmi(r3, if_false);
+    // Check for undetectable objects => true.
+    __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset));
+    __ lbz(r4, FieldMemOperand(r3, Map::kBitFieldOffset));
+    __ andi(r0, r4, Operand(1 << Map::kIsUndetectable));
+    Split(ne, if_true, if_false, fall_through, cr0);
+
+  } else if (String::Equals(check, factory->function_string())) {
+    __ JumpIfSmi(r3, if_false);
+    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+    __ CompareObjectType(r3, r3, r4, JS_FUNCTION_TYPE);
+    __ beq(if_true);
+    __ cmpi(r4, Operand(JS_FUNCTION_PROXY_TYPE));
+    Split(eq, if_true, if_false, fall_through);
+  } else if (String::Equals(check, factory->object_string())) {
+    __ JumpIfSmi(r3, if_false);
+    __ CompareRoot(r3, Heap::kNullValueRootIndex);
+    __ beq(if_true);
+    // Check for JS objects => true.
+    __ CompareObjectType(r3, r3, r4, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
+    __ blt(if_false);
+    __ CompareInstanceType(r3, r4, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
+    __ bgt(if_false);
+    // Check for undetectable objects => false.
+    __ lbz(r4, FieldMemOperand(r3, Map::kBitFieldOffset));
+    __ andi(r0, r4, Operand(1 << Map::kIsUndetectable));
+    Split(eq, if_true, if_false, fall_through, cr0);
+  } else {
+    if (if_false != fall_through) __ b(if_false);
+  }
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
+  Comment cmnt(masm_, "[ CompareOperation");
+  SetSourcePosition(expr->position());
+
+  // First we try a fast inlined version of the compare when one of
+  // the operands is a literal.
+  if (TryLiteralCompare(expr)) return;
+
+  // Always perform the comparison for its control flow.  Pack the result
+  // into the expression's context after the comparison is performed.
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  Token::Value op = expr->op();
+  VisitForStackValue(expr->left());
+  switch (op) {
+    case Token::IN:
+      VisitForStackValue(expr->right());
+      __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
+      PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
+      __ LoadRoot(ip, Heap::kTrueValueRootIndex);
+      __ cmp(r3, ip);
+      Split(eq, if_true, if_false, fall_through);
+      break;
+
+    case Token::INSTANCEOF: {
+      VisitForStackValue(expr->right());
+      InstanceofStub stub(isolate(), InstanceofStub::kNoFlags);
+      __ CallStub(&stub);
+      PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+      // The stub returns 0 for true.
+      __ cmpi(r3, Operand::Zero());
+      Split(eq, if_true, if_false, fall_through);
+      break;
+    }
+
+    default: {
+      VisitForAccumulatorValue(expr->right());
+      Condition cond = CompareIC::ComputeCondition(op);
+      __ pop(r4);
+
+      bool inline_smi_code = ShouldInlineSmiCase(op);
+      JumpPatchSite patch_site(masm_);
+      if (inline_smi_code) {
+        Label slow_case;
+        __ orx(r5, r3, r4);
+        patch_site.EmitJumpIfNotSmi(r5, &slow_case);
+        __ cmp(r4, r3);
+        Split(cond, if_true, if_false, NULL);
+        __ bind(&slow_case);
+      }
+
+      // Record position and call the compare IC.
+      SetSourcePosition(expr->position());
+      Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
+      CallIC(ic, expr->CompareOperationFeedbackId());
+      patch_site.EmitPatchInfo();
+      PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+      __ cmpi(r3, Operand::Zero());
+      Split(cond, if_true, if_false, fall_through);
+    }
+  }
+
+  // Convert the result of the comparison into one expected for this
+  // expression's context.
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
+                                              Expression* sub_expr,
+                                              NilValue nil) {
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  VisitForAccumulatorValue(sub_expr);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  if (expr->op() == Token::EQ_STRICT) {
+    Heap::RootListIndex nil_value = nil == kNullValue
+                                        ? Heap::kNullValueRootIndex
+                                        : Heap::kUndefinedValueRootIndex;
+    __ LoadRoot(r4, nil_value);
+    __ cmp(r3, r4);
+    Split(eq, if_true, if_false, fall_through);
+  } else {
+    Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil);
+    CallIC(ic, expr->CompareOperationFeedbackId());
+    __ cmpi(r3, Operand::Zero());
+    Split(ne, if_true, if_false, fall_through);
+  }
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
+  __ LoadP(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  context()->Plug(r3);
+}
+
+
+Register FullCodeGenerator::result_register() { return r3; }
+
+
+Register FullCodeGenerator::context_register() { return cp; }
+
+
+void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
+  DCHECK_EQ(static_cast<int>(POINTER_SIZE_ALIGN(frame_offset)), frame_offset);
+  __ StoreP(value, MemOperand(fp, frame_offset), r0);
+}
+
+
+void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
+  __ LoadP(dst, ContextOperand(cp, context_index), r0);
+}
+
+
+void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
+  Scope* declaration_scope = scope()->DeclarationScope();
+  if (declaration_scope->is_script_scope() ||
+      declaration_scope->is_module_scope()) {
+    // Contexts nested in the native context have a canonical empty function
+    // as their closure, not the anonymous closure containing the global
+    // code.  Pass a smi sentinel and let the runtime look up the empty
+    // function.
+    __ LoadSmiLiteral(ip, Smi::FromInt(0));
+  } else if (declaration_scope->is_eval_scope()) {
+    // Contexts created by a call to eval have the same closure as the
+    // context calling eval, not the anonymous closure containing the eval
+    // code.  Fetch it from the context.
+    __ LoadP(ip, ContextOperand(cp, Context::CLOSURE_INDEX));
+  } else {
+    DCHECK(declaration_scope->is_function_scope());
+    __ LoadP(ip, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  }
+  __ push(ip);
+}
+
+
+// ----------------------------------------------------------------------------
+// Non-local control flow support.
+
+void FullCodeGenerator::EnterFinallyBlock() {
+  DCHECK(!result_register().is(r4));
+  // Store result register while executing finally block.
+  __ push(result_register());
+  // Cook return address in link register to stack (smi encoded Code* delta)
+  __ mflr(r4);
+  __ mov(ip, Operand(masm_->CodeObject()));
+  __ sub(r4, r4, ip);
+  __ SmiTag(r4);
+
+  // Store result register while executing finally block.
+  __ push(r4);
+
+  // Store pending message while executing finally block.
+  ExternalReference pending_message_obj =
+      ExternalReference::address_of_pending_message_obj(isolate());
+  __ mov(ip, Operand(pending_message_obj));
+  __ LoadP(r4, MemOperand(ip));
+  __ push(r4);
+
+  ExternalReference has_pending_message =
+      ExternalReference::address_of_has_pending_message(isolate());
+  __ mov(ip, Operand(has_pending_message));
+  __ lbz(r4, MemOperand(ip));
+  __ SmiTag(r4);
+  __ push(r4);
+
+  ExternalReference pending_message_script =
+      ExternalReference::address_of_pending_message_script(isolate());
+  __ mov(ip, Operand(pending_message_script));
+  __ LoadP(r4, MemOperand(ip));
+  __ push(r4);
+}
+
+
+void FullCodeGenerator::ExitFinallyBlock() {
+  DCHECK(!result_register().is(r4));
+  // Restore pending message from stack.
+  __ pop(r4);
+  ExternalReference pending_message_script =
+      ExternalReference::address_of_pending_message_script(isolate());
+  __ mov(ip, Operand(pending_message_script));
+  __ StoreP(r4, MemOperand(ip));
+
+  __ pop(r4);
+  __ SmiUntag(r4);
+  ExternalReference has_pending_message =
+      ExternalReference::address_of_has_pending_message(isolate());
+  __ mov(ip, Operand(has_pending_message));
+  __ stb(r4, MemOperand(ip));
+
+  __ pop(r4);
+  ExternalReference pending_message_obj =
+      ExternalReference::address_of_pending_message_obj(isolate());
+  __ mov(ip, Operand(pending_message_obj));
+  __ StoreP(r4, MemOperand(ip));
+
+  // Restore result register from stack.
+  __ pop(r4);
+
+  // Uncook return address and return.
+  __ pop(result_register());
+  __ SmiUntag(r4);
+  __ mov(ip, Operand(masm_->CodeObject()));
+  __ add(ip, ip, r4);
+  __ mtctr(ip);
+  __ bctr();
+}
+
+
+#undef __
+
+#define __ ACCESS_MASM(masm())
+
+FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
+    int* stack_depth, int* context_length) {
+  // The macros used here must preserve the result register.
+
+  // Because the handler block contains the context of the finally
+  // code, we can restore it directly from there for the finally code
+  // rather than iteratively unwinding contexts via their previous
+  // links.
+  __ Drop(*stack_depth);  // Down to the handler block.
+  if (*context_length > 0) {
+    // Restore the context to its dedicated register and the stack.
+    __ LoadP(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
+    __ StoreP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  }
+  __ PopTryHandler();
+  __ b(finally_entry_, SetLK);
+
+  *stack_depth = 0;
+  *context_length = 0;
+  return previous_;
+}
+
+#undef __
+
+
+void BackEdgeTable::PatchAt(Code* unoptimized_code, Address pc,
+                            BackEdgeState target_state,
+                            Code* replacement_code) {
+  Address mov_address = Assembler::target_address_from_return_address(pc);
+  Address cmp_address = mov_address - 2 * Assembler::kInstrSize;
+  CodePatcher patcher(cmp_address, 1);
+
+  switch (target_state) {
+    case INTERRUPT: {
+      //  <decrement profiling counter>
+      //         cmpi    r6, 0
+      //         bge     <ok>            ;; not changed
+      //         mov     r12, <interrupt stub address>
+      //         mtlr    r12
+      //         blrl
+      //  <reset profiling counter>
+      //  ok-label
+      patcher.masm()->cmpi(r6, Operand::Zero());
+      break;
+    }
+    case ON_STACK_REPLACEMENT:
+    case OSR_AFTER_STACK_CHECK:
+      //  <decrement profiling counter>
+      //         crset
+      //         bge     <ok>            ;; not changed
+      //         mov     r12, <on-stack replacement address>
+      //         mtlr    r12
+      //         blrl
+      //  <reset profiling counter>
+      //  ok-label ----- pc_after points here
+
+      // Set the LT bit such that bge is a NOP
+      patcher.masm()->crset(Assembler::encode_crbit(cr7, CR_LT));
+      break;
+  }
+
+  // Replace the stack check address in the mov sequence with the
+  // entry address of the replacement code.
+  Assembler::set_target_address_at(mov_address, unoptimized_code,
+                                   replacement_code->entry());
+
+  unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
+      unoptimized_code, mov_address, replacement_code);
+}
+
+
+BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
+    Isolate* isolate, Code* unoptimized_code, Address pc) {
+  Address mov_address = Assembler::target_address_from_return_address(pc);
+  Address cmp_address = mov_address - 2 * Assembler::kInstrSize;
+  Address interrupt_address =
+      Assembler::target_address_at(mov_address, unoptimized_code);
+
+  if (Assembler::IsCmpImmediate(Assembler::instr_at(cmp_address))) {
+    DCHECK(interrupt_address == isolate->builtins()->InterruptCheck()->entry());
+    return INTERRUPT;
+  }
+
+  DCHECK(Assembler::IsCrSet(Assembler::instr_at(cmp_address)));
+
+  if (interrupt_address == isolate->builtins()->OnStackReplacement()->entry()) {
+    return ON_STACK_REPLACEMENT;
+  }
+
+  DCHECK(interrupt_address ==
+         isolate->builtins()->OsrAfterStackCheck()->entry());
+  return OSR_AFTER_STACK_CHECK;
+}
+}
+}  // namespace v8::internal
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ppc/interface-descriptors-ppc.cc b/src/ppc/interface-descriptors-ppc.cc
new file mode 100644
index 0000000..693f341
--- /dev/null
+++ b/src/ppc/interface-descriptors-ppc.cc
@@ -0,0 +1,306 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/interface-descriptors.h"
+
+namespace v8 {
+namespace internal {
+
+const Register CallInterfaceDescriptor::ContextRegister() { return cp; }
+
+
+const Register LoadDescriptor::ReceiverRegister() { return r4; }
+const Register LoadDescriptor::NameRegister() { return r5; }
+
+
+const Register VectorLoadICTrampolineDescriptor::SlotRegister() { return r3; }
+
+
+const Register VectorLoadICDescriptor::VectorRegister() { return r6; }
+
+
+const Register StoreDescriptor::ReceiverRegister() { return r4; }
+const Register StoreDescriptor::NameRegister() { return r5; }
+const Register StoreDescriptor::ValueRegister() { return r3; }
+
+
+const Register StoreTransitionDescriptor::MapRegister() { return r6; }
+
+
+const Register ElementTransitionAndStoreDescriptor::MapRegister() { return r6; }
+
+
+const Register InstanceofDescriptor::left() { return r3; }
+const Register InstanceofDescriptor::right() { return r4; }
+
+
+const Register ArgumentsAccessReadDescriptor::index() { return r4; }
+const Register ArgumentsAccessReadDescriptor::parameter_count() { return r3; }
+
+
+const Register ApiGetterDescriptor::function_address() { return r5; }
+
+
+const Register MathPowTaggedDescriptor::exponent() { return r5; }
+
+
+const Register MathPowIntegerDescriptor::exponent() {
+  return MathPowTaggedDescriptor::exponent();
+}
+
+
+void FastNewClosureDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r5};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void FastNewContextDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r4};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void ToNumberDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r3};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void NumberToStringDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r3};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void FastCloneShallowArrayDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r6, r5, r4};
+  Representation representations[] = {
+      Representation::Tagged(), Representation::Tagged(), Representation::Smi(),
+      Representation::Tagged()};
+  data->Initialize(arraysize(registers), registers, representations);
+}
+
+
+void FastCloneShallowObjectDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r6, r5, r4, r3};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void CreateAllocationSiteDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r5, r6};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void StoreArrayLiteralElementDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r6, r3};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void CallFunctionDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r4};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void CallFunctionWithFeedbackDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r4, r6};
+  Representation representations[] = {Representation::Tagged(),
+                                      Representation::Tagged(),
+                                      Representation::Smi()};
+  data->Initialize(arraysize(registers), registers, representations);
+}
+
+
+void CallConstructDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  // r3 : number of arguments
+  // r4 : the function to call
+  // r5 : feedback vector
+  // r6 : (only if r5 is not the megamorphic symbol) slot in feedback
+  //      vector (Smi)
+  // TODO(turbofan): So far we don't gather type feedback and hence skip the
+  // slot parameter, but ArrayConstructStub needs the vector to be undefined.
+  Register registers[] = {cp, r3, r4, r5};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void RegExpConstructResultDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r5, r4, r3};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void TransitionElementsKindDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r3, r4};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void ArrayConstructorConstantArgCountDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // register state
+  // cp -- context
+  // r3 -- number of arguments
+  // r4 -- function
+  // r5 -- allocation site with elements kind
+  Register registers[] = {cp, r4, r5};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void ArrayConstructorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  // stack param count needs (constructor pointer, and single argument)
+  Register registers[] = {cp, r4, r5, r3};
+  Representation representations[] = {
+      Representation::Tagged(), Representation::Tagged(),
+      Representation::Tagged(), Representation::Integer32()};
+  data->Initialize(arraysize(registers), registers, representations);
+}
+
+
+void InternalArrayConstructorConstantArgCountDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // register state
+  // cp -- context
+  // r3 -- number of arguments
+  // r4 -- constructor function
+  Register registers[] = {cp, r4};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void InternalArrayConstructorDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // stack param count needs (constructor pointer, and single argument)
+  Register registers[] = {cp, r4, r3};
+  Representation representations[] = {Representation::Tagged(),
+                                      Representation::Tagged(),
+                                      Representation::Integer32()};
+  data->Initialize(arraysize(registers), registers, representations);
+}
+
+
+void CompareNilDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r3};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void ToBooleanDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r3};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void BinaryOpDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r4, r3};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void BinaryOpWithAllocationSiteDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r5, r4, r3};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void StringAddDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, r4, r3};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void KeyedDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {
+      cp,  // context
+      r5,  // key
+  };
+  Representation representations[] = {
+      Representation::Tagged(),  // context
+      Representation::Tagged(),  // key
+  };
+  data->Initialize(arraysize(registers), registers, representations);
+}
+
+
+void NamedDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {
+      cp,  // context
+      r5,  // name
+  };
+  Representation representations[] = {
+      Representation::Tagged(),  // context
+      Representation::Tagged(),  // name
+  };
+  data->Initialize(arraysize(registers), registers, representations);
+}
+
+
+void CallHandlerDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {
+      cp,  // context
+      r3,  // receiver
+  };
+  Representation representations[] = {
+      Representation::Tagged(),  // context
+      Representation::Tagged(),  // receiver
+  };
+  data->Initialize(arraysize(registers), registers, representations);
+}
+
+
+void ArgumentAdaptorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {
+      cp,  // context
+      r4,  // JSFunction
+      r3,  // actual number of arguments
+      r5,  // expected number of arguments
+  };
+  Representation representations[] = {
+      Representation::Tagged(),     // context
+      Representation::Tagged(),     // JSFunction
+      Representation::Integer32(),  // actual number of arguments
+      Representation::Integer32(),  // expected number of arguments
+  };
+  data->Initialize(arraysize(registers), registers, representations);
+}
+
+
+void ApiFunctionDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  Register registers[] = {
+      cp,  // context
+      r3,  // callee
+      r7,  // call_data
+      r5,  // holder
+      r4,  // api_function_address
+  };
+  Representation representations[] = {
+      Representation::Tagged(),    // context
+      Representation::Tagged(),    // callee
+      Representation::Tagged(),    // call_data
+      Representation::Tagged(),    // holder
+      Representation::External(),  // api_function_address
+  };
+  data->Initialize(arraysize(registers), registers, representations);
+}
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ppc/lithium-codegen-ppc.cc b/src/ppc/lithium-codegen-ppc.cc
new file mode 100644
index 0000000..7b6052c
--- /dev/null
+++ b/src/ppc/lithium-codegen-ppc.cc
@@ -0,0 +1,6136 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/base/bits.h"
+#include "src/code-factory.h"
+#include "src/code-stubs.h"
+#include "src/hydrogen-osr.h"
+#include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
+#include "src/ppc/lithium-codegen-ppc.h"
+#include "src/ppc/lithium-gap-resolver-ppc.h"
+
+namespace v8 {
+namespace internal {
+
+
+class SafepointGenerator FINAL : public CallWrapper {
+ public:
+  SafepointGenerator(LCodeGen* codegen, LPointerMap* pointers,
+                     Safepoint::DeoptMode mode)
+      : codegen_(codegen), pointers_(pointers), deopt_mode_(mode) {}
+  virtual ~SafepointGenerator() {}
+
+  void BeforeCall(int call_size) const OVERRIDE {}
+
+  void AfterCall() const OVERRIDE {
+    codegen_->RecordSafepoint(pointers_, deopt_mode_);
+  }
+
+ private:
+  LCodeGen* codegen_;
+  LPointerMap* pointers_;
+  Safepoint::DeoptMode deopt_mode_;
+};
+
+
+#define __ masm()->
+
+bool LCodeGen::GenerateCode() {
+  LPhase phase("Z_Code generation", chunk());
+  DCHECK(is_unused());
+  status_ = GENERATING;
+
+  // Open a frame scope to indicate that there is a frame on the stack.  The
+  // NONE indicates that the scope shouldn't actually generate code to set up
+  // the frame (that is done in GeneratePrologue).
+  FrameScope frame_scope(masm_, StackFrame::NONE);
+
+  return GeneratePrologue() && GenerateBody() && GenerateDeferredCode() &&
+         GenerateJumpTable() && GenerateSafepointTable();
+}
+
+
+void LCodeGen::FinishCode(Handle<Code> code) {
+  DCHECK(is_done());
+  code->set_stack_slots(GetStackSlotCount());
+  code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
+  if (code->is_optimized_code()) RegisterWeakObjectsInOptimizedCode(code);
+  PopulateDeoptimizationData(code);
+}
+
+
+void LCodeGen::SaveCallerDoubles() {
+  DCHECK(info()->saves_caller_doubles());
+  DCHECK(NeedsEagerFrame());
+  Comment(";;; Save clobbered callee double registers");
+  int count = 0;
+  BitVector* doubles = chunk()->allocated_double_registers();
+  BitVector::Iterator save_iterator(doubles);
+  while (!save_iterator.Done()) {
+    __ stfd(DoubleRegister::FromAllocationIndex(save_iterator.Current()),
+            MemOperand(sp, count * kDoubleSize));
+    save_iterator.Advance();
+    count++;
+  }
+}
+
+
+void LCodeGen::RestoreCallerDoubles() {
+  DCHECK(info()->saves_caller_doubles());
+  DCHECK(NeedsEagerFrame());
+  Comment(";;; Restore clobbered callee double registers");
+  BitVector* doubles = chunk()->allocated_double_registers();
+  BitVector::Iterator save_iterator(doubles);
+  int count = 0;
+  while (!save_iterator.Done()) {
+    __ lfd(DoubleRegister::FromAllocationIndex(save_iterator.Current()),
+           MemOperand(sp, count * kDoubleSize));
+    save_iterator.Advance();
+    count++;
+  }
+}
+
+
+bool LCodeGen::GeneratePrologue() {
+  DCHECK(is_generating());
+
+  if (info()->IsOptimizing()) {
+    ProfileEntryHookStub::MaybeCallEntryHook(masm_);
+
+#ifdef DEBUG
+    if (strlen(FLAG_stop_at) > 0 &&
+        info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
+      __ stop("stop_at");
+    }
+#endif
+
+    // r4: Callee's JS function.
+    // cp: Callee's context.
+    // pp: Callee's constant pool pointer (if FLAG_enable_ool_constant_pool)
+    // fp: Caller's frame pointer.
+    // lr: Caller's pc.
+    // ip: Our own function entry (required by the prologue)
+
+    // Sloppy mode functions and builtins need to replace the receiver with the
+    // global proxy when called as functions (without an explicit receiver
+    // object).
+    if (info_->this_has_uses() && info_->strict_mode() == SLOPPY &&
+        !info_->is_native()) {
+      Label ok;
+      int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
+      __ LoadP(r5, MemOperand(sp, receiver_offset));
+      __ CompareRoot(r5, Heap::kUndefinedValueRootIndex);
+      __ bne(&ok);
+
+      __ LoadP(r5, GlobalObjectOperand());
+      __ LoadP(r5, FieldMemOperand(r5, GlobalObject::kGlobalProxyOffset));
+
+      __ StoreP(r5, MemOperand(sp, receiver_offset));
+
+      __ bind(&ok);
+    }
+  }
+
+  int prologue_offset = masm_->pc_offset();
+
+  if (prologue_offset) {
+    // Prologue logic requires it's starting address in ip and the
+    // corresponding offset from the function entry.
+    prologue_offset += Instruction::kInstrSize;
+    __ addi(ip, ip, Operand(prologue_offset));
+  }
+  info()->set_prologue_offset(prologue_offset);
+  if (NeedsEagerFrame()) {
+    if (info()->IsStub()) {
+      __ StubPrologue(prologue_offset);
+    } else {
+      __ Prologue(info()->IsCodePreAgingActive(), prologue_offset);
+    }
+    frame_is_built_ = true;
+    info_->AddNoFrameRange(0, masm_->pc_offset());
+  }
+
+  // Reserve space for the stack slots needed by the code.
+  int slots = GetStackSlotCount();
+  if (slots > 0) {
+    __ subi(sp, sp, Operand(slots * kPointerSize));
+    if (FLAG_debug_code) {
+      __ Push(r3, r4);
+      __ li(r0, Operand(slots));
+      __ mtctr(r0);
+      __ addi(r3, sp, Operand((slots + 2) * kPointerSize));
+      __ mov(r4, Operand(kSlotsZapValue));
+      Label loop;
+      __ bind(&loop);
+      __ StorePU(r4, MemOperand(r3, -kPointerSize));
+      __ bdnz(&loop);
+      __ Pop(r3, r4);
+    }
+  }
+
+  if (info()->saves_caller_doubles()) {
+    SaveCallerDoubles();
+  }
+
+  // Possibly allocate a local context.
+  int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+  if (heap_slots > 0) {
+    Comment(";;; Allocate local context");
+    bool need_write_barrier = true;
+    // Argument to NewContext is the function, which is in r4.
+    if (heap_slots <= FastNewContextStub::kMaximumSlots) {
+      FastNewContextStub stub(isolate(), heap_slots);
+      __ CallStub(&stub);
+      // Result of FastNewContextStub is always in new space.
+      need_write_barrier = false;
+    } else {
+      __ push(r4);
+      __ CallRuntime(Runtime::kNewFunctionContext, 1);
+    }
+    RecordSafepoint(Safepoint::kNoLazyDeopt);
+    // Context is returned in both r3 and cp.  It replaces the context
+    // passed to us.  It's saved in the stack and kept live in cp.
+    __ mr(cp, r3);
+    __ StoreP(r3, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    // Copy any necessary parameters into the context.
+    int num_parameters = scope()->num_parameters();
+    for (int i = 0; i < num_parameters; i++) {
+      Variable* var = scope()->parameter(i);
+      if (var->IsContextSlot()) {
+        int parameter_offset = StandardFrameConstants::kCallerSPOffset +
+                               (num_parameters - 1 - i) * kPointerSize;
+        // Load parameter from stack.
+        __ LoadP(r3, MemOperand(fp, parameter_offset));
+        // Store it in the context.
+        MemOperand target = ContextOperand(cp, var->index());
+        __ StoreP(r3, target, r0);
+        // Update the write barrier. This clobbers r6 and r3.
+        if (need_write_barrier) {
+          __ RecordWriteContextSlot(cp, target.offset(), r3, r6,
+                                    GetLinkRegisterState(), kSaveFPRegs);
+        } else if (FLAG_debug_code) {
+          Label done;
+          __ JumpIfInNewSpace(cp, r3, &done);
+          __ Abort(kExpectedNewSpaceObject);
+          __ bind(&done);
+        }
+      }
+    }
+    Comment(";;; End allocate local context");
+  }
+
+  // Trace the call.
+  if (FLAG_trace && info()->IsOptimizing()) {
+    // We have not executed any compiled code yet, so cp still holds the
+    // incoming context.
+    __ CallRuntime(Runtime::kTraceEnter, 0);
+  }
+  return !is_aborted();
+}
+
+
+void LCodeGen::GenerateOsrPrologue() {
+  // Generate the OSR entry prologue at the first unknown OSR value, or if there
+  // are none, at the OSR entrypoint instruction.
+  if (osr_pc_offset_ >= 0) return;
+
+  osr_pc_offset_ = masm()->pc_offset();
+
+  // Adjust the frame size, subsuming the unoptimized frame into the
+  // optimized frame.
+  int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
+  DCHECK(slots >= 0);
+  __ subi(sp, sp, Operand(slots * kPointerSize));
+}
+
+
+void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
+  if (instr->IsCall()) {
+    EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
+  }
+  if (!instr->IsLazyBailout() && !instr->IsGap()) {
+    safepoints_.BumpLastLazySafepointIndex();
+  }
+}
+
+
+bool LCodeGen::GenerateDeferredCode() {
+  DCHECK(is_generating());
+  if (deferred_.length() > 0) {
+    for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
+      LDeferredCode* code = deferred_[i];
+
+      HValue* value =
+          instructions_->at(code->instruction_index())->hydrogen_value();
+      RecordAndWritePosition(
+          chunk()->graph()->SourcePositionToScriptPosition(value->position()));
+
+      Comment(
+          ";;; <@%d,#%d> "
+          "-------------------- Deferred %s --------------------",
+          code->instruction_index(), code->instr()->hydrogen_value()->id(),
+          code->instr()->Mnemonic());
+      __ bind(code->entry());
+      if (NeedsDeferredFrame()) {
+        Comment(";;; Build frame");
+        DCHECK(!frame_is_built_);
+        DCHECK(info()->IsStub());
+        frame_is_built_ = true;
+        __ LoadSmiLiteral(scratch0(), Smi::FromInt(StackFrame::STUB));
+        __ PushFixedFrame(scratch0());
+        __ addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+        Comment(";;; Deferred code");
+      }
+      code->Generate();
+      if (NeedsDeferredFrame()) {
+        Comment(";;; Destroy frame");
+        DCHECK(frame_is_built_);
+        __ PopFixedFrame(ip);
+        frame_is_built_ = false;
+      }
+      __ b(code->exit());
+    }
+  }
+
+  return !is_aborted();
+}
+
+
+bool LCodeGen::GenerateJumpTable() {
+  // Check that the jump table is accessible from everywhere in the function
+  // code, i.e. that offsets to the table can be encoded in the 24bit signed
+  // immediate of a branch instruction.
+  // To simplify we consider the code size from the first instruction to the
+  // end of the jump table. We also don't consider the pc load delta.
+  // Each entry in the jump table generates one instruction and inlines one
+  // 32bit data after it.
+  if (!is_int24((masm()->pc_offset() / Assembler::kInstrSize) +
+                jump_table_.length() * 7)) {
+    Abort(kGeneratedCodeIsTooLarge);
+  }
+
+  if (jump_table_.length() > 0) {
+    Label needs_frame, call_deopt_entry;
+
+    Comment(";;; -------------------- Jump table --------------------");
+    Address base = jump_table_[0].address;
+
+    Register entry_offset = scratch0();
+
+    int length = jump_table_.length();
+    for (int i = 0; i < length; i++) {
+      Deoptimizer::JumpTableEntry* table_entry = &jump_table_[i];
+      __ bind(&table_entry->label);
+
+      DCHECK_EQ(jump_table_[0].bailout_type, table_entry->bailout_type);
+      Address entry = table_entry->address;
+      DeoptComment(table_entry->reason);
+
+      // Second-level deopt table entries are contiguous and small, so instead
+      // of loading the full, absolute address of each one, load an immediate
+      // offset which will be added to the base address later.
+      __ mov(entry_offset, Operand(entry - base));
+
+      if (table_entry->needs_frame) {
+        DCHECK(!info()->saves_caller_doubles());
+        if (needs_frame.is_bound()) {
+          __ b(&needs_frame);
+        } else {
+          __ bind(&needs_frame);
+          Comment(";;; call deopt with frame");
+          // This variant of deopt can only be used with stubs. Since we don't
+          // have a function pointer to install in the stack frame that we're
+          // building, install a special marker there instead.
+          DCHECK(info()->IsStub());
+          __ LoadSmiLiteral(ip, Smi::FromInt(StackFrame::STUB));
+          __ PushFixedFrame(ip);
+          __ addi(fp, sp,
+                  Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+          __ bind(&call_deopt_entry);
+          // Add the base address to the offset previously loaded in
+          // entry_offset.
+          __ mov(ip, Operand(ExternalReference::ForDeoptEntry(base)));
+          __ add(ip, entry_offset, ip);
+          __ Call(ip);
+        }
+      } else {
+        // The last entry can fall through into `call_deopt_entry`, avoiding a
+        // branch.
+        bool need_branch = ((i + 1) != length) || call_deopt_entry.is_bound();
+
+        if (need_branch) __ b(&call_deopt_entry);
+      }
+    }
+
+    if (!call_deopt_entry.is_bound()) {
+      Comment(";;; call deopt");
+      __ bind(&call_deopt_entry);
+
+      if (info()->saves_caller_doubles()) {
+        DCHECK(info()->IsStub());
+        RestoreCallerDoubles();
+      }
+
+      // Add the base address to the offset previously loaded in entry_offset.
+      __ mov(ip, Operand(ExternalReference::ForDeoptEntry(base)));
+      __ add(ip, entry_offset, ip);
+      __ Call(ip);
+    }
+  }
+
+  // The deoptimization jump table is the last part of the instruction
+  // sequence. Mark the generated code as done unless we bailed out.
+  if (!is_aborted()) status_ = DONE;
+  return !is_aborted();
+}
+
+
+bool LCodeGen::GenerateSafepointTable() {
+  DCHECK(is_done());
+  safepoints_.Emit(masm(), GetStackSlotCount());
+  return !is_aborted();
+}
+
+
+Register LCodeGen::ToRegister(int index) const {
+  return Register::FromAllocationIndex(index);
+}
+
+
+DoubleRegister LCodeGen::ToDoubleRegister(int index) const {
+  return DoubleRegister::FromAllocationIndex(index);
+}
+
+
+Register LCodeGen::ToRegister(LOperand* op) const {
+  DCHECK(op->IsRegister());
+  return ToRegister(op->index());
+}
+
+
+Register LCodeGen::EmitLoadRegister(LOperand* op, Register scratch) {
+  if (op->IsRegister()) {
+    return ToRegister(op->index());
+  } else if (op->IsConstantOperand()) {
+    LConstantOperand* const_op = LConstantOperand::cast(op);
+    HConstant* constant = chunk_->LookupConstant(const_op);
+    Handle<Object> literal = constant->handle(isolate());
+    Representation r = chunk_->LookupLiteralRepresentation(const_op);
+    if (r.IsInteger32()) {
+      DCHECK(literal->IsNumber());
+      __ LoadIntLiteral(scratch, static_cast<int32_t>(literal->Number()));
+    } else if (r.IsDouble()) {
+      Abort(kEmitLoadRegisterUnsupportedDoubleImmediate);
+    } else {
+      DCHECK(r.IsSmiOrTagged());
+      __ Move(scratch, literal);
+    }
+    return scratch;
+  } else if (op->IsStackSlot()) {
+    __ LoadP(scratch, ToMemOperand(op));
+    return scratch;
+  }
+  UNREACHABLE();
+  return scratch;
+}
+
+
+void LCodeGen::EmitLoadIntegerConstant(LConstantOperand* const_op,
+                                       Register dst) {
+  DCHECK(IsInteger32(const_op));
+  HConstant* constant = chunk_->LookupConstant(const_op);
+  int32_t value = constant->Integer32Value();
+  if (IsSmi(const_op)) {
+    __ LoadSmiLiteral(dst, Smi::FromInt(value));
+  } else {
+    __ LoadIntLiteral(dst, value);
+  }
+}
+
+
+DoubleRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
+  DCHECK(op->IsDoubleRegister());
+  return ToDoubleRegister(op->index());
+}
+
+
+Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
+  HConstant* constant = chunk_->LookupConstant(op);
+  DCHECK(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
+  return constant->handle(isolate());
+}
+
+
+bool LCodeGen::IsInteger32(LConstantOperand* op) const {
+  return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
+}
+
+
+bool LCodeGen::IsSmi(LConstantOperand* op) const {
+  return chunk_->LookupLiteralRepresentation(op).IsSmi();
+}
+
+
+int32_t LCodeGen::ToInteger32(LConstantOperand* op) const {
+  return ToRepresentation(op, Representation::Integer32());
+}
+
+
+intptr_t LCodeGen::ToRepresentation(LConstantOperand* op,
+                                    const Representation& r) const {
+  HConstant* constant = chunk_->LookupConstant(op);
+  int32_t value = constant->Integer32Value();
+  if (r.IsInteger32()) return value;
+  DCHECK(r.IsSmiOrTagged());
+  return reinterpret_cast<intptr_t>(Smi::FromInt(value));
+}
+
+
+Smi* LCodeGen::ToSmi(LConstantOperand* op) const {
+  HConstant* constant = chunk_->LookupConstant(op);
+  return Smi::FromInt(constant->Integer32Value());
+}
+
+
+double LCodeGen::ToDouble(LConstantOperand* op) const {
+  HConstant* constant = chunk_->LookupConstant(op);
+  DCHECK(constant->HasDoubleValue());
+  return constant->DoubleValue();
+}
+
+
+Operand LCodeGen::ToOperand(LOperand* op) {
+  if (op->IsConstantOperand()) {
+    LConstantOperand* const_op = LConstantOperand::cast(op);
+    HConstant* constant = chunk()->LookupConstant(const_op);
+    Representation r = chunk_->LookupLiteralRepresentation(const_op);
+    if (r.IsSmi()) {
+      DCHECK(constant->HasSmiValue());
+      return Operand(Smi::FromInt(constant->Integer32Value()));
+    } else if (r.IsInteger32()) {
+      DCHECK(constant->HasInteger32Value());
+      return Operand(constant->Integer32Value());
+    } else if (r.IsDouble()) {
+      Abort(kToOperandUnsupportedDoubleImmediate);
+    }
+    DCHECK(r.IsTagged());
+    return Operand(constant->handle(isolate()));
+  } else if (op->IsRegister()) {
+    return Operand(ToRegister(op));
+  } else if (op->IsDoubleRegister()) {
+    Abort(kToOperandIsDoubleRegisterUnimplemented);
+    return Operand::Zero();
+  }
+  // Stack slots not implemented, use ToMemOperand instead.
+  UNREACHABLE();
+  return Operand::Zero();
+}
+
+
+static int ArgumentsOffsetWithoutFrame(int index) {
+  DCHECK(index < 0);
+  return -(index + 1) * kPointerSize;
+}
+
+
+MemOperand LCodeGen::ToMemOperand(LOperand* op) const {
+  DCHECK(!op->IsRegister());
+  DCHECK(!op->IsDoubleRegister());
+  DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
+  if (NeedsEagerFrame()) {
+    return MemOperand(fp, StackSlotOffset(op->index()));
+  } else {
+    // Retrieve parameter without eager stack-frame relative to the
+    // stack-pointer.
+    return MemOperand(sp, ArgumentsOffsetWithoutFrame(op->index()));
+  }
+}
+
+
+MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const {
+  DCHECK(op->IsDoubleStackSlot());
+  if (NeedsEagerFrame()) {
+    return MemOperand(fp, StackSlotOffset(op->index()) + kPointerSize);
+  } else {
+    // Retrieve parameter without eager stack-frame relative to the
+    // stack-pointer.
+    return MemOperand(sp,
+                      ArgumentsOffsetWithoutFrame(op->index()) + kPointerSize);
+  }
+}
+
+
+void LCodeGen::WriteTranslation(LEnvironment* environment,
+                                Translation* translation) {
+  if (environment == NULL) return;
+
+  // The translation includes one command per value in the environment.
+  int translation_size = environment->translation_size();
+  // The output frame height does not include the parameters.
+  int height = translation_size - environment->parameter_count();
+
+  WriteTranslation(environment->outer(), translation);
+  bool has_closure_id =
+      !info()->closure().is_null() &&
+      !info()->closure().is_identical_to(environment->closure());
+  int closure_id = has_closure_id
+                       ? DefineDeoptimizationLiteral(environment->closure())
+                       : Translation::kSelfLiteralId;
+
+  switch (environment->frame_type()) {
+    case JS_FUNCTION:
+      translation->BeginJSFrame(environment->ast_id(), closure_id, height);
+      break;
+    case JS_CONSTRUCT:
+      translation->BeginConstructStubFrame(closure_id, translation_size);
+      break;
+    case JS_GETTER:
+      DCHECK(translation_size == 1);
+      DCHECK(height == 0);
+      translation->BeginGetterStubFrame(closure_id);
+      break;
+    case JS_SETTER:
+      DCHECK(translation_size == 2);
+      DCHECK(height == 0);
+      translation->BeginSetterStubFrame(closure_id);
+      break;
+    case STUB:
+      translation->BeginCompiledStubFrame();
+      break;
+    case ARGUMENTS_ADAPTOR:
+      translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
+      break;
+  }
+
+  int object_index = 0;
+  int dematerialized_index = 0;
+  for (int i = 0; i < translation_size; ++i) {
+    LOperand* value = environment->values()->at(i);
+    AddToTranslation(
+        environment, translation, value, environment->HasTaggedValueAt(i),
+        environment->HasUint32ValueAt(i), &object_index, &dematerialized_index);
+  }
+}
+
+
+void LCodeGen::AddToTranslation(LEnvironment* environment,
+                                Translation* translation, LOperand* op,
+                                bool is_tagged, bool is_uint32,
+                                int* object_index_pointer,
+                                int* dematerialized_index_pointer) {
+  if (op == LEnvironment::materialization_marker()) {
+    int object_index = (*object_index_pointer)++;
+    if (environment->ObjectIsDuplicateAt(object_index)) {
+      int dupe_of = environment->ObjectDuplicateOfAt(object_index);
+      translation->DuplicateObject(dupe_of);
+      return;
+    }
+    int object_length = environment->ObjectLengthAt(object_index);
+    if (environment->ObjectIsArgumentsAt(object_index)) {
+      translation->BeginArgumentsObject(object_length);
+    } else {
+      translation->BeginCapturedObject(object_length);
+    }
+    int dematerialized_index = *dematerialized_index_pointer;
+    int env_offset = environment->translation_size() + dematerialized_index;
+    *dematerialized_index_pointer += object_length;
+    for (int i = 0; i < object_length; ++i) {
+      LOperand* value = environment->values()->at(env_offset + i);
+      AddToTranslation(environment, translation, value,
+                       environment->HasTaggedValueAt(env_offset + i),
+                       environment->HasUint32ValueAt(env_offset + i),
+                       object_index_pointer, dematerialized_index_pointer);
+    }
+    return;
+  }
+
+  if (op->IsStackSlot()) {
+    if (is_tagged) {
+      translation->StoreStackSlot(op->index());
+    } else if (is_uint32) {
+      translation->StoreUint32StackSlot(op->index());
+    } else {
+      translation->StoreInt32StackSlot(op->index());
+    }
+  } else if (op->IsDoubleStackSlot()) {
+    translation->StoreDoubleStackSlot(op->index());
+  } else if (op->IsRegister()) {
+    Register reg = ToRegister(op);
+    if (is_tagged) {
+      translation->StoreRegister(reg);
+    } else if (is_uint32) {
+      translation->StoreUint32Register(reg);
+    } else {
+      translation->StoreInt32Register(reg);
+    }
+  } else if (op->IsDoubleRegister()) {
+    DoubleRegister reg = ToDoubleRegister(op);
+    translation->StoreDoubleRegister(reg);
+  } else if (op->IsConstantOperand()) {
+    HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
+    int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
+    translation->StoreLiteral(src_index);
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+void LCodeGen::CallCode(Handle<Code> code, RelocInfo::Mode mode,
+                        LInstruction* instr) {
+  CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
+}
+
+
+void LCodeGen::CallCodeGeneric(Handle<Code> code, RelocInfo::Mode mode,
+                               LInstruction* instr,
+                               SafepointMode safepoint_mode) {
+  DCHECK(instr != NULL);
+  __ Call(code, mode);
+  RecordSafepointWithLazyDeopt(instr, safepoint_mode);
+
+  // Signal that we don't inline smi code before these stubs in the
+  // optimizing code generator.
+  if (code->kind() == Code::BINARY_OP_IC || code->kind() == Code::COMPARE_IC) {
+    __ nop();
+  }
+}
+
+
+void LCodeGen::CallRuntime(const Runtime::Function* function, int num_arguments,
+                           LInstruction* instr, SaveFPRegsMode save_doubles) {
+  DCHECK(instr != NULL);
+
+  __ CallRuntime(function, num_arguments, save_doubles);
+
+  RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
+}
+
+
+void LCodeGen::LoadContextFromDeferred(LOperand* context) {
+  if (context->IsRegister()) {
+    __ Move(cp, ToRegister(context));
+  } else if (context->IsStackSlot()) {
+    __ LoadP(cp, ToMemOperand(context));
+  } else if (context->IsConstantOperand()) {
+    HConstant* constant =
+        chunk_->LookupConstant(LConstantOperand::cast(context));
+    __ Move(cp, Handle<Object>::cast(constant->handle(isolate())));
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, int argc,
+                                       LInstruction* instr, LOperand* context) {
+  LoadContextFromDeferred(context);
+  __ CallRuntimeSaveDoubles(id);
+  RecordSafepointWithRegisters(instr->pointer_map(), argc,
+                               Safepoint::kNoLazyDeopt);
+}
+
+
+void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
+                                                    Safepoint::DeoptMode mode) {
+  environment->set_has_been_used();
+  if (!environment->HasBeenRegistered()) {
+    // Physical stack frame layout:
+    // -x ............. -4  0 ..................................... y
+    // [incoming arguments] [spill slots] [pushed outgoing arguments]
+
+    // Layout of the environment:
+    // 0 ..................................................... size-1
+    // [parameters] [locals] [expression stack including arguments]
+
+    // Layout of the translation:
+    // 0 ........................................................ size - 1 + 4
+    // [expression stack including arguments] [locals] [4 words] [parameters]
+    // |>------------  translation_size ------------<|
+
+    int frame_count = 0;
+    int jsframe_count = 0;
+    for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
+      ++frame_count;
+      if (e->frame_type() == JS_FUNCTION) {
+        ++jsframe_count;
+      }
+    }
+    Translation translation(&translations_, frame_count, jsframe_count, zone());
+    WriteTranslation(environment, &translation);
+    int deoptimization_index = deoptimizations_.length();
+    int pc_offset = masm()->pc_offset();
+    environment->Register(deoptimization_index, translation.index(),
+                          (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
+    deoptimizations_.Add(environment, zone());
+  }
+}
+
+
+void LCodeGen::DeoptimizeIf(Condition cond, LInstruction* instr,
+                            const char* detail,
+                            Deoptimizer::BailoutType bailout_type,
+                            CRegister cr) {
+  LEnvironment* environment = instr->environment();
+  RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
+  DCHECK(environment->HasBeenRegistered());
+  int id = environment->deoptimization_index();
+  DCHECK(info()->IsOptimizing() || info()->IsStub());
+  Address entry =
+      Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
+  if (entry == NULL) {
+    Abort(kBailoutWasNotPrepared);
+    return;
+  }
+
+  if (FLAG_deopt_every_n_times != 0 && !info()->IsStub()) {
+    CRegister alt_cr = cr6;
+    Register scratch = scratch0();
+    ExternalReference count = ExternalReference::stress_deopt_count(isolate());
+    Label no_deopt;
+    DCHECK(!alt_cr.is(cr));
+    __ Push(r4, scratch);
+    __ mov(scratch, Operand(count));
+    __ lwz(r4, MemOperand(scratch));
+    __ subi(r4, r4, Operand(1));
+    __ cmpi(r4, Operand::Zero(), alt_cr);
+    __ bne(&no_deopt, alt_cr);
+    __ li(r4, Operand(FLAG_deopt_every_n_times));
+    __ stw(r4, MemOperand(scratch));
+    __ Pop(r4, scratch);
+
+    __ Call(entry, RelocInfo::RUNTIME_ENTRY);
+    __ bind(&no_deopt);
+    __ stw(r4, MemOperand(scratch));
+    __ Pop(r4, scratch);
+  }
+
+  if (info()->ShouldTrapOnDeopt()) {
+    __ stop("trap_on_deopt", cond, kDefaultStopCode, cr);
+  }
+
+  Deoptimizer::Reason reason(instr->hydrogen_value()->position().raw(),
+                             instr->Mnemonic(), detail);
+  DCHECK(info()->IsStub() || frame_is_built_);
+  // Go through jump table if we need to handle condition, build frame, or
+  // restore caller doubles.
+  if (cond == al && frame_is_built_ && !info()->saves_caller_doubles()) {
+    DeoptComment(reason);
+    __ Call(entry, RelocInfo::RUNTIME_ENTRY);
+  } else {
+    Deoptimizer::JumpTableEntry table_entry(entry, reason, bailout_type,
+                                            !frame_is_built_);
+    // We often have several deopts to the same entry, reuse the last
+    // jump entry if this is the case.
+    if (jump_table_.is_empty() ||
+        !table_entry.IsEquivalentTo(jump_table_.last())) {
+      jump_table_.Add(table_entry, zone());
+    }
+    __ b(cond, &jump_table_.last().label, cr);
+  }
+}
+
+
+void LCodeGen::DeoptimizeIf(Condition condition, LInstruction* instr,
+                            const char* detail, CRegister cr) {
+  Deoptimizer::BailoutType bailout_type =
+      info()->IsStub() ? Deoptimizer::LAZY : Deoptimizer::EAGER;
+  DeoptimizeIf(condition, instr, detail, bailout_type, cr);
+}
+
+
+void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
+  int length = deoptimizations_.length();
+  if (length == 0) return;
+  Handle<DeoptimizationInputData> data =
+      DeoptimizationInputData::New(isolate(), length, TENURED);
+
+  Handle<ByteArray> translations =
+      translations_.CreateByteArray(isolate()->factory());
+  data->SetTranslationByteArray(*translations);
+  data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
+  data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
+  if (info_->IsOptimizing()) {
+    // Reference to shared function info does not change between phases.
+    AllowDeferredHandleDereference allow_handle_dereference;
+    data->SetSharedFunctionInfo(*info_->shared_info());
+  } else {
+    data->SetSharedFunctionInfo(Smi::FromInt(0));
+  }
+
+  Handle<FixedArray> literals =
+      factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
+  {
+    AllowDeferredHandleDereference copy_handles;
+    for (int i = 0; i < deoptimization_literals_.length(); i++) {
+      literals->set(i, *deoptimization_literals_[i]);
+    }
+    data->SetLiteralArray(*literals);
+  }
+
+  data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
+  data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
+
+  // Populate the deoptimization entries.
+  for (int i = 0; i < length; i++) {
+    LEnvironment* env = deoptimizations_[i];
+    data->SetAstId(i, env->ast_id());
+    data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
+    data->SetArgumentsStackHeight(i,
+                                  Smi::FromInt(env->arguments_stack_height()));
+    data->SetPc(i, Smi::FromInt(env->pc_offset()));
+  }
+  code->set_deoptimization_data(*data);
+}
+
+
+int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
+  int result = deoptimization_literals_.length();
+  for (int i = 0; i < deoptimization_literals_.length(); ++i) {
+    if (deoptimization_literals_[i].is_identical_to(literal)) return i;
+  }
+  deoptimization_literals_.Add(literal, zone());
+  return result;
+}
+
+
+void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
+  DCHECK(deoptimization_literals_.length() == 0);
+
+  const ZoneList<Handle<JSFunction> >* inlined_closures =
+      chunk()->inlined_closures();
+
+  for (int i = 0, length = inlined_closures->length(); i < length; i++) {
+    DefineDeoptimizationLiteral(inlined_closures->at(i));
+  }
+
+  inlined_function_count_ = deoptimization_literals_.length();
+}
+
+
+void LCodeGen::RecordSafepointWithLazyDeopt(LInstruction* instr,
+                                            SafepointMode safepoint_mode) {
+  if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
+    RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
+  } else {
+    DCHECK(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
+    RecordSafepointWithRegisters(instr->pointer_map(), 0,
+                                 Safepoint::kLazyDeopt);
+  }
+}
+
+
+void LCodeGen::RecordSafepoint(LPointerMap* pointers, Safepoint::Kind kind,
+                               int arguments, Safepoint::DeoptMode deopt_mode) {
+  DCHECK(expected_safepoint_kind_ == kind);
+
+  const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
+  Safepoint safepoint =
+      safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
+  for (int i = 0; i < operands->length(); i++) {
+    LOperand* pointer = operands->at(i);
+    if (pointer->IsStackSlot()) {
+      safepoint.DefinePointerSlot(pointer->index(), zone());
+    } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
+      safepoint.DefinePointerRegister(ToRegister(pointer), zone());
+    }
+  }
+#if V8_OOL_CONSTANT_POOL
+  if (kind & Safepoint::kWithRegisters) {
+    // Register always contains a pointer to the constant pool.
+    safepoint.DefinePointerRegister(kConstantPoolRegister, zone());
+  }
+#endif
+}
+
+
+void LCodeGen::RecordSafepoint(LPointerMap* pointers,
+                               Safepoint::DeoptMode deopt_mode) {
+  RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
+}
+
+
+void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
+  LPointerMap empty_pointers(zone());
+  RecordSafepoint(&empty_pointers, deopt_mode);
+}
+
+
+void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
+                                            int arguments,
+                                            Safepoint::DeoptMode deopt_mode) {
+  RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
+}
+
+
+void LCodeGen::RecordAndWritePosition(int position) {
+  if (position == RelocInfo::kNoPosition) return;
+  masm()->positions_recorder()->RecordPosition(position);
+  masm()->positions_recorder()->WriteRecordedPositions();
+}
+
+
+static const char* LabelType(LLabel* label) {
+  if (label->is_loop_header()) return " (loop header)";
+  if (label->is_osr_entry()) return " (OSR entry)";
+  return "";
+}
+
+
+void LCodeGen::DoLabel(LLabel* label) {
+  Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------",
+          current_instruction_, label->hydrogen_value()->id(),
+          label->block_id(), LabelType(label));
+  __ bind(label->label());
+  current_block_ = label->block_id();
+  DoGap(label);
+}
+
+
+void LCodeGen::DoParallelMove(LParallelMove* move) { resolver_.Resolve(move); }
+
+
+void LCodeGen::DoGap(LGap* gap) {
+  for (int i = LGap::FIRST_INNER_POSITION; i <= LGap::LAST_INNER_POSITION;
+       i++) {
+    LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
+    LParallelMove* move = gap->GetParallelMove(inner_pos);
+    if (move != NULL) DoParallelMove(move);
+  }
+}
+
+
+void LCodeGen::DoInstructionGap(LInstructionGap* instr) { DoGap(instr); }
+
+
+void LCodeGen::DoParameter(LParameter* instr) {
+  // Nothing to do.
+}
+
+
+void LCodeGen::DoCallStub(LCallStub* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->result()).is(r3));
+  switch (instr->hydrogen()->major_key()) {
+    case CodeStub::RegExpExec: {
+      RegExpExecStub stub(isolate());
+      CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+      break;
+    }
+    case CodeStub::SubString: {
+      SubStringStub stub(isolate());
+      CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+      break;
+    }
+    case CodeStub::StringCompare: {
+      StringCompareStub stub(isolate());
+      CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+      break;
+    }
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
+  GenerateOsrPrologue();
+}
+
+
+void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
+  Register dividend = ToRegister(instr->dividend());
+  int32_t divisor = instr->divisor();
+  DCHECK(dividend.is(ToRegister(instr->result())));
+
+  // Theoretically, a variation of the branch-free code for integer division by
+  // a power of 2 (calculating the remainder via an additional multiplication
+  // (which gets simplified to an 'and') and subtraction) should be faster, and
+  // this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to
+  // indicate that positive dividends are heavily favored, so the branching
+  // version performs better.
+  HMod* hmod = instr->hydrogen();
+  int32_t shift = WhichPowerOf2Abs(divisor);
+  Label dividend_is_not_negative, done;
+  if (hmod->CheckFlag(HValue::kLeftCanBeNegative)) {
+    __ cmpwi(dividend, Operand::Zero());
+    __ bge(&dividend_is_not_negative);
+    if (shift) {
+      // Note that this is correct even for kMinInt operands.
+      __ neg(dividend, dividend);
+      __ ExtractBitRange(dividend, dividend, shift - 1, 0);
+      __ neg(dividend, dividend, LeaveOE, SetRC);
+      if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
+        DeoptimizeIf(eq, instr, "minus zero", cr0);
+      }
+    } else if (!hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      __ li(dividend, Operand::Zero());
+    } else {
+      DeoptimizeIf(al, instr, "minus zero");
+    }
+    __ b(&done);
+  }
+
+  __ bind(&dividend_is_not_negative);
+  if (shift) {
+    __ ExtractBitRange(dividend, dividend, shift - 1, 0);
+  } else {
+    __ li(dividend, Operand::Zero());
+  }
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoModByConstI(LModByConstI* instr) {
+  Register dividend = ToRegister(instr->dividend());
+  int32_t divisor = instr->divisor();
+  Register result = ToRegister(instr->result());
+  DCHECK(!dividend.is(result));
+
+  if (divisor == 0) {
+    DeoptimizeIf(al, instr, "division by zero");
+    return;
+  }
+
+  __ TruncatingDiv(result, dividend, Abs(divisor));
+  __ mov(ip, Operand(Abs(divisor)));
+  __ mullw(result, result, ip);
+  __ sub(result, dividend, result, LeaveOE, SetRC);
+
+  // Check for negative zero.
+  HMod* hmod = instr->hydrogen();
+  if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    Label remainder_not_zero;
+    __ bne(&remainder_not_zero, cr0);
+    __ cmpwi(dividend, Operand::Zero());
+    DeoptimizeIf(lt, instr, "minus zero");
+    __ bind(&remainder_not_zero);
+  }
+}
+
+
+void LCodeGen::DoModI(LModI* instr) {
+  HMod* hmod = instr->hydrogen();
+  Register left_reg = ToRegister(instr->left());
+  Register right_reg = ToRegister(instr->right());
+  Register result_reg = ToRegister(instr->result());
+  Register scratch = scratch0();
+  Label done;
+
+  if (hmod->CheckFlag(HValue::kCanOverflow)) {
+    __ li(r0, Operand::Zero());  // clear xer
+    __ mtxer(r0);
+  }
+
+  __ divw(scratch, left_reg, right_reg, SetOE, SetRC);
+
+  // Check for x % 0.
+  if (hmod->CheckFlag(HValue::kCanBeDivByZero)) {
+    __ cmpwi(right_reg, Operand::Zero());
+    DeoptimizeIf(eq, instr, "division by zero");
+  }
+
+  // Check for kMinInt % -1, divw will return undefined, which is not what we
+  // want. We have to deopt if we care about -0, because we can't return that.
+  if (hmod->CheckFlag(HValue::kCanOverflow)) {
+    Label no_overflow_possible;
+    if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      DeoptimizeIf(overflow, instr, "minus zero", cr0);
+    } else {
+      __ bnooverflow(&no_overflow_possible, cr0);
+      __ li(result_reg, Operand::Zero());
+      __ b(&done);
+    }
+    __ bind(&no_overflow_possible);
+  }
+
+  __ mullw(scratch, right_reg, scratch);
+  __ sub(result_reg, left_reg, scratch, LeaveOE, SetRC);
+
+  // If we care about -0, test if the dividend is <0 and the result is 0.
+  if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    __ bne(&done, cr0);
+    __ cmpwi(left_reg, Operand::Zero());
+    DeoptimizeIf(lt, instr, "minus zero");
+  }
+
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
+  Register dividend = ToRegister(instr->dividend());
+  int32_t divisor = instr->divisor();
+  Register result = ToRegister(instr->result());
+  DCHECK(divisor == kMinInt || base::bits::IsPowerOfTwo32(Abs(divisor)));
+  DCHECK(!result.is(dividend));
+
+  // Check for (0 / -x) that will produce negative zero.
+  HDiv* hdiv = instr->hydrogen();
+  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
+    __ cmpwi(dividend, Operand::Zero());
+    DeoptimizeIf(eq, instr, "minus zero");
+  }
+  // Check for (kMinInt / -1).
+  if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) {
+    __ lis(r0, Operand(SIGN_EXT_IMM16(0x8000)));
+    __ cmpw(dividend, r0);
+    DeoptimizeIf(eq, instr, "overflow");
+  }
+
+  int32_t shift = WhichPowerOf2Abs(divisor);
+
+  // Deoptimize if remainder will not be 0.
+  if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) && shift) {
+    __ TestBitRange(dividend, shift - 1, 0, r0);
+    DeoptimizeIf(ne, instr, "lost precision", cr0);
+  }
+
+  if (divisor == -1) {  // Nice shortcut, not needed for correctness.
+    __ neg(result, dividend);
+    return;
+  }
+  if (shift == 0) {
+    __ mr(result, dividend);
+  } else {
+    if (shift == 1) {
+      __ srwi(result, dividend, Operand(31));
+    } else {
+      __ srawi(result, dividend, 31);
+      __ srwi(result, result, Operand(32 - shift));
+    }
+    __ add(result, dividend, result);
+    __ srawi(result, result, shift);
+  }
+  if (divisor < 0) __ neg(result, result);
+}
+
+
+void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
+  Register dividend = ToRegister(instr->dividend());
+  int32_t divisor = instr->divisor();
+  Register result = ToRegister(instr->result());
+  DCHECK(!dividend.is(result));
+
+  if (divisor == 0) {
+    DeoptimizeIf(al, instr, "division by zero");
+    return;
+  }
+
+  // Check for (0 / -x) that will produce negative zero.
+  HDiv* hdiv = instr->hydrogen();
+  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
+    __ cmpwi(dividend, Operand::Zero());
+    DeoptimizeIf(eq, instr, "minus zero");
+  }
+
+  __ TruncatingDiv(result, dividend, Abs(divisor));
+  if (divisor < 0) __ neg(result, result);
+
+  if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
+    Register scratch = scratch0();
+    __ mov(ip, Operand(divisor));
+    __ mullw(scratch, result, ip);
+    __ cmpw(scratch, dividend);
+    DeoptimizeIf(ne, instr, "lost precision");
+  }
+}
+
+
+// TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI.
+void LCodeGen::DoDivI(LDivI* instr) {
+  HBinaryOperation* hdiv = instr->hydrogen();
+  const Register dividend = ToRegister(instr->dividend());
+  const Register divisor = ToRegister(instr->divisor());
+  Register result = ToRegister(instr->result());
+
+  DCHECK(!dividend.is(result));
+  DCHECK(!divisor.is(result));
+
+  if (hdiv->CheckFlag(HValue::kCanOverflow)) {
+    __ li(r0, Operand::Zero());  // clear xer
+    __ mtxer(r0);
+  }
+
+  __ divw(result, dividend, divisor, SetOE, SetRC);
+
+  // Check for x / 0.
+  if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
+    __ cmpwi(divisor, Operand::Zero());
+    DeoptimizeIf(eq, instr, "division by zero");
+  }
+
+  // Check for (0 / -x) that will produce negative zero.
+  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    Label dividend_not_zero;
+    __ cmpwi(dividend, Operand::Zero());
+    __ bne(&dividend_not_zero);
+    __ cmpwi(divisor, Operand::Zero());
+    DeoptimizeIf(lt, instr, "minus zero");
+    __ bind(&dividend_not_zero);
+  }
+
+  // Check for (kMinInt / -1).
+  if (hdiv->CheckFlag(HValue::kCanOverflow)) {
+    Label no_overflow_possible;
+    if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
+      DeoptimizeIf(overflow, instr, "overflow", cr0);
+    } else {
+      // When truncating, we want kMinInt / -1 = kMinInt.
+      __ bnooverflow(&no_overflow_possible, cr0);
+      __ mr(result, dividend);
+    }
+    __ bind(&no_overflow_possible);
+  }
+
+  if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
+    // Deoptimize if remainder is not 0.
+    Register scratch = scratch0();
+    __ mullw(scratch, divisor, result);
+    __ cmpw(dividend, scratch);
+    DeoptimizeIf(ne, instr, "lost precision");
+  }
+}
+
+
+void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
+  HBinaryOperation* hdiv = instr->hydrogen();
+  Register dividend = ToRegister(instr->dividend());
+  Register result = ToRegister(instr->result());
+  int32_t divisor = instr->divisor();
+
+  // If the divisor is positive, things are easy: There can be no deopts and we
+  // can simply do an arithmetic right shift.
+  int32_t shift = WhichPowerOf2Abs(divisor);
+  if (divisor > 0) {
+    if (shift || !result.is(dividend)) {
+      __ srawi(result, dividend, shift);
+    }
+    return;
+  }
+
+  // If the divisor is negative, we have to negate and handle edge cases.
+  OEBit oe = LeaveOE;
+#if V8_TARGET_ARCH_PPC64
+  if (divisor == -1 && hdiv->CheckFlag(HValue::kLeftCanBeMinInt)) {
+    __ lis(r0, Operand(SIGN_EXT_IMM16(0x8000)));
+    __ cmpw(dividend, r0);
+    DeoptimizeIf(eq, instr, "overflow");
+  }
+#else
+  if (hdiv->CheckFlag(HValue::kLeftCanBeMinInt)) {
+    __ li(r0, Operand::Zero());  // clear xer
+    __ mtxer(r0);
+    oe = SetOE;
+  }
+#endif
+
+  __ neg(result, dividend, oe, SetRC);
+  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    DeoptimizeIf(eq, instr, "minus zero", cr0);
+  }
+
+// If the negation could not overflow, simply shifting is OK.
+#if !V8_TARGET_ARCH_PPC64
+  if (!instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
+#endif
+    if (shift) {
+      __ ShiftRightArithImm(result, result, shift);
+    }
+    return;
+#if !V8_TARGET_ARCH_PPC64
+  }
+
+  // Dividing by -1 is basically negation, unless we overflow.
+  if (divisor == -1) {
+    DeoptimizeIf(overflow, instr, "overflow", cr0);
+    return;
+  }
+
+  Label overflow, done;
+  __ boverflow(&overflow, cr0);
+  __ srawi(result, result, shift);
+  __ b(&done);
+  __ bind(&overflow);
+  __ mov(result, Operand(kMinInt / divisor));
+  __ bind(&done);
+#endif
+}
+
+
+void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
+  Register dividend = ToRegister(instr->dividend());
+  int32_t divisor = instr->divisor();
+  Register result = ToRegister(instr->result());
+  DCHECK(!dividend.is(result));
+
+  if (divisor == 0) {
+    DeoptimizeIf(al, instr, "division by zero");
+    return;
+  }
+
+  // Check for (0 / -x) that will produce negative zero.
+  HMathFloorOfDiv* hdiv = instr->hydrogen();
+  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
+    __ cmpwi(dividend, Operand::Zero());
+    DeoptimizeIf(eq, instr, "minus zero");
+  }
+
+  // Easy case: We need no dynamic check for the dividend and the flooring
+  // division is the same as the truncating division.
+  if ((divisor > 0 && !hdiv->CheckFlag(HValue::kLeftCanBeNegative)) ||
+      (divisor < 0 && !hdiv->CheckFlag(HValue::kLeftCanBePositive))) {
+    __ TruncatingDiv(result, dividend, Abs(divisor));
+    if (divisor < 0) __ neg(result, result);
+    return;
+  }
+
+  // In the general case we may need to adjust before and after the truncating
+  // division to get a flooring division.
+  Register temp = ToRegister(instr->temp());
+  DCHECK(!temp.is(dividend) && !temp.is(result));
+  Label needs_adjustment, done;
+  __ cmpwi(dividend, Operand::Zero());
+  __ b(divisor > 0 ? lt : gt, &needs_adjustment);
+  __ TruncatingDiv(result, dividend, Abs(divisor));
+  if (divisor < 0) __ neg(result, result);
+  __ b(&done);
+  __ bind(&needs_adjustment);
+  __ addi(temp, dividend, Operand(divisor > 0 ? 1 : -1));
+  __ TruncatingDiv(result, temp, Abs(divisor));
+  if (divisor < 0) __ neg(result, result);
+  __ subi(result, result, Operand(1));
+  __ bind(&done);
+}
+
+
+// TODO(svenpanne) Refactor this to avoid code duplication with DoDivI.
+void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
+  HBinaryOperation* hdiv = instr->hydrogen();
+  const Register dividend = ToRegister(instr->dividend());
+  const Register divisor = ToRegister(instr->divisor());
+  Register result = ToRegister(instr->result());
+
+  DCHECK(!dividend.is(result));
+  DCHECK(!divisor.is(result));
+
+  if (hdiv->CheckFlag(HValue::kCanOverflow)) {
+    __ li(r0, Operand::Zero());  // clear xer
+    __ mtxer(r0);
+  }
+
+  __ divw(result, dividend, divisor, SetOE, SetRC);
+
+  // Check for x / 0.
+  if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
+    __ cmpwi(divisor, Operand::Zero());
+    DeoptimizeIf(eq, instr, "division by zero");
+  }
+
+  // Check for (0 / -x) that will produce negative zero.
+  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    Label dividend_not_zero;
+    __ cmpwi(dividend, Operand::Zero());
+    __ bne(&dividend_not_zero);
+    __ cmpwi(divisor, Operand::Zero());
+    DeoptimizeIf(lt, instr, "minus zero");
+    __ bind(&dividend_not_zero);
+  }
+
+  // Check for (kMinInt / -1).
+  if (hdiv->CheckFlag(HValue::kCanOverflow)) {
+    Label no_overflow_possible;
+    if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
+      DeoptimizeIf(overflow, instr, "overflow", cr0);
+    } else {
+      // When truncating, we want kMinInt / -1 = kMinInt.
+      __ bnooverflow(&no_overflow_possible, cr0);
+      __ mr(result, dividend);
+    }
+    __ bind(&no_overflow_possible);
+  }
+
+  Label done;
+  Register scratch = scratch0();
+// If both operands have the same sign then we are done.
+#if V8_TARGET_ARCH_PPC64
+  __ xor_(scratch, dividend, divisor);
+  __ cmpwi(scratch, Operand::Zero());
+  __ bge(&done);
+#else
+  __ xor_(scratch, dividend, divisor, SetRC);
+  __ bge(&done, cr0);
+#endif
+
+  // If there is no remainder then we are done.
+  __ mullw(scratch, divisor, result);
+  __ cmpw(dividend, scratch);
+  __ beq(&done);
+
+  // We performed a truncating division. Correct the result.
+  __ subi(result, result, Operand(1));
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) {
+  DoubleRegister addend = ToDoubleRegister(instr->addend());
+  DoubleRegister multiplier = ToDoubleRegister(instr->multiplier());
+  DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+
+  __ fmadd(result, multiplier, multiplicand, addend);
+}
+
+
+void LCodeGen::DoMultiplySubD(LMultiplySubD* instr) {
+  DoubleRegister minuend = ToDoubleRegister(instr->minuend());
+  DoubleRegister multiplier = ToDoubleRegister(instr->multiplier());
+  DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+
+  __ fmsub(result, multiplier, multiplicand, minuend);
+}
+
+
+void LCodeGen::DoMulI(LMulI* instr) {
+  Register scratch = scratch0();
+  Register result = ToRegister(instr->result());
+  // Note that result may alias left.
+  Register left = ToRegister(instr->left());
+  LOperand* right_op = instr->right();
+
+  bool bailout_on_minus_zero =
+      instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
+  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+
+  if (right_op->IsConstantOperand()) {
+    int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
+
+    if (bailout_on_minus_zero && (constant < 0)) {
+      // The case of a null constant will be handled separately.
+      // If constant is negative and left is null, the result should be -0.
+      __ cmpi(left, Operand::Zero());
+      DeoptimizeIf(eq, instr, "minus zero");
+    }
+
+    switch (constant) {
+      case -1:
+        if (can_overflow) {
+#if V8_TARGET_ARCH_PPC64
+          if (instr->hydrogen()->representation().IsSmi()) {
+#endif
+            __ li(r0, Operand::Zero());  // clear xer
+            __ mtxer(r0);
+            __ neg(result, left, SetOE, SetRC);
+            DeoptimizeIf(overflow, instr, "overflow", cr0);
+#if V8_TARGET_ARCH_PPC64
+          } else {
+            __ neg(result, left);
+            __ TestIfInt32(result, scratch, r0);
+            DeoptimizeIf(ne, instr, "overflow");
+          }
+#endif
+        } else {
+          __ neg(result, left);
+        }
+        break;
+      case 0:
+        if (bailout_on_minus_zero) {
+// If left is strictly negative and the constant is null, the
+// result is -0. Deoptimize if required, otherwise return 0.
+#if V8_TARGET_ARCH_PPC64
+          if (instr->hydrogen()->representation().IsSmi()) {
+#endif
+            __ cmpi(left, Operand::Zero());
+#if V8_TARGET_ARCH_PPC64
+          } else {
+            __ cmpwi(left, Operand::Zero());
+          }
+#endif
+          DeoptimizeIf(lt, instr, "minus zero");
+        }
+        __ li(result, Operand::Zero());
+        break;
+      case 1:
+        __ Move(result, left);
+        break;
+      default:
+        // Multiplying by powers of two and powers of two plus or minus
+        // one can be done faster with shifted operands.
+        // For other constants we emit standard code.
+        int32_t mask = constant >> 31;
+        uint32_t constant_abs = (constant + mask) ^ mask;
+
+        if (base::bits::IsPowerOfTwo32(constant_abs)) {
+          int32_t shift = WhichPowerOf2(constant_abs);
+          __ ShiftLeftImm(result, left, Operand(shift));
+          // Correct the sign of the result if the constant is negative.
+          if (constant < 0) __ neg(result, result);
+        } else if (base::bits::IsPowerOfTwo32(constant_abs - 1)) {
+          int32_t shift = WhichPowerOf2(constant_abs - 1);
+          __ ShiftLeftImm(scratch, left, Operand(shift));
+          __ add(result, scratch, left);
+          // Correct the sign of the result if the constant is negative.
+          if (constant < 0) __ neg(result, result);
+        } else if (base::bits::IsPowerOfTwo32(constant_abs + 1)) {
+          int32_t shift = WhichPowerOf2(constant_abs + 1);
+          __ ShiftLeftImm(scratch, left, Operand(shift));
+          __ sub(result, scratch, left);
+          // Correct the sign of the result if the constant is negative.
+          if (constant < 0) __ neg(result, result);
+        } else {
+          // Generate standard code.
+          __ mov(ip, Operand(constant));
+          __ Mul(result, left, ip);
+        }
+    }
+
+  } else {
+    DCHECK(right_op->IsRegister());
+    Register right = ToRegister(right_op);
+
+    if (can_overflow) {
+#if V8_TARGET_ARCH_PPC64
+      // result = left * right.
+      if (instr->hydrogen()->representation().IsSmi()) {
+        __ SmiUntag(result, left);
+        __ SmiUntag(scratch, right);
+        __ Mul(result, result, scratch);
+      } else {
+        __ Mul(result, left, right);
+      }
+      __ TestIfInt32(result, scratch, r0);
+      DeoptimizeIf(ne, instr, "overflow");
+      if (instr->hydrogen()->representation().IsSmi()) {
+        __ SmiTag(result);
+      }
+#else
+      // scratch:result = left * right.
+      if (instr->hydrogen()->representation().IsSmi()) {
+        __ SmiUntag(result, left);
+        __ mulhw(scratch, result, right);
+        __ mullw(result, result, right);
+      } else {
+        __ mulhw(scratch, left, right);
+        __ mullw(result, left, right);
+      }
+      __ TestIfInt32(scratch, result, r0);
+      DeoptimizeIf(ne, instr, "overflow");
+#endif
+    } else {
+      if (instr->hydrogen()->representation().IsSmi()) {
+        __ SmiUntag(result, left);
+        __ Mul(result, result, right);
+      } else {
+        __ Mul(result, left, right);
+      }
+    }
+
+    if (bailout_on_minus_zero) {
+      Label done;
+#if V8_TARGET_ARCH_PPC64
+      if (instr->hydrogen()->representation().IsSmi()) {
+#endif
+        __ xor_(r0, left, right, SetRC);
+        __ bge(&done, cr0);
+#if V8_TARGET_ARCH_PPC64
+      } else {
+        __ xor_(r0, left, right);
+        __ cmpwi(r0, Operand::Zero());
+        __ bge(&done);
+      }
+#endif
+      // Bail out if the result is minus zero.
+      __ cmpi(result, Operand::Zero());
+      DeoptimizeIf(eq, instr, "minus zero");
+      __ bind(&done);
+    }
+  }
+}
+
+
+void LCodeGen::DoBitI(LBitI* instr) {
+  LOperand* left_op = instr->left();
+  LOperand* right_op = instr->right();
+  DCHECK(left_op->IsRegister());
+  Register left = ToRegister(left_op);
+  Register result = ToRegister(instr->result());
+  Operand right(no_reg);
+
+  if (right_op->IsStackSlot()) {
+    right = Operand(EmitLoadRegister(right_op, ip));
+  } else {
+    DCHECK(right_op->IsRegister() || right_op->IsConstantOperand());
+    right = ToOperand(right_op);
+
+    if (right_op->IsConstantOperand() && is_uint16(right.immediate())) {
+      switch (instr->op()) {
+        case Token::BIT_AND:
+          __ andi(result, left, right);
+          break;
+        case Token::BIT_OR:
+          __ ori(result, left, right);
+          break;
+        case Token::BIT_XOR:
+          __ xori(result, left, right);
+          break;
+        default:
+          UNREACHABLE();
+          break;
+      }
+      return;
+    }
+  }
+
+  switch (instr->op()) {
+    case Token::BIT_AND:
+      __ And(result, left, right);
+      break;
+    case Token::BIT_OR:
+      __ Or(result, left, right);
+      break;
+    case Token::BIT_XOR:
+      if (right_op->IsConstantOperand() && right.immediate() == int32_t(~0)) {
+        __ notx(result, left);
+      } else {
+        __ Xor(result, left, right);
+      }
+      break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+}
+
+
+void LCodeGen::DoShiftI(LShiftI* instr) {
+  // Both 'left' and 'right' are "used at start" (see LCodeGen::DoShift), so
+  // result may alias either of them.
+  LOperand* right_op = instr->right();
+  Register left = ToRegister(instr->left());
+  Register result = ToRegister(instr->result());
+  Register scratch = scratch0();
+  if (right_op->IsRegister()) {
+    // Mask the right_op operand.
+    __ andi(scratch, ToRegister(right_op), Operand(0x1F));
+    switch (instr->op()) {
+      case Token::ROR:
+        // rotate_right(a, b) == rotate_left(a, 32 - b)
+        __ subfic(scratch, scratch, Operand(32));
+        __ rotlw(result, left, scratch);
+        break;
+      case Token::SAR:
+        __ sraw(result, left, scratch);
+        break;
+      case Token::SHR:
+        if (instr->can_deopt()) {
+          __ srw(result, left, scratch, SetRC);
+#if V8_TARGET_ARCH_PPC64
+          __ extsw(result, result, SetRC);
+#endif
+          DeoptimizeIf(lt, instr, "negative value", cr0);
+        } else {
+          __ srw(result, left, scratch);
+        }
+        break;
+      case Token::SHL:
+        __ slw(result, left, scratch);
+#if V8_TARGET_ARCH_PPC64
+        __ extsw(result, result);
+#endif
+        break;
+      default:
+        UNREACHABLE();
+        break;
+    }
+  } else {
+    // Mask the right_op operand.
+    int value = ToInteger32(LConstantOperand::cast(right_op));
+    uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
+    switch (instr->op()) {
+      case Token::ROR:
+        if (shift_count != 0) {
+          __ rotrwi(result, left, shift_count);
+        } else {
+          __ Move(result, left);
+        }
+        break;
+      case Token::SAR:
+        if (shift_count != 0) {
+          __ srawi(result, left, shift_count);
+        } else {
+          __ Move(result, left);
+        }
+        break;
+      case Token::SHR:
+        if (shift_count != 0) {
+          __ srwi(result, left, Operand(shift_count));
+        } else {
+          if (instr->can_deopt()) {
+            __ cmpwi(left, Operand::Zero());
+            DeoptimizeIf(lt, instr, "negative value");
+          }
+          __ Move(result, left);
+        }
+        break;
+      case Token::SHL:
+        if (shift_count != 0) {
+#if V8_TARGET_ARCH_PPC64
+          if (instr->hydrogen_value()->representation().IsSmi()) {
+            __ sldi(result, left, Operand(shift_count));
+#else
+          if (instr->hydrogen_value()->representation().IsSmi() &&
+              instr->can_deopt()) {
+            if (shift_count != 1) {
+              __ slwi(result, left, Operand(shift_count - 1));
+              __ SmiTagCheckOverflow(result, result, scratch);
+            } else {
+              __ SmiTagCheckOverflow(result, left, scratch);
+            }
+            DeoptimizeIf(lt, instr, "overflow", cr0);
+#endif
+          } else {
+            __ slwi(result, left, Operand(shift_count));
+#if V8_TARGET_ARCH_PPC64
+            __ extsw(result, result);
+#endif
+          }
+        } else {
+          __ Move(result, left);
+        }
+        break;
+      default:
+        UNREACHABLE();
+        break;
+    }
+  }
+}
+
+
+void LCodeGen::DoSubI(LSubI* instr) {
+  LOperand* right = instr->right();
+  Register left = ToRegister(instr->left());
+  Register result = ToRegister(instr->result());
+  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+  if (!can_overflow) {
+    if (right->IsConstantOperand()) {
+      __ Add(result, left, -(ToOperand(right).immediate()), r0);
+    } else {
+      __ sub(result, left, EmitLoadRegister(right, ip));
+    }
+  } else {
+    if (right->IsConstantOperand()) {
+      __ AddAndCheckForOverflow(result, left, -(ToOperand(right).immediate()),
+                                scratch0(), r0);
+    } else {
+      __ SubAndCheckForOverflow(result, left, EmitLoadRegister(right, ip),
+                                scratch0(), r0);
+    }
+// Doptimize on overflow
+#if V8_TARGET_ARCH_PPC64
+    if (!instr->hydrogen()->representation().IsSmi()) {
+      __ extsw(scratch0(), scratch0(), SetRC);
+    }
+#endif
+    DeoptimizeIf(lt, instr, "overflow", cr0);
+  }
+
+#if V8_TARGET_ARCH_PPC64
+  if (!instr->hydrogen()->representation().IsSmi()) {
+    __ extsw(result, result);
+  }
+#endif
+}
+
+
+void LCodeGen::DoRSubI(LRSubI* instr) {
+  LOperand* left = instr->left();
+  LOperand* right = instr->right();
+  LOperand* result = instr->result();
+
+  DCHECK(!instr->hydrogen()->CheckFlag(HValue::kCanOverflow) &&
+         right->IsConstantOperand());
+
+  Operand right_operand = ToOperand(right);
+  if (is_int16(right_operand.immediate())) {
+    __ subfic(ToRegister(result), ToRegister(left), right_operand);
+  } else {
+    __ mov(r0, right_operand);
+    __ sub(ToRegister(result), r0, ToRegister(left));
+  }
+}
+
+
+void LCodeGen::DoConstantI(LConstantI* instr) {
+  __ mov(ToRegister(instr->result()), Operand(instr->value()));
+}
+
+
+void LCodeGen::DoConstantS(LConstantS* instr) {
+  __ LoadSmiLiteral(ToRegister(instr->result()), instr->value());
+}
+
+
+// TODO(penguin): put const to constant pool instead
+// of storing double to stack
+void LCodeGen::DoConstantD(LConstantD* instr) {
+  DCHECK(instr->result()->IsDoubleRegister());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  double v = instr->value();
+  __ LoadDoubleLiteral(result, v, scratch0());
+}
+
+
+void LCodeGen::DoConstantE(LConstantE* instr) {
+  __ mov(ToRegister(instr->result()), Operand(instr->value()));
+}
+
+
+void LCodeGen::DoConstantT(LConstantT* instr) {
+  Handle<Object> object = instr->value(isolate());
+  AllowDeferredHandleDereference smi_check;
+  __ Move(ToRegister(instr->result()), object);
+}
+
+
+void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
+  Register result = ToRegister(instr->result());
+  Register map = ToRegister(instr->value());
+  __ EnumLength(result, map);
+}
+
+
+void LCodeGen::DoDateField(LDateField* instr) {
+  Register object = ToRegister(instr->date());
+  Register result = ToRegister(instr->result());
+  Register scratch = ToRegister(instr->temp());
+  Smi* index = instr->index();
+  Label runtime, done;
+  DCHECK(object.is(result));
+  DCHECK(object.is(r3));
+  DCHECK(!scratch.is(scratch0()));
+  DCHECK(!scratch.is(object));
+
+  __ TestIfSmi(object, r0);
+  DeoptimizeIf(eq, instr, "Smi", cr0);
+  __ CompareObjectType(object, scratch, scratch, JS_DATE_TYPE);
+  DeoptimizeIf(ne, instr, "not a date object");
+
+  if (index->value() == 0) {
+    __ LoadP(result, FieldMemOperand(object, JSDate::kValueOffset));
+  } else {
+    if (index->value() < JSDate::kFirstUncachedField) {
+      ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
+      __ mov(scratch, Operand(stamp));
+      __ LoadP(scratch, MemOperand(scratch));
+      __ LoadP(scratch0(), FieldMemOperand(object, JSDate::kCacheStampOffset));
+      __ cmp(scratch, scratch0());
+      __ bne(&runtime);
+      __ LoadP(result,
+               FieldMemOperand(object, JSDate::kValueOffset +
+                                           kPointerSize * index->value()));
+      __ b(&done);
+    }
+    __ bind(&runtime);
+    __ PrepareCallCFunction(2, scratch);
+    __ LoadSmiLiteral(r4, index);
+    __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
+    __ bind(&done);
+  }
+}
+
+
+MemOperand LCodeGen::BuildSeqStringOperand(Register string, LOperand* index,
+                                           String::Encoding encoding) {
+  if (index->IsConstantOperand()) {
+    int offset = ToInteger32(LConstantOperand::cast(index));
+    if (encoding == String::TWO_BYTE_ENCODING) {
+      offset *= kUC16Size;
+    }
+    STATIC_ASSERT(kCharSize == 1);
+    return FieldMemOperand(string, SeqString::kHeaderSize + offset);
+  }
+  Register scratch = scratch0();
+  DCHECK(!scratch.is(string));
+  DCHECK(!scratch.is(ToRegister(index)));
+  if (encoding == String::ONE_BYTE_ENCODING) {
+    __ add(scratch, string, ToRegister(index));
+  } else {
+    STATIC_ASSERT(kUC16Size == 2);
+    __ ShiftLeftImm(scratch, ToRegister(index), Operand(1));
+    __ add(scratch, string, scratch);
+  }
+  return FieldMemOperand(scratch, SeqString::kHeaderSize);
+}
+
+
+void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
+  String::Encoding encoding = instr->hydrogen()->encoding();
+  Register string = ToRegister(instr->string());
+  Register result = ToRegister(instr->result());
+
+  if (FLAG_debug_code) {
+    Register scratch = scratch0();
+    __ LoadP(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
+    __ lbz(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+
+    __ andi(scratch, scratch,
+            Operand(kStringRepresentationMask | kStringEncodingMask));
+    static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+    static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+    __ cmpi(scratch,
+            Operand(encoding == String::ONE_BYTE_ENCODING ? one_byte_seq_type
+                                                          : two_byte_seq_type));
+    __ Check(eq, kUnexpectedStringType);
+  }
+
+  MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
+  if (encoding == String::ONE_BYTE_ENCODING) {
+    __ lbz(result, operand);
+  } else {
+    __ lhz(result, operand);
+  }
+}
+
+
+void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
+  String::Encoding encoding = instr->hydrogen()->encoding();
+  Register string = ToRegister(instr->string());
+  Register value = ToRegister(instr->value());
+
+  if (FLAG_debug_code) {
+    Register index = ToRegister(instr->index());
+    static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+    static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+    int encoding_mask =
+        instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
+            ? one_byte_seq_type
+            : two_byte_seq_type;
+    __ EmitSeqStringSetCharCheck(string, index, value, encoding_mask);
+  }
+
+  MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
+  if (encoding == String::ONE_BYTE_ENCODING) {
+    __ stb(value, operand);
+  } else {
+    __ sth(value, operand);
+  }
+}
+
+
+void LCodeGen::DoAddI(LAddI* instr) {
+  LOperand* right = instr->right();
+  Register left = ToRegister(instr->left());
+  Register result = ToRegister(instr->result());
+  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+#if V8_TARGET_ARCH_PPC64
+  bool isInteger = !(instr->hydrogen()->representation().IsSmi() ||
+                     instr->hydrogen()->representation().IsExternal());
+#endif
+
+  if (!can_overflow) {
+    if (right->IsConstantOperand()) {
+      __ Add(result, left, ToOperand(right).immediate(), r0);
+    } else {
+      __ add(result, left, EmitLoadRegister(right, ip));
+    }
+  } else {
+    if (right->IsConstantOperand()) {
+      __ AddAndCheckForOverflow(result, left, ToOperand(right).immediate(),
+                                scratch0(), r0);
+    } else {
+      __ AddAndCheckForOverflow(result, left, EmitLoadRegister(right, ip),
+                                scratch0(), r0);
+    }
+// Doptimize on overflow
+#if V8_TARGET_ARCH_PPC64
+    if (isInteger) {
+      __ extsw(scratch0(), scratch0(), SetRC);
+    }
+#endif
+    DeoptimizeIf(lt, instr, "overflow", cr0);
+  }
+
+#if V8_TARGET_ARCH_PPC64
+  if (isInteger) {
+    __ extsw(result, result);
+  }
+#endif
+}
+
+
+void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
+  LOperand* left = instr->left();
+  LOperand* right = instr->right();
+  HMathMinMax::Operation operation = instr->hydrogen()->operation();
+  Condition cond = (operation == HMathMinMax::kMathMin) ? le : ge;
+  if (instr->hydrogen()->representation().IsSmiOrInteger32()) {
+    Register left_reg = ToRegister(left);
+    Register right_reg = EmitLoadRegister(right, ip);
+    Register result_reg = ToRegister(instr->result());
+    Label return_left, done;
+#if V8_TARGET_ARCH_PPC64
+    if (instr->hydrogen_value()->representation().IsSmi()) {
+#endif
+      __ cmp(left_reg, right_reg);
+#if V8_TARGET_ARCH_PPC64
+    } else {
+      __ cmpw(left_reg, right_reg);
+    }
+#endif
+    __ b(cond, &return_left);
+    __ Move(result_reg, right_reg);
+    __ b(&done);
+    __ bind(&return_left);
+    __ Move(result_reg, left_reg);
+    __ bind(&done);
+  } else {
+    DCHECK(instr->hydrogen()->representation().IsDouble());
+    DoubleRegister left_reg = ToDoubleRegister(left);
+    DoubleRegister right_reg = ToDoubleRegister(right);
+    DoubleRegister result_reg = ToDoubleRegister(instr->result());
+    Label check_nan_left, check_zero, return_left, return_right, done;
+    __ fcmpu(left_reg, right_reg);
+    __ bunordered(&check_nan_left);
+    __ beq(&check_zero);
+    __ b(cond, &return_left);
+    __ b(&return_right);
+
+    __ bind(&check_zero);
+    __ fcmpu(left_reg, kDoubleRegZero);
+    __ bne(&return_left);  // left == right != 0.
+
+    // At this point, both left and right are either 0 or -0.
+    // N.B. The following works because +0 + -0 == +0
+    if (operation == HMathMinMax::kMathMin) {
+      // For min we want logical-or of sign bit: -(-L + -R)
+      __ fneg(left_reg, left_reg);
+      __ fsub(result_reg, left_reg, right_reg);
+      __ fneg(result_reg, result_reg);
+    } else {
+      // For max we want logical-and of sign bit: (L + R)
+      __ fadd(result_reg, left_reg, right_reg);
+    }
+    __ b(&done);
+
+    __ bind(&check_nan_left);
+    __ fcmpu(left_reg, left_reg);
+    __ bunordered(&return_left);  // left == NaN.
+
+    __ bind(&return_right);
+    if (!right_reg.is(result_reg)) {
+      __ fmr(result_reg, right_reg);
+    }
+    __ b(&done);
+
+    __ bind(&return_left);
+    if (!left_reg.is(result_reg)) {
+      __ fmr(result_reg, left_reg);
+    }
+    __ bind(&done);
+  }
+}
+
+
+void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
+  DoubleRegister left = ToDoubleRegister(instr->left());
+  DoubleRegister right = ToDoubleRegister(instr->right());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  switch (instr->op()) {
+    case Token::ADD:
+      __ fadd(result, left, right);
+      break;
+    case Token::SUB:
+      __ fsub(result, left, right);
+      break;
+    case Token::MUL:
+      __ fmul(result, left, right);
+      break;
+    case Token::DIV:
+      __ fdiv(result, left, right);
+      break;
+    case Token::MOD: {
+      __ PrepareCallCFunction(0, 2, scratch0());
+      __ MovToFloatParameters(left, right);
+      __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
+                       0, 2);
+      // Move the result in the double result register.
+      __ MovFromFloatResult(result);
+      break;
+    }
+    default:
+      UNREACHABLE();
+      break;
+  }
+}
+
+
+void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->left()).is(r4));
+  DCHECK(ToRegister(instr->right()).is(r3));
+  DCHECK(ToRegister(instr->result()).is(r3));
+
+  Handle<Code> code =
+      CodeFactory::BinaryOpIC(isolate(), instr->op(), NO_OVERWRITE).code();
+  CallCode(code, RelocInfo::CODE_TARGET, instr);
+}
+
+
+template <class InstrType>
+void LCodeGen::EmitBranch(InstrType instr, Condition cond, CRegister cr) {
+  int left_block = instr->TrueDestination(chunk_);
+  int right_block = instr->FalseDestination(chunk_);
+
+  int next_block = GetNextEmittedBlock();
+
+  if (right_block == left_block || cond == al) {
+    EmitGoto(left_block);
+  } else if (left_block == next_block) {
+    __ b(NegateCondition(cond), chunk_->GetAssemblyLabel(right_block), cr);
+  } else if (right_block == next_block) {
+    __ b(cond, chunk_->GetAssemblyLabel(left_block), cr);
+  } else {
+    __ b(cond, chunk_->GetAssemblyLabel(left_block), cr);
+    __ b(chunk_->GetAssemblyLabel(right_block));
+  }
+}
+
+
+template <class InstrType>
+void LCodeGen::EmitFalseBranch(InstrType instr, Condition cond, CRegister cr) {
+  int false_block = instr->FalseDestination(chunk_);
+  __ b(cond, chunk_->GetAssemblyLabel(false_block), cr);
+}
+
+
+void LCodeGen::DoDebugBreak(LDebugBreak* instr) { __ stop("LBreak"); }
+
+
+void LCodeGen::DoBranch(LBranch* instr) {
+  Representation r = instr->hydrogen()->value()->representation();
+  DoubleRegister dbl_scratch = double_scratch0();
+  const uint crZOrNaNBits = (1 << (31 - Assembler::encode_crbit(cr7, CR_EQ)) |
+                             1 << (31 - Assembler::encode_crbit(cr7, CR_FU)));
+
+  if (r.IsInteger32()) {
+    DCHECK(!info()->IsStub());
+    Register reg = ToRegister(instr->value());
+    __ cmpwi(reg, Operand::Zero());
+    EmitBranch(instr, ne);
+  } else if (r.IsSmi()) {
+    DCHECK(!info()->IsStub());
+    Register reg = ToRegister(instr->value());
+    __ cmpi(reg, Operand::Zero());
+    EmitBranch(instr, ne);
+  } else if (r.IsDouble()) {
+    DCHECK(!info()->IsStub());
+    DoubleRegister reg = ToDoubleRegister(instr->value());
+    // Test the double value. Zero and NaN are false.
+    __ fcmpu(reg, kDoubleRegZero, cr7);
+    __ mfcr(r0);
+    __ andi(r0, r0, Operand(crZOrNaNBits));
+    EmitBranch(instr, eq, cr0);
+  } else {
+    DCHECK(r.IsTagged());
+    Register reg = ToRegister(instr->value());
+    HType type = instr->hydrogen()->value()->type();
+    if (type.IsBoolean()) {
+      DCHECK(!info()->IsStub());
+      __ CompareRoot(reg, Heap::kTrueValueRootIndex);
+      EmitBranch(instr, eq);
+    } else if (type.IsSmi()) {
+      DCHECK(!info()->IsStub());
+      __ cmpi(reg, Operand::Zero());
+      EmitBranch(instr, ne);
+    } else if (type.IsJSArray()) {
+      DCHECK(!info()->IsStub());
+      EmitBranch(instr, al);
+    } else if (type.IsHeapNumber()) {
+      DCHECK(!info()->IsStub());
+      __ lfd(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset));
+      // Test the double value. Zero and NaN are false.
+      __ fcmpu(dbl_scratch, kDoubleRegZero, cr7);
+      __ mfcr(r0);
+      __ andi(r0, r0, Operand(crZOrNaNBits));
+      EmitBranch(instr, eq, cr0);
+    } else if (type.IsString()) {
+      DCHECK(!info()->IsStub());
+      __ LoadP(ip, FieldMemOperand(reg, String::kLengthOffset));
+      __ cmpi(ip, Operand::Zero());
+      EmitBranch(instr, ne);
+    } else {
+      ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
+      // Avoid deopts in the case where we've never executed this path before.
+      if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
+
+      if (expected.Contains(ToBooleanStub::UNDEFINED)) {
+        // undefined -> false.
+        __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
+        __ beq(instr->FalseLabel(chunk_));
+      }
+      if (expected.Contains(ToBooleanStub::BOOLEAN)) {
+        // Boolean -> its value.
+        __ CompareRoot(reg, Heap::kTrueValueRootIndex);
+        __ beq(instr->TrueLabel(chunk_));
+        __ CompareRoot(reg, Heap::kFalseValueRootIndex);
+        __ beq(instr->FalseLabel(chunk_));
+      }
+      if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
+        // 'null' -> false.
+        __ CompareRoot(reg, Heap::kNullValueRootIndex);
+        __ beq(instr->FalseLabel(chunk_));
+      }
+
+      if (expected.Contains(ToBooleanStub::SMI)) {
+        // Smis: 0 -> false, all other -> true.
+        __ cmpi(reg, Operand::Zero());
+        __ beq(instr->FalseLabel(chunk_));
+        __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
+      } else if (expected.NeedsMap()) {
+        // If we need a map later and have a Smi -> deopt.
+        __ TestIfSmi(reg, r0);
+        DeoptimizeIf(eq, instr, "Smi", cr0);
+      }
+
+      const Register map = scratch0();
+      if (expected.NeedsMap()) {
+        __ LoadP(map, FieldMemOperand(reg, HeapObject::kMapOffset));
+
+        if (expected.CanBeUndetectable()) {
+          // Undetectable -> false.
+          __ lbz(ip, FieldMemOperand(map, Map::kBitFieldOffset));
+          __ TestBit(ip, Map::kIsUndetectable, r0);
+          __ bne(instr->FalseLabel(chunk_), cr0);
+        }
+      }
+
+      if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
+        // spec object -> true.
+        __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
+        __ bge(instr->TrueLabel(chunk_));
+      }
+
+      if (expected.Contains(ToBooleanStub::STRING)) {
+        // String value -> false iff empty.
+        Label not_string;
+        __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
+        __ bge(&not_string);
+        __ LoadP(ip, FieldMemOperand(reg, String::kLengthOffset));
+        __ cmpi(ip, Operand::Zero());
+        __ bne(instr->TrueLabel(chunk_));
+        __ b(instr->FalseLabel(chunk_));
+        __ bind(&not_string);
+      }
+
+      if (expected.Contains(ToBooleanStub::SYMBOL)) {
+        // Symbol value -> true.
+        __ CompareInstanceType(map, ip, SYMBOL_TYPE);
+        __ beq(instr->TrueLabel(chunk_));
+      }
+
+      if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
+        // heap number -> false iff +0, -0, or NaN.
+        Label not_heap_number;
+        __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
+        __ bne(&not_heap_number);
+        __ lfd(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset));
+        // Test the double value. Zero and NaN are false.
+        __ fcmpu(dbl_scratch, kDoubleRegZero, cr7);
+        __ mfcr(r0);
+        __ andi(r0, r0, Operand(crZOrNaNBits));
+        __ bne(instr->FalseLabel(chunk_), cr0);
+        __ b(instr->TrueLabel(chunk_));
+        __ bind(&not_heap_number);
+      }
+
+      if (!expected.IsGeneric()) {
+        // We've seen something for the first time -> deopt.
+        // This can only happen if we are not generic already.
+        DeoptimizeIf(al, instr, "unexpected object");
+      }
+    }
+  }
+}
+
+
+void LCodeGen::EmitGoto(int block) {
+  if (!IsNextEmittedBlock(block)) {
+    __ b(chunk_->GetAssemblyLabel(LookupDestination(block)));
+  }
+}
+
+
+void LCodeGen::DoGoto(LGoto* instr) { EmitGoto(instr->block_id()); }
+
+
+Condition LCodeGen::TokenToCondition(Token::Value op) {
+  Condition cond = kNoCondition;
+  switch (op) {
+    case Token::EQ:
+    case Token::EQ_STRICT:
+      cond = eq;
+      break;
+    case Token::NE:
+    case Token::NE_STRICT:
+      cond = ne;
+      break;
+    case Token::LT:
+      cond = lt;
+      break;
+    case Token::GT:
+      cond = gt;
+      break;
+    case Token::LTE:
+      cond = le;
+      break;
+    case Token::GTE:
+      cond = ge;
+      break;
+    case Token::IN:
+    case Token::INSTANCEOF:
+    default:
+      UNREACHABLE();
+  }
+  return cond;
+}
+
+
+void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
+  LOperand* left = instr->left();
+  LOperand* right = instr->right();
+  bool is_unsigned =
+      instr->hydrogen()->left()->CheckFlag(HInstruction::kUint32) ||
+      instr->hydrogen()->right()->CheckFlag(HInstruction::kUint32);
+  Condition cond = TokenToCondition(instr->op());
+
+  if (left->IsConstantOperand() && right->IsConstantOperand()) {
+    // We can statically evaluate the comparison.
+    double left_val = ToDouble(LConstantOperand::cast(left));
+    double right_val = ToDouble(LConstantOperand::cast(right));
+    int next_block = EvalComparison(instr->op(), left_val, right_val)
+                         ? instr->TrueDestination(chunk_)
+                         : instr->FalseDestination(chunk_);
+    EmitGoto(next_block);
+  } else {
+    if (instr->is_double()) {
+      // Compare left and right operands as doubles and load the
+      // resulting flags into the normal status register.
+      __ fcmpu(ToDoubleRegister(left), ToDoubleRegister(right));
+      // If a NaN is involved, i.e. the result is unordered,
+      // jump to false block label.
+      __ bunordered(instr->FalseLabel(chunk_));
+    } else {
+      if (right->IsConstantOperand()) {
+        int32_t value = ToInteger32(LConstantOperand::cast(right));
+        if (instr->hydrogen_value()->representation().IsSmi()) {
+          if (is_unsigned) {
+            __ CmplSmiLiteral(ToRegister(left), Smi::FromInt(value), r0);
+          } else {
+            __ CmpSmiLiteral(ToRegister(left), Smi::FromInt(value), r0);
+          }
+        } else {
+          if (is_unsigned) {
+            __ Cmplwi(ToRegister(left), Operand(value), r0);
+          } else {
+            __ Cmpwi(ToRegister(left), Operand(value), r0);
+          }
+        }
+      } else if (left->IsConstantOperand()) {
+        int32_t value = ToInteger32(LConstantOperand::cast(left));
+        if (instr->hydrogen_value()->representation().IsSmi()) {
+          if (is_unsigned) {
+            __ CmplSmiLiteral(ToRegister(right), Smi::FromInt(value), r0);
+          } else {
+            __ CmpSmiLiteral(ToRegister(right), Smi::FromInt(value), r0);
+          }
+        } else {
+          if (is_unsigned) {
+            __ Cmplwi(ToRegister(right), Operand(value), r0);
+          } else {
+            __ Cmpwi(ToRegister(right), Operand(value), r0);
+          }
+        }
+        // We commuted the operands, so commute the condition.
+        cond = CommuteCondition(cond);
+      } else if (instr->hydrogen_value()->representation().IsSmi()) {
+        if (is_unsigned) {
+          __ cmpl(ToRegister(left), ToRegister(right));
+        } else {
+          __ cmp(ToRegister(left), ToRegister(right));
+        }
+      } else {
+        if (is_unsigned) {
+          __ cmplw(ToRegister(left), ToRegister(right));
+        } else {
+          __ cmpw(ToRegister(left), ToRegister(right));
+        }
+      }
+    }
+    EmitBranch(instr, cond);
+  }
+}
+
+
+void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
+  Register left = ToRegister(instr->left());
+  Register right = ToRegister(instr->right());
+
+  __ cmp(left, right);
+  EmitBranch(instr, eq);
+}
+
+
+void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
+  if (instr->hydrogen()->representation().IsTagged()) {
+    Register input_reg = ToRegister(instr->object());
+    __ mov(ip, Operand(factory()->the_hole_value()));
+    __ cmp(input_reg, ip);
+    EmitBranch(instr, eq);
+    return;
+  }
+
+  DoubleRegister input_reg = ToDoubleRegister(instr->object());
+  __ fcmpu(input_reg, input_reg);
+  EmitFalseBranch(instr, ordered);
+
+  Register scratch = scratch0();
+  __ MovDoubleHighToInt(scratch, input_reg);
+  __ Cmpi(scratch, Operand(kHoleNanUpper32), r0);
+  EmitBranch(instr, eq);
+}
+
+
+void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
+  Representation rep = instr->hydrogen()->value()->representation();
+  DCHECK(!rep.IsInteger32());
+  Register scratch = ToRegister(instr->temp());
+
+  if (rep.IsDouble()) {
+    DoubleRegister value = ToDoubleRegister(instr->value());
+    __ fcmpu(value, kDoubleRegZero);
+    EmitFalseBranch(instr, ne);
+#if V8_TARGET_ARCH_PPC64
+    __ MovDoubleToInt64(scratch, value);
+#else
+    __ MovDoubleHighToInt(scratch, value);
+#endif
+    __ cmpi(scratch, Operand::Zero());
+    EmitBranch(instr, lt);
+  } else {
+    Register value = ToRegister(instr->value());
+    __ CheckMap(value, scratch, Heap::kHeapNumberMapRootIndex,
+                instr->FalseLabel(chunk()), DO_SMI_CHECK);
+#if V8_TARGET_ARCH_PPC64
+    __ LoadP(scratch, FieldMemOperand(value, HeapNumber::kValueOffset));
+    __ li(ip, Operand(1));
+    __ rotrdi(ip, ip, 1);  // ip = 0x80000000_00000000
+    __ cmp(scratch, ip);
+#else
+    __ lwz(scratch, FieldMemOperand(value, HeapNumber::kExponentOffset));
+    __ lwz(ip, FieldMemOperand(value, HeapNumber::kMantissaOffset));
+    Label skip;
+    __ lis(r0, Operand(SIGN_EXT_IMM16(0x8000)));
+    __ cmp(scratch, r0);
+    __ bne(&skip);
+    __ cmpi(ip, Operand::Zero());
+    __ bind(&skip);
+#endif
+    EmitBranch(instr, eq);
+  }
+}
+
+
+Condition LCodeGen::EmitIsObject(Register input, Register temp1,
+                                 Label* is_not_object, Label* is_object) {
+  Register temp2 = scratch0();
+  __ JumpIfSmi(input, is_not_object);
+
+  __ LoadRoot(temp2, Heap::kNullValueRootIndex);
+  __ cmp(input, temp2);
+  __ beq(is_object);
+
+  // Load map.
+  __ LoadP(temp1, FieldMemOperand(input, HeapObject::kMapOffset));
+  // Undetectable objects behave like undefined.
+  __ lbz(temp2, FieldMemOperand(temp1, Map::kBitFieldOffset));
+  __ TestBit(temp2, Map::kIsUndetectable, r0);
+  __ bne(is_not_object, cr0);
+
+  // Load instance type and check that it is in object type range.
+  __ lbz(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset));
+  __ cmpi(temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+  __ blt(is_not_object);
+  __ cmpi(temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
+  return le;
+}
+
+
+void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
+  Register reg = ToRegister(instr->value());
+  Register temp1 = ToRegister(instr->temp());
+
+  Condition true_cond = EmitIsObject(reg, temp1, instr->FalseLabel(chunk_),
+                                     instr->TrueLabel(chunk_));
+
+  EmitBranch(instr, true_cond);
+}
+
+
+Condition LCodeGen::EmitIsString(Register input, Register temp1,
+                                 Label* is_not_string,
+                                 SmiCheck check_needed = INLINE_SMI_CHECK) {
+  if (check_needed == INLINE_SMI_CHECK) {
+    __ JumpIfSmi(input, is_not_string);
+  }
+  __ CompareObjectType(input, temp1, temp1, FIRST_NONSTRING_TYPE);
+
+  return lt;
+}
+
+
+void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
+  Register reg = ToRegister(instr->value());
+  Register temp1 = ToRegister(instr->temp());
+
+  SmiCheck check_needed = instr->hydrogen()->value()->type().IsHeapObject()
+                              ? OMIT_SMI_CHECK
+                              : INLINE_SMI_CHECK;
+  Condition true_cond =
+      EmitIsString(reg, temp1, instr->FalseLabel(chunk_), check_needed);
+
+  EmitBranch(instr, true_cond);
+}
+
+
+void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
+  Register input_reg = EmitLoadRegister(instr->value(), ip);
+  __ TestIfSmi(input_reg, r0);
+  EmitBranch(instr, eq, cr0);
+}
+
+
+void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
+  Register input = ToRegister(instr->value());
+  Register temp = ToRegister(instr->temp());
+
+  if (!instr->hydrogen()->value()->type().IsHeapObject()) {
+    __ JumpIfSmi(input, instr->FalseLabel(chunk_));
+  }
+  __ LoadP(temp, FieldMemOperand(input, HeapObject::kMapOffset));
+  __ lbz(temp, FieldMemOperand(temp, Map::kBitFieldOffset));
+  __ TestBit(temp, Map::kIsUndetectable, r0);
+  EmitBranch(instr, ne, cr0);
+}
+
+
+static Condition ComputeCompareCondition(Token::Value op) {
+  switch (op) {
+    case Token::EQ_STRICT:
+    case Token::EQ:
+      return eq;
+    case Token::LT:
+      return lt;
+    case Token::GT:
+      return gt;
+    case Token::LTE:
+      return le;
+    case Token::GTE:
+      return ge;
+    default:
+      UNREACHABLE();
+      return kNoCondition;
+  }
+}
+
+
+void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  Token::Value op = instr->op();
+
+  Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+  // This instruction also signals no smi code inlined
+  __ cmpi(r3, Operand::Zero());
+
+  Condition condition = ComputeCompareCondition(op);
+
+  EmitBranch(instr, condition);
+}
+
+
+static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
+  InstanceType from = instr->from();
+  InstanceType to = instr->to();
+  if (from == FIRST_TYPE) return to;
+  DCHECK(from == to || to == LAST_TYPE);
+  return from;
+}
+
+
+static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
+  InstanceType from = instr->from();
+  InstanceType to = instr->to();
+  if (from == to) return eq;
+  if (to == LAST_TYPE) return ge;
+  if (from == FIRST_TYPE) return le;
+  UNREACHABLE();
+  return eq;
+}
+
+
+void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
+  Register scratch = scratch0();
+  Register input = ToRegister(instr->value());
+
+  if (!instr->hydrogen()->value()->type().IsHeapObject()) {
+    __ JumpIfSmi(input, instr->FalseLabel(chunk_));
+  }
+
+  __ CompareObjectType(input, scratch, scratch, TestType(instr->hydrogen()));
+  EmitBranch(instr, BranchCondition(instr->hydrogen()));
+}
+
+
+void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
+  Register input = ToRegister(instr->value());
+  Register result = ToRegister(instr->result());
+
+  __ AssertString(input);
+
+  __ lwz(result, FieldMemOperand(input, String::kHashFieldOffset));
+  __ IndexFromHash(result, result);
+}
+
+
+void LCodeGen::DoHasCachedArrayIndexAndBranch(
+    LHasCachedArrayIndexAndBranch* instr) {
+  Register input = ToRegister(instr->value());
+  Register scratch = scratch0();
+
+  __ lwz(scratch, FieldMemOperand(input, String::kHashFieldOffset));
+  __ mov(r0, Operand(String::kContainsCachedArrayIndexMask));
+  __ and_(r0, scratch, r0, SetRC);
+  EmitBranch(instr, eq, cr0);
+}
+
+
+// Branches to a label or falls through with the answer in flags.  Trashes
+// the temp registers, but not the input.
+void LCodeGen::EmitClassOfTest(Label* is_true, Label* is_false,
+                               Handle<String> class_name, Register input,
+                               Register temp, Register temp2) {
+  DCHECK(!input.is(temp));
+  DCHECK(!input.is(temp2));
+  DCHECK(!temp.is(temp2));
+
+  __ JumpIfSmi(input, is_false);
+
+  if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
+    // Assuming the following assertions, we can use the same compares to test
+    // for both being a function type and being in the object type range.
+    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+    STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  FIRST_SPEC_OBJECT_TYPE + 1);
+    STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  LAST_SPEC_OBJECT_TYPE - 1);
+    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
+    __ CompareObjectType(input, temp, temp2, FIRST_SPEC_OBJECT_TYPE);
+    __ blt(is_false);
+    __ beq(is_true);
+    __ cmpi(temp2, Operand(LAST_SPEC_OBJECT_TYPE));
+    __ beq(is_true);
+  } else {
+    // Faster code path to avoid two compares: subtract lower bound from the
+    // actual type and do a signed compare with the width of the type range.
+    __ LoadP(temp, FieldMemOperand(input, HeapObject::kMapOffset));
+    __ lbz(temp2, FieldMemOperand(temp, Map::kInstanceTypeOffset));
+    __ subi(temp2, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+    __ cmpi(temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
+                           FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+    __ bgt(is_false);
+  }
+
+  // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
+  // Check if the constructor in the map is a function.
+  __ LoadP(temp, FieldMemOperand(temp, Map::kConstructorOffset));
+
+  // Objects with a non-function constructor have class 'Object'.
+  __ CompareObjectType(temp, temp2, temp2, JS_FUNCTION_TYPE);
+  if (class_name->IsOneByteEqualTo(STATIC_CHAR_VECTOR("Object"))) {
+    __ bne(is_true);
+  } else {
+    __ bne(is_false);
+  }
+
+  // temp now contains the constructor function. Grab the
+  // instance class name from there.
+  __ LoadP(temp, FieldMemOperand(temp, JSFunction::kSharedFunctionInfoOffset));
+  __ LoadP(temp,
+           FieldMemOperand(temp, SharedFunctionInfo::kInstanceClassNameOffset));
+  // The class name we are testing against is internalized since it's a literal.
+  // The name in the constructor is internalized because of the way the context
+  // is booted.  This routine isn't expected to work for random API-created
+  // classes and it doesn't have to because you can't access it with natives
+  // syntax.  Since both sides are internalized it is sufficient to use an
+  // identity comparison.
+  __ Cmpi(temp, Operand(class_name), r0);
+  // End with the answer in flags.
+}
+
+
+void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
+  Register input = ToRegister(instr->value());
+  Register temp = scratch0();
+  Register temp2 = ToRegister(instr->temp());
+  Handle<String> class_name = instr->hydrogen()->class_name();
+
+  EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
+                  class_name, input, temp, temp2);
+
+  EmitBranch(instr, eq);
+}
+
+
+void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
+  Register reg = ToRegister(instr->value());
+  Register temp = ToRegister(instr->temp());
+
+  __ LoadP(temp, FieldMemOperand(reg, HeapObject::kMapOffset));
+  __ Cmpi(temp, Operand(instr->map()), r0);
+  EmitBranch(instr, eq);
+}
+
+
+void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->left()).is(r3));   // Object is in r3.
+  DCHECK(ToRegister(instr->right()).is(r4));  // Function is in r4.
+
+  InstanceofStub stub(isolate(), InstanceofStub::kArgsInRegisters);
+  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+
+  Label equal, done;
+  __ cmpi(r3, Operand::Zero());
+  __ beq(&equal);
+  __ mov(r3, Operand(factory()->false_value()));
+  __ b(&done);
+
+  __ bind(&equal);
+  __ mov(r3, Operand(factory()->true_value()));
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
+  class DeferredInstanceOfKnownGlobal FINAL : public LDeferredCode {
+   public:
+    DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
+                                  LInstanceOfKnownGlobal* instr)
+        : LDeferredCode(codegen), instr_(instr) {}
+    void Generate() OVERRIDE {
+      codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
+    }
+    LInstruction* instr() OVERRIDE { return instr_; }
+    Label* map_check() { return &map_check_; }
+
+   private:
+    LInstanceOfKnownGlobal* instr_;
+    Label map_check_;
+  };
+
+  DeferredInstanceOfKnownGlobal* deferred;
+  deferred = new (zone()) DeferredInstanceOfKnownGlobal(this, instr);
+
+  Label done, false_result;
+  Register object = ToRegister(instr->value());
+  Register temp = ToRegister(instr->temp());
+  Register result = ToRegister(instr->result());
+
+  // A Smi is not instance of anything.
+  __ JumpIfSmi(object, &false_result);
+
+  // This is the inlined call site instanceof cache. The two occurences of the
+  // hole value will be patched to the last map/result pair generated by the
+  // instanceof stub.
+  Label cache_miss;
+  Register map = temp;
+  __ LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset));
+  {
+    // Block constant pool emission to ensure the positions of instructions are
+    // as expected by the patcher. See InstanceofStub::Generate().
+    Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
+    __ bind(deferred->map_check());  // Label for calculating code patching.
+    // We use Factory::the_hole_value() on purpose instead of loading from the
+    // root array to force relocation to be able to later patch with
+    // the cached map.
+    Handle<Cell> cell = factory()->NewCell(factory()->the_hole_value());
+    __ mov(ip, Operand(Handle<Object>(cell)));
+    __ LoadP(ip, FieldMemOperand(ip, PropertyCell::kValueOffset));
+    __ cmp(map, ip);
+    __ bne(&cache_miss);
+    // We use Factory::the_hole_value() on purpose instead of loading from the
+    // root array to force relocation to be able to later patch
+    // with true or false.
+    __ mov(result, Operand(factory()->the_hole_value()));
+  }
+  __ b(&done);
+
+  // The inlined call site cache did not match. Check null and string before
+  // calling the deferred code.
+  __ bind(&cache_miss);
+  // Null is not instance of anything.
+  __ LoadRoot(ip, Heap::kNullValueRootIndex);
+  __ cmp(object, ip);
+  __ beq(&false_result);
+
+  // String values is not instance of anything.
+  Condition is_string = masm_->IsObjectStringType(object, temp);
+  __ b(is_string, &false_result, cr0);
+
+  // Go to the deferred code.
+  __ b(deferred->entry());
+
+  __ bind(&false_result);
+  __ LoadRoot(result, Heap::kFalseValueRootIndex);
+
+  // Here result has either true or false. Deferred code also produces true or
+  // false object.
+  __ bind(deferred->exit());
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
+                                               Label* map_check) {
+  InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
+  flags = static_cast<InstanceofStub::Flags>(flags |
+                                             InstanceofStub::kArgsInRegisters);
+  flags = static_cast<InstanceofStub::Flags>(
+      flags | InstanceofStub::kCallSiteInlineCheck);
+  flags = static_cast<InstanceofStub::Flags>(
+      flags | InstanceofStub::kReturnTrueFalseObject);
+  InstanceofStub stub(isolate(), flags);
+
+  PushSafepointRegistersScope scope(this);
+  LoadContextFromDeferred(instr->context());
+
+  __ Move(InstanceofStub::right(), instr->function());
+  // Include instructions below in delta: mov + call = mov + (mov + 2)
+  static const int kAdditionalDelta = (2 * Assembler::kMovInstructions) + 2;
+  int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta;
+  {
+    Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
+    // r8 is used to communicate the offset to the location of the map check.
+    __ mov(r8, Operand(delta * Instruction::kInstrSize));
+  }
+  CallCodeGeneric(stub.GetCode(), RelocInfo::CODE_TARGET, instr,
+                  RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
+  DCHECK(delta == masm_->InstructionsGeneratedSince(map_check));
+  LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
+  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
+  // Put the result value (r3) into the result register slot and
+  // restore all registers.
+  __ StoreToSafepointRegisterSlot(r3, ToRegister(instr->result()));
+}
+
+
+void LCodeGen::DoCmpT(LCmpT* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  Token::Value op = instr->op();
+
+  Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+  // This instruction also signals no smi code inlined
+  __ cmpi(r3, Operand::Zero());
+
+  Condition condition = ComputeCompareCondition(op);
+  Label true_value, done;
+
+  __ b(condition, &true_value);
+
+  __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
+  __ b(&done);
+
+  __ bind(&true_value);
+  __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
+
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoReturn(LReturn* instr) {
+  if (FLAG_trace && info()->IsOptimizing()) {
+    // Push the return value on the stack as the parameter.
+    // Runtime::TraceExit returns its parameter in r3.  We're leaving the code
+    // managed by the register allocator and tearing down the frame, it's
+    // safe to write to the context register.
+    __ push(r3);
+    __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    __ CallRuntime(Runtime::kTraceExit, 1);
+  }
+  if (info()->saves_caller_doubles()) {
+    RestoreCallerDoubles();
+  }
+  int no_frame_start = -1;
+  if (instr->has_constant_parameter_count()) {
+    int parameter_count = ToInteger32(instr->constant_parameter_count());
+    int32_t sp_delta = (parameter_count + 1) * kPointerSize;
+    if (NeedsEagerFrame()) {
+      no_frame_start = masm_->LeaveFrame(StackFrame::JAVA_SCRIPT, sp_delta);
+    } else if (sp_delta != 0) {
+      __ addi(sp, sp, Operand(sp_delta));
+    }
+  } else {
+    Register reg = ToRegister(instr->parameter_count());
+    // The argument count parameter is a smi
+    if (NeedsEagerFrame()) {
+      no_frame_start = masm_->LeaveFrame(StackFrame::JAVA_SCRIPT);
+    }
+    __ SmiToPtrArrayOffset(r0, reg);
+    __ add(sp, sp, r0);
+  }
+
+  __ blr();
+
+  if (no_frame_start != -1) {
+    info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
+  }
+}
+
+
+void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
+  Register result = ToRegister(instr->result());
+  __ mov(ip, Operand(Handle<Object>(instr->hydrogen()->cell().handle())));
+  __ LoadP(result, FieldMemOperand(ip, Cell::kValueOffset));
+  if (instr->hydrogen()->RequiresHoleCheck()) {
+    __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+    __ cmp(result, ip);
+    DeoptimizeIf(eq, instr, "hole");
+  }
+}
+
+
+template <class T>
+void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
+  DCHECK(FLAG_vector_ics);
+  Register vector = ToRegister(instr->temp_vector());
+  DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
+  __ Move(vector, instr->hydrogen()->feedback_vector());
+  // No need to allocate this register.
+  DCHECK(VectorLoadICDescriptor::SlotRegister().is(r3));
+  __ mov(VectorLoadICDescriptor::SlotRegister(),
+         Operand(Smi::FromInt(instr->hydrogen()->slot())));
+}
+
+
+void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->global_object())
+             .is(LoadDescriptor::ReceiverRegister()));
+  DCHECK(ToRegister(instr->result()).is(r3));
+
+  __ mov(LoadDescriptor::NameRegister(), Operand(instr->name()));
+  if (FLAG_vector_ics) {
+    EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
+  }
+  ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
+  Handle<Code> ic = CodeFactory::LoadIC(isolate(), mode).code();
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
+  Register value = ToRegister(instr->value());
+  Register cell = scratch0();
+
+  // Load the cell.
+  __ mov(cell, Operand(instr->hydrogen()->cell().handle()));
+
+  // If the cell we are storing to contains the hole it could have
+  // been deleted from the property dictionary. In that case, we need
+  // to update the property details in the property dictionary to mark
+  // it as no longer deleted.
+  if (instr->hydrogen()->RequiresHoleCheck()) {
+    // We use a temp to check the payload (CompareRoot might clobber ip).
+    Register payload = ToRegister(instr->temp());
+    __ LoadP(payload, FieldMemOperand(cell, Cell::kValueOffset));
+    __ CompareRoot(payload, Heap::kTheHoleValueRootIndex);
+    DeoptimizeIf(eq, instr, "hole");
+  }
+
+  // Store the value.
+  __ StoreP(value, FieldMemOperand(cell, Cell::kValueOffset), r0);
+  // Cells are always rescanned, so no write barrier here.
+}
+
+
+void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
+  Register context = ToRegister(instr->context());
+  Register result = ToRegister(instr->result());
+  __ LoadP(result, ContextOperand(context, instr->slot_index()));
+  if (instr->hydrogen()->RequiresHoleCheck()) {
+    __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+    __ cmp(result, ip);
+    if (instr->hydrogen()->DeoptimizesOnHole()) {
+      DeoptimizeIf(eq, instr, "hole");
+    } else {
+      Label skip;
+      __ bne(&skip);
+      __ mov(result, Operand(factory()->undefined_value()));
+      __ bind(&skip);
+    }
+  }
+}
+
+
+void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
+  Register context = ToRegister(instr->context());
+  Register value = ToRegister(instr->value());
+  Register scratch = scratch0();
+  MemOperand target = ContextOperand(context, instr->slot_index());
+
+  Label skip_assignment;
+
+  if (instr->hydrogen()->RequiresHoleCheck()) {
+    __ LoadP(scratch, target);
+    __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+    __ cmp(scratch, ip);
+    if (instr->hydrogen()->DeoptimizesOnHole()) {
+      DeoptimizeIf(eq, instr, "hole");
+    } else {
+      __ bne(&skip_assignment);
+    }
+  }
+
+  __ StoreP(value, target, r0);
+  if (instr->hydrogen()->NeedsWriteBarrier()) {
+    SmiCheck check_needed = instr->hydrogen()->value()->type().IsHeapObject()
+                                ? OMIT_SMI_CHECK
+                                : INLINE_SMI_CHECK;
+    __ RecordWriteContextSlot(context, target.offset(), value, scratch,
+                              GetLinkRegisterState(), kSaveFPRegs,
+                              EMIT_REMEMBERED_SET, check_needed);
+  }
+
+  __ bind(&skip_assignment);
+}
+
+
+void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
+  HObjectAccess access = instr->hydrogen()->access();
+  int offset = access.offset();
+  Register object = ToRegister(instr->object());
+
+  if (access.IsExternalMemory()) {
+    Register result = ToRegister(instr->result());
+    MemOperand operand = MemOperand(object, offset);
+    __ LoadRepresentation(result, operand, access.representation(), r0);
+    return;
+  }
+
+  if (instr->hydrogen()->representation().IsDouble()) {
+    DoubleRegister result = ToDoubleRegister(instr->result());
+    __ lfd(result, FieldMemOperand(object, offset));
+    return;
+  }
+
+  Register result = ToRegister(instr->result());
+  if (!access.IsInobject()) {
+    __ LoadP(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
+    object = result;
+  }
+
+  Representation representation = access.representation();
+
+#if V8_TARGET_ARCH_PPC64
+  // 64-bit Smi optimization
+  if (representation.IsSmi() &&
+      instr->hydrogen()->representation().IsInteger32()) {
+    // Read int value directly from upper half of the smi.
+    STATIC_ASSERT(kSmiTag == 0);
+    STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
+#if V8_TARGET_LITTLE_ENDIAN
+    offset += kPointerSize / 2;
+#endif
+    representation = Representation::Integer32();
+  }
+#endif
+
+  __ LoadRepresentation(result, FieldMemOperand(object, offset), representation,
+                        r0);
+}
+
+
+void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->object()).is(LoadDescriptor::ReceiverRegister()));
+  DCHECK(ToRegister(instr->result()).is(r3));
+
+  // Name is always in r5.
+  __ mov(LoadDescriptor::NameRegister(), Operand(instr->name()));
+  if (FLAG_vector_ics) {
+    EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
+  }
+  Handle<Code> ic = CodeFactory::LoadIC(isolate(), NOT_CONTEXTUAL).code();
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
+  Register scratch = scratch0();
+  Register function = ToRegister(instr->function());
+  Register result = ToRegister(instr->result());
+
+  // Get the prototype or initial map from the function.
+  __ LoadP(result,
+           FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
+
+  // Check that the function has a prototype or an initial map.
+  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+  __ cmp(result, ip);
+  DeoptimizeIf(eq, instr, "hole");
+
+  // If the function does not have an initial map, we're done.
+  Label done;
+  __ CompareObjectType(result, scratch, scratch, MAP_TYPE);
+  __ bne(&done);
+
+  // Get the prototype from the initial map.
+  __ LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset));
+
+  // All done.
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoLoadRoot(LLoadRoot* instr) {
+  Register result = ToRegister(instr->result());
+  __ LoadRoot(result, instr->index());
+}
+
+
+void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
+  Register arguments = ToRegister(instr->arguments());
+  Register result = ToRegister(instr->result());
+  // There are two words between the frame pointer and the last argument.
+  // Subtracting from length accounts for one of them add one more.
+  if (instr->length()->IsConstantOperand()) {
+    int const_length = ToInteger32(LConstantOperand::cast(instr->length()));
+    if (instr->index()->IsConstantOperand()) {
+      int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
+      int index = (const_length - const_index) + 1;
+      __ LoadP(result, MemOperand(arguments, index * kPointerSize), r0);
+    } else {
+      Register index = ToRegister(instr->index());
+      __ subfic(result, index, Operand(const_length + 1));
+      __ ShiftLeftImm(result, result, Operand(kPointerSizeLog2));
+      __ LoadPX(result, MemOperand(arguments, result));
+    }
+  } else if (instr->index()->IsConstantOperand()) {
+    Register length = ToRegister(instr->length());
+    int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
+    int loc = const_index - 1;
+    if (loc != 0) {
+      __ subi(result, length, Operand(loc));
+      __ ShiftLeftImm(result, result, Operand(kPointerSizeLog2));
+      __ LoadPX(result, MemOperand(arguments, result));
+    } else {
+      __ ShiftLeftImm(result, length, Operand(kPointerSizeLog2));
+      __ LoadPX(result, MemOperand(arguments, result));
+    }
+  } else {
+    Register length = ToRegister(instr->length());
+    Register index = ToRegister(instr->index());
+    __ sub(result, length, index);
+    __ addi(result, result, Operand(1));
+    __ ShiftLeftImm(result, result, Operand(kPointerSizeLog2));
+    __ LoadPX(result, MemOperand(arguments, result));
+  }
+}
+
+
+void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
+  Register external_pointer = ToRegister(instr->elements());
+  Register key = no_reg;
+  ElementsKind elements_kind = instr->elements_kind();
+  bool key_is_constant = instr->key()->IsConstantOperand();
+  int constant_key = 0;
+  if (key_is_constant) {
+    constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
+    if (constant_key & 0xF0000000) {
+      Abort(kArrayIndexConstantValueTooBig);
+    }
+  } else {
+    key = ToRegister(instr->key());
+  }
+  int element_size_shift = ElementsKindToShiftSize(elements_kind);
+  bool key_is_smi = instr->hydrogen()->key()->representation().IsSmi();
+  int base_offset = instr->base_offset();
+
+  if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+      elements_kind == FLOAT32_ELEMENTS ||
+      elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+      elements_kind == FLOAT64_ELEMENTS) {
+    DoubleRegister result = ToDoubleRegister(instr->result());
+    if (key_is_constant) {
+      __ Add(scratch0(), external_pointer, constant_key << element_size_shift,
+             r0);
+    } else {
+      __ IndexToArrayOffset(r0, key, element_size_shift, key_is_smi);
+      __ add(scratch0(), external_pointer, r0);
+    }
+    if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+        elements_kind == FLOAT32_ELEMENTS) {
+      __ lfs(result, MemOperand(scratch0(), base_offset));
+    } else {  // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
+      __ lfd(result, MemOperand(scratch0(), base_offset));
+    }
+  } else {
+    Register result = ToRegister(instr->result());
+    MemOperand mem_operand =
+        PrepareKeyedOperand(key, external_pointer, key_is_constant, key_is_smi,
+                            constant_key, element_size_shift, base_offset);
+    switch (elements_kind) {
+      case EXTERNAL_INT8_ELEMENTS:
+      case INT8_ELEMENTS:
+        if (key_is_constant) {
+          __ LoadByte(result, mem_operand, r0);
+        } else {
+          __ lbzx(result, mem_operand);
+        }
+        __ extsb(result, result);
+        break;
+      case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+      case EXTERNAL_UINT8_ELEMENTS:
+      case UINT8_ELEMENTS:
+      case UINT8_CLAMPED_ELEMENTS:
+        if (key_is_constant) {
+          __ LoadByte(result, mem_operand, r0);
+        } else {
+          __ lbzx(result, mem_operand);
+        }
+        break;
+      case EXTERNAL_INT16_ELEMENTS:
+      case INT16_ELEMENTS:
+        if (key_is_constant) {
+          __ LoadHalfWord(result, mem_operand, r0);
+        } else {
+          __ lhzx(result, mem_operand);
+        }
+        __ extsh(result, result);
+        break;
+      case EXTERNAL_UINT16_ELEMENTS:
+      case UINT16_ELEMENTS:
+        if (key_is_constant) {
+          __ LoadHalfWord(result, mem_operand, r0);
+        } else {
+          __ lhzx(result, mem_operand);
+        }
+        break;
+      case EXTERNAL_INT32_ELEMENTS:
+      case INT32_ELEMENTS:
+        if (key_is_constant) {
+          __ LoadWord(result, mem_operand, r0);
+        } else {
+          __ lwzx(result, mem_operand);
+        }
+#if V8_TARGET_ARCH_PPC64
+        __ extsw(result, result);
+#endif
+        break;
+      case EXTERNAL_UINT32_ELEMENTS:
+      case UINT32_ELEMENTS:
+        if (key_is_constant) {
+          __ LoadWord(result, mem_operand, r0);
+        } else {
+          __ lwzx(result, mem_operand);
+        }
+        if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
+          __ lis(r0, Operand(SIGN_EXT_IMM16(0x8000)));
+          __ cmplw(result, r0);
+          DeoptimizeIf(ge, instr, "negative value");
+        }
+        break;
+      case FLOAT32_ELEMENTS:
+      case FLOAT64_ELEMENTS:
+      case EXTERNAL_FLOAT32_ELEMENTS:
+      case EXTERNAL_FLOAT64_ELEMENTS:
+      case FAST_HOLEY_DOUBLE_ELEMENTS:
+      case FAST_HOLEY_ELEMENTS:
+      case FAST_HOLEY_SMI_ELEMENTS:
+      case FAST_DOUBLE_ELEMENTS:
+      case FAST_ELEMENTS:
+      case FAST_SMI_ELEMENTS:
+      case DICTIONARY_ELEMENTS:
+      case SLOPPY_ARGUMENTS_ELEMENTS:
+        UNREACHABLE();
+        break;
+    }
+  }
+}
+
+
+void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
+  Register elements = ToRegister(instr->elements());
+  bool key_is_constant = instr->key()->IsConstantOperand();
+  Register key = no_reg;
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  Register scratch = scratch0();
+
+  int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
+  bool key_is_smi = instr->hydrogen()->key()->representation().IsSmi();
+  int constant_key = 0;
+  if (key_is_constant) {
+    constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
+    if (constant_key & 0xF0000000) {
+      Abort(kArrayIndexConstantValueTooBig);
+    }
+  } else {
+    key = ToRegister(instr->key());
+  }
+
+  int base_offset = instr->base_offset() + constant_key * kDoubleSize;
+  if (!key_is_constant) {
+    __ IndexToArrayOffset(r0, key, element_size_shift, key_is_smi);
+    __ add(scratch, elements, r0);
+    elements = scratch;
+  }
+  if (!is_int16(base_offset)) {
+    __ Add(scratch, elements, base_offset, r0);
+    base_offset = 0;
+    elements = scratch;
+  }
+  __ lfd(result, MemOperand(elements, base_offset));
+
+  if (instr->hydrogen()->RequiresHoleCheck()) {
+    if (is_int16(base_offset + Register::kExponentOffset)) {
+      __ lwz(scratch,
+             MemOperand(elements, base_offset + Register::kExponentOffset));
+    } else {
+      __ addi(scratch, elements, Operand(base_offset));
+      __ lwz(scratch, MemOperand(scratch, Register::kExponentOffset));
+    }
+    __ Cmpi(scratch, Operand(kHoleNanUpper32), r0);
+    DeoptimizeIf(eq, instr, "hole");
+  }
+}
+
+
+void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
+  HLoadKeyed* hinstr = instr->hydrogen();
+  Register elements = ToRegister(instr->elements());
+  Register result = ToRegister(instr->result());
+  Register scratch = scratch0();
+  Register store_base = scratch;
+  int offset = instr->base_offset();
+
+  if (instr->key()->IsConstantOperand()) {
+    LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
+    offset += ToInteger32(const_operand) * kPointerSize;
+    store_base = elements;
+  } else {
+    Register key = ToRegister(instr->key());
+    // Even though the HLoadKeyed instruction forces the input
+    // representation for the key to be an integer, the input gets replaced
+    // during bound check elimination with the index argument to the bounds
+    // check, which can be tagged, so that case must be handled here, too.
+    if (hinstr->key()->representation().IsSmi()) {
+      __ SmiToPtrArrayOffset(r0, key);
+    } else {
+      __ ShiftLeftImm(r0, key, Operand(kPointerSizeLog2));
+    }
+    __ add(scratch, elements, r0);
+  }
+
+  bool requires_hole_check = hinstr->RequiresHoleCheck();
+  Representation representation = hinstr->representation();
+
+#if V8_TARGET_ARCH_PPC64
+  // 64-bit Smi optimization
+  if (representation.IsInteger32() &&
+      hinstr->elements_kind() == FAST_SMI_ELEMENTS) {
+    DCHECK(!requires_hole_check);
+    // Read int value directly from upper half of the smi.
+    STATIC_ASSERT(kSmiTag == 0);
+    STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
+#if V8_TARGET_LITTLE_ENDIAN
+    offset += kPointerSize / 2;
+#endif
+  }
+#endif
+
+  __ LoadRepresentation(result, MemOperand(store_base, offset), representation,
+                        r0);
+
+  // Check for the hole value.
+  if (requires_hole_check) {
+    if (IsFastSmiElementsKind(hinstr->elements_kind())) {
+      __ TestIfSmi(result, r0);
+      DeoptimizeIf(ne, instr, "not a Smi", cr0);
+    } else {
+      __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
+      __ cmp(result, scratch);
+      DeoptimizeIf(eq, instr, "hole");
+    }
+  }
+}
+
+
+void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
+  if (instr->is_typed_elements()) {
+    DoLoadKeyedExternalArray(instr);
+  } else if (instr->hydrogen()->representation().IsDouble()) {
+    DoLoadKeyedFixedDoubleArray(instr);
+  } else {
+    DoLoadKeyedFixedArray(instr);
+  }
+}
+
+
+MemOperand LCodeGen::PrepareKeyedOperand(Register key, Register base,
+                                         bool key_is_constant, bool key_is_smi,
+                                         int constant_key,
+                                         int element_size_shift,
+                                         int base_offset) {
+  Register scratch = scratch0();
+
+  if (key_is_constant) {
+    return MemOperand(base, (constant_key << element_size_shift) + base_offset);
+  }
+
+  bool needs_shift =
+      (element_size_shift != (key_is_smi ? kSmiTagSize + kSmiShiftSize : 0));
+
+  if (!(base_offset || needs_shift)) {
+    return MemOperand(base, key);
+  }
+
+  if (needs_shift) {
+    __ IndexToArrayOffset(scratch, key, element_size_shift, key_is_smi);
+    key = scratch;
+  }
+
+  if (base_offset) {
+    __ Add(scratch, key, base_offset, r0);
+  }
+
+  return MemOperand(base, scratch);
+}
+
+
+void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->object()).is(LoadDescriptor::ReceiverRegister()));
+  DCHECK(ToRegister(instr->key()).is(LoadDescriptor::NameRegister()));
+
+  if (FLAG_vector_ics) {
+    EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
+  }
+
+  Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
+  Register scratch = scratch0();
+  Register result = ToRegister(instr->result());
+
+  if (instr->hydrogen()->from_inlined()) {
+    __ subi(result, sp, Operand(2 * kPointerSize));
+  } else {
+    // Check if the calling frame is an arguments adaptor frame.
+    Label done, adapted;
+    __ LoadP(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+    __ LoadP(result,
+             MemOperand(scratch, StandardFrameConstants::kContextOffset));
+    __ CmpSmiLiteral(result, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
+
+    // Result is the frame pointer for the frame if not adapted and for the real
+    // frame below the adaptor frame if adapted.
+    __ beq(&adapted);
+    __ mr(result, fp);
+    __ b(&done);
+
+    __ bind(&adapted);
+    __ mr(result, scratch);
+    __ bind(&done);
+  }
+}
+
+
+void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
+  Register elem = ToRegister(instr->elements());
+  Register result = ToRegister(instr->result());
+
+  Label done;
+
+  // If no arguments adaptor frame the number of arguments is fixed.
+  __ cmp(fp, elem);
+  __ mov(result, Operand(scope()->num_parameters()));
+  __ beq(&done);
+
+  // Arguments adaptor frame present. Get argument length from there.
+  __ LoadP(result, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ LoadP(result,
+           MemOperand(result, ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ SmiUntag(result);
+
+  // Argument length is in result register.
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
+  Register receiver = ToRegister(instr->receiver());
+  Register function = ToRegister(instr->function());
+  Register result = ToRegister(instr->result());
+  Register scratch = scratch0();
+
+  // If the receiver is null or undefined, we have to pass the global
+  // object as a receiver to normal functions. Values have to be
+  // passed unchanged to builtins and strict-mode functions.
+  Label global_object, result_in_receiver;
+
+  if (!instr->hydrogen()->known_function()) {
+    // Do not transform the receiver to object for strict mode
+    // functions.
+    __ LoadP(scratch,
+             FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
+    __ lwz(scratch,
+           FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
+    __ TestBit(scratch,
+#if V8_TARGET_ARCH_PPC64
+               SharedFunctionInfo::kStrictModeFunction,
+#else
+               SharedFunctionInfo::kStrictModeFunction + kSmiTagSize,
+#endif
+               r0);
+    __ bne(&result_in_receiver, cr0);
+
+    // Do not transform the receiver to object for builtins.
+    __ TestBit(scratch,
+#if V8_TARGET_ARCH_PPC64
+               SharedFunctionInfo::kNative,
+#else
+               SharedFunctionInfo::kNative + kSmiTagSize,
+#endif
+               r0);
+    __ bne(&result_in_receiver, cr0);
+  }
+
+  // Normal function. Replace undefined or null with global receiver.
+  __ LoadRoot(scratch, Heap::kNullValueRootIndex);
+  __ cmp(receiver, scratch);
+  __ beq(&global_object);
+  __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
+  __ cmp(receiver, scratch);
+  __ beq(&global_object);
+
+  // Deoptimize if the receiver is not a JS object.
+  __ TestIfSmi(receiver, r0);
+  DeoptimizeIf(eq, instr, "Smi");
+  __ CompareObjectType(receiver, scratch, scratch, FIRST_SPEC_OBJECT_TYPE);
+  DeoptimizeIf(lt, instr, "not a JavaScript object");
+
+  __ b(&result_in_receiver);
+  __ bind(&global_object);
+  __ LoadP(result, FieldMemOperand(function, JSFunction::kContextOffset));
+  __ LoadP(result, ContextOperand(result, Context::GLOBAL_OBJECT_INDEX));
+  __ LoadP(result, FieldMemOperand(result, GlobalObject::kGlobalProxyOffset));
+  if (result.is(receiver)) {
+    __ bind(&result_in_receiver);
+  } else {
+    Label result_ok;
+    __ b(&result_ok);
+    __ bind(&result_in_receiver);
+    __ mr(result, receiver);
+    __ bind(&result_ok);
+  }
+}
+
+
+void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
+  Register receiver = ToRegister(instr->receiver());
+  Register function = ToRegister(instr->function());
+  Register length = ToRegister(instr->length());
+  Register elements = ToRegister(instr->elements());
+  Register scratch = scratch0();
+  DCHECK(receiver.is(r3));  // Used for parameter count.
+  DCHECK(function.is(r4));  // Required by InvokeFunction.
+  DCHECK(ToRegister(instr->result()).is(r3));
+
+  // Copy the arguments to this function possibly from the
+  // adaptor frame below it.
+  const uint32_t kArgumentsLimit = 1 * KB;
+  __ cmpli(length, Operand(kArgumentsLimit));
+  DeoptimizeIf(gt, instr, "too many arguments");
+
+  // Push the receiver and use the register to keep the original
+  // number of arguments.
+  __ push(receiver);
+  __ mr(receiver, length);
+  // The arguments are at a one pointer size offset from elements.
+  __ addi(elements, elements, Operand(1 * kPointerSize));
+
+  // Loop through the arguments pushing them onto the execution
+  // stack.
+  Label invoke, loop;
+  // length is a small non-negative integer, due to the test above.
+  __ cmpi(length, Operand::Zero());
+  __ beq(&invoke);
+  __ mtctr(length);
+  __ bind(&loop);
+  __ ShiftLeftImm(r0, length, Operand(kPointerSizeLog2));
+  __ LoadPX(scratch, MemOperand(elements, r0));
+  __ push(scratch);
+  __ addi(length, length, Operand(-1));
+  __ bdnz(&loop);
+
+  __ bind(&invoke);
+  DCHECK(instr->HasPointerMap());
+  LPointerMap* pointers = instr->pointer_map();
+  SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt);
+  // The number of arguments is stored in receiver which is r3, as expected
+  // by InvokeFunction.
+  ParameterCount actual(receiver);
+  __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator);
+}
+
+
+void LCodeGen::DoPushArgument(LPushArgument* instr) {
+  LOperand* argument = instr->value();
+  if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) {
+    Abort(kDoPushArgumentNotImplementedForDoubleType);
+  } else {
+    Register argument_reg = EmitLoadRegister(argument, ip);
+    __ push(argument_reg);
+  }
+}
+
+
+void LCodeGen::DoDrop(LDrop* instr) { __ Drop(instr->count()); }
+
+
+void LCodeGen::DoThisFunction(LThisFunction* instr) {
+  Register result = ToRegister(instr->result());
+  __ LoadP(result, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+}
+
+
+void LCodeGen::DoContext(LContext* instr) {
+  // If there is a non-return use, the context must be moved to a register.
+  Register result = ToRegister(instr->result());
+  if (info()->IsOptimizing()) {
+    __ LoadP(result, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  } else {
+    // If there is no frame, the context must be in cp.
+    DCHECK(result.is(cp));
+  }
+}
+
+
+void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  __ push(cp);  // The context is the first argument.
+  __ Move(scratch0(), instr->hydrogen()->pairs());
+  __ push(scratch0());
+  __ LoadSmiLiteral(scratch0(), Smi::FromInt(instr->hydrogen()->flags()));
+  __ push(scratch0());
+  CallRuntime(Runtime::kDeclareGlobals, 3, instr);
+}
+
+
+void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
+                                 int formal_parameter_count, int arity,
+                                 LInstruction* instr, R4State r4_state) {
+  bool dont_adapt_arguments =
+      formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
+  bool can_invoke_directly =
+      dont_adapt_arguments || formal_parameter_count == arity;
+
+  LPointerMap* pointers = instr->pointer_map();
+
+  if (can_invoke_directly) {
+    if (r4_state == R4_UNINITIALIZED) {
+      __ Move(r4, function);
+    }
+
+    // Change context.
+    __ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
+
+    // Set r3 to arguments count if adaption is not needed. Assumes that r3
+    // is available to write to at this point.
+    if (dont_adapt_arguments) {
+      __ mov(r3, Operand(arity));
+    }
+
+    bool is_self_call = function.is_identical_to(info()->closure());
+
+    // Invoke function.
+    if (is_self_call) {
+      __ CallSelf();
+    } else {
+      __ LoadP(ip, FieldMemOperand(r4, JSFunction::kCodeEntryOffset));
+      __ CallJSEntry(ip);
+    }
+
+    // Set up deoptimization.
+    RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
+  } else {
+    SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+    ParameterCount count(arity);
+    ParameterCount expected(formal_parameter_count);
+    __ InvokeFunction(function, expected, count, CALL_FUNCTION, generator);
+  }
+}
+
+
+void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
+  DCHECK(instr->context() != NULL);
+  DCHECK(ToRegister(instr->context()).is(cp));
+  Register input = ToRegister(instr->value());
+  Register result = ToRegister(instr->result());
+  Register scratch = scratch0();
+
+  // Deoptimize if not a heap number.
+  __ LoadP(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
+  __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
+  __ cmp(scratch, ip);
+  DeoptimizeIf(ne, instr, "not a heap number");
+
+  Label done;
+  Register exponent = scratch0();
+  scratch = no_reg;
+  __ lwz(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
+  // Check the sign of the argument. If the argument is positive, just
+  // return it.
+  __ cmpwi(exponent, Operand::Zero());
+  // Move the input to the result if necessary.
+  __ Move(result, input);
+  __ bge(&done);
+
+  // Input is negative. Reverse its sign.
+  // Preserve the value of all registers.
+  {
+    PushSafepointRegistersScope scope(this);
+
+    // Registers were saved at the safepoint, so we can use
+    // many scratch registers.
+    Register tmp1 = input.is(r4) ? r3 : r4;
+    Register tmp2 = input.is(r5) ? r3 : r5;
+    Register tmp3 = input.is(r6) ? r3 : r6;
+    Register tmp4 = input.is(r7) ? r3 : r7;
+
+    // exponent: floating point exponent value.
+
+    Label allocated, slow;
+    __ LoadRoot(tmp4, Heap::kHeapNumberMapRootIndex);
+    __ AllocateHeapNumber(tmp1, tmp2, tmp3, tmp4, &slow);
+    __ b(&allocated);
+
+    // Slow case: Call the runtime system to do the number allocation.
+    __ bind(&slow);
+
+    CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr,
+                            instr->context());
+    // Set the pointer to the new heap number in tmp.
+    if (!tmp1.is(r3)) __ mr(tmp1, r3);
+    // Restore input_reg after call to runtime.
+    __ LoadFromSafepointRegisterSlot(input, input);
+    __ lwz(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
+
+    __ bind(&allocated);
+    // exponent: floating point exponent value.
+    // tmp1: allocated heap number.
+    STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
+    __ clrlwi(exponent, exponent, Operand(1));  // clear sign bit
+    __ stw(exponent, FieldMemOperand(tmp1, HeapNumber::kExponentOffset));
+    __ lwz(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset));
+    __ stw(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset));
+
+    __ StoreToSafepointRegisterSlot(tmp1, result);
+  }
+
+  __ bind(&done);
+}
+
+
+void LCodeGen::EmitMathAbs(LMathAbs* instr) {
+  Register input = ToRegister(instr->value());
+  Register result = ToRegister(instr->result());
+  Label done;
+  __ cmpi(input, Operand::Zero());
+  __ Move(result, input);
+  __ bge(&done);
+  __ li(r0, Operand::Zero());  // clear xer
+  __ mtxer(r0);
+  __ neg(result, result, SetOE, SetRC);
+  // Deoptimize on overflow.
+  DeoptimizeIf(overflow, instr, "overflow", cr0);
+  __ bind(&done);
+}
+
+
+#if V8_TARGET_ARCH_PPC64
+void LCodeGen::EmitInteger32MathAbs(LMathAbs* instr) {
+  Register input = ToRegister(instr->value());
+  Register result = ToRegister(instr->result());
+  Label done;
+  __ cmpwi(input, Operand::Zero());
+  __ Move(result, input);
+  __ bge(&done);
+
+  // Deoptimize on overflow.
+  __ lis(r0, Operand(SIGN_EXT_IMM16(0x8000)));
+  __ cmpw(input, r0);
+  DeoptimizeIf(eq, instr, "overflow");
+
+  __ neg(result, result);
+  __ bind(&done);
+}
+#endif
+
+
+void LCodeGen::DoMathAbs(LMathAbs* instr) {
+  // Class for deferred case.
+  class DeferredMathAbsTaggedHeapNumber FINAL : public LDeferredCode {
+   public:
+    DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
+        : LDeferredCode(codegen), instr_(instr) {}
+    void Generate() OVERRIDE {
+      codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
+    }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
+   private:
+    LMathAbs* instr_;
+  };
+
+  Representation r = instr->hydrogen()->value()->representation();
+  if (r.IsDouble()) {
+    DoubleRegister input = ToDoubleRegister(instr->value());
+    DoubleRegister result = ToDoubleRegister(instr->result());
+    __ fabs(result, input);
+#if V8_TARGET_ARCH_PPC64
+  } else if (r.IsInteger32()) {
+    EmitInteger32MathAbs(instr);
+  } else if (r.IsSmi()) {
+#else
+  } else if (r.IsSmiOrInteger32()) {
+#endif
+    EmitMathAbs(instr);
+  } else {
+    // Representation is tagged.
+    DeferredMathAbsTaggedHeapNumber* deferred =
+        new (zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
+    Register input = ToRegister(instr->value());
+    // Smi check.
+    __ JumpIfNotSmi(input, deferred->entry());
+    // If smi, handle it directly.
+    EmitMathAbs(instr);
+    __ bind(deferred->exit());
+  }
+}
+
+
+void LCodeGen::DoMathFloor(LMathFloor* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  Register result = ToRegister(instr->result());
+  Register input_high = scratch0();
+  Register scratch = ip;
+  Label done, exact;
+
+  __ TryInt32Floor(result, input, input_high, scratch, double_scratch0(), &done,
+                   &exact);
+  DeoptimizeIf(al, instr, "lost precision or NaN");
+
+  __ bind(&exact);
+  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    // Test for -0.
+    __ cmpi(result, Operand::Zero());
+    __ bne(&done);
+    __ cmpwi(input_high, Operand::Zero());
+    DeoptimizeIf(lt, instr, "minus zero");
+  }
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoMathRound(LMathRound* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  Register result = ToRegister(instr->result());
+  DoubleRegister double_scratch1 = ToDoubleRegister(instr->temp());
+  DoubleRegister input_plus_dot_five = double_scratch1;
+  Register scratch1 = scratch0();
+  Register scratch2 = ip;
+  DoubleRegister dot_five = double_scratch0();
+  Label convert, done;
+
+  __ LoadDoubleLiteral(dot_five, 0.5, r0);
+  __ fabs(double_scratch1, input);
+  __ fcmpu(double_scratch1, dot_five);
+  DeoptimizeIf(unordered, instr, "lost precision or NaN");
+  // If input is in [-0.5, -0], the result is -0.
+  // If input is in [+0, +0.5[, the result is +0.
+  // If the input is +0.5, the result is 1.
+  __ bgt(&convert);  // Out of [-0.5, +0.5].
+  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+#if V8_TARGET_ARCH_PPC64
+    __ MovDoubleToInt64(scratch1, input);
+#else
+    __ MovDoubleHighToInt(scratch1, input);
+#endif
+    __ cmpi(scratch1, Operand::Zero());
+    // [-0.5, -0].
+    DeoptimizeIf(lt, instr, "minus zero");
+  }
+  Label return_zero;
+  __ fcmpu(input, dot_five);
+  __ bne(&return_zero);
+  __ li(result, Operand(1));  // +0.5.
+  __ b(&done);
+  // Remaining cases: [+0, +0.5[ or [-0.5, +0.5[, depending on
+  // flag kBailoutOnMinusZero.
+  __ bind(&return_zero);
+  __ li(result, Operand::Zero());
+  __ b(&done);
+
+  __ bind(&convert);
+  __ fadd(input_plus_dot_five, input, dot_five);
+  // Reuse dot_five (double_scratch0) as we no longer need this value.
+  __ TryInt32Floor(result, input_plus_dot_five, scratch1, scratch2,
+                   double_scratch0(), &done, &done);
+  DeoptimizeIf(al, instr, "lost precision or NaN");
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoMathFround(LMathFround* instr) {
+  DoubleRegister input_reg = ToDoubleRegister(instr->value());
+  DoubleRegister output_reg = ToDoubleRegister(instr->result());
+  __ frsp(output_reg, input_reg);
+}
+
+
+void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  __ fsqrt(result, input);
+}
+
+
+void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  DoubleRegister temp = double_scratch0();
+
+  // Note that according to ECMA-262 15.8.2.13:
+  // Math.pow(-Infinity, 0.5) == Infinity
+  // Math.sqrt(-Infinity) == NaN
+  Label skip, done;
+
+  __ LoadDoubleLiteral(temp, -V8_INFINITY, scratch0());
+  __ fcmpu(input, temp);
+  __ bne(&skip);
+  __ fneg(result, temp);
+  __ b(&done);
+
+  // Add +0 to convert -0 to +0.
+  __ bind(&skip);
+  __ fadd(result, input, kDoubleRegZero);
+  __ fsqrt(result, result);
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoPower(LPower* instr) {
+  Representation exponent_type = instr->hydrogen()->right()->representation();
+// Having marked this as a call, we can use any registers.
+// Just make sure that the input/output registers are the expected ones.
+#ifdef DEBUG
+  Register tagged_exponent = MathPowTaggedDescriptor::exponent();
+#endif
+  DCHECK(!instr->right()->IsDoubleRegister() ||
+         ToDoubleRegister(instr->right()).is(d2));
+  DCHECK(!instr->right()->IsRegister() ||
+         ToRegister(instr->right()).is(tagged_exponent));
+  DCHECK(ToDoubleRegister(instr->left()).is(d1));
+  DCHECK(ToDoubleRegister(instr->result()).is(d3));
+
+  if (exponent_type.IsSmi()) {
+    MathPowStub stub(isolate(), MathPowStub::TAGGED);
+    __ CallStub(&stub);
+  } else if (exponent_type.IsTagged()) {
+    Label no_deopt;
+    __ JumpIfSmi(r5, &no_deopt);
+    __ LoadP(r10, FieldMemOperand(r5, HeapObject::kMapOffset));
+    __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
+    __ cmp(r10, ip);
+    DeoptimizeIf(ne, instr, "not a heap number");
+    __ bind(&no_deopt);
+    MathPowStub stub(isolate(), MathPowStub::TAGGED);
+    __ CallStub(&stub);
+  } else if (exponent_type.IsInteger32()) {
+    MathPowStub stub(isolate(), MathPowStub::INTEGER);
+    __ CallStub(&stub);
+  } else {
+    DCHECK(exponent_type.IsDouble());
+    MathPowStub stub(isolate(), MathPowStub::DOUBLE);
+    __ CallStub(&stub);
+  }
+}
+
+
+void LCodeGen::DoMathExp(LMathExp* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
+  DoubleRegister double_scratch2 = double_scratch0();
+  Register temp1 = ToRegister(instr->temp1());
+  Register temp2 = ToRegister(instr->temp2());
+
+  MathExpGenerator::EmitMathExp(masm(), input, result, double_scratch1,
+                                double_scratch2, temp1, temp2, scratch0());
+}
+
+
+void LCodeGen::DoMathLog(LMathLog* instr) {
+  __ PrepareCallCFunction(0, 1, scratch0());
+  __ MovToFloatParameter(ToDoubleRegister(instr->value()));
+  __ CallCFunction(ExternalReference::math_log_double_function(isolate()), 0,
+                   1);
+  __ MovFromFloatResult(ToDoubleRegister(instr->result()));
+}
+
+
+void LCodeGen::DoMathClz32(LMathClz32* instr) {
+  Register input = ToRegister(instr->value());
+  Register result = ToRegister(instr->result());
+  __ cntlzw_(result, input);
+}
+
+
+void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->function()).is(r4));
+  DCHECK(instr->HasPointerMap());
+
+  Handle<JSFunction> known_function = instr->hydrogen()->known_function();
+  if (known_function.is_null()) {
+    LPointerMap* pointers = instr->pointer_map();
+    SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+    ParameterCount count(instr->arity());
+    __ InvokeFunction(r4, count, CALL_FUNCTION, generator);
+  } else {
+    CallKnownFunction(known_function,
+                      instr->hydrogen()->formal_parameter_count(),
+                      instr->arity(), instr, R4_CONTAINS_TARGET);
+  }
+}
+
+
+void LCodeGen::DoTailCallThroughMegamorphicCache(
+    LTailCallThroughMegamorphicCache* instr) {
+  Register receiver = ToRegister(instr->receiver());
+  Register name = ToRegister(instr->name());
+  DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
+  DCHECK(name.is(LoadDescriptor::NameRegister()));
+  DCHECK(receiver.is(r4));
+  DCHECK(name.is(r5));
+
+  Register scratch = r6;
+  Register extra = r7;
+  Register extra2 = r8;
+  Register extra3 = r9;
+
+  // Important for the tail-call.
+  bool must_teardown_frame = NeedsEagerFrame();
+
+  // The probe will tail call to a handler if found.
+  isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
+                                         must_teardown_frame, receiver, name,
+                                         scratch, extra, extra2, extra3);
+
+  // Tail call to miss if we ended up here.
+  if (must_teardown_frame) __ LeaveFrame(StackFrame::INTERNAL);
+  LoadIC::GenerateMiss(masm());
+}
+
+
+void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
+  DCHECK(ToRegister(instr->result()).is(r3));
+
+  LPointerMap* pointers = instr->pointer_map();
+  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+
+  if (instr->target()->IsConstantOperand()) {
+    LConstantOperand* target = LConstantOperand::cast(instr->target());
+    Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+    generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
+    __ Call(code, RelocInfo::CODE_TARGET);
+  } else {
+    DCHECK(instr->target()->IsRegister());
+    Register target = ToRegister(instr->target());
+    generator.BeforeCall(__ CallSize(target));
+    __ addi(ip, target, Operand(Code::kHeaderSize - kHeapObjectTag));
+    __ CallJSEntry(ip);
+  }
+  generator.AfterCall();
+}
+
+
+void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) {
+  DCHECK(ToRegister(instr->function()).is(r4));
+  DCHECK(ToRegister(instr->result()).is(r3));
+
+  if (instr->hydrogen()->pass_argument_count()) {
+    __ mov(r3, Operand(instr->arity()));
+  }
+
+  // Change context.
+  __ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
+
+  bool is_self_call = false;
+  if (instr->hydrogen()->function()->IsConstant()) {
+    HConstant* fun_const = HConstant::cast(instr->hydrogen()->function());
+    Handle<JSFunction> jsfun =
+        Handle<JSFunction>::cast(fun_const->handle(isolate()));
+    is_self_call = jsfun.is_identical_to(info()->closure());
+  }
+
+  if (is_self_call) {
+    __ CallSelf();
+  } else {
+    __ LoadP(ip, FieldMemOperand(r4, JSFunction::kCodeEntryOffset));
+    __ CallJSEntry(ip);
+  }
+
+  RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
+}
+
+
+void LCodeGen::DoCallFunction(LCallFunction* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->function()).is(r4));
+  DCHECK(ToRegister(instr->result()).is(r3));
+
+  int arity = instr->arity();
+  CallFunctionStub stub(isolate(), arity, instr->hydrogen()->function_flags());
+  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoCallNew(LCallNew* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->constructor()).is(r4));
+  DCHECK(ToRegister(instr->result()).is(r3));
+
+  __ mov(r3, Operand(instr->arity()));
+  // No cell in r5 for construct type feedback in optimized code
+  __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
+  CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
+  CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
+}
+
+
+void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->constructor()).is(r4));
+  DCHECK(ToRegister(instr->result()).is(r3));
+
+  __ mov(r3, Operand(instr->arity()));
+  __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
+  ElementsKind kind = instr->hydrogen()->elements_kind();
+  AllocationSiteOverrideMode override_mode =
+      (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
+          ? DISABLE_ALLOCATION_SITES
+          : DONT_OVERRIDE;
+
+  if (instr->arity() == 0) {
+    ArrayNoArgumentConstructorStub stub(isolate(), kind, override_mode);
+    CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
+  } else if (instr->arity() == 1) {
+    Label done;
+    if (IsFastPackedElementsKind(kind)) {
+      Label packed_case;
+      // We might need a change here
+      // look at the first argument
+      __ LoadP(r8, MemOperand(sp, 0));
+      __ cmpi(r8, Operand::Zero());
+      __ beq(&packed_case);
+
+      ElementsKind holey_kind = GetHoleyElementsKind(kind);
+      ArraySingleArgumentConstructorStub stub(isolate(), holey_kind,
+                                              override_mode);
+      CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
+      __ b(&done);
+      __ bind(&packed_case);
+    }
+
+    ArraySingleArgumentConstructorStub stub(isolate(), kind, override_mode);
+    CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
+    __ bind(&done);
+  } else {
+    ArrayNArgumentsConstructorStub stub(isolate(), kind, override_mode);
+    CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
+  }
+}
+
+
+void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
+  CallRuntime(instr->function(), instr->arity(), instr);
+}
+
+
+void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) {
+  Register function = ToRegister(instr->function());
+  Register code_object = ToRegister(instr->code_object());
+  __ addi(code_object, code_object,
+          Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ StoreP(code_object,
+            FieldMemOperand(function, JSFunction::kCodeEntryOffset), r0);
+}
+
+
+void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
+  Register result = ToRegister(instr->result());
+  Register base = ToRegister(instr->base_object());
+  if (instr->offset()->IsConstantOperand()) {
+    LConstantOperand* offset = LConstantOperand::cast(instr->offset());
+    __ Add(result, base, ToInteger32(offset), r0);
+  } else {
+    Register offset = ToRegister(instr->offset());
+    __ add(result, base, offset);
+  }
+}
+
+
+void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
+  HStoreNamedField* hinstr = instr->hydrogen();
+  Representation representation = instr->representation();
+
+  Register object = ToRegister(instr->object());
+  Register scratch = scratch0();
+  HObjectAccess access = hinstr->access();
+  int offset = access.offset();
+
+  if (access.IsExternalMemory()) {
+    Register value = ToRegister(instr->value());
+    MemOperand operand = MemOperand(object, offset);
+    __ StoreRepresentation(value, operand, representation, r0);
+    return;
+  }
+
+  __ AssertNotSmi(object);
+
+#if V8_TARGET_ARCH_PPC64
+  DCHECK(!representation.IsSmi() || !instr->value()->IsConstantOperand() ||
+         IsInteger32(LConstantOperand::cast(instr->value())));
+#else
+  DCHECK(!representation.IsSmi() || !instr->value()->IsConstantOperand() ||
+         IsSmi(LConstantOperand::cast(instr->value())));
+#endif
+  if (representation.IsDouble()) {
+    DCHECK(access.IsInobject());
+    DCHECK(!hinstr->has_transition());
+    DCHECK(!hinstr->NeedsWriteBarrier());
+    DoubleRegister value = ToDoubleRegister(instr->value());
+    __ stfd(value, FieldMemOperand(object, offset));
+    return;
+  }
+
+  if (hinstr->has_transition()) {
+    Handle<Map> transition = hinstr->transition_map();
+    AddDeprecationDependency(transition);
+    __ mov(scratch, Operand(transition));
+    __ StoreP(scratch, FieldMemOperand(object, HeapObject::kMapOffset), r0);
+    if (hinstr->NeedsWriteBarrierForMap()) {
+      Register temp = ToRegister(instr->temp());
+      // Update the write barrier for the map field.
+      __ RecordWriteForMap(object, scratch, temp, GetLinkRegisterState(),
+                           kSaveFPRegs);
+    }
+  }
+
+  // Do the store.
+  Register value = ToRegister(instr->value());
+
+#if V8_TARGET_ARCH_PPC64
+  // 64-bit Smi optimization
+  if (representation.IsSmi() &&
+      hinstr->value()->representation().IsInteger32()) {
+    DCHECK(hinstr->store_mode() == STORE_TO_INITIALIZED_ENTRY);
+    // Store int value directly to upper half of the smi.
+    STATIC_ASSERT(kSmiTag == 0);
+    STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
+#if V8_TARGET_LITTLE_ENDIAN
+    offset += kPointerSize / 2;
+#endif
+    representation = Representation::Integer32();
+  }
+#endif
+
+  if (access.IsInobject()) {
+    MemOperand operand = FieldMemOperand(object, offset);
+    __ StoreRepresentation(value, operand, representation, r0);
+    if (hinstr->NeedsWriteBarrier()) {
+      // Update the write barrier for the object for in-object properties.
+      __ RecordWriteField(
+          object, offset, value, scratch, GetLinkRegisterState(), kSaveFPRegs,
+          EMIT_REMEMBERED_SET, hinstr->SmiCheckForWriteBarrier(),
+          hinstr->PointersToHereCheckForValue());
+    }
+  } else {
+    __ LoadP(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset));
+    MemOperand operand = FieldMemOperand(scratch, offset);
+    __ StoreRepresentation(value, operand, representation, r0);
+    if (hinstr->NeedsWriteBarrier()) {
+      // Update the write barrier for the properties array.
+      // object is used as a scratch register.
+      __ RecordWriteField(
+          scratch, offset, value, object, GetLinkRegisterState(), kSaveFPRegs,
+          EMIT_REMEMBERED_SET, hinstr->SmiCheckForWriteBarrier(),
+          hinstr->PointersToHereCheckForValue());
+    }
+  }
+}
+
+
+void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->object()).is(StoreDescriptor::ReceiverRegister()));
+  DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
+
+  __ mov(StoreDescriptor::NameRegister(), Operand(instr->name()));
+  Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->strict_mode());
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
+  Representation representation = instr->hydrogen()->length()->representation();
+  DCHECK(representation.Equals(instr->hydrogen()->index()->representation()));
+  DCHECK(representation.IsSmiOrInteger32());
+
+  Condition cc = instr->hydrogen()->allow_equality() ? lt : le;
+  if (instr->length()->IsConstantOperand()) {
+    int32_t length = ToInteger32(LConstantOperand::cast(instr->length()));
+    Register index = ToRegister(instr->index());
+    if (representation.IsSmi()) {
+      __ Cmpli(index, Operand(Smi::FromInt(length)), r0);
+    } else {
+      __ Cmplwi(index, Operand(length), r0);
+    }
+    cc = CommuteCondition(cc);
+  } else if (instr->index()->IsConstantOperand()) {
+    int32_t index = ToInteger32(LConstantOperand::cast(instr->index()));
+    Register length = ToRegister(instr->length());
+    if (representation.IsSmi()) {
+      __ Cmpli(length, Operand(Smi::FromInt(index)), r0);
+    } else {
+      __ Cmplwi(length, Operand(index), r0);
+    }
+  } else {
+    Register index = ToRegister(instr->index());
+    Register length = ToRegister(instr->length());
+    if (representation.IsSmi()) {
+      __ cmpl(length, index);
+    } else {
+      __ cmplw(length, index);
+    }
+  }
+  if (FLAG_debug_code && instr->hydrogen()->skip_check()) {
+    Label done;
+    __ b(NegateCondition(cc), &done);
+    __ stop("eliminated bounds check failed");
+    __ bind(&done);
+  } else {
+    DeoptimizeIf(cc, instr, "out of bounds");
+  }
+}
+
+
+void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
+  Register external_pointer = ToRegister(instr->elements());
+  Register key = no_reg;
+  ElementsKind elements_kind = instr->elements_kind();
+  bool key_is_constant = instr->key()->IsConstantOperand();
+  int constant_key = 0;
+  if (key_is_constant) {
+    constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
+    if (constant_key & 0xF0000000) {
+      Abort(kArrayIndexConstantValueTooBig);
+    }
+  } else {
+    key = ToRegister(instr->key());
+  }
+  int element_size_shift = ElementsKindToShiftSize(elements_kind);
+  bool key_is_smi = instr->hydrogen()->key()->representation().IsSmi();
+  int base_offset = instr->base_offset();
+
+  if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+      elements_kind == FLOAT32_ELEMENTS ||
+      elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
+      elements_kind == FLOAT64_ELEMENTS) {
+    Register address = scratch0();
+    DoubleRegister value(ToDoubleRegister(instr->value()));
+    if (key_is_constant) {
+      if (constant_key != 0) {
+        __ Add(address, external_pointer, constant_key << element_size_shift,
+               r0);
+      } else {
+        address = external_pointer;
+      }
+    } else {
+      __ IndexToArrayOffset(r0, key, element_size_shift, key_is_smi);
+      __ add(address, external_pointer, r0);
+    }
+    if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
+        elements_kind == FLOAT32_ELEMENTS) {
+      __ frsp(double_scratch0(), value);
+      __ stfs(double_scratch0(), MemOperand(address, base_offset));
+    } else {  // Storing doubles, not floats.
+      __ stfd(value, MemOperand(address, base_offset));
+    }
+  } else {
+    Register value(ToRegister(instr->value()));
+    MemOperand mem_operand =
+        PrepareKeyedOperand(key, external_pointer, key_is_constant, key_is_smi,
+                            constant_key, element_size_shift, base_offset);
+    switch (elements_kind) {
+      case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+      case EXTERNAL_INT8_ELEMENTS:
+      case EXTERNAL_UINT8_ELEMENTS:
+      case UINT8_ELEMENTS:
+      case UINT8_CLAMPED_ELEMENTS:
+      case INT8_ELEMENTS:
+        if (key_is_constant) {
+          __ StoreByte(value, mem_operand, r0);
+        } else {
+          __ stbx(value, mem_operand);
+        }
+        break;
+      case EXTERNAL_INT16_ELEMENTS:
+      case EXTERNAL_UINT16_ELEMENTS:
+      case INT16_ELEMENTS:
+      case UINT16_ELEMENTS:
+        if (key_is_constant) {
+          __ StoreHalfWord(value, mem_operand, r0);
+        } else {
+          __ sthx(value, mem_operand);
+        }
+        break;
+      case EXTERNAL_INT32_ELEMENTS:
+      case EXTERNAL_UINT32_ELEMENTS:
+      case INT32_ELEMENTS:
+      case UINT32_ELEMENTS:
+        if (key_is_constant) {
+          __ StoreWord(value, mem_operand, r0);
+        } else {
+          __ stwx(value, mem_operand);
+        }
+        break;
+      case FLOAT32_ELEMENTS:
+      case FLOAT64_ELEMENTS:
+      case EXTERNAL_FLOAT32_ELEMENTS:
+      case EXTERNAL_FLOAT64_ELEMENTS:
+      case FAST_DOUBLE_ELEMENTS:
+      case FAST_ELEMENTS:
+      case FAST_SMI_ELEMENTS:
+      case FAST_HOLEY_DOUBLE_ELEMENTS:
+      case FAST_HOLEY_ELEMENTS:
+      case FAST_HOLEY_SMI_ELEMENTS:
+      case DICTIONARY_ELEMENTS:
+      case SLOPPY_ARGUMENTS_ELEMENTS:
+        UNREACHABLE();
+        break;
+    }
+  }
+}
+
+
+void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
+  DoubleRegister value = ToDoubleRegister(instr->value());
+  Register elements = ToRegister(instr->elements());
+  Register key = no_reg;
+  Register scratch = scratch0();
+  DoubleRegister double_scratch = double_scratch0();
+  bool key_is_constant = instr->key()->IsConstantOperand();
+  int constant_key = 0;
+
+  // Calculate the effective address of the slot in the array to store the
+  // double value.
+  if (key_is_constant) {
+    constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
+    if (constant_key & 0xF0000000) {
+      Abort(kArrayIndexConstantValueTooBig);
+    }
+  } else {
+    key = ToRegister(instr->key());
+  }
+  int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
+  bool key_is_smi = instr->hydrogen()->key()->representation().IsSmi();
+  int base_offset = instr->base_offset() + constant_key * kDoubleSize;
+  if (!key_is_constant) {
+    __ IndexToArrayOffset(scratch, key, element_size_shift, key_is_smi);
+    __ add(scratch, elements, scratch);
+    elements = scratch;
+  }
+  if (!is_int16(base_offset)) {
+    __ Add(scratch, elements, base_offset, r0);
+    base_offset = 0;
+    elements = scratch;
+  }
+
+  if (instr->NeedsCanonicalization()) {
+    // Force a canonical NaN.
+    __ CanonicalizeNaN(double_scratch, value);
+    __ stfd(double_scratch, MemOperand(elements, base_offset));
+  } else {
+    __ stfd(value, MemOperand(elements, base_offset));
+  }
+}
+
+
+void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
+  HStoreKeyed* hinstr = instr->hydrogen();
+  Register value = ToRegister(instr->value());
+  Register elements = ToRegister(instr->elements());
+  Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
+  Register scratch = scratch0();
+  Register store_base = scratch;
+  int offset = instr->base_offset();
+
+  // Do the store.
+  if (instr->key()->IsConstantOperand()) {
+    DCHECK(!hinstr->NeedsWriteBarrier());
+    LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
+    offset += ToInteger32(const_operand) * kPointerSize;
+    store_base = elements;
+  } else {
+    // Even though the HLoadKeyed instruction forces the input
+    // representation for the key to be an integer, the input gets replaced
+    // during bound check elimination with the index argument to the bounds
+    // check, which can be tagged, so that case must be handled here, too.
+    if (hinstr->key()->representation().IsSmi()) {
+      __ SmiToPtrArrayOffset(scratch, key);
+    } else {
+      __ ShiftLeftImm(scratch, key, Operand(kPointerSizeLog2));
+    }
+    __ add(scratch, elements, scratch);
+  }
+
+  Representation representation = hinstr->value()->representation();
+
+#if V8_TARGET_ARCH_PPC64
+  // 64-bit Smi optimization
+  if (representation.IsInteger32()) {
+    DCHECK(hinstr->store_mode() == STORE_TO_INITIALIZED_ENTRY);
+    DCHECK(hinstr->elements_kind() == FAST_SMI_ELEMENTS);
+    // Store int value directly to upper half of the smi.
+    STATIC_ASSERT(kSmiTag == 0);
+    STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
+#if V8_TARGET_LITTLE_ENDIAN
+    offset += kPointerSize / 2;
+#endif
+  }
+#endif
+
+  __ StoreRepresentation(value, MemOperand(store_base, offset), representation,
+                         r0);
+
+  if (hinstr->NeedsWriteBarrier()) {
+    SmiCheck check_needed = hinstr->value()->type().IsHeapObject()
+                                ? OMIT_SMI_CHECK
+                                : INLINE_SMI_CHECK;
+    // Compute address of modified element and store it into key register.
+    __ Add(key, store_base, offset, r0);
+    __ RecordWrite(elements, key, value, GetLinkRegisterState(), kSaveFPRegs,
+                   EMIT_REMEMBERED_SET, check_needed,
+                   hinstr->PointersToHereCheckForValue());
+  }
+}
+
+
+void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
+  // By cases: external, fast double
+  if (instr->is_typed_elements()) {
+    DoStoreKeyedExternalArray(instr);
+  } else if (instr->hydrogen()->value()->representation().IsDouble()) {
+    DoStoreKeyedFixedDoubleArray(instr);
+  } else {
+    DoStoreKeyedFixedArray(instr);
+  }
+}
+
+
+void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->object()).is(StoreDescriptor::ReceiverRegister()));
+  DCHECK(ToRegister(instr->key()).is(StoreDescriptor::NameRegister()));
+  DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
+
+  Handle<Code> ic =
+      CodeFactory::KeyedStoreIC(isolate(), instr->strict_mode()).code();
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
+  Register object_reg = ToRegister(instr->object());
+  Register scratch = scratch0();
+
+  Handle<Map> from_map = instr->original_map();
+  Handle<Map> to_map = instr->transitioned_map();
+  ElementsKind from_kind = instr->from_kind();
+  ElementsKind to_kind = instr->to_kind();
+
+  Label not_applicable;
+  __ LoadP(scratch, FieldMemOperand(object_reg, HeapObject::kMapOffset));
+  __ Cmpi(scratch, Operand(from_map), r0);
+  __ bne(&not_applicable);
+
+  if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
+    Register new_map_reg = ToRegister(instr->new_map_temp());
+    __ mov(new_map_reg, Operand(to_map));
+    __ StoreP(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset),
+              r0);
+    // Write barrier.
+    __ RecordWriteForMap(object_reg, new_map_reg, scratch,
+                         GetLinkRegisterState(), kDontSaveFPRegs);
+  } else {
+    DCHECK(ToRegister(instr->context()).is(cp));
+    DCHECK(object_reg.is(r3));
+    PushSafepointRegistersScope scope(this);
+    __ Move(r4, to_map);
+    bool is_js_array = from_map->instance_type() == JS_ARRAY_TYPE;
+    TransitionElementsKindStub stub(isolate(), from_kind, to_kind, is_js_array);
+    __ CallStub(&stub);
+    RecordSafepointWithRegisters(instr->pointer_map(), 0,
+                                 Safepoint::kLazyDeopt);
+  }
+  __ bind(&not_applicable);
+}
+
+
+void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
+  Register object = ToRegister(instr->object());
+  Register temp = ToRegister(instr->temp());
+  Label no_memento_found;
+  __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found);
+  DeoptimizeIf(eq, instr, "memento found");
+  __ bind(&no_memento_found);
+}
+
+
+void LCodeGen::DoStringAdd(LStringAdd* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->left()).is(r4));
+  DCHECK(ToRegister(instr->right()).is(r3));
+  StringAddStub stub(isolate(), instr->hydrogen()->flags(),
+                     instr->hydrogen()->pretenure_flag());
+  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
+  class DeferredStringCharCodeAt FINAL : public LDeferredCode {
+   public:
+    DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
+        : LDeferredCode(codegen), instr_(instr) {}
+    void Generate() OVERRIDE { codegen()->DoDeferredStringCharCodeAt(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
+   private:
+    LStringCharCodeAt* instr_;
+  };
+
+  DeferredStringCharCodeAt* deferred =
+      new (zone()) DeferredStringCharCodeAt(this, instr);
+
+  StringCharLoadGenerator::Generate(
+      masm(), ToRegister(instr->string()), ToRegister(instr->index()),
+      ToRegister(instr->result()), deferred->entry());
+  __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
+  Register string = ToRegister(instr->string());
+  Register result = ToRegister(instr->result());
+  Register scratch = scratch0();
+
+  // TODO(3095996): Get rid of this. For now, we need to make the
+  // result register contain a valid pointer because it is already
+  // contained in the register pointer map.
+  __ li(result, Operand::Zero());
+
+  PushSafepointRegistersScope scope(this);
+  __ push(string);
+  // Push the index as a smi. This is safe because of the checks in
+  // DoStringCharCodeAt above.
+  if (instr->index()->IsConstantOperand()) {
+    int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
+    __ LoadSmiLiteral(scratch, Smi::FromInt(const_index));
+    __ push(scratch);
+  } else {
+    Register index = ToRegister(instr->index());
+    __ SmiTag(index);
+    __ push(index);
+  }
+  CallRuntimeFromDeferred(Runtime::kStringCharCodeAtRT, 2, instr,
+                          instr->context());
+  __ AssertSmi(r3);
+  __ SmiUntag(r3);
+  __ StoreToSafepointRegisterSlot(r3, result);
+}
+
+
+void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
+  class DeferredStringCharFromCode FINAL : public LDeferredCode {
+   public:
+    DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
+        : LDeferredCode(codegen), instr_(instr) {}
+    void Generate() OVERRIDE {
+      codegen()->DoDeferredStringCharFromCode(instr_);
+    }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
+   private:
+    LStringCharFromCode* instr_;
+  };
+
+  DeferredStringCharFromCode* deferred =
+      new (zone()) DeferredStringCharFromCode(this, instr);
+
+  DCHECK(instr->hydrogen()->value()->representation().IsInteger32());
+  Register char_code = ToRegister(instr->char_code());
+  Register result = ToRegister(instr->result());
+  DCHECK(!char_code.is(result));
+
+  __ cmpli(char_code, Operand(String::kMaxOneByteCharCode));
+  __ bgt(deferred->entry());
+  __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
+  __ ShiftLeftImm(r0, char_code, Operand(kPointerSizeLog2));
+  __ add(result, result, r0);
+  __ LoadP(result, FieldMemOperand(result, FixedArray::kHeaderSize));
+  __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+  __ cmp(result, ip);
+  __ beq(deferred->entry());
+  __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
+  Register char_code = ToRegister(instr->char_code());
+  Register result = ToRegister(instr->result());
+
+  // TODO(3095996): Get rid of this. For now, we need to make the
+  // result register contain a valid pointer because it is already
+  // contained in the register pointer map.
+  __ li(result, Operand::Zero());
+
+  PushSafepointRegistersScope scope(this);
+  __ SmiTag(char_code);
+  __ push(char_code);
+  CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
+  __ StoreToSafepointRegisterSlot(r3, result);
+}
+
+
+void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
+  LOperand* input = instr->value();
+  DCHECK(input->IsRegister() || input->IsStackSlot());
+  LOperand* output = instr->result();
+  DCHECK(output->IsDoubleRegister());
+  if (input->IsStackSlot()) {
+    Register scratch = scratch0();
+    __ LoadP(scratch, ToMemOperand(input));
+    __ ConvertIntToDouble(scratch, ToDoubleRegister(output));
+  } else {
+    __ ConvertIntToDouble(ToRegister(input), ToDoubleRegister(output));
+  }
+}
+
+
+void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
+  LOperand* input = instr->value();
+  LOperand* output = instr->result();
+  __ ConvertUnsignedIntToDouble(ToRegister(input), ToDoubleRegister(output));
+}
+
+
+void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
+  class DeferredNumberTagI FINAL : public LDeferredCode {
+   public:
+    DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
+        : LDeferredCode(codegen), instr_(instr) {}
+    void Generate() OVERRIDE {
+      codegen()->DoDeferredNumberTagIU(instr_, instr_->value(), instr_->temp1(),
+                                       instr_->temp2(), SIGNED_INT32);
+    }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
+   private:
+    LNumberTagI* instr_;
+  };
+
+  Register src = ToRegister(instr->value());
+  Register dst = ToRegister(instr->result());
+
+  DeferredNumberTagI* deferred = new (zone()) DeferredNumberTagI(this, instr);
+#if V8_TARGET_ARCH_PPC64
+  __ SmiTag(dst, src);
+#else
+  __ SmiTagCheckOverflow(dst, src, r0);
+  __ BranchOnOverflow(deferred->entry());
+#endif
+  __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
+  class DeferredNumberTagU FINAL : public LDeferredCode {
+   public:
+    DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
+        : LDeferredCode(codegen), instr_(instr) {}
+    void Generate() OVERRIDE {
+      codegen()->DoDeferredNumberTagIU(instr_, instr_->value(), instr_->temp1(),
+                                       instr_->temp2(), UNSIGNED_INT32);
+    }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
+   private:
+    LNumberTagU* instr_;
+  };
+
+  Register input = ToRegister(instr->value());
+  Register result = ToRegister(instr->result());
+
+  DeferredNumberTagU* deferred = new (zone()) DeferredNumberTagU(this, instr);
+  __ Cmpli(input, Operand(Smi::kMaxValue), r0);
+  __ bgt(deferred->entry());
+  __ SmiTag(result, input);
+  __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredNumberTagIU(LInstruction* instr, LOperand* value,
+                                     LOperand* temp1, LOperand* temp2,
+                                     IntegerSignedness signedness) {
+  Label done, slow;
+  Register src = ToRegister(value);
+  Register dst = ToRegister(instr->result());
+  Register tmp1 = scratch0();
+  Register tmp2 = ToRegister(temp1);
+  Register tmp3 = ToRegister(temp2);
+  DoubleRegister dbl_scratch = double_scratch0();
+
+  if (signedness == SIGNED_INT32) {
+    // There was overflow, so bits 30 and 31 of the original integer
+    // disagree. Try to allocate a heap number in new space and store
+    // the value in there. If that fails, call the runtime system.
+    if (dst.is(src)) {
+      __ SmiUntag(src, dst);
+      __ xoris(src, src, Operand(HeapNumber::kSignMask >> 16));
+    }
+    __ ConvertIntToDouble(src, dbl_scratch);
+  } else {
+    __ ConvertUnsignedIntToDouble(src, dbl_scratch);
+  }
+
+  if (FLAG_inline_new) {
+    __ LoadRoot(tmp3, Heap::kHeapNumberMapRootIndex);
+    __ AllocateHeapNumber(dst, tmp1, tmp2, tmp3, &slow);
+    __ b(&done);
+  }
+
+  // Slow case: Call the runtime system to do the number allocation.
+  __ bind(&slow);
+  {
+    // TODO(3095996): Put a valid pointer value in the stack slot where the
+    // result register is stored, as this register is in the pointer map, but
+    // contains an integer value.
+    __ li(dst, Operand::Zero());
+
+    // Preserve the value of all registers.
+    PushSafepointRegistersScope scope(this);
+
+    // NumberTagI and NumberTagD use the context from the frame, rather than
+    // the environment's HContext or HInlinedContext value.
+    // They only call Runtime::kAllocateHeapNumber.
+    // The corresponding HChange instructions are added in a phase that does
+    // not have easy access to the local context.
+    __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
+    RecordSafepointWithRegisters(instr->pointer_map(), 0,
+                                 Safepoint::kNoLazyDeopt);
+    __ StoreToSafepointRegisterSlot(r3, dst);
+  }
+
+  // Done. Put the value in dbl_scratch into the value of the allocated heap
+  // number.
+  __ bind(&done);
+  __ stfd(dbl_scratch, FieldMemOperand(dst, HeapNumber::kValueOffset));
+}
+
+
+void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
+  class DeferredNumberTagD FINAL : public LDeferredCode {
+   public:
+    DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
+        : LDeferredCode(codegen), instr_(instr) {}
+    void Generate() OVERRIDE { codegen()->DoDeferredNumberTagD(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
+   private:
+    LNumberTagD* instr_;
+  };
+
+  DoubleRegister input_reg = ToDoubleRegister(instr->value());
+  Register scratch = scratch0();
+  Register reg = ToRegister(instr->result());
+  Register temp1 = ToRegister(instr->temp());
+  Register temp2 = ToRegister(instr->temp2());
+
+  DeferredNumberTagD* deferred = new (zone()) DeferredNumberTagD(this, instr);
+  if (FLAG_inline_new) {
+    __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex);
+    __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry());
+  } else {
+    __ b(deferred->entry());
+  }
+  __ bind(deferred->exit());
+  __ stfd(input_reg, FieldMemOperand(reg, HeapNumber::kValueOffset));
+}
+
+
+void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
+  // TODO(3095996): Get rid of this. For now, we need to make the
+  // result register contain a valid pointer because it is already
+  // contained in the register pointer map.
+  Register reg = ToRegister(instr->result());
+  __ li(reg, Operand::Zero());
+
+  PushSafepointRegistersScope scope(this);
+  // NumberTagI and NumberTagD use the context from the frame, rather than
+  // the environment's HContext or HInlinedContext value.
+  // They only call Runtime::kAllocateHeapNumber.
+  // The corresponding HChange instructions are added in a phase that does
+  // not have easy access to the local context.
+  __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
+  RecordSafepointWithRegisters(instr->pointer_map(), 0,
+                               Safepoint::kNoLazyDeopt);
+  __ StoreToSafepointRegisterSlot(r3, reg);
+}
+
+
+void LCodeGen::DoSmiTag(LSmiTag* instr) {
+  HChange* hchange = instr->hydrogen();
+  Register input = ToRegister(instr->value());
+  Register output = ToRegister(instr->result());
+  if (hchange->CheckFlag(HValue::kCanOverflow) &&
+      hchange->value()->CheckFlag(HValue::kUint32)) {
+    __ TestUnsignedSmiCandidate(input, r0);
+    DeoptimizeIf(ne, instr, "overflow", cr0);
+  }
+#if !V8_TARGET_ARCH_PPC64
+  if (hchange->CheckFlag(HValue::kCanOverflow) &&
+      !hchange->value()->CheckFlag(HValue::kUint32)) {
+    __ SmiTagCheckOverflow(output, input, r0);
+    DeoptimizeIf(lt, instr, "overflow", cr0);
+  } else {
+#endif
+    __ SmiTag(output, input);
+#if !V8_TARGET_ARCH_PPC64
+  }
+#endif
+}
+
+
+void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
+  Register scratch = scratch0();
+  Register input = ToRegister(instr->value());
+  Register result = ToRegister(instr->result());
+  if (instr->needs_check()) {
+    STATIC_ASSERT(kHeapObjectTag == 1);
+    // If the input is a HeapObject, value of scratch won't be zero.
+    __ andi(scratch, input, Operand(kHeapObjectTag));
+    __ SmiUntag(result, input);
+    DeoptimizeIf(ne, instr, "not a Smi", cr0);
+  } else {
+    __ SmiUntag(result, input);
+  }
+}
+
+
+void LCodeGen::EmitNumberUntagD(LNumberUntagD* instr, Register input_reg,
+                                DoubleRegister result_reg,
+                                NumberUntagDMode mode) {
+  bool can_convert_undefined_to_nan =
+      instr->hydrogen()->can_convert_undefined_to_nan();
+  bool deoptimize_on_minus_zero = instr->hydrogen()->deoptimize_on_minus_zero();
+
+  Register scratch = scratch0();
+  DCHECK(!result_reg.is(double_scratch0()));
+
+  Label convert, load_smi, done;
+
+  if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
+    // Smi check.
+    __ UntagAndJumpIfSmi(scratch, input_reg, &load_smi);
+
+    // Heap number map check.
+    __ LoadP(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
+    __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
+    __ cmp(scratch, ip);
+    if (can_convert_undefined_to_nan) {
+      __ bne(&convert);
+    } else {
+      DeoptimizeIf(ne, instr, "not a heap number");
+    }
+    // load heap number
+    __ lfd(result_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset));
+    if (deoptimize_on_minus_zero) {
+#if V8_TARGET_ARCH_PPC64
+      __ MovDoubleToInt64(scratch, result_reg);
+      // rotate left by one for simple compare.
+      __ rldicl(scratch, scratch, 1, 0);
+      __ cmpi(scratch, Operand(1));
+#else
+      __ MovDoubleToInt64(scratch, ip, result_reg);
+      __ cmpi(ip, Operand::Zero());
+      __ bne(&done);
+      __ Cmpi(scratch, Operand(HeapNumber::kSignMask), r0);
+#endif
+      DeoptimizeIf(eq, instr, "minus zero");
+    }
+    __ b(&done);
+    if (can_convert_undefined_to_nan) {
+      __ bind(&convert);
+      // Convert undefined (and hole) to NaN.
+      __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+      __ cmp(input_reg, ip);
+      DeoptimizeIf(ne, instr, "not a heap number/undefined");
+      __ LoadRoot(scratch, Heap::kNanValueRootIndex);
+      __ lfd(result_reg, FieldMemOperand(scratch, HeapNumber::kValueOffset));
+      __ b(&done);
+    }
+  } else {
+    __ SmiUntag(scratch, input_reg);
+    DCHECK(mode == NUMBER_CANDIDATE_IS_SMI);
+  }
+  // Smi to double register conversion
+  __ bind(&load_smi);
+  // scratch: untagged value of input_reg
+  __ ConvertIntToDouble(scratch, result_reg);
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
+  Register input_reg = ToRegister(instr->value());
+  Register scratch1 = scratch0();
+  Register scratch2 = ToRegister(instr->temp());
+  DoubleRegister double_scratch = double_scratch0();
+  DoubleRegister double_scratch2 = ToDoubleRegister(instr->temp2());
+
+  DCHECK(!scratch1.is(input_reg) && !scratch1.is(scratch2));
+  DCHECK(!scratch2.is(input_reg) && !scratch2.is(scratch1));
+
+  Label done;
+
+  // Heap number map check.
+  __ LoadP(scratch1, FieldMemOperand(input_reg, HeapObject::kMapOffset));
+  __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
+  __ cmp(scratch1, ip);
+
+  if (instr->truncating()) {
+    // Performs a truncating conversion of a floating point number as used by
+    // the JS bitwise operations.
+    Label no_heap_number, check_bools, check_false;
+    __ bne(&no_heap_number);
+    __ mr(scratch2, input_reg);
+    __ TruncateHeapNumberToI(input_reg, scratch2);
+    __ b(&done);
+
+    // Check for Oddballs. Undefined/False is converted to zero and True to one
+    // for truncating conversions.
+    __ bind(&no_heap_number);
+    __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+    __ cmp(input_reg, ip);
+    __ bne(&check_bools);
+    __ li(input_reg, Operand::Zero());
+    __ b(&done);
+
+    __ bind(&check_bools);
+    __ LoadRoot(ip, Heap::kTrueValueRootIndex);
+    __ cmp(input_reg, ip);
+    __ bne(&check_false);
+    __ li(input_reg, Operand(1));
+    __ b(&done);
+
+    __ bind(&check_false);
+    __ LoadRoot(ip, Heap::kFalseValueRootIndex);
+    __ cmp(input_reg, ip);
+    DeoptimizeIf(ne, instr, "not a heap number/undefined/true/false", cr7);
+    __ li(input_reg, Operand::Zero());
+  } else {
+    DeoptimizeIf(ne, instr, "not a heap number", cr7);
+
+    __ lfd(double_scratch2,
+           FieldMemOperand(input_reg, HeapNumber::kValueOffset));
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      // preserve heap number pointer in scratch2 for minus zero check below
+      __ mr(scratch2, input_reg);
+    }
+    __ TryDoubleToInt32Exact(input_reg, double_scratch2, scratch1,
+                             double_scratch);
+    DeoptimizeIf(ne, instr, "lost precision or NaN", cr7);
+
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      __ cmpi(input_reg, Operand::Zero());
+      __ bne(&done);
+      __ lwz(scratch1,
+             FieldMemOperand(scratch2, HeapNumber::kValueOffset +
+                                           Register::kExponentOffset));
+      __ cmpwi(scratch1, Operand::Zero());
+      DeoptimizeIf(lt, instr, "minus zero", cr7);
+    }
+  }
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
+  class DeferredTaggedToI FINAL : public LDeferredCode {
+   public:
+    DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
+        : LDeferredCode(codegen), instr_(instr) {}
+    void Generate() OVERRIDE { codegen()->DoDeferredTaggedToI(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
+   private:
+    LTaggedToI* instr_;
+  };
+
+  LOperand* input = instr->value();
+  DCHECK(input->IsRegister());
+  DCHECK(input->Equals(instr->result()));
+
+  Register input_reg = ToRegister(input);
+
+  if (instr->hydrogen()->value()->representation().IsSmi()) {
+    __ SmiUntag(input_reg);
+  } else {
+    DeferredTaggedToI* deferred = new (zone()) DeferredTaggedToI(this, instr);
+
+    // Branch to deferred code if the input is a HeapObject.
+    __ JumpIfNotSmi(input_reg, deferred->entry());
+
+    __ SmiUntag(input_reg);
+    __ bind(deferred->exit());
+  }
+}
+
+
+void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
+  LOperand* input = instr->value();
+  DCHECK(input->IsRegister());
+  LOperand* result = instr->result();
+  DCHECK(result->IsDoubleRegister());
+
+  Register input_reg = ToRegister(input);
+  DoubleRegister result_reg = ToDoubleRegister(result);
+
+  HValue* value = instr->hydrogen()->value();
+  NumberUntagDMode mode = value->representation().IsSmi()
+                              ? NUMBER_CANDIDATE_IS_SMI
+                              : NUMBER_CANDIDATE_IS_ANY_TAGGED;
+
+  EmitNumberUntagD(instr, input_reg, result_reg, mode);
+}
+
+
+void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
+  Register result_reg = ToRegister(instr->result());
+  Register scratch1 = scratch0();
+  DoubleRegister double_input = ToDoubleRegister(instr->value());
+  DoubleRegister double_scratch = double_scratch0();
+
+  if (instr->truncating()) {
+    __ TruncateDoubleToI(result_reg, double_input);
+  } else {
+    __ TryDoubleToInt32Exact(result_reg, double_input, scratch1,
+                             double_scratch);
+    // Deoptimize if the input wasn't a int32 (inside a double).
+    DeoptimizeIf(ne, instr, "lost precision or NaN");
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      Label done;
+      __ cmpi(result_reg, Operand::Zero());
+      __ bne(&done);
+#if V8_TARGET_ARCH_PPC64
+      __ MovDoubleToInt64(scratch1, double_input);
+#else
+      __ MovDoubleHighToInt(scratch1, double_input);
+#endif
+      __ cmpi(scratch1, Operand::Zero());
+      DeoptimizeIf(lt, instr, "minus zero");
+      __ bind(&done);
+    }
+  }
+}
+
+
+void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
+  Register result_reg = ToRegister(instr->result());
+  Register scratch1 = scratch0();
+  DoubleRegister double_input = ToDoubleRegister(instr->value());
+  DoubleRegister double_scratch = double_scratch0();
+
+  if (instr->truncating()) {
+    __ TruncateDoubleToI(result_reg, double_input);
+  } else {
+    __ TryDoubleToInt32Exact(result_reg, double_input, scratch1,
+                             double_scratch);
+    // Deoptimize if the input wasn't a int32 (inside a double).
+    DeoptimizeIf(ne, instr, "lost precision or NaN");
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      Label done;
+      __ cmpi(result_reg, Operand::Zero());
+      __ bne(&done);
+#if V8_TARGET_ARCH_PPC64
+      __ MovDoubleToInt64(scratch1, double_input);
+#else
+      __ MovDoubleHighToInt(scratch1, double_input);
+#endif
+      __ cmpi(scratch1, Operand::Zero());
+      DeoptimizeIf(lt, instr, "minus zero");
+      __ bind(&done);
+    }
+  }
+#if V8_TARGET_ARCH_PPC64
+  __ SmiTag(result_reg);
+#else
+  __ SmiTagCheckOverflow(result_reg, r0);
+  DeoptimizeIf(lt, instr, "overflow", cr0);
+#endif
+}
+
+
+void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
+  LOperand* input = instr->value();
+  __ TestIfSmi(ToRegister(input), r0);
+  DeoptimizeIf(ne, instr, "not a Smi", cr0);
+}
+
+
+void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
+  if (!instr->hydrogen()->value()->type().IsHeapObject()) {
+    LOperand* input = instr->value();
+    __ TestIfSmi(ToRegister(input), r0);
+    DeoptimizeIf(eq, instr, "Smi", cr0);
+  }
+}
+
+
+void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
+  Register input = ToRegister(instr->value());
+  Register scratch = scratch0();
+
+  __ LoadP(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
+  __ lbz(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+
+  if (instr->hydrogen()->is_interval_check()) {
+    InstanceType first;
+    InstanceType last;
+    instr->hydrogen()->GetCheckInterval(&first, &last);
+
+    __ cmpli(scratch, Operand(first));
+
+    // If there is only one type in the interval check for equality.
+    if (first == last) {
+      DeoptimizeIf(ne, instr, "wrong instance type");
+    } else {
+      DeoptimizeIf(lt, instr, "wrong instance type");
+      // Omit check for the last type.
+      if (last != LAST_TYPE) {
+        __ cmpli(scratch, Operand(last));
+        DeoptimizeIf(gt, instr, "wrong instance type");
+      }
+    }
+  } else {
+    uint8_t mask;
+    uint8_t tag;
+    instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
+
+    if (base::bits::IsPowerOfTwo32(mask)) {
+      DCHECK(tag == 0 || base::bits::IsPowerOfTwo32(tag));
+      __ andi(r0, scratch, Operand(mask));
+      DeoptimizeIf(tag == 0 ? ne : eq, instr, "wrong instance type", cr0);
+    } else {
+      __ andi(scratch, scratch, Operand(mask));
+      __ cmpi(scratch, Operand(tag));
+      DeoptimizeIf(ne, instr, "wrong instance type");
+    }
+  }
+}
+
+
+void LCodeGen::DoCheckValue(LCheckValue* instr) {
+  Register reg = ToRegister(instr->value());
+  Handle<HeapObject> object = instr->hydrogen()->object().handle();
+  AllowDeferredHandleDereference smi_check;
+  if (isolate()->heap()->InNewSpace(*object)) {
+    Register reg = ToRegister(instr->value());
+    Handle<Cell> cell = isolate()->factory()->NewCell(object);
+    __ mov(ip, Operand(Handle<Object>(cell)));
+    __ LoadP(ip, FieldMemOperand(ip, Cell::kValueOffset));
+    __ cmp(reg, ip);
+  } else {
+    __ Cmpi(reg, Operand(object), r0);
+  }
+  DeoptimizeIf(ne, instr, "value mismatch");
+}
+
+
+void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
+  {
+    PushSafepointRegistersScope scope(this);
+    __ push(object);
+    __ li(cp, Operand::Zero());
+    __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance);
+    RecordSafepointWithRegisters(instr->pointer_map(), 1,
+                                 Safepoint::kNoLazyDeopt);
+    __ StoreToSafepointRegisterSlot(r3, scratch0());
+  }
+  __ TestIfSmi(scratch0(), r0);
+  DeoptimizeIf(eq, instr, "instance migration failed", cr0);
+}
+
+
+void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
+  class DeferredCheckMaps FINAL : public LDeferredCode {
+   public:
+    DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object)
+        : LDeferredCode(codegen), instr_(instr), object_(object) {
+      SetExit(check_maps());
+    }
+    void Generate() OVERRIDE {
+      codegen()->DoDeferredInstanceMigration(instr_, object_);
+    }
+    Label* check_maps() { return &check_maps_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
+   private:
+    LCheckMaps* instr_;
+    Label check_maps_;
+    Register object_;
+  };
+
+  if (instr->hydrogen()->IsStabilityCheck()) {
+    const UniqueSet<Map>* maps = instr->hydrogen()->maps();
+    for (int i = 0; i < maps->size(); ++i) {
+      AddStabilityDependency(maps->at(i).handle());
+    }
+    return;
+  }
+
+  Register map_reg = scratch0();
+
+  LOperand* input = instr->value();
+  DCHECK(input->IsRegister());
+  Register reg = ToRegister(input);
+
+  __ LoadP(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
+
+  DeferredCheckMaps* deferred = NULL;
+  if (instr->hydrogen()->HasMigrationTarget()) {
+    deferred = new (zone()) DeferredCheckMaps(this, instr, reg);
+    __ bind(deferred->check_maps());
+  }
+
+  const UniqueSet<Map>* maps = instr->hydrogen()->maps();
+  Label success;
+  for (int i = 0; i < maps->size() - 1; i++) {
+    Handle<Map> map = maps->at(i).handle();
+    __ CompareMap(map_reg, map, &success);
+    __ beq(&success);
+  }
+
+  Handle<Map> map = maps->at(maps->size() - 1).handle();
+  __ CompareMap(map_reg, map, &success);
+  if (instr->hydrogen()->HasMigrationTarget()) {
+    __ bne(deferred->entry());
+  } else {
+    DeoptimizeIf(ne, instr, "wrong map");
+  }
+
+  __ bind(&success);
+}
+
+
+void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
+  DoubleRegister value_reg = ToDoubleRegister(instr->unclamped());
+  Register result_reg = ToRegister(instr->result());
+  __ ClampDoubleToUint8(result_reg, value_reg, double_scratch0());
+}
+
+
+void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
+  Register unclamped_reg = ToRegister(instr->unclamped());
+  Register result_reg = ToRegister(instr->result());
+  __ ClampUint8(result_reg, unclamped_reg);
+}
+
+
+void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
+  Register scratch = scratch0();
+  Register input_reg = ToRegister(instr->unclamped());
+  Register result_reg = ToRegister(instr->result());
+  DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
+  Label is_smi, done, heap_number;
+
+  // Both smi and heap number cases are handled.
+  __ UntagAndJumpIfSmi(result_reg, input_reg, &is_smi);
+
+  // Check for heap number
+  __ LoadP(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
+  __ Cmpi(scratch, Operand(factory()->heap_number_map()), r0);
+  __ beq(&heap_number);
+
+  // Check for undefined. Undefined is converted to zero for clamping
+  // conversions.
+  __ Cmpi(input_reg, Operand(factory()->undefined_value()), r0);
+  DeoptimizeIf(ne, instr, "not a heap number/undefined");
+  __ li(result_reg, Operand::Zero());
+  __ b(&done);
+
+  // Heap number
+  __ bind(&heap_number);
+  __ lfd(temp_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset));
+  __ ClampDoubleToUint8(result_reg, temp_reg, double_scratch0());
+  __ b(&done);
+
+  // smi
+  __ bind(&is_smi);
+  __ ClampUint8(result_reg, result_reg);
+
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoDoubleBits(LDoubleBits* instr) {
+  DoubleRegister value_reg = ToDoubleRegister(instr->value());
+  Register result_reg = ToRegister(instr->result());
+
+  if (instr->hydrogen()->bits() == HDoubleBits::HIGH) {
+    __ MovDoubleHighToInt(result_reg, value_reg);
+  } else {
+    __ MovDoubleLowToInt(result_reg, value_reg);
+  }
+}
+
+
+void LCodeGen::DoConstructDouble(LConstructDouble* instr) {
+  Register hi_reg = ToRegister(instr->hi());
+  Register lo_reg = ToRegister(instr->lo());
+  DoubleRegister result_reg = ToDoubleRegister(instr->result());
+#if V8_TARGET_ARCH_PPC64
+  __ MovInt64ComponentsToDouble(result_reg, hi_reg, lo_reg, r0);
+#else
+  __ MovInt64ToDouble(result_reg, hi_reg, lo_reg);
+#endif
+}
+
+
+void LCodeGen::DoAllocate(LAllocate* instr) {
+  class DeferredAllocate FINAL : public LDeferredCode {
+   public:
+    DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
+        : LDeferredCode(codegen), instr_(instr) {}
+    void Generate() OVERRIDE { codegen()->DoDeferredAllocate(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
+   private:
+    LAllocate* instr_;
+  };
+
+  DeferredAllocate* deferred = new (zone()) DeferredAllocate(this, instr);
+
+  Register result = ToRegister(instr->result());
+  Register scratch = ToRegister(instr->temp1());
+  Register scratch2 = ToRegister(instr->temp2());
+
+  // Allocate memory for the object.
+  AllocationFlags flags = TAG_OBJECT;
+  if (instr->hydrogen()->MustAllocateDoubleAligned()) {
+    flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
+  }
+  if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
+    DCHECK(!instr->hydrogen()->IsOldDataSpaceAllocation());
+    DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
+    flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
+  } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
+    DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
+    flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
+  }
+
+  if (instr->size()->IsConstantOperand()) {
+    int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
+    if (size <= Page::kMaxRegularHeapObjectSize) {
+      __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
+    } else {
+      __ b(deferred->entry());
+    }
+  } else {
+    Register size = ToRegister(instr->size());
+    __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
+  }
+
+  __ bind(deferred->exit());
+
+  if (instr->hydrogen()->MustPrefillWithFiller()) {
+    STATIC_ASSERT(kHeapObjectTag == 1);
+    if (instr->size()->IsConstantOperand()) {
+      int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
+      __ LoadIntLiteral(scratch, size - kHeapObjectTag);
+    } else {
+      __ subi(scratch, ToRegister(instr->size()), Operand(kHeapObjectTag));
+    }
+    __ mov(scratch2, Operand(isolate()->factory()->one_pointer_filler_map()));
+    Label loop;
+    __ bind(&loop);
+    __ subi(scratch, scratch, Operand(kPointerSize));
+    __ StorePX(scratch2, MemOperand(result, scratch));
+    __ cmpi(scratch, Operand::Zero());
+    __ bge(&loop);
+  }
+}
+
+
+void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
+  Register result = ToRegister(instr->result());
+
+  // TODO(3095996): Get rid of this. For now, we need to make the
+  // result register contain a valid pointer because it is already
+  // contained in the register pointer map.
+  __ LoadSmiLiteral(result, Smi::FromInt(0));
+
+  PushSafepointRegistersScope scope(this);
+  if (instr->size()->IsRegister()) {
+    Register size = ToRegister(instr->size());
+    DCHECK(!size.is(result));
+    __ SmiTag(size);
+    __ push(size);
+  } else {
+    int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
+#if !V8_TARGET_ARCH_PPC64
+    if (size >= 0 && size <= Smi::kMaxValue) {
+#endif
+      __ Push(Smi::FromInt(size));
+#if !V8_TARGET_ARCH_PPC64
+    } else {
+      // We should never get here at runtime => abort
+      __ stop("invalid allocation size");
+      return;
+    }
+#endif
+  }
+
+  int flags = AllocateDoubleAlignFlag::encode(
+      instr->hydrogen()->MustAllocateDoubleAligned());
+  if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
+    DCHECK(!instr->hydrogen()->IsOldDataSpaceAllocation());
+    DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
+    flags = AllocateTargetSpace::update(flags, OLD_POINTER_SPACE);
+  } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
+    DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
+    flags = AllocateTargetSpace::update(flags, OLD_DATA_SPACE);
+  } else {
+    flags = AllocateTargetSpace::update(flags, NEW_SPACE);
+  }
+  __ Push(Smi::FromInt(flags));
+
+  CallRuntimeFromDeferred(Runtime::kAllocateInTargetSpace, 2, instr,
+                          instr->context());
+  __ StoreToSafepointRegisterSlot(r3, result);
+}
+
+
+void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
+  DCHECK(ToRegister(instr->value()).is(r3));
+  __ push(r3);
+  CallRuntime(Runtime::kToFastProperties, 1, instr);
+}
+
+
+void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  Label materialized;
+  // Registers will be used as follows:
+  // r10 = literals array.
+  // r4 = regexp literal.
+  // r3 = regexp literal clone.
+  // r5 and r7-r9 are used as temporaries.
+  int literal_offset =
+      FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
+  __ Move(r10, instr->hydrogen()->literals());
+  __ LoadP(r4, FieldMemOperand(r10, literal_offset));
+  __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+  __ cmp(r4, ip);
+  __ bne(&materialized);
+
+  // Create regexp literal using runtime function
+  // Result will be in r3.
+  __ LoadSmiLiteral(r9, Smi::FromInt(instr->hydrogen()->literal_index()));
+  __ mov(r8, Operand(instr->hydrogen()->pattern()));
+  __ mov(r7, Operand(instr->hydrogen()->flags()));
+  __ Push(r10, r9, r8, r7);
+  CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
+  __ mr(r4, r3);
+
+  __ bind(&materialized);
+  int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
+  Label allocated, runtime_allocate;
+
+  __ Allocate(size, r3, r5, r6, &runtime_allocate, TAG_OBJECT);
+  __ b(&allocated);
+
+  __ bind(&runtime_allocate);
+  __ LoadSmiLiteral(r3, Smi::FromInt(size));
+  __ Push(r4, r3);
+  CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
+  __ pop(r4);
+
+  __ bind(&allocated);
+  // Copy the content into the newly allocated memory.
+  __ CopyFields(r3, r4, r5.bit(), size / kPointerSize);
+}
+
+
+void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  // Use the fast case closure allocation code that allocates in new
+  // space for nested functions that don't need literals cloning.
+  bool pretenure = instr->hydrogen()->pretenure();
+  if (!pretenure && instr->hydrogen()->has_no_literals()) {
+    FastNewClosureStub stub(isolate(), instr->hydrogen()->strict_mode(),
+                            instr->hydrogen()->kind());
+    __ mov(r5, Operand(instr->hydrogen()->shared_info()));
+    CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+  } else {
+    __ mov(r5, Operand(instr->hydrogen()->shared_info()));
+    __ mov(r4, Operand(pretenure ? factory()->true_value()
+                                 : factory()->false_value()));
+    __ Push(cp, r5, r4);
+    CallRuntime(Runtime::kNewClosure, 3, instr);
+  }
+}
+
+
+void LCodeGen::DoTypeof(LTypeof* instr) {
+  Register input = ToRegister(instr->value());
+  __ push(input);
+  CallRuntime(Runtime::kTypeof, 1, instr);
+}
+
+
+void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
+  Register input = ToRegister(instr->value());
+
+  Condition final_branch_condition =
+      EmitTypeofIs(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), input,
+                   instr->type_literal());
+  if (final_branch_condition != kNoCondition) {
+    EmitBranch(instr, final_branch_condition);
+  }
+}
+
+
+Condition LCodeGen::EmitTypeofIs(Label* true_label, Label* false_label,
+                                 Register input, Handle<String> type_name) {
+  Condition final_branch_condition = kNoCondition;
+  Register scratch = scratch0();
+  Factory* factory = isolate()->factory();
+  if (String::Equals(type_name, factory->number_string())) {
+    __ JumpIfSmi(input, true_label);
+    __ LoadP(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
+    __ CompareRoot(scratch, Heap::kHeapNumberMapRootIndex);
+    final_branch_condition = eq;
+
+  } else if (String::Equals(type_name, factory->string_string())) {
+    __ JumpIfSmi(input, false_label);
+    __ CompareObjectType(input, scratch, no_reg, FIRST_NONSTRING_TYPE);
+    __ bge(false_label);
+    __ lbz(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
+    __ ExtractBit(r0, scratch, Map::kIsUndetectable);
+    __ cmpi(r0, Operand::Zero());
+    final_branch_condition = eq;
+
+  } else if (String::Equals(type_name, factory->symbol_string())) {
+    __ JumpIfSmi(input, false_label);
+    __ CompareObjectType(input, scratch, no_reg, SYMBOL_TYPE);
+    final_branch_condition = eq;
+
+  } else if (String::Equals(type_name, factory->boolean_string())) {
+    __ CompareRoot(input, Heap::kTrueValueRootIndex);
+    __ beq(true_label);
+    __ CompareRoot(input, Heap::kFalseValueRootIndex);
+    final_branch_condition = eq;
+
+  } else if (String::Equals(type_name, factory->undefined_string())) {
+    __ CompareRoot(input, Heap::kUndefinedValueRootIndex);
+    __ beq(true_label);
+    __ JumpIfSmi(input, false_label);
+    // Check for undetectable objects => true.
+    __ LoadP(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
+    __ lbz(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
+    __ ExtractBit(r0, scratch, Map::kIsUndetectable);
+    __ cmpi(r0, Operand::Zero());
+    final_branch_condition = ne;
+
+  } else if (String::Equals(type_name, factory->function_string())) {
+    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+    Register type_reg = scratch;
+    __ JumpIfSmi(input, false_label);
+    __ CompareObjectType(input, scratch, type_reg, JS_FUNCTION_TYPE);
+    __ beq(true_label);
+    __ cmpi(type_reg, Operand(JS_FUNCTION_PROXY_TYPE));
+    final_branch_condition = eq;
+
+  } else if (String::Equals(type_name, factory->object_string())) {
+    Register map = scratch;
+    __ JumpIfSmi(input, false_label);
+    __ CompareRoot(input, Heap::kNullValueRootIndex);
+    __ beq(true_label);
+    __ CheckObjectTypeRange(input, map, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE,
+                            LAST_NONCALLABLE_SPEC_OBJECT_TYPE, false_label);
+    // Check for undetectable objects => false.
+    __ lbz(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
+    __ ExtractBit(r0, scratch, Map::kIsUndetectable);
+    __ cmpi(r0, Operand::Zero());
+    final_branch_condition = eq;
+
+  } else {
+    __ b(false_label);
+  }
+
+  return final_branch_condition;
+}
+
+
+void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
+  Register temp1 = ToRegister(instr->temp());
+
+  EmitIsConstructCall(temp1, scratch0());
+  EmitBranch(instr, eq);
+}
+
+
+void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) {
+  DCHECK(!temp1.is(temp2));
+  // Get the frame pointer for the calling frame.
+  __ LoadP(temp1, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+
+  // Skip the arguments adaptor frame if it exists.
+  Label check_frame_marker;
+  __ LoadP(temp2, MemOperand(temp1, StandardFrameConstants::kContextOffset));
+  __ CmpSmiLiteral(temp2, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
+  __ bne(&check_frame_marker);
+  __ LoadP(temp1, MemOperand(temp1, StandardFrameConstants::kCallerFPOffset));
+
+  // Check the marker in the calling frame.
+  __ bind(&check_frame_marker);
+  __ LoadP(temp1, MemOperand(temp1, StandardFrameConstants::kMarkerOffset));
+  __ CmpSmiLiteral(temp1, Smi::FromInt(StackFrame::CONSTRUCT), r0);
+}
+
+
+void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) {
+  if (!info()->IsStub()) {
+    // Ensure that we have enough space after the previous lazy-bailout
+    // instruction for patching the code here.
+    int current_pc = masm()->pc_offset();
+    if (current_pc < last_lazy_deopt_pc_ + space_needed) {
+      int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
+      DCHECK_EQ(0, padding_size % Assembler::kInstrSize);
+      while (padding_size > 0) {
+        __ nop();
+        padding_size -= Assembler::kInstrSize;
+      }
+    }
+  }
+  last_lazy_deopt_pc_ = masm()->pc_offset();
+}
+
+
+void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
+  last_lazy_deopt_pc_ = masm()->pc_offset();
+  DCHECK(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
+  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
+}
+
+
+void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
+  Deoptimizer::BailoutType type = instr->hydrogen()->type();
+  // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the
+  // needed return address), even though the implementation of LAZY and EAGER is
+  // now identical. When LAZY is eventually completely folded into EAGER, remove
+  // the special case below.
+  if (info()->IsStub() && type == Deoptimizer::EAGER) {
+    type = Deoptimizer::LAZY;
+  }
+
+  DeoptimizeIf(al, instr, instr->hydrogen()->reason(), type);
+}
+
+
+void LCodeGen::DoDummy(LDummy* instr) {
+  // Nothing to see here, move on!
+}
+
+
+void LCodeGen::DoDummyUse(LDummyUse* instr) {
+  // Nothing to see here, move on!
+}
+
+
+void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
+  PushSafepointRegistersScope scope(this);
+  LoadContextFromDeferred(instr->context());
+  __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
+  RecordSafepointWithLazyDeopt(
+      instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
+  DCHECK(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
+}
+
+
+void LCodeGen::DoStackCheck(LStackCheck* instr) {
+  class DeferredStackCheck FINAL : public LDeferredCode {
+   public:
+    DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
+        : LDeferredCode(codegen), instr_(instr) {}
+    void Generate() OVERRIDE { codegen()->DoDeferredStackCheck(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
+   private:
+    LStackCheck* instr_;
+  };
+
+  DCHECK(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  // There is no LLazyBailout instruction for stack-checks. We have to
+  // prepare for lazy deoptimization explicitly here.
+  if (instr->hydrogen()->is_function_entry()) {
+    // Perform stack overflow check.
+    Label done;
+    __ LoadRoot(ip, Heap::kStackLimitRootIndex);
+    __ cmpl(sp, ip);
+    __ bge(&done);
+    DCHECK(instr->context()->IsRegister());
+    DCHECK(ToRegister(instr->context()).is(cp));
+    CallCode(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET,
+             instr);
+    __ bind(&done);
+  } else {
+    DCHECK(instr->hydrogen()->is_backwards_branch());
+    // Perform stack overflow check if this goto needs it before jumping.
+    DeferredStackCheck* deferred_stack_check =
+        new (zone()) DeferredStackCheck(this, instr);
+    __ LoadRoot(ip, Heap::kStackLimitRootIndex);
+    __ cmpl(sp, ip);
+    __ blt(deferred_stack_check->entry());
+    EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
+    __ bind(instr->done_label());
+    deferred_stack_check->SetExit(instr->done_label());
+    RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
+    // Don't record a deoptimization index for the safepoint here.
+    // This will be done explicitly when emitting call and the safepoint in
+    // the deferred code.
+  }
+}
+
+
+void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
+  // This is a pseudo-instruction that ensures that the environment here is
+  // properly registered for deoptimization and records the assembler's PC
+  // offset.
+  LEnvironment* environment = instr->environment();
+
+  // If the environment were already registered, we would have no way of
+  // backpatching it with the spill slot operands.
+  DCHECK(!environment->HasBeenRegistered());
+  RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
+
+  GenerateOsrPrologue();
+}
+
+
+void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
+  __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+  __ cmp(r3, ip);
+  DeoptimizeIf(eq, instr, "undefined");
+
+  Register null_value = r8;
+  __ LoadRoot(null_value, Heap::kNullValueRootIndex);
+  __ cmp(r3, null_value);
+  DeoptimizeIf(eq, instr, "null");
+
+  __ TestIfSmi(r3, r0);
+  DeoptimizeIf(eq, instr, "Smi", cr0);
+
+  STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
+  __ CompareObjectType(r3, r4, r4, LAST_JS_PROXY_TYPE);
+  DeoptimizeIf(le, instr, "wrong instance type");
+
+  Label use_cache, call_runtime;
+  __ CheckEnumCache(null_value, &call_runtime);
+
+  __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ b(&use_cache);
+
+  // Get the set of properties to enumerate.
+  __ bind(&call_runtime);
+  __ push(r3);
+  CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
+
+  __ LoadP(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ LoadRoot(ip, Heap::kMetaMapRootIndex);
+  __ cmp(r4, ip);
+  DeoptimizeIf(ne, instr, "wrong map");
+  __ bind(&use_cache);
+}
+
+
+void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
+  Register map = ToRegister(instr->map());
+  Register result = ToRegister(instr->result());
+  Label load_cache, done;
+  __ EnumLength(result, map);
+  __ CmpSmiLiteral(result, Smi::FromInt(0), r0);
+  __ bne(&load_cache);
+  __ mov(result, Operand(isolate()->factory()->empty_fixed_array()));
+  __ b(&done);
+
+  __ bind(&load_cache);
+  __ LoadInstanceDescriptors(map, result);
+  __ LoadP(result, FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
+  __ LoadP(result, FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
+  __ cmpi(result, Operand::Zero());
+  DeoptimizeIf(eq, instr, "no cache");
+
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
+  Register object = ToRegister(instr->value());
+  Register map = ToRegister(instr->map());
+  __ LoadP(scratch0(), FieldMemOperand(object, HeapObject::kMapOffset));
+  __ cmp(map, scratch0());
+  DeoptimizeIf(ne, instr, "wrong map");
+}
+
+
+void LCodeGen::DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr,
+                                           Register result, Register object,
+                                           Register index) {
+  PushSafepointRegistersScope scope(this);
+  __ Push(object, index);
+  __ li(cp, Operand::Zero());
+  __ CallRuntimeSaveDoubles(Runtime::kLoadMutableDouble);
+  RecordSafepointWithRegisters(instr->pointer_map(), 2,
+                               Safepoint::kNoLazyDeopt);
+  __ StoreToSafepointRegisterSlot(r3, result);
+}
+
+
+void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
+  class DeferredLoadMutableDouble FINAL : public LDeferredCode {
+   public:
+    DeferredLoadMutableDouble(LCodeGen* codegen, LLoadFieldByIndex* instr,
+                              Register result, Register object, Register index)
+        : LDeferredCode(codegen),
+          instr_(instr),
+          result_(result),
+          object_(object),
+          index_(index) {}
+    void Generate() OVERRIDE {
+      codegen()->DoDeferredLoadMutableDouble(instr_, result_, object_, index_);
+    }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
+   private:
+    LLoadFieldByIndex* instr_;
+    Register result_;
+    Register object_;
+    Register index_;
+  };
+
+  Register object = ToRegister(instr->object());
+  Register index = ToRegister(instr->index());
+  Register result = ToRegister(instr->result());
+  Register scratch = scratch0();
+
+  DeferredLoadMutableDouble* deferred;
+  deferred = new (zone())
+      DeferredLoadMutableDouble(this, instr, result, object, index);
+
+  Label out_of_object, done;
+
+  __ TestBitMask(index, reinterpret_cast<uintptr_t>(Smi::FromInt(1)), r0);
+  __ bne(deferred->entry(), cr0);
+  __ ShiftRightArithImm(index, index, 1);
+
+  __ cmpi(index, Operand::Zero());
+  __ blt(&out_of_object);
+
+  __ SmiToPtrArrayOffset(r0, index);
+  __ add(scratch, object, r0);
+  __ LoadP(result, FieldMemOperand(scratch, JSObject::kHeaderSize));
+
+  __ b(&done);
+
+  __ bind(&out_of_object);
+  __ LoadP(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
+  // Index is equal to negated out of object property index plus 1.
+  __ SmiToPtrArrayOffset(r0, index);
+  __ sub(scratch, result, r0);
+  __ LoadP(result,
+           FieldMemOperand(scratch, FixedArray::kHeaderSize - kPointerSize));
+  __ bind(deferred->exit());
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) {
+  Register context = ToRegister(instr->context());
+  __ StoreP(context, MemOperand(fp, StandardFrameConstants::kContextOffset));
+}
+
+
+void LCodeGen::DoAllocateBlockContext(LAllocateBlockContext* instr) {
+  Handle<ScopeInfo> scope_info = instr->scope_info();
+  __ Push(scope_info);
+  __ push(ToRegister(instr->function()));
+  CallRuntime(Runtime::kPushBlockContext, 2, instr);
+  RecordSafepoint(Safepoint::kNoLazyDeopt);
+}
+
+
+#undef __
+}
+}  // namespace v8::internal
diff --git a/src/ppc/lithium-codegen-ppc.h b/src/ppc/lithium-codegen-ppc.h
new file mode 100644
index 0000000..8ae3b3c
--- /dev/null
+++ b/src/ppc/lithium-codegen-ppc.h
@@ -0,0 +1,372 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PPC_LITHIUM_CODEGEN_PPC_H_
+#define V8_PPC_LITHIUM_CODEGEN_PPC_H_
+
+#include "src/ppc/lithium-ppc.h"
+
+#include "src/ppc/lithium-gap-resolver-ppc.h"
+#include "src/deoptimizer.h"
+#include "src/lithium-codegen.h"
+#include "src/safepoint-table.h"
+#include "src/scopes.h"
+#include "src/utils.h"
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class LDeferredCode;
+class SafepointGenerator;
+
+class LCodeGen : public LCodeGenBase {
+ public:
+  LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info)
+      : LCodeGenBase(chunk, assembler, info),
+        deoptimizations_(4, info->zone()),
+        jump_table_(4, info->zone()),
+        deoptimization_literals_(8, info->zone()),
+        inlined_function_count_(0),
+        scope_(info->scope()),
+        translations_(info->zone()),
+        deferred_(8, info->zone()),
+        osr_pc_offset_(-1),
+        frame_is_built_(false),
+        safepoints_(info->zone()),
+        resolver_(this),
+        expected_safepoint_kind_(Safepoint::kSimple) {
+    PopulateDeoptimizationLiteralsWithInlinedFunctions();
+  }
+
+
+  int LookupDestination(int block_id) const {
+    return chunk()->LookupDestination(block_id);
+  }
+
+  bool IsNextEmittedBlock(int block_id) const {
+    return LookupDestination(block_id) == GetNextEmittedBlock();
+  }
+
+  bool NeedsEagerFrame() const {
+    return GetStackSlotCount() > 0 || info()->is_non_deferred_calling() ||
+           !info()->IsStub() || info()->requires_frame();
+  }
+  bool NeedsDeferredFrame() const {
+    return !NeedsEagerFrame() && info()->is_deferred_calling();
+  }
+
+  LinkRegisterStatus GetLinkRegisterState() const {
+    return frame_is_built_ ? kLRHasBeenSaved : kLRHasNotBeenSaved;
+  }
+
+  // Support for converting LOperands to assembler types.
+  // LOperand must be a register.
+  Register ToRegister(LOperand* op) const;
+
+  // LOperand is loaded into scratch, unless already a register.
+  Register EmitLoadRegister(LOperand* op, Register scratch);
+
+  // LConstantOperand must be an Integer32 or Smi
+  void EmitLoadIntegerConstant(LConstantOperand* const_op, Register dst);
+
+  // LOperand must be a double register.
+  DoubleRegister ToDoubleRegister(LOperand* op) const;
+
+  intptr_t ToRepresentation(LConstantOperand* op,
+                            const Representation& r) const;
+  int32_t ToInteger32(LConstantOperand* op) const;
+  Smi* ToSmi(LConstantOperand* op) const;
+  double ToDouble(LConstantOperand* op) const;
+  Operand ToOperand(LOperand* op);
+  MemOperand ToMemOperand(LOperand* op) const;
+  // Returns a MemOperand pointing to the high word of a DoubleStackSlot.
+  MemOperand ToHighMemOperand(LOperand* op) const;
+
+  bool IsInteger32(LConstantOperand* op) const;
+  bool IsSmi(LConstantOperand* op) const;
+  Handle<Object> ToHandle(LConstantOperand* op) const;
+
+  // Try to generate code for the entire chunk, but it may fail if the
+  // chunk contains constructs we cannot handle. Returns true if the
+  // code generation attempt succeeded.
+  bool GenerateCode();
+
+  // Finish the code by setting stack height, safepoint, and bailout
+  // information on it.
+  void FinishCode(Handle<Code> code);
+
+  // Deferred code support.
+  void DoDeferredNumberTagD(LNumberTagD* instr);
+
+  enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 };
+  void DoDeferredNumberTagIU(LInstruction* instr, LOperand* value,
+                             LOperand* temp1, LOperand* temp2,
+                             IntegerSignedness signedness);
+
+  void DoDeferredTaggedToI(LTaggedToI* instr);
+  void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
+  void DoDeferredStackCheck(LStackCheck* instr);
+  void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
+  void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
+  void DoDeferredAllocate(LAllocate* instr);
+  void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
+                                       Label* map_check);
+  void DoDeferredInstanceMigration(LCheckMaps* instr, Register object);
+  void DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr, Register result,
+                                   Register object, Register index);
+
+  // Parallel move support.
+  void DoParallelMove(LParallelMove* move);
+  void DoGap(LGap* instr);
+
+  MemOperand PrepareKeyedOperand(Register key, Register base,
+                                 bool key_is_constant, bool key_is_tagged,
+                                 int constant_key, int element_size_shift,
+                                 int base_offset);
+
+  // Emit frame translation commands for an environment.
+  void WriteTranslation(LEnvironment* environment, Translation* translation);
+
+// Declare methods that deal with the individual node types.
+#define DECLARE_DO(type) void Do##type(L##type* node);
+  LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
+#undef DECLARE_DO
+
+ private:
+  StrictMode strict_mode() const { return info()->strict_mode(); }
+
+  Scope* scope() const { return scope_; }
+
+  Register scratch0() { return r11; }
+  DoubleRegister double_scratch0() { return kScratchDoubleReg; }
+
+  LInstruction* GetNextInstruction();
+
+  void EmitClassOfTest(Label* if_true, Label* if_false,
+                       Handle<String> class_name, Register input,
+                       Register temporary, Register temporary2);
+
+  int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
+
+  void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); }
+
+  void SaveCallerDoubles();
+  void RestoreCallerDoubles();
+
+  // Code generation passes.  Returns true if code generation should
+  // continue.
+  void GenerateBodyInstructionPre(LInstruction* instr) OVERRIDE;
+  bool GeneratePrologue();
+  bool GenerateDeferredCode();
+  bool GenerateJumpTable();
+  bool GenerateSafepointTable();
+
+  // Generates the custom OSR entrypoint and sets the osr_pc_offset.
+  void GenerateOsrPrologue();
+
+  enum SafepointMode {
+    RECORD_SIMPLE_SAFEPOINT,
+    RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
+  };
+
+  void CallCode(Handle<Code> code, RelocInfo::Mode mode, LInstruction* instr);
+
+  void CallCodeGeneric(Handle<Code> code, RelocInfo::Mode mode,
+                       LInstruction* instr, SafepointMode safepoint_mode);
+
+  void CallRuntime(const Runtime::Function* function, int num_arguments,
+                   LInstruction* instr,
+                   SaveFPRegsMode save_doubles = kDontSaveFPRegs);
+
+  void CallRuntime(Runtime::FunctionId id, int num_arguments,
+                   LInstruction* instr) {
+    const Runtime::Function* function = Runtime::FunctionForId(id);
+    CallRuntime(function, num_arguments, instr);
+  }
+
+  void LoadContextFromDeferred(LOperand* context);
+  void CallRuntimeFromDeferred(Runtime::FunctionId id, int argc,
+                               LInstruction* instr, LOperand* context);
+
+  enum R4State { R4_UNINITIALIZED, R4_CONTAINS_TARGET };
+
+  // Generate a direct call to a known function.  Expects the function
+  // to be in r4.
+  void CallKnownFunction(Handle<JSFunction> function,
+                         int formal_parameter_count, int arity,
+                         LInstruction* instr, R4State r4_state);
+
+  void RecordSafepointWithLazyDeopt(LInstruction* instr,
+                                    SafepointMode safepoint_mode);
+
+  void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
+                                            Safepoint::DeoptMode mode);
+  void DeoptimizeIf(Condition condition, LInstruction* instr,
+                    const char* detail, Deoptimizer::BailoutType bailout_type,
+                    CRegister cr = cr7);
+  void DeoptimizeIf(Condition condition, LInstruction* instr,
+                    const char* detail, CRegister cr = cr7);
+
+  void AddToTranslation(LEnvironment* environment, Translation* translation,
+                        LOperand* op, bool is_tagged, bool is_uint32,
+                        int* object_index_pointer,
+                        int* dematerialized_index_pointer);
+  void PopulateDeoptimizationData(Handle<Code> code);
+  int DefineDeoptimizationLiteral(Handle<Object> literal);
+
+  void PopulateDeoptimizationLiteralsWithInlinedFunctions();
+
+  Register ToRegister(int index) const;
+  DoubleRegister ToDoubleRegister(int index) const;
+
+  MemOperand BuildSeqStringOperand(Register string, LOperand* index,
+                                   String::Encoding encoding);
+
+  void EmitMathAbs(LMathAbs* instr);
+#if V8_TARGET_ARCH_PPC64
+  void EmitInteger32MathAbs(LMathAbs* instr);
+#endif
+
+  // Support for recording safepoint and position information.
+  void RecordSafepoint(LPointerMap* pointers, Safepoint::Kind kind,
+                       int arguments, Safepoint::DeoptMode mode);
+  void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
+  void RecordSafepoint(Safepoint::DeoptMode mode);
+  void RecordSafepointWithRegisters(LPointerMap* pointers, int arguments,
+                                    Safepoint::DeoptMode mode);
+
+  void RecordAndWritePosition(int position) OVERRIDE;
+
+  static Condition TokenToCondition(Token::Value op);
+  void EmitGoto(int block);
+
+  // EmitBranch expects to be the last instruction of a block.
+  template <class InstrType>
+  void EmitBranch(InstrType instr, Condition condition, CRegister cr = cr7);
+  template <class InstrType>
+  void EmitFalseBranch(InstrType instr, Condition condition,
+                       CRegister cr = cr7);
+  void EmitNumberUntagD(LNumberUntagD* instr, Register input,
+                        DoubleRegister result, NumberUntagDMode mode);
+
+  // Emits optimized code for typeof x == "y".  Modifies input register.
+  // Returns the condition on which a final split to
+  // true and false label should be made, to optimize fallthrough.
+  Condition EmitTypeofIs(Label* true_label, Label* false_label, Register input,
+                         Handle<String> type_name);
+
+  // Emits optimized code for %_IsObject(x).  Preserves input register.
+  // Returns the condition on which a final split to
+  // true and false label should be made, to optimize fallthrough.
+  Condition EmitIsObject(Register input, Register temp1, Label* is_not_object,
+                         Label* is_object);
+
+  // Emits optimized code for %_IsString(x).  Preserves input register.
+  // Returns the condition on which a final split to
+  // true and false label should be made, to optimize fallthrough.
+  Condition EmitIsString(Register input, Register temp1, Label* is_not_string,
+                         SmiCheck check_needed);
+
+  // Emits optimized code for %_IsConstructCall().
+  // Caller should branch on equal condition.
+  void EmitIsConstructCall(Register temp1, Register temp2);
+
+  // Emits optimized code to deep-copy the contents of statically known
+  // object graphs (e.g. object literal boilerplate).
+  void EmitDeepCopy(Handle<JSObject> object, Register result, Register source,
+                    int* offset, AllocationSiteMode mode);
+
+  void EnsureSpaceForLazyDeopt(int space_needed) OVERRIDE;
+  void DoLoadKeyedExternalArray(LLoadKeyed* instr);
+  void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr);
+  void DoLoadKeyedFixedArray(LLoadKeyed* instr);
+  void DoStoreKeyedExternalArray(LStoreKeyed* instr);
+  void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr);
+  void DoStoreKeyedFixedArray(LStoreKeyed* instr);
+
+  template <class T>
+  void EmitVectorLoadICRegisters(T* instr);
+
+  ZoneList<LEnvironment*> deoptimizations_;
+  ZoneList<Deoptimizer::JumpTableEntry> jump_table_;
+  ZoneList<Handle<Object> > deoptimization_literals_;
+  int inlined_function_count_;
+  Scope* const scope_;
+  TranslationBuffer translations_;
+  ZoneList<LDeferredCode*> deferred_;
+  int osr_pc_offset_;
+  bool frame_is_built_;
+
+  // Builder that keeps track of safepoints in the code. The table
+  // itself is emitted at the end of the generated code.
+  SafepointTableBuilder safepoints_;
+
+  // Compiler from a set of parallel moves to a sequential list of moves.
+  LGapResolver resolver_;
+
+  Safepoint::Kind expected_safepoint_kind_;
+
+  class PushSafepointRegistersScope FINAL BASE_EMBEDDED {
+   public:
+    explicit PushSafepointRegistersScope(LCodeGen* codegen)
+        : codegen_(codegen) {
+      DCHECK(codegen_->info()->is_calling());
+      DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
+      codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters;
+      StoreRegistersStateStub stub(codegen_->isolate());
+      codegen_->masm_->CallStub(&stub);
+    }
+
+    ~PushSafepointRegistersScope() {
+      DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters);
+      RestoreRegistersStateStub stub(codegen_->isolate());
+      codegen_->masm_->CallStub(&stub);
+      codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
+    }
+
+   private:
+    LCodeGen* codegen_;
+  };
+
+  friend class LDeferredCode;
+  friend class LEnvironment;
+  friend class SafepointGenerator;
+  DISALLOW_COPY_AND_ASSIGN(LCodeGen);
+};
+
+
+class LDeferredCode : public ZoneObject {
+ public:
+  explicit LDeferredCode(LCodeGen* codegen)
+      : codegen_(codegen),
+        external_exit_(NULL),
+        instruction_index_(codegen->current_instruction_) {
+    codegen->AddDeferredCode(this);
+  }
+
+  virtual ~LDeferredCode() {}
+  virtual void Generate() = 0;
+  virtual LInstruction* instr() = 0;
+
+  void SetExit(Label* exit) { external_exit_ = exit; }
+  Label* entry() { return &entry_; }
+  Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
+  int instruction_index() const { return instruction_index_; }
+
+ protected:
+  LCodeGen* codegen() const { return codegen_; }
+  MacroAssembler* masm() const { return codegen_->masm(); }
+
+ private:
+  LCodeGen* codegen_;
+  Label entry_;
+  Label exit_;
+  Label* external_exit_;
+  int instruction_index_;
+};
+}
+}  // namespace v8::internal
+
+#endif  // V8_PPC_LITHIUM_CODEGEN_PPC_H_
diff --git a/src/ppc/lithium-gap-resolver-ppc.cc b/src/ppc/lithium-gap-resolver-ppc.cc
new file mode 100644
index 0000000..c261b66
--- /dev/null
+++ b/src/ppc/lithium-gap-resolver-ppc.cc
@@ -0,0 +1,288 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/ppc/lithium-codegen-ppc.h"
+#include "src/ppc/lithium-gap-resolver-ppc.h"
+
+namespace v8 {
+namespace internal {
+
+static const Register kSavedValueRegister = {11};
+
+LGapResolver::LGapResolver(LCodeGen* owner)
+    : cgen_(owner),
+      moves_(32, owner->zone()),
+      root_index_(0),
+      in_cycle_(false),
+      saved_destination_(NULL) {}
+
+
+void LGapResolver::Resolve(LParallelMove* parallel_move) {
+  DCHECK(moves_.is_empty());
+  // Build up a worklist of moves.
+  BuildInitialMoveList(parallel_move);
+
+  for (int i = 0; i < moves_.length(); ++i) {
+    LMoveOperands move = moves_[i];
+    // Skip constants to perform them last.  They don't block other moves
+    // and skipping such moves with register destinations keeps those
+    // registers free for the whole algorithm.
+    if (!move.IsEliminated() && !move.source()->IsConstantOperand()) {
+      root_index_ = i;  // Any cycle is found when by reaching this move again.
+      PerformMove(i);
+      if (in_cycle_) {
+        RestoreValue();
+      }
+    }
+  }
+
+  // Perform the moves with constant sources.
+  for (int i = 0; i < moves_.length(); ++i) {
+    if (!moves_[i].IsEliminated()) {
+      DCHECK(moves_[i].source()->IsConstantOperand());
+      EmitMove(i);
+    }
+  }
+
+  moves_.Rewind(0);
+}
+
+
+void LGapResolver::BuildInitialMoveList(LParallelMove* parallel_move) {
+  // Perform a linear sweep of the moves to add them to the initial list of
+  // moves to perform, ignoring any move that is redundant (the source is
+  // the same as the destination, the destination is ignored and
+  // unallocated, or the move was already eliminated).
+  const ZoneList<LMoveOperands>* moves = parallel_move->move_operands();
+  for (int i = 0; i < moves->length(); ++i) {
+    LMoveOperands move = moves->at(i);
+    if (!move.IsRedundant()) moves_.Add(move, cgen_->zone());
+  }
+  Verify();
+}
+
+
+void LGapResolver::PerformMove(int index) {
+  // Each call to this function performs a move and deletes it from the move
+  // graph.  We first recursively perform any move blocking this one.  We
+  // mark a move as "pending" on entry to PerformMove in order to detect
+  // cycles in the move graph.
+
+  // We can only find a cycle, when doing a depth-first traversal of moves,
+  // be encountering the starting move again. So by spilling the source of
+  // the starting move, we break the cycle.  All moves are then unblocked,
+  // and the starting move is completed by writing the spilled value to
+  // its destination.  All other moves from the spilled source have been
+  // completed prior to breaking the cycle.
+  // An additional complication is that moves to MemOperands with large
+  // offsets (more than 1K or 4K) require us to spill this spilled value to
+  // the stack, to free up the register.
+  DCHECK(!moves_[index].IsPending());
+  DCHECK(!moves_[index].IsRedundant());
+
+  // Clear this move's destination to indicate a pending move.  The actual
+  // destination is saved in a stack allocated local.  Multiple moves can
+  // be pending because this function is recursive.
+  DCHECK(moves_[index].source() != NULL);  // Or else it will look eliminated.
+  LOperand* destination = moves_[index].destination();
+  moves_[index].set_destination(NULL);
+
+  // Perform a depth-first traversal of the move graph to resolve
+  // dependencies.  Any unperformed, unpending move with a source the same
+  // as this one's destination blocks this one so recursively perform all
+  // such moves.
+  for (int i = 0; i < moves_.length(); ++i) {
+    LMoveOperands other_move = moves_[i];
+    if (other_move.Blocks(destination) && !other_move.IsPending()) {
+      PerformMove(i);
+      // If there is a blocking, pending move it must be moves_[root_index_]
+      // and all other moves with the same source as moves_[root_index_] are
+      // sucessfully executed (because they are cycle-free) by this loop.
+    }
+  }
+
+  // We are about to resolve this move and don't need it marked as
+  // pending, so restore its destination.
+  moves_[index].set_destination(destination);
+
+  // The move may be blocked on a pending move, which must be the starting move.
+  // In this case, we have a cycle, and we save the source of this move to
+  // a scratch register to break it.
+  LMoveOperands other_move = moves_[root_index_];
+  if (other_move.Blocks(destination)) {
+    DCHECK(other_move.IsPending());
+    BreakCycle(index);
+    return;
+  }
+
+  // This move is no longer blocked.
+  EmitMove(index);
+}
+
+
+void LGapResolver::Verify() {
+#ifdef ENABLE_SLOW_DCHECKS
+  // No operand should be the destination for more than one move.
+  for (int i = 0; i < moves_.length(); ++i) {
+    LOperand* destination = moves_[i].destination();
+    for (int j = i + 1; j < moves_.length(); ++j) {
+      SLOW_DCHECK(!destination->Equals(moves_[j].destination()));
+    }
+  }
+#endif
+}
+
+#define __ ACCESS_MASM(cgen_->masm())
+
+void LGapResolver::BreakCycle(int index) {
+  // We save in a register the value that should end up in the source of
+  // moves_[root_index].  After performing all moves in the tree rooted
+  // in that move, we save the value to that source.
+  DCHECK(moves_[index].destination()->Equals(moves_[root_index_].source()));
+  DCHECK(!in_cycle_);
+  in_cycle_ = true;
+  LOperand* source = moves_[index].source();
+  saved_destination_ = moves_[index].destination();
+  if (source->IsRegister()) {
+    __ mr(kSavedValueRegister, cgen_->ToRegister(source));
+  } else if (source->IsStackSlot()) {
+    __ LoadP(kSavedValueRegister, cgen_->ToMemOperand(source));
+  } else if (source->IsDoubleRegister()) {
+    __ fmr(kScratchDoubleReg, cgen_->ToDoubleRegister(source));
+  } else if (source->IsDoubleStackSlot()) {
+    __ lfd(kScratchDoubleReg, cgen_->ToMemOperand(source));
+  } else {
+    UNREACHABLE();
+  }
+  // This move will be done by restoring the saved value to the destination.
+  moves_[index].Eliminate();
+}
+
+
+void LGapResolver::RestoreValue() {
+  DCHECK(in_cycle_);
+  DCHECK(saved_destination_ != NULL);
+
+  // Spilled value is in kSavedValueRegister or kSavedDoubleValueRegister.
+  if (saved_destination_->IsRegister()) {
+    __ mr(cgen_->ToRegister(saved_destination_), kSavedValueRegister);
+  } else if (saved_destination_->IsStackSlot()) {
+    __ StoreP(kSavedValueRegister, cgen_->ToMemOperand(saved_destination_));
+  } else if (saved_destination_->IsDoubleRegister()) {
+    __ fmr(cgen_->ToDoubleRegister(saved_destination_), kScratchDoubleReg);
+  } else if (saved_destination_->IsDoubleStackSlot()) {
+    __ stfd(kScratchDoubleReg, cgen_->ToMemOperand(saved_destination_));
+  } else {
+    UNREACHABLE();
+  }
+
+  in_cycle_ = false;
+  saved_destination_ = NULL;
+}
+
+
+void LGapResolver::EmitMove(int index) {
+  LOperand* source = moves_[index].source();
+  LOperand* destination = moves_[index].destination();
+
+  // Dispatch on the source and destination operand kinds.  Not all
+  // combinations are possible.
+
+  if (source->IsRegister()) {
+    Register source_register = cgen_->ToRegister(source);
+    if (destination->IsRegister()) {
+      __ mr(cgen_->ToRegister(destination), source_register);
+    } else {
+      DCHECK(destination->IsStackSlot());
+      __ StoreP(source_register, cgen_->ToMemOperand(destination));
+    }
+  } else if (source->IsStackSlot()) {
+    MemOperand source_operand = cgen_->ToMemOperand(source);
+    if (destination->IsRegister()) {
+      __ LoadP(cgen_->ToRegister(destination), source_operand);
+    } else {
+      DCHECK(destination->IsStackSlot());
+      MemOperand destination_operand = cgen_->ToMemOperand(destination);
+      if (in_cycle_) {
+        __ LoadP(ip, source_operand);
+        __ StoreP(ip, destination_operand);
+      } else {
+        __ LoadP(kSavedValueRegister, source_operand);
+        __ StoreP(kSavedValueRegister, destination_operand);
+      }
+    }
+
+  } else if (source->IsConstantOperand()) {
+    LConstantOperand* constant_source = LConstantOperand::cast(source);
+    if (destination->IsRegister()) {
+      Register dst = cgen_->ToRegister(destination);
+      if (cgen_->IsInteger32(constant_source)) {
+        cgen_->EmitLoadIntegerConstant(constant_source, dst);
+      } else {
+        __ Move(dst, cgen_->ToHandle(constant_source));
+      }
+    } else if (destination->IsDoubleRegister()) {
+      DoubleRegister result = cgen_->ToDoubleRegister(destination);
+      double v = cgen_->ToDouble(constant_source);
+      __ LoadDoubleLiteral(result, v, ip);
+    } else {
+      DCHECK(destination->IsStackSlot());
+      DCHECK(!in_cycle_);  // Constant moves happen after all cycles are gone.
+      if (cgen_->IsInteger32(constant_source)) {
+        cgen_->EmitLoadIntegerConstant(constant_source, kSavedValueRegister);
+      } else {
+        __ Move(kSavedValueRegister, cgen_->ToHandle(constant_source));
+      }
+      __ StoreP(kSavedValueRegister, cgen_->ToMemOperand(destination));
+    }
+
+  } else if (source->IsDoubleRegister()) {
+    DoubleRegister source_register = cgen_->ToDoubleRegister(source);
+    if (destination->IsDoubleRegister()) {
+      __ fmr(cgen_->ToDoubleRegister(destination), source_register);
+    } else {
+      DCHECK(destination->IsDoubleStackSlot());
+      __ stfd(source_register, cgen_->ToMemOperand(destination));
+    }
+
+  } else if (source->IsDoubleStackSlot()) {
+    MemOperand source_operand = cgen_->ToMemOperand(source);
+    if (destination->IsDoubleRegister()) {
+      __ lfd(cgen_->ToDoubleRegister(destination), source_operand);
+    } else {
+      DCHECK(destination->IsDoubleStackSlot());
+      MemOperand destination_operand = cgen_->ToMemOperand(destination);
+      if (in_cycle_) {
+// kSavedDoubleValueRegister was used to break the cycle,
+// but kSavedValueRegister is free.
+#if V8_TARGET_ARCH_PPC64
+        __ ld(kSavedValueRegister, source_operand);
+        __ std(kSavedValueRegister, destination_operand);
+#else
+        MemOperand source_high_operand = cgen_->ToHighMemOperand(source);
+        MemOperand destination_high_operand =
+            cgen_->ToHighMemOperand(destination);
+        __ lwz(kSavedValueRegister, source_operand);
+        __ stw(kSavedValueRegister, destination_operand);
+        __ lwz(kSavedValueRegister, source_high_operand);
+        __ stw(kSavedValueRegister, destination_high_operand);
+#endif
+      } else {
+        __ lfd(kScratchDoubleReg, source_operand);
+        __ stfd(kScratchDoubleReg, destination_operand);
+      }
+    }
+  } else {
+    UNREACHABLE();
+  }
+
+  moves_[index].Eliminate();
+}
+
+
+#undef __
+}
+}  // namespace v8::internal
diff --git a/src/ppc/lithium-gap-resolver-ppc.h b/src/ppc/lithium-gap-resolver-ppc.h
new file mode 100644
index 0000000..78bd213
--- /dev/null
+++ b/src/ppc/lithium-gap-resolver-ppc.h
@@ -0,0 +1,60 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PPC_LITHIUM_GAP_RESOLVER_PPC_H_
+#define V8_PPC_LITHIUM_GAP_RESOLVER_PPC_H_
+
+#include "src/v8.h"
+
+#include "src/lithium.h"
+
+namespace v8 {
+namespace internal {
+
+class LCodeGen;
+class LGapResolver;
+
+class LGapResolver FINAL BASE_EMBEDDED {
+ public:
+  explicit LGapResolver(LCodeGen* owner);
+
+  // Resolve a set of parallel moves, emitting assembler instructions.
+  void Resolve(LParallelMove* parallel_move);
+
+ private:
+  // Build the initial list of moves.
+  void BuildInitialMoveList(LParallelMove* parallel_move);
+
+  // Perform the move at the moves_ index in question (possibly requiring
+  // other moves to satisfy dependencies).
+  void PerformMove(int index);
+
+  // If a cycle is found in the series of moves, save the blocking value to
+  // a scratch register.  The cycle must be found by hitting the root of the
+  // depth-first search.
+  void BreakCycle(int index);
+
+  // After a cycle has been resolved, restore the value from the scratch
+  // register to its proper destination.
+  void RestoreValue();
+
+  // Emit a move and remove it from the move graph.
+  void EmitMove(int index);
+
+  // Verify the move list before performing moves.
+  void Verify();
+
+  LCodeGen* cgen_;
+
+  // List of moves not yet resolved.
+  ZoneList<LMoveOperands> moves_;
+
+  int root_index_;
+  bool in_cycle_;
+  LOperand* saved_destination_;
+};
+}
+}  // namespace v8::internal
+
+#endif  // V8_PPC_LITHIUM_GAP_RESOLVER_PPC_H_
diff --git a/src/ppc/lithium-ppc.cc b/src/ppc/lithium-ppc.cc
new file mode 100644
index 0000000..42470c5
--- /dev/null
+++ b/src/ppc/lithium-ppc.cc
@@ -0,0 +1,2626 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sstream>
+
+#include "src/v8.h"
+
+#include "src/hydrogen-osr.h"
+#include "src/lithium-inl.h"
+#include "src/ppc/lithium-codegen-ppc.h"
+
+namespace v8 {
+namespace internal {
+
+#define DEFINE_COMPILE(type)                           \
+  void L##type::CompileToNative(LCodeGen* generator) { \
+    generator->Do##type(this);                         \
+  }
+LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
+#undef DEFINE_COMPILE
+
+#ifdef DEBUG
+void LInstruction::VerifyCall() {
+  // Call instructions can use only fixed registers as temporaries and
+  // outputs because all registers are blocked by the calling convention.
+  // Inputs operands must use a fixed register or use-at-start policy or
+  // a non-register policy.
+  DCHECK(Output() == NULL || LUnallocated::cast(Output())->HasFixedPolicy() ||
+         !LUnallocated::cast(Output())->HasRegisterPolicy());
+  for (UseIterator it(this); !it.Done(); it.Advance()) {
+    LUnallocated* operand = LUnallocated::cast(it.Current());
+    DCHECK(operand->HasFixedPolicy() || operand->IsUsedAtStart());
+  }
+  for (TempIterator it(this); !it.Done(); it.Advance()) {
+    LUnallocated* operand = LUnallocated::cast(it.Current());
+    DCHECK(operand->HasFixedPolicy() || !operand->HasRegisterPolicy());
+  }
+}
+#endif
+
+
+void LInstruction::PrintTo(StringStream* stream) {
+  stream->Add("%s ", this->Mnemonic());
+
+  PrintOutputOperandTo(stream);
+
+  PrintDataTo(stream);
+
+  if (HasEnvironment()) {
+    stream->Add(" ");
+    environment()->PrintTo(stream);
+  }
+
+  if (HasPointerMap()) {
+    stream->Add(" ");
+    pointer_map()->PrintTo(stream);
+  }
+}
+
+
+void LInstruction::PrintDataTo(StringStream* stream) {
+  stream->Add("= ");
+  for (int i = 0; i < InputCount(); i++) {
+    if (i > 0) stream->Add(" ");
+    if (InputAt(i) == NULL) {
+      stream->Add("NULL");
+    } else {
+      InputAt(i)->PrintTo(stream);
+    }
+  }
+}
+
+
+void LInstruction::PrintOutputOperandTo(StringStream* stream) {
+  if (HasResult()) result()->PrintTo(stream);
+}
+
+
+void LLabel::PrintDataTo(StringStream* stream) {
+  LGap::PrintDataTo(stream);
+  LLabel* rep = replacement();
+  if (rep != NULL) {
+    stream->Add(" Dead block replaced with B%d", rep->block_id());
+  }
+}
+
+
+bool LGap::IsRedundant() const {
+  for (int i = 0; i < 4; i++) {
+    if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+void LGap::PrintDataTo(StringStream* stream) {
+  for (int i = 0; i < 4; i++) {
+    stream->Add("(");
+    if (parallel_moves_[i] != NULL) {
+      parallel_moves_[i]->PrintDataTo(stream);
+    }
+    stream->Add(") ");
+  }
+}
+
+
+const char* LArithmeticD::Mnemonic() const {
+  switch (op()) {
+    case Token::ADD:
+      return "add-d";
+    case Token::SUB:
+      return "sub-d";
+    case Token::MUL:
+      return "mul-d";
+    case Token::DIV:
+      return "div-d";
+    case Token::MOD:
+      return "mod-d";
+    default:
+      UNREACHABLE();
+      return NULL;
+  }
+}
+
+
+const char* LArithmeticT::Mnemonic() const {
+  switch (op()) {
+    case Token::ADD:
+      return "add-t";
+    case Token::SUB:
+      return "sub-t";
+    case Token::MUL:
+      return "mul-t";
+    case Token::MOD:
+      return "mod-t";
+    case Token::DIV:
+      return "div-t";
+    case Token::BIT_AND:
+      return "bit-and-t";
+    case Token::BIT_OR:
+      return "bit-or-t";
+    case Token::BIT_XOR:
+      return "bit-xor-t";
+    case Token::ROR:
+      return "ror-t";
+    case Token::SHL:
+      return "shl-t";
+    case Token::SAR:
+      return "sar-t";
+    case Token::SHR:
+      return "shr-t";
+    default:
+      UNREACHABLE();
+      return NULL;
+  }
+}
+
+
+bool LGoto::HasInterestingComment(LCodeGen* gen) const {
+  return !gen->IsNextEmittedBlock(block_id());
+}
+
+
+void LGoto::PrintDataTo(StringStream* stream) {
+  stream->Add("B%d", block_id());
+}
+
+
+void LBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
+  value()->PrintTo(stream);
+}
+
+
+void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if ");
+  left()->PrintTo(stream);
+  stream->Add(" %s ", Token::String(op()));
+  right()->PrintTo(stream);
+  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if is_object(");
+  value()->PrintTo(stream);
+  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if is_string(");
+  value()->PrintTo(stream);
+  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if is_smi(");
+  value()->PrintTo(stream);
+  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if is_undetectable(");
+  value()->PrintTo(stream);
+  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if string_compare(");
+  left()->PrintTo(stream);
+  right()->PrintTo(stream);
+  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if has_instance_type(");
+  value()->PrintTo(stream);
+  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if has_cached_array_index(");
+  value()->PrintTo(stream);
+  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if class_of_test(");
+  value()->PrintTo(stream);
+  stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(),
+              true_block_id(), false_block_id());
+}
+
+
+void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if typeof ");
+  value()->PrintTo(stream);
+  stream->Add(" == \"%s\" then B%d else B%d",
+              hydrogen()->type_literal()->ToCString().get(), true_block_id(),
+              false_block_id());
+}
+
+
+void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
+  stream->Add(" = ");
+  function()->PrintTo(stream);
+  stream->Add(".code_entry = ");
+  code_object()->PrintTo(stream);
+}
+
+
+void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
+  stream->Add(" = ");
+  base_object()->PrintTo(stream);
+  stream->Add(" + ");
+  offset()->PrintTo(stream);
+}
+
+
+void LCallJSFunction::PrintDataTo(StringStream* stream) {
+  stream->Add("= ");
+  function()->PrintTo(stream);
+  stream->Add("#%d / ", arity());
+}
+
+
+void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
+  for (int i = 0; i < InputCount(); i++) {
+    InputAt(i)->PrintTo(stream);
+    stream->Add(" ");
+  }
+  stream->Add("#%d / ", arity());
+}
+
+
+void LLoadContextSlot::PrintDataTo(StringStream* stream) {
+  context()->PrintTo(stream);
+  stream->Add("[%d]", slot_index());
+}
+
+
+void LStoreContextSlot::PrintDataTo(StringStream* stream) {
+  context()->PrintTo(stream);
+  stream->Add("[%d] <- ", slot_index());
+  value()->PrintTo(stream);
+}
+
+
+void LInvokeFunction::PrintDataTo(StringStream* stream) {
+  stream->Add("= ");
+  function()->PrintTo(stream);
+  stream->Add(" #%d / ", arity());
+}
+
+
+void LCallNew::PrintDataTo(StringStream* stream) {
+  stream->Add("= ");
+  constructor()->PrintTo(stream);
+  stream->Add(" #%d / ", arity());
+}
+
+
+void LCallNewArray::PrintDataTo(StringStream* stream) {
+  stream->Add("= ");
+  constructor()->PrintTo(stream);
+  stream->Add(" #%d / ", arity());
+  ElementsKind kind = hydrogen()->elements_kind();
+  stream->Add(" (%s) ", ElementsKindToString(kind));
+}
+
+
+void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
+  arguments()->PrintTo(stream);
+  stream->Add(" length ");
+  length()->PrintTo(stream);
+  stream->Add(" index ");
+  index()->PrintTo(stream);
+}
+
+
+void LStoreNamedField::PrintDataTo(StringStream* stream) {
+  object()->PrintTo(stream);
+  std::ostringstream os;
+  os << hydrogen()->access() << " <- ";
+  stream->Add(os.str().c_str());
+  value()->PrintTo(stream);
+}
+
+
+void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
+  object()->PrintTo(stream);
+  stream->Add(".");
+  stream->Add(String::cast(*name())->ToCString().get());
+  stream->Add(" <- ");
+  value()->PrintTo(stream);
+}
+
+
+void LLoadKeyed::PrintDataTo(StringStream* stream) {
+  elements()->PrintTo(stream);
+  stream->Add("[");
+  key()->PrintTo(stream);
+  if (hydrogen()->IsDehoisted()) {
+    stream->Add(" + %d]", base_offset());
+  } else {
+    stream->Add("]");
+  }
+}
+
+
+void LStoreKeyed::PrintDataTo(StringStream* stream) {
+  elements()->PrintTo(stream);
+  stream->Add("[");
+  key()->PrintTo(stream);
+  if (hydrogen()->IsDehoisted()) {
+    stream->Add(" + %d] <-", base_offset());
+  } else {
+    stream->Add("] <- ");
+  }
+
+  if (value() == NULL) {
+    DCHECK(hydrogen()->IsConstantHoleStore() &&
+           hydrogen()->value()->representation().IsDouble());
+    stream->Add("<the hole(nan)>");
+  } else {
+    value()->PrintTo(stream);
+  }
+}
+
+
+void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
+  object()->PrintTo(stream);
+  stream->Add("[");
+  key()->PrintTo(stream);
+  stream->Add("] <- ");
+  value()->PrintTo(stream);
+}
+
+
+void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
+  object()->PrintTo(stream);
+  stream->Add(" %p -> %p", *original_map(), *transitioned_map());
+}
+
+
+int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
+  // Skip a slot if for a double-width slot.
+  if (kind == DOUBLE_REGISTERS) spill_slot_count_++;
+  return spill_slot_count_++;
+}
+
+
+LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
+  int index = GetNextSpillIndex(kind);
+  if (kind == DOUBLE_REGISTERS) {
+    return LDoubleStackSlot::Create(index, zone());
+  } else {
+    DCHECK(kind == GENERAL_REGISTERS);
+    return LStackSlot::Create(index, zone());
+  }
+}
+
+
+LPlatformChunk* LChunkBuilder::Build() {
+  DCHECK(is_unused());
+  chunk_ = new (zone()) LPlatformChunk(info(), graph());
+  LPhase phase("L_Building chunk", chunk_);
+  status_ = BUILDING;
+
+  // If compiling for OSR, reserve space for the unoptimized frame,
+  // which will be subsumed into this frame.
+  if (graph()->has_osr()) {
+    for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
+      chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
+    }
+  }
+
+  const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
+  for (int i = 0; i < blocks->length(); i++) {
+    HBasicBlock* next = NULL;
+    if (i < blocks->length() - 1) next = blocks->at(i + 1);
+    DoBasicBlock(blocks->at(i), next);
+    if (is_aborted()) return NULL;
+  }
+  status_ = DONE;
+  return chunk_;
+}
+
+
+LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
+  return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
+                                   Register::ToAllocationIndex(reg));
+}
+
+
+LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
+  return new (zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
+                                   DoubleRegister::ToAllocationIndex(reg));
+}
+
+
+LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
+  return Use(value, ToUnallocated(fixed_register));
+}
+
+
+LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) {
+  return Use(value, ToUnallocated(reg));
+}
+
+
+LOperand* LChunkBuilder::UseRegister(HValue* value) {
+  return Use(value,
+             new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
+}
+
+
+LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
+  return Use(value, new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
+                                              LUnallocated::USED_AT_START));
+}
+
+
+LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
+  return Use(value, new (zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
+}
+
+
+LOperand* LChunkBuilder::Use(HValue* value) {
+  return Use(value, new (zone()) LUnallocated(LUnallocated::NONE));
+}
+
+
+LOperand* LChunkBuilder::UseAtStart(HValue* value) {
+  return Use(value, new (zone())
+             LUnallocated(LUnallocated::NONE, LUnallocated::USED_AT_START));
+}
+
+
+LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
+  return value->IsConstant()
+             ? chunk_->DefineConstantOperand(HConstant::cast(value))
+             : Use(value);
+}
+
+
+LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
+  return value->IsConstant()
+             ? chunk_->DefineConstantOperand(HConstant::cast(value))
+             : UseAtStart(value);
+}
+
+
+LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
+  return value->IsConstant()
+             ? chunk_->DefineConstantOperand(HConstant::cast(value))
+             : UseRegister(value);
+}
+
+
+LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
+  return value->IsConstant()
+             ? chunk_->DefineConstantOperand(HConstant::cast(value))
+             : UseRegisterAtStart(value);
+}
+
+
+LOperand* LChunkBuilder::UseConstant(HValue* value) {
+  return chunk_->DefineConstantOperand(HConstant::cast(value));
+}
+
+
+LOperand* LChunkBuilder::UseAny(HValue* value) {
+  return value->IsConstant()
+             ? chunk_->DefineConstantOperand(HConstant::cast(value))
+             : Use(value, new (zone()) LUnallocated(LUnallocated::ANY));
+}
+
+
+LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
+  if (value->EmitAtUses()) {
+    HInstruction* instr = HInstruction::cast(value);
+    VisitInstruction(instr);
+  }
+  operand->set_virtual_register(value->id());
+  return operand;
+}
+
+
+LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
+                                    LUnallocated* result) {
+  result->set_virtual_register(current_instruction_->id());
+  instr->set_result(result);
+  return instr;
+}
+
+
+LInstruction* LChunkBuilder::DefineAsRegister(
+    LTemplateResultInstruction<1>* instr) {
+  return Define(instr,
+                new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
+}
+
+
+LInstruction* LChunkBuilder::DefineAsSpilled(
+    LTemplateResultInstruction<1>* instr, int index) {
+  return Define(instr,
+                new (zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
+}
+
+
+LInstruction* LChunkBuilder::DefineSameAsFirst(
+    LTemplateResultInstruction<1>* instr) {
+  return Define(instr,
+                new (zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
+}
+
+
+LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
+                                         Register reg) {
+  return Define(instr, ToUnallocated(reg));
+}
+
+
+LInstruction* LChunkBuilder::DefineFixedDouble(
+    LTemplateResultInstruction<1>* instr, DoubleRegister reg) {
+  return Define(instr, ToUnallocated(reg));
+}
+
+
+LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
+  HEnvironment* hydrogen_env = current_block_->last_environment();
+  int argument_index_accumulator = 0;
+  ZoneList<HValue*> objects_to_materialize(0, zone());
+  instr->set_environment(CreateEnvironment(
+      hydrogen_env, &argument_index_accumulator, &objects_to_materialize));
+  return instr;
+}
+
+
+LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
+                                        HInstruction* hinstr,
+                                        CanDeoptimize can_deoptimize) {
+  info()->MarkAsNonDeferredCalling();
+#ifdef DEBUG
+  instr->VerifyCall();
+#endif
+  instr->MarkAsCall();
+  instr = AssignPointerMap(instr);
+
+  // If instruction does not have side-effects lazy deoptimization
+  // after the call will try to deoptimize to the point before the call.
+  // Thus we still need to attach environment to this call even if
+  // call sequence can not deoptimize eagerly.
+  bool needs_environment = (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
+                           !hinstr->HasObservableSideEffects();
+  if (needs_environment && !instr->HasEnvironment()) {
+    instr = AssignEnvironment(instr);
+    // We can't really figure out if the environment is needed or not.
+    instr->environment()->set_has_been_used();
+  }
+
+  return instr;
+}
+
+
+LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
+  DCHECK(!instr->HasPointerMap());
+  instr->set_pointer_map(new (zone()) LPointerMap(zone()));
+  return instr;
+}
+
+
+LUnallocated* LChunkBuilder::TempRegister() {
+  LUnallocated* operand =
+      new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
+  int vreg = allocator_->GetVirtualRegister();
+  if (!allocator_->AllocationOk()) {
+    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
+    vreg = 0;
+  }
+  operand->set_virtual_register(vreg);
+  return operand;
+}
+
+
+LUnallocated* LChunkBuilder::TempDoubleRegister() {
+  LUnallocated* operand =
+      new (zone()) LUnallocated(LUnallocated::MUST_HAVE_DOUBLE_REGISTER);
+  int vreg = allocator_->GetVirtualRegister();
+  if (!allocator_->AllocationOk()) {
+    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
+    vreg = 0;
+  }
+  operand->set_virtual_register(vreg);
+  return operand;
+}
+
+
+LOperand* LChunkBuilder::FixedTemp(Register reg) {
+  LUnallocated* operand = ToUnallocated(reg);
+  DCHECK(operand->HasFixedPolicy());
+  return operand;
+}
+
+
+LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
+  LUnallocated* operand = ToUnallocated(reg);
+  DCHECK(operand->HasFixedPolicy());
+  return operand;
+}
+
+
+LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
+  return new (zone()) LLabel(instr->block());
+}
+
+
+LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
+  return DefineAsRegister(new (zone()) LDummyUse(UseAny(instr->value())));
+}
+
+
+LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
+  UNREACHABLE();
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
+  return AssignEnvironment(new (zone()) LDeoptimize);
+}
+
+
+LInstruction* LChunkBuilder::DoShift(Token::Value op,
+                                     HBitwiseBinaryOperation* instr) {
+  if (instr->representation().IsSmiOrInteger32()) {
+    DCHECK(instr->left()->representation().Equals(instr->representation()));
+    DCHECK(instr->right()->representation().Equals(instr->representation()));
+    LOperand* left = UseRegisterAtStart(instr->left());
+
+    HValue* right_value = instr->right();
+    LOperand* right = NULL;
+    int constant_value = 0;
+    bool does_deopt = false;
+    if (right_value->IsConstant()) {
+      HConstant* constant = HConstant::cast(right_value);
+      right = chunk_->DefineConstantOperand(constant);
+      constant_value = constant->Integer32Value() & 0x1f;
+      // Left shifts can deoptimize if we shift by > 0 and the result cannot be
+      // truncated to smi.
+      if (instr->representation().IsSmi() && constant_value > 0) {
+        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi);
+      }
+    } else {
+      right = UseRegisterAtStart(right_value);
+    }
+
+    // Shift operations can only deoptimize if we do a logical shift
+    // by 0 and the result cannot be truncated to int32.
+    if (op == Token::SHR && constant_value == 0) {
+      does_deopt = !instr->CheckFlag(HInstruction::kUint32);
+    }
+
+    LInstruction* result =
+        DefineAsRegister(new (zone()) LShiftI(op, left, right, does_deopt));
+    return does_deopt ? AssignEnvironment(result) : result;
+  } else {
+    return DoArithmeticT(op, instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
+                                           HArithmeticBinaryOperation* instr) {
+  DCHECK(instr->representation().IsDouble());
+  DCHECK(instr->left()->representation().IsDouble());
+  DCHECK(instr->right()->representation().IsDouble());
+  if (op == Token::MOD) {
+    LOperand* left = UseFixedDouble(instr->left(), d1);
+    LOperand* right = UseFixedDouble(instr->right(), d2);
+    LArithmeticD* result = new (zone()) LArithmeticD(op, left, right);
+    // We call a C function for double modulo. It can't trigger a GC. We need
+    // to use fixed result register for the call.
+    // TODO(fschneider): Allow any register as input registers.
+    return MarkAsCall(DefineFixedDouble(result, d1), instr);
+  } else {
+    LOperand* left = UseRegisterAtStart(instr->left());
+    LOperand* right = UseRegisterAtStart(instr->right());
+    LArithmeticD* result = new (zone()) LArithmeticD(op, left, right);
+    return DefineAsRegister(result);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
+                                           HBinaryOperation* instr) {
+  HValue* left = instr->left();
+  HValue* right = instr->right();
+  DCHECK(left->representation().IsTagged());
+  DCHECK(right->representation().IsTagged());
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* left_operand = UseFixed(left, r4);
+  LOperand* right_operand = UseFixed(right, r3);
+  LArithmeticT* result =
+      new (zone()) LArithmeticT(op, context, left_operand, right_operand);
+  return MarkAsCall(DefineFixed(result, r3), instr);
+}
+
+
+void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
+  DCHECK(is_building());
+  current_block_ = block;
+  next_block_ = next_block;
+  if (block->IsStartBlock()) {
+    block->UpdateEnvironment(graph_->start_environment());
+    argument_count_ = 0;
+  } else if (block->predecessors()->length() == 1) {
+    // We have a single predecessor => copy environment and outgoing
+    // argument count from the predecessor.
+    DCHECK(block->phis()->length() == 0);
+    HBasicBlock* pred = block->predecessors()->at(0);
+    HEnvironment* last_environment = pred->last_environment();
+    DCHECK(last_environment != NULL);
+    // Only copy the environment, if it is later used again.
+    if (pred->end()->SecondSuccessor() == NULL) {
+      DCHECK(pred->end()->FirstSuccessor() == block);
+    } else {
+      if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
+          pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
+        last_environment = last_environment->Copy();
+      }
+    }
+    block->UpdateEnvironment(last_environment);
+    DCHECK(pred->argument_count() >= 0);
+    argument_count_ = pred->argument_count();
+  } else {
+    // We are at a state join => process phis.
+    HBasicBlock* pred = block->predecessors()->at(0);
+    // No need to copy the environment, it cannot be used later.
+    HEnvironment* last_environment = pred->last_environment();
+    for (int i = 0; i < block->phis()->length(); ++i) {
+      HPhi* phi = block->phis()->at(i);
+      if (phi->HasMergedIndex()) {
+        last_environment->SetValueAt(phi->merged_index(), phi);
+      }
+    }
+    for (int i = 0; i < block->deleted_phis()->length(); ++i) {
+      if (block->deleted_phis()->at(i) < last_environment->length()) {
+        last_environment->SetValueAt(block->deleted_phis()->at(i),
+                                     graph_->GetConstantUndefined());
+      }
+    }
+    block->UpdateEnvironment(last_environment);
+    // Pick up the outgoing argument count of one of the predecessors.
+    argument_count_ = pred->argument_count();
+  }
+  HInstruction* current = block->first();
+  int start = chunk_->instructions()->length();
+  while (current != NULL && !is_aborted()) {
+    // Code for constants in registers is generated lazily.
+    if (!current->EmitAtUses()) {
+      VisitInstruction(current);
+    }
+    current = current->next();
+  }
+  int end = chunk_->instructions()->length() - 1;
+  if (end >= start) {
+    block->set_first_instruction_index(start);
+    block->set_last_instruction_index(end);
+  }
+  block->set_argument_count(argument_count_);
+  next_block_ = NULL;
+  current_block_ = NULL;
+}
+
+
+void LChunkBuilder::VisitInstruction(HInstruction* current) {
+  HInstruction* old_current = current_instruction_;
+  current_instruction_ = current;
+
+  LInstruction* instr = NULL;
+  if (current->CanReplaceWithDummyUses()) {
+    if (current->OperandCount() == 0) {
+      instr = DefineAsRegister(new (zone()) LDummy());
+    } else {
+      DCHECK(!current->OperandAt(0)->IsControlInstruction());
+      instr = DefineAsRegister(new (zone())
+                               LDummyUse(UseAny(current->OperandAt(0))));
+    }
+    for (int i = 1; i < current->OperandCount(); ++i) {
+      if (current->OperandAt(i)->IsControlInstruction()) continue;
+      LInstruction* dummy =
+          new (zone()) LDummyUse(UseAny(current->OperandAt(i)));
+      dummy->set_hydrogen_value(current);
+      chunk_->AddInstruction(dummy, current_block_);
+    }
+  } else {
+    HBasicBlock* successor;
+    if (current->IsControlInstruction() &&
+        HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
+        successor != NULL) {
+      instr = new (zone()) LGoto(successor);
+    } else {
+      instr = current->CompileToLithium(this);
+    }
+  }
+
+  argument_count_ += current->argument_delta();
+  DCHECK(argument_count_ >= 0);
+
+  if (instr != NULL) {
+    AddInstruction(instr, current);
+  }
+
+  current_instruction_ = old_current;
+}
+
+
+void LChunkBuilder::AddInstruction(LInstruction* instr,
+                                   HInstruction* hydrogen_val) {
+  // Associate the hydrogen instruction first, since we may need it for
+  // the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
+  instr->set_hydrogen_value(hydrogen_val);
+
+#if DEBUG
+  // Make sure that the lithium instruction has either no fixed register
+  // constraints in temps or the result OR no uses that are only used at
+  // start. If this invariant doesn't hold, the register allocator can decide
+  // to insert a split of a range immediately before the instruction due to an
+  // already allocated register needing to be used for the instruction's fixed
+  // register constraint. In this case, The register allocator won't see an
+  // interference between the split child and the use-at-start (it would if
+  // the it was just a plain use), so it is free to move the split child into
+  // the same register that is used for the use-at-start.
+  // See https://code.google.com/p/chromium/issues/detail?id=201590
+  if (!(instr->ClobbersRegisters() &&
+        instr->ClobbersDoubleRegisters(isolate()))) {
+    int fixed = 0;
+    int used_at_start = 0;
+    for (UseIterator it(instr); !it.Done(); it.Advance()) {
+      LUnallocated* operand = LUnallocated::cast(it.Current());
+      if (operand->IsUsedAtStart()) ++used_at_start;
+    }
+    if (instr->Output() != NULL) {
+      if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
+    }
+    for (TempIterator it(instr); !it.Done(); it.Advance()) {
+      LUnallocated* operand = LUnallocated::cast(it.Current());
+      if (operand->HasFixedPolicy()) ++fixed;
+    }
+    DCHECK(fixed == 0 || used_at_start == 0);
+  }
+#endif
+
+  if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
+    instr = AssignPointerMap(instr);
+  }
+  if (FLAG_stress_environments && !instr->HasEnvironment()) {
+    instr = AssignEnvironment(instr);
+  }
+  chunk_->AddInstruction(instr, current_block_);
+
+  if (instr->IsCall()) {
+    HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
+    LInstruction* instruction_needing_environment = NULL;
+    if (hydrogen_val->HasObservableSideEffects()) {
+      HSimulate* sim = HSimulate::cast(hydrogen_val->next());
+      instruction_needing_environment = instr;
+      sim->ReplayEnvironment(current_block_->last_environment());
+      hydrogen_value_for_lazy_bailout = sim;
+    }
+    LInstruction* bailout = AssignEnvironment(new (zone()) LLazyBailout());
+    bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
+    chunk_->AddInstruction(bailout, current_block_);
+    if (instruction_needing_environment != NULL) {
+      // Store the lazy deopt environment with the instruction if needed.
+      // Right now it is only used for LInstanceOfKnownGlobal.
+      instruction_needing_environment->SetDeferredLazyDeoptimizationEnvironment(
+          bailout->environment());
+    }
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
+  return new (zone()) LGoto(instr->FirstSuccessor());
+}
+
+
+LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
+  HValue* value = instr->value();
+  Representation r = value->representation();
+  HType type = value->type();
+  ToBooleanStub::Types expected = instr->expected_input_types();
+  if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
+
+  bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
+                   type.IsJSArray() || type.IsHeapNumber() || type.IsString();
+  LInstruction* branch = new (zone()) LBranch(UseRegister(value));
+  if (!easy_case &&
+      ((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
+       !expected.IsGeneric())) {
+    branch = AssignEnvironment(branch);
+  }
+  return branch;
+}
+
+
+LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
+  return new (zone()) LDebugBreak();
+}
+
+
+LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LOperand* temp = TempRegister();
+  return new (zone()) LCmpMapAndBranch(value, temp);
+}
+
+
+LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* instr) {
+  info()->MarkAsRequiresFrame();
+  LOperand* value = UseRegister(instr->value());
+  return DefineAsRegister(new (zone()) LArgumentsLength(value));
+}
+
+
+LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
+  info()->MarkAsRequiresFrame();
+  return DefineAsRegister(new (zone()) LArgumentsElements);
+}
+
+
+LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LInstanceOf* result = new (zone()) LInstanceOf(
+      context, UseFixed(instr->left(), r3), UseFixed(instr->right(), r4));
+  return MarkAsCall(DefineFixed(result, r3), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
+    HInstanceOfKnownGlobal* instr) {
+  LInstanceOfKnownGlobal* result = new (zone())
+      LInstanceOfKnownGlobal(UseFixed(instr->context(), cp),
+                             UseFixed(instr->left(), r3), FixedTemp(r7));
+  return MarkAsCall(DefineFixed(result, r3), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
+  LOperand* receiver = UseRegisterAtStart(instr->receiver());
+  LOperand* function = UseRegisterAtStart(instr->function());
+  LWrapReceiver* result = new (zone()) LWrapReceiver(receiver, function);
+  return AssignEnvironment(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
+  LOperand* function = UseFixed(instr->function(), r4);
+  LOperand* receiver = UseFixed(instr->receiver(), r3);
+  LOperand* length = UseFixed(instr->length(), r5);
+  LOperand* elements = UseFixed(instr->elements(), r6);
+  LApplyArguments* result =
+      new (zone()) LApplyArguments(function, receiver, length, elements);
+  return MarkAsCall(DefineFixed(result, r3), instr, CAN_DEOPTIMIZE_EAGERLY);
+}
+
+
+LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
+  int argc = instr->OperandCount();
+  for (int i = 0; i < argc; ++i) {
+    LOperand* argument = Use(instr->argument(i));
+    AddInstruction(new (zone()) LPushArgument(argument), instr);
+  }
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoStoreCodeEntry(
+    HStoreCodeEntry* store_code_entry) {
+  LOperand* function = UseRegister(store_code_entry->function());
+  LOperand* code_object = UseTempRegister(store_code_entry->code_object());
+  return new (zone()) LStoreCodeEntry(function, code_object);
+}
+
+
+LInstruction* LChunkBuilder::DoInnerAllocatedObject(
+    HInnerAllocatedObject* instr) {
+  LOperand* base_object = UseRegisterAtStart(instr->base_object());
+  LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
+  return DefineAsRegister(new (zone())
+                          LInnerAllocatedObject(base_object, offset));
+}
+
+
+LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
+  return instr->HasNoUses() ? NULL
+                            : DefineAsRegister(new (zone()) LThisFunction);
+}
+
+
+LInstruction* LChunkBuilder::DoContext(HContext* instr) {
+  if (instr->HasNoUses()) return NULL;
+
+  if (info()->IsStub()) {
+    return DefineFixed(new (zone()) LContext, cp);
+  }
+
+  return DefineAsRegister(new (zone()) LContext);
+}
+
+
+LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  return MarkAsCall(new (zone()) LDeclareGlobals(context), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoCallJSFunction(HCallJSFunction* instr) {
+  LOperand* function = UseFixed(instr->function(), r4);
+
+  LCallJSFunction* result = new (zone()) LCallJSFunction(function);
+
+  return MarkAsCall(DefineFixed(result, r3), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoCallWithDescriptor(HCallWithDescriptor* instr) {
+  CallInterfaceDescriptor descriptor = instr->descriptor();
+
+  LOperand* target = UseRegisterOrConstantAtStart(instr->target());
+  ZoneList<LOperand*> ops(instr->OperandCount(), zone());
+  ops.Add(target, zone());
+  for (int i = 1; i < instr->OperandCount(); i++) {
+    LOperand* op =
+        UseFixed(instr->OperandAt(i), descriptor.GetParameterRegister(i - 1));
+    ops.Add(op, zone());
+  }
+
+  LCallWithDescriptor* result =
+      new (zone()) LCallWithDescriptor(descriptor, ops, zone());
+  return MarkAsCall(DefineFixed(result, r3), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoTailCallThroughMegamorphicCache(
+    HTailCallThroughMegamorphicCache* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* receiver_register =
+      UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
+  LOperand* name_register =
+      UseFixed(instr->name(), LoadDescriptor::NameRegister());
+  // Not marked as call. It can't deoptimize, and it never returns.
+  return new (zone()) LTailCallThroughMegamorphicCache(
+      context, receiver_register, name_register);
+}
+
+
+LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* function = UseFixed(instr->function(), r4);
+  LInvokeFunction* result = new (zone()) LInvokeFunction(context, function);
+  return MarkAsCall(DefineFixed(result, r3), instr, CANNOT_DEOPTIMIZE_EAGERLY);
+}
+
+
+LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
+  switch (instr->op()) {
+    case kMathFloor:
+      return DoMathFloor(instr);
+    case kMathRound:
+      return DoMathRound(instr);
+    case kMathFround:
+      return DoMathFround(instr);
+    case kMathAbs:
+      return DoMathAbs(instr);
+    case kMathLog:
+      return DoMathLog(instr);
+    case kMathExp:
+      return DoMathExp(instr);
+    case kMathSqrt:
+      return DoMathSqrt(instr);
+    case kMathPowHalf:
+      return DoMathPowHalf(instr);
+    case kMathClz32:
+      return DoMathClz32(instr);
+    default:
+      UNREACHABLE();
+      return NULL;
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegister(instr->value());
+  LMathFloor* result = new (zone()) LMathFloor(input);
+  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+}
+
+
+LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegister(instr->value());
+  LOperand* temp = TempDoubleRegister();
+  LMathRound* result = new (zone()) LMathRound(input, temp);
+  return AssignEnvironment(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegister(instr->value());
+  LMathFround* result = new (zone()) LMathFround(input);
+  return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
+  Representation r = instr->value()->representation();
+  LOperand* context = (r.IsDouble() || r.IsSmiOrInteger32())
+                          ? NULL
+                          : UseFixed(instr->context(), cp);
+  LOperand* input = UseRegister(instr->value());
+  LInstruction* result =
+      DefineAsRegister(new (zone()) LMathAbs(context, input));
+  if (!r.IsDouble() && !r.IsSmiOrInteger32()) result = AssignPointerMap(result);
+  if (!r.IsDouble()) result = AssignEnvironment(result);
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
+  DCHECK(instr->representation().IsDouble());
+  DCHECK(instr->value()->representation().IsDouble());
+  LOperand* input = UseFixedDouble(instr->value(), d1);
+  return MarkAsCall(DefineFixedDouble(new (zone()) LMathLog(input), d1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegisterAtStart(instr->value());
+  LMathClz32* result = new (zone()) LMathClz32(input);
+  return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
+  DCHECK(instr->representation().IsDouble());
+  DCHECK(instr->value()->representation().IsDouble());
+  LOperand* input = UseRegister(instr->value());
+  LOperand* temp1 = TempRegister();
+  LOperand* temp2 = TempRegister();
+  LOperand* double_temp = TempDoubleRegister();
+  LMathExp* result = new (zone()) LMathExp(input, double_temp, temp1, temp2);
+  return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegisterAtStart(instr->value());
+  LMathSqrt* result = new (zone()) LMathSqrt(input);
+  return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegisterAtStart(instr->value());
+  LMathPowHalf* result = new (zone()) LMathPowHalf(input);
+  return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* constructor = UseFixed(instr->constructor(), r4);
+  LCallNew* result = new (zone()) LCallNew(context, constructor);
+  return MarkAsCall(DefineFixed(result, r3), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* constructor = UseFixed(instr->constructor(), r4);
+  LCallNewArray* result = new (zone()) LCallNewArray(context, constructor);
+  return MarkAsCall(DefineFixed(result, r3), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* function = UseFixed(instr->function(), r4);
+  LCallFunction* call = new (zone()) LCallFunction(context, function);
+  return MarkAsCall(DefineFixed(call, r3), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  return MarkAsCall(DefineFixed(new (zone()) LCallRuntime(context), r3), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoRor(HRor* instr) {
+  return DoShift(Token::ROR, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoShr(HShr* instr) {
+  return DoShift(Token::SHR, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoSar(HSar* instr) {
+  return DoShift(Token::SAR, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoShl(HShl* instr) {
+  return DoShift(Token::SHL, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
+  if (instr->representation().IsSmiOrInteger32()) {
+    DCHECK(instr->left()->representation().Equals(instr->representation()));
+    DCHECK(instr->right()->representation().Equals(instr->representation()));
+    DCHECK(instr->CheckFlag(HValue::kTruncatingToInt32));
+
+    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
+    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
+    return DefineAsRegister(new (zone()) LBitI(left, right));
+  } else {
+    return DoArithmeticT(instr->op(), instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
+  DCHECK(instr->representation().IsSmiOrInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegister(instr->left());
+  int32_t divisor = instr->right()->GetInteger32Constant();
+  LInstruction* result =
+      DefineAsRegister(new (zone()) LDivByPowerOf2I(dividend, divisor));
+  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
+      (instr->CheckFlag(HValue::kCanOverflow) && divisor == -1) ||
+      (!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
+       divisor != 1 && divisor != -1)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
+  DCHECK(instr->representation().IsInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegister(instr->left());
+  int32_t divisor = instr->right()->GetInteger32Constant();
+  LInstruction* result =
+      DefineAsRegister(new (zone()) LDivByConstI(dividend, divisor));
+  if (divisor == 0 ||
+      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
+      !instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
+  DCHECK(instr->representation().IsSmiOrInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegister(instr->left());
+  LOperand* divisor = UseRegister(instr->right());
+  LInstruction* result =
+      DefineAsRegister(new (zone()) LDivI(dividend, divisor));
+  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
+      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
+      (instr->CheckFlag(HValue::kCanOverflow) &&
+       !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) ||
+      (!instr->IsMathFloorOfDiv() &&
+       !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
+  if (instr->representation().IsSmiOrInteger32()) {
+    if (instr->RightIsPowerOf2()) {
+      return DoDivByPowerOf2I(instr);
+    } else if (instr->right()->IsConstant()) {
+      return DoDivByConstI(instr);
+    } else {
+      return DoDivI(instr);
+    }
+  } else if (instr->representation().IsDouble()) {
+    return DoArithmeticD(Token::DIV, instr);
+  } else {
+    return DoArithmeticT(Token::DIV, instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
+  LOperand* dividend = UseRegisterAtStart(instr->left());
+  int32_t divisor = instr->right()->GetInteger32Constant();
+  LInstruction* result =
+      DefineAsRegister(new (zone()) LFlooringDivByPowerOf2I(dividend, divisor));
+  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
+      (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
+  DCHECK(instr->representation().IsInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegister(instr->left());
+  int32_t divisor = instr->right()->GetInteger32Constant();
+  LOperand* temp =
+      ((divisor > 0 && !instr->CheckFlag(HValue::kLeftCanBeNegative)) ||
+       (divisor < 0 && !instr->CheckFlag(HValue::kLeftCanBePositive)))
+          ? NULL
+          : TempRegister();
+  LInstruction* result = DefineAsRegister(
+      new (zone()) LFlooringDivByConstI(dividend, divisor, temp));
+  if (divisor == 0 ||
+      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
+  DCHECK(instr->representation().IsSmiOrInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegister(instr->left());
+  LOperand* divisor = UseRegister(instr->right());
+  LFlooringDivI* div = new (zone()) LFlooringDivI(dividend, divisor);
+  return AssignEnvironment(DefineAsRegister(div));
+}
+
+
+LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
+  if (instr->RightIsPowerOf2()) {
+    return DoFlooringDivByPowerOf2I(instr);
+  } else if (instr->right()->IsConstant()) {
+    return DoFlooringDivByConstI(instr);
+  } else {
+    return DoFlooringDivI(instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
+  DCHECK(instr->representation().IsSmiOrInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegisterAtStart(instr->left());
+  int32_t divisor = instr->right()->GetInteger32Constant();
+  LInstruction* result =
+      DefineSameAsFirst(new (zone()) LModByPowerOf2I(dividend, divisor));
+  if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
+      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoModByConstI(HMod* instr) {
+  DCHECK(instr->representation().IsSmiOrInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegister(instr->left());
+  int32_t divisor = instr->right()->GetInteger32Constant();
+  LInstruction* result =
+      DefineAsRegister(new (zone()) LModByConstI(dividend, divisor));
+  if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoModI(HMod* instr) {
+  DCHECK(instr->representation().IsSmiOrInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegister(instr->left());
+  LOperand* divisor = UseRegister(instr->right());
+  LInstruction* result =
+      DefineAsRegister(new (zone()) LModI(dividend, divisor));
+  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
+      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoMod(HMod* instr) {
+  if (instr->representation().IsSmiOrInteger32()) {
+    if (instr->RightIsPowerOf2()) {
+      return DoModByPowerOf2I(instr);
+    } else if (instr->right()->IsConstant()) {
+      return DoModByConstI(instr);
+    } else {
+      return DoModI(instr);
+    }
+  } else if (instr->representation().IsDouble()) {
+    return DoArithmeticD(Token::MOD, instr);
+  } else {
+    return DoArithmeticT(Token::MOD, instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoMul(HMul* instr) {
+  if (instr->representation().IsSmiOrInteger32()) {
+    DCHECK(instr->left()->representation().Equals(instr->representation()));
+    DCHECK(instr->right()->representation().Equals(instr->representation()));
+    HValue* left = instr->BetterLeftOperand();
+    HValue* right = instr->BetterRightOperand();
+    LOperand* left_op;
+    LOperand* right_op;
+    bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
+    bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
+
+    if (right->IsConstant()) {
+      HConstant* constant = HConstant::cast(right);
+      int32_t constant_value = constant->Integer32Value();
+      // Constants -1, 0 and 1 can be optimized if the result can overflow.
+      // For other constants, it can be optimized only without overflow.
+      if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) {
+        left_op = UseRegisterAtStart(left);
+        right_op = UseConstant(right);
+      } else {
+        if (bailout_on_minus_zero) {
+          left_op = UseRegister(left);
+        } else {
+          left_op = UseRegisterAtStart(left);
+        }
+        right_op = UseRegister(right);
+      }
+    } else {
+      if (bailout_on_minus_zero) {
+        left_op = UseRegister(left);
+      } else {
+        left_op = UseRegisterAtStart(left);
+      }
+      right_op = UseRegister(right);
+    }
+    LMulI* mul = new (zone()) LMulI(left_op, right_op);
+    if (can_overflow || bailout_on_minus_zero) {
+      AssignEnvironment(mul);
+    }
+    return DefineAsRegister(mul);
+
+  } else if (instr->representation().IsDouble()) {
+    if (instr->HasOneUse() &&
+        (instr->uses().value()->IsAdd() || instr->uses().value()->IsSub())) {
+      HBinaryOperation* use = HBinaryOperation::cast(instr->uses().value());
+
+      if (use->IsAdd() && instr == use->left()) {
+        // This mul is the lhs of an add. The add and mul will be folded into a
+        // multiply-add in DoAdd.
+        return NULL;
+      }
+      if (instr == use->right() && use->IsAdd() &&
+          !(use->left()->IsMul() && use->left()->HasOneUse())) {
+        // This mul is the rhs of an add, where the lhs is not another mul.
+        // The add and mul will be folded into a multiply-add in DoAdd.
+        return NULL;
+      }
+      if (instr == use->left() && use->IsSub()) {
+        // This mul is the lhs of a sub. The mul and sub will be folded into a
+        // multiply-sub in DoSub.
+        return NULL;
+      }
+    }
+
+    return DoArithmeticD(Token::MUL, instr);
+  } else {
+    return DoArithmeticT(Token::MUL, instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoSub(HSub* instr) {
+  if (instr->representation().IsSmiOrInteger32()) {
+    DCHECK(instr->left()->representation().Equals(instr->representation()));
+    DCHECK(instr->right()->representation().Equals(instr->representation()));
+
+    if (instr->left()->IsConstant() &&
+        !instr->CheckFlag(HValue::kCanOverflow)) {
+      // If lhs is constant, do reverse subtraction instead.
+      return DoRSub(instr);
+    }
+
+    LOperand* left = UseRegisterAtStart(instr->left());
+    LOperand* right = UseOrConstantAtStart(instr->right());
+    LSubI* sub = new (zone()) LSubI(left, right);
+    LInstruction* result = DefineAsRegister(sub);
+    if (instr->CheckFlag(HValue::kCanOverflow)) {
+      result = AssignEnvironment(result);
+    }
+    return result;
+  } else if (instr->representation().IsDouble()) {
+    if (instr->left()->IsMul() && instr->left()->HasOneUse()) {
+      return DoMultiplySub(instr->right(), HMul::cast(instr->left()));
+    }
+
+    return DoArithmeticD(Token::SUB, instr);
+  } else {
+    return DoArithmeticT(Token::SUB, instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoRSub(HSub* instr) {
+  DCHECK(instr->representation().IsSmiOrInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
+
+  // Note: The lhs of the subtraction becomes the rhs of the
+  // reverse-subtraction.
+  LOperand* left = UseRegisterAtStart(instr->right());
+  LOperand* right = UseOrConstantAtStart(instr->left());
+  LRSubI* rsb = new (zone()) LRSubI(left, right);
+  LInstruction* result = DefineAsRegister(rsb);
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) {
+  LOperand* multiplier_op = UseRegisterAtStart(mul->left());
+  LOperand* multiplicand_op = UseRegisterAtStart(mul->right());
+  LOperand* addend_op = UseRegisterAtStart(addend);
+  return DefineSameAsFirst(
+      new (zone()) LMultiplyAddD(addend_op, multiplier_op, multiplicand_op));
+}
+
+
+LInstruction* LChunkBuilder::DoMultiplySub(HValue* minuend, HMul* mul) {
+  LOperand* minuend_op = UseRegisterAtStart(minuend);
+  LOperand* multiplier_op = UseRegisterAtStart(mul->left());
+  LOperand* multiplicand_op = UseRegisterAtStart(mul->right());
+
+  return DefineSameAsFirst(
+      new (zone()) LMultiplySubD(minuend_op, multiplier_op, multiplicand_op));
+}
+
+
+LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
+  if (instr->representation().IsSmiOrInteger32()) {
+    DCHECK(instr->left()->representation().Equals(instr->representation()));
+    DCHECK(instr->right()->representation().Equals(instr->representation()));
+    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
+    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
+    LAddI* add = new (zone()) LAddI(left, right);
+    LInstruction* result = DefineAsRegister(add);
+    if (instr->CheckFlag(HValue::kCanOverflow)) {
+      result = AssignEnvironment(result);
+    }
+    return result;
+  } else if (instr->representation().IsExternal()) {
+    DCHECK(instr->left()->representation().IsExternal());
+    DCHECK(instr->right()->representation().IsInteger32());
+    DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
+    LOperand* left = UseRegisterAtStart(instr->left());
+    LOperand* right = UseOrConstantAtStart(instr->right());
+    LAddI* add = new (zone()) LAddI(left, right);
+    LInstruction* result = DefineAsRegister(add);
+    return result;
+  } else if (instr->representation().IsDouble()) {
+    if (instr->left()->IsMul() && instr->left()->HasOneUse()) {
+      return DoMultiplyAdd(HMul::cast(instr->left()), instr->right());
+    }
+
+    if (instr->right()->IsMul() && instr->right()->HasOneUse()) {
+      DCHECK(!instr->left()->IsMul() || !instr->left()->HasOneUse());
+      return DoMultiplyAdd(HMul::cast(instr->right()), instr->left());
+    }
+
+    return DoArithmeticD(Token::ADD, instr);
+  } else {
+    return DoArithmeticT(Token::ADD, instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
+  LOperand* left = NULL;
+  LOperand* right = NULL;
+  if (instr->representation().IsSmiOrInteger32()) {
+    DCHECK(instr->left()->representation().Equals(instr->representation()));
+    DCHECK(instr->right()->representation().Equals(instr->representation()));
+    left = UseRegisterAtStart(instr->BetterLeftOperand());
+    right = UseOrConstantAtStart(instr->BetterRightOperand());
+  } else {
+    DCHECK(instr->representation().IsDouble());
+    DCHECK(instr->left()->representation().IsDouble());
+    DCHECK(instr->right()->representation().IsDouble());
+    left = UseRegisterAtStart(instr->left());
+    right = UseRegisterAtStart(instr->right());
+  }
+  return DefineAsRegister(new (zone()) LMathMinMax(left, right));
+}
+
+
+LInstruction* LChunkBuilder::DoPower(HPower* instr) {
+  DCHECK(instr->representation().IsDouble());
+  // We call a C function for double power. It can't trigger a GC.
+  // We need to use fixed result register for the call.
+  Representation exponent_type = instr->right()->representation();
+  DCHECK(instr->left()->representation().IsDouble());
+  LOperand* left = UseFixedDouble(instr->left(), d1);
+  LOperand* right =
+      exponent_type.IsDouble()
+          ? UseFixedDouble(instr->right(), d2)
+          : UseFixed(instr->right(), MathPowTaggedDescriptor::exponent());
+  LPower* result = new (zone()) LPower(left, right);
+  return MarkAsCall(DefineFixedDouble(result, d3), instr,
+                    CAN_DEOPTIMIZE_EAGERLY);
+}
+
+
+LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
+  DCHECK(instr->left()->representation().IsTagged());
+  DCHECK(instr->right()->representation().IsTagged());
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* left = UseFixed(instr->left(), r4);
+  LOperand* right = UseFixed(instr->right(), r3);
+  LCmpT* result = new (zone()) LCmpT(context, left, right);
+  return MarkAsCall(DefineFixed(result, r3), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
+    HCompareNumericAndBranch* instr) {
+  Representation r = instr->representation();
+  if (r.IsSmiOrInteger32()) {
+    DCHECK(instr->left()->representation().Equals(r));
+    DCHECK(instr->right()->representation().Equals(r));
+    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
+    LOperand* right = UseRegisterOrConstantAtStart(instr->right());
+    return new (zone()) LCompareNumericAndBranch(left, right);
+  } else {
+    DCHECK(r.IsDouble());
+    DCHECK(instr->left()->representation().IsDouble());
+    DCHECK(instr->right()->representation().IsDouble());
+    LOperand* left = UseRegisterAtStart(instr->left());
+    LOperand* right = UseRegisterAtStart(instr->right());
+    return new (zone()) LCompareNumericAndBranch(left, right);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
+    HCompareObjectEqAndBranch* instr) {
+  LOperand* left = UseRegisterAtStart(instr->left());
+  LOperand* right = UseRegisterAtStart(instr->right());
+  return new (zone()) LCmpObjectEqAndBranch(left, right);
+}
+
+
+LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
+    HCompareHoleAndBranch* instr) {
+  LOperand* value = UseRegisterAtStart(instr->value());
+  return new (zone()) LCmpHoleAndBranch(value);
+}
+
+
+LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
+    HCompareMinusZeroAndBranch* instr) {
+  LOperand* value = UseRegister(instr->value());
+  LOperand* scratch = TempRegister();
+  return new (zone()) LCompareMinusZeroAndBranch(value, scratch);
+}
+
+
+LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LOperand* temp = TempRegister();
+  return new (zone()) LIsObjectAndBranch(value, temp);
+}
+
+
+LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LOperand* temp = TempRegister();
+  return new (zone()) LIsStringAndBranch(value, temp);
+}
+
+
+LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  return new (zone()) LIsSmiAndBranch(Use(instr->value()));
+}
+
+
+LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
+    HIsUndetectableAndBranch* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  return new (zone()) LIsUndetectableAndBranch(value, TempRegister());
+}
+
+
+LInstruction* LChunkBuilder::DoStringCompareAndBranch(
+    HStringCompareAndBranch* instr) {
+  DCHECK(instr->left()->representation().IsTagged());
+  DCHECK(instr->right()->representation().IsTagged());
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* left = UseFixed(instr->left(), r4);
+  LOperand* right = UseFixed(instr->right(), r3);
+  LStringCompareAndBranch* result =
+      new (zone()) LStringCompareAndBranch(context, left, right);
+  return MarkAsCall(result, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
+    HHasInstanceTypeAndBranch* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  return new (zone()) LHasInstanceTypeAndBranch(value);
+}
+
+
+LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
+    HGetCachedArrayIndex* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegisterAtStart(instr->value());
+
+  return DefineAsRegister(new (zone()) LGetCachedArrayIndex(value));
+}
+
+
+LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
+    HHasCachedArrayIndexAndBranch* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  return new (zone())
+      LHasCachedArrayIndexAndBranch(UseRegisterAtStart(instr->value()));
+}
+
+
+LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
+    HClassOfTestAndBranch* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegister(instr->value());
+  return new (zone()) LClassOfTestAndBranch(value, TempRegister());
+}
+
+
+LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
+  LOperand* map = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new (zone()) LMapEnumLength(map));
+}
+
+
+LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
+  LOperand* object = UseFixed(instr->value(), r3);
+  LDateField* result =
+      new (zone()) LDateField(object, FixedTemp(r4), instr->index());
+  return MarkAsCall(DefineFixed(result, r3), instr, CAN_DEOPTIMIZE_EAGERLY);
+}
+
+
+LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
+  LOperand* string = UseRegisterAtStart(instr->string());
+  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
+  return DefineAsRegister(new (zone()) LSeqStringGetChar(string, index));
+}
+
+
+LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
+  LOperand* string = UseRegisterAtStart(instr->string());
+  LOperand* index = FLAG_debug_code
+                        ? UseRegisterAtStart(instr->index())
+                        : UseRegisterOrConstantAtStart(instr->index());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
+  return new (zone()) LSeqStringSetChar(context, string, index, value);
+}
+
+
+LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
+  if (!FLAG_debug_code && instr->skip_check()) return NULL;
+  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
+  LOperand* length = !index->IsConstantOperand()
+                         ? UseRegisterOrConstantAtStart(instr->length())
+                         : UseRegisterAtStart(instr->length());
+  LInstruction* result = new (zone()) LBoundsCheck(index, length);
+  if (!FLAG_debug_code || !instr->skip_check()) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
+    HBoundsCheckBaseIndexInformation* instr) {
+  UNREACHABLE();
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
+  // The control instruction marking the end of a block that completed
+  // abruptly (e.g., threw an exception).  There is nothing specific to do.
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) { return NULL; }
+
+
+LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
+  // All HForceRepresentation instructions should be eliminated in the
+  // representation change phase of Hydrogen.
+  UNREACHABLE();
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoChange(HChange* instr) {
+  Representation from = instr->from();
+  Representation to = instr->to();
+  HValue* val = instr->value();
+  if (from.IsSmi()) {
+    if (to.IsTagged()) {
+      LOperand* value = UseRegister(val);
+      return DefineSameAsFirst(new (zone()) LDummyUse(value));
+    }
+    from = Representation::Tagged();
+  }
+  if (from.IsTagged()) {
+    if (to.IsDouble()) {
+      LOperand* value = UseRegister(val);
+      LInstruction* result =
+          DefineAsRegister(new (zone()) LNumberUntagD(value));
+      if (!val->representation().IsSmi()) result = AssignEnvironment(result);
+      return result;
+    } else if (to.IsSmi()) {
+      LOperand* value = UseRegister(val);
+      if (val->type().IsSmi()) {
+        return DefineSameAsFirst(new (zone()) LDummyUse(value));
+      }
+      return AssignEnvironment(
+          DefineSameAsFirst(new (zone()) LCheckSmi(value)));
+    } else {
+      DCHECK(to.IsInteger32());
+      if (val->type().IsSmi() || val->representation().IsSmi()) {
+        LOperand* value = UseRegisterAtStart(val);
+        return DefineAsRegister(new (zone()) LSmiUntag(value, false));
+      } else {
+        LOperand* value = UseRegister(val);
+        LOperand* temp1 = TempRegister();
+        LOperand* temp2 = TempDoubleRegister();
+        LInstruction* result =
+            DefineSameAsFirst(new (zone()) LTaggedToI(value, temp1, temp2));
+        if (!val->representation().IsSmi()) result = AssignEnvironment(result);
+        return result;
+      }
+    }
+  } else if (from.IsDouble()) {
+    if (to.IsTagged()) {
+      info()->MarkAsDeferredCalling();
+      LOperand* value = UseRegister(val);
+      LOperand* temp1 = TempRegister();
+      LOperand* temp2 = TempRegister();
+      LUnallocated* result_temp = TempRegister();
+      LNumberTagD* result = new (zone()) LNumberTagD(value, temp1, temp2);
+      return AssignPointerMap(Define(result, result_temp));
+    } else if (to.IsSmi()) {
+      LOperand* value = UseRegister(val);
+      return AssignEnvironment(
+          DefineAsRegister(new (zone()) LDoubleToSmi(value)));
+    } else {
+      DCHECK(to.IsInteger32());
+      LOperand* value = UseRegister(val);
+      LInstruction* result = DefineAsRegister(new (zone()) LDoubleToI(value));
+      if (!instr->CanTruncateToInt32()) result = AssignEnvironment(result);
+      return result;
+    }
+  } else if (from.IsInteger32()) {
+    info()->MarkAsDeferredCalling();
+    if (to.IsTagged()) {
+      if (!instr->CheckFlag(HValue::kCanOverflow)) {
+        LOperand* value = UseRegisterAtStart(val);
+        return DefineAsRegister(new (zone()) LSmiTag(value));
+      } else if (val->CheckFlag(HInstruction::kUint32)) {
+        LOperand* value = UseRegisterAtStart(val);
+        LOperand* temp1 = TempRegister();
+        LOperand* temp2 = TempRegister();
+        LNumberTagU* result = new (zone()) LNumberTagU(value, temp1, temp2);
+        return AssignPointerMap(DefineAsRegister(result));
+      } else {
+        LOperand* value = UseRegisterAtStart(val);
+        LOperand* temp1 = TempRegister();
+        LOperand* temp2 = TempRegister();
+        LNumberTagI* result = new (zone()) LNumberTagI(value, temp1, temp2);
+        return AssignPointerMap(DefineAsRegister(result));
+      }
+    } else if (to.IsSmi()) {
+      LOperand* value = UseRegister(val);
+      LInstruction* result = DefineAsRegister(new (zone()) LSmiTag(value));
+      if (instr->CheckFlag(HValue::kCanOverflow)) {
+        result = AssignEnvironment(result);
+      }
+      return result;
+    } else {
+      DCHECK(to.IsDouble());
+      if (val->CheckFlag(HInstruction::kUint32)) {
+        return DefineAsRegister(new (zone()) LUint32ToDouble(UseRegister(val)));
+      } else {
+        return DefineAsRegister(new (zone()) LInteger32ToDouble(Use(val)));
+      }
+    }
+  }
+  UNREACHABLE();
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LInstruction* result = new (zone()) LCheckNonSmi(value);
+  if (!instr->value()->type().IsHeapObject()) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
+  LOperand* value = UseRegisterAtStart(instr->value());
+  return AssignEnvironment(new (zone()) LCheckSmi(value));
+}
+
+
+LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LInstruction* result = new (zone()) LCheckInstanceType(value);
+  return AssignEnvironment(result);
+}
+
+
+LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
+  LOperand* value = UseRegisterAtStart(instr->value());
+  return AssignEnvironment(new (zone()) LCheckValue(value));
+}
+
+
+LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
+  if (instr->IsStabilityCheck()) return new (zone()) LCheckMaps;
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LInstruction* result = AssignEnvironment(new (zone()) LCheckMaps(value));
+  if (instr->HasMigrationTarget()) {
+    info()->MarkAsDeferredCalling();
+    result = AssignPointerMap(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
+  HValue* value = instr->value();
+  Representation input_rep = value->representation();
+  LOperand* reg = UseRegister(value);
+  if (input_rep.IsDouble()) {
+    return DefineAsRegister(new (zone()) LClampDToUint8(reg));
+  } else if (input_rep.IsInteger32()) {
+    return DefineAsRegister(new (zone()) LClampIToUint8(reg));
+  } else {
+    DCHECK(input_rep.IsSmiOrTagged());
+    LClampTToUint8* result =
+        new (zone()) LClampTToUint8(reg, TempDoubleRegister());
+    return AssignEnvironment(DefineAsRegister(result));
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoDoubleBits(HDoubleBits* instr) {
+  HValue* value = instr->value();
+  DCHECK(value->representation().IsDouble());
+  return DefineAsRegister(new (zone()) LDoubleBits(UseRegister(value)));
+}
+
+
+LInstruction* LChunkBuilder::DoConstructDouble(HConstructDouble* instr) {
+  LOperand* lo = UseRegister(instr->lo());
+  LOperand* hi = UseRegister(instr->hi());
+  return DefineAsRegister(new (zone()) LConstructDouble(hi, lo));
+}
+
+
+LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
+  LOperand* context = info()->IsStub() ? UseFixed(instr->context(), cp) : NULL;
+  LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
+  return new (zone())
+      LReturn(UseFixed(instr->value(), r3), context, parameter_count);
+}
+
+
+LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
+  Representation r = instr->representation();
+  if (r.IsSmi()) {
+    return DefineAsRegister(new (zone()) LConstantS);
+  } else if (r.IsInteger32()) {
+    return DefineAsRegister(new (zone()) LConstantI);
+  } else if (r.IsDouble()) {
+    return DefineAsRegister(new (zone()) LConstantD);
+  } else if (r.IsExternal()) {
+    return DefineAsRegister(new (zone()) LConstantE);
+  } else if (r.IsTagged()) {
+    return DefineAsRegister(new (zone()) LConstantT);
+  } else {
+    UNREACHABLE();
+    return NULL;
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
+  LLoadGlobalCell* result = new (zone()) LLoadGlobalCell;
+  return instr->RequiresHoleCheck()
+             ? AssignEnvironment(DefineAsRegister(result))
+             : DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* global_object =
+      UseFixed(instr->global_object(), LoadDescriptor::ReceiverRegister());
+  LOperand* vector = NULL;
+  if (FLAG_vector_ics) {
+    vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
+  }
+  LLoadGlobalGeneric* result =
+      new (zone()) LLoadGlobalGeneric(context, global_object, vector);
+  return MarkAsCall(DefineFixed(result, r3), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
+  LOperand* value = UseRegister(instr->value());
+  // Use a temp to check the value in the cell in the case where we perform
+  // a hole check.
+  return instr->RequiresHoleCheck()
+             ? AssignEnvironment(new (zone())
+                                 LStoreGlobalCell(value, TempRegister()))
+             : new (zone()) LStoreGlobalCell(value, NULL);
+}
+
+
+LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
+  LOperand* context = UseRegisterAtStart(instr->value());
+  LInstruction* result =
+      DefineAsRegister(new (zone()) LLoadContextSlot(context));
+  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
+  LOperand* context;
+  LOperand* value;
+  if (instr->NeedsWriteBarrier()) {
+    context = UseTempRegister(instr->context());
+    value = UseTempRegister(instr->value());
+  } else {
+    context = UseRegister(instr->context());
+    value = UseRegister(instr->value());
+  }
+  LInstruction* result = new (zone()) LStoreContextSlot(context, value);
+  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
+  LOperand* obj = UseRegisterAtStart(instr->object());
+  return DefineAsRegister(new (zone()) LLoadNamedField(obj));
+}
+
+
+LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* object =
+      UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
+  LOperand* vector = NULL;
+  if (FLAG_vector_ics) {
+    vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
+  }
+
+  LInstruction* result =
+      DefineFixed(new (zone()) LLoadNamedGeneric(context, object, vector), r3);
+  return MarkAsCall(result, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
+    HLoadFunctionPrototype* instr) {
+  return AssignEnvironment(DefineAsRegister(
+      new (zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
+}
+
+
+LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
+  return DefineAsRegister(new (zone()) LLoadRoot);
+}
+
+
+LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
+  DCHECK(instr->key()->representation().IsSmiOrInteger32());
+  ElementsKind elements_kind = instr->elements_kind();
+  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
+  LInstruction* result = NULL;
+
+  if (!instr->is_typed_elements()) {
+    LOperand* obj = NULL;
+    if (instr->representation().IsDouble()) {
+      obj = UseRegister(instr->elements());
+    } else {
+      obj = UseRegisterAtStart(instr->elements());
+    }
+    result = DefineAsRegister(new (zone()) LLoadKeyed(obj, key));
+  } else {
+    DCHECK((instr->representation().IsInteger32() &&
+            !IsDoubleOrFloatElementsKind(elements_kind)) ||
+           (instr->representation().IsDouble() &&
+            IsDoubleOrFloatElementsKind(elements_kind)));
+    LOperand* backing_store = UseRegister(instr->elements());
+    result = DefineAsRegister(new (zone()) LLoadKeyed(backing_store, key));
+  }
+
+  if ((instr->is_external() || instr->is_fixed_typed_array())
+          ?
+          // see LCodeGen::DoLoadKeyedExternalArray
+          ((elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+            elements_kind == UINT32_ELEMENTS) &&
+           !instr->CheckFlag(HInstruction::kUint32))
+          :
+          // see LCodeGen::DoLoadKeyedFixedDoubleArray and
+          // LCodeGen::DoLoadKeyedFixedArray
+          instr->RequiresHoleCheck()) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* object =
+      UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
+  LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
+  LOperand* vector = NULL;
+  if (FLAG_vector_ics) {
+    vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
+  }
+
+  LInstruction* result = DefineFixed(
+      new (zone()) LLoadKeyedGeneric(context, object, key, vector), r3);
+  return MarkAsCall(result, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
+  if (!instr->is_typed_elements()) {
+    DCHECK(instr->elements()->representation().IsTagged());
+    bool needs_write_barrier = instr->NeedsWriteBarrier();
+    LOperand* object = NULL;
+    LOperand* key = NULL;
+    LOperand* val = NULL;
+
+    if (instr->value()->representation().IsDouble()) {
+      object = UseRegisterAtStart(instr->elements());
+      val = UseRegister(instr->value());
+      key = UseRegisterOrConstantAtStart(instr->key());
+    } else {
+      if (needs_write_barrier) {
+        object = UseTempRegister(instr->elements());
+        val = UseTempRegister(instr->value());
+        key = UseTempRegister(instr->key());
+      } else {
+        object = UseRegisterAtStart(instr->elements());
+        val = UseRegisterAtStart(instr->value());
+        key = UseRegisterOrConstantAtStart(instr->key());
+      }
+    }
+
+    return new (zone()) LStoreKeyed(object, key, val);
+  }
+
+  DCHECK((instr->value()->representation().IsInteger32() &&
+          !IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
+         (instr->value()->representation().IsDouble() &&
+          IsDoubleOrFloatElementsKind(instr->elements_kind())));
+  DCHECK((instr->is_fixed_typed_array() &&
+          instr->elements()->representation().IsTagged()) ||
+         (instr->is_external() &&
+          instr->elements()->representation().IsExternal()));
+  LOperand* val = UseRegister(instr->value());
+  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
+  LOperand* backing_store = UseRegister(instr->elements());
+  return new (zone()) LStoreKeyed(backing_store, key, val);
+}
+
+
+LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* obj =
+      UseFixed(instr->object(), StoreDescriptor::ReceiverRegister());
+  LOperand* key = UseFixed(instr->key(), StoreDescriptor::NameRegister());
+  LOperand* val = UseFixed(instr->value(), StoreDescriptor::ValueRegister());
+
+  DCHECK(instr->object()->representation().IsTagged());
+  DCHECK(instr->key()->representation().IsTagged());
+  DCHECK(instr->value()->representation().IsTagged());
+
+  return MarkAsCall(new (zone()) LStoreKeyedGeneric(context, obj, key, val),
+                    instr);
+}
+
+
+LInstruction* LChunkBuilder::DoTransitionElementsKind(
+    HTransitionElementsKind* instr) {
+  if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
+    LOperand* object = UseRegister(instr->object());
+    LOperand* new_map_reg = TempRegister();
+    LTransitionElementsKind* result =
+        new (zone()) LTransitionElementsKind(object, NULL, new_map_reg);
+    return result;
+  } else {
+    LOperand* object = UseFixed(instr->object(), r3);
+    LOperand* context = UseFixed(instr->context(), cp);
+    LTransitionElementsKind* result =
+        new (zone()) LTransitionElementsKind(object, context, NULL);
+    return MarkAsCall(result, instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoTrapAllocationMemento(
+    HTrapAllocationMemento* instr) {
+  LOperand* object = UseRegister(instr->object());
+  LOperand* temp = TempRegister();
+  LTrapAllocationMemento* result =
+      new (zone()) LTrapAllocationMemento(object, temp);
+  return AssignEnvironment(result);
+}
+
+
+LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
+  bool is_in_object = instr->access().IsInobject();
+  bool needs_write_barrier = instr->NeedsWriteBarrier();
+  bool needs_write_barrier_for_map =
+      instr->has_transition() && instr->NeedsWriteBarrierForMap();
+
+  LOperand* obj;
+  if (needs_write_barrier) {
+    obj = is_in_object ? UseRegister(instr->object())
+                       : UseTempRegister(instr->object());
+  } else {
+    obj = needs_write_barrier_for_map ? UseRegister(instr->object())
+                                      : UseRegisterAtStart(instr->object());
+  }
+
+  LOperand* val;
+  if (needs_write_barrier) {
+    val = UseTempRegister(instr->value());
+  } else if (instr->field_representation().IsDouble()) {
+    val = UseRegisterAtStart(instr->value());
+  } else {
+    val = UseRegister(instr->value());
+  }
+
+  // We need a temporary register for write barrier of the map field.
+  LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL;
+
+  return new (zone()) LStoreNamedField(obj, val, temp);
+}
+
+
+LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* obj =
+      UseFixed(instr->object(), StoreDescriptor::ReceiverRegister());
+  LOperand* val = UseFixed(instr->value(), StoreDescriptor::ValueRegister());
+
+  LInstruction* result = new (zone()) LStoreNamedGeneric(context, obj, val);
+  return MarkAsCall(result, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* left = UseFixed(instr->left(), r4);
+  LOperand* right = UseFixed(instr->right(), r3);
+  return MarkAsCall(
+      DefineFixed(new (zone()) LStringAdd(context, left, right), r3), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
+  LOperand* string = UseTempRegister(instr->string());
+  LOperand* index = UseTempRegister(instr->index());
+  LOperand* context = UseAny(instr->context());
+  LStringCharCodeAt* result =
+      new (zone()) LStringCharCodeAt(context, string, index);
+  return AssignPointerMap(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
+  LOperand* char_code = UseRegister(instr->value());
+  LOperand* context = UseAny(instr->context());
+  LStringCharFromCode* result =
+      new (zone()) LStringCharFromCode(context, char_code);
+  return AssignPointerMap(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
+  info()->MarkAsDeferredCalling();
+  LOperand* context = UseAny(instr->context());
+  LOperand* size = UseRegisterOrConstant(instr->size());
+  LOperand* temp1 = TempRegister();
+  LOperand* temp2 = TempRegister();
+  LAllocate* result = new (zone()) LAllocate(context, size, temp1, temp2);
+  return AssignPointerMap(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  return MarkAsCall(DefineFixed(new (zone()) LRegExpLiteral(context), r3),
+                    instr);
+}
+
+
+LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  return MarkAsCall(DefineFixed(new (zone()) LFunctionLiteral(context), r3),
+                    instr);
+}
+
+
+LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
+  DCHECK(argument_count_ == 0);
+  allocator_->MarkAsOsrEntry();
+  current_block_->last_environment()->set_ast_id(instr->ast_id());
+  return AssignEnvironment(new (zone()) LOsrEntry);
+}
+
+
+LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
+  LParameter* result = new (zone()) LParameter;
+  if (instr->kind() == HParameter::STACK_PARAMETER) {
+    int spill_index = chunk()->GetParameterStackSlot(instr->index());
+    return DefineAsSpilled(result, spill_index);
+  } else {
+    DCHECK(info()->IsStub());
+    CallInterfaceDescriptor descriptor =
+        info()->code_stub()->GetCallInterfaceDescriptor();
+    int index = static_cast<int>(instr->index());
+    Register reg = descriptor.GetEnvironmentParameterRegister(index);
+    return DefineFixed(result, reg);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
+  // Use an index that corresponds to the location in the unoptimized frame,
+  // which the optimized frame will subsume.
+  int env_index = instr->index();
+  int spill_index = 0;
+  if (instr->environment()->is_parameter_index(env_index)) {
+    spill_index = chunk()->GetParameterStackSlot(env_index);
+  } else {
+    spill_index = env_index - instr->environment()->first_local_index();
+    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
+      Retry(kTooManySpillSlotsNeededForOSR);
+      spill_index = 0;
+    }
+  }
+  return DefineAsSpilled(new (zone()) LUnknownOSRValue, spill_index);
+}
+
+
+LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  return MarkAsCall(DefineFixed(new (zone()) LCallStub(context), r3), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
+  // There are no real uses of the arguments object.
+  // arguments.length and element access are supported directly on
+  // stack arguments, and any real arguments object use causes a bailout.
+  // So this value is never used.
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
+  instr->ReplayEnvironment(current_block_->last_environment());
+
+  // There are no real uses of a captured object.
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
+  info()->MarkAsRequiresFrame();
+  LOperand* args = UseRegister(instr->arguments());
+  LOperand* length = UseRegisterOrConstantAtStart(instr->length());
+  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
+  return DefineAsRegister(new (zone()) LAccessArgumentsAt(args, length, index));
+}
+
+
+LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
+  LOperand* object = UseFixed(instr->value(), r3);
+  LToFastProperties* result = new (zone()) LToFastProperties(object);
+  return MarkAsCall(DefineFixed(result, r3), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LTypeof* result = new (zone()) LTypeof(context, UseFixed(instr->value(), r3));
+  return MarkAsCall(DefineFixed(result, r3), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
+  return new (zone()) LTypeofIsAndBranch(UseRegister(instr->value()));
+}
+
+
+LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
+    HIsConstructCallAndBranch* instr) {
+  return new (zone()) LIsConstructCallAndBranch(TempRegister());
+}
+
+
+LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
+  instr->ReplayEnvironment(current_block_->last_environment());
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
+  if (instr->is_function_entry()) {
+    LOperand* context = UseFixed(instr->context(), cp);
+    return MarkAsCall(new (zone()) LStackCheck(context), instr);
+  } else {
+    DCHECK(instr->is_backwards_branch());
+    LOperand* context = UseAny(instr->context());
+    return AssignEnvironment(
+        AssignPointerMap(new (zone()) LStackCheck(context)));
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
+  HEnvironment* outer = current_block_->last_environment();
+  outer->set_ast_id(instr->ReturnId());
+  HConstant* undefined = graph()->GetConstantUndefined();
+  HEnvironment* inner = outer->CopyForInlining(
+      instr->closure(), instr->arguments_count(), instr->function(), undefined,
+      instr->inlining_kind());
+  // Only replay binding of arguments object if it wasn't removed from graph.
+  if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
+    inner->Bind(instr->arguments_var(), instr->arguments_object());
+  }
+  inner->BindContext(instr->closure_context());
+  inner->set_entry(instr);
+  current_block_->UpdateEnvironment(inner);
+  chunk_->AddInlinedClosure(instr->closure());
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
+  LInstruction* pop = NULL;
+
+  HEnvironment* env = current_block_->last_environment();
+
+  if (env->entry()->arguments_pushed()) {
+    int argument_count = env->arguments_environment()->parameter_count();
+    pop = new (zone()) LDrop(argument_count);
+    DCHECK(instr->argument_delta() == -argument_count);
+  }
+
+  HEnvironment* outer =
+      current_block_->last_environment()->DiscardInlined(false);
+  current_block_->UpdateEnvironment(outer);
+
+  return pop;
+}
+
+
+LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* object = UseFixed(instr->enumerable(), r3);
+  LForInPrepareMap* result = new (zone()) LForInPrepareMap(context, object);
+  return MarkAsCall(DefineFixed(result, r3), instr, CAN_DEOPTIMIZE_EAGERLY);
+}
+
+
+LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
+  LOperand* map = UseRegister(instr->map());
+  return AssignEnvironment(
+      DefineAsRegister(new (zone()) LForInCacheArray(map)));
+}
+
+
+LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LOperand* map = UseRegisterAtStart(instr->map());
+  return AssignEnvironment(new (zone()) LCheckMapValue(value, map));
+}
+
+
+LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
+  LOperand* object = UseRegister(instr->object());
+  LOperand* index = UseTempRegister(instr->index());
+  LLoadFieldByIndex* load = new (zone()) LLoadFieldByIndex(object, index);
+  LInstruction* result = DefineSameAsFirst(load);
+  return AssignPointerMap(result);
+}
+
+
+LInstruction* LChunkBuilder::DoStoreFrameContext(HStoreFrameContext* instr) {
+  LOperand* context = UseRegisterAtStart(instr->context());
+  return new (zone()) LStoreFrameContext(context);
+}
+
+
+LInstruction* LChunkBuilder::DoAllocateBlockContext(
+    HAllocateBlockContext* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* function = UseRegisterAtStart(instr->function());
+  LAllocateBlockContext* result =
+      new (zone()) LAllocateBlockContext(context, function);
+  return MarkAsCall(DefineFixed(result, cp), instr);
+}
+}
+}  // namespace v8::internal
diff --git a/src/ppc/lithium-ppc.h b/src/ppc/lithium-ppc.h
new file mode 100644
index 0000000..2176fa6
--- /dev/null
+++ b/src/ppc/lithium-ppc.h
@@ -0,0 +1,2746 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PPC_LITHIUM_PPC_H_
+#define V8_PPC_LITHIUM_PPC_H_
+
+#include "src/hydrogen.h"
+#include "src/lithium.h"
+#include "src/lithium-allocator.h"
+#include "src/safepoint-table.h"
+#include "src/utils.h"
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class LCodeGen;
+
+#define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \
+  V(AccessArgumentsAt)                       \
+  V(AddI)                                    \
+  V(Allocate)                                \
+  V(AllocateBlockContext)                    \
+  V(ApplyArguments)                          \
+  V(ArgumentsElements)                       \
+  V(ArgumentsLength)                         \
+  V(ArithmeticD)                             \
+  V(ArithmeticT)                             \
+  V(BitI)                                    \
+  V(BoundsCheck)                             \
+  V(Branch)                                  \
+  V(CallJSFunction)                          \
+  V(CallWithDescriptor)                      \
+  V(CallFunction)                            \
+  V(CallNew)                                 \
+  V(CallNewArray)                            \
+  V(CallRuntime)                             \
+  V(CallStub)                                \
+  V(CheckInstanceType)                       \
+  V(CheckNonSmi)                             \
+  V(CheckMaps)                               \
+  V(CheckMapValue)                           \
+  V(CheckSmi)                                \
+  V(CheckValue)                              \
+  V(ClampDToUint8)                           \
+  V(ClampIToUint8)                           \
+  V(ClampTToUint8)                           \
+  V(ClassOfTestAndBranch)                    \
+  V(CompareMinusZeroAndBranch)               \
+  V(CompareNumericAndBranch)                 \
+  V(CmpObjectEqAndBranch)                    \
+  V(CmpHoleAndBranch)                        \
+  V(CmpMapAndBranch)                         \
+  V(CmpT)                                    \
+  V(ConstantD)                               \
+  V(ConstantE)                               \
+  V(ConstantI)                               \
+  V(ConstantS)                               \
+  V(ConstantT)                               \
+  V(ConstructDouble)                         \
+  V(Context)                                 \
+  V(DateField)                               \
+  V(DebugBreak)                              \
+  V(DeclareGlobals)                          \
+  V(Deoptimize)                              \
+  V(DivByConstI)                             \
+  V(DivByPowerOf2I)                          \
+  V(DivI)                                    \
+  V(DoubleBits)                              \
+  V(DoubleToI)                               \
+  V(DoubleToSmi)                             \
+  V(Drop)                                    \
+  V(Dummy)                                   \
+  V(DummyUse)                                \
+  V(FlooringDivByConstI)                     \
+  V(FlooringDivByPowerOf2I)                  \
+  V(FlooringDivI)                            \
+  V(ForInCacheArray)                         \
+  V(ForInPrepareMap)                         \
+  V(FunctionLiteral)                         \
+  V(GetCachedArrayIndex)                     \
+  V(Goto)                                    \
+  V(HasCachedArrayIndexAndBranch)            \
+  V(HasInstanceTypeAndBranch)                \
+  V(InnerAllocatedObject)                    \
+  V(InstanceOf)                              \
+  V(InstanceOfKnownGlobal)                   \
+  V(InstructionGap)                          \
+  V(Integer32ToDouble)                       \
+  V(InvokeFunction)                          \
+  V(IsConstructCallAndBranch)                \
+  V(IsObjectAndBranch)                       \
+  V(IsStringAndBranch)                       \
+  V(IsSmiAndBranch)                          \
+  V(IsUndetectableAndBranch)                 \
+  V(Label)                                   \
+  V(LazyBailout)                             \
+  V(LoadContextSlot)                         \
+  V(LoadRoot)                                \
+  V(LoadFieldByIndex)                        \
+  V(LoadFunctionPrototype)                   \
+  V(LoadGlobalCell)                          \
+  V(LoadGlobalGeneric)                       \
+  V(LoadKeyed)                               \
+  V(LoadKeyedGeneric)                        \
+  V(LoadNamedField)                          \
+  V(LoadNamedGeneric)                        \
+  V(MapEnumLength)                           \
+  V(MathAbs)                                 \
+  V(MathClz32)                               \
+  V(MathExp)                                 \
+  V(MathFloor)                               \
+  V(MathFround)                              \
+  V(MathLog)                                 \
+  V(MathMinMax)                              \
+  V(MathPowHalf)                             \
+  V(MathRound)                               \
+  V(MathSqrt)                                \
+  V(ModByConstI)                             \
+  V(ModByPowerOf2I)                          \
+  V(ModI)                                    \
+  V(MulI)                                    \
+  V(MultiplyAddD)                            \
+  V(MultiplySubD)                            \
+  V(NumberTagD)                              \
+  V(NumberTagI)                              \
+  V(NumberTagU)                              \
+  V(NumberUntagD)                            \
+  V(OsrEntry)                                \
+  V(Parameter)                               \
+  V(Power)                                   \
+  V(PushArgument)                            \
+  V(RegExpLiteral)                           \
+  V(Return)                                  \
+  V(SeqStringGetChar)                        \
+  V(SeqStringSetChar)                        \
+  V(ShiftI)                                  \
+  V(SmiTag)                                  \
+  V(SmiUntag)                                \
+  V(StackCheck)                              \
+  V(StoreCodeEntry)                          \
+  V(StoreContextSlot)                        \
+  V(StoreFrameContext)                       \
+  V(StoreGlobalCell)                         \
+  V(StoreKeyed)                              \
+  V(StoreKeyedGeneric)                       \
+  V(StoreNamedField)                         \
+  V(StoreNamedGeneric)                       \
+  V(StringAdd)                               \
+  V(StringCharCodeAt)                        \
+  V(StringCharFromCode)                      \
+  V(StringCompareAndBranch)                  \
+  V(SubI)                                    \
+  V(RSubI)                                   \
+  V(TaggedToI)                               \
+  V(TailCallThroughMegamorphicCache)         \
+  V(ThisFunction)                            \
+  V(ToFastProperties)                        \
+  V(TransitionElementsKind)                  \
+  V(TrapAllocationMemento)                   \
+  V(Typeof)                                  \
+  V(TypeofIsAndBranch)                       \
+  V(Uint32ToDouble)                          \
+  V(UnknownOSRValue)                         \
+  V(WrapReceiver)
+
+
+#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)            \
+  Opcode opcode() const FINAL { return LInstruction::k##type; } \
+  void CompileToNative(LCodeGen* generator) FINAL;              \
+  const char* Mnemonic() const FINAL { return mnemonic; }       \
+  static L##type* cast(LInstruction* instr) {                   \
+    DCHECK(instr->Is##type());                                  \
+    return reinterpret_cast<L##type*>(instr);                   \
+  }
+
+
+#define DECLARE_HYDROGEN_ACCESSOR(type) \
+  H##type* hydrogen() const { return H##type::cast(hydrogen_value()); }
+
+
+class LInstruction : public ZoneObject {
+ public:
+  LInstruction()
+      : environment_(NULL),
+        hydrogen_value_(NULL),
+        bit_field_(IsCallBits::encode(false)) {}
+
+  virtual ~LInstruction() {}
+
+  virtual void CompileToNative(LCodeGen* generator) = 0;
+  virtual const char* Mnemonic() const = 0;
+  virtual void PrintTo(StringStream* stream);
+  virtual void PrintDataTo(StringStream* stream);
+  virtual void PrintOutputOperandTo(StringStream* stream);
+
+  enum Opcode {
+// Declare a unique enum value for each instruction.
+#define DECLARE_OPCODE(type) k##type,
+    LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE) kNumberOfInstructions
+#undef DECLARE_OPCODE
+  };
+
+  virtual Opcode opcode() const = 0;
+
+// Declare non-virtual type testers for all leaf IR classes.
+#define DECLARE_PREDICATE(type) \
+  bool Is##type() const { return opcode() == k##type; }
+  LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
+#undef DECLARE_PREDICATE
+
+  // Declare virtual predicates for instructions that don't have
+  // an opcode.
+  virtual bool IsGap() const { return false; }
+
+  virtual bool IsControl() const { return false; }
+
+  // Try deleting this instruction if possible.
+  virtual bool TryDelete() { return false; }
+
+  void set_environment(LEnvironment* env) { environment_ = env; }
+  LEnvironment* environment() const { return environment_; }
+  bool HasEnvironment() const { return environment_ != NULL; }
+
+  void set_pointer_map(LPointerMap* p) { pointer_map_.set(p); }
+  LPointerMap* pointer_map() const { return pointer_map_.get(); }
+  bool HasPointerMap() const { return pointer_map_.is_set(); }
+
+  void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; }
+  HValue* hydrogen_value() const { return hydrogen_value_; }
+
+  virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) {}
+
+  void MarkAsCall() { bit_field_ = IsCallBits::update(bit_field_, true); }
+  bool IsCall() const { return IsCallBits::decode(bit_field_); }
+
+  // Interface to the register allocator and iterators.
+  bool ClobbersTemps() const { return IsCall(); }
+  bool ClobbersRegisters() const { return IsCall(); }
+  virtual bool ClobbersDoubleRegisters(Isolate* isolate) const {
+    return IsCall();
+  }
+
+  // Interface to the register allocator and iterators.
+  bool IsMarkedAsCall() const { return IsCall(); }
+
+  virtual bool HasResult() const = 0;
+  virtual LOperand* result() const = 0;
+
+  LOperand* FirstInput() { return InputAt(0); }
+  LOperand* Output() { return HasResult() ? result() : NULL; }
+
+  virtual bool HasInterestingComment(LCodeGen* gen) const { return true; }
+
+#ifdef DEBUG
+  void VerifyCall();
+#endif
+
+  virtual int InputCount() = 0;
+  virtual LOperand* InputAt(int i) = 0;
+
+ private:
+  // Iterator support.
+  friend class InputIterator;
+
+  friend class TempIterator;
+  virtual int TempCount() = 0;
+  virtual LOperand* TempAt(int i) = 0;
+
+  class IsCallBits : public BitField<bool, 0, 1> {};
+
+  LEnvironment* environment_;
+  SetOncePointer<LPointerMap> pointer_map_;
+  HValue* hydrogen_value_;
+  int bit_field_;
+};
+
+
+// R = number of result operands (0 or 1).
+template <int R>
+class LTemplateResultInstruction : public LInstruction {
+ public:
+  // Allow 0 or 1 output operands.
+  STATIC_ASSERT(R == 0 || R == 1);
+  bool HasResult() const FINAL { return R != 0 && result() != NULL; }
+  void set_result(LOperand* operand) { results_[0] = operand; }
+  LOperand* result() const { return results_[0]; }
+
+ protected:
+  EmbeddedContainer<LOperand*, R> results_;
+};
+
+
+// R = number of result operands (0 or 1).
+// I = number of input operands.
+// T = number of temporary operands.
+template <int R, int I, int T>
+class LTemplateInstruction : public LTemplateResultInstruction<R> {
+ protected:
+  EmbeddedContainer<LOperand*, I> inputs_;
+  EmbeddedContainer<LOperand*, T> temps_;
+
+ private:
+  // Iterator support.
+  int InputCount() FINAL { return I; }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
+
+  int TempCount() FINAL { return T; }
+  LOperand* TempAt(int i) FINAL { return temps_[i]; }
+};
+
+
+class LGap : public LTemplateInstruction<0, 0, 0> {
+ public:
+  explicit LGap(HBasicBlock* block) : block_(block) {
+    parallel_moves_[BEFORE] = NULL;
+    parallel_moves_[START] = NULL;
+    parallel_moves_[END] = NULL;
+    parallel_moves_[AFTER] = NULL;
+  }
+
+  // Can't use the DECLARE-macro here because of sub-classes.
+  bool IsGap() const OVERRIDE { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+  static LGap* cast(LInstruction* instr) {
+    DCHECK(instr->IsGap());
+    return reinterpret_cast<LGap*>(instr);
+  }
+
+  bool IsRedundant() const;
+
+  HBasicBlock* block() const { return block_; }
+
+  enum InnerPosition {
+    BEFORE,
+    START,
+    END,
+    AFTER,
+    FIRST_INNER_POSITION = BEFORE,
+    LAST_INNER_POSITION = AFTER
+  };
+
+  LParallelMove* GetOrCreateParallelMove(InnerPosition pos, Zone* zone) {
+    if (parallel_moves_[pos] == NULL) {
+      parallel_moves_[pos] = new (zone) LParallelMove(zone);
+    }
+    return parallel_moves_[pos];
+  }
+
+  LParallelMove* GetParallelMove(InnerPosition pos) {
+    return parallel_moves_[pos];
+  }
+
+ private:
+  LParallelMove* parallel_moves_[LAST_INNER_POSITION + 1];
+  HBasicBlock* block_;
+};
+
+
+class LInstructionGap FINAL : public LGap {
+ public:
+  explicit LInstructionGap(HBasicBlock* block) : LGap(block) {}
+
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
+    return !IsRedundant();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(InstructionGap, "gap")
+};
+
+
+class LGoto FINAL : public LTemplateInstruction<0, 0, 0> {
+ public:
+  explicit LGoto(HBasicBlock* block) : block_(block) {}
+
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
+  DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsControl() const OVERRIDE { return true; }
+
+  int block_id() const { return block_->block_id(); }
+
+ private:
+  HBasicBlock* block_;
+};
+
+
+class LLazyBailout FINAL : public LTemplateInstruction<0, 0, 0> {
+ public:
+  LLazyBailout() : gap_instructions_size_(0) {}
+
+  DECLARE_CONCRETE_INSTRUCTION(LazyBailout, "lazy-bailout")
+
+  void set_gap_instructions_size(int gap_instructions_size) {
+    gap_instructions_size_ = gap_instructions_size;
+  }
+  int gap_instructions_size() { return gap_instructions_size_; }
+
+ private:
+  int gap_instructions_size_;
+};
+
+
+class LDummy FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  LDummy() {}
+  DECLARE_CONCRETE_INSTRUCTION(Dummy, "dummy")
+};
+
+
+class LDummyUse FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LDummyUse(LOperand* value) { inputs_[0] = value; }
+  DECLARE_CONCRETE_INSTRUCTION(DummyUse, "dummy-use")
+};
+
+
+class LDeoptimize FINAL : public LTemplateInstruction<0, 0, 0> {
+ public:
+  bool IsControl() const OVERRIDE { return true; }
+  DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
+  DECLARE_HYDROGEN_ACCESSOR(Deoptimize)
+};
+
+
+class LLabel FINAL : public LGap {
+ public:
+  explicit LLabel(HBasicBlock* block) : LGap(block), replacement_(NULL) {}
+
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
+  DECLARE_CONCRETE_INSTRUCTION(Label, "label")
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  int block_id() const { return block()->block_id(); }
+  bool is_loop_header() const { return block()->IsLoopHeader(); }
+  bool is_osr_entry() const { return block()->is_osr_entry(); }
+  Label* label() { return &label_; }
+  LLabel* replacement() const { return replacement_; }
+  void set_replacement(LLabel* label) { replacement_ = label; }
+  bool HasReplacement() const { return replacement_ != NULL; }
+
+ private:
+  Label label_;
+  LLabel* replacement_;
+};
+
+
+class LParameter FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  virtual bool HasInterestingComment(LCodeGen* gen) const { return false; }
+  DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter")
+};
+
+
+class LCallStub FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LCallStub(LOperand* context) { inputs_[0] = context; }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallStub, "call-stub")
+  DECLARE_HYDROGEN_ACCESSOR(CallStub)
+};
+
+
+class LTailCallThroughMegamorphicCache FINAL
+    : public LTemplateInstruction<0, 3, 0> {
+ public:
+  explicit LTailCallThroughMegamorphicCache(LOperand* context,
+                                            LOperand* receiver,
+                                            LOperand* name) {
+    inputs_[0] = context;
+    inputs_[1] = receiver;
+    inputs_[2] = name;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* receiver() { return inputs_[1]; }
+  LOperand* name() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
+                               "tail-call-through-megamorphic-cache")
+  DECLARE_HYDROGEN_ACCESSOR(TailCallThroughMegamorphicCache)
+};
+
+class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
+  DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown-osr-value")
+};
+
+
+template <int I, int T>
+class LControlInstruction : public LTemplateInstruction<0, I, T> {
+ public:
+  LControlInstruction() : false_label_(NULL), true_label_(NULL) {}
+
+  bool IsControl() const FINAL { return true; }
+
+  int SuccessorCount() { return hydrogen()->SuccessorCount(); }
+  HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); }
+
+  int TrueDestination(LChunk* chunk) {
+    return chunk->LookupDestination(true_block_id());
+  }
+  int FalseDestination(LChunk* chunk) {
+    return chunk->LookupDestination(false_block_id());
+  }
+
+  Label* TrueLabel(LChunk* chunk) {
+    if (true_label_ == NULL) {
+      true_label_ = chunk->GetAssemblyLabel(TrueDestination(chunk));
+    }
+    return true_label_;
+  }
+  Label* FalseLabel(LChunk* chunk) {
+    if (false_label_ == NULL) {
+      false_label_ = chunk->GetAssemblyLabel(FalseDestination(chunk));
+    }
+    return false_label_;
+  }
+
+ protected:
+  int true_block_id() { return SuccessorAt(0)->block_id(); }
+  int false_block_id() { return SuccessorAt(1)->block_id(); }
+
+ private:
+  HControlInstruction* hydrogen() {
+    return HControlInstruction::cast(this->hydrogen_value());
+  }
+
+  Label* false_label_;
+  Label* true_label_;
+};
+
+
+class LWrapReceiver FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LWrapReceiver(LOperand* receiver, LOperand* function) {
+    inputs_[0] = receiver;
+    inputs_[1] = function;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver")
+  DECLARE_HYDROGEN_ACCESSOR(WrapReceiver)
+
+  LOperand* receiver() { return inputs_[0]; }
+  LOperand* function() { return inputs_[1]; }
+};
+
+
+class LApplyArguments FINAL : public LTemplateInstruction<1, 4, 0> {
+ public:
+  LApplyArguments(LOperand* function, LOperand* receiver, LOperand* length,
+                  LOperand* elements) {
+    inputs_[0] = function;
+    inputs_[1] = receiver;
+    inputs_[2] = length;
+    inputs_[3] = elements;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments")
+
+  LOperand* function() { return inputs_[0]; }
+  LOperand* receiver() { return inputs_[1]; }
+  LOperand* length() { return inputs_[2]; }
+  LOperand* elements() { return inputs_[3]; }
+};
+
+
+class LAccessArgumentsAt FINAL : public LTemplateInstruction<1, 3, 0> {
+ public:
+  LAccessArgumentsAt(LOperand* arguments, LOperand* length, LOperand* index) {
+    inputs_[0] = arguments;
+    inputs_[1] = length;
+    inputs_[2] = index;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at")
+
+  LOperand* arguments() { return inputs_[0]; }
+  LOperand* length() { return inputs_[1]; }
+  LOperand* index() { return inputs_[2]; }
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LArgumentsLength FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LArgumentsLength(LOperand* elements) { inputs_[0] = elements; }
+
+  LOperand* elements() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments-length")
+};
+
+
+class LArgumentsElements FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements")
+  DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements)
+};
+
+
+class LModByPowerOf2I FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  LModByPowerOf2I(LOperand* dividend, int32_t divisor) {
+    inputs_[0] = dividend;
+    divisor_ = divisor;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  int32_t divisor() const { return divisor_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ModByPowerOf2I, "mod-by-power-of-2-i")
+  DECLARE_HYDROGEN_ACCESSOR(Mod)
+
+ private:
+  int32_t divisor_;
+};
+
+
+class LModByConstI FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  LModByConstI(LOperand* dividend, int32_t divisor) {
+    inputs_[0] = dividend;
+    divisor_ = divisor;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  int32_t divisor() const { return divisor_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ModByConstI, "mod-by-const-i")
+  DECLARE_HYDROGEN_ACCESSOR(Mod)
+
+ private:
+  int32_t divisor_;
+};
+
+
+class LModI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LModI(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i")
+  DECLARE_HYDROGEN_ACCESSOR(Mod)
+};
+
+
+class LDivByPowerOf2I FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  LDivByPowerOf2I(LOperand* dividend, int32_t divisor) {
+    inputs_[0] = dividend;
+    divisor_ = divisor;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  int32_t divisor() const { return divisor_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DivByPowerOf2I, "div-by-power-of-2-i")
+  DECLARE_HYDROGEN_ACCESSOR(Div)
+
+ private:
+  int32_t divisor_;
+};
+
+
+class LDivByConstI FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  LDivByConstI(LOperand* dividend, int32_t divisor) {
+    inputs_[0] = dividend;
+    divisor_ = divisor;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  int32_t divisor() const { return divisor_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DivByConstI, "div-by-const-i")
+  DECLARE_HYDROGEN_ACCESSOR(Div)
+
+ private:
+  int32_t divisor_;
+};
+
+
+class LDivI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LDivI(LOperand* dividend, LOperand* divisor) {
+    inputs_[0] = dividend;
+    inputs_[1] = divisor;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  LOperand* divisor() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
+  DECLARE_HYDROGEN_ACCESSOR(BinaryOperation)
+};
+
+
+class LFlooringDivByPowerOf2I FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  LFlooringDivByPowerOf2I(LOperand* dividend, int32_t divisor) {
+    inputs_[0] = dividend;
+    divisor_ = divisor;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  int32_t divisor() { return divisor_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(FlooringDivByPowerOf2I,
+                               "flooring-div-by-power-of-2-i")
+  DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
+
+ private:
+  int32_t divisor_;
+};
+
+
+class LFlooringDivByConstI FINAL : public LTemplateInstruction<1, 1, 1> {
+ public:
+  LFlooringDivByConstI(LOperand* dividend, int32_t divisor, LOperand* temp) {
+    inputs_[0] = dividend;
+    divisor_ = divisor;
+    temps_[0] = temp;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  int32_t divisor() const { return divisor_; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(FlooringDivByConstI, "flooring-div-by-const-i")
+  DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
+
+ private:
+  int32_t divisor_;
+};
+
+
+class LFlooringDivI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LFlooringDivI(LOperand* dividend, LOperand* divisor) {
+    inputs_[0] = dividend;
+    inputs_[1] = divisor;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  LOperand* divisor() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(FlooringDivI, "flooring-div-i")
+  DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
+};
+
+
+class LMulI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LMulI(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i")
+  DECLARE_HYDROGEN_ACCESSOR(Mul)
+};
+
+
+// Instruction for computing multiplier * multiplicand + addend.
+class LMultiplyAddD FINAL : public LTemplateInstruction<1, 3, 0> {
+ public:
+  LMultiplyAddD(LOperand* addend, LOperand* multiplier,
+                LOperand* multiplicand) {
+    inputs_[0] = addend;
+    inputs_[1] = multiplier;
+    inputs_[2] = multiplicand;
+  }
+
+  LOperand* addend() { return inputs_[0]; }
+  LOperand* multiplier() { return inputs_[1]; }
+  LOperand* multiplicand() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MultiplyAddD, "multiply-add-d")
+};
+
+
+// Instruction for computing minuend - multiplier * multiplicand.
+class LMultiplySubD FINAL : public LTemplateInstruction<1, 3, 0> {
+ public:
+  LMultiplySubD(LOperand* minuend, LOperand* multiplier,
+                LOperand* multiplicand) {
+    inputs_[0] = minuend;
+    inputs_[1] = multiplier;
+    inputs_[2] = multiplicand;
+  }
+
+  LOperand* minuend() { return inputs_[0]; }
+  LOperand* multiplier() { return inputs_[1]; }
+  LOperand* multiplicand() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MultiplySubD, "multiply-sub-d")
+};
+
+
+class LDebugBreak FINAL : public LTemplateInstruction<0, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(DebugBreak, "break")
+};
+
+
+class LCompareNumericAndBranch FINAL : public LControlInstruction<2, 0> {
+ public:
+  LCompareNumericAndBranch(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch,
+                               "compare-numeric-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(CompareNumericAndBranch)
+
+  Token::Value op() const { return hydrogen()->token(); }
+  bool is_double() const { return hydrogen()->representation().IsDouble(); }
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LMathFloor FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathFloor(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathFloor, "math-floor")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathRound FINAL : public LTemplateInstruction<1, 1, 1> {
+ public:
+  LMathRound(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathFround FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathFround(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathFround, "math-fround")
+};
+
+
+class LMathAbs FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LMathAbs(LOperand* context, LOperand* value) {
+    inputs_[1] = context;
+    inputs_[0] = value;
+  }
+
+  LOperand* context() { return inputs_[1]; }
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathAbs, "math-abs")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathLog FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathLog(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathLog, "math-log")
+};
+
+
+class LMathClz32 FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathClz32(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
+};
+
+
+class LMathExp FINAL : public LTemplateInstruction<1, 1, 3> {
+ public:
+  LMathExp(LOperand* value, LOperand* double_temp, LOperand* temp1,
+           LOperand* temp2) {
+    inputs_[0] = value;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+    temps_[2] = double_temp;
+    ExternalReference::InitializeMathExpData();
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+  LOperand* double_temp() { return temps_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
+};
+
+
+class LMathSqrt FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathSqrt(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathSqrt, "math-sqrt")
+};
+
+
+class LMathPowHalf FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathPowHalf(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
+};
+
+
+class LCmpObjectEqAndBranch FINAL : public LControlInstruction<2, 0> {
+ public:
+  LCmpObjectEqAndBranch(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch, "cmp-object-eq-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(CompareObjectEqAndBranch)
+};
+
+
+class LCmpHoleAndBranch FINAL : public LControlInstruction<1, 0> {
+ public:
+  explicit LCmpHoleAndBranch(LOperand* object) { inputs_[0] = object; }
+
+  LOperand* object() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CmpHoleAndBranch, "cmp-hole-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(CompareHoleAndBranch)
+};
+
+
+class LCompareMinusZeroAndBranch FINAL : public LControlInstruction<1, 1> {
+ public:
+  LCompareMinusZeroAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch,
+                               "cmp-minus-zero-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(CompareMinusZeroAndBranch)
+};
+
+
+class LIsObjectAndBranch FINAL : public LControlInstruction<1, 1> {
+ public:
+  LIsObjectAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LIsStringAndBranch FINAL : public LControlInstruction<1, 1> {
+ public:
+  LIsStringAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LIsSmiAndBranch FINAL : public LControlInstruction<1, 0> {
+ public:
+  explicit LIsSmiAndBranch(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LIsUndetectableAndBranch FINAL : public LControlInstruction<1, 1> {
+ public:
+  explicit LIsUndetectableAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch,
+                               "is-undetectable-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LStringCompareAndBranch FINAL : public LControlInstruction<3, 0> {
+ public:
+  LStringCompareAndBranch(LOperand* context, LOperand* left, LOperand* right) {
+    inputs_[0] = context;
+    inputs_[1] = left;
+    inputs_[2] = right;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* left() { return inputs_[1]; }
+  LOperand* right() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch,
+                               "string-compare-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch)
+
+  Token::Value op() const { return hydrogen()->token(); }
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LHasInstanceTypeAndBranch FINAL : public LControlInstruction<1, 0> {
+ public:
+  explicit LHasInstanceTypeAndBranch(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch,
+                               "has-instance-type-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LGetCachedArrayIndex FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LGetCachedArrayIndex(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex, "get-cached-array-index")
+  DECLARE_HYDROGEN_ACCESSOR(GetCachedArrayIndex)
+};
+
+
+class LHasCachedArrayIndexAndBranch FINAL : public LControlInstruction<1, 0> {
+ public:
+  explicit LHasCachedArrayIndexAndBranch(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch,
+                               "has-cached-array-index-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LClassOfTestAndBranch FINAL : public LControlInstruction<1, 1> {
+ public:
+  LClassOfTestAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, "class-of-test-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LCmpT FINAL : public LTemplateInstruction<1, 3, 0> {
+ public:
+  LCmpT(LOperand* context, LOperand* left, LOperand* right) {
+    inputs_[0] = context;
+    inputs_[1] = left;
+    inputs_[2] = right;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* left() { return inputs_[1]; }
+  LOperand* right() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
+  DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
+
+  Token::Value op() const { return hydrogen()->token(); }
+};
+
+
+class LInstanceOf FINAL : public LTemplateInstruction<1, 3, 0> {
+ public:
+  LInstanceOf(LOperand* context, LOperand* left, LOperand* right) {
+    inputs_[0] = context;
+    inputs_[1] = left;
+    inputs_[2] = right;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* left() { return inputs_[1]; }
+  LOperand* right() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of")
+};
+
+
+class LInstanceOfKnownGlobal FINAL : public LTemplateInstruction<1, 2, 1> {
+ public:
+  LInstanceOfKnownGlobal(LOperand* context, LOperand* value, LOperand* temp) {
+    inputs_[0] = context;
+    inputs_[1] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* value() { return inputs_[1]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal,
+                               "instance-of-known-global")
+  DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal)
+
+  Handle<JSFunction> function() const { return hydrogen()->function(); }
+  LEnvironment* GetDeferredLazyDeoptimizationEnvironment() {
+    return lazy_deopt_env_;
+  }
+  virtual void SetDeferredLazyDeoptimizationEnvironment(
+      LEnvironment* env) OVERRIDE {
+    lazy_deopt_env_ = env;
+  }
+
+ private:
+  LEnvironment* lazy_deopt_env_;
+};
+
+
+class LBoundsCheck FINAL : public LTemplateInstruction<0, 2, 0> {
+ public:
+  LBoundsCheck(LOperand* index, LOperand* length) {
+    inputs_[0] = index;
+    inputs_[1] = length;
+  }
+
+  LOperand* index() { return inputs_[0]; }
+  LOperand* length() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(BoundsCheck, "bounds-check")
+  DECLARE_HYDROGEN_ACCESSOR(BoundsCheck)
+};
+
+
+class LBitI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LBitI(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  Token::Value op() const { return hydrogen()->op(); }
+
+  DECLARE_CONCRETE_INSTRUCTION(BitI, "bit-i")
+  DECLARE_HYDROGEN_ACCESSOR(Bitwise)
+};
+
+
+class LShiftI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LShiftI(Token::Value op, LOperand* left, LOperand* right, bool can_deopt)
+      : op_(op), can_deopt_(can_deopt) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  Token::Value op() const { return op_; }
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+  bool can_deopt() const { return can_deopt_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ShiftI, "shift-i")
+
+ private:
+  Token::Value op_;
+  bool can_deopt_;
+};
+
+
+class LSubI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LSubI(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(SubI, "sub-i")
+  DECLARE_HYDROGEN_ACCESSOR(Sub)
+};
+
+
+class LRSubI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LRSubI(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(RSubI, "rsub-i")
+  DECLARE_HYDROGEN_ACCESSOR(Sub)
+};
+
+
+class LConstantI FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(ConstantI, "constant-i")
+  DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+  int32_t value() const { return hydrogen()->Integer32Value(); }
+};
+
+
+class LConstantS FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(ConstantS, "constant-s")
+  DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+  Smi* value() const { return Smi::FromInt(hydrogen()->Integer32Value()); }
+};
+
+
+class LConstantD FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d")
+  DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+  double value() const { return hydrogen()->DoubleValue(); }
+};
+
+
+class LConstantE FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(ConstantE, "constant-e")
+  DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+  ExternalReference value() const {
+    return hydrogen()->ExternalReferenceValue();
+  }
+};
+
+
+class LConstantT FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(ConstantT, "constant-t")
+  DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+  Handle<Object> value(Isolate* isolate) const {
+    return hydrogen()->handle(isolate);
+  }
+};
+
+
+class LBranch FINAL : public LControlInstruction<1, 0> {
+ public:
+  explicit LBranch(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
+  DECLARE_HYDROGEN_ACCESSOR(Branch)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LCmpMapAndBranch FINAL : public LControlInstruction<1, 1> {
+ public:
+  LCmpMapAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(CompareMap)
+
+  Handle<Map> map() const { return hydrogen()->map().handle(); }
+};
+
+
+class LMapEnumLength FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMapEnumLength(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MapEnumLength, "map-enum-length")
+};
+
+
+class LDateField FINAL : public LTemplateInstruction<1, 1, 1> {
+ public:
+  LDateField(LOperand* date, LOperand* temp, Smi* index) : index_(index) {
+    inputs_[0] = date;
+    temps_[0] = temp;
+  }
+
+  LOperand* date() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+  Smi* index() const { return index_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DateField, "date-field")
+  DECLARE_HYDROGEN_ACCESSOR(DateField)
+
+ private:
+  Smi* index_;
+};
+
+
+class LSeqStringGetChar FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LSeqStringGetChar(LOperand* string, LOperand* index) {
+    inputs_[0] = string;
+    inputs_[1] = index;
+  }
+
+  LOperand* string() const { return inputs_[0]; }
+  LOperand* index() const { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar, "seq-string-get-char")
+  DECLARE_HYDROGEN_ACCESSOR(SeqStringGetChar)
+};
+
+
+class LSeqStringSetChar FINAL : public LTemplateInstruction<1, 4, 0> {
+ public:
+  LSeqStringSetChar(LOperand* context, LOperand* string, LOperand* index,
+                    LOperand* value) {
+    inputs_[0] = context;
+    inputs_[1] = string;
+    inputs_[2] = index;
+    inputs_[3] = value;
+  }
+
+  LOperand* string() { return inputs_[1]; }
+  LOperand* index() { return inputs_[2]; }
+  LOperand* value() { return inputs_[3]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
+  DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
+};
+
+
+class LAddI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LAddI(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(AddI, "add-i")
+  DECLARE_HYDROGEN_ACCESSOR(Add)
+};
+
+
+class LMathMinMax FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LMathMinMax(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "math-min-max")
+  DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
+};
+
+
+class LPower FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LPower(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Power, "power")
+  DECLARE_HYDROGEN_ACCESSOR(Power)
+};
+
+
+class LArithmeticD FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LArithmeticD(Token::Value op, LOperand* left, LOperand* right) : op_(op) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  Token::Value op() const { return op_; }
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticD; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
+
+ private:
+  Token::Value op_;
+};
+
+
+class LArithmeticT FINAL : public LTemplateInstruction<1, 3, 0> {
+ public:
+  LArithmeticT(Token::Value op, LOperand* context, LOperand* left,
+               LOperand* right)
+      : op_(op) {
+    inputs_[0] = context;
+    inputs_[1] = left;
+    inputs_[2] = right;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* left() { return inputs_[1]; }
+  LOperand* right() { return inputs_[2]; }
+  Token::Value op() const { return op_; }
+
+  Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticT; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
+
+ private:
+  Token::Value op_;
+};
+
+
+class LReturn FINAL : public LTemplateInstruction<0, 3, 0> {
+ public:
+  LReturn(LOperand* value, LOperand* context, LOperand* parameter_count) {
+    inputs_[0] = value;
+    inputs_[1] = context;
+    inputs_[2] = parameter_count;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  bool has_constant_parameter_count() {
+    return parameter_count()->IsConstantOperand();
+  }
+  LConstantOperand* constant_parameter_count() {
+    DCHECK(has_constant_parameter_count());
+    return LConstantOperand::cast(parameter_count());
+  }
+  LOperand* parameter_count() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Return, "return")
+};
+
+
+class LLoadNamedField FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LLoadNamedField(LOperand* object) { inputs_[0] = object; }
+
+  LOperand* object() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field")
+  DECLARE_HYDROGEN_ACCESSOR(LoadNamedField)
+};
+
+
+class LLoadNamedGeneric FINAL : public LTemplateInstruction<1, 2, 1> {
+ public:
+  LLoadNamedGeneric(LOperand* context, LOperand* object, LOperand* vector) {
+    inputs_[0] = context;
+    inputs_[1] = object;
+    temps_[0] = vector;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* object() { return inputs_[1]; }
+  LOperand* temp_vector() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic")
+  DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric)
+
+  Handle<Object> name() const { return hydrogen()->name(); }
+};
+
+
+class LLoadFunctionPrototype FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LLoadFunctionPrototype(LOperand* function) { inputs_[0] = function; }
+
+  LOperand* function() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype")
+  DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype)
+};
+
+
+class LLoadRoot FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(LoadRoot, "load-root")
+  DECLARE_HYDROGEN_ACCESSOR(LoadRoot)
+
+  Heap::RootListIndex index() const { return hydrogen()->index(); }
+};
+
+
+class LLoadKeyed FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LLoadKeyed(LOperand* elements, LOperand* key) {
+    inputs_[0] = elements;
+    inputs_[1] = key;
+  }
+
+  LOperand* elements() { return inputs_[0]; }
+  LOperand* key() { return inputs_[1]; }
+  ElementsKind elements_kind() const { return hydrogen()->elements_kind(); }
+  bool is_external() const { return hydrogen()->is_external(); }
+  bool is_fixed_typed_array() const {
+    return hydrogen()->is_fixed_typed_array();
+  }
+  bool is_typed_elements() const {
+    return is_external() || is_fixed_typed_array();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
+  DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+  uint32_t base_offset() const { return hydrogen()->base_offset(); }
+};
+
+
+class LLoadKeyedGeneric FINAL : public LTemplateInstruction<1, 3, 1> {
+ public:
+  LLoadKeyedGeneric(LOperand* context, LOperand* object, LOperand* key,
+                    LOperand* vector) {
+    inputs_[0] = context;
+    inputs_[1] = object;
+    inputs_[2] = key;
+    temps_[0] = vector;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* object() { return inputs_[1]; }
+  LOperand* key() { return inputs_[2]; }
+  LOperand* temp_vector() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic")
+  DECLARE_HYDROGEN_ACCESSOR(LoadKeyedGeneric)
+};
+
+
+class LLoadGlobalCell FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell, "load-global-cell")
+  DECLARE_HYDROGEN_ACCESSOR(LoadGlobalCell)
+};
+
+
+class LLoadGlobalGeneric FINAL : public LTemplateInstruction<1, 2, 1> {
+ public:
+  LLoadGlobalGeneric(LOperand* context, LOperand* global_object,
+                     LOperand* vector) {
+    inputs_[0] = context;
+    inputs_[1] = global_object;
+    temps_[0] = vector;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* global_object() { return inputs_[1]; }
+  LOperand* temp_vector() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic")
+  DECLARE_HYDROGEN_ACCESSOR(LoadGlobalGeneric)
+
+  Handle<Object> name() const { return hydrogen()->name(); }
+  bool for_typeof() const { return hydrogen()->for_typeof(); }
+};
+
+
+class LStoreGlobalCell FINAL : public LTemplateInstruction<0, 1, 1> {
+ public:
+  LStoreGlobalCell(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell, "store-global-cell")
+  DECLARE_HYDROGEN_ACCESSOR(StoreGlobalCell)
+};
+
+
+class LLoadContextSlot FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LLoadContextSlot(LOperand* context) { inputs_[0] = context; }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load-context-slot")
+  DECLARE_HYDROGEN_ACCESSOR(LoadContextSlot)
+
+  int slot_index() { return hydrogen()->slot_index(); }
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LStoreContextSlot FINAL : public LTemplateInstruction<0, 2, 0> {
+ public:
+  LStoreContextSlot(LOperand* context, LOperand* value) {
+    inputs_[0] = context;
+    inputs_[1] = value;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* value() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot, "store-context-slot")
+  DECLARE_HYDROGEN_ACCESSOR(StoreContextSlot)
+
+  int slot_index() { return hydrogen()->slot_index(); }
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LPushArgument FINAL : public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LPushArgument(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push-argument")
+};
+
+
+class LDrop FINAL : public LTemplateInstruction<0, 0, 0> {
+ public:
+  explicit LDrop(int count) : count_(count) {}
+
+  int count() const { return count_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Drop, "drop")
+
+ private:
+  int count_;
+};
+
+
+class LStoreCodeEntry FINAL : public LTemplateInstruction<0, 2, 0> {
+ public:
+  LStoreCodeEntry(LOperand* function, LOperand* code_object) {
+    inputs_[0] = function;
+    inputs_[1] = code_object;
+  }
+
+  LOperand* function() { return inputs_[0]; }
+  LOperand* code_object() { return inputs_[1]; }
+
+  virtual void PrintDataTo(StringStream* stream);
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry, "store-code-entry")
+  DECLARE_HYDROGEN_ACCESSOR(StoreCodeEntry)
+};
+
+
+class LInnerAllocatedObject FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LInnerAllocatedObject(LOperand* base_object, LOperand* offset) {
+    inputs_[0] = base_object;
+    inputs_[1] = offset;
+  }
+
+  LOperand* base_object() const { return inputs_[0]; }
+  LOperand* offset() const { return inputs_[1]; }
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object")
+};
+
+
+class LThisFunction FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function")
+  DECLARE_HYDROGEN_ACCESSOR(ThisFunction)
+};
+
+
+class LContext FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(Context, "context")
+  DECLARE_HYDROGEN_ACCESSOR(Context)
+};
+
+
+class LDeclareGlobals FINAL : public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LDeclareGlobals(LOperand* context) { inputs_[0] = context; }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals, "declare-globals")
+  DECLARE_HYDROGEN_ACCESSOR(DeclareGlobals)
+};
+
+
+class LCallJSFunction FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LCallJSFunction(LOperand* function) { inputs_[0] = function; }
+
+  LOperand* function() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallJSFunction, "call-js-function")
+  DECLARE_HYDROGEN_ACCESSOR(CallJSFunction)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  int arity() const { return hydrogen()->argument_count() - 1; }
+};
+
+
+class LCallWithDescriptor FINAL : public LTemplateResultInstruction<1> {
+ public:
+  LCallWithDescriptor(CallInterfaceDescriptor descriptor,
+                      const ZoneList<LOperand*>& operands, Zone* zone)
+      : descriptor_(descriptor),
+        inputs_(descriptor.GetRegisterParameterCount() + 1, zone) {
+    DCHECK(descriptor.GetRegisterParameterCount() + 1 == operands.length());
+    inputs_.AddAll(operands, zone);
+  }
+
+  LOperand* target() const { return inputs_[0]; }
+
+  const CallInterfaceDescriptor descriptor() { return descriptor_; }
+
+ private:
+  DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
+  DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  int arity() const { return hydrogen()->argument_count() - 1; }
+
+  CallInterfaceDescriptor descriptor_;
+  ZoneList<LOperand*> inputs_;
+
+  // Iterator support.
+  int InputCount() FINAL { return inputs_.length(); }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
+
+  int TempCount() FINAL { return 0; }
+  LOperand* TempAt(int i) FINAL { return NULL; }
+};
+
+
+class LInvokeFunction FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LInvokeFunction(LOperand* context, LOperand* function) {
+    inputs_[0] = context;
+    inputs_[1] = function;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* function() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function")
+  DECLARE_HYDROGEN_ACCESSOR(InvokeFunction)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  int arity() const { return hydrogen()->argument_count() - 1; }
+};
+
+
+class LCallFunction FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LCallFunction(LOperand* context, LOperand* function) {
+    inputs_[0] = context;
+    inputs_[1] = function;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* function() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
+  DECLARE_HYDROGEN_ACCESSOR(CallFunction)
+
+  int arity() const { return hydrogen()->argument_count() - 1; }
+};
+
+
+class LCallNew FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LCallNew(LOperand* context, LOperand* constructor) {
+    inputs_[0] = context;
+    inputs_[1] = constructor;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* constructor() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
+  DECLARE_HYDROGEN_ACCESSOR(CallNew)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  int arity() const { return hydrogen()->argument_count() - 1; }
+};
+
+
+class LCallNewArray FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LCallNewArray(LOperand* context, LOperand* constructor) {
+    inputs_[0] = context;
+    inputs_[1] = constructor;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* constructor() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
+  DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  int arity() const { return hydrogen()->argument_count() - 1; }
+};
+
+
+class LCallRuntime FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LCallRuntime(LOperand* context) { inputs_[0] = context; }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
+  DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
+
+  bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
+    return save_doubles() == kDontSaveFPRegs;
+  }
+
+  const Runtime::Function* function() const { return hydrogen()->function(); }
+  int arity() const { return hydrogen()->argument_count(); }
+  SaveFPRegsMode save_doubles() const { return hydrogen()->save_doubles(); }
+};
+
+
+class LInteger32ToDouble FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LInteger32ToDouble(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Integer32ToDouble, "int32-to-double")
+};
+
+
+class LUint32ToDouble FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LUint32ToDouble(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Uint32ToDouble, "uint32-to-double")
+};
+
+
+class LNumberTagI FINAL : public LTemplateInstruction<1, 1, 2> {
+ public:
+  LNumberTagI(LOperand* value, LOperand* temp1, LOperand* temp2) {
+    inputs_[0] = value;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(NumberTagI, "number-tag-i")
+};
+
+
+class LNumberTagU FINAL : public LTemplateInstruction<1, 1, 2> {
+ public:
+  LNumberTagU(LOperand* value, LOperand* temp1, LOperand* temp2) {
+    inputs_[0] = value;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(NumberTagU, "number-tag-u")
+};
+
+
+class LNumberTagD FINAL : public LTemplateInstruction<1, 1, 2> {
+ public:
+  LNumberTagD(LOperand* value, LOperand* temp, LOperand* temp2) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+    temps_[1] = temp2;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d")
+  DECLARE_HYDROGEN_ACCESSOR(Change)
+};
+
+
+class LDoubleToSmi FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LDoubleToSmi(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DoubleToSmi, "double-to-smi")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
+
+  bool truncating() { return hydrogen()->CanTruncateToInt32(); }
+};
+
+
+// Sometimes truncating conversion from a tagged value to an int32.
+class LDoubleToI FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LDoubleToI(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DoubleToI, "double-to-i")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
+
+  bool truncating() { return hydrogen()->CanTruncateToInt32(); }
+};
+
+
+// Truncating conversion from a tagged value to an int32.
+class LTaggedToI FINAL : public LTemplateInstruction<1, 1, 2> {
+ public:
+  LTaggedToI(LOperand* value, LOperand* temp, LOperand* temp2) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+    temps_[1] = temp2;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i")
+  DECLARE_HYDROGEN_ACCESSOR(Change)
+
+  bool truncating() { return hydrogen()->CanTruncateToInt32(); }
+};
+
+
+class LSmiTag FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LSmiTag(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(SmiTag, "smi-tag")
+  DECLARE_HYDROGEN_ACCESSOR(Change)
+};
+
+
+class LNumberUntagD FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LNumberUntagD(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
+  DECLARE_HYDROGEN_ACCESSOR(Change)
+};
+
+
+class LSmiUntag FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  LSmiUntag(LOperand* value, bool needs_check) : needs_check_(needs_check) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  bool needs_check() const { return needs_check_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag")
+
+ private:
+  bool needs_check_;
+};
+
+
+class LStoreNamedField FINAL : public LTemplateInstruction<0, 2, 1> {
+ public:
+  LStoreNamedField(LOperand* object, LOperand* value, LOperand* temp) {
+    inputs_[0] = object;
+    inputs_[1] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* object() { return inputs_[0]; }
+  LOperand* value() { return inputs_[1]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
+  DECLARE_HYDROGEN_ACCESSOR(StoreNamedField)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  Representation representation() const {
+    return hydrogen()->field_representation();
+  }
+};
+
+
+class LStoreNamedGeneric FINAL : public LTemplateInstruction<0, 3, 0> {
+ public:
+  LStoreNamedGeneric(LOperand* context, LOperand* object, LOperand* value) {
+    inputs_[0] = context;
+    inputs_[1] = object;
+    inputs_[2] = value;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* object() { return inputs_[1]; }
+  LOperand* value() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
+  DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  Handle<Object> name() const { return hydrogen()->name(); }
+  StrictMode strict_mode() { return hydrogen()->strict_mode(); }
+};
+
+
+class LStoreKeyed FINAL : public LTemplateInstruction<0, 3, 0> {
+ public:
+  LStoreKeyed(LOperand* object, LOperand* key, LOperand* value) {
+    inputs_[0] = object;
+    inputs_[1] = key;
+    inputs_[2] = value;
+  }
+
+  bool is_external() const { return hydrogen()->is_external(); }
+  bool is_fixed_typed_array() const {
+    return hydrogen()->is_fixed_typed_array();
+  }
+  bool is_typed_elements() const {
+    return is_external() || is_fixed_typed_array();
+  }
+  LOperand* elements() { return inputs_[0]; }
+  LOperand* key() { return inputs_[1]; }
+  LOperand* value() { return inputs_[2]; }
+  ElementsKind elements_kind() const { return hydrogen()->elements_kind(); }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed")
+  DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool NeedsCanonicalization() {
+    if (hydrogen()->value()->IsAdd() || hydrogen()->value()->IsSub() ||
+        hydrogen()->value()->IsMul() || hydrogen()->value()->IsDiv()) {
+      return false;
+    }
+    return hydrogen()->NeedsCanonicalization();
+  }
+  uint32_t base_offset() const { return hydrogen()->base_offset(); }
+};
+
+
+class LStoreKeyedGeneric FINAL : public LTemplateInstruction<0, 4, 0> {
+ public:
+  LStoreKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key,
+                     LOperand* value) {
+    inputs_[0] = context;
+    inputs_[1] = obj;
+    inputs_[2] = key;
+    inputs_[3] = value;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* object() { return inputs_[1]; }
+  LOperand* key() { return inputs_[2]; }
+  LOperand* value() { return inputs_[3]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
+  DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  StrictMode strict_mode() { return hydrogen()->strict_mode(); }
+};
+
+
+class LTransitionElementsKind FINAL : public LTemplateInstruction<0, 2, 1> {
+ public:
+  LTransitionElementsKind(LOperand* object, LOperand* context,
+                          LOperand* new_map_temp) {
+    inputs_[0] = object;
+    inputs_[1] = context;
+    temps_[0] = new_map_temp;
+  }
+
+  LOperand* context() { return inputs_[1]; }
+  LOperand* object() { return inputs_[0]; }
+  LOperand* new_map_temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind,
+                               "transition-elements-kind")
+  DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind)
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  Handle<Map> original_map() { return hydrogen()->original_map().handle(); }
+  Handle<Map> transitioned_map() {
+    return hydrogen()->transitioned_map().handle();
+  }
+  ElementsKind from_kind() { return hydrogen()->from_kind(); }
+  ElementsKind to_kind() { return hydrogen()->to_kind(); }
+};
+
+
+class LTrapAllocationMemento FINAL : public LTemplateInstruction<0, 1, 1> {
+ public:
+  LTrapAllocationMemento(LOperand* object, LOperand* temp) {
+    inputs_[0] = object;
+    temps_[0] = temp;
+  }
+
+  LOperand* object() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento, "trap-allocation-memento")
+};
+
+
+class LStringAdd FINAL : public LTemplateInstruction<1, 3, 0> {
+ public:
+  LStringAdd(LOperand* context, LOperand* left, LOperand* right) {
+    inputs_[0] = context;
+    inputs_[1] = left;
+    inputs_[2] = right;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* left() { return inputs_[1]; }
+  LOperand* right() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add")
+  DECLARE_HYDROGEN_ACCESSOR(StringAdd)
+};
+
+
+class LStringCharCodeAt FINAL : public LTemplateInstruction<1, 3, 0> {
+ public:
+  LStringCharCodeAt(LOperand* context, LOperand* string, LOperand* index) {
+    inputs_[0] = context;
+    inputs_[1] = string;
+    inputs_[2] = index;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* string() { return inputs_[1]; }
+  LOperand* index() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at")
+  DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt)
+};
+
+
+class LStringCharFromCode FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  explicit LStringCharFromCode(LOperand* context, LOperand* char_code) {
+    inputs_[0] = context;
+    inputs_[1] = char_code;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* char_code() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code")
+  DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode)
+};
+
+
+class LCheckValue FINAL : public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LCheckValue(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckValue, "check-value")
+  DECLARE_HYDROGEN_ACCESSOR(CheckValue)
+};
+
+
+class LCheckInstanceType FINAL : public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LCheckInstanceType(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check-instance-type")
+  DECLARE_HYDROGEN_ACCESSOR(CheckInstanceType)
+};
+
+
+class LCheckMaps FINAL : public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LCheckMaps(LOperand* value = NULL) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps")
+  DECLARE_HYDROGEN_ACCESSOR(CheckMaps)
+};
+
+
+class LCheckSmi FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LCheckSmi(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckSmi, "check-smi")
+};
+
+
+class LCheckNonSmi FINAL : public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LCheckNonSmi(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
+  DECLARE_HYDROGEN_ACCESSOR(CheckHeapObject)
+};
+
+
+class LClampDToUint8 FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LClampDToUint8(LOperand* unclamped) { inputs_[0] = unclamped; }
+
+  LOperand* unclamped() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ClampDToUint8, "clamp-d-to-uint8")
+};
+
+
+class LClampIToUint8 FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LClampIToUint8(LOperand* unclamped) { inputs_[0] = unclamped; }
+
+  LOperand* unclamped() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ClampIToUint8, "clamp-i-to-uint8")
+};
+
+
+class LClampTToUint8 FINAL : public LTemplateInstruction<1, 1, 1> {
+ public:
+  LClampTToUint8(LOperand* unclamped, LOperand* temp) {
+    inputs_[0] = unclamped;
+    temps_[0] = temp;
+  }
+
+  LOperand* unclamped() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ClampTToUint8, "clamp-t-to-uint8")
+};
+
+
+class LDoubleBits FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LDoubleBits(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DoubleBits, "double-bits")
+  DECLARE_HYDROGEN_ACCESSOR(DoubleBits)
+};
+
+
+class LConstructDouble FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LConstructDouble(LOperand* hi, LOperand* lo) {
+    inputs_[0] = hi;
+    inputs_[1] = lo;
+  }
+
+  LOperand* hi() { return inputs_[0]; }
+  LOperand* lo() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ConstructDouble, "construct-double")
+};
+
+
+class LAllocate FINAL : public LTemplateInstruction<1, 2, 2> {
+ public:
+  LAllocate(LOperand* context, LOperand* size, LOperand* temp1,
+            LOperand* temp2) {
+    inputs_[0] = context;
+    inputs_[1] = size;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* size() { return inputs_[1]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Allocate, "allocate")
+  DECLARE_HYDROGEN_ACCESSOR(Allocate)
+};
+
+
+class LRegExpLiteral FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LRegExpLiteral(LOperand* context) { inputs_[0] = context; }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral, "regexp-literal")
+  DECLARE_HYDROGEN_ACCESSOR(RegExpLiteral)
+};
+
+
+class LFunctionLiteral FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LFunctionLiteral(LOperand* context) { inputs_[0] = context; }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral, "function-literal")
+  DECLARE_HYDROGEN_ACCESSOR(FunctionLiteral)
+};
+
+
+class LToFastProperties FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LToFastProperties(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties")
+  DECLARE_HYDROGEN_ACCESSOR(ToFastProperties)
+};
+
+
+class LTypeof FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LTypeof(LOperand* context, LOperand* value) {
+    inputs_[0] = context;
+    inputs_[1] = value;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* value() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof")
+};
+
+
+class LTypeofIsAndBranch FINAL : public LControlInstruction<1, 0> {
+ public:
+  explicit LTypeofIsAndBranch(LOperand* value) { inputs_[0] = value; }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(TypeofIsAndBranch)
+
+  Handle<String> type_literal() { return hydrogen()->type_literal(); }
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LIsConstructCallAndBranch FINAL : public LControlInstruction<0, 1> {
+ public:
+  explicit LIsConstructCallAndBranch(LOperand* temp) { temps_[0] = temp; }
+
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch,
+                               "is-construct-call-and-branch")
+};
+
+
+class LOsrEntry FINAL : public LTemplateInstruction<0, 0, 0> {
+ public:
+  LOsrEntry() {}
+
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
+  DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry")
+};
+
+
+class LStackCheck FINAL : public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LStackCheck(LOperand* context) { inputs_[0] = context; }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StackCheck, "stack-check")
+  DECLARE_HYDROGEN_ACCESSOR(StackCheck)
+
+  Label* done_label() { return &done_label_; }
+
+ private:
+  Label done_label_;
+};
+
+
+class LForInPrepareMap FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LForInPrepareMap(LOperand* context, LOperand* object) {
+    inputs_[0] = context;
+    inputs_[1] = object;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* object() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap, "for-in-prepare-map")
+};
+
+
+class LForInCacheArray FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LForInCacheArray(LOperand* map) { inputs_[0] = map; }
+
+  LOperand* map() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray, "for-in-cache-array")
+
+  int idx() { return HForInCacheArray::cast(this->hydrogen_value())->idx(); }
+};
+
+
+class LCheckMapValue FINAL : public LTemplateInstruction<0, 2, 0> {
+ public:
+  LCheckMapValue(LOperand* value, LOperand* map) {
+    inputs_[0] = value;
+    inputs_[1] = map;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* map() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckMapValue, "check-map-value")
+};
+
+
+class LLoadFieldByIndex FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LLoadFieldByIndex(LOperand* object, LOperand* index) {
+    inputs_[0] = object;
+    inputs_[1] = index;
+  }
+
+  LOperand* object() { return inputs_[0]; }
+  LOperand* index() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex, "load-field-by-index")
+};
+
+
+class LStoreFrameContext : public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LStoreFrameContext(LOperand* context) { inputs_[0] = context; }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext, "store-frame-context")
+};
+
+
+class LAllocateBlockContext : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LAllocateBlockContext(LOperand* context, LOperand* function) {
+    inputs_[0] = context;
+    inputs_[1] = function;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* function() { return inputs_[1]; }
+
+  Handle<ScopeInfo> scope_info() { return hydrogen()->scope_info(); }
+
+  DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext, "allocate-block-context")
+  DECLARE_HYDROGEN_ACCESSOR(AllocateBlockContext)
+};
+
+
+class LChunkBuilder;
+class LPlatformChunk FINAL : public LChunk {
+ public:
+  LPlatformChunk(CompilationInfo* info, HGraph* graph) : LChunk(info, graph) {}
+
+  int GetNextSpillIndex(RegisterKind kind);
+  LOperand* GetNextSpillSlot(RegisterKind kind);
+};
+
+
+class LChunkBuilder FINAL : public LChunkBuilderBase {
+ public:
+  LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator)
+      : LChunkBuilderBase(info, graph),
+        current_instruction_(NULL),
+        current_block_(NULL),
+        next_block_(NULL),
+        allocator_(allocator) {}
+
+  // Build the sequence for the graph.
+  LPlatformChunk* Build();
+
+// Declare methods that deal with the individual node types.
+#define DECLARE_DO(type) LInstruction* Do##type(H##type* node);
+  HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
+#undef DECLARE_DO
+
+  LInstruction* DoMultiplyAdd(HMul* mul, HValue* addend);
+  LInstruction* DoMultiplySub(HValue* minuend, HMul* mul);
+  LInstruction* DoRSub(HSub* instr);
+
+  static bool HasMagicNumberForDivisor(int32_t divisor);
+
+  LInstruction* DoMathFloor(HUnaryMathOperation* instr);
+  LInstruction* DoMathRound(HUnaryMathOperation* instr);
+  LInstruction* DoMathFround(HUnaryMathOperation* instr);
+  LInstruction* DoMathAbs(HUnaryMathOperation* instr);
+  LInstruction* DoMathLog(HUnaryMathOperation* instr);
+  LInstruction* DoMathExp(HUnaryMathOperation* instr);
+  LInstruction* DoMathSqrt(HUnaryMathOperation* instr);
+  LInstruction* DoMathPowHalf(HUnaryMathOperation* instr);
+  LInstruction* DoMathClz32(HUnaryMathOperation* instr);
+  LInstruction* DoDivByPowerOf2I(HDiv* instr);
+  LInstruction* DoDivByConstI(HDiv* instr);
+  LInstruction* DoDivI(HDiv* instr);
+  LInstruction* DoModByPowerOf2I(HMod* instr);
+  LInstruction* DoModByConstI(HMod* instr);
+  LInstruction* DoModI(HMod* instr);
+  LInstruction* DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr);
+  LInstruction* DoFlooringDivByConstI(HMathFloorOfDiv* instr);
+  LInstruction* DoFlooringDivI(HMathFloorOfDiv* instr);
+
+ private:
+  // Methods for getting operands for Use / Define / Temp.
+  LUnallocated* ToUnallocated(Register reg);
+  LUnallocated* ToUnallocated(DoubleRegister reg);
+
+  // Methods for setting up define-use relationships.
+  MUST_USE_RESULT LOperand* Use(HValue* value, LUnallocated* operand);
+  MUST_USE_RESULT LOperand* UseFixed(HValue* value, Register fixed_register);
+  MUST_USE_RESULT LOperand* UseFixedDouble(HValue* value,
+                                           DoubleRegister fixed_register);
+
+  // A value that is guaranteed to be allocated to a register.
+  // Operand created by UseRegister is guaranteed to be live until the end of
+  // instruction. This means that register allocator will not reuse it's
+  // register for any other operand inside instruction.
+  // Operand created by UseRegisterAtStart is guaranteed to be live only at
+  // instruction start. Register allocator is free to assign the same register
+  // to some other operand used inside instruction (i.e. temporary or
+  // output).
+  MUST_USE_RESULT LOperand* UseRegister(HValue* value);
+  MUST_USE_RESULT LOperand* UseRegisterAtStart(HValue* value);
+
+  // An input operand in a register that may be trashed.
+  MUST_USE_RESULT LOperand* UseTempRegister(HValue* value);
+
+  // An input operand in a register or stack slot.
+  MUST_USE_RESULT LOperand* Use(HValue* value);
+  MUST_USE_RESULT LOperand* UseAtStart(HValue* value);
+
+  // An input operand in a register, stack slot or a constant operand.
+  MUST_USE_RESULT LOperand* UseOrConstant(HValue* value);
+  MUST_USE_RESULT LOperand* UseOrConstantAtStart(HValue* value);
+
+  // An input operand in a register or a constant operand.
+  MUST_USE_RESULT LOperand* UseRegisterOrConstant(HValue* value);
+  MUST_USE_RESULT LOperand* UseRegisterOrConstantAtStart(HValue* value);
+
+  // An input operand in a constant operand.
+  MUST_USE_RESULT LOperand* UseConstant(HValue* value);
+
+  // An input operand in register, stack slot or a constant operand.
+  // Will not be moved to a register even if one is freely available.
+  MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE;
+
+  // Temporary operand that must be in a register.
+  MUST_USE_RESULT LUnallocated* TempRegister();
+  MUST_USE_RESULT LUnallocated* TempDoubleRegister();
+  MUST_USE_RESULT LOperand* FixedTemp(Register reg);
+  MUST_USE_RESULT LOperand* FixedTemp(DoubleRegister reg);
+
+  // Methods for setting up define-use relationships.
+  // Return the same instruction that they are passed.
+  LInstruction* Define(LTemplateResultInstruction<1>* instr,
+                       LUnallocated* result);
+  LInstruction* DefineAsRegister(LTemplateResultInstruction<1>* instr);
+  LInstruction* DefineAsSpilled(LTemplateResultInstruction<1>* instr,
+                                int index);
+  LInstruction* DefineSameAsFirst(LTemplateResultInstruction<1>* instr);
+  LInstruction* DefineFixed(LTemplateResultInstruction<1>* instr, Register reg);
+  LInstruction* DefineFixedDouble(LTemplateResultInstruction<1>* instr,
+                                  DoubleRegister reg);
+  LInstruction* AssignEnvironment(LInstruction* instr);
+  LInstruction* AssignPointerMap(LInstruction* instr);
+
+  enum CanDeoptimize { CAN_DEOPTIMIZE_EAGERLY, CANNOT_DEOPTIMIZE_EAGERLY };
+
+  // By default we assume that instruction sequences generated for calls
+  // cannot deoptimize eagerly and we do not attach environment to this
+  // instruction.
+  LInstruction* MarkAsCall(
+      LInstruction* instr, HInstruction* hinstr,
+      CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
+
+  void VisitInstruction(HInstruction* current);
+  void AddInstruction(LInstruction* instr, HInstruction* current);
+
+  void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
+  LInstruction* DoShift(Token::Value op, HBitwiseBinaryOperation* instr);
+  LInstruction* DoArithmeticD(Token::Value op,
+                              HArithmeticBinaryOperation* instr);
+  LInstruction* DoArithmeticT(Token::Value op, HBinaryOperation* instr);
+
+  HInstruction* current_instruction_;
+  HBasicBlock* current_block_;
+  HBasicBlock* next_block_;
+  LAllocator* allocator_;
+
+  DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
+};
+
+#undef DECLARE_HYDROGEN_ACCESSOR
+#undef DECLARE_CONCRETE_INSTRUCTION
+}
+}  // namespace v8::internal
+
+#endif  // V8_PPC_LITHIUM_PPC_H_
diff --git a/src/ppc/macro-assembler-ppc.cc b/src/ppc/macro-assembler-ppc.cc
new file mode 100644
index 0000000..0b3d729
--- /dev/null
+++ b/src/ppc/macro-assembler-ppc.cc
@@ -0,0 +1,4819 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <assert.h>  // For assert
+#include <limits.h>  // For LONG_MIN, LONG_MAX.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/base/bits.h"
+#include "src/base/division-by-constant.h"
+#include "src/bootstrapper.h"
+#include "src/codegen.h"
+#include "src/cpu-profiler.h"
+#include "src/debug.h"
+#include "src/isolate-inl.h"
+#include "src/runtime/runtime.h"
+
+namespace v8 {
+namespace internal {
+
+MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size)
+    : Assembler(arg_isolate, buffer, size),
+      generating_stub_(false),
+      has_frame_(false) {
+  if (isolate() != NULL) {
+    code_object_ =
+        Handle<Object>(isolate()->heap()->undefined_value(), isolate());
+  }
+}
+
+
+void MacroAssembler::Jump(Register target) {
+  mtctr(target);
+  bctr();
+}
+
+
+void MacroAssembler::JumpToJSEntry(Register target) {
+  Move(ip, target);
+  Jump(ip);
+}
+
+
+void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
+                          Condition cond, CRegister cr) {
+  Label skip;
+
+  if (cond != al) b(NegateCondition(cond), &skip, cr);
+
+  DCHECK(rmode == RelocInfo::CODE_TARGET || rmode == RelocInfo::RUNTIME_ENTRY);
+
+  mov(ip, Operand(target, rmode));
+  mtctr(ip);
+  bctr();
+
+  bind(&skip);
+}
+
+
+void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode, Condition cond,
+                          CRegister cr) {
+  DCHECK(!RelocInfo::IsCodeTarget(rmode));
+  Jump(reinterpret_cast<intptr_t>(target), rmode, cond, cr);
+}
+
+
+void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
+                          Condition cond) {
+  DCHECK(RelocInfo::IsCodeTarget(rmode));
+  // 'code' is always generated ppc code, never THUMB code
+  AllowDeferredHandleDereference embedding_raw_address;
+  Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond);
+}
+
+
+int MacroAssembler::CallSize(Register target) { return 2 * kInstrSize; }
+
+
+void MacroAssembler::Call(Register target) {
+  BlockTrampolinePoolScope block_trampoline_pool(this);
+  Label start;
+  bind(&start);
+
+  // Statement positions are expected to be recorded when the target
+  // address is loaded.
+  positions_recorder()->WriteRecordedPositions();
+
+  // branch via link register and set LK bit for return point
+  mtctr(target);
+  bctrl();
+
+  DCHECK_EQ(CallSize(target), SizeOfCodeGeneratedSince(&start));
+}
+
+
+void MacroAssembler::CallJSEntry(Register target) {
+  DCHECK(target.is(ip));
+  Call(target);
+}
+
+
+int MacroAssembler::CallSize(Address target, RelocInfo::Mode rmode,
+                             Condition cond) {
+  Operand mov_operand = Operand(reinterpret_cast<intptr_t>(target), rmode);
+  return (2 + instructions_required_for_mov(mov_operand)) * kInstrSize;
+}
+
+
+int MacroAssembler::CallSizeNotPredictableCodeSize(Address target,
+                                                   RelocInfo::Mode rmode,
+                                                   Condition cond) {
+  return (2 + kMovInstructionsNoConstantPool) * kInstrSize;
+}
+
+
+void MacroAssembler::Call(Address target, RelocInfo::Mode rmode,
+                          Condition cond) {
+  BlockTrampolinePoolScope block_trampoline_pool(this);
+  DCHECK(cond == al);
+
+#ifdef DEBUG
+  // Check the expected size before generating code to ensure we assume the same
+  // constant pool availability (e.g., whether constant pool is full or not).
+  int expected_size = CallSize(target, rmode, cond);
+  Label start;
+  bind(&start);
+#endif
+
+  // Statement positions are expected to be recorded when the target
+  // address is loaded.
+  positions_recorder()->WriteRecordedPositions();
+
+  // This can likely be optimized to make use of bc() with 24bit relative
+  //
+  // RecordRelocInfo(x.rmode_, x.imm_);
+  // bc( BA, .... offset, LKset);
+  //
+
+  mov(ip, Operand(reinterpret_cast<intptr_t>(target), rmode));
+  mtctr(ip);
+  bctrl();
+
+  DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start));
+}
+
+
+int MacroAssembler::CallSize(Handle<Code> code, RelocInfo::Mode rmode,
+                             TypeFeedbackId ast_id, Condition cond) {
+  AllowDeferredHandleDereference using_raw_address;
+  return CallSize(reinterpret_cast<Address>(code.location()), rmode, cond);
+}
+
+
+void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
+                          TypeFeedbackId ast_id, Condition cond) {
+  BlockTrampolinePoolScope block_trampoline_pool(this);
+  DCHECK(RelocInfo::IsCodeTarget(rmode));
+
+#ifdef DEBUG
+  // Check the expected size before generating code to ensure we assume the same
+  // constant pool availability (e.g., whether constant pool is full or not).
+  int expected_size = CallSize(code, rmode, ast_id, cond);
+  Label start;
+  bind(&start);
+#endif
+
+  if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) {
+    SetRecordedAstId(ast_id);
+    rmode = RelocInfo::CODE_TARGET_WITH_ID;
+  }
+  AllowDeferredHandleDereference using_raw_address;
+  Call(reinterpret_cast<Address>(code.location()), rmode, cond);
+  DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start));
+}
+
+
+void MacroAssembler::Ret(Condition cond) {
+  DCHECK(cond == al);
+  blr();
+}
+
+
+void MacroAssembler::Drop(int count, Condition cond) {
+  DCHECK(cond == al);
+  if (count > 0) {
+    Add(sp, sp, count * kPointerSize, r0);
+  }
+}
+
+
+void MacroAssembler::Ret(int drop, Condition cond) {
+  Drop(drop, cond);
+  Ret(cond);
+}
+
+
+void MacroAssembler::Call(Label* target) { b(target, SetLK); }
+
+
+void MacroAssembler::Push(Handle<Object> handle) {
+  mov(r0, Operand(handle));
+  push(r0);
+}
+
+
+void MacroAssembler::Move(Register dst, Handle<Object> value) {
+  AllowDeferredHandleDereference smi_check;
+  if (value->IsSmi()) {
+    LoadSmiLiteral(dst, reinterpret_cast<Smi*>(*value));
+  } else {
+    DCHECK(value->IsHeapObject());
+    if (isolate()->heap()->InNewSpace(*value)) {
+      Handle<Cell> cell = isolate()->factory()->NewCell(value);
+      mov(dst, Operand(cell));
+      LoadP(dst, FieldMemOperand(dst, Cell::kValueOffset));
+    } else {
+      mov(dst, Operand(value));
+    }
+  }
+}
+
+
+void MacroAssembler::Move(Register dst, Register src, Condition cond) {
+  DCHECK(cond == al);
+  if (!dst.is(src)) {
+    mr(dst, src);
+  }
+}
+
+
+void MacroAssembler::Move(DoubleRegister dst, DoubleRegister src) {
+  if (!dst.is(src)) {
+    fmr(dst, src);
+  }
+}
+
+
+void MacroAssembler::MultiPush(RegList regs) {
+  int16_t num_to_push = NumberOfBitsSet(regs);
+  int16_t stack_offset = num_to_push * kPointerSize;
+
+  subi(sp, sp, Operand(stack_offset));
+  for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
+    if ((regs & (1 << i)) != 0) {
+      stack_offset -= kPointerSize;
+      StoreP(ToRegister(i), MemOperand(sp, stack_offset));
+    }
+  }
+}
+
+
+void MacroAssembler::MultiPop(RegList regs) {
+  int16_t stack_offset = 0;
+
+  for (int16_t i = 0; i < kNumRegisters; i++) {
+    if ((regs & (1 << i)) != 0) {
+      LoadP(ToRegister(i), MemOperand(sp, stack_offset));
+      stack_offset += kPointerSize;
+    }
+  }
+  addi(sp, sp, Operand(stack_offset));
+}
+
+
+void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index,
+                              Condition cond) {
+  DCHECK(cond == al);
+  LoadP(destination, MemOperand(kRootRegister, index << kPointerSizeLog2), r0);
+}
+
+
+void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index,
+                               Condition cond) {
+  DCHECK(cond == al);
+  StoreP(source, MemOperand(kRootRegister, index << kPointerSizeLog2), r0);
+}
+
+
+void MacroAssembler::InNewSpace(Register object, Register scratch,
+                                Condition cond, Label* branch) {
+  // N.B. scratch may be same register as object
+  DCHECK(cond == eq || cond == ne);
+  mov(r0, Operand(ExternalReference::new_space_mask(isolate())));
+  and_(scratch, object, r0);
+  mov(r0, Operand(ExternalReference::new_space_start(isolate())));
+  cmp(scratch, r0);
+  b(cond, branch);
+}
+
+
+void MacroAssembler::RecordWriteField(
+    Register object, int offset, Register value, Register dst,
+    LinkRegisterStatus lr_status, SaveFPRegsMode save_fp,
+    RememberedSetAction remembered_set_action, SmiCheck smi_check,
+    PointersToHereCheck pointers_to_here_check_for_value) {
+  // First, check if a write barrier is even needed. The tests below
+  // catch stores of Smis.
+  Label done;
+
+  // Skip barrier if writing a smi.
+  if (smi_check == INLINE_SMI_CHECK) {
+    JumpIfSmi(value, &done);
+  }
+
+  // Although the object register is tagged, the offset is relative to the start
+  // of the object, so so offset must be a multiple of kPointerSize.
+  DCHECK(IsAligned(offset, kPointerSize));
+
+  Add(dst, object, offset - kHeapObjectTag, r0);
+  if (emit_debug_code()) {
+    Label ok;
+    andi(r0, dst, Operand((1 << kPointerSizeLog2) - 1));
+    beq(&ok, cr0);
+    stop("Unaligned cell in write barrier");
+    bind(&ok);
+  }
+
+  RecordWrite(object, dst, value, lr_status, save_fp, remembered_set_action,
+              OMIT_SMI_CHECK, pointers_to_here_check_for_value);
+
+  bind(&done);
+
+  // Clobber clobbered input registers when running with the debug-code flag
+  // turned on to provoke errors.
+  if (emit_debug_code()) {
+    mov(value, Operand(bit_cast<intptr_t>(kZapValue + 4)));
+    mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 8)));
+  }
+}
+
+
+// Will clobber 4 registers: object, map, dst, ip.  The
+// register 'object' contains a heap object pointer.
+void MacroAssembler::RecordWriteForMap(Register object, Register map,
+                                       Register dst,
+                                       LinkRegisterStatus lr_status,
+                                       SaveFPRegsMode fp_mode) {
+  if (emit_debug_code()) {
+    LoadP(dst, FieldMemOperand(map, HeapObject::kMapOffset));
+    Cmpi(dst, Operand(isolate()->factory()->meta_map()), r0);
+    Check(eq, kWrongAddressOrValuePassedToRecordWrite);
+  }
+
+  if (!FLAG_incremental_marking) {
+    return;
+  }
+
+  if (emit_debug_code()) {
+    LoadP(ip, FieldMemOperand(object, HeapObject::kMapOffset));
+    cmp(ip, map);
+    Check(eq, kWrongAddressOrValuePassedToRecordWrite);
+  }
+
+  Label done;
+
+  // A single check of the map's pages interesting flag suffices, since it is
+  // only set during incremental collection, and then it's also guaranteed that
+  // the from object's page's interesting flag is also set.  This optimization
+  // relies on the fact that maps can never be in new space.
+  CheckPageFlag(map,
+                map,  // Used as scratch.
+                MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
+
+  addi(dst, object, Operand(HeapObject::kMapOffset - kHeapObjectTag));
+  if (emit_debug_code()) {
+    Label ok;
+    andi(r0, dst, Operand((1 << kPointerSizeLog2) - 1));
+    beq(&ok, cr0);
+    stop("Unaligned cell in write barrier");
+    bind(&ok);
+  }
+
+  // Record the actual write.
+  if (lr_status == kLRHasNotBeenSaved) {
+    mflr(r0);
+    push(r0);
+  }
+  RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET,
+                       fp_mode);
+  CallStub(&stub);
+  if (lr_status == kLRHasNotBeenSaved) {
+    pop(r0);
+    mtlr(r0);
+  }
+
+  bind(&done);
+
+  // Count number of write barriers in generated code.
+  isolate()->counters()->write_barriers_static()->Increment();
+  IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip, dst);
+
+  // Clobber clobbered registers when running with the debug-code flag
+  // turned on to provoke errors.
+  if (emit_debug_code()) {
+    mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 12)));
+    mov(map, Operand(bit_cast<intptr_t>(kZapValue + 16)));
+  }
+}
+
+
+// Will clobber 4 registers: object, address, scratch, ip.  The
+// register 'object' contains a heap object pointer.  The heap object
+// tag is shifted away.
+void MacroAssembler::RecordWrite(
+    Register object, Register address, Register value,
+    LinkRegisterStatus lr_status, SaveFPRegsMode fp_mode,
+    RememberedSetAction remembered_set_action, SmiCheck smi_check,
+    PointersToHereCheck pointers_to_here_check_for_value) {
+  DCHECK(!object.is(value));
+  if (emit_debug_code()) {
+    LoadP(r0, MemOperand(address));
+    cmp(r0, value);
+    Check(eq, kWrongAddressOrValuePassedToRecordWrite);
+  }
+
+  if (remembered_set_action == OMIT_REMEMBERED_SET &&
+      !FLAG_incremental_marking) {
+    return;
+  }
+
+  // First, check if a write barrier is even needed. The tests below
+  // catch stores of smis and stores into the young generation.
+  Label done;
+
+  if (smi_check == INLINE_SMI_CHECK) {
+    JumpIfSmi(value, &done);
+  }
+
+  if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) {
+    CheckPageFlag(value,
+                  value,  // Used as scratch.
+                  MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
+  }
+  CheckPageFlag(object,
+                value,  // Used as scratch.
+                MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done);
+
+  // Record the actual write.
+  if (lr_status == kLRHasNotBeenSaved) {
+    mflr(r0);
+    push(r0);
+  }
+  RecordWriteStub stub(isolate(), object, value, address, remembered_set_action,
+                       fp_mode);
+  CallStub(&stub);
+  if (lr_status == kLRHasNotBeenSaved) {
+    pop(r0);
+    mtlr(r0);
+  }
+
+  bind(&done);
+
+  // Count number of write barriers in generated code.
+  isolate()->counters()->write_barriers_static()->Increment();
+  IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip,
+                   value);
+
+  // Clobber clobbered registers when running with the debug-code flag
+  // turned on to provoke errors.
+  if (emit_debug_code()) {
+    mov(address, Operand(bit_cast<intptr_t>(kZapValue + 12)));
+    mov(value, Operand(bit_cast<intptr_t>(kZapValue + 16)));
+  }
+}
+
+
+void MacroAssembler::RememberedSetHelper(Register object,  // For debug tests.
+                                         Register address, Register scratch,
+                                         SaveFPRegsMode fp_mode,
+                                         RememberedSetFinalAction and_then) {
+  Label done;
+  if (emit_debug_code()) {
+    Label ok;
+    JumpIfNotInNewSpace(object, scratch, &ok);
+    stop("Remembered set pointer is in new space");
+    bind(&ok);
+  }
+  // Load store buffer top.
+  ExternalReference store_buffer =
+      ExternalReference::store_buffer_top(isolate());
+  mov(ip, Operand(store_buffer));
+  LoadP(scratch, MemOperand(ip));
+  // Store pointer to buffer and increment buffer top.
+  StoreP(address, MemOperand(scratch));
+  addi(scratch, scratch, Operand(kPointerSize));
+  // Write back new top of buffer.
+  StoreP(scratch, MemOperand(ip));
+  // Call stub on end of buffer.
+  // Check for end of buffer.
+  mov(r0, Operand(StoreBuffer::kStoreBufferOverflowBit));
+  and_(r0, scratch, r0, SetRC);
+
+  if (and_then == kFallThroughAtEnd) {
+    beq(&done, cr0);
+  } else {
+    DCHECK(and_then == kReturnAtEnd);
+    beq(&done, cr0);
+  }
+  mflr(r0);
+  push(r0);
+  StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode);
+  CallStub(&store_buffer_overflow);
+  pop(r0);
+  mtlr(r0);
+  bind(&done);
+  if (and_then == kReturnAtEnd) {
+    Ret();
+  }
+}
+
+
+void MacroAssembler::PushFixedFrame(Register marker_reg) {
+  mflr(r0);
+#if V8_OOL_CONSTANT_POOL
+  if (marker_reg.is_valid()) {
+    Push(r0, fp, kConstantPoolRegister, cp, marker_reg);
+  } else {
+    Push(r0, fp, kConstantPoolRegister, cp);
+  }
+#else
+  if (marker_reg.is_valid()) {
+    Push(r0, fp, cp, marker_reg);
+  } else {
+    Push(r0, fp, cp);
+  }
+#endif
+}
+
+
+void MacroAssembler::PopFixedFrame(Register marker_reg) {
+#if V8_OOL_CONSTANT_POOL
+  if (marker_reg.is_valid()) {
+    Pop(r0, fp, kConstantPoolRegister, cp, marker_reg);
+  } else {
+    Pop(r0, fp, kConstantPoolRegister, cp);
+  }
+#else
+  if (marker_reg.is_valid()) {
+    Pop(r0, fp, cp, marker_reg);
+  } else {
+    Pop(r0, fp, cp);
+  }
+#endif
+  mtlr(r0);
+}
+
+
+// Push and pop all registers that can hold pointers.
+void MacroAssembler::PushSafepointRegisters() {
+  // Safepoints expect a block of kNumSafepointRegisters values on the
+  // stack, so adjust the stack for unsaved registers.
+  const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
+  DCHECK(num_unsaved >= 0);
+  if (num_unsaved > 0) {
+    subi(sp, sp, Operand(num_unsaved * kPointerSize));
+  }
+  MultiPush(kSafepointSavedRegisters);
+}
+
+
+void MacroAssembler::PopSafepointRegisters() {
+  const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
+  MultiPop(kSafepointSavedRegisters);
+  if (num_unsaved > 0) {
+    addi(sp, sp, Operand(num_unsaved * kPointerSize));
+  }
+}
+
+
+void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) {
+  StoreP(src, SafepointRegisterSlot(dst));
+}
+
+
+void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
+  LoadP(dst, SafepointRegisterSlot(src));
+}
+
+
+int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
+  // The registers are pushed starting with the highest encoding,
+  // which means that lowest encodings are closest to the stack pointer.
+  RegList regs = kSafepointSavedRegisters;
+  int index = 0;
+
+  DCHECK(reg_code >= 0 && reg_code < kNumRegisters);
+
+  for (int16_t i = 0; i < reg_code; i++) {
+    if ((regs & (1 << i)) != 0) {
+      index++;
+    }
+  }
+
+  return index;
+}
+
+
+MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
+  return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
+}
+
+
+MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
+  // General purpose registers are pushed last on the stack.
+  int doubles_size = DoubleRegister::NumAllocatableRegisters() * kDoubleSize;
+  int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
+  return MemOperand(sp, doubles_size + register_offset);
+}
+
+
+void MacroAssembler::CanonicalizeNaN(const DoubleRegister dst,
+                                     const DoubleRegister src) {
+  Label done;
+
+  // Test for NaN
+  fcmpu(src, src);
+
+  if (dst.is(src)) {
+    bordered(&done);
+  } else {
+    Label is_nan;
+    bunordered(&is_nan);
+    fmr(dst, src);
+    b(&done);
+    bind(&is_nan);
+  }
+
+  // Replace with canonical NaN.
+  double nan_value = FixedDoubleArray::canonical_not_the_hole_nan_as_double();
+  LoadDoubleLiteral(dst, nan_value, r0);
+
+  bind(&done);
+}
+
+
+void MacroAssembler::ConvertIntToDouble(Register src,
+                                        DoubleRegister double_dst) {
+  MovIntToDouble(double_dst, src, r0);
+  fcfid(double_dst, double_dst);
+}
+
+
+void MacroAssembler::ConvertUnsignedIntToDouble(Register src,
+                                                DoubleRegister double_dst) {
+  MovUnsignedIntToDouble(double_dst, src, r0);
+  fcfid(double_dst, double_dst);
+}
+
+
+void MacroAssembler::ConvertIntToFloat(const DoubleRegister dst,
+                                       const Register src,
+                                       const Register int_scratch) {
+  MovIntToDouble(dst, src, int_scratch);
+  fcfid(dst, dst);
+  frsp(dst, dst);
+}
+
+
+void MacroAssembler::ConvertDoubleToInt64(const DoubleRegister double_input,
+#if !V8_TARGET_ARCH_PPC64
+                                          const Register dst_hi,
+#endif
+                                          const Register dst,
+                                          const DoubleRegister double_dst,
+                                          FPRoundingMode rounding_mode) {
+  if (rounding_mode == kRoundToZero) {
+    fctidz(double_dst, double_input);
+  } else {
+    SetRoundingMode(rounding_mode);
+    fctid(double_dst, double_input);
+    ResetRoundingMode();
+  }
+
+  MovDoubleToInt64(
+#if !V8_TARGET_ARCH_PPC64
+      dst_hi,
+#endif
+      dst, double_dst);
+}
+
+
+#if V8_OOL_CONSTANT_POOL
+void MacroAssembler::LoadConstantPoolPointerRegister(
+    CodeObjectAccessMethod access_method, int ip_code_entry_delta) {
+  Register base;
+  int constant_pool_offset = Code::kConstantPoolOffset - Code::kHeaderSize;
+  if (access_method == CAN_USE_IP) {
+    base = ip;
+    constant_pool_offset += ip_code_entry_delta;
+  } else {
+    DCHECK(access_method == CONSTRUCT_INTERNAL_REFERENCE);
+    base = kConstantPoolRegister;
+    ConstantPoolUnavailableScope constant_pool_unavailable(this);
+
+    // CheckBuffer() is called too frequently. This will pre-grow
+    // the buffer if needed to avoid spliting the relocation and instructions
+    EnsureSpaceFor(kMovInstructionsNoConstantPool * kInstrSize);
+
+    uintptr_t code_start = reinterpret_cast<uintptr_t>(pc_) - pc_offset();
+    mov(base, Operand(code_start, RelocInfo::INTERNAL_REFERENCE));
+  }
+  LoadP(kConstantPoolRegister, MemOperand(base, constant_pool_offset));
+}
+#endif
+
+
+void MacroAssembler::StubPrologue(int prologue_offset) {
+  LoadSmiLiteral(r11, Smi::FromInt(StackFrame::STUB));
+  PushFixedFrame(r11);
+  // Adjust FP to point to saved FP.
+  addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+#if V8_OOL_CONSTANT_POOL
+  // ip contains prologue address
+  LoadConstantPoolPointerRegister(CAN_USE_IP, -prologue_offset);
+  set_ool_constant_pool_available(true);
+#endif
+}
+
+
+void MacroAssembler::Prologue(bool code_pre_aging, int prologue_offset) {
+  {
+    PredictableCodeSizeScope predictible_code_size_scope(
+        this, kNoCodeAgeSequenceLength);
+    Assembler::BlockTrampolinePoolScope block_trampoline_pool(this);
+    // The following instructions must remain together and unmodified
+    // for code aging to work properly.
+    if (code_pre_aging) {
+      // Pre-age the code.
+      // This matches the code found in PatchPlatformCodeAge()
+      Code* stub = Code::GetPreAgedCodeAgeStub(isolate());
+      intptr_t target = reinterpret_cast<intptr_t>(stub->instruction_start());
+      // Don't use Call -- we need to preserve ip and lr
+      nop();  // marker to detect sequence (see IsOld)
+      mov(r3, Operand(target));
+      Jump(r3);
+      for (int i = 0; i < kCodeAgingSequenceNops; i++) {
+        nop();
+      }
+    } else {
+      // This matches the code found in GetNoCodeAgeSequence()
+      PushFixedFrame(r4);
+      // Adjust fp to point to saved fp.
+      addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+      for (int i = 0; i < kNoCodeAgeSequenceNops; i++) {
+        nop();
+      }
+    }
+  }
+#if V8_OOL_CONSTANT_POOL
+  // ip contains prologue address
+  LoadConstantPoolPointerRegister(CAN_USE_IP, -prologue_offset);
+  set_ool_constant_pool_available(true);
+#endif
+}
+
+
+void MacroAssembler::EnterFrame(StackFrame::Type type,
+                                bool load_constant_pool_pointer_reg) {
+  if (FLAG_enable_ool_constant_pool && load_constant_pool_pointer_reg) {
+    PushFixedFrame();
+#if V8_OOL_CONSTANT_POOL
+    // This path should not rely on ip containing code entry.
+    LoadConstantPoolPointerRegister(CONSTRUCT_INTERNAL_REFERENCE);
+#endif
+    LoadSmiLiteral(ip, Smi::FromInt(type));
+    push(ip);
+  } else {
+    LoadSmiLiteral(ip, Smi::FromInt(type));
+    PushFixedFrame(ip);
+  }
+  // Adjust FP to point to saved FP.
+  addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+
+  mov(r0, Operand(CodeObject()));
+  push(r0);
+}
+
+
+int MacroAssembler::LeaveFrame(StackFrame::Type type, int stack_adjustment) {
+#if V8_OOL_CONSTANT_POOL
+  ConstantPoolUnavailableScope constant_pool_unavailable(this);
+#endif
+  // r3: preserved
+  // r4: preserved
+  // r5: preserved
+
+  // Drop the execution stack down to the frame pointer and restore
+  // the caller frame pointer, return address and constant pool pointer.
+  int frame_ends;
+  LoadP(r0, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
+  LoadP(ip, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+#if V8_OOL_CONSTANT_POOL
+  const int exitOffset = ExitFrameConstants::kConstantPoolOffset;
+  const int standardOffset = StandardFrameConstants::kConstantPoolOffset;
+  const int offset = ((type == StackFrame::EXIT) ? exitOffset : standardOffset);
+  LoadP(kConstantPoolRegister, MemOperand(fp, offset));
+#endif
+  mtlr(r0);
+  frame_ends = pc_offset();
+  Add(sp, fp, StandardFrameConstants::kCallerSPOffset + stack_adjustment, r0);
+  mr(fp, ip);
+  return frame_ends;
+}
+
+
+// ExitFrame layout (probably wrongish.. needs updating)
+//
+//  SP -> previousSP
+//        LK reserved
+//        code
+//        sp_on_exit (for debug?)
+// oldSP->prev SP
+//        LK
+//        <parameters on stack>
+
+// Prior to calling EnterExitFrame, we've got a bunch of parameters
+// on the stack that we need to wrap a real frame around.. so first
+// we reserve a slot for LK and push the previous SP which is captured
+// in the fp register (r31)
+// Then - we buy a new frame
+
+void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
+  // Set up the frame structure on the stack.
+  DCHECK_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
+  DCHECK_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
+  DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
+  DCHECK(stack_space > 0);
+
+  // This is an opportunity to build a frame to wrap
+  // all of the pushes that have happened inside of V8
+  // since we were called from C code
+
+  // replicate ARM frame - TODO make this more closely follow PPC ABI
+  mflr(r0);
+  Push(r0, fp);
+  mr(fp, sp);
+  // Reserve room for saved entry sp and code object.
+  subi(sp, sp, Operand(ExitFrameConstants::kFrameSize));
+
+  if (emit_debug_code()) {
+    li(r8, Operand::Zero());
+    StoreP(r8, MemOperand(fp, ExitFrameConstants::kSPOffset));
+  }
+#if V8_OOL_CONSTANT_POOL
+  StoreP(kConstantPoolRegister,
+         MemOperand(fp, ExitFrameConstants::kConstantPoolOffset));
+#endif
+  mov(r8, Operand(CodeObject()));
+  StoreP(r8, MemOperand(fp, ExitFrameConstants::kCodeOffset));
+
+  // Save the frame pointer and the context in top.
+  mov(r8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
+  StoreP(fp, MemOperand(r8));
+  mov(r8, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
+  StoreP(cp, MemOperand(r8));
+
+  // Optionally save all volatile double registers.
+  if (save_doubles) {
+    SaveFPRegs(sp, 0, DoubleRegister::kNumVolatileRegisters);
+    // Note that d0 will be accessible at
+    //   fp - ExitFrameConstants::kFrameSize -
+    //   kNumVolatileRegisters * kDoubleSize,
+    // since the sp slot and code slot were pushed after the fp.
+  }
+
+  addi(sp, sp, Operand(-stack_space * kPointerSize));
+
+  // Allocate and align the frame preparing for calling the runtime
+  // function.
+  const int frame_alignment = ActivationFrameAlignment();
+  if (frame_alignment > kPointerSize) {
+    DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
+    ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
+  }
+  li(r0, Operand::Zero());
+  StorePU(r0, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize));
+
+  // Set the exit frame sp value to point just before the return address
+  // location.
+  addi(r8, sp, Operand((kStackFrameExtraParamSlot + 1) * kPointerSize));
+  StoreP(r8, MemOperand(fp, ExitFrameConstants::kSPOffset));
+}
+
+
+void MacroAssembler::InitializeNewString(Register string, Register length,
+                                         Heap::RootListIndex map_index,
+                                         Register scratch1, Register scratch2) {
+  SmiTag(scratch1, length);
+  LoadRoot(scratch2, map_index);
+  StoreP(scratch1, FieldMemOperand(string, String::kLengthOffset), r0);
+  li(scratch1, Operand(String::kEmptyHashField));
+  StoreP(scratch2, FieldMemOperand(string, HeapObject::kMapOffset), r0);
+  StoreP(scratch1, FieldMemOperand(string, String::kHashFieldSlot), r0);
+}
+
+
+int MacroAssembler::ActivationFrameAlignment() {
+#if !defined(USE_SIMULATOR)
+  // Running on the real platform. Use the alignment as mandated by the local
+  // environment.
+  // Note: This will break if we ever start generating snapshots on one PPC
+  // platform for another PPC platform with a different alignment.
+  return base::OS::ActivationFrameAlignment();
+#else  // Simulated
+  // If we are using the simulator then we should always align to the expected
+  // alignment. As the simulator is used to generate snapshots we do not know
+  // if the target platform will need alignment, so this is controlled from a
+  // flag.
+  return FLAG_sim_stack_alignment;
+#endif
+}
+
+
+void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
+                                    bool restore_context) {
+#if V8_OOL_CONSTANT_POOL
+  ConstantPoolUnavailableScope constant_pool_unavailable(this);
+#endif
+  // Optionally restore all double registers.
+  if (save_doubles) {
+    // Calculate the stack location of the saved doubles and restore them.
+    const int kNumRegs = DoubleRegister::kNumVolatileRegisters;
+    const int offset =
+        (ExitFrameConstants::kFrameSize + kNumRegs * kDoubleSize);
+    addi(r6, fp, Operand(-offset));
+    RestoreFPRegs(r6, 0, kNumRegs);
+  }
+
+  // Clear top frame.
+  li(r6, Operand::Zero());
+  mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
+  StoreP(r6, MemOperand(ip));
+
+  // Restore current context from top and clear it in debug mode.
+  if (restore_context) {
+    mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
+    LoadP(cp, MemOperand(ip));
+  }
+#ifdef DEBUG
+  mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
+  StoreP(r6, MemOperand(ip));
+#endif
+
+  // Tear down the exit frame, pop the arguments, and return.
+  LeaveFrame(StackFrame::EXIT);
+
+  if (argument_count.is_valid()) {
+    ShiftLeftImm(argument_count, argument_count, Operand(kPointerSizeLog2));
+    add(sp, sp, argument_count);
+  }
+}
+
+
+void MacroAssembler::MovFromFloatResult(const DoubleRegister dst) {
+  Move(dst, d1);
+}
+
+
+void MacroAssembler::MovFromFloatParameter(const DoubleRegister dst) {
+  Move(dst, d1);
+}
+
+
+void MacroAssembler::InvokePrologue(const ParameterCount& expected,
+                                    const ParameterCount& actual,
+                                    Handle<Code> code_constant,
+                                    Register code_reg, Label* done,
+                                    bool* definitely_mismatches,
+                                    InvokeFlag flag,
+                                    const CallWrapper& call_wrapper) {
+  bool definitely_matches = false;
+  *definitely_mismatches = false;
+  Label regular_invoke;
+
+  // Check whether the expected and actual arguments count match. If not,
+  // setup registers according to contract with ArgumentsAdaptorTrampoline:
+  //  r3: actual arguments count
+  //  r4: function (passed through to callee)
+  //  r5: expected arguments count
+
+  // The code below is made a lot easier because the calling code already sets
+  // up actual and expected registers according to the contract if values are
+  // passed in registers.
+
+  // ARM has some sanity checks as per below, considering add them for PPC
+  //  DCHECK(actual.is_immediate() || actual.reg().is(r3));
+  //  DCHECK(expected.is_immediate() || expected.reg().is(r5));
+  //  DCHECK((!code_constant.is_null() && code_reg.is(no_reg))
+  //          || code_reg.is(r6));
+
+  if (expected.is_immediate()) {
+    DCHECK(actual.is_immediate());
+    if (expected.immediate() == actual.immediate()) {
+      definitely_matches = true;
+    } else {
+      mov(r3, Operand(actual.immediate()));
+      const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
+      if (expected.immediate() == sentinel) {
+        // Don't worry about adapting arguments for builtins that
+        // don't want that done. Skip adaption code by making it look
+        // like we have a match between expected and actual number of
+        // arguments.
+        definitely_matches = true;
+      } else {
+        *definitely_mismatches = true;
+        mov(r5, Operand(expected.immediate()));
+      }
+    }
+  } else {
+    if (actual.is_immediate()) {
+      cmpi(expected.reg(), Operand(actual.immediate()));
+      beq(&regular_invoke);
+      mov(r3, Operand(actual.immediate()));
+    } else {
+      cmp(expected.reg(), actual.reg());
+      beq(&regular_invoke);
+    }
+  }
+
+  if (!definitely_matches) {
+    if (!code_constant.is_null()) {
+      mov(r6, Operand(code_constant));
+      addi(r6, r6, Operand(Code::kHeaderSize - kHeapObjectTag));
+    }
+
+    Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline();
+    if (flag == CALL_FUNCTION) {
+      call_wrapper.BeforeCall(CallSize(adaptor));
+      Call(adaptor);
+      call_wrapper.AfterCall();
+      if (!*definitely_mismatches) {
+        b(done);
+      }
+    } else {
+      Jump(adaptor, RelocInfo::CODE_TARGET);
+    }
+    bind(&regular_invoke);
+  }
+}
+
+
+void MacroAssembler::InvokeCode(Register code, const ParameterCount& expected,
+                                const ParameterCount& actual, InvokeFlag flag,
+                                const CallWrapper& call_wrapper) {
+  // You can't call a function without a valid frame.
+  DCHECK(flag == JUMP_FUNCTION || has_frame());
+
+  Label done;
+  bool definitely_mismatches = false;
+  InvokePrologue(expected, actual, Handle<Code>::null(), code, &done,
+                 &definitely_mismatches, flag, call_wrapper);
+  if (!definitely_mismatches) {
+    if (flag == CALL_FUNCTION) {
+      call_wrapper.BeforeCall(CallSize(code));
+      CallJSEntry(code);
+      call_wrapper.AfterCall();
+    } else {
+      DCHECK(flag == JUMP_FUNCTION);
+      JumpToJSEntry(code);
+    }
+
+    // Continue here if InvokePrologue does handle the invocation due to
+    // mismatched parameter counts.
+    bind(&done);
+  }
+}
+
+
+void MacroAssembler::InvokeFunction(Register fun, const ParameterCount& actual,
+                                    InvokeFlag flag,
+                                    const CallWrapper& call_wrapper) {
+  // You can't call a function without a valid frame.
+  DCHECK(flag == JUMP_FUNCTION || has_frame());
+
+  // Contract with called JS functions requires that function is passed in r4.
+  DCHECK(fun.is(r4));
+
+  Register expected_reg = r5;
+  Register code_reg = ip;
+
+  LoadP(code_reg, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
+  LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
+  LoadWordArith(expected_reg,
+                FieldMemOperand(
+                    code_reg, SharedFunctionInfo::kFormalParameterCountOffset));
+#if !defined(V8_TARGET_ARCH_PPC64)
+  SmiUntag(expected_reg);
+#endif
+  LoadP(code_reg, FieldMemOperand(r4, JSFunction::kCodeEntryOffset));
+
+  ParameterCount expected(expected_reg);
+  InvokeCode(code_reg, expected, actual, flag, call_wrapper);
+}
+
+
+void MacroAssembler::InvokeFunction(Register function,
+                                    const ParameterCount& expected,
+                                    const ParameterCount& actual,
+                                    InvokeFlag flag,
+                                    const CallWrapper& call_wrapper) {
+  // You can't call a function without a valid frame.
+  DCHECK(flag == JUMP_FUNCTION || has_frame());
+
+  // Contract with called JS functions requires that function is passed in r4.
+  DCHECK(function.is(r4));
+
+  // Get the function and setup the context.
+  LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
+
+  // We call indirectly through the code field in the function to
+  // allow recompilation to take effect without changing any of the
+  // call sites.
+  LoadP(ip, FieldMemOperand(r4, JSFunction::kCodeEntryOffset));
+  InvokeCode(ip, expected, actual, flag, call_wrapper);
+}
+
+
+void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
+                                    const ParameterCount& expected,
+                                    const ParameterCount& actual,
+                                    InvokeFlag flag,
+                                    const CallWrapper& call_wrapper) {
+  Move(r4, function);
+  InvokeFunction(r4, expected, actual, flag, call_wrapper);
+}
+
+
+void MacroAssembler::IsObjectJSObjectType(Register heap_object, Register map,
+                                          Register scratch, Label* fail) {
+  LoadP(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
+  IsInstanceJSObjectType(map, scratch, fail);
+}
+
+
+void MacroAssembler::IsInstanceJSObjectType(Register map, Register scratch,
+                                            Label* fail) {
+  lbz(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  cmpi(scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
+  blt(fail);
+  cmpi(scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
+  bgt(fail);
+}
+
+
+void MacroAssembler::IsObjectJSStringType(Register object, Register scratch,
+                                          Label* fail) {
+  DCHECK(kNotStringTag != 0);
+
+  LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
+  lbz(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+  andi(r0, scratch, Operand(kIsNotStringMask));
+  bne(fail, cr0);
+}
+
+
+void MacroAssembler::IsObjectNameType(Register object, Register scratch,
+                                      Label* fail) {
+  LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
+  lbz(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+  cmpi(scratch, Operand(LAST_NAME_TYPE));
+  bgt(fail);
+}
+
+
+void MacroAssembler::DebugBreak() {
+  li(r3, Operand::Zero());
+  mov(r4, Operand(ExternalReference(Runtime::kDebugBreak, isolate())));
+  CEntryStub ces(isolate(), 1);
+  DCHECK(AllowThisStubCall(&ces));
+  Call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
+}
+
+
+void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
+                                    int handler_index) {
+  // Adjust this code if not the case.
+  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
+
+  // For the JSEntry handler, we must preserve r1-r7, r0,r8-r15 are available.
+  // We want the stack to look like
+  // sp -> NextOffset
+  //       CodeObject
+  //       state
+  //       context
+  //       frame pointer
+
+  // Link the current handler as the next handler.
+  mov(r8, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
+  LoadP(r0, MemOperand(r8));
+  StorePU(r0, MemOperand(sp, -StackHandlerConstants::kSize));
+  // Set this new handler as the current one.
+  StoreP(sp, MemOperand(r8));
+
+  if (kind == StackHandler::JS_ENTRY) {
+    li(r8, Operand::Zero());  // NULL frame pointer.
+    StoreP(r8, MemOperand(sp, StackHandlerConstants::kFPOffset));
+    LoadSmiLiteral(r8, Smi::FromInt(0));  // Indicates no context.
+    StoreP(r8, MemOperand(sp, StackHandlerConstants::kContextOffset));
+  } else {
+    // still not sure if fp is right
+    StoreP(fp, MemOperand(sp, StackHandlerConstants::kFPOffset));
+    StoreP(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
+  }
+  unsigned state = StackHandler::IndexField::encode(handler_index) |
+                   StackHandler::KindField::encode(kind);
+  LoadIntLiteral(r8, state);
+  StoreP(r8, MemOperand(sp, StackHandlerConstants::kStateOffset));
+  mov(r8, Operand(CodeObject()));
+  StoreP(r8, MemOperand(sp, StackHandlerConstants::kCodeOffset));
+}
+
+
+void MacroAssembler::PopTryHandler() {
+  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
+  pop(r4);
+  mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
+  addi(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+  StoreP(r4, MemOperand(ip));
+}
+
+
+// PPC - make use of ip as a temporary register
+void MacroAssembler::JumpToHandlerEntry() {
+// Compute the handler entry address and jump to it.  The handler table is
+// a fixed array of (smi-tagged) code offsets.
+// r3 = exception, r4 = code object, r5 = state.
+#if V8_OOL_CONSTANT_POOL
+  ConstantPoolUnavailableScope constant_pool_unavailable(this);
+  LoadP(kConstantPoolRegister, FieldMemOperand(r4, Code::kConstantPoolOffset));
+#endif
+  LoadP(r6, FieldMemOperand(r4, Code::kHandlerTableOffset));  // Handler table.
+  addi(r6, r6, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  srwi(r5, r5, Operand(StackHandler::kKindWidth));  // Handler index.
+  slwi(ip, r5, Operand(kPointerSizeLog2));
+  add(ip, r6, ip);
+  LoadP(r5, MemOperand(ip));  // Smi-tagged offset.
+  addi(r4, r4, Operand(Code::kHeaderSize - kHeapObjectTag));  // Code start.
+  SmiUntag(ip, r5);
+  add(r0, r4, ip);
+  mtctr(r0);
+  bctr();
+}
+
+
+void MacroAssembler::Throw(Register value) {
+  // Adjust this code if not the case.
+  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
+  STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
+  Label skip;
+
+  // The exception is expected in r3.
+  if (!value.is(r3)) {
+    mr(r3, value);
+  }
+  // Drop the stack pointer to the top of the top handler.
+  mov(r6, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
+  LoadP(sp, MemOperand(r6));
+  // Restore the next handler.
+  pop(r5);
+  StoreP(r5, MemOperand(r6));
+
+  // Get the code object (r4) and state (r5).  Restore the context and frame
+  // pointer.
+  pop(r4);
+  pop(r5);
+  pop(cp);
+  pop(fp);
+
+  // If the handler is a JS frame, restore the context to the frame.
+  // (kind == ENTRY) == (fp == 0) == (cp == 0), so we could test either fp
+  // or cp.
+  cmpi(cp, Operand::Zero());
+  beq(&skip);
+  StoreP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  bind(&skip);
+
+  JumpToHandlerEntry();
+}
+
+
+void MacroAssembler::ThrowUncatchable(Register value) {
+  // Adjust this code if not the case.
+  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
+
+  // The exception is expected in r3.
+  if (!value.is(r3)) {
+    mr(r3, value);
+  }
+  // Drop the stack pointer to the top of the top stack handler.
+  mov(r6, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
+  LoadP(sp, MemOperand(r6));
+
+  // Unwind the handlers until the ENTRY handler is found.
+  Label fetch_next, check_kind;
+  b(&check_kind);
+  bind(&fetch_next);
+  LoadP(sp, MemOperand(sp, StackHandlerConstants::kNextOffset));
+
+  bind(&check_kind);
+  STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
+  LoadP(r5, MemOperand(sp, StackHandlerConstants::kStateOffset));
+  andi(r0, r5, Operand(StackHandler::KindField::kMask));
+  bne(&fetch_next, cr0);
+
+  // Set the top handler address to next handler past the top ENTRY handler.
+  pop(r5);
+  StoreP(r5, MemOperand(r6));
+  // Get the code object (r4) and state (r5).  Clear the context and frame
+  // pointer (0 was saved in the handler).
+  pop(r4);
+  pop(r5);
+  pop(cp);
+  pop(fp);
+
+  JumpToHandlerEntry();
+}
+
+
+void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
+                                            Register scratch, Label* miss) {
+  Label same_contexts;
+
+  DCHECK(!holder_reg.is(scratch));
+  DCHECK(!holder_reg.is(ip));
+  DCHECK(!scratch.is(ip));
+
+  // Load current lexical context from the stack frame.
+  LoadP(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset));
+// In debug mode, make sure the lexical context is set.
+#ifdef DEBUG
+  cmpi(scratch, Operand::Zero());
+  Check(ne, kWeShouldNotHaveAnEmptyLexicalContext);
+#endif
+
+  // Load the native context of the current context.
+  int offset =
+      Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
+  LoadP(scratch, FieldMemOperand(scratch, offset));
+  LoadP(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
+
+  // Check the context is a native context.
+  if (emit_debug_code()) {
+    // Cannot use ip as a temporary in this verification code. Due to the fact
+    // that ip is clobbered as part of cmp with an object Operand.
+    push(holder_reg);  // Temporarily save holder on the stack.
+    // Read the first word and compare to the native_context_map.
+    LoadP(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset));
+    LoadRoot(ip, Heap::kNativeContextMapRootIndex);
+    cmp(holder_reg, ip);
+    Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext);
+    pop(holder_reg);  // Restore holder.
+  }
+
+  // Check if both contexts are the same.
+  LoadP(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
+  cmp(scratch, ip);
+  beq(&same_contexts);
+
+  // Check the context is a native context.
+  if (emit_debug_code()) {
+    // Cannot use ip as a temporary in this verification code. Due to the fact
+    // that ip is clobbered as part of cmp with an object Operand.
+    push(holder_reg);    // Temporarily save holder on the stack.
+    mr(holder_reg, ip);  // Move ip to its holding place.
+    LoadRoot(ip, Heap::kNullValueRootIndex);
+    cmp(holder_reg, ip);
+    Check(ne, kJSGlobalProxyContextShouldNotBeNull);
+
+    LoadP(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset));
+    LoadRoot(ip, Heap::kNativeContextMapRootIndex);
+    cmp(holder_reg, ip);
+    Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext);
+    // Restore ip is not needed. ip is reloaded below.
+    pop(holder_reg);  // Restore holder.
+    // Restore ip to holder's context.
+    LoadP(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
+  }
+
+  // Check that the security token in the calling global object is
+  // compatible with the security token in the receiving global
+  // object.
+  int token_offset =
+      Context::kHeaderSize + Context::SECURITY_TOKEN_INDEX * kPointerSize;
+
+  LoadP(scratch, FieldMemOperand(scratch, token_offset));
+  LoadP(ip, FieldMemOperand(ip, token_offset));
+  cmp(scratch, ip);
+  bne(miss);
+
+  bind(&same_contexts);
+}
+
+
+// Compute the hash code from the untagged key.  This must be kept in sync with
+// ComputeIntegerHash in utils.h and KeyedLoadGenericStub in
+// code-stub-hydrogen.cc
+void MacroAssembler::GetNumberHash(Register t0, Register scratch) {
+  // First of all we assign the hash seed to scratch.
+  LoadRoot(scratch, Heap::kHashSeedRootIndex);
+  SmiUntag(scratch);
+
+  // Xor original key with a seed.
+  xor_(t0, t0, scratch);
+
+  // Compute the hash code from the untagged key.  This must be kept in sync
+  // with ComputeIntegerHash in utils.h.
+  //
+  // hash = ~hash + (hash << 15);
+  notx(scratch, t0);
+  slwi(t0, t0, Operand(15));
+  add(t0, scratch, t0);
+  // hash = hash ^ (hash >> 12);
+  srwi(scratch, t0, Operand(12));
+  xor_(t0, t0, scratch);
+  // hash = hash + (hash << 2);
+  slwi(scratch, t0, Operand(2));
+  add(t0, t0, scratch);
+  // hash = hash ^ (hash >> 4);
+  srwi(scratch, t0, Operand(4));
+  xor_(t0, t0, scratch);
+  // hash = hash * 2057;
+  mr(r0, t0);
+  slwi(scratch, t0, Operand(3));
+  add(t0, t0, scratch);
+  slwi(scratch, r0, Operand(11));
+  add(t0, t0, scratch);
+  // hash = hash ^ (hash >> 16);
+  srwi(scratch, t0, Operand(16));
+  xor_(t0, t0, scratch);
+}
+
+
+void MacroAssembler::LoadFromNumberDictionary(Label* miss, Register elements,
+                                              Register key, Register result,
+                                              Register t0, Register t1,
+                                              Register t2) {
+  // Register use:
+  //
+  // elements - holds the slow-case elements of the receiver on entry.
+  //            Unchanged unless 'result' is the same register.
+  //
+  // key      - holds the smi key on entry.
+  //            Unchanged unless 'result' is the same register.
+  //
+  // result   - holds the result on exit if the load succeeded.
+  //            Allowed to be the same as 'key' or 'result'.
+  //            Unchanged on bailout so 'key' or 'result' can be used
+  //            in further computation.
+  //
+  // Scratch registers:
+  //
+  // t0 - holds the untagged key on entry and holds the hash once computed.
+  //
+  // t1 - used to hold the capacity mask of the dictionary
+  //
+  // t2 - used for the index into the dictionary.
+  Label done;
+
+  GetNumberHash(t0, t1);
+
+  // Compute the capacity mask.
+  LoadP(t1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset));
+  SmiUntag(t1);
+  subi(t1, t1, Operand(1));
+
+  // Generate an unrolled loop that performs a few probes before giving up.
+  for (int i = 0; i < kNumberDictionaryProbes; i++) {
+    // Use t2 for index calculations and keep the hash intact in t0.
+    mr(t2, t0);
+    // Compute the masked index: (hash + i + i * i) & mask.
+    if (i > 0) {
+      addi(t2, t2, Operand(SeededNumberDictionary::GetProbeOffset(i)));
+    }
+    and_(t2, t2, t1);
+
+    // Scale the index by multiplying by the element size.
+    DCHECK(SeededNumberDictionary::kEntrySize == 3);
+    slwi(ip, t2, Operand(1));
+    add(t2, t2, ip);  // t2 = t2 * 3
+
+    // Check if the key is identical to the name.
+    slwi(t2, t2, Operand(kPointerSizeLog2));
+    add(t2, elements, t2);
+    LoadP(ip,
+          FieldMemOperand(t2, SeededNumberDictionary::kElementsStartOffset));
+    cmp(key, ip);
+    if (i != kNumberDictionaryProbes - 1) {
+      beq(&done);
+    } else {
+      bne(miss);
+    }
+  }
+
+  bind(&done);
+  // Check that the value is a field property.
+  // t2: elements + (index * kPointerSize)
+  const int kDetailsOffset =
+      SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
+  LoadP(t1, FieldMemOperand(t2, kDetailsOffset));
+  LoadSmiLiteral(ip, Smi::FromInt(PropertyDetails::TypeField::kMask));
+  DCHECK_EQ(FIELD, 0);
+  and_(r0, t1, ip, SetRC);
+  bne(miss, cr0);
+
+  // Get the value at the masked, scaled index and return.
+  const int kValueOffset =
+      SeededNumberDictionary::kElementsStartOffset + kPointerSize;
+  LoadP(result, FieldMemOperand(t2, kValueOffset));
+}
+
+
+void MacroAssembler::Allocate(int object_size, Register result,
+                              Register scratch1, Register scratch2,
+                              Label* gc_required, AllocationFlags flags) {
+  DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
+  if (!FLAG_inline_new) {
+    if (emit_debug_code()) {
+      // Trash the registers to simulate an allocation failure.
+      li(result, Operand(0x7091));
+      li(scratch1, Operand(0x7191));
+      li(scratch2, Operand(0x7291));
+    }
+    b(gc_required);
+    return;
+  }
+
+  DCHECK(!result.is(scratch1));
+  DCHECK(!result.is(scratch2));
+  DCHECK(!scratch1.is(scratch2));
+  DCHECK(!scratch1.is(ip));
+  DCHECK(!scratch2.is(ip));
+
+  // Make object size into bytes.
+  if ((flags & SIZE_IN_WORDS) != 0) {
+    object_size *= kPointerSize;
+  }
+  DCHECK_EQ(0, static_cast<int>(object_size & kObjectAlignmentMask));
+
+  // Check relative positions of allocation top and limit addresses.
+  ExternalReference allocation_top =
+      AllocationUtils::GetAllocationTopReference(isolate(), flags);
+  ExternalReference allocation_limit =
+      AllocationUtils::GetAllocationLimitReference(isolate(), flags);
+
+  intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
+  intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
+  DCHECK((limit - top) == kPointerSize);
+
+  // Set up allocation top address register.
+  Register topaddr = scratch1;
+  mov(topaddr, Operand(allocation_top));
+
+  // This code stores a temporary value in ip. This is OK, as the code below
+  // does not need ip for implicit literal generation.
+  if ((flags & RESULT_CONTAINS_TOP) == 0) {
+    // Load allocation top into result and allocation limit into ip.
+    LoadP(result, MemOperand(topaddr));
+    LoadP(ip, MemOperand(topaddr, kPointerSize));
+  } else {
+    if (emit_debug_code()) {
+      // Assert that result actually contains top on entry. ip is used
+      // immediately below so this use of ip does not cause difference with
+      // respect to register content between debug and release mode.
+      LoadP(ip, MemOperand(topaddr));
+      cmp(result, ip);
+      Check(eq, kUnexpectedAllocationTop);
+    }
+    // Load allocation limit into ip. Result already contains allocation top.
+    LoadP(ip, MemOperand(topaddr, limit - top), r0);
+  }
+
+  if ((flags & DOUBLE_ALIGNMENT) != 0) {
+    // Align the next allocation. Storing the filler map without checking top is
+    // safe in new-space because the limit of the heap is aligned there.
+    DCHECK((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
+#if V8_TARGET_ARCH_PPC64
+    STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
+#else
+    STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
+    andi(scratch2, result, Operand(kDoubleAlignmentMask));
+    Label aligned;
+    beq(&aligned, cr0);
+    if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
+      cmpl(result, ip);
+      bge(gc_required);
+    }
+    mov(scratch2, Operand(isolate()->factory()->one_pointer_filler_map()));
+    stw(scratch2, MemOperand(result));
+    addi(result, result, Operand(kDoubleSize / 2));
+    bind(&aligned);
+#endif
+  }
+
+  // Calculate new top and bail out if new space is exhausted. Use result
+  // to calculate the new top.
+  sub(r0, ip, result);
+  if (is_int16(object_size)) {
+    cmpi(r0, Operand(object_size));
+    blt(gc_required);
+    addi(scratch2, result, Operand(object_size));
+  } else {
+    Cmpi(r0, Operand(object_size), scratch2);
+    blt(gc_required);
+    add(scratch2, result, scratch2);
+  }
+  StoreP(scratch2, MemOperand(topaddr));
+
+  // Tag object if requested.
+  if ((flags & TAG_OBJECT) != 0) {
+    addi(result, result, Operand(kHeapObjectTag));
+  }
+}
+
+
+void MacroAssembler::Allocate(Register object_size, Register result,
+                              Register scratch1, Register scratch2,
+                              Label* gc_required, AllocationFlags flags) {
+  if (!FLAG_inline_new) {
+    if (emit_debug_code()) {
+      // Trash the registers to simulate an allocation failure.
+      li(result, Operand(0x7091));
+      li(scratch1, Operand(0x7191));
+      li(scratch2, Operand(0x7291));
+    }
+    b(gc_required);
+    return;
+  }
+
+  // Assert that the register arguments are different and that none of
+  // them are ip. ip is used explicitly in the code generated below.
+  DCHECK(!result.is(scratch1));
+  DCHECK(!result.is(scratch2));
+  DCHECK(!scratch1.is(scratch2));
+  DCHECK(!object_size.is(ip));
+  DCHECK(!result.is(ip));
+  DCHECK(!scratch1.is(ip));
+  DCHECK(!scratch2.is(ip));
+
+  // Check relative positions of allocation top and limit addresses.
+  ExternalReference allocation_top =
+      AllocationUtils::GetAllocationTopReference(isolate(), flags);
+  ExternalReference allocation_limit =
+      AllocationUtils::GetAllocationLimitReference(isolate(), flags);
+  intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
+  intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
+  DCHECK((limit - top) == kPointerSize);
+
+  // Set up allocation top address.
+  Register topaddr = scratch1;
+  mov(topaddr, Operand(allocation_top));
+
+  // This code stores a temporary value in ip. This is OK, as the code below
+  // does not need ip for implicit literal generation.
+  if ((flags & RESULT_CONTAINS_TOP) == 0) {
+    // Load allocation top into result and allocation limit into ip.
+    LoadP(result, MemOperand(topaddr));
+    LoadP(ip, MemOperand(topaddr, kPointerSize));
+  } else {
+    if (emit_debug_code()) {
+      // Assert that result actually contains top on entry. ip is used
+      // immediately below so this use of ip does not cause difference with
+      // respect to register content between debug and release mode.
+      LoadP(ip, MemOperand(topaddr));
+      cmp(result, ip);
+      Check(eq, kUnexpectedAllocationTop);
+    }
+    // Load allocation limit into ip. Result already contains allocation top.
+    LoadP(ip, MemOperand(topaddr, limit - top));
+  }
+
+  if ((flags & DOUBLE_ALIGNMENT) != 0) {
+    // Align the next allocation. Storing the filler map without checking top is
+    // safe in new-space because the limit of the heap is aligned there.
+    DCHECK((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
+#if V8_TARGET_ARCH_PPC64
+    STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
+#else
+    STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
+    andi(scratch2, result, Operand(kDoubleAlignmentMask));
+    Label aligned;
+    beq(&aligned, cr0);
+    if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
+      cmpl(result, ip);
+      bge(gc_required);
+    }
+    mov(scratch2, Operand(isolate()->factory()->one_pointer_filler_map()));
+    stw(scratch2, MemOperand(result));
+    addi(result, result, Operand(kDoubleSize / 2));
+    bind(&aligned);
+#endif
+  }
+
+  // Calculate new top and bail out if new space is exhausted. Use result
+  // to calculate the new top. Object size may be in words so a shift is
+  // required to get the number of bytes.
+  sub(r0, ip, result);
+  if ((flags & SIZE_IN_WORDS) != 0) {
+    ShiftLeftImm(scratch2, object_size, Operand(kPointerSizeLog2));
+    cmp(r0, scratch2);
+    blt(gc_required);
+    add(scratch2, result, scratch2);
+  } else {
+    cmp(r0, object_size);
+    blt(gc_required);
+    add(scratch2, result, object_size);
+  }
+
+  // Update allocation top. result temporarily holds the new top.
+  if (emit_debug_code()) {
+    andi(r0, scratch2, Operand(kObjectAlignmentMask));
+    Check(eq, kUnalignedAllocationInNewSpace, cr0);
+  }
+  StoreP(scratch2, MemOperand(topaddr));
+
+  // Tag object if requested.
+  if ((flags & TAG_OBJECT) != 0) {
+    addi(result, result, Operand(kHeapObjectTag));
+  }
+}
+
+
+void MacroAssembler::UndoAllocationInNewSpace(Register object,
+                                              Register scratch) {
+  ExternalReference new_space_allocation_top =
+      ExternalReference::new_space_allocation_top_address(isolate());
+
+  // Make sure the object has no tag before resetting top.
+  mov(r0, Operand(~kHeapObjectTagMask));
+  and_(object, object, r0);
+// was.. and_(object, object, Operand(~kHeapObjectTagMask));
+#ifdef DEBUG
+  // Check that the object un-allocated is below the current top.
+  mov(scratch, Operand(new_space_allocation_top));
+  LoadP(scratch, MemOperand(scratch));
+  cmp(object, scratch);
+  Check(lt, kUndoAllocationOfNonAllocatedMemory);
+#endif
+  // Write the address of the object to un-allocate as the current top.
+  mov(scratch, Operand(new_space_allocation_top));
+  StoreP(object, MemOperand(scratch));
+}
+
+
+void MacroAssembler::AllocateTwoByteString(Register result, Register length,
+                                           Register scratch1, Register scratch2,
+                                           Register scratch3,
+                                           Label* gc_required) {
+  // Calculate the number of bytes needed for the characters in the string while
+  // observing object alignment.
+  DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
+  slwi(scratch1, length, Operand(1));  // Length in bytes, not chars.
+  addi(scratch1, scratch1,
+       Operand(kObjectAlignmentMask + SeqTwoByteString::kHeaderSize));
+  mov(r0, Operand(~kObjectAlignmentMask));
+  and_(scratch1, scratch1, r0);
+
+  // Allocate two-byte string in new space.
+  Allocate(scratch1, result, scratch2, scratch3, gc_required, TAG_OBJECT);
+
+  // Set the map, length and hash field.
+  InitializeNewString(result, length, Heap::kStringMapRootIndex, scratch1,
+                      scratch2);
+}
+
+
+void MacroAssembler::AllocateOneByteString(Register result, Register length,
+                                           Register scratch1, Register scratch2,
+                                           Register scratch3,
+                                           Label* gc_required) {
+  // Calculate the number of bytes needed for the characters in the string while
+  // observing object alignment.
+  DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
+  DCHECK(kCharSize == 1);
+  addi(scratch1, length,
+       Operand(kObjectAlignmentMask + SeqOneByteString::kHeaderSize));
+  li(r0, Operand(~kObjectAlignmentMask));
+  and_(scratch1, scratch1, r0);
+
+  // Allocate one-byte string in new space.
+  Allocate(scratch1, result, scratch2, scratch3, gc_required, TAG_OBJECT);
+
+  // Set the map, length and hash field.
+  InitializeNewString(result, length, Heap::kOneByteStringMapRootIndex,
+                      scratch1, scratch2);
+}
+
+
+void MacroAssembler::AllocateTwoByteConsString(Register result, Register length,
+                                               Register scratch1,
+                                               Register scratch2,
+                                               Label* gc_required) {
+  Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
+           TAG_OBJECT);
+
+  InitializeNewString(result, length, Heap::kConsStringMapRootIndex, scratch1,
+                      scratch2);
+}
+
+
+void MacroAssembler::AllocateOneByteConsString(Register result, Register length,
+                                               Register scratch1,
+                                               Register scratch2,
+                                               Label* gc_required) {
+  Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
+           TAG_OBJECT);
+
+  InitializeNewString(result, length, Heap::kConsOneByteStringMapRootIndex,
+                      scratch1, scratch2);
+}
+
+
+void MacroAssembler::AllocateTwoByteSlicedString(Register result,
+                                                 Register length,
+                                                 Register scratch1,
+                                                 Register scratch2,
+                                                 Label* gc_required) {
+  Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
+           TAG_OBJECT);
+
+  InitializeNewString(result, length, Heap::kSlicedStringMapRootIndex, scratch1,
+                      scratch2);
+}
+
+
+void MacroAssembler::AllocateOneByteSlicedString(Register result,
+                                                 Register length,
+                                                 Register scratch1,
+                                                 Register scratch2,
+                                                 Label* gc_required) {
+  Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
+           TAG_OBJECT);
+
+  InitializeNewString(result, length, Heap::kSlicedOneByteStringMapRootIndex,
+                      scratch1, scratch2);
+}
+
+
+void MacroAssembler::CompareObjectType(Register object, Register map,
+                                       Register type_reg, InstanceType type) {
+  const Register temp = type_reg.is(no_reg) ? r0 : type_reg;
+
+  LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset));
+  CompareInstanceType(map, temp, type);
+}
+
+
+void MacroAssembler::CheckObjectTypeRange(Register object, Register map,
+                                          InstanceType min_type,
+                                          InstanceType max_type,
+                                          Label* false_label) {
+  STATIC_ASSERT(Map::kInstanceTypeOffset < 4096);
+  STATIC_ASSERT(LAST_TYPE < 256);
+  LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset));
+  lbz(ip, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  subi(ip, ip, Operand(min_type));
+  cmpli(ip, Operand(max_type - min_type));
+  bgt(false_label);
+}
+
+
+void MacroAssembler::CompareInstanceType(Register map, Register type_reg,
+                                         InstanceType type) {
+  STATIC_ASSERT(Map::kInstanceTypeOffset < 4096);
+  STATIC_ASSERT(LAST_TYPE < 256);
+  lbz(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  cmpi(type_reg, Operand(type));
+}
+
+
+void MacroAssembler::CompareRoot(Register obj, Heap::RootListIndex index) {
+  DCHECK(!obj.is(r0));
+  LoadRoot(r0, index);
+  cmp(obj, r0);
+}
+
+
+void MacroAssembler::CheckFastElements(Register map, Register scratch,
+                                       Label* fail) {
+  STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+  STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+  STATIC_ASSERT(FAST_ELEMENTS == 2);
+  STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
+  lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset));
+  STATIC_ASSERT(Map::kMaximumBitField2FastHoleyElementValue < 0x8000);
+  cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue));
+  bgt(fail);
+}
+
+
+void MacroAssembler::CheckFastObjectElements(Register map, Register scratch,
+                                             Label* fail) {
+  STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+  STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+  STATIC_ASSERT(FAST_ELEMENTS == 2);
+  STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
+  lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset));
+  cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
+  ble(fail);
+  cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue));
+  bgt(fail);
+}
+
+
+void MacroAssembler::CheckFastSmiElements(Register map, Register scratch,
+                                          Label* fail) {
+  STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+  STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+  lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset));
+  cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
+  bgt(fail);
+}
+
+
+void MacroAssembler::StoreNumberToDoubleElements(
+    Register value_reg, Register key_reg, Register elements_reg,
+    Register scratch1, DoubleRegister double_scratch, Label* fail,
+    int elements_offset) {
+  Label smi_value, store;
+
+  // Handle smi values specially.
+  JumpIfSmi(value_reg, &smi_value);
+
+  // Ensure that the object is a heap number
+  CheckMap(value_reg, scratch1, isolate()->factory()->heap_number_map(), fail,
+           DONT_DO_SMI_CHECK);
+
+  lfd(double_scratch, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
+  // Force a canonical NaN.
+  CanonicalizeNaN(double_scratch);
+  b(&store);
+
+  bind(&smi_value);
+  SmiToDouble(double_scratch, value_reg);
+
+  bind(&store);
+  SmiToDoubleArrayOffset(scratch1, key_reg);
+  add(scratch1, elements_reg, scratch1);
+  stfd(double_scratch, FieldMemOperand(scratch1, FixedDoubleArray::kHeaderSize -
+                                                     elements_offset));
+}
+
+
+void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left,
+                                            Register right,
+                                            Register overflow_dst,
+                                            Register scratch) {
+  DCHECK(!dst.is(overflow_dst));
+  DCHECK(!dst.is(scratch));
+  DCHECK(!overflow_dst.is(scratch));
+  DCHECK(!overflow_dst.is(left));
+  DCHECK(!overflow_dst.is(right));
+
+  // C = A+B; C overflows if A/B have same sign and C has diff sign than A
+  if (dst.is(left)) {
+    mr(scratch, left);            // Preserve left.
+    add(dst, left, right);        // Left is overwritten.
+    xor_(scratch, dst, scratch);  // Original left.
+    xor_(overflow_dst, dst, right);
+  } else if (dst.is(right)) {
+    mr(scratch, right);           // Preserve right.
+    add(dst, left, right);        // Right is overwritten.
+    xor_(scratch, dst, scratch);  // Original right.
+    xor_(overflow_dst, dst, left);
+  } else {
+    add(dst, left, right);
+    xor_(overflow_dst, dst, left);
+    xor_(scratch, dst, right);
+  }
+  and_(overflow_dst, scratch, overflow_dst, SetRC);
+}
+
+
+void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left,
+                                            intptr_t right,
+                                            Register overflow_dst,
+                                            Register scratch) {
+  Register original_left = left;
+  DCHECK(!dst.is(overflow_dst));
+  DCHECK(!dst.is(scratch));
+  DCHECK(!overflow_dst.is(scratch));
+  DCHECK(!overflow_dst.is(left));
+
+  // C = A+B; C overflows if A/B have same sign and C has diff sign than A
+  if (dst.is(left)) {
+    // Preserve left.
+    original_left = overflow_dst;
+    mr(original_left, left);
+  }
+  Add(dst, left, right, scratch);
+  xor_(overflow_dst, dst, original_left);
+  if (right >= 0) {
+    and_(overflow_dst, overflow_dst, dst, SetRC);
+  } else {
+    andc(overflow_dst, overflow_dst, dst, SetRC);
+  }
+}
+
+
+void MacroAssembler::SubAndCheckForOverflow(Register dst, Register left,
+                                            Register right,
+                                            Register overflow_dst,
+                                            Register scratch) {
+  DCHECK(!dst.is(overflow_dst));
+  DCHECK(!dst.is(scratch));
+  DCHECK(!overflow_dst.is(scratch));
+  DCHECK(!overflow_dst.is(left));
+  DCHECK(!overflow_dst.is(right));
+
+  // C = A-B; C overflows if A/B have diff signs and C has diff sign than A
+  if (dst.is(left)) {
+    mr(scratch, left);      // Preserve left.
+    sub(dst, left, right);  // Left is overwritten.
+    xor_(overflow_dst, dst, scratch);
+    xor_(scratch, scratch, right);
+    and_(overflow_dst, overflow_dst, scratch, SetRC);
+  } else if (dst.is(right)) {
+    mr(scratch, right);     // Preserve right.
+    sub(dst, left, right);  // Right is overwritten.
+    xor_(overflow_dst, dst, left);
+    xor_(scratch, left, scratch);
+    and_(overflow_dst, overflow_dst, scratch, SetRC);
+  } else {
+    sub(dst, left, right);
+    xor_(overflow_dst, dst, left);
+    xor_(scratch, left, right);
+    and_(overflow_dst, scratch, overflow_dst, SetRC);
+  }
+}
+
+
+void MacroAssembler::CompareMap(Register obj, Register scratch, Handle<Map> map,
+                                Label* early_success) {
+  LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
+  CompareMap(scratch, map, early_success);
+}
+
+
+void MacroAssembler::CompareMap(Register obj_map, Handle<Map> map,
+                                Label* early_success) {
+  mov(r0, Operand(map));
+  cmp(obj_map, r0);
+}
+
+
+void MacroAssembler::CheckMap(Register obj, Register scratch, Handle<Map> map,
+                              Label* fail, SmiCheckType smi_check_type) {
+  if (smi_check_type == DO_SMI_CHECK) {
+    JumpIfSmi(obj, fail);
+  }
+
+  Label success;
+  CompareMap(obj, scratch, map, &success);
+  bne(fail);
+  bind(&success);
+}
+
+
+void MacroAssembler::CheckMap(Register obj, Register scratch,
+                              Heap::RootListIndex index, Label* fail,
+                              SmiCheckType smi_check_type) {
+  if (smi_check_type == DO_SMI_CHECK) {
+    JumpIfSmi(obj, fail);
+  }
+  LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
+  LoadRoot(r0, index);
+  cmp(scratch, r0);
+  bne(fail);
+}
+
+
+void MacroAssembler::DispatchMap(Register obj, Register scratch,
+                                 Handle<Map> map, Handle<Code> success,
+                                 SmiCheckType smi_check_type) {
+  Label fail;
+  if (smi_check_type == DO_SMI_CHECK) {
+    JumpIfSmi(obj, &fail);
+  }
+  LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
+  mov(r0, Operand(map));
+  cmp(scratch, r0);
+  bne(&fail);
+  Jump(success, RelocInfo::CODE_TARGET, al);
+  bind(&fail);
+}
+
+
+void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
+                                             Register scratch, Label* miss,
+                                             bool miss_on_bound_function) {
+  Label non_instance;
+  if (miss_on_bound_function) {
+    // Check that the receiver isn't a smi.
+    JumpIfSmi(function, miss);
+
+    // Check that the function really is a function.  Load map into result reg.
+    CompareObjectType(function, result, scratch, JS_FUNCTION_TYPE);
+    bne(miss);
+
+    LoadP(scratch,
+          FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
+    lwz(scratch,
+        FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
+    TestBit(scratch,
+#if V8_TARGET_ARCH_PPC64
+            SharedFunctionInfo::kBoundFunction,
+#else
+            SharedFunctionInfo::kBoundFunction + kSmiTagSize,
+#endif
+            r0);
+    bne(miss, cr0);
+
+    // Make sure that the function has an instance prototype.
+    lbz(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
+    andi(r0, scratch, Operand(1 << Map::kHasNonInstancePrototype));
+    bne(&non_instance, cr0);
+  }
+
+  // Get the prototype or initial map from the function.
+  LoadP(result,
+        FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
+
+  // If the prototype or initial map is the hole, don't return it and
+  // simply miss the cache instead. This will allow us to allocate a
+  // prototype object on-demand in the runtime system.
+  LoadRoot(r0, Heap::kTheHoleValueRootIndex);
+  cmp(result, r0);
+  beq(miss);
+
+  // If the function does not have an initial map, we're done.
+  Label done;
+  CompareObjectType(result, scratch, scratch, MAP_TYPE);
+  bne(&done);
+
+  // Get the prototype from the initial map.
+  LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset));
+
+  if (miss_on_bound_function) {
+    b(&done);
+
+    // Non-instance prototype: Fetch prototype from constructor field
+    // in initial map.
+    bind(&non_instance);
+    LoadP(result, FieldMemOperand(result, Map::kConstructorOffset));
+  }
+
+  // All done.
+  bind(&done);
+}
+
+
+void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id,
+                              Condition cond) {
+  DCHECK(AllowThisStubCall(stub));  // Stub calls are not allowed in some stubs.
+  Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id, cond);
+}
+
+
+void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) {
+  Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
+}
+
+
+static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
+  return ref0.address() - ref1.address();
+}
+
+
+void MacroAssembler::CallApiFunctionAndReturn(
+    Register function_address, ExternalReference thunk_ref, int stack_space,
+    MemOperand return_value_operand, MemOperand* context_restore_operand) {
+  ExternalReference next_address =
+      ExternalReference::handle_scope_next_address(isolate());
+  const int kNextOffset = 0;
+  const int kLimitOffset = AddressOffset(
+      ExternalReference::handle_scope_limit_address(isolate()), next_address);
+  const int kLevelOffset = AddressOffset(
+      ExternalReference::handle_scope_level_address(isolate()), next_address);
+
+  DCHECK(function_address.is(r4) || function_address.is(r5));
+  Register scratch = r6;
+
+  Label profiler_disabled;
+  Label end_profiler_check;
+  mov(scratch, Operand(ExternalReference::is_profiling_address(isolate())));
+  lbz(scratch, MemOperand(scratch, 0));
+  cmpi(scratch, Operand::Zero());
+  beq(&profiler_disabled);
+
+  // Additional parameter is the address of the actual callback.
+  mov(scratch, Operand(thunk_ref));
+  jmp(&end_profiler_check);
+
+  bind(&profiler_disabled);
+  mr(scratch, function_address);
+  bind(&end_profiler_check);
+
+  // Allocate HandleScope in callee-save registers.
+  // r17 - next_address
+  // r14 - next_address->kNextOffset
+  // r15 - next_address->kLimitOffset
+  // r16 - next_address->kLevelOffset
+  mov(r17, Operand(next_address));
+  LoadP(r14, MemOperand(r17, kNextOffset));
+  LoadP(r15, MemOperand(r17, kLimitOffset));
+  lwz(r16, MemOperand(r17, kLevelOffset));
+  addi(r16, r16, Operand(1));
+  stw(r16, MemOperand(r17, kLevelOffset));
+
+  if (FLAG_log_timer_events) {
+    FrameScope frame(this, StackFrame::MANUAL);
+    PushSafepointRegisters();
+    PrepareCallCFunction(1, r3);
+    mov(r3, Operand(ExternalReference::isolate_address(isolate())));
+    CallCFunction(ExternalReference::log_enter_external_function(isolate()), 1);
+    PopSafepointRegisters();
+  }
+
+  // Native call returns to the DirectCEntry stub which redirects to the
+  // return address pushed on stack (could have moved after GC).
+  // DirectCEntry stub itself is generated early and never moves.
+  DirectCEntryStub stub(isolate());
+  stub.GenerateCall(this, scratch);
+
+  if (FLAG_log_timer_events) {
+    FrameScope frame(this, StackFrame::MANUAL);
+    PushSafepointRegisters();
+    PrepareCallCFunction(1, r3);
+    mov(r3, Operand(ExternalReference::isolate_address(isolate())));
+    CallCFunction(ExternalReference::log_leave_external_function(isolate()), 1);
+    PopSafepointRegisters();
+  }
+
+  Label promote_scheduled_exception;
+  Label exception_handled;
+  Label delete_allocated_handles;
+  Label leave_exit_frame;
+  Label return_value_loaded;
+
+  // load value from ReturnValue
+  LoadP(r3, return_value_operand);
+  bind(&return_value_loaded);
+  // No more valid handles (the result handle was the last one). Restore
+  // previous handle scope.
+  StoreP(r14, MemOperand(r17, kNextOffset));
+  if (emit_debug_code()) {
+    lwz(r4, MemOperand(r17, kLevelOffset));
+    cmp(r4, r16);
+    Check(eq, kUnexpectedLevelAfterReturnFromApiCall);
+  }
+  subi(r16, r16, Operand(1));
+  stw(r16, MemOperand(r17, kLevelOffset));
+  LoadP(r0, MemOperand(r17, kLimitOffset));
+  cmp(r15, r0);
+  bne(&delete_allocated_handles);
+
+  // Check if the function scheduled an exception.
+  bind(&leave_exit_frame);
+  LoadRoot(r14, Heap::kTheHoleValueRootIndex);
+  mov(r15, Operand(ExternalReference::scheduled_exception_address(isolate())));
+  LoadP(r15, MemOperand(r15));
+  cmp(r14, r15);
+  bne(&promote_scheduled_exception);
+  bind(&exception_handled);
+
+  bool restore_context = context_restore_operand != NULL;
+  if (restore_context) {
+    LoadP(cp, *context_restore_operand);
+  }
+  // LeaveExitFrame expects unwind space to be in a register.
+  mov(r14, Operand(stack_space));
+  LeaveExitFrame(false, r14, !restore_context);
+  blr();
+
+  bind(&promote_scheduled_exception);
+  {
+    FrameScope frame(this, StackFrame::INTERNAL);
+    CallExternalReference(
+        ExternalReference(Runtime::kPromoteScheduledException, isolate()), 0);
+  }
+  jmp(&exception_handled);
+
+  // HandleScope limit has changed. Delete allocated extensions.
+  bind(&delete_allocated_handles);
+  StoreP(r15, MemOperand(r17, kLimitOffset));
+  mr(r14, r3);
+  PrepareCallCFunction(1, r15);
+  mov(r3, Operand(ExternalReference::isolate_address(isolate())));
+  CallCFunction(ExternalReference::delete_handle_scope_extensions(isolate()),
+                1);
+  mr(r3, r14);
+  b(&leave_exit_frame);
+}
+
+
+bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
+  return has_frame_ || !stub->SometimesSetsUpAFrame();
+}
+
+
+void MacroAssembler::IndexFromHash(Register hash, Register index) {
+  // If the hash field contains an array index pick it out. The assert checks
+  // that the constants for the maximum number of digits for an array index
+  // cached in the hash field and the number of bits reserved for it does not
+  // conflict.
+  DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
+         (1 << String::kArrayIndexValueBits));
+  DecodeFieldToSmi<String::ArrayIndexValueBits>(index, hash);
+}
+
+
+void MacroAssembler::SmiToDouble(DoubleRegister value, Register smi) {
+  SmiUntag(ip, smi);
+  ConvertIntToDouble(ip, value);
+}
+
+
+void MacroAssembler::TestDoubleIsInt32(DoubleRegister double_input,
+                                       Register scratch1, Register scratch2,
+                                       DoubleRegister double_scratch) {
+  TryDoubleToInt32Exact(scratch1, double_input, scratch2, double_scratch);
+}
+
+
+void MacroAssembler::TryDoubleToInt32Exact(Register result,
+                                           DoubleRegister double_input,
+                                           Register scratch,
+                                           DoubleRegister double_scratch) {
+  Label done;
+  DCHECK(!double_input.is(double_scratch));
+
+  ConvertDoubleToInt64(double_input,
+#if !V8_TARGET_ARCH_PPC64
+                       scratch,
+#endif
+                       result, double_scratch);
+
+#if V8_TARGET_ARCH_PPC64
+  TestIfInt32(result, scratch, r0);
+#else
+  TestIfInt32(scratch, result, r0);
+#endif
+  bne(&done);
+
+  // convert back and compare
+  fcfid(double_scratch, double_scratch);
+  fcmpu(double_scratch, double_input);
+  bind(&done);
+}
+
+
+void MacroAssembler::TryInt32Floor(Register result, DoubleRegister double_input,
+                                   Register input_high, Register scratch,
+                                   DoubleRegister double_scratch, Label* done,
+                                   Label* exact) {
+  DCHECK(!result.is(input_high));
+  DCHECK(!double_input.is(double_scratch));
+  Label exception;
+
+  MovDoubleHighToInt(input_high, double_input);
+
+  // Test for NaN/Inf
+  ExtractBitMask(result, input_high, HeapNumber::kExponentMask);
+  cmpli(result, Operand(0x7ff));
+  beq(&exception);
+
+  // Convert (rounding to -Inf)
+  ConvertDoubleToInt64(double_input,
+#if !V8_TARGET_ARCH_PPC64
+                       scratch,
+#endif
+                       result, double_scratch, kRoundToMinusInf);
+
+// Test for overflow
+#if V8_TARGET_ARCH_PPC64
+  TestIfInt32(result, scratch, r0);
+#else
+  TestIfInt32(scratch, result, r0);
+#endif
+  bne(&exception);
+
+  // Test for exactness
+  fcfid(double_scratch, double_scratch);
+  fcmpu(double_scratch, double_input);
+  beq(exact);
+  b(done);
+
+  bind(&exception);
+}
+
+
+void MacroAssembler::TryInlineTruncateDoubleToI(Register result,
+                                                DoubleRegister double_input,
+                                                Label* done) {
+  DoubleRegister double_scratch = kScratchDoubleReg;
+  Register scratch = ip;
+
+  ConvertDoubleToInt64(double_input,
+#if !V8_TARGET_ARCH_PPC64
+                       scratch,
+#endif
+                       result, double_scratch);
+
+// Test for overflow
+#if V8_TARGET_ARCH_PPC64
+  TestIfInt32(result, scratch, r0);
+#else
+  TestIfInt32(scratch, result, r0);
+#endif
+  beq(done);
+}
+
+
+void MacroAssembler::TruncateDoubleToI(Register result,
+                                       DoubleRegister double_input) {
+  Label done;
+
+  TryInlineTruncateDoubleToI(result, double_input, &done);
+
+  // If we fell through then inline version didn't succeed - call stub instead.
+  mflr(r0);
+  push(r0);
+  // Put input on stack.
+  stfdu(double_input, MemOperand(sp, -kDoubleSize));
+
+  DoubleToIStub stub(isolate(), sp, result, 0, true, true);
+  CallStub(&stub);
+
+  addi(sp, sp, Operand(kDoubleSize));
+  pop(r0);
+  mtlr(r0);
+
+  bind(&done);
+}
+
+
+void MacroAssembler::TruncateHeapNumberToI(Register result, Register object) {
+  Label done;
+  DoubleRegister double_scratch = kScratchDoubleReg;
+  DCHECK(!result.is(object));
+
+  lfd(double_scratch, FieldMemOperand(object, HeapNumber::kValueOffset));
+  TryInlineTruncateDoubleToI(result, double_scratch, &done);
+
+  // If we fell through then inline version didn't succeed - call stub instead.
+  mflr(r0);
+  push(r0);
+  DoubleToIStub stub(isolate(), object, result,
+                     HeapNumber::kValueOffset - kHeapObjectTag, true, true);
+  CallStub(&stub);
+  pop(r0);
+  mtlr(r0);
+
+  bind(&done);
+}
+
+
+void MacroAssembler::TruncateNumberToI(Register object, Register result,
+                                       Register heap_number_map,
+                                       Register scratch1, Label* not_number) {
+  Label done;
+  DCHECK(!result.is(object));
+
+  UntagAndJumpIfSmi(result, object, &done);
+  JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
+  TruncateHeapNumberToI(result, object);
+
+  bind(&done);
+}
+
+
+void MacroAssembler::GetLeastBitsFromSmi(Register dst, Register src,
+                                         int num_least_bits) {
+#if V8_TARGET_ARCH_PPC64
+  rldicl(dst, src, kBitsPerPointer - kSmiShift,
+         kBitsPerPointer - num_least_bits);
+#else
+  rlwinm(dst, src, kBitsPerPointer - kSmiShift,
+         kBitsPerPointer - num_least_bits, 31);
+#endif
+}
+
+
+void MacroAssembler::GetLeastBitsFromInt32(Register dst, Register src,
+                                           int num_least_bits) {
+  rlwinm(dst, src, 0, 32 - num_least_bits, 31);
+}
+
+
+void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
+                                 SaveFPRegsMode save_doubles) {
+  // All parameters are on the stack.  r3 has the return value after call.
+
+  // If the expected number of arguments of the runtime function is
+  // constant, we check that the actual number of arguments match the
+  // expectation.
+  CHECK(f->nargs < 0 || f->nargs == num_arguments);
+
+  // TODO(1236192): Most runtime routines don't need the number of
+  // arguments passed in because it is constant. At some point we
+  // should remove this need and make the runtime routine entry code
+  // smarter.
+  mov(r3, Operand(num_arguments));
+  mov(r4, Operand(ExternalReference(f, isolate())));
+  CEntryStub stub(isolate(),
+#if V8_TARGET_ARCH_PPC64
+                  f->result_size,
+#else
+                  1,
+#endif
+                  save_doubles);
+  CallStub(&stub);
+}
+
+
+void MacroAssembler::CallExternalReference(const ExternalReference& ext,
+                                           int num_arguments) {
+  mov(r3, Operand(num_arguments));
+  mov(r4, Operand(ext));
+
+  CEntryStub stub(isolate(), 1);
+  CallStub(&stub);
+}
+
+
+void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
+                                               int num_arguments,
+                                               int result_size) {
+  // TODO(1236192): Most runtime routines don't need the number of
+  // arguments passed in because it is constant. At some point we
+  // should remove this need and make the runtime routine entry code
+  // smarter.
+  mov(r3, Operand(num_arguments));
+  JumpToExternalReference(ext);
+}
+
+
+void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid, int num_arguments,
+                                     int result_size) {
+  TailCallExternalReference(ExternalReference(fid, isolate()), num_arguments,
+                            result_size);
+}
+
+
+void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) {
+  mov(r4, Operand(builtin));
+  CEntryStub stub(isolate(), 1);
+  Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+}
+
+
+void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag,
+                                   const CallWrapper& call_wrapper) {
+  // You can't call a builtin without a valid frame.
+  DCHECK(flag == JUMP_FUNCTION || has_frame());
+
+  GetBuiltinEntry(ip, id);
+  if (flag == CALL_FUNCTION) {
+    call_wrapper.BeforeCall(CallSize(ip));
+    CallJSEntry(ip);
+    call_wrapper.AfterCall();
+  } else {
+    DCHECK(flag == JUMP_FUNCTION);
+    JumpToJSEntry(ip);
+  }
+}
+
+
+void MacroAssembler::GetBuiltinFunction(Register target,
+                                        Builtins::JavaScript id) {
+  // Load the builtins object into target register.
+  LoadP(target,
+        MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
+  LoadP(target, FieldMemOperand(target, GlobalObject::kBuiltinsOffset));
+  // Load the JavaScript builtin function from the builtins object.
+  LoadP(target,
+        FieldMemOperand(target, JSBuiltinsObject::OffsetOfFunctionWithId(id)),
+        r0);
+}
+
+
+void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
+  DCHECK(!target.is(r4));
+  GetBuiltinFunction(r4, id);
+  // Load the code entry point from the builtins object.
+  LoadP(target, FieldMemOperand(r4, JSFunction::kCodeEntryOffset));
+}
+
+
+void MacroAssembler::SetCounter(StatsCounter* counter, int value,
+                                Register scratch1, Register scratch2) {
+  if (FLAG_native_code_counters && counter->Enabled()) {
+    mov(scratch1, Operand(value));
+    mov(scratch2, Operand(ExternalReference(counter)));
+    stw(scratch1, MemOperand(scratch2));
+  }
+}
+
+
+void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
+                                      Register scratch1, Register scratch2) {
+  DCHECK(value > 0);
+  if (FLAG_native_code_counters && counter->Enabled()) {
+    mov(scratch2, Operand(ExternalReference(counter)));
+    lwz(scratch1, MemOperand(scratch2));
+    addi(scratch1, scratch1, Operand(value));
+    stw(scratch1, MemOperand(scratch2));
+  }
+}
+
+
+void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
+                                      Register scratch1, Register scratch2) {
+  DCHECK(value > 0);
+  if (FLAG_native_code_counters && counter->Enabled()) {
+    mov(scratch2, Operand(ExternalReference(counter)));
+    lwz(scratch1, MemOperand(scratch2));
+    subi(scratch1, scratch1, Operand(value));
+    stw(scratch1, MemOperand(scratch2));
+  }
+}
+
+
+void MacroAssembler::Assert(Condition cond, BailoutReason reason,
+                            CRegister cr) {
+  if (emit_debug_code()) Check(cond, reason, cr);
+}
+
+
+void MacroAssembler::AssertFastElements(Register elements) {
+  if (emit_debug_code()) {
+    DCHECK(!elements.is(r0));
+    Label ok;
+    push(elements);
+    LoadP(elements, FieldMemOperand(elements, HeapObject::kMapOffset));
+    LoadRoot(r0, Heap::kFixedArrayMapRootIndex);
+    cmp(elements, r0);
+    beq(&ok);
+    LoadRoot(r0, Heap::kFixedDoubleArrayMapRootIndex);
+    cmp(elements, r0);
+    beq(&ok);
+    LoadRoot(r0, Heap::kFixedCOWArrayMapRootIndex);
+    cmp(elements, r0);
+    beq(&ok);
+    Abort(kJSObjectWithFastElementsMapHasSlowElements);
+    bind(&ok);
+    pop(elements);
+  }
+}
+
+
+void MacroAssembler::Check(Condition cond, BailoutReason reason, CRegister cr) {
+  Label L;
+  b(cond, &L, cr);
+  Abort(reason);
+  // will not return here
+  bind(&L);
+}
+
+
+void MacroAssembler::Abort(BailoutReason reason) {
+  Label abort_start;
+  bind(&abort_start);
+#ifdef DEBUG
+  const char* msg = GetBailoutReason(reason);
+  if (msg != NULL) {
+    RecordComment("Abort message: ");
+    RecordComment(msg);
+  }
+
+  if (FLAG_trap_on_abort) {
+    stop(msg);
+    return;
+  }
+#endif
+
+  LoadSmiLiteral(r0, Smi::FromInt(reason));
+  push(r0);
+  // Disable stub call restrictions to always allow calls to abort.
+  if (!has_frame_) {
+    // We don't actually want to generate a pile of code for this, so just
+    // claim there is a stack frame, without generating one.
+    FrameScope scope(this, StackFrame::NONE);
+    CallRuntime(Runtime::kAbort, 1);
+  } else {
+    CallRuntime(Runtime::kAbort, 1);
+  }
+  // will not return here
+}
+
+
+void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
+  if (context_chain_length > 0) {
+    // Move up the chain of contexts to the context containing the slot.
+    LoadP(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX)));
+    for (int i = 1; i < context_chain_length; i++) {
+      LoadP(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
+    }
+  } else {
+    // Slot is in the current function context.  Move it into the
+    // destination register in case we store into it (the write barrier
+    // cannot be allowed to destroy the context in esi).
+    mr(dst, cp);
+  }
+}
+
+
+void MacroAssembler::LoadTransitionedArrayMapConditional(
+    ElementsKind expected_kind, ElementsKind transitioned_kind,
+    Register map_in_out, Register scratch, Label* no_map_match) {
+  // Load the global or builtins object from the current context.
+  LoadP(scratch,
+        MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
+  LoadP(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
+
+  // Check that the function's map is the same as the expected cached map.
+  LoadP(scratch,
+        MemOperand(scratch, Context::SlotOffset(Context::JS_ARRAY_MAPS_INDEX)));
+  size_t offset = expected_kind * kPointerSize + FixedArrayBase::kHeaderSize;
+  LoadP(scratch, FieldMemOperand(scratch, offset));
+  cmp(map_in_out, scratch);
+  bne(no_map_match);
+
+  // Use the transitioned cached map.
+  offset = transitioned_kind * kPointerSize + FixedArrayBase::kHeaderSize;
+  LoadP(map_in_out, FieldMemOperand(scratch, offset));
+}
+
+
+void MacroAssembler::LoadGlobalFunction(int index, Register function) {
+  // Load the global or builtins object from the current context.
+  LoadP(function,
+        MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
+  // Load the native context from the global or builtins object.
+  LoadP(function,
+        FieldMemOperand(function, GlobalObject::kNativeContextOffset));
+  // Load the function from the native context.
+  LoadP(function, MemOperand(function, Context::SlotOffset(index)), r0);
+}
+
+
+void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
+                                                  Register map,
+                                                  Register scratch) {
+  // Load the initial map. The global functions all have initial maps.
+  LoadP(map,
+        FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
+  if (emit_debug_code()) {
+    Label ok, fail;
+    CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK);
+    b(&ok);
+    bind(&fail);
+    Abort(kGlobalFunctionsMustHaveInitialMap);
+    bind(&ok);
+  }
+}
+
+
+void MacroAssembler::JumpIfNotPowerOfTwoOrZero(
+    Register reg, Register scratch, Label* not_power_of_two_or_zero) {
+  subi(scratch, reg, Operand(1));
+  cmpi(scratch, Operand::Zero());
+  blt(not_power_of_two_or_zero);
+  and_(r0, scratch, reg, SetRC);
+  bne(not_power_of_two_or_zero, cr0);
+}
+
+
+void MacroAssembler::JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg,
+                                                     Register scratch,
+                                                     Label* zero_and_neg,
+                                                     Label* not_power_of_two) {
+  subi(scratch, reg, Operand(1));
+  cmpi(scratch, Operand::Zero());
+  blt(zero_and_neg);
+  and_(r0, scratch, reg, SetRC);
+  bne(not_power_of_two, cr0);
+}
+
+#if !V8_TARGET_ARCH_PPC64
+void MacroAssembler::SmiTagCheckOverflow(Register reg, Register overflow) {
+  DCHECK(!reg.is(overflow));
+  mr(overflow, reg);  // Save original value.
+  SmiTag(reg);
+  xor_(overflow, overflow, reg, SetRC);  // Overflow if (value ^ 2 * value) < 0.
+}
+
+
+void MacroAssembler::SmiTagCheckOverflow(Register dst, Register src,
+                                         Register overflow) {
+  if (dst.is(src)) {
+    // Fall back to slower case.
+    SmiTagCheckOverflow(dst, overflow);
+  } else {
+    DCHECK(!dst.is(src));
+    DCHECK(!dst.is(overflow));
+    DCHECK(!src.is(overflow));
+    SmiTag(dst, src);
+    xor_(overflow, dst, src, SetRC);  // Overflow if (value ^ 2 * value) < 0.
+  }
+}
+#endif
+
+void MacroAssembler::JumpIfNotBothSmi(Register reg1, Register reg2,
+                                      Label* on_not_both_smi) {
+  STATIC_ASSERT(kSmiTag == 0);
+  DCHECK_EQ(1, static_cast<int>(kSmiTagMask));
+  orx(r0, reg1, reg2, LeaveRC);
+  JumpIfNotSmi(r0, on_not_both_smi);
+}
+
+
+void MacroAssembler::UntagAndJumpIfSmi(Register dst, Register src,
+                                       Label* smi_case) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+  TestBit(src, 0, r0);
+  SmiUntag(dst, src);
+  beq(smi_case, cr0);
+}
+
+
+void MacroAssembler::UntagAndJumpIfNotSmi(Register dst, Register src,
+                                          Label* non_smi_case) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+  TestBit(src, 0, r0);
+  SmiUntag(dst, src);
+  bne(non_smi_case, cr0);
+}
+
+
+void MacroAssembler::JumpIfEitherSmi(Register reg1, Register reg2,
+                                     Label* on_either_smi) {
+  STATIC_ASSERT(kSmiTag == 0);
+  JumpIfSmi(reg1, on_either_smi);
+  JumpIfSmi(reg2, on_either_smi);
+}
+
+
+void MacroAssembler::AssertNotSmi(Register object) {
+  if (emit_debug_code()) {
+    STATIC_ASSERT(kSmiTag == 0);
+    TestIfSmi(object, r0);
+    Check(ne, kOperandIsASmi, cr0);
+  }
+}
+
+
+void MacroAssembler::AssertSmi(Register object) {
+  if (emit_debug_code()) {
+    STATIC_ASSERT(kSmiTag == 0);
+    TestIfSmi(object, r0);
+    Check(eq, kOperandIsNotSmi, cr0);
+  }
+}
+
+
+void MacroAssembler::AssertString(Register object) {
+  if (emit_debug_code()) {
+    STATIC_ASSERT(kSmiTag == 0);
+    TestIfSmi(object, r0);
+    Check(ne, kOperandIsASmiAndNotAString, cr0);
+    push(object);
+    LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset));
+    CompareInstanceType(object, object, FIRST_NONSTRING_TYPE);
+    pop(object);
+    Check(lt, kOperandIsNotAString);
+  }
+}
+
+
+void MacroAssembler::AssertName(Register object) {
+  if (emit_debug_code()) {
+    STATIC_ASSERT(kSmiTag == 0);
+    TestIfSmi(object, r0);
+    Check(ne, kOperandIsASmiAndNotAName, cr0);
+    push(object);
+    LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset));
+    CompareInstanceType(object, object, LAST_NAME_TYPE);
+    pop(object);
+    Check(le, kOperandIsNotAName);
+  }
+}
+
+
+void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
+                                                     Register scratch) {
+  if (emit_debug_code()) {
+    Label done_checking;
+    AssertNotSmi(object);
+    CompareRoot(object, Heap::kUndefinedValueRootIndex);
+    beq(&done_checking);
+    LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
+    CompareRoot(scratch, Heap::kAllocationSiteMapRootIndex);
+    Assert(eq, kExpectedUndefinedOrCell);
+    bind(&done_checking);
+  }
+}
+
+
+void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) {
+  if (emit_debug_code()) {
+    CompareRoot(reg, index);
+    Check(eq, kHeapNumberMapRegisterClobbered);
+  }
+}
+
+
+void MacroAssembler::JumpIfNotHeapNumber(Register object,
+                                         Register heap_number_map,
+                                         Register scratch,
+                                         Label* on_not_heap_number) {
+  LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
+  AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
+  cmp(scratch, heap_number_map);
+  bne(on_not_heap_number);
+}
+
+
+void MacroAssembler::LookupNumberStringCache(Register object, Register result,
+                                             Register scratch1,
+                                             Register scratch2,
+                                             Register scratch3,
+                                             Label* not_found) {
+  // Use of registers. Register result is used as a temporary.
+  Register number_string_cache = result;
+  Register mask = scratch3;
+
+  // Load the number string cache.
+  LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
+
+  // Make the hash mask from the length of the number string cache. It
+  // contains two elements (number and string) for each cache entry.
+  LoadP(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset));
+  // Divide length by two (length is a smi).
+  ShiftRightArithImm(mask, mask, kSmiTagSize + kSmiShiftSize + 1);
+  subi(mask, mask, Operand(1));  // Make mask.
+
+  // Calculate the entry in the number string cache. The hash value in the
+  // number string cache for smis is just the smi value, and the hash for
+  // doubles is the xor of the upper and lower words. See
+  // Heap::GetNumberStringCache.
+  Label is_smi;
+  Label load_result_from_cache;
+  JumpIfSmi(object, &is_smi);
+  CheckMap(object, scratch1, Heap::kHeapNumberMapRootIndex, not_found,
+           DONT_DO_SMI_CHECK);
+
+  STATIC_ASSERT(8 == kDoubleSize);
+  lwz(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
+  lwz(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset));
+  xor_(scratch1, scratch1, scratch2);
+  and_(scratch1, scratch1, mask);
+
+  // Calculate address of entry in string cache: each entry consists
+  // of two pointer sized fields.
+  ShiftLeftImm(scratch1, scratch1, Operand(kPointerSizeLog2 + 1));
+  add(scratch1, number_string_cache, scratch1);
+
+  Register probe = mask;
+  LoadP(probe, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
+  JumpIfSmi(probe, not_found);
+  lfd(d0, FieldMemOperand(object, HeapNumber::kValueOffset));
+  lfd(d1, FieldMemOperand(probe, HeapNumber::kValueOffset));
+  fcmpu(d0, d1);
+  bne(not_found);  // The cache did not contain this value.
+  b(&load_result_from_cache);
+
+  bind(&is_smi);
+  Register scratch = scratch1;
+  SmiUntag(scratch, object);
+  and_(scratch, mask, scratch);
+  // Calculate address of entry in string cache: each entry consists
+  // of two pointer sized fields.
+  ShiftLeftImm(scratch, scratch, Operand(kPointerSizeLog2 + 1));
+  add(scratch, number_string_cache, scratch);
+
+  // Check if the entry is the smi we are looking for.
+  LoadP(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize));
+  cmp(object, probe);
+  bne(not_found);
+
+  // Get the result from the cache.
+  bind(&load_result_from_cache);
+  LoadP(result,
+        FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize));
+  IncrementCounter(isolate()->counters()->number_to_string_native(), 1,
+                   scratch1, scratch2);
+}
+
+
+void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings(
+    Register first, Register second, Register scratch1, Register scratch2,
+    Label* failure) {
+  // Test that both first and second are sequential one-byte strings.
+  // Assume that they are non-smis.
+  LoadP(scratch1, FieldMemOperand(first, HeapObject::kMapOffset));
+  LoadP(scratch2, FieldMemOperand(second, HeapObject::kMapOffset));
+  lbz(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
+  lbz(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
+
+  JumpIfBothInstanceTypesAreNotSequentialOneByte(scratch1, scratch2, scratch1,
+                                                 scratch2, failure);
+}
+
+void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register first,
+                                                           Register second,
+                                                           Register scratch1,
+                                                           Register scratch2,
+                                                           Label* failure) {
+  // Check that neither is a smi.
+  and_(scratch1, first, second);
+  JumpIfSmi(scratch1, failure);
+  JumpIfNonSmisNotBothSequentialOneByteStrings(first, second, scratch1,
+                                               scratch2, failure);
+}
+
+
+void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register reg,
+                                                     Label* not_unique_name) {
+  STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
+  Label succeed;
+  andi(r0, reg, Operand(kIsNotStringMask | kIsNotInternalizedMask));
+  beq(&succeed, cr0);
+  cmpi(reg, Operand(SYMBOL_TYPE));
+  bne(not_unique_name);
+
+  bind(&succeed);
+}
+
+
+// Allocates a heap number or jumps to the need_gc label if the young space
+// is full and a scavenge is needed.
+void MacroAssembler::AllocateHeapNumber(Register result, Register scratch1,
+                                        Register scratch2,
+                                        Register heap_number_map,
+                                        Label* gc_required,
+                                        TaggingMode tagging_mode,
+                                        MutableMode mode) {
+  // Allocate an object in the heap for the heap number and tag it as a heap
+  // object.
+  Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
+           tagging_mode == TAG_RESULT ? TAG_OBJECT : NO_ALLOCATION_FLAGS);
+
+  Heap::RootListIndex map_index = mode == MUTABLE
+                                      ? Heap::kMutableHeapNumberMapRootIndex
+                                      : Heap::kHeapNumberMapRootIndex;
+  AssertIsRoot(heap_number_map, map_index);
+
+  // Store heap number map in the allocated object.
+  if (tagging_mode == TAG_RESULT) {
+    StoreP(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset),
+           r0);
+  } else {
+    StoreP(heap_number_map, MemOperand(result, HeapObject::kMapOffset));
+  }
+}
+
+
+void MacroAssembler::AllocateHeapNumberWithValue(
+    Register result, DoubleRegister value, Register scratch1, Register scratch2,
+    Register heap_number_map, Label* gc_required) {
+  AllocateHeapNumber(result, scratch1, scratch2, heap_number_map, gc_required);
+  stfd(value, FieldMemOperand(result, HeapNumber::kValueOffset));
+}
+
+
+// Copies a fixed number of fields of heap objects from src to dst.
+void MacroAssembler::CopyFields(Register dst, Register src, RegList temps,
+                                int field_count) {
+  // At least one bit set in the first 15 registers.
+  DCHECK((temps & ((1 << 15) - 1)) != 0);
+  DCHECK((temps & dst.bit()) == 0);
+  DCHECK((temps & src.bit()) == 0);
+  // Primitive implementation using only one temporary register.
+
+  Register tmp = no_reg;
+  // Find a temp register in temps list.
+  for (int i = 0; i < 15; i++) {
+    if ((temps & (1 << i)) != 0) {
+      tmp.set_code(i);
+      break;
+    }
+  }
+  DCHECK(!tmp.is(no_reg));
+
+  for (int i = 0; i < field_count; i++) {
+    LoadP(tmp, FieldMemOperand(src, i * kPointerSize), r0);
+    StoreP(tmp, FieldMemOperand(dst, i * kPointerSize), r0);
+  }
+}
+
+
+void MacroAssembler::CopyBytes(Register src, Register dst, Register length,
+                               Register scratch) {
+  Label align_loop, aligned, word_loop, byte_loop, byte_loop_1, done;
+
+  DCHECK(!scratch.is(r0));
+
+  cmpi(length, Operand::Zero());
+  beq(&done);
+
+  // Check src alignment and length to see whether word_loop is possible
+  andi(scratch, src, Operand(kPointerSize - 1));
+  beq(&aligned, cr0);
+  subfic(scratch, scratch, Operand(kPointerSize * 2));
+  cmp(length, scratch);
+  blt(&byte_loop);
+
+  // Align src before copying in word size chunks.
+  subi(scratch, scratch, Operand(kPointerSize));
+  mtctr(scratch);
+  bind(&align_loop);
+  lbz(scratch, MemOperand(src));
+  addi(src, src, Operand(1));
+  subi(length, length, Operand(1));
+  stb(scratch, MemOperand(dst));
+  addi(dst, dst, Operand(1));
+  bdnz(&align_loop);
+
+  bind(&aligned);
+
+  // Copy bytes in word size chunks.
+  if (emit_debug_code()) {
+    andi(r0, src, Operand(kPointerSize - 1));
+    Assert(eq, kExpectingAlignmentForCopyBytes, cr0);
+  }
+
+  ShiftRightImm(scratch, length, Operand(kPointerSizeLog2));
+  cmpi(scratch, Operand::Zero());
+  beq(&byte_loop);
+
+  mtctr(scratch);
+  bind(&word_loop);
+  LoadP(scratch, MemOperand(src));
+  addi(src, src, Operand(kPointerSize));
+  subi(length, length, Operand(kPointerSize));
+  if (CpuFeatures::IsSupported(UNALIGNED_ACCESSES)) {
+    // currently false for PPC - but possible future opt
+    StoreP(scratch, MemOperand(dst));
+    addi(dst, dst, Operand(kPointerSize));
+  } else {
+#if V8_TARGET_LITTLE_ENDIAN
+    stb(scratch, MemOperand(dst, 0));
+    ShiftRightImm(scratch, scratch, Operand(8));
+    stb(scratch, MemOperand(dst, 1));
+    ShiftRightImm(scratch, scratch, Operand(8));
+    stb(scratch, MemOperand(dst, 2));
+    ShiftRightImm(scratch, scratch, Operand(8));
+    stb(scratch, MemOperand(dst, 3));
+#if V8_TARGET_ARCH_PPC64
+    ShiftRightImm(scratch, scratch, Operand(8));
+    stb(scratch, MemOperand(dst, 4));
+    ShiftRightImm(scratch, scratch, Operand(8));
+    stb(scratch, MemOperand(dst, 5));
+    ShiftRightImm(scratch, scratch, Operand(8));
+    stb(scratch, MemOperand(dst, 6));
+    ShiftRightImm(scratch, scratch, Operand(8));
+    stb(scratch, MemOperand(dst, 7));
+#endif
+#else
+#if V8_TARGET_ARCH_PPC64
+    stb(scratch, MemOperand(dst, 7));
+    ShiftRightImm(scratch, scratch, Operand(8));
+    stb(scratch, MemOperand(dst, 6));
+    ShiftRightImm(scratch, scratch, Operand(8));
+    stb(scratch, MemOperand(dst, 5));
+    ShiftRightImm(scratch, scratch, Operand(8));
+    stb(scratch, MemOperand(dst, 4));
+    ShiftRightImm(scratch, scratch, Operand(8));
+#endif
+    stb(scratch, MemOperand(dst, 3));
+    ShiftRightImm(scratch, scratch, Operand(8));
+    stb(scratch, MemOperand(dst, 2));
+    ShiftRightImm(scratch, scratch, Operand(8));
+    stb(scratch, MemOperand(dst, 1));
+    ShiftRightImm(scratch, scratch, Operand(8));
+    stb(scratch, MemOperand(dst, 0));
+#endif
+    addi(dst, dst, Operand(kPointerSize));
+  }
+  bdnz(&word_loop);
+
+  // Copy the last bytes if any left.
+  cmpi(length, Operand::Zero());
+  beq(&done);
+
+  bind(&byte_loop);
+  mtctr(length);
+  bind(&byte_loop_1);
+  lbz(scratch, MemOperand(src));
+  addi(src, src, Operand(1));
+  stb(scratch, MemOperand(dst));
+  addi(dst, dst, Operand(1));
+  bdnz(&byte_loop_1);
+
+  bind(&done);
+}
+
+
+void MacroAssembler::InitializeNFieldsWithFiller(Register start_offset,
+                                                 Register count,
+                                                 Register filler) {
+  Label loop;
+  mtctr(count);
+  bind(&loop);
+  StoreP(filler, MemOperand(start_offset));
+  addi(start_offset, start_offset, Operand(kPointerSize));
+  bdnz(&loop);
+}
+
+void MacroAssembler::InitializeFieldsWithFiller(Register start_offset,
+                                                Register end_offset,
+                                                Register filler) {
+  Label done;
+  sub(r0, end_offset, start_offset, LeaveOE, SetRC);
+  beq(&done, cr0);
+  ShiftRightImm(r0, r0, Operand(kPointerSizeLog2));
+  InitializeNFieldsWithFiller(start_offset, r0, filler);
+  bind(&done);
+}
+
+
+void MacroAssembler::SaveFPRegs(Register location, int first, int count) {
+  DCHECK(count > 0);
+  int cur = first;
+  subi(location, location, Operand(count * kDoubleSize));
+  for (int i = 0; i < count; i++) {
+    DoubleRegister reg = DoubleRegister::from_code(cur++);
+    stfd(reg, MemOperand(location, i * kDoubleSize));
+  }
+}
+
+
+void MacroAssembler::RestoreFPRegs(Register location, int first, int count) {
+  DCHECK(count > 0);
+  int cur = first + count - 1;
+  for (int i = count - 1; i >= 0; i--) {
+    DoubleRegister reg = DoubleRegister::from_code(cur--);
+    lfd(reg, MemOperand(location, i * kDoubleSize));
+  }
+  addi(location, location, Operand(count * kDoubleSize));
+}
+
+
+void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte(
+    Register first, Register second, Register scratch1, Register scratch2,
+    Label* failure) {
+  const int kFlatOneByteStringMask =
+      kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
+  const int kFlatOneByteStringTag =
+      kStringTag | kOneByteStringTag | kSeqStringTag;
+  andi(scratch1, first, Operand(kFlatOneByteStringMask));
+  andi(scratch2, second, Operand(kFlatOneByteStringMask));
+  cmpi(scratch1, Operand(kFlatOneByteStringTag));
+  bne(failure);
+  cmpi(scratch2, Operand(kFlatOneByteStringTag));
+  bne(failure);
+}
+
+
+void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(Register type,
+                                                              Register scratch,
+                                                              Label* failure) {
+  const int kFlatOneByteStringMask =
+      kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
+  const int kFlatOneByteStringTag =
+      kStringTag | kOneByteStringTag | kSeqStringTag;
+  andi(scratch, type, Operand(kFlatOneByteStringMask));
+  cmpi(scratch, Operand(kFlatOneByteStringTag));
+  bne(failure);
+}
+
+static const int kRegisterPassedArguments = 8;
+
+
+int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments,
+                                              int num_double_arguments) {
+  int stack_passed_words = 0;
+  if (num_double_arguments > DoubleRegister::kNumRegisters) {
+    stack_passed_words +=
+        2 * (num_double_arguments - DoubleRegister::kNumRegisters);
+  }
+  // Up to 8 simple arguments are passed in registers r3..r10.
+  if (num_reg_arguments > kRegisterPassedArguments) {
+    stack_passed_words += num_reg_arguments - kRegisterPassedArguments;
+  }
+  return stack_passed_words;
+}
+
+
+void MacroAssembler::EmitSeqStringSetCharCheck(Register string, Register index,
+                                               Register value,
+                                               uint32_t encoding_mask) {
+  Label is_object;
+  TestIfSmi(string, r0);
+  Check(ne, kNonObject, cr0);
+
+  LoadP(ip, FieldMemOperand(string, HeapObject::kMapOffset));
+  lbz(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset));
+
+  andi(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask));
+  cmpi(ip, Operand(encoding_mask));
+  Check(eq, kUnexpectedStringType);
+
+// The index is assumed to be untagged coming in, tag it to compare with the
+// string length without using a temp register, it is restored at the end of
+// this function.
+#if !V8_TARGET_ARCH_PPC64
+  Label index_tag_ok, index_tag_bad;
+  JumpIfNotSmiCandidate(index, r0, &index_tag_bad);
+#endif
+  SmiTag(index, index);
+#if !V8_TARGET_ARCH_PPC64
+  b(&index_tag_ok);
+  bind(&index_tag_bad);
+  Abort(kIndexIsTooLarge);
+  bind(&index_tag_ok);
+#endif
+
+  LoadP(ip, FieldMemOperand(string, String::kLengthOffset));
+  cmp(index, ip);
+  Check(lt, kIndexIsTooLarge);
+
+  DCHECK(Smi::FromInt(0) == 0);
+  cmpi(index, Operand::Zero());
+  Check(ge, kIndexIsNegative);
+
+  SmiUntag(index, index);
+}
+
+
+void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
+                                          int num_double_arguments,
+                                          Register scratch) {
+  int frame_alignment = ActivationFrameAlignment();
+  int stack_passed_arguments =
+      CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
+  int stack_space = kNumRequiredStackFrameSlots;
+
+  if (frame_alignment > kPointerSize) {
+    // Make stack end at alignment and make room for stack arguments
+    // -- preserving original value of sp.
+    mr(scratch, sp);
+    addi(sp, sp, Operand(-(stack_passed_arguments + 1) * kPointerSize));
+    DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
+    ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
+    StoreP(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
+  } else {
+    // Make room for stack arguments
+    stack_space += stack_passed_arguments;
+  }
+
+  // Allocate frame with required slots to make ABI work.
+  li(r0, Operand::Zero());
+  StorePU(r0, MemOperand(sp, -stack_space * kPointerSize));
+}
+
+
+void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
+                                          Register scratch) {
+  PrepareCallCFunction(num_reg_arguments, 0, scratch);
+}
+
+
+void MacroAssembler::MovToFloatParameter(DoubleRegister src) { Move(d1, src); }
+
+
+void MacroAssembler::MovToFloatResult(DoubleRegister src) { Move(d1, src); }
+
+
+void MacroAssembler::MovToFloatParameters(DoubleRegister src1,
+                                          DoubleRegister src2) {
+  if (src2.is(d1)) {
+    DCHECK(!src1.is(d2));
+    Move(d2, src2);
+    Move(d1, src1);
+  } else {
+    Move(d1, src1);
+    Move(d2, src2);
+  }
+}
+
+
+void MacroAssembler::CallCFunction(ExternalReference function,
+                                   int num_reg_arguments,
+                                   int num_double_arguments) {
+  mov(ip, Operand(function));
+  CallCFunctionHelper(ip, num_reg_arguments, num_double_arguments);
+}
+
+
+void MacroAssembler::CallCFunction(Register function, int num_reg_arguments,
+                                   int num_double_arguments) {
+  CallCFunctionHelper(function, num_reg_arguments, num_double_arguments);
+}
+
+
+void MacroAssembler::CallCFunction(ExternalReference function,
+                                   int num_arguments) {
+  CallCFunction(function, num_arguments, 0);
+}
+
+
+void MacroAssembler::CallCFunction(Register function, int num_arguments) {
+  CallCFunction(function, num_arguments, 0);
+}
+
+
+void MacroAssembler::CallCFunctionHelper(Register function,
+                                         int num_reg_arguments,
+                                         int num_double_arguments) {
+  DCHECK(has_frame());
+// Just call directly. The function called cannot cause a GC, or
+// allow preemption, so the return address in the link register
+// stays correct.
+#if ABI_USES_FUNCTION_DESCRIPTORS && !defined(USE_SIMULATOR)
+  // AIX uses a function descriptor. When calling C code be aware
+  // of this descriptor and pick up values from it
+  LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(function, kPointerSize));
+  LoadP(ip, MemOperand(function, 0));
+  Register dest = ip;
+#elif ABI_TOC_ADDRESSABILITY_VIA_IP
+  Move(ip, function);
+  Register dest = ip;
+#else
+  Register dest = function;
+#endif
+
+  Call(dest);
+
+  // Remove frame bought in PrepareCallCFunction
+  int stack_passed_arguments =
+      CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
+  int stack_space = kNumRequiredStackFrameSlots + stack_passed_arguments;
+  if (ActivationFrameAlignment() > kPointerSize) {
+    LoadP(sp, MemOperand(sp, stack_space * kPointerSize));
+  } else {
+    addi(sp, sp, Operand(stack_space * kPointerSize));
+  }
+}
+
+
+void MacroAssembler::FlushICache(Register address, size_t size,
+                                 Register scratch) {
+  if (CpuFeatures::IsSupported(INSTR_AND_DATA_CACHE_COHERENCY)) {
+    sync();
+    icbi(r0, address);
+    isync();
+    return;
+  }
+
+  Label done;
+
+  dcbf(r0, address);
+  sync();
+  icbi(r0, address);
+  isync();
+
+  // This code handles ranges which cross a single cacheline boundary.
+  // scratch is last cacheline which intersects range.
+  const int kCacheLineSizeLog2 = WhichPowerOf2(CpuFeatures::cache_line_size());
+
+  DCHECK(size > 0 && size <= (size_t)(1 << kCacheLineSizeLog2));
+  addi(scratch, address, Operand(size - 1));
+  ClearRightImm(scratch, scratch, Operand(kCacheLineSizeLog2));
+  cmpl(scratch, address);
+  ble(&done);
+
+  dcbf(r0, scratch);
+  sync();
+  icbi(r0, scratch);
+  isync();
+
+  bind(&done);
+}
+
+
+void MacroAssembler::SetRelocatedValue(Register location, Register scratch,
+                                       Register new_value) {
+  lwz(scratch, MemOperand(location));
+
+#if V8_OOL_CONSTANT_POOL
+  if (emit_debug_code()) {
+// Check that the instruction sequence is a load from the constant pool
+#if V8_TARGET_ARCH_PPC64
+    And(scratch, scratch, Operand(kOpcodeMask | (0x1f * B16)));
+    Cmpi(scratch, Operand(ADDI), r0);
+    Check(eq, kTheInstructionShouldBeALi);
+    lwz(scratch, MemOperand(location, kInstrSize));
+#endif
+    ExtractBitMask(scratch, scratch, 0x1f * B16);
+    cmpi(scratch, Operand(kConstantPoolRegister.code()));
+    Check(eq, kTheInstructionToPatchShouldBeALoadFromConstantPool);
+    // Scratch was clobbered. Restore it.
+    lwz(scratch, MemOperand(location));
+  }
+  // Get the address of the constant and patch it.
+  andi(scratch, scratch, Operand(kImm16Mask));
+  StorePX(new_value, MemOperand(kConstantPoolRegister, scratch));
+#else
+  // This code assumes a FIXED_SEQUENCE for lis/ori
+
+  // At this point scratch is a lis instruction.
+  if (emit_debug_code()) {
+    And(scratch, scratch, Operand(kOpcodeMask | (0x1f * B16)));
+    Cmpi(scratch, Operand(ADDIS), r0);
+    Check(eq, kTheInstructionToPatchShouldBeALis);
+    lwz(scratch, MemOperand(location));
+  }
+
+// insert new high word into lis instruction
+#if V8_TARGET_ARCH_PPC64
+  srdi(ip, new_value, Operand(32));
+  rlwimi(scratch, ip, 16, 16, 31);
+#else
+  rlwimi(scratch, new_value, 16, 16, 31);
+#endif
+
+  stw(scratch, MemOperand(location));
+
+  lwz(scratch, MemOperand(location, kInstrSize));
+  // scratch is now ori.
+  if (emit_debug_code()) {
+    And(scratch, scratch, Operand(kOpcodeMask));
+    Cmpi(scratch, Operand(ORI), r0);
+    Check(eq, kTheInstructionShouldBeAnOri);
+    lwz(scratch, MemOperand(location, kInstrSize));
+  }
+
+// insert new low word into ori instruction
+#if V8_TARGET_ARCH_PPC64
+  rlwimi(scratch, ip, 0, 16, 31);
+#else
+  rlwimi(scratch, new_value, 0, 16, 31);
+#endif
+  stw(scratch, MemOperand(location, kInstrSize));
+
+#if V8_TARGET_ARCH_PPC64
+  if (emit_debug_code()) {
+    lwz(scratch, MemOperand(location, 2 * kInstrSize));
+    // scratch is now sldi.
+    And(scratch, scratch, Operand(kOpcodeMask | kExt5OpcodeMask));
+    Cmpi(scratch, Operand(EXT5 | RLDICR), r0);
+    Check(eq, kTheInstructionShouldBeASldi);
+  }
+
+  lwz(scratch, MemOperand(location, 3 * kInstrSize));
+  // scratch is now ori.
+  if (emit_debug_code()) {
+    And(scratch, scratch, Operand(kOpcodeMask));
+    Cmpi(scratch, Operand(ORIS), r0);
+    Check(eq, kTheInstructionShouldBeAnOris);
+    lwz(scratch, MemOperand(location, 3 * kInstrSize));
+  }
+
+  rlwimi(scratch, new_value, 16, 16, 31);
+  stw(scratch, MemOperand(location, 3 * kInstrSize));
+
+  lwz(scratch, MemOperand(location, 4 * kInstrSize));
+  // scratch is now ori.
+  if (emit_debug_code()) {
+    And(scratch, scratch, Operand(kOpcodeMask));
+    Cmpi(scratch, Operand(ORI), r0);
+    Check(eq, kTheInstructionShouldBeAnOri);
+    lwz(scratch, MemOperand(location, 4 * kInstrSize));
+  }
+  rlwimi(scratch, new_value, 0, 16, 31);
+  stw(scratch, MemOperand(location, 4 * kInstrSize));
+#endif
+
+// Update the I-cache so the new lis and addic can be executed.
+#if V8_TARGET_ARCH_PPC64
+  FlushICache(location, 5 * kInstrSize, scratch);
+#else
+  FlushICache(location, 2 * kInstrSize, scratch);
+#endif
+#endif
+}
+
+
+void MacroAssembler::GetRelocatedValue(Register location, Register result,
+                                       Register scratch) {
+  lwz(result, MemOperand(location));
+
+#if V8_OOL_CONSTANT_POOL
+  if (emit_debug_code()) {
+// Check that the instruction sequence is a load from the constant pool
+#if V8_TARGET_ARCH_PPC64
+    And(result, result, Operand(kOpcodeMask | (0x1f * B16)));
+    Cmpi(result, Operand(ADDI), r0);
+    Check(eq, kTheInstructionShouldBeALi);
+    lwz(result, MemOperand(location, kInstrSize));
+#endif
+    ExtractBitMask(result, result, 0x1f * B16);
+    cmpi(result, Operand(kConstantPoolRegister.code()));
+    Check(eq, kTheInstructionToPatchShouldBeALoadFromConstantPool);
+    lwz(result, MemOperand(location));
+  }
+  // Get the address of the constant and retrieve it.
+  andi(result, result, Operand(kImm16Mask));
+  LoadPX(result, MemOperand(kConstantPoolRegister, result));
+#else
+  // This code assumes a FIXED_SEQUENCE for lis/ori
+  if (emit_debug_code()) {
+    And(result, result, Operand(kOpcodeMask | (0x1f * B16)));
+    Cmpi(result, Operand(ADDIS), r0);
+    Check(eq, kTheInstructionShouldBeALis);
+    lwz(result, MemOperand(location));
+  }
+
+  // result now holds a lis instruction. Extract the immediate.
+  slwi(result, result, Operand(16));
+
+  lwz(scratch, MemOperand(location, kInstrSize));
+  if (emit_debug_code()) {
+    And(scratch, scratch, Operand(kOpcodeMask));
+    Cmpi(scratch, Operand(ORI), r0);
+    Check(eq, kTheInstructionShouldBeAnOri);
+    lwz(scratch, MemOperand(location, kInstrSize));
+  }
+  // Copy the low 16bits from ori instruction into result
+  rlwimi(result, scratch, 0, 16, 31);
+
+#if V8_TARGET_ARCH_PPC64
+  if (emit_debug_code()) {
+    lwz(scratch, MemOperand(location, 2 * kInstrSize));
+    // scratch is now sldi.
+    And(scratch, scratch, Operand(kOpcodeMask | kExt5OpcodeMask));
+    Cmpi(scratch, Operand(EXT5 | RLDICR), r0);
+    Check(eq, kTheInstructionShouldBeASldi);
+  }
+
+  lwz(scratch, MemOperand(location, 3 * kInstrSize));
+  // scratch is now ori.
+  if (emit_debug_code()) {
+    And(scratch, scratch, Operand(kOpcodeMask));
+    Cmpi(scratch, Operand(ORIS), r0);
+    Check(eq, kTheInstructionShouldBeAnOris);
+    lwz(scratch, MemOperand(location, 3 * kInstrSize));
+  }
+  sldi(result, result, Operand(16));
+  rldimi(result, scratch, 0, 48);
+
+  lwz(scratch, MemOperand(location, 4 * kInstrSize));
+  // scratch is now ori.
+  if (emit_debug_code()) {
+    And(scratch, scratch, Operand(kOpcodeMask));
+    Cmpi(scratch, Operand(ORI), r0);
+    Check(eq, kTheInstructionShouldBeAnOri);
+    lwz(scratch, MemOperand(location, 4 * kInstrSize));
+  }
+  sldi(result, result, Operand(16));
+  rldimi(result, scratch, 0, 48);
+#endif
+#endif
+}
+
+
+void MacroAssembler::CheckPageFlag(
+    Register object,
+    Register scratch,  // scratch may be same register as object
+    int mask, Condition cc, Label* condition_met) {
+  DCHECK(cc == ne || cc == eq);
+  ClearRightImm(scratch, object, Operand(kPageSizeBits));
+  LoadP(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
+
+  And(r0, scratch, Operand(mask), SetRC);
+
+  if (cc == ne) {
+    bne(condition_met, cr0);
+  }
+  if (cc == eq) {
+    beq(condition_met, cr0);
+  }
+}
+
+
+void MacroAssembler::CheckMapDeprecated(Handle<Map> map, Register scratch,
+                                        Label* if_deprecated) {
+  if (map->CanBeDeprecated()) {
+    mov(scratch, Operand(map));
+    lwz(scratch, FieldMemOperand(scratch, Map::kBitField3Offset));
+    ExtractBitMask(scratch, scratch, Map::Deprecated::kMask, SetRC);
+    bne(if_deprecated, cr0);
+  }
+}
+
+
+void MacroAssembler::JumpIfBlack(Register object, Register scratch0,
+                                 Register scratch1, Label* on_black) {
+  HasColor(object, scratch0, scratch1, on_black, 1, 0);  // kBlackBitPattern.
+  DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
+}
+
+
+void MacroAssembler::HasColor(Register object, Register bitmap_scratch,
+                              Register mask_scratch, Label* has_color,
+                              int first_bit, int second_bit) {
+  DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, no_reg));
+
+  GetMarkBits(object, bitmap_scratch, mask_scratch);
+
+  Label other_color, word_boundary;
+  lwz(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
+  // Test the first bit
+  and_(r0, ip, mask_scratch, SetRC);
+  b(first_bit == 1 ? eq : ne, &other_color, cr0);
+  // Shift left 1
+  // May need to load the next cell
+  slwi(mask_scratch, mask_scratch, Operand(1), SetRC);
+  beq(&word_boundary, cr0);
+  // Test the second bit
+  and_(r0, ip, mask_scratch, SetRC);
+  b(second_bit == 1 ? ne : eq, has_color, cr0);
+  b(&other_color);
+
+  bind(&word_boundary);
+  lwz(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize + kIntSize));
+  andi(r0, ip, Operand(1));
+  b(second_bit == 1 ? ne : eq, has_color, cr0);
+  bind(&other_color);
+}
+
+
+// Detect some, but not all, common pointer-free objects.  This is used by the
+// incremental write barrier which doesn't care about oddballs (they are always
+// marked black immediately so this code is not hit).
+void MacroAssembler::JumpIfDataObject(Register value, Register scratch,
+                                      Label* not_data_object) {
+  Label is_data_object;
+  LoadP(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
+  CompareRoot(scratch, Heap::kHeapNumberMapRootIndex);
+  beq(&is_data_object);
+  DCHECK(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1);
+  DCHECK(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
+  // If it's a string and it's not a cons string then it's an object containing
+  // no GC pointers.
+  lbz(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+  STATIC_ASSERT((kIsIndirectStringMask | kIsNotStringMask) == 0x81);
+  andi(scratch, scratch, Operand(kIsIndirectStringMask | kIsNotStringMask));
+  bne(not_data_object, cr0);
+  bind(&is_data_object);
+}
+
+
+void MacroAssembler::GetMarkBits(Register addr_reg, Register bitmap_reg,
+                                 Register mask_reg) {
+  DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, no_reg));
+  DCHECK((~Page::kPageAlignmentMask & 0xffff) == 0);
+  lis(r0, Operand((~Page::kPageAlignmentMask >> 16)));
+  and_(bitmap_reg, addr_reg, r0);
+  const int kLowBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2;
+  ExtractBitRange(mask_reg, addr_reg, kLowBits - 1, kPointerSizeLog2);
+  ExtractBitRange(ip, addr_reg, kPageSizeBits - 1, kLowBits);
+  ShiftLeftImm(ip, ip, Operand(Bitmap::kBytesPerCellLog2));
+  add(bitmap_reg, bitmap_reg, ip);
+  li(ip, Operand(1));
+  slw(mask_reg, ip, mask_reg);
+}
+
+
+void MacroAssembler::EnsureNotWhite(Register value, Register bitmap_scratch,
+                                    Register mask_scratch,
+                                    Register load_scratch,
+                                    Label* value_is_white_and_not_data) {
+  DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ip));
+  GetMarkBits(value, bitmap_scratch, mask_scratch);
+
+  // If the value is black or grey we don't need to do anything.
+  DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
+  DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
+  DCHECK(strcmp(Marking::kGreyBitPattern, "11") == 0);
+  DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
+
+  Label done;
+
+  // Since both black and grey have a 1 in the first position and white does
+  // not have a 1 there we only need to check one bit.
+  lwz(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
+  and_(r0, mask_scratch, load_scratch, SetRC);
+  bne(&done, cr0);
+
+  if (emit_debug_code()) {
+    // Check for impossible bit pattern.
+    Label ok;
+    // LSL may overflow, making the check conservative.
+    slwi(r0, mask_scratch, Operand(1));
+    and_(r0, load_scratch, r0, SetRC);
+    beq(&ok, cr0);
+    stop("Impossible marking bit pattern");
+    bind(&ok);
+  }
+
+  // Value is white.  We check whether it is data that doesn't need scanning.
+  // Currently only checks for HeapNumber and non-cons strings.
+  Register map = load_scratch;     // Holds map while checking type.
+  Register length = load_scratch;  // Holds length of object after testing type.
+  Label is_data_object, maybe_string_object, is_string_object, is_encoded;
+#if V8_TARGET_ARCH_PPC64
+  Label length_computed;
+#endif
+
+
+  // Check for heap-number
+  LoadP(map, FieldMemOperand(value, HeapObject::kMapOffset));
+  CompareRoot(map, Heap::kHeapNumberMapRootIndex);
+  bne(&maybe_string_object);
+  li(length, Operand(HeapNumber::kSize));
+  b(&is_data_object);
+  bind(&maybe_string_object);
+
+  // Check for strings.
+  DCHECK(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1);
+  DCHECK(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
+  // If it's a string and it's not a cons string then it's an object containing
+  // no GC pointers.
+  Register instance_type = load_scratch;
+  lbz(instance_type, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  andi(r0, instance_type, Operand(kIsIndirectStringMask | kIsNotStringMask));
+  bne(value_is_white_and_not_data, cr0);
+  // It's a non-indirect (non-cons and non-slice) string.
+  // If it's external, the length is just ExternalString::kSize.
+  // Otherwise it's String::kHeaderSize + string->length() * (1 or 2).
+  // External strings are the only ones with the kExternalStringTag bit
+  // set.
+  DCHECK_EQ(0, kSeqStringTag & kExternalStringTag);
+  DCHECK_EQ(0, kConsStringTag & kExternalStringTag);
+  andi(r0, instance_type, Operand(kExternalStringTag));
+  beq(&is_string_object, cr0);
+  li(length, Operand(ExternalString::kSize));
+  b(&is_data_object);
+  bind(&is_string_object);
+
+  // Sequential string, either Latin1 or UC16.
+  // For Latin1 (char-size of 1) we untag the smi to get the length.
+  // For UC16 (char-size of 2):
+  //   - (32-bit) we just leave the smi tag in place, thereby getting
+  //              the length multiplied by 2.
+  //   - (64-bit) we compute the offset in the 2-byte array
+  DCHECK(kOneByteStringTag == 4 && kStringEncodingMask == 4);
+  LoadP(ip, FieldMemOperand(value, String::kLengthOffset));
+  andi(r0, instance_type, Operand(kStringEncodingMask));
+  beq(&is_encoded, cr0);
+  SmiUntag(ip);
+#if V8_TARGET_ARCH_PPC64
+  b(&length_computed);
+#endif
+  bind(&is_encoded);
+#if V8_TARGET_ARCH_PPC64
+  SmiToShortArrayOffset(ip, ip);
+  bind(&length_computed);
+#else
+  DCHECK(kSmiShift == 1);
+#endif
+  addi(length, ip, Operand(SeqString::kHeaderSize + kObjectAlignmentMask));
+  li(r0, Operand(~kObjectAlignmentMask));
+  and_(length, length, r0);
+
+  bind(&is_data_object);
+  // Value is a data object, and it is white.  Mark it black.  Since we know
+  // that the object is white we can make it black by flipping one bit.
+  lwz(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
+  orx(ip, ip, mask_scratch);
+  stw(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
+
+  mov(ip, Operand(~Page::kPageAlignmentMask));
+  and_(bitmap_scratch, bitmap_scratch, ip);
+  lwz(ip, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
+  add(ip, ip, length);
+  stw(ip, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
+
+  bind(&done);
+}
+
+
+// Saturate a value into 8-bit unsigned integer
+//   if input_value < 0, output_value is 0
+//   if input_value > 255, output_value is 255
+//   otherwise output_value is the input_value
+void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) {
+  Label done, negative_label, overflow_label;
+  int satval = (1 << 8) - 1;
+
+  cmpi(input_reg, Operand::Zero());
+  blt(&negative_label);
+
+  cmpi(input_reg, Operand(satval));
+  bgt(&overflow_label);
+  if (!output_reg.is(input_reg)) {
+    mr(output_reg, input_reg);
+  }
+  b(&done);
+
+  bind(&negative_label);
+  li(output_reg, Operand::Zero());  // set to 0 if negative
+  b(&done);
+
+
+  bind(&overflow_label);  // set to satval if > satval
+  li(output_reg, Operand(satval));
+
+  bind(&done);
+}
+
+
+void MacroAssembler::SetRoundingMode(FPRoundingMode RN) { mtfsfi(7, RN); }
+
+
+void MacroAssembler::ResetRoundingMode() {
+  mtfsfi(7, kRoundToNearest);  // reset (default is kRoundToNearest)
+}
+
+
+void MacroAssembler::ClampDoubleToUint8(Register result_reg,
+                                        DoubleRegister input_reg,
+                                        DoubleRegister double_scratch) {
+  Label above_zero;
+  Label done;
+  Label in_bounds;
+
+  LoadDoubleLiteral(double_scratch, 0.0, result_reg);
+  fcmpu(input_reg, double_scratch);
+  bgt(&above_zero);
+
+  // Double value is less than zero, NaN or Inf, return 0.
+  LoadIntLiteral(result_reg, 0);
+  b(&done);
+
+  // Double value is >= 255, return 255.
+  bind(&above_zero);
+  LoadDoubleLiteral(double_scratch, 255.0, result_reg);
+  fcmpu(input_reg, double_scratch);
+  ble(&in_bounds);
+  LoadIntLiteral(result_reg, 255);
+  b(&done);
+
+  // In 0-255 range, round and truncate.
+  bind(&in_bounds);
+
+  // round to nearest (default rounding mode)
+  fctiw(double_scratch, input_reg);
+  MovDoubleLowToInt(result_reg, double_scratch);
+  bind(&done);
+}
+
+
+void MacroAssembler::LoadInstanceDescriptors(Register map,
+                                             Register descriptors) {
+  LoadP(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
+}
+
+
+void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
+  lwz(dst, FieldMemOperand(map, Map::kBitField3Offset));
+  DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
+}
+
+
+void MacroAssembler::EnumLength(Register dst, Register map) {
+  STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
+  lwz(dst, FieldMemOperand(map, Map::kBitField3Offset));
+  ExtractBitMask(dst, dst, Map::EnumLengthBits::kMask);
+  SmiTag(dst);
+}
+
+
+void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
+  Register empty_fixed_array_value = r9;
+  LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
+  Label next, start;
+  mr(r5, r3);
+
+  // Check if the enum length field is properly initialized, indicating that
+  // there is an enum cache.
+  LoadP(r4, FieldMemOperand(r5, HeapObject::kMapOffset));
+
+  EnumLength(r6, r4);
+  CmpSmiLiteral(r6, Smi::FromInt(kInvalidEnumCacheSentinel), r0);
+  beq(call_runtime);
+
+  b(&start);
+
+  bind(&next);
+  LoadP(r4, FieldMemOperand(r5, HeapObject::kMapOffset));
+
+  // For all objects but the receiver, check that the cache is empty.
+  EnumLength(r6, r4);
+  CmpSmiLiteral(r6, Smi::FromInt(0), r0);
+  bne(call_runtime);
+
+  bind(&start);
+
+  // Check that there are no elements. Register r5 contains the current JS
+  // object we've reached through the prototype chain.
+  Label no_elements;
+  LoadP(r5, FieldMemOperand(r5, JSObject::kElementsOffset));
+  cmp(r5, empty_fixed_array_value);
+  beq(&no_elements);
+
+  // Second chance, the object may be using the empty slow element dictionary.
+  CompareRoot(r5, Heap::kEmptySlowElementDictionaryRootIndex);
+  bne(call_runtime);
+
+  bind(&no_elements);
+  LoadP(r5, FieldMemOperand(r4, Map::kPrototypeOffset));
+  cmp(r5, null_value);
+  bne(&next);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// New MacroAssembler Interfaces added for PPC
+//
+////////////////////////////////////////////////////////////////////////////////
+void MacroAssembler::LoadIntLiteral(Register dst, int value) {
+  mov(dst, Operand(value));
+}
+
+
+void MacroAssembler::LoadSmiLiteral(Register dst, Smi* smi) {
+  mov(dst, Operand(smi));
+}
+
+
+void MacroAssembler::LoadDoubleLiteral(DoubleRegister result, double value,
+                                       Register scratch) {
+#if V8_OOL_CONSTANT_POOL
+  // TODO(mbrandy): enable extended constant pool usage for doubles.
+  //                See ARM commit e27ab337 for a reference.
+  if (is_ool_constant_pool_available() && !is_constant_pool_full()) {
+    RelocInfo rinfo(pc_, value);
+    ConstantPoolAddEntry(rinfo);
+#if V8_TARGET_ARCH_PPC64
+    // We use 2 instruction sequence here for consistency with mov.
+    li(scratch, Operand::Zero());
+    lfdx(result, MemOperand(kConstantPoolRegister, scratch));
+#else
+    lfd(result, MemOperand(kConstantPoolRegister, 0));
+#endif
+    return;
+  }
+#endif
+
+  // avoid gcc strict aliasing error using union cast
+  union {
+    double dval;
+#if V8_TARGET_ARCH_PPC64
+    intptr_t ival;
+#else
+    intptr_t ival[2];
+#endif
+  } litVal;
+
+  litVal.dval = value;
+
+#if V8_TARGET_ARCH_PPC64
+  if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
+    mov(scratch, Operand(litVal.ival));
+    mtfprd(result, scratch);
+    return;
+  }
+#endif
+
+  addi(sp, sp, Operand(-kDoubleSize));
+#if V8_TARGET_ARCH_PPC64
+  mov(scratch, Operand(litVal.ival));
+  std(scratch, MemOperand(sp));
+#else
+  LoadIntLiteral(scratch, litVal.ival[0]);
+  stw(scratch, MemOperand(sp, 0));
+  LoadIntLiteral(scratch, litVal.ival[1]);
+  stw(scratch, MemOperand(sp, 4));
+#endif
+  nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
+  lfd(result, MemOperand(sp, 0));
+  addi(sp, sp, Operand(kDoubleSize));
+}
+
+
+void MacroAssembler::MovIntToDouble(DoubleRegister dst, Register src,
+                                    Register scratch) {
+// sign-extend src to 64-bit
+#if V8_TARGET_ARCH_PPC64
+  if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
+    mtfprwa(dst, src);
+    return;
+  }
+#endif
+
+  DCHECK(!src.is(scratch));
+  subi(sp, sp, Operand(kDoubleSize));
+#if V8_TARGET_ARCH_PPC64
+  extsw(scratch, src);
+  std(scratch, MemOperand(sp, 0));
+#else
+  srawi(scratch, src, 31);
+  stw(scratch, MemOperand(sp, Register::kExponentOffset));
+  stw(src, MemOperand(sp, Register::kMantissaOffset));
+#endif
+  nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
+  lfd(dst, MemOperand(sp, 0));
+  addi(sp, sp, Operand(kDoubleSize));
+}
+
+
+void MacroAssembler::MovUnsignedIntToDouble(DoubleRegister dst, Register src,
+                                            Register scratch) {
+// zero-extend src to 64-bit
+#if V8_TARGET_ARCH_PPC64
+  if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
+    mtfprwz(dst, src);
+    return;
+  }
+#endif
+
+  DCHECK(!src.is(scratch));
+  subi(sp, sp, Operand(kDoubleSize));
+#if V8_TARGET_ARCH_PPC64
+  clrldi(scratch, src, Operand(32));
+  std(scratch, MemOperand(sp, 0));
+#else
+  li(scratch, Operand::Zero());
+  stw(scratch, MemOperand(sp, Register::kExponentOffset));
+  stw(src, MemOperand(sp, Register::kMantissaOffset));
+#endif
+  nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
+  lfd(dst, MemOperand(sp, 0));
+  addi(sp, sp, Operand(kDoubleSize));
+}
+
+
+void MacroAssembler::MovInt64ToDouble(DoubleRegister dst,
+#if !V8_TARGET_ARCH_PPC64
+                                      Register src_hi,
+#endif
+                                      Register src) {
+#if V8_TARGET_ARCH_PPC64
+  if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
+    mtfprd(dst, src);
+    return;
+  }
+#endif
+
+  subi(sp, sp, Operand(kDoubleSize));
+#if V8_TARGET_ARCH_PPC64
+  std(src, MemOperand(sp, 0));
+#else
+  stw(src_hi, MemOperand(sp, Register::kExponentOffset));
+  stw(src, MemOperand(sp, Register::kMantissaOffset));
+#endif
+  nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
+  lfd(dst, MemOperand(sp, 0));
+  addi(sp, sp, Operand(kDoubleSize));
+}
+
+
+#if V8_TARGET_ARCH_PPC64
+void MacroAssembler::MovInt64ComponentsToDouble(DoubleRegister dst,
+                                                Register src_hi,
+                                                Register src_lo,
+                                                Register scratch) {
+  if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
+    sldi(scratch, src_hi, Operand(32));
+    rldimi(scratch, src_lo, 0, 32);
+    mtfprd(dst, scratch);
+    return;
+  }
+
+  subi(sp, sp, Operand(kDoubleSize));
+  stw(src_hi, MemOperand(sp, Register::kExponentOffset));
+  stw(src_lo, MemOperand(sp, Register::kMantissaOffset));
+  nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
+  lfd(dst, MemOperand(sp));
+  addi(sp, sp, Operand(kDoubleSize));
+}
+#endif
+
+
+void MacroAssembler::MovDoubleLowToInt(Register dst, DoubleRegister src) {
+#if V8_TARGET_ARCH_PPC64
+  if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
+    mffprwz(dst, src);
+    return;
+  }
+#endif
+
+  subi(sp, sp, Operand(kDoubleSize));
+  stfd(src, MemOperand(sp));
+  nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
+  lwz(dst, MemOperand(sp, Register::kMantissaOffset));
+  addi(sp, sp, Operand(kDoubleSize));
+}
+
+
+void MacroAssembler::MovDoubleHighToInt(Register dst, DoubleRegister src) {
+#if V8_TARGET_ARCH_PPC64
+  if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
+    mffprd(dst, src);
+    srdi(dst, dst, Operand(32));
+    return;
+  }
+#endif
+
+  subi(sp, sp, Operand(kDoubleSize));
+  stfd(src, MemOperand(sp));
+  nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
+  lwz(dst, MemOperand(sp, Register::kExponentOffset));
+  addi(sp, sp, Operand(kDoubleSize));
+}
+
+
+void MacroAssembler::MovDoubleToInt64(
+#if !V8_TARGET_ARCH_PPC64
+    Register dst_hi,
+#endif
+    Register dst, DoubleRegister src) {
+#if V8_TARGET_ARCH_PPC64
+  if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
+    mffprd(dst, src);
+    return;
+  }
+#endif
+
+  subi(sp, sp, Operand(kDoubleSize));
+  stfd(src, MemOperand(sp));
+  nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
+#if V8_TARGET_ARCH_PPC64
+  ld(dst, MemOperand(sp, 0));
+#else
+  lwz(dst_hi, MemOperand(sp, Register::kExponentOffset));
+  lwz(dst, MemOperand(sp, Register::kMantissaOffset));
+#endif
+  addi(sp, sp, Operand(kDoubleSize));
+}
+
+
+void MacroAssembler::Add(Register dst, Register src, intptr_t value,
+                         Register scratch) {
+  if (is_int16(value)) {
+    addi(dst, src, Operand(value));
+  } else {
+    mov(scratch, Operand(value));
+    add(dst, src, scratch);
+  }
+}
+
+
+void MacroAssembler::Cmpi(Register src1, const Operand& src2, Register scratch,
+                          CRegister cr) {
+  intptr_t value = src2.immediate();
+  if (is_int16(value)) {
+    cmpi(src1, src2, cr);
+  } else {
+    mov(scratch, src2);
+    cmp(src1, scratch, cr);
+  }
+}
+
+
+void MacroAssembler::Cmpli(Register src1, const Operand& src2, Register scratch,
+                           CRegister cr) {
+  intptr_t value = src2.immediate();
+  if (is_uint16(value)) {
+    cmpli(src1, src2, cr);
+  } else {
+    mov(scratch, src2);
+    cmpl(src1, scratch, cr);
+  }
+}
+
+
+void MacroAssembler::Cmpwi(Register src1, const Operand& src2, Register scratch,
+                           CRegister cr) {
+  intptr_t value = src2.immediate();
+  if (is_int16(value)) {
+    cmpwi(src1, src2, cr);
+  } else {
+    mov(scratch, src2);
+    cmpw(src1, scratch, cr);
+  }
+}
+
+
+void MacroAssembler::Cmplwi(Register src1, const Operand& src2,
+                            Register scratch, CRegister cr) {
+  intptr_t value = src2.immediate();
+  if (is_uint16(value)) {
+    cmplwi(src1, src2, cr);
+  } else {
+    mov(scratch, src2);
+    cmplw(src1, scratch, cr);
+  }
+}
+
+
+void MacroAssembler::And(Register ra, Register rs, const Operand& rb,
+                         RCBit rc) {
+  if (rb.is_reg()) {
+    and_(ra, rs, rb.rm(), rc);
+  } else {
+    if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == SetRC) {
+      andi(ra, rs, rb);
+    } else {
+      // mov handles the relocation.
+      DCHECK(!rs.is(r0));
+      mov(r0, rb);
+      and_(ra, rs, r0, rc);
+    }
+  }
+}
+
+
+void MacroAssembler::Or(Register ra, Register rs, const Operand& rb, RCBit rc) {
+  if (rb.is_reg()) {
+    orx(ra, rs, rb.rm(), rc);
+  } else {
+    if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == LeaveRC) {
+      ori(ra, rs, rb);
+    } else {
+      // mov handles the relocation.
+      DCHECK(!rs.is(r0));
+      mov(r0, rb);
+      orx(ra, rs, r0, rc);
+    }
+  }
+}
+
+
+void MacroAssembler::Xor(Register ra, Register rs, const Operand& rb,
+                         RCBit rc) {
+  if (rb.is_reg()) {
+    xor_(ra, rs, rb.rm(), rc);
+  } else {
+    if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == LeaveRC) {
+      xori(ra, rs, rb);
+    } else {
+      // mov handles the relocation.
+      DCHECK(!rs.is(r0));
+      mov(r0, rb);
+      xor_(ra, rs, r0, rc);
+    }
+  }
+}
+
+
+void MacroAssembler::CmpSmiLiteral(Register src1, Smi* smi, Register scratch,
+                                   CRegister cr) {
+#if V8_TARGET_ARCH_PPC64
+  LoadSmiLiteral(scratch, smi);
+  cmp(src1, scratch, cr);
+#else
+  Cmpi(src1, Operand(smi), scratch, cr);
+#endif
+}
+
+
+void MacroAssembler::CmplSmiLiteral(Register src1, Smi* smi, Register scratch,
+                                    CRegister cr) {
+#if V8_TARGET_ARCH_PPC64
+  LoadSmiLiteral(scratch, smi);
+  cmpl(src1, scratch, cr);
+#else
+  Cmpli(src1, Operand(smi), scratch, cr);
+#endif
+}
+
+
+void MacroAssembler::AddSmiLiteral(Register dst, Register src, Smi* smi,
+                                   Register scratch) {
+#if V8_TARGET_ARCH_PPC64
+  LoadSmiLiteral(scratch, smi);
+  add(dst, src, scratch);
+#else
+  Add(dst, src, reinterpret_cast<intptr_t>(smi), scratch);
+#endif
+}
+
+
+void MacroAssembler::SubSmiLiteral(Register dst, Register src, Smi* smi,
+                                   Register scratch) {
+#if V8_TARGET_ARCH_PPC64
+  LoadSmiLiteral(scratch, smi);
+  sub(dst, src, scratch);
+#else
+  Add(dst, src, -(reinterpret_cast<intptr_t>(smi)), scratch);
+#endif
+}
+
+
+void MacroAssembler::AndSmiLiteral(Register dst, Register src, Smi* smi,
+                                   Register scratch, RCBit rc) {
+#if V8_TARGET_ARCH_PPC64
+  LoadSmiLiteral(scratch, smi);
+  and_(dst, src, scratch, rc);
+#else
+  And(dst, src, Operand(smi), rc);
+#endif
+}
+
+
+// Load a "pointer" sized value from the memory location
+void MacroAssembler::LoadP(Register dst, const MemOperand& mem,
+                           Register scratch) {
+  int offset = mem.offset();
+
+  if (!scratch.is(no_reg) && !is_int16(offset)) {
+    /* cannot use d-form */
+    LoadIntLiteral(scratch, offset);
+#if V8_TARGET_ARCH_PPC64
+    ldx(dst, MemOperand(mem.ra(), scratch));
+#else
+    lwzx(dst, MemOperand(mem.ra(), scratch));
+#endif
+  } else {
+#if V8_TARGET_ARCH_PPC64
+    int misaligned = (offset & 3);
+    if (misaligned) {
+      // adjust base to conform to offset alignment requirements
+      // Todo: enhance to use scratch if dst is unsuitable
+      DCHECK(!dst.is(r0));
+      addi(dst, mem.ra(), Operand((offset & 3) - 4));
+      ld(dst, MemOperand(dst, (offset & ~3) + 4));
+    } else {
+      ld(dst, mem);
+    }
+#else
+    lwz(dst, mem);
+#endif
+  }
+}
+
+
+// Store a "pointer" sized value to the memory location
+void MacroAssembler::StoreP(Register src, const MemOperand& mem,
+                            Register scratch) {
+  int offset = mem.offset();
+
+  if (!scratch.is(no_reg) && !is_int16(offset)) {
+    /* cannot use d-form */
+    LoadIntLiteral(scratch, offset);
+#if V8_TARGET_ARCH_PPC64
+    stdx(src, MemOperand(mem.ra(), scratch));
+#else
+    stwx(src, MemOperand(mem.ra(), scratch));
+#endif
+  } else {
+#if V8_TARGET_ARCH_PPC64
+    int misaligned = (offset & 3);
+    if (misaligned) {
+      // adjust base to conform to offset alignment requirements
+      // a suitable scratch is required here
+      DCHECK(!scratch.is(no_reg));
+      if (scratch.is(r0)) {
+        LoadIntLiteral(scratch, offset);
+        stdx(src, MemOperand(mem.ra(), scratch));
+      } else {
+        addi(scratch, mem.ra(), Operand((offset & 3) - 4));
+        std(src, MemOperand(scratch, (offset & ~3) + 4));
+      }
+    } else {
+      std(src, mem);
+    }
+#else
+    stw(src, mem);
+#endif
+  }
+}
+
+void MacroAssembler::LoadWordArith(Register dst, const MemOperand& mem,
+                                   Register scratch) {
+  int offset = mem.offset();
+
+  if (!scratch.is(no_reg) && !is_int16(offset)) {
+    /* cannot use d-form */
+    LoadIntLiteral(scratch, offset);
+#if V8_TARGET_ARCH_PPC64
+    // lwax(dst, MemOperand(mem.ra(), scratch));
+    DCHECK(0);  // lwax not yet implemented
+#else
+    lwzx(dst, MemOperand(mem.ra(), scratch));
+#endif
+  } else {
+#if V8_TARGET_ARCH_PPC64
+    int misaligned = (offset & 3);
+    if (misaligned) {
+      // adjust base to conform to offset alignment requirements
+      // Todo: enhance to use scratch if dst is unsuitable
+      DCHECK(!dst.is(r0));
+      addi(dst, mem.ra(), Operand((offset & 3) - 4));
+      lwa(dst, MemOperand(dst, (offset & ~3) + 4));
+    } else {
+      lwa(dst, mem);
+    }
+#else
+    lwz(dst, mem);
+#endif
+  }
+}
+
+
+// Variable length depending on whether offset fits into immediate field
+// MemOperand currently only supports d-form
+void MacroAssembler::LoadWord(Register dst, const MemOperand& mem,
+                              Register scratch) {
+  Register base = mem.ra();
+  int offset = mem.offset();
+
+  if (!is_int16(offset)) {
+    LoadIntLiteral(scratch, offset);
+    lwzx(dst, MemOperand(base, scratch));
+  } else {
+    lwz(dst, mem);
+  }
+}
+
+
+// Variable length depending on whether offset fits into immediate field
+// MemOperand current only supports d-form
+void MacroAssembler::StoreWord(Register src, const MemOperand& mem,
+                               Register scratch) {
+  Register base = mem.ra();
+  int offset = mem.offset();
+
+  if (!is_int16(offset)) {
+    LoadIntLiteral(scratch, offset);
+    stwx(src, MemOperand(base, scratch));
+  } else {
+    stw(src, mem);
+  }
+}
+
+
+// Variable length depending on whether offset fits into immediate field
+// MemOperand currently only supports d-form
+void MacroAssembler::LoadHalfWord(Register dst, const MemOperand& mem,
+                                  Register scratch) {
+  Register base = mem.ra();
+  int offset = mem.offset();
+
+  if (!is_int16(offset)) {
+    LoadIntLiteral(scratch, offset);
+    lhzx(dst, MemOperand(base, scratch));
+  } else {
+    lhz(dst, mem);
+  }
+}
+
+
+// Variable length depending on whether offset fits into immediate field
+// MemOperand current only supports d-form
+void MacroAssembler::StoreHalfWord(Register src, const MemOperand& mem,
+                                   Register scratch) {
+  Register base = mem.ra();
+  int offset = mem.offset();
+
+  if (!is_int16(offset)) {
+    LoadIntLiteral(scratch, offset);
+    sthx(src, MemOperand(base, scratch));
+  } else {
+    sth(src, mem);
+  }
+}
+
+
+// Variable length depending on whether offset fits into immediate field
+// MemOperand currently only supports d-form
+void MacroAssembler::LoadByte(Register dst, const MemOperand& mem,
+                              Register scratch) {
+  Register base = mem.ra();
+  int offset = mem.offset();
+
+  if (!is_int16(offset)) {
+    LoadIntLiteral(scratch, offset);
+    lbzx(dst, MemOperand(base, scratch));
+  } else {
+    lbz(dst, mem);
+  }
+}
+
+
+// Variable length depending on whether offset fits into immediate field
+// MemOperand current only supports d-form
+void MacroAssembler::StoreByte(Register src, const MemOperand& mem,
+                               Register scratch) {
+  Register base = mem.ra();
+  int offset = mem.offset();
+
+  if (!is_int16(offset)) {
+    LoadIntLiteral(scratch, offset);
+    stbx(src, MemOperand(base, scratch));
+  } else {
+    stb(src, mem);
+  }
+}
+
+
+void MacroAssembler::LoadRepresentation(Register dst, const MemOperand& mem,
+                                        Representation r, Register scratch) {
+  DCHECK(!r.IsDouble());
+  if (r.IsInteger8()) {
+    LoadByte(dst, mem, scratch);
+    extsb(dst, dst);
+  } else if (r.IsUInteger8()) {
+    LoadByte(dst, mem, scratch);
+  } else if (r.IsInteger16()) {
+    LoadHalfWord(dst, mem, scratch);
+    extsh(dst, dst);
+  } else if (r.IsUInteger16()) {
+    LoadHalfWord(dst, mem, scratch);
+#if V8_TARGET_ARCH_PPC64
+  } else if (r.IsInteger32()) {
+    LoadWord(dst, mem, scratch);
+#endif
+  } else {
+    LoadP(dst, mem, scratch);
+  }
+}
+
+
+void MacroAssembler::StoreRepresentation(Register src, const MemOperand& mem,
+                                         Representation r, Register scratch) {
+  DCHECK(!r.IsDouble());
+  if (r.IsInteger8() || r.IsUInteger8()) {
+    StoreByte(src, mem, scratch);
+  } else if (r.IsInteger16() || r.IsUInteger16()) {
+    StoreHalfWord(src, mem, scratch);
+#if V8_TARGET_ARCH_PPC64
+  } else if (r.IsInteger32()) {
+    StoreWord(src, mem, scratch);
+#endif
+  } else {
+    if (r.IsHeapObject()) {
+      AssertNotSmi(src);
+    } else if (r.IsSmi()) {
+      AssertSmi(src);
+    }
+    StoreP(src, mem, scratch);
+  }
+}
+
+
+void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver_reg,
+                                                     Register scratch_reg,
+                                                     Label* no_memento_found) {
+  ExternalReference new_space_start =
+      ExternalReference::new_space_start(isolate());
+  ExternalReference new_space_allocation_top =
+      ExternalReference::new_space_allocation_top_address(isolate());
+  addi(scratch_reg, receiver_reg,
+       Operand(JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag));
+  Cmpi(scratch_reg, Operand(new_space_start), r0);
+  blt(no_memento_found);
+  mov(ip, Operand(new_space_allocation_top));
+  LoadP(ip, MemOperand(ip));
+  cmp(scratch_reg, ip);
+  bgt(no_memento_found);
+  LoadP(scratch_reg, MemOperand(scratch_reg, -AllocationMemento::kSize));
+  Cmpi(scratch_reg, Operand(isolate()->factory()->allocation_memento_map()),
+       r0);
+}
+
+
+Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2, Register reg3,
+                                   Register reg4, Register reg5,
+                                   Register reg6) {
+  RegList regs = 0;
+  if (reg1.is_valid()) regs |= reg1.bit();
+  if (reg2.is_valid()) regs |= reg2.bit();
+  if (reg3.is_valid()) regs |= reg3.bit();
+  if (reg4.is_valid()) regs |= reg4.bit();
+  if (reg5.is_valid()) regs |= reg5.bit();
+  if (reg6.is_valid()) regs |= reg6.bit();
+
+  for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
+    Register candidate = Register::FromAllocationIndex(i);
+    if (regs & candidate.bit()) continue;
+    return candidate;
+  }
+  UNREACHABLE();
+  return no_reg;
+}
+
+
+void MacroAssembler::JumpIfDictionaryInPrototypeChain(Register object,
+                                                      Register scratch0,
+                                                      Register scratch1,
+                                                      Label* found) {
+  DCHECK(!scratch1.is(scratch0));
+  Factory* factory = isolate()->factory();
+  Register current = scratch0;
+  Label loop_again;
+
+  // scratch contained elements pointer.
+  mr(current, object);
+
+  // Loop based on the map going up the prototype chain.
+  bind(&loop_again);
+  LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset));
+  lbz(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
+  DecodeField<Map::ElementsKindBits>(scratch1);
+  cmpi(scratch1, Operand(DICTIONARY_ELEMENTS));
+  beq(found);
+  LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset));
+  Cmpi(current, Operand(factory->null_value()), r0);
+  bne(&loop_again);
+}
+
+
+#ifdef DEBUG
+bool AreAliased(Register reg1, Register reg2, Register reg3, Register reg4,
+                Register reg5, Register reg6, Register reg7, Register reg8) {
+  int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + reg3.is_valid() +
+                        reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
+                        reg7.is_valid() + reg8.is_valid();
+
+  RegList regs = 0;
+  if (reg1.is_valid()) regs |= reg1.bit();
+  if (reg2.is_valid()) regs |= reg2.bit();
+  if (reg3.is_valid()) regs |= reg3.bit();
+  if (reg4.is_valid()) regs |= reg4.bit();
+  if (reg5.is_valid()) regs |= reg5.bit();
+  if (reg6.is_valid()) regs |= reg6.bit();
+  if (reg7.is_valid()) regs |= reg7.bit();
+  if (reg8.is_valid()) regs |= reg8.bit();
+  int n_of_non_aliasing_regs = NumRegs(regs);
+
+  return n_of_valid_regs != n_of_non_aliasing_regs;
+}
+#endif
+
+
+CodePatcher::CodePatcher(byte* address, int instructions,
+                         FlushICache flush_cache)
+    : address_(address),
+      size_(instructions * Assembler::kInstrSize),
+      masm_(NULL, address, size_ + Assembler::kGap),
+      flush_cache_(flush_cache) {
+  // Create a new macro assembler pointing to the address of the code to patch.
+  // The size is adjusted with kGap on order for the assembler to generate size
+  // bytes of instructions without failing with buffer size constraints.
+  DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
+}
+
+
+CodePatcher::~CodePatcher() {
+  // Indicate that code has changed.
+  if (flush_cache_ == FLUSH) {
+    CpuFeatures::FlushICache(address_, size_);
+  }
+
+  // Check that the code was patched as expected.
+  DCHECK(masm_.pc_ == address_ + size_);
+  DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
+}
+
+
+void CodePatcher::Emit(Instr instr) { masm()->emit(instr); }
+
+
+void CodePatcher::EmitCondition(Condition cond) {
+  Instr instr = Assembler::instr_at(masm_.pc_);
+  switch (cond) {
+    case eq:
+      instr = (instr & ~kCondMask) | BT;
+      break;
+    case ne:
+      instr = (instr & ~kCondMask) | BF;
+      break;
+    default:
+      UNIMPLEMENTED();
+  }
+  masm_.emit(instr);
+}
+
+
+void MacroAssembler::TruncatingDiv(Register result, Register dividend,
+                                   int32_t divisor) {
+  DCHECK(!dividend.is(result));
+  DCHECK(!dividend.is(r0));
+  DCHECK(!result.is(r0));
+  base::MagicNumbersForDivision<uint32_t> mag =
+      base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
+  mov(r0, Operand(mag.multiplier));
+  mulhw(result, dividend, r0);
+  bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
+  if (divisor > 0 && neg) {
+    add(result, result, dividend);
+  }
+  if (divisor < 0 && !neg && mag.multiplier > 0) {
+    sub(result, result, dividend);
+  }
+  if (mag.shift > 0) srawi(result, result, mag.shift);
+  ExtractBit(r0, dividend, 31);
+  add(result, result, r0);
+}
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ppc/macro-assembler-ppc.h b/src/ppc/macro-assembler-ppc.h
new file mode 100644
index 0000000..8f1aeab
--- /dev/null
+++ b/src/ppc/macro-assembler-ppc.h
@@ -0,0 +1,1554 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PPC_MACRO_ASSEMBLER_PPC_H_
+#define V8_PPC_MACRO_ASSEMBLER_PPC_H_
+
+#include "src/assembler.h"
+#include "src/bailout-reason.h"
+#include "src/frames.h"
+#include "src/globals.h"
+
+namespace v8 {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+// Static helper functions
+
+// Generate a MemOperand for loading a field from an object.
+inline MemOperand FieldMemOperand(Register object, int offset) {
+  return MemOperand(object, offset - kHeapObjectTag);
+}
+
+
+// Flags used for AllocateHeapNumber
+enum TaggingMode {
+  // Tag the result.
+  TAG_RESULT,
+  // Don't tag
+  DONT_TAG_RESULT
+};
+
+
+enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
+enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
+enum PointersToHereCheck {
+  kPointersToHereMaybeInteresting,
+  kPointersToHereAreAlwaysInteresting
+};
+enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved };
+
+
+Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2 = no_reg,
+                                   Register reg3 = no_reg,
+                                   Register reg4 = no_reg,
+                                   Register reg5 = no_reg,
+                                   Register reg6 = no_reg);
+
+
+#ifdef DEBUG
+bool AreAliased(Register reg1, Register reg2, Register reg3 = no_reg,
+                Register reg4 = no_reg, Register reg5 = no_reg,
+                Register reg6 = no_reg, Register reg7 = no_reg,
+                Register reg8 = no_reg);
+#endif
+
+// These exist to provide portability between 32 and 64bit
+#if V8_TARGET_ARCH_PPC64
+#define LoadPU ldu
+#define LoadPX ldx
+#define LoadPUX ldux
+#define StorePU stdu
+#define StorePX stdx
+#define StorePUX stdux
+#define ShiftLeftImm sldi
+#define ShiftRightImm srdi
+#define ClearLeftImm clrldi
+#define ClearRightImm clrrdi
+#define ShiftRightArithImm sradi
+#define ShiftLeft_ sld
+#define ShiftRight_ srd
+#define ShiftRightArith srad
+#define Mul mulld
+#define Div divd
+#else
+#define LoadPU lwzu
+#define LoadPX lwzx
+#define LoadPUX lwzux
+#define StorePU stwu
+#define StorePX stwx
+#define StorePUX stwux
+#define ShiftLeftImm slwi
+#define ShiftRightImm srwi
+#define ClearLeftImm clrlwi
+#define ClearRightImm clrrwi
+#define ShiftRightArithImm srawi
+#define ShiftLeft_ slw
+#define ShiftRight_ srw
+#define ShiftRightArith sraw
+#define Mul mullw
+#define Div divw
+#endif
+
+
+// MacroAssembler implements a collection of frequently used macros.
+class MacroAssembler : public Assembler {
+ public:
+  // The isolate parameter can be NULL if the macro assembler should
+  // not use isolate-dependent functionality. In this case, it's the
+  // responsibility of the caller to never invoke such function on the
+  // macro assembler.
+  MacroAssembler(Isolate* isolate, void* buffer, int size);
+
+
+  // Returns the size of a call in instructions. Note, the value returned is
+  // only valid as long as no entries are added to the constant pool between
+  // checking the call size and emitting the actual call.
+  static int CallSize(Register target);
+  int CallSize(Address target, RelocInfo::Mode rmode, Condition cond = al);
+  static int CallSizeNotPredictableCodeSize(Address target,
+                                            RelocInfo::Mode rmode,
+                                            Condition cond = al);
+
+  // Jump, Call, and Ret pseudo instructions implementing inter-working.
+  void Jump(Register target);
+  void JumpToJSEntry(Register target);
+  void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al,
+            CRegister cr = cr7);
+  void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
+  void Call(Register target);
+  void CallJSEntry(Register target);
+  void Call(Address target, RelocInfo::Mode rmode, Condition cond = al);
+  int CallSize(Handle<Code> code,
+               RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
+               TypeFeedbackId ast_id = TypeFeedbackId::None(),
+               Condition cond = al);
+  void Call(Handle<Code> code, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
+            TypeFeedbackId ast_id = TypeFeedbackId::None(),
+            Condition cond = al);
+  void Ret(Condition cond = al);
+
+  // Emit code to discard a non-negative number of pointer-sized elements
+  // from the stack, clobbering only the sp register.
+  void Drop(int count, Condition cond = al);
+
+  void Ret(int drop, Condition cond = al);
+
+  void Call(Label* target);
+
+  // Emit call to the code we are currently generating.
+  void CallSelf() {
+    Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
+    Call(self, RelocInfo::CODE_TARGET);
+  }
+
+  // Register move. May do nothing if the registers are identical.
+  void Move(Register dst, Handle<Object> value);
+  void Move(Register dst, Register src, Condition cond = al);
+  void Move(DoubleRegister dst, DoubleRegister src);
+
+  void MultiPush(RegList regs);
+  void MultiPop(RegList regs);
+
+  // Load an object from the root table.
+  void LoadRoot(Register destination, Heap::RootListIndex index,
+                Condition cond = al);
+  // Store an object to the root table.
+  void StoreRoot(Register source, Heap::RootListIndex index,
+                 Condition cond = al);
+
+  // ---------------------------------------------------------------------------
+  // GC Support
+
+  void IncrementalMarkingRecordWriteHelper(Register object, Register value,
+                                           Register address);
+
+  enum RememberedSetFinalAction { kReturnAtEnd, kFallThroughAtEnd };
+
+  // Record in the remembered set the fact that we have a pointer to new space
+  // at the address pointed to by the addr register.  Only works if addr is not
+  // in new space.
+  void RememberedSetHelper(Register object,  // Used for debug code.
+                           Register addr, Register scratch,
+                           SaveFPRegsMode save_fp,
+                           RememberedSetFinalAction and_then);
+
+  void CheckPageFlag(Register object, Register scratch, int mask, Condition cc,
+                     Label* condition_met);
+
+  void CheckMapDeprecated(Handle<Map> map, Register scratch,
+                          Label* if_deprecated);
+
+  // Check if object is in new space.  Jumps if the object is not in new space.
+  // The register scratch can be object itself, but scratch will be clobbered.
+  void JumpIfNotInNewSpace(Register object, Register scratch, Label* branch) {
+    InNewSpace(object, scratch, ne, branch);
+  }
+
+  // Check if object is in new space.  Jumps if the object is in new space.
+  // The register scratch can be object itself, but it will be clobbered.
+  void JumpIfInNewSpace(Register object, Register scratch, Label* branch) {
+    InNewSpace(object, scratch, eq, branch);
+  }
+
+  // Check if an object has a given incremental marking color.
+  void HasColor(Register object, Register scratch0, Register scratch1,
+                Label* has_color, int first_bit, int second_bit);
+
+  void JumpIfBlack(Register object, Register scratch0, Register scratch1,
+                   Label* on_black);
+
+  // Checks the color of an object.  If the object is already grey or black
+  // then we just fall through, since it is already live.  If it is white and
+  // we can determine that it doesn't need to be scanned, then we just mark it
+  // black and fall through.  For the rest we jump to the label so the
+  // incremental marker can fix its assumptions.
+  void EnsureNotWhite(Register object, Register scratch1, Register scratch2,
+                      Register scratch3, Label* object_is_white_and_not_data);
+
+  // Detects conservatively whether an object is data-only, i.e. it does need to
+  // be scanned by the garbage collector.
+  void JumpIfDataObject(Register value, Register scratch,
+                        Label* not_data_object);
+
+  // Notify the garbage collector that we wrote a pointer into an object.
+  // |object| is the object being stored into, |value| is the object being
+  // stored.  value and scratch registers are clobbered by the operation.
+  // The offset is the offset from the start of the object, not the offset from
+  // the tagged HeapObject pointer.  For use with FieldOperand(reg, off).
+  void RecordWriteField(
+      Register object, int offset, Register value, Register scratch,
+      LinkRegisterStatus lr_status, SaveFPRegsMode save_fp,
+      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
+      SmiCheck smi_check = INLINE_SMI_CHECK,
+      PointersToHereCheck pointers_to_here_check_for_value =
+          kPointersToHereMaybeInteresting);
+
+  // As above, but the offset has the tag presubtracted.  For use with
+  // MemOperand(reg, off).
+  inline void RecordWriteContextSlot(
+      Register context, int offset, Register value, Register scratch,
+      LinkRegisterStatus lr_status, SaveFPRegsMode save_fp,
+      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
+      SmiCheck smi_check = INLINE_SMI_CHECK,
+      PointersToHereCheck pointers_to_here_check_for_value =
+          kPointersToHereMaybeInteresting) {
+    RecordWriteField(context, offset + kHeapObjectTag, value, scratch,
+                     lr_status, save_fp, remembered_set_action, smi_check,
+                     pointers_to_here_check_for_value);
+  }
+
+  void RecordWriteForMap(Register object, Register map, Register dst,
+                         LinkRegisterStatus lr_status, SaveFPRegsMode save_fp);
+
+  // For a given |object| notify the garbage collector that the slot |address|
+  // has been written.  |value| is the object being stored. The value and
+  // address registers are clobbered by the operation.
+  void RecordWrite(
+      Register object, Register address, Register value,
+      LinkRegisterStatus lr_status, SaveFPRegsMode save_fp,
+      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
+      SmiCheck smi_check = INLINE_SMI_CHECK,
+      PointersToHereCheck pointers_to_here_check_for_value =
+          kPointersToHereMaybeInteresting);
+
+  void Push(Register src) { push(src); }
+
+  // Push a handle.
+  void Push(Handle<Object> handle);
+  void Push(Smi* smi) { Push(Handle<Smi>(smi, isolate())); }
+
+  // Push two registers.  Pushes leftmost register first (to highest address).
+  void Push(Register src1, Register src2) {
+    StorePU(src2, MemOperand(sp, -2 * kPointerSize));
+    StoreP(src1, MemOperand(sp, kPointerSize));
+  }
+
+  // Push three registers.  Pushes leftmost register first (to highest address).
+  void Push(Register src1, Register src2, Register src3) {
+    StorePU(src3, MemOperand(sp, -3 * kPointerSize));
+    StoreP(src2, MemOperand(sp, kPointerSize));
+    StoreP(src1, MemOperand(sp, 2 * kPointerSize));
+  }
+
+  // Push four registers.  Pushes leftmost register first (to highest address).
+  void Push(Register src1, Register src2, Register src3, Register src4) {
+    StorePU(src4, MemOperand(sp, -4 * kPointerSize));
+    StoreP(src3, MemOperand(sp, kPointerSize));
+    StoreP(src2, MemOperand(sp, 2 * kPointerSize));
+    StoreP(src1, MemOperand(sp, 3 * kPointerSize));
+  }
+
+  // Push five registers.  Pushes leftmost register first (to highest address).
+  void Push(Register src1, Register src2, Register src3, Register src4,
+            Register src5) {
+    StorePU(src5, MemOperand(sp, -5 * kPointerSize));
+    StoreP(src4, MemOperand(sp, kPointerSize));
+    StoreP(src3, MemOperand(sp, 2 * kPointerSize));
+    StoreP(src2, MemOperand(sp, 3 * kPointerSize));
+    StoreP(src1, MemOperand(sp, 4 * kPointerSize));
+  }
+
+  void Pop(Register dst) { pop(dst); }
+
+  // Pop two registers. Pops rightmost register first (from lower address).
+  void Pop(Register src1, Register src2) {
+    LoadP(src2, MemOperand(sp, 0));
+    LoadP(src1, MemOperand(sp, kPointerSize));
+    addi(sp, sp, Operand(2 * kPointerSize));
+  }
+
+  // Pop three registers.  Pops rightmost register first (from lower address).
+  void Pop(Register src1, Register src2, Register src3) {
+    LoadP(src3, MemOperand(sp, 0));
+    LoadP(src2, MemOperand(sp, kPointerSize));
+    LoadP(src1, MemOperand(sp, 2 * kPointerSize));
+    addi(sp, sp, Operand(3 * kPointerSize));
+  }
+
+  // Pop four registers.  Pops rightmost register first (from lower address).
+  void Pop(Register src1, Register src2, Register src3, Register src4) {
+    LoadP(src4, MemOperand(sp, 0));
+    LoadP(src3, MemOperand(sp, kPointerSize));
+    LoadP(src2, MemOperand(sp, 2 * kPointerSize));
+    LoadP(src1, MemOperand(sp, 3 * kPointerSize));
+    addi(sp, sp, Operand(4 * kPointerSize));
+  }
+
+  // Pop five registers.  Pops rightmost register first (from lower address).
+  void Pop(Register src1, Register src2, Register src3, Register src4,
+           Register src5) {
+    LoadP(src5, MemOperand(sp, 0));
+    LoadP(src4, MemOperand(sp, kPointerSize));
+    LoadP(src3, MemOperand(sp, 2 * kPointerSize));
+    LoadP(src2, MemOperand(sp, 3 * kPointerSize));
+    LoadP(src1, MemOperand(sp, 4 * kPointerSize));
+    addi(sp, sp, Operand(5 * kPointerSize));
+  }
+
+  // Push a fixed frame, consisting of lr, fp, context and
+  // JS function / marker id if marker_reg is a valid register.
+  void PushFixedFrame(Register marker_reg = no_reg);
+  void PopFixedFrame(Register marker_reg = no_reg);
+
+  // Push and pop the registers that can hold pointers, as defined by the
+  // RegList constant kSafepointSavedRegisters.
+  void PushSafepointRegisters();
+  void PopSafepointRegisters();
+  // Store value in register src in the safepoint stack slot for
+  // register dst.
+  void StoreToSafepointRegisterSlot(Register src, Register dst);
+  // Load the value of the src register from its safepoint stack slot
+  // into register dst.
+  void LoadFromSafepointRegisterSlot(Register dst, Register src);
+
+  // Flush the I-cache from asm code. You should use CpuFeatures::FlushICache
+  // from C.
+  // Does not handle errors.
+  void FlushICache(Register address, size_t size, Register scratch);
+
+  // If the value is a NaN, canonicalize the value else, do nothing.
+  void CanonicalizeNaN(const DoubleRegister dst, const DoubleRegister src);
+  void CanonicalizeNaN(const DoubleRegister value) {
+    CanonicalizeNaN(value, value);
+  }
+
+  // Converts the integer (untagged smi) in |src| to a double, storing
+  // the result to |double_dst|
+  void ConvertIntToDouble(Register src, DoubleRegister double_dst);
+
+  // Converts the unsigned integer (untagged smi) in |src| to
+  // a double, storing the result to |double_dst|
+  void ConvertUnsignedIntToDouble(Register src, DoubleRegister double_dst);
+
+  // Converts the integer (untagged smi) in |src| to
+  // a float, storing the result in |dst|
+  // Warning: The value in |int_scrach| will be changed in the process!
+  void ConvertIntToFloat(const DoubleRegister dst, const Register src,
+                         const Register int_scratch);
+
+  // Converts the double_input to an integer.  Note that, upon return,
+  // the contents of double_dst will also hold the fixed point representation.
+  void ConvertDoubleToInt64(const DoubleRegister double_input,
+#if !V8_TARGET_ARCH_PPC64
+                            const Register dst_hi,
+#endif
+                            const Register dst, const DoubleRegister double_dst,
+                            FPRoundingMode rounding_mode = kRoundToZero);
+
+  // Generates function and stub prologue code.
+  void StubPrologue(int prologue_offset = 0);
+  void Prologue(bool code_pre_aging, int prologue_offset = 0);
+
+  // Enter exit frame.
+  // stack_space - extra stack space, used for alignment before call to C.
+  void EnterExitFrame(bool save_doubles, int stack_space = 0);
+
+  // Leave the current exit frame. Expects the return value in r0.
+  // Expect the number of values, pushed prior to the exit frame, to
+  // remove in a register (or no_reg, if there is nothing to remove).
+  void LeaveExitFrame(bool save_doubles, Register argument_count,
+                      bool restore_context);
+
+  // Get the actual activation frame alignment for target environment.
+  static int ActivationFrameAlignment();
+
+  void LoadContext(Register dst, int context_chain_length);
+
+  // Conditionally load the cached Array transitioned map of type
+  // transitioned_kind from the native context if the map in register
+  // map_in_out is the cached Array map in the native context of
+  // expected_kind.
+  void LoadTransitionedArrayMapConditional(ElementsKind expected_kind,
+                                           ElementsKind transitioned_kind,
+                                           Register map_in_out,
+                                           Register scratch,
+                                           Label* no_map_match);
+
+  void LoadGlobalFunction(int index, Register function);
+
+  // Load the initial map from the global function. The registers
+  // function and map can be the same, function is then overwritten.
+  void LoadGlobalFunctionInitialMap(Register function, Register map,
+                                    Register scratch);
+
+  void InitializeRootRegister() {
+    ExternalReference roots_array_start =
+        ExternalReference::roots_array_start(isolate());
+    mov(kRootRegister, Operand(roots_array_start));
+  }
+
+  // ----------------------------------------------------------------
+  // new PPC macro-assembler interfaces that are slightly higher level
+  // than assembler-ppc and may generate variable length sequences
+
+  // load a literal signed int value <value> to GPR <dst>
+  void LoadIntLiteral(Register dst, int value);
+
+  // load an SMI value <value> to GPR <dst>
+  void LoadSmiLiteral(Register dst, Smi* smi);
+
+  // load a literal double value <value> to FPR <result>
+  void LoadDoubleLiteral(DoubleRegister result, double value, Register scratch);
+
+  void LoadWord(Register dst, const MemOperand& mem, Register scratch);
+
+  void LoadWordArith(Register dst, const MemOperand& mem,
+                     Register scratch = no_reg);
+
+  void StoreWord(Register src, const MemOperand& mem, Register scratch);
+
+  void LoadHalfWord(Register dst, const MemOperand& mem, Register scratch);
+
+  void StoreHalfWord(Register src, const MemOperand& mem, Register scratch);
+
+  void LoadByte(Register dst, const MemOperand& mem, Register scratch);
+
+  void StoreByte(Register src, const MemOperand& mem, Register scratch);
+
+  void LoadRepresentation(Register dst, const MemOperand& mem, Representation r,
+                          Register scratch = no_reg);
+
+  void StoreRepresentation(Register src, const MemOperand& mem,
+                           Representation r, Register scratch = no_reg);
+
+  // Move values between integer and floating point registers.
+  void MovIntToDouble(DoubleRegister dst, Register src, Register scratch);
+  void MovUnsignedIntToDouble(DoubleRegister dst, Register src,
+                              Register scratch);
+  void MovInt64ToDouble(DoubleRegister dst,
+#if !V8_TARGET_ARCH_PPC64
+                        Register src_hi,
+#endif
+                        Register src);
+#if V8_TARGET_ARCH_PPC64
+  void MovInt64ComponentsToDouble(DoubleRegister dst, Register src_hi,
+                                  Register src_lo, Register scratch);
+#endif
+  void MovDoubleLowToInt(Register dst, DoubleRegister src);
+  void MovDoubleHighToInt(Register dst, DoubleRegister src);
+  void MovDoubleToInt64(
+#if !V8_TARGET_ARCH_PPC64
+      Register dst_hi,
+#endif
+      Register dst, DoubleRegister src);
+
+  void Add(Register dst, Register src, intptr_t value, Register scratch);
+  void Cmpi(Register src1, const Operand& src2, Register scratch,
+            CRegister cr = cr7);
+  void Cmpli(Register src1, const Operand& src2, Register scratch,
+             CRegister cr = cr7);
+  void Cmpwi(Register src1, const Operand& src2, Register scratch,
+             CRegister cr = cr7);
+  void Cmplwi(Register src1, const Operand& src2, Register scratch,
+              CRegister cr = cr7);
+  void And(Register ra, Register rs, const Operand& rb, RCBit rc = LeaveRC);
+  void Or(Register ra, Register rs, const Operand& rb, RCBit rc = LeaveRC);
+  void Xor(Register ra, Register rs, const Operand& rb, RCBit rc = LeaveRC);
+
+  void AddSmiLiteral(Register dst, Register src, Smi* smi, Register scratch);
+  void SubSmiLiteral(Register dst, Register src, Smi* smi, Register scratch);
+  void CmpSmiLiteral(Register src1, Smi* smi, Register scratch,
+                     CRegister cr = cr7);
+  void CmplSmiLiteral(Register src1, Smi* smi, Register scratch,
+                      CRegister cr = cr7);
+  void AndSmiLiteral(Register dst, Register src, Smi* smi, Register scratch,
+                     RCBit rc = LeaveRC);
+
+  // Set new rounding mode RN to FPSCR
+  void SetRoundingMode(FPRoundingMode RN);
+
+  // reset rounding mode to default (kRoundToNearest)
+  void ResetRoundingMode();
+
+  // These exist to provide portability between 32 and 64bit
+  void LoadP(Register dst, const MemOperand& mem, Register scratch = no_reg);
+  void StoreP(Register src, const MemOperand& mem, Register scratch = no_reg);
+
+  // ---------------------------------------------------------------------------
+  // JavaScript invokes
+
+  // Invoke the JavaScript function code by either calling or jumping.
+  void InvokeCode(Register code, const ParameterCount& expected,
+                  const ParameterCount& actual, InvokeFlag flag,
+                  const CallWrapper& call_wrapper);
+
+  // Invoke the JavaScript function in the given register. Changes the
+  // current context to the context in the function before invoking.
+  void InvokeFunction(Register function, const ParameterCount& actual,
+                      InvokeFlag flag, const CallWrapper& call_wrapper);
+
+  void InvokeFunction(Register function, const ParameterCount& expected,
+                      const ParameterCount& actual, InvokeFlag flag,
+                      const CallWrapper& call_wrapper);
+
+  void InvokeFunction(Handle<JSFunction> function,
+                      const ParameterCount& expected,
+                      const ParameterCount& actual, InvokeFlag flag,
+                      const CallWrapper& call_wrapper);
+
+  void IsObjectJSObjectType(Register heap_object, Register map,
+                            Register scratch, Label* fail);
+
+  void IsInstanceJSObjectType(Register map, Register scratch, Label* fail);
+
+  void IsObjectJSStringType(Register object, Register scratch, Label* fail);
+
+  void IsObjectNameType(Register object, Register scratch, Label* fail);
+
+  // ---------------------------------------------------------------------------
+  // Debugger Support
+
+  void DebugBreak();
+
+  // ---------------------------------------------------------------------------
+  // Exception handling
+
+  // Push a new try handler and link into try handler chain.
+  void PushTryHandler(StackHandler::Kind kind, int handler_index);
+
+  // Unlink the stack handler on top of the stack from the try handler chain.
+  // Must preserve the result register.
+  void PopTryHandler();
+
+  // Passes thrown value to the handler of top of the try handler chain.
+  void Throw(Register value);
+
+  // Propagates an uncatchable exception to the top of the current JS stack's
+  // handler chain.
+  void ThrowUncatchable(Register value);
+
+  // ---------------------------------------------------------------------------
+  // Inline caching support
+
+  // Generate code for checking access rights - used for security checks
+  // on access to global objects across environments. The holder register
+  // is left untouched, whereas both scratch registers are clobbered.
+  void CheckAccessGlobalProxy(Register holder_reg, Register scratch,
+                              Label* miss);
+
+  void GetNumberHash(Register t0, Register scratch);
+
+  void LoadFromNumberDictionary(Label* miss, Register elements, Register key,
+                                Register result, Register t0, Register t1,
+                                Register t2);
+
+
+  inline void MarkCode(NopMarkerTypes type) { nop(type); }
+
+  // Check if the given instruction is a 'type' marker.
+  // i.e. check if is is a mov r<type>, r<type> (referenced as nop(type))
+  // These instructions are generated to mark special location in the code,
+  // like some special IC code.
+  static inline bool IsMarkedCode(Instr instr, int type) {
+    DCHECK((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER));
+    return IsNop(instr, type);
+  }
+
+
+  static inline int GetCodeMarker(Instr instr) {
+    int dst_reg_offset = 12;
+    int dst_mask = 0xf << dst_reg_offset;
+    int src_mask = 0xf;
+    int dst_reg = (instr & dst_mask) >> dst_reg_offset;
+    int src_reg = instr & src_mask;
+    uint32_t non_register_mask = ~(dst_mask | src_mask);
+    uint32_t mov_mask = al | 13 << 21;
+
+    // Return <n> if we have a mov rn rn, else return -1.
+    int type = ((instr & non_register_mask) == mov_mask) &&
+                       (dst_reg == src_reg) && (FIRST_IC_MARKER <= dst_reg) &&
+                       (dst_reg < LAST_CODE_MARKER)
+                   ? src_reg
+                   : -1;
+    DCHECK((type == -1) ||
+           ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)));
+    return type;
+  }
+
+
+  // ---------------------------------------------------------------------------
+  // Allocation support
+
+  // Allocate an object in new space or old pointer space. The object_size is
+  // specified either in bytes or in words if the allocation flag SIZE_IN_WORDS
+  // is passed. If the space is exhausted control continues at the gc_required
+  // label. The allocated object is returned in result. If the flag
+  // tag_allocated_object is true the result is tagged as as a heap object.
+  // All registers are clobbered also when control continues at the gc_required
+  // label.
+  void Allocate(int object_size, Register result, Register scratch1,
+                Register scratch2, Label* gc_required, AllocationFlags flags);
+
+  void Allocate(Register object_size, Register result, Register scratch1,
+                Register scratch2, Label* gc_required, AllocationFlags flags);
+
+  // Undo allocation in new space. The object passed and objects allocated after
+  // it will no longer be allocated. The caller must make sure that no pointers
+  // are left to the object(s) no longer allocated as they would be invalid when
+  // allocation is undone.
+  void UndoAllocationInNewSpace(Register object, Register scratch);
+
+
+  void AllocateTwoByteString(Register result, Register length,
+                             Register scratch1, Register scratch2,
+                             Register scratch3, Label* gc_required);
+  void AllocateOneByteString(Register result, Register length,
+                             Register scratch1, Register scratch2,
+                             Register scratch3, Label* gc_required);
+  void AllocateTwoByteConsString(Register result, Register length,
+                                 Register scratch1, Register scratch2,
+                                 Label* gc_required);
+  void AllocateOneByteConsString(Register result, Register length,
+                                 Register scratch1, Register scratch2,
+                                 Label* gc_required);
+  void AllocateTwoByteSlicedString(Register result, Register length,
+                                   Register scratch1, Register scratch2,
+                                   Label* gc_required);
+  void AllocateOneByteSlicedString(Register result, Register length,
+                                   Register scratch1, Register scratch2,
+                                   Label* gc_required);
+
+  // Allocates a heap number or jumps to the gc_required label if the young
+  // space is full and a scavenge is needed. All registers are clobbered also
+  // when control continues at the gc_required label.
+  void AllocateHeapNumber(Register result, Register scratch1, Register scratch2,
+                          Register heap_number_map, Label* gc_required,
+                          TaggingMode tagging_mode = TAG_RESULT,
+                          MutableMode mode = IMMUTABLE);
+  void AllocateHeapNumberWithValue(Register result, DoubleRegister value,
+                                   Register scratch1, Register scratch2,
+                                   Register heap_number_map,
+                                   Label* gc_required);
+
+  // Copies a fixed number of fields of heap objects from src to dst.
+  void CopyFields(Register dst, Register src, RegList temps, int field_count);
+
+  // Copies a number of bytes from src to dst. All registers are clobbered. On
+  // exit src and dst will point to the place just after where the last byte was
+  // read or written and length will be zero.
+  void CopyBytes(Register src, Register dst, Register length, Register scratch);
+
+  // Initialize fields with filler values.  |count| fields starting at
+  // |start_offset| are overwritten with the value in |filler|.  At the end the
+  // loop, |start_offset| points at the next uninitialized field.  |count| is
+  // assumed to be non-zero.
+  void InitializeNFieldsWithFiller(Register start_offset, Register count,
+                                   Register filler);
+
+  // Initialize fields with filler values.  Fields starting at |start_offset|
+  // not including end_offset are overwritten with the value in |filler|.  At
+  // the end the loop, |start_offset| takes the value of |end_offset|.
+  void InitializeFieldsWithFiller(Register start_offset, Register end_offset,
+                                  Register filler);
+
+  // ---------------------------------------------------------------------------
+  // Support functions.
+
+  // Try to get function prototype of a function and puts the value in
+  // the result register. Checks that the function really is a
+  // function and jumps to the miss label if the fast checks fail. The
+  // function register will be untouched; the other registers may be
+  // clobbered.
+  void TryGetFunctionPrototype(Register function, Register result,
+                               Register scratch, Label* miss,
+                               bool miss_on_bound_function = false);
+
+  // Compare object type for heap object.  heap_object contains a non-Smi
+  // whose object type should be compared with the given type.  This both
+  // sets the flags and leaves the object type in the type_reg register.
+  // It leaves the map in the map register (unless the type_reg and map register
+  // are the same register).  It leaves the heap object in the heap_object
+  // register unless the heap_object register is the same register as one of the
+  // other registers.
+  // Type_reg can be no_reg. In that case ip is used.
+  void CompareObjectType(Register heap_object, Register map, Register type_reg,
+                         InstanceType type);
+
+  // Compare object type for heap object. Branch to false_label if type
+  // is lower than min_type or greater than max_type.
+  // Load map into the register map.
+  void CheckObjectTypeRange(Register heap_object, Register map,
+                            InstanceType min_type, InstanceType max_type,
+                            Label* false_label);
+
+  // Compare instance type in a map.  map contains a valid map object whose
+  // object type should be compared with the given type.  This both
+  // sets the flags and leaves the object type in the type_reg register.
+  void CompareInstanceType(Register map, Register type_reg, InstanceType type);
+
+
+  // Check if a map for a JSObject indicates that the object has fast elements.
+  // Jump to the specified label if it does not.
+  void CheckFastElements(Register map, Register scratch, Label* fail);
+
+  // Check if a map for a JSObject indicates that the object can have both smi
+  // and HeapObject elements.  Jump to the specified label if it does not.
+  void CheckFastObjectElements(Register map, Register scratch, Label* fail);
+
+  // Check if a map for a JSObject indicates that the object has fast smi only
+  // elements.  Jump to the specified label if it does not.
+  void CheckFastSmiElements(Register map, Register scratch, Label* fail);
+
+  // Check to see if maybe_number can be stored as a double in
+  // FastDoubleElements. If it can, store it at the index specified by key in
+  // the FastDoubleElements array elements. Otherwise jump to fail.
+  void StoreNumberToDoubleElements(Register value_reg, Register key_reg,
+                                   Register elements_reg, Register scratch1,
+                                   DoubleRegister double_scratch, Label* fail,
+                                   int elements_offset = 0);
+
+  // Compare an object's map with the specified map and its transitioned
+  // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Condition flags are
+  // set with result of map compare. If multiple map compares are required, the
+  // compare sequences branches to early_success.
+  void CompareMap(Register obj, Register scratch, Handle<Map> map,
+                  Label* early_success);
+
+  // As above, but the map of the object is already loaded into the register
+  // which is preserved by the code generated.
+  void CompareMap(Register obj_map, Handle<Map> map, Label* early_success);
+
+  // Check if the map of an object is equal to a specified map and branch to
+  // label if not. Skip the smi check if not required (object is known to be a
+  // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match
+  // against maps that are ElementsKind transition maps of the specified map.
+  void CheckMap(Register obj, Register scratch, Handle<Map> map, Label* fail,
+                SmiCheckType smi_check_type);
+
+
+  void CheckMap(Register obj, Register scratch, Heap::RootListIndex index,
+                Label* fail, SmiCheckType smi_check_type);
+
+
+  // Check if the map of an object is equal to a specified map and branch to a
+  // specified target if equal. Skip the smi check if not required (object is
+  // known to be a heap object)
+  void DispatchMap(Register obj, Register scratch, Handle<Map> map,
+                   Handle<Code> success, SmiCheckType smi_check_type);
+
+
+  // Compare the object in a register to a value from the root list.
+  // Uses the ip register as scratch.
+  void CompareRoot(Register obj, Heap::RootListIndex index);
+
+
+  // Load and check the instance type of an object for being a string.
+  // Loads the type into the second argument register.
+  // Returns a condition that will be enabled if the object was a string.
+  Condition IsObjectStringType(Register obj, Register type) {
+    LoadP(type, FieldMemOperand(obj, HeapObject::kMapOffset));
+    lbz(type, FieldMemOperand(type, Map::kInstanceTypeOffset));
+    andi(r0, type, Operand(kIsNotStringMask));
+    DCHECK_EQ(0, kStringTag);
+    return eq;
+  }
+
+
+  // Picks out an array index from the hash field.
+  // Register use:
+  //   hash - holds the index's hash. Clobbered.
+  //   index - holds the overwritten index on exit.
+  void IndexFromHash(Register hash, Register index);
+
+  // Get the number of least significant bits from a register
+  void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits);
+  void GetLeastBitsFromInt32(Register dst, Register src, int mun_least_bits);
+
+  // Load the value of a smi object into a double register.
+  void SmiToDouble(DoubleRegister value, Register smi);
+
+  // Check if a double can be exactly represented as a signed 32-bit integer.
+  // CR_EQ in cr7 is set if true.
+  void TestDoubleIsInt32(DoubleRegister double_input, Register scratch1,
+                         Register scratch2, DoubleRegister double_scratch);
+
+  // Try to convert a double to a signed 32-bit integer.
+  // CR_EQ in cr7 is set and result assigned if the conversion is exact.
+  void TryDoubleToInt32Exact(Register result, DoubleRegister double_input,
+                             Register scratch, DoubleRegister double_scratch);
+
+  // Floor a double and writes the value to the result register.
+  // Go to exact if the conversion is exact (to be able to test -0),
+  // fall through calling code if an overflow occurred, else go to done.
+  // In return, input_high is loaded with high bits of input.
+  void TryInt32Floor(Register result, DoubleRegister double_input,
+                     Register input_high, Register scratch,
+                     DoubleRegister double_scratch, Label* done, Label* exact);
+
+  // Performs a truncating conversion of a floating point number as used by
+  // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it
+  // succeeds, otherwise falls through if result is saturated. On return
+  // 'result' either holds answer, or is clobbered on fall through.
+  //
+  // Only public for the test code in test-code-stubs-arm.cc.
+  void TryInlineTruncateDoubleToI(Register result, DoubleRegister input,
+                                  Label* done);
+
+  // Performs a truncating conversion of a floating point number as used by
+  // the JS bitwise operations. See ECMA-262 9.5: ToInt32.
+  // Exits with 'result' holding the answer.
+  void TruncateDoubleToI(Register result, DoubleRegister double_input);
+
+  // Performs a truncating conversion of a heap number as used by
+  // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 'result' and 'input'
+  // must be different registers.  Exits with 'result' holding the answer.
+  void TruncateHeapNumberToI(Register result, Register object);
+
+  // Converts the smi or heap number in object to an int32 using the rules
+  // for ToInt32 as described in ECMAScript 9.5.: the value is truncated
+  // and brought into the range -2^31 .. +2^31 - 1. 'result' and 'input' must be
+  // different registers.
+  void TruncateNumberToI(Register object, Register result,
+                         Register heap_number_map, Register scratch1,
+                         Label* not_int32);
+
+  // Overflow handling functions.
+  // Usage: call the appropriate arithmetic function and then call one of the
+  // flow control functions with the corresponding label.
+
+  // Compute dst = left + right, setting condition codes. dst may be same as
+  // either left or right (or a unique register). left and right must not be
+  // the same register.
+  void AddAndCheckForOverflow(Register dst, Register left, Register right,
+                              Register overflow_dst, Register scratch = r0);
+  void AddAndCheckForOverflow(Register dst, Register left, intptr_t right,
+                              Register overflow_dst, Register scratch = r0);
+
+  // Compute dst = left - right, setting condition codes. dst may be same as
+  // either left or right (or a unique register). left and right must not be
+  // the same register.
+  void SubAndCheckForOverflow(Register dst, Register left, Register right,
+                              Register overflow_dst, Register scratch = r0);
+
+  void BranchOnOverflow(Label* label) { blt(label, cr0); }
+
+  void BranchOnNoOverflow(Label* label) { bge(label, cr0); }
+
+  void RetOnOverflow(void) {
+    Label label;
+
+    blt(&label, cr0);
+    Ret();
+    bind(&label);
+  }
+
+  void RetOnNoOverflow(void) {
+    Label label;
+
+    bge(&label, cr0);
+    Ret();
+    bind(&label);
+  }
+
+  // Pushes <count> double values to <location>, starting from d<first>.
+  void SaveFPRegs(Register location, int first, int count);
+
+  // Pops <count> double values from <location>, starting from d<first>.
+  void RestoreFPRegs(Register location, int first, int count);
+
+  // ---------------------------------------------------------------------------
+  // Runtime calls
+
+  // Call a code stub.
+  void CallStub(CodeStub* stub, TypeFeedbackId ast_id = TypeFeedbackId::None(),
+                Condition cond = al);
+
+  // Call a code stub.
+  void TailCallStub(CodeStub* stub, Condition cond = al);
+
+  // Call a runtime routine.
+  void CallRuntime(const Runtime::Function* f, int num_arguments,
+                   SaveFPRegsMode save_doubles = kDontSaveFPRegs);
+  void CallRuntimeSaveDoubles(Runtime::FunctionId id) {
+    const Runtime::Function* function = Runtime::FunctionForId(id);
+    CallRuntime(function, function->nargs, kSaveFPRegs);
+  }
+
+  // Convenience function: Same as above, but takes the fid instead.
+  void CallRuntime(Runtime::FunctionId id, int num_arguments,
+                   SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
+    CallRuntime(Runtime::FunctionForId(id), num_arguments, save_doubles);
+  }
+
+  // Convenience function: call an external reference.
+  void CallExternalReference(const ExternalReference& ext, int num_arguments);
+
+  // Tail call of a runtime routine (jump).
+  // Like JumpToExternalReference, but also takes care of passing the number
+  // of parameters.
+  void TailCallExternalReference(const ExternalReference& ext,
+                                 int num_arguments, int result_size);
+
+  // Convenience function: tail call a runtime routine (jump).
+  void TailCallRuntime(Runtime::FunctionId fid, int num_arguments,
+                       int result_size);
+
+  int CalculateStackPassedWords(int num_reg_arguments,
+                                int num_double_arguments);
+
+  // Before calling a C-function from generated code, align arguments on stack.
+  // After aligning the frame, non-register arguments must be stored in
+  // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments
+  // are word sized. If double arguments are used, this function assumes that
+  // all double arguments are stored before core registers; otherwise the
+  // correct alignment of the double values is not guaranteed.
+  // Some compilers/platforms require the stack to be aligned when calling
+  // C++ code.
+  // Needs a scratch register to do some arithmetic. This register will be
+  // trashed.
+  void PrepareCallCFunction(int num_reg_arguments, int num_double_registers,
+                            Register scratch);
+  void PrepareCallCFunction(int num_reg_arguments, Register scratch);
+
+  // There are two ways of passing double arguments on ARM, depending on
+  // whether soft or hard floating point ABI is used. These functions
+  // abstract parameter passing for the three different ways we call
+  // C functions from generated code.
+  void MovToFloatParameter(DoubleRegister src);
+  void MovToFloatParameters(DoubleRegister src1, DoubleRegister src2);
+  void MovToFloatResult(DoubleRegister src);
+
+  // Calls a C function and cleans up the space for arguments allocated
+  // by PrepareCallCFunction. The called function is not allowed to trigger a
+  // garbage collection, since that might move the code and invalidate the
+  // return address (unless this is somehow accounted for by the called
+  // function).
+  void CallCFunction(ExternalReference function, int num_arguments);
+  void CallCFunction(Register function, int num_arguments);
+  void CallCFunction(ExternalReference function, int num_reg_arguments,
+                     int num_double_arguments);
+  void CallCFunction(Register function, int num_reg_arguments,
+                     int num_double_arguments);
+
+  void MovFromFloatParameter(DoubleRegister dst);
+  void MovFromFloatResult(DoubleRegister dst);
+
+  // Calls an API function.  Allocates HandleScope, extracts returned value
+  // from handle and propagates exceptions.  Restores context.  stack_space
+  // - space to be unwound on exit (includes the call JS arguments space and
+  // the additional space allocated for the fast call).
+  void CallApiFunctionAndReturn(Register function_address,
+                                ExternalReference thunk_ref, int stack_space,
+                                MemOperand return_value_operand,
+                                MemOperand* context_restore_operand);
+
+  // Jump to a runtime routine.
+  void JumpToExternalReference(const ExternalReference& builtin);
+
+  // Invoke specified builtin JavaScript function. Adds an entry to
+  // the unresolved list if the name does not resolve.
+  void InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag,
+                     const CallWrapper& call_wrapper = NullCallWrapper());
+
+  // Store the code object for the given builtin in the target register and
+  // setup the function in r1.
+  void GetBuiltinEntry(Register target, Builtins::JavaScript id);
+
+  // Store the function for the given builtin in the target register.
+  void GetBuiltinFunction(Register target, Builtins::JavaScript id);
+
+  Handle<Object> CodeObject() {
+    DCHECK(!code_object_.is_null());
+    return code_object_;
+  }
+
+
+  // Emit code for a truncating division by a constant. The dividend register is
+  // unchanged and ip gets clobbered. Dividend and result must be different.
+  void TruncatingDiv(Register result, Register dividend, int32_t divisor);
+
+  // ---------------------------------------------------------------------------
+  // StatsCounter support
+
+  void SetCounter(StatsCounter* counter, int value, Register scratch1,
+                  Register scratch2);
+  void IncrementCounter(StatsCounter* counter, int value, Register scratch1,
+                        Register scratch2);
+  void DecrementCounter(StatsCounter* counter, int value, Register scratch1,
+                        Register scratch2);
+
+
+  // ---------------------------------------------------------------------------
+  // Debugging
+
+  // Calls Abort(msg) if the condition cond is not satisfied.
+  // Use --debug_code to enable.
+  void Assert(Condition cond, BailoutReason reason, CRegister cr = cr7);
+  void AssertFastElements(Register elements);
+
+  // Like Assert(), but always enabled.
+  void Check(Condition cond, BailoutReason reason, CRegister cr = cr7);
+
+  // Print a message to stdout and abort execution.
+  void Abort(BailoutReason reason);
+
+  // Verify restrictions about code generated in stubs.
+  void set_generating_stub(bool value) { generating_stub_ = value; }
+  bool generating_stub() { return generating_stub_; }
+  void set_has_frame(bool value) { has_frame_ = value; }
+  bool has_frame() { return has_frame_; }
+  inline bool AllowThisStubCall(CodeStub* stub);
+
+  // ---------------------------------------------------------------------------
+  // Number utilities
+
+  // Check whether the value of reg is a power of two and not zero. If not
+  // control continues at the label not_power_of_two. If reg is a power of two
+  // the register scratch contains the value of (reg - 1) when control falls
+  // through.
+  void JumpIfNotPowerOfTwoOrZero(Register reg, Register scratch,
+                                 Label* not_power_of_two_or_zero);
+  // Check whether the value of reg is a power of two and not zero.
+  // Control falls through if it is, with scratch containing the mask
+  // value (reg - 1).
+  // Otherwise control jumps to the 'zero_and_neg' label if the value of reg is
+  // zero or negative, or jumps to the 'not_power_of_two' label if the value is
+  // strictly positive but not a power of two.
+  void JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg, Register scratch,
+                                       Label* zero_and_neg,
+                                       Label* not_power_of_two);
+
+  // ---------------------------------------------------------------------------
+  // Bit testing/extraction
+  //
+  // Bit numbering is such that the least significant bit is bit 0
+  // (for consistency between 32/64-bit).
+
+  // Extract consecutive bits (defined by rangeStart - rangeEnd) from src
+  // and place them into the least significant bits of dst.
+  inline void ExtractBitRange(Register dst, Register src, int rangeStart,
+                              int rangeEnd, RCBit rc = LeaveRC) {
+    DCHECK(rangeStart >= rangeEnd && rangeStart < kBitsPerPointer);
+    int rotate = (rangeEnd == 0) ? 0 : kBitsPerPointer - rangeEnd;
+    int width = rangeStart - rangeEnd + 1;
+#if V8_TARGET_ARCH_PPC64
+    rldicl(dst, src, rotate, kBitsPerPointer - width, rc);
+#else
+    rlwinm(dst, src, rotate, kBitsPerPointer - width, kBitsPerPointer - 1, rc);
+#endif
+  }
+
+  inline void ExtractBit(Register dst, Register src, uint32_t bitNumber,
+                         RCBit rc = LeaveRC) {
+    ExtractBitRange(dst, src, bitNumber, bitNumber, rc);
+  }
+
+  // Extract consecutive bits (defined by mask) from src and place them
+  // into the least significant bits of dst.
+  inline void ExtractBitMask(Register dst, Register src, uintptr_t mask,
+                             RCBit rc = LeaveRC) {
+    int start = kBitsPerPointer - 1;
+    int end;
+    uintptr_t bit = (1L << start);
+
+    while (bit && (mask & bit) == 0) {
+      start--;
+      bit >>= 1;
+    }
+    end = start;
+    bit >>= 1;
+
+    while (bit && (mask & bit)) {
+      end--;
+      bit >>= 1;
+    }
+
+    // 1-bits in mask must be contiguous
+    DCHECK(bit == 0 || (mask & ((bit << 1) - 1)) == 0);
+
+    ExtractBitRange(dst, src, start, end, rc);
+  }
+
+  // Test single bit in value.
+  inline void TestBit(Register value, int bitNumber, Register scratch = r0) {
+    ExtractBitRange(scratch, value, bitNumber, bitNumber, SetRC);
+  }
+
+  // Test consecutive bit range in value.  Range is defined by
+  // rangeStart - rangeEnd.
+  inline void TestBitRange(Register value, int rangeStart, int rangeEnd,
+                           Register scratch = r0) {
+    ExtractBitRange(scratch, value, rangeStart, rangeEnd, SetRC);
+  }
+
+  // Test consecutive bit range in value.  Range is defined by mask.
+  inline void TestBitMask(Register value, uintptr_t mask,
+                          Register scratch = r0) {
+    ExtractBitMask(scratch, value, mask, SetRC);
+  }
+
+
+  // ---------------------------------------------------------------------------
+  // Smi utilities
+
+  // Shift left by 1
+  void SmiTag(Register reg, RCBit rc = LeaveRC) { SmiTag(reg, reg, rc); }
+  void SmiTag(Register dst, Register src, RCBit rc = LeaveRC) {
+    ShiftLeftImm(dst, src, Operand(kSmiShift), rc);
+  }
+
+#if !V8_TARGET_ARCH_PPC64
+  // Test for overflow < 0: use BranchOnOverflow() or BranchOnNoOverflow().
+  void SmiTagCheckOverflow(Register reg, Register overflow);
+  void SmiTagCheckOverflow(Register dst, Register src, Register overflow);
+
+  inline void JumpIfNotSmiCandidate(Register value, Register scratch,
+                                    Label* not_smi_label) {
+    // High bits must be identical to fit into an Smi
+    addis(scratch, value, Operand(0x40000000u >> 16));
+    cmpi(scratch, Operand::Zero());
+    blt(not_smi_label);
+  }
+#endif
+  inline void TestUnsignedSmiCandidate(Register value, Register scratch) {
+    // The test is different for unsigned int values. Since we need
+    // the value to be in the range of a positive smi, we can't
+    // handle any of the high bits being set in the value.
+    TestBitRange(value, kBitsPerPointer - 1, kBitsPerPointer - 1 - kSmiShift,
+                 scratch);
+  }
+  inline void JumpIfNotUnsignedSmiCandidate(Register value, Register scratch,
+                                            Label* not_smi_label) {
+    TestUnsignedSmiCandidate(value, scratch);
+    bne(not_smi_label, cr0);
+  }
+
+  void SmiUntag(Register reg, RCBit rc = LeaveRC) { SmiUntag(reg, reg, rc); }
+
+  void SmiUntag(Register dst, Register src, RCBit rc = LeaveRC) {
+    ShiftRightArithImm(dst, src, kSmiShift, rc);
+  }
+
+  void SmiToPtrArrayOffset(Register dst, Register src) {
+#if V8_TARGET_ARCH_PPC64
+    STATIC_ASSERT(kSmiTag == 0 && kSmiShift > kPointerSizeLog2);
+    ShiftRightArithImm(dst, src, kSmiShift - kPointerSizeLog2);
+#else
+    STATIC_ASSERT(kSmiTag == 0 && kSmiShift < kPointerSizeLog2);
+    ShiftLeftImm(dst, src, Operand(kPointerSizeLog2 - kSmiShift));
+#endif
+  }
+
+  void SmiToByteArrayOffset(Register dst, Register src) { SmiUntag(dst, src); }
+
+  void SmiToShortArrayOffset(Register dst, Register src) {
+#if V8_TARGET_ARCH_PPC64
+    STATIC_ASSERT(kSmiTag == 0 && kSmiShift > 1);
+    ShiftRightArithImm(dst, src, kSmiShift - 1);
+#else
+    STATIC_ASSERT(kSmiTag == 0 && kSmiShift == 1);
+    if (!dst.is(src)) {
+      mr(dst, src);
+    }
+#endif
+  }
+
+  void SmiToIntArrayOffset(Register dst, Register src) {
+#if V8_TARGET_ARCH_PPC64
+    STATIC_ASSERT(kSmiTag == 0 && kSmiShift > 2);
+    ShiftRightArithImm(dst, src, kSmiShift - 2);
+#else
+    STATIC_ASSERT(kSmiTag == 0 && kSmiShift < 2);
+    ShiftLeftImm(dst, src, Operand(2 - kSmiShift));
+#endif
+  }
+
+#define SmiToFloatArrayOffset SmiToIntArrayOffset
+
+  void SmiToDoubleArrayOffset(Register dst, Register src) {
+#if V8_TARGET_ARCH_PPC64
+    STATIC_ASSERT(kSmiTag == 0 && kSmiShift > kDoubleSizeLog2);
+    ShiftRightArithImm(dst, src, kSmiShift - kDoubleSizeLog2);
+#else
+    STATIC_ASSERT(kSmiTag == 0 && kSmiShift < kDoubleSizeLog2);
+    ShiftLeftImm(dst, src, Operand(kDoubleSizeLog2 - kSmiShift));
+#endif
+  }
+
+  void SmiToArrayOffset(Register dst, Register src, int elementSizeLog2) {
+    if (kSmiShift < elementSizeLog2) {
+      ShiftLeftImm(dst, src, Operand(elementSizeLog2 - kSmiShift));
+    } else if (kSmiShift > elementSizeLog2) {
+      ShiftRightArithImm(dst, src, kSmiShift - elementSizeLog2);
+    } else if (!dst.is(src)) {
+      mr(dst, src);
+    }
+  }
+
+  void IndexToArrayOffset(Register dst, Register src, int elementSizeLog2,
+                          bool isSmi) {
+    if (isSmi) {
+      SmiToArrayOffset(dst, src, elementSizeLog2);
+    } else {
+      ShiftLeftImm(dst, src, Operand(elementSizeLog2));
+    }
+  }
+
+  // Untag the source value into destination and jump if source is a smi.
+  // Souce and destination can be the same register.
+  void UntagAndJumpIfSmi(Register dst, Register src, Label* smi_case);
+
+  // Untag the source value into destination and jump if source is not a smi.
+  // Souce and destination can be the same register.
+  void UntagAndJumpIfNotSmi(Register dst, Register src, Label* non_smi_case);
+
+  inline void TestIfSmi(Register value, Register scratch) {
+    TestBit(value, 0, scratch);  // tst(value, Operand(kSmiTagMask));
+  }
+
+  inline void TestIfPositiveSmi(Register value, Register scratch) {
+    STATIC_ASSERT((kSmiTagMask | kSmiSignMask) ==
+                  (intptr_t)(1UL << (kBitsPerPointer - 1) | 1));
+#if V8_TARGET_ARCH_PPC64
+    rldicl(scratch, value, 1, kBitsPerPointer - 2, SetRC);
+#else
+    rlwinm(scratch, value, 1, kBitsPerPointer - 2, kBitsPerPointer - 1, SetRC);
+#endif
+  }
+
+  // Jump the register contains a smi.
+  inline void JumpIfSmi(Register value, Label* smi_label) {
+    TestIfSmi(value, r0);
+    beq(smi_label, cr0);  // branch if SMI
+  }
+  // Jump if either of the registers contain a non-smi.
+  inline void JumpIfNotSmi(Register value, Label* not_smi_label) {
+    TestIfSmi(value, r0);
+    bne(not_smi_label, cr0);
+  }
+  // Jump if either of the registers contain a non-smi.
+  void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi);
+  // Jump if either of the registers contain a smi.
+  void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi);
+
+  // Abort execution if argument is a smi, enabled via --debug-code.
+  void AssertNotSmi(Register object);
+  void AssertSmi(Register object);
+
+
+#if V8_TARGET_ARCH_PPC64
+  inline void TestIfInt32(Register value, Register scratch1, Register scratch2,
+                          CRegister cr = cr7) {
+    // High bits must be identical to fit into an 32-bit integer
+    srawi(scratch1, value, 31);
+    sradi(scratch2, value, 32);
+    cmp(scratch1, scratch2, cr);
+  }
+#else
+  inline void TestIfInt32(Register hi_word, Register lo_word, Register scratch,
+                          CRegister cr = cr7) {
+    // High bits must be identical to fit into an 32-bit integer
+    srawi(scratch, lo_word, 31);
+    cmp(scratch, hi_word, cr);
+  }
+#endif
+
+  // Abort execution if argument is not a string, enabled via --debug-code.
+  void AssertString(Register object);
+
+  // Abort execution if argument is not a name, enabled via --debug-code.
+  void AssertName(Register object);
+
+  // Abort execution if argument is not undefined or an AllocationSite, enabled
+  // via --debug-code.
+  void AssertUndefinedOrAllocationSite(Register object, Register scratch);
+
+  // Abort execution if reg is not the root value with the given index,
+  // enabled via --debug-code.
+  void AssertIsRoot(Register reg, Heap::RootListIndex index);
+
+  // ---------------------------------------------------------------------------
+  // HeapNumber utilities
+
+  void JumpIfNotHeapNumber(Register object, Register heap_number_map,
+                           Register scratch, Label* on_not_heap_number);
+
+  // ---------------------------------------------------------------------------
+  // String utilities
+
+  // Generate code to do a lookup in the number string cache. If the number in
+  // the register object is found in the cache the generated code falls through
+  // with the result in the result register. The object and the result register
+  // can be the same. If the number is not found in the cache the code jumps to
+  // the label not_found with only the content of register object unchanged.
+  void LookupNumberStringCache(Register object, Register result,
+                               Register scratch1, Register scratch2,
+                               Register scratch3, Label* not_found);
+
+  // Checks if both objects are sequential one-byte strings and jumps to label
+  // if either is not. Assumes that neither object is a smi.
+  void JumpIfNonSmisNotBothSequentialOneByteStrings(Register object1,
+                                                    Register object2,
+                                                    Register scratch1,
+                                                    Register scratch2,
+                                                    Label* failure);
+
+  // Checks if both objects are sequential one-byte strings and jumps to label
+  // if either is not.
+  void JumpIfNotBothSequentialOneByteStrings(Register first, Register second,
+                                             Register scratch1,
+                                             Register scratch2,
+                                             Label* not_flat_one_byte_strings);
+
+  // Checks if both instance types are sequential one-byte strings and jumps to
+  // label if either is not.
+  void JumpIfBothInstanceTypesAreNotSequentialOneByte(
+      Register first_object_instance_type, Register second_object_instance_type,
+      Register scratch1, Register scratch2, Label* failure);
+
+  // Check if instance type is sequential one-byte string and jump to label if
+  // it is not.
+  void JumpIfInstanceTypeIsNotSequentialOneByte(Register type, Register scratch,
+                                                Label* failure);
+
+  void JumpIfNotUniqueNameInstanceType(Register reg, Label* not_unique_name);
+
+  void EmitSeqStringSetCharCheck(Register string, Register index,
+                                 Register value, uint32_t encoding_mask);
+
+  // ---------------------------------------------------------------------------
+  // Patching helpers.
+
+  // Retrieve/patch the relocated value (lis/ori pair or constant pool load).
+  void GetRelocatedValue(Register location, Register result, Register scratch);
+  void SetRelocatedValue(Register location, Register scratch,
+                         Register new_value);
+
+  void ClampUint8(Register output_reg, Register input_reg);
+
+  // Saturate a value into 8-bit unsigned integer
+  //   if input_value < 0, output_value is 0
+  //   if input_value > 255, output_value is 255
+  //   otherwise output_value is the (int)input_value (round to nearest)
+  void ClampDoubleToUint8(Register result_reg, DoubleRegister input_reg,
+                          DoubleRegister temp_double_reg);
+
+
+  void LoadInstanceDescriptors(Register map, Register descriptors);
+  void EnumLength(Register dst, Register map);
+  void NumberOfOwnDescriptors(Register dst, Register map);
+
+  template <typename Field>
+  void DecodeField(Register dst, Register src) {
+    ExtractBitRange(dst, src, Field::kShift + Field::kSize - 1, Field::kShift);
+  }
+
+  template <typename Field>
+  void DecodeField(Register reg) {
+    DecodeField<Field>(reg, reg);
+  }
+
+  template <typename Field>
+  void DecodeFieldToSmi(Register dst, Register src) {
+#if V8_TARGET_ARCH_PPC64
+    DecodeField<Field>(dst, src);
+    SmiTag(dst);
+#else
+    // 32-bit can do this in one instruction:
+    int start = Field::kSize + kSmiShift - 1;
+    int end = kSmiShift;
+    int rotate = kSmiShift - Field::kShift;
+    if (rotate < 0) {
+      rotate += kBitsPerPointer;
+    }
+    rlwinm(dst, src, rotate, kBitsPerPointer - start - 1,
+           kBitsPerPointer - end - 1);
+#endif
+  }
+
+  template <typename Field>
+  void DecodeFieldToSmi(Register reg) {
+    DecodeFieldToSmi<Field>(reg, reg);
+  }
+
+  // Activation support.
+  void EnterFrame(StackFrame::Type type,
+                  bool load_constant_pool_pointer_reg = false);
+  // Returns the pc offset at which the frame ends.
+  int LeaveFrame(StackFrame::Type type, int stack_adjustment = 0);
+
+  // Expects object in r0 and returns map with validated enum cache
+  // in r0.  Assumes that any other register can be used as a scratch.
+  void CheckEnumCache(Register null_value, Label* call_runtime);
+
+  // AllocationMemento support. Arrays may have an associated
+  // AllocationMemento object that can be checked for in order to pretransition
+  // to another type.
+  // On entry, receiver_reg should point to the array object.
+  // scratch_reg gets clobbered.
+  // If allocation info is present, condition flags are set to eq.
+  void TestJSArrayForAllocationMemento(Register receiver_reg,
+                                       Register scratch_reg,
+                                       Label* no_memento_found);
+
+  void JumpIfJSArrayHasAllocationMemento(Register receiver_reg,
+                                         Register scratch_reg,
+                                         Label* memento_found) {
+    Label no_memento_found;
+    TestJSArrayForAllocationMemento(receiver_reg, scratch_reg,
+                                    &no_memento_found);
+    beq(memento_found);
+    bind(&no_memento_found);
+  }
+
+  // Jumps to found label if a prototype map has dictionary elements.
+  void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
+                                        Register scratch1, Label* found);
+
+ private:
+  static const int kSmiShift = kSmiTagSize + kSmiShiftSize;
+
+  void CallCFunctionHelper(Register function, int num_reg_arguments,
+                           int num_double_arguments);
+
+  void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al,
+            CRegister cr = cr7);
+
+  // Helper functions for generating invokes.
+  void InvokePrologue(const ParameterCount& expected,
+                      const ParameterCount& actual, Handle<Code> code_constant,
+                      Register code_reg, Label* done,
+                      bool* definitely_mismatches, InvokeFlag flag,
+                      const CallWrapper& call_wrapper);
+
+  void InitializeNewString(Register string, Register length,
+                           Heap::RootListIndex map_index, Register scratch1,
+                           Register scratch2);
+
+  // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
+  void InNewSpace(Register object, Register scratch,
+                  Condition cond,  // eq for new space, ne otherwise.
+                  Label* branch);
+
+  // Helper for finding the mark bits for an address.  Afterwards, the
+  // bitmap register points at the word with the mark bits and the mask
+  // the position of the first bit.  Leaves addr_reg unchanged.
+  inline void GetMarkBits(Register addr_reg, Register bitmap_reg,
+                          Register mask_reg);
+
+  // Helper for throwing exceptions.  Compute a handler address and jump to
+  // it.  See the implementation for register usage.
+  void JumpToHandlerEntry();
+
+  // Compute memory operands for safepoint stack slots.
+  static int SafepointRegisterStackIndex(int reg_code);
+  MemOperand SafepointRegisterSlot(Register reg);
+  MemOperand SafepointRegistersAndDoublesSlot(Register reg);
+
+#if V8_OOL_CONSTANT_POOL
+  // Loads the constant pool pointer (kConstantPoolRegister).
+  enum CodeObjectAccessMethod { CAN_USE_IP, CONSTRUCT_INTERNAL_REFERENCE };
+  void LoadConstantPoolPointerRegister(CodeObjectAccessMethod access_method,
+                                       int ip_code_entry_delta = 0);
+#endif
+
+  bool generating_stub_;
+  bool has_frame_;
+  // This handle will be patched with the code object on installation.
+  Handle<Object> code_object_;
+
+  // Needs access to SafepointRegisterStackIndex for compiled frame
+  // traversal.
+  friend class StandardFrame;
+};
+
+
+// The code patcher is used to patch (typically) small parts of code e.g. for
+// debugging and other types of instrumentation. When using the code patcher
+// the exact number of bytes specified must be emitted. It is not legal to emit
+// relocation information. If any of these constraints are violated it causes
+// an assertion to fail.
+class CodePatcher {
+ public:
+  enum FlushICache { FLUSH, DONT_FLUSH };
+
+  CodePatcher(byte* address, int instructions, FlushICache flush_cache = FLUSH);
+  virtual ~CodePatcher();
+
+  // Macro assembler to emit code.
+  MacroAssembler* masm() { return &masm_; }
+
+  // Emit an instruction directly.
+  void Emit(Instr instr);
+
+  // Emit the condition part of an instruction leaving the rest of the current
+  // instruction unchanged.
+  void EmitCondition(Condition cond);
+
+ private:
+  byte* address_;            // The address of the code being patched.
+  int size_;                 // Number of bytes of the expected patch size.
+  MacroAssembler masm_;      // Macro assembler used to generate the code.
+  FlushICache flush_cache_;  // Whether to flush the I cache after patching.
+};
+
+
+// -----------------------------------------------------------------------------
+// Static helper functions.
+
+inline MemOperand ContextOperand(Register context, int index) {
+  return MemOperand(context, Context::SlotOffset(index));
+}
+
+
+inline MemOperand GlobalObjectOperand() {
+  return ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX);
+}
+
+
+#ifdef GENERATED_CODE_COVERAGE
+#define CODE_COVERAGE_STRINGIFY(x) #x
+#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
+#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
+#define ACCESS_MASM(masm)    \
+  masm->stop(__FILE_LINE__); \
+  masm->
+#else
+#define ACCESS_MASM(masm) masm->
+#endif
+}
+}  // namespace v8::internal
+
+#endif  // V8_PPC_MACRO_ASSEMBLER_PPC_H_
diff --git a/src/ppc/regexp-macro-assembler-ppc.cc b/src/ppc/regexp-macro-assembler-ppc.cc
new file mode 100644
index 0000000..54acce1
--- /dev/null
+++ b/src/ppc/regexp-macro-assembler-ppc.cc
@@ -0,0 +1,1337 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/base/bits.h"
+#include "src/code-stubs.h"
+#include "src/cpu-profiler.h"
+#include "src/log.h"
+#include "src/macro-assembler.h"
+#include "src/regexp-macro-assembler.h"
+#include "src/regexp-stack.h"
+#include "src/unicode.h"
+
+#include "src/ppc/regexp-macro-assembler-ppc.h"
+
+namespace v8 {
+namespace internal {
+
+#ifndef V8_INTERPRETED_REGEXP
+/*
+ * This assembler uses the following register assignment convention
+ * - r25: Temporarily stores the index of capture start after a matching pass
+ *        for a global regexp.
+ * - r26: Pointer to current code object (Code*) including heap object tag.
+ * - r27: Current position in input, as negative offset from end of string.
+ *        Please notice that this is the byte offset, not the character offset!
+ * - r28: Currently loaded character. Must be loaded using
+ *        LoadCurrentCharacter before using any of the dispatch methods.
+ * - r29: Points to tip of backtrack stack
+ * - r30: End of input (points to byte after last character in input).
+ * - r31: Frame pointer. Used to access arguments, local variables and
+ *         RegExp registers.
+ * - r12: IP register, used by assembler. Very volatile.
+ * - r1/sp : Points to tip of C stack.
+ *
+ * The remaining registers are free for computations.
+ * Each call to a public method should retain this convention.
+ *
+ * The stack will have the following structure:
+ *  - fp[44]  Isolate* isolate   (address of the current isolate)
+ *  - fp[40]  secondary link/return address used by native call.
+ *  - fp[36]  lr save area (currently unused)
+ *  - fp[32]  backchain    (currently unused)
+ *  --- sp when called ---
+ *  - fp[28]  return address     (lr).
+ *  - fp[24]  old frame pointer  (r31).
+ *  - fp[0..20]  backup of registers r25..r30
+ *  --- frame pointer ----
+ *  - fp[-4]  direct_call        (if 1, direct call from JavaScript code,
+ *                                if 0, call through the runtime system).
+ *  - fp[-8]  stack_area_base    (high end of the memory area to use as
+ *                                backtracking stack).
+ *  - fp[-12] capture array size (may fit multiple sets of matches)
+ *  - fp[-16] int* capture_array (int[num_saved_registers_], for output).
+ *  - fp[-20] end of input       (address of end of string).
+ *  - fp[-24] start of input     (address of first character in string).
+ *  - fp[-28] start index        (character index of start).
+ *  - fp[-32] void* input_string (location of a handle containing the string).
+ *  - fp[-36] success counter    (only for global regexps to count matches).
+ *  - fp[-40] Offset of location before start of input (effectively character
+ *            position -1). Used to initialize capture registers to a
+ *            non-position.
+ *  - fp[-44] At start (if 1, we are starting at the start of the
+ *    string, otherwise 0)
+ *  - fp[-48] register 0         (Only positions must be stored in the first
+ *  -         register 1          num_saved_registers_ registers)
+ *  -         ...
+ *  -         register num_registers-1
+ *  --- sp ---
+ *
+ * The first num_saved_registers_ registers are initialized to point to
+ * "character -1" in the string (i.e., char_size() bytes before the first
+ * character of the string). The remaining registers start out as garbage.
+ *
+ * The data up to the return address must be placed there by the calling
+ * code and the remaining arguments are passed in registers, e.g. by calling the
+ * code entry as cast to a function with the signature:
+ * int (*match)(String* input_string,
+ *              int start_index,
+ *              Address start,
+ *              Address end,
+ *              int* capture_output_array,
+ *              byte* stack_area_base,
+ *              Address secondary_return_address,  // Only used by native call.
+ *              bool direct_call = false)
+ * The call is performed by NativeRegExpMacroAssembler::Execute()
+ * (in regexp-macro-assembler.cc) via the CALL_GENERATED_REGEXP_CODE macro
+ * in ppc/simulator-ppc.h.
+ * When calling as a non-direct call (i.e., from C++ code), the return address
+ * area is overwritten with the LR register by the RegExp code. When doing a
+ * direct call from generated code, the return address is placed there by
+ * the calling code, as in a normal exit frame.
+ */
+
+#define __ ACCESS_MASM(masm_)
+
+RegExpMacroAssemblerPPC::RegExpMacroAssemblerPPC(Mode mode,
+                                                 int registers_to_save,
+                                                 Zone* zone)
+    : NativeRegExpMacroAssembler(zone),
+      masm_(new MacroAssembler(zone->isolate(), NULL, kRegExpCodeSize)),
+      mode_(mode),
+      num_registers_(registers_to_save),
+      num_saved_registers_(registers_to_save),
+      entry_label_(),
+      start_label_(),
+      success_label_(),
+      backtrack_label_(),
+      exit_label_(),
+      internal_failure_label_() {
+  DCHECK_EQ(0, registers_to_save % 2);
+
+// Called from C
+#if ABI_USES_FUNCTION_DESCRIPTORS
+  __ function_descriptor();
+#endif
+
+  __ b(&entry_label_);  // We'll write the entry code later.
+  // If the code gets too big or corrupted, an internal exception will be
+  // raised, and we will exit right away.
+  __ bind(&internal_failure_label_);
+  __ li(r3, Operand(FAILURE));
+  __ Ret();
+  __ bind(&start_label_);  // And then continue from here.
+}
+
+
+RegExpMacroAssemblerPPC::~RegExpMacroAssemblerPPC() {
+  delete masm_;
+  // Unuse labels in case we throw away the assembler without calling GetCode.
+  entry_label_.Unuse();
+  start_label_.Unuse();
+  success_label_.Unuse();
+  backtrack_label_.Unuse();
+  exit_label_.Unuse();
+  check_preempt_label_.Unuse();
+  stack_overflow_label_.Unuse();
+  internal_failure_label_.Unuse();
+}
+
+
+int RegExpMacroAssemblerPPC::stack_limit_slack() {
+  return RegExpStack::kStackLimitSlack;
+}
+
+
+void RegExpMacroAssemblerPPC::AdvanceCurrentPosition(int by) {
+  if (by != 0) {
+    __ addi(current_input_offset(), current_input_offset(),
+            Operand(by * char_size()));
+  }
+}
+
+
+void RegExpMacroAssemblerPPC::AdvanceRegister(int reg, int by) {
+  DCHECK(reg >= 0);
+  DCHECK(reg < num_registers_);
+  if (by != 0) {
+    __ LoadP(r3, register_location(reg), r0);
+    __ mov(r0, Operand(by));
+    __ add(r3, r3, r0);
+    __ StoreP(r3, register_location(reg), r0);
+  }
+}
+
+
+void RegExpMacroAssemblerPPC::Backtrack() {
+  CheckPreemption();
+  // Pop Code* offset from backtrack stack, add Code* and jump to location.
+  Pop(r3);
+  __ add(r3, r3, code_pointer());
+  __ mtctr(r3);
+  __ bctr();
+}
+
+
+void RegExpMacroAssemblerPPC::Bind(Label* label) { __ bind(label); }
+
+
+void RegExpMacroAssemblerPPC::CheckCharacter(uint32_t c, Label* on_equal) {
+  __ Cmpli(current_character(), Operand(c), r0);
+  BranchOrBacktrack(eq, on_equal);
+}
+
+
+void RegExpMacroAssemblerPPC::CheckCharacterGT(uc16 limit, Label* on_greater) {
+  __ Cmpli(current_character(), Operand(limit), r0);
+  BranchOrBacktrack(gt, on_greater);
+}
+
+
+void RegExpMacroAssemblerPPC::CheckAtStart(Label* on_at_start) {
+  Label not_at_start;
+  // Did we start the match at the start of the string at all?
+  __ LoadP(r3, MemOperand(frame_pointer(), kStartIndex));
+  __ cmpi(r3, Operand::Zero());
+  BranchOrBacktrack(ne, &not_at_start);
+
+  // If we did, are we still at the start of the input?
+  __ LoadP(r4, MemOperand(frame_pointer(), kInputStart));
+  __ mr(r0, current_input_offset());
+  __ add(r3, end_of_input_address(), r0);
+  __ cmp(r4, r3);
+  BranchOrBacktrack(eq, on_at_start);
+  __ bind(&not_at_start);
+}
+
+
+void RegExpMacroAssemblerPPC::CheckNotAtStart(Label* on_not_at_start) {
+  // Did we start the match at the start of the string at all?
+  __ LoadP(r3, MemOperand(frame_pointer(), kStartIndex));
+  __ cmpi(r3, Operand::Zero());
+  BranchOrBacktrack(ne, on_not_at_start);
+  // If we did, are we still at the start of the input?
+  __ LoadP(r4, MemOperand(frame_pointer(), kInputStart));
+  __ add(r3, end_of_input_address(), current_input_offset());
+  __ cmp(r3, r4);
+  BranchOrBacktrack(ne, on_not_at_start);
+}
+
+
+void RegExpMacroAssemblerPPC::CheckCharacterLT(uc16 limit, Label* on_less) {
+  __ Cmpli(current_character(), Operand(limit), r0);
+  BranchOrBacktrack(lt, on_less);
+}
+
+
+void RegExpMacroAssemblerPPC::CheckGreedyLoop(Label* on_equal) {
+  Label backtrack_non_equal;
+  __ LoadP(r3, MemOperand(backtrack_stackpointer(), 0));
+  __ cmp(current_input_offset(), r3);
+  __ bne(&backtrack_non_equal);
+  __ addi(backtrack_stackpointer(), backtrack_stackpointer(),
+          Operand(kPointerSize));
+
+  __ bind(&backtrack_non_equal);
+  BranchOrBacktrack(eq, on_equal);
+}
+
+
+void RegExpMacroAssemblerPPC::CheckNotBackReferenceIgnoreCase(
+    int start_reg, Label* on_no_match) {
+  Label fallthrough;
+  __ LoadP(r3, register_location(start_reg), r0);  // Index of start of capture
+  __ LoadP(r4, register_location(start_reg + 1), r0);  // Index of end
+  __ sub(r4, r4, r3, LeaveOE, SetRC);                  // Length of capture.
+
+  // If length is zero, either the capture is empty or it is not participating.
+  // In either case succeed immediately.
+  __ beq(&fallthrough, cr0);
+
+  // Check that there are enough characters left in the input.
+  __ add(r0, r4, current_input_offset(), LeaveOE, SetRC);
+  //  __ cmn(r1, Operand(current_input_offset()));
+  BranchOrBacktrack(gt, on_no_match, cr0);
+
+  if (mode_ == LATIN1) {
+    Label success;
+    Label fail;
+    Label loop_check;
+
+    // r3 - offset of start of capture
+    // r4 - length of capture
+    __ add(r3, r3, end_of_input_address());
+    __ add(r5, end_of_input_address(), current_input_offset());
+    __ add(r4, r3, r4);
+
+    // r3 - Address of start of capture.
+    // r4 - Address of end of capture
+    // r5 - Address of current input position.
+
+    Label loop;
+    __ bind(&loop);
+    __ lbz(r6, MemOperand(r3));
+    __ addi(r3, r3, Operand(char_size()));
+    __ lbz(r25, MemOperand(r5));
+    __ addi(r5, r5, Operand(char_size()));
+    __ cmp(r25, r6);
+    __ beq(&loop_check);
+
+    // Mismatch, try case-insensitive match (converting letters to lower-case).
+    __ ori(r6, r6, Operand(0x20));  // Convert capture character to lower-case.
+    __ ori(r25, r25, Operand(0x20));  // Also convert input character.
+    __ cmp(r25, r6);
+    __ bne(&fail);
+    __ subi(r6, r6, Operand('a'));
+    __ cmpli(r6, Operand('z' - 'a'));  // Is r6 a lowercase letter?
+    __ ble(&loop_check);               // In range 'a'-'z'.
+    // Latin-1: Check for values in range [224,254] but not 247.
+    __ subi(r6, r6, Operand(224 - 'a'));
+    __ cmpli(r6, Operand(254 - 224));
+    __ bgt(&fail);                    // Weren't Latin-1 letters.
+    __ cmpi(r6, Operand(247 - 224));  // Check for 247.
+    __ beq(&fail);
+
+    __ bind(&loop_check);
+    __ cmp(r3, r4);
+    __ blt(&loop);
+    __ b(&success);
+
+    __ bind(&fail);
+    BranchOrBacktrack(al, on_no_match);
+
+    __ bind(&success);
+    // Compute new value of character position after the matched part.
+    __ sub(current_input_offset(), r5, end_of_input_address());
+  } else {
+    DCHECK(mode_ == UC16);
+    int argument_count = 4;
+    __ PrepareCallCFunction(argument_count, r5);
+
+    // r3 - offset of start of capture
+    // r4 - length of capture
+
+    // Put arguments into arguments registers.
+    // Parameters are
+    //   r3: Address byte_offset1 - Address captured substring's start.
+    //   r4: Address byte_offset2 - Address of current character position.
+    //   r5: size_t byte_length - length of capture in bytes(!)
+    //   r6: Isolate* isolate
+
+    // Address of start of capture.
+    __ add(r3, r3, end_of_input_address());
+    // Length of capture.
+    __ mr(r5, r4);
+    // Save length in callee-save register for use on return.
+    __ mr(r25, r4);
+    // Address of current input position.
+    __ add(r4, current_input_offset(), end_of_input_address());
+    // Isolate.
+    __ mov(r6, Operand(ExternalReference::isolate_address(isolate())));
+
+    {
+      AllowExternalCallThatCantCauseGC scope(masm_);
+      ExternalReference function =
+          ExternalReference::re_case_insensitive_compare_uc16(isolate());
+      __ CallCFunction(function, argument_count);
+    }
+
+    // Check if function returned non-zero for success or zero for failure.
+    __ cmpi(r3, Operand::Zero());
+    BranchOrBacktrack(eq, on_no_match);
+    // On success, increment position by length of capture.
+    __ add(current_input_offset(), current_input_offset(), r25);
+  }
+
+  __ bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerPPC::CheckNotBackReference(int start_reg,
+                                                    Label* on_no_match) {
+  Label fallthrough;
+  Label success;
+
+  // Find length of back-referenced capture.
+  __ LoadP(r3, register_location(start_reg), r0);
+  __ LoadP(r4, register_location(start_reg + 1), r0);
+  __ sub(r4, r4, r3, LeaveOE, SetRC);  // Length to check.
+  // Succeed on empty capture (including no capture).
+  __ beq(&fallthrough, cr0);
+
+  // Check that there are enough characters left in the input.
+  __ add(r0, r4, current_input_offset(), LeaveOE, SetRC);
+  BranchOrBacktrack(gt, on_no_match, cr0);
+
+  // Compute pointers to match string and capture string
+  __ add(r3, r3, end_of_input_address());
+  __ add(r5, end_of_input_address(), current_input_offset());
+  __ add(r4, r4, r3);
+
+  Label loop;
+  __ bind(&loop);
+  if (mode_ == LATIN1) {
+    __ lbz(r6, MemOperand(r3));
+    __ addi(r3, r3, Operand(char_size()));
+    __ lbz(r25, MemOperand(r5));
+    __ addi(r5, r5, Operand(char_size()));
+  } else {
+    DCHECK(mode_ == UC16);
+    __ lhz(r6, MemOperand(r3));
+    __ addi(r3, r3, Operand(char_size()));
+    __ lhz(r25, MemOperand(r5));
+    __ addi(r5, r5, Operand(char_size()));
+  }
+  __ cmp(r6, r25);
+  BranchOrBacktrack(ne, on_no_match);
+  __ cmp(r3, r4);
+  __ blt(&loop);
+
+  // Move current character position to position after match.
+  __ sub(current_input_offset(), r5, end_of_input_address());
+  __ bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerPPC::CheckNotCharacter(unsigned c,
+                                                Label* on_not_equal) {
+  __ Cmpli(current_character(), Operand(c), r0);
+  BranchOrBacktrack(ne, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerPPC::CheckCharacterAfterAnd(uint32_t c, uint32_t mask,
+                                                     Label* on_equal) {
+  __ mov(r0, Operand(mask));
+  if (c == 0) {
+    __ and_(r3, current_character(), r0, SetRC);
+  } else {
+    __ and_(r3, current_character(), r0);
+    __ Cmpli(r3, Operand(c), r0, cr0);
+  }
+  BranchOrBacktrack(eq, on_equal, cr0);
+}
+
+
+void RegExpMacroAssemblerPPC::CheckNotCharacterAfterAnd(unsigned c,
+                                                        unsigned mask,
+                                                        Label* on_not_equal) {
+  __ mov(r0, Operand(mask));
+  if (c == 0) {
+    __ and_(r3, current_character(), r0, SetRC);
+  } else {
+    __ and_(r3, current_character(), r0);
+    __ Cmpli(r3, Operand(c), r0, cr0);
+  }
+  BranchOrBacktrack(ne, on_not_equal, cr0);
+}
+
+
+void RegExpMacroAssemblerPPC::CheckNotCharacterAfterMinusAnd(
+    uc16 c, uc16 minus, uc16 mask, Label* on_not_equal) {
+  DCHECK(minus < String::kMaxUtf16CodeUnit);
+  __ subi(r3, current_character(), Operand(minus));
+  __ mov(r0, Operand(mask));
+  __ and_(r3, r3, r0);
+  __ Cmpli(r3, Operand(c), r0);
+  BranchOrBacktrack(ne, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerPPC::CheckCharacterInRange(uc16 from, uc16 to,
+                                                    Label* on_in_range) {
+  __ mov(r0, Operand(from));
+  __ sub(r3, current_character(), r0);
+  __ Cmpli(r3, Operand(to - from), r0);
+  BranchOrBacktrack(le, on_in_range);  // Unsigned lower-or-same condition.
+}
+
+
+void RegExpMacroAssemblerPPC::CheckCharacterNotInRange(uc16 from, uc16 to,
+                                                       Label* on_not_in_range) {
+  __ mov(r0, Operand(from));
+  __ sub(r3, current_character(), r0);
+  __ Cmpli(r3, Operand(to - from), r0);
+  BranchOrBacktrack(gt, on_not_in_range);  // Unsigned higher condition.
+}
+
+
+void RegExpMacroAssemblerPPC::CheckBitInTable(Handle<ByteArray> table,
+                                              Label* on_bit_set) {
+  __ mov(r3, Operand(table));
+  if (mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) {
+    __ andi(r4, current_character(), Operand(kTableSize - 1));
+    __ addi(r4, r4, Operand(ByteArray::kHeaderSize - kHeapObjectTag));
+  } else {
+    __ addi(r4, current_character(),
+            Operand(ByteArray::kHeaderSize - kHeapObjectTag));
+  }
+  __ lbzx(r3, MemOperand(r3, r4));
+  __ cmpi(r3, Operand::Zero());
+  BranchOrBacktrack(ne, on_bit_set);
+}
+
+
+bool RegExpMacroAssemblerPPC::CheckSpecialCharacterClass(uc16 type,
+                                                         Label* on_no_match) {
+  // Range checks (c in min..max) are generally implemented by an unsigned
+  // (c - min) <= (max - min) check
+  switch (type) {
+    case 's':
+      // Match space-characters
+      if (mode_ == LATIN1) {
+        // One byte space characters are '\t'..'\r', ' ' and \u00a0.
+        Label success;
+        __ cmpi(current_character(), Operand(' '));
+        __ beq(&success);
+        // Check range 0x09..0x0d
+        __ subi(r3, current_character(), Operand('\t'));
+        __ cmpli(r3, Operand('\r' - '\t'));
+        __ ble(&success);
+        // \u00a0 (NBSP).
+        __ cmpi(r3, Operand(0x00a0 - '\t'));
+        BranchOrBacktrack(ne, on_no_match);
+        __ bind(&success);
+        return true;
+      }
+      return false;
+    case 'S':
+      // The emitted code for generic character classes is good enough.
+      return false;
+    case 'd':
+      // Match ASCII digits ('0'..'9')
+      __ subi(r3, current_character(), Operand('0'));
+      __ cmpli(r3, Operand('9' - '0'));
+      BranchOrBacktrack(gt, on_no_match);
+      return true;
+    case 'D':
+      // Match non ASCII-digits
+      __ subi(r3, current_character(), Operand('0'));
+      __ cmpli(r3, Operand('9' - '0'));
+      BranchOrBacktrack(le, on_no_match);
+      return true;
+    case '.': {
+      // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
+      __ xori(r3, current_character(), Operand(0x01));
+      // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
+      __ subi(r3, r3, Operand(0x0b));
+      __ cmpli(r3, Operand(0x0c - 0x0b));
+      BranchOrBacktrack(le, on_no_match);
+      if (mode_ == UC16) {
+        // Compare original value to 0x2028 and 0x2029, using the already
+        // computed (current_char ^ 0x01 - 0x0b). I.e., check for
+        // 0x201d (0x2028 - 0x0b) or 0x201e.
+        __ subi(r3, r3, Operand(0x2028 - 0x0b));
+        __ cmpli(r3, Operand(1));
+        BranchOrBacktrack(le, on_no_match);
+      }
+      return true;
+    }
+    case 'n': {
+      // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
+      __ xori(r3, current_character(), Operand(0x01));
+      // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
+      __ subi(r3, r3, Operand(0x0b));
+      __ cmpli(r3, Operand(0x0c - 0x0b));
+      if (mode_ == LATIN1) {
+        BranchOrBacktrack(gt, on_no_match);
+      } else {
+        Label done;
+        __ ble(&done);
+        // Compare original value to 0x2028 and 0x2029, using the already
+        // computed (current_char ^ 0x01 - 0x0b). I.e., check for
+        // 0x201d (0x2028 - 0x0b) or 0x201e.
+        __ subi(r3, r3, Operand(0x2028 - 0x0b));
+        __ cmpli(r3, Operand(1));
+        BranchOrBacktrack(gt, on_no_match);
+        __ bind(&done);
+      }
+      return true;
+    }
+    case 'w': {
+      if (mode_ != LATIN1) {
+        // Table is 256 entries, so all Latin1 characters can be tested.
+        __ cmpi(current_character(), Operand('z'));
+        BranchOrBacktrack(gt, on_no_match);
+      }
+      ExternalReference map = ExternalReference::re_word_character_map();
+      __ mov(r3, Operand(map));
+      __ lbzx(r3, MemOperand(r3, current_character()));
+      __ cmpli(r3, Operand::Zero());
+      BranchOrBacktrack(eq, on_no_match);
+      return true;
+    }
+    case 'W': {
+      Label done;
+      if (mode_ != LATIN1) {
+        // Table is 256 entries, so all Latin1 characters can be tested.
+        __ cmpli(current_character(), Operand('z'));
+        __ bgt(&done);
+      }
+      ExternalReference map = ExternalReference::re_word_character_map();
+      __ mov(r3, Operand(map));
+      __ lbzx(r3, MemOperand(r3, current_character()));
+      __ cmpli(r3, Operand::Zero());
+      BranchOrBacktrack(ne, on_no_match);
+      if (mode_ != LATIN1) {
+        __ bind(&done);
+      }
+      return true;
+    }
+    case '*':
+      // Match any character.
+      return true;
+    // No custom implementation (yet): s(UC16), S(UC16).
+    default:
+      return false;
+  }
+}
+
+
+void RegExpMacroAssemblerPPC::Fail() {
+  __ li(r3, Operand(FAILURE));
+  __ b(&exit_label_);
+}
+
+
+Handle<HeapObject> RegExpMacroAssemblerPPC::GetCode(Handle<String> source) {
+  Label return_r3;
+
+  if (masm_->has_exception()) {
+    // If the code gets corrupted due to long regular expressions and lack of
+    // space on trampolines, an internal exception flag is set. If this case
+    // is detected, we will jump into exit sequence right away.
+    __ bind_to(&entry_label_, internal_failure_label_.pos());
+  } else {
+    // Finalize code - write the entry point code now we know how many
+    // registers we need.
+
+    // Entry code:
+    __ bind(&entry_label_);
+
+    // Tell the system that we have a stack frame.  Because the type
+    // is MANUAL, no is generated.
+    FrameScope scope(masm_, StackFrame::MANUAL);
+
+    // Ensure register assigments are consistent with callee save mask
+    DCHECK(r25.bit() & kRegExpCalleeSaved);
+    DCHECK(code_pointer().bit() & kRegExpCalleeSaved);
+    DCHECK(current_input_offset().bit() & kRegExpCalleeSaved);
+    DCHECK(current_character().bit() & kRegExpCalleeSaved);
+    DCHECK(backtrack_stackpointer().bit() & kRegExpCalleeSaved);
+    DCHECK(end_of_input_address().bit() & kRegExpCalleeSaved);
+    DCHECK(frame_pointer().bit() & kRegExpCalleeSaved);
+
+    // Actually emit code to start a new stack frame.
+    // Push arguments
+    // Save callee-save registers.
+    // Start new stack frame.
+    // Store link register in existing stack-cell.
+    // Order here should correspond to order of offset constants in header file.
+    RegList registers_to_retain = kRegExpCalleeSaved;
+    RegList argument_registers = r3.bit() | r4.bit() | r5.bit() | r6.bit() |
+                                 r7.bit() | r8.bit() | r9.bit() | r10.bit();
+    __ mflr(r0);
+    __ push(r0);
+    __ MultiPush(argument_registers | registers_to_retain);
+    // Set frame pointer in space for it if this is not a direct call
+    // from generated code.
+    __ addi(frame_pointer(), sp, Operand(8 * kPointerSize));
+    __ li(r3, Operand::Zero());
+    __ push(r3);  // Make room for success counter and initialize it to 0.
+    __ push(r3);  // Make room for "position - 1" constant (value is irrelevant)
+    // Check if we have space on the stack for registers.
+    Label stack_limit_hit;
+    Label stack_ok;
+
+    ExternalReference stack_limit =
+        ExternalReference::address_of_stack_limit(isolate());
+    __ mov(r3, Operand(stack_limit));
+    __ LoadP(r3, MemOperand(r3));
+    __ sub(r3, sp, r3, LeaveOE, SetRC);
+    // Handle it if the stack pointer is already below the stack limit.
+    __ ble(&stack_limit_hit, cr0);
+    // Check if there is room for the variable number of registers above
+    // the stack limit.
+    __ Cmpli(r3, Operand(num_registers_ * kPointerSize), r0);
+    __ bge(&stack_ok);
+    // Exit with OutOfMemory exception. There is not enough space on the stack
+    // for our working registers.
+    __ li(r3, Operand(EXCEPTION));
+    __ b(&return_r3);
+
+    __ bind(&stack_limit_hit);
+    CallCheckStackGuardState(r3);
+    __ cmpi(r3, Operand::Zero());
+    // If returned value is non-zero, we exit with the returned value as result.
+    __ bne(&return_r3);
+
+    __ bind(&stack_ok);
+
+    // Allocate space on stack for registers.
+    __ Add(sp, sp, -num_registers_ * kPointerSize, r0);
+    // Load string end.
+    __ LoadP(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
+    // Load input start.
+    __ LoadP(r3, MemOperand(frame_pointer(), kInputStart));
+    // Find negative length (offset of start relative to end).
+    __ sub(current_input_offset(), r3, end_of_input_address());
+    // Set r3 to address of char before start of the input string
+    // (effectively string position -1).
+    __ LoadP(r4, MemOperand(frame_pointer(), kStartIndex));
+    __ subi(r3, current_input_offset(), Operand(char_size()));
+    if (mode_ == UC16) {
+      __ ShiftLeftImm(r0, r4, Operand(1));
+      __ sub(r3, r3, r0);
+    } else {
+      __ sub(r3, r3, r4);
+    }
+    // Store this value in a local variable, for use when clearing
+    // position registers.
+    __ StoreP(r3, MemOperand(frame_pointer(), kInputStartMinusOne));
+
+    // Initialize code pointer register
+    __ mov(code_pointer(), Operand(masm_->CodeObject()));
+
+    Label load_char_start_regexp, start_regexp;
+    // Load newline if index is at start, previous character otherwise.
+    __ cmpi(r4, Operand::Zero());
+    __ bne(&load_char_start_regexp);
+    __ li(current_character(), Operand('\n'));
+    __ b(&start_regexp);
+
+    // Global regexp restarts matching here.
+    __ bind(&load_char_start_regexp);
+    // Load previous char as initial value of current character register.
+    LoadCurrentCharacterUnchecked(-1, 1);
+    __ bind(&start_regexp);
+
+    // Initialize on-stack registers.
+    if (num_saved_registers_ > 0) {  // Always is, if generated from a regexp.
+      // Fill saved registers with initial value = start offset - 1
+      if (num_saved_registers_ > 8) {
+        // One slot beyond address of register 0.
+        __ addi(r4, frame_pointer(), Operand(kRegisterZero + kPointerSize));
+        __ li(r5, Operand(num_saved_registers_));
+        __ mtctr(r5);
+        Label init_loop;
+        __ bind(&init_loop);
+        __ StorePU(r3, MemOperand(r4, -kPointerSize));
+        __ bdnz(&init_loop);
+      } else {
+        for (int i = 0; i < num_saved_registers_; i++) {
+          __ StoreP(r3, register_location(i), r0);
+        }
+      }
+    }
+
+    // Initialize backtrack stack pointer.
+    __ LoadP(backtrack_stackpointer(),
+             MemOperand(frame_pointer(), kStackHighEnd));
+
+    __ b(&start_label_);
+
+    // Exit code:
+    if (success_label_.is_linked()) {
+      // Save captures when successful.
+      __ bind(&success_label_);
+      if (num_saved_registers_ > 0) {
+        // copy captures to output
+        __ LoadP(r4, MemOperand(frame_pointer(), kInputStart));
+        __ LoadP(r3, MemOperand(frame_pointer(), kRegisterOutput));
+        __ LoadP(r5, MemOperand(frame_pointer(), kStartIndex));
+        __ sub(r4, end_of_input_address(), r4);
+        // r4 is length of input in bytes.
+        if (mode_ == UC16) {
+          __ ShiftRightImm(r4, r4, Operand(1));
+        }
+        // r4 is length of input in characters.
+        __ add(r4, r4, r5);
+        // r4 is length of string in characters.
+
+        DCHECK_EQ(0, num_saved_registers_ % 2);
+        // Always an even number of capture registers. This allows us to
+        // unroll the loop once to add an operation between a load of a register
+        // and the following use of that register.
+        for (int i = 0; i < num_saved_registers_; i += 2) {
+          __ LoadP(r5, register_location(i), r0);
+          __ LoadP(r6, register_location(i + 1), r0);
+          if (i == 0 && global_with_zero_length_check()) {
+            // Keep capture start in r25 for the zero-length check later.
+            __ mr(r25, r5);
+          }
+          if (mode_ == UC16) {
+            __ ShiftRightArithImm(r5, r5, 1);
+            __ add(r5, r4, r5);
+            __ ShiftRightArithImm(r6, r6, 1);
+            __ add(r6, r4, r6);
+          } else {
+            __ add(r5, r4, r5);
+            __ add(r6, r4, r6);
+          }
+          __ stw(r5, MemOperand(r3));
+          __ addi(r3, r3, Operand(kIntSize));
+          __ stw(r6, MemOperand(r3));
+          __ addi(r3, r3, Operand(kIntSize));
+        }
+      }
+
+      if (global()) {
+        // Restart matching if the regular expression is flagged as global.
+        __ LoadP(r3, MemOperand(frame_pointer(), kSuccessfulCaptures));
+        __ LoadP(r4, MemOperand(frame_pointer(), kNumOutputRegisters));
+        __ LoadP(r5, MemOperand(frame_pointer(), kRegisterOutput));
+        // Increment success counter.
+        __ addi(r3, r3, Operand(1));
+        __ StoreP(r3, MemOperand(frame_pointer(), kSuccessfulCaptures));
+        // Capture results have been stored, so the number of remaining global
+        // output registers is reduced by the number of stored captures.
+        __ subi(r4, r4, Operand(num_saved_registers_));
+        // Check whether we have enough room for another set of capture results.
+        __ cmpi(r4, Operand(num_saved_registers_));
+        __ blt(&return_r3);
+
+        __ StoreP(r4, MemOperand(frame_pointer(), kNumOutputRegisters));
+        // Advance the location for output.
+        __ addi(r5, r5, Operand(num_saved_registers_ * kIntSize));
+        __ StoreP(r5, MemOperand(frame_pointer(), kRegisterOutput));
+
+        // Prepare r3 to initialize registers with its value in the next run.
+        __ LoadP(r3, MemOperand(frame_pointer(), kInputStartMinusOne));
+
+        if (global_with_zero_length_check()) {
+          // Special case for zero-length matches.
+          // r25: capture start index
+          __ cmp(current_input_offset(), r25);
+          // Not a zero-length match, restart.
+          __ bne(&load_char_start_regexp);
+          // Offset from the end is zero if we already reached the end.
+          __ cmpi(current_input_offset(), Operand::Zero());
+          __ beq(&exit_label_);
+          // Advance current position after a zero-length match.
+          __ addi(current_input_offset(), current_input_offset(),
+                  Operand((mode_ == UC16) ? 2 : 1));
+        }
+
+        __ b(&load_char_start_regexp);
+      } else {
+        __ li(r3, Operand(SUCCESS));
+      }
+    }
+
+    // Exit and return r3
+    __ bind(&exit_label_);
+    if (global()) {
+      __ LoadP(r3, MemOperand(frame_pointer(), kSuccessfulCaptures));
+    }
+
+    __ bind(&return_r3);
+    // Skip sp past regexp registers and local variables..
+    __ mr(sp, frame_pointer());
+    // Restore registers r25..r31 and return (restoring lr to pc).
+    __ MultiPop(registers_to_retain);
+    __ pop(r0);
+    __ mtctr(r0);
+    __ bctr();
+
+    // Backtrack code (branch target for conditional backtracks).
+    if (backtrack_label_.is_linked()) {
+      __ bind(&backtrack_label_);
+      Backtrack();
+    }
+
+    Label exit_with_exception;
+
+    // Preempt-code
+    if (check_preempt_label_.is_linked()) {
+      SafeCallTarget(&check_preempt_label_);
+
+      CallCheckStackGuardState(r3);
+      __ cmpi(r3, Operand::Zero());
+      // If returning non-zero, we should end execution with the given
+      // result as return value.
+      __ bne(&return_r3);
+
+      // String might have moved: Reload end of string from frame.
+      __ LoadP(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
+      SafeReturn();
+    }
+
+    // Backtrack stack overflow code.
+    if (stack_overflow_label_.is_linked()) {
+      SafeCallTarget(&stack_overflow_label_);
+      // Reached if the backtrack-stack limit has been hit.
+      Label grow_failed;
+
+      // Call GrowStack(backtrack_stackpointer(), &stack_base)
+      static const int num_arguments = 3;
+      __ PrepareCallCFunction(num_arguments, r3);
+      __ mr(r3, backtrack_stackpointer());
+      __ addi(r4, frame_pointer(), Operand(kStackHighEnd));
+      __ mov(r5, Operand(ExternalReference::isolate_address(isolate())));
+      ExternalReference grow_stack =
+          ExternalReference::re_grow_stack(isolate());
+      __ CallCFunction(grow_stack, num_arguments);
+      // If return NULL, we have failed to grow the stack, and
+      // must exit with a stack-overflow exception.
+      __ cmpi(r3, Operand::Zero());
+      __ beq(&exit_with_exception);
+      // Otherwise use return value as new stack pointer.
+      __ mr(backtrack_stackpointer(), r3);
+      // Restore saved registers and continue.
+      SafeReturn();
+    }
+
+    if (exit_with_exception.is_linked()) {
+      // If any of the code above needed to exit with an exception.
+      __ bind(&exit_with_exception);
+      // Exit with Result EXCEPTION(-1) to signal thrown exception.
+      __ li(r3, Operand(EXCEPTION));
+      __ b(&return_r3);
+    }
+  }
+
+  CodeDesc code_desc;
+  masm_->GetCode(&code_desc);
+  Handle<Code> code = isolate()->factory()->NewCode(
+      code_desc, Code::ComputeFlags(Code::REGEXP), masm_->CodeObject());
+  PROFILE(masm_->isolate(), RegExpCodeCreateEvent(*code, *source));
+  return Handle<HeapObject>::cast(code);
+}
+
+
+void RegExpMacroAssemblerPPC::GoTo(Label* to) { BranchOrBacktrack(al, to); }
+
+
+void RegExpMacroAssemblerPPC::IfRegisterGE(int reg, int comparand,
+                                           Label* if_ge) {
+  __ LoadP(r3, register_location(reg), r0);
+  __ Cmpi(r3, Operand(comparand), r0);
+  BranchOrBacktrack(ge, if_ge);
+}
+
+
+void RegExpMacroAssemblerPPC::IfRegisterLT(int reg, int comparand,
+                                           Label* if_lt) {
+  __ LoadP(r3, register_location(reg), r0);
+  __ Cmpi(r3, Operand(comparand), r0);
+  BranchOrBacktrack(lt, if_lt);
+}
+
+
+void RegExpMacroAssemblerPPC::IfRegisterEqPos(int reg, Label* if_eq) {
+  __ LoadP(r3, register_location(reg), r0);
+  __ cmp(r3, current_input_offset());
+  BranchOrBacktrack(eq, if_eq);
+}
+
+
+RegExpMacroAssembler::IrregexpImplementation
+RegExpMacroAssemblerPPC::Implementation() {
+  return kPPCImplementation;
+}
+
+
+void RegExpMacroAssemblerPPC::LoadCurrentCharacter(int cp_offset,
+                                                   Label* on_end_of_input,
+                                                   bool check_bounds,
+                                                   int characters) {
+  DCHECK(cp_offset >= -1);        // ^ and \b can look behind one character.
+  DCHECK(cp_offset < (1 << 30));  // Be sane! (And ensure negation works)
+  if (check_bounds) {
+    CheckPosition(cp_offset + characters - 1, on_end_of_input);
+  }
+  LoadCurrentCharacterUnchecked(cp_offset, characters);
+}
+
+
+void RegExpMacroAssemblerPPC::PopCurrentPosition() {
+  Pop(current_input_offset());
+}
+
+
+void RegExpMacroAssemblerPPC::PopRegister(int register_index) {
+  Pop(r3);
+  __ StoreP(r3, register_location(register_index), r0);
+}
+
+
+void RegExpMacroAssemblerPPC::PushBacktrack(Label* label) {
+  __ mov_label_offset(r3, label);
+  Push(r3);
+  CheckStackLimit();
+}
+
+
+void RegExpMacroAssemblerPPC::PushCurrentPosition() {
+  Push(current_input_offset());
+}
+
+
+void RegExpMacroAssemblerPPC::PushRegister(int register_index,
+                                           StackCheckFlag check_stack_limit) {
+  __ LoadP(r3, register_location(register_index), r0);
+  Push(r3);
+  if (check_stack_limit) CheckStackLimit();
+}
+
+
+void RegExpMacroAssemblerPPC::ReadCurrentPositionFromRegister(int reg) {
+  __ LoadP(current_input_offset(), register_location(reg), r0);
+}
+
+
+void RegExpMacroAssemblerPPC::ReadStackPointerFromRegister(int reg) {
+  __ LoadP(backtrack_stackpointer(), register_location(reg), r0);
+  __ LoadP(r3, MemOperand(frame_pointer(), kStackHighEnd));
+  __ add(backtrack_stackpointer(), backtrack_stackpointer(), r3);
+}
+
+
+void RegExpMacroAssemblerPPC::SetCurrentPositionFromEnd(int by) {
+  Label after_position;
+  __ Cmpi(current_input_offset(), Operand(-by * char_size()), r0);
+  __ bge(&after_position);
+  __ mov(current_input_offset(), Operand(-by * char_size()));
+  // On RegExp code entry (where this operation is used), the character before
+  // the current position is expected to be already loaded.
+  // We have advanced the position, so it's safe to read backwards.
+  LoadCurrentCharacterUnchecked(-1, 1);
+  __ bind(&after_position);
+}
+
+
+void RegExpMacroAssemblerPPC::SetRegister(int register_index, int to) {
+  DCHECK(register_index >= num_saved_registers_);  // Reserved for positions!
+  __ mov(r3, Operand(to));
+  __ StoreP(r3, register_location(register_index), r0);
+}
+
+
+bool RegExpMacroAssemblerPPC::Succeed() {
+  __ b(&success_label_);
+  return global();
+}
+
+
+void RegExpMacroAssemblerPPC::WriteCurrentPositionToRegister(int reg,
+                                                             int cp_offset) {
+  if (cp_offset == 0) {
+    __ StoreP(current_input_offset(), register_location(reg), r0);
+  } else {
+    __ mov(r0, Operand(cp_offset * char_size()));
+    __ add(r3, current_input_offset(), r0);
+    __ StoreP(r3, register_location(reg), r0);
+  }
+}
+
+
+void RegExpMacroAssemblerPPC::ClearRegisters(int reg_from, int reg_to) {
+  DCHECK(reg_from <= reg_to);
+  __ LoadP(r3, MemOperand(frame_pointer(), kInputStartMinusOne));
+  for (int reg = reg_from; reg <= reg_to; reg++) {
+    __ StoreP(r3, register_location(reg), r0);
+  }
+}
+
+
+void RegExpMacroAssemblerPPC::WriteStackPointerToRegister(int reg) {
+  __ LoadP(r4, MemOperand(frame_pointer(), kStackHighEnd));
+  __ sub(r3, backtrack_stackpointer(), r4);
+  __ StoreP(r3, register_location(reg), r0);
+}
+
+
+// Private methods:
+
+void RegExpMacroAssemblerPPC::CallCheckStackGuardState(Register scratch) {
+  int frame_alignment = masm_->ActivationFrameAlignment();
+  int stack_space = kNumRequiredStackFrameSlots;
+  int stack_passed_arguments = 1;  // space for return address pointer
+
+  // The following stack manipulation logic is similar to
+  // PrepareCallCFunction.  However, we need an extra slot on the
+  // stack to house the return address parameter.
+  if (frame_alignment > kPointerSize) {
+    // Make stack end at alignment and make room for stack arguments
+    // -- preserving original value of sp.
+    __ mr(scratch, sp);
+    __ addi(sp, sp, Operand(-(stack_passed_arguments + 1) * kPointerSize));
+    DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
+    __ ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
+    __ StoreP(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
+  } else {
+    // Make room for stack arguments
+    stack_space += stack_passed_arguments;
+  }
+
+  // Allocate frame with required slots to make ABI work.
+  __ li(r0, Operand::Zero());
+  __ StorePU(r0, MemOperand(sp, -stack_space * kPointerSize));
+
+  // RegExp code frame pointer.
+  __ mr(r5, frame_pointer());
+  // Code* of self.
+  __ mov(r4, Operand(masm_->CodeObject()));
+  // r3 will point to the return address, placed by DirectCEntry.
+  __ addi(r3, sp, Operand(kStackFrameExtraParamSlot * kPointerSize));
+
+  ExternalReference stack_guard_check =
+      ExternalReference::re_check_stack_guard_state(isolate());
+  __ mov(ip, Operand(stack_guard_check));
+  DirectCEntryStub stub(isolate());
+  stub.GenerateCall(masm_, ip);
+
+  // Restore the stack pointer
+  stack_space = kNumRequiredStackFrameSlots + stack_passed_arguments;
+  if (frame_alignment > kPointerSize) {
+    __ LoadP(sp, MemOperand(sp, stack_space * kPointerSize));
+  } else {
+    __ addi(sp, sp, Operand(stack_space * kPointerSize));
+  }
+
+  __ mov(code_pointer(), Operand(masm_->CodeObject()));
+}
+
+
+// Helper function for reading a value out of a stack frame.
+template <typename T>
+static T& frame_entry(Address re_frame, int frame_offset) {
+  return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
+}
+
+
+int RegExpMacroAssemblerPPC::CheckStackGuardState(Address* return_address,
+                                                  Code* re_code,
+                                                  Address re_frame) {
+  Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
+  StackLimitCheck check(isolate);
+  if (check.JsHasOverflowed()) {
+    isolate->StackOverflow();
+    return EXCEPTION;
+  }
+
+  // If not real stack overflow the stack guard was used to interrupt
+  // execution for another purpose.
+
+  // If this is a direct call from JavaScript retry the RegExp forcing the call
+  // through the runtime system. Currently the direct call cannot handle a GC.
+  if (frame_entry<int>(re_frame, kDirectCall) == 1) {
+    return RETRY;
+  }
+
+  // Prepare for possible GC.
+  HandleScope handles(isolate);
+  Handle<Code> code_handle(re_code);
+
+  Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
+
+  // Current string.
+  bool is_one_byte = subject->IsOneByteRepresentationUnderneath();
+
+  DCHECK(re_code->instruction_start() <= *return_address);
+  DCHECK(*return_address <=
+         re_code->instruction_start() + re_code->instruction_size());
+
+  Object* result = isolate->stack_guard()->HandleInterrupts();
+
+  if (*code_handle != re_code) {  // Return address no longer valid
+    intptr_t delta = code_handle->address() - re_code->address();
+    // Overwrite the return address on the stack.
+    *return_address += delta;
+  }
+
+  if (result->IsException()) {
+    return EXCEPTION;
+  }
+
+  Handle<String> subject_tmp = subject;
+  int slice_offset = 0;
+
+  // Extract the underlying string and the slice offset.
+  if (StringShape(*subject_tmp).IsCons()) {
+    subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
+  } else if (StringShape(*subject_tmp).IsSliced()) {
+    SlicedString* slice = SlicedString::cast(*subject_tmp);
+    subject_tmp = Handle<String>(slice->parent());
+    slice_offset = slice->offset();
+  }
+
+  // String might have changed.
+  if (subject_tmp->IsOneByteRepresentation() != is_one_byte) {
+    // If we changed between an Latin1 and an UC16 string, the specialized
+    // code cannot be used, and we need to restart regexp matching from
+    // scratch (including, potentially, compiling a new version of the code).
+    return RETRY;
+  }
+
+  // Otherwise, the content of the string might have moved. It must still
+  // be a sequential or external string with the same content.
+  // Update the start and end pointers in the stack frame to the current
+  // location (whether it has actually moved or not).
+  DCHECK(StringShape(*subject_tmp).IsSequential() ||
+         StringShape(*subject_tmp).IsExternal());
+
+  // The original start address of the characters to match.
+  const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
+
+  // Find the current start address of the same character at the current string
+  // position.
+  int start_index = frame_entry<intptr_t>(re_frame, kStartIndex);
+  const byte* new_address =
+      StringCharacterPosition(*subject_tmp, start_index + slice_offset);
+
+  if (start_address != new_address) {
+    // If there is a difference, update the object pointer and start and end
+    // addresses in the RegExp stack frame to match the new value.
+    const byte* end_address = frame_entry<const byte*>(re_frame, kInputEnd);
+    int byte_length = static_cast<int>(end_address - start_address);
+    frame_entry<const String*>(re_frame, kInputString) = *subject;
+    frame_entry<const byte*>(re_frame, kInputStart) = new_address;
+    frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
+  } else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
+    // Subject string might have been a ConsString that underwent
+    // short-circuiting during GC. That will not change start_address but
+    // will change pointer inside the subject handle.
+    frame_entry<const String*>(re_frame, kInputString) = *subject;
+  }
+
+  return 0;
+}
+
+
+MemOperand RegExpMacroAssemblerPPC::register_location(int register_index) {
+  DCHECK(register_index < (1 << 30));
+  if (num_registers_ <= register_index) {
+    num_registers_ = register_index + 1;
+  }
+  return MemOperand(frame_pointer(),
+                    kRegisterZero - register_index * kPointerSize);
+}
+
+
+void RegExpMacroAssemblerPPC::CheckPosition(int cp_offset,
+                                            Label* on_outside_input) {
+  __ Cmpi(current_input_offset(), Operand(-cp_offset * char_size()), r0);
+  BranchOrBacktrack(ge, on_outside_input);
+}
+
+
+void RegExpMacroAssemblerPPC::BranchOrBacktrack(Condition condition, Label* to,
+                                                CRegister cr) {
+  if (condition == al) {  // Unconditional.
+    if (to == NULL) {
+      Backtrack();
+      return;
+    }
+    __ b(to);
+    return;
+  }
+  if (to == NULL) {
+    __ b(condition, &backtrack_label_, cr);
+    return;
+  }
+  __ b(condition, to, cr);
+}
+
+
+void RegExpMacroAssemblerPPC::SafeCall(Label* to, Condition cond,
+                                       CRegister cr) {
+  __ b(cond, to, cr, SetLK);
+}
+
+
+void RegExpMacroAssemblerPPC::SafeReturn() {
+  __ pop(r0);
+  __ mov(ip, Operand(masm_->CodeObject()));
+  __ add(r0, r0, ip);
+  __ mtlr(r0);
+  __ blr();
+}
+
+
+void RegExpMacroAssemblerPPC::SafeCallTarget(Label* name) {
+  __ bind(name);
+  __ mflr(r0);
+  __ mov(ip, Operand(masm_->CodeObject()));
+  __ sub(r0, r0, ip);
+  __ push(r0);
+}
+
+
+void RegExpMacroAssemblerPPC::Push(Register source) {
+  DCHECK(!source.is(backtrack_stackpointer()));
+  __ StorePU(source, MemOperand(backtrack_stackpointer(), -kPointerSize));
+}
+
+
+void RegExpMacroAssemblerPPC::Pop(Register target) {
+  DCHECK(!target.is(backtrack_stackpointer()));
+  __ LoadP(target, MemOperand(backtrack_stackpointer()));
+  __ addi(backtrack_stackpointer(), backtrack_stackpointer(),
+          Operand(kPointerSize));
+}
+
+
+void RegExpMacroAssemblerPPC::CheckPreemption() {
+  // Check for preemption.
+  ExternalReference stack_limit =
+      ExternalReference::address_of_stack_limit(isolate());
+  __ mov(r3, Operand(stack_limit));
+  __ LoadP(r3, MemOperand(r3));
+  __ cmpl(sp, r3);
+  SafeCall(&check_preempt_label_, le);
+}
+
+
+void RegExpMacroAssemblerPPC::CheckStackLimit() {
+  ExternalReference stack_limit =
+      ExternalReference::address_of_regexp_stack_limit(isolate());
+  __ mov(r3, Operand(stack_limit));
+  __ LoadP(r3, MemOperand(r3));
+  __ cmpl(backtrack_stackpointer(), r3);
+  SafeCall(&stack_overflow_label_, le);
+}
+
+
+bool RegExpMacroAssemblerPPC::CanReadUnaligned() {
+  return CpuFeatures::IsSupported(UNALIGNED_ACCESSES) && !slow_safe();
+}
+
+
+void RegExpMacroAssemblerPPC::LoadCurrentCharacterUnchecked(int cp_offset,
+                                                            int characters) {
+  Register offset = current_input_offset();
+  if (cp_offset != 0) {
+    // r25 is not being used to store the capture start index at this point.
+    __ addi(r25, current_input_offset(), Operand(cp_offset * char_size()));
+    offset = r25;
+  }
+  // The lwz, stw, lhz, sth instructions can do unaligned accesses, if the CPU
+  // and the operating system running on the target allow it.
+  // We assume we don't want to do unaligned loads on PPC, so this function
+  // must only be used to load a single character at a time.
+
+  DCHECK(characters == 1);
+  __ add(current_character(), end_of_input_address(), offset);
+  if (mode_ == LATIN1) {
+    __ lbz(current_character(), MemOperand(current_character()));
+  } else {
+    DCHECK(mode_ == UC16);
+    __ lhz(current_character(), MemOperand(current_character()));
+  }
+}
+
+
+#undef __
+
+#endif  // V8_INTERPRETED_REGEXP
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ppc/regexp-macro-assembler-ppc.h b/src/ppc/regexp-macro-assembler-ppc.h
new file mode 100644
index 0000000..1f9c3a0
--- /dev/null
+++ b/src/ppc/regexp-macro-assembler-ppc.h
@@ -0,0 +1,212 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PPC_REGEXP_MACRO_ASSEMBLER_PPC_H_
+#define V8_PPC_REGEXP_MACRO_ASSEMBLER_PPC_H_
+
+#include "src/macro-assembler.h"
+#include "src/ppc/assembler-ppc.h"
+#include "src/ppc/assembler-ppc-inl.h"
+
+namespace v8 {
+namespace internal {
+
+
+#ifndef V8_INTERPRETED_REGEXP
+class RegExpMacroAssemblerPPC : public NativeRegExpMacroAssembler {
+ public:
+  RegExpMacroAssemblerPPC(Mode mode, int registers_to_save, Zone* zone);
+  virtual ~RegExpMacroAssemblerPPC();
+  virtual int stack_limit_slack();
+  virtual void AdvanceCurrentPosition(int by);
+  virtual void AdvanceRegister(int reg, int by);
+  virtual void Backtrack();
+  virtual void Bind(Label* label);
+  virtual void CheckAtStart(Label* on_at_start);
+  virtual void CheckCharacter(unsigned c, Label* on_equal);
+  virtual void CheckCharacterAfterAnd(unsigned c, unsigned mask,
+                                      Label* on_equal);
+  virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
+  virtual void CheckCharacterLT(uc16 limit, Label* on_less);
+  // A "greedy loop" is a loop that is both greedy and with a simple
+  // body. It has a particularly simple implementation.
+  virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
+  virtual void CheckNotAtStart(Label* on_not_at_start);
+  virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
+  virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
+                                               Label* on_no_match);
+  virtual void CheckNotCharacter(unsigned c, Label* on_not_equal);
+  virtual void CheckNotCharacterAfterAnd(unsigned c, unsigned mask,
+                                         Label* on_not_equal);
+  virtual void CheckNotCharacterAfterMinusAnd(uc16 c, uc16 minus, uc16 mask,
+                                              Label* on_not_equal);
+  virtual void CheckCharacterInRange(uc16 from, uc16 to, Label* on_in_range);
+  virtual void CheckCharacterNotInRange(uc16 from, uc16 to,
+                                        Label* on_not_in_range);
+  virtual void CheckBitInTable(Handle<ByteArray> table, Label* on_bit_set);
+
+  // Checks whether the given offset from the current position is before
+  // the end of the string.
+  virtual void CheckPosition(int cp_offset, Label* on_outside_input);
+  virtual bool CheckSpecialCharacterClass(uc16 type, Label* on_no_match);
+  virtual void Fail();
+  virtual Handle<HeapObject> GetCode(Handle<String> source);
+  virtual void GoTo(Label* label);
+  virtual void IfRegisterGE(int reg, int comparand, Label* if_ge);
+  virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
+  virtual void IfRegisterEqPos(int reg, Label* if_eq);
+  virtual IrregexpImplementation Implementation();
+  virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input,
+                                    bool check_bounds = true,
+                                    int characters = 1);
+  virtual void PopCurrentPosition();
+  virtual void PopRegister(int register_index);
+  virtual void PushBacktrack(Label* label);
+  virtual void PushCurrentPosition();
+  virtual void PushRegister(int register_index,
+                            StackCheckFlag check_stack_limit);
+  virtual void ReadCurrentPositionFromRegister(int reg);
+  virtual void ReadStackPointerFromRegister(int reg);
+  virtual void SetCurrentPositionFromEnd(int by);
+  virtual void SetRegister(int register_index, int to);
+  virtual bool Succeed();
+  virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
+  virtual void ClearRegisters(int reg_from, int reg_to);
+  virtual void WriteStackPointerToRegister(int reg);
+  virtual bool CanReadUnaligned();
+
+  // Called from RegExp if the stack-guard is triggered.
+  // If the code object is relocated, the return address is fixed before
+  // returning.
+  static int CheckStackGuardState(Address* return_address, Code* re_code,
+                                  Address re_frame);
+
+ private:
+  // Offsets from frame_pointer() of function parameters and stored registers.
+  static const int kFramePointer = 0;
+
+  // Above the frame pointer - Stored registers and stack passed parameters.
+  // Register 25..31.
+  static const int kStoredRegisters = kFramePointer;
+  // Return address (stored from link register, read into pc on return).
+  static const int kReturnAddress = kStoredRegisters + 7 * kPointerSize;
+  static const int kCallerFrame = kReturnAddress + kPointerSize;
+  // Stack parameters placed by caller.
+  static const int kSecondaryReturnAddress =
+      kCallerFrame + kStackFrameExtraParamSlot * kPointerSize;
+  static const int kIsolate = kSecondaryReturnAddress + kPointerSize;
+
+  // Below the frame pointer.
+  // Register parameters stored by setup code.
+  static const int kDirectCall = kFramePointer - kPointerSize;
+  static const int kStackHighEnd = kDirectCall - kPointerSize;
+  static const int kNumOutputRegisters = kStackHighEnd - kPointerSize;
+  static const int kRegisterOutput = kNumOutputRegisters - kPointerSize;
+  static const int kInputEnd = kRegisterOutput - kPointerSize;
+  static const int kInputStart = kInputEnd - kPointerSize;
+  static const int kStartIndex = kInputStart - kPointerSize;
+  static const int kInputString = kStartIndex - kPointerSize;
+  // When adding local variables remember to push space for them in
+  // the frame in GetCode.
+  static const int kSuccessfulCaptures = kInputString - kPointerSize;
+  static const int kInputStartMinusOne = kSuccessfulCaptures - kPointerSize;
+  // First register address. Following registers are below it on the stack.
+  static const int kRegisterZero = kInputStartMinusOne - kPointerSize;
+
+  // Initial size of code buffer.
+  static const size_t kRegExpCodeSize = 1024;
+
+  // Load a number of characters at the given offset from the
+  // current position, into the current-character register.
+  void LoadCurrentCharacterUnchecked(int cp_offset, int character_count);
+
+  // Check whether preemption has been requested.
+  void CheckPreemption();
+
+  // Check whether we are exceeding the stack limit on the backtrack stack.
+  void CheckStackLimit();
+
+
+  // Generate a call to CheckStackGuardState.
+  void CallCheckStackGuardState(Register scratch);
+
+  // The ebp-relative location of a regexp register.
+  MemOperand register_location(int register_index);
+
+  // Register holding the current input position as negative offset from
+  // the end of the string.
+  inline Register current_input_offset() { return r27; }
+
+  // The register containing the current character after LoadCurrentCharacter.
+  inline Register current_character() { return r28; }
+
+  // Register holding address of the end of the input string.
+  inline Register end_of_input_address() { return r30; }
+
+  // Register holding the frame address. Local variables, parameters and
+  // regexp registers are addressed relative to this.
+  inline Register frame_pointer() { return fp; }
+
+  // The register containing the backtrack stack top. Provides a meaningful
+  // name to the register.
+  inline Register backtrack_stackpointer() { return r29; }
+
+  // Register holding pointer to the current code object.
+  inline Register code_pointer() { return r26; }
+
+  // Byte size of chars in the string to match (decided by the Mode argument)
+  inline int char_size() { return static_cast<int>(mode_); }
+
+  // Equivalent to a conditional branch to the label, unless the label
+  // is NULL, in which case it is a conditional Backtrack.
+  void BranchOrBacktrack(Condition condition, Label* to, CRegister cr = cr7);
+
+  // Call and return internally in the generated code in a way that
+  // is GC-safe (i.e., doesn't leave absolute code addresses on the stack)
+  inline void SafeCall(Label* to, Condition cond = al, CRegister cr = cr7);
+  inline void SafeReturn();
+  inline void SafeCallTarget(Label* name);
+
+  // Pushes the value of a register on the backtrack stack. Decrements the
+  // stack pointer by a word size and stores the register's value there.
+  inline void Push(Register source);
+
+  // Pops a value from the backtrack stack. Reads the word at the stack pointer
+  // and increments it by a word size.
+  inline void Pop(Register target);
+
+  Isolate* isolate() const { return masm_->isolate(); }
+
+  MacroAssembler* masm_;
+
+  // Which mode to generate code for (Latin1 or UC16).
+  Mode mode_;
+
+  // One greater than maximal register index actually used.
+  int num_registers_;
+
+  // Number of registers to output at the end (the saved registers
+  // are always 0..num_saved_registers_-1)
+  int num_saved_registers_;
+
+  // Labels used internally.
+  Label entry_label_;
+  Label start_label_;
+  Label success_label_;
+  Label backtrack_label_;
+  Label exit_label_;
+  Label check_preempt_label_;
+  Label stack_overflow_label_;
+  Label internal_failure_label_;
+};
+
+// Set of non-volatile registers saved/restored by generated regexp code.
+const RegList kRegExpCalleeSaved =
+    1 << 25 | 1 << 26 | 1 << 27 | 1 << 28 | 1 << 29 | 1 << 30 | 1 << 31;
+
+#endif  // V8_INTERPRETED_REGEXP
+}
+}  // namespace v8::internal
+
+#endif  // V8_PPC_REGEXP_MACRO_ASSEMBLER_PPC_H_
diff --git a/src/ppc/simulator-ppc.cc b/src/ppc/simulator-ppc.cc
new file mode 100644
index 0000000..0d10153
--- /dev/null
+++ b/src/ppc/simulator-ppc.cc
@@ -0,0 +1,3803 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <cmath>
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_PPC
+
+#include "src/assembler.h"
+#include "src/codegen.h"
+#include "src/disasm.h"
+#include "src/ppc/constants-ppc.h"
+#include "src/ppc/frames-ppc.h"
+#include "src/ppc/simulator-ppc.h"
+
+#if defined(USE_SIMULATOR)
+
+// Only build the simulator if not compiling for real PPC hardware.
+namespace v8 {
+namespace internal {
+
+// This macro provides a platform independent use of sscanf. The reason for
+// SScanF not being implemented in a platform independent way through
+// ::v8::internal::OS in the same way as SNPrintF is that the
+// Windows C Run-Time Library does not provide vsscanf.
+#define SScanF sscanf  // NOLINT
+
+// The PPCDebugger class is used by the simulator while debugging simulated
+// PowerPC code.
+class PPCDebugger {
+ public:
+  explicit PPCDebugger(Simulator* sim) : sim_(sim) {}
+  ~PPCDebugger();
+
+  void Stop(Instruction* instr);
+  void Info(Instruction* instr);
+  void Debug();
+
+ private:
+  static const Instr kBreakpointInstr = (TWI | 0x1f * B21);
+  static const Instr kNopInstr = (ORI);  // ori, 0,0,0
+
+  Simulator* sim_;
+
+  intptr_t GetRegisterValue(int regnum);
+  double GetRegisterPairDoubleValue(int regnum);
+  double GetFPDoubleRegisterValue(int regnum);
+  bool GetValue(const char* desc, intptr_t* value);
+  bool GetFPDoubleValue(const char* desc, double* value);
+
+  // Set or delete a breakpoint. Returns true if successful.
+  bool SetBreakpoint(Instruction* break_pc);
+  bool DeleteBreakpoint(Instruction* break_pc);
+
+  // Undo and redo all breakpoints. This is needed to bracket disassembly and
+  // execution to skip past breakpoints when run from the debugger.
+  void UndoBreakpoints();
+  void RedoBreakpoints();
+};
+
+
+PPCDebugger::~PPCDebugger() {}
+
+
+#ifdef GENERATED_CODE_COVERAGE
+static FILE* coverage_log = NULL;
+
+
+static void InitializeCoverage() {
+  char* file_name = getenv("V8_GENERATED_CODE_COVERAGE_LOG");
+  if (file_name != NULL) {
+    coverage_log = fopen(file_name, "aw+");
+  }
+}
+
+
+void PPCDebugger::Stop(Instruction* instr) {
+  // Get the stop code.
+  uint32_t code = instr->SvcValue() & kStopCodeMask;
+  // Retrieve the encoded address, which comes just after this stop.
+  char** msg_address =
+      reinterpret_cast<char**>(sim_->get_pc() + Instruction::kInstrSize);
+  char* msg = *msg_address;
+  DCHECK(msg != NULL);
+
+  // Update this stop description.
+  if (isWatchedStop(code) && !watched_stops_[code].desc) {
+    watched_stops_[code].desc = msg;
+  }
+
+  if (strlen(msg) > 0) {
+    if (coverage_log != NULL) {
+      fprintf(coverage_log, "%s\n", msg);
+      fflush(coverage_log);
+    }
+    // Overwrite the instruction and address with nops.
+    instr->SetInstructionBits(kNopInstr);
+    reinterpret_cast<Instruction*>(msg_address)->SetInstructionBits(kNopInstr);
+  }
+  sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize + kPointerSize);
+}
+
+#else  // ndef GENERATED_CODE_COVERAGE
+
+static void InitializeCoverage() {}
+
+
+void PPCDebugger::Stop(Instruction* instr) {
+  // Get the stop code.
+  // use of kStopCodeMask not right on PowerPC
+  uint32_t code = instr->SvcValue() & kStopCodeMask;
+  // Retrieve the encoded address, which comes just after this stop.
+  char* msg =
+      *reinterpret_cast<char**>(sim_->get_pc() + Instruction::kInstrSize);
+  // Update this stop description.
+  if (sim_->isWatchedStop(code) && !sim_->watched_stops_[code].desc) {
+    sim_->watched_stops_[code].desc = msg;
+  }
+  // Print the stop message and code if it is not the default code.
+  if (code != kMaxStopCode) {
+    PrintF("Simulator hit stop %u: %s\n", code, msg);
+  } else {
+    PrintF("Simulator hit %s\n", msg);
+  }
+  sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize + kPointerSize);
+  Debug();
+}
+#endif
+
+
+void PPCDebugger::Info(Instruction* instr) {
+  // Retrieve the encoded address immediately following the Info breakpoint.
+  char* msg =
+      *reinterpret_cast<char**>(sim_->get_pc() + Instruction::kInstrSize);
+  PrintF("Simulator info %s\n", msg);
+  sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize + kPointerSize);
+}
+
+
+intptr_t PPCDebugger::GetRegisterValue(int regnum) {
+  return sim_->get_register(regnum);
+}
+
+
+double PPCDebugger::GetRegisterPairDoubleValue(int regnum) {
+  return sim_->get_double_from_register_pair(regnum);
+}
+
+
+double PPCDebugger::GetFPDoubleRegisterValue(int regnum) {
+  return sim_->get_double_from_d_register(regnum);
+}
+
+
+bool PPCDebugger::GetValue(const char* desc, intptr_t* value) {
+  int regnum = Registers::Number(desc);
+  if (regnum != kNoRegister) {
+    *value = GetRegisterValue(regnum);
+    return true;
+  } else {
+    if (strncmp(desc, "0x", 2) == 0) {
+      return SScanF(desc + 2, "%" V8PRIxPTR,
+                    reinterpret_cast<uintptr_t*>(value)) == 1;
+    } else {
+      return SScanF(desc, "%" V8PRIuPTR, reinterpret_cast<uintptr_t*>(value)) ==
+             1;
+    }
+  }
+  return false;
+}
+
+
+bool PPCDebugger::GetFPDoubleValue(const char* desc, double* value) {
+  int regnum = FPRegisters::Number(desc);
+  if (regnum != kNoRegister) {
+    *value = sim_->get_double_from_d_register(regnum);
+    return true;
+  }
+  return false;
+}
+
+
+bool PPCDebugger::SetBreakpoint(Instruction* break_pc) {
+  // Check if a breakpoint can be set. If not return without any side-effects.
+  if (sim_->break_pc_ != NULL) {
+    return false;
+  }
+
+  // Set the breakpoint.
+  sim_->break_pc_ = break_pc;
+  sim_->break_instr_ = break_pc->InstructionBits();
+  // Not setting the breakpoint instruction in the code itself. It will be set
+  // when the debugger shell continues.
+  return true;
+}
+
+
+bool PPCDebugger::DeleteBreakpoint(Instruction* break_pc) {
+  if (sim_->break_pc_ != NULL) {
+    sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
+  }
+
+  sim_->break_pc_ = NULL;
+  sim_->break_instr_ = 0;
+  return true;
+}
+
+
+void PPCDebugger::UndoBreakpoints() {
+  if (sim_->break_pc_ != NULL) {
+    sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
+  }
+}
+
+
+void PPCDebugger::RedoBreakpoints() {
+  if (sim_->break_pc_ != NULL) {
+    sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
+  }
+}
+
+
+void PPCDebugger::Debug() {
+  intptr_t last_pc = -1;
+  bool done = false;
+
+#define COMMAND_SIZE 63
+#define ARG_SIZE 255
+
+#define STR(a) #a
+#define XSTR(a) STR(a)
+
+  char cmd[COMMAND_SIZE + 1];
+  char arg1[ARG_SIZE + 1];
+  char arg2[ARG_SIZE + 1];
+  char* argv[3] = {cmd, arg1, arg2};
+
+  // make sure to have a proper terminating character if reaching the limit
+  cmd[COMMAND_SIZE] = 0;
+  arg1[ARG_SIZE] = 0;
+  arg2[ARG_SIZE] = 0;
+
+  // Undo all set breakpoints while running in the debugger shell. This will
+  // make them invisible to all commands.
+  UndoBreakpoints();
+  // Disable tracing while simulating
+  bool trace = ::v8::internal::FLAG_trace_sim;
+  ::v8::internal::FLAG_trace_sim = false;
+
+  while (!done && !sim_->has_bad_pc()) {
+    if (last_pc != sim_->get_pc()) {
+      disasm::NameConverter converter;
+      disasm::Disassembler dasm(converter);
+      // use a reasonably large buffer
+      v8::internal::EmbeddedVector<char, 256> buffer;
+      dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(sim_->get_pc()));
+      PrintF("  0x%08" V8PRIxPTR "  %s\n", sim_->get_pc(), buffer.start());
+      last_pc = sim_->get_pc();
+    }
+    char* line = ReadLine("sim> ");
+    if (line == NULL) {
+      break;
+    } else {
+      char* last_input = sim_->last_debugger_input();
+      if (strcmp(line, "\n") == 0 && last_input != NULL) {
+        line = last_input;
+      } else {
+        // Ownership is transferred to sim_;
+        sim_->set_last_debugger_input(line);
+      }
+      // Use sscanf to parse the individual parts of the command line. At the
+      // moment no command expects more than two parameters.
+      int argc = SScanF(line,
+                        "%" XSTR(COMMAND_SIZE) "s "
+                        "%" XSTR(ARG_SIZE) "s "
+                        "%" XSTR(ARG_SIZE) "s",
+                        cmd, arg1, arg2);
+      if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
+        intptr_t value;
+
+        // If at a breakpoint, proceed past it.
+        if ((reinterpret_cast<Instruction*>(sim_->get_pc()))
+                ->InstructionBits() == 0x7d821008) {
+          sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
+        } else {
+          sim_->ExecuteInstruction(
+              reinterpret_cast<Instruction*>(sim_->get_pc()));
+        }
+
+        if (argc == 2 && last_pc != sim_->get_pc() && GetValue(arg1, &value)) {
+          for (int i = 1; i < value; i++) {
+            disasm::NameConverter converter;
+            disasm::Disassembler dasm(converter);
+            // use a reasonably large buffer
+            v8::internal::EmbeddedVector<char, 256> buffer;
+            dasm.InstructionDecode(buffer,
+                                   reinterpret_cast<byte*>(sim_->get_pc()));
+            PrintF("  0x%08" V8PRIxPTR "  %s\n", sim_->get_pc(),
+                   buffer.start());
+            sim_->ExecuteInstruction(
+                reinterpret_cast<Instruction*>(sim_->get_pc()));
+          }
+        }
+      } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
+        // If at a breakpoint, proceed past it.
+        if ((reinterpret_cast<Instruction*>(sim_->get_pc()))
+                ->InstructionBits() == 0x7d821008) {
+          sim_->set_pc(sim_->get_pc() + Instruction::kInstrSize);
+        } else {
+          // Execute the one instruction we broke at with breakpoints disabled.
+          sim_->ExecuteInstruction(
+              reinterpret_cast<Instruction*>(sim_->get_pc()));
+        }
+        // Leave the debugger shell.
+        done = true;
+      } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
+        if (argc == 2 || (argc == 3 && strcmp(arg2, "fp") == 0)) {
+          intptr_t value;
+          double dvalue;
+          if (strcmp(arg1, "all") == 0) {
+            for (int i = 0; i < kNumRegisters; i++) {
+              value = GetRegisterValue(i);
+              PrintF("    %3s: %08" V8PRIxPTR, Registers::Name(i), value);
+              if ((argc == 3 && strcmp(arg2, "fp") == 0) && i < 8 &&
+                  (i % 2) == 0) {
+                dvalue = GetRegisterPairDoubleValue(i);
+                PrintF(" (%f)\n", dvalue);
+              } else if (i != 0 && !((i + 1) & 3)) {
+                PrintF("\n");
+              }
+            }
+            PrintF("  pc: %08" V8PRIxPTR "  lr: %08" V8PRIxPTR
+                   "  "
+                   "ctr: %08" V8PRIxPTR "  xer: %08x  cr: %08x\n",
+                   sim_->special_reg_pc_, sim_->special_reg_lr_,
+                   sim_->special_reg_ctr_, sim_->special_reg_xer_,
+                   sim_->condition_reg_);
+          } else if (strcmp(arg1, "alld") == 0) {
+            for (int i = 0; i < kNumRegisters; i++) {
+              value = GetRegisterValue(i);
+              PrintF("     %3s: %08" V8PRIxPTR " %11" V8PRIdPTR,
+                     Registers::Name(i), value, value);
+              if ((argc == 3 && strcmp(arg2, "fp") == 0) && i < 8 &&
+                  (i % 2) == 0) {
+                dvalue = GetRegisterPairDoubleValue(i);
+                PrintF(" (%f)\n", dvalue);
+              } else if (!((i + 1) % 2)) {
+                PrintF("\n");
+              }
+            }
+            PrintF("   pc: %08" V8PRIxPTR "  lr: %08" V8PRIxPTR
+                   "  "
+                   "ctr: %08" V8PRIxPTR "  xer: %08x  cr: %08x\n",
+                   sim_->special_reg_pc_, sim_->special_reg_lr_,
+                   sim_->special_reg_ctr_, sim_->special_reg_xer_,
+                   sim_->condition_reg_);
+          } else if (strcmp(arg1, "allf") == 0) {
+            for (int i = 0; i < DoubleRegister::kNumRegisters; i++) {
+              dvalue = GetFPDoubleRegisterValue(i);
+              uint64_t as_words = bit_cast<uint64_t>(dvalue);
+              PrintF("%3s: %f 0x%08x %08x\n", FPRegisters::Name(i), dvalue,
+                     static_cast<uint32_t>(as_words >> 32),
+                     static_cast<uint32_t>(as_words & 0xffffffff));
+            }
+          } else if (arg1[0] == 'r' &&
+                     (arg1[1] >= '0' && arg1[1] <= '9' &&
+                      (arg1[2] == '\0' || (arg1[2] >= '0' && arg1[2] <= '9' &&
+                                           arg1[3] == '\0')))) {
+            int regnum = strtoul(&arg1[1], 0, 10);
+            if (regnum != kNoRegister) {
+              value = GetRegisterValue(regnum);
+              PrintF("%s: 0x%08" V8PRIxPTR " %" V8PRIdPTR "\n", arg1, value,
+                     value);
+            } else {
+              PrintF("%s unrecognized\n", arg1);
+            }
+          } else {
+            if (GetValue(arg1, &value)) {
+              PrintF("%s: 0x%08" V8PRIxPTR " %" V8PRIdPTR "\n", arg1, value,
+                     value);
+            } else if (GetFPDoubleValue(arg1, &dvalue)) {
+              uint64_t as_words = bit_cast<uint64_t>(dvalue);
+              PrintF("%s: %f 0x%08x %08x\n", arg1, dvalue,
+                     static_cast<uint32_t>(as_words >> 32),
+                     static_cast<uint32_t>(as_words & 0xffffffff));
+            } else {
+              PrintF("%s unrecognized\n", arg1);
+            }
+          }
+        } else {
+          PrintF("print <register>\n");
+        }
+      } else if ((strcmp(cmd, "po") == 0) ||
+                 (strcmp(cmd, "printobject") == 0)) {
+        if (argc == 2) {
+          intptr_t value;
+          OFStream os(stdout);
+          if (GetValue(arg1, &value)) {
+            Object* obj = reinterpret_cast<Object*>(value);
+            os << arg1 << ": \n";
+#ifdef DEBUG
+            obj->Print(os);
+            os << "\n";
+#else
+            os << Brief(obj) << "\n";
+#endif
+          } else {
+            os << arg1 << " unrecognized\n";
+          }
+        } else {
+          PrintF("printobject <value>\n");
+        }
+      } else if (strcmp(cmd, "setpc") == 0) {
+        intptr_t value;
+
+        if (!GetValue(arg1, &value)) {
+          PrintF("%s unrecognized\n", arg1);
+          continue;
+        }
+        sim_->set_pc(value);
+      } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
+        intptr_t* cur = NULL;
+        intptr_t* end = NULL;
+        int next_arg = 1;
+
+        if (strcmp(cmd, "stack") == 0) {
+          cur = reinterpret_cast<intptr_t*>(sim_->get_register(Simulator::sp));
+        } else {  // "mem"
+          intptr_t value;
+          if (!GetValue(arg1, &value)) {
+            PrintF("%s unrecognized\n", arg1);
+            continue;
+          }
+          cur = reinterpret_cast<intptr_t*>(value);
+          next_arg++;
+        }
+
+        intptr_t words;  // likely inaccurate variable name for 64bit
+        if (argc == next_arg) {
+          words = 10;
+        } else {
+          if (!GetValue(argv[next_arg], &words)) {
+            words = 10;
+          }
+        }
+        end = cur + words;
+
+        while (cur < end) {
+          PrintF("  0x%08" V8PRIxPTR ":  0x%08" V8PRIxPTR " %10" V8PRIdPTR,
+                 reinterpret_cast<intptr_t>(cur), *cur, *cur);
+          HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
+          intptr_t value = *cur;
+          Heap* current_heap = v8::internal::Isolate::Current()->heap();
+          if (((value & 1) == 0) || current_heap->Contains(obj)) {
+            PrintF(" (");
+            if ((value & 1) == 0) {
+              PrintF("smi %d", PlatformSmiTagging::SmiToInt(obj));
+            } else {
+              obj->ShortPrint();
+            }
+            PrintF(")");
+          }
+          PrintF("\n");
+          cur++;
+        }
+      } else if (strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) {
+        disasm::NameConverter converter;
+        disasm::Disassembler dasm(converter);
+        // use a reasonably large buffer
+        v8::internal::EmbeddedVector<char, 256> buffer;
+
+        byte* prev = NULL;
+        byte* cur = NULL;
+        byte* end = NULL;
+
+        if (argc == 1) {
+          cur = reinterpret_cast<byte*>(sim_->get_pc());
+          end = cur + (10 * Instruction::kInstrSize);
+        } else if (argc == 2) {
+          int regnum = Registers::Number(arg1);
+          if (regnum != kNoRegister || strncmp(arg1, "0x", 2) == 0) {
+            // The argument is an address or a register name.
+            intptr_t value;
+            if (GetValue(arg1, &value)) {
+              cur = reinterpret_cast<byte*>(value);
+              // Disassemble 10 instructions at <arg1>.
+              end = cur + (10 * Instruction::kInstrSize);
+            }
+          } else {
+            // The argument is the number of instructions.
+            intptr_t value;
+            if (GetValue(arg1, &value)) {
+              cur = reinterpret_cast<byte*>(sim_->get_pc());
+              // Disassemble <arg1> instructions.
+              end = cur + (value * Instruction::kInstrSize);
+            }
+          }
+        } else {
+          intptr_t value1;
+          intptr_t value2;
+          if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
+            cur = reinterpret_cast<byte*>(value1);
+            end = cur + (value2 * Instruction::kInstrSize);
+          }
+        }
+
+        while (cur < end) {
+          prev = cur;
+          cur += dasm.InstructionDecode(buffer, cur);
+          PrintF("  0x%08" V8PRIxPTR "  %s\n", reinterpret_cast<intptr_t>(prev),
+                 buffer.start());
+        }
+      } else if (strcmp(cmd, "gdb") == 0) {
+        PrintF("relinquishing control to gdb\n");
+        v8::base::OS::DebugBreak();
+        PrintF("regaining control from gdb\n");
+      } else if (strcmp(cmd, "break") == 0) {
+        if (argc == 2) {
+          intptr_t value;
+          if (GetValue(arg1, &value)) {
+            if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
+              PrintF("setting breakpoint failed\n");
+            }
+          } else {
+            PrintF("%s unrecognized\n", arg1);
+          }
+        } else {
+          PrintF("break <address>\n");
+        }
+      } else if (strcmp(cmd, "del") == 0) {
+        if (!DeleteBreakpoint(NULL)) {
+          PrintF("deleting breakpoint failed\n");
+        }
+      } else if (strcmp(cmd, "cr") == 0) {
+        PrintF("Condition reg: %08x\n", sim_->condition_reg_);
+      } else if (strcmp(cmd, "lr") == 0) {
+        PrintF("Link reg: %08" V8PRIxPTR "\n", sim_->special_reg_lr_);
+      } else if (strcmp(cmd, "ctr") == 0) {
+        PrintF("Ctr reg: %08" V8PRIxPTR "\n", sim_->special_reg_ctr_);
+      } else if (strcmp(cmd, "xer") == 0) {
+        PrintF("XER: %08x\n", sim_->special_reg_xer_);
+      } else if (strcmp(cmd, "fpscr") == 0) {
+        PrintF("FPSCR: %08x\n", sim_->fp_condition_reg_);
+      } else if (strcmp(cmd, "stop") == 0) {
+        intptr_t value;
+        intptr_t stop_pc =
+            sim_->get_pc() - (Instruction::kInstrSize + kPointerSize);
+        Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
+        Instruction* msg_address =
+            reinterpret_cast<Instruction*>(stop_pc + Instruction::kInstrSize);
+        if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
+          // Remove the current stop.
+          if (sim_->isStopInstruction(stop_instr)) {
+            stop_instr->SetInstructionBits(kNopInstr);
+            msg_address->SetInstructionBits(kNopInstr);
+          } else {
+            PrintF("Not at debugger stop.\n");
+          }
+        } else if (argc == 3) {
+          // Print information about all/the specified breakpoint(s).
+          if (strcmp(arg1, "info") == 0) {
+            if (strcmp(arg2, "all") == 0) {
+              PrintF("Stop information:\n");
+              for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
+                sim_->PrintStopInfo(i);
+              }
+            } else if (GetValue(arg2, &value)) {
+              sim_->PrintStopInfo(value);
+            } else {
+              PrintF("Unrecognized argument.\n");
+            }
+          } else if (strcmp(arg1, "enable") == 0) {
+            // Enable all/the specified breakpoint(s).
+            if (strcmp(arg2, "all") == 0) {
+              for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
+                sim_->EnableStop(i);
+              }
+            } else if (GetValue(arg2, &value)) {
+              sim_->EnableStop(value);
+            } else {
+              PrintF("Unrecognized argument.\n");
+            }
+          } else if (strcmp(arg1, "disable") == 0) {
+            // Disable all/the specified breakpoint(s).
+            if (strcmp(arg2, "all") == 0) {
+              for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
+                sim_->DisableStop(i);
+              }
+            } else if (GetValue(arg2, &value)) {
+              sim_->DisableStop(value);
+            } else {
+              PrintF("Unrecognized argument.\n");
+            }
+          }
+        } else {
+          PrintF("Wrong usage. Use help command for more information.\n");
+        }
+      } else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) {
+        ::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim;
+        PrintF("Trace of executed instructions is %s\n",
+               ::v8::internal::FLAG_trace_sim ? "on" : "off");
+      } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
+        PrintF("cont\n");
+        PrintF("  continue execution (alias 'c')\n");
+        PrintF("stepi [num instructions]\n");
+        PrintF("  step one/num instruction(s) (alias 'si')\n");
+        PrintF("print <register>\n");
+        PrintF("  print register content (alias 'p')\n");
+        PrintF("  use register name 'all' to display all integer registers\n");
+        PrintF(
+            "  use register name 'alld' to display integer registers "
+            "with decimal values\n");
+        PrintF("  use register name 'rN' to display register number 'N'\n");
+        PrintF("  add argument 'fp' to print register pair double values\n");
+        PrintF(
+            "  use register name 'allf' to display floating-point "
+            "registers\n");
+        PrintF("printobject <register>\n");
+        PrintF("  print an object from a register (alias 'po')\n");
+        PrintF("cr\n");
+        PrintF("  print condition register\n");
+        PrintF("lr\n");
+        PrintF("  print link register\n");
+        PrintF("ctr\n");
+        PrintF("  print ctr register\n");
+        PrintF("xer\n");
+        PrintF("  print XER\n");
+        PrintF("fpscr\n");
+        PrintF("  print FPSCR\n");
+        PrintF("stack [<num words>]\n");
+        PrintF("  dump stack content, default dump 10 words)\n");
+        PrintF("mem <address> [<num words>]\n");
+        PrintF("  dump memory content, default dump 10 words)\n");
+        PrintF("disasm [<instructions>]\n");
+        PrintF("disasm [<address/register>]\n");
+        PrintF("disasm [[<address/register>] <instructions>]\n");
+        PrintF("  disassemble code, default is 10 instructions\n");
+        PrintF("  from pc (alias 'di')\n");
+        PrintF("gdb\n");
+        PrintF("  enter gdb\n");
+        PrintF("break <address>\n");
+        PrintF("  set a break point on the address\n");
+        PrintF("del\n");
+        PrintF("  delete the breakpoint\n");
+        PrintF("trace (alias 't')\n");
+        PrintF("  toogle the tracing of all executed statements\n");
+        PrintF("stop feature:\n");
+        PrintF("  Description:\n");
+        PrintF("    Stops are debug instructions inserted by\n");
+        PrintF("    the Assembler::stop() function.\n");
+        PrintF("    When hitting a stop, the Simulator will\n");
+        PrintF("    stop and and give control to the PPCDebugger.\n");
+        PrintF("    The first %d stop codes are watched:\n",
+               Simulator::kNumOfWatchedStops);
+        PrintF("    - They can be enabled / disabled: the Simulator\n");
+        PrintF("      will / won't stop when hitting them.\n");
+        PrintF("    - The Simulator keeps track of how many times they \n");
+        PrintF("      are met. (See the info command.) Going over a\n");
+        PrintF("      disabled stop still increases its counter. \n");
+        PrintF("  Commands:\n");
+        PrintF("    stop info all/<code> : print infos about number <code>\n");
+        PrintF("      or all stop(s).\n");
+        PrintF("    stop enable/disable all/<code> : enables / disables\n");
+        PrintF("      all or number <code> stop(s)\n");
+        PrintF("    stop unstop\n");
+        PrintF("      ignore the stop instruction at the current location\n");
+        PrintF("      from now on\n");
+      } else {
+        PrintF("Unknown command: %s\n", cmd);
+      }
+    }
+  }
+
+  // Add all the breakpoints back to stop execution and enter the debugger
+  // shell when hit.
+  RedoBreakpoints();
+  // Restore tracing
+  ::v8::internal::FLAG_trace_sim = trace;
+
+#undef COMMAND_SIZE
+#undef ARG_SIZE
+
+#undef STR
+#undef XSTR
+}
+
+
+static bool ICacheMatch(void* one, void* two) {
+  DCHECK((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0);
+  DCHECK((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0);
+  return one == two;
+}
+
+
+static uint32_t ICacheHash(void* key) {
+  return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
+}
+
+
+static bool AllOnOnePage(uintptr_t start, int size) {
+  intptr_t start_page = (start & ~CachePage::kPageMask);
+  intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
+  return start_page == end_page;
+}
+
+
+void Simulator::set_last_debugger_input(char* input) {
+  DeleteArray(last_debugger_input_);
+  last_debugger_input_ = input;
+}
+
+
+void Simulator::FlushICache(v8::internal::HashMap* i_cache, void* start_addr,
+                            size_t size) {
+  intptr_t start = reinterpret_cast<intptr_t>(start_addr);
+  int intra_line = (start & CachePage::kLineMask);
+  start -= intra_line;
+  size += intra_line;
+  size = ((size - 1) | CachePage::kLineMask) + 1;
+  int offset = (start & CachePage::kPageMask);
+  while (!AllOnOnePage(start, size - 1)) {
+    int bytes_to_flush = CachePage::kPageSize - offset;
+    FlushOnePage(i_cache, start, bytes_to_flush);
+    start += bytes_to_flush;
+    size -= bytes_to_flush;
+    DCHECK_EQ(0, static_cast<int>(start & CachePage::kPageMask));
+    offset = 0;
+  }
+  if (size != 0) {
+    FlushOnePage(i_cache, start, size);
+  }
+}
+
+
+CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) {
+  v8::internal::HashMap::Entry* entry =
+      i_cache->Lookup(page, ICacheHash(page), true);
+  if (entry->value == NULL) {
+    CachePage* new_page = new CachePage();
+    entry->value = new_page;
+  }
+  return reinterpret_cast<CachePage*>(entry->value);
+}
+
+
+// Flush from start up to and not including start + size.
+void Simulator::FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
+                             int size) {
+  DCHECK(size <= CachePage::kPageSize);
+  DCHECK(AllOnOnePage(start, size - 1));
+  DCHECK((start & CachePage::kLineMask) == 0);
+  DCHECK((size & CachePage::kLineMask) == 0);
+  void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
+  int offset = (start & CachePage::kPageMask);
+  CachePage* cache_page = GetCachePage(i_cache, page);
+  char* valid_bytemap = cache_page->ValidityByte(offset);
+  memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
+}
+
+
+void Simulator::CheckICache(v8::internal::HashMap* i_cache,
+                            Instruction* instr) {
+  intptr_t address = reinterpret_cast<intptr_t>(instr);
+  void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
+  void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
+  int offset = (address & CachePage::kPageMask);
+  CachePage* cache_page = GetCachePage(i_cache, page);
+  char* cache_valid_byte = cache_page->ValidityByte(offset);
+  bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
+  char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
+  if (cache_hit) {
+    // Check that the data in memory matches the contents of the I-cache.
+    CHECK_EQ(0,
+             memcmp(reinterpret_cast<void*>(instr),
+                    cache_page->CachedData(offset), Instruction::kInstrSize));
+  } else {
+    // Cache miss.  Load memory into the cache.
+    memcpy(cached_line, line, CachePage::kLineLength);
+    *cache_valid_byte = CachePage::LINE_VALID;
+  }
+}
+
+
+void Simulator::Initialize(Isolate* isolate) {
+  if (isolate->simulator_initialized()) return;
+  isolate->set_simulator_initialized(true);
+  ::v8::internal::ExternalReference::set_redirector(isolate,
+                                                    &RedirectExternalReference);
+}
+
+
+Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
+  i_cache_ = isolate_->simulator_i_cache();
+  if (i_cache_ == NULL) {
+    i_cache_ = new v8::internal::HashMap(&ICacheMatch);
+    isolate_->set_simulator_i_cache(i_cache_);
+  }
+  Initialize(isolate);
+// Set up simulator support first. Some of this information is needed to
+// setup the architecture state.
+#if V8_TARGET_ARCH_PPC64
+  size_t stack_size = 2 * 1024 * 1024;  // allocate 2MB for stack
+#else
+  size_t stack_size = 1 * 1024 * 1024;  // allocate 1MB for stack
+#endif
+  stack_ = reinterpret_cast<char*>(malloc(stack_size));
+  pc_modified_ = false;
+  icount_ = 0;
+  break_pc_ = NULL;
+  break_instr_ = 0;
+
+  // Set up architecture state.
+  // All registers are initialized to zero to start with.
+  for (int i = 0; i < kNumGPRs; i++) {
+    registers_[i] = 0;
+  }
+  condition_reg_ = 0;
+  fp_condition_reg_ = 0;
+  special_reg_pc_ = 0;
+  special_reg_lr_ = 0;
+  special_reg_ctr_ = 0;
+
+  // Initializing FP registers.
+  for (int i = 0; i < kNumFPRs; i++) {
+    fp_registers_[i] = 0.0;
+  }
+
+  // The sp is initialized to point to the bottom (high address) of the
+  // allocated stack area. To be safe in potential stack underflows we leave
+  // some buffer below.
+  registers_[sp] = reinterpret_cast<intptr_t>(stack_) + stack_size - 64;
+  InitializeCoverage();
+
+  last_debugger_input_ = NULL;
+}
+
+
+Simulator::~Simulator() {}
+
+
+// When the generated code calls an external reference we need to catch that in
+// the simulator.  The external reference will be a function compiled for the
+// host architecture.  We need to call that function instead of trying to
+// execute it with the simulator.  We do that by redirecting the external
+// reference to a svc (Supervisor Call) instruction that is handled by
+// the simulator.  We write the original destination of the jump just at a known
+// offset from the svc instruction so the simulator knows what to call.
+class Redirection {
+ public:
+  Redirection(void* external_function, ExternalReference::Type type)
+      : external_function_(external_function),
+        swi_instruction_(rtCallRedirInstr | kCallRtRedirected),
+        type_(type),
+        next_(NULL) {
+    Isolate* isolate = Isolate::Current();
+    next_ = isolate->simulator_redirection();
+    Simulator::current(isolate)->FlushICache(
+        isolate->simulator_i_cache(),
+        reinterpret_cast<void*>(&swi_instruction_), Instruction::kInstrSize);
+    isolate->set_simulator_redirection(this);
+  }
+
+  void* address_of_swi_instruction() {
+    return reinterpret_cast<void*>(&swi_instruction_);
+  }
+
+  void* external_function() { return external_function_; }
+  ExternalReference::Type type() { return type_; }
+
+  static Redirection* Get(void* external_function,
+                          ExternalReference::Type type) {
+    Isolate* isolate = Isolate::Current();
+    Redirection* current = isolate->simulator_redirection();
+    for (; current != NULL; current = current->next_) {
+      if (current->external_function_ == external_function) {
+        DCHECK_EQ(current->type(), type);
+        return current;
+      }
+    }
+    return new Redirection(external_function, type);
+  }
+
+  static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
+    char* addr_of_swi = reinterpret_cast<char*>(swi_instruction);
+    char* addr_of_redirection =
+        addr_of_swi - OFFSET_OF(Redirection, swi_instruction_);
+    return reinterpret_cast<Redirection*>(addr_of_redirection);
+  }
+
+  static void* ReverseRedirection(intptr_t reg) {
+    Redirection* redirection = FromSwiInstruction(
+        reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
+    return redirection->external_function();
+  }
+
+ private:
+  void* external_function_;
+  uint32_t swi_instruction_;
+  ExternalReference::Type type_;
+  Redirection* next_;
+};
+
+
+void* Simulator::RedirectExternalReference(void* external_function,
+                                           ExternalReference::Type type) {
+  Redirection* redirection = Redirection::Get(external_function, type);
+  return redirection->address_of_swi_instruction();
+}
+
+
+// Get the active Simulator for the current thread.
+Simulator* Simulator::current(Isolate* isolate) {
+  v8::internal::Isolate::PerIsolateThreadData* isolate_data =
+      isolate->FindOrAllocatePerThreadDataForThisThread();
+  DCHECK(isolate_data != NULL);
+
+  Simulator* sim = isolate_data->simulator();
+  if (sim == NULL) {
+    // TODO(146): delete the simulator object when a thread/isolate goes away.
+    sim = new Simulator(isolate);
+    isolate_data->set_simulator(sim);
+  }
+  return sim;
+}
+
+
+// Sets the register in the architecture state.
+void Simulator::set_register(int reg, intptr_t value) {
+  DCHECK((reg >= 0) && (reg < kNumGPRs));
+  registers_[reg] = value;
+}
+
+
+// Get the register from the architecture state.
+intptr_t Simulator::get_register(int reg) const {
+  DCHECK((reg >= 0) && (reg < kNumGPRs));
+  // Stupid code added to avoid bug in GCC.
+  // See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
+  if (reg >= kNumGPRs) return 0;
+  // End stupid code.
+  return registers_[reg];
+}
+
+
+double Simulator::get_double_from_register_pair(int reg) {
+  DCHECK((reg >= 0) && (reg < kNumGPRs) && ((reg % 2) == 0));
+
+  double dm_val = 0.0;
+#if !V8_TARGET_ARCH_PPC64  // doesn't make sense in 64bit mode
+  // Read the bits from the unsigned integer register_[] array
+  // into the double precision floating point value and return it.
+  char buffer[sizeof(fp_registers_[0])];
+  memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
+  memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
+#endif
+  return (dm_val);
+}
+
+
+// Raw access to the PC register.
+void Simulator::set_pc(intptr_t value) {
+  pc_modified_ = true;
+  special_reg_pc_ = value;
+}
+
+
+bool Simulator::has_bad_pc() const {
+  return ((special_reg_pc_ == bad_lr) || (special_reg_pc_ == end_sim_pc));
+}
+
+
+// Raw access to the PC register without the special adjustment when reading.
+intptr_t Simulator::get_pc() const { return special_reg_pc_; }
+
+
+// Runtime FP routines take:
+// - two double arguments
+// - one double argument and zero or one integer arguments.
+// All are consructed here from d1, d2 and r3.
+void Simulator::GetFpArgs(double* x, double* y, intptr_t* z) {
+  *x = get_double_from_d_register(1);
+  *y = get_double_from_d_register(2);
+  *z = get_register(3);
+}
+
+
+// The return value is in d1.
+void Simulator::SetFpResult(const double& result) { fp_registers_[1] = result; }
+
+
+void Simulator::TrashCallerSaveRegisters() {
+// We don't trash the registers with the return value.
+#if 0  // A good idea to trash volatile registers, needs to be done
+  registers_[2] = 0x50Bad4U;
+  registers_[3] = 0x50Bad4U;
+  registers_[12] = 0x50Bad4U;
+#endif
+}
+
+
+uint32_t Simulator::ReadWU(intptr_t addr, Instruction* instr) {
+  uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
+  return *ptr;
+}
+
+
+int32_t Simulator::ReadW(intptr_t addr, Instruction* instr) {
+  int32_t* ptr = reinterpret_cast<int32_t*>(addr);
+  return *ptr;
+}
+
+
+void Simulator::WriteW(intptr_t addr, uint32_t value, Instruction* instr) {
+  uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
+  *ptr = value;
+  return;
+}
+
+
+void Simulator::WriteW(intptr_t addr, int32_t value, Instruction* instr) {
+  int32_t* ptr = reinterpret_cast<int32_t*>(addr);
+  *ptr = value;
+  return;
+}
+
+
+uint16_t Simulator::ReadHU(intptr_t addr, Instruction* instr) {
+  uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
+  return *ptr;
+}
+
+
+int16_t Simulator::ReadH(intptr_t addr, Instruction* instr) {
+  int16_t* ptr = reinterpret_cast<int16_t*>(addr);
+  return *ptr;
+}
+
+
+void Simulator::WriteH(intptr_t addr, uint16_t value, Instruction* instr) {
+  uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
+  *ptr = value;
+  return;
+}
+
+
+void Simulator::WriteH(intptr_t addr, int16_t value, Instruction* instr) {
+  int16_t* ptr = reinterpret_cast<int16_t*>(addr);
+  *ptr = value;
+  return;
+}
+
+
+uint8_t Simulator::ReadBU(intptr_t addr) {
+  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
+  return *ptr;
+}
+
+
+int8_t Simulator::ReadB(intptr_t addr) {
+  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
+  return *ptr;
+}
+
+
+void Simulator::WriteB(intptr_t addr, uint8_t value) {
+  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
+  *ptr = value;
+}
+
+
+void Simulator::WriteB(intptr_t addr, int8_t value) {
+  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
+  *ptr = value;
+}
+
+
+intptr_t* Simulator::ReadDW(intptr_t addr) {
+  intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
+  return ptr;
+}
+
+
+void Simulator::WriteDW(intptr_t addr, int64_t value) {
+  int64_t* ptr = reinterpret_cast<int64_t*>(addr);
+  *ptr = value;
+  return;
+}
+
+
+// Returns the limit of the stack area to enable checking for stack overflows.
+uintptr_t Simulator::StackLimit() const {
+  // Leave a safety margin of 1024 bytes to prevent overrunning the stack when
+  // pushing values.
+  return reinterpret_cast<uintptr_t>(stack_) + 1024;
+}
+
+
+// Unsupported instructions use Format to print an error and stop execution.
+void Simulator::Format(Instruction* instr, const char* format) {
+  PrintF("Simulator found unsupported instruction:\n 0x%08" V8PRIxPTR ": %s\n",
+         reinterpret_cast<intptr_t>(instr), format);
+  UNIMPLEMENTED();
+}
+
+
+// Calculate C flag value for additions.
+bool Simulator::CarryFrom(int32_t left, int32_t right, int32_t carry) {
+  uint32_t uleft = static_cast<uint32_t>(left);
+  uint32_t uright = static_cast<uint32_t>(right);
+  uint32_t urest = 0xffffffffU - uleft;
+
+  return (uright > urest) ||
+         (carry && (((uright + 1) > urest) || (uright > (urest - 1))));
+}
+
+
+// Calculate C flag value for subtractions.
+bool Simulator::BorrowFrom(int32_t left, int32_t right) {
+  uint32_t uleft = static_cast<uint32_t>(left);
+  uint32_t uright = static_cast<uint32_t>(right);
+
+  return (uright > uleft);
+}
+
+
+// Calculate V flag value for additions and subtractions.
+bool Simulator::OverflowFrom(int32_t alu_out, int32_t left, int32_t right,
+                             bool addition) {
+  bool overflow;
+  if (addition) {
+    // operands have the same sign
+    overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
+               // and operands and result have different sign
+               &&
+               ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
+  } else {
+    // operands have different signs
+    overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
+               // and first operand and result have different signs
+               &&
+               ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
+  }
+  return overflow;
+}
+
+
+#if !V8_TARGET_ARCH_PPC64
+// Calls into the V8 runtime are based on this very simple interface.
+// Note: To be able to return two values from some calls the code in runtime.cc
+// uses the ObjectPair which is essentially two 32-bit values stuffed into a
+// 64-bit value. With the code below we assume that all runtime calls return
+// 64 bits of result. If they don't, the r4 result register contains a bogus
+// value, which is fine because it is caller-saved.
+typedef int64_t (*SimulatorRuntimeCall)(intptr_t arg0, intptr_t arg1,
+                                        intptr_t arg2, intptr_t arg3,
+                                        intptr_t arg4, intptr_t arg5);
+#else
+// For 64-bit, we need to be more explicit.
+typedef intptr_t (*SimulatorRuntimeCall)(intptr_t arg0, intptr_t arg1,
+                                         intptr_t arg2, intptr_t arg3,
+                                         intptr_t arg4, intptr_t arg5);
+struct ObjectPair {
+  intptr_t x;
+  intptr_t y;
+};
+
+typedef struct ObjectPair (*SimulatorRuntimeObjectPairCall)(
+    intptr_t arg0, intptr_t arg1, intptr_t arg2, intptr_t arg3, intptr_t arg4,
+    intptr_t arg5);
+#endif
+
+// These prototypes handle the four types of FP calls.
+typedef int (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
+typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
+typedef double (*SimulatorRuntimeFPCall)(double darg0);
+typedef double (*SimulatorRuntimeFPIntCall)(double darg0, intptr_t arg0);
+
+// This signature supports direct call in to API function native callback
+// (refer to InvocationCallback in v8.h).
+typedef void (*SimulatorRuntimeDirectApiCall)(intptr_t arg0);
+typedef void (*SimulatorRuntimeProfilingApiCall)(intptr_t arg0, void* arg1);
+
+// This signature supports direct call to accessor getter callback.
+typedef void (*SimulatorRuntimeDirectGetterCall)(intptr_t arg0, intptr_t arg1);
+typedef void (*SimulatorRuntimeProfilingGetterCall)(intptr_t arg0,
+                                                    intptr_t arg1, void* arg2);
+
+// Software interrupt instructions are used by the simulator to call into the
+// C-based V8 runtime.
+void Simulator::SoftwareInterrupt(Instruction* instr) {
+  int svc = instr->SvcValue();
+  switch (svc) {
+    case kCallRtRedirected: {
+      // Check if stack is aligned. Error if not aligned is reported below to
+      // include information on the function called.
+      bool stack_aligned =
+          (get_register(sp) & (::v8::internal::FLAG_sim_stack_alignment - 1)) ==
+          0;
+      Redirection* redirection = Redirection::FromSwiInstruction(instr);
+      const int kArgCount = 6;
+      int arg0_regnum = 3;
+#if V8_TARGET_ARCH_PPC64 && !ABI_RETURNS_OBJECT_PAIRS_IN_REGS
+      intptr_t result_buffer = 0;
+      if (redirection->type() == ExternalReference::BUILTIN_OBJECTPAIR_CALL) {
+        result_buffer = get_register(r3);
+        arg0_regnum++;
+      }
+#endif
+      intptr_t arg[kArgCount];
+      for (int i = 0; i < kArgCount; i++) {
+        arg[i] = get_register(arg0_regnum + i);
+      }
+      bool fp_call =
+          (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
+          (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
+          (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
+          (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
+      // This is dodgy but it works because the C entry stubs are never moved.
+      // See comment in codegen-arm.cc and bug 1242173.
+      intptr_t saved_lr = special_reg_lr_;
+      intptr_t external =
+          reinterpret_cast<intptr_t>(redirection->external_function());
+      if (fp_call) {
+        double dval0, dval1;  // one or two double parameters
+        intptr_t ival;        // zero or one integer parameters
+        int iresult = 0;      // integer return value
+        double dresult = 0;   // double return value
+        GetFpArgs(&dval0, &dval1, &ival);
+        if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
+          SimulatorRuntimeCall generic_target =
+              reinterpret_cast<SimulatorRuntimeCall>(external);
+          switch (redirection->type()) {
+            case ExternalReference::BUILTIN_FP_FP_CALL:
+            case ExternalReference::BUILTIN_COMPARE_CALL:
+              PrintF("Call to host function at %p with args %f, %f",
+                     FUNCTION_ADDR(generic_target), dval0, dval1);
+              break;
+            case ExternalReference::BUILTIN_FP_CALL:
+              PrintF("Call to host function at %p with arg %f",
+                     FUNCTION_ADDR(generic_target), dval0);
+              break;
+            case ExternalReference::BUILTIN_FP_INT_CALL:
+              PrintF("Call to host function at %p with args %f, %" V8PRIdPTR,
+                     FUNCTION_ADDR(generic_target), dval0, ival);
+              break;
+            default:
+              UNREACHABLE();
+              break;
+          }
+          if (!stack_aligned) {
+            PrintF(" with unaligned stack %08" V8PRIxPTR "\n",
+                   get_register(sp));
+          }
+          PrintF("\n");
+        }
+        CHECK(stack_aligned);
+        switch (redirection->type()) {
+          case ExternalReference::BUILTIN_COMPARE_CALL: {
+            SimulatorRuntimeCompareCall target =
+                reinterpret_cast<SimulatorRuntimeCompareCall>(external);
+            iresult = target(dval0, dval1);
+            set_register(r3, iresult);
+            break;
+          }
+          case ExternalReference::BUILTIN_FP_FP_CALL: {
+            SimulatorRuntimeFPFPCall target =
+                reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
+            dresult = target(dval0, dval1);
+            SetFpResult(dresult);
+            break;
+          }
+          case ExternalReference::BUILTIN_FP_CALL: {
+            SimulatorRuntimeFPCall target =
+                reinterpret_cast<SimulatorRuntimeFPCall>(external);
+            dresult = target(dval0);
+            SetFpResult(dresult);
+            break;
+          }
+          case ExternalReference::BUILTIN_FP_INT_CALL: {
+            SimulatorRuntimeFPIntCall target =
+                reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
+            dresult = target(dval0, ival);
+            SetFpResult(dresult);
+            break;
+          }
+          default:
+            UNREACHABLE();
+            break;
+        }
+        if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
+          switch (redirection->type()) {
+            case ExternalReference::BUILTIN_COMPARE_CALL:
+              PrintF("Returned %08x\n", iresult);
+              break;
+            case ExternalReference::BUILTIN_FP_FP_CALL:
+            case ExternalReference::BUILTIN_FP_CALL:
+            case ExternalReference::BUILTIN_FP_INT_CALL:
+              PrintF("Returned %f\n", dresult);
+              break;
+            default:
+              UNREACHABLE();
+              break;
+          }
+        }
+      } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
+        // See callers of MacroAssembler::CallApiFunctionAndReturn for
+        // explanation of register usage.
+        if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
+          PrintF("Call to host function at %p args %08" V8PRIxPTR,
+                 reinterpret_cast<void*>(external), arg[0]);
+          if (!stack_aligned) {
+            PrintF(" with unaligned stack %08" V8PRIxPTR "\n",
+                   get_register(sp));
+          }
+          PrintF("\n");
+        }
+        CHECK(stack_aligned);
+        SimulatorRuntimeDirectApiCall target =
+            reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
+        target(arg[0]);
+      } else if (redirection->type() == ExternalReference::PROFILING_API_CALL) {
+        // See callers of MacroAssembler::CallApiFunctionAndReturn for
+        // explanation of register usage.
+        if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
+          PrintF("Call to host function at %p args %08" V8PRIxPTR
+                 " %08" V8PRIxPTR,
+                 reinterpret_cast<void*>(external), arg[0], arg[1]);
+          if (!stack_aligned) {
+            PrintF(" with unaligned stack %08" V8PRIxPTR "\n",
+                   get_register(sp));
+          }
+          PrintF("\n");
+        }
+        CHECK(stack_aligned);
+        SimulatorRuntimeProfilingApiCall target =
+            reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
+        target(arg[0], Redirection::ReverseRedirection(arg[1]));
+      } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
+        // See callers of MacroAssembler::CallApiFunctionAndReturn for
+        // explanation of register usage.
+        if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
+          PrintF("Call to host function at %p args %08" V8PRIxPTR
+                 " %08" V8PRIxPTR,
+                 reinterpret_cast<void*>(external), arg[0], arg[1]);
+          if (!stack_aligned) {
+            PrintF(" with unaligned stack %08" V8PRIxPTR "\n",
+                   get_register(sp));
+          }
+          PrintF("\n");
+        }
+        CHECK(stack_aligned);
+        SimulatorRuntimeDirectGetterCall target =
+            reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
+#if !ABI_PASSES_HANDLES_IN_REGS
+        arg[0] = *(reinterpret_cast<intptr_t*>(arg[0]));
+#endif
+        target(arg[0], arg[1]);
+      } else if (redirection->type() ==
+                 ExternalReference::PROFILING_GETTER_CALL) {
+        if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
+          PrintF("Call to host function at %p args %08" V8PRIxPTR
+                 " %08" V8PRIxPTR " %08" V8PRIxPTR,
+                 reinterpret_cast<void*>(external), arg[0], arg[1], arg[2]);
+          if (!stack_aligned) {
+            PrintF(" with unaligned stack %08" V8PRIxPTR "\n",
+                   get_register(sp));
+          }
+          PrintF("\n");
+        }
+        CHECK(stack_aligned);
+        SimulatorRuntimeProfilingGetterCall target =
+            reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
+#if !ABI_PASSES_HANDLES_IN_REGS
+        arg[0] = *(reinterpret_cast<intptr_t*>(arg[0]));
+#endif
+        target(arg[0], arg[1], Redirection::ReverseRedirection(arg[2]));
+      } else {
+        // builtin call.
+        if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
+          SimulatorRuntimeCall target =
+              reinterpret_cast<SimulatorRuntimeCall>(external);
+          PrintF(
+              "Call to host function at %p,\n"
+              "\t\t\t\targs %08" V8PRIxPTR ", %08" V8PRIxPTR ", %08" V8PRIxPTR
+              ", %08" V8PRIxPTR ", %08" V8PRIxPTR ", %08" V8PRIxPTR,
+              FUNCTION_ADDR(target), arg[0], arg[1], arg[2], arg[3], arg[4],
+              arg[5]);
+          if (!stack_aligned) {
+            PrintF(" with unaligned stack %08" V8PRIxPTR "\n",
+                   get_register(sp));
+          }
+          PrintF("\n");
+        }
+        CHECK(stack_aligned);
+#if !V8_TARGET_ARCH_PPC64
+        DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL);
+        SimulatorRuntimeCall target =
+            reinterpret_cast<SimulatorRuntimeCall>(external);
+        int64_t result = target(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
+        int32_t lo_res = static_cast<int32_t>(result);
+        int32_t hi_res = static_cast<int32_t>(result >> 32);
+#if V8_TARGET_BIG_ENDIAN
+        if (::v8::internal::FLAG_trace_sim) {
+          PrintF("Returned %08x\n", hi_res);
+        }
+        set_register(r3, hi_res);
+        set_register(r4, lo_res);
+#else
+        if (::v8::internal::FLAG_trace_sim) {
+          PrintF("Returned %08x\n", lo_res);
+        }
+        set_register(r3, lo_res);
+        set_register(r4, hi_res);
+#endif
+#else
+        if (redirection->type() == ExternalReference::BUILTIN_CALL) {
+          SimulatorRuntimeCall target =
+              reinterpret_cast<SimulatorRuntimeCall>(external);
+          intptr_t result =
+              target(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
+          if (::v8::internal::FLAG_trace_sim) {
+            PrintF("Returned %08" V8PRIxPTR "\n", result);
+          }
+          set_register(r3, result);
+        } else {
+          DCHECK(redirection->type() ==
+                 ExternalReference::BUILTIN_OBJECTPAIR_CALL);
+          SimulatorRuntimeObjectPairCall target =
+              reinterpret_cast<SimulatorRuntimeObjectPairCall>(external);
+          struct ObjectPair result =
+              target(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
+          if (::v8::internal::FLAG_trace_sim) {
+            PrintF("Returned %08" V8PRIxPTR ", %08" V8PRIxPTR "\n", result.x,
+                   result.y);
+          }
+#if ABI_RETURNS_OBJECT_PAIRS_IN_REGS
+          set_register(r3, result.x);
+          set_register(r4, result.y);
+#else
+          memcpy(reinterpret_cast<void*>(result_buffer), &result,
+                 sizeof(struct ObjectPair));
+#endif
+        }
+#endif
+      }
+      set_pc(saved_lr);
+      break;
+    }
+    case kBreakpoint: {
+      PPCDebugger dbg(this);
+      dbg.Debug();
+      break;
+    }
+    case kInfo: {
+      PPCDebugger dbg(this);
+      dbg.Info(instr);
+      break;
+    }
+    // stop uses all codes greater than 1 << 23.
+    default: {
+      if (svc >= (1 << 23)) {
+        uint32_t code = svc & kStopCodeMask;
+        if (isWatchedStop(code)) {
+          IncreaseStopCounter(code);
+        }
+        // Stop if it is enabled, otherwise go on jumping over the stop
+        // and the message address.
+        if (isEnabledStop(code)) {
+          PPCDebugger dbg(this);
+          dbg.Stop(instr);
+        } else {
+          set_pc(get_pc() + Instruction::kInstrSize + kPointerSize);
+        }
+      } else {
+        // This is not a valid svc code.
+        UNREACHABLE();
+        break;
+      }
+    }
+  }
+}
+
+
+// Stop helper functions.
+bool Simulator::isStopInstruction(Instruction* instr) {
+  return (instr->Bits(27, 24) == 0xF) && (instr->SvcValue() >= kStopCode);
+}
+
+
+bool Simulator::isWatchedStop(uint32_t code) {
+  DCHECK(code <= kMaxStopCode);
+  return code < kNumOfWatchedStops;
+}
+
+
+bool Simulator::isEnabledStop(uint32_t code) {
+  DCHECK(code <= kMaxStopCode);
+  // Unwatched stops are always enabled.
+  return !isWatchedStop(code) ||
+         !(watched_stops_[code].count & kStopDisabledBit);
+}
+
+
+void Simulator::EnableStop(uint32_t code) {
+  DCHECK(isWatchedStop(code));
+  if (!isEnabledStop(code)) {
+    watched_stops_[code].count &= ~kStopDisabledBit;
+  }
+}
+
+
+void Simulator::DisableStop(uint32_t code) {
+  DCHECK(isWatchedStop(code));
+  if (isEnabledStop(code)) {
+    watched_stops_[code].count |= kStopDisabledBit;
+  }
+}
+
+
+void Simulator::IncreaseStopCounter(uint32_t code) {
+  DCHECK(code <= kMaxStopCode);
+  DCHECK(isWatchedStop(code));
+  if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
+    PrintF(
+        "Stop counter for code %i has overflowed.\n"
+        "Enabling this code and reseting the counter to 0.\n",
+        code);
+    watched_stops_[code].count = 0;
+    EnableStop(code);
+  } else {
+    watched_stops_[code].count++;
+  }
+}
+
+
+// Print a stop status.
+void Simulator::PrintStopInfo(uint32_t code) {
+  DCHECK(code <= kMaxStopCode);
+  if (!isWatchedStop(code)) {
+    PrintF("Stop not watched.");
+  } else {
+    const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
+    int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
+    // Don't print the state of unused breakpoints.
+    if (count != 0) {
+      if (watched_stops_[code].desc) {
+        PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", code, code,
+               state, count, watched_stops_[code].desc);
+      } else {
+        PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n", code, code, state,
+               count);
+      }
+    }
+  }
+}
+
+
+void Simulator::SetCR0(intptr_t result, bool setSO) {
+  int bf = 0;
+  if (result < 0) {
+    bf |= 0x80000000;
+  }
+  if (result > 0) {
+    bf |= 0x40000000;
+  }
+  if (result == 0) {
+    bf |= 0x20000000;
+  }
+  if (setSO) {
+    bf |= 0x10000000;
+  }
+  condition_reg_ = (condition_reg_ & ~0xF0000000) | bf;
+}
+
+
+void Simulator::ExecuteBranchConditional(Instruction* instr) {
+  int bo = instr->Bits(25, 21) << 21;
+  int offset = (instr->Bits(15, 2) << 18) >> 16;
+  int condition_bit = instr->Bits(20, 16);
+  int condition_mask = 0x80000000 >> condition_bit;
+  switch (bo) {
+    case DCBNZF:  // Decrement CTR; branch if CTR != 0 and condition false
+    case DCBEZF:  // Decrement CTR; branch if CTR == 0 and condition false
+      UNIMPLEMENTED();
+    case BF: {  // Branch if condition false
+      if (!(condition_reg_ & condition_mask)) {
+        if (instr->Bit(0) == 1) {  // LK flag set
+          special_reg_lr_ = get_pc() + 4;
+        }
+        set_pc(get_pc() + offset);
+      }
+      break;
+    }
+    case DCBNZT:  // Decrement CTR; branch if CTR != 0 and condition true
+    case DCBEZT:  // Decrement CTR; branch if CTR == 0 and condition true
+      UNIMPLEMENTED();
+    case BT: {  // Branch if condition true
+      if (condition_reg_ & condition_mask) {
+        if (instr->Bit(0) == 1) {  // LK flag set
+          special_reg_lr_ = get_pc() + 4;
+        }
+        set_pc(get_pc() + offset);
+      }
+      break;
+    }
+    case DCBNZ:  // Decrement CTR; branch if CTR != 0
+    case DCBEZ:  // Decrement CTR; branch if CTR == 0
+      special_reg_ctr_ -= 1;
+      if ((special_reg_ctr_ == 0) == (bo == DCBEZ)) {
+        if (instr->Bit(0) == 1) {  // LK flag set
+          special_reg_lr_ = get_pc() + 4;
+        }
+        set_pc(get_pc() + offset);
+      }
+      break;
+    case BA: {                   // Branch always
+      if (instr->Bit(0) == 1) {  // LK flag set
+        special_reg_lr_ = get_pc() + 4;
+      }
+      set_pc(get_pc() + offset);
+      break;
+    }
+    default:
+      UNIMPLEMENTED();  // Invalid encoding
+  }
+}
+
+
+// Handle execution based on instruction types.
+void Simulator::ExecuteExt1(Instruction* instr) {
+  switch (instr->Bits(10, 1) << 1) {
+    case MCRF:
+      UNIMPLEMENTED();  // Not used by V8.
+    case BCLRX: {
+      // need to check BO flag
+      intptr_t old_pc = get_pc();
+      set_pc(special_reg_lr_);
+      if (instr->Bit(0) == 1) {  // LK flag set
+        special_reg_lr_ = old_pc + 4;
+      }
+      break;
+    }
+    case BCCTRX: {
+      // need to check BO flag
+      intptr_t old_pc = get_pc();
+      set_pc(special_reg_ctr_);
+      if (instr->Bit(0) == 1) {  // LK flag set
+        special_reg_lr_ = old_pc + 4;
+      }
+      break;
+    }
+    case CRNOR:
+    case RFI:
+    case CRANDC:
+      UNIMPLEMENTED();
+    case ISYNC: {
+      // todo - simulate isync
+      break;
+    }
+    case CRXOR: {
+      int bt = instr->Bits(25, 21);
+      int ba = instr->Bits(20, 16);
+      int bb = instr->Bits(15, 11);
+      int ba_val = ((0x80000000 >> ba) & condition_reg_) == 0 ? 0 : 1;
+      int bb_val = ((0x80000000 >> bb) & condition_reg_) == 0 ? 0 : 1;
+      int bt_val = ba_val ^ bb_val;
+      bt_val = bt_val << (31 - bt);  // shift bit to correct destination
+      condition_reg_ &= ~(0x80000000 >> bt);
+      condition_reg_ |= bt_val;
+      break;
+    }
+    case CREQV: {
+      int bt = instr->Bits(25, 21);
+      int ba = instr->Bits(20, 16);
+      int bb = instr->Bits(15, 11);
+      int ba_val = ((0x80000000 >> ba) & condition_reg_) == 0 ? 0 : 1;
+      int bb_val = ((0x80000000 >> bb) & condition_reg_) == 0 ? 0 : 1;
+      int bt_val = 1 - (ba_val ^ bb_val);
+      bt_val = bt_val << (31 - bt);  // shift bit to correct destination
+      condition_reg_ &= ~(0x80000000 >> bt);
+      condition_reg_ |= bt_val;
+      break;
+    }
+    case CRNAND:
+    case CRAND:
+    case CRORC:
+    case CROR:
+    default: {
+      UNIMPLEMENTED();  // Not used by V8.
+    }
+  }
+}
+
+
+bool Simulator::ExecuteExt2_10bit(Instruction* instr) {
+  bool found = true;
+
+  int opcode = instr->Bits(10, 1) << 1;
+  switch (opcode) {
+    case SRWX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      uint32_t rs_val = get_register(rs);
+      uintptr_t rb_val = get_register(rb);
+      intptr_t result = rs_val >> (rb_val & 0x3f);
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      break;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case SRDX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      uintptr_t rs_val = get_register(rs);
+      uintptr_t rb_val = get_register(rb);
+      intptr_t result = rs_val >> (rb_val & 0x7f);
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      break;
+    }
+#endif
+    case SRAW: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      int32_t rs_val = get_register(rs);
+      intptr_t rb_val = get_register(rb);
+      intptr_t result = rs_val >> (rb_val & 0x3f);
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      break;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case SRAD: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t rs_val = get_register(rs);
+      intptr_t rb_val = get_register(rb);
+      intptr_t result = rs_val >> (rb_val & 0x7f);
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      break;
+    }
+#endif
+    case SRAWIX: {
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      int sh = instr->Bits(15, 11);
+      int32_t rs_val = get_register(rs);
+      intptr_t result = rs_val >> sh;
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      break;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case EXTSW: {
+      const int shift = kBitsPerPointer - 32;
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      intptr_t rs_val = get_register(rs);
+      intptr_t ra_val = (rs_val << shift) >> shift;
+      set_register(ra, ra_val);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(ra_val);
+      }
+      break;
+    }
+#endif
+    case EXTSH: {
+      const int shift = kBitsPerPointer - 16;
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      intptr_t rs_val = get_register(rs);
+      intptr_t ra_val = (rs_val << shift) >> shift;
+      set_register(ra, ra_val);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(ra_val);
+      }
+      break;
+    }
+    case EXTSB: {
+      const int shift = kBitsPerPointer - 8;
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      intptr_t rs_val = get_register(rs);
+      intptr_t ra_val = (rs_val << shift) >> shift;
+      set_register(ra, ra_val);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(ra_val);
+      }
+      break;
+    }
+    case LFSUX:
+    case LFSX: {
+      int frt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      intptr_t rb_val = get_register(rb);
+      int32_t val = ReadW(ra_val + rb_val, instr);
+      float* fptr = reinterpret_cast<float*>(&val);
+      set_d_register_from_double(frt, static_cast<double>(*fptr));
+      if (opcode == LFSUX) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + rb_val);
+      }
+      break;
+    }
+    case LFDUX:
+    case LFDX: {
+      int frt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      intptr_t rb_val = get_register(rb);
+      double* dptr = reinterpret_cast<double*>(ReadDW(ra_val + rb_val));
+      set_d_register_from_double(frt, *dptr);
+      if (opcode == LFDUX) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + rb_val);
+      }
+      break;
+    }
+    case STFSUX: {
+      case STFSX:
+        int frs = instr->RSValue();
+        int ra = instr->RAValue();
+        int rb = instr->RBValue();
+        intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+        intptr_t rb_val = get_register(rb);
+        float frs_val = static_cast<float>(get_double_from_d_register(frs));
+        int32_t* p = reinterpret_cast<int32_t*>(&frs_val);
+        WriteW(ra_val + rb_val, *p, instr);
+        if (opcode == STFSUX) {
+          DCHECK(ra != 0);
+          set_register(ra, ra_val + rb_val);
+        }
+        break;
+    }
+    case STFDUX: {
+      case STFDX:
+        int frs = instr->RSValue();
+        int ra = instr->RAValue();
+        int rb = instr->RBValue();
+        intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+        intptr_t rb_val = get_register(rb);
+        double frs_val = get_double_from_d_register(frs);
+        int64_t* p = reinterpret_cast<int64_t*>(&frs_val);
+        WriteDW(ra_val + rb_val, *p);
+        if (opcode == STFDUX) {
+          DCHECK(ra != 0);
+          set_register(ra, ra_val + rb_val);
+        }
+        break;
+    }
+    case SYNC: {
+      // todo - simulate sync
+      break;
+    }
+    case ICBI: {
+      // todo - simulate icbi
+      break;
+    }
+    default: {
+      found = false;
+      break;
+    }
+  }
+
+  if (found) return found;
+
+  found = true;
+  opcode = instr->Bits(10, 2) << 2;
+  switch (opcode) {
+    case SRADIX: {
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      int sh = (instr->Bits(15, 11) | (instr->Bit(1) << 5));
+      intptr_t rs_val = get_register(rs);
+      intptr_t result = rs_val >> sh;
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      break;
+    }
+    default: {
+      found = false;
+      break;
+    }
+  }
+
+  return found;
+}
+
+
+bool Simulator::ExecuteExt2_9bit_part1(Instruction* instr) {
+  bool found = true;
+
+  int opcode = instr->Bits(9, 1) << 1;
+  switch (opcode) {
+    case TW: {
+      // used for call redirection in simulation mode
+      SoftwareInterrupt(instr);
+      break;
+    }
+    case CMP: {
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      int cr = instr->Bits(25, 23);
+      uint32_t bf = 0;
+#if V8_TARGET_ARCH_PPC64
+      int L = instr->Bit(21);
+      if (L) {
+#endif
+        intptr_t ra_val = get_register(ra);
+        intptr_t rb_val = get_register(rb);
+        if (ra_val < rb_val) {
+          bf |= 0x80000000;
+        }
+        if (ra_val > rb_val) {
+          bf |= 0x40000000;
+        }
+        if (ra_val == rb_val) {
+          bf |= 0x20000000;
+        }
+#if V8_TARGET_ARCH_PPC64
+      } else {
+        int32_t ra_val = get_register(ra);
+        int32_t rb_val = get_register(rb);
+        if (ra_val < rb_val) {
+          bf |= 0x80000000;
+        }
+        if (ra_val > rb_val) {
+          bf |= 0x40000000;
+        }
+        if (ra_val == rb_val) {
+          bf |= 0x20000000;
+        }
+      }
+#endif
+      uint32_t condition_mask = 0xF0000000U >> (cr * 4);
+      uint32_t condition = bf >> (cr * 4);
+      condition_reg_ = (condition_reg_ & ~condition_mask) | condition;
+      break;
+    }
+    case SUBFCX: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      // int oe = instr->Bit(10);
+      uintptr_t ra_val = get_register(ra);
+      uintptr_t rb_val = get_register(rb);
+      uintptr_t alu_out = ~ra_val + rb_val + 1;
+      set_register(rt, alu_out);
+      // If the sign of rb and alu_out don't match, carry = 0
+      if ((alu_out ^ rb_val) & 0x80000000) {
+        special_reg_xer_ &= ~0xF0000000;
+      } else {
+        special_reg_xer_ = (special_reg_xer_ & ~0xF0000000) | 0x20000000;
+      }
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(alu_out);
+      }
+      // todo - handle OE bit
+      break;
+    }
+    case ADDCX: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      // int oe = instr->Bit(10);
+      uintptr_t ra_val = get_register(ra);
+      uintptr_t rb_val = get_register(rb);
+      uintptr_t alu_out = ra_val + rb_val;
+      // Check overflow
+      if (~ra_val < rb_val) {
+        special_reg_xer_ = (special_reg_xer_ & ~0xF0000000) | 0x20000000;
+      } else {
+        special_reg_xer_ &= ~0xF0000000;
+      }
+      set_register(rt, alu_out);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(static_cast<intptr_t>(alu_out));
+      }
+      // todo - handle OE bit
+      break;
+    }
+    case MULHWX: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      int32_t ra_val = (get_register(ra) & 0xFFFFFFFF);
+      int32_t rb_val = (get_register(rb) & 0xFFFFFFFF);
+      int64_t alu_out = (int64_t)ra_val * (int64_t)rb_val;
+      alu_out >>= 32;
+      set_register(rt, alu_out);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(static_cast<intptr_t>(alu_out));
+      }
+      // todo - handle OE bit
+      break;
+    }
+    case NEGX: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      intptr_t ra_val = get_register(ra);
+      intptr_t alu_out = 1 + ~ra_val;
+#if V8_TARGET_ARCH_PPC64
+      intptr_t one = 1;  // work-around gcc
+      intptr_t kOverflowVal = (one << 63);
+#else
+      intptr_t kOverflowVal = kMinInt;
+#endif
+      set_register(rt, alu_out);
+      if (instr->Bit(10)) {  // OE bit set
+        if (ra_val == kOverflowVal) {
+          special_reg_xer_ |= 0xC0000000;  // set SO,OV
+        } else {
+          special_reg_xer_ &= ~0x40000000;  // clear OV
+        }
+      }
+      if (instr->Bit(0)) {  // RC bit set
+        bool setSO = (special_reg_xer_ & 0x80000000);
+        SetCR0(alu_out, setSO);
+      }
+      break;
+    }
+    case SLWX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      uint32_t rs_val = get_register(rs);
+      uintptr_t rb_val = get_register(rb);
+      uint32_t result = rs_val << (rb_val & 0x3f);
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      break;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case SLDX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      uintptr_t rs_val = get_register(rs);
+      uintptr_t rb_val = get_register(rb);
+      uintptr_t result = rs_val << (rb_val & 0x7f);
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      break;
+    }
+    case MFVSRD: {
+      DCHECK(!instr->Bit(0));
+      int frt = instr->RTValue();
+      int ra = instr->RAValue();
+      double frt_val = get_double_from_d_register(frt);
+      int64_t* p = reinterpret_cast<int64_t*>(&frt_val);
+      set_register(ra, *p);
+      break;
+    }
+    case MFVSRWZ: {
+      DCHECK(!instr->Bit(0));
+      int frt = instr->RTValue();
+      int ra = instr->RAValue();
+      double frt_val = get_double_from_d_register(frt);
+      int64_t* p = reinterpret_cast<int64_t*>(&frt_val);
+      set_register(ra, static_cast<uint32_t>(*p));
+      break;
+    }
+    case MTVSRD: {
+      DCHECK(!instr->Bit(0));
+      int frt = instr->RTValue();
+      int ra = instr->RAValue();
+      int64_t ra_val = get_register(ra);
+      double* p = reinterpret_cast<double*>(&ra_val);
+      set_d_register_from_double(frt, *p);
+      break;
+    }
+    case MTVSRWA: {
+      DCHECK(!instr->Bit(0));
+      int frt = instr->RTValue();
+      int ra = instr->RAValue();
+      int64_t ra_val = static_cast<int32_t>(get_register(ra));
+      double* p = reinterpret_cast<double*>(&ra_val);
+      set_d_register_from_double(frt, *p);
+      break;
+    }
+    case MTVSRWZ: {
+      DCHECK(!instr->Bit(0));
+      int frt = instr->RTValue();
+      int ra = instr->RAValue();
+      uint64_t ra_val = static_cast<uint32_t>(get_register(ra));
+      double* p = reinterpret_cast<double*>(&ra_val);
+      set_d_register_from_double(frt, *p);
+      break;
+    }
+#endif
+    default: {
+      found = false;
+      break;
+    }
+  }
+
+  return found;
+}
+
+
+void Simulator::ExecuteExt2_9bit_part2(Instruction* instr) {
+  int opcode = instr->Bits(9, 1) << 1;
+  switch (opcode) {
+    case CNTLZWX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      uintptr_t rs_val = get_register(rs);
+      uintptr_t count = 0;
+      int n = 0;
+      uintptr_t bit = 0x80000000;
+      for (; n < 32; n++) {
+        if (bit & rs_val) break;
+        count++;
+        bit >>= 1;
+      }
+      set_register(ra, count);
+      if (instr->Bit(0)) {  // RC Bit set
+        int bf = 0;
+        if (count > 0) {
+          bf |= 0x40000000;
+        }
+        if (count == 0) {
+          bf |= 0x20000000;
+        }
+        condition_reg_ = (condition_reg_ & ~0xF0000000) | bf;
+      }
+      break;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case CNTLZDX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      uintptr_t rs_val = get_register(rs);
+      uintptr_t count = 0;
+      int n = 0;
+      uintptr_t bit = 0x8000000000000000UL;
+      for (; n < 64; n++) {
+        if (bit & rs_val) break;
+        count++;
+        bit >>= 1;
+      }
+      set_register(ra, count);
+      if (instr->Bit(0)) {  // RC Bit set
+        int bf = 0;
+        if (count > 0) {
+          bf |= 0x40000000;
+        }
+        if (count == 0) {
+          bf |= 0x20000000;
+        }
+        condition_reg_ = (condition_reg_ & ~0xF0000000) | bf;
+      }
+      break;
+    }
+#endif
+    case ANDX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t rs_val = get_register(rs);
+      intptr_t rb_val = get_register(rb);
+      intptr_t alu_out = rs_val & rb_val;
+      set_register(ra, alu_out);
+      if (instr->Bit(0)) {  // RC Bit set
+        SetCR0(alu_out);
+      }
+      break;
+    }
+    case ANDCX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t rs_val = get_register(rs);
+      intptr_t rb_val = get_register(rb);
+      intptr_t alu_out = rs_val & ~rb_val;
+      set_register(ra, alu_out);
+      if (instr->Bit(0)) {  // RC Bit set
+        SetCR0(alu_out);
+      }
+      break;
+    }
+    case CMPL: {
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      int cr = instr->Bits(25, 23);
+      uint32_t bf = 0;
+#if V8_TARGET_ARCH_PPC64
+      int L = instr->Bit(21);
+      if (L) {
+#endif
+        uintptr_t ra_val = get_register(ra);
+        uintptr_t rb_val = get_register(rb);
+        if (ra_val < rb_val) {
+          bf |= 0x80000000;
+        }
+        if (ra_val > rb_val) {
+          bf |= 0x40000000;
+        }
+        if (ra_val == rb_val) {
+          bf |= 0x20000000;
+        }
+#if V8_TARGET_ARCH_PPC64
+      } else {
+        uint32_t ra_val = get_register(ra);
+        uint32_t rb_val = get_register(rb);
+        if (ra_val < rb_val) {
+          bf |= 0x80000000;
+        }
+        if (ra_val > rb_val) {
+          bf |= 0x40000000;
+        }
+        if (ra_val == rb_val) {
+          bf |= 0x20000000;
+        }
+      }
+#endif
+      uint32_t condition_mask = 0xF0000000U >> (cr * 4);
+      uint32_t condition = bf >> (cr * 4);
+      condition_reg_ = (condition_reg_ & ~condition_mask) | condition;
+      break;
+    }
+    case SUBFX: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      // int oe = instr->Bit(10);
+      intptr_t ra_val = get_register(ra);
+      intptr_t rb_val = get_register(rb);
+      intptr_t alu_out = rb_val - ra_val;
+      // todo - figure out underflow
+      set_register(rt, alu_out);
+      if (instr->Bit(0)) {  // RC Bit set
+        SetCR0(alu_out);
+      }
+      // todo - handle OE bit
+      break;
+    }
+    case ADDZEX: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      intptr_t ra_val = get_register(ra);
+      if (special_reg_xer_ & 0x20000000) {
+        ra_val += 1;
+      }
+      set_register(rt, ra_val);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(ra_val);
+      }
+      // todo - handle OE bit
+      break;
+    }
+    case NORX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t rs_val = get_register(rs);
+      intptr_t rb_val = get_register(rb);
+      intptr_t alu_out = ~(rs_val | rb_val);
+      set_register(ra, alu_out);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(alu_out);
+      }
+      break;
+    }
+    case MULLW: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      int32_t ra_val = (get_register(ra) & 0xFFFFFFFF);
+      int32_t rb_val = (get_register(rb) & 0xFFFFFFFF);
+      int32_t alu_out = ra_val * rb_val;
+      set_register(rt, alu_out);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(alu_out);
+      }
+      // todo - handle OE bit
+      break;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case MULLD: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      int64_t ra_val = get_register(ra);
+      int64_t rb_val = get_register(rb);
+      int64_t alu_out = ra_val * rb_val;
+      set_register(rt, alu_out);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(alu_out);
+      }
+      // todo - handle OE bit
+      break;
+    }
+#endif
+    case DIVW: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      int32_t ra_val = get_register(ra);
+      int32_t rb_val = get_register(rb);
+      bool overflow = (ra_val == kMinInt && rb_val == -1);
+      // result is undefined if divisor is zero or if operation
+      // is 0x80000000 / -1.
+      int32_t alu_out = (rb_val == 0 || overflow) ? -1 : ra_val / rb_val;
+      set_register(rt, alu_out);
+      if (instr->Bit(10)) {  // OE bit set
+        if (overflow) {
+          special_reg_xer_ |= 0xC0000000;  // set SO,OV
+        } else {
+          special_reg_xer_ &= ~0x40000000;  // clear OV
+        }
+      }
+      if (instr->Bit(0)) {  // RC bit set
+        bool setSO = (special_reg_xer_ & 0x80000000);
+        SetCR0(alu_out, setSO);
+      }
+      break;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case DIVD: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      int64_t ra_val = get_register(ra);
+      int64_t rb_val = get_register(rb);
+      int64_t one = 1;  // work-around gcc
+      int64_t kMinLongLong = (one << 63);
+      // result is undefined if divisor is zero or if operation
+      // is 0x80000000_00000000 / -1.
+      int64_t alu_out =
+          (rb_val == 0 || (ra_val == kMinLongLong && rb_val == -1))
+              ? -1
+              : ra_val / rb_val;
+      set_register(rt, alu_out);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(alu_out);
+      }
+      // todo - handle OE bit
+      break;
+    }
+#endif
+    case ADDX: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      // int oe = instr->Bit(10);
+      intptr_t ra_val = get_register(ra);
+      intptr_t rb_val = get_register(rb);
+      intptr_t alu_out = ra_val + rb_val;
+      set_register(rt, alu_out);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(alu_out);
+      }
+      // todo - handle OE bit
+      break;
+    }
+    case XORX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t rs_val = get_register(rs);
+      intptr_t rb_val = get_register(rb);
+      intptr_t alu_out = rs_val ^ rb_val;
+      set_register(ra, alu_out);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(alu_out);
+      }
+      break;
+    }
+    case ORX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t rs_val = get_register(rs);
+      intptr_t rb_val = get_register(rb);
+      intptr_t alu_out = rs_val | rb_val;
+      set_register(ra, alu_out);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(alu_out);
+      }
+      break;
+    }
+    case MFSPR: {
+      int rt = instr->RTValue();
+      int spr = instr->Bits(20, 11);
+      if (spr != 256) {
+        UNIMPLEMENTED();  // Only LRLR supported
+      }
+      set_register(rt, special_reg_lr_);
+      break;
+    }
+    case MTSPR: {
+      int rt = instr->RTValue();
+      intptr_t rt_val = get_register(rt);
+      int spr = instr->Bits(20, 11);
+      if (spr == 256) {
+        special_reg_lr_ = rt_val;
+      } else if (spr == 288) {
+        special_reg_ctr_ = rt_val;
+      } else if (spr == 32) {
+        special_reg_xer_ = rt_val;
+      } else {
+        UNIMPLEMENTED();  // Only LR supported
+      }
+      break;
+    }
+    case MFCR: {
+      int rt = instr->RTValue();
+      set_register(rt, condition_reg_);
+      break;
+    }
+    case STWUX:
+    case STWX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      int32_t rs_val = get_register(rs);
+      intptr_t rb_val = get_register(rb);
+      WriteW(ra_val + rb_val, rs_val, instr);
+      if (opcode == STWUX) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + rb_val);
+      }
+      break;
+    }
+    case STBUX:
+    case STBX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      int8_t rs_val = get_register(rs);
+      intptr_t rb_val = get_register(rb);
+      WriteB(ra_val + rb_val, rs_val);
+      if (opcode == STBUX) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + rb_val);
+      }
+      break;
+    }
+    case STHUX:
+    case STHX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      int16_t rs_val = get_register(rs);
+      intptr_t rb_val = get_register(rb);
+      WriteH(ra_val + rb_val, rs_val, instr);
+      if (opcode == STHUX) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + rb_val);
+      }
+      break;
+    }
+    case LWZX:
+    case LWZUX: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      intptr_t rb_val = get_register(rb);
+      set_register(rt, ReadWU(ra_val + rb_val, instr));
+      if (opcode == LWZUX) {
+        DCHECK(ra != 0 && ra != rt);
+        set_register(ra, ra_val + rb_val);
+      }
+      break;
+    }
+#if V8_TARGET_ARCH_PPC64
+    case LDX:
+    case LDUX: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      intptr_t rb_val = get_register(rb);
+      intptr_t* result = ReadDW(ra_val + rb_val);
+      set_register(rt, *result);
+      if (opcode == LDUX) {
+        DCHECK(ra != 0 && ra != rt);
+        set_register(ra, ra_val + rb_val);
+      }
+      break;
+    }
+    case STDX:
+    case STDUX: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      intptr_t rs_val = get_register(rs);
+      intptr_t rb_val = get_register(rb);
+      WriteDW(ra_val + rb_val, rs_val);
+      if (opcode == STDUX) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + rb_val);
+      }
+      break;
+    }
+#endif
+    case LBZX:
+    case LBZUX: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      intptr_t rb_val = get_register(rb);
+      set_register(rt, ReadBU(ra_val + rb_val) & 0xFF);
+      if (opcode == LBZUX) {
+        DCHECK(ra != 0 && ra != rt);
+        set_register(ra, ra_val + rb_val);
+      }
+      break;
+    }
+    case LHZX:
+    case LHZUX: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int rb = instr->RBValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      intptr_t rb_val = get_register(rb);
+      set_register(rt, ReadHU(ra_val + rb_val, instr) & 0xFFFF);
+      if (opcode == LHZUX) {
+        DCHECK(ra != 0 && ra != rt);
+        set_register(ra, ra_val + rb_val);
+      }
+      break;
+    }
+    case DCBF: {
+      // todo - simulate dcbf
+      break;
+    }
+    default: {
+      PrintF("Unimplemented: %08x\n", instr->InstructionBits());
+      UNIMPLEMENTED();  // Not used by V8.
+    }
+  }
+}
+
+
+void Simulator::ExecuteExt2(Instruction* instr) {
+  // Check first the 10-1 bit versions
+  if (ExecuteExt2_10bit(instr)) return;
+  // Now look at the lesser encodings
+  if (ExecuteExt2_9bit_part1(instr)) return;
+  ExecuteExt2_9bit_part2(instr);
+}
+
+
+void Simulator::ExecuteExt4(Instruction* instr) {
+  switch (instr->Bits(5, 1) << 1) {
+    case FDIV: {
+      int frt = instr->RTValue();
+      int fra = instr->RAValue();
+      int frb = instr->RBValue();
+      double fra_val = get_double_from_d_register(fra);
+      double frb_val = get_double_from_d_register(frb);
+      double frt_val = fra_val / frb_val;
+      set_d_register_from_double(frt, frt_val);
+      return;
+    }
+    case FSUB: {
+      int frt = instr->RTValue();
+      int fra = instr->RAValue();
+      int frb = instr->RBValue();
+      double fra_val = get_double_from_d_register(fra);
+      double frb_val = get_double_from_d_register(frb);
+      double frt_val = fra_val - frb_val;
+      set_d_register_from_double(frt, frt_val);
+      return;
+    }
+    case FADD: {
+      int frt = instr->RTValue();
+      int fra = instr->RAValue();
+      int frb = instr->RBValue();
+      double fra_val = get_double_from_d_register(fra);
+      double frb_val = get_double_from_d_register(frb);
+      double frt_val = fra_val + frb_val;
+      set_d_register_from_double(frt, frt_val);
+      return;
+    }
+    case FSQRT: {
+      int frt = instr->RTValue();
+      int frb = instr->RBValue();
+      double frb_val = get_double_from_d_register(frb);
+      double frt_val = std::sqrt(frb_val);
+      set_d_register_from_double(frt, frt_val);
+      return;
+    }
+    case FSEL: {
+      int frt = instr->RTValue();
+      int fra = instr->RAValue();
+      int frb = instr->RBValue();
+      int frc = instr->RCValue();
+      double fra_val = get_double_from_d_register(fra);
+      double frb_val = get_double_from_d_register(frb);
+      double frc_val = get_double_from_d_register(frc);
+      double frt_val = ((fra_val >= 0.0) ? frc_val : frb_val);
+      set_d_register_from_double(frt, frt_val);
+      return;
+    }
+    case FMUL: {
+      int frt = instr->RTValue();
+      int fra = instr->RAValue();
+      int frc = instr->RCValue();
+      double fra_val = get_double_from_d_register(fra);
+      double frc_val = get_double_from_d_register(frc);
+      double frt_val = fra_val * frc_val;
+      set_d_register_from_double(frt, frt_val);
+      return;
+    }
+    case FMSUB: {
+      int frt = instr->RTValue();
+      int fra = instr->RAValue();
+      int frb = instr->RBValue();
+      int frc = instr->RCValue();
+      double fra_val = get_double_from_d_register(fra);
+      double frb_val = get_double_from_d_register(frb);
+      double frc_val = get_double_from_d_register(frc);
+      double frt_val = (fra_val * frc_val) - frb_val;
+      set_d_register_from_double(frt, frt_val);
+      return;
+    }
+    case FMADD: {
+      int frt = instr->RTValue();
+      int fra = instr->RAValue();
+      int frb = instr->RBValue();
+      int frc = instr->RCValue();
+      double fra_val = get_double_from_d_register(fra);
+      double frb_val = get_double_from_d_register(frb);
+      double frc_val = get_double_from_d_register(frc);
+      double frt_val = (fra_val * frc_val) + frb_val;
+      set_d_register_from_double(frt, frt_val);
+      return;
+    }
+  }
+  int opcode = instr->Bits(10, 1) << 1;
+  switch (opcode) {
+    case FCMPU: {
+      int fra = instr->RAValue();
+      int frb = instr->RBValue();
+      double fra_val = get_double_from_d_register(fra);
+      double frb_val = get_double_from_d_register(frb);
+      int cr = instr->Bits(25, 23);
+      int bf = 0;
+      if (fra_val < frb_val) {
+        bf |= 0x80000000;
+      }
+      if (fra_val > frb_val) {
+        bf |= 0x40000000;
+      }
+      if (fra_val == frb_val) {
+        bf |= 0x20000000;
+      }
+      if (std::isunordered(fra_val, frb_val)) {
+        bf |= 0x10000000;
+      }
+      int condition_mask = 0xF0000000 >> (cr * 4);
+      int condition = bf >> (cr * 4);
+      condition_reg_ = (condition_reg_ & ~condition_mask) | condition;
+      return;
+    }
+    case FRSP: {
+      int frt = instr->RTValue();
+      int frb = instr->RBValue();
+      double frb_val = get_double_from_d_register(frb);
+      // frsp round 8-byte double-precision value to 8-byte
+      // single-precision value, ignore the round here
+      set_d_register_from_double(frt, frb_val);
+      if (instr->Bit(0)) {  // RC bit set
+                            //  UNIMPLEMENTED();
+      }
+      return;
+    }
+    case FCFID: {
+      int frt = instr->RTValue();
+      int frb = instr->RBValue();
+      double t_val = get_double_from_d_register(frb);
+      int64_t* frb_val_p = reinterpret_cast<int64_t*>(&t_val);
+      double frt_val = static_cast<double>(*frb_val_p);
+      set_d_register_from_double(frt, frt_val);
+      return;
+    }
+    case FCTID: {
+      int frt = instr->RTValue();
+      int frb = instr->RBValue();
+      double frb_val = get_double_from_d_register(frb);
+      int64_t frt_val;
+      int64_t one = 1;  // work-around gcc
+      int64_t kMinLongLong = (one << 63);
+      int64_t kMaxLongLong = kMinLongLong - 1;
+
+      if (frb_val > kMaxLongLong) {
+        frt_val = kMaxLongLong;
+      } else if (frb_val < kMinLongLong) {
+        frt_val = kMinLongLong;
+      } else {
+        switch (fp_condition_reg_ & kFPRoundingModeMask) {
+          case kRoundToZero:
+            frt_val = (int64_t)frb_val;
+            break;
+          case kRoundToPlusInf:
+            frt_val = (int64_t)std::ceil(frb_val);
+            break;
+          case kRoundToMinusInf:
+            frt_val = (int64_t)std::floor(frb_val);
+            break;
+          default:
+            frt_val = (int64_t)frb_val;
+            UNIMPLEMENTED();  // Not used by V8.
+            break;
+        }
+      }
+      double* p = reinterpret_cast<double*>(&frt_val);
+      set_d_register_from_double(frt, *p);
+      return;
+    }
+    case FCTIDZ: {
+      int frt = instr->RTValue();
+      int frb = instr->RBValue();
+      double frb_val = get_double_from_d_register(frb);
+      int64_t frt_val;
+      int64_t one = 1;  // work-around gcc
+      int64_t kMinLongLong = (one << 63);
+      int64_t kMaxLongLong = kMinLongLong - 1;
+
+      if (frb_val > kMaxLongLong) {
+        frt_val = kMaxLongLong;
+      } else if (frb_val < kMinLongLong) {
+        frt_val = kMinLongLong;
+      } else {
+        frt_val = (int64_t)frb_val;
+      }
+      double* p = reinterpret_cast<double*>(&frt_val);
+      set_d_register_from_double(frt, *p);
+      return;
+    }
+    case FCTIW:
+    case FCTIWZ: {
+      int frt = instr->RTValue();
+      int frb = instr->RBValue();
+      double frb_val = get_double_from_d_register(frb);
+      int64_t frt_val;
+      if (frb_val > kMaxInt) {
+        frt_val = kMaxInt;
+      } else if (frb_val < kMinInt) {
+        frt_val = kMinInt;
+      } else {
+        if (opcode == FCTIWZ) {
+          frt_val = (int64_t)frb_val;
+        } else {
+          switch (fp_condition_reg_ & kFPRoundingModeMask) {
+            case kRoundToZero:
+              frt_val = (int64_t)frb_val;
+              break;
+            case kRoundToPlusInf:
+              frt_val = (int64_t)std::ceil(frb_val);
+              break;
+            case kRoundToMinusInf:
+              frt_val = (int64_t)std::floor(frb_val);
+              break;
+            case kRoundToNearest:
+              frt_val = (int64_t)lround(frb_val);
+
+              // Round to even if exactly halfway.  (lround rounds up)
+              if (std::fabs(static_cast<double>(frt_val) - frb_val) == 0.5 &&
+                  (frt_val % 2)) {
+                frt_val += ((frt_val > 0) ? -1 : 1);
+              }
+
+              break;
+            default:
+              DCHECK(false);
+              frt_val = (int64_t)frb_val;
+              break;
+          }
+        }
+      }
+      double* p = reinterpret_cast<double*>(&frt_val);
+      set_d_register_from_double(frt, *p);
+      return;
+    }
+    case FNEG: {
+      int frt = instr->RTValue();
+      int frb = instr->RBValue();
+      double frb_val = get_double_from_d_register(frb);
+      double frt_val = -frb_val;
+      set_d_register_from_double(frt, frt_val);
+      return;
+    }
+    case FMR: {
+      int frt = instr->RTValue();
+      int frb = instr->RBValue();
+      double frb_val = get_double_from_d_register(frb);
+      double frt_val = frb_val;
+      set_d_register_from_double(frt, frt_val);
+      return;
+    }
+    case MTFSFI: {
+      int bf = instr->Bits(25, 23);
+      int imm = instr->Bits(15, 12);
+      int fp_condition_mask = 0xF0000000 >> (bf * 4);
+      fp_condition_reg_ &= ~fp_condition_mask;
+      fp_condition_reg_ |= (imm << (28 - (bf * 4)));
+      if (instr->Bit(0)) {  // RC bit set
+        condition_reg_ &= 0xF0FFFFFF;
+        condition_reg_ |= (imm << 23);
+      }
+      return;
+    }
+    case MTFSF: {
+      int frb = instr->RBValue();
+      double frb_dval = get_double_from_d_register(frb);
+      int64_t* p = reinterpret_cast<int64_t*>(&frb_dval);
+      int32_t frb_ival = static_cast<int32_t>((*p) & 0xffffffff);
+      int l = instr->Bits(25, 25);
+      if (l == 1) {
+        fp_condition_reg_ = frb_ival;
+      } else {
+        UNIMPLEMENTED();
+      }
+      if (instr->Bit(0)) {  // RC bit set
+        UNIMPLEMENTED();
+        // int w = instr->Bits(16, 16);
+        // int flm = instr->Bits(24, 17);
+      }
+      return;
+    }
+    case MFFS: {
+      int frt = instr->RTValue();
+      int64_t lval = static_cast<int64_t>(fp_condition_reg_);
+      double* p = reinterpret_cast<double*>(&lval);
+      set_d_register_from_double(frt, *p);
+      return;
+    }
+    case FABS: {
+      int frt = instr->RTValue();
+      int frb = instr->RBValue();
+      double frb_val = get_double_from_d_register(frb);
+      double frt_val = std::fabs(frb_val);
+      set_d_register_from_double(frt, frt_val);
+      return;
+    }
+    case FRIM: {
+      int frt = instr->RTValue();
+      int frb = instr->RBValue();
+      double frb_val = get_double_from_d_register(frb);
+      int64_t floor_val = (int64_t)frb_val;
+      if (floor_val > frb_val) floor_val--;
+      double frt_val = static_cast<double>(floor_val);
+      set_d_register_from_double(frt, frt_val);
+      return;
+    }
+  }
+  UNIMPLEMENTED();  // Not used by V8.
+}
+
+#if V8_TARGET_ARCH_PPC64
+void Simulator::ExecuteExt5(Instruction* instr) {
+  switch (instr->Bits(4, 2) << 2) {
+    case RLDICL: {
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      uintptr_t rs_val = get_register(rs);
+      int sh = (instr->Bits(15, 11) | (instr->Bit(1) << 5));
+      int mb = (instr->Bits(10, 6) | (instr->Bit(5) << 5));
+      DCHECK(sh >= 0 && sh <= 63);
+      DCHECK(mb >= 0 && mb <= 63);
+      // rotate left
+      uintptr_t result = (rs_val << sh) | (rs_val >> (64 - sh));
+      uintptr_t mask = 0xffffffffffffffff >> mb;
+      result &= mask;
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      return;
+    }
+    case RLDICR: {
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      uintptr_t rs_val = get_register(rs);
+      int sh = (instr->Bits(15, 11) | (instr->Bit(1) << 5));
+      int me = (instr->Bits(10, 6) | (instr->Bit(5) << 5));
+      DCHECK(sh >= 0 && sh <= 63);
+      DCHECK(me >= 0 && me <= 63);
+      // rotate left
+      uintptr_t result = (rs_val << sh) | (rs_val >> (64 - sh));
+      uintptr_t mask = 0xffffffffffffffff << (63 - me);
+      result &= mask;
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      return;
+    }
+    case RLDIC: {
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      uintptr_t rs_val = get_register(rs);
+      int sh = (instr->Bits(15, 11) | (instr->Bit(1) << 5));
+      int mb = (instr->Bits(10, 6) | (instr->Bit(5) << 5));
+      DCHECK(sh >= 0 && sh <= 63);
+      DCHECK(mb >= 0 && mb <= 63);
+      // rotate left
+      uintptr_t result = (rs_val << sh) | (rs_val >> (64 - sh));
+      uintptr_t mask = (0xffffffffffffffff >> mb) & (0xffffffffffffffff << sh);
+      result &= mask;
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      return;
+    }
+    case RLDIMI: {
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      uintptr_t rs_val = get_register(rs);
+      intptr_t ra_val = get_register(ra);
+      int sh = (instr->Bits(15, 11) | (instr->Bit(1) << 5));
+      int mb = (instr->Bits(10, 6) | (instr->Bit(5) << 5));
+      int me = 63 - sh;
+      // rotate left
+      uintptr_t result = (rs_val << sh) | (rs_val >> (64 - sh));
+      uintptr_t mask = 0;
+      if (mb < me + 1) {
+        uintptr_t bit = 0x8000000000000000 >> mb;
+        for (; mb <= me; mb++) {
+          mask |= bit;
+          bit >>= 1;
+        }
+      } else if (mb == me + 1) {
+        mask = 0xffffffffffffffff;
+      } else {                                           // mb > me+1
+        uintptr_t bit = 0x8000000000000000 >> (me + 1);  // needs to be tested
+        mask = 0xffffffffffffffff;
+        for (; me < mb; me++) {
+          mask ^= bit;
+          bit >>= 1;
+        }
+      }
+      result &= mask;
+      ra_val &= ~mask;
+      result |= ra_val;
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      return;
+    }
+  }
+  switch (instr->Bits(4, 1) << 1) {
+    case RLDCL: {
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      int rb = instr->RBValue();
+      uintptr_t rs_val = get_register(rs);
+      uintptr_t rb_val = get_register(rb);
+      int sh = (rb_val & 0x3f);
+      int mb = (instr->Bits(10, 6) | (instr->Bit(5) << 5));
+      DCHECK(sh >= 0 && sh <= 63);
+      DCHECK(mb >= 0 && mb <= 63);
+      // rotate left
+      uintptr_t result = (rs_val << sh) | (rs_val >> (64 - sh));
+      uintptr_t mask = 0xffffffffffffffff >> mb;
+      result &= mask;
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      return;
+    }
+  }
+  UNIMPLEMENTED();  // Not used by V8.
+}
+#endif
+
+
+void Simulator::ExecuteGeneric(Instruction* instr) {
+  int opcode = instr->OpcodeValue() << 26;
+  switch (opcode) {
+    case SUBFIC: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      intptr_t ra_val = get_register(ra);
+      int32_t im_val = instr->Bits(15, 0);
+      im_val = SIGN_EXT_IMM16(im_val);
+      intptr_t alu_out = im_val - ra_val;
+      set_register(rt, alu_out);
+      // todo - handle RC bit
+      break;
+    }
+    case CMPLI: {
+      int ra = instr->RAValue();
+      uint32_t im_val = instr->Bits(15, 0);
+      int cr = instr->Bits(25, 23);
+      uint32_t bf = 0;
+#if V8_TARGET_ARCH_PPC64
+      int L = instr->Bit(21);
+      if (L) {
+#endif
+        uintptr_t ra_val = get_register(ra);
+        if (ra_val < im_val) {
+          bf |= 0x80000000;
+        }
+        if (ra_val > im_val) {
+          bf |= 0x40000000;
+        }
+        if (ra_val == im_val) {
+          bf |= 0x20000000;
+        }
+#if V8_TARGET_ARCH_PPC64
+      } else {
+        uint32_t ra_val = get_register(ra);
+        if (ra_val < im_val) {
+          bf |= 0x80000000;
+        }
+        if (ra_val > im_val) {
+          bf |= 0x40000000;
+        }
+        if (ra_val == im_val) {
+          bf |= 0x20000000;
+        }
+      }
+#endif
+      uint32_t condition_mask = 0xF0000000U >> (cr * 4);
+      uint32_t condition = bf >> (cr * 4);
+      condition_reg_ = (condition_reg_ & ~condition_mask) | condition;
+      break;
+    }
+    case CMPI: {
+      int ra = instr->RAValue();
+      int32_t im_val = instr->Bits(15, 0);
+      im_val = SIGN_EXT_IMM16(im_val);
+      int cr = instr->Bits(25, 23);
+      uint32_t bf = 0;
+#if V8_TARGET_ARCH_PPC64
+      int L = instr->Bit(21);
+      if (L) {
+#endif
+        intptr_t ra_val = get_register(ra);
+        if (ra_val < im_val) {
+          bf |= 0x80000000;
+        }
+        if (ra_val > im_val) {
+          bf |= 0x40000000;
+        }
+        if (ra_val == im_val) {
+          bf |= 0x20000000;
+        }
+#if V8_TARGET_ARCH_PPC64
+      } else {
+        int32_t ra_val = get_register(ra);
+        if (ra_val < im_val) {
+          bf |= 0x80000000;
+        }
+        if (ra_val > im_val) {
+          bf |= 0x40000000;
+        }
+        if (ra_val == im_val) {
+          bf |= 0x20000000;
+        }
+      }
+#endif
+      uint32_t condition_mask = 0xF0000000U >> (cr * 4);
+      uint32_t condition = bf >> (cr * 4);
+      condition_reg_ = (condition_reg_ & ~condition_mask) | condition;
+      break;
+    }
+    case ADDIC: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      uintptr_t ra_val = get_register(ra);
+      uintptr_t im_val = SIGN_EXT_IMM16(instr->Bits(15, 0));
+      uintptr_t alu_out = ra_val + im_val;
+      // Check overflow
+      if (~ra_val < im_val) {
+        special_reg_xer_ = (special_reg_xer_ & ~0xF0000000) | 0x20000000;
+      } else {
+        special_reg_xer_ &= ~0xF0000000;
+      }
+      set_register(rt, alu_out);
+      break;
+    }
+    case ADDI: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int32_t im_val = SIGN_EXT_IMM16(instr->Bits(15, 0));
+      intptr_t alu_out;
+      if (ra == 0) {
+        alu_out = im_val;
+      } else {
+        intptr_t ra_val = get_register(ra);
+        alu_out = ra_val + im_val;
+      }
+      set_register(rt, alu_out);
+      // todo - handle RC bit
+      break;
+    }
+    case ADDIS: {
+      int rt = instr->RTValue();
+      int ra = instr->RAValue();
+      int32_t im_val = (instr->Bits(15, 0) << 16);
+      intptr_t alu_out;
+      if (ra == 0) {  // treat r0 as zero
+        alu_out = im_val;
+      } else {
+        intptr_t ra_val = get_register(ra);
+        alu_out = ra_val + im_val;
+      }
+      set_register(rt, alu_out);
+      break;
+    }
+    case BCX: {
+      ExecuteBranchConditional(instr);
+      break;
+    }
+    case BX: {
+      int offset = (instr->Bits(25, 2) << 8) >> 6;
+      if (instr->Bit(0) == 1) {  // LK flag set
+        special_reg_lr_ = get_pc() + 4;
+      }
+      set_pc(get_pc() + offset);
+      // todo - AA flag
+      break;
+    }
+    case EXT1: {
+      ExecuteExt1(instr);
+      break;
+    }
+    case RLWIMIX: {
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      uint32_t rs_val = get_register(rs);
+      int32_t ra_val = get_register(ra);
+      int sh = instr->Bits(15, 11);
+      int mb = instr->Bits(10, 6);
+      int me = instr->Bits(5, 1);
+      // rotate left
+      uint32_t result = (rs_val << sh) | (rs_val >> (32 - sh));
+      int mask = 0;
+      if (mb < me + 1) {
+        int bit = 0x80000000 >> mb;
+        for (; mb <= me; mb++) {
+          mask |= bit;
+          bit >>= 1;
+        }
+      } else if (mb == me + 1) {
+        mask = 0xffffffff;
+      } else {                             // mb > me+1
+        int bit = 0x80000000 >> (me + 1);  // needs to be tested
+        mask = 0xffffffff;
+        for (; me < mb; me++) {
+          mask ^= bit;
+          bit >>= 1;
+        }
+      }
+      result &= mask;
+      ra_val &= ~mask;
+      result |= ra_val;
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      break;
+    }
+    case RLWINMX:
+    case RLWNMX: {
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      uint32_t rs_val = get_register(rs);
+      int sh = 0;
+      if (opcode == RLWINMX) {
+        sh = instr->Bits(15, 11);
+      } else {
+        int rb = instr->RBValue();
+        uint32_t rb_val = get_register(rb);
+        sh = (rb_val & 0x1f);
+      }
+      int mb = instr->Bits(10, 6);
+      int me = instr->Bits(5, 1);
+      // rotate left
+      uint32_t result = (rs_val << sh) | (rs_val >> (32 - sh));
+      int mask = 0;
+      if (mb < me + 1) {
+        int bit = 0x80000000 >> mb;
+        for (; mb <= me; mb++) {
+          mask |= bit;
+          bit >>= 1;
+        }
+      } else if (mb == me + 1) {
+        mask = 0xffffffff;
+      } else {                             // mb > me+1
+        int bit = 0x80000000 >> (me + 1);  // needs to be tested
+        mask = 0xffffffff;
+        for (; me < mb; me++) {
+          mask ^= bit;
+          bit >>= 1;
+        }
+      }
+      result &= mask;
+      set_register(ra, result);
+      if (instr->Bit(0)) {  // RC bit set
+        SetCR0(result);
+      }
+      break;
+    }
+    case ORI: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      intptr_t rs_val = get_register(rs);
+      uint32_t im_val = instr->Bits(15, 0);
+      intptr_t alu_out = rs_val | im_val;
+      set_register(ra, alu_out);
+      break;
+    }
+    case ORIS: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      intptr_t rs_val = get_register(rs);
+      uint32_t im_val = instr->Bits(15, 0);
+      intptr_t alu_out = rs_val | (im_val << 16);
+      set_register(ra, alu_out);
+      break;
+    }
+    case XORI: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      intptr_t rs_val = get_register(rs);
+      uint32_t im_val = instr->Bits(15, 0);
+      intptr_t alu_out = rs_val ^ im_val;
+      set_register(ra, alu_out);
+      // todo - set condition based SO bit
+      break;
+    }
+    case XORIS: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      intptr_t rs_val = get_register(rs);
+      uint32_t im_val = instr->Bits(15, 0);
+      intptr_t alu_out = rs_val ^ (im_val << 16);
+      set_register(ra, alu_out);
+      break;
+    }
+    case ANDIx: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      intptr_t rs_val = get_register(rs);
+      uint32_t im_val = instr->Bits(15, 0);
+      intptr_t alu_out = rs_val & im_val;
+      set_register(ra, alu_out);
+      SetCR0(alu_out);
+      break;
+    }
+    case ANDISx: {
+      int rs = instr->RSValue();
+      int ra = instr->RAValue();
+      intptr_t rs_val = get_register(rs);
+      uint32_t im_val = instr->Bits(15, 0);
+      intptr_t alu_out = rs_val & (im_val << 16);
+      set_register(ra, alu_out);
+      SetCR0(alu_out);
+      break;
+    }
+    case EXT2: {
+      ExecuteExt2(instr);
+      break;
+    }
+
+    case LWZU:
+    case LWZ: {
+      int ra = instr->RAValue();
+      int rt = instr->RTValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
+      set_register(rt, ReadWU(ra_val + offset, instr));
+      if (opcode == LWZU) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + offset);
+      }
+      break;
+    }
+
+    case LBZU:
+    case LBZ: {
+      int ra = instr->RAValue();
+      int rt = instr->RTValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
+      set_register(rt, ReadB(ra_val + offset) & 0xFF);
+      if (opcode == LBZU) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + offset);
+      }
+      break;
+    }
+
+    case STWU:
+    case STW: {
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      int32_t rs_val = get_register(rs);
+      int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
+      WriteW(ra_val + offset, rs_val, instr);
+      if (opcode == STWU) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + offset);
+      }
+      // printf("r%d %08x -> %08x\n", rs, rs_val, offset); // 0xdead
+      break;
+    }
+
+    case STBU:
+    case STB: {
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      int8_t rs_val = get_register(rs);
+      int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
+      WriteB(ra_val + offset, rs_val);
+      if (opcode == STBU) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + offset);
+      }
+      break;
+    }
+
+    case LHZU:
+    case LHZ: {
+      int ra = instr->RAValue();
+      int rt = instr->RTValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
+      uintptr_t result = ReadHU(ra_val + offset, instr) & 0xffff;
+      set_register(rt, result);
+      if (opcode == LHZU) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + offset);
+      }
+      break;
+    }
+
+    case LHA:
+    case LHAU: {
+      UNIMPLEMENTED();
+      break;
+    }
+
+    case STHU:
+    case STH: {
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      int16_t rs_val = get_register(rs);
+      int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
+      WriteH(ra_val + offset, rs_val, instr);
+      if (opcode == STHU) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + offset);
+      }
+      break;
+    }
+
+    case LMW:
+    case STMW: {
+      UNIMPLEMENTED();
+      break;
+    }
+
+    case LFSU:
+    case LFS: {
+      int frt = instr->RTValue();
+      int ra = instr->RAValue();
+      int32_t offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      int32_t val = ReadW(ra_val + offset, instr);
+      float* fptr = reinterpret_cast<float*>(&val);
+      set_d_register_from_double(frt, static_cast<double>(*fptr));
+      if (opcode == LFSU) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + offset);
+      }
+      break;
+    }
+
+    case LFDU:
+    case LFD: {
+      int frt = instr->RTValue();
+      int ra = instr->RAValue();
+      int32_t offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      double* dptr = reinterpret_cast<double*>(ReadDW(ra_val + offset));
+      set_d_register_from_double(frt, *dptr);
+      if (opcode == LFDU) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + offset);
+      }
+      break;
+    }
+
+    case STFSU: {
+      case STFS:
+        int frs = instr->RSValue();
+        int ra = instr->RAValue();
+        int32_t offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
+        intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+        float frs_val = static_cast<float>(get_double_from_d_register(frs));
+        int32_t* p = reinterpret_cast<int32_t*>(&frs_val);
+        WriteW(ra_val + offset, *p, instr);
+        if (opcode == STFSU) {
+          DCHECK(ra != 0);
+          set_register(ra, ra_val + offset);
+        }
+        break;
+    }
+
+    case STFDU:
+    case STFD: {
+      int frs = instr->RSValue();
+      int ra = instr->RAValue();
+      int32_t offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
+      intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+      double frs_val = get_double_from_d_register(frs);
+      int64_t* p = reinterpret_cast<int64_t*>(&frs_val);
+      WriteDW(ra_val + offset, *p);
+      if (opcode == STFDU) {
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + offset);
+      }
+      break;
+    }
+
+    case EXT3:
+      UNIMPLEMENTED();
+    case EXT4: {
+      ExecuteExt4(instr);
+      break;
+    }
+
+#if V8_TARGET_ARCH_PPC64
+    case EXT5: {
+      ExecuteExt5(instr);
+      break;
+    }
+    case LD: {
+      int ra = instr->RAValue();
+      int rt = instr->RTValue();
+      int64_t ra_val = ra == 0 ? 0 : get_register(ra);
+      int offset = SIGN_EXT_IMM16(instr->Bits(15, 0) & ~3);
+      switch (instr->Bits(1, 0)) {
+        case 0: {  // ld
+          intptr_t* result = ReadDW(ra_val + offset);
+          set_register(rt, *result);
+          break;
+        }
+        case 1: {  // ldu
+          intptr_t* result = ReadDW(ra_val + offset);
+          set_register(rt, *result);
+          DCHECK(ra != 0);
+          set_register(ra, ra_val + offset);
+          break;
+        }
+        case 2: {  // lwa
+          intptr_t result = ReadW(ra_val + offset, instr);
+          set_register(rt, result);
+          break;
+        }
+      }
+      break;
+    }
+
+    case STD: {
+      int ra = instr->RAValue();
+      int rs = instr->RSValue();
+      int64_t ra_val = ra == 0 ? 0 : get_register(ra);
+      int64_t rs_val = get_register(rs);
+      int offset = SIGN_EXT_IMM16(instr->Bits(15, 0) & ~3);
+      WriteDW(ra_val + offset, rs_val);
+      if (instr->Bit(0) == 1) {  // This is the STDU form
+        DCHECK(ra != 0);
+        set_register(ra, ra_val + offset);
+      }
+      break;
+    }
+#endif
+
+    case FAKE_OPCODE: {
+      if (instr->Bits(MARKER_SUBOPCODE_BIT, MARKER_SUBOPCODE_BIT) == 1) {
+        int marker_code = instr->Bits(STUB_MARKER_HIGH_BIT, 0);
+        DCHECK(marker_code < F_NEXT_AVAILABLE_STUB_MARKER);
+        PrintF("Hit stub-marker: %d (EMIT_STUB_MARKER)\n", marker_code);
+      } else {
+        int fake_opcode = instr->Bits(FAKE_OPCODE_HIGH_BIT, 0);
+        if (fake_opcode == fBKPT) {
+          PPCDebugger dbg(this);
+          PrintF("Simulator hit BKPT.\n");
+          dbg.Debug();
+        } else {
+          DCHECK(fake_opcode < fLastFaker);
+          PrintF("Hit ARM opcode: %d(FAKE_OPCODE defined in constant-ppc.h)\n",
+                 fake_opcode);
+          UNIMPLEMENTED();
+        }
+      }
+      break;
+    }
+
+    default: {
+      UNIMPLEMENTED();
+      break;
+    }
+  }
+}  // NOLINT
+
+
+void Simulator::Trace(Instruction* instr) {
+  disasm::NameConverter converter;
+  disasm::Disassembler dasm(converter);
+  // use a reasonably large buffer
+  v8::internal::EmbeddedVector<char, 256> buffer;
+  dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
+  PrintF("%05d  %08" V8PRIxPTR "  %s\n", icount_,
+         reinterpret_cast<intptr_t>(instr), buffer.start());
+}
+
+
+// Executes the current instruction.
+void Simulator::ExecuteInstruction(Instruction* instr) {
+  if (v8::internal::FLAG_check_icache) {
+    CheckICache(isolate_->simulator_i_cache(), instr);
+  }
+  pc_modified_ = false;
+  if (::v8::internal::FLAG_trace_sim) {
+    Trace(instr);
+  }
+  int opcode = instr->OpcodeValue() << 26;
+  if (opcode == TWI) {
+    SoftwareInterrupt(instr);
+  } else {
+    ExecuteGeneric(instr);
+  }
+  if (!pc_modified_) {
+    set_pc(reinterpret_cast<intptr_t>(instr) + Instruction::kInstrSize);
+  }
+}
+
+
+void Simulator::Execute() {
+  // Get the PC to simulate. Cannot use the accessor here as we need the
+  // raw PC value and not the one used as input to arithmetic instructions.
+  intptr_t program_counter = get_pc();
+
+  if (::v8::internal::FLAG_stop_sim_at == 0) {
+    // Fast version of the dispatch loop without checking whether the simulator
+    // should be stopping at a particular executed instruction.
+    while (program_counter != end_sim_pc) {
+      Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
+      icount_++;
+      ExecuteInstruction(instr);
+      program_counter = get_pc();
+    }
+  } else {
+    // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
+    // we reach the particular instuction count.
+    while (program_counter != end_sim_pc) {
+      Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
+      icount_++;
+      if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
+        PPCDebugger dbg(this);
+        dbg.Debug();
+      } else {
+        ExecuteInstruction(instr);
+      }
+      program_counter = get_pc();
+    }
+  }
+}
+
+
+void Simulator::CallInternal(byte* entry) {
+// Prepare to execute the code at entry
+#if ABI_USES_FUNCTION_DESCRIPTORS
+  // entry is the function descriptor
+  set_pc(*(reinterpret_cast<intptr_t*>(entry)));
+#else
+  // entry is the instruction address
+  set_pc(reinterpret_cast<intptr_t>(entry));
+#endif
+
+  // Put down marker for end of simulation. The simulator will stop simulation
+  // when the PC reaches this value. By saving the "end simulation" value into
+  // the LR the simulation stops when returning to this call point.
+  special_reg_lr_ = end_sim_pc;
+
+  // Remember the values of non-volatile registers.
+  intptr_t r2_val = get_register(r2);
+  intptr_t r13_val = get_register(r13);
+  intptr_t r14_val = get_register(r14);
+  intptr_t r15_val = get_register(r15);
+  intptr_t r16_val = get_register(r16);
+  intptr_t r17_val = get_register(r17);
+  intptr_t r18_val = get_register(r18);
+  intptr_t r19_val = get_register(r19);
+  intptr_t r20_val = get_register(r20);
+  intptr_t r21_val = get_register(r21);
+  intptr_t r22_val = get_register(r22);
+  intptr_t r23_val = get_register(r23);
+  intptr_t r24_val = get_register(r24);
+  intptr_t r25_val = get_register(r25);
+  intptr_t r26_val = get_register(r26);
+  intptr_t r27_val = get_register(r27);
+  intptr_t r28_val = get_register(r28);
+  intptr_t r29_val = get_register(r29);
+  intptr_t r30_val = get_register(r30);
+  intptr_t r31_val = get_register(fp);
+
+  // Set up the non-volatile registers with a known value. To be able to check
+  // that they are preserved properly across JS execution.
+  intptr_t callee_saved_value = icount_;
+  set_register(r2, callee_saved_value);
+  set_register(r13, callee_saved_value);
+  set_register(r14, callee_saved_value);
+  set_register(r15, callee_saved_value);
+  set_register(r16, callee_saved_value);
+  set_register(r17, callee_saved_value);
+  set_register(r18, callee_saved_value);
+  set_register(r19, callee_saved_value);
+  set_register(r20, callee_saved_value);
+  set_register(r21, callee_saved_value);
+  set_register(r22, callee_saved_value);
+  set_register(r23, callee_saved_value);
+  set_register(r24, callee_saved_value);
+  set_register(r25, callee_saved_value);
+  set_register(r26, callee_saved_value);
+  set_register(r27, callee_saved_value);
+  set_register(r28, callee_saved_value);
+  set_register(r29, callee_saved_value);
+  set_register(r30, callee_saved_value);
+  set_register(fp, callee_saved_value);
+
+  // Start the simulation
+  Execute();
+
+  // Check that the non-volatile registers have been preserved.
+  CHECK_EQ(callee_saved_value, get_register(r2));
+  CHECK_EQ(callee_saved_value, get_register(r13));
+  CHECK_EQ(callee_saved_value, get_register(r14));
+  CHECK_EQ(callee_saved_value, get_register(r15));
+  CHECK_EQ(callee_saved_value, get_register(r16));
+  CHECK_EQ(callee_saved_value, get_register(r17));
+  CHECK_EQ(callee_saved_value, get_register(r18));
+  CHECK_EQ(callee_saved_value, get_register(r19));
+  CHECK_EQ(callee_saved_value, get_register(r20));
+  CHECK_EQ(callee_saved_value, get_register(r21));
+  CHECK_EQ(callee_saved_value, get_register(r22));
+  CHECK_EQ(callee_saved_value, get_register(r23));
+  CHECK_EQ(callee_saved_value, get_register(r24));
+  CHECK_EQ(callee_saved_value, get_register(r25));
+  CHECK_EQ(callee_saved_value, get_register(r26));
+  CHECK_EQ(callee_saved_value, get_register(r27));
+  CHECK_EQ(callee_saved_value, get_register(r28));
+  CHECK_EQ(callee_saved_value, get_register(r29));
+  CHECK_EQ(callee_saved_value, get_register(r30));
+  CHECK_EQ(callee_saved_value, get_register(fp));
+
+  // Restore non-volatile registers with the original value.
+  set_register(r2, r2_val);
+  set_register(r13, r13_val);
+  set_register(r14, r14_val);
+  set_register(r15, r15_val);
+  set_register(r16, r16_val);
+  set_register(r17, r17_val);
+  set_register(r18, r18_val);
+  set_register(r19, r19_val);
+  set_register(r20, r20_val);
+  set_register(r21, r21_val);
+  set_register(r22, r22_val);
+  set_register(r23, r23_val);
+  set_register(r24, r24_val);
+  set_register(r25, r25_val);
+  set_register(r26, r26_val);
+  set_register(r27, r27_val);
+  set_register(r28, r28_val);
+  set_register(r29, r29_val);
+  set_register(r30, r30_val);
+  set_register(fp, r31_val);
+}
+
+
+intptr_t Simulator::Call(byte* entry, int argument_count, ...) {
+  va_list parameters;
+  va_start(parameters, argument_count);
+  // Set up arguments
+
+  // First eight arguments passed in registers r3-r10.
+  int reg_arg_count = (argument_count > 8) ? 8 : argument_count;
+  int stack_arg_count = argument_count - reg_arg_count;
+  for (int i = 0; i < reg_arg_count; i++) {
+    set_register(i + 3, va_arg(parameters, intptr_t));
+  }
+
+  // Remaining arguments passed on stack.
+  intptr_t original_stack = get_register(sp);
+  // Compute position of stack on entry to generated code.
+  intptr_t entry_stack =
+      (original_stack -
+       (kNumRequiredStackFrameSlots + stack_arg_count) * sizeof(intptr_t));
+  if (base::OS::ActivationFrameAlignment() != 0) {
+    entry_stack &= -base::OS::ActivationFrameAlignment();
+  }
+  // Store remaining arguments on stack, from low to high memory.
+  // +2 is a hack for the LR slot + old SP on PPC
+  intptr_t* stack_argument =
+      reinterpret_cast<intptr_t*>(entry_stack) + kStackFrameExtraParamSlot;
+  for (int i = 0; i < stack_arg_count; i++) {
+    stack_argument[i] = va_arg(parameters, intptr_t);
+  }
+  va_end(parameters);
+  set_register(sp, entry_stack);
+
+  CallInternal(entry);
+
+  // Pop stack passed arguments.
+  CHECK_EQ(entry_stack, get_register(sp));
+  set_register(sp, original_stack);
+
+  intptr_t result = get_register(r3);
+  return result;
+}
+
+
+void Simulator::CallFP(byte* entry, double d0, double d1) {
+  set_d_register_from_double(1, d0);
+  set_d_register_from_double(2, d1);
+  CallInternal(entry);
+}
+
+
+int32_t Simulator::CallFPReturnsInt(byte* entry, double d0, double d1) {
+  CallFP(entry, d0, d1);
+  int32_t result = get_register(r3);
+  return result;
+}
+
+
+double Simulator::CallFPReturnsDouble(byte* entry, double d0, double d1) {
+  CallFP(entry, d0, d1);
+  return get_double_from_d_register(1);
+}
+
+
+uintptr_t Simulator::PushAddress(uintptr_t address) {
+  uintptr_t new_sp = get_register(sp) - sizeof(uintptr_t);
+  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
+  *stack_slot = address;
+  set_register(sp, new_sp);
+  return new_sp;
+}
+
+
+uintptr_t Simulator::PopAddress() {
+  uintptr_t current_sp = get_register(sp);
+  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
+  uintptr_t address = *stack_slot;
+  set_register(sp, current_sp + sizeof(uintptr_t));
+  return address;
+}
+}
+}  // namespace v8::internal
+
+#endif  // USE_SIMULATOR
+#endif  // V8_TARGET_ARCH_PPC
diff --git a/src/ppc/simulator-ppc.h b/src/ppc/simulator-ppc.h
new file mode 100644
index 0000000..98fe9a5
--- /dev/null
+++ b/src/ppc/simulator-ppc.h
@@ -0,0 +1,413 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+// Declares a Simulator for PPC instructions if we are not generating a native
+// PPC binary. This Simulator allows us to run and debug PPC code generation on
+// regular desktop machines.
+// V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro,
+// which will start execution in the Simulator or forwards to the real entry
+// on a PPC HW platform.
+
+#ifndef V8_PPC_SIMULATOR_PPC_H_
+#define V8_PPC_SIMULATOR_PPC_H_
+
+#include "src/allocation.h"
+
+#if !defined(USE_SIMULATOR)
+// Running without a simulator on a native ppc platform.
+
+namespace v8 {
+namespace internal {
+
+// When running without a simulator we call the entry directly.
+#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
+  (entry(p0, p1, p2, p3, p4))
+
+typedef int (*ppc_regexp_matcher)(String*, int, const byte*, const byte*, int*,
+                                  int, Address, int, void*, Isolate*);
+
+
+// Call the generated regexp code directly. The code at the entry address
+// should act as a function matching the type ppc_regexp_matcher.
+// The ninth argument is a dummy that reserves the space used for
+// the return address added by the ExitFrame in native calls.
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
+  (FUNCTION_CAST<ppc_regexp_matcher>(entry)(p0, p1, p2, p3, p4, p5, p6, p7,   \
+                                            NULL, p8))
+
+// The stack limit beyond which we will throw stack overflow errors in
+// generated code. Because generated code on ppc uses the C stack, we
+// just use the C stack limit.
+class SimulatorStack : public v8::internal::AllStatic {
+ public:
+  static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
+                                            uintptr_t c_limit) {
+    USE(isolate);
+    return c_limit;
+  }
+
+  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
+    return try_catch_address;
+  }
+
+  static inline void UnregisterCTryCatch() {}
+};
+}
+}  // namespace v8::internal
+
+#else  // !defined(USE_SIMULATOR)
+// Running with a simulator.
+
+#include "src/assembler.h"
+#include "src/hashmap.h"
+#include "src/ppc/constants-ppc.h"
+
+namespace v8 {
+namespace internal {
+
+class CachePage {
+ public:
+  static const int LINE_VALID = 0;
+  static const int LINE_INVALID = 1;
+
+  static const int kPageShift = 12;
+  static const int kPageSize = 1 << kPageShift;
+  static const int kPageMask = kPageSize - 1;
+  static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
+  static const int kLineLength = 1 << kLineShift;
+  static const int kLineMask = kLineLength - 1;
+
+  CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); }
+
+  char* ValidityByte(int offset) {
+    return &validity_map_[offset >> kLineShift];
+  }
+
+  char* CachedData(int offset) { return &data_[offset]; }
+
+ private:
+  char data_[kPageSize];  // The cached data.
+  static const int kValidityMapSize = kPageSize >> kLineShift;
+  char validity_map_[kValidityMapSize];  // One byte per line.
+};
+
+
+class Simulator {
+ public:
+  friend class PPCDebugger;
+  enum Register {
+    no_reg = -1,
+    r0 = 0,
+    sp,
+    r2,
+    r3,
+    r4,
+    r5,
+    r6,
+    r7,
+    r8,
+    r9,
+    r10,
+    r11,
+    r12,
+    r13,
+    r14,
+    r15,
+    r16,
+    r17,
+    r18,
+    r19,
+    r20,
+    r21,
+    r22,
+    r23,
+    r24,
+    r25,
+    r26,
+    r27,
+    r28,
+    r29,
+    r30,
+    fp,
+    kNumGPRs = 32,
+    d0 = 0,
+    d1,
+    d2,
+    d3,
+    d4,
+    d5,
+    d6,
+    d7,
+    d8,
+    d9,
+    d10,
+    d11,
+    d12,
+    d13,
+    d14,
+    d15,
+    d16,
+    d17,
+    d18,
+    d19,
+    d20,
+    d21,
+    d22,
+    d23,
+    d24,
+    d25,
+    d26,
+    d27,
+    d28,
+    d29,
+    d30,
+    d31,
+    kNumFPRs = 32
+  };
+
+  explicit Simulator(Isolate* isolate);
+  ~Simulator();
+
+  // The currently executing Simulator instance. Potentially there can be one
+  // for each native thread.
+  static Simulator* current(v8::internal::Isolate* isolate);
+
+  // Accessors for register state.
+  void set_register(int reg, intptr_t value);
+  intptr_t get_register(int reg) const;
+  double get_double_from_register_pair(int reg);
+  void set_d_register_from_double(int dreg, const double dbl) {
+    DCHECK(dreg >= 0 && dreg < kNumFPRs);
+    fp_registers_[dreg] = dbl;
+  }
+  double get_double_from_d_register(int dreg) { return fp_registers_[dreg]; }
+
+  // Special case of set_register and get_register to access the raw PC value.
+  void set_pc(intptr_t value);
+  intptr_t get_pc() const;
+
+  Address get_sp() {
+    return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
+  }
+
+  // Accessor to the internal simulator stack area.
+  uintptr_t StackLimit() const;
+
+  // Executes PPC instructions until the PC reaches end_sim_pc.
+  void Execute();
+
+  // Call on program start.
+  static void Initialize(Isolate* isolate);
+
+  // V8 generally calls into generated JS code with 5 parameters and into
+  // generated RegExp code with 7 parameters. This is a convenience function,
+  // which sets up the simulator state and grabs the result on return.
+  intptr_t Call(byte* entry, int argument_count, ...);
+  // Alternative: call a 2-argument double function.
+  void CallFP(byte* entry, double d0, double d1);
+  int32_t CallFPReturnsInt(byte* entry, double d0, double d1);
+  double CallFPReturnsDouble(byte* entry, double d0, double d1);
+
+  // Push an address onto the JS stack.
+  uintptr_t PushAddress(uintptr_t address);
+
+  // Pop an address from the JS stack.
+  uintptr_t PopAddress();
+
+  // Debugger input.
+  void set_last_debugger_input(char* input);
+  char* last_debugger_input() { return last_debugger_input_; }
+
+  // ICache checking.
+  static void FlushICache(v8::internal::HashMap* i_cache, void* start,
+                          size_t size);
+
+  // Returns true if pc register contains one of the 'special_values' defined
+  // below (bad_lr, end_sim_pc).
+  bool has_bad_pc() const;
+
+ private:
+  enum special_values {
+    // Known bad pc value to ensure that the simulator does not execute
+    // without being properly setup.
+    bad_lr = -1,
+    // A pc value used to signal the simulator to stop execution.  Generally
+    // the lr is set to this value on transition from native C code to
+    // simulated execution, so that the simulator can "return" to the native
+    // C code.
+    end_sim_pc = -2
+  };
+
+  // Unsupported instructions use Format to print an error and stop execution.
+  void Format(Instruction* instr, const char* format);
+
+  // Helper functions to set the conditional flags in the architecture state.
+  bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0);
+  bool BorrowFrom(int32_t left, int32_t right);
+  bool OverflowFrom(int32_t alu_out, int32_t left, int32_t right,
+                    bool addition);
+
+  // Helper functions to decode common "addressing" modes
+  int32_t GetShiftRm(Instruction* instr, bool* carry_out);
+  int32_t GetImm(Instruction* instr, bool* carry_out);
+  void ProcessPUW(Instruction* instr, int num_regs, int operand_size,
+                  intptr_t* start_address, intptr_t* end_address);
+  void HandleRList(Instruction* instr, bool load);
+  void HandleVList(Instruction* inst);
+  void SoftwareInterrupt(Instruction* instr);
+
+  // Stop helper functions.
+  inline bool isStopInstruction(Instruction* instr);
+  inline bool isWatchedStop(uint32_t bkpt_code);
+  inline bool isEnabledStop(uint32_t bkpt_code);
+  inline void EnableStop(uint32_t bkpt_code);
+  inline void DisableStop(uint32_t bkpt_code);
+  inline void IncreaseStopCounter(uint32_t bkpt_code);
+  void PrintStopInfo(uint32_t code);
+
+  // Read and write memory.
+  inline uint8_t ReadBU(intptr_t addr);
+  inline int8_t ReadB(intptr_t addr);
+  inline void WriteB(intptr_t addr, uint8_t value);
+  inline void WriteB(intptr_t addr, int8_t value);
+
+  inline uint16_t ReadHU(intptr_t addr, Instruction* instr);
+  inline int16_t ReadH(intptr_t addr, Instruction* instr);
+  // Note: Overloaded on the sign of the value.
+  inline void WriteH(intptr_t addr, uint16_t value, Instruction* instr);
+  inline void WriteH(intptr_t addr, int16_t value, Instruction* instr);
+
+  inline uint32_t ReadWU(intptr_t addr, Instruction* instr);
+  inline int32_t ReadW(intptr_t addr, Instruction* instr);
+  inline void WriteW(intptr_t addr, uint32_t value, Instruction* instr);
+  inline void WriteW(intptr_t addr, int32_t value, Instruction* instr);
+
+  intptr_t* ReadDW(intptr_t addr);
+  void WriteDW(intptr_t addr, int64_t value);
+
+  void Trace(Instruction* instr);
+  void SetCR0(intptr_t result, bool setSO = false);
+  void ExecuteBranchConditional(Instruction* instr);
+  void ExecuteExt1(Instruction* instr);
+  bool ExecuteExt2_10bit(Instruction* instr);
+  bool ExecuteExt2_9bit_part1(Instruction* instr);
+  void ExecuteExt2_9bit_part2(Instruction* instr);
+  void ExecuteExt2(Instruction* instr);
+  void ExecuteExt4(Instruction* instr);
+#if V8_TARGET_ARCH_PPC64
+  void ExecuteExt5(Instruction* instr);
+#endif
+  void ExecuteGeneric(Instruction* instr);
+
+  // Executes one instruction.
+  void ExecuteInstruction(Instruction* instr);
+
+  // ICache.
+  static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
+  static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
+                           int size);
+  static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
+
+  // Runtime call support.
+  static void* RedirectExternalReference(
+      void* external_function, v8::internal::ExternalReference::Type type);
+
+  // Handle arguments and return value for runtime FP functions.
+  void GetFpArgs(double* x, double* y, intptr_t* z);
+  void SetFpResult(const double& result);
+  void TrashCallerSaveRegisters();
+
+  void CallInternal(byte* entry);
+
+  // Architecture state.
+  // Saturating instructions require a Q flag to indicate saturation.
+  // There is currently no way to read the CPSR directly, and thus read the Q
+  // flag, so this is left unimplemented.
+  intptr_t registers_[kNumGPRs];
+  int32_t condition_reg_;
+  int32_t fp_condition_reg_;
+  intptr_t special_reg_lr_;
+  intptr_t special_reg_pc_;
+  intptr_t special_reg_ctr_;
+  int32_t special_reg_xer_;
+
+  double fp_registers_[kNumFPRs];
+
+  // Simulator support.
+  char* stack_;
+  bool pc_modified_;
+  int icount_;
+
+  // Debugger input.
+  char* last_debugger_input_;
+
+  // Icache simulation
+  v8::internal::HashMap* i_cache_;
+
+  // Registered breakpoints.
+  Instruction* break_pc_;
+  Instr break_instr_;
+
+  v8::internal::Isolate* isolate_;
+
+  // A stop is watched if its code is less than kNumOfWatchedStops.
+  // Only watched stops support enabling/disabling and the counter feature.
+  static const uint32_t kNumOfWatchedStops = 256;
+
+  // Breakpoint is disabled if bit 31 is set.
+  static const uint32_t kStopDisabledBit = 1 << 31;
+
+  // A stop is enabled, meaning the simulator will stop when meeting the
+  // instruction, if bit 31 of watched_stops_[code].count is unset.
+  // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
+  // the breakpoint was hit or gone through.
+  struct StopCountAndDesc {
+    uint32_t count;
+    char* desc;
+  };
+  StopCountAndDesc watched_stops_[kNumOfWatchedStops];
+};
+
+
+// When running with the simulator transition into simulated execution at this
+// point.
+#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4)                    \
+  reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
+      FUNCTION_ADDR(entry), 5, (intptr_t)p0, (intptr_t)p1, (intptr_t)p2,  \
+      (intptr_t)p3, (intptr_t)p4))
+
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
+  Simulator::current(Isolate::Current())                                      \
+      ->Call(entry, 10, (intptr_t)p0, (intptr_t)p1, (intptr_t)p2,             \
+             (intptr_t)p3, (intptr_t)p4, (intptr_t)p5, (intptr_t)p6,          \
+             (intptr_t)p7, (intptr_t)NULL, (intptr_t)p8)
+
+
+// The simulator has its own stack. Thus it has a different stack limit from
+// the C-based native code.  Setting the c_limit to indicate a very small
+// stack cause stack overflow errors, since the simulator ignores the input.
+// This is unlikely to be an issue in practice, though it might cause testing
+// trouble down the line.
+class SimulatorStack : public v8::internal::AllStatic {
+ public:
+  static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
+                                            uintptr_t c_limit) {
+    return Simulator::current(isolate)->StackLimit();
+  }
+
+  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
+    Simulator* sim = Simulator::current(Isolate::Current());
+    return sim->PushAddress(try_catch_address);
+  }
+
+  static inline void UnregisterCTryCatch() {
+    Simulator::current(Isolate::Current())->PopAddress();
+  }
+};
+}
+}  // namespace v8::internal
+
+#endif  // !defined(USE_SIMULATOR)
+#endif  // V8_PPC_SIMULATOR_PPC_H_
diff --git a/src/preparse-data.cc b/src/preparse-data.cc
index 15509c0..c101493 100644
--- a/src/preparse-data.cc
+++ b/src/preparse-data.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "include/v8stdint.h"
 #include "src/base/logging.h"
 #include "src/compiler.h"
 #include "src/globals.h"
diff --git a/src/preparser.cc b/src/preparser.cc
index 3173cc0..b552676 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -4,8 +4,6 @@
 
 #include <cmath>
 
-#include "include/v8stdint.h"
-
 #include "src/allocation.h"
 #include "src/base/logging.h"
 #include "src/conversions-inl.h"
@@ -19,26 +17,9 @@
 #include "src/unicode.h"
 #include "src/utils.h"
 
-#if V8_LIBC_MSVCRT && (_MSC_VER < 1800)
-namespace std {
-
-// Usually defined in math.h, but not in MSVC until VS2013+.
-// Abstracted to work
-int isfinite(double value);
-
-}  // namespace std
-#endif
-
 namespace v8 {
 namespace internal {
 
-class PreParserTraits::Checkpoint
-    : public ParserBase<PreParserTraits>::CheckpointBase {
- public:
-  explicit Checkpoint(ParserBase<PreParserTraits>* parser)
-      : ParserBase<PreParserTraits>::CheckpointBase(parser) {}
-};
-
 void PreParserTraits::ReportMessageAt(Scanner::Location location,
                                       const char* message,
                                       const char* arg,
@@ -69,6 +50,8 @@
     return PreParserIdentifier::FutureStrictReserved();
   } else if (scanner->current_token() == Token::LET) {
     return PreParserIdentifier::Let();
+  } else if (scanner->current_token() == Token::STATIC) {
+    return PreParserIdentifier::Static();
   } else if (scanner->current_token() == Token::YIELD) {
     return PreParserIdentifier::Yield();
   }
@@ -78,10 +61,10 @@
   if (scanner->UnescapedLiteralMatches("arguments", 9)) {
     return PreParserIdentifier::Arguments();
   }
-  if (scanner->UnescapedLiteralMatches("prototype", 9)) {
+  if (scanner->LiteralMatches("prototype", 9)) {
     return PreParserIdentifier::Prototype();
   }
-  if (scanner->UnescapedLiteralMatches("constructor", 11)) {
+  if (scanner->LiteralMatches("constructor", 11)) {
     return PreParserIdentifier::Constructor();
   }
   return PreParserIdentifier::Default();
@@ -122,13 +105,14 @@
     StrictMode strict_mode, bool is_generator, ParserRecorder* log) {
   log_ = log;
   // Lazy functions always have trivial outer scopes (no with/catch scopes).
-  PreParserScope top_scope(scope_, GLOBAL_SCOPE);
-  FunctionState top_state(&function_state_, &scope_, &top_scope, NULL,
-                          this->ast_value_factory());
+  PreParserScope top_scope(scope_, SCRIPT_SCOPE);
+  PreParserFactory top_factory(NULL);
+  FunctionState top_state(&function_state_, &scope_, &top_scope, &top_factory);
   scope_->SetStrictMode(strict_mode);
   PreParserScope function_scope(scope_, FUNCTION_SCOPE);
-  FunctionState function_state(&function_state_, &scope_, &function_scope, NULL,
-                               this->ast_value_factory());
+  PreParserFactory function_factory(NULL);
+  FunctionState function_state(&function_state_, &scope_, &function_scope,
+                               &function_factory);
   function_state.set_is_generator(is_generator);
   DCHECK_EQ(Token::LBRACE, scanner()->current_token());
   bool ok = true;
@@ -141,13 +125,21 @@
     DCHECK_EQ(Token::RBRACE, scanner()->peek());
     if (scope_->strict_mode() == STRICT) {
       int end_pos = scanner()->location().end_pos;
-      CheckOctalLiteral(start_position, end_pos, &ok);
+      CheckStrictOctalLiteral(start_position, end_pos, &ok);
     }
   }
   return kPreParseSuccess;
 }
 
 
+PreParserExpression PreParserTraits::ParseClassLiteral(
+    PreParserIdentifier name, Scanner::Location class_name_location,
+    bool name_is_strict_reserved, int pos, bool* ok) {
+  return pre_parser_->ParseClassLiteral(name, class_name_location,
+                                        name_is_strict_reserved, pos, ok);
+}
+
+
 // Preparsing checks a JavaScript program and emits preparse-data that helps
 // a later parsing to be faster.
 // See preparser-data.h for the data.
@@ -358,6 +350,12 @@
 
 PreParser::Statement PreParser::ParseClassDeclaration(bool* ok) {
   Expect(Token::CLASS, CHECK_OK);
+  if (!allow_harmony_sloppy() && strict_mode() == SLOPPY) {
+    ReportMessage("sloppy_lexical");
+    *ok = false;
+    return Statement::Default();
+  }
+
   int pos = position();
   bool is_strict_reserved = false;
   Identifier name =
@@ -427,6 +425,7 @@
   // ConstBinding ::
   //   BindingPattern '=' AssignmentExpression
   bool require_initializer = false;
+  bool is_strict_const = false;
   if (peek() == Token::VAR) {
     Consume(Token::VAR);
   } else if (peek() == Token::CONST) {
@@ -448,7 +447,8 @@
           *ok = false;
           return Statement::Default();
         }
-        require_initializer = true;
+        is_strict_const = true;
+        require_initializer = var_context != kForStatement;
       } else {
         Scanner::Location location = scanner()->peek_location();
         ReportMessageAt(location, "strict_const");
@@ -478,7 +478,9 @@
     if (nvars > 0) Consume(Token::COMMA);
     ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
     nvars++;
-    if (peek() == Token::ASSIGN || require_initializer) {
+    if (peek() == Token::ASSIGN || require_initializer ||
+        // require initializers for multiple consts.
+        (is_strict_const && peek() == Token::COMMA)) {
       Expect(Token::ASSIGN, CHECK_OK);
       ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
       if (decl_props != NULL) *decl_props = kHasInitializers;
@@ -505,8 +507,7 @@
     // identifier.
     DCHECK(!expr.AsIdentifier().IsFutureReserved());
     DCHECK(strict_mode() == SLOPPY ||
-           (!expr.AsIdentifier().IsFutureStrictReserved() &&
-            !expr.AsIdentifier().IsYield()));
+           !IsFutureStrictReserved(expr.AsIdentifier()));
     Consume(Token::COLON);
     return ParseStatement(ok);
     // Preparsing is disabled for extensions (because the extension details
@@ -514,6 +515,13 @@
     // accept "native function" in the preparser.
   }
   // Parsed expression statement.
+  // Detect attempts at 'let' declarations in sloppy mode.
+  if (peek() == Token::IDENTIFIER && strict_mode() == SLOPPY &&
+      expr.IsIdentifier() && expr.AsIdentifier().IsLet()) {
+    ReportMessage("sloppy_lexical", NULL);
+    *ok = false;
+    return Statement::Default();
+  }
   ExpectSemicolon(CHECK_OK);
   return Statement::ExpressionStatement(expr);
 }
@@ -693,16 +701,18 @@
 
   Expect(Token::FOR, CHECK_OK);
   Expect(Token::LPAREN, CHECK_OK);
+  bool is_let_identifier_expression = false;
   if (peek() != Token::SEMICOLON) {
     if (peek() == Token::VAR || peek() == Token::CONST ||
         (peek() == Token::LET && strict_mode() == STRICT)) {
-      bool is_let = peek() == Token::LET;
+      bool is_lexical = peek() == Token::LET ||
+                        (peek() == Token::CONST && strict_mode() == STRICT);
       int decl_count;
       VariableDeclarationProperties decl_props = kHasNoInitializers;
       ParseVariableDeclarations(
           kForStatement, &decl_props, &decl_count, CHECK_OK);
       bool has_initializers = decl_props == kHasInitializers;
-      bool accept_IN = decl_count == 1 && !(is_let && has_initializers);
+      bool accept_IN = decl_count == 1 && !(is_lexical && has_initializers);
       bool accept_OF = !has_initializers;
       if (accept_IN && CheckInOrOf(accept_OF)) {
         ParseExpression(true, CHECK_OK);
@@ -713,6 +723,8 @@
       }
     } else {
       Expression lhs = ParseExpression(false, CHECK_OK);
+      is_let_identifier_expression =
+          lhs.IsIdentifier() && lhs.AsIdentifier().IsLet();
       if (CheckInOrOf(lhs.IsIdentifier())) {
         ParseExpression(true, CHECK_OK);
         Expect(Token::RPAREN, CHECK_OK);
@@ -724,6 +736,13 @@
   }
 
   // Parsed initializer at this point.
+  // Detect attempts at 'let' declarations in sloppy mode.
+  if (peek() == Token::IDENTIFIER && strict_mode() == SLOPPY &&
+      is_let_identifier_expression) {
+    ReportMessage("sloppy_lexical", NULL);
+    *ok = false;
+    return Statement::Default();
+  }
   Expect(Token::SEMICOLON, CHECK_OK);
 
   if (peek() != Token::SEMICOLON) {
@@ -831,8 +850,9 @@
   // Parse function body.
   ScopeType outer_scope_type = scope_->type();
   PreParserScope function_scope(scope_, FUNCTION_SCOPE);
-  FunctionState function_state(&function_state_, &scope_, &function_scope, NULL,
-                               this->ast_value_factory());
+  PreParserFactory factory(NULL);
+  FunctionState function_state(&function_state_, &scope_, &function_scope,
+                               &factory);
   function_state.set_is_generator(IsGeneratorFunction(kind));
   //  FormalParameterList ::
   //    '(' (Identifier)*[','] ')'
@@ -874,7 +894,7 @@
 
   // See Parser::ParseFunctionLiteral for more information about lazy parsing
   // and lazy compilation.
-  bool is_lazily_parsed = (outer_scope_type == GLOBAL_SCOPE && allow_lazy() &&
+  bool is_lazily_parsed = (outer_scope_type == SCRIPT_SCOPE && allow_lazy() &&
                            !parenthesized_function_);
   parenthesized_function_ = false;
 
@@ -917,7 +937,7 @@
     }
 
     int end_position = scanner()->location().end_pos;
-    CheckOctalLiteral(start_position, end_position, CHECK_OK);
+    CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
   }
 
   return Expression::Default();
@@ -939,11 +959,52 @@
 }
 
 
+PreParserExpression PreParser::ParseClassLiteral(
+    PreParserIdentifier name, Scanner::Location class_name_location,
+    bool name_is_strict_reserved, int pos, bool* ok) {
+  // All parts of a ClassDeclaration and ClassExpression are strict code.
+  if (name_is_strict_reserved) {
+    ReportMessageAt(class_name_location, "unexpected_strict_reserved");
+    *ok = false;
+    return EmptyExpression();
+  }
+  if (IsEvalOrArguments(name)) {
+    ReportMessageAt(class_name_location, "strict_eval_arguments");
+    *ok = false;
+    return EmptyExpression();
+  }
+
+  PreParserScope scope = NewScope(scope_, BLOCK_SCOPE);
+  BlockState block_state(&scope_, &scope);
+  scope_->SetStrictMode(STRICT);
+  scope_->SetScopeName(name);
+
+  if (Check(Token::EXTENDS)) {
+    ParseLeftHandSideExpression(CHECK_OK);
+  }
+
+  bool has_seen_constructor = false;
+
+  Expect(Token::LBRACE, CHECK_OK);
+  while (peek() != Token::RBRACE) {
+    if (Check(Token::SEMICOLON)) continue;
+    const bool in_class = true;
+    const bool is_static = false;
+    ParsePropertyDefinition(NULL, in_class, is_static, &has_seen_constructor,
+                            CHECK_OK);
+  }
+
+  Expect(Token::RBRACE, CHECK_OK);
+
+  return Expression::Default();
+}
+
+
 PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
   // CallRuntime ::
   //   '%' Identifier Arguments
   Expect(Token::MOD, CHECK_OK);
-  if (!allow_natives_syntax()) {
+  if (!allow_natives()) {
     *ok = false;
     return Expression::Default();
   }
diff --git a/src/preparser.h b/src/preparser.h
index 78f6a26..5fb60d0 100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -70,7 +70,6 @@
 
   ParserBase(Scanner* scanner, uintptr_t stack_limit, v8::Extension* extension,
              ParserRecorder* log, typename Traits::Type::Zone* zone,
-             AstNode::IdGen* ast_node_id_gen,
              typename Traits::Type::Parser this_object)
       : Traits(this_object),
         parenthesized_function_(false),
@@ -84,47 +83,65 @@
         scanner_(scanner),
         stack_overflow_(false),
         allow_lazy_(false),
-        allow_natives_syntax_(false),
-        allow_arrow_functions_(false),
+        allow_natives_(false),
+        allow_harmony_arrow_functions_(false),
         allow_harmony_object_literals_(false),
-        zone_(zone),
-        ast_node_id_gen_(ast_node_id_gen) {}
+        allow_harmony_sloppy_(false),
+        zone_(zone) {}
 
   // Getters that indicate whether certain syntactical constructs are
   // allowed to be parsed by this instance of the parser.
   bool allow_lazy() const { return allow_lazy_; }
-  bool allow_natives_syntax() const { return allow_natives_syntax_; }
-  bool allow_arrow_functions() const { return allow_arrow_functions_; }
-  bool allow_modules() const { return scanner()->HarmonyModules(); }
+  bool allow_natives() const { return allow_natives_; }
+  bool allow_harmony_arrow_functions() const {
+    return allow_harmony_arrow_functions_;
+  }
+  bool allow_harmony_modules() const { return scanner()->HarmonyModules(); }
   bool allow_harmony_scoping() const { return scanner()->HarmonyScoping(); }
   bool allow_harmony_numeric_literals() const {
     return scanner()->HarmonyNumericLiterals();
   }
-  bool allow_classes() const { return scanner()->HarmonyClasses(); }
+  bool allow_harmony_classes() const { return scanner()->HarmonyClasses(); }
   bool allow_harmony_object_literals() const {
     return allow_harmony_object_literals_;
   }
+  bool allow_harmony_templates() const { return scanner()->HarmonyTemplates(); }
+  bool allow_harmony_sloppy() const { return allow_harmony_sloppy_; }
+  bool allow_harmony_unicode() const { return scanner()->HarmonyUnicode(); }
 
   // Setters that determine whether certain syntactical constructs are
   // allowed to be parsed by this instance of the parser.
   void set_allow_lazy(bool allow) { allow_lazy_ = allow; }
-  void set_allow_natives_syntax(bool allow) { allow_natives_syntax_ = allow; }
-  void set_allow_arrow_functions(bool allow) { allow_arrow_functions_ = allow; }
-  void set_allow_modules(bool allow) { scanner()->SetHarmonyModules(allow); }
+  void set_allow_natives(bool allow) { allow_natives_ = allow; }
+  void set_allow_harmony_arrow_functions(bool allow) {
+    allow_harmony_arrow_functions_ = allow;
+  }
+  void set_allow_harmony_modules(bool allow) {
+    scanner()->SetHarmonyModules(allow);
+  }
   void set_allow_harmony_scoping(bool allow) {
     scanner()->SetHarmonyScoping(allow);
   }
   void set_allow_harmony_numeric_literals(bool allow) {
     scanner()->SetHarmonyNumericLiterals(allow);
   }
-  void set_allow_classes(bool allow) { scanner()->SetHarmonyClasses(allow); }
+  void set_allow_harmony_classes(bool allow) {
+    scanner()->SetHarmonyClasses(allow);
+  }
   void set_allow_harmony_object_literals(bool allow) {
     allow_harmony_object_literals_ = allow;
   }
+  void set_allow_harmony_templates(bool allow) {
+    scanner()->SetHarmonyTemplates(allow);
+  }
+  void set_allow_harmony_sloppy(bool allow) {
+    allow_harmony_sloppy_ = allow;
+  }
+  void set_allow_harmony_unicode(bool allow) {
+    scanner()->SetHarmonyUnicode(allow);
+  }
 
  protected:
-  friend class Traits::Checkpoint;
-
   enum AllowEvalOrArgumentsAsIdentifier {
     kAllowEvalOrArguments,
     kDontAllowEvalOrArguments
@@ -135,7 +152,7 @@
     PARSE_EAGERLY
   };
 
-  class CheckpointBase;
+  class Checkpoint;
   class ObjectLiteralChecker;
 
   // ---------------------------------------------------------------------------
@@ -165,15 +182,7 @@
     FunctionState(FunctionState** function_state_stack,
                   typename Traits::Type::Scope** scope_stack,
                   typename Traits::Type::Scope* scope,
-                  typename Traits::Type::Zone* zone = NULL,
-                  AstValueFactory* ast_value_factory = NULL,
-                  AstNode::IdGen* ast_node_id_gen = NULL);
-    FunctionState(FunctionState** function_state_stack,
-                  typename Traits::Type::Scope** scope_stack,
-                  typename Traits::Type::Scope** scope,
-                  typename Traits::Type::Zone* zone = NULL,
-                  AstValueFactory* ast_value_factory = NULL,
-                  AstNode::IdGen* ast_node_id_gen = NULL);
+                  typename Traits::Type::Factory* factory);
     ~FunctionState();
 
     int NextMaterializedLiteralIndex() {
@@ -204,7 +213,7 @@
       return generator_object_variable_;
     }
 
-    typename Traits::Type::Factory* factory() { return &factory_; }
+    typename Traits::Type::Factory* factory() { return factory_; }
 
    private:
     // Used to assign an index to each literal that needs materialization in
@@ -229,22 +238,20 @@
     FunctionState* outer_function_state_;
     typename Traits::Type::Scope** scope_stack_;
     typename Traits::Type::Scope* outer_scope_;
-    AstNode::IdGen* ast_node_id_gen_;  // Only used by ParserTraits.
-    AstNode::IdGen saved_id_gen_;      // Ditto.
     typename Traits::Type::Zone* extra_param_;
-    typename Traits::Type::Factory factory_;
+    typename Traits::Type::Factory* factory_;
 
     friend class ParserTraits;
-    friend class CheckpointBase;
+    friend class Checkpoint;
   };
 
   // Annoyingly, arrow functions first parse as comma expressions, then when we
   // see the => we have to go back and reinterpret the arguments as being formal
   // parameters.  To do so we need to reset some of the parser state back to
   // what it was before the arguments were first seen.
-  class CheckpointBase BASE_EMBEDDED {
+  class Checkpoint BASE_EMBEDDED {
    public:
-    explicit CheckpointBase(ParserBase* parser) {
+    explicit Checkpoint(ParserBase* parser) {
       function_state_ = parser->function_state_;
       next_materialized_literal_index_ =
           function_state_->next_materialized_literal_index_;
@@ -289,7 +296,6 @@
   void set_stack_overflow() { stack_overflow_ = true; }
   Mode mode() const { return mode_; }
   typename Traits::Type::Zone* zone() const { return zone_; }
-  AstNode::IdGen* ast_node_id_gen() const { return ast_node_id_gen_; }
 
   INLINE(Token::Value peek()) {
     if (stack_overflow_) return Token::ILLEGAL;
@@ -351,22 +357,24 @@
 
   bool peek_any_identifier() {
     Token::Value next = peek();
-    return next == Token::IDENTIFIER ||
-        next == Token::FUTURE_RESERVED_WORD ||
-        next == Token::FUTURE_STRICT_RESERVED_WORD ||
-        next == Token::LET ||
-        next == Token::YIELD;
+    return next == Token::IDENTIFIER || next == Token::FUTURE_RESERVED_WORD ||
+           next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
+           next == Token::STATIC || next == Token::YIELD;
   }
 
   bool CheckContextualKeyword(Vector<const char> keyword) {
-    if (peek() == Token::IDENTIFIER &&
-        scanner()->is_next_contextual_keyword(keyword)) {
+    if (PeekContextualKeyword(keyword)) {
       Consume(Token::IDENTIFIER);
       return true;
     }
     return false;
   }
 
+  bool PeekContextualKeyword(Vector<const char> keyword) {
+    return peek() == Token::IDENTIFIER &&
+           scanner()->is_next_contextual_keyword(keyword);
+  }
+
   void ExpectContextualKeyword(Vector<const char> keyword, bool* ok) {
     Expect(Token::IDENTIFIER, ok);
     if (!*ok) return;
@@ -377,17 +385,26 @@
   }
 
   // Checks whether an octal literal was last seen between beg_pos and end_pos.
-  // If so, reports an error. Only called for strict mode.
-  void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
+  // If so, reports an error. Only called for strict mode and template strings.
+  void CheckOctalLiteral(int beg_pos, int end_pos, const char* error,
+                         bool* ok) {
     Scanner::Location octal = scanner()->octal_position();
     if (octal.IsValid() && beg_pos <= octal.beg_pos &&
         octal.end_pos <= end_pos) {
-      ReportMessageAt(octal, "strict_octal_literal");
+      ReportMessageAt(octal, error);
       scanner()->clear_octal_position();
       *ok = false;
     }
   }
 
+  inline void CheckStrictOctalLiteral(int beg_pos, int end_pos, bool* ok) {
+    CheckOctalLiteral(beg_pos, end_pos, "strict_octal_literal", ok);
+  }
+
+  inline void CheckTemplateOctalLiteral(int beg_pos, int end_pos, bool* ok) {
+    CheckOctalLiteral(beg_pos, end_pos, "template_octal_literal", ok);
+  }
+
   // Validates strict mode for function parameter lists. This has to be
   // done after parsing the function, since the function can declare
   // itself strict.
@@ -450,7 +467,7 @@
   void ReportMessageAt(Scanner::Location location, const char* message,
                        bool is_reference_error = false) {
     Traits::ReportMessageAt(location, message,
-                            reinterpret_cast<const char*>(NULL),
+                            reinterpret_cast<const char*>(0),
                             is_reference_error);
   }
 
@@ -487,6 +504,7 @@
   ExpressionT ParseObjectLiteral(bool* ok);
   ObjectLiteralPropertyT ParsePropertyDefinition(ObjectLiteralChecker* checker,
                                                  bool in_class, bool is_static,
+                                                 bool* has_seen_constructor,
                                                  bool* ok);
   typename Traits::Type::ExpressionList ParseArguments(bool* ok);
   ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok);
@@ -502,10 +520,8 @@
                                                 bool* ok);
   ExpressionT ParseArrowFunctionLiteral(int start_pos, ExpressionT params_ast,
                                         bool* ok);
-  ExpressionT ParseClassLiteral(IdentifierT name,
-                                Scanner::Location function_name_location,
-                                bool name_is_strict_reserved, int pos,
-                                bool* ok);
+  ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool* ok);
+  void AddTemplateExpression(ExpressionT);
 
   // Checks if the expression is a valid reference expression (e.g., on the
   // left-hand side of assignments). Although ruled out by ECMA as early errors,
@@ -587,12 +603,12 @@
   bool stack_overflow_;
 
   bool allow_lazy_;
-  bool allow_natives_syntax_;
-  bool allow_arrow_functions_;
+  bool allow_natives_;
+  bool allow_harmony_arrow_functions_;
   bool allow_harmony_object_literals_;
+  bool allow_harmony_sloppy_;
 
   typename Traits::Type::Zone* zone_;  // Only used by Parser.
-  AstNode::IdGen* ast_node_id_gen_;
 };
 
 
@@ -617,6 +633,9 @@
   static PreParserIdentifier Let() {
     return PreParserIdentifier(kLetIdentifier);
   }
+  static PreParserIdentifier Static() {
+    return PreParserIdentifier(kStaticIdentifier);
+  }
   static PreParserIdentifier Yield() {
     return PreParserIdentifier(kYieldIdentifier);
   }
@@ -627,7 +646,11 @@
     return PreParserIdentifier(kConstructorIdentifier);
   }
   bool IsEval() const { return type_ == kEvalIdentifier; }
-  bool IsArguments() const { return type_ == kArgumentsIdentifier; }
+  bool IsArguments(const AstValueFactory* = NULL) const {
+    return type_ == kArgumentsIdentifier;
+  }
+  bool IsLet() const { return type_ == kLetIdentifier; }
+  bool IsStatic() const { return type_ == kStaticIdentifier; }
   bool IsYield() const { return type_ == kYieldIdentifier; }
   bool IsPrototype() const { return type_ == kPrototypeIdentifier; }
   bool IsConstructor() const { return type_ == kConstructorIdentifier; }
@@ -636,9 +659,16 @@
   }
   bool IsFutureReserved() const { return type_ == kFutureReservedIdentifier; }
   bool IsFutureStrictReserved() const {
-    return type_ == kFutureStrictReservedIdentifier;
+    return type_ == kFutureStrictReservedIdentifier ||
+           type_ == kLetIdentifier || type_ == kStaticIdentifier ||
+           type_ == kYieldIdentifier;
   }
   bool IsValidStrictVariable() const { return type_ == kUnknownIdentifier; }
+  V8_INLINE bool IsValidArrowParam() const {
+    // A valid identifier can be an arrow function parameter
+    // except for eval, arguments, yield, and reserved keywords.
+    return !(IsEval() || IsArguments() || IsFutureStrictReserved());
+  }
 
   // Allow identifier->name()[->length()] to work. The preparser
   // does not need the actual positions/lengths of the identifiers.
@@ -654,6 +684,7 @@
     kFutureReservedIdentifier,
     kFutureStrictReservedIdentifier,
     kLetIdentifier,
+    kStaticIdentifier,
     kYieldIdentifier,
     kEvalIdentifier,
     kArgumentsIdentifier,
@@ -668,30 +699,27 @@
 };
 
 
-// Bits 0 and 1 are used to identify the type of expression:
-// If bit 0 is set, it's an identifier.
-// if bit 1 is set, it's a string literal.
-// If neither is set, it's no particular type, and both set isn't
-// use yet.
 class PreParserExpression {
  public:
   static PreParserExpression Default() {
-    return PreParserExpression(kUnknownExpression);
+    return PreParserExpression(TypeField::encode(kExpression));
   }
 
   static PreParserExpression FromIdentifier(PreParserIdentifier id) {
-    return PreParserExpression(kTypeIdentifier |
-                               (id.type_ << kIdentifierShift));
+    return PreParserExpression(TypeField::encode(kIdentifierExpression) |
+                               IdentifierTypeField::encode(id.type_));
   }
 
   static PreParserExpression BinaryOperation(PreParserExpression left,
                                              Token::Value op,
                                              PreParserExpression right) {
-    int code = ((op == Token::COMMA) && !left.is_parenthesized() &&
-                !right.is_parenthesized())
-                   ? left.ArrowParamListBit() & right.ArrowParamListBit()
-                   : 0;
-    return PreParserExpression(kTypeBinaryOperation | code);
+    bool valid_arrow_param_list =
+        op == Token::COMMA && !left.is_parenthesized() &&
+        !right.is_parenthesized() && left.IsValidArrowParams() &&
+        right.IsValidArrowParams();
+    return PreParserExpression(
+        TypeField::encode(kBinaryOperationExpression) |
+        IsValidArrowParamListField::encode(valid_arrow_param_list));
   }
 
   static PreParserExpression EmptyArrowParamList() {
@@ -701,88 +729,120 @@
   }
 
   static PreParserExpression StringLiteral() {
-    return PreParserExpression(kUnknownStringLiteral);
+    return PreParserExpression(TypeField::encode(kStringLiteralExpression) |
+                               IsUseStrictField::encode(false));
   }
 
   static PreParserExpression UseStrictStringLiteral() {
-    return PreParserExpression(kUseStrictString);
+    return PreParserExpression(TypeField::encode(kStringLiteralExpression) |
+                               IsUseStrictField::encode(true));
   }
 
   static PreParserExpression This() {
-    return PreParserExpression(kThisExpression);
+    return PreParserExpression(TypeField::encode(kExpression) |
+                               ExpressionTypeField::encode(kThisExpression));
   }
 
   static PreParserExpression Super() {
-    return PreParserExpression(kSuperExpression);
+    return PreParserExpression(TypeField::encode(kExpression) |
+                               ExpressionTypeField::encode(kSuperExpression));
   }
 
   static PreParserExpression ThisProperty() {
-    return PreParserExpression(kThisPropertyExpression);
+    return PreParserExpression(
+        TypeField::encode(kExpression) |
+        ExpressionTypeField::encode(kThisPropertyExpression));
   }
 
   static PreParserExpression Property() {
-    return PreParserExpression(kPropertyExpression);
+    return PreParserExpression(
+        TypeField::encode(kExpression) |
+        ExpressionTypeField::encode(kPropertyExpression));
   }
 
   static PreParserExpression Call() {
-    return PreParserExpression(kCallExpression);
+    return PreParserExpression(TypeField::encode(kExpression) |
+                               ExpressionTypeField::encode(kCallExpression));
   }
 
-  bool IsIdentifier() const { return (code_ & kTypeMask) == kTypeIdentifier; }
+  static PreParserExpression NoTemplateTag() {
+    return PreParserExpression(TypeField::encode(kExpression) |
+                               ExpressionTypeField::encode(
+                                  kNoTemplateTagExpression));
+  }
+
+  bool IsIdentifier() const {
+    return TypeField::decode(code_) == kIdentifierExpression;
+  }
 
   PreParserIdentifier AsIdentifier() const {
     DCHECK(IsIdentifier());
-    return PreParserIdentifier(
-        static_cast<PreParserIdentifier::Type>(code_ >> kIdentifierShift));
+    return PreParserIdentifier(IdentifierTypeField::decode(code_));
   }
 
   bool IsStringLiteral() const {
-    return (code_ & kTypeMask) == kTypeStringLiteral;
+    return TypeField::decode(code_) == kStringLiteralExpression;
   }
 
   bool IsUseStrictLiteral() const {
-    return (code_ & kUseStrictString) == kUseStrictString;
+    return TypeField::decode(code_) == kStringLiteralExpression &&
+           IsUseStrictField::decode(code_);
   }
 
-  bool IsThis() const { return (code_ & kThisExpression) == kThisExpression; }
+  bool IsThis() const {
+    return TypeField::decode(code_) == kExpression &&
+           ExpressionTypeField::decode(code_) == kThisExpression;
+  }
 
   bool IsThisProperty() const {
-    return (code_ & kThisPropertyExpression) == kThisPropertyExpression;
+    return TypeField::decode(code_) == kExpression &&
+           ExpressionTypeField::decode(code_) == kThisPropertyExpression;
   }
 
   bool IsProperty() const {
-    return (code_ & kPropertyExpression) == kPropertyExpression ||
-           (code_ & kThisPropertyExpression) == kThisPropertyExpression;
+    return TypeField::decode(code_) == kExpression &&
+           (ExpressionTypeField::decode(code_) == kPropertyExpression ||
+            ExpressionTypeField::decode(code_) == kThisPropertyExpression);
   }
 
-  bool IsCall() const { return (code_ & kCallExpression) == kCallExpression; }
+  bool IsCall() const {
+    return TypeField::decode(code_) == kExpression &&
+           ExpressionTypeField::decode(code_) == kCallExpression;
+  }
 
   bool IsValidReferenceExpression() const {
     return IsIdentifier() || IsProperty();
   }
 
   bool IsValidArrowParamList() const {
-    return (ArrowParamListBit() & kBinaryOperationArrowParamList) != 0 &&
-           (code_ & kMultiParenthesizedExpression) == 0;
+    return IsValidArrowParams() &&
+           ParenthesizationField::decode(code_) !=
+               kMultiParenthesizedExpression;
   }
 
   // At the moment PreParser doesn't track these expression types.
   bool IsFunctionLiteral() const { return false; }
   bool IsCallNew() const { return false; }
 
+  bool IsNoTemplateTag() const {
+    return TypeField::decode(code_) == kExpression &&
+           ExpressionTypeField::decode(code_) == kNoTemplateTagExpression;
+  }
+
   PreParserExpression AsFunctionLiteral() { return *this; }
 
   bool IsBinaryOperation() const {
-    return (code_ & kTypeMask) == kTypeBinaryOperation;
+    return TypeField::decode(code_) == kBinaryOperationExpression;
   }
 
   bool is_parenthesized() const {
-    return (code_ & kParenthesizedExpression) != 0;
+    return ParenthesizationField::decode(code_) != kNotParenthesized;
   }
 
   void increase_parenthesization_level() {
-    code_ |= is_parenthesized() ? kMultiParenthesizedExpression
-                                : kParenthesizedExpression;
+    code_ = ParenthesizationField::update(
+        code_, is_parenthesized() ? kMultiParenthesizedExpression
+                                  : kParanthesizedExpression);
   }
 
   // Dummy implementation for making expression->somefunc() work in both Parser
@@ -795,69 +855,54 @@
 
   int position() const { return RelocInfo::kNoPosition; }
   void set_function_token_position(int position) {}
-  void set_ast_properties(int* ast_properties) {}
-  void set_dont_optimize_reason(BailoutReason dont_optimize_reason) {}
-
-  bool operator==(const PreParserExpression& other) const {
-    return code_ == other.code_;
-  }
-  bool operator!=(const PreParserExpression& other) const {
-    return code_ != other.code_;
-  }
 
  private:
-  // Least significant 2 bits are used as expression type. The third least
-  // significant bit tracks whether an expression is parenthesized. If the
-  // expression is an identifier or a string literal, the other bits
-  // describe the type/ (see PreParserIdentifier::Type and string literal
-  // constants below). For binary operations, the other bits are flags
-  // which further describe the contents of the expression.
-  enum {
-    kUnknownExpression = 0,
-    kTypeMask = 1 | 2,
-    kParenthesizedExpression = (1 << 2),
-    kMultiParenthesizedExpression = (1 << 3),
-
-    // Identifiers
-    kTypeIdentifier = 1,  // Used to detect labels.
-    kIdentifierShift = 5,
-    kTypeStringLiteral = 2,  // Used to detect directive prologue.
-    kUnknownStringLiteral = kTypeStringLiteral,
-    kUseStrictString = kTypeStringLiteral | 32,
-    kStringLiteralMask = kUseStrictString,
-
-    // Binary operations. Those are needed to detect certain keywords and
-    // duplicated identifier in parameter lists for arrow functions, because
-    // they are initially parsed as comma-separated expressions.
-    kTypeBinaryOperation = 3,
-    kBinaryOperationArrowParamList = (1 << 4),
-
-    // Below here applies if neither identifier nor string literal. Reserve the
-    // 2 least significant bits for flags.
-    kThisExpression = (1 << 4),
-    kThisPropertyExpression = (2 << 4),
-    kPropertyExpression = (3 << 4),
-    kCallExpression = (4 << 4),
-    kSuperExpression = (5 << 4)
+  enum Type {
+    kExpression,
+    kIdentifierExpression,
+    kStringLiteralExpression,
+    kBinaryOperationExpression
   };
 
-  explicit PreParserExpression(int expression_code) : code_(expression_code) {}
+  enum Parenthesization {
+    kNotParenthesized,
+    kParanthesizedExpression,
+    kMultiParenthesizedExpression
+  };
 
-  V8_INLINE int ArrowParamListBit() const {
-    if (IsBinaryOperation()) return code_ & kBinaryOperationArrowParamList;
-    if (IsIdentifier()) {
-      const PreParserIdentifier ident = AsIdentifier();
-      // A valid identifier can be an arrow function parameter list
-      // except for eval, arguments, yield, and reserved keywords.
-      if (ident.IsEval() || ident.IsArguments() || ident.IsYield() ||
-          ident.IsFutureStrictReserved())
-        return 0;
-      return kBinaryOperationArrowParamList;
-    }
-    return 0;
+  enum ExpressionType {
+    kThisExpression,
+    kThisPropertyExpression,
+    kPropertyExpression,
+    kCallExpression,
+    kSuperExpression,
+    kNoTemplateTagExpression
+  };
+
+  explicit PreParserExpression(uint32_t expression_code)
+      : code_(expression_code) {}
+
+  V8_INLINE bool IsValidArrowParams() const {
+    return IsBinaryOperation()
+               ? IsValidArrowParamListField::decode(code_)
+               : (IsIdentifier() && AsIdentifier().IsValidArrowParam());
   }
 
-  int code_;
+  // The first four bits are for the Type and Parenthesization.
+  typedef BitField<Type, 0, 2> TypeField;
+  typedef BitField<Parenthesization, TypeField::kNext, 2> ParenthesizationField;
+
+  // The rest of the bits are interpreted depending on the value
+  // of the Type field, so they can share the storage.
+  typedef BitField<ExpressionType, ParenthesizationField::kNext, 3>
+      ExpressionTypeField;
+  typedef BitField<bool, ParenthesizationField::kNext, 1> IsUseStrictField;
+  typedef BitField<bool, ParenthesizationField::kNext, 1>
+      IsValidArrowParamListField;
+  typedef BitField<PreParserIdentifier::Type, ParenthesizationField::kNext, 10>
+      IdentifierTypeField;
+
+  uint32_t code_;
 };
 
 
@@ -958,6 +1003,10 @@
 
   bool IsDeclared(const PreParserIdentifier& identifier) const { return false; }
   void DeclareParameter(const PreParserIdentifier& identifier, VariableMode) {}
+  void RecordArgumentsUsage() {}
+  void RecordSuperPropertyUsage() {}
+  void RecordSuperConstructorCallUsage() {}
+  void RecordThisUsage() {}
 
   // Allow scope->Foo() to work.
   PreParserScope* operator->() { return this; }
@@ -970,7 +1019,7 @@
 
 class PreParserFactory {
  public:
-  PreParserFactory(void*, void*, void*) {}
+  explicit PreParserFactory(void* unused_value_factory) {}
   PreParserExpression NewStringLiteral(PreParserIdentifier identifier,
                                        int pos) {
     return PreParserExpression::Default();
@@ -1083,18 +1132,10 @@
       int position) {
     return PreParserExpression::Default();
   }
-  PreParserExpression NewClassLiteral(PreParserIdentifier name,
-                                      PreParserExpression extends,
-                                      PreParserExpression constructor,
-                                      PreParserExpressionList properties,
-                                      int position) {
-    return PreParserExpression::Default();
-  }
 
   // Return the object itself as AstVisitor and implement the needed
   // dummy method right in this class.
   PreParserFactory* visitor() { return this; }
-  BailoutReason dont_optimize_reason() { return kNoReason; }
   int* ast_properties() {
     static int dummy = 42;
     return &dummy;
@@ -1114,6 +1155,7 @@
     // Used by FunctionState and BlockState.
     typedef PreParserScope Scope;
     typedef PreParserScope ScopePtr;
+    inline static Scope* ptr_to_scope(ScopePtr& scope) { return &scope; }
 
     // PreParser doesn't need to store generator variables.
     typedef void GeneratorVariable;
@@ -1139,17 +1181,8 @@
     typedef PreParserFactory Factory;
   };
 
-  class Checkpoint;
-
   explicit PreParserTraits(PreParser* pre_parser) : pre_parser_(pre_parser) {}
 
-  // Custom operations executed when FunctionStates are created and
-  // destructed. (The PreParser doesn't need to do anything.)
-  template <typename FunctionState>
-  static void SetUpFunctionState(FunctionState* function_state) {}
-  template <typename FunctionState>
-  static void TearDownFunctionState(FunctionState* function_state) {}
-
   // Helper functions for recursive descent.
   static bool IsEvalOrArguments(PreParserIdentifier identifier) {
     return identifier.IsEvalOrArguments();
@@ -1177,7 +1210,7 @@
   }
 
   static bool IsFutureStrictReserved(PreParserIdentifier identifier) {
-    return identifier.IsYield() || identifier.IsFutureStrictReserved();
+    return identifier.IsFutureStrictReserved();
   }
 
   static bool IsBoilerplateProperty(PreParserExpression property) {
@@ -1189,6 +1222,10 @@
     return false;
   }
 
+  static PreParserExpression GetPropertyValue(PreParserExpression property) {
+    return PreParserExpression::Default();
+  }
+
   // Functions for encapsulating the differences between parsing and preparsing;
   // operations interleaved with the recursive descent.
   static void PushLiteralName(FuncNameInferrer* fni, PreParserIdentifier id) {
@@ -1314,12 +1351,9 @@
     return PreParserExpression::Super();
   }
 
-  static PreParserExpression ClassLiteral(PreParserIdentifier name,
-                                          PreParserExpression extends,
-                                          PreParserExpression constructor,
-                                          PreParserExpressionList properties,
-                                          int position,
-                                          PreParserFactory* factory) {
+  static PreParserExpression DefaultConstructor(bool call_super,
+                                                PreParserScope* scope, int pos,
+                                                int end_pos) {
     return PreParserExpression::Default();
   }
 
@@ -1377,6 +1411,29 @@
     return 0;
   }
 
+  struct TemplateLiteralState {};
+
+  TemplateLiteralState OpenTemplateLiteral(int pos) {
+    return TemplateLiteralState();
+  }
+  void AddTemplateSpan(TemplateLiteralState*, bool) {}
+  void AddTemplateExpression(TemplateLiteralState*, PreParserExpression) {}
+  PreParserExpression CloseTemplateLiteral(TemplateLiteralState*, int,
+                                           PreParserExpression tag) {
+    if (IsTaggedTemplate(tag)) {
+      // Emulate generation of array literals for tag callsite
+      // 1st is array of cooked strings, second is array of raw strings
+      MaterializeTemplateCallsiteLiterals();
+    }
+    return EmptyExpression();
+  }
+  inline void MaterializeTemplateCallsiteLiterals();
+  PreParserExpression NoTemplateTag() {
+    return PreParserExpression::NoTemplateTag();
+  }
+  static bool IsTaggedTemplate(const PreParserExpression tag) {
+    return !tag.IsNoTemplateTag();
+  }
   static AstValueFactory* ast_value_factory() { return NULL; }
 
   void CheckConflictingVarDeclarations(PreParserScope scope, bool* ok) {}
@@ -1389,6 +1446,11 @@
       int function_token_position, FunctionLiteral::FunctionType type,
       FunctionLiteral::ArityRestriction arity_restriction, bool* ok);
 
+  PreParserExpression ParseClassLiteral(PreParserIdentifier name,
+                                        Scanner::Location class_name_location,
+                                        bool name_is_strict_reserved, int pos,
+                                        bool* ok);
+
  private:
   PreParser* pre_parser_;
 };
@@ -1418,16 +1480,17 @@
   };
 
   PreParser(Scanner* scanner, ParserRecorder* log, uintptr_t stack_limit)
-      : ParserBase<PreParserTraits>(scanner, stack_limit, NULL, log, NULL, NULL,
+      : ParserBase<PreParserTraits>(scanner, stack_limit, NULL, log, NULL,
                                     this) {}
 
   // Pre-parse the program from the character stream; returns true on
   // success (even if parsing failed, the pre-parse data successfully
   // captured the syntax error), and false if a stack-overflow happened
   // during parsing.
-  PreParseResult PreParseProgram() {
-    PreParserScope scope(scope_, GLOBAL_SCOPE);
-    FunctionState top_scope(&function_state_, &scope_, &scope);
+  PreParseResult PreParseProgram(int* materialized_literals = 0) {
+    PreParserScope scope(scope_, SCRIPT_SCOPE);
+    PreParserFactory factory(NULL);
+    FunctionState top_scope(&function_state_, &scope_, &scope, &factory);
     bool ok = true;
     int start_position = scanner()->peek_location().beg_pos;
     ParseSourceElements(Token::EOS, &ok);
@@ -1435,7 +1498,11 @@
     if (!ok) {
       ReportUnexpectedToken(scanner()->current_token());
     } else if (scope_->strict_mode() == STRICT) {
-      CheckOctalLiteral(start_position, scanner()->location().end_pos, &ok);
+      CheckStrictOctalLiteral(start_position, scanner()->location().end_pos,
+                              &ok);
+    }
+    if (materialized_literals) {
+      *materialized_literals = function_state_->materialized_literal_count();
     }
     return kPreParseSuccess;
   }
@@ -1525,10 +1592,21 @@
       FunctionLiteral::ArityRestriction arity_restriction, bool* ok);
   void ParseLazyFunctionLiteralBody(bool* ok);
 
+  PreParserExpression ParseClassLiteral(PreParserIdentifier name,
+                                        Scanner::Location class_name_location,
+                                        bool name_is_strict_reserved, int pos,
+                                        bool* ok);
+
   bool CheckInOrOf(bool accept_OF);
 };
 
 
+void PreParserTraits::MaterializeTemplateCallsiteLiterals() {
+  pre_parser_->function_state_->NextMaterializedLiteralIndex();
+  pre_parser_->function_state_->NextMaterializedLiteralIndex();
+}
+
+
 PreParserStatementList PreParser::ParseEagerFunctionBody(
     PreParserIdentifier function_name, int pos, Variable* fvar,
     Token::Value fvar_init_op, bool is_generator, bool* ok) {
@@ -1554,8 +1632,8 @@
 ParserBase<Traits>::FunctionState::FunctionState(
     FunctionState** function_state_stack,
     typename Traits::Type::Scope** scope_stack,
-    typename Traits::Type::Scope* scope, typename Traits::Type::Zone* zone,
-    AstValueFactory* ast_value_factory, AstNode::IdGen* ast_node_id_gen)
+    typename Traits::Type::Scope* scope,
+    typename Traits::Type::Factory* factory)
     : next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize),
       next_handler_index_(0),
       expected_property_count_(0),
@@ -1565,34 +1643,9 @@
       outer_function_state_(*function_state_stack),
       scope_stack_(scope_stack),
       outer_scope_(*scope_stack),
-      ast_node_id_gen_(ast_node_id_gen),
-      factory_(zone, ast_value_factory, ast_node_id_gen) {
+      factory_(factory) {
   *scope_stack_ = scope;
   *function_state_stack = this;
-  Traits::SetUpFunctionState(this);
-}
-
-
-template <class Traits>
-ParserBase<Traits>::FunctionState::FunctionState(
-    FunctionState** function_state_stack,
-    typename Traits::Type::Scope** scope_stack,
-    typename Traits::Type::Scope** scope, typename Traits::Type::Zone* zone,
-    AstValueFactory* ast_value_factory, AstNode::IdGen* ast_node_id_gen)
-    : next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize),
-      next_handler_index_(0),
-      expected_property_count_(0),
-      is_generator_(false),
-      generator_object_variable_(NULL),
-      function_state_stack_(function_state_stack),
-      outer_function_state_(*function_state_stack),
-      scope_stack_(scope_stack),
-      outer_scope_(*scope_stack),
-      ast_node_id_gen_(ast_node_id_gen),
-      factory_(zone, ast_value_factory, ast_node_id_gen) {
-  *scope_stack_ = *scope;
-  *function_state_stack = this;
-  Traits::SetUpFunctionState(this);
 }
 
 
@@ -1600,7 +1653,6 @@
 ParserBase<Traits>::FunctionState::~FunctionState() {
   *scope_stack_ = outer_scope_;
   *function_state_stack_ = outer_function_state_;
-  Traits::TearDownFunctionState(this);
 }
 
 
@@ -1621,10 +1673,15 @@
     case Token::FUTURE_RESERVED_WORD:
       return ReportMessageAt(source_location, "unexpected_reserved");
     case Token::LET:
+    case Token::STATIC:
     case Token::YIELD:
     case Token::FUTURE_STRICT_RESERVED_WORD:
       return ReportMessageAt(source_location, strict_mode() == SLOPPY
           ? "unexpected_token_identifier" : "unexpected_strict_reserved");
+    case Token::TEMPLATE_SPAN:
+    case Token::TEMPLATE_TAIL:
+      return Traits::ReportMessageAt(source_location,
+          "unexpected_template_string");
     default:
       const char* name = Token::String(token);
       DCHECK(name != NULL);
@@ -1645,11 +1702,13 @@
       ReportMessage("strict_eval_arguments");
       *ok = false;
     }
+    if (name->IsArguments(this->ast_value_factory()))
+      scope_->RecordArgumentsUsage();
     return name;
   } else if (strict_mode() == SLOPPY &&
              (next == Token::FUTURE_STRICT_RESERVED_WORD ||
-             (next == Token::LET) ||
-             (next == Token::YIELD && !is_generator()))) {
+              next == Token::LET || next == Token::STATIC ||
+              (next == Token::YIELD && !is_generator()))) {
     return this->GetSymbol(scanner());
   } else {
     this->ReportUnexpectedToken(next);
@@ -1666,8 +1725,8 @@
   Token::Value next = Next();
   if (next == Token::IDENTIFIER) {
     *is_strict_reserved = false;
-  } else if (next == Token::FUTURE_STRICT_RESERVED_WORD ||
-             next == Token::LET ||
+  } else if (next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
+             next == Token::STATIC ||
              (next == Token::YIELD && !this->is_generator())) {
     *is_strict_reserved = true;
   } else {
@@ -1675,7 +1734,11 @@
     *ok = false;
     return Traits::EmptyIdentifier();
   }
-  return this->GetSymbol(scanner());
+
+  IdentifierT name = this->GetSymbol(scanner());
+  if (name->IsArguments(this->ast_value_factory()))
+    scope_->RecordArgumentsUsage();
+  return name;
 }
 
 
@@ -1684,13 +1747,17 @@
 ParserBase<Traits>::ParseIdentifierName(bool* ok) {
   Token::Value next = Next();
   if (next != Token::IDENTIFIER && next != Token::FUTURE_RESERVED_WORD &&
-      next != Token::LET && next != Token::YIELD &&
+      next != Token::LET && next != Token::STATIC && next != Token::YIELD &&
       next != Token::FUTURE_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
     this->ReportUnexpectedToken(next);
     *ok = false;
     return Traits::EmptyIdentifier();
   }
-  return this->GetSymbol(scanner());
+
+  IdentifierT name = this->GetSymbol(scanner());
+  if (name->IsArguments(this->ast_value_factory()))
+    scope_->RecordArgumentsUsage();
+  return name;
 }
 
 
@@ -1722,7 +1789,7 @@
   IdentifierT js_pattern = this->GetNextSymbol(scanner());
   if (!scanner()->ScanRegExpFlags()) {
     Next();
-    ReportMessage("invalid_regexp_flags");
+    ReportMessage("malformed_regexp_flags");
     *ok = false;
     return Traits::EmptyExpression();
   }
@@ -1761,6 +1828,7 @@
   //   RegExpLiteral
   //   ClassLiteral
   //   '(' Expression ')'
+  //   TemplateLiteral
 
   int pos = peek_position();
   ExpressionT result = this->EmptyExpression();
@@ -1768,6 +1836,7 @@
   switch (token) {
     case Token::THIS: {
       Consume(Token::THIS);
+      scope_->RecordThisUsage();
       result = this->ThisExpression(scope_, factory());
       break;
     }
@@ -1782,6 +1851,7 @@
 
     case Token::IDENTIFIER:
     case Token::LET:
+    case Token::STATIC:
     case Token::YIELD:
     case Token::FUTURE_STRICT_RESERVED_WORD: {
       // Using eval or arguments in this context is OK even in strict mode.
@@ -1814,7 +1884,7 @@
 
     case Token::LPAREN:
       Consume(Token::LPAREN);
-      if (allow_arrow_functions() && peek() == Token::RPAREN) {
+      if (allow_harmony_arrow_functions() && peek() == Token::RPAREN) {
         // Arrow functions are the only expression type constructions
         // for which an empty parameter list "()" is valid input.
         Consume(Token::RPAREN);
@@ -1832,6 +1902,11 @@
 
     case Token::CLASS: {
       Consume(Token::CLASS);
+      if (!allow_harmony_sloppy() && strict_mode() == SLOPPY) {
+        ReportMessage("sloppy_lexical", NULL);
+        *ok = false;
+        break;
+      }
       int class_token_position = position();
       IdentifierT name = this->EmptyIdentifier();
       bool is_strict_reserved_name = false;
@@ -1847,8 +1922,14 @@
       break;
     }
 
+    case Token::TEMPLATE_SPAN:
+    case Token::TEMPLATE_TAIL:
+      result =
+          this->ParseTemplateLiteral(Traits::NoTemplateTag(), pos, CHECK_OK);
+      break;
+
     case Token::MOD:
-      if (allow_natives_syntax() || extension_ != NULL) {
+      if (allow_natives() || extension_ != NULL) {
         result = this->ParseV8Intrinsic(CHECK_OK);
         break;
       }
@@ -1940,7 +2021,9 @@
 template <class Traits>
 typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
     Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker,
-                                     bool in_class, bool is_static, bool* ok) {
+                                     bool in_class, bool is_static,
+                                     bool* has_seen_constructor, bool* ok) {
+  DCHECK(!in_class || is_static || has_seen_constructor != NULL);
   ExpressionT value = this->EmptyExpression();
   bool is_get = false;
   bool is_set = false;
@@ -1957,8 +2040,10 @@
 
   if (!in_class && !is_generator && peek() == Token::COLON) {
     // PropertyDefinition : PropertyName ':' AssignmentExpression
-    checker->CheckProperty(name_token, kValueProperty,
-                           CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+    if (checker != NULL) {
+      checker->CheckProperty(name_token, kValueProperty,
+                             CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+    }
     Consume(Token::COLON);
     value = this->ParseAssignmentExpression(
         true, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
@@ -1972,17 +2057,32 @@
       *ok = false;
       return this->EmptyObjectLiteralProperty();
     }
-    if (is_generator && in_class && !is_static && this->IsConstructor(name)) {
-      ReportMessageAt(scanner()->location(), "constructor_special_method");
-      *ok = false;
-      return this->EmptyObjectLiteralProperty();
-    }
 
-    checker->CheckProperty(name_token, kValueProperty,
-                           CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
     FunctionKind kind = is_generator ? FunctionKind::kConciseGeneratorMethod
                                      : FunctionKind::kConciseMethod;
 
+    if (in_class && !is_static && this->IsConstructor(name)) {
+      if (is_generator) {
+        ReportMessageAt(scanner()->location(), "constructor_special_method");
+        *ok = false;
+        return this->EmptyObjectLiteralProperty();
+      }
+
+      if (*has_seen_constructor) {
+        ReportMessageAt(scanner()->location(), "duplicate_constructor");
+        *ok = false;
+        return this->EmptyObjectLiteralProperty();
+      }
+
+      *has_seen_constructor = true;
+      kind = FunctionKind::kNormalFunction;
+    }
+
+    if (checker != NULL) {
+      checker->CheckProperty(name_token, kValueProperty,
+                             CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+    }
+
     value = this->ParseFunctionLiteral(
         name, scanner()->location(),
         false,  // reserved words are allowed here
@@ -1992,7 +2092,7 @@
 
   } else if (in_class && name_is_static && !is_static) {
     // static MethodDefinition
-    return ParsePropertyDefinition(checker, true, true, ok);
+    return ParsePropertyDefinition(checker, true, true, NULL, ok);
 
   } else if (is_get || is_set) {
     // Accessor
@@ -2007,16 +2107,15 @@
       *ok = false;
       return this->EmptyObjectLiteralProperty();
     } else if (in_class && !is_static && this->IsConstructor(name)) {
-      // ES6, spec draft rev 27, treats static get constructor as an error too.
-      // https://bugs.ecmascript.org/show_bug.cgi?id=3223
-      // TODO(arv): Update when bug is resolved.
       ReportMessageAt(scanner()->location(), "constructor_special_method");
       *ok = false;
       return this->EmptyObjectLiteralProperty();
     }
-    checker->CheckProperty(name_token,
-                           is_get ? kGetterProperty : kSetterProperty,
-                           CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+    if (checker != NULL) {
+      checker->CheckProperty(name_token,
+                             is_get ? kGetterProperty : kSetterProperty,
+                             CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+    }
 
     typename Traits::Type::FunctionLiteral value = this->ParseFunctionLiteral(
         name, scanner()->location(),
@@ -2027,6 +2126,12 @@
         CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
     return factory()->NewObjectLiteralProperty(is_get, value, next_pos,
                                                is_static);
+
+  } else if (!in_class && allow_harmony_object_literals_ &&
+             Token::IsIdentifier(name_token, strict_mode(),
+                                 this->is_generator())) {
+    value = this->ExpressionFromIdentifier(name, next_pos, scope_, factory());
+
   } else {
     Token::Value next = Next();
     ReportUnexpectedToken(next);
@@ -2064,8 +2169,8 @@
 
     const bool in_class = false;
     const bool is_static = false;
-    ObjectLiteralPropertyT property =
-        this->ParsePropertyDefinition(&checker, in_class, is_static, CHECK_OK);
+    ObjectLiteralPropertyT property = this->ParsePropertyDefinition(
+        &checker, in_class, is_static, NULL, CHECK_OK);
 
     // Mark top-level object literals that contain function literals and
     // pretenure the literal so it can be added as a constant function
@@ -2148,11 +2253,11 @@
   }
 
   if (fni_ != NULL) fni_->Enter();
-  typename Traits::Checkpoint checkpoint(this);
+  ParserBase<Traits>::Checkpoint checkpoint(this);
   ExpressionT expression =
       this->ParseConditionalExpression(accept_IN, CHECK_OK);
 
-  if (allow_arrow_functions() && peek() == Token::ARROW) {
+  if (allow_harmony_arrow_functions() && peek() == Token::ARROW) {
     checkpoint.Restore();
     expression = this->ParseArrowFunctionLiteral(lhs_location.beg_pos,
                                                  expression, CHECK_OK);
@@ -2446,6 +2551,23 @@
         break;
       }
 
+      case Token::TEMPLATE_SPAN:
+      case Token::TEMPLATE_TAIL: {
+        int pos;
+        if (scanner()->current_token() == Token::IDENTIFIER) {
+          pos = position();
+        } else {
+          pos = peek_position();
+          if (result->IsFunctionLiteral() && mode() == PARSE_EAGERLY) {
+            // If the tag function looks like an IIFE, set_parenthesized() to
+            // force eager compilation.
+            result->AsFunctionLiteral()->set_parenthesized();
+          }
+        }
+        result = ParseTemplateLiteral(result, pos, CHECK_OK);
+        break;
+      }
+
       case Token::PERIOD: {
         Consume(Token::PERIOD);
         int pos = position();
@@ -2548,8 +2670,11 @@
     int beg_pos = position();
     Consume(Token::SUPER);
     Token::Value next = peek();
-    if (next == Token::PERIOD || next == Token::LBRACK ||
-        next == Token::LPAREN) {
+    if (next == Token::PERIOD || next == Token::LBRACK) {
+      scope_->RecordSuperPropertyUsage();
+      result = this->SuperReference(scope_, factory());
+    } else if (next == Token::LPAREN) {
+      scope_->RecordSuperConstructorCallUsage();
       result = this->SuperReference(scope_, factory());
     } else {
       ReportMessageAt(Scanner::Location(beg_pos, position()),
@@ -2609,20 +2734,18 @@
 typename ParserBase<Traits>::ExpressionT ParserBase<
     Traits>::ParseArrowFunctionLiteral(int start_pos, ExpressionT params_ast,
                                        bool* ok) {
-  // TODO(aperez): Change this to use ARROW_SCOPE
-  typename Traits::Type::ScopePtr scope =
-      this->NewScope(scope_, FUNCTION_SCOPE);
+  typename Traits::Type::ScopePtr scope = this->NewScope(scope_, ARROW_SCOPE);
   typename Traits::Type::StatementList body;
-  typename Traits::Type::AstProperties ast_properties;
-  BailoutReason dont_optimize_reason = kNoReason;
   int num_parameters = -1;
   int materialized_literal_count = -1;
   int expected_property_count = -1;
   int handler_count = 0;
 
   {
-    FunctionState function_state(&function_state_, &scope_, &scope, zone(),
-                                 this->ast_value_factory(), ast_node_id_gen_);
+    typename Traits::Type::Factory function_factory(this->ast_value_factory());
+    FunctionState function_state(&function_state_, &scope_,
+                                 Traits::Type::ptr_to_scope(scope),
+                                 &function_factory);
     Scanner::Location dupe_error_loc = Scanner::Location::invalid();
     num_parameters = Traits::DeclareArrowParametersFromExpression(
         params_ast, scope_, &dupe_error_loc, ok);
@@ -2689,14 +2812,12 @@
 
     // Validate strict mode.
     if (strict_mode() == STRICT) {
-      CheckOctalLiteral(start_pos, scanner()->location().end_pos, CHECK_OK);
+      CheckStrictOctalLiteral(start_pos, scanner()->location().end_pos,
+                              CHECK_OK);
     }
 
     if (allow_harmony_scoping() && strict_mode() == STRICT)
       this->CheckConflictingVarDeclarations(scope, CHECK_OK);
-
-    ast_properties = *factory()->visitor()->ast_properties();
-    dont_optimize_reason = factory()->visitor()->dont_optimize_reason();
   }
 
   FunctionLiteralT function_literal = factory()->NewFunctionLiteral(
@@ -2708,8 +2829,6 @@
       start_pos);
 
   function_literal->set_function_token_position(start_pos);
-  function_literal->set_ast_properties(&ast_properties);
-  function_literal->set_dont_optimize_reason(dont_optimize_reason);
 
   if (fni_ != NULL) this->InferFunctionName(fni_, function_literal);
 
@@ -2717,71 +2836,102 @@
 }
 
 
-template <class Traits>
-typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseClassLiteral(
-    IdentifierT name, Scanner::Location class_name_location,
-    bool name_is_strict_reserved, int pos, bool* ok) {
-  // All parts of a ClassDeclaration or a ClassExpression are strict code.
-  if (name_is_strict_reserved) {
-    ReportMessageAt(class_name_location, "unexpected_strict_reserved");
-    *ok = false;
-    return this->EmptyExpression();
-  }
-  if (this->IsEvalOrArguments(name)) {
-    ReportMessageAt(class_name_location, "strict_eval_arguments");
-    *ok = false;
-    return this->EmptyExpression();
+template <typename Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::ParseTemplateLiteral(ExpressionT tag, int start, bool* ok) {
+  // A TemplateLiteral is made up of 0 or more TEMPLATE_SPAN tokens (literal
+  // text followed by a substitution expression), finalized by a single
+  // TEMPLATE_TAIL.
+  //
+  // In terms of draft language, TEMPLATE_SPAN may be either the TemplateHead or
+  // TemplateMiddle productions, while TEMPLATE_TAIL is either TemplateTail, or
+  // NoSubstitutionTemplate.
+  //
+  // When parsing a TemplateLiteral, we must have scanned either an initial
+  // TEMPLATE_SPAN, or a TEMPLATE_TAIL.
+  CHECK(peek() == Token::TEMPLATE_SPAN || peek() == Token::TEMPLATE_TAIL);
+
+  // If we reach a TEMPLATE_TAIL first, we are parsing a NoSubstitutionTemplate.
+  // In this case we may simply consume the token and build a template with a
+  // single TEMPLATE_SPAN and no expressions.
+  if (peek() == Token::TEMPLATE_TAIL) {
+    Consume(Token::TEMPLATE_TAIL);
+    int pos = position();
+    CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
+    typename Traits::TemplateLiteralState ts = Traits::OpenTemplateLiteral(pos);
+    Traits::AddTemplateSpan(&ts, true);
+    return Traits::CloseTemplateLiteral(&ts, start, tag);
   }
 
-  // TODO(arv): Implement scopes and name binding in class body only.
-  // TODO(arv): Maybe add CLASS_SCOPE?
-  typename Traits::Type::ScopePtr extends_scope =
-      this->NewScope(scope_, BLOCK_SCOPE);
-  FunctionState extends_function_state(
-      &function_state_, &scope_, &extends_scope, zone(),
-      this->ast_value_factory(), ast_node_id_gen_);
-  scope_->SetStrictMode(STRICT);
-  scope_->SetScopeName(name);
+  Consume(Token::TEMPLATE_SPAN);
+  int pos = position();
+  typename Traits::TemplateLiteralState ts = Traits::OpenTemplateLiteral(pos);
+  Traits::AddTemplateSpan(&ts, false);
+  Token::Value next;
 
-  ExpressionT extends = this->EmptyExpression();
-  if (Check(Token::EXTENDS)) {
-    extends = this->ParseLeftHandSideExpression(CHECK_OK);
-  }
+  // If we open with a TEMPLATE_SPAN, we must scan the subsequent expression,
+  // and repeat if the following token is a TEMPLATE_SPAN as well (in this
+  // case, representing a TemplateMiddle).
 
-  ObjectLiteralChecker checker(this, STRICT);
-  typename Traits::Type::PropertyList properties =
-      this->NewPropertyList(4, zone_);
-  FunctionLiteralT constructor = this->EmptyFunctionLiteral();
-
-  Expect(Token::LBRACE, CHECK_OK);
-  while (peek() != Token::RBRACE) {
-    if (Check(Token::SEMICOLON)) continue;
-    if (fni_ != NULL) fni_->Enter();
-
-    const bool in_class = true;
-    const bool is_static = false;
-    ObjectLiteralPropertyT property =
-        this->ParsePropertyDefinition(&checker, in_class, is_static, CHECK_OK);
-
-    properties->Add(property, zone());
-
-    if (fni_ != NULL) {
-      fni_->Infer();
-      fni_->Leave();
+  do {
+    next = peek();
+    if (next == Token::EOS) {
+      ReportMessageAt(Scanner::Location(start, peek_position()),
+                      "unterminated_template");
+      *ok = false;
+      return Traits::EmptyExpression();
+    } else if (next == Token::ILLEGAL) {
+      Traits::ReportMessageAt(
+          Scanner::Location(position() + 1, peek_position()),
+          "unexpected_token", "ILLEGAL", false);
+      *ok = false;
+      return Traits::EmptyExpression();
     }
-  }
-  Expect(Token::RBRACE, CHECK_OK);
 
-  return this->ClassLiteral(name, extends, constructor, properties, pos,
-                            factory());
+    int expr_pos = peek_position();
+    ExpressionT expression = this->ParseExpression(true, CHECK_OK);
+    Traits::AddTemplateExpression(&ts, expression);
+
+    if (peek() != Token::RBRACE) {
+      ReportMessageAt(Scanner::Location(expr_pos, peek_position()),
+                      "unterminated_template_expr");
+      *ok = false;
+      return Traits::EmptyExpression();
+    }
+
+    // If we didn't die parsing that expression, our next token should be a
+    // TEMPLATE_SPAN or TEMPLATE_TAIL.
+    next = scanner()->ScanTemplateContinuation();
+    Next();
+
+    if (next == Token::EOS) {
+      ReportMessageAt(Scanner::Location(start, position()),
+                      "unterminated_template");
+      *ok = false;
+      return Traits::EmptyExpression();
+    } else if (next == Token::ILLEGAL) {
+      Traits::ReportMessageAt(
+          Scanner::Location(position() + 1, peek_position()),
+          "unexpected_token", "ILLEGAL", false);
+      *ok = false;
+      return Traits::EmptyExpression();
+    }
+
+    Traits::AddTemplateSpan(&ts, next == Token::TEMPLATE_TAIL);
+  } while (next == Token::TEMPLATE_SPAN);
+
+  DCHECK_EQ(next, Token::TEMPLATE_TAIL);
+  CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
+  // Once we've reached a TEMPLATE_TAIL, we can close the TemplateLiteral.
+  return Traits::CloseTemplateLiteral(&ts, start, tag);
 }
 
 
 template <typename Traits>
-typename ParserBase<Traits>::ExpressionT
-ParserBase<Traits>::CheckAndRewriteReferenceExpression(
-    ExpressionT expression,
-    Scanner::Location location, const char* message, bool* ok) {
+typename ParserBase<Traits>::ExpressionT ParserBase<
+    Traits>::CheckAndRewriteReferenceExpression(ExpressionT expression,
+                                                Scanner::Location location,
+                                                const char* message, bool* ok) {
   if (strict_mode() == STRICT && this->IsIdentifier(expression) &&
       this->IsEvalOrArguments(this->AsIdentifier(expression))) {
     this->ReportMessageAt(location, "strict_eval_arguments", false);
diff --git a/src/prettyprinter.h b/src/prettyprinter.h
index d300d9a..bf01520 100644
--- a/src/prettyprinter.h
+++ b/src/prettyprinter.h
@@ -30,7 +30,7 @@
   static void PrintOut(Zone* zone, AstNode* node);
 
   // Individual nodes
-#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+#define DECLARE_VISIT(type) void Visit##type(type* node) OVERRIDE;
   AST_NODE_LIST(DECLARE_VISIT)
 #undef DECLARE_VISIT
 
diff --git a/src/profile-generator-inl.h b/src/profile-generator-inl.h
index 58c124f..c53d749 100644
--- a/src/profile-generator-inl.h
+++ b/src/profile-generator-inl.h
@@ -10,14 +10,12 @@
 namespace v8 {
 namespace internal {
 
-CodeEntry::CodeEntry(Logger::LogEventsAndTags tag,
-                     const char* name,
-                     const char* name_prefix,
-                     const char* resource_name,
-                     int line_number,
-                     int column_number)
-    : tag_(tag),
-      builtin_id_(Builtins::builtin_count),
+CodeEntry::CodeEntry(Logger::LogEventsAndTags tag, const char* name,
+                     const char* name_prefix, const char* resource_name,
+                     int line_number, int column_number,
+                     JITLineInfoTable* line_info, Address instruction_start)
+    : bit_field_(TagField::encode(tag) |
+                 BuiltinIdField::encode(Builtins::builtin_count)),
       name_prefix_(name_prefix),
       name_(name),
       resource_name_(resource_name),
@@ -26,7 +24,9 @@
       shared_id_(0),
       script_id_(v8::UnboundScript::kNoScriptId),
       no_frame_ranges_(NULL),
-      bailout_reason_(kEmptyBailoutReason) { }
+      bailout_reason_(kEmptyBailoutReason),
+      line_info_(line_info),
+      instruction_start_(instruction_start) {}
 
 
 bool CodeEntry::is_js_function_tag(Logger::LogEventsAndTags tag) {
@@ -44,8 +44,8 @@
       entry_(entry),
       self_ticks_(0),
       children_(CodeEntriesMatch),
-      id_(tree->next_node_id()) { }
-
+      id_(tree->next_node_id()),
+      line_ticks_(LineTickMatch) {}
 } }  // namespace v8::internal
 
 #endif  // V8_PROFILE_GENERATOR_INL_H_
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 6017f12..7ad4910 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -132,6 +132,31 @@
 }
 
 
+JITLineInfoTable::JITLineInfoTable() {}
+
+
+JITLineInfoTable::~JITLineInfoTable() {}
+
+
+void JITLineInfoTable::SetPosition(int pc_offset, int line) {
+  DCHECK(pc_offset >= 0);
+  DCHECK(line > 0);  // The 1-based number of the source line.
+  if (GetSourceLineNumber(pc_offset) != line) {
+    pc_offset_map_.insert(std::make_pair(pc_offset, line));
+  }
+}
+
+
+int JITLineInfoTable::GetSourceLineNumber(int pc_offset) const {
+  PcOffsetMap::const_iterator it = pc_offset_map_.lower_bound(pc_offset);
+  if (it == pc_offset_map_.end()) {
+    if (pc_offset_map_.empty()) return v8::CpuProfileNode::kNoLineNumberInfo;
+    return (--pc_offset_map_.end())->second;
+  }
+  return it->second;
+}
+
+
 const char* const CodeEntry::kEmptyNamePrefix = "";
 const char* const CodeEntry::kEmptyResourceName = "";
 const char* const CodeEntry::kEmptyBailoutReason = "";
@@ -139,11 +164,12 @@
 
 CodeEntry::~CodeEntry() {
   delete no_frame_ranges_;
+  delete line_info_;
 }
 
 
 uint32_t CodeEntry::GetCallUid() const {
-  uint32_t hash = ComputeIntegerHash(tag_, v8::internal::kZeroHashSeed);
+  uint32_t hash = ComputeIntegerHash(tag(), v8::internal::kZeroHashSeed);
   if (shared_id_ != 0) {
     hash ^= ComputeIntegerHash(static_cast<uint32_t>(shared_id_),
                                v8::internal::kZeroHashSeed);
@@ -164,20 +190,26 @@
 
 
 bool CodeEntry::IsSameAs(CodeEntry* entry) const {
-  return this == entry
-      || (tag_ == entry->tag_
-          && shared_id_ == entry->shared_id_
-          && (shared_id_ != 0
-              || (name_prefix_ == entry->name_prefix_
-                  && name_ == entry->name_
-                  && resource_name_ == entry->resource_name_
-                  && line_number_ == entry->line_number_)));
+  return this == entry ||
+         (tag() == entry->tag() && shared_id_ == entry->shared_id_ &&
+          (shared_id_ != 0 ||
+           (name_prefix_ == entry->name_prefix_ && name_ == entry->name_ &&
+            resource_name_ == entry->resource_name_ &&
+            line_number_ == entry->line_number_)));
 }
 
 
 void CodeEntry::SetBuiltinId(Builtins::Name id) {
-  tag_ = Logger::BUILTIN_TAG;
-  builtin_id_ = id;
+  bit_field_ = TagField::update(bit_field_, Logger::BUILTIN_TAG);
+  bit_field_ = BuiltinIdField::update(bit_field_, id);
+}
+
+
+int CodeEntry::GetSourceLine(int pc_offset) const {
+  if (line_info_ && !line_info_->empty()) {
+    return line_info_->GetSourceLineNumber(pc_offset);
+  }
+  return v8::CpuProfileNode::kNoLineNumberInfo;
 }
 
 
@@ -202,6 +234,40 @@
 }
 
 
+void ProfileNode::IncrementLineTicks(int src_line) {
+  if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) return;
+  // Increment a hit counter of a certain source line.
+  // Add a new source line if not found.
+  HashMap::Entry* e =
+      line_ticks_.Lookup(reinterpret_cast<void*>(src_line), src_line, true);
+  DCHECK(e);
+  e->value = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(e->value) + 1);
+}
+
+
+bool ProfileNode::GetLineTicks(v8::CpuProfileNode::LineTick* entries,
+                               unsigned int length) const {
+  if (entries == NULL || length == 0) return false;
+
+  unsigned line_count = line_ticks_.occupancy();
+
+  if (line_count == 0) return true;
+  if (length < line_count) return false;
+
+  v8::CpuProfileNode::LineTick* entry = entries;
+
+  for (HashMap::Entry* p = line_ticks_.Start(); p != NULL;
+       p = line_ticks_.Next(p), entry++) {
+    entry->line =
+        static_cast<unsigned int>(reinterpret_cast<uintptr_t>(p->key));
+    entry->hit_count =
+        static_cast<unsigned int>(reinterpret_cast<uintptr_t>(p->value));
+  }
+
+  return true;
+}
+
+
 void ProfileNode::Print(int indent) {
   base::OS::Print("%5u %*s %s%s %d #%d %s", self_ticks_, indent, "",
                   entry_->name_prefix(), entry_->name(), entry_->script_id(),
@@ -242,7 +308,8 @@
 }
 
 
-ProfileNode* ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path) {
+ProfileNode* ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path,
+                                         int src_line) {
   ProfileNode* node = root_;
   for (CodeEntry** entry = path.start() + path.length() - 1;
        entry != path.start() - 1;
@@ -252,11 +319,15 @@
     }
   }
   node->IncrementSelfTicks();
+  if (src_line != v8::CpuProfileNode::kNoLineNumberInfo) {
+    node->IncrementLineTicks(src_line);
+  }
   return node;
 }
 
 
-void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path) {
+void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path,
+                                   int src_line) {
   ProfileNode* node = root_;
   for (CodeEntry** entry = path.start();
        entry != path.start() + path.length();
@@ -266,6 +337,9 @@
     }
   }
   node->IncrementSelfTicks();
+  if (src_line != v8::CpuProfileNode::kNoLineNumberInfo) {
+    node->IncrementLineTicks(src_line);
+  }
 }
 
 
@@ -327,8 +401,8 @@
 
 
 void CpuProfile::AddPath(base::TimeTicks timestamp,
-                         const Vector<CodeEntry*>& path) {
-  ProfileNode* top_frame_node = top_down_.AddPathFromEnd(path);
+                         const Vector<CodeEntry*>& path, int src_line) {
+  ProfileNode* top_frame_node = top_down_.AddPathFromEnd(path, src_line);
   if (record_samples_) {
     timestamps_.Add(timestamp);
     samples_.Add(top_frame_node);
@@ -517,31 +591,25 @@
 
 
 void CpuProfilesCollection::AddPathToCurrentProfiles(
-    base::TimeTicks timestamp, const Vector<CodeEntry*>& path) {
+    base::TimeTicks timestamp, const Vector<CodeEntry*>& path, int src_line) {
   // As starting / stopping profiles is rare relatively to this
   // method, we don't bother minimizing the duration of lock holding,
   // e.g. copying contents of the list to a local vector.
   current_profiles_semaphore_.Wait();
   for (int i = 0; i < current_profiles_.length(); ++i) {
-    current_profiles_[i]->AddPath(timestamp, path);
+    current_profiles_[i]->AddPath(timestamp, path, src_line);
   }
   current_profiles_semaphore_.Signal();
 }
 
 
 CodeEntry* CpuProfilesCollection::NewCodeEntry(
-      Logger::LogEventsAndTags tag,
-      const char* name,
-      const char* name_prefix,
-      const char* resource_name,
-      int line_number,
-      int column_number) {
-  CodeEntry* code_entry = new CodeEntry(tag,
-                                        name,
-                                        name_prefix,
-                                        resource_name,
-                                        line_number,
-                                        column_number);
+    Logger::LogEventsAndTags tag, const char* name, const char* name_prefix,
+    const char* resource_name, int line_number, int column_number,
+    JITLineInfoTable* line_info, Address instruction_start) {
+  CodeEntry* code_entry =
+      new CodeEntry(tag, name, name_prefix, resource_name, line_number,
+                    column_number, line_info, instruction_start);
   code_entries_.Add(code_entry);
   return code_entry;
 }
@@ -579,6 +647,15 @@
   // entries vector with NULL values.
   CodeEntry** entry = entries.start();
   memset(entry, 0, entries.length() * sizeof(*entry));
+
+  // The ProfileNode knows nothing about all versions of generated code for
+  // the same JS function. The line number information associated with
+  // the latest version of generated code is used to find a source line number
+  // for a JS function. Then, the detected source line is passed to
+  // ProfileNode to increase the tick count for this source line.
+  int src_line = v8::CpuProfileNode::kNoLineNumberInfo;
+  bool src_line_not_found = true;
+
   if (sample.pc != NULL) {
     if (sample.has_external_callback && sample.state == EXTERNAL &&
         sample.top_frame_type == StackFrame::EXIT) {
@@ -595,10 +672,9 @@
       // frame. Check for this case and just skip such samples.
       if (pc_entry) {
         List<OffsetRange>* ranges = pc_entry->no_frame_ranges();
+        int pc_offset =
+            static_cast<int>(sample.pc - pc_entry->instruction_start());
         if (ranges) {
-          Code* code = Code::cast(HeapObject::FromAddress(start));
-          int pc_offset = static_cast<int>(
-              sample.pc - code->instruction_start());
           for (int i = 0; i < ranges->length(); i++) {
             OffsetRange& range = ranges->at(i);
             if (range.from <= pc_offset && pc_offset < range.to) {
@@ -606,6 +682,11 @@
             }
           }
         }
+        src_line = pc_entry->GetSourceLine(pc_offset);
+        if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) {
+          src_line = pc_entry->line_number();
+        }
+        src_line_not_found = false;
         *entry++ = pc_entry;
 
         if (pc_entry->builtin_id() == Builtins::kFunctionCall ||
@@ -626,7 +707,22 @@
            *stack_end = stack_pos + sample.frames_count;
          stack_pos != stack_end;
          ++stack_pos) {
-      *entry++ = code_map_.FindEntry(*stack_pos);
+      Address start = NULL;
+      *entry = code_map_.FindEntry(*stack_pos, &start);
+
+      // Skip unresolved frames (e.g. internal frame) and get source line of
+      // the first JS caller.
+      if (src_line_not_found && *entry) {
+        int pc_offset =
+            static_cast<int>(*stack_pos - (*entry)->instruction_start());
+        src_line = (*entry)->GetSourceLine(pc_offset);
+        if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) {
+          src_line = (*entry)->line_number();
+        }
+        src_line_not_found = false;
+      }
+
+      entry++;
     }
   }
 
@@ -644,7 +740,7 @@
     }
   }
 
-  profiles_->AddPathToCurrentProfiles(sample.timestamp, entries);
+  profiles_->AddPathToCurrentProfiles(sample.timestamp, entries, src_line);
 }
 
 
diff --git a/src/profile-generator.h b/src/profile-generator.h
index 5ebb92b..2127a1e 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -5,6 +5,7 @@
 #ifndef V8_PROFILE_GENERATOR_H_
 #define V8_PROFILE_GENERATOR_H_
 
+#include <map>
 #include "include/v8-profiler.h"
 #include "src/allocation.h"
 #include "src/hashmap.h"
@@ -44,24 +45,45 @@
 };
 
 
+// Provides a mapping from the offsets within generated code to
+// the source line.
+class JITLineInfoTable : public Malloced {
+ public:
+  JITLineInfoTable();
+  ~JITLineInfoTable();
+
+  void SetPosition(int pc_offset, int line);
+  int GetSourceLineNumber(int pc_offset) const;
+
+  bool empty() const { return pc_offset_map_.empty(); }
+
+ private:
+  // pc_offset -> source line
+  typedef std::map<int, int> PcOffsetMap;
+  PcOffsetMap pc_offset_map_;
+  DISALLOW_COPY_AND_ASSIGN(JITLineInfoTable);
+};
+
 class CodeEntry {
  public:
   // CodeEntry doesn't own name strings, just references them.
-  inline CodeEntry(Logger::LogEventsAndTags tag,
-                   const char* name,
+  inline CodeEntry(Logger::LogEventsAndTags tag, const char* name,
                    const char* name_prefix = CodeEntry::kEmptyNamePrefix,
                    const char* resource_name = CodeEntry::kEmptyResourceName,
                    int line_number = v8::CpuProfileNode::kNoLineNumberInfo,
-                   int column_number = v8::CpuProfileNode::kNoColumnNumberInfo);
+                   int column_number = v8::CpuProfileNode::kNoColumnNumberInfo,
+                   JITLineInfoTable* line_info = NULL,
+                   Address instruction_start = NULL);
   ~CodeEntry();
 
-  bool is_js_function() const { return is_js_function_tag(tag_); }
+  bool is_js_function() const { return is_js_function_tag(tag()); }
   const char* name_prefix() const { return name_prefix_; }
   bool has_name_prefix() const { return name_prefix_[0] != '\0'; }
   const char* name() const { return name_; }
   const char* resource_name() const { return resource_name_; }
   int line_number() const { return line_number_; }
   int column_number() const { return column_number_; }
+  const JITLineInfoTable* line_info() const { return line_info_; }
   void set_shared_id(int shared_id) { shared_id_ = shared_id; }
   int script_id() const { return script_id_; }
   void set_script_id(int script_id) { script_id_ = script_id; }
@@ -78,18 +100,27 @@
   }
 
   void SetBuiltinId(Builtins::Name id);
-  Builtins::Name builtin_id() const { return builtin_id_; }
+  Builtins::Name builtin_id() const {
+    return BuiltinIdField::decode(bit_field_);
+  }
 
   uint32_t GetCallUid() const;
   bool IsSameAs(CodeEntry* entry) const;
 
+  int GetSourceLine(int pc_offset) const;
+
+  Address instruction_start() const { return instruction_start_; }
+
   static const char* const kEmptyNamePrefix;
   static const char* const kEmptyResourceName;
   static const char* const kEmptyBailoutReason;
 
  private:
-  Logger::LogEventsAndTags tag_ : 8;
-  Builtins::Name builtin_id_ : 8;
+  class TagField : public BitField<Logger::LogEventsAndTags, 0, 8> {};
+  class BuiltinIdField : public BitField<Builtins::Name, 8, 8> {};
+  Logger::LogEventsAndTags tag() const { return TagField::decode(bit_field_); }
+
+  uint32_t bit_field_;
   const char* name_prefix_;
   const char* name_;
   const char* resource_name_;
@@ -99,6 +130,8 @@
   int script_id_;
   List<OffsetRange>* no_frame_ranges_;
   const char* bailout_reason_;
+  JITLineInfoTable* line_info_;
+  Address instruction_start_;
 
   DISALLOW_COPY_AND_ASSIGN(CodeEntry);
 };
@@ -114,11 +147,15 @@
   ProfileNode* FindOrAddChild(CodeEntry* entry);
   void IncrementSelfTicks() { ++self_ticks_; }
   void IncreaseSelfTicks(unsigned amount) { self_ticks_ += amount; }
+  void IncrementLineTicks(int src_line);
 
   CodeEntry* entry() const { return entry_; }
   unsigned self_ticks() const { return self_ticks_; }
   const List<ProfileNode*>* children() const { return &children_list_; }
   unsigned id() const { return id_; }
+  unsigned int GetHitLineCount() const { return line_ticks_.occupancy(); }
+  bool GetLineTicks(v8::CpuProfileNode::LineTick* entries,
+                    unsigned int length) const;
 
   void Print(int indent);
 
@@ -132,6 +169,8 @@
     return entry->GetCallUid();
   }
 
+  static bool LineTickMatch(void* a, void* b) { return a == b; }
+
   ProfileTree* tree_;
   CodeEntry* entry_;
   unsigned self_ticks_;
@@ -139,6 +178,7 @@
   HashMap children_;
   List<ProfileNode*> children_list_;
   unsigned id_;
+  HashMap line_ticks_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileNode);
 };
@@ -149,8 +189,11 @@
   ProfileTree();
   ~ProfileTree();
 
-  ProfileNode* AddPathFromEnd(const Vector<CodeEntry*>& path);
-  void AddPathFromStart(const Vector<CodeEntry*>& path);
+  ProfileNode* AddPathFromEnd(
+      const Vector<CodeEntry*>& path,
+      int src_line = v8::CpuProfileNode::kNoLineNumberInfo);
+  void AddPathFromStart(const Vector<CodeEntry*>& path,
+                        int src_line = v8::CpuProfileNode::kNoLineNumberInfo);
   ProfileNode* root() const { return root_; }
   unsigned next_node_id() { return next_node_id_++; }
 
@@ -175,7 +218,8 @@
   CpuProfile(const char* title, bool record_samples);
 
   // Add pc -> ... -> main() call path to the profile.
-  void AddPath(base::TimeTicks timestamp, const Vector<CodeEntry*>& path);
+  void AddPath(base::TimeTicks timestamp, const Vector<CodeEntry*>& path,
+               int src_line);
   void CalculateTotalTicksAndSamplingRate();
 
   const char* title() const { return title_; }
@@ -277,16 +321,16 @@
   void RemoveProfile(CpuProfile* profile);
 
   CodeEntry* NewCodeEntry(
-      Logger::LogEventsAndTags tag,
-      const char* name,
+      Logger::LogEventsAndTags tag, const char* name,
       const char* name_prefix = CodeEntry::kEmptyNamePrefix,
       const char* resource_name = CodeEntry::kEmptyResourceName,
       int line_number = v8::CpuProfileNode::kNoLineNumberInfo,
-      int column_number = v8::CpuProfileNode::kNoColumnNumberInfo);
+      int column_number = v8::CpuProfileNode::kNoColumnNumberInfo,
+      JITLineInfoTable* line_info = NULL, Address instruction_start = NULL);
 
   // Called from profile generator thread.
-  void AddPathToCurrentProfiles(
-      base::TimeTicks timestamp, const Vector<CodeEntry*>& path);
+  void AddPathToCurrentProfiles(base::TimeTicks timestamp,
+                                const Vector<CodeEntry*>& path, int src_line);
 
   // Limits the number of profiles that can be simultaneously collected.
   static const int kMaxSimultaneousProfiles = 100;
diff --git a/src/promise.js b/src/promise.js
index 37c10ec..c096296 100644
--- a/src/promise.js
+++ b/src/promise.js
@@ -19,6 +19,7 @@
 var PromiseCatch;
 var PromiseThen;
 var PromiseHasRejectHandler;
+var PromiseHasUserDefinedRejectHandler;
 
 // mirror-debugger.js currently uses builtins.promiseStatus. It would be nice
 // if we could move these property names into the closure below.
@@ -30,9 +31,10 @@
 var promiseOnResolve = GLOBAL_PRIVATE("Promise#onResolve");
 var promiseOnReject = GLOBAL_PRIVATE("Promise#onReject");
 var promiseRaw = GLOBAL_PRIVATE("Promise#raw");
-var promiseDebug = GLOBAL_PRIVATE("Promise#debug");
+var promiseHasHandler = %PromiseHasHandlerSymbol();
 var lastMicrotaskId = 0;
 
+
 (function() {
 
   var $Promise = function Promise(resolver) {
@@ -65,6 +67,13 @@
     return promise;
   }
 
+  function PromiseCreateAndSet(status, value) {
+    var promise = new $Promise(promiseRaw);
+    // If debug is active, notify about the newly created promise first.
+    if (DEBUG_IS_ACTIVE) PromiseSet(promise, 0, UNDEFINED);
+    return PromiseSet(promise, status, value);
+  }
+
   function PromiseInit(promise) {
     return PromiseSet(
         promise, 0, UNDEFINED, new InternalArray, new InternalArray)
@@ -72,7 +81,8 @@
 
   function PromiseDone(promise, status, value, promiseQueue) {
     if (GET_PRIVATE(promise, promiseStatus) === 0) {
-      PromiseEnqueue(value, GET_PRIVATE(promise, promiseQueue), status);
+      var tasks = GET_PRIVATE(promise, promiseQueue);
+      if (tasks.length) PromiseEnqueue(value, tasks, status);
       PromiseSet(promise, status, value);
     }
   }
@@ -101,6 +111,7 @@
   function PromiseHandle(value, handler, deferred) {
     try {
       %DebugPushPromise(deferred.promise);
+      DEBUG_PREPARE_STEP_IN_IF_STEPPING(handler);
       var result = handler(value);
       if (result === deferred.promise)
         throw MakeTypeError('promise_cyclic', [result]);
@@ -159,11 +170,12 @@
 
   PromiseReject = function PromiseReject(promise, r) {
     // Check promise status to confirm that this reject has an effect.
-    // Check promiseDebug property to avoid duplicate event.
-    if (DEBUG_IS_ACTIVE &&
-        GET_PRIVATE(promise, promiseStatus) == 0 &&
-        !HAS_DEFINED_PRIVATE(promise, promiseDebug)) {
-      %DebugPromiseRejectEvent(promise, r);
+    // Call runtime for callbacks to the debugger or for unhandled reject.
+    if (GET_PRIVATE(promise, promiseStatus) == 0) {
+      var debug_is_active = DEBUG_IS_ACTIVE;
+      if (debug_is_active || !HAS_DEFINED_PRIVATE(promise, promiseHasHandler)) {
+        %PromiseRejectEvent(promise, r, debug_is_active);
+      }
     }
     PromiseDone(promise, -1, r, promiseOnReject)
   }
@@ -192,19 +204,24 @@
   function PromiseResolved(x) {
     if (this === $Promise) {
       // Optimized case, avoid extra closure.
-      return PromiseSet(new $Promise(promiseRaw), +1, x);
+      return PromiseCreateAndSet(+1, x);
     } else {
       return new this(function(resolve, reject) { resolve(x) });
     }
   }
 
   function PromiseRejected(r) {
+    var promise;
     if (this === $Promise) {
       // Optimized case, avoid extra closure.
-      return PromiseSet(new $Promise(promiseRaw), -1, r);
+      promise = PromiseCreateAndSet(-1, r);
+      // The debug event for this would always be an uncaught promise reject,
+      // which is usually simply noise. Do not trigger that debug event.
+      %PromiseRejectEvent(promise, r, false);
     } else {
-      return new this(function(resolve, reject) { reject(r) });
+      promise = new this(function(resolve, reject) { reject(r) });
     }
+    return promise;
   }
 
   // Simple chaining.
@@ -227,11 +244,18 @@
                        +1);
         break;
       case -1:  // Rejected
+        if (!HAS_DEFINED_PRIVATE(this, promiseHasHandler)) {
+          // Promise has already been rejected, but had no handler.
+          // Revoke previously triggered reject event.
+          %PromiseRevokeReject(this);
+        }
         PromiseEnqueue(GET_PRIVATE(this, promiseValue),
                        [onReject, deferred],
                        -1);
         break;
     }
+    // Mark this promise as having handler.
+    SET_PRIVATE(this, promiseHasHandler, true);
     if (DEBUG_IS_ACTIVE) {
       %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this });
     }
@@ -255,8 +279,15 @@
       this,
       function(x) {
         x = PromiseCoerce(constructor, x);
-        return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) :
-               IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x);
+        if (x === that) {
+          DEBUG_PREPARE_STEP_IN_IF_STEPPING(onReject);
+          return onReject(MakeTypeError('promise_cyclic', [x]));
+        } else if (IsPromise(x)) {
+          return x.then(onResolve, onReject);
+        } else {
+          DEBUG_PREPARE_STEP_IN_IF_STEPPING(onResolve);
+          return onResolve(x);
+        }
       },
       onReject,
       PromiseChain
@@ -325,22 +356,24 @@
 
   // Utility for debugger
 
-  function PromiseHasRejectHandlerRecursive(promise) {
+  function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
     var queue = GET_PRIVATE(promise, promiseOnReject);
     if (IS_UNDEFINED(queue)) return false;
-    // Do a depth first search for a reject handler that's not
-    // the default PromiseIdRejectHandler.
     for (var i = 0; i < queue.length; i += 2) {
       if (queue[i] != PromiseIdRejectHandler) return true;
-      if (PromiseHasRejectHandlerRecursive(queue[i + 1].promise)) return true;
+      if (PromiseHasUserDefinedRejectHandlerRecursive(queue[i + 1].promise)) {
+        return true;
+      }
     }
     return false;
   }
 
-  PromiseHasRejectHandler = function PromiseHasRejectHandler() {
-    // Mark promise as already having triggered a reject event.
-    SET_PRIVATE(this, promiseDebug, true);
-    return PromiseHasRejectHandlerRecursive(this);
+  // Return whether the promise will be handled by a user-defined reject
+  // handler somewhere down the promise chain. For this, we do a depth-first
+  // search for a reject handler that's not the default PromiseIdRejectHandler.
+  PromiseHasUserDefinedRejectHandler =
+      function PromiseHasUserDefinedRejectHandler() {
+    return PromiseHasUserDefinedRejectHandlerRecursive(this);
   };
 
   // -------------------------------------------------------------------
@@ -348,6 +381,8 @@
 
   %CheckIsBootstrapping();
   %AddNamedProperty(global, 'Promise', $Promise, DONT_ENUM);
+  %AddNamedProperty(
+      $Promise.prototype, symbolToStringTag, "Promise", DONT_ENUM | READ_ONLY);
   InstallFunctions($Promise, DONT_ENUM, [
     "defer", PromiseDeferred,
     "accept", PromiseResolved,
diff --git a/src/property-details.h b/src/property-details.h
index f75bcff..6140e0d 100644
--- a/src/property-details.h
+++ b/src/property-details.h
@@ -41,16 +41,24 @@
 class TypeInfo;
 
 // Type of properties.
+// Order of kinds is significant.
+// Must fit in the BitField PropertyDetails::KindField.
+enum PropertyKind { DATA = 0, ACCESSOR = 1 };
+
+
+// Order of modes is significant.
+// Must fit in the BitField PropertyDetails::StoreModeField.
+enum PropertyLocation { IN_OBJECT = 0, IN_DESCRIPTOR = 1 };
+
+
 // Order of properties is significant.
 // Must fit in the BitField PropertyDetails::TypeField.
 // A copy of this is in mirror-debugger.js.
 enum PropertyType {
-  // Only in slow mode.
-  NORMAL = 0,
-  // Only in fast mode.
-  FIELD = 1,
-  CONSTANT = 2,
-  CALLBACKS = 3
+  FIELD = (IN_OBJECT << 1) | DATA,
+  CONSTANT = (IN_DESCRIPTOR << 1) | DATA,
+  ACCESSOR_FIELD = (IN_OBJECT << 1) | ACCESSOR,
+  CALLBACKS = (IN_DESCRIPTOR << 1) | ACCESSOR
 };
 
 
@@ -229,6 +237,9 @@
     return Representation::FromKind(static_cast<Representation::Kind>(bits));
   }
 
+  PropertyKind kind() const { return KindField::decode(value_); }
+  PropertyLocation location() const { return LocationField::decode(value_); }
+
   PropertyType type() const { return TypeField::decode(value_); }
 
   PropertyAttributes attributes() const {
@@ -240,13 +251,12 @@
   }
 
   Representation representation() const {
-    DCHECK(type() != NORMAL);
     return DecodeRepresentation(RepresentationField::decode(value_));
   }
 
-  int field_index() const {
-    return FieldIndexField::decode(value_);
-  }
+  int field_index() const { return FieldIndexField::decode(value_); }
+
+  inline int field_width_in_words() const;
 
   inline PropertyDetails AsDeleted() const;
 
@@ -257,11 +267,12 @@
   bool IsReadOnly() const { return (attributes() & READ_ONLY) != 0; }
   bool IsConfigurable() const { return (attributes() & DONT_DELETE) == 0; }
   bool IsDontEnum() const { return (attributes() & DONT_ENUM) != 0; }
-  bool IsDeleted() const { return DeletedField::decode(value_) != 0;}
+  bool IsDeleted() const { return DeletedField::decode(value_) != 0; }
 
   // Bit fields in value_ (type, shift, size). Must be public so the
   // constants can be embedded in generated code.
-  class TypeField : public BitField<PropertyType, 0, 2> {};
+  class KindField : public BitField<PropertyKind, 0, 1> {};
+  class LocationField : public BitField<PropertyLocation, 1, 1> {};
   class AttributesField : public BitField<PropertyAttributes, 2, 3> {};
 
   // Bit fields for normalized objects.
@@ -275,11 +286,24 @@
   class FieldIndexField
       : public BitField<uint32_t, 9 + kDescriptorIndexBitCount,
                         kDescriptorIndexBitCount> {};  // NOLINT
-  // All bits for fast objects must fix in a smi.
-  STATIC_ASSERT(9 + kDescriptorIndexBitCount + kDescriptorIndexBitCount <= 31);
+
+  // NOTE: TypeField overlaps with KindField and LocationField.
+  class TypeField : public BitField<PropertyType, 0, 2> {};
+  STATIC_ASSERT(KindField::kNext == LocationField::kShift);
+  STATIC_ASSERT(TypeField::kShift == KindField::kShift);
+  STATIC_ASSERT(TypeField::kNext == LocationField::kNext);
+
+  // All bits for both fast and slow objects must fit in a smi.
+  STATIC_ASSERT(DictionaryStorageField::kNext <= 31);
+  STATIC_ASSERT(FieldIndexField::kNext <= 31);
 
   static const int kInitialIndex = 1;
 
+#ifdef OBJECT_PRINT
+  // For our gdb macros, we should perhaps change these in the future.
+  void Print(bool dictionary_mode);
+#endif
+
  private:
   PropertyDetails(int value, int pointer) {
     value_ = DescriptorPointer::update(value, pointer);
@@ -295,6 +319,10 @@
   uint32_t value_;
 };
 
+
+std::ostream& operator<<(std::ostream& os,
+                         const PropertyAttributes& attributes);
+std::ostream& operator<<(std::ostream& os, const PropertyDetails& details);
 } }  // namespace v8::internal
 
 #endif  // V8_PROPERTY_DETAILS_H_
diff --git a/src/property.cc b/src/property.cc
index f0ff95c..d00998c 100644
--- a/src/property.cc
+++ b/src/property.cc
@@ -20,7 +20,7 @@
 }
 
 
-OStream& operator<<(OStream& os, const LookupResult& r) {
+std::ostream& operator<<(std::ostream& os, const LookupResult& r) {
   if (!r.IsFound()) return os << "Not Found\n";
 
   os << "LookupResult:\n";
@@ -31,9 +31,76 @@
 }
 
 
-OStream& operator<<(OStream& os, const Descriptor& d) {
-  return os << "Descriptor " << Brief(*d.GetKey()) << " @ "
-            << Brief(*d.GetValue());
+std::ostream& operator<<(std::ostream& os,
+                         const PropertyAttributes& attributes) {
+  os << "[";
+  os << (((attributes & READ_ONLY) == 0) ? "W" : "_");    // writable
+  os << (((attributes & DONT_ENUM) == 0) ? "E" : "_");    // enumerable
+  os << (((attributes & DONT_DELETE) == 0) ? "C" : "_");  // configurable
+  os << "]";
+  return os;
+}
+
+
+struct FastPropertyDetails {
+  explicit FastPropertyDetails(const PropertyDetails& v) : details(v) {}
+  const PropertyDetails details;
+};
+
+
+// Outputs PropertyDetails as a dictionary details.
+std::ostream& operator<<(std::ostream& os, const PropertyDetails& details) {
+  os << "(";
+  if (details.location() == IN_DESCRIPTOR) {
+    os << "immutable ";
+  }
+  os << (details.kind() == DATA ? "data" : "accessor");
+  return os << ", dictionary_index: " << details.dictionary_index()
+            << ", attrs: " << details.attributes() << ")";
+}
+
+
+// Outputs PropertyDetails as a descriptor array details.
+std::ostream& operator<<(std::ostream& os,
+                         const FastPropertyDetails& details_fast) {
+  const PropertyDetails& details = details_fast.details;
+  os << "(";
+  if (details.location() == IN_DESCRIPTOR) {
+    os << "immutable ";
+  }
+  os << (details.kind() == DATA ? "data" : "accessor");
+  if (details.location() == IN_OBJECT) {
+    os << ": " << details.representation().Mnemonic()
+       << ", field_index: " << details.field_index();
+  }
+  return os << ", p: " << details.pointer()
+            << ", attrs: " << details.attributes() << ")";
+}
+
+
+#ifdef OBJECT_PRINT
+void PropertyDetails::Print(bool dictionary_mode) {
+  OFStream os(stdout);
+  if (dictionary_mode) {
+    os << *this;
+  } else {
+    os << FastPropertyDetails(*this);
+  }
+  os << "\n" << std::flush;
+}
+#endif
+
+
+std::ostream& operator<<(std::ostream& os, const Descriptor& d) {
+  Object* value = *d.GetValue();
+  os << "Descriptor " << Brief(*d.GetKey()) << " @ " << Brief(value) << " ";
+  if (value->IsAccessorPair()) {
+    AccessorPair* pair = AccessorPair::cast(value);
+    os << "(get: " << Brief(pair->getter())
+       << ", set: " << Brief(pair->setter()) << ") ";
+  }
+  os << FastPropertyDetails(d.GetDetails());
+  return os;
 }
 
 } }  // namespace v8::internal
diff --git a/src/property.h b/src/property.h
index 779d9fc..a9d8b09 100644
--- a/src/property.h
+++ b/src/property.h
@@ -5,6 +5,8 @@
 #ifndef V8_PROPERTY_H_
 #define V8_PROPERTY_H_
 
+#include <iosfwd>
+
 #include "src/factory.h"
 #include "src/field-index.h"
 #include "src/field-index-inl.h"
@@ -14,8 +16,6 @@
 namespace v8 {
 namespace internal {
 
-class OStream;
-
 // Abstraction for elements in instance-descriptor arrays.
 //
 // Each descriptor has a key, property attributes, property type,
@@ -70,7 +70,7 @@
 };
 
 
-OStream& operator<<(OStream& os, const Descriptor& d);
+std::ostream& operator<<(std::ostream& os, const Descriptor& d);
 
 
 class FieldDescriptor FINAL : public Descriptor {
@@ -119,7 +119,7 @@
         lookup_type_(NOT_FOUND),
         holder_(NULL),
         transition_(NULL),
-        details_(NONE, NORMAL, Representation::None()) {
+        details_(NONE, FIELD, Representation::None()) {
     isolate->set_top_lookup_result(this);
   }
 
@@ -148,7 +148,7 @@
 
   void NotFound() {
     lookup_type_ = NOT_FOUND;
-    details_ = PropertyDetails(NONE, NORMAL, Representation::None());
+    details_ = PropertyDetails(NONE, FIELD, 0);
     holder_ = NULL;
     transition_ = NULL;
   }
@@ -160,7 +160,6 @@
 
   // Property callbacks does not include transitions to callbacks.
   bool IsPropertyCallbacks() const {
-    DCHECK(!(details_.type() == CALLBACKS && !IsFound()));
     return !IsTransition() && details_.type() == CALLBACKS;
   }
 
@@ -170,12 +169,10 @@
   }
 
   bool IsField() const {
-    DCHECK(!(details_.type() == FIELD && !IsFound()));
     return lookup_type_ == DESCRIPTOR_TYPE && details_.type() == FIELD;
   }
 
   bool IsConstant() const {
-    DCHECK(!(details_.type() == CONSTANT && !IsFound()));
     return lookup_type_ == DESCRIPTOR_TYPE && details_.type() == CONSTANT;
   }
 
@@ -249,7 +246,7 @@
 };
 
 
-OStream& operator<<(OStream& os, const LookupResult& r);
+std::ostream& operator<<(std::ostream& os, const LookupResult& r);
 } }  // namespace v8::internal
 
 #endif  // V8_PROPERTY_H_
diff --git a/src/regexp.js b/src/regexp.js
index 0f3dbb6..e1eac76 100644
--- a/src/regexp.js
+++ b/src/regexp.js
@@ -30,46 +30,7 @@
   pattern = IS_UNDEFINED(pattern) ? '' : ToString(pattern);
   flags = IS_UNDEFINED(flags) ? '' : ToString(flags);
 
-  var global = false;
-  var ignoreCase = false;
-  var multiline = false;
-  var sticky = false;
-  for (var i = 0; i < flags.length; i++) {
-    var c = %_CallFunction(flags, i, StringCharAt);
-    switch (c) {
-      case 'g':
-        if (global) {
-          throw MakeSyntaxError("invalid_regexp_flags", [flags]);
-        }
-        global = true;
-        break;
-      case 'i':
-        if (ignoreCase) {
-          throw MakeSyntaxError("invalid_regexp_flags", [flags]);
-        }
-        ignoreCase = true;
-        break;
-      case 'm':
-        if (multiline) {
-          throw MakeSyntaxError("invalid_regexp_flags", [flags]);
-        }
-        multiline = true;
-        break;
-      case 'y':
-        if (!harmony_regexps || sticky) {
-          throw MakeSyntaxError("invalid_regexp_flags", [flags]);
-        }
-        sticky = true;
-        break;
-      default:
-        throw MakeSyntaxError("invalid_regexp_flags", [flags]);
-    }
-  }
-
-  %RegExpInitializeObject(object, pattern, global, ignoreCase, multiline, sticky);
-
-  // Call internal function to compile the pattern.
-  %RegExpCompile(object, pattern, flags);
+  %RegExpInitializeAndCompile(object, pattern, flags);
 }
 
 
diff --git a/src/rewriter.cc b/src/rewriter.cc
index 867229a..c52051a 100644
--- a/src/rewriter.cc
+++ b/src/rewriter.cc
@@ -15,15 +15,13 @@
 
 class Processor: public AstVisitor {
  public:
-  Processor(Variable* result, Zone* zone, AstNode::IdGen* ast_node_id_gen)
+  Processor(Variable* result, AstValueFactory* ast_value_factory)
       : result_(result),
         result_assigned_(false),
         is_set_(false),
         in_try_(false),
-        // Passing a null AstValueFactory is fine, because Processor doesn't
-        // need to create strings or literals.
-        factory_(zone, NULL, ast_node_id_gen) {
-    InitializeAstVisitor(zone);
+        factory_(ast_value_factory) {
+    InitializeAstVisitor(ast_value_factory->zone());
   }
 
   virtual ~Processor() { }
@@ -31,9 +29,7 @@
   void Process(ZoneList<Statement*>* statements);
   bool result_assigned() const { return result_assigned_; }
 
-  AstNodeFactory<AstNullVisitor>* factory() {
-    return &factory_;
-  }
+  AstNodeFactory* factory() { return &factory_; }
 
  private:
   Variable* result_;
@@ -51,7 +47,7 @@
   bool is_set_;
   bool in_try_;
 
-  AstNodeFactory<AstNullVisitor> factory_;
+  AstNodeFactory factory_;
 
   Expression* SetResult(Expression* value) {
     result_assigned_ = true;
@@ -61,8 +57,7 @@
   }
 
   // Node visitors.
-#define DEF_VISIT(type) \
-  virtual void Visit##type(type* node);
+#define DEF_VISIT(type) virtual void Visit##type(type* node) OVERRIDE;
   AST_NODE_LIST(DEF_VISIT)
 #undef DEF_VISIT
 
@@ -232,7 +227,7 @@
   DCHECK(function != NULL);
   Scope* scope = function->scope();
   DCHECK(scope != NULL);
-  if (!scope->is_global_scope() && !scope->is_eval_scope()) return true;
+  if (!scope->is_script_scope() && !scope->is_eval_scope()) return true;
 
   ZoneList<Statement*>* body = function->body();
   if (!body->is_empty()) {
@@ -240,7 +235,7 @@
         scope->NewTemporary(info->ast_value_factory()->dot_result_string());
     // The name string must be internalized at this point.
     DCHECK(!result->name().is_null());
-    Processor processor(result, info->zone(), info->ast_node_id_gen());
+    Processor processor(result, info->ast_value_factory());
     processor.Process(body);
     if (processor.HasStackOverflow()) return false;
 
@@ -253,9 +248,8 @@
       // the end position of the function generated for executing the eval code
       // coincides with the end of the with scope which is the position of '1'.
       int pos = function->end_position();
-      VariableProxy* result_proxy = processor.factory()->NewVariableProxy(
-          result->raw_name(), false, result->interface(), pos);
-      result_proxy->BindTo(result);
+      VariableProxy* result_proxy =
+          processor.factory()->NewVariableProxy(result, pos);
       Statement* result_statement =
           processor.factory()->NewReturnStatement(result_proxy, pos);
       body->Add(result_statement, info->zone());
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index d6099d4..6c99714 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -57,9 +57,11 @@
 }
 
 
-static void GetICCounts(Code* shared_code, int* ic_with_type_info_count,
-                        int* ic_generic_count, int* ic_total_count,
-                        int* type_info_percentage, int* generic_percentage) {
+static void GetICCounts(SharedFunctionInfo* shared,
+                        int* ic_with_type_info_count, int* ic_generic_count,
+                        int* ic_total_count, int* type_info_percentage,
+                        int* generic_percentage) {
+  Code* shared_code = shared->code();
   *ic_total_count = 0;
   *ic_generic_count = 0;
   *ic_with_type_info_count = 0;
@@ -70,6 +72,12 @@
     *ic_generic_count = info->ic_generic_count();
     *ic_total_count = info->ic_total_count();
   }
+
+  // Harvest vector-ics as well
+  TypeFeedbackVector* vector = shared->feedback_vector();
+  *ic_with_type_info_count += vector->ic_with_type_info_count();
+  *ic_generic_count += vector->ic_generic_count();
+
   if (*ic_total_count > 0) {
     *type_info_percentage = 100 * *ic_with_type_info_count / *ic_total_count;
     *generic_percentage = 100 * *ic_generic_count / *ic_total_count;
@@ -89,7 +97,7 @@
     PrintF(" for recompilation, reason: %s", reason);
     if (FLAG_type_info_threshold > 0) {
       int typeinfo, generic, total, type_percentage, generic_percentage;
-      GetICCounts(function->shared()->code(), &typeinfo, &generic, &total,
+      GetICCounts(function->shared(), &typeinfo, &generic, &total,
                   &type_percentage, &generic_percentage);
       PrintF(", ICs with typeinfo: %d/%d (%d%%)", typeinfo, total,
              type_percentage);
@@ -98,23 +106,7 @@
     PrintF("]\n");
   }
 
-
-  if (isolate_->concurrent_recompilation_enabled() &&
-      !isolate_->bootstrapper()->IsActive()) {
-    if (isolate_->concurrent_osr_enabled() &&
-        isolate_->optimizing_compiler_thread()->IsQueuedForOSR(function)) {
-      // Do not attempt regular recompilation if we already queued this for OSR.
-      // TODO(yangguo): This is necessary so that we don't install optimized
-      // code on a function that is already optimized, since OSR and regular
-      // recompilation race.  This goes away as soon as OSR becomes one-shot.
-      return;
-    }
-    DCHECK(!function->IsInOptimizationQueue());
-    function->MarkForConcurrentOptimization();
-  } else {
-    // The next call to the function will trigger optimization.
-    function->MarkForOptimization();
-  }
+  function->AttemptConcurrentOptimization();
 }
 
 
@@ -155,7 +147,7 @@
 void RuntimeProfiler::OptimizeNow() {
   HandleScope scope(isolate_);
 
-  if (isolate_->DebuggerHasBreakPoints()) return;
+  if (!isolate_->use_crankshaft() || isolate_->DebuggerHasBreakPoints()) return;
 
   DisallowHeapAllocation no_gc;
 
@@ -236,7 +228,7 @@
 
     if (ticks >= kProfilerTicksBeforeOptimization) {
       int typeinfo, generic, total, type_percentage, generic_percentage;
-      GetICCounts(shared_code, &typeinfo, &generic, &total, &type_percentage,
+      GetICCounts(shared, &typeinfo, &generic, &total, &type_percentage,
                   &generic_percentage);
       if (type_percentage >= FLAG_type_info_threshold &&
           generic_percentage <= FLAG_generic_ic_threshold) {
@@ -259,7 +251,7 @@
       // If no IC was patched since the last tick and this function is very
       // small, optimistically optimize it now.
       int typeinfo, generic, total, type_percentage, generic_percentage;
-      GetICCounts(shared_code, &typeinfo, &generic, &total, &type_percentage,
+      GetICCounts(shared, &typeinfo, &generic, &total, &type_percentage,
                   &generic_percentage);
       if (type_percentage >= FLAG_type_info_threshold &&
           generic_percentage <= FLAG_generic_ic_threshold) {
diff --git a/src/runtime.cc b/src/runtime.cc
deleted file mode 100644
index cfef8c2..0000000
--- a/src/runtime.cc
+++ /dev/null
@@ -1,15771 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stdlib.h>
-#include <limits>
-
-#include "src/v8.h"
-
-#include "src/accessors.h"
-#include "src/allocation-site-scopes.h"
-#include "src/api.h"
-#include "src/arguments.h"
-#include "src/bailout-reason.h"
-#include "src/base/cpu.h"
-#include "src/base/platform/platform.h"
-#include "src/bootstrapper.h"
-#include "src/codegen.h"
-#include "src/compilation-cache.h"
-#include "src/compiler.h"
-#include "src/conversions.h"
-#include "src/cpu-profiler.h"
-#include "src/date.h"
-#include "src/dateparser-inl.h"
-#include "src/debug.h"
-#include "src/deoptimizer.h"
-#include "src/execution.h"
-#include "src/full-codegen.h"
-#include "src/global-handles.h"
-#include "src/isolate-inl.h"
-#include "src/json-parser.h"
-#include "src/json-stringifier.h"
-#include "src/jsregexp-inl.h"
-#include "src/jsregexp.h"
-#include "src/liveedit.h"
-#include "src/misc-intrinsics.h"
-#include "src/parser.h"
-#include "src/prototype.h"
-#include "src/runtime.h"
-#include "src/runtime-profiler.h"
-#include "src/scopeinfo.h"
-#include "src/smart-pointers.h"
-#include "src/string-search.h"
-#include "src/uri.h"
-#include "src/utils.h"
-#include "src/v8threads.h"
-#include "src/vm-state-inl.h"
-#include "third_party/fdlibm/fdlibm.h"
-
-#ifdef V8_I18N_SUPPORT
-#include "src/i18n.h"
-#include "unicode/brkiter.h"
-#include "unicode/calendar.h"
-#include "unicode/coll.h"
-#include "unicode/curramt.h"
-#include "unicode/datefmt.h"
-#include "unicode/dcfmtsym.h"
-#include "unicode/decimfmt.h"
-#include "unicode/dtfmtsym.h"
-#include "unicode/dtptngen.h"
-#include "unicode/locid.h"
-#include "unicode/numfmt.h"
-#include "unicode/numsys.h"
-#include "unicode/rbbi.h"
-#include "unicode/smpdtfmt.h"
-#include "unicode/timezone.h"
-#include "unicode/uchar.h"
-#include "unicode/ucol.h"
-#include "unicode/ucurr.h"
-#include "unicode/uloc.h"
-#include "unicode/unum.h"
-#include "unicode/uversion.h"
-#endif
-
-#ifndef _STLP_VENDOR_CSTD
-// STLPort doesn't import fpclassify and isless into the std namespace.
-using std::fpclassify;
-using std::isless;
-#endif
-
-namespace v8 {
-namespace internal {
-
-
-#define RUNTIME_ASSERT(value) \
-  if (!(value)) return isolate->ThrowIllegalOperation();
-
-#define RUNTIME_ASSERT_HANDLIFIED(value, T)                          \
-  if (!(value)) {                                                    \
-    isolate->ThrowIllegalOperation();                                \
-    return MaybeHandle<T>();                                         \
-  }
-
-// Cast the given object to a value of the specified type and store
-// it in a variable with the given name.  If the object is not of the
-// expected type call IllegalOperation and return.
-#define CONVERT_ARG_CHECKED(Type, name, index)                       \
-  RUNTIME_ASSERT(args[index]->Is##Type());                           \
-  Type* name = Type::cast(args[index]);
-
-#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index)                \
-  RUNTIME_ASSERT(args[index]->Is##Type());                           \
-  Handle<Type> name = args.at<Type>(index);
-
-#define CONVERT_NUMBER_ARG_HANDLE_CHECKED(name, index)               \
-  RUNTIME_ASSERT(args[index]->IsNumber());                           \
-  Handle<Object> name = args.at<Object>(index);
-
-// Cast the given object to a boolean and store it in a variable with
-// the given name.  If the object is not a boolean call IllegalOperation
-// and return.
-#define CONVERT_BOOLEAN_ARG_CHECKED(name, index)                     \
-  RUNTIME_ASSERT(args[index]->IsBoolean());                          \
-  bool name = args[index]->IsTrue();
-
-// Cast the given argument to a Smi and store its value in an int variable
-// with the given name.  If the argument is not a Smi call IllegalOperation
-// and return.
-#define CONVERT_SMI_ARG_CHECKED(name, index)                         \
-  RUNTIME_ASSERT(args[index]->IsSmi());                              \
-  int name = args.smi_at(index);
-
-// Cast the given argument to a double and store it in a variable with
-// the given name.  If the argument is not a number (as opposed to
-// the number not-a-number) call IllegalOperation and return.
-#define CONVERT_DOUBLE_ARG_CHECKED(name, index)                      \
-  RUNTIME_ASSERT(args[index]->IsNumber());                           \
-  double name = args.number_at(index);
-
-// Call the specified converter on the object *comand store the result in
-// a variable of the specified type with the given name.  If the
-// object is not a Number call IllegalOperation and return.
-#define CONVERT_NUMBER_CHECKED(type, name, Type, obj)                \
-  RUNTIME_ASSERT(obj->IsNumber());                                   \
-  type name = NumberTo##Type(obj);
-
-
-// Cast the given argument to PropertyDetails and store its value in a
-// variable with the given name.  If the argument is not a Smi call
-// IllegalOperation and return.
-#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index)                \
-  RUNTIME_ASSERT(args[index]->IsSmi());                              \
-  PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
-
-
-// Assert that the given argument has a valid value for a StrictMode
-// and store it in a StrictMode variable with the given name.
-#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index)                 \
-  RUNTIME_ASSERT(args[index]->IsSmi());                              \
-  RUNTIME_ASSERT(args.smi_at(index) == STRICT ||                     \
-                 args.smi_at(index) == SLOPPY);                      \
-  StrictMode name = static_cast<StrictMode>(args.smi_at(index));
-
-
-// Assert that the given argument is a number within the Int32 range
-// and convert it to int32_t.  If the argument is not an Int32 call
-// IllegalOperation and return.
-#define CONVERT_INT32_ARG_CHECKED(name, index)                       \
-  RUNTIME_ASSERT(args[index]->IsNumber());                           \
-  int32_t name = 0;                                                  \
-  RUNTIME_ASSERT(args[index]->ToInt32(&name));
-
-
-static Handle<Map> ComputeObjectLiteralMap(
-    Handle<Context> context,
-    Handle<FixedArray> constant_properties,
-    bool* is_result_from_cache) {
-  Isolate* isolate = context->GetIsolate();
-  int properties_length = constant_properties->length();
-  int number_of_properties = properties_length / 2;
-  // Check that there are only internal strings and array indices among keys.
-  int number_of_string_keys = 0;
-  for (int p = 0; p != properties_length; p += 2) {
-    Object* key = constant_properties->get(p);
-    uint32_t element_index = 0;
-    if (key->IsInternalizedString()) {
-      number_of_string_keys++;
-    } else if (key->ToArrayIndex(&element_index)) {
-      // An index key does not require space in the property backing store.
-      number_of_properties--;
-    } else {
-      // Bail out as a non-internalized-string non-index key makes caching
-      // impossible.
-      // DCHECK to make sure that the if condition after the loop is false.
-      DCHECK(number_of_string_keys != number_of_properties);
-      break;
-    }
-  }
-  // If we only have internalized strings and array indices among keys then we
-  // can use the map cache in the native context.
-  const int kMaxKeys = 10;
-  if ((number_of_string_keys == number_of_properties) &&
-      (number_of_string_keys < kMaxKeys)) {
-    // Create the fixed array with the key.
-    Handle<FixedArray> keys =
-        isolate->factory()->NewFixedArray(number_of_string_keys);
-    if (number_of_string_keys > 0) {
-      int index = 0;
-      for (int p = 0; p < properties_length; p += 2) {
-        Object* key = constant_properties->get(p);
-        if (key->IsInternalizedString()) {
-          keys->set(index++, key);
-        }
-      }
-      DCHECK(index == number_of_string_keys);
-    }
-    *is_result_from_cache = true;
-    return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
-  }
-  *is_result_from_cache = false;
-  return Map::Create(isolate, number_of_properties);
-}
-
-
-MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate(
-    Isolate* isolate,
-    Handle<FixedArray> literals,
-    Handle<FixedArray> constant_properties);
-
-
-MUST_USE_RESULT static MaybeHandle<Object> CreateObjectLiteralBoilerplate(
-    Isolate* isolate,
-    Handle<FixedArray> literals,
-    Handle<FixedArray> constant_properties,
-    bool should_have_fast_elements,
-    bool has_function_literal) {
-  // Get the native context from the literals array.  This is the
-  // context in which the function was created and we use the object
-  // function from this context to create the object literal.  We do
-  // not use the object function from the current native context
-  // because this might be the object function from another context
-  // which we should not have access to.
-  Handle<Context> context =
-      Handle<Context>(JSFunction::NativeContextFromLiterals(*literals));
-
-  // In case we have function literals, we want the object to be in
-  // slow properties mode for now. We don't go in the map cache because
-  // maps with constant functions can't be shared if the functions are
-  // not the same (which is the common case).
-  bool is_result_from_cache = false;
-  Handle<Map> map = has_function_literal
-      ? Handle<Map>(context->object_function()->initial_map())
-      : ComputeObjectLiteralMap(context,
-                                constant_properties,
-                                &is_result_from_cache);
-
-  PretenureFlag pretenure_flag =
-      isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
-
-  Handle<JSObject> boilerplate =
-      isolate->factory()->NewJSObjectFromMap(map, pretenure_flag);
-
-  // Normalize the elements of the boilerplate to save space if needed.
-  if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
-
-  // Add the constant properties to the boilerplate.
-  int length = constant_properties->length();
-  bool should_transform =
-      !is_result_from_cache && boilerplate->HasFastProperties();
-  bool should_normalize = should_transform || has_function_literal;
-  if (should_normalize) {
-    // TODO(verwaest): We might not want to ever normalize here.
-    JSObject::NormalizeProperties(
-        boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
-  }
-  // TODO(verwaest): Support tracking representations in the boilerplate.
-  for (int index = 0; index < length; index +=2) {
-    Handle<Object> key(constant_properties->get(index+0), isolate);
-    Handle<Object> value(constant_properties->get(index+1), isolate);
-    if (value->IsFixedArray()) {
-      // The value contains the constant_properties of a
-      // simple object or array literal.
-      Handle<FixedArray> array = Handle<FixedArray>::cast(value);
-      ASSIGN_RETURN_ON_EXCEPTION(
-          isolate, value,
-          CreateLiteralBoilerplate(isolate, literals, array),
-          Object);
-    }
-    MaybeHandle<Object> maybe_result;
-    uint32_t element_index = 0;
-    if (key->IsInternalizedString()) {
-      if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
-        // Array index as string (uint32).
-        if (value->IsUninitialized()) value = handle(Smi::FromInt(0), isolate);
-        maybe_result =
-            JSObject::SetOwnElement(boilerplate, element_index, value, SLOPPY);
-      } else {
-        Handle<String> name(String::cast(*key));
-        DCHECK(!name->AsArrayIndex(&element_index));
-        maybe_result = JSObject::SetOwnPropertyIgnoreAttributes(
-            boilerplate, name, value, NONE);
-      }
-    } else if (key->ToArrayIndex(&element_index)) {
-      // Array index (uint32).
-      if (value->IsUninitialized()) value = handle(Smi::FromInt(0), isolate);
-      maybe_result =
-          JSObject::SetOwnElement(boilerplate, element_index, value, SLOPPY);
-    } else {
-      // Non-uint32 number.
-      DCHECK(key->IsNumber());
-      double num = key->Number();
-      char arr[100];
-      Vector<char> buffer(arr, arraysize(arr));
-      const char* str = DoubleToCString(num, buffer);
-      Handle<String> name = isolate->factory()->NewStringFromAsciiChecked(str);
-      maybe_result = JSObject::SetOwnPropertyIgnoreAttributes(boilerplate, name,
-                                                              value, NONE);
-    }
-    // If setting the property on the boilerplate throws an
-    // exception, the exception is converted to an empty handle in
-    // the handle based operations.  In that case, we need to
-    // convert back to an exception.
-    RETURN_ON_EXCEPTION(isolate, maybe_result, Object);
-  }
-
-  // Transform to fast properties if necessary. For object literals with
-  // containing function literals we defer this operation until after all
-  // computed properties have been assigned so that we can generate
-  // constant function properties.
-  if (should_transform && !has_function_literal) {
-    JSObject::MigrateSlowToFast(
-        boilerplate, boilerplate->map()->unused_property_fields());
-  }
-
-  return boilerplate;
-}
-
-
-MUST_USE_RESULT static MaybeHandle<Object> TransitionElements(
-    Handle<Object> object,
-    ElementsKind to_kind,
-    Isolate* isolate) {
-  HandleScope scope(isolate);
-  if (!object->IsJSObject()) {
-    isolate->ThrowIllegalOperation();
-    return MaybeHandle<Object>();
-  }
-  ElementsKind from_kind =
-      Handle<JSObject>::cast(object)->map()->elements_kind();
-  if (Map::IsValidElementsTransition(from_kind, to_kind)) {
-    JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
-    return object;
-  }
-  isolate->ThrowIllegalOperation();
-  return MaybeHandle<Object>();
-}
-
-
-MaybeHandle<Object> Runtime::CreateArrayLiteralBoilerplate(
-    Isolate* isolate,
-    Handle<FixedArray> literals,
-    Handle<FixedArray> elements) {
-  // Create the JSArray.
-  Handle<JSFunction> constructor(
-      JSFunction::NativeContextFromLiterals(*literals)->array_function());
-
-  PretenureFlag pretenure_flag =
-      isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
-
-  Handle<JSArray> object = Handle<JSArray>::cast(
-      isolate->factory()->NewJSObject(constructor, pretenure_flag));
-
-  ElementsKind constant_elements_kind =
-      static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
-  Handle<FixedArrayBase> constant_elements_values(
-      FixedArrayBase::cast(elements->get(1)));
-
-  { DisallowHeapAllocation no_gc;
-    DCHECK(IsFastElementsKind(constant_elements_kind));
-    Context* native_context = isolate->context()->native_context();
-    Object* maps_array = native_context->js_array_maps();
-    DCHECK(!maps_array->IsUndefined());
-    Object* map = FixedArray::cast(maps_array)->get(constant_elements_kind);
-    object->set_map(Map::cast(map));
-  }
-
-  Handle<FixedArrayBase> copied_elements_values;
-  if (IsFastDoubleElementsKind(constant_elements_kind)) {
-    copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
-        Handle<FixedDoubleArray>::cast(constant_elements_values));
-  } else {
-    DCHECK(IsFastSmiOrObjectElementsKind(constant_elements_kind));
-    const bool is_cow =
-        (constant_elements_values->map() ==
-         isolate->heap()->fixed_cow_array_map());
-    if (is_cow) {
-      copied_elements_values = constant_elements_values;
-#if DEBUG
-      Handle<FixedArray> fixed_array_values =
-          Handle<FixedArray>::cast(copied_elements_values);
-      for (int i = 0; i < fixed_array_values->length(); i++) {
-        DCHECK(!fixed_array_values->get(i)->IsFixedArray());
-      }
-#endif
-    } else {
-      Handle<FixedArray> fixed_array_values =
-          Handle<FixedArray>::cast(constant_elements_values);
-      Handle<FixedArray> fixed_array_values_copy =
-          isolate->factory()->CopyFixedArray(fixed_array_values);
-      copied_elements_values = fixed_array_values_copy;
-      for (int i = 0; i < fixed_array_values->length(); i++) {
-        if (fixed_array_values->get(i)->IsFixedArray()) {
-          // The value contains the constant_properties of a
-          // simple object or array literal.
-          Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
-          Handle<Object> result;
-          ASSIGN_RETURN_ON_EXCEPTION(
-              isolate, result,
-              CreateLiteralBoilerplate(isolate, literals, fa),
-              Object);
-          fixed_array_values_copy->set(i, *result);
-        }
-      }
-    }
-  }
-  object->set_elements(*copied_elements_values);
-  object->set_length(Smi::FromInt(copied_elements_values->length()));
-
-  JSObject::ValidateElements(object);
-  return object;
-}
-
-
-MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate(
-    Isolate* isolate,
-    Handle<FixedArray> literals,
-    Handle<FixedArray> array) {
-  Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
-  const bool kHasNoFunctionLiteral = false;
-  switch (CompileTimeValue::GetLiteralType(array)) {
-    case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
-      return CreateObjectLiteralBoilerplate(isolate,
-                                            literals,
-                                            elements,
-                                            true,
-                                            kHasNoFunctionLiteral);
-    case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
-      return CreateObjectLiteralBoilerplate(isolate,
-                                            literals,
-                                            elements,
-                                            false,
-                                            kHasNoFunctionLiteral);
-    case CompileTimeValue::ARRAY_LITERAL:
-      return Runtime::CreateArrayLiteralBoilerplate(
-          isolate, literals, elements);
-    default:
-      UNREACHABLE();
-      return MaybeHandle<Object>();
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-  CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
-  CONVERT_SMI_ARG_CHECKED(literals_index, 1);
-  CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
-  CONVERT_SMI_ARG_CHECKED(flags, 3);
-  bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
-  bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
-
-  RUNTIME_ASSERT(literals_index >= 0 && literals_index < literals->length());
-
-  // Check if boilerplate exists. If not, create it first.
-  Handle<Object> literal_site(literals->get(literals_index), isolate);
-  Handle<AllocationSite> site;
-  Handle<JSObject> boilerplate;
-  if (*literal_site == isolate->heap()->undefined_value()) {
-    Handle<Object> raw_boilerplate;
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, raw_boilerplate,
-        CreateObjectLiteralBoilerplate(
-            isolate,
-            literals,
-            constant_properties,
-            should_have_fast_elements,
-            has_function_literal));
-    boilerplate = Handle<JSObject>::cast(raw_boilerplate);
-
-    AllocationSiteCreationContext creation_context(isolate);
-    site = creation_context.EnterNewScope();
-    RETURN_FAILURE_ON_EXCEPTION(
-        isolate,
-        JSObject::DeepWalk(boilerplate, &creation_context));
-    creation_context.ExitScope(site, boilerplate);
-
-    // Update the functions literal and return the boilerplate.
-    literals->set(literals_index, *site);
-  } else {
-    site = Handle<AllocationSite>::cast(literal_site);
-    boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
-                                   isolate);
-  }
-
-  AllocationSiteUsageContext usage_context(isolate, site, true);
-  usage_context.EnterNewScope();
-  MaybeHandle<Object> maybe_copy = JSObject::DeepCopy(
-      boilerplate, &usage_context);
-  usage_context.ExitScope(site, boilerplate);
-  Handle<Object> copy;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, copy, maybe_copy);
-  return *copy;
-}
-
-
-MUST_USE_RESULT static MaybeHandle<AllocationSite> GetLiteralAllocationSite(
-    Isolate* isolate,
-    Handle<FixedArray> literals,
-    int literals_index,
-    Handle<FixedArray> elements) {
-  // Check if boilerplate exists. If not, create it first.
-  Handle<Object> literal_site(literals->get(literals_index), isolate);
-  Handle<AllocationSite> site;
-  if (*literal_site == isolate->heap()->undefined_value()) {
-    DCHECK(*elements != isolate->heap()->empty_fixed_array());
-    Handle<Object> boilerplate;
-    ASSIGN_RETURN_ON_EXCEPTION(
-        isolate, boilerplate,
-        Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements),
-        AllocationSite);
-
-    AllocationSiteCreationContext creation_context(isolate);
-    site = creation_context.EnterNewScope();
-    if (JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate),
-                           &creation_context).is_null()) {
-      return Handle<AllocationSite>::null();
-    }
-    creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate));
-
-    literals->set(literals_index, *site);
-  } else {
-    site = Handle<AllocationSite>::cast(literal_site);
-  }
-
-  return site;
-}
-
-
-static MaybeHandle<JSObject> CreateArrayLiteralImpl(Isolate* isolate,
-                                           Handle<FixedArray> literals,
-                                           int literals_index,
-                                           Handle<FixedArray> elements,
-                                           int flags) {
-  RUNTIME_ASSERT_HANDLIFIED(literals_index >= 0 &&
-                            literals_index < literals->length(), JSObject);
-  Handle<AllocationSite> site;
-  ASSIGN_RETURN_ON_EXCEPTION(
-      isolate, site,
-      GetLiteralAllocationSite(isolate, literals, literals_index, elements),
-      JSObject);
-
-  bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0;
-  Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
-  AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
-  usage_context.EnterNewScope();
-  JSObject::DeepCopyHints hints = (flags & ArrayLiteral::kShallowElements) == 0
-                                      ? JSObject::kNoHints
-                                      : JSObject::kObjectIsShallow;
-  MaybeHandle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context,
-                                                  hints);
-  usage_context.ExitScope(site, boilerplate);
-  return copy;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreateArrayLiteral) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-  CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
-  CONVERT_SMI_ARG_CHECKED(literals_index, 1);
-  CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
-  CONVERT_SMI_ARG_CHECKED(flags, 3);
-
-  Handle<JSObject> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
-      CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
-                             flags));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreateArrayLiteralStubBailout) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
-  CONVERT_SMI_ARG_CHECKED(literals_index, 1);
-  CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
-
-  Handle<JSObject> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
-     CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
-                            ArrayLiteral::kShallowElements));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreateSymbol) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
-  RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
-  Handle<Symbol> symbol = isolate->factory()->NewSymbol();
-  if (name->IsString()) symbol->set_name(*name);
-  return *symbol;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreatePrivateSymbol) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
-  RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
-  Handle<Symbol> symbol = isolate->factory()->NewPrivateSymbol();
-  if (name->IsString()) symbol->set_name(*name);
-  return *symbol;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreatePrivateOwnSymbol) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
-  RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
-  Handle<Symbol> symbol = isolate->factory()->NewPrivateOwnSymbol();
-  if (name->IsString()) symbol->set_name(*name);
-  return *symbol;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreateGlobalPrivateOwnSymbol) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
-  Handle<JSObject> registry = isolate->GetSymbolRegistry();
-  Handle<String> part = isolate->factory()->private_intern_string();
-  Handle<Object> privates;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, privates, Object::GetPropertyOrElement(registry, part));
-  Handle<Object> symbol;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, symbol, Object::GetPropertyOrElement(privates, name));
-  if (!symbol->IsSymbol()) {
-    DCHECK(symbol->IsUndefined());
-    symbol = isolate->factory()->NewPrivateSymbol();
-    Handle<Symbol>::cast(symbol)->set_name(*name);
-    Handle<Symbol>::cast(symbol)->set_is_own(true);
-    JSObject::SetProperty(Handle<JSObject>::cast(privates), name, symbol,
-                          STRICT).Assert();
-  }
-  return *symbol;
-}
-
-
-RUNTIME_FUNCTION(Runtime_NewSymbolWrapper) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Symbol, symbol, 0);
-  return *Object::ToObject(isolate, symbol).ToHandleChecked();
-}
-
-
-RUNTIME_FUNCTION(Runtime_SymbolDescription) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Symbol, symbol, 0);
-  return symbol->name();
-}
-
-
-RUNTIME_FUNCTION(Runtime_SymbolRegistry) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-  return *isolate->GetSymbolRegistry();
-}
-
-
-RUNTIME_FUNCTION(Runtime_SymbolIsPrivate) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Symbol, symbol, 0);
-  return isolate->heap()->ToBoolean(symbol->is_private());
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreateJSProxy) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
-  if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value();
-  return *isolate->factory()->NewJSProxy(handler, prototype);
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreateJSFunctionProxy) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, call_trap, 1);
-  RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy());
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, construct_trap, 2);
-  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 3);
-  if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value();
-  return *isolate->factory()->NewJSFunctionProxy(
-      handler, call_trap, construct_trap, prototype);
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsJSProxy) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
-  return isolate->heap()->ToBoolean(obj->IsJSProxy());
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsJSFunctionProxy) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
-  return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetHandler) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
-  return proxy->handler();
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetCallTrap) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
-  return proxy->call_trap();
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetConstructTrap) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
-  return proxy->construct_trap();
-}
-
-
-RUNTIME_FUNCTION(Runtime_Fix) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0);
-  JSProxy::Fix(proxy);
-  return isolate->heap()->undefined_value();
-}
-
-
-void Runtime::FreeArrayBuffer(Isolate* isolate,
-                              JSArrayBuffer* phantom_array_buffer) {
-  if (phantom_array_buffer->should_be_freed()) {
-    DCHECK(phantom_array_buffer->is_external());
-    free(phantom_array_buffer->backing_store());
-  }
-  if (phantom_array_buffer->is_external()) return;
-
-  size_t allocated_length = NumberToSize(
-      isolate, phantom_array_buffer->byte_length());
-
-  reinterpret_cast<v8::Isolate*>(isolate)
-      ->AdjustAmountOfExternalAllocatedMemory(
-          -static_cast<int64_t>(allocated_length));
-  CHECK(V8::ArrayBufferAllocator() != NULL);
-  V8::ArrayBufferAllocator()->Free(
-      phantom_array_buffer->backing_store(),
-      allocated_length);
-}
-
-
-void Runtime::SetupArrayBuffer(Isolate* isolate,
-                               Handle<JSArrayBuffer> array_buffer,
-                               bool is_external,
-                               void* data,
-                               size_t allocated_length) {
-  DCHECK(array_buffer->GetInternalFieldCount() ==
-      v8::ArrayBuffer::kInternalFieldCount);
-  for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
-    array_buffer->SetInternalField(i, Smi::FromInt(0));
-  }
-  array_buffer->set_backing_store(data);
-  array_buffer->set_flag(Smi::FromInt(0));
-  array_buffer->set_is_external(is_external);
-
-  Handle<Object> byte_length =
-      isolate->factory()->NewNumberFromSize(allocated_length);
-  CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
-  array_buffer->set_byte_length(*byte_length);
-
-  array_buffer->set_weak_next(isolate->heap()->array_buffers_list());
-  isolate->heap()->set_array_buffers_list(*array_buffer);
-  array_buffer->set_weak_first_view(isolate->heap()->undefined_value());
-}
-
-
-bool Runtime::SetupArrayBufferAllocatingData(
-    Isolate* isolate,
-    Handle<JSArrayBuffer> array_buffer,
-    size_t allocated_length,
-    bool initialize) {
-  void* data;
-  CHECK(V8::ArrayBufferAllocator() != NULL);
-  if (allocated_length != 0) {
-    if (initialize) {
-      data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
-    } else {
-      data =
-          V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length);
-    }
-    if (data == NULL) return false;
-  } else {
-    data = NULL;
-  }
-
-  SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length);
-
-  reinterpret_cast<v8::Isolate*>(isolate)
-      ->AdjustAmountOfExternalAllocatedMemory(allocated_length);
-
-  return true;
-}
-
-
-void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) {
-  Isolate* isolate = array_buffer->GetIsolate();
-  for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate);
-       !view_obj->IsUndefined();) {
-    Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj));
-    if (view->IsJSTypedArray()) {
-      JSTypedArray::cast(*view)->Neuter();
-    } else if (view->IsJSDataView()) {
-      JSDataView::cast(*view)->Neuter();
-    } else {
-      UNREACHABLE();
-    }
-    view_obj = handle(view->weak_next(), isolate);
-  }
-  array_buffer->Neuter();
-}
-
-
-RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
-  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1);
-  if (!holder->byte_length()->IsUndefined()) {
-    // ArrayBuffer is already initialized; probably a fuzz test.
-    return *holder;
-  }
-  size_t allocated_length = 0;
-  if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) {
-    THROW_NEW_ERROR_RETURN_FAILURE(
-        isolate, NewRangeError("invalid_array_buffer_length",
-                               HandleVector<Object>(NULL, 0)));
-  }
-  if (!Runtime::SetupArrayBufferAllocatingData(isolate,
-                                               holder, allocated_length)) {
-    THROW_NEW_ERROR_RETURN_FAILURE(
-        isolate, NewRangeError("invalid_array_buffer_length",
-                               HandleVector<Object>(NULL, 0)));
-  }
-  return *holder;
-}
-
-
-RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
-  return holder->byte_length();
-}
-
-
-RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
-  CONVERT_NUMBER_ARG_HANDLE_CHECKED(first, 2);
-  RUNTIME_ASSERT(!source.is_identical_to(target));
-  size_t start = 0;
-  RUNTIME_ASSERT(TryNumberToSize(isolate, *first, &start));
-  size_t target_length = NumberToSize(isolate, target->byte_length());
-
-  if (target_length == 0) return isolate->heap()->undefined_value();
-
-  size_t source_byte_length = NumberToSize(isolate, source->byte_length());
-  RUNTIME_ASSERT(start <= source_byte_length);
-  RUNTIME_ASSERT(source_byte_length - start >= target_length);
-  uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
-  uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
-  CopyBytes(target_data, source_data + start, target_length);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_ArrayBufferIsView) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, object, 0);
-  return isolate->heap()->ToBoolean(object->IsJSArrayBufferView());
-}
-
-
-RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0);
-  if (array_buffer->backing_store() == NULL) {
-    CHECK(Smi::FromInt(0) == array_buffer->byte_length());
-    return isolate->heap()->undefined_value();
-  }
-  DCHECK(!array_buffer->is_external());
-  void* backing_store = array_buffer->backing_store();
-  size_t byte_length = NumberToSize(isolate, array_buffer->byte_length());
-  array_buffer->set_is_external(true);
-  Runtime::NeuterArrayBuffer(array_buffer);
-  V8::ArrayBufferAllocator()->Free(backing_store, byte_length);
-  return isolate->heap()->undefined_value();
-}
-
-
-void Runtime::ArrayIdToTypeAndSize(
-    int arrayId,
-    ExternalArrayType* array_type,
-    ElementsKind* external_elements_kind,
-    ElementsKind* fixed_elements_kind,
-    size_t* element_size) {
-  switch (arrayId) {
-#define ARRAY_ID_CASE(Type, type, TYPE, ctype, size)                           \
-    case ARRAY_ID_##TYPE:                                                      \
-      *array_type = kExternal##Type##Array;                                    \
-      *external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS;                    \
-      *fixed_elements_kind = TYPE##_ELEMENTS;                                  \
-      *element_size = size;                                                    \
-      break;
-
-    TYPED_ARRAYS(ARRAY_ID_CASE)
-#undef ARRAY_ID_CASE
-
-    default:
-      UNREACHABLE();
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 5);
-  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
-  CONVERT_SMI_ARG_CHECKED(arrayId, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2);
-  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3);
-  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4);
-
-  RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
-                 arrayId <= Runtime::ARRAY_ID_LAST);
-
-  ExternalArrayType array_type = kExternalInt8Array;  // Bogus initialization.
-  size_t element_size = 1;  // Bogus initialization.
-  ElementsKind external_elements_kind =
-      EXTERNAL_INT8_ELEMENTS;  // Bogus initialization.
-  ElementsKind fixed_elements_kind = INT8_ELEMENTS;  // Bogus initialization.
-  Runtime::ArrayIdToTypeAndSize(arrayId,
-      &array_type,
-      &external_elements_kind,
-      &fixed_elements_kind,
-      &element_size);
-  RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
-
-  size_t byte_offset = 0;
-  size_t byte_length = 0;
-  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset_object, &byte_offset));
-  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length_object, &byte_length));
-
-  if (maybe_buffer->IsJSArrayBuffer()) {
-    Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
-    size_t array_buffer_byte_length =
-        NumberToSize(isolate, buffer->byte_length());
-    RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length);
-    RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length);
-  } else {
-    RUNTIME_ASSERT(maybe_buffer->IsNull());
-  }
-
-  RUNTIME_ASSERT(byte_length % element_size == 0);
-  size_t length = byte_length / element_size;
-
-  if (length > static_cast<unsigned>(Smi::kMaxValue)) {
-    THROW_NEW_ERROR_RETURN_FAILURE(
-        isolate, NewRangeError("invalid_typed_array_length",
-                               HandleVector<Object>(NULL, 0)));
-  }
-
-  // All checks are done, now we can modify objects.
-
-  DCHECK(holder->GetInternalFieldCount() ==
-      v8::ArrayBufferView::kInternalFieldCount);
-  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
-    holder->SetInternalField(i, Smi::FromInt(0));
-  }
-  Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
-  holder->set_length(*length_obj);
-  holder->set_byte_offset(*byte_offset_object);
-  holder->set_byte_length(*byte_length_object);
-
-  if (!maybe_buffer->IsNull()) {
-    Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
-    holder->set_buffer(*buffer);
-    holder->set_weak_next(buffer->weak_first_view());
-    buffer->set_weak_first_view(*holder);
-
-    Handle<ExternalArray> elements =
-        isolate->factory()->NewExternalArray(
-            static_cast<int>(length), array_type,
-            static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
-    Handle<Map> map =
-        JSObject::GetElementsTransitionMap(holder, external_elements_kind);
-    JSObject::SetMapAndElements(holder, map, elements);
-    DCHECK(IsExternalArrayElementsKind(holder->map()->elements_kind()));
-  } else {
-    holder->set_buffer(Smi::FromInt(0));
-    holder->set_weak_next(isolate->heap()->undefined_value());
-    Handle<FixedTypedArrayBase> elements =
-        isolate->factory()->NewFixedTypedArray(
-            static_cast<int>(length), array_type);
-    holder->set_elements(*elements);
-  }
-  return isolate->heap()->undefined_value();
-}
-
-
-// Initializes a typed array from an array-like object.
-// If an array-like object happens to be a typed array of the same type,
-// initializes backing store using memove.
-//
-// Returns true if backing store was initialized or false otherwise.
-RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
-  CONVERT_SMI_ARG_CHECKED(arrayId, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
-  CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3);
-
-  RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
-                 arrayId <= Runtime::ARRAY_ID_LAST);
-
-  ExternalArrayType array_type = kExternalInt8Array;  // Bogus initialization.
-  size_t element_size = 1;  // Bogus initialization.
-  ElementsKind external_elements_kind =
-      EXTERNAL_INT8_ELEMENTS;  // Bogus intialization.
-  ElementsKind fixed_elements_kind = INT8_ELEMENTS;  // Bogus initialization.
-  Runtime::ArrayIdToTypeAndSize(arrayId,
-      &array_type,
-      &external_elements_kind,
-      &fixed_elements_kind,
-      &element_size);
-
-  RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
-
-  Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
-  if (source->IsJSTypedArray() &&
-      JSTypedArray::cast(*source)->type() == array_type) {
-    length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate);
-  }
-  size_t length = 0;
-  RUNTIME_ASSERT(TryNumberToSize(isolate, *length_obj, &length));
-
-  if ((length > static_cast<unsigned>(Smi::kMaxValue)) ||
-      (length > (kMaxInt / element_size))) {
-    THROW_NEW_ERROR_RETURN_FAILURE(
-        isolate, NewRangeError("invalid_typed_array_length",
-                               HandleVector<Object>(NULL, 0)));
-  }
-  size_t byte_length = length * element_size;
-
-  DCHECK(holder->GetInternalFieldCount() ==
-      v8::ArrayBufferView::kInternalFieldCount);
-  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
-    holder->SetInternalField(i, Smi::FromInt(0));
-  }
-
-  // NOTE: not initializing backing store.
-  // We assume that the caller of this function will initialize holder
-  // with the loop
-  //      for(i = 0; i < length; i++) { holder[i] = source[i]; }
-  // We assume that the caller of this function is always a typed array
-  // constructor.
-  // If source is a typed array, this loop will always run to completion,
-  // so we are sure that the backing store will be initialized.
-  // Otherwise, the indexing operation might throw, so the loop will not
-  // run to completion and the typed array might remain partly initialized.
-  // However we further assume that the caller of this function is a typed array
-  // constructor, and the exception will propagate out of the constructor,
-  // therefore uninitialized memory will not be accessible by a user program.
-  //
-  // TODO(dslomov): revise this once we support subclassing.
-
-  if (!Runtime::SetupArrayBufferAllocatingData(
-        isolate, buffer, byte_length, false)) {
-    THROW_NEW_ERROR_RETURN_FAILURE(
-        isolate, NewRangeError("invalid_array_buffer_length",
-                               HandleVector<Object>(NULL, 0)));
-  }
-
-  holder->set_buffer(*buffer);
-  holder->set_byte_offset(Smi::FromInt(0));
-  Handle<Object> byte_length_obj(
-      isolate->factory()->NewNumberFromSize(byte_length));
-  holder->set_byte_length(*byte_length_obj);
-  holder->set_length(*length_obj);
-  holder->set_weak_next(buffer->weak_first_view());
-  buffer->set_weak_first_view(*holder);
-
-  Handle<ExternalArray> elements =
-      isolate->factory()->NewExternalArray(
-          static_cast<int>(length), array_type,
-          static_cast<uint8_t*>(buffer->backing_store()));
-  Handle<Map> map = JSObject::GetElementsTransitionMap(
-      holder, external_elements_kind);
-  JSObject::SetMapAndElements(holder, map, elements);
-
-  if (source->IsJSTypedArray()) {
-    Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
-
-    if (typed_array->type() == holder->type()) {
-      uint8_t* backing_store =
-        static_cast<uint8_t*>(
-          typed_array->GetBuffer()->backing_store());
-      size_t source_byte_offset =
-          NumberToSize(isolate, typed_array->byte_offset());
-      memcpy(
-          buffer->backing_store(),
-          backing_store + source_byte_offset,
-          byte_length);
-      return isolate->heap()->true_value();
-    }
-  }
-
-  return isolate->heap()->false_value();
-}
-
-
-#define BUFFER_VIEW_GETTER(Type, getter, accessor) \
-  RUNTIME_FUNCTION(Runtime_##Type##Get##getter) {                    \
-    HandleScope scope(isolate);                                               \
-    DCHECK(args.length() == 1);                                               \
-    CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0);                          \
-    return holder->accessor();                                                \
-  }
-
-BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length)
-BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset)
-BUFFER_VIEW_GETTER(TypedArray, Length, length)
-BUFFER_VIEW_GETTER(DataView, Buffer, buffer)
-
-#undef BUFFER_VIEW_GETTER
-
-RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
-  return *holder->GetBuffer();
-}
-
-
-// Return codes for Runtime_TypedArraySetFastCases.
-// Should be synchronized with typedarray.js natives.
-enum TypedArraySetResultCodes {
-  // Set from typed array of the same type.
-  // This is processed by TypedArraySetFastCases
-  TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
-  // Set from typed array of the different type, overlapping in memory.
-  TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
-  // Set from typed array of the different type, non-overlapping.
-  TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
-  // Set from non-typed array.
-  TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
-};
-
-
-RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  if (!args[0]->IsJSTypedArray()) {
-    THROW_NEW_ERROR_RETURN_FAILURE(
-        isolate,
-        NewTypeError("not_typed_array", HandleVector<Object>(NULL, 0)));
-  }
-
-  if (!args[1]->IsJSTypedArray())
-    return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1);
-  CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2);
-
-  Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
-  Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
-  size_t offset = 0;
-  RUNTIME_ASSERT(TryNumberToSize(isolate, *offset_obj, &offset));
-  size_t target_length = NumberToSize(isolate, target->length());
-  size_t source_length = NumberToSize(isolate, source->length());
-  size_t target_byte_length = NumberToSize(isolate, target->byte_length());
-  size_t source_byte_length = NumberToSize(isolate, source->byte_length());
-  if (offset > target_length || offset + source_length > target_length ||
-      offset + source_length < offset) {  // overflow
-    THROW_NEW_ERROR_RETURN_FAILURE(
-        isolate, NewRangeError("typed_array_set_source_too_large",
-                               HandleVector<Object>(NULL, 0)));
-  }
-
-  size_t target_offset = NumberToSize(isolate, target->byte_offset());
-  size_t source_offset = NumberToSize(isolate, source->byte_offset());
-  uint8_t* target_base =
-      static_cast<uint8_t*>(
-        target->GetBuffer()->backing_store()) + target_offset;
-  uint8_t* source_base =
-      static_cast<uint8_t*>(
-        source->GetBuffer()->backing_store()) + source_offset;
-
-  // Typed arrays of the same type: use memmove.
-  if (target->type() == source->type()) {
-    memmove(target_base + offset * target->element_size(),
-        source_base, source_byte_length);
-    return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
-  }
-
-  // Typed arrays of different types over the same backing store
-  if ((source_base <= target_base &&
-        source_base + source_byte_length > target_base) ||
-      (target_base <= source_base &&
-        target_base + target_byte_length > source_base)) {
-    // We do not support overlapping ArrayBuffers
-    DCHECK(
-      target->GetBuffer()->backing_store() ==
-      source->GetBuffer()->backing_store());
-    return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
-  } else {  // Non-overlapping typed arrays
-    return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) {
-  DCHECK(args.length() == 0);
-  DCHECK_OBJECT_SIZE(
-      FLAG_typed_array_max_size_in_heap + FixedTypedArrayBase::kDataOffset);
-  return Smi::FromInt(FLAG_typed_array_max_size_in_heap);
-}
-
-
-RUNTIME_FUNCTION(Runtime_DataViewInitialize) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-  CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1);
-  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2);
-  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3);
-
-  DCHECK(holder->GetInternalFieldCount() ==
-      v8::ArrayBufferView::kInternalFieldCount);
-  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
-    holder->SetInternalField(i, Smi::FromInt(0));
-  }
-  size_t buffer_length = 0;
-  size_t offset = 0;
-  size_t length = 0;
-  RUNTIME_ASSERT(
-      TryNumberToSize(isolate, buffer->byte_length(), &buffer_length));
-  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset));
-  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length));
-
-  // TODO(jkummerow): When we have a "safe numerics" helper class, use it here.
-  // Entire range [offset, offset + length] must be in bounds.
-  RUNTIME_ASSERT(offset <= buffer_length);
-  RUNTIME_ASSERT(offset + length <= buffer_length);
-  // No overflow.
-  RUNTIME_ASSERT(offset + length >= offset);
-
-  holder->set_buffer(*buffer);
-  holder->set_byte_offset(*byte_offset);
-  holder->set_byte_length(*byte_length);
-
-  holder->set_weak_next(buffer->weak_first_view());
-  buffer->set_weak_first_view(*holder);
-
-  return isolate->heap()->undefined_value();
-}
-
-
-inline static bool NeedToFlipBytes(bool is_little_endian) {
-#ifdef V8_TARGET_LITTLE_ENDIAN
-  return !is_little_endian;
-#else
-  return is_little_endian;
-#endif
-}
-
-
-template<int n>
-inline void CopyBytes(uint8_t* target, uint8_t* source) {
-  for (int i = 0; i < n; i++) {
-    *(target++) = *(source++);
-  }
-}
-
-
-template<int n>
-inline void FlipBytes(uint8_t* target, uint8_t* source) {
-  source = source + (n-1);
-  for (int i = 0; i < n; i++) {
-    *(target++) = *(source--);
-  }
-}
-
-
-template<typename T>
-inline static bool DataViewGetValue(
-    Isolate* isolate,
-    Handle<JSDataView> data_view,
-    Handle<Object> byte_offset_obj,
-    bool is_little_endian,
-    T* result) {
-  size_t byte_offset = 0;
-  if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
-    return false;
-  }
-  Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
-
-  size_t data_view_byte_offset =
-      NumberToSize(isolate, data_view->byte_offset());
-  size_t data_view_byte_length =
-      NumberToSize(isolate, data_view->byte_length());
-  if (byte_offset + sizeof(T) > data_view_byte_length ||
-      byte_offset + sizeof(T) < byte_offset)  {  // overflow
-    return false;
-  }
-
-  union Value {
-    T data;
-    uint8_t bytes[sizeof(T)];
-  };
-
-  Value value;
-  size_t buffer_offset = data_view_byte_offset + byte_offset;
-  DCHECK(
-      NumberToSize(isolate, buffer->byte_length())
-      >= buffer_offset + sizeof(T));
-  uint8_t* source =
-        static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
-  if (NeedToFlipBytes(is_little_endian)) {
-    FlipBytes<sizeof(T)>(value.bytes, source);
-  } else {
-    CopyBytes<sizeof(T)>(value.bytes, source);
-  }
-  *result = value.data;
-  return true;
-}
-
-
-template<typename T>
-static bool DataViewSetValue(
-    Isolate* isolate,
-    Handle<JSDataView> data_view,
-    Handle<Object> byte_offset_obj,
-    bool is_little_endian,
-    T data) {
-  size_t byte_offset = 0;
-  if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
-    return false;
-  }
-  Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
-
-  size_t data_view_byte_offset =
-      NumberToSize(isolate, data_view->byte_offset());
-  size_t data_view_byte_length =
-      NumberToSize(isolate, data_view->byte_length());
-  if (byte_offset + sizeof(T) > data_view_byte_length ||
-      byte_offset + sizeof(T) < byte_offset)  {  // overflow
-    return false;
-  }
-
-  union Value {
-    T data;
-    uint8_t bytes[sizeof(T)];
-  };
-
-  Value value;
-  value.data = data;
-  size_t buffer_offset = data_view_byte_offset + byte_offset;
-  DCHECK(
-      NumberToSize(isolate, buffer->byte_length())
-      >= buffer_offset + sizeof(T));
-  uint8_t* target =
-        static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
-  if (NeedToFlipBytes(is_little_endian)) {
-    FlipBytes<sizeof(T)>(target, value.bytes);
-  } else {
-    CopyBytes<sizeof(T)>(target, value.bytes);
-  }
-  return true;
-}
-
-
-#define DATA_VIEW_GETTER(TypeName, Type, Converter)                   \
-  RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) {                   \
-    HandleScope scope(isolate);                                       \
-    DCHECK(args.length() == 3);                                       \
-    CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);                \
-    CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1);                     \
-    CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2);                 \
-    Type result;                                                      \
-    if (DataViewGetValue(isolate, holder, offset, is_little_endian,   \
-                         &result)) {                                  \
-      return *isolate->factory()->Converter(result);                  \
-    } else {                                                          \
-      THROW_NEW_ERROR_RETURN_FAILURE(                                 \
-          isolate, NewRangeError("invalid_data_view_accessor_offset", \
-                                 HandleVector<Object>(NULL, 0)));     \
-    }                                                                 \
-  }
-
-DATA_VIEW_GETTER(Uint8, uint8_t, NewNumberFromUint)
-DATA_VIEW_GETTER(Int8, int8_t, NewNumberFromInt)
-DATA_VIEW_GETTER(Uint16, uint16_t, NewNumberFromUint)
-DATA_VIEW_GETTER(Int16, int16_t, NewNumberFromInt)
-DATA_VIEW_GETTER(Uint32, uint32_t, NewNumberFromUint)
-DATA_VIEW_GETTER(Int32, int32_t, NewNumberFromInt)
-DATA_VIEW_GETTER(Float32, float, NewNumber)
-DATA_VIEW_GETTER(Float64, double, NewNumber)
-
-#undef DATA_VIEW_GETTER
-
-
-template <typename T>
-static T DataViewConvertValue(double value);
-
-
-template <>
-int8_t DataViewConvertValue<int8_t>(double value) {
-  return static_cast<int8_t>(DoubleToInt32(value));
-}
-
-
-template <>
-int16_t DataViewConvertValue<int16_t>(double value) {
-  return static_cast<int16_t>(DoubleToInt32(value));
-}
-
-
-template <>
-int32_t DataViewConvertValue<int32_t>(double value) {
-  return DoubleToInt32(value);
-}
-
-
-template <>
-uint8_t DataViewConvertValue<uint8_t>(double value) {
-  return static_cast<uint8_t>(DoubleToUint32(value));
-}
-
-
-template <>
-uint16_t DataViewConvertValue<uint16_t>(double value) {
-  return static_cast<uint16_t>(DoubleToUint32(value));
-}
-
-
-template <>
-uint32_t DataViewConvertValue<uint32_t>(double value) {
-  return DoubleToUint32(value);
-}
-
-
-template <>
-float DataViewConvertValue<float>(double value) {
-  return static_cast<float>(value);
-}
-
-
-template <>
-double DataViewConvertValue<double>(double value) {
-  return value;
-}
-
-
-#define DATA_VIEW_SETTER(TypeName, Type)                                  \
-  RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) {                       \
-    HandleScope scope(isolate);                                           \
-    DCHECK(args.length() == 4);                                           \
-    CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);                    \
-    CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1);                         \
-    CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);                          \
-    CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3);                     \
-    Type v = DataViewConvertValue<Type>(value->Number());                 \
-    if (DataViewSetValue(isolate, holder, offset, is_little_endian, v)) { \
-      return isolate->heap()->undefined_value();                          \
-    } else {                                                              \
-      THROW_NEW_ERROR_RETURN_FAILURE(                                     \
-          isolate, NewRangeError("invalid_data_view_accessor_offset",     \
-                                 HandleVector<Object>(NULL, 0)));         \
-    }                                                                     \
-  }
-
-DATA_VIEW_SETTER(Uint8, uint8_t)
-DATA_VIEW_SETTER(Int8, int8_t)
-DATA_VIEW_SETTER(Uint16, uint16_t)
-DATA_VIEW_SETTER(Int16, int16_t)
-DATA_VIEW_SETTER(Uint32, uint32_t)
-DATA_VIEW_SETTER(Int32, int32_t)
-DATA_VIEW_SETTER(Float32, float)
-DATA_VIEW_SETTER(Float64, double)
-
-#undef DATA_VIEW_SETTER
-
-
-RUNTIME_FUNCTION(Runtime_SetInitialize) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
-  Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
-  holder->set_table(*table);
-  return *holder;
-}
-
-
-RUNTIME_FUNCTION(Runtime_SetAdd) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
-  table = OrderedHashSet::Add(table, key);
-  holder->set_table(*table);
-  return *holder;
-}
-
-
-RUNTIME_FUNCTION(Runtime_SetHas) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
-  return isolate->heap()->ToBoolean(table->Contains(key));
-}
-
-
-RUNTIME_FUNCTION(Runtime_SetDelete) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
-  bool was_present = false;
-  table = OrderedHashSet::Remove(table, key, &was_present);
-  holder->set_table(*table);
-  return isolate->heap()->ToBoolean(was_present);
-}
-
-
-RUNTIME_FUNCTION(Runtime_SetClear) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
-  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
-  table = OrderedHashSet::Clear(table);
-  holder->set_table(*table);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_SetGetSize) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
-  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
-  return Smi::FromInt(table->NumberOfElements());
-}
-
-
-RUNTIME_FUNCTION(Runtime_SetIteratorInitialize) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSSet, set, 1);
-  CONVERT_SMI_ARG_CHECKED(kind, 2)
-  RUNTIME_ASSERT(kind == JSSetIterator::kKindValues ||
-                 kind == JSSetIterator::kKindEntries);
-  Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
-  holder->set_table(*table);
-  holder->set_index(Smi::FromInt(0));
-  holder->set_kind(Smi::FromInt(kind));
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_SetIteratorNext) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_CHECKED(JSSetIterator, holder, 0);
-  CONVERT_ARG_CHECKED(JSArray, value_array, 1);
-  return holder->Next(value_array);
-}
-
-
-RUNTIME_FUNCTION(Runtime_MapInitialize) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
-  Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
-  holder->set_table(*table);
-  return *holder;
-}
-
-
-RUNTIME_FUNCTION(Runtime_MapGet) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
-  Handle<Object> lookup(table->Lookup(key), isolate);
-  return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
-}
-
-
-RUNTIME_FUNCTION(Runtime_MapHas) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
-  Handle<Object> lookup(table->Lookup(key), isolate);
-  return isolate->heap()->ToBoolean(!lookup->IsTheHole());
-}
-
-
-RUNTIME_FUNCTION(Runtime_MapDelete) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
-  bool was_present = false;
-  Handle<OrderedHashMap> new_table =
-      OrderedHashMap::Remove(table, key, &was_present);
-  holder->set_table(*new_table);
-  return isolate->heap()->ToBoolean(was_present);
-}
-
-
-RUNTIME_FUNCTION(Runtime_MapClear) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
-  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
-  table = OrderedHashMap::Clear(table);
-  holder->set_table(*table);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_MapSet) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
-  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
-  Handle<OrderedHashMap> new_table = OrderedHashMap::Put(table, key, value);
-  holder->set_table(*new_table);
-  return *holder;
-}
-
-
-RUNTIME_FUNCTION(Runtime_MapGetSize) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
-  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
-  return Smi::FromInt(table->NumberOfElements());
-}
-
-
-RUNTIME_FUNCTION(Runtime_MapIteratorInitialize) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSMap, map, 1);
-  CONVERT_SMI_ARG_CHECKED(kind, 2)
-  RUNTIME_ASSERT(kind == JSMapIterator::kKindKeys
-      || kind == JSMapIterator::kKindValues
-      || kind == JSMapIterator::kKindEntries);
-  Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
-  holder->set_table(*table);
-  holder->set_index(Smi::FromInt(0));
-  holder->set_kind(Smi::FromInt(kind));
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetWeakMapEntries) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
-  Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
-  Handle<FixedArray> entries =
-      isolate->factory()->NewFixedArray(table->NumberOfElements() * 2);
-  {
-    DisallowHeapAllocation no_gc;
-    int number_of_non_hole_elements = 0;
-    for (int i = 0; i < table->Capacity(); i++) {
-      Handle<Object> key(table->KeyAt(i), isolate);
-      if (table->IsKey(*key)) {
-        entries->set(number_of_non_hole_elements++, *key);
-        Object* value = table->Lookup(key);
-        entries->set(number_of_non_hole_elements++, value);
-      }
-    }
-    DCHECK_EQ(table->NumberOfElements() * 2, number_of_non_hole_elements);
-  }
-  return *isolate->factory()->NewJSArrayWithElements(entries);
-}
-
-
-RUNTIME_FUNCTION(Runtime_MapIteratorNext) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_CHECKED(JSMapIterator, holder, 0);
-  CONVERT_ARG_CHECKED(JSArray, value_array, 1);
-  return holder->Next(value_array);
-}
-
-
-static Handle<JSWeakCollection> WeakCollectionInitialize(
-    Isolate* isolate,
-    Handle<JSWeakCollection> weak_collection) {
-  DCHECK(weak_collection->map()->inobject_properties() == 0);
-  Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
-  weak_collection->set_table(*table);
-  return weak_collection;
-}
-
-
-RUNTIME_FUNCTION(Runtime_WeakCollectionInitialize) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
-  return *WeakCollectionInitialize(isolate, weak_collection);
-}
-
-
-RUNTIME_FUNCTION(Runtime_WeakCollectionGet) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
-  Handle<ObjectHashTable> table(
-      ObjectHashTable::cast(weak_collection->table()));
-  RUNTIME_ASSERT(table->IsKey(*key));
-  Handle<Object> lookup(table->Lookup(key), isolate);
-  return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
-}
-
-
-RUNTIME_FUNCTION(Runtime_WeakCollectionHas) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
-  Handle<ObjectHashTable> table(
-      ObjectHashTable::cast(weak_collection->table()));
-  RUNTIME_ASSERT(table->IsKey(*key));
-  Handle<Object> lookup(table->Lookup(key), isolate);
-  return isolate->heap()->ToBoolean(!lookup->IsTheHole());
-}
-
-
-RUNTIME_FUNCTION(Runtime_WeakCollectionDelete) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
-  Handle<ObjectHashTable> table(ObjectHashTable::cast(
-      weak_collection->table()));
-  RUNTIME_ASSERT(table->IsKey(*key));
-  bool was_present = false;
-  Handle<ObjectHashTable> new_table =
-      ObjectHashTable::Remove(table, key, &was_present);
-  weak_collection->set_table(*new_table);
-  return isolate->heap()->ToBoolean(was_present);
-}
-
-
-RUNTIME_FUNCTION(Runtime_WeakCollectionSet) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
-  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
-  Handle<ObjectHashTable> table(
-      ObjectHashTable::cast(weak_collection->table()));
-  RUNTIME_ASSERT(table->IsKey(*key));
-  Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value);
-  weak_collection->set_table(*new_table);
-  return *weak_collection;
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetWeakSetValues) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
-  Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
-  Handle<FixedArray> values =
-      isolate->factory()->NewFixedArray(table->NumberOfElements());
-  {
-    DisallowHeapAllocation no_gc;
-    int number_of_non_hole_elements = 0;
-    for (int i = 0; i < table->Capacity(); i++) {
-      Handle<Object> key(table->KeyAt(i), isolate);
-      if (table->IsKey(*key)) {
-        values->set(number_of_non_hole_elements++, *key);
-      }
-    }
-    DCHECK_EQ(table->NumberOfElements(), number_of_non_hole_elements);
-  }
-  return *isolate->factory()->NewJSArrayWithElements(values);
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetPrototype) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
-  // We don't expect access checks to be needed on JSProxy objects.
-  DCHECK(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
-  PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
-  do {
-    if (PrototypeIterator::GetCurrent(iter)->IsAccessCheckNeeded() &&
-        !isolate->MayNamedAccess(
-            Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
-            isolate->factory()->proto_string(), v8::ACCESS_GET)) {
-      isolate->ReportFailedAccessCheck(
-          Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
-          v8::ACCESS_GET);
-      RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
-      return isolate->heap()->undefined_value();
-    }
-    iter.AdvanceIgnoringProxies();
-    if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
-      return *PrototypeIterator::GetCurrent(iter);
-    }
-  } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN));
-  return *PrototypeIterator::GetCurrent(iter);
-}
-
-
-static inline Handle<Object> GetPrototypeSkipHiddenPrototypes(
-    Isolate* isolate, Handle<Object> receiver) {
-  PrototypeIterator iter(isolate, receiver);
-  while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
-    if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
-      return PrototypeIterator::GetCurrent(iter);
-    }
-    iter.Advance();
-  }
-  return PrototypeIterator::GetCurrent(iter);
-}
-
-
-RUNTIME_FUNCTION(Runtime_InternalSetPrototype) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
-  DCHECK(!obj->IsAccessCheckNeeded());
-  DCHECK(!obj->map()->is_observed());
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, JSObject::SetPrototype(obj, prototype, false));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_SetPrototype) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
-  if (obj->IsAccessCheckNeeded() &&
-      !isolate->MayNamedAccess(
-          obj, isolate->factory()->proto_string(), v8::ACCESS_SET)) {
-    isolate->ReportFailedAccessCheck(obj, v8::ACCESS_SET);
-    RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
-    return isolate->heap()->undefined_value();
-  }
-  if (obj->map()->is_observed()) {
-    Handle<Object> old_value = GetPrototypeSkipHiddenPrototypes(isolate, obj);
-    Handle<Object> result;
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, result,
-        JSObject::SetPrototype(obj, prototype, true));
-
-    Handle<Object> new_value = GetPrototypeSkipHiddenPrototypes(isolate, obj);
-    if (!new_value->SameValue(*old_value)) {
-      JSObject::EnqueueChangeRecord(obj, "setPrototype",
-                                    isolate->factory()->proto_string(),
-                                    old_value);
-    }
-    return *result;
-  }
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      JSObject::SetPrototype(obj, prototype, true));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsInPrototypeChain) {
-  HandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
-  CONVERT_ARG_HANDLE_CHECKED(Object, O, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, V, 1);
-  PrototypeIterator iter(isolate, V, PrototypeIterator::START_AT_RECEIVER);
-  while (true) {
-    iter.AdvanceIgnoringProxies();
-    if (iter.IsAtEnd()) return isolate->heap()->false_value();
-    if (iter.IsAtEnd(O)) return isolate->heap()->true_value();
-  }
-}
-
-
-// Enumerator used as indices into the array returned from GetOwnProperty
-enum PropertyDescriptorIndices {
-  IS_ACCESSOR_INDEX,
-  VALUE_INDEX,
-  GETTER_INDEX,
-  SETTER_INDEX,
-  WRITABLE_INDEX,
-  ENUMERABLE_INDEX,
-  CONFIGURABLE_INDEX,
-  DESCRIPTOR_SIZE
-};
-
-
-MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate,
-                                                          Handle<JSObject> obj,
-                                                          Handle<Name> name) {
-  Heap* heap = isolate->heap();
-  Factory* factory = isolate->factory();
-
-  PropertyAttributes attrs;
-  uint32_t index = 0;
-  Handle<Object> value;
-  MaybeHandle<AccessorPair> maybe_accessors;
-  // TODO(verwaest): Unify once indexed properties can be handled by the
-  // LookupIterator.
-  if (name->AsArrayIndex(&index)) {
-    // Get attributes.
-    Maybe<PropertyAttributes> maybe =
-        JSReceiver::GetOwnElementAttribute(obj, index);
-    if (!maybe.has_value) return MaybeHandle<Object>();
-    attrs = maybe.value;
-    if (attrs == ABSENT) return factory->undefined_value();
-
-    // Get AccessorPair if present.
-    maybe_accessors = JSObject::GetOwnElementAccessorPair(obj, index);
-
-    // Get value if not an AccessorPair.
-    if (maybe_accessors.is_null()) {
-      ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
-          Runtime::GetElementOrCharAt(isolate, obj, index), Object);
-    }
-  } else {
-    // Get attributes.
-    LookupIterator it(obj, name, LookupIterator::HIDDEN);
-    Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(&it);
-    if (!maybe.has_value) return MaybeHandle<Object>();
-    attrs = maybe.value;
-    if (attrs == ABSENT) return factory->undefined_value();
-
-    // Get AccessorPair if present.
-    if (it.state() == LookupIterator::ACCESSOR &&
-        it.GetAccessors()->IsAccessorPair()) {
-      maybe_accessors = Handle<AccessorPair>::cast(it.GetAccessors());
-    }
-
-    // Get value if not an AccessorPair.
-    if (maybe_accessors.is_null()) {
-      ASSIGN_RETURN_ON_EXCEPTION(
-          isolate, value, Object::GetProperty(&it), Object);
-    }
-  }
-  DCHECK(!isolate->has_pending_exception());
-  Handle<FixedArray> elms = factory->NewFixedArray(DESCRIPTOR_SIZE);
-  elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0));
-  elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0));
-  elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(!maybe_accessors.is_null()));
-
-  Handle<AccessorPair> accessors;
-  if (maybe_accessors.ToHandle(&accessors)) {
-    Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate);
-    Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate);
-    elms->set(GETTER_INDEX, *getter);
-    elms->set(SETTER_INDEX, *setter);
-  } else {
-    elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0));
-    elms->set(VALUE_INDEX, *value);
-  }
-
-  return factory->NewJSArrayWithElements(elms);
-}
-
-
-// Returns an array with the property description:
-//  if args[1] is not a property on args[0]
-//          returns undefined
-//  if args[1] is a data property on args[0]
-//         [false, value, Writeable, Enumerable, Configurable]
-//  if args[1] is an accessor on args[0]
-//         [true, GetFunction, SetFunction, Enumerable, Configurable]
-RUNTIME_FUNCTION(Runtime_GetOwnProperty) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, GetOwnProperty(isolate, obj, name));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_PreventExtensions) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, JSObject::PreventExtensions(obj));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_ToMethod) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
-  Handle<JSFunction> clone = JSFunction::CloneClosure(fun);
-  Handle<Symbol> home_object_symbol(isolate->heap()->home_object_symbol());
-  JSObject::SetOwnPropertyIgnoreAttributes(clone, home_object_symbol,
-                                           home_object, DONT_ENUM).Assert();
-  return *clone;
-}
-
-
-RUNTIME_FUNCTION(Runtime_HomeObjectSymbol) {
-  DCHECK(args.length() == 0);
-  return isolate->heap()->home_object_symbol();
-}
-
-
-RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
-
-  if (home_object->IsAccessCheckNeeded() &&
-      !isolate->MayNamedAccess(home_object, name, v8::ACCESS_GET)) {
-    isolate->ReportFailedAccessCheck(home_object, v8::ACCESS_GET);
-    RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
-  }
-
-  PrototypeIterator iter(isolate, home_object);
-  Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
-  if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value();
-
-  LookupIterator it(receiver, name, Handle<JSReceiver>::cast(proto));
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsExtensible) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSObject, obj, 0);
-  if (obj->IsJSGlobalProxy()) {
-    PrototypeIterator iter(isolate, obj);
-    if (iter.IsAtEnd()) return isolate->heap()->false_value();
-    DCHECK(iter.GetCurrent()->IsJSGlobalObject());
-    obj = JSObject::cast(iter.GetCurrent());
-  }
-  return isolate->heap()->ToBoolean(obj->map()->is_extensible());
-}
-
-
-RUNTIME_FUNCTION(Runtime_RegExpCompile) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, RegExpImpl::Compile(re, pattern, flags));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreateApiFunction) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
-  return *isolate->factory()->CreateApiFunction(data, prototype);
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsTemplate) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, arg, 0);
-  bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
-  return isolate->heap()->ToBoolean(result);
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetTemplateField) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_CHECKED(HeapObject, templ, 0);
-  CONVERT_SMI_ARG_CHECKED(index, 1);
-  int offset = index * kPointerSize + HeapObject::kHeaderSize;
-  InstanceType type = templ->map()->instance_type();
-  RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
-                 type == OBJECT_TEMPLATE_INFO_TYPE);
-  RUNTIME_ASSERT(offset > 0);
-  if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
-    RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
-  } else {
-    RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
-  }
-  return *HeapObject::RawField(templ, offset);
-}
-
-
-RUNTIME_FUNCTION(Runtime_DisableAccessChecks) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0);
-  Handle<Map> old_map(object->map());
-  bool needs_access_checks = old_map->is_access_check_needed();
-  if (needs_access_checks) {
-    // Copy map so it won't interfere constructor's initial map.
-    Handle<Map> new_map = Map::Copy(old_map);
-    new_map->set_is_access_check_needed(false);
-    JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
-  }
-  return isolate->heap()->ToBoolean(needs_access_checks);
-}
-
-
-RUNTIME_FUNCTION(Runtime_EnableAccessChecks) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-  Handle<Map> old_map(object->map());
-  RUNTIME_ASSERT(!old_map->is_access_check_needed());
-  // Copy map so it won't interfere constructor's initial map.
-  Handle<Map> new_map = Map::Copy(old_map);
-  new_map->set_is_access_check_needed(true);
-  JSObject::MigrateToMap(object, new_map);
-  return isolate->heap()->undefined_value();
-}
-
-
-static Object* ThrowRedeclarationError(Isolate* isolate, Handle<String> name) {
-  HandleScope scope(isolate);
-  Handle<Object> args[1] = { name };
-  THROW_NEW_ERROR_RETURN_FAILURE(
-      isolate, NewTypeError("var_redeclaration", HandleVector(args, 1)));
-}
-
-
-// May throw a RedeclarationError.
-static Object* DeclareGlobals(Isolate* isolate, Handle<GlobalObject> global,
-                              Handle<String> name, Handle<Object> value,
-                              PropertyAttributes attr, bool is_var,
-                              bool is_const, bool is_function) {
-  // Do the lookup own properties only, see ES5 erratum.
-  LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
-  Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
-  if (!maybe.has_value) return isolate->heap()->exception();
-
-  if (it.IsFound()) {
-    PropertyAttributes old_attributes = maybe.value;
-    // The name was declared before; check for conflicting re-declarations.
-    if (is_const) return ThrowRedeclarationError(isolate, name);
-
-    // Skip var re-declarations.
-    if (is_var) return isolate->heap()->undefined_value();
-
-    DCHECK(is_function);
-    if ((old_attributes & DONT_DELETE) != 0) {
-      // Only allow reconfiguring globals to functions in user code (no
-      // natives, which are marked as read-only).
-      DCHECK((attr & READ_ONLY) == 0);
-
-      // Check whether we can reconfigure the existing property into a
-      // function.
-      PropertyDetails old_details = it.property_details();
-      // TODO(verwaest): CALLBACKS invalidly includes ExecutableAccessInfo,
-      // which are actually data properties, not accessor properties.
-      if (old_details.IsReadOnly() || old_details.IsDontEnum() ||
-          old_details.type() == CALLBACKS) {
-        return ThrowRedeclarationError(isolate, name);
-      }
-      // If the existing property is not configurable, keep its attributes. Do
-      attr = old_attributes;
-    }
-  }
-
-  // Define or redefine own property.
-  RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
-                                           global, name, value, attr));
-
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  Handle<GlobalObject> global(isolate->global_object());
-
-  CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
-  CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
-  CONVERT_SMI_ARG_CHECKED(flags, 2);
-
-  // Traverse the name/value pairs and set the properties.
-  int length = pairs->length();
-  for (int i = 0; i < length; i += 2) {
-    HandleScope scope(isolate);
-    Handle<String> name(String::cast(pairs->get(i)));
-    Handle<Object> initial_value(pairs->get(i + 1), isolate);
-
-    // We have to declare a global const property. To capture we only
-    // assign to it when evaluating the assignment for "const x =
-    // <expr>" the initial value is the hole.
-    bool is_var = initial_value->IsUndefined();
-    bool is_const = initial_value->IsTheHole();
-    bool is_function = initial_value->IsSharedFunctionInfo();
-    DCHECK(is_var + is_const + is_function == 1);
-
-    Handle<Object> value;
-    if (is_function) {
-      // Copy the function and update its context. Use it as value.
-      Handle<SharedFunctionInfo> shared =
-          Handle<SharedFunctionInfo>::cast(initial_value);
-      Handle<JSFunction> function =
-          isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
-                                                                TENURED);
-      value = function;
-    } else {
-      value = isolate->factory()->undefined_value();
-    }
-
-    // Compute the property attributes. According to ECMA-262,
-    // the property must be non-configurable except in eval.
-    bool is_native = DeclareGlobalsNativeFlag::decode(flags);
-    bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
-    int attr = NONE;
-    if (is_const) attr |= READ_ONLY;
-    if (is_function && is_native) attr |= READ_ONLY;
-    if (!is_const && !is_eval) attr |= DONT_DELETE;
-
-    Object* result = DeclareGlobals(isolate, global, name, value,
-                                    static_cast<PropertyAttributes>(attr),
-                                    is_var, is_const, is_function);
-    if (isolate->has_pending_exception()) return result;
-  }
-
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) {
-  HandleScope scope(isolate);
-  // args[0] == name
-  // args[1] == language_mode
-  // args[2] == value (optional)
-
-  // Determine if we need to assign to the variable if it already
-  // exists (based on the number of arguments).
-  RUNTIME_ASSERT(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
-  CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
-
-  Handle<GlobalObject> global(isolate->context()->global_object());
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, Object::SetProperty(global, name, value, strict_mode));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) {
-  HandleScope handle_scope(isolate);
-  // All constants are declared with an initial value. The name
-  // of the constant is the first argument and the initial value
-  // is the second.
-  RUNTIME_ASSERT(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
-
-  Handle<GlobalObject> global = isolate->global_object();
-
-  // Lookup the property as own on the global object.
-  LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
-  Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
-  DCHECK(maybe.has_value);
-  PropertyAttributes old_attributes = maybe.value;
-
-  PropertyAttributes attr =
-      static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
-  // Set the value if the property is either missing, or the property attributes
-  // allow setting the value without invoking an accessor.
-  if (it.IsFound()) {
-    // Ignore if we can't reconfigure the value.
-    if ((old_attributes & DONT_DELETE) != 0) {
-      if ((old_attributes & READ_ONLY) != 0 ||
-          it.state() == LookupIterator::ACCESSOR) {
-        return *value;
-      }
-      attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
-    }
-  }
-
-  RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
-                                           global, name, value, attr));
-
-  return *value;
-}
-
-
-RUNTIME_FUNCTION(Runtime_DeclareLookupSlot) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-
-  // Declarations are always made in a function, native, or global context. In
-  // the case of eval code, the context passed is the context of the caller,
-  // which may be some nested context and not the declaration context.
-  CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 0);
-  Handle<Context> context(context_arg->declaration_context());
-  CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
-  CONVERT_SMI_ARG_CHECKED(attr_arg, 2);
-  PropertyAttributes attr = static_cast<PropertyAttributes>(attr_arg);
-  RUNTIME_ASSERT(attr == READ_ONLY || attr == NONE);
-  CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 3);
-
-  // TODO(verwaest): Unify the encoding indicating "var" with DeclareGlobals.
-  bool is_var = *initial_value == NULL;
-  bool is_const = initial_value->IsTheHole();
-  bool is_function = initial_value->IsJSFunction();
-  DCHECK(is_var + is_const + is_function == 1);
-
-  int index;
-  PropertyAttributes attributes;
-  ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
-  BindingFlags binding_flags;
-  Handle<Object> holder =
-      context->Lookup(name, flags, &index, &attributes, &binding_flags);
-
-  Handle<JSObject> object;
-  Handle<Object> value =
-      is_function ? initial_value
-                  : Handle<Object>::cast(isolate->factory()->undefined_value());
-
-  // TODO(verwaest): This case should probably not be covered by this function,
-  // but by DeclareGlobals instead.
-  if ((attributes != ABSENT && holder->IsJSGlobalObject()) ||
-      (context_arg->has_extension() &&
-       context_arg->extension()->IsJSGlobalObject())) {
-    return DeclareGlobals(isolate, Handle<JSGlobalObject>::cast(holder), name,
-                          value, attr, is_var, is_const, is_function);
-  }
-
-  if (attributes != ABSENT) {
-    // The name was declared before; check for conflicting re-declarations.
-    if (is_const || (attributes & READ_ONLY) != 0) {
-      return ThrowRedeclarationError(isolate, name);
-    }
-
-    // Skip var re-declarations.
-    if (is_var) return isolate->heap()->undefined_value();
-
-    DCHECK(is_function);
-    if (index >= 0) {
-      DCHECK(holder.is_identical_to(context));
-      context->set(index, *initial_value);
-      return isolate->heap()->undefined_value();
-    }
-
-    object = Handle<JSObject>::cast(holder);
-
-  } else if (context->has_extension()) {
-    object = handle(JSObject::cast(context->extension()));
-    DCHECK(object->IsJSContextExtensionObject() || object->IsJSGlobalObject());
-  } else {
-    DCHECK(context->IsFunctionContext());
-    object =
-        isolate->factory()->NewJSObject(isolate->context_extension_function());
-    context->set_extension(*object);
-  }
-
-  RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
-                                           object, name, value, attr));
-
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_InitializeLegacyConstLookupSlot) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
-  DCHECK(!value->IsTheHole());
-  // Initializations are always done in a function or native context.
-  CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 1);
-  Handle<Context> context(context_arg->declaration_context());
-  CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
-
-  int index;
-  PropertyAttributes attributes;
-  ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
-  BindingFlags binding_flags;
-  Handle<Object> holder =
-      context->Lookup(name, flags, &index, &attributes, &binding_flags);
-
-  if (index >= 0) {
-    DCHECK(holder->IsContext());
-    // Property was found in a context.  Perform the assignment if the constant
-    // was uninitialized.
-    Handle<Context> context = Handle<Context>::cast(holder);
-    DCHECK((attributes & READ_ONLY) != 0);
-    if (context->get(index)->IsTheHole()) context->set(index, *value);
-    return *value;
-  }
-
-  PropertyAttributes attr =
-      static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
-
-  // Strict mode handling not needed (legacy const is disallowed in strict
-  // mode).
-
-  // The declared const was configurable, and may have been deleted in the
-  // meanwhile. If so, re-introduce the variable in the context extension.
-  DCHECK(context_arg->has_extension());
-  if (attributes == ABSENT) {
-    holder = handle(context_arg->extension(), isolate);
-  } else {
-    // For JSContextExtensionObjects, the initializer can be run multiple times
-    // if in a for loop: for (var i = 0; i < 2; i++) { const x = i; }. Only the
-    // first assignment should go through. For JSGlobalObjects, additionally any
-    // code can run in between that modifies the declared property.
-    DCHECK(holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject());
-
-    LookupIterator it(holder, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
-    Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
-    if (!maybe.has_value) return isolate->heap()->exception();
-    PropertyAttributes old_attributes = maybe.value;
-
-    // Ignore if we can't reconfigure the value.
-    if ((old_attributes & DONT_DELETE) != 0) {
-      if ((old_attributes & READ_ONLY) != 0 ||
-          it.state() == LookupIterator::ACCESSOR) {
-        return *value;
-      }
-      attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
-    }
-  }
-
-  RETURN_FAILURE_ON_EXCEPTION(
-      isolate, JSObject::SetOwnPropertyIgnoreAttributes(
-                   Handle<JSObject>::cast(holder), name, value, attr));
-
-  return *value;
-}
-
-
-RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-  CONVERT_SMI_ARG_CHECKED(properties, 1);
-  // Conservative upper limit to prevent fuzz tests from going OOM.
-  RUNTIME_ASSERT(properties <= 100000);
-  if (object->HasFastProperties() && !object->IsJSGlobalProxy()) {
-    JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
-  }
-  return *object;
-}
-
-
-RUNTIME_FUNCTION(Runtime_RegExpExecRT) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
-  CONVERT_INT32_ARG_CHECKED(index, 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
-  // Due to the way the JS calls are constructed this must be less than the
-  // length of a string, i.e. it is always a Smi.  We check anyway for security.
-  RUNTIME_ASSERT(index >= 0);
-  RUNTIME_ASSERT(index <= subject->length());
-  isolate->counters()->regexp_entry_runtime()->Increment();
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      RegExpImpl::Exec(regexp, subject, index, last_match_info));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_RegExpConstructResult) {
-  HandleScope handle_scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_SMI_ARG_CHECKED(size, 0);
-  RUNTIME_ASSERT(size >= 0 && size <= FixedArray::kMaxLength);
-  CONVERT_ARG_HANDLE_CHECKED(Object, index, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, input, 2);
-  Handle<FixedArray> elements =  isolate->factory()->NewFixedArray(size);
-  Handle<Map> regexp_map(isolate->native_context()->regexp_result_map());
-  Handle<JSObject> object =
-      isolate->factory()->NewJSObjectFromMap(regexp_map, NOT_TENURED, false);
-  Handle<JSArray> array = Handle<JSArray>::cast(object);
-  array->set_elements(*elements);
-  array->set_length(Smi::FromInt(size));
-  // Write in-object properties after the length of the array.
-  array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, *index);
-  array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, *input);
-  return *array;
-}
-
-
-RUNTIME_FUNCTION(Runtime_RegExpInitializeObject) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 6);
-  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
-  // If source is the empty string we set it to "(?:)" instead as
-  // suggested by ECMA-262, 5th, section 15.10.4.1.
-  if (source->length() == 0) source = isolate->factory()->query_colon_string();
-
-  CONVERT_ARG_HANDLE_CHECKED(Object, global, 2);
-  if (!global->IsTrue()) global = isolate->factory()->false_value();
-
-  CONVERT_ARG_HANDLE_CHECKED(Object, ignoreCase, 3);
-  if (!ignoreCase->IsTrue()) ignoreCase = isolate->factory()->false_value();
-
-  CONVERT_ARG_HANDLE_CHECKED(Object, multiline, 4);
-  if (!multiline->IsTrue()) multiline = isolate->factory()->false_value();
-
-  CONVERT_ARG_HANDLE_CHECKED(Object, sticky, 5);
-  if (!sticky->IsTrue()) sticky = isolate->factory()->false_value();
-
-  Map* map = regexp->map();
-  Object* constructor = map->constructor();
-  if (!FLAG_harmony_regexps &&
-      constructor->IsJSFunction() &&
-      JSFunction::cast(constructor)->initial_map() == map) {
-    // If we still have the original map, set in-object properties directly.
-    regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *source);
-    // Both true and false are immovable immortal objects so no need for write
-    // barrier.
-    regexp->InObjectPropertyAtPut(
-        JSRegExp::kGlobalFieldIndex, *global, SKIP_WRITE_BARRIER);
-    regexp->InObjectPropertyAtPut(
-        JSRegExp::kIgnoreCaseFieldIndex, *ignoreCase, SKIP_WRITE_BARRIER);
-    regexp->InObjectPropertyAtPut(
-        JSRegExp::kMultilineFieldIndex, *multiline, SKIP_WRITE_BARRIER);
-    regexp->InObjectPropertyAtPut(
-        JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER);
-    return *regexp;
-  }
-
-  // Map has changed, so use generic, but slower, method.  We also end here if
-  // the --harmony-regexp flag is set, because the initial map does not have
-  // space for the 'sticky' flag, since it is from the snapshot, but must work
-  // both with and without --harmony-regexp.  When sticky comes out from under
-  // the flag, we will be able to use the fast initial map.
-  PropertyAttributes final =
-      static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
-  PropertyAttributes writable =
-      static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
-  Handle<Object> zero(Smi::FromInt(0), isolate);
-  Factory* factory = isolate->factory();
-  JSObject::SetOwnPropertyIgnoreAttributes(
-      regexp, factory->source_string(), source, final).Check();
-  JSObject::SetOwnPropertyIgnoreAttributes(
-      regexp, factory->global_string(), global, final).Check();
-  JSObject::SetOwnPropertyIgnoreAttributes(
-      regexp, factory->ignore_case_string(), ignoreCase, final).Check();
-  JSObject::SetOwnPropertyIgnoreAttributes(
-      regexp, factory->multiline_string(), multiline, final).Check();
-  if (FLAG_harmony_regexps) {
-    JSObject::SetOwnPropertyIgnoreAttributes(
-        regexp, factory->sticky_string(), sticky, final).Check();
-  }
-  JSObject::SetOwnPropertyIgnoreAttributes(
-      regexp, factory->last_index_string(), zero, writable).Check();
-  return *regexp;
-}
-
-
-RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
-  Object* length = prototype->length();
-  RUNTIME_ASSERT(length->IsSmi() && Smi::cast(length)->value() == 0);
-  RUNTIME_ASSERT(prototype->HasFastSmiOrObjectElements());
-  // This is necessary to enable fast checks for absence of elements
-  // on Array.prototype and below.
-  prototype->set_elements(isolate->heap()->empty_fixed_array());
-  return Smi::FromInt(0);
-}
-
-
-static void InstallBuiltin(Isolate* isolate,
-                           Handle<JSObject> holder,
-                           const char* name,
-                           Builtins::Name builtin_name) {
-  Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
-  Handle<Code> code(isolate->builtins()->builtin(builtin_name));
-  Handle<JSFunction> optimized =
-      isolate->factory()->NewFunctionWithoutPrototype(key, code);
-  optimized->shared()->DontAdaptArguments();
-  JSObject::AddProperty(holder, key, optimized, NONE);
-}
-
-
-RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-  Handle<JSObject> holder =
-      isolate->factory()->NewJSObject(isolate->object_function());
-
-  InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
-  InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
-  InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
-  InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
-  InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
-  InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
-  InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
-
-  return *holder;
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsSloppyModeFunction) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
-  if (!callable->IsJSFunction()) {
-    HandleScope scope(isolate);
-    Handle<Object> delegate;
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, delegate,
-        Execution::TryGetFunctionDelegate(
-            isolate, Handle<JSReceiver>(callable)));
-    callable = JSFunction::cast(*delegate);
-  }
-  JSFunction* function = JSFunction::cast(callable);
-  SharedFunctionInfo* shared = function->shared();
-  return isolate->heap()->ToBoolean(shared->strict_mode() == SLOPPY);
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetDefaultReceiver) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
-
-  if (!callable->IsJSFunction()) {
-    HandleScope scope(isolate);
-    Handle<Object> delegate;
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, delegate,
-        Execution::TryGetFunctionDelegate(
-            isolate, Handle<JSReceiver>(callable)));
-    callable = JSFunction::cast(*delegate);
-  }
-  JSFunction* function = JSFunction::cast(callable);
-
-  SharedFunctionInfo* shared = function->shared();
-  if (shared->native() || shared->strict_mode() == STRICT) {
-    return isolate->heap()->undefined_value();
-  }
-  // Returns undefined for strict or native functions, or
-  // the associated global receiver for "normal" functions.
-
-  return function->global_proxy();
-}
-
-
-RUNTIME_FUNCTION(Runtime_MaterializeRegExpLiteral) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-  CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
-  CONVERT_SMI_ARG_CHECKED(index, 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2);
-  CONVERT_ARG_HANDLE_CHECKED(String, flags, 3);
-
-  // Get the RegExp function from the context in the literals array.
-  // This is the RegExp function from the context in which the
-  // function was created.  We do not use the RegExp function from the
-  // current native context because this might be the RegExp function
-  // from another context which we should not have access to.
-  Handle<JSFunction> constructor =
-      Handle<JSFunction>(
-          JSFunction::NativeContextFromLiterals(*literals)->regexp_function());
-  // Compute the regular expression literal.
-  Handle<Object> regexp;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, regexp,
-      RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags));
-  literals->set(index, *regexp);
-  return *regexp;
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionGetName) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_CHECKED(JSFunction, f, 0);
-  return f->shared()->name();
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionSetName) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_CHECKED(JSFunction, f, 0);
-  CONVERT_ARG_CHECKED(String, name, 1);
-  f->shared()->set_name(name);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionNameShouldPrintAsAnonymous) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSFunction, f, 0);
-  return isolate->heap()->ToBoolean(
-      f->shared()->name_should_print_as_anonymous());
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSFunction, f, 0);
-  f->shared()->set_name_should_print_as_anonymous(true);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionIsGenerator) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSFunction, f, 0);
-  return isolate->heap()->ToBoolean(f->shared()->is_generator());
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionIsArrow) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSFunction, f, 0);
-  return isolate->heap()->ToBoolean(f->shared()->is_arrow());
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionIsConciseMethod) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSFunction, f, 0);
-  return isolate->heap()->ToBoolean(f->shared()->is_concise_method());
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionRemovePrototype) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_CHECKED(JSFunction, f, 0);
-  RUNTIME_ASSERT(f->RemovePrototype());
-
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionGetScript) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_CHECKED(JSFunction, fun, 0);
-  Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
-  if (!script->IsScript()) return isolate->heap()->undefined_value();
-
-  return *Script::GetWrapper(Handle<Script>::cast(script));
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionGetSourceCode) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
-  Handle<SharedFunctionInfo> shared(f->shared());
-  return *shared->GetSourceCode();
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionGetScriptSourcePosition) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_CHECKED(JSFunction, fun, 0);
-  int pos = fun->shared()->start_position();
-  return Smi::FromInt(pos);
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionGetPositionForOffset) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_CHECKED(Code, code, 0);
-  CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
-
-  RUNTIME_ASSERT(0 <= offset && offset < code->Size());
-
-  Address pc = code->address() + offset;
-  return Smi::FromInt(code->SourcePosition(pc));
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionSetInstanceClassName) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_CHECKED(JSFunction, fun, 0);
-  CONVERT_ARG_CHECKED(String, name, 1);
-  fun->SetInstanceClassName(name);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionSetLength) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_CHECKED(JSFunction, fun, 0);
-  CONVERT_SMI_ARG_CHECKED(length, 1);
-  RUNTIME_ASSERT((length & 0xC0000000) == 0xC0000000 ||
-                 (length & 0xC0000000) == 0x0);
-  fun->shared()->set_length(length);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
-  RUNTIME_ASSERT(fun->should_have_prototype());
-  Accessors::FunctionSetPrototype(fun, value);
-  return args[0];  // return TOS
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionIsAPIFunction) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_CHECKED(JSFunction, f, 0);
-  return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionIsBuiltin) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_CHECKED(JSFunction, f, 0);
-  return isolate->heap()->ToBoolean(f->IsBuiltin());
-}
-
-
-RUNTIME_FUNCTION(Runtime_SetCode) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, source, 1);
-
-  Handle<SharedFunctionInfo> target_shared(target->shared());
-  Handle<SharedFunctionInfo> source_shared(source->shared());
-  RUNTIME_ASSERT(!source_shared->bound());
-
-  if (!Compiler::EnsureCompiled(source, KEEP_EXCEPTION)) {
-    return isolate->heap()->exception();
-  }
-
-  // Mark both, the source and the target, as un-flushable because the
-  // shared unoptimized code makes them impossible to enqueue in a list.
-  DCHECK(target_shared->code()->gc_metadata() == NULL);
-  DCHECK(source_shared->code()->gc_metadata() == NULL);
-  target_shared->set_dont_flush(true);
-  source_shared->set_dont_flush(true);
-
-  // Set the code, scope info, formal parameter count, and the length
-  // of the target shared function info.
-  target_shared->ReplaceCode(source_shared->code());
-  target_shared->set_scope_info(source_shared->scope_info());
-  target_shared->set_length(source_shared->length());
-  target_shared->set_feedback_vector(source_shared->feedback_vector());
-  target_shared->set_formal_parameter_count(
-      source_shared->formal_parameter_count());
-  target_shared->set_script(source_shared->script());
-  target_shared->set_start_position_and_type(
-      source_shared->start_position_and_type());
-  target_shared->set_end_position(source_shared->end_position());
-  bool was_native = target_shared->native();
-  target_shared->set_compiler_hints(source_shared->compiler_hints());
-  target_shared->set_native(was_native);
-  target_shared->set_profiler_ticks(source_shared->profiler_ticks());
-
-  // Set the code of the target function.
-  target->ReplaceCode(source_shared->code());
-  DCHECK(target->next_function_link()->IsUndefined());
-
-  // Make sure we get a fresh copy of the literal vector to avoid cross
-  // context contamination.
-  Handle<Context> context(source->context());
-  int number_of_literals = source->NumberOfLiterals();
-  Handle<FixedArray> literals =
-      isolate->factory()->NewFixedArray(number_of_literals, TENURED);
-  if (number_of_literals > 0) {
-    literals->set(JSFunction::kLiteralNativeContextIndex,
-                  context->native_context());
-  }
-  target->set_context(*context);
-  target->set_literals(*literals);
-
-  if (isolate->logger()->is_logging_code_events() ||
-      isolate->cpu_profiler()->is_profiling()) {
-    isolate->logger()->LogExistingFunction(
-        source_shared, Handle<Code>(source_shared->code()));
-  }
-
-  return *target;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-
-  JavaScriptFrameIterator it(isolate);
-  JavaScriptFrame* frame = it.frame();
-  Handle<JSFunction> function(frame->function());
-  RUNTIME_ASSERT(function->shared()->is_generator());
-
-  Handle<JSGeneratorObject> generator;
-  if (frame->IsConstructor()) {
-    generator = handle(JSGeneratorObject::cast(frame->receiver()));
-  } else {
-    generator = isolate->factory()->NewJSGeneratorObject(function);
-  }
-  generator->set_function(*function);
-  generator->set_context(Context::cast(frame->context()));
-  generator->set_receiver(frame->receiver());
-  generator->set_continuation(0);
-  generator->set_operand_stack(isolate->heap()->empty_fixed_array());
-  generator->set_stack_handler_index(-1);
-
-  return *generator;
-}
-
-
-RUNTIME_FUNCTION(Runtime_SuspendJSGeneratorObject) {
-  HandleScope handle_scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0);
-
-  JavaScriptFrameIterator stack_iterator(isolate);
-  JavaScriptFrame* frame = stack_iterator.frame();
-  RUNTIME_ASSERT(frame->function()->shared()->is_generator());
-  DCHECK_EQ(frame->function(), generator_object->function());
-
-  // The caller should have saved the context and continuation already.
-  DCHECK_EQ(generator_object->context(), Context::cast(frame->context()));
-  DCHECK_LT(0, generator_object->continuation());
-
-  // We expect there to be at least two values on the operand stack: the return
-  // value of the yield expression, and the argument to this runtime call.
-  // Neither of those should be saved.
-  int operands_count = frame->ComputeOperandsCount();
-  DCHECK_GE(operands_count, 2);
-  operands_count -= 2;
-
-  if (operands_count == 0) {
-    // Although it's semantically harmless to call this function with an
-    // operands_count of zero, it is also unnecessary.
-    DCHECK_EQ(generator_object->operand_stack(),
-              isolate->heap()->empty_fixed_array());
-    DCHECK_EQ(generator_object->stack_handler_index(), -1);
-    // If there are no operands on the stack, there shouldn't be a handler
-    // active either.
-    DCHECK(!frame->HasHandler());
-  } else {
-    int stack_handler_index = -1;
-    Handle<FixedArray> operand_stack =
-        isolate->factory()->NewFixedArray(operands_count);
-    frame->SaveOperandStack(*operand_stack, &stack_handler_index);
-    generator_object->set_operand_stack(*operand_stack);
-    generator_object->set_stack_handler_index(stack_handler_index);
-  }
-
-  return isolate->heap()->undefined_value();
-}
-
-
-// Note that this function is the slow path for resuming generators.  It is only
-// called if the suspended activation had operands on the stack, stack handlers
-// needing rewinding, or if the resume should throw an exception.  The fast path
-// is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is
-// inlined into GeneratorNext and GeneratorThrow.  EmitGeneratorResumeResume is
-// called in any case, as it needs to reconstruct the stack frame and make space
-// for arguments and operands.
-RUNTIME_FUNCTION(Runtime_ResumeJSGeneratorObject) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
-  CONVERT_ARG_CHECKED(Object, value, 1);
-  CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2);
-  JavaScriptFrameIterator stack_iterator(isolate);
-  JavaScriptFrame* frame = stack_iterator.frame();
-
-  DCHECK_EQ(frame->function(), generator_object->function());
-  DCHECK(frame->function()->is_compiled());
-
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
-
-  Address pc = generator_object->function()->code()->instruction_start();
-  int offset = generator_object->continuation();
-  DCHECK(offset > 0);
-  frame->set_pc(pc + offset);
-  if (FLAG_enable_ool_constant_pool) {
-    frame->set_constant_pool(
-        generator_object->function()->code()->constant_pool());
-  }
-  generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting);
-
-  FixedArray* operand_stack = generator_object->operand_stack();
-  int operands_count = operand_stack->length();
-  if (operands_count != 0) {
-    frame->RestoreOperandStack(operand_stack,
-                               generator_object->stack_handler_index());
-    generator_object->set_operand_stack(isolate->heap()->empty_fixed_array());
-    generator_object->set_stack_handler_index(-1);
-  }
-
-  JSGeneratorObject::ResumeMode resume_mode =
-      static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int);
-  switch (resume_mode) {
-    case JSGeneratorObject::NEXT:
-      return value;
-    case JSGeneratorObject::THROW:
-      return isolate->Throw(value);
-  }
-
-  UNREACHABLE();
-  return isolate->ThrowIllegalOperation();
-}
-
-
-RUNTIME_FUNCTION(Runtime_ThrowGeneratorStateError) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
-  int continuation = generator->continuation();
-  const char* message = continuation == JSGeneratorObject::kGeneratorClosed ?
-      "generator_finished" : "generator_running";
-  Vector< Handle<Object> > argv = HandleVector<Object>(NULL, 0);
-  THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewError(message, argv));
-}
-
-
-RUNTIME_FUNCTION(Runtime_ObjectFreeze) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-
-  // %ObjectFreeze is a fast path and these cases are handled elsewhere.
-  RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() &&
-                 !object->map()->is_observed() &&
-                 !object->IsJSProxy());
-
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringCharCodeAtRT) {
-  HandleScope handle_scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
-  CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]);
-
-  // Flatten the string.  If someone wants to get a char at an index
-  // in a cons string, it is likely that more indices will be
-  // accessed.
-  subject = String::Flatten(subject);
-
-  if (i >= static_cast<uint32_t>(subject->length())) {
-    return isolate->heap()->nan_value();
-  }
-
-  return Smi::FromInt(subject->Get(i));
-}
-
-
-RUNTIME_FUNCTION(Runtime_CharFromCode) {
-  HandleScope handlescope(isolate);
-  DCHECK(args.length() == 1);
-  if (args[0]->IsNumber()) {
-    CONVERT_NUMBER_CHECKED(uint32_t, code, Uint32, args[0]);
-    code &= 0xffff;
-    return *isolate->factory()->LookupSingleCharacterStringFromCode(code);
-  }
-  return isolate->heap()->empty_string();
-}
-
-
-class FixedArrayBuilder {
- public:
-  explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
-      : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
-        length_(0),
-        has_non_smi_elements_(false) {
-    // Require a non-zero initial size. Ensures that doubling the size to
-    // extend the array will work.
-    DCHECK(initial_capacity > 0);
-  }
-
-  explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
-      : array_(backing_store),
-        length_(0),
-        has_non_smi_elements_(false) {
-    // Require a non-zero initial size. Ensures that doubling the size to
-    // extend the array will work.
-    DCHECK(backing_store->length() > 0);
-  }
-
-  bool HasCapacity(int elements) {
-    int length = array_->length();
-    int required_length = length_ + elements;
-    return (length >= required_length);
-  }
-
-  void EnsureCapacity(int elements) {
-    int length = array_->length();
-    int required_length = length_ + elements;
-    if (length < required_length) {
-      int new_length = length;
-      do {
-        new_length *= 2;
-      } while (new_length < required_length);
-      Handle<FixedArray> extended_array =
-          array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
-      array_->CopyTo(0, *extended_array, 0, length_);
-      array_ = extended_array;
-    }
-  }
-
-  void Add(Object* value) {
-    DCHECK(!value->IsSmi());
-    DCHECK(length_ < capacity());
-    array_->set(length_, value);
-    length_++;
-    has_non_smi_elements_ = true;
-  }
-
-  void Add(Smi* value) {
-    DCHECK(value->IsSmi());
-    DCHECK(length_ < capacity());
-    array_->set(length_, value);
-    length_++;
-  }
-
-  Handle<FixedArray> array() {
-    return array_;
-  }
-
-  int length() {
-    return length_;
-  }
-
-  int capacity() {
-    return array_->length();
-  }
-
-  Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
-    JSArray::SetContent(target_array, array_);
-    target_array->set_length(Smi::FromInt(length_));
-    return target_array;
-  }
-
-
- private:
-  Handle<FixedArray> array_;
-  int length_;
-  bool has_non_smi_elements_;
-};
-
-
-// Forward declarations.
-const int kStringBuilderConcatHelperLengthBits = 11;
-const int kStringBuilderConcatHelperPositionBits = 19;
-
-template <typename schar>
-static inline void StringBuilderConcatHelper(String*,
-                                             schar*,
-                                             FixedArray*,
-                                             int);
-
-typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
-    StringBuilderSubstringLength;
-typedef BitField<int,
-                 kStringBuilderConcatHelperLengthBits,
-                 kStringBuilderConcatHelperPositionBits>
-    StringBuilderSubstringPosition;
-
-
-class ReplacementStringBuilder {
- public:
-  ReplacementStringBuilder(Heap* heap, Handle<String> subject,
-                           int estimated_part_count)
-      : heap_(heap),
-        array_builder_(heap->isolate(), estimated_part_count),
-        subject_(subject),
-        character_count_(0),
-        is_one_byte_(subject->IsOneByteRepresentation()) {
-    // Require a non-zero initial size. Ensures that doubling the size to
-    // extend the array will work.
-    DCHECK(estimated_part_count > 0);
-  }
-
-  static inline void AddSubjectSlice(FixedArrayBuilder* builder,
-                                     int from,
-                                     int to) {
-    DCHECK(from >= 0);
-    int length = to - from;
-    DCHECK(length > 0);
-    if (StringBuilderSubstringLength::is_valid(length) &&
-        StringBuilderSubstringPosition::is_valid(from)) {
-      int encoded_slice = StringBuilderSubstringLength::encode(length) |
-          StringBuilderSubstringPosition::encode(from);
-      builder->Add(Smi::FromInt(encoded_slice));
-    } else {
-      // Otherwise encode as two smis.
-      builder->Add(Smi::FromInt(-length));
-      builder->Add(Smi::FromInt(from));
-    }
-  }
-
-
-  void EnsureCapacity(int elements) {
-    array_builder_.EnsureCapacity(elements);
-  }
-
-
-  void AddSubjectSlice(int from, int to) {
-    AddSubjectSlice(&array_builder_, from, to);
-    IncrementCharacterCount(to - from);
-  }
-
-
-  void AddString(Handle<String> string) {
-    int length = string->length();
-    DCHECK(length > 0);
-    AddElement(*string);
-    if (!string->IsOneByteRepresentation()) {
-      is_one_byte_ = false;
-    }
-    IncrementCharacterCount(length);
-  }
-
-
-  MaybeHandle<String> ToString() {
-    Isolate* isolate = heap_->isolate();
-    if (array_builder_.length() == 0) {
-      return isolate->factory()->empty_string();
-    }
-
-    Handle<String> joined_string;
-    if (is_one_byte_) {
-      Handle<SeqOneByteString> seq;
-      ASSIGN_RETURN_ON_EXCEPTION(
-          isolate, seq,
-          isolate->factory()->NewRawOneByteString(character_count_),
-          String);
-
-      DisallowHeapAllocation no_gc;
-      uint8_t* char_buffer = seq->GetChars();
-      StringBuilderConcatHelper(*subject_,
-                                char_buffer,
-                                *array_builder_.array(),
-                                array_builder_.length());
-      joined_string = Handle<String>::cast(seq);
-    } else {
-      // Two-byte.
-      Handle<SeqTwoByteString> seq;
-      ASSIGN_RETURN_ON_EXCEPTION(
-          isolate, seq,
-          isolate->factory()->NewRawTwoByteString(character_count_),
-          String);
-
-      DisallowHeapAllocation no_gc;
-      uc16* char_buffer = seq->GetChars();
-      StringBuilderConcatHelper(*subject_,
-                                char_buffer,
-                                *array_builder_.array(),
-                                array_builder_.length());
-      joined_string = Handle<String>::cast(seq);
-    }
-    return joined_string;
-  }
-
-
-  void IncrementCharacterCount(int by) {
-    if (character_count_ > String::kMaxLength - by) {
-      STATIC_ASSERT(String::kMaxLength < kMaxInt);
-      character_count_ = kMaxInt;
-    } else {
-      character_count_ += by;
-    }
-  }
-
- private:
-  void AddElement(Object* element) {
-    DCHECK(element->IsSmi() || element->IsString());
-    DCHECK(array_builder_.capacity() > array_builder_.length());
-    array_builder_.Add(element);
-  }
-
-  Heap* heap_;
-  FixedArrayBuilder array_builder_;
-  Handle<String> subject_;
-  int character_count_;
-  bool is_one_byte_;
-};
-
-
-class CompiledReplacement {
- public:
-  explicit CompiledReplacement(Zone* zone)
-      : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {}
-
-  // Return whether the replacement is simple.
-  bool Compile(Handle<String> replacement,
-               int capture_count,
-               int subject_length);
-
-  // Use Apply only if Compile returned false.
-  void Apply(ReplacementStringBuilder* builder,
-             int match_from,
-             int match_to,
-             int32_t* match);
-
-  // Number of distinct parts of the replacement pattern.
-  int parts() {
-    return parts_.length();
-  }
-
-  Zone* zone() const { return zone_; }
-
- private:
-  enum PartType {
-    SUBJECT_PREFIX = 1,
-    SUBJECT_SUFFIX,
-    SUBJECT_CAPTURE,
-    REPLACEMENT_SUBSTRING,
-    REPLACEMENT_STRING,
-
-    NUMBER_OF_PART_TYPES
-  };
-
-  struct ReplacementPart {
-    static inline ReplacementPart SubjectMatch() {
-      return ReplacementPart(SUBJECT_CAPTURE, 0);
-    }
-    static inline ReplacementPart SubjectCapture(int capture_index) {
-      return ReplacementPart(SUBJECT_CAPTURE, capture_index);
-    }
-    static inline ReplacementPart SubjectPrefix() {
-      return ReplacementPart(SUBJECT_PREFIX, 0);
-    }
-    static inline ReplacementPart SubjectSuffix(int subject_length) {
-      return ReplacementPart(SUBJECT_SUFFIX, subject_length);
-    }
-    static inline ReplacementPart ReplacementString() {
-      return ReplacementPart(REPLACEMENT_STRING, 0);
-    }
-    static inline ReplacementPart ReplacementSubString(int from, int to) {
-      DCHECK(from >= 0);
-      DCHECK(to > from);
-      return ReplacementPart(-from, to);
-    }
-
-    // If tag <= 0 then it is the negation of a start index of a substring of
-    // the replacement pattern, otherwise it's a value from PartType.
-    ReplacementPart(int tag, int data)
-        : tag(tag), data(data) {
-      // Must be non-positive or a PartType value.
-      DCHECK(tag < NUMBER_OF_PART_TYPES);
-    }
-    // Either a value of PartType or a non-positive number that is
-    // the negation of an index into the replacement string.
-    int tag;
-    // The data value's interpretation depends on the value of tag:
-    // tag == SUBJECT_PREFIX ||
-    // tag == SUBJECT_SUFFIX:  data is unused.
-    // tag == SUBJECT_CAPTURE: data is the number of the capture.
-    // tag == REPLACEMENT_SUBSTRING ||
-    // tag == REPLACEMENT_STRING:    data is index into array of substrings
-    //                               of the replacement string.
-    // tag <= 0: Temporary representation of the substring of the replacement
-    //           string ranging over -tag .. data.
-    //           Is replaced by REPLACEMENT_{SUB,}STRING when we create the
-    //           substring objects.
-    int data;
-  };
-
-  template<typename Char>
-  bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
-                               Vector<Char> characters,
-                               int capture_count,
-                               int subject_length,
-                               Zone* zone) {
-    int length = characters.length();
-    int last = 0;
-    for (int i = 0; i < length; i++) {
-      Char c = characters[i];
-      if (c == '$') {
-        int next_index = i + 1;
-        if (next_index == length) {  // No next character!
-          break;
-        }
-        Char c2 = characters[next_index];
-        switch (c2) {
-        case '$':
-          if (i > last) {
-            // There is a substring before. Include the first "$".
-            parts->Add(ReplacementPart::ReplacementSubString(last, next_index),
-                       zone);
-            last = next_index + 1;  // Continue after the second "$".
-          } else {
-            // Let the next substring start with the second "$".
-            last = next_index;
-          }
-          i = next_index;
-          break;
-        case '`':
-          if (i > last) {
-            parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
-          }
-          parts->Add(ReplacementPart::SubjectPrefix(), zone);
-          i = next_index;
-          last = i + 1;
-          break;
-        case '\'':
-          if (i > last) {
-            parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
-          }
-          parts->Add(ReplacementPart::SubjectSuffix(subject_length), zone);
-          i = next_index;
-          last = i + 1;
-          break;
-        case '&':
-          if (i > last) {
-            parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
-          }
-          parts->Add(ReplacementPart::SubjectMatch(), zone);
-          i = next_index;
-          last = i + 1;
-          break;
-        case '0':
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9': {
-          int capture_ref = c2 - '0';
-          if (capture_ref > capture_count) {
-            i = next_index;
-            continue;
-          }
-          int second_digit_index = next_index + 1;
-          if (second_digit_index < length) {
-            // Peek ahead to see if we have two digits.
-            Char c3 = characters[second_digit_index];
-            if ('0' <= c3 && c3 <= '9') {  // Double digits.
-              int double_digit_ref = capture_ref * 10 + c3 - '0';
-              if (double_digit_ref <= capture_count) {
-                next_index = second_digit_index;
-                capture_ref = double_digit_ref;
-              }
-            }
-          }
-          if (capture_ref > 0) {
-            if (i > last) {
-              parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
-            }
-            DCHECK(capture_ref <= capture_count);
-            parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone);
-            last = next_index + 1;
-          }
-          i = next_index;
-          break;
-        }
-        default:
-          i = next_index;
-          break;
-        }
-      }
-    }
-    if (length > last) {
-      if (last == 0) {
-        // Replacement is simple.  Do not use Apply to do the replacement.
-        return true;
-      } else {
-        parts->Add(ReplacementPart::ReplacementSubString(last, length), zone);
-      }
-    }
-    return false;
-  }
-
-  ZoneList<ReplacementPart> parts_;
-  ZoneList<Handle<String> > replacement_substrings_;
-  Zone* zone_;
-};
-
-
-bool CompiledReplacement::Compile(Handle<String> replacement,
-                                  int capture_count,
-                                  int subject_length) {
-  {
-    DisallowHeapAllocation no_gc;
-    String::FlatContent content = replacement->GetFlatContent();
-    DCHECK(content.IsFlat());
-    bool simple = false;
-    if (content.IsOneByte()) {
-      simple = ParseReplacementPattern(&parts_,
-                                       content.ToOneByteVector(),
-                                       capture_count,
-                                       subject_length,
-                                       zone());
-    } else {
-      DCHECK(content.IsTwoByte());
-      simple = ParseReplacementPattern(&parts_,
-                                       content.ToUC16Vector(),
-                                       capture_count,
-                                       subject_length,
-                                       zone());
-    }
-    if (simple) return true;
-  }
-
-  Isolate* isolate = replacement->GetIsolate();
-  // Find substrings of replacement string and create them as String objects.
-  int substring_index = 0;
-  for (int i = 0, n = parts_.length(); i < n; i++) {
-    int tag = parts_[i].tag;
-    if (tag <= 0) {  // A replacement string slice.
-      int from = -tag;
-      int to = parts_[i].data;
-      replacement_substrings_.Add(
-          isolate->factory()->NewSubString(replacement, from, to), zone());
-      parts_[i].tag = REPLACEMENT_SUBSTRING;
-      parts_[i].data = substring_index;
-      substring_index++;
-    } else if (tag == REPLACEMENT_STRING) {
-      replacement_substrings_.Add(replacement, zone());
-      parts_[i].data = substring_index;
-      substring_index++;
-    }
-  }
-  return false;
-}
-
-
-void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
-                                int match_from,
-                                int match_to,
-                                int32_t* match) {
-  DCHECK_LT(0, parts_.length());
-  for (int i = 0, n = parts_.length(); i < n; i++) {
-    ReplacementPart part = parts_[i];
-    switch (part.tag) {
-      case SUBJECT_PREFIX:
-        if (match_from > 0) builder->AddSubjectSlice(0, match_from);
-        break;
-      case SUBJECT_SUFFIX: {
-        int subject_length = part.data;
-        if (match_to < subject_length) {
-          builder->AddSubjectSlice(match_to, subject_length);
-        }
-        break;
-      }
-      case SUBJECT_CAPTURE: {
-        int capture = part.data;
-        int from = match[capture * 2];
-        int to = match[capture * 2 + 1];
-        if (from >= 0 && to > from) {
-          builder->AddSubjectSlice(from, to);
-        }
-        break;
-      }
-      case REPLACEMENT_SUBSTRING:
-      case REPLACEMENT_STRING:
-        builder->AddString(replacement_substrings_[part.data]);
-        break;
-      default:
-        UNREACHABLE();
-    }
-  }
-}
-
-
-void FindOneByteStringIndices(Vector<const uint8_t> subject, char pattern,
-                              ZoneList<int>* indices, unsigned int limit,
-                              Zone* zone) {
-  DCHECK(limit > 0);
-  // Collect indices of pattern in subject using memchr.
-  // Stop after finding at most limit values.
-  const uint8_t* subject_start = subject.start();
-  const uint8_t* subject_end = subject_start + subject.length();
-  const uint8_t* pos = subject_start;
-  while (limit > 0) {
-    pos = reinterpret_cast<const uint8_t*>(
-        memchr(pos, pattern, subject_end - pos));
-    if (pos == NULL) return;
-    indices->Add(static_cast<int>(pos - subject_start), zone);
-    pos++;
-    limit--;
-  }
-}
-
-
-void FindTwoByteStringIndices(const Vector<const uc16> subject,
-                              uc16 pattern,
-                              ZoneList<int>* indices,
-                              unsigned int limit,
-                              Zone* zone) {
-  DCHECK(limit > 0);
-  const uc16* subject_start = subject.start();
-  const uc16* subject_end = subject_start + subject.length();
-  for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) {
-    if (*pos == pattern) {
-      indices->Add(static_cast<int>(pos - subject_start), zone);
-      limit--;
-    }
-  }
-}
-
-
-template <typename SubjectChar, typename PatternChar>
-void FindStringIndices(Isolate* isolate,
-                       Vector<const SubjectChar> subject,
-                       Vector<const PatternChar> pattern,
-                       ZoneList<int>* indices,
-                       unsigned int limit,
-                       Zone* zone) {
-  DCHECK(limit > 0);
-  // Collect indices of pattern in subject.
-  // Stop after finding at most limit values.
-  int pattern_length = pattern.length();
-  int index = 0;
-  StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
-  while (limit > 0) {
-    index = search.Search(subject, index);
-    if (index < 0) return;
-    indices->Add(index, zone);
-    index += pattern_length;
-    limit--;
-  }
-}
-
-
-void FindStringIndicesDispatch(Isolate* isolate,
-                               String* subject,
-                               String* pattern,
-                               ZoneList<int>* indices,
-                               unsigned int limit,
-                               Zone* zone) {
-  {
-    DisallowHeapAllocation no_gc;
-    String::FlatContent subject_content = subject->GetFlatContent();
-    String::FlatContent pattern_content = pattern->GetFlatContent();
-    DCHECK(subject_content.IsFlat());
-    DCHECK(pattern_content.IsFlat());
-    if (subject_content.IsOneByte()) {
-      Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
-      if (pattern_content.IsOneByte()) {
-        Vector<const uint8_t> pattern_vector =
-            pattern_content.ToOneByteVector();
-        if (pattern_vector.length() == 1) {
-          FindOneByteStringIndices(subject_vector, pattern_vector[0], indices,
-                                   limit, zone);
-        } else {
-          FindStringIndices(isolate,
-                            subject_vector,
-                            pattern_vector,
-                            indices,
-                            limit,
-                            zone);
-        }
-      } else {
-        FindStringIndices(isolate,
-                          subject_vector,
-                          pattern_content.ToUC16Vector(),
-                          indices,
-                          limit,
-                          zone);
-      }
-    } else {
-      Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
-      if (pattern_content.IsOneByte()) {
-        Vector<const uint8_t> pattern_vector =
-            pattern_content.ToOneByteVector();
-        if (pattern_vector.length() == 1) {
-          FindTwoByteStringIndices(subject_vector,
-                                   pattern_vector[0],
-                                   indices,
-                                   limit,
-                                   zone);
-        } else {
-          FindStringIndices(isolate,
-                            subject_vector,
-                            pattern_vector,
-                            indices,
-                            limit,
-                            zone);
-        }
-      } else {
-        Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector();
-        if (pattern_vector.length() == 1) {
-          FindTwoByteStringIndices(subject_vector,
-                                   pattern_vector[0],
-                                   indices,
-                                   limit,
-                                   zone);
-        } else {
-          FindStringIndices(isolate,
-                            subject_vector,
-                            pattern_vector,
-                            indices,
-                            limit,
-                            zone);
-        }
-      }
-    }
-  }
-}
-
-
-template<typename ResultSeqString>
-MUST_USE_RESULT static Object* StringReplaceGlobalAtomRegExpWithString(
-    Isolate* isolate,
-    Handle<String> subject,
-    Handle<JSRegExp> pattern_regexp,
-    Handle<String> replacement,
-    Handle<JSArray> last_match_info) {
-  DCHECK(subject->IsFlat());
-  DCHECK(replacement->IsFlat());
-
-  ZoneScope zone_scope(isolate->runtime_zone());
-  ZoneList<int> indices(8, zone_scope.zone());
-  DCHECK_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
-  String* pattern =
-      String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
-  int subject_len = subject->length();
-  int pattern_len = pattern->length();
-  int replacement_len = replacement->length();
-
-  FindStringIndicesDispatch(
-      isolate, *subject, pattern, &indices, 0xffffffff, zone_scope.zone());
-
-  int matches = indices.length();
-  if (matches == 0) return *subject;
-
-  // Detect integer overflow.
-  int64_t result_len_64 =
-      (static_cast<int64_t>(replacement_len) -
-       static_cast<int64_t>(pattern_len)) *
-      static_cast<int64_t>(matches) +
-      static_cast<int64_t>(subject_len);
-  int result_len;
-  if (result_len_64 > static_cast<int64_t>(String::kMaxLength)) {
-    STATIC_ASSERT(String::kMaxLength < kMaxInt);
-    result_len = kMaxInt;  // Provoke exception.
-  } else {
-    result_len = static_cast<int>(result_len_64);
-  }
-
-  int subject_pos = 0;
-  int result_pos = 0;
-
-  MaybeHandle<SeqString> maybe_res;
-  if (ResultSeqString::kHasOneByteEncoding) {
-    maybe_res = isolate->factory()->NewRawOneByteString(result_len);
-  } else {
-    maybe_res = isolate->factory()->NewRawTwoByteString(result_len);
-  }
-  Handle<SeqString> untyped_res;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, untyped_res, maybe_res);
-  Handle<ResultSeqString> result = Handle<ResultSeqString>::cast(untyped_res);
-
-  for (int i = 0; i < matches; i++) {
-    // Copy non-matched subject content.
-    if (subject_pos < indices.at(i)) {
-      String::WriteToFlat(*subject,
-                          result->GetChars() + result_pos,
-                          subject_pos,
-                          indices.at(i));
-      result_pos += indices.at(i) - subject_pos;
-    }
-
-    // Replace match.
-    if (replacement_len > 0) {
-      String::WriteToFlat(*replacement,
-                          result->GetChars() + result_pos,
-                          0,
-                          replacement_len);
-      result_pos += replacement_len;
-    }
-
-    subject_pos = indices.at(i) + pattern_len;
-  }
-  // Add remaining subject content at the end.
-  if (subject_pos < subject_len) {
-    String::WriteToFlat(*subject,
-                        result->GetChars() + result_pos,
-                        subject_pos,
-                        subject_len);
-  }
-
-  int32_t match_indices[] = { indices.at(matches - 1),
-                              indices.at(matches - 1) + pattern_len };
-  RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices);
-
-  return *result;
-}
-
-
-MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString(
-    Isolate* isolate,
-    Handle<String> subject,
-    Handle<JSRegExp> regexp,
-    Handle<String> replacement,
-    Handle<JSArray> last_match_info) {
-  DCHECK(subject->IsFlat());
-  DCHECK(replacement->IsFlat());
-
-  int capture_count = regexp->CaptureCount();
-  int subject_length = subject->length();
-
-  // CompiledReplacement uses zone allocation.
-  ZoneScope zone_scope(isolate->runtime_zone());
-  CompiledReplacement compiled_replacement(zone_scope.zone());
-  bool simple_replace = compiled_replacement.Compile(replacement,
-                                                     capture_count,
-                                                     subject_length);
-
-  // Shortcut for simple non-regexp global replacements
-  if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) {
-    if (subject->HasOnlyOneByteChars() &&
-        replacement->HasOnlyOneByteChars()) {
-      return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
-          isolate, subject, regexp, replacement, last_match_info);
-    } else {
-      return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
-          isolate, subject, regexp, replacement, last_match_info);
-    }
-  }
-
-  RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
-  if (global_cache.HasException()) return isolate->heap()->exception();
-
-  int32_t* current_match = global_cache.FetchNext();
-  if (current_match == NULL) {
-    if (global_cache.HasException()) return isolate->heap()->exception();
-    return *subject;
-  }
-
-  // Guessing the number of parts that the final result string is built
-  // from. Global regexps can match any number of times, so we guess
-  // conservatively.
-  int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1;
-  ReplacementStringBuilder builder(isolate->heap(),
-                                   subject,
-                                   expected_parts);
-
-  // Number of parts added by compiled replacement plus preceeding
-  // string and possibly suffix after last match.  It is possible for
-  // all components to use two elements when encoded as two smis.
-  const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
-
-  int prev = 0;
-
-  do {
-    builder.EnsureCapacity(parts_added_per_loop);
-
-    int start = current_match[0];
-    int end = current_match[1];
-
-    if (prev < start) {
-      builder.AddSubjectSlice(prev, start);
-    }
-
-    if (simple_replace) {
-      builder.AddString(replacement);
-    } else {
-      compiled_replacement.Apply(&builder,
-                                 start,
-                                 end,
-                                 current_match);
-    }
-    prev = end;
-
-    current_match = global_cache.FetchNext();
-  } while (current_match != NULL);
-
-  if (global_cache.HasException()) return isolate->heap()->exception();
-
-  if (prev < subject_length) {
-    builder.EnsureCapacity(2);
-    builder.AddSubjectSlice(prev, subject_length);
-  }
-
-  RegExpImpl::SetLastMatchInfo(last_match_info,
-                               subject,
-                               capture_count,
-                               global_cache.LastSuccessfulMatch());
-
-  Handle<String> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, builder.ToString());
-  return *result;
-}
-
-
-template <typename ResultSeqString>
-MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString(
-    Isolate* isolate,
-    Handle<String> subject,
-    Handle<JSRegExp> regexp,
-    Handle<JSArray> last_match_info) {
-  DCHECK(subject->IsFlat());
-
-  // Shortcut for simple non-regexp global replacements
-  if (regexp->TypeTag() == JSRegExp::ATOM) {
-    Handle<String> empty_string = isolate->factory()->empty_string();
-    if (subject->IsOneByteRepresentation()) {
-      return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
-          isolate, subject, regexp, empty_string, last_match_info);
-    } else {
-      return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
-          isolate, subject, regexp, empty_string, last_match_info);
-    }
-  }
-
-  RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
-  if (global_cache.HasException()) return isolate->heap()->exception();
-
-  int32_t* current_match = global_cache.FetchNext();
-  if (current_match == NULL) {
-    if (global_cache.HasException()) return isolate->heap()->exception();
-    return *subject;
-  }
-
-  int start = current_match[0];
-  int end = current_match[1];
-  int capture_count = regexp->CaptureCount();
-  int subject_length = subject->length();
-
-  int new_length = subject_length - (end - start);
-  if (new_length == 0) return isolate->heap()->empty_string();
-
-  Handle<ResultSeqString> answer;
-  if (ResultSeqString::kHasOneByteEncoding) {
-    answer = Handle<ResultSeqString>::cast(
-        isolate->factory()->NewRawOneByteString(new_length).ToHandleChecked());
-  } else {
-    answer = Handle<ResultSeqString>::cast(
-        isolate->factory()->NewRawTwoByteString(new_length).ToHandleChecked());
-  }
-
-  int prev = 0;
-  int position = 0;
-
-  do {
-    start = current_match[0];
-    end = current_match[1];
-    if (prev < start) {
-      // Add substring subject[prev;start] to answer string.
-      String::WriteToFlat(*subject, answer->GetChars() + position, prev, start);
-      position += start - prev;
-    }
-    prev = end;
-
-    current_match = global_cache.FetchNext();
-  } while (current_match != NULL);
-
-  if (global_cache.HasException()) return isolate->heap()->exception();
-
-  RegExpImpl::SetLastMatchInfo(last_match_info,
-                               subject,
-                               capture_count,
-                               global_cache.LastSuccessfulMatch());
-
-  if (prev < subject_length) {
-    // Add substring subject[prev;length] to answer string.
-    String::WriteToFlat(
-        *subject, answer->GetChars() + position, prev, subject_length);
-    position += subject_length - prev;
-  }
-
-  if (position == 0) return isolate->heap()->empty_string();
-
-  // Shorten string and fill
-  int string_size = ResultSeqString::SizeFor(position);
-  int allocated_string_size = ResultSeqString::SizeFor(new_length);
-  int delta = allocated_string_size - string_size;
-
-  answer->set_length(position);
-  if (delta == 0) return *answer;
-
-  Address end_of_string = answer->address() + string_size;
-  Heap* heap = isolate->heap();
-
-  // The trimming is performed on a newly allocated object, which is on a
-  // fresly allocated page or on an already swept page. Hence, the sweeper
-  // thread can not get confused with the filler creation. No synchronization
-  // needed.
-  heap->CreateFillerObjectAt(end_of_string, delta);
-  heap->AdjustLiveBytes(answer->address(), -delta, Heap::FROM_MUTATOR);
-  return *answer;
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
-
-  RUNTIME_ASSERT(regexp->GetFlags().is_global());
-  RUNTIME_ASSERT(last_match_info->HasFastObjectElements());
-
-  subject = String::Flatten(subject);
-
-  if (replacement->length() == 0) {
-    if (subject->HasOnlyOneByteChars()) {
-      return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>(
-          isolate, subject, regexp, last_match_info);
-    } else {
-      return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>(
-          isolate, subject, regexp, last_match_info);
-    }
-  }
-
-  replacement = String::Flatten(replacement);
-
-  return StringReplaceGlobalRegExpWithString(
-      isolate, subject, regexp, replacement, last_match_info);
-}
-
-
-// This may return an empty MaybeHandle if an exception is thrown or
-// we abort due to reaching the recursion limit.
-MaybeHandle<String> StringReplaceOneCharWithString(Isolate* isolate,
-                                                   Handle<String> subject,
-                                                   Handle<String> search,
-                                                   Handle<String> replace,
-                                                   bool* found,
-                                                   int recursion_limit) {
-  StackLimitCheck stackLimitCheck(isolate);
-  if (stackLimitCheck.HasOverflowed() || (recursion_limit == 0)) {
-    return MaybeHandle<String>();
-  }
-  recursion_limit--;
-  if (subject->IsConsString()) {
-    ConsString* cons = ConsString::cast(*subject);
-    Handle<String> first = Handle<String>(cons->first());
-    Handle<String> second = Handle<String>(cons->second());
-    Handle<String> new_first;
-    if (!StringReplaceOneCharWithString(
-            isolate, first, search, replace, found, recursion_limit)
-            .ToHandle(&new_first)) {
-      return MaybeHandle<String>();
-    }
-    if (*found) return isolate->factory()->NewConsString(new_first, second);
-
-    Handle<String> new_second;
-    if (!StringReplaceOneCharWithString(
-            isolate, second, search, replace, found, recursion_limit)
-            .ToHandle(&new_second)) {
-      return MaybeHandle<String>();
-    }
-    if (*found) return isolate->factory()->NewConsString(first, new_second);
-
-    return subject;
-  } else {
-    int index = Runtime::StringMatch(isolate, subject, search, 0);
-    if (index == -1) return subject;
-    *found = true;
-    Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
-    Handle<String> cons1;
-    ASSIGN_RETURN_ON_EXCEPTION(
-        isolate, cons1,
-        isolate->factory()->NewConsString(first, replace),
-        String);
-    Handle<String> second =
-        isolate->factory()->NewSubString(subject, index + 1, subject->length());
-    return isolate->factory()->NewConsString(cons1, second);
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringReplaceOneCharWithString) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
-
-  // If the cons string tree is too deep, we simply abort the recursion and
-  // retry with a flattened subject string.
-  const int kRecursionLimit = 0x1000;
-  bool found = false;
-  Handle<String> result;
-  if (StringReplaceOneCharWithString(
-          isolate, subject, search, replace, &found, kRecursionLimit)
-          .ToHandle(&result)) {
-    return *result;
-  }
-  if (isolate->has_pending_exception()) return isolate->heap()->exception();
-
-  subject = String::Flatten(subject);
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      StringReplaceOneCharWithString(
-          isolate, subject, search, replace, &found, kRecursionLimit));
-  return *result;
-}
-
-
-// Perform string match of pattern on subject, starting at start index.
-// Caller must ensure that 0 <= start_index <= sub->length(),
-// and should check that pat->length() + start_index <= sub->length().
-int Runtime::StringMatch(Isolate* isolate,
-                         Handle<String> sub,
-                         Handle<String> pat,
-                         int start_index) {
-  DCHECK(0 <= start_index);
-  DCHECK(start_index <= sub->length());
-
-  int pattern_length = pat->length();
-  if (pattern_length == 0) return start_index;
-
-  int subject_length = sub->length();
-  if (start_index + pattern_length > subject_length) return -1;
-
-  sub = String::Flatten(sub);
-  pat = String::Flatten(pat);
-
-  DisallowHeapAllocation no_gc;  // ensure vectors stay valid
-  // Extract flattened substrings of cons strings before getting encoding.
-  String::FlatContent seq_sub = sub->GetFlatContent();
-  String::FlatContent seq_pat = pat->GetFlatContent();
-
-  // dispatch on type of strings
-  if (seq_pat.IsOneByte()) {
-    Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector();
-    if (seq_sub.IsOneByte()) {
-      return SearchString(isolate,
-                          seq_sub.ToOneByteVector(),
-                          pat_vector,
-                          start_index);
-    }
-    return SearchString(isolate,
-                        seq_sub.ToUC16Vector(),
-                        pat_vector,
-                        start_index);
-  }
-  Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
-  if (seq_sub.IsOneByte()) {
-    return SearchString(isolate,
-                        seq_sub.ToOneByteVector(),
-                        pat_vector,
-                        start_index);
-  }
-  return SearchString(isolate,
-                      seq_sub.ToUC16Vector(),
-                      pat_vector,
-                      start_index);
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringIndexOf) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, index, 2);
-
-  uint32_t start_index;
-  if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
-
-  RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
-  int position = Runtime::StringMatch(isolate, sub, pat, start_index);
-  return Smi::FromInt(position);
-}
-
-
-template <typename schar, typename pchar>
-static int StringMatchBackwards(Vector<const schar> subject,
-                                Vector<const pchar> pattern,
-                                int idx) {
-  int pattern_length = pattern.length();
-  DCHECK(pattern_length >= 1);
-  DCHECK(idx + pattern_length <= subject.length());
-
-  if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
-    for (int i = 0; i < pattern_length; i++) {
-      uc16 c = pattern[i];
-      if (c > String::kMaxOneByteCharCode) {
-        return -1;
-      }
-    }
-  }
-
-  pchar pattern_first_char = pattern[0];
-  for (int i = idx; i >= 0; i--) {
-    if (subject[i] != pattern_first_char) continue;
-    int j = 1;
-    while (j < pattern_length) {
-      if (pattern[j] != subject[i+j]) {
-        break;
-      }
-      j++;
-    }
-    if (j == pattern_length) {
-      return i;
-    }
-  }
-  return -1;
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringLastIndexOf) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, index, 2);
-
-  uint32_t start_index;
-  if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
-
-  uint32_t pat_length = pat->length();
-  uint32_t sub_length = sub->length();
-
-  if (start_index + pat_length > sub_length) {
-    start_index = sub_length - pat_length;
-  }
-
-  if (pat_length == 0) {
-    return Smi::FromInt(start_index);
-  }
-
-  sub = String::Flatten(sub);
-  pat = String::Flatten(pat);
-
-  int position = -1;
-  DisallowHeapAllocation no_gc;  // ensure vectors stay valid
-
-  String::FlatContent sub_content = sub->GetFlatContent();
-  String::FlatContent pat_content = pat->GetFlatContent();
-
-  if (pat_content.IsOneByte()) {
-    Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector();
-    if (sub_content.IsOneByte()) {
-      position = StringMatchBackwards(sub_content.ToOneByteVector(),
-                                      pat_vector,
-                                      start_index);
-    } else {
-      position = StringMatchBackwards(sub_content.ToUC16Vector(),
-                                      pat_vector,
-                                      start_index);
-    }
-  } else {
-    Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
-    if (sub_content.IsOneByte()) {
-      position = StringMatchBackwards(sub_content.ToOneByteVector(),
-                                      pat_vector,
-                                      start_index);
-    } else {
-      position = StringMatchBackwards(sub_content.ToUC16Vector(),
-                                      pat_vector,
-                                      start_index);
-    }
-  }
-
-  return Smi::FromInt(position);
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringLocaleCompare) {
-  HandleScope handle_scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, str1, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, str2, 1);
-
-  if (str1.is_identical_to(str2)) return Smi::FromInt(0);  // Equal.
-  int str1_length = str1->length();
-  int str2_length = str2->length();
-
-  // Decide trivial cases without flattening.
-  if (str1_length == 0) {
-    if (str2_length == 0) return Smi::FromInt(0);  // Equal.
-    return Smi::FromInt(-str2_length);
-  } else {
-    if (str2_length == 0) return Smi::FromInt(str1_length);
-  }
-
-  int end = str1_length < str2_length ? str1_length : str2_length;
-
-  // No need to flatten if we are going to find the answer on the first
-  // character.  At this point we know there is at least one character
-  // in each string, due to the trivial case handling above.
-  int d = str1->Get(0) - str2->Get(0);
-  if (d != 0) return Smi::FromInt(d);
-
-  str1 = String::Flatten(str1);
-  str2 = String::Flatten(str2);
-
-  DisallowHeapAllocation no_gc;
-  String::FlatContent flat1 = str1->GetFlatContent();
-  String::FlatContent flat2 = str2->GetFlatContent();
-
-  for (int i = 0; i < end; i++) {
-    if (flat1.Get(i) != flat2.Get(i)) {
-      return Smi::FromInt(flat1.Get(i) - flat2.Get(i));
-    }
-  }
-
-  return Smi::FromInt(str1_length - str2_length);
-}
-
-
-RUNTIME_FUNCTION(Runtime_SubString) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
-  int start, end;
-  // We have a fast integer-only case here to avoid a conversion to double in
-  // the common case where from and to are Smis.
-  if (args[1]->IsSmi() && args[2]->IsSmi()) {
-    CONVERT_SMI_ARG_CHECKED(from_number, 1);
-    CONVERT_SMI_ARG_CHECKED(to_number, 2);
-    start = from_number;
-    end = to_number;
-  } else {
-    CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
-    CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
-    start = FastD2IChecked(from_number);
-    end = FastD2IChecked(to_number);
-  }
-  RUNTIME_ASSERT(end >= start);
-  RUNTIME_ASSERT(start >= 0);
-  RUNTIME_ASSERT(end <= string->length());
-  isolate->counters()->sub_string_runtime()->Increment();
-
-  return *isolate->factory()->NewSubString(string, start, end);
-}
-
-
-RUNTIME_FUNCTION(Runtime_InternalizeString) {
-  HandleScope handles(isolate);
-  RUNTIME_ASSERT(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
-  return *isolate->factory()->InternalizeString(string);
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringMatch) {
-  HandleScope handles(isolate);
-  DCHECK(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
-
-  RUNTIME_ASSERT(regexp_info->HasFastObjectElements());
-
-  RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
-  if (global_cache.HasException()) return isolate->heap()->exception();
-
-  int capture_count = regexp->CaptureCount();
-
-  ZoneScope zone_scope(isolate->runtime_zone());
-  ZoneList<int> offsets(8, zone_scope.zone());
-
-  while (true) {
-    int32_t* match = global_cache.FetchNext();
-    if (match == NULL) break;
-    offsets.Add(match[0], zone_scope.zone());  // start
-    offsets.Add(match[1], zone_scope.zone());  // end
-  }
-
-  if (global_cache.HasException()) return isolate->heap()->exception();
-
-  if (offsets.length() == 0) {
-    // Not a single match.
-    return isolate->heap()->null_value();
-  }
-
-  RegExpImpl::SetLastMatchInfo(regexp_info,
-                               subject,
-                               capture_count,
-                               global_cache.LastSuccessfulMatch());
-
-  int matches = offsets.length() / 2;
-  Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
-  Handle<String> substring =
-      isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1));
-  elements->set(0, *substring);
-  for (int i = 1; i < matches; i++) {
-    HandleScope temp_scope(isolate);
-    int from = offsets.at(i * 2);
-    int to = offsets.at(i * 2 + 1);
-    Handle<String> substring =
-        isolate->factory()->NewProperSubString(subject, from, to);
-    elements->set(i, *substring);
-  }
-  Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
-  result->set_length(Smi::FromInt(matches));
-  return *result;
-}
-
-
-// Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
-// separate last match info.  See comment on that function.
-template<bool has_capture>
-static Object* SearchRegExpMultiple(
-    Isolate* isolate,
-    Handle<String> subject,
-    Handle<JSRegExp> regexp,
-    Handle<JSArray> last_match_array,
-    Handle<JSArray> result_array) {
-  DCHECK(subject->IsFlat());
-  DCHECK_NE(has_capture, regexp->CaptureCount() == 0);
-
-  int capture_count = regexp->CaptureCount();
-  int subject_length = subject->length();
-
-  static const int kMinLengthToCache = 0x1000;
-
-  if (subject_length > kMinLengthToCache) {
-    Handle<Object> cached_answer(RegExpResultsCache::Lookup(
-        isolate->heap(),
-        *subject,
-        regexp->data(),
-        RegExpResultsCache::REGEXP_MULTIPLE_INDICES), isolate);
-    if (*cached_answer != Smi::FromInt(0)) {
-      Handle<FixedArray> cached_fixed_array =
-          Handle<FixedArray>(FixedArray::cast(*cached_answer));
-      // The cache FixedArray is a COW-array and can therefore be reused.
-      JSArray::SetContent(result_array, cached_fixed_array);
-      // The actual length of the result array is stored in the last element of
-      // the backing store (the backing FixedArray may have a larger capacity).
-      Object* cached_fixed_array_last_element =
-          cached_fixed_array->get(cached_fixed_array->length() - 1);
-      Smi* js_array_length = Smi::cast(cached_fixed_array_last_element);
-      result_array->set_length(js_array_length);
-      RegExpImpl::SetLastMatchInfo(
-          last_match_array, subject, capture_count, NULL);
-      return *result_array;
-    }
-  }
-
-  RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
-  if (global_cache.HasException()) return isolate->heap()->exception();
-
-  // Ensured in Runtime_RegExpExecMultiple.
-  DCHECK(result_array->HasFastObjectElements());
-  Handle<FixedArray> result_elements(
-      FixedArray::cast(result_array->elements()));
-  if (result_elements->length() < 16) {
-    result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
-  }
-
-  FixedArrayBuilder builder(result_elements);
-
-  // Position to search from.
-  int match_start = -1;
-  int match_end = 0;
-  bool first = true;
-
-  // Two smis before and after the match, for very long strings.
-  static const int kMaxBuilderEntriesPerRegExpMatch = 5;
-
-  while (true) {
-    int32_t* current_match = global_cache.FetchNext();
-    if (current_match == NULL) break;
-    match_start = current_match[0];
-    builder.EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
-    if (match_end < match_start) {
-      ReplacementStringBuilder::AddSubjectSlice(&builder,
-                                                match_end,
-                                                match_start);
-    }
-    match_end = current_match[1];
-    {
-      // Avoid accumulating new handles inside loop.
-      HandleScope temp_scope(isolate);
-      Handle<String> match;
-      if (!first) {
-        match = isolate->factory()->NewProperSubString(subject,
-                                                       match_start,
-                                                       match_end);
-      } else {
-        match = isolate->factory()->NewSubString(subject,
-                                                 match_start,
-                                                 match_end);
-        first = false;
-      }
-
-      if (has_capture) {
-        // Arguments array to replace function is match, captures, index and
-        // subject, i.e., 3 + capture count in total.
-        Handle<FixedArray> elements =
-            isolate->factory()->NewFixedArray(3 + capture_count);
-
-        elements->set(0, *match);
-        for (int i = 1; i <= capture_count; i++) {
-          int start = current_match[i * 2];
-          if (start >= 0) {
-            int end = current_match[i * 2 + 1];
-            DCHECK(start <= end);
-            Handle<String> substring =
-                isolate->factory()->NewSubString(subject, start, end);
-            elements->set(i, *substring);
-          } else {
-            DCHECK(current_match[i * 2 + 1] < 0);
-            elements->set(i, isolate->heap()->undefined_value());
-          }
-        }
-        elements->set(capture_count + 1, Smi::FromInt(match_start));
-        elements->set(capture_count + 2, *subject);
-        builder.Add(*isolate->factory()->NewJSArrayWithElements(elements));
-      } else {
-        builder.Add(*match);
-      }
-    }
-  }
-
-  if (global_cache.HasException()) return isolate->heap()->exception();
-
-  if (match_start >= 0) {
-    // Finished matching, with at least one match.
-    if (match_end < subject_length) {
-      ReplacementStringBuilder::AddSubjectSlice(&builder,
-                                                match_end,
-                                                subject_length);
-    }
-
-    RegExpImpl::SetLastMatchInfo(
-        last_match_array, subject, capture_count, NULL);
-
-    if (subject_length > kMinLengthToCache) {
-      // Store the length of the result array into the last element of the
-      // backing FixedArray.
-      builder.EnsureCapacity(1);
-      Handle<FixedArray> fixed_array = builder.array();
-      fixed_array->set(fixed_array->length() - 1,
-                       Smi::FromInt(builder.length()));
-      // Cache the result and turn the FixedArray into a COW array.
-      RegExpResultsCache::Enter(isolate,
-                                subject,
-                                handle(regexp->data(), isolate),
-                                fixed_array,
-                                RegExpResultsCache::REGEXP_MULTIPLE_INDICES);
-    }
-    return *builder.ToJSArray(result_array);
-  } else {
-    return isolate->heap()->null_value();  // No matches at all.
-  }
-}
-
-
-// This is only called for StringReplaceGlobalRegExpWithFunction.  This sets
-// lastMatchInfoOverride to maintain the last match info, so we don't need to
-// set any other last match array info.
-RUNTIME_FUNCTION(Runtime_RegExpExecMultiple) {
-  HandleScope handles(isolate);
-  DCHECK(args.length() == 4);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
-  RUNTIME_ASSERT(last_match_info->HasFastObjectElements());
-  RUNTIME_ASSERT(result_array->HasFastObjectElements());
-
-  subject = String::Flatten(subject);
-  RUNTIME_ASSERT(regexp->GetFlags().is_global());
-
-  if (regexp->CaptureCount() == 0) {
-    return SearchRegExpMultiple<false>(
-        isolate, subject, regexp, last_match_info, result_array);
-  } else {
-    return SearchRegExpMultiple<true>(
-        isolate, subject, regexp, last_match_info, result_array);
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberToRadixString) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_SMI_ARG_CHECKED(radix, 1);
-  RUNTIME_ASSERT(2 <= radix && radix <= 36);
-
-  // Fast case where the result is a one character string.
-  if (args[0]->IsSmi()) {
-    int value = args.smi_at(0);
-    if (value >= 0 && value < radix) {
-      // Character array used for conversion.
-      static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
-      return *isolate->factory()->
-          LookupSingleCharacterStringFromCode(kCharTable[value]);
-    }
-  }
-
-  // Slow case.
-  CONVERT_DOUBLE_ARG_CHECKED(value, 0);
-  if (std::isnan(value)) {
-    return isolate->heap()->nan_string();
-  }
-  if (std::isinf(value)) {
-    if (value < 0) {
-      return isolate->heap()->minus_infinity_string();
-    }
-    return isolate->heap()->infinity_string();
-  }
-  char* str = DoubleToRadixCString(value, radix);
-  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
-  DeleteArray(str);
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberToFixed) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_DOUBLE_ARG_CHECKED(value, 0);
-  CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
-  int f = FastD2IChecked(f_number);
-  // See DoubleToFixedCString for these constants:
-  RUNTIME_ASSERT(f >= 0 && f <= 20);
-  RUNTIME_ASSERT(!Double(value).IsSpecial());
-  char* str = DoubleToFixedCString(value, f);
-  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
-  DeleteArray(str);
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberToExponential) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_DOUBLE_ARG_CHECKED(value, 0);
-  CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
-  int f = FastD2IChecked(f_number);
-  RUNTIME_ASSERT(f >= -1 && f <= 20);
-  RUNTIME_ASSERT(!Double(value).IsSpecial());
-  char* str = DoubleToExponentialCString(value, f);
-  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
-  DeleteArray(str);
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberToPrecision) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_DOUBLE_ARG_CHECKED(value, 0);
-  CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
-  int f = FastD2IChecked(f_number);
-  RUNTIME_ASSERT(f >= 1 && f <= 21);
-  RUNTIME_ASSERT(!Double(value).IsSpecial());
-  char* str = DoubleToPrecisionCString(value, f);
-  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
-  DeleteArray(str);
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsValidSmi) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]);
-  return isolate->heap()->ToBoolean(Smi::IsValid(number));
-}
-
-
-// Returns a single character string where first character equals
-// string->Get(index).
-static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
-  if (index < static_cast<uint32_t>(string->length())) {
-    Factory* factory = string->GetIsolate()->factory();
-    return factory->LookupSingleCharacterStringFromCode(
-        String::Flatten(string)->Get(index));
-  }
-  return Execution::CharAt(string, index);
-}
-
-
-MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate,
-                                                Handle<Object> object,
-                                                uint32_t index) {
-  // Handle [] indexing on Strings
-  if (object->IsString()) {
-    Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
-    if (!result->IsUndefined()) return result;
-  }
-
-  // Handle [] indexing on String objects
-  if (object->IsStringObjectWithCharacterAt(index)) {
-    Handle<JSValue> js_value = Handle<JSValue>::cast(object);
-    Handle<Object> result =
-        GetCharAt(Handle<String>(String::cast(js_value->value())), index);
-    if (!result->IsUndefined()) return result;
-  }
-
-  Handle<Object> result;
-  if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
-    PrototypeIterator iter(isolate, object);
-    return Object::GetElement(isolate, PrototypeIterator::GetCurrent(iter),
-                              index);
-  } else {
-    return Object::GetElement(isolate, object, index);
-  }
-}
-
-
-MUST_USE_RESULT
-static MaybeHandle<Name> ToName(Isolate* isolate, Handle<Object> key) {
-  if (key->IsName()) {
-    return Handle<Name>::cast(key);
-  } else {
-    Handle<Object> converted;
-    ASSIGN_RETURN_ON_EXCEPTION(
-        isolate, converted, Execution::ToString(isolate, key), Name);
-    return Handle<Name>::cast(converted);
-  }
-}
-
-
-MaybeHandle<Object> Runtime::HasObjectProperty(Isolate* isolate,
-                                               Handle<JSReceiver> object,
-                                               Handle<Object> key) {
-  Maybe<bool> maybe;
-  // Check if the given key is an array index.
-  uint32_t index;
-  if (key->ToArrayIndex(&index)) {
-    maybe = JSReceiver::HasElement(object, index);
-  } else {
-    // Convert the key to a name - possibly by calling back into JavaScript.
-    Handle<Name> name;
-    ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
-
-    maybe = JSReceiver::HasProperty(object, name);
-  }
-
-  if (!maybe.has_value) return MaybeHandle<Object>();
-  return isolate->factory()->ToBoolean(maybe.value);
-}
-
-
-MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
-                                               Handle<Object> object,
-                                               Handle<Object> key) {
-  if (object->IsUndefined() || object->IsNull()) {
-    Handle<Object> args[2] = { key, object };
-    THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_load",
-                                          HandleVector(args, 2)),
-                    Object);
-  }
-
-  // Check if the given key is an array index.
-  uint32_t index;
-  if (key->ToArrayIndex(&index)) {
-    return GetElementOrCharAt(isolate, object, index);
-  }
-
-  // Convert the key to a name - possibly by calling back into JavaScript.
-  Handle<Name> name;
-  ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
-
-  // Check if the name is trivially convertible to an index and get
-  // the element if so.
-  if (name->AsArrayIndex(&index)) {
-    return GetElementOrCharAt(isolate, object, index);
-  } else {
-    return Object::GetProperty(object, name);
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetProperty) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      Runtime::GetObjectProperty(isolate, object, key));
-  return *result;
-}
-
-
-// KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
-RUNTIME_FUNCTION(Runtime_KeyedGetProperty) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1);
-
-  // Fast cases for getting named properties of the receiver JSObject
-  // itself.
-  //
-  // The global proxy objects has to be excluded since LookupOwn on
-  // the global proxy object can return a valid result even though the
-  // global proxy object never has properties.  This is the case
-  // because the global proxy object forwards everything to its hidden
-  // prototype including own lookups.
-  //
-  // Additionally, we need to make sure that we do not cache results
-  // for objects that require access checks.
-  if (receiver_obj->IsJSObject()) {
-    if (!receiver_obj->IsJSGlobalProxy() &&
-        !receiver_obj->IsAccessCheckNeeded() &&
-        key_obj->IsName()) {
-      DisallowHeapAllocation no_allocation;
-      Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj);
-      Handle<Name> key = Handle<Name>::cast(key_obj);
-      if (receiver->HasFastProperties()) {
-        // Attempt to use lookup cache.
-        Handle<Map> receiver_map(receiver->map(), isolate);
-        KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
-        int index = keyed_lookup_cache->Lookup(receiver_map, key);
-        if (index != -1) {
-          // Doubles are not cached, so raw read the value.
-          return receiver->RawFastPropertyAt(
-              FieldIndex::ForKeyedLookupCacheIndex(*receiver_map, index));
-        }
-        // Lookup cache miss.  Perform lookup and update the cache if
-        // appropriate.
-        LookupIterator it(receiver, key, LookupIterator::OWN);
-        if (it.state() == LookupIterator::DATA &&
-            it.property_details().type() == FIELD) {
-          FieldIndex field_index = it.GetFieldIndex();
-          // Do not track double fields in the keyed lookup cache. Reading
-          // double values requires boxing.
-          if (!it.representation().IsDouble()) {
-            keyed_lookup_cache->Update(receiver_map, key,
-                field_index.GetKeyedLookupCacheIndex());
-          }
-          AllowHeapAllocation allow_allocation;
-          return *JSObject::FastPropertyAt(receiver, it.representation(),
-                                           field_index);
-        }
-      } else {
-        // Attempt dictionary lookup.
-        NameDictionary* dictionary = receiver->property_dictionary();
-        int entry = dictionary->FindEntry(key);
-        if ((entry != NameDictionary::kNotFound) &&
-            (dictionary->DetailsAt(entry).type() == NORMAL)) {
-          Object* value = dictionary->ValueAt(entry);
-          if (!receiver->IsGlobalObject()) return value;
-          value = PropertyCell::cast(value)->value();
-          if (!value->IsTheHole()) return value;
-          // If value is the hole (meaning, absent) do the general lookup.
-        }
-      }
-    } else if (key_obj->IsSmi()) {
-      // JSObject without a name key. If the key is a Smi, check for a
-      // definite out-of-bounds access to elements, which is a strong indicator
-      // that subsequent accesses will also call the runtime. Proactively
-      // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
-      // doubles for those future calls in the case that the elements would
-      // become FAST_DOUBLE_ELEMENTS.
-      Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj);
-      ElementsKind elements_kind = js_object->GetElementsKind();
-      if (IsFastDoubleElementsKind(elements_kind)) {
-        Handle<Smi> key = Handle<Smi>::cast(key_obj);
-        if (key->value() >= js_object->elements()->length()) {
-          if (IsFastHoleyElementsKind(elements_kind)) {
-            elements_kind = FAST_HOLEY_ELEMENTS;
-          } else {
-            elements_kind = FAST_ELEMENTS;
-          }
-          RETURN_FAILURE_ON_EXCEPTION(
-              isolate, TransitionElements(js_object, elements_kind, isolate));
-        }
-      } else {
-        DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
-               !IsFastElementsKind(elements_kind));
-      }
-    }
-  } else if (receiver_obj->IsString() && key_obj->IsSmi()) {
-    // Fast case for string indexing using [] with a smi index.
-    Handle<String> str = Handle<String>::cast(receiver_obj);
-    int index = args.smi_at(1);
-    if (index >= 0 && index < str->length()) {
-      return *GetCharAt(str, index);
-    }
-  }
-
-  // Fall back to GetObjectProperty.
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      Runtime::GetObjectProperty(isolate, receiver_obj, key_obj));
-  return *result;
-}
-
-
-static bool IsValidAccessor(Handle<Object> obj) {
-  return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
-}
-
-
-// Transform getter or setter into something DefineAccessor can handle.
-static Handle<Object> InstantiateAccessorComponent(Isolate* isolate,
-                                                   Handle<Object> component) {
-  if (component->IsUndefined()) return isolate->factory()->undefined_value();
-  Handle<FunctionTemplateInfo> info =
-      Handle<FunctionTemplateInfo>::cast(component);
-  return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction());
-}
-
-
-RUNTIME_FUNCTION(Runtime_DefineApiAccessorProperty) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 5);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
-  CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
-  CONVERT_SMI_ARG_CHECKED(attribute, 4);
-  RUNTIME_ASSERT(getter->IsUndefined() || getter->IsFunctionTemplateInfo());
-  RUNTIME_ASSERT(setter->IsUndefined() || setter->IsFunctionTemplateInfo());
-  RUNTIME_ASSERT(PropertyDetails::AttributesField::is_valid(
-      static_cast<PropertyAttributes>(attribute)));
-  RETURN_FAILURE_ON_EXCEPTION(
-      isolate, JSObject::DefineAccessor(
-                   object, name, InstantiateAccessorComponent(isolate, getter),
-                   InstantiateAccessorComponent(isolate, setter),
-                   static_cast<PropertyAttributes>(attribute)));
-  return isolate->heap()->undefined_value();
-}
-
-
-// Implements part of 8.12.9 DefineOwnProperty.
-// There are 3 cases that lead here:
-// Step 4b - define a new accessor property.
-// Steps 9c & 12 - replace an existing data property with an accessor property.
-// Step 12 - update an existing accessor property with an accessor or generic
-//           descriptor.
-RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 5);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-  RUNTIME_ASSERT(!obj->IsNull());
-  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
-  RUNTIME_ASSERT(IsValidAccessor(getter));
-  CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
-  RUNTIME_ASSERT(IsValidAccessor(setter));
-  CONVERT_SMI_ARG_CHECKED(unchecked, 4);
-  RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
-  PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
-
-  bool fast = obj->HasFastProperties();
-  RETURN_FAILURE_ON_EXCEPTION(
-      isolate, JSObject::DefineAccessor(obj, name, getter, setter, attr));
-  if (fast) JSObject::MigrateSlowToFast(obj, 0);
-  return isolate->heap()->undefined_value();
-}
-
-
-// Implements part of 8.12.9 DefineOwnProperty.
-// There are 3 cases that lead here:
-// Step 4a - define a new data property.
-// Steps 9b & 12 - replace an existing accessor property with a data property.
-// Step 12 - update an existing data property with a data or generic
-//           descriptor.
-RUNTIME_FUNCTION(Runtime_DefineDataPropertyUnchecked) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
-  CONVERT_SMI_ARG_CHECKED(unchecked, 3);
-  RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
-  PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
-
-  LookupIterator it(js_object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
-  if (it.IsFound() && it.state() == LookupIterator::ACCESS_CHECK) {
-    if (!isolate->MayNamedAccess(js_object, name, v8::ACCESS_SET)) {
-      return isolate->heap()->undefined_value();
-    }
-    it.Next();
-  }
-
-  // Take special care when attributes are different and there is already
-  // a property.
-  if (it.state() == LookupIterator::ACCESSOR) {
-    // Use IgnoreAttributes version since a readonly property may be
-    // overridden and SetProperty does not allow this.
-    Handle<Object> result;
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, result,
-        JSObject::SetOwnPropertyIgnoreAttributes(
-            js_object, name, obj_value, attr,
-            JSObject::DONT_FORCE_FIELD));
-    return *result;
-  }
-
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      Runtime::DefineObjectProperty(js_object, name, obj_value, attr));
-  return *result;
-}
-
-
-// Return property without being observable by accessors or interceptors.
-RUNTIME_FUNCTION(Runtime_GetDataProperty) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
-  return *JSObject::GetDataProperty(object, key);
-}
-
-
-MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
-                                               Handle<Object> object,
-                                               Handle<Object> key,
-                                               Handle<Object> value,
-                                               StrictMode strict_mode) {
-  if (object->IsUndefined() || object->IsNull()) {
-    Handle<Object> args[2] = { key, object };
-    THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_store",
-                                          HandleVector(args, 2)),
-                    Object);
-  }
-
-  if (object->IsJSProxy()) {
-    Handle<Object> name_object;
-    if (key->IsSymbol()) {
-      name_object = key;
-    } else {
-      ASSIGN_RETURN_ON_EXCEPTION(
-          isolate, name_object, Execution::ToString(isolate, key), Object);
-    }
-    Handle<Name> name = Handle<Name>::cast(name_object);
-    return Object::SetProperty(Handle<JSProxy>::cast(object), name, value,
-                               strict_mode);
-  }
-
-  // Check if the given key is an array index.
-  uint32_t index;
-  if (key->ToArrayIndex(&index)) {
-    // TODO(verwaest): Support non-JSObject receivers.
-    if (!object->IsJSObject()) return value;
-    Handle<JSObject> js_object = Handle<JSObject>::cast(object);
-
-    // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
-    // of a string using [] notation.  We need to support this too in
-    // JavaScript.
-    // In the case of a String object we just need to redirect the assignment to
-    // the underlying string if the index is in range.  Since the underlying
-    // string does nothing with the assignment then we can ignore such
-    // assignments.
-    if (js_object->IsStringObjectWithCharacterAt(index)) {
-      return value;
-    }
-
-    JSObject::ValidateElements(js_object);
-    if (js_object->HasExternalArrayElements() ||
-        js_object->HasFixedTypedArrayElements()) {
-      if (!value->IsNumber() && !value->IsUndefined()) {
-        ASSIGN_RETURN_ON_EXCEPTION(
-            isolate, value, Execution::ToNumber(isolate, value), Object);
-      }
-    }
-
-    MaybeHandle<Object> result = JSObject::SetElement(
-        js_object, index, value, NONE, strict_mode, true, SET_PROPERTY);
-    JSObject::ValidateElements(js_object);
-
-    return result.is_null() ? result : value;
-  }
-
-  if (key->IsName()) {
-    Handle<Name> name = Handle<Name>::cast(key);
-    if (name->AsArrayIndex(&index)) {
-      // TODO(verwaest): Support non-JSObject receivers.
-      if (!object->IsJSObject()) return value;
-      Handle<JSObject> js_object = Handle<JSObject>::cast(object);
-      if (js_object->HasExternalArrayElements()) {
-        if (!value->IsNumber() && !value->IsUndefined()) {
-          ASSIGN_RETURN_ON_EXCEPTION(
-              isolate, value, Execution::ToNumber(isolate, value), Object);
-        }
-      }
-      return JSObject::SetElement(js_object, index, value, NONE, strict_mode,
-                                  true, SET_PROPERTY);
-    } else {
-      if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
-      return Object::SetProperty(object, name, value, strict_mode);
-    }
-  }
-
-  // Call-back into JavaScript to convert the key to a string.
-  Handle<Object> converted;
-  ASSIGN_RETURN_ON_EXCEPTION(
-      isolate, converted, Execution::ToString(isolate, key), Object);
-  Handle<String> name = Handle<String>::cast(converted);
-
-  if (name->AsArrayIndex(&index)) {
-    // TODO(verwaest): Support non-JSObject receivers.
-    if (!object->IsJSObject()) return value;
-    Handle<JSObject> js_object = Handle<JSObject>::cast(object);
-    return JSObject::SetElement(js_object, index, value, NONE, strict_mode,
-                                true, SET_PROPERTY);
-  }
-  return Object::SetProperty(object, name, value, strict_mode);
-}
-
-
-MaybeHandle<Object> Runtime::DefineObjectProperty(Handle<JSObject> js_object,
-                                                  Handle<Object> key,
-                                                  Handle<Object> value,
-                                                  PropertyAttributes attr) {
-  Isolate* isolate = js_object->GetIsolate();
-  // Check if the given key is an array index.
-  uint32_t index;
-  if (key->ToArrayIndex(&index)) {
-    // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
-    // of a string using [] notation.  We need to support this too in
-    // JavaScript.
-    // In the case of a String object we just need to redirect the assignment to
-    // the underlying string if the index is in range.  Since the underlying
-    // string does nothing with the assignment then we can ignore such
-    // assignments.
-    if (js_object->IsStringObjectWithCharacterAt(index)) {
-      return value;
-    }
-
-    return JSObject::SetElement(js_object, index, value, attr,
-                                SLOPPY, false, DEFINE_PROPERTY);
-  }
-
-  if (key->IsName()) {
-    Handle<Name> name = Handle<Name>::cast(key);
-    if (name->AsArrayIndex(&index)) {
-      return JSObject::SetElement(js_object, index, value, attr,
-                                  SLOPPY, false, DEFINE_PROPERTY);
-    } else {
-      if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
-      return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value,
-                                                      attr);
-    }
-  }
-
-  // Call-back into JavaScript to convert the key to a string.
-  Handle<Object> converted;
-  ASSIGN_RETURN_ON_EXCEPTION(
-      isolate, converted, Execution::ToString(isolate, key), Object);
-  Handle<String> name = Handle<String>::cast(converted);
-
-  if (name->AsArrayIndex(&index)) {
-    return JSObject::SetElement(js_object, index, value, attr,
-                                SLOPPY, false, DEFINE_PROPERTY);
-  } else {
-    return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value,
-                                                    attr);
-  }
-}
-
-
-MaybeHandle<Object> Runtime::DeleteObjectProperty(Isolate* isolate,
-                                                  Handle<JSReceiver> receiver,
-                                                  Handle<Object> key,
-                                                  JSReceiver::DeleteMode mode) {
-  // Check if the given key is an array index.
-  uint32_t index;
-  if (key->ToArrayIndex(&index)) {
-    // In Firefox/SpiderMonkey, Safari and Opera you can access the
-    // characters of a string using [] notation.  In the case of a
-    // String object we just need to redirect the deletion to the
-    // underlying string if the index is in range.  Since the
-    // underlying string does nothing with the deletion, we can ignore
-    // such deletions.
-    if (receiver->IsStringObjectWithCharacterAt(index)) {
-      return isolate->factory()->true_value();
-    }
-
-    return JSReceiver::DeleteElement(receiver, index, mode);
-  }
-
-  Handle<Name> name;
-  if (key->IsName()) {
-    name = Handle<Name>::cast(key);
-  } else {
-    // Call-back into JavaScript to convert the key to a string.
-    Handle<Object> converted;
-    ASSIGN_RETURN_ON_EXCEPTION(
-        isolate, converted, Execution::ToString(isolate, key), Object);
-    name = Handle<String>::cast(converted);
-  }
-
-  if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
-  return JSReceiver::DeleteProperty(receiver, name, mode);
-}
-
-
-RUNTIME_FUNCTION(Runtime_SetHiddenProperty) {
-  HandleScope scope(isolate);
-  RUNTIME_ASSERT(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, key, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
-  RUNTIME_ASSERT(key->IsUniqueName());
-  return *JSObject::SetHiddenProperty(object, key, value);
-}
-
-
-RUNTIME_FUNCTION(Runtime_AddNamedProperty) {
-  HandleScope scope(isolate);
-  RUNTIME_ASSERT(args.length() == 4);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
-  CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
-  RUNTIME_ASSERT(
-      (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
-  // Compute attributes.
-  PropertyAttributes attributes =
-      static_cast<PropertyAttributes>(unchecked_attributes);
-
-#ifdef DEBUG
-  uint32_t index = 0;
-  DCHECK(!key->ToArrayIndex(&index));
-  LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
-  Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
-  if (!maybe.has_value) return isolate->heap()->exception();
-  RUNTIME_ASSERT(!it.IsFound());
-#endif
-
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      JSObject::SetOwnPropertyIgnoreAttributes(object, key, value, attributes));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_AddPropertyForTemplate) {
-  HandleScope scope(isolate);
-  RUNTIME_ASSERT(args.length() == 4);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
-  CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
-  RUNTIME_ASSERT(
-      (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
-  // Compute attributes.
-  PropertyAttributes attributes =
-      static_cast<PropertyAttributes>(unchecked_attributes);
-
-#ifdef DEBUG
-  bool duplicate;
-  if (key->IsName()) {
-    LookupIterator it(object, Handle<Name>::cast(key),
-                      LookupIterator::OWN_SKIP_INTERCEPTOR);
-    Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
-    DCHECK(maybe.has_value);
-    duplicate = it.IsFound();
-  } else {
-    uint32_t index = 0;
-    RUNTIME_ASSERT(key->ToArrayIndex(&index));
-    Maybe<bool> maybe = JSReceiver::HasOwnElement(object, index);
-    if (!maybe.has_value) return isolate->heap()->exception();
-    duplicate = maybe.value;
-  }
-  if (duplicate) {
-    Handle<Object> args[1] = { key };
-    THROW_NEW_ERROR_RETURN_FAILURE(
-        isolate,
-        NewTypeError("duplicate_template_property", HandleVector(args, 1)));
-  }
-#endif
-
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      Runtime::DefineObjectProperty(object, key, value, attributes));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_SetProperty) {
-  HandleScope scope(isolate);
-  RUNTIME_ASSERT(args.length() == 4);
-
-  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
-  CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_arg, 3);
-  StrictMode strict_mode = strict_mode_arg;
-
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      Runtime::SetObjectProperty(isolate, object, key, value, strict_mode));
-  return *result;
-}
-
-
-// Adds an element to an array.
-// This is used to create an indexed data property into an array.
-RUNTIME_FUNCTION(Runtime_AddElement) {
-  HandleScope scope(isolate);
-  RUNTIME_ASSERT(args.length() == 4);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
-  CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
-  RUNTIME_ASSERT(
-      (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
-  // Compute attributes.
-  PropertyAttributes attributes =
-      static_cast<PropertyAttributes>(unchecked_attributes);
-
-  uint32_t index = 0;
-  key->ToArrayIndex(&index);
-
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, JSObject::SetElement(object, index, value, attributes,
-                                            SLOPPY, false, DEFINE_PROPERTY));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
-  HandleScope scope(isolate);
-  RUNTIME_ASSERT(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Map, map, 1);
-  JSObject::TransitionElementsKind(array, map->elements_kind());
-  return *array;
-}
-
-
-// Set the native flag on the function.
-// This is used to decide if we should transform null and undefined
-// into the global object when doing call and apply.
-RUNTIME_FUNCTION(Runtime_SetNativeFlag) {
-  SealHandleScope shs(isolate);
-  RUNTIME_ASSERT(args.length() == 1);
-
-  CONVERT_ARG_CHECKED(Object, object, 0);
-
-  if (object->IsJSFunction()) {
-    JSFunction* func = JSFunction::cast(object);
-    func->shared()->set_native(true);
-  }
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_SetInlineBuiltinFlag) {
-  SealHandleScope shs(isolate);
-  RUNTIME_ASSERT(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
-
-  if (object->IsJSFunction()) {
-    JSFunction* func = JSFunction::cast(*object);
-    func->shared()->set_inline_builtin(true);
-  }
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_StoreArrayLiteralElement) {
-  HandleScope scope(isolate);
-  RUNTIME_ASSERT(args.length() == 5);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-  CONVERT_SMI_ARG_CHECKED(store_index, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
-  CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
-  CONVERT_SMI_ARG_CHECKED(literal_index, 4);
-
-  Object* raw_literal_cell = literals->get(literal_index);
-  JSArray* boilerplate = NULL;
-  if (raw_literal_cell->IsAllocationSite()) {
-    AllocationSite* site = AllocationSite::cast(raw_literal_cell);
-    boilerplate = JSArray::cast(site->transition_info());
-  } else {
-    boilerplate = JSArray::cast(raw_literal_cell);
-  }
-  Handle<JSArray> boilerplate_object(boilerplate);
-  ElementsKind elements_kind = object->GetElementsKind();
-  DCHECK(IsFastElementsKind(elements_kind));
-  // Smis should never trigger transitions.
-  DCHECK(!value->IsSmi());
-
-  if (value->IsNumber()) {
-    DCHECK(IsFastSmiElementsKind(elements_kind));
-    ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
-        ? FAST_HOLEY_DOUBLE_ELEMENTS
-        : FAST_DOUBLE_ELEMENTS;
-    if (IsMoreGeneralElementsKindTransition(
-            boilerplate_object->GetElementsKind(),
-            transitioned_kind)) {
-      JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
-    }
-    JSObject::TransitionElementsKind(object, transitioned_kind);
-    DCHECK(IsFastDoubleElementsKind(object->GetElementsKind()));
-    FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
-    HeapNumber* number = HeapNumber::cast(*value);
-    double_array->set(store_index, number->Number());
-  } else {
-    if (!IsFastObjectElementsKind(elements_kind)) {
-      ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
-          ? FAST_HOLEY_ELEMENTS
-          : FAST_ELEMENTS;
-      JSObject::TransitionElementsKind(object, transitioned_kind);
-      ElementsKind boilerplate_elements_kind =
-          boilerplate_object->GetElementsKind();
-      if (IsMoreGeneralElementsKindTransition(boilerplate_elements_kind,
-                                              transitioned_kind)) {
-        JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
-      }
-    }
-    FixedArray* object_array = FixedArray::cast(object->elements());
-    object_array->set(store_index, *value);
-  }
-  return *object;
-}
-
-
-// Check whether debugger and is about to step into the callback that is passed
-// to a built-in function such as Array.forEach.
-RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) {
-  DCHECK(args.length() == 1);
-  if (!isolate->debug()->is_active() || !isolate->debug()->StepInActive()) {
-    return isolate->heap()->false_value();
-  }
-  CONVERT_ARG_CHECKED(Object, callback, 0);
-  // We do not step into the callback if it's a builtin or not even a function.
-  return isolate->heap()->ToBoolean(
-      callback->IsJSFunction() && !JSFunction::cast(callback)->IsBuiltin());
-}
-
-
-// Set one shot breakpoints for the callback function that is passed to a
-// built-in function such as Array.forEach to enable stepping into the callback.
-RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) {
-  DCHECK(args.length() == 1);
-  Debug* debug = isolate->debug();
-  if (!debug->IsStepping()) return isolate->heap()->undefined_value();
-
-  HandleScope scope(isolate);
-  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
-  RUNTIME_ASSERT(object->IsJSFunction() || object->IsJSGeneratorObject());
-  Handle<JSFunction> fun;
-  if (object->IsJSFunction()) {
-    fun = Handle<JSFunction>::cast(object);
-  } else {
-    fun = Handle<JSFunction>(
-        Handle<JSGeneratorObject>::cast(object)->function(), isolate);
-  }
-  // When leaving the function, step out has been activated, but not performed
-  // if we do not leave the builtin.  To be able to step into the function
-  // again, we need to clear the step out at this point.
-  debug->ClearStepOut();
-  debug->FloodWithOneShot(fun);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugPushPromise) {
-  DCHECK(args.length() == 1);
-  HandleScope scope(isolate);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
-  isolate->PushPromise(promise);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugPopPromise) {
-  DCHECK(args.length() == 0);
-  SealHandleScope shs(isolate);
-  isolate->PopPromise();
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugPromiseEvent) {
-  DCHECK(args.length() == 1);
-  HandleScope scope(isolate);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
-  isolate->debug()->OnPromiseEvent(data);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugPromiseRejectEvent) {
-  DCHECK(args.length() == 2);
-  HandleScope scope(isolate);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
-  isolate->debug()->OnPromiseReject(promise, value);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugAsyncTaskEvent) {
-  DCHECK(args.length() == 1);
-  HandleScope scope(isolate);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
-  isolate->debug()->OnAsyncTaskEvent(data);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DeleteProperty) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
-  CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
-  JSReceiver::DeleteMode delete_mode = strict_mode == STRICT
-      ? JSReceiver::STRICT_DELETION : JSReceiver::NORMAL_DELETION;
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      JSReceiver::DeleteProperty(object, key, delete_mode));
-  return *result;
-}
-
-
-static Object* HasOwnPropertyImplementation(Isolate* isolate,
-                                            Handle<JSObject> object,
-                                            Handle<Name> key) {
-  Maybe<bool> maybe = JSReceiver::HasOwnProperty(object, key);
-  if (!maybe.has_value) return isolate->heap()->exception();
-  if (maybe.value) return isolate->heap()->true_value();
-  // Handle hidden prototypes.  If there's a hidden prototype above this thing
-  // then we have to check it for properties, because they are supposed to
-  // look like they are on this object.
-  PrototypeIterator iter(isolate, object);
-  if (!iter.IsAtEnd() &&
-      Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter))
-          ->map()
-          ->is_hidden_prototype()) {
-    // TODO(verwaest): The recursion is not necessary for keys that are array
-    // indices. Removing this.
-    return HasOwnPropertyImplementation(
-        isolate, Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
-        key);
-  }
-  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
-  return isolate->heap()->false_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_HasOwnProperty) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0)
-  CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
-
-  uint32_t index;
-  const bool key_is_array_index = key->AsArrayIndex(&index);
-
-  // Only JS objects can have properties.
-  if (object->IsJSObject()) {
-    Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
-    // Fast case: either the key is a real named property or it is not
-    // an array index and there are no interceptors or hidden
-    // prototypes.
-    Maybe<bool> maybe = JSObject::HasRealNamedProperty(js_obj, key);
-    if (!maybe.has_value) return isolate->heap()->exception();
-    DCHECK(!isolate->has_pending_exception());
-    if (maybe.value) {
-      return isolate->heap()->true_value();
-    }
-    Map* map = js_obj->map();
-    if (!key_is_array_index &&
-        !map->has_named_interceptor() &&
-        !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
-      return isolate->heap()->false_value();
-    }
-    // Slow case.
-    return HasOwnPropertyImplementation(isolate,
-                                        Handle<JSObject>(js_obj),
-                                        Handle<Name>(key));
-  } else if (object->IsString() && key_is_array_index) {
-    // Well, there is one exception:  Handle [] on strings.
-    Handle<String> string = Handle<String>::cast(object);
-    if (index < static_cast<uint32_t>(string->length())) {
-      return isolate->heap()->true_value();
-    }
-  }
-  return isolate->heap()->false_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_HasProperty) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
-
-  Maybe<bool> maybe = JSReceiver::HasProperty(receiver, key);
-  if (!maybe.has_value) return isolate->heap()->exception();
-  return isolate->heap()->ToBoolean(maybe.value);
-}
-
-
-RUNTIME_FUNCTION(Runtime_HasElement) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
-  CONVERT_SMI_ARG_CHECKED(index, 1);
-
-  Maybe<bool> maybe = JSReceiver::HasElement(receiver, index);
-  if (!maybe.has_value) return isolate->heap()->exception();
-  return isolate->heap()->ToBoolean(maybe.value);
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsPropertyEnumerable) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
-
-  Maybe<PropertyAttributes> maybe =
-      JSReceiver::GetOwnPropertyAttributes(object, key);
-  if (!maybe.has_value) return isolate->heap()->exception();
-  if (maybe.value == ABSENT) maybe.value = DONT_ENUM;
-  return isolate->heap()->ToBoolean((maybe.value & DONT_ENUM) == 0);
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetPropertyNames) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
-  Handle<JSArray> result;
-
-  isolate->counters()->for_in()->Increment();
-  Handle<FixedArray> elements;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, elements,
-      JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS));
-  return *isolate->factory()->NewJSArrayWithElements(elements);
-}
-
-
-// Returns either a FixedArray as Runtime_GetPropertyNames,
-// or, if the given object has an enum cache that contains
-// all enumerable properties of the object and its prototypes
-// have none, the map of the object. This is used to speed up
-// the check for deletions during a for-in.
-RUNTIME_FUNCTION(Runtime_GetPropertyNamesFast) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
-
-  if (raw_object->IsSimpleEnum()) return raw_object->map();
-
-  HandleScope scope(isolate);
-  Handle<JSReceiver> object(raw_object);
-  Handle<FixedArray> content;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, content,
-      JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS));
-
-  // Test again, since cache may have been built by preceding call.
-  if (object->IsSimpleEnum()) return object->map();
-
-  return *content;
-}
-
-
-// Find the length of the prototype chain that is to be handled as one. If a
-// prototype object is hidden it is to be viewed as part of the the object it
-// is prototype for.
-static int OwnPrototypeChainLength(JSObject* obj) {
-  int count = 1;
-  for (PrototypeIterator iter(obj->GetIsolate(), obj);
-       !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
-    count++;
-  }
-  return count;
-}
-
-
-// Return the names of the own named properties.
-// args[0]: object
-// args[1]: PropertyAttributes as int
-RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  if (!args[0]->IsJSObject()) {
-    return isolate->heap()->undefined_value();
-  }
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-  CONVERT_SMI_ARG_CHECKED(filter_value, 1);
-  PropertyAttributes filter = static_cast<PropertyAttributes>(filter_value);
-
-  // Skip the global proxy as it has no properties and always delegates to the
-  // real global object.
-  if (obj->IsJSGlobalProxy()) {
-    // Only collect names if access is permitted.
-    if (obj->IsAccessCheckNeeded() &&
-        !isolate->MayNamedAccess(
-            obj, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
-      isolate->ReportFailedAccessCheck(obj, v8::ACCESS_KEYS);
-      RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
-      return *isolate->factory()->NewJSArray(0);
-    }
-    PrototypeIterator iter(isolate, obj);
-    obj = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
-  }
-
-  // Find the number of objects making up this.
-  int length = OwnPrototypeChainLength(*obj);
-
-  // Find the number of own properties for each of the objects.
-  ScopedVector<int> own_property_count(length);
-  int total_property_count = 0;
-  {
-    PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
-    for (int i = 0; i < length; i++) {
-      DCHECK(!iter.IsAtEnd());
-      Handle<JSObject> jsproto =
-          Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
-      // Only collect names if access is permitted.
-      if (jsproto->IsAccessCheckNeeded() &&
-          !isolate->MayNamedAccess(jsproto,
-                                   isolate->factory()->undefined_value(),
-                                   v8::ACCESS_KEYS)) {
-        isolate->ReportFailedAccessCheck(jsproto, v8::ACCESS_KEYS);
-        RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
-        return *isolate->factory()->NewJSArray(0);
-      }
-      int n;
-      n = jsproto->NumberOfOwnProperties(filter);
-      own_property_count[i] = n;
-      total_property_count += n;
-      iter.Advance();
-    }
-  }
-
-  // Allocate an array with storage for all the property names.
-  Handle<FixedArray> names =
-      isolate->factory()->NewFixedArray(total_property_count);
-
-  // Get the property names.
-  int next_copy_index = 0;
-  int hidden_strings = 0;
-  {
-    PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
-    for (int i = 0; i < length; i++) {
-      DCHECK(!iter.IsAtEnd());
-      Handle<JSObject> jsproto =
-          Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
-      jsproto->GetOwnPropertyNames(*names, next_copy_index, filter);
-      if (i > 0) {
-        // Names from hidden prototypes may already have been added
-        // for inherited function template instances. Count the duplicates
-        // and stub them out; the final copy pass at the end ignores holes.
-        for (int j = next_copy_index;
-             j < next_copy_index + own_property_count[i]; j++) {
-          Object* name_from_hidden_proto = names->get(j);
-          for (int k = 0; k < next_copy_index; k++) {
-            if (names->get(k) != isolate->heap()->hidden_string()) {
-              Object* name = names->get(k);
-              if (name_from_hidden_proto == name) {
-                names->set(j, isolate->heap()->hidden_string());
-                hidden_strings++;
-                break;
-              }
-            }
-          }
-        }
-      }
-      next_copy_index += own_property_count[i];
-
-      // Hidden properties only show up if the filter does not skip strings.
-      if ((filter & STRING) == 0 && JSObject::HasHiddenProperties(jsproto)) {
-        hidden_strings++;
-      }
-      iter.Advance();
-    }
-  }
-
-  // Filter out name of hidden properties object and
-  // hidden prototype duplicates.
-  if (hidden_strings > 0) {
-    Handle<FixedArray> old_names = names;
-    names = isolate->factory()->NewFixedArray(
-        names->length() - hidden_strings);
-    int dest_pos = 0;
-    for (int i = 0; i < total_property_count; i++) {
-      Object* name = old_names->get(i);
-      if (name == isolate->heap()->hidden_string()) {
-        hidden_strings--;
-        continue;
-      }
-      names->set(dest_pos++, name);
-    }
-    DCHECK_EQ(0, hidden_strings);
-  }
-
-  return *isolate->factory()->NewJSArrayWithElements(names);
-}
-
-
-// Return the names of the own indexed properties.
-// args[0]: object
-RUNTIME_FUNCTION(Runtime_GetOwnElementNames) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  if (!args[0]->IsJSObject()) {
-    return isolate->heap()->undefined_value();
-  }
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-
-  int n = obj->NumberOfOwnElements(static_cast<PropertyAttributes>(NONE));
-  Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
-  obj->GetOwnElementKeys(*names, static_cast<PropertyAttributes>(NONE));
-  return *isolate->factory()->NewJSArrayWithElements(names);
-}
-
-
-// Return information on whether an object has a named or indexed interceptor.
-// args[0]: object
-RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  if (!args[0]->IsJSObject()) {
-    return Smi::FromInt(0);
-  }
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-
-  int result = 0;
-  if (obj->HasNamedInterceptor()) result |= 2;
-  if (obj->HasIndexedInterceptor()) result |= 1;
-
-  return Smi::FromInt(result);
-}
-
-
-// Return property names from named interceptor.
-// args[0]: object
-RUNTIME_FUNCTION(Runtime_GetNamedInterceptorPropertyNames) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-
-  if (obj->HasNamedInterceptor()) {
-    Handle<JSObject> result;
-    if (JSObject::GetKeysForNamedInterceptor(obj, obj).ToHandle(&result)) {
-      return *result;
-    }
-  }
-  return isolate->heap()->undefined_value();
-}
-
-
-// Return element names from indexed interceptor.
-// args[0]: object
-RUNTIME_FUNCTION(Runtime_GetIndexedInterceptorElementNames) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-
-  if (obj->HasIndexedInterceptor()) {
-    Handle<JSObject> result;
-    if (JSObject::GetKeysForIndexedInterceptor(obj, obj).ToHandle(&result)) {
-      return *result;
-    }
-  }
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_OwnKeys) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
-  Handle<JSObject> object(raw_object);
-
-  if (object->IsJSGlobalProxy()) {
-    // Do access checks before going to the global object.
-    if (object->IsAccessCheckNeeded() &&
-        !isolate->MayNamedAccess(
-            object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
-      isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
-      RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
-      return *isolate->factory()->NewJSArray(0);
-    }
-
-    PrototypeIterator iter(isolate, object);
-    // If proxy is detached we simply return an empty array.
-    if (iter.IsAtEnd()) return *isolate->factory()->NewJSArray(0);
-    object = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
-  }
-
-  Handle<FixedArray> contents;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, contents,
-      JSReceiver::GetKeys(object, JSReceiver::OWN_ONLY));
-
-  // Some fast paths through GetKeysInFixedArrayFor reuse a cached
-  // property array and since the result is mutable we have to create
-  // a fresh clone on each invocation.
-  int length = contents->length();
-  Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
-  for (int i = 0; i < length; i++) {
-    Object* entry = contents->get(i);
-    if (entry->IsString()) {
-      copy->set(i, entry);
-    } else {
-      DCHECK(entry->IsNumber());
-      HandleScope scope(isolate);
-      Handle<Object> entry_handle(entry, isolate);
-      Handle<Object> entry_str =
-          isolate->factory()->NumberToString(entry_handle);
-      copy->set(i, *entry_str);
-    }
-  }
-  return *isolate->factory()->NewJSArrayWithElements(copy);
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetArgumentsProperty) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, raw_key, 0);
-
-  // Compute the frame holding the arguments.
-  JavaScriptFrameIterator it(isolate);
-  it.AdvanceToArgumentsFrame();
-  JavaScriptFrame* frame = it.frame();
-
-  // Get the actual number of provided arguments.
-  const uint32_t n = frame->ComputeParametersCount();
-
-  // Try to convert the key to an index. If successful and within
-  // index return the the argument from the frame.
-  uint32_t index;
-  if (raw_key->ToArrayIndex(&index) && index < n) {
-    return frame->GetParameter(index);
-  }
-
-  HandleScope scope(isolate);
-  if (raw_key->IsSymbol()) {
-    Handle<Symbol> symbol = Handle<Symbol>::cast(raw_key);
-    if (symbol->Equals(isolate->native_context()->iterator_symbol())) {
-      return isolate->native_context()->array_values_iterator();
-    }
-    // Lookup in the initial Object.prototype object.
-    Handle<Object> result;
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, result,
-        Object::GetProperty(isolate->initial_object_prototype(),
-                            Handle<Symbol>::cast(raw_key)));
-    return *result;
-  }
-
-  // Convert the key to a string.
-  Handle<Object> converted;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, converted, Execution::ToString(isolate, raw_key));
-  Handle<String> key = Handle<String>::cast(converted);
-
-  // Try to convert the string key into an array index.
-  if (key->AsArrayIndex(&index)) {
-    if (index < n) {
-      return frame->GetParameter(index);
-    } else {
-      Handle<Object> initial_prototype(isolate->initial_object_prototype());
-      Handle<Object> result;
-      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-          isolate, result,
-          Object::GetElement(isolate, initial_prototype, index));
-      return *result;
-    }
-  }
-
-  // Handle special arguments properties.
-  if (String::Equals(isolate->factory()->length_string(), key)) {
-    return Smi::FromInt(n);
-  }
-  if (String::Equals(isolate->factory()->callee_string(), key)) {
-    JSFunction* function = frame->function();
-    if (function->shared()->strict_mode() == STRICT) {
-      THROW_NEW_ERROR_RETURN_FAILURE(
-          isolate, NewTypeError("strict_arguments_callee",
-                                HandleVector<Object>(NULL, 0)));
-    }
-    return function;
-  }
-
-  // Lookup in the initial Object.prototype object.
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      Object::GetProperty(isolate->initial_object_prototype(), key));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_ToFastProperties) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
-  if (object->IsJSObject() && !object->IsGlobalObject()) {
-    JSObject::MigrateSlowToFast(Handle<JSObject>::cast(object), 0);
-  }
-  return *object;
-}
-
-
-RUNTIME_FUNCTION(Runtime_ToBool) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, object, 0);
-
-  return isolate->heap()->ToBoolean(object->BooleanValue());
-}
-
-
-// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
-// Possible optimizations: put the type string into the oddballs.
-RUNTIME_FUNCTION(Runtime_Typeof) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  if (obj->IsNumber()) return isolate->heap()->number_string();
-  HeapObject* heap_obj = HeapObject::cast(obj);
-
-  // typeof an undetectable object is 'undefined'
-  if (heap_obj->map()->is_undetectable()) {
-    return isolate->heap()->undefined_string();
-  }
-
-  InstanceType instance_type = heap_obj->map()->instance_type();
-  if (instance_type < FIRST_NONSTRING_TYPE) {
-    return isolate->heap()->string_string();
-  }
-
-  switch (instance_type) {
-    case ODDBALL_TYPE:
-      if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
-        return isolate->heap()->boolean_string();
-      }
-      if (heap_obj->IsNull()) {
-        return isolate->heap()->object_string();
-      }
-      DCHECK(heap_obj->IsUndefined());
-      return isolate->heap()->undefined_string();
-    case SYMBOL_TYPE:
-      return isolate->heap()->symbol_string();
-    case JS_FUNCTION_TYPE:
-    case JS_FUNCTION_PROXY_TYPE:
-      return isolate->heap()->function_string();
-    default:
-      // For any kind of object not handled above, the spec rule for
-      // host objects gives that it is okay to return "object"
-      return isolate->heap()->object_string();
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_Booleanize) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_CHECKED(Object, value_raw, 0);
-  CONVERT_SMI_ARG_CHECKED(token_raw, 1);
-  intptr_t value = reinterpret_cast<intptr_t>(value_raw);
-  Token::Value token = static_cast<Token::Value>(token_raw);
-  switch (token) {
-    case Token::EQ:
-    case Token::EQ_STRICT:
-      return isolate->heap()->ToBoolean(value == 0);
-    case Token::NE:
-    case Token::NE_STRICT:
-      return isolate->heap()->ToBoolean(value != 0);
-    case Token::LT:
-      return isolate->heap()->ToBoolean(value < 0);
-    case Token::GT:
-      return isolate->heap()->ToBoolean(value > 0);
-    case Token::LTE:
-      return isolate->heap()->ToBoolean(value <= 0);
-    case Token::GTE:
-      return isolate->heap()->ToBoolean(value >= 0);
-    default:
-      // This should only happen during natives fuzzing.
-      return isolate->heap()->undefined_value();
-  }
-}
-
-
-static bool AreDigits(const uint8_t*s, int from, int to) {
-  for (int i = from; i < to; i++) {
-    if (s[i] < '0' || s[i] > '9') return false;
-  }
-
-  return true;
-}
-
-
-static int ParseDecimalInteger(const uint8_t*s, int from, int to) {
-  DCHECK(to - from < 10);  // Overflow is not possible.
-  DCHECK(from < to);
-  int d = s[from] - '0';
-
-  for (int i = from + 1; i < to; i++) {
-    d = 10 * d + (s[i] - '0');
-  }
-
-  return d;
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringToNumber) {
-  HandleScope handle_scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
-  subject = String::Flatten(subject);
-
-  // Fast case: short integer or some sorts of junk values.
-  if (subject->IsSeqOneByteString()) {
-    int len = subject->length();
-    if (len == 0) return Smi::FromInt(0);
-
-    DisallowHeapAllocation no_gc;
-    uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
-    bool minus = (data[0] == '-');
-    int start_pos = (minus ? 1 : 0);
-
-    if (start_pos == len) {
-      return isolate->heap()->nan_value();
-    } else if (data[start_pos] > '9') {
-      // Fast check for a junk value. A valid string may start from a
-      // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
-      // or the 'I' character ('Infinity'). All of that have codes not greater
-      // than '9' except 'I' and &nbsp;.
-      if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
-        return isolate->heap()->nan_value();
-      }
-    } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
-      // The maximal/minimal smi has 10 digits. If the string has less digits
-      // we know it will fit into the smi-data type.
-      int d = ParseDecimalInteger(data, start_pos, len);
-      if (minus) {
-        if (d == 0) return isolate->heap()->minus_zero_value();
-        d = -d;
-      } else if (!subject->HasHashCode() &&
-                 len <= String::kMaxArrayIndexSize &&
-                 (len == 1 || data[0] != '0')) {
-        // String hash is not calculated yet but all the data are present.
-        // Update the hash field to speed up sequential convertions.
-        uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
-#ifdef DEBUG
-        subject->Hash();  // Force hash calculation.
-        DCHECK_EQ(static_cast<int>(subject->hash_field()),
-                  static_cast<int>(hash));
-#endif
-        subject->set_hash_field(hash);
-      }
-      return Smi::FromInt(d);
-    }
-  }
-
-  // Slower case.
-  int flags = ALLOW_HEX;
-  if (FLAG_harmony_numeric_literals) {
-    // The current spec draft has not updated "ToNumber Applied to the String
-    // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584
-    flags |= ALLOW_OCTAL | ALLOW_BINARY;
-  }
-
-  return *isolate->factory()->NewNumber(StringToDouble(
-      isolate->unicode_cache(), *subject, flags));
-}
-
-
-RUNTIME_FUNCTION(Runtime_NewString) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_INT32_ARG_CHECKED(length, 0);
-  CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1);
-  if (length == 0) return isolate->heap()->empty_string();
-  Handle<String> result;
-  if (is_one_byte) {
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, result, isolate->factory()->NewRawOneByteString(length));
-  } else {
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, result, isolate->factory()->NewRawTwoByteString(length));
-  }
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_TruncateString) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0);
-  CONVERT_INT32_ARG_CHECKED(new_length, 1);
-  RUNTIME_ASSERT(new_length >= 0);
-  return *SeqString::Truncate(string, new_length);
-}
-
-
-RUNTIME_FUNCTION(Runtime_URIEscape) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
-  Handle<String> string = String::Flatten(source);
-  DCHECK(string->IsFlat());
-  Handle<String> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      string->IsOneByteRepresentationUnderneath()
-            ? URIEscape::Escape<uint8_t>(isolate, source)
-            : URIEscape::Escape<uc16>(isolate, source));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_URIUnescape) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
-  Handle<String> string = String::Flatten(source);
-  DCHECK(string->IsFlat());
-  Handle<String> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      string->IsOneByteRepresentationUnderneath()
-            ? URIUnescape::Unescape<uint8_t>(isolate, source)
-            : URIUnescape::Unescape<uc16>(isolate, source));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_QuoteJSONString) {
-  HandleScope scope(isolate);
-  CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
-  DCHECK(args.length() == 1);
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, BasicJsonStringifier::StringifyString(isolate, string));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_BasicJSONStringify) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
-  BasicJsonStringifier stringifier(isolate);
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, stringifier.Stringify(object));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringParseInt) {
-  HandleScope handle_scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
-  CONVERT_NUMBER_CHECKED(int, radix, Int32, args[1]);
-  RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
-
-  subject = String::Flatten(subject);
-  double value;
-
-  { DisallowHeapAllocation no_gc;
-    String::FlatContent flat = subject->GetFlatContent();
-
-    // ECMA-262 section 15.1.2.3, empty string is NaN
-    if (flat.IsOneByte()) {
-      value = StringToInt(
-          isolate->unicode_cache(), flat.ToOneByteVector(), radix);
-    } else {
-      value = StringToInt(
-          isolate->unicode_cache(), flat.ToUC16Vector(), radix);
-    }
-  }
-
-  return *isolate->factory()->NewNumber(value);
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringParseFloat) {
-  HandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
-
-  subject = String::Flatten(subject);
-  double value = StringToDouble(isolate->unicode_cache(), *subject,
-                                ALLOW_TRAILING_JUNK, base::OS::nan_value());
-
-  return *isolate->factory()->NewNumber(value);
-}
-
-
-static inline bool ToUpperOverflows(uc32 character) {
-  // y with umlauts and the micro sign are the only characters that stop
-  // fitting into one-byte when converting to uppercase.
-  static const uc32 yuml_code = 0xff;
-  static const uc32 micro_code = 0xb5;
-  return (character == yuml_code || character == micro_code);
-}
-
-
-template <class Converter>
-MUST_USE_RESULT static Object* ConvertCaseHelper(
-    Isolate* isolate,
-    String* string,
-    SeqString* result,
-    int result_length,
-    unibrow::Mapping<Converter, 128>* mapping) {
-  DisallowHeapAllocation no_gc;
-  // We try this twice, once with the assumption that the result is no longer
-  // than the input and, if that assumption breaks, again with the exact
-  // length.  This may not be pretty, but it is nicer than what was here before
-  // and I hereby claim my vaffel-is.
-  //
-  // NOTE: This assumes that the upper/lower case of an ASCII
-  // character is also ASCII.  This is currently the case, but it
-  // might break in the future if we implement more context and locale
-  // dependent upper/lower conversions.
-  bool has_changed_character = false;
-
-  // Convert all characters to upper case, assuming that they will fit
-  // in the buffer
-  Access<ConsStringIteratorOp> op(
-      isolate->runtime_state()->string_iterator());
-  StringCharacterStream stream(string, op.value());
-  unibrow::uchar chars[Converter::kMaxWidth];
-  // We can assume that the string is not empty
-  uc32 current = stream.GetNext();
-  bool ignore_overflow = Converter::kIsToLower || result->IsSeqTwoByteString();
-  for (int i = 0; i < result_length;) {
-    bool has_next = stream.HasMore();
-    uc32 next = has_next ? stream.GetNext() : 0;
-    int char_length = mapping->get(current, next, chars);
-    if (char_length == 0) {
-      // The case conversion of this character is the character itself.
-      result->Set(i, current);
-      i++;
-    } else if (char_length == 1 &&
-               (ignore_overflow || !ToUpperOverflows(current))) {
-      // Common case: converting the letter resulted in one character.
-      DCHECK(static_cast<uc32>(chars[0]) != current);
-      result->Set(i, chars[0]);
-      has_changed_character = true;
-      i++;
-    } else if (result_length == string->length()) {
-      bool overflows = ToUpperOverflows(current);
-      // We've assumed that the result would be as long as the
-      // input but here is a character that converts to several
-      // characters.  No matter, we calculate the exact length
-      // of the result and try the whole thing again.
-      //
-      // Note that this leaves room for optimization.  We could just
-      // memcpy what we already have to the result string.  Also,
-      // the result string is the last object allocated we could
-      // "realloc" it and probably, in the vast majority of cases,
-      // extend the existing string to be able to hold the full
-      // result.
-      int next_length = 0;
-      if (has_next) {
-        next_length = mapping->get(next, 0, chars);
-        if (next_length == 0) next_length = 1;
-      }
-      int current_length = i + char_length + next_length;
-      while (stream.HasMore()) {
-        current = stream.GetNext();
-        overflows |= ToUpperOverflows(current);
-        // NOTE: we use 0 as the next character here because, while
-        // the next character may affect what a character converts to,
-        // it does not in any case affect the length of what it convert
-        // to.
-        int char_length = mapping->get(current, 0, chars);
-        if (char_length == 0) char_length = 1;
-        current_length += char_length;
-        if (current_length > String::kMaxLength) {
-          AllowHeapAllocation allocate_error_and_return;
-          THROW_NEW_ERROR_RETURN_FAILURE(isolate,
-                                         NewInvalidStringLengthError());
-        }
-      }
-      // Try again with the real length.  Return signed if we need
-      // to allocate a two-byte string for to uppercase.
-      return (overflows && !ignore_overflow) ? Smi::FromInt(-current_length)
-                                             : Smi::FromInt(current_length);
-    } else {
-      for (int j = 0; j < char_length; j++) {
-        result->Set(i, chars[j]);
-        i++;
-      }
-      has_changed_character = true;
-    }
-    current = next;
-  }
-  if (has_changed_character) {
-    return result;
-  } else {
-    // If we didn't actually change anything in doing the conversion
-    // we simple return the result and let the converted string
-    // become garbage; there is no reason to keep two identical strings
-    // alive.
-    return string;
-  }
-}
-
-
-namespace {
-
-static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
-static const uintptr_t kAsciiMask = kOneInEveryByte << 7;
-
-// Given a word and two range boundaries returns a word with high bit
-// set in every byte iff the corresponding input byte was strictly in
-// the range (m, n). All the other bits in the result are cleared.
-// This function is only useful when it can be inlined and the
-// boundaries are statically known.
-// Requires: all bytes in the input word and the boundaries must be
-// ASCII (less than 0x7F).
-static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
-  // Use strict inequalities since in edge cases the function could be
-  // further simplified.
-  DCHECK(0 < m && m < n);
-  // Has high bit set in every w byte less than n.
-  uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
-  // Has high bit set in every w byte greater than m.
-  uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
-  return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
-}
-
-
-#ifdef DEBUG
-static bool CheckFastAsciiConvert(char* dst,
-                                  const char* src,
-                                  int length,
-                                  bool changed,
-                                  bool is_to_lower) {
-  bool expected_changed = false;
-  for (int i = 0; i < length; i++) {
-    if (dst[i] == src[i]) continue;
-    expected_changed = true;
-    if (is_to_lower) {
-      DCHECK('A' <= src[i] && src[i] <= 'Z');
-      DCHECK(dst[i] == src[i] + ('a' - 'A'));
-    } else {
-      DCHECK('a' <= src[i] && src[i] <= 'z');
-      DCHECK(dst[i] == src[i] - ('a' - 'A'));
-    }
-  }
-  return (expected_changed == changed);
-}
-#endif
-
-
-template<class Converter>
-static bool FastAsciiConvert(char* dst,
-                             const char* src,
-                             int length,
-                             bool* changed_out) {
-#ifdef DEBUG
-    char* saved_dst = dst;
-    const char* saved_src = src;
-#endif
-  DisallowHeapAllocation no_gc;
-  // We rely on the distance between upper and lower case letters
-  // being a known power of 2.
-  DCHECK('a' - 'A' == (1 << 5));
-  // Boundaries for the range of input characters than require conversion.
-  static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1;
-  static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1;
-  bool changed = false;
-  uintptr_t or_acc = 0;
-  const char* const limit = src + length;
-
-  // dst is newly allocated and always aligned.
-  DCHECK(IsAligned(reinterpret_cast<intptr_t>(dst), sizeof(uintptr_t)));
-  // Only attempt processing one word at a time if src is also aligned.
-  if (IsAligned(reinterpret_cast<intptr_t>(src), sizeof(uintptr_t))) {
-    // Process the prefix of the input that requires no conversion one aligned
-    // (machine) word at a time.
-    while (src <= limit - sizeof(uintptr_t)) {
-      const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src);
-      or_acc |= w;
-      if (AsciiRangeMask(w, lo, hi) != 0) {
-        changed = true;
-        break;
-      }
-      *reinterpret_cast<uintptr_t*>(dst) = w;
-      src += sizeof(uintptr_t);
-      dst += sizeof(uintptr_t);
-    }
-    // Process the remainder of the input performing conversion when
-    // required one word at a time.
-    while (src <= limit - sizeof(uintptr_t)) {
-      const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src);
-      or_acc |= w;
-      uintptr_t m = AsciiRangeMask(w, lo, hi);
-      // The mask has high (7th) bit set in every byte that needs
-      // conversion and we know that the distance between cases is
-      // 1 << 5.
-      *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
-      src += sizeof(uintptr_t);
-      dst += sizeof(uintptr_t);
-    }
-  }
-  // Process the last few bytes of the input (or the whole input if
-  // unaligned access is not supported).
-  while (src < limit) {
-    char c = *src;
-    or_acc |= c;
-    if (lo < c && c < hi) {
-      c ^= (1 << 5);
-      changed = true;
-    }
-    *dst = c;
-    ++src;
-    ++dst;
-  }
-
-  if ((or_acc & kAsciiMask) != 0) return false;
-
-  DCHECK(CheckFastAsciiConvert(
-             saved_dst, saved_src, length, changed, Converter::kIsToLower));
-
-  *changed_out = changed;
-  return true;
-}
-
-}  // namespace
-
-
-template <class Converter>
-MUST_USE_RESULT static Object* ConvertCase(
-    Handle<String> s,
-    Isolate* isolate,
-    unibrow::Mapping<Converter, 128>* mapping) {
-  s = String::Flatten(s);
-  int length = s->length();
-  // Assume that the string is not empty; we need this assumption later
-  if (length == 0) return *s;
-
-  // Simpler handling of ASCII strings.
-  //
-  // NOTE: This assumes that the upper/lower case of an ASCII
-  // character is also ASCII.  This is currently the case, but it
-  // might break in the future if we implement more context and locale
-  // dependent upper/lower conversions.
-  if (s->IsOneByteRepresentationUnderneath()) {
-    // Same length as input.
-    Handle<SeqOneByteString> result =
-        isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
-    DisallowHeapAllocation no_gc;
-    String::FlatContent flat_content = s->GetFlatContent();
-    DCHECK(flat_content.IsFlat());
-    bool has_changed_character = false;
-    bool is_ascii = FastAsciiConvert<Converter>(
-        reinterpret_cast<char*>(result->GetChars()),
-        reinterpret_cast<const char*>(flat_content.ToOneByteVector().start()),
-        length,
-        &has_changed_character);
-    // If not ASCII, we discard the result and take the 2 byte path.
-    if (is_ascii) return has_changed_character ? *result : *s;
-  }
-
-  Handle<SeqString> result;  // Same length as input.
-  if (s->IsOneByteRepresentation()) {
-    result = isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
-  } else {
-    result = isolate->factory()->NewRawTwoByteString(length).ToHandleChecked();
-  }
-
-  Object* answer = ConvertCaseHelper(isolate, *s, *result, length, mapping);
-  if (answer->IsException() || answer->IsString()) return answer;
-
-  DCHECK(answer->IsSmi());
-  length = Smi::cast(answer)->value();
-  if (s->IsOneByteRepresentation() && length > 0) {
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, result, isolate->factory()->NewRawOneByteString(length));
-  } else {
-    if (length < 0) length = -length;
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, result, isolate->factory()->NewRawTwoByteString(length));
-  }
-  return ConvertCaseHelper(isolate, *s, *result, length, mapping);
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringToLowerCase) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
-  return ConvertCase(
-      s, isolate, isolate->runtime_state()->to_lower_mapping());
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringToUpperCase) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
-  return ConvertCase(
-      s, isolate, isolate->runtime_state()->to_upper_mapping());
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringTrim) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
-  CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
-  CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
-
-  string = String::Flatten(string);
-  int length = string->length();
-
-  int left = 0;
-  UnicodeCache* unicode_cache = isolate->unicode_cache();
-  if (trimLeft) {
-    while (left < length &&
-           unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
-      left++;
-    }
-  }
-
-  int right = length;
-  if (trimRight) {
-    while (right > left &&
-           unicode_cache->IsWhiteSpaceOrLineTerminator(
-               string->Get(right - 1))) {
-      right--;
-    }
-  }
-
-  return *isolate->factory()->NewSubString(string, left, right);
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringSplit) {
-  HandleScope handle_scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
-  CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
-  RUNTIME_ASSERT(limit > 0);
-
-  int subject_length = subject->length();
-  int pattern_length = pattern->length();
-  RUNTIME_ASSERT(pattern_length > 0);
-
-  if (limit == 0xffffffffu) {
-    Handle<Object> cached_answer(
-        RegExpResultsCache::Lookup(isolate->heap(),
-                                   *subject,
-                                   *pattern,
-                                   RegExpResultsCache::STRING_SPLIT_SUBSTRINGS),
-        isolate);
-    if (*cached_answer != Smi::FromInt(0)) {
-      // The cache FixedArray is a COW-array and can therefore be reused.
-      Handle<JSArray> result =
-          isolate->factory()->NewJSArrayWithElements(
-              Handle<FixedArray>::cast(cached_answer));
-      return *result;
-    }
-  }
-
-  // The limit can be very large (0xffffffffu), but since the pattern
-  // isn't empty, we can never create more parts than ~half the length
-  // of the subject.
-
-  subject = String::Flatten(subject);
-  pattern = String::Flatten(pattern);
-
-  static const int kMaxInitialListCapacity = 16;
-
-  ZoneScope zone_scope(isolate->runtime_zone());
-
-  // Find (up to limit) indices of separator and end-of-string in subject
-  int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
-  ZoneList<int> indices(initial_capacity, zone_scope.zone());
-
-  FindStringIndicesDispatch(isolate, *subject, *pattern,
-                            &indices, limit, zone_scope.zone());
-
-  if (static_cast<uint32_t>(indices.length()) < limit) {
-    indices.Add(subject_length, zone_scope.zone());
-  }
-
-  // The list indices now contains the end of each part to create.
-
-  // Create JSArray of substrings separated by separator.
-  int part_count = indices.length();
-
-  Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
-  JSObject::EnsureCanContainHeapObjectElements(result);
-  result->set_length(Smi::FromInt(part_count));
-
-  DCHECK(result->HasFastObjectElements());
-
-  if (part_count == 1 && indices.at(0) == subject_length) {
-    FixedArray::cast(result->elements())->set(0, *subject);
-    return *result;
-  }
-
-  Handle<FixedArray> elements(FixedArray::cast(result->elements()));
-  int part_start = 0;
-  for (int i = 0; i < part_count; i++) {
-    HandleScope local_loop_handle(isolate);
-    int part_end = indices.at(i);
-    Handle<String> substring =
-        isolate->factory()->NewProperSubString(subject, part_start, part_end);
-    elements->set(i, *substring);
-    part_start = part_end + pattern_length;
-  }
-
-  if (limit == 0xffffffffu) {
-    if (result->HasFastObjectElements()) {
-      RegExpResultsCache::Enter(isolate,
-                                subject,
-                                pattern,
-                                elements,
-                                RegExpResultsCache::STRING_SPLIT_SUBSTRINGS);
-    }
-  }
-
-  return *result;
-}
-
-
-// Copies Latin1 characters to the given fixed array looking up
-// one-char strings in the cache. Gives up on the first char that is
-// not in the cache and fills the remainder with smi zeros. Returns
-// the length of the successfully copied prefix.
-static int CopyCachedOneByteCharsToArray(Heap* heap, const uint8_t* chars,
-                                         FixedArray* elements, int length) {
-  DisallowHeapAllocation no_gc;
-  FixedArray* one_byte_cache = heap->single_character_string_cache();
-  Object* undefined = heap->undefined_value();
-  int i;
-  WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
-  for (i = 0; i < length; ++i) {
-    Object* value = one_byte_cache->get(chars[i]);
-    if (value == undefined) break;
-    elements->set(i, value, mode);
-  }
-  if (i < length) {
-    DCHECK(Smi::FromInt(0) == 0);
-    memset(elements->data_start() + i, 0, kPointerSize * (length - i));
-  }
-#ifdef DEBUG
-  for (int j = 0; j < length; ++j) {
-    Object* element = elements->get(j);
-    DCHECK(element == Smi::FromInt(0) ||
-           (element->IsString() && String::cast(element)->LooksValid()));
-  }
-#endif
-  return i;
-}
-
-
-// Converts a String to JSArray.
-// For example, "foo" => ["f", "o", "o"].
-RUNTIME_FUNCTION(Runtime_StringToArray) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
-  CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
-
-  s = String::Flatten(s);
-  const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
-
-  Handle<FixedArray> elements;
-  int position = 0;
-  if (s->IsFlat() && s->IsOneByteRepresentation()) {
-    // Try using cached chars where possible.
-    elements = isolate->factory()->NewUninitializedFixedArray(length);
-
-    DisallowHeapAllocation no_gc;
-    String::FlatContent content = s->GetFlatContent();
-    if (content.IsOneByte()) {
-      Vector<const uint8_t> chars = content.ToOneByteVector();
-      // Note, this will initialize all elements (not only the prefix)
-      // to prevent GC from seeing partially initialized array.
-      position = CopyCachedOneByteCharsToArray(isolate->heap(), chars.start(),
-                                               *elements, length);
-    } else {
-      MemsetPointer(elements->data_start(),
-                    isolate->heap()->undefined_value(),
-                    length);
-    }
-  } else {
-    elements = isolate->factory()->NewFixedArray(length);
-  }
-  for (int i = position; i < length; ++i) {
-    Handle<Object> str =
-        isolate->factory()->LookupSingleCharacterStringFromCode(s->Get(i));
-    elements->set(i, *str);
-  }
-
-#ifdef DEBUG
-  for (int i = 0; i < length; ++i) {
-    DCHECK(String::cast(elements->get(i))->length() == 1);
-  }
-#endif
-
-  return *isolate->factory()->NewJSArrayWithElements(elements);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NewStringWrapper) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, value, 0);
-  return *Object::ToObject(isolate, value).ToHandleChecked();
-}
-
-
-bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
-  unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
-  int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
-  return char_length == 0;
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberToStringRT) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
-
-  return *isolate->factory()->NumberToString(number);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
-
-  return *isolate->factory()->NumberToString(number, false);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberToInteger) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_DOUBLE_ARG_CHECKED(number, 0);
-  return *isolate->factory()->NewNumber(DoubleToInteger(number));
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberToIntegerMapMinusZero) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_DOUBLE_ARG_CHECKED(number, 0);
-  double double_value = DoubleToInteger(number);
-  // Map both -0 and +0 to +0.
-  if (double_value == 0) double_value = 0;
-
-  return *isolate->factory()->NewNumber(double_value);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberToJSUint32) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
-  return *isolate->factory()->NewNumberFromUint(number);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberToJSInt32) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_DOUBLE_ARG_CHECKED(number, 0);
-  return *isolate->factory()->NewNumberFromInt(DoubleToInt32(number));
-}
-
-
-// Converts a Number to a Smi, if possible. Returns NaN if the number is not
-// a small integer.
-RUNTIME_FUNCTION(Runtime_NumberToSmi) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  if (obj->IsSmi()) {
-    return obj;
-  }
-  if (obj->IsHeapNumber()) {
-    double value = HeapNumber::cast(obj)->value();
-    int int_value = FastD2I(value);
-    if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
-      return Smi::FromInt(int_value);
-    }
-  }
-  return isolate->heap()->nan_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-  return *isolate->factory()->NewHeapNumber(0);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberAdd) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
-  return *isolate->factory()->NewNumber(x + y);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberSub) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
-  return *isolate->factory()->NewNumber(x - y);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberMul) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
-  return *isolate->factory()->NewNumber(x * y);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberUnaryMinus) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  return *isolate->factory()->NewNumber(-x);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberDiv) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
-  return *isolate->factory()->NewNumber(x / y);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberMod) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
-  return *isolate->factory()->NewNumber(modulo(x, y));
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberImul) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  // We rely on implementation-defined behavior below, but at least not on
-  // undefined behavior.
-  CONVERT_NUMBER_CHECKED(uint32_t, x, Int32, args[0]);
-  CONVERT_NUMBER_CHECKED(uint32_t, y, Int32, args[1]);
-  int32_t product = static_cast<int32_t>(x * y);
-  return *isolate->factory()->NewNumberFromInt(product);
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringAdd) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(String, str1, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, str2, 1);
-  isolate->counters()->string_add_runtime()->Increment();
-  Handle<String> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, isolate->factory()->NewConsString(str1, str2));
-  return *result;
-}
-
-
-template <typename sinkchar>
-static inline void StringBuilderConcatHelper(String* special,
-                                             sinkchar* sink,
-                                             FixedArray* fixed_array,
-                                             int array_length) {
-  DisallowHeapAllocation no_gc;
-  int position = 0;
-  for (int i = 0; i < array_length; i++) {
-    Object* element = fixed_array->get(i);
-    if (element->IsSmi()) {
-      // Smi encoding of position and length.
-      int encoded_slice = Smi::cast(element)->value();
-      int pos;
-      int len;
-      if (encoded_slice > 0) {
-        // Position and length encoded in one smi.
-        pos = StringBuilderSubstringPosition::decode(encoded_slice);
-        len = StringBuilderSubstringLength::decode(encoded_slice);
-      } else {
-        // Position and length encoded in two smis.
-        Object* obj = fixed_array->get(++i);
-        DCHECK(obj->IsSmi());
-        pos = Smi::cast(obj)->value();
-        len = -encoded_slice;
-      }
-      String::WriteToFlat(special,
-                          sink + position,
-                          pos,
-                          pos + len);
-      position += len;
-    } else {
-      String* string = String::cast(element);
-      int element_length = string->length();
-      String::WriteToFlat(string, sink + position, 0, element_length);
-      position += element_length;
-    }
-  }
-}
-
-
-// Returns the result length of the concatenation.
-// On illegal argument, -1 is returned.
-static inline int StringBuilderConcatLength(int special_length,
-                                            FixedArray* fixed_array,
-                                            int array_length,
-                                            bool* one_byte) {
-  DisallowHeapAllocation no_gc;
-  int position = 0;
-  for (int i = 0; i < array_length; i++) {
-    int increment = 0;
-    Object* elt = fixed_array->get(i);
-    if (elt->IsSmi()) {
-      // Smi encoding of position and length.
-      int smi_value = Smi::cast(elt)->value();
-      int pos;
-      int len;
-      if (smi_value > 0) {
-        // Position and length encoded in one smi.
-        pos = StringBuilderSubstringPosition::decode(smi_value);
-        len = StringBuilderSubstringLength::decode(smi_value);
-      } else {
-        // Position and length encoded in two smis.
-        len = -smi_value;
-        // Get the position and check that it is a positive smi.
-        i++;
-        if (i >= array_length) return -1;
-        Object* next_smi = fixed_array->get(i);
-        if (!next_smi->IsSmi()) return -1;
-        pos = Smi::cast(next_smi)->value();
-        if (pos < 0) return -1;
-      }
-      DCHECK(pos >= 0);
-      DCHECK(len >= 0);
-      if (pos > special_length || len > special_length - pos) return -1;
-      increment = len;
-    } else if (elt->IsString()) {
-      String* element = String::cast(elt);
-      int element_length = element->length();
-      increment = element_length;
-      if (*one_byte && !element->HasOnlyOneByteChars()) {
-        *one_byte = false;
-      }
-    } else {
-      return -1;
-    }
-    if (increment > String::kMaxLength - position) {
-      return kMaxInt;  // Provoke throw on allocation.
-    }
-    position += increment;
-  }
-  return position;
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringBuilderConcat) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
-  int32_t array_length;
-  if (!args[1]->ToInt32(&array_length)) {
-    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
-  }
-  CONVERT_ARG_HANDLE_CHECKED(String, special, 2);
-
-  size_t actual_array_length = 0;
-  RUNTIME_ASSERT(
-      TryNumberToSize(isolate, array->length(), &actual_array_length));
-  RUNTIME_ASSERT(array_length >= 0);
-  RUNTIME_ASSERT(static_cast<size_t>(array_length) <= actual_array_length);
-
-  // This assumption is used by the slice encoding in one or two smis.
-  DCHECK(Smi::kMaxValue >= String::kMaxLength);
-
-  RUNTIME_ASSERT(array->HasFastElements());
-  JSObject::EnsureCanContainHeapObjectElements(array);
-
-  int special_length = special->length();
-  if (!array->HasFastObjectElements()) {
-    return isolate->Throw(isolate->heap()->illegal_argument_string());
-  }
-
-  int length;
-  bool one_byte = special->HasOnlyOneByteChars();
-
-  { DisallowHeapAllocation no_gc;
-    FixedArray* fixed_array = FixedArray::cast(array->elements());
-    if (fixed_array->length() < array_length) {
-      array_length = fixed_array->length();
-    }
-
-    if (array_length == 0) {
-      return isolate->heap()->empty_string();
-    } else if (array_length == 1) {
-      Object* first = fixed_array->get(0);
-      if (first->IsString()) return first;
-    }
-    length = StringBuilderConcatLength(
-        special_length, fixed_array, array_length, &one_byte);
-  }
-
-  if (length == -1) {
-    return isolate->Throw(isolate->heap()->illegal_argument_string());
-  }
-
-  if (one_byte) {
-    Handle<SeqOneByteString> answer;
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, answer,
-        isolate->factory()->NewRawOneByteString(length));
-    StringBuilderConcatHelper(*special,
-                              answer->GetChars(),
-                              FixedArray::cast(array->elements()),
-                              array_length);
-    return *answer;
-  } else {
-    Handle<SeqTwoByteString> answer;
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, answer,
-        isolate->factory()->NewRawTwoByteString(length));
-    StringBuilderConcatHelper(*special,
-                              answer->GetChars(),
-                              FixedArray::cast(array->elements()),
-                              array_length);
-    return *answer;
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringBuilderJoin) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
-  int32_t array_length;
-  if (!args[1]->ToInt32(&array_length)) {
-    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
-  }
-  CONVERT_ARG_HANDLE_CHECKED(String, separator, 2);
-  RUNTIME_ASSERT(array->HasFastObjectElements());
-  RUNTIME_ASSERT(array_length >= 0);
-
-  Handle<FixedArray> fixed_array(FixedArray::cast(array->elements()));
-  if (fixed_array->length() < array_length) {
-    array_length = fixed_array->length();
-  }
-
-  if (array_length == 0) {
-    return isolate->heap()->empty_string();
-  } else if (array_length == 1) {
-    Object* first = fixed_array->get(0);
-    RUNTIME_ASSERT(first->IsString());
-    return first;
-  }
-
-  int separator_length = separator->length();
-  RUNTIME_ASSERT(separator_length > 0);
-  int max_nof_separators =
-      (String::kMaxLength + separator_length - 1) / separator_length;
-  if (max_nof_separators < (array_length - 1)) {
-    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
-  }
-  int length = (array_length - 1) * separator_length;
-  for (int i = 0; i < array_length; i++) {
-    Object* element_obj = fixed_array->get(i);
-    RUNTIME_ASSERT(element_obj->IsString());
-    String* element = String::cast(element_obj);
-    int increment = element->length();
-    if (increment > String::kMaxLength - length) {
-      STATIC_ASSERT(String::kMaxLength < kMaxInt);
-      length = kMaxInt;  // Provoke exception;
-      break;
-    }
-    length += increment;
-  }
-
-  Handle<SeqTwoByteString> answer;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, answer,
-      isolate->factory()->NewRawTwoByteString(length));
-
-  DisallowHeapAllocation no_gc;
-
-  uc16* sink = answer->GetChars();
-#ifdef DEBUG
-  uc16* end = sink + length;
-#endif
-
-  RUNTIME_ASSERT(fixed_array->get(0)->IsString());
-  String* first = String::cast(fixed_array->get(0));
-  String* separator_raw = *separator;
-  int first_length = first->length();
-  String::WriteToFlat(first, sink, 0, first_length);
-  sink += first_length;
-
-  for (int i = 1; i < array_length; i++) {
-    DCHECK(sink + separator_length <= end);
-    String::WriteToFlat(separator_raw, sink, 0, separator_length);
-    sink += separator_length;
-
-    RUNTIME_ASSERT(fixed_array->get(i)->IsString());
-    String* element = String::cast(fixed_array->get(i));
-    int element_length = element->length();
-    DCHECK(sink + element_length <= end);
-    String::WriteToFlat(element, sink, 0, element_length);
-    sink += element_length;
-  }
-  DCHECK(sink == end);
-
-  // Use %_FastOneByteArrayJoin instead.
-  DCHECK(!answer->IsOneByteRepresentation());
-  return *answer;
-}
-
-template <typename Char>
-static void JoinSparseArrayWithSeparator(FixedArray* elements,
-                                         int elements_length,
-                                         uint32_t array_length,
-                                         String* separator,
-                                         Vector<Char> buffer) {
-  DisallowHeapAllocation no_gc;
-  int previous_separator_position = 0;
-  int separator_length = separator->length();
-  int cursor = 0;
-  for (int i = 0; i < elements_length; i += 2) {
-    int position = NumberToInt32(elements->get(i));
-    String* string = String::cast(elements->get(i + 1));
-    int string_length = string->length();
-    if (string->length() > 0) {
-      while (previous_separator_position < position) {
-        String::WriteToFlat<Char>(separator, &buffer[cursor],
-                                  0, separator_length);
-        cursor += separator_length;
-        previous_separator_position++;
-      }
-      String::WriteToFlat<Char>(string, &buffer[cursor],
-                                0, string_length);
-      cursor += string->length();
-    }
-  }
-  if (separator_length > 0) {
-    // Array length must be representable as a signed 32-bit number,
-    // otherwise the total string length would have been too large.
-    DCHECK(array_length <= 0x7fffffff);  // Is int32_t.
-    int last_array_index = static_cast<int>(array_length - 1);
-    while (previous_separator_position < last_array_index) {
-      String::WriteToFlat<Char>(separator, &buffer[cursor],
-                                0, separator_length);
-      cursor += separator_length;
-      previous_separator_position++;
-    }
-  }
-  DCHECK(cursor <= buffer.length());
-}
-
-
-RUNTIME_FUNCTION(Runtime_SparseJoinWithSeparator) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, elements_array, 0);
-  CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
-  CONVERT_ARG_HANDLE_CHECKED(String, separator, 2);
-  // elements_array is fast-mode JSarray of alternating positions
-  // (increasing order) and strings.
-  RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements());
-  // array_length is length of original array (used to add separators);
-  // separator is string to put between elements. Assumed to be non-empty.
-  RUNTIME_ASSERT(array_length > 0);
-
-  // Find total length of join result.
-  int string_length = 0;
-  bool is_one_byte = separator->IsOneByteRepresentation();
-  bool overflow = false;
-  CONVERT_NUMBER_CHECKED(int, elements_length, Int32, elements_array->length());
-  RUNTIME_ASSERT(elements_length <= elements_array->elements()->length());
-  RUNTIME_ASSERT((elements_length & 1) == 0);  // Even length.
-  FixedArray* elements = FixedArray::cast(elements_array->elements());
-  for (int i = 0; i < elements_length; i += 2) {
-    RUNTIME_ASSERT(elements->get(i)->IsNumber());
-    CONVERT_NUMBER_CHECKED(uint32_t, position, Uint32, elements->get(i));
-    RUNTIME_ASSERT(position < array_length);
-    RUNTIME_ASSERT(elements->get(i + 1)->IsString());
-  }
-
-  { DisallowHeapAllocation no_gc;
-    for (int i = 0; i < elements_length; i += 2) {
-      String* string = String::cast(elements->get(i + 1));
-      int length = string->length();
-      if (is_one_byte && !string->IsOneByteRepresentation()) {
-        is_one_byte = false;
-      }
-      if (length > String::kMaxLength ||
-          String::kMaxLength - length < string_length) {
-        overflow = true;
-        break;
-      }
-      string_length += length;
-    }
-  }
-
-  int separator_length = separator->length();
-  if (!overflow && separator_length > 0) {
-    if (array_length <= 0x7fffffffu) {
-      int separator_count = static_cast<int>(array_length) - 1;
-      int remaining_length = String::kMaxLength - string_length;
-      if ((remaining_length / separator_length) >= separator_count) {
-        string_length += separator_length * (array_length - 1);
-      } else {
-        // Not room for the separators within the maximal string length.
-        overflow = true;
-      }
-    } else {
-      // Nonempty separator and at least 2^31-1 separators necessary
-      // means that the string is too large to create.
-      STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
-      overflow = true;
-    }
-  }
-  if (overflow) {
-    // Throw an exception if the resulting string is too large. See
-    // https://code.google.com/p/chromium/issues/detail?id=336820
-    // for details.
-    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
-  }
-
-  if (is_one_byte) {
-    Handle<SeqOneByteString> result = isolate->factory()->NewRawOneByteString(
-        string_length).ToHandleChecked();
-    JoinSparseArrayWithSeparator<uint8_t>(
-        FixedArray::cast(elements_array->elements()),
-        elements_length,
-        array_length,
-        *separator,
-        Vector<uint8_t>(result->GetChars(), string_length));
-    return *result;
-  } else {
-    Handle<SeqTwoByteString> result = isolate->factory()->NewRawTwoByteString(
-        string_length).ToHandleChecked();
-    JoinSparseArrayWithSeparator<uc16>(
-        FixedArray::cast(elements_array->elements()),
-        elements_length,
-        array_length,
-        *separator,
-        Vector<uc16>(result->GetChars(), string_length));
-    return *result;
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberOr) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
-  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
-  return *isolate->factory()->NewNumberFromInt(x | y);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberAnd) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
-  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
-  return *isolate->factory()->NewNumberFromInt(x & y);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberXor) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
-  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
-  return *isolate->factory()->NewNumberFromInt(x ^ y);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberShl) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
-  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
-  return *isolate->factory()->NewNumberFromInt(x << (y & 0x1f));
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberShr) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
-  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
-  return *isolate->factory()->NewNumberFromUint(x >> (y & 0x1f));
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberSar) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
-  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
-  return *isolate->factory()->NewNumberFromInt(
-      ArithmeticShiftRight(x, y & 0x1f));
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberEquals) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
-  if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL);
-  if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL);
-  if (x == y) return Smi::FromInt(EQUAL);
-  Object* result;
-  if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
-    result = Smi::FromInt(EQUAL);
-  } else {
-    result = Smi::FromInt(NOT_EQUAL);
-  }
-  return result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringEquals) {
-  HandleScope handle_scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
-
-  bool not_equal = !String::Equals(x, y);
-  // This is slightly convoluted because the value that signifies
-  // equality is 0 and inequality is 1 so we have to negate the result
-  // from String::Equals.
-  DCHECK(not_equal == 0 || not_equal == 1);
-  STATIC_ASSERT(EQUAL == 0);
-  STATIC_ASSERT(NOT_EQUAL == 1);
-  return Smi::FromInt(not_equal);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NumberCompare) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 3);
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, uncomparable_result, 2)
-  if (std::isnan(x) || std::isnan(y)) return *uncomparable_result;
-  if (x == y) return Smi::FromInt(EQUAL);
-  if (isless(x, y)) return Smi::FromInt(LESS);
-  return Smi::FromInt(GREATER);
-}
-
-
-// Compare two Smis as if they were converted to strings and then
-// compared lexicographically.
-RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_SMI_ARG_CHECKED(x_value, 0);
-  CONVERT_SMI_ARG_CHECKED(y_value, 1);
-
-  // If the integers are equal so are the string representations.
-  if (x_value == y_value) return Smi::FromInt(EQUAL);
-
-  // If one of the integers is zero the normal integer order is the
-  // same as the lexicographic order of the string representations.
-  if (x_value == 0 || y_value == 0)
-    return Smi::FromInt(x_value < y_value ? LESS : GREATER);
-
-  // If only one of the integers is negative the negative number is
-  // smallest because the char code of '-' is less than the char code
-  // of any digit.  Otherwise, we make both values positive.
-
-  // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
-  // architectures using 32-bit Smis.
-  uint32_t x_scaled = x_value;
-  uint32_t y_scaled = y_value;
-  if (x_value < 0 || y_value < 0) {
-    if (y_value >= 0) return Smi::FromInt(LESS);
-    if (x_value >= 0) return Smi::FromInt(GREATER);
-    x_scaled = -x_value;
-    y_scaled = -y_value;
-  }
-
-  static const uint32_t kPowersOf10[] = {
-    1, 10, 100, 1000, 10*1000, 100*1000,
-    1000*1000, 10*1000*1000, 100*1000*1000,
-    1000*1000*1000
-  };
-
-  // If the integers have the same number of decimal digits they can be
-  // compared directly as the numeric order is the same as the
-  // lexicographic order.  If one integer has fewer digits, it is scaled
-  // by some power of 10 to have the same number of digits as the longer
-  // integer.  If the scaled integers are equal it means the shorter
-  // integer comes first in the lexicographic order.
-
-  // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
-  int x_log2 = IntegerLog2(x_scaled);
-  int x_log10 = ((x_log2 + 1) * 1233) >> 12;
-  x_log10 -= x_scaled < kPowersOf10[x_log10];
-
-  int y_log2 = IntegerLog2(y_scaled);
-  int y_log10 = ((y_log2 + 1) * 1233) >> 12;
-  y_log10 -= y_scaled < kPowersOf10[y_log10];
-
-  int tie = EQUAL;
-
-  if (x_log10 < y_log10) {
-    // X has fewer digits.  We would like to simply scale up X but that
-    // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
-    // be scaled up to 9_000_000_000. So we scale up by the next
-    // smallest power and scale down Y to drop one digit. It is OK to
-    // drop one digit from the longer integer since the final digit is
-    // past the length of the shorter integer.
-    x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
-    y_scaled /= 10;
-    tie = LESS;
-  } else if (y_log10 < x_log10) {
-    y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
-    x_scaled /= 10;
-    tie = GREATER;
-  }
-
-  if (x_scaled < y_scaled) return Smi::FromInt(LESS);
-  if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
-  return Smi::FromInt(tie);
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringCompare) {
-  HandleScope handle_scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
-
-  isolate->counters()->string_compare_runtime()->Increment();
-
-  // A few fast case tests before we flatten.
-  if (x.is_identical_to(y)) return Smi::FromInt(EQUAL);
-  if (y->length() == 0) {
-    if (x->length() == 0) return Smi::FromInt(EQUAL);
-    return Smi::FromInt(GREATER);
-  } else if (x->length() == 0) {
-    return Smi::FromInt(LESS);
-  }
-
-  int d = x->Get(0) - y->Get(0);
-  if (d < 0) return Smi::FromInt(LESS);
-  else if (d > 0) return Smi::FromInt(GREATER);
-
-  // Slow case.
-  x = String::Flatten(x);
-  y = String::Flatten(y);
-
-  DisallowHeapAllocation no_gc;
-  Object* equal_prefix_result = Smi::FromInt(EQUAL);
-  int prefix_length = x->length();
-  if (y->length() < prefix_length) {
-    prefix_length = y->length();
-    equal_prefix_result = Smi::FromInt(GREATER);
-  } else if (y->length() > prefix_length) {
-    equal_prefix_result = Smi::FromInt(LESS);
-  }
-  int r;
-  String::FlatContent x_content = x->GetFlatContent();
-  String::FlatContent y_content = y->GetFlatContent();
-  if (x_content.IsOneByte()) {
-    Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
-    if (y_content.IsOneByte()) {
-      Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
-      r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
-    } else {
-      Vector<const uc16> y_chars = y_content.ToUC16Vector();
-      r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
-    }
-  } else {
-    Vector<const uc16> x_chars = x_content.ToUC16Vector();
-    if (y_content.IsOneByte()) {
-      Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
-      r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
-    } else {
-      Vector<const uc16> y_chars = y_content.ToUC16Vector();
-      r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
-    }
-  }
-  Object* result;
-  if (r == 0) {
-    result = equal_prefix_result;
-  } else {
-    result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
-  }
-  return result;
-}
-
-
-#define RUNTIME_UNARY_MATH(Name, name)                                         \
-RUNTIME_FUNCTION(Runtime_Math##Name) {                           \
-  HandleScope scope(isolate);                                                  \
-  DCHECK(args.length() == 1);                                                  \
-  isolate->counters()->math_##name()->Increment();                             \
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);                                            \
-  return *isolate->factory()->NewHeapNumber(std::name(x));                     \
-}
-
-RUNTIME_UNARY_MATH(Acos, acos)
-RUNTIME_UNARY_MATH(Asin, asin)
-RUNTIME_UNARY_MATH(Atan, atan)
-RUNTIME_UNARY_MATH(LogRT, log)
-#undef RUNTIME_UNARY_MATH
-
-
-RUNTIME_FUNCTION(Runtime_DoubleHi) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  uint64_t integer = double_to_uint64(x);
-  integer = (integer >> 32) & 0xFFFFFFFFu;
-  return *isolate->factory()->NewNumber(static_cast<int32_t>(integer));
-}
-
-
-RUNTIME_FUNCTION(Runtime_DoubleLo) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  return *isolate->factory()->NewNumber(
-      static_cast<int32_t>(double_to_uint64(x) & 0xFFFFFFFFu));
-}
-
-
-RUNTIME_FUNCTION(Runtime_ConstructDouble) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]);
-  CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]);
-  uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo;
-  return *isolate->factory()->NewNumber(uint64_to_double(result));
-}
-
-
-RUNTIME_FUNCTION(Runtime_RemPiO2) {
-  HandleScope handle_scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  Factory* factory = isolate->factory();
-  double y[2] = {0.0, 0.0};
-  int n = fdlibm::rempio2(x, y);
-  Handle<FixedArray> array = factory->NewFixedArray(3);
-  Handle<HeapNumber> y0 = factory->NewHeapNumber(y[0]);
-  Handle<HeapNumber> y1 = factory->NewHeapNumber(y[1]);
-  array->set(0, Smi::FromInt(n));
-  array->set(1, *y0);
-  array->set(2, *y1);
-  return *factory->NewJSArrayWithElements(array);
-}
-
-
-static const double kPiDividedBy4 = 0.78539816339744830962;
-
-
-RUNTIME_FUNCTION(Runtime_MathAtan2) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  isolate->counters()->math_atan2()->Increment();
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
-  double result;
-  if (std::isinf(x) && std::isinf(y)) {
-    // Make sure that the result in case of two infinite arguments
-    // is a multiple of Pi / 4. The sign of the result is determined
-    // by the first argument (x) and the sign of the second argument
-    // determines the multiplier: one or three.
-    int multiplier = (x < 0) ? -1 : 1;
-    if (y < 0) multiplier *= 3;
-    result = multiplier * kPiDividedBy4;
-  } else {
-    result = std::atan2(x, y);
-  }
-  return *isolate->factory()->NewNumber(result);
-}
-
-
-RUNTIME_FUNCTION(Runtime_MathExpRT) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  isolate->counters()->math_exp()->Increment();
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  lazily_initialize_fast_exp();
-  return *isolate->factory()->NewNumber(fast_exp(x));
-}
-
-
-RUNTIME_FUNCTION(Runtime_MathFloorRT) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  isolate->counters()->math_floor()->Increment();
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  return *isolate->factory()->NewNumber(Floor(x));
-}
-
-
-// Slow version of Math.pow.  We check for fast paths for special cases.
-// Used if VFP3 is not available.
-RUNTIME_FUNCTION(Runtime_MathPowSlow) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  isolate->counters()->math_pow()->Increment();
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-
-  // If the second argument is a smi, it is much faster to call the
-  // custom powi() function than the generic pow().
-  if (args[1]->IsSmi()) {
-    int y = args.smi_at(1);
-    return *isolate->factory()->NewNumber(power_double_int(x, y));
-  }
-
-  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
-  double result = power_helper(x, y);
-  if (std::isnan(result)) return isolate->heap()->nan_value();
-  return *isolate->factory()->NewNumber(result);
-}
-
-
-// Fast version of Math.pow if we know that y is not an integer and y is not
-// -0.5 or 0.5.  Used as slow case from full codegen.
-RUNTIME_FUNCTION(Runtime_MathPowRT) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  isolate->counters()->math_pow()->Increment();
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
-  if (y == 0) {
-    return Smi::FromInt(1);
-  } else {
-    double result = power_double_double(x, y);
-    if (std::isnan(result)) return isolate->heap()->nan_value();
-    return *isolate->factory()->NewNumber(result);
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_RoundNumber) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_NUMBER_ARG_HANDLE_CHECKED(input, 0);
-  isolate->counters()->math_round()->Increment();
-
-  if (!input->IsHeapNumber()) {
-    DCHECK(input->IsSmi());
-    return *input;
-  }
-
-  Handle<HeapNumber> number = Handle<HeapNumber>::cast(input);
-
-  double value = number->value();
-  int exponent = number->get_exponent();
-  int sign = number->get_sign();
-
-  if (exponent < -1) {
-    // Number in range ]-0.5..0.5[. These always round to +/-zero.
-    if (sign) return isolate->heap()->minus_zero_value();
-    return Smi::FromInt(0);
-  }
-
-  // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
-  // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
-  // argument holds for 32-bit smis).
-  if (!sign && exponent < kSmiValueSize - 2) {
-    return Smi::FromInt(static_cast<int>(value + 0.5));
-  }
-
-  // If the magnitude is big enough, there's no place for fraction part. If we
-  // try to add 0.5 to this number, 1.0 will be added instead.
-  if (exponent >= 52) {
-    return *number;
-  }
-
-  if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
-
-  // Do not call NumberFromDouble() to avoid extra checks.
-  return *isolate->factory()->NewNumber(Floor(value + 0.5));
-}
-
-
-RUNTIME_FUNCTION(Runtime_MathSqrtRT) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  isolate->counters()->math_sqrt()->Increment();
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  return *isolate->factory()->NewNumber(fast_sqrt(x));
-}
-
-
-RUNTIME_FUNCTION(Runtime_MathFround) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  float xf = DoubleToFloat32(x);
-  return *isolate->factory()->NewNumber(xf);
-}
-
-
-RUNTIME_FUNCTION(Runtime_DateMakeDay) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_SMI_ARG_CHECKED(year, 0);
-  CONVERT_SMI_ARG_CHECKED(month, 1);
-
-  int days = isolate->date_cache()->DaysFromYearMonth(year, month);
-  RUNTIME_ASSERT(Smi::IsValid(days));
-  return Smi::FromInt(days);
-}
-
-
-RUNTIME_FUNCTION(Runtime_DateSetValue) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
-  CONVERT_DOUBLE_ARG_CHECKED(time, 1);
-  CONVERT_SMI_ARG_CHECKED(is_utc, 2);
-
-  DateCache* date_cache = isolate->date_cache();
-
-  Handle<Object> value;;
-  bool is_value_nan = false;
-  if (std::isnan(time)) {
-    value = isolate->factory()->nan_value();
-    is_value_nan = true;
-  } else if (!is_utc &&
-             (time < -DateCache::kMaxTimeBeforeUTCInMs ||
-              time > DateCache::kMaxTimeBeforeUTCInMs)) {
-    value = isolate->factory()->nan_value();
-    is_value_nan = true;
-  } else {
-    time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
-    if (time < -DateCache::kMaxTimeInMs ||
-        time > DateCache::kMaxTimeInMs) {
-      value = isolate->factory()->nan_value();
-      is_value_nan = true;
-    } else  {
-      value = isolate->factory()->NewNumber(DoubleToInteger(time));
-    }
-  }
-  date->SetValue(*value, is_value_nan);
-  return *value;
-}
-
-
-static Handle<JSObject> NewSloppyArguments(Isolate* isolate,
-                                           Handle<JSFunction> callee,
-                                           Object** parameters,
-                                           int argument_count) {
-  Handle<JSObject> result =
-      isolate->factory()->NewArgumentsObject(callee, argument_count);
-
-  // Allocate the elements if needed.
-  int parameter_count = callee->shared()->formal_parameter_count();
-  if (argument_count > 0) {
-    if (parameter_count > 0) {
-      int mapped_count = Min(argument_count, parameter_count);
-      Handle<FixedArray> parameter_map =
-          isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
-      parameter_map->set_map(
-          isolate->heap()->sloppy_arguments_elements_map());
-
-      Handle<Map> map = Map::Copy(handle(result->map()));
-      map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS);
-
-      result->set_map(*map);
-      result->set_elements(*parameter_map);
-
-      // Store the context and the arguments array at the beginning of the
-      // parameter map.
-      Handle<Context> context(isolate->context());
-      Handle<FixedArray> arguments =
-          isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
-      parameter_map->set(0, *context);
-      parameter_map->set(1, *arguments);
-
-      // Loop over the actual parameters backwards.
-      int index = argument_count - 1;
-      while (index >= mapped_count) {
-        // These go directly in the arguments array and have no
-        // corresponding slot in the parameter map.
-        arguments->set(index, *(parameters - index - 1));
-        --index;
-      }
-
-      Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
-      while (index >= 0) {
-        // Detect duplicate names to the right in the parameter list.
-        Handle<String> name(scope_info->ParameterName(index));
-        int context_local_count = scope_info->ContextLocalCount();
-        bool duplicate = false;
-        for (int j = index + 1; j < parameter_count; ++j) {
-          if (scope_info->ParameterName(j) == *name) {
-            duplicate = true;
-            break;
-          }
-        }
-
-        if (duplicate) {
-          // This goes directly in the arguments array with a hole in the
-          // parameter map.
-          arguments->set(index, *(parameters - index - 1));
-          parameter_map->set_the_hole(index + 2);
-        } else {
-          // The context index goes in the parameter map with a hole in the
-          // arguments array.
-          int context_index = -1;
-          for (int j = 0; j < context_local_count; ++j) {
-            if (scope_info->ContextLocalName(j) == *name) {
-              context_index = j;
-              break;
-            }
-          }
-          DCHECK(context_index >= 0);
-          arguments->set_the_hole(index);
-          parameter_map->set(index + 2, Smi::FromInt(
-              Context::MIN_CONTEXT_SLOTS + context_index));
-        }
-
-        --index;
-      }
-    } else {
-      // If there is no aliasing, the arguments object elements are not
-      // special in any way.
-      Handle<FixedArray> elements =
-          isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
-      result->set_elements(*elements);
-      for (int i = 0; i < argument_count; ++i) {
-        elements->set(i, *(parameters - i - 1));
-      }
-    }
-  }
-  return result;
-}
-
-
-static Handle<JSObject> NewStrictArguments(Isolate* isolate,
-                                           Handle<JSFunction> callee,
-                                           Object** parameters,
-                                           int argument_count) {
-  Handle<JSObject> result =
-      isolate->factory()->NewArgumentsObject(callee, argument_count);
-
-  if (argument_count > 0) {
-    Handle<FixedArray> array =
-        isolate->factory()->NewUninitializedFixedArray(argument_count);
-    DisallowHeapAllocation no_gc;
-    WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
-    for (int i = 0; i < argument_count; i++) {
-      array->set(i, *--parameters, mode);
-    }
-    result->set_elements(*array);
-  }
-  return result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_NewArguments) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
-  JavaScriptFrameIterator it(isolate);
-
-  // Find the frame that holds the actual arguments passed to the function.
-  it.AdvanceToArgumentsFrame();
-  JavaScriptFrame* frame = it.frame();
-
-  // Determine parameter location on the stack and dispatch on language mode.
-  int argument_count = frame->GetArgumentsLength();
-  Object** parameters = reinterpret_cast<Object**>(frame->GetParameterSlot(-1));
-  return callee->shared()->strict_mode() == STRICT
-             ? *NewStrictArguments(isolate, callee, parameters, argument_count)
-             : *NewSloppyArguments(isolate, callee, parameters, argument_count);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
-  Object** parameters = reinterpret_cast<Object**>(args[1]);
-  CONVERT_SMI_ARG_CHECKED(argument_count, 2);
-  return *NewSloppyArguments(isolate, callee, parameters, argument_count);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NewStrictArguments) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0)
-  Object** parameters = reinterpret_cast<Object**>(args[1]);
-  CONVERT_SMI_ARG_CHECKED(argument_count, 2);
-  return *NewStrictArguments(isolate, callee, parameters, argument_count);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NewClosureFromStubFailure) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
-  Handle<Context> context(isolate->context());
-  PretenureFlag pretenure_flag = NOT_TENURED;
-  return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
-                                                                pretenure_flag);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NewClosure) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
-  CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
-  CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
-
-  // The caller ensures that we pretenure closures that are assigned
-  // directly to properties.
-  PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
-  return *isolate->factory()->NewFunctionFromSharedFunctionInfo(
-      shared, context, pretenure_flag);
-}
-
-
-// Find the arguments of the JavaScript function invocation that called
-// into C++ code. Collect these in a newly allocated array of handles (possibly
-// prefixed by a number of empty handles).
-static SmartArrayPointer<Handle<Object> > GetCallerArguments(
-    Isolate* isolate,
-    int prefix_argc,
-    int* total_argc) {
-  // Find frame containing arguments passed to the caller.
-  JavaScriptFrameIterator it(isolate);
-  JavaScriptFrame* frame = it.frame();
-  List<JSFunction*> functions(2);
-  frame->GetFunctions(&functions);
-  if (functions.length() > 1) {
-    int inlined_jsframe_index = functions.length() - 1;
-    JSFunction* inlined_function = functions[inlined_jsframe_index];
-    SlotRefValueBuilder slot_refs(
-        frame,
-        inlined_jsframe_index,
-        inlined_function->shared()->formal_parameter_count());
-
-    int args_count = slot_refs.args_length();
-
-    *total_argc = prefix_argc + args_count;
-    SmartArrayPointer<Handle<Object> > param_data(
-        NewArray<Handle<Object> >(*total_argc));
-    slot_refs.Prepare(isolate);
-    for (int i = 0; i < args_count; i++) {
-      Handle<Object> val = slot_refs.GetNext(isolate, 0);
-      param_data[prefix_argc + i] = val;
-    }
-    slot_refs.Finish(isolate);
-
-    return param_data;
-  } else {
-    it.AdvanceToArgumentsFrame();
-    frame = it.frame();
-    int args_count = frame->ComputeParametersCount();
-
-    *total_argc = prefix_argc + args_count;
-    SmartArrayPointer<Handle<Object> > param_data(
-        NewArray<Handle<Object> >(*total_argc));
-    for (int i = 0; i < args_count; i++) {
-      Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
-      param_data[prefix_argc + i] = val;
-    }
-    return param_data;
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionBindArguments) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, bindee, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, this_object, 2);
-  CONVERT_NUMBER_ARG_HANDLE_CHECKED(new_length, 3);
-
-  // TODO(lrn): Create bound function in C++ code from premade shared info.
-  bound_function->shared()->set_bound(true);
-  // Get all arguments of calling function (Function.prototype.bind).
-  int argc = 0;
-  SmartArrayPointer<Handle<Object> > arguments =
-      GetCallerArguments(isolate, 0, &argc);
-  // Don't count the this-arg.
-  if (argc > 0) {
-    RUNTIME_ASSERT(arguments[0].is_identical_to(this_object));
-    argc--;
-  } else {
-    RUNTIME_ASSERT(this_object->IsUndefined());
-  }
-  // Initialize array of bindings (function, this, and any existing arguments
-  // if the function was already bound).
-  Handle<FixedArray> new_bindings;
-  int i;
-  if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
-    Handle<FixedArray> old_bindings(
-        JSFunction::cast(*bindee)->function_bindings());
-    RUNTIME_ASSERT(old_bindings->length() > JSFunction::kBoundFunctionIndex);
-    new_bindings =
-        isolate->factory()->NewFixedArray(old_bindings->length() + argc);
-    bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex),
-                            isolate);
-    i = 0;
-    for (int n = old_bindings->length(); i < n; i++) {
-      new_bindings->set(i, old_bindings->get(i));
-    }
-  } else {
-    int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
-    new_bindings = isolate->factory()->NewFixedArray(array_size);
-    new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
-    new_bindings->set(JSFunction::kBoundThisIndex, *this_object);
-    i = 2;
-  }
-  // Copy arguments, skipping the first which is "this_arg".
-  for (int j = 0; j < argc; j++, i++) {
-    new_bindings->set(i, *arguments[j + 1]);
-  }
-  new_bindings->set_map_no_write_barrier(
-      isolate->heap()->fixed_cow_array_map());
-  bound_function->set_function_bindings(*new_bindings);
-
-  // Update length. Have to remove the prototype first so that map migration
-  // is happy about the number of fields.
-  RUNTIME_ASSERT(bound_function->RemovePrototype());
-  Handle<Map> bound_function_map(
-      isolate->native_context()->bound_function_map());
-  JSObject::MigrateToMap(bound_function, bound_function_map);
-  Handle<String> length_string = isolate->factory()->length_string();
-  PropertyAttributes attr =
-      static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
-  RETURN_FAILURE_ON_EXCEPTION(
-      isolate,
-      JSObject::SetOwnPropertyIgnoreAttributes(
-          bound_function, length_string, new_length, attr));
-  return *bound_function;
-}
-
-
-RUNTIME_FUNCTION(Runtime_BoundFunctionGetBindings) {
-  HandleScope handles(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
-  if (callable->IsJSFunction()) {
-    Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
-    if (function->shared()->bound()) {
-      Handle<FixedArray> bindings(function->function_bindings());
-      RUNTIME_ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
-      return *isolate->factory()->NewJSArrayWithElements(bindings);
-    }
-  }
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_NewObjectFromBound) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  // First argument is a function to use as a constructor.
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  RUNTIME_ASSERT(function->shared()->bound());
-
-  // The argument is a bound function. Extract its bound arguments
-  // and callable.
-  Handle<FixedArray> bound_args =
-      Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
-  int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
-  Handle<Object> bound_function(
-      JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)),
-      isolate);
-  DCHECK(!bound_function->IsJSFunction() ||
-         !Handle<JSFunction>::cast(bound_function)->shared()->bound());
-
-  int total_argc = 0;
-  SmartArrayPointer<Handle<Object> > param_data =
-      GetCallerArguments(isolate, bound_argc, &total_argc);
-  for (int i = 0; i < bound_argc; i++) {
-    param_data[i] = Handle<Object>(bound_args->get(
-        JSFunction::kBoundArgumentsStartIndex + i), isolate);
-  }
-
-  if (!bound_function->IsJSFunction()) {
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, bound_function,
-        Execution::TryGetConstructorDelegate(isolate, bound_function));
-  }
-  DCHECK(bound_function->IsJSFunction());
-
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      Execution::New(Handle<JSFunction>::cast(bound_function),
-                     total_argc, param_data.get()));
-  return *result;
-}
-
-
-static Object* Runtime_NewObjectHelper(Isolate* isolate,
-                                            Handle<Object> constructor,
-                                            Handle<AllocationSite> site) {
-  // If the constructor isn't a proper function we throw a type error.
-  if (!constructor->IsJSFunction()) {
-    Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
-    THROW_NEW_ERROR_RETURN_FAILURE(isolate,
-                                   NewTypeError("not_constructor", arguments));
-  }
-
-  Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
-
-  // If function should not have prototype, construction is not allowed. In this
-  // case generated code bailouts here, since function has no initial_map.
-  if (!function->should_have_prototype() && !function->shared()->bound()) {
-    Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
-    THROW_NEW_ERROR_RETURN_FAILURE(isolate,
-                                   NewTypeError("not_constructor", arguments));
-  }
-
-  Debug* debug = isolate->debug();
-  // Handle stepping into constructors if step into is active.
-  if (debug->StepInActive()) {
-    debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
-  }
-
-  if (function->has_initial_map()) {
-    if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
-      // The 'Function' function ignores the receiver object when
-      // called using 'new' and creates a new JSFunction object that
-      // is returned.  The receiver object is only used for error
-      // reporting if an error occurs when constructing the new
-      // JSFunction. Factory::NewJSObject() should not be used to
-      // allocate JSFunctions since it does not properly initialize
-      // the shared part of the function. Since the receiver is
-      // ignored anyway, we use the global object as the receiver
-      // instead of a new JSFunction object. This way, errors are
-      // reported the same way whether or not 'Function' is called
-      // using 'new'.
-      return isolate->global_proxy();
-    }
-  }
-
-  // The function should be compiled for the optimization hints to be
-  // available.
-  Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
-
-  Handle<JSObject> result;
-  if (site.is_null()) {
-    result = isolate->factory()->NewJSObject(function);
-  } else {
-    result = isolate->factory()->NewJSObjectWithMemento(function, site);
-  }
-
-  isolate->counters()->constructed_objects()->Increment();
-  isolate->counters()->constructed_objects_runtime()->Increment();
-
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_NewObject) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 0);
-  return Runtime_NewObjectHelper(isolate,
-                                 constructor,
-                                 Handle<AllocationSite>::null());
-}
-
-
-RUNTIME_FUNCTION(Runtime_NewObjectWithAllocationSite) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, feedback, 0);
-  Handle<AllocationSite> site;
-  if (feedback->IsAllocationSite()) {
-    // The feedback can be an AllocationSite or undefined.
-    site = Handle<AllocationSite>::cast(feedback);
-  }
-  return Runtime_NewObjectHelper(isolate, constructor, site);
-}
-
-
-RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  function->CompleteInobjectSlackTracking();
-
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_CompileLazy) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-#ifdef DEBUG
-  if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
-    PrintF("[unoptimized: ");
-    function->PrintName();
-    PrintF("]\n");
-  }
-#endif
-
-  // Compile the target function.
-  DCHECK(function->shared()->allows_lazy_compilation());
-
-  Handle<Code> code;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, code,
-                                     Compiler::GetLazyCode(function));
-  DCHECK(code->kind() == Code::FUNCTION ||
-         code->kind() == Code::OPTIMIZED_FUNCTION);
-  function->ReplaceCode(*code);
-  return *code;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CompileOptimized) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  CONVERT_BOOLEAN_ARG_CHECKED(concurrent, 1);
-
-  Handle<Code> unoptimized(function->shared()->code());
-  if (!isolate->use_crankshaft() ||
-      function->shared()->optimization_disabled() ||
-      isolate->DebuggerHasBreakPoints()) {
-    // If the function is not optimizable or debugger is active continue
-    // using the code from the full compiler.
-    if (FLAG_trace_opt) {
-      PrintF("[failed to optimize ");
-      function->PrintName();
-      PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
-          function->shared()->optimization_disabled() ? "F" : "T",
-          isolate->DebuggerHasBreakPoints() ? "T" : "F");
-    }
-    function->ReplaceCode(*unoptimized);
-    return function->code();
-  }
-
-  Compiler::ConcurrencyMode mode =
-      concurrent ? Compiler::CONCURRENT : Compiler::NOT_CONCURRENT;
-  Handle<Code> code;
-  if (Compiler::GetOptimizedCode(function, unoptimized, mode).ToHandle(&code)) {
-    function->ReplaceCode(*code);
-  } else {
-    function->ReplaceCode(function->shared()->code());
-  }
-
-  DCHECK(function->code()->kind() == Code::FUNCTION ||
-         function->code()->kind() == Code::OPTIMIZED_FUNCTION ||
-         function->IsInOptimizationQueue());
-  return function->code();
-}
-
-
-class ActivationsFinder : public ThreadVisitor {
- public:
-  Code* code_;
-  bool has_code_activations_;
-
-  explicit ActivationsFinder(Code* code)
-    : code_(code),
-      has_code_activations_(false) { }
-
-  void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
-    JavaScriptFrameIterator it(isolate, top);
-    VisitFrames(&it);
-  }
-
-  void VisitFrames(JavaScriptFrameIterator* it) {
-    for (; !it->done(); it->Advance()) {
-      JavaScriptFrame* frame = it->frame();
-      if (code_->contains(frame->pc())) has_code_activations_ = true;
-    }
-  }
-};
-
-
-RUNTIME_FUNCTION(Runtime_NotifyStubFailure) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-  Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
-  DCHECK(AllowHeapAllocation::IsAllowed());
-  delete deoptimizer;
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_SMI_ARG_CHECKED(type_arg, 0);
-  Deoptimizer::BailoutType type =
-      static_cast<Deoptimizer::BailoutType>(type_arg);
-  Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
-  DCHECK(AllowHeapAllocation::IsAllowed());
-
-  Handle<JSFunction> function = deoptimizer->function();
-  Handle<Code> optimized_code = deoptimizer->compiled_code();
-
-  DCHECK(optimized_code->kind() == Code::OPTIMIZED_FUNCTION);
-  DCHECK(type == deoptimizer->bailout_type());
-
-  // Make sure to materialize objects before causing any allocation.
-  JavaScriptFrameIterator it(isolate);
-  deoptimizer->MaterializeHeapObjects(&it);
-  delete deoptimizer;
-
-  JavaScriptFrame* frame = it.frame();
-  RUNTIME_ASSERT(frame->function()->IsJSFunction());
-  DCHECK(frame->function() == *function);
-
-  // Avoid doing too much work when running with --always-opt and keep
-  // the optimized code around.
-  if (FLAG_always_opt || type == Deoptimizer::LAZY) {
-    return isolate->heap()->undefined_value();
-  }
-
-  // Search for other activations of the same function and code.
-  ActivationsFinder activations_finder(*optimized_code);
-  activations_finder.VisitFrames(&it);
-  isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
-
-  if (!activations_finder.has_code_activations_) {
-    if (function->code() == *optimized_code) {
-      if (FLAG_trace_deopt) {
-        PrintF("[removing optimized code for: ");
-        function->PrintName();
-        PrintF("]\n");
-      }
-      function->ReplaceCode(function->shared()->code());
-      // Evict optimized code for this function from the cache so that it
-      // doesn't get used for new closures.
-      function->shared()->EvictFromOptimizedCodeMap(*optimized_code,
-                                                    "notify deoptimized");
-    }
-  } else {
-    // TODO(titzer): we should probably do DeoptimizeCodeList(code)
-    // unconditionally if the code is not already marked for deoptimization.
-    // If there is an index by shared function info, all the better.
-    Deoptimizer::DeoptimizeFunction(*function);
-  }
-
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  if (!function->IsOptimized()) return isolate->heap()->undefined_value();
-
-  // TODO(turbofan): Deoptimization is not supported yet.
-  if (function->code()->is_turbofanned() && !FLAG_turbo_deoptimization) {
-    return isolate->heap()->undefined_value();
-  }
-
-  Deoptimizer::DeoptimizeFunction(*function);
-
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_ClearFunctionTypeFeedback) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  function->shared()->ClearTypeFeedbackInfo();
-  Code* unoptimized = function->shared()->code();
-  if (unoptimized->kind() == Code::FUNCTION) {
-    unoptimized->ClearInlineCaches();
-  }
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_RunningInSimulator) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-#if defined(USE_SIMULATOR)
-  return isolate->heap()->true_value();
-#else
-  return isolate->heap()->false_value();
-#endif
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  return isolate->heap()->ToBoolean(
-      isolate->concurrent_recompilation_enabled());
-}
-
-
-RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
-  HandleScope scope(isolate);
-  RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  // The following two assertions are lifted from the DCHECKs inside
-  // JSFunction::MarkForOptimization().
-  RUNTIME_ASSERT(!function->shared()->is_generator());
-  RUNTIME_ASSERT(function->shared()->allows_lazy_compilation() ||
-                 (function->code()->kind() == Code::FUNCTION &&
-                  function->code()->optimizable()));
-
-  // If the function is optimized, just return.
-  if (function->IsOptimized()) return isolate->heap()->undefined_value();
-
-  function->MarkForOptimization();
-
-  Code* unoptimized = function->shared()->code();
-  if (args.length() == 2 &&
-      unoptimized->kind() == Code::FUNCTION) {
-    CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
-    if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("osr")) && FLAG_use_osr) {
-      // Start patching from the currently patched loop nesting level.
-      DCHECK(BackEdgeTable::Verify(isolate, unoptimized));
-      isolate->runtime_profiler()->AttemptOnStackReplacement(
-          *function, Code::kMaxLoopNestingMarker);
-    } else if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("concurrent")) &&
-               isolate->concurrent_recompilation_enabled()) {
-      function->MarkForConcurrentOptimization();
-    }
-  }
-
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSFunction, function, 0);
-  function->shared()->set_optimization_disabled(true);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
-  HandleScope scope(isolate);
-  RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
-  if (!isolate->use_crankshaft()) {
-    return Smi::FromInt(4);  // 4 == "never".
-  }
-  bool sync_with_compiler_thread = true;
-  if (args.length() == 2) {
-    CONVERT_ARG_HANDLE_CHECKED(String, sync, 1);
-    if (sync->IsOneByteEqualTo(STATIC_CHAR_VECTOR("no sync"))) {
-      sync_with_compiler_thread = false;
-    }
-  }
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  if (isolate->concurrent_recompilation_enabled() &&
-      sync_with_compiler_thread) {
-    while (function->IsInOptimizationQueue()) {
-      isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
-      base::OS::Sleep(50);
-    }
-  }
-  if (FLAG_always_opt) {
-    // We may have always opt, but that is more best-effort than a real
-    // promise, so we still say "no" if it is not optimized.
-    return function->IsOptimized() ? Smi::FromInt(3)   // 3 == "always".
-                                   : Smi::FromInt(2);  // 2 == "no".
-  }
-  if (FLAG_deopt_every_n_times) {
-    return Smi::FromInt(6);  // 6 == "maybe deopted".
-  }
-  if (function->IsOptimized() && function->code()->is_turbofanned()) {
-    return Smi::FromInt(7);  // 7 == "TurboFan compiler".
-  }
-  return function->IsOptimized() ? Smi::FromInt(1)   // 1 == "yes".
-                                 : Smi::FromInt(2);  // 2 == "no".
-}
-
-
-RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) {
-  DCHECK(args.length() == 0);
-  RUNTIME_ASSERT(FLAG_block_concurrent_recompilation);
-  RUNTIME_ASSERT(isolate->concurrent_recompilation_enabled());
-  isolate->optimizing_compiler_thread()->Unblock();
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetOptimizationCount) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  return Smi::FromInt(function->shared()->opt_count());
-}
-
-
-static bool IsSuitableForOnStackReplacement(Isolate* isolate,
-                                            Handle<JSFunction> function,
-                                            Handle<Code> current_code) {
-  // Keep track of whether we've succeeded in optimizing.
-  if (!isolate->use_crankshaft() || !current_code->optimizable()) return false;
-  // If we are trying to do OSR when there are already optimized
-  // activations of the function, it means (a) the function is directly or
-  // indirectly recursive and (b) an optimized invocation has been
-  // deoptimized so that we are currently in an unoptimized activation.
-  // Check for optimized activations of this function.
-  for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
-    JavaScriptFrame* frame = it.frame();
-    if (frame->is_optimized() && frame->function() == *function) return false;
-  }
-
-  return true;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  Handle<Code> caller_code(function->shared()->code());
-
-  // We're not prepared to handle a function with arguments object.
-  DCHECK(!function->shared()->uses_arguments());
-
-  RUNTIME_ASSERT(FLAG_use_osr);
-
-  // Passing the PC in the javascript frame from the caller directly is
-  // not GC safe, so we walk the stack to get it.
-  JavaScriptFrameIterator it(isolate);
-  JavaScriptFrame* frame = it.frame();
-  if (!caller_code->contains(frame->pc())) {
-    // Code on the stack may not be the code object referenced by the shared
-    // function info.  It may have been replaced to include deoptimization data.
-    caller_code = Handle<Code>(frame->LookupCode());
-  }
-
-  uint32_t pc_offset = static_cast<uint32_t>(
-      frame->pc() - caller_code->instruction_start());
-
-#ifdef DEBUG
-  DCHECK_EQ(frame->function(), *function);
-  DCHECK_EQ(frame->LookupCode(), *caller_code);
-  DCHECK(caller_code->contains(frame->pc()));
-#endif  // DEBUG
-
-
-  BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset);
-  DCHECK(!ast_id.IsNone());
-
-  Compiler::ConcurrencyMode mode =
-      isolate->concurrent_osr_enabled() &&
-      (function->shared()->ast_node_count() > 512) ? Compiler::CONCURRENT
-                                                   : Compiler::NOT_CONCURRENT;
-  Handle<Code> result = Handle<Code>::null();
-
-  OptimizedCompileJob* job = NULL;
-  if (mode == Compiler::CONCURRENT) {
-    // Gate the OSR entry with a stack check.
-    BackEdgeTable::AddStackCheck(caller_code, pc_offset);
-    // Poll already queued compilation jobs.
-    OptimizingCompilerThread* thread = isolate->optimizing_compiler_thread();
-    if (thread->IsQueuedForOSR(function, ast_id)) {
-      if (FLAG_trace_osr) {
-        PrintF("[OSR - Still waiting for queued: ");
-        function->PrintName();
-        PrintF(" at AST id %d]\n", ast_id.ToInt());
-      }
-      return NULL;
-    }
-
-    job = thread->FindReadyOSRCandidate(function, ast_id);
-  }
-
-  if (job != NULL) {
-    if (FLAG_trace_osr) {
-      PrintF("[OSR - Found ready: ");
-      function->PrintName();
-      PrintF(" at AST id %d]\n", ast_id.ToInt());
-    }
-    result = Compiler::GetConcurrentlyOptimizedCode(job);
-  } else if (IsSuitableForOnStackReplacement(isolate, function, caller_code)) {
-    if (FLAG_trace_osr) {
-      PrintF("[OSR - Compiling: ");
-      function->PrintName();
-      PrintF(" at AST id %d]\n", ast_id.ToInt());
-    }
-    MaybeHandle<Code> maybe_result = Compiler::GetOptimizedCode(
-        function, caller_code, mode, ast_id);
-    if (maybe_result.ToHandle(&result) &&
-        result.is_identical_to(isolate->builtins()->InOptimizationQueue())) {
-      // Optimization is queued.  Return to check later.
-      return NULL;
-    }
-  }
-
-  // Revert the patched back edge table, regardless of whether OSR succeeds.
-  BackEdgeTable::Revert(isolate, *caller_code);
-
-  // Check whether we ended up with usable optimized code.
-  if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) {
-    DeoptimizationInputData* data =
-        DeoptimizationInputData::cast(result->deoptimization_data());
-
-    if (data->OsrPcOffset()->value() >= 0) {
-      DCHECK(BailoutId(data->OsrAstId()->value()) == ast_id);
-      if (FLAG_trace_osr) {
-        PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n",
-               ast_id.ToInt(), data->OsrPcOffset()->value());
-      }
-      // TODO(titzer): this is a massive hack to make the deopt counts
-      // match. Fix heuristics for reenabling optimizations!
-      function->shared()->increment_deopt_count();
-
-      // TODO(titzer): Do not install code into the function.
-      function->ReplaceCode(*result);
-      return *result;
-    }
-  }
-
-  // Failed.
-  if (FLAG_trace_osr) {
-    PrintF("[OSR - Failed: ");
-    function->PrintName();
-    PrintF(" at AST id %d]\n", ast_id.ToInt());
-  }
-
-  if (!function->IsOptimized()) {
-    function->ReplaceCode(function->shared()->code());
-  }
-  return NULL;
-}
-
-
-RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2 || args.length() == 3);
-#ifdef DEBUG
-  CONVERT_SMI_ARG_CHECKED(interval, 0);
-  CONVERT_SMI_ARG_CHECKED(timeout, 1);
-  isolate->heap()->set_allocation_timeout(timeout);
-  FLAG_gc_interval = interval;
-  if (args.length() == 3) {
-    // Enable/disable inline allocation if requested.
-    CONVERT_BOOLEAN_ARG_CHECKED(inline_allocation, 2);
-    if (inline_allocation) {
-      isolate->heap()->EnableInlineAllocation();
-    } else {
-      isolate->heap()->DisableInlineAllocation();
-    }
-  }
-#endif
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_CheckIsBootstrapping) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetRootNaN) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
-  return isolate->heap()->nan_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_Call) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() >= 2);
-  int argc = args.length() - 2;
-  CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
-  Object* receiver = args[0];
-
-  // If there are too many arguments, allocate argv via malloc.
-  const int argv_small_size = 10;
-  Handle<Object> argv_small_buffer[argv_small_size];
-  SmartArrayPointer<Handle<Object> > argv_large_buffer;
-  Handle<Object>* argv = argv_small_buffer;
-  if (argc > argv_small_size) {
-    argv = new Handle<Object>[argc];
-    if (argv == NULL) return isolate->StackOverflow();
-    argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
-  }
-
-  for (int i = 0; i < argc; ++i) {
-     argv[i] = Handle<Object>(args[1 + i], isolate);
-  }
-
-  Handle<JSReceiver> hfun(fun);
-  Handle<Object> hreceiver(receiver, isolate);
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      Execution::Call(isolate, hfun, hreceiver, argc, argv, true));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_Apply) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 5);
-  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
-  CONVERT_INT32_ARG_CHECKED(offset, 3);
-  CONVERT_INT32_ARG_CHECKED(argc, 4);
-  RUNTIME_ASSERT(offset >= 0);
-  // Loose upper bound to allow fuzzing. We'll most likely run out of
-  // stack space before hitting this limit.
-  static int kMaxArgc = 1000000;
-  RUNTIME_ASSERT(argc >= 0 && argc <= kMaxArgc);
-
-  // If there are too many arguments, allocate argv via malloc.
-  const int argv_small_size = 10;
-  Handle<Object> argv_small_buffer[argv_small_size];
-  SmartArrayPointer<Handle<Object> > argv_large_buffer;
-  Handle<Object>* argv = argv_small_buffer;
-  if (argc > argv_small_size) {
-    argv = new Handle<Object>[argc];
-    if (argv == NULL) return isolate->StackOverflow();
-    argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
-  }
-
-  for (int i = 0; i < argc; ++i) {
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, argv[i],
-        Object::GetElement(isolate, arguments, offset + i));
-  }
-
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      Execution::Call(isolate, fun, receiver, argc, argv, true));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetFunctionDelegate) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
-  RUNTIME_ASSERT(!object->IsJSFunction());
-  return *Execution::GetFunctionDelegate(isolate, object);
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetConstructorDelegate) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
-  RUNTIME_ASSERT(!object->IsJSFunction());
-  return *Execution::GetConstructorDelegate(isolate, object);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NewGlobalContext) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
-  Handle<Context> result =
-      isolate->factory()->NewGlobalContext(function, scope_info);
-
-  DCHECK(function->context() == isolate->context());
-  DCHECK(function->context()->global_object() == result->global_object());
-  result->global_object()->set_global_context(*result);
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-
-  DCHECK(function->context() == isolate->context());
-  int length = function->shared()->scope_info()->ContextLength();
-  return *isolate->factory()->NewFunctionContext(length, function);
-}
-
-
-RUNTIME_FUNCTION(Runtime_PushWithContext) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  Handle<JSReceiver> extension_object;
-  if (args[0]->IsJSReceiver()) {
-    extension_object = args.at<JSReceiver>(0);
-  } else {
-    // Try to convert the object to a proper JavaScript object.
-    MaybeHandle<JSReceiver> maybe_object =
-        Object::ToObject(isolate, args.at<Object>(0));
-    if (!maybe_object.ToHandle(&extension_object)) {
-      Handle<Object> handle = args.at<Object>(0);
-      THROW_NEW_ERROR_RETURN_FAILURE(
-          isolate, NewTypeError("with_expression", HandleVector(&handle, 1)));
-    }
-  }
-
-  Handle<JSFunction> function;
-  if (args[1]->IsSmi()) {
-    // A smi sentinel indicates a context nested inside global code rather
-    // than some function.  There is a canonical empty function that can be
-    // gotten from the native context.
-    function = handle(isolate->native_context()->closure());
-  } else {
-    function = args.at<JSFunction>(1);
-  }
-
-  Handle<Context> current(isolate->context());
-  Handle<Context> context = isolate->factory()->NewWithContext(
-      function, current, extension_object);
-  isolate->set_context(*context);
-  return *context;
-}
-
-
-RUNTIME_FUNCTION(Runtime_PushCatchContext) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 1);
-  Handle<JSFunction> function;
-  if (args[2]->IsSmi()) {
-    // A smi sentinel indicates a context nested inside global code rather
-    // than some function.  There is a canonical empty function that can be
-    // gotten from the native context.
-    function = handle(isolate->native_context()->closure());
-  } else {
-    function = args.at<JSFunction>(2);
-  }
-  Handle<Context> current(isolate->context());
-  Handle<Context> context = isolate->factory()->NewCatchContext(
-      function, current, name, thrown_object);
-  isolate->set_context(*context);
-  return *context;
-}
-
-
-RUNTIME_FUNCTION(Runtime_PushBlockContext) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
-  Handle<JSFunction> function;
-  if (args[1]->IsSmi()) {
-    // A smi sentinel indicates a context nested inside global code rather
-    // than some function.  There is a canonical empty function that can be
-    // gotten from the native context.
-    function = handle(isolate->native_context()->closure());
-  } else {
-    function = args.at<JSFunction>(1);
-  }
-  Handle<Context> current(isolate->context());
-  Handle<Context> context = isolate->factory()->NewBlockContext(
-      function, current, scope_info);
-  isolate->set_context(*context);
-  return *context;
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsJSModule) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  return isolate->heap()->ToBoolean(obj->IsJSModule());
-}
-
-
-RUNTIME_FUNCTION(Runtime_PushModuleContext) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_SMI_ARG_CHECKED(index, 0);
-
-  if (!args[1]->IsScopeInfo()) {
-    // Module already initialized. Find hosting context and retrieve context.
-    Context* host = Context::cast(isolate->context())->global_context();
-    Context* context = Context::cast(host->get(index));
-    DCHECK(context->previous() == isolate->context());
-    isolate->set_context(context);
-    return context;
-  }
-
-  CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
-
-  // Allocate module context.
-  HandleScope scope(isolate);
-  Factory* factory = isolate->factory();
-  Handle<Context> context = factory->NewModuleContext(scope_info);
-  Handle<JSModule> module = factory->NewJSModule(context, scope_info);
-  context->set_module(*module);
-  Context* previous = isolate->context();
-  context->set_previous(previous);
-  context->set_closure(previous->closure());
-  context->set_global_object(previous->global_object());
-  isolate->set_context(*context);
-
-  // Find hosting scope and initialize internal variable holding module there.
-  previous->global_context()->set(index, *context);
-
-  return *context;
-}
-
-
-RUNTIME_FUNCTION(Runtime_DeclareModules) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0);
-  Context* host_context = isolate->context();
-
-  for (int i = 0; i < descriptions->length(); ++i) {
-    Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i)));
-    int host_index = description->host_index();
-    Handle<Context> context(Context::cast(host_context->get(host_index)));
-    Handle<JSModule> module(context->module());
-
-    for (int j = 0; j < description->length(); ++j) {
-      Handle<String> name(description->name(j));
-      VariableMode mode = description->mode(j);
-      int index = description->index(j);
-      switch (mode) {
-        case VAR:
-        case LET:
-        case CONST:
-        case CONST_LEGACY: {
-          PropertyAttributes attr =
-              IsImmutableVariableMode(mode) ? FROZEN : SEALED;
-          Handle<AccessorInfo> info =
-              Accessors::MakeModuleExport(name, index, attr);
-          Handle<Object> result =
-              JSObject::SetAccessor(module, info).ToHandleChecked();
-          DCHECK(!result->IsUndefined());
-          USE(result);
-          break;
-        }
-        case MODULE: {
-          Object* referenced_context = Context::cast(host_context)->get(index);
-          Handle<JSModule> value(Context::cast(referenced_context)->module());
-          JSObject::SetOwnPropertyIgnoreAttributes(module, name, value, FROZEN)
-              .Assert();
-          break;
-        }
-        case INTERNAL:
-        case TEMPORARY:
-        case DYNAMIC:
-        case DYNAMIC_GLOBAL:
-        case DYNAMIC_LOCAL:
-          UNREACHABLE();
-      }
-    }
-
-    JSObject::PreventExtensions(module).Assert();
-  }
-
-  DCHECK(!isolate->has_pending_exception());
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
-
-  int index;
-  PropertyAttributes attributes;
-  ContextLookupFlags flags = FOLLOW_CHAINS;
-  BindingFlags binding_flags;
-  Handle<Object> holder = context->Lookup(name,
-                                          flags,
-                                          &index,
-                                          &attributes,
-                                          &binding_flags);
-
-  // If the slot was not found the result is true.
-  if (holder.is_null()) {
-    return isolate->heap()->true_value();
-  }
-
-  // If the slot was found in a context, it should be DONT_DELETE.
-  if (holder->IsContext()) {
-    return isolate->heap()->false_value();
-  }
-
-  // The slot was found in a JSObject, either a context extension object,
-  // the global object, or the subject of a with.  Try to delete it
-  // (respecting DONT_DELETE).
-  Handle<JSObject> object = Handle<JSObject>::cast(holder);
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      JSReceiver::DeleteProperty(object, name));
-  return *result;
-}
-
-
-// A mechanism to return a pair of Object pointers in registers (if possible).
-// How this is achieved is calling convention-dependent.
-// All currently supported x86 compiles uses calling conventions that are cdecl
-// variants where a 64-bit value is returned in two 32-bit registers
-// (edx:eax on ia32, r1:r0 on ARM).
-// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
-// In Win64 calling convention, a struct of two pointers is returned in memory,
-// allocated by the caller, and passed as a pointer in a hidden first parameter.
-#ifdef V8_HOST_ARCH_64_BIT
-struct ObjectPair {
-  Object* x;
-  Object* y;
-};
-
-
-static inline ObjectPair MakePair(Object* x, Object* y) {
-  ObjectPair result = {x, y};
-  // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
-  // In Win64 they are assigned to a hidden first argument.
-  return result;
-}
-#elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
-// For x32 a 128-bit struct return is done as rax and rdx from the ObjectPair
-// are used in the full codegen and Crankshaft compiler. An alternative is
-// using uint64_t and modifying full codegen and Crankshaft compiler.
-struct ObjectPair {
-  Object* x;
-  uint32_t x_upper;
-  Object* y;
-  uint32_t y_upper;
-};
-
-
-static inline ObjectPair MakePair(Object* x, Object* y) {
-  ObjectPair result = {x, 0, y, 0};
-  // Pointers x and y returned in rax and rdx, in x32-abi.
-  return result;
-}
-#else
-typedef uint64_t ObjectPair;
-static inline ObjectPair MakePair(Object* x, Object* y) {
-#if defined(V8_TARGET_LITTLE_ENDIAN)
-  return reinterpret_cast<uint32_t>(x) |
-      (reinterpret_cast<ObjectPair>(y) << 32);
-#elif defined(V8_TARGET_BIG_ENDIAN)
-    return reinterpret_cast<uint32_t>(y) |
-        (reinterpret_cast<ObjectPair>(x) << 32);
-#else
-#error Unknown endianness
-#endif
-}
-#endif
-
-
-static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
-                                           JSObject* holder) {
-  DCHECK(!holder->IsGlobalObject());
-  Context* top = isolate->context();
-  // Get the context extension function.
-  JSFunction* context_extension_function =
-      top->native_context()->context_extension_function();
-  // If the holder isn't a context extension object, we just return it
-  // as the receiver. This allows arguments objects to be used as
-  // receivers, but only if they are put in the context scope chain
-  // explicitly via a with-statement.
-  Object* constructor = holder->map()->constructor();
-  if (constructor != context_extension_function) return holder;
-  // Fall back to using the global object as the implicit receiver if
-  // the property turns out to be a local variable allocated in a
-  // context extension object - introduced via eval.
-  return isolate->heap()->undefined_value();
-}
-
-
-static ObjectPair LoadLookupSlotHelper(Arguments args, Isolate* isolate,
-                                       bool throw_error) {
-  HandleScope scope(isolate);
-  DCHECK_EQ(2, args.length());
-
-  if (!args[0]->IsContext() || !args[1]->IsString()) {
-    return MakePair(isolate->ThrowIllegalOperation(), NULL);
-  }
-  Handle<Context> context = args.at<Context>(0);
-  Handle<String> name = args.at<String>(1);
-
-  int index;
-  PropertyAttributes attributes;
-  ContextLookupFlags flags = FOLLOW_CHAINS;
-  BindingFlags binding_flags;
-  Handle<Object> holder = context->Lookup(name,
-                                          flags,
-                                          &index,
-                                          &attributes,
-                                          &binding_flags);
-  if (isolate->has_pending_exception()) {
-    return MakePair(isolate->heap()->exception(), NULL);
-  }
-
-  // If the index is non-negative, the slot has been found in a context.
-  if (index >= 0) {
-    DCHECK(holder->IsContext());
-    // If the "property" we were looking for is a local variable, the
-    // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
-    Handle<Object> receiver = isolate->factory()->undefined_value();
-    Object* value = Context::cast(*holder)->get(index);
-    // Check for uninitialized bindings.
-    switch (binding_flags) {
-      case MUTABLE_CHECK_INITIALIZED:
-      case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
-        if (value->IsTheHole()) {
-          Handle<Object> error;
-          MaybeHandle<Object> maybe_error =
-              isolate->factory()->NewReferenceError("not_defined",
-                                                    HandleVector(&name, 1));
-          if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
-          return MakePair(isolate->heap()->exception(), NULL);
-        }
-        // FALLTHROUGH
-      case MUTABLE_IS_INITIALIZED:
-      case IMMUTABLE_IS_INITIALIZED:
-      case IMMUTABLE_IS_INITIALIZED_HARMONY:
-        DCHECK(!value->IsTheHole());
-        return MakePair(value, *receiver);
-      case IMMUTABLE_CHECK_INITIALIZED:
-        if (value->IsTheHole()) {
-          DCHECK((attributes & READ_ONLY) != 0);
-          value = isolate->heap()->undefined_value();
-        }
-        return MakePair(value, *receiver);
-      case MISSING_BINDING:
-        UNREACHABLE();
-        return MakePair(NULL, NULL);
-    }
-  }
-
-  // Otherwise, if the slot was found the holder is a context extension
-  // object, subject of a with, or a global object.  We read the named
-  // property from it.
-  if (!holder.is_null()) {
-    Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
-#ifdef DEBUG
-    if (!object->IsJSProxy()) {
-      Maybe<bool> maybe = JSReceiver::HasProperty(object, name);
-      DCHECK(maybe.has_value);
-      DCHECK(maybe.value);
-    }
-#endif
-    // GetProperty below can cause GC.
-    Handle<Object> receiver_handle(
-        object->IsGlobalObject()
-            ? Object::cast(isolate->heap()->undefined_value())
-            : object->IsJSProxy() ? static_cast<Object*>(*object)
-                : ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)),
-        isolate);
-
-    // No need to unhole the value here.  This is taken care of by the
-    // GetProperty function.
-    Handle<Object> value;
-    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-        isolate, value,
-        Object::GetProperty(object, name),
-        MakePair(isolate->heap()->exception(), NULL));
-    return MakePair(*value, *receiver_handle);
-  }
-
-  if (throw_error) {
-    // The property doesn't exist - throw exception.
-    Handle<Object> error;
-    MaybeHandle<Object> maybe_error = isolate->factory()->NewReferenceError(
-        "not_defined", HandleVector(&name, 1));
-    if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
-    return MakePair(isolate->heap()->exception(), NULL);
-  } else {
-    // The property doesn't exist - return undefined.
-    return MakePair(isolate->heap()->undefined_value(),
-                    isolate->heap()->undefined_value());
-  }
-}
-
-
-RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlot) {
-  return LoadLookupSlotHelper(args, isolate, true);
-}
-
-
-RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotNoReferenceError) {
-  return LoadLookupSlotHelper(args, isolate, false);
-}
-
-
-RUNTIME_FUNCTION(Runtime_StoreLookupSlot) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-
-  CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
-  CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 3);
-
-  int index;
-  PropertyAttributes attributes;
-  ContextLookupFlags flags = FOLLOW_CHAINS;
-  BindingFlags binding_flags;
-  Handle<Object> holder = context->Lookup(name,
-                                          flags,
-                                          &index,
-                                          &attributes,
-                                          &binding_flags);
-  // In case of JSProxy, an exception might have been thrown.
-  if (isolate->has_pending_exception()) return isolate->heap()->exception();
-
-  // The property was found in a context slot.
-  if (index >= 0) {
-    if ((attributes & READ_ONLY) == 0) {
-      Handle<Context>::cast(holder)->set(index, *value);
-    } else if (strict_mode == STRICT) {
-      // Setting read only property in strict mode.
-      THROW_NEW_ERROR_RETURN_FAILURE(
-          isolate,
-          NewTypeError("strict_cannot_assign", HandleVector(&name, 1)));
-    }
-    return *value;
-  }
-
-  // Slow case: The property is not in a context slot.  It is either in a
-  // context extension object, a property of the subject of a with, or a
-  // property of the global object.
-  Handle<JSReceiver> object;
-  if (attributes != ABSENT) {
-    // The property exists on the holder.
-    object = Handle<JSReceiver>::cast(holder);
-  } else if (strict_mode == STRICT) {
-    // If absent in strict mode: throw.
-    THROW_NEW_ERROR_RETURN_FAILURE(
-        isolate, NewReferenceError("not_defined", HandleVector(&name, 1)));
-  } else {
-    // If absent in sloppy mode: add the property to the global object.
-    object = Handle<JSReceiver>(context->global_object());
-  }
-
-  RETURN_FAILURE_ON_EXCEPTION(
-      isolate, Object::SetProperty(object, name, value, strict_mode));
-
-  return *value;
-}
-
-
-RUNTIME_FUNCTION(Runtime_Throw) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  return isolate->Throw(args[0]);
-}
-
-
-RUNTIME_FUNCTION(Runtime_ReThrow) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  return isolate->ReThrow(args[0]);
-}
-
-
-RUNTIME_FUNCTION(Runtime_PromoteScheduledException) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  return isolate->PromoteScheduledException();
-}
-
-
-RUNTIME_FUNCTION(Runtime_ThrowReferenceError) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
-  THROW_NEW_ERROR_RETURN_FAILURE(
-      isolate, NewReferenceError("not_defined", HandleVector(&name, 1)));
-}
-
-
-RUNTIME_FUNCTION(Runtime_ThrowNonMethodError) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-  THROW_NEW_ERROR_RETURN_FAILURE(
-      isolate, NewReferenceError("non_method", HandleVector<Object>(NULL, 0)));
-}
-
-
-RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-  THROW_NEW_ERROR_RETURN_FAILURE(
-      isolate,
-      NewReferenceError("unsupported_super", HandleVector<Object>(NULL, 0)));
-}
-
-
-RUNTIME_FUNCTION(Runtime_ThrowNotDateError) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-  THROW_NEW_ERROR_RETURN_FAILURE(
-      isolate, NewTypeError("not_date_object", HandleVector<Object>(NULL, 0)));
-}
-
-
-RUNTIME_FUNCTION(Runtime_StackGuard) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-
-  // First check if this is a real stack overflow.
-  StackLimitCheck check(isolate);
-  if (check.JsHasOverflowed()) {
-    return isolate->StackOverflow();
-  }
-
-  return isolate->stack_guard()->HandleInterrupts();
-}
-
-
-RUNTIME_FUNCTION(Runtime_TryInstallOptimizedCode) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-
-  // First check if this is a real stack overflow.
-  StackLimitCheck check(isolate);
-  if (check.JsHasOverflowed()) {
-    SealHandleScope shs(isolate);
-    return isolate->StackOverflow();
-  }
-
-  isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
-  return (function->IsOptimized()) ? function->code()
-                                   : function->shared()->code();
-}
-
-
-RUNTIME_FUNCTION(Runtime_Interrupt) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  return isolate->stack_guard()->HandleInterrupts();
-}
-
-
-static int StackSize(Isolate* isolate) {
-  int n = 0;
-  for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
-  return n;
-}
-
-
-static void PrintTransition(Isolate* isolate, Object* result) {
-  // indentation
-  { const int nmax = 80;
-    int n = StackSize(isolate);
-    if (n <= nmax)
-      PrintF("%4d:%*s", n, n, "");
-    else
-      PrintF("%4d:%*s", n, nmax, "...");
-  }
-
-  if (result == NULL) {
-    JavaScriptFrame::PrintTop(isolate, stdout, true, false);
-    PrintF(" {\n");
-  } else {
-    // function result
-    PrintF("} -> ");
-    result->ShortPrint();
-    PrintF("\n");
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_TraceEnter) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  PrintTransition(isolate, NULL);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_TraceExit) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  PrintTransition(isolate, obj);
-  return obj;  // return TOS
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugPrint) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-
-  OFStream os(stdout);
-#ifdef DEBUG
-  if (args[0]->IsString()) {
-    // If we have a string, assume it's a code "marker"
-    // and print some interesting cpu debugging info.
-    JavaScriptFrameIterator it(isolate);
-    JavaScriptFrame* frame = it.frame();
-    os << "fp = " << frame->fp() << ", sp = " << frame->sp()
-       << ", caller_sp = " << frame->caller_sp() << ": ";
-  } else {
-    os << "DebugPrint: ";
-  }
-  args[0]->Print(os);
-  if (args[0]->IsHeapObject()) {
-    os << "\n";
-    HeapObject::cast(args[0])->map()->Print(os);
-  }
-#else
-  // ShortPrint is available in release mode. Print is not.
-  os << Brief(args[0]);
-#endif
-  os << endl;
-
-  return args[0];  // return TOS
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugTrace) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  isolate->PrintStack(stdout);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DateCurrentTime) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-  if (FLAG_log_timer_events) LOG(isolate, CurrentTimeEvent());
-
-  // According to ECMA-262, section 15.9.1, page 117, the precision of
-  // the number in a Date object representing a particular instant in
-  // time is milliseconds. Therefore, we floor the result of getting
-  // the OS time.
-  double millis;
-  if (FLAG_verify_predictable) {
-    millis = 1388534400000.0;  // Jan 1 2014 00:00:00 GMT+0000
-    millis += Floor(isolate->heap()->synthetic_time());
-  } else {
-    millis = Floor(base::OS::TimeCurrentMillis());
-  }
-  return *isolate->factory()->NewNumber(millis);
-}
-
-
-RUNTIME_FUNCTION(Runtime_DateParseString) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
-
-  RUNTIME_ASSERT(output->HasFastElements());
-  JSObject::EnsureCanContainHeapObjectElements(output);
-  RUNTIME_ASSERT(output->HasFastObjectElements());
-  Handle<FixedArray> output_array(FixedArray::cast(output->elements()));
-  RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
-
-  str = String::Flatten(str);
-  DisallowHeapAllocation no_gc;
-
-  bool result;
-  String::FlatContent str_content = str->GetFlatContent();
-  if (str_content.IsOneByte()) {
-    result = DateParser::Parse(str_content.ToOneByteVector(),
-                               *output_array,
-                               isolate->unicode_cache());
-  } else {
-    DCHECK(str_content.IsTwoByte());
-    result = DateParser::Parse(str_content.ToUC16Vector(),
-                               *output_array,
-                               isolate->unicode_cache());
-  }
-
-  if (result) {
-    return *output;
-  } else {
-    return isolate->heap()->null_value();
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_DateLocalTimezone) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs &&
-                 x <= DateCache::kMaxTimeBeforeUTCInMs);
-  const char* zone =
-      isolate->date_cache()->LocalTimezone(static_cast<int64_t>(x));
-  Handle<String> result = isolate->factory()->NewStringFromUtf8(
-      CStrVector(zone)).ToHandleChecked();
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_DateToUTC) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs &&
-                 x <= DateCache::kMaxTimeBeforeUTCInMs);
-  int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
-
-  return *isolate->factory()->NewNumber(static_cast<double>(time));
-}
-
-
-RUNTIME_FUNCTION(Runtime_DateCacheVersion) {
-  HandleScope hs(isolate);
-  DCHECK(args.length() == 0);
-  if (!isolate->eternal_handles()->Exists(EternalHandles::DATE_CACHE_VERSION)) {
-    Handle<FixedArray> date_cache_version =
-        isolate->factory()->NewFixedArray(1, TENURED);
-    date_cache_version->set(0, Smi::FromInt(0));
-    isolate->eternal_handles()->CreateSingleton(
-        isolate, *date_cache_version, EternalHandles::DATE_CACHE_VERSION);
-  }
-  Handle<FixedArray> date_cache_version =
-      Handle<FixedArray>::cast(isolate->eternal_handles()->GetSingleton(
-          EternalHandles::DATE_CACHE_VERSION));
-  // Return result as a JS array.
-  Handle<JSObject> result =
-      isolate->factory()->NewJSObject(isolate->array_function());
-  JSArray::SetContent(Handle<JSArray>::cast(result), date_cache_version);
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_GlobalProxy) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, global, 0);
-  if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
-  return JSGlobalObject::cast(global)->global_proxy();
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsAttachedGlobal) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, global, 0);
-  if (!global->IsJSGlobalObject()) return isolate->heap()->false_value();
-  return isolate->heap()->ToBoolean(
-      !JSGlobalObject::cast(global)->IsDetached());
-}
-
-
-RUNTIME_FUNCTION(Runtime_ParseJson) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
-
-  source = String::Flatten(source);
-  // Optimized fast case where we only have Latin1 characters.
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      source->IsSeqOneByteString() ? JsonParser<true>::Parse(source)
-                                   : JsonParser<false>::Parse(source));
-  return *result;
-}
-
-
-bool CodeGenerationFromStringsAllowed(Isolate* isolate,
-                                      Handle<Context> context) {
-  DCHECK(context->allow_code_gen_from_strings()->IsFalse());
-  // Check with callback if set.
-  AllowCodeGenerationFromStringsCallback callback =
-      isolate->allow_code_gen_callback();
-  if (callback == NULL) {
-    // No callback set and code generation disallowed.
-    return false;
-  } else {
-    // Callback set. Let it decide if code generation is allowed.
-    VMState<EXTERNAL> state(isolate);
-    return callback(v8::Utils::ToLocal(context));
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_CompileString) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
-  CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1);
-
-  // Extract native context.
-  Handle<Context> context(isolate->native_context());
-
-  // Check if native context allows code generation from
-  // strings. Throw an exception if it doesn't.
-  if (context->allow_code_gen_from_strings()->IsFalse() &&
-      !CodeGenerationFromStringsAllowed(isolate, context)) {
-    Handle<Object> error_message =
-        context->ErrorMessageForCodeGenerationFromStrings();
-    THROW_NEW_ERROR_RETURN_FAILURE(
-        isolate, NewEvalError("code_gen_from_strings",
-                              HandleVector<Object>(&error_message, 1)));
-  }
-
-  // Compile source string in the native context.
-  ParseRestriction restriction = function_literal_only
-      ? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION;
-  Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate);
-  Handle<JSFunction> fun;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, fun,
-      Compiler::GetFunctionFromEval(
-          source, outer_info,
-          context, SLOPPY, restriction, RelocInfo::kNoPosition));
-  return *fun;
-}
-
-
-static ObjectPair CompileGlobalEval(Isolate* isolate,
-                                    Handle<String> source,
-                                    Handle<SharedFunctionInfo> outer_info,
-                                    Handle<Object> receiver,
-                                    StrictMode strict_mode,
-                                    int scope_position) {
-  Handle<Context> context = Handle<Context>(isolate->context());
-  Handle<Context> native_context = Handle<Context>(context->native_context());
-
-  // Check if native context allows code generation from
-  // strings. Throw an exception if it doesn't.
-  if (native_context->allow_code_gen_from_strings()->IsFalse() &&
-      !CodeGenerationFromStringsAllowed(isolate, native_context)) {
-    Handle<Object> error_message =
-        native_context->ErrorMessageForCodeGenerationFromStrings();
-    Handle<Object> error;
-    MaybeHandle<Object> maybe_error = isolate->factory()->NewEvalError(
-        "code_gen_from_strings", HandleVector<Object>(&error_message, 1));
-    if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
-    return MakePair(isolate->heap()->exception(), NULL);
-  }
-
-  // Deal with a normal eval call with a string argument. Compile it
-  // and return the compiled function bound in the local context.
-  static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
-  Handle<JSFunction> compiled;
-  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-      isolate, compiled,
-      Compiler::GetFunctionFromEval(
-          source, outer_info,
-          context, strict_mode, restriction, scope_position),
-      MakePair(isolate->heap()->exception(), NULL));
-  return MakePair(*compiled, *receiver);
-}
-
-
-RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ResolvePossiblyDirectEval) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 6);
-
-  Handle<Object> callee = args.at<Object>(0);
-
-  // If "eval" didn't refer to the original GlobalEval, it's not a
-  // direct call to eval.
-  // (And even if it is, but the first argument isn't a string, just let
-  // execution default to an indirect call to eval, which will also return
-  // the first argument without doing anything).
-  if (*callee != isolate->native_context()->global_eval_fun() ||
-      !args[1]->IsString()) {
-    return MakePair(*callee, isolate->heap()->undefined_value());
-  }
-
-  DCHECK(args[4]->IsSmi());
-  DCHECK(args.smi_at(4) == SLOPPY || args.smi_at(4) == STRICT);
-  StrictMode strict_mode = static_cast<StrictMode>(args.smi_at(4));
-  DCHECK(args[5]->IsSmi());
-  Handle<SharedFunctionInfo> outer_info(args.at<JSFunction>(2)->shared(),
-                                        isolate);
-  return CompileGlobalEval(isolate,
-                           args.at<String>(1),
-                           outer_info,
-                           args.at<Object>(3),
-                           strict_mode,
-                           args.smi_at(5));
-}
-
-
-RUNTIME_FUNCTION(Runtime_AllocateInNewSpace) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_SMI_ARG_CHECKED(size, 0);
-  RUNTIME_ASSERT(IsAligned(size, kPointerSize));
-  RUNTIME_ASSERT(size > 0);
-  RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize);
-  return *isolate->factory()->NewFillerObject(size, false, NEW_SPACE);
-}
-
-
-RUNTIME_FUNCTION(Runtime_AllocateInTargetSpace) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_SMI_ARG_CHECKED(size, 0);
-  CONVERT_SMI_ARG_CHECKED(flags, 1);
-  RUNTIME_ASSERT(IsAligned(size, kPointerSize));
-  RUNTIME_ASSERT(size > 0);
-  RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize);
-  bool double_align = AllocateDoubleAlignFlag::decode(flags);
-  AllocationSpace space = AllocateTargetSpace::decode(flags);
-  return *isolate->factory()->NewFillerObject(size, double_align, space);
-}
-
-
-// Push an object unto an array of objects if it is not already in the
-// array.  Returns true if the element was pushed on the stack and
-// false otherwise.
-RUNTIME_FUNCTION(Runtime_PushIfAbsent) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, element, 1);
-  RUNTIME_ASSERT(array->HasFastSmiOrObjectElements());
-  int length = Smi::cast(array->length())->value();
-  FixedArray* elements = FixedArray::cast(array->elements());
-  for (int i = 0; i < length; i++) {
-    if (elements->get(i) == *element) return isolate->heap()->false_value();
-  }
-
-  // Strict not needed. Used for cycle detection in Array join implementation.
-  RETURN_FAILURE_ON_EXCEPTION(
-      isolate,
-      JSObject::SetFastElement(array, length, element, SLOPPY, true));
-  return isolate->heap()->true_value();
-}
-
-
-/**
- * A simple visitor visits every element of Array's.
- * The backend storage can be a fixed array for fast elements case,
- * or a dictionary for sparse array. Since Dictionary is a subtype
- * of FixedArray, the class can be used by both fast and slow cases.
- * The second parameter of the constructor, fast_elements, specifies
- * whether the storage is a FixedArray or Dictionary.
- *
- * An index limit is used to deal with the situation that a result array
- * length overflows 32-bit non-negative integer.
- */
-class ArrayConcatVisitor {
- public:
-  ArrayConcatVisitor(Isolate* isolate,
-                     Handle<FixedArray> storage,
-                     bool fast_elements) :
-      isolate_(isolate),
-      storage_(Handle<FixedArray>::cast(
-          isolate->global_handles()->Create(*storage))),
-      index_offset_(0u),
-      fast_elements_(fast_elements),
-      exceeds_array_limit_(false) { }
-
-  ~ArrayConcatVisitor() {
-    clear_storage();
-  }
-
-  void visit(uint32_t i, Handle<Object> elm) {
-    if (i > JSObject::kMaxElementCount - index_offset_) {
-      exceeds_array_limit_ = true;
-      return;
-    }
-    uint32_t index = index_offset_ + i;
-
-    if (fast_elements_) {
-      if (index < static_cast<uint32_t>(storage_->length())) {
-        storage_->set(index, *elm);
-        return;
-      }
-      // Our initial estimate of length was foiled, possibly by
-      // getters on the arrays increasing the length of later arrays
-      // during iteration.
-      // This shouldn't happen in anything but pathological cases.
-      SetDictionaryMode();
-      // Fall-through to dictionary mode.
-    }
-    DCHECK(!fast_elements_);
-    Handle<SeededNumberDictionary> dict(
-        SeededNumberDictionary::cast(*storage_));
-    Handle<SeededNumberDictionary> result =
-        SeededNumberDictionary::AtNumberPut(dict, index, elm);
-    if (!result.is_identical_to(dict)) {
-      // Dictionary needed to grow.
-      clear_storage();
-      set_storage(*result);
-    }
-  }
-
-  void increase_index_offset(uint32_t delta) {
-    if (JSObject::kMaxElementCount - index_offset_ < delta) {
-      index_offset_ = JSObject::kMaxElementCount;
-    } else {
-      index_offset_ += delta;
-    }
-    // If the initial length estimate was off (see special case in visit()),
-    // but the array blowing the limit didn't contain elements beyond the
-    // provided-for index range, go to dictionary mode now.
-    if (fast_elements_ &&
-        index_offset_ >
-            static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) {
-      SetDictionaryMode();
-    }
-  }
-
-  bool exceeds_array_limit() {
-    return exceeds_array_limit_;
-  }
-
-  Handle<JSArray> ToArray() {
-    Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
-    Handle<Object> length =
-        isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
-    Handle<Map> map = JSObject::GetElementsTransitionMap(
-        array,
-        fast_elements_ ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS);
-    array->set_map(*map);
-    array->set_length(*length);
-    array->set_elements(*storage_);
-    return array;
-  }
-
- private:
-  // Convert storage to dictionary mode.
-  void SetDictionaryMode() {
-    DCHECK(fast_elements_);
-    Handle<FixedArray> current_storage(*storage_);
-    Handle<SeededNumberDictionary> slow_storage(
-        SeededNumberDictionary::New(isolate_, current_storage->length()));
-    uint32_t current_length = static_cast<uint32_t>(current_storage->length());
-    for (uint32_t i = 0; i < current_length; i++) {
-      HandleScope loop_scope(isolate_);
-      Handle<Object> element(current_storage->get(i), isolate_);
-      if (!element->IsTheHole()) {
-        Handle<SeededNumberDictionary> new_storage =
-            SeededNumberDictionary::AtNumberPut(slow_storage, i, element);
-        if (!new_storage.is_identical_to(slow_storage)) {
-          slow_storage = loop_scope.CloseAndEscape(new_storage);
-        }
-      }
-    }
-    clear_storage();
-    set_storage(*slow_storage);
-    fast_elements_ = false;
-  }
-
-  inline void clear_storage() {
-    GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
-  }
-
-  inline void set_storage(FixedArray* storage) {
-    storage_ = Handle<FixedArray>::cast(
-        isolate_->global_handles()->Create(storage));
-  }
-
-  Isolate* isolate_;
-  Handle<FixedArray> storage_;  // Always a global handle.
-  // Index after last seen index. Always less than or equal to
-  // JSObject::kMaxElementCount.
-  uint32_t index_offset_;
-  bool fast_elements_ : 1;
-  bool exceeds_array_limit_ : 1;
-};
-
-
-static uint32_t EstimateElementCount(Handle<JSArray> array) {
-  uint32_t length = static_cast<uint32_t>(array->length()->Number());
-  int element_count = 0;
-  switch (array->GetElementsKind()) {
-    case FAST_SMI_ELEMENTS:
-    case FAST_HOLEY_SMI_ELEMENTS:
-    case FAST_ELEMENTS:
-    case FAST_HOLEY_ELEMENTS: {
-      // Fast elements can't have lengths that are not representable by
-      // a 32-bit signed integer.
-      DCHECK(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
-      int fast_length = static_cast<int>(length);
-      Handle<FixedArray> elements(FixedArray::cast(array->elements()));
-      for (int i = 0; i < fast_length; i++) {
-        if (!elements->get(i)->IsTheHole()) element_count++;
-      }
-      break;
-    }
-    case FAST_DOUBLE_ELEMENTS:
-    case FAST_HOLEY_DOUBLE_ELEMENTS: {
-      // Fast elements can't have lengths that are not representable by
-      // a 32-bit signed integer.
-      DCHECK(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
-      int fast_length = static_cast<int>(length);
-      if (array->elements()->IsFixedArray()) {
-        DCHECK(FixedArray::cast(array->elements())->length() == 0);
-        break;
-      }
-      Handle<FixedDoubleArray> elements(
-          FixedDoubleArray::cast(array->elements()));
-      for (int i = 0; i < fast_length; i++) {
-        if (!elements->is_the_hole(i)) element_count++;
-      }
-      break;
-    }
-    case DICTIONARY_ELEMENTS: {
-      Handle<SeededNumberDictionary> dictionary(
-          SeededNumberDictionary::cast(array->elements()));
-      int capacity = dictionary->Capacity();
-      for (int i = 0; i < capacity; i++) {
-        Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate());
-        if (dictionary->IsKey(*key)) {
-          element_count++;
-        }
-      }
-      break;
-    }
-    case SLOPPY_ARGUMENTS_ELEMENTS:
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                      \
-    case EXTERNAL_##TYPE##_ELEMENTS:                                         \
-    case TYPE##_ELEMENTS:                                                    \
-
-    TYPED_ARRAYS(TYPED_ARRAY_CASE)
-#undef TYPED_ARRAY_CASE
-      // External arrays are always dense.
-      return length;
-  }
-  // As an estimate, we assume that the prototype doesn't contain any
-  // inherited elements.
-  return element_count;
-}
-
-
-
-template<class ExternalArrayClass, class ElementType>
-static void IterateExternalArrayElements(Isolate* isolate,
-                                         Handle<JSObject> receiver,
-                                         bool elements_are_ints,
-                                         bool elements_are_guaranteed_smis,
-                                         ArrayConcatVisitor* visitor) {
-  Handle<ExternalArrayClass> array(
-      ExternalArrayClass::cast(receiver->elements()));
-  uint32_t len = static_cast<uint32_t>(array->length());
-
-  DCHECK(visitor != NULL);
-  if (elements_are_ints) {
-    if (elements_are_guaranteed_smis) {
-      for (uint32_t j = 0; j < len; j++) {
-        HandleScope loop_scope(isolate);
-        Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))),
-                      isolate);
-        visitor->visit(j, e);
-      }
-    } else {
-      for (uint32_t j = 0; j < len; j++) {
-        HandleScope loop_scope(isolate);
-        int64_t val = static_cast<int64_t>(array->get_scalar(j));
-        if (Smi::IsValid(static_cast<intptr_t>(val))) {
-          Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate);
-          visitor->visit(j, e);
-        } else {
-          Handle<Object> e =
-              isolate->factory()->NewNumber(static_cast<ElementType>(val));
-          visitor->visit(j, e);
-        }
-      }
-    }
-  } else {
-    for (uint32_t j = 0; j < len; j++) {
-      HandleScope loop_scope(isolate);
-      Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
-      visitor->visit(j, e);
-    }
-  }
-}
-
-
-// Used for sorting indices in a List<uint32_t>.
-static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
-  uint32_t a = *ap;
-  uint32_t b = *bp;
-  return (a == b) ? 0 : (a < b) ? -1 : 1;
-}
-
-
-static void CollectElementIndices(Handle<JSObject> object,
-                                  uint32_t range,
-                                  List<uint32_t>* indices) {
-  Isolate* isolate = object->GetIsolate();
-  ElementsKind kind = object->GetElementsKind();
-  switch (kind) {
-    case FAST_SMI_ELEMENTS:
-    case FAST_ELEMENTS:
-    case FAST_HOLEY_SMI_ELEMENTS:
-    case FAST_HOLEY_ELEMENTS: {
-      Handle<FixedArray> elements(FixedArray::cast(object->elements()));
-      uint32_t length = static_cast<uint32_t>(elements->length());
-      if (range < length) length = range;
-      for (uint32_t i = 0; i < length; i++) {
-        if (!elements->get(i)->IsTheHole()) {
-          indices->Add(i);
-        }
-      }
-      break;
-    }
-    case FAST_HOLEY_DOUBLE_ELEMENTS:
-    case FAST_DOUBLE_ELEMENTS: {
-      if (object->elements()->IsFixedArray()) {
-        DCHECK(object->elements()->length() == 0);
-        break;
-      }
-      Handle<FixedDoubleArray> elements(
-          FixedDoubleArray::cast(object->elements()));
-      uint32_t length = static_cast<uint32_t>(elements->length());
-      if (range < length) length = range;
-      for (uint32_t i = 0; i < length; i++) {
-        if (!elements->is_the_hole(i)) {
-          indices->Add(i);
-        }
-      }
-      break;
-    }
-    case DICTIONARY_ELEMENTS: {
-      Handle<SeededNumberDictionary> dict(
-          SeededNumberDictionary::cast(object->elements()));
-      uint32_t capacity = dict->Capacity();
-      for (uint32_t j = 0; j < capacity; j++) {
-        HandleScope loop_scope(isolate);
-        Handle<Object> k(dict->KeyAt(j), isolate);
-        if (dict->IsKey(*k)) {
-          DCHECK(k->IsNumber());
-          uint32_t index = static_cast<uint32_t>(k->Number());
-          if (index < range) {
-            indices->Add(index);
-          }
-        }
-      }
-      break;
-    }
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
-    case TYPE##_ELEMENTS:                               \
-    case EXTERNAL_##TYPE##_ELEMENTS:
-
-      TYPED_ARRAYS(TYPED_ARRAY_CASE)
-#undef TYPED_ARRAY_CASE
-    {
-      uint32_t length = static_cast<uint32_t>(
-          FixedArrayBase::cast(object->elements())->length());
-      if (range <= length) {
-        length = range;
-        // We will add all indices, so we might as well clear it first
-        // and avoid duplicates.
-        indices->Clear();
-      }
-      for (uint32_t i = 0; i < length; i++) {
-        indices->Add(i);
-      }
-      if (length == range) return;  // All indices accounted for already.
-      break;
-    }
-    case SLOPPY_ARGUMENTS_ELEMENTS: {
-      MaybeHandle<Object> length_obj =
-          Object::GetProperty(object, isolate->factory()->length_string());
-      double length_num = length_obj.ToHandleChecked()->Number();
-      uint32_t length = static_cast<uint32_t>(DoubleToInt32(length_num));
-      ElementsAccessor* accessor = object->GetElementsAccessor();
-      for (uint32_t i = 0; i < length; i++) {
-        if (accessor->HasElement(object, object, i)) {
-          indices->Add(i);
-        }
-      }
-      break;
-    }
-  }
-
-  PrototypeIterator iter(isolate, object);
-  if (!iter.IsAtEnd()) {
-    // The prototype will usually have no inherited element indices,
-    // but we have to check.
-    CollectElementIndices(
-        Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), range,
-        indices);
-  }
-}
-
-
-/**
- * A helper function that visits elements of a JSArray in numerical
- * order.
- *
- * The visitor argument called for each existing element in the array
- * with the element index and the element's value.
- * Afterwards it increments the base-index of the visitor by the array
- * length.
- * Returns false if any access threw an exception, otherwise true.
- */
-static bool IterateElements(Isolate* isolate,
-                            Handle<JSArray> receiver,
-                            ArrayConcatVisitor* visitor) {
-  uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
-  switch (receiver->GetElementsKind()) {
-    case FAST_SMI_ELEMENTS:
-    case FAST_ELEMENTS:
-    case FAST_HOLEY_SMI_ELEMENTS:
-    case FAST_HOLEY_ELEMENTS: {
-      // Run through the elements FixedArray and use HasElement and GetElement
-      // to check the prototype for missing elements.
-      Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
-      int fast_length = static_cast<int>(length);
-      DCHECK(fast_length <= elements->length());
-      for (int j = 0; j < fast_length; j++) {
-        HandleScope loop_scope(isolate);
-        Handle<Object> element_value(elements->get(j), isolate);
-        if (!element_value->IsTheHole()) {
-          visitor->visit(j, element_value);
-        } else {
-          Maybe<bool> maybe = JSReceiver::HasElement(receiver, j);
-          if (!maybe.has_value) return false;
-          if (maybe.value) {
-            // Call GetElement on receiver, not its prototype, or getters won't
-            // have the correct receiver.
-            ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-                isolate, element_value,
-                Object::GetElement(isolate, receiver, j), false);
-            visitor->visit(j, element_value);
-          }
-        }
-      }
-      break;
-    }
-    case FAST_HOLEY_DOUBLE_ELEMENTS:
-    case FAST_DOUBLE_ELEMENTS: {
-      // Empty array is FixedArray but not FixedDoubleArray.
-      if (length == 0) break;
-      // Run through the elements FixedArray and use HasElement and GetElement
-      // to check the prototype for missing elements.
-      if (receiver->elements()->IsFixedArray()) {
-        DCHECK(receiver->elements()->length() == 0);
-        break;
-      }
-      Handle<FixedDoubleArray> elements(
-          FixedDoubleArray::cast(receiver->elements()));
-      int fast_length = static_cast<int>(length);
-      DCHECK(fast_length <= elements->length());
-      for (int j = 0; j < fast_length; j++) {
-        HandleScope loop_scope(isolate);
-        if (!elements->is_the_hole(j)) {
-          double double_value = elements->get_scalar(j);
-          Handle<Object> element_value =
-              isolate->factory()->NewNumber(double_value);
-          visitor->visit(j, element_value);
-        } else {
-          Maybe<bool> maybe = JSReceiver::HasElement(receiver, j);
-          if (!maybe.has_value) return false;
-          if (maybe.value) {
-            // Call GetElement on receiver, not its prototype, or getters won't
-            // have the correct receiver.
-            Handle<Object> element_value;
-            ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-                isolate, element_value,
-                Object::GetElement(isolate, receiver, j), false);
-            visitor->visit(j, element_value);
-          }
-        }
-      }
-      break;
-    }
-    case DICTIONARY_ELEMENTS: {
-      Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
-      List<uint32_t> indices(dict->Capacity() / 2);
-      // Collect all indices in the object and the prototypes less
-      // than length. This might introduce duplicates in the indices list.
-      CollectElementIndices(receiver, length, &indices);
-      indices.Sort(&compareUInt32);
-      int j = 0;
-      int n = indices.length();
-      while (j < n) {
-        HandleScope loop_scope(isolate);
-        uint32_t index = indices[j];
-        Handle<Object> element;
-        ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-            isolate, element,
-            Object::GetElement(isolate, receiver, index),
-            false);
-        visitor->visit(index, element);
-        // Skip to next different index (i.e., omit duplicates).
-        do {
-          j++;
-        } while (j < n && indices[j] == index);
-      }
-      break;
-    }
-    case EXTERNAL_UINT8_CLAMPED_ELEMENTS: {
-      Handle<ExternalUint8ClampedArray> pixels(ExternalUint8ClampedArray::cast(
-          receiver->elements()));
-      for (uint32_t j = 0; j < length; j++) {
-        Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
-        visitor->visit(j, e);
-      }
-      break;
-    }
-    case EXTERNAL_INT8_ELEMENTS: {
-      IterateExternalArrayElements<ExternalInt8Array, int8_t>(
-          isolate, receiver, true, true, visitor);
-      break;
-    }
-    case EXTERNAL_UINT8_ELEMENTS: {
-      IterateExternalArrayElements<ExternalUint8Array, uint8_t>(
-          isolate, receiver, true, true, visitor);
-      break;
-    }
-    case EXTERNAL_INT16_ELEMENTS: {
-      IterateExternalArrayElements<ExternalInt16Array, int16_t>(
-          isolate, receiver, true, true, visitor);
-      break;
-    }
-    case EXTERNAL_UINT16_ELEMENTS: {
-      IterateExternalArrayElements<ExternalUint16Array, uint16_t>(
-          isolate, receiver, true, true, visitor);
-      break;
-    }
-    case EXTERNAL_INT32_ELEMENTS: {
-      IterateExternalArrayElements<ExternalInt32Array, int32_t>(
-          isolate, receiver, true, false, visitor);
-      break;
-    }
-    case EXTERNAL_UINT32_ELEMENTS: {
-      IterateExternalArrayElements<ExternalUint32Array, uint32_t>(
-          isolate, receiver, true, false, visitor);
-      break;
-    }
-    case EXTERNAL_FLOAT32_ELEMENTS: {
-      IterateExternalArrayElements<ExternalFloat32Array, float>(
-          isolate, receiver, false, false, visitor);
-      break;
-    }
-    case EXTERNAL_FLOAT64_ELEMENTS: {
-      IterateExternalArrayElements<ExternalFloat64Array, double>(
-          isolate, receiver, false, false, visitor);
-      break;
-    }
-    default:
-      UNREACHABLE();
-      break;
-  }
-  visitor->increase_index_offset(length);
-  return true;
-}
-
-
-/**
- * Array::concat implementation.
- * See ECMAScript 262, 15.4.4.4.
- * TODO(581): Fix non-compliance for very large concatenations and update to
- * following the ECMAScript 5 specification.
- */
-RUNTIME_FUNCTION(Runtime_ArrayConcat) {
-  HandleScope handle_scope(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
-  int argument_count = static_cast<int>(arguments->length()->Number());
-  RUNTIME_ASSERT(arguments->HasFastObjectElements());
-  Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
-
-  // Pass 1: estimate the length and number of elements of the result.
-  // The actual length can be larger if any of the arguments have getters
-  // that mutate other arguments (but will otherwise be precise).
-  // The number of elements is precise if there are no inherited elements.
-
-  ElementsKind kind = FAST_SMI_ELEMENTS;
-
-  uint32_t estimate_result_length = 0;
-  uint32_t estimate_nof_elements = 0;
-  for (int i = 0; i < argument_count; i++) {
-    HandleScope loop_scope(isolate);
-    Handle<Object> obj(elements->get(i), isolate);
-    uint32_t length_estimate;
-    uint32_t element_estimate;
-    if (obj->IsJSArray()) {
-      Handle<JSArray> array(Handle<JSArray>::cast(obj));
-      length_estimate = static_cast<uint32_t>(array->length()->Number());
-      if (length_estimate != 0) {
-        ElementsKind array_kind =
-            GetPackedElementsKind(array->map()->elements_kind());
-        if (IsMoreGeneralElementsKindTransition(kind, array_kind)) {
-          kind = array_kind;
-        }
-      }
-      element_estimate = EstimateElementCount(array);
-    } else {
-      if (obj->IsHeapObject()) {
-        if (obj->IsNumber()) {
-          if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) {
-            kind = FAST_DOUBLE_ELEMENTS;
-          }
-        } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) {
-          kind = FAST_ELEMENTS;
-        }
-      }
-      length_estimate = 1;
-      element_estimate = 1;
-    }
-    // Avoid overflows by capping at kMaxElementCount.
-    if (JSObject::kMaxElementCount - estimate_result_length <
-        length_estimate) {
-      estimate_result_length = JSObject::kMaxElementCount;
-    } else {
-      estimate_result_length += length_estimate;
-    }
-    if (JSObject::kMaxElementCount - estimate_nof_elements <
-        element_estimate) {
-      estimate_nof_elements = JSObject::kMaxElementCount;
-    } else {
-      estimate_nof_elements += element_estimate;
-    }
-  }
-
-  // If estimated number of elements is more than half of length, a
-  // fixed array (fast case) is more time and space-efficient than a
-  // dictionary.
-  bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
-
-  if (fast_case && kind == FAST_DOUBLE_ELEMENTS) {
-    Handle<FixedArrayBase> storage =
-        isolate->factory()->NewFixedDoubleArray(estimate_result_length);
-    int j = 0;
-    bool failure = false;
-    if (estimate_result_length > 0) {
-      Handle<FixedDoubleArray> double_storage =
-          Handle<FixedDoubleArray>::cast(storage);
-      for (int i = 0; i < argument_count; i++) {
-        Handle<Object> obj(elements->get(i), isolate);
-        if (obj->IsSmi()) {
-          double_storage->set(j, Smi::cast(*obj)->value());
-          j++;
-        } else if (obj->IsNumber()) {
-          double_storage->set(j, obj->Number());
-          j++;
-        } else {
-          JSArray* array = JSArray::cast(*obj);
-          uint32_t length = static_cast<uint32_t>(array->length()->Number());
-          switch (array->map()->elements_kind()) {
-            case FAST_HOLEY_DOUBLE_ELEMENTS:
-            case FAST_DOUBLE_ELEMENTS: {
-              // Empty array is FixedArray but not FixedDoubleArray.
-              if (length == 0) break;
-              FixedDoubleArray* elements =
-                  FixedDoubleArray::cast(array->elements());
-              for (uint32_t i = 0; i < length; i++) {
-                if (elements->is_the_hole(i)) {
-                  // TODO(jkummerow/verwaest): We could be a bit more clever
-                  // here: Check if there are no elements/getters on the
-                  // prototype chain, and if so, allow creation of a holey
-                  // result array.
-                  // Same thing below (holey smi case).
-                  failure = true;
-                  break;
-                }
-                double double_value = elements->get_scalar(i);
-                double_storage->set(j, double_value);
-                j++;
-              }
-              break;
-            }
-            case FAST_HOLEY_SMI_ELEMENTS:
-            case FAST_SMI_ELEMENTS: {
-              FixedArray* elements(
-                  FixedArray::cast(array->elements()));
-              for (uint32_t i = 0; i < length; i++) {
-                Object* element = elements->get(i);
-                if (element->IsTheHole()) {
-                  failure = true;
-                  break;
-                }
-                int32_t int_value = Smi::cast(element)->value();
-                double_storage->set(j, int_value);
-                j++;
-              }
-              break;
-            }
-            case FAST_HOLEY_ELEMENTS:
-            case FAST_ELEMENTS:
-              DCHECK_EQ(0, length);
-              break;
-            default:
-              UNREACHABLE();
-          }
-        }
-        if (failure) break;
-      }
-    }
-    if (!failure) {
-      Handle<JSArray> array = isolate->factory()->NewJSArray(0);
-      Smi* length = Smi::FromInt(j);
-      Handle<Map> map;
-      map = JSObject::GetElementsTransitionMap(array, kind);
-      array->set_map(*map);
-      array->set_length(length);
-      array->set_elements(*storage);
-      return *array;
-    }
-    // In case of failure, fall through.
-  }
-
-  Handle<FixedArray> storage;
-  if (fast_case) {
-    // The backing storage array must have non-existing elements to preserve
-    // holes across concat operations.
-    storage = isolate->factory()->NewFixedArrayWithHoles(
-        estimate_result_length);
-  } else {
-    // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
-    uint32_t at_least_space_for = estimate_nof_elements +
-                                  (estimate_nof_elements >> 2);
-    storage = Handle<FixedArray>::cast(
-        SeededNumberDictionary::New(isolate, at_least_space_for));
-  }
-
-  ArrayConcatVisitor visitor(isolate, storage, fast_case);
-
-  for (int i = 0; i < argument_count; i++) {
-    Handle<Object> obj(elements->get(i), isolate);
-    if (obj->IsJSArray()) {
-      Handle<JSArray> array = Handle<JSArray>::cast(obj);
-      if (!IterateElements(isolate, array, &visitor)) {
-        return isolate->heap()->exception();
-      }
-    } else {
-      visitor.visit(0, obj);
-      visitor.increase_index_offset(1);
-    }
-  }
-
-  if (visitor.exceeds_array_limit()) {
-    THROW_NEW_ERROR_RETURN_FAILURE(
-        isolate,
-        NewRangeError("invalid_array_length", HandleVector<Object>(NULL, 0)));
-  }
-  return *visitor.ToArray();
-}
-
-
-// This will not allocate (flatten the string), but it may run
-// very slowly for very deeply nested ConsStrings.  For debugging use only.
-RUNTIME_FUNCTION(Runtime_GlobalPrint) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_CHECKED(String, string, 0);
-  ConsStringIteratorOp op;
-  StringCharacterStream stream(string, &op);
-  while (stream.HasMore()) {
-    uint16_t character = stream.GetNext();
-    PrintF("%c", character);
-  }
-  return string;
-}
-
-
-// Moves all own elements of an object, that are below a limit, to positions
-// starting at zero. All undefined values are placed after non-undefined values,
-// and are followed by non-existing element. Does not change the length
-// property.
-// Returns the number of non-undefined elements collected.
-// Returns -1 if hole removal is not supported by this method.
-RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-  CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
-  return *JSObject::PrepareElementsForSort(object, limit);
-}
-
-
-// Move contents of argument 0 (an array) to argument 1 (an array)
-RUNTIME_FUNCTION(Runtime_MoveArrayContents) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, from, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, to, 1);
-  JSObject::ValidateElements(from);
-  JSObject::ValidateElements(to);
-
-  Handle<FixedArrayBase> new_elements(from->elements());
-  ElementsKind from_kind = from->GetElementsKind();
-  Handle<Map> new_map = JSObject::GetElementsTransitionMap(to, from_kind);
-  JSObject::SetMapAndElements(to, new_map, new_elements);
-  to->set_length(from->length());
-
-  JSObject::ResetElements(from);
-  from->set_length(Smi::FromInt(0));
-
-  JSObject::ValidateElements(to);
-  return *to;
-}
-
-
-// How many elements does this object/array have?
-RUNTIME_FUNCTION(Runtime_EstimateNumberOfElements) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
-  Handle<FixedArrayBase> elements(array->elements(), isolate);
-  SealHandleScope shs(isolate);
-  if (elements->IsDictionary()) {
-    int result =
-        Handle<SeededNumberDictionary>::cast(elements)->NumberOfElements();
-    return Smi::FromInt(result);
-  } else {
-    DCHECK(array->length()->IsSmi());
-    // For packed elements, we know the exact number of elements
-    int length = elements->length();
-    ElementsKind kind = array->GetElementsKind();
-    if (IsFastPackedElementsKind(kind)) {
-      return Smi::FromInt(length);
-    }
-    // For holey elements, take samples from the buffer checking for holes
-    // to generate the estimate.
-    const int kNumberOfHoleCheckSamples = 97;
-    int increment = (length < kNumberOfHoleCheckSamples)
-                        ? 1
-                        : static_cast<int>(length / kNumberOfHoleCheckSamples);
-    ElementsAccessor* accessor = array->GetElementsAccessor();
-    int holes = 0;
-    for (int i = 0; i < length; i += increment) {
-      if (!accessor->HasElement(array, array, i, elements)) {
-        ++holes;
-      }
-    }
-    int estimate = static_cast<int>((kNumberOfHoleCheckSamples - holes) /
-                                    kNumberOfHoleCheckSamples * length);
-    return Smi::FromInt(estimate);
-  }
-}
-
-
-// Returns an array that tells you where in the [0, length) interval an array
-// might have elements.  Can either return an array of keys (positive integers
-// or undefined) or a number representing the positive length of an interval
-// starting at index 0.
-// Intervals can span over some keys that are not in the object.
-RUNTIME_FUNCTION(Runtime_GetArrayKeys) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
-  CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
-  if (array->elements()->IsDictionary()) {
-    Handle<FixedArray> keys = isolate->factory()->empty_fixed_array();
-    for (PrototypeIterator iter(isolate, array,
-                                PrototypeIterator::START_AT_RECEIVER);
-         !iter.IsAtEnd(); iter.Advance()) {
-      if (PrototypeIterator::GetCurrent(iter)->IsJSProxy() ||
-          JSObject::cast(*PrototypeIterator::GetCurrent(iter))
-              ->HasIndexedInterceptor()) {
-        // Bail out if we find a proxy or interceptor, likely not worth
-        // collecting keys in that case.
-        return *isolate->factory()->NewNumberFromUint(length);
-      }
-      Handle<JSObject> current =
-          Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
-      Handle<FixedArray> current_keys =
-          isolate->factory()->NewFixedArray(current->NumberOfOwnElements(NONE));
-      current->GetOwnElementKeys(*current_keys, NONE);
-      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-          isolate, keys, FixedArray::UnionOfKeys(keys, current_keys));
-    }
-    // Erase any keys >= length.
-    // TODO(adamk): Remove this step when the contract of %GetArrayKeys
-    // is changed to let this happen on the JS side.
-    for (int i = 0; i < keys->length(); i++) {
-      if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i);
-    }
-    return *isolate->factory()->NewJSArrayWithElements(keys);
-  } else {
-    RUNTIME_ASSERT(array->HasFastSmiOrObjectElements() ||
-                   array->HasFastDoubleElements());
-    uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
-    return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_LookupAccessor) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
-  CONVERT_SMI_ARG_CHECKED(flag, 2);
-  AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
-  if (!receiver->IsJSObject()) return isolate->heap()->undefined_value();
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugBreak) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  isolate->debug()->HandleDebugBreak();
-  return isolate->heap()->undefined_value();
-}
-
-
-// Helper functions for wrapping and unwrapping stack frame ids.
-static Smi* WrapFrameId(StackFrame::Id id) {
-  DCHECK(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
-  return Smi::FromInt(id >> 2);
-}
-
-
-static StackFrame::Id UnwrapFrameId(int wrapped) {
-  return static_cast<StackFrame::Id>(wrapped << 2);
-}
-
-
-// Adds a JavaScript function as a debug event listener.
-// args[0]: debug event listener function to set or null or undefined for
-//          clearing the event listener function
-// args[1]: object supplied during callback
-RUNTIME_FUNCTION(Runtime_SetDebugEventListener) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  RUNTIME_ASSERT(args[0]->IsJSFunction() ||
-                 args[0]->IsUndefined() ||
-                 args[0]->IsNull());
-  CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, data, 1);
-  isolate->debug()->SetEventListener(callback, data);
-
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_Break) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  isolate->stack_guard()->RequestDebugBreak();
-  return isolate->heap()->undefined_value();
-}
-
-
-static Handle<Object> DebugGetProperty(LookupIterator* it,
-                                       bool* has_caught = NULL) {
-  for (; it->IsFound(); it->Next()) {
-    switch (it->state()) {
-      case LookupIterator::NOT_FOUND:
-      case LookupIterator::TRANSITION:
-        UNREACHABLE();
-      case LookupIterator::ACCESS_CHECK:
-        // Ignore access checks.
-        break;
-      case LookupIterator::INTERCEPTOR:
-      case LookupIterator::JSPROXY:
-        return it->isolate()->factory()->undefined_value();
-      case LookupIterator::ACCESSOR: {
-        Handle<Object> accessors = it->GetAccessors();
-        if (!accessors->IsAccessorInfo()) {
-          return it->isolate()->factory()->undefined_value();
-        }
-        MaybeHandle<Object> maybe_result = JSObject::GetPropertyWithAccessor(
-            it->GetReceiver(), it->name(), it->GetHolder<JSObject>(),
-            accessors);
-        Handle<Object> result;
-        if (!maybe_result.ToHandle(&result)) {
-          result = handle(it->isolate()->pending_exception(), it->isolate());
-          it->isolate()->clear_pending_exception();
-          if (has_caught != NULL) *has_caught = true;
-        }
-        return result;
-      }
-
-      case LookupIterator::DATA:
-        return it->GetDataValue();
-    }
-  }
-
-  return it->isolate()->factory()->undefined_value();
-}
-
-
-// Get debugger related details for an object property, in the following format:
-// 0: Property value
-// 1: Property details
-// 2: Property value is exception
-// 3: Getter function if defined
-// 4: Setter function if defined
-// Items 2-4 are only filled if the property has either a getter or a setter.
-RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
-
-  // Make sure to set the current context to the context before the debugger was
-  // entered (if the debugger is entered). The reason for switching context here
-  // is that for some property lookups (accessors and interceptors) callbacks
-  // into the embedding application can occour, and the embedding application
-  // could have the assumption that its own native context is the current
-  // context and not some internal debugger context.
-  SaveContext save(isolate);
-  if (isolate->debug()->in_debug_scope()) {
-    isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
-  }
-
-  // Check if the name is trivially convertible to an index and get the element
-  // if so.
-  uint32_t index;
-  if (name->AsArrayIndex(&index)) {
-    Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
-    Handle<Object> element_or_char;
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, element_or_char,
-        Runtime::GetElementOrCharAt(isolate, obj, index));
-    details->set(0, *element_or_char);
-    details->set(
-        1, PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi());
-    return *isolate->factory()->NewJSArrayWithElements(details);
-  }
-
-  LookupIterator it(obj, name, LookupIterator::HIDDEN);
-  bool has_caught = false;
-  Handle<Object> value = DebugGetProperty(&it, &has_caught);
-  if (!it.IsFound()) return isolate->heap()->undefined_value();
-
-  Handle<Object> maybe_pair;
-  if (it.state() == LookupIterator::ACCESSOR) {
-    maybe_pair = it.GetAccessors();
-  }
-
-  // If the callback object is a fixed array then it contains JavaScript
-  // getter and/or setter.
-  bool has_js_accessors = !maybe_pair.is_null() && maybe_pair->IsAccessorPair();
-  Handle<FixedArray> details =
-      isolate->factory()->NewFixedArray(has_js_accessors ? 6 : 3);
-  details->set(0, *value);
-  // TODO(verwaest): Get rid of this random way of handling interceptors.
-  PropertyDetails d = it.state() == LookupIterator::INTERCEPTOR
-                          ? PropertyDetails(NONE, NORMAL, 0)
-                          : it.property_details();
-  details->set(1, d.AsSmi());
-  details->set(
-      2, isolate->heap()->ToBoolean(it.state() == LookupIterator::INTERCEPTOR));
-  if (has_js_accessors) {
-    AccessorPair* accessors = AccessorPair::cast(*maybe_pair);
-    details->set(3, isolate->heap()->ToBoolean(has_caught));
-    details->set(4, accessors->GetComponent(ACCESSOR_GETTER));
-    details->set(5, accessors->GetComponent(ACCESSOR_SETTER));
-  }
-
-  return *isolate->factory()->NewJSArrayWithElements(details);
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugGetProperty) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
-
-  LookupIterator it(obj, name);
-  return *DebugGetProperty(&it);
-}
-
-
-// Return the property type calculated from the property details.
-// args[0]: smi with property details.
-RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
-  return Smi::FromInt(static_cast<int>(details.type()));
-}
-
-
-// Return the property attribute calculated from the property details.
-// args[0]: smi with property details.
-RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
-  return Smi::FromInt(static_cast<int>(details.attributes()));
-}
-
-
-// Return the property insertion index calculated from the property details.
-// args[0]: smi with property details.
-RUNTIME_FUNCTION(Runtime_DebugPropertyIndexFromDetails) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
-  // TODO(verwaest): Depends on the type of details.
-  return Smi::FromInt(details.dictionary_index());
-}
-
-
-// Return property value from named interceptor.
-// args[0]: object
-// args[1]: property name
-RUNTIME_FUNCTION(Runtime_DebugNamedInterceptorPropertyValue) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-  RUNTIME_ASSERT(obj->HasNamedInterceptor());
-  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
-
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, JSObject::GetProperty(obj, name));
-  return *result;
-}
-
-
-// Return element value from indexed interceptor.
-// args[0]: object
-// args[1]: index
-RUNTIME_FUNCTION(Runtime_DebugIndexedInterceptorElementValue) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-  RUNTIME_ASSERT(obj->HasIndexedInterceptor());
-  CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, JSObject::GetElementWithInterceptor(obj, obj, index));
-  return *result;
-}
-
-
-static bool CheckExecutionState(Isolate* isolate, int break_id) {
-  return !isolate->debug()->debug_context().is_null() &&
-         isolate->debug()->break_id() != 0 &&
-         isolate->debug()->break_id() == break_id;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CheckExecutionState) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
-  RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-  return isolate->heap()->true_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetFrameCount) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
-  RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
-  // Count all frames which are relevant to debugging stack trace.
-  int n = 0;
-  StackFrame::Id id = isolate->debug()->break_frame_id();
-  if (id == StackFrame::NO_ID) {
-    // If there is no JavaScript stack frame count is 0.
-    return Smi::FromInt(0);
-  }
-
-  for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
-    List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
-    it.frame()->Summarize(&frames);
-    for (int i = frames.length() - 1; i >= 0; i--) {
-      // Omit functions from native scripts.
-      if (!frames[i].function()->IsFromNativeScript()) n++;
-    }
-  }
-  return Smi::FromInt(n);
-}
-
-
-class FrameInspector {
- public:
-  FrameInspector(JavaScriptFrame* frame,
-                 int inlined_jsframe_index,
-                 Isolate* isolate)
-      : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
-    // Calculate the deoptimized frame.
-    if (frame->is_optimized()) {
-      deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
-          frame, inlined_jsframe_index, isolate);
-    }
-    has_adapted_arguments_ = frame_->has_adapted_arguments();
-    is_bottommost_ = inlined_jsframe_index == 0;
-    is_optimized_ = frame_->is_optimized();
-  }
-
-  ~FrameInspector() {
-    // Get rid of the calculated deoptimized frame if any.
-    if (deoptimized_frame_ != NULL) {
-      Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
-                                                  isolate_);
-    }
-  }
-
-  int GetParametersCount() {
-    return is_optimized_
-        ? deoptimized_frame_->parameters_count()
-        : frame_->ComputeParametersCount();
-  }
-  int expression_count() { return deoptimized_frame_->expression_count(); }
-  Object* GetFunction() {
-    return is_optimized_
-        ? deoptimized_frame_->GetFunction()
-        : frame_->function();
-  }
-  Object* GetParameter(int index) {
-    return is_optimized_
-        ? deoptimized_frame_->GetParameter(index)
-        : frame_->GetParameter(index);
-  }
-  Object* GetExpression(int index) {
-    return is_optimized_
-        ? deoptimized_frame_->GetExpression(index)
-        : frame_->GetExpression(index);
-  }
-  int GetSourcePosition() {
-    return is_optimized_
-        ? deoptimized_frame_->GetSourcePosition()
-        : frame_->LookupCode()->SourcePosition(frame_->pc());
-  }
-  bool IsConstructor() {
-    return is_optimized_ && !is_bottommost_
-        ? deoptimized_frame_->HasConstructStub()
-        : frame_->IsConstructor();
-  }
-  Object* GetContext() {
-    return is_optimized_ ? deoptimized_frame_->GetContext() : frame_->context();
-  }
-
-  // To inspect all the provided arguments the frame might need to be
-  // replaced with the arguments frame.
-  void SetArgumentsFrame(JavaScriptFrame* frame) {
-    DCHECK(has_adapted_arguments_);
-    frame_ = frame;
-    is_optimized_ = frame_->is_optimized();
-    DCHECK(!is_optimized_);
-  }
-
- private:
-  JavaScriptFrame* frame_;
-  DeoptimizedFrameInfo* deoptimized_frame_;
-  Isolate* isolate_;
-  bool is_optimized_;
-  bool is_bottommost_;
-  bool has_adapted_arguments_;
-
-  DISALLOW_COPY_AND_ASSIGN(FrameInspector);
-};
-
-
-static const int kFrameDetailsFrameIdIndex = 0;
-static const int kFrameDetailsReceiverIndex = 1;
-static const int kFrameDetailsFunctionIndex = 2;
-static const int kFrameDetailsArgumentCountIndex = 3;
-static const int kFrameDetailsLocalCountIndex = 4;
-static const int kFrameDetailsSourcePositionIndex = 5;
-static const int kFrameDetailsConstructCallIndex = 6;
-static const int kFrameDetailsAtReturnIndex = 7;
-static const int kFrameDetailsFlagsIndex = 8;
-static const int kFrameDetailsFirstDynamicIndex = 9;
-
-
-static SaveContext* FindSavedContextForFrame(Isolate* isolate,
-                                             JavaScriptFrame* frame) {
-  SaveContext* save = isolate->save_context();
-  while (save != NULL && !save->IsBelowFrame(frame)) {
-    save = save->prev();
-  }
-  DCHECK(save != NULL);
-  return save;
-}
-
-
-// Advances the iterator to the frame that matches the index and returns the
-// inlined frame index, or -1 if not found.  Skips native JS functions.
-static int FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index) {
-  int count = -1;
-  for (; !it->done(); it->Advance()) {
-    List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
-    it->frame()->Summarize(&frames);
-    for (int i = frames.length() - 1; i >= 0; i--) {
-      // Omit functions from native scripts.
-      if (frames[i].function()->IsFromNativeScript()) continue;
-      if (++count == index) return i;
-    }
-  }
-  return -1;
-}
-
-
-// Return an array with frame details
-// args[0]: number: break id
-// args[1]: number: frame index
-//
-// The array returned contains the following information:
-// 0: Frame id
-// 1: Receiver
-// 2: Function
-// 3: Argument count
-// 4: Local count
-// 5: Source position
-// 6: Constructor call
-// 7: Is at return
-// 8: Flags
-// Arguments name, value
-// Locals name, value
-// Return value if any
-RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
-  RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
-  CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
-  Heap* heap = isolate->heap();
-
-  // Find the relevant frame with the requested index.
-  StackFrame::Id id = isolate->debug()->break_frame_id();
-  if (id == StackFrame::NO_ID) {
-    // If there are no JavaScript stack frames return undefined.
-    return heap->undefined_value();
-  }
-
-  JavaScriptFrameIterator it(isolate, id);
-  // Inlined frame index in optimized frame, starting from outer function.
-  int inlined_jsframe_index = FindIndexedNonNativeFrame(&it, index);
-  if (inlined_jsframe_index == -1) return heap->undefined_value();
-
-  FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
-  bool is_optimized = it.frame()->is_optimized();
-
-  // Traverse the saved contexts chain to find the active context for the
-  // selected frame.
-  SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
-
-  // Get the frame id.
-  Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
-
-  // Find source position in unoptimized code.
-  int position = frame_inspector.GetSourcePosition();
-
-  // Check for constructor frame.
-  bool constructor = frame_inspector.IsConstructor();
-
-  // Get scope info and read from it for local variable information.
-  Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
-  Handle<SharedFunctionInfo> shared(function->shared());
-  Handle<ScopeInfo> scope_info(shared->scope_info());
-  DCHECK(*scope_info != ScopeInfo::Empty(isolate));
-
-  // Get the locals names and values into a temporary array.
-  int local_count = scope_info->LocalCount();
-  for (int slot = 0; slot < scope_info->LocalCount(); ++slot) {
-    // Hide compiler-introduced temporary variables, whether on the stack or on
-    // the context.
-    if (scope_info->LocalIsSynthetic(slot))
-      local_count--;
-  }
-
-  Handle<FixedArray> locals =
-      isolate->factory()->NewFixedArray(local_count * 2);
-
-  // Fill in the values of the locals.
-  int local = 0;
-  int i = 0;
-  for (; i < scope_info->StackLocalCount(); ++i) {
-    // Use the value from the stack.
-    if (scope_info->LocalIsSynthetic(i))
-      continue;
-    locals->set(local * 2, scope_info->LocalName(i));
-    locals->set(local * 2 + 1, frame_inspector.GetExpression(i));
-    local++;
-  }
-  if (local < local_count) {
-    // Get the context containing declarations.
-    Handle<Context> context(
-        Context::cast(frame_inspector.GetContext())->declaration_context());
-    for (; i < scope_info->LocalCount(); ++i) {
-      if (scope_info->LocalIsSynthetic(i))
-        continue;
-      Handle<String> name(scope_info->LocalName(i));
-      VariableMode mode;
-      InitializationFlag init_flag;
-      MaybeAssignedFlag maybe_assigned_flag;
-      locals->set(local * 2, *name);
-      int context_slot_index = ScopeInfo::ContextSlotIndex(
-          scope_info, name, &mode, &init_flag, &maybe_assigned_flag);
-      Object* value = context->get(context_slot_index);
-      locals->set(local * 2 + 1, value);
-      local++;
-    }
-  }
-
-  // Check whether this frame is positioned at return. If not top
-  // frame or if the frame is optimized it cannot be at a return.
-  bool at_return = false;
-  if (!is_optimized && index == 0) {
-    at_return = isolate->debug()->IsBreakAtReturn(it.frame());
-  }
-
-  // If positioned just before return find the value to be returned and add it
-  // to the frame information.
-  Handle<Object> return_value = isolate->factory()->undefined_value();
-  if (at_return) {
-    StackFrameIterator it2(isolate);
-    Address internal_frame_sp = NULL;
-    while (!it2.done()) {
-      if (it2.frame()->is_internal()) {
-        internal_frame_sp = it2.frame()->sp();
-      } else {
-        if (it2.frame()->is_java_script()) {
-          if (it2.frame()->id() == it.frame()->id()) {
-            // The internal frame just before the JavaScript frame contains the
-            // value to return on top. A debug break at return will create an
-            // internal frame to store the return value (eax/rax/r0) before
-            // entering the debug break exit frame.
-            if (internal_frame_sp != NULL) {
-              return_value =
-                  Handle<Object>(Memory::Object_at(internal_frame_sp),
-                                 isolate);
-              break;
-            }
-          }
-        }
-
-        // Indicate that the previous frame was not an internal frame.
-        internal_frame_sp = NULL;
-      }
-      it2.Advance();
-    }
-  }
-
-  // Now advance to the arguments adapter frame (if any). It contains all
-  // the provided parameters whereas the function frame always have the number
-  // of arguments matching the functions parameters. The rest of the
-  // information (except for what is collected above) is the same.
-  if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
-    it.AdvanceToArgumentsFrame();
-    frame_inspector.SetArgumentsFrame(it.frame());
-  }
-
-  // Find the number of arguments to fill. At least fill the number of
-  // parameters for the function and fill more if more parameters are provided.
-  int argument_count = scope_info->ParameterCount();
-  if (argument_count < frame_inspector.GetParametersCount()) {
-    argument_count = frame_inspector.GetParametersCount();
-  }
-
-  // Calculate the size of the result.
-  int details_size = kFrameDetailsFirstDynamicIndex +
-                     2 * (argument_count + local_count) +
-                     (at_return ? 1 : 0);
-  Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
-
-  // Add the frame id.
-  details->set(kFrameDetailsFrameIdIndex, *frame_id);
-
-  // Add the function (same as in function frame).
-  details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
-
-  // Add the arguments count.
-  details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
-
-  // Add the locals count
-  details->set(kFrameDetailsLocalCountIndex,
-               Smi::FromInt(local_count));
-
-  // Add the source position.
-  if (position != RelocInfo::kNoPosition) {
-    details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
-  } else {
-    details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
-  }
-
-  // Add the constructor information.
-  details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
-
-  // Add the at return information.
-  details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
-
-  // Add flags to indicate information on whether this frame is
-  //   bit 0: invoked in the debugger context.
-  //   bit 1: optimized frame.
-  //   bit 2: inlined in optimized frame
-  int flags = 0;
-  if (*save->context() == *isolate->debug()->debug_context()) {
-    flags |= 1 << 0;
-  }
-  if (is_optimized) {
-    flags |= 1 << 1;
-    flags |= inlined_jsframe_index << 2;
-  }
-  details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
-
-  // Fill the dynamic part.
-  int details_index = kFrameDetailsFirstDynamicIndex;
-
-  // Add arguments name and value.
-  for (int i = 0; i < argument_count; i++) {
-    // Name of the argument.
-    if (i < scope_info->ParameterCount()) {
-      details->set(details_index++, scope_info->ParameterName(i));
-    } else {
-      details->set(details_index++, heap->undefined_value());
-    }
-
-    // Parameter value.
-    if (i < frame_inspector.GetParametersCount()) {
-      // Get the value from the stack.
-      details->set(details_index++, frame_inspector.GetParameter(i));
-    } else {
-      details->set(details_index++, heap->undefined_value());
-    }
-  }
-
-  // Add locals name and value from the temporary copy from the function frame.
-  for (int i = 0; i < local_count * 2; i++) {
-    details->set(details_index++, locals->get(i));
-  }
-
-  // Add the value being returned.
-  if (at_return) {
-    details->set(details_index++, *return_value);
-  }
-
-  // Add the receiver (same as in function frame).
-  // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
-  // THE FRAME ITERATOR TO WRAP THE RECEIVER.
-  Handle<Object> receiver(it.frame()->receiver(), isolate);
-  if (!receiver->IsJSObject() &&
-      shared->strict_mode() == SLOPPY &&
-      !function->IsBuiltin()) {
-    // If the receiver is not a JSObject and the function is not a
-    // builtin or strict-mode we have hit an optimization where a
-    // value object is not converted into a wrapped JS objects. To
-    // hide this optimization from the debugger, we wrap the receiver
-    // by creating correct wrapper object based on the calling frame's
-    // native context.
-    it.Advance();
-    if (receiver->IsUndefined()) {
-      receiver = handle(function->global_proxy());
-    } else {
-      Context* context = Context::cast(it.frame()->context());
-      Handle<Context> native_context(Context::cast(context->native_context()));
-      if (!Object::ToObject(isolate, receiver, native_context)
-               .ToHandle(&receiver)) {
-        // This only happens if the receiver is forcibly set in %_CallFunction.
-        return heap->undefined_value();
-      }
-    }
-  }
-  details->set(kFrameDetailsReceiverIndex, *receiver);
-
-  DCHECK_EQ(details_size, details_index);
-  return *isolate->factory()->NewJSArrayWithElements(details);
-}
-
-
-static bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info,
-                                              Handle<String> parameter_name) {
-  VariableMode mode;
-  InitializationFlag init_flag;
-  MaybeAssignedFlag maybe_assigned_flag;
-  return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &init_flag,
-                                     &maybe_assigned_flag) != -1;
-}
-
-
-// Create a plain JSObject which materializes the local scope for the specified
-// frame.
-MUST_USE_RESULT
-static MaybeHandle<JSObject> MaterializeStackLocalsWithFrameInspector(
-    Isolate* isolate,
-    Handle<JSObject> target,
-    Handle<JSFunction> function,
-    FrameInspector* frame_inspector) {
-  Handle<SharedFunctionInfo> shared(function->shared());
-  Handle<ScopeInfo> scope_info(shared->scope_info());
-
-  // First fill all parameters.
-  for (int i = 0; i < scope_info->ParameterCount(); ++i) {
-    // Do not materialize the parameter if it is shadowed by a context local.
-    Handle<String> name(scope_info->ParameterName(i));
-    if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
-
-    HandleScope scope(isolate);
-    Handle<Object> value(i < frame_inspector->GetParametersCount()
-                             ? frame_inspector->GetParameter(i)
-                             : isolate->heap()->undefined_value(),
-                         isolate);
-    DCHECK(!value->IsTheHole());
-
-    RETURN_ON_EXCEPTION(
-        isolate,
-        Runtime::SetObjectProperty(isolate, target, name, value, SLOPPY),
-        JSObject);
-  }
-
-  // Second fill all stack locals.
-  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
-    if (scope_info->LocalIsSynthetic(i)) continue;
-    Handle<String> name(scope_info->StackLocalName(i));
-    Handle<Object> value(frame_inspector->GetExpression(i), isolate);
-    if (value->IsTheHole()) continue;
-
-    RETURN_ON_EXCEPTION(
-        isolate,
-        Runtime::SetObjectProperty(isolate, target, name, value, SLOPPY),
-        JSObject);
-  }
-
-  return target;
-}
-
-
-static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate,
-                                                    Handle<JSObject> target,
-                                                    Handle<JSFunction> function,
-                                                    JavaScriptFrame* frame,
-                                                    int inlined_jsframe_index) {
-  if (inlined_jsframe_index != 0 || frame->is_optimized()) {
-    // Optimized frames are not supported.
-    // TODO(yangguo): make sure all code deoptimized when debugger is active
-    //                and assert that this cannot happen.
-    return;
-  }
-
-  Handle<SharedFunctionInfo> shared(function->shared());
-  Handle<ScopeInfo> scope_info(shared->scope_info());
-
-  // Parameters.
-  for (int i = 0; i < scope_info->ParameterCount(); ++i) {
-    // Shadowed parameters were not materialized.
-    Handle<String> name(scope_info->ParameterName(i));
-    if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
-
-    DCHECK(!frame->GetParameter(i)->IsTheHole());
-    HandleScope scope(isolate);
-    Handle<Object> value =
-        Object::GetPropertyOrElement(target, name).ToHandleChecked();
-    frame->SetParameterValue(i, *value);
-  }
-
-  // Stack locals.
-  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
-    if (scope_info->LocalIsSynthetic(i)) continue;
-    if (frame->GetExpression(i)->IsTheHole()) continue;
-    HandleScope scope(isolate);
-    Handle<Object> value = Object::GetPropertyOrElement(
-        target,
-        handle(scope_info->StackLocalName(i), isolate)).ToHandleChecked();
-    frame->SetExpression(i, *value);
-  }
-}
-
-
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext(
-    Isolate* isolate,
-    Handle<JSObject> target,
-    Handle<JSFunction> function,
-    JavaScriptFrame* frame) {
-  HandleScope scope(isolate);
-  Handle<SharedFunctionInfo> shared(function->shared());
-  Handle<ScopeInfo> scope_info(shared->scope_info());
-
-  if (!scope_info->HasContext()) return target;
-
-  // Third fill all context locals.
-  Handle<Context> frame_context(Context::cast(frame->context()));
-  Handle<Context> function_context(frame_context->declaration_context());
-  if (!ScopeInfo::CopyContextLocalsToScopeObject(
-          scope_info, function_context, target)) {
-    return MaybeHandle<JSObject>();
-  }
-
-  // Finally copy any properties from the function context extension.
-  // These will be variables introduced by eval.
-  if (function_context->closure() == *function) {
-    if (function_context->has_extension() &&
-        !function_context->IsNativeContext()) {
-      Handle<JSObject> ext(JSObject::cast(function_context->extension()));
-      Handle<FixedArray> keys;
-      ASSIGN_RETURN_ON_EXCEPTION(
-          isolate, keys,
-          JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS),
-          JSObject);
-
-      for (int i = 0; i < keys->length(); i++) {
-        // Names of variables introduced by eval are strings.
-        DCHECK(keys->get(i)->IsString());
-        Handle<String> key(String::cast(keys->get(i)));
-        Handle<Object> value;
-        ASSIGN_RETURN_ON_EXCEPTION(
-            isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
-        RETURN_ON_EXCEPTION(
-            isolate,
-            Runtime::SetObjectProperty(isolate, target, key, value, SLOPPY),
-            JSObject);
-      }
-    }
-  }
-
-  return target;
-}
-
-
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope(
-    Isolate* isolate,
-    JavaScriptFrame* frame,
-    int inlined_jsframe_index) {
-  FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
-  Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
-
-  Handle<JSObject> local_scope =
-      isolate->factory()->NewJSObject(isolate->object_function());
-  ASSIGN_RETURN_ON_EXCEPTION(
-      isolate, local_scope,
-      MaterializeStackLocalsWithFrameInspector(
-          isolate, local_scope, function, &frame_inspector),
-      JSObject);
-
-  return MaterializeLocalContext(isolate, local_scope, function, frame);
-}
-
-
-// Set the context local variable value.
-static bool SetContextLocalValue(Isolate* isolate,
-                                 Handle<ScopeInfo> scope_info,
-                                 Handle<Context> context,
-                                 Handle<String> variable_name,
-                                 Handle<Object> new_value) {
-  for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
-    Handle<String> next_name(scope_info->ContextLocalName(i));
-    if (String::Equals(variable_name, next_name)) {
-      VariableMode mode;
-      InitializationFlag init_flag;
-      MaybeAssignedFlag maybe_assigned_flag;
-      int context_index = ScopeInfo::ContextSlotIndex(
-          scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag);
-      context->set(context_index, *new_value);
-      return true;
-    }
-  }
-
-  return false;
-}
-
-
-static bool SetLocalVariableValue(Isolate* isolate,
-                                  JavaScriptFrame* frame,
-                                  int inlined_jsframe_index,
-                                  Handle<String> variable_name,
-                                  Handle<Object> new_value) {
-  if (inlined_jsframe_index != 0 || frame->is_optimized()) {
-    // Optimized frames are not supported.
-    return false;
-  }
-
-  Handle<JSFunction> function(frame->function());
-  Handle<SharedFunctionInfo> shared(function->shared());
-  Handle<ScopeInfo> scope_info(shared->scope_info());
-
-  bool default_result = false;
-
-  // Parameters.
-  for (int i = 0; i < scope_info->ParameterCount(); ++i) {
-    HandleScope scope(isolate);
-    if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) {
-      frame->SetParameterValue(i, *new_value);
-      // Argument might be shadowed in heap context, don't stop here.
-      default_result = true;
-    }
-  }
-
-  // Stack locals.
-  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
-    HandleScope scope(isolate);
-    if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
-      frame->SetExpression(i, *new_value);
-      return true;
-    }
-  }
-
-  if (scope_info->HasContext()) {
-    // Context locals.
-    Handle<Context> frame_context(Context::cast(frame->context()));
-    Handle<Context> function_context(frame_context->declaration_context());
-    if (SetContextLocalValue(
-        isolate, scope_info, function_context, variable_name, new_value)) {
-      return true;
-    }
-
-    // Function context extension. These are variables introduced by eval.
-    if (function_context->closure() == *function) {
-      if (function_context->has_extension() &&
-          !function_context->IsNativeContext()) {
-        Handle<JSObject> ext(JSObject::cast(function_context->extension()));
-
-        Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
-        DCHECK(maybe.has_value);
-        if (maybe.value) {
-          // We don't expect this to do anything except replacing
-          // property value.
-          Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
-                                     SLOPPY).Assert();
-          return true;
-        }
-      }
-    }
-  }
-
-  return default_result;
-}
-
-
-// Create a plain JSObject which materializes the closure content for the
-// context.
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeClosure(
-    Isolate* isolate,
-    Handle<Context> context) {
-  DCHECK(context->IsFunctionContext());
-
-  Handle<SharedFunctionInfo> shared(context->closure()->shared());
-  Handle<ScopeInfo> scope_info(shared->scope_info());
-
-  // Allocate and initialize a JSObject with all the content of this function
-  // closure.
-  Handle<JSObject> closure_scope =
-      isolate->factory()->NewJSObject(isolate->object_function());
-
-  // Fill all context locals to the context extension.
-  if (!ScopeInfo::CopyContextLocalsToScopeObject(
-          scope_info, context, closure_scope)) {
-    return MaybeHandle<JSObject>();
-  }
-
-  // Finally copy any properties from the function context extension. This will
-  // be variables introduced by eval.
-  if (context->has_extension()) {
-    Handle<JSObject> ext(JSObject::cast(context->extension()));
-    Handle<FixedArray> keys;
-    ASSIGN_RETURN_ON_EXCEPTION(
-        isolate, keys,
-        JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS), JSObject);
-
-    for (int i = 0; i < keys->length(); i++) {
-      HandleScope scope(isolate);
-      // Names of variables introduced by eval are strings.
-      DCHECK(keys->get(i)->IsString());
-      Handle<String> key(String::cast(keys->get(i)));
-      Handle<Object> value;
-      ASSIGN_RETURN_ON_EXCEPTION(
-          isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
-      RETURN_ON_EXCEPTION(
-          isolate,
-          Runtime::DefineObjectProperty(closure_scope, key, value, NONE),
-          JSObject);
-    }
-  }
-
-  return closure_scope;
-}
-
-
-// This method copies structure of MaterializeClosure method above.
-static bool SetClosureVariableValue(Isolate* isolate,
-                                    Handle<Context> context,
-                                    Handle<String> variable_name,
-                                    Handle<Object> new_value) {
-  DCHECK(context->IsFunctionContext());
-
-  Handle<SharedFunctionInfo> shared(context->closure()->shared());
-  Handle<ScopeInfo> scope_info(shared->scope_info());
-
-  // Context locals to the context extension.
-  if (SetContextLocalValue(
-          isolate, scope_info, context, variable_name, new_value)) {
-    return true;
-  }
-
-  // Properties from the function context extension. This will
-  // be variables introduced by eval.
-  if (context->has_extension()) {
-    Handle<JSObject> ext(JSObject::cast(context->extension()));
-    Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
-    DCHECK(maybe.has_value);
-    if (maybe.value) {
-      // We don't expect this to do anything except replacing property value.
-      Runtime::DefineObjectProperty(
-          ext, variable_name, new_value, NONE).Assert();
-      return true;
-    }
-  }
-
-  return false;
-}
-
-
-// Create a plain JSObject which materializes the scope for the specified
-// catch context.
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeCatchScope(
-    Isolate* isolate,
-    Handle<Context> context) {
-  DCHECK(context->IsCatchContext());
-  Handle<String> name(String::cast(context->extension()));
-  Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
-                               isolate);
-  Handle<JSObject> catch_scope =
-      isolate->factory()->NewJSObject(isolate->object_function());
-  RETURN_ON_EXCEPTION(
-      isolate,
-      Runtime::DefineObjectProperty(catch_scope, name, thrown_object, NONE),
-      JSObject);
-  return catch_scope;
-}
-
-
-static bool SetCatchVariableValue(Isolate* isolate,
-                                  Handle<Context> context,
-                                  Handle<String> variable_name,
-                                  Handle<Object> new_value) {
-  DCHECK(context->IsCatchContext());
-  Handle<String> name(String::cast(context->extension()));
-  if (!String::Equals(name, variable_name)) {
-    return false;
-  }
-  context->set(Context::THROWN_OBJECT_INDEX, *new_value);
-  return true;
-}
-
-
-// Create a plain JSObject which materializes the block scope for the specified
-// block context.
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeBlockScope(
-    Isolate* isolate,
-    Handle<Context> context) {
-  DCHECK(context->IsBlockContext());
-  Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
-
-  // Allocate and initialize a JSObject with all the arguments, stack locals
-  // heap locals and extension properties of the debugged function.
-  Handle<JSObject> block_scope =
-      isolate->factory()->NewJSObject(isolate->object_function());
-
-  // Fill all context locals.
-  if (!ScopeInfo::CopyContextLocalsToScopeObject(
-          scope_info, context, block_scope)) {
-    return MaybeHandle<JSObject>();
-  }
-
-  return block_scope;
-}
-
-
-// Create a plain JSObject which materializes the module scope for the specified
-// module context.
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope(
-    Isolate* isolate,
-    Handle<Context> context) {
-  DCHECK(context->IsModuleContext());
-  Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
-
-  // Allocate and initialize a JSObject with all the members of the debugged
-  // module.
-  Handle<JSObject> module_scope =
-      isolate->factory()->NewJSObject(isolate->object_function());
-
-  // Fill all context locals.
-  if (!ScopeInfo::CopyContextLocalsToScopeObject(
-          scope_info, context, module_scope)) {
-    return MaybeHandle<JSObject>();
-  }
-
-  return module_scope;
-}
-
-
-// Iterate over the actual scopes visible from a stack frame or from a closure.
-// The iteration proceeds from the innermost visible nested scope outwards.
-// All scopes are backed by an actual context except the local scope,
-// which is inserted "artificially" in the context chain.
-class ScopeIterator {
- public:
-  enum ScopeType {
-    ScopeTypeGlobal = 0,
-    ScopeTypeLocal,
-    ScopeTypeWith,
-    ScopeTypeClosure,
-    ScopeTypeCatch,
-    ScopeTypeBlock,
-    ScopeTypeModule
-  };
-
-  ScopeIterator(Isolate* isolate,
-                JavaScriptFrame* frame,
-                int inlined_jsframe_index,
-                bool ignore_nested_scopes = false)
-    : isolate_(isolate),
-      frame_(frame),
-      inlined_jsframe_index_(inlined_jsframe_index),
-      function_(frame->function()),
-      context_(Context::cast(frame->context())),
-      nested_scope_chain_(4),
-      failed_(false) {
-
-    // Catch the case when the debugger stops in an internal function.
-    Handle<SharedFunctionInfo> shared_info(function_->shared());
-    Handle<ScopeInfo> scope_info(shared_info->scope_info());
-    if (shared_info->script() == isolate->heap()->undefined_value()) {
-      while (context_->closure() == *function_) {
-        context_ = Handle<Context>(context_->previous(), isolate_);
-      }
-      return;
-    }
-
-    // Get the debug info (create it if it does not exist).
-    if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) {
-      // Return if ensuring debug info failed.
-      return;
-    }
-
-    // Currently it takes too much time to find nested scopes due to script
-    // parsing. Sometimes we want to run the ScopeIterator as fast as possible
-    // (for example, while collecting async call stacks on every
-    // addEventListener call), even if we drop some nested scopes.
-    // Later we may optimize getting the nested scopes (cache the result?)
-    // and include nested scopes into the "fast" iteration case as well.
-    if (!ignore_nested_scopes) {
-      Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
-
-      // Find the break point where execution has stopped.
-      BreakLocationIterator break_location_iterator(debug_info,
-                                                    ALL_BREAK_LOCATIONS);
-      // pc points to the instruction after the current one, possibly a break
-      // location as well. So the "- 1" to exclude it from the search.
-      break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
-
-      // Within the return sequence at the moment it is not possible to
-      // get a source position which is consistent with the current scope chain.
-      // Thus all nested with, catch and block contexts are skipped and we only
-      // provide the function scope.
-      ignore_nested_scopes = break_location_iterator.IsExit();
-    }
-
-    if (ignore_nested_scopes) {
-      if (scope_info->HasContext()) {
-        context_ = Handle<Context>(context_->declaration_context(), isolate_);
-      } else {
-        while (context_->closure() == *function_) {
-          context_ = Handle<Context>(context_->previous(), isolate_);
-        }
-      }
-      if (scope_info->scope_type() == FUNCTION_SCOPE) {
-        nested_scope_chain_.Add(scope_info);
-      }
-    } else {
-      // Reparse the code and analyze the scopes.
-      Handle<Script> script(Script::cast(shared_info->script()));
-      Scope* scope = NULL;
-
-      // Check whether we are in global, eval or function code.
-      Handle<ScopeInfo> scope_info(shared_info->scope_info());
-      if (scope_info->scope_type() != FUNCTION_SCOPE) {
-        // Global or eval code.
-        CompilationInfoWithZone info(script);
-        if (scope_info->scope_type() == GLOBAL_SCOPE) {
-          info.MarkAsGlobal();
-        } else {
-          DCHECK(scope_info->scope_type() == EVAL_SCOPE);
-          info.MarkAsEval();
-          info.SetContext(Handle<Context>(function_->context()));
-        }
-        if (Parser::Parse(&info) && Scope::Analyze(&info)) {
-          scope = info.function()->scope();
-        }
-        RetrieveScopeChain(scope, shared_info);
-      } else {
-        // Function code
-        CompilationInfoWithZone info(shared_info);
-        if (Parser::Parse(&info) && Scope::Analyze(&info)) {
-          scope = info.function()->scope();
-        }
-        RetrieveScopeChain(scope, shared_info);
-      }
-    }
-  }
-
-  ScopeIterator(Isolate* isolate,
-                Handle<JSFunction> function)
-    : isolate_(isolate),
-      frame_(NULL),
-      inlined_jsframe_index_(0),
-      function_(function),
-      context_(function->context()),
-      failed_(false) {
-    if (function->IsBuiltin()) {
-      context_ = Handle<Context>();
-    }
-  }
-
-  // More scopes?
-  bool Done() {
-    DCHECK(!failed_);
-    return context_.is_null();
-  }
-
-  bool Failed() { return failed_; }
-
-  // Move to the next scope.
-  void Next() {
-    DCHECK(!failed_);
-    ScopeType scope_type = Type();
-    if (scope_type == ScopeTypeGlobal) {
-      // The global scope is always the last in the chain.
-      DCHECK(context_->IsNativeContext());
-      context_ = Handle<Context>();
-      return;
-    }
-    if (nested_scope_chain_.is_empty()) {
-      context_ = Handle<Context>(context_->previous(), isolate_);
-    } else {
-      if (nested_scope_chain_.last()->HasContext()) {
-        DCHECK(context_->previous() != NULL);
-        context_ = Handle<Context>(context_->previous(), isolate_);
-      }
-      nested_scope_chain_.RemoveLast();
-    }
-  }
-
-  // Return the type of the current scope.
-  ScopeType Type() {
-    DCHECK(!failed_);
-    if (!nested_scope_chain_.is_empty()) {
-      Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
-      switch (scope_info->scope_type()) {
-        case FUNCTION_SCOPE:
-          DCHECK(context_->IsFunctionContext() ||
-                 !scope_info->HasContext());
-          return ScopeTypeLocal;
-        case MODULE_SCOPE:
-          DCHECK(context_->IsModuleContext());
-          return ScopeTypeModule;
-        case GLOBAL_SCOPE:
-          DCHECK(context_->IsNativeContext());
-          return ScopeTypeGlobal;
-        case WITH_SCOPE:
-          DCHECK(context_->IsWithContext());
-          return ScopeTypeWith;
-        case CATCH_SCOPE:
-          DCHECK(context_->IsCatchContext());
-          return ScopeTypeCatch;
-        case BLOCK_SCOPE:
-          DCHECK(!scope_info->HasContext() ||
-                 context_->IsBlockContext());
-          return ScopeTypeBlock;
-        case EVAL_SCOPE:
-          UNREACHABLE();
-      }
-    }
-    if (context_->IsNativeContext()) {
-      DCHECK(context_->global_object()->IsGlobalObject());
-      return ScopeTypeGlobal;
-    }
-    if (context_->IsFunctionContext()) {
-      return ScopeTypeClosure;
-    }
-    if (context_->IsCatchContext()) {
-      return ScopeTypeCatch;
-    }
-    if (context_->IsBlockContext()) {
-      return ScopeTypeBlock;
-    }
-    if (context_->IsModuleContext()) {
-      return ScopeTypeModule;
-    }
-    DCHECK(context_->IsWithContext());
-    return ScopeTypeWith;
-  }
-
-  // Return the JavaScript object with the content of the current scope.
-  MaybeHandle<JSObject> ScopeObject() {
-    DCHECK(!failed_);
-    switch (Type()) {
-      case ScopeIterator::ScopeTypeGlobal:
-        return Handle<JSObject>(CurrentContext()->global_object());
-      case ScopeIterator::ScopeTypeLocal:
-        // Materialize the content of the local scope into a JSObject.
-        DCHECK(nested_scope_chain_.length() == 1);
-        return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
-      case ScopeIterator::ScopeTypeWith:
-        // Return the with object.
-        return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
-      case ScopeIterator::ScopeTypeCatch:
-        return MaterializeCatchScope(isolate_, CurrentContext());
-      case ScopeIterator::ScopeTypeClosure:
-        // Materialize the content of the closure scope into a JSObject.
-        return MaterializeClosure(isolate_, CurrentContext());
-      case ScopeIterator::ScopeTypeBlock:
-        return MaterializeBlockScope(isolate_, CurrentContext());
-      case ScopeIterator::ScopeTypeModule:
-        return MaterializeModuleScope(isolate_, CurrentContext());
-    }
-    UNREACHABLE();
-    return Handle<JSObject>();
-  }
-
-  bool SetVariableValue(Handle<String> variable_name,
-                        Handle<Object> new_value) {
-    DCHECK(!failed_);
-    switch (Type()) {
-      case ScopeIterator::ScopeTypeGlobal:
-        break;
-      case ScopeIterator::ScopeTypeLocal:
-        return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_,
-            variable_name, new_value);
-      case ScopeIterator::ScopeTypeWith:
-        break;
-      case ScopeIterator::ScopeTypeCatch:
-        return SetCatchVariableValue(isolate_, CurrentContext(),
-            variable_name, new_value);
-      case ScopeIterator::ScopeTypeClosure:
-        return SetClosureVariableValue(isolate_, CurrentContext(),
-            variable_name, new_value);
-      case ScopeIterator::ScopeTypeBlock:
-        // TODO(2399): should we implement it?
-        break;
-      case ScopeIterator::ScopeTypeModule:
-        // TODO(2399): should we implement it?
-        break;
-    }
-    return false;
-  }
-
-  Handle<ScopeInfo> CurrentScopeInfo() {
-    DCHECK(!failed_);
-    if (!nested_scope_chain_.is_empty()) {
-      return nested_scope_chain_.last();
-    } else if (context_->IsBlockContext()) {
-      return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
-    } else if (context_->IsFunctionContext()) {
-      return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
-    }
-    return Handle<ScopeInfo>::null();
-  }
-
-  // Return the context for this scope. For the local context there might not
-  // be an actual context.
-  Handle<Context> CurrentContext() {
-    DCHECK(!failed_);
-    if (Type() == ScopeTypeGlobal ||
-        nested_scope_chain_.is_empty()) {
-      return context_;
-    } else if (nested_scope_chain_.last()->HasContext()) {
-      return context_;
-    } else {
-      return Handle<Context>();
-    }
-  }
-
-#ifdef DEBUG
-  // Debug print of the content of the current scope.
-  void DebugPrint() {
-    OFStream os(stdout);
-    DCHECK(!failed_);
-    switch (Type()) {
-      case ScopeIterator::ScopeTypeGlobal:
-        os << "Global:\n";
-        CurrentContext()->Print(os);
-        break;
-
-      case ScopeIterator::ScopeTypeLocal: {
-        os << "Local:\n";
-        function_->shared()->scope_info()->Print();
-        if (!CurrentContext().is_null()) {
-          CurrentContext()->Print(os);
-          if (CurrentContext()->has_extension()) {
-            Handle<Object> extension(CurrentContext()->extension(), isolate_);
-            if (extension->IsJSContextExtensionObject()) {
-              extension->Print(os);
-            }
-          }
-        }
-        break;
-      }
-
-      case ScopeIterator::ScopeTypeWith:
-        os << "With:\n";
-        CurrentContext()->extension()->Print(os);
-        break;
-
-      case ScopeIterator::ScopeTypeCatch:
-        os << "Catch:\n";
-        CurrentContext()->extension()->Print(os);
-        CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os);
-        break;
-
-      case ScopeIterator::ScopeTypeClosure:
-        os << "Closure:\n";
-        CurrentContext()->Print(os);
-        if (CurrentContext()->has_extension()) {
-          Handle<Object> extension(CurrentContext()->extension(), isolate_);
-          if (extension->IsJSContextExtensionObject()) {
-            extension->Print(os);
-          }
-        }
-        break;
-
-      default:
-        UNREACHABLE();
-    }
-    PrintF("\n");
-  }
-#endif
-
- private:
-  Isolate* isolate_;
-  JavaScriptFrame* frame_;
-  int inlined_jsframe_index_;
-  Handle<JSFunction> function_;
-  Handle<Context> context_;
-  List<Handle<ScopeInfo> > nested_scope_chain_;
-  bool failed_;
-
-  void RetrieveScopeChain(Scope* scope,
-                          Handle<SharedFunctionInfo> shared_info) {
-    if (scope != NULL) {
-      int source_position = shared_info->code()->SourcePosition(frame_->pc());
-      scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
-    } else {
-      // A failed reparse indicates that the preparser has diverged from the
-      // parser or that the preparse data given to the initial parse has been
-      // faulty. We fail in debug mode but in release mode we only provide the
-      // information we get from the context chain but nothing about
-      // completely stack allocated scopes or stack allocated locals.
-      // Or it could be due to stack overflow.
-      DCHECK(isolate_->has_pending_exception());
-      failed_ = true;
-    }
-  }
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
-};
-
-
-RUNTIME_FUNCTION(Runtime_GetScopeCount) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
-  RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
-  CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
-
-  // Get the frame where the debugging is performed.
-  StackFrame::Id id = UnwrapFrameId(wrapped_id);
-  JavaScriptFrameIterator it(isolate, id);
-  JavaScriptFrame* frame = it.frame();
-
-  // Count the visible scopes.
-  int n = 0;
-  for (ScopeIterator it(isolate, frame, 0);
-       !it.Done();
-       it.Next()) {
-    n++;
-  }
-
-  return Smi::FromInt(n);
-}
-
-
-// Returns the list of step-in positions (text offset) in a function of the
-// stack frame in a range from the current debug break position to the end
-// of the corresponding statement.
-RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
-  RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
-  CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
-
-  // Get the frame where the debugging is performed.
-  StackFrame::Id id = UnwrapFrameId(wrapped_id);
-  JavaScriptFrameIterator frame_it(isolate, id);
-  RUNTIME_ASSERT(!frame_it.done());
-
-  JavaScriptFrame* frame = frame_it.frame();
-
-  Handle<JSFunction> fun =
-      Handle<JSFunction>(frame->function());
-  Handle<SharedFunctionInfo> shared =
-      Handle<SharedFunctionInfo>(fun->shared());
-
-  if (!isolate->debug()->EnsureDebugInfo(shared, fun)) {
-    return isolate->heap()->undefined_value();
-  }
-
-  Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared);
-
-  int len = 0;
-  Handle<JSArray> array(isolate->factory()->NewJSArray(10));
-  // Find the break point where execution has stopped.
-  BreakLocationIterator break_location_iterator(debug_info,
-                                                ALL_BREAK_LOCATIONS);
-
-  break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
-  int current_statement_pos = break_location_iterator.statement_position();
-
-  while (!break_location_iterator.Done()) {
-    bool accept;
-    if (break_location_iterator.pc() > frame->pc()) {
-      accept = true;
-    } else {
-      StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
-      // The break point is near our pc. Could be a step-in possibility,
-      // that is currently taken by active debugger call.
-      if (break_frame_id == StackFrame::NO_ID) {
-        // We are not stepping.
-        accept = false;
-      } else {
-        JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id);
-        // If our frame is a top frame and we are stepping, we can do step-in
-        // at this place.
-        accept = additional_frame_it.frame()->id() == id;
-      }
-    }
-    if (accept) {
-      if (break_location_iterator.IsStepInLocation(isolate)) {
-        Smi* position_value = Smi::FromInt(break_location_iterator.position());
-        RETURN_FAILURE_ON_EXCEPTION(
-            isolate,
-            JSObject::SetElement(array, len,
-                                 Handle<Object>(position_value, isolate),
-                                 NONE, SLOPPY));
-        len++;
-      }
-    }
-    // Advance iterator.
-    break_location_iterator.Next();
-    if (current_statement_pos !=
-        break_location_iterator.statement_position()) {
-      break;
-    }
-  }
-  return *array;
-}
-
-
-static const int kScopeDetailsTypeIndex = 0;
-static const int kScopeDetailsObjectIndex = 1;
-static const int kScopeDetailsSize = 2;
-
-
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScopeDetails(
-    Isolate* isolate,
-    ScopeIterator* it) {
-  // Calculate the size of the result.
-  int details_size = kScopeDetailsSize;
-  Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
-
-  // Fill in scope details.
-  details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
-  Handle<JSObject> scope_object;
-  ASSIGN_RETURN_ON_EXCEPTION(
-      isolate, scope_object, it->ScopeObject(), JSObject);
-  details->set(kScopeDetailsObjectIndex, *scope_object);
-
-  return isolate->factory()->NewJSArrayWithElements(details);
-}
-
-
-// Return an array with scope details
-// args[0]: number: break id
-// args[1]: number: frame index
-// args[2]: number: inlined frame index
-// args[3]: number: scope index
-//
-// The array returned contains the following information:
-// 0: Scope type
-// 1: Scope object
-RUNTIME_FUNCTION(Runtime_GetScopeDetails) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
-  RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
-  CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
-  CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
-  CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
-
-  // Get the frame where the debugging is performed.
-  StackFrame::Id id = UnwrapFrameId(wrapped_id);
-  JavaScriptFrameIterator frame_it(isolate, id);
-  JavaScriptFrame* frame = frame_it.frame();
-
-  // Find the requested scope.
-  int n = 0;
-  ScopeIterator it(isolate, frame, inlined_jsframe_index);
-  for (; !it.Done() && n < index; it.Next()) {
-    n++;
-  }
-  if (it.Done()) {
-    return isolate->heap()->undefined_value();
-  }
-  Handle<JSObject> details;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, details, MaterializeScopeDetails(isolate, &it));
-  return *details;
-}
-
-
-// Return an array of scope details
-// args[0]: number: break id
-// args[1]: number: frame index
-// args[2]: number: inlined frame index
-// args[3]: boolean: ignore nested scopes
-//
-// The array returned contains arrays with the following information:
-// 0: Scope type
-// 1: Scope object
-RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3 || args.length() == 4);
-  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
-  RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
-  CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
-  CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
-
-  bool ignore_nested_scopes = false;
-  if (args.length() == 4) {
-    CONVERT_BOOLEAN_ARG_CHECKED(flag, 3);
-    ignore_nested_scopes = flag;
-  }
-
-  // Get the frame where the debugging is performed.
-  StackFrame::Id id = UnwrapFrameId(wrapped_id);
-  JavaScriptFrameIterator frame_it(isolate, id);
-  JavaScriptFrame* frame = frame_it.frame();
-
-  List<Handle<JSObject> > result(4);
-  ScopeIterator it(isolate, frame, inlined_jsframe_index, ignore_nested_scopes);
-  for (; !it.Done(); it.Next()) {
-    Handle<JSObject> details;
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, details, MaterializeScopeDetails(isolate, &it));
-    result.Add(details);
-  }
-
-  Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length());
-  for (int i = 0; i < result.length(); ++i) {
-    array->set(i, *result[i]);
-  }
-  return *isolate->factory()->NewJSArrayWithElements(array);
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-
-  // Check arguments.
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
-
-  // Count the visible scopes.
-  int n = 0;
-  for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
-    n++;
-  }
-
-  return Smi::FromInt(n);
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  // Check arguments.
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
-  CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
-
-  // Find the requested scope.
-  int n = 0;
-  ScopeIterator it(isolate, fun);
-  for (; !it.Done() && n < index; it.Next()) {
-    n++;
-  }
-  if (it.Done()) {
-    return isolate->heap()->undefined_value();
-  }
-
-  Handle<JSObject> details;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, details, MaterializeScopeDetails(isolate, &it));
-  return *details;
-}
-
-
-static bool SetScopeVariableValue(ScopeIterator* it, int index,
-                                  Handle<String> variable_name,
-                                  Handle<Object> new_value) {
-  for (int n = 0; !it->Done() && n < index; it->Next()) {
-    n++;
-  }
-  if (it->Done()) {
-    return false;
-  }
-  return it->SetVariableValue(variable_name, new_value);
-}
-
-
-// Change variable value in closure or local scope
-// args[0]: number or JsFunction: break id or function
-// args[1]: number: frame index (when arg[0] is break id)
-// args[2]: number: inlined frame index (when arg[0] is break id)
-// args[3]: number: scope index
-// args[4]: string: variable name
-// args[5]: object: new value
-//
-// Return true if success and false otherwise
-RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 6);
-
-  // Check arguments.
-  CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
-  CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4);
-  CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 5);
-
-  bool res;
-  if (args[0]->IsNumber()) {
-    CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
-    RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
-    CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
-    CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
-
-    // Get the frame where the debugging is performed.
-    StackFrame::Id id = UnwrapFrameId(wrapped_id);
-    JavaScriptFrameIterator frame_it(isolate, id);
-    JavaScriptFrame* frame = frame_it.frame();
-
-    ScopeIterator it(isolate, frame, inlined_jsframe_index);
-    res = SetScopeVariableValue(&it, index, variable_name, new_value);
-  } else {
-    CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
-    ScopeIterator it(isolate, fun);
-    res = SetScopeVariableValue(&it, index, variable_name, new_value);
-  }
-
-  return isolate->heap()->ToBoolean(res);
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugPrintScopes) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-
-#ifdef DEBUG
-  // Print the scopes for the top frame.
-  StackFrameLocator locator(isolate);
-  JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
-  for (ScopeIterator it(isolate, frame, 0);
-       !it.Done();
-       it.Next()) {
-    it.DebugPrint();
-  }
-#endif
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetThreadCount) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
-  RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
-  // Count all archived V8 threads.
-  int n = 0;
-  for (ThreadState* thread =
-          isolate->thread_manager()->FirstThreadStateInUse();
-       thread != NULL;
-       thread = thread->Next()) {
-    n++;
-  }
-
-  // Total number of threads is current thread and archived threads.
-  return Smi::FromInt(n + 1);
-}
-
-
-static const int kThreadDetailsCurrentThreadIndex = 0;
-static const int kThreadDetailsThreadIdIndex = 1;
-static const int kThreadDetailsSize = 2;
-
-// Return an array with thread details
-// args[0]: number: break id
-// args[1]: number: thread index
-//
-// The array returned contains the following information:
-// 0: Is current thread?
-// 1: Thread id
-RUNTIME_FUNCTION(Runtime_GetThreadDetails) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
-  RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
-  CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
-
-  // Allocate array for result.
-  Handle<FixedArray> details =
-      isolate->factory()->NewFixedArray(kThreadDetailsSize);
-
-  // Thread index 0 is current thread.
-  if (index == 0) {
-    // Fill the details.
-    details->set(kThreadDetailsCurrentThreadIndex,
-                 isolate->heap()->true_value());
-    details->set(kThreadDetailsThreadIdIndex,
-                 Smi::FromInt(ThreadId::Current().ToInteger()));
-  } else {
-    // Find the thread with the requested index.
-    int n = 1;
-    ThreadState* thread =
-        isolate->thread_manager()->FirstThreadStateInUse();
-    while (index != n && thread != NULL) {
-      thread = thread->Next();
-      n++;
-    }
-    if (thread == NULL) {
-      return isolate->heap()->undefined_value();
-    }
-
-    // Fill the details.
-    details->set(kThreadDetailsCurrentThreadIndex,
-                 isolate->heap()->false_value());
-    details->set(kThreadDetailsThreadIdIndex,
-                 Smi::FromInt(thread->id().ToInteger()));
-  }
-
-  // Convert to JS array and return.
-  return *isolate->factory()->NewJSArrayWithElements(details);
-}
-
-
-// Sets the disable break state
-// args[0]: disable break state
-RUNTIME_FUNCTION(Runtime_SetDisableBreak) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
-  isolate->debug()->set_disable_break(disable_break);
-  return  isolate->heap()->undefined_value();
-}
-
-
-static bool IsPositionAlignmentCodeCorrect(int alignment) {
-  return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED;
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetBreakLocations) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
-  CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]);
-
-  if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
-    return isolate->ThrowIllegalOperation();
-  }
-  BreakPositionAlignment alignment =
-      static_cast<BreakPositionAlignment>(statement_aligned_code);
-
-  Handle<SharedFunctionInfo> shared(fun->shared());
-  // Find the number of break points
-  Handle<Object> break_locations =
-      Debug::GetSourceBreakLocations(shared, alignment);
-  if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
-  // Return array as JS array
-  return *isolate->factory()->NewJSArrayWithElements(
-      Handle<FixedArray>::cast(break_locations));
-}
-
-
-// Set a break point in a function.
-// args[0]: function
-// args[1]: number: break source position (within the function source)
-// args[2]: number: break point object
-RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
-  RUNTIME_ASSERT(source_position >= function->shared()->start_position() &&
-                 source_position <= function->shared()->end_position());
-  CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2);
-
-  // Set break point.
-  RUNTIME_ASSERT(isolate->debug()->SetBreakPoint(
-      function, break_point_object_arg, &source_position));
-
-  return Smi::FromInt(source_position);
-}
-
-
-// Changes the state of a break point in a script and returns source position
-// where break point was set. NOTE: Regarding performance see the NOTE for
-// GetScriptFromScriptData.
-// args[0]: script to set break point in
-// args[1]: number: break source position (within the script source)
-// args[2]: number, breakpoint position alignment
-// args[3]: number: break point object
-RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-  CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
-  CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
-  RUNTIME_ASSERT(source_position >= 0);
-  CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]);
-  CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3);
-
-  if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
-    return isolate->ThrowIllegalOperation();
-  }
-  BreakPositionAlignment alignment =
-      static_cast<BreakPositionAlignment>(statement_aligned_code);
-
-  // Get the script from the script wrapper.
-  RUNTIME_ASSERT(wrapper->value()->IsScript());
-  Handle<Script> script(Script::cast(wrapper->value()));
-
-  // Set break point.
-  if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
-                                                &source_position,
-                                                alignment)) {
-    return isolate->heap()->undefined_value();
-  }
-
-  return Smi::FromInt(source_position);
-}
-
-
-// Clear a break point
-// args[0]: number: break point object
-RUNTIME_FUNCTION(Runtime_ClearBreakPoint) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0);
-
-  // Clear break point.
-  isolate->debug()->ClearBreakPoint(break_point_object_arg);
-
-  return isolate->heap()->undefined_value();
-}
-
-
-// Change the state of break on exceptions.
-// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
-// args[1]: Boolean indicating on/off.
-RUNTIME_FUNCTION(Runtime_ChangeBreakOnException) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
-  CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
-
-  // If the number doesn't match an enum value, the ChangeBreakOnException
-  // function will default to affecting caught exceptions.
-  ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
-  // Update break point state.
-  isolate->debug()->ChangeBreakOnException(type, enable);
-  return isolate->heap()->undefined_value();
-}
-
-
-// Returns the state of break on exceptions
-// args[0]: boolean indicating uncaught exceptions
-RUNTIME_FUNCTION(Runtime_IsBreakOnException) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
-
-  ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
-  bool result = isolate->debug()->IsBreakOnException(type);
-  return Smi::FromInt(result);
-}
-
-
-// Prepare for stepping
-// args[0]: break id for checking execution state
-// args[1]: step action from the enumeration StepAction
-// args[2]: number of times to perform the step, for step out it is the number
-//          of frames to step down.
-RUNTIME_FUNCTION(Runtime_PrepareStep) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
-  RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
-  if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
-    return isolate->Throw(isolate->heap()->illegal_argument_string());
-  }
-
-  CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]);
-
-  StackFrame::Id frame_id;
-  if (wrapped_frame_id == 0) {
-    frame_id = StackFrame::NO_ID;
-  } else {
-    frame_id = UnwrapFrameId(wrapped_frame_id);
-  }
-
-  // Get the step action and check validity.
-  StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
-  if (step_action != StepIn &&
-      step_action != StepNext &&
-      step_action != StepOut &&
-      step_action != StepInMin &&
-      step_action != StepMin) {
-    return isolate->Throw(isolate->heap()->illegal_argument_string());
-  }
-
-  if (frame_id != StackFrame::NO_ID && step_action != StepNext &&
-      step_action != StepMin && step_action != StepOut) {
-    return isolate->ThrowIllegalOperation();
-  }
-
-  // Get the number of steps.
-  int step_count = NumberToInt32(args[2]);
-  if (step_count < 1) {
-    return isolate->Throw(isolate->heap()->illegal_argument_string());
-  }
-
-  // Clear all current stepping setup.
-  isolate->debug()->ClearStepping();
-
-  // Prepare step.
-  isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
-                                step_count,
-                                frame_id);
-  return isolate->heap()->undefined_value();
-}
-
-
-// Clear all stepping set by PrepareStep.
-RUNTIME_FUNCTION(Runtime_ClearStepping) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-  isolate->debug()->ClearStepping();
-  return isolate->heap()->undefined_value();
-}
-
-
-// Helper function to find or create the arguments object for
-// Runtime_DebugEvaluate.
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeArgumentsObject(
-    Isolate* isolate,
-    Handle<JSObject> target,
-    Handle<JSFunction> function) {
-  // Do not materialize the arguments object for eval or top-level code.
-  // Skip if "arguments" is already taken.
-  if (!function->shared()->is_function()) return target;
-  Maybe<bool> maybe = JSReceiver::HasOwnProperty(
-      target, isolate->factory()->arguments_string());
-  if (!maybe.has_value) return MaybeHandle<JSObject>();
-  if (maybe.value) return target;
-
-  // FunctionGetArguments can't throw an exception.
-  Handle<JSObject> arguments = Handle<JSObject>::cast(
-      Accessors::FunctionGetArguments(function));
-  Handle<String> arguments_str = isolate->factory()->arguments_string();
-  RETURN_ON_EXCEPTION(
-      isolate,
-      Runtime::DefineObjectProperty(target, arguments_str, arguments, NONE),
-      JSObject);
-  return target;
-}
-
-
-// Compile and evaluate source for the given context.
-static MaybeHandle<Object> DebugEvaluate(Isolate* isolate,
-                                         Handle<SharedFunctionInfo> outer_info,
-                                         Handle<Context> context,
-                                         Handle<Object> context_extension,
-                                         Handle<Object> receiver,
-                                         Handle<String> source) {
-  if (context_extension->IsJSObject()) {
-    Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
-    Handle<JSFunction> closure(context->closure(), isolate);
-    context = isolate->factory()->NewWithContext(closure, context, extension);
-  }
-
-  Handle<JSFunction> eval_fun;
-  ASSIGN_RETURN_ON_EXCEPTION(
-      isolate, eval_fun,
-      Compiler::GetFunctionFromEval(source,
-                                    outer_info,
-                                    context,
-                                    SLOPPY,
-                                    NO_PARSE_RESTRICTION,
-                                    RelocInfo::kNoPosition),
-      Object);
-
-  Handle<Object> result;
-  ASSIGN_RETURN_ON_EXCEPTION(
-      isolate, result,
-      Execution::Call(isolate, eval_fun, receiver, 0, NULL),
-      Object);
-
-  // Skip the global proxy as it has no properties and always delegates to the
-  // real global object.
-  if (result->IsJSGlobalProxy()) {
-    PrototypeIterator iter(isolate, result);
-    // TODO(verwaest): This will crash when the global proxy is detached.
-    result = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
-  }
-
-  // Clear the oneshot breakpoints so that the debugger does not step further.
-  isolate->debug()->ClearStepping();
-  return result;
-}
-
-
-static Handle<JSObject> NewJSObjectWithNullProto(Isolate* isolate) {
-  Handle<JSObject> result =
-      isolate->factory()->NewJSObject(isolate->object_function());
-  Handle<Map> new_map = Map::Copy(Handle<Map>(result->map()));
-  new_map->set_prototype(*isolate->factory()->null_value());
-  JSObject::MigrateToMap(result, new_map);
-  return result;
-}
-
-
-// Evaluate a piece of JavaScript in the context of a stack frame for
-// debugging.  Things that need special attention are:
-// - Parameters and stack-allocated locals need to be materialized.  Altered
-//   values need to be written back to the stack afterwards.
-// - The arguments object needs to materialized.
-RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
-  HandleScope scope(isolate);
-
-  // Check the execution state and decode arguments frame and source to be
-  // evaluated.
-  DCHECK(args.length() == 6);
-  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
-  RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
-  CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
-  CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
-  CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
-  CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
-  CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5);
-
-  // Handle the processing of break.
-  DisableBreak disable_break_scope(isolate->debug(), disable_break);
-
-  // Get the frame where the debugging is performed.
-  StackFrame::Id id = UnwrapFrameId(wrapped_id);
-  JavaScriptFrameIterator it(isolate, id);
-  JavaScriptFrame* frame = it.frame();
-  FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
-  Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
-  Handle<SharedFunctionInfo> outer_info(function->shared());
-
-  // Traverse the saved contexts chain to find the active context for the
-  // selected frame.
-  SaveContext* save = FindSavedContextForFrame(isolate, frame);
-
-  SaveContext savex(isolate);
-  isolate->set_context(*(save->context()));
-
-  // Evaluate on the context of the frame.
-  Handle<Context> context(Context::cast(frame_inspector.GetContext()));
-  DCHECK(!context.is_null());
-
-  // Materialize stack locals and the arguments object.
-  Handle<JSObject> materialized = NewJSObjectWithNullProto(isolate);
-
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, materialized,
-      MaterializeStackLocalsWithFrameInspector(
-          isolate, materialized, function, &frame_inspector));
-
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, materialized,
-      MaterializeArgumentsObject(isolate, materialized, function));
-
-  // Add the materialized object in a with-scope to shadow the stack locals.
-  context = isolate->factory()->NewWithContext(function, context, materialized);
-
-  Handle<Object> receiver(frame->receiver(), isolate);
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      DebugEvaluate(isolate, outer_info,
-                    context, context_extension, receiver, source));
-
-  // Write back potential changes to materialized stack locals to the stack.
-  UpdateStackLocalsFromMaterializedObject(
-      isolate, materialized, function, frame, inlined_jsframe_index);
-
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
-  HandleScope scope(isolate);
-
-  // Check the execution state and decode arguments frame and source to be
-  // evaluated.
-  DCHECK(args.length() == 4);
-  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
-  RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
-  CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
-  CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
-  CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3);
-
-  // Handle the processing of break.
-  DisableBreak disable_break_scope(isolate->debug(), disable_break);
-
-  // Enter the top context from before the debugger was invoked.
-  SaveContext save(isolate);
-  SaveContext* top = &save;
-  while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
-    top = top->prev();
-  }
-  if (top != NULL) {
-    isolate->set_context(*top->context());
-  }
-
-  // Get the native context now set to the top context from before the
-  // debugger was invoked.
-  Handle<Context> context = isolate->native_context();
-  Handle<JSObject> receiver(context->global_proxy());
-  Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate);
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      DebugEvaluate(isolate, outer_info,
-                    context, context_extension, receiver, source));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-
-  // Fill the script objects.
-  Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
-
-  // Convert the script objects to proper JS objects.
-  for (int i = 0; i < instances->length(); i++) {
-    Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
-    // Get the script wrapper in a local handle before calling GetScriptWrapper,
-    // because using
-    //   instances->set(i, *GetScriptWrapper(script))
-    // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
-    // already have dereferenced the instances handle.
-    Handle<JSObject> wrapper = Script::GetWrapper(script);
-    instances->set(i, *wrapper);
-  }
-
-  // Return result as a JS array.
-  Handle<JSObject> result =
-      isolate->factory()->NewJSObject(isolate->array_function());
-  JSArray::SetContent(Handle<JSArray>::cast(result), instances);
-  return *result;
-}
-
-
-// Helper function used by Runtime_DebugReferencedBy below.
-static int DebugReferencedBy(HeapIterator* iterator,
-                             JSObject* target,
-                             Object* instance_filter, int max_references,
-                             FixedArray* instances, int instances_size,
-                             JSFunction* arguments_function) {
-  Isolate* isolate = target->GetIsolate();
-  SealHandleScope shs(isolate);
-  DisallowHeapAllocation no_allocation;
-
-  // Iterate the heap.
-  int count = 0;
-  JSObject* last = NULL;
-  HeapObject* heap_obj = NULL;
-  while (((heap_obj = iterator->next()) != NULL) &&
-         (max_references == 0 || count < max_references)) {
-    // Only look at all JSObjects.
-    if (heap_obj->IsJSObject()) {
-      // Skip context extension objects and argument arrays as these are
-      // checked in the context of functions using them.
-      JSObject* obj = JSObject::cast(heap_obj);
-      if (obj->IsJSContextExtensionObject() ||
-          obj->map()->constructor() == arguments_function) {
-        continue;
-      }
-
-      // Check if the JS object has a reference to the object looked for.
-      if (obj->ReferencesObject(target)) {
-        // Check instance filter if supplied. This is normally used to avoid
-        // references from mirror objects (see Runtime_IsInPrototypeChain).
-        if (!instance_filter->IsUndefined()) {
-          for (PrototypeIterator iter(isolate, obj); !iter.IsAtEnd();
-               iter.Advance()) {
-            if (iter.GetCurrent() == instance_filter) {
-              obj = NULL;  // Don't add this object.
-              break;
-            }
-          }
-        }
-
-        if (obj != NULL) {
-          // Valid reference found add to instance array if supplied an update
-          // count.
-          if (instances != NULL && count < instances_size) {
-            instances->set(count, obj);
-          }
-          last = obj;
-          count++;
-        }
-      }
-    }
-  }
-
-  // Check for circular reference only. This can happen when the object is only
-  // referenced from mirrors and has a circular reference in which case the
-  // object is not really alive and would have been garbage collected if not
-  // referenced from the mirror.
-  if (count == 1 && last == target) {
-    count = 0;
-  }
-
-  // Return the number of referencing objects found.
-  return count;
-}
-
-
-// Scan the heap for objects with direct references to an object
-// args[0]: the object to find references to
-// args[1]: constructor function for instances to exclude (Mirror)
-// args[2]: the the maximum number of objects to return
-RUNTIME_FUNCTION(Runtime_DebugReferencedBy) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-
-  // Check parameters.
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, instance_filter, 1);
-  RUNTIME_ASSERT(instance_filter->IsUndefined() ||
-                 instance_filter->IsJSObject());
-  CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
-  RUNTIME_ASSERT(max_references >= 0);
-
-
-  // Get the constructor function for context extension and arguments array.
-  Handle<JSFunction> arguments_function(
-      JSFunction::cast(isolate->sloppy_arguments_map()->constructor()));
-
-  // Get the number of referencing objects.
-  int count;
-  // First perform a full GC in order to avoid dead objects and to make the heap
-  // iterable.
-  Heap* heap = isolate->heap();
-  heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
-  {
-    HeapIterator heap_iterator(heap);
-    count = DebugReferencedBy(&heap_iterator,
-                              *target, *instance_filter, max_references,
-                              NULL, 0, *arguments_function);
-  }
-
-  // Allocate an array to hold the result.
-  Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
-
-  // Fill the referencing objects.
-  {
-    HeapIterator heap_iterator(heap);
-    count = DebugReferencedBy(&heap_iterator,
-                              *target, *instance_filter, max_references,
-                              *instances, count, *arguments_function);
-  }
-
-  // Return result as JS array.
-  Handle<JSFunction> constructor = isolate->array_function();
-
-  Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
-  JSArray::SetContent(Handle<JSArray>::cast(result), instances);
-  return *result;
-}
-
-
-// Helper function used by Runtime_DebugConstructedBy below.
-static int DebugConstructedBy(HeapIterator* iterator,
-                              JSFunction* constructor,
-                              int max_references,
-                              FixedArray* instances,
-                              int instances_size) {
-  DisallowHeapAllocation no_allocation;
-
-  // Iterate the heap.
-  int count = 0;
-  HeapObject* heap_obj = NULL;
-  while (((heap_obj = iterator->next()) != NULL) &&
-         (max_references == 0 || count < max_references)) {
-    // Only look at all JSObjects.
-    if (heap_obj->IsJSObject()) {
-      JSObject* obj = JSObject::cast(heap_obj);
-      if (obj->map()->constructor() == constructor) {
-        // Valid reference found add to instance array if supplied an update
-        // count.
-        if (instances != NULL && count < instances_size) {
-          instances->set(count, obj);
-        }
-        count++;
-      }
-    }
-  }
-
-  // Return the number of referencing objects found.
-  return count;
-}
-
-
-// Scan the heap for objects constructed by a specific function.
-// args[0]: the constructor to find instances of
-// args[1]: the the maximum number of objects to return
-RUNTIME_FUNCTION(Runtime_DebugConstructedBy) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-
-  // Check parameters.
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
-  CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
-  RUNTIME_ASSERT(max_references >= 0);
-
-  // Get the number of referencing objects.
-  int count;
-  // First perform a full GC in order to avoid dead objects and to make the heap
-  // iterable.
-  Heap* heap = isolate->heap();
-  heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
-  {
-    HeapIterator heap_iterator(heap);
-    count = DebugConstructedBy(&heap_iterator,
-                               *constructor,
-                               max_references,
-                               NULL,
-                               0);
-  }
-
-  // Allocate an array to hold the result.
-  Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
-
-  // Fill the referencing objects.
-  {
-    HeapIterator heap_iterator2(heap);
-    count = DebugConstructedBy(&heap_iterator2,
-                               *constructor,
-                               max_references,
-                               *instances,
-                               count);
-  }
-
-  // Return result as JS array.
-  Handle<JSFunction> array_function = isolate->array_function();
-  Handle<JSObject> result = isolate->factory()->NewJSObject(array_function);
-  JSArray::SetContent(Handle<JSArray>::cast(result), instances);
-  return *result;
-}
-
-
-// Find the effective prototype object as returned by __proto__.
-// args[0]: the object to find the prototype for.
-RUNTIME_FUNCTION(Runtime_DebugGetPrototype) {
-  HandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
-  return *GetPrototypeSkipHiddenPrototypes(isolate, obj);
-}
-
-
-// Patches script source (should be called upon BeforeCompile event).
-RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
-
-  RUNTIME_ASSERT(script_wrapper->value()->IsScript());
-  Handle<Script> script(Script::cast(script_wrapper->value()));
-
-  int compilation_state = script->compilation_state();
-  RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
-  script->set_source(*source);
-
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_SystemBreak) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  base::OS::DebugBreak();
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugDisassembleFunction) {
-  HandleScope scope(isolate);
-#ifdef DEBUG
-  DCHECK(args.length() == 1);
-  // Get the function and make sure it is compiled.
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
-  if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
-    return isolate->heap()->exception();
-  }
-  OFStream os(stdout);
-  func->code()->Print(os);
-  os << endl;
-#endif  // DEBUG
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugDisassembleConstructor) {
-  HandleScope scope(isolate);
-#ifdef DEBUG
-  DCHECK(args.length() == 1);
-  // Get the function and make sure it is compiled.
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
-  if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
-    return isolate->heap()->exception();
-  }
-  OFStream os(stdout);
-  func->shared()->construct_stub()->Print(os);
-  os << endl;
-#endif  // DEBUG
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_CHECKED(JSFunction, f, 0);
-  return f->shared()->inferred_name();
-}
-
-
-static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
-                                            Script* script,
-                                            FixedArray* buffer) {
-  DisallowHeapAllocation no_allocation;
-  int counter = 0;
-  int buffer_size = buffer->length();
-  for (HeapObject* obj = iterator->next();
-       obj != NULL;
-       obj = iterator->next()) {
-    DCHECK(obj != NULL);
-    if (!obj->IsSharedFunctionInfo()) {
-      continue;
-    }
-    SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
-    if (shared->script() != script) {
-      continue;
-    }
-    if (counter < buffer_size) {
-      buffer->set(counter, shared);
-    }
-    counter++;
-  }
-  return counter;
-}
-
-
-// For a script finds all SharedFunctionInfo's in the heap that points
-// to this script. Returns JSArray of SharedFunctionInfo wrapped
-// in OpaqueReferences.
-RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) {
-  HandleScope scope(isolate);
-  CHECK(isolate->debug()->live_edit_enabled());
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSValue, script_value, 0);
-
-  RUNTIME_ASSERT(script_value->value()->IsScript());
-  Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
-
-  const int kBufferSize = 32;
-
-  Handle<FixedArray> array;
-  array = isolate->factory()->NewFixedArray(kBufferSize);
-  int number;
-  Heap* heap = isolate->heap();
-  {
-    HeapIterator heap_iterator(heap);
-    Script* scr = *script;
-    FixedArray* arr = *array;
-    number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
-  }
-  if (number > kBufferSize) {
-    array = isolate->factory()->NewFixedArray(number);
-    HeapIterator heap_iterator(heap);
-    Script* scr = *script;
-    FixedArray* arr = *array;
-    FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
-  }
-
-  Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
-  result->set_length(Smi::FromInt(number));
-
-  LiveEdit::WrapSharedFunctionInfos(result);
-
-  return *result;
-}
-
-
-// For a script calculates compilation information about all its functions.
-// The script source is explicitly specified by the second argument.
-// The source of the actual script is not used, however it is important that
-// all generated code keeps references to this particular instance of script.
-// Returns a JSArray of compilation infos. The array is ordered so that
-// each function with all its descendant is always stored in a continues range
-// with the function itself going first. The root function is a script function.
-RUNTIME_FUNCTION(Runtime_LiveEditGatherCompileInfo) {
-  HandleScope scope(isolate);
-  CHECK(isolate->debug()->live_edit_enabled());
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_CHECKED(JSValue, script, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
-
-  RUNTIME_ASSERT(script->value()->IsScript());
-  Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
-
-  Handle<JSArray> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result, LiveEdit::GatherCompileInfo(script_handle, source));
-  return *result;
-}
-
-
-// Changes the source of the script to a new_source.
-// If old_script_name is provided (i.e. is a String), also creates a copy of
-// the script with its original source and sends notification to debugger.
-RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) {
-  HandleScope scope(isolate);
-  CHECK(isolate->debug()->live_edit_enabled());
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, old_script_name, 2);
-
-  RUNTIME_ASSERT(original_script_value->value()->IsScript());
-  Handle<Script> original_script(Script::cast(original_script_value->value()));
-
-  Handle<Object> old_script = LiveEdit::ChangeScriptSource(
-      original_script,  new_source,  old_script_name);
-
-  if (old_script->IsScript()) {
-    Handle<Script> script_handle = Handle<Script>::cast(old_script);
-    return *Script::GetWrapper(script_handle);
-  } else {
-    return isolate->heap()->null_value();
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) {
-  HandleScope scope(isolate);
-  CHECK(isolate->debug()->live_edit_enabled());
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
-  RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info));
-
-  LiveEdit::FunctionSourceUpdated(shared_info);
-  return isolate->heap()->undefined_value();
-}
-
-
-// Replaces code of SharedFunctionInfo with a new one.
-RUNTIME_FUNCTION(Runtime_LiveEditReplaceFunctionCode) {
-  HandleScope scope(isolate);
-  CHECK(isolate->debug()->live_edit_enabled());
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
-  RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info));
-
-  LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
-  return isolate->heap()->undefined_value();
-}
-
-
-// Connects SharedFunctionInfo to another script.
-RUNTIME_FUNCTION(Runtime_LiveEditFunctionSetScript) {
-  HandleScope scope(isolate);
-  CHECK(isolate->debug()->live_edit_enabled());
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, script_object, 1);
-
-  if (function_object->IsJSValue()) {
-    Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
-    if (script_object->IsJSValue()) {
-      RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
-      Script* script = Script::cast(JSValue::cast(*script_object)->value());
-      script_object = Handle<Object>(script, isolate);
-    }
-    RUNTIME_ASSERT(function_wrapper->value()->IsSharedFunctionInfo());
-    LiveEdit::SetFunctionScript(function_wrapper, script_object);
-  } else {
-    // Just ignore this. We may not have a SharedFunctionInfo for some functions
-    // and we check it in this function.
-  }
-
-  return isolate->heap()->undefined_value();
-}
-
-
-// In a code of a parent function replaces original function as embedded object
-// with a substitution one.
-RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) {
-  HandleScope scope(isolate);
-  CHECK(isolate->debug()->live_edit_enabled());
-  DCHECK(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
-  RUNTIME_ASSERT(parent_wrapper->value()->IsSharedFunctionInfo());
-  RUNTIME_ASSERT(orig_wrapper->value()->IsSharedFunctionInfo());
-  RUNTIME_ASSERT(subst_wrapper->value()->IsSharedFunctionInfo());
-
-  LiveEdit::ReplaceRefToNestedFunction(
-      parent_wrapper, orig_wrapper, subst_wrapper);
-  return isolate->heap()->undefined_value();
-}
-
-
-// Updates positions of a shared function info (first parameter) according
-// to script source change. Text change is described in second parameter as
-// array of groups of 3 numbers:
-// (change_begin, change_end, change_end_new_position).
-// Each group describes a change in text; groups are sorted by change_begin.
-RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) {
-  HandleScope scope(isolate);
-  CHECK(isolate->debug()->live_edit_enabled());
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
-  RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_array))
-
-  LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
-  return isolate->heap()->undefined_value();
-}
-
-
-// For array of SharedFunctionInfo's (each wrapped in JSValue)
-// checks that none of them have activations on stacks (of any thread).
-// Returns array of the same length with corresponding results of
-// LiveEdit::FunctionPatchabilityStatus type.
-RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) {
-  HandleScope scope(isolate);
-  CHECK(isolate->debug()->live_edit_enabled());
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
-  CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
-  RUNTIME_ASSERT(shared_array->length()->IsSmi());
-  RUNTIME_ASSERT(shared_array->HasFastElements())
-  int array_length = Smi::cast(shared_array->length())->value();
-  for (int i = 0; i < array_length; i++) {
-    Handle<Object> element =
-        Object::GetElement(isolate, shared_array, i).ToHandleChecked();
-    RUNTIME_ASSERT(
-        element->IsJSValue() &&
-        Handle<JSValue>::cast(element)->value()->IsSharedFunctionInfo());
-  }
-
-  return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
-}
-
-
-// Compares 2 strings line-by-line, then token-wise and returns diff in form
-// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
-// of diff chunks.
-RUNTIME_FUNCTION(Runtime_LiveEditCompareStrings) {
-  HandleScope scope(isolate);
-  CHECK(isolate->debug()->live_edit_enabled());
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
-
-  return *LiveEdit::CompareStrings(s1, s2);
-}
-
-
-// Restarts a call frame and completely drops all frames above.
-// Returns true if successful. Otherwise returns undefined or an error message.
-RUNTIME_FUNCTION(Runtime_LiveEditRestartFrame) {
-  HandleScope scope(isolate);
-  CHECK(isolate->debug()->live_edit_enabled());
-  DCHECK(args.length() == 2);
-  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
-  RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
-  CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
-  Heap* heap = isolate->heap();
-
-  // Find the relevant frame with the requested index.
-  StackFrame::Id id = isolate->debug()->break_frame_id();
-  if (id == StackFrame::NO_ID) {
-    // If there are no JavaScript stack frames return undefined.
-    return heap->undefined_value();
-  }
-
-  JavaScriptFrameIterator it(isolate, id);
-  int inlined_jsframe_index = FindIndexedNonNativeFrame(&it, index);
-  if (inlined_jsframe_index == -1) return heap->undefined_value();
-  // We don't really care what the inlined frame index is, since we are
-  // throwing away the entire frame anyways.
-  const char* error_message = LiveEdit::RestartFrame(it.frame());
-  if (error_message) {
-    return *(isolate->factory()->InternalizeUtf8String(error_message));
-  }
-  return heap->true_value();
-}
-
-
-// A testing entry. Returns statement position which is the closest to
-// source_position.
-RUNTIME_FUNCTION(Runtime_GetFunctionCodePositionFromSource) {
-  HandleScope scope(isolate);
-  CHECK(isolate->debug()->live_edit_enabled());
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
-
-  Handle<Code> code(function->code(), isolate);
-
-  if (code->kind() != Code::FUNCTION &&
-      code->kind() != Code::OPTIMIZED_FUNCTION) {
-    return isolate->heap()->undefined_value();
-  }
-
-  RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
-  int closest_pc = 0;
-  int distance = kMaxInt;
-  while (!it.done()) {
-    int statement_position = static_cast<int>(it.rinfo()->data());
-    // Check if this break point is closer that what was previously found.
-    if (source_position <= statement_position &&
-        statement_position - source_position < distance) {
-      closest_pc =
-          static_cast<int>(it.rinfo()->pc() - code->instruction_start());
-      distance = statement_position - source_position;
-      // Check whether we can't get any closer.
-      if (distance == 0) break;
-    }
-    it.next();
-  }
-
-  return Smi::FromInt(closest_pc);
-}
-
-
-// Calls specified function with or without entering the debugger.
-// This is used in unit tests to run code as if debugger is entered or simply
-// to have a stack with C++ frame in the middle.
-RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
-
-  MaybeHandle<Object> maybe_result;
-  if (without_debugger) {
-    maybe_result = Execution::Call(isolate,
-                                   function,
-                                   handle(function->global_proxy()),
-                                   0,
-                                   NULL);
-  } else {
-    DebugScope debug_scope(isolate->debug());
-    maybe_result = Execution::Call(isolate,
-                                   function,
-                                   handle(function->global_proxy()),
-                                   0,
-                                   NULL);
-  }
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
-  return *result;
-}
-
-
-// Sets a v8 flag.
-RUNTIME_FUNCTION(Runtime_SetFlags) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(String, arg, 0);
-  SmartArrayPointer<char> flags =
-      arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
-  FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get()));
-  return isolate->heap()->undefined_value();
-}
-
-
-// Performs a GC.
-// Presently, it only does a full GC.
-RUNTIME_FUNCTION(Runtime_CollectGarbage) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
-  return isolate->heap()->undefined_value();
-}
-
-
-// Gets the current heap usage.
-RUNTIME_FUNCTION(Runtime_GetHeapUsage) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
-  if (!Smi::IsValid(usage)) {
-    return *isolate->factory()->NewNumberFromInt(usage);
-  }
-  return Smi::FromInt(usage);
-}
-
-
-#ifdef V8_I18N_SUPPORT
-RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) {
-  HandleScope scope(isolate);
-  Factory* factory = isolate->factory();
-
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0);
-
-  v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str));
-
-  // Return value which denotes invalid language tag.
-  const char* const kInvalidTag = "invalid-tag";
-
-  UErrorCode error = U_ZERO_ERROR;
-  char icu_result[ULOC_FULLNAME_CAPACITY];
-  int icu_length = 0;
-
-  uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY,
-                      &icu_length, &error);
-  if (U_FAILURE(error) || icu_length == 0) {
-    return *factory->NewStringFromAsciiChecked(kInvalidTag);
-  }
-
-  char result[ULOC_FULLNAME_CAPACITY];
-
-  // Force strict BCP47 rules.
-  uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error);
-
-  if (U_FAILURE(error)) {
-    return *factory->NewStringFromAsciiChecked(kInvalidTag);
-  }
-
-  return *factory->NewStringFromAsciiChecked(result);
-}
-
-
-RUNTIME_FUNCTION(Runtime_AvailableLocalesOf) {
-  HandleScope scope(isolate);
-  Factory* factory = isolate->factory();
-
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, service, 0);
-
-  const icu::Locale* available_locales = NULL;
-  int32_t count = 0;
-
-  if (service->IsUtf8EqualTo(CStrVector("collator"))) {
-    available_locales = icu::Collator::getAvailableLocales(count);
-  } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) {
-    available_locales = icu::NumberFormat::getAvailableLocales(count);
-  } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) {
-    available_locales = icu::DateFormat::getAvailableLocales(count);
-  } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) {
-    available_locales = icu::BreakIterator::getAvailableLocales(count);
-  }
-
-  UErrorCode error = U_ZERO_ERROR;
-  char result[ULOC_FULLNAME_CAPACITY];
-  Handle<JSObject> locales =
-      factory->NewJSObject(isolate->object_function());
-
-  for (int32_t i = 0; i < count; ++i) {
-    const char* icu_name = available_locales[i].getName();
-
-    error = U_ZERO_ERROR;
-    // No need to force strict BCP47 rules.
-    uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
-    if (U_FAILURE(error)) {
-      // This shouldn't happen, but lets not break the user.
-      continue;
-    }
-
-    RETURN_FAILURE_ON_EXCEPTION(isolate,
-        JSObject::SetOwnPropertyIgnoreAttributes(
-            locales,
-            factory->NewStringFromAsciiChecked(result),
-            factory->NewNumber(i),
-            NONE));
-  }
-
-  return *locales;
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetDefaultICULocale) {
-  HandleScope scope(isolate);
-  Factory* factory = isolate->factory();
-
-  DCHECK(args.length() == 0);
-
-  icu::Locale default_locale;
-
-  // Set the locale
-  char result[ULOC_FULLNAME_CAPACITY];
-  UErrorCode status = U_ZERO_ERROR;
-  uloc_toLanguageTag(
-      default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
-  if (U_SUCCESS(status)) {
-    return *factory->NewStringFromAsciiChecked(result);
-  }
-
-  return *factory->NewStringFromStaticChars("und");
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetLanguageTagVariants) {
-  HandleScope scope(isolate);
-  Factory* factory = isolate->factory();
-
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0);
-
-  uint32_t length = static_cast<uint32_t>(input->length()->Number());
-  // Set some limit to prevent fuzz tests from going OOM.
-  // Can be bumped when callers' requirements change.
-  RUNTIME_ASSERT(length < 100);
-  Handle<FixedArray> output = factory->NewFixedArray(length);
-  Handle<Name> maximized = factory->NewStringFromStaticChars("maximized");
-  Handle<Name> base = factory->NewStringFromStaticChars("base");
-  for (unsigned int i = 0; i < length; ++i) {
-    Handle<Object> locale_id;
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, locale_id, Object::GetElement(isolate, input, i));
-    if (!locale_id->IsString()) {
-      return isolate->Throw(*factory->illegal_argument_string());
-    }
-
-    v8::String::Utf8Value utf8_locale_id(
-        v8::Utils::ToLocal(Handle<String>::cast(locale_id)));
-
-    UErrorCode error = U_ZERO_ERROR;
-
-    // Convert from BCP47 to ICU format.
-    // de-DE-u-co-phonebk -> de_DE@collation=phonebook
-    char icu_locale[ULOC_FULLNAME_CAPACITY];
-    int icu_locale_length = 0;
-    uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY,
-                        &icu_locale_length, &error);
-    if (U_FAILURE(error) || icu_locale_length == 0) {
-      return isolate->Throw(*factory->illegal_argument_string());
-    }
-
-    // Maximize the locale.
-    // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook
-    char icu_max_locale[ULOC_FULLNAME_CAPACITY];
-    uloc_addLikelySubtags(
-        icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error);
-
-    // Remove extensions from maximized locale.
-    // de_Latn_DE@collation=phonebook -> de_Latn_DE
-    char icu_base_max_locale[ULOC_FULLNAME_CAPACITY];
-    uloc_getBaseName(
-        icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error);
-
-    // Get original name without extensions.
-    // de_DE@collation=phonebook -> de_DE
-    char icu_base_locale[ULOC_FULLNAME_CAPACITY];
-    uloc_getBaseName(
-        icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error);
-
-    // Convert from ICU locale format to BCP47 format.
-    // de_Latn_DE -> de-Latn-DE
-    char base_max_locale[ULOC_FULLNAME_CAPACITY];
-    uloc_toLanguageTag(icu_base_max_locale, base_max_locale,
-                       ULOC_FULLNAME_CAPACITY, FALSE, &error);
-
-    // de_DE -> de-DE
-    char base_locale[ULOC_FULLNAME_CAPACITY];
-    uloc_toLanguageTag(
-        icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error);
-
-    if (U_FAILURE(error)) {
-      return isolate->Throw(*factory->illegal_argument_string());
-    }
-
-    Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
-    Handle<String> value = factory->NewStringFromAsciiChecked(base_max_locale);
-    JSObject::AddProperty(result, maximized, value, NONE);
-    value = factory->NewStringFromAsciiChecked(base_locale);
-    JSObject::AddProperty(result, base, value, NONE);
-    output->set(i, *result);
-  }
-
-  Handle<JSArray> result = factory->NewJSArrayWithElements(output);
-  result->set_length(Smi::FromInt(length));
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsInitializedIntlObject) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
-
-  if (!input->IsJSObject()) return isolate->heap()->false_value();
-  Handle<JSObject> obj = Handle<JSObject>::cast(input);
-
-  Handle<String> marker = isolate->factory()->intl_initialized_marker_string();
-  Handle<Object> tag(obj->GetHiddenProperty(marker), isolate);
-  return isolate->heap()->ToBoolean(!tag->IsTheHole());
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsInitializedIntlObjectOfType) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, expected_type, 1);
-
-  if (!input->IsJSObject()) return isolate->heap()->false_value();
-  Handle<JSObject> obj = Handle<JSObject>::cast(input);
-
-  Handle<String> marker = isolate->factory()->intl_initialized_marker_string();
-  Handle<Object> tag(obj->GetHiddenProperty(marker), isolate);
-  return isolate->heap()->ToBoolean(
-      tag->IsString() && String::cast(*tag)->Equals(*expected_type));
-}
-
-
-RUNTIME_FUNCTION(Runtime_MarkAsInitializedIntlObjectOfType) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, impl, 2);
-
-  Handle<String> marker = isolate->factory()->intl_initialized_marker_string();
-  JSObject::SetHiddenProperty(input, marker, type);
-
-  marker = isolate->factory()->intl_impl_object_string();
-  JSObject::SetHiddenProperty(input, marker, impl);
-
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetImplFromInitializedIntlObject) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
-
-  if (!input->IsJSObject()) {
-    Vector< Handle<Object> > arguments = HandleVector(&input, 1);
-    THROW_NEW_ERROR_RETURN_FAILURE(isolate,
-                                   NewTypeError("not_intl_object", arguments));
-  }
-
-  Handle<JSObject> obj = Handle<JSObject>::cast(input);
-
-  Handle<String> marker = isolate->factory()->intl_impl_object_string();
-  Handle<Object> impl(obj->GetHiddenProperty(marker), isolate);
-  if (impl->IsTheHole()) {
-    Vector< Handle<Object> > arguments = HandleVector(&obj, 1);
-    THROW_NEW_ERROR_RETURN_FAILURE(isolate,
-                                   NewTypeError("not_intl_object", arguments));
-  }
-  return *impl;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreateDateTimeFormat) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
-
-  Handle<ObjectTemplateInfo> date_format_template =
-      I18N::GetTemplate(isolate);
-
-  // Create an empty object wrapper.
-  Handle<JSObject> local_object;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, local_object,
-      Execution::InstantiateObject(date_format_template));
-
-  // Set date time formatter as internal field of the resulting JS object.
-  icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat(
-      isolate, locale, options, resolved);
-
-  if (!date_format) return isolate->ThrowIllegalOperation();
-
-  local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format));
-
-  Factory* factory = isolate->factory();
-  Handle<String> key = factory->NewStringFromStaticChars("dateFormat");
-  Handle<String> value = factory->NewStringFromStaticChars("valid");
-  JSObject::AddProperty(local_object, key, value, NONE);
-
-  // Make object handle weak so we can delete the data format once GC kicks in.
-  Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
-  GlobalHandles::MakeWeak(wrapper.location(),
-                          reinterpret_cast<void*>(wrapper.location()),
-                          DateFormat::DeleteDateFormat);
-  return *local_object;
-}
-
-
-RUNTIME_FUNCTION(Runtime_InternalDateFormat) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1);
-
-  Handle<Object> value;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, value, Execution::ToNumber(isolate, date));
-
-  icu::SimpleDateFormat* date_format =
-      DateFormat::UnpackDateFormat(isolate, date_format_holder);
-  if (!date_format) return isolate->ThrowIllegalOperation();
-
-  icu::UnicodeString result;
-  date_format->format(value->Number(), result);
-
-  Handle<String> result_str;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result_str,
-      isolate->factory()->NewStringFromTwoByte(
-          Vector<const uint16_t>(
-              reinterpret_cast<const uint16_t*>(result.getBuffer()),
-              result.length())));
-  return *result_str;
-}
-
-
-RUNTIME_FUNCTION(Runtime_InternalDateParse) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1);
-
-  v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string));
-  icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date));
-  icu::SimpleDateFormat* date_format =
-      DateFormat::UnpackDateFormat(isolate, date_format_holder);
-  if (!date_format) return isolate->ThrowIllegalOperation();
-
-  UErrorCode status = U_ZERO_ERROR;
-  UDate date = date_format->parse(u_date, status);
-  if (U_FAILURE(status)) return isolate->heap()->undefined_value();
-
-  Handle<Object> result;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      Execution::NewDate(isolate, static_cast<double>(date)));
-  DCHECK(result->IsJSDate());
-  return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreateNumberFormat) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
-
-  Handle<ObjectTemplateInfo> number_format_template =
-      I18N::GetTemplate(isolate);
-
-  // Create an empty object wrapper.
-  Handle<JSObject> local_object;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, local_object,
-      Execution::InstantiateObject(number_format_template));
-
-  // Set number formatter as internal field of the resulting JS object.
-  icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat(
-      isolate, locale, options, resolved);
-
-  if (!number_format) return isolate->ThrowIllegalOperation();
-
-  local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format));
-
-  Factory* factory = isolate->factory();
-  Handle<String> key = factory->NewStringFromStaticChars("numberFormat");
-  Handle<String> value = factory->NewStringFromStaticChars("valid");
-  JSObject::AddProperty(local_object, key, value, NONE);
-
-  Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
-  GlobalHandles::MakeWeak(wrapper.location(),
-                          reinterpret_cast<void*>(wrapper.location()),
-                          NumberFormat::DeleteNumberFormat);
-  return *local_object;
-}
-
-
-RUNTIME_FUNCTION(Runtime_InternalNumberFormat) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, number, 1);
-
-  Handle<Object> value;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, value, Execution::ToNumber(isolate, number));
-
-  icu::DecimalFormat* number_format =
-      NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
-  if (!number_format) return isolate->ThrowIllegalOperation();
-
-  icu::UnicodeString result;
-  number_format->format(value->Number(), result);
-
-  Handle<String> result_str;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result_str,
-      isolate->factory()->NewStringFromTwoByte(
-          Vector<const uint16_t>(
-              reinterpret_cast<const uint16_t*>(result.getBuffer()),
-              result.length())));
-  return *result_str;
-}
-
-
-RUNTIME_FUNCTION(Runtime_InternalNumberParse) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1);
-
-  v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string));
-  icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number));
-  icu::DecimalFormat* number_format =
-      NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
-  if (!number_format) return isolate->ThrowIllegalOperation();
-
-  UErrorCode status = U_ZERO_ERROR;
-  icu::Formattable result;
-  // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49
-  // to be part of Chrome.
-  // TODO(cira): Include currency parsing code using parseCurrency call.
-  // We need to check if the formatter parses all currencies or only the
-  // one it was constructed with (it will impact the API - how to return ISO
-  // code and the value).
-  number_format->parse(u_number, result, status);
-  if (U_FAILURE(status)) return isolate->heap()->undefined_value();
-
-  switch (result.getType()) {
-  case icu::Formattable::kDouble:
-    return *isolate->factory()->NewNumber(result.getDouble());
-  case icu::Formattable::kLong:
-    return *isolate->factory()->NewNumberFromInt(result.getLong());
-  case icu::Formattable::kInt64:
-    return *isolate->factory()->NewNumber(
-        static_cast<double>(result.getInt64()));
-  default:
-    return isolate->heap()->undefined_value();
-  }
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreateCollator) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
-
-  Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate);
-
-  // Create an empty object wrapper.
-  Handle<JSObject> local_object;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, local_object, Execution::InstantiateObject(collator_template));
-
-  // Set collator as internal field of the resulting JS object.
-  icu::Collator* collator = Collator::InitializeCollator(
-      isolate, locale, options, resolved);
-
-  if (!collator) return isolate->ThrowIllegalOperation();
-
-  local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator));
-
-  Factory* factory = isolate->factory();
-  Handle<String> key = factory->NewStringFromStaticChars("collator");
-  Handle<String> value = factory->NewStringFromStaticChars("valid");
-  JSObject::AddProperty(local_object, key, value, NONE);
-
-  Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
-  GlobalHandles::MakeWeak(wrapper.location(),
-                          reinterpret_cast<void*>(wrapper.location()),
-                          Collator::DeleteCollator);
-  return *local_object;
-}
-
-
-RUNTIME_FUNCTION(Runtime_InternalCompare) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, string1, 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, string2, 2);
-
-  icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder);
-  if (!collator) return isolate->ThrowIllegalOperation();
-
-  v8::String::Value string_value1(v8::Utils::ToLocal(string1));
-  v8::String::Value string_value2(v8::Utils::ToLocal(string2));
-  const UChar* u_string1 = reinterpret_cast<const UChar*>(*string_value1);
-  const UChar* u_string2 = reinterpret_cast<const UChar*>(*string_value2);
-  UErrorCode status = U_ZERO_ERROR;
-  UCollationResult result = collator->compare(u_string1,
-                                              string_value1.length(),
-                                              u_string2,
-                                              string_value2.length(),
-                                              status);
-  if (U_FAILURE(status)) return isolate->ThrowIllegalOperation();
-
-  return *isolate->factory()->NewNumberFromInt(result);
-}
-
-
-RUNTIME_FUNCTION(Runtime_StringNormalize) {
-  HandleScope scope(isolate);
-  static const UNormalizationMode normalizationForms[] =
-      { UNORM_NFC, UNORM_NFD, UNORM_NFKC, UNORM_NFKD };
-
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, stringValue, 0);
-  CONVERT_NUMBER_CHECKED(int, form_id, Int32, args[1]);
-  RUNTIME_ASSERT(form_id >= 0 &&
-                 static_cast<size_t>(form_id) < arraysize(normalizationForms));
-
-  v8::String::Value string_value(v8::Utils::ToLocal(stringValue));
-  const UChar* u_value = reinterpret_cast<const UChar*>(*string_value);
-
-  // TODO(mnita): check Normalizer2 (not available in ICU 46)
-  UErrorCode status = U_ZERO_ERROR;
-  icu::UnicodeString result;
-  icu::Normalizer::normalize(u_value, normalizationForms[form_id], 0,
-      result, status);
-  if (U_FAILURE(status)) {
-    return isolate->heap()->undefined_value();
-  }
-
-  Handle<String> result_str;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result_str,
-      isolate->factory()->NewStringFromTwoByte(
-          Vector<const uint16_t>(
-              reinterpret_cast<const uint16_t*>(result.getBuffer()),
-              result.length())));
-  return *result_str;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CreateBreakIterator) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 3);
-
-  CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
-
-  Handle<ObjectTemplateInfo> break_iterator_template =
-      I18N::GetTemplate2(isolate);
-
-  // Create an empty object wrapper.
-  Handle<JSObject> local_object;
-  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, local_object,
-      Execution::InstantiateObject(break_iterator_template));
-
-  // Set break iterator as internal field of the resulting JS object.
-  icu::BreakIterator* break_iterator = BreakIterator::InitializeBreakIterator(
-      isolate, locale, options, resolved);
-
-  if (!break_iterator) return isolate->ThrowIllegalOperation();
-
-  local_object->SetInternalField(0, reinterpret_cast<Smi*>(break_iterator));
-  // Make sure that the pointer to adopted text is NULL.
-  local_object->SetInternalField(1, reinterpret_cast<Smi*>(NULL));
-
-  Factory* factory = isolate->factory();
-  Handle<String> key = factory->NewStringFromStaticChars("breakIterator");
-  Handle<String> value = factory->NewStringFromStaticChars("valid");
-  JSObject::AddProperty(local_object, key, value, NONE);
-
-  // Make object handle weak so we can delete the break iterator once GC kicks
-  // in.
-  Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
-  GlobalHandles::MakeWeak(wrapper.location(),
-                          reinterpret_cast<void*>(wrapper.location()),
-                          BreakIterator::DeleteBreakIterator);
-  return *local_object;
-}
-
-
-RUNTIME_FUNCTION(Runtime_BreakIteratorAdoptText) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 2);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, text, 1);
-
-  icu::BreakIterator* break_iterator =
-      BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
-  if (!break_iterator) return isolate->ThrowIllegalOperation();
-
-  icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>(
-      break_iterator_holder->GetInternalField(1));
-  delete u_text;
-
-  v8::String::Value text_value(v8::Utils::ToLocal(text));
-  u_text = new icu::UnicodeString(
-      reinterpret_cast<const UChar*>(*text_value), text_value.length());
-  break_iterator_holder->SetInternalField(1, reinterpret_cast<Smi*>(u_text));
-
-  break_iterator->setText(*u_text);
-
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_BreakIteratorFirst) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
-
-  icu::BreakIterator* break_iterator =
-      BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
-  if (!break_iterator) return isolate->ThrowIllegalOperation();
-
-  return *isolate->factory()->NewNumberFromInt(break_iterator->first());
-}
-
-
-RUNTIME_FUNCTION(Runtime_BreakIteratorNext) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
-
-  icu::BreakIterator* break_iterator =
-      BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
-  if (!break_iterator) return isolate->ThrowIllegalOperation();
-
-  return *isolate->factory()->NewNumberFromInt(break_iterator->next());
-}
-
-
-RUNTIME_FUNCTION(Runtime_BreakIteratorCurrent) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
-
-  icu::BreakIterator* break_iterator =
-      BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
-  if (!break_iterator) return isolate->ThrowIllegalOperation();
-
-  return *isolate->factory()->NewNumberFromInt(break_iterator->current());
-}
-
-
-RUNTIME_FUNCTION(Runtime_BreakIteratorBreakType) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
-
-  icu::BreakIterator* break_iterator =
-      BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
-  if (!break_iterator) return isolate->ThrowIllegalOperation();
-
-  // TODO(cira): Remove cast once ICU fixes base BreakIterator class.
-  icu::RuleBasedBreakIterator* rule_based_iterator =
-      static_cast<icu::RuleBasedBreakIterator*>(break_iterator);
-  int32_t status = rule_based_iterator->getRuleStatus();
-  // Keep return values in sync with JavaScript BreakType enum.
-  if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
-    return *isolate->factory()->NewStringFromStaticChars("none");
-  } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
-    return *isolate->factory()->number_string();
-  } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
-    return *isolate->factory()->NewStringFromStaticChars("letter");
-  } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
-    return *isolate->factory()->NewStringFromStaticChars("kana");
-  } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
-    return *isolate->factory()->NewStringFromStaticChars("ideo");
-  } else {
-    return *isolate->factory()->NewStringFromStaticChars("unknown");
-  }
-}
-#endif  // V8_I18N_SUPPORT
-
-
-// Finds the script object from the script data. NOTE: This operation uses
-// heap traversal to find the function generated for the source position
-// for the requested break point. For lazily compiled functions several heap
-// traversals might be required rendering this operation as a rather slow
-// operation. However for setting break points which is normally done through
-// some kind of user interaction the performance is not crucial.
-static Handle<Object> Runtime_GetScriptFromScriptName(
-    Handle<String> script_name) {
-  // Scan the heap for Script objects to find the script with the requested
-  // script data.
-  Handle<Script> script;
-  Factory* factory = script_name->GetIsolate()->factory();
-  Heap* heap = script_name->GetHeap();
-  HeapIterator iterator(heap);
-  HeapObject* obj = NULL;
-  while (script.is_null() && ((obj = iterator.next()) != NULL)) {
-    // If a script is found check if it has the script data requested.
-    if (obj->IsScript()) {
-      if (Script::cast(obj)->name()->IsString()) {
-        if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
-          script = Handle<Script>(Script::cast(obj));
-        }
-      }
-    }
-  }
-
-  // If no script with the requested script data is found return undefined.
-  if (script.is_null()) return factory->undefined_value();
-
-  // Return the script found.
-  return Script::GetWrapper(script);
-}
-
-
-// Get the script object from script data. NOTE: Regarding performance
-// see the NOTE for GetScriptFromScriptData.
-// args[0]: script data for the script to find the source for
-RUNTIME_FUNCTION(Runtime_GetScript) {
-  HandleScope scope(isolate);
-
-  DCHECK(args.length() == 1);
-
-  CONVERT_ARG_CHECKED(String, script_name, 0);
-
-  // Find the requested script.
-  Handle<Object> result =
-      Runtime_GetScriptFromScriptName(Handle<String>(script_name));
-  return *result;
-}
-
-
-// Collect the raw data for a stack trace.  Returns an array of 4
-// element segments each containing a receiver, function, code and
-// native code offset.
-RUNTIME_FUNCTION(Runtime_CollectStackTrace) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Object, caller, 1);
-
-  if (!isolate->bootstrapper()->IsActive()) {
-    // Optionally capture a more detailed stack trace for the message.
-    isolate->CaptureAndSetDetailedStackTrace(error_object);
-    // Capture a simple stack trace for the stack property.
-    isolate->CaptureAndSetSimpleStackTrace(error_object, caller);
-  }
-  return isolate->heap()->undefined_value();
-}
-
-
-// Returns V8 version as a string.
-RUNTIME_FUNCTION(Runtime_GetV8Version) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-
-  const char* version_string = v8::V8::GetVersion();
-
-  return *isolate->factory()->NewStringFromAsciiChecked(version_string);
-}
-
-
-// Returns function of generator activation.
-RUNTIME_FUNCTION(Runtime_GeneratorGetFunction) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
-
-  return generator->function();
-}
-
-
-// Returns context of generator activation.
-RUNTIME_FUNCTION(Runtime_GeneratorGetContext) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
-
-  return generator->context();
-}
-
-
-// Returns receiver of generator activation.
-RUNTIME_FUNCTION(Runtime_GeneratorGetReceiver) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
-
-  return generator->receiver();
-}
-
-
-// Returns generator continuation as a PC offset, or the magic -1 or 0 values.
-RUNTIME_FUNCTION(Runtime_GeneratorGetContinuation) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
-
-  return Smi::FromInt(generator->continuation());
-}
-
-
-RUNTIME_FUNCTION(Runtime_GeneratorGetSourcePosition) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
-
-  if (generator->is_suspended()) {
-    Handle<Code> code(generator->function()->code(), isolate);
-    int offset = generator->continuation();
-
-    RUNTIME_ASSERT(0 <= offset && offset < code->Size());
-    Address pc = code->address() + offset;
-
-    return Smi::FromInt(code->SourcePosition(pc));
-  }
-
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_Abort) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_SMI_ARG_CHECKED(message_id, 0);
-  const char* message = GetBailoutReason(
-      static_cast<BailoutReason>(message_id));
-  base::OS::PrintError("abort: %s\n", message);
-  isolate->PrintStack(stderr);
-  base::OS::Abort();
-  UNREACHABLE();
-  return NULL;
-}
-
-
-RUNTIME_FUNCTION(Runtime_AbortJS) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
-  base::OS::PrintError("abort: %s\n", message->ToCString().get());
-  isolate->PrintStack(stderr);
-  base::OS::Abort();
-  UNREACHABLE();
-  return NULL;
-}
-
-
-RUNTIME_FUNCTION(Runtime_FlattenString) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
-  return *String::Flatten(str);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-  isolate->heap()->NotifyContextDisposed();
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_LoadMutableDouble) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-  CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1);
-  RUNTIME_ASSERT((index->value() & 1) == 1);
-  FieldIndex field_index =
-      FieldIndex::ForLoadByFieldIndex(object->map(), index->value());
-  if (field_index.is_inobject()) {
-    RUNTIME_ASSERT(field_index.property_index() <
-                   object->map()->inobject_properties());
-  } else {
-    RUNTIME_ASSERT(field_index.outobject_array_index() <
-                   object->properties()->length());
-  }
-  Handle<Object> raw_value(object->RawFastPropertyAt(field_index), isolate);
-  RUNTIME_ASSERT(raw_value->IsMutableHeapNumber());
-  return *Object::WrapForRead(isolate, raw_value, Representation::Double());
-}
-
-
-RUNTIME_FUNCTION(Runtime_TryMigrateInstance) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
-  if (!object->IsJSObject()) return Smi::FromInt(0);
-  Handle<JSObject> js_object = Handle<JSObject>::cast(object);
-  if (!js_object->map()->is_deprecated()) return Smi::FromInt(0);
-  // This call must not cause lazy deopts, because it's called from deferred
-  // code where we can't handle lazy deopts for lack of a suitable bailout
-  // ID. So we just try migration and signal failure if necessary,
-  // which will also trigger a deopt.
-  if (!JSObject::TryMigrateInstance(js_object)) return Smi::FromInt(0);
-  return *object;
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetFromCache) {
-  SealHandleScope shs(isolate);
-  // This is only called from codegen, so checks might be more lax.
-  CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
-  CONVERT_ARG_CHECKED(Object, key, 1);
-
-  {
-    DisallowHeapAllocation no_alloc;
-
-    int finger_index = cache->finger_index();
-    Object* o = cache->get(finger_index);
-    if (o == key) {
-      // The fastest case: hit the same place again.
-      return cache->get(finger_index + 1);
-    }
-
-    for (int i = finger_index - 2;
-         i >= JSFunctionResultCache::kEntriesIndex;
-         i -= 2) {
-      o = cache->get(i);
-      if (o == key) {
-        cache->set_finger_index(i);
-        return cache->get(i + 1);
-      }
-    }
-
-    int size = cache->size();
-    DCHECK(size <= cache->length());
-
-    for (int i = size - 2; i > finger_index; i -= 2) {
-      o = cache->get(i);
-      if (o == key) {
-        cache->set_finger_index(i);
-        return cache->get(i + 1);
-      }
-    }
-  }
-
-  // There is no value in the cache.  Invoke the function and cache result.
-  HandleScope scope(isolate);
-
-  Handle<JSFunctionResultCache> cache_handle(cache);
-  Handle<Object> key_handle(key, isolate);
-  Handle<Object> value;
-  {
-    Handle<JSFunction> factory(JSFunction::cast(
-          cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
-    // TODO(antonm): consider passing a receiver when constructing a cache.
-    Handle<JSObject> receiver(isolate->global_proxy());
-    // This handle is nor shared, nor used later, so it's safe.
-    Handle<Object> argv[] = { key_handle };
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-        isolate, value,
-        Execution::Call(isolate, factory, receiver, arraysize(argv), argv));
-  }
-
-#ifdef VERIFY_HEAP
-  if (FLAG_verify_heap) {
-    cache_handle->JSFunctionResultCacheVerify();
-  }
-#endif
-
-  // Function invocation may have cleared the cache.  Reread all the data.
-  int finger_index = cache_handle->finger_index();
-  int size = cache_handle->size();
-
-  // If we have spare room, put new data into it, otherwise evict post finger
-  // entry which is likely to be the least recently used.
-  int index = -1;
-  if (size < cache_handle->length()) {
-    cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
-    index = size;
-  } else {
-    index = finger_index + JSFunctionResultCache::kEntrySize;
-    if (index == cache_handle->length()) {
-      index = JSFunctionResultCache::kEntriesIndex;
-    }
-  }
-
-  DCHECK(index % 2 == 0);
-  DCHECK(index >= JSFunctionResultCache::kEntriesIndex);
-  DCHECK(index < cache_handle->length());
-
-  cache_handle->set(index, *key_handle);
-  cache_handle->set(index + 1, *value);
-  cache_handle->set_finger_index(index);
-
-#ifdef VERIFY_HEAP
-  if (FLAG_verify_heap) {
-    cache_handle->JSFunctionResultCacheVerify();
-  }
-#endif
-
-  return *value;
-}
-
-
-RUNTIME_FUNCTION(Runtime_MessageGetStartPosition) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
-  return Smi::FromInt(message->start_position());
-}
-
-
-RUNTIME_FUNCTION(Runtime_MessageGetScript) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
-  return message->script();
-}
-
-
-#ifdef DEBUG
-// ListNatives is ONLY used by the fuzz-natives.js in debug mode
-// Exclude the code in release mode.
-RUNTIME_FUNCTION(Runtime_ListNatives) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-#define COUNT_ENTRY(Name, argc, ressize) + 1
-  int entry_count = 0
-      RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
-      INLINE_FUNCTION_LIST(COUNT_ENTRY)
-      INLINE_OPTIMIZED_FUNCTION_LIST(COUNT_ENTRY);
-#undef COUNT_ENTRY
-  Factory* factory = isolate->factory();
-  Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
-  int index = 0;
-  bool inline_runtime_functions = false;
-#define ADD_ENTRY(Name, argc, ressize)                                      \
-  {                                                                         \
-    HandleScope inner(isolate);                                             \
-    Handle<String> name;                                                    \
-    /* Inline runtime functions have an underscore in front of the name. */ \
-    if (inline_runtime_functions) {                                         \
-      name = factory->NewStringFromStaticChars("_" #Name);                  \
-    } else {                                                                \
-      name = factory->NewStringFromStaticChars(#Name);                      \
-    }                                                                       \
-    Handle<FixedArray> pair_elements = factory->NewFixedArray(2);           \
-    pair_elements->set(0, *name);                                           \
-    pair_elements->set(1, Smi::FromInt(argc));                              \
-    Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements);  \
-    elements->set(index++, *pair);                                          \
-  }
-  inline_runtime_functions = false;
-  RUNTIME_FUNCTION_LIST(ADD_ENTRY)
-  INLINE_OPTIMIZED_FUNCTION_LIST(ADD_ENTRY)
-  inline_runtime_functions = true;
-  INLINE_FUNCTION_LIST(ADD_ENTRY)
-#undef ADD_ENTRY
-  DCHECK_EQ(index, entry_count);
-  Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
-  return *result;
-}
-#endif
-
-
-RUNTIME_FUNCTION(Runtime_IS_VAR) {
-  UNREACHABLE();  // implemented as macro in the parser
-  return NULL;
-}
-
-
-#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name)        \
-  RUNTIME_FUNCTION(Runtime_Has##Name) {          \
-    CONVERT_ARG_CHECKED(JSObject, obj, 0);                \
-    return isolate->heap()->ToBoolean(obj->Has##Name());  \
-  }
-
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements)
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
-// Properties test sitting with elements tests - not fooling anyone.
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
-
-#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
-
-
-#define TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, size)     \
-  RUNTIME_FUNCTION(Runtime_HasExternal##Type##Elements) {             \
-    CONVERT_ARG_CHECKED(JSObject, obj, 0);                                     \
-    return isolate->heap()->ToBoolean(obj->HasExternal##Type##Elements());     \
-  }
-
-TYPED_ARRAYS(TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
-
-#undef TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
-
-
-#define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s)  \
-  RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) {                \
-    CONVERT_ARG_CHECKED(JSObject, obj, 0);                                     \
-    return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements());        \
-  }
-
-TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
-
-#undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
-
-
-RUNTIME_FUNCTION(Runtime_HaveSameMap) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_CHECKED(JSObject, obj1, 0);
-  CONVERT_ARG_CHECKED(JSObject, obj2, 1);
-  return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy());
-}
-
-
-RUNTIME_FUNCTION(Runtime_IsObserved) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-
-  if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value();
-  CONVERT_ARG_CHECKED(JSReceiver, obj, 0);
-  DCHECK(!obj->IsJSGlobalProxy() || !obj->map()->is_observed());
-  return isolate->heap()->ToBoolean(obj->map()->is_observed());
-}
-
-
-RUNTIME_FUNCTION(Runtime_SetIsObserved) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
-  RUNTIME_ASSERT(!obj->IsJSGlobalProxy());
-  if (obj->IsJSProxy()) return isolate->heap()->undefined_value();
-  RUNTIME_ASSERT(!obj->map()->is_observed());
-
-  DCHECK(obj->IsJSObject());
-  JSObject::SetObserved(Handle<JSObject>::cast(obj));
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_EnqueueMicrotask) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, microtask, 0);
-  isolate->EnqueueMicrotask(microtask);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_RunMicrotasks) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-  isolate->RunMicrotasks();
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetObservationState) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  return isolate->heap()->observation_state();
-}
-
-
-RUNTIME_FUNCTION(Runtime_ObservationWeakMapCreate) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 0);
-  // TODO(adamk): Currently this runtime function is only called three times per
-  // isolate. If it's called more often, the map should be moved into the
-  // strong root list.
-  Handle<Map> map =
-      isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize);
-  Handle<JSWeakMap> weakmap =
-      Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map));
-  return *WeakCollectionInitialize(isolate, weakmap);
-}
-
-
-static bool ContextsHaveSameOrigin(Handle<Context> context1,
-                                   Handle<Context> context2) {
-  return context1->security_token() == context2->security_token();
-}
-
-
-RUNTIME_FUNCTION(Runtime_ObserverObjectAndRecordHaveSameOrigin) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, record, 2);
-
-  Handle<Context> observer_context(observer->context()->native_context());
-  Handle<Context> object_context(object->GetCreationContext());
-  Handle<Context> record_context(record->GetCreationContext());
-
-  return isolate->heap()->ToBoolean(
-      ContextsHaveSameOrigin(object_context, observer_context) &&
-      ContextsHaveSameOrigin(object_context, record_context));
-}
-
-
-RUNTIME_FUNCTION(Runtime_ObjectWasCreatedInCurrentOrigin) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-
-  Handle<Context> creation_context(object->GetCreationContext(), isolate);
-  return isolate->heap()->ToBoolean(
-      ContextsHaveSameOrigin(creation_context, isolate->native_context()));
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetObjectContextObjectObserve) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-
-  Handle<Context> context(object->GetCreationContext(), isolate);
-  return context->native_object_observe();
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetObjectContextObjectGetNotifier) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
-
-  Handle<Context> context(object->GetCreationContext(), isolate);
-  return context->native_object_get_notifier();
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetObjectContextNotifierPerformChange) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, object_info, 0);
-
-  Handle<Context> context(object_info->GetCreationContext(), isolate);
-  return context->native_object_notifier_perform_change();
-}
-
-
-static Object* ArrayConstructorCommon(Isolate* isolate,
-                                           Handle<JSFunction> constructor,
-                                           Handle<AllocationSite> site,
-                                           Arguments* caller_args) {
-  Factory* factory = isolate->factory();
-
-  bool holey = false;
-  bool can_use_type_feedback = true;
-  if (caller_args->length() == 1) {
-    Handle<Object> argument_one = caller_args->at<Object>(0);
-    if (argument_one->IsSmi()) {
-      int value = Handle<Smi>::cast(argument_one)->value();
-      if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) {
-        // the array is a dictionary in this case.
-        can_use_type_feedback = false;
-      } else if (value != 0) {
-        holey = true;
-      }
-    } else {
-      // Non-smi length argument produces a dictionary
-      can_use_type_feedback = false;
-    }
-  }
-
-  Handle<JSArray> array;
-  if (!site.is_null() && can_use_type_feedback) {
-    ElementsKind to_kind = site->GetElementsKind();
-    if (holey && !IsFastHoleyElementsKind(to_kind)) {
-      to_kind = GetHoleyElementsKind(to_kind);
-      // Update the allocation site info to reflect the advice alteration.
-      site->SetElementsKind(to_kind);
-    }
-
-    // We should allocate with an initial map that reflects the allocation site
-    // advice. Therefore we use AllocateJSObjectFromMap instead of passing
-    // the constructor.
-    Handle<Map> initial_map(constructor->initial_map(), isolate);
-    if (to_kind != initial_map->elements_kind()) {
-      initial_map = Map::AsElementsKind(initial_map, to_kind);
-    }
-
-    // If we don't care to track arrays of to_kind ElementsKind, then
-    // don't emit a memento for them.
-    Handle<AllocationSite> allocation_site;
-    if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) {
-      allocation_site = site;
-    }
-
-    array = Handle<JSArray>::cast(factory->NewJSObjectFromMap(
-        initial_map, NOT_TENURED, true, allocation_site));
-  } else {
-    array = Handle<JSArray>::cast(factory->NewJSObject(constructor));
-
-    // We might need to transition to holey
-    ElementsKind kind = constructor->initial_map()->elements_kind();
-    if (holey && !IsFastHoleyElementsKind(kind)) {
-      kind = GetHoleyElementsKind(kind);
-      JSObject::TransitionElementsKind(array, kind);
-    }
-  }
-
-  factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS);
-
-  ElementsKind old_kind = array->GetElementsKind();
-  RETURN_FAILURE_ON_EXCEPTION(
-      isolate, ArrayConstructInitializeElements(array, caller_args));
-  if (!site.is_null() &&
-      (old_kind != array->GetElementsKind() ||
-       !can_use_type_feedback)) {
-    // The arguments passed in caused a transition. This kind of complexity
-    // can't be dealt with in the inlined hydrogen array constructor case.
-    // We must mark the allocationsite as un-inlinable.
-    site->SetDoNotInlineCall();
-  }
-  return *array;
-}
-
-
-RUNTIME_FUNCTION(Runtime_ArrayConstructor) {
-  HandleScope scope(isolate);
-  // If we get 2 arguments then they are the stub parameters (constructor, type
-  // info).  If we get 4, then the first one is a pointer to the arguments
-  // passed by the caller, and the last one is the length of the arguments
-  // passed to the caller (redundant, but useful to check on the deoptimizer
-  // with an assert).
-  Arguments empty_args(0, NULL);
-  bool no_caller_args = args.length() == 2;
-  DCHECK(no_caller_args || args.length() == 4);
-  int parameters_start = no_caller_args ? 0 : 1;
-  Arguments* caller_args = no_caller_args
-      ? &empty_args
-      : reinterpret_cast<Arguments*>(args[0]);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
-  CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1);
-#ifdef DEBUG
-  if (!no_caller_args) {
-    CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 2);
-    DCHECK(arg_count == caller_args->length());
-  }
-#endif
-
-  Handle<AllocationSite> site;
-  if (!type_info.is_null() &&
-      *type_info != isolate->heap()->undefined_value()) {
-    site = Handle<AllocationSite>::cast(type_info);
-    DCHECK(!site->SitePointsToLiteral());
-  }
-
-  return ArrayConstructorCommon(isolate,
-                                constructor,
-                                site,
-                                caller_args);
-}
-
-
-RUNTIME_FUNCTION(Runtime_InternalArrayConstructor) {
-  HandleScope scope(isolate);
-  Arguments empty_args(0, NULL);
-  bool no_caller_args = args.length() == 1;
-  DCHECK(no_caller_args || args.length() == 3);
-  int parameters_start = no_caller_args ? 0 : 1;
-  Arguments* caller_args = no_caller_args
-      ? &empty_args
-      : reinterpret_cast<Arguments*>(args[0]);
-  CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
-#ifdef DEBUG
-  if (!no_caller_args) {
-    CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 1);
-    DCHECK(arg_count == caller_args->length());
-  }
-#endif
-  return ArrayConstructorCommon(isolate,
-                                constructor,
-                                Handle<AllocationSite>::null(),
-                                caller_args);
-}
-
-
-RUNTIME_FUNCTION(Runtime_NormalizeElements) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
-  RUNTIME_ASSERT(!array->HasExternalArrayElements() &&
-                 !array->HasFixedTypedArrayElements());
-  JSObject::NormalizeElements(array);
-  return *array;
-}
-
-
-RUNTIME_FUNCTION(Runtime_MaxSmi) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  return Smi::FromInt(Smi::kMaxValue);
-}
-
-
-// TODO(dcarney): remove this function when TurboFan supports it.
-// Takes the object to be iterated over and the result of GetPropertyNamesFast
-// Returns pair (cache_array, cache_type).
-RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ForInInit) {
-  SealHandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  // This simulates CONVERT_ARG_HANDLE_CHECKED for calls returning pairs.
-  // Not worth creating a macro atm as this function should be removed.
-  if (!args[0]->IsJSReceiver() || !args[1]->IsObject()) {
-    Object* error = isolate->ThrowIllegalOperation();
-    return MakePair(error, isolate->heap()->undefined_value());
-  }
-  Handle<JSReceiver> object = args.at<JSReceiver>(0);
-  Handle<Object> cache_type = args.at<Object>(1);
-  if (cache_type->IsMap()) {
-    // Enum cache case.
-    if (Map::EnumLengthBits::decode(Map::cast(*cache_type)->bit_field3()) ==
-        0) {
-      // 0 length enum.
-      // Can't handle this case in the graph builder,
-      // so transform it into the empty fixed array case.
-      return MakePair(isolate->heap()->empty_fixed_array(), Smi::FromInt(1));
-    }
-    return MakePair(object->map()->instance_descriptors()->GetEnumCache(),
-                    *cache_type);
-  } else {
-    // FixedArray case.
-    Smi* new_cache_type = Smi::FromInt(object->IsJSProxy() ? 0 : 1);
-    return MakePair(*Handle<FixedArray>::cast(cache_type), new_cache_type);
-  }
-}
-
-
-// TODO(dcarney): remove this function when TurboFan supports it.
-RUNTIME_FUNCTION(Runtime_ForInCacheArrayLength) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(Object, cache_type, 0);
-  CONVERT_ARG_HANDLE_CHECKED(FixedArray, array, 1);
-  int length = 0;
-  if (cache_type->IsMap()) {
-    length = Map::cast(*cache_type)->EnumLength();
-  } else {
-    DCHECK(cache_type->IsSmi());
-    length = array->length();
-  }
-  return Smi::FromInt(length);
-}
-
-
-// TODO(dcarney): remove this function when TurboFan supports it.
-// Takes (the object to be iterated over,
-//        cache_array from ForInInit,
-//        cache_type from ForInInit,
-//        the current index)
-// Returns pair (array[index], needs_filtering).
-RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ForInNext) {
-  SealHandleScope scope(isolate);
-  DCHECK(args.length() == 4);
-  int32_t index;
-  // This simulates CONVERT_ARG_HANDLE_CHECKED for calls returning pairs.
-  // Not worth creating a macro atm as this function should be removed.
-  if (!args[0]->IsJSReceiver() || !args[1]->IsFixedArray() ||
-      !args[2]->IsObject() || !args[3]->ToInt32(&index)) {
-    Object* error = isolate->ThrowIllegalOperation();
-    return MakePair(error, isolate->heap()->undefined_value());
-  }
-  Handle<JSReceiver> object = args.at<JSReceiver>(0);
-  Handle<FixedArray> array = args.at<FixedArray>(1);
-  Handle<Object> cache_type = args.at<Object>(2);
-  // Figure out first if a slow check is needed for this object.
-  bool slow_check_needed = false;
-  if (cache_type->IsMap()) {
-    if (object->map() != Map::cast(*cache_type)) {
-      // Object transitioned.  Need slow check.
-      slow_check_needed = true;
-    }
-  } else {
-    // No slow check needed for proxies.
-    slow_check_needed = Smi::cast(*cache_type)->value() == 1;
-  }
-  return MakePair(array->get(index),
-                  isolate->heap()->ToBoolean(slow_check_needed));
-}
-
-
-// ----------------------------------------------------------------------------
-// Reference implementation for inlined runtime functions.  Only used when the
-// compiler does not support a certain intrinsic.  Don't optimize these, but
-// implement the intrinsic in the respective compiler instead.
-
-// TODO(mstarzinger): These are place-holder stubs for TurboFan and will
-// eventually all have a C++ implementation and this macro will be gone.
-#define U(name)                               \
-  RUNTIME_FUNCTION(RuntimeReference_##name) { \
-    UNIMPLEMENTED();                          \
-    return NULL;                              \
-  }
-
-U(IsStringWrapperSafeForDefaultValueOf)
-U(DebugBreakInOptimizedCode)
-
-#undef U
-
-
-RUNTIME_FUNCTION(RuntimeReference_IsSmi) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  return isolate->heap()->ToBoolean(obj->IsSmi());
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_IsNonNegativeSmi) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  return isolate->heap()->ToBoolean(obj->IsSmi() &&
-                                    Smi::cast(obj)->value() >= 0);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_IsArray) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  return isolate->heap()->ToBoolean(obj->IsJSArray());
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_IsRegExp) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  return isolate->heap()->ToBoolean(obj->IsJSRegExp());
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_IsConstructCall) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  JavaScriptFrameIterator it(isolate);
-  JavaScriptFrame* frame = it.frame();
-  return isolate->heap()->ToBoolean(frame->IsConstructor());
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_CallFunction) {
-  SealHandleScope shs(isolate);
-  return __RT_impl_Runtime_Call(args, isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_ArgumentsLength) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 0);
-  JavaScriptFrameIterator it(isolate);
-  JavaScriptFrame* frame = it.frame();
-  return Smi::FromInt(frame->GetArgumentsLength());
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_Arguments) {
-  SealHandleScope shs(isolate);
-  return __RT_impl_Runtime_GetArgumentsProperty(args, isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_ValueOf) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  if (!obj->IsJSValue()) return obj;
-  return JSValue::cast(obj)->value();
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_SetValueOf) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  CONVERT_ARG_CHECKED(Object, value, 1);
-  if (!obj->IsJSValue()) return value;
-  JSValue::cast(obj)->set_value(value);
-  return value;
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_DateField) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  CONVERT_SMI_ARG_CHECKED(index, 1);
-  if (!obj->IsJSDate()) {
-    HandleScope scope(isolate);
-    THROW_NEW_ERROR_RETURN_FAILURE(
-        isolate,
-        NewTypeError("not_date_object", HandleVector<Object>(NULL, 0)));
-  }
-  JSDate* date = JSDate::cast(obj);
-  if (index == 0) return date->value();
-  return JSDate::GetField(date, Smi::FromInt(index));
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_StringCharFromCode) {
-  SealHandleScope shs(isolate);
-  return __RT_impl_Runtime_CharFromCode(args, isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_StringCharAt) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  if (!args[0]->IsString()) return Smi::FromInt(0);
-  if (!args[1]->IsNumber()) return Smi::FromInt(0);
-  if (std::isinf(args.number_at(1))) return isolate->heap()->empty_string();
-  Object* code = __RT_impl_Runtime_StringCharCodeAtRT(args, isolate);
-  if (code->IsNaN()) return isolate->heap()->empty_string();
-  return __RT_impl_Runtime_CharFromCode(Arguments(1, &code), isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_OneByteSeqStringSetChar) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_INT32_ARG_CHECKED(index, 0);
-  CONVERT_INT32_ARG_CHECKED(value, 1);
-  CONVERT_ARG_CHECKED(SeqOneByteString, string, 2);
-  string->SeqOneByteStringSet(index, value);
-  return string;
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_TwoByteSeqStringSetChar) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 3);
-  CONVERT_INT32_ARG_CHECKED(index, 0);
-  CONVERT_INT32_ARG_CHECKED(value, 1);
-  CONVERT_ARG_CHECKED(SeqTwoByteString, string, 2);
-  string->SeqTwoByteStringSet(index, value);
-  return string;
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_ObjectEquals) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_ARG_CHECKED(Object, obj1, 0);
-  CONVERT_ARG_CHECKED(Object, obj2, 1);
-  return isolate->heap()->ToBoolean(obj1 == obj2);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_IsObject) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  if (!obj->IsHeapObject()) return isolate->heap()->false_value();
-  if (obj->IsNull()) return isolate->heap()->true_value();
-  if (obj->IsUndetectableObject()) return isolate->heap()->false_value();
-  Map* map = HeapObject::cast(obj)->map();
-  bool is_non_callable_spec_object =
-      map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
-      map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE;
-  return isolate->heap()->ToBoolean(is_non_callable_spec_object);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_IsFunction) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  return isolate->heap()->ToBoolean(obj->IsJSFunction());
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_IsUndetectableObject) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  return isolate->heap()->ToBoolean(obj->IsUndetectableObject());
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_IsSpecObject) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  return isolate->heap()->ToBoolean(obj->IsSpecObject());
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_MathPow) {
-  SealHandleScope shs(isolate);
-  return __RT_impl_Runtime_MathPowSlow(args, isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_IsMinusZero) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  if (!obj->IsHeapNumber()) return isolate->heap()->false_value();
-  HeapNumber* number = HeapNumber::cast(obj);
-  return isolate->heap()->ToBoolean(IsMinusZero(number->value()));
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_HasCachedArrayIndex) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  return isolate->heap()->false_value();
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_GetCachedArrayIndex) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_FastOneByteArrayJoin) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_GeneratorNext) {
-  UNREACHABLE();  // Optimization disabled in SetUpGenerators().
-  return NULL;
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_GeneratorThrow) {
-  UNREACHABLE();  // Optimization disabled in SetUpGenerators().
-  return NULL;
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_ClassOf) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 1);
-  CONVERT_ARG_CHECKED(Object, obj, 0);
-  if (!obj->IsJSReceiver()) return isolate->heap()->null_value();
-  return JSReceiver::cast(obj)->class_name();
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_StringCharCodeAt) {
-  SealHandleScope shs(isolate);
-  DCHECK(args.length() == 2);
-  if (!args[0]->IsString()) return isolate->heap()->undefined_value();
-  if (!args[1]->IsNumber()) return isolate->heap()->undefined_value();
-  if (std::isinf(args.number_at(1))) return isolate->heap()->nan_value();
-  return __RT_impl_Runtime_StringCharCodeAtRT(args, isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_StringAdd) {
-  SealHandleScope shs(isolate);
-  return __RT_impl_Runtime_StringAdd(args, isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_SubString) {
-  SealHandleScope shs(isolate);
-  return __RT_impl_Runtime_SubString(args, isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_StringCompare) {
-  SealHandleScope shs(isolate);
-  return __RT_impl_Runtime_StringCompare(args, isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_RegExpExec) {
-  SealHandleScope shs(isolate);
-  return __RT_impl_Runtime_RegExpExecRT(args, isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_RegExpConstructResult) {
-  SealHandleScope shs(isolate);
-  return __RT_impl_Runtime_RegExpConstructResult(args, isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_GetFromCache) {
-  HandleScope scope(isolate);
-  DCHECK(args.length() == 2);
-  CONVERT_SMI_ARG_CHECKED(id, 0);
-  args[0] = isolate->native_context()->jsfunction_result_caches()->get(id);
-  return __RT_impl_Runtime_GetFromCache(args, isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_NumberToString) {
-  SealHandleScope shs(isolate);
-  return __RT_impl_Runtime_NumberToStringRT(args, isolate);
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_DebugIsActive) {
-  SealHandleScope shs(isolate);
-  return Smi::FromInt(isolate->debug()->is_active());
-}
-
-
-// ----------------------------------------------------------------------------
-// Implementation of Runtime
-
-#define F(name, number_of_args, result_size)                                  \
-  {                                                                           \
-    Runtime::k##name, Runtime::RUNTIME, #name, FUNCTION_ADDR(Runtime_##name), \
-        number_of_args, result_size                                           \
-  }                                                                           \
-  ,
-
-
-#define I(name, number_of_args, result_size)                                \
-  {                                                                         \
-    Runtime::kInline##name, Runtime::INLINE, "_" #name,                     \
-        FUNCTION_ADDR(RuntimeReference_##name), number_of_args, result_size \
-  }                                                                         \
-  ,
-
-
-#define IO(name, number_of_args, result_size)                              \
-  {                                                                        \
-    Runtime::kInlineOptimized##name, Runtime::INLINE_OPTIMIZED, "_" #name, \
-        FUNCTION_ADDR(Runtime_##name), number_of_args, result_size         \
-  }                                                                        \
-  ,
-
-
-static const Runtime::Function kIntrinsicFunctions[] = {
-  RUNTIME_FUNCTION_LIST(F)
-  INLINE_OPTIMIZED_FUNCTION_LIST(F)
-  INLINE_FUNCTION_LIST(I)
-  INLINE_OPTIMIZED_FUNCTION_LIST(IO)
-};
-
-#undef IO
-#undef I
-#undef F
-
-
-void Runtime::InitializeIntrinsicFunctionNames(Isolate* isolate,
-                                               Handle<NameDictionary> dict) {
-  DCHECK(dict->NumberOfElements() == 0);
-  HandleScope scope(isolate);
-  for (int i = 0; i < kNumFunctions; ++i) {
-    const char* name = kIntrinsicFunctions[i].name;
-    if (name == NULL) continue;
-    Handle<NameDictionary> new_dict = NameDictionary::Add(
-        dict,
-        isolate->factory()->InternalizeUtf8String(name),
-        Handle<Smi>(Smi::FromInt(i), isolate),
-        PropertyDetails(NONE, NORMAL, Representation::None()));
-    // The dictionary does not need to grow.
-    CHECK(new_dict.is_identical_to(dict));
-  }
-}
-
-
-const Runtime::Function* Runtime::FunctionForName(Handle<String> name) {
-  Heap* heap = name->GetHeap();
-  int entry = heap->intrinsic_function_names()->FindEntry(name);
-  if (entry != kNotFound) {
-    Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
-    int function_index = Smi::cast(smi_index)->value();
-    return &(kIntrinsicFunctions[function_index]);
-  }
-  return NULL;
-}
-
-
-const Runtime::Function* Runtime::FunctionForEntry(Address entry) {
-  for (size_t i = 0; i < arraysize(kIntrinsicFunctions); ++i) {
-    if (entry == kIntrinsicFunctions[i].entry) {
-      return &(kIntrinsicFunctions[i]);
-    }
-  }
-  return NULL;
-}
-
-
-const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
-  return &(kIntrinsicFunctions[static_cast<int>(id)]);
-}
-
-} }  // namespace v8::internal
diff --git a/src/runtime.h b/src/runtime.h
deleted file mode 100644
index e63cd90..0000000
--- a/src/runtime.h
+++ /dev/null
@@ -1,922 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_RUNTIME_H_
-#define V8_RUNTIME_H_
-
-#include "src/allocation.h"
-#include "src/zone.h"
-
-namespace v8 {
-namespace internal {
-
-// The interface to C++ runtime functions.
-
-// ----------------------------------------------------------------------------
-// RUNTIME_FUNCTION_LIST_ALWAYS defines runtime calls available in both
-// release and debug mode.
-// This macro should only be used by the macro RUNTIME_FUNCTION_LIST.
-
-// WARNING: RUNTIME_FUNCTION_LIST_ALWAYS_* is a very large macro that caused
-// MSVC Intellisense to crash.  It was broken into two macros to work around
-// this problem. Please avoid large recursive macros whenever possible.
-#define RUNTIME_FUNCTION_LIST_ALWAYS_1(F)                  \
-  /* Property access */                                    \
-  F(GetProperty, 2, 1)                                     \
-  F(KeyedGetProperty, 2, 1)                                \
-  F(DeleteProperty, 3, 1)                                  \
-  F(HasOwnProperty, 2, 1)                                  \
-  F(HasProperty, 2, 1)                                     \
-  F(HasElement, 2, 1)                                      \
-  F(IsPropertyEnumerable, 2, 1)                            \
-  F(GetPropertyNames, 1, 1)                                \
-  F(GetPropertyNamesFast, 1, 1)                            \
-  F(GetOwnPropertyNames, 2, 1)                             \
-  F(GetOwnElementNames, 1, 1)                              \
-  F(GetInterceptorInfo, 1, 1)                              \
-  F(GetNamedInterceptorPropertyNames, 1, 1)                \
-  F(GetIndexedInterceptorElementNames, 1, 1)               \
-  F(GetArgumentsProperty, 1, 1)                            \
-  F(ToFastProperties, 1, 1)                                \
-  F(FinishArrayPrototypeSetup, 1, 1)                       \
-  F(SpecialArrayFunctions, 0, 1)                           \
-  F(IsSloppyModeFunction, 1, 1)                            \
-  F(GetDefaultReceiver, 1, 1)                              \
-                                                           \
-  F(GetPrototype, 1, 1)                                    \
-  F(SetPrototype, 2, 1)                                    \
-  F(InternalSetPrototype, 2, 1)                            \
-  F(IsInPrototypeChain, 2, 1)                              \
-                                                           \
-  F(GetOwnProperty, 2, 1)                                  \
-                                                           \
-  F(IsExtensible, 1, 1)                                    \
-  F(PreventExtensions, 1, 1)                               \
-                                                           \
-  /* Utilities */                                          \
-  F(CheckIsBootstrapping, 0, 1)                            \
-  F(GetRootNaN, 0, 1)                                      \
-  F(Call, -1 /* >= 2 */, 1)                                \
-  F(Apply, 5, 1)                                           \
-  F(GetFunctionDelegate, 1, 1)                             \
-  F(GetConstructorDelegate, 1, 1)                          \
-  F(DeoptimizeFunction, 1, 1)                              \
-  F(ClearFunctionTypeFeedback, 1, 1)                       \
-  F(RunningInSimulator, 0, 1)                              \
-  F(IsConcurrentRecompilationSupported, 0, 1)              \
-  F(OptimizeFunctionOnNextCall, -1, 1)                     \
-  F(NeverOptimizeFunction, 1, 1)                           \
-  F(GetOptimizationStatus, -1, 1)                          \
-  F(GetOptimizationCount, 1, 1)                            \
-  F(UnblockConcurrentRecompilation, 0, 1)                  \
-  F(CompileForOnStackReplacement, 1, 1)                    \
-  F(SetAllocationTimeout, -1 /* 2 || 3 */, 1)              \
-  F(SetNativeFlag, 1, 1)                                   \
-  F(SetInlineBuiltinFlag, 1, 1)                            \
-  F(StoreArrayLiteralElement, 5, 1)                        \
-  F(DebugPrepareStepInIfStepping, 1, 1)                    \
-  F(DebugPushPromise, 1, 1)                                \
-  F(DebugPopPromise, 0, 1)                                 \
-  F(DebugPromiseEvent, 1, 1)                               \
-  F(DebugPromiseRejectEvent, 2, 1)                         \
-  F(DebugAsyncTaskEvent, 1, 1)                             \
-  F(FlattenString, 1, 1)                                   \
-  F(LoadMutableDouble, 2, 1)                               \
-  F(TryMigrateInstance, 1, 1)                              \
-  F(NotifyContextDisposed, 0, 1)                           \
-                                                           \
-  /* Array join support */                                 \
-  F(PushIfAbsent, 2, 1)                                    \
-  F(ArrayConcat, 1, 1)                                     \
-                                                           \
-  /* Conversions */                                        \
-  F(ToBool, 1, 1)                                          \
-  F(Typeof, 1, 1)                                          \
-                                                           \
-  F(Booleanize, 2, 1) /* TODO(turbofan): Only temporary */ \
-                                                           \
-  F(StringToNumber, 1, 1)                                  \
-  F(StringParseInt, 2, 1)                                  \
-  F(StringParseFloat, 1, 1)                                \
-  F(StringToLowerCase, 1, 1)                               \
-  F(StringToUpperCase, 1, 1)                               \
-  F(StringSplit, 3, 1)                                     \
-  F(CharFromCode, 1, 1)                                    \
-  F(URIEscape, 1, 1)                                       \
-  F(URIUnescape, 1, 1)                                     \
-                                                           \
-  F(NumberToInteger, 1, 1)                                 \
-  F(NumberToIntegerMapMinusZero, 1, 1)                     \
-  F(NumberToJSUint32, 1, 1)                                \
-  F(NumberToJSInt32, 1, 1)                                 \
-                                                           \
-  /* Arithmetic operations */                              \
-  F(NumberAdd, 2, 1)                                       \
-  F(NumberSub, 2, 1)                                       \
-  F(NumberMul, 2, 1)                                       \
-  F(NumberDiv, 2, 1)                                       \
-  F(NumberMod, 2, 1)                                       \
-  F(NumberUnaryMinus, 1, 1)                                \
-  F(NumberImul, 2, 1)                                      \
-                                                           \
-  F(StringBuilderConcat, 3, 1)                             \
-  F(StringBuilderJoin, 3, 1)                               \
-  F(SparseJoinWithSeparator, 3, 1)                         \
-                                                           \
-  /* Bit operations */                                     \
-  F(NumberOr, 2, 1)                                        \
-  F(NumberAnd, 2, 1)                                       \
-  F(NumberXor, 2, 1)                                       \
-                                                           \
-  F(NumberShl, 2, 1)                                       \
-  F(NumberShr, 2, 1)                                       \
-  F(NumberSar, 2, 1)                                       \
-                                                           \
-  /* Comparisons */                                        \
-  F(NumberEquals, 2, 1)                                    \
-  F(StringEquals, 2, 1)                                    \
-                                                           \
-  F(NumberCompare, 3, 1)                                   \
-  F(SmiLexicographicCompare, 2, 1)                         \
-                                                           \
-  /* Math */                                               \
-  F(MathAcos, 1, 1)                                        \
-  F(MathAsin, 1, 1)                                        \
-  F(MathAtan, 1, 1)                                        \
-  F(MathFloorRT, 1, 1)                                     \
-  F(MathAtan2, 2, 1)                                       \
-  F(MathExpRT, 1, 1)                                       \
-  F(RoundNumber, 1, 1)                                     \
-  F(MathFround, 1, 1)                                      \
-  F(RemPiO2, 1, 1)                                         \
-                                                           \
-  /* Regular expressions */                                \
-  F(RegExpCompile, 3, 1)                                   \
-  F(RegExpExecMultiple, 4, 1)                              \
-  F(RegExpInitializeObject, 6, 1)                          \
-                                                           \
-  /* JSON */                                               \
-  F(ParseJson, 1, 1)                                       \
-  F(BasicJSONStringify, 1, 1)                              \
-  F(QuoteJSONString, 1, 1)                                 \
-                                                           \
-  /* Strings */                                            \
-  F(StringIndexOf, 3, 1)                                   \
-  F(StringLastIndexOf, 3, 1)                               \
-  F(StringLocaleCompare, 2, 1)                             \
-  F(StringReplaceGlobalRegExpWithString, 4, 1)             \
-  F(StringReplaceOneCharWithString, 3, 1)                  \
-  F(StringMatch, 3, 1)                                     \
-  F(StringTrim, 3, 1)                                      \
-  F(StringToArray, 2, 1)                                   \
-  F(NewStringWrapper, 1, 1)                                \
-  F(NewString, 2, 1)                                       \
-  F(TruncateString, 2, 1)                                  \
-                                                           \
-  /* Numbers */                                            \
-  F(NumberToRadixString, 2, 1)                             \
-  F(NumberToFixed, 2, 1)                                   \
-  F(NumberToExponential, 2, 1)                             \
-  F(NumberToPrecision, 2, 1)                               \
-  F(IsValidSmi, 1, 1)                                      \
-                                                           \
-  /* Classes support */                                    \
-  F(ToMethod, 2, 1)                                        \
-  F(HomeObjectSymbol, 0, 1)                                \
-  F(ThrowNonMethodError, 0, 1)                             \
-  F(ThrowUnsupportedSuperError, 0, 1)                      \
-  F(LoadFromSuper, 3, 1)
-
-
-#define RUNTIME_FUNCTION_LIST_ALWAYS_2(F)                             \
-  /* Reflection */                                                    \
-  F(FunctionSetInstanceClassName, 2, 1)                               \
-  F(FunctionSetLength, 2, 1)                                          \
-  F(FunctionSetPrototype, 2, 1)                                       \
-  F(FunctionGetName, 1, 1)                                            \
-  F(FunctionSetName, 2, 1)                                            \
-  F(FunctionNameShouldPrintAsAnonymous, 1, 1)                         \
-  F(FunctionMarkNameShouldPrintAsAnonymous, 1, 1)                     \
-  F(FunctionIsGenerator, 1, 1)                                        \
-  F(FunctionIsArrow, 1, 1)                                            \
-  F(FunctionIsConciseMethod, 1, 1)                                    \
-  F(FunctionBindArguments, 4, 1)                                      \
-  F(BoundFunctionGetBindings, 1, 1)                                   \
-  F(FunctionRemovePrototype, 1, 1)                                    \
-  F(FunctionGetSourceCode, 1, 1)                                      \
-  F(FunctionGetScript, 1, 1)                                          \
-  F(FunctionGetScriptSourcePosition, 1, 1)                            \
-  F(FunctionGetPositionForOffset, 2, 1)                               \
-  F(FunctionIsAPIFunction, 1, 1)                                      \
-  F(FunctionIsBuiltin, 1, 1)                                          \
-  F(GetScript, 1, 1)                                                  \
-  F(CollectStackTrace, 2, 1)                                          \
-  F(GetV8Version, 0, 1)                                               \
-  F(GeneratorGetFunction, 1, 1)                                       \
-  F(GeneratorGetContext, 1, 1)                                        \
-  F(GeneratorGetReceiver, 1, 1)                                       \
-  F(GeneratorGetContinuation, 1, 1)                                   \
-  F(GeneratorGetSourcePosition, 1, 1)                                 \
-                                                                      \
-  F(SetCode, 2, 1)                                                    \
-                                                                      \
-  F(CreateApiFunction, 2, 1)                                          \
-  F(IsTemplate, 1, 1)                                                 \
-  F(GetTemplateField, 2, 1)                                           \
-  F(DisableAccessChecks, 1, 1)                                        \
-  F(EnableAccessChecks, 1, 1)                                         \
-                                                                      \
-  /* Dates */                                                         \
-  F(DateCurrentTime, 0, 1)                                            \
-  F(DateParseString, 2, 1)                                            \
-  F(DateLocalTimezone, 1, 1)                                          \
-  F(DateToUTC, 1, 1)                                                  \
-  F(DateMakeDay, 2, 1)                                                \
-  F(DateSetValue, 3, 1)                                               \
-  F(DateCacheVersion, 0, 1)                                           \
-                                                                      \
-  /* Globals */                                                       \
-  F(CompileString, 2, 1)                                              \
-                                                                      \
-  /* Eval */                                                          \
-  F(GlobalProxy, 1, 1)                                                \
-  F(IsAttachedGlobal, 1, 1)                                           \
-                                                                      \
-  F(AddNamedProperty, 4, 1)                                           \
-  F(AddPropertyForTemplate, 4, 1)                                     \
-  F(SetProperty, 4, 1)                                                \
-  F(AddElement, 4, 1)                                                 \
-  F(DefineApiAccessorProperty, 5, 1)                                  \
-  F(DefineDataPropertyUnchecked, 4, 1)                                \
-  F(DefineAccessorPropertyUnchecked, 5, 1)                            \
-  F(GetDataProperty, 2, 1)                                            \
-  F(SetHiddenProperty, 3, 1)                                          \
-                                                                      \
-  /* Arrays */                                                        \
-  F(RemoveArrayHoles, 2, 1)                                           \
-  F(GetArrayKeys, 2, 1)                                               \
-  F(MoveArrayContents, 2, 1)                                          \
-  F(EstimateNumberOfElements, 1, 1)                                   \
-  F(NormalizeElements, 1, 1)                                          \
-                                                                      \
-  /* Getters and Setters */                                           \
-  F(LookupAccessor, 3, 1)                                             \
-                                                                      \
-  /* ES5 */                                                           \
-  F(ObjectFreeze, 1, 1)                                               \
-                                                                      \
-  /* Harmony modules */                                               \
-  F(IsJSModule, 1, 1)                                                 \
-                                                                      \
-  /* Harmony symbols */                                               \
-  F(CreateSymbol, 1, 1)                                               \
-  F(CreatePrivateSymbol, 1, 1)                                        \
-  F(CreateGlobalPrivateOwnSymbol, 1, 1)                               \
-  F(CreatePrivateOwnSymbol, 1, 1)                                     \
-  F(NewSymbolWrapper, 1, 1)                                           \
-  F(SymbolDescription, 1, 1)                                          \
-  F(SymbolRegistry, 0, 1)                                             \
-  F(SymbolIsPrivate, 1, 1)                                            \
-                                                                      \
-  /* Harmony proxies */                                               \
-  F(CreateJSProxy, 2, 1)                                              \
-  F(CreateJSFunctionProxy, 4, 1)                                      \
-  F(IsJSProxy, 1, 1)                                                  \
-  F(IsJSFunctionProxy, 1, 1)                                          \
-  F(GetHandler, 1, 1)                                                 \
-  F(GetCallTrap, 1, 1)                                                \
-  F(GetConstructTrap, 1, 1)                                           \
-  F(Fix, 1, 1)                                                        \
-                                                                      \
-  /* Harmony sets */                                                  \
-  F(SetInitialize, 1, 1)                                              \
-  F(SetAdd, 2, 1)                                                     \
-  F(SetHas, 2, 1)                                                     \
-  F(SetDelete, 2, 1)                                                  \
-  F(SetClear, 1, 1)                                                   \
-  F(SetGetSize, 1, 1)                                                 \
-                                                                      \
-  F(SetIteratorInitialize, 3, 1)                                      \
-  F(SetIteratorNext, 2, 1)                                            \
-                                                                      \
-  /* Harmony maps */                                                  \
-  F(MapInitialize, 1, 1)                                              \
-  F(MapGet, 2, 1)                                                     \
-  F(MapHas, 2, 1)                                                     \
-  F(MapDelete, 2, 1)                                                  \
-  F(MapClear, 1, 1)                                                   \
-  F(MapSet, 3, 1)                                                     \
-  F(MapGetSize, 1, 1)                                                 \
-                                                                      \
-  F(MapIteratorInitialize, 3, 1)                                      \
-  F(MapIteratorNext, 2, 1)                                            \
-                                                                      \
-  /* Harmony weak maps and sets */                                    \
-  F(WeakCollectionInitialize, 1, 1)                                   \
-  F(WeakCollectionGet, 2, 1)                                          \
-  F(WeakCollectionHas, 2, 1)                                          \
-  F(WeakCollectionDelete, 2, 1)                                       \
-  F(WeakCollectionSet, 3, 1)                                          \
-                                                                      \
-  F(GetWeakMapEntries, 1, 1)                                          \
-  F(GetWeakSetValues, 1, 1)                                           \
-                                                                      \
-  /* Harmony events */                                                \
-  F(EnqueueMicrotask, 1, 1)                                           \
-  F(RunMicrotasks, 0, 1)                                              \
-                                                                      \
-  /* Harmony observe */                                               \
-  F(IsObserved, 1, 1)                                                 \
-  F(SetIsObserved, 1, 1)                                              \
-  F(GetObservationState, 0, 1)                                        \
-  F(ObservationWeakMapCreate, 0, 1)                                   \
-  F(ObserverObjectAndRecordHaveSameOrigin, 3, 1)                      \
-  F(ObjectWasCreatedInCurrentOrigin, 1, 1)                            \
-  F(GetObjectContextObjectObserve, 1, 1)                              \
-  F(GetObjectContextObjectGetNotifier, 1, 1)                          \
-  F(GetObjectContextNotifierPerformChange, 1, 1)                      \
-                                                                      \
-  /* Harmony typed arrays */                                          \
-  F(ArrayBufferInitialize, 2, 1)                                      \
-  F(ArrayBufferSliceImpl, 3, 1)                                       \
-  F(ArrayBufferIsView, 1, 1)                                          \
-  F(ArrayBufferNeuter, 1, 1)                                          \
-                                                                      \
-  F(TypedArrayInitializeFromArrayLike, 4, 1)                          \
-  F(TypedArrayGetBuffer, 1, 1)                                        \
-  F(TypedArraySetFastCases, 3, 1)                                     \
-                                                                      \
-  F(DataViewGetBuffer, 1, 1)                                          \
-  F(DataViewGetInt8, 3, 1)                                            \
-  F(DataViewGetUint8, 3, 1)                                           \
-  F(DataViewGetInt16, 3, 1)                                           \
-  F(DataViewGetUint16, 3, 1)                                          \
-  F(DataViewGetInt32, 3, 1)                                           \
-  F(DataViewGetUint32, 3, 1)                                          \
-  F(DataViewGetFloat32, 3, 1)                                         \
-  F(DataViewGetFloat64, 3, 1)                                         \
-                                                                      \
-  F(DataViewSetInt8, 4, 1)                                            \
-  F(DataViewSetUint8, 4, 1)                                           \
-  F(DataViewSetInt16, 4, 1)                                           \
-  F(DataViewSetUint16, 4, 1)                                          \
-  F(DataViewSetInt32, 4, 1)                                           \
-  F(DataViewSetUint32, 4, 1)                                          \
-  F(DataViewSetFloat32, 4, 1)                                         \
-  F(DataViewSetFloat64, 4, 1)                                         \
-                                                                      \
-  /* Statements */                                                    \
-  F(NewObjectFromBound, 1, 1)                                         \
-                                                                      \
-  /* Declarations and initialization */                               \
-  F(InitializeVarGlobal, 3, 1)                                        \
-  F(OptimizeObjectForAddingMultipleProperties, 2, 1)                  \
-                                                                      \
-  /* Debugging */                                                     \
-  F(DebugPrint, 1, 1)                                                 \
-  F(GlobalPrint, 1, 1)                                                \
-  F(DebugTrace, 0, 1)                                                 \
-  F(TraceEnter, 0, 1)                                                 \
-  F(TraceExit, 1, 1)                                                  \
-  F(Abort, 1, 1)                                                      \
-  F(AbortJS, 1, 1)                                                    \
-  /* ES5 */                                                           \
-  F(OwnKeys, 1, 1)                                                    \
-                                                                      \
-  /* Message objects */                                               \
-  F(MessageGetStartPosition, 1, 1)                                    \
-  F(MessageGetScript, 1, 1)                                           \
-                                                                      \
-  /* Pseudo functions - handled as macros by parser */                \
-  F(IS_VAR, 1, 1)                                                     \
-                                                                      \
-  /* expose boolean functions from objects-inl.h */                   \
-  F(HasFastSmiElements, 1, 1)                                         \
-  F(HasFastSmiOrObjectElements, 1, 1)                                 \
-  F(HasFastObjectElements, 1, 1)                                      \
-  F(HasFastDoubleElements, 1, 1)                                      \
-  F(HasFastHoleyElements, 1, 1)                                       \
-  F(HasDictionaryElements, 1, 1)                                      \
-  F(HasSloppyArgumentsElements, 1, 1)                                 \
-  F(HasExternalUint8ClampedElements, 1, 1)                            \
-  F(HasExternalArrayElements, 1, 1)                                   \
-  F(HasExternalInt8Elements, 1, 1)                                    \
-  F(HasExternalUint8Elements, 1, 1)                                   \
-  F(HasExternalInt16Elements, 1, 1)                                   \
-  F(HasExternalUint16Elements, 1, 1)                                  \
-  F(HasExternalInt32Elements, 1, 1)                                   \
-  F(HasExternalUint32Elements, 1, 1)                                  \
-  F(HasExternalFloat32Elements, 1, 1)                                 \
-  F(HasExternalFloat64Elements, 1, 1)                                 \
-  F(HasFixedUint8ClampedElements, 1, 1)                               \
-  F(HasFixedInt8Elements, 1, 1)                                       \
-  F(HasFixedUint8Elements, 1, 1)                                      \
-  F(HasFixedInt16Elements, 1, 1)                                      \
-  F(HasFixedUint16Elements, 1, 1)                                     \
-  F(HasFixedInt32Elements, 1, 1)                                      \
-  F(HasFixedUint32Elements, 1, 1)                                     \
-  F(HasFixedFloat32Elements, 1, 1)                                    \
-  F(HasFixedFloat64Elements, 1, 1)                                    \
-  F(HasFastProperties, 1, 1)                                          \
-  F(TransitionElementsKind, 2, 1)                                     \
-  F(HaveSameMap, 2, 1)                                                \
-  F(IsJSGlobalProxy, 1, 1)                                            \
-  F(ForInInit, 2, 2)             /* TODO(turbofan): Only temporary */ \
-  F(ForInNext, 4, 2)             /* TODO(turbofan): Only temporary */ \
-  F(ForInCacheArrayLength, 2, 1) /* TODO(turbofan): Only temporary */
-
-
-#define RUNTIME_FUNCTION_LIST_ALWAYS_3(F)                    \
-  /* String and Regexp */                                    \
-  F(NumberToStringRT, 1, 1)                                  \
-  F(RegExpConstructResult, 3, 1)                             \
-  F(RegExpExecRT, 4, 1)                                      \
-  F(StringAdd, 2, 1)                                         \
-  F(SubString, 3, 1)                                         \
-  F(InternalizeString, 1, 1)                                 \
-  F(StringCompare, 2, 1)                                     \
-  F(StringCharCodeAtRT, 2, 1)                                \
-  F(GetFromCache, 2, 1)                                      \
-                                                             \
-  /* Compilation */                                          \
-  F(CompileLazy, 1, 1)                                       \
-  F(CompileOptimized, 2, 1)                                  \
-  F(TryInstallOptimizedCode, 1, 1)                           \
-  F(NotifyDeoptimized, 1, 1)                                 \
-  F(NotifyStubFailure, 0, 1)                                 \
-                                                             \
-  /* Utilities */                                            \
-  F(AllocateInNewSpace, 1, 1)                                \
-  F(AllocateInTargetSpace, 2, 1)                             \
-  F(AllocateHeapNumber, 0, 1)                                \
-  F(NumberToSmi, 1, 1)                                       \
-  F(NumberToStringSkipCache, 1, 1)                           \
-                                                             \
-  F(NewArguments, 1, 1) /* TODO(turbofan): Only temporary */ \
-  F(NewSloppyArguments, 3, 1)                                \
-  F(NewStrictArguments, 3, 1)                                \
-                                                             \
-  /* Harmony generators */                                   \
-  F(CreateJSGeneratorObject, 0, 1)                           \
-  F(SuspendJSGeneratorObject, 1, 1)                          \
-  F(ResumeJSGeneratorObject, 3, 1)                           \
-  F(ThrowGeneratorStateError, 1, 1)                          \
-                                                             \
-  /* Arrays */                                               \
-  F(ArrayConstructor, -1, 1)                                 \
-  F(InternalArrayConstructor, -1, 1)                         \
-                                                             \
-  /* Literals */                                             \
-  F(MaterializeRegExpLiteral, 4, 1)                          \
-  F(CreateObjectLiteral, 4, 1)                               \
-  F(CreateArrayLiteral, 4, 1)                                \
-  F(CreateArrayLiteralStubBailout, 3, 1)                     \
-                                                             \
-  /* Statements */                                           \
-  F(NewClosure, 3, 1)                                        \
-  F(NewClosureFromStubFailure, 1, 1)                         \
-  F(NewObject, 1, 1)                                         \
-  F(NewObjectWithAllocationSite, 2, 1)                       \
-  F(FinalizeInstanceSize, 1, 1)                              \
-  F(Throw, 1, 1)                                             \
-  F(ReThrow, 1, 1)                                           \
-  F(ThrowReferenceError, 1, 1)                               \
-  F(ThrowNotDateError, 0, 1)                                 \
-  F(StackGuard, 0, 1)                                        \
-  F(Interrupt, 0, 1)                                         \
-  F(PromoteScheduledException, 0, 1)                         \
-                                                             \
-  /* Contexts */                                             \
-  F(NewGlobalContext, 2, 1)                                  \
-  F(NewFunctionContext, 1, 1)                                \
-  F(PushWithContext, 2, 1)                                   \
-  F(PushCatchContext, 3, 1)                                  \
-  F(PushBlockContext, 2, 1)                                  \
-  F(PushModuleContext, 2, 1)                                 \
-  F(DeleteLookupSlot, 2, 1)                                  \
-  F(LoadLookupSlot, 2, 2)                                    \
-  F(LoadLookupSlotNoReferenceError, 2, 2)                    \
-  F(StoreLookupSlot, 4, 1)                                   \
-                                                             \
-  /* Declarations and initialization */                      \
-  F(DeclareGlobals, 3, 1)                                    \
-  F(DeclareModules, 1, 1)                                    \
-  F(DeclareLookupSlot, 4, 1)                                 \
-  F(InitializeConstGlobal, 2, 1)                             \
-  F(InitializeLegacyConstLookupSlot, 3, 1)                   \
-                                                             \
-  /* Eval */                                                 \
-  F(ResolvePossiblyDirectEval, 6, 2)                         \
-                                                             \
-  /* Maths */                                                \
-  F(MathPowSlow, 2, 1)                                       \
-  F(MathPowRT, 2, 1)
-
-
-#define RUNTIME_FUNCTION_LIST_DEBUGGER(F) \
-  /* Debugger support*/ \
-  F(DebugBreak, 0, 1) \
-  F(SetDebugEventListener, 2, 1) \
-  F(Break, 0, 1) \
-  F(DebugGetPropertyDetails, 2, 1) \
-  F(DebugGetProperty, 2, 1) \
-  F(DebugPropertyTypeFromDetails, 1, 1) \
-  F(DebugPropertyAttributesFromDetails, 1, 1) \
-  F(DebugPropertyIndexFromDetails, 1, 1) \
-  F(DebugNamedInterceptorPropertyValue, 2, 1) \
-  F(DebugIndexedInterceptorElementValue, 2, 1) \
-  F(CheckExecutionState, 1, 1) \
-  F(GetFrameCount, 1, 1) \
-  F(GetFrameDetails, 2, 1) \
-  F(GetScopeCount, 2, 1) \
-  F(GetStepInPositions, 2, 1) \
-  F(GetScopeDetails, 4, 1) \
-  F(GetAllScopesDetails, 4, 1) \
-  F(GetFunctionScopeCount, 1, 1) \
-  F(GetFunctionScopeDetails, 2, 1) \
-  F(SetScopeVariableValue, 6, 1) \
-  F(DebugPrintScopes, 0, 1) \
-  F(GetThreadCount, 1, 1) \
-  F(GetThreadDetails, 2, 1) \
-  F(SetDisableBreak, 1, 1) \
-  F(GetBreakLocations, 2, 1) \
-  F(SetFunctionBreakPoint, 3, 1) \
-  F(SetScriptBreakPoint, 4, 1) \
-  F(ClearBreakPoint, 1, 1) \
-  F(ChangeBreakOnException, 2, 1) \
-  F(IsBreakOnException, 1, 1) \
-  F(PrepareStep, 4, 1) \
-  F(ClearStepping, 0, 1) \
-  F(DebugEvaluate, 6, 1) \
-  F(DebugEvaluateGlobal, 4, 1) \
-  F(DebugGetLoadedScripts, 0, 1) \
-  F(DebugReferencedBy, 3, 1) \
-  F(DebugConstructedBy, 2, 1) \
-  F(DebugGetPrototype, 1, 1) \
-  F(DebugSetScriptSource, 2, 1) \
-  F(DebugCallbackSupportsStepping, 1, 1) \
-  F(SystemBreak, 0, 1) \
-  F(DebugDisassembleFunction, 1, 1) \
-  F(DebugDisassembleConstructor, 1, 1) \
-  F(FunctionGetInferredName, 1, 1) \
-  F(LiveEditFindSharedFunctionInfosForScript, 1, 1) \
-  F(LiveEditGatherCompileInfo, 2, 1) \
-  F(LiveEditReplaceScript, 3, 1) \
-  F(LiveEditReplaceFunctionCode, 2, 1) \
-  F(LiveEditFunctionSourceUpdated, 1, 1) \
-  F(LiveEditFunctionSetScript, 2, 1) \
-  F(LiveEditReplaceRefToNestedFunction, 3, 1) \
-  F(LiveEditPatchFunctionPositions, 2, 1) \
-  F(LiveEditCheckAndDropActivations, 2, 1) \
-  F(LiveEditCompareStrings, 2, 1) \
-  F(LiveEditRestartFrame, 2, 1) \
-  F(GetFunctionCodePositionFromSource, 2, 1) \
-  F(ExecuteInDebugContext, 2, 1) \
-  \
-  F(SetFlags, 1, 1) \
-  F(CollectGarbage, 1, 1) \
-  F(GetHeapUsage, 0, 1) \
-
-
-#ifdef V8_I18N_SUPPORT
-#define RUNTIME_FUNCTION_LIST_I18N_SUPPORT(F) \
-  /* i18n support */ \
-  /* Standalone, helper methods. */ \
-  F(CanonicalizeLanguageTag, 1, 1) \
-  F(AvailableLocalesOf, 1, 1) \
-  F(GetDefaultICULocale, 0, 1) \
-  F(GetLanguageTagVariants, 1, 1) \
-  F(IsInitializedIntlObject, 1, 1) \
-  F(IsInitializedIntlObjectOfType, 2, 1) \
-  F(MarkAsInitializedIntlObjectOfType, 3, 1) \
-  F(GetImplFromInitializedIntlObject, 1, 1) \
-  \
-  /* Date format and parse. */ \
-  F(CreateDateTimeFormat, 3, 1) \
-  F(InternalDateFormat, 2, 1) \
-  F(InternalDateParse, 2, 1) \
-  \
-  /* Number format and parse. */ \
-  F(CreateNumberFormat, 3, 1) \
-  F(InternalNumberFormat, 2, 1) \
-  F(InternalNumberParse, 2, 1) \
-  \
-  /* Collator. */ \
-  F(CreateCollator, 3, 1) \
-  F(InternalCompare, 3, 1) \
-  \
-  /* String.prototype.normalize. */ \
-  F(StringNormalize, 2, 1) \
-  \
-  /* Break iterator. */ \
-  F(CreateBreakIterator, 3, 1) \
-  F(BreakIteratorAdoptText, 2, 1) \
-  F(BreakIteratorFirst, 1, 1) \
-  F(BreakIteratorNext, 1, 1) \
-  F(BreakIteratorCurrent, 1, 1) \
-  F(BreakIteratorBreakType, 1, 1) \
-
-#else
-#define RUNTIME_FUNCTION_LIST_I18N_SUPPORT(F)
-#endif
-
-
-#ifdef DEBUG
-#define RUNTIME_FUNCTION_LIST_DEBUG(F) \
-  /* Testing */ \
-  F(ListNatives, 0, 1)
-#else
-#define RUNTIME_FUNCTION_LIST_DEBUG(F)
-#endif
-
-// ----------------------------------------------------------------------------
-// RUNTIME_FUNCTION_LIST defines all runtime functions accessed
-// either directly by id (via the code generator), or indirectly
-// via a native call by name (from within JS code).
-// Entries have the form F(name, number of arguments, number of return values).
-
-#define RUNTIME_FUNCTION_LIST(F) \
-  RUNTIME_FUNCTION_LIST_ALWAYS_1(F) \
-  RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
-  RUNTIME_FUNCTION_LIST_ALWAYS_3(F) \
-  RUNTIME_FUNCTION_LIST_DEBUG(F) \
-  RUNTIME_FUNCTION_LIST_DEBUGGER(F) \
-  RUNTIME_FUNCTION_LIST_I18N_SUPPORT(F)
-
-// ----------------------------------------------------------------------------
-// INLINE_FUNCTION_LIST defines all inlined functions accessed
-// with a native call of the form %_name from within JS code.
-// Entries have the form F(name, number of arguments, number of return values).
-#define INLINE_FUNCTION_LIST(F)                             \
-  F(IsSmi, 1, 1)                                            \
-  F(IsNonNegativeSmi, 1, 1)                                 \
-  F(IsArray, 1, 1)                                          \
-  F(IsRegExp, 1, 1)                                         \
-  F(IsConstructCall, 0, 1)                                  \
-  F(CallFunction, -1 /* receiver + n args + function */, 1) \
-  F(ArgumentsLength, 0, 1)                                  \
-  F(Arguments, 1, 1)                                        \
-  F(ValueOf, 1, 1)                                          \
-  F(SetValueOf, 2, 1)                                       \
-  F(DateField, 2 /* date object, field index */, 1)         \
-  F(StringCharFromCode, 1, 1)                               \
-  F(StringCharAt, 2, 1)                                     \
-  F(OneByteSeqStringSetChar, 3, 1)                          \
-  F(TwoByteSeqStringSetChar, 3, 1)                          \
-  F(ObjectEquals, 2, 1)                                     \
-  F(IsObject, 1, 1)                                         \
-  F(IsFunction, 1, 1)                                       \
-  F(IsUndetectableObject, 1, 1)                             \
-  F(IsSpecObject, 1, 1)                                     \
-  F(IsStringWrapperSafeForDefaultValueOf, 1, 1)             \
-  F(MathPow, 2, 1)                                          \
-  F(IsMinusZero, 1, 1)                                      \
-  F(HasCachedArrayIndex, 1, 1)                              \
-  F(GetCachedArrayIndex, 1, 1)                              \
-  F(FastOneByteArrayJoin, 2, 1)                             \
-  F(GeneratorNext, 2, 1)                                    \
-  F(GeneratorThrow, 2, 1)                                   \
-  F(DebugBreakInOptimizedCode, 0, 1)                        \
-  F(ClassOf, 1, 1)                                          \
-  F(StringCharCodeAt, 2, 1)                                 \
-  F(StringAdd, 2, 1)                                        \
-  F(SubString, 3, 1)                                        \
-  F(StringCompare, 2, 1)                                    \
-  F(RegExpExec, 4, 1)                                       \
-  F(RegExpConstructResult, 3, 1)                            \
-  F(GetFromCache, 2, 1)                                     \
-  F(NumberToString, 1, 1)                                   \
-  F(DebugIsActive, 0, 1)
-
-
-// ----------------------------------------------------------------------------
-// INLINE_OPTIMIZED_FUNCTION_LIST defines all inlined functions accessed
-// with a native call of the form %_name from within JS code that also have
-// a corresponding runtime function, that is called from non-optimized code.
-// For the benefit of (fuzz) tests, the runtime version can also be called
-// directly as %name (i.e. without the leading underscore).
-// Entries have the form F(name, number of arguments, number of return values).
-#define INLINE_OPTIMIZED_FUNCTION_LIST(F) \
-  /* Typed Arrays */                                                         \
-  F(TypedArrayInitialize, 5, 1)                                              \
-  F(DataViewInitialize, 4, 1)                                                \
-  F(MaxSmi, 0, 1)                                                            \
-  F(TypedArrayMaxSizeInHeap, 0, 1)                                           \
-  F(ArrayBufferViewGetByteLength, 1, 1)                                      \
-  F(ArrayBufferViewGetByteOffset, 1, 1)                                      \
-  F(TypedArrayGetLength, 1, 1)                                               \
-  /* ArrayBuffer */                                                          \
-  F(ArrayBufferGetByteLength, 1, 1)                                          \
-  /* Maths */                                                                \
-  F(ConstructDouble, 2, 1)                                                   \
-  F(DoubleHi, 1, 1)                                                          \
-  F(DoubleLo, 1, 1)                                                          \
-  F(MathSqrtRT, 1, 1)                                                        \
-  F(MathLogRT, 1, 1)
-
-
-//---------------------------------------------------------------------------
-// Runtime provides access to all C++ runtime functions.
-
-class RuntimeState {
- public:
-  StaticResource<ConsStringIteratorOp>* string_iterator() {
-    return &string_iterator_;
-  }
-  unibrow::Mapping<unibrow::ToUppercase, 128>* to_upper_mapping() {
-    return &to_upper_mapping_;
-  }
-  unibrow::Mapping<unibrow::ToLowercase, 128>* to_lower_mapping() {
-    return &to_lower_mapping_;
-  }
-  ConsStringIteratorOp* string_iterator_compare_x() {
-    return &string_iterator_compare_x_;
-  }
-  ConsStringIteratorOp* string_iterator_compare_y() {
-    return &string_iterator_compare_y_;
-  }
-  ConsStringIteratorOp* string_locale_compare_it1() {
-    return &string_locale_compare_it1_;
-  }
-  ConsStringIteratorOp* string_locale_compare_it2() {
-    return &string_locale_compare_it2_;
-  }
-
- private:
-  RuntimeState() {}
-  // Non-reentrant string buffer for efficient general use in the runtime.
-  StaticResource<ConsStringIteratorOp> string_iterator_;
-  unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping_;
-  unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping_;
-  ConsStringIteratorOp string_iterator_compare_x_;
-  ConsStringIteratorOp string_iterator_compare_y_;
-  ConsStringIteratorOp string_locale_compare_it1_;
-  ConsStringIteratorOp string_locale_compare_it2_;
-
-  friend class Isolate;
-  friend class Runtime;
-
-  DISALLOW_COPY_AND_ASSIGN(RuntimeState);
-};
-
-
-class Runtime : public AllStatic {
- public:
-  enum FunctionId {
-#define F(name, nargs, ressize) k##name,
-    RUNTIME_FUNCTION_LIST(F)
-    INLINE_OPTIMIZED_FUNCTION_LIST(F)
-#undef F
-#define F(name, nargs, ressize) kInline##name,
-    INLINE_FUNCTION_LIST(F)
-#undef F
-#define F(name, nargs, ressize) kInlineOptimized##name,
-    INLINE_OPTIMIZED_FUNCTION_LIST(F)
-#undef F
-    kNumFunctions,
-    kFirstInlineFunction = kInlineIsSmi
-  };
-
-  enum IntrinsicType {
-    RUNTIME,
-    INLINE,
-    INLINE_OPTIMIZED
-  };
-
-  // Intrinsic function descriptor.
-  struct Function {
-    FunctionId function_id;
-    IntrinsicType intrinsic_type;
-    // The JS name of the function.
-    const char* name;
-
-    // The C++ (native) entry point.  NULL if the function is inlined.
-    byte* entry;
-
-    // The number of arguments expected. nargs is -1 if the function takes
-    // a variable number of arguments.
-    int nargs;
-    // Size of result.  Most functions return a single pointer, size 1.
-    int result_size;
-  };
-
-  static const int kNotFound = -1;
-
-  // Add internalized strings for all the intrinsic function names to a
-  // StringDictionary.
-  static void InitializeIntrinsicFunctionNames(Isolate* isolate,
-                                               Handle<NameDictionary> dict);
-
-  // Get the intrinsic function with the given name, which must be internalized.
-  static const Function* FunctionForName(Handle<String> name);
-
-  // Get the intrinsic function with the given FunctionId.
-  static const Function* FunctionForId(FunctionId id);
-
-  // Get the intrinsic function with the given function entry address.
-  static const Function* FunctionForEntry(Address ref);
-
-  // General-purpose helper functions for runtime system.
-  static int StringMatch(Isolate* isolate,
-                         Handle<String> sub,
-                         Handle<String> pat,
-                         int index);
-
-  static bool IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch);
-
-  // TODO(1240886): Some of the following methods are *not* handle safe, but
-  // accept handle arguments. This seems fragile.
-
-  // Support getting the characters in a string using [] notation as
-  // in Firefox/SpiderMonkey, Safari and Opera.
-  MUST_USE_RESULT static MaybeHandle<Object> GetElementOrCharAt(
-      Isolate* isolate,
-      Handle<Object> object,
-      uint32_t index);
-
-  MUST_USE_RESULT static MaybeHandle<Object> SetObjectProperty(
-      Isolate* isolate, Handle<Object> object, Handle<Object> key,
-      Handle<Object> value, StrictMode strict_mode);
-
-  MUST_USE_RESULT static MaybeHandle<Object> DefineObjectProperty(
-      Handle<JSObject> object, Handle<Object> key, Handle<Object> value,
-      PropertyAttributes attr);
-
-  MUST_USE_RESULT static MaybeHandle<Object> DeleteObjectProperty(
-      Isolate* isolate,
-      Handle<JSReceiver> object,
-      Handle<Object> key,
-      JSReceiver::DeleteMode mode);
-
-  MUST_USE_RESULT static MaybeHandle<Object> HasObjectProperty(
-      Isolate* isolate,
-      Handle<JSReceiver> object,
-      Handle<Object> key);
-
-  MUST_USE_RESULT static MaybeHandle<Object> GetObjectProperty(
-      Isolate* isolate,
-      Handle<Object> object,
-      Handle<Object> key);
-
-  static void SetupArrayBuffer(Isolate* isolate,
-                               Handle<JSArrayBuffer> array_buffer,
-                               bool is_external,
-                               void* data,
-                               size_t allocated_length);
-
-  static bool SetupArrayBufferAllocatingData(
-      Isolate* isolate,
-      Handle<JSArrayBuffer> array_buffer,
-      size_t allocated_length,
-      bool initialize = true);
-
-  static void NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer);
-
-  static void FreeArrayBuffer(
-      Isolate* isolate,
-      JSArrayBuffer* phantom_array_buffer);
-
-  enum TypedArrayId {
-    // arrayIds below should be synchromized with typedarray.js natives.
-    ARRAY_ID_UINT8 = 1,
-    ARRAY_ID_INT8 = 2,
-    ARRAY_ID_UINT16 = 3,
-    ARRAY_ID_INT16 = 4,
-    ARRAY_ID_UINT32 = 5,
-    ARRAY_ID_INT32 = 6,
-    ARRAY_ID_FLOAT32 = 7,
-    ARRAY_ID_FLOAT64 = 8,
-    ARRAY_ID_UINT8_CLAMPED = 9,
-
-    ARRAY_ID_FIRST = ARRAY_ID_UINT8,
-    ARRAY_ID_LAST = ARRAY_ID_UINT8_CLAMPED
-  };
-
-  static void ArrayIdToTypeAndSize(int array_id,
-      ExternalArrayType *type,
-      ElementsKind* external_elements_kind,
-      ElementsKind* fixed_elements_kind,
-      size_t *element_size);
-
-  // Used in runtime.cc and hydrogen's VisitArrayLiteral.
-  MUST_USE_RESULT static MaybeHandle<Object> CreateArrayLiteralBoilerplate(
-      Isolate* isolate,
-      Handle<FixedArray> literals,
-      Handle<FixedArray> elements);
-};
-
-
-//---------------------------------------------------------------------------
-// Constants used by interface to runtime functions.
-
-class AllocateDoubleAlignFlag:  public BitField<bool,            0, 1> {};
-class AllocateTargetSpace:      public BitField<AllocationSpace, 1, 3> {};
-
-class DeclareGlobalsEvalFlag:   public BitField<bool,       0, 1> {};
-class DeclareGlobalsNativeFlag: public BitField<bool,       1, 1> {};
-class DeclareGlobalsStrictMode: public BitField<StrictMode, 2, 1> {};
-
-} }  // namespace v8::internal
-
-#endif  // V8_RUNTIME_H_
diff --git a/src/runtime.js b/src/runtime.js
index 4d15d20..978429e 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -6,9 +6,7 @@
 
 // CAUTION: Some of the functions specified in this file are called
 // directly from compiled code. These are the functions with names in
-// ALL CAPS. The compiled code passes the first argument in 'this' and
-// it does not push the function onto the stack. This means that you
-// cannot use contexts in all these functions.
+// ALL CAPS. The compiled code passes the first argument in 'this'.
 
 
 /* -----------------------------------
@@ -324,8 +322,13 @@
   if (!IS_SPEC_OBJECT(x)) {
     throw %MakeTypeError('invalid_in_operator_use', [this, x]);
   }
-  return %_IsNonNegativeSmi(this) ?
-    %HasElement(x, this) : %HasProperty(x, %ToName(this));
+  if (%_IsNonNegativeSmi(this)) {
+    if (IS_ARRAY(x) && %_HasFastPackedElements(x)) {
+      return this < x.length;
+    }
+    return %HasElement(x, this);
+  }
+  return %HasProperty(x, %ToName(this));
 }
 
 
@@ -598,6 +601,15 @@
   return x === y;
 }
 
+// ES6, section 7.2.4
+function SameValueZero(x, y) {
+  if (typeof x != typeof y) return false;
+  if (IS_NUMBER(x)) {
+    if (NUMBER_IS_NAN(x) && NUMBER_IS_NAN(y)) return true;
+  }
+  return x === y;
+}
+
 
 /* ---------------------------------
    - - -   U t i l i t i e s   - - -
@@ -614,6 +626,15 @@
 }
 
 
+// ES6, draft 10-14-14, section 22.1.3.1.1
+function IsConcatSpreadable(O) {
+  if (!IS_SPEC_OBJECT(O)) return false;
+  var spreadable = O[symbolIsConcatSpreadable];
+  if (IS_UNDEFINED(spreadable)) return IS_ARRAY(O);
+  return ToBoolean(spreadable);
+}
+
+
 // ECMA-262, section 8.6.2.6, page 28.
 function DefaultNumber(x) {
   if (!IS_SYMBOL_WRAPPER(x)) {
@@ -651,7 +672,7 @@
 }
 
 function ToPositiveInteger(x, rangeErrorName) {
-  var i = TO_INTEGER(x);
+  var i = TO_INTEGER_MAP_MINUS_ZERO(x);
   if (i < 0) throw MakeRangeError(rangeErrorName);
   return i;
 }
diff --git a/src/runtime/runtime-api.cc b/src/runtime/runtime-api.cc
new file mode 100644
index 0000000..740832e
--- /dev/null
+++ b/src/runtime/runtime-api.cc
@@ -0,0 +1,127 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/bootstrapper.h"
+#include "src/runtime/runtime.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_CreateApiFunction) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
+  return *isolate->factory()->CreateApiFunction(data, prototype);
+}
+
+
+RUNTIME_FUNCTION(Runtime_IsTemplate) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, arg, 0);
+  bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
+  return isolate->heap()->ToBoolean(result);
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetTemplateField) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_CHECKED(HeapObject, templ, 0);
+  CONVERT_SMI_ARG_CHECKED(index, 1);
+  int offset = index * kPointerSize + HeapObject::kHeaderSize;
+  InstanceType type = templ->map()->instance_type();
+  RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
+                 type == OBJECT_TEMPLATE_INFO_TYPE);
+  RUNTIME_ASSERT(offset > 0);
+  if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
+    RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
+  } else {
+    RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
+  }
+  return *HeapObject::RawField(templ, offset);
+}
+
+
+// Transform getter or setter into something DefineAccessor can handle.
+static Handle<Object> InstantiateAccessorComponent(Isolate* isolate,
+                                                   Handle<Object> component) {
+  if (component->IsUndefined()) return isolate->factory()->undefined_value();
+  Handle<FunctionTemplateInfo> info =
+      Handle<FunctionTemplateInfo>::cast(component);
+  return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction());
+}
+
+
+RUNTIME_FUNCTION(Runtime_DefineApiAccessorProperty) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 5);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
+  CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
+  CONVERT_SMI_ARG_CHECKED(attribute, 4);
+  RUNTIME_ASSERT(getter->IsUndefined() || getter->IsFunctionTemplateInfo());
+  RUNTIME_ASSERT(setter->IsUndefined() || setter->IsFunctionTemplateInfo());
+  RUNTIME_ASSERT(PropertyDetails::AttributesField::is_valid(
+      static_cast<PropertyAttributes>(attribute)));
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate, JSObject::DefineAccessor(
+                   object, name, InstantiateAccessorComponent(isolate, getter),
+                   InstantiateAccessorComponent(isolate, setter),
+                   static_cast<PropertyAttributes>(attribute)));
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_AddPropertyForTemplate) {
+  HandleScope scope(isolate);
+  RUNTIME_ASSERT(args.length() == 4);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
+  CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
+  RUNTIME_ASSERT(
+      (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
+  // Compute attributes.
+  PropertyAttributes attributes =
+      static_cast<PropertyAttributes>(unchecked_attributes);
+
+#ifdef DEBUG
+  bool duplicate;
+  if (key->IsName()) {
+    LookupIterator it(object, Handle<Name>::cast(key),
+                      LookupIterator::OWN_SKIP_INTERCEPTOR);
+    Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
+    DCHECK(maybe.has_value);
+    duplicate = it.IsFound();
+  } else {
+    uint32_t index = 0;
+    RUNTIME_ASSERT(key->ToArrayIndex(&index));
+    Maybe<bool> maybe = JSReceiver::HasOwnElement(object, index);
+    if (!maybe.has_value) return isolate->heap()->exception();
+    duplicate = maybe.value;
+  }
+  if (duplicate) {
+    Handle<Object> args[1] = {key};
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate,
+        NewTypeError("duplicate_template_property", HandleVector(args, 1)));
+  }
+#endif
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Runtime::DefineObjectProperty(object, key, value, attributes));
+  return *result;
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-array.cc b/src/runtime/runtime-array.cc
new file mode 100644
index 0000000..a017236
--- /dev/null
+++ b/src/runtime/runtime-array.cc
@@ -0,0 +1,1317 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
+  Object* length = prototype->length();
+  RUNTIME_ASSERT(length->IsSmi() && Smi::cast(length)->value() == 0);
+  RUNTIME_ASSERT(prototype->HasFastSmiOrObjectElements());
+  // This is necessary to enable fast checks for absence of elements
+  // on Array.prototype and below.
+  prototype->set_elements(isolate->heap()->empty_fixed_array());
+  return Smi::FromInt(0);
+}
+
+
+static void InstallBuiltin(Isolate* isolate, Handle<JSObject> holder,
+                           const char* name, Builtins::Name builtin_name) {
+  Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
+  Handle<Code> code(isolate->builtins()->builtin(builtin_name));
+  Handle<JSFunction> optimized =
+      isolate->factory()->NewFunctionWithoutPrototype(key, code);
+  optimized->shared()->DontAdaptArguments();
+  JSObject::AddProperty(holder, key, optimized, NONE);
+}
+
+
+RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+  Handle<JSObject> holder =
+      isolate->factory()->NewJSObject(isolate->object_function());
+
+  InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
+  InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
+  InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
+  InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
+  InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
+  InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
+  InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
+
+  return *holder;
+}
+
+
+RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
+  HandleScope scope(isolate);
+  RUNTIME_ASSERT(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Map, map, 1);
+  JSObject::TransitionElementsKind(array, map->elements_kind());
+  return *array;
+}
+
+
+// Push an object unto an array of objects if it is not already in the
+// array.  Returns true if the element was pushed on the stack and
+// false otherwise.
+RUNTIME_FUNCTION(Runtime_PushIfAbsent) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, element, 1);
+  RUNTIME_ASSERT(array->HasFastSmiOrObjectElements());
+  int length = Smi::cast(array->length())->value();
+  FixedArray* elements = FixedArray::cast(array->elements());
+  for (int i = 0; i < length; i++) {
+    if (elements->get(i) == *element) return isolate->heap()->false_value();
+  }
+
+  // Strict not needed. Used for cycle detection in Array join implementation.
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate, JSObject::SetFastElement(array, length, element, SLOPPY, true));
+  return isolate->heap()->true_value();
+}
+
+
+/**
+ * A simple visitor visits every element of Array's.
+ * The backend storage can be a fixed array for fast elements case,
+ * or a dictionary for sparse array. Since Dictionary is a subtype
+ * of FixedArray, the class can be used by both fast and slow cases.
+ * The second parameter of the constructor, fast_elements, specifies
+ * whether the storage is a FixedArray or Dictionary.
+ *
+ * An index limit is used to deal with the situation that a result array
+ * length overflows 32-bit non-negative integer.
+ */
+class ArrayConcatVisitor {
+ public:
+  ArrayConcatVisitor(Isolate* isolate, Handle<FixedArray> storage,
+                     bool fast_elements)
+      : isolate_(isolate),
+        storage_(Handle<FixedArray>::cast(
+            isolate->global_handles()->Create(*storage))),
+        index_offset_(0u),
+        bit_field_(FastElementsField::encode(fast_elements) |
+                   ExceedsLimitField::encode(false)) {}
+
+  ~ArrayConcatVisitor() { clear_storage(); }
+
+  void visit(uint32_t i, Handle<Object> elm) {
+    if (i > JSObject::kMaxElementCount - index_offset_) {
+      set_exceeds_array_limit(true);
+      return;
+    }
+    uint32_t index = index_offset_ + i;
+
+    if (fast_elements()) {
+      if (index < static_cast<uint32_t>(storage_->length())) {
+        storage_->set(index, *elm);
+        return;
+      }
+      // Our initial estimate of length was foiled, possibly by
+      // getters on the arrays increasing the length of later arrays
+      // during iteration.
+      // This shouldn't happen in anything but pathological cases.
+      SetDictionaryMode();
+      // Fall-through to dictionary mode.
+    }
+    DCHECK(!fast_elements());
+    Handle<SeededNumberDictionary> dict(
+        SeededNumberDictionary::cast(*storage_));
+    Handle<SeededNumberDictionary> result =
+        SeededNumberDictionary::AtNumberPut(dict, index, elm);
+    if (!result.is_identical_to(dict)) {
+      // Dictionary needed to grow.
+      clear_storage();
+      set_storage(*result);
+    }
+  }
+
+  void increase_index_offset(uint32_t delta) {
+    if (JSObject::kMaxElementCount - index_offset_ < delta) {
+      index_offset_ = JSObject::kMaxElementCount;
+    } else {
+      index_offset_ += delta;
+    }
+    // If the initial length estimate was off (see special case in visit()),
+    // but the array blowing the limit didn't contain elements beyond the
+    // provided-for index range, go to dictionary mode now.
+    if (fast_elements() &&
+        index_offset_ >
+            static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) {
+      SetDictionaryMode();
+    }
+  }
+
+  bool exceeds_array_limit() const {
+    return ExceedsLimitField::decode(bit_field_);
+  }
+
+  Handle<JSArray> ToArray() {
+    Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
+    Handle<Object> length =
+        isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
+    Handle<Map> map = JSObject::GetElementsTransitionMap(
+        array, fast_elements() ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS);
+    array->set_map(*map);
+    array->set_length(*length);
+    array->set_elements(*storage_);
+    return array;
+  }
+
+ private:
+  // Convert storage to dictionary mode.
+  void SetDictionaryMode() {
+    DCHECK(fast_elements());
+    Handle<FixedArray> current_storage(*storage_);
+    Handle<SeededNumberDictionary> slow_storage(
+        SeededNumberDictionary::New(isolate_, current_storage->length()));
+    uint32_t current_length = static_cast<uint32_t>(current_storage->length());
+    for (uint32_t i = 0; i < current_length; i++) {
+      HandleScope loop_scope(isolate_);
+      Handle<Object> element(current_storage->get(i), isolate_);
+      if (!element->IsTheHole()) {
+        Handle<SeededNumberDictionary> new_storage =
+            SeededNumberDictionary::AtNumberPut(slow_storage, i, element);
+        if (!new_storage.is_identical_to(slow_storage)) {
+          slow_storage = loop_scope.CloseAndEscape(new_storage);
+        }
+      }
+    }
+    clear_storage();
+    set_storage(*slow_storage);
+    set_fast_elements(false);
+  }
+
+  inline void clear_storage() {
+    GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
+  }
+
+  inline void set_storage(FixedArray* storage) {
+    storage_ =
+        Handle<FixedArray>::cast(isolate_->global_handles()->Create(storage));
+  }
+
+  class FastElementsField : public BitField<bool, 0, 1> {};
+  class ExceedsLimitField : public BitField<bool, 1, 1> {};
+
+  bool fast_elements() const { return FastElementsField::decode(bit_field_); }
+  void set_fast_elements(bool fast) {
+    bit_field_ = FastElementsField::update(bit_field_, fast);
+  }
+  void set_exceeds_array_limit(bool exceeds) {
+    bit_field_ = ExceedsLimitField::update(bit_field_, exceeds);
+  }
+
+  Isolate* isolate_;
+  Handle<FixedArray> storage_;  // Always a global handle.
+  // Index after last seen index. Always less than or equal to
+  // JSObject::kMaxElementCount.
+  uint32_t index_offset_;
+  uint32_t bit_field_;
+};
+
+
+static uint32_t EstimateElementCount(Handle<JSArray> array) {
+  uint32_t length = static_cast<uint32_t>(array->length()->Number());
+  int element_count = 0;
+  switch (array->GetElementsKind()) {
+    case FAST_SMI_ELEMENTS:
+    case FAST_HOLEY_SMI_ELEMENTS:
+    case FAST_ELEMENTS:
+    case FAST_HOLEY_ELEMENTS: {
+      // Fast elements can't have lengths that are not representable by
+      // a 32-bit signed integer.
+      DCHECK(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
+      int fast_length = static_cast<int>(length);
+      Handle<FixedArray> elements(FixedArray::cast(array->elements()));
+      for (int i = 0; i < fast_length; i++) {
+        if (!elements->get(i)->IsTheHole()) element_count++;
+      }
+      break;
+    }
+    case FAST_DOUBLE_ELEMENTS:
+    case FAST_HOLEY_DOUBLE_ELEMENTS: {
+      // Fast elements can't have lengths that are not representable by
+      // a 32-bit signed integer.
+      DCHECK(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
+      int fast_length = static_cast<int>(length);
+      if (array->elements()->IsFixedArray()) {
+        DCHECK(FixedArray::cast(array->elements())->length() == 0);
+        break;
+      }
+      Handle<FixedDoubleArray> elements(
+          FixedDoubleArray::cast(array->elements()));
+      for (int i = 0; i < fast_length; i++) {
+        if (!elements->is_the_hole(i)) element_count++;
+      }
+      break;
+    }
+    case DICTIONARY_ELEMENTS: {
+      Handle<SeededNumberDictionary> dictionary(
+          SeededNumberDictionary::cast(array->elements()));
+      int capacity = dictionary->Capacity();
+      for (int i = 0; i < capacity; i++) {
+        Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate());
+        if (dictionary->IsKey(*key)) {
+          element_count++;
+        }
+      }
+      break;
+    }
+    case SLOPPY_ARGUMENTS_ELEMENTS:
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+  case EXTERNAL_##TYPE##_ELEMENTS:                      \
+  case TYPE##_ELEMENTS:
+
+      TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+      // External arrays are always dense.
+      return length;
+  }
+  // As an estimate, we assume that the prototype doesn't contain any
+  // inherited elements.
+  return element_count;
+}
+
+
+template <class ExternalArrayClass, class ElementType>
+static void IterateTypedArrayElements(Isolate* isolate,
+                                      Handle<JSObject> receiver,
+                                      bool elements_are_ints,
+                                      bool elements_are_guaranteed_smis,
+                                      ArrayConcatVisitor* visitor) {
+  Handle<ExternalArrayClass> array(
+      ExternalArrayClass::cast(receiver->elements()));
+  uint32_t len = static_cast<uint32_t>(array->length());
+
+  DCHECK(visitor != NULL);
+  if (elements_are_ints) {
+    if (elements_are_guaranteed_smis) {
+      for (uint32_t j = 0; j < len; j++) {
+        HandleScope loop_scope(isolate);
+        Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))),
+                      isolate);
+        visitor->visit(j, e);
+      }
+    } else {
+      for (uint32_t j = 0; j < len; j++) {
+        HandleScope loop_scope(isolate);
+        int64_t val = static_cast<int64_t>(array->get_scalar(j));
+        if (Smi::IsValid(static_cast<intptr_t>(val))) {
+          Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate);
+          visitor->visit(j, e);
+        } else {
+          Handle<Object> e =
+              isolate->factory()->NewNumber(static_cast<ElementType>(val));
+          visitor->visit(j, e);
+        }
+      }
+    }
+  } else {
+    for (uint32_t j = 0; j < len; j++) {
+      HandleScope loop_scope(isolate);
+      Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
+      visitor->visit(j, e);
+    }
+  }
+}
+
+
+// Used for sorting indices in a List<uint32_t>.
+static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
+  uint32_t a = *ap;
+  uint32_t b = *bp;
+  return (a == b) ? 0 : (a < b) ? -1 : 1;
+}
+
+
+static void CollectElementIndices(Handle<JSObject> object, uint32_t range,
+                                  List<uint32_t>* indices) {
+  Isolate* isolate = object->GetIsolate();
+  ElementsKind kind = object->GetElementsKind();
+  switch (kind) {
+    case FAST_SMI_ELEMENTS:
+    case FAST_ELEMENTS:
+    case FAST_HOLEY_SMI_ELEMENTS:
+    case FAST_HOLEY_ELEMENTS: {
+      Handle<FixedArray> elements(FixedArray::cast(object->elements()));
+      uint32_t length = static_cast<uint32_t>(elements->length());
+      if (range < length) length = range;
+      for (uint32_t i = 0; i < length; i++) {
+        if (!elements->get(i)->IsTheHole()) {
+          indices->Add(i);
+        }
+      }
+      break;
+    }
+    case FAST_HOLEY_DOUBLE_ELEMENTS:
+    case FAST_DOUBLE_ELEMENTS: {
+      if (object->elements()->IsFixedArray()) {
+        DCHECK(object->elements()->length() == 0);
+        break;
+      }
+      Handle<FixedDoubleArray> elements(
+          FixedDoubleArray::cast(object->elements()));
+      uint32_t length = static_cast<uint32_t>(elements->length());
+      if (range < length) length = range;
+      for (uint32_t i = 0; i < length; i++) {
+        if (!elements->is_the_hole(i)) {
+          indices->Add(i);
+        }
+      }
+      break;
+    }
+    case DICTIONARY_ELEMENTS: {
+      Handle<SeededNumberDictionary> dict(
+          SeededNumberDictionary::cast(object->elements()));
+      uint32_t capacity = dict->Capacity();
+      for (uint32_t j = 0; j < capacity; j++) {
+        HandleScope loop_scope(isolate);
+        Handle<Object> k(dict->KeyAt(j), isolate);
+        if (dict->IsKey(*k)) {
+          DCHECK(k->IsNumber());
+          uint32_t index = static_cast<uint32_t>(k->Number());
+          if (index < range) {
+            indices->Add(index);
+          }
+        }
+      }
+      break;
+    }
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+  case TYPE##_ELEMENTS:                                 \
+  case EXTERNAL_##TYPE##_ELEMENTS:
+
+      TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+      {
+        uint32_t length = static_cast<uint32_t>(
+            FixedArrayBase::cast(object->elements())->length());
+        if (range <= length) {
+          length = range;
+          // We will add all indices, so we might as well clear it first
+          // and avoid duplicates.
+          indices->Clear();
+        }
+        for (uint32_t i = 0; i < length; i++) {
+          indices->Add(i);
+        }
+        if (length == range) return;  // All indices accounted for already.
+        break;
+      }
+    case SLOPPY_ARGUMENTS_ELEMENTS: {
+      MaybeHandle<Object> length_obj =
+          Object::GetProperty(object, isolate->factory()->length_string());
+      double length_num = length_obj.ToHandleChecked()->Number();
+      uint32_t length = static_cast<uint32_t>(DoubleToInt32(length_num));
+      ElementsAccessor* accessor = object->GetElementsAccessor();
+      for (uint32_t i = 0; i < length; i++) {
+        if (accessor->HasElement(object, object, i)) {
+          indices->Add(i);
+        }
+      }
+      break;
+    }
+  }
+
+  PrototypeIterator iter(isolate, object);
+  if (!iter.IsAtEnd()) {
+    // The prototype will usually have no inherited element indices,
+    // but we have to check.
+    CollectElementIndices(
+        Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), range,
+        indices);
+  }
+}
+
+
+static bool IterateElementsSlow(Isolate* isolate, Handle<JSObject> receiver,
+                                uint32_t length, ArrayConcatVisitor* visitor) {
+  for (uint32_t i = 0; i < length; ++i) {
+    HandleScope loop_scope(isolate);
+    Maybe<bool> maybe = JSReceiver::HasElement(receiver, i);
+    if (!maybe.has_value) return false;
+    if (maybe.value) {
+      Handle<Object> element_value;
+      ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+          isolate, element_value,
+          Runtime::GetElementOrCharAt(isolate, receiver, i), false);
+      visitor->visit(i, element_value);
+    }
+  }
+  visitor->increase_index_offset(length);
+  return true;
+}
+
+
+/**
+ * A helper function that visits elements of a JSObject in numerical
+ * order.
+ *
+ * The visitor argument called for each existing element in the array
+ * with the element index and the element's value.
+ * Afterwards it increments the base-index of the visitor by the array
+ * length.
+ * Returns false if any access threw an exception, otherwise true.
+ */
+static bool IterateElements(Isolate* isolate, Handle<JSObject> receiver,
+                            ArrayConcatVisitor* visitor) {
+  uint32_t length = 0;
+
+  if (receiver->IsJSArray()) {
+    Handle<JSArray> array(Handle<JSArray>::cast(receiver));
+    length = static_cast<uint32_t>(array->length()->Number());
+  } else {
+    Handle<Object> val;
+    Handle<Object> key(isolate->heap()->length_string(), isolate);
+    ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, val,
+        Runtime::GetObjectProperty(isolate, receiver, key), false);
+    // TODO(caitp): Support larger element indexes (up to 2^53-1).
+    if (!val->ToUint32(&length)) {
+      ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, val,
+          Execution::ToLength(isolate, val), false);
+      val->ToUint32(&length);
+    }
+  }
+
+  if (!(receiver->IsJSArray() || receiver->IsJSTypedArray())) {
+    // For classes which are not known to be safe to access via elements alone,
+    // use the slow case.
+    return IterateElementsSlow(isolate, receiver, length, visitor);
+  }
+
+  switch (receiver->GetElementsKind()) {
+    case FAST_SMI_ELEMENTS:
+    case FAST_ELEMENTS:
+    case FAST_HOLEY_SMI_ELEMENTS:
+    case FAST_HOLEY_ELEMENTS: {
+      // Run through the elements FixedArray and use HasElement and GetElement
+      // to check the prototype for missing elements.
+      Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
+      int fast_length = static_cast<int>(length);
+      DCHECK(fast_length <= elements->length());
+      for (int j = 0; j < fast_length; j++) {
+        HandleScope loop_scope(isolate);
+        Handle<Object> element_value(elements->get(j), isolate);
+        if (!element_value->IsTheHole()) {
+          visitor->visit(j, element_value);
+        } else {
+          Maybe<bool> maybe = JSReceiver::HasElement(receiver, j);
+          if (!maybe.has_value) return false;
+          if (maybe.value) {
+            // Call GetElement on receiver, not its prototype, or getters won't
+            // have the correct receiver.
+            ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+                isolate, element_value,
+                Object::GetElement(isolate, receiver, j), false);
+            visitor->visit(j, element_value);
+          }
+        }
+      }
+      break;
+    }
+    case FAST_HOLEY_DOUBLE_ELEMENTS:
+    case FAST_DOUBLE_ELEMENTS: {
+      // Empty array is FixedArray but not FixedDoubleArray.
+      if (length == 0) break;
+      // Run through the elements FixedArray and use HasElement and GetElement
+      // to check the prototype for missing elements.
+      if (receiver->elements()->IsFixedArray()) {
+        DCHECK(receiver->elements()->length() == 0);
+        break;
+      }
+      Handle<FixedDoubleArray> elements(
+          FixedDoubleArray::cast(receiver->elements()));
+      int fast_length = static_cast<int>(length);
+      DCHECK(fast_length <= elements->length());
+      for (int j = 0; j < fast_length; j++) {
+        HandleScope loop_scope(isolate);
+        if (!elements->is_the_hole(j)) {
+          double double_value = elements->get_scalar(j);
+          Handle<Object> element_value =
+              isolate->factory()->NewNumber(double_value);
+          visitor->visit(j, element_value);
+        } else {
+          Maybe<bool> maybe = JSReceiver::HasElement(receiver, j);
+          if (!maybe.has_value) return false;
+          if (maybe.value) {
+            // Call GetElement on receiver, not its prototype, or getters won't
+            // have the correct receiver.
+            Handle<Object> element_value;
+            ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+                isolate, element_value,
+                Object::GetElement(isolate, receiver, j), false);
+            visitor->visit(j, element_value);
+          }
+        }
+      }
+      break;
+    }
+    case DICTIONARY_ELEMENTS: {
+      Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
+      List<uint32_t> indices(dict->Capacity() / 2);
+      // Collect all indices in the object and the prototypes less
+      // than length. This might introduce duplicates in the indices list.
+      CollectElementIndices(receiver, length, &indices);
+      indices.Sort(&compareUInt32);
+      int j = 0;
+      int n = indices.length();
+      while (j < n) {
+        HandleScope loop_scope(isolate);
+        uint32_t index = indices[j];
+        Handle<Object> element;
+        ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+            isolate, element, Object::GetElement(isolate, receiver, index),
+            false);
+        visitor->visit(index, element);
+        // Skip to next different index (i.e., omit duplicates).
+        do {
+          j++;
+        } while (j < n && indices[j] == index);
+      }
+      break;
+    }
+    case EXTERNAL_UINT8_CLAMPED_ELEMENTS: {
+      Handle<ExternalUint8ClampedArray> pixels(
+          ExternalUint8ClampedArray::cast(receiver->elements()));
+      for (uint32_t j = 0; j < length; j++) {
+        Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
+        visitor->visit(j, e);
+      }
+      break;
+    }
+    case UINT8_CLAMPED_ELEMENTS: {
+      Handle<FixedUint8ClampedArray> pixels(
+      FixedUint8ClampedArray::cast(receiver->elements()));
+      for (uint32_t j = 0; j < length; j++) {
+        Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
+        visitor->visit(j, e);
+      }
+      break;
+    }
+    case EXTERNAL_INT8_ELEMENTS: {
+      IterateTypedArrayElements<ExternalInt8Array, int8_t>(
+          isolate, receiver, true, true, visitor);
+      break;
+    }
+    case INT8_ELEMENTS: {
+      IterateTypedArrayElements<FixedInt8Array, int8_t>(
+      isolate, receiver, true, true, visitor);
+      break;
+    }
+    case EXTERNAL_UINT8_ELEMENTS: {
+      IterateTypedArrayElements<ExternalUint8Array, uint8_t>(
+          isolate, receiver, true, true, visitor);
+      break;
+    }
+    case UINT8_ELEMENTS: {
+      IterateTypedArrayElements<FixedUint8Array, uint8_t>(
+      isolate, receiver, true, true, visitor);
+      break;
+    }
+    case EXTERNAL_INT16_ELEMENTS: {
+      IterateTypedArrayElements<ExternalInt16Array, int16_t>(
+          isolate, receiver, true, true, visitor);
+      break;
+    }
+    case INT16_ELEMENTS: {
+      IterateTypedArrayElements<FixedInt16Array, int16_t>(
+      isolate, receiver, true, true, visitor);
+      break;
+    }
+    case EXTERNAL_UINT16_ELEMENTS: {
+      IterateTypedArrayElements<ExternalUint16Array, uint16_t>(
+          isolate, receiver, true, true, visitor);
+      break;
+    }
+    case UINT16_ELEMENTS: {
+      IterateTypedArrayElements<FixedUint16Array, uint16_t>(
+      isolate, receiver, true, true, visitor);
+      break;
+    }
+    case EXTERNAL_INT32_ELEMENTS: {
+      IterateTypedArrayElements<ExternalInt32Array, int32_t>(
+          isolate, receiver, true, false, visitor);
+      break;
+    }
+    case INT32_ELEMENTS: {
+      IterateTypedArrayElements<FixedInt32Array, int32_t>(
+      isolate, receiver, true, false, visitor);
+      break;
+    }
+    case EXTERNAL_UINT32_ELEMENTS: {
+      IterateTypedArrayElements<ExternalUint32Array, uint32_t>(
+          isolate, receiver, true, false, visitor);
+      break;
+    }
+    case UINT32_ELEMENTS: {
+      IterateTypedArrayElements<FixedUint32Array, uint32_t>(
+      isolate, receiver, true, false, visitor);
+      break;
+    }
+    case EXTERNAL_FLOAT32_ELEMENTS: {
+      IterateTypedArrayElements<ExternalFloat32Array, float>(
+          isolate, receiver, false, false, visitor);
+      break;
+    }
+    case FLOAT32_ELEMENTS: {
+      IterateTypedArrayElements<FixedFloat32Array, float>(
+      isolate, receiver, false, false, visitor);
+      break;
+    }
+    case EXTERNAL_FLOAT64_ELEMENTS: {
+      IterateTypedArrayElements<ExternalFloat64Array, double>(
+          isolate, receiver, false, false, visitor);
+      break;
+    }
+    case FLOAT64_ELEMENTS: {
+      IterateTypedArrayElements<FixedFloat64Array, double>(
+      isolate, receiver, false, false, visitor);
+      break;
+    }
+    case SLOPPY_ARGUMENTS_ELEMENTS: {
+      ElementsAccessor* accessor = receiver->GetElementsAccessor();
+      for (uint32_t index = 0; index < length; index++) {
+        HandleScope loop_scope(isolate);
+        if (accessor->HasElement(receiver, receiver, index)) {
+          Handle<Object> element;
+          ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+              isolate, element, accessor->Get(receiver, receiver, index),
+              false);
+          visitor->visit(index, element);
+        }
+      }
+      break;
+    }
+  }
+  visitor->increase_index_offset(length);
+  return true;
+}
+
+
+static bool IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) {
+  HandleScope handle_scope(isolate);
+  if (!obj->IsSpecObject()) return false;
+  if (obj->IsJSArray()) return true;
+  if (FLAG_harmony_arrays) {
+    Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol());
+    Handle<Object> value;
+    MaybeHandle<Object> maybeValue =
+        i::Runtime::GetObjectProperty(isolate, obj, key);
+    if (maybeValue.ToHandle(&value)) {
+      return value->BooleanValue();
+    }
+  }
+  return false;
+}
+
+
+/**
+ * Array::concat implementation.
+ * See ECMAScript 262, 15.4.4.4.
+ * TODO(581): Fix non-compliance for very large concatenations and update to
+ * following the ECMAScript 5 specification.
+ */
+RUNTIME_FUNCTION(Runtime_ArrayConcat) {
+  HandleScope handle_scope(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
+  int argument_count = static_cast<int>(arguments->length()->Number());
+  RUNTIME_ASSERT(arguments->HasFastObjectElements());
+  Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
+
+  // Pass 1: estimate the length and number of elements of the result.
+  // The actual length can be larger if any of the arguments have getters
+  // that mutate other arguments (but will otherwise be precise).
+  // The number of elements is precise if there are no inherited elements.
+
+  ElementsKind kind = FAST_SMI_ELEMENTS;
+
+  uint32_t estimate_result_length = 0;
+  uint32_t estimate_nof_elements = 0;
+  for (int i = 0; i < argument_count; i++) {
+    HandleScope loop_scope(isolate);
+    Handle<Object> obj(elements->get(i), isolate);
+    uint32_t length_estimate;
+    uint32_t element_estimate;
+    if (obj->IsJSArray()) {
+      Handle<JSArray> array(Handle<JSArray>::cast(obj));
+      length_estimate = static_cast<uint32_t>(array->length()->Number());
+      if (length_estimate != 0) {
+        ElementsKind array_kind =
+            GetPackedElementsKind(array->map()->elements_kind());
+        if (IsMoreGeneralElementsKindTransition(kind, array_kind)) {
+          kind = array_kind;
+        }
+      }
+      element_estimate = EstimateElementCount(array);
+    } else {
+      if (obj->IsHeapObject()) {
+        if (obj->IsNumber()) {
+          if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) {
+            kind = FAST_DOUBLE_ELEMENTS;
+          }
+        } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) {
+          kind = FAST_ELEMENTS;
+        }
+      }
+      length_estimate = 1;
+      element_estimate = 1;
+    }
+    // Avoid overflows by capping at kMaxElementCount.
+    if (JSObject::kMaxElementCount - estimate_result_length < length_estimate) {
+      estimate_result_length = JSObject::kMaxElementCount;
+    } else {
+      estimate_result_length += length_estimate;
+    }
+    if (JSObject::kMaxElementCount - estimate_nof_elements < element_estimate) {
+      estimate_nof_elements = JSObject::kMaxElementCount;
+    } else {
+      estimate_nof_elements += element_estimate;
+    }
+  }
+
+  // If estimated number of elements is more than half of length, a
+  // fixed array (fast case) is more time and space-efficient than a
+  // dictionary.
+  bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
+
+  if (fast_case && kind == FAST_DOUBLE_ELEMENTS) {
+    Handle<FixedArrayBase> storage =
+        isolate->factory()->NewFixedDoubleArray(estimate_result_length);
+    int j = 0;
+    bool failure = false;
+    if (estimate_result_length > 0) {
+      Handle<FixedDoubleArray> double_storage =
+          Handle<FixedDoubleArray>::cast(storage);
+      for (int i = 0; i < argument_count; i++) {
+        Handle<Object> obj(elements->get(i), isolate);
+        if (obj->IsSmi()) {
+          double_storage->set(j, Smi::cast(*obj)->value());
+          j++;
+        } else if (obj->IsNumber()) {
+          double_storage->set(j, obj->Number());
+          j++;
+        } else {
+          JSArray* array = JSArray::cast(*obj);
+          uint32_t length = static_cast<uint32_t>(array->length()->Number());
+          switch (array->map()->elements_kind()) {
+            case FAST_HOLEY_DOUBLE_ELEMENTS:
+            case FAST_DOUBLE_ELEMENTS: {
+              // Empty array is FixedArray but not FixedDoubleArray.
+              if (length == 0) break;
+              FixedDoubleArray* elements =
+                  FixedDoubleArray::cast(array->elements());
+              for (uint32_t i = 0; i < length; i++) {
+                if (elements->is_the_hole(i)) {
+                  // TODO(jkummerow/verwaest): We could be a bit more clever
+                  // here: Check if there are no elements/getters on the
+                  // prototype chain, and if so, allow creation of a holey
+                  // result array.
+                  // Same thing below (holey smi case).
+                  failure = true;
+                  break;
+                }
+                double double_value = elements->get_scalar(i);
+                double_storage->set(j, double_value);
+                j++;
+              }
+              break;
+            }
+            case FAST_HOLEY_SMI_ELEMENTS:
+            case FAST_SMI_ELEMENTS: {
+              FixedArray* elements(FixedArray::cast(array->elements()));
+              for (uint32_t i = 0; i < length; i++) {
+                Object* element = elements->get(i);
+                if (element->IsTheHole()) {
+                  failure = true;
+                  break;
+                }
+                int32_t int_value = Smi::cast(element)->value();
+                double_storage->set(j, int_value);
+                j++;
+              }
+              break;
+            }
+            case FAST_HOLEY_ELEMENTS:
+            case FAST_ELEMENTS:
+              DCHECK_EQ(0, length);
+              break;
+            default:
+              UNREACHABLE();
+          }
+        }
+        if (failure) break;
+      }
+    }
+    if (!failure) {
+      Handle<JSArray> array = isolate->factory()->NewJSArray(0);
+      Smi* length = Smi::FromInt(j);
+      Handle<Map> map;
+      map = JSObject::GetElementsTransitionMap(array, kind);
+      array->set_map(*map);
+      array->set_length(length);
+      array->set_elements(*storage);
+      return *array;
+    }
+    // In case of failure, fall through.
+  }
+
+  Handle<FixedArray> storage;
+  if (fast_case) {
+    // The backing storage array must have non-existing elements to preserve
+    // holes across concat operations.
+    storage =
+        isolate->factory()->NewFixedArrayWithHoles(estimate_result_length);
+  } else {
+    // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
+    uint32_t at_least_space_for =
+        estimate_nof_elements + (estimate_nof_elements >> 2);
+    storage = Handle<FixedArray>::cast(
+        SeededNumberDictionary::New(isolate, at_least_space_for));
+  }
+
+  ArrayConcatVisitor visitor(isolate, storage, fast_case);
+
+  for (int i = 0; i < argument_count; i++) {
+    Handle<Object> obj(elements->get(i), isolate);
+    bool spreadable = IsConcatSpreadable(isolate, obj);
+    if (isolate->has_pending_exception()) return isolate->heap()->exception();
+    if (spreadable) {
+      Handle<JSObject> object = Handle<JSObject>::cast(obj);
+      if (!IterateElements(isolate, object, &visitor)) {
+        return isolate->heap()->exception();
+      }
+    } else {
+      visitor.visit(0, obj);
+      visitor.increase_index_offset(1);
+    }
+  }
+
+  if (visitor.exceeds_array_limit()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate,
+        NewRangeError("invalid_array_length", HandleVector<Object>(NULL, 0)));
+  }
+  return *visitor.ToArray();
+}
+
+
+// Moves all own elements of an object, that are below a limit, to positions
+// starting at zero. All undefined values are placed after non-undefined values,
+// and are followed by non-existing element. Does not change the length
+// property.
+// Returns the number of non-undefined elements collected.
+// Returns -1 if hole removal is not supported by this method.
+RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
+  return *JSObject::PrepareElementsForSort(object, limit);
+}
+
+
+// Move contents of argument 0 (an array) to argument 1 (an array)
+RUNTIME_FUNCTION(Runtime_MoveArrayContents) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, from, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, to, 1);
+  JSObject::ValidateElements(from);
+  JSObject::ValidateElements(to);
+
+  Handle<FixedArrayBase> new_elements(from->elements());
+  ElementsKind from_kind = from->GetElementsKind();
+  Handle<Map> new_map = JSObject::GetElementsTransitionMap(to, from_kind);
+  JSObject::SetMapAndElements(to, new_map, new_elements);
+  to->set_length(from->length());
+
+  JSObject::ResetElements(from);
+  from->set_length(Smi::FromInt(0));
+
+  JSObject::ValidateElements(to);
+  return *to;
+}
+
+
+// How many elements does this object/array have?
+RUNTIME_FUNCTION(Runtime_EstimateNumberOfElements) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
+  Handle<FixedArrayBase> elements(array->elements(), isolate);
+  SealHandleScope shs(isolate);
+  if (elements->IsDictionary()) {
+    int result =
+        Handle<SeededNumberDictionary>::cast(elements)->NumberOfElements();
+    return Smi::FromInt(result);
+  } else {
+    DCHECK(array->length()->IsSmi());
+    // For packed elements, we know the exact number of elements
+    int length = elements->length();
+    ElementsKind kind = array->GetElementsKind();
+    if (IsFastPackedElementsKind(kind)) {
+      return Smi::FromInt(length);
+    }
+    // For holey elements, take samples from the buffer checking for holes
+    // to generate the estimate.
+    const int kNumberOfHoleCheckSamples = 97;
+    int increment = (length < kNumberOfHoleCheckSamples)
+                        ? 1
+                        : static_cast<int>(length / kNumberOfHoleCheckSamples);
+    ElementsAccessor* accessor = array->GetElementsAccessor();
+    int holes = 0;
+    for (int i = 0; i < length; i += increment) {
+      if (!accessor->HasElement(array, array, i, elements)) {
+        ++holes;
+      }
+    }
+    int estimate = static_cast<int>((kNumberOfHoleCheckSamples - holes) /
+                                    kNumberOfHoleCheckSamples * length);
+    return Smi::FromInt(estimate);
+  }
+}
+
+
+// Returns an array that tells you where in the [0, length) interval an array
+// might have elements.  Can either return an array of keys (positive integers
+// or undefined) or a number representing the positive length of an interval
+// starting at index 0.
+// Intervals can span over some keys that are not in the object.
+RUNTIME_FUNCTION(Runtime_GetArrayKeys) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
+  CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
+  if (array->elements()->IsDictionary()) {
+    Handle<FixedArray> keys = isolate->factory()->empty_fixed_array();
+    for (PrototypeIterator iter(isolate, array,
+                                PrototypeIterator::START_AT_RECEIVER);
+         !iter.IsAtEnd(); iter.Advance()) {
+      if (PrototypeIterator::GetCurrent(iter)->IsJSProxy() ||
+          JSObject::cast(*PrototypeIterator::GetCurrent(iter))
+              ->HasIndexedInterceptor()) {
+        // Bail out if we find a proxy or interceptor, likely not worth
+        // collecting keys in that case.
+        return *isolate->factory()->NewNumberFromUint(length);
+      }
+      Handle<JSObject> current =
+          Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+      Handle<FixedArray> current_keys =
+          isolate->factory()->NewFixedArray(current->NumberOfOwnElements(NONE));
+      current->GetOwnElementKeys(*current_keys, NONE);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+          isolate, keys, FixedArray::UnionOfKeys(keys, current_keys));
+    }
+    // Erase any keys >= length.
+    // TODO(adamk): Remove this step when the contract of %GetArrayKeys
+    // is changed to let this happen on the JS side.
+    for (int i = 0; i < keys->length(); i++) {
+      if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i);
+    }
+    return *isolate->factory()->NewJSArrayWithElements(keys);
+  } else {
+    RUNTIME_ASSERT(array->HasFastSmiOrObjectElements() ||
+                   array->HasFastDoubleElements());
+    uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
+    return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
+  }
+}
+
+
+static Object* ArrayConstructorCommon(Isolate* isolate,
+                                      Handle<JSFunction> constructor,
+                                      Handle<AllocationSite> site,
+                                      Arguments* caller_args) {
+  Factory* factory = isolate->factory();
+
+  bool holey = false;
+  bool can_use_type_feedback = true;
+  if (caller_args->length() == 1) {
+    Handle<Object> argument_one = caller_args->at<Object>(0);
+    if (argument_one->IsSmi()) {
+      int value = Handle<Smi>::cast(argument_one)->value();
+      if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) {
+        // the array is a dictionary in this case.
+        can_use_type_feedback = false;
+      } else if (value != 0) {
+        holey = true;
+      }
+    } else {
+      // Non-smi length argument produces a dictionary
+      can_use_type_feedback = false;
+    }
+  }
+
+  Handle<JSArray> array;
+  if (!site.is_null() && can_use_type_feedback) {
+    ElementsKind to_kind = site->GetElementsKind();
+    if (holey && !IsFastHoleyElementsKind(to_kind)) {
+      to_kind = GetHoleyElementsKind(to_kind);
+      // Update the allocation site info to reflect the advice alteration.
+      site->SetElementsKind(to_kind);
+    }
+
+    // We should allocate with an initial map that reflects the allocation site
+    // advice. Therefore we use AllocateJSObjectFromMap instead of passing
+    // the constructor.
+    Handle<Map> initial_map(constructor->initial_map(), isolate);
+    if (to_kind != initial_map->elements_kind()) {
+      initial_map = Map::AsElementsKind(initial_map, to_kind);
+    }
+
+    // If we don't care to track arrays of to_kind ElementsKind, then
+    // don't emit a memento for them.
+    Handle<AllocationSite> allocation_site;
+    if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) {
+      allocation_site = site;
+    }
+
+    array = Handle<JSArray>::cast(factory->NewJSObjectFromMap(
+        initial_map, NOT_TENURED, true, allocation_site));
+  } else {
+    array = Handle<JSArray>::cast(factory->NewJSObject(constructor));
+
+    // We might need to transition to holey
+    ElementsKind kind = constructor->initial_map()->elements_kind();
+    if (holey && !IsFastHoleyElementsKind(kind)) {
+      kind = GetHoleyElementsKind(kind);
+      JSObject::TransitionElementsKind(array, kind);
+    }
+  }
+
+  factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS);
+
+  ElementsKind old_kind = array->GetElementsKind();
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate, ArrayConstructInitializeElements(array, caller_args));
+  if (!site.is_null() &&
+      (old_kind != array->GetElementsKind() || !can_use_type_feedback)) {
+    // The arguments passed in caused a transition. This kind of complexity
+    // can't be dealt with in the inlined hydrogen array constructor case.
+    // We must mark the allocationsite as un-inlinable.
+    site->SetDoNotInlineCall();
+  }
+  return *array;
+}
+
+
+RUNTIME_FUNCTION(Runtime_ArrayConstructor) {
+  HandleScope scope(isolate);
+  // If we get 2 arguments then they are the stub parameters (constructor, type
+  // info).  If we get 4, then the first one is a pointer to the arguments
+  // passed by the caller, and the last one is the length of the arguments
+  // passed to the caller (redundant, but useful to check on the deoptimizer
+  // with an assert).
+  Arguments empty_args(0, NULL);
+  bool no_caller_args = args.length() == 2;
+  DCHECK(no_caller_args || args.length() == 4);
+  int parameters_start = no_caller_args ? 0 : 1;
+  Arguments* caller_args =
+      no_caller_args ? &empty_args : reinterpret_cast<Arguments*>(args[0]);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
+  CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1);
+#ifdef DEBUG
+  if (!no_caller_args) {
+    CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 2);
+    DCHECK(arg_count == caller_args->length());
+  }
+#endif
+
+  Handle<AllocationSite> site;
+  if (!type_info.is_null() &&
+      *type_info != isolate->heap()->undefined_value()) {
+    site = Handle<AllocationSite>::cast(type_info);
+    DCHECK(!site->SitePointsToLiteral());
+  }
+
+  return ArrayConstructorCommon(isolate, constructor, site, caller_args);
+}
+
+
+RUNTIME_FUNCTION(Runtime_InternalArrayConstructor) {
+  HandleScope scope(isolate);
+  Arguments empty_args(0, NULL);
+  bool no_caller_args = args.length() == 1;
+  DCHECK(no_caller_args || args.length() == 3);
+  int parameters_start = no_caller_args ? 0 : 1;
+  Arguments* caller_args =
+      no_caller_args ? &empty_args : reinterpret_cast<Arguments*>(args[0]);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
+#ifdef DEBUG
+  if (!no_caller_args) {
+    CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 1);
+    DCHECK(arg_count == caller_args->length());
+  }
+#endif
+  return ArrayConstructorCommon(isolate, constructor,
+                                Handle<AllocationSite>::null(), caller_args);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NormalizeElements) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
+  RUNTIME_ASSERT(!array->HasExternalArrayElements() &&
+                 !array->HasFixedTypedArrayElements());
+  JSObject::NormalizeElements(array);
+  return *array;
+}
+
+
+RUNTIME_FUNCTION(Runtime_HasComplexElements) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
+  for (PrototypeIterator iter(isolate, array,
+                              PrototypeIterator::START_AT_RECEIVER);
+       !iter.IsAtEnd(); iter.Advance()) {
+    if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
+      return isolate->heap()->true_value();
+    }
+    Handle<JSObject> current =
+        Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+    if (current->HasIndexedInterceptor()) {
+      return isolate->heap()->true_value();
+    }
+    if (!current->HasDictionaryElements()) continue;
+    if (current->element_dictionary()->HasComplexElements()) {
+      return isolate->heap()->true_value();
+    }
+  }
+  return isolate->heap()->false_value();
+}
+
+
+// TODO(dcarney): remove this function when TurboFan supports it.
+// Takes the object to be iterated over and the result of GetPropertyNamesFast
+// Returns pair (cache_array, cache_type).
+RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ForInInit) {
+  SealHandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  // This simulates CONVERT_ARG_HANDLE_CHECKED for calls returning pairs.
+  // Not worth creating a macro atm as this function should be removed.
+  if (!args[0]->IsJSReceiver() || !args[1]->IsObject()) {
+    Object* error = isolate->ThrowIllegalOperation();
+    return MakePair(error, isolate->heap()->undefined_value());
+  }
+  Handle<JSReceiver> object = args.at<JSReceiver>(0);
+  Handle<Object> cache_type = args.at<Object>(1);
+  if (cache_type->IsMap()) {
+    // Enum cache case.
+    if (Map::EnumLengthBits::decode(Map::cast(*cache_type)->bit_field3()) ==
+        0) {
+      // 0 length enum.
+      // Can't handle this case in the graph builder,
+      // so transform it into the empty fixed array case.
+      return MakePair(isolate->heap()->empty_fixed_array(), Smi::FromInt(1));
+    }
+    return MakePair(object->map()->instance_descriptors()->GetEnumCache(),
+                    *cache_type);
+  } else {
+    // FixedArray case.
+    Smi* new_cache_type = Smi::FromInt(object->IsJSProxy() ? 0 : 1);
+    return MakePair(*Handle<FixedArray>::cast(cache_type), new_cache_type);
+  }
+}
+
+
+// TODO(dcarney): remove this function when TurboFan supports it.
+RUNTIME_FUNCTION(Runtime_ForInCacheArrayLength) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(Object, cache_type, 0);
+  CONVERT_ARG_HANDLE_CHECKED(FixedArray, array, 1);
+  int length = 0;
+  if (cache_type->IsMap()) {
+    length = Map::cast(*cache_type)->EnumLength();
+  } else {
+    DCHECK(cache_type->IsSmi());
+    length = array->length();
+  }
+  return Smi::FromInt(length);
+}
+
+
+// TODO(dcarney): remove this function when TurboFan supports it.
+// Takes (the object to be iterated over,
+//        cache_array from ForInInit,
+//        cache_type from ForInInit,
+//        the current index)
+// Returns pair (array[index], needs_filtering).
+RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ForInNext) {
+  SealHandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  int32_t index;
+  // This simulates CONVERT_ARG_HANDLE_CHECKED for calls returning pairs.
+  // Not worth creating a macro atm as this function should be removed.
+  if (!args[0]->IsJSReceiver() || !args[1]->IsFixedArray() ||
+      !args[2]->IsObject() || !args[3]->ToInt32(&index)) {
+    Object* error = isolate->ThrowIllegalOperation();
+    return MakePair(error, isolate->heap()->undefined_value());
+  }
+  Handle<JSReceiver> object = args.at<JSReceiver>(0);
+  Handle<FixedArray> array = args.at<FixedArray>(1);
+  Handle<Object> cache_type = args.at<Object>(2);
+  // Figure out first if a slow check is needed for this object.
+  bool slow_check_needed = false;
+  if (cache_type->IsMap()) {
+    if (object->map() != Map::cast(*cache_type)) {
+      // Object transitioned.  Need slow check.
+      slow_check_needed = true;
+    }
+  } else {
+    // No slow check needed for proxies.
+    slow_check_needed = Smi::cast(*cache_type)->value() == 1;
+  }
+  return MakePair(array->get(index),
+                  isolate->heap()->ToBoolean(slow_check_needed));
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_IsArray) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  return isolate->heap()->ToBoolean(obj->IsJSArray());
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_HasCachedArrayIndex) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  return isolate->heap()->false_value();
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_GetCachedArrayIndex) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_FastOneByteArrayJoin) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  return isolate->heap()->undefined_value();
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-classes.cc b/src/runtime/runtime-classes.cc
new file mode 100644
index 0000000..7c827f0
--- /dev/null
+++ b/src/runtime/runtime-classes.cc
@@ -0,0 +1,488 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdlib.h>
+#include <limits>
+
+#include "src/v8.h"
+
+#include "src/isolate-inl.h"
+#include "src/runtime/runtime.h"
+#include "src/runtime/runtime-utils.h"
+
+
+namespace v8 {
+namespace internal {
+
+
+RUNTIME_FUNCTION(Runtime_ThrowNonMethodError) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+  THROW_NEW_ERROR_RETURN_FAILURE(
+      isolate, NewReferenceError("non_method", HandleVector<Object>(NULL, 0)));
+}
+
+
+static Object* ThrowUnsupportedSuper(Isolate* isolate) {
+  THROW_NEW_ERROR_RETURN_FAILURE(
+      isolate,
+      NewReferenceError("unsupported_super", HandleVector<Object>(NULL, 0)));
+}
+
+
+RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+  return ThrowUnsupportedSuper(isolate);
+}
+
+
+RUNTIME_FUNCTION(Runtime_ToMethod) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
+  Handle<JSFunction> clone = JSFunction::CloneClosure(fun);
+  Handle<Symbol> home_object_symbol(isolate->heap()->home_object_symbol());
+  JSObject::SetOwnPropertyIgnoreAttributes(clone, home_object_symbol,
+                                           home_object, DONT_ENUM).Assert();
+  return *clone;
+}
+
+
+RUNTIME_FUNCTION(Runtime_HomeObjectSymbol) {
+  DCHECK(args.length() == 0);
+  return isolate->heap()->home_object_symbol();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DefineClass) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 6);
+  CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, super_class, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 2);
+  CONVERT_ARG_HANDLE_CHECKED(Script, script, 3);
+  CONVERT_SMI_ARG_CHECKED(start_position, 4);
+  CONVERT_SMI_ARG_CHECKED(end_position, 5);
+
+  Handle<Object> prototype_parent;
+  Handle<Object> constructor_parent;
+
+  if (super_class->IsTheHole()) {
+    prototype_parent = isolate->initial_object_prototype();
+  } else {
+    if (super_class->IsNull()) {
+      prototype_parent = isolate->factory()->null_value();
+    } else if (super_class->IsSpecFunction()) {
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+          isolate, prototype_parent,
+          Runtime::GetObjectProperty(isolate, super_class,
+                                     isolate->factory()->prototype_string()));
+      if (!prototype_parent->IsNull() && !prototype_parent->IsSpecObject()) {
+        Handle<Object> args[1] = {prototype_parent};
+        THROW_NEW_ERROR_RETURN_FAILURE(
+            isolate, NewTypeError("prototype_parent_not_an_object",
+                                  HandleVector(args, 1)));
+      }
+      constructor_parent = super_class;
+    } else {
+      // TODO(arv): Should be IsConstructor.
+      Handle<Object> args[1] = {super_class};
+      THROW_NEW_ERROR_RETURN_FAILURE(
+          isolate,
+          NewTypeError("extends_value_not_a_function", HandleVector(args, 1)));
+    }
+  }
+
+  Handle<Map> map =
+      isolate->factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+  map->SetPrototype(prototype_parent);
+  map->set_constructor(*constructor);
+  Handle<JSObject> prototype = isolate->factory()->NewJSObjectFromMap(map);
+
+  Handle<String> name_string = name->IsString()
+                                   ? Handle<String>::cast(name)
+                                   : isolate->factory()->empty_string();
+  constructor->shared()->set_name(*name_string);
+
+  JSFunction::SetPrototype(constructor, prototype);
+  PropertyAttributes attribs =
+      static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+                   constructor, isolate->factory()->prototype_string(),
+                   prototype, attribs));
+
+  // TODO(arv): Only do this conditionally.
+  Handle<Symbol> home_object_symbol(isolate->heap()->home_object_symbol());
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+                   constructor, home_object_symbol, prototype, DONT_ENUM));
+
+  if (!constructor_parent.is_null()) {
+    RETURN_FAILURE_ON_EXCEPTION(
+        isolate,
+        JSObject::SetPrototype(constructor, constructor_parent, false));
+  }
+
+  JSObject::AddProperty(prototype, isolate->factory()->constructor_string(),
+                        constructor, DONT_ENUM);
+
+  // Install private properties that are used to construct the FunctionToString.
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate, Object::SetProperty(constructor,
+                                   isolate->factory()->class_script_symbol(),
+                                   script, STRICT));
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate,
+      Object::SetProperty(
+          constructor, isolate->factory()->class_start_position_symbol(),
+          handle(Smi::FromInt(start_position), isolate), STRICT));
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate, Object::SetProperty(
+                   constructor, isolate->factory()->class_end_position_symbol(),
+                   handle(Smi::FromInt(end_position), isolate), STRICT));
+
+  return *constructor;
+}
+
+
+RUNTIME_FUNCTION(Runtime_DefineClassMethod) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 2);
+
+  uint32_t index;
+  if (key->ToArrayIndex(&index)) {
+    RETURN_FAILURE_ON_EXCEPTION(
+        isolate, JSObject::SetOwnElement(object, index, function, STRICT));
+  }
+
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Runtime::ToName(isolate, key));
+  if (name->AsArrayIndex(&index)) {
+    RETURN_FAILURE_ON_EXCEPTION(
+        isolate, JSObject::SetOwnElement(object, index, function, STRICT));
+  } else {
+    RETURN_FAILURE_ON_EXCEPTION(
+        isolate,
+        JSObject::SetOwnPropertyIgnoreAttributes(object, name, function, NONE));
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DefineClassGetter) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, getter, 2);
+
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Runtime::ToName(isolate, key));
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate,
+      JSObject::DefineAccessor(object, name, getter,
+                               isolate->factory()->null_value(), NONE));
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DefineClassSetter) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, setter, 2);
+
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Runtime::ToName(isolate, key));
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate,
+      JSObject::DefineAccessor(object, name, isolate->factory()->null_value(),
+                               setter, NONE));
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_ClassGetSourceCode) {
+  HandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
+
+  Handle<Object> script;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, script,
+      Object::GetProperty(fun, isolate->factory()->class_script_symbol()));
+  if (!script->IsScript()) {
+    return isolate->heap()->undefined_value();
+  }
+
+  Handle<Symbol> start_position_symbol(
+      isolate->heap()->class_start_position_symbol());
+  Handle<Object> start_position;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, start_position, Object::GetProperty(fun, start_position_symbol));
+
+  Handle<Symbol> end_position_symbol(
+      isolate->heap()->class_end_position_symbol());
+  Handle<Object> end_position;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, end_position, Object::GetProperty(fun, end_position_symbol));
+
+  if (!start_position->IsSmi() || !end_position->IsSmi() ||
+      !Handle<Script>::cast(script)->HasValidSource()) {
+    return isolate->ThrowIllegalOperation();
+  }
+
+  Handle<String> source(String::cast(Handle<Script>::cast(script)->source()));
+  return *isolate->factory()->NewSubString(
+      source, Handle<Smi>::cast(start_position)->value(),
+      Handle<Smi>::cast(end_position)->value());
+}
+
+
+static Object* LoadFromSuper(Isolate* isolate, Handle<Object> receiver,
+                             Handle<JSObject> home_object, Handle<Name> name) {
+  if (home_object->IsAccessCheckNeeded() &&
+      !isolate->MayNamedAccess(home_object, name, v8::ACCESS_GET)) {
+    isolate->ReportFailedAccessCheck(home_object, v8::ACCESS_GET);
+    RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
+  }
+
+  PrototypeIterator iter(isolate, home_object);
+  Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
+  if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value();
+
+  LookupIterator it(receiver, name, Handle<JSReceiver>::cast(proto));
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
+  return *result;
+}
+
+
+static Object* LoadElementFromSuper(Isolate* isolate, Handle<Object> receiver,
+                                    Handle<JSObject> home_object,
+                                    uint32_t index) {
+  if (home_object->IsAccessCheckNeeded() &&
+      !isolate->MayIndexedAccess(home_object, index, v8::ACCESS_GET)) {
+    isolate->ReportFailedAccessCheck(home_object, v8::ACCESS_GET);
+    RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
+  }
+
+  PrototypeIterator iter(isolate, home_object);
+  Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
+  if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value();
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Object::GetElementWithReceiver(isolate, proto, receiver, index));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
+
+  return LoadFromSuper(isolate, receiver, home_object, name);
+}
+
+
+RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
+
+  uint32_t index;
+  if (key->ToArrayIndex(&index)) {
+    return LoadElementFromSuper(isolate, receiver, home_object, index);
+  }
+
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Runtime::ToName(isolate, key));
+  if (name->AsArrayIndex(&index)) {
+    return LoadElementFromSuper(isolate, receiver, home_object, index);
+  }
+  return LoadFromSuper(isolate, receiver, home_object, name);
+}
+
+
+static Object* StoreToSuper(Isolate* isolate, Handle<JSObject> home_object,
+                            Handle<Object> receiver, Handle<Name> name,
+                            Handle<Object> value, StrictMode strict_mode) {
+  if (home_object->IsAccessCheckNeeded() &&
+      !isolate->MayNamedAccess(home_object, name, v8::ACCESS_SET)) {
+    isolate->ReportFailedAccessCheck(home_object, v8::ACCESS_SET);
+    RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
+  }
+
+  PrototypeIterator iter(isolate, home_object);
+  Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
+  if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value();
+
+  LookupIterator it(receiver, name, Handle<JSReceiver>::cast(proto));
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Object::SetProperty(&it, value, strict_mode,
+                          Object::CERTAINLY_NOT_STORE_FROM_KEYED,
+                          Object::SUPER_PROPERTY));
+  return *result;
+}
+
+
+static Object* StoreElementToSuper(Isolate* isolate,
+                                   Handle<JSObject> home_object,
+                                   Handle<Object> receiver, uint32_t index,
+                                   Handle<Object> value,
+                                   StrictMode strict_mode) {
+  if (home_object->IsAccessCheckNeeded() &&
+      !isolate->MayIndexedAccess(home_object, index, v8::ACCESS_SET)) {
+    isolate->ReportFailedAccessCheck(home_object, v8::ACCESS_SET);
+    RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
+  }
+
+  PrototypeIterator iter(isolate, home_object);
+  Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
+  if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value();
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Object::SetElementWithReceiver(isolate, proto, receiver, index, value,
+                                     strict_mode));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_StoreToSuper_Strict) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
+
+  return StoreToSuper(isolate, home_object, receiver, name, value, STRICT);
+}
+
+
+RUNTIME_FUNCTION(Runtime_StoreToSuper_Sloppy) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
+
+  return StoreToSuper(isolate, home_object, receiver, name, value, SLOPPY);
+}
+
+
+static Object* StoreKeyedToSuper(Isolate* isolate, Handle<JSObject> home_object,
+                                 Handle<Object> receiver, Handle<Object> key,
+                                 Handle<Object> value, StrictMode strict_mode) {
+  uint32_t index;
+
+  if (key->ToArrayIndex(&index)) {
+    return StoreElementToSuper(isolate, home_object, receiver, index, value,
+                               strict_mode);
+  }
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Runtime::ToName(isolate, key));
+  if (name->AsArrayIndex(&index)) {
+    return StoreElementToSuper(isolate, home_object, receiver, index, value,
+                               strict_mode);
+  }
+  return StoreToSuper(isolate, home_object, receiver, name, value, strict_mode);
+}
+
+
+RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Strict) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
+
+  return StoreKeyedToSuper(isolate, home_object, receiver, key, value, STRICT);
+}
+
+
+RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Sloppy) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
+
+  return StoreKeyedToSuper(isolate, home_object, receiver, key, value, SLOPPY);
+}
+
+
+RUNTIME_FUNCTION(Runtime_DefaultConstructorSuperCall) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+
+  // Compute the frame holding the arguments.
+  JavaScriptFrameIterator it(isolate);
+  it.AdvanceToArgumentsFrame();
+  JavaScriptFrame* frame = it.frame();
+
+  Handle<JSFunction> function(frame->function(), isolate);
+  Handle<Object> receiver(frame->receiver(), isolate);
+
+  Handle<Object> proto_function;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, proto_function,
+                                     Runtime::GetPrototype(isolate, function));
+
+  // Get the actual number of provided arguments.
+  const int argc = frame->ComputeParametersCount();
+
+  // Loose upper bound to allow fuzzing. We'll most likely run out of
+  // stack space before hitting this limit.
+  static int kMaxArgc = 1000000;
+  RUNTIME_ASSERT(argc >= 0 && argc <= kMaxArgc);
+
+  // If there are too many arguments, allocate argv via malloc.
+  const int argv_small_size = 10;
+  Handle<Object> argv_small_buffer[argv_small_size];
+  SmartArrayPointer<Handle<Object> > argv_large_buffer;
+  Handle<Object>* argv = argv_small_buffer;
+  if (argc > argv_small_size) {
+    argv = new Handle<Object>[argc];
+    if (argv == NULL) return isolate->StackOverflow();
+    argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
+  }
+
+  for (int i = 0; i < argc; ++i) {
+    argv[i] = handle(frame->GetParameter(i), isolate);
+  }
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Execution::Call(isolate, proto_function, receiver, argc, argv, false));
+  return *result;
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-collections.cc b/src/runtime/runtime-collections.cc
new file mode 100644
index 0000000..abdd056
--- /dev/null
+++ b/src/runtime/runtime-collections.cc
@@ -0,0 +1,427 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/runtime/runtime-utils.h"
+
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_SetInitialize) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
+  Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
+  holder->set_table(*table);
+  return *holder;
+}
+
+
+RUNTIME_FUNCTION(Runtime_SetAdd) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
+  table = OrderedHashSet::Add(table, key);
+  holder->set_table(*table);
+  return *holder;
+}
+
+
+RUNTIME_FUNCTION(Runtime_SetHas) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
+  return isolate->heap()->ToBoolean(table->Contains(key));
+}
+
+
+RUNTIME_FUNCTION(Runtime_SetDelete) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
+  bool was_present = false;
+  table = OrderedHashSet::Remove(table, key, &was_present);
+  holder->set_table(*table);
+  return isolate->heap()->ToBoolean(was_present);
+}
+
+
+RUNTIME_FUNCTION(Runtime_SetClear) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
+  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
+  table = OrderedHashSet::Clear(table);
+  holder->set_table(*table);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_SetGetSize) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
+  Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
+  return Smi::FromInt(table->NumberOfElements());
+}
+
+
+RUNTIME_FUNCTION(Runtime_SetIteratorInitialize) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSSet, set, 1);
+  CONVERT_SMI_ARG_CHECKED(kind, 2)
+  RUNTIME_ASSERT(kind == JSSetIterator::kKindValues ||
+                 kind == JSSetIterator::kKindEntries);
+  Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
+  holder->set_table(*table);
+  holder->set_index(Smi::FromInt(0));
+  holder->set_kind(Smi::FromInt(kind));
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_SetIteratorClone) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
+
+  Handle<JSSetIterator> result = isolate->factory()->NewJSSetIterator();
+  result->set_table(holder->table());
+  result->set_index(Smi::FromInt(Smi::cast(holder->index())->value()));
+  result->set_kind(Smi::FromInt(Smi::cast(holder->kind())->value()));
+
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_SetIteratorNext) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_CHECKED(JSSetIterator, holder, 0);
+  CONVERT_ARG_CHECKED(JSArray, value_array, 1);
+  return holder->Next(value_array);
+}
+
+
+// The array returned contains the following information:
+// 0: HasMore flag
+// 1: Iteration index
+// 2: Iteration kind
+RUNTIME_FUNCTION(Runtime_SetIteratorDetails) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
+  Handle<FixedArray> details = isolate->factory()->NewFixedArray(4);
+  details->set(0, isolate->heap()->ToBoolean(holder->HasMore()));
+  details->set(1, holder->index());
+  details->set(2, holder->kind());
+  return *isolate->factory()->NewJSArrayWithElements(details);
+}
+
+
+RUNTIME_FUNCTION(Runtime_MapInitialize) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
+  Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
+  holder->set_table(*table);
+  return *holder;
+}
+
+
+RUNTIME_FUNCTION(Runtime_MapGet) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
+  Handle<Object> lookup(table->Lookup(key), isolate);
+  return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
+}
+
+
+RUNTIME_FUNCTION(Runtime_MapHas) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
+  Handle<Object> lookup(table->Lookup(key), isolate);
+  return isolate->heap()->ToBoolean(!lookup->IsTheHole());
+}
+
+
+RUNTIME_FUNCTION(Runtime_MapDelete) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
+  bool was_present = false;
+  Handle<OrderedHashMap> new_table =
+      OrderedHashMap::Remove(table, key, &was_present);
+  holder->set_table(*new_table);
+  return isolate->heap()->ToBoolean(was_present);
+}
+
+
+RUNTIME_FUNCTION(Runtime_MapClear) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
+  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
+  table = OrderedHashMap::Clear(table);
+  holder->set_table(*table);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_MapSet) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
+  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
+  Handle<OrderedHashMap> new_table = OrderedHashMap::Put(table, key, value);
+  holder->set_table(*new_table);
+  return *holder;
+}
+
+
+RUNTIME_FUNCTION(Runtime_MapGetSize) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
+  Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
+  return Smi::FromInt(table->NumberOfElements());
+}
+
+
+RUNTIME_FUNCTION(Runtime_MapIteratorInitialize) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSMap, map, 1);
+  CONVERT_SMI_ARG_CHECKED(kind, 2)
+  RUNTIME_ASSERT(kind == JSMapIterator::kKindKeys ||
+                 kind == JSMapIterator::kKindValues ||
+                 kind == JSMapIterator::kKindEntries);
+  Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
+  holder->set_table(*table);
+  holder->set_index(Smi::FromInt(0));
+  holder->set_kind(Smi::FromInt(kind));
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_MapIteratorClone) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
+
+  Handle<JSMapIterator> result = isolate->factory()->NewJSMapIterator();
+  result->set_table(holder->table());
+  result->set_index(Smi::FromInt(Smi::cast(holder->index())->value()));
+  result->set_kind(Smi::FromInt(Smi::cast(holder->kind())->value()));
+
+  return *result;
+}
+
+
+// The array returned contains the following information:
+// 0: HasMore flag
+// 1: Iteration index
+// 2: Iteration kind
+RUNTIME_FUNCTION(Runtime_MapIteratorDetails) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
+  Handle<FixedArray> details = isolate->factory()->NewFixedArray(4);
+  details->set(0, isolate->heap()->ToBoolean(holder->HasMore()));
+  details->set(1, holder->index());
+  details->set(2, holder->kind());
+  return *isolate->factory()->NewJSArrayWithElements(details);
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetWeakMapEntries) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
+  CONVERT_NUMBER_CHECKED(int, max_entries, Int32, args[1]);
+  RUNTIME_ASSERT(max_entries >= 0);
+
+  Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
+  if (max_entries == 0 || max_entries > table->NumberOfElements()) {
+    max_entries = table->NumberOfElements();
+  }
+  Handle<FixedArray> entries =
+      isolate->factory()->NewFixedArray(max_entries * 2);
+  {
+    DisallowHeapAllocation no_gc;
+    int count = 0;
+    for (int i = 0; count / 2 < max_entries && i < table->Capacity(); i++) {
+      Handle<Object> key(table->KeyAt(i), isolate);
+      if (table->IsKey(*key)) {
+        entries->set(count++, *key);
+        Object* value = table->Lookup(key);
+        entries->set(count++, value);
+      }
+    }
+    DCHECK_EQ(max_entries * 2, count);
+  }
+  return *isolate->factory()->NewJSArrayWithElements(entries);
+}
+
+
+RUNTIME_FUNCTION(Runtime_MapIteratorNext) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_CHECKED(JSMapIterator, holder, 0);
+  CONVERT_ARG_CHECKED(JSArray, value_array, 1);
+  return holder->Next(value_array);
+}
+
+
+static Handle<JSWeakCollection> WeakCollectionInitialize(
+    Isolate* isolate, Handle<JSWeakCollection> weak_collection) {
+  DCHECK(weak_collection->map()->inobject_properties() == 0);
+  Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
+  weak_collection->set_table(*table);
+  return weak_collection;
+}
+
+
+RUNTIME_FUNCTION(Runtime_WeakCollectionInitialize) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
+  return *WeakCollectionInitialize(isolate, weak_collection);
+}
+
+
+RUNTIME_FUNCTION(Runtime_WeakCollectionGet) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
+  Handle<ObjectHashTable> table(
+      ObjectHashTable::cast(weak_collection->table()));
+  RUNTIME_ASSERT(table->IsKey(*key));
+  Handle<Object> lookup(table->Lookup(key), isolate);
+  return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
+}
+
+
+RUNTIME_FUNCTION(Runtime_WeakCollectionHas) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
+  Handle<ObjectHashTable> table(
+      ObjectHashTable::cast(weak_collection->table()));
+  RUNTIME_ASSERT(table->IsKey(*key));
+  Handle<Object> lookup(table->Lookup(key), isolate);
+  return isolate->heap()->ToBoolean(!lookup->IsTheHole());
+}
+
+
+RUNTIME_FUNCTION(Runtime_WeakCollectionDelete) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
+  Handle<ObjectHashTable> table(
+      ObjectHashTable::cast(weak_collection->table()));
+  RUNTIME_ASSERT(table->IsKey(*key));
+  bool was_present = false;
+  Handle<ObjectHashTable> new_table =
+      ObjectHashTable::Remove(table, key, &was_present);
+  weak_collection->set_table(*new_table);
+  if (*table != *new_table) {
+    // Zap the old table since we didn't record slots for its elements.
+    table->FillWithHoles(0, table->length());
+  }
+  return isolate->heap()->ToBoolean(was_present);
+}
+
+
+RUNTIME_FUNCTION(Runtime_WeakCollectionSet) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
+  Handle<ObjectHashTable> table(
+      ObjectHashTable::cast(weak_collection->table()));
+  RUNTIME_ASSERT(table->IsKey(*key));
+  Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value);
+  weak_collection->set_table(*new_table);
+  if (*table != *new_table) {
+    // Zap the old table since we didn't record slots for its elements.
+    table->FillWithHoles(0, table->length());
+  }
+  return *weak_collection;
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetWeakSetValues) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
+  CONVERT_NUMBER_CHECKED(int, max_values, Int32, args[1]);
+  RUNTIME_ASSERT(max_values >= 0);
+
+  Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
+  if (max_values == 0 || max_values > table->NumberOfElements()) {
+    max_values = table->NumberOfElements();
+  }
+  Handle<FixedArray> values = isolate->factory()->NewFixedArray(max_values);
+  // Recompute max_values because GC could have removed elements from the table.
+  if (max_values > table->NumberOfElements()) {
+    max_values = table->NumberOfElements();
+  }
+  {
+    DisallowHeapAllocation no_gc;
+    int count = 0;
+    for (int i = 0; count < max_values && i < table->Capacity(); i++) {
+      Handle<Object> key(table->KeyAt(i), isolate);
+      if (table->IsKey(*key)) values->set(count++, *key);
+    }
+    DCHECK_EQ(max_values, count);
+  }
+  return *isolate->factory()->NewJSArrayWithElements(values);
+}
+
+
+RUNTIME_FUNCTION(Runtime_ObservationWeakMapCreate) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+  // TODO(adamk): Currently this runtime function is only called three times per
+  // isolate. If it's called more often, the map should be moved into the
+  // strong root list.
+  Handle<Map> map =
+      isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize);
+  Handle<JSWeakMap> weakmap =
+      Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map));
+  return *WeakCollectionInitialize(isolate, weakmap);
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-compiler.cc b/src/runtime/runtime-compiler.cc
new file mode 100644
index 0000000..ebd0c13
--- /dev/null
+++ b/src/runtime/runtime-compiler.cc
@@ -0,0 +1,451 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/compiler.h"
+#include "src/deoptimizer.h"
+#include "src/frames.h"
+#include "src/full-codegen.h"
+#include "src/isolate-inl.h"
+#include "src/runtime/runtime-utils.h"
+#include "src/v8threads.h"
+#include "src/vm-state-inl.h"
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_CompileLazy) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+#ifdef DEBUG
+  if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
+    PrintF("[unoptimized: ");
+    function->PrintName();
+    PrintF("]\n");
+  }
+#endif
+
+  // Compile the target function.
+  DCHECK(function->shared()->allows_lazy_compilation());
+
+  Handle<Code> code;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, code,
+                                     Compiler::GetLazyCode(function));
+  DCHECK(code->kind() == Code::FUNCTION ||
+         code->kind() == Code::OPTIMIZED_FUNCTION);
+  function->ReplaceCode(*code);
+  return *code;
+}
+
+
+RUNTIME_FUNCTION(Runtime_CompileOptimized) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+  CONVERT_BOOLEAN_ARG_CHECKED(concurrent, 1);
+  DCHECK(isolate->use_crankshaft());
+
+  Handle<Code> unoptimized(function->shared()->code());
+  if (function->shared()->optimization_disabled() ||
+      isolate->DebuggerHasBreakPoints()) {
+    // If the function is not optimizable or debugger is active continue
+    // using the code from the full compiler.
+    if (FLAG_trace_opt) {
+      PrintF("[failed to optimize ");
+      function->PrintName();
+      PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
+             function->shared()->optimization_disabled() ? "F" : "T",
+             isolate->DebuggerHasBreakPoints() ? "T" : "F");
+    }
+    function->ReplaceCode(*unoptimized);
+    return function->code();
+  }
+
+  Compiler::ConcurrencyMode mode =
+      concurrent ? Compiler::CONCURRENT : Compiler::NOT_CONCURRENT;
+  Handle<Code> code;
+  if (Compiler::GetOptimizedCode(function, unoptimized, mode).ToHandle(&code)) {
+    function->ReplaceCode(*code);
+  } else {
+    function->ReplaceCode(function->shared()->code());
+  }
+
+  DCHECK(function->code()->kind() == Code::FUNCTION ||
+         function->code()->kind() == Code::OPTIMIZED_FUNCTION ||
+         function->IsInOptimizationQueue());
+  return function->code();
+}
+
+
+RUNTIME_FUNCTION(Runtime_NotifyStubFailure) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+  Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
+  DCHECK(AllowHeapAllocation::IsAllowed());
+  delete deoptimizer;
+  return isolate->heap()->undefined_value();
+}
+
+
+class ActivationsFinder : public ThreadVisitor {
+ public:
+  Code* code_;
+  bool has_code_activations_;
+
+  explicit ActivationsFinder(Code* code)
+      : code_(code), has_code_activations_(false) {}
+
+  void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
+    JavaScriptFrameIterator it(isolate, top);
+    VisitFrames(&it);
+  }
+
+  void VisitFrames(JavaScriptFrameIterator* it) {
+    for (; !it->done(); it->Advance()) {
+      JavaScriptFrame* frame = it->frame();
+      if (code_->contains(frame->pc())) has_code_activations_ = true;
+    }
+  }
+};
+
+
+RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_SMI_ARG_CHECKED(type_arg, 0);
+  Deoptimizer::BailoutType type =
+      static_cast<Deoptimizer::BailoutType>(type_arg);
+  Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
+  DCHECK(AllowHeapAllocation::IsAllowed());
+
+  Handle<JSFunction> function = deoptimizer->function();
+  Handle<Code> optimized_code = deoptimizer->compiled_code();
+
+  DCHECK(optimized_code->kind() == Code::OPTIMIZED_FUNCTION);
+  DCHECK(type == deoptimizer->bailout_type());
+
+  // Make sure to materialize objects before causing any allocation.
+  JavaScriptFrameIterator it(isolate);
+  deoptimizer->MaterializeHeapObjects(&it);
+  delete deoptimizer;
+
+  JavaScriptFrame* frame = it.frame();
+  RUNTIME_ASSERT(frame->function()->IsJSFunction());
+  DCHECK(frame->function() == *function);
+
+  // Avoid doing too much work when running with --always-opt and keep
+  // the optimized code around.
+  if (FLAG_always_opt || type == Deoptimizer::LAZY) {
+    return isolate->heap()->undefined_value();
+  }
+
+  // Search for other activations of the same function and code.
+  ActivationsFinder activations_finder(*optimized_code);
+  activations_finder.VisitFrames(&it);
+  isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
+
+  if (!activations_finder.has_code_activations_) {
+    if (function->code() == *optimized_code) {
+      if (FLAG_trace_deopt) {
+        PrintF("[removing optimized code for: ");
+        function->PrintName();
+        PrintF("]\n");
+      }
+      function->ReplaceCode(function->shared()->code());
+      // Evict optimized code for this function from the cache so that it
+      // doesn't get used for new closures.
+      function->shared()->EvictFromOptimizedCodeMap(*optimized_code,
+                                                    "notify deoptimized");
+    }
+  } else {
+    // TODO(titzer): we should probably do DeoptimizeCodeList(code)
+    // unconditionally if the code is not already marked for deoptimization.
+    // If there is an index by shared function info, all the better.
+    Deoptimizer::DeoptimizeFunction(*function);
+  }
+
+  return isolate->heap()->undefined_value();
+}
+
+
+static bool IsSuitableForOnStackReplacement(Isolate* isolate,
+                                            Handle<JSFunction> function,
+                                            Handle<Code> current_code) {
+  // Keep track of whether we've succeeded in optimizing.
+  if (!current_code->optimizable()) return false;
+  // If we are trying to do OSR when there are already optimized
+  // activations of the function, it means (a) the function is directly or
+  // indirectly recursive and (b) an optimized invocation has been
+  // deoptimized so that we are currently in an unoptimized activation.
+  // Check for optimized activations of this function.
+  for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
+    JavaScriptFrame* frame = it.frame();
+    if (frame->is_optimized() && frame->function() == *function) return false;
+  }
+
+  return true;
+}
+
+
+RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+  Handle<Code> caller_code(function->shared()->code());
+
+  // We're not prepared to handle a function with arguments object.
+  DCHECK(!function->shared()->uses_arguments());
+
+  RUNTIME_ASSERT(FLAG_use_osr);
+
+  // Passing the PC in the javascript frame from the caller directly is
+  // not GC safe, so we walk the stack to get it.
+  JavaScriptFrameIterator it(isolate);
+  JavaScriptFrame* frame = it.frame();
+  if (!caller_code->contains(frame->pc())) {
+    // Code on the stack may not be the code object referenced by the shared
+    // function info.  It may have been replaced to include deoptimization data.
+    caller_code = Handle<Code>(frame->LookupCode());
+  }
+
+  uint32_t pc_offset =
+      static_cast<uint32_t>(frame->pc() - caller_code->instruction_start());
+
+#ifdef DEBUG
+  DCHECK_EQ(frame->function(), *function);
+  DCHECK_EQ(frame->LookupCode(), *caller_code);
+  DCHECK(caller_code->contains(frame->pc()));
+#endif  // DEBUG
+
+
+  BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset);
+  DCHECK(!ast_id.IsNone());
+
+  Compiler::ConcurrencyMode mode =
+      isolate->concurrent_osr_enabled() &&
+              (function->shared()->ast_node_count() > 512)
+          ? Compiler::CONCURRENT
+          : Compiler::NOT_CONCURRENT;
+  Handle<Code> result = Handle<Code>::null();
+
+  OptimizedCompileJob* job = NULL;
+  if (mode == Compiler::CONCURRENT) {
+    // Gate the OSR entry with a stack check.
+    BackEdgeTable::AddStackCheck(caller_code, pc_offset);
+    // Poll already queued compilation jobs.
+    OptimizingCompilerThread* thread = isolate->optimizing_compiler_thread();
+    if (thread->IsQueuedForOSR(function, ast_id)) {
+      if (FLAG_trace_osr) {
+        PrintF("[OSR - Still waiting for queued: ");
+        function->PrintName();
+        PrintF(" at AST id %d]\n", ast_id.ToInt());
+      }
+      return NULL;
+    }
+
+    job = thread->FindReadyOSRCandidate(function, ast_id);
+  }
+
+  if (job != NULL) {
+    if (FLAG_trace_osr) {
+      PrintF("[OSR - Found ready: ");
+      function->PrintName();
+      PrintF(" at AST id %d]\n", ast_id.ToInt());
+    }
+    result = Compiler::GetConcurrentlyOptimizedCode(job);
+  } else if (IsSuitableForOnStackReplacement(isolate, function, caller_code)) {
+    if (FLAG_trace_osr) {
+      PrintF("[OSR - Compiling: ");
+      function->PrintName();
+      PrintF(" at AST id %d]\n", ast_id.ToInt());
+    }
+    MaybeHandle<Code> maybe_result =
+        Compiler::GetOptimizedCode(function, caller_code, mode, ast_id);
+    if (maybe_result.ToHandle(&result) &&
+        result.is_identical_to(isolate->builtins()->InOptimizationQueue())) {
+      // Optimization is queued.  Return to check later.
+      return NULL;
+    }
+  }
+
+  // Revert the patched back edge table, regardless of whether OSR succeeds.
+  BackEdgeTable::Revert(isolate, *caller_code);
+
+  // Check whether we ended up with usable optimized code.
+  if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) {
+    DeoptimizationInputData* data =
+        DeoptimizationInputData::cast(result->deoptimization_data());
+
+    if (data->OsrPcOffset()->value() >= 0) {
+      DCHECK(BailoutId(data->OsrAstId()->value()) == ast_id);
+      if (FLAG_trace_osr) {
+        PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n",
+               ast_id.ToInt(), data->OsrPcOffset()->value());
+      }
+      // TODO(titzer): this is a massive hack to make the deopt counts
+      // match. Fix heuristics for reenabling optimizations!
+      function->shared()->increment_deopt_count();
+
+      // TODO(titzer): Do not install code into the function.
+      function->ReplaceCode(*result);
+      return *result;
+    }
+  }
+
+  // Failed.
+  if (FLAG_trace_osr) {
+    PrintF("[OSR - Failed: ");
+    function->PrintName();
+    PrintF(" at AST id %d]\n", ast_id.ToInt());
+  }
+
+  if (!function->IsOptimized()) {
+    function->ReplaceCode(function->shared()->code());
+  }
+  return NULL;
+}
+
+
+RUNTIME_FUNCTION(Runtime_TryInstallOptimizedCode) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+
+  // First check if this is a real stack overflow.
+  StackLimitCheck check(isolate);
+  if (check.JsHasOverflowed()) {
+    SealHandleScope shs(isolate);
+    return isolate->StackOverflow();
+  }
+
+  isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
+  return (function->IsOptimized()) ? function->code()
+                                   : function->shared()->code();
+}
+
+
+bool CodeGenerationFromStringsAllowed(Isolate* isolate,
+                                      Handle<Context> context) {
+  DCHECK(context->allow_code_gen_from_strings()->IsFalse());
+  // Check with callback if set.
+  AllowCodeGenerationFromStringsCallback callback =
+      isolate->allow_code_gen_callback();
+  if (callback == NULL) {
+    // No callback set and code generation disallowed.
+    return false;
+  } else {
+    // Callback set. Let it decide if code generation is allowed.
+    VMState<EXTERNAL> state(isolate);
+    return callback(v8::Utils::ToLocal(context));
+  }
+}
+
+
+RUNTIME_FUNCTION(Runtime_CompileString) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
+  CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1);
+  CONVERT_SMI_ARG_CHECKED(source_offset, 2);
+
+  // Extract native context.
+  Handle<Context> context(isolate->native_context());
+
+  // Check if native context allows code generation from
+  // strings. Throw an exception if it doesn't.
+  if (context->allow_code_gen_from_strings()->IsFalse() &&
+      !CodeGenerationFromStringsAllowed(isolate, context)) {
+    Handle<Object> error_message =
+        context->ErrorMessageForCodeGenerationFromStrings();
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewEvalError("code_gen_from_strings",
+                              HandleVector<Object>(&error_message, 1)));
+  }
+
+  // Compile source string in the native context.
+  ParseRestriction restriction = function_literal_only
+                                     ? ONLY_SINGLE_FUNCTION_LITERAL
+                                     : NO_PARSE_RESTRICTION;
+  Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate);
+  Handle<JSFunction> fun;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, fun,
+      Compiler::GetFunctionFromEval(source, outer_info, context, SLOPPY,
+                                    restriction, RelocInfo::kNoPosition));
+  if (function_literal_only) {
+    // The actual body is wrapped, which shifts line numbers.
+    Handle<Script> script(Script::cast(fun->shared()->script()), isolate);
+    if (script->line_offset() == 0) {
+      int line_num = Script::GetLineNumber(script, source_offset);
+      script->set_line_offset(Smi::FromInt(-line_num));
+    }
+  }
+  return *fun;
+}
+
+
+static ObjectPair CompileGlobalEval(Isolate* isolate, Handle<String> source,
+                                    Handle<SharedFunctionInfo> outer_info,
+                                    Handle<Object> receiver,
+                                    StrictMode strict_mode,
+                                    int scope_position) {
+  Handle<Context> context = Handle<Context>(isolate->context());
+  Handle<Context> native_context = Handle<Context>(context->native_context());
+
+  // Check if native context allows code generation from
+  // strings. Throw an exception if it doesn't.
+  if (native_context->allow_code_gen_from_strings()->IsFalse() &&
+      !CodeGenerationFromStringsAllowed(isolate, native_context)) {
+    Handle<Object> error_message =
+        native_context->ErrorMessageForCodeGenerationFromStrings();
+    Handle<Object> error;
+    MaybeHandle<Object> maybe_error = isolate->factory()->NewEvalError(
+        "code_gen_from_strings", HandleVector<Object>(&error_message, 1));
+    if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
+    return MakePair(isolate->heap()->exception(), NULL);
+  }
+
+  // Deal with a normal eval call with a string argument. Compile it
+  // and return the compiled function bound in the local context.
+  static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
+  Handle<JSFunction> compiled;
+  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+      isolate, compiled,
+      Compiler::GetFunctionFromEval(source, outer_info, context, strict_mode,
+                                    restriction, scope_position),
+      MakePair(isolate->heap()->exception(), NULL));
+  return MakePair(*compiled, *receiver);
+}
+
+
+RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ResolvePossiblyDirectEval) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 6);
+
+  Handle<Object> callee = args.at<Object>(0);
+
+  // If "eval" didn't refer to the original GlobalEval, it's not a
+  // direct call to eval.
+  // (And even if it is, but the first argument isn't a string, just let
+  // execution default to an indirect call to eval, which will also return
+  // the first argument without doing anything).
+  if (*callee != isolate->native_context()->global_eval_fun() ||
+      !args[1]->IsString()) {
+    return MakePair(*callee, isolate->heap()->undefined_value());
+  }
+
+  DCHECK(args[4]->IsSmi());
+  DCHECK(args.smi_at(4) == SLOPPY || args.smi_at(4) == STRICT);
+  StrictMode strict_mode = static_cast<StrictMode>(args.smi_at(4));
+  DCHECK(args[5]->IsSmi());
+  Handle<SharedFunctionInfo> outer_info(args.at<JSFunction>(2)->shared(),
+                                        isolate);
+  return CompileGlobalEval(isolate, args.at<String>(1), outer_info,
+                           args.at<Object>(3), strict_mode, args.smi_at(5));
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-date.cc b/src/runtime/runtime-date.cc
new file mode 100644
index 0000000..65d8fc6
--- /dev/null
+++ b/src/runtime/runtime-date.cc
@@ -0,0 +1,189 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/date.h"
+#include "src/dateparser-inl.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_DateMakeDay) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_SMI_ARG_CHECKED(year, 0);
+  CONVERT_SMI_ARG_CHECKED(month, 1);
+
+  int days = isolate->date_cache()->DaysFromYearMonth(year, month);
+  RUNTIME_ASSERT(Smi::IsValid(days));
+  return Smi::FromInt(days);
+}
+
+
+RUNTIME_FUNCTION(Runtime_DateSetValue) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
+  CONVERT_DOUBLE_ARG_CHECKED(time, 1);
+  CONVERT_SMI_ARG_CHECKED(is_utc, 2);
+
+  DateCache* date_cache = isolate->date_cache();
+
+  Handle<Object> value;
+  ;
+  bool is_value_nan = false;
+  if (std::isnan(time)) {
+    value = isolate->factory()->nan_value();
+    is_value_nan = true;
+  } else if (!is_utc && (time < -DateCache::kMaxTimeBeforeUTCInMs ||
+                         time > DateCache::kMaxTimeBeforeUTCInMs)) {
+    value = isolate->factory()->nan_value();
+    is_value_nan = true;
+  } else {
+    time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
+    if (time < -DateCache::kMaxTimeInMs || time > DateCache::kMaxTimeInMs) {
+      value = isolate->factory()->nan_value();
+      is_value_nan = true;
+    } else {
+      value = isolate->factory()->NewNumber(DoubleToInteger(time));
+    }
+  }
+  date->SetValue(*value, is_value_nan);
+  return *value;
+}
+
+
+RUNTIME_FUNCTION(Runtime_ThrowNotDateError) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+  THROW_NEW_ERROR_RETURN_FAILURE(
+      isolate, NewTypeError("not_date_object", HandleVector<Object>(NULL, 0)));
+}
+
+
+RUNTIME_FUNCTION(Runtime_DateCurrentTime) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+  if (FLAG_log_timer_events) LOG(isolate, CurrentTimeEvent());
+
+  // According to ECMA-262, section 15.9.1, page 117, the precision of
+  // the number in a Date object representing a particular instant in
+  // time is milliseconds. Therefore, we floor the result of getting
+  // the OS time.
+  double millis;
+  if (FLAG_verify_predictable) {
+    millis = 1388534400000.0;  // Jan 1 2014 00:00:00 GMT+0000
+    millis += Floor(isolate->heap()->synthetic_time());
+  } else {
+    millis = Floor(base::OS::TimeCurrentMillis());
+  }
+  return *isolate->factory()->NewNumber(millis);
+}
+
+
+RUNTIME_FUNCTION(Runtime_DateParseString) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
+
+  RUNTIME_ASSERT(output->HasFastElements());
+  JSObject::EnsureCanContainHeapObjectElements(output);
+  RUNTIME_ASSERT(output->HasFastObjectElements());
+  Handle<FixedArray> output_array(FixedArray::cast(output->elements()));
+  RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
+
+  str = String::Flatten(str);
+  DisallowHeapAllocation no_gc;
+
+  bool result;
+  String::FlatContent str_content = str->GetFlatContent();
+  if (str_content.IsOneByte()) {
+    result = DateParser::Parse(str_content.ToOneByteVector(), *output_array,
+                               isolate->unicode_cache());
+  } else {
+    DCHECK(str_content.IsTwoByte());
+    result = DateParser::Parse(str_content.ToUC16Vector(), *output_array,
+                               isolate->unicode_cache());
+  }
+
+  if (result) {
+    return *output;
+  } else {
+    return isolate->heap()->null_value();
+  }
+}
+
+
+RUNTIME_FUNCTION(Runtime_DateLocalTimezone) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs &&
+                 x <= DateCache::kMaxTimeBeforeUTCInMs);
+  const char* zone =
+      isolate->date_cache()->LocalTimezone(static_cast<int64_t>(x));
+  Handle<String> result =
+      isolate->factory()->NewStringFromUtf8(CStrVector(zone)).ToHandleChecked();
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_DateToUTC) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs &&
+                 x <= DateCache::kMaxTimeBeforeUTCInMs);
+  int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
+
+  return *isolate->factory()->NewNumber(static_cast<double>(time));
+}
+
+
+RUNTIME_FUNCTION(Runtime_DateCacheVersion) {
+  HandleScope hs(isolate);
+  DCHECK(args.length() == 0);
+  if (!isolate->eternal_handles()->Exists(EternalHandles::DATE_CACHE_VERSION)) {
+    Handle<FixedArray> date_cache_version =
+        isolate->factory()->NewFixedArray(1, TENURED);
+    date_cache_version->set(0, Smi::FromInt(0));
+    isolate->eternal_handles()->CreateSingleton(
+        isolate, *date_cache_version, EternalHandles::DATE_CACHE_VERSION);
+  }
+  Handle<FixedArray> date_cache_version =
+      Handle<FixedArray>::cast(isolate->eternal_handles()->GetSingleton(
+          EternalHandles::DATE_CACHE_VERSION));
+  // Return result as a JS array.
+  Handle<JSObject> result =
+      isolate->factory()->NewJSObject(isolate->array_function());
+  JSArray::SetContent(Handle<JSArray>::cast(result), date_cache_version);
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_DateField) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  CONVERT_SMI_ARG_CHECKED(index, 1);
+  if (!obj->IsJSDate()) {
+    HandleScope scope(isolate);
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate,
+        NewTypeError("not_date_object", HandleVector<Object>(NULL, 0)));
+  }
+  JSDate* date = JSDate::cast(obj);
+  if (index == 0) return date->value();
+  return JSDate::GetField(date, Smi::FromInt(index));
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-debug.cc b/src/runtime/runtime-debug.cc
new file mode 100644
index 0000000..9b71a4f
--- /dev/null
+++ b/src/runtime/runtime-debug.cc
@@ -0,0 +1,2819 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/accessors.h"
+#include "src/arguments.h"
+#include "src/debug.h"
+#include "src/deoptimizer.h"
+#include "src/isolate-inl.h"
+#include "src/parser.h"
+#include "src/runtime/runtime.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_DebugBreak) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  isolate->debug()->HandleDebugBreak();
+  return isolate->heap()->undefined_value();
+}
+
+
+// Helper functions for wrapping and unwrapping stack frame ids.
+static Smi* WrapFrameId(StackFrame::Id id) {
+  DCHECK(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
+  return Smi::FromInt(id >> 2);
+}
+
+
+static StackFrame::Id UnwrapFrameId(int wrapped) {
+  return static_cast<StackFrame::Id>(wrapped << 2);
+}
+
+
+// Adds a JavaScript function as a debug event listener.
+// args[0]: debug event listener function to set or null or undefined for
+//          clearing the event listener function
+// args[1]: object supplied during callback
+RUNTIME_FUNCTION(Runtime_SetDebugEventListener) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  RUNTIME_ASSERT(args[0]->IsJSFunction() || args[0]->IsUndefined() ||
+                 args[0]->IsNull());
+  CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, data, 1);
+  isolate->debug()->SetEventListener(callback, data);
+
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_Break) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  isolate->stack_guard()->RequestDebugBreak();
+  return isolate->heap()->undefined_value();
+}
+
+
+static Handle<Object> DebugGetProperty(LookupIterator* it,
+                                       bool* has_caught = NULL) {
+  for (; it->IsFound(); it->Next()) {
+    switch (it->state()) {
+      case LookupIterator::NOT_FOUND:
+      case LookupIterator::TRANSITION:
+        UNREACHABLE();
+      case LookupIterator::ACCESS_CHECK:
+        // Ignore access checks.
+        break;
+      case LookupIterator::INTERCEPTOR:
+      case LookupIterator::JSPROXY:
+        return it->isolate()->factory()->undefined_value();
+      case LookupIterator::ACCESSOR: {
+        Handle<Object> accessors = it->GetAccessors();
+        if (!accessors->IsAccessorInfo()) {
+          return it->isolate()->factory()->undefined_value();
+        }
+        MaybeHandle<Object> maybe_result = JSObject::GetPropertyWithAccessor(
+            it->GetReceiver(), it->name(), it->GetHolder<JSObject>(),
+            accessors);
+        Handle<Object> result;
+        if (!maybe_result.ToHandle(&result)) {
+          result = handle(it->isolate()->pending_exception(), it->isolate());
+          it->isolate()->clear_pending_exception();
+          if (has_caught != NULL) *has_caught = true;
+        }
+        return result;
+      }
+
+      case LookupIterator::DATA:
+        return it->GetDataValue();
+    }
+  }
+
+  return it->isolate()->factory()->undefined_value();
+}
+
+
+// Get debugger related details for an object property, in the following format:
+// 0: Property value
+// 1: Property details
+// 2: Property value is exception
+// 3: Getter function if defined
+// 4: Setter function if defined
+// Items 2-4 are only filled if the property has either a getter or a setter.
+RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
+
+  // Make sure to set the current context to the context before the debugger was
+  // entered (if the debugger is entered). The reason for switching context here
+  // is that for some property lookups (accessors and interceptors) callbacks
+  // into the embedding application can occour, and the embedding application
+  // could have the assumption that its own native context is the current
+  // context and not some internal debugger context.
+  SaveContext save(isolate);
+  if (isolate->debug()->in_debug_scope()) {
+    isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
+  }
+
+  // Check if the name is trivially convertible to an index and get the element
+  // if so.
+  uint32_t index;
+  if (name->AsArrayIndex(&index)) {
+    Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
+    Handle<Object> element_or_char;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, element_or_char,
+        Runtime::GetElementOrCharAt(isolate, obj, index));
+    details->set(0, *element_or_char);
+    details->set(1, PropertyDetails(NONE, FIELD, 0).AsSmi());
+    return *isolate->factory()->NewJSArrayWithElements(details);
+  }
+
+  LookupIterator it(obj, name, LookupIterator::HIDDEN);
+  bool has_caught = false;
+  Handle<Object> value = DebugGetProperty(&it, &has_caught);
+  if (!it.IsFound()) return isolate->heap()->undefined_value();
+
+  Handle<Object> maybe_pair;
+  if (it.state() == LookupIterator::ACCESSOR) {
+    maybe_pair = it.GetAccessors();
+  }
+
+  // If the callback object is a fixed array then it contains JavaScript
+  // getter and/or setter.
+  bool has_js_accessors = !maybe_pair.is_null() && maybe_pair->IsAccessorPair();
+  Handle<FixedArray> details =
+      isolate->factory()->NewFixedArray(has_js_accessors ? 6 : 3);
+  details->set(0, *value);
+  // TODO(verwaest): Get rid of this random way of handling interceptors.
+  PropertyDetails d = it.state() == LookupIterator::INTERCEPTOR
+                          ? PropertyDetails(NONE, FIELD, 0)
+                          : it.property_details();
+  details->set(1, d.AsSmi());
+  details->set(
+      2, isolate->heap()->ToBoolean(it.state() == LookupIterator::INTERCEPTOR));
+  if (has_js_accessors) {
+    AccessorPair* accessors = AccessorPair::cast(*maybe_pair);
+    details->set(3, isolate->heap()->ToBoolean(has_caught));
+    details->set(4, accessors->GetComponent(ACCESSOR_GETTER));
+    details->set(5, accessors->GetComponent(ACCESSOR_SETTER));
+  }
+
+  return *isolate->factory()->NewJSArrayWithElements(details);
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugGetProperty) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
+
+  LookupIterator it(obj, name);
+  return *DebugGetProperty(&it);
+}
+
+
+// Return the property type calculated from the property details.
+// args[0]: smi with property details.
+RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
+  return Smi::FromInt(static_cast<int>(details.type()));
+}
+
+
+// Return the property attribute calculated from the property details.
+// args[0]: smi with property details.
+RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
+  return Smi::FromInt(static_cast<int>(details.attributes()));
+}
+
+
+// Return the property insertion index calculated from the property details.
+// args[0]: smi with property details.
+RUNTIME_FUNCTION(Runtime_DebugPropertyIndexFromDetails) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
+  // TODO(verwaest): Works only for dictionary mode holders.
+  return Smi::FromInt(details.dictionary_index());
+}
+
+
+// Return property value from named interceptor.
+// args[0]: object
+// args[1]: property name
+RUNTIME_FUNCTION(Runtime_DebugNamedInterceptorPropertyValue) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+  RUNTIME_ASSERT(obj->HasNamedInterceptor());
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     JSObject::GetProperty(obj, name));
+  return *result;
+}
+
+
+// Return element value from indexed interceptor.
+// args[0]: object
+// args[1]: index
+RUNTIME_FUNCTION(Runtime_DebugIndexedInterceptorElementValue) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+  RUNTIME_ASSERT(obj->HasIndexedInterceptor());
+  CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      JSObject::GetElementWithInterceptor(obj, obj, index, true));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_CheckExecutionState) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+  RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+  return isolate->heap()->true_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetFrameCount) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+  RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+  // Count all frames which are relevant to debugging stack trace.
+  int n = 0;
+  StackFrame::Id id = isolate->debug()->break_frame_id();
+  if (id == StackFrame::NO_ID) {
+    // If there is no JavaScript stack frame count is 0.
+    return Smi::FromInt(0);
+  }
+
+  for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
+    List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
+    it.frame()->Summarize(&frames);
+    for (int i = frames.length() - 1; i >= 0; i--) {
+      // Omit functions from native scripts.
+      if (!frames[i].function()->IsFromNativeScript()) n++;
+    }
+  }
+  return Smi::FromInt(n);
+}
+
+
+class FrameInspector {
+ public:
+  FrameInspector(JavaScriptFrame* frame, int inlined_jsframe_index,
+                 Isolate* isolate)
+      : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
+    // Calculate the deoptimized frame.
+    if (frame->is_optimized()) {
+      deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
+          frame, inlined_jsframe_index, isolate);
+    }
+    has_adapted_arguments_ = frame_->has_adapted_arguments();
+    is_bottommost_ = inlined_jsframe_index == 0;
+    is_optimized_ = frame_->is_optimized();
+  }
+
+  ~FrameInspector() {
+    // Get rid of the calculated deoptimized frame if any.
+    if (deoptimized_frame_ != NULL) {
+      Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, isolate_);
+    }
+  }
+
+  int GetParametersCount() {
+    return is_optimized_ ? deoptimized_frame_->parameters_count()
+                         : frame_->ComputeParametersCount();
+  }
+  int expression_count() { return deoptimized_frame_->expression_count(); }
+  Object* GetFunction() {
+    return is_optimized_ ? deoptimized_frame_->GetFunction()
+                         : frame_->function();
+  }
+  Object* GetParameter(int index) {
+    return is_optimized_ ? deoptimized_frame_->GetParameter(index)
+                         : frame_->GetParameter(index);
+  }
+  Object* GetExpression(int index) {
+    return is_optimized_ ? deoptimized_frame_->GetExpression(index)
+                         : frame_->GetExpression(index);
+  }
+  int GetSourcePosition() {
+    return is_optimized_ ? deoptimized_frame_->GetSourcePosition()
+                         : frame_->LookupCode()->SourcePosition(frame_->pc());
+  }
+  bool IsConstructor() {
+    return is_optimized_ && !is_bottommost_
+               ? deoptimized_frame_->HasConstructStub()
+               : frame_->IsConstructor();
+  }
+  Object* GetContext() {
+    return is_optimized_ ? deoptimized_frame_->GetContext() : frame_->context();
+  }
+
+  // To inspect all the provided arguments the frame might need to be
+  // replaced with the arguments frame.
+  void SetArgumentsFrame(JavaScriptFrame* frame) {
+    DCHECK(has_adapted_arguments_);
+    frame_ = frame;
+    is_optimized_ = frame_->is_optimized();
+    DCHECK(!is_optimized_);
+  }
+
+ private:
+  JavaScriptFrame* frame_;
+  DeoptimizedFrameInfo* deoptimized_frame_;
+  Isolate* isolate_;
+  bool is_optimized_;
+  bool is_bottommost_;
+  bool has_adapted_arguments_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameInspector);
+};
+
+
+static const int kFrameDetailsFrameIdIndex = 0;
+static const int kFrameDetailsReceiverIndex = 1;
+static const int kFrameDetailsFunctionIndex = 2;
+static const int kFrameDetailsArgumentCountIndex = 3;
+static const int kFrameDetailsLocalCountIndex = 4;
+static const int kFrameDetailsSourcePositionIndex = 5;
+static const int kFrameDetailsConstructCallIndex = 6;
+static const int kFrameDetailsAtReturnIndex = 7;
+static const int kFrameDetailsFlagsIndex = 8;
+static const int kFrameDetailsFirstDynamicIndex = 9;
+
+
+static SaveContext* FindSavedContextForFrame(Isolate* isolate,
+                                             JavaScriptFrame* frame) {
+  SaveContext* save = isolate->save_context();
+  while (save != NULL && !save->IsBelowFrame(frame)) {
+    save = save->prev();
+  }
+  DCHECK(save != NULL);
+  return save;
+}
+
+
+// Advances the iterator to the frame that matches the index and returns the
+// inlined frame index, or -1 if not found.  Skips native JS functions.
+int Runtime::FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index) {
+  int count = -1;
+  for (; !it->done(); it->Advance()) {
+    List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
+    it->frame()->Summarize(&frames);
+    for (int i = frames.length() - 1; i >= 0; i--) {
+      // Omit functions from native scripts.
+      if (frames[i].function()->IsFromNativeScript()) continue;
+      if (++count == index) return i;
+    }
+  }
+  return -1;
+}
+
+
+// Return an array with frame details
+// args[0]: number: break id
+// args[1]: number: frame index
+//
+// The array returned contains the following information:
+// 0: Frame id
+// 1: Receiver
+// 2: Function
+// 3: Argument count
+// 4: Local count
+// 5: Source position
+// 6: Constructor call
+// 7: Is at return
+// 8: Flags
+// Arguments name, value
+// Locals name, value
+// Return value if any
+RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+  RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+  CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
+  Heap* heap = isolate->heap();
+
+  // Find the relevant frame with the requested index.
+  StackFrame::Id id = isolate->debug()->break_frame_id();
+  if (id == StackFrame::NO_ID) {
+    // If there are no JavaScript stack frames return undefined.
+    return heap->undefined_value();
+  }
+
+  JavaScriptFrameIterator it(isolate, id);
+  // Inlined frame index in optimized frame, starting from outer function.
+  int inlined_jsframe_index = Runtime::FindIndexedNonNativeFrame(&it, index);
+  if (inlined_jsframe_index == -1) return heap->undefined_value();
+
+  FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
+  bool is_optimized = it.frame()->is_optimized();
+
+  // Traverse the saved contexts chain to find the active context for the
+  // selected frame.
+  SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
+
+  // Get the frame id.
+  Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
+
+  // Find source position in unoptimized code.
+  int position = frame_inspector.GetSourcePosition();
+
+  // Check for constructor frame.
+  bool constructor = frame_inspector.IsConstructor();
+
+  // Get scope info and read from it for local variable information.
+  Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
+  Handle<SharedFunctionInfo> shared(function->shared());
+  Handle<ScopeInfo> scope_info(shared->scope_info());
+  DCHECK(*scope_info != ScopeInfo::Empty(isolate));
+
+  // Get the locals names and values into a temporary array.
+  int local_count = scope_info->LocalCount();
+  for (int slot = 0; slot < scope_info->LocalCount(); ++slot) {
+    // Hide compiler-introduced temporary variables, whether on the stack or on
+    // the context.
+    if (scope_info->LocalIsSynthetic(slot)) local_count--;
+  }
+
+  Handle<FixedArray> locals =
+      isolate->factory()->NewFixedArray(local_count * 2);
+
+  // Fill in the values of the locals.
+  int local = 0;
+  int i = 0;
+  for (; i < scope_info->StackLocalCount(); ++i) {
+    // Use the value from the stack.
+    if (scope_info->LocalIsSynthetic(i)) continue;
+    locals->set(local * 2, scope_info->LocalName(i));
+    locals->set(local * 2 + 1, frame_inspector.GetExpression(i));
+    local++;
+  }
+  if (local < local_count) {
+    // Get the context containing declarations.
+    Handle<Context> context(
+        Context::cast(frame_inspector.GetContext())->declaration_context());
+    for (; i < scope_info->LocalCount(); ++i) {
+      if (scope_info->LocalIsSynthetic(i)) continue;
+      Handle<String> name(scope_info->LocalName(i));
+      VariableMode mode;
+      InitializationFlag init_flag;
+      MaybeAssignedFlag maybe_assigned_flag;
+      locals->set(local * 2, *name);
+      int context_slot_index = ScopeInfo::ContextSlotIndex(
+          scope_info, name, &mode, &init_flag, &maybe_assigned_flag);
+      Object* value = context->get(context_slot_index);
+      locals->set(local * 2 + 1, value);
+      local++;
+    }
+  }
+
+  // Check whether this frame is positioned at return. If not top
+  // frame or if the frame is optimized it cannot be at a return.
+  bool at_return = false;
+  if (!is_optimized && index == 0) {
+    at_return = isolate->debug()->IsBreakAtReturn(it.frame());
+  }
+
+  // If positioned just before return find the value to be returned and add it
+  // to the frame information.
+  Handle<Object> return_value = isolate->factory()->undefined_value();
+  if (at_return) {
+    StackFrameIterator it2(isolate);
+    Address internal_frame_sp = NULL;
+    while (!it2.done()) {
+      if (it2.frame()->is_internal()) {
+        internal_frame_sp = it2.frame()->sp();
+      } else {
+        if (it2.frame()->is_java_script()) {
+          if (it2.frame()->id() == it.frame()->id()) {
+            // The internal frame just before the JavaScript frame contains the
+            // value to return on top. A debug break at return will create an
+            // internal frame to store the return value (eax/rax/r0) before
+            // entering the debug break exit frame.
+            if (internal_frame_sp != NULL) {
+              return_value =
+                  Handle<Object>(Memory::Object_at(internal_frame_sp), isolate);
+              break;
+            }
+          }
+        }
+
+        // Indicate that the previous frame was not an internal frame.
+        internal_frame_sp = NULL;
+      }
+      it2.Advance();
+    }
+  }
+
+  // Now advance to the arguments adapter frame (if any). It contains all
+  // the provided parameters whereas the function frame always have the number
+  // of arguments matching the functions parameters. The rest of the
+  // information (except for what is collected above) is the same.
+  if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
+    it.AdvanceToArgumentsFrame();
+    frame_inspector.SetArgumentsFrame(it.frame());
+  }
+
+  // Find the number of arguments to fill. At least fill the number of
+  // parameters for the function and fill more if more parameters are provided.
+  int argument_count = scope_info->ParameterCount();
+  if (argument_count < frame_inspector.GetParametersCount()) {
+    argument_count = frame_inspector.GetParametersCount();
+  }
+
+  // Calculate the size of the result.
+  int details_size = kFrameDetailsFirstDynamicIndex +
+                     2 * (argument_count + local_count) + (at_return ? 1 : 0);
+  Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
+
+  // Add the frame id.
+  details->set(kFrameDetailsFrameIdIndex, *frame_id);
+
+  // Add the function (same as in function frame).
+  details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
+
+  // Add the arguments count.
+  details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
+
+  // Add the locals count
+  details->set(kFrameDetailsLocalCountIndex, Smi::FromInt(local_count));
+
+  // Add the source position.
+  if (position != RelocInfo::kNoPosition) {
+    details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
+  } else {
+    details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
+  }
+
+  // Add the constructor information.
+  details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
+
+  // Add the at return information.
+  details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
+
+  // Add flags to indicate information on whether this frame is
+  //   bit 0: invoked in the debugger context.
+  //   bit 1: optimized frame.
+  //   bit 2: inlined in optimized frame
+  int flags = 0;
+  if (*save->context() == *isolate->debug()->debug_context()) {
+    flags |= 1 << 0;
+  }
+  if (is_optimized) {
+    flags |= 1 << 1;
+    flags |= inlined_jsframe_index << 2;
+  }
+  details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
+
+  // Fill the dynamic part.
+  int details_index = kFrameDetailsFirstDynamicIndex;
+
+  // Add arguments name and value.
+  for (int i = 0; i < argument_count; i++) {
+    // Name of the argument.
+    if (i < scope_info->ParameterCount()) {
+      details->set(details_index++, scope_info->ParameterName(i));
+    } else {
+      details->set(details_index++, heap->undefined_value());
+    }
+
+    // Parameter value.
+    if (i < frame_inspector.GetParametersCount()) {
+      // Get the value from the stack.
+      details->set(details_index++, frame_inspector.GetParameter(i));
+    } else {
+      details->set(details_index++, heap->undefined_value());
+    }
+  }
+
+  // Add locals name and value from the temporary copy from the function frame.
+  for (int i = 0; i < local_count * 2; i++) {
+    details->set(details_index++, locals->get(i));
+  }
+
+  // Add the value being returned.
+  if (at_return) {
+    details->set(details_index++, *return_value);
+  }
+
+  // Add the receiver (same as in function frame).
+  // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
+  // THE FRAME ITERATOR TO WRAP THE RECEIVER.
+  Handle<Object> receiver(it.frame()->receiver(), isolate);
+  if (!receiver->IsJSObject() && shared->strict_mode() == SLOPPY &&
+      !function->IsBuiltin()) {
+    // If the receiver is not a JSObject and the function is not a
+    // builtin or strict-mode we have hit an optimization where a
+    // value object is not converted into a wrapped JS objects. To
+    // hide this optimization from the debugger, we wrap the receiver
+    // by creating correct wrapper object based on the calling frame's
+    // native context.
+    it.Advance();
+    if (receiver->IsUndefined()) {
+      receiver = handle(function->global_proxy());
+    } else {
+      Context* context = Context::cast(it.frame()->context());
+      Handle<Context> native_context(Context::cast(context->native_context()));
+      if (!Object::ToObject(isolate, receiver, native_context)
+               .ToHandle(&receiver)) {
+        // This only happens if the receiver is forcibly set in %_CallFunction.
+        return heap->undefined_value();
+      }
+    }
+  }
+  details->set(kFrameDetailsReceiverIndex, *receiver);
+
+  DCHECK_EQ(details_size, details_index);
+  return *isolate->factory()->NewJSArrayWithElements(details);
+}
+
+
+static bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info,
+                                              Handle<String> parameter_name) {
+  VariableMode mode;
+  InitializationFlag init_flag;
+  MaybeAssignedFlag maybe_assigned_flag;
+  return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &init_flag,
+                                     &maybe_assigned_flag) != -1;
+}
+
+
+// Create a plain JSObject which materializes the local scope for the specified
+// frame.
+MUST_USE_RESULT
+static MaybeHandle<JSObject> MaterializeStackLocalsWithFrameInspector(
+    Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function,
+    FrameInspector* frame_inspector) {
+  Handle<SharedFunctionInfo> shared(function->shared());
+  Handle<ScopeInfo> scope_info(shared->scope_info());
+
+  // First fill all parameters.
+  for (int i = 0; i < scope_info->ParameterCount(); ++i) {
+    // Do not materialize the parameter if it is shadowed by a context local.
+    Handle<String> name(scope_info->ParameterName(i));
+    if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
+
+    HandleScope scope(isolate);
+    Handle<Object> value(i < frame_inspector->GetParametersCount()
+                             ? frame_inspector->GetParameter(i)
+                             : isolate->heap()->undefined_value(),
+                         isolate);
+    DCHECK(!value->IsTheHole());
+
+    RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty(
+                                     isolate, target, name, value, SLOPPY),
+                        JSObject);
+  }
+
+  // Second fill all stack locals.
+  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
+    if (scope_info->LocalIsSynthetic(i)) continue;
+    Handle<String> name(scope_info->StackLocalName(i));
+    Handle<Object> value(frame_inspector->GetExpression(i), isolate);
+    if (value->IsTheHole()) continue;
+
+    RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty(
+                                     isolate, target, name, value, SLOPPY),
+                        JSObject);
+  }
+
+  return target;
+}
+
+
+static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate,
+                                                    Handle<JSObject> target,
+                                                    Handle<JSFunction> function,
+                                                    JavaScriptFrame* frame,
+                                                    int inlined_jsframe_index) {
+  if (inlined_jsframe_index != 0 || frame->is_optimized()) {
+    // Optimized frames are not supported.
+    // TODO(yangguo): make sure all code deoptimized when debugger is active
+    //                and assert that this cannot happen.
+    return;
+  }
+
+  Handle<SharedFunctionInfo> shared(function->shared());
+  Handle<ScopeInfo> scope_info(shared->scope_info());
+
+  // Parameters.
+  for (int i = 0; i < scope_info->ParameterCount(); ++i) {
+    // Shadowed parameters were not materialized.
+    Handle<String> name(scope_info->ParameterName(i));
+    if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
+
+    DCHECK(!frame->GetParameter(i)->IsTheHole());
+    HandleScope scope(isolate);
+    Handle<Object> value =
+        Object::GetPropertyOrElement(target, name).ToHandleChecked();
+    frame->SetParameterValue(i, *value);
+  }
+
+  // Stack locals.
+  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
+    if (scope_info->LocalIsSynthetic(i)) continue;
+    if (frame->GetExpression(i)->IsTheHole()) continue;
+    HandleScope scope(isolate);
+    Handle<Object> value = Object::GetPropertyOrElement(
+                               target, handle(scope_info->StackLocalName(i),
+                                              isolate)).ToHandleChecked();
+    frame->SetExpression(i, *value);
+  }
+}
+
+
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext(
+    Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function,
+    JavaScriptFrame* frame) {
+  HandleScope scope(isolate);
+  Handle<SharedFunctionInfo> shared(function->shared());
+  Handle<ScopeInfo> scope_info(shared->scope_info());
+
+  if (!scope_info->HasContext()) return target;
+
+  // Third fill all context locals.
+  Handle<Context> frame_context(Context::cast(frame->context()));
+  Handle<Context> function_context(frame_context->declaration_context());
+  if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, function_context,
+                                                 target)) {
+    return MaybeHandle<JSObject>();
+  }
+
+  // Finally copy any properties from the function context extension.
+  // These will be variables introduced by eval.
+  if (function_context->closure() == *function) {
+    if (function_context->has_extension() &&
+        !function_context->IsNativeContext()) {
+      Handle<JSObject> ext(JSObject::cast(function_context->extension()));
+      Handle<FixedArray> keys;
+      ASSIGN_RETURN_ON_EXCEPTION(
+          isolate, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS),
+          JSObject);
+
+      for (int i = 0; i < keys->length(); i++) {
+        // Names of variables introduced by eval are strings.
+        DCHECK(keys->get(i)->IsString());
+        Handle<String> key(String::cast(keys->get(i)));
+        Handle<Object> value;
+        ASSIGN_RETURN_ON_EXCEPTION(
+            isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
+        RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty(
+                                         isolate, target, key, value, SLOPPY),
+                            JSObject);
+      }
+    }
+  }
+
+  return target;
+}
+
+
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScriptScope(
+    Handle<GlobalObject> global) {
+  Isolate* isolate = global->GetIsolate();
+  Handle<ScriptContextTable> script_contexts(
+      global->native_context()->script_context_table());
+
+  Handle<JSObject> script_scope =
+      isolate->factory()->NewJSObject(isolate->object_function());
+
+  for (int context_index = 0; context_index < script_contexts->used();
+       context_index++) {
+    Handle<Context> context =
+        ScriptContextTable::GetContext(script_contexts, context_index);
+    Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
+    if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
+                                                   script_scope)) {
+      return MaybeHandle<JSObject>();
+    }
+  }
+  return script_scope;
+}
+
+
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope(
+    Isolate* isolate, JavaScriptFrame* frame, int inlined_jsframe_index) {
+  FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
+  Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
+
+  Handle<JSObject> local_scope =
+      isolate->factory()->NewJSObject(isolate->object_function());
+  ASSIGN_RETURN_ON_EXCEPTION(
+      isolate, local_scope,
+      MaterializeStackLocalsWithFrameInspector(isolate, local_scope, function,
+                                               &frame_inspector),
+      JSObject);
+
+  return MaterializeLocalContext(isolate, local_scope, function, frame);
+}
+
+
+// Set the context local variable value.
+static bool SetContextLocalValue(Isolate* isolate, Handle<ScopeInfo> scope_info,
+                                 Handle<Context> context,
+                                 Handle<String> variable_name,
+                                 Handle<Object> new_value) {
+  for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
+    Handle<String> next_name(scope_info->ContextLocalName(i));
+    if (String::Equals(variable_name, next_name)) {
+      VariableMode mode;
+      InitializationFlag init_flag;
+      MaybeAssignedFlag maybe_assigned_flag;
+      int context_index = ScopeInfo::ContextSlotIndex(
+          scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag);
+      context->set(context_index, *new_value);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+static bool SetLocalVariableValue(Isolate* isolate, JavaScriptFrame* frame,
+                                  int inlined_jsframe_index,
+                                  Handle<String> variable_name,
+                                  Handle<Object> new_value) {
+  if (inlined_jsframe_index != 0 || frame->is_optimized()) {
+    // Optimized frames are not supported.
+    return false;
+  }
+
+  Handle<JSFunction> function(frame->function());
+  Handle<SharedFunctionInfo> shared(function->shared());
+  Handle<ScopeInfo> scope_info(shared->scope_info());
+
+  bool default_result = false;
+
+  // Parameters.
+  for (int i = 0; i < scope_info->ParameterCount(); ++i) {
+    HandleScope scope(isolate);
+    if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) {
+      frame->SetParameterValue(i, *new_value);
+      // Argument might be shadowed in heap context, don't stop here.
+      default_result = true;
+    }
+  }
+
+  // Stack locals.
+  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
+    HandleScope scope(isolate);
+    if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
+      frame->SetExpression(i, *new_value);
+      return true;
+    }
+  }
+
+  if (scope_info->HasContext()) {
+    // Context locals.
+    Handle<Context> frame_context(Context::cast(frame->context()));
+    Handle<Context> function_context(frame_context->declaration_context());
+    if (SetContextLocalValue(isolate, scope_info, function_context,
+                             variable_name, new_value)) {
+      return true;
+    }
+
+    // Function context extension. These are variables introduced by eval.
+    if (function_context->closure() == *function) {
+      if (function_context->has_extension() &&
+          !function_context->IsNativeContext()) {
+        Handle<JSObject> ext(JSObject::cast(function_context->extension()));
+
+        Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
+        DCHECK(maybe.has_value);
+        if (maybe.value) {
+          // We don't expect this to do anything except replacing
+          // property value.
+          Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
+                                     SLOPPY).Assert();
+          return true;
+        }
+      }
+    }
+  }
+
+  return default_result;
+}
+
+
+// Create a plain JSObject which materializes the closure content for the
+// context.
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeClosure(
+    Isolate* isolate, Handle<Context> context) {
+  DCHECK(context->IsFunctionContext());
+
+  Handle<SharedFunctionInfo> shared(context->closure()->shared());
+  Handle<ScopeInfo> scope_info(shared->scope_info());
+
+  // Allocate and initialize a JSObject with all the content of this function
+  // closure.
+  Handle<JSObject> closure_scope =
+      isolate->factory()->NewJSObject(isolate->object_function());
+
+  // Fill all context locals to the context extension.
+  if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
+                                                 closure_scope)) {
+    return MaybeHandle<JSObject>();
+  }
+
+  // Finally copy any properties from the function context extension. This will
+  // be variables introduced by eval.
+  if (context->has_extension()) {
+    Handle<JSObject> ext(JSObject::cast(context->extension()));
+    Handle<FixedArray> keys;
+    ASSIGN_RETURN_ON_EXCEPTION(
+        isolate, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS),
+        JSObject);
+
+    for (int i = 0; i < keys->length(); i++) {
+      HandleScope scope(isolate);
+      // Names of variables introduced by eval are strings.
+      DCHECK(keys->get(i)->IsString());
+      Handle<String> key(String::cast(keys->get(i)));
+      Handle<Object> value;
+      ASSIGN_RETURN_ON_EXCEPTION(
+          isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
+      RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
+                                       closure_scope, key, value, NONE),
+                          JSObject);
+    }
+  }
+
+  return closure_scope;
+}
+
+
+// This method copies structure of MaterializeClosure method above.
+static bool SetClosureVariableValue(Isolate* isolate, Handle<Context> context,
+                                    Handle<String> variable_name,
+                                    Handle<Object> new_value) {
+  DCHECK(context->IsFunctionContext());
+
+  Handle<SharedFunctionInfo> shared(context->closure()->shared());
+  Handle<ScopeInfo> scope_info(shared->scope_info());
+
+  // Context locals to the context extension.
+  if (SetContextLocalValue(isolate, scope_info, context, variable_name,
+                           new_value)) {
+    return true;
+  }
+
+  // Properties from the function context extension. This will
+  // be variables introduced by eval.
+  if (context->has_extension()) {
+    Handle<JSObject> ext(JSObject::cast(context->extension()));
+    Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
+    DCHECK(maybe.has_value);
+    if (maybe.value) {
+      // We don't expect this to do anything except replacing property value.
+      Runtime::DefineObjectProperty(ext, variable_name, new_value, NONE)
+          .Assert();
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+static bool SetBlockContextVariableValue(Handle<Context> block_context,
+                                         Handle<String> variable_name,
+                                         Handle<Object> new_value) {
+  DCHECK(block_context->IsBlockContext());
+  Handle<ScopeInfo> scope_info(ScopeInfo::cast(block_context->extension()));
+
+  return SetContextLocalValue(block_context->GetIsolate(), scope_info,
+                              block_context, variable_name, new_value);
+}
+
+
+static bool SetScriptVariableValue(Handle<Context> context,
+                                   Handle<String> variable_name,
+                                   Handle<Object> new_value) {
+  Handle<ScriptContextTable> script_contexts(
+      context->global_object()->native_context()->script_context_table());
+  ScriptContextTable::LookupResult lookup_result;
+  if (ScriptContextTable::Lookup(script_contexts, variable_name,
+                                 &lookup_result)) {
+    Handle<Context> script_context = ScriptContextTable::GetContext(
+        script_contexts, lookup_result.context_index);
+    script_context->set(lookup_result.slot_index, *new_value);
+    return true;
+  }
+
+  return false;
+}
+
+
+// Create a plain JSObject which materializes the scope for the specified
+// catch context.
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeCatchScope(
+    Isolate* isolate, Handle<Context> context) {
+  DCHECK(context->IsCatchContext());
+  Handle<String> name(String::cast(context->extension()));
+  Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
+                               isolate);
+  Handle<JSObject> catch_scope =
+      isolate->factory()->NewJSObject(isolate->object_function());
+  RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
+                                   catch_scope, name, thrown_object, NONE),
+                      JSObject);
+  return catch_scope;
+}
+
+
+static bool SetCatchVariableValue(Isolate* isolate, Handle<Context> context,
+                                  Handle<String> variable_name,
+                                  Handle<Object> new_value) {
+  DCHECK(context->IsCatchContext());
+  Handle<String> name(String::cast(context->extension()));
+  if (!String::Equals(name, variable_name)) {
+    return false;
+  }
+  context->set(Context::THROWN_OBJECT_INDEX, *new_value);
+  return true;
+}
+
+
+// Create a plain JSObject which materializes the block scope for the specified
+// block context.
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeBlockScope(
+    Isolate* isolate, Handle<Context> context) {
+  DCHECK(context->IsBlockContext());
+  Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
+
+  // Allocate and initialize a JSObject with all the arguments, stack locals
+  // heap locals and extension properties of the debugged function.
+  Handle<JSObject> block_scope =
+      isolate->factory()->NewJSObject(isolate->object_function());
+
+  // Fill all context locals.
+  if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
+                                                 block_scope)) {
+    return MaybeHandle<JSObject>();
+  }
+
+  return block_scope;
+}
+
+
+// Create a plain JSObject which materializes the module scope for the specified
+// module context.
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope(
+    Isolate* isolate, Handle<Context> context) {
+  DCHECK(context->IsModuleContext());
+  Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
+
+  // Allocate and initialize a JSObject with all the members of the debugged
+  // module.
+  Handle<JSObject> module_scope =
+      isolate->factory()->NewJSObject(isolate->object_function());
+
+  // Fill all context locals.
+  if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
+                                                 module_scope)) {
+    return MaybeHandle<JSObject>();
+  }
+
+  return module_scope;
+}
+
+
+// Iterate over the actual scopes visible from a stack frame or from a closure.
+// The iteration proceeds from the innermost visible nested scope outwards.
+// All scopes are backed by an actual context except the local scope,
+// which is inserted "artificially" in the context chain.
+class ScopeIterator {
+ public:
+  enum ScopeType {
+    ScopeTypeGlobal = 0,
+    ScopeTypeLocal,
+    ScopeTypeWith,
+    ScopeTypeClosure,
+    ScopeTypeCatch,
+    ScopeTypeBlock,
+    ScopeTypeScript,
+    ScopeTypeModule
+  };
+
+  ScopeIterator(Isolate* isolate, JavaScriptFrame* frame,
+                int inlined_jsframe_index, bool ignore_nested_scopes = false)
+      : isolate_(isolate),
+        frame_(frame),
+        inlined_jsframe_index_(inlined_jsframe_index),
+        function_(frame->function()),
+        context_(Context::cast(frame->context())),
+        nested_scope_chain_(4),
+        seen_script_scope_(false),
+        failed_(false) {
+    // Catch the case when the debugger stops in an internal function.
+    Handle<SharedFunctionInfo> shared_info(function_->shared());
+    Handle<ScopeInfo> scope_info(shared_info->scope_info());
+    if (shared_info->script() == isolate->heap()->undefined_value()) {
+      while (context_->closure() == *function_) {
+        context_ = Handle<Context>(context_->previous(), isolate_);
+      }
+      return;
+    }
+
+    // Get the debug info (create it if it does not exist).
+    if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) {
+      // Return if ensuring debug info failed.
+      return;
+    }
+
+    // Currently it takes too much time to find nested scopes due to script
+    // parsing. Sometimes we want to run the ScopeIterator as fast as possible
+    // (for example, while collecting async call stacks on every
+    // addEventListener call), even if we drop some nested scopes.
+    // Later we may optimize getting the nested scopes (cache the result?)
+    // and include nested scopes into the "fast" iteration case as well.
+    if (!ignore_nested_scopes) {
+      Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
+
+      // Find the break point where execution has stopped.
+      BreakLocationIterator break_location_iterator(debug_info,
+                                                    ALL_BREAK_LOCATIONS);
+      // pc points to the instruction after the current one, possibly a break
+      // location as well. So the "- 1" to exclude it from the search.
+      break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
+
+      // Within the return sequence at the moment it is not possible to
+      // get a source position which is consistent with the current scope chain.
+      // Thus all nested with, catch and block contexts are skipped and we only
+      // provide the function scope.
+      ignore_nested_scopes = break_location_iterator.IsExit();
+    }
+
+    if (ignore_nested_scopes) {
+      if (scope_info->HasContext()) {
+        context_ = Handle<Context>(context_->declaration_context(), isolate_);
+      } else {
+        while (context_->closure() == *function_) {
+          context_ = Handle<Context>(context_->previous(), isolate_);
+        }
+      }
+      if (scope_info->scope_type() == FUNCTION_SCOPE ||
+          scope_info->scope_type() == ARROW_SCOPE) {
+        nested_scope_chain_.Add(scope_info);
+      }
+    } else {
+      // Reparse the code and analyze the scopes.
+      Handle<Script> script(Script::cast(shared_info->script()));
+      Scope* scope = NULL;
+
+      // Check whether we are in global, eval or function code.
+      Handle<ScopeInfo> scope_info(shared_info->scope_info());
+      if (scope_info->scope_type() != FUNCTION_SCOPE &&
+          scope_info->scope_type() != ARROW_SCOPE) {
+        // Global or eval code.
+        CompilationInfoWithZone info(script);
+        if (scope_info->scope_type() == SCRIPT_SCOPE) {
+          info.MarkAsGlobal();
+        } else {
+          DCHECK(scope_info->scope_type() == EVAL_SCOPE);
+          info.MarkAsEval();
+          info.SetContext(Handle<Context>(function_->context()));
+        }
+        if (Parser::Parse(&info) && Scope::Analyze(&info)) {
+          scope = info.function()->scope();
+        }
+        RetrieveScopeChain(scope, shared_info);
+      } else {
+        // Function code
+        CompilationInfoWithZone info(shared_info);
+        if (Parser::Parse(&info) && Scope::Analyze(&info)) {
+          scope = info.function()->scope();
+        }
+        RetrieveScopeChain(scope, shared_info);
+      }
+    }
+  }
+
+  ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
+      : isolate_(isolate),
+        frame_(NULL),
+        inlined_jsframe_index_(0),
+        function_(function),
+        context_(function->context()),
+        seen_script_scope_(false),
+        failed_(false) {
+    if (function->IsBuiltin()) {
+      context_ = Handle<Context>();
+    }
+  }
+
+  // More scopes?
+  bool Done() {
+    DCHECK(!failed_);
+    return context_.is_null();
+  }
+
+  bool Failed() { return failed_; }
+
+  // Move to the next scope.
+  void Next() {
+    DCHECK(!failed_);
+    ScopeType scope_type = Type();
+    if (scope_type == ScopeTypeGlobal) {
+      // The global scope is always the last in the chain.
+      DCHECK(context_->IsNativeContext());
+      context_ = Handle<Context>();
+      return;
+    }
+    if (scope_type == ScopeTypeScript) seen_script_scope_ = true;
+    if (nested_scope_chain_.is_empty()) {
+      if (scope_type == ScopeTypeScript) {
+        if (context_->IsScriptContext()) {
+          context_ = Handle<Context>(context_->previous(), isolate_);
+        }
+        CHECK(context_->IsNativeContext());
+      } else {
+        context_ = Handle<Context>(context_->previous(), isolate_);
+      }
+    } else {
+      if (nested_scope_chain_.last()->HasContext()) {
+        DCHECK(context_->previous() != NULL);
+        context_ = Handle<Context>(context_->previous(), isolate_);
+      }
+      nested_scope_chain_.RemoveLast();
+    }
+  }
+
+  // Return the type of the current scope.
+  ScopeType Type() {
+    DCHECK(!failed_);
+    if (!nested_scope_chain_.is_empty()) {
+      Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
+      switch (scope_info->scope_type()) {
+        case FUNCTION_SCOPE:
+        case ARROW_SCOPE:
+          DCHECK(context_->IsFunctionContext() || !scope_info->HasContext());
+          return ScopeTypeLocal;
+        case MODULE_SCOPE:
+          DCHECK(context_->IsModuleContext());
+          return ScopeTypeModule;
+        case SCRIPT_SCOPE:
+          DCHECK(context_->IsScriptContext() || context_->IsNativeContext());
+          return ScopeTypeScript;
+        case WITH_SCOPE:
+          DCHECK(context_->IsWithContext());
+          return ScopeTypeWith;
+        case CATCH_SCOPE:
+          DCHECK(context_->IsCatchContext());
+          return ScopeTypeCatch;
+        case BLOCK_SCOPE:
+          DCHECK(!scope_info->HasContext() || context_->IsBlockContext());
+          return ScopeTypeBlock;
+        case EVAL_SCOPE:
+          UNREACHABLE();
+      }
+    }
+    if (context_->IsNativeContext()) {
+      DCHECK(context_->global_object()->IsGlobalObject());
+      // If we are at the native context and have not yet seen script scope,
+      // fake it.
+      return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript;
+    }
+    if (context_->IsFunctionContext()) {
+      return ScopeTypeClosure;
+    }
+    if (context_->IsCatchContext()) {
+      return ScopeTypeCatch;
+    }
+    if (context_->IsBlockContext()) {
+      return ScopeTypeBlock;
+    }
+    if (context_->IsModuleContext()) {
+      return ScopeTypeModule;
+    }
+    if (context_->IsScriptContext()) {
+      return ScopeTypeScript;
+    }
+    DCHECK(context_->IsWithContext());
+    return ScopeTypeWith;
+  }
+
+  // Return the JavaScript object with the content of the current scope.
+  MaybeHandle<JSObject> ScopeObject() {
+    DCHECK(!failed_);
+    switch (Type()) {
+      case ScopeIterator::ScopeTypeGlobal:
+        return Handle<JSObject>(CurrentContext()->global_object());
+      case ScopeIterator::ScopeTypeScript:
+        return MaterializeScriptScope(
+            Handle<GlobalObject>(CurrentContext()->global_object()));
+      case ScopeIterator::ScopeTypeLocal:
+        // Materialize the content of the local scope into a JSObject.
+        DCHECK(nested_scope_chain_.length() == 1);
+        return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
+      case ScopeIterator::ScopeTypeWith:
+        // Return the with object.
+        return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
+      case ScopeIterator::ScopeTypeCatch:
+        return MaterializeCatchScope(isolate_, CurrentContext());
+      case ScopeIterator::ScopeTypeClosure:
+        // Materialize the content of the closure scope into a JSObject.
+        return MaterializeClosure(isolate_, CurrentContext());
+      case ScopeIterator::ScopeTypeBlock:
+        return MaterializeBlockScope(isolate_, CurrentContext());
+      case ScopeIterator::ScopeTypeModule:
+        return MaterializeModuleScope(isolate_, CurrentContext());
+    }
+    UNREACHABLE();
+    return Handle<JSObject>();
+  }
+
+  bool SetVariableValue(Handle<String> variable_name,
+                        Handle<Object> new_value) {
+    DCHECK(!failed_);
+    switch (Type()) {
+      case ScopeIterator::ScopeTypeGlobal:
+        break;
+      case ScopeIterator::ScopeTypeLocal:
+        return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_,
+                                     variable_name, new_value);
+      case ScopeIterator::ScopeTypeWith:
+        break;
+      case ScopeIterator::ScopeTypeCatch:
+        return SetCatchVariableValue(isolate_, CurrentContext(), variable_name,
+                                     new_value);
+      case ScopeIterator::ScopeTypeClosure:
+        return SetClosureVariableValue(isolate_, CurrentContext(),
+                                       variable_name, new_value);
+      case ScopeIterator::ScopeTypeScript:
+        return SetScriptVariableValue(CurrentContext(), variable_name,
+                                      new_value);
+      case ScopeIterator::ScopeTypeBlock:
+        return SetBlockContextVariableValue(CurrentContext(), variable_name,
+                                            new_value);
+      case ScopeIterator::ScopeTypeModule:
+        // TODO(2399): should we implement it?
+        break;
+    }
+    return false;
+  }
+
+  Handle<ScopeInfo> CurrentScopeInfo() {
+    DCHECK(!failed_);
+    if (!nested_scope_chain_.is_empty()) {
+      return nested_scope_chain_.last();
+    } else if (context_->IsBlockContext()) {
+      return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
+    } else if (context_->IsFunctionContext()) {
+      return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
+    }
+    return Handle<ScopeInfo>::null();
+  }
+
+  // Return the context for this scope. For the local context there might not
+  // be an actual context.
+  Handle<Context> CurrentContext() {
+    DCHECK(!failed_);
+    if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript ||
+        nested_scope_chain_.is_empty()) {
+      return context_;
+    } else if (nested_scope_chain_.last()->HasContext()) {
+      return context_;
+    } else {
+      return Handle<Context>();
+    }
+  }
+
+#ifdef DEBUG
+  // Debug print of the content of the current scope.
+  void DebugPrint() {
+    OFStream os(stdout);
+    DCHECK(!failed_);
+    switch (Type()) {
+      case ScopeIterator::ScopeTypeGlobal:
+        os << "Global:\n";
+        CurrentContext()->Print(os);
+        break;
+
+      case ScopeIterator::ScopeTypeLocal: {
+        os << "Local:\n";
+        function_->shared()->scope_info()->Print();
+        if (!CurrentContext().is_null()) {
+          CurrentContext()->Print(os);
+          if (CurrentContext()->has_extension()) {
+            Handle<Object> extension(CurrentContext()->extension(), isolate_);
+            if (extension->IsJSContextExtensionObject()) {
+              extension->Print(os);
+            }
+          }
+        }
+        break;
+      }
+
+      case ScopeIterator::ScopeTypeWith:
+        os << "With:\n";
+        CurrentContext()->extension()->Print(os);
+        break;
+
+      case ScopeIterator::ScopeTypeCatch:
+        os << "Catch:\n";
+        CurrentContext()->extension()->Print(os);
+        CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os);
+        break;
+
+      case ScopeIterator::ScopeTypeClosure:
+        os << "Closure:\n";
+        CurrentContext()->Print(os);
+        if (CurrentContext()->has_extension()) {
+          Handle<Object> extension(CurrentContext()->extension(), isolate_);
+          if (extension->IsJSContextExtensionObject()) {
+            extension->Print(os);
+          }
+        }
+        break;
+
+      case ScopeIterator::ScopeTypeScript:
+        os << "Script:\n";
+        CurrentContext()
+            ->global_object()
+            ->native_context()
+            ->script_context_table()
+            ->Print(os);
+        break;
+
+      default:
+        UNREACHABLE();
+    }
+    PrintF("\n");
+  }
+#endif
+
+ private:
+  Isolate* isolate_;
+  JavaScriptFrame* frame_;
+  int inlined_jsframe_index_;
+  Handle<JSFunction> function_;
+  Handle<Context> context_;
+  List<Handle<ScopeInfo> > nested_scope_chain_;
+  bool seen_script_scope_;
+  bool failed_;
+
+  void RetrieveScopeChain(Scope* scope,
+                          Handle<SharedFunctionInfo> shared_info) {
+    if (scope != NULL) {
+      int source_position = shared_info->code()->SourcePosition(frame_->pc());
+      scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
+    } else {
+      // A failed reparse indicates that the preparser has diverged from the
+      // parser or that the preparse data given to the initial parse has been
+      // faulty. We fail in debug mode but in release mode we only provide the
+      // information we get from the context chain but nothing about
+      // completely stack allocated scopes or stack allocated locals.
+      // Or it could be due to stack overflow.
+      DCHECK(isolate_->has_pending_exception());
+      failed_ = true;
+    }
+  }
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
+};
+
+
+RUNTIME_FUNCTION(Runtime_GetScopeCount) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+  RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+  CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
+
+  // Get the frame where the debugging is performed.
+  StackFrame::Id id = UnwrapFrameId(wrapped_id);
+  JavaScriptFrameIterator it(isolate, id);
+  JavaScriptFrame* frame = it.frame();
+
+  // Count the visible scopes.
+  int n = 0;
+  for (ScopeIterator it(isolate, frame, 0); !it.Done(); it.Next()) {
+    n++;
+  }
+
+  return Smi::FromInt(n);
+}
+
+
+// Returns the list of step-in positions (text offset) in a function of the
+// stack frame in a range from the current debug break position to the end
+// of the corresponding statement.
+RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+  RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+  CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
+
+  // Get the frame where the debugging is performed.
+  StackFrame::Id id = UnwrapFrameId(wrapped_id);
+  JavaScriptFrameIterator frame_it(isolate, id);
+  RUNTIME_ASSERT(!frame_it.done());
+
+  JavaScriptFrame* frame = frame_it.frame();
+
+  Handle<JSFunction> fun = Handle<JSFunction>(frame->function());
+  Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(fun->shared());
+
+  if (!isolate->debug()->EnsureDebugInfo(shared, fun)) {
+    return isolate->heap()->undefined_value();
+  }
+
+  Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared);
+
+  int len = 0;
+  Handle<JSArray> array(isolate->factory()->NewJSArray(10));
+  // Find the break point where execution has stopped.
+  BreakLocationIterator break_location_iterator(debug_info,
+                                                ALL_BREAK_LOCATIONS);
+
+  break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
+  int current_statement_pos = break_location_iterator.statement_position();
+
+  while (!break_location_iterator.Done()) {
+    bool accept;
+    if (break_location_iterator.pc() > frame->pc()) {
+      accept = true;
+    } else {
+      StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
+      // The break point is near our pc. Could be a step-in possibility,
+      // that is currently taken by active debugger call.
+      if (break_frame_id == StackFrame::NO_ID) {
+        // We are not stepping.
+        accept = false;
+      } else {
+        JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id);
+        // If our frame is a top frame and we are stepping, we can do step-in
+        // at this place.
+        accept = additional_frame_it.frame()->id() == id;
+      }
+    }
+    if (accept) {
+      if (break_location_iterator.IsStepInLocation(isolate)) {
+        Smi* position_value = Smi::FromInt(break_location_iterator.position());
+        RETURN_FAILURE_ON_EXCEPTION(
+            isolate, JSObject::SetElement(
+                         array, len, Handle<Object>(position_value, isolate),
+                         NONE, SLOPPY));
+        len++;
+      }
+    }
+    // Advance iterator.
+    break_location_iterator.Next();
+    if (current_statement_pos != break_location_iterator.statement_position()) {
+      break;
+    }
+  }
+  return *array;
+}
+
+
+static const int kScopeDetailsTypeIndex = 0;
+static const int kScopeDetailsObjectIndex = 1;
+static const int kScopeDetailsSize = 2;
+
+
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScopeDetails(
+    Isolate* isolate, ScopeIterator* it) {
+  // Calculate the size of the result.
+  int details_size = kScopeDetailsSize;
+  Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
+
+  // Fill in scope details.
+  details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
+  Handle<JSObject> scope_object;
+  ASSIGN_RETURN_ON_EXCEPTION(isolate, scope_object, it->ScopeObject(),
+                             JSObject);
+  details->set(kScopeDetailsObjectIndex, *scope_object);
+
+  return isolate->factory()->NewJSArrayWithElements(details);
+}
+
+
+// Return an array with scope details
+// args[0]: number: break id
+// args[1]: number: frame index
+// args[2]: number: inlined frame index
+// args[3]: number: scope index
+//
+// The array returned contains the following information:
+// 0: Scope type
+// 1: Scope object
+RUNTIME_FUNCTION(Runtime_GetScopeDetails) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+  RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+  CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
+  CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
+  CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
+
+  // Get the frame where the debugging is performed.
+  StackFrame::Id id = UnwrapFrameId(wrapped_id);
+  JavaScriptFrameIterator frame_it(isolate, id);
+  JavaScriptFrame* frame = frame_it.frame();
+
+  // Find the requested scope.
+  int n = 0;
+  ScopeIterator it(isolate, frame, inlined_jsframe_index);
+  for (; !it.Done() && n < index; it.Next()) {
+    n++;
+  }
+  if (it.Done()) {
+    return isolate->heap()->undefined_value();
+  }
+  Handle<JSObject> details;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
+                                     MaterializeScopeDetails(isolate, &it));
+  return *details;
+}
+
+
+// Return an array of scope details
+// args[0]: number: break id
+// args[1]: number: frame index
+// args[2]: number: inlined frame index
+// args[3]: boolean: ignore nested scopes
+//
+// The array returned contains arrays with the following information:
+// 0: Scope type
+// 1: Scope object
+RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3 || args.length() == 4);
+  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+  RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+  CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
+  CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
+
+  bool ignore_nested_scopes = false;
+  if (args.length() == 4) {
+    CONVERT_BOOLEAN_ARG_CHECKED(flag, 3);
+    ignore_nested_scopes = flag;
+  }
+
+  // Get the frame where the debugging is performed.
+  StackFrame::Id id = UnwrapFrameId(wrapped_id);
+  JavaScriptFrameIterator frame_it(isolate, id);
+  JavaScriptFrame* frame = frame_it.frame();
+
+  List<Handle<JSObject> > result(4);
+  ScopeIterator it(isolate, frame, inlined_jsframe_index, ignore_nested_scopes);
+  for (; !it.Done(); it.Next()) {
+    Handle<JSObject> details;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
+                                       MaterializeScopeDetails(isolate, &it));
+    result.Add(details);
+  }
+
+  Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length());
+  for (int i = 0; i < result.length(); ++i) {
+    array->set(i, *result[i]);
+  }
+  return *isolate->factory()->NewJSArrayWithElements(array);
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  // Check arguments.
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
+
+  // Count the visible scopes.
+  int n = 0;
+  for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
+    n++;
+  }
+
+  return Smi::FromInt(n);
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  // Check arguments.
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
+  CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
+
+  // Find the requested scope.
+  int n = 0;
+  ScopeIterator it(isolate, fun);
+  for (; !it.Done() && n < index; it.Next()) {
+    n++;
+  }
+  if (it.Done()) {
+    return isolate->heap()->undefined_value();
+  }
+
+  Handle<JSObject> details;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
+                                     MaterializeScopeDetails(isolate, &it));
+  return *details;
+}
+
+
+static bool SetScopeVariableValue(ScopeIterator* it, int index,
+                                  Handle<String> variable_name,
+                                  Handle<Object> new_value) {
+  for (int n = 0; !it->Done() && n < index; it->Next()) {
+    n++;
+  }
+  if (it->Done()) {
+    return false;
+  }
+  return it->SetVariableValue(variable_name, new_value);
+}
+
+
+// Change variable value in closure or local scope
+// args[0]: number or JsFunction: break id or function
+// args[1]: number: frame index (when arg[0] is break id)
+// args[2]: number: inlined frame index (when arg[0] is break id)
+// args[3]: number: scope index
+// args[4]: string: variable name
+// args[5]: object: new value
+//
+// Return true if success and false otherwise
+RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 6);
+
+  // Check arguments.
+  CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
+  CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4);
+  CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 5);
+
+  bool res;
+  if (args[0]->IsNumber()) {
+    CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+    RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+    CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
+    CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
+
+    // Get the frame where the debugging is performed.
+    StackFrame::Id id = UnwrapFrameId(wrapped_id);
+    JavaScriptFrameIterator frame_it(isolate, id);
+    JavaScriptFrame* frame = frame_it.frame();
+
+    ScopeIterator it(isolate, frame, inlined_jsframe_index);
+    res = SetScopeVariableValue(&it, index, variable_name, new_value);
+  } else {
+    CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
+    ScopeIterator it(isolate, fun);
+    res = SetScopeVariableValue(&it, index, variable_name, new_value);
+  }
+
+  return isolate->heap()->ToBoolean(res);
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugPrintScopes) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+
+#ifdef DEBUG
+  // Print the scopes for the top frame.
+  StackFrameLocator locator(isolate);
+  JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
+  for (ScopeIterator it(isolate, frame, 0); !it.Done(); it.Next()) {
+    it.DebugPrint();
+  }
+#endif
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetThreadCount) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+  RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+  // Count all archived V8 threads.
+  int n = 0;
+  for (ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse();
+       thread != NULL; thread = thread->Next()) {
+    n++;
+  }
+
+  // Total number of threads is current thread and archived threads.
+  return Smi::FromInt(n + 1);
+}
+
+
+static const int kThreadDetailsCurrentThreadIndex = 0;
+static const int kThreadDetailsThreadIdIndex = 1;
+static const int kThreadDetailsSize = 2;
+
+// Return an array with thread details
+// args[0]: number: break id
+// args[1]: number: thread index
+//
+// The array returned contains the following information:
+// 0: Is current thread?
+// 1: Thread id
+RUNTIME_FUNCTION(Runtime_GetThreadDetails) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+  RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+  CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
+
+  // Allocate array for result.
+  Handle<FixedArray> details =
+      isolate->factory()->NewFixedArray(kThreadDetailsSize);
+
+  // Thread index 0 is current thread.
+  if (index == 0) {
+    // Fill the details.
+    details->set(kThreadDetailsCurrentThreadIndex,
+                 isolate->heap()->true_value());
+    details->set(kThreadDetailsThreadIdIndex,
+                 Smi::FromInt(ThreadId::Current().ToInteger()));
+  } else {
+    // Find the thread with the requested index.
+    int n = 1;
+    ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse();
+    while (index != n && thread != NULL) {
+      thread = thread->Next();
+      n++;
+    }
+    if (thread == NULL) {
+      return isolate->heap()->undefined_value();
+    }
+
+    // Fill the details.
+    details->set(kThreadDetailsCurrentThreadIndex,
+                 isolate->heap()->false_value());
+    details->set(kThreadDetailsThreadIdIndex,
+                 Smi::FromInt(thread->id().ToInteger()));
+  }
+
+  // Convert to JS array and return.
+  return *isolate->factory()->NewJSArrayWithElements(details);
+}
+
+
+// Sets the disable break state
+// args[0]: disable break state
+RUNTIME_FUNCTION(Runtime_SetDisableBreak) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
+  isolate->debug()->set_disable_break(disable_break);
+  return isolate->heap()->undefined_value();
+}
+
+
+static bool IsPositionAlignmentCodeCorrect(int alignment) {
+  return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED;
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetBreakLocations) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
+  CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]);
+
+  if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
+    return isolate->ThrowIllegalOperation();
+  }
+  BreakPositionAlignment alignment =
+      static_cast<BreakPositionAlignment>(statement_aligned_code);
+
+  Handle<SharedFunctionInfo> shared(fun->shared());
+  // Find the number of break points
+  Handle<Object> break_locations =
+      Debug::GetSourceBreakLocations(shared, alignment);
+  if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
+  // Return array as JS array
+  return *isolate->factory()->NewJSArrayWithElements(
+      Handle<FixedArray>::cast(break_locations));
+}
+
+
+// Set a break point in a function.
+// args[0]: function
+// args[1]: number: break source position (within the function source)
+// args[2]: number: break point object
+RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+  CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
+  RUNTIME_ASSERT(source_position >= function->shared()->start_position() &&
+                 source_position <= function->shared()->end_position());
+  CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2);
+
+  // Set break point.
+  RUNTIME_ASSERT(isolate->debug()->SetBreakPoint(
+      function, break_point_object_arg, &source_position));
+
+  return Smi::FromInt(source_position);
+}
+
+
+// Changes the state of a break point in a script and returns source position
+// where break point was set. NOTE: Regarding performance see the NOTE for
+// GetScriptFromScriptData.
+// args[0]: script to set break point in
+// args[1]: number: break source position (within the script source)
+// args[2]: number, breakpoint position alignment
+// args[3]: number: break point object
+RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
+  CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
+  RUNTIME_ASSERT(source_position >= 0);
+  CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]);
+  CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3);
+
+  if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
+    return isolate->ThrowIllegalOperation();
+  }
+  BreakPositionAlignment alignment =
+      static_cast<BreakPositionAlignment>(statement_aligned_code);
+
+  // Get the script from the script wrapper.
+  RUNTIME_ASSERT(wrapper->value()->IsScript());
+  Handle<Script> script(Script::cast(wrapper->value()));
+
+  // Set break point.
+  if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
+                                                &source_position, alignment)) {
+    return isolate->heap()->undefined_value();
+  }
+
+  return Smi::FromInt(source_position);
+}
+
+
+// Clear a break point
+// args[0]: number: break point object
+RUNTIME_FUNCTION(Runtime_ClearBreakPoint) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0);
+
+  // Clear break point.
+  isolate->debug()->ClearBreakPoint(break_point_object_arg);
+
+  return isolate->heap()->undefined_value();
+}
+
+
+// Change the state of break on exceptions.
+// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
+// args[1]: Boolean indicating on/off.
+RUNTIME_FUNCTION(Runtime_ChangeBreakOnException) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
+  CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
+
+  // If the number doesn't match an enum value, the ChangeBreakOnException
+  // function will default to affecting caught exceptions.
+  ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
+  // Update break point state.
+  isolate->debug()->ChangeBreakOnException(type, enable);
+  return isolate->heap()->undefined_value();
+}
+
+
+// Returns the state of break on exceptions
+// args[0]: boolean indicating uncaught exceptions
+RUNTIME_FUNCTION(Runtime_IsBreakOnException) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
+
+  ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
+  bool result = isolate->debug()->IsBreakOnException(type);
+  return Smi::FromInt(result);
+}
+
+
+// Prepare for stepping
+// args[0]: break id for checking execution state
+// args[1]: step action from the enumeration StepAction
+// args[2]: number of times to perform the step, for step out it is the number
+//          of frames to step down.
+RUNTIME_FUNCTION(Runtime_PrepareStep) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+  RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+  if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
+    return isolate->Throw(isolate->heap()->illegal_argument_string());
+  }
+
+  CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]);
+
+  StackFrame::Id frame_id;
+  if (wrapped_frame_id == 0) {
+    frame_id = StackFrame::NO_ID;
+  } else {
+    frame_id = UnwrapFrameId(wrapped_frame_id);
+  }
+
+  // Get the step action and check validity.
+  StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
+  if (step_action != StepIn && step_action != StepNext &&
+      step_action != StepOut && step_action != StepInMin &&
+      step_action != StepMin && step_action != StepFrame) {
+    return isolate->Throw(isolate->heap()->illegal_argument_string());
+  }
+
+  if (frame_id != StackFrame::NO_ID && step_action != StepNext &&
+      step_action != StepMin && step_action != StepOut) {
+    return isolate->ThrowIllegalOperation();
+  }
+
+  // Get the number of steps.
+  int step_count = NumberToInt32(args[2]);
+  if (step_count < 1) {
+    return isolate->Throw(isolate->heap()->illegal_argument_string());
+  }
+
+  // Clear all current stepping setup.
+  isolate->debug()->ClearStepping();
+
+  // Prepare step.
+  isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
+                                step_count, frame_id);
+  return isolate->heap()->undefined_value();
+}
+
+
+// Clear all stepping set by PrepareStep.
+RUNTIME_FUNCTION(Runtime_ClearStepping) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+  isolate->debug()->ClearStepping();
+  return isolate->heap()->undefined_value();
+}
+
+
+// Helper function to find or create the arguments object for
+// Runtime_DebugEvaluate.
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeArgumentsObject(
+    Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function) {
+  // Do not materialize the arguments object for eval or top-level code.
+  // Skip if "arguments" is already taken.
+  if (!function->shared()->is_function()) return target;
+  Maybe<bool> maybe = JSReceiver::HasOwnProperty(
+      target, isolate->factory()->arguments_string());
+  if (!maybe.has_value) return MaybeHandle<JSObject>();
+  if (maybe.value) return target;
+
+  // FunctionGetArguments can't throw an exception.
+  Handle<JSObject> arguments =
+      Handle<JSObject>::cast(Accessors::FunctionGetArguments(function));
+  Handle<String> arguments_str = isolate->factory()->arguments_string();
+  RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
+                                   target, arguments_str, arguments, NONE),
+                      JSObject);
+  return target;
+}
+
+
+// Compile and evaluate source for the given context.
+static MaybeHandle<Object> DebugEvaluate(Isolate* isolate,
+                                         Handle<SharedFunctionInfo> outer_info,
+                                         Handle<Context> context,
+                                         Handle<Object> context_extension,
+                                         Handle<Object> receiver,
+                                         Handle<String> source) {
+  if (context_extension->IsJSObject()) {
+    Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
+    Handle<JSFunction> closure(context->closure(), isolate);
+    context = isolate->factory()->NewWithContext(closure, context, extension);
+  }
+
+  Handle<JSFunction> eval_fun;
+  ASSIGN_RETURN_ON_EXCEPTION(isolate, eval_fun,
+                             Compiler::GetFunctionFromEval(
+                                 source, outer_info, context, SLOPPY,
+                                 NO_PARSE_RESTRICTION, RelocInfo::kNoPosition),
+                             Object);
+
+  Handle<Object> result;
+  ASSIGN_RETURN_ON_EXCEPTION(
+      isolate, result, Execution::Call(isolate, eval_fun, receiver, 0, NULL),
+      Object);
+
+  // Skip the global proxy as it has no properties and always delegates to the
+  // real global object.
+  if (result->IsJSGlobalProxy()) {
+    PrototypeIterator iter(isolate, result);
+    // TODO(verwaest): This will crash when the global proxy is detached.
+    result = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+  }
+
+  // Clear the oneshot breakpoints so that the debugger does not step further.
+  isolate->debug()->ClearStepping();
+  return result;
+}
+
+
+static Handle<JSObject> NewJSObjectWithNullProto(Isolate* isolate) {
+  Handle<JSObject> result =
+      isolate->factory()->NewJSObject(isolate->object_function());
+  Handle<Map> new_map =
+      Map::Copy(Handle<Map>(result->map()), "ObjectWithNullProto");
+  new_map->SetPrototype(isolate->factory()->null_value());
+  JSObject::MigrateToMap(result, new_map);
+  return result;
+}
+
+
+// Evaluate a piece of JavaScript in the context of a stack frame for
+// debugging.  Things that need special attention are:
+// - Parameters and stack-allocated locals need to be materialized.  Altered
+//   values need to be written back to the stack afterwards.
+// - The arguments object needs to materialized.
+RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
+  HandleScope scope(isolate);
+
+  // Check the execution state and decode arguments frame and source to be
+  // evaluated.
+  DCHECK(args.length() == 6);
+  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+  RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+  CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
+  CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
+  CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
+  CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
+  CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5);
+
+  // Handle the processing of break.
+  DisableBreak disable_break_scope(isolate->debug(), disable_break);
+
+  // Get the frame where the debugging is performed.
+  StackFrame::Id id = UnwrapFrameId(wrapped_id);
+  JavaScriptFrameIterator it(isolate, id);
+  JavaScriptFrame* frame = it.frame();
+  FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
+  Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
+  Handle<SharedFunctionInfo> outer_info(function->shared());
+
+  // Traverse the saved contexts chain to find the active context for the
+  // selected frame.
+  SaveContext* save = FindSavedContextForFrame(isolate, frame);
+
+  SaveContext savex(isolate);
+  isolate->set_context(*(save->context()));
+
+  // Materialize stack locals and the arguments object.
+  Handle<JSObject> materialized = NewJSObjectWithNullProto(isolate);
+
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, materialized,
+      MaterializeStackLocalsWithFrameInspector(isolate, materialized, function,
+                                               &frame_inspector));
+
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, materialized,
+      MaterializeArgumentsObject(isolate, materialized, function));
+
+  // At this point, the lookup chain may look like this:
+  // [inner context] -> [function stack]+[function context] -> [outer context]
+  // The function stack is not an actual context, it complements the function
+  // context. In order to have the same lookup chain when debug-evaluating,
+  // we materialize the stack and insert it into the context chain as a
+  // with-context before the function context.
+  // [inner context] -> [with context] -> [function context] -> [outer context]
+  // Ordering the with-context before the function context forces a dynamic
+  // lookup instead of a static lookup that could fail as the scope info is
+  // outdated and may expect variables to still be stack-allocated.
+  // Afterwards, we write changes to the with-context back to the stack
+  // and remove it from the context chain.
+  // This could cause lookup failures if debug-evaluate creates a closure that
+  // uses this temporary context chain.
+
+  Handle<Context> eval_context(Context::cast(frame_inspector.GetContext()));
+  DCHECK(!eval_context.is_null());
+  Handle<Context> function_context = eval_context;
+  Handle<Context> outer_context(function->context(), isolate);
+  Handle<Context> inner_context;
+  // We iterate to find the function's context. If the function has no
+  // context-allocated variables, we iterate until we hit the outer context.
+  while (!function_context->IsFunctionContext() &&
+         !function_context->IsScriptContext() &&
+         !function_context.is_identical_to(outer_context)) {
+    inner_context = function_context;
+    function_context = Handle<Context>(function_context->previous(), isolate);
+  }
+
+  Handle<Context> materialized_context = isolate->factory()->NewWithContext(
+      function, function_context, materialized);
+
+  if (inner_context.is_null()) {
+    // No inner context. The with-context is now inner-most.
+    eval_context = materialized_context;
+  } else {
+    inner_context->set_previous(*materialized_context);
+  }
+
+  Handle<Object> receiver(frame->receiver(), isolate);
+  MaybeHandle<Object> maybe_result = DebugEvaluate(
+      isolate, outer_info, eval_context, context_extension, receiver, source);
+
+  // Remove with-context if it was inserted in between.
+  if (!inner_context.is_null()) inner_context->set_previous(*function_context);
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
+
+  // Write back potential changes to materialized stack locals to the stack.
+  UpdateStackLocalsFromMaterializedObject(isolate, materialized, function,
+                                          frame, inlined_jsframe_index);
+
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
+  HandleScope scope(isolate);
+
+  // Check the execution state and decode arguments frame and source to be
+  // evaluated.
+  DCHECK(args.length() == 4);
+  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+  RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+  CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
+  CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
+  CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3);
+
+  // Handle the processing of break.
+  DisableBreak disable_break_scope(isolate->debug(), disable_break);
+
+  // Enter the top context from before the debugger was invoked.
+  SaveContext save(isolate);
+  SaveContext* top = &save;
+  while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
+    top = top->prev();
+  }
+  if (top != NULL) {
+    isolate->set_context(*top->context());
+  }
+
+  // Get the native context now set to the top context from before the
+  // debugger was invoked.
+  Handle<Context> context = isolate->native_context();
+  Handle<JSObject> receiver(context->global_proxy());
+  Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, DebugEvaluate(isolate, outer_info, context,
+                                     context_extension, receiver, source));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+
+  // Fill the script objects.
+  Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
+
+  // Convert the script objects to proper JS objects.
+  for (int i = 0; i < instances->length(); i++) {
+    Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
+    // Get the script wrapper in a local handle before calling GetScriptWrapper,
+    // because using
+    //   instances->set(i, *GetScriptWrapper(script))
+    // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
+    // already have dereferenced the instances handle.
+    Handle<JSObject> wrapper = Script::GetWrapper(script);
+    instances->set(i, *wrapper);
+  }
+
+  // Return result as a JS array.
+  Handle<JSObject> result =
+      isolate->factory()->NewJSObject(isolate->array_function());
+  JSArray::SetContent(Handle<JSArray>::cast(result), instances);
+  return *result;
+}
+
+
+// Helper function used by Runtime_DebugReferencedBy below.
+static int DebugReferencedBy(HeapIterator* iterator, JSObject* target,
+                             Object* instance_filter, int max_references,
+                             FixedArray* instances, int instances_size,
+                             JSFunction* arguments_function) {
+  Isolate* isolate = target->GetIsolate();
+  SealHandleScope shs(isolate);
+  DisallowHeapAllocation no_allocation;
+
+  // Iterate the heap.
+  int count = 0;
+  JSObject* last = NULL;
+  HeapObject* heap_obj = NULL;
+  while (((heap_obj = iterator->next()) != NULL) &&
+         (max_references == 0 || count < max_references)) {
+    // Only look at all JSObjects.
+    if (heap_obj->IsJSObject()) {
+      // Skip context extension objects and argument arrays as these are
+      // checked in the context of functions using them.
+      JSObject* obj = JSObject::cast(heap_obj);
+      if (obj->IsJSContextExtensionObject() ||
+          obj->map()->constructor() == arguments_function) {
+        continue;
+      }
+
+      // Check if the JS object has a reference to the object looked for.
+      if (obj->ReferencesObject(target)) {
+        // Check instance filter if supplied. This is normally used to avoid
+        // references from mirror objects (see Runtime_IsInPrototypeChain).
+        if (!instance_filter->IsUndefined()) {
+          for (PrototypeIterator iter(isolate, obj); !iter.IsAtEnd();
+               iter.Advance()) {
+            if (iter.GetCurrent() == instance_filter) {
+              obj = NULL;  // Don't add this object.
+              break;
+            }
+          }
+        }
+
+        if (obj != NULL) {
+          // Valid reference found add to instance array if supplied an update
+          // count.
+          if (instances != NULL && count < instances_size) {
+            instances->set(count, obj);
+          }
+          last = obj;
+          count++;
+        }
+      }
+    }
+  }
+
+  // Check for circular reference only. This can happen when the object is only
+  // referenced from mirrors and has a circular reference in which case the
+  // object is not really alive and would have been garbage collected if not
+  // referenced from the mirror.
+  if (count == 1 && last == target) {
+    count = 0;
+  }
+
+  // Return the number of referencing objects found.
+  return count;
+}
+
+
+// Scan the heap for objects with direct references to an object
+// args[0]: the object to find references to
+// args[1]: constructor function for instances to exclude (Mirror)
+// args[2]: the the maximum number of objects to return
+RUNTIME_FUNCTION(Runtime_DebugReferencedBy) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+
+  // Check parameters.
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, instance_filter, 1);
+  RUNTIME_ASSERT(instance_filter->IsUndefined() ||
+                 instance_filter->IsJSObject());
+  CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
+  RUNTIME_ASSERT(max_references >= 0);
+
+
+  // Get the constructor function for context extension and arguments array.
+  Handle<JSFunction> arguments_function(
+      JSFunction::cast(isolate->sloppy_arguments_map()->constructor()));
+
+  // Get the number of referencing objects.
+  int count;
+  // First perform a full GC in order to avoid dead objects and to make the heap
+  // iterable.
+  Heap* heap = isolate->heap();
+  heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
+  {
+    HeapIterator heap_iterator(heap);
+    count = DebugReferencedBy(&heap_iterator, *target, *instance_filter,
+                              max_references, NULL, 0, *arguments_function);
+  }
+
+  // Allocate an array to hold the result.
+  Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
+
+  // Fill the referencing objects.
+  {
+    HeapIterator heap_iterator(heap);
+    count = DebugReferencedBy(&heap_iterator, *target, *instance_filter,
+                              max_references, *instances, count,
+                              *arguments_function);
+  }
+
+  // Return result as JS array.
+  Handle<JSFunction> constructor = isolate->array_function();
+
+  Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
+  JSArray::SetContent(Handle<JSArray>::cast(result), instances);
+  return *result;
+}
+
+
+// Helper function used by Runtime_DebugConstructedBy below.
+static int DebugConstructedBy(HeapIterator* iterator, JSFunction* constructor,
+                              int max_references, FixedArray* instances,
+                              int instances_size) {
+  DisallowHeapAllocation no_allocation;
+
+  // Iterate the heap.
+  int count = 0;
+  HeapObject* heap_obj = NULL;
+  while (((heap_obj = iterator->next()) != NULL) &&
+         (max_references == 0 || count < max_references)) {
+    // Only look at all JSObjects.
+    if (heap_obj->IsJSObject()) {
+      JSObject* obj = JSObject::cast(heap_obj);
+      if (obj->map()->constructor() == constructor) {
+        // Valid reference found add to instance array if supplied an update
+        // count.
+        if (instances != NULL && count < instances_size) {
+          instances->set(count, obj);
+        }
+        count++;
+      }
+    }
+  }
+
+  // Return the number of referencing objects found.
+  return count;
+}
+
+
+// Scan the heap for objects constructed by a specific function.
+// args[0]: the constructor to find instances of
+// args[1]: the the maximum number of objects to return
+RUNTIME_FUNCTION(Runtime_DebugConstructedBy) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+
+  // Check parameters.
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
+  CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
+  RUNTIME_ASSERT(max_references >= 0);
+
+  // Get the number of referencing objects.
+  int count;
+  // First perform a full GC in order to avoid dead objects and to make the heap
+  // iterable.
+  Heap* heap = isolate->heap();
+  heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
+  {
+    HeapIterator heap_iterator(heap);
+    count = DebugConstructedBy(&heap_iterator, *constructor, max_references,
+                               NULL, 0);
+  }
+
+  // Allocate an array to hold the result.
+  Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
+
+  // Fill the referencing objects.
+  {
+    HeapIterator heap_iterator2(heap);
+    count = DebugConstructedBy(&heap_iterator2, *constructor, max_references,
+                               *instances, count);
+  }
+
+  // Return result as JS array.
+  Handle<JSFunction> array_function = isolate->array_function();
+  Handle<JSObject> result = isolate->factory()->NewJSObject(array_function);
+  JSArray::SetContent(Handle<JSArray>::cast(result), instances);
+  return *result;
+}
+
+
+// Find the effective prototype object as returned by __proto__.
+// args[0]: the object to find the prototype for.
+RUNTIME_FUNCTION(Runtime_DebugGetPrototype) {
+  HandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+  return *Object::GetPrototypeSkipHiddenPrototypes(isolate, obj);
+}
+
+
+// Patches script source (should be called upon BeforeCompile event).
+RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
+
+  RUNTIME_ASSERT(script_wrapper->value()->IsScript());
+  Handle<Script> script(Script::cast(script_wrapper->value()));
+
+  int compilation_state = script->compilation_state();
+  RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
+  script->set_source(*source);
+
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugDisassembleFunction) {
+  HandleScope scope(isolate);
+#ifdef DEBUG
+  DCHECK(args.length() == 1);
+  // Get the function and make sure it is compiled.
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
+  if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
+    return isolate->heap()->exception();
+  }
+  OFStream os(stdout);
+  func->code()->Print(os);
+  os << std::endl;
+#endif  // DEBUG
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugDisassembleConstructor) {
+  HandleScope scope(isolate);
+#ifdef DEBUG
+  DCHECK(args.length() == 1);
+  // Get the function and make sure it is compiled.
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
+  if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
+    return isolate->heap()->exception();
+  }
+  OFStream os(stdout);
+  func->shared()->construct_stub()->Print(os);
+  os << std::endl;
+#endif  // DEBUG
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_CHECKED(JSFunction, f, 0);
+  return f->shared()->inferred_name();
+}
+
+
+// A testing entry. Returns statement position which is the closest to
+// source_position.
+RUNTIME_FUNCTION(Runtime_GetFunctionCodePositionFromSource) {
+  HandleScope scope(isolate);
+  CHECK(isolate->debug()->live_edit_enabled());
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+  CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
+
+  Handle<Code> code(function->code(), isolate);
+
+  if (code->kind() != Code::FUNCTION &&
+      code->kind() != Code::OPTIMIZED_FUNCTION) {
+    return isolate->heap()->undefined_value();
+  }
+
+  RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
+  int closest_pc = 0;
+  int distance = kMaxInt;
+  while (!it.done()) {
+    int statement_position = static_cast<int>(it.rinfo()->data());
+    // Check if this break point is closer that what was previously found.
+    if (source_position <= statement_position &&
+        statement_position - source_position < distance) {
+      closest_pc =
+          static_cast<int>(it.rinfo()->pc() - code->instruction_start());
+      distance = statement_position - source_position;
+      // Check whether we can't get any closer.
+      if (distance == 0) break;
+    }
+    it.next();
+  }
+
+  return Smi::FromInt(closest_pc);
+}
+
+
+// Calls specified function with or without entering the debugger.
+// This is used in unit tests to run code as if debugger is entered or simply
+// to have a stack with C++ frame in the middle.
+RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+  CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
+
+  MaybeHandle<Object> maybe_result;
+  if (without_debugger) {
+    maybe_result = Execution::Call(isolate, function,
+                                   handle(function->global_proxy()), 0, NULL);
+  } else {
+    DebugScope debug_scope(isolate->debug());
+    maybe_result = Execution::Call(isolate, function,
+                                   handle(function->global_proxy()), 0, NULL);
+  }
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
+  return *result;
+}
+
+
+// Performs a GC.
+// Presently, it only does a full GC.
+RUNTIME_FUNCTION(Runtime_CollectGarbage) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
+  return isolate->heap()->undefined_value();
+}
+
+
+// Gets the current heap usage.
+RUNTIME_FUNCTION(Runtime_GetHeapUsage) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
+  if (!Smi::IsValid(usage)) {
+    return *isolate->factory()->NewNumberFromInt(usage);
+  }
+  return Smi::FromInt(usage);
+}
+
+
+// Finds the script object from the script data. NOTE: This operation uses
+// heap traversal to find the function generated for the source position
+// for the requested break point. For lazily compiled functions several heap
+// traversals might be required rendering this operation as a rather slow
+// operation. However for setting break points which is normally done through
+// some kind of user interaction the performance is not crucial.
+RUNTIME_FUNCTION(Runtime_GetScript) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, script_name, 0);
+
+  Handle<Script> found;
+  Heap* heap = isolate->heap();
+  {
+    HeapIterator iterator(heap);
+    HeapObject* obj = NULL;
+    while ((obj = iterator.next()) != NULL) {
+      if (!obj->IsScript()) continue;
+      Script* script = Script::cast(obj);
+      if (!script->name()->IsString()) continue;
+      String* name = String::cast(script->name());
+      if (name->Equals(*script_name)) {
+        found = Handle<Script>(script, isolate);
+        break;
+      }
+    }
+  }
+
+  if (found.is_null()) return heap->undefined_value();
+  return *Script::GetWrapper(found);
+}
+
+
+// Check whether debugger and is about to step into the callback that is passed
+// to a built-in function such as Array.forEach.
+RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) {
+  DCHECK(args.length() == 1);
+  Debug* debug = isolate->debug();
+  if (!debug->is_active() || !debug->IsStepping() ||
+      debug->last_step_action() != StepIn) {
+    return isolate->heap()->false_value();
+  }
+  CONVERT_ARG_CHECKED(Object, callback, 0);
+  // We do not step into the callback if it's a builtin or not even a function.
+  return isolate->heap()->ToBoolean(callback->IsJSFunction() &&
+                                    !JSFunction::cast(callback)->IsBuiltin());
+}
+
+
+// Set one shot breakpoints for the callback function that is passed to a
+// built-in function such as Array.forEach to enable stepping into the callback.
+RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) {
+  DCHECK(args.length() == 1);
+  Debug* debug = isolate->debug();
+  if (!debug->IsStepping()) return isolate->heap()->undefined_value();
+
+  HandleScope scope(isolate);
+  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
+  RUNTIME_ASSERT(object->IsJSFunction() || object->IsJSGeneratorObject());
+  Handle<JSFunction> fun;
+  if (object->IsJSFunction()) {
+    fun = Handle<JSFunction>::cast(object);
+  } else {
+    fun = Handle<JSFunction>(
+        Handle<JSGeneratorObject>::cast(object)->function(), isolate);
+  }
+  // When leaving the function, step out has been activated, but not performed
+  // if we do not leave the builtin.  To be able to step into the function
+  // again, we need to clear the step out at this point.
+  debug->ClearStepOut();
+  debug->FloodWithOneShot(fun);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugPushPromise) {
+  DCHECK(args.length() == 1);
+  HandleScope scope(isolate);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
+  isolate->PushPromise(promise);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugPopPromise) {
+  DCHECK(args.length() == 0);
+  SealHandleScope shs(isolate);
+  isolate->PopPromise();
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugPromiseEvent) {
+  DCHECK(args.length() == 1);
+  HandleScope scope(isolate);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
+  isolate->debug()->OnPromiseEvent(data);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugAsyncTaskEvent) {
+  DCHECK(args.length() == 1);
+  HandleScope scope(isolate);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
+  isolate->debug()->OnAsyncTaskEvent(data);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_DebugIsActive) {
+  SealHandleScope shs(isolate);
+  return Smi::FromInt(isolate->debug()->is_active());
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_DebugBreakInOptimizedCode) {
+  UNIMPLEMENTED();
+  return NULL;
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-function.cc b/src/runtime/runtime-function.cc
new file mode 100644
index 0000000..e25b659
--- /dev/null
+++ b/src/runtime/runtime-function.cc
@@ -0,0 +1,625 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/accessors.h"
+#include "src/arguments.h"
+#include "src/compiler.h"
+#include "src/deoptimizer.h"
+#include "src/frames.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_IsSloppyModeFunction) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
+  if (!callable->IsJSFunction()) {
+    HandleScope scope(isolate);
+    Handle<Object> delegate;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, delegate, Execution::TryGetFunctionDelegate(
+                               isolate, Handle<JSReceiver>(callable)));
+    callable = JSFunction::cast(*delegate);
+  }
+  JSFunction* function = JSFunction::cast(callable);
+  SharedFunctionInfo* shared = function->shared();
+  return isolate->heap()->ToBoolean(shared->strict_mode() == SLOPPY);
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetDefaultReceiver) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
+
+  if (!callable->IsJSFunction()) {
+    HandleScope scope(isolate);
+    Handle<Object> delegate;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, delegate, Execution::TryGetFunctionDelegate(
+                               isolate, Handle<JSReceiver>(callable)));
+    callable = JSFunction::cast(*delegate);
+  }
+  JSFunction* function = JSFunction::cast(callable);
+
+  SharedFunctionInfo* shared = function->shared();
+  if (shared->native() || shared->strict_mode() == STRICT) {
+    return isolate->heap()->undefined_value();
+  }
+  // Returns undefined for strict or native functions, or
+  // the associated global receiver for "normal" functions.
+
+  return function->global_proxy();
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionGetName) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_CHECKED(JSFunction, f, 0);
+  return f->shared()->name();
+}
+
+
+static Handle<String> NameToFunctionName(Handle<Name> name) {
+  Handle<String> stringName(name->GetHeap()->empty_string());
+
+  // TODO(caitp): Follow proper rules in section 9.2.11 (SetFunctionName)
+  if (name->IsSymbol()) {
+    Handle<Object> description(Handle<Symbol>::cast(name)->name(),
+                               name->GetIsolate());
+    if (description->IsString()) {
+      stringName = Handle<String>::cast(description);
+    }
+  } else {
+    stringName = Handle<String>::cast(name);
+  }
+
+  return stringName;
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionSetName) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
+
+  f->shared()->set_name(*NameToFunctionName(name));
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionNameShouldPrintAsAnonymous) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSFunction, f, 0);
+  return isolate->heap()->ToBoolean(
+      f->shared()->name_should_print_as_anonymous());
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSFunction, f, 0);
+  f->shared()->set_name_should_print_as_anonymous(true);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionIsArrow) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSFunction, f, 0);
+  return isolate->heap()->ToBoolean(f->shared()->is_arrow());
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionIsConciseMethod) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSFunction, f, 0);
+  return isolate->heap()->ToBoolean(f->shared()->is_concise_method());
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionRemovePrototype) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_CHECKED(JSFunction, f, 0);
+  RUNTIME_ASSERT(f->RemovePrototype());
+
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionGetScript) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_CHECKED(JSFunction, fun, 0);
+  Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
+  if (!script->IsScript()) return isolate->heap()->undefined_value();
+
+  return *Script::GetWrapper(Handle<Script>::cast(script));
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionGetSourceCode) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
+  Handle<SharedFunctionInfo> shared(f->shared());
+  return *shared->GetSourceCode();
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionGetScriptSourcePosition) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_CHECKED(JSFunction, fun, 0);
+  int pos = fun->shared()->start_position();
+  return Smi::FromInt(pos);
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionGetPositionForOffset) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_CHECKED(Code, code, 0);
+  CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
+
+  RUNTIME_ASSERT(0 <= offset && offset < code->Size());
+
+  Address pc = code->address() + offset;
+  return Smi::FromInt(code->SourcePosition(pc));
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionSetInstanceClassName) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_CHECKED(JSFunction, fun, 0);
+  CONVERT_ARG_CHECKED(String, name, 1);
+  fun->SetInstanceClassName(name);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionSetLength) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_CHECKED(JSFunction, fun, 0);
+  CONVERT_SMI_ARG_CHECKED(length, 1);
+  RUNTIME_ASSERT((length & 0xC0000000) == 0xC0000000 ||
+                 (length & 0xC0000000) == 0x0);
+  fun->shared()->set_length(length);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
+  RUNTIME_ASSERT(fun->should_have_prototype());
+  RETURN_FAILURE_ON_EXCEPTION(isolate,
+                              Accessors::FunctionSetPrototype(fun, value));
+  return args[0];  // return TOS
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionIsAPIFunction) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_CHECKED(JSFunction, f, 0);
+  return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionIsBuiltin) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_CHECKED(JSFunction, f, 0);
+  return isolate->heap()->ToBoolean(f->IsBuiltin());
+}
+
+
+RUNTIME_FUNCTION(Runtime_SetCode) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, source, 1);
+
+  Handle<SharedFunctionInfo> target_shared(target->shared());
+  Handle<SharedFunctionInfo> source_shared(source->shared());
+  RUNTIME_ASSERT(!source_shared->bound());
+
+  if (!Compiler::EnsureCompiled(source, KEEP_EXCEPTION)) {
+    return isolate->heap()->exception();
+  }
+
+  // Mark both, the source and the target, as un-flushable because the
+  // shared unoptimized code makes them impossible to enqueue in a list.
+  DCHECK(target_shared->code()->gc_metadata() == NULL);
+  DCHECK(source_shared->code()->gc_metadata() == NULL);
+  target_shared->set_dont_flush(true);
+  source_shared->set_dont_flush(true);
+
+  // Set the code, scope info, formal parameter count, and the length
+  // of the target shared function info.
+  target_shared->ReplaceCode(source_shared->code());
+  target_shared->set_scope_info(source_shared->scope_info());
+  target_shared->set_length(source_shared->length());
+  target_shared->set_feedback_vector(source_shared->feedback_vector());
+  target_shared->set_formal_parameter_count(
+      source_shared->formal_parameter_count());
+  target_shared->set_script(source_shared->script());
+  target_shared->set_start_position_and_type(
+      source_shared->start_position_and_type());
+  target_shared->set_end_position(source_shared->end_position());
+  bool was_native = target_shared->native();
+  target_shared->set_compiler_hints(source_shared->compiler_hints());
+  target_shared->set_native(was_native);
+  target_shared->set_profiler_ticks(source_shared->profiler_ticks());
+
+  // Set the code of the target function.
+  target->ReplaceCode(source_shared->code());
+  DCHECK(target->next_function_link()->IsUndefined());
+
+  // Make sure we get a fresh copy of the literal vector to avoid cross
+  // context contamination.
+  Handle<Context> context(source->context());
+  int number_of_literals = source->NumberOfLiterals();
+  Handle<FixedArray> literals =
+      isolate->factory()->NewFixedArray(number_of_literals, TENURED);
+  if (number_of_literals > 0) {
+    literals->set(JSFunction::kLiteralNativeContextIndex,
+                  context->native_context());
+  }
+  target->set_context(*context);
+  target->set_literals(*literals);
+
+  if (isolate->logger()->is_logging_code_events() ||
+      isolate->cpu_profiler()->is_profiling()) {
+    isolate->logger()->LogExistingFunction(source_shared,
+                                           Handle<Code>(source_shared->code()));
+  }
+
+  return *target;
+}
+
+
+// Set the native flag on the function.
+// This is used to decide if we should transform null and undefined
+// into the global object when doing call and apply.
+RUNTIME_FUNCTION(Runtime_SetNativeFlag) {
+  SealHandleScope shs(isolate);
+  RUNTIME_ASSERT(args.length() == 1);
+
+  CONVERT_ARG_CHECKED(Object, object, 0);
+
+  if (object->IsJSFunction()) {
+    JSFunction* func = JSFunction::cast(object);
+    func->shared()->set_native(true);
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_SetInlineBuiltinFlag) {
+  SealHandleScope shs(isolate);
+  RUNTIME_ASSERT(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
+
+  if (object->IsJSFunction()) {
+    JSFunction* func = JSFunction::cast(*object);
+    func->shared()->set_inline_builtin(true);
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
+// Find the arguments of the JavaScript function invocation that called
+// into C++ code. Collect these in a newly allocated array of handles (possibly
+// prefixed by a number of empty handles).
+static SmartArrayPointer<Handle<Object> > GetCallerArguments(Isolate* isolate,
+                                                             int prefix_argc,
+                                                             int* total_argc) {
+  // Find frame containing arguments passed to the caller.
+  JavaScriptFrameIterator it(isolate);
+  JavaScriptFrame* frame = it.frame();
+  List<JSFunction*> functions(2);
+  frame->GetFunctions(&functions);
+  if (functions.length() > 1) {
+    int inlined_jsframe_index = functions.length() - 1;
+    JSFunction* inlined_function = functions[inlined_jsframe_index];
+    SlotRefValueBuilder slot_refs(
+        frame, inlined_jsframe_index,
+        inlined_function->shared()->formal_parameter_count());
+
+    int args_count = slot_refs.args_length();
+
+    *total_argc = prefix_argc + args_count;
+    SmartArrayPointer<Handle<Object> > param_data(
+        NewArray<Handle<Object> >(*total_argc));
+    slot_refs.Prepare(isolate);
+    for (int i = 0; i < args_count; i++) {
+      Handle<Object> val = slot_refs.GetNext(isolate, 0);
+      param_data[prefix_argc + i] = val;
+    }
+    slot_refs.Finish(isolate);
+
+    return param_data;
+  } else {
+    it.AdvanceToArgumentsFrame();
+    frame = it.frame();
+    int args_count = frame->ComputeParametersCount();
+
+    *total_argc = prefix_argc + args_count;
+    SmartArrayPointer<Handle<Object> > param_data(
+        NewArray<Handle<Object> >(*total_argc));
+    for (int i = 0; i < args_count; i++) {
+      Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
+      param_data[prefix_argc + i] = val;
+    }
+    return param_data;
+  }
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionBindArguments) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, bindee, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, this_object, 2);
+  CONVERT_NUMBER_ARG_HANDLE_CHECKED(new_length, 3);
+
+  // TODO(lrn): Create bound function in C++ code from premade shared info.
+  bound_function->shared()->set_bound(true);
+  // Get all arguments of calling function (Function.prototype.bind).
+  int argc = 0;
+  SmartArrayPointer<Handle<Object> > arguments =
+      GetCallerArguments(isolate, 0, &argc);
+  // Don't count the this-arg.
+  if (argc > 0) {
+    RUNTIME_ASSERT(arguments[0].is_identical_to(this_object));
+    argc--;
+  } else {
+    RUNTIME_ASSERT(this_object->IsUndefined());
+  }
+  // Initialize array of bindings (function, this, and any existing arguments
+  // if the function was already bound).
+  Handle<FixedArray> new_bindings;
+  int i;
+  if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
+    Handle<FixedArray> old_bindings(
+        JSFunction::cast(*bindee)->function_bindings());
+    RUNTIME_ASSERT(old_bindings->length() > JSFunction::kBoundFunctionIndex);
+    new_bindings =
+        isolate->factory()->NewFixedArray(old_bindings->length() + argc);
+    bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex),
+                            isolate);
+    i = 0;
+    for (int n = old_bindings->length(); i < n; i++) {
+      new_bindings->set(i, old_bindings->get(i));
+    }
+  } else {
+    int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
+    new_bindings = isolate->factory()->NewFixedArray(array_size);
+    new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
+    new_bindings->set(JSFunction::kBoundThisIndex, *this_object);
+    i = 2;
+  }
+  // Copy arguments, skipping the first which is "this_arg".
+  for (int j = 0; j < argc; j++, i++) {
+    new_bindings->set(i, *arguments[j + 1]);
+  }
+  new_bindings->set_map_no_write_barrier(
+      isolate->heap()->fixed_cow_array_map());
+  bound_function->set_function_bindings(*new_bindings);
+
+  // Update length. Have to remove the prototype first so that map migration
+  // is happy about the number of fields.
+  RUNTIME_ASSERT(bound_function->RemovePrototype());
+  Handle<Map> bound_function_map(
+      isolate->native_context()->bound_function_map());
+  JSObject::MigrateToMap(bound_function, bound_function_map);
+  Handle<String> length_string = isolate->factory()->length_string();
+  PropertyAttributes attr =
+      static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+                   bound_function, length_string, new_length, attr));
+  return *bound_function;
+}
+
+
+RUNTIME_FUNCTION(Runtime_BoundFunctionGetBindings) {
+  HandleScope handles(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
+  if (callable->IsJSFunction()) {
+    Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
+    if (function->shared()->bound()) {
+      Handle<FixedArray> bindings(function->function_bindings());
+      RUNTIME_ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
+      return *isolate->factory()->NewJSArrayWithElements(bindings);
+    }
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewObjectFromBound) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  // First argument is a function to use as a constructor.
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+  RUNTIME_ASSERT(function->shared()->bound());
+
+  // The argument is a bound function. Extract its bound arguments
+  // and callable.
+  Handle<FixedArray> bound_args =
+      Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
+  int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
+  Handle<Object> bound_function(
+      JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)),
+      isolate);
+  DCHECK(!bound_function->IsJSFunction() ||
+         !Handle<JSFunction>::cast(bound_function)->shared()->bound());
+
+  int total_argc = 0;
+  SmartArrayPointer<Handle<Object> > param_data =
+      GetCallerArguments(isolate, bound_argc, &total_argc);
+  for (int i = 0; i < bound_argc; i++) {
+    param_data[i] = Handle<Object>(
+        bound_args->get(JSFunction::kBoundArgumentsStartIndex + i), isolate);
+  }
+
+  if (!bound_function->IsJSFunction()) {
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, bound_function,
+        Execution::TryGetConstructorDelegate(isolate, bound_function));
+  }
+  DCHECK(bound_function->IsJSFunction());
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, Execution::New(Handle<JSFunction>::cast(bound_function),
+                                      total_argc, param_data.get()));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_Call) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() >= 2);
+  int argc = args.length() - 2;
+  CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
+  Object* receiver = args[0];
+
+  // If there are too many arguments, allocate argv via malloc.
+  const int argv_small_size = 10;
+  Handle<Object> argv_small_buffer[argv_small_size];
+  SmartArrayPointer<Handle<Object> > argv_large_buffer;
+  Handle<Object>* argv = argv_small_buffer;
+  if (argc > argv_small_size) {
+    argv = new Handle<Object>[argc];
+    if (argv == NULL) return isolate->StackOverflow();
+    argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
+  }
+
+  for (int i = 0; i < argc; ++i) {
+    argv[i] = Handle<Object>(args[1 + i], isolate);
+  }
+
+  Handle<JSReceiver> hfun(fun);
+  Handle<Object> hreceiver(receiver, isolate);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Execution::Call(isolate, hfun, hreceiver, argc, argv, true));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_Apply) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 5);
+  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
+  CONVERT_INT32_ARG_CHECKED(offset, 3);
+  CONVERT_INT32_ARG_CHECKED(argc, 4);
+  RUNTIME_ASSERT(offset >= 0);
+  // Loose upper bound to allow fuzzing. We'll most likely run out of
+  // stack space before hitting this limit.
+  static int kMaxArgc = 1000000;
+  RUNTIME_ASSERT(argc >= 0 && argc <= kMaxArgc);
+
+  // If there are too many arguments, allocate argv via malloc.
+  const int argv_small_size = 10;
+  Handle<Object> argv_small_buffer[argv_small_size];
+  SmartArrayPointer<Handle<Object> > argv_large_buffer;
+  Handle<Object>* argv = argv_small_buffer;
+  if (argc > argv_small_size) {
+    argv = new Handle<Object>[argc];
+    if (argv == NULL) return isolate->StackOverflow();
+    argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
+  }
+
+  for (int i = 0; i < argc; ++i) {
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, argv[i], Object::GetElement(isolate, arguments, offset + i));
+  }
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Execution::Call(isolate, fun, receiver, argc, argv, true));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetFunctionDelegate) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
+  RUNTIME_ASSERT(!object->IsJSFunction());
+  return *Execution::GetFunctionDelegate(isolate, object);
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetConstructorDelegate) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
+  RUNTIME_ASSERT(!object->IsJSFunction());
+  return *Execution::GetConstructorDelegate(isolate, object);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_CallFunction) {
+  SealHandleScope shs(isolate);
+  return __RT_impl_Runtime_Call(args, isolate);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_IsConstructCall) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  JavaScriptFrameIterator it(isolate);
+  JavaScriptFrame* frame = it.frame();
+  return isolate->heap()->ToBoolean(frame->IsConstructor());
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_IsFunction) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  return isolate->heap()->ToBoolean(obj->IsJSFunction());
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-generator.cc b/src/runtime/runtime-generator.cc
new file mode 100644
index 0000000..ff07acd
--- /dev/null
+++ b/src/runtime/runtime-generator.cc
@@ -0,0 +1,227 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/frames-inl.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+
+  JavaScriptFrameIterator it(isolate);
+  JavaScriptFrame* frame = it.frame();
+  Handle<JSFunction> function(frame->function());
+  RUNTIME_ASSERT(function->shared()->is_generator());
+
+  Handle<JSGeneratorObject> generator;
+  if (frame->IsConstructor()) {
+    generator = handle(JSGeneratorObject::cast(frame->receiver()));
+  } else {
+    generator = isolate->factory()->NewJSGeneratorObject(function);
+  }
+  generator->set_function(*function);
+  generator->set_context(Context::cast(frame->context()));
+  generator->set_receiver(frame->receiver());
+  generator->set_continuation(0);
+  generator->set_operand_stack(isolate->heap()->empty_fixed_array());
+  generator->set_stack_handler_index(-1);
+
+  return *generator;
+}
+
+
+RUNTIME_FUNCTION(Runtime_SuspendJSGeneratorObject) {
+  HandleScope handle_scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0);
+
+  JavaScriptFrameIterator stack_iterator(isolate);
+  JavaScriptFrame* frame = stack_iterator.frame();
+  RUNTIME_ASSERT(frame->function()->shared()->is_generator());
+  DCHECK_EQ(frame->function(), generator_object->function());
+
+  // The caller should have saved the context and continuation already.
+  DCHECK_EQ(generator_object->context(), Context::cast(frame->context()));
+  DCHECK_LT(0, generator_object->continuation());
+
+  // We expect there to be at least two values on the operand stack: the return
+  // value of the yield expression, and the argument to this runtime call.
+  // Neither of those should be saved.
+  int operands_count = frame->ComputeOperandsCount();
+  DCHECK_GE(operands_count, 2);
+  operands_count -= 2;
+
+  if (operands_count == 0) {
+    // Although it's semantically harmless to call this function with an
+    // operands_count of zero, it is also unnecessary.
+    DCHECK_EQ(generator_object->operand_stack(),
+              isolate->heap()->empty_fixed_array());
+    DCHECK_EQ(generator_object->stack_handler_index(), -1);
+    // If there are no operands on the stack, there shouldn't be a handler
+    // active either.
+    DCHECK(!frame->HasHandler());
+  } else {
+    int stack_handler_index = -1;
+    Handle<FixedArray> operand_stack =
+        isolate->factory()->NewFixedArray(operands_count);
+    frame->SaveOperandStack(*operand_stack, &stack_handler_index);
+    generator_object->set_operand_stack(*operand_stack);
+    generator_object->set_stack_handler_index(stack_handler_index);
+  }
+
+  return isolate->heap()->undefined_value();
+}
+
+
+// Note that this function is the slow path for resuming generators.  It is only
+// called if the suspended activation had operands on the stack, stack handlers
+// needing rewinding, or if the resume should throw an exception.  The fast path
+// is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is
+// inlined into GeneratorNext and GeneratorThrow.  EmitGeneratorResumeResume is
+// called in any case, as it needs to reconstruct the stack frame and make space
+// for arguments and operands.
+RUNTIME_FUNCTION(Runtime_ResumeJSGeneratorObject) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
+  CONVERT_ARG_CHECKED(Object, value, 1);
+  CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2);
+  JavaScriptFrameIterator stack_iterator(isolate);
+  JavaScriptFrame* frame = stack_iterator.frame();
+
+  DCHECK_EQ(frame->function(), generator_object->function());
+  DCHECK(frame->function()->is_compiled());
+
+  STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
+  STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
+
+  Address pc = generator_object->function()->code()->instruction_start();
+  int offset = generator_object->continuation();
+  DCHECK(offset > 0);
+  frame->set_pc(pc + offset);
+  if (FLAG_enable_ool_constant_pool) {
+    frame->set_constant_pool(
+        generator_object->function()->code()->constant_pool());
+  }
+  generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting);
+
+  FixedArray* operand_stack = generator_object->operand_stack();
+  int operands_count = operand_stack->length();
+  if (operands_count != 0) {
+    frame->RestoreOperandStack(operand_stack,
+                               generator_object->stack_handler_index());
+    generator_object->set_operand_stack(isolate->heap()->empty_fixed_array());
+    generator_object->set_stack_handler_index(-1);
+  }
+
+  JSGeneratorObject::ResumeMode resume_mode =
+      static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int);
+  switch (resume_mode) {
+    case JSGeneratorObject::NEXT:
+      return value;
+    case JSGeneratorObject::THROW:
+      return isolate->Throw(value);
+  }
+
+  UNREACHABLE();
+  return isolate->ThrowIllegalOperation();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GeneratorClose) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
+
+  generator->set_continuation(JSGeneratorObject::kGeneratorClosed);
+
+  return isolate->heap()->undefined_value();
+}
+
+
+// Returns function of generator activation.
+RUNTIME_FUNCTION(Runtime_GeneratorGetFunction) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
+
+  return generator->function();
+}
+
+
+// Returns context of generator activation.
+RUNTIME_FUNCTION(Runtime_GeneratorGetContext) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
+
+  return generator->context();
+}
+
+
+// Returns receiver of generator activation.
+RUNTIME_FUNCTION(Runtime_GeneratorGetReceiver) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
+
+  return generator->receiver();
+}
+
+
+// Returns generator continuation as a PC offset, or the magic -1 or 0 values.
+RUNTIME_FUNCTION(Runtime_GeneratorGetContinuation) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
+
+  return Smi::FromInt(generator->continuation());
+}
+
+
+RUNTIME_FUNCTION(Runtime_GeneratorGetSourcePosition) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
+
+  if (generator->is_suspended()) {
+    Handle<Code> code(generator->function()->code(), isolate);
+    int offset = generator->continuation();
+
+    RUNTIME_ASSERT(0 <= offset && offset < code->Size());
+    Address pc = code->address() + offset;
+
+    return Smi::FromInt(code->SourcePosition(pc));
+  }
+
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionIsGenerator) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSFunction, f, 0);
+  return isolate->heap()->ToBoolean(f->shared()->is_generator());
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_GeneratorNext) {
+  UNREACHABLE();  // Optimization disabled in SetUpGenerators().
+  return NULL;
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_GeneratorThrow) {
+  UNREACHABLE();  // Optimization disabled in SetUpGenerators().
+  return NULL;
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-i18n.cc b/src/runtime/runtime-i18n.cc
new file mode 100644
index 0000000..94d9f42
--- /dev/null
+++ b/src/runtime/runtime-i18n.cc
@@ -0,0 +1,751 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+#ifdef V8_I18N_SUPPORT
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/i18n.h"
+#include "src/runtime/runtime-utils.h"
+
+#include "unicode/brkiter.h"
+#include "unicode/calendar.h"
+#include "unicode/coll.h"
+#include "unicode/curramt.h"
+#include "unicode/datefmt.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/decimfmt.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/dtptngen.h"
+#include "unicode/locid.h"
+#include "unicode/numfmt.h"
+#include "unicode/numsys.h"
+#include "unicode/rbbi.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/timezone.h"
+#include "unicode/uchar.h"
+#include "unicode/ucol.h"
+#include "unicode/ucurr.h"
+#include "unicode/uloc.h"
+#include "unicode/unum.h"
+#include "unicode/uversion.h"
+
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) {
+  HandleScope scope(isolate);
+  Factory* factory = isolate->factory();
+
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0);
+
+  v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str));
+
+  // Return value which denotes invalid language tag.
+  const char* const kInvalidTag = "invalid-tag";
+
+  UErrorCode error = U_ZERO_ERROR;
+  char icu_result[ULOC_FULLNAME_CAPACITY];
+  int icu_length = 0;
+
+  uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY,
+                      &icu_length, &error);
+  if (U_FAILURE(error) || icu_length == 0) {
+    return *factory->NewStringFromAsciiChecked(kInvalidTag);
+  }
+
+  char result[ULOC_FULLNAME_CAPACITY];
+
+  // Force strict BCP47 rules.
+  uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error);
+
+  if (U_FAILURE(error)) {
+    return *factory->NewStringFromAsciiChecked(kInvalidTag);
+  }
+
+  return *factory->NewStringFromAsciiChecked(result);
+}
+
+
+RUNTIME_FUNCTION(Runtime_AvailableLocalesOf) {
+  HandleScope scope(isolate);
+  Factory* factory = isolate->factory();
+
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, service, 0);
+
+  const icu::Locale* available_locales = NULL;
+  int32_t count = 0;
+
+  if (service->IsUtf8EqualTo(CStrVector("collator"))) {
+    available_locales = icu::Collator::getAvailableLocales(count);
+  } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) {
+    available_locales = icu::NumberFormat::getAvailableLocales(count);
+  } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) {
+    available_locales = icu::DateFormat::getAvailableLocales(count);
+  } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) {
+    available_locales = icu::BreakIterator::getAvailableLocales(count);
+  }
+
+  UErrorCode error = U_ZERO_ERROR;
+  char result[ULOC_FULLNAME_CAPACITY];
+  Handle<JSObject> locales = factory->NewJSObject(isolate->object_function());
+
+  for (int32_t i = 0; i < count; ++i) {
+    const char* icu_name = available_locales[i].getName();
+
+    error = U_ZERO_ERROR;
+    // No need to force strict BCP47 rules.
+    uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
+    if (U_FAILURE(error)) {
+      // This shouldn't happen, but lets not break the user.
+      continue;
+    }
+
+    RETURN_FAILURE_ON_EXCEPTION(
+        isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+                     locales, factory->NewStringFromAsciiChecked(result),
+                     factory->NewNumber(i), NONE));
+  }
+
+  return *locales;
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetDefaultICULocale) {
+  HandleScope scope(isolate);
+  Factory* factory = isolate->factory();
+
+  DCHECK(args.length() == 0);
+
+  icu::Locale default_locale;
+
+  // Set the locale
+  char result[ULOC_FULLNAME_CAPACITY];
+  UErrorCode status = U_ZERO_ERROR;
+  uloc_toLanguageTag(default_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
+                     FALSE, &status);
+  if (U_SUCCESS(status)) {
+    return *factory->NewStringFromAsciiChecked(result);
+  }
+
+  return *factory->NewStringFromStaticChars("und");
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetLanguageTagVariants) {
+  HandleScope scope(isolate);
+  Factory* factory = isolate->factory();
+
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0);
+
+  uint32_t length = static_cast<uint32_t>(input->length()->Number());
+  // Set some limit to prevent fuzz tests from going OOM.
+  // Can be bumped when callers' requirements change.
+  RUNTIME_ASSERT(length < 100);
+  Handle<FixedArray> output = factory->NewFixedArray(length);
+  Handle<Name> maximized = factory->NewStringFromStaticChars("maximized");
+  Handle<Name> base = factory->NewStringFromStaticChars("base");
+  for (unsigned int i = 0; i < length; ++i) {
+    Handle<Object> locale_id;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, locale_id,
+                                       Object::GetElement(isolate, input, i));
+    if (!locale_id->IsString()) {
+      return isolate->Throw(*factory->illegal_argument_string());
+    }
+
+    v8::String::Utf8Value utf8_locale_id(
+        v8::Utils::ToLocal(Handle<String>::cast(locale_id)));
+
+    UErrorCode error = U_ZERO_ERROR;
+
+    // Convert from BCP47 to ICU format.
+    // de-DE-u-co-phonebk -> de_DE@collation=phonebook
+    char icu_locale[ULOC_FULLNAME_CAPACITY];
+    int icu_locale_length = 0;
+    uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY,
+                        &icu_locale_length, &error);
+    if (U_FAILURE(error) || icu_locale_length == 0) {
+      return isolate->Throw(*factory->illegal_argument_string());
+    }
+
+    // Maximize the locale.
+    // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook
+    char icu_max_locale[ULOC_FULLNAME_CAPACITY];
+    uloc_addLikelySubtags(icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY,
+                          &error);
+
+    // Remove extensions from maximized locale.
+    // de_Latn_DE@collation=phonebook -> de_Latn_DE
+    char icu_base_max_locale[ULOC_FULLNAME_CAPACITY];
+    uloc_getBaseName(icu_max_locale, icu_base_max_locale,
+                     ULOC_FULLNAME_CAPACITY, &error);
+
+    // Get original name without extensions.
+    // de_DE@collation=phonebook -> de_DE
+    char icu_base_locale[ULOC_FULLNAME_CAPACITY];
+    uloc_getBaseName(icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY,
+                     &error);
+
+    // Convert from ICU locale format to BCP47 format.
+    // de_Latn_DE -> de-Latn-DE
+    char base_max_locale[ULOC_FULLNAME_CAPACITY];
+    uloc_toLanguageTag(icu_base_max_locale, base_max_locale,
+                       ULOC_FULLNAME_CAPACITY, FALSE, &error);
+
+    // de_DE -> de-DE
+    char base_locale[ULOC_FULLNAME_CAPACITY];
+    uloc_toLanguageTag(icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY,
+                       FALSE, &error);
+
+    if (U_FAILURE(error)) {
+      return isolate->Throw(*factory->illegal_argument_string());
+    }
+
+    Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
+    Handle<String> value = factory->NewStringFromAsciiChecked(base_max_locale);
+    JSObject::AddProperty(result, maximized, value, NONE);
+    value = factory->NewStringFromAsciiChecked(base_locale);
+    JSObject::AddProperty(result, base, value, NONE);
+    output->set(i, *result);
+  }
+
+  Handle<JSArray> result = factory->NewJSArrayWithElements(output);
+  result->set_length(Smi::FromInt(length));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_IsInitializedIntlObject) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
+
+  if (!input->IsJSObject()) return isolate->heap()->false_value();
+  Handle<JSObject> obj = Handle<JSObject>::cast(input);
+
+  Handle<Symbol> marker = isolate->factory()->intl_initialized_marker_symbol();
+  Handle<Object> tag = JSObject::GetDataProperty(obj, marker);
+  return isolate->heap()->ToBoolean(!tag->IsUndefined());
+}
+
+
+RUNTIME_FUNCTION(Runtime_IsInitializedIntlObjectOfType) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, expected_type, 1);
+
+  if (!input->IsJSObject()) return isolate->heap()->false_value();
+  Handle<JSObject> obj = Handle<JSObject>::cast(input);
+
+  Handle<Symbol> marker = isolate->factory()->intl_initialized_marker_symbol();
+  Handle<Object> tag = JSObject::GetDataProperty(obj, marker);
+  return isolate->heap()->ToBoolean(tag->IsString() &&
+                                    String::cast(*tag)->Equals(*expected_type));
+}
+
+
+RUNTIME_FUNCTION(Runtime_MarkAsInitializedIntlObjectOfType) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, impl, 2);
+
+  Handle<Symbol> marker = isolate->factory()->intl_initialized_marker_symbol();
+  JSObject::SetProperty(input, marker, type, STRICT).Assert();
+
+  marker = isolate->factory()->intl_impl_object_symbol();
+  JSObject::SetProperty(input, marker, impl, STRICT).Assert();
+
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetImplFromInitializedIntlObject) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
+
+  if (!input->IsJSObject()) {
+    Vector<Handle<Object> > arguments = HandleVector(&input, 1);
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate,
+                                   NewTypeError("not_intl_object", arguments));
+  }
+
+  Handle<JSObject> obj = Handle<JSObject>::cast(input);
+
+  Handle<Symbol> marker = isolate->factory()->intl_impl_object_symbol();
+
+  Handle<Object> impl = JSObject::GetDataProperty(obj, marker);
+  if (impl->IsTheHole()) {
+    Vector<Handle<Object> > arguments = HandleVector(&obj, 1);
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate,
+                                   NewTypeError("not_intl_object", arguments));
+  }
+  return *impl;
+}
+
+
+RUNTIME_FUNCTION(Runtime_CreateDateTimeFormat) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
+
+  Handle<ObjectTemplateInfo> date_format_template = I18N::GetTemplate(isolate);
+
+  // Create an empty object wrapper.
+  Handle<JSObject> local_object;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, local_object,
+      Execution::InstantiateObject(date_format_template));
+
+  // Set date time formatter as internal field of the resulting JS object.
+  icu::SimpleDateFormat* date_format =
+      DateFormat::InitializeDateTimeFormat(isolate, locale, options, resolved);
+
+  if (!date_format) return isolate->ThrowIllegalOperation();
+
+  local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format));
+
+  Factory* factory = isolate->factory();
+  Handle<String> key = factory->NewStringFromStaticChars("dateFormat");
+  Handle<String> value = factory->NewStringFromStaticChars("valid");
+  JSObject::AddProperty(local_object, key, value, NONE);
+
+  // Make object handle weak so we can delete the data format once GC kicks in.
+  Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
+  GlobalHandles::MakeWeak(wrapper.location(),
+                          reinterpret_cast<void*>(wrapper.location()),
+                          DateFormat::DeleteDateFormat);
+  return *local_object;
+}
+
+
+RUNTIME_FUNCTION(Runtime_InternalDateFormat) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1);
+
+  Handle<Object> value;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
+                                     Execution::ToNumber(isolate, date));
+
+  icu::SimpleDateFormat* date_format =
+      DateFormat::UnpackDateFormat(isolate, date_format_holder);
+  if (!date_format) return isolate->ThrowIllegalOperation();
+
+  icu::UnicodeString result;
+  date_format->format(value->Number(), result);
+
+  Handle<String> result_str;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result_str,
+      isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
+          reinterpret_cast<const uint16_t*>(result.getBuffer()),
+          result.length())));
+  return *result_str;
+}
+
+
+RUNTIME_FUNCTION(Runtime_InternalDateParse) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1);
+
+  v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string));
+  icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date));
+  icu::SimpleDateFormat* date_format =
+      DateFormat::UnpackDateFormat(isolate, date_format_holder);
+  if (!date_format) return isolate->ThrowIllegalOperation();
+
+  UErrorCode status = U_ZERO_ERROR;
+  UDate date = date_format->parse(u_date, status);
+  if (U_FAILURE(status)) return isolate->heap()->undefined_value();
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, Execution::NewDate(isolate, static_cast<double>(date)));
+  DCHECK(result->IsJSDate());
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_CreateNumberFormat) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
+
+  Handle<ObjectTemplateInfo> number_format_template =
+      I18N::GetTemplate(isolate);
+
+  // Create an empty object wrapper.
+  Handle<JSObject> local_object;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, local_object,
+      Execution::InstantiateObject(number_format_template));
+
+  // Set number formatter as internal field of the resulting JS object.
+  icu::DecimalFormat* number_format =
+      NumberFormat::InitializeNumberFormat(isolate, locale, options, resolved);
+
+  if (!number_format) return isolate->ThrowIllegalOperation();
+
+  local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format));
+
+  Factory* factory = isolate->factory();
+  Handle<String> key = factory->NewStringFromStaticChars("numberFormat");
+  Handle<String> value = factory->NewStringFromStaticChars("valid");
+  JSObject::AddProperty(local_object, key, value, NONE);
+
+  Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
+  GlobalHandles::MakeWeak(wrapper.location(),
+                          reinterpret_cast<void*>(wrapper.location()),
+                          NumberFormat::DeleteNumberFormat);
+  return *local_object;
+}
+
+
+RUNTIME_FUNCTION(Runtime_InternalNumberFormat) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, number, 1);
+
+  Handle<Object> value;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
+                                     Execution::ToNumber(isolate, number));
+
+  icu::DecimalFormat* number_format =
+      NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
+  if (!number_format) return isolate->ThrowIllegalOperation();
+
+  icu::UnicodeString result;
+  number_format->format(value->Number(), result);
+
+  Handle<String> result_str;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result_str,
+      isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
+          reinterpret_cast<const uint16_t*>(result.getBuffer()),
+          result.length())));
+  return *result_str;
+}
+
+
+RUNTIME_FUNCTION(Runtime_InternalNumberParse) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1);
+
+  v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string));
+  icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number));
+  icu::DecimalFormat* number_format =
+      NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
+  if (!number_format) return isolate->ThrowIllegalOperation();
+
+  UErrorCode status = U_ZERO_ERROR;
+  icu::Formattable result;
+  // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49
+  // to be part of Chrome.
+  // TODO(cira): Include currency parsing code using parseCurrency call.
+  // We need to check if the formatter parses all currencies or only the
+  // one it was constructed with (it will impact the API - how to return ISO
+  // code and the value).
+  number_format->parse(u_number, result, status);
+  if (U_FAILURE(status)) return isolate->heap()->undefined_value();
+
+  switch (result.getType()) {
+    case icu::Formattable::kDouble:
+      return *isolate->factory()->NewNumber(result.getDouble());
+    case icu::Formattable::kLong:
+      return *isolate->factory()->NewNumberFromInt(result.getLong());
+    case icu::Formattable::kInt64:
+      return *isolate->factory()->NewNumber(
+          static_cast<double>(result.getInt64()));
+    default:
+      return isolate->heap()->undefined_value();
+  }
+}
+
+
+RUNTIME_FUNCTION(Runtime_CreateCollator) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
+
+  Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate);
+
+  // Create an empty object wrapper.
+  Handle<JSObject> local_object;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, local_object, Execution::InstantiateObject(collator_template));
+
+  // Set collator as internal field of the resulting JS object.
+  icu::Collator* collator =
+      Collator::InitializeCollator(isolate, locale, options, resolved);
+
+  if (!collator) return isolate->ThrowIllegalOperation();
+
+  local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator));
+
+  Factory* factory = isolate->factory();
+  Handle<String> key = factory->NewStringFromStaticChars("collator");
+  Handle<String> value = factory->NewStringFromStaticChars("valid");
+  JSObject::AddProperty(local_object, key, value, NONE);
+
+  Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
+  GlobalHandles::MakeWeak(wrapper.location(),
+                          reinterpret_cast<void*>(wrapper.location()),
+                          Collator::DeleteCollator);
+  return *local_object;
+}
+
+
+RUNTIME_FUNCTION(Runtime_InternalCompare) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, string1, 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, string2, 2);
+
+  icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder);
+  if (!collator) return isolate->ThrowIllegalOperation();
+
+  v8::String::Value string_value1(v8::Utils::ToLocal(string1));
+  v8::String::Value string_value2(v8::Utils::ToLocal(string2));
+  const UChar* u_string1 = reinterpret_cast<const UChar*>(*string_value1);
+  const UChar* u_string2 = reinterpret_cast<const UChar*>(*string_value2);
+  UErrorCode status = U_ZERO_ERROR;
+  UCollationResult result =
+      collator->compare(u_string1, string_value1.length(), u_string2,
+                        string_value2.length(), status);
+  if (U_FAILURE(status)) return isolate->ThrowIllegalOperation();
+
+  return *isolate->factory()->NewNumberFromInt(result);
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringNormalize) {
+  HandleScope scope(isolate);
+  static const UNormalizationMode normalizationForms[] = {
+      UNORM_NFC, UNORM_NFD, UNORM_NFKC, UNORM_NFKD};
+
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, stringValue, 0);
+  CONVERT_NUMBER_CHECKED(int, form_id, Int32, args[1]);
+  RUNTIME_ASSERT(form_id >= 0 &&
+                 static_cast<size_t>(form_id) < arraysize(normalizationForms));
+
+  v8::String::Value string_value(v8::Utils::ToLocal(stringValue));
+  const UChar* u_value = reinterpret_cast<const UChar*>(*string_value);
+
+  // TODO(mnita): check Normalizer2 (not available in ICU 46)
+  UErrorCode status = U_ZERO_ERROR;
+  icu::UnicodeString result;
+  icu::Normalizer::normalize(u_value, normalizationForms[form_id], 0, result,
+                             status);
+  if (U_FAILURE(status)) {
+    return isolate->heap()->undefined_value();
+  }
+
+  Handle<String> result_str;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result_str,
+      isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
+          reinterpret_cast<const uint16_t*>(result.getBuffer()),
+          result.length())));
+  return *result_str;
+}
+
+
+RUNTIME_FUNCTION(Runtime_CreateBreakIterator) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
+
+  Handle<ObjectTemplateInfo> break_iterator_template =
+      I18N::GetTemplate2(isolate);
+
+  // Create an empty object wrapper.
+  Handle<JSObject> local_object;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, local_object,
+      Execution::InstantiateObject(break_iterator_template));
+
+  // Set break iterator as internal field of the resulting JS object.
+  icu::BreakIterator* break_iterator = BreakIterator::InitializeBreakIterator(
+      isolate, locale, options, resolved);
+
+  if (!break_iterator) return isolate->ThrowIllegalOperation();
+
+  local_object->SetInternalField(0, reinterpret_cast<Smi*>(break_iterator));
+  // Make sure that the pointer to adopted text is NULL.
+  local_object->SetInternalField(1, reinterpret_cast<Smi*>(NULL));
+
+  Factory* factory = isolate->factory();
+  Handle<String> key = factory->NewStringFromStaticChars("breakIterator");
+  Handle<String> value = factory->NewStringFromStaticChars("valid");
+  JSObject::AddProperty(local_object, key, value, NONE);
+
+  // Make object handle weak so we can delete the break iterator once GC kicks
+  // in.
+  Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
+  GlobalHandles::MakeWeak(wrapper.location(),
+                          reinterpret_cast<void*>(wrapper.location()),
+                          BreakIterator::DeleteBreakIterator);
+  return *local_object;
+}
+
+
+RUNTIME_FUNCTION(Runtime_BreakIteratorAdoptText) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, text, 1);
+
+  icu::BreakIterator* break_iterator =
+      BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
+  if (!break_iterator) return isolate->ThrowIllegalOperation();
+
+  icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>(
+      break_iterator_holder->GetInternalField(1));
+  delete u_text;
+
+  v8::String::Value text_value(v8::Utils::ToLocal(text));
+  u_text = new icu::UnicodeString(reinterpret_cast<const UChar*>(*text_value),
+                                  text_value.length());
+  break_iterator_holder->SetInternalField(1, reinterpret_cast<Smi*>(u_text));
+
+  break_iterator->setText(*u_text);
+
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_BreakIteratorFirst) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
+
+  icu::BreakIterator* break_iterator =
+      BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
+  if (!break_iterator) return isolate->ThrowIllegalOperation();
+
+  return *isolate->factory()->NewNumberFromInt(break_iterator->first());
+}
+
+
+RUNTIME_FUNCTION(Runtime_BreakIteratorNext) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
+
+  icu::BreakIterator* break_iterator =
+      BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
+  if (!break_iterator) return isolate->ThrowIllegalOperation();
+
+  return *isolate->factory()->NewNumberFromInt(break_iterator->next());
+}
+
+
+RUNTIME_FUNCTION(Runtime_BreakIteratorCurrent) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
+
+  icu::BreakIterator* break_iterator =
+      BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
+  if (!break_iterator) return isolate->ThrowIllegalOperation();
+
+  return *isolate->factory()->NewNumberFromInt(break_iterator->current());
+}
+
+
+RUNTIME_FUNCTION(Runtime_BreakIteratorBreakType) {
+  HandleScope scope(isolate);
+
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
+
+  icu::BreakIterator* break_iterator =
+      BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
+  if (!break_iterator) return isolate->ThrowIllegalOperation();
+
+  // TODO(cira): Remove cast once ICU fixes base BreakIterator class.
+  icu::RuleBasedBreakIterator* rule_based_iterator =
+      static_cast<icu::RuleBasedBreakIterator*>(break_iterator);
+  int32_t status = rule_based_iterator->getRuleStatus();
+  // Keep return values in sync with JavaScript BreakType enum.
+  if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
+    return *isolate->factory()->NewStringFromStaticChars("none");
+  } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
+    return *isolate->factory()->number_string();
+  } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
+    return *isolate->factory()->NewStringFromStaticChars("letter");
+  } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
+    return *isolate->factory()->NewStringFromStaticChars("kana");
+  } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
+    return *isolate->factory()->NewStringFromStaticChars("ideo");
+  } else {
+    return *isolate->factory()->NewStringFromStaticChars("unknown");
+  }
+}
+}
+}  // namespace v8::internal
+
+#endif  // V8_I18N_SUPPORT
diff --git a/src/runtime/runtime-internal.cc b/src/runtime/runtime-internal.cc
new file mode 100644
index 0000000..79dface
--- /dev/null
+++ b/src/runtime/runtime-internal.cc
@@ -0,0 +1,282 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/bootstrapper.h"
+#include "src/debug.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_CheckIsBootstrapping) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_Throw) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  return isolate->Throw(args[0]);
+}
+
+
+RUNTIME_FUNCTION(Runtime_ReThrow) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  return isolate->ReThrow(args[0]);
+}
+
+
+RUNTIME_FUNCTION(Runtime_PromoteScheduledException) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  return isolate->PromoteScheduledException();
+}
+
+
+RUNTIME_FUNCTION(Runtime_ThrowReferenceError) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
+  THROW_NEW_ERROR_RETURN_FAILURE(
+      isolate, NewReferenceError("not_defined", HandleVector(&name, 1)));
+}
+
+
+RUNTIME_FUNCTION(Runtime_PromiseRejectEvent) {
+  DCHECK(args.length() == 3);
+  HandleScope scope(isolate);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
+  CONVERT_BOOLEAN_ARG_CHECKED(debug_event, 2);
+  if (debug_event) isolate->debug()->OnPromiseReject(promise, value);
+  Handle<Symbol> key = isolate->factory()->promise_has_handler_symbol();
+  // Do not report if we actually have a handler.
+  if (JSObject::GetDataProperty(promise, key)->IsUndefined()) {
+    isolate->ReportPromiseReject(promise, value,
+                                 v8::kPromiseRejectWithNoHandler);
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_PromiseRevokeReject) {
+  DCHECK(args.length() == 1);
+  HandleScope scope(isolate);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
+  Handle<Symbol> key = isolate->factory()->promise_has_handler_symbol();
+  // At this point, no revocation has been issued before
+  RUNTIME_ASSERT(JSObject::GetDataProperty(promise, key)->IsUndefined());
+  isolate->ReportPromiseReject(promise, Handle<Object>(),
+                               v8::kPromiseHandlerAddedAfterReject);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_PromiseHasHandlerSymbol) {
+  DCHECK(args.length() == 0);
+  return isolate->heap()->promise_has_handler_symbol();
+}
+
+
+RUNTIME_FUNCTION(Runtime_StackGuard) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+
+  // First check if this is a real stack overflow.
+  StackLimitCheck check(isolate);
+  if (check.JsHasOverflowed()) {
+    return isolate->StackOverflow();
+  }
+
+  return isolate->stack_guard()->HandleInterrupts();
+}
+
+
+RUNTIME_FUNCTION(Runtime_Interrupt) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  return isolate->stack_guard()->HandleInterrupts();
+}
+
+
+RUNTIME_FUNCTION(Runtime_AllocateInNewSpace) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_SMI_ARG_CHECKED(size, 0);
+  RUNTIME_ASSERT(IsAligned(size, kPointerSize));
+  RUNTIME_ASSERT(size > 0);
+  RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize);
+  return *isolate->factory()->NewFillerObject(size, false, NEW_SPACE);
+}
+
+
+RUNTIME_FUNCTION(Runtime_AllocateInTargetSpace) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_SMI_ARG_CHECKED(size, 0);
+  CONVERT_SMI_ARG_CHECKED(flags, 1);
+  RUNTIME_ASSERT(IsAligned(size, kPointerSize));
+  RUNTIME_ASSERT(size > 0);
+  RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize);
+  bool double_align = AllocateDoubleAlignFlag::decode(flags);
+  AllocationSpace space = AllocateTargetSpace::decode(flags);
+  return *isolate->factory()->NewFillerObject(size, double_align, space);
+}
+
+
+// Collect the raw data for a stack trace.  Returns an array of 4
+// element segments each containing a receiver, function, code and
+// native code offset.
+RUNTIME_FUNCTION(Runtime_CollectStackTrace) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, caller, 1);
+
+  if (!isolate->bootstrapper()->IsActive()) {
+    // Optionally capture a more detailed stack trace for the message.
+    isolate->CaptureAndSetDetailedStackTrace(error_object);
+    // Capture a simple stack trace for the stack property.
+    isolate->CaptureAndSetSimpleStackTrace(error_object, caller);
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetFromCache) {
+  SealHandleScope shs(isolate);
+  // This is only called from codegen, so checks might be more lax.
+  CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
+  CONVERT_ARG_CHECKED(Object, key, 1);
+
+  {
+    DisallowHeapAllocation no_alloc;
+
+    int finger_index = cache->finger_index();
+    Object* o = cache->get(finger_index);
+    if (o == key) {
+      // The fastest case: hit the same place again.
+      return cache->get(finger_index + 1);
+    }
+
+    for (int i = finger_index - 2; i >= JSFunctionResultCache::kEntriesIndex;
+         i -= 2) {
+      o = cache->get(i);
+      if (o == key) {
+        cache->set_finger_index(i);
+        return cache->get(i + 1);
+      }
+    }
+
+    int size = cache->size();
+    DCHECK(size <= cache->length());
+
+    for (int i = size - 2; i > finger_index; i -= 2) {
+      o = cache->get(i);
+      if (o == key) {
+        cache->set_finger_index(i);
+        return cache->get(i + 1);
+      }
+    }
+  }
+
+  // There is no value in the cache.  Invoke the function and cache result.
+  HandleScope scope(isolate);
+
+  Handle<JSFunctionResultCache> cache_handle(cache);
+  Handle<Object> key_handle(key, isolate);
+  Handle<Object> value;
+  {
+    Handle<JSFunction> factory(JSFunction::cast(
+        cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
+    // TODO(antonm): consider passing a receiver when constructing a cache.
+    Handle<JSObject> receiver(isolate->global_proxy());
+    // This handle is nor shared, nor used later, so it's safe.
+    Handle<Object> argv[] = {key_handle};
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, value,
+        Execution::Call(isolate, factory, receiver, arraysize(argv), argv));
+  }
+
+#ifdef VERIFY_HEAP
+  if (FLAG_verify_heap) {
+    cache_handle->JSFunctionResultCacheVerify();
+  }
+#endif
+
+  // Function invocation may have cleared the cache.  Reread all the data.
+  int finger_index = cache_handle->finger_index();
+  int size = cache_handle->size();
+
+  // If we have spare room, put new data into it, otherwise evict post finger
+  // entry which is likely to be the least recently used.
+  int index = -1;
+  if (size < cache_handle->length()) {
+    cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
+    index = size;
+  } else {
+    index = finger_index + JSFunctionResultCache::kEntrySize;
+    if (index == cache_handle->length()) {
+      index = JSFunctionResultCache::kEntriesIndex;
+    }
+  }
+
+  DCHECK(index % 2 == 0);
+  DCHECK(index >= JSFunctionResultCache::kEntriesIndex);
+  DCHECK(index < cache_handle->length());
+
+  cache_handle->set(index, *key_handle);
+  cache_handle->set(index + 1, *value);
+  cache_handle->set_finger_index(index);
+
+#ifdef VERIFY_HEAP
+  if (FLAG_verify_heap) {
+    cache_handle->JSFunctionResultCacheVerify();
+  }
+#endif
+
+  return *value;
+}
+
+
+RUNTIME_FUNCTION(Runtime_MessageGetStartPosition) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
+  return Smi::FromInt(message->start_position());
+}
+
+
+RUNTIME_FUNCTION(Runtime_MessageGetScript) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
+  return message->script();
+}
+
+
+RUNTIME_FUNCTION(Runtime_IS_VAR) {
+  UNREACHABLE();  // implemented as macro in the parser
+  return NULL;
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_GetFromCache) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_SMI_ARG_CHECKED(id, 0);
+  args[0] = isolate->native_context()->jsfunction_result_caches()->get(id);
+  return __RT_impl_Runtime_GetFromCache(args, isolate);
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-json.cc b/src/runtime/runtime-json.cc
new file mode 100644
index 0000000..647f48b
--- /dev/null
+++ b/src/runtime/runtime-json.cc
@@ -0,0 +1,53 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/json-parser.h"
+#include "src/json-stringifier.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_QuoteJSONString) {
+  HandleScope scope(isolate);
+  CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
+  DCHECK(args.length() == 1);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, BasicJsonStringifier::StringifyString(isolate, string));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_BasicJSONStringify) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
+  BasicJsonStringifier stringifier(isolate);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     stringifier.Stringify(object));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_ParseJson) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
+
+  source = String::Flatten(source);
+  // Optimized fast case where we only have Latin1 characters.
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     source->IsSeqOneByteString()
+                                         ? JsonParser<true>::Parse(source)
+                                         : JsonParser<false>::Parse(source));
+  return *result;
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-literals.cc b/src/runtime/runtime-literals.cc
new file mode 100644
index 0000000..8bbe0ee
--- /dev/null
+++ b/src/runtime/runtime-literals.cc
@@ -0,0 +1,435 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/allocation-site-scopes.h"
+#include "src/arguments.h"
+#include "src/ast.h"
+#include "src/parser.h"
+#include "src/runtime/runtime.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+static Handle<Map> ComputeObjectLiteralMap(
+    Handle<Context> context, Handle<FixedArray> constant_properties,
+    bool* is_result_from_cache) {
+  int properties_length = constant_properties->length();
+  int number_of_properties = properties_length / 2;
+
+  for (int p = 0; p != properties_length; p += 2) {
+    Object* key = constant_properties->get(p);
+    uint32_t element_index = 0;
+    if (key->ToArrayIndex(&element_index)) {
+      // An index key does not require space in the property backing store.
+      number_of_properties--;
+    }
+  }
+  Isolate* isolate = context->GetIsolate();
+  return isolate->factory()->ObjectLiteralMapFromCache(
+      context, number_of_properties, is_result_from_cache);
+}
+
+MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate(
+    Isolate* isolate, Handle<FixedArray> literals,
+    Handle<FixedArray> constant_properties);
+
+
+MUST_USE_RESULT static MaybeHandle<Object> CreateObjectLiteralBoilerplate(
+    Isolate* isolate, Handle<FixedArray> literals,
+    Handle<FixedArray> constant_properties, bool should_have_fast_elements,
+    bool has_function_literal) {
+  // Get the native context from the literals array.  This is the
+  // context in which the function was created and we use the object
+  // function from this context to create the object literal.  We do
+  // not use the object function from the current native context
+  // because this might be the object function from another context
+  // which we should not have access to.
+  Handle<Context> context =
+      Handle<Context>(JSFunction::NativeContextFromLiterals(*literals));
+
+  // In case we have function literals, we want the object to be in
+  // slow properties mode for now. We don't go in the map cache because
+  // maps with constant functions can't be shared if the functions are
+  // not the same (which is the common case).
+  bool is_result_from_cache = false;
+  Handle<Map> map = has_function_literal
+                        ? Handle<Map>(context->object_function()->initial_map())
+                        : ComputeObjectLiteralMap(context, constant_properties,
+                                                  &is_result_from_cache);
+
+  PretenureFlag pretenure_flag =
+      isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
+
+  Handle<JSObject> boilerplate =
+      isolate->factory()->NewJSObjectFromMap(map, pretenure_flag);
+
+  // Normalize the elements of the boilerplate to save space if needed.
+  if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
+
+  // Add the constant properties to the boilerplate.
+  int length = constant_properties->length();
+  bool should_transform =
+      !is_result_from_cache && boilerplate->HasFastProperties();
+  bool should_normalize = should_transform || has_function_literal;
+  if (should_normalize) {
+    // TODO(verwaest): We might not want to ever normalize here.
+    JSObject::NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES,
+                                  length / 2, "Boilerplate");
+  }
+  // TODO(verwaest): Support tracking representations in the boilerplate.
+  for (int index = 0; index < length; index += 2) {
+    Handle<Object> key(constant_properties->get(index + 0), isolate);
+    Handle<Object> value(constant_properties->get(index + 1), isolate);
+    if (value->IsFixedArray()) {
+      // The value contains the constant_properties of a
+      // simple object or array literal.
+      Handle<FixedArray> array = Handle<FixedArray>::cast(value);
+      ASSIGN_RETURN_ON_EXCEPTION(
+          isolate, value, CreateLiteralBoilerplate(isolate, literals, array),
+          Object);
+    }
+    MaybeHandle<Object> maybe_result;
+    uint32_t element_index = 0;
+    if (key->IsInternalizedString()) {
+      if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
+        // Array index as string (uint32).
+        if (value->IsUninitialized()) value = handle(Smi::FromInt(0), isolate);
+        maybe_result =
+            JSObject::SetOwnElement(boilerplate, element_index, value, SLOPPY);
+      } else {
+        Handle<String> name(String::cast(*key));
+        DCHECK(!name->AsArrayIndex(&element_index));
+        maybe_result = JSObject::SetOwnPropertyIgnoreAttributes(
+            boilerplate, name, value, NONE);
+      }
+    } else if (key->ToArrayIndex(&element_index)) {
+      // Array index (uint32).
+      if (value->IsUninitialized()) value = handle(Smi::FromInt(0), isolate);
+      maybe_result =
+          JSObject::SetOwnElement(boilerplate, element_index, value, SLOPPY);
+    } else {
+      // Non-uint32 number.
+      DCHECK(key->IsNumber());
+      double num = key->Number();
+      char arr[100];
+      Vector<char> buffer(arr, arraysize(arr));
+      const char* str = DoubleToCString(num, buffer);
+      Handle<String> name = isolate->factory()->NewStringFromAsciiChecked(str);
+      maybe_result = JSObject::SetOwnPropertyIgnoreAttributes(boilerplate, name,
+                                                              value, NONE);
+    }
+    // If setting the property on the boilerplate throws an
+    // exception, the exception is converted to an empty handle in
+    // the handle based operations.  In that case, we need to
+    // convert back to an exception.
+    RETURN_ON_EXCEPTION(isolate, maybe_result, Object);
+  }
+
+  // Transform to fast properties if necessary. For object literals with
+  // containing function literals we defer this operation until after all
+  // computed properties have been assigned so that we can generate
+  // constant function properties.
+  if (should_transform && !has_function_literal) {
+    JSObject::MigrateSlowToFast(boilerplate,
+                                boilerplate->map()->unused_property_fields(),
+                                "FastLiteral");
+  }
+  return boilerplate;
+}
+
+
+MaybeHandle<Object> Runtime::CreateArrayLiteralBoilerplate(
+    Isolate* isolate, Handle<FixedArray> literals,
+    Handle<FixedArray> elements) {
+  // Create the JSArray.
+  Handle<JSFunction> constructor(
+      JSFunction::NativeContextFromLiterals(*literals)->array_function());
+
+  PretenureFlag pretenure_flag =
+      isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
+
+  Handle<JSArray> object = Handle<JSArray>::cast(
+      isolate->factory()->NewJSObject(constructor, pretenure_flag));
+
+  ElementsKind constant_elements_kind =
+      static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
+  Handle<FixedArrayBase> constant_elements_values(
+      FixedArrayBase::cast(elements->get(1)));
+
+  {
+    DisallowHeapAllocation no_gc;
+    DCHECK(IsFastElementsKind(constant_elements_kind));
+    Context* native_context = isolate->context()->native_context();
+    Object* maps_array = native_context->js_array_maps();
+    DCHECK(!maps_array->IsUndefined());
+    Object* map = FixedArray::cast(maps_array)->get(constant_elements_kind);
+    object->set_map(Map::cast(map));
+  }
+
+  Handle<FixedArrayBase> copied_elements_values;
+  if (IsFastDoubleElementsKind(constant_elements_kind)) {
+    copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
+        Handle<FixedDoubleArray>::cast(constant_elements_values));
+  } else {
+    DCHECK(IsFastSmiOrObjectElementsKind(constant_elements_kind));
+    const bool is_cow = (constant_elements_values->map() ==
+                         isolate->heap()->fixed_cow_array_map());
+    if (is_cow) {
+      copied_elements_values = constant_elements_values;
+#if DEBUG
+      Handle<FixedArray> fixed_array_values =
+          Handle<FixedArray>::cast(copied_elements_values);
+      for (int i = 0; i < fixed_array_values->length(); i++) {
+        DCHECK(!fixed_array_values->get(i)->IsFixedArray());
+      }
+#endif
+    } else {
+      Handle<FixedArray> fixed_array_values =
+          Handle<FixedArray>::cast(constant_elements_values);
+      Handle<FixedArray> fixed_array_values_copy =
+          isolate->factory()->CopyFixedArray(fixed_array_values);
+      copied_elements_values = fixed_array_values_copy;
+      for (int i = 0; i < fixed_array_values->length(); i++) {
+        if (fixed_array_values->get(i)->IsFixedArray()) {
+          // The value contains the constant_properties of a
+          // simple object or array literal.
+          Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
+          Handle<Object> result;
+          ASSIGN_RETURN_ON_EXCEPTION(
+              isolate, result, CreateLiteralBoilerplate(isolate, literals, fa),
+              Object);
+          fixed_array_values_copy->set(i, *result);
+        }
+      }
+    }
+  }
+  object->set_elements(*copied_elements_values);
+  object->set_length(Smi::FromInt(copied_elements_values->length()));
+
+  JSObject::ValidateElements(object);
+  return object;
+}
+
+
+MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate(
+    Isolate* isolate, Handle<FixedArray> literals, Handle<FixedArray> array) {
+  Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
+  const bool kHasNoFunctionLiteral = false;
+  switch (CompileTimeValue::GetLiteralType(array)) {
+    case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
+      return CreateObjectLiteralBoilerplate(isolate, literals, elements, true,
+                                            kHasNoFunctionLiteral);
+    case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
+      return CreateObjectLiteralBoilerplate(isolate, literals, elements, false,
+                                            kHasNoFunctionLiteral);
+    case CompileTimeValue::ARRAY_LITERAL:
+      return Runtime::CreateArrayLiteralBoilerplate(isolate, literals,
+                                                    elements);
+    default:
+      UNREACHABLE();
+      return MaybeHandle<Object>();
+  }
+}
+
+
+RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
+  CONVERT_SMI_ARG_CHECKED(literals_index, 1);
+  CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
+  CONVERT_SMI_ARG_CHECKED(flags, 3);
+  bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
+  bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
+
+  RUNTIME_ASSERT(literals_index >= 0 && literals_index < literals->length());
+
+  // Check if boilerplate exists. If not, create it first.
+  Handle<Object> literal_site(literals->get(literals_index), isolate);
+  Handle<AllocationSite> site;
+  Handle<JSObject> boilerplate;
+  if (*literal_site == isolate->heap()->undefined_value()) {
+    Handle<Object> raw_boilerplate;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, raw_boilerplate,
+        CreateObjectLiteralBoilerplate(isolate, literals, constant_properties,
+                                       should_have_fast_elements,
+                                       has_function_literal));
+    boilerplate = Handle<JSObject>::cast(raw_boilerplate);
+
+    AllocationSiteCreationContext creation_context(isolate);
+    site = creation_context.EnterNewScope();
+    RETURN_FAILURE_ON_EXCEPTION(
+        isolate, JSObject::DeepWalk(boilerplate, &creation_context));
+    creation_context.ExitScope(site, boilerplate);
+
+    // Update the functions literal and return the boilerplate.
+    literals->set(literals_index, *site);
+  } else {
+    site = Handle<AllocationSite>::cast(literal_site);
+    boilerplate =
+        Handle<JSObject>(JSObject::cast(site->transition_info()), isolate);
+  }
+
+  AllocationSiteUsageContext usage_context(isolate, site, true);
+  usage_context.EnterNewScope();
+  MaybeHandle<Object> maybe_copy =
+      JSObject::DeepCopy(boilerplate, &usage_context);
+  usage_context.ExitScope(site, boilerplate);
+  Handle<Object> copy;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, copy, maybe_copy);
+  return *copy;
+}
+
+
+MUST_USE_RESULT static MaybeHandle<AllocationSite> GetLiteralAllocationSite(
+    Isolate* isolate, Handle<FixedArray> literals, int literals_index,
+    Handle<FixedArray> elements) {
+  // Check if boilerplate exists. If not, create it first.
+  Handle<Object> literal_site(literals->get(literals_index), isolate);
+  Handle<AllocationSite> site;
+  if (*literal_site == isolate->heap()->undefined_value()) {
+    DCHECK(*elements != isolate->heap()->empty_fixed_array());
+    Handle<Object> boilerplate;
+    ASSIGN_RETURN_ON_EXCEPTION(
+        isolate, boilerplate,
+        Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements),
+        AllocationSite);
+
+    AllocationSiteCreationContext creation_context(isolate);
+    site = creation_context.EnterNewScope();
+    if (JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate),
+                           &creation_context).is_null()) {
+      return Handle<AllocationSite>::null();
+    }
+    creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate));
+
+    literals->set(literals_index, *site);
+  } else {
+    site = Handle<AllocationSite>::cast(literal_site);
+  }
+
+  return site;
+}
+
+
+static MaybeHandle<JSObject> CreateArrayLiteralImpl(Isolate* isolate,
+                                                    Handle<FixedArray> literals,
+                                                    int literals_index,
+                                                    Handle<FixedArray> elements,
+                                                    int flags) {
+  RUNTIME_ASSERT_HANDLIFIED(
+      literals_index >= 0 && literals_index < literals->length(), JSObject);
+  Handle<AllocationSite> site;
+  ASSIGN_RETURN_ON_EXCEPTION(
+      isolate, site,
+      GetLiteralAllocationSite(isolate, literals, literals_index, elements),
+      JSObject);
+
+  bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0;
+  Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
+  AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
+  usage_context.EnterNewScope();
+  JSObject::DeepCopyHints hints = (flags & ArrayLiteral::kShallowElements) == 0
+                                      ? JSObject::kNoHints
+                                      : JSObject::kObjectIsShallow;
+  MaybeHandle<JSObject> copy =
+      JSObject::DeepCopy(boilerplate, &usage_context, hints);
+  usage_context.ExitScope(site, boilerplate);
+  return copy;
+}
+
+
+RUNTIME_FUNCTION(Runtime_CreateArrayLiteral) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
+  CONVERT_SMI_ARG_CHECKED(literals_index, 1);
+  CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
+  CONVERT_SMI_ARG_CHECKED(flags, 3);
+
+  Handle<JSObject> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, CreateArrayLiteralImpl(isolate, literals, literals_index,
+                                              elements, flags));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_CreateArrayLiteralStubBailout) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
+  CONVERT_SMI_ARG_CHECKED(literals_index, 1);
+  CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
+
+  Handle<JSObject> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
+                             ArrayLiteral::kShallowElements));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_StoreArrayLiteralElement) {
+  HandleScope scope(isolate);
+  RUNTIME_ASSERT(args.length() == 5);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_SMI_ARG_CHECKED(store_index, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
+  CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
+  CONVERT_SMI_ARG_CHECKED(literal_index, 4);
+
+  Object* raw_literal_cell = literals->get(literal_index);
+  JSArray* boilerplate = NULL;
+  if (raw_literal_cell->IsAllocationSite()) {
+    AllocationSite* site = AllocationSite::cast(raw_literal_cell);
+    boilerplate = JSArray::cast(site->transition_info());
+  } else {
+    boilerplate = JSArray::cast(raw_literal_cell);
+  }
+  Handle<JSArray> boilerplate_object(boilerplate);
+  ElementsKind elements_kind = object->GetElementsKind();
+  DCHECK(IsFastElementsKind(elements_kind));
+  // Smis should never trigger transitions.
+  DCHECK(!value->IsSmi());
+
+  if (value->IsNumber()) {
+    DCHECK(IsFastSmiElementsKind(elements_kind));
+    ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
+                                         ? FAST_HOLEY_DOUBLE_ELEMENTS
+                                         : FAST_DOUBLE_ELEMENTS;
+    if (IsMoreGeneralElementsKindTransition(
+            boilerplate_object->GetElementsKind(), transitioned_kind)) {
+      JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
+    }
+    JSObject::TransitionElementsKind(object, transitioned_kind);
+    DCHECK(IsFastDoubleElementsKind(object->GetElementsKind()));
+    FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
+    HeapNumber* number = HeapNumber::cast(*value);
+    double_array->set(store_index, number->Number());
+  } else {
+    if (!IsFastObjectElementsKind(elements_kind)) {
+      ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
+                                           ? FAST_HOLEY_ELEMENTS
+                                           : FAST_ELEMENTS;
+      JSObject::TransitionElementsKind(object, transitioned_kind);
+      ElementsKind boilerplate_elements_kind =
+          boilerplate_object->GetElementsKind();
+      if (IsMoreGeneralElementsKindTransition(boilerplate_elements_kind,
+                                              transitioned_kind)) {
+        JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
+      }
+    }
+    FixedArray* object_array = FixedArray::cast(object->elements());
+    object_array->set(store_index, *value);
+  }
+  return *object;
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-liveedit.cc b/src/runtime/runtime-liveedit.cc
new file mode 100644
index 0000000..b453d15
--- /dev/null
+++ b/src/runtime/runtime-liveedit.cc
@@ -0,0 +1,293 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/debug.h"
+#include "src/liveedit.h"
+#include "src/runtime/runtime.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+
+static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
+                                            Script* script,
+                                            FixedArray* buffer) {
+  DisallowHeapAllocation no_allocation;
+  int counter = 0;
+  int buffer_size = buffer->length();
+  for (HeapObject* obj = iterator->next(); obj != NULL;
+       obj = iterator->next()) {
+    DCHECK(obj != NULL);
+    if (!obj->IsSharedFunctionInfo()) {
+      continue;
+    }
+    SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
+    if (shared->script() != script) {
+      continue;
+    }
+    if (counter < buffer_size) {
+      buffer->set(counter, shared);
+    }
+    counter++;
+  }
+  return counter;
+}
+
+
+// For a script finds all SharedFunctionInfo's in the heap that points
+// to this script. Returns JSArray of SharedFunctionInfo wrapped
+// in OpaqueReferences.
+RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) {
+  HandleScope scope(isolate);
+  CHECK(isolate->debug()->live_edit_enabled());
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSValue, script_value, 0);
+
+  RUNTIME_ASSERT(script_value->value()->IsScript());
+  Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
+
+  const int kBufferSize = 32;
+
+  Handle<FixedArray> array;
+  array = isolate->factory()->NewFixedArray(kBufferSize);
+  int number;
+  Heap* heap = isolate->heap();
+  {
+    HeapIterator heap_iterator(heap);
+    Script* scr = *script;
+    FixedArray* arr = *array;
+    number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
+  }
+  if (number > kBufferSize) {
+    array = isolate->factory()->NewFixedArray(number);
+    HeapIterator heap_iterator(heap);
+    Script* scr = *script;
+    FixedArray* arr = *array;
+    FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
+  }
+
+  Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
+  result->set_length(Smi::FromInt(number));
+
+  LiveEdit::WrapSharedFunctionInfos(result);
+
+  return *result;
+}
+
+
+// For a script calculates compilation information about all its functions.
+// The script source is explicitly specified by the second argument.
+// The source of the actual script is not used, however it is important that
+// all generated code keeps references to this particular instance of script.
+// Returns a JSArray of compilation infos. The array is ordered so that
+// each function with all its descendant is always stored in a continues range
+// with the function itself going first. The root function is a script function.
+RUNTIME_FUNCTION(Runtime_LiveEditGatherCompileInfo) {
+  HandleScope scope(isolate);
+  CHECK(isolate->debug()->live_edit_enabled());
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_CHECKED(JSValue, script, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
+
+  RUNTIME_ASSERT(script->value()->IsScript());
+  Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
+
+  Handle<JSArray> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, LiveEdit::GatherCompileInfo(script_handle, source));
+  return *result;
+}
+
+
+// Changes the source of the script to a new_source.
+// If old_script_name is provided (i.e. is a String), also creates a copy of
+// the script with its original source and sends notification to debugger.
+RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) {
+  HandleScope scope(isolate);
+  CHECK(isolate->debug()->live_edit_enabled());
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, old_script_name, 2);
+
+  RUNTIME_ASSERT(original_script_value->value()->IsScript());
+  Handle<Script> original_script(Script::cast(original_script_value->value()));
+
+  Handle<Object> old_script = LiveEdit::ChangeScriptSource(
+      original_script, new_source, old_script_name);
+
+  if (old_script->IsScript()) {
+    Handle<Script> script_handle = Handle<Script>::cast(old_script);
+    return *Script::GetWrapper(script_handle);
+  } else {
+    return isolate->heap()->null_value();
+  }
+}
+
+
+RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) {
+  HandleScope scope(isolate);
+  CHECK(isolate->debug()->live_edit_enabled());
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
+  RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info));
+
+  LiveEdit::FunctionSourceUpdated(shared_info);
+  return isolate->heap()->undefined_value();
+}
+
+
+// Replaces code of SharedFunctionInfo with a new one.
+RUNTIME_FUNCTION(Runtime_LiveEditReplaceFunctionCode) {
+  HandleScope scope(isolate);
+  CHECK(isolate->debug()->live_edit_enabled());
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
+  RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info));
+
+  LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
+  return isolate->heap()->undefined_value();
+}
+
+
+// Connects SharedFunctionInfo to another script.
+RUNTIME_FUNCTION(Runtime_LiveEditFunctionSetScript) {
+  HandleScope scope(isolate);
+  CHECK(isolate->debug()->live_edit_enabled());
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, script_object, 1);
+
+  if (function_object->IsJSValue()) {
+    Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
+    if (script_object->IsJSValue()) {
+      RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
+      Script* script = Script::cast(JSValue::cast(*script_object)->value());
+      script_object = Handle<Object>(script, isolate);
+    }
+    RUNTIME_ASSERT(function_wrapper->value()->IsSharedFunctionInfo());
+    LiveEdit::SetFunctionScript(function_wrapper, script_object);
+  } else {
+    // Just ignore this. We may not have a SharedFunctionInfo for some functions
+    // and we check it in this function.
+  }
+
+  return isolate->heap()->undefined_value();
+}
+
+
+// In a code of a parent function replaces original function as embedded object
+// with a substitution one.
+RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) {
+  HandleScope scope(isolate);
+  CHECK(isolate->debug()->live_edit_enabled());
+  DCHECK(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
+  RUNTIME_ASSERT(parent_wrapper->value()->IsSharedFunctionInfo());
+  RUNTIME_ASSERT(orig_wrapper->value()->IsSharedFunctionInfo());
+  RUNTIME_ASSERT(subst_wrapper->value()->IsSharedFunctionInfo());
+
+  LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
+                                       subst_wrapper);
+  return isolate->heap()->undefined_value();
+}
+
+
+// Updates positions of a shared function info (first parameter) according
+// to script source change. Text change is described in second parameter as
+// array of groups of 3 numbers:
+// (change_begin, change_end, change_end_new_position).
+// Each group describes a change in text; groups are sorted by change_begin.
+RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) {
+  HandleScope scope(isolate);
+  CHECK(isolate->debug()->live_edit_enabled());
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
+  RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_array))
+
+  LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
+  return isolate->heap()->undefined_value();
+}
+
+
+// For array of SharedFunctionInfo's (each wrapped in JSValue)
+// checks that none of them have activations on stacks (of any thread).
+// Returns array of the same length with corresponding results of
+// LiveEdit::FunctionPatchabilityStatus type.
+RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) {
+  HandleScope scope(isolate);
+  CHECK(isolate->debug()->live_edit_enabled());
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
+  CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
+  RUNTIME_ASSERT(shared_array->length()->IsSmi());
+  RUNTIME_ASSERT(shared_array->HasFastElements())
+  int array_length = Smi::cast(shared_array->length())->value();
+  for (int i = 0; i < array_length; i++) {
+    Handle<Object> element =
+        Object::GetElement(isolate, shared_array, i).ToHandleChecked();
+    RUNTIME_ASSERT(
+        element->IsJSValue() &&
+        Handle<JSValue>::cast(element)->value()->IsSharedFunctionInfo());
+  }
+
+  return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
+}
+
+
+// Compares 2 strings line-by-line, then token-wise and returns diff in form
+// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
+// of diff chunks.
+RUNTIME_FUNCTION(Runtime_LiveEditCompareStrings) {
+  HandleScope scope(isolate);
+  CHECK(isolate->debug()->live_edit_enabled());
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
+
+  return *LiveEdit::CompareStrings(s1, s2);
+}
+
+
+// Restarts a call frame and completely drops all frames above.
+// Returns true if successful. Otherwise returns undefined or an error message.
+RUNTIME_FUNCTION(Runtime_LiveEditRestartFrame) {
+  HandleScope scope(isolate);
+  CHECK(isolate->debug()->live_edit_enabled());
+  DCHECK(args.length() == 2);
+  CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+  RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+  CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
+  Heap* heap = isolate->heap();
+
+  // Find the relevant frame with the requested index.
+  StackFrame::Id id = isolate->debug()->break_frame_id();
+  if (id == StackFrame::NO_ID) {
+    // If there are no JavaScript stack frames return undefined.
+    return heap->undefined_value();
+  }
+
+  JavaScriptFrameIterator it(isolate, id);
+  int inlined_jsframe_index = Runtime::FindIndexedNonNativeFrame(&it, index);
+  if (inlined_jsframe_index == -1) return heap->undefined_value();
+  // We don't really care what the inlined frame index is, since we are
+  // throwing away the entire frame anyways.
+  const char* error_message = LiveEdit::RestartFrame(it.frame());
+  if (error_message) {
+    return *(isolate->factory()->InternalizeUtf8String(error_message));
+  }
+  return heap->true_value();
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-maths.cc b/src/runtime/runtime-maths.cc
new file mode 100644
index 0000000..6397ad1
--- /dev/null
+++ b/src/runtime/runtime-maths.cc
@@ -0,0 +1,246 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/assembler.h"
+#include "src/codegen.h"
+#include "src/runtime/runtime-utils.h"
+#include "src/third_party/fdlibm/fdlibm.h"
+
+
+namespace v8 {
+namespace internal {
+
+#define RUNTIME_UNARY_MATH(Name, name)                       \
+  RUNTIME_FUNCTION(Runtime_Math##Name) {                     \
+    HandleScope scope(isolate);                              \
+    DCHECK(args.length() == 1);                              \
+    isolate->counters()->math_##name()->Increment();         \
+    CONVERT_DOUBLE_ARG_CHECKED(x, 0);                        \
+    return *isolate->factory()->NewHeapNumber(std::name(x)); \
+  }
+
+RUNTIME_UNARY_MATH(Acos, acos)
+RUNTIME_UNARY_MATH(Asin, asin)
+RUNTIME_UNARY_MATH(Atan, atan)
+RUNTIME_UNARY_MATH(LogRT, log)
+#undef RUNTIME_UNARY_MATH
+
+
+RUNTIME_FUNCTION(Runtime_DoubleHi) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  uint64_t integer = double_to_uint64(x);
+  integer = (integer >> 32) & 0xFFFFFFFFu;
+  return *isolate->factory()->NewNumber(static_cast<int32_t>(integer));
+}
+
+
+RUNTIME_FUNCTION(Runtime_DoubleLo) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  return *isolate->factory()->NewNumber(
+      static_cast<int32_t>(double_to_uint64(x) & 0xFFFFFFFFu));
+}
+
+
+RUNTIME_FUNCTION(Runtime_ConstructDouble) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]);
+  CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]);
+  uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo;
+  return *isolate->factory()->NewNumber(uint64_to_double(result));
+}
+
+
+RUNTIME_FUNCTION(Runtime_RemPiO2) {
+  HandleScope handle_scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  Factory* factory = isolate->factory();
+  double y[2] = {0.0, 0.0};
+  int n = fdlibm::rempio2(x, y);
+  Handle<FixedArray> array = factory->NewFixedArray(3);
+  Handle<HeapNumber> y0 = factory->NewHeapNumber(y[0]);
+  Handle<HeapNumber> y1 = factory->NewHeapNumber(y[1]);
+  array->set(0, Smi::FromInt(n));
+  array->set(1, *y0);
+  array->set(2, *y1);
+  return *factory->NewJSArrayWithElements(array);
+}
+
+
+static const double kPiDividedBy4 = 0.78539816339744830962;
+
+
+RUNTIME_FUNCTION(Runtime_MathAtan2) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  isolate->counters()->math_atan2()->Increment();
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
+  double result;
+  if (std::isinf(x) && std::isinf(y)) {
+    // Make sure that the result in case of two infinite arguments
+    // is a multiple of Pi / 4. The sign of the result is determined
+    // by the first argument (x) and the sign of the second argument
+    // determines the multiplier: one or three.
+    int multiplier = (x < 0) ? -1 : 1;
+    if (y < 0) multiplier *= 3;
+    result = multiplier * kPiDividedBy4;
+  } else {
+    result = std::atan2(x, y);
+  }
+  return *isolate->factory()->NewNumber(result);
+}
+
+
+RUNTIME_FUNCTION(Runtime_MathExpRT) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  isolate->counters()->math_exp()->Increment();
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  lazily_initialize_fast_exp();
+  return *isolate->factory()->NewNumber(fast_exp(x));
+}
+
+
+RUNTIME_FUNCTION(Runtime_MathFloorRT) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  isolate->counters()->math_floor()->Increment();
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  return *isolate->factory()->NewNumber(Floor(x));
+}
+
+
+// Slow version of Math.pow.  We check for fast paths for special cases.
+// Used if VFP3 is not available.
+RUNTIME_FUNCTION(Runtime_MathPowSlow) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  isolate->counters()->math_pow()->Increment();
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+
+  // If the second argument is a smi, it is much faster to call the
+  // custom powi() function than the generic pow().
+  if (args[1]->IsSmi()) {
+    int y = args.smi_at(1);
+    return *isolate->factory()->NewNumber(power_double_int(x, y));
+  }
+
+  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
+  double result = power_helper(x, y);
+  if (std::isnan(result)) return isolate->heap()->nan_value();
+  return *isolate->factory()->NewNumber(result);
+}
+
+
+// Fast version of Math.pow if we know that y is not an integer and y is not
+// -0.5 or 0.5.  Used as slow case from full codegen.
+RUNTIME_FUNCTION(Runtime_MathPowRT) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  isolate->counters()->math_pow()->Increment();
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
+  if (y == 0) {
+    return Smi::FromInt(1);
+  } else {
+    double result = power_double_double(x, y);
+    if (std::isnan(result)) return isolate->heap()->nan_value();
+    return *isolate->factory()->NewNumber(result);
+  }
+}
+
+
+RUNTIME_FUNCTION(Runtime_RoundNumber) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_NUMBER_ARG_HANDLE_CHECKED(input, 0);
+  isolate->counters()->math_round()->Increment();
+
+  if (!input->IsHeapNumber()) {
+    DCHECK(input->IsSmi());
+    return *input;
+  }
+
+  Handle<HeapNumber> number = Handle<HeapNumber>::cast(input);
+
+  double value = number->value();
+  int exponent = number->get_exponent();
+  int sign = number->get_sign();
+
+  if (exponent < -1) {
+    // Number in range ]-0.5..0.5[. These always round to +/-zero.
+    if (sign) return isolate->heap()->minus_zero_value();
+    return Smi::FromInt(0);
+  }
+
+  // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
+  // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
+  // argument holds for 32-bit smis).
+  if (!sign && exponent < kSmiValueSize - 2) {
+    return Smi::FromInt(static_cast<int>(value + 0.5));
+  }
+
+  // If the magnitude is big enough, there's no place for fraction part. If we
+  // try to add 0.5 to this number, 1.0 will be added instead.
+  if (exponent >= 52) {
+    return *number;
+  }
+
+  if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
+
+  // Do not call NumberFromDouble() to avoid extra checks.
+  return *isolate->factory()->NewNumber(Floor(value + 0.5));
+}
+
+
+RUNTIME_FUNCTION(Runtime_MathSqrtRT) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  isolate->counters()->math_sqrt()->Increment();
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  return *isolate->factory()->NewNumber(fast_sqrt(x));
+}
+
+
+RUNTIME_FUNCTION(Runtime_MathFround) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  float xf = DoubleToFloat32(x);
+  return *isolate->factory()->NewNumber(xf);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_MathPow) {
+  SealHandleScope shs(isolate);
+  return __RT_impl_Runtime_MathPowSlow(args, isolate);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_IsMinusZero) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  if (!obj->IsHeapNumber()) return isolate->heap()->false_value();
+  HeapNumber* number = HeapNumber::cast(obj);
+  return isolate->heap()->ToBoolean(IsMinusZero(number->value()));
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-numbers.cc b/src/runtime/runtime-numbers.cc
new file mode 100644
index 0000000..bc0bb36
--- /dev/null
+++ b/src/runtime/runtime-numbers.cc
@@ -0,0 +1,596 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/base/bits.h"
+#include "src/bootstrapper.h"
+#include "src/codegen.h"
+#include "src/runtime/runtime-utils.h"
+
+
+#ifndef _STLP_VENDOR_CSTD
+// STLPort doesn't import fpclassify and isless into the std namespace.
+using std::fpclassify;
+using std::isless;
+#endif
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_NumberToRadixString) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_SMI_ARG_CHECKED(radix, 1);
+  RUNTIME_ASSERT(2 <= radix && radix <= 36);
+
+  // Fast case where the result is a one character string.
+  if (args[0]->IsSmi()) {
+    int value = args.smi_at(0);
+    if (value >= 0 && value < radix) {
+      // Character array used for conversion.
+      static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+      return *isolate->factory()->LookupSingleCharacterStringFromCode(
+          kCharTable[value]);
+    }
+  }
+
+  // Slow case.
+  CONVERT_DOUBLE_ARG_CHECKED(value, 0);
+  if (std::isnan(value)) {
+    return isolate->heap()->nan_string();
+  }
+  if (std::isinf(value)) {
+    if (value < 0) {
+      return isolate->heap()->minus_infinity_string();
+    }
+    return isolate->heap()->infinity_string();
+  }
+  char* str = DoubleToRadixCString(value, radix);
+  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
+  DeleteArray(str);
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberToFixed) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_DOUBLE_ARG_CHECKED(value, 0);
+  CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
+  int f = FastD2IChecked(f_number);
+  // See DoubleToFixedCString for these constants:
+  RUNTIME_ASSERT(f >= 0 && f <= 20);
+  RUNTIME_ASSERT(!Double(value).IsSpecial());
+  char* str = DoubleToFixedCString(value, f);
+  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
+  DeleteArray(str);
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberToExponential) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_DOUBLE_ARG_CHECKED(value, 0);
+  CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
+  int f = FastD2IChecked(f_number);
+  RUNTIME_ASSERT(f >= -1 && f <= 20);
+  RUNTIME_ASSERT(!Double(value).IsSpecial());
+  char* str = DoubleToExponentialCString(value, f);
+  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
+  DeleteArray(str);
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberToPrecision) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_DOUBLE_ARG_CHECKED(value, 0);
+  CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
+  int f = FastD2IChecked(f_number);
+  RUNTIME_ASSERT(f >= 1 && f <= 21);
+  RUNTIME_ASSERT(!Double(value).IsSpecial());
+  char* str = DoubleToPrecisionCString(value, f);
+  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
+  DeleteArray(str);
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_IsValidSmi) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]);
+  return isolate->heap()->ToBoolean(Smi::IsValid(number));
+}
+
+
+static bool AreDigits(const uint8_t* s, int from, int to) {
+  for (int i = from; i < to; i++) {
+    if (s[i] < '0' || s[i] > '9') return false;
+  }
+
+  return true;
+}
+
+
+static int ParseDecimalInteger(const uint8_t* s, int from, int to) {
+  DCHECK(to - from < 10);  // Overflow is not possible.
+  DCHECK(from < to);
+  int d = s[from] - '0';
+
+  for (int i = from + 1; i < to; i++) {
+    d = 10 * d + (s[i] - '0');
+  }
+
+  return d;
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringToNumber) {
+  HandleScope handle_scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
+  subject = String::Flatten(subject);
+
+  // Fast case: short integer or some sorts of junk values.
+  if (subject->IsSeqOneByteString()) {
+    int len = subject->length();
+    if (len == 0) return Smi::FromInt(0);
+
+    DisallowHeapAllocation no_gc;
+    uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
+    bool minus = (data[0] == '-');
+    int start_pos = (minus ? 1 : 0);
+
+    if (start_pos == len) {
+      return isolate->heap()->nan_value();
+    } else if (data[start_pos] > '9') {
+      // Fast check for a junk value. A valid string may start from a
+      // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
+      // or the 'I' character ('Infinity'). All of that have codes not greater
+      // than '9' except 'I' and &nbsp;.
+      if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
+        return isolate->heap()->nan_value();
+      }
+    } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
+      // The maximal/minimal smi has 10 digits. If the string has less digits
+      // we know it will fit into the smi-data type.
+      int d = ParseDecimalInteger(data, start_pos, len);
+      if (minus) {
+        if (d == 0) return isolate->heap()->minus_zero_value();
+        d = -d;
+      } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
+                 (len == 1 || data[0] != '0')) {
+        // String hash is not calculated yet but all the data are present.
+        // Update the hash field to speed up sequential convertions.
+        uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
+#ifdef DEBUG
+        subject->Hash();  // Force hash calculation.
+        DCHECK_EQ(static_cast<int>(subject->hash_field()),
+                  static_cast<int>(hash));
+#endif
+        subject->set_hash_field(hash);
+      }
+      return Smi::FromInt(d);
+    }
+  }
+
+  // Slower case.
+  int flags = ALLOW_HEX;
+  if (FLAG_harmony_numeric_literals) {
+    // The current spec draft has not updated "ToNumber Applied to the String
+    // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584
+    flags |= ALLOW_OCTAL | ALLOW_BINARY;
+  }
+
+  return *isolate->factory()->NewNumber(
+      StringToDouble(isolate->unicode_cache(), subject, flags));
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringParseInt) {
+  HandleScope handle_scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
+  CONVERT_NUMBER_CHECKED(int, radix, Int32, args[1]);
+  RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
+
+  subject = String::Flatten(subject);
+  double value;
+
+  {
+    DisallowHeapAllocation no_gc;
+    String::FlatContent flat = subject->GetFlatContent();
+
+    // ECMA-262 section 15.1.2.3, empty string is NaN
+    if (flat.IsOneByte()) {
+      value =
+          StringToInt(isolate->unicode_cache(), flat.ToOneByteVector(), radix);
+    } else {
+      value = StringToInt(isolate->unicode_cache(), flat.ToUC16Vector(), radix);
+    }
+  }
+
+  return *isolate->factory()->NewNumber(value);
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringParseFloat) {
+  HandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
+
+  double value = StringToDouble(isolate->unicode_cache(), subject,
+                                ALLOW_TRAILING_JUNK, base::OS::nan_value());
+
+  return *isolate->factory()->NewNumber(value);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberToStringRT) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
+
+  return *isolate->factory()->NumberToString(number);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
+
+  return *isolate->factory()->NumberToString(number, false);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberToInteger) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_DOUBLE_ARG_CHECKED(number, 0);
+  return *isolate->factory()->NewNumber(DoubleToInteger(number));
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberToIntegerMapMinusZero) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_DOUBLE_ARG_CHECKED(number, 0);
+  double double_value = DoubleToInteger(number);
+  // Map both -0 and +0 to +0.
+  if (double_value == 0) double_value = 0;
+
+  return *isolate->factory()->NewNumber(double_value);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberToJSUint32) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
+  return *isolate->factory()->NewNumberFromUint(number);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberToJSInt32) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_DOUBLE_ARG_CHECKED(number, 0);
+  return *isolate->factory()->NewNumberFromInt(DoubleToInt32(number));
+}
+
+
+// Converts a Number to a Smi, if possible. Returns NaN if the number is not
+// a small integer.
+RUNTIME_FUNCTION(Runtime_NumberToSmi) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  if (obj->IsSmi()) {
+    return obj;
+  }
+  if (obj->IsHeapNumber()) {
+    double value = HeapNumber::cast(obj)->value();
+    int int_value = FastD2I(value);
+    if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
+      return Smi::FromInt(int_value);
+    }
+  }
+  return isolate->heap()->nan_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberAdd) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
+  return *isolate->factory()->NewNumber(x + y);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberSub) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
+  return *isolate->factory()->NewNumber(x - y);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberMul) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
+  return *isolate->factory()->NewNumber(x * y);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberUnaryMinus) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  return *isolate->factory()->NewNumber(-x);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberDiv) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
+  return *isolate->factory()->NewNumber(x / y);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberMod) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
+  return *isolate->factory()->NewNumber(modulo(x, y));
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberImul) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  // We rely on implementation-defined behavior below, but at least not on
+  // undefined behavior.
+  CONVERT_NUMBER_CHECKED(uint32_t, x, Int32, args[0]);
+  CONVERT_NUMBER_CHECKED(uint32_t, y, Int32, args[1]);
+  int32_t product = static_cast<int32_t>(x * y);
+  return *isolate->factory()->NewNumberFromInt(product);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberOr) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
+  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
+  return *isolate->factory()->NewNumberFromInt(x | y);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberAnd) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
+  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
+  return *isolate->factory()->NewNumberFromInt(x & y);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberXor) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
+  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
+  return *isolate->factory()->NewNumberFromInt(x ^ y);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberShl) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
+  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
+  return *isolate->factory()->NewNumberFromInt(x << (y & 0x1f));
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberShr) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
+  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
+  return *isolate->factory()->NewNumberFromUint(x >> (y & 0x1f));
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberSar) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
+  CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
+  return *isolate->factory()->NewNumberFromInt(
+      ArithmeticShiftRight(x, y & 0x1f));
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberEquals) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
+  if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL);
+  if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL);
+  if (x == y) return Smi::FromInt(EQUAL);
+  Object* result;
+  if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
+    result = Smi::FromInt(EQUAL);
+  } else {
+    result = Smi::FromInt(NOT_EQUAL);
+  }
+  return result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_NumberCompare) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 3);
+
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  CONVERT_DOUBLE_ARG_CHECKED(y, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, uncomparable_result, 2)
+  if (std::isnan(x) || std::isnan(y)) return *uncomparable_result;
+  if (x == y) return Smi::FromInt(EQUAL);
+  if (isless(x, y)) return Smi::FromInt(LESS);
+  return Smi::FromInt(GREATER);
+}
+
+
+// Compare two Smis as if they were converted to strings and then
+// compared lexicographically.
+RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_SMI_ARG_CHECKED(x_value, 0);
+  CONVERT_SMI_ARG_CHECKED(y_value, 1);
+
+  // If the integers are equal so are the string representations.
+  if (x_value == y_value) return Smi::FromInt(EQUAL);
+
+  // If one of the integers is zero the normal integer order is the
+  // same as the lexicographic order of the string representations.
+  if (x_value == 0 || y_value == 0)
+    return Smi::FromInt(x_value < y_value ? LESS : GREATER);
+
+  // If only one of the integers is negative the negative number is
+  // smallest because the char code of '-' is less than the char code
+  // of any digit.  Otherwise, we make both values positive.
+
+  // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
+  // architectures using 32-bit Smis.
+  uint32_t x_scaled = x_value;
+  uint32_t y_scaled = y_value;
+  if (x_value < 0 || y_value < 0) {
+    if (y_value >= 0) return Smi::FromInt(LESS);
+    if (x_value >= 0) return Smi::FromInt(GREATER);
+    x_scaled = -x_value;
+    y_scaled = -y_value;
+  }
+
+  static const uint32_t kPowersOf10[] = {
+      1,                 10,                100,         1000,
+      10 * 1000,         100 * 1000,        1000 * 1000, 10 * 1000 * 1000,
+      100 * 1000 * 1000, 1000 * 1000 * 1000};
+
+  // If the integers have the same number of decimal digits they can be
+  // compared directly as the numeric order is the same as the
+  // lexicographic order.  If one integer has fewer digits, it is scaled
+  // by some power of 10 to have the same number of digits as the longer
+  // integer.  If the scaled integers are equal it means the shorter
+  // integer comes first in the lexicographic order.
+
+  // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
+  int x_log2 = 31 - base::bits::CountLeadingZeros32(x_scaled);
+  int x_log10 = ((x_log2 + 1) * 1233) >> 12;
+  x_log10 -= x_scaled < kPowersOf10[x_log10];
+
+  int y_log2 = 31 - base::bits::CountLeadingZeros32(y_scaled);
+  int y_log10 = ((y_log2 + 1) * 1233) >> 12;
+  y_log10 -= y_scaled < kPowersOf10[y_log10];
+
+  int tie = EQUAL;
+
+  if (x_log10 < y_log10) {
+    // X has fewer digits.  We would like to simply scale up X but that
+    // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
+    // be scaled up to 9_000_000_000. So we scale up by the next
+    // smallest power and scale down Y to drop one digit. It is OK to
+    // drop one digit from the longer integer since the final digit is
+    // past the length of the shorter integer.
+    x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
+    y_scaled /= 10;
+    tie = LESS;
+  } else if (y_log10 < x_log10) {
+    y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
+    x_scaled /= 10;
+    tie = GREATER;
+  }
+
+  if (x_scaled < y_scaled) return Smi::FromInt(LESS);
+  if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
+  return Smi::FromInt(tie);
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetRootNaN) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
+  return isolate->heap()->nan_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_MaxSmi) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  return Smi::FromInt(Smi::kMaxValue);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_NumberToString) {
+  SealHandleScope shs(isolate);
+  return __RT_impl_Runtime_NumberToStringRT(args, isolate);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_IsSmi) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  return isolate->heap()->ToBoolean(obj->IsSmi());
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_IsNonNegativeSmi) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  return isolate->heap()->ToBoolean(obj->IsSmi() &&
+                                    Smi::cast(obj)->value() >= 0);
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc
new file mode 100644
index 0000000..407f237
--- /dev/null
+++ b/src/runtime/runtime-object.cc
@@ -0,0 +1,1610 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/bootstrapper.h"
+#include "src/debug.h"
+#include "src/runtime/runtime.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+// Returns a single character string where first character equals
+// string->Get(index).
+static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
+  if (index < static_cast<uint32_t>(string->length())) {
+    Factory* factory = string->GetIsolate()->factory();
+    return factory->LookupSingleCharacterStringFromCode(
+        String::Flatten(string)->Get(index));
+  }
+  return Execution::CharAt(string, index);
+}
+
+
+MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate,
+                                                Handle<Object> object,
+                                                uint32_t index) {
+  // Handle [] indexing on Strings
+  if (object->IsString()) {
+    Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
+    if (!result->IsUndefined()) return result;
+  }
+
+  // Handle [] indexing on String objects
+  if (object->IsStringObjectWithCharacterAt(index)) {
+    Handle<JSValue> js_value = Handle<JSValue>::cast(object);
+    Handle<Object> result =
+        GetCharAt(Handle<String>(String::cast(js_value->value())), index);
+    if (!result->IsUndefined()) return result;
+  }
+
+  Handle<Object> result;
+  if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
+    PrototypeIterator iter(isolate, object);
+    return Object::GetElement(isolate, PrototypeIterator::GetCurrent(iter),
+                              index);
+  } else {
+    return Object::GetElement(isolate, object, index);
+  }
+}
+
+
+MaybeHandle<Name> Runtime::ToName(Isolate* isolate, Handle<Object> key) {
+  if (key->IsName()) {
+    return Handle<Name>::cast(key);
+  } else {
+    Handle<Object> converted;
+    ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
+                               Execution::ToString(isolate, key), Name);
+    return Handle<Name>::cast(converted);
+  }
+}
+
+
+MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
+                                               Handle<Object> object,
+                                               Handle<Object> key) {
+  if (object->IsUndefined() || object->IsNull()) {
+    Handle<Object> args[2] = {key, object};
+    THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_load",
+                                          HandleVector(args, 2)),
+                    Object);
+  }
+
+  // Check if the given key is an array index.
+  uint32_t index;
+  if (key->ToArrayIndex(&index)) {
+    return GetElementOrCharAt(isolate, object, index);
+  }
+
+  // Convert the key to a name - possibly by calling back into JavaScript.
+  Handle<Name> name;
+  ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
+
+  // Check if the name is trivially convertible to an index and get
+  // the element if so.
+  if (name->AsArrayIndex(&index)) {
+    return GetElementOrCharAt(isolate, object, index);
+  } else {
+    return Object::GetProperty(object, name);
+  }
+}
+
+
+MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
+                                               Handle<Object> object,
+                                               Handle<Object> key,
+                                               Handle<Object> value,
+                                               StrictMode strict_mode) {
+  if (object->IsUndefined() || object->IsNull()) {
+    Handle<Object> args[2] = {key, object};
+    THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_store",
+                                          HandleVector(args, 2)),
+                    Object);
+  }
+
+  if (object->IsJSProxy()) {
+    Handle<Object> name_object;
+    if (key->IsSymbol()) {
+      name_object = key;
+    } else {
+      ASSIGN_RETURN_ON_EXCEPTION(isolate, name_object,
+                                 Execution::ToString(isolate, key), Object);
+    }
+    Handle<Name> name = Handle<Name>::cast(name_object);
+    return Object::SetProperty(Handle<JSProxy>::cast(object), name, value,
+                               strict_mode);
+  }
+
+  // Check if the given key is an array index.
+  uint32_t index;
+  if (key->ToArrayIndex(&index)) {
+    // TODO(verwaest): Support non-JSObject receivers.
+    if (!object->IsJSObject()) return value;
+    Handle<JSObject> js_object = Handle<JSObject>::cast(object);
+
+    // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
+    // of a string using [] notation.  We need to support this too in
+    // JavaScript.
+    // In the case of a String object we just need to redirect the assignment to
+    // the underlying string if the index is in range.  Since the underlying
+    // string does nothing with the assignment then we can ignore such
+    // assignments.
+    if (js_object->IsStringObjectWithCharacterAt(index)) {
+      return value;
+    }
+
+    JSObject::ValidateElements(js_object);
+    if (js_object->HasExternalArrayElements() ||
+        js_object->HasFixedTypedArrayElements()) {
+      if (!value->IsNumber() && !value->IsUndefined()) {
+        ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
+                                   Execution::ToNumber(isolate, value), Object);
+      }
+    }
+
+    MaybeHandle<Object> result = JSObject::SetElement(
+        js_object, index, value, NONE, strict_mode, true, SET_PROPERTY);
+    JSObject::ValidateElements(js_object);
+
+    return result.is_null() ? result : value;
+  }
+
+  if (key->IsName()) {
+    Handle<Name> name = Handle<Name>::cast(key);
+    if (name->AsArrayIndex(&index)) {
+      // TODO(verwaest): Support non-JSObject receivers.
+      if (!object->IsJSObject()) return value;
+      Handle<JSObject> js_object = Handle<JSObject>::cast(object);
+      if (js_object->HasExternalArrayElements()) {
+        if (!value->IsNumber() && !value->IsUndefined()) {
+          ASSIGN_RETURN_ON_EXCEPTION(
+              isolate, value, Execution::ToNumber(isolate, value), Object);
+        }
+      }
+      return JSObject::SetElement(js_object, index, value, NONE, strict_mode,
+                                  true, SET_PROPERTY);
+    } else {
+      if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
+      return Object::SetProperty(object, name, value, strict_mode);
+    }
+  }
+
+  // Call-back into JavaScript to convert the key to a string.
+  Handle<Object> converted;
+  ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
+                             Execution::ToString(isolate, key), Object);
+  Handle<String> name = Handle<String>::cast(converted);
+
+  if (name->AsArrayIndex(&index)) {
+    // TODO(verwaest): Support non-JSObject receivers.
+    if (!object->IsJSObject()) return value;
+    Handle<JSObject> js_object = Handle<JSObject>::cast(object);
+    return JSObject::SetElement(js_object, index, value, NONE, strict_mode,
+                                true, SET_PROPERTY);
+  }
+  return Object::SetProperty(object, name, value, strict_mode);
+}
+
+
+MaybeHandle<Object> Runtime::DefineObjectProperty(Handle<JSObject> js_object,
+                                                  Handle<Object> key,
+                                                  Handle<Object> value,
+                                                  PropertyAttributes attr) {
+  Isolate* isolate = js_object->GetIsolate();
+  // Check if the given key is an array index.
+  uint32_t index;
+  if (key->ToArrayIndex(&index)) {
+    // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
+    // of a string using [] notation.  We need to support this too in
+    // JavaScript.
+    // In the case of a String object we just need to redirect the assignment to
+    // the underlying string if the index is in range.  Since the underlying
+    // string does nothing with the assignment then we can ignore such
+    // assignments.
+    if (js_object->IsStringObjectWithCharacterAt(index)) {
+      return value;
+    }
+
+    return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
+                                DEFINE_PROPERTY);
+  }
+
+  if (key->IsName()) {
+    Handle<Name> name = Handle<Name>::cast(key);
+    if (name->AsArrayIndex(&index)) {
+      return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
+                                  DEFINE_PROPERTY);
+    } else {
+      if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
+      return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value,
+                                                      attr);
+    }
+  }
+
+  // Call-back into JavaScript to convert the key to a string.
+  Handle<Object> converted;
+  ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
+                             Execution::ToString(isolate, key), Object);
+  Handle<String> name = Handle<String>::cast(converted);
+
+  if (name->AsArrayIndex(&index)) {
+    return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
+                                DEFINE_PROPERTY);
+  } else {
+    return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value,
+                                                    attr);
+  }
+}
+
+
+MaybeHandle<Object> Runtime::GetPrototype(Isolate* isolate,
+                                          Handle<Object> obj) {
+  // We don't expect access checks to be needed on JSProxy objects.
+  DCHECK(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
+  PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
+  do {
+    if (PrototypeIterator::GetCurrent(iter)->IsAccessCheckNeeded() &&
+        !isolate->MayNamedAccess(
+            Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
+            isolate->factory()->proto_string(), v8::ACCESS_GET)) {
+      isolate->ReportFailedAccessCheck(
+          Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
+          v8::ACCESS_GET);
+      RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
+      return isolate->factory()->undefined_value();
+    }
+    iter.AdvanceIgnoringProxies();
+    if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
+      return PrototypeIterator::GetCurrent(iter);
+    }
+  } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN));
+  return PrototypeIterator::GetCurrent(iter);
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetPrototype) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     Runtime::GetPrototype(isolate, obj));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_InternalSetPrototype) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
+  DCHECK(!obj->IsAccessCheckNeeded());
+  DCHECK(!obj->map()->is_observed());
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, JSObject::SetPrototype(obj, prototype, false));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_SetPrototype) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
+  if (obj->IsAccessCheckNeeded() &&
+      !isolate->MayNamedAccess(obj, isolate->factory()->proto_string(),
+                               v8::ACCESS_SET)) {
+    isolate->ReportFailedAccessCheck(obj, v8::ACCESS_SET);
+    RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
+    return isolate->heap()->undefined_value();
+  }
+  if (obj->map()->is_observed()) {
+    Handle<Object> old_value =
+        Object::GetPrototypeSkipHiddenPrototypes(isolate, obj);
+    Handle<Object> result;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, result, JSObject::SetPrototype(obj, prototype, true));
+
+    Handle<Object> new_value =
+        Object::GetPrototypeSkipHiddenPrototypes(isolate, obj);
+    if (!new_value->SameValue(*old_value)) {
+      RETURN_FAILURE_ON_EXCEPTION(
+          isolate, JSObject::EnqueueChangeRecord(
+                       obj, "setPrototype", isolate->factory()->proto_string(),
+                       old_value));
+    }
+    return *result;
+  }
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, JSObject::SetPrototype(obj, prototype, true));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_IsInPrototypeChain) {
+  HandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
+  CONVERT_ARG_HANDLE_CHECKED(Object, O, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, V, 1);
+  PrototypeIterator iter(isolate, V, PrototypeIterator::START_AT_RECEIVER);
+  while (true) {
+    iter.AdvanceIgnoringProxies();
+    if (iter.IsAtEnd()) return isolate->heap()->false_value();
+    if (iter.IsAtEnd(O)) return isolate->heap()->true_value();
+  }
+}
+
+
+// Enumerator used as indices into the array returned from GetOwnProperty
+enum PropertyDescriptorIndices {
+  IS_ACCESSOR_INDEX,
+  VALUE_INDEX,
+  GETTER_INDEX,
+  SETTER_INDEX,
+  WRITABLE_INDEX,
+  ENUMERABLE_INDEX,
+  CONFIGURABLE_INDEX,
+  DESCRIPTOR_SIZE
+};
+
+
+MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate,
+                                                          Handle<JSObject> obj,
+                                                          Handle<Name> name) {
+  Heap* heap = isolate->heap();
+  Factory* factory = isolate->factory();
+
+  PropertyAttributes attrs;
+  uint32_t index = 0;
+  Handle<Object> value;
+  MaybeHandle<AccessorPair> maybe_accessors;
+  // TODO(verwaest): Unify once indexed properties can be handled by the
+  // LookupIterator.
+  if (name->AsArrayIndex(&index)) {
+    // Get attributes.
+    Maybe<PropertyAttributes> maybe =
+        JSReceiver::GetOwnElementAttribute(obj, index);
+    if (!maybe.has_value) return MaybeHandle<Object>();
+    attrs = maybe.value;
+    if (attrs == ABSENT) return factory->undefined_value();
+
+    // Get AccessorPair if present.
+    maybe_accessors = JSObject::GetOwnElementAccessorPair(obj, index);
+
+    // Get value if not an AccessorPair.
+    if (maybe_accessors.is_null()) {
+      ASSIGN_RETURN_ON_EXCEPTION(
+          isolate, value, Runtime::GetElementOrCharAt(isolate, obj, index),
+          Object);
+    }
+  } else {
+    // Get attributes.
+    LookupIterator it(obj, name, LookupIterator::HIDDEN);
+    Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(&it);
+    if (!maybe.has_value) return MaybeHandle<Object>();
+    attrs = maybe.value;
+    if (attrs == ABSENT) return factory->undefined_value();
+
+    // Get AccessorPair if present.
+    if (it.state() == LookupIterator::ACCESSOR &&
+        it.GetAccessors()->IsAccessorPair()) {
+      maybe_accessors = Handle<AccessorPair>::cast(it.GetAccessors());
+    }
+
+    // Get value if not an AccessorPair.
+    if (maybe_accessors.is_null()) {
+      ASSIGN_RETURN_ON_EXCEPTION(isolate, value, Object::GetProperty(&it),
+                                 Object);
+    }
+  }
+  DCHECK(!isolate->has_pending_exception());
+  Handle<FixedArray> elms = factory->NewFixedArray(DESCRIPTOR_SIZE);
+  elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0));
+  elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0));
+  elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(!maybe_accessors.is_null()));
+
+  Handle<AccessorPair> accessors;
+  if (maybe_accessors.ToHandle(&accessors)) {
+    Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate);
+    Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate);
+    elms->set(GETTER_INDEX, *getter);
+    elms->set(SETTER_INDEX, *setter);
+  } else {
+    elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0));
+    elms->set(VALUE_INDEX, *value);
+  }
+
+  return factory->NewJSArrayWithElements(elms);
+}
+
+
+// Returns an array with the property description:
+//  if args[1] is not a property on args[0]
+//          returns undefined
+//  if args[1] is a data property on args[0]
+//         [false, value, Writeable, Enumerable, Configurable]
+//  if args[1] is an accessor on args[0]
+//         [true, GetFunction, SetFunction, Enumerable, Configurable]
+RUNTIME_FUNCTION(Runtime_GetOwnProperty) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     GetOwnProperty(isolate, obj, name));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_PreventExtensions) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     JSObject::PreventExtensions(obj));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_IsExtensible) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSObject, obj, 0);
+  if (obj->IsJSGlobalProxy()) {
+    PrototypeIterator iter(isolate, obj);
+    if (iter.IsAtEnd()) return isolate->heap()->false_value();
+    DCHECK(iter.GetCurrent()->IsJSGlobalObject());
+    obj = JSObject::cast(iter.GetCurrent());
+  }
+  return isolate->heap()->ToBoolean(obj->map()->is_extensible());
+}
+
+
+RUNTIME_FUNCTION(Runtime_DisableAccessChecks) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0);
+  Handle<Map> old_map(object->map());
+  bool needs_access_checks = old_map->is_access_check_needed();
+  if (needs_access_checks) {
+    // Copy map so it won't interfere constructor's initial map.
+    Handle<Map> new_map = Map::Copy(old_map, "DisableAccessChecks");
+    new_map->set_is_access_check_needed(false);
+    JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
+  }
+  return isolate->heap()->ToBoolean(needs_access_checks);
+}
+
+
+RUNTIME_FUNCTION(Runtime_EnableAccessChecks) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  Handle<Map> old_map(object->map());
+  RUNTIME_ASSERT(!old_map->is_access_check_needed());
+  // Copy map so it won't interfere constructor's initial map.
+  Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks");
+  new_map->set_is_access_check_needed(true);
+  JSObject::MigrateToMap(object, new_map);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_SMI_ARG_CHECKED(properties, 1);
+  // Conservative upper limit to prevent fuzz tests from going OOM.
+  RUNTIME_ASSERT(properties <= 100000);
+  if (object->HasFastProperties() && !object->IsJSGlobalProxy()) {
+    JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties,
+                                  "OptimizeForAdding");
+  }
+  return *object;
+}
+
+
+RUNTIME_FUNCTION(Runtime_ObjectFreeze) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+
+  // %ObjectFreeze is a fast path and these cases are handled elsewhere.
+  RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() &&
+                 !object->map()->is_observed() && !object->IsJSProxy());
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_ObjectSeal) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+
+  // %ObjectSeal is a fast path and these cases are handled elsewhere.
+  RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() &&
+                 !object->map()->is_observed() && !object->IsJSProxy());
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Seal(object));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetProperty) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, Runtime::GetObjectProperty(isolate, object, key));
+  return *result;
+}
+
+
+MUST_USE_RESULT static MaybeHandle<Object> TransitionElements(
+    Handle<Object> object, ElementsKind to_kind, Isolate* isolate) {
+  HandleScope scope(isolate);
+  if (!object->IsJSObject()) {
+    isolate->ThrowIllegalOperation();
+    return MaybeHandle<Object>();
+  }
+  ElementsKind from_kind =
+      Handle<JSObject>::cast(object)->map()->elements_kind();
+  if (Map::IsValidElementsTransition(from_kind, to_kind)) {
+    JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
+    return object;
+  }
+  isolate->ThrowIllegalOperation();
+  return MaybeHandle<Object>();
+}
+
+
+// KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
+RUNTIME_FUNCTION(Runtime_KeyedGetProperty) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1);
+
+  // Fast cases for getting named properties of the receiver JSObject
+  // itself.
+  //
+  // The global proxy objects has to be excluded since LookupOwn on
+  // the global proxy object can return a valid result even though the
+  // global proxy object never has properties.  This is the case
+  // because the global proxy object forwards everything to its hidden
+  // prototype including own lookups.
+  //
+  // Additionally, we need to make sure that we do not cache results
+  // for objects that require access checks.
+  if (receiver_obj->IsJSObject()) {
+    if (!receiver_obj->IsJSGlobalProxy() &&
+        !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) {
+      DisallowHeapAllocation no_allocation;
+      Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj);
+      Handle<Name> key = Handle<Name>::cast(key_obj);
+      if (receiver->HasFastProperties()) {
+        // Attempt to use lookup cache.
+        Handle<Map> receiver_map(receiver->map(), isolate);
+        KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
+        int index = keyed_lookup_cache->Lookup(receiver_map, key);
+        if (index != -1) {
+          // Doubles are not cached, so raw read the value.
+          return receiver->RawFastPropertyAt(
+              FieldIndex::ForKeyedLookupCacheIndex(*receiver_map, index));
+        }
+        // Lookup cache miss.  Perform lookup and update the cache if
+        // appropriate.
+        LookupIterator it(receiver, key, LookupIterator::OWN);
+        if (it.state() == LookupIterator::DATA &&
+            it.property_details().type() == FIELD) {
+          FieldIndex field_index = it.GetFieldIndex();
+          // Do not track double fields in the keyed lookup cache. Reading
+          // double values requires boxing.
+          if (!it.representation().IsDouble()) {
+            keyed_lookup_cache->Update(receiver_map, key,
+                                       field_index.GetKeyedLookupCacheIndex());
+          }
+          AllowHeapAllocation allow_allocation;
+          return *JSObject::FastPropertyAt(receiver, it.representation(),
+                                           field_index);
+        }
+      } else {
+        // Attempt dictionary lookup.
+        NameDictionary* dictionary = receiver->property_dictionary();
+        int entry = dictionary->FindEntry(key);
+        if ((entry != NameDictionary::kNotFound) &&
+            (dictionary->DetailsAt(entry).type() == FIELD)) {
+          Object* value = dictionary->ValueAt(entry);
+          if (!receiver->IsGlobalObject()) return value;
+          value = PropertyCell::cast(value)->value();
+          if (!value->IsTheHole()) return value;
+          // If value is the hole (meaning, absent) do the general lookup.
+        }
+      }
+    } else if (key_obj->IsSmi()) {
+      // JSObject without a name key. If the key is a Smi, check for a
+      // definite out-of-bounds access to elements, which is a strong indicator
+      // that subsequent accesses will also call the runtime. Proactively
+      // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
+      // doubles for those future calls in the case that the elements would
+      // become FAST_DOUBLE_ELEMENTS.
+      Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj);
+      ElementsKind elements_kind = js_object->GetElementsKind();
+      if (IsFastDoubleElementsKind(elements_kind)) {
+        Handle<Smi> key = Handle<Smi>::cast(key_obj);
+        if (key->value() >= js_object->elements()->length()) {
+          if (IsFastHoleyElementsKind(elements_kind)) {
+            elements_kind = FAST_HOLEY_ELEMENTS;
+          } else {
+            elements_kind = FAST_ELEMENTS;
+          }
+          RETURN_FAILURE_ON_EXCEPTION(
+              isolate, TransitionElements(js_object, elements_kind, isolate));
+        }
+      } else {
+        DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
+               !IsFastElementsKind(elements_kind));
+      }
+    }
+  } else if (receiver_obj->IsString() && key_obj->IsSmi()) {
+    // Fast case for string indexing using [] with a smi index.
+    Handle<String> str = Handle<String>::cast(receiver_obj);
+    int index = args.smi_at(1);
+    if (index >= 0 && index < str->length()) {
+      return *GetCharAt(str, index);
+    }
+  }
+
+  // Fall back to GetObjectProperty.
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Runtime::GetObjectProperty(isolate, receiver_obj, key_obj));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_AddNamedProperty) {
+  HandleScope scope(isolate);
+  RUNTIME_ASSERT(args.length() == 4);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
+  CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
+  RUNTIME_ASSERT(
+      (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
+  // Compute attributes.
+  PropertyAttributes attributes =
+      static_cast<PropertyAttributes>(unchecked_attributes);
+
+#ifdef DEBUG
+  uint32_t index = 0;
+  DCHECK(!key->ToArrayIndex(&index));
+  LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
+  Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
+  if (!maybe.has_value) return isolate->heap()->exception();
+  RUNTIME_ASSERT(!it.IsFound());
+#endif
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      JSObject::SetOwnPropertyIgnoreAttributes(object, key, value, attributes));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_SetProperty) {
+  HandleScope scope(isolate);
+  RUNTIME_ASSERT(args.length() == 4);
+
+  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
+  CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_arg, 3);
+  StrictMode strict_mode = strict_mode_arg;
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Runtime::SetObjectProperty(isolate, object, key, value, strict_mode));
+  return *result;
+}
+
+
+// Adds an element to an array.
+// This is used to create an indexed data property into an array.
+RUNTIME_FUNCTION(Runtime_AddElement) {
+  HandleScope scope(isolate);
+  RUNTIME_ASSERT(args.length() == 4);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
+  CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
+  RUNTIME_ASSERT(
+      (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
+  // Compute attributes.
+  PropertyAttributes attributes =
+      static_cast<PropertyAttributes>(unchecked_attributes);
+
+  uint32_t index = 0;
+  key->ToArrayIndex(&index);
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, JSObject::SetElement(object, index, value, attributes,
+                                            SLOPPY, false, DEFINE_PROPERTY));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_DeleteProperty) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
+  CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
+  JSReceiver::DeleteMode delete_mode = strict_mode == STRICT
+                                           ? JSReceiver::STRICT_DELETION
+                                           : JSReceiver::NORMAL_DELETION;
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, JSReceiver::DeleteProperty(object, key, delete_mode));
+  return *result;
+}
+
+
+static Object* HasOwnPropertyImplementation(Isolate* isolate,
+                                            Handle<JSObject> object,
+                                            Handle<Name> key) {
+  Maybe<bool> maybe = JSReceiver::HasOwnProperty(object, key);
+  if (!maybe.has_value) return isolate->heap()->exception();
+  if (maybe.value) return isolate->heap()->true_value();
+  // Handle hidden prototypes.  If there's a hidden prototype above this thing
+  // then we have to check it for properties, because they are supposed to
+  // look like they are on this object.
+  PrototypeIterator iter(isolate, object);
+  if (!iter.IsAtEnd() &&
+      Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter))
+          ->map()
+          ->is_hidden_prototype()) {
+    // TODO(verwaest): The recursion is not necessary for keys that are array
+    // indices. Removing this.
+    return HasOwnPropertyImplementation(
+        isolate, Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
+        key);
+  }
+  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
+  return isolate->heap()->false_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_HasOwnProperty) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0)
+  CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
+
+  uint32_t index;
+  const bool key_is_array_index = key->AsArrayIndex(&index);
+
+  // Only JS objects can have properties.
+  if (object->IsJSObject()) {
+    Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
+    // Fast case: either the key is a real named property or it is not
+    // an array index and there are no interceptors or hidden
+    // prototypes.
+    Maybe<bool> maybe;
+    if (key_is_array_index) {
+      maybe = JSObject::HasOwnElement(js_obj, index);
+    } else {
+      maybe = JSObject::HasRealNamedProperty(js_obj, key);
+    }
+    if (!maybe.has_value) return isolate->heap()->exception();
+    DCHECK(!isolate->has_pending_exception());
+    if (maybe.value) {
+      return isolate->heap()->true_value();
+    }
+    Map* map = js_obj->map();
+    if (!key_is_array_index && !map->has_named_interceptor() &&
+        !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
+      return isolate->heap()->false_value();
+    }
+    // Slow case.
+    return HasOwnPropertyImplementation(isolate, Handle<JSObject>(js_obj),
+                                        Handle<Name>(key));
+  } else if (object->IsString() && key_is_array_index) {
+    // Well, there is one exception:  Handle [] on strings.
+    Handle<String> string = Handle<String>::cast(object);
+    if (index < static_cast<uint32_t>(string->length())) {
+      return isolate->heap()->true_value();
+    }
+  }
+  return isolate->heap()->false_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_HasProperty) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
+
+  Maybe<bool> maybe = JSReceiver::HasProperty(receiver, key);
+  if (!maybe.has_value) return isolate->heap()->exception();
+  return isolate->heap()->ToBoolean(maybe.value);
+}
+
+
+RUNTIME_FUNCTION(Runtime_HasElement) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
+  CONVERT_SMI_ARG_CHECKED(index, 1);
+
+  Maybe<bool> maybe = JSReceiver::HasElement(receiver, index);
+  if (!maybe.has_value) return isolate->heap()->exception();
+  return isolate->heap()->ToBoolean(maybe.value);
+}
+
+
+RUNTIME_FUNCTION(Runtime_IsPropertyEnumerable) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
+
+  Maybe<PropertyAttributes> maybe =
+      JSReceiver::GetOwnPropertyAttributes(object, key);
+  if (!maybe.has_value) return isolate->heap()->exception();
+  if (maybe.value == ABSENT) maybe.value = DONT_ENUM;
+  return isolate->heap()->ToBoolean((maybe.value & DONT_ENUM) == 0);
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetPropertyNames) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
+  Handle<JSArray> result;
+
+  isolate->counters()->for_in()->Increment();
+  Handle<FixedArray> elements;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, elements,
+      JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS));
+  return *isolate->factory()->NewJSArrayWithElements(elements);
+}
+
+
+// Returns either a FixedArray as Runtime_GetPropertyNames,
+// or, if the given object has an enum cache that contains
+// all enumerable properties of the object and its prototypes
+// have none, the map of the object. This is used to speed up
+// the check for deletions during a for-in.
+RUNTIME_FUNCTION(Runtime_GetPropertyNamesFast) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
+
+  if (raw_object->IsSimpleEnum()) return raw_object->map();
+
+  HandleScope scope(isolate);
+  Handle<JSReceiver> object(raw_object);
+  Handle<FixedArray> content;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, content,
+      JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS));
+
+  // Test again, since cache may have been built by preceding call.
+  if (object->IsSimpleEnum()) return object->map();
+
+  return *content;
+}
+
+
+// Find the length of the prototype chain that is to be handled as one. If a
+// prototype object is hidden it is to be viewed as part of the the object it
+// is prototype for.
+static int OwnPrototypeChainLength(JSObject* obj) {
+  int count = 1;
+  for (PrototypeIterator iter(obj->GetIsolate(), obj);
+       !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
+    count++;
+  }
+  return count;
+}
+
+
+// Return the names of the own named properties.
+// args[0]: object
+// args[1]: PropertyAttributes as int
+RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  if (!args[0]->IsJSObject()) {
+    return isolate->heap()->undefined_value();
+  }
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+  CONVERT_SMI_ARG_CHECKED(filter_value, 1);
+  PropertyAttributes filter = static_cast<PropertyAttributes>(filter_value);
+
+  // Skip the global proxy as it has no properties and always delegates to the
+  // real global object.
+  if (obj->IsJSGlobalProxy()) {
+    // Only collect names if access is permitted.
+    if (obj->IsAccessCheckNeeded() &&
+        !isolate->MayNamedAccess(obj, isolate->factory()->undefined_value(),
+                                 v8::ACCESS_KEYS)) {
+      isolate->ReportFailedAccessCheck(obj, v8::ACCESS_KEYS);
+      RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
+      return *isolate->factory()->NewJSArray(0);
+    }
+    PrototypeIterator iter(isolate, obj);
+    obj = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+  }
+
+  // Find the number of objects making up this.
+  int length = OwnPrototypeChainLength(*obj);
+
+  // Find the number of own properties for each of the objects.
+  ScopedVector<int> own_property_count(length);
+  int total_property_count = 0;
+  {
+    PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
+    for (int i = 0; i < length; i++) {
+      DCHECK(!iter.IsAtEnd());
+      Handle<JSObject> jsproto =
+          Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+      // Only collect names if access is permitted.
+      if (jsproto->IsAccessCheckNeeded() &&
+          !isolate->MayNamedAccess(jsproto,
+                                   isolate->factory()->undefined_value(),
+                                   v8::ACCESS_KEYS)) {
+        isolate->ReportFailedAccessCheck(jsproto, v8::ACCESS_KEYS);
+        RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
+        return *isolate->factory()->NewJSArray(0);
+      }
+      int n;
+      n = jsproto->NumberOfOwnProperties(filter);
+      own_property_count[i] = n;
+      total_property_count += n;
+      iter.Advance();
+    }
+  }
+
+  // Allocate an array with storage for all the property names.
+  Handle<FixedArray> names =
+      isolate->factory()->NewFixedArray(total_property_count);
+
+  // Get the property names.
+  int next_copy_index = 0;
+  int hidden_strings = 0;
+  {
+    PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
+    for (int i = 0; i < length; i++) {
+      DCHECK(!iter.IsAtEnd());
+      Handle<JSObject> jsproto =
+          Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+      jsproto->GetOwnPropertyNames(*names, next_copy_index, filter);
+      // Names from hidden prototypes may already have been added
+      // for inherited function template instances. Count the duplicates
+      // and stub them out; the final copy pass at the end ignores holes.
+      for (int j = next_copy_index; j < next_copy_index + own_property_count[i];
+           j++) {
+        Object* name_from_hidden_proto = names->get(j);
+        if (isolate->IsInternallyUsedPropertyName(name_from_hidden_proto)) {
+          hidden_strings++;
+        } else {
+          for (int k = 0; k < next_copy_index; k++) {
+            Object* name = names->get(k);
+            if (name_from_hidden_proto == name) {
+              names->set(j, isolate->heap()->hidden_string());
+              hidden_strings++;
+              break;
+            }
+          }
+        }
+      }
+      next_copy_index += own_property_count[i];
+
+      iter.Advance();
+    }
+  }
+
+  // Filter out name of hidden properties object and
+  // hidden prototype duplicates.
+  if (hidden_strings > 0) {
+    Handle<FixedArray> old_names = names;
+    names = isolate->factory()->NewFixedArray(names->length() - hidden_strings);
+    int dest_pos = 0;
+    for (int i = 0; i < total_property_count; i++) {
+      Object* name = old_names->get(i);
+      if (isolate->IsInternallyUsedPropertyName(name)) {
+        hidden_strings--;
+        continue;
+      }
+      names->set(dest_pos++, name);
+    }
+    DCHECK_EQ(0, hidden_strings);
+  }
+
+  return *isolate->factory()->NewJSArrayWithElements(names);
+}
+
+
+// Return the names of the own indexed properties.
+// args[0]: object
+RUNTIME_FUNCTION(Runtime_GetOwnElementNames) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  if (!args[0]->IsJSObject()) {
+    return isolate->heap()->undefined_value();
+  }
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+
+  int n = obj->NumberOfOwnElements(static_cast<PropertyAttributes>(NONE));
+  Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
+  obj->GetOwnElementKeys(*names, static_cast<PropertyAttributes>(NONE));
+  return *isolate->factory()->NewJSArrayWithElements(names);
+}
+
+
+// Return information on whether an object has a named or indexed interceptor.
+// args[0]: object
+RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  if (!args[0]->IsJSObject()) {
+    return Smi::FromInt(0);
+  }
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+
+  int result = 0;
+  if (obj->HasNamedInterceptor()) result |= 2;
+  if (obj->HasIndexedInterceptor()) result |= 1;
+
+  return Smi::FromInt(result);
+}
+
+
+// Return property names from named interceptor.
+// args[0]: object
+RUNTIME_FUNCTION(Runtime_GetNamedInterceptorPropertyNames) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+
+  if (obj->HasNamedInterceptor()) {
+    Handle<JSObject> result;
+    if (JSObject::GetKeysForNamedInterceptor(obj, obj).ToHandle(&result)) {
+      return *result;
+    }
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
+// Return element names from indexed interceptor.
+// args[0]: object
+RUNTIME_FUNCTION(Runtime_GetIndexedInterceptorElementNames) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+
+  if (obj->HasIndexedInterceptor()) {
+    Handle<JSObject> result;
+    if (JSObject::GetKeysForIndexedInterceptor(obj, obj).ToHandle(&result)) {
+      return *result;
+    }
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_OwnKeys) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
+  Handle<JSObject> object(raw_object);
+
+  if (object->IsJSGlobalProxy()) {
+    // Do access checks before going to the global object.
+    if (object->IsAccessCheckNeeded() &&
+        !isolate->MayNamedAccess(object, isolate->factory()->undefined_value(),
+                                 v8::ACCESS_KEYS)) {
+      isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
+      RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
+      return *isolate->factory()->NewJSArray(0);
+    }
+
+    PrototypeIterator iter(isolate, object);
+    // If proxy is detached we simply return an empty array.
+    if (iter.IsAtEnd()) return *isolate->factory()->NewJSArray(0);
+    object = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+  }
+
+  Handle<FixedArray> contents;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, contents, JSReceiver::GetKeys(object, JSReceiver::OWN_ONLY));
+
+  // Some fast paths through GetKeysInFixedArrayFor reuse a cached
+  // property array and since the result is mutable we have to create
+  // a fresh clone on each invocation.
+  int length = contents->length();
+  Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
+  for (int i = 0; i < length; i++) {
+    Object* entry = contents->get(i);
+    if (entry->IsString()) {
+      copy->set(i, entry);
+    } else {
+      DCHECK(entry->IsNumber());
+      HandleScope scope(isolate);
+      Handle<Object> entry_handle(entry, isolate);
+      Handle<Object> entry_str =
+          isolate->factory()->NumberToString(entry_handle);
+      copy->set(i, *entry_str);
+    }
+  }
+  return *isolate->factory()->NewJSArrayWithElements(copy);
+}
+
+
+RUNTIME_FUNCTION(Runtime_ToFastProperties) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
+  if (object->IsJSObject() && !object->IsGlobalObject()) {
+    JSObject::MigrateSlowToFast(Handle<JSObject>::cast(object), 0,
+                                "RuntimeToFastProperties");
+  }
+  return *object;
+}
+
+
+RUNTIME_FUNCTION(Runtime_ToBool) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, object, 0);
+
+  return isolate->heap()->ToBoolean(object->BooleanValue());
+}
+
+
+// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
+// Possible optimizations: put the type string into the oddballs.
+RUNTIME_FUNCTION(Runtime_Typeof) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  if (obj->IsNumber()) return isolate->heap()->number_string();
+  HeapObject* heap_obj = HeapObject::cast(obj);
+
+  // typeof an undetectable object is 'undefined'
+  if (heap_obj->map()->is_undetectable()) {
+    return isolate->heap()->undefined_string();
+  }
+
+  InstanceType instance_type = heap_obj->map()->instance_type();
+  if (instance_type < FIRST_NONSTRING_TYPE) {
+    return isolate->heap()->string_string();
+  }
+
+  switch (instance_type) {
+    case ODDBALL_TYPE:
+      if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
+        return isolate->heap()->boolean_string();
+      }
+      if (heap_obj->IsNull()) {
+        return isolate->heap()->object_string();
+      }
+      DCHECK(heap_obj->IsUndefined());
+      return isolate->heap()->undefined_string();
+    case SYMBOL_TYPE:
+      return isolate->heap()->symbol_string();
+    case JS_FUNCTION_TYPE:
+    case JS_FUNCTION_PROXY_TYPE:
+      return isolate->heap()->function_string();
+    default:
+      // For any kind of object not handled above, the spec rule for
+      // host objects gives that it is okay to return "object"
+      return isolate->heap()->object_string();
+  }
+}
+
+
+RUNTIME_FUNCTION(Runtime_Booleanize) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_CHECKED(Object, value_raw, 0);
+  CONVERT_SMI_ARG_CHECKED(token_raw, 1);
+  intptr_t value = reinterpret_cast<intptr_t>(value_raw);
+  Token::Value token = static_cast<Token::Value>(token_raw);
+  switch (token) {
+    case Token::EQ:
+    case Token::EQ_STRICT:
+      return isolate->heap()->ToBoolean(value == 0);
+    case Token::NE:
+    case Token::NE_STRICT:
+      return isolate->heap()->ToBoolean(value != 0);
+    case Token::LT:
+      return isolate->heap()->ToBoolean(value < 0);
+    case Token::GT:
+      return isolate->heap()->ToBoolean(value > 0);
+    case Token::LTE:
+      return isolate->heap()->ToBoolean(value <= 0);
+    case Token::GTE:
+      return isolate->heap()->ToBoolean(value >= 0);
+    default:
+      // This should only happen during natives fuzzing.
+      return isolate->heap()->undefined_value();
+  }
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewStringWrapper) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, value, 0);
+  return *Object::ToObject(isolate, value).ToHandleChecked();
+}
+
+
+RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+  return *isolate->factory()->NewHeapNumber(0);
+}
+
+
+static Object* Runtime_NewObjectHelper(Isolate* isolate,
+                                       Handle<Object> constructor,
+                                       Handle<AllocationSite> site) {
+  // If the constructor isn't a proper function we throw a type error.
+  if (!constructor->IsJSFunction()) {
+    Vector<Handle<Object> > arguments = HandleVector(&constructor, 1);
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate,
+                                   NewTypeError("not_constructor", arguments));
+  }
+
+  Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
+
+  // If function should not have prototype, construction is not allowed. In this
+  // case generated code bailouts here, since function has no initial_map.
+  if (!function->should_have_prototype() && !function->shared()->bound()) {
+    Vector<Handle<Object> > arguments = HandleVector(&constructor, 1);
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate,
+                                   NewTypeError("not_constructor", arguments));
+  }
+
+  Debug* debug = isolate->debug();
+  // Handle stepping into constructors if step into is active.
+  if (debug->StepInActive()) {
+    debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
+  }
+
+  if (function->has_initial_map()) {
+    if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
+      // The 'Function' function ignores the receiver object when
+      // called using 'new' and creates a new JSFunction object that
+      // is returned.  The receiver object is only used for error
+      // reporting if an error occurs when constructing the new
+      // JSFunction. Factory::NewJSObject() should not be used to
+      // allocate JSFunctions since it does not properly initialize
+      // the shared part of the function. Since the receiver is
+      // ignored anyway, we use the global object as the receiver
+      // instead of a new JSFunction object. This way, errors are
+      // reported the same way whether or not 'Function' is called
+      // using 'new'.
+      return isolate->global_proxy();
+    }
+  }
+
+  // The function should be compiled for the optimization hints to be
+  // available.
+  Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
+
+  Handle<JSObject> result;
+  if (site.is_null()) {
+    result = isolate->factory()->NewJSObject(function);
+  } else {
+    result = isolate->factory()->NewJSObjectWithMemento(function, site);
+  }
+
+  isolate->counters()->constructed_objects()->Increment();
+  isolate->counters()->constructed_objects_runtime()->Increment();
+
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewObject) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 0);
+  return Runtime_NewObjectHelper(isolate, constructor,
+                                 Handle<AllocationSite>::null());
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewObjectWithAllocationSite) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, feedback, 0);
+  Handle<AllocationSite> site;
+  if (feedback->IsAllocationSite()) {
+    // The feedback can be an AllocationSite or undefined.
+    site = Handle<AllocationSite>::cast(feedback);
+  }
+  return Runtime_NewObjectHelper(isolate, constructor, site);
+}
+
+
+RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+  function->CompleteInobjectSlackTracking();
+
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GlobalProxy) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, global, 0);
+  if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
+  return JSGlobalObject::cast(global)->global_proxy();
+}
+
+
+RUNTIME_FUNCTION(Runtime_LookupAccessor) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
+  CONVERT_SMI_ARG_CHECKED(flag, 2);
+  AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
+  if (!receiver->IsJSObject()) return isolate->heap()->undefined_value();
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_LoadMutableDouble) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1);
+  RUNTIME_ASSERT((index->value() & 1) == 1);
+  FieldIndex field_index =
+      FieldIndex::ForLoadByFieldIndex(object->map(), index->value());
+  if (field_index.is_inobject()) {
+    RUNTIME_ASSERT(field_index.property_index() <
+                   object->map()->inobject_properties());
+  } else {
+    RUNTIME_ASSERT(field_index.outobject_array_index() <
+                   object->properties()->length());
+  }
+  return *JSObject::FastPropertyAt(object, Representation::Double(),
+                                   field_index);
+}
+
+
+RUNTIME_FUNCTION(Runtime_TryMigrateInstance) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
+  if (!object->IsJSObject()) return Smi::FromInt(0);
+  Handle<JSObject> js_object = Handle<JSObject>::cast(object);
+  if (!js_object->map()->is_deprecated()) return Smi::FromInt(0);
+  // This call must not cause lazy deopts, because it's called from deferred
+  // code where we can't handle lazy deopts for lack of a suitable bailout
+  // ID. So we just try migration and signal failure if necessary,
+  // which will also trigger a deopt.
+  if (!JSObject::TryMigrateInstance(js_object)) return Smi::FromInt(0);
+  return *object;
+}
+
+
+RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy());
+}
+
+
+static bool IsValidAccessor(Handle<Object> obj) {
+  return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
+}
+
+
+// Implements part of 8.12.9 DefineOwnProperty.
+// There are 3 cases that lead here:
+// Step 4b - define a new accessor property.
+// Steps 9c & 12 - replace an existing data property with an accessor property.
+// Step 12 - update an existing accessor property with an accessor or generic
+//           descriptor.
+RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 5);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+  RUNTIME_ASSERT(!obj->IsNull());
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
+  RUNTIME_ASSERT(IsValidAccessor(getter));
+  CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
+  RUNTIME_ASSERT(IsValidAccessor(setter));
+  CONVERT_SMI_ARG_CHECKED(unchecked, 4);
+  RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
+  PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
+
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate, JSObject::DefineAccessor(obj, name, getter, setter, attr));
+  return isolate->heap()->undefined_value();
+}
+
+
+// Implements part of 8.12.9 DefineOwnProperty.
+// There are 3 cases that lead here:
+// Step 4a - define a new data property.
+// Steps 9b & 12 - replace an existing accessor property with a data property.
+// Step 12 - update an existing data property with a data or generic
+//           descriptor.
+RUNTIME_FUNCTION(Runtime_DefineDataPropertyUnchecked) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
+  CONVERT_SMI_ARG_CHECKED(unchecked, 3);
+  RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
+  PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
+
+  LookupIterator it(js_object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
+  if (it.IsFound() && it.state() == LookupIterator::ACCESS_CHECK) {
+    if (!isolate->MayNamedAccess(js_object, name, v8::ACCESS_SET)) {
+      return isolate->heap()->undefined_value();
+    }
+    it.Next();
+  }
+
+  // Take special care when attributes are different and there is already
+  // a property.
+  if (it.state() == LookupIterator::ACCESSOR) {
+    // Use IgnoreAttributes version since a readonly property may be
+    // overridden and SetProperty does not allow this.
+    Handle<Object> result;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, result,
+        JSObject::SetOwnPropertyIgnoreAttributes(
+            js_object, name, obj_value, attr, JSObject::DONT_FORCE_FIELD));
+    return *result;
+  }
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Runtime::DefineObjectProperty(js_object, name, obj_value, attr));
+  return *result;
+}
+
+
+// Return property without being observable by accessors or interceptors.
+RUNTIME_FUNCTION(Runtime_GetDataProperty) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
+  return *JSObject::GetDataProperty(object, key);
+}
+
+
+RUNTIME_FUNCTION(Runtime_HasFastPackedElements) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(HeapObject, obj, 0);
+  return isolate->heap()->ToBoolean(
+      IsFastPackedElementsKind(obj->map()->elements_kind()));
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_ValueOf) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  if (!obj->IsJSValue()) return obj;
+  return JSValue::cast(obj)->value();
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_SetValueOf) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  CONVERT_ARG_CHECKED(Object, value, 1);
+  if (!obj->IsJSValue()) return value;
+  JSValue::cast(obj)->set_value(value);
+  return value;
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_ObjectEquals) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_CHECKED(Object, obj1, 0);
+  CONVERT_ARG_CHECKED(Object, obj2, 1);
+  return isolate->heap()->ToBoolean(obj1 == obj2);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_IsObject) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  if (!obj->IsHeapObject()) return isolate->heap()->false_value();
+  if (obj->IsNull()) return isolate->heap()->true_value();
+  if (obj->IsUndetectableObject()) return isolate->heap()->false_value();
+  Map* map = HeapObject::cast(obj)->map();
+  bool is_non_callable_spec_object =
+      map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
+      map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE;
+  return isolate->heap()->ToBoolean(is_non_callable_spec_object);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_IsUndetectableObject) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  return isolate->heap()->ToBoolean(obj->IsUndetectableObject());
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_IsSpecObject) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  return isolate->heap()->ToBoolean(obj->IsSpecObject());
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_ClassOf) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  if (!obj->IsJSReceiver()) return isolate->heap()->null_value();
+  return JSReceiver::cast(obj)->class_name();
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-observe.cc b/src/runtime/runtime-observe.cc
new file mode 100644
index 0000000..211922c
--- /dev/null
+++ b/src/runtime/runtime-observe.cc
@@ -0,0 +1,160 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/debug.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_IsObserved) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+
+  if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value();
+  CONVERT_ARG_CHECKED(JSReceiver, obj, 0);
+  DCHECK(!obj->IsJSGlobalProxy() || !obj->map()->is_observed());
+  return isolate->heap()->ToBoolean(obj->map()->is_observed());
+}
+
+
+RUNTIME_FUNCTION(Runtime_SetIsObserved) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
+  RUNTIME_ASSERT(!obj->IsJSGlobalProxy());
+  if (obj->IsJSProxy()) return isolate->heap()->undefined_value();
+  RUNTIME_ASSERT(!obj->map()->is_observed());
+
+  DCHECK(obj->IsJSObject());
+  JSObject::SetObserved(Handle<JSObject>::cast(obj));
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_EnqueueMicrotask) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, microtask, 0);
+  isolate->EnqueueMicrotask(microtask);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_RunMicrotasks) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+  isolate->RunMicrotasks();
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DeliverObservationChangeRecords) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, callback, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, argument, 1);
+  v8::TryCatch catcher;
+  // We should send a message on uncaught exception thrown during
+  // Object.observe delivery while not interrupting further delivery, thus
+  // we make a call inside a verbose TryCatch.
+  catcher.SetVerbose(true);
+  Handle<Object> argv[] = {argument};
+
+  // Allow stepping into the observer callback.
+  Debug* debug = isolate->debug();
+  if (debug->is_active() && debug->IsStepping() &&
+      debug->last_step_action() == StepIn) {
+    // Previous StepIn may have activated a StepOut if it was at the frame exit.
+    // In this case to be able to step into the callback again, we need to clear
+    // the step out first.
+    debug->ClearStepOut();
+    debug->FloodWithOneShot(callback);
+  }
+
+  USE(Execution::Call(isolate, callback, isolate->factory()->undefined_value(),
+                      arraysize(argv), argv));
+  if (isolate->has_pending_exception()) {
+    isolate->ReportPendingMessages();
+    isolate->clear_pending_exception();
+    isolate->set_external_caught_exception(false);
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetObservationState) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  return isolate->heap()->observation_state();
+}
+
+
+static bool ContextsHaveSameOrigin(Handle<Context> context1,
+                                   Handle<Context> context2) {
+  return context1->security_token() == context2->security_token();
+}
+
+
+RUNTIME_FUNCTION(Runtime_ObserverObjectAndRecordHaveSameOrigin) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, record, 2);
+
+  Handle<Context> observer_context(observer->context()->native_context());
+  Handle<Context> object_context(object->GetCreationContext());
+  Handle<Context> record_context(record->GetCreationContext());
+
+  return isolate->heap()->ToBoolean(
+      ContextsHaveSameOrigin(object_context, observer_context) &&
+      ContextsHaveSameOrigin(object_context, record_context));
+}
+
+
+RUNTIME_FUNCTION(Runtime_ObjectWasCreatedInCurrentOrigin) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+
+  Handle<Context> creation_context(object->GetCreationContext(), isolate);
+  return isolate->heap()->ToBoolean(
+      ContextsHaveSameOrigin(creation_context, isolate->native_context()));
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetObjectContextObjectObserve) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+
+  Handle<Context> context(object->GetCreationContext(), isolate);
+  return context->native_object_observe();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetObjectContextObjectGetNotifier) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+
+  Handle<Context> context(object->GetCreationContext(), isolate);
+  return context->native_object_get_notifier();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetObjectContextNotifierPerformChange) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object_info, 0);
+
+  Handle<Context> context(object_info->GetCreationContext(), isolate);
+  return context->native_object_notifier_perform_change();
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-proxy.cc b/src/runtime/runtime-proxy.cc
new file mode 100644
index 0000000..baf7cdb
--- /dev/null
+++ b/src/runtime/runtime-proxy.cc
@@ -0,0 +1,85 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_CreateJSProxy) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
+  if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value();
+  return *isolate->factory()->NewJSProxy(handler, prototype);
+}
+
+
+RUNTIME_FUNCTION(Runtime_CreateJSFunctionProxy) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, call_trap, 1);
+  RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy());
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, construct_trap, 2);
+  CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 3);
+  if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value();
+  return *isolate->factory()->NewJSFunctionProxy(handler, call_trap,
+                                                 construct_trap, prototype);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_IsJSProxy) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  return isolate->heap()->ToBoolean(obj->IsJSProxy());
+}
+
+
+RUNTIME_FUNCTION(Runtime_IsJSFunctionProxy) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
+  return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetHandler) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
+  return proxy->handler();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetCallTrap) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
+  return proxy->call_trap();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetConstructTrap) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
+  return proxy->construct_trap();
+}
+
+
+RUNTIME_FUNCTION(Runtime_Fix) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0);
+  JSProxy::Fix(proxy);
+  return isolate->heap()->undefined_value();
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-regexp.cc b/src/runtime/runtime-regexp.cc
new file mode 100644
index 0000000..9296a4b
--- /dev/null
+++ b/src/runtime/runtime-regexp.cc
@@ -0,0 +1,1122 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/jsregexp-inl.h"
+#include "src/jsregexp.h"
+#include "src/runtime/runtime-utils.h"
+#include "src/string-builder.h"
+#include "src/string-search.h"
+
+namespace v8 {
+namespace internal {
+
+class CompiledReplacement {
+ public:
+  explicit CompiledReplacement(Zone* zone)
+      : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {}
+
+  // Return whether the replacement is simple.
+  bool Compile(Handle<String> replacement, int capture_count,
+               int subject_length);
+
+  // Use Apply only if Compile returned false.
+  void Apply(ReplacementStringBuilder* builder, int match_from, int match_to,
+             int32_t* match);
+
+  // Number of distinct parts of the replacement pattern.
+  int parts() { return parts_.length(); }
+
+  Zone* zone() const { return zone_; }
+
+ private:
+  enum PartType {
+    SUBJECT_PREFIX = 1,
+    SUBJECT_SUFFIX,
+    SUBJECT_CAPTURE,
+    REPLACEMENT_SUBSTRING,
+    REPLACEMENT_STRING,
+    NUMBER_OF_PART_TYPES
+  };
+
+  struct ReplacementPart {
+    static inline ReplacementPart SubjectMatch() {
+      return ReplacementPart(SUBJECT_CAPTURE, 0);
+    }
+    static inline ReplacementPart SubjectCapture(int capture_index) {
+      return ReplacementPart(SUBJECT_CAPTURE, capture_index);
+    }
+    static inline ReplacementPart SubjectPrefix() {
+      return ReplacementPart(SUBJECT_PREFIX, 0);
+    }
+    static inline ReplacementPart SubjectSuffix(int subject_length) {
+      return ReplacementPart(SUBJECT_SUFFIX, subject_length);
+    }
+    static inline ReplacementPart ReplacementString() {
+      return ReplacementPart(REPLACEMENT_STRING, 0);
+    }
+    static inline ReplacementPart ReplacementSubString(int from, int to) {
+      DCHECK(from >= 0);
+      DCHECK(to > from);
+      return ReplacementPart(-from, to);
+    }
+
+    // If tag <= 0 then it is the negation of a start index of a substring of
+    // the replacement pattern, otherwise it's a value from PartType.
+    ReplacementPart(int tag, int data) : tag(tag), data(data) {
+      // Must be non-positive or a PartType value.
+      DCHECK(tag < NUMBER_OF_PART_TYPES);
+    }
+    // Either a value of PartType or a non-positive number that is
+    // the negation of an index into the replacement string.
+    int tag;
+    // The data value's interpretation depends on the value of tag:
+    // tag == SUBJECT_PREFIX ||
+    // tag == SUBJECT_SUFFIX:  data is unused.
+    // tag == SUBJECT_CAPTURE: data is the number of the capture.
+    // tag == REPLACEMENT_SUBSTRING ||
+    // tag == REPLACEMENT_STRING:    data is index into array of substrings
+    //                               of the replacement string.
+    // tag <= 0: Temporary representation of the substring of the replacement
+    //           string ranging over -tag .. data.
+    //           Is replaced by REPLACEMENT_{SUB,}STRING when we create the
+    //           substring objects.
+    int data;
+  };
+
+  template <typename Char>
+  bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
+                               Vector<Char> characters, int capture_count,
+                               int subject_length, Zone* zone) {
+    int length = characters.length();
+    int last = 0;
+    for (int i = 0; i < length; i++) {
+      Char c = characters[i];
+      if (c == '$') {
+        int next_index = i + 1;
+        if (next_index == length) {  // No next character!
+          break;
+        }
+        Char c2 = characters[next_index];
+        switch (c2) {
+          case '$':
+            if (i > last) {
+              // There is a substring before. Include the first "$".
+              parts->Add(
+                  ReplacementPart::ReplacementSubString(last, next_index),
+                  zone);
+              last = next_index + 1;  // Continue after the second "$".
+            } else {
+              // Let the next substring start with the second "$".
+              last = next_index;
+            }
+            i = next_index;
+            break;
+          case '`':
+            if (i > last) {
+              parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
+            }
+            parts->Add(ReplacementPart::SubjectPrefix(), zone);
+            i = next_index;
+            last = i + 1;
+            break;
+          case '\'':
+            if (i > last) {
+              parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
+            }
+            parts->Add(ReplacementPart::SubjectSuffix(subject_length), zone);
+            i = next_index;
+            last = i + 1;
+            break;
+          case '&':
+            if (i > last) {
+              parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
+            }
+            parts->Add(ReplacementPart::SubjectMatch(), zone);
+            i = next_index;
+            last = i + 1;
+            break;
+          case '0':
+          case '1':
+          case '2':
+          case '3':
+          case '4':
+          case '5':
+          case '6':
+          case '7':
+          case '8':
+          case '9': {
+            int capture_ref = c2 - '0';
+            if (capture_ref > capture_count) {
+              i = next_index;
+              continue;
+            }
+            int second_digit_index = next_index + 1;
+            if (second_digit_index < length) {
+              // Peek ahead to see if we have two digits.
+              Char c3 = characters[second_digit_index];
+              if ('0' <= c3 && c3 <= '9') {  // Double digits.
+                int double_digit_ref = capture_ref * 10 + c3 - '0';
+                if (double_digit_ref <= capture_count) {
+                  next_index = second_digit_index;
+                  capture_ref = double_digit_ref;
+                }
+              }
+            }
+            if (capture_ref > 0) {
+              if (i > last) {
+                parts->Add(ReplacementPart::ReplacementSubString(last, i),
+                           zone);
+              }
+              DCHECK(capture_ref <= capture_count);
+              parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone);
+              last = next_index + 1;
+            }
+            i = next_index;
+            break;
+          }
+          default:
+            i = next_index;
+            break;
+        }
+      }
+    }
+    if (length > last) {
+      if (last == 0) {
+        // Replacement is simple.  Do not use Apply to do the replacement.
+        return true;
+      } else {
+        parts->Add(ReplacementPart::ReplacementSubString(last, length), zone);
+      }
+    }
+    return false;
+  }
+
+  ZoneList<ReplacementPart> parts_;
+  ZoneList<Handle<String> > replacement_substrings_;
+  Zone* zone_;
+};
+
+
+bool CompiledReplacement::Compile(Handle<String> replacement, int capture_count,
+                                  int subject_length) {
+  {
+    DisallowHeapAllocation no_gc;
+    String::FlatContent content = replacement->GetFlatContent();
+    DCHECK(content.IsFlat());
+    bool simple = false;
+    if (content.IsOneByte()) {
+      simple = ParseReplacementPattern(&parts_, content.ToOneByteVector(),
+                                       capture_count, subject_length, zone());
+    } else {
+      DCHECK(content.IsTwoByte());
+      simple = ParseReplacementPattern(&parts_, content.ToUC16Vector(),
+                                       capture_count, subject_length, zone());
+    }
+    if (simple) return true;
+  }
+
+  Isolate* isolate = replacement->GetIsolate();
+  // Find substrings of replacement string and create them as String objects.
+  int substring_index = 0;
+  for (int i = 0, n = parts_.length(); i < n; i++) {
+    int tag = parts_[i].tag;
+    if (tag <= 0) {  // A replacement string slice.
+      int from = -tag;
+      int to = parts_[i].data;
+      replacement_substrings_.Add(
+          isolate->factory()->NewSubString(replacement, from, to), zone());
+      parts_[i].tag = REPLACEMENT_SUBSTRING;
+      parts_[i].data = substring_index;
+      substring_index++;
+    } else if (tag == REPLACEMENT_STRING) {
+      replacement_substrings_.Add(replacement, zone());
+      parts_[i].data = substring_index;
+      substring_index++;
+    }
+  }
+  return false;
+}
+
+
+void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
+                                int match_from, int match_to, int32_t* match) {
+  DCHECK_LT(0, parts_.length());
+  for (int i = 0, n = parts_.length(); i < n; i++) {
+    ReplacementPart part = parts_[i];
+    switch (part.tag) {
+      case SUBJECT_PREFIX:
+        if (match_from > 0) builder->AddSubjectSlice(0, match_from);
+        break;
+      case SUBJECT_SUFFIX: {
+        int subject_length = part.data;
+        if (match_to < subject_length) {
+          builder->AddSubjectSlice(match_to, subject_length);
+        }
+        break;
+      }
+      case SUBJECT_CAPTURE: {
+        int capture = part.data;
+        int from = match[capture * 2];
+        int to = match[capture * 2 + 1];
+        if (from >= 0 && to > from) {
+          builder->AddSubjectSlice(from, to);
+        }
+        break;
+      }
+      case REPLACEMENT_SUBSTRING:
+      case REPLACEMENT_STRING:
+        builder->AddString(replacement_substrings_[part.data]);
+        break;
+      default:
+        UNREACHABLE();
+    }
+  }
+}
+
+
+void FindOneByteStringIndices(Vector<const uint8_t> subject, uint8_t pattern,
+                              ZoneList<int>* indices, unsigned int limit,
+                              Zone* zone) {
+  DCHECK(limit > 0);
+  // Collect indices of pattern in subject using memchr.
+  // Stop after finding at most limit values.
+  const uint8_t* subject_start = subject.start();
+  const uint8_t* subject_end = subject_start + subject.length();
+  const uint8_t* pos = subject_start;
+  while (limit > 0) {
+    pos = reinterpret_cast<const uint8_t*>(
+        memchr(pos, pattern, subject_end - pos));
+    if (pos == NULL) return;
+    indices->Add(static_cast<int>(pos - subject_start), zone);
+    pos++;
+    limit--;
+  }
+}
+
+
+void FindTwoByteStringIndices(const Vector<const uc16> subject, uc16 pattern,
+                              ZoneList<int>* indices, unsigned int limit,
+                              Zone* zone) {
+  DCHECK(limit > 0);
+  const uc16* subject_start = subject.start();
+  const uc16* subject_end = subject_start + subject.length();
+  for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) {
+    if (*pos == pattern) {
+      indices->Add(static_cast<int>(pos - subject_start), zone);
+      limit--;
+    }
+  }
+}
+
+
+template <typename SubjectChar, typename PatternChar>
+void FindStringIndices(Isolate* isolate, Vector<const SubjectChar> subject,
+                       Vector<const PatternChar> pattern,
+                       ZoneList<int>* indices, unsigned int limit, Zone* zone) {
+  DCHECK(limit > 0);
+  // Collect indices of pattern in subject.
+  // Stop after finding at most limit values.
+  int pattern_length = pattern.length();
+  int index = 0;
+  StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
+  while (limit > 0) {
+    index = search.Search(subject, index);
+    if (index < 0) return;
+    indices->Add(index, zone);
+    index += pattern_length;
+    limit--;
+  }
+}
+
+
+void FindStringIndicesDispatch(Isolate* isolate, String* subject,
+                               String* pattern, ZoneList<int>* indices,
+                               unsigned int limit, Zone* zone) {
+  {
+    DisallowHeapAllocation no_gc;
+    String::FlatContent subject_content = subject->GetFlatContent();
+    String::FlatContent pattern_content = pattern->GetFlatContent();
+    DCHECK(subject_content.IsFlat());
+    DCHECK(pattern_content.IsFlat());
+    if (subject_content.IsOneByte()) {
+      Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
+      if (pattern_content.IsOneByte()) {
+        Vector<const uint8_t> pattern_vector =
+            pattern_content.ToOneByteVector();
+        if (pattern_vector.length() == 1) {
+          FindOneByteStringIndices(subject_vector, pattern_vector[0], indices,
+                                   limit, zone);
+        } else {
+          FindStringIndices(isolate, subject_vector, pattern_vector, indices,
+                            limit, zone);
+        }
+      } else {
+        FindStringIndices(isolate, subject_vector,
+                          pattern_content.ToUC16Vector(), indices, limit, zone);
+      }
+    } else {
+      Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
+      if (pattern_content.IsOneByte()) {
+        Vector<const uint8_t> pattern_vector =
+            pattern_content.ToOneByteVector();
+        if (pattern_vector.length() == 1) {
+          FindTwoByteStringIndices(subject_vector, pattern_vector[0], indices,
+                                   limit, zone);
+        } else {
+          FindStringIndices(isolate, subject_vector, pattern_vector, indices,
+                            limit, zone);
+        }
+      } else {
+        Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector();
+        if (pattern_vector.length() == 1) {
+          FindTwoByteStringIndices(subject_vector, pattern_vector[0], indices,
+                                   limit, zone);
+        } else {
+          FindStringIndices(isolate, subject_vector, pattern_vector, indices,
+                            limit, zone);
+        }
+      }
+    }
+  }
+}
+
+
+template <typename ResultSeqString>
+MUST_USE_RESULT static Object* StringReplaceGlobalAtomRegExpWithString(
+    Isolate* isolate, Handle<String> subject, Handle<JSRegExp> pattern_regexp,
+    Handle<String> replacement, Handle<JSArray> last_match_info) {
+  DCHECK(subject->IsFlat());
+  DCHECK(replacement->IsFlat());
+
+  ZoneScope zone_scope(isolate->runtime_zone());
+  ZoneList<int> indices(8, zone_scope.zone());
+  DCHECK_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
+  String* pattern =
+      String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
+  int subject_len = subject->length();
+  int pattern_len = pattern->length();
+  int replacement_len = replacement->length();
+
+  FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff,
+                            zone_scope.zone());
+
+  int matches = indices.length();
+  if (matches == 0) return *subject;
+
+  // Detect integer overflow.
+  int64_t result_len_64 = (static_cast<int64_t>(replacement_len) -
+                           static_cast<int64_t>(pattern_len)) *
+                              static_cast<int64_t>(matches) +
+                          static_cast<int64_t>(subject_len);
+  int result_len;
+  if (result_len_64 > static_cast<int64_t>(String::kMaxLength)) {
+    STATIC_ASSERT(String::kMaxLength < kMaxInt);
+    result_len = kMaxInt;  // Provoke exception.
+  } else {
+    result_len = static_cast<int>(result_len_64);
+  }
+
+  int subject_pos = 0;
+  int result_pos = 0;
+
+  MaybeHandle<SeqString> maybe_res;
+  if (ResultSeqString::kHasOneByteEncoding) {
+    maybe_res = isolate->factory()->NewRawOneByteString(result_len);
+  } else {
+    maybe_res = isolate->factory()->NewRawTwoByteString(result_len);
+  }
+  Handle<SeqString> untyped_res;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, untyped_res, maybe_res);
+  Handle<ResultSeqString> result = Handle<ResultSeqString>::cast(untyped_res);
+
+  for (int i = 0; i < matches; i++) {
+    // Copy non-matched subject content.
+    if (subject_pos < indices.at(i)) {
+      String::WriteToFlat(*subject, result->GetChars() + result_pos,
+                          subject_pos, indices.at(i));
+      result_pos += indices.at(i) - subject_pos;
+    }
+
+    // Replace match.
+    if (replacement_len > 0) {
+      String::WriteToFlat(*replacement, result->GetChars() + result_pos, 0,
+                          replacement_len);
+      result_pos += replacement_len;
+    }
+
+    subject_pos = indices.at(i) + pattern_len;
+  }
+  // Add remaining subject content at the end.
+  if (subject_pos < subject_len) {
+    String::WriteToFlat(*subject, result->GetChars() + result_pos, subject_pos,
+                        subject_len);
+  }
+
+  int32_t match_indices[] = {indices.at(matches - 1),
+                             indices.at(matches - 1) + pattern_len};
+  RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices);
+
+  return *result;
+}
+
+
+MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString(
+    Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp,
+    Handle<String> replacement, Handle<JSArray> last_match_info) {
+  DCHECK(subject->IsFlat());
+  DCHECK(replacement->IsFlat());
+
+  int capture_count = regexp->CaptureCount();
+  int subject_length = subject->length();
+
+  // CompiledReplacement uses zone allocation.
+  ZoneScope zone_scope(isolate->runtime_zone());
+  CompiledReplacement compiled_replacement(zone_scope.zone());
+  bool simple_replace =
+      compiled_replacement.Compile(replacement, capture_count, subject_length);
+
+  // Shortcut for simple non-regexp global replacements
+  if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) {
+    if (subject->HasOnlyOneByteChars() && replacement->HasOnlyOneByteChars()) {
+      return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
+          isolate, subject, regexp, replacement, last_match_info);
+    } else {
+      return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
+          isolate, subject, regexp, replacement, last_match_info);
+    }
+  }
+
+  RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
+  if (global_cache.HasException()) return isolate->heap()->exception();
+
+  int32_t* current_match = global_cache.FetchNext();
+  if (current_match == NULL) {
+    if (global_cache.HasException()) return isolate->heap()->exception();
+    return *subject;
+  }
+
+  // Guessing the number of parts that the final result string is built
+  // from. Global regexps can match any number of times, so we guess
+  // conservatively.
+  int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1;
+  ReplacementStringBuilder builder(isolate->heap(), subject, expected_parts);
+
+  // Number of parts added by compiled replacement plus preceeding
+  // string and possibly suffix after last match.  It is possible for
+  // all components to use two elements when encoded as two smis.
+  const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
+
+  int prev = 0;
+
+  do {
+    builder.EnsureCapacity(parts_added_per_loop);
+
+    int start = current_match[0];
+    int end = current_match[1];
+
+    if (prev < start) {
+      builder.AddSubjectSlice(prev, start);
+    }
+
+    if (simple_replace) {
+      builder.AddString(replacement);
+    } else {
+      compiled_replacement.Apply(&builder, start, end, current_match);
+    }
+    prev = end;
+
+    current_match = global_cache.FetchNext();
+  } while (current_match != NULL);
+
+  if (global_cache.HasException()) return isolate->heap()->exception();
+
+  if (prev < subject_length) {
+    builder.EnsureCapacity(2);
+    builder.AddSubjectSlice(prev, subject_length);
+  }
+
+  RegExpImpl::SetLastMatchInfo(last_match_info, subject, capture_count,
+                               global_cache.LastSuccessfulMatch());
+
+  Handle<String> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, builder.ToString());
+  return *result;
+}
+
+
+template <typename ResultSeqString>
+MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString(
+    Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp,
+    Handle<JSArray> last_match_info) {
+  DCHECK(subject->IsFlat());
+
+  // Shortcut for simple non-regexp global replacements
+  if (regexp->TypeTag() == JSRegExp::ATOM) {
+    Handle<String> empty_string = isolate->factory()->empty_string();
+    if (subject->IsOneByteRepresentation()) {
+      return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
+          isolate, subject, regexp, empty_string, last_match_info);
+    } else {
+      return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
+          isolate, subject, regexp, empty_string, last_match_info);
+    }
+  }
+
+  RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
+  if (global_cache.HasException()) return isolate->heap()->exception();
+
+  int32_t* current_match = global_cache.FetchNext();
+  if (current_match == NULL) {
+    if (global_cache.HasException()) return isolate->heap()->exception();
+    return *subject;
+  }
+
+  int start = current_match[0];
+  int end = current_match[1];
+  int capture_count = regexp->CaptureCount();
+  int subject_length = subject->length();
+
+  int new_length = subject_length - (end - start);
+  if (new_length == 0) return isolate->heap()->empty_string();
+
+  Handle<ResultSeqString> answer;
+  if (ResultSeqString::kHasOneByteEncoding) {
+    answer = Handle<ResultSeqString>::cast(
+        isolate->factory()->NewRawOneByteString(new_length).ToHandleChecked());
+  } else {
+    answer = Handle<ResultSeqString>::cast(
+        isolate->factory()->NewRawTwoByteString(new_length).ToHandleChecked());
+  }
+
+  int prev = 0;
+  int position = 0;
+
+  do {
+    start = current_match[0];
+    end = current_match[1];
+    if (prev < start) {
+      // Add substring subject[prev;start] to answer string.
+      String::WriteToFlat(*subject, answer->GetChars() + position, prev, start);
+      position += start - prev;
+    }
+    prev = end;
+
+    current_match = global_cache.FetchNext();
+  } while (current_match != NULL);
+
+  if (global_cache.HasException()) return isolate->heap()->exception();
+
+  RegExpImpl::SetLastMatchInfo(last_match_info, subject, capture_count,
+                               global_cache.LastSuccessfulMatch());
+
+  if (prev < subject_length) {
+    // Add substring subject[prev;length] to answer string.
+    String::WriteToFlat(*subject, answer->GetChars() + position, prev,
+                        subject_length);
+    position += subject_length - prev;
+  }
+
+  if (position == 0) return isolate->heap()->empty_string();
+
+  // Shorten string and fill
+  int string_size = ResultSeqString::SizeFor(position);
+  int allocated_string_size = ResultSeqString::SizeFor(new_length);
+  int delta = allocated_string_size - string_size;
+
+  answer->set_length(position);
+  if (delta == 0) return *answer;
+
+  Address end_of_string = answer->address() + string_size;
+  Heap* heap = isolate->heap();
+
+  // The trimming is performed on a newly allocated object, which is on a
+  // fresly allocated page or on an already swept page. Hence, the sweeper
+  // thread can not get confused with the filler creation. No synchronization
+  // needed.
+  heap->CreateFillerObjectAt(end_of_string, delta);
+  heap->AdjustLiveBytes(answer->address(), -delta, Heap::FROM_MUTATOR);
+  return *answer;
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
+
+  RUNTIME_ASSERT(regexp->GetFlags().is_global());
+  RUNTIME_ASSERT(last_match_info->HasFastObjectElements());
+
+  subject = String::Flatten(subject);
+
+  if (replacement->length() == 0) {
+    if (subject->HasOnlyOneByteChars()) {
+      return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>(
+          isolate, subject, regexp, last_match_info);
+    } else {
+      return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>(
+          isolate, subject, regexp, last_match_info);
+    }
+  }
+
+  replacement = String::Flatten(replacement);
+
+  return StringReplaceGlobalRegExpWithString(isolate, subject, regexp,
+                                             replacement, last_match_info);
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringSplit) {
+  HandleScope handle_scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
+  CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
+  RUNTIME_ASSERT(limit > 0);
+
+  int subject_length = subject->length();
+  int pattern_length = pattern->length();
+  RUNTIME_ASSERT(pattern_length > 0);
+
+  if (limit == 0xffffffffu) {
+    Handle<Object> cached_answer(
+        RegExpResultsCache::Lookup(isolate->heap(), *subject, *pattern,
+                                   RegExpResultsCache::STRING_SPLIT_SUBSTRINGS),
+        isolate);
+    if (*cached_answer != Smi::FromInt(0)) {
+      // The cache FixedArray is a COW-array and can therefore be reused.
+      Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(
+          Handle<FixedArray>::cast(cached_answer));
+      return *result;
+    }
+  }
+
+  // The limit can be very large (0xffffffffu), but since the pattern
+  // isn't empty, we can never create more parts than ~half the length
+  // of the subject.
+
+  subject = String::Flatten(subject);
+  pattern = String::Flatten(pattern);
+
+  static const int kMaxInitialListCapacity = 16;
+
+  ZoneScope zone_scope(isolate->runtime_zone());
+
+  // Find (up to limit) indices of separator and end-of-string in subject
+  int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
+  ZoneList<int> indices(initial_capacity, zone_scope.zone());
+
+  FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit,
+                            zone_scope.zone());
+
+  if (static_cast<uint32_t>(indices.length()) < limit) {
+    indices.Add(subject_length, zone_scope.zone());
+  }
+
+  // The list indices now contains the end of each part to create.
+
+  // Create JSArray of substrings separated by separator.
+  int part_count = indices.length();
+
+  Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
+  JSObject::EnsureCanContainHeapObjectElements(result);
+  result->set_length(Smi::FromInt(part_count));
+
+  DCHECK(result->HasFastObjectElements());
+
+  if (part_count == 1 && indices.at(0) == subject_length) {
+    FixedArray::cast(result->elements())->set(0, *subject);
+    return *result;
+  }
+
+  Handle<FixedArray> elements(FixedArray::cast(result->elements()));
+  int part_start = 0;
+  for (int i = 0; i < part_count; i++) {
+    HandleScope local_loop_handle(isolate);
+    int part_end = indices.at(i);
+    Handle<String> substring =
+        isolate->factory()->NewProperSubString(subject, part_start, part_end);
+    elements->set(i, *substring);
+    part_start = part_end + pattern_length;
+  }
+
+  if (limit == 0xffffffffu) {
+    if (result->HasFastObjectElements()) {
+      RegExpResultsCache::Enter(isolate, subject, pattern, elements,
+                                RegExpResultsCache::STRING_SPLIT_SUBSTRINGS);
+    }
+  }
+
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_RegExpExecRT) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
+  CONVERT_INT32_ARG_CHECKED(index, 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
+  // Due to the way the JS calls are constructed this must be less than the
+  // length of a string, i.e. it is always a Smi.  We check anyway for security.
+  RUNTIME_ASSERT(index >= 0);
+  RUNTIME_ASSERT(index <= subject->length());
+  isolate->counters()->regexp_entry_runtime()->Increment();
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      RegExpImpl::Exec(regexp, subject, index, last_match_info));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_RegExpConstructResult) {
+  HandleScope handle_scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_SMI_ARG_CHECKED(size, 0);
+  RUNTIME_ASSERT(size >= 0 && size <= FixedArray::kMaxLength);
+  CONVERT_ARG_HANDLE_CHECKED(Object, index, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, input, 2);
+  Handle<FixedArray> elements = isolate->factory()->NewFixedArray(size);
+  Handle<Map> regexp_map(isolate->native_context()->regexp_result_map());
+  Handle<JSObject> object =
+      isolate->factory()->NewJSObjectFromMap(regexp_map, NOT_TENURED, false);
+  Handle<JSArray> array = Handle<JSArray>::cast(object);
+  array->set_elements(*elements);
+  array->set_length(Smi::FromInt(size));
+  // Write in-object properties after the length of the array.
+  array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, *index);
+  array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, *input);
+  return *array;
+}
+
+
+static JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags,
+                                             bool* success) {
+  uint32_t value = JSRegExp::NONE;
+  int length = flags->length();
+  // A longer flags string cannot be valid.
+  if (length > 4) return JSRegExp::Flags(0);
+  for (int i = 0; i < length; i++) {
+    uint32_t flag = JSRegExp::NONE;
+    switch (flags->Get(i)) {
+      case 'g':
+        flag = JSRegExp::GLOBAL;
+        break;
+      case 'i':
+        flag = JSRegExp::IGNORE_CASE;
+        break;
+      case 'm':
+        flag = JSRegExp::MULTILINE;
+        break;
+      case 'y':
+        if (!FLAG_harmony_regexps) return JSRegExp::Flags(0);
+        flag = JSRegExp::STICKY;
+        break;
+      default:
+        return JSRegExp::Flags(0);
+    }
+    // Duplicate flag.
+    if (value & flag) return JSRegExp::Flags(0);
+    value |= flag;
+  }
+  *success = true;
+  return JSRegExp::Flags(value);
+}
+
+
+RUNTIME_FUNCTION(Runtime_RegExpInitializeAndCompile) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, flags_string, 2);
+  Factory* factory = isolate->factory();
+  // If source is the empty string we set it to "(?:)" instead as
+  // suggested by ECMA-262, 5th, section 15.10.4.1.
+  if (source->length() == 0) source = factory->query_colon_string();
+
+  bool success = false;
+  JSRegExp::Flags flags = RegExpFlagsFromString(flags_string, &success);
+  if (!success) {
+    Handle<FixedArray> element = factory->NewFixedArray(1);
+    element->set(0, *flags_string);
+    Handle<JSArray> args = factory->NewJSArrayWithElements(element);
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewSyntaxError("invalid_regexp_flags", args));
+  }
+
+  Handle<Object> global = factory->ToBoolean(flags.is_global());
+  Handle<Object> ignore_case = factory->ToBoolean(flags.is_ignore_case());
+  Handle<Object> multiline = factory->ToBoolean(flags.is_multiline());
+  Handle<Object> sticky = factory->ToBoolean(flags.is_sticky());
+
+  Map* map = regexp->map();
+  Object* constructor = map->constructor();
+  if (!FLAG_harmony_regexps && constructor->IsJSFunction() &&
+      JSFunction::cast(constructor)->initial_map() == map) {
+    // If we still have the original map, set in-object properties directly.
+    // Both true and false are immovable immortal objects so no need for write
+    // barrier.
+    regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, *global,
+                                  SKIP_WRITE_BARRIER);
+    regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, *ignore_case,
+                                  SKIP_WRITE_BARRIER);
+    regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, *multiline,
+                                  SKIP_WRITE_BARRIER);
+    regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
+                                  Smi::FromInt(0), SKIP_WRITE_BARRIER);
+  } else {
+    // Map has changed, so use generic, but slower, method.  We also end here if
+    // the --harmony-regexp flag is set, because the initial map does not have
+    // space for the 'sticky' flag, since it is from the snapshot, but must work
+    // both with and without --harmony-regexp.  When sticky comes out from under
+    // the flag, we will be able to use the fast initial map.
+    PropertyAttributes final =
+        static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
+    PropertyAttributes writable =
+        static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
+    Handle<Object> zero(Smi::FromInt(0), isolate);
+    JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->global_string(),
+                                             global, final).Check();
+    JSObject::SetOwnPropertyIgnoreAttributes(
+        regexp, factory->ignore_case_string(), ignore_case, final).Check();
+    JSObject::SetOwnPropertyIgnoreAttributes(
+        regexp, factory->multiline_string(), multiline, final).Check();
+    if (FLAG_harmony_regexps) {
+      JSObject::SetOwnPropertyIgnoreAttributes(regexp, factory->sticky_string(),
+                                               sticky, final).Check();
+    }
+    JSObject::SetOwnPropertyIgnoreAttributes(
+        regexp, factory->last_index_string(), zero, writable).Check();
+  }
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, RegExpImpl::Compile(regexp, source, flags));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_MaterializeRegExpLiteral) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
+  CONVERT_SMI_ARG_CHECKED(index, 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2);
+  CONVERT_ARG_HANDLE_CHECKED(String, flags, 3);
+
+  // Get the RegExp function from the context in the literals array.
+  // This is the RegExp function from the context in which the
+  // function was created.  We do not use the RegExp function from the
+  // current native context because this might be the RegExp function
+  // from another context which we should not have access to.
+  Handle<JSFunction> constructor = Handle<JSFunction>(
+      JSFunction::NativeContextFromLiterals(*literals)->regexp_function());
+  // Compute the regular expression literal.
+  Handle<Object> regexp;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, regexp,
+      RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags));
+  literals->set(index, *regexp);
+  return *regexp;
+}
+
+
+// Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
+// separate last match info.  See comment on that function.
+template <bool has_capture>
+static Object* SearchRegExpMultiple(Isolate* isolate, Handle<String> subject,
+                                    Handle<JSRegExp> regexp,
+                                    Handle<JSArray> last_match_array,
+                                    Handle<JSArray> result_array) {
+  DCHECK(subject->IsFlat());
+  DCHECK_NE(has_capture, regexp->CaptureCount() == 0);
+
+  int capture_count = regexp->CaptureCount();
+  int subject_length = subject->length();
+
+  static const int kMinLengthToCache = 0x1000;
+
+  if (subject_length > kMinLengthToCache) {
+    Handle<Object> cached_answer(
+        RegExpResultsCache::Lookup(isolate->heap(), *subject, regexp->data(),
+                                   RegExpResultsCache::REGEXP_MULTIPLE_INDICES),
+        isolate);
+    if (*cached_answer != Smi::FromInt(0)) {
+      Handle<FixedArray> cached_fixed_array =
+          Handle<FixedArray>(FixedArray::cast(*cached_answer));
+      // The cache FixedArray is a COW-array and can therefore be reused.
+      JSArray::SetContent(result_array, cached_fixed_array);
+      // The actual length of the result array is stored in the last element of
+      // the backing store (the backing FixedArray may have a larger capacity).
+      Object* cached_fixed_array_last_element =
+          cached_fixed_array->get(cached_fixed_array->length() - 1);
+      Smi* js_array_length = Smi::cast(cached_fixed_array_last_element);
+      result_array->set_length(js_array_length);
+      RegExpImpl::SetLastMatchInfo(last_match_array, subject, capture_count,
+                                   NULL);
+      return *result_array;
+    }
+  }
+
+  RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
+  if (global_cache.HasException()) return isolate->heap()->exception();
+
+  // Ensured in Runtime_RegExpExecMultiple.
+  DCHECK(result_array->HasFastObjectElements());
+  Handle<FixedArray> result_elements(
+      FixedArray::cast(result_array->elements()));
+  if (result_elements->length() < 16) {
+    result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
+  }
+
+  FixedArrayBuilder builder(result_elements);
+
+  // Position to search from.
+  int match_start = -1;
+  int match_end = 0;
+  bool first = true;
+
+  // Two smis before and after the match, for very long strings.
+  static const int kMaxBuilderEntriesPerRegExpMatch = 5;
+
+  while (true) {
+    int32_t* current_match = global_cache.FetchNext();
+    if (current_match == NULL) break;
+    match_start = current_match[0];
+    builder.EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
+    if (match_end < match_start) {
+      ReplacementStringBuilder::AddSubjectSlice(&builder, match_end,
+                                                match_start);
+    }
+    match_end = current_match[1];
+    {
+      // Avoid accumulating new handles inside loop.
+      HandleScope temp_scope(isolate);
+      Handle<String> match;
+      if (!first) {
+        match = isolate->factory()->NewProperSubString(subject, match_start,
+                                                       match_end);
+      } else {
+        match =
+            isolate->factory()->NewSubString(subject, match_start, match_end);
+        first = false;
+      }
+
+      if (has_capture) {
+        // Arguments array to replace function is match, captures, index and
+        // subject, i.e., 3 + capture count in total.
+        Handle<FixedArray> elements =
+            isolate->factory()->NewFixedArray(3 + capture_count);
+
+        elements->set(0, *match);
+        for (int i = 1; i <= capture_count; i++) {
+          int start = current_match[i * 2];
+          if (start >= 0) {
+            int end = current_match[i * 2 + 1];
+            DCHECK(start <= end);
+            Handle<String> substring =
+                isolate->factory()->NewSubString(subject, start, end);
+            elements->set(i, *substring);
+          } else {
+            DCHECK(current_match[i * 2 + 1] < 0);
+            elements->set(i, isolate->heap()->undefined_value());
+          }
+        }
+        elements->set(capture_count + 1, Smi::FromInt(match_start));
+        elements->set(capture_count + 2, *subject);
+        builder.Add(*isolate->factory()->NewJSArrayWithElements(elements));
+      } else {
+        builder.Add(*match);
+      }
+    }
+  }
+
+  if (global_cache.HasException()) return isolate->heap()->exception();
+
+  if (match_start >= 0) {
+    // Finished matching, with at least one match.
+    if (match_end < subject_length) {
+      ReplacementStringBuilder::AddSubjectSlice(&builder, match_end,
+                                                subject_length);
+    }
+
+    RegExpImpl::SetLastMatchInfo(last_match_array, subject, capture_count,
+                                 NULL);
+
+    if (subject_length > kMinLengthToCache) {
+      // Store the length of the result array into the last element of the
+      // backing FixedArray.
+      builder.EnsureCapacity(1);
+      Handle<FixedArray> fixed_array = builder.array();
+      fixed_array->set(fixed_array->length() - 1,
+                       Smi::FromInt(builder.length()));
+      // Cache the result and turn the FixedArray into a COW array.
+      RegExpResultsCache::Enter(isolate, subject,
+                                handle(regexp->data(), isolate), fixed_array,
+                                RegExpResultsCache::REGEXP_MULTIPLE_INDICES);
+    }
+    return *builder.ToJSArray(result_array);
+  } else {
+    return isolate->heap()->null_value();  // No matches at all.
+  }
+}
+
+
+// This is only called for StringReplaceGlobalRegExpWithFunction.  This sets
+// lastMatchInfoOverride to maintain the last match info, so we don't need to
+// set any other last match array info.
+RUNTIME_FUNCTION(Runtime_RegExpExecMultiple) {
+  HandleScope handles(isolate);
+  DCHECK(args.length() == 4);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
+  RUNTIME_ASSERT(last_match_info->HasFastObjectElements());
+  RUNTIME_ASSERT(result_array->HasFastObjectElements());
+
+  subject = String::Flatten(subject);
+  RUNTIME_ASSERT(regexp->GetFlags().is_global());
+
+  if (regexp->CaptureCount() == 0) {
+    return SearchRegExpMultiple<false>(isolate, subject, regexp,
+                                       last_match_info, result_array);
+  } else {
+    return SearchRegExpMultiple<true>(isolate, subject, regexp, last_match_info,
+                                      result_array);
+  }
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_RegExpConstructResult) {
+  SealHandleScope shs(isolate);
+  return __RT_impl_Runtime_RegExpConstructResult(args, isolate);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_RegExpExec) {
+  SealHandleScope shs(isolate);
+  return __RT_impl_Runtime_RegExpExecRT(args, isolate);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_IsRegExp) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  return isolate->heap()->ToBoolean(obj->IsJSRegExp());
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-scopes.cc b/src/runtime/runtime-scopes.cc
new file mode 100644
index 0000000..2a0b435
--- /dev/null
+++ b/src/runtime/runtime-scopes.cc
@@ -0,0 +1,1088 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/accessors.h"
+#include "src/arguments.h"
+#include "src/frames-inl.h"
+#include "src/runtime/runtime-utils.h"
+#include "src/scopeinfo.h"
+#include "src/scopes.h"
+
+namespace v8 {
+namespace internal {
+
+static Object* ThrowRedeclarationError(Isolate* isolate, Handle<String> name) {
+  HandleScope scope(isolate);
+  Handle<Object> args[1] = {name};
+  THROW_NEW_ERROR_RETURN_FAILURE(
+      isolate, NewTypeError("var_redeclaration", HandleVector(args, 1)));
+}
+
+
+RUNTIME_FUNCTION(Runtime_ThrowConstAssignError) {
+  HandleScope scope(isolate);
+  THROW_NEW_ERROR_RETURN_FAILURE(
+      isolate,
+      NewTypeError("harmony_const_assign", HandleVector<Object>(NULL, 0)));
+}
+
+
+// May throw a RedeclarationError.
+static Object* DeclareGlobals(Isolate* isolate, Handle<GlobalObject> global,
+                              Handle<String> name, Handle<Object> value,
+                              PropertyAttributes attr, bool is_var,
+                              bool is_const, bool is_function) {
+  Handle<ScriptContextTable> script_contexts(
+      global->native_context()->script_context_table());
+  ScriptContextTable::LookupResult lookup;
+  if (ScriptContextTable::Lookup(script_contexts, name, &lookup) &&
+      IsLexicalVariableMode(lookup.mode)) {
+    return ThrowRedeclarationError(isolate, name);
+  }
+
+  // Do the lookup own properties only, see ES5 erratum.
+  LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
+  Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
+  if (!maybe.has_value) return isolate->heap()->exception();
+
+  if (it.IsFound()) {
+    PropertyAttributes old_attributes = maybe.value;
+    // The name was declared before; check for conflicting re-declarations.
+    if (is_const) return ThrowRedeclarationError(isolate, name);
+
+    // Skip var re-declarations.
+    if (is_var) return isolate->heap()->undefined_value();
+
+    DCHECK(is_function);
+    if ((old_attributes & DONT_DELETE) != 0) {
+      // Only allow reconfiguring globals to functions in user code (no
+      // natives, which are marked as read-only).
+      DCHECK((attr & READ_ONLY) == 0);
+
+      // Check whether we can reconfigure the existing property into a
+      // function.
+      PropertyDetails old_details = it.property_details();
+      // TODO(verwaest): CALLBACKS invalidly includes ExecutableAccessInfo,
+      // which are actually data properties, not accessor properties.
+      if (old_details.IsReadOnly() || old_details.IsDontEnum() ||
+          old_details.type() == CALLBACKS) {
+        return ThrowRedeclarationError(isolate, name);
+      }
+      // If the existing property is not configurable, keep its attributes. Do
+      attr = old_attributes;
+    }
+  }
+
+  // Define or redefine own property.
+  RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+                                           global, name, value, attr));
+
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  Handle<GlobalObject> global(isolate->global_object());
+
+  CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
+  CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
+  CONVERT_SMI_ARG_CHECKED(flags, 2);
+
+  // Traverse the name/value pairs and set the properties.
+  int length = pairs->length();
+  for (int i = 0; i < length; i += 2) {
+    HandleScope scope(isolate);
+    Handle<String> name(String::cast(pairs->get(i)));
+    Handle<Object> initial_value(pairs->get(i + 1), isolate);
+
+    // We have to declare a global const property. To capture we only
+    // assign to it when evaluating the assignment for "const x =
+    // <expr>" the initial value is the hole.
+    bool is_var = initial_value->IsUndefined();
+    bool is_const = initial_value->IsTheHole();
+    bool is_function = initial_value->IsSharedFunctionInfo();
+    DCHECK(is_var + is_const + is_function == 1);
+
+    Handle<Object> value;
+    if (is_function) {
+      // Copy the function and update its context. Use it as value.
+      Handle<SharedFunctionInfo> shared =
+          Handle<SharedFunctionInfo>::cast(initial_value);
+      Handle<JSFunction> function =
+          isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
+                                                                TENURED);
+      value = function;
+    } else {
+      value = isolate->factory()->undefined_value();
+    }
+
+    // Compute the property attributes. According to ECMA-262,
+    // the property must be non-configurable except in eval.
+    bool is_native = DeclareGlobalsNativeFlag::decode(flags);
+    bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
+    int attr = NONE;
+    if (is_const) attr |= READ_ONLY;
+    if (is_function && is_native) attr |= READ_ONLY;
+    if (!is_const && !is_eval) attr |= DONT_DELETE;
+
+    Object* result = DeclareGlobals(isolate, global, name, value,
+                                    static_cast<PropertyAttributes>(attr),
+                                    is_var, is_const, is_function);
+    if (isolate->has_pending_exception()) return result;
+  }
+
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) {
+  HandleScope scope(isolate);
+  // args[0] == name
+  // args[1] == language_mode
+  // args[2] == value (optional)
+
+  // Determine if we need to assign to the variable if it already
+  // exists (based on the number of arguments).
+  RUNTIME_ASSERT(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
+  CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
+
+  Handle<GlobalObject> global(isolate->context()->global_object());
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, Object::SetProperty(global, name, value, strict_mode));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) {
+  HandleScope handle_scope(isolate);
+  // All constants are declared with an initial value. The name
+  // of the constant is the first argument and the initial value
+  // is the second.
+  RUNTIME_ASSERT(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
+
+  Handle<GlobalObject> global = isolate->global_object();
+
+  // Lookup the property as own on the global object.
+  LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
+  Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
+  DCHECK(maybe.has_value);
+  PropertyAttributes old_attributes = maybe.value;
+
+  PropertyAttributes attr =
+      static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
+  // Set the value if the property is either missing, or the property attributes
+  // allow setting the value without invoking an accessor.
+  if (it.IsFound()) {
+    // Ignore if we can't reconfigure the value.
+    if ((old_attributes & DONT_DELETE) != 0) {
+      if ((old_attributes & READ_ONLY) != 0 ||
+          it.state() == LookupIterator::ACCESSOR) {
+        return *value;
+      }
+      attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
+    }
+  }
+
+  RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+                                           global, name, value, attr));
+
+  return *value;
+}
+
+
+RUNTIME_FUNCTION(Runtime_DeclareLookupSlot) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+
+  // Declarations are always made in a function, eval or script context. In
+  // the case of eval code, the context passed is the context of the caller,
+  // which may be some nested context and not the declaration context.
+  CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 0);
+  Handle<Context> context(context_arg->declaration_context());
+  CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
+  CONVERT_SMI_ARG_CHECKED(attr_arg, 2);
+  PropertyAttributes attr = static_cast<PropertyAttributes>(attr_arg);
+  RUNTIME_ASSERT(attr == READ_ONLY || attr == NONE);
+  CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 3);
+
+  // TODO(verwaest): Unify the encoding indicating "var" with DeclareGlobals.
+  bool is_var = *initial_value == NULL;
+  bool is_const = initial_value->IsTheHole();
+  bool is_function = initial_value->IsJSFunction();
+  DCHECK(is_var + is_const + is_function == 1);
+
+  int index;
+  PropertyAttributes attributes;
+  ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
+  BindingFlags binding_flags;
+  Handle<Object> holder =
+      context->Lookup(name, flags, &index, &attributes, &binding_flags);
+
+  Handle<JSObject> object;
+  Handle<Object> value =
+      is_function ? initial_value
+                  : Handle<Object>::cast(isolate->factory()->undefined_value());
+
+  // TODO(verwaest): This case should probably not be covered by this function,
+  // but by DeclareGlobals instead.
+  if ((attributes != ABSENT && holder->IsJSGlobalObject()) ||
+      (context_arg->has_extension() &&
+       context_arg->extension()->IsJSGlobalObject())) {
+    return DeclareGlobals(isolate, Handle<JSGlobalObject>::cast(holder), name,
+                          value, attr, is_var, is_const, is_function);
+  }
+
+  if (attributes != ABSENT) {
+    // The name was declared before; check for conflicting re-declarations.
+    if (is_const || (attributes & READ_ONLY) != 0) {
+      return ThrowRedeclarationError(isolate, name);
+    }
+
+    // Skip var re-declarations.
+    if (is_var) return isolate->heap()->undefined_value();
+
+    DCHECK(is_function);
+    if (index >= 0) {
+      DCHECK(holder.is_identical_to(context));
+      context->set(index, *initial_value);
+      return isolate->heap()->undefined_value();
+    }
+
+    object = Handle<JSObject>::cast(holder);
+
+  } else if (context->has_extension()) {
+    object = handle(JSObject::cast(context->extension()));
+    DCHECK(object->IsJSContextExtensionObject() || object->IsJSGlobalObject());
+  } else {
+    DCHECK(context->IsFunctionContext());
+    object =
+        isolate->factory()->NewJSObject(isolate->context_extension_function());
+    context->set_extension(*object);
+  }
+
+  RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+                                           object, name, value, attr));
+
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_InitializeLegacyConstLookupSlot) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
+  DCHECK(!value->IsTheHole());
+  // Initializations are always done in a function or native context.
+  CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 1);
+  Handle<Context> context(context_arg->declaration_context());
+  CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
+
+  int index;
+  PropertyAttributes attributes;
+  ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
+  BindingFlags binding_flags;
+  Handle<Object> holder =
+      context->Lookup(name, flags, &index, &attributes, &binding_flags);
+
+  if (index >= 0) {
+    DCHECK(holder->IsContext());
+    // Property was found in a context.  Perform the assignment if the constant
+    // was uninitialized.
+    Handle<Context> context = Handle<Context>::cast(holder);
+    DCHECK((attributes & READ_ONLY) != 0);
+    if (context->get(index)->IsTheHole()) context->set(index, *value);
+    return *value;
+  }
+
+  PropertyAttributes attr =
+      static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
+
+  // Strict mode handling not needed (legacy const is disallowed in strict
+  // mode).
+
+  // The declared const was configurable, and may have been deleted in the
+  // meanwhile. If so, re-introduce the variable in the context extension.
+  if (attributes == ABSENT) {
+    Handle<Context> declaration_context(context_arg->declaration_context());
+    DCHECK(declaration_context->has_extension());
+    holder = handle(declaration_context->extension(), isolate);
+    CHECK(holder->IsJSObject());
+  } else {
+    // For JSContextExtensionObjects, the initializer can be run multiple times
+    // if in a for loop: for (var i = 0; i < 2; i++) { const x = i; }. Only the
+    // first assignment should go through. For JSGlobalObjects, additionally any
+    // code can run in between that modifies the declared property.
+    DCHECK(holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject());
+
+    LookupIterator it(holder, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
+    Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
+    if (!maybe.has_value) return isolate->heap()->exception();
+    PropertyAttributes old_attributes = maybe.value;
+
+    // Ignore if we can't reconfigure the value.
+    if ((old_attributes & DONT_DELETE) != 0) {
+      if ((old_attributes & READ_ONLY) != 0 ||
+          it.state() == LookupIterator::ACCESSOR) {
+        return *value;
+      }
+      attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
+    }
+  }
+
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+                   Handle<JSObject>::cast(holder), name, value, attr));
+
+  return *value;
+}
+
+
+static Handle<JSObject> NewSloppyArguments(Isolate* isolate,
+                                           Handle<JSFunction> callee,
+                                           Object** parameters,
+                                           int argument_count) {
+  Handle<JSObject> result =
+      isolate->factory()->NewArgumentsObject(callee, argument_count);
+
+  // Allocate the elements if needed.
+  int parameter_count = callee->shared()->formal_parameter_count();
+  if (argument_count > 0) {
+    if (parameter_count > 0) {
+      int mapped_count = Min(argument_count, parameter_count);
+      Handle<FixedArray> parameter_map =
+          isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
+      parameter_map->set_map(isolate->heap()->sloppy_arguments_elements_map());
+
+      Handle<Map> map = Map::Copy(handle(result->map()), "NewSloppyArguments");
+      map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS);
+
+      result->set_map(*map);
+      result->set_elements(*parameter_map);
+
+      // Store the context and the arguments array at the beginning of the
+      // parameter map.
+      Handle<Context> context(isolate->context());
+      Handle<FixedArray> arguments =
+          isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
+      parameter_map->set(0, *context);
+      parameter_map->set(1, *arguments);
+
+      // Loop over the actual parameters backwards.
+      int index = argument_count - 1;
+      while (index >= mapped_count) {
+        // These go directly in the arguments array and have no
+        // corresponding slot in the parameter map.
+        arguments->set(index, *(parameters - index - 1));
+        --index;
+      }
+
+      Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
+      while (index >= 0) {
+        // Detect duplicate names to the right in the parameter list.
+        Handle<String> name(scope_info->ParameterName(index));
+        int context_local_count = scope_info->ContextLocalCount();
+        bool duplicate = false;
+        for (int j = index + 1; j < parameter_count; ++j) {
+          if (scope_info->ParameterName(j) == *name) {
+            duplicate = true;
+            break;
+          }
+        }
+
+        if (duplicate) {
+          // This goes directly in the arguments array with a hole in the
+          // parameter map.
+          arguments->set(index, *(parameters - index - 1));
+          parameter_map->set_the_hole(index + 2);
+        } else {
+          // The context index goes in the parameter map with a hole in the
+          // arguments array.
+          int context_index = -1;
+          for (int j = 0; j < context_local_count; ++j) {
+            if (scope_info->ContextLocalName(j) == *name) {
+              context_index = j;
+              break;
+            }
+          }
+          DCHECK(context_index >= 0);
+          arguments->set_the_hole(index);
+          parameter_map->set(
+              index + 2,
+              Smi::FromInt(Context::MIN_CONTEXT_SLOTS + context_index));
+        }
+
+        --index;
+      }
+    } else {
+      // If there is no aliasing, the arguments object elements are not
+      // special in any way.
+      Handle<FixedArray> elements =
+          isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
+      result->set_elements(*elements);
+      for (int i = 0; i < argument_count; ++i) {
+        elements->set(i, *(parameters - i - 1));
+      }
+    }
+  }
+  return result;
+}
+
+
+static Handle<JSObject> NewStrictArguments(Isolate* isolate,
+                                           Handle<JSFunction> callee,
+                                           Object** parameters,
+                                           int argument_count) {
+  Handle<JSObject> result =
+      isolate->factory()->NewArgumentsObject(callee, argument_count);
+
+  if (argument_count > 0) {
+    Handle<FixedArray> array =
+        isolate->factory()->NewUninitializedFixedArray(argument_count);
+    DisallowHeapAllocation no_gc;
+    WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
+    for (int i = 0; i < argument_count; i++) {
+      array->set(i, *--parameters, mode);
+    }
+    result->set_elements(*array);
+  }
+  return result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewArguments) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
+  JavaScriptFrameIterator it(isolate);
+
+  // Find the frame that holds the actual arguments passed to the function.
+  it.AdvanceToArgumentsFrame();
+  JavaScriptFrame* frame = it.frame();
+
+  // Determine parameter location on the stack and dispatch on language mode.
+  int argument_count = frame->GetArgumentsLength();
+  Object** parameters = reinterpret_cast<Object**>(frame->GetParameterSlot(-1));
+  return callee->shared()->strict_mode() == STRICT
+             ? *NewStrictArguments(isolate, callee, parameters, argument_count)
+             : *NewSloppyArguments(isolate, callee, parameters, argument_count);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
+  Object** parameters = reinterpret_cast<Object**>(args[1]);
+  CONVERT_SMI_ARG_CHECKED(argument_count, 2);
+  return *NewSloppyArguments(isolate, callee, parameters, argument_count);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewStrictArguments) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0)
+  Object** parameters = reinterpret_cast<Object**>(args[1]);
+  CONVERT_SMI_ARG_CHECKED(argument_count, 2);
+  return *NewStrictArguments(isolate, callee, parameters, argument_count);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewClosureFromStubFailure) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
+  Handle<Context> context(isolate->context());
+  PretenureFlag pretenure_flag = NOT_TENURED;
+  return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
+                                                                pretenure_flag);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewClosure) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
+  CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
+  CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
+
+  // The caller ensures that we pretenure closures that are assigned
+  // directly to properties.
+  PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
+  return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
+                                                                pretenure_flag);
+}
+
+static Object* FindNameClash(Handle<ScopeInfo> scope_info,
+                             Handle<GlobalObject> global_object,
+                             Handle<ScriptContextTable> script_context) {
+  Isolate* isolate = scope_info->GetIsolate();
+  for (int var = 0; var < scope_info->ContextLocalCount(); var++) {
+    Handle<String> name(scope_info->ContextLocalName(var));
+    VariableMode mode = scope_info->ContextLocalMode(var);
+    ScriptContextTable::LookupResult lookup;
+    if (ScriptContextTable::Lookup(script_context, name, &lookup)) {
+      if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(lookup.mode)) {
+        return ThrowRedeclarationError(isolate, name);
+      }
+    }
+
+    if (IsLexicalVariableMode(mode)) {
+      LookupIterator it(global_object, name,
+                        LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
+      Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
+      if (!maybe.has_value) return isolate->heap()->exception();
+      if ((maybe.value & DONT_DELETE) != 0) {
+        return ThrowRedeclarationError(isolate, name);
+      }
+
+      GlobalObject::InvalidatePropertyCell(global_object, name);
+    }
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewScriptContext) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+  CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
+  Handle<GlobalObject> global_object(function->context()->global_object());
+  Handle<Context> native_context(global_object->native_context());
+  Handle<ScriptContextTable> script_context_table(
+      native_context->script_context_table());
+
+  Handle<String> clashed_name;
+  Object* name_clash_result =
+      FindNameClash(scope_info, global_object, script_context_table);
+  if (isolate->has_pending_exception()) return name_clash_result;
+
+  Handle<Context> result =
+      isolate->factory()->NewScriptContext(function, scope_info);
+
+  DCHECK(function->context() == isolate->context());
+  DCHECK(function->context()->global_object() == result->global_object());
+
+  Handle<ScriptContextTable> new_script_context_table =
+      ScriptContextTable::Extend(script_context_table, result);
+  native_context->set_script_context_table(*new_script_context_table);
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+
+  DCHECK(function->context() == isolate->context());
+  int length = function->shared()->scope_info()->ContextLength();
+  return *isolate->factory()->NewFunctionContext(length, function);
+}
+
+
+RUNTIME_FUNCTION(Runtime_PushWithContext) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  Handle<JSReceiver> extension_object;
+  if (args[0]->IsJSReceiver()) {
+    extension_object = args.at<JSReceiver>(0);
+  } else {
+    // Try to convert the object to a proper JavaScript object.
+    MaybeHandle<JSReceiver> maybe_object =
+        Object::ToObject(isolate, args.at<Object>(0));
+    if (!maybe_object.ToHandle(&extension_object)) {
+      Handle<Object> handle = args.at<Object>(0);
+      THROW_NEW_ERROR_RETURN_FAILURE(
+          isolate, NewTypeError("with_expression", HandleVector(&handle, 1)));
+    }
+  }
+
+  Handle<JSFunction> function;
+  if (args[1]->IsSmi()) {
+    // A smi sentinel indicates a context nested inside global code rather
+    // than some function.  There is a canonical empty function that can be
+    // gotten from the native context.
+    function = handle(isolate->native_context()->closure());
+  } else {
+    function = args.at<JSFunction>(1);
+  }
+
+  Handle<Context> current(isolate->context());
+  Handle<Context> context =
+      isolate->factory()->NewWithContext(function, current, extension_object);
+  isolate->set_context(*context);
+  return *context;
+}
+
+
+RUNTIME_FUNCTION(Runtime_PushCatchContext) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 1);
+  Handle<JSFunction> function;
+  if (args[2]->IsSmi()) {
+    // A smi sentinel indicates a context nested inside global code rather
+    // than some function.  There is a canonical empty function that can be
+    // gotten from the native context.
+    function = handle(isolate->native_context()->closure());
+  } else {
+    function = args.at<JSFunction>(2);
+  }
+  Handle<Context> current(isolate->context());
+  Handle<Context> context = isolate->factory()->NewCatchContext(
+      function, current, name, thrown_object);
+  isolate->set_context(*context);
+  return *context;
+}
+
+
+RUNTIME_FUNCTION(Runtime_PushBlockContext) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
+  Handle<JSFunction> function;
+  if (args[1]->IsSmi()) {
+    // A smi sentinel indicates a context nested inside global code rather
+    // than some function.  There is a canonical empty function that can be
+    // gotten from the native context.
+    function = handle(isolate->native_context()->closure());
+  } else {
+    function = args.at<JSFunction>(1);
+  }
+  Handle<Context> current(isolate->context());
+  Handle<Context> context =
+      isolate->factory()->NewBlockContext(function, current, scope_info);
+  isolate->set_context(*context);
+  return *context;
+}
+
+
+RUNTIME_FUNCTION(Runtime_IsJSModule) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  return isolate->heap()->ToBoolean(obj->IsJSModule());
+}
+
+
+RUNTIME_FUNCTION(Runtime_PushModuleContext) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_SMI_ARG_CHECKED(index, 0);
+
+  if (!args[1]->IsScopeInfo()) {
+    // Module already initialized. Find hosting context and retrieve context.
+    Context* host = Context::cast(isolate->context())->script_context();
+    Context* context = Context::cast(host->get(index));
+    DCHECK(context->previous() == isolate->context());
+    isolate->set_context(context);
+    return context;
+  }
+
+  CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
+
+  // Allocate module context.
+  HandleScope scope(isolate);
+  Factory* factory = isolate->factory();
+  Handle<Context> context = factory->NewModuleContext(scope_info);
+  Handle<JSModule> module = factory->NewJSModule(context, scope_info);
+  context->set_module(*module);
+  Context* previous = isolate->context();
+  context->set_previous(previous);
+  context->set_closure(previous->closure());
+  context->set_global_object(previous->global_object());
+  isolate->set_context(*context);
+
+  // Find hosting scope and initialize internal variable holding module there.
+  previous->script_context()->set(index, *context);
+
+  return *context;
+}
+
+
+RUNTIME_FUNCTION(Runtime_DeclareModules) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0);
+  Context* host_context = isolate->context();
+
+  for (int i = 0; i < descriptions->length(); ++i) {
+    Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i)));
+    int host_index = description->host_index();
+    Handle<Context> context(Context::cast(host_context->get(host_index)));
+    Handle<JSModule> module(context->module());
+
+    for (int j = 0; j < description->length(); ++j) {
+      Handle<String> name(description->name(j));
+      VariableMode mode = description->mode(j);
+      int index = description->index(j);
+      switch (mode) {
+        case VAR:
+        case LET:
+        case CONST:
+        case CONST_LEGACY: {
+          PropertyAttributes attr =
+              IsImmutableVariableMode(mode) ? FROZEN : SEALED;
+          Handle<AccessorInfo> info =
+              Accessors::MakeModuleExport(name, index, attr);
+          Handle<Object> result =
+              JSObject::SetAccessor(module, info).ToHandleChecked();
+          DCHECK(!result->IsUndefined());
+          USE(result);
+          break;
+        }
+        case MODULE: {
+          Object* referenced_context = Context::cast(host_context)->get(index);
+          Handle<JSModule> value(Context::cast(referenced_context)->module());
+          JSObject::SetOwnPropertyIgnoreAttributes(module, name, value, FROZEN)
+              .Assert();
+          break;
+        }
+        case INTERNAL:
+        case TEMPORARY:
+        case DYNAMIC:
+        case DYNAMIC_GLOBAL:
+        case DYNAMIC_LOCAL:
+          UNREACHABLE();
+      }
+    }
+
+    JSObject::PreventExtensions(module).Assert();
+  }
+
+  DCHECK(!isolate->has_pending_exception());
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
+
+  int index;
+  PropertyAttributes attributes;
+  ContextLookupFlags flags = FOLLOW_CHAINS;
+  BindingFlags binding_flags;
+  Handle<Object> holder =
+      context->Lookup(name, flags, &index, &attributes, &binding_flags);
+
+  // If the slot was not found the result is true.
+  if (holder.is_null()) {
+    return isolate->heap()->true_value();
+  }
+
+  // If the slot was found in a context, it should be DONT_DELETE.
+  if (holder->IsContext()) {
+    return isolate->heap()->false_value();
+  }
+
+  // The slot was found in a JSObject, either a context extension object,
+  // the global object, or the subject of a with.  Try to delete it
+  // (respecting DONT_DELETE).
+  Handle<JSObject> object = Handle<JSObject>::cast(holder);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     JSReceiver::DeleteProperty(object, name));
+  return *result;
+}
+
+
+static Object* ComputeReceiverForNonGlobal(Isolate* isolate, JSObject* holder) {
+  DCHECK(!holder->IsGlobalObject());
+  Context* top = isolate->context();
+  // Get the context extension function.
+  JSFunction* context_extension_function =
+      top->native_context()->context_extension_function();
+  // If the holder isn't a context extension object, we just return it
+  // as the receiver. This allows arguments objects to be used as
+  // receivers, but only if they are put in the context scope chain
+  // explicitly via a with-statement.
+  Object* constructor = holder->map()->constructor();
+  if (constructor != context_extension_function) return holder;
+  // Fall back to using the global object as the implicit receiver if
+  // the property turns out to be a local variable allocated in a
+  // context extension object - introduced via eval.
+  return isolate->heap()->undefined_value();
+}
+
+
+static ObjectPair LoadLookupSlotHelper(Arguments args, Isolate* isolate,
+                                       bool throw_error) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(2, args.length());
+
+  if (!args[0]->IsContext() || !args[1]->IsString()) {
+    return MakePair(isolate->ThrowIllegalOperation(), NULL);
+  }
+  Handle<Context> context = args.at<Context>(0);
+  Handle<String> name = args.at<String>(1);
+
+  int index;
+  PropertyAttributes attributes;
+  ContextLookupFlags flags = FOLLOW_CHAINS;
+  BindingFlags binding_flags;
+  Handle<Object> holder =
+      context->Lookup(name, flags, &index, &attributes, &binding_flags);
+  if (isolate->has_pending_exception()) {
+    return MakePair(isolate->heap()->exception(), NULL);
+  }
+
+  // If the index is non-negative, the slot has been found in a context.
+  if (index >= 0) {
+    DCHECK(holder->IsContext());
+    // If the "property" we were looking for is a local variable, the
+    // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
+    Handle<Object> receiver = isolate->factory()->undefined_value();
+    Object* value = Context::cast(*holder)->get(index);
+    // Check for uninitialized bindings.
+    switch (binding_flags) {
+      case MUTABLE_CHECK_INITIALIZED:
+      case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
+        if (value->IsTheHole()) {
+          Handle<Object> error;
+          MaybeHandle<Object> maybe_error =
+              isolate->factory()->NewReferenceError("not_defined",
+                                                    HandleVector(&name, 1));
+          if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
+          return MakePair(isolate->heap()->exception(), NULL);
+        }
+      // FALLTHROUGH
+      case MUTABLE_IS_INITIALIZED:
+      case IMMUTABLE_IS_INITIALIZED:
+      case IMMUTABLE_IS_INITIALIZED_HARMONY:
+        DCHECK(!value->IsTheHole());
+        return MakePair(value, *receiver);
+      case IMMUTABLE_CHECK_INITIALIZED:
+        if (value->IsTheHole()) {
+          DCHECK((attributes & READ_ONLY) != 0);
+          value = isolate->heap()->undefined_value();
+        }
+        return MakePair(value, *receiver);
+      case MISSING_BINDING:
+        UNREACHABLE();
+        return MakePair(NULL, NULL);
+    }
+  }
+
+  // Otherwise, if the slot was found the holder is a context extension
+  // object, subject of a with, or a global object.  We read the named
+  // property from it.
+  if (!holder.is_null()) {
+    Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
+#ifdef DEBUG
+    if (!object->IsJSProxy()) {
+      Maybe<bool> maybe = JSReceiver::HasProperty(object, name);
+      DCHECK(maybe.has_value);
+      DCHECK(maybe.value);
+    }
+#endif
+    // GetProperty below can cause GC.
+    Handle<Object> receiver_handle(
+        object->IsGlobalObject()
+            ? Object::cast(isolate->heap()->undefined_value())
+            : object->IsJSProxy() ? static_cast<Object*>(*object)
+                                  : ComputeReceiverForNonGlobal(
+                                        isolate, JSObject::cast(*object)),
+        isolate);
+
+    // No need to unhole the value here.  This is taken care of by the
+    // GetProperty function.
+    Handle<Object> value;
+    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+        isolate, value, Object::GetProperty(object, name),
+        MakePair(isolate->heap()->exception(), NULL));
+    return MakePair(*value, *receiver_handle);
+  }
+
+  if (throw_error) {
+    // The property doesn't exist - throw exception.
+    Handle<Object> error;
+    MaybeHandle<Object> maybe_error = isolate->factory()->NewReferenceError(
+        "not_defined", HandleVector(&name, 1));
+    if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
+    return MakePair(isolate->heap()->exception(), NULL);
+  } else {
+    // The property doesn't exist - return undefined.
+    return MakePair(isolate->heap()->undefined_value(),
+                    isolate->heap()->undefined_value());
+  }
+}
+
+
+RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlot) {
+  return LoadLookupSlotHelper(args, isolate, true);
+}
+
+
+RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotNoReferenceError) {
+  return LoadLookupSlotHelper(args, isolate, false);
+}
+
+
+RUNTIME_FUNCTION(Runtime_StoreLookupSlot) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+
+  CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
+  CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 3);
+
+  int index;
+  PropertyAttributes attributes;
+  ContextLookupFlags flags = FOLLOW_CHAINS;
+  BindingFlags binding_flags;
+  Handle<Object> holder =
+      context->Lookup(name, flags, &index, &attributes, &binding_flags);
+  // In case of JSProxy, an exception might have been thrown.
+  if (isolate->has_pending_exception()) return isolate->heap()->exception();
+
+  // The property was found in a context slot.
+  if (index >= 0) {
+    if ((attributes & READ_ONLY) == 0) {
+      Handle<Context>::cast(holder)->set(index, *value);
+    } else if (strict_mode == STRICT) {
+      // Setting read only property in strict mode.
+      THROW_NEW_ERROR_RETURN_FAILURE(
+          isolate,
+          NewTypeError("strict_cannot_assign", HandleVector(&name, 1)));
+    }
+    return *value;
+  }
+
+  // Slow case: The property is not in a context slot.  It is either in a
+  // context extension object, a property of the subject of a with, or a
+  // property of the global object.
+  Handle<JSReceiver> object;
+  if (attributes != ABSENT) {
+    // The property exists on the holder.
+    object = Handle<JSReceiver>::cast(holder);
+  } else if (strict_mode == STRICT) {
+    // If absent in strict mode: throw.
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewReferenceError("not_defined", HandleVector(&name, 1)));
+  } else {
+    // If absent in sloppy mode: add the property to the global object.
+    object = Handle<JSReceiver>(context->global_object());
+  }
+
+  RETURN_FAILURE_ON_EXCEPTION(
+      isolate, Object::SetProperty(object, name, value, strict_mode));
+
+  return *value;
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetArgumentsProperty) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, raw_key, 0);
+
+  // Compute the frame holding the arguments.
+  JavaScriptFrameIterator it(isolate);
+  it.AdvanceToArgumentsFrame();
+  JavaScriptFrame* frame = it.frame();
+
+  // Get the actual number of provided arguments.
+  const uint32_t n = frame->ComputeParametersCount();
+
+  // Try to convert the key to an index. If successful and within
+  // index return the the argument from the frame.
+  uint32_t index;
+  if (raw_key->ToArrayIndex(&index) && index < n) {
+    return frame->GetParameter(index);
+  }
+
+  HandleScope scope(isolate);
+  if (raw_key->IsSymbol()) {
+    Handle<Symbol> symbol = Handle<Symbol>::cast(raw_key);
+    if (Name::Equals(symbol, isolate->factory()->iterator_symbol())) {
+      return isolate->native_context()->array_values_iterator();
+    }
+    // Lookup in the initial Object.prototype object.
+    Handle<Object> result;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, result,
+        Object::GetProperty(isolate->initial_object_prototype(),
+                            Handle<Symbol>::cast(raw_key)));
+    return *result;
+  }
+
+  // Convert the key to a string.
+  Handle<Object> converted;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, converted,
+                                     Execution::ToString(isolate, raw_key));
+  Handle<String> key = Handle<String>::cast(converted);
+
+  // Try to convert the string key into an array index.
+  if (key->AsArrayIndex(&index)) {
+    if (index < n) {
+      return frame->GetParameter(index);
+    } else {
+      Handle<Object> initial_prototype(isolate->initial_object_prototype());
+      Handle<Object> result;
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+          isolate, result,
+          Object::GetElement(isolate, initial_prototype, index));
+      return *result;
+    }
+  }
+
+  // Handle special arguments properties.
+  if (String::Equals(isolate->factory()->length_string(), key)) {
+    return Smi::FromInt(n);
+  }
+  if (String::Equals(isolate->factory()->callee_string(), key)) {
+    JSFunction* function = frame->function();
+    if (function->shared()->strict_mode() == STRICT) {
+      THROW_NEW_ERROR_RETURN_FAILURE(
+          isolate, NewTypeError("strict_arguments_callee",
+                                HandleVector<Object>(NULL, 0)));
+    }
+    return function;
+  }
+
+  // Lookup in the initial Object.prototype object.
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Object::GetProperty(isolate->initial_object_prototype(), key));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_ArgumentsLength) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  JavaScriptFrameIterator it(isolate);
+  JavaScriptFrame* frame = it.frame();
+  return Smi::FromInt(frame->GetArgumentsLength());
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_Arguments) {
+  SealHandleScope shs(isolate);
+  return __RT_impl_Runtime_GetArgumentsProperty(args, isolate);
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-strings.cc b/src/runtime/runtime-strings.cc
new file mode 100644
index 0000000..df2210c
--- /dev/null
+++ b/src/runtime/runtime-strings.cc
@@ -0,0 +1,1305 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/jsregexp-inl.h"
+#include "src/jsregexp.h"
+#include "src/runtime/runtime-utils.h"
+#include "src/string-builder.h"
+#include "src/string-search.h"
+
+namespace v8 {
+namespace internal {
+
+
+// Perform string match of pattern on subject, starting at start index.
+// Caller must ensure that 0 <= start_index <= sub->length(),
+// and should check that pat->length() + start_index <= sub->length().
+int StringMatch(Isolate* isolate, Handle<String> sub, Handle<String> pat,
+                int start_index) {
+  DCHECK(0 <= start_index);
+  DCHECK(start_index <= sub->length());
+
+  int pattern_length = pat->length();
+  if (pattern_length == 0) return start_index;
+
+  int subject_length = sub->length();
+  if (start_index + pattern_length > subject_length) return -1;
+
+  sub = String::Flatten(sub);
+  pat = String::Flatten(pat);
+
+  DisallowHeapAllocation no_gc;  // ensure vectors stay valid
+  // Extract flattened substrings of cons strings before getting encoding.
+  String::FlatContent seq_sub = sub->GetFlatContent();
+  String::FlatContent seq_pat = pat->GetFlatContent();
+
+  // dispatch on type of strings
+  if (seq_pat.IsOneByte()) {
+    Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector();
+    if (seq_sub.IsOneByte()) {
+      return SearchString(isolate, seq_sub.ToOneByteVector(), pat_vector,
+                          start_index);
+    }
+    return SearchString(isolate, seq_sub.ToUC16Vector(), pat_vector,
+                        start_index);
+  }
+  Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
+  if (seq_sub.IsOneByte()) {
+    return SearchString(isolate, seq_sub.ToOneByteVector(), pat_vector,
+                        start_index);
+  }
+  return SearchString(isolate, seq_sub.ToUC16Vector(), pat_vector, start_index);
+}
+
+
+// This may return an empty MaybeHandle if an exception is thrown or
+// we abort due to reaching the recursion limit.
+MaybeHandle<String> StringReplaceOneCharWithString(
+    Isolate* isolate, Handle<String> subject, Handle<String> search,
+    Handle<String> replace, bool* found, int recursion_limit) {
+  StackLimitCheck stackLimitCheck(isolate);
+  if (stackLimitCheck.HasOverflowed() || (recursion_limit == 0)) {
+    return MaybeHandle<String>();
+  }
+  recursion_limit--;
+  if (subject->IsConsString()) {
+    ConsString* cons = ConsString::cast(*subject);
+    Handle<String> first = Handle<String>(cons->first());
+    Handle<String> second = Handle<String>(cons->second());
+    Handle<String> new_first;
+    if (!StringReplaceOneCharWithString(isolate, first, search, replace, found,
+                                        recursion_limit).ToHandle(&new_first)) {
+      return MaybeHandle<String>();
+    }
+    if (*found) return isolate->factory()->NewConsString(new_first, second);
+
+    Handle<String> new_second;
+    if (!StringReplaceOneCharWithString(isolate, second, search, replace, found,
+                                        recursion_limit)
+             .ToHandle(&new_second)) {
+      return MaybeHandle<String>();
+    }
+    if (*found) return isolate->factory()->NewConsString(first, new_second);
+
+    return subject;
+  } else {
+    int index = StringMatch(isolate, subject, search, 0);
+    if (index == -1) return subject;
+    *found = true;
+    Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
+    Handle<String> cons1;
+    ASSIGN_RETURN_ON_EXCEPTION(
+        isolate, cons1, isolate->factory()->NewConsString(first, replace),
+        String);
+    Handle<String> second =
+        isolate->factory()->NewSubString(subject, index + 1, subject->length());
+    return isolate->factory()->NewConsString(cons1, second);
+  }
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringReplaceOneCharWithString) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
+
+  // If the cons string tree is too deep, we simply abort the recursion and
+  // retry with a flattened subject string.
+  const int kRecursionLimit = 0x1000;
+  bool found = false;
+  Handle<String> result;
+  if (StringReplaceOneCharWithString(isolate, subject, search, replace, &found,
+                                     kRecursionLimit).ToHandle(&result)) {
+    return *result;
+  }
+  if (isolate->has_pending_exception()) return isolate->heap()->exception();
+
+  subject = String::Flatten(subject);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      StringReplaceOneCharWithString(isolate, subject, search, replace, &found,
+                                     kRecursionLimit));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringIndexOf) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, index, 2);
+
+  uint32_t start_index;
+  if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
+
+  RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
+  int position = StringMatch(isolate, sub, pat, start_index);
+  return Smi::FromInt(position);
+}
+
+
+template <typename schar, typename pchar>
+static int StringMatchBackwards(Vector<const schar> subject,
+                                Vector<const pchar> pattern, int idx) {
+  int pattern_length = pattern.length();
+  DCHECK(pattern_length >= 1);
+  DCHECK(idx + pattern_length <= subject.length());
+
+  if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
+    for (int i = 0; i < pattern_length; i++) {
+      uc16 c = pattern[i];
+      if (c > String::kMaxOneByteCharCode) {
+        return -1;
+      }
+    }
+  }
+
+  pchar pattern_first_char = pattern[0];
+  for (int i = idx; i >= 0; i--) {
+    if (subject[i] != pattern_first_char) continue;
+    int j = 1;
+    while (j < pattern_length) {
+      if (pattern[j] != subject[i + j]) {
+        break;
+      }
+      j++;
+    }
+    if (j == pattern_length) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringLastIndexOf) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, index, 2);
+
+  uint32_t start_index;
+  if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
+
+  uint32_t pat_length = pat->length();
+  uint32_t sub_length = sub->length();
+
+  if (start_index + pat_length > sub_length) {
+    start_index = sub_length - pat_length;
+  }
+
+  if (pat_length == 0) {
+    return Smi::FromInt(start_index);
+  }
+
+  sub = String::Flatten(sub);
+  pat = String::Flatten(pat);
+
+  int position = -1;
+  DisallowHeapAllocation no_gc;  // ensure vectors stay valid
+
+  String::FlatContent sub_content = sub->GetFlatContent();
+  String::FlatContent pat_content = pat->GetFlatContent();
+
+  if (pat_content.IsOneByte()) {
+    Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector();
+    if (sub_content.IsOneByte()) {
+      position = StringMatchBackwards(sub_content.ToOneByteVector(), pat_vector,
+                                      start_index);
+    } else {
+      position = StringMatchBackwards(sub_content.ToUC16Vector(), pat_vector,
+                                      start_index);
+    }
+  } else {
+    Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
+    if (sub_content.IsOneByte()) {
+      position = StringMatchBackwards(sub_content.ToOneByteVector(), pat_vector,
+                                      start_index);
+    } else {
+      position = StringMatchBackwards(sub_content.ToUC16Vector(), pat_vector,
+                                      start_index);
+    }
+  }
+
+  return Smi::FromInt(position);
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringLocaleCompare) {
+  HandleScope handle_scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, str1, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, str2, 1);
+
+  if (str1.is_identical_to(str2)) return Smi::FromInt(0);  // Equal.
+  int str1_length = str1->length();
+  int str2_length = str2->length();
+
+  // Decide trivial cases without flattening.
+  if (str1_length == 0) {
+    if (str2_length == 0) return Smi::FromInt(0);  // Equal.
+    return Smi::FromInt(-str2_length);
+  } else {
+    if (str2_length == 0) return Smi::FromInt(str1_length);
+  }
+
+  int end = str1_length < str2_length ? str1_length : str2_length;
+
+  // No need to flatten if we are going to find the answer on the first
+  // character.  At this point we know there is at least one character
+  // in each string, due to the trivial case handling above.
+  int d = str1->Get(0) - str2->Get(0);
+  if (d != 0) return Smi::FromInt(d);
+
+  str1 = String::Flatten(str1);
+  str2 = String::Flatten(str2);
+
+  DisallowHeapAllocation no_gc;
+  String::FlatContent flat1 = str1->GetFlatContent();
+  String::FlatContent flat2 = str2->GetFlatContent();
+
+  for (int i = 0; i < end; i++) {
+    if (flat1.Get(i) != flat2.Get(i)) {
+      return Smi::FromInt(flat1.Get(i) - flat2.Get(i));
+    }
+  }
+
+  return Smi::FromInt(str1_length - str2_length);
+}
+
+
+RUNTIME_FUNCTION(Runtime_SubString) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
+  int start, end;
+  // We have a fast integer-only case here to avoid a conversion to double in
+  // the common case where from and to are Smis.
+  if (args[1]->IsSmi() && args[2]->IsSmi()) {
+    CONVERT_SMI_ARG_CHECKED(from_number, 1);
+    CONVERT_SMI_ARG_CHECKED(to_number, 2);
+    start = from_number;
+    end = to_number;
+  } else {
+    CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
+    CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
+    start = FastD2IChecked(from_number);
+    end = FastD2IChecked(to_number);
+  }
+  RUNTIME_ASSERT(end >= start);
+  RUNTIME_ASSERT(start >= 0);
+  RUNTIME_ASSERT(end <= string->length());
+  isolate->counters()->sub_string_runtime()->Increment();
+
+  return *isolate->factory()->NewSubString(string, start, end);
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringAdd) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(String, str1, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, str2, 1);
+  isolate->counters()->string_add_runtime()->Increment();
+  Handle<String> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, isolate->factory()->NewConsString(str1, str2));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_InternalizeString) {
+  HandleScope handles(isolate);
+  RUNTIME_ASSERT(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
+  return *isolate->factory()->InternalizeString(string);
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringMatch) {
+  HandleScope handles(isolate);
+  DCHECK(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
+
+  RUNTIME_ASSERT(regexp_info->HasFastObjectElements());
+
+  RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
+  if (global_cache.HasException()) return isolate->heap()->exception();
+
+  int capture_count = regexp->CaptureCount();
+
+  ZoneScope zone_scope(isolate->runtime_zone());
+  ZoneList<int> offsets(8, zone_scope.zone());
+
+  while (true) {
+    int32_t* match = global_cache.FetchNext();
+    if (match == NULL) break;
+    offsets.Add(match[0], zone_scope.zone());  // start
+    offsets.Add(match[1], zone_scope.zone());  // end
+  }
+
+  if (global_cache.HasException()) return isolate->heap()->exception();
+
+  if (offsets.length() == 0) {
+    // Not a single match.
+    return isolate->heap()->null_value();
+  }
+
+  RegExpImpl::SetLastMatchInfo(regexp_info, subject, capture_count,
+                               global_cache.LastSuccessfulMatch());
+
+  int matches = offsets.length() / 2;
+  Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
+  Handle<String> substring =
+      isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1));
+  elements->set(0, *substring);
+  for (int i = 1; i < matches; i++) {
+    HandleScope temp_scope(isolate);
+    int from = offsets.at(i * 2);
+    int to = offsets.at(i * 2 + 1);
+    Handle<String> substring =
+        isolate->factory()->NewProperSubString(subject, from, to);
+    elements->set(i, *substring);
+  }
+  Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
+  result->set_length(Smi::FromInt(matches));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringCharCodeAtRT) {
+  HandleScope handle_scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
+  CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]);
+
+  // Flatten the string.  If someone wants to get a char at an index
+  // in a cons string, it is likely that more indices will be
+  // accessed.
+  subject = String::Flatten(subject);
+
+  if (i >= static_cast<uint32_t>(subject->length())) {
+    return isolate->heap()->nan_value();
+  }
+
+  return Smi::FromInt(subject->Get(i));
+}
+
+
+RUNTIME_FUNCTION(Runtime_CharFromCode) {
+  HandleScope handlescope(isolate);
+  DCHECK(args.length() == 1);
+  if (args[0]->IsNumber()) {
+    CONVERT_NUMBER_CHECKED(uint32_t, code, Uint32, args[0]);
+    code &= 0xffff;
+    return *isolate->factory()->LookupSingleCharacterStringFromCode(code);
+  }
+  return isolate->heap()->empty_string();
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringCompare) {
+  HandleScope handle_scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
+
+  isolate->counters()->string_compare_runtime()->Increment();
+
+  // A few fast case tests before we flatten.
+  if (x.is_identical_to(y)) return Smi::FromInt(EQUAL);
+  if (y->length() == 0) {
+    if (x->length() == 0) return Smi::FromInt(EQUAL);
+    return Smi::FromInt(GREATER);
+  } else if (x->length() == 0) {
+    return Smi::FromInt(LESS);
+  }
+
+  int d = x->Get(0) - y->Get(0);
+  if (d < 0)
+    return Smi::FromInt(LESS);
+  else if (d > 0)
+    return Smi::FromInt(GREATER);
+
+  // Slow case.
+  x = String::Flatten(x);
+  y = String::Flatten(y);
+
+  DisallowHeapAllocation no_gc;
+  Object* equal_prefix_result = Smi::FromInt(EQUAL);
+  int prefix_length = x->length();
+  if (y->length() < prefix_length) {
+    prefix_length = y->length();
+    equal_prefix_result = Smi::FromInt(GREATER);
+  } else if (y->length() > prefix_length) {
+    equal_prefix_result = Smi::FromInt(LESS);
+  }
+  int r;
+  String::FlatContent x_content = x->GetFlatContent();
+  String::FlatContent y_content = y->GetFlatContent();
+  if (x_content.IsOneByte()) {
+    Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
+    if (y_content.IsOneByte()) {
+      Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
+      r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+    } else {
+      Vector<const uc16> y_chars = y_content.ToUC16Vector();
+      r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+    }
+  } else {
+    Vector<const uc16> x_chars = x_content.ToUC16Vector();
+    if (y_content.IsOneByte()) {
+      Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
+      r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+    } else {
+      Vector<const uc16> y_chars = y_content.ToUC16Vector();
+      r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+    }
+  }
+  Object* result;
+  if (r == 0) {
+    result = equal_prefix_result;
+  } else {
+    result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
+  }
+  return result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringBuilderConcat) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
+  int32_t array_length;
+  if (!args[1]->ToInt32(&array_length)) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
+  }
+  CONVERT_ARG_HANDLE_CHECKED(String, special, 2);
+
+  size_t actual_array_length = 0;
+  RUNTIME_ASSERT(
+      TryNumberToSize(isolate, array->length(), &actual_array_length));
+  RUNTIME_ASSERT(array_length >= 0);
+  RUNTIME_ASSERT(static_cast<size_t>(array_length) <= actual_array_length);
+
+  // This assumption is used by the slice encoding in one or two smis.
+  DCHECK(Smi::kMaxValue >= String::kMaxLength);
+
+  RUNTIME_ASSERT(array->HasFastElements());
+  JSObject::EnsureCanContainHeapObjectElements(array);
+
+  int special_length = special->length();
+  if (!array->HasFastObjectElements()) {
+    return isolate->Throw(isolate->heap()->illegal_argument_string());
+  }
+
+  int length;
+  bool one_byte = special->HasOnlyOneByteChars();
+
+  {
+    DisallowHeapAllocation no_gc;
+    FixedArray* fixed_array = FixedArray::cast(array->elements());
+    if (fixed_array->length() < array_length) {
+      array_length = fixed_array->length();
+    }
+
+    if (array_length == 0) {
+      return isolate->heap()->empty_string();
+    } else if (array_length == 1) {
+      Object* first = fixed_array->get(0);
+      if (first->IsString()) return first;
+    }
+    length = StringBuilderConcatLength(special_length, fixed_array,
+                                       array_length, &one_byte);
+  }
+
+  if (length == -1) {
+    return isolate->Throw(isolate->heap()->illegal_argument_string());
+  }
+
+  if (one_byte) {
+    Handle<SeqOneByteString> answer;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, answer, isolate->factory()->NewRawOneByteString(length));
+    StringBuilderConcatHelper(*special, answer->GetChars(),
+                              FixedArray::cast(array->elements()),
+                              array_length);
+    return *answer;
+  } else {
+    Handle<SeqTwoByteString> answer;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, answer, isolate->factory()->NewRawTwoByteString(length));
+    StringBuilderConcatHelper(*special, answer->GetChars(),
+                              FixedArray::cast(array->elements()),
+                              array_length);
+    return *answer;
+  }
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringBuilderJoin) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
+  int32_t array_length;
+  if (!args[1]->ToInt32(&array_length)) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
+  }
+  CONVERT_ARG_HANDLE_CHECKED(String, separator, 2);
+  RUNTIME_ASSERT(array->HasFastObjectElements());
+  RUNTIME_ASSERT(array_length >= 0);
+
+  Handle<FixedArray> fixed_array(FixedArray::cast(array->elements()));
+  if (fixed_array->length() < array_length) {
+    array_length = fixed_array->length();
+  }
+
+  if (array_length == 0) {
+    return isolate->heap()->empty_string();
+  } else if (array_length == 1) {
+    Object* first = fixed_array->get(0);
+    RUNTIME_ASSERT(first->IsString());
+    return first;
+  }
+
+  int separator_length = separator->length();
+  RUNTIME_ASSERT(separator_length > 0);
+  int max_nof_separators =
+      (String::kMaxLength + separator_length - 1) / separator_length;
+  if (max_nof_separators < (array_length - 1)) {
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
+  }
+  int length = (array_length - 1) * separator_length;
+  for (int i = 0; i < array_length; i++) {
+    Object* element_obj = fixed_array->get(i);
+    RUNTIME_ASSERT(element_obj->IsString());
+    String* element = String::cast(element_obj);
+    int increment = element->length();
+    if (increment > String::kMaxLength - length) {
+      STATIC_ASSERT(String::kMaxLength < kMaxInt);
+      length = kMaxInt;  // Provoke exception;
+      break;
+    }
+    length += increment;
+  }
+
+  Handle<SeqTwoByteString> answer;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, answer, isolate->factory()->NewRawTwoByteString(length));
+
+  DisallowHeapAllocation no_gc;
+
+  uc16* sink = answer->GetChars();
+#ifdef DEBUG
+  uc16* end = sink + length;
+#endif
+
+  RUNTIME_ASSERT(fixed_array->get(0)->IsString());
+  String* first = String::cast(fixed_array->get(0));
+  String* separator_raw = *separator;
+  int first_length = first->length();
+  String::WriteToFlat(first, sink, 0, first_length);
+  sink += first_length;
+
+  for (int i = 1; i < array_length; i++) {
+    DCHECK(sink + separator_length <= end);
+    String::WriteToFlat(separator_raw, sink, 0, separator_length);
+    sink += separator_length;
+
+    RUNTIME_ASSERT(fixed_array->get(i)->IsString());
+    String* element = String::cast(fixed_array->get(i));
+    int element_length = element->length();
+    DCHECK(sink + element_length <= end);
+    String::WriteToFlat(element, sink, 0, element_length);
+    sink += element_length;
+  }
+  DCHECK(sink == end);
+
+  // Use %_FastOneByteArrayJoin instead.
+  DCHECK(!answer->IsOneByteRepresentation());
+  return *answer;
+}
+
+template <typename Char>
+static void JoinSparseArrayWithSeparator(FixedArray* elements,
+                                         int elements_length,
+                                         uint32_t array_length,
+                                         String* separator,
+                                         Vector<Char> buffer) {
+  DisallowHeapAllocation no_gc;
+  int previous_separator_position = 0;
+  int separator_length = separator->length();
+  int cursor = 0;
+  for (int i = 0; i < elements_length; i += 2) {
+    int position = NumberToInt32(elements->get(i));
+    String* string = String::cast(elements->get(i + 1));
+    int string_length = string->length();
+    if (string->length() > 0) {
+      while (previous_separator_position < position) {
+        String::WriteToFlat<Char>(separator, &buffer[cursor], 0,
+                                  separator_length);
+        cursor += separator_length;
+        previous_separator_position++;
+      }
+      String::WriteToFlat<Char>(string, &buffer[cursor], 0, string_length);
+      cursor += string->length();
+    }
+  }
+  if (separator_length > 0) {
+    // Array length must be representable as a signed 32-bit number,
+    // otherwise the total string length would have been too large.
+    DCHECK(array_length <= 0x7fffffff);  // Is int32_t.
+    int last_array_index = static_cast<int>(array_length - 1);
+    while (previous_separator_position < last_array_index) {
+      String::WriteToFlat<Char>(separator, &buffer[cursor], 0,
+                                separator_length);
+      cursor += separator_length;
+      previous_separator_position++;
+    }
+  }
+  DCHECK(cursor <= buffer.length());
+}
+
+
+RUNTIME_FUNCTION(Runtime_SparseJoinWithSeparator) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSArray, elements_array, 0);
+  CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
+  CONVERT_ARG_HANDLE_CHECKED(String, separator, 2);
+  // elements_array is fast-mode JSarray of alternating positions
+  // (increasing order) and strings.
+  RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements());
+  // array_length is length of original array (used to add separators);
+  // separator is string to put between elements. Assumed to be non-empty.
+  RUNTIME_ASSERT(array_length > 0);
+
+  // Find total length of join result.
+  int string_length = 0;
+  bool is_one_byte = separator->IsOneByteRepresentation();
+  bool overflow = false;
+  CONVERT_NUMBER_CHECKED(int, elements_length, Int32, elements_array->length());
+  RUNTIME_ASSERT(elements_length <= elements_array->elements()->length());
+  RUNTIME_ASSERT((elements_length & 1) == 0);  // Even length.
+  FixedArray* elements = FixedArray::cast(elements_array->elements());
+  for (int i = 0; i < elements_length; i += 2) {
+    RUNTIME_ASSERT(elements->get(i)->IsNumber());
+    CONVERT_NUMBER_CHECKED(uint32_t, position, Uint32, elements->get(i));
+    RUNTIME_ASSERT(position < array_length);
+    RUNTIME_ASSERT(elements->get(i + 1)->IsString());
+  }
+
+  {
+    DisallowHeapAllocation no_gc;
+    for (int i = 0; i < elements_length; i += 2) {
+      String* string = String::cast(elements->get(i + 1));
+      int length = string->length();
+      if (is_one_byte && !string->IsOneByteRepresentation()) {
+        is_one_byte = false;
+      }
+      if (length > String::kMaxLength ||
+          String::kMaxLength - length < string_length) {
+        overflow = true;
+        break;
+      }
+      string_length += length;
+    }
+  }
+
+  int separator_length = separator->length();
+  if (!overflow && separator_length > 0) {
+    if (array_length <= 0x7fffffffu) {
+      int separator_count = static_cast<int>(array_length) - 1;
+      int remaining_length = String::kMaxLength - string_length;
+      if ((remaining_length / separator_length) >= separator_count) {
+        string_length += separator_length * (array_length - 1);
+      } else {
+        // Not room for the separators within the maximal string length.
+        overflow = true;
+      }
+    } else {
+      // Nonempty separator and at least 2^31-1 separators necessary
+      // means that the string is too large to create.
+      STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
+      overflow = true;
+    }
+  }
+  if (overflow) {
+    // Throw an exception if the resulting string is too large. See
+    // https://code.google.com/p/chromium/issues/detail?id=336820
+    // for details.
+    THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
+  }
+
+  if (is_one_byte) {
+    Handle<SeqOneByteString> result = isolate->factory()
+                                          ->NewRawOneByteString(string_length)
+                                          .ToHandleChecked();
+    JoinSparseArrayWithSeparator<uint8_t>(
+        FixedArray::cast(elements_array->elements()), elements_length,
+        array_length, *separator,
+        Vector<uint8_t>(result->GetChars(), string_length));
+    return *result;
+  } else {
+    Handle<SeqTwoByteString> result = isolate->factory()
+                                          ->NewRawTwoByteString(string_length)
+                                          .ToHandleChecked();
+    JoinSparseArrayWithSeparator<uc16>(
+        FixedArray::cast(elements_array->elements()), elements_length,
+        array_length, *separator,
+        Vector<uc16>(result->GetChars(), string_length));
+    return *result;
+  }
+}
+
+
+// Copies Latin1 characters to the given fixed array looking up
+// one-char strings in the cache. Gives up on the first char that is
+// not in the cache and fills the remainder with smi zeros. Returns
+// the length of the successfully copied prefix.
+static int CopyCachedOneByteCharsToArray(Heap* heap, const uint8_t* chars,
+                                         FixedArray* elements, int length) {
+  DisallowHeapAllocation no_gc;
+  FixedArray* one_byte_cache = heap->single_character_string_cache();
+  Object* undefined = heap->undefined_value();
+  int i;
+  WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
+  for (i = 0; i < length; ++i) {
+    Object* value = one_byte_cache->get(chars[i]);
+    if (value == undefined) break;
+    elements->set(i, value, mode);
+  }
+  if (i < length) {
+    DCHECK(Smi::FromInt(0) == 0);
+    memset(elements->data_start() + i, 0, kPointerSize * (length - i));
+  }
+#ifdef DEBUG
+  for (int j = 0; j < length; ++j) {
+    Object* element = elements->get(j);
+    DCHECK(element == Smi::FromInt(0) ||
+           (element->IsString() && String::cast(element)->LooksValid()));
+  }
+#endif
+  return i;
+}
+
+
+// Converts a String to JSArray.
+// For example, "foo" => ["f", "o", "o"].
+RUNTIME_FUNCTION(Runtime_StringToArray) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
+  CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
+
+  s = String::Flatten(s);
+  const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
+
+  Handle<FixedArray> elements;
+  int position = 0;
+  if (s->IsFlat() && s->IsOneByteRepresentation()) {
+    // Try using cached chars where possible.
+    elements = isolate->factory()->NewUninitializedFixedArray(length);
+
+    DisallowHeapAllocation no_gc;
+    String::FlatContent content = s->GetFlatContent();
+    if (content.IsOneByte()) {
+      Vector<const uint8_t> chars = content.ToOneByteVector();
+      // Note, this will initialize all elements (not only the prefix)
+      // to prevent GC from seeing partially initialized array.
+      position = CopyCachedOneByteCharsToArray(isolate->heap(), chars.start(),
+                                               *elements, length);
+    } else {
+      MemsetPointer(elements->data_start(), isolate->heap()->undefined_value(),
+                    length);
+    }
+  } else {
+    elements = isolate->factory()->NewFixedArray(length);
+  }
+  for (int i = position; i < length; ++i) {
+    Handle<Object> str =
+        isolate->factory()->LookupSingleCharacterStringFromCode(s->Get(i));
+    elements->set(i, *str);
+  }
+
+#ifdef DEBUG
+  for (int i = 0; i < length; ++i) {
+    DCHECK(String::cast(elements->get(i))->length() == 1);
+  }
+#endif
+
+  return *isolate->factory()->NewJSArrayWithElements(elements);
+}
+
+
+static inline bool ToUpperOverflows(uc32 character) {
+  // y with umlauts and the micro sign are the only characters that stop
+  // fitting into one-byte when converting to uppercase.
+  static const uc32 yuml_code = 0xff;
+  static const uc32 micro_code = 0xb5;
+  return (character == yuml_code || character == micro_code);
+}
+
+
+template <class Converter>
+MUST_USE_RESULT static Object* ConvertCaseHelper(
+    Isolate* isolate, String* string, SeqString* result, int result_length,
+    unibrow::Mapping<Converter, 128>* mapping) {
+  DisallowHeapAllocation no_gc;
+  // We try this twice, once with the assumption that the result is no longer
+  // than the input and, if that assumption breaks, again with the exact
+  // length.  This may not be pretty, but it is nicer than what was here before
+  // and I hereby claim my vaffel-is.
+  //
+  // NOTE: This assumes that the upper/lower case of an ASCII
+  // character is also ASCII.  This is currently the case, but it
+  // might break in the future if we implement more context and locale
+  // dependent upper/lower conversions.
+  bool has_changed_character = false;
+
+  // Convert all characters to upper case, assuming that they will fit
+  // in the buffer
+  StringCharacterStream stream(string);
+  unibrow::uchar chars[Converter::kMaxWidth];
+  // We can assume that the string is not empty
+  uc32 current = stream.GetNext();
+  bool ignore_overflow = Converter::kIsToLower || result->IsSeqTwoByteString();
+  for (int i = 0; i < result_length;) {
+    bool has_next = stream.HasMore();
+    uc32 next = has_next ? stream.GetNext() : 0;
+    int char_length = mapping->get(current, next, chars);
+    if (char_length == 0) {
+      // The case conversion of this character is the character itself.
+      result->Set(i, current);
+      i++;
+    } else if (char_length == 1 &&
+               (ignore_overflow || !ToUpperOverflows(current))) {
+      // Common case: converting the letter resulted in one character.
+      DCHECK(static_cast<uc32>(chars[0]) != current);
+      result->Set(i, chars[0]);
+      has_changed_character = true;
+      i++;
+    } else if (result_length == string->length()) {
+      bool overflows = ToUpperOverflows(current);
+      // We've assumed that the result would be as long as the
+      // input but here is a character that converts to several
+      // characters.  No matter, we calculate the exact length
+      // of the result and try the whole thing again.
+      //
+      // Note that this leaves room for optimization.  We could just
+      // memcpy what we already have to the result string.  Also,
+      // the result string is the last object allocated we could
+      // "realloc" it and probably, in the vast majority of cases,
+      // extend the existing string to be able to hold the full
+      // result.
+      int next_length = 0;
+      if (has_next) {
+        next_length = mapping->get(next, 0, chars);
+        if (next_length == 0) next_length = 1;
+      }
+      int current_length = i + char_length + next_length;
+      while (stream.HasMore()) {
+        current = stream.GetNext();
+        overflows |= ToUpperOverflows(current);
+        // NOTE: we use 0 as the next character here because, while
+        // the next character may affect what a character converts to,
+        // it does not in any case affect the length of what it convert
+        // to.
+        int char_length = mapping->get(current, 0, chars);
+        if (char_length == 0) char_length = 1;
+        current_length += char_length;
+        if (current_length > String::kMaxLength) {
+          AllowHeapAllocation allocate_error_and_return;
+          THROW_NEW_ERROR_RETURN_FAILURE(isolate,
+                                         NewInvalidStringLengthError());
+        }
+      }
+      // Try again with the real length.  Return signed if we need
+      // to allocate a two-byte string for to uppercase.
+      return (overflows && !ignore_overflow) ? Smi::FromInt(-current_length)
+                                             : Smi::FromInt(current_length);
+    } else {
+      for (int j = 0; j < char_length; j++) {
+        result->Set(i, chars[j]);
+        i++;
+      }
+      has_changed_character = true;
+    }
+    current = next;
+  }
+  if (has_changed_character) {
+    return result;
+  } else {
+    // If we didn't actually change anything in doing the conversion
+    // we simple return the result and let the converted string
+    // become garbage; there is no reason to keep two identical strings
+    // alive.
+    return string;
+  }
+}
+
+
+static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
+static const uintptr_t kAsciiMask = kOneInEveryByte << 7;
+
+// Given a word and two range boundaries returns a word with high bit
+// set in every byte iff the corresponding input byte was strictly in
+// the range (m, n). All the other bits in the result are cleared.
+// This function is only useful when it can be inlined and the
+// boundaries are statically known.
+// Requires: all bytes in the input word and the boundaries must be
+// ASCII (less than 0x7F).
+static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
+  // Use strict inequalities since in edge cases the function could be
+  // further simplified.
+  DCHECK(0 < m && m < n);
+  // Has high bit set in every w byte less than n.
+  uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
+  // Has high bit set in every w byte greater than m.
+  uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
+  return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
+}
+
+
+#ifdef DEBUG
+static bool CheckFastAsciiConvert(char* dst, const char* src, int length,
+                                  bool changed, bool is_to_lower) {
+  bool expected_changed = false;
+  for (int i = 0; i < length; i++) {
+    if (dst[i] == src[i]) continue;
+    expected_changed = true;
+    if (is_to_lower) {
+      DCHECK('A' <= src[i] && src[i] <= 'Z');
+      DCHECK(dst[i] == src[i] + ('a' - 'A'));
+    } else {
+      DCHECK('a' <= src[i] && src[i] <= 'z');
+      DCHECK(dst[i] == src[i] - ('a' - 'A'));
+    }
+  }
+  return (expected_changed == changed);
+}
+#endif
+
+
+template <class Converter>
+static bool FastAsciiConvert(char* dst, const char* src, int length,
+                             bool* changed_out) {
+#ifdef DEBUG
+  char* saved_dst = dst;
+  const char* saved_src = src;
+#endif
+  DisallowHeapAllocation no_gc;
+  // We rely on the distance between upper and lower case letters
+  // being a known power of 2.
+  DCHECK('a' - 'A' == (1 << 5));
+  // Boundaries for the range of input characters than require conversion.
+  static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1;
+  static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1;
+  bool changed = false;
+  uintptr_t or_acc = 0;
+  const char* const limit = src + length;
+
+  // dst is newly allocated and always aligned.
+  DCHECK(IsAligned(reinterpret_cast<intptr_t>(dst), sizeof(uintptr_t)));
+  // Only attempt processing one word at a time if src is also aligned.
+  if (IsAligned(reinterpret_cast<intptr_t>(src), sizeof(uintptr_t))) {
+    // Process the prefix of the input that requires no conversion one aligned
+    // (machine) word at a time.
+    while (src <= limit - sizeof(uintptr_t)) {
+      const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src);
+      or_acc |= w;
+      if (AsciiRangeMask(w, lo, hi) != 0) {
+        changed = true;
+        break;
+      }
+      *reinterpret_cast<uintptr_t*>(dst) = w;
+      src += sizeof(uintptr_t);
+      dst += sizeof(uintptr_t);
+    }
+    // Process the remainder of the input performing conversion when
+    // required one word at a time.
+    while (src <= limit - sizeof(uintptr_t)) {
+      const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src);
+      or_acc |= w;
+      uintptr_t m = AsciiRangeMask(w, lo, hi);
+      // The mask has high (7th) bit set in every byte that needs
+      // conversion and we know that the distance between cases is
+      // 1 << 5.
+      *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
+      src += sizeof(uintptr_t);
+      dst += sizeof(uintptr_t);
+    }
+  }
+  // Process the last few bytes of the input (or the whole input if
+  // unaligned access is not supported).
+  while (src < limit) {
+    char c = *src;
+    or_acc |= c;
+    if (lo < c && c < hi) {
+      c ^= (1 << 5);
+      changed = true;
+    }
+    *dst = c;
+    ++src;
+    ++dst;
+  }
+
+  if ((or_acc & kAsciiMask) != 0) return false;
+
+  DCHECK(CheckFastAsciiConvert(saved_dst, saved_src, length, changed,
+                               Converter::kIsToLower));
+
+  *changed_out = changed;
+  return true;
+}
+
+
+template <class Converter>
+MUST_USE_RESULT static Object* ConvertCase(
+    Handle<String> s, Isolate* isolate,
+    unibrow::Mapping<Converter, 128>* mapping) {
+  s = String::Flatten(s);
+  int length = s->length();
+  // Assume that the string is not empty; we need this assumption later
+  if (length == 0) return *s;
+
+  // Simpler handling of ASCII strings.
+  //
+  // NOTE: This assumes that the upper/lower case of an ASCII
+  // character is also ASCII.  This is currently the case, but it
+  // might break in the future if we implement more context and locale
+  // dependent upper/lower conversions.
+  if (s->IsOneByteRepresentationUnderneath()) {
+    // Same length as input.
+    Handle<SeqOneByteString> result =
+        isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
+    DisallowHeapAllocation no_gc;
+    String::FlatContent flat_content = s->GetFlatContent();
+    DCHECK(flat_content.IsFlat());
+    bool has_changed_character = false;
+    bool is_ascii = FastAsciiConvert<Converter>(
+        reinterpret_cast<char*>(result->GetChars()),
+        reinterpret_cast<const char*>(flat_content.ToOneByteVector().start()),
+        length, &has_changed_character);
+    // If not ASCII, we discard the result and take the 2 byte path.
+    if (is_ascii) return has_changed_character ? *result : *s;
+  }
+
+  Handle<SeqString> result;  // Same length as input.
+  if (s->IsOneByteRepresentation()) {
+    result = isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
+  } else {
+    result = isolate->factory()->NewRawTwoByteString(length).ToHandleChecked();
+  }
+
+  Object* answer = ConvertCaseHelper(isolate, *s, *result, length, mapping);
+  if (answer->IsException() || answer->IsString()) return answer;
+
+  DCHECK(answer->IsSmi());
+  length = Smi::cast(answer)->value();
+  if (s->IsOneByteRepresentation() && length > 0) {
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, result, isolate->factory()->NewRawOneByteString(length));
+  } else {
+    if (length < 0) length = -length;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, result, isolate->factory()->NewRawTwoByteString(length));
+  }
+  return ConvertCaseHelper(isolate, *s, *result, length, mapping);
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringToLowerCase) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
+  return ConvertCase(s, isolate, isolate->runtime_state()->to_lower_mapping());
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringToUpperCase) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
+  return ConvertCase(s, isolate, isolate->runtime_state()->to_upper_mapping());
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringTrim) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
+  CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
+  CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
+
+  string = String::Flatten(string);
+  int length = string->length();
+
+  int left = 0;
+  UnicodeCache* unicode_cache = isolate->unicode_cache();
+  if (trimLeft) {
+    while (left < length &&
+           unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
+      left++;
+    }
+  }
+
+  int right = length;
+  if (trimRight) {
+    while (
+        right > left &&
+        unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
+      right--;
+    }
+  }
+
+  return *isolate->factory()->NewSubString(string, left, right);
+}
+
+
+RUNTIME_FUNCTION(Runtime_TruncateString) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0);
+  CONVERT_INT32_ARG_CHECKED(new_length, 1);
+  RUNTIME_ASSERT(new_length >= 0);
+  return *SeqString::Truncate(string, new_length);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewString) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_INT32_ARG_CHECKED(length, 0);
+  CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1);
+  if (length == 0) return isolate->heap()->empty_string();
+  Handle<String> result;
+  if (is_one_byte) {
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, result, isolate->factory()->NewRawOneByteString(length));
+  } else {
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, result, isolate->factory()->NewRawTwoByteString(length));
+  }
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_StringEquals) {
+  HandleScope handle_scope(isolate);
+  DCHECK(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
+
+  bool not_equal = !String::Equals(x, y);
+  // This is slightly convoluted because the value that signifies
+  // equality is 0 and inequality is 1 so we have to negate the result
+  // from String::Equals.
+  DCHECK(not_equal == 0 || not_equal == 1);
+  STATIC_ASSERT(EQUAL == 0);
+  STATIC_ASSERT(NOT_EQUAL == 1);
+  return Smi::FromInt(not_equal);
+}
+
+
+RUNTIME_FUNCTION(Runtime_FlattenString) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
+  return *String::Flatten(str);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_StringCharFromCode) {
+  SealHandleScope shs(isolate);
+  return __RT_impl_Runtime_CharFromCode(args, isolate);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_StringCharAt) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  if (!args[0]->IsString()) return Smi::FromInt(0);
+  if (!args[1]->IsNumber()) return Smi::FromInt(0);
+  if (std::isinf(args.number_at(1))) return isolate->heap()->empty_string();
+  Object* code = __RT_impl_Runtime_StringCharCodeAtRT(args, isolate);
+  if (code->IsNaN()) return isolate->heap()->empty_string();
+  return __RT_impl_Runtime_CharFromCode(Arguments(1, &code), isolate);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_OneByteSeqStringSetChar) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_INT32_ARG_CHECKED(index, 0);
+  CONVERT_INT32_ARG_CHECKED(value, 1);
+  CONVERT_ARG_CHECKED(SeqOneByteString, string, 2);
+  string->SeqOneByteStringSet(index, value);
+  return string;
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_TwoByteSeqStringSetChar) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_INT32_ARG_CHECKED(index, 0);
+  CONVERT_INT32_ARG_CHECKED(value, 1);
+  CONVERT_ARG_CHECKED(SeqTwoByteString, string, 2);
+  string->SeqTwoByteStringSet(index, value);
+  return string;
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_StringCompare) {
+  SealHandleScope shs(isolate);
+  return __RT_impl_Runtime_StringCompare(args, isolate);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_StringCharCodeAt) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  if (!args[0]->IsString()) return isolate->heap()->undefined_value();
+  if (!args[1]->IsNumber()) return isolate->heap()->undefined_value();
+  if (std::isinf(args.number_at(1))) return isolate->heap()->nan_value();
+  return __RT_impl_Runtime_StringCharCodeAtRT(args, isolate);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_SubString) {
+  SealHandleScope shs(isolate);
+  return __RT_impl_Runtime_SubString(args, isolate);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_StringAdd) {
+  SealHandleScope shs(isolate);
+  return __RT_impl_Runtime_StringAdd(args, isolate);
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_IsStringWrapperSafeForDefaultValueOf) {
+  UNIMPLEMENTED();
+  return NULL;
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-symbol.cc b/src/runtime/runtime-symbol.cc
new file mode 100644
index 0000000..31b6bed
--- /dev/null
+++ b/src/runtime/runtime-symbol.cc
@@ -0,0 +1,100 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_CreateSymbol) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
+  RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
+  Handle<Symbol> symbol = isolate->factory()->NewSymbol();
+  if (name->IsString()) symbol->set_name(*name);
+  return *symbol;
+}
+
+
+RUNTIME_FUNCTION(Runtime_CreatePrivateSymbol) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
+  RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
+  Handle<Symbol> symbol = isolate->factory()->NewPrivateSymbol();
+  if (name->IsString()) symbol->set_name(*name);
+  return *symbol;
+}
+
+
+RUNTIME_FUNCTION(Runtime_CreatePrivateOwnSymbol) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
+  RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
+  Handle<Symbol> symbol = isolate->factory()->NewPrivateOwnSymbol();
+  if (name->IsString()) symbol->set_name(*name);
+  return *symbol;
+}
+
+
+RUNTIME_FUNCTION(Runtime_CreateGlobalPrivateOwnSymbol) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
+  Handle<JSObject> registry = isolate->GetSymbolRegistry();
+  Handle<String> part = isolate->factory()->private_intern_string();
+  Handle<Object> privates;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, privates, Object::GetPropertyOrElement(registry, part));
+  Handle<Object> symbol;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, symbol, Object::GetPropertyOrElement(privates, name));
+  if (!symbol->IsSymbol()) {
+    DCHECK(symbol->IsUndefined());
+    symbol = isolate->factory()->NewPrivateSymbol();
+    Handle<Symbol>::cast(symbol)->set_name(*name);
+    Handle<Symbol>::cast(symbol)->set_is_own(true);
+    JSObject::SetProperty(Handle<JSObject>::cast(privates), name, symbol,
+                          STRICT).Assert();
+  }
+  return *symbol;
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewSymbolWrapper) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(Symbol, symbol, 0);
+  return *Object::ToObject(isolate, symbol).ToHandleChecked();
+}
+
+
+RUNTIME_FUNCTION(Runtime_SymbolDescription) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Symbol, symbol, 0);
+  return symbol->name();
+}
+
+
+RUNTIME_FUNCTION(Runtime_SymbolRegistry) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+  return *isolate->GetSymbolRegistry();
+}
+
+
+RUNTIME_FUNCTION(Runtime_SymbolIsPrivate) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Symbol, symbol, 0);
+  return isolate->heap()->ToBoolean(symbol->is_private());
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-test.cc b/src/runtime/runtime-test.cc
new file mode 100644
index 0000000..b4b90e2
--- /dev/null
+++ b/src/runtime/runtime-test.cc
@@ -0,0 +1,418 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/deoptimizer.h"
+#include "src/full-codegen.h"
+#include "src/natives.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+  if (!function->IsOptimized()) return isolate->heap()->undefined_value();
+
+  // TODO(turbofan): Deoptimization is not supported yet.
+  if (function->code()->is_turbofanned() && !FLAG_turbo_deoptimization) {
+    return isolate->heap()->undefined_value();
+  }
+
+  Deoptimizer::DeoptimizeFunction(*function);
+
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_RunningInSimulator) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+#if defined(USE_SIMULATOR)
+  return isolate->heap()->true_value();
+#else
+  return isolate->heap()->false_value();
+#endif
+}
+
+
+RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  return isolate->heap()->ToBoolean(
+      isolate->concurrent_recompilation_enabled());
+}
+
+
+RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
+  HandleScope scope(isolate);
+  RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+  // The following two assertions are lifted from the DCHECKs inside
+  // JSFunction::MarkForOptimization().
+  RUNTIME_ASSERT(!function->shared()->is_generator());
+  RUNTIME_ASSERT(function->shared()->allows_lazy_compilation() ||
+                 (function->code()->kind() == Code::FUNCTION &&
+                  function->code()->optimizable()));
+
+  if (!isolate->use_crankshaft()) return isolate->heap()->undefined_value();
+
+  // If the function is already optimized, just return.
+  if (function->IsOptimized()) return isolate->heap()->undefined_value();
+
+  // If the function cannot optimized, just return.
+  if (function->shared()->optimization_disabled()) {
+    return isolate->heap()->undefined_value();
+  }
+
+  function->MarkForOptimization();
+
+  Code* unoptimized = function->shared()->code();
+  if (args.length() == 2 && unoptimized->kind() == Code::FUNCTION) {
+    CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
+    if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("osr")) && FLAG_use_osr) {
+      // Start patching from the currently patched loop nesting level.
+      DCHECK(BackEdgeTable::Verify(isolate, unoptimized));
+      isolate->runtime_profiler()->AttemptOnStackReplacement(
+          *function, Code::kMaxLoopNestingMarker);
+    } else if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("concurrent")) &&
+               isolate->concurrent_recompilation_enabled()) {
+      function->AttemptConcurrentOptimization();
+    }
+  }
+
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSFunction, function, 0);
+  function->shared()->set_disable_optimization_reason(kOptimizationDisabled);
+  function->shared()->set_optimization_disabled(true);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
+  HandleScope scope(isolate);
+  RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
+  if (!isolate->use_crankshaft()) {
+    return Smi::FromInt(4);  // 4 == "never".
+  }
+  bool sync_with_compiler_thread = true;
+  if (args.length() == 2) {
+    CONVERT_ARG_HANDLE_CHECKED(String, sync, 1);
+    if (sync->IsOneByteEqualTo(STATIC_CHAR_VECTOR("no sync"))) {
+      sync_with_compiler_thread = false;
+    }
+  }
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+  if (isolate->concurrent_recompilation_enabled() &&
+      sync_with_compiler_thread) {
+    while (function->IsInOptimizationQueue()) {
+      isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
+      base::OS::Sleep(50);
+    }
+  }
+  if (FLAG_always_opt) {
+    // We may have always opt, but that is more best-effort than a real
+    // promise, so we still say "no" if it is not optimized.
+    return function->IsOptimized() ? Smi::FromInt(3)   // 3 == "always".
+                                   : Smi::FromInt(2);  // 2 == "no".
+  }
+  if (FLAG_deopt_every_n_times) {
+    return Smi::FromInt(6);  // 6 == "maybe deopted".
+  }
+  if (function->IsOptimized() && function->code()->is_turbofanned()) {
+    return Smi::FromInt(7);  // 7 == "TurboFan compiler".
+  }
+  return function->IsOptimized() ? Smi::FromInt(1)   // 1 == "yes".
+                                 : Smi::FromInt(2);  // 2 == "no".
+}
+
+
+RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) {
+  DCHECK(args.length() == 0);
+  RUNTIME_ASSERT(FLAG_block_concurrent_recompilation);
+  RUNTIME_ASSERT(isolate->concurrent_recompilation_enabled());
+  isolate->optimizing_compiler_thread()->Unblock();
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetOptimizationCount) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+  return Smi::FromInt(function->shared()->opt_count());
+}
+
+
+RUNTIME_FUNCTION(Runtime_ClearFunctionTypeFeedback) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+  function->shared()->ClearTypeFeedbackInfo();
+  Code* unoptimized = function->shared()->code();
+  if (unoptimized->kind() == Code::FUNCTION) {
+    unoptimized->ClearInlineCaches();
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+  isolate->heap()->NotifyContextDisposed(true);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2 || args.length() == 3);
+#ifdef DEBUG
+  CONVERT_SMI_ARG_CHECKED(interval, 0);
+  CONVERT_SMI_ARG_CHECKED(timeout, 1);
+  isolate->heap()->set_allocation_timeout(timeout);
+  FLAG_gc_interval = interval;
+  if (args.length() == 3) {
+    // Enable/disable inline allocation if requested.
+    CONVERT_BOOLEAN_ARG_CHECKED(inline_allocation, 2);
+    if (inline_allocation) {
+      isolate->heap()->EnableInlineAllocation();
+    } else {
+      isolate->heap()->DisableInlineAllocation();
+    }
+  }
+#endif
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugPrint) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+
+  OFStream os(stdout);
+#ifdef DEBUG
+  if (args[0]->IsString()) {
+    // If we have a string, assume it's a code "marker"
+    // and print some interesting cpu debugging info.
+    JavaScriptFrameIterator it(isolate);
+    JavaScriptFrame* frame = it.frame();
+    os << "fp = " << frame->fp() << ", sp = " << frame->sp()
+       << ", caller_sp = " << frame->caller_sp() << ": ";
+  } else {
+    os << "DebugPrint: ";
+  }
+  args[0]->Print(os);
+  if (args[0]->IsHeapObject()) {
+    os << "\n";
+    HeapObject::cast(args[0])->map()->Print(os);
+  }
+#else
+  // ShortPrint is available in release mode. Print is not.
+  os << Brief(args[0]);
+#endif
+  os << std::endl;
+
+  return args[0];  // return TOS
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugTrace) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  isolate->PrintStack(stdout);
+  return isolate->heap()->undefined_value();
+}
+
+
+// This will not allocate (flatten the string), but it may run
+// very slowly for very deeply nested ConsStrings.  For debugging use only.
+RUNTIME_FUNCTION(Runtime_GlobalPrint) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+
+  CONVERT_ARG_CHECKED(String, string, 0);
+  StringCharacterStream stream(string);
+  while (stream.HasMore()) {
+    uint16_t character = stream.GetNext();
+    PrintF("%c", character);
+  }
+  return string;
+}
+
+
+RUNTIME_FUNCTION(Runtime_SystemBreak) {
+  // The code below doesn't create handles, but when breaking here in GDB
+  // having a handle scope might be useful.
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+  base::OS::DebugBreak();
+  return isolate->heap()->undefined_value();
+}
+
+
+// Sets a v8 flag.
+RUNTIME_FUNCTION(Runtime_SetFlags) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(String, arg, 0);
+  SmartArrayPointer<char> flags =
+      arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+  FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get()));
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_Abort) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_SMI_ARG_CHECKED(message_id, 0);
+  const char* message =
+      GetBailoutReason(static_cast<BailoutReason>(message_id));
+  base::OS::PrintError("abort: %s\n", message);
+  isolate->PrintStack(stderr);
+  base::OS::Abort();
+  UNREACHABLE();
+  return NULL;
+}
+
+
+RUNTIME_FUNCTION(Runtime_AbortJS) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
+  base::OS::PrintError("abort: %s\n", message->ToCString().get());
+  isolate->PrintStack(stderr);
+  base::OS::Abort();
+  UNREACHABLE();
+  return NULL;
+}
+
+
+RUNTIME_FUNCTION(Runtime_NativeScriptsCount) {
+  DCHECK(args.length() == 0);
+  return Smi::FromInt(Natives::GetBuiltinsCount());
+}
+
+
+// Returns V8 version as a string.
+RUNTIME_FUNCTION(Runtime_GetV8Version) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 0);
+
+  const char* version_string = v8::V8::GetVersion();
+
+  return *isolate->factory()->NewStringFromAsciiChecked(version_string);
+}
+
+
+static int StackSize(Isolate* isolate) {
+  int n = 0;
+  for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
+  return n;
+}
+
+
+static void PrintTransition(Isolate* isolate, Object* result) {
+  // indentation
+  {
+    const int nmax = 80;
+    int n = StackSize(isolate);
+    if (n <= nmax)
+      PrintF("%4d:%*s", n, n, "");
+    else
+      PrintF("%4d:%*s", n, nmax, "...");
+  }
+
+  if (result == NULL) {
+    JavaScriptFrame::PrintTop(isolate, stdout, true, false);
+    PrintF(" {\n");
+  } else {
+    // function result
+    PrintF("} -> ");
+    result->ShortPrint();
+    PrintF("\n");
+  }
+}
+
+
+RUNTIME_FUNCTION(Runtime_TraceEnter) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 0);
+  PrintTransition(isolate, NULL);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_TraceExit) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, obj, 0);
+  PrintTransition(isolate, obj);
+  return obj;  // return TOS
+}
+
+
+RUNTIME_FUNCTION(Runtime_HaveSameMap) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_CHECKED(JSObject, obj1, 0);
+  CONVERT_ARG_CHECKED(JSObject, obj2, 1);
+  return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
+}
+
+
+#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name)       \
+  RUNTIME_FUNCTION(Runtime_Has##Name) {                  \
+    CONVERT_ARG_CHECKED(JSObject, obj, 0);               \
+    return isolate->heap()->ToBoolean(obj->Has##Name()); \
+  }
+
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements)
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
+// Properties test sitting with elements tests - not fooling anyone.
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
+
+#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
+
+
+#define TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, size) \
+  RUNTIME_FUNCTION(Runtime_HasExternal##Type##Elements) {                  \
+    CONVERT_ARG_CHECKED(JSObject, obj, 0);                                 \
+    return isolate->heap()->ToBoolean(obj->HasExternal##Type##Elements()); \
+  }
+
+TYPED_ARRAYS(TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
+
+#undef TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
+
+
+#define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \
+  RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) {                        \
+    CONVERT_ARG_CHECKED(JSObject, obj, 0);                                    \
+    return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements());       \
+  }
+
+TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
+
+#undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-typedarray.cc b/src/runtime/runtime-typedarray.cc
new file mode 100644
index 0000000..cd2c0eb
--- /dev/null
+++ b/src/runtime/runtime-typedarray.cc
@@ -0,0 +1,768 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/runtime/runtime.h"
+#include "src/runtime/runtime-utils.h"
+
+
+namespace v8 {
+namespace internal {
+
+void Runtime::FreeArrayBuffer(Isolate* isolate,
+                              JSArrayBuffer* phantom_array_buffer) {
+  if (phantom_array_buffer->should_be_freed()) {
+    DCHECK(phantom_array_buffer->is_external());
+    free(phantom_array_buffer->backing_store());
+  }
+  if (phantom_array_buffer->is_external()) return;
+
+  size_t allocated_length =
+      NumberToSize(isolate, phantom_array_buffer->byte_length());
+
+  reinterpret_cast<v8::Isolate*>(isolate)
+      ->AdjustAmountOfExternalAllocatedMemory(
+          -static_cast<int64_t>(allocated_length));
+  CHECK(V8::ArrayBufferAllocator() != NULL);
+  V8::ArrayBufferAllocator()->Free(phantom_array_buffer->backing_store(),
+                                   allocated_length);
+}
+
+
+void Runtime::SetupArrayBuffer(Isolate* isolate,
+                               Handle<JSArrayBuffer> array_buffer,
+                               bool is_external, void* data,
+                               size_t allocated_length) {
+  DCHECK(array_buffer->GetInternalFieldCount() ==
+         v8::ArrayBuffer::kInternalFieldCount);
+  for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
+    array_buffer->SetInternalField(i, Smi::FromInt(0));
+  }
+  array_buffer->set_backing_store(data);
+  array_buffer->set_flag(Smi::FromInt(0));
+  array_buffer->set_is_external(is_external);
+  array_buffer->set_is_neuterable(true);
+
+  Handle<Object> byte_length =
+      isolate->factory()->NewNumberFromSize(allocated_length);
+  CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
+  array_buffer->set_byte_length(*byte_length);
+
+  array_buffer->set_weak_next(isolate->heap()->array_buffers_list());
+  isolate->heap()->set_array_buffers_list(*array_buffer);
+  array_buffer->set_weak_first_view(isolate->heap()->undefined_value());
+}
+
+
+bool Runtime::SetupArrayBufferAllocatingData(Isolate* isolate,
+                                             Handle<JSArrayBuffer> array_buffer,
+                                             size_t allocated_length,
+                                             bool initialize) {
+  void* data;
+  CHECK(V8::ArrayBufferAllocator() != NULL);
+  if (allocated_length != 0) {
+    if (initialize) {
+      data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
+    } else {
+      data =
+          V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length);
+    }
+    if (data == NULL) return false;
+  } else {
+    data = NULL;
+  }
+
+  SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length);
+
+  reinterpret_cast<v8::Isolate*>(isolate)
+      ->AdjustAmountOfExternalAllocatedMemory(allocated_length);
+
+  return true;
+}
+
+
+void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) {
+  Isolate* isolate = array_buffer->GetIsolate();
+  for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate);
+       !view_obj->IsUndefined();) {
+    Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj));
+    if (view->IsJSTypedArray()) {
+      JSTypedArray::cast(*view)->Neuter();
+    } else if (view->IsJSDataView()) {
+      JSDataView::cast(*view)->Neuter();
+    } else {
+      UNREACHABLE();
+    }
+    view_obj = handle(view->weak_next(), isolate);
+  }
+  array_buffer->Neuter();
+}
+
+
+RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
+  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1);
+  if (!holder->byte_length()->IsUndefined()) {
+    // ArrayBuffer is already initialized; probably a fuzz test.
+    return *holder;
+  }
+  size_t allocated_length = 0;
+  if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewRangeError("invalid_array_buffer_length",
+                               HandleVector<Object>(NULL, 0)));
+  }
+  if (!Runtime::SetupArrayBufferAllocatingData(isolate, holder,
+                                               allocated_length)) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewRangeError("invalid_array_buffer_length",
+                               HandleVector<Object>(NULL, 0)));
+  }
+  return *holder;
+}
+
+
+RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) {
+  SealHandleScope shs(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
+  return holder->byte_length();
+}
+
+
+RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
+  CONVERT_NUMBER_ARG_HANDLE_CHECKED(first, 2);
+  RUNTIME_ASSERT(!source.is_identical_to(target));
+  size_t start = 0;
+  RUNTIME_ASSERT(TryNumberToSize(isolate, *first, &start));
+  size_t target_length = NumberToSize(isolate, target->byte_length());
+
+  if (target_length == 0) return isolate->heap()->undefined_value();
+
+  size_t source_byte_length = NumberToSize(isolate, source->byte_length());
+  RUNTIME_ASSERT(start <= source_byte_length);
+  RUNTIME_ASSERT(source_byte_length - start >= target_length);
+  uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
+  uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
+  CopyBytes(target_data, source_data + start, target_length);
+  return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_ArrayBufferIsView) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_CHECKED(Object, object, 0);
+  return isolate->heap()->ToBoolean(object->IsJSArrayBufferView());
+}
+
+
+RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0);
+  if (array_buffer->backing_store() == NULL) {
+    CHECK(Smi::FromInt(0) == array_buffer->byte_length());
+    return isolate->heap()->undefined_value();
+  }
+  DCHECK(!array_buffer->is_external());
+  void* backing_store = array_buffer->backing_store();
+  size_t byte_length = NumberToSize(isolate, array_buffer->byte_length());
+  array_buffer->set_is_external(true);
+  Runtime::NeuterArrayBuffer(array_buffer);
+  V8::ArrayBufferAllocator()->Free(backing_store, byte_length);
+  return isolate->heap()->undefined_value();
+}
+
+
+void Runtime::ArrayIdToTypeAndSize(int arrayId, ExternalArrayType* array_type,
+                                   ElementsKind* external_elements_kind,
+                                   ElementsKind* fixed_elements_kind,
+                                   size_t* element_size) {
+  switch (arrayId) {
+#define ARRAY_ID_CASE(Type, type, TYPE, ctype, size)      \
+  case ARRAY_ID_##TYPE:                                   \
+    *array_type = kExternal##Type##Array;                 \
+    *external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS; \
+    *fixed_elements_kind = TYPE##_ELEMENTS;               \
+    *element_size = size;                                 \
+    break;
+
+    TYPED_ARRAYS(ARRAY_ID_CASE)
+#undef ARRAY_ID_CASE
+
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 5);
+  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
+  CONVERT_SMI_ARG_CHECKED(arrayId, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2);
+  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3);
+  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4);
+
+  RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
+                 arrayId <= Runtime::ARRAY_ID_LAST);
+
+  ExternalArrayType array_type = kExternalInt8Array;  // Bogus initialization.
+  size_t element_size = 1;                            // Bogus initialization.
+  ElementsKind external_elements_kind =
+      EXTERNAL_INT8_ELEMENTS;                        // Bogus initialization.
+  ElementsKind fixed_elements_kind = INT8_ELEMENTS;  // Bogus initialization.
+  Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind,
+                                &fixed_elements_kind, &element_size);
+  RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
+
+  size_t byte_offset = 0;
+  size_t byte_length = 0;
+  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset_object, &byte_offset));
+  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length_object, &byte_length));
+
+  if (maybe_buffer->IsJSArrayBuffer()) {
+    Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
+    size_t array_buffer_byte_length =
+        NumberToSize(isolate, buffer->byte_length());
+    RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length);
+    RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length);
+  } else {
+    RUNTIME_ASSERT(maybe_buffer->IsNull());
+  }
+
+  RUNTIME_ASSERT(byte_length % element_size == 0);
+  size_t length = byte_length / element_size;
+
+  if (length > static_cast<unsigned>(Smi::kMaxValue)) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewRangeError("invalid_typed_array_length",
+                               HandleVector<Object>(NULL, 0)));
+  }
+
+  // All checks are done, now we can modify objects.
+
+  DCHECK(holder->GetInternalFieldCount() ==
+         v8::ArrayBufferView::kInternalFieldCount);
+  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
+    holder->SetInternalField(i, Smi::FromInt(0));
+  }
+  Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
+  holder->set_length(*length_obj);
+  holder->set_byte_offset(*byte_offset_object);
+  holder->set_byte_length(*byte_length_object);
+
+  if (!maybe_buffer->IsNull()) {
+    Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
+    holder->set_buffer(*buffer);
+    holder->set_weak_next(buffer->weak_first_view());
+    buffer->set_weak_first_view(*holder);
+
+    Handle<ExternalArray> elements = isolate->factory()->NewExternalArray(
+        static_cast<int>(length), array_type,
+        static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
+    Handle<Map> map =
+        JSObject::GetElementsTransitionMap(holder, external_elements_kind);
+    JSObject::SetMapAndElements(holder, map, elements);
+    DCHECK(IsExternalArrayElementsKind(holder->map()->elements_kind()));
+  } else {
+    holder->set_buffer(Smi::FromInt(0));
+    holder->set_weak_next(isolate->heap()->undefined_value());
+    Handle<FixedTypedArrayBase> elements =
+        isolate->factory()->NewFixedTypedArray(static_cast<int>(length),
+                                               array_type);
+    holder->set_elements(*elements);
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
+// Initializes a typed array from an array-like object.
+// If an array-like object happens to be a typed array of the same type,
+// initializes backing store using memove.
+//
+// Returns true if backing store was initialized or false otherwise.
+RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
+  CONVERT_SMI_ARG_CHECKED(arrayId, 1);
+  CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
+  CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3);
+
+  RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
+                 arrayId <= Runtime::ARRAY_ID_LAST);
+
+  ExternalArrayType array_type = kExternalInt8Array;  // Bogus initialization.
+  size_t element_size = 1;                            // Bogus initialization.
+  ElementsKind external_elements_kind =
+      EXTERNAL_INT8_ELEMENTS;                        // Bogus intialization.
+  ElementsKind fixed_elements_kind = INT8_ELEMENTS;  // Bogus initialization.
+  Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind,
+                                &fixed_elements_kind, &element_size);
+
+  RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
+
+  Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
+  if (source->IsJSTypedArray() &&
+      JSTypedArray::cast(*source)->type() == array_type) {
+    length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate);
+  }
+  size_t length = 0;
+  RUNTIME_ASSERT(TryNumberToSize(isolate, *length_obj, &length));
+
+  if ((length > static_cast<unsigned>(Smi::kMaxValue)) ||
+      (length > (kMaxInt / element_size))) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewRangeError("invalid_typed_array_length",
+                               HandleVector<Object>(NULL, 0)));
+  }
+  size_t byte_length = length * element_size;
+
+  DCHECK(holder->GetInternalFieldCount() ==
+         v8::ArrayBufferView::kInternalFieldCount);
+  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
+    holder->SetInternalField(i, Smi::FromInt(0));
+  }
+
+  // NOTE: not initializing backing store.
+  // We assume that the caller of this function will initialize holder
+  // with the loop
+  //      for(i = 0; i < length; i++) { holder[i] = source[i]; }
+  // We assume that the caller of this function is always a typed array
+  // constructor.
+  // If source is a typed array, this loop will always run to completion,
+  // so we are sure that the backing store will be initialized.
+  // Otherwise, the indexing operation might throw, so the loop will not
+  // run to completion and the typed array might remain partly initialized.
+  // However we further assume that the caller of this function is a typed array
+  // constructor, and the exception will propagate out of the constructor,
+  // therefore uninitialized memory will not be accessible by a user program.
+  //
+  // TODO(dslomov): revise this once we support subclassing.
+
+  if (!Runtime::SetupArrayBufferAllocatingData(isolate, buffer, byte_length,
+                                               false)) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewRangeError("invalid_array_buffer_length",
+                               HandleVector<Object>(NULL, 0)));
+  }
+
+  holder->set_buffer(*buffer);
+  holder->set_byte_offset(Smi::FromInt(0));
+  Handle<Object> byte_length_obj(
+      isolate->factory()->NewNumberFromSize(byte_length));
+  holder->set_byte_length(*byte_length_obj);
+  holder->set_length(*length_obj);
+  holder->set_weak_next(buffer->weak_first_view());
+  buffer->set_weak_first_view(*holder);
+
+  Handle<ExternalArray> elements = isolate->factory()->NewExternalArray(
+      static_cast<int>(length), array_type,
+      static_cast<uint8_t*>(buffer->backing_store()));
+  Handle<Map> map =
+      JSObject::GetElementsTransitionMap(holder, external_elements_kind);
+  JSObject::SetMapAndElements(holder, map, elements);
+
+  if (source->IsJSTypedArray()) {
+    Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
+
+    if (typed_array->type() == holder->type()) {
+      uint8_t* backing_store =
+          static_cast<uint8_t*>(typed_array->GetBuffer()->backing_store());
+      size_t source_byte_offset =
+          NumberToSize(isolate, typed_array->byte_offset());
+      memcpy(buffer->backing_store(), backing_store + source_byte_offset,
+             byte_length);
+      return isolate->heap()->true_value();
+    }
+  }
+
+  return isolate->heap()->false_value();
+}
+
+
+#define BUFFER_VIEW_GETTER(Type, getter, accessor)   \
+  RUNTIME_FUNCTION(Runtime_##Type##Get##getter) {    \
+    HandleScope scope(isolate);                      \
+    DCHECK(args.length() == 1);                      \
+    CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0); \
+    return holder->accessor();                       \
+  }
+
+BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length)
+BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset)
+BUFFER_VIEW_GETTER(TypedArray, Length, length)
+BUFFER_VIEW_GETTER(DataView, Buffer, buffer)
+
+#undef BUFFER_VIEW_GETTER
+
+RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
+  return *holder->GetBuffer();
+}
+
+
+// Return codes for Runtime_TypedArraySetFastCases.
+// Should be synchronized with typedarray.js natives.
+enum TypedArraySetResultCodes {
+  // Set from typed array of the same type.
+  // This is processed by TypedArraySetFastCases
+  TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
+  // Set from typed array of the different type, overlapping in memory.
+  TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
+  // Set from typed array of the different type, non-overlapping.
+  TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
+  // Set from non-typed array.
+  TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
+};
+
+
+RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 3);
+  if (!args[0]->IsJSTypedArray()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate,
+        NewTypeError("not_typed_array", HandleVector<Object>(NULL, 0)));
+  }
+
+  if (!args[1]->IsJSTypedArray())
+    return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1);
+  CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2);
+
+  Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
+  Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
+  size_t offset = 0;
+  RUNTIME_ASSERT(TryNumberToSize(isolate, *offset_obj, &offset));
+  size_t target_length = NumberToSize(isolate, target->length());
+  size_t source_length = NumberToSize(isolate, source->length());
+  size_t target_byte_length = NumberToSize(isolate, target->byte_length());
+  size_t source_byte_length = NumberToSize(isolate, source->byte_length());
+  if (offset > target_length || offset + source_length > target_length ||
+      offset + source_length < offset) {  // overflow
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewRangeError("typed_array_set_source_too_large",
+                               HandleVector<Object>(NULL, 0)));
+  }
+
+  size_t target_offset = NumberToSize(isolate, target->byte_offset());
+  size_t source_offset = NumberToSize(isolate, source->byte_offset());
+  uint8_t* target_base =
+      static_cast<uint8_t*>(target->GetBuffer()->backing_store()) +
+      target_offset;
+  uint8_t* source_base =
+      static_cast<uint8_t*>(source->GetBuffer()->backing_store()) +
+      source_offset;
+
+  // Typed arrays of the same type: use memmove.
+  if (target->type() == source->type()) {
+    memmove(target_base + offset * target->element_size(), source_base,
+            source_byte_length);
+    return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
+  }
+
+  // Typed arrays of different types over the same backing store
+  if ((source_base <= target_base &&
+       source_base + source_byte_length > target_base) ||
+      (target_base <= source_base &&
+       target_base + target_byte_length > source_base)) {
+    // We do not support overlapping ArrayBuffers
+    DCHECK(target->GetBuffer()->backing_store() ==
+           source->GetBuffer()->backing_store());
+    return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
+  } else {  // Non-overlapping typed arrays
+    return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
+  }
+}
+
+
+RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) {
+  DCHECK(args.length() == 0);
+  DCHECK_OBJECT_SIZE(FLAG_typed_array_max_size_in_heap +
+                     FixedTypedArrayBase::kDataOffset);
+  return Smi::FromInt(FLAG_typed_array_max_size_in_heap);
+}
+
+
+RUNTIME_FUNCTION(Runtime_IsTypedArray) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  return isolate->heap()->ToBoolean(args[0]->IsJSTypedArray());
+}
+
+
+RUNTIME_FUNCTION(Runtime_DataViewInitialize) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 4);
+  CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1);
+  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2);
+  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3);
+
+  DCHECK(holder->GetInternalFieldCount() ==
+         v8::ArrayBufferView::kInternalFieldCount);
+  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
+    holder->SetInternalField(i, Smi::FromInt(0));
+  }
+  size_t buffer_length = 0;
+  size_t offset = 0;
+  size_t length = 0;
+  RUNTIME_ASSERT(
+      TryNumberToSize(isolate, buffer->byte_length(), &buffer_length));
+  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset));
+  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length));
+
+  // TODO(jkummerow): When we have a "safe numerics" helper class, use it here.
+  // Entire range [offset, offset + length] must be in bounds.
+  RUNTIME_ASSERT(offset <= buffer_length);
+  RUNTIME_ASSERT(offset + length <= buffer_length);
+  // No overflow.
+  RUNTIME_ASSERT(offset + length >= offset);
+
+  holder->set_buffer(*buffer);
+  holder->set_byte_offset(*byte_offset);
+  holder->set_byte_length(*byte_length);
+
+  holder->set_weak_next(buffer->weak_first_view());
+  buffer->set_weak_first_view(*holder);
+
+  return isolate->heap()->undefined_value();
+}
+
+
+inline static bool NeedToFlipBytes(bool is_little_endian) {
+#ifdef V8_TARGET_LITTLE_ENDIAN
+  return !is_little_endian;
+#else
+  return is_little_endian;
+#endif
+}
+
+
+template <int n>
+inline void CopyBytes(uint8_t* target, uint8_t* source) {
+  for (int i = 0; i < n; i++) {
+    *(target++) = *(source++);
+  }
+}
+
+
+template <int n>
+inline void FlipBytes(uint8_t* target, uint8_t* source) {
+  source = source + (n - 1);
+  for (int i = 0; i < n; i++) {
+    *(target++) = *(source--);
+  }
+}
+
+
+template <typename T>
+inline static bool DataViewGetValue(Isolate* isolate,
+                                    Handle<JSDataView> data_view,
+                                    Handle<Object> byte_offset_obj,
+                                    bool is_little_endian, T* result) {
+  size_t byte_offset = 0;
+  if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
+    return false;
+  }
+  Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
+
+  size_t data_view_byte_offset =
+      NumberToSize(isolate, data_view->byte_offset());
+  size_t data_view_byte_length =
+      NumberToSize(isolate, data_view->byte_length());
+  if (byte_offset + sizeof(T) > data_view_byte_length ||
+      byte_offset + sizeof(T) < byte_offset) {  // overflow
+    return false;
+  }
+
+  union Value {
+    T data;
+    uint8_t bytes[sizeof(T)];
+  };
+
+  Value value;
+  size_t buffer_offset = data_view_byte_offset + byte_offset;
+  DCHECK(NumberToSize(isolate, buffer->byte_length()) >=
+         buffer_offset + sizeof(T));
+  uint8_t* source =
+      static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
+  if (NeedToFlipBytes(is_little_endian)) {
+    FlipBytes<sizeof(T)>(value.bytes, source);
+  } else {
+    CopyBytes<sizeof(T)>(value.bytes, source);
+  }
+  *result = value.data;
+  return true;
+}
+
+
+template <typename T>
+static bool DataViewSetValue(Isolate* isolate, Handle<JSDataView> data_view,
+                             Handle<Object> byte_offset_obj,
+                             bool is_little_endian, T data) {
+  size_t byte_offset = 0;
+  if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
+    return false;
+  }
+  Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
+
+  size_t data_view_byte_offset =
+      NumberToSize(isolate, data_view->byte_offset());
+  size_t data_view_byte_length =
+      NumberToSize(isolate, data_view->byte_length());
+  if (byte_offset + sizeof(T) > data_view_byte_length ||
+      byte_offset + sizeof(T) < byte_offset) {  // overflow
+    return false;
+  }
+
+  union Value {
+    T data;
+    uint8_t bytes[sizeof(T)];
+  };
+
+  Value value;
+  value.data = data;
+  size_t buffer_offset = data_view_byte_offset + byte_offset;
+  DCHECK(NumberToSize(isolate, buffer->byte_length()) >=
+         buffer_offset + sizeof(T));
+  uint8_t* target =
+      static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
+  if (NeedToFlipBytes(is_little_endian)) {
+    FlipBytes<sizeof(T)>(target, value.bytes);
+  } else {
+    CopyBytes<sizeof(T)>(target, value.bytes);
+  }
+  return true;
+}
+
+
+#define DATA_VIEW_GETTER(TypeName, Type, Converter)                   \
+  RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) {                   \
+    HandleScope scope(isolate);                                       \
+    DCHECK(args.length() == 3);                                       \
+    CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);                \
+    CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1);                     \
+    CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2);                 \
+    Type result;                                                      \
+    if (DataViewGetValue(isolate, holder, offset, is_little_endian,   \
+                         &result)) {                                  \
+      return *isolate->factory()->Converter(result);                  \
+    } else {                                                          \
+      THROW_NEW_ERROR_RETURN_FAILURE(                                 \
+          isolate, NewRangeError("invalid_data_view_accessor_offset", \
+                                 HandleVector<Object>(NULL, 0)));     \
+    }                                                                 \
+  }
+
+DATA_VIEW_GETTER(Uint8, uint8_t, NewNumberFromUint)
+DATA_VIEW_GETTER(Int8, int8_t, NewNumberFromInt)
+DATA_VIEW_GETTER(Uint16, uint16_t, NewNumberFromUint)
+DATA_VIEW_GETTER(Int16, int16_t, NewNumberFromInt)
+DATA_VIEW_GETTER(Uint32, uint32_t, NewNumberFromUint)
+DATA_VIEW_GETTER(Int32, int32_t, NewNumberFromInt)
+DATA_VIEW_GETTER(Float32, float, NewNumber)
+DATA_VIEW_GETTER(Float64, double, NewNumber)
+
+#undef DATA_VIEW_GETTER
+
+
+template <typename T>
+static T DataViewConvertValue(double value);
+
+
+template <>
+int8_t DataViewConvertValue<int8_t>(double value) {
+  return static_cast<int8_t>(DoubleToInt32(value));
+}
+
+
+template <>
+int16_t DataViewConvertValue<int16_t>(double value) {
+  return static_cast<int16_t>(DoubleToInt32(value));
+}
+
+
+template <>
+int32_t DataViewConvertValue<int32_t>(double value) {
+  return DoubleToInt32(value);
+}
+
+
+template <>
+uint8_t DataViewConvertValue<uint8_t>(double value) {
+  return static_cast<uint8_t>(DoubleToUint32(value));
+}
+
+
+template <>
+uint16_t DataViewConvertValue<uint16_t>(double value) {
+  return static_cast<uint16_t>(DoubleToUint32(value));
+}
+
+
+template <>
+uint32_t DataViewConvertValue<uint32_t>(double value) {
+  return DoubleToUint32(value);
+}
+
+
+template <>
+float DataViewConvertValue<float>(double value) {
+  return static_cast<float>(value);
+}
+
+
+template <>
+double DataViewConvertValue<double>(double value) {
+  return value;
+}
+
+
+#define DATA_VIEW_SETTER(TypeName, Type)                                  \
+  RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) {                       \
+    HandleScope scope(isolate);                                           \
+    DCHECK(args.length() == 4);                                           \
+    CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);                    \
+    CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1);                         \
+    CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);                          \
+    CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3);                     \
+    Type v = DataViewConvertValue<Type>(value->Number());                 \
+    if (DataViewSetValue(isolate, holder, offset, is_little_endian, v)) { \
+      return isolate->heap()->undefined_value();                          \
+    } else {                                                              \
+      THROW_NEW_ERROR_RETURN_FAILURE(                                     \
+          isolate, NewRangeError("invalid_data_view_accessor_offset",     \
+                                 HandleVector<Object>(NULL, 0)));         \
+    }                                                                     \
+  }
+
+DATA_VIEW_SETTER(Uint8, uint8_t)
+DATA_VIEW_SETTER(Int8, int8_t)
+DATA_VIEW_SETTER(Uint16, uint16_t)
+DATA_VIEW_SETTER(Int16, int16_t)
+DATA_VIEW_SETTER(Uint32, uint32_t)
+DATA_VIEW_SETTER(Int32, int32_t)
+DATA_VIEW_SETTER(Float32, float)
+DATA_VIEW_SETTER(Float64, double)
+
+#undef DATA_VIEW_SETTER
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-uri.cc b/src/runtime/runtime-uri.cc
new file mode 100644
index 0000000..477071a
--- /dev/null
+++ b/src/runtime/runtime-uri.cc
@@ -0,0 +1,288 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/arguments.h"
+#include "src/conversions.h"
+#include "src/runtime/runtime-utils.h"
+#include "src/string-search.h"
+#include "src/utils.h"
+
+
+namespace v8 {
+namespace internal {
+
+class URIUnescape : public AllStatic {
+ public:
+  template <typename Char>
+  MUST_USE_RESULT static MaybeHandle<String> Unescape(Isolate* isolate,
+                                                      Handle<String> source);
+
+ private:
+  static const signed char kHexValue['g'];
+
+  template <typename Char>
+  MUST_USE_RESULT static MaybeHandle<String> UnescapeSlow(Isolate* isolate,
+                                                          Handle<String> string,
+                                                          int start_index);
+
+  static INLINE(int TwoDigitHex(uint16_t character1, uint16_t character2));
+
+  template <typename Char>
+  static INLINE(int UnescapeChar(Vector<const Char> vector, int i, int length,
+                                 int* step));
+};
+
+
+const signed char URIUnescape::kHexValue[] = {
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -0, 1,  2,  3,  4,  5,
+    6,  7,  8,  9,  -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15};
+
+
+template <typename Char>
+MaybeHandle<String> URIUnescape::Unescape(Isolate* isolate,
+                                          Handle<String> source) {
+  int index;
+  {
+    DisallowHeapAllocation no_allocation;
+    StringSearch<uint8_t, Char> search(isolate, STATIC_CHAR_VECTOR("%"));
+    index = search.Search(source->GetCharVector<Char>(), 0);
+    if (index < 0) return source;
+  }
+  return UnescapeSlow<Char>(isolate, source, index);
+}
+
+
+template <typename Char>
+MaybeHandle<String> URIUnescape::UnescapeSlow(Isolate* isolate,
+                                              Handle<String> string,
+                                              int start_index) {
+  bool one_byte = true;
+  int length = string->length();
+
+  int unescaped_length = 0;
+  {
+    DisallowHeapAllocation no_allocation;
+    Vector<const Char> vector = string->GetCharVector<Char>();
+    for (int i = start_index; i < length; unescaped_length++) {
+      int step;
+      if (UnescapeChar(vector, i, length, &step) >
+          String::kMaxOneByteCharCode) {
+        one_byte = false;
+      }
+      i += step;
+    }
+  }
+
+  DCHECK(start_index < length);
+  Handle<String> first_part =
+      isolate->factory()->NewProperSubString(string, 0, start_index);
+
+  int dest_position = 0;
+  Handle<String> second_part;
+  DCHECK(unescaped_length <= String::kMaxLength);
+  if (one_byte) {
+    Handle<SeqOneByteString> dest = isolate->factory()
+                                        ->NewRawOneByteString(unescaped_length)
+                                        .ToHandleChecked();
+    DisallowHeapAllocation no_allocation;
+    Vector<const Char> vector = string->GetCharVector<Char>();
+    for (int i = start_index; i < length; dest_position++) {
+      int step;
+      dest->SeqOneByteStringSet(dest_position,
+                                UnescapeChar(vector, i, length, &step));
+      i += step;
+    }
+    second_part = dest;
+  } else {
+    Handle<SeqTwoByteString> dest = isolate->factory()
+                                        ->NewRawTwoByteString(unescaped_length)
+                                        .ToHandleChecked();
+    DisallowHeapAllocation no_allocation;
+    Vector<const Char> vector = string->GetCharVector<Char>();
+    for (int i = start_index; i < length; dest_position++) {
+      int step;
+      dest->SeqTwoByteStringSet(dest_position,
+                                UnescapeChar(vector, i, length, &step));
+      i += step;
+    }
+    second_part = dest;
+  }
+  return isolate->factory()->NewConsString(first_part, second_part);
+}
+
+
+int URIUnescape::TwoDigitHex(uint16_t character1, uint16_t character2) {
+  if (character1 > 'f') return -1;
+  int hi = kHexValue[character1];
+  if (hi == -1) return -1;
+  if (character2 > 'f') return -1;
+  int lo = kHexValue[character2];
+  if (lo == -1) return -1;
+  return (hi << 4) + lo;
+}
+
+
+template <typename Char>
+int URIUnescape::UnescapeChar(Vector<const Char> vector, int i, int length,
+                              int* step) {
+  uint16_t character = vector[i];
+  int32_t hi = 0;
+  int32_t lo = 0;
+  if (character == '%' && i <= length - 6 && vector[i + 1] == 'u' &&
+      (hi = TwoDigitHex(vector[i + 2], vector[i + 3])) != -1 &&
+      (lo = TwoDigitHex(vector[i + 4], vector[i + 5])) != -1) {
+    *step = 6;
+    return (hi << 8) + lo;
+  } else if (character == '%' && i <= length - 3 &&
+             (lo = TwoDigitHex(vector[i + 1], vector[i + 2])) != -1) {
+    *step = 3;
+    return lo;
+  } else {
+    *step = 1;
+    return character;
+  }
+}
+
+
+class URIEscape : public AllStatic {
+ public:
+  template <typename Char>
+  MUST_USE_RESULT static MaybeHandle<String> Escape(Isolate* isolate,
+                                                    Handle<String> string);
+
+ private:
+  static const char kHexChars[17];
+  static const char kNotEscaped[256];
+
+  static bool IsNotEscaped(uint16_t c) { return kNotEscaped[c] != 0; }
+};
+
+
+const char URIEscape::kHexChars[] = "0123456789ABCDEF";
+
+
+// kNotEscaped is generated by the following:
+//
+// #!/bin/perl
+// for (my $i = 0; $i < 256; $i++) {
+//   print "\n" if $i % 16 == 0;
+//   my $c = chr($i);
+//   my $escaped = 1;
+//   $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
+//   print $escaped ? "0, " : "1, ";
+// }
+
+const char URIEscape::kNotEscaped[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+
+template <typename Char>
+MaybeHandle<String> URIEscape::Escape(Isolate* isolate, Handle<String> string) {
+  DCHECK(string->IsFlat());
+  int escaped_length = 0;
+  int length = string->length();
+
+  {
+    DisallowHeapAllocation no_allocation;
+    Vector<const Char> vector = string->GetCharVector<Char>();
+    for (int i = 0; i < length; i++) {
+      uint16_t c = vector[i];
+      if (c >= 256) {
+        escaped_length += 6;
+      } else if (IsNotEscaped(c)) {
+        escaped_length++;
+      } else {
+        escaped_length += 3;
+      }
+
+      // We don't allow strings that are longer than a maximal length.
+      DCHECK(String::kMaxLength < 0x7fffffff - 6);     // Cannot overflow.
+      if (escaped_length > String::kMaxLength) break;  // Provoke exception.
+    }
+  }
+
+  // No length change implies no change.  Return original string if no change.
+  if (escaped_length == length) return string;
+
+  Handle<SeqOneByteString> dest;
+  ASSIGN_RETURN_ON_EXCEPTION(
+      isolate, dest, isolate->factory()->NewRawOneByteString(escaped_length),
+      String);
+  int dest_position = 0;
+
+  {
+    DisallowHeapAllocation no_allocation;
+    Vector<const Char> vector = string->GetCharVector<Char>();
+    for (int i = 0; i < length; i++) {
+      uint16_t c = vector[i];
+      if (c >= 256) {
+        dest->SeqOneByteStringSet(dest_position, '%');
+        dest->SeqOneByteStringSet(dest_position + 1, 'u');
+        dest->SeqOneByteStringSet(dest_position + 2, kHexChars[c >> 12]);
+        dest->SeqOneByteStringSet(dest_position + 3, kHexChars[(c >> 8) & 0xf]);
+        dest->SeqOneByteStringSet(dest_position + 4, kHexChars[(c >> 4) & 0xf]);
+        dest->SeqOneByteStringSet(dest_position + 5, kHexChars[c & 0xf]);
+        dest_position += 6;
+      } else if (IsNotEscaped(c)) {
+        dest->SeqOneByteStringSet(dest_position, c);
+        dest_position++;
+      } else {
+        dest->SeqOneByteStringSet(dest_position, '%');
+        dest->SeqOneByteStringSet(dest_position + 1, kHexChars[c >> 4]);
+        dest->SeqOneByteStringSet(dest_position + 2, kHexChars[c & 0xf]);
+        dest_position += 3;
+      }
+    }
+  }
+
+  return dest;
+}
+
+
+RUNTIME_FUNCTION(Runtime_URIEscape) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
+  Handle<String> string = String::Flatten(source);
+  DCHECK(string->IsFlat());
+  Handle<String> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, string->IsOneByteRepresentationUnderneath()
+                           ? URIEscape::Escape<uint8_t>(isolate, source)
+                           : URIEscape::Escape<uc16>(isolate, source));
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_URIUnescape) {
+  HandleScope scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
+  Handle<String> string = String::Flatten(source);
+  DCHECK(string->IsFlat());
+  Handle<String> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, string->IsOneByteRepresentationUnderneath()
+                           ? URIUnescape::Unescape<uint8_t>(isolate, source)
+                           : URIUnescape::Unescape<uc16>(isolate, source));
+  return *result;
+}
+}
+}  // namespace v8::internal
diff --git a/src/runtime/runtime-utils.h b/src/runtime/runtime-utils.h
new file mode 100644
index 0000000..95d75f5
--- /dev/null
+++ b/src/runtime/runtime-utils.h
@@ -0,0 +1,147 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_RUNTIME_RUNTIME_UTILS_H_
+#define V8_RUNTIME_RUNTIME_UTILS_H_
+
+
+namespace v8 {
+namespace internal {
+
+#define RUNTIME_ASSERT(value) \
+  if (!(value)) return isolate->ThrowIllegalOperation();
+
+#define RUNTIME_ASSERT_HANDLIFIED(value, T) \
+  if (!(value)) {                           \
+    isolate->ThrowIllegalOperation();       \
+    return MaybeHandle<T>();                \
+  }
+
+// Cast the given object to a value of the specified type and store
+// it in a variable with the given name.  If the object is not of the
+// expected type call IllegalOperation and return.
+#define CONVERT_ARG_CHECKED(Type, name, index) \
+  RUNTIME_ASSERT(args[index]->Is##Type());     \
+  Type* name = Type::cast(args[index]);
+
+#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
+  RUNTIME_ASSERT(args[index]->Is##Type());            \
+  Handle<Type> name = args.at<Type>(index);
+
+#define CONVERT_NUMBER_ARG_HANDLE_CHECKED(name, index) \
+  RUNTIME_ASSERT(args[index]->IsNumber());             \
+  Handle<Object> name = args.at<Object>(index);
+
+// Cast the given object to a boolean and store it in a variable with
+// the given name.  If the object is not a boolean call IllegalOperation
+// and return.
+#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
+  RUNTIME_ASSERT(args[index]->IsBoolean());      \
+  bool name = args[index]->IsTrue();
+
+// Cast the given argument to a Smi and store its value in an int variable
+// with the given name.  If the argument is not a Smi call IllegalOperation
+// and return.
+#define CONVERT_SMI_ARG_CHECKED(name, index) \
+  RUNTIME_ASSERT(args[index]->IsSmi());      \
+  int name = args.smi_at(index);
+
+// Cast the given argument to a double and store it in a variable with
+// the given name.  If the argument is not a number (as opposed to
+// the number not-a-number) call IllegalOperation and return.
+#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
+  RUNTIME_ASSERT(args[index]->IsNumber());      \
+  double name = args.number_at(index);
+
+// Call the specified converter on the object *comand store the result in
+// a variable of the specified type with the given name.  If the
+// object is not a Number call IllegalOperation and return.
+#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
+  RUNTIME_ASSERT(obj->IsNumber());                    \
+  type name = NumberTo##Type(obj);
+
+
+// Cast the given argument to PropertyDetails and store its value in a
+// variable with the given name.  If the argument is not a Smi call
+// IllegalOperation and return.
+#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
+  RUNTIME_ASSERT(args[index]->IsSmi());               \
+  PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
+
+
+// Assert that the given argument has a valid value for a StrictMode
+// and store it in a StrictMode variable with the given name.
+#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
+  RUNTIME_ASSERT(args[index]->IsSmi());              \
+  RUNTIME_ASSERT(args.smi_at(index) == STRICT ||     \
+                 args.smi_at(index) == SLOPPY);      \
+  StrictMode name = static_cast<StrictMode>(args.smi_at(index));
+
+
+// Assert that the given argument is a number within the Int32 range
+// and convert it to int32_t.  If the argument is not an Int32 call
+// IllegalOperation and return.
+#define CONVERT_INT32_ARG_CHECKED(name, index) \
+  RUNTIME_ASSERT(args[index]->IsNumber());     \
+  int32_t name = 0;                            \
+  RUNTIME_ASSERT(args[index]->ToInt32(&name));
+
+
+// A mechanism to return a pair of Object pointers in registers (if possible).
+// How this is achieved is calling convention-dependent.
+// All currently supported x86 compiles uses calling conventions that are cdecl
+// variants where a 64-bit value is returned in two 32-bit registers
+// (edx:eax on ia32, r1:r0 on ARM).
+// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
+// In Win64 calling convention, a struct of two pointers is returned in memory,
+// allocated by the caller, and passed as a pointer in a hidden first parameter.
+#ifdef V8_HOST_ARCH_64_BIT
+struct ObjectPair {
+  Object* x;
+  Object* y;
+};
+
+
+static inline ObjectPair MakePair(Object* x, Object* y) {
+  ObjectPair result = {x, y};
+  // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
+  // In Win64 they are assigned to a hidden first argument.
+  return result;
+}
+#elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
+// For x32 a 128-bit struct return is done as rax and rdx from the ObjectPair
+// are used in the full codegen and Crankshaft compiler. An alternative is
+// using uint64_t and modifying full codegen and Crankshaft compiler.
+struct ObjectPair {
+  Object* x;
+  uint32_t x_upper;
+  Object* y;
+  uint32_t y_upper;
+};
+
+
+static inline ObjectPair MakePair(Object* x, Object* y) {
+  ObjectPair result = {x, 0, y, 0};
+  // Pointers x and y returned in rax and rdx, in x32-abi.
+  return result;
+}
+#else
+typedef uint64_t ObjectPair;
+static inline ObjectPair MakePair(Object* x, Object* y) {
+#if defined(V8_TARGET_LITTLE_ENDIAN)
+  return reinterpret_cast<uint32_t>(x) |
+         (reinterpret_cast<ObjectPair>(y) << 32);
+#elif defined(V8_TARGET_BIG_ENDIAN)
+  return reinterpret_cast<uint32_t>(y) |
+         (reinterpret_cast<ObjectPair>(x) << 32);
+#else
+#error Unknown endianness
+#endif
+}
+#endif
+
+}
+}  // namespace v8::internal
+
+#endif  // V8_RUNTIME_RUNTIME_UTILS_H_
diff --git a/src/runtime/runtime.cc b/src/runtime/runtime.cc
new file mode 100644
index 0000000..459ca50
--- /dev/null
+++ b/src/runtime/runtime.cc
@@ -0,0 +1,122 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/runtime/runtime.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+// Header of runtime functions.
+#define F(name, number_of_args, result_size)                    \
+  Object* Runtime_##name(int args_length, Object** args_object, \
+                         Isolate* isolate);
+
+#define P(name, number_of_args, result_size)                       \
+  ObjectPair Runtime_##name(int args_length, Object** args_object, \
+                            Isolate* isolate);
+
+// Reference implementation for inlined runtime functions.  Only used when the
+// compiler does not support a certain intrinsic.  Don't optimize these, but
+// implement the intrinsic in the respective compiler instead.
+// TODO(mstarzinger): These are place-holder stubs for TurboFan and will
+// eventually all have a C++ implementation and this macro will be gone.
+#define I(name, number_of_args, result_size)                             \
+  Object* RuntimeReference_##name(int args_length, Object** args_object, \
+                                  Isolate* isolate);
+
+RUNTIME_FUNCTION_LIST_RETURN_OBJECT(F)
+RUNTIME_FUNCTION_LIST_RETURN_PAIR(P)
+INLINE_OPTIMIZED_FUNCTION_LIST(F)
+INLINE_FUNCTION_LIST(I)
+
+#undef I
+#undef F
+#undef P
+
+
+#define F(name, number_of_args, result_size)                                  \
+  {                                                                           \
+    Runtime::k##name, Runtime::RUNTIME, #name, FUNCTION_ADDR(Runtime_##name), \
+        number_of_args, result_size                                           \
+  }                                                                           \
+  ,
+
+
+#define I(name, number_of_args, result_size)                                \
+  {                                                                         \
+    Runtime::kInline##name, Runtime::INLINE, "_" #name,                     \
+        FUNCTION_ADDR(RuntimeReference_##name), number_of_args, result_size \
+  }                                                                         \
+  ,
+
+
+#define IO(name, number_of_args, result_size)                              \
+  {                                                                        \
+    Runtime::kInlineOptimized##name, Runtime::INLINE_OPTIMIZED, "_" #name, \
+        FUNCTION_ADDR(Runtime_##name), number_of_args, result_size         \
+  }                                                                        \
+  ,
+
+
+static const Runtime::Function kIntrinsicFunctions[] = {
+    RUNTIME_FUNCTION_LIST(F) INLINE_OPTIMIZED_FUNCTION_LIST(F)
+    INLINE_FUNCTION_LIST(I) INLINE_OPTIMIZED_FUNCTION_LIST(IO)};
+
+#undef IO
+#undef I
+#undef F
+
+
+void Runtime::InitializeIntrinsicFunctionNames(Isolate* isolate,
+                                               Handle<NameDictionary> dict) {
+  DCHECK(dict->NumberOfElements() == 0);
+  HandleScope scope(isolate);
+  for (int i = 0; i < kNumFunctions; ++i) {
+    const char* name = kIntrinsicFunctions[i].name;
+    if (name == NULL) continue;
+    Handle<NameDictionary> new_dict = NameDictionary::Add(
+        dict, isolate->factory()->InternalizeUtf8String(name),
+        Handle<Smi>(Smi::FromInt(i), isolate), PropertyDetails(NONE, FIELD, 0));
+    // The dictionary does not need to grow.
+    CHECK(new_dict.is_identical_to(dict));
+  }
+}
+
+
+const Runtime::Function* Runtime::FunctionForName(Handle<String> name) {
+  Heap* heap = name->GetHeap();
+  int entry = heap->intrinsic_function_names()->FindEntry(name);
+  if (entry != kNotFound) {
+    Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
+    int function_index = Smi::cast(smi_index)->value();
+    return &(kIntrinsicFunctions[function_index]);
+  }
+  return NULL;
+}
+
+
+const Runtime::Function* Runtime::FunctionForEntry(Address entry) {
+  for (size_t i = 0; i < arraysize(kIntrinsicFunctions); ++i) {
+    if (entry == kIntrinsicFunctions[i].entry) {
+      return &(kIntrinsicFunctions[i]);
+    }
+  }
+  return NULL;
+}
+
+
+const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
+  return &(kIntrinsicFunctions[static_cast<int>(id)]);
+}
+
+
+std::ostream& operator<<(std::ostream& os, Runtime::FunctionId id) {
+  return os << Runtime::FunctionForId(id)->name;
+}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
new file mode 100644
index 0000000..9e6c495
--- /dev/null
+++ b/src/runtime/runtime.h
@@ -0,0 +1,898 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_RUNTIME_RUNTIME_H_
+#define V8_RUNTIME_RUNTIME_H_
+
+#include "src/allocation.h"
+#include "src/objects.h"
+#include "src/zone.h"
+
+namespace v8 {
+namespace internal {
+
+// The interface to C++ runtime functions.
+
+// ----------------------------------------------------------------------------
+// RUNTIME_FUNCTION_LIST_ALWAYS defines runtime calls available in both
+// release and debug mode.
+// This macro should only be used by the macro RUNTIME_FUNCTION_LIST.
+
+// WARNING: RUNTIME_FUNCTION_LIST_ALWAYS_* is a very large macro that caused
+// MSVC Intellisense to crash.  It was broken into two macros to work around
+// this problem. Please avoid large recursive macros whenever possible.
+#define RUNTIME_FUNCTION_LIST_ALWAYS_1(F)                  \
+  /* Property access */                                    \
+  F(GetProperty, 2, 1)                                     \
+  F(KeyedGetProperty, 2, 1)                                \
+  F(DeleteProperty, 3, 1)                                  \
+  F(HasOwnProperty, 2, 1)                                  \
+  F(HasProperty, 2, 1)                                     \
+  F(HasElement, 2, 1)                                      \
+  F(IsPropertyEnumerable, 2, 1)                            \
+  F(GetPropertyNames, 1, 1)                                \
+  F(GetPropertyNamesFast, 1, 1)                            \
+  F(GetOwnPropertyNames, 2, 1)                             \
+  F(GetOwnElementNames, 1, 1)                              \
+  F(GetInterceptorInfo, 1, 1)                              \
+  F(GetNamedInterceptorPropertyNames, 1, 1)                \
+  F(GetIndexedInterceptorElementNames, 1, 1)               \
+  F(GetArgumentsProperty, 1, 1)                            \
+  F(ToFastProperties, 1, 1)                                \
+  F(FinishArrayPrototypeSetup, 1, 1)                       \
+  F(SpecialArrayFunctions, 0, 1)                           \
+  F(IsSloppyModeFunction, 1, 1)                            \
+  F(GetDefaultReceiver, 1, 1)                              \
+                                                           \
+  F(SetPrototype, 2, 1)                                    \
+  F(InternalSetPrototype, 2, 1)                            \
+  F(IsInPrototypeChain, 2, 1)                              \
+                                                           \
+  F(GetOwnProperty, 2, 1)                                  \
+                                                           \
+  F(IsExtensible, 1, 1)                                    \
+  F(PreventExtensions, 1, 1)                               \
+                                                           \
+  /* Utilities */                                          \
+  F(CheckIsBootstrapping, 0, 1)                            \
+  F(GetRootNaN, 0, 1)                                      \
+  F(Call, -1 /* >= 2 */, 1)                                \
+  F(Apply, 5, 1)                                           \
+  F(GetFunctionDelegate, 1, 1)                             \
+  F(GetConstructorDelegate, 1, 1)                          \
+  F(DeoptimizeFunction, 1, 1)                              \
+  F(ClearFunctionTypeFeedback, 1, 1)                       \
+  F(RunningInSimulator, 0, 1)                              \
+  F(IsConcurrentRecompilationSupported, 0, 1)              \
+  F(OptimizeFunctionOnNextCall, -1, 1)                     \
+  F(NeverOptimizeFunction, 1, 1)                           \
+  F(GetOptimizationStatus, -1, 1)                          \
+  F(GetOptimizationCount, 1, 1)                            \
+  F(UnblockConcurrentRecompilation, 0, 1)                  \
+  F(CompileForOnStackReplacement, 1, 1)                    \
+  F(SetAllocationTimeout, -1 /* 2 || 3 */, 1)              \
+  F(SetNativeFlag, 1, 1)                                   \
+  F(SetInlineBuiltinFlag, 1, 1)                            \
+  F(StoreArrayLiteralElement, 5, 1)                        \
+  F(DebugPrepareStepInIfStepping, 1, 1)                    \
+  F(DebugPushPromise, 1, 1)                                \
+  F(DebugPopPromise, 0, 1)                                 \
+  F(DebugPromiseEvent, 1, 1)                               \
+  F(DebugAsyncTaskEvent, 1, 1)                             \
+  F(PromiseRejectEvent, 3, 1)                              \
+  F(PromiseRevokeReject, 1, 1)                             \
+  F(PromiseHasHandlerSymbol, 0, 1)                         \
+  F(FlattenString, 1, 1)                                   \
+  F(LoadMutableDouble, 2, 1)                               \
+  F(TryMigrateInstance, 1, 1)                              \
+  F(NotifyContextDisposed, 0, 1)                           \
+                                                           \
+  /* Array join support */                                 \
+  F(PushIfAbsent, 2, 1)                                    \
+  F(ArrayConcat, 1, 1)                                     \
+                                                           \
+  /* Conversions */                                        \
+  F(ToBool, 1, 1)                                          \
+  F(Typeof, 1, 1)                                          \
+                                                           \
+  F(Booleanize, 2, 1) /* TODO(turbofan): Only temporary */ \
+                                                           \
+  F(StringToNumber, 1, 1)                                  \
+  F(StringParseInt, 2, 1)                                  \
+  F(StringParseFloat, 1, 1)                                \
+  F(StringToLowerCase, 1, 1)                               \
+  F(StringToUpperCase, 1, 1)                               \
+  F(StringSplit, 3, 1)                                     \
+  F(CharFromCode, 1, 1)                                    \
+  F(URIEscape, 1, 1)                                       \
+  F(URIUnescape, 1, 1)                                     \
+                                                           \
+  F(NumberToInteger, 1, 1)                                 \
+  F(NumberToIntegerMapMinusZero, 1, 1)                     \
+  F(NumberToJSUint32, 1, 1)                                \
+  F(NumberToJSInt32, 1, 1)                                 \
+                                                           \
+  /* Arithmetic operations */                              \
+  F(NumberAdd, 2, 1)                                       \
+  F(NumberSub, 2, 1)                                       \
+  F(NumberMul, 2, 1)                                       \
+  F(NumberDiv, 2, 1)                                       \
+  F(NumberMod, 2, 1)                                       \
+  F(NumberUnaryMinus, 1, 1)                                \
+  F(NumberImul, 2, 1)                                      \
+                                                           \
+  F(StringBuilderConcat, 3, 1)                             \
+  F(StringBuilderJoin, 3, 1)                               \
+  F(SparseJoinWithSeparator, 3, 1)                         \
+                                                           \
+  /* Bit operations */                                     \
+  F(NumberOr, 2, 1)                                        \
+  F(NumberAnd, 2, 1)                                       \
+  F(NumberXor, 2, 1)                                       \
+                                                           \
+  F(NumberShl, 2, 1)                                       \
+  F(NumberShr, 2, 1)                                       \
+  F(NumberSar, 2, 1)                                       \
+                                                           \
+  /* Comparisons */                                        \
+  F(NumberEquals, 2, 1)                                    \
+  F(StringEquals, 2, 1)                                    \
+                                                           \
+  F(NumberCompare, 3, 1)                                   \
+  F(SmiLexicographicCompare, 2, 1)                         \
+                                                           \
+  /* Math */                                               \
+  F(MathAcos, 1, 1)                                        \
+  F(MathAsin, 1, 1)                                        \
+  F(MathAtan, 1, 1)                                        \
+  F(MathFloorRT, 1, 1)                                     \
+  F(MathAtan2, 2, 1)                                       \
+  F(MathExpRT, 1, 1)                                       \
+  F(RoundNumber, 1, 1)                                     \
+  F(MathFround, 1, 1)                                      \
+  F(RemPiO2, 1, 1)                                         \
+                                                           \
+  /* Regular expressions */                                \
+  F(RegExpInitializeAndCompile, 3, 1)                      \
+  F(RegExpExecMultiple, 4, 1)                              \
+                                                           \
+  /* JSON */                                               \
+  F(ParseJson, 1, 1)                                       \
+  F(BasicJSONStringify, 1, 1)                              \
+  F(QuoteJSONString, 1, 1)                                 \
+                                                           \
+  /* Strings */                                            \
+  F(StringIndexOf, 3, 1)                                   \
+  F(StringLastIndexOf, 3, 1)                               \
+  F(StringLocaleCompare, 2, 1)                             \
+  F(StringReplaceGlobalRegExpWithString, 4, 1)             \
+  F(StringReplaceOneCharWithString, 3, 1)                  \
+  F(StringMatch, 3, 1)                                     \
+  F(StringTrim, 3, 1)                                      \
+  F(StringToArray, 2, 1)                                   \
+  F(NewStringWrapper, 1, 1)                                \
+  F(NewString, 2, 1)                                       \
+  F(TruncateString, 2, 1)                                  \
+                                                           \
+  /* Numbers */                                            \
+  F(NumberToRadixString, 2, 1)                             \
+  F(NumberToFixed, 2, 1)                                   \
+  F(NumberToExponential, 2, 1)                             \
+  F(NumberToPrecision, 2, 1)                               \
+  F(IsValidSmi, 1, 1)                                      \
+                                                           \
+  /* Classes support */                                    \
+  F(ToMethod, 2, 1)                                        \
+  F(HomeObjectSymbol, 0, 1)                                \
+  F(DefineClass, 6, 1)                                     \
+  F(DefineClassMethod, 3, 1)                               \
+  F(DefineClassGetter, 3, 1)                               \
+  F(DefineClassSetter, 3, 1)                               \
+  F(ClassGetSourceCode, 1, 1)                              \
+  F(ThrowNonMethodError, 0, 1)                             \
+  F(ThrowUnsupportedSuperError, 0, 1)                      \
+  F(LoadFromSuper, 3, 1)                                   \
+  F(LoadKeyedFromSuper, 3, 1)                              \
+  F(StoreToSuper_Strict, 4, 1)                             \
+  F(StoreToSuper_Sloppy, 4, 1)                             \
+  F(StoreKeyedToSuper_Strict, 4, 1)                        \
+  F(StoreKeyedToSuper_Sloppy, 4, 1)                        \
+  F(DefaultConstructorSuperCall, 0, 1)
+
+
+#define RUNTIME_FUNCTION_LIST_ALWAYS_2(F)              \
+  /* Reflection */                                     \
+  F(FunctionSetInstanceClassName, 2, 1)                \
+  F(FunctionSetLength, 2, 1)                           \
+  F(FunctionSetPrototype, 2, 1)                        \
+  F(FunctionGetName, 1, 1)                             \
+  F(FunctionSetName, 2, 1)                             \
+  F(FunctionNameShouldPrintAsAnonymous, 1, 1)          \
+  F(FunctionMarkNameShouldPrintAsAnonymous, 1, 1)      \
+  F(FunctionIsGenerator, 1, 1)                         \
+  F(FunctionIsArrow, 1, 1)                             \
+  F(FunctionIsConciseMethod, 1, 1)                     \
+  F(FunctionBindArguments, 4, 1)                       \
+  F(BoundFunctionGetBindings, 1, 1)                    \
+  F(FunctionRemovePrototype, 1, 1)                     \
+  F(FunctionGetSourceCode, 1, 1)                       \
+  F(FunctionGetScript, 1, 1)                           \
+  F(FunctionGetScriptSourcePosition, 1, 1)             \
+  F(FunctionGetPositionForOffset, 2, 1)                \
+  F(FunctionIsAPIFunction, 1, 1)                       \
+  F(FunctionIsBuiltin, 1, 1)                           \
+  F(GetScript, 1, 1)                                   \
+  F(CollectStackTrace, 2, 1)                           \
+  F(GetV8Version, 0, 1)                                \
+  F(GeneratorGetFunction, 1, 1)                        \
+  F(GeneratorGetContext, 1, 1)                         \
+  F(GeneratorGetReceiver, 1, 1)                        \
+  F(GeneratorGetContinuation, 1, 1)                    \
+  F(GeneratorGetSourcePosition, 1, 1)                  \
+                                                       \
+  F(SetCode, 2, 1)                                     \
+                                                       \
+  F(CreateApiFunction, 2, 1)                           \
+  F(IsTemplate, 1, 1)                                  \
+  F(GetTemplateField, 2, 1)                            \
+  F(DisableAccessChecks, 1, 1)                         \
+  F(EnableAccessChecks, 1, 1)                          \
+                                                       \
+  /* Dates */                                          \
+  F(DateCurrentTime, 0, 1)                             \
+  F(DateParseString, 2, 1)                             \
+  F(DateLocalTimezone, 1, 1)                           \
+  F(DateToUTC, 1, 1)                                   \
+  F(DateMakeDay, 2, 1)                                 \
+  F(DateSetValue, 3, 1)                                \
+  F(DateCacheVersion, 0, 1)                            \
+                                                       \
+  /* Globals */                                        \
+  F(CompileString, 3, 1)                               \
+                                                       \
+  /* Eval */                                           \
+  F(GlobalProxy, 1, 1)                                 \
+                                                       \
+  F(AddNamedProperty, 4, 1)                            \
+  F(AddPropertyForTemplate, 4, 1)                      \
+  F(SetProperty, 4, 1)                                 \
+  F(AddElement, 4, 1)                                  \
+  F(DefineApiAccessorProperty, 5, 1)                   \
+  F(DefineDataPropertyUnchecked, 4, 1)                 \
+  F(DefineAccessorPropertyUnchecked, 5, 1)             \
+  F(GetDataProperty, 2, 1)                             \
+                                                       \
+  /* Arrays */                                         \
+  F(RemoveArrayHoles, 2, 1)                            \
+  F(GetArrayKeys, 2, 1)                                \
+  F(MoveArrayContents, 2, 1)                           \
+  F(EstimateNumberOfElements, 1, 1)                    \
+  F(NormalizeElements, 1, 1)                           \
+  F(HasComplexElements, 1, 1)                          \
+                                                       \
+  /* Getters and Setters */                            \
+  F(LookupAccessor, 3, 1)                              \
+                                                       \
+  /* ES5 */                                            \
+  F(ObjectSeal, 1, 1)                                  \
+  F(ObjectFreeze, 1, 1)                                \
+                                                       \
+  /* Harmony modules */                                \
+  F(IsJSModule, 1, 1)                                  \
+                                                       \
+  /* Harmony symbols */                                \
+  F(CreateSymbol, 1, 1)                                \
+  F(CreatePrivateSymbol, 1, 1)                         \
+  F(CreateGlobalPrivateOwnSymbol, 1, 1)                \
+  F(CreatePrivateOwnSymbol, 1, 1)                      \
+  F(NewSymbolWrapper, 1, 1)                            \
+  F(SymbolDescription, 1, 1)                           \
+  F(SymbolRegistry, 0, 1)                              \
+  F(SymbolIsPrivate, 1, 1)                             \
+                                                       \
+  /* Harmony proxies */                                \
+  F(CreateJSProxy, 2, 1)                               \
+  F(CreateJSFunctionProxy, 4, 1)                       \
+  F(IsJSFunctionProxy, 1, 1)                           \
+  F(GetHandler, 1, 1)                                  \
+  F(GetCallTrap, 1, 1)                                 \
+  F(GetConstructTrap, 1, 1)                            \
+  F(Fix, 1, 1)                                         \
+                                                       \
+  /* ES6 collection iterators */                       \
+  F(SetIteratorInitialize, 3, 1)                       \
+  F(SetIteratorClone, 1, 1)                            \
+  F(SetIteratorNext, 2, 1)                             \
+  F(SetIteratorDetails, 1, 1)                          \
+  F(MapIteratorInitialize, 3, 1)                       \
+  F(MapIteratorClone, 1, 1)                            \
+  F(MapIteratorNext, 2, 1)                             \
+  F(MapIteratorDetails, 1, 1)                          \
+                                                       \
+  /* Harmony weak maps and sets */                     \
+  F(WeakCollectionInitialize, 1, 1)                    \
+  F(WeakCollectionGet, 2, 1)                           \
+  F(WeakCollectionHas, 2, 1)                           \
+  F(WeakCollectionDelete, 2, 1)                        \
+  F(WeakCollectionSet, 3, 1)                           \
+                                                       \
+  F(GetWeakMapEntries, 2, 1)                           \
+  F(GetWeakSetValues, 2, 1)                            \
+                                                       \
+  /* Harmony events */                                 \
+  F(EnqueueMicrotask, 1, 1)                            \
+  F(RunMicrotasks, 0, 1)                               \
+                                                       \
+  /* Harmony observe */                                \
+  F(IsObserved, 1, 1)                                  \
+  F(SetIsObserved, 1, 1)                               \
+  F(GetObservationState, 0, 1)                         \
+  F(ObservationWeakMapCreate, 0, 1)                    \
+  F(ObserverObjectAndRecordHaveSameOrigin, 3, 1)       \
+  F(ObjectWasCreatedInCurrentOrigin, 1, 1)             \
+  F(GetObjectContextObjectObserve, 1, 1)               \
+  F(GetObjectContextObjectGetNotifier, 1, 1)           \
+  F(GetObjectContextNotifierPerformChange, 1, 1)       \
+  F(DeliverObservationChangeRecords, 2, 1)             \
+                                                       \
+  /* Harmony typed arrays */                           \
+  F(ArrayBufferInitialize, 2, 1)                       \
+  F(ArrayBufferSliceImpl, 3, 1)                        \
+  F(ArrayBufferIsView, 1, 1)                           \
+  F(ArrayBufferNeuter, 1, 1)                           \
+                                                       \
+  F(IsTypedArray, 1, 1)                                \
+  F(TypedArrayInitializeFromArrayLike, 4, 1)           \
+  F(TypedArrayGetBuffer, 1, 1)                         \
+  F(TypedArraySetFastCases, 3, 1)                      \
+                                                       \
+  F(DataViewGetBuffer, 1, 1)                           \
+  F(DataViewGetInt8, 3, 1)                             \
+  F(DataViewGetUint8, 3, 1)                            \
+  F(DataViewGetInt16, 3, 1)                            \
+  F(DataViewGetUint16, 3, 1)                           \
+  F(DataViewGetInt32, 3, 1)                            \
+  F(DataViewGetUint32, 3, 1)                           \
+  F(DataViewGetFloat32, 3, 1)                          \
+  F(DataViewGetFloat64, 3, 1)                          \
+                                                       \
+  F(DataViewSetInt8, 4, 1)                             \
+  F(DataViewSetUint8, 4, 1)                            \
+  F(DataViewSetInt16, 4, 1)                            \
+  F(DataViewSetUint16, 4, 1)                           \
+  F(DataViewSetInt32, 4, 1)                            \
+  F(DataViewSetUint32, 4, 1)                           \
+  F(DataViewSetFloat32, 4, 1)                          \
+  F(DataViewSetFloat64, 4, 1)                          \
+                                                       \
+  /* Statements */                                     \
+  F(NewObjectFromBound, 1, 1)                          \
+                                                       \
+  /* Declarations and initialization */                \
+  F(InitializeVarGlobal, 3, 1)                         \
+  F(OptimizeObjectForAddingMultipleProperties, 2, 1)   \
+                                                       \
+  /* Debugging */                                      \
+  F(DebugPrint, 1, 1)                                  \
+  F(GlobalPrint, 1, 1)                                 \
+  F(DebugTrace, 0, 1)                                  \
+  F(TraceEnter, 0, 1)                                  \
+  F(TraceExit, 1, 1)                                   \
+  F(Abort, 1, 1)                                       \
+  F(AbortJS, 1, 1)                                     \
+  F(NativeScriptsCount, 0, 1)                          \
+  /* ES5 */                                            \
+  F(OwnKeys, 1, 1)                                     \
+                                                       \
+  /* Message objects */                                \
+  F(MessageGetStartPosition, 1, 1)                     \
+  F(MessageGetScript, 1, 1)                            \
+                                                       \
+  /* Pseudo functions - handled as macros by parser */ \
+  F(IS_VAR, 1, 1)                                      \
+                                                       \
+  /* expose boolean functions from objects-inl.h */    \
+  F(HasFastSmiElements, 1, 1)                          \
+  F(HasFastSmiOrObjectElements, 1, 1)                  \
+  F(HasFastObjectElements, 1, 1)                       \
+  F(HasFastDoubleElements, 1, 1)                       \
+  F(HasFastHoleyElements, 1, 1)                        \
+  F(HasDictionaryElements, 1, 1)                       \
+  F(HasSloppyArgumentsElements, 1, 1)                  \
+  F(HasExternalUint8ClampedElements, 1, 1)             \
+  F(HasExternalArrayElements, 1, 1)                    \
+  F(HasExternalInt8Elements, 1, 1)                     \
+  F(HasExternalUint8Elements, 1, 1)                    \
+  F(HasExternalInt16Elements, 1, 1)                    \
+  F(HasExternalUint16Elements, 1, 1)                   \
+  F(HasExternalInt32Elements, 1, 1)                    \
+  F(HasExternalUint32Elements, 1, 1)                   \
+  F(HasExternalFloat32Elements, 1, 1)                  \
+  F(HasExternalFloat64Elements, 1, 1)                  \
+  F(HasFixedUint8ClampedElements, 1, 1)                \
+  F(HasFixedInt8Elements, 1, 1)                        \
+  F(HasFixedUint8Elements, 1, 1)                       \
+  F(HasFixedInt16Elements, 1, 1)                       \
+  F(HasFixedUint16Elements, 1, 1)                      \
+  F(HasFixedInt32Elements, 1, 1)                       \
+  F(HasFixedUint32Elements, 1, 1)                      \
+  F(HasFixedFloat32Elements, 1, 1)                     \
+  F(HasFixedFloat64Elements, 1, 1)                     \
+  F(HasFastProperties, 1, 1)                           \
+  F(TransitionElementsKind, 2, 1)                      \
+  F(HaveSameMap, 2, 1)                                 \
+  F(IsJSGlobalProxy, 1, 1)                             \
+  F(ForInCacheArrayLength, 2, 1) /* TODO(turbofan): Only temporary */
+
+
+#define RUNTIME_FUNCTION_LIST_ALWAYS_3(F)                    \
+  /* String and Regexp */                                    \
+  F(NumberToStringRT, 1, 1)                                  \
+  F(RegExpConstructResult, 3, 1)                             \
+  F(RegExpExecRT, 4, 1)                                      \
+  F(StringAdd, 2, 1)                                         \
+  F(SubString, 3, 1)                                         \
+  F(InternalizeString, 1, 1)                                 \
+  F(StringCompare, 2, 1)                                     \
+  F(StringCharCodeAtRT, 2, 1)                                \
+  F(GetFromCache, 2, 1)                                      \
+                                                             \
+  /* Compilation */                                          \
+  F(CompileLazy, 1, 1)                                       \
+  F(CompileOptimized, 2, 1)                                  \
+  F(TryInstallOptimizedCode, 1, 1)                           \
+  F(NotifyDeoptimized, 1, 1)                                 \
+  F(NotifyStubFailure, 0, 1)                                 \
+                                                             \
+  /* Utilities */                                            \
+  F(AllocateInNewSpace, 1, 1)                                \
+  F(AllocateInTargetSpace, 2, 1)                             \
+  F(AllocateHeapNumber, 0, 1)                                \
+  F(NumberToSmi, 1, 1)                                       \
+  F(NumberToStringSkipCache, 1, 1)                           \
+                                                             \
+  F(NewArguments, 1, 1) /* TODO(turbofan): Only temporary */ \
+  F(NewSloppyArguments, 3, 1)                                \
+  F(NewStrictArguments, 3, 1)                                \
+                                                             \
+  /* Harmony generators */                                   \
+  F(CreateJSGeneratorObject, 0, 1)                           \
+  F(SuspendJSGeneratorObject, 1, 1)                          \
+  F(ResumeJSGeneratorObject, 3, 1)                           \
+  F(GeneratorClose, 1, 1)                                    \
+                                                             \
+  /* Arrays */                                               \
+  F(ArrayConstructor, -1, 1)                                 \
+  F(InternalArrayConstructor, -1, 1)                         \
+                                                             \
+  /* Literals */                                             \
+  F(MaterializeRegExpLiteral, 4, 1)                          \
+  F(CreateObjectLiteral, 4, 1)                               \
+  F(CreateArrayLiteral, 4, 1)                                \
+  F(CreateArrayLiteralStubBailout, 3, 1)                     \
+                                                             \
+  /* Statements */                                           \
+  F(NewClosure, 3, 1)                                        \
+  F(NewClosureFromStubFailure, 1, 1)                         \
+  F(NewObject, 1, 1)                                         \
+  F(NewObjectWithAllocationSite, 2, 1)                       \
+  F(FinalizeInstanceSize, 1, 1)                              \
+  F(Throw, 1, 1)                                             \
+  F(ReThrow, 1, 1)                                           \
+  F(ThrowReferenceError, 1, 1)                               \
+  F(ThrowNotDateError, 0, 1)                                 \
+  F(ThrowConstAssignError, 0, 1)                             \
+  F(StackGuard, 0, 1)                                        \
+  F(Interrupt, 0, 1)                                         \
+  F(PromoteScheduledException, 0, 1)                         \
+                                                             \
+  /* Contexts */                                             \
+  F(NewScriptContext, 2, 1)                                  \
+  F(NewFunctionContext, 1, 1)                                \
+  F(PushWithContext, 2, 1)                                   \
+  F(PushCatchContext, 3, 1)                                  \
+  F(PushBlockContext, 2, 1)                                  \
+  F(PushModuleContext, 2, 1)                                 \
+  F(DeleteLookupSlot, 2, 1)                                  \
+  F(StoreLookupSlot, 4, 1)                                   \
+                                                             \
+  /* Declarations and initialization */                      \
+  F(DeclareGlobals, 3, 1)                                    \
+  F(DeclareModules, 1, 1)                                    \
+  F(DeclareLookupSlot, 4, 1)                                 \
+  F(InitializeConstGlobal, 2, 1)                             \
+  F(InitializeLegacyConstLookupSlot, 3, 1)                   \
+                                                             \
+  /* Maths */                                                \
+  F(MathPowSlow, 2, 1)                                       \
+  F(MathPowRT, 2, 1)
+
+
+#define RUNTIME_FUNCTION_LIST_RETURN_PAIR(F)              \
+  F(LoadLookupSlot, 2, 2)                                 \
+  F(LoadLookupSlotNoReferenceError, 2, 2)                 \
+  F(ResolvePossiblyDirectEval, 6, 2)                      \
+  F(ForInInit, 2, 2) /* TODO(turbofan): Only temporary */ \
+  F(ForInNext, 4, 2) /* TODO(turbofan): Only temporary */
+
+
+#define RUNTIME_FUNCTION_LIST_DEBUGGER(F)           \
+  /* Debugger support*/                             \
+  F(DebugBreak, 0, 1)                               \
+  F(SetDebugEventListener, 2, 1)                    \
+  F(Break, 0, 1)                                    \
+  F(DebugGetPropertyDetails, 2, 1)                  \
+  F(DebugGetProperty, 2, 1)                         \
+  F(DebugPropertyTypeFromDetails, 1, 1)             \
+  F(DebugPropertyAttributesFromDetails, 1, 1)       \
+  F(DebugPropertyIndexFromDetails, 1, 1)            \
+  F(DebugNamedInterceptorPropertyValue, 2, 1)       \
+  F(DebugIndexedInterceptorElementValue, 2, 1)      \
+  F(CheckExecutionState, 1, 1)                      \
+  F(GetFrameCount, 1, 1)                            \
+  F(GetFrameDetails, 2, 1)                          \
+  F(GetScopeCount, 2, 1)                            \
+  F(GetStepInPositions, 2, 1)                       \
+  F(GetScopeDetails, 4, 1)                          \
+  F(GetAllScopesDetails, 4, 1)                      \
+  F(GetFunctionScopeCount, 1, 1)                    \
+  F(GetFunctionScopeDetails, 2, 1)                  \
+  F(SetScopeVariableValue, 6, 1)                    \
+  F(DebugPrintScopes, 0, 1)                         \
+  F(GetThreadCount, 1, 1)                           \
+  F(GetThreadDetails, 2, 1)                         \
+  F(SetDisableBreak, 1, 1)                          \
+  F(GetBreakLocations, 2, 1)                        \
+  F(SetFunctionBreakPoint, 3, 1)                    \
+  F(SetScriptBreakPoint, 4, 1)                      \
+  F(ClearBreakPoint, 1, 1)                          \
+  F(ChangeBreakOnException, 2, 1)                   \
+  F(IsBreakOnException, 1, 1)                       \
+  F(PrepareStep, 4, 1)                              \
+  F(ClearStepping, 0, 1)                            \
+  F(DebugEvaluate, 6, 1)                            \
+  F(DebugEvaluateGlobal, 4, 1)                      \
+  F(DebugGetLoadedScripts, 0, 1)                    \
+  F(DebugReferencedBy, 3, 1)                        \
+  F(DebugConstructedBy, 2, 1)                       \
+  F(DebugGetPrototype, 1, 1)                        \
+  F(DebugSetScriptSource, 2, 1)                     \
+  F(DebugCallbackSupportsStepping, 1, 1)            \
+  F(SystemBreak, 0, 1)                              \
+  F(DebugDisassembleFunction, 1, 1)                 \
+  F(DebugDisassembleConstructor, 1, 1)              \
+  F(FunctionGetInferredName, 1, 1)                  \
+  F(LiveEditFindSharedFunctionInfosForScript, 1, 1) \
+  F(LiveEditGatherCompileInfo, 2, 1)                \
+  F(LiveEditReplaceScript, 3, 1)                    \
+  F(LiveEditReplaceFunctionCode, 2, 1)              \
+  F(LiveEditFunctionSourceUpdated, 1, 1)            \
+  F(LiveEditFunctionSetScript, 2, 1)                \
+  F(LiveEditReplaceRefToNestedFunction, 3, 1)       \
+  F(LiveEditPatchFunctionPositions, 2, 1)           \
+  F(LiveEditCheckAndDropActivations, 2, 1)          \
+  F(LiveEditCompareStrings, 2, 1)                   \
+  F(LiveEditRestartFrame, 2, 1)                     \
+  F(GetFunctionCodePositionFromSource, 2, 1)        \
+  F(ExecuteInDebugContext, 2, 1)                    \
+                                                    \
+  F(SetFlags, 1, 1)                                 \
+  F(CollectGarbage, 1, 1)                           \
+  F(GetHeapUsage, 0, 1)
+
+
+#ifdef V8_I18N_SUPPORT
+#define RUNTIME_FUNCTION_LIST_I18N_SUPPORT(F) \
+  /* i18n support */                          \
+  /* Standalone, helper methods. */           \
+  F(CanonicalizeLanguageTag, 1, 1)            \
+  F(AvailableLocalesOf, 1, 1)                 \
+  F(GetDefaultICULocale, 0, 1)                \
+  F(GetLanguageTagVariants, 1, 1)             \
+  F(IsInitializedIntlObject, 1, 1)            \
+  F(IsInitializedIntlObjectOfType, 2, 1)      \
+  F(MarkAsInitializedIntlObjectOfType, 3, 1)  \
+  F(GetImplFromInitializedIntlObject, 1, 1)   \
+                                              \
+  /* Date format and parse. */                \
+  F(CreateDateTimeFormat, 3, 1)               \
+  F(InternalDateFormat, 2, 1)                 \
+  F(InternalDateParse, 2, 1)                  \
+                                              \
+  /* Number format and parse. */              \
+  F(CreateNumberFormat, 3, 1)                 \
+  F(InternalNumberFormat, 2, 1)               \
+  F(InternalNumberParse, 2, 1)                \
+                                              \
+  /* Collator. */                             \
+  F(CreateCollator, 3, 1)                     \
+  F(InternalCompare, 3, 1)                    \
+                                              \
+  /* String.prototype.normalize. */           \
+  F(StringNormalize, 2, 1)                    \
+                                              \
+  /* Break iterator. */                       \
+  F(CreateBreakIterator, 3, 1)                \
+  F(BreakIteratorAdoptText, 2, 1)             \
+  F(BreakIteratorFirst, 1, 1)                 \
+  F(BreakIteratorNext, 1, 1)                  \
+  F(BreakIteratorCurrent, 1, 1)               \
+  F(BreakIteratorBreakType, 1, 1)
+
+#else
+#define RUNTIME_FUNCTION_LIST_I18N_SUPPORT(F)
+#endif
+
+
+// ----------------------------------------------------------------------------
+// RUNTIME_FUNCTION_LIST defines all runtime functions accessed
+// either directly by id (via the code generator), or indirectly
+// via a native call by name (from within JS code).
+// Entries have the form F(name, number of arguments, number of return values).
+
+#define RUNTIME_FUNCTION_LIST_RETURN_OBJECT(F) \
+  RUNTIME_FUNCTION_LIST_ALWAYS_1(F)            \
+  RUNTIME_FUNCTION_LIST_ALWAYS_2(F)            \
+  RUNTIME_FUNCTION_LIST_ALWAYS_3(F)            \
+  RUNTIME_FUNCTION_LIST_DEBUGGER(F)            \
+  RUNTIME_FUNCTION_LIST_I18N_SUPPORT(F)
+
+
+#define RUNTIME_FUNCTION_LIST(F)         \
+  RUNTIME_FUNCTION_LIST_RETURN_OBJECT(F) \
+  RUNTIME_FUNCTION_LIST_RETURN_PAIR(F)
+
+// ----------------------------------------------------------------------------
+// INLINE_FUNCTION_LIST defines all inlined functions accessed
+// with a native call of the form %_name from within JS code.
+// Entries have the form F(name, number of arguments, number of return values).
+#define INLINE_FUNCTION_LIST(F)                             \
+  F(IsSmi, 1, 1)                                            \
+  F(IsNonNegativeSmi, 1, 1)                                 \
+  F(IsArray, 1, 1)                                          \
+  F(IsRegExp, 1, 1)                                         \
+  F(IsJSProxy, 1, 1)                                        \
+  F(IsConstructCall, 0, 1)                                  \
+  F(CallFunction, -1 /* receiver + n args + function */, 1) \
+  F(ArgumentsLength, 0, 1)                                  \
+  F(Arguments, 1, 1)                                        \
+  F(ValueOf, 1, 1)                                          \
+  F(SetValueOf, 2, 1)                                       \
+  F(DateField, 2 /* date object, field index */, 1)         \
+  F(StringCharFromCode, 1, 1)                               \
+  F(StringCharAt, 2, 1)                                     \
+  F(OneByteSeqStringSetChar, 3, 1)                          \
+  F(TwoByteSeqStringSetChar, 3, 1)                          \
+  F(ObjectEquals, 2, 1)                                     \
+  F(IsObject, 1, 1)                                         \
+  F(IsFunction, 1, 1)                                       \
+  F(IsUndetectableObject, 1, 1)                             \
+  F(IsSpecObject, 1, 1)                                     \
+  F(IsStringWrapperSafeForDefaultValueOf, 1, 1)             \
+  F(MathPow, 2, 1)                                          \
+  F(IsMinusZero, 1, 1)                                      \
+  F(HasCachedArrayIndex, 1, 1)                              \
+  F(GetCachedArrayIndex, 1, 1)                              \
+  F(FastOneByteArrayJoin, 2, 1)                             \
+  F(GeneratorNext, 2, 1)                                    \
+  F(GeneratorThrow, 2, 1)                                   \
+  F(DebugBreakInOptimizedCode, 0, 1)                        \
+  F(ClassOf, 1, 1)                                          \
+  F(StringCharCodeAt, 2, 1)                                 \
+  F(StringAdd, 2, 1)                                        \
+  F(SubString, 3, 1)                                        \
+  F(StringCompare, 2, 1)                                    \
+  F(RegExpExec, 4, 1)                                       \
+  F(RegExpConstructResult, 3, 1)                            \
+  F(GetFromCache, 2, 1)                                     \
+  F(NumberToString, 1, 1)                                   \
+  F(DebugIsActive, 0, 1)
+
+
+// ----------------------------------------------------------------------------
+// INLINE_OPTIMIZED_FUNCTION_LIST defines all inlined functions accessed
+// with a native call of the form %_name from within JS code that also have
+// a corresponding runtime function, that is called from non-optimized code.
+// For the benefit of (fuzz) tests, the runtime version can also be called
+// directly as %name (i.e. without the leading underscore).
+// Entries have the form F(name, number of arguments, number of return values).
+#define INLINE_OPTIMIZED_FUNCTION_LIST(F) \
+  /* Typed Arrays */                      \
+  F(TypedArrayInitialize, 5, 1)           \
+  F(DataViewInitialize, 4, 1)             \
+  F(MaxSmi, 0, 1)                         \
+  F(TypedArrayMaxSizeInHeap, 0, 1)        \
+  F(ArrayBufferViewGetByteLength, 1, 1)   \
+  F(ArrayBufferViewGetByteOffset, 1, 1)   \
+  F(TypedArrayGetLength, 1, 1)            \
+  /* ArrayBuffer */                       \
+  F(ArrayBufferGetByteLength, 1, 1)       \
+  /* Maths */                             \
+  F(ConstructDouble, 2, 1)                \
+  F(DoubleHi, 1, 1)                       \
+  F(DoubleLo, 1, 1)                       \
+  F(MathSqrtRT, 1, 1)                     \
+  F(MathLogRT, 1, 1)                      \
+  /* ES6 Collections */                   \
+  F(MapClear, 1, 1)                       \
+  F(MapDelete, 2, 1)                      \
+  F(MapGet, 2, 1)                         \
+  F(MapGetSize, 1, 1)                     \
+  F(MapHas, 2, 1)                         \
+  F(MapInitialize, 1, 1)                  \
+  F(MapSet, 3, 1)                         \
+  F(SetAdd, 2, 1)                         \
+  F(SetClear, 1, 1)                       \
+  F(SetDelete, 2, 1)                      \
+  F(SetGetSize, 1, 1)                     \
+  F(SetHas, 2, 1)                         \
+  F(SetInitialize, 1, 1)                  \
+  /* Arrays */                            \
+  F(HasFastPackedElements, 1, 1)          \
+  F(GetPrototype, 1, 1)
+
+
+//---------------------------------------------------------------------------
+// Runtime provides access to all C++ runtime functions.
+
+class RuntimeState {
+ public:
+  unibrow::Mapping<unibrow::ToUppercase, 128>* to_upper_mapping() {
+    return &to_upper_mapping_;
+  }
+  unibrow::Mapping<unibrow::ToLowercase, 128>* to_lower_mapping() {
+    return &to_lower_mapping_;
+  }
+
+ private:
+  RuntimeState() {}
+  unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping_;
+  unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping_;
+
+  friend class Isolate;
+  friend class Runtime;
+
+  DISALLOW_COPY_AND_ASSIGN(RuntimeState);
+};
+
+
+class JavaScriptFrameIterator;  // Forward declaration.
+
+
+class Runtime : public AllStatic {
+ public:
+  enum FunctionId {
+#define F(name, nargs, ressize) k##name,
+    RUNTIME_FUNCTION_LIST(F) INLINE_OPTIMIZED_FUNCTION_LIST(F)
+#undef F
+#define F(name, nargs, ressize) kInline##name,
+    INLINE_FUNCTION_LIST(F)
+#undef F
+#define F(name, nargs, ressize) kInlineOptimized##name,
+    INLINE_OPTIMIZED_FUNCTION_LIST(F)
+#undef F
+    kNumFunctions,
+    kFirstInlineFunction = kInlineIsSmi
+  };
+
+  enum IntrinsicType { RUNTIME, INLINE, INLINE_OPTIMIZED };
+
+  // Intrinsic function descriptor.
+  struct Function {
+    FunctionId function_id;
+    IntrinsicType intrinsic_type;
+    // The JS name of the function.
+    const char* name;
+
+    // The C++ (native) entry point.  NULL if the function is inlined.
+    byte* entry;
+
+    // The number of arguments expected. nargs is -1 if the function takes
+    // a variable number of arguments.
+    int nargs;
+    // Size of result.  Most functions return a single pointer, size 1.
+    int result_size;
+  };
+
+  static const int kNotFound = -1;
+
+  // Add internalized strings for all the intrinsic function names to a
+  // StringDictionary.
+  static void InitializeIntrinsicFunctionNames(Isolate* isolate,
+                                               Handle<NameDictionary> dict);
+
+  // Get the intrinsic function with the given name, which must be internalized.
+  static const Function* FunctionForName(Handle<String> name);
+
+  // Get the intrinsic function with the given FunctionId.
+  static const Function* FunctionForId(FunctionId id);
+
+  // Get the intrinsic function with the given function entry address.
+  static const Function* FunctionForEntry(Address ref);
+
+  // TODO(1240886): Some of the following methods are *not* handle safe, but
+  // accept handle arguments. This seems fragile.
+
+  // Support getting the characters in a string using [] notation as
+  // in Firefox/SpiderMonkey, Safari and Opera.
+  MUST_USE_RESULT static MaybeHandle<Object> GetElementOrCharAt(
+      Isolate* isolate, Handle<Object> object, uint32_t index);
+
+  MUST_USE_RESULT static MaybeHandle<Object> SetObjectProperty(
+      Isolate* isolate, Handle<Object> object, Handle<Object> key,
+      Handle<Object> value, StrictMode strict_mode);
+
+  MUST_USE_RESULT static MaybeHandle<Object> DefineObjectProperty(
+      Handle<JSObject> object, Handle<Object> key, Handle<Object> value,
+      PropertyAttributes attr);
+
+  MUST_USE_RESULT static MaybeHandle<Object> GetObjectProperty(
+      Isolate* isolate, Handle<Object> object, Handle<Object> key);
+
+  MUST_USE_RESULT static MaybeHandle<Object> GetPrototype(
+      Isolate* isolate, Handle<Object> object);
+
+  MUST_USE_RESULT static MaybeHandle<Name> ToName(Isolate* isolate,
+                                                  Handle<Object> key);
+
+  static void SetupArrayBuffer(Isolate* isolate,
+                               Handle<JSArrayBuffer> array_buffer,
+                               bool is_external, void* data,
+                               size_t allocated_length);
+
+  static bool SetupArrayBufferAllocatingData(Isolate* isolate,
+                                             Handle<JSArrayBuffer> array_buffer,
+                                             size_t allocated_length,
+                                             bool initialize = true);
+
+  static void NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer);
+
+  static void FreeArrayBuffer(Isolate* isolate,
+                              JSArrayBuffer* phantom_array_buffer);
+
+  static int FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index);
+
+  enum TypedArrayId {
+    // arrayIds below should be synchromized with typedarray.js natives.
+    ARRAY_ID_UINT8 = 1,
+    ARRAY_ID_INT8 = 2,
+    ARRAY_ID_UINT16 = 3,
+    ARRAY_ID_INT16 = 4,
+    ARRAY_ID_UINT32 = 5,
+    ARRAY_ID_INT32 = 6,
+    ARRAY_ID_FLOAT32 = 7,
+    ARRAY_ID_FLOAT64 = 8,
+    ARRAY_ID_UINT8_CLAMPED = 9,
+    ARRAY_ID_FIRST = ARRAY_ID_UINT8,
+    ARRAY_ID_LAST = ARRAY_ID_UINT8_CLAMPED
+  };
+
+  static void ArrayIdToTypeAndSize(int array_id, ExternalArrayType* type,
+                                   ElementsKind* external_elements_kind,
+                                   ElementsKind* fixed_elements_kind,
+                                   size_t* element_size);
+
+  // Used in runtime.cc and hydrogen's VisitArrayLiteral.
+  MUST_USE_RESULT static MaybeHandle<Object> CreateArrayLiteralBoilerplate(
+      Isolate* isolate, Handle<FixedArray> literals,
+      Handle<FixedArray> elements);
+};
+
+
+std::ostream& operator<<(std::ostream&, Runtime::FunctionId);
+
+//---------------------------------------------------------------------------
+// Constants used by interface to runtime functions.
+
+class AllocateDoubleAlignFlag : public BitField<bool, 0, 1> {};
+class AllocateTargetSpace : public BitField<AllocationSpace, 1, 3> {};
+
+class DeclareGlobalsEvalFlag : public BitField<bool, 0, 1> {};
+class DeclareGlobalsNativeFlag : public BitField<bool, 1, 1> {};
+class DeclareGlobalsStrictMode : public BitField<StrictMode, 2, 1> {};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_RUNTIME_RUNTIME_H_
diff --git a/src/safepoint-table.cc b/src/safepoint-table.cc
index 89500e2..aaa32b9 100644
--- a/src/safepoint-table.cc
+++ b/src/safepoint-table.cc
@@ -61,7 +61,8 @@
 }
 
 
-void SafepointTable::PrintEntry(unsigned index, OStream& os) const {  // NOLINT
+void SafepointTable::PrintEntry(unsigned index,
+                                std::ostream& os) const {  // NOLINT
   disasm::NameConverter converter;
   SafepointEntry entry = GetEntry(index);
   uint8_t* bits = entry.bits();
@@ -86,7 +87,7 @@
 }
 
 
-void SafepointTable::PrintBits(OStream& os,  // NOLINT
+void SafepointTable::PrintBits(std::ostream& os,  // NOLINT
                                uint8_t byte, int digits) {
   DCHECK(digits >= 0 && digits <= kBitsPerByte);
   for (int i = 0; i < digits; i++) {
diff --git a/src/safepoint-table.h b/src/safepoint-table.h
index 5fbfe41..a7719e0 100644
--- a/src/safepoint-table.h
+++ b/src/safepoint-table.h
@@ -104,7 +104,7 @@
   // Returns the entry for the given pc.
   SafepointEntry FindEntry(Address pc) const;
 
-  void PrintEntry(unsigned index, OStream& os) const;  // NOLINT
+  void PrintEntry(unsigned index, std::ostream& os) const;  // NOLINT
 
  private:
   static const uint8_t kNoRegisters = 0xFF;
@@ -127,7 +127,7 @@
     return GetPcOffsetLocation(index) + kPcSize;
   }
 
-  static void PrintBits(OStream& os,  // NOLINT
+  static void PrintBits(std::ostream& os,  // NOLINT
                         uint8_t byte, int digits);
 
   DisallowHeapAllocation no_allocation_;
diff --git a/src/sampler.cc b/src/sampler.cc
index 394efeb..760df80 100644
--- a/src/sampler.cc
+++ b/src/sampler.cc
@@ -226,13 +226,13 @@
 #if defined(USE_SIMULATOR)
 class SimulatorHelper {
  public:
-  inline bool Init(Sampler* sampler, Isolate* isolate) {
+  inline bool Init(Isolate* isolate) {
     simulator_ = isolate->thread_local_top()->simulator_;
     // Check if there is active simulator.
     return simulator_ != NULL;
   }
 
-  inline void FillRegisters(RegisterState* state) {
+  inline void FillRegisters(v8::RegisterState* state) {
 #if V8_TARGET_ARCH_ARM
     state->pc = reinterpret_cast<Address>(simulator_->get_pc());
     state->sp = reinterpret_cast<Address>(simulator_->get_register(
@@ -241,22 +241,16 @@
         Simulator::r11));
 #elif V8_TARGET_ARCH_ARM64
     if (simulator_->sp() == 0 || simulator_->fp() == 0) {
-      // It possible that the simulator is interrupted while it is updating
+      // It's possible that the simulator is interrupted while it is updating
       // the sp or fp register. ARM64 simulator does this in two steps:
-      // first setting it to zero and then setting it to the new value.
+      // first setting it to zero and then setting it to a new value.
       // Bailout if sp/fp doesn't contain the new value.
       return;
     }
     state->pc = reinterpret_cast<Address>(simulator_->pc());
     state->sp = reinterpret_cast<Address>(simulator_->sp());
     state->fp = reinterpret_cast<Address>(simulator_->fp());
-#elif V8_TARGET_ARCH_MIPS
-    state->pc = reinterpret_cast<Address>(simulator_->get_pc());
-    state->sp = reinterpret_cast<Address>(simulator_->get_register(
-        Simulator::sp));
-    state->fp = reinterpret_cast<Address>(simulator_->get_register(
-        Simulator::fp));
-#elif V8_TARGET_ARCH_MIPS64
+#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
     state->pc = reinterpret_cast<Address>(simulator_->get_pc());
     state->sp = reinterpret_cast<Address>(simulator_->get_register(
         Simulator::sp));
@@ -341,7 +335,7 @@
   USE(info);
   if (signal != SIGPROF) return;
   Isolate* isolate = Isolate::UnsafeCurrent();
-  if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
+  if (isolate == NULL || !isolate->IsInUse()) {
     // We require a fully initialized and entered isolate.
     return;
   }
@@ -353,11 +347,11 @@
   Sampler* sampler = isolate->logger()->sampler();
   if (sampler == NULL) return;
 
-  RegisterState state;
+  v8::RegisterState state;
 
 #if defined(USE_SIMULATOR)
   SimulatorHelper helper;
-  if (!helper.Init(sampler, isolate)) return;
+  if (!helper.Init(isolate)) return;
   helper.FillRegisters(&state);
   // It possible that the simulator is interrupted while it is updating
   // the sp or fp register. ARM64 simulator does this in two steps:
@@ -380,8 +374,7 @@
   state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
   state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
 #elif V8_HOST_ARCH_ARM
-#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
-    (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+#if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
   // Old GLibc ARM versions used a gregs[] array to access the register
   // values from mcontext_t.
   state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
@@ -391,8 +384,7 @@
   state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
   state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
   state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
-#endif  // defined(__GLIBC__) && !defined(__UCLIBC__) &&
-        // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+#endif  // V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
 #elif V8_HOST_ARCH_ARM64
   state.pc = reinterpret_cast<Address>(mcontext.pc);
   state.sp = reinterpret_cast<Address>(mcontext.sp);
@@ -548,7 +540,6 @@
         // profiled. We must not suspend.
         for (int i = 0; i < active_samplers_.length(); ++i) {
           Sampler* sampler = active_samplers_.at(i);
-          if (!sampler->isolate()->IsInitialized()) continue;
           if (!sampler->IsProfiling()) continue;
           sampler->DoSample();
         }
@@ -577,20 +568,17 @@
 // StackTracer implementation
 //
 DISABLE_ASAN void TickSample::Init(Isolate* isolate,
-                                   const RegisterState& regs) {
-  DCHECK(isolate->IsInitialized());
+                                   const v8::RegisterState& regs,
+                                   RecordCEntryFrame record_c_entry_frame) {
   timestamp = base::TimeTicks::HighResolutionNow();
-  pc = regs.pc;
+  pc = reinterpret_cast<Address>(regs.pc);
   state = isolate->current_vm_state();
 
   // Avoid collecting traces while doing GC.
   if (state == GC) return;
 
   Address js_entry_sp = isolate->js_entry_sp();
-  if (js_entry_sp == 0) {
-    // Not executing JS now.
-    return;
-  }
+  if (js_entry_sp == 0) return;  // Not executing JS now.
 
   ExternalCallbackScope* scope = isolate->external_callback_scope();
   Address handler = Isolate::handler(isolate->thread_local_top());
@@ -603,18 +591,44 @@
   } else {
     // Sample potential return address value for frameless invocation of
     // stubs (we'll figure out later, if this value makes sense).
-    tos = Memory::Address_at(regs.sp);
+    tos = Memory::Address_at(reinterpret_cast<Address>(regs.sp));
     has_external_callback = false;
   }
 
-  SafeStackFrameIterator it(isolate, regs.fp, regs.sp, js_entry_sp);
+  SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp),
+                            reinterpret_cast<Address>(regs.sp), js_entry_sp);
   top_frame_type = it.top_frame_type();
-  unsigned i = 0;
-  while (!it.done() && i < TickSample::kMaxFramesCount) {
-    stack[i++] = it.frame()->pc();
+
+  SampleInfo info;
+  GetStackSample(isolate, regs, record_c_entry_frame,
+                 reinterpret_cast<void**>(&stack[0]), kMaxFramesCount, &info);
+  frames_count = static_cast<unsigned>(info.frames_count);
+}
+
+
+void TickSample::GetStackSample(Isolate* isolate, const v8::RegisterState& regs,
+                                RecordCEntryFrame record_c_entry_frame,
+                                void** frames, size_t frames_limit,
+                                v8::SampleInfo* sample_info) {
+  sample_info->frames_count = 0;
+  sample_info->vm_state = isolate->current_vm_state();
+  if (sample_info->vm_state == GC) return;
+
+  Address js_entry_sp = isolate->js_entry_sp();
+  if (js_entry_sp == 0) return;  // Not executing JS now.
+
+  SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp),
+                            reinterpret_cast<Address>(regs.sp), js_entry_sp);
+  size_t i = 0;
+  if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() &&
+      it.top_frame_type() == StackFrame::EXIT) {
+    frames[i++] = isolate->c_function();
+  }
+  while (!it.done() && i < frames_limit) {
+    frames[i++] = it.frame()->pc();
     it.Advance();
   }
-  frames_count = i;
+  sample_info->frames_count = i;
 }
 
 
@@ -682,11 +696,11 @@
 }
 
 
-void Sampler::SampleStack(const RegisterState& state) {
+void Sampler::SampleStack(const v8::RegisterState& state) {
   TickSample* sample = isolate_->cpu_profiler()->StartTickSample();
   TickSample sample_obj;
   if (sample == NULL) sample = &sample_obj;
-  sample->Init(isolate_, state);
+  sample->Init(isolate_, state, TickSample::kIncludeCEntryFrame);
   if (is_counting_samples_) {
     if (sample->state == JS || sample->state == EXTERNAL) {
       ++js_and_external_sample_count_;
@@ -714,7 +728,7 @@
 
 #if defined(USE_SIMULATOR)
   SimulatorHelper helper;
-  if (!helper.Init(this, isolate())) return;
+  if (!helper.Init(isolate())) return;
 #endif
 
   const DWORD kSuspendFailed = static_cast<DWORD>(-1);
@@ -725,7 +739,7 @@
   memset(&context, 0, sizeof(context));
   context.ContextFlags = CONTEXT_FULL;
   if (GetThreadContext(profiled_thread, &context) != 0) {
-    RegisterState state;
+    v8::RegisterState state;
 #if defined(USE_SIMULATOR)
     helper.FillRegisters(&state);
 #else
diff --git a/src/sampler.h b/src/sampler.h
index c3dce4e..120260d 100644
--- a/src/sampler.h
+++ b/src/sampler.h
@@ -5,6 +5,8 @@
 #ifndef V8_SAMPLER_H_
 #define V8_SAMPLER_H_
 
+#include "include/v8.h"
+
 #include "src/base/atomicops.h"
 #include "src/frames.h"
 #include "src/globals.h"
@@ -21,15 +23,13 @@
 // (if used for profiling) the program counter and stack pointer for
 // the thread that created it.
 
-struct RegisterState {
-  RegisterState() : pc(NULL), sp(NULL), fp(NULL) {}
-  Address pc;      // Instruction pointer.
-  Address sp;      // Stack pointer.
-  Address fp;      // Frame pointer.
-};
-
 // TickSample captures the information collected for each sample.
 struct TickSample {
+  // Internal profiling (with --prof + tools/$OS-tick-processor) wants to
+  // include the runtime function we're calling. Externally exposed tick
+  // samples don't care.
+  enum RecordCEntryFrame { kIncludeCEntryFrame, kSkipCEntryFrame };
+
   TickSample()
       : state(OTHER),
         pc(NULL),
@@ -37,7 +37,12 @@
         frames_count(0),
         has_external_callback(false),
         top_frame_type(StackFrame::NONE) {}
-  void Init(Isolate* isolate, const RegisterState& state);
+  void Init(Isolate* isolate, const v8::RegisterState& state,
+            RecordCEntryFrame record_c_entry_frame);
+  static void GetStackSample(Isolate* isolate, const v8::RegisterState& state,
+                             RecordCEntryFrame record_c_entry_frame,
+                             void** frames, size_t frames_limit,
+                             v8::SampleInfo* sample_info);
   StateTag state;  // The state of the VM.
   Address pc;      // Instruction pointer.
   union {
@@ -67,7 +72,7 @@
   int interval() const { return interval_; }
 
   // Performs stack sampling.
-  void SampleStack(const RegisterState& regs);
+  void SampleStack(const v8::RegisterState& regs);
 
   // Start and stop sampler.
   void Start();
diff --git a/src/scanner-character-streams.cc b/src/scanner-character-streams.cc
index d06f479..50c3955 100644
--- a/src/scanner-character-streams.cc
+++ b/src/scanner-character-streams.cc
@@ -18,6 +18,10 @@
 unsigned CopyCharsHelper(uint16_t* dest, unsigned length, const uint8_t* src,
                          unsigned* src_pos, unsigned src_length,
                          ScriptCompiler::StreamedSource::Encoding encoding) {
+  // It's possible that this will be called with length 0, but don't assume that
+  // the functions this calls handle it gracefully.
+  if (length == 0) return 0;
+
   if (encoding == ScriptCompiler::StreamedSource::UTF8) {
     return v8::internal::Utf8ToUtf16CharacterStream::CopyChars(
         dest, length, src, src_pos, src_length);
@@ -381,15 +385,22 @@
 
 void ExternalStreamingStream::HandleUtf8SplitCharacters(
     unsigned* data_in_buffer) {
+  // Note the following property of UTF-8 which makes this function possible:
+  // Given any byte, we can always read its local environment (in both
+  // directions) to find out the (possibly multi-byte) character it belongs
+  // to. Single byte characters are of the form 0b0XXXXXXX. The first byte of a
+  // multi-byte character is of the form 0b110XXXXX, 0b1110XXXX or
+  // 0b11110XXX. The continuation bytes are of the form 0b10XXXXXX.
+
   // First check if we have leftover data from the last chunk.
   unibrow::uchar c;
   if (utf8_split_char_buffer_length_ > 0) {
     // Move the bytes which are part of the split character (which started in
-    // the previous chunk) into utf8_split_char_buffer_.
+    // the previous chunk) into utf8_split_char_buffer_. Note that the
+    // continuation bytes are of the form 0b10XXXXXX, thus c >> 6 == 2.
     while (current_data_offset_ < current_data_length_ &&
            utf8_split_char_buffer_length_ < 4 &&
-           (c = current_data_[current_data_offset_]) >
-               unibrow::Utf8::kMaxOneByteChar) {
+           (c = current_data_[current_data_offset_]) >> 6 == 2) {
       utf8_split_char_buffer_[utf8_split_char_buffer_length_] = c;
       ++utf8_split_char_buffer_length_;
       ++current_data_offset_;
@@ -420,6 +431,12 @@
          utf8_split_char_buffer_length_ < 4) {
     --current_data_length_;
     ++utf8_split_char_buffer_length_;
+    if (c >= (3 << 6)) {
+      // 3 << 6 = 0b11000000; this is the first byte of the multi-byte
+      // character. No need to copy the previous characters into the conversion
+      // buffer (even if they're multi-byte).
+      break;
+    }
   }
   CHECK(utf8_split_char_buffer_length_ <= 4);
   for (unsigned i = 0; i < utf8_split_char_buffer_length_; ++i) {
diff --git a/src/scanner-character-streams.h b/src/scanner-character-streams.h
index afca13f..3c1cccc 100644
--- a/src/scanner-character-streams.h
+++ b/src/scanner-character-streams.h
@@ -91,7 +91,7 @@
 
   virtual ~ExternalStreamingStream() { delete[] current_data_; }
 
-  virtual unsigned BufferSeekForward(unsigned delta) OVERRIDE {
+  unsigned BufferSeekForward(unsigned delta) OVERRIDE {
     // We never need to seek forward when streaming scripts. We only seek
     // forward when we want to parse a function whose location we already know,
     // and when streaming, we don't know the locations of anything we haven't
@@ -100,7 +100,7 @@
     return 0;
   }
 
-  virtual unsigned FillBuffer(unsigned position);
+  unsigned FillBuffer(unsigned position) OVERRIDE;
 
  private:
   void HandleUtf8SplitCharacters(unsigned* data_in_buffer);
diff --git a/src/scanner.cc b/src/scanner.cc
index 72874aa..d499e9b 100644
--- a/src/scanner.cc
+++ b/src/scanner.cc
@@ -4,11 +4,12 @@
 
 // Features shared by parsing and pre-parsing scanners.
 
+#include <stdint.h>
+
 #include <cmath>
 
 #include "src/v8.h"
 
-#include "include/v8stdint.h"
 #include "src/ast-value-factory.h"
 #include "src/char-predicates-inl.h"
 #include "src/conversions-inl.h"
@@ -37,7 +38,9 @@
       harmony_scoping_(false),
       harmony_modules_(false),
       harmony_numeric_literals_(false),
-      harmony_classes_(false) { }
+      harmony_classes_(false),
+      harmony_templates_(false),
+      harmony_unicode_(false) {}
 
 
 void Scanner::Initialize(Utf16CharacterStream* source) {
@@ -53,33 +56,41 @@
 }
 
 
+template <bool capture_raw>
 uc32 Scanner::ScanHexNumber(int expected_length) {
   DCHECK(expected_length <= 4);  // prevent overflow
 
-  uc32 digits[4] = { 0, 0, 0, 0 };
   uc32 x = 0;
   for (int i = 0; i < expected_length; i++) {
-    digits[i] = c0_;
     int d = HexValue(c0_);
     if (d < 0) {
-      // According to ECMA-262, 3rd, 7.8.4, page 18, these hex escapes
-      // should be illegal, but other JS VMs just return the
-      // non-escaped version of the original character.
-
-      // Push back digits that we have advanced past.
-      for (int j = i-1; j >= 0; j--) {
-        PushBack(digits[j]);
-      }
       return -1;
     }
     x = x * 16 + d;
-    Advance();
+    Advance<capture_raw>();
   }
 
   return x;
 }
 
 
+template <bool capture_raw>
+uc32 Scanner::ScanUnlimitedLengthHexNumber(int max_value) {
+  uc32 x = 0;
+  int d = HexValue(c0_);
+  if (d < 0) {
+    return -1;
+  }
+  while (d >= 0) {
+    x = x * 16 + d;
+    if (x > max_value) return -1;
+    Advance<capture_raw>();
+    d = HexValue(c0_);
+  }
+  return x;
+}
+
+
 // Ensure that tokens can be stored in a byte.
 STATIC_ASSERT(Token::NUM_TOKENS <= 0x100);
 
@@ -254,6 +265,8 @@
 
   while (true) {
     while (true) {
+      // The unicode cache accepts unsigned inputs.
+      if (c0_ < 0) break;
       // Advance as long as character is a WhiteSpace or LineTerminator.
       // Remember if the latter is the case.
       if (unicode_cache_->IsLineTerminator(c0_)) {
@@ -318,8 +331,7 @@
 void Scanner::TryToParseSourceURLComment() {
   // Magic comments are of the form: //[#@]\s<name>=\s*<value>\s*.* and this
   // function will just return if it cannot parse a magic comment.
-  if (!unicode_cache_->IsWhiteSpace(c0_))
-    return;
+  if (c0_ < 0 || !unicode_cache_->IsWhiteSpace(c0_)) return;
   Advance();
   LiteralBuffer name;
   while (c0_ >= 0 && !unicode_cache_->IsWhiteSpaceOrLineTerminator(c0_) &&
@@ -374,7 +386,7 @@
   while (c0_ >= 0) {
     uc32 ch = c0_;
     Advance();
-    if (unicode_cache_->IsLineTerminator(ch)) {
+    if (c0_ >= 0 && unicode_cache_->IsLineTerminator(ch)) {
       // Following ECMA-262, section 7.4, a comment containing
       // a newline will make the comment count as a line-terminator.
       has_multiline_comment_before_next_ = true;
@@ -410,6 +422,7 @@
 
 void Scanner::Scan() {
   next_.literal_chars = NULL;
+  next_.raw_literal_chars = NULL;
   Token::Value token;
   do {
     // Remember the position of the next token
@@ -633,15 +646,21 @@
         token = Select(Token::BIT_NOT);
         break;
 
+      case '`':
+        if (HarmonyTemplates()) {
+          token = ScanTemplateStart();
+          break;
+        }
+
       default:
-        if (unicode_cache_->IsIdentifierStart(c0_)) {
+        if (c0_ < 0) {
+          token = Token::EOS;
+        } else if (unicode_cache_->IsIdentifierStart(c0_)) {
           token = ScanIdentifierOrKeyword();
         } else if (IsDecimalDigit(c0_)) {
           token = ScanNumber(false);
         } else if (SkipWhiteSpace()) {
           token = Token::WHITESPACE;
-        } else if (c0_ < 0) {
-          token = Token::EOS;
         } else {
           token = Select(Token::ILLEGAL);
         }
@@ -678,16 +697,17 @@
 }
 
 
+template <bool capture_raw, bool in_template_literal>
 bool Scanner::ScanEscape() {
   uc32 c = c0_;
-  Advance();
+  Advance<capture_raw>();
 
   // Skip escaped newlines.
-  if (unicode_cache_->IsLineTerminator(c)) {
+  if (!in_template_literal && c0_ >= 0 && unicode_cache_->IsLineTerminator(c)) {
     // Allow CR+LF newlines in multiline string literals.
-    if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance();
+    if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance<capture_raw>();
     // Allow LF+CR newlines in multiline string literals.
-    if (IsLineFeed(c) && IsCarriageReturn(c0_)) Advance();
+    if (IsLineFeed(c) && IsCarriageReturn(c0_)) Advance<capture_raw>();
     return true;
   }
 
@@ -701,24 +721,28 @@
     case 'r' : c = '\r'; break;
     case 't' : c = '\t'; break;
     case 'u' : {
-      c = ScanHexNumber(4);
+      c = ScanUnicodeEscape<capture_raw>();
       if (c < 0) return false;
       break;
     }
-    case 'v' : c = '\v'; break;
-    case 'x' : {
-      c = ScanHexNumber(2);
+    case 'v':
+      c = '\v';
+      break;
+    case 'x': {
+      c = ScanHexNumber<capture_raw>(2);
       if (c < 0) return false;
       break;
     }
-    case '0' :  // fall through
-    case '1' :  // fall through
-    case '2' :  // fall through
-    case '3' :  // fall through
-    case '4' :  // fall through
-    case '5' :  // fall through
-    case '6' :  // fall through
-    case '7' : c = ScanOctalEscape(c, 2); break;
+    case '0':  // Fall through.
+    case '1':  // fall through
+    case '2':  // fall through
+    case '3':  // fall through
+    case '4':  // fall through
+    case '5':  // fall through
+    case '6':  // fall through
+    case '7':
+      c = ScanOctalEscape<capture_raw>(c, 2);
+      break;
   }
 
   // According to ECMA-262, section 7.8.4, characters not covered by the
@@ -731,6 +755,7 @@
 
 // Octal escapes of the forms '\0xx' and '\xxx' are not a part of
 // ECMA-262. Other JS VMs support them.
+template <bool capture_raw>
 uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
   uc32 x = c - '0';
   int i = 0;
@@ -740,7 +765,7 @@
     int nx = x * 8 + d;
     if (nx >= 256) break;
     x = nx;
-    Advance();
+    Advance<capture_raw>();
   }
   // Anything except '\0' is an octal escape sequence, illegal in strict mode.
   // Remember the position of octal escape sequences so that an error
@@ -764,7 +789,7 @@
     uc32 c = c0_;
     Advance();
     if (c == '\\') {
-      if (c0_ < 0 || !ScanEscape()) return Token::ILLEGAL;
+      if (c0_ < 0 || !ScanEscape<false, false>()) return Token::ILLEGAL;
     } else {
       AddLiteralChar(c);
     }
@@ -777,6 +802,96 @@
 }
 
 
+Token::Value Scanner::ScanTemplateSpan() {
+  // When scanning a TemplateSpan, we are looking for the following construct:
+  // TEMPLATE_SPAN ::
+  //     ` LiteralChars* ${
+  //   | } LiteralChars* ${
+  //
+  // TEMPLATE_TAIL ::
+  //     ` LiteralChars* `
+  //   | } LiteralChar* `
+  //
+  // A TEMPLATE_SPAN should always be followed by an Expression, while a
+  // TEMPLATE_TAIL terminates a TemplateLiteral and does not need to be
+  // followed by an Expression.
+
+  Token::Value result = Token::TEMPLATE_SPAN;
+  LiteralScope literal(this);
+  StartRawLiteral();
+  const bool capture_raw = true;
+  const bool in_template_literal = true;
+
+  while (true) {
+    uc32 c = c0_;
+    Advance<capture_raw>();
+    if (c == '`') {
+      result = Token::TEMPLATE_TAIL;
+      ReduceRawLiteralLength(1);
+      break;
+    } else if (c == '$' && c0_ == '{') {
+      Advance<capture_raw>();  // Consume '{'
+      ReduceRawLiteralLength(2);
+      break;
+    } else if (c == '\\') {
+      if (unicode_cache_->IsLineTerminator(c0_)) {
+        // The TV of LineContinuation :: \ LineTerminatorSequence is the empty
+        // code unit sequence.
+        uc32 lastChar = c0_;
+        Advance<capture_raw>();
+        if (lastChar == '\r') {
+          ReduceRawLiteralLength(1);  // Remove \r
+          if (c0_ == '\n') {
+            Advance<capture_raw>();  // Adds \n
+          } else {
+            AddRawLiteralChar('\n');
+          }
+        }
+      } else if (!ScanEscape<capture_raw, in_template_literal>()) {
+        return Token::ILLEGAL;
+      }
+    } else if (c < 0) {
+      // Unterminated template literal
+      PushBack(c);
+      break;
+    } else {
+      // The TRV of LineTerminatorSequence :: <CR> is the CV 0x000A.
+      // The TRV of LineTerminatorSequence :: <CR><LF> is the sequence
+      // consisting of the CV 0x000A.
+      if (c == '\r') {
+        ReduceRawLiteralLength(1);  // Remove \r
+        if (c0_ == '\n') {
+          Advance<capture_raw>();  // Adds \n
+        } else {
+          AddRawLiteralChar('\n');
+        }
+        c = '\n';
+      }
+      AddLiteralChar(c);
+    }
+  }
+  literal.Complete();
+  next_.location.end_pos = source_pos();
+  next_.token = result;
+  return result;
+}
+
+
+Token::Value Scanner::ScanTemplateStart() {
+  DCHECK(c0_ == '`');
+  next_.location.beg_pos = source_pos();
+  Advance();  // Consume `
+  return ScanTemplateSpan();
+}
+
+
+Token::Value Scanner::ScanTemplateContinuation() {
+  DCHECK_EQ(next_.token, Token::RBRACE);
+  next_.location.beg_pos = source_pos() - 1;  // We already consumed }
+  return ScanTemplateSpan();
+}
+
+
 void Scanner::ScanDecimalDigits() {
   while (IsDecimalDigit(c0_))
     AddLiteralCharAdvance();
@@ -880,7 +995,8 @@
   // not be an identifier start or a decimal digit; see ECMA-262
   // section 7.8.3, page 17 (note that we read only one decimal digit
   // if the value is 0).
-  if (IsDecimalDigit(c0_) || unicode_cache_->IsIdentifierStart(c0_))
+  if (IsDecimalDigit(c0_) ||
+      (c0_ >= 0 && unicode_cache_->IsIdentifierStart(c0_)))
     return Token::ILLEGAL;
 
   literal.Complete();
@@ -893,9 +1009,28 @@
   Advance();
   if (c0_ != 'u') return -1;
   Advance();
-  uc32 result = ScanHexNumber(4);
-  if (result < 0) PushBack('u');
-  return result;
+  return ScanUnicodeEscape<false>();
+}
+
+
+template <bool capture_raw>
+uc32 Scanner::ScanUnicodeEscape() {
+  // Accept both \uxxxx and \u{xxxxxx} (if harmony unicode escapes are
+  // allowed). In the latter case, the number of hex digits between { } is
+  // arbitrary. \ and u have already been read.
+  if (c0_ == '{' && HarmonyUnicode()) {
+    Advance<capture_raw>();
+    uc32 cp = ScanUnlimitedLengthHexNumber<capture_raw>(0x10ffff);
+    if (cp < 0) {
+      return -1;
+    }
+    if (c0_ != '}') {
+      return -1;
+    }
+    Advance<capture_raw>();
+    return cp;
+  }
+  return ScanHexNumber<capture_raw>(4);
 }
 
 
@@ -1017,11 +1152,15 @@
 bool Scanner::IdentifierIsFutureStrictReserved(
     const AstRawString* string) const {
   // Keywords are always 1-byte strings.
-  return string->is_one_byte() &&
-         Token::FUTURE_STRICT_RESERVED_WORD ==
-             KeywordOrIdentifierToken(string->raw_data(), string->length(),
-                                      harmony_scoping_, harmony_modules_,
-                                      harmony_classes_);
+  if (!string->is_one_byte()) return false;
+  if (string->IsOneByteEqualTo("let") || string->IsOneByteEqualTo("static") ||
+      string->IsOneByteEqualTo("yield")) {
+    return true;
+  }
+  return Token::FUTURE_STRICT_RESERVED_WORD ==
+         KeywordOrIdentifierToken(string->raw_data(), string->length(),
+                                  harmony_scoping_, harmony_modules_,
+                                  harmony_classes_);
 }
 
 
@@ -1046,7 +1185,7 @@
   AddLiteralChar(first_char);
 
   // Scan the rest of the identifier characters.
-  while (unicode_cache_->IsIdentifierPart(c0_)) {
+  while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) {
     if (c0_ != '\\') {
       uc32 next_char = c0_;
       Advance();
@@ -1074,7 +1213,7 @@
 
 Token::Value Scanner::ScanIdentifierSuffix(LiteralScope* literal) {
   // Scan the rest of the identifier characters.
-  while (unicode_cache_->IsIdentifierPart(c0_)) {
+  while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) {
     if (c0_ == '\\') {
       uc32 c = ScanIdentifierUnicodeEscape();
       // Only allow legal identifier part characters.
@@ -1113,10 +1252,10 @@
   }
 
   while (c0_ != '/' || in_character_class) {
-    if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false;
+    if (c0_ < 0 || unicode_cache_->IsLineTerminator(c0_)) return false;
     if (c0_ == '\\') {  // Escape sequence.
       AddLiteralCharAdvance();
-      if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false;
+      if (c0_ < 0 || unicode_cache_->IsLineTerminator(c0_)) return false;
       AddLiteralCharAdvance();
       // If the escape allows more characters, i.e., \x??, \u????, or \c?,
       // only "safe" characters are allowed (letters, digits, underscore),
@@ -1142,47 +1281,14 @@
 }
 
 
-bool Scanner::ScanLiteralUnicodeEscape() {
-  DCHECK(c0_ == '\\');
-  uc32 chars_read[6] = {'\\', 'u', 0, 0, 0, 0};
-  Advance();
-  int i = 1;
-  if (c0_ == 'u') {
-    i++;
-    while (i < 6) {
-      Advance();
-      if (!IsHexDigit(c0_)) break;
-      chars_read[i] = c0_;
-      i++;
-    }
-  }
-  if (i < 6) {
-    // Incomplete escape. Undo all advances and return false.
-    while (i > 0) {
-      i--;
-      PushBack(chars_read[i]);
-    }
-    return false;
-  }
-  // Complete escape. Add all chars to current literal buffer.
-  for (int i = 0; i < 6; i++) {
-    AddLiteralChar(chars_read[i]);
-  }
-  return true;
-}
-
-
 bool Scanner::ScanRegExpFlags() {
   // Scan regular expression flags.
   LiteralScope literal(this);
-  while (unicode_cache_->IsIdentifierPart(c0_)) {
+  while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) {
     if (c0_ != '\\') {
       AddLiteralCharAdvance();
     } else {
-      if (!ScanLiteralUnicodeEscape()) {
-        break;
-      }
-      Advance();
+      return false;
     }
   }
   literal.Complete();
@@ -1208,6 +1314,15 @@
 }
 
 
+const AstRawString* Scanner::CurrentRawSymbol(
+    AstValueFactory* ast_value_factory) {
+  if (is_raw_literal_one_byte()) {
+    return ast_value_factory->GetOneByteString(raw_literal_one_byte_string());
+  }
+  return ast_value_factory->GetTwoByteString(raw_literal_two_byte_string());
+}
+
+
 double Scanner::DoubleValue() {
   DCHECK(is_literal_one_byte());
   return StringToDouble(
diff --git a/src/scanner.h b/src/scanner.h
index 356c8e4..6e668fd 100644
--- a/src/scanner.h
+++ b/src/scanner.h
@@ -15,6 +15,7 @@
 #include "src/list.h"
 #include "src/token.h"
 #include "src/unicode-inl.h"
+#include "src/unicode-decoder.h"
 #include "src/utils.h"
 
 namespace v8 {
@@ -211,9 +212,18 @@
       }
       ConvertToTwoByte();
     }
-    DCHECK(code_unit < 0x10000u);
-    *reinterpret_cast<uint16_t*>(&backing_store_[position_]) = code_unit;
-    position_ += kUC16Size;
+    if (code_unit <= unibrow::Utf16::kMaxNonSurrogateCharCode) {
+      *reinterpret_cast<uint16_t*>(&backing_store_[position_]) = code_unit;
+      position_ += kUC16Size;
+    } else {
+      *reinterpret_cast<uint16_t*>(&backing_store_[position_]) =
+          unibrow::Utf16::LeadSurrogate(code_unit);
+      position_ += kUC16Size;
+      if (position_ >= backing_store_.length()) ExpandBuffer();
+      *reinterpret_cast<uint16_t*>(&backing_store_[position_]) =
+          unibrow::Utf16::TrailSurrogate(code_unit);
+      position_ += kUC16Size;
+    }
   }
 
   bool is_one_byte() const { return is_one_byte_; }
@@ -242,6 +252,10 @@
     return is_one_byte_ ? position_ : (position_ >> 1);
   }
 
+  void ReduceLength(int delta) {
+    position_ -= delta * (is_one_byte_ ? kOneByteSize : kUC16Size);
+  }
+
   void Reset() {
     position_ = 0;
     is_one_byte_ = true;
@@ -308,15 +322,13 @@
   // if aborting the scanning before it's complete.
   class LiteralScope {
    public:
-    explicit LiteralScope(Scanner* self)
-        : scanner_(self), complete_(false) {
+    explicit LiteralScope(Scanner* self) : scanner_(self), complete_(false) {
       scanner_->StartLiteral();
     }
      ~LiteralScope() {
        if (!complete_) scanner_->DropLiteral();
      }
     void Complete() {
-      scanner_->TerminateLiteral();
       complete_ = true;
     }
 
@@ -382,18 +394,23 @@
 
   const AstRawString* CurrentSymbol(AstValueFactory* ast_value_factory);
   const AstRawString* NextSymbol(AstValueFactory* ast_value_factory);
+  const AstRawString* CurrentRawSymbol(AstValueFactory* ast_value_factory);
 
   double DoubleValue();
-  bool UnescapedLiteralMatches(const char* data, int length) {
+  bool LiteralMatches(const char* data, int length, bool allow_escapes = true) {
     if (is_literal_one_byte() &&
         literal_length() == length &&
-        !literal_contains_escapes()) {
+        (allow_escapes || !literal_contains_escapes())) {
       const char* token =
           reinterpret_cast<const char*>(literal_one_byte_string().start());
       return !strncmp(token, data, length);
     }
     return false;
   }
+  inline bool UnescapedLiteralMatches(const char* data, int length) {
+    return LiteralMatches(data, length, false);
+  }
+
   void IsGetOrSet(bool* is_get, bool* is_set) {
     if (is_literal_one_byte() &&
         literal_length() == 3 &&
@@ -444,6 +461,10 @@
   void SetHarmonyClasses(bool classes) {
     harmony_classes_ = classes;
   }
+  bool HarmonyTemplates() const { return harmony_templates_; }
+  void SetHarmonyTemplates(bool templates) { harmony_templates_ = templates; }
+  bool HarmonyUnicode() const { return harmony_unicode_; }
+  void SetHarmonyUnicode(bool unicode) { harmony_unicode_ = unicode; }
 
   // Returns true if there was a line terminator before the peek'ed token,
   // possibly inside a multi-line comment.
@@ -459,6 +480,10 @@
   // be empty).
   bool ScanRegExpFlags();
 
+  // Scans the input as a template literal
+  Token::Value ScanTemplateStart();
+  Token::Value ScanTemplateContinuation();
+
   const LiteralBuffer* source_url() const { return &source_url_; }
   const LiteralBuffer* source_mapping_url() const {
     return &source_mapping_url_;
@@ -472,11 +497,13 @@
     Token::Value token;
     Location location;
     LiteralBuffer* literal_chars;
+    LiteralBuffer* raw_literal_chars;
   };
 
   static const int kCharacterLookaheadBufferSize = 1;
 
   // Scans octal escape sequence. Also accepts "\0" decimal escape sequence.
+  template <bool capture_raw>
   uc32 ScanOctalEscape(uc32 c, int length);
 
   // Call this after setting source_ to the input.
@@ -486,6 +513,7 @@
     Advance();
     // Initialize current_ to not refer to a literal.
     current_.literal_chars = NULL;
+    current_.raw_literal_chars = NULL;
   }
 
   // Literal buffer support
@@ -496,20 +524,31 @@
     next_.literal_chars = free_buffer;
   }
 
+  inline void StartRawLiteral() {
+    raw_literal_buffer_.Reset();
+    next_.raw_literal_chars = &raw_literal_buffer_;
+  }
+
   INLINE(void AddLiteralChar(uc32 c)) {
     DCHECK_NOT_NULL(next_.literal_chars);
     next_.literal_chars->AddChar(c);
   }
 
-  // Complete scanning of a literal.
-  inline void TerminateLiteral() {
-    // Does nothing in the current implementation.
+  INLINE(void AddRawLiteralChar(uc32 c)) {
+    DCHECK_NOT_NULL(next_.raw_literal_chars);
+    next_.raw_literal_chars->AddChar(c);
+  }
+
+  INLINE(void ReduceRawLiteralLength(int delta)) {
+    DCHECK_NOT_NULL(next_.raw_literal_chars);
+    next_.raw_literal_chars->ReduceLength(delta);
   }
 
   // Stops scanning of a literal and drop the collected characters,
   // e.g., due to an encountered error.
   inline void DropLiteral() {
     next_.literal_chars = NULL;
+    next_.raw_literal_chars = NULL;
   }
 
   inline void AddLiteralCharAdvance() {
@@ -518,9 +557,29 @@
   }
 
   // Low-level scanning support.
-  void Advance() { c0_ = source_->Advance(); }
+  template <bool capture_raw = false>
+  void Advance() {
+    if (capture_raw) {
+      AddRawLiteralChar(c0_);
+    }
+    c0_ = source_->Advance();
+    if (unibrow::Utf16::IsLeadSurrogate(c0_)) {
+      uc32 c1 = source_->Advance();
+      if (!unibrow::Utf16::IsTrailSurrogate(c1)) {
+        source_->PushBack(c1);
+      } else {
+        c0_ = unibrow::Utf16::CombineSurrogatePair(c0_, c1);
+      }
+    }
+  }
+
   void PushBack(uc32 ch) {
-    source_->PushBack(c0_);
+    if (ch > static_cast<uc32>(unibrow::Utf16::kMaxNonSurrogateCharCode)) {
+      source_->PushBack(unibrow::Utf16::TrailSurrogate(c0_));
+      source_->PushBack(unibrow::Utf16::LeadSurrogate(c0_));
+    } else {
+      source_->PushBack(c0_);
+    }
     c0_ = ch;
   }
 
@@ -541,10 +600,11 @@
 
   // Returns the literal string, if any, for the current token (the
   // token last returned by Next()). The string is 0-terminated.
-  // Literal strings are collected for identifiers, strings, and
-  // numbers.
-  // These functions only give the correct result if the literal
-  // was scanned between calls to StartLiteral() and TerminateLiteral().
+  // Literal strings are collected for identifiers, strings, numbers as well
+  // as for template literals. For template literals we also collect the raw
+  // form.
+  // These functions only give the correct result if the literal was scanned
+  // when a LiteralScope object is alive.
   Vector<const uint8_t> literal_one_byte_string() {
     DCHECK_NOT_NULL(current_.literal_chars);
     return current_.literal_chars->one_byte_literal();
@@ -575,12 +635,26 @@
     DCHECK_NOT_NULL(next_.literal_chars);
     return next_.literal_chars->is_one_byte();
   }
-  int next_literal_length() const {
-    DCHECK_NOT_NULL(next_.literal_chars);
-    return next_.literal_chars->length();
+  Vector<const uint8_t> raw_literal_one_byte_string() {
+    DCHECK_NOT_NULL(current_.raw_literal_chars);
+    return current_.raw_literal_chars->one_byte_literal();
+  }
+  Vector<const uint16_t> raw_literal_two_byte_string() {
+    DCHECK_NOT_NULL(current_.raw_literal_chars);
+    return current_.raw_literal_chars->two_byte_literal();
+  }
+  bool is_raw_literal_one_byte() {
+    DCHECK_NOT_NULL(current_.raw_literal_chars);
+    return current_.raw_literal_chars->is_one_byte();
   }
 
+  template <bool capture_raw>
   uc32 ScanHexNumber(int expected_length);
+  // Scan a number of any length but not bigger than max_value. For example, the
+  // number can be 000000001, so it's very long in characters but its value is
+  // small.
+  template <bool capture_raw>
+  uc32 ScanUnlimitedLengthHexNumber(int max_value);
 
   // Scans a single JavaScript token.
   void Scan();
@@ -603,14 +677,17 @@
   // Scans an escape-sequence which is part of a string and adds the
   // decoded character to the current literal. Returns true if a pattern
   // is scanned.
+  template <bool capture_raw, bool in_template_literal>
   bool ScanEscape();
+
   // Decodes a Unicode escape-sequence which is part of an identifier.
   // If the escape sequence cannot be decoded the result is kBadChar.
   uc32 ScanIdentifierUnicodeEscape();
-  // Scans a Unicode escape-sequence and adds its characters,
-  // uninterpreted, to the current literal. Used for parsing RegExp
-  // flags.
-  bool ScanLiteralUnicodeEscape();
+  // Helper for the above functions.
+  template <bool capture_raw>
+  uc32 ScanUnicodeEscape();
+
+  Token::Value ScanTemplateSpan();
 
   // Return the current source position.
   int source_pos() {
@@ -627,6 +704,9 @@
   LiteralBuffer source_url_;
   LiteralBuffer source_mapping_url_;
 
+  // Buffer to store raw string values
+  LiteralBuffer raw_literal_buffer_;
+
   TokenDesc current_;  // desc for current token (as returned by Next())
   TokenDesc next_;     // desc for next token (one token look-ahead)
 
@@ -655,6 +735,10 @@
   bool harmony_numeric_literals_;
   // Whether we scan 'class', 'extends', 'static' and 'super' as keywords.
   bool harmony_classes_;
+  // Whether we scan TEMPLATE_SPAN and TEMPLATE_TAIL
+  bool harmony_templates_;
+  // Whether we allow \u{xxxxx}.
+  bool harmony_unicode_;
 };
 
 } }  // namespace v8::internal
diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc
index 75bf014..b9cb6f3 100644
--- a/src/scopeinfo.cc
+++ b/src/scopeinfo.cc
@@ -170,11 +170,11 @@
     int context_locals = ContextLocalCount();
     bool function_name_context_slot =
         FunctionVariableField::decode(Flags()) == CONTEXT;
-    bool has_context = context_locals > 0 ||
-        function_name_context_slot ||
-        scope_type() == WITH_SCOPE ||
-        (scope_type() == FUNCTION_SCOPE && CallsEval()) ||
-        scope_type() == MODULE_SCOPE;
+    bool has_context = context_locals > 0 || function_name_context_slot ||
+                       scope_type() == WITH_SCOPE ||
+                       (scope_type() == ARROW_SCOPE && CallsEval()) ||
+                       (scope_type() == FUNCTION_SCOPE && CallsEval()) ||
+                       scope_type() == MODULE_SCOPE;
     if (has_context) {
       return Context::MIN_CONTEXT_SLOTS + context_locals +
           (function_name_context_slot ? 1 : 0);
@@ -380,13 +380,14 @@
   for (int i = 0; i < local_count; ++i) {
     if (scope_info->LocalIsSynthetic(first_context_var + i)) continue;
     int context_index = Context::MIN_CONTEXT_SLOTS + i;
+    Handle<Object> value = Handle<Object>(context->get(context_index), isolate);
+    // Do not reflect variables under TDZ in scope object.
+    if (value->IsTheHole()) continue;
     RETURN_ON_EXCEPTION_VALUE(
-        isolate,
-        Runtime::DefineObjectProperty(
-            scope_object,
-            Handle<String>(String::cast(scope_info->get(i + start))),
-            Handle<Object>(context->get(context_index), isolate),
-            ::NONE),
+        isolate, Runtime::DefineObjectProperty(
+                     scope_object,
+                     Handle<String>(String::cast(scope_info->get(i + start))),
+                     value, ::NONE),
         false);
   }
   return true;
diff --git a/src/scopes.cc b/src/scopes.cc
index 440c7f2..39b67a8 100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -78,14 +78,14 @@
       unresolved_(16, zone),
       decls_(4, zone),
       interface_(FLAG_harmony_modules &&
-                 (scope_type == MODULE_SCOPE || scope_type == GLOBAL_SCOPE)
+                 (scope_type == MODULE_SCOPE || scope_type == SCRIPT_SCOPE)
                      ? Interface::NewModule(zone) : NULL),
       already_resolved_(false),
       ast_value_factory_(ast_value_factory),
       zone_(zone) {
   SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null());
-  // The outermost scope must be a global scope.
-  DCHECK(scope_type == GLOBAL_SCOPE || outer_scope != NULL);
+  // The outermost scope must be a script scope.
+  DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL);
   DCHECK(!HasIllegalRedeclaration());
 }
 
@@ -160,12 +160,20 @@
   scope_inside_with_ = false;
   scope_contains_with_ = false;
   scope_calls_eval_ = false;
+  scope_uses_arguments_ = false;
+  scope_uses_super_property_ = false;
+  scope_uses_super_constructor_call_ = false;
+  scope_uses_this_ = false;
   asm_module_ = false;
   asm_function_ = outer_scope != NULL && outer_scope->asm_module_;
   // Inherit the strict mode from the parent scope.
   strict_mode_ = outer_scope != NULL ? outer_scope->strict_mode_ : SLOPPY;
   outer_scope_calls_sloppy_eval_ = false;
   inner_scope_calls_eval_ = false;
+  inner_scope_uses_arguments_ = false;
+  inner_scope_uses_this_ = false;
+  inner_scope_uses_super_property_ = false;
+  inner_scope_uses_super_constructor_call_ = false;
   force_eager_compilation_ = false;
   force_context_allocation_ = (outer_scope != NULL && !is_function_scope())
       ? outer_scope->has_forced_context_allocation() : false;
@@ -184,7 +192,7 @@
 }
 
 
-Scope* Scope::DeserializeScopeChain(Context* context, Scope* global_scope,
+Scope* Scope::DeserializeScopeChain(Context* context, Scope* script_scope,
                                     Zone* zone) {
   // Reconstruct the outer scope chain from a closure's context chain.
   Scope* current_scope = NULL;
@@ -195,7 +203,7 @@
       Scope* with_scope = new(zone) Scope(current_scope,
                                           WITH_SCOPE,
                                           Handle<ScopeInfo>::null(),
-                                          global_scope->ast_value_factory_,
+                                          script_scope->ast_value_factory_,
                                           zone);
       current_scope = with_scope;
       // All the inner scopes are inside a with.
@@ -203,26 +211,26 @@
       for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) {
         s->scope_inside_with_ = true;
       }
-    } else if (context->IsGlobalContext()) {
+    } else if (context->IsScriptContext()) {
       ScopeInfo* scope_info = ScopeInfo::cast(context->extension());
       current_scope = new(zone) Scope(current_scope,
-                                      GLOBAL_SCOPE,
+                                      SCRIPT_SCOPE,
                                       Handle<ScopeInfo>(scope_info),
-                                      global_scope->ast_value_factory_,
+                                      script_scope->ast_value_factory_,
                                       zone);
     } else if (context->IsModuleContext()) {
       ScopeInfo* scope_info = ScopeInfo::cast(context->module()->scope_info());
       current_scope = new(zone) Scope(current_scope,
                                       MODULE_SCOPE,
                                       Handle<ScopeInfo>(scope_info),
-                                      global_scope->ast_value_factory_,
+                                      script_scope->ast_value_factory_,
                                       zone);
     } else if (context->IsFunctionContext()) {
       ScopeInfo* scope_info = context->closure()->shared()->scope_info();
       current_scope = new(zone) Scope(current_scope,
                                       FUNCTION_SCOPE,
                                       Handle<ScopeInfo>(scope_info),
-                                      global_scope->ast_value_factory_,
+                                      script_scope->ast_value_factory_,
                                       zone);
       if (scope_info->IsAsmFunction()) current_scope->asm_function_ = true;
       if (scope_info->IsAsmModule()) current_scope->asm_module_ = true;
@@ -231,15 +239,15 @@
       current_scope = new(zone) Scope(current_scope,
                                       BLOCK_SCOPE,
                                       Handle<ScopeInfo>(scope_info),
-                                      global_scope->ast_value_factory_,
+                                      script_scope->ast_value_factory_,
                                       zone);
     } else {
       DCHECK(context->IsCatchContext());
       String* name = String::cast(context->extension());
       current_scope = new (zone) Scope(
           current_scope,
-          global_scope->ast_value_factory_->GetString(Handle<String>(name)),
-          global_scope->ast_value_factory_, zone);
+          script_scope->ast_value_factory_->GetString(Handle<String>(name)),
+          script_scope->ast_value_factory_, zone);
     }
     if (contains_with) current_scope->RecordWithStatement();
     if (innermost_scope == NULL) innermost_scope = current_scope;
@@ -251,9 +259,9 @@
     context = context->previous();
   }
 
-  global_scope->AddInnerScope(current_scope);
-  global_scope->PropagateScopeInfo(false);
-  return (innermost_scope == NULL) ? global_scope : innermost_scope;
+  script_scope->AddInnerScope(current_scope);
+  script_scope->PropagateScopeInfo(false);
+  return (innermost_scope == NULL) ? script_scope : innermost_scope;
 }
 
 
@@ -264,15 +272,14 @@
 
   // Traverse the scope tree up to the first unresolved scope or the global
   // scope and start scope resolution and variable allocation from that scope.
-  while (!top->is_global_scope() &&
+  while (!top->is_script_scope() &&
          !top->outer_scope()->already_resolved()) {
     top = top->outer_scope();
   }
 
   // Allocate the variables.
   {
-    AstNodeFactory<AstNullVisitor> ast_node_factory(
-        info->zone(), info->ast_value_factory(), info->ast_node_id_gen());
+    AstNodeFactory ast_node_factory(info->ast_value_factory());
     if (!top->AllocateVariables(info, &ast_node_factory)) return false;
   }
 
@@ -283,7 +290,7 @@
     scope->Print();
   }
 
-  if (FLAG_harmony_modules && FLAG_print_interfaces && top->is_global_scope()) {
+  if (FLAG_harmony_modules && FLAG_print_interfaces && top->is_script_scope()) {
     PrintF("global : ");
     top->interface()->Print();
   }
@@ -306,9 +313,9 @@
   }
 
   // Declare convenience variables.
-  // Declare and allocate receiver (even for the global scope, and even
+  // Declare and allocate receiver (even for the script scope, and even
   // if naccesses_ == 0).
-  // NOTE: When loading parameters in the global scope, we must take
+  // NOTE: When loading parameters in the script scope, we must take
   // care not to access them as properties of the global object, but
   // instead load them directly from the stack. Currently, the only
   // such parameter is 'this' which is passed on the stack when
@@ -368,6 +375,13 @@
     outer_scope()->unresolved_.Add(unresolved_[i], zone());
   }
 
+  // Propagate usage flags to outer scope.
+  if (uses_arguments()) outer_scope_->RecordArgumentsUsage();
+  if (uses_super_property()) outer_scope_->RecordSuperPropertyUsage();
+  if (uses_super_constructor_call())
+    outer_scope_->RecordSuperConstructorCallUsage();
+  if (uses_this()) outer_scope_->RecordThisUsage();
+
   return NULL;
 }
 
@@ -414,7 +428,7 @@
 
 
 Variable* Scope::LookupFunctionVar(const AstRawString* name,
-                                   AstNodeFactory<AstNullVisitor>* factory) {
+                                   AstNodeFactory* factory) {
   if (function_ != NULL && function_->proxy()->raw_name() == name) {
     return function_->proxy()->var();
   } else if (!scope_info_.is_null()) {
@@ -474,7 +488,7 @@
 
 
 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) {
-  DCHECK(is_global_scope());
+  DCHECK(is_script_scope());
   return variables_.Declare(this,
                             name,
                             DYNAMIC_GLOBAL,
@@ -633,8 +647,7 @@
 }
 
 
-bool Scope::AllocateVariables(CompilationInfo* info,
-                              AstNodeFactory<AstNullVisitor>* factory) {
+bool Scope::AllocateVariables(CompilationInfo* info, AstNodeFactory* factory) {
   // 1) Propagate scope information.
   bool outer_scope_calls_sloppy_eval = false;
   if (outer_scope_ != NULL) {
@@ -645,7 +658,7 @@
   PropagateScopeInfo(outer_scope_calls_sloppy_eval);
 
   // 2) Allocate module instances.
-  if (FLAG_harmony_modules && (is_global_scope() || is_module_scope())) {
+  if (FLAG_harmony_modules && (is_script_scope() || is_module_scope())) {
     DCHECK(num_modules_ == 0);
     AllocateModulesRecursively(this);
   }
@@ -725,9 +738,9 @@
 }
 
 
-Scope* Scope::GlobalScope() {
+Scope* Scope::ScriptScope() {
   Scope* scope = this;
-  while (!scope->is_global_scope()) {
+  while (!scope->is_script_scope()) {
     scope = scope->outer_scope();
   }
   return scope;
@@ -775,10 +788,11 @@
     case EVAL_SCOPE: return "eval";
     case FUNCTION_SCOPE: return "function";
     case MODULE_SCOPE: return "module";
-    case GLOBAL_SCOPE: return "global";
+    case SCRIPT_SCOPE: return "global";
     case CATCH_SCOPE: return "catch";
     case BLOCK_SCOPE: return "block";
     case WITH_SCOPE: return "with";
+    case ARROW_SCOPE: return "arrow";
   }
   UNREACHABLE();
   return NULL;
@@ -885,6 +899,21 @@
   if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
   if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
   if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
+  if (scope_uses_arguments_) Indent(n1, "// scope uses 'arguments'\n");
+  if (scope_uses_super_property_)
+    Indent(n1, "// scope uses 'super' property\n");
+  if (scope_uses_super_constructor_call_)
+    Indent(n1, "// scope uses 'super' constructor\n");
+  if (scope_uses_this_) Indent(n1, "// scope uses 'this'\n");
+  if (inner_scope_uses_arguments_) {
+    Indent(n1, "// inner scope uses 'arguments'\n");
+  }
+  if (inner_scope_uses_super_property_)
+    Indent(n1, "// inner scope uses 'super' property\n");
+  if (inner_scope_uses_super_constructor_call_) {
+    Indent(n1, "// inner scope uses 'super' constructor\n");
+  }
+  if (inner_scope_uses_this_) Indent(n1, "// inner scope uses 'this'\n");
   if (outer_scope_calls_sloppy_eval_) {
     Indent(n1, "// outer scope calls 'eval' in sloppy context\n");
   }
@@ -962,7 +991,7 @@
 
 Variable* Scope::LookupRecursive(VariableProxy* proxy,
                                  BindingKind* binding_kind,
-                                 AstNodeFactory<AstNullVisitor>* factory) {
+                                 AstNodeFactory* factory) {
   DCHECK(binding_kind != NULL);
   if (already_resolved() && is_with_scope()) {
     // Short-cut: if the scope is deserialized from a scope info, variable
@@ -995,7 +1024,7 @@
       var->ForceContextAllocation();
     }
   } else {
-    DCHECK(is_global_scope());
+    DCHECK(is_script_scope());
   }
 
   if (is_with_scope()) {
@@ -1024,14 +1053,13 @@
 }
 
 
-bool Scope::ResolveVariable(CompilationInfo* info,
-                            VariableProxy* proxy,
-                            AstNodeFactory<AstNullVisitor>* factory) {
-  DCHECK(info->global_scope()->is_global_scope());
+bool Scope::ResolveVariable(CompilationInfo* info, VariableProxy* proxy,
+                            AstNodeFactory* factory) {
+  DCHECK(info->script_scope()->is_script_scope());
 
   // If the proxy is already resolved there's nothing to do
   // (functions and consts may be resolved by the parser).
-  if (proxy->var() != NULL) return true;
+  if (proxy->is_resolved()) return true;
 
   // Otherwise, try to resolve the variable.
   BindingKind binding_kind;
@@ -1059,7 +1087,7 @@
 
     case UNBOUND:
       // No binding has been found. Declare a variable on the global object.
-      var = info->global_scope()->DeclareDynamicGlobal(proxy->raw_name());
+      var = info->script_scope()->DeclareDynamicGlobal(proxy->raw_name());
       break;
 
     case UNBOUND_EVAL_SHADOWED:
@@ -1076,21 +1104,6 @@
   DCHECK(var != NULL);
   if (proxy->is_assigned()) var->set_maybe_assigned();
 
-  if (FLAG_harmony_scoping && strict_mode() == STRICT &&
-      var->is_const_mode() && proxy->is_assigned()) {
-    // Assignment to const. Throw a syntax error.
-    MessageLocation location(
-        info->script(), proxy->position(), proxy->position());
-    Isolate* isolate = info->isolate();
-    Factory* factory = isolate->factory();
-    Handle<JSArray> array = factory->NewJSArray(0);
-    Handle<Object> error;
-    MaybeHandle<Object> maybe_error =
-        factory->NewSyntaxError("harmony_const_assign", array);
-    if (maybe_error.ToHandle(&error)) isolate->Throw(*error, &location);
-    return false;
-  }
-
   if (FLAG_harmony_modules) {
     bool ok;
 #ifdef DEBUG
@@ -1133,10 +1146,9 @@
 }
 
 
-bool Scope::ResolveVariablesRecursively(
-    CompilationInfo* info,
-    AstNodeFactory<AstNullVisitor>* factory) {
-  DCHECK(info->global_scope()->is_global_scope());
+bool Scope::ResolveVariablesRecursively(CompilationInfo* info,
+                                        AstNodeFactory* factory) {
+  DCHECK(info->script_scope()->is_script_scope());
 
   // Resolve unresolved variables for this scope.
   for (int i = 0; i < unresolved_.length(); i++) {
@@ -1166,6 +1178,25 @@
     if (inner->scope_calls_eval_ || inner->inner_scope_calls_eval_) {
       inner_scope_calls_eval_ = true;
     }
+    // If the inner scope is an arrow function, propagate the flags tracking
+    // usage of arguments/super/this, but do not propagate them out from normal
+    // functions.
+    if (!inner->is_function_scope() || inner->is_arrow_scope()) {
+      if (inner->scope_uses_arguments_ || inner->inner_scope_uses_arguments_) {
+        inner_scope_uses_arguments_ = true;
+      }
+      if (inner->scope_uses_super_property_ ||
+          inner->inner_scope_uses_super_property_) {
+        inner_scope_uses_super_property_ = true;
+      }
+      if (inner->uses_super_constructor_call() ||
+          inner->inner_scope_uses_super_constructor_call_) {
+        inner_scope_uses_super_constructor_call_ = true;
+      }
+      if (inner->scope_uses_this_ || inner->inner_scope_uses_this_) {
+        inner_scope_uses_this_ = true;
+      }
+    }
     if (inner->force_eager_compilation_) {
       force_eager_compilation_ = true;
     }
@@ -1188,7 +1219,7 @@
        is_catch_scope() ||
        is_block_scope() ||
        is_module_scope() ||
-       is_global_scope())) {
+       is_script_scope())) {
     var->set_is_used();
     if (scope_calls_eval_ || inner_scope_calls_eval_) var->set_maybe_assigned();
   }
@@ -1211,7 +1242,7 @@
   if (var->mode() == TEMPORARY) return false;
   if (var->mode() == INTERNAL) return true;
   if (is_catch_scope() || is_block_scope() || is_module_scope()) return true;
-  if (is_global_scope() && IsLexicalVariableMode(var->mode())) return true;
+  if (is_script_scope() && IsLexicalVariableMode(var->mode())) return true;
   return var->has_forced_context_allocation() ||
       scope_calls_eval_ ||
       inner_scope_calls_eval_ ||
diff --git a/src/scopes.h b/src/scopes.h
index 06c6c99..8d79006 100644
--- a/src/scopes.h
+++ b/src/scopes.h
@@ -80,7 +80,7 @@
   // doesn't re-allocate variables repeatedly.
   static bool Analyze(CompilationInfo* info);
 
-  static Scope* DeserializeScopeChain(Context* context, Scope* global_scope,
+  static Scope* DeserializeScopeChain(Context* context, Scope* script_scope,
                                       Zone* zone);
 
   // The scope name is only used for printing/debugging.
@@ -108,7 +108,7 @@
   // the name of named function literal is kept in an intermediate scope
   // in between this scope and the next outer scope.)
   Variable* LookupFunctionVar(const AstRawString* name,
-                              AstNodeFactory<AstNullVisitor>* factory);
+                              AstNodeFactory* factory);
 
   // Lookup a variable in this scope or outer scopes.
   // Returns the variable or NULL if not found.
@@ -135,14 +135,13 @@
                          Interface* interface = Interface::NewValue());
 
   // Declare an implicit global variable in this scope which must be a
-  // global scope.  The variable was introduced (possibly from an inner
+  // script scope.  The variable was introduced (possibly from an inner
   // scope) by a reference to an unresolved variable with no intervening
   // with statements or eval calls.
   Variable* DeclareDynamicGlobal(const AstRawString* name);
 
   // Create a new unresolved variable.
-  template<class Visitor>
-  VariableProxy* NewUnresolved(AstNodeFactory<Visitor>* factory,
+  VariableProxy* NewUnresolved(AstNodeFactory* factory,
                                const AstRawString* name,
                                Interface* interface = Interface::NewValue(),
                                int position = RelocInfo::kNoPosition) {
@@ -209,7 +208,21 @@
   void RecordWithStatement() { scope_contains_with_ = true; }
 
   // Inform the scope that the corresponding code contains an eval call.
-  void RecordEvalCall() { if (!is_global_scope()) scope_calls_eval_ = true; }
+  void RecordEvalCall() { if (!is_script_scope()) scope_calls_eval_ = true; }
+
+  // Inform the scope that the corresponding code uses "arguments".
+  void RecordArgumentsUsage() { scope_uses_arguments_ = true; }
+
+  // Inform the scope that the corresponding code uses "super".
+  void RecordSuperPropertyUsage() { scope_uses_super_property_ = true; }
+
+  // Inform the scope that the corresponding code invokes "super" constructor.
+  void RecordSuperConstructorCallUsage() {
+    scope_uses_super_constructor_call_ = true;
+  }
+
+  // Inform the scope that the corresponding code uses "this".
+  void RecordThisUsage() { scope_uses_this_ = true; }
 
   // Set the strict mode flag (unless disabled by a global flag).
   void SetStrictMode(StrictMode strict_mode) { strict_mode_ = strict_mode; }
@@ -262,15 +275,18 @@
 
   // Specific scope types.
   bool is_eval_scope() const { return scope_type_ == EVAL_SCOPE; }
-  bool is_function_scope() const { return scope_type_ == FUNCTION_SCOPE; }
+  bool is_function_scope() const {
+    return scope_type_ == FUNCTION_SCOPE || scope_type_ == ARROW_SCOPE;
+  }
   bool is_module_scope() const { return scope_type_ == MODULE_SCOPE; }
-  bool is_global_scope() const { return scope_type_ == GLOBAL_SCOPE; }
+  bool is_script_scope() const { return scope_type_ == SCRIPT_SCOPE; }
   bool is_catch_scope() const { return scope_type_ == CATCH_SCOPE; }
   bool is_block_scope() const { return scope_type_ == BLOCK_SCOPE; }
   bool is_with_scope() const { return scope_type_ == WITH_SCOPE; }
+  bool is_arrow_scope() const { return scope_type_ == ARROW_SCOPE; }
   bool is_declaration_scope() const {
     return is_eval_scope() || is_function_scope() ||
-        is_module_scope() || is_global_scope();
+        is_module_scope() || is_script_scope();
   }
   bool is_strict_eval_scope() const {
     return is_eval_scope() && strict_mode_ == STRICT;
@@ -292,6 +308,29 @@
   // Does this scope contain a with statement.
   bool contains_with() const { return scope_contains_with_; }
 
+  // Does this scope access "arguments".
+  bool uses_arguments() const { return scope_uses_arguments_; }
+  // Does any inner scope access "arguments".
+  bool inner_uses_arguments() const { return inner_scope_uses_arguments_; }
+  // Does this scope access "super" property (super.foo).
+  bool uses_super_property() const { return scope_uses_super_property_; }
+  // Does any inner scope access "super" property.
+  bool inner_uses_super_property() const {
+    return inner_scope_uses_super_property_;
+  }
+  // Does this scope calls "super" constructor.
+  bool uses_super_constructor_call() const {
+    return scope_uses_super_constructor_call_;
+  }
+  // Does  any inner scope calls "super" constructor.
+  bool inner_uses_super_constructor_call() const {
+    return inner_scope_uses_super_constructor_call_;
+  }
+  // Does this scope access "this".
+  bool uses_this() const { return scope_uses_this_; }
+  // Does any inner scope access "this".
+  bool inner_uses_this() const { return inner_scope_uses_this_; }
+
   // ---------------------------------------------------------------------------
   // Accessors.
 
@@ -354,7 +393,7 @@
   int StackLocalCount() const;
   int ContextLocalCount() const;
 
-  // For global scopes, the number of module literals (including nested ones).
+  // For script scopes, the number of module literals (including nested ones).
   int num_modules() const { return num_modules_; }
 
   // For module scopes, the host scope's internal variable binding this module.
@@ -378,8 +417,10 @@
   // The number of contexts between this and scope; zero if this == scope.
   int ContextChainLength(Scope* scope);
 
-  // Find the innermost global scope.
-  Scope* GlobalScope();
+  // Find the script scope.
+  // Used in modules implemenetation to find hosting scope.
+  // TODO(rossberg): is this needed?
+  Scope* ScriptScope();
 
   // Find the first function, global, or eval scope.  This is the scope
   // where var declarations will be hoisted to in the implementation.
@@ -431,7 +472,7 @@
 
   // The variables declared in this scope:
   //
-  // All user-declared variables (incl. parameters).  For global scopes
+  // All user-declared variables (incl. parameters).  For script scopes
   // variables may be implicitly 'declared' by being used (possibly in
   // an inner scope) with no intervening with statements or eval calls.
   VariableMap variables_;
@@ -468,6 +509,14 @@
   // This scope or a nested catch scope or with scope contain an 'eval' call. At
   // the 'eval' call site this scope is the declaration scope.
   bool scope_calls_eval_;
+  // This scope uses "arguments".
+  bool scope_uses_arguments_;
+  // This scope uses "super" property ('super.foo').
+  bool scope_uses_super_property_;
+  // This scope uses "super" constructor ('super(..)').
+  bool scope_uses_super_constructor_call_;
+  // This scope uses "this".
+  bool scope_uses_this_;
   // This scope contains an "use asm" annotation.
   bool asm_module_;
   // This scope's outer context is an asm module.
@@ -481,6 +530,10 @@
   // Computed via PropagateScopeInfo.
   bool outer_scope_calls_sloppy_eval_;
   bool inner_scope_calls_eval_;
+  bool inner_scope_uses_arguments_;
+  bool inner_scope_uses_super_property_;
+  bool inner_scope_uses_super_constructor_call_;
+  bool inner_scope_uses_this_;
   bool force_eager_compilation_;
   bool force_context_allocation_;
 
@@ -531,14 +584,14 @@
     // The variable reference could not be statically resolved to any binding
     // and thus should be considered referencing a global variable. NULL is
     // returned. The variable reference is not inside any 'with' statement and
-    // no scope between the reference scope (inclusive) and global scope
+    // no scope between the reference scope (inclusive) and script scope
     // (exclusive) makes a sloppy 'eval' call.
     UNBOUND,
 
     // The variable reference could not be statically resolved to any binding
     // NULL is returned. The variable reference is not inside any 'with'
     // statement, but some scope between the reference scope (inclusive) and
-    // global scope (exclusive) makes a sloppy 'eval' call, that might
+    // script scope (exclusive) makes a sloppy 'eval' call, that might
     // possibly introduce a variable binding. Thus the reference should be
     // considered referencing a global variable unless it is shadowed by an
     // 'eval' introduced binding.
@@ -558,16 +611,14 @@
   // Lookup a variable reference given by name recursively starting with this
   // scope. If the code is executed because of a call to 'eval', the context
   // parameter should be set to the calling context of 'eval'.
-  Variable* LookupRecursive(VariableProxy* proxy,
-                            BindingKind* binding_kind,
-                            AstNodeFactory<AstNullVisitor>* factory);
+  Variable* LookupRecursive(VariableProxy* proxy, BindingKind* binding_kind,
+                            AstNodeFactory* factory);
   MUST_USE_RESULT
-  bool ResolveVariable(CompilationInfo* info,
-                       VariableProxy* proxy,
-                       AstNodeFactory<AstNullVisitor>* factory);
+  bool ResolveVariable(CompilationInfo* info, VariableProxy* proxy,
+                       AstNodeFactory* factory);
   MUST_USE_RESULT
   bool ResolveVariablesRecursively(CompilationInfo* info,
-                                   AstNodeFactory<AstNullVisitor>* factory);
+                                   AstNodeFactory* factory);
 
   // Scope analysis.
   void PropagateScopeInfo(bool outer_scope_calls_sloppy_eval);
@@ -596,8 +647,7 @@
   // parameter is the context in which eval was called.  In all other
   // cases the context parameter is an empty handle.
   MUST_USE_RESULT
-  bool AllocateVariables(CompilationInfo* info,
-                         AstNodeFactory<AstNullVisitor>* factory);
+  bool AllocateVariables(CompilationInfo* info, AstNodeFactory* factory);
 
  private:
   // Construct a scope based on the scope info.
diff --git a/src/serialize.cc b/src/serialize.cc
index dce62fe..c5f8b63 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -16,7 +16,7 @@
 #include "src/ic/stub-cache.h"
 #include "src/natives.h"
 #include "src/objects.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 #include "src/serialize.h"
 #include "src/snapshot.h"
 #include "src/snapshot-source-sink.h"
@@ -365,15 +365,11 @@
   }
 
   // Accessors
-#define ACCESSOR_INFO_DECLARATION(name) \
-  Add(FUNCTION_ADDR(&Accessors::name##Getter), \
-      ACCESSOR, \
-      Accessors::k##name##Getter, \
-      "Accessors::" #name "Getter"); \
-  Add(FUNCTION_ADDR(&Accessors::name##Setter), \
-      ACCESSOR, \
-      Accessors::k##name##Setter, \
-      "Accessors::" #name "Setter");
+#define ACCESSOR_INFO_DECLARATION(name)                          \
+  Add(FUNCTION_ADDR(&Accessors::name##Getter), ACCESSOR_CODE,    \
+      Accessors::k##name##Getter, "Accessors::" #name "Getter"); \
+  Add(FUNCTION_ADDR(&Accessors::name##Setter), ACCESSOR_CODE,    \
+      Accessors::k##name##Setter, "Accessors::" #name "Setter");
   ACCESSOR_INFO_LIST(ACCESSOR_INFO_DECLARATION)
 #undef ACCESSOR_INFO_DECLARATION
 
@@ -481,6 +477,27 @@
 }
 
 
+RootIndexMap::RootIndexMap(Isolate* isolate) {
+  map_ = new HashMap(HashMap::PointersMatch);
+  Object** root_array = isolate->heap()->roots_array_start();
+  for (int i = 0; i < Heap::kStrongRootListLength; i++) {
+    Object* root = root_array[i];
+    if (root->IsHeapObject() && !isolate->heap()->InNewSpace(root)) {
+      HeapObject* heap_object = HeapObject::cast(root);
+      if (LookupEntry(map_, heap_object, false) != NULL) {
+        // Some root values are initialized to the empty FixedArray();
+        // Do not add them to the map.
+        // TODO(yangguo): This assert is not true. Some roots like
+        // instanceof_cache_answer can be e.g. null.
+        // DCHECK_EQ(isolate->heap()->empty_fixed_array(), heap_object);
+      } else {
+        SetValue(LookupEntry(map_, heap_object, true), i);
+      }
+    }
+  }
+}
+
+
 class CodeAddressMap: public CodeEventLogger {
  public:
   explicit CodeAddressMap(Isolate* isolate)
@@ -592,14 +609,17 @@
 };
 
 
-Deserializer::Deserializer(SnapshotByteSource* source)
-    : isolate_(NULL),
-      attached_objects_(NULL),
-      source_(source),
-      external_reference_decoder_(NULL) {
-  for (int i = 0; i < LAST_SPACE + 1; i++) {
-    reservations_[i] = kUninitializedReservation;
+void Deserializer::DecodeReservation(
+    Vector<const SerializedData::Reservation> res) {
+  DCHECK_EQ(0, reservations_[NEW_SPACE].length());
+  STATIC_ASSERT(NEW_SPACE == 0);
+  int current_space = NEW_SPACE;
+  for (const auto& r : res) {
+    reservations_[current_space].Add({r.chunk_size(), NULL, NULL});
+    if (r.is_last()) current_space++;
   }
+  DCHECK_EQ(kNumberOfSpaces, current_space);
+  for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) current_chunk_[i] = 0;
 }
 
 
@@ -612,10 +632,19 @@
 }
 
 
+bool Deserializer::ReserveSpace() {
+  if (!isolate_->heap()->ReserveSpace(reservations_)) return false;
+  for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) {
+    high_water_[i] = reservations_[i][0].start;
+  }
+  return true;
+}
+
+
 void Deserializer::Deserialize(Isolate* isolate) {
   isolate_ = isolate;
   DCHECK(isolate_ != NULL);
-  isolate_->heap()->ReserveSpace(reservations_, &high_water_[0]);
+  if (!ReserveSpace()) FatalProcessOutOfMemory("deserializing context");
   // No active threads.
   DCHECK_EQ(NULL, isolate_->thread_manager()->FirstThreadStateInUse());
   // No active handles.
@@ -657,12 +686,17 @@
 }
 
 
-void Deserializer::DeserializePartial(Isolate* isolate, Object** root) {
+void Deserializer::DeserializePartial(Isolate* isolate, Object** root,
+                                      OnOOM on_oom) {
   isolate_ = isolate;
   for (int i = NEW_SPACE; i < kNumberOfSpaces; i++) {
-    DCHECK(reservations_[i] != kUninitializedReservation);
+    DCHECK(reservations_[i].length() > 0);
   }
-  isolate_->heap()->ReserveSpace(reservations_, &high_water_[0]);
+  if (!ReserveSpace()) {
+    if (on_oom == FATAL_ON_OOM) FatalProcessOutOfMemory("deserialize context");
+    *root = NULL;
+    return;
+  }
   if (external_reference_decoder_ == NULL) {
     external_reference_decoder_ = new ExternalReferenceDecoder(isolate);
   }
@@ -684,7 +718,7 @@
 
 Deserializer::~Deserializer() {
   // TODO(svenpanne) Re-enable this assertion when v8 initialization is fixed.
-  // DCHECK(source_->AtEOF());
+  // DCHECK(source_.AtEOF());
   if (external_reference_decoder_) {
     delete external_reference_decoder_;
     external_reference_decoder_ = NULL;
@@ -698,7 +732,7 @@
 void Deserializer::VisitPointers(Object** start, Object** end) {
   // The space must be new space.  Any other space would cause ReadChunk to try
   // to update the remembered using NULL as the address.
-  ReadChunk(start, end, NEW_SPACE, NULL);
+  ReadData(start, end, NEW_SPACE, NULL);
 }
 
 
@@ -720,7 +754,7 @@
     DCHECK(string->IsInternalizedString());
   }
 
-  virtual bool IsMatch(Object* string) {
+  bool IsMatch(Object* string) OVERRIDE {
     // We know that all entries in a hash table had their hash keys created.
     // Use that knowledge to have fast failure.
     if (hash_ != HashForObject(string)) return false;
@@ -728,9 +762,9 @@
     return string_->SlowEquals(String::cast(string));
   }
 
-  virtual uint32_t Hash() OVERRIDE { return hash_; }
+  uint32_t Hash() OVERRIDE { return hash_; }
 
-  virtual uint32_t HashForObject(Object* key) OVERRIDE {
+  uint32_t HashForObject(Object* key) OVERRIDE {
     return String::cast(key)->Hash();
   }
 
@@ -762,10 +796,24 @@
 }
 
 
-Object* Deserializer::ProcessBackRefInSerializedCode(Object* obj) {
-  if (obj->IsInternalizedString()) {
-    return String::cast(obj)->GetForwardedInternalizedString();
+HeapObject* Deserializer::GetBackReferencedObject(int space) {
+  HeapObject* obj;
+  if (space == LO_SPACE) {
+    uint32_t index = source_.GetInt();
+    obj = deserialized_large_objects_[index];
+  } else {
+    BackReference back_reference(source_.GetInt());
+    DCHECK(space < kNumberOfPreallocatedSpaces);
+    uint32_t chunk_index = back_reference.chunk_index();
+    DCHECK_LE(chunk_index, current_chunk_[space]);
+    uint32_t chunk_offset = back_reference.chunk_offset();
+    obj = HeapObject::FromAddress(reservations_[space][chunk_index].start +
+                                  chunk_offset);
   }
+  if (deserializing_user_code() && obj->IsInternalizedString()) {
+    obj = String::cast(obj)->GetForwardedInternalizedString();
+  }
+  hot_objects_.Add(obj);
   return obj;
 }
 
@@ -775,18 +823,34 @@
 // The reason for this strange interface is that otherwise the object is
 // written very late, which means the FreeSpace map is not set up by the
 // time we need to use it to mark the space at the end of a page free.
-void Deserializer::ReadObject(int space_number,
-                              Object** write_back) {
-  int size = source_->GetInt() << kObjectAlignmentBits;
-  Address address = Allocate(space_number, size);
-  HeapObject* obj = HeapObject::FromAddress(address);
+void Deserializer::ReadObject(int space_number, Object** write_back) {
+  Address address;
+  HeapObject* obj;
+  int next_int = source_.GetInt();
+
+  bool double_align = false;
+#ifndef V8_HOST_ARCH_64_BIT
+  double_align = next_int == kDoubleAlignmentSentinel;
+  if (double_align) next_int = source_.GetInt();
+#endif
+
+  DCHECK_NE(kDoubleAlignmentSentinel, next_int);
+  int size = next_int << kObjectAlignmentBits;
+  int reserved_size = size + (double_align ? kPointerSize : 0);
+  address = Allocate(space_number, reserved_size);
+  obj = HeapObject::FromAddress(address);
+  if (double_align) {
+    obj = isolate_->heap()->DoubleAlignForDeserialization(obj, reserved_size);
+    address = obj->address();
+  }
+
   isolate_->heap()->OnAllocationEvent(obj, size);
   Object** current = reinterpret_cast<Object**>(address);
   Object** limit = current + (size >> kPointerSizeLog2);
   if (FLAG_log_snapshot_positions) {
-    LOG(isolate_, SnapshotPositionEvent(address, source_->position()));
+    LOG(isolate_, SnapshotPositionEvent(address, source_.position()));
   }
-  ReadChunk(current, limit, space_number, address);
+  ReadData(current, limit, space_number, address);
 
   // TODO(mvstanton): consider treating the heap()->allocation_sites_list()
   // as a (weak) root. If this root is relocated correctly,
@@ -798,15 +862,53 @@
 
   *write_back = obj;
 #ifdef DEBUG
-  bool is_codespace = (space_number == CODE_SPACE);
-  DCHECK(obj->IsCode() == is_codespace);
+  if (obj->IsCode()) {
+    DCHECK(space_number == CODE_SPACE || space_number == LO_SPACE);
+  } else {
+    DCHECK(space_number != CODE_SPACE);
+  }
 #endif
 }
 
-void Deserializer::ReadChunk(Object** current,
-                             Object** limit,
-                             int source_space,
-                             Address current_object_address) {
+
+// We know the space requirements before deserialization and can
+// pre-allocate that reserved space. During deserialization, all we need
+// to do is to bump up the pointer for each space in the reserved
+// space. This is also used for fixing back references.
+// We may have to split up the pre-allocation into several chunks
+// because it would not fit onto a single page. We do not have to keep
+// track of when to move to the next chunk. An opcode will signal this.
+// Since multiple large objects cannot be folded into one large object
+// space allocation, we have to do an actual allocation when deserializing
+// each large object. Instead of tracking offset for back references, we
+// reference large objects by index.
+Address Deserializer::Allocate(int space_index, int size) {
+  if (space_index == LO_SPACE) {
+    AlwaysAllocateScope scope(isolate_);
+    LargeObjectSpace* lo_space = isolate_->heap()->lo_space();
+    Executability exec = static_cast<Executability>(source_.Get());
+    AllocationResult result = lo_space->AllocateRaw(size, exec);
+    HeapObject* obj = HeapObject::cast(result.ToObjectChecked());
+    deserialized_large_objects_.Add(obj);
+    return obj->address();
+  } else {
+    DCHECK(space_index < kNumberOfPreallocatedSpaces);
+    Address address = high_water_[space_index];
+    DCHECK_NE(NULL, address);
+    high_water_[space_index] += size;
+#ifdef DEBUG
+    // Assert that the current reserved chunk is still big enough.
+    const Heap::Reservation& reservation = reservations_[space_index];
+    int chunk_index = current_chunk_[space_index];
+    CHECK_LE(high_water_[space_index], reservation[chunk_index].end);
+#endif
+    return address;
+  }
+}
+
+
+void Deserializer::ReadData(Object** current, Object** limit, int source_space,
+                            Address current_object_address) {
   Isolate* const isolate = isolate_;
   // Write barrier support costs around 1% in startup time.  In fact there
   // are no new space objects in current boot snapshots, so it's not needed,
@@ -818,7 +920,7 @@
                                source_space != CODE_SPACE &&
                                source_space != OLD_DATA_SPACE);
   while (current < limit) {
-    int data = source_->Get();
+    byte data = source_.Get();
     switch (data) {
 #define CASE_STATEMENT(where, how, within, space_number) \
   case where + how + within + space_number:              \
@@ -842,29 +944,26 @@
       if (where == kNewObject) {                                               \
         ReadObject(space_number, &new_object);                                 \
       } else if (where == kRootArray) {                                        \
-        int root_id = source_->GetInt();                                       \
+        int root_id = source_.GetInt();                                        \
         new_object = isolate->heap()->roots_array_start()[root_id];            \
         emit_write_barrier = isolate->heap()->InNewSpace(new_object);          \
       } else if (where == kPartialSnapshotCache) {                             \
-        int cache_index = source_->GetInt();                                   \
+        int cache_index = source_.GetInt();                                    \
         new_object = isolate->serialize_partial_snapshot_cache()[cache_index]; \
         emit_write_barrier = isolate->heap()->InNewSpace(new_object);          \
       } else if (where == kExternalReference) {                                \
-        int skip = source_->GetInt();                                          \
+        int skip = source_.GetInt();                                           \
         current = reinterpret_cast<Object**>(                                  \
             reinterpret_cast<Address>(current) + skip);                        \
-        int reference_id = source_->GetInt();                                  \
+        int reference_id = source_.GetInt();                                   \
         Address address = external_reference_decoder_->Decode(reference_id);   \
         new_object = reinterpret_cast<Object*>(address);                       \
       } else if (where == kBackref) {                                          \
         emit_write_barrier = (space_number == NEW_SPACE);                      \
-        new_object = GetAddressFromEnd(data & kSpaceMask);                     \
-        if (deserializing_user_code()) {                                       \
-          new_object = ProcessBackRefInSerializedCode(new_object);             \
-        }                                                                      \
+        new_object = GetBackReferencedObject(data & kSpaceMask);               \
       } else if (where == kBuiltin) {                                          \
         DCHECK(deserializing_user_code());                                     \
-        int builtin_id = source_->GetInt();                                    \
+        int builtin_id = source_.GetInt();                                     \
         DCHECK_LE(0, builtin_id);                                              \
         DCHECK_LT(builtin_id, Builtins::builtin_count);                        \
         Builtins::Name name = static_cast<Builtins::Name>(builtin_id);         \
@@ -872,19 +971,16 @@
         emit_write_barrier = false;                                            \
       } else if (where == kAttachedReference) {                                \
         DCHECK(deserializing_user_code());                                     \
-        int index = source_->GetInt();                                         \
+        int index = source_.GetInt();                                          \
         new_object = *attached_objects_->at(index);                            \
         emit_write_barrier = isolate->heap()->InNewSpace(new_object);          \
       } else {                                                                 \
         DCHECK(where == kBackrefWithSkip);                                     \
-        int skip = source_->GetInt();                                          \
+        int skip = source_.GetInt();                                           \
         current = reinterpret_cast<Object**>(                                  \
             reinterpret_cast<Address>(current) + skip);                        \
         emit_write_barrier = (space_number == NEW_SPACE);                      \
-        new_object = GetAddressFromEnd(data & kSpaceMask);                     \
-        if (deserializing_user_code()) {                                       \
-          new_object = ProcessBackRefInSerializedCode(new_object);             \
-        }                                                                      \
+        new_object = GetBackReferencedObject(data & kSpaceMask);               \
       }                                                                        \
       if (within == kInnerPointer) {                                           \
         if (space_number != CODE_SPACE || new_object->IsCode()) {              \
@@ -925,15 +1021,16 @@
 // This generates a case and a body for the new space (which has to do extra
 // write barrier handling) and handles the other spaces with 8 fall-through
 // cases and one body.
-#define ALL_SPACES(where, how, within)                                         \
-  CASE_STATEMENT(where, how, within, NEW_SPACE)                                \
-  CASE_BODY(where, how, within, NEW_SPACE)                                     \
-  CASE_STATEMENT(where, how, within, OLD_DATA_SPACE)                           \
-  CASE_STATEMENT(where, how, within, OLD_POINTER_SPACE)                        \
-  CASE_STATEMENT(where, how, within, CODE_SPACE)                               \
-  CASE_STATEMENT(where, how, within, CELL_SPACE)                               \
-  CASE_STATEMENT(where, how, within, PROPERTY_CELL_SPACE)                      \
-  CASE_STATEMENT(where, how, within, MAP_SPACE)                                \
+#define ALL_SPACES(where, how, within)                    \
+  CASE_STATEMENT(where, how, within, NEW_SPACE)           \
+  CASE_BODY(where, how, within, NEW_SPACE)                \
+  CASE_STATEMENT(where, how, within, OLD_DATA_SPACE)      \
+  CASE_STATEMENT(where, how, within, OLD_POINTER_SPACE)   \
+  CASE_STATEMENT(where, how, within, CODE_SPACE)          \
+  CASE_STATEMENT(where, how, within, MAP_SPACE)           \
+  CASE_STATEMENT(where, how, within, CELL_SPACE)          \
+  CASE_STATEMENT(where, how, within, PROPERTY_CELL_SPACE) \
+  CASE_STATEMENT(where, how, within, LO_SPACE)            \
   CASE_BODY(where, how, within, kAnyOldSpace)
 
 #define FOUR_CASES(byte_code)             \
@@ -983,23 +1080,22 @@
 
       // We generate 15 cases and bodies that process special tags that combine
       // the raw data tag and the length into one byte.
-#define RAW_CASE(index)                                                      \
-      case kRawData + index: {                                               \
-        byte* raw_data_out = reinterpret_cast<byte*>(current);               \
-        source_->CopyRaw(raw_data_out, index * kPointerSize);                \
-        current =                                                            \
-            reinterpret_cast<Object**>(raw_data_out + index * kPointerSize); \
-        break;                                                               \
-      }
+#define RAW_CASE(index)                                                        \
+  case kRawData + index: {                                                     \
+    byte* raw_data_out = reinterpret_cast<byte*>(current);                     \
+    source_.CopyRaw(raw_data_out, index* kPointerSize);                        \
+    current = reinterpret_cast<Object**>(raw_data_out + index * kPointerSize); \
+    break;                                                                     \
+  }
       COMMON_RAW_LENGTHS(RAW_CASE)
 #undef RAW_CASE
 
       // Deserialize a chunk of raw data that doesn't have one of the popular
       // lengths.
       case kRawData: {
-        int size = source_->GetInt();
+        int size = source_.GetInt();
         byte* raw_data_out = reinterpret_cast<byte*>(current);
-        source_->CopyRaw(raw_data_out, size);
+        source_.CopyRaw(raw_data_out, size);
         break;
       }
 
@@ -1015,7 +1111,7 @@
       SIXTEEN_CASES(kRootArrayConstants + kHasSkipDistance)
       SIXTEEN_CASES(kRootArrayConstants + kHasSkipDistance + 16) {
         int root_id = RootArrayConstantFromByteCode(data);
-        int skip = source_->GetInt();
+        int skip = source_.GetInt();
         current = reinterpret_cast<Object**>(
             reinterpret_cast<intptr_t>(current) + skip);
         Object* object = isolate->heap()->roots_array_start()[root_id];
@@ -1024,8 +1120,8 @@
         break;
       }
 
-      case kRepeat: {
-        int repeats = source_->GetInt();
+      case kVariableRepeat: {
+        int repeats = source_.GetInt();
         Object* object = current[-1];
         DCHECK(!isolate->heap()->InNewSpace(object));
         for (int i = 0; i < repeats; i++) current[i] = object;
@@ -1035,11 +1131,13 @@
 
       STATIC_ASSERT(kRootArrayNumberOfConstantEncodings ==
                     Heap::kOldSpaceRoots);
-      STATIC_ASSERT(kMaxRepeats == 13);
-      case kConstantRepeat:
-      FOUR_CASES(kConstantRepeat + 1)
-      FOUR_CASES(kConstantRepeat + 5)
-      FOUR_CASES(kConstantRepeat + 9) {
+      STATIC_ASSERT(kMaxFixedRepeats == 15);
+      FOUR_CASES(kFixedRepeat)
+      FOUR_CASES(kFixedRepeat + 4)
+      FOUR_CASES(kFixedRepeat + 8)
+      case kFixedRepeat + 12:
+      case kFixedRepeat + 13:
+      case kFixedRepeat + 14: {
         int repeats = RepeatsForCode(data);
         Object* object = current[-1];
         DCHECK(!isolate->heap()->InNewSpace(object));
@@ -1125,13 +1223,8 @@
       // Find a builtin and write a pointer to it to the current object.
       CASE_STATEMENT(kBuiltin, kPlain, kStartOfObject, 0)
       CASE_BODY(kBuiltin, kPlain, kStartOfObject, 0)
-#if V8_OOL_CONSTANT_POOL
-      // Find a builtin code entry and write a pointer to it to the current
-      // object.
       CASE_STATEMENT(kBuiltin, kPlain, kInnerPointer, 0)
       CASE_BODY(kBuiltin, kPlain, kInnerPointer, 0)
-#endif
-      // Find a builtin and write a pointer to it in the current code object.
       CASE_STATEMENT(kBuiltin, kFromCode, kInnerPointer, 0)
       CASE_BODY(kBuiltin, kFromCode, kInnerPointer, 0)
       // Find an object in the attached references and write a pointer to it to
@@ -1148,15 +1241,15 @@
 #undef ALL_SPACES
 
       case kSkip: {
-        int size = source_->GetInt();
+        int size = source_.GetInt();
         current = reinterpret_cast<Object**>(
             reinterpret_cast<intptr_t>(current) + size);
         break;
       }
 
       case kNativesStringResource: {
-        int index = source_->Get();
-        Vector<const char> source_vector = Natives::GetRawScriptSource(index);
+        int index = source_.Get();
+        Vector<const char> source_vector = Natives::GetScriptSource(index);
         NativesExternalStringResource* resource =
             new NativesExternalStringResource(isolate->bootstrapper(),
                                               source_vector.start(),
@@ -1165,6 +1258,41 @@
         break;
       }
 
+      case kNextChunk: {
+        int space = source_.Get();
+        DCHECK(space < kNumberOfPreallocatedSpaces);
+        int chunk_index = current_chunk_[space];
+        const Heap::Reservation& reservation = reservations_[space];
+        // Make sure the current chunk is indeed exhausted.
+        CHECK_EQ(reservation[chunk_index].end, high_water_[space]);
+        // Move to next reserved chunk.
+        chunk_index = ++current_chunk_[space];
+        DCHECK_LT(chunk_index, reservation.length());
+        high_water_[space] = reservation[chunk_index].start;
+        break;
+      }
+
+      FOUR_CASES(kHotObjectWithSkip)
+      FOUR_CASES(kHotObjectWithSkip + 4) {
+        int skip = source_.GetInt();
+        current = reinterpret_cast<Object**>(
+            reinterpret_cast<Address>(current) + skip);
+        // Fall through.
+      }
+      FOUR_CASES(kHotObject)
+      FOUR_CASES(kHotObject + 4) {
+        int index = data & kHotObjectIndexMask;
+        *current = hot_objects_.Get(index);
+        if (write_barrier_needed && isolate->heap()->InNewSpace(*current)) {
+          Address current_address = reinterpret_cast<Address>(current);
+          isolate->heap()->RecordWrite(
+              current_object_address,
+              static_cast<int>(current_address - current_object_address));
+        }
+        current++;
+        break;
+      }
+
       case kSynchronize: {
         // If we get here then that indicates that you have a mismatch between
         // the number of GC roots when serializing and deserializing.
@@ -1183,12 +1311,16 @@
     : isolate_(isolate),
       sink_(sink),
       external_reference_encoder_(new ExternalReferenceEncoder(isolate)),
-      root_index_wave_front_(0),
-      code_address_map_(NULL) {
+      root_index_map_(isolate),
+      code_address_map_(NULL),
+      large_objects_total_size_(0),
+      seen_large_objects_index_(0) {
   // The serializer is meant to be used only to generate initial heap images
   // from a context in which there is only one isolate.
-  for (int i = 0; i <= LAST_SPACE; i++) {
-    fullness_[i] = 0;
+  for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) {
+    pending_chunk_[i] = 0;
+    max_chunk_size_[i] = static_cast<uint32_t>(
+        MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(i)));
   }
 }
 
@@ -1214,6 +1346,27 @@
 }
 
 
+void StartupSerializer::VisitPointers(Object** start, Object** end) {
+  for (Object** current = start; current < end; current++) {
+    if (start == isolate()->heap()->roots_array_start()) {
+      root_index_wave_front_ =
+          Max(root_index_wave_front_, static_cast<intptr_t>(current - start));
+    }
+    if (ShouldBeSkipped(current)) {
+      sink_->Put(kSkip, "Skip");
+      sink_->PutInt(kPointerSize, "SkipOneWord");
+    } else if ((*current)->IsSmi()) {
+      sink_->Put(kOnePointerRawData, "Smi");
+      for (int i = 0; i < kPointerSize; i++) {
+        sink_->Put(reinterpret_cast<byte*>(current)[i], "Byte");
+      }
+    } else {
+      SerializeObject(HeapObject::cast(*current), kPlain, kStartOfObject, 0);
+    }
+  }
+}
+
+
 void PartialSerializer::Serialize(Object** object) {
   this->VisitPointer(object);
   Pad();
@@ -1229,28 +1382,37 @@
 
 
 void Serializer::VisitPointers(Object** start, Object** end) {
-  Isolate* isolate = this->isolate();;
-
   for (Object** current = start; current < end; current++) {
-    if (start == isolate->heap()->roots_array_start()) {
-      root_index_wave_front_ =
-          Max(root_index_wave_front_, static_cast<intptr_t>(current - start));
-    }
-    if (ShouldBeSkipped(current)) {
-      sink_->Put(kSkip, "Skip");
-      sink_->PutInt(kPointerSize, "SkipOneWord");
-    } else if ((*current)->IsSmi()) {
-      sink_->Put(kRawData + 1, "Smi");
+    if ((*current)->IsSmi()) {
+      sink_->Put(kOnePointerRawData, "Smi");
       for (int i = 0; i < kPointerSize; i++) {
         sink_->Put(reinterpret_cast<byte*>(current)[i], "Byte");
       }
     } else {
-      SerializeObject(*current, kPlain, kStartOfObject, 0);
+      SerializeObject(HeapObject::cast(*current), kPlain, kStartOfObject, 0);
     }
   }
 }
 
 
+void Serializer::EncodeReservations(
+    List<SerializedData::Reservation>* out) const {
+  for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) {
+    for (int j = 0; j < completed_chunks_[i].length(); j++) {
+      out->Add(SerializedData::Reservation(completed_chunks_[i][j]));
+    }
+
+    if (pending_chunk_[i] > 0 || completed_chunks_[i].length() == 0) {
+      out->Add(SerializedData::Reservation(pending_chunk_[i]));
+    }
+    out->last().mark_as_last();
+  }
+
+  out->Add(SerializedData::Reservation(large_objects_total_size_));
+  out->last().mark_as_last();
+}
+
+
 // This ensures that the partial snapshot cache keeps things alive during GC and
 // tracks their movement.  When it is called during serialization of the startup
 // snapshot nothing happens.  When the partial (context) snapshot is created,
@@ -1302,80 +1464,90 @@
 }
 
 
-int Serializer::RootIndex(HeapObject* heap_object, HowToCode from) {
-  Heap* heap = isolate()->heap();
-  if (heap->InNewSpace(heap_object)) return kInvalidRootIndex;
-  for (int i = 0; i < root_index_wave_front_; i++) {
-    Object* root = heap->roots_array_start()[i];
-    if (!root->IsSmi() && root == heap_object) {
-      return i;
+bool Serializer::SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
+                                      WhereToPoint where_to_point, int skip) {
+  if (how_to_code == kPlain && where_to_point == kStartOfObject) {
+    // Encode a reference to a hot object by its index in the working set.
+    int index = hot_objects_.Find(obj);
+    if (index != HotObjectsList::kNotFound) {
+      DCHECK(index >= 0 && index <= kMaxHotObjectIndex);
+      if (FLAG_trace_serializer) {
+        PrintF(" Encoding hot object %d:", index);
+        obj->ShortPrint();
+        PrintF("\n");
+      }
+      if (skip != 0) {
+        sink_->Put(kHotObjectWithSkip + index, "HotObjectWithSkip");
+        sink_->PutInt(skip, "HotObjectSkipDistance");
+      } else {
+        sink_->Put(kHotObject + index, "HotObject");
+      }
+      return true;
     }
   }
-  return kInvalidRootIndex;
-}
+  BackReference back_reference = back_reference_map_.Lookup(obj);
+  if (back_reference.is_valid()) {
+    // Encode the location of an already deserialized object in order to write
+    // its location into a later object.  We can encode the location as an
+    // offset fromthe start of the deserialized objects or as an offset
+    // backwards from thecurrent allocation pointer.
+    if (back_reference.is_source()) {
+      FlushSkip(skip);
+      if (FLAG_trace_serializer) PrintF(" Encoding source object\n");
+      DCHECK(how_to_code == kPlain && where_to_point == kStartOfObject);
+      sink_->Put(kAttachedReference + how_to_code + where_to_point, "Source");
+      sink_->PutInt(kSourceObjectReference, "kSourceObjectIndex");
+    } else {
+      if (FLAG_trace_serializer) {
+        PrintF(" Encoding back reference to: ");
+        obj->ShortPrint();
+        PrintF("\n");
+      }
 
+      AllocationSpace space = back_reference.space();
+      if (skip == 0) {
+        sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRef");
+      } else {
+        sink_->Put(kBackrefWithSkip + how_to_code + where_to_point + space,
+                   "BackRefWithSkip");
+        sink_->PutInt(skip, "BackRefSkipDistance");
+      }
+      sink_->PutInt(back_reference.reference(), "BackRefValue");
 
-// Encode the location of an already deserialized object in order to write its
-// location into a later object.  We can encode the location as an offset from
-// the start of the deserialized objects or as an offset backwards from the
-// current allocation pointer.
-void Serializer::SerializeReferenceToPreviousObject(HeapObject* heap_object,
-                                                    HowToCode how_to_code,
-                                                    WhereToPoint where_to_point,
-                                                    int skip) {
-  int space = SpaceOfObject(heap_object);
-  int address = address_mapper_.MappedTo(heap_object);
-  int offset = CurrentAllocationAddress(space) - address;
-  // Shift out the bits that are always 0.
-  offset >>= kObjectAlignmentBits;
-  if (skip == 0) {
-    sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRefSer");
-  } else {
-    sink_->Put(kBackrefWithSkip + how_to_code + where_to_point + space,
-               "BackRefSerWithSkip");
-    sink_->PutInt(skip, "BackRefSkipDistance");
+      hot_objects_.Add(obj);
+    }
+    return true;
   }
-  sink_->PutInt(offset, "offset");
+  return false;
 }
 
 
-void StartupSerializer::SerializeObject(
-    Object* o,
-    HowToCode how_to_code,
-    WhereToPoint where_to_point,
-    int skip) {
-  CHECK(o->IsHeapObject());
-  HeapObject* heap_object = HeapObject::cast(o);
-  DCHECK(!heap_object->IsJSFunction());
+void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
+                                        WhereToPoint where_to_point, int skip) {
+  DCHECK(!obj->IsJSFunction());
 
-  int root_index;
-  if ((root_index = RootIndex(heap_object, how_to_code)) != kInvalidRootIndex) {
-    PutRoot(root_index, heap_object, how_to_code, where_to_point, skip);
+  int root_index = root_index_map_.Lookup(obj);
+  // We can only encode roots as such if it has already been serialized.
+  // That applies to root indices below the wave front.
+  if (root_index != RootIndexMap::kInvalidRootIndex &&
+      root_index < root_index_wave_front_) {
+    PutRoot(root_index, obj, how_to_code, where_to_point, skip);
     return;
   }
 
-  if (address_mapper_.IsMapped(heap_object)) {
-    SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point,
-                                       skip);
-  } else {
-    if (skip != 0) {
-      sink_->Put(kSkip, "FlushPendingSkip");
-      sink_->PutInt(skip, "SkipDistance");
-    }
+  if (SerializeKnownObject(obj, how_to_code, where_to_point, skip)) return;
 
-    // Object has not yet been serialized.  Serialize it here.
-    ObjectSerializer object_serializer(this,
-                                       heap_object,
-                                       sink_,
-                                       how_to_code,
-                                       where_to_point);
-    object_serializer.Serialize();
-  }
+  FlushSkip(skip);
+
+  // Object has not yet been serialized.  Serialize it here.
+  ObjectSerializer object_serializer(this, obj, sink_, how_to_code,
+                                     where_to_point);
+  object_serializer.Serialize();
 }
 
 
 void StartupSerializer::SerializeWeakReferences() {
-  // This phase comes right after the partial serialization (of the snapshot).
+  // This phase comes right after the serialization (of the snapshot).
   // After we have done the partial serialization the partial snapshot cache
   // will contain some references needed to decode the partial snapshot.  We
   // add one entry with 'undefined' which is the sentinel that the deserializer
@@ -1392,6 +1564,12 @@
                          SerializerDeserializer::HowToCode how_to_code,
                          SerializerDeserializer::WhereToPoint where_to_point,
                          int skip) {
+  if (FLAG_trace_serializer) {
+    PrintF(" Encoding root %d:", root_index);
+    object->ShortPrint();
+    PrintF("\n");
+  }
+
   if (how_to_code == kPlain &&
       where_to_point == kStartOfObject &&
       root_index < kRootArrayNumberOfConstantEncodings &&
@@ -1405,44 +1583,31 @@
       sink_->PutInt(skip, "SkipInPutRoot");
     }
   } else {
-    if (skip != 0) {
-      sink_->Put(kSkip, "SkipFromPutRoot");
-      sink_->PutInt(skip, "SkipFromPutRootDistance");
-    }
+    FlushSkip(skip);
     sink_->Put(kRootArray + how_to_code + where_to_point, "RootSerialization");
     sink_->PutInt(root_index, "root_index");
   }
 }
 
 
-void PartialSerializer::SerializeObject(
-    Object* o,
-    HowToCode how_to_code,
-    WhereToPoint where_to_point,
-    int skip) {
-  CHECK(o->IsHeapObject());
-  HeapObject* heap_object = HeapObject::cast(o);
-
-  if (heap_object->IsMap()) {
+void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
+                                        WhereToPoint where_to_point, int skip) {
+  if (obj->IsMap()) {
     // The code-caches link to context-specific code objects, which
     // the startup and context serializes cannot currently handle.
-    DCHECK(Map::cast(heap_object)->code_cache() ==
-           heap_object->GetHeap()->empty_fixed_array());
+    DCHECK(Map::cast(obj)->code_cache() == obj->GetHeap()->empty_fixed_array());
   }
 
-  int root_index;
-  if ((root_index = RootIndex(heap_object, how_to_code)) != kInvalidRootIndex) {
-    PutRoot(root_index, heap_object, how_to_code, where_to_point, skip);
+  int root_index = root_index_map_.Lookup(obj);
+  if (root_index != RootIndexMap::kInvalidRootIndex) {
+    PutRoot(root_index, obj, how_to_code, where_to_point, skip);
     return;
   }
 
-  if (ShouldBeInThePartialSnapshotCache(heap_object)) {
-    if (skip != 0) {
-      sink_->Put(kSkip, "SkipFromSerializeObject");
-      sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
-    }
+  if (ShouldBeInThePartialSnapshotCache(obj)) {
+    FlushSkip(skip);
 
-    int cache_index = PartialSnapshotCacheIndex(heap_object);
+    int cache_index = PartialSnapshotCacheIndex(obj);
     sink_->Put(kPartialSnapshotCache + how_to_code + where_to_point,
                "PartialSnapshotCache");
     sink_->PutInt(cache_index, "partial_snapshot_cache_index");
@@ -1452,38 +1617,23 @@
   // Pointers from the partial snapshot to the objects in the startup snapshot
   // should go through the root array or through the partial snapshot cache.
   // If this is not the case you may have to add something to the root array.
-  DCHECK(!startup_serializer_->address_mapper()->IsMapped(heap_object));
+  DCHECK(!startup_serializer_->back_reference_map()->Lookup(obj).is_valid());
   // All the internalized strings that the partial snapshot needs should be
   // either in the root table or in the partial snapshot cache.
-  DCHECK(!heap_object->IsInternalizedString());
+  DCHECK(!obj->IsInternalizedString());
 
-  if (address_mapper_.IsMapped(heap_object)) {
-    SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point,
-                                       skip);
-  } else {
-    if (skip != 0) {
-      sink_->Put(kSkip, "SkipFromSerializeObject");
-      sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
-    }
-    // Object has not yet been serialized.  Serialize it here.
-    ObjectSerializer serializer(this,
-                                heap_object,
-                                sink_,
-                                how_to_code,
-                                where_to_point);
-    serializer.Serialize();
-  }
+  if (SerializeKnownObject(obj, how_to_code, where_to_point, skip)) return;
+
+  FlushSkip(skip);
+
+  // Object has not yet been serialized.  Serialize it here.
+  ObjectSerializer serializer(this, obj, sink_, how_to_code, where_to_point);
+  serializer.Serialize();
 }
 
 
-void Serializer::ObjectSerializer::Serialize() {
-  int space = Serializer::SpaceOfObject(object_);
-  int size = object_->Size();
-
-  sink_->Put(kNewObject + reference_representation_ + space,
-             "ObjectSerialization");
-  sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
-
+void Serializer::ObjectSerializer::SerializePrologue(AllocationSpace space,
+                                                     int size, Map* map) {
   if (serializer_->code_address_map_) {
     const char* code_name =
         serializer_->code_address_map_->Lookup(object_->address());
@@ -1493,17 +1643,140 @@
         SnapshotPositionEvent(object_->address(), sink_->Position()));
   }
 
+  BackReference back_reference;
+  if (space == LO_SPACE) {
+    sink_->Put(kNewObject + reference_representation_ + space,
+               "NewLargeObject");
+    sink_->PutInt(size >> kObjectAlignmentBits, "ObjectSizeInWords");
+    if (object_->IsCode()) {
+      sink_->Put(EXECUTABLE, "executable large object");
+    } else {
+      sink_->Put(NOT_EXECUTABLE, "not executable large object");
+    }
+    back_reference = serializer_->AllocateLargeObject(size);
+  } else {
+    bool needs_double_align = false;
+    if (object_->NeedsToEnsureDoubleAlignment()) {
+      // Add wriggle room for double alignment padding.
+      back_reference = serializer_->Allocate(space, size + kPointerSize);
+      needs_double_align = true;
+    } else {
+      back_reference = serializer_->Allocate(space, size);
+    }
+    sink_->Put(kNewObject + reference_representation_ + space, "NewObject");
+    if (needs_double_align)
+      sink_->PutInt(kDoubleAlignmentSentinel, "DoubleAlignSentinel");
+    int encoded_size = size >> kObjectAlignmentBits;
+    DCHECK_NE(kDoubleAlignmentSentinel, encoded_size);
+    sink_->PutInt(encoded_size, "ObjectSizeInWords");
+  }
+
   // Mark this object as already serialized.
-  int offset = serializer_->Allocate(space, size);
-  serializer_->address_mapper()->AddMapping(object_, offset);
+  serializer_->back_reference_map()->Add(object_, back_reference);
 
   // Serialize the map (first word of the object).
-  serializer_->SerializeObject(object_->map(), kPlain, kStartOfObject, 0);
+  serializer_->SerializeObject(map, kPlain, kStartOfObject, 0);
+}
+
+
+void Serializer::ObjectSerializer::SerializeExternalString() {
+  // Instead of serializing this as an external string, we serialize
+  // an imaginary sequential string with the same content.
+  Isolate* isolate = serializer_->isolate();
+  DCHECK(object_->IsExternalString());
+  DCHECK(object_->map() != isolate->heap()->native_source_string_map());
+  ExternalString* string = ExternalString::cast(object_);
+  int length = string->length();
+  Map* map;
+  int content_size;
+  int allocation_size;
+  const byte* resource;
+  // Find the map and size for the imaginary sequential string.
+  bool internalized = object_->IsInternalizedString();
+  if (object_->IsExternalOneByteString()) {
+    map = internalized ? isolate->heap()->one_byte_internalized_string_map()
+                       : isolate->heap()->one_byte_string_map();
+    allocation_size = SeqOneByteString::SizeFor(length);
+    content_size = length * kCharSize;
+    resource = reinterpret_cast<const byte*>(
+        ExternalOneByteString::cast(string)->resource()->data());
+  } else {
+    map = internalized ? isolate->heap()->internalized_string_map()
+                       : isolate->heap()->string_map();
+    allocation_size = SeqTwoByteString::SizeFor(length);
+    content_size = length * kShortSize;
+    resource = reinterpret_cast<const byte*>(
+        ExternalTwoByteString::cast(string)->resource()->data());
+  }
+
+  AllocationSpace space = (allocation_size > Page::kMaxRegularHeapObjectSize)
+                              ? LO_SPACE
+                              : OLD_DATA_SPACE;
+  SerializePrologue(space, allocation_size, map);
+
+  // Output the rest of the imaginary string.
+  int bytes_to_output = allocation_size - HeapObject::kHeaderSize;
+
+  // Output raw data header. Do not bother with common raw length cases here.
+  sink_->Put(kRawData, "RawDataForString");
+  sink_->PutInt(bytes_to_output, "length");
+
+  // Serialize string header (except for map).
+  Address string_start = string->address();
+  for (int i = HeapObject::kHeaderSize; i < SeqString::kHeaderSize; i++) {
+    sink_->PutSection(string_start[i], "StringHeader");
+  }
+
+  // Serialize string content.
+  sink_->PutRaw(resource, content_size, "StringContent");
+
+  // Since the allocation size is rounded up to object alignment, there
+  // maybe left-over bytes that need to be padded.
+  int padding_size = allocation_size - SeqString::kHeaderSize - content_size;
+  DCHECK(0 <= padding_size && padding_size < kObjectAlignment);
+  for (int i = 0; i < padding_size; i++) sink_->PutSection(0, "StringPadding");
+
+  sink_->Put(kSkip, "SkipAfterString");
+  sink_->PutInt(bytes_to_output, "SkipDistance");
+}
+
+
+void Serializer::ObjectSerializer::Serialize() {
+  if (FLAG_trace_serializer) {
+    PrintF(" Encoding heap object: ");
+    object_->ShortPrint();
+    PrintF("\n");
+  }
+
+  if (object_->IsScript()) {
+    // Clear cached line ends.
+    Object* undefined = serializer_->isolate()->heap()->undefined_value();
+    Script::cast(object_)->set_line_ends(undefined);
+  }
+
+  if (object_->IsExternalString()) {
+    Heap* heap = serializer_->isolate()->heap();
+    if (object_->map() != heap->native_source_string_map()) {
+      // Usually we cannot recreate resources for external strings. To work
+      // around this, external strings are serialized to look like ordinary
+      // sequential strings.
+      // The exception are native source code strings, since we can recreate
+      // their resources. In that case we fall through and leave it to
+      // VisitExternalOneByteString further down.
+      SerializeExternalString();
+      return;
+    }
+  }
+
+  int size = object_->Size();
+  Map* map = object_->map();
+  SerializePrologue(Serializer::SpaceOfObject(object_), size, map);
 
   // Serialize the rest of the object.
   CHECK_EQ(0, bytes_processed_so_far_);
   bytes_processed_so_far_ = kPointerSize;
-  object_->IterateBody(object_->map()->instance_type(), size, this);
+
+  object_->IterateBody(map->instance_type(), size, this);
   OutputRawData(object_->address() + size);
 }
 
@@ -1517,13 +1790,11 @@
 
     while (current < end && !(*current)->IsSmi()) {
       HeapObject* current_contents = HeapObject::cast(*current);
-      int root_index = serializer_->RootIndex(current_contents, kPlain);
-      // Repeats are not subject to the write barrier so there are only some
-      // objects that can be used in a repeat encoding.  These are the early
-      // ones in the root array that are never in new space.
-      if (current != start &&
-          root_index != kInvalidRootIndex &&
-          root_index < kRootArrayNumberOfConstantEncodings &&
+      int root_index = serializer_->root_index_map()->Lookup(current_contents);
+      // Repeats are not subject to the write barrier so we can only use
+      // immortal immovable root members. They are never in new space.
+      if (current != start && root_index != RootIndexMap::kInvalidRootIndex &&
+          Heap::RootIsImmortalImmovable(root_index) &&
           current_contents == current[-1]) {
         DCHECK(!serializer_->isolate()->heap()->InNewSpace(current_contents));
         int repeat_count = 1;
@@ -1533,8 +1804,8 @@
         }
         current += repeat_count;
         bytes_processed_so_far_ += repeat_count * kPointerSize;
-        if (repeat_count > kMaxRepeats) {
-          sink_->Put(kRepeat, "SerializeRepeats");
+        if (repeat_count > kMaxFixedRepeats) {
+          sink_->Put(kVariableRepeat, "SerializeRepeats");
           sink_->PutInt(repeat_count, "SerializeRepeats");
         } else {
           sink_->Put(CodeForRepeats(repeat_count), "SerializeRepeats");
@@ -1558,7 +1829,8 @@
                            kCanReturnSkipInsteadOfSkipping);
   HowToCode how_to_code = rinfo->IsCodedSpecially() ? kFromCode : kPlain;
   Object* object = rinfo->target_object();
-  serializer_->SerializeObject(object, how_to_code, kStartOfObject, skip);
+  serializer_->SerializeObject(HeapObject::cast(object), how_to_code,
+                               kStartOfObject, skip);
   bytes_processed_so_far_ += rinfo->target_address_size();
 }
 
@@ -1649,7 +1921,7 @@
     }
   }
   // One of the strings in the natives cache should match the resource.  We
-  // can't serialize any other kinds of external strings.
+  // don't expect any other kinds of external strings here.
   UNREACHABLE();
 }
 
@@ -1712,6 +1984,8 @@
     // To make snapshots reproducible, we need to wipe out all pointers in code.
     if (code_object_) {
       Code* code = CloneCodeObject(object_);
+      // Code age headers are not serializable.
+      code->MakeYoung(serializer_->isolate());
       WipeOutRelocations(code);
       // We need to wipe out the header fields *after* wiping out the
       // relocations, because some of these fields are needed for the latter.
@@ -1720,9 +1994,7 @@
     }
 
     const char* description = code_object_ ? "Code" : "Byte";
-    for (int i = 0; i < bytes_to_output; i++) {
-      sink_->PutSection(object_start[base + i], description);
-    }
+    sink_->PutRaw(object_start + base, bytes_to_output, description);
     if (code_object_) delete[] object_start;
   }
   if (to_skip != 0 && return_skip == kIgnoringReturn) {
@@ -1734,33 +2006,45 @@
 }
 
 
-int Serializer::SpaceOfObject(HeapObject* object) {
+AllocationSpace Serializer::SpaceOfObject(HeapObject* object) {
   for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
     AllocationSpace s = static_cast<AllocationSpace>(i);
     if (object->GetHeap()->InSpace(object, s)) {
       DCHECK(i < kNumberOfSpaces);
-      return i;
+      return s;
     }
   }
   UNREACHABLE();
-  return 0;
+  return FIRST_SPACE;
 }
 
 
-int Serializer::Allocate(int space, int size) {
-  CHECK(space >= 0 && space < kNumberOfSpaces);
-  int allocation_address = fullness_[space];
-  fullness_[space] = allocation_address + size;
-  return allocation_address;
+BackReference Serializer::AllocateLargeObject(int size) {
+  // Large objects are allocated one-by-one when deserializing. We do not
+  // have to keep track of multiple chunks.
+  large_objects_total_size_ += size;
+  return BackReference::LargeObjectReference(seen_large_objects_index_++);
 }
 
 
-int Serializer::SpaceAreaSize(int space) {
-  if (space == CODE_SPACE) {
-    return isolate_->memory_allocator()->CodePageAreaSize();
-  } else {
-    return Page::kPageSize - Page::kObjectStartOffset;
+BackReference Serializer::Allocate(AllocationSpace space, int size) {
+  DCHECK(space >= 0 && space < kNumberOfPreallocatedSpaces);
+  DCHECK(size > 0 && size <= static_cast<int>(max_chunk_size(space)));
+  uint32_t new_chunk_size = pending_chunk_[space] + size;
+  if (new_chunk_size > max_chunk_size(space)) {
+    // The new chunk size would not fit onto a single page. Complete the
+    // current chunk and start a new one.
+    sink_->Put(kNextChunk, "NextChunk");
+    sink_->Put(space, "NextChunkSpace");
+    completed_chunks_[space].Add(pending_chunk_[space]);
+    DCHECK_LE(completed_chunks_[space].length(), BackReference::kMaxChunkIndex);
+    pending_chunk_[space] = 0;
+    new_chunk_size = size;
   }
+  uint32_t offset = pending_chunk_[space];
+  pending_chunk_[space] = new_chunk_size;
+  return BackReference::Reference(space, completed_chunks_[space].length(),
+                                  offset);
 }
 
 
@@ -1770,6 +2054,10 @@
   for (unsigned i = 0; i < sizeof(int32_t) - 1; i++) {
     sink_->Put(kNop, "Padding");
   }
+  // Pad up to pointer size for checksum.
+  while (!IsAligned(sink_->Position(), kPointerAlignment)) {
+    sink_->Put(kNop, "Padding");
+  }
 }
 
 
@@ -1784,21 +2072,22 @@
                                       Handle<String> source) {
   base::ElapsedTimer timer;
   if (FLAG_profile_deserialization) timer.Start();
+  if (FLAG_trace_serializer) {
+    PrintF("[Serializing from");
+    Object* script = info->script();
+    if (script->IsScript()) Script::cast(script)->name()->ShortPrint();
+    PrintF("]\n");
+  }
 
   // Serialize code object.
-  List<byte> payload;
-  ListSnapshotSink list_sink(&payload);
-  DebugSnapshotSink debug_sink(&list_sink);
-  SnapshotByteSink* sink = FLAG_trace_code_serializer
-                               ? static_cast<SnapshotByteSink*>(&debug_sink)
-                               : static_cast<SnapshotByteSink*>(&list_sink);
-  CodeSerializer cs(isolate, sink, *source);
+  SnapshotByteSink sink(info->code()->CodeSize() * 2);
+  CodeSerializer cs(isolate, &sink, *source, info->code());
   DisallowHeapAllocation no_gc;
   Object** location = Handle<Object>::cast(info).location();
   cs.VisitPointer(location);
   cs.Pad();
 
-  SerializedCodeData data(&payload, &cs);
+  SerializedCodeData data(sink.data(), cs);
   ScriptData* script_data = data.GetScriptData();
 
   if (FLAG_profile_deserialization) {
@@ -1811,76 +2100,70 @@
 }
 
 
-void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
+void CodeSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
                                      WhereToPoint where_to_point, int skip) {
-  CHECK(o->IsHeapObject());
-  HeapObject* heap_object = HeapObject::cast(o);
-
-  // The code-caches link to context-specific code objects, which
-  // the startup and context serializes cannot currently handle.
-  DCHECK(!heap_object->IsMap() ||
-         Map::cast(heap_object)->code_cache() ==
-             heap_object->GetHeap()->empty_fixed_array());
-
-  int root_index;
-  if ((root_index = RootIndex(heap_object, how_to_code)) != kInvalidRootIndex) {
-    PutRoot(root_index, heap_object, how_to_code, where_to_point, skip);
+  int root_index = root_index_map_.Lookup(obj);
+  if (root_index != RootIndexMap::kInvalidRootIndex) {
+    PutRoot(root_index, obj, how_to_code, where_to_point, skip);
     return;
   }
 
-  // TODO(yangguo) wire up global object.
-  // TODO(yangguo) We cannot deal with different hash seeds yet.
-  DCHECK(!heap_object->IsHashTable());
+  if (SerializeKnownObject(obj, how_to_code, where_to_point, skip)) return;
 
-  if (address_mapper_.IsMapped(heap_object)) {
-    SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point,
-                                       skip);
-    return;
-  }
+  FlushSkip(skip);
 
-  if (heap_object->IsCode()) {
-    Code* code_object = Code::cast(heap_object);
-    if (code_object->kind() == Code::BUILTIN) {
-      SerializeBuiltin(code_object, how_to_code, where_to_point, skip);
-      return;
+  if (obj->IsCode()) {
+    Code* code_object = Code::cast(obj);
+    switch (code_object->kind()) {
+      case Code::OPTIMIZED_FUNCTION:  // No optimized code compiled yet.
+      case Code::HANDLER:             // No handlers patched in yet.
+      case Code::REGEXP:              // No regexp literals initialized yet.
+      case Code::NUMBER_OF_KINDS:     // Pseudo enum value.
+        CHECK(false);
+      case Code::BUILTIN:
+        SerializeBuiltin(code_object->builtin_index(), how_to_code,
+                         where_to_point);
+        return;
+      case Code::STUB:
+        SerializeCodeStub(code_object->stub_key(), how_to_code, where_to_point);
+        return;
+#define IC_KIND_CASE(KIND) case Code::KIND:
+        IC_KIND_LIST(IC_KIND_CASE)
+#undef IC_KIND_CASE
+        SerializeIC(code_object, how_to_code, where_to_point);
+        return;
+      case Code::FUNCTION:
+        DCHECK(code_object->has_reloc_info_for_serialization());
+        // Only serialize the code for the toplevel function unless specified
+        // by flag. Replace code of inner functions by the lazy compile builtin.
+        // This is safe, as checked in Compiler::BuildFunctionInfo.
+        if (code_object != main_code_ && !FLAG_serialize_inner) {
+          SerializeBuiltin(Builtins::kCompileLazy, how_to_code, where_to_point);
+        } else {
+          SerializeGeneric(code_object, how_to_code, where_to_point);
+        }
+        return;
     }
-    if (code_object->IsCodeStubOrIC()) {
-      SerializeCodeStub(code_object, how_to_code, where_to_point, skip);
-      return;
-    }
-    code_object->ClearInlineCaches();
+    UNREACHABLE();
   }
 
-  if (heap_object == source_) {
-    SerializeSourceObject(how_to_code, where_to_point, skip);
-    return;
-  }
+  // Past this point we should not see any (context-specific) maps anymore.
+  CHECK(!obj->IsMap());
+  // There should be no references to the global object embedded.
+  CHECK(!obj->IsJSGlobalProxy() && !obj->IsGlobalObject());
+  // There should be no hash table embedded. They would require rehashing.
+  CHECK(!obj->IsHashTable());
+  // We expect no instantiated function objects or contexts.
+  CHECK(!obj->IsJSFunction() && !obj->IsContext());
 
-  SerializeHeapObject(heap_object, how_to_code, where_to_point, skip);
+  SerializeGeneric(obj, how_to_code, where_to_point);
 }
 
 
-void CodeSerializer::SerializeHeapObject(HeapObject* heap_object,
-                                         HowToCode how_to_code,
-                                         WhereToPoint where_to_point,
-                                         int skip) {
-  if (heap_object->IsScript()) {
-    // The wrapper cache uses a Foreign object to point to a global handle.
-    // However, the object visitor expects foreign objects to point to external
-    // references.  Clear the cache to avoid this issue.
-    Script::cast(heap_object)->ClearWrapperCache();
-  }
-
-  if (skip != 0) {
-    sink_->Put(kSkip, "SkipFromSerializeObject");
-    sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
-  }
-
-  if (FLAG_trace_code_serializer) {
-    PrintF("Encoding heap object: ");
-    heap_object->ShortPrint();
-    PrintF("\n");
-  }
+void CodeSerializer::SerializeGeneric(HeapObject* heap_object,
+                                      HowToCode how_to_code,
+                                      WhereToPoint where_to_point) {
+  if (heap_object->IsInternalizedString()) num_internalized_strings_++;
 
   // Object has not yet been serialized.  Serialize it here.
   ObjectSerializer serializer(this, heap_object, sink_, how_to_code,
@@ -1889,22 +2172,16 @@
 }
 
 
-void CodeSerializer::SerializeBuiltin(Code* builtin, HowToCode how_to_code,
-                                      WhereToPoint where_to_point, int skip) {
-  if (skip != 0) {
-    sink_->Put(kSkip, "SkipFromSerializeBuiltin");
-    sink_->PutInt(skip, "SkipDistanceFromSerializeBuiltin");
-  }
-
+void CodeSerializer::SerializeBuiltin(int builtin_index, HowToCode how_to_code,
+                                      WhereToPoint where_to_point) {
   DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) ||
          (how_to_code == kPlain && where_to_point == kInnerPointer) ||
          (how_to_code == kFromCode && where_to_point == kInnerPointer));
-  int builtin_index = builtin->builtin_index();
   DCHECK_LT(builtin_index, Builtins::builtin_count);
   DCHECK_LE(0, builtin_index);
 
-  if (FLAG_trace_code_serializer) {
-    PrintF("Encoding builtin: %s\n",
+  if (FLAG_trace_serializer) {
+    PrintF(" Encoding builtin: %s\n",
            isolate()->builtins()->name(builtin_index));
   }
 
@@ -1913,30 +2190,18 @@
 }
 
 
-void CodeSerializer::SerializeCodeStub(Code* code, HowToCode how_to_code,
-                                       WhereToPoint where_to_point, int skip) {
+void CodeSerializer::SerializeCodeStub(uint32_t stub_key, HowToCode how_to_code,
+                                       WhereToPoint where_to_point) {
   DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) ||
          (how_to_code == kPlain && where_to_point == kInnerPointer) ||
          (how_to_code == kFromCode && where_to_point == kInnerPointer));
-  uint32_t stub_key = code->stub_key();
-
-  if (stub_key == CodeStub::NoCacheKey()) {
-    if (FLAG_trace_code_serializer) {
-      PrintF("Encoding uncacheable code stub as heap object\n");
-    }
-    SerializeHeapObject(code, how_to_code, where_to_point, skip);
-    return;
-  }
-
-  if (skip != 0) {
-    sink_->Put(kSkip, "SkipFromSerializeCodeStub");
-    sink_->PutInt(skip, "SkipDistanceFromSerializeCodeStub");
-  }
+  DCHECK(CodeStub::MajorKeyFromKey(stub_key) != CodeStub::NoCache);
+  DCHECK(!CodeStub::GetCode(isolate(), stub_key).is_null());
 
   int index = AddCodeStubKey(stub_key) + kCodeStubsBaseIndex;
 
-  if (FLAG_trace_code_serializer) {
-    PrintF("Encoding code stub %s as %d\n",
+  if (FLAG_trace_serializer) {
+    PrintF(" Encoding code stub %s as %d\n",
            CodeStub::MajorName(CodeStub::MajorKeyFromKey(stub_key), false),
            index);
   }
@@ -1946,6 +2211,44 @@
 }
 
 
+void CodeSerializer::SerializeIC(Code* ic, HowToCode how_to_code,
+                                 WhereToPoint where_to_point) {
+  // The IC may be implemented as a stub.
+  uint32_t stub_key = ic->stub_key();
+  if (stub_key != CodeStub::NoCacheKey()) {
+    if (FLAG_trace_serializer) {
+      PrintF(" %s is a code stub\n", Code::Kind2String(ic->kind()));
+    }
+    SerializeCodeStub(stub_key, how_to_code, where_to_point);
+    return;
+  }
+  // The IC may be implemented as builtin. Only real builtins have an
+  // actual builtin_index value attached (otherwise it's just garbage).
+  // Compare to make sure we are really dealing with a builtin.
+  int builtin_index = ic->builtin_index();
+  if (builtin_index < Builtins::builtin_count) {
+    Builtins::Name name = static_cast<Builtins::Name>(builtin_index);
+    Code* builtin = isolate()->builtins()->builtin(name);
+    if (builtin == ic) {
+      if (FLAG_trace_serializer) {
+        PrintF(" %s is a builtin\n", Code::Kind2String(ic->kind()));
+      }
+      DCHECK(ic->kind() == Code::KEYED_LOAD_IC ||
+             ic->kind() == Code::KEYED_STORE_IC);
+      SerializeBuiltin(builtin_index, how_to_code, where_to_point);
+      return;
+    }
+  }
+  // The IC may also just be a piece of code kept in the non_monomorphic_cache.
+  // In that case, just serialize as a normal code object.
+  if (FLAG_trace_serializer) {
+    PrintF(" %s has no special handling\n", Code::Kind2String(ic->kind()));
+  }
+  DCHECK(ic->kind() == Code::LOAD_IC || ic->kind() == Code::STORE_IC);
+  SerializeGeneric(ic, how_to_code, where_to_point);
+}
+
+
 int CodeSerializer::AddCodeStubKey(uint32_t stub_key) {
   // TODO(yangguo) Maybe we need a hash table for a faster lookup than O(n^2).
   int index = 0;
@@ -1959,16 +2262,8 @@
 
 
 void CodeSerializer::SerializeSourceObject(HowToCode how_to_code,
-                                           WhereToPoint where_to_point,
-                                           int skip) {
-  if (skip != 0) {
-    sink_->Put(kSkip, "SkipFromSerializeSourceObject");
-    sink_->PutInt(skip, "SkipDistanceFromSerializeSourceObject");
-  }
-
-  if (FLAG_trace_code_serializer) {
-    PrintF("Encoding source object\n");
-  }
+                                           WhereToPoint where_to_point) {
+  if (FLAG_trace_serializer) PrintF(" Encoding source object\n");
 
   DCHECK(how_to_code == kPlain && where_to_point == kStartOfObject);
   sink_->Put(kAttachedReference + how_to_code + where_to_point, "Source");
@@ -1976,9 +2271,8 @@
 }
 
 
-Handle<SharedFunctionInfo> CodeSerializer::Deserialize(Isolate* isolate,
-                                                       ScriptData* data,
-                                                       Handle<String> source) {
+MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
+    Isolate* isolate, ScriptData* cached_data, Handle<String> source) {
   base::ElapsedTimer timer;
   if (FLAG_profile_deserialization) timer.Start();
 
@@ -1987,16 +2281,20 @@
   {
     HandleScope scope(isolate);
 
-    SerializedCodeData scd(data, *source);
-    SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());
-    Deserializer deserializer(&payload);
-    STATIC_ASSERT(NEW_SPACE == 0);
-    for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
-      deserializer.set_reservation(i, scd.GetReservation(i));
+    SmartPointer<SerializedCodeData> scd(
+        SerializedCodeData::FromCachedData(cached_data, *source));
+    if (scd.is_empty()) {
+      if (FLAG_profile_deserialization) PrintF("[Cached code failed check]\n");
+      DCHECK(cached_data->rejected());
+      return MaybeHandle<SharedFunctionInfo>();
     }
 
+    // Eagerly expand string table to avoid allocations during deserialization.
+    StringTable::EnsureCapacityForDeserialization(
+        isolate, scd->NumInternalizedStrings());
+
     // Prepare and register list of attached objects.
-    Vector<const uint32_t> code_stub_keys = scd.CodeStubKeys();
+    Vector<const uint32_t> code_stub_keys = scd->CodeStubKeys();
     Vector<Handle<Object> > attached_objects = Vector<Handle<Object> >::New(
         code_stub_keys.length() + kCodeStubsBaseIndex);
     attached_objects[kSourceObjectIndex] = source;
@@ -2004,69 +2302,232 @@
       attached_objects[i + kCodeStubsBaseIndex] =
           CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked();
     }
+
+    Deserializer deserializer(scd.get());
     deserializer.SetAttachedObjects(&attached_objects);
 
     // Deserialize.
-    deserializer.DeserializePartial(isolate, &root);
+    deserializer.DeserializePartial(isolate, &root, Deserializer::NULL_ON_OOM);
+    if (root == NULL) {
+      // Deserializing may fail if the reservations cannot be fulfilled.
+      if (FLAG_profile_deserialization) PrintF("[Deserializing failed]\n");
+      return MaybeHandle<SharedFunctionInfo>();
+    }
     deserializer.FlushICacheForNewCodeObjects();
   }
 
   if (FLAG_profile_deserialization) {
     double ms = timer.Elapsed().InMillisecondsF();
-    int length = data->length();
+    int length = cached_data->length();
     PrintF("[Deserializing from %d bytes took %0.3f ms]\n", length, ms);
   }
-  return Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(root), isolate);
-}
+  Handle<SharedFunctionInfo> result(SharedFunctionInfo::cast(root), isolate);
+  result->set_deserialized(true);
 
-
-SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs)
-    : owns_script_data_(true) {
-  DisallowHeapAllocation no_gc;
-  List<uint32_t>* stub_keys = cs->stub_keys();
-
-  // Calculate sizes.
-  int num_stub_keys = stub_keys->length();
-  int stub_keys_size = stub_keys->length() * kInt32Size;
-  int data_length = kHeaderSize + stub_keys_size + payload->length();
-
-  // Allocate backing store and create result data.
-  byte* data = NewArray<byte>(data_length);
-  DCHECK(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
-  script_data_ = new ScriptData(data, data_length);
-  script_data_->AcquireDataOwnership();
-
-  // Set header values.
-  SetHeaderValue(kCheckSumOffset, CheckSum(cs->source()));
-  SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
-  SetHeaderValue(kPayloadLengthOffset, payload->length());
-  STATIC_ASSERT(NEW_SPACE == 0);
-  for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
-    SetHeaderValue(kReservationsOffset + i, cs->CurrentAllocationAddress(i));
+  if (isolate->logger()->is_logging_code_events() ||
+      isolate->cpu_profiler()->is_profiling()) {
+    String* name = isolate->heap()->empty_string();
+    if (result->script()->IsScript()) {
+      Script* script = Script::cast(result->script());
+      if (script->name()->IsString()) name = String::cast(script->name());
+    }
+    isolate->logger()->CodeCreateEvent(Logger::SCRIPT_TAG, result->code(),
+                                       *result, NULL, name);
   }
 
-  // Copy code stub keys.
-  CopyBytes(data + kHeaderSize, reinterpret_cast<byte*>(stub_keys->begin()),
-            stub_keys_size);
+  return result;
+}
+
+
+void SerializedData::AllocateData(int size) {
+  DCHECK(!owns_data_);
+  data_ = NewArray<byte>(size);
+  size_ = size;
+  owns_data_ = true;
+  DCHECK(IsAligned(reinterpret_cast<intptr_t>(data_), kPointerAlignment));
+}
+
+
+SnapshotData::SnapshotData(const SnapshotByteSink& sink,
+                           const Serializer& ser) {
+  DisallowHeapAllocation no_gc;
+  List<Reservation> reservations;
+  ser.EncodeReservations(&reservations);
+  const List<byte>& payload = sink.data();
+
+  // Calculate sizes.
+  int reservation_size = reservations.length() * kInt32Size;
+  int size = kHeaderSize + reservation_size + payload.length();
+
+  // Allocate backing store and create result data.
+  AllocateData(size);
+
+  // Set header values.
+  SetHeaderValue(kCheckSumOffset, Version::Hash());
+  SetHeaderValue(kReservationsOffset, reservations.length());
+  SetHeaderValue(kPayloadLengthOffset, payload.length());
+
+  // Copy reservation chunk sizes.
+  CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
+            reservation_size);
 
   // Copy serialized data.
-  CopyBytes(data + kHeaderSize + stub_keys_size, payload->begin(),
-            static_cast<size_t>(payload->length()));
+  CopyBytes(data_ + kHeaderSize + reservation_size, payload.begin(),
+            static_cast<size_t>(payload.length()));
 }
 
 
-bool SerializedCodeData::IsSane(String* source) {
-  return GetHeaderValue(kCheckSumOffset) == CheckSum(source) &&
-         PayloadLength() >= SharedFunctionInfo::kSize;
+bool SnapshotData::IsSane() {
+  return GetHeaderValue(kCheckSumOffset) == Version::Hash();
 }
 
 
-int SerializedCodeData::CheckSum(String* string) {
-  int checksum = Version::Hash();
-#ifdef DEBUG
-  uint32_t seed = static_cast<uint32_t>(checksum);
-  checksum = static_cast<int>(IteratingStringHasher::Hash(string, seed));
-#endif  // DEBUG
-  return checksum;
+Vector<const SerializedData::Reservation> SnapshotData::Reservations() const {
+  return Vector<const Reservation>(
+      reinterpret_cast<const Reservation*>(data_ + kHeaderSize),
+      GetHeaderValue(kReservationsOffset));
+}
+
+
+Vector<const byte> SnapshotData::Payload() const {
+  int reservations_size = GetHeaderValue(kReservationsOffset) * kInt32Size;
+  const byte* payload = data_ + kHeaderSize + reservations_size;
+  int length = GetHeaderValue(kPayloadLengthOffset);
+  DCHECK_EQ(data_ + size_, payload + length);
+  return Vector<const byte>(payload, length);
+}
+
+
+class Checksum {
+ public:
+  explicit Checksum(Vector<const byte> payload) {
+    // Fletcher's checksum. Modified to reduce 64-bit sums to 32-bit.
+    uintptr_t a = 1;
+    uintptr_t b = 0;
+    const uintptr_t* cur = reinterpret_cast<const uintptr_t*>(payload.start());
+    DCHECK(IsAligned(payload.length(), kIntptrSize));
+    const uintptr_t* end = cur + payload.length() / kIntptrSize;
+    while (cur < end) {
+      // Unsigned overflow expected and intended.
+      a += *cur++;
+      b += a;
+    }
+#if V8_HOST_ARCH_64_BIT
+    a ^= a >> 32;
+    b ^= b >> 32;
+#endif  // V8_HOST_ARCH_64_BIT
+    a_ = static_cast<uint32_t>(a);
+    b_ = static_cast<uint32_t>(b);
+  }
+
+  bool Check(uint32_t a, uint32_t b) const { return a == a_ && b == b_; }
+
+  uint32_t a() const { return a_; }
+  uint32_t b() const { return b_; }
+
+ private:
+  uint32_t a_;
+  uint32_t b_;
+
+  DISALLOW_COPY_AND_ASSIGN(Checksum);
+};
+
+
+SerializedCodeData::SerializedCodeData(const List<byte>& payload,
+                                       const CodeSerializer& cs) {
+  DisallowHeapAllocation no_gc;
+  const List<uint32_t>* stub_keys = cs.stub_keys();
+
+  List<Reservation> reservations;
+  cs.EncodeReservations(&reservations);
+
+  // Calculate sizes.
+  int reservation_size = reservations.length() * kInt32Size;
+  int num_stub_keys = stub_keys->length();
+  int stub_keys_size = stub_keys->length() * kInt32Size;
+  int size = kHeaderSize + reservation_size + stub_keys_size + payload.length();
+
+  // Allocate backing store and create result data.
+  AllocateData(size);
+
+  // Set header values.
+  SetHeaderValue(kVersionHashOffset, Version::Hash());
+  SetHeaderValue(kSourceHashOffset, SourceHash(cs.source()));
+  SetHeaderValue(kCpuFeaturesOffset,
+                 static_cast<uint32_t>(CpuFeatures::SupportedFeatures()));
+  SetHeaderValue(kFlagHashOffset, FlagList::Hash());
+  SetHeaderValue(kNumInternalizedStringsOffset, cs.num_internalized_strings());
+  SetHeaderValue(kReservationsOffset, reservations.length());
+  SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
+  SetHeaderValue(kPayloadLengthOffset, payload.length());
+
+  Checksum checksum(payload.ToConstVector());
+  SetHeaderValue(kChecksum1Offset, checksum.a());
+  SetHeaderValue(kChecksum2Offset, checksum.b());
+
+  // Copy reservation chunk sizes.
+  CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
+            reservation_size);
+
+  // Copy code stub keys.
+  CopyBytes(data_ + kHeaderSize + reservation_size,
+            reinterpret_cast<byte*>(stub_keys->begin()), stub_keys_size);
+
+  // Copy serialized data.
+  CopyBytes(data_ + kHeaderSize + reservation_size + stub_keys_size,
+            payload.begin(), static_cast<size_t>(payload.length()));
+}
+
+
+bool SerializedCodeData::IsSane(String* source) const {
+  return GetHeaderValue(kVersionHashOffset) == Version::Hash() &&
+         GetHeaderValue(kSourceHashOffset) == SourceHash(source) &&
+         GetHeaderValue(kCpuFeaturesOffset) ==
+             static_cast<uint32_t>(CpuFeatures::SupportedFeatures()) &&
+         GetHeaderValue(kFlagHashOffset) == FlagList::Hash() &&
+         Checksum(Payload()).Check(GetHeaderValue(kChecksum1Offset),
+                                   GetHeaderValue(kChecksum2Offset));
+}
+
+
+// Return ScriptData object and relinquish ownership over it to the caller.
+ScriptData* SerializedCodeData::GetScriptData() {
+  DCHECK(owns_data_);
+  ScriptData* result = new ScriptData(data_, size_);
+  result->AcquireDataOwnership();
+  owns_data_ = false;
+  data_ = NULL;
+  return result;
+}
+
+
+Vector<const SerializedData::Reservation> SerializedCodeData::Reservations()
+    const {
+  return Vector<const Reservation>(
+      reinterpret_cast<const Reservation*>(data_ + kHeaderSize),
+      GetHeaderValue(kReservationsOffset));
+}
+
+
+Vector<const byte> SerializedCodeData::Payload() const {
+  int reservations_size = GetHeaderValue(kReservationsOffset) * kInt32Size;
+  int code_stubs_size = GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size;
+  const byte* payload =
+      data_ + kHeaderSize + reservations_size + code_stubs_size;
+  int length = GetHeaderValue(kPayloadLengthOffset);
+  DCHECK_EQ(data_ + size_, payload + length);
+  return Vector<const byte>(payload, length);
+}
+
+
+int SerializedCodeData::NumInternalizedStrings() const {
+  return GetHeaderValue(kNumInternalizedStringsOffset);
+}
+
+Vector<const uint32_t> SerializedCodeData::CodeStubKeys() const {
+  int reservations_size = GetHeaderValue(kReservationsOffset) * kInt32Size;
+  const byte* start = data_ + kHeaderSize + reservations_size;
+  return Vector<const uint32_t>(reinterpret_cast<const uint32_t*>(start),
+                                GetHeaderValue(kNumCodeStubKeysOffset));
 }
 } }  // namespace v8::internal
diff --git a/src/serialize.h b/src/serialize.h
index 71b274b..da750cb 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -24,7 +24,7 @@
   IC_UTILITY,
   STATS_COUNTER,
   TOP_ADDRESS,
-  ACCESSOR,
+  ACCESSOR_CODE,
   STUB_CACHE_TABLE,
   RUNTIME_ENTRY,
   LAZY_DEOPTIMIZATION
@@ -139,6 +139,189 @@
 };
 
 
+class AddressMapBase {
+ protected:
+  static void SetValue(HashMap::Entry* entry, uint32_t v) {
+    entry->value = reinterpret_cast<void*>(v);
+  }
+
+  static uint32_t GetValue(HashMap::Entry* entry) {
+    return static_cast<uint32_t>(reinterpret_cast<intptr_t>(entry->value));
+  }
+
+  static HashMap::Entry* LookupEntry(HashMap* map, HeapObject* obj,
+                                     bool insert) {
+    return map->Lookup(Key(obj), Hash(obj), insert);
+  }
+
+ private:
+  static uint32_t Hash(HeapObject* obj) {
+    return static_cast<int32_t>(reinterpret_cast<intptr_t>(obj->address()));
+  }
+
+  static void* Key(HeapObject* obj) {
+    return reinterpret_cast<void*>(obj->address());
+  }
+};
+
+
+class RootIndexMap : public AddressMapBase {
+ public:
+  explicit RootIndexMap(Isolate* isolate);
+
+  ~RootIndexMap() { delete map_; }
+
+  static const int kInvalidRootIndex = -1;
+  int Lookup(HeapObject* obj) {
+    HashMap::Entry* entry = LookupEntry(map_, obj, false);
+    if (entry) return GetValue(entry);
+    return kInvalidRootIndex;
+  }
+
+ private:
+  HashMap* map_;
+
+  DISALLOW_COPY_AND_ASSIGN(RootIndexMap);
+};
+
+
+class BackReference {
+ public:
+  explicit BackReference(uint32_t bitfield) : bitfield_(bitfield) {}
+
+  BackReference() : bitfield_(kInvalidValue) {}
+
+  static BackReference SourceReference() { return BackReference(kSourceValue); }
+
+  static BackReference LargeObjectReference(uint32_t index) {
+    return BackReference(SpaceBits::encode(LO_SPACE) |
+                         ChunkOffsetBits::encode(index));
+  }
+
+  static BackReference Reference(AllocationSpace space, uint32_t chunk_index,
+                                 uint32_t chunk_offset) {
+    DCHECK(IsAligned(chunk_offset, kObjectAlignment));
+    DCHECK_NE(LO_SPACE, space);
+    return BackReference(
+        SpaceBits::encode(space) | ChunkIndexBits::encode(chunk_index) |
+        ChunkOffsetBits::encode(chunk_offset >> kObjectAlignmentBits));
+  }
+
+  bool is_valid() const { return bitfield_ != kInvalidValue; }
+  bool is_source() const { return bitfield_ == kSourceValue; }
+
+  AllocationSpace space() const {
+    DCHECK(is_valid());
+    return SpaceBits::decode(bitfield_);
+  }
+
+  uint32_t chunk_offset() const {
+    DCHECK(is_valid());
+    return ChunkOffsetBits::decode(bitfield_) << kObjectAlignmentBits;
+  }
+
+  uint32_t chunk_index() const {
+    DCHECK(is_valid());
+    return ChunkIndexBits::decode(bitfield_);
+  }
+
+  uint32_t reference() const {
+    DCHECK(is_valid());
+    return bitfield_ & (ChunkOffsetBits::kMask | ChunkIndexBits::kMask);
+  }
+
+  uint32_t bitfield() const { return bitfield_; }
+
+ private:
+  static const uint32_t kInvalidValue = 0xFFFFFFFF;
+  static const uint32_t kSourceValue = 0xFFFFFFFE;
+  static const int kChunkOffsetSize = kPageSizeBits - kObjectAlignmentBits;
+  static const int kChunkIndexSize = 32 - kChunkOffsetSize - kSpaceTagSize;
+
+ public:
+  static const int kMaxChunkIndex = (1 << kChunkIndexSize) - 1;
+
+ private:
+  class ChunkOffsetBits : public BitField<uint32_t, 0, kChunkOffsetSize> {};
+  class ChunkIndexBits
+      : public BitField<uint32_t, ChunkOffsetBits::kNext, kChunkIndexSize> {};
+  class SpaceBits
+      : public BitField<AllocationSpace, ChunkIndexBits::kNext, kSpaceTagSize> {
+  };
+
+  uint32_t bitfield_;
+};
+
+
+// Mapping objects to their location after deserialization.
+// This is used during building, but not at runtime by V8.
+class BackReferenceMap : public AddressMapBase {
+ public:
+  BackReferenceMap()
+      : no_allocation_(), map_(new HashMap(HashMap::PointersMatch)) {}
+
+  ~BackReferenceMap() { delete map_; }
+
+  BackReference Lookup(HeapObject* obj) {
+    HashMap::Entry* entry = LookupEntry(map_, obj, false);
+    return entry ? BackReference(GetValue(entry)) : BackReference();
+  }
+
+  void Add(HeapObject* obj, BackReference b) {
+    DCHECK(b.is_valid());
+    DCHECK_EQ(NULL, LookupEntry(map_, obj, false));
+    HashMap::Entry* entry = LookupEntry(map_, obj, true);
+    SetValue(entry, b.bitfield());
+  }
+
+  void AddSourceString(String* string) {
+    Add(string, BackReference::SourceReference());
+  }
+
+ private:
+  DisallowHeapAllocation no_allocation_;
+  HashMap* map_;
+  DISALLOW_COPY_AND_ASSIGN(BackReferenceMap);
+};
+
+
+class HotObjectsList {
+ public:
+  HotObjectsList() : index_(0) {
+    for (int i = 0; i < kSize; i++) circular_queue_[i] = NULL;
+  }
+
+  void Add(HeapObject* object) {
+    circular_queue_[index_] = object;
+    index_ = (index_ + 1) & kSizeMask;
+  }
+
+  HeapObject* Get(int index) {
+    DCHECK_NE(NULL, circular_queue_[index]);
+    return circular_queue_[index];
+  }
+
+  static const int kNotFound = -1;
+
+  int Find(HeapObject* object) {
+    for (int i = 0; i < kSize; i++) {
+      if (circular_queue_[i] == object) return i;
+    }
+    return kNotFound;
+  }
+
+  static const int kSize = 8;
+
+ private:
+  STATIC_ASSERT(IS_POWER_OF_TWO(kSize));
+  static const int kSizeMask = kSize - 1;
+  HeapObject* circular_queue_[kSize];
+  int index_;
+
+  DISALLOW_COPY_AND_ASSIGN(HotObjectsList);
+};
+
+
 // The Serializer/Deserializer class is a common superclass for Serializer and
 // Deserializer which is used to store common constants and methods used by
 // both.
@@ -148,23 +331,28 @@
 
   static int nop() { return kNop; }
 
+  // No reservation for large object space necessary.
+  static const int kNumberOfPreallocatedSpaces = LO_SPACE;
+  static const int kNumberOfSpaces = LAST_SPACE + 1;
+
  protected:
   // Where the pointed-to object can be found:
   enum Where {
-    kNewObject = 0,  // Object is next in snapshot.
-    // 1-6                             One per space.
+    kNewObject = 0,  //              Object is next in snapshot.
+    // 1-7                           One per space.
+    // 0x8                           Unused.
     kRootArray = 0x9,             // Object is found in root array.
     kPartialSnapshotCache = 0xa,  // Object is in the cache.
     kExternalReference = 0xb,     // Pointer to an external reference.
     kSkip = 0xc,                  // Skip n bytes.
     kBuiltin = 0xd,               // Builtin code object.
     kAttachedReference = 0xe,     // Object is described in an attached list.
-    kNop = 0xf,                   // Does nothing, used to pad.
-    kBackref = 0x10,              // Object is described relative to end.
-    // 0x11-0x16                       One per space.
-    kBackrefWithSkip = 0x18,  // Object is described relative to end.
-    // 0x19-0x1e                       One per space.
-    // 0x20-0x3f                       Used by misc. tags below.
+    // 0xf                           Used by misc. See below.
+    kBackref = 0x10,  //             Object is described relative to end.
+    // 0x11-0x17                     One per space.
+    kBackrefWithSkip = 0x18,  //     Object is described relative to end.
+    // 0x19-0x1f                     One per space.
+    // 0x20-0x3f                     Used by misc. See below.
     kPointedToMask = 0x3f
   };
 
@@ -196,40 +384,118 @@
   // entire code in one memcpy, then fix up stuff with kSkip and other byte
   // codes that overwrite data.
   static const int kRawData = 0x20;
-  // Some common raw lengths: 0x21-0x3f.  These autoadvance the current pointer.
-  // A tag emitted at strategic points in the snapshot to delineate sections.
-  // If the deserializer does not find these at the expected moments then it
-  // is an indication that the snapshot and the VM do not fit together.
-  // Examine the build process for architecture, version or configuration
-  // mismatches.
-  static const int kSynchronize = 0x70;
-  // Used for the source code of the natives, which is in the executable, but
-  // is referred to from external strings in the snapshot.
-  static const int kNativesStringResource = 0x71;
-  static const int kRepeat = 0x72;
-  static const int kConstantRepeat = 0x73;
-  // 0x73-0x7f            Repeat last word (subtract 0x72 to get the count).
-  static const int kMaxRepeats = 0x7f - 0x72;
+  // Some common raw lengths: 0x21-0x3f.
+  // These autoadvance the current pointer.
+  static const int kOnePointerRawData = 0x21;
+
+  static const int kVariableRepeat = 0x60;
+  // 0x61-0x6f   Repeat last word
+  static const int kFixedRepeat = 0x61;
+  static const int kFixedRepeatBase = kFixedRepeat - 1;
+  static const int kLastFixedRepeat = 0x6f;
+  static const int kMaxFixedRepeats = kLastFixedRepeat - kFixedRepeatBase;
   static int CodeForRepeats(int repeats) {
-    DCHECK(repeats >= 1 && repeats <= kMaxRepeats);
-    return 0x72 + repeats;
+    DCHECK(repeats >= 1 && repeats <= kMaxFixedRepeats);
+    return kFixedRepeatBase + repeats;
   }
   static int RepeatsForCode(int byte_code) {
-    DCHECK(byte_code >= kConstantRepeat && byte_code <= 0x7f);
-    return byte_code - 0x72;
+    DCHECK(byte_code > kFixedRepeatBase && byte_code <= kLastFixedRepeat);
+    return byte_code - kFixedRepeatBase;
   }
+
+  // Hot objects are a small set of recently seen or back-referenced objects.
+  // They are represented by a single opcode to save space.
+  // We use 0x70..0x77 for 8 hot objects, and 0x78..0x7f to add skip.
+  static const int kHotObject = 0x70;
+  static const int kMaxHotObjectIndex = 0x77 - kHotObject;
+  static const int kHotObjectWithSkip = 0x78;
+  STATIC_ASSERT(HotObjectsList::kSize == kMaxHotObjectIndex + 1);
+  STATIC_ASSERT(0x7f - kHotObjectWithSkip == kMaxHotObjectIndex);
+  static const int kHotObjectIndexMask = 0x7;
+
   static const int kRootArrayConstants = 0xa0;
-  // 0xa0-0xbf            Things from the first 32 elements of the root array.
+  // 0xa0-0xbf  Things from the first 32 elements of the root array.
   static const int kRootArrayNumberOfConstantEncodings = 0x20;
   static int RootArrayConstantFromByteCode(int byte_code) {
     return byte_code & 0x1f;
   }
 
-  static const int kNumberOfSpaces = LO_SPACE;
+  // Do nothing, used for padding.
+  static const int kNop = 0xf;
+
+  // Move to next reserved chunk.
+  static const int kNextChunk = 0x4f;
+
+  // A tag emitted at strategic points in the snapshot to delineate sections.
+  // If the deserializer does not find these at the expected moments then it
+  // is an indication that the snapshot and the VM do not fit together.
+  // Examine the build process for architecture, version or configuration
+  // mismatches.
+  static const int kSynchronize = 0x8f;
+
+  // Used for the source code of the natives, which is in the executable, but
+  // is referred to from external strings in the snapshot.
+  static const int kNativesStringResource = 0xcf;
+
   static const int kAnyOldSpace = -1;
 
   // A bitmask for getting the space out of an instruction.
   static const int kSpaceMask = 7;
+  STATIC_ASSERT(kNumberOfSpaces <= kSpaceMask + 1);
+
+  // Sentinel after a new object to indicate that double alignment is needed.
+  static const int kDoubleAlignmentSentinel = 0;
+
+  // Used as index for the attached reference representing the source object.
+  static const int kSourceObjectReference = 0;
+
+  HotObjectsList hot_objects_;
+};
+
+
+class SerializedData {
+ public:
+  class Reservation {
+   public:
+    explicit Reservation(uint32_t size)
+        : reservation_(ChunkSizeBits::encode(size)) {}
+
+    uint32_t chunk_size() const { return ChunkSizeBits::decode(reservation_); }
+    bool is_last() const { return IsLastChunkBits::decode(reservation_); }
+
+    void mark_as_last() { reservation_ |= IsLastChunkBits::encode(true); }
+
+   private:
+    uint32_t reservation_;
+  };
+
+  SerializedData(byte* data, int size)
+      : data_(data), size_(size), owns_data_(false) {}
+  SerializedData() : data_(NULL), size_(0), owns_data_(false) {}
+
+  ~SerializedData() {
+    if (owns_data_) DeleteArray<byte>(data_);
+  }
+
+  class ChunkSizeBits : public BitField<uint32_t, 0, 31> {};
+  class IsLastChunkBits : public BitField<bool, 31, 1> {};
+
+ protected:
+  void SetHeaderValue(int offset, uint32_t value) {
+    memcpy(reinterpret_cast<uint32_t*>(data_) + offset, &value, sizeof(value));
+  }
+
+  uint32_t GetHeaderValue(int offset) const {
+    uint32_t value;
+    memcpy(&value, reinterpret_cast<int*>(data_) + offset, sizeof(value));
+    return value;
+  }
+
+  void AllocateData(int size);
+
+  byte* data_;
+  int size_;
+  bool owns_data_;
 };
 
 
@@ -237,21 +503,27 @@
 class Deserializer: public SerializerDeserializer {
  public:
   // Create a deserializer from a snapshot byte source.
-  explicit Deserializer(SnapshotByteSource* source);
+  template <class Data>
+  explicit Deserializer(Data* data)
+      : isolate_(NULL),
+        attached_objects_(NULL),
+        source_(data->Payload()),
+        external_reference_decoder_(NULL),
+        deserialized_large_objects_(0) {
+    DecodeReservation(data->Reservations());
+  }
 
   virtual ~Deserializer();
 
   // Deserialize the snapshot into an empty heap.
   void Deserialize(Isolate* isolate);
 
-  // Deserialize a single object and the objects reachable from it.
-  void DeserializePartial(Isolate* isolate, Object** root);
+  enum OnOOM { FATAL_ON_OOM, NULL_ON_OOM };
 
-  void set_reservation(int space_number, int reservation) {
-    DCHECK(space_number >= 0);
-    DCHECK(space_number <= LAST_SPACE);
-    reservations_[space_number] = reservation;
-  }
+  // Deserialize a single object and the objects reachable from it.
+  // We may want to abort gracefully even if deserialization fails.
+  void DeserializePartial(Isolate* isolate, Object** root,
+                          OnOOM on_oom = FATAL_ON_OOM);
 
   void FlushICacheForNewCodeObjects();
 
@@ -270,6 +542,10 @@
     UNREACHABLE();
   }
 
+  void DecodeReservation(Vector<const SerializedData::Reservation> res);
+
+  bool ReserveSpace();
+
   // Allocation sites are present in the snapshot, and must be linked into
   // a list at deserialization time.
   void RelinkAllocationSite(AllocationSite* site);
@@ -279,30 +555,17 @@
   // of the object we are writing into, or NULL if we are not writing into an
   // object, i.e. if we are writing a series of tagged values that are not on
   // the heap.
-  void ReadChunk(
-      Object** start, Object** end, int space, Address object_address);
+  void ReadData(Object** start, Object** end, int space,
+                Address object_address);
   void ReadObject(int space_number, Object** write_back);
+  Address Allocate(int space_index, int size);
 
   // Special handling for serialized code like hooking up internalized strings.
   HeapObject* ProcessNewObjectFromSerializedCode(HeapObject* obj);
-  Object* ProcessBackRefInSerializedCode(Object* obj);
-
-  // This routine both allocates a new object, and also keeps
-  // track of where objects have been allocated so that we can
-  // fix back references when deserializing.
-  Address Allocate(int space_index, int size) {
-    Address address = high_water_[space_index];
-    high_water_[space_index] = address + size;
-    return address;
-  }
 
   // This returns the address of an object that has been described in the
-  // snapshot as being offset bytes back in a particular space.
-  HeapObject* GetAddressFromEnd(int space) {
-    int offset = source_->GetInt();
-    offset <<= kObjectAlignmentBits;
-    return HeapObject::FromAddress(high_water_[space] - offset);
-  }
+  // snapshot by chunk index and offset.
+  HeapObject* GetBackReferencedObject(int space);
 
   // Cached current isolate.
   Isolate* isolate_;
@@ -310,68 +573,23 @@
   // Objects from the attached object descriptions in the serialized user code.
   Vector<Handle<Object> >* attached_objects_;
 
-  SnapshotByteSource* source_;
-  // This is the address of the next object that will be allocated in each
-  // space.  It is used to calculate the addresses of back-references.
-  Address high_water_[LAST_SPACE + 1];
-
-  int reservations_[LAST_SPACE + 1];
-  static const intptr_t kUninitializedReservation = -1;
+  SnapshotByteSource source_;
+  // The address of the next object that will be allocated in each space.
+  // Each space has a number of chunks reserved by the GC, with each chunk
+  // fitting into a page. Deserialized objects are allocated into the
+  // current chunk of the target space by bumping up high water mark.
+  Heap::Reservation reservations_[kNumberOfSpaces];
+  uint32_t current_chunk_[kNumberOfPreallocatedSpaces];
+  Address high_water_[kNumberOfPreallocatedSpaces];
 
   ExternalReferenceDecoder* external_reference_decoder_;
 
+  List<HeapObject*> deserialized_large_objects_;
+
   DISALLOW_COPY_AND_ASSIGN(Deserializer);
 };
 
 
-// Mapping objects to their location after deserialization.
-// This is used during building, but not at runtime by V8.
-class SerializationAddressMapper {
- public:
-  SerializationAddressMapper()
-      : no_allocation_(),
-        serialization_map_(new HashMap(HashMap::PointersMatch)) { }
-
-  ~SerializationAddressMapper() {
-    delete serialization_map_;
-  }
-
-  bool IsMapped(HeapObject* obj) {
-    return serialization_map_->Lookup(Key(obj), Hash(obj), false) != NULL;
-  }
-
-  int MappedTo(HeapObject* obj) {
-    DCHECK(IsMapped(obj));
-    return static_cast<int>(reinterpret_cast<intptr_t>(
-        serialization_map_->Lookup(Key(obj), Hash(obj), false)->value));
-  }
-
-  void AddMapping(HeapObject* obj, int to) {
-    DCHECK(!IsMapped(obj));
-    HashMap::Entry* entry =
-        serialization_map_->Lookup(Key(obj), Hash(obj), true);
-    entry->value = Value(to);
-  }
-
- private:
-  static uint32_t Hash(HeapObject* obj) {
-    return static_cast<int32_t>(reinterpret_cast<intptr_t>(obj->address()));
-  }
-
-  static void* Key(HeapObject* obj) {
-    return reinterpret_cast<void*>(obj->address());
-  }
-
-  static void* Value(int v) {
-    return reinterpret_cast<void*>(v);
-  }
-
-  DisallowHeapAllocation no_allocation_;
-  HashMap* serialization_map_;
-  DISALLOW_COPY_AND_ASSIGN(SerializationAddressMapper);
-};
-
-
 class CodeAddressMap;
 
 // There can be only one serializer per V8 process.
@@ -379,33 +597,16 @@
  public:
   Serializer(Isolate* isolate, SnapshotByteSink* sink);
   ~Serializer();
-  void VisitPointers(Object** start, Object** end);
-  // You can call this after serialization to find out how much space was used
-  // in each space.
-  int CurrentAllocationAddress(int space) const {
-    DCHECK(space < kNumberOfSpaces);
-    return fullness_[space];
-  }
+  void VisitPointers(Object** start, Object** end) OVERRIDE;
+
+  void EncodeReservations(List<SerializedData::Reservation>* out) const;
 
   Isolate* isolate() const { return isolate_; }
 
-  SerializationAddressMapper* address_mapper() { return &address_mapper_; }
-  void PutRoot(int index,
-               HeapObject* object,
-               HowToCode how,
-               WhereToPoint where,
-               int skip);
+  BackReferenceMap* back_reference_map() { return &back_reference_map_; }
+  RootIndexMap* root_index_map() { return &root_index_map_; }
 
  protected:
-  static const int kInvalidRootIndex = -1;
-
-  int RootIndex(HeapObject* heap_object, HowToCode from);
-  intptr_t root_index_wave_front() { return root_index_wave_front_; }
-  void set_root_index_wave_front(intptr_t value) {
-    DCHECK(value >= root_index_wave_front_);
-    root_index_wave_front_ = value;
-  }
-
   class ObjectSerializer : public ObjectVisitor {
    public:
     ObjectSerializer(Serializer* serializer,
@@ -439,12 +640,16 @@
     }
 
    private:
+    void SerializePrologue(AllocationSpace space, int size, Map* map);
+
     enum ReturnSkip { kCanReturnSkipInsteadOfSkipping, kIgnoringReturn };
     // This function outputs or skips the raw data between the last pointer and
     // up to the current position.  It optionally can just return the number of
     // bytes to skip instead of performing a skip instruction, in case the skip
     // can be merged into the next instruction.
     int OutputRawData(Address up_to, ReturnSkip return_skip = kIgnoringReturn);
+    // External strings are serialized in a way to resemble sequential strings.
+    void SerializeExternalString();
 
     Serializer* serializer_;
     HeapObject* object_;
@@ -455,48 +660,74 @@
     bool code_has_been_output_;
   };
 
-  virtual void SerializeObject(Object* o,
-                               HowToCode how_to_code,
-                               WhereToPoint where_to_point,
-                               int skip) = 0;
-  void SerializeReferenceToPreviousObject(HeapObject* heap_object,
-                                          HowToCode how_to_code,
-                                          WhereToPoint where_to_point,
-                                          int skip);
+  virtual void SerializeObject(HeapObject* o, HowToCode how_to_code,
+                               WhereToPoint where_to_point, int skip) = 0;
+
+  void PutRoot(int index, HeapObject* object, HowToCode how, WhereToPoint where,
+               int skip);
+
+  // Returns true if the object was successfully serialized.
+  bool SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
+                            WhereToPoint where_to_point, int skip);
+
+  inline void FlushSkip(int skip) {
+    if (skip != 0) {
+      sink_->Put(kSkip, "SkipFromSerializeObject");
+      sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
+    }
+  }
+
   void InitializeAllocators();
   // This will return the space for an object.
-  static int SpaceOfObject(HeapObject* object);
-  int Allocate(int space, int size);
+  static AllocationSpace SpaceOfObject(HeapObject* object);
+  BackReference AllocateLargeObject(int size);
+  BackReference Allocate(AllocationSpace space, int size);
   int EncodeExternalReference(Address addr) {
     return external_reference_encoder_->Encode(addr);
   }
 
-  int SpaceAreaSize(int space);
+  // GetInt reads 4 bytes at once, requiring padding at the end.
+  void Pad();
 
   // Some roots should not be serialized, because their actual value depends on
   // absolute addresses and they are reset after deserialization, anyway.
   bool ShouldBeSkipped(Object** current);
 
-  Isolate* isolate_;
-  // Keep track of the fullness of each space in order to generate
-  // relative addresses for back references.
-  int fullness_[LAST_SPACE + 1];
-  SnapshotByteSink* sink_;
-  ExternalReferenceEncoder* external_reference_encoder_;
-
-  SerializationAddressMapper address_mapper_;
-  intptr_t root_index_wave_front_;
-  void Pad();
-
-  friend class ObjectSerializer;
-  friend class Deserializer;
-
   // We may not need the code address map for logging for every instance
   // of the serializer.  Initialize it on demand.
   void InitializeCodeAddressMap();
 
+  inline uint32_t max_chunk_size(int space) const {
+    DCHECK_LE(0, space);
+    DCHECK_LT(space, kNumberOfSpaces);
+    return max_chunk_size_[space];
+  }
+
+  Isolate* isolate_;
+
+  SnapshotByteSink* sink_;
+  ExternalReferenceEncoder* external_reference_encoder_;
+
+  BackReferenceMap back_reference_map_;
+  RootIndexMap root_index_map_;
+
+  friend class ObjectSerializer;
+  friend class Deserializer;
+
  private:
   CodeAddressMap* code_address_map_;
+  // Objects from the same space are put into chunks for bulk-allocation
+  // when deserializing. We have to make sure that each chunk fits into a
+  // page. So we track the chunk size in pending_chunk_ of a space, but
+  // when it exceeds a page, we complete the current chunk and start a new one.
+  uint32_t pending_chunk_[kNumberOfPreallocatedSpaces];
+  List<uint32_t> completed_chunks_[kNumberOfPreallocatedSpaces];
+  uint32_t max_chunk_size_[kNumberOfPreallocatedSpaces];
+
+  // We map serialized large objects to indexes for back-referencing.
+  uint32_t large_objects_total_size_;
+  uint32_t seen_large_objects_index_;
+
   DISALLOW_COPY_AND_ASSIGN(Serializer);
 };
 
@@ -508,16 +739,13 @@
                     SnapshotByteSink* sink)
     : Serializer(isolate, sink),
       startup_serializer_(startup_snapshot_serializer) {
-    set_root_index_wave_front(Heap::kStrongRootListLength);
     InitializeCodeAddressMap();
   }
 
   // Serialize the objects reachable from a single object pointer.
   void Serialize(Object** o);
-  virtual void SerializeObject(Object* o,
-                               HowToCode how_to_code,
-                               WhereToPoint where_to_point,
-                               int skip);
+  virtual void SerializeObject(HeapObject* o, HowToCode how_to_code,
+                               WhereToPoint where_to_point, int skip) OVERRIDE;
 
  private:
   int PartialSnapshotCacheIndex(HeapObject* o);
@@ -543,7 +771,7 @@
 class StartupSerializer : public Serializer {
  public:
   StartupSerializer(Isolate* isolate, SnapshotByteSink* sink)
-    : Serializer(isolate, sink) {
+      : Serializer(isolate, sink), root_index_wave_front_(0) {
     // Clear the cache of objects used by the partial snapshot.  After the
     // strong roots have been serialized we can create a partial snapshot
     // which will repopulate the cache with objects needed by that partial
@@ -551,15 +779,18 @@
     isolate->set_serialize_partial_snapshot_cache_length(0);
     InitializeCodeAddressMap();
   }
+
+  // The StartupSerializer has to serialize the root array, which is slightly
+  // different.
+  void VisitPointers(Object** start, Object** end) OVERRIDE;
+
   // Serialize the current state of the heap.  The order is:
   // 1) Strong references.
   // 2) Partial snapshot cache.
   // 3) Weak references (e.g. the string table).
   virtual void SerializeStrongReferences();
-  virtual void SerializeObject(Object* o,
-                               HowToCode how_to_code,
-                               WhereToPoint where_to_point,
-                               int skip);
+  virtual void SerializeObject(HeapObject* o, HowToCode how_to_code,
+                               WhereToPoint where_to_point, int skip) OVERRIDE;
   void SerializeWeakReferences();
   void Serialize() {
     SerializeStrongReferences();
@@ -568,139 +799,155 @@
   }
 
  private:
+  intptr_t root_index_wave_front_;
   DISALLOW_COPY_AND_ASSIGN(StartupSerializer);
 };
 
 
 class CodeSerializer : public Serializer {
  public:
-  CodeSerializer(Isolate* isolate, SnapshotByteSink* sink, String* source)
-      : Serializer(isolate, sink), source_(source) {
-    set_root_index_wave_front(Heap::kStrongRootListLength);
-    InitializeCodeAddressMap();
-  }
-
   static ScriptData* Serialize(Isolate* isolate,
                                Handle<SharedFunctionInfo> info,
                                Handle<String> source);
 
-  virtual void SerializeObject(Object* o, HowToCode how_to_code,
-                               WhereToPoint where_to_point, int skip);
-
-  static Handle<SharedFunctionInfo> Deserialize(Isolate* isolate,
-                                                ScriptData* data,
-                                                Handle<String> source);
+  MUST_USE_RESULT static MaybeHandle<SharedFunctionInfo> Deserialize(
+      Isolate* isolate, ScriptData* cached_data, Handle<String> source);
 
   static const int kSourceObjectIndex = 0;
+  STATIC_ASSERT(kSourceObjectReference == kSourceObjectIndex);
+
   static const int kCodeStubsBaseIndex = 1;
 
-  String* source() {
+  String* source() const {
     DCHECK(!AllowHeapAllocation::IsAllowed());
     return source_;
   }
 
-  List<uint32_t>* stub_keys() { return &stub_keys_; }
+  const List<uint32_t>* stub_keys() const { return &stub_keys_; }
+  int num_internalized_strings() const { return num_internalized_strings_; }
 
  private:
-  void SerializeBuiltin(Code* builtin, HowToCode how_to_code,
-                        WhereToPoint where_to_point, int skip);
-  void SerializeCodeStub(Code* code, HowToCode how_to_code,
-                         WhereToPoint where_to_point, int skip);
-  void SerializeSourceObject(HowToCode how_to_code, WhereToPoint where_to_point,
-                             int skip);
-  void SerializeHeapObject(HeapObject* heap_object, HowToCode how_to_code,
-                           WhereToPoint where_to_point, int skip);
+  CodeSerializer(Isolate* isolate, SnapshotByteSink* sink, String* source,
+                 Code* main_code)
+      : Serializer(isolate, sink),
+        source_(source),
+        main_code_(main_code),
+        num_internalized_strings_(0) {
+    back_reference_map_.AddSourceString(source);
+  }
+
+  virtual void SerializeObject(HeapObject* o, HowToCode how_to_code,
+                               WhereToPoint where_to_point, int skip) OVERRIDE;
+
+  void SerializeBuiltin(int builtin_index, HowToCode how_to_code,
+                        WhereToPoint where_to_point);
+  void SerializeIC(Code* ic, HowToCode how_to_code,
+                   WhereToPoint where_to_point);
+  void SerializeCodeStub(uint32_t stub_key, HowToCode how_to_code,
+                         WhereToPoint where_to_point);
+  void SerializeSourceObject(HowToCode how_to_code,
+                             WhereToPoint where_to_point);
+  void SerializeGeneric(HeapObject* heap_object, HowToCode how_to_code,
+                        WhereToPoint where_to_point);
   int AddCodeStubKey(uint32_t stub_key);
 
   DisallowHeapAllocation no_gc_;
   String* source_;
+  Code* main_code_;
+  int num_internalized_strings_;
   List<uint32_t> stub_keys_;
   DISALLOW_COPY_AND_ASSIGN(CodeSerializer);
 };
 
 
-// Wrapper around ScriptData to provide code-serializer-specific functionality.
-class SerializedCodeData {
+// Wrapper around reservation sizes and the serialization payload.
+class SnapshotData : public SerializedData {
  public:
-  // Used by when consuming.
-  explicit SerializedCodeData(ScriptData* data, String* source)
-      : script_data_(data), owns_script_data_(false) {
-    DisallowHeapAllocation no_gc;
-    CHECK(IsSane(source));
-  }
-
   // Used when producing.
-  SerializedCodeData(List<byte>* payload, CodeSerializer* cs);
+  SnapshotData(const SnapshotByteSink& sink, const Serializer& ser);
 
-  ~SerializedCodeData() {
-    if (owns_script_data_) delete script_data_;
+  // Used when consuming.
+  explicit SnapshotData(const Vector<const byte> snapshot)
+      : SerializedData(const_cast<byte*>(snapshot.begin()), snapshot.length()) {
+    CHECK(IsSane());
   }
 
-  // Return ScriptData object and relinquish ownership over it to the caller.
-  ScriptData* GetScriptData() {
-    ScriptData* result = script_data_;
-    script_data_ = NULL;
-    DCHECK(owns_script_data_);
-    owns_script_data_ = false;
-    return result;
-  }
+  Vector<const Reservation> Reservations() const;
+  Vector<const byte> Payload() const;
 
-  Vector<const uint32_t> CodeStubKeys() const {
-    return Vector<const uint32_t>(
-        reinterpret_cast<const uint32_t*>(script_data_->data() + kHeaderSize),
-        GetHeaderValue(kNumCodeStubKeysOffset));
-  }
-
-  const byte* Payload() const {
-    int code_stubs_size = GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size;
-    return script_data_->data() + kHeaderSize + code_stubs_size;
-  }
-
-  int PayloadLength() const {
-    int payload_length = GetHeaderValue(kPayloadLengthOffset);
-    DCHECK_EQ(script_data_->data() + script_data_->length(),
-              Payload() + payload_length);
-    return payload_length;
-  }
-
-  int GetReservation(int space) const {
-    return GetHeaderValue(kReservationsOffset + space);
+  Vector<const byte> RawData() const {
+    return Vector<const byte>(data_, size_);
   }
 
  private:
-  void SetHeaderValue(int offset, int value) {
-    reinterpret_cast<int*>(const_cast<byte*>(script_data_->data()))[offset] =
-        value;
+  bool IsSane();
+  // The data header consists of int-sized entries:
+  // [0] version hash
+  // [1] number of reservation size entries
+  // [2] payload length
+  static const int kCheckSumOffset = 0;
+  static const int kReservationsOffset = 1;
+  static const int kPayloadLengthOffset = 2;
+  static const int kHeaderSize = (kPayloadLengthOffset + 1) * kIntSize;
+};
+
+
+// Wrapper around ScriptData to provide code-serializer-specific functionality.
+class SerializedCodeData : public SerializedData {
+ public:
+  // Used when consuming.
+  static SerializedCodeData* FromCachedData(ScriptData* cached_data,
+                                            String* source) {
+    DisallowHeapAllocation no_gc;
+    SerializedCodeData* scd = new SerializedCodeData(cached_data);
+    if (scd->IsSane(source)) return scd;
+    cached_data->Reject();
+    delete scd;
+    return NULL;
   }
 
-  int GetHeaderValue(int offset) const {
-    return reinterpret_cast<const int*>(script_data_->data())[offset];
-  }
+  // Used when producing.
+  SerializedCodeData(const List<byte>& payload, const CodeSerializer& cs);
 
-  bool IsSane(String* source);
+  // Return ScriptData object and relinquish ownership over it to the caller.
+  ScriptData* GetScriptData();
 
-  int CheckSum(String* source);
+  Vector<const Reservation> Reservations() const;
+  Vector<const byte> Payload() const;
+
+  int NumInternalizedStrings() const;
+  Vector<const uint32_t> CodeStubKeys() const;
+
+ private:
+  explicit SerializedCodeData(ScriptData* data)
+      : SerializedData(const_cast<byte*>(data->data()), data->length()) {}
+
+  bool IsSane(String* source) const;
+
+  static uint32_t SourceHash(String* source) { return source->length(); }
 
   // The data header consists of int-sized entries:
   // [0] version hash
-  // [1] number of code stub keys
-  // [2] payload length
-  // [3..9] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE.
-  static const int kCheckSumOffset = 0;
-  static const int kNumCodeStubKeysOffset = 1;
-  static const int kPayloadLengthOffset = 2;
-  static const int kReservationsOffset = 3;
-
-  static const int kNumSpaces = PROPERTY_CELL_SPACE - NEW_SPACE + 1;
-  static const int kHeaderEntries = kReservationsOffset + kNumSpaces;
-  static const int kHeaderSize = kHeaderEntries * kIntSize;
-
-  // Following the header, we store, in sequential order
-  // - code stub keys
-  // - serialization payload
-
-  ScriptData* script_data_;
-  bool owns_script_data_;
+  // [1] source hash
+  // [2] cpu features
+  // [3] flag hash
+  // [4] number of internalized strings
+  // [5] number of code stub keys
+  // [6] number of reservation size entries
+  // [7] payload length
+  // [8] checksum 1
+  // [9] checksum 2
+  static const int kVersionHashOffset = 0;
+  static const int kSourceHashOffset = 1;
+  static const int kCpuFeaturesOffset = 2;
+  static const int kFlagHashOffset = 3;
+  static const int kNumInternalizedStringsOffset = 4;
+  static const int kReservationsOffset = 5;
+  static const int kNumCodeStubKeysOffset = 6;
+  static const int kPayloadLengthOffset = 7;
+  static const int kChecksum1Offset = 8;
+  static const int kChecksum2Offset = 9;
+  static const int kHeaderSize = (kChecksum2Offset + 1) * kIntSize;
 };
 } }  // namespace v8::internal
 
diff --git a/src/snapshot-common.cc b/src/snapshot-common.cc
index a2d5213..dc7f655 100644
--- a/src/snapshot-common.cc
+++ b/src/snapshot-common.cc
@@ -14,73 +14,78 @@
 namespace v8 {
 namespace internal {
 
-void Snapshot::ReserveSpaceForLinkedInSnapshot(Deserializer* deserializer) {
-  deserializer->set_reservation(NEW_SPACE, new_space_used_);
-  deserializer->set_reservation(OLD_POINTER_SPACE, pointer_space_used_);
-  deserializer->set_reservation(OLD_DATA_SPACE, data_space_used_);
-  deserializer->set_reservation(CODE_SPACE, code_space_used_);
-  deserializer->set_reservation(MAP_SPACE, map_space_used_);
-  deserializer->set_reservation(CELL_SPACE, cell_space_used_);
-  deserializer->set_reservation(PROPERTY_CELL_SPACE,
-                                property_cell_space_used_);
+bool Snapshot::HaveASnapshotToStartFrom() {
+  return SnapshotBlob().data != NULL;
 }
 
 
 bool Snapshot::Initialize(Isolate* isolate) {
-  if (size_ > 0) {
-    base::ElapsedTimer timer;
-    if (FLAG_profile_deserialization) {
-      timer.Start();
-    }
-    SnapshotByteSource source(raw_data_, raw_size_);
-    Deserializer deserializer(&source);
-    ReserveSpaceForLinkedInSnapshot(&deserializer);
-    bool success = isolate->Init(&deserializer);
-    if (FLAG_profile_deserialization) {
-      double ms = timer.Elapsed().InMillisecondsF();
-      PrintF("[Snapshot loading and deserialization took %0.3f ms]\n", ms);
-    }
-    return success;
+  if (!HaveASnapshotToStartFrom()) return false;
+  base::ElapsedTimer timer;
+  if (FLAG_profile_deserialization) timer.Start();
+
+  const v8::StartupData blob = SnapshotBlob();
+  SnapshotData snapshot_data(ExtractStartupData(&blob));
+  Deserializer deserializer(&snapshot_data);
+  bool success = isolate->Init(&deserializer);
+  if (FLAG_profile_deserialization) {
+    double ms = timer.Elapsed().InMillisecondsF();
+    PrintF("[Snapshot loading and deserialization took %0.3f ms]\n", ms);
   }
-  return false;
-}
-
-
-bool Snapshot::HaveASnapshotToStartFrom() {
-  return size_ != 0;
+  return success;
 }
 
 
 Handle<Context> Snapshot::NewContextFromSnapshot(Isolate* isolate) {
-  if (context_size_ == 0) {
-    return Handle<Context>();
-  }
-  SnapshotByteSource source(context_raw_data_,
-                            context_raw_size_);
-  Deserializer deserializer(&source);
+  if (!HaveASnapshotToStartFrom()) return Handle<Context>();
+
+  const v8::StartupData blob = SnapshotBlob();
+  SnapshotData snapshot_data(ExtractContextData(&blob));
+  Deserializer deserializer(&snapshot_data);
   Object* root;
-  deserializer.set_reservation(NEW_SPACE, context_new_space_used_);
-  deserializer.set_reservation(OLD_POINTER_SPACE, context_pointer_space_used_);
-  deserializer.set_reservation(OLD_DATA_SPACE, context_data_space_used_);
-  deserializer.set_reservation(CODE_SPACE, context_code_space_used_);
-  deserializer.set_reservation(MAP_SPACE, context_map_space_used_);
-  deserializer.set_reservation(CELL_SPACE, context_cell_space_used_);
-  deserializer.set_reservation(PROPERTY_CELL_SPACE,
-                               context_property_cell_space_used_);
   deserializer.DeserializePartial(isolate, &root);
   CHECK(root->IsContext());
   return Handle<Context>(Context::cast(root));
 }
 
 
-#ifdef V8_USE_EXTERNAL_STARTUP_DATA
-// Dummy implementations of Set*FromFile(..) APIs.
-//
-// These are meant for use with snapshot-external.cc. Should this file
-// be compiled with those options we just supply these dummy implementations
-// below. This happens when compiling the mksnapshot utility.
-void SetNativesFromFile(StartupData* data) { CHECK(false); }
-void SetSnapshotFromFile(StartupData* data) { CHECK(false); }
-#endif  // V8_USE_EXTERNAL_STARTUP_DATA
+v8::StartupData Snapshot::CreateSnapshotBlob(
+    const Vector<const byte> startup_data,
+    const Vector<const byte> context_data) {
+  int startup_length = startup_data.length();
+  int context_length = context_data.length();
+  int context_offset = kIntSize + startup_length;
+  int length = context_offset + context_length;
+  char* data = new char[length];
 
+  memcpy(data, &startup_length, kIntSize);
+  memcpy(data + kIntSize, startup_data.begin(), startup_length);
+  memcpy(data + context_offset, context_data.begin(), context_length);
+  v8::StartupData result = {data, length};
+  return result;
+}
+
+
+Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
+  DCHECK_LT(kIntSize, data->raw_size);
+  int startup_length;
+  memcpy(&startup_length, data->data, kIntSize);
+  DCHECK_LT(startup_length, data->raw_size);
+  const byte* startup_data =
+      reinterpret_cast<const byte*>(data->data + kIntSize);
+  return Vector<const byte>(startup_data, startup_length);
+}
+
+
+Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data) {
+  DCHECK_LT(kIntSize, data->raw_size);
+  int startup_length;
+  memcpy(&startup_length, data->data, kIntSize);
+  int context_offset = kIntSize + startup_length;
+  const byte* context_data =
+      reinterpret_cast<const byte*>(data->data + context_offset);
+  DCHECK_LT(context_offset, data->raw_size);
+  int context_length = data->raw_size - context_offset;
+  return Vector<const byte>(context_data, context_length);
+}
 } }  // namespace v8::internal
diff --git a/src/snapshot-empty.cc b/src/snapshot-empty.cc
index 65207bf..020d1cb 100644
--- a/src/snapshot-empty.cc
+++ b/src/snapshot-empty.cc
@@ -11,29 +11,18 @@
 namespace v8 {
 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;
+#ifdef V8_USE_EXTERNAL_STARTUP_DATA
+// Dummy implementations of Set*FromFile(..) APIs.
+//
+// These are meant for use with snapshot-external.cc. Should this file
+// be compiled with those options we just supply these dummy implementations
+// below. This happens when compiling the mksnapshot utility.
+void SetNativesFromFile(StartupData* data) { CHECK(false); }
+void SetSnapshotFromFile(StartupData* data) { CHECK(false); }
+#endif  // V8_USE_EXTERNAL_STARTUP_DATA
 
-const int Snapshot::new_space_used_ = 0;
-const int Snapshot::pointer_space_used_ = 0;
-const int Snapshot::data_space_used_ = 0;
-const int Snapshot::code_space_used_ = 0;
-const int Snapshot::map_space_used_ = 0;
-const int Snapshot::cell_space_used_ = 0;
-const int Snapshot::property_cell_space_used_ = 0;
 
-const int Snapshot::context_new_space_used_ = 0;
-const int Snapshot::context_pointer_space_used_ = 0;
-const int Snapshot::context_data_space_used_ = 0;
-const int Snapshot::context_code_space_used_ = 0;
-const int Snapshot::context_map_space_used_ = 0;
-const int Snapshot::context_cell_space_used_ = 0;
-const int Snapshot::context_property_cell_space_used_ = 0;
-
+const v8::StartupData Snapshot::SnapshotBlob() {
+  return {NULL, 0};
+}
 } }  // namespace v8::internal
diff --git a/src/snapshot-external.cc b/src/snapshot-external.cc
index ee1a8f4..2fda571 100644
--- a/src/snapshot-external.cc
+++ b/src/snapshot-external.cc
@@ -10,131 +10,28 @@
 #include "src/snapshot-source-sink.h"
 #include "src/v8.h"  // for V8::Initialize
 
+
+#ifndef V8_USE_EXTERNAL_STARTUP_DATA
+#error snapshot-external.cc is used only for the external snapshot build.
+#endif  // V8_USE_EXTERNAL_STARTUP_DATA
+
+
 namespace v8 {
 namespace internal {
 
-
-struct SnapshotImpl {
- public:
-  const byte* data;
-  int size;
-  int new_space_used;
-  int pointer_space_used;
-  int data_space_used;
-  int code_space_used;
-  int map_space_used;
-  int cell_space_used;
-  int property_cell_space_used;
-
-  const byte* context_data;
-  int context_size;
-  int context_new_space_used;
-  int context_pointer_space_used;
-  int context_data_space_used;
-  int context_code_space_used;
-  int context_map_space_used;
-  int context_cell_space_used;
-  int context_property_cell_space_used;
-};
-
-
-static SnapshotImpl* snapshot_impl_ = NULL;
-
-
-bool Snapshot::HaveASnapshotToStartFrom() {
-  return snapshot_impl_ != NULL;
-}
-
-
-bool Snapshot::Initialize(Isolate* isolate) {
-  if (!HaveASnapshotToStartFrom())
-    return false;
-
-  base::ElapsedTimer timer;
-  if (FLAG_profile_deserialization) {
-    timer.Start();
-  }
-  SnapshotByteSource source(snapshot_impl_->data, snapshot_impl_->size);
-  Deserializer deserializer(&source);
-  deserializer.set_reservation(NEW_SPACE, snapshot_impl_->new_space_used);
-  deserializer.set_reservation(OLD_POINTER_SPACE,
-                               snapshot_impl_->pointer_space_used);
-  deserializer.set_reservation(OLD_DATA_SPACE,
-                               snapshot_impl_->data_space_used);
-  deserializer.set_reservation(CODE_SPACE, snapshot_impl_->code_space_used);
-  deserializer.set_reservation(MAP_SPACE, snapshot_impl_->map_space_used);
-  deserializer.set_reservation(CELL_SPACE, snapshot_impl_->cell_space_used);
-  deserializer.set_reservation(PROPERTY_CELL_SPACE,
-                               snapshot_impl_->property_cell_space_used);
-  bool success = isolate->Init(&deserializer);
-  if (FLAG_profile_deserialization) {
-    double ms = timer.Elapsed().InMillisecondsF();
-    PrintF("[Snapshot loading and deserialization took %0.3f ms]\n", ms);
-  }
-  return success;
-}
-
-
-Handle<Context> Snapshot::NewContextFromSnapshot(Isolate* isolate) {
-  if (!HaveASnapshotToStartFrom())
-    return Handle<Context>();
-
-  SnapshotByteSource source(snapshot_impl_->context_data,
-                            snapshot_impl_->context_size);
-  Deserializer deserializer(&source);
-  deserializer.set_reservation(NEW_SPACE,
-                               snapshot_impl_->context_new_space_used);
-  deserializer.set_reservation(OLD_POINTER_SPACE,
-                               snapshot_impl_->context_pointer_space_used);
-  deserializer.set_reservation(OLD_DATA_SPACE,
-                               snapshot_impl_->context_data_space_used);
-  deserializer.set_reservation(CODE_SPACE,
-                               snapshot_impl_->context_code_space_used);
-  deserializer.set_reservation(MAP_SPACE,
-                               snapshot_impl_->context_map_space_used);
-  deserializer.set_reservation(CELL_SPACE,
-                               snapshot_impl_->context_cell_space_used);
-  deserializer.set_reservation(PROPERTY_CELL_SPACE,
-                               snapshot_impl_->
-                                   context_property_cell_space_used);
-  Object* root;
-  deserializer.DeserializePartial(isolate, &root);
-  CHECK(root->IsContext());
-  return Handle<Context>(Context::cast(root));
-}
-
+static v8::StartupData external_startup_blob = {NULL, 0};
 
 void SetSnapshotFromFile(StartupData* snapshot_blob) {
   DCHECK(snapshot_blob);
   DCHECK(snapshot_blob->data);
   DCHECK(snapshot_blob->raw_size > 0);
-  DCHECK(!snapshot_impl_);
-
-  snapshot_impl_ = new SnapshotImpl;
-  SnapshotByteSource source(reinterpret_cast<const byte*>(snapshot_blob->data),
-                            snapshot_blob->raw_size);
-
-  bool success = source.GetBlob(&snapshot_impl_->data,
-                                &snapshot_impl_->size);
-  snapshot_impl_->new_space_used = source.GetInt();
-  snapshot_impl_->pointer_space_used = source.GetInt();
-  snapshot_impl_->data_space_used = source.GetInt();
-  snapshot_impl_->code_space_used = source.GetInt();
-  snapshot_impl_->map_space_used = source.GetInt();
-  snapshot_impl_->cell_space_used = source.GetInt();
-  snapshot_impl_->property_cell_space_used = source.GetInt();
-
-  success &= source.GetBlob(&snapshot_impl_->context_data,
-                            &snapshot_impl_->context_size);
-  snapshot_impl_->context_new_space_used = source.GetInt();
-  snapshot_impl_->context_pointer_space_used = source.GetInt();
-  snapshot_impl_->context_data_space_used = source.GetInt();
-  snapshot_impl_->context_code_space_used = source.GetInt();
-  snapshot_impl_->context_map_space_used = source.GetInt();
-  snapshot_impl_->context_cell_space_used = source.GetInt();
-  snapshot_impl_->context_property_cell_space_used = source.GetInt();
-
-  DCHECK(success);
+  DCHECK(!external_startup_blob.data);
+  // Validate snapshot blob.
+  DCHECK(!Snapshot::ExtractStartupData(snapshot_blob).is_empty());
+  DCHECK(!Snapshot::ExtractContextData(snapshot_blob).is_empty());
+  external_startup_blob = *snapshot_blob;
 }
 
+
+const v8::StartupData Snapshot::SnapshotBlob() { return external_startup_blob; }
 } }  // namespace v8::internal
diff --git a/src/snapshot-source-sink.cc b/src/snapshot-source-sink.cc
index 44f8706..fd94724 100644
--- a/src/snapshot-source-sink.cc
+++ b/src/snapshot-source-sink.cc
@@ -13,15 +13,6 @@
 namespace v8 {
 namespace internal {
 
-
-SnapshotByteSource::SnapshotByteSource(const byte* array, int length)
-    : data_(array), length_(length), position_(0) {
-}
-
-
-SnapshotByteSource::~SnapshotByteSource() { }
-
-
 int32_t SnapshotByteSource::GetUnalignedInt() {
   DCHECK(position_ < length_);  // Require at least one byte left.
   int32_t answer = data_[position_];
@@ -39,28 +30,23 @@
 
 
 void SnapshotByteSink::PutInt(uintptr_t integer, const char* description) {
-  DCHECK(integer < 1 << 22);
+  DCHECK(integer < 1 << 30);
   integer <<= 2;
   int bytes = 1;
   if (integer > 0xff) bytes = 2;
   if (integer > 0xffff) bytes = 3;
-  integer |= bytes;
+  if (integer > 0xffffff) bytes = 4;
+  integer |= (bytes - 1);
   Put(static_cast<int>(integer & 0xff), "IntPart1");
   if (bytes > 1) Put(static_cast<int>((integer >> 8) & 0xff), "IntPart2");
   if (bytes > 2) Put(static_cast<int>((integer >> 16) & 0xff), "IntPart3");
+  if (bytes > 3) Put(static_cast<int>((integer >> 24) & 0xff), "IntPart4");
 }
 
-void SnapshotByteSink::PutRaw(byte* data, int number_of_bytes,
+
+void SnapshotByteSink::PutRaw(const byte* data, int number_of_bytes,
                               const char* description) {
-  for (int i = 0; i < number_of_bytes; ++i) {
-    Put(data[i], description);
-  }
-}
-
-void SnapshotByteSink::PutBlob(byte* data, int number_of_bytes,
-                               const char* description) {
-  PutInt(number_of_bytes, description);
-  PutRaw(data, number_of_bytes, description);
+  data_.AddAll(Vector<byte>(const_cast<byte*>(data), number_of_bytes));
 }
 
 
@@ -77,7 +63,7 @@
   int size = GetInt();
   *number_of_bytes = size;
 
-  if (position_ + size < length_) {
+  if (position_ + size <= length_) {
     *data = &data_[position_];
     Advance(size);
     return true;
@@ -87,11 +73,5 @@
   }
 }
 
-
-void DebugSnapshotSink::Put(byte b, const char* description) {
-  PrintF("%24s: %x\n", description, b);
-  sink_->Put(b, description);
-}
-
 }  // namespace v8::internal
 }  // namespace v8
diff --git a/src/snapshot-source-sink.h b/src/snapshot-source-sink.h
index 3c64bca..66feaec 100644
--- a/src/snapshot-source-sink.h
+++ b/src/snapshot-source-sink.h
@@ -19,12 +19,19 @@
  */
 class SnapshotByteSource FINAL {
  public:
-  SnapshotByteSource(const byte* array, int length);
-  ~SnapshotByteSource();
+  SnapshotByteSource(const char* data, int length)
+      : data_(reinterpret_cast<const byte*>(data)),
+        length_(length),
+        position_(0) {}
+
+  explicit SnapshotByteSource(Vector<const byte> payload)
+      : data_(payload.start()), length_(payload.length()), position_(0) {}
+
+  ~SnapshotByteSource() {}
 
   bool HasMore() { return position_ < length_; }
 
-  int Get() {
+  byte Get() {
     DCHECK(position_ < length_);
     return data_[position_++];
   }
@@ -39,7 +46,7 @@
     // This way of variable-length encoding integers does not suffer from branch
     // mispredictions.
     uint32_t answer = GetUnalignedInt();
-    int bytes = answer & 3;
+    int bytes = (answer & 3) + 1;
     Advance(bytes);
     uint32_t mask = 0xffffffffu;
     mask >>= 32 - (bytes << 3);
@@ -70,53 +77,26 @@
  */
 class SnapshotByteSink {
  public:
-  virtual ~SnapshotByteSink() { }
-  virtual void Put(byte b, const char* description) = 0;
-  virtual void PutSection(int b, const char* description) {
+  SnapshotByteSink() {}
+  explicit SnapshotByteSink(int initial_size) : data_(initial_size) {}
+
+  ~SnapshotByteSink() {}
+
+  void Put(byte b, const char* description) { data_.Add(b); }
+
+  void PutSection(int b, const char* description) {
     DCHECK_LE(b, kMaxUInt8);
     Put(static_cast<byte>(b), description);
   }
+
   void PutInt(uintptr_t integer, const char* description);
-  void PutRaw(byte* data, int number_of_bytes, const char* description);
-  void PutBlob(byte* data, int number_of_bytes, const char* description);
-  virtual int Position() = 0;
-};
+  void PutRaw(const byte* data, int number_of_bytes, const char* description);
+  int Position() { return data_.length(); }
 
-
-class DummySnapshotSink : public SnapshotByteSink {
- public:
-  DummySnapshotSink() : length_(0) {}
-  virtual ~DummySnapshotSink() {}
-  virtual void Put(byte b, const char* description) { length_++; }
-  virtual int Position() { return length_; }
+  const List<byte>& data() const { return data_; }
 
  private:
-  int length_;
-};
-
-
-// Wrap a SnapshotByteSink into a DebugSnapshotSink to get debugging output.
-class DebugSnapshotSink : public SnapshotByteSink {
- public:
-  explicit DebugSnapshotSink(SnapshotByteSink* chained) : sink_(chained) {}
-  virtual void Put(byte b, const char* description) OVERRIDE;
-  virtual int Position() OVERRIDE { return sink_->Position(); }
-
- private:
-  SnapshotByteSink* sink_;
-};
-
-
-class ListSnapshotSink : public i::SnapshotByteSink {
- public:
-  explicit ListSnapshotSink(i::List<byte>* data) : data_(data) {}
-  virtual void Put(byte b, const char* description) OVERRIDE {
-    data_->Add(b);
-  }
-  virtual int Position() OVERRIDE { return data_->length(); }
-
- private:
-  i::List<byte>* data_;
+  List<byte> data_;
 };
 
 }  // namespace v8::internal
diff --git a/src/snapshot.h b/src/snapshot.h
index 3d752a7..25a07cd 100644
--- a/src/snapshot.h
+++ b/src/snapshot.h
@@ -10,58 +10,27 @@
 namespace v8 {
 namespace internal {
 
-class Snapshot {
+class Snapshot : public AllStatic {
  public:
   // Initialize the Isolate from the internal snapshot. Returns false if no
   // snapshot could be found.
   static bool Initialize(Isolate* isolate);
-
-  static bool HaveASnapshotToStartFrom();
-
   // Create a new context using the internal partial snapshot.
   static Handle<Context> NewContextFromSnapshot(Isolate* isolate);
 
-  // These methods support COMPRESS_STARTUP_DATA_BZ2.
-  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;
-  }
+  static bool HaveASnapshotToStartFrom();
+
+  // To be implemented by the snapshot source.
+  static const v8::StartupData SnapshotBlob();
+
+  static v8::StartupData CreateSnapshotBlob(
+      const Vector<const byte> startup_data,
+      const Vector<const byte> context_data);
+
+  static Vector<const byte> ExtractStartupData(const v8::StartupData* data);
+  static Vector<const byte> ExtractContextData(const v8::StartupData* 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 code_space_used_;
-  static const int map_space_used_;
-  static const int cell_space_used_;
-  static const int property_cell_space_used_;
-  static const int context_new_space_used_;
-  static const int context_pointer_space_used_;
-  static const int context_data_space_used_;
-  static const int context_code_space_used_;
-  static const int context_map_space_used_;
-  static const int context_cell_space_used_;
-  static const int context_property_cell_space_used_;
-  static const int size_;
-  static const int raw_size_;
-  static const int context_size_;
-  static const int context_raw_size_;
-
-  static void ReserveSpaceForLinkedInSnapshot(Deserializer* deserializer);
-
   DISALLOW_IMPLICIT_CONSTRUCTORS(Snapshot);
 };
 
diff --git a/src/string-builder.cc b/src/string-builder.cc
new file mode 100644
index 0000000..38c3188
--- /dev/null
+++ b/src/string-builder.cc
@@ -0,0 +1,111 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/string-builder.h"
+
+namespace v8 {
+namespace internal {
+
+MaybeHandle<String> ReplacementStringBuilder::ToString() {
+  Isolate* isolate = heap_->isolate();
+  if (array_builder_.length() == 0) {
+    return isolate->factory()->empty_string();
+  }
+
+  Handle<String> joined_string;
+  if (is_one_byte_) {
+    Handle<SeqOneByteString> seq;
+    ASSIGN_RETURN_ON_EXCEPTION(
+        isolate, seq, isolate->factory()->NewRawOneByteString(character_count_),
+        String);
+
+    DisallowHeapAllocation no_gc;
+    uint8_t* char_buffer = seq->GetChars();
+    StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(),
+                              array_builder_.length());
+    joined_string = Handle<String>::cast(seq);
+  } else {
+    // Two-byte.
+    Handle<SeqTwoByteString> seq;
+    ASSIGN_RETURN_ON_EXCEPTION(
+        isolate, seq, isolate->factory()->NewRawTwoByteString(character_count_),
+        String);
+
+    DisallowHeapAllocation no_gc;
+    uc16* char_buffer = seq->GetChars();
+    StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(),
+                              array_builder_.length());
+    joined_string = Handle<String>::cast(seq);
+  }
+  return joined_string;
+}
+
+
+IncrementalStringBuilder::IncrementalStringBuilder(Isolate* isolate)
+    : isolate_(isolate),
+      encoding_(String::ONE_BYTE_ENCODING),
+      overflowed_(false),
+      part_length_(kInitialPartLength),
+      current_index_(0) {
+  // Create an accumulator handle starting with the empty string.
+  accumulator_ = Handle<String>(isolate->heap()->empty_string(), isolate);
+  current_part_ =
+      factory()->NewRawOneByteString(part_length_).ToHandleChecked();
+}
+
+
+void IncrementalStringBuilder::Accumulate() {
+  // Only accumulate fully written strings. Shrink first if necessary.
+  DCHECK_EQ(current_index_, current_part()->length());
+  Handle<String> new_accumulator;
+  if (accumulator()->length() + current_part()->length() > String::kMaxLength) {
+    // Set the flag and carry on. Delay throwing the exception till the end.
+    new_accumulator = factory()->empty_string();
+    overflowed_ = true;
+  } else {
+    new_accumulator = factory()
+                          ->NewConsString(accumulator(), current_part())
+                          .ToHandleChecked();
+  }
+  set_accumulator(new_accumulator);
+}
+
+
+void IncrementalStringBuilder::Extend() {
+  Accumulate();
+  if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) {
+    part_length_ *= kPartLengthGrowthFactor;
+  }
+  Handle<String> new_part;
+  if (encoding_ == String::ONE_BYTE_ENCODING) {
+    new_part = factory()->NewRawOneByteString(part_length_).ToHandleChecked();
+  } else {
+    new_part = factory()->NewRawTwoByteString(part_length_).ToHandleChecked();
+  }
+  // Reuse the same handle to avoid being invalidated when exiting handle scope.
+  set_current_part(new_part);
+  current_index_ = 0;
+}
+
+
+MaybeHandle<String> IncrementalStringBuilder::Finish() {
+  ShrinkCurrentPart();
+  Accumulate();
+  if (overflowed_) {
+    THROW_NEW_ERROR(isolate_, NewInvalidStringLengthError(), String);
+  }
+  return accumulator();
+}
+
+
+void IncrementalStringBuilder::AppendString(Handle<String> string) {
+  ShrinkCurrentPart();
+  part_length_ = kInitialPartLength;  // Allocate conservatively.
+  Extend();  // Attach current part and allocate new part.
+  Handle<String> concat =
+      factory()->NewConsString(accumulator(), string).ToHandleChecked();
+  set_accumulator(concat);
+}
+}
+}  // namespace v8::internal
diff --git a/src/string-builder.h b/src/string-builder.h
new file mode 100644
index 0000000..43b690d
--- /dev/null
+++ b/src/string-builder.h
@@ -0,0 +1,430 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_STRING_BUILDER_H_
+#define V8_STRING_BUILDER_H_
+
+#include "src/v8.h"
+
+namespace v8 {
+namespace internal {
+
+const int kStringBuilderConcatHelperLengthBits = 11;
+const int kStringBuilderConcatHelperPositionBits = 19;
+
+typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
+    StringBuilderSubstringLength;
+typedef BitField<int, kStringBuilderConcatHelperLengthBits,
+                 kStringBuilderConcatHelperPositionBits>
+    StringBuilderSubstringPosition;
+
+
+template <typename sinkchar>
+static inline void StringBuilderConcatHelper(String* special, sinkchar* sink,
+                                             FixedArray* fixed_array,
+                                             int array_length) {
+  DisallowHeapAllocation no_gc;
+  int position = 0;
+  for (int i = 0; i < array_length; i++) {
+    Object* element = fixed_array->get(i);
+    if (element->IsSmi()) {
+      // Smi encoding of position and length.
+      int encoded_slice = Smi::cast(element)->value();
+      int pos;
+      int len;
+      if (encoded_slice > 0) {
+        // Position and length encoded in one smi.
+        pos = StringBuilderSubstringPosition::decode(encoded_slice);
+        len = StringBuilderSubstringLength::decode(encoded_slice);
+      } else {
+        // Position and length encoded in two smis.
+        Object* obj = fixed_array->get(++i);
+        DCHECK(obj->IsSmi());
+        pos = Smi::cast(obj)->value();
+        len = -encoded_slice;
+      }
+      String::WriteToFlat(special, sink + position, pos, pos + len);
+      position += len;
+    } else {
+      String* string = String::cast(element);
+      int element_length = string->length();
+      String::WriteToFlat(string, sink + position, 0, element_length);
+      position += element_length;
+    }
+  }
+}
+
+
+// Returns the result length of the concatenation.
+// On illegal argument, -1 is returned.
+static inline int StringBuilderConcatLength(int special_length,
+                                            FixedArray* fixed_array,
+                                            int array_length, bool* one_byte) {
+  DisallowHeapAllocation no_gc;
+  int position = 0;
+  for (int i = 0; i < array_length; i++) {
+    int increment = 0;
+    Object* elt = fixed_array->get(i);
+    if (elt->IsSmi()) {
+      // Smi encoding of position and length.
+      int smi_value = Smi::cast(elt)->value();
+      int pos;
+      int len;
+      if (smi_value > 0) {
+        // Position and length encoded in one smi.
+        pos = StringBuilderSubstringPosition::decode(smi_value);
+        len = StringBuilderSubstringLength::decode(smi_value);
+      } else {
+        // Position and length encoded in two smis.
+        len = -smi_value;
+        // Get the position and check that it is a positive smi.
+        i++;
+        if (i >= array_length) return -1;
+        Object* next_smi = fixed_array->get(i);
+        if (!next_smi->IsSmi()) return -1;
+        pos = Smi::cast(next_smi)->value();
+        if (pos < 0) return -1;
+      }
+      DCHECK(pos >= 0);
+      DCHECK(len >= 0);
+      if (pos > special_length || len > special_length - pos) return -1;
+      increment = len;
+    } else if (elt->IsString()) {
+      String* element = String::cast(elt);
+      int element_length = element->length();
+      increment = element_length;
+      if (*one_byte && !element->HasOnlyOneByteChars()) {
+        *one_byte = false;
+      }
+    } else {
+      return -1;
+    }
+    if (increment > String::kMaxLength - position) {
+      return kMaxInt;  // Provoke throw on allocation.
+    }
+    position += increment;
+  }
+  return position;
+}
+
+
+class FixedArrayBuilder {
+ public:
+  explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
+      : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
+        length_(0),
+        has_non_smi_elements_(false) {
+    // Require a non-zero initial size. Ensures that doubling the size to
+    // extend the array will work.
+    DCHECK(initial_capacity > 0);
+  }
+
+  explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
+      : array_(backing_store), length_(0), has_non_smi_elements_(false) {
+    // Require a non-zero initial size. Ensures that doubling the size to
+    // extend the array will work.
+    DCHECK(backing_store->length() > 0);
+  }
+
+  bool HasCapacity(int elements) {
+    int length = array_->length();
+    int required_length = length_ + elements;
+    return (length >= required_length);
+  }
+
+  void EnsureCapacity(int elements) {
+    int length = array_->length();
+    int required_length = length_ + elements;
+    if (length < required_length) {
+      int new_length = length;
+      do {
+        new_length *= 2;
+      } while (new_length < required_length);
+      Handle<FixedArray> extended_array =
+          array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
+      array_->CopyTo(0, *extended_array, 0, length_);
+      array_ = extended_array;
+    }
+  }
+
+  void Add(Object* value) {
+    DCHECK(!value->IsSmi());
+    DCHECK(length_ < capacity());
+    array_->set(length_, value);
+    length_++;
+    has_non_smi_elements_ = true;
+  }
+
+  void Add(Smi* value) {
+    DCHECK(value->IsSmi());
+    DCHECK(length_ < capacity());
+    array_->set(length_, value);
+    length_++;
+  }
+
+  Handle<FixedArray> array() { return array_; }
+
+  int length() { return length_; }
+
+  int capacity() { return array_->length(); }
+
+  Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
+    JSArray::SetContent(target_array, array_);
+    target_array->set_length(Smi::FromInt(length_));
+    return target_array;
+  }
+
+
+ private:
+  Handle<FixedArray> array_;
+  int length_;
+  bool has_non_smi_elements_;
+};
+
+
+class ReplacementStringBuilder {
+ public:
+  ReplacementStringBuilder(Heap* heap, Handle<String> subject,
+                           int estimated_part_count)
+      : heap_(heap),
+        array_builder_(heap->isolate(), estimated_part_count),
+        subject_(subject),
+        character_count_(0),
+        is_one_byte_(subject->IsOneByteRepresentation()) {
+    // Require a non-zero initial size. Ensures that doubling the size to
+    // extend the array will work.
+    DCHECK(estimated_part_count > 0);
+  }
+
+  static inline void AddSubjectSlice(FixedArrayBuilder* builder, int from,
+                                     int to) {
+    DCHECK(from >= 0);
+    int length = to - from;
+    DCHECK(length > 0);
+    if (StringBuilderSubstringLength::is_valid(length) &&
+        StringBuilderSubstringPosition::is_valid(from)) {
+      int encoded_slice = StringBuilderSubstringLength::encode(length) |
+                          StringBuilderSubstringPosition::encode(from);
+      builder->Add(Smi::FromInt(encoded_slice));
+    } else {
+      // Otherwise encode as two smis.
+      builder->Add(Smi::FromInt(-length));
+      builder->Add(Smi::FromInt(from));
+    }
+  }
+
+
+  void EnsureCapacity(int elements) { array_builder_.EnsureCapacity(elements); }
+
+
+  void AddSubjectSlice(int from, int to) {
+    AddSubjectSlice(&array_builder_, from, to);
+    IncrementCharacterCount(to - from);
+  }
+
+
+  void AddString(Handle<String> string) {
+    int length = string->length();
+    DCHECK(length > 0);
+    AddElement(*string);
+    if (!string->IsOneByteRepresentation()) {
+      is_one_byte_ = false;
+    }
+    IncrementCharacterCount(length);
+  }
+
+
+  MaybeHandle<String> ToString();
+
+
+  void IncrementCharacterCount(int by) {
+    if (character_count_ > String::kMaxLength - by) {
+      STATIC_ASSERT(String::kMaxLength < kMaxInt);
+      character_count_ = kMaxInt;
+    } else {
+      character_count_ += by;
+    }
+  }
+
+ private:
+  void AddElement(Object* element) {
+    DCHECK(element->IsSmi() || element->IsString());
+    DCHECK(array_builder_.capacity() > array_builder_.length());
+    array_builder_.Add(element);
+  }
+
+  Heap* heap_;
+  FixedArrayBuilder array_builder_;
+  Handle<String> subject_;
+  int character_count_;
+  bool is_one_byte_;
+};
+
+
+class IncrementalStringBuilder {
+ public:
+  explicit IncrementalStringBuilder(Isolate* isolate);
+
+  INLINE(String::Encoding CurrentEncoding()) { return encoding_; }
+
+  template <typename SrcChar, typename DestChar>
+  INLINE(void Append(SrcChar c));
+
+  INLINE(void AppendCharacter(uint8_t c)) {
+    if (encoding_ == String::ONE_BYTE_ENCODING) {
+      Append<uint8_t, uint8_t>(c);
+    } else {
+      Append<uint8_t, uc16>(c);
+    }
+  }
+
+  INLINE(void AppendCString(const char* s)) {
+    const uint8_t* u = reinterpret_cast<const uint8_t*>(s);
+    if (encoding_ == String::ONE_BYTE_ENCODING) {
+      while (*u != '\0') Append<uint8_t, uint8_t>(*(u++));
+    } else {
+      while (*u != '\0') Append<uint8_t, uc16>(*(u++));
+    }
+  }
+
+  INLINE(bool CurrentPartCanFit(int length)) {
+    return part_length_ - current_index_ > length;
+  }
+
+  void AppendString(Handle<String> string);
+
+  MaybeHandle<String> Finish();
+
+  // Change encoding to two-byte.
+  void ChangeEncoding() {
+    DCHECK_EQ(String::ONE_BYTE_ENCODING, encoding_);
+    ShrinkCurrentPart();
+    encoding_ = String::TWO_BYTE_ENCODING;
+    Extend();
+  }
+
+  template <typename DestChar>
+  class NoExtend {
+   public:
+    explicit NoExtend(Handle<String> string, int offset) {
+      DCHECK(string->IsSeqOneByteString() || string->IsSeqTwoByteString());
+      if (sizeof(DestChar) == 1) {
+        start_ = reinterpret_cast<DestChar*>(
+            Handle<SeqOneByteString>::cast(string)->GetChars() + offset);
+      } else {
+        start_ = reinterpret_cast<DestChar*>(
+            Handle<SeqTwoByteString>::cast(string)->GetChars() + offset);
+      }
+      cursor_ = start_;
+    }
+
+    INLINE(void Append(DestChar c)) { *(cursor_++) = c; }
+    INLINE(void AppendCString(const char* s)) {
+      const uint8_t* u = reinterpret_cast<const uint8_t*>(s);
+      while (*u != '\0') Append(*(u++));
+    }
+
+    int written() { return static_cast<int>(cursor_ - start_); }
+
+   private:
+    DestChar* start_;
+    DestChar* cursor_;
+    DisallowHeapAllocation no_gc_;
+  };
+
+  template <typename DestChar>
+  class NoExtendString : public NoExtend<DestChar> {
+   public:
+    NoExtendString(Handle<String> string, int required_length)
+        : NoExtend<DestChar>(string, 0), string_(string) {
+      DCHECK(string->length() >= required_length);
+    }
+
+    ~NoExtendString() {
+      Handle<SeqString> string = Handle<SeqString>::cast(string_);
+      int length = NoExtend<DestChar>::written();
+      *string_.location() = *SeqString::Truncate(string, length);
+    }
+
+   private:
+    Handle<String> string_;
+  };
+
+  template <typename DestChar>
+  class NoExtendBuilder : public NoExtend<DestChar> {
+   public:
+    NoExtendBuilder(IncrementalStringBuilder* builder, int required_length)
+        : NoExtend<DestChar>(builder->current_part(), builder->current_index_),
+          builder_(builder) {
+      DCHECK(builder->CurrentPartCanFit(required_length));
+    }
+
+    ~NoExtendBuilder() {
+      builder_->current_index_ += NoExtend<DestChar>::written();
+    }
+
+   private:
+    IncrementalStringBuilder* builder_;
+  };
+
+ private:
+  Factory* factory() { return isolate_->factory(); }
+
+  INLINE(Handle<String> accumulator()) { return accumulator_; }
+
+  INLINE(void set_accumulator(Handle<String> string)) {
+    *accumulator_.location() = *string;
+  }
+
+  INLINE(Handle<String> current_part()) { return current_part_; }
+
+  INLINE(void set_current_part(Handle<String> string)) {
+    *current_part_.location() = *string;
+  }
+
+  // Add the current part to the accumulator.
+  void Accumulate();
+
+  // Finish the current part and allocate a new part.
+  void Extend();
+
+  // Shrink current part to the right size.
+  void ShrinkCurrentPart() {
+    DCHECK(current_index_ < part_length_);
+    set_current_part(SeqString::Truncate(
+        Handle<SeqString>::cast(current_part()), current_index_));
+  }
+
+  static const int kInitialPartLength = 32;
+  static const int kMaxPartLength = 16 * 1024;
+  static const int kPartLengthGrowthFactor = 2;
+
+  Isolate* isolate_;
+  String::Encoding encoding_;
+  bool overflowed_;
+  int part_length_;
+  int current_index_;
+  Handle<String> accumulator_;
+  Handle<String> current_part_;
+};
+
+
+template <typename SrcChar, typename DestChar>
+void IncrementalStringBuilder::Append(SrcChar c) {
+  DCHECK_EQ(encoding_ == String::ONE_BYTE_ENCODING, sizeof(DestChar) == 1);
+  if (sizeof(DestChar) == 1) {
+    DCHECK_EQ(String::ONE_BYTE_ENCODING, encoding_);
+    SeqOneByteString::cast(*current_part_)
+        ->SeqOneByteStringSet(current_index_++, c);
+  } else {
+    DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding_);
+    SeqTwoByteString::cast(*current_part_)
+        ->SeqTwoByteStringSet(current_index_++, c);
+  }
+  if (current_index_ == part_length_) Extend();
+}
+}
+}  // namespace v8::internal
+
+#endif  // V8_STRING_BUILDER_H_
diff --git a/src/string-iterator.js b/src/string-iterator.js
index cb578e7..f5eef37 100644
--- a/src/string-iterator.js
+++ b/src/string-iterator.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-'use strict';
+"use strict";
 
 
 // This file relies on the fact that the following declaration has been made
@@ -87,6 +87,8 @@
   %FunctionSetName(StringIteratorIterator, '[Symbol.iterator]');
   %AddNamedProperty(StringIterator.prototype, symbolIterator,
                     StringIteratorIterator, DONT_ENUM);
+  %AddNamedProperty(StringIterator.prototype, symbolToStringTag,
+                    "String Iterator", READ_ONLY | DONT_ENUM);
 }
 SetUpStringIterator();
 
diff --git a/src/string-stream.cc b/src/string-stream.cc
index 42c2af7..21f66a6 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -295,8 +295,7 @@
 
 
 bool StringStream::Put(String* str, int start, int end) {
-  ConsStringIteratorOp op;
-  StringCharacterStream stream(str, &op, start);
+  StringCharacterStream stream(str, start);
   for (int i = start; i < end && stream.HasMore(); i++) {
     uint16_t c = stream.GetNext();
     if (c >= 127 || c < 32) {
@@ -352,8 +351,13 @@
         }
         Add(": ");
         FieldIndex index = FieldIndex::ForDescriptor(map, i);
-        Object* value = js_object->RawFastPropertyAt(index);
-        Add("%o\n", value);
+        if (js_object->IsUnboxedDoubleField(index)) {
+          double value = js_object->RawFastDoublePropertyAt(index);
+          Add("<unboxed double> %.16g\n", FmtElm(value));
+        } else {
+          Object* value = js_object->RawFastPropertyAt(index);
+          Add("%o\n", value);
+        }
       }
     }
   }
diff --git a/src/string-stream.h b/src/string-stream.h
index fca1d4b..3b820cd 100644
--- a/src/string-stream.h
+++ b/src/string-stream.h
@@ -27,8 +27,8 @@
 class HeapStringAllocator FINAL : public StringAllocator {
  public:
   ~HeapStringAllocator() { DeleteArray(space_); }
-  virtual char* allocate(unsigned bytes) OVERRIDE;
-  virtual char* grow(unsigned* bytes) OVERRIDE;
+  char* allocate(unsigned bytes) OVERRIDE;
+  char* grow(unsigned* bytes) OVERRIDE;
 
  private:
   char* space_;
diff --git a/src/symbol.js b/src/symbol.js
index ce3327b..d9cf792 100644
--- a/src/symbol.js
+++ b/src/symbol.js
@@ -8,6 +8,14 @@
 // in runtime.js:
 // var $Array = global.Array;
 
+// And requires following symbols to be set in the bootstrapper during genesis:
+// - symbolHasInstance
+// - symbolIsConcatSpreadable
+// - symbolIsRegExp
+// - symbolIterator
+// - symbolToStringTag
+// - symbolUnscopables
+
 var $Symbol = global.Symbol;
 
 // -------------------------------------------------------------------
@@ -40,15 +48,6 @@
 }
 
 
-function InternalSymbol(key) {
-  var internal_registry = %SymbolRegistry().for_intern;
-  if (IS_UNDEFINED(internal_registry[key])) {
-    internal_registry[key] = %CreateSymbol(key);
-  }
-  return internal_registry[key];
-}
-
-
 function SymbolFor(key) {
   key = TO_STRING_INLINE(key);
   var registry = %SymbolRegistry();
@@ -69,27 +68,13 @@
 
 // ES6 19.1.2.8
 function ObjectGetOwnPropertySymbols(obj) {
-  if (!IS_SPEC_OBJECT(obj)) {
-    throw MakeTypeError("called_on_non_object",
-                        ["Object.getOwnPropertySymbols"]);
-  }
+  obj = ToObject(obj);
 
   // TODO(arv): Proxies use a shared trap for String and Symbol keys.
 
-  return ObjectGetOwnPropertyKeys(obj, true);
+  return ObjectGetOwnPropertyKeys(obj, PROPERTY_ATTRIBUTES_STRING);
 }
 
-
-//-------------------------------------------------------------------
-
-var symbolHasInstance = InternalSymbol("Symbol.hasInstance");
-var symbolIsConcatSpreadable = InternalSymbol("Symbol.isConcatSpreadable");
-var symbolIsRegExp = InternalSymbol("Symbol.isRegExp");
-var symbolIterator = InternalSymbol("Symbol.iterator");
-var symbolToStringTag = InternalSymbol("Symbol.toStringTag");
-var symbolUnscopables = InternalSymbol("Symbol.unscopables");
-
-
 //-------------------------------------------------------------------
 
 function SetUpSymbol() {
@@ -104,6 +89,8 @@
     // "isConcatSpreadable", symbolIsConcatSpreadable,
     // "isRegExp", symbolIsRegExp,
     "iterator", symbolIterator,
+    // TODO(dslomov, caitp): Currently defined in harmony-tostring.js ---
+    // Move here when shipping
     // "toStringTag", symbolToStringTag,
     "unscopables", symbolUnscopables
   ));
@@ -113,6 +100,8 @@
   ));
 
   %AddNamedProperty($Symbol.prototype, "constructor", $Symbol, DONT_ENUM);
+  %AddNamedProperty(
+      $Symbol.prototype, symbolToStringTag, "Symbol", DONT_ENUM | READ_ONLY);
   InstallFunctions($Symbol.prototype, DONT_ENUM, $Array(
     "toString", SymbolToString,
     "valueOf", SymbolValueOf
diff --git a/src/test/DEPS b/src/test/DEPS
deleted file mode 100644
index 13855ec..0000000
--- a/src/test/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+include/libplatform/libplatform.h"
-]
diff --git a/src/test/test-utils.cc b/src/test/test-utils.cc
deleted file mode 100644
index 1041465..0000000
--- a/src/test/test-utils.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/test/test-utils.h"
-
-#include "src/isolate-inl.h"
-
-namespace v8 {
-
-// static
-Isolate* TestWithIsolate::isolate_ = NULL;
-
-
-TestWithIsolate::TestWithIsolate()
-    : isolate_scope_(isolate()), handle_scope_(isolate()) {}
-
-
-TestWithIsolate::~TestWithIsolate() {}
-
-
-// static
-void TestWithIsolate::SetUpTestCase() {
-  Test::SetUpTestCase();
-  EXPECT_EQ(NULL, isolate_);
-  isolate_ = v8::Isolate::New();
-  EXPECT_TRUE(isolate_ != NULL);
-}
-
-
-// static
-void TestWithIsolate::TearDownTestCase() {
-  ASSERT_TRUE(isolate_ != NULL);
-  isolate_->Dispose();
-  isolate_ = NULL;
-  Test::TearDownTestCase();
-}
-
-
-TestWithContext::TestWithContext()
-    : context_(Context::New(isolate())), context_scope_(context_) {}
-
-
-TestWithContext::~TestWithContext() {}
-
-
-namespace internal {
-
-TestWithIsolate::~TestWithIsolate() {}
-
-
-Factory* TestWithIsolate::factory() const { return isolate()->factory(); }
-
-
-TestWithZone::~TestWithZone() {}
-
-}  // namespace internal
-}  // namespace v8
diff --git a/src/test/test-utils.h b/src/test/test-utils.h
deleted file mode 100644
index 05d1ea6..0000000
--- a/src/test/test-utils.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_TEST_TEST_UTILS_H_
-#define V8_TEST_TEST_UTILS_H_
-
-#include "include/v8.h"
-#include "src/base/macros.h"
-#include "src/zone.h"
-#include "testing/gtest-support.h"
-
-namespace v8 {
-
-class TestWithIsolate : public ::testing::Test {
- public:
-  TestWithIsolate();
-  virtual ~TestWithIsolate();
-
-  Isolate* isolate() const { return isolate_; }
-
-  static void SetUpTestCase();
-  static void TearDownTestCase();
-
- private:
-  static Isolate* isolate_;
-  Isolate::Scope isolate_scope_;
-  HandleScope handle_scope_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestWithIsolate);
-};
-
-
-class TestWithContext : public virtual TestWithIsolate {
- public:
-  TestWithContext();
-  virtual ~TestWithContext();
-
-  const Local<Context>& context() const { return context_; }
-
- private:
-  Local<Context> context_;
-  Context::Scope context_scope_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestWithContext);
-};
-
-
-namespace internal {
-
-// Forward declarations.
-class Factory;
-
-
-class TestWithIsolate : public virtual ::v8::TestWithIsolate {
- public:
-  TestWithIsolate() {}
-  virtual ~TestWithIsolate();
-
-  Factory* factory() const;
-  Isolate* isolate() const {
-    return reinterpret_cast<Isolate*>(::v8::TestWithIsolate::isolate());
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestWithIsolate);
-};
-
-
-class TestWithZone : public TestWithIsolate {
- public:
-  TestWithZone() : zone_(isolate()) {}
-  virtual ~TestWithZone();
-
-  Zone* zone() { return &zone_; }
-
- private:
-  Zone zone_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestWithZone);
-};
-
-}  // namespace internal
-}  // namespace v8
-
-#endif  // V8_TEST_TEST_UTILS_H_
diff --git a/src/test/test.gyp b/src/test/test.gyp
deleted file mode 100644
index f4c6a5e..0000000
--- a/src/test/test.gyp
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright 2014 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  'variables': {
-    'v8_code': 1,
-  },
-  'includes': ['../../build/toolchain.gypi', '../../build/features.gypi'],
-  'targets': [
-    {
-      'target_name': 'run-all-unittests',
-      'type': 'static_library',
-      'variables': {
-        'optimize': 'max',
-      },
-      'dependencies': [
-        '../../testing/gmock.gyp:gmock',
-        '../../testing/gtest.gyp:gtest',
-        '../../tools/gyp/v8.gyp:v8_libplatform',
-      ],
-      'include_dirs': [
-        '../..',
-      ],
-      'sources': [  ### gcmole(all) ###
-        'run-all-unittests.cc',
-        'test-utils.h',
-        'test-utils.cc',
-      ],
-      'export_dependent_settings': [
-        '../../testing/gmock.gyp:gmock',
-        '../../testing/gtest.gyp:gtest',
-      ],
-      'conditions': [
-        ['component=="shared_library"', {
-          # compiler-unittests can't be built against a shared library, so we
-          # need to depend on the underlying static target in that case.
-          'conditions': [
-            ['v8_use_snapshot=="true"', {
-              'dependencies': ['../../tools/gyp/v8.gyp:v8_snapshot'],
-            },
-            {
-              'dependencies': [
-                '../../tools/gyp/v8.gyp:v8_nosnapshot',
-              ],
-            }],
-          ],
-        }, {
-          'dependencies': ['../../tools/gyp/v8.gyp:v8'],
-        }],
-        ['os_posix == 1', {
-          # TODO(svenpanne): This is a temporary work-around to fix the warnings
-          # that show up because we use -std=gnu++0x instead of -std=c++11.
-          'cflags!': [
-            '-pedantic',
-          ],
-          'direct_dependent_settings': {
-            'cflags!': [
-              '-pedantic',
-            ],
-          },
-        }],
-        ['want_separate_host_toolset==1', {
-          'toolsets': ['host', 'target'],
-        }, {
-          'toolsets': ['target'],
-        }],
-      ],
-    },
-  ],
-}
diff --git a/third_party/fdlibm/LICENSE b/src/third_party/fdlibm/LICENSE
similarity index 100%
rename from third_party/fdlibm/LICENSE
rename to src/third_party/fdlibm/LICENSE
diff --git a/third_party/fdlibm/README.v8 b/src/third_party/fdlibm/README.v8
similarity index 100%
rename from third_party/fdlibm/README.v8
rename to src/third_party/fdlibm/README.v8
diff --git a/src/third_party/fdlibm/fdlibm.cc b/src/third_party/fdlibm/fdlibm.cc
new file mode 100644
index 0000000..cc5dbc2
--- /dev/null
+++ b/src/third_party/fdlibm/fdlibm.cc
@@ -0,0 +1,294 @@
+// The following is adapted from fdlibm (http://www.netlib.org/fdlibm).
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunSoft, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2014 the V8 project authors. All rights reserved.
+
+#include "src/v8.h"
+
+#include "src/double.h"
+#include "src/third_party/fdlibm/fdlibm.h"
+
+
+namespace v8 {
+namespace fdlibm {
+
+#ifdef _MSC_VER
+inline double scalbn(double x, int y) { return _scalb(x, y); }
+#endif  // _MSC_VER
+
+const double MathConstants::constants[] = {
+    6.36619772367581382433e-01,   // invpio2    0
+    1.57079632673412561417e+00,   // pio2_1     1
+    6.07710050650619224932e-11,   // pio2_1t    2
+    6.07710050630396597660e-11,   // pio2_2     3
+    2.02226624879595063154e-21,   // pio2_2t    4
+    2.02226624871116645580e-21,   // pio2_3     5
+    8.47842766036889956997e-32,   // pio2_3t    6
+    -1.66666666666666324348e-01,  // S1         7  coefficients for sin
+    8.33333333332248946124e-03,   //            8
+    -1.98412698298579493134e-04,  //            9
+    2.75573137070700676789e-06,   //           10
+    -2.50507602534068634195e-08,  //           11
+    1.58969099521155010221e-10,   // S6        12
+    4.16666666666666019037e-02,   // C1        13  coefficients for cos
+    -1.38888888888741095749e-03,  //           14
+    2.48015872894767294178e-05,   //           15
+    -2.75573143513906633035e-07,  //           16
+    2.08757232129817482790e-09,   //           17
+    -1.13596475577881948265e-11,  // C6        18
+    3.33333333333334091986e-01,   // T0        19  coefficients for tan
+    1.33333333333201242699e-01,   //           20
+    5.39682539762260521377e-02,   //           21
+    2.18694882948595424599e-02,   //           22
+    8.86323982359930005737e-03,   //           23
+    3.59207910759131235356e-03,   //           24
+    1.45620945432529025516e-03,   //           25
+    5.88041240820264096874e-04,   //           26
+    2.46463134818469906812e-04,   //           27
+    7.81794442939557092300e-05,   //           28
+    7.14072491382608190305e-05,   //           29
+    -1.85586374855275456654e-05,  //           30
+    2.59073051863633712884e-05,   // T12       31
+    7.85398163397448278999e-01,   // pio4      32
+    3.06161699786838301793e-17,   // pio4lo    33
+    6.93147180369123816490e-01,   // ln2_hi    34
+    1.90821492927058770002e-10,   // ln2_lo    35
+    6.666666666666666666e-01,     // 2/3       36
+    6.666666666666735130e-01,     // LP1       37  coefficients for log1p
+    3.999999999940941908e-01,     //           38
+    2.857142874366239149e-01,     //           39
+    2.222219843214978396e-01,     //           40
+    1.818357216161805012e-01,     //           41
+    1.531383769920937332e-01,     //           42
+    1.479819860511658591e-01,     // LP7       43
+    7.09782712893383973096e+02,   //           44  overflow threshold for expm1
+    1.44269504088896338700e+00,   // 1/ln2     45
+    -3.33333333333331316428e-02,  // Q1        46  coefficients for expm1
+    1.58730158725481460165e-03,   //           47
+    -7.93650757867487942473e-05,  //           48
+    4.00821782732936239552e-06,   //           49
+    -2.01099218183624371326e-07,  // Q5        50
+    710.4758600739439,            //           51  overflow threshold sinh, cosh
+    4.34294481903251816668e-01,   // ivln10    52  coefficients for log10
+    3.01029995663611771306e-01,   // log10_2hi 53
+    3.69423907715893078616e-13,   // log10_2lo 54
+    5.99999999999994648725e-01,   // L1        55  coefficients for log2
+    4.28571428578550184252e-01,   //           56
+    3.33333329818377432918e-01,   //           57
+    2.72728123808534006489e-01,   //           58
+    2.30660745775561754067e-01,   //           59
+    2.06975017800338417784e-01,   // L6        60
+    9.61796693925975554329e-01,   // cp        61  2/(3*ln(2))
+    9.61796700954437255859e-01,   // cp_h      62
+    -7.02846165095275826516e-09,  // cp_l      63
+    5.84962487220764160156e-01,   // dp_h      64
+    1.35003920212974897128e-08    // dp_l      65
+};
+
+
+// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
+static const int two_over_pi[] = {
+    0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C,
+    0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649,
+    0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, 0xA73EE8, 0x8235F5, 0x2EBB44,
+    0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, 0x845F8B,
+    0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D,
+    0x367ECF, 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
+    0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330,
+    0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, 0x91615E, 0xE61B08,
+    0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA,
+    0x73A8C9, 0x60E27B, 0xC08C6B};
+
+static const double zero = 0.0;
+static const double two24 = 1.6777216e+07;
+static const double one = 1.0;
+static const double twon24 = 5.9604644775390625e-08;
+
+static const double PIo2[] = {
+    1.57079625129699707031e+00,  // 0x3FF921FB, 0x40000000
+    7.54978941586159635335e-08,  // 0x3E74442D, 0x00000000
+    5.39030252995776476554e-15,  // 0x3CF84698, 0x80000000
+    3.28200341580791294123e-22,  // 0x3B78CC51, 0x60000000
+    1.27065575308067607349e-29,  // 0x39F01B83, 0x80000000
+    1.22933308981111328932e-36,  // 0x387A2520, 0x40000000
+    2.73370053816464559624e-44,  // 0x36E38222, 0x80000000
+    2.16741683877804819444e-51   // 0x3569F31D, 0x00000000
+};
+
+
+int __kernel_rem_pio2(double* x, double* y, int e0, int nx) {
+  static const int32_t jk = 3;
+  double fw;
+  int32_t jx = nx - 1;
+  int32_t jv = (e0 - 3) / 24;
+  if (jv < 0) jv = 0;
+  int32_t q0 = e0 - 24 * (jv + 1);
+  int32_t m = jx + jk;
+
+  double f[10];
+  for (int i = 0, j = jv - jx; i <= m; i++, j++) {
+    f[i] = (j < 0) ? zero : static_cast<double>(two_over_pi[j]);
+  }
+
+  double q[10];
+  for (int i = 0; i <= jk; i++) {
+    fw = 0.0;
+    for (int j = 0; j <= jx; j++) fw += x[j] * f[jx + i - j];
+    q[i] = fw;
+  }
+
+  int32_t jz = jk;
+
+recompute:
+
+  int32_t iq[10];
+  double z = q[jz];
+  for (int i = 0, j = jz; j > 0; i++, j--) {
+    fw = static_cast<double>(static_cast<int32_t>(twon24 * z));
+    iq[i] = static_cast<int32_t>(z - two24 * fw);
+    z = q[j - 1] + fw;
+  }
+
+  z = scalbn(z, q0);
+  z -= 8.0 * std::floor(z * 0.125);
+  int32_t n = static_cast<int32_t>(z);
+  z -= static_cast<double>(n);
+  int32_t ih = 0;
+  if (q0 > 0) {
+    int32_t i = (iq[jz - 1] >> (24 - q0));
+    n += i;
+    iq[jz - 1] -= i << (24 - q0);
+    ih = iq[jz - 1] >> (23 - q0);
+  } else if (q0 == 0) {
+    ih = iq[jz - 1] >> 23;
+  } else if (z >= 0.5) {
+    ih = 2;
+  }
+
+  if (ih > 0) {
+    n += 1;
+    int32_t carry = 0;
+    for (int i = 0; i < jz; i++) {
+      int32_t j = iq[i];
+      if (carry == 0) {
+        if (j != 0) {
+          carry = 1;
+          iq[i] = 0x1000000 - j;
+        }
+      } else {
+        iq[i] = 0xffffff - j;
+      }
+    }
+    if (q0 == 1) {
+      iq[jz - 1] &= 0x7fffff;
+    } else if (q0 == 2) {
+      iq[jz - 1] &= 0x3fffff;
+    }
+    if (ih == 2) {
+      z = one - z;
+      if (carry != 0) z -= scalbn(one, q0);
+    }
+  }
+
+  if (z == zero) {
+    int32_t j = 0;
+    for (int i = jz - 1; i >= jk; i--) j |= iq[i];
+    if (j == 0) {
+      int32_t k = 1;
+      while (iq[jk - k] == 0) k++;
+      for (int i = jz + 1; i <= jz + k; i++) {
+        f[jx + i] = static_cast<double>(two_over_pi[jv + i]);
+        for (j = 0, fw = 0.0; j <= jx; j++) fw += x[j] * f[jx + i - j];
+        q[i] = fw;
+      }
+      jz += k;
+      goto recompute;
+    }
+  }
+
+  if (z == 0.0) {
+    jz -= 1;
+    q0 -= 24;
+    while (iq[jz] == 0) {
+      jz--;
+      q0 -= 24;
+    }
+  } else {
+    z = scalbn(z, -q0);
+    if (z >= two24) {
+      fw = static_cast<double>(static_cast<int32_t>(twon24 * z));
+      iq[jz] = static_cast<int32_t>(z - two24 * fw);
+      jz += 1;
+      q0 += 24;
+      iq[jz] = static_cast<int32_t>(fw);
+    } else {
+      iq[jz] = static_cast<int32_t>(z);
+    }
+  }
+
+  fw = scalbn(one, q0);
+  for (int i = jz; i >= 0; i--) {
+    q[i] = fw * static_cast<double>(iq[i]);
+    fw *= twon24;
+  }
+
+  double fq[10];
+  for (int i = jz; i >= 0; i--) {
+    fw = 0.0;
+    for (int k = 0; k <= jk && k <= jz - i; k++) fw += PIo2[k] * q[i + k];
+    fq[jz - i] = fw;
+  }
+
+  fw = 0.0;
+  for (int i = jz; i >= 0; i--) fw += fq[i];
+  y[0] = (ih == 0) ? fw : -fw;
+  fw = fq[0] - fw;
+  for (int i = 1; i <= jz; i++) fw += fq[i];
+  y[1] = (ih == 0) ? fw : -fw;
+  return n & 7;
+}
+
+
+int rempio2(double x, double* y) {
+  int32_t hx = static_cast<int32_t>(internal::double_to_uint64(x) >> 32);
+  int32_t ix = hx & 0x7fffffff;
+
+  if (ix >= 0x7ff00000) {
+    *y = base::OS::nan_value();
+    return 0;
+  }
+
+  int32_t e0 = (ix >> 20) - 1046;
+  uint64_t zi = internal::double_to_uint64(x) & 0xFFFFFFFFu;
+  zi |= static_cast<uint64_t>(ix - (e0 << 20)) << 32;
+  double z = internal::uint64_to_double(zi);
+
+  double tx[3];
+  for (int i = 0; i < 2; i++) {
+    tx[i] = static_cast<double>(static_cast<int32_t>(z));
+    z = (z - tx[i]) * two24;
+  }
+  tx[2] = z;
+
+  int nx = 3;
+  while (tx[nx - 1] == zero) nx--;
+  int n = __kernel_rem_pio2(tx, y, e0, nx);
+  if (hx < 0) {
+    y[0] = -y[0];
+    y[1] = -y[1];
+    return -n;
+  }
+  return n;
+}
+}
+}  // namespace v8::internal
diff --git a/src/third_party/fdlibm/fdlibm.h b/src/third_party/fdlibm/fdlibm.h
new file mode 100644
index 0000000..c7bc09a
--- /dev/null
+++ b/src/third_party/fdlibm/fdlibm.h
@@ -0,0 +1,31 @@
+// The following is adapted from fdlibm (http://www.netlib.org/fdlibm).
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunSoft, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2014 the V8 project authors. All rights reserved.
+
+#ifndef V8_FDLIBM_H_
+#define V8_FDLIBM_H_
+
+namespace v8 {
+namespace fdlibm {
+
+int rempio2(double x, double* y);
+
+// Constants to be exposed to builtins via Float64Array.
+struct MathConstants {
+  static const double constants[66];
+};
+}
+}  // namespace v8::internal
+
+#endif  // V8_FDLIBM_H_
diff --git a/src/third_party/fdlibm/fdlibm.js b/src/third_party/fdlibm/fdlibm.js
new file mode 100644
index 0000000..ceeacc5
--- /dev/null
+++ b/src/third_party/fdlibm/fdlibm.js
@@ -0,0 +1,996 @@
+// The following is adapted from fdlibm (http://www.netlib.org/fdlibm),
+//
+// ====================================================
+// Copyright (C) 1993-2004 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunSoft, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2014 the V8 project authors. All rights reserved.
+//
+// The following is a straightforward translation of fdlibm routines
+// by Raymond Toy (rtoy@google.com).
+
+// Double constants that do not have empty lower 32 bits are found in fdlibm.cc
+// and exposed through kMath as typed array. We assume the compiler to convert
+// from decimal to binary accurately enough to produce the intended values.
+// kMath is initialized to a Float64Array during genesis and not writable.
+
+"use strict";
+
+var kMath;
+
+const INVPIO2 = kMath[0];
+const PIO2_1  = kMath[1];
+const PIO2_1T = kMath[2];
+const PIO2_2  = kMath[3];
+const PIO2_2T = kMath[4];
+const PIO2_3  = kMath[5];
+const PIO2_3T = kMath[6];
+const PIO4    = kMath[32];
+const PIO4LO  = kMath[33];
+
+// Compute k and r such that x - k*pi/2 = r where |r| < pi/4. For
+// precision, r is returned as two values y0 and y1 such that r = y0 + y1
+// to more than double precision.
+macro REMPIO2(X)
+  var n, y0, y1;
+  var hx = %_DoubleHi(X);
+  var ix = hx & 0x7fffffff;
+
+  if (ix < 0x4002d97c) {
+    // |X| ~< 3*pi/4, special case with n = +/- 1
+    if (hx > 0) {
+      var z = X - PIO2_1;
+      if (ix != 0x3ff921fb) {
+        // 33+53 bit pi is good enough
+        y0 = z - PIO2_1T;
+        y1 = (z - y0) - PIO2_1T;
+      } else {
+        // near pi/2, use 33+33+53 bit pi
+        z -= PIO2_2;
+        y0 = z - PIO2_2T;
+        y1 = (z - y0) - PIO2_2T;
+      }
+      n = 1;
+    } else {
+      // Negative X
+      var z = X + PIO2_1;
+      if (ix != 0x3ff921fb) {
+        // 33+53 bit pi is good enough
+        y0 = z + PIO2_1T;
+        y1 = (z - y0) + PIO2_1T;
+      } else {
+        // near pi/2, use 33+33+53 bit pi
+        z += PIO2_2;
+        y0 = z + PIO2_2T;
+        y1 = (z - y0) + PIO2_2T;
+      }
+      n = -1;
+    }
+  } else if (ix <= 0x413921fb) {
+    // |X| ~<= 2^19*(pi/2), medium size
+    var t = MathAbs(X);
+    n = (t * INVPIO2 + 0.5) | 0;
+    var r = t - n * PIO2_1;
+    var w = n * PIO2_1T;
+    // First round good to 85 bit
+    y0 = r - w;
+    if (ix - (%_DoubleHi(y0) & 0x7ff00000) > 0x1000000) {
+      // 2nd iteration needed, good to 118
+      t = r;
+      w = n * PIO2_2;
+      r = t - w;
+      w = n * PIO2_2T - ((t - r) - w);
+      y0 = r - w;
+      if (ix - (%_DoubleHi(y0) & 0x7ff00000) > 0x3100000) {
+        // 3rd iteration needed. 151 bits accuracy
+        t = r;
+        w = n * PIO2_3;
+        r = t - w;
+        w = n * PIO2_3T - ((t - r) - w);
+        y0 = r - w;
+      }
+    }
+    y1 = (r - y0) - w;
+    if (hx < 0) {
+      n = -n;
+      y0 = -y0;
+      y1 = -y1;
+    }
+  } else {
+    // Need to do full Payne-Hanek reduction here.
+    var r = %RemPiO2(X);
+    n = r[0];
+    y0 = r[1];
+    y1 = r[2];
+  }
+endmacro
+
+
+// __kernel_sin(X, Y, IY)
+// kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854
+// Input X is assumed to be bounded by ~pi/4 in magnitude.
+// Input Y is the tail of X so that x = X + Y.
+//
+// Algorithm
+//  1. Since ieee_sin(-x) = -ieee_sin(x), we need only to consider positive x.
+//  2. ieee_sin(x) is approximated by a polynomial of degree 13 on
+//     [0,pi/4]
+//                           3            13
+//          sin(x) ~ x + S1*x + ... + S6*x
+//     where
+//
+//    |ieee_sin(x)    2     4     6     8     10     12  |     -58
+//    |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x  +S6*x   )| <= 2
+//    |  x                                               |
+//
+//  3. ieee_sin(X+Y) = ieee_sin(X) + sin'(X')*Y
+//              ~ ieee_sin(X) + (1-X*X/2)*Y
+//     For better accuracy, let
+//               3      2      2      2      2
+//          r = X *(S2+X *(S3+X *(S4+X *(S5+X *S6))))
+//     then                   3    2
+//          sin(x) = X + (S1*X + (X *(r-Y/2)+Y))
+//
+macro KSIN(x)
+kMath[7+x]
+endmacro
+
+macro RETURN_KERNELSIN(X, Y, SIGN)
+  var z = X * X;
+  var v = z * X;
+  var r = KSIN(1) + z * (KSIN(2) + z * (KSIN(3) +
+                    z * (KSIN(4) + z * KSIN(5))));
+  return (X - ((z * (0.5 * Y - v * r) - Y) - v * KSIN(0))) SIGN;
+endmacro
+
+// __kernel_cos(X, Y)
+// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
+// Input X is assumed to be bounded by ~pi/4 in magnitude.
+// Input Y is the tail of X so that x = X + Y.
+//
+// Algorithm
+//  1. Since ieee_cos(-x) = ieee_cos(x), we need only to consider positive x.
+//  2. ieee_cos(x) is approximated by a polynomial of degree 14 on
+//     [0,pi/4]
+//                                   4            14
+//          cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
+//     where the remez error is
+//
+//  |                   2     4     6     8     10    12     14 |     -58
+//  |ieee_cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  )| <= 2
+//  |                                                           |
+//
+//                 4     6     8     10    12     14
+//  3. let r = C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  , then
+//         ieee_cos(x) = 1 - x*x/2 + r
+//     since ieee_cos(X+Y) ~ ieee_cos(X) - ieee_sin(X)*Y
+//                    ~ ieee_cos(X) - X*Y,
+//     a correction term is necessary in ieee_cos(x) and hence
+//         cos(X+Y) = 1 - (X*X/2 - (r - X*Y))
+//     For better accuracy when x > 0.3, let qx = |x|/4 with
+//     the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125.
+//     Then
+//         cos(X+Y) = (1-qx) - ((X*X/2-qx) - (r-X*Y)).
+//     Note that 1-qx and (X*X/2-qx) is EXACT here, and the
+//     magnitude of the latter is at least a quarter of X*X/2,
+//     thus, reducing the rounding error in the subtraction.
+//
+macro KCOS(x)
+kMath[13+x]
+endmacro
+
+macro RETURN_KERNELCOS(X, Y, SIGN)
+  var ix = %_DoubleHi(X) & 0x7fffffff;
+  var z = X * X;
+  var r = z * (KCOS(0) + z * (KCOS(1) + z * (KCOS(2)+
+          z * (KCOS(3) + z * (KCOS(4) + z * KCOS(5))))));
+  if (ix < 0x3fd33333) {  // |x| ~< 0.3
+    return (1 - (0.5 * z - (z * r - X * Y))) SIGN;
+  } else {
+    var qx;
+    if (ix > 0x3fe90000) {  // |x| > 0.78125
+      qx = 0.28125;
+    } else {
+      qx = %_ConstructDouble(%_DoubleHi(0.25 * X), 0);
+    }
+    var hz = 0.5 * z - qx;
+    return (1 - qx - (hz - (z * r - X * Y))) SIGN;
+  }
+endmacro
+
+
+// kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854
+// Input x is assumed to be bounded by ~pi/4 in magnitude.
+// Input y is the tail of x.
+// Input k indicates whether ieee_tan (if k = 1) or -1/tan (if k = -1)
+// is returned.
+//
+// Algorithm
+//  1. Since ieee_tan(-x) = -ieee_tan(x), we need only to consider positive x.
+//  2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0.
+//  3. ieee_tan(x) is approximated by a odd polynomial of degree 27 on
+//     [0,0.67434]
+//                           3             27
+//          tan(x) ~ x + T1*x + ... + T13*x
+//     where
+//
+//     |ieee_tan(x)    2     4            26   |     -59.2
+//     |----- - (1+T1*x +T2*x +.... +T13*x    )| <= 2
+//     |  x                                    |
+//
+//     Note: ieee_tan(x+y) = ieee_tan(x) + tan'(x)*y
+//                    ~ ieee_tan(x) + (1+x*x)*y
+//     Therefore, for better accuracy in computing ieee_tan(x+y), let
+//               3      2      2       2       2
+//          r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
+//     then
+//                              3    2
+//          tan(x+y) = x + (T1*x + (x *(r+y)+y))
+//
+//  4. For x in [0.67434,pi/4],  let y = pi/4 - x, then
+//          tan(x) = ieee_tan(pi/4-y) = (1-ieee_tan(y))/(1+ieee_tan(y))
+//                 = 1 - 2*(ieee_tan(y) - (ieee_tan(y)^2)/(1+ieee_tan(y)))
+//
+// Set returnTan to 1 for tan; -1 for cot.  Anything else is illegal
+// and will cause incorrect results.
+//
+macro KTAN(x)
+kMath[19+x]
+endmacro
+
+function KernelTan(x, y, returnTan) {
+  var z;
+  var w;
+  var hx = %_DoubleHi(x);
+  var ix = hx & 0x7fffffff;
+
+  if (ix < 0x3e300000) {  // |x| < 2^-28
+    if (((ix | %_DoubleLo(x)) | (returnTan + 1)) == 0) {
+      // x == 0 && returnTan = -1
+      return 1 / MathAbs(x);
+    } else {
+      if (returnTan == 1) {
+        return x;
+      } else {
+        // Compute -1/(x + y) carefully
+        var w = x + y;
+        var z = %_ConstructDouble(%_DoubleHi(w), 0);
+        var v = y - (z - x);
+        var a = -1 / w;
+        var t = %_ConstructDouble(%_DoubleHi(a), 0);
+        var s = 1 + t * z;
+        return t + a * (s + t * v);
+      }
+    }
+  }
+  if (ix >= 0x3fe59428) {  // |x| > .6744
+    if (x < 0) {
+      x = -x;
+      y = -y;
+    }
+    z = PIO4 - x;
+    w = PIO4LO - y;
+    x = z + w;
+    y = 0;
+  }
+  z = x * x;
+  w = z * z;
+
+  // Break x^5 * (T1 + x^2*T2 + ...) into
+  // x^5 * (T1 + x^4*T3 + ... + x^20*T11) +
+  // x^5 * (x^2 * (T2 + x^4*T4 + ... + x^22*T12))
+  var r = KTAN(1) + w * (KTAN(3) + w * (KTAN(5) +
+                    w * (KTAN(7) + w * (KTAN(9) + w * KTAN(11)))));
+  var v = z * (KTAN(2) + w * (KTAN(4) + w * (KTAN(6) +
+                         w * (KTAN(8) + w * (KTAN(10) + w * KTAN(12))))));
+  var s = z * x;
+  r = y + z * (s * (r + v) + y);
+  r = r + KTAN(0) * s;
+  w = x + r;
+  if (ix >= 0x3fe59428) {
+    return (1 - ((hx >> 30) & 2)) *
+      (returnTan - 2.0 * (x - (w * w / (w + returnTan) - r)));
+  }
+  if (returnTan == 1) {
+    return w;
+  } else {
+    z = %_ConstructDouble(%_DoubleHi(w), 0);
+    v = r - (z - x);
+    var a = -1 / w;
+    var t = %_ConstructDouble(%_DoubleHi(a), 0);
+    s = 1 + t * z;
+    return t + a * (s + t * v);
+  }
+}
+
+function MathSinSlow(x) {
+  REMPIO2(x);
+  var sign = 1 - (n & 2);
+  if (n & 1) {
+    RETURN_KERNELCOS(y0, y1, * sign);
+  } else {
+    RETURN_KERNELSIN(y0, y1, * sign);
+  }
+}
+
+function MathCosSlow(x) {
+  REMPIO2(x);
+  if (n & 1) {
+    var sign = (n & 2) - 1;
+    RETURN_KERNELSIN(y0, y1, * sign);
+  } else {
+    var sign = 1 - (n & 2);
+    RETURN_KERNELCOS(y0, y1, * sign);
+  }
+}
+
+// ECMA 262 - 15.8.2.16
+function MathSin(x) {
+  x = x * 1;  // Convert to number.
+  if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
+    // |x| < pi/4, approximately.  No reduction needed.
+    RETURN_KERNELSIN(x, 0, /* empty */);
+  }
+  return MathSinSlow(x);
+}
+
+// ECMA 262 - 15.8.2.7
+function MathCos(x) {
+  x = x * 1;  // Convert to number.
+  if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
+    // |x| < pi/4, approximately.  No reduction needed.
+    RETURN_KERNELCOS(x, 0, /* empty */);
+  }
+  return MathCosSlow(x);
+}
+
+// ECMA 262 - 15.8.2.18
+function MathTan(x) {
+  x = x * 1;  // Convert to number.
+  if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
+    // |x| < pi/4, approximately.  No reduction needed.
+    return KernelTan(x, 0, 1);
+  }
+  REMPIO2(x);
+  return KernelTan(y0, y1, (n & 1) ? -1 : 1);
+}
+
+// ES6 draft 09-27-13, section 20.2.2.20.
+// Math.log1p
+//
+// Method :                  
+//   1. Argument Reduction: find k and f such that 
+//                      1+x = 2^k * (1+f), 
+//         where  sqrt(2)/2 < 1+f < sqrt(2) .
+//
+//      Note. If k=0, then f=x is exact. However, if k!=0, then f
+//      may not be representable exactly. In that case, a correction
+//      term is need. Let u=1+x rounded. Let c = (1+x)-u, then
+//      log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
+//      and add back the correction term c/u.
+//      (Note: when x > 2**53, one can simply return log(x))
+//
+//   2. Approximation of log1p(f).
+//      Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+//            = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+//            = 2s + s*R
+//      We use a special Reme algorithm on [0,0.1716] to generate 
+//      a polynomial of degree 14 to approximate R The maximum error 
+//      of this polynomial approximation is bounded by 2**-58.45. In
+//      other words,
+//                      2      4      6      8      10      12      14
+//          R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s  +Lp6*s  +Lp7*s
+//      (the values of Lp1 to Lp7 are listed in the program)
+//      and
+//          |      2          14          |     -58.45
+//          | Lp1*s +...+Lp7*s    -  R(z) | <= 2 
+//          |                             |
+//      Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+//      In order to guarantee error in log below 1ulp, we compute log
+//      by
+//              log1p(f) = f - (hfsq - s*(hfsq+R)).
+//
+//      3. Finally, log1p(x) = k*ln2 + log1p(f).  
+//                           = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+//         Here ln2 is split into two floating point number: 
+//                      ln2_hi + ln2_lo,
+//         where n*ln2_hi is always exact for |n| < 2000.
+//
+// Special cases:
+//      log1p(x) is NaN with signal if x < -1 (including -INF) ; 
+//      log1p(+INF) is +INF; log1p(-1) is -INF with signal;
+//      log1p(NaN) is that NaN with no signal.
+//
+// Accuracy:
+//      according to an error analysis, the error is always less than
+//      1 ulp (unit in the last place).
+//
+// Constants:
+//      Constants are found in fdlibm.cc. We assume the C++ compiler to convert
+//      from decimal to binary accurately enough to produce the intended values.
+//
+// Note: Assuming log() return accurate answer, the following
+//       algorithm can be used to compute log1p(x) to within a few ULP:
+//
+//              u = 1+x;
+//              if (u==1.0) return x ; else
+//                          return log(u)*(x/(u-1.0));
+//
+//       See HP-15C Advanced Functions Handbook, p.193.
+//
+const LN2_HI    = kMath[34];
+const LN2_LO    = kMath[35];
+const TWO_THIRD = kMath[36];
+macro KLOG1P(x)
+(kMath[37+x])
+endmacro
+// 2^54
+const TWO54 = 18014398509481984;
+
+function MathLog1p(x) {
+  x = x * 1;  // Convert to number.
+  var hx = %_DoubleHi(x);
+  var ax = hx & 0x7fffffff;
+  var k = 1;
+  var f = x;
+  var hu = 1;
+  var c = 0;
+  var u = x;
+
+  if (hx < 0x3fda827a) {
+    // x < 0.41422
+    if (ax >= 0x3ff00000) {  // |x| >= 1
+      if (x === -1) {
+        return -INFINITY;  // log1p(-1) = -inf
+      } else {
+        return NAN;  // log1p(x<-1) = NaN
+      }
+    } else if (ax < 0x3c900000)  {
+      // For |x| < 2^-54 we can return x.
+      return x;
+    } else if (ax < 0x3e200000) {
+      // For |x| < 2^-29 we can use a simple two-term Taylor series.
+      return x - x * x * 0.5;
+    }
+
+    if ((hx > 0) || (hx <= -0x402D413D)) {  // (int) 0xbfd2bec3 = -0x402d413d
+      // -.2929 < x < 0.41422
+      k = 0;
+    }
+  }
+
+  // Handle Infinity and NAN
+  if (hx >= 0x7ff00000) return x;
+
+  if (k !== 0) {
+    if (hx < 0x43400000) {
+      // x < 2^53
+      u = 1 + x;
+      hu = %_DoubleHi(u);
+      k = (hu >> 20) - 1023;
+      c = (k > 0) ? 1 - (u - x) : x - (u - 1);
+      c = c / u;
+    } else {
+      hu = %_DoubleHi(u);
+      k = (hu >> 20) - 1023;
+    }
+    hu = hu & 0xfffff;
+    if (hu < 0x6a09e) {
+      u = %_ConstructDouble(hu | 0x3ff00000, %_DoubleLo(u));  // Normalize u.
+    } else {
+      ++k;
+      u = %_ConstructDouble(hu | 0x3fe00000, %_DoubleLo(u));  // Normalize u/2.
+      hu = (0x00100000 - hu) >> 2;
+    }
+    f = u - 1;
+  }
+
+  var hfsq = 0.5 * f * f;
+  if (hu === 0) {
+    // |f| < 2^-20;
+    if (f === 0) {
+      if (k === 0) {
+        return 0.0;
+      } else {
+        return k * LN2_HI + (c + k * LN2_LO);
+      }
+    }
+    var R = hfsq * (1 - TWO_THIRD * f);
+    if (k === 0) {
+      return f - R;
+    } else {
+      return k * LN2_HI - ((R - (k * LN2_LO + c)) - f);
+    }
+  }
+
+  var s = f / (2 + f); 
+  var z = s * s;
+  var R = z * (KLOG1P(0) + z * (KLOG1P(1) + z *
+              (KLOG1P(2) + z * (KLOG1P(3) + z *
+              (KLOG1P(4) + z * (KLOG1P(5) + z * KLOG1P(6)))))));
+  if (k === 0) {
+    return f - (hfsq - s * (hfsq + R));
+  } else {
+    return k * LN2_HI - ((hfsq - (s * (hfsq + R) + (k * LN2_LO + c))) - f);
+  }
+}
+
+// ES6 draft 09-27-13, section 20.2.2.14.
+// Math.expm1
+// Returns exp(x)-1, the exponential of x minus 1.
+//
+// Method
+//   1. Argument reduction:
+//      Given x, find r and integer k such that
+//
+//               x = k*ln2 + r,  |r| <= 0.5*ln2 ~ 0.34658  
+//
+//      Here a correction term c will be computed to compensate 
+//      the error in r when rounded to a floating-point number.
+//
+//   2. Approximating expm1(r) by a special rational function on
+//      the interval [0,0.34658]:
+//      Since
+//          r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
+//      we define R1(r*r) by
+//          r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
+//      That is,
+//          R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
+//                   = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
+//                   = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
+//      We use a special Remes algorithm on [0,0.347] to generate 
+//      a polynomial of degree 5 in r*r to approximate R1. The 
+//      maximum error of this polynomial approximation is bounded 
+//      by 2**-61. In other words,
+//          R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
+//      where   Q1  =  -1.6666666666666567384E-2,
+//              Q2  =   3.9682539681370365873E-4,
+//              Q3  =  -9.9206344733435987357E-6,
+//              Q4  =   2.5051361420808517002E-7,
+//              Q5  =  -6.2843505682382617102E-9;
+//      (where z=r*r, and the values of Q1 to Q5 are listed below)
+//      with error bounded by
+//          |                  5           |     -61
+//          | 1.0+Q1*z+...+Q5*z   -  R1(z) | <= 2 
+//          |                              |
+//
+//      expm1(r) = exp(r)-1 is then computed by the following 
+//      specific way which minimize the accumulation rounding error: 
+//                             2     3
+//                            r     r    [ 3 - (R1 + R1*r/2)  ]
+//            expm1(r) = r + --- + --- * [--------------------]
+//                            2     2    [ 6 - r*(3 - R1*r/2) ]
+//
+//      To compensate the error in the argument reduction, we use
+//              expm1(r+c) = expm1(r) + c + expm1(r)*c 
+//                         ~ expm1(r) + c + r*c 
+//      Thus c+r*c will be added in as the correction terms for
+//      expm1(r+c). Now rearrange the term to avoid optimization 
+//      screw up:
+//                      (      2                                    2 )
+//                      ({  ( r    [ R1 -  (3 - R1*r/2) ]  )  }    r  )
+//       expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
+//                      ({  ( 2    [ 6 - r*(3 - R1*r/2) ]  )  }    2  )
+//                      (                                             )
+//
+//                 = r - E
+//   3. Scale back to obtain expm1(x):
+//      From step 1, we have
+//         expm1(x) = either 2^k*[expm1(r)+1] - 1
+//                  = or     2^k*[expm1(r) + (1-2^-k)]
+//   4. Implementation notes:
+//      (A). To save one multiplication, we scale the coefficient Qi
+//           to Qi*2^i, and replace z by (x^2)/2.
+//      (B). To achieve maximum accuracy, we compute expm1(x) by
+//        (i)   if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
+//        (ii)  if k=0, return r-E
+//        (iii) if k=-1, return 0.5*(r-E)-0.5
+//        (iv)  if k=1 if r < -0.25, return 2*((r+0.5)- E)
+//                     else          return  1.0+2.0*(r-E);
+//        (v)   if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
+//        (vi)  if k <= 20, return 2^k((1-2^-k)-(E-r)), else
+//        (vii) return 2^k(1-((E+2^-k)-r)) 
+//
+// Special cases:
+//      expm1(INF) is INF, expm1(NaN) is NaN;
+//      expm1(-INF) is -1, and
+//      for finite argument, only expm1(0)=0 is exact.
+//
+// Accuracy:
+//      according to an error analysis, the error is always less than
+//      1 ulp (unit in the last place).
+//
+// Misc. info.
+//      For IEEE double 
+//          if x > 7.09782712893383973096e+02 then expm1(x) overflow
+//
+const KEXPM1_OVERFLOW = kMath[44];
+const INVLN2          = kMath[45];
+macro KEXPM1(x)
+(kMath[46+x])
+endmacro
+
+function MathExpm1(x) {
+  x = x * 1;  // Convert to number.
+  var y;
+  var hi;
+  var lo;
+  var k;
+  var t;
+  var c;
+    
+  var hx = %_DoubleHi(x);
+  var xsb = hx & 0x80000000;     // Sign bit of x
+  var y = (xsb === 0) ? x : -x;  // y = |x|
+  hx &= 0x7fffffff;              // High word of |x|
+
+  // Filter out huge and non-finite argument
+  if (hx >= 0x4043687a) {     // if |x| ~=> 56 * ln2
+    if (hx >= 0x40862e42) {   // if |x| >= 709.78
+      if (hx >= 0x7ff00000) {
+        // expm1(inf) = inf; expm1(-inf) = -1; expm1(nan) = nan;
+        return (x === -INFINITY) ? -1 : x;
+      }
+      if (x > KEXPM1_OVERFLOW) return INFINITY;  // Overflow
+    }
+    if (xsb != 0) return -1;  // x < -56 * ln2, return -1.
+  }
+
+  // Argument reduction
+  if (hx > 0x3fd62e42) {    // if |x| > 0.5 * ln2
+    if (hx < 0x3ff0a2b2) {  // and |x| < 1.5 * ln2
+      if (xsb === 0) {
+        hi = x - LN2_HI;
+        lo = LN2_LO;
+        k = 1;
+      } else {
+        hi = x + LN2_HI;
+        lo = -LN2_LO;
+        k = -1;
+      }
+    } else {
+      k = (INVLN2 * x + ((xsb === 0) ? 0.5 : -0.5)) | 0;
+      t = k;
+      // t * ln2_hi is exact here.
+      hi = x - t * LN2_HI;
+      lo = t * LN2_LO;
+    }
+    x = hi - lo;
+    c = (hi - x) - lo;
+  } else if (hx < 0x3c900000)	{
+    // When |x| < 2^-54, we can return x.
+    return x;
+  } else {
+    // Fall through.
+    k = 0;
+  }
+
+  // x is now in primary range
+  var hfx = 0.5 * x;
+  var hxs = x * hfx;
+  var r1 = 1 + hxs * (KEXPM1(0) + hxs * (KEXPM1(1) + hxs *
+                     (KEXPM1(2) + hxs * (KEXPM1(3) + hxs * KEXPM1(4)))));
+  t = 3 - r1 * hfx;
+  var e = hxs * ((r1 - t) / (6 - x * t));
+  if (k === 0) {  // c is 0
+    return x - (x*e - hxs);
+  } else {
+    e = (x * (e - c) - c);
+    e -= hxs;
+    if (k === -1) return 0.5 * (x - e) - 0.5;
+    if (k === 1) {
+      if (x < -0.25) return -2 * (e - (x + 0.5));
+      return 1 + 2 * (x - e);
+    }
+
+    if (k <= -2 || k > 56) {
+      // suffice to return exp(x) + 1
+      y = 1 - (e - x);
+      // Add k to y's exponent
+      y = %_ConstructDouble(%_DoubleHi(y) + (k << 20), %_DoubleLo(y));
+      return y - 1;
+    }
+    if (k < 20) {
+      // t = 1 - 2^k
+      t = %_ConstructDouble(0x3ff00000 - (0x200000 >> k), 0);
+      y = t - (e - x);
+      // Add k to y's exponent
+      y = %_ConstructDouble(%_DoubleHi(y) + (k << 20), %_DoubleLo(y));
+    } else {
+      // t = 2^-k
+      t = %_ConstructDouble((0x3ff - k) << 20, 0);
+      y = x - (e + t);
+      y += 1;
+      // Add k to y's exponent
+      y = %_ConstructDouble(%_DoubleHi(y) + (k << 20), %_DoubleLo(y));
+    }
+  }
+  return y;
+}
+
+
+// ES6 draft 09-27-13, section 20.2.2.30.
+// Math.sinh
+// Method :
+// mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
+//      1. Replace x by |x| (sinh(-x) = -sinh(x)).
+//      2.
+//                                                  E + E/(E+1)
+//          0        <= x <= 22     :  sinh(x) := --------------, E=expm1(x)
+//                                                      2
+//
+//          22       <= x <= lnovft :  sinh(x) := exp(x)/2 
+//          lnovft   <= x <= ln2ovft:  sinh(x) := exp(x/2)/2 * exp(x/2)
+//          ln2ovft  <  x           :  sinh(x) := x*shuge (overflow)
+//
+// Special cases:
+//      sinh(x) is |x| if x is +Infinity, -Infinity, or NaN.
+//      only sinh(0)=0 is exact for finite x.
+//
+const KSINH_OVERFLOW = kMath[51];
+const TWO_M28 = 3.725290298461914e-9;  // 2^-28, empty lower half
+const LOG_MAXD = 709.7822265625;  // 0x40862e42 00000000, empty lower half
+
+function MathSinh(x) {
+  x = x * 1;  // Convert to number.
+  var h = (x < 0) ? -0.5 : 0.5;
+  // |x| in [0, 22]. return sign(x)*0.5*(E+E/(E+1))
+  var ax = MathAbs(x);
+  if (ax < 22) {
+    // For |x| < 2^-28, sinh(x) = x
+    if (ax < TWO_M28) return x;
+    var t = MathExpm1(ax);
+    if (ax < 1) return h * (2 * t - t * t / (t + 1));
+    return h * (t + t / (t + 1));
+  }
+  // |x| in [22, log(maxdouble)], return 0.5 * exp(|x|)
+  if (ax < LOG_MAXD) return h * MathExp(ax);
+  // |x| in [log(maxdouble), overflowthreshold]
+  // overflowthreshold = 710.4758600739426
+  if (ax <= KSINH_OVERFLOW) {
+    var w = MathExp(0.5 * ax);
+    var t = h * w;
+    return t * w;
+  }
+  // |x| > overflowthreshold or is NaN.
+  // Return Infinity of the appropriate sign or NaN.
+  return x * INFINITY;
+}
+
+
+// ES6 draft 09-27-13, section 20.2.2.12.
+// Math.cosh
+// Method : 
+// mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
+//      1. Replace x by |x| (cosh(x) = cosh(-x)). 
+//      2.
+//                                                      [ exp(x) - 1 ]^2 
+//          0        <= x <= ln2/2  :  cosh(x) := 1 + -------------------
+//                                                         2*exp(x)
+//
+//                                                 exp(x) + 1/exp(x)
+//          ln2/2    <= x <= 22     :  cosh(x) := -------------------
+//                                                        2
+//          22       <= x <= lnovft :  cosh(x) := exp(x)/2 
+//          lnovft   <= x <= ln2ovft:  cosh(x) := exp(x/2)/2 * exp(x/2)
+//          ln2ovft  <  x           :  cosh(x) := huge*huge (overflow)
+//
+// Special cases:
+//      cosh(x) is |x| if x is +INF, -INF, or NaN.
+//      only cosh(0)=1 is exact for finite x.
+//
+const KCOSH_OVERFLOW = kMath[51];
+
+function MathCosh(x) {
+  x = x * 1;  // Convert to number.
+  var ix = %_DoubleHi(x) & 0x7fffffff;
+  // |x| in [0,0.5*log2], return 1+expm1(|x|)^2/(2*exp(|x|))
+  if (ix < 0x3fd62e43) {
+    var t = MathExpm1(MathAbs(x));
+    var w = 1 + t;
+    // For |x| < 2^-55, cosh(x) = 1
+    if (ix < 0x3c800000) return w;
+    return 1 + (t * t) / (w + w);
+  }
+  // |x| in [0.5*log2, 22], return (exp(|x|)+1/exp(|x|)/2
+  if (ix < 0x40360000) {
+    var t = MathExp(MathAbs(x));
+    return 0.5 * t + 0.5 / t;
+  }
+  // |x| in [22, log(maxdouble)], return half*exp(|x|)
+  if (ix < 0x40862e42) return 0.5 * MathExp(MathAbs(x));
+  // |x| in [log(maxdouble), overflowthreshold]
+  if (MathAbs(x) <= KCOSH_OVERFLOW) {
+    var w = MathExp(0.5 * MathAbs(x));
+    var t = 0.5 * w;
+    return t * w;
+  }
+  if (NUMBER_IS_NAN(x)) return x;
+  // |x| > overflowthreshold.
+  return INFINITY;
+}
+
+// ES6 draft 09-27-13, section 20.2.2.21.
+// Return the base 10 logarithm of x
+//
+// Method :
+//      Let log10_2hi = leading 40 bits of log10(2) and
+//          log10_2lo = log10(2) - log10_2hi,
+//          ivln10   = 1/log(10) rounded.
+//      Then
+//              n = ilogb(x),
+//              if(n<0)  n = n+1;
+//              x = scalbn(x,-n);
+//              log10(x) := n*log10_2hi + (n*log10_2lo + ivln10*log(x))
+//
+// Note 1:
+//      To guarantee log10(10**n)=n, where 10**n is normal, the rounding
+//      mode must set to Round-to-Nearest.
+// Note 2:
+//      [1/log(10)] rounded to 53 bits has error .198 ulps;
+//      log10 is monotonic at all binary break points.
+//
+// Special cases:
+//      log10(x) is NaN if x < 0;
+//      log10(+INF) is +INF; log10(0) is -INF;
+//      log10(NaN) is that NaN;
+//      log10(10**N) = N  for N=0,1,...,22.
+//
+
+const IVLN10 = kMath[52];
+const LOG10_2HI = kMath[53];
+const LOG10_2LO = kMath[54];
+
+function MathLog10(x) {
+  x = x * 1;  // Convert to number.
+  var hx = %_DoubleHi(x);
+  var lx = %_DoubleLo(x);
+  var k = 0;
+
+  if (hx < 0x00100000) {
+    // x < 2^-1022
+    // log10(+/- 0) = -Infinity.
+    if (((hx & 0x7fffffff) | lx) === 0) return -INFINITY;
+    // log10 of negative number is NaN.
+    if (hx < 0) return NAN;
+    // Subnormal number. Scale up x.
+    k -= 54;
+    x *= TWO54;
+    hx = %_DoubleHi(x);
+    lx = %_DoubleLo(x);
+  }
+
+  // Infinity or NaN.
+  if (hx >= 0x7ff00000) return x;
+
+  k += (hx >> 20) - 1023;
+  i = (k & 0x80000000) >> 31;
+  hx = (hx & 0x000fffff) | ((0x3ff - i) << 20);
+  y = k + i;
+  x = %_ConstructDouble(hx, lx);
+
+  z = y * LOG10_2LO + IVLN10 * MathLog(x);
+  return z + y * LOG10_2HI;
+}
+
+
+// ES6 draft 09-27-13, section 20.2.2.22.
+// Return the base 2 logarithm of x
+//
+// fdlibm does not have an explicit log2 function, but fdlibm's pow
+// function does implement an accurate log2 function as part of the
+// pow implementation.  This extracts the core parts of that as a
+// separate log2 function.
+
+// Method:
+// Compute log2(x) in two pieces:
+// log2(x) = w1 + w2
+// where w1 has 53-24 = 29 bits of trailing zeroes.
+
+const DP_H = kMath[64];
+const DP_L = kMath[65];
+
+// Polynomial coefficients for (3/2)*(log2(x) - 2*s - 2/3*s^3)
+macro KLOG2(x)
+(kMath[55+x])
+endmacro
+
+// cp = 2/(3*ln(2)). Note that cp_h + cp_l is cp, but with more accuracy.
+const CP = kMath[61];
+const CP_H = kMath[62];
+const CP_L = kMath[63];
+// 2^53
+const TWO53 = 9007199254740992; 
+
+function MathLog2(x) {
+  x = x * 1;  // Convert to number.
+  var ax = MathAbs(x);
+  var hx = %_DoubleHi(x);
+  var lx = %_DoubleLo(x);
+  var ix = hx & 0x7fffffff;
+
+  // Handle special cases.
+  // log2(+/- 0) = -Infinity
+  if ((ix | lx) == 0) return -INFINITY;
+
+  // log(x) = NaN, if x < 0
+  if (hx < 0) return NAN;
+
+  // log2(Infinity) = Infinity, log2(NaN) = NaN
+  if (ix >= 0x7ff00000) return x;
+
+  var n = 0;
+
+  // Take care of subnormal number.
+  if (ix < 0x00100000) {
+    ax *= TWO53;
+    n -= 53;
+    ix = %_DoubleHi(ax);
+  }
+
+  n += (ix >> 20) - 0x3ff;
+  var j = ix & 0x000fffff;
+
+  // Determine interval.
+  ix = j | 0x3ff00000;  // normalize ix.
+
+  var bp = 1;
+  var dp_h = 0;
+  var dp_l = 0;
+  if (j > 0x3988e) {  // |x| > sqrt(3/2)
+    if (j < 0xbb67a) {  // |x| < sqrt(3)
+      bp = 1.5;
+      dp_h = DP_H;
+      dp_l = DP_L;
+    } else {
+      n += 1;
+      ix -= 0x00100000;
+    }
+  }
+ 
+  ax = %_ConstructDouble(ix, %_DoubleLo(ax));
+
+  // Compute ss = s_h + s_l = (x - 1)/(x+1) or (x - 1.5)/(x + 1.5)
+  var u = ax - bp;
+  var v = 1 / (ax + bp);
+  var ss = u * v;
+  var s_h = %_ConstructDouble(%_DoubleHi(ss), 0);
+
+  // t_h = ax + bp[k] High
+  var t_h = %_ConstructDouble(%_DoubleHi(ax + bp), 0)
+  var t_l = ax - (t_h - bp);
+  var s_l = v * ((u - s_h * t_h) - s_h * t_l);
+
+  // Compute log2(ax)
+  var s2 = ss * ss;
+  var r = s2 * s2 * (KLOG2(0) + s2 * (KLOG2(1) + s2 * (KLOG2(2) + s2 * (
+                     KLOG2(3) + s2 * (KLOG2(4) + s2 * KLOG2(5))))));
+  r += s_l * (s_h + ss);
+  s2  = s_h * s_h;
+  t_h = %_ConstructDouble(%_DoubleHi(3.0 + s2 + r), 0);
+  t_l = r - ((t_h - 3.0) - s2);
+  // u + v = ss * (1 + ...)
+  u = s_h * t_h;
+  v = s_l * t_h + t_l * ss;
+
+  // 2 / (3 * log(2)) * (ss + ...)
+  p_h = %_ConstructDouble(%_DoubleHi(u + v), 0);
+  p_l = v - (p_h - u);
+  z_h = CP_H * p_h;
+  z_l = CP_L * p_h + p_l * CP + dp_l;
+
+  // log2(ax) = (ss + ...) * 2 / (3 * log(2)) = n + dp_h + z_h + z_l
+  var t = n;
+  var t1 = %_ConstructDouble(%_DoubleHi(((z_h + z_l) + dp_h) + t), 0);
+  var t2 = z_l - (((t1 - t) - dp_h) - z_h);
+
+  // t1 + t2 = log2(ax), sum up because we do not care about extra precision.
+  return t1 + t2;
+}
diff --git a/src/third_party/vtune/v8-vtune.h b/src/third_party/vtune/v8-vtune.h
index a7e5116..34da9cb 100644
--- a/src/third_party/vtune/v8-vtune.h
+++ b/src/third_party/vtune/v8-vtune.h
@@ -62,7 +62,7 @@
 
 namespace vTune {
 
-void InitializeVtuneForV8(v8::Isolate::CreateParams& params);
+v8::JitCodeEventHandler GetVtuneCodeEventHandler();
 
 }  // namespace vTune
 
diff --git a/src/third_party/vtune/vtune-jit.cc b/src/third_party/vtune/vtune-jit.cc
index e489d6e..b621cbc 100644
--- a/src/third_party/vtune/vtune-jit.cc
+++ b/src/third_party/vtune/vtune-jit.cc
@@ -271,10 +271,10 @@
 
 }  // namespace internal
 
-void InitializeVtuneForV8(v8::Isolate::CreateParams& params) {
+v8::JitCodeEventHandler GetVtuneCodeEventHandler() {
   v8::V8::SetFlagsFromString("--nocompact_code_space",
                              (int)strlen("--nocompact_code_space"));
-  params.code_event_handler = vTune::internal::VTUNEJITInterface::event_handler;
+  return vTune::internal::VTUNEJITInterface::event_handler;
 }
 
 }  // namespace vTune
diff --git a/src/token.cc b/src/token.cc
index 5dc67bb..db88271 100644
--- a/src/token.cc
+++ b/src/token.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "include/v8stdint.h"
+#include <stdint.h>
 #include "src/token.h"
 
 namespace v8 {
diff --git a/src/token.h b/src/token.h
index 9c719b8..de8ede9 100644
--- a/src/token.h
+++ b/src/token.h
@@ -6,6 +6,7 @@
 #define V8_TOKEN_H_
 
 #include "src/base/logging.h"
+#include "src/globals.h"
 
 namespace v8 {
 namespace internal {
@@ -162,7 +163,11 @@
   T(ILLEGAL, "ILLEGAL", 0)                                           \
                                                                      \
   /* Scanner-internal use only. */                                   \
-  T(WHITESPACE, NULL, 0)
+  T(WHITESPACE, NULL, 0)                                             \
+                                                                     \
+  /* ES6 Template Literals */                                        \
+  T(TEMPLATE_SPAN, NULL, 0)                                          \
+  T(TEMPLATE_TAIL, NULL, 0)
 
 
 class Token {
@@ -187,6 +192,24 @@
     return token_type[tok] == 'K';
   }
 
+  static bool IsIdentifier(Value tok, StrictMode strict_mode,
+                           bool is_generator) {
+    switch (tok) {
+      case IDENTIFIER:
+        return true;
+      case FUTURE_STRICT_RESERVED_WORD:
+      case LET:
+      case STATIC:
+        return strict_mode == SLOPPY;
+      case YIELD:
+        return !is_generator && strict_mode == SLOPPY;
+      default:
+        return false;
+    }
+    UNREACHABLE();
+    return false;
+  }
+
   static bool IsAssignmentOp(Value tok) {
     return INIT_VAR <= tok && tok <= ASSIGN_MOD;
   }
diff --git a/src/transitions-inl.h b/src/transitions-inl.h
index a16eb44..fd8eb8b 100644
--- a/src/transitions-inl.h
+++ b/src/transitions-inl.h
@@ -34,7 +34,7 @@
 
 
 bool TransitionArray::HasElementsTransition() {
-  return Search(GetHeap()->elements_transition_symbol()) != kNotFound;
+  return SearchSpecial(GetHeap()->elements_transition_symbol()) != kNotFound;
 }
 
 
@@ -134,13 +134,83 @@
 }
 
 
-int TransitionArray::Search(Name* name) {
+Object* TransitionArray::GetTargetValue(int transition_number) {
+  Map* map = GetTarget(transition_number);
+  return map->instance_descriptors()->GetValue(map->LastAdded());
+}
+
+
+int TransitionArray::SearchName(Name* name, int* out_insertion_index) {
   if (IsSimpleTransition()) {
     Name* key = GetKey(kSimpleTransitionIndex);
     if (key->Equals(name)) return kSimpleTransitionIndex;
+    if (out_insertion_index != NULL) {
+      *out_insertion_index = key->Hash() > name->Hash() ? 0 : 1;
+    }
     return kNotFound;
   }
-  return internal::Search<ALL_ENTRIES>(this, name);
+  return internal::Search<ALL_ENTRIES>(this, name, 0, out_insertion_index);
+}
+
+
+#ifdef DEBUG
+bool TransitionArray::IsSpecialTransition(Name* name) {
+  if (!name->IsSymbol()) return false;
+  Heap* heap = name->GetHeap();
+  return name == heap->nonextensible_symbol() ||
+         name == heap->sealed_symbol() || name == heap->frozen_symbol() ||
+         name == heap->elements_transition_symbol() ||
+         name == heap->observed_symbol();
+}
+#endif
+
+
+int TransitionArray::CompareKeys(Name* key1, uint32_t hash1, PropertyKind kind1,
+                                 PropertyAttributes attributes1, Name* key2,
+                                 uint32_t hash2, PropertyKind kind2,
+                                 PropertyAttributes attributes2) {
+  int cmp = CompareNames(key1, hash1, key2, hash2);
+  if (cmp != 0) return cmp;
+
+  return CompareDetails(kind1, attributes1, kind2, attributes2);
+}
+
+
+int TransitionArray::CompareNames(Name* key1, uint32_t hash1, Name* key2,
+                                  uint32_t hash2) {
+  if (key1 != key2) {
+    // In case of hash collisions key1 is always "less" than key2.
+    return hash1 <= hash2 ? -1 : 1;
+  }
+
+  return 0;
+}
+
+
+int TransitionArray::CompareDetails(PropertyKind kind1,
+                                    PropertyAttributes attributes1,
+                                    PropertyKind kind2,
+                                    PropertyAttributes attributes2) {
+  if (kind1 != kind2) {
+    return static_cast<int>(kind1) < static_cast<int>(kind2) ? -1 : 1;
+  }
+
+  if (attributes1 != attributes2) {
+    return static_cast<int>(attributes1) < static_cast<int>(attributes2) ? -1
+                                                                         : 1;
+  }
+
+  return 0;
+}
+
+
+PropertyDetails TransitionArray::GetTargetDetails(Name* name, Map* target) {
+  DCHECK(!IsSpecialTransition(name));
+  int descriptor = target->LastAdded();
+  DescriptorArray* descriptors = target->instance_descriptors();
+  // Transitions are allowed only for the last added property.
+  DCHECK(descriptors->GetKey(descriptor)->Equals(name));
+  return descriptors->GetDetails(descriptor);
 }
 
 
@@ -154,6 +224,15 @@
 }
 
 
+void TransitionArray::SetNumberOfTransitions(int number_of_transitions) {
+  if (IsFullTransitionArray()) {
+    DCHECK(number_of_transitions <= number_of_transitions_storage());
+    WRITE_FIELD(this, kTransitionLengthOffset,
+                Smi::FromInt(number_of_transitions));
+  }
+}
+
+
 #undef FIELD_ADDR
 #undef WRITE_FIELD
 #undef CONDITIONAL_WRITE_BARRIER
diff --git a/src/transitions.cc b/src/transitions.cc
index 96ed870..c8c63d7 100644
--- a/src/transitions.cc
+++ b/src/transitions.cc
@@ -13,10 +13,12 @@
 
 
 Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate,
-                                                  int number_of_transitions) {
-  Handle<FixedArray> array =
-      isolate->factory()->NewFixedArray(ToKeyIndex(number_of_transitions));
+                                                  int number_of_transitions,
+                                                  int slack) {
+  Handle<FixedArray> array = isolate->factory()->NewFixedArray(
+      LengthFor(number_of_transitions + slack));
   array->set(kPrototypeTransitionsIndex, Smi::FromInt(0));
+  array->set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions));
   return Handle<TransitionArray>::cast(array);
 }
 
@@ -39,11 +41,6 @@
 }
 
 
-static bool InsertionPointFound(Name* key1, Name* key2) {
-  return key1->Hash() > key2->Hash();
-}
-
-
 Handle<TransitionArray> TransitionArray::NewWith(Handle<Map> map,
                                                  Handle<Name> name,
                                                  Handle<Map> target,
@@ -51,7 +48,7 @@
   Handle<TransitionArray> result;
   Isolate* isolate = name->GetIsolate();
 
-  if (flag == SIMPLE_TRANSITION) {
+  if (flag == SIMPLE_PROPERTY_TRANSITION) {
     result = AllocateSimple(isolate, target);
   } else {
     result = Allocate(isolate, 1);
@@ -74,6 +71,7 @@
   if (new_nof != nof) {
     DCHECK(new_nof == 0);
     result->Shrink(ToKeyIndex(0));
+    result->SetNumberOfTransitions(0);
   } else if (nof == 1) {
     result->NoIncrementalWriteBarrierCopyFrom(
         containing_map->transitions(), kSimpleTransitionIndex, 0);
@@ -85,21 +83,63 @@
 }
 
 
-Handle<TransitionArray> TransitionArray::CopyInsert(Handle<Map> map,
-                                                    Handle<Name> name,
-                                                    Handle<Map> target,
-                                                    SimpleTransitionFlag flag) {
+Handle<TransitionArray> TransitionArray::Insert(Handle<Map> map,
+                                                Handle<Name> name,
+                                                Handle<Map> target,
+                                                SimpleTransitionFlag flag) {
   if (!map->HasTransitionArray()) {
     return TransitionArray::NewWith(map, name, target, flag);
   }
 
   int number_of_transitions = map->transitions()->number_of_transitions();
-  int new_size = number_of_transitions;
+  int new_nof = number_of_transitions;
 
-  int insertion_index = map->transitions()->Search(*name);
-  if (insertion_index == kNotFound) ++new_size;
+  bool is_special_transition = flag == SPECIAL_TRANSITION;
+  DCHECK_EQ(is_special_transition, IsSpecialTransition(*name));
+  PropertyDetails details = is_special_transition
+                                ? PropertyDetails(NONE, FIELD, 0)
+                                : GetTargetDetails(*name, *target);
 
-  Handle<TransitionArray> result = Allocate(map->GetIsolate(), new_size);
+  int insertion_index = kNotFound;
+  int index =
+      is_special_transition
+          ? map->transitions()->SearchSpecial(Symbol::cast(*name),
+                                              &insertion_index)
+          : map->transitions()->Search(details.kind(), *name,
+                                       details.attributes(), &insertion_index);
+  if (index == kNotFound) {
+    ++new_nof;
+  } else {
+    insertion_index = index;
+  }
+  DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);
+
+  CHECK(new_nof <= kMaxNumberOfTransitions);
+
+  if (new_nof <= map->transitions()->number_of_transitions_storage()) {
+    DisallowHeapAllocation no_gc;
+    TransitionArray* array = map->transitions();
+
+    if (index != kNotFound) {
+      array->SetTarget(index, *target);
+      return handle(array);
+    }
+
+    array->SetNumberOfTransitions(new_nof);
+    for (index = number_of_transitions; index > insertion_index; --index) {
+      Name* key = array->GetKey(index - 1);
+      array->SetKey(index, key);
+      array->SetTarget(index, array->GetTarget(index - 1));
+    }
+    array->SetKey(index, *name);
+    array->SetTarget(index, *target);
+    SLOW_DCHECK(array->IsSortedNoDuplicates());
+    return handle(array);
+  }
+
+  Handle<TransitionArray> result = Allocate(
+      map->GetIsolate(), new_nof,
+      Map::SlackForArraySize(number_of_transitions, kMaxNumberOfTransitions));
 
   // The map's transition array may grown smaller during the allocation above as
   // it was weakly traversed, though it is guaranteed not to disappear. Trim the
@@ -111,46 +151,75 @@
     DCHECK(array->number_of_transitions() < number_of_transitions);
 
     number_of_transitions = array->number_of_transitions();
-    new_size = number_of_transitions;
+    new_nof = number_of_transitions;
 
-    insertion_index = array->Search(*name);
-    if (insertion_index == kNotFound) ++new_size;
+    insertion_index = kNotFound;
+    index = is_special_transition ? map->transitions()->SearchSpecial(
+                                        Symbol::cast(*name), &insertion_index)
+                                  : map->transitions()->Search(
+                                        details.kind(), *name,
+                                        details.attributes(), &insertion_index);
+    if (index == kNotFound) {
+      ++new_nof;
+    } else {
+      insertion_index = index;
+    }
+    DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);
 
-    result->Shrink(ToKeyIndex(new_size));
+    result->Shrink(ToKeyIndex(new_nof));
+    result->SetNumberOfTransitions(new_nof);
   }
 
   if (array->HasPrototypeTransitions()) {
     result->SetPrototypeTransitions(array->GetPrototypeTransitions());
   }
 
-  if (insertion_index != kNotFound) {
-    for (int i = 0; i < number_of_transitions; ++i) {
-      if (i != insertion_index) {
-        result->NoIncrementalWriteBarrierCopyFrom(array, i, i);
-      }
-    }
-    result->NoIncrementalWriteBarrierSet(insertion_index, *name, *target);
-    result->set_back_pointer_storage(array->back_pointer_storage());
-    return result;
+  DCHECK_NE(kNotFound, insertion_index);
+  for (int i = 0; i < insertion_index; ++i) {
+    result->NoIncrementalWriteBarrierCopyFrom(array, i, i);
   }
-
-  insertion_index = 0;
-  for (; insertion_index < number_of_transitions; ++insertion_index) {
-    if (InsertionPointFound(array->GetKey(insertion_index), *name)) break;
-    result->NoIncrementalWriteBarrierCopyFrom(
-        array, insertion_index, insertion_index);
-  }
-
   result->NoIncrementalWriteBarrierSet(insertion_index, *name, *target);
-
-  for (; insertion_index < number_of_transitions; ++insertion_index) {
-    result->NoIncrementalWriteBarrierCopyFrom(
-        array, insertion_index, insertion_index + 1);
+  for (int i = insertion_index; i < number_of_transitions; ++i) {
+    result->NoIncrementalWriteBarrierCopyFrom(array, i, i + 1);
   }
 
   result->set_back_pointer_storage(array->back_pointer_storage());
+  SLOW_DCHECK(result->IsSortedNoDuplicates());
   return result;
 }
 
 
+int TransitionArray::SearchDetails(int transition, PropertyKind kind,
+                                   PropertyAttributes attributes,
+                                   int* out_insertion_index) {
+  int nof_transitions = number_of_transitions();
+  DCHECK(transition < nof_transitions);
+  Name* key = GetKey(transition);
+  for (; transition < nof_transitions && GetKey(transition) == key;
+       transition++) {
+    Map* target = GetTarget(transition);
+    PropertyDetails target_details = GetTargetDetails(key, target);
+
+    int cmp = CompareDetails(kind, attributes, target_details.kind(),
+                             target_details.attributes());
+    if (cmp == 0) {
+      return transition;
+    } else if (cmp < 0) {
+      break;
+    }
+  }
+  if (out_insertion_index != NULL) *out_insertion_index = transition;
+  return kNotFound;
+}
+
+
+int TransitionArray::Search(PropertyKind kind, Name* name,
+                            PropertyAttributes attributes,
+                            int* out_insertion_index) {
+  int transition = SearchName(name, out_insertion_index);
+  if (transition == kNotFound) {
+    return kNotFound;
+  }
+  return SearchDetails(transition, kind, attributes, out_insertion_index);
+}
 } }  // namespace v8::internal
diff --git a/src/transitions.h b/src/transitions.h
index 21c02ac..999ad86 100644
--- a/src/transitions.h
+++ b/src/transitions.h
@@ -30,8 +30,9 @@
 // The full format is:
 // [0] Undefined or back pointer map
 // [1] Smi(0) or fixed array of prototype transitions
-// [2] First transition
-// [length() - kTransitionSize] Last transition
+// [2] Number of transitions
+// [3] First transition
+// [3 + number of transitions * kTransitionSize]: start of slack
 class TransitionArray: public FixedArray {
  public:
   // Accessors for fetching instance transition at transition number.
@@ -48,6 +49,7 @@
   inline void SetTarget(int transition_number, Map* target);
 
   inline PropertyDetails GetTargetDetails(int transition_number);
+  inline Object* GetTargetValue(int transition_number);
 
   inline bool HasElementsTransition();
 
@@ -66,10 +68,21 @@
   // Returns the number of transitions in the array.
   int number_of_transitions() {
     if (IsSimpleTransition()) return 1;
-    int len = length();
-    return len <= kFirstIndex ? 0 : (len - kFirstIndex) / kTransitionSize;
+    if (length() <= kFirstIndex) return 0;
+    return Smi::cast(get(kTransitionLengthIndex))->value();
   }
 
+  int number_of_transitions_storage() {
+    if (IsSimpleTransition()) return 1;
+    if (length() <= kFirstIndex) return 0;
+    return (length() - kFirstIndex) / kTransitionSize;
+  }
+
+  int NumberOfSlackTransitions() {
+    return number_of_transitions_storage() - number_of_transitions();
+  }
+
+  inline void SetNumberOfTransitions(int number_of_transitions);
   inline int number_of_entries() { return number_of_transitions(); }
 
   // Creates a FullTransitionArray from a SimpleTransitionArray in
@@ -77,21 +90,30 @@
   static Handle<TransitionArray> ExtendToFullTransitionArray(
       Handle<Map> containing_map);
 
-  // Create a transition array, copying from the owning map if it already has
-  // one, otherwise creating a new one according to flag.
+  // Return a transition array, using the array from the owning map if it
+  // already has one (copying into a larger array if necessary), otherwise
+  // creating a new one according to flag.
   // TODO(verwaest): This should not cause an existing transition to be
   // overwritten.
-  static Handle<TransitionArray> CopyInsert(Handle<Map> map,
-                                            Handle<Name> name,
-                                            Handle<Map> target,
-                                            SimpleTransitionFlag flag);
+  static Handle<TransitionArray> Insert(Handle<Map> map, Handle<Name> name,
+                                        Handle<Map> target,
+                                        SimpleTransitionFlag flag);
+  // Search a  transition for a given kind, property name and attributes.
+  int Search(PropertyKind kind, Name* name, PropertyAttributes attributes,
+             int* out_insertion_index = NULL);
 
-  // Search a transition for a given property name.
-  inline int Search(Name* name);
+  // Search a non-property transition (like elements kind, observe or frozen
+  // transitions).
+  inline int SearchSpecial(Symbol* symbol, int* out_insertion_index = NULL) {
+    return SearchName(symbol, out_insertion_index);
+  }
+
+  static inline PropertyDetails GetTargetDetails(Name* name, Map* target);
 
   // Allocates a TransitionArray.
-  static Handle<TransitionArray> Allocate(
-      Isolate* isolate, int number_of_transitions);
+  static Handle<TransitionArray> Allocate(Isolate* isolate,
+                                          int number_of_transitions,
+                                          int slack = 0);
 
   bool IsSimpleTransition() {
     return length() == kSimpleTransitionSize &&
@@ -119,7 +141,8 @@
 
   // Layout for full transition arrays.
   static const int kPrototypeTransitionsIndex = 1;
-  static const int kFirstIndex = 2;
+  static const int kTransitionLengthIndex = 2;
+  static const int kFirstIndex = 3;
 
   // Layout for simple transition arrays.
   static const int kSimpleTransitionTarget = 1;
@@ -132,27 +155,42 @@
   // Layout for the full transition array header.
   static const int kPrototypeTransitionsOffset = kBackPointerStorageOffset +
                                                  kPointerSize;
+  static const int kTransitionLengthOffset =
+      kPrototypeTransitionsOffset + kPointerSize;
 
   // Layout of map transition entries in full transition arrays.
   static const int kTransitionKey = 0;
   static const int kTransitionTarget = 1;
   static const int kTransitionSize = 2;
 
-#ifdef OBJECT_PRINT
+#if defined(DEBUG) || defined(OBJECT_PRINT)
+  // For our gdb macros, we should perhaps change these in the future.
+  void Print();
+
   // Print all the transitions.
-  void PrintTransitions(OStream& os);  // NOLINT
+  void PrintTransitions(std::ostream& os, bool print_header = true);  // NOLINT
 #endif
 
 #ifdef DEBUG
   bool IsSortedNoDuplicates(int valid_entries = -1);
   bool IsConsistentWithBackPointers(Map* current_map);
   bool IsEqualTo(TransitionArray* other);
+
+  // Returns true for a non-property transitions like elements kind, observed
+  // or frozen transitions.
+  static inline bool IsSpecialTransition(Name* name);
 #endif
 
   // The maximum number of transitions we want in a transition array (should
   // fit in a page).
   static const int kMaxNumberOfTransitions = 1024 + 512;
 
+  // Returns the fixed array length required to hold number_of_transitions
+  // transitions.
+  static int LengthFor(int number_of_transitions) {
+    return ToKeyIndex(number_of_transitions);
+  }
+
  private:
   // Conversion from transition number to array indices.
   static int ToKeyIndex(int transition_number) {
@@ -176,6 +214,30 @@
                                          Handle<Map> target,
                                          SimpleTransitionFlag flag);
 
+  // Search a first transition for a given property name.
+  inline int SearchName(Name* name, int* out_insertion_index = NULL);
+  int SearchDetails(int transition, PropertyKind kind,
+                    PropertyAttributes attributes, int* out_insertion_index);
+
+  // Compares two tuples <key, kind, attributes>, returns -1 if
+  // tuple1 is "less" than tuple2, 0 if tuple1 equal to tuple2 and 1 otherwise.
+  static inline int CompareKeys(Name* key1, uint32_t hash1, PropertyKind kind1,
+                                PropertyAttributes attributes1, Name* key2,
+                                uint32_t hash2, PropertyKind kind2,
+                                PropertyAttributes attributes2);
+
+  // Compares keys, returns -1 if key1 is "less" than key2,
+  // 0 if key1 equal to key2 and 1 otherwise.
+  static inline int CompareNames(Name* key1, uint32_t hash1, Name* key2,
+                                 uint32_t hash2);
+
+  // Compares two details, returns -1 if details1 is "less" than details2,
+  // 0 if details1 equal to details2 and 1 otherwise.
+  static inline int CompareDetails(PropertyKind kind1,
+                                   PropertyAttributes attributes1,
+                                   PropertyKind kind2,
+                                   PropertyAttributes attributes2);
+
   inline void NoIncrementalWriteBarrierSet(int transition_number,
                                            Name* key,
                                            Map* target);
diff --git a/src/type-feedback-vector-inl.h b/src/type-feedback-vector-inl.h
index 43e768e..612004e 100644
--- a/src/type-feedback-vector-inl.h
+++ b/src/type-feedback-vector-inl.h
@@ -10,6 +10,11 @@
 namespace v8 {
 namespace internal {
 
+int TypeFeedbackVector::ic_metadata_length() const {
+  return FLAG_vector_ics ? VectorICComputer::word_count(ICSlots()) : 0;
+}
+
+
 Handle<Object> TypeFeedbackVector::UninitializedSentinel(Isolate* isolate) {
   return isolate->factory()->uninitialized_symbol();
 }
@@ -21,7 +26,7 @@
 
 
 Handle<Object> TypeFeedbackVector::PremonomorphicSentinel(Isolate* isolate) {
-  return isolate->factory()->megamorphic_symbol();
+  return isolate->factory()->premonomorphic_symbol();
 }
 
 
diff --git a/src/type-feedback-vector.cc b/src/type-feedback-vector.cc
index a3fe070..c51d987 100644
--- a/src/type-feedback-vector.cc
+++ b/src/type-feedback-vector.cc
@@ -4,6 +4,8 @@
 
 #include "src/v8.h"
 
+#include "src/ic/ic.h"
+#include "src/ic/ic-state.h"
 #include "src/objects.h"
 #include "src/type-feedback-vector-inl.h"
 
@@ -11,6 +13,114 @@
 namespace internal {
 
 // static
+TypeFeedbackVector::VectorICKind TypeFeedbackVector::FromCodeKind(
+    Code::Kind kind) {
+  switch (kind) {
+    case Code::CALL_IC:
+      return KindCallIC;
+    case Code::LOAD_IC:
+      return KindLoadIC;
+    case Code::KEYED_LOAD_IC:
+      return KindKeyedLoadIC;
+    default:
+      // Shouldn't get here.
+      UNREACHABLE();
+  }
+
+  return KindUnused;
+}
+
+
+// static
+Code::Kind TypeFeedbackVector::FromVectorICKind(VectorICKind kind) {
+  switch (kind) {
+    case KindCallIC:
+      return Code::CALL_IC;
+    case KindLoadIC:
+      return Code::LOAD_IC;
+    case KindKeyedLoadIC:
+      return Code::KEYED_LOAD_IC;
+    case KindUnused:
+      break;
+  }
+  // Sentinel for no information.
+  return Code::NUMBER_OF_KINDS;
+}
+
+
+Code::Kind TypeFeedbackVector::GetKind(FeedbackVectorICSlot slot) const {
+  if (!FLAG_vector_ics) {
+    // We only have CALL_ICs
+    return Code::CALL_IC;
+  }
+
+  int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
+  int data = Smi::cast(get(index))->value();
+  VectorICKind b = VectorICComputer::decode(data, slot.ToInt());
+  return FromVectorICKind(b);
+}
+
+
+void TypeFeedbackVector::SetKind(FeedbackVectorICSlot slot, Code::Kind kind) {
+  if (!FLAG_vector_ics) {
+    // Nothing to do if we only have CALL_ICs
+    return;
+  }
+
+  VectorICKind b = FromCodeKind(kind);
+  int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
+  int data = Smi::cast(get(index))->value();
+  int new_data = VectorICComputer::encode(data, slot.ToInt(), b);
+  set(index, Smi::FromInt(new_data));
+}
+
+
+// static
+Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(
+    Isolate* isolate, const FeedbackVectorSpec& spec) {
+  const int slot_count = spec.slots();
+  const int ic_slot_count = spec.ic_slots();
+  const int index_count =
+      FLAG_vector_ics ? VectorICComputer::word_count(ic_slot_count) : 0;
+  const int length =
+      slot_count + ic_slot_count + index_count + kReservedIndexCount;
+  if (length == kReservedIndexCount) {
+    return Handle<TypeFeedbackVector>::cast(
+        isolate->factory()->empty_fixed_array());
+  }
+
+  Handle<FixedArray> array = isolate->factory()->NewFixedArray(length, TENURED);
+  if (ic_slot_count > 0) {
+    array->set(kFirstICSlotIndex,
+               Smi::FromInt(slot_count + index_count + kReservedIndexCount));
+  } else {
+    array->set(kFirstICSlotIndex, Smi::FromInt(length));
+  }
+  array->set(kWithTypesIndex, Smi::FromInt(0));
+  array->set(kGenericCountIndex, Smi::FromInt(0));
+  // Fill the indexes with zeros.
+  for (int i = 0; i < index_count; i++) {
+    array->set(kReservedIndexCount + i, Smi::FromInt(0));
+  }
+
+  // Ensure we can skip the write barrier
+  Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
+  DCHECK_EQ(isolate->heap()->uninitialized_symbol(), *uninitialized_sentinel);
+  for (int i = kReservedIndexCount + index_count; i < length; i++) {
+    array->set(i, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
+  }
+
+  Handle<TypeFeedbackVector> vector = Handle<TypeFeedbackVector>::cast(array);
+  if (FLAG_vector_ics) {
+    for (int i = 0; i < ic_slot_count; i++) {
+      vector->SetKind(FeedbackVectorICSlot(i), spec.GetKind(i));
+    }
+  }
+  return vector;
+}
+
+
+// static
 Handle<TypeFeedbackVector> TypeFeedbackVector::Copy(
     Isolate* isolate, Handle<TypeFeedbackVector> vector) {
   Handle<TypeFeedbackVector> result;
@@ -18,5 +128,389 @@
       isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector)));
   return result;
 }
+
+
+// This logic is copied from
+// StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget.
+// TODO(mvstanton): with weak handling of all vector ics, this logic should
+// actually be completely eliminated and we no longer need to clear the
+// vector ICs.
+static bool ClearLogic(Heap* heap, int ic_age, Code::Kind kind,
+                       InlineCacheState state) {
+  if (FLAG_cleanup_code_caches_at_gc &&
+      (kind == Code::CALL_IC || heap->flush_monomorphic_ics() ||
+       // TODO(mvstanton): is this ic_age granular enough? it comes from
+       // the SharedFunctionInfo which may change on a different schedule
+       // than ic targets.
+       // ic_age != heap->global_ic_age() ||
+       // is_invalidated_weak_stub ||
+       heap->isolate()->serializer_enabled())) {
+    return true;
+  }
+  return false;
+}
+
+
+void TypeFeedbackVector::ClearSlots(SharedFunctionInfo* shared) {
+  int slots = Slots();
+  Isolate* isolate = GetIsolate();
+  Object* uninitialized_sentinel =
+      TypeFeedbackVector::RawUninitializedSentinel(isolate->heap());
+
+  for (int i = 0; i < slots; i++) {
+    FeedbackVectorSlot slot(i);
+    Object* obj = Get(slot);
+    if (obj->IsHeapObject()) {
+      InstanceType instance_type =
+          HeapObject::cast(obj)->map()->instance_type();
+      // AllocationSites are exempt from clearing. They don't store Maps
+      // or Code pointers which can cause memory leaks if not cleared
+      // regularly.
+      if (instance_type != ALLOCATION_SITE_TYPE) {
+        Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER);
+      }
+    }
+  }
+
+  slots = ICSlots();
+  if (slots == 0) return;
+
+  // Now clear vector-based ICs.
+  // Try and pass the containing code (the "host").
+  Heap* heap = isolate->heap();
+  Code* host = shared->code();
+  // I'm not sure yet if this ic age is the correct one.
+  int ic_age = shared->ic_age();
+  for (int i = 0; i < slots; i++) {
+    FeedbackVectorICSlot slot(i);
+    Object* obj = Get(slot);
+    if (obj != uninitialized_sentinel) {
+      Code::Kind kind = GetKind(slot);
+      if (kind == Code::CALL_IC) {
+        CallICNexus nexus(this, slot);
+        if (ClearLogic(heap, ic_age, kind, nexus.StateFromFeedback())) {
+          nexus.Clear(host);
+        }
+      } else if (kind == Code::LOAD_IC) {
+        LoadICNexus nexus(this, slot);
+        if (ClearLogic(heap, ic_age, kind, nexus.StateFromFeedback())) {
+          nexus.Clear(host);
+        }
+      } else if (kind == Code::KEYED_LOAD_IC) {
+        KeyedLoadICNexus nexus(this, slot);
+        if (ClearLogic(heap, ic_age, kind, nexus.StateFromFeedback())) {
+          nexus.Clear(host);
+        }
+      }
+    }
+  }
+}
+
+
+Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
+  Isolate* isolate = GetIsolate();
+  Handle<Object> feedback = handle(GetFeedback(), isolate);
+  if (!feedback->IsFixedArray() ||
+      FixedArray::cast(*feedback)->length() != length) {
+    Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
+    SetFeedback(*array);
+    return array;
+  }
+  return Handle<FixedArray>::cast(feedback);
+}
+
+
+void FeedbackNexus::InstallHandlers(int start_index, TypeHandleList* types,
+                                    CodeHandleList* handlers) {
+  Isolate* isolate = GetIsolate();
+  Handle<FixedArray> array = handle(FixedArray::cast(GetFeedback()), isolate);
+  int receiver_count = types->length();
+  for (int current = 0; current < receiver_count; ++current) {
+    Handle<HeapType> type = types->at(current);
+    Handle<Map> map = IC::TypeToMap(*type, isolate);
+    Handle<WeakCell> cell = Map::WeakCellForMap(map);
+    array->set(start_index + (current * 2), *cell);
+    array->set(start_index + (current * 2 + 1), *handlers->at(current));
+  }
+}
+
+
+InlineCacheState LoadICNexus::StateFromFeedback() const {
+  Isolate* isolate = GetIsolate();
+  Object* feedback = GetFeedback();
+  if (feedback == *vector()->UninitializedSentinel(isolate)) {
+    return UNINITIALIZED;
+  } else if (feedback == *vector()->MegamorphicSentinel(isolate)) {
+    return MEGAMORPHIC;
+  } else if (feedback == *vector()->PremonomorphicSentinel(isolate)) {
+    return PREMONOMORPHIC;
+  } else if (feedback->IsFixedArray()) {
+    // Determine state purely by our structure, don't check if the maps are
+    // cleared.
+    FixedArray* array = FixedArray::cast(feedback);
+    int length = array->length();
+    DCHECK(length >= 2);
+    return length == 2 ? MONOMORPHIC : POLYMORPHIC;
+  }
+
+  return UNINITIALIZED;
+}
+
+
+InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
+  Isolate* isolate = GetIsolate();
+  Object* feedback = GetFeedback();
+  if (feedback == *vector()->UninitializedSentinel(isolate)) {
+    return UNINITIALIZED;
+  } else if (feedback == *vector()->PremonomorphicSentinel(isolate)) {
+    return PREMONOMORPHIC;
+  } else if (feedback == *vector()->GenericSentinel(isolate)) {
+    return GENERIC;
+  } else if (feedback->IsFixedArray()) {
+    // Determine state purely by our structure, don't check if the maps are
+    // cleared.
+    FixedArray* array = FixedArray::cast(feedback);
+    int length = array->length();
+    DCHECK(length >= 3);
+    return length == 3 ? MONOMORPHIC : POLYMORPHIC;
+  }
+
+  return UNINITIALIZED;
+}
+
+
+InlineCacheState CallICNexus::StateFromFeedback() const {
+  Isolate* isolate = GetIsolate();
+  Object* feedback = GetFeedback();
+
+  if (feedback == *vector()->MegamorphicSentinel(isolate)) {
+    return GENERIC;
+  } else if (feedback->IsAllocationSite() || feedback->IsJSFunction()) {
+    return MONOMORPHIC;
+  }
+
+  CHECK(feedback == *vector()->UninitializedSentinel(isolate));
+  return UNINITIALIZED;
+}
+
+
+void CallICNexus::Clear(Code* host) { CallIC::Clear(GetIsolate(), host, this); }
+
+
+void CallICNexus::ConfigureGeneric() {
+  SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
+}
+
+
+void CallICNexus::ConfigureMonomorphicArray() {
+  Object* feedback = GetFeedback();
+  if (!feedback->IsAllocationSite()) {
+    Handle<AllocationSite> new_site =
+        GetIsolate()->factory()->NewAllocationSite();
+    SetFeedback(*new_site);
+  }
+}
+
+
+void CallICNexus::ConfigureUninitialized() {
+  SetFeedback(*vector()->UninitializedSentinel(GetIsolate()),
+              SKIP_WRITE_BARRIER);
+}
+
+
+void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
+  SetFeedback(*function);
+}
+
+
+void KeyedLoadICNexus::ConfigureGeneric() {
+  SetFeedback(*vector()->GenericSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
+}
+
+
+void LoadICNexus::ConfigureMegamorphic() {
+  SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
+}
+
+
+void LoadICNexus::ConfigurePremonomorphic() {
+  SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
+              SKIP_WRITE_BARRIER);
+}
+
+
+void KeyedLoadICNexus::ConfigurePremonomorphic() {
+  SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
+              SKIP_WRITE_BARRIER);
+}
+
+
+void LoadICNexus::ConfigureMonomorphic(Handle<HeapType> type,
+                                       Handle<Code> handler) {
+  Handle<FixedArray> array = EnsureArrayOfSize(2);
+  Handle<Map> receiver_map = IC::TypeToMap(*type, GetIsolate());
+  Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
+  array->set(0, *cell);
+  array->set(1, *handler);
+}
+
+
+void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
+                                            Handle<HeapType> type,
+                                            Handle<Code> handler) {
+  Handle<FixedArray> array = EnsureArrayOfSize(3);
+  Handle<Map> receiver_map = IC::TypeToMap(*type, GetIsolate());
+  if (name.is_null()) {
+    array->set(0, Smi::FromInt(0));
+  } else {
+    array->set(0, *name);
+  }
+  Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
+  array->set(1, *cell);
+  array->set(2, *handler);
+}
+
+
+void LoadICNexus::ConfigurePolymorphic(TypeHandleList* types,
+                                       CodeHandleList* handlers) {
+  int receiver_count = types->length();
+  EnsureArrayOfSize(receiver_count * 2);
+  InstallHandlers(0, types, handlers);
+}
+
+
+void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
+                                            TypeHandleList* types,
+                                            CodeHandleList* handlers) {
+  int receiver_count = types->length();
+  Handle<FixedArray> array = EnsureArrayOfSize(1 + receiver_count * 2);
+  if (name.is_null()) {
+    array->set(0, Smi::FromInt(0));
+  } else {
+    array->set(0, *name);
+  }
+  InstallHandlers(1, types, handlers);
+}
+
+
+int FeedbackNexus::ExtractMaps(int start_index, MapHandleList* maps) const {
+  Isolate* isolate = GetIsolate();
+  Object* feedback = GetFeedback();
+  if (feedback->IsFixedArray()) {
+    int found = 0;
+    FixedArray* array = FixedArray::cast(feedback);
+    // The array should be of the form [<optional name>], then
+    // [map, handler, map, handler, ... ]
+    DCHECK(array->length() >= (2 + start_index));
+    for (int i = start_index; i < array->length(); i += 2) {
+      WeakCell* cell = WeakCell::cast(array->get(i));
+      if (!cell->cleared()) {
+        Map* map = Map::cast(cell->value());
+        maps->Add(handle(map, isolate));
+        found++;
+      }
+    }
+    return found;
+  }
+
+  return 0;
+}
+
+
+MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(int start_index,
+                                                   Handle<Map> map) const {
+  Object* feedback = GetFeedback();
+  if (feedback->IsFixedArray()) {
+    FixedArray* array = FixedArray::cast(feedback);
+    for (int i = start_index; i < array->length(); i += 2) {
+      WeakCell* cell = WeakCell::cast(array->get(i));
+      if (!cell->cleared()) {
+        Map* array_map = Map::cast(cell->value());
+        if (array_map == *map) {
+          Code* code = Code::cast(array->get(i + 1));
+          DCHECK(code->kind() == Code::HANDLER);
+          return handle(code);
+        }
+      }
+    }
+  }
+
+  return MaybeHandle<Code>();
+}
+
+
+bool FeedbackNexus::FindHandlers(int start_index, CodeHandleList* code_list,
+                                 int length) const {
+  Object* feedback = GetFeedback();
+  int count = 0;
+  if (feedback->IsFixedArray()) {
+    FixedArray* array = FixedArray::cast(feedback);
+    // The array should be of the form [<optional name>], then
+    // [map, handler, map, handler, ... ]. Be sure to skip handlers whose maps
+    // have been cleared.
+    DCHECK(array->length() >= (2 + start_index));
+    for (int i = start_index; i < array->length(); i += 2) {
+      WeakCell* cell = WeakCell::cast(array->get(i));
+      if (!cell->cleared()) {
+        Code* code = Code::cast(array->get(i + 1));
+        DCHECK(code->kind() == Code::HANDLER);
+        code_list->Add(handle(code));
+        count++;
+      }
+    }
+  }
+  return count == length;
+}
+
+
+int LoadICNexus::ExtractMaps(MapHandleList* maps) const {
+  return FeedbackNexus::ExtractMaps(0, maps);
+}
+
+
+void LoadICNexus::Clear(Code* host) { LoadIC::Clear(GetIsolate(), host, this); }
+
+
+void KeyedLoadICNexus::Clear(Code* host) {
+  KeyedLoadIC::Clear(GetIsolate(), host, this);
+}
+
+
+int KeyedLoadICNexus::ExtractMaps(MapHandleList* maps) const {
+  return FeedbackNexus::ExtractMaps(1, maps);
+}
+
+
+MaybeHandle<Code> LoadICNexus::FindHandlerForMap(Handle<Map> map) const {
+  return FeedbackNexus::FindHandlerForMap(0, map);
+}
+
+
+MaybeHandle<Code> KeyedLoadICNexus::FindHandlerForMap(Handle<Map> map) const {
+  return FeedbackNexus::FindHandlerForMap(1, map);
+}
+
+
+bool LoadICNexus::FindHandlers(CodeHandleList* code_list, int length) const {
+  return FeedbackNexus::FindHandlers(0, code_list, length);
+}
+
+
+bool KeyedLoadICNexus::FindHandlers(CodeHandleList* code_list,
+                                    int length) const {
+  return FeedbackNexus::FindHandlers(1, code_list, length);
+}
+
+
+Name* KeyedLoadICNexus::FindFirstName() const {
+  Object* feedback = GetFeedback();
+  if (feedback->IsFixedArray()) {
+    FixedArray* array = FixedArray::cast(feedback);
+    DCHECK(array->length() >= 3);
+    Object* name = array->get(0);
+    if (name->IsName()) return Name::cast(name);
+  }
+  return NULL;
+}
 }
 }  // namespace v8::internal
diff --git a/src/type-feedback-vector.h b/src/type-feedback-vector.h
index b6fadba..864f336 100644
--- a/src/type-feedback-vector.h
+++ b/src/type-feedback-vector.h
@@ -5,6 +5,8 @@
 #ifndef V8_TYPE_FEEDBACK_VECTOR_H_
 #define V8_TYPE_FEEDBACK_VECTOR_H_
 
+#include <vector>
+
 #include "src/checks.h"
 #include "src/elements-kind.h"
 #include "src/heap/heap.h"
@@ -14,6 +16,51 @@
 namespace v8 {
 namespace internal {
 
+class FeedbackVectorSpec {
+ public:
+  FeedbackVectorSpec() : slots_(0), ic_slots_(0) {}
+  FeedbackVectorSpec(int slots, int ic_slots)
+      : slots_(slots), ic_slots_(ic_slots) {
+    if (FLAG_vector_ics) ic_slot_kinds_.resize(ic_slots);
+  }
+
+  int slots() const { return slots_; }
+  void increase_slots(int count) { slots_ += count; }
+
+  int ic_slots() const { return ic_slots_; }
+  void increase_ic_slots(int count) {
+    ic_slots_ += count;
+    if (FLAG_vector_ics) ic_slot_kinds_.resize(ic_slots_);
+  }
+
+  void SetKind(int ic_slot, Code::Kind kind) {
+    DCHECK(FLAG_vector_ics);
+    ic_slot_kinds_[ic_slot] = kind;
+  }
+
+  Code::Kind GetKind(int ic_slot) const {
+    DCHECK(FLAG_vector_ics);
+    return static_cast<Code::Kind>(ic_slot_kinds_.at(ic_slot));
+  }
+
+ private:
+  int slots_;
+  int ic_slots_;
+  std::vector<unsigned char> ic_slot_kinds_;
+};
+
+
+// The shape of the TypeFeedbackVector is an array with:
+// 0: first_ic_slot_index (== length() if no ic slots are present)
+// 1: ics_with_types
+// 2: ics_with_generic_info
+// 3: type information for ic slots, if any
+// ...
+// N: first feedback slot (N >= 3)
+// ...
+// [<first_ic_slot_index>: feedback slot]
+// ...to length() - 1
+//
 class TypeFeedbackVector : public FixedArray {
  public:
   // Casting.
@@ -22,9 +69,103 @@
     return reinterpret_cast<TypeFeedbackVector*>(obj);
   }
 
+  static const int kReservedIndexCount = 3;
+  static const int kFirstICSlotIndex = 0;
+  static const int kWithTypesIndex = 1;
+  static const int kGenericCountIndex = 2;
+
+  int first_ic_slot_index() const {
+    DCHECK(length() >= kReservedIndexCount);
+    return Smi::cast(get(kFirstICSlotIndex))->value();
+  }
+
+  int ic_with_type_info_count() {
+    return length() > 0 ? Smi::cast(get(kWithTypesIndex))->value() : 0;
+  }
+
+  void change_ic_with_type_info_count(int delta) {
+    if (delta == 0) return;
+    int value = ic_with_type_info_count() + delta;
+    // Could go negative because of the debugger.
+    if (value >= 0) {
+      set(kWithTypesIndex, Smi::FromInt(value));
+    }
+  }
+
+  int ic_generic_count() {
+    return length() > 0 ? Smi::cast(get(kGenericCountIndex))->value() : 0;
+  }
+
+  void change_ic_generic_count(int delta) {
+    if (delta == 0) return;
+    int value = ic_generic_count() + delta;
+    if (value >= 0) {
+      set(kGenericCountIndex, Smi::FromInt(value));
+    }
+  }
+
+  inline int ic_metadata_length() const;
+
+  int Slots() const {
+    if (length() == 0) return 0;
+    return Max(
+        0, first_ic_slot_index() - ic_metadata_length() - kReservedIndexCount);
+  }
+
+  int ICSlots() const {
+    if (length() == 0) return 0;
+    return length() - first_ic_slot_index();
+  }
+
+  // Conversion from a slot or ic slot to an integer index to the underlying
+  // array.
+  int GetIndex(FeedbackVectorSlot slot) const {
+    return kReservedIndexCount + ic_metadata_length() + slot.ToInt();
+  }
+
+  int GetIndex(FeedbackVectorICSlot slot) const {
+    int first_ic_slot = first_ic_slot_index();
+    DCHECK(slot.ToInt() < ICSlots());
+    return first_ic_slot + slot.ToInt();
+  }
+
+  // Conversion from an integer index to either a slot or an ic slot. The caller
+  // should know what kind she expects.
+  FeedbackVectorSlot ToSlot(int index) const {
+    DCHECK(index >= kReservedIndexCount && index < first_ic_slot_index());
+    return FeedbackVectorSlot(index - ic_metadata_length() -
+                              kReservedIndexCount);
+  }
+
+  FeedbackVectorICSlot ToICSlot(int index) const {
+    DCHECK(index >= first_ic_slot_index() && index < length());
+    return FeedbackVectorICSlot(index - first_ic_slot_index());
+  }
+
+  Object* Get(FeedbackVectorSlot slot) const { return get(GetIndex(slot)); }
+  void Set(FeedbackVectorSlot slot, Object* value,
+           WriteBarrierMode mode = UPDATE_WRITE_BARRIER) {
+    set(GetIndex(slot), value, mode);
+  }
+
+  Object* Get(FeedbackVectorICSlot slot) const { return get(GetIndex(slot)); }
+  void Set(FeedbackVectorICSlot slot, Object* value,
+           WriteBarrierMode mode = UPDATE_WRITE_BARRIER) {
+    set(GetIndex(slot), value, mode);
+  }
+
+  // IC slots need metadata to recognize the type of IC.
+  Code::Kind GetKind(FeedbackVectorICSlot slot) const;
+
+  static Handle<TypeFeedbackVector> Allocate(Isolate* isolate,
+                                             const FeedbackVectorSpec& spec);
+
   static Handle<TypeFeedbackVector> Copy(Isolate* isolate,
                                          Handle<TypeFeedbackVector> vector);
 
+  // Clears the vector slots and the vector ic slots.
+  void ClearSlots(SharedFunctionInfo* shared);
+
   // The object that indicates an uninitialized cache.
   static inline Handle<Object> UninitializedSentinel(Isolate* isolate);
 
@@ -47,8 +188,182 @@
   static inline Object* RawUninitializedSentinel(Heap* heap);
 
  private:
+  enum VectorICKind {
+    KindUnused = 0x0,
+    KindCallIC = 0x1,
+    KindLoadIC = 0x2,
+    KindKeyedLoadIC = 0x3
+  };
+
+  static const int kVectorICKindBits = 2;
+  static VectorICKind FromCodeKind(Code::Kind kind);
+  static Code::Kind FromVectorICKind(VectorICKind kind);
+  void SetKind(FeedbackVectorICSlot slot, Code::Kind kind);
+
+  typedef BitSetComputer<VectorICKind, kVectorICKindBits, kSmiValueSize,
+                         uint32_t> VectorICComputer;
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(TypeFeedbackVector);
 };
+
+
+// A FeedbackNexus is the combination of a TypeFeedbackVector and a slot.
+// Derived classes customize the update and retrieval of feedback.
+class FeedbackNexus {
+ public:
+  FeedbackNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
+      : vector_handle_(vector), vector_(NULL), slot_(slot) {}
+  FeedbackNexus(TypeFeedbackVector* vector, FeedbackVectorICSlot slot)
+      : vector_(vector), slot_(slot) {}
+  virtual ~FeedbackNexus() {}
+
+  Handle<TypeFeedbackVector> vector_handle() const {
+    DCHECK(vector_ == NULL);
+    return vector_handle_;
+  }
+  TypeFeedbackVector* vector() const {
+    return vector_handle_.is_null() ? vector_ : *vector_handle_;
+  }
+  FeedbackVectorICSlot slot() const { return slot_; }
+
+  InlineCacheState ic_state() const { return StateFromFeedback(); }
+  Map* FindFirstMap() const {
+    MapHandleList maps;
+    ExtractMaps(&maps);
+    if (maps.length() > 0) return *maps.at(0);
+    return NULL;
+  }
+
+  // TODO(mvstanton): remove FindAllMaps, it didn't survive a code review.
+  void FindAllMaps(MapHandleList* maps) const { ExtractMaps(maps); }
+
+  virtual InlineCacheState StateFromFeedback() const = 0;
+  virtual int ExtractMaps(MapHandleList* maps) const = 0;
+  virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const = 0;
+  virtual bool FindHandlers(CodeHandleList* code_list, int length = -1) const {
+    return length == 0;
+  }
+  virtual Name* FindFirstName() const { return NULL; }
+
+  Object* GetFeedback() const { return vector()->Get(slot()); }
+
+ protected:
+  Isolate* GetIsolate() const { return vector()->GetIsolate(); }
+
+  void SetFeedback(Object* feedback,
+                   WriteBarrierMode mode = UPDATE_WRITE_BARRIER) {
+    vector()->Set(slot(), feedback, mode);
+  }
+
+  Handle<FixedArray> EnsureArrayOfSize(int length);
+  void InstallHandlers(int start_index, TypeHandleList* types,
+                       CodeHandleList* handlers);
+  int ExtractMaps(int start_index, MapHandleList* maps) const;
+  MaybeHandle<Code> FindHandlerForMap(int start_index, Handle<Map> map) const;
+  bool FindHandlers(int start_index, CodeHandleList* code_list,
+                    int length) const;
+
+ private:
+  // The reason for having a vector handle and a raw pointer is that we can and
+  // should use handles during IC miss, but not during GC when we clear ICs. If
+  // you have a handle to the vector that is better because more operations can
+  // be done, like allocation.
+  Handle<TypeFeedbackVector> vector_handle_;
+  TypeFeedbackVector* vector_;
+  FeedbackVectorICSlot slot_;
+};
+
+
+class CallICNexus : public FeedbackNexus {
+ public:
+  CallICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
+      : FeedbackNexus(vector, slot) {
+    DCHECK(vector->GetKind(slot) == Code::CALL_IC);
+  }
+  CallICNexus(TypeFeedbackVector* vector, FeedbackVectorICSlot slot)
+      : FeedbackNexus(vector, slot) {
+    DCHECK(vector->GetKind(slot) == Code::CALL_IC);
+  }
+
+  void Clear(Code* host);
+
+  void ConfigureUninitialized();
+  void ConfigureGeneric();
+  void ConfigureMonomorphicArray();
+  void ConfigureMonomorphic(Handle<JSFunction> function);
+
+  InlineCacheState StateFromFeedback() const OVERRIDE;
+
+  int ExtractMaps(MapHandleList* maps) const OVERRIDE {
+    // CallICs don't record map feedback.
+    return 0;
+  }
+  MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const OVERRIDE {
+    return MaybeHandle<Code>();
+  }
+  virtual bool FindHandlers(CodeHandleList* code_list,
+                            int length = -1) const OVERRIDE {
+    return length == 0;
+  }
+};
+
+
+class LoadICNexus : public FeedbackNexus {
+ public:
+  LoadICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
+      : FeedbackNexus(vector, slot) {
+    DCHECK(vector->GetKind(slot) == Code::LOAD_IC);
+  }
+  LoadICNexus(TypeFeedbackVector* vector, FeedbackVectorICSlot slot)
+      : FeedbackNexus(vector, slot) {
+    DCHECK(vector->GetKind(slot) == Code::LOAD_IC);
+  }
+
+  void Clear(Code* host);
+
+  void ConfigureMegamorphic();
+  void ConfigurePremonomorphic();
+  void ConfigureMonomorphic(Handle<HeapType> type, Handle<Code> handler);
+
+  void ConfigurePolymorphic(TypeHandleList* types, CodeHandleList* handlers);
+
+  InlineCacheState StateFromFeedback() const OVERRIDE;
+  int ExtractMaps(MapHandleList* maps) const OVERRIDE;
+  MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const OVERRIDE;
+  virtual bool FindHandlers(CodeHandleList* code_list,
+                            int length = -1) const OVERRIDE;
+};
+
+
+class KeyedLoadICNexus : public FeedbackNexus {
+ public:
+  KeyedLoadICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
+      : FeedbackNexus(vector, slot) {
+    DCHECK(vector->GetKind(slot) == Code::KEYED_LOAD_IC);
+  }
+  KeyedLoadICNexus(TypeFeedbackVector* vector, FeedbackVectorICSlot slot)
+      : FeedbackNexus(vector, slot) {
+    DCHECK(vector->GetKind(slot) == Code::KEYED_LOAD_IC);
+  }
+
+  void Clear(Code* host);
+
+  void ConfigureGeneric();
+  void ConfigurePremonomorphic();
+  // name can be a null handle for element loads.
+  void ConfigureMonomorphic(Handle<Name> name, Handle<HeapType> type,
+                            Handle<Code> handler);
+  // name can be null.
+  void ConfigurePolymorphic(Handle<Name> name, TypeHandleList* types,
+                            CodeHandleList* handlers);
+
+  InlineCacheState StateFromFeedback() const OVERRIDE;
+  int ExtractMaps(MapHandleList* maps) const OVERRIDE;
+  MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const OVERRIDE;
+  virtual bool FindHandlers(CodeHandleList* code_list,
+                            int length = -1) const OVERRIDE;
+  Name* FindFirstName() const OVERRIDE;
+};
 }
 }  // namespace v8::internal
 
diff --git a/src/type-info.cc b/src/type-info.cc
index cf3950f..611373f 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -9,11 +9,8 @@
 #include "src/compiler.h"
 #include "src/ic/ic.h"
 #include "src/ic/stub-cache.h"
-#include "src/macro-assembler.h"
 #include "src/type-info.h"
 
-#include "src/objects-inl.h"
-
 namespace v8 {
 namespace internal {
 
@@ -52,9 +49,20 @@
 }
 
 
-Handle<Object> TypeFeedbackOracle::GetInfo(int slot) {
-  DCHECK(slot >= 0 && slot < feedback_vector_->length());
-  Object* obj = feedback_vector_->get(slot);
+Handle<Object> TypeFeedbackOracle::GetInfo(FeedbackVectorSlot slot) {
+  DCHECK(slot.ToInt() >= 0 && slot.ToInt() < feedback_vector_->length());
+  Object* obj = feedback_vector_->Get(slot);
+  if (!obj->IsJSFunction() ||
+      !CanRetainOtherContext(JSFunction::cast(obj), *native_context_)) {
+    return Handle<Object>(obj, isolate());
+  }
+  return Handle<Object>::cast(isolate()->factory()->undefined_value());
+}
+
+
+Handle<Object> TypeFeedbackOracle::GetInfo(FeedbackVectorICSlot slot) {
+  DCHECK(slot.ToInt() >= 0 && slot.ToInt() < feedback_vector_->length());
+  Object* obj = feedback_vector_->Get(slot);
   if (!obj->IsJSFunction() ||
       !CanRetainOtherContext(JSFunction::cast(obj), *native_context_)) {
     return Handle<Object>(obj, isolate());
@@ -73,6 +81,24 @@
 }
 
 
+bool TypeFeedbackOracle::LoadIsUninitialized(FeedbackVectorICSlot slot) {
+  Code::Kind kind = feedback_vector_->GetKind(slot);
+  if (kind == Code::LOAD_IC) {
+    LoadICNexus nexus(feedback_vector_, slot);
+    return nexus.StateFromFeedback() == UNINITIALIZED;
+  } else if (kind == Code::KEYED_LOAD_IC) {
+    KeyedLoadICNexus nexus(feedback_vector_, slot);
+    return nexus.StateFromFeedback() == UNINITIALIZED;
+  } else if (kind == Code::NUMBER_OF_KINDS) {
+    // Code::NUMBER_OF_KINDS indicates a slot that was never even compiled
+    // in full code.
+    return true;
+  }
+
+  return false;
+}
+
+
 bool TypeFeedbackOracle::StoreIsUninitialized(TypeFeedbackId ast_id) {
   Handle<Object> maybe_code = GetInfo(ast_id);
   if (!maybe_code->IsCode()) return false;
@@ -81,24 +107,21 @@
 }
 
 
-bool TypeFeedbackOracle::StoreIsKeyedPolymorphic(TypeFeedbackId ast_id) {
-  Handle<Object> maybe_code = GetInfo(ast_id);
-  if (maybe_code->IsCode()) {
-    Handle<Code> code = Handle<Code>::cast(maybe_code);
-    return code->is_keyed_store_stub() &&
-        code->ic_state() == POLYMORPHIC;
-  }
-  return false;
+bool TypeFeedbackOracle::CallIsUninitialized(FeedbackVectorICSlot slot) {
+  Handle<Object> value = GetInfo(slot);
+  return value->IsUndefined() ||
+         value.is_identical_to(
+             TypeFeedbackVector::UninitializedSentinel(isolate()));
 }
 
 
-bool TypeFeedbackOracle::CallIsMonomorphic(int slot) {
+bool TypeFeedbackOracle::CallIsMonomorphic(FeedbackVectorICSlot slot) {
   Handle<Object> value = GetInfo(slot);
   return value->IsAllocationSite() || value->IsJSFunction();
 }
 
 
-bool TypeFeedbackOracle::CallNewIsMonomorphic(int slot) {
+bool TypeFeedbackOracle::CallNewIsMonomorphic(FeedbackVectorSlot slot) {
   Handle<Object> info = GetInfo(slot);
   return FLAG_pretenuring_call_new
       ? info->IsJSFunction()
@@ -106,7 +129,7 @@
 }
 
 
-byte TypeFeedbackOracle::ForInType(int feedback_vector_slot) {
+byte TypeFeedbackOracle::ForInType(FeedbackVectorSlot feedback_vector_slot) {
   Handle<Object> value = GetInfo(feedback_vector_slot);
   return value.is_identical_to(
              TypeFeedbackVector::UninitializedSentinel(isolate()))
@@ -115,20 +138,41 @@
 }
 
 
-KeyedAccessStoreMode TypeFeedbackOracle::GetStoreMode(
-    TypeFeedbackId ast_id) {
+void TypeFeedbackOracle::GetStoreModeAndKeyType(
+    TypeFeedbackId ast_id, KeyedAccessStoreMode* store_mode,
+    IcCheckType* key_type) {
   Handle<Object> maybe_code = GetInfo(ast_id);
   if (maybe_code->IsCode()) {
     Handle<Code> code = Handle<Code>::cast(maybe_code);
     if (code->kind() == Code::KEYED_STORE_IC) {
-      return KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state());
+      ExtraICState extra_ic_state = code->extra_ic_state();
+      *store_mode = KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state);
+      *key_type = KeyedStoreIC::GetKeyType(extra_ic_state);
+      return;
     }
   }
-  return STANDARD_STORE;
+  *store_mode = STANDARD_STORE;
+  *key_type = ELEMENT;
 }
 
 
-Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(int slot) {
+void TypeFeedbackOracle::GetLoadKeyType(
+    TypeFeedbackId ast_id, IcCheckType* key_type) {
+  Handle<Object> maybe_code = GetInfo(ast_id);
+  if (maybe_code->IsCode()) {
+    Handle<Code> code = Handle<Code>::cast(maybe_code);
+    if (code->kind() == Code::KEYED_LOAD_IC) {
+      ExtraICState extra_ic_state = code->extra_ic_state();
+      *key_type = KeyedLoadIC::GetKeyType(extra_ic_state);
+      return;
+    }
+  }
+  *key_type = ELEMENT;
+}
+
+
+Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(
+    FeedbackVectorICSlot slot) {
   Handle<Object> info = GetInfo(slot);
   if (info->IsAllocationSite()) {
     return Handle<JSFunction>(isolate()->native_context()->array_function());
@@ -138,7 +182,8 @@
 }
 
 
-Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(int slot) {
+Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(
+    FeedbackVectorSlot slot) {
   Handle<Object> info = GetInfo(slot);
   if (FLAG_pretenuring_call_new || info->IsJSFunction()) {
     return Handle<JSFunction>::cast(info);
@@ -149,7 +194,8 @@
 }
 
 
-Handle<AllocationSite> TypeFeedbackOracle::GetCallAllocationSite(int slot) {
+Handle<AllocationSite> TypeFeedbackOracle::GetCallAllocationSite(
+    FeedbackVectorICSlot slot) {
   Handle<Object> info = GetInfo(slot);
   if (info->IsAllocationSite()) {
     return Handle<AllocationSite>::cast(info);
@@ -158,7 +204,8 @@
 }
 
 
-Handle<AllocationSite> TypeFeedbackOracle::GetCallNewAllocationSite(int slot) {
+Handle<AllocationSite> TypeFeedbackOracle::GetCallNewAllocationSite(
+    FeedbackVectorSlot slot) {
   Handle<Object> info = GetInfo(slot);
   if (FLAG_pretenuring_call_new || info->IsAllocationSite()) {
     return Handle<AllocationSite>::cast(info);
@@ -263,15 +310,45 @@
 }
 
 
-void TypeFeedbackOracle::KeyedPropertyReceiverTypes(
-    TypeFeedbackId id, SmallMapList* receiver_types, bool* is_string) {
-  receiver_types->Clear();
-  *is_string = false;
-  if (LoadIsBuiltin(id, Builtins::kKeyedLoadIC_String)) {
-    *is_string = true;
-  } else {
-    CollectReceiverTypes(id, receiver_types);
+bool TypeFeedbackOracle::HasOnlyStringMaps(SmallMapList* receiver_types) {
+  bool all_strings = receiver_types->length() > 0;
+  for (int i = 0; i < receiver_types->length(); i++) {
+    all_strings &= receiver_types->at(i)->IsStringMap();
   }
+  return all_strings;
+}
+
+
+void TypeFeedbackOracle::KeyedPropertyReceiverTypes(
+    TypeFeedbackId id,
+    SmallMapList* receiver_types,
+    bool* is_string,
+    IcCheckType* key_type) {
+  receiver_types->Clear();
+  CollectReceiverTypes(id, receiver_types);
+  *is_string = HasOnlyStringMaps(receiver_types);
+  GetLoadKeyType(id, key_type);
+}
+
+
+void TypeFeedbackOracle::PropertyReceiverTypes(FeedbackVectorICSlot slot,
+                                               Handle<String> name,
+                                               SmallMapList* receiver_types) {
+  receiver_types->Clear();
+  LoadICNexus nexus(feedback_vector_, slot);
+  Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
+  CollectReceiverTypes(&nexus, name, flags, receiver_types);
+}
+
+
+void TypeFeedbackOracle::KeyedPropertyReceiverTypes(
+    FeedbackVectorICSlot slot, SmallMapList* receiver_types, bool* is_string,
+    IcCheckType* key_type) {
+  receiver_types->Clear();
+  KeyedLoadICNexus nexus(feedback_vector_, slot);
+  CollectReceiverTypes<FeedbackNexus>(&nexus, receiver_types);
+  *is_string = HasOnlyStringMaps(receiver_types);
+  *key_type = nexus.FindFirstName() != NULL ? PROPERTY : ELEMENT;
 }
 
 
@@ -285,10 +362,10 @@
 
 void TypeFeedbackOracle::KeyedAssignmentReceiverTypes(
     TypeFeedbackId id, SmallMapList* receiver_types,
-    KeyedAccessStoreMode* store_mode) {
+    KeyedAccessStoreMode* store_mode, IcCheckType* key_type) {
   receiver_types->Clear();
   CollectReceiverTypes(id, receiver_types);
-  *store_mode = GetStoreMode(id);
+  GetStoreModeAndKeyType(id, store_mode, key_type);
 }
 
 
@@ -308,14 +385,21 @@
 
   DCHECK(object->IsCode());
   Handle<Code> code(Handle<Code>::cast(object));
+  CollectReceiverTypes<Code>(*code, name, flags, types);
+}
 
+
+template <class T>
+void TypeFeedbackOracle::CollectReceiverTypes(T* obj, Handle<String> name,
+                                              Code::Flags flags,
+                                              SmallMapList* types) {
   if (FLAG_collect_megamorphic_maps_from_stub_cache &&
-      code->ic_state() == MEGAMORPHIC) {
+      obj->ic_state() == MEGAMORPHIC) {
     types->Reserve(4, zone());
     isolate()->stub_cache()->CollectMatchingMaps(
         types, name, flags, native_context_, zone());
   } else {
-    CollectReceiverTypes(ast_id, types);
+    CollectReceiverTypes<T>(obj, types);
   }
 }
 
@@ -359,12 +443,18 @@
   Handle<Object> object = GetInfo(ast_id);
   if (!object->IsCode()) return;
   Handle<Code> code = Handle<Code>::cast(object);
+  CollectReceiverTypes<Code>(*code, types);
+}
+
+
+template <class T>
+void TypeFeedbackOracle::CollectReceiverTypes(T* obj, SmallMapList* types) {
   MapHandleList maps;
-  if (code->ic_state() == MONOMORPHIC) {
-    Map* map = code->FindFirstMap();
+  if (obj->ic_state() == MONOMORPHIC) {
+    Map* map = obj->FindFirstMap();
     if (map != NULL) maps.Add(handle(map));
-  } else if (code->ic_state() == POLYMORPHIC) {
-    code->FindAllMaps(&maps);
+  } else if (obj->ic_state() == POLYMORPHIC) {
+    obj->FindAllMaps(&maps);
   } else {
     return;
   }
diff --git a/src/type-info.h b/src/type-info.h
index 434ddd6..60f156f 100644
--- a/src/type-info.h
+++ b/src/type-info.h
@@ -24,46 +24,58 @@
                      Handle<Context> native_context, Zone* zone);
 
   bool LoadIsUninitialized(TypeFeedbackId id);
+  bool LoadIsUninitialized(FeedbackVectorICSlot slot);
   bool StoreIsUninitialized(TypeFeedbackId id);
-  bool StoreIsKeyedPolymorphic(TypeFeedbackId id);
-  bool CallIsMonomorphic(int slot);
-  bool CallIsMonomorphic(TypeFeedbackId aid);
+  bool CallIsUninitialized(FeedbackVectorICSlot slot);
+  bool CallIsMonomorphic(FeedbackVectorICSlot slot);
   bool KeyedArrayCallIsHoley(TypeFeedbackId id);
-  bool CallNewIsMonomorphic(int slot);
+  bool CallNewIsMonomorphic(FeedbackVectorSlot slot);
 
   // TODO(1571) We can't use ForInStatement::ForInType as the return value due
   // to various cycles in our headers.
   // TODO(rossberg): once all oracle access is removed from ast.cc, it should
   // be possible.
-  byte ForInType(int feedback_vector_slot);
+  byte ForInType(FeedbackVectorSlot feedback_vector_slot);
 
-  KeyedAccessStoreMode GetStoreMode(TypeFeedbackId id);
+  void GetStoreModeAndKeyType(TypeFeedbackId id,
+                              KeyedAccessStoreMode* store_mode,
+                              IcCheckType* key_type);
+  void GetLoadKeyType(TypeFeedbackId id, IcCheckType* key_type);
 
   void PropertyReceiverTypes(TypeFeedbackId id, Handle<String> name,
                              SmallMapList* receiver_types);
+  void PropertyReceiverTypes(FeedbackVectorICSlot slot, Handle<String> name,
+                             SmallMapList* receiver_types);
   void KeyedPropertyReceiverTypes(TypeFeedbackId id,
                                   SmallMapList* receiver_types,
-                                  bool* is_string);
+                                  bool* is_string,
+                                  IcCheckType* key_type);
+  void KeyedPropertyReceiverTypes(FeedbackVectorICSlot slot,
+                                  SmallMapList* receiver_types, bool* is_string,
+                                  IcCheckType* key_type);
   void AssignmentReceiverTypes(TypeFeedbackId id,
                                Handle<String> name,
                                SmallMapList* receiver_types);
   void KeyedAssignmentReceiverTypes(TypeFeedbackId id,
                                     SmallMapList* receiver_types,
-                                    KeyedAccessStoreMode* store_mode);
+                                    KeyedAccessStoreMode* store_mode,
+                                    IcCheckType* key_type);
   void CountReceiverTypes(TypeFeedbackId id,
                           SmallMapList* receiver_types);
 
   void CollectReceiverTypes(TypeFeedbackId id,
                             SmallMapList* types);
+  template <class T>
+  void CollectReceiverTypes(T* obj, SmallMapList* types);
 
   static bool CanRetainOtherContext(Map* map, Context* native_context);
   static bool CanRetainOtherContext(JSFunction* function,
                                     Context* native_context);
 
-  Handle<JSFunction> GetCallTarget(int slot);
-  Handle<AllocationSite> GetCallAllocationSite(int slot);
-  Handle<JSFunction> GetCallNewTarget(int slot);
-  Handle<AllocationSite> GetCallNewAllocationSite(int slot);
+  Handle<JSFunction> GetCallTarget(FeedbackVectorICSlot slot);
+  Handle<AllocationSite> GetCallAllocationSite(FeedbackVectorICSlot slot);
+  Handle<JSFunction> GetCallNewTarget(FeedbackVectorSlot slot);
+  Handle<AllocationSite> GetCallNewAllocationSite(FeedbackVectorSlot slot);
 
   bool LoadIsBuiltin(TypeFeedbackId id, Builtins::Name builtin_id);
 
@@ -96,6 +108,13 @@
                             Handle<String> name,
                             Code::Flags flags,
                             SmallMapList* types);
+  template <class T>
+  void CollectReceiverTypes(T* obj, Handle<String> name, Code::Flags flags,
+                            SmallMapList* types);
+
+  // Returns true if there is at least one string map and if
+  // all maps are string maps.
+  bool HasOnlyStringMaps(SmallMapList* receiver_types);
 
   void SetInfo(TypeFeedbackId id, Object* target);
 
@@ -113,7 +132,8 @@
 
   // Returns an element from the type feedback vector. Returns undefined
   // if there is no information.
-  Handle<Object> GetInfo(int slot);
+  Handle<Object> GetInfo(FeedbackVectorSlot slot);
+  Handle<Object> GetInfo(FeedbackVectorICSlot slot);
 
  private:
   Handle<Context> native_context_;
diff --git a/src/typedarray.js b/src/typedarray.js
index c149b35..4420bce 100644
--- a/src/typedarray.js
+++ b/src/typedarray.js
@@ -291,6 +291,13 @@
   }
 }
 
+function TypedArrayGetToStringTag() {
+  if (!%IsTypedArray(this)) return;
+  var name = %_ClassOf(this);
+  if (IS_UNDEFINED(name)) return;
+  return name;
+}
+
 // -------------------------------------------------------------------
 
 function SetupTypedArrays() {
@@ -310,7 +317,8 @@
   InstallGetter(global.NAME.prototype, "byteOffset", NAME_GetByteOffset);
   InstallGetter(global.NAME.prototype, "byteLength", NAME_GetByteLength);
   InstallGetter(global.NAME.prototype, "length", NAME_GetLength);
-
+  InstallGetter(global.NAME.prototype, symbolToStringTag,
+                TypedArrayGetToStringTag);
   InstallFunctions(global.NAME.prototype, DONT_ENUM, $Array(
         "subarray", NAMESubArray,
         "set", TypedArraySet
@@ -437,6 +445,8 @@
 
   // Set up constructor property on the DataView prototype.
   %AddNamedProperty($DataView.prototype, "constructor", $DataView, DONT_ENUM);
+  %AddNamedProperty(
+      $DataView.prototype, symbolToStringTag, "DataView", READ_ONLY|DONT_ENUM);
 
   InstallGetter($DataView.prototype, "buffer", DataViewGetBufferJS);
   InstallGetter($DataView.prototype, "byteOffset", DataViewGetByteOffset);
diff --git a/src/types-inl.h b/src/types-inl.h
index 162e658..2e7f8a3 100644
--- a/src/types-inl.h
+++ b/src/types-inl.h
@@ -56,6 +56,13 @@
 
 // static
 template<class T>
+T* ZoneTypeConfig::null_handle() {
+  return NULL;
+}
+
+
+// static
+template<class T>
 T* ZoneTypeConfig::handle(T* type) {
   return type;
 }
@@ -199,6 +206,13 @@
 
 // static
 template<class T>
+i::Handle<T> HeapTypeConfig::null_handle() {
+  return i::Handle<T>();
+}
+
+
+// static
+template<class T>
 i::Handle<T> HeapTypeConfig::handle(T* type) {
   return i::handle(type, i::HeapObject::cast(type)->GetIsolate());
 }
diff --git a/src/types.cc b/src/types.cc
index 8e96d86..c4f1bae 100644
--- a/src/types.cc
+++ b/src/types.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <iomanip>
+
 #include "src/types.h"
 
 #include "src/ostreams.h"
@@ -80,7 +82,7 @@
   if (this->IsBitset()) return BitsetType::Min(this->AsBitset());
   if (this->IsUnion()) {
     double min = +V8_INFINITY;
-    for (int i = 0; i < this->AsUnion()->Length(); ++i) {
+    for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
       min = std::min(min, this->AsUnion()->Get(i)->Min());
     }
     return min;
@@ -98,7 +100,7 @@
   if (this->IsBitset()) return BitsetType::Max(this->AsBitset());
   if (this->IsUnion()) {
     double max = -V8_INFINITY;
-    for (int i = 0; i < this->AsUnion()->Length(); ++i) {
+    for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
       max = std::max(max, this->AsUnion()->Get(i)->Max());
     }
     return max;
@@ -139,7 +141,7 @@
   if (type->IsBitset()) return type->AsBitset();
   if (type->IsUnion()) {
     int bitset = kNone;
-    for (int i = 0; i < type->AsUnion()->Length(); ++i) {
+    for (int i = 0, n = type->AsUnion()->Length(); i < n; ++i) {
       bitset |= type->AsUnion()->Get(i)->BitsetLub();
     }
     return bitset;
@@ -151,9 +153,9 @@
   }
   if (type->IsConstant()) return type->AsConstant()->Bound()->AsBitset();
   if (type->IsRange()) return type->AsRange()->BitsetLub();
-  if (type->IsContext()) return kInternal & kTaggedPtr;
+  if (type->IsContext()) return kInternal & kTaggedPointer;
   if (type->IsArray()) return kArray;
-  if (type->IsFunction()) return kFunction;
+  if (type->IsFunction()) return kOtherObject;  // TODO(rossberg): kFunction
   UNREACHABLE();
   return kNone;
 }
@@ -198,10 +200,10 @@
              map == heap->no_interceptor_result_sentinel_map() ||
              map == heap->termination_exception_map() ||
              map == heap->arguments_marker_map());
-      return kInternal & kTaggedPtr;
+      return kInternal & kTaggedPointer;
     }
     case HEAP_NUMBER_TYPE:
-      return kNumber & kTaggedPtr;
+      return kNumber & kTaggedPointer;
     case JS_VALUE_TYPE:
     case JS_DATE_TYPE:
     case JS_OBJECT_TYPE:
@@ -225,9 +227,9 @@
     case JS_ARRAY_TYPE:
       return kArray;
     case JS_FUNCTION_TYPE:
-      return kFunction;
+      return kOtherObject;  // TODO(rossberg): there should be a Function type.
     case JS_REGEXP_TYPE:
-      return kRegExp;
+      return kOtherObject;  // TODO(rossberg): there should be a RegExp type.
     case JS_PROXY_TYPE:
     case JS_FUNCTION_PROXY_TYPE:
       return kProxy;
@@ -247,9 +249,10 @@
     case SHARED_FUNCTION_INFO_TYPE:
     case ACCESSOR_PAIR_TYPE:
     case FIXED_ARRAY_TYPE:
+    case BYTE_ARRAY_TYPE:
     case FOREIGN_TYPE:
     case CODE_TYPE:
-      return kInternal & kTaggedPtr;
+      return kInternal & kTaggedPointer;
     default:
       UNREACHABLE();
       return kNone;
@@ -262,7 +265,8 @@
 TypeImpl<Config>::BitsetType::Lub(i::Object* value) {
   DisallowHeapAllocation no_allocation;
   if (value->IsNumber()) {
-    return Lub(value->Number()) & (value->IsSmi() ? kTaggedInt : kTaggedPtr);
+    return Lub(value->Number()) &
+        (value->IsSmi() ? kTaggedSigned : kTaggedPointer);
   }
   return Lub(i::HeapObject::cast(value)->map());
 }
@@ -274,73 +278,48 @@
   DisallowHeapAllocation no_allocation;
   if (i::IsMinusZero(value)) return kMinusZero;
   if (std::isnan(value)) return kNaN;
-  if (IsUint32Double(value)) return Lub(FastD2UI(value));
-  if (IsInt32Double(value)) return Lub(FastD2I(value));
-  return kOtherNumber;
-}
-
-
-template<class Config>
-typename TypeImpl<Config>::bitset
-TypeImpl<Config>::BitsetType::Lub(int32_t value) {
-  DisallowHeapAllocation no_allocation;
-  if (value >= 0x40000000) {
-    return i::SmiValuesAre31Bits() ? kOtherUnsigned31 : kUnsignedSmall;
-  }
-  if (value >= 0) return kUnsignedSmall;
-  if (value >= -0x40000000) return kOtherSignedSmall;
-  return i::SmiValuesAre31Bits() ? kOtherSigned32 : kOtherSignedSmall;
-}
-
-
-template<class Config>
-typename TypeImpl<Config>::bitset
-TypeImpl<Config>::BitsetType::Lub(uint32_t value) {
-  DisallowHeapAllocation no_allocation;
-  if (value >= 0x80000000u) return kOtherUnsigned32;
-  if (value >= 0x40000000u) {
-    return i::SmiValuesAre31Bits() ? kOtherUnsigned31 : kUnsignedSmall;
-  }
-  return kUnsignedSmall;
+  if (IsUint32Double(value) || IsInt32Double(value)) return Lub(value, value);
+  return kPlainNumber;
 }
 
 
 // Minimum values of regular numeric bitsets when SmiValuesAre31Bits.
-template<class Config>
+template <class Config>
 const typename TypeImpl<Config>::BitsetType::BitsetMin
-TypeImpl<Config>::BitsetType::BitsetMins31[] = {
-    {kOtherNumber, -V8_INFINITY},
-    {kOtherSigned32, kMinInt},
-    {kOtherSignedSmall, -0x40000000},
-    {kUnsignedSmall, 0},
-    {kOtherUnsigned31, 0x40000000},
-    {kOtherUnsigned32, 0x80000000},
-    {kOtherNumber, static_cast<double>(kMaxUInt32) + 1}
-};
+    TypeImpl<Config>::BitsetType::BitsetMins31[] = {
+        {kOtherNumber, -V8_INFINITY},
+        {kOtherSigned32, kMinInt},
+        {kNegativeSignedSmall, -0x40000000},
+        {kUnsignedSmall, 0},
+        {kOtherUnsigned31, 0x40000000},
+        {kOtherUnsigned32, 0x80000000},
+        {kOtherNumber, static_cast<double>(kMaxUInt32) + 1}};
 
 
 // Minimum values of regular numeric bitsets when SmiValuesAre32Bits.
 // OtherSigned32 and OtherUnsigned31 are empty (see the diagrams in types.h).
-template<class Config>
+template <class Config>
 const typename TypeImpl<Config>::BitsetType::BitsetMin
-TypeImpl<Config>::BitsetType::BitsetMins32[] = {
-    {kOtherNumber, -V8_INFINITY},
-    {kOtherSignedSmall, kMinInt},
-    {kUnsignedSmall, 0},
-    {kOtherUnsigned32, 0x80000000},
-    {kOtherNumber, static_cast<double>(kMaxUInt32) + 1}
-};
+    TypeImpl<Config>::BitsetType::BitsetMins32[] = {
+        {kOtherNumber, -V8_INFINITY},
+        {kNegativeSignedSmall, kMinInt},
+        {kUnsignedSmall, 0},
+        {kOtherUnsigned32, 0x80000000},
+        {kOtherNumber, static_cast<double>(kMaxUInt32) + 1}};
 
 
 template<class Config>
 typename TypeImpl<Config>::bitset
-TypeImpl<Config>::BitsetType::Lub(Limits lim) {
+TypeImpl<Config>::BitsetType::Lub(double min, double max) {
   DisallowHeapAllocation no_allocation;
-  double min = lim.min->Number();
-  double max = lim.max->Number();
   int lub = kNone;
   const BitsetMin* mins = BitsetMins();
 
+  // Make sure the min-max range touches 0, so we are guaranteed no holes
+  // in unions of valid bitsets.
+  if (max < -1) max = -1;
+  if (min > 0) min = 0;
+
   for (size_t i = 1; i < BitsetMinsSize(); ++i) {
     if (min < mins[i].min) {
       lub |= mins[i-1].bits;
@@ -372,7 +351,7 @@
   DisallowHeapAllocation no_allocation;
   DCHECK(Is(bits, kNumber));
   const BitsetMin* mins = BitsetMins();
-  bool mz = bits & kMinusZero;
+  bool mz = SEMANTIC(bits & kMinusZero);
   if (BitsetType::Is(mins[BitsetMinsSize()-1].bits, bits)) {
     return +V8_INFINITY;
   }
@@ -419,7 +398,7 @@
         !this_fun->Receiver()->Equals(that_fun->Receiver())) {
       return false;
     }
-    for (int i = 0; i < this_fun->Arity(); ++i) {
+    for (int i = 0, n = this_fun->Arity(); i < n; ++i) {
       if (!this_fun->Parameter(i)->Equals(that_fun->Parameter(i))) return false;
     }
     return true;
@@ -443,16 +422,15 @@
 
   // (T1 \/ ... \/ Tn) <= T  if  (T1 <= T) /\ ... /\ (Tn <= T)
   if (this->IsUnion()) {
-    UnionHandle unioned = handle(this->AsUnion());
-    for (int i = 0; i < unioned->Length(); ++i) {
-      if (!unioned->Get(i)->Is(that)) return false;
+    for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
+      if (!this->AsUnion()->Get(i)->Is(that)) return false;
     }
     return true;
   }
 
   // T <= (T1 \/ ... \/ Tn)  if  (T <= T1) \/ ... \/ (T <= Tn)
   if (that->IsUnion()) {
-    for (int i = 0; i < that->AsUnion()->Length(); ++i) {
+    for (int i = 0, n = that->AsUnion()->Length(); i < n; ++i) {
       if (this->Is(that->AsUnion()->Get(i))) return true;
       if (i > 1 && this->IsRange()) return false;  // Shortcut.
     }
@@ -465,6 +443,7 @@
             Contains(that->AsRange(), *this->AsConstant()->Value()));
   }
   if (this->IsRange()) return false;
+
   return this->SimplyEquals(that);
 }
 
@@ -507,16 +486,15 @@
 
   // (T1 \/ ... \/ Tn) overlaps T  if  (T1 overlaps T) \/ ... \/ (Tn overlaps T)
   if (this->IsUnion()) {
-    UnionHandle unioned = handle(this->AsUnion());
-    for (int i = 0; i < unioned->Length(); ++i) {
-      if (unioned->Get(i)->Maybe(that)) return true;
+    for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
+      if (this->AsUnion()->Get(i)->Maybe(that)) return true;
     }
     return false;
   }
 
   // T overlaps (T1 \/ ... \/ Tn)  if  (T overlaps T1) \/ ... \/ (T overlaps Tn)
   if (that->IsUnion()) {
-    for (int i = 0; i < that->AsUnion()->Length(); ++i) {
+    for (int i = 0, n = that->AsUnion()->Length(); i < n; ++i) {
       if (this->Maybe(that->AsUnion()->Get(i))) return true;
     }
     return false;
@@ -683,13 +661,13 @@
     TypeHandle lhs, TypeHandle rhs,
     UnionHandle result, int size, Region* region) {
   if (lhs->IsUnion()) {
-    for (int i = 0; i < lhs->AsUnion()->Length(); ++i) {
+    for (int i = 0, n = lhs->AsUnion()->Length(); i < n; ++i) {
       size = IntersectAux(lhs->AsUnion()->Get(i), rhs, result, size, region);
     }
     return size;
   }
   if (rhs->IsUnion()) {
-    for (int i = 0; i < rhs->AsUnion()->Length(); ++i) {
+    for (int i = 0, n = rhs->AsUnion()->Length(); i < n; ++i) {
       size = IntersectAux(lhs, rhs->AsUnion()->Get(i), result, size, region);
     }
     return size;
@@ -793,7 +771,7 @@
     TypeHandle type, UnionHandle result, int size, Region* region) {
   if (type->IsBitset() || type->IsRange()) return size;
   if (type->IsUnion()) {
-    for (int i = 0; i < type->AsUnion()->Length(); ++i) {
+    for (int i = 0, n = type->AsUnion()->Length(); i < n; ++i) {
       size = AddToUnion(type->AsUnion()->Get(i), result, size, region);
     }
     return size;
@@ -834,10 +812,9 @@
   if (this->IsClass()) {
     return 1;
   } else if (this->IsUnion()) {
-    UnionHandle unioned = handle(this->AsUnion());
     int result = 0;
-    for (int i = 0; i < unioned->Length(); ++i) {
-      if (unioned->Get(i)->IsClass()) ++result;
+    for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
+      if (this->AsUnion()->Get(i)->IsClass()) ++result;
     }
     return result;
   } else {
@@ -852,10 +829,9 @@
   if (this->IsConstant()) {
     return 1;
   } else if (this->IsUnion()) {
-    UnionHandle unioned = handle(this->AsUnion());
     int result = 0;
-    for (int i = 0; i < unioned->Length(); ++i) {
-      if (unioned->Get(i)->IsConstant()) ++result;
+    for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
+      if (this->AsUnion()->Get(i)->IsConstant()) ++result;
     }
     return result;
   } else {
@@ -917,9 +893,8 @@
   DisallowHeapAllocation no_allocation;
   ++index_;
   if (type_->IsUnion()) {
-    UnionHandle unioned = Config::template cast<UnionType>(type_);
-    for (; index_ < unioned->Length(); ++index_) {
-      if (matches(unioned->Get(index_))) return;
+    for (int n = type_->AsUnion()->Length(); index_ < n; ++index_) {
+      if (matches(type_->AsUnion()->Get(index_))) return;
     }
   } else if (index_ == 0 && matches(type_)) {
     return;
@@ -1000,7 +975,7 @@
 
 
 template <class Config>
-void TypeImpl<Config>::BitsetType::Print(OStream& os,  // NOLINT
+void TypeImpl<Config>::BitsetType::Print(std::ostream& os,  // NOLINT
                                          bitset bits) {
   DisallowHeapAllocation no_allocation;
   const char* name = Name(bits);
@@ -1015,6 +990,7 @@
 #undef BITSET_CONSTANT
 
 #define BITSET_CONSTANT(type, value) SEMANTIC(k##type),
+      INTERNAL_BITSET_TYPE_LIST(BITSET_CONSTANT)
       SEMANTIC_BITSET_TYPE_LIST(BITSET_CONSTANT)
 #undef BITSET_CONSTANT
   };
@@ -1036,7 +1012,7 @@
 
 
 template <class Config>
-void TypeImpl<Config>::PrintTo(OStream& os, PrintDimension dim) {  // NOLINT
+void TypeImpl<Config>::PrintTo(std::ostream& os, PrintDimension dim) {
   DisallowHeapAllocation no_allocation;
   if (dim != REPRESENTATION_DIM) {
     if (this->IsBitset()) {
@@ -1046,20 +1022,22 @@
       BitsetType::New(BitsetType::Lub(this))->PrintTo(os, dim);
       os << ")";
     } else if (this->IsConstant()) {
-      os << "Constant(" << static_cast<void*>(*this->AsConstant()->Value())
-         << ")";
+      os << "Constant(" << Brief(*this->AsConstant()->Value()) << ")";
     } else if (this->IsRange()) {
-      os << "Range(" << this->AsRange()->Min()->Number()
-         << ", " << this->AsRange()->Max()->Number() << ")";
+      std::ostream::fmtflags saved_flags = os.setf(std::ios::fixed);
+      std::streamsize saved_precision = os.precision(0);
+      os << "Range(" << this->AsRange()->Min()->Number() << ", "
+         << this->AsRange()->Max()->Number() << ")";
+      os.flags(saved_flags);
+      os.precision(saved_precision);
     } else if (this->IsContext()) {
       os << "Context(";
       this->AsContext()->Outer()->PrintTo(os, dim);
       os << ")";
     } else if (this->IsUnion()) {
       os << "(";
-      UnionHandle unioned = handle(this->AsUnion());
-      for (int i = 0; i < unioned->Length(); ++i) {
-        TypeHandle type_i = unioned->Get(i);
+      for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
+        TypeHandle type_i = this->AsUnion()->Get(i);
         if (i > 0) os << " | ";
         type_i->PrintTo(os, dim);
       }
@@ -1096,13 +1074,13 @@
 void TypeImpl<Config>::Print() {
   OFStream os(stdout);
   PrintTo(os);
-  os << endl;
+  os << std::endl;
 }
 template <class Config>
 void TypeImpl<Config>::BitsetType::Print(bitset bits) {
   OFStream os(stdout);
   Print(os, bits);
-  os << endl;
+  os << std::endl;
 }
 #endif
 
diff --git a/src/types.h b/src/types.h
index e7815ed..4b7d8ba 100644
--- a/src/types.h
+++ b/src/types.h
@@ -154,75 +154,90 @@
 // Values for bitset types
 
 #define MASK_BITSET_TYPE_LIST(V) \
-  V(Representation, 0xff800000u) \
-  V(Semantic,       0x007ffffeu)
+  V(Representation, 0xfff00000u) \
+  V(Semantic,       0x000ffffeu)
 
 #define REPRESENTATION(k) ((k) & BitsetType::kRepresentation)
 #define SEMANTIC(k)       ((k) & BitsetType::kSemantic)
 
-#define REPRESENTATION_BITSET_TYPE_LIST(V) \
-  V(None,             0)                   \
-  V(UntaggedInt1,     1u << 23 | kSemantic) \
-  V(UntaggedInt8,     1u << 24 | kSemantic) \
-  V(UntaggedInt16,    1u << 25 | kSemantic) \
-  V(UntaggedInt32,    1u << 26 | kSemantic) \
-  V(UntaggedFloat32,  1u << 27 | kSemantic) \
-  V(UntaggedFloat64,  1u << 28 | kSemantic) \
-  V(UntaggedPtr,      1u << 29 | kSemantic) \
-  V(TaggedInt,        1u << 30 | kSemantic) \
-  V(TaggedPtr,        1u << 31 | kSemantic) \
+#define REPRESENTATION_BITSET_TYPE_LIST(V)    \
+  V(None,               0)                    \
+  V(UntaggedBit,        1u << 20 | kSemantic) \
+  V(UntaggedSigned8,    1u << 21 | kSemantic) \
+  V(UntaggedSigned16,   1u << 22 | kSemantic) \
+  V(UntaggedSigned32,   1u << 23 | kSemantic) \
+  V(UntaggedUnsigned8,  1u << 24 | kSemantic) \
+  V(UntaggedUnsigned16, 1u << 25 | kSemantic) \
+  V(UntaggedUnsigned32, 1u << 26 | kSemantic) \
+  V(UntaggedFloat32,    1u << 27 | kSemantic) \
+  V(UntaggedFloat64,    1u << 28 | kSemantic) \
+  V(UntaggedPointer,    1u << 29 | kSemantic) \
+  V(TaggedSigned,       1u << 30 | kSemantic) \
+  V(TaggedPointer,      1u << 31 | kSemantic) \
   \
-  V(UntaggedInt,      kUntaggedInt1 | kUntaggedInt8 |      \
-                      kUntaggedInt16 | kUntaggedInt32)     \
-  V(UntaggedFloat,    kUntaggedFloat32 | kUntaggedFloat64) \
-  V(UntaggedNumber,   kUntaggedInt | kUntaggedFloat)       \
-  V(Untagged,         kUntaggedNumber | kUntaggedPtr)      \
-  V(Tagged,           kTaggedInt | kTaggedPtr)
+  V(UntaggedSigned,     kUntaggedSigned8 | kUntaggedSigned16 |              \
+                        kUntaggedSigned32)                                  \
+  V(UntaggedUnsigned,   kUntaggedUnsigned8 | kUntaggedUnsigned16 |          \
+                        kUntaggedUnsigned32)                                \
+  V(UntaggedIntegral8,  kUntaggedSigned8 | kUntaggedUnsigned8)              \
+  V(UntaggedIntegral16, kUntaggedSigned16 | kUntaggedUnsigned16)            \
+  V(UntaggedIntegral32, kUntaggedSigned32 | kUntaggedUnsigned32)            \
+  V(UntaggedIntegral,   kUntaggedBit | kUntaggedSigned | kUntaggedUnsigned) \
+  V(UntaggedFloat,      kUntaggedFloat32 | kUntaggedFloat64)                \
+  V(UntaggedNumber,     kUntaggedIntegral | kUntaggedFloat)                 \
+  V(Untagged,           kUntaggedNumber | kUntaggedPointer)                 \
+  V(Tagged,             kTaggedSigned | kTaggedPointer)
+
+#define INTERNAL_BITSET_TYPE_LIST(V)                                      \
+  V(OtherUnsigned31, 1u << 1 | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(OtherUnsigned32, 1u << 2 | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(OtherSigned32,   1u << 3 | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(OtherNumber,     1u << 4 | REPRESENTATION(kTagged | kUntaggedNumber))
 
 #define SEMANTIC_BITSET_TYPE_LIST(V) \
-  V(Null,                1u << 1  | REPRESENTATION(kTaggedPtr)) \
-  V(Undefined,           1u << 2  | REPRESENTATION(kTaggedPtr)) \
-  V(Boolean,             1u << 3  | REPRESENTATION(kTaggedPtr)) \
-  V(UnsignedSmall,       1u << 4  | REPRESENTATION(kTagged | kUntaggedNumber)) \
-  V(OtherSignedSmall,    1u << 5  | REPRESENTATION(kTagged | kUntaggedNumber)) \
-  V(OtherUnsigned31,     1u << 6  | REPRESENTATION(kTagged | kUntaggedNumber)) \
-  V(OtherUnsigned32,     1u << 7  | REPRESENTATION(kTagged | kUntaggedNumber)) \
-  V(OtherSigned32,       1u << 8  | REPRESENTATION(kTagged | kUntaggedNumber)) \
-  V(MinusZero,           1u << 9  | REPRESENTATION(kTagged | kUntaggedNumber)) \
-  V(NaN,                 1u << 10 | REPRESENTATION(kTagged | kUntaggedNumber)) \
-  V(OtherNumber,         1u << 11 | REPRESENTATION(kTagged | kUntaggedNumber)) \
-  V(Symbol,              1u << 12 | REPRESENTATION(kTaggedPtr)) \
-  V(InternalizedString,  1u << 13 | REPRESENTATION(kTaggedPtr)) \
-  V(OtherString,         1u << 14 | REPRESENTATION(kTaggedPtr)) \
-  V(Undetectable,        1u << 15 | REPRESENTATION(kTaggedPtr)) \
-  V(Array,               1u << 16 | REPRESENTATION(kTaggedPtr)) \
-  V(Buffer,              1u << 17 | REPRESENTATION(kTaggedPtr)) \
-  V(Function,            1u << 18 | REPRESENTATION(kTaggedPtr)) \
-  V(RegExp,              1u << 19 | REPRESENTATION(kTaggedPtr)) \
-  V(OtherObject,         1u << 20 | REPRESENTATION(kTaggedPtr)) \
-  V(Proxy,               1u << 21 | REPRESENTATION(kTaggedPtr)) \
-  V(Internal,            1u << 22 | REPRESENTATION(kTagged | kUntagged)) \
+  V(NegativeSignedSmall, 1u << 5  | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(Null,                1u << 6  | REPRESENTATION(kTaggedPointer)) \
+  V(Undefined,           1u << 7  | REPRESENTATION(kTaggedPointer)) \
+  V(Boolean,             1u << 8  | REPRESENTATION(kTaggedPointer)) \
+  V(UnsignedSmall,       1u << 9  | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(MinusZero,           1u << 10 | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(NaN,                 1u << 11 | REPRESENTATION(kTagged | kUntaggedNumber)) \
+  V(Symbol,              1u << 12 | REPRESENTATION(kTaggedPointer)) \
+  V(InternalizedString,  1u << 13 | REPRESENTATION(kTaggedPointer)) \
+  V(OtherString,         1u << 14 | REPRESENTATION(kTaggedPointer)) \
+  V(Undetectable,        1u << 15 | REPRESENTATION(kTaggedPointer)) \
+  V(Array,               1u << 16 | REPRESENTATION(kTaggedPointer)) \
+  V(OtherObject,         1u << 17 | REPRESENTATION(kTaggedPointer)) \
+  V(Proxy,               1u << 18 | REPRESENTATION(kTaggedPointer)) \
+  V(Internal,            1u << 19 | REPRESENTATION(kTagged | kUntagged)) \
   \
-  V(SignedSmall,         kUnsignedSmall | kOtherSignedSmall) \
+  V(SignedSmall,         kUnsignedSmall | kNegativeSignedSmall) \
   V(Signed32,            kSignedSmall | kOtherUnsigned31 | kOtherSigned32) \
+  V(NegativeSigned32,    kNegativeSignedSmall | kOtherSigned32) \
+  V(NonNegativeSigned32, kUnsignedSmall | kOtherUnsigned31) \
   V(Unsigned32,          kUnsignedSmall | kOtherUnsigned31 | kOtherUnsigned32) \
   V(Integral32,          kSigned32 | kUnsigned32) \
-  V(OrderedNumber,       kIntegral32 | kMinusZero | kOtherNumber) \
+  V(PlainNumber,         kIntegral32 | kOtherNumber) \
+  V(OrderedNumber,       kPlainNumber | kMinusZero) \
   V(Number,              kOrderedNumber | kNaN) \
   V(String,              kInternalizedString | kOtherString) \
   V(UniqueName,          kSymbol | kInternalizedString) \
   V(Name,                kSymbol | kString) \
   V(NumberOrString,      kNumber | kString) \
-  V(Primitive,           kNumber | kName | kBoolean | kNull | kUndefined) \
-  V(DetectableObject,    kArray | kFunction | kRegExp | kOtherObject) \
+  V(PlainPrimitive,      kNumberOrString | kBoolean | kNull | kUndefined) \
+  V(Primitive,           kSymbol | kPlainPrimitive) \
+  V(DetectableObject,    kArray | kOtherObject) \
   V(DetectableReceiver,  kDetectableObject | kProxy) \
   V(Detectable,          kDetectableReceiver | kNumber | kName) \
   V(Object,              kDetectableObject | kUndetectable) \
   V(Receiver,            kObject | kProxy) \
-  V(NonNumber,           kBoolean | kName | kNull | kReceiver | \
-                         kUndefined | kInternal) \
+  V(StringOrReceiver,    kString | kReceiver) \
+  V(Unique,              kBoolean | kUniqueName | kNull | kUndefined | \
+                         kReceiver) \
+  V(NonNumber,           kUnique | kString | kInternal) \
   V(Any,                 0xfffffffeu)
 
+
 /*
  * The following diagrams show how integers (in the mathematical sense) are
  * divided among the different atomic numerical types.
@@ -242,15 +257,20 @@
  *
  * E.g., OtherUnsigned32 (OU32) covers all integers from 2^31 to 2^32-1.
  *
+ * NOTE: OtherSigned32 (OS32) and OU31 (OtherUnsigned31) are empty if Smis are
+ *       32-bit wide.  They should thus never be used directly, only indirectly
+ *       via e.g. Number.
  */
 
 #define PROPER_BITSET_TYPE_LIST(V) \
   REPRESENTATION_BITSET_TYPE_LIST(V) \
   SEMANTIC_BITSET_TYPE_LIST(V)
 
-#define BITSET_TYPE_LIST(V) \
-  MASK_BITSET_TYPE_LIST(V) \
-  PROPER_BITSET_TYPE_LIST(V)
+#define BITSET_TYPE_LIST(V)          \
+  MASK_BITSET_TYPE_LIST(V)           \
+  REPRESENTATION_BITSET_TYPE_LIST(V) \
+  INTERNAL_BITSET_TYPE_LIST(V)       \
+  SEMANTIC_BITSET_TYPE_LIST(V)
 
 
 // -----------------------------------------------------------------------------
@@ -262,6 +282,7 @@
 //   typedef Struct;
 //   typedef Region;
 //   template<class> struct Handle { typedef type; }  // No template typedefs...
+//   template<class T> static Handle<T>::type null_handle();
 //   template<class T> static Handle<T>::type handle(T* t);  // !is_bitset(t)
 //   template<class T> static Handle<T>::type cast(Handle<Type>::type);
 //   static bool is_bitset(Type*);
@@ -372,6 +393,12 @@
 
   static TypeHandle Union(TypeHandle type1, TypeHandle type2, Region* reg);
   static TypeHandle Intersect(TypeHandle type1, TypeHandle type2, Region* reg);
+  static TypeImpl* Union(TypeImpl* type1, TypeImpl* type2) {
+    return BitsetType::New(type1->AsBitset() | type2->AsBitset());
+  }
+  static TypeImpl* Intersect(TypeImpl* type1, TypeImpl* type2) {
+    return BitsetType::New(type1->AsBitset() & type2->AsBitset());
+  }
 
   static TypeHandle Of(double value, Region* region) {
     return Config::from_bitset(BitsetType::Lub(value), region);
@@ -453,6 +480,11 @@
   double Min();
   double Max();
 
+  // Extracts a range from the type. If the type is a range, it just
+  // returns it; if it is a union, it returns the range component.
+  // Note that it does not contain range for constants.
+  RangeType* GetRange();
+
   int NumClasses();
   int NumConstants();
 
@@ -478,7 +510,7 @@
 
   enum PrintDimension { BOTH_DIMS, SEMANTIC_DIM, REPRESENTATION_DIM };
 
-  void PrintTo(OStream& os, PrintDimension dim = BOTH_DIMS);  // NOLINT
+  void PrintTo(std::ostream& os, PrintDimension dim = BOTH_DIMS);  // NOLINT
 
 #ifdef DEBUG
   void Print();
@@ -540,7 +572,6 @@
   static bool Contains(RangeType* lhs, RangeType* rhs);
   static bool Contains(RangeType* range, i::Object* val);
 
-  RangeType* GetRange();
   static int UpdateRange(
       RangeHandle type, UnionHandle result, int size, Region* region);
 
@@ -576,6 +607,20 @@
 
   static TypeImpl* New(bitset bits) {
     DCHECK(bits == kNone || IsInhabited(bits));
+
+    if (FLAG_enable_slow_asserts) {
+      // Check that the bitset does not contain any holes in number ranges.
+      bitset mask = kSemantic;
+      if (!i::SmiValuesAre31Bits()) {
+        mask &= ~(kOtherUnsigned31 | kOtherSigned32);
+      }
+      bitset number_bits = bits & kPlainNumber & mask;
+      if (number_bits != 0) {
+        bitset lub = Lub(Min(number_bits), Max(number_bits)) & mask;
+        CHECK(lub == number_bits);
+      }
+    }
+
     return Config::from_bitset(bits);
   }
   static TypeHandle New(bitset bits, Region* region) {
@@ -598,15 +643,13 @@
 
   static bitset Glb(TypeImpl* type);  // greatest lower bound that's a bitset
   static bitset Lub(TypeImpl* type);  // least upper bound that's a bitset
+  static bitset Lub(i::Map* map);
   static bitset Lub(i::Object* value);
   static bitset Lub(double value);
-  static bitset Lub(int32_t value);
-  static bitset Lub(uint32_t value);
-  static bitset Lub(i::Map* map);
-  static bitset Lub(Limits lim);
+  static bitset Lub(double min, double max);
 
   static const char* Name(bitset);
-  static void Print(OStream& os, bitset);  // NOLINT
+  static void Print(std::ostream& os, bitset);  // NOLINT
 #ifdef DEBUG
   static void Print(bitset);
 #endif
@@ -778,10 +821,12 @@
 
   static RangeHandle New(
       i::Handle<i::Object> min, i::Handle<i::Object> max, Region* region) {
+    DCHECK(IsInteger(min->Number()) && IsInteger(max->Number()));
     DCHECK(min->Number() <= max->Number());
     RangeHandle type = Config::template cast<RangeType>(
         StructuralType::New(StructuralType::kRangeTag, 3, region));
-    type->Set(0, BitsetType::New(BitsetType::Lub(Limits(min, max)), region));
+    type->Set(0, BitsetType::New(
+        BitsetType::Lub(min->Number(), max->Number()), region));
     type->SetValue(1, min);
     type->SetValue(2, max);
     return type;
@@ -910,6 +955,7 @@
   typedef i::Zone Region;
   template<class T> struct Handle { typedef T* type; };
 
+  template<class T> static inline T* null_handle();
   template<class T> static inline T* handle(T* type);
   template<class T> static inline T* cast(Type* type);
 
@@ -952,6 +998,7 @@
   typedef i::Isolate Region;
   template<class T> struct Handle { typedef i::Handle<T> type; };
 
+  template<class T> static inline i::Handle<T> null_handle();
   template<class T> static inline i::Handle<T> handle(T* type);
   template<class T> static inline i::Handle<T> cast(i::Handle<Type> type);
 
@@ -1000,7 +1047,9 @@
   TypeHandle lower;
   TypeHandle upper;
 
-  BoundsImpl() {}
+  BoundsImpl() :  // Make sure accessing uninitialized bounds crashes big-time.
+    lower(Config::template null_handle<Type>()),
+    upper(Config::template null_handle<Type>()) {}
   explicit BoundsImpl(TypeHandle t) : lower(t), upper(t) {}
   BoundsImpl(TypeHandle l, TypeHandle u) : lower(l), upper(u) {
     DCHECK(lower->Is(upper));
@@ -1016,7 +1065,7 @@
     TypeHandle lower = Type::Union(b1.lower, b2.lower, region);
     TypeHandle upper = Type::Intersect(b1.upper, b2.upper, region);
     // Lower bounds are considered approximate, correct as necessary.
-    lower = Type::Intersect(lower, upper, region);
+    if (!lower->Is(upper)) lower = upper;
     return BoundsImpl(lower, upper);
   }
 
@@ -1028,14 +1077,16 @@
   }
 
   static BoundsImpl NarrowLower(BoundsImpl b, TypeHandle t, Region* region) {
-    // Lower bounds are considered approximate, correct as necessary.
-    t = Type::Intersect(t, b.upper, region);
     TypeHandle lower = Type::Union(b.lower, t, region);
+    // Lower bounds are considered approximate, correct as necessary.
+    if (!lower->Is(b.upper)) lower = b.upper;
     return BoundsImpl(lower, b.upper);
   }
   static BoundsImpl NarrowUpper(BoundsImpl b, TypeHandle t, Region* region) {
-    TypeHandle lower = Type::Intersect(b.lower, t, region);
+    TypeHandle lower = b.lower;
     TypeHandle upper = Type::Intersect(b.upper, t, region);
+    // Lower bounds are considered approximate, correct as necessary.
+    if (!lower->Is(upper)) lower = upper;
     return BoundsImpl(lower, upper);
   }
 
diff --git a/src/typing.cc b/src/typing.cc
index 02c9603..17deb6d 100644
--- a/src/typing.cc
+++ b/src/typing.cc
@@ -56,7 +56,7 @@
     var->name()->Print(os);
     os << " : " << Brief(value) << " -> ";
     type->PrintTo(os);
-    os << endl;
+    os << std::endl;
   }
 #endif  // OBJECT_PRINT
 
@@ -394,7 +394,8 @@
 
 
 void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
-  NarrowType(expr, Bounds(Type::RegExp(zone())));
+  // TODO(rossberg): Reintroduce RegExp type.
+  NarrowType(expr, Bounds(Type::Object(zone())));
 }
 
 
@@ -444,9 +445,11 @@
         oracle()->AssignmentReceiverTypes(id, name, expr->GetReceiverTypes());
       } else {
         KeyedAccessStoreMode store_mode;
-        oracle()->KeyedAssignmentReceiverTypes(
-            id, expr->GetReceiverTypes(), &store_mode);
+        IcCheckType key_type;
+        oracle()->KeyedAssignmentReceiverTypes(id, expr->GetReceiverTypes(),
+                                               &store_mode, &key_type);
         expr->set_store_mode(store_mode);
+        expr->set_key_type(key_type);
       }
     }
   }
@@ -482,19 +485,38 @@
 
 void AstTyper::VisitProperty(Property* expr) {
   // Collect type feedback.
-  TypeFeedbackId id = expr->PropertyFeedbackId();
-  expr->set_is_uninitialized(oracle()->LoadIsUninitialized(id));
+  FeedbackVectorICSlot slot(FeedbackVectorICSlot::Invalid());
+  TypeFeedbackId id(TypeFeedbackId::None());
+  if (FLAG_vector_ics) {
+    slot = expr->PropertyFeedbackSlot();
+    expr->set_is_uninitialized(oracle()->LoadIsUninitialized(slot));
+  } else {
+    id = expr->PropertyFeedbackId();
+    expr->set_is_uninitialized(oracle()->LoadIsUninitialized(id));
+  }
+
   if (!expr->IsUninitialized()) {
     if (expr->key()->IsPropertyName()) {
       Literal* lit_key = expr->key()->AsLiteral();
       DCHECK(lit_key != NULL && lit_key->value()->IsString());
       Handle<String> name = Handle<String>::cast(lit_key->value());
-      oracle()->PropertyReceiverTypes(id, name, expr->GetReceiverTypes());
+      if (FLAG_vector_ics) {
+        oracle()->PropertyReceiverTypes(slot, name, expr->GetReceiverTypes());
+      } else {
+        oracle()->PropertyReceiverTypes(id, name, expr->GetReceiverTypes());
+      }
     } else {
       bool is_string;
-      oracle()->KeyedPropertyReceiverTypes(
-          id, expr->GetReceiverTypes(), &is_string);
+      IcCheckType key_type;
+      if (FLAG_vector_ics) {
+        oracle()->KeyedPropertyReceiverTypes(slot, expr->GetReceiverTypes(),
+                                             &is_string, &key_type);
+      } else {
+        oracle()->KeyedPropertyReceiverTypes(id, expr->GetReceiverTypes(),
+                                             &is_string, &key_type);
+      }
       expr->set_is_string_access(is_string);
+      expr->set_key_type(key_type);
     }
   }
 
@@ -508,15 +530,20 @@
 void AstTyper::VisitCall(Call* expr) {
   // Collect type feedback.
   RECURSE(Visit(expr->expression()));
-  if (!expr->expression()->IsProperty() &&
-      expr->IsUsingCallFeedbackSlot(isolate()) &&
-      oracle()->CallIsMonomorphic(expr->CallFeedbackSlot())) {
-    expr->set_target(oracle()->GetCallTarget(expr->CallFeedbackSlot()));
-    Handle<AllocationSite> site =
-        oracle()->GetCallAllocationSite(expr->CallFeedbackSlot());
-    expr->set_allocation_site(site);
+  bool is_uninitialized = true;
+  if (expr->IsUsingCallFeedbackSlot(isolate())) {
+    FeedbackVectorICSlot slot = expr->CallFeedbackSlot();
+    is_uninitialized = oracle()->CallIsUninitialized(slot);
+    if (!expr->expression()->IsProperty() &&
+        oracle()->CallIsMonomorphic(slot)) {
+      expr->set_target(oracle()->GetCallTarget(slot));
+      Handle<AllocationSite> site = oracle()->GetCallAllocationSite(slot);
+      expr->set_allocation_site(site);
+    }
   }
 
+  expr->set_is_uninitialized(is_uninitialized);
+
   ZoneList<Expression*>* args = expr->arguments();
   for (int i = 0; i < args->length(); ++i) {
     Expression* arg = args->at(i);
@@ -587,7 +614,11 @@
 void AstTyper::VisitCountOperation(CountOperation* expr) {
   // Collect type feedback.
   TypeFeedbackId store_id = expr->CountStoreFeedbackId();
-  expr->set_store_mode(oracle()->GetStoreMode(store_id));
+  KeyedAccessStoreMode store_mode;
+  IcCheckType key_type;
+  oracle()->GetStoreModeAndKeyType(store_id, &store_mode, &key_type);
+  expr->set_store_mode(store_mode);
+  expr->set_key_type(key_type);
   oracle()->CountReceiverTypes(store_id, expr->GetReceiverTypes());
   expr->set_type(oracle()->CountType(expr->CountBinOpFeedbackId()));
   // TODO(rossberg): merge the count type with the generic expression type.
diff --git a/src/typing.h b/src/typing.h
index 6f6b0dc..b56c878 100644
--- a/src/typing.h
+++ b/src/typing.h
@@ -72,10 +72,10 @@
            var->IsParameter() ? parameter_index(var->index()) : kNoVar;
   }
 
-  void VisitDeclarations(ZoneList<Declaration*>* declarations);
-  void VisitStatements(ZoneList<Statement*>* statements);
+  void VisitDeclarations(ZoneList<Declaration*>* declarations) OVERRIDE;
+  void VisitStatements(ZoneList<Statement*>* statements) OVERRIDE;
 
-#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node) OVERRIDE;
   AST_NODE_LIST(DECLARE_VISIT)
 #undef DECLARE_VISIT
 
diff --git a/src/unicode-decoder.cc b/src/unicode-decoder.cc
new file mode 100644
index 0000000..88eff3a
--- /dev/null
+++ b/src/unicode-decoder.cc
@@ -0,0 +1,78 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+#include "src/unicode-inl.h"
+#include "src/unicode-decoder.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+namespace unibrow {
+
+void Utf8DecoderBase::Reset(uint16_t* buffer, unsigned buffer_length,
+                            const uint8_t* stream, unsigned stream_length) {
+  // Assume everything will fit in the buffer and stream won't be needed.
+  last_byte_of_buffer_unused_ = false;
+  unbuffered_start_ = NULL;
+  bool writing_to_buffer = true;
+  // Loop until stream is read, writing to buffer as long as buffer has space.
+  unsigned utf16_length = 0;
+  while (stream_length != 0) {
+    unsigned cursor = 0;
+    uint32_t character = Utf8::ValueOf(stream, stream_length, &cursor);
+    DCHECK(cursor > 0 && cursor <= stream_length);
+    stream += cursor;
+    stream_length -= cursor;
+    bool is_two_characters = character > Utf16::kMaxNonSurrogateCharCode;
+    utf16_length += is_two_characters ? 2 : 1;
+    // Don't need to write to the buffer, but still need utf16_length.
+    if (!writing_to_buffer) continue;
+    // Write out the characters to the buffer.
+    // Must check for equality with buffer_length as we've already updated it.
+    if (utf16_length <= buffer_length) {
+      if (is_two_characters) {
+        *buffer++ = Utf16::LeadSurrogate(character);
+        *buffer++ = Utf16::TrailSurrogate(character);
+      } else {
+        *buffer++ = character;
+      }
+      if (utf16_length == buffer_length) {
+        // Just wrote last character of buffer
+        writing_to_buffer = false;
+        unbuffered_start_ = stream;
+      }
+      continue;
+    }
+    // Have gone over buffer.
+    // Last char of buffer is unused, set cursor back.
+    DCHECK(is_two_characters);
+    writing_to_buffer = false;
+    last_byte_of_buffer_unused_ = true;
+    unbuffered_start_ = stream - cursor;
+  }
+  utf16_length_ = utf16_length;
+}
+
+
+void Utf8DecoderBase::WriteUtf16Slow(const uint8_t* stream, uint16_t* data,
+                                     unsigned data_length) {
+  while (data_length != 0) {
+    unsigned cursor = 0;
+    uint32_t character = Utf8::ValueOf(stream, Utf8::kMaxEncodedSize, &cursor);
+    // There's a total lack of bounds checking for stream
+    // as it was already done in Reset.
+    stream += cursor;
+    if (character > unibrow::Utf16::kMaxNonSurrogateCharCode) {
+      *data++ = Utf16::LeadSurrogate(character);
+      *data++ = Utf16::TrailSurrogate(character);
+      DCHECK(data_length > 1);
+      data_length -= 2;
+    } else {
+      *data++ = character;
+      data_length -= 1;
+    }
+  }
+}
+
+}  // namespace unibrow
diff --git a/src/unicode-decoder.h b/src/unicode-decoder.h
new file mode 100644
index 0000000..35ea30c
--- /dev/null
+++ b/src/unicode-decoder.h
@@ -0,0 +1,121 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UNICODE_DECODER_H_
+#define V8_UNICODE_DECODER_H_
+
+#include <sys/types.h>
+#include "src/globals.h"
+
+namespace unibrow {
+
+class Utf8DecoderBase {
+ public:
+  // Initialization done in subclass.
+  inline Utf8DecoderBase();
+  inline Utf8DecoderBase(uint16_t* buffer, unsigned buffer_length,
+                         const uint8_t* stream, unsigned stream_length);
+  inline unsigned Utf16Length() const { return utf16_length_; }
+
+ protected:
+  // This reads all characters and sets the utf16_length_.
+  // The first buffer_length utf16 chars are cached in the buffer.
+  void Reset(uint16_t* buffer, unsigned buffer_length, const uint8_t* stream,
+             unsigned stream_length);
+  static void WriteUtf16Slow(const uint8_t* stream, uint16_t* data,
+                             unsigned length);
+  const uint8_t* unbuffered_start_;
+  unsigned utf16_length_;
+  bool last_byte_of_buffer_unused_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Utf8DecoderBase);
+};
+
+template <unsigned kBufferSize>
+class Utf8Decoder : public Utf8DecoderBase {
+ public:
+  inline Utf8Decoder() {}
+  inline Utf8Decoder(const char* stream, unsigned length);
+  inline void Reset(const char* stream, unsigned length);
+  inline unsigned WriteUtf16(uint16_t* data, unsigned length) const;
+
+ private:
+  uint16_t buffer_[kBufferSize];
+};
+
+
+Utf8DecoderBase::Utf8DecoderBase()
+    : unbuffered_start_(NULL),
+      utf16_length_(0),
+      last_byte_of_buffer_unused_(false) {}
+
+
+Utf8DecoderBase::Utf8DecoderBase(uint16_t* buffer, unsigned buffer_length,
+                                 const uint8_t* stream,
+                                 unsigned stream_length) {
+  Reset(buffer, buffer_length, stream, stream_length);
+}
+
+
+template <unsigned kBufferSize>
+Utf8Decoder<kBufferSize>::Utf8Decoder(const char* stream, unsigned length)
+    : Utf8DecoderBase(buffer_, kBufferSize,
+                      reinterpret_cast<const uint8_t*>(stream), length) {}
+
+
+template <unsigned kBufferSize>
+void Utf8Decoder<kBufferSize>::Reset(const char* stream, unsigned length) {
+  Utf8DecoderBase::Reset(buffer_, kBufferSize,
+                         reinterpret_cast<const uint8_t*>(stream), length);
+}
+
+
+template <unsigned kBufferSize>
+unsigned Utf8Decoder<kBufferSize>::WriteUtf16(uint16_t* data,
+                                              unsigned length) const {
+  DCHECK(length > 0);
+  if (length > utf16_length_) length = utf16_length_;
+  // memcpy everything in buffer.
+  unsigned buffer_length =
+      last_byte_of_buffer_unused_ ? kBufferSize - 1 : kBufferSize;
+  unsigned memcpy_length = length <= buffer_length ? length : buffer_length;
+  v8::internal::MemCopy(data, buffer_, memcpy_length * sizeof(uint16_t));
+  if (length <= buffer_length) return length;
+  DCHECK(unbuffered_start_ != NULL);
+  // Copy the rest the slow way.
+  WriteUtf16Slow(unbuffered_start_, data + buffer_length,
+                 length - buffer_length);
+  return length;
+}
+
+class Latin1 {
+ public:
+  static const unsigned kMaxChar = 0xff;
+  // Returns 0 if character does not convert to single latin-1 character
+  // or if the character doesn't not convert back to latin-1 via inverse
+  // operation (upper to lower, etc).
+  static inline uint16_t ConvertNonLatin1ToLatin1(uint16_t);
+};
+
+
+uint16_t Latin1::ConvertNonLatin1ToLatin1(uint16_t c) {
+  DCHECK(c > Latin1::kMaxChar);
+  switch (c) {
+    // This are equivalent characters in unicode.
+    case 0x39c:
+    case 0x3bc:
+      return 0xb5;
+    // This is an uppercase of a Latin-1 character
+    // outside of Latin-1.
+    case 0x178:
+      return 0xff;
+  }
+  return 0;
+}
+
+
+}  // namespace unibrow
+
+#endif  // V8_UNICODE_DECODER_H_
diff --git a/src/unicode-inl.h b/src/unicode-inl.h
index 81327d7..0f78d39 100644
--- a/src/unicode-inl.h
+++ b/src/unicode-inl.h
@@ -13,7 +13,7 @@
 
 template <class T, int s> bool Predicate<T, s>::get(uchar code_point) {
   CacheEntry entry = entries_[code_point & kMask];
-  if (entry.code_point_ == code_point) return entry.value_;
+  if (entry.code_point() == code_point) return entry.value();
   return CalculateValue(code_point);
 }
 
@@ -57,22 +57,6 @@
 }
 
 
-uint16_t Latin1::ConvertNonLatin1ToLatin1(uint16_t c) {
-  DCHECK(c > Latin1::kMaxChar);
-  switch (c) {
-    // This are equivalent characters in unicode.
-    case 0x39c:
-    case 0x3bc:
-      return 0xb5;
-    // This is an uppercase of a Latin-1 character
-    // outside of Latin-1.
-    case 0x178:
-      return 0xff;
-  }
-  return 0;
-}
-
-
 unsigned Utf8::EncodeOneByte(char* str, uint8_t c) {
   static const int kMask = ~(1 << 6);
   if (c <= kMaxOneByteChar) {
@@ -153,53 +137,6 @@
   }
 }
 
-Utf8DecoderBase::Utf8DecoderBase()
-  : unbuffered_start_(NULL),
-    utf16_length_(0),
-    last_byte_of_buffer_unused_(false) {}
-
-Utf8DecoderBase::Utf8DecoderBase(uint16_t* buffer,
-                                 unsigned buffer_length,
-                                 const uint8_t* stream,
-                                 unsigned stream_length) {
-  Reset(buffer, buffer_length, stream, stream_length);
-}
-
-template<unsigned kBufferSize>
-Utf8Decoder<kBufferSize>::Utf8Decoder(const char* stream, unsigned length)
-  : Utf8DecoderBase(buffer_,
-                    kBufferSize,
-                    reinterpret_cast<const uint8_t*>(stream),
-                    length) {
-}
-
-template<unsigned kBufferSize>
-void Utf8Decoder<kBufferSize>::Reset(const char* stream, unsigned length) {
-  Utf8DecoderBase::Reset(buffer_,
-                         kBufferSize,
-                         reinterpret_cast<const uint8_t*>(stream),
-                         length);
-}
-
-template <unsigned kBufferSize>
-unsigned Utf8Decoder<kBufferSize>::WriteUtf16(uint16_t* data,
-                                              unsigned length) const {
-  DCHECK(length > 0);
-  if (length > utf16_length_) length = utf16_length_;
-  // memcpy everything in buffer.
-  unsigned buffer_length =
-      last_byte_of_buffer_unused_ ? kBufferSize - 1 : kBufferSize;
-  unsigned memcpy_length = length <= buffer_length ? length : buffer_length;
-  v8::internal::MemCopy(data, buffer_, memcpy_length * sizeof(uint16_t));
-  if (length <= buffer_length) return length;
-  DCHECK(unbuffered_start_ != NULL);
-  // Copy the rest the slow way.
-  WriteUtf16Slow(unbuffered_start_,
-                 data + buffer_length,
-                 length - buffer_length);
-  return length;
-}
-
 }  // namespace unibrow
 
 #endif  // V8_UNICODE_INL_H_
diff --git a/src/unicode.cc b/src/unicode.cc
index a128a6f..26a336a 100644
--- a/src/unicode.cc
+++ b/src/unicode.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// This file was generated at 2014-02-07 15:31:16.733174
+// This file was generated at 2014-10-08 15:25:47.940335
 
 #include "src/unicode-inl.h"
 #include <stdio.h>
@@ -23,6 +23,7 @@
 typedef unsigned short uint16_t;  // NOLINT
 typedef int int32_t;  // NOLINT
 
+
 // All access to the character table should go through this function.
 template <int D>
 static inline uchar TableGet(const int32_t* table, int index) {
@@ -188,6 +189,7 @@
   }
 }
 
+
 uchar Utf8::CalculateValue(const byte* str,
                            unsigned length,
                            unsigned* cursor) {
@@ -258,136 +260,124 @@
 }
 
 
-void Utf8DecoderBase::Reset(uint16_t* buffer,
-                            unsigned buffer_length,
-                            const uint8_t* stream,
-                            unsigned stream_length) {
-  // Assume everything will fit in the buffer and stream won't be needed.
-  last_byte_of_buffer_unused_ = false;
-  unbuffered_start_ = NULL;
-  bool writing_to_buffer = true;
-  // Loop until stream is read, writing to buffer as long as buffer has space.
-  unsigned utf16_length = 0;
-  while (stream_length != 0) {
-    unsigned cursor = 0;
-    uint32_t character = Utf8::ValueOf(stream, stream_length, &cursor);
-    DCHECK(cursor > 0 && cursor <= stream_length);
-    stream += cursor;
-    stream_length -= cursor;
-    bool is_two_characters = character > Utf16::kMaxNonSurrogateCharCode;
-    utf16_length += is_two_characters ? 2 : 1;
-    // Don't need to write to the buffer, but still need utf16_length.
-    if (!writing_to_buffer) continue;
-    // Write out the characters to the buffer.
-    // Must check for equality with buffer_length as we've already updated it.
-    if (utf16_length <= buffer_length) {
-      if (is_two_characters) {
-        *buffer++ = Utf16::LeadSurrogate(character);
-        *buffer++ = Utf16::TrailSurrogate(character);
-      } else {
-        *buffer++ = character;
-      }
-      if (utf16_length == buffer_length) {
-        // Just wrote last character of buffer
-        writing_to_buffer = false;
-        unbuffered_start_ = stream;
-      }
-      continue;
-    }
-    // Have gone over buffer.
-    // Last char of buffer is unused, set cursor back.
-    DCHECK(is_two_characters);
-    writing_to_buffer = false;
-    last_byte_of_buffer_unused_ = true;
-    unbuffered_start_ = stream - cursor;
-  }
-  utf16_length_ = utf16_length;
-}
-
-
-void Utf8DecoderBase::WriteUtf16Slow(const uint8_t* stream,
-                                     uint16_t* data,
-                                     unsigned data_length) {
-  while (data_length != 0) {
-    unsigned cursor = 0;
-    uint32_t character = Utf8::ValueOf(stream, Utf8::kMaxEncodedSize, &cursor);
-    // There's a total lack of bounds checking for stream
-    // as it was already done in Reset.
-    stream += cursor;
-    if (character > unibrow::Utf16::kMaxNonSurrogateCharCode) {
-      *data++ = Utf16::LeadSurrogate(character);
-      *data++ = Utf16::TrailSurrogate(character);
-      DCHECK(data_length > 1);
-      data_length -= 2;
-    } else {
-      *data++ = character;
-      data_length -= 1;
-    }
-  }
-}
-
-
 // Uppercase:            point.category == 'Lu'
 
-static const uint16_t kUppercaseTable0Size = 450;
-static const int32_t kUppercaseTable0[450] = {
-  1073741889, 90, 1073742016, 214, 1073742040, 222, 256, 258,  // NOLINT
-  260, 262, 264, 266, 268, 270, 272, 274,  // NOLINT
-  276, 278, 280, 282, 284, 286, 288, 290,  // NOLINT
-  292, 294, 296, 298, 300, 302, 304, 306,  // NOLINT
-  308, 310, 313, 315, 317, 319, 321, 323,  // NOLINT
-  325, 327, 330, 332, 334, 336, 338, 340,  // NOLINT
-  342, 344, 346, 348, 350, 352, 354, 356,  // NOLINT
-  358, 360, 362, 364, 366, 368, 370, 372,  // NOLINT
-  374, 1073742200, 377, 379, 381, 1073742209, 386, 388,  // NOLINT
-  1073742214, 391, 1073742217, 395, 1073742222, 401, 1073742227, 404,  // NOLINT
-  1073742230, 408, 1073742236, 413, 1073742239, 416, 418, 420,  // NOLINT
-  1073742246, 423, 425, 428, 1073742254, 431, 1073742257, 435,  // NOLINT
-  437, 1073742263, 440, 444, 452, 455, 458, 461,  // NOLINT
-  463, 465, 467, 469, 471, 473, 475, 478,  // NOLINT
-  480, 482, 484, 486, 488, 490, 492, 494,  // NOLINT
-  497, 500, 1073742326, 504, 506, 508, 510, 512,  // NOLINT
-  514, 516, 518, 520, 522, 524, 526, 528,  // NOLINT
-  530, 532, 534, 536, 538, 540, 542, 544,  // NOLINT
-  546, 548, 550, 552, 554, 556, 558, 560,  // NOLINT
-  562, 1073742394, 571, 1073742397, 574, 577, 1073742403, 582,  // NOLINT
-  584, 586, 588, 590, 880, 882, 886, 902,  // NOLINT
-  1073742728, 906, 908, 1073742734, 911, 1073742737, 929, 1073742755,  // NOLINT
-  939, 975, 1073742802, 980, 984, 986, 988, 990,  // NOLINT
-  992, 994, 996, 998, 1000, 1002, 1004, 1006,  // NOLINT
-  1012, 1015, 1073742841, 1018, 1073742845, 1071, 1120, 1122,  // NOLINT
-  1124, 1126, 1128, 1130, 1132, 1134, 1136, 1138,  // NOLINT
-  1140, 1142, 1144, 1146, 1148, 1150, 1152, 1162,  // NOLINT
-  1164, 1166, 1168, 1170, 1172, 1174, 1176, 1178,  // NOLINT
-  1180, 1182, 1184, 1186, 1188, 1190, 1192, 1194,  // NOLINT
-  1196, 1198, 1200, 1202, 1204, 1206, 1208, 1210,  // NOLINT
-  1212, 1214, 1073743040, 1217, 1219, 1221, 1223, 1225,  // NOLINT
-  1227, 1229, 1232, 1234, 1236, 1238, 1240, 1242,  // NOLINT
-  1244, 1246, 1248, 1250, 1252, 1254, 1256, 1258,  // NOLINT
-  1260, 1262, 1264, 1266, 1268, 1270, 1272, 1274,  // NOLINT
-  1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290,  // NOLINT
-  1292, 1294, 1296, 1298, 1300, 1302, 1304, 1306,  // NOLINT
-  1308, 1310, 1312, 1314, 1316, 1318, 1073743153, 1366,  // NOLINT
-  1073746080, 4293, 4295, 4301, 7680, 7682, 7684, 7686,  // NOLINT
-  7688, 7690, 7692, 7694, 7696, 7698, 7700, 7702,  // NOLINT
-  7704, 7706, 7708, 7710, 7712, 7714, 7716, 7718,  // NOLINT
-  7720, 7722, 7724, 7726, 7728, 7730, 7732, 7734,  // NOLINT
-  7736, 7738, 7740, 7742, 7744, 7746, 7748, 7750,  // NOLINT
-  7752, 7754, 7756, 7758, 7760, 7762, 7764, 7766,  // NOLINT
-  7768, 7770, 7772, 7774, 7776, 7778, 7780, 7782,  // NOLINT
-  7784, 7786, 7788, 7790, 7792, 7794, 7796, 7798,  // NOLINT
-  7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814,  // NOLINT
-  7816, 7818, 7820, 7822, 7824, 7826, 7828, 7838,  // NOLINT
-  7840, 7842, 7844, 7846, 7848, 7850, 7852, 7854,  // NOLINT
-  7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870,  // NOLINT
-  7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886,  // NOLINT
-  7888, 7890, 7892, 7894, 7896, 7898, 7900, 7902,  // NOLINT
-  7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918,  // NOLINT
-  7920, 7922, 7924, 7926, 7928, 7930, 7932, 7934,  // NOLINT
-  1073749768, 7951, 1073749784, 7965, 1073749800, 7983, 1073749816, 7999,  // NOLINT
-  1073749832, 8013, 8025, 8027, 8029, 8031, 1073749864, 8047,  // NOLINT
-  1073749944, 8123, 1073749960, 8139, 1073749976, 8155, 1073749992, 8172,  // NOLINT
-  1073750008, 8187 };  // NOLINT
+static const uint16_t kUppercaseTable0Size = 455;
+static const int32_t kUppercaseTable0[455] = {
+    1073741889, 90,         1073742016, 214,
+    1073742040, 222,        256,        258,  // NOLINT
+    260,        262,        264,        266,
+    268,        270,        272,        274,  // NOLINT
+    276,        278,        280,        282,
+    284,        286,        288,        290,  // NOLINT
+    292,        294,        296,        298,
+    300,        302,        304,        306,  // NOLINT
+    308,        310,        313,        315,
+    317,        319,        321,        323,  // NOLINT
+    325,        327,        330,        332,
+    334,        336,        338,        340,  // NOLINT
+    342,        344,        346,        348,
+    350,        352,        354,        356,  // NOLINT
+    358,        360,        362,        364,
+    366,        368,        370,        372,  // NOLINT
+    374,        1073742200, 377,        379,
+    381,        1073742209, 386,        388,  // NOLINT
+    1073742214, 391,        1073742217, 395,
+    1073742222, 401,        1073742227, 404,  // NOLINT
+    1073742230, 408,        1073742236, 413,
+    1073742239, 416,        418,        420,  // NOLINT
+    1073742246, 423,        425,        428,
+    1073742254, 431,        1073742257, 435,  // NOLINT
+    437,        1073742263, 440,        444,
+    452,        455,        458,        461,  // NOLINT
+    463,        465,        467,        469,
+    471,        473,        475,        478,  // NOLINT
+    480,        482,        484,        486,
+    488,        490,        492,        494,  // NOLINT
+    497,        500,        1073742326, 504,
+    506,        508,        510,        512,  // NOLINT
+    514,        516,        518,        520,
+    522,        524,        526,        528,  // NOLINT
+    530,        532,        534,        536,
+    538,        540,        542,        544,  // NOLINT
+    546,        548,        550,        552,
+    554,        556,        558,        560,  // NOLINT
+    562,        1073742394, 571,        1073742397,
+    574,        577,        1073742403, 582,  // NOLINT
+    584,        586,        588,        590,
+    880,        882,        886,        895,  // NOLINT
+    902,        1073742728, 906,        908,
+    1073742734, 911,        1073742737, 929,  // NOLINT
+    1073742755, 939,        975,        1073742802,
+    980,        984,        986,        988,  // NOLINT
+    990,        992,        994,        996,
+    998,        1000,       1002,       1004,  // NOLINT
+    1006,       1012,       1015,       1073742841,
+    1018,       1073742845, 1071,       1120,  // NOLINT
+    1122,       1124,       1126,       1128,
+    1130,       1132,       1134,       1136,  // NOLINT
+    1138,       1140,       1142,       1144,
+    1146,       1148,       1150,       1152,  // NOLINT
+    1162,       1164,       1166,       1168,
+    1170,       1172,       1174,       1176,  // NOLINT
+    1178,       1180,       1182,       1184,
+    1186,       1188,       1190,       1192,  // NOLINT
+    1194,       1196,       1198,       1200,
+    1202,       1204,       1206,       1208,  // NOLINT
+    1210,       1212,       1214,       1073743040,
+    1217,       1219,       1221,       1223,  // NOLINT
+    1225,       1227,       1229,       1232,
+    1234,       1236,       1238,       1240,  // NOLINT
+    1242,       1244,       1246,       1248,
+    1250,       1252,       1254,       1256,  // NOLINT
+    1258,       1260,       1262,       1264,
+    1266,       1268,       1270,       1272,  // NOLINT
+    1274,       1276,       1278,       1280,
+    1282,       1284,       1286,       1288,  // NOLINT
+    1290,       1292,       1294,       1296,
+    1298,       1300,       1302,       1304,  // NOLINT
+    1306,       1308,       1310,       1312,
+    1314,       1316,       1318,       1320,  // NOLINT
+    1322,       1324,       1326,       1073743153,
+    1366,       1073746080, 4293,       4295,  // NOLINT
+    4301,       7680,       7682,       7684,
+    7686,       7688,       7690,       7692,  // NOLINT
+    7694,       7696,       7698,       7700,
+    7702,       7704,       7706,       7708,  // NOLINT
+    7710,       7712,       7714,       7716,
+    7718,       7720,       7722,       7724,  // NOLINT
+    7726,       7728,       7730,       7732,
+    7734,       7736,       7738,       7740,  // NOLINT
+    7742,       7744,       7746,       7748,
+    7750,       7752,       7754,       7756,  // NOLINT
+    7758,       7760,       7762,       7764,
+    7766,       7768,       7770,       7772,  // NOLINT
+    7774,       7776,       7778,       7780,
+    7782,       7784,       7786,       7788,  // NOLINT
+    7790,       7792,       7794,       7796,
+    7798,       7800,       7802,       7804,  // NOLINT
+    7806,       7808,       7810,       7812,
+    7814,       7816,       7818,       7820,  // NOLINT
+    7822,       7824,       7826,       7828,
+    7838,       7840,       7842,       7844,  // NOLINT
+    7846,       7848,       7850,       7852,
+    7854,       7856,       7858,       7860,  // NOLINT
+    7862,       7864,       7866,       7868,
+    7870,       7872,       7874,       7876,  // NOLINT
+    7878,       7880,       7882,       7884,
+    7886,       7888,       7890,       7892,  // NOLINT
+    7894,       7896,       7898,       7900,
+    7902,       7904,       7906,       7908,  // NOLINT
+    7910,       7912,       7914,       7916,
+    7918,       7920,       7922,       7924,  // NOLINT
+    7926,       7928,       7930,       7932,
+    7934,       1073749768, 7951,       1073749784,  // NOLINT
+    7965,       1073749800, 7983,       1073749816,
+    7999,       1073749832, 8013,       8025,  // NOLINT
+    8027,       8029,       8031,       1073749864,
+    8047,       1073749944, 8123,       1073749960,  // NOLINT
+    8139,       1073749976, 8155,       1073749992,
+    8172,       1073750008, 8187};  // NOLINT
 static const uint16_t kUppercaseTable1Size = 86;
 static const int32_t kUppercaseTable1[86] = {
   258, 263, 1073742091, 269, 1073742096, 274, 277, 1073742105,  // NOLINT
@@ -401,20 +391,21 @@
   3262, 3264, 3266, 3268, 3270, 3272, 3274, 3276,  // NOLINT
   3278, 3280, 3282, 3284, 3286, 3288, 3290, 3292,  // NOLINT
   3294, 3296, 3298, 3307, 3309, 3314 };  // NOLINT
-static const uint16_t kUppercaseTable5Size = 91;
-static const int32_t kUppercaseTable5[91] = {
-  1600, 1602, 1604, 1606, 1608, 1610, 1612, 1614,  // NOLINT
-  1616, 1618, 1620, 1622, 1624, 1626, 1628, 1630,  // NOLINT
-  1632, 1634, 1636, 1638, 1640, 1642, 1644, 1664,  // NOLINT
-  1666, 1668, 1670, 1672, 1674, 1676, 1678, 1680,  // NOLINT
-  1682, 1684, 1686, 1826, 1828, 1830, 1832, 1834,  // NOLINT
-  1836, 1838, 1842, 1844, 1846, 1848, 1850, 1852,  // NOLINT
-  1854, 1856, 1858, 1860, 1862, 1864, 1866, 1868,  // NOLINT
-  1870, 1872, 1874, 1876, 1878, 1880, 1882, 1884,  // NOLINT
-  1886, 1888, 1890, 1892, 1894, 1896, 1898, 1900,  // NOLINT
-  1902, 1913, 1915, 1073743741, 1918, 1920, 1922, 1924,  // NOLINT
-  1926, 1931, 1933, 1936, 1938, 1952, 1954, 1956,  // NOLINT
-  1958, 1960, 1962 };  // NOLINT
+static const uint16_t kUppercaseTable5Size = 101;
+static const int32_t kUppercaseTable5[101] = {
+    1600, 1602,       1604, 1606,       1608, 1610,       1612, 1614,  // NOLINT
+    1616, 1618,       1620, 1622,       1624, 1626,       1628, 1630,  // NOLINT
+    1632, 1634,       1636, 1638,       1640, 1642,       1644, 1664,  // NOLINT
+    1666, 1668,       1670, 1672,       1674, 1676,       1678, 1680,  // NOLINT
+    1682, 1684,       1686, 1688,       1690, 1826,       1828, 1830,  // NOLINT
+    1832, 1834,       1836, 1838,       1842, 1844,       1846, 1848,  // NOLINT
+    1850, 1852,       1854, 1856,       1858, 1860,       1862, 1864,  // NOLINT
+    1866, 1868,       1870, 1872,       1874, 1876,       1878, 1880,  // NOLINT
+    1882, 1884,       1886, 1888,       1890, 1892,       1894, 1896,  // NOLINT
+    1898, 1900,       1902, 1913,       1915, 1073743741, 1918, 1920,  // NOLINT
+    1922, 1924,       1926, 1931,       1933, 1936,       1938, 1942,  // NOLINT
+    1944, 1946,       1948, 1950,       1952, 1954,       1956, 1958,  // NOLINT
+    1960, 1073743786, 1965, 1073743792, 1969};                         // NOLINT
 static const uint16_t kUppercaseTable7Size = 2;
 static const int32_t kUppercaseTable7[2] = {
   1073749793, 7994 };  // NOLINT
@@ -440,66 +431,125 @@
 
 // Lowercase:            point.category == 'Ll'
 
-static const uint16_t kLowercaseTable0Size = 463;
-static const int32_t kLowercaseTable0[463] = {
-  1073741921, 122, 181, 1073742047, 246, 1073742072, 255, 257,  // NOLINT
-  259, 261, 263, 265, 267, 269, 271, 273,  // NOLINT
-  275, 277, 279, 281, 283, 285, 287, 289,  // NOLINT
-  291, 293, 295, 297, 299, 301, 303, 305,  // NOLINT
-  307, 309, 1073742135, 312, 314, 316, 318, 320,  // NOLINT
-  322, 324, 326, 1073742152, 329, 331, 333, 335,  // NOLINT
-  337, 339, 341, 343, 345, 347, 349, 351,  // NOLINT
-  353, 355, 357, 359, 361, 363, 365, 367,  // NOLINT
-  369, 371, 373, 375, 378, 380, 1073742206, 384,  // NOLINT
-  387, 389, 392, 1073742220, 397, 402, 405, 1073742233,  // NOLINT
-  411, 414, 417, 419, 421, 424, 1073742250, 427,  // NOLINT
-  429, 432, 436, 438, 1073742265, 442, 1073742269, 447,  // NOLINT
-  454, 457, 460, 462, 464, 466, 468, 470,  // NOLINT
-  472, 474, 1073742300, 477, 479, 481, 483, 485,  // NOLINT
-  487, 489, 491, 493, 1073742319, 496, 499, 501,  // NOLINT
-  505, 507, 509, 511, 513, 515, 517, 519,  // NOLINT
-  521, 523, 525, 527, 529, 531, 533, 535,  // NOLINT
-  537, 539, 541, 543, 545, 547, 549, 551,  // NOLINT
-  553, 555, 557, 559, 561, 1073742387, 569, 572,  // NOLINT
-  1073742399, 576, 578, 583, 585, 587, 589, 1073742415,  // NOLINT
-  659, 1073742485, 687, 881, 883, 887, 1073742715, 893,  // NOLINT
-  912, 1073742764, 974, 1073742800, 977, 1073742805, 983, 985,  // NOLINT
-  987, 989, 991, 993, 995, 997, 999, 1001,  // NOLINT
-  1003, 1005, 1073742831, 1011, 1013, 1016, 1073742843, 1020,  // NOLINT
-  1073742896, 1119, 1121, 1123, 1125, 1127, 1129, 1131,  // NOLINT
-  1133, 1135, 1137, 1139, 1141, 1143, 1145, 1147,  // NOLINT
-  1149, 1151, 1153, 1163, 1165, 1167, 1169, 1171,  // NOLINT
-  1173, 1175, 1177, 1179, 1181, 1183, 1185, 1187,  // NOLINT
-  1189, 1191, 1193, 1195, 1197, 1199, 1201, 1203,  // NOLINT
-  1205, 1207, 1209, 1211, 1213, 1215, 1218, 1220,  // NOLINT
-  1222, 1224, 1226, 1228, 1073743054, 1231, 1233, 1235,  // NOLINT
-  1237, 1239, 1241, 1243, 1245, 1247, 1249, 1251,  // NOLINT
-  1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267,  // NOLINT
-  1269, 1271, 1273, 1275, 1277, 1279, 1281, 1283,  // NOLINT
-  1285, 1287, 1289, 1291, 1293, 1295, 1297, 1299,  // NOLINT
-  1301, 1303, 1305, 1307, 1309, 1311, 1313, 1315,  // NOLINT
-  1317, 1319, 1073743201, 1415, 1073749248, 7467, 1073749355, 7543,  // NOLINT
-  1073749369, 7578, 7681, 7683, 7685, 7687, 7689, 7691,  // NOLINT
-  7693, 7695, 7697, 7699, 7701, 7703, 7705, 7707,  // NOLINT
-  7709, 7711, 7713, 7715, 7717, 7719, 7721, 7723,  // NOLINT
-  7725, 7727, 7729, 7731, 7733, 7735, 7737, 7739,  // NOLINT
-  7741, 7743, 7745, 7747, 7749, 7751, 7753, 7755,  // NOLINT
-  7757, 7759, 7761, 7763, 7765, 7767, 7769, 7771,  // NOLINT
-  7773, 7775, 7777, 7779, 7781, 7783, 7785, 7787,  // NOLINT
-  7789, 7791, 7793, 7795, 7797, 7799, 7801, 7803,  // NOLINT
-  7805, 7807, 7809, 7811, 7813, 7815, 7817, 7819,  // NOLINT
-  7821, 7823, 7825, 7827, 1073749653, 7837, 7839, 7841,  // NOLINT
-  7843, 7845, 7847, 7849, 7851, 7853, 7855, 7857,  // NOLINT
-  7859, 7861, 7863, 7865, 7867, 7869, 7871, 7873,  // NOLINT
-  7875, 7877, 7879, 7881, 7883, 7885, 7887, 7889,  // NOLINT
-  7891, 7893, 7895, 7897, 7899, 7901, 7903, 7905,  // NOLINT
-  7907, 7909, 7911, 7913, 7915, 7917, 7919, 7921,  // NOLINT
-  7923, 7925, 7927, 7929, 7931, 7933, 1073749759, 7943,  // NOLINT
-  1073749776, 7957, 1073749792, 7975, 1073749808, 7991, 1073749824, 8005,  // NOLINT
-  1073749840, 8023, 1073749856, 8039, 1073749872, 8061, 1073749888, 8071,  // NOLINT
-  1073749904, 8087, 1073749920, 8103, 1073749936, 8116, 1073749942, 8119,  // NOLINT
-  8126, 1073749954, 8132, 1073749958, 8135, 1073749968, 8147, 1073749974,  // NOLINT
-  8151, 1073749984, 8167, 1073750002, 8180, 1073750006, 8183 };  // NOLINT
+static const uint16_t kLowercaseTable0Size = 467;
+static const int32_t kLowercaseTable0[467] = {
+    1073741921, 122,        181,        1073742047,
+    246,        1073742072, 255,        257,  // NOLINT
+    259,        261,        263,        265,
+    267,        269,        271,        273,  // NOLINT
+    275,        277,        279,        281,
+    283,        285,        287,        289,  // NOLINT
+    291,        293,        295,        297,
+    299,        301,        303,        305,  // NOLINT
+    307,        309,        1073742135, 312,
+    314,        316,        318,        320,  // NOLINT
+    322,        324,        326,        1073742152,
+    329,        331,        333,        335,  // NOLINT
+    337,        339,        341,        343,
+    345,        347,        349,        351,  // NOLINT
+    353,        355,        357,        359,
+    361,        363,        365,        367,  // NOLINT
+    369,        371,        373,        375,
+    378,        380,        1073742206, 384,  // NOLINT
+    387,        389,        392,        1073742220,
+    397,        402,        405,        1073742233,  // NOLINT
+    411,        414,        417,        419,
+    421,        424,        1073742250, 427,  // NOLINT
+    429,        432,        436,        438,
+    1073742265, 442,        1073742269, 447,  // NOLINT
+    454,        457,        460,        462,
+    464,        466,        468,        470,  // NOLINT
+    472,        474,        1073742300, 477,
+    479,        481,        483,        485,  // NOLINT
+    487,        489,        491,        493,
+    1073742319, 496,        499,        501,  // NOLINT
+    505,        507,        509,        511,
+    513,        515,        517,        519,  // NOLINT
+    521,        523,        525,        527,
+    529,        531,        533,        535,  // NOLINT
+    537,        539,        541,        543,
+    545,        547,        549,        551,  // NOLINT
+    553,        555,        557,        559,
+    561,        1073742387, 569,        572,  // NOLINT
+    1073742399, 576,        578,        583,
+    585,        587,        589,        1073742415,  // NOLINT
+    659,        1073742485, 687,        881,
+    883,        887,        1073742715, 893,  // NOLINT
+    912,        1073742764, 974,        1073742800,
+    977,        1073742805, 983,        985,  // NOLINT
+    987,        989,        991,        993,
+    995,        997,        999,        1001,  // NOLINT
+    1003,       1005,       1073742831, 1011,
+    1013,       1016,       1073742843, 1020,  // NOLINT
+    1073742896, 1119,       1121,       1123,
+    1125,       1127,       1129,       1131,  // NOLINT
+    1133,       1135,       1137,       1139,
+    1141,       1143,       1145,       1147,  // NOLINT
+    1149,       1151,       1153,       1163,
+    1165,       1167,       1169,       1171,  // NOLINT
+    1173,       1175,       1177,       1179,
+    1181,       1183,       1185,       1187,  // NOLINT
+    1189,       1191,       1193,       1195,
+    1197,       1199,       1201,       1203,  // NOLINT
+    1205,       1207,       1209,       1211,
+    1213,       1215,       1218,       1220,  // NOLINT
+    1222,       1224,       1226,       1228,
+    1073743054, 1231,       1233,       1235,  // NOLINT
+    1237,       1239,       1241,       1243,
+    1245,       1247,       1249,       1251,  // NOLINT
+    1253,       1255,       1257,       1259,
+    1261,       1263,       1265,       1267,  // NOLINT
+    1269,       1271,       1273,       1275,
+    1277,       1279,       1281,       1283,  // NOLINT
+    1285,       1287,       1289,       1291,
+    1293,       1295,       1297,       1299,  // NOLINT
+    1301,       1303,       1305,       1307,
+    1309,       1311,       1313,       1315,  // NOLINT
+    1317,       1319,       1321,       1323,
+    1325,       1327,       1073743201, 1415,  // NOLINT
+    1073749248, 7467,       1073749355, 7543,
+    1073749369, 7578,       7681,       7683,  // NOLINT
+    7685,       7687,       7689,       7691,
+    7693,       7695,       7697,       7699,  // NOLINT
+    7701,       7703,       7705,       7707,
+    7709,       7711,       7713,       7715,  // NOLINT
+    7717,       7719,       7721,       7723,
+    7725,       7727,       7729,       7731,  // NOLINT
+    7733,       7735,       7737,       7739,
+    7741,       7743,       7745,       7747,  // NOLINT
+    7749,       7751,       7753,       7755,
+    7757,       7759,       7761,       7763,  // NOLINT
+    7765,       7767,       7769,       7771,
+    7773,       7775,       7777,       7779,  // NOLINT
+    7781,       7783,       7785,       7787,
+    7789,       7791,       7793,       7795,  // NOLINT
+    7797,       7799,       7801,       7803,
+    7805,       7807,       7809,       7811,  // NOLINT
+    7813,       7815,       7817,       7819,
+    7821,       7823,       7825,       7827,  // NOLINT
+    1073749653, 7837,       7839,       7841,
+    7843,       7845,       7847,       7849,  // NOLINT
+    7851,       7853,       7855,       7857,
+    7859,       7861,       7863,       7865,  // NOLINT
+    7867,       7869,       7871,       7873,
+    7875,       7877,       7879,       7881,  // NOLINT
+    7883,       7885,       7887,       7889,
+    7891,       7893,       7895,       7897,  // NOLINT
+    7899,       7901,       7903,       7905,
+    7907,       7909,       7911,       7913,  // NOLINT
+    7915,       7917,       7919,       7921,
+    7923,       7925,       7927,       7929,  // NOLINT
+    7931,       7933,       1073749759, 7943,
+    1073749776, 7957,       1073749792, 7975,  // NOLINT
+    1073749808, 7991,       1073749824, 8005,
+    1073749840, 8023,       1073749856, 8039,  // NOLINT
+    1073749872, 8061,       1073749888, 8071,
+    1073749904, 8087,       1073749920, 8103,  // NOLINT
+    1073749936, 8116,       1073749942, 8119,
+    8126,       1073749954, 8132,       1073749958,  // NOLINT
+    8135,       1073749968, 8147,       1073749974,
+    8151,       1073749984, 8167,       1073750002,  // NOLINT
+    8180,       1073750006, 8183};                   // NOLINT
 static const uint16_t kLowercaseTable1Size = 84;
 static const int32_t kLowercaseTable1[84] = {
   266, 1073742094, 271, 275, 303, 308, 313, 1073742140,  // NOLINT
@@ -513,20 +563,35 @@
   3277, 3279, 3281, 3283, 3285, 3287, 3289, 3291,  // NOLINT
   3293, 3295, 3297, 1073745123, 3300, 3308, 3310, 3315,  // NOLINT
   1073745152, 3365, 3367, 3373 };  // NOLINT
-static const uint16_t kLowercaseTable5Size = 93;
-static const int32_t kLowercaseTable5[93] = {
-  1601, 1603, 1605, 1607, 1609, 1611, 1613, 1615,  // NOLINT
-  1617, 1619, 1621, 1623, 1625, 1627, 1629, 1631,  // NOLINT
-  1633, 1635, 1637, 1639, 1641, 1643, 1645, 1665,  // NOLINT
-  1667, 1669, 1671, 1673, 1675, 1677, 1679, 1681,  // NOLINT
-  1683, 1685, 1687, 1827, 1829, 1831, 1833, 1835,  // NOLINT
-  1837, 1073743663, 1841, 1843, 1845, 1847, 1849, 1851,  // NOLINT
-  1853, 1855, 1857, 1859, 1861, 1863, 1865, 1867,  // NOLINT
-  1869, 1871, 1873, 1875, 1877, 1879, 1881, 1883,  // NOLINT
-  1885, 1887, 1889, 1891, 1893, 1895, 1897, 1899,  // NOLINT
-  1901, 1903, 1073743729, 1912, 1914, 1916, 1919, 1921,  // NOLINT
-  1923, 1925, 1927, 1932, 1934, 1937, 1939, 1953,  // NOLINT
-  1955, 1957, 1959, 1961, 2042 };  // NOLINT
+static const uint16_t kLowercaseTable5Size = 105;
+static const int32_t kLowercaseTable5[105] = {
+    1601,       1603,       1605, 1607,
+    1609,       1611,       1613, 1615,  // NOLINT
+    1617,       1619,       1621, 1623,
+    1625,       1627,       1629, 1631,  // NOLINT
+    1633,       1635,       1637, 1639,
+    1641,       1643,       1645, 1665,  // NOLINT
+    1667,       1669,       1671, 1673,
+    1675,       1677,       1679, 1681,  // NOLINT
+    1683,       1685,       1687, 1689,
+    1691,       1827,       1829, 1831,  // NOLINT
+    1833,       1835,       1837, 1073743663,
+    1841,       1843,       1845, 1847,  // NOLINT
+    1849,       1851,       1853, 1855,
+    1857,       1859,       1861, 1863,  // NOLINT
+    1865,       1867,       1869, 1871,
+    1873,       1875,       1877, 1879,  // NOLINT
+    1881,       1883,       1885, 1887,
+    1889,       1891,       1893, 1895,  // NOLINT
+    1897,       1899,       1901, 1903,
+    1073743729, 1912,       1914, 1916,  // NOLINT
+    1919,       1921,       1923, 1925,
+    1927,       1932,       1934, 1937,  // NOLINT
+    1073743763, 1941,       1943, 1945,
+    1947,       1949,       1951, 1953,  // NOLINT
+    1955,       1957,       1959, 1961,
+    2042,       1073744688, 2906, 1073744740,  // NOLINT
+    2917};                                     // NOLINT
 static const uint16_t kLowercaseTable7Size = 6;
 static const int32_t kLowercaseTable7[6] = {
   1073748736, 6918, 1073748755, 6935, 1073749825, 8026 };  // NOLINT
@@ -550,65 +615,118 @@
 }
 
 
-// Letter:               point.category in ['Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl' ]
+// Letter:               point.category in ['Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl']
 
-static const uint16_t kLetterTable0Size = 435;
-static const int32_t kLetterTable0[435] = {
-  1073741889, 90, 1073741921, 122, 170, 181, 186, 1073742016,  // NOLINT
-  214, 1073742040, 246, 1073742072, 705, 1073742534, 721, 1073742560,  // NOLINT
-  740, 748, 750, 1073742704, 884, 1073742710, 887, 1073742714,  // NOLINT
-  893, 902, 1073742728, 906, 908, 1073742734, 929, 1073742755,  // NOLINT
-  1013, 1073742839, 1153, 1073742986, 1319, 1073743153, 1366, 1369,  // NOLINT
-  1073743201, 1415, 1073743312, 1514, 1073743344, 1522, 1073743392, 1610,  // NOLINT
-  1073743470, 1647, 1073743473, 1747, 1749, 1073743589, 1766, 1073743598,  // NOLINT
-  1775, 1073743610, 1788, 1791, 1808, 1073743634, 1839, 1073743693,  // NOLINT
-  1957, 1969, 1073743818, 2026, 1073743860, 2037, 2042, 1073743872,  // NOLINT
-  2069, 2074, 2084, 2088, 1073743936, 2136, 2208, 1073744034,  // NOLINT
-  2220, 1073744132, 2361, 2365, 2384, 1073744216, 2401, 1073744241,  // NOLINT
-  2423, 1073744249, 2431, 1073744261, 2444, 1073744271, 2448, 1073744275,  // NOLINT
-  2472, 1073744298, 2480, 2482, 1073744310, 2489, 2493, 2510,  // NOLINT
-  1073744348, 2525, 1073744351, 2529, 1073744368, 2545, 1073744389, 2570,  // NOLINT
-  1073744399, 2576, 1073744403, 2600, 1073744426, 2608, 1073744434, 2611,  // NOLINT
-  1073744437, 2614, 1073744440, 2617, 1073744473, 2652, 2654, 1073744498,  // NOLINT
-  2676, 1073744517, 2701, 1073744527, 2705, 1073744531, 2728, 1073744554,  // NOLINT
-  2736, 1073744562, 2739, 1073744565, 2745, 2749, 2768, 1073744608,  // NOLINT
-  2785, 1073744645, 2828, 1073744655, 2832, 1073744659, 2856, 1073744682,  // NOLINT
-  2864, 1073744690, 2867, 1073744693, 2873, 2877, 1073744732, 2909,  // NOLINT
-  1073744735, 2913, 2929, 2947, 1073744773, 2954, 1073744782, 2960,  // NOLINT
-  1073744786, 2965, 1073744793, 2970, 2972, 1073744798, 2975, 1073744803,  // NOLINT
-  2980, 1073744808, 2986, 1073744814, 3001, 3024, 1073744901, 3084,  // NOLINT
-  1073744910, 3088, 1073744914, 3112, 1073744938, 3123, 1073744949, 3129,  // NOLINT
-  3133, 1073744984, 3161, 1073744992, 3169, 1073745029, 3212, 1073745038,  // NOLINT
-  3216, 1073745042, 3240, 1073745066, 3251, 1073745077, 3257, 3261,  // NOLINT
-  3294, 1073745120, 3297, 1073745137, 3314, 1073745157, 3340, 1073745166,  // NOLINT
-  3344, 1073745170, 3386, 3389, 3406, 1073745248, 3425, 1073745274,  // NOLINT
-  3455, 1073745285, 3478, 1073745306, 3505, 1073745331, 3515, 3517,  // NOLINT
-  1073745344, 3526, 1073745409, 3632, 1073745458, 3635, 1073745472, 3654,  // NOLINT
-  1073745537, 3714, 3716, 1073745543, 3720, 3722, 3725, 1073745556,  // NOLINT
-  3735, 1073745561, 3743, 1073745569, 3747, 3749, 3751, 1073745578,  // NOLINT
-  3755, 1073745581, 3760, 1073745586, 3763, 3773, 1073745600, 3780,  // NOLINT
-  3782, 1073745628, 3807, 3840, 1073745728, 3911, 1073745737, 3948,  // NOLINT
-  1073745800, 3980, 1073745920, 4138, 4159, 1073746000, 4181, 1073746010,  // NOLINT
-  4189, 4193, 1073746021, 4198, 1073746030, 4208, 1073746037, 4225,  // NOLINT
-  4238, 1073746080, 4293, 4295, 4301, 1073746128, 4346, 1073746172,  // NOLINT
-  4680, 1073746506, 4685, 1073746512, 4694, 4696, 1073746522, 4701,  // NOLINT
-  1073746528, 4744, 1073746570, 4749, 1073746576, 4784, 1073746610, 4789,  // NOLINT
-  1073746616, 4798, 4800, 1073746626, 4805, 1073746632, 4822, 1073746648,  // NOLINT
-  4880, 1073746706, 4885, 1073746712, 4954, 1073746816, 5007, 1073746848,  // NOLINT
-  5108, 1073746945, 5740, 1073747567, 5759, 1073747585, 5786, 1073747616,  // NOLINT
-  5866, 1073747694, 5872, 1073747712, 5900, 1073747726, 5905, 1073747744,  // NOLINT
-  5937, 1073747776, 5969, 1073747808, 5996, 1073747822, 6000, 1073747840,  // NOLINT
-  6067, 6103, 6108, 1073748000, 6263, 1073748096, 6312, 6314,  // NOLINT
-  1073748144, 6389, 1073748224, 6428, 1073748304, 6509, 1073748336, 6516,  // NOLINT
-  1073748352, 6571, 1073748417, 6599, 1073748480, 6678, 1073748512, 6740,  // NOLINT
-  6823, 1073748741, 6963, 1073748805, 6987, 1073748867, 7072, 1073748910,  // NOLINT
-  7087, 1073748922, 7141, 1073748992, 7203, 1073749069, 7247, 1073749082,  // NOLINT
-  7293, 1073749225, 7404, 1073749230, 7409, 1073749237, 7414, 1073749248,  // NOLINT
-  7615, 1073749504, 7957, 1073749784, 7965, 1073749792, 8005, 1073749832,  // NOLINT
-  8013, 1073749840, 8023, 8025, 8027, 8029, 1073749855, 8061,  // NOLINT
-  1073749888, 8116, 1073749942, 8124, 8126, 1073749954, 8132, 1073749958,  // NOLINT
-  8140, 1073749968, 8147, 1073749974, 8155, 1073749984, 8172, 1073750002,  // NOLINT
-  8180, 1073750006, 8188 };  // NOLINT
+static const uint16_t kLetterTable0Size = 431;
+static const int32_t kLetterTable0[431] = {
+    1073741889, 90,         1073741921, 122,
+    170,        181,        186,        1073742016,  // NOLINT
+    214,        1073742040, 246,        1073742072,
+    705,        1073742534, 721,        1073742560,  // NOLINT
+    740,        748,        750,        1073742704,
+    884,        1073742710, 887,        1073742714,  // NOLINT
+    893,        895,        902,        1073742728,
+    906,        908,        1073742734, 929,  // NOLINT
+    1073742755, 1013,       1073742839, 1153,
+    1073742986, 1327,       1073743153, 1366,  // NOLINT
+    1369,       1073743201, 1415,       1073743312,
+    1514,       1073743344, 1522,       1073743392,  // NOLINT
+    1610,       1073743470, 1647,       1073743473,
+    1747,       1749,       1073743589, 1766,  // NOLINT
+    1073743598, 1775,       1073743610, 1788,
+    1791,       1808,       1073743634, 1839,  // NOLINT
+    1073743693, 1957,       1969,       1073743818,
+    2026,       1073743860, 2037,       2042,  // NOLINT
+    1073743872, 2069,       2074,       2084,
+    2088,       1073743936, 2136,       1073744032,  // NOLINT
+    2226,       1073744132, 2361,       2365,
+    2384,       1073744216, 2401,       1073744241,  // NOLINT
+    2432,       1073744261, 2444,       1073744271,
+    2448,       1073744275, 2472,       1073744298,  // NOLINT
+    2480,       2482,       1073744310, 2489,
+    2493,       2510,       1073744348, 2525,  // NOLINT
+    1073744351, 2529,       1073744368, 2545,
+    1073744389, 2570,       1073744399, 2576,  // NOLINT
+    1073744403, 2600,       1073744426, 2608,
+    1073744434, 2611,       1073744437, 2614,  // NOLINT
+    1073744440, 2617,       1073744473, 2652,
+    2654,       1073744498, 2676,       1073744517,  // NOLINT
+    2701,       1073744527, 2705,       1073744531,
+    2728,       1073744554, 2736,       1073744562,  // NOLINT
+    2739,       1073744565, 2745,       2749,
+    2768,       1073744608, 2785,       1073744645,  // NOLINT
+    2828,       1073744655, 2832,       1073744659,
+    2856,       1073744682, 2864,       1073744690,  // NOLINT
+    2867,       1073744693, 2873,       2877,
+    1073744732, 2909,       1073744735, 2913,  // NOLINT
+    2929,       2947,       1073744773, 2954,
+    1073744782, 2960,       1073744786, 2965,  // NOLINT
+    1073744793, 2970,       2972,       1073744798,
+    2975,       1073744803, 2980,       1073744808,  // NOLINT
+    2986,       1073744814, 3001,       3024,
+    1073744901, 3084,       1073744910, 3088,  // NOLINT
+    1073744914, 3112,       1073744938, 3129,
+    3133,       1073744984, 3161,       1073744992,  // NOLINT
+    3169,       1073745029, 3212,       1073745038,
+    3216,       1073745042, 3240,       1073745066,  // NOLINT
+    3251,       1073745077, 3257,       3261,
+    3294,       1073745120, 3297,       1073745137,  // NOLINT
+    3314,       1073745157, 3340,       1073745166,
+    3344,       1073745170, 3386,       3389,  // NOLINT
+    3406,       1073745248, 3425,       1073745274,
+    3455,       1073745285, 3478,       1073745306,  // NOLINT
+    3505,       1073745331, 3515,       3517,
+    1073745344, 3526,       1073745409, 3632,  // NOLINT
+    1073745458, 3635,       1073745472, 3654,
+    1073745537, 3714,       3716,       1073745543,  // NOLINT
+    3720,       3722,       3725,       1073745556,
+    3735,       1073745561, 3743,       1073745569,  // NOLINT
+    3747,       3749,       3751,       1073745578,
+    3755,       1073745581, 3760,       1073745586,  // NOLINT
+    3763,       3773,       1073745600, 3780,
+    3782,       1073745628, 3807,       3840,  // NOLINT
+    1073745728, 3911,       1073745737, 3948,
+    1073745800, 3980,       1073745920, 4138,  // NOLINT
+    4159,       1073746000, 4181,       1073746010,
+    4189,       4193,       1073746021, 4198,  // NOLINT
+    1073746030, 4208,       1073746037, 4225,
+    4238,       1073746080, 4293,       4295,  // NOLINT
+    4301,       1073746128, 4346,       1073746172,
+    4680,       1073746506, 4685,       1073746512,  // NOLINT
+    4694,       4696,       1073746522, 4701,
+    1073746528, 4744,       1073746570, 4749,  // NOLINT
+    1073746576, 4784,       1073746610, 4789,
+    1073746616, 4798,       4800,       1073746626,  // NOLINT
+    4805,       1073746632, 4822,       1073746648,
+    4880,       1073746706, 4885,       1073746712,  // NOLINT
+    4954,       1073746816, 5007,       1073746848,
+    5108,       1073746945, 5740,       1073747567,  // NOLINT
+    5759,       1073747585, 5786,       1073747616,
+    5866,       1073747694, 5880,       1073747712,  // NOLINT
+    5900,       1073747726, 5905,       1073747744,
+    5937,       1073747776, 5969,       1073747808,  // NOLINT
+    5996,       1073747822, 6000,       1073747840,
+    6067,       6103,       6108,       1073748000,  // NOLINT
+    6263,       1073748096, 6312,       6314,
+    1073748144, 6389,       1073748224, 6430,  // NOLINT
+    1073748304, 6509,       1073748336, 6516,
+    1073748352, 6571,       1073748417, 6599,  // NOLINT
+    1073748480, 6678,       1073748512, 6740,
+    6823,       1073748741, 6963,       1073748805,  // NOLINT
+    6987,       1073748867, 7072,       1073748910,
+    7087,       1073748922, 7141,       1073748992,  // NOLINT
+    7203,       1073749069, 7247,       1073749082,
+    7293,       1073749225, 7404,       1073749230,  // NOLINT
+    7409,       1073749237, 7414,       1073749248,
+    7615,       1073749504, 7957,       1073749784,  // NOLINT
+    7965,       1073749792, 8005,       1073749832,
+    8013,       1073749840, 8023,       8025,  // NOLINT
+    8027,       8029,       1073749855, 8061,
+    1073749888, 8116,       1073749942, 8124,  // NOLINT
+    8126,       1073749954, 8132,       1073749958,
+    8140,       1073749968, 8147,       1073749974,  // NOLINT
+    8155,       1073749984, 8172,       1073750002,
+    8180,       1073750006, 8188};  // NOLINT
 static const uint16_t kLetterTable1Size = 87;
 static const int32_t kLetterTable1[87] = {
   113, 127, 1073741968, 156, 258, 263, 1073742090, 275,  // NOLINT
@@ -631,19 +749,33 @@
 static const uint16_t kLetterTable4Size = 2;
 static const int32_t kLetterTable4[2] = {
   1073741824, 8140 };  // NOLINT
-static const uint16_t kLetterTable5Size = 88;
-static const int32_t kLetterTable5[88] = {
-  1073741824, 1164, 1073743056, 1277, 1073743104, 1548, 1073743376, 1567,  // NOLINT
-  1073743402, 1579, 1073743424, 1646, 1073743487, 1687, 1073743520, 1775,  // NOLINT
-  1073743639, 1823, 1073743650, 1928, 1073743755, 1934, 1073743760, 1939,  // NOLINT
-  1073743776, 1962, 1073743864, 2049, 1073743875, 2053, 1073743879, 2058,  // NOLINT
-  1073743884, 2082, 1073743936, 2163, 1073744002, 2227, 1073744114, 2295,  // NOLINT
-  2299, 1073744138, 2341, 1073744176, 2374, 1073744224, 2428, 1073744260,  // NOLINT
-  2482, 2511, 1073744384, 2600, 1073744448, 2626, 1073744452, 2635,  // NOLINT
-  1073744480, 2678, 2682, 1073744512, 2735, 2737, 1073744565, 2742,  // NOLINT
-  1073744569, 2749, 2752, 2754, 1073744603, 2781, 1073744608, 2794,  // NOLINT
-  1073744626, 2804, 1073744641, 2822, 1073744649, 2830, 1073744657, 2838,  // NOLINT
-  1073744672, 2854, 1073744680, 2862, 1073744832, 3042, 1073744896, 8191 };  // NOLINT
+static const uint16_t kLetterTable5Size = 100;
+static const int32_t kLetterTable5[100] = {
+    1073741824, 1164,       1073743056, 1277,
+    1073743104, 1548,       1073743376, 1567,  // NOLINT
+    1073743402, 1579,       1073743424, 1646,
+    1073743487, 1693,       1073743520, 1775,  // NOLINT
+    1073743639, 1823,       1073743650, 1928,
+    1073743755, 1934,       1073743760, 1965,  // NOLINT
+    1073743792, 1969,       1073743863, 2049,
+    1073743875, 2053,       1073743879, 2058,  // NOLINT
+    1073743884, 2082,       1073743936, 2163,
+    1073744002, 2227,       1073744114, 2295,  // NOLINT
+    2299,       1073744138, 2341,       1073744176,
+    2374,       1073744224, 2428,       1073744260,  // NOLINT
+    2482,       2511,       1073744352, 2532,
+    1073744358, 2543,       1073744378, 2558,  // NOLINT
+    1073744384, 2600,       1073744448, 2626,
+    1073744452, 2635,       1073744480, 2678,  // NOLINT
+    2682,       1073744510, 2735,       2737,
+    1073744565, 2742,       1073744569, 2749,  // NOLINT
+    2752,       2754,       1073744603, 2781,
+    1073744608, 2794,       1073744626, 2804,  // NOLINT
+    1073744641, 2822,       1073744649, 2830,
+    1073744657, 2838,       1073744672, 2854,  // NOLINT
+    1073744680, 2862,       1073744688, 2906,
+    1073744732, 2911,       1073744740, 2917,   // NOLINT
+    1073744832, 3042,       1073744896, 8191};  // NOLINT
 static const uint16_t kLetterTable6Size = 6;
 static const int32_t kLetterTable6[6] = {
   1073741824, 6051, 1073747888, 6086, 1073747915, 6139 };  // NOLINT
@@ -687,49 +819,363 @@
 }
 
 
-// Number:               point.category == 'Nd'
+// ID_Start:             ((point.category in ['Lu', 'Ll', 'Lt', 'Lm', 'Lo',
+// 'Nl'] or 'Other_ID_Start' in point.properties) and ('Pattern_Syntax' not in
+// point.properties) and ('Pattern_White_Space' not in point.properties)) or
+// ('JS_ID_Start' in point.properties)
 
-static const uint16_t kNumberTable0Size = 56;
-static const int32_t kNumberTable0[56] = {
-  1073741872, 57, 1073743456, 1641, 1073743600, 1785, 1073743808, 1993,  // NOLINT
-  1073744230, 2415, 1073744358, 2543, 1073744486, 2671, 1073744614, 2799,  // NOLINT
-  1073744742, 2927, 1073744870, 3055, 1073744998, 3183, 1073745126, 3311,  // NOLINT
-  1073745254, 3439, 1073745488, 3673, 1073745616, 3801, 1073745696, 3881,  // NOLINT
-  1073745984, 4169, 1073746064, 4249, 1073747936, 6121, 1073747984, 6169,  // NOLINT
-  1073748294, 6479, 1073748432, 6617, 1073748608, 6793, 1073748624, 6809,  // NOLINT
-  1073748816, 7001, 1073748912, 7097, 1073749056, 7241, 1073749072, 7257 };  // NOLINT
-static const uint16_t kNumberTable5Size = 12;
-static const int32_t kNumberTable5[12] = {
-  1073743392, 1577, 1073744080, 2265, 1073744128, 2313, 1073744336, 2521,  // NOLINT
-  1073744464, 2649, 1073744880, 3065 };  // NOLINT
-static const uint16_t kNumberTable7Size = 2;
-static const int32_t kNumberTable7[2] = {
-  1073749776, 7961 };  // NOLINT
-bool Number::Is(uchar c) {
+static const uint16_t kID_StartTable0Size = 434;
+static const int32_t kID_StartTable0[434] = {
+    36,         1073741889, 90,         92,
+    95,         1073741921, 122,        170,  // NOLINT
+    181,        186,        1073742016, 214,
+    1073742040, 246,        1073742072, 705,  // NOLINT
+    1073742534, 721,        1073742560, 740,
+    748,        750,        1073742704, 884,  // NOLINT
+    1073742710, 887,        1073742714, 893,
+    895,        902,        1073742728, 906,  // NOLINT
+    908,        1073742734, 929,        1073742755,
+    1013,       1073742839, 1153,       1073742986,  // NOLINT
+    1327,       1073743153, 1366,       1369,
+    1073743201, 1415,       1073743312, 1514,  // NOLINT
+    1073743344, 1522,       1073743392, 1610,
+    1073743470, 1647,       1073743473, 1747,  // NOLINT
+    1749,       1073743589, 1766,       1073743598,
+    1775,       1073743610, 1788,       1791,  // NOLINT
+    1808,       1073743634, 1839,       1073743693,
+    1957,       1969,       1073743818, 2026,  // NOLINT
+    1073743860, 2037,       2042,       1073743872,
+    2069,       2074,       2084,       2088,  // NOLINT
+    1073743936, 2136,       1073744032, 2226,
+    1073744132, 2361,       2365,       2384,  // NOLINT
+    1073744216, 2401,       1073744241, 2432,
+    1073744261, 2444,       1073744271, 2448,  // NOLINT
+    1073744275, 2472,       1073744298, 2480,
+    2482,       1073744310, 2489,       2493,  // NOLINT
+    2510,       1073744348, 2525,       1073744351,
+    2529,       1073744368, 2545,       1073744389,  // NOLINT
+    2570,       1073744399, 2576,       1073744403,
+    2600,       1073744426, 2608,       1073744434,  // NOLINT
+    2611,       1073744437, 2614,       1073744440,
+    2617,       1073744473, 2652,       2654,  // NOLINT
+    1073744498, 2676,       1073744517, 2701,
+    1073744527, 2705,       1073744531, 2728,  // NOLINT
+    1073744554, 2736,       1073744562, 2739,
+    1073744565, 2745,       2749,       2768,  // NOLINT
+    1073744608, 2785,       1073744645, 2828,
+    1073744655, 2832,       1073744659, 2856,  // NOLINT
+    1073744682, 2864,       1073744690, 2867,
+    1073744693, 2873,       2877,       1073744732,  // NOLINT
+    2909,       1073744735, 2913,       2929,
+    2947,       1073744773, 2954,       1073744782,  // NOLINT
+    2960,       1073744786, 2965,       1073744793,
+    2970,       2972,       1073744798, 2975,  // NOLINT
+    1073744803, 2980,       1073744808, 2986,
+    1073744814, 3001,       3024,       1073744901,  // NOLINT
+    3084,       1073744910, 3088,       1073744914,
+    3112,       1073744938, 3129,       3133,  // NOLINT
+    1073744984, 3161,       1073744992, 3169,
+    1073745029, 3212,       1073745038, 3216,  // NOLINT
+    1073745042, 3240,       1073745066, 3251,
+    1073745077, 3257,       3261,       3294,  // NOLINT
+    1073745120, 3297,       1073745137, 3314,
+    1073745157, 3340,       1073745166, 3344,  // NOLINT
+    1073745170, 3386,       3389,       3406,
+    1073745248, 3425,       1073745274, 3455,  // NOLINT
+    1073745285, 3478,       1073745306, 3505,
+    1073745331, 3515,       3517,       1073745344,  // NOLINT
+    3526,       1073745409, 3632,       1073745458,
+    3635,       1073745472, 3654,       1073745537,  // NOLINT
+    3714,       3716,       1073745543, 3720,
+    3722,       3725,       1073745556, 3735,  // NOLINT
+    1073745561, 3743,       1073745569, 3747,
+    3749,       3751,       1073745578, 3755,  // NOLINT
+    1073745581, 3760,       1073745586, 3763,
+    3773,       1073745600, 3780,       3782,  // NOLINT
+    1073745628, 3807,       3840,       1073745728,
+    3911,       1073745737, 3948,       1073745800,  // NOLINT
+    3980,       1073745920, 4138,       4159,
+    1073746000, 4181,       1073746010, 4189,  // NOLINT
+    4193,       1073746021, 4198,       1073746030,
+    4208,       1073746037, 4225,       4238,  // NOLINT
+    1073746080, 4293,       4295,       4301,
+    1073746128, 4346,       1073746172, 4680,  // NOLINT
+    1073746506, 4685,       1073746512, 4694,
+    4696,       1073746522, 4701,       1073746528,  // NOLINT
+    4744,       1073746570, 4749,       1073746576,
+    4784,       1073746610, 4789,       1073746616,  // NOLINT
+    4798,       4800,       1073746626, 4805,
+    1073746632, 4822,       1073746648, 4880,  // NOLINT
+    1073746706, 4885,       1073746712, 4954,
+    1073746816, 5007,       1073746848, 5108,  // NOLINT
+    1073746945, 5740,       1073747567, 5759,
+    1073747585, 5786,       1073747616, 5866,  // NOLINT
+    1073747694, 5880,       1073747712, 5900,
+    1073747726, 5905,       1073747744, 5937,  // NOLINT
+    1073747776, 5969,       1073747808, 5996,
+    1073747822, 6000,       1073747840, 6067,  // NOLINT
+    6103,       6108,       1073748000, 6263,
+    1073748096, 6312,       6314,       1073748144,  // NOLINT
+    6389,       1073748224, 6430,       1073748304,
+    6509,       1073748336, 6516,       1073748352,  // NOLINT
+    6571,       1073748417, 6599,       1073748480,
+    6678,       1073748512, 6740,       6823,  // NOLINT
+    1073748741, 6963,       1073748805, 6987,
+    1073748867, 7072,       1073748910, 7087,  // NOLINT
+    1073748922, 7141,       1073748992, 7203,
+    1073749069, 7247,       1073749082, 7293,  // NOLINT
+    1073749225, 7404,       1073749230, 7409,
+    1073749237, 7414,       1073749248, 7615,  // NOLINT
+    1073749504, 7957,       1073749784, 7965,
+    1073749792, 8005,       1073749832, 8013,  // NOLINT
+    1073749840, 8023,       8025,       8027,
+    8029,       1073749855, 8061,       1073749888,  // NOLINT
+    8116,       1073749942, 8124,       8126,
+    1073749954, 8132,       1073749958, 8140,  // NOLINT
+    1073749968, 8147,       1073749974, 8155,
+    1073749984, 8172,       1073750002, 8180,  // NOLINT
+    1073750006, 8188};                         // NOLINT
+static const uint16_t kID_StartTable1Size = 84;
+static const int32_t kID_StartTable1[84] = {
+    113,        127,        1073741968, 156,
+    258,        263,        1073742090, 275,  // NOLINT
+    277,        1073742104, 285,        292,
+    294,        296,        1073742122, 313,  // NOLINT
+    1073742140, 319,        1073742149, 329,
+    334,        1073742176, 392,        1073744896,  // NOLINT
+    3118,       1073744944, 3166,       1073744992,
+    3300,       1073745131, 3310,       1073745138,  // NOLINT
+    3315,       1073745152, 3365,       3367,
+    3373,       1073745200, 3431,       3439,  // NOLINT
+    1073745280, 3478,       1073745312, 3494,
+    1073745320, 3502,       1073745328, 3510,  // NOLINT
+    1073745336, 3518,       1073745344, 3526,
+    1073745352, 3534,       1073745360, 3542,  // NOLINT
+    1073745368, 3550,       1073745925, 4103,
+    1073745953, 4137,       1073745969, 4149,  // NOLINT
+    1073745976, 4156,       1073745985, 4246,
+    1073746075, 4255,       1073746081, 4346,  // NOLINT
+    1073746172, 4351,       1073746181, 4397,
+    1073746225, 4494,       1073746336, 4538,   // NOLINT
+    1073746416, 4607,       1073746944, 8191};  // NOLINT
+static const uint16_t kID_StartTable2Size = 4;
+static const int32_t kID_StartTable2[4] = {1073741824, 3509, 1073745408,
+                                           8191};  // NOLINT
+static const uint16_t kID_StartTable3Size = 2;
+static const int32_t kID_StartTable3[2] = {1073741824, 8191};  // NOLINT
+static const uint16_t kID_StartTable4Size = 2;
+static const int32_t kID_StartTable4[2] = {1073741824, 8140};  // NOLINT
+static const uint16_t kID_StartTable5Size = 100;
+static const int32_t kID_StartTable5[100] = {
+    1073741824, 1164,       1073743056, 1277,
+    1073743104, 1548,       1073743376, 1567,  // NOLINT
+    1073743402, 1579,       1073743424, 1646,
+    1073743487, 1693,       1073743520, 1775,  // NOLINT
+    1073743639, 1823,       1073743650, 1928,
+    1073743755, 1934,       1073743760, 1965,  // NOLINT
+    1073743792, 1969,       1073743863, 2049,
+    1073743875, 2053,       1073743879, 2058,  // NOLINT
+    1073743884, 2082,       1073743936, 2163,
+    1073744002, 2227,       1073744114, 2295,  // NOLINT
+    2299,       1073744138, 2341,       1073744176,
+    2374,       1073744224, 2428,       1073744260,  // NOLINT
+    2482,       2511,       1073744352, 2532,
+    1073744358, 2543,       1073744378, 2558,  // NOLINT
+    1073744384, 2600,       1073744448, 2626,
+    1073744452, 2635,       1073744480, 2678,  // NOLINT
+    2682,       1073744510, 2735,       2737,
+    1073744565, 2742,       1073744569, 2749,  // NOLINT
+    2752,       2754,       1073744603, 2781,
+    1073744608, 2794,       1073744626, 2804,  // NOLINT
+    1073744641, 2822,       1073744649, 2830,
+    1073744657, 2838,       1073744672, 2854,  // NOLINT
+    1073744680, 2862,       1073744688, 2906,
+    1073744732, 2911,       1073744740, 2917,   // NOLINT
+    1073744832, 3042,       1073744896, 8191};  // NOLINT
+static const uint16_t kID_StartTable6Size = 6;
+static const int32_t kID_StartTable6[6] = {1073741824, 6051, 1073747888, 6086,
+                                           1073747915, 6139};  // NOLINT
+static const uint16_t kID_StartTable7Size = 48;
+static const int32_t kID_StartTable7[48] = {
+    1073748224, 6765,       1073748592, 6873,
+    1073748736, 6918,       1073748755, 6935,  // NOLINT
+    6941,       1073748767, 6952,       1073748778,
+    6966,       1073748792, 6972,       6974,  // NOLINT
+    1073748800, 6977,       1073748803, 6980,
+    1073748806, 7089,       1073748947, 7485,  // NOLINT
+    1073749328, 7567,       1073749394, 7623,
+    1073749488, 7675,       1073749616, 7796,  // NOLINT
+    1073749622, 7932,       1073749793, 7994,
+    1073749825, 8026,       1073749862, 8126,  // NOLINT
+    1073749954, 8135,       1073749962, 8143,
+    1073749970, 8151,       1073749978, 8156};  // NOLINT
+bool ID_Start::Is(uchar c) {
   int chunk_index = c >> 13;
   switch (chunk_index) {
-    case 0: return LookupPredicate(kNumberTable0,
-                                       kNumberTable0Size,
-                                       c);
-    case 5: return LookupPredicate(kNumberTable5,
-                                       kNumberTable5Size,
-                                       c);
-    case 7: return LookupPredicate(kNumberTable7,
-                                       kNumberTable7Size,
-                                       c);
+    case 0:
+      return LookupPredicate(kID_StartTable0, kID_StartTable0Size, c);
+    case 1:
+      return LookupPredicate(kID_StartTable1, kID_StartTable1Size, c);
+    case 2:
+      return LookupPredicate(kID_StartTable2, kID_StartTable2Size, c);
+    case 3:
+      return LookupPredicate(kID_StartTable3, kID_StartTable3Size, c);
+    case 4:
+      return LookupPredicate(kID_StartTable4, kID_StartTable4Size, c);
+    case 5:
+      return LookupPredicate(kID_StartTable5, kID_StartTable5Size, c);
+    case 6:
+      return LookupPredicate(kID_StartTable6, kID_StartTable6Size, c);
+    case 7:
+      return LookupPredicate(kID_StartTable7, kID_StartTable7Size, c);
+    default:
+      return false;
+  }
+}
+
+
+// ID_Continue:          point.category in ['Nd', 'Mn', 'Mc', 'Pc'] or
+// 'Other_ID_Continue' in point.properties or 'JS_ID_Continue' in
+// point.properties
+
+static const uint16_t kID_ContinueTable0Size = 315;
+static const int32_t kID_ContinueTable0[315] = {
+    1073741872, 57,         95,         183,
+    1073742592, 879,        903,        1073742979,  // NOLINT
+    1159,       1073743249, 1469,       1471,
+    1073743297, 1474,       1073743300, 1477,  // NOLINT
+    1479,       1073743376, 1562,       1073743435,
+    1641,       1648,       1073743574, 1756,  // NOLINT
+    1073743583, 1764,       1073743591, 1768,
+    1073743594, 1773,       1073743600, 1785,  // NOLINT
+    1809,       1073743664, 1866,       1073743782,
+    1968,       1073743808, 1993,       1073743851,  // NOLINT
+    2035,       1073743894, 2073,       1073743899,
+    2083,       1073743909, 2087,       1073743913,  // NOLINT
+    2093,       1073743961, 2139,       1073744100,
+    2307,       1073744186, 2364,       1073744190,  // NOLINT
+    2383,       1073744209, 2391,       1073744226,
+    2403,       1073744230, 2415,       1073744257,  // NOLINT
+    2435,       2492,       1073744318, 2500,
+    1073744327, 2504,       1073744331, 2509,  // NOLINT
+    2519,       1073744354, 2531,       1073744358,
+    2543,       1073744385, 2563,       2620,  // NOLINT
+    1073744446, 2626,       1073744455, 2632,
+    1073744459, 2637,       2641,       1073744486,  // NOLINT
+    2673,       2677,       1073744513, 2691,
+    2748,       1073744574, 2757,       1073744583,  // NOLINT
+    2761,       1073744587, 2765,       1073744610,
+    2787,       1073744614, 2799,       1073744641,  // NOLINT
+    2819,       2876,       1073744702, 2884,
+    1073744711, 2888,       1073744715, 2893,  // NOLINT
+    1073744726, 2903,       1073744738, 2915,
+    1073744742, 2927,       2946,       1073744830,  // NOLINT
+    3010,       1073744838, 3016,       1073744842,
+    3021,       3031,       1073744870, 3055,  // NOLINT
+    1073744896, 3075,       1073744958, 3140,
+    1073744966, 3144,       1073744970, 3149,  // NOLINT
+    1073744981, 3158,       1073744994, 3171,
+    1073744998, 3183,       1073745025, 3203,  // NOLINT
+    3260,       1073745086, 3268,       1073745094,
+    3272,       1073745098, 3277,       1073745109,  // NOLINT
+    3286,       1073745122, 3299,       1073745126,
+    3311,       1073745153, 3331,       1073745214,  // NOLINT
+    3396,       1073745222, 3400,       1073745226,
+    3405,       3415,       1073745250, 3427,  // NOLINT
+    1073745254, 3439,       1073745282, 3459,
+    3530,       1073745359, 3540,       3542,  // NOLINT
+    1073745368, 3551,       1073745382, 3567,
+    1073745394, 3571,       3633,       1073745460,  // NOLINT
+    3642,       1073745479, 3662,       1073745488,
+    3673,       3761,       1073745588, 3769,  // NOLINT
+    1073745595, 3772,       1073745608, 3789,
+    1073745616, 3801,       1073745688, 3865,  // NOLINT
+    1073745696, 3881,       3893,       3895,
+    3897,       1073745726, 3903,       1073745777,  // NOLINT
+    3972,       1073745798, 3975,       1073745805,
+    3991,       1073745817, 4028,       4038,  // NOLINT
+    1073745963, 4158,       1073745984, 4169,
+    1073746006, 4185,       1073746014, 4192,  // NOLINT
+    1073746018, 4196,       1073746023, 4205,
+    1073746033, 4212,       1073746050, 4237,  // NOLINT
+    1073746063, 4253,       1073746781, 4959,
+    1073746793, 4977,       1073747730, 5908,  // NOLINT
+    1073747762, 5940,       1073747794, 5971,
+    1073747826, 6003,       1073747892, 6099,  // NOLINT
+    6109,       1073747936, 6121,       1073747979,
+    6157,       1073747984, 6169,       6313,  // NOLINT
+    1073748256, 6443,       1073748272, 6459,
+    1073748294, 6479,       1073748400, 6592,  // NOLINT
+    1073748424, 6601,       1073748432, 6618,
+    1073748503, 6683,       1073748565, 6750,  // NOLINT
+    1073748576, 6780,       1073748607, 6793,
+    1073748624, 6809,       1073748656, 6845,  // NOLINT
+    1073748736, 6916,       1073748788, 6980,
+    1073748816, 7001,       1073748843, 7027,  // NOLINT
+    1073748864, 7042,       1073748897, 7085,
+    1073748912, 7097,       1073748966, 7155,  // NOLINT
+    1073749028, 7223,       1073749056, 7241,
+    1073749072, 7257,       1073749200, 7378,  // NOLINT
+    1073749204, 7400,       7405,       1073749234,
+    7412,       1073749240, 7417,       1073749440,  // NOLINT
+    7669,       1073749500, 7679};                   // NOLINT
+static const uint16_t kID_ContinueTable1Size = 19;
+static const int32_t kID_ContinueTable1[19] = {
+    1073741836, 13,         1073741887, 64,
+    84,         1073742032, 220,        225,  // NOLINT
+    1073742053, 240,        1073745135, 3313,
+    3455,       1073745376, 3583,       1073745962,  // NOLINT
+    4143,       1073746073, 4250};                   // NOLINT
+static const uint16_t kID_ContinueTable5Size = 63;
+static const int32_t kID_ContinueTable5[63] = {
+    1073743392, 1577,       1647,       1073743476,
+    1661,       1695,       1073743600, 1777,  // NOLINT
+    2050,       2054,       2059,       1073743907,
+    2087,       1073744000, 2177,       1073744052,  // NOLINT
+    2244,       1073744080, 2265,       1073744096,
+    2289,       1073744128, 2313,       1073744166,  // NOLINT
+    2349,       1073744199, 2387,       1073744256,
+    2435,       1073744307, 2496,       1073744336,  // NOLINT
+    2521,       2533,       1073744368, 2553,
+    1073744425, 2614,       2627,       1073744460,  // NOLINT
+    2637,       1073744464, 2649,       1073744507,
+    2685,       2736,       1073744562, 2740,  // NOLINT
+    1073744567, 2744,       1073744574, 2751,
+    2753,       1073744619, 2799,       1073744629,  // NOLINT
+    2806,       1073744867, 3050,       1073744876,
+    3053,       1073744880, 3065};  // NOLINT
+static const uint16_t kID_ContinueTable7Size = 12;
+static const int32_t kID_ContinueTable7[12] = {
+    6942, 1073749504, 7695, 1073749536,
+    7725, 1073749555, 7732, 1073749581,  // NOLINT
+    7759, 1073749776, 7961, 7999};       // NOLINT
+bool ID_Continue::Is(uchar c) {
+  int chunk_index = c >> 13;
+  switch (chunk_index) {
+    case 0:
+      return LookupPredicate(kID_ContinueTable0, kID_ContinueTable0Size, c);
+    case 1:
+      return LookupPredicate(kID_ContinueTable1, kID_ContinueTable1Size, c);
+    case 5:
+      return LookupPredicate(kID_ContinueTable5, kID_ContinueTable5Size, c);
+    case 7:
+      return LookupPredicate(kID_ContinueTable7, kID_ContinueTable7Size, c);
     default: return false;
   }
 }
 
 
-// WhiteSpace:           point.category == 'Zs'
+// WhiteSpace:           (point.category == 'Zs') or ('JS_White_Space' in
+// point.properties)
 
-static const uint16_t kWhiteSpaceTable0Size = 4;
-static const int32_t kWhiteSpaceTable0[4] = {
-  32, 160, 5760, 6158 };  // NOLINT
+static const uint16_t kWhiteSpaceTable0Size = 7;
+static const int32_t kWhiteSpaceTable0[7] = {9,   1073741835, 12,  32,
+                                             160, 5760,       6158};  // NOLINT
 static const uint16_t kWhiteSpaceTable1Size = 5;
 static const int32_t kWhiteSpaceTable1[5] = {
   1073741824, 10, 47, 95, 4096 };  // NOLINT
+static const uint16_t kWhiteSpaceTable7Size = 1;
+static const int32_t kWhiteSpaceTable7[1] = {7935};  // NOLINT
 bool WhiteSpace::Is(uchar c) {
   int chunk_index = c >> 13;
   switch (chunk_index) {
@@ -739,12 +1185,14 @@
     case 1: return LookupPredicate(kWhiteSpaceTable1,
                                        kWhiteSpaceTable1Size,
                                        c);
+    case 7:
+      return LookupPredicate(kWhiteSpaceTable7, kWhiteSpaceTable7Size, c);
     default: return false;
   }
 }
 
 
-// LineTerminator:       'Lt' in point.properties
+// LineTerminator:       'JS_Line_Terminator' in point.properties
 
 static const uint16_t kLineTerminatorTable0Size = 2;
 static const int32_t kLineTerminatorTable0[2] = {
@@ -765,171 +1213,193 @@
   }
 }
 
-
-// CombiningMark:        point.category in ['Mn', 'Mc']
-
-static const uint16_t kCombiningMarkTable0Size = 258;
-static const int32_t kCombiningMarkTable0[258] = {
-  1073742592, 879, 1073742979, 1159, 1073743249, 1469, 1471, 1073743297,  // NOLINT
-  1474, 1073743300, 1477, 1479, 1073743376, 1562, 1073743435, 1631,  // NOLINT
-  1648, 1073743574, 1756, 1073743583, 1764, 1073743591, 1768, 1073743594,  // NOLINT
-  1773, 1809, 1073743664, 1866, 1073743782, 1968, 1073743851, 2035,  // NOLINT
-  1073743894, 2073, 1073743899, 2083, 1073743909, 2087, 1073743913, 2093,  // NOLINT
-  1073743961, 2139, 1073744100, 2302, 1073744128, 2307, 1073744186, 2364,  // NOLINT
-  1073744190, 2383, 1073744209, 2391, 1073744226, 2403, 1073744257, 2435,  // NOLINT
-  2492, 1073744318, 2500, 1073744327, 2504, 1073744331, 2509, 2519,  // NOLINT
-  1073744354, 2531, 1073744385, 2563, 2620, 1073744446, 2626, 1073744455,  // NOLINT
-  2632, 1073744459, 2637, 2641, 1073744496, 2673, 2677, 1073744513,  // NOLINT
-  2691, 2748, 1073744574, 2757, 1073744583, 2761, 1073744587, 2765,  // NOLINT
-  1073744610, 2787, 1073744641, 2819, 2876, 1073744702, 2884, 1073744711,  // NOLINT
-  2888, 1073744715, 2893, 1073744726, 2903, 1073744738, 2915, 2946,  // NOLINT
-  1073744830, 3010, 1073744838, 3016, 1073744842, 3021, 3031, 1073744897,  // NOLINT
-  3075, 1073744958, 3140, 1073744966, 3144, 1073744970, 3149, 1073744981,  // NOLINT
-  3158, 1073744994, 3171, 1073745026, 3203, 3260, 1073745086, 3268,  // NOLINT
-  1073745094, 3272, 1073745098, 3277, 1073745109, 3286, 1073745122, 3299,  // NOLINT
-  1073745154, 3331, 1073745214, 3396, 1073745222, 3400, 1073745226, 3405,  // NOLINT
-  3415, 1073745250, 3427, 1073745282, 3459, 3530, 1073745359, 3540,  // NOLINT
-  3542, 1073745368, 3551, 1073745394, 3571, 3633, 1073745460, 3642,  // NOLINT
-  1073745479, 3662, 3761, 1073745588, 3769, 1073745595, 3772, 1073745608,  // NOLINT
-  3789, 1073745688, 3865, 3893, 3895, 3897, 1073745726, 3903,  // NOLINT
-  1073745777, 3972, 1073745798, 3975, 1073745805, 3991, 1073745817, 4028,  // NOLINT
-  4038, 1073745963, 4158, 1073746006, 4185, 1073746014, 4192, 1073746018,  // NOLINT
-  4196, 1073746023, 4205, 1073746033, 4212, 1073746050, 4237, 4239,  // NOLINT
-  1073746074, 4253, 1073746781, 4959, 1073747730, 5908, 1073747762, 5940,  // NOLINT
-  1073747794, 5971, 1073747826, 6003, 1073747892, 6099, 6109, 1073747979,  // NOLINT
-  6157, 6313, 1073748256, 6443, 1073748272, 6459, 1073748400, 6592,  // NOLINT
-  1073748424, 6601, 1073748503, 6683, 1073748565, 6750, 1073748576, 6780,  // NOLINT
-  6783, 1073748736, 6916, 1073748788, 6980, 1073748843, 7027, 1073748864,  // NOLINT
-  7042, 1073748897, 7085, 1073748966, 7155, 1073749028, 7223, 1073749200,  // NOLINT
-  7378, 1073749204, 7400, 7405, 1073749234, 7412, 1073749440, 7654,  // NOLINT
-  1073749500, 7679 };  // NOLINT
-static const uint16_t kCombiningMarkTable1Size = 14;
-static const int32_t kCombiningMarkTable1[14] = {
-  1073742032, 220, 225, 1073742053, 240, 1073745135, 3313, 3455,  // NOLINT
-  1073745376, 3583, 1073745962, 4143, 1073746073, 4250 };  // NOLINT
-static const uint16_t kCombiningMarkTable5Size = 47;
-static const int32_t kCombiningMarkTable5[47] = {
-  1647, 1073743476, 1661, 1695, 1073743600, 1777, 2050, 2054,  // NOLINT
-  2059, 1073743907, 2087, 1073744000, 2177, 1073744052, 2244, 1073744096,  // NOLINT
-  2289, 1073744166, 2349, 1073744199, 2387, 1073744256, 2435, 1073744307,  // NOLINT
-  2496, 1073744425, 2614, 2627, 1073744460, 2637, 2683, 2736,  // NOLINT
-  1073744562, 2740, 1073744567, 2744, 1073744574, 2751, 2753, 1073744619,  // NOLINT
-  2799, 1073744629, 2806, 1073744867, 3050, 1073744876, 3053 };  // NOLINT
-static const uint16_t kCombiningMarkTable7Size = 5;
-static const int32_t kCombiningMarkTable7[5] = {
-  6942, 1073749504, 7695, 1073749536, 7718 };  // NOLINT
-bool CombiningMark::Is(uchar c) {
-  int chunk_index = c >> 13;
-  switch (chunk_index) {
-    case 0: return LookupPredicate(kCombiningMarkTable0,
-                                       kCombiningMarkTable0Size,
-                                       c);
-    case 1: return LookupPredicate(kCombiningMarkTable1,
-                                       kCombiningMarkTable1Size,
-                                       c);
-    case 5: return LookupPredicate(kCombiningMarkTable5,
-                                       kCombiningMarkTable5Size,
-                                       c);
-    case 7: return LookupPredicate(kCombiningMarkTable7,
-                                       kCombiningMarkTable7Size,
-                                       c);
-    default: return false;
-  }
-}
-
-
-// ConnectorPunctuation: point.category == 'Pc'
-
-static const uint16_t kConnectorPunctuationTable0Size = 1;
-static const int32_t kConnectorPunctuationTable0[1] = {
-  95 };  // NOLINT
-static const uint16_t kConnectorPunctuationTable1Size = 3;
-static const int32_t kConnectorPunctuationTable1[3] = {
-  1073741887, 64, 84 };  // NOLINT
-static const uint16_t kConnectorPunctuationTable7Size = 5;
-static const int32_t kConnectorPunctuationTable7[5] = {
-  1073749555, 7732, 1073749581, 7759, 7999 };  // NOLINT
-bool ConnectorPunctuation::Is(uchar c) {
-  int chunk_index = c >> 13;
-  switch (chunk_index) {
-    case 0: return LookupPredicate(kConnectorPunctuationTable0,
-                                       kConnectorPunctuationTable0Size,
-                                       c);
-    case 1: return LookupPredicate(kConnectorPunctuationTable1,
-                                       kConnectorPunctuationTable1Size,
-                                       c);
-    case 7: return LookupPredicate(kConnectorPunctuationTable7,
-                                       kConnectorPunctuationTable7Size,
-                                       c);
-    default: return false;
-  }
-}
-
 static const MultiCharacterSpecialCase<2> kToLowercaseMultiStrings0[2] = {  // NOLINT
   {{105, 775}}, {{kSentinel}} }; // NOLINT
-static const uint16_t kToLowercaseTable0Size = 483;  // NOLINT
-static const int32_t kToLowercaseTable0[966] = {
-  1073741889, 128, 90, 128, 1073742016, 128, 214, 128, 1073742040, 128, 222, 128, 256, 4, 258, 4,  // NOLINT
-  260, 4, 262, 4, 264, 4, 266, 4, 268, 4, 270, 4, 272, 4, 274, 4,  // NOLINT
-  276, 4, 278, 4, 280, 4, 282, 4, 284, 4, 286, 4, 288, 4, 290, 4,  // NOLINT
-  292, 4, 294, 4, 296, 4, 298, 4, 300, 4, 302, 4, 304, 1, 306, 4,  // NOLINT
-  308, 4, 310, 4, 313, 4, 315, 4, 317, 4, 319, 4, 321, 4, 323, 4,  // NOLINT
-  325, 4, 327, 4, 330, 4, 332, 4, 334, 4, 336, 4, 338, 4, 340, 4,  // NOLINT
-  342, 4, 344, 4, 346, 4, 348, 4, 350, 4, 352, 4, 354, 4, 356, 4,  // NOLINT
-  358, 4, 360, 4, 362, 4, 364, 4, 366, 4, 368, 4, 370, 4, 372, 4,  // NOLINT
-  374, 4, 376, -484, 377, 4, 379, 4, 381, 4, 385, 840, 386, 4, 388, 4,  // NOLINT
-  390, 824, 391, 4, 1073742217, 820, 394, 820, 395, 4, 398, 316, 399, 808, 400, 812,  // NOLINT
-  401, 4, 403, 820, 404, 828, 406, 844, 407, 836, 408, 4, 412, 844, 413, 852,  // NOLINT
-  415, 856, 416, 4, 418, 4, 420, 4, 422, 872, 423, 4, 425, 872, 428, 4,  // NOLINT
-  430, 872, 431, 4, 1073742257, 868, 434, 868, 435, 4, 437, 4, 439, 876, 440, 4,  // NOLINT
-  444, 4, 452, 8, 453, 4, 455, 8, 456, 4, 458, 8, 459, 4, 461, 4,  // NOLINT
-  463, 4, 465, 4, 467, 4, 469, 4, 471, 4, 473, 4, 475, 4, 478, 4,  // NOLINT
-  480, 4, 482, 4, 484, 4, 486, 4, 488, 4, 490, 4, 492, 4, 494, 4,  // NOLINT
-  497, 8, 498, 4, 500, 4, 502, -388, 503, -224, 504, 4, 506, 4, 508, 4,  // NOLINT
-  510, 4, 512, 4, 514, 4, 516, 4, 518, 4, 520, 4, 522, 4, 524, 4,  // NOLINT
-  526, 4, 528, 4, 530, 4, 532, 4, 534, 4, 536, 4, 538, 4, 540, 4,  // NOLINT
-  542, 4, 544, -520, 546, 4, 548, 4, 550, 4, 552, 4, 554, 4, 556, 4,  // NOLINT
-  558, 4, 560, 4, 562, 4, 570, 43180, 571, 4, 573, -652, 574, 43168, 577, 4,  // NOLINT
-  579, -780, 580, 276, 581, 284, 582, 4, 584, 4, 586, 4, 588, 4, 590, 4,  // NOLINT
-  880, 4, 882, 4, 886, 4, 902, 152, 1073742728, 148, 906, 148, 908, 256, 1073742734, 252,  // NOLINT
-  911, 252, 1073742737, 128, 929, 128, 931, 6, 1073742756, 128, 939, 128, 975, 32, 984, 4,  // NOLINT
-  986, 4, 988, 4, 990, 4, 992, 4, 994, 4, 996, 4, 998, 4, 1000, 4,  // NOLINT
-  1002, 4, 1004, 4, 1006, 4, 1012, -240, 1015, 4, 1017, -28, 1018, 4, 1073742845, -520,  // NOLINT
-  1023, -520, 1073742848, 320, 1039, 320, 1073742864, 128, 1071, 128, 1120, 4, 1122, 4, 1124, 4,  // NOLINT
-  1126, 4, 1128, 4, 1130, 4, 1132, 4, 1134, 4, 1136, 4, 1138, 4, 1140, 4,  // NOLINT
-  1142, 4, 1144, 4, 1146, 4, 1148, 4, 1150, 4, 1152, 4, 1162, 4, 1164, 4,  // NOLINT
-  1166, 4, 1168, 4, 1170, 4, 1172, 4, 1174, 4, 1176, 4, 1178, 4, 1180, 4,  // NOLINT
-  1182, 4, 1184, 4, 1186, 4, 1188, 4, 1190, 4, 1192, 4, 1194, 4, 1196, 4,  // NOLINT
-  1198, 4, 1200, 4, 1202, 4, 1204, 4, 1206, 4, 1208, 4, 1210, 4, 1212, 4,  // NOLINT
-  1214, 4, 1216, 60, 1217, 4, 1219, 4, 1221, 4, 1223, 4, 1225, 4, 1227, 4,  // NOLINT
-  1229, 4, 1232, 4, 1234, 4, 1236, 4, 1238, 4, 1240, 4, 1242, 4, 1244, 4,  // NOLINT
-  1246, 4, 1248, 4, 1250, 4, 1252, 4, 1254, 4, 1256, 4, 1258, 4, 1260, 4,  // NOLINT
-  1262, 4, 1264, 4, 1266, 4, 1268, 4, 1270, 4, 1272, 4, 1274, 4, 1276, 4,  // NOLINT
-  1278, 4, 1280, 4, 1282, 4, 1284, 4, 1286, 4, 1288, 4, 1290, 4, 1292, 4,  // NOLINT
-  1294, 4, 1296, 4, 1298, 4, 1300, 4, 1302, 4, 1304, 4, 1306, 4, 1308, 4,  // NOLINT
-  1310, 4, 1312, 4, 1314, 4, 1316, 4, 1318, 4, 1073743153, 192, 1366, 192, 1073746080, 29056,  // NOLINT
-  4293, 29056, 4295, 29056, 4301, 29056, 7680, 4, 7682, 4, 7684, 4, 7686, 4, 7688, 4,  // NOLINT
-  7690, 4, 7692, 4, 7694, 4, 7696, 4, 7698, 4, 7700, 4, 7702, 4, 7704, 4,  // NOLINT
-  7706, 4, 7708, 4, 7710, 4, 7712, 4, 7714, 4, 7716, 4, 7718, 4, 7720, 4,  // NOLINT
-  7722, 4, 7724, 4, 7726, 4, 7728, 4, 7730, 4, 7732, 4, 7734, 4, 7736, 4,  // NOLINT
-  7738, 4, 7740, 4, 7742, 4, 7744, 4, 7746, 4, 7748, 4, 7750, 4, 7752, 4,  // NOLINT
-  7754, 4, 7756, 4, 7758, 4, 7760, 4, 7762, 4, 7764, 4, 7766, 4, 7768, 4,  // NOLINT
-  7770, 4, 7772, 4, 7774, 4, 7776, 4, 7778, 4, 7780, 4, 7782, 4, 7784, 4,  // NOLINT
-  7786, 4, 7788, 4, 7790, 4, 7792, 4, 7794, 4, 7796, 4, 7798, 4, 7800, 4,  // NOLINT
-  7802, 4, 7804, 4, 7806, 4, 7808, 4, 7810, 4, 7812, 4, 7814, 4, 7816, 4,  // NOLINT
-  7818, 4, 7820, 4, 7822, 4, 7824, 4, 7826, 4, 7828, 4, 7838, -30460, 7840, 4,  // NOLINT
-  7842, 4, 7844, 4, 7846, 4, 7848, 4, 7850, 4, 7852, 4, 7854, 4, 7856, 4,  // NOLINT
-  7858, 4, 7860, 4, 7862, 4, 7864, 4, 7866, 4, 7868, 4, 7870, 4, 7872, 4,  // NOLINT
-  7874, 4, 7876, 4, 7878, 4, 7880, 4, 7882, 4, 7884, 4, 7886, 4, 7888, 4,  // NOLINT
-  7890, 4, 7892, 4, 7894, 4, 7896, 4, 7898, 4, 7900, 4, 7902, 4, 7904, 4,  // NOLINT
-  7906, 4, 7908, 4, 7910, 4, 7912, 4, 7914, 4, 7916, 4, 7918, 4, 7920, 4,  // NOLINT
-  7922, 4, 7924, 4, 7926, 4, 7928, 4, 7930, 4, 7932, 4, 7934, 4, 1073749768, -32,  // NOLINT
-  7951, -32, 1073749784, -32, 7965, -32, 1073749800, -32, 7983, -32, 1073749816, -32, 7999, -32, 1073749832, -32,  // NOLINT
-  8013, -32, 8025, -32, 8027, -32, 8029, -32, 8031, -32, 1073749864, -32, 8047, -32, 1073749896, -32,  // NOLINT
-  8079, -32, 1073749912, -32, 8095, -32, 1073749928, -32, 8111, -32, 1073749944, -32, 8121, -32, 1073749946, -296,  // NOLINT
-  8123, -296, 8124, -36, 1073749960, -344, 8139, -344, 8140, -36, 1073749976, -32, 8153, -32, 1073749978, -400,  // NOLINT
-  8155, -400, 1073749992, -32, 8169, -32, 1073749994, -448, 8171, -448, 8172, -28, 1073750008, -512, 8185, -512,  // NOLINT
-  1073750010, -504, 8187, -504, 8188, -36 };  // NOLINT
+static const uint16_t kToLowercaseTable0Size = 488;  // NOLINT
+static const int32_t kToLowercaseTable0[976] = {
+    1073741889, 128,    90,         128,   1073742016, 128,
+    214,        128,    1073742040, 128,   222,        128,
+    256,        4,      258,        4,  // NOLINT
+    260,        4,      262,        4,     264,        4,
+    266,        4,      268,        4,     270,        4,
+    272,        4,      274,        4,  // NOLINT
+    276,        4,      278,        4,     280,        4,
+    282,        4,      284,        4,     286,        4,
+    288,        4,      290,        4,  // NOLINT
+    292,        4,      294,        4,     296,        4,
+    298,        4,      300,        4,     302,        4,
+    304,        1,      306,        4,  // NOLINT
+    308,        4,      310,        4,     313,        4,
+    315,        4,      317,        4,     319,        4,
+    321,        4,      323,        4,  // NOLINT
+    325,        4,      327,        4,     330,        4,
+    332,        4,      334,        4,     336,        4,
+    338,        4,      340,        4,  // NOLINT
+    342,        4,      344,        4,     346,        4,
+    348,        4,      350,        4,     352,        4,
+    354,        4,      356,        4,  // NOLINT
+    358,        4,      360,        4,     362,        4,
+    364,        4,      366,        4,     368,        4,
+    370,        4,      372,        4,  // NOLINT
+    374,        4,      376,        -484,  377,        4,
+    379,        4,      381,        4,     385,        840,
+    386,        4,      388,        4,  // NOLINT
+    390,        824,    391,        4,     1073742217, 820,
+    394,        820,    395,        4,     398,        316,
+    399,        808,    400,        812,  // NOLINT
+    401,        4,      403,        820,   404,        828,
+    406,        844,    407,        836,   408,        4,
+    412,        844,    413,        852,  // NOLINT
+    415,        856,    416,        4,     418,        4,
+    420,        4,      422,        872,   423,        4,
+    425,        872,    428,        4,  // NOLINT
+    430,        872,    431,        4,     1073742257, 868,
+    434,        868,    435,        4,     437,        4,
+    439,        876,    440,        4,  // NOLINT
+    444,        4,      452,        8,     453,        4,
+    455,        8,      456,        4,     458,        8,
+    459,        4,      461,        4,  // NOLINT
+    463,        4,      465,        4,     467,        4,
+    469,        4,      471,        4,     473,        4,
+    475,        4,      478,        4,  // NOLINT
+    480,        4,      482,        4,     484,        4,
+    486,        4,      488,        4,     490,        4,
+    492,        4,      494,        4,  // NOLINT
+    497,        8,      498,        4,     500,        4,
+    502,        -388,   503,        -224,  504,        4,
+    506,        4,      508,        4,  // NOLINT
+    510,        4,      512,        4,     514,        4,
+    516,        4,      518,        4,     520,        4,
+    522,        4,      524,        4,  // NOLINT
+    526,        4,      528,        4,     530,        4,
+    532,        4,      534,        4,     536,        4,
+    538,        4,      540,        4,  // NOLINT
+    542,        4,      544,        -520,  546,        4,
+    548,        4,      550,        4,     552,        4,
+    554,        4,      556,        4,  // NOLINT
+    558,        4,      560,        4,     562,        4,
+    570,        43180,  571,        4,     573,        -652,
+    574,        43168,  577,        4,  // NOLINT
+    579,        -780,   580,        276,   581,        284,
+    582,        4,      584,        4,     586,        4,
+    588,        4,      590,        4,  // NOLINT
+    880,        4,      882,        4,     886,        4,
+    895,        464,    902,        152,   1073742728, 148,
+    906,        148,    908,        256,  // NOLINT
+    1073742734, 252,    911,        252,   1073742737, 128,
+    929,        128,    931,        6,     1073742756, 128,
+    939,        128,    975,        32,  // NOLINT
+    984,        4,      986,        4,     988,        4,
+    990,        4,      992,        4,     994,        4,
+    996,        4,      998,        4,  // NOLINT
+    1000,       4,      1002,       4,     1004,       4,
+    1006,       4,      1012,       -240,  1015,       4,
+    1017,       -28,    1018,       4,  // NOLINT
+    1073742845, -520,   1023,       -520,  1073742848, 320,
+    1039,       320,    1073742864, 128,   1071,       128,
+    1120,       4,      1122,       4,  // NOLINT
+    1124,       4,      1126,       4,     1128,       4,
+    1130,       4,      1132,       4,     1134,       4,
+    1136,       4,      1138,       4,  // NOLINT
+    1140,       4,      1142,       4,     1144,       4,
+    1146,       4,      1148,       4,     1150,       4,
+    1152,       4,      1162,       4,  // NOLINT
+    1164,       4,      1166,       4,     1168,       4,
+    1170,       4,      1172,       4,     1174,       4,
+    1176,       4,      1178,       4,  // NOLINT
+    1180,       4,      1182,       4,     1184,       4,
+    1186,       4,      1188,       4,     1190,       4,
+    1192,       4,      1194,       4,  // NOLINT
+    1196,       4,      1198,       4,     1200,       4,
+    1202,       4,      1204,       4,     1206,       4,
+    1208,       4,      1210,       4,  // NOLINT
+    1212,       4,      1214,       4,     1216,       60,
+    1217,       4,      1219,       4,     1221,       4,
+    1223,       4,      1225,       4,  // NOLINT
+    1227,       4,      1229,       4,     1232,       4,
+    1234,       4,      1236,       4,     1238,       4,
+    1240,       4,      1242,       4,  // NOLINT
+    1244,       4,      1246,       4,     1248,       4,
+    1250,       4,      1252,       4,     1254,       4,
+    1256,       4,      1258,       4,  // NOLINT
+    1260,       4,      1262,       4,     1264,       4,
+    1266,       4,      1268,       4,     1270,       4,
+    1272,       4,      1274,       4,  // NOLINT
+    1276,       4,      1278,       4,     1280,       4,
+    1282,       4,      1284,       4,     1286,       4,
+    1288,       4,      1290,       4,  // NOLINT
+    1292,       4,      1294,       4,     1296,       4,
+    1298,       4,      1300,       4,     1302,       4,
+    1304,       4,      1306,       4,  // NOLINT
+    1308,       4,      1310,       4,     1312,       4,
+    1314,       4,      1316,       4,     1318,       4,
+    1320,       4,      1322,       4,  // NOLINT
+    1324,       4,      1326,       4,     1073743153, 192,
+    1366,       192,    1073746080, 29056, 4293,       29056,
+    4295,       29056,  4301,       29056,  // NOLINT
+    7680,       4,      7682,       4,     7684,       4,
+    7686,       4,      7688,       4,     7690,       4,
+    7692,       4,      7694,       4,  // NOLINT
+    7696,       4,      7698,       4,     7700,       4,
+    7702,       4,      7704,       4,     7706,       4,
+    7708,       4,      7710,       4,  // NOLINT
+    7712,       4,      7714,       4,     7716,       4,
+    7718,       4,      7720,       4,     7722,       4,
+    7724,       4,      7726,       4,  // NOLINT
+    7728,       4,      7730,       4,     7732,       4,
+    7734,       4,      7736,       4,     7738,       4,
+    7740,       4,      7742,       4,  // NOLINT
+    7744,       4,      7746,       4,     7748,       4,
+    7750,       4,      7752,       4,     7754,       4,
+    7756,       4,      7758,       4,  // NOLINT
+    7760,       4,      7762,       4,     7764,       4,
+    7766,       4,      7768,       4,     7770,       4,
+    7772,       4,      7774,       4,  // NOLINT
+    7776,       4,      7778,       4,     7780,       4,
+    7782,       4,      7784,       4,     7786,       4,
+    7788,       4,      7790,       4,  // NOLINT
+    7792,       4,      7794,       4,     7796,       4,
+    7798,       4,      7800,       4,     7802,       4,
+    7804,       4,      7806,       4,  // NOLINT
+    7808,       4,      7810,       4,     7812,       4,
+    7814,       4,      7816,       4,     7818,       4,
+    7820,       4,      7822,       4,  // NOLINT
+    7824,       4,      7826,       4,     7828,       4,
+    7838,       -30460, 7840,       4,     7842,       4,
+    7844,       4,      7846,       4,  // NOLINT
+    7848,       4,      7850,       4,     7852,       4,
+    7854,       4,      7856,       4,     7858,       4,
+    7860,       4,      7862,       4,  // NOLINT
+    7864,       4,      7866,       4,     7868,       4,
+    7870,       4,      7872,       4,     7874,       4,
+    7876,       4,      7878,       4,  // NOLINT
+    7880,       4,      7882,       4,     7884,       4,
+    7886,       4,      7888,       4,     7890,       4,
+    7892,       4,      7894,       4,  // NOLINT
+    7896,       4,      7898,       4,     7900,       4,
+    7902,       4,      7904,       4,     7906,       4,
+    7908,       4,      7910,       4,  // NOLINT
+    7912,       4,      7914,       4,     7916,       4,
+    7918,       4,      7920,       4,     7922,       4,
+    7924,       4,      7926,       4,  // NOLINT
+    7928,       4,      7930,       4,     7932,       4,
+    7934,       4,      1073749768, -32,   7951,       -32,
+    1073749784, -32,    7965,       -32,  // NOLINT
+    1073749800, -32,    7983,       -32,   1073749816, -32,
+    7999,       -32,    1073749832, -32,   8013,       -32,
+    8025,       -32,    8027,       -32,  // NOLINT
+    8029,       -32,    8031,       -32,   1073749864, -32,
+    8047,       -32,    1073749896, -32,   8079,       -32,
+    1073749912, -32,    8095,       -32,  // NOLINT
+    1073749928, -32,    8111,       -32,   1073749944, -32,
+    8121,       -32,    1073749946, -296,  8123,       -296,
+    8124,       -36,    1073749960, -344,  // NOLINT
+    8139,       -344,   8140,       -36,   1073749976, -32,
+    8153,       -32,    1073749978, -400,  8155,       -400,
+    1073749992, -32,    8169,       -32,  // NOLINT
+    1073749994, -448,   8171,       -448,  8172,       -28,
+    1073750008, -512,   8185,       -512,  1073750010, -504,
+    8187,       -504,   8188,       -36};                 // NOLINT
 static const uint16_t kToLowercaseMultiStrings0Size = 2;  // NOLINT
 static const MultiCharacterSpecialCase<1> kToLowercaseMultiStrings1[1] = {  // NOLINT
   {{kSentinel}} }; // NOLINT
@@ -948,20 +1418,34 @@
 static const uint16_t kToLowercaseMultiStrings1Size = 1;  // NOLINT
 static const MultiCharacterSpecialCase<1> kToLowercaseMultiStrings5[1] = {  // NOLINT
   {{kSentinel}} }; // NOLINT
-static const uint16_t kToLowercaseTable5Size = 91;  // NOLINT
-static const int32_t kToLowercaseTable5[182] = {
-  1600, 4, 1602, 4, 1604, 4, 1606, 4, 1608, 4, 1610, 4, 1612, 4, 1614, 4,  // NOLINT
-  1616, 4, 1618, 4, 1620, 4, 1622, 4, 1624, 4, 1626, 4, 1628, 4, 1630, 4,  // NOLINT
-  1632, 4, 1634, 4, 1636, 4, 1638, 4, 1640, 4, 1642, 4, 1644, 4, 1664, 4,  // NOLINT
-  1666, 4, 1668, 4, 1670, 4, 1672, 4, 1674, 4, 1676, 4, 1678, 4, 1680, 4,  // NOLINT
-  1682, 4, 1684, 4, 1686, 4, 1826, 4, 1828, 4, 1830, 4, 1832, 4, 1834, 4,  // NOLINT
-  1836, 4, 1838, 4, 1842, 4, 1844, 4, 1846, 4, 1848, 4, 1850, 4, 1852, 4,  // NOLINT
-  1854, 4, 1856, 4, 1858, 4, 1860, 4, 1862, 4, 1864, 4, 1866, 4, 1868, 4,  // NOLINT
-  1870, 4, 1872, 4, 1874, 4, 1876, 4, 1878, 4, 1880, 4, 1882, 4, 1884, 4,  // NOLINT
-  1886, 4, 1888, 4, 1890, 4, 1892, 4, 1894, 4, 1896, 4, 1898, 4, 1900, 4,  // NOLINT
-  1902, 4, 1913, 4, 1915, 4, 1917, -141328, 1918, 4, 1920, 4, 1922, 4, 1924, 4,  // NOLINT
-  1926, 4, 1931, 4, 1933, -169120, 1936, 4, 1938, 4, 1952, 4, 1954, 4, 1956, 4,  // NOLINT
-  1958, 4, 1960, 4, 1962, -169232 };  // NOLINT
+static const uint16_t kToLowercaseTable5Size = 103;  // NOLINT
+static const int32_t kToLowercaseTable5[206] = {
+    1600, 4,       1602, 4,       1604, 4,       1606, 4,
+    1608, 4,       1610, 4,       1612, 4,       1614, 4,  // NOLINT
+    1616, 4,       1618, 4,       1620, 4,       1622, 4,
+    1624, 4,       1626, 4,       1628, 4,       1630, 4,  // NOLINT
+    1632, 4,       1634, 4,       1636, 4,       1638, 4,
+    1640, 4,       1642, 4,       1644, 4,       1664, 4,  // NOLINT
+    1666, 4,       1668, 4,       1670, 4,       1672, 4,
+    1674, 4,       1676, 4,       1678, 4,       1680, 4,  // NOLINT
+    1682, 4,       1684, 4,       1686, 4,       1688, 4,
+    1690, 4,       1826, 4,       1828, 4,       1830, 4,  // NOLINT
+    1832, 4,       1834, 4,       1836, 4,       1838, 4,
+    1842, 4,       1844, 4,       1846, 4,       1848, 4,  // NOLINT
+    1850, 4,       1852, 4,       1854, 4,       1856, 4,
+    1858, 4,       1860, 4,       1862, 4,       1864, 4,  // NOLINT
+    1866, 4,       1868, 4,       1870, 4,       1872, 4,
+    1874, 4,       1876, 4,       1878, 4,       1880, 4,  // NOLINT
+    1882, 4,       1884, 4,       1886, 4,       1888, 4,
+    1890, 4,       1892, 4,       1894, 4,       1896, 4,  // NOLINT
+    1898, 4,       1900, 4,       1902, 4,       1913, 4,
+    1915, 4,       1917, -141328, 1918, 4,       1920, 4,  // NOLINT
+    1922, 4,       1924, 4,       1926, 4,       1931, 4,
+    1933, -169120, 1936, 4,       1938, 4,       1942, 4,  // NOLINT
+    1944, 4,       1946, 4,       1948, 4,       1950, 4,
+    1952, 4,       1954, 4,       1956, 4,       1958, 4,  // NOLINT
+    1960, 4,       1962, -169232, 1963, -169276, 1964, -169260,
+    1965, -169220, 1968, -169032, 1969, -169128};         // NOLINT
 static const uint16_t kToLowercaseMultiStrings5Size = 1;  // NOLINT
 static const MultiCharacterSpecialCase<1> kToLowercaseMultiStrings7[1] = {  // NOLINT
   {{kSentinel}} }; // NOLINT
@@ -1024,81 +1508,229 @@
   {{933, 776, 768}}, {{929, 787, kSentinel}}, {{933, 834, kSentinel}}, {{933, 776, 834}},  // NOLINT
   {{8186, 921, kSentinel}}, {{937, 921, kSentinel}}, {{911, 921, kSentinel}}, {{937, 834, kSentinel}},  // NOLINT
   {{937, 834, 921}}, {{kSentinel}} }; // NOLINT
-static const uint16_t kToUppercaseTable0Size = 580;  // NOLINT
-static const int32_t kToUppercaseTable0[1160] = {
-  1073741921, -128, 122, -128, 181, 2972, 223, 1, 1073742048, -128, 246, -128, 1073742072, -128, 254, -128,  // NOLINT
-  255, 484, 257, -4, 259, -4, 261, -4, 263, -4, 265, -4, 267, -4, 269, -4,  // NOLINT
-  271, -4, 273, -4, 275, -4, 277, -4, 279, -4, 281, -4, 283, -4, 285, -4,  // NOLINT
-  287, -4, 289, -4, 291, -4, 293, -4, 295, -4, 297, -4, 299, -4, 301, -4,  // NOLINT
-  303, -4, 305, -928, 307, -4, 309, -4, 311, -4, 314, -4, 316, -4, 318, -4,  // NOLINT
-  320, -4, 322, -4, 324, -4, 326, -4, 328, -4, 329, 5, 331, -4, 333, -4,  // NOLINT
-  335, -4, 337, -4, 339, -4, 341, -4, 343, -4, 345, -4, 347, -4, 349, -4,  // NOLINT
-  351, -4, 353, -4, 355, -4, 357, -4, 359, -4, 361, -4, 363, -4, 365, -4,  // NOLINT
-  367, -4, 369, -4, 371, -4, 373, -4, 375, -4, 378, -4, 380, -4, 382, -4,  // NOLINT
-  383, -1200, 384, 780, 387, -4, 389, -4, 392, -4, 396, -4, 402, -4, 405, 388,  // NOLINT
-  409, -4, 410, 652, 414, 520, 417, -4, 419, -4, 421, -4, 424, -4, 429, -4,  // NOLINT
-  432, -4, 436, -4, 438, -4, 441, -4, 445, -4, 447, 224, 453, -4, 454, -8,  // NOLINT
-  456, -4, 457, -8, 459, -4, 460, -8, 462, -4, 464, -4, 466, -4, 468, -4,  // NOLINT
-  470, -4, 472, -4, 474, -4, 476, -4, 477, -316, 479, -4, 481, -4, 483, -4,  // NOLINT
-  485, -4, 487, -4, 489, -4, 491, -4, 493, -4, 495, -4, 496, 9, 498, -4,  // NOLINT
-  499, -8, 501, -4, 505, -4, 507, -4, 509, -4, 511, -4, 513, -4, 515, -4,  // NOLINT
-  517, -4, 519, -4, 521, -4, 523, -4, 525, -4, 527, -4, 529, -4, 531, -4,  // NOLINT
-  533, -4, 535, -4, 537, -4, 539, -4, 541, -4, 543, -4, 547, -4, 549, -4,  // NOLINT
-  551, -4, 553, -4, 555, -4, 557, -4, 559, -4, 561, -4, 563, -4, 572, -4,  // NOLINT
-  1073742399, 43260, 576, 43260, 578, -4, 583, -4, 585, -4, 587, -4, 589, -4, 591, -4,  // NOLINT
-  592, 43132, 593, 43120, 594, 43128, 595, -840, 596, -824, 1073742422, -820, 599, -820, 601, -808,  // NOLINT
-  603, -812, 608, -820, 611, -828, 613, 169120, 614, 169232, 616, -836, 617, -844, 619, 42972,  // NOLINT
-  623, -844, 625, 42996, 626, -852, 629, -856, 637, 42908, 640, -872, 643, -872, 648, -872,  // NOLINT
-  649, -276, 1073742474, -868, 651, -868, 652, -284, 658, -876, 837, 336, 881, -4, 883, -4,  // NOLINT
-  887, -4, 1073742715, 520, 893, 520, 912, 13, 940, -152, 1073742765, -148, 943, -148, 944, 17,  // NOLINT
-  1073742769, -128, 961, -128, 962, -124, 1073742787, -128, 971, -128, 972, -256, 1073742797, -252, 974, -252,  // NOLINT
-  976, -248, 977, -228, 981, -188, 982, -216, 983, -32, 985, -4, 987, -4, 989, -4,  // NOLINT
-  991, -4, 993, -4, 995, -4, 997, -4, 999, -4, 1001, -4, 1003, -4, 1005, -4,  // NOLINT
-  1007, -4, 1008, -344, 1009, -320, 1010, 28, 1013, -384, 1016, -4, 1019, -4, 1073742896, -128,  // NOLINT
-  1103, -128, 1073742928, -320, 1119, -320, 1121, -4, 1123, -4, 1125, -4, 1127, -4, 1129, -4,  // NOLINT
-  1131, -4, 1133, -4, 1135, -4, 1137, -4, 1139, -4, 1141, -4, 1143, -4, 1145, -4,  // NOLINT
-  1147, -4, 1149, -4, 1151, -4, 1153, -4, 1163, -4, 1165, -4, 1167, -4, 1169, -4,  // NOLINT
-  1171, -4, 1173, -4, 1175, -4, 1177, -4, 1179, -4, 1181, -4, 1183, -4, 1185, -4,  // NOLINT
-  1187, -4, 1189, -4, 1191, -4, 1193, -4, 1195, -4, 1197, -4, 1199, -4, 1201, -4,  // NOLINT
-  1203, -4, 1205, -4, 1207, -4, 1209, -4, 1211, -4, 1213, -4, 1215, -4, 1218, -4,  // NOLINT
-  1220, -4, 1222, -4, 1224, -4, 1226, -4, 1228, -4, 1230, -4, 1231, -60, 1233, -4,  // NOLINT
-  1235, -4, 1237, -4, 1239, -4, 1241, -4, 1243, -4, 1245, -4, 1247, -4, 1249, -4,  // NOLINT
-  1251, -4, 1253, -4, 1255, -4, 1257, -4, 1259, -4, 1261, -4, 1263, -4, 1265, -4,  // NOLINT
-  1267, -4, 1269, -4, 1271, -4, 1273, -4, 1275, -4, 1277, -4, 1279, -4, 1281, -4,  // NOLINT
-  1283, -4, 1285, -4, 1287, -4, 1289, -4, 1291, -4, 1293, -4, 1295, -4, 1297, -4,  // NOLINT
-  1299, -4, 1301, -4, 1303, -4, 1305, -4, 1307, -4, 1309, -4, 1311, -4, 1313, -4,  // NOLINT
-  1315, -4, 1317, -4, 1319, -4, 1073743201, -192, 1414, -192, 1415, 21, 7545, 141328, 7549, 15256,  // NOLINT
-  7681, -4, 7683, -4, 7685, -4, 7687, -4, 7689, -4, 7691, -4, 7693, -4, 7695, -4,  // NOLINT
-  7697, -4, 7699, -4, 7701, -4, 7703, -4, 7705, -4, 7707, -4, 7709, -4, 7711, -4,  // NOLINT
-  7713, -4, 7715, -4, 7717, -4, 7719, -4, 7721, -4, 7723, -4, 7725, -4, 7727, -4,  // NOLINT
-  7729, -4, 7731, -4, 7733, -4, 7735, -4, 7737, -4, 7739, -4, 7741, -4, 7743, -4,  // NOLINT
-  7745, -4, 7747, -4, 7749, -4, 7751, -4, 7753, -4, 7755, -4, 7757, -4, 7759, -4,  // NOLINT
-  7761, -4, 7763, -4, 7765, -4, 7767, -4, 7769, -4, 7771, -4, 7773, -4, 7775, -4,  // NOLINT
-  7777, -4, 7779, -4, 7781, -4, 7783, -4, 7785, -4, 7787, -4, 7789, -4, 7791, -4,  // NOLINT
-  7793, -4, 7795, -4, 7797, -4, 7799, -4, 7801, -4, 7803, -4, 7805, -4, 7807, -4,  // NOLINT
-  7809, -4, 7811, -4, 7813, -4, 7815, -4, 7817, -4, 7819, -4, 7821, -4, 7823, -4,  // NOLINT
-  7825, -4, 7827, -4, 7829, -4, 7830, 25, 7831, 29, 7832, 33, 7833, 37, 7834, 41,  // NOLINT
-  7835, -236, 7841, -4, 7843, -4, 7845, -4, 7847, -4, 7849, -4, 7851, -4, 7853, -4,  // NOLINT
-  7855, -4, 7857, -4, 7859, -4, 7861, -4, 7863, -4, 7865, -4, 7867, -4, 7869, -4,  // NOLINT
-  7871, -4, 7873, -4, 7875, -4, 7877, -4, 7879, -4, 7881, -4, 7883, -4, 7885, -4,  // NOLINT
-  7887, -4, 7889, -4, 7891, -4, 7893, -4, 7895, -4, 7897, -4, 7899, -4, 7901, -4,  // NOLINT
-  7903, -4, 7905, -4, 7907, -4, 7909, -4, 7911, -4, 7913, -4, 7915, -4, 7917, -4,  // NOLINT
-  7919, -4, 7921, -4, 7923, -4, 7925, -4, 7927, -4, 7929, -4, 7931, -4, 7933, -4,  // NOLINT
-  7935, -4, 1073749760, 32, 7943, 32, 1073749776, 32, 7957, 32, 1073749792, 32, 7975, 32, 1073749808, 32,  // NOLINT
-  7991, 32, 1073749824, 32, 8005, 32, 8016, 45, 8017, 32, 8018, 49, 8019, 32, 8020, 53,  // NOLINT
-  8021, 32, 8022, 57, 8023, 32, 1073749856, 32, 8039, 32, 1073749872, 296, 8049, 296, 1073749874, 344,  // NOLINT
-  8053, 344, 1073749878, 400, 8055, 400, 1073749880, 512, 8057, 512, 1073749882, 448, 8059, 448, 1073749884, 504,  // NOLINT
-  8061, 504, 8064, 61, 8065, 65, 8066, 69, 8067, 73, 8068, 77, 8069, 81, 8070, 85,  // NOLINT
-  8071, 89, 8072, 61, 8073, 65, 8074, 69, 8075, 73, 8076, 77, 8077, 81, 8078, 85,  // NOLINT
-  8079, 89, 8080, 93, 8081, 97, 8082, 101, 8083, 105, 8084, 109, 8085, 113, 8086, 117,  // NOLINT
-  8087, 121, 8088, 93, 8089, 97, 8090, 101, 8091, 105, 8092, 109, 8093, 113, 8094, 117,  // NOLINT
-  8095, 121, 8096, 125, 8097, 129, 8098, 133, 8099, 137, 8100, 141, 8101, 145, 8102, 149,  // NOLINT
-  8103, 153, 8104, 125, 8105, 129, 8106, 133, 8107, 137, 8108, 141, 8109, 145, 8110, 149,  // NOLINT
-  8111, 153, 1073749936, 32, 8113, 32, 8114, 157, 8115, 161, 8116, 165, 8118, 169, 8119, 173,  // NOLINT
-  8124, 161, 8126, -28820, 8130, 177, 8131, 181, 8132, 185, 8134, 189, 8135, 193, 8140, 181,  // NOLINT
-  1073749968, 32, 8145, 32, 8146, 197, 8147, 13, 8150, 201, 8151, 205, 1073749984, 32, 8161, 32,  // NOLINT
-  8162, 209, 8163, 17, 8164, 213, 8165, 28, 8166, 217, 8167, 221, 8178, 225, 8179, 229,  // NOLINT
-  8180, 233, 8182, 237, 8183, 241, 8188, 229 };  // NOLINT
+static const uint16_t kToUppercaseTable0Size = 590;  // NOLINT
+static const int32_t kToUppercaseTable0[1180] = {
+    1073741921, -128,   122,        -128,   181,        2972,
+    223,        1,      1073742048, -128,   246,        -128,
+    1073742072, -128,   254,        -128,  // NOLINT
+    255,        484,    257,        -4,     259,        -4,
+    261,        -4,     263,        -4,     265,        -4,
+    267,        -4,     269,        -4,  // NOLINT
+    271,        -4,     273,        -4,     275,        -4,
+    277,        -4,     279,        -4,     281,        -4,
+    283,        -4,     285,        -4,  // NOLINT
+    287,        -4,     289,        -4,     291,        -4,
+    293,        -4,     295,        -4,     297,        -4,
+    299,        -4,     301,        -4,  // NOLINT
+    303,        -4,     305,        -928,   307,        -4,
+    309,        -4,     311,        -4,     314,        -4,
+    316,        -4,     318,        -4,  // NOLINT
+    320,        -4,     322,        -4,     324,        -4,
+    326,        -4,     328,        -4,     329,        5,
+    331,        -4,     333,        -4,  // NOLINT
+    335,        -4,     337,        -4,     339,        -4,
+    341,        -4,     343,        -4,     345,        -4,
+    347,        -4,     349,        -4,  // NOLINT
+    351,        -4,     353,        -4,     355,        -4,
+    357,        -4,     359,        -4,     361,        -4,
+    363,        -4,     365,        -4,  // NOLINT
+    367,        -4,     369,        -4,     371,        -4,
+    373,        -4,     375,        -4,     378,        -4,
+    380,        -4,     382,        -4,  // NOLINT
+    383,        -1200,  384,        780,    387,        -4,
+    389,        -4,     392,        -4,     396,        -4,
+    402,        -4,     405,        388,  // NOLINT
+    409,        -4,     410,        652,    414,        520,
+    417,        -4,     419,        -4,     421,        -4,
+    424,        -4,     429,        -4,  // NOLINT
+    432,        -4,     436,        -4,     438,        -4,
+    441,        -4,     445,        -4,     447,        224,
+    453,        -4,     454,        -8,  // NOLINT
+    456,        -4,     457,        -8,     459,        -4,
+    460,        -8,     462,        -4,     464,        -4,
+    466,        -4,     468,        -4,  // NOLINT
+    470,        -4,     472,        -4,     474,        -4,
+    476,        -4,     477,        -316,   479,        -4,
+    481,        -4,     483,        -4,  // NOLINT
+    485,        -4,     487,        -4,     489,        -4,
+    491,        -4,     493,        -4,     495,        -4,
+    496,        9,      498,        -4,  // NOLINT
+    499,        -8,     501,        -4,     505,        -4,
+    507,        -4,     509,        -4,     511,        -4,
+    513,        -4,     515,        -4,  // NOLINT
+    517,        -4,     519,        -4,     521,        -4,
+    523,        -4,     525,        -4,     527,        -4,
+    529,        -4,     531,        -4,  // NOLINT
+    533,        -4,     535,        -4,     537,        -4,
+    539,        -4,     541,        -4,     543,        -4,
+    547,        -4,     549,        -4,  // NOLINT
+    551,        -4,     553,        -4,     555,        -4,
+    557,        -4,     559,        -4,     561,        -4,
+    563,        -4,     572,        -4,  // NOLINT
+    1073742399, 43260,  576,        43260,  578,        -4,
+    583,        -4,     585,        -4,     587,        -4,
+    589,        -4,     591,        -4,  // NOLINT
+    592,        43132,  593,        43120,  594,        43128,
+    595,        -840,   596,        -824,   1073742422, -820,
+    599,        -820,   601,        -808,  // NOLINT
+    603,        -812,   604,        169276, 608,        -820,
+    609,        169260, 611,        -828,   613,        169120,
+    614,        169232, 616,        -836,  // NOLINT
+    617,        -844,   619,        42972,  620,        169220,
+    623,        -844,   625,        42996,  626,        -852,
+    629,        -856,   637,        42908,  // NOLINT
+    640,        -872,   643,        -872,   647,        169128,
+    648,        -872,   649,        -276,   1073742474, -868,
+    651,        -868,   652,        -284,  // NOLINT
+    658,        -876,   670,        169032, 837,        336,
+    881,        -4,     883,        -4,     887,        -4,
+    1073742715, 520,    893,        520,  // NOLINT
+    912,        13,     940,        -152,   1073742765, -148,
+    943,        -148,   944,        17,     1073742769, -128,
+    961,        -128,   962,        -124,  // NOLINT
+    1073742787, -128,   971,        -128,   972,        -256,
+    1073742797, -252,   974,        -252,   976,        -248,
+    977,        -228,   981,        -188,  // NOLINT
+    982,        -216,   983,        -32,    985,        -4,
+    987,        -4,     989,        -4,     991,        -4,
+    993,        -4,     995,        -4,  // NOLINT
+    997,        -4,     999,        -4,     1001,       -4,
+    1003,       -4,     1005,       -4,     1007,       -4,
+    1008,       -344,   1009,       -320,  // NOLINT
+    1010,       28,     1011,       -464,   1013,       -384,
+    1016,       -4,     1019,       -4,     1073742896, -128,
+    1103,       -128,   1073742928, -320,  // NOLINT
+    1119,       -320,   1121,       -4,     1123,       -4,
+    1125,       -4,     1127,       -4,     1129,       -4,
+    1131,       -4,     1133,       -4,  // NOLINT
+    1135,       -4,     1137,       -4,     1139,       -4,
+    1141,       -4,     1143,       -4,     1145,       -4,
+    1147,       -4,     1149,       -4,  // NOLINT
+    1151,       -4,     1153,       -4,     1163,       -4,
+    1165,       -4,     1167,       -4,     1169,       -4,
+    1171,       -4,     1173,       -4,  // NOLINT
+    1175,       -4,     1177,       -4,     1179,       -4,
+    1181,       -4,     1183,       -4,     1185,       -4,
+    1187,       -4,     1189,       -4,  // NOLINT
+    1191,       -4,     1193,       -4,     1195,       -4,
+    1197,       -4,     1199,       -4,     1201,       -4,
+    1203,       -4,     1205,       -4,  // NOLINT
+    1207,       -4,     1209,       -4,     1211,       -4,
+    1213,       -4,     1215,       -4,     1218,       -4,
+    1220,       -4,     1222,       -4,  // NOLINT
+    1224,       -4,     1226,       -4,     1228,       -4,
+    1230,       -4,     1231,       -60,    1233,       -4,
+    1235,       -4,     1237,       -4,  // NOLINT
+    1239,       -4,     1241,       -4,     1243,       -4,
+    1245,       -4,     1247,       -4,     1249,       -4,
+    1251,       -4,     1253,       -4,  // NOLINT
+    1255,       -4,     1257,       -4,     1259,       -4,
+    1261,       -4,     1263,       -4,     1265,       -4,
+    1267,       -4,     1269,       -4,  // NOLINT
+    1271,       -4,     1273,       -4,     1275,       -4,
+    1277,       -4,     1279,       -4,     1281,       -4,
+    1283,       -4,     1285,       -4,  // NOLINT
+    1287,       -4,     1289,       -4,     1291,       -4,
+    1293,       -4,     1295,       -4,     1297,       -4,
+    1299,       -4,     1301,       -4,  // NOLINT
+    1303,       -4,     1305,       -4,     1307,       -4,
+    1309,       -4,     1311,       -4,     1313,       -4,
+    1315,       -4,     1317,       -4,  // NOLINT
+    1319,       -4,     1321,       -4,     1323,       -4,
+    1325,       -4,     1327,       -4,     1073743201, -192,
+    1414,       -192,   1415,       21,  // NOLINT
+    7545,       141328, 7549,       15256,  7681,       -4,
+    7683,       -4,     7685,       -4,     7687,       -4,
+    7689,       -4,     7691,       -4,  // NOLINT
+    7693,       -4,     7695,       -4,     7697,       -4,
+    7699,       -4,     7701,       -4,     7703,       -4,
+    7705,       -4,     7707,       -4,  // NOLINT
+    7709,       -4,     7711,       -4,     7713,       -4,
+    7715,       -4,     7717,       -4,     7719,       -4,
+    7721,       -4,     7723,       -4,  // NOLINT
+    7725,       -4,     7727,       -4,     7729,       -4,
+    7731,       -4,     7733,       -4,     7735,       -4,
+    7737,       -4,     7739,       -4,  // NOLINT
+    7741,       -4,     7743,       -4,     7745,       -4,
+    7747,       -4,     7749,       -4,     7751,       -4,
+    7753,       -4,     7755,       -4,  // NOLINT
+    7757,       -4,     7759,       -4,     7761,       -4,
+    7763,       -4,     7765,       -4,     7767,       -4,
+    7769,       -4,     7771,       -4,  // NOLINT
+    7773,       -4,     7775,       -4,     7777,       -4,
+    7779,       -4,     7781,       -4,     7783,       -4,
+    7785,       -4,     7787,       -4,  // NOLINT
+    7789,       -4,     7791,       -4,     7793,       -4,
+    7795,       -4,     7797,       -4,     7799,       -4,
+    7801,       -4,     7803,       -4,  // NOLINT
+    7805,       -4,     7807,       -4,     7809,       -4,
+    7811,       -4,     7813,       -4,     7815,       -4,
+    7817,       -4,     7819,       -4,  // NOLINT
+    7821,       -4,     7823,       -4,     7825,       -4,
+    7827,       -4,     7829,       -4,     7830,       25,
+    7831,       29,     7832,       33,  // NOLINT
+    7833,       37,     7834,       41,     7835,       -236,
+    7841,       -4,     7843,       -4,     7845,       -4,
+    7847,       -4,     7849,       -4,  // NOLINT
+    7851,       -4,     7853,       -4,     7855,       -4,
+    7857,       -4,     7859,       -4,     7861,       -4,
+    7863,       -4,     7865,       -4,  // NOLINT
+    7867,       -4,     7869,       -4,     7871,       -4,
+    7873,       -4,     7875,       -4,     7877,       -4,
+    7879,       -4,     7881,       -4,  // NOLINT
+    7883,       -4,     7885,       -4,     7887,       -4,
+    7889,       -4,     7891,       -4,     7893,       -4,
+    7895,       -4,     7897,       -4,  // NOLINT
+    7899,       -4,     7901,       -4,     7903,       -4,
+    7905,       -4,     7907,       -4,     7909,       -4,
+    7911,       -4,     7913,       -4,  // NOLINT
+    7915,       -4,     7917,       -4,     7919,       -4,
+    7921,       -4,     7923,       -4,     7925,       -4,
+    7927,       -4,     7929,       -4,  // NOLINT
+    7931,       -4,     7933,       -4,     7935,       -4,
+    1073749760, 32,     7943,       32,     1073749776, 32,
+    7957,       32,     1073749792, 32,  // NOLINT
+    7975,       32,     1073749808, 32,     7991,       32,
+    1073749824, 32,     8005,       32,     8016,       45,
+    8017,       32,     8018,       49,  // NOLINT
+    8019,       32,     8020,       53,     8021,       32,
+    8022,       57,     8023,       32,     1073749856, 32,
+    8039,       32,     1073749872, 296,  // NOLINT
+    8049,       296,    1073749874, 344,    8053,       344,
+    1073749878, 400,    8055,       400,    1073749880, 512,
+    8057,       512,    1073749882, 448,  // NOLINT
+    8059,       448,    1073749884, 504,    8061,       504,
+    8064,       61,     8065,       65,     8066,       69,
+    8067,       73,     8068,       77,  // NOLINT
+    8069,       81,     8070,       85,     8071,       89,
+    8072,       61,     8073,       65,     8074,       69,
+    8075,       73,     8076,       77,  // NOLINT
+    8077,       81,     8078,       85,     8079,       89,
+    8080,       93,     8081,       97,     8082,       101,
+    8083,       105,    8084,       109,  // NOLINT
+    8085,       113,    8086,       117,    8087,       121,
+    8088,       93,     8089,       97,     8090,       101,
+    8091,       105,    8092,       109,  // NOLINT
+    8093,       113,    8094,       117,    8095,       121,
+    8096,       125,    8097,       129,    8098,       133,
+    8099,       137,    8100,       141,  // NOLINT
+    8101,       145,    8102,       149,    8103,       153,
+    8104,       125,    8105,       129,    8106,       133,
+    8107,       137,    8108,       141,  // NOLINT
+    8109,       145,    8110,       149,    8111,       153,
+    1073749936, 32,     8113,       32,     8114,       157,
+    8115,       161,    8116,       165,  // NOLINT
+    8118,       169,    8119,       173,    8124,       161,
+    8126,       -28820, 8130,       177,    8131,       181,
+    8132,       185,    8134,       189,  // NOLINT
+    8135,       193,    8140,       181,    1073749968, 32,
+    8145,       32,     8146,       197,    8147,       13,
+    8150,       201,    8151,       205,  // NOLINT
+    1073749984, 32,     8161,       32,     8162,       209,
+    8163,       17,     8164,       213,    8165,       28,
+    8166,       217,    8167,       221,  // NOLINT
+    8178,       225,    8179,       229,    8180,       233,
+    8182,       237,    8183,       241,    8188,       229};  // NOLINT
 static const uint16_t kToUppercaseMultiStrings0Size = 62;  // NOLINT
 static const MultiCharacterSpecialCase<1> kToUppercaseMultiStrings1[1] = {  // NOLINT
   {{kSentinel}} }; // NOLINT
@@ -1117,19 +1749,32 @@
 static const uint16_t kToUppercaseMultiStrings1Size = 1;  // NOLINT
 static const MultiCharacterSpecialCase<1> kToUppercaseMultiStrings5[1] = {  // NOLINT
   {{kSentinel}} }; // NOLINT
-static const uint16_t kToUppercaseTable5Size = 88;  // NOLINT
-static const int32_t kToUppercaseTable5[176] = {
-  1601, -4, 1603, -4, 1605, -4, 1607, -4, 1609, -4, 1611, -4, 1613, -4, 1615, -4,  // NOLINT
-  1617, -4, 1619, -4, 1621, -4, 1623, -4, 1625, -4, 1627, -4, 1629, -4, 1631, -4,  // NOLINT
-  1633, -4, 1635, -4, 1637, -4, 1639, -4, 1641, -4, 1643, -4, 1645, -4, 1665, -4,  // NOLINT
-  1667, -4, 1669, -4, 1671, -4, 1673, -4, 1675, -4, 1677, -4, 1679, -4, 1681, -4,  // NOLINT
-  1683, -4, 1685, -4, 1687, -4, 1827, -4, 1829, -4, 1831, -4, 1833, -4, 1835, -4,  // NOLINT
-  1837, -4, 1839, -4, 1843, -4, 1845, -4, 1847, -4, 1849, -4, 1851, -4, 1853, -4,  // NOLINT
-  1855, -4, 1857, -4, 1859, -4, 1861, -4, 1863, -4, 1865, -4, 1867, -4, 1869, -4,  // NOLINT
-  1871, -4, 1873, -4, 1875, -4, 1877, -4, 1879, -4, 1881, -4, 1883, -4, 1885, -4,  // NOLINT
-  1887, -4, 1889, -4, 1891, -4, 1893, -4, 1895, -4, 1897, -4, 1899, -4, 1901, -4,  // NOLINT
-  1903, -4, 1914, -4, 1916, -4, 1919, -4, 1921, -4, 1923, -4, 1925, -4, 1927, -4,  // NOLINT
-  1932, -4, 1937, -4, 1939, -4, 1953, -4, 1955, -4, 1957, -4, 1959, -4, 1961, -4 };  // NOLINT
+static const uint16_t kToUppercaseTable5Size = 95;  // NOLINT
+static const int32_t
+    kToUppercaseTable5[190] = {1601, -4, 1603, -4, 1605, -4, 1607, -4, 1609, -4,
+                               1611, -4, 1613, -4, 1615, -4,  // NOLINT
+                               1617, -4, 1619, -4, 1621, -4, 1623, -4, 1625, -4,
+                               1627, -4, 1629, -4, 1631, -4,  // NOLINT
+                               1633, -4, 1635, -4, 1637, -4, 1639, -4, 1641, -4,
+                               1643, -4, 1645, -4, 1665, -4,  // NOLINT
+                               1667, -4, 1669, -4, 1671, -4, 1673, -4, 1675, -4,
+                               1677, -4, 1679, -4, 1681, -4,  // NOLINT
+                               1683, -4, 1685, -4, 1687, -4, 1689, -4, 1691, -4,
+                               1827, -4, 1829, -4, 1831, -4,  // NOLINT
+                               1833, -4, 1835, -4, 1837, -4, 1839, -4, 1843, -4,
+                               1845, -4, 1847, -4, 1849, -4,  // NOLINT
+                               1851, -4, 1853, -4, 1855, -4, 1857, -4, 1859, -4,
+                               1861, -4, 1863, -4, 1865, -4,  // NOLINT
+                               1867, -4, 1869, -4, 1871, -4, 1873, -4, 1875, -4,
+                               1877, -4, 1879, -4, 1881, -4,  // NOLINT
+                               1883, -4, 1885, -4, 1887, -4, 1889, -4, 1891, -4,
+                               1893, -4, 1895, -4, 1897, -4,  // NOLINT
+                               1899, -4, 1901, -4, 1903, -4, 1914, -4, 1916, -4,
+                               1919, -4, 1921, -4, 1923, -4,  // NOLINT
+                               1925, -4, 1927, -4, 1932, -4, 1937, -4, 1939, -4,
+                               1943, -4, 1945, -4, 1947, -4,  // NOLINT
+                               1949, -4, 1951, -4, 1953, -4, 1955, -4, 1957, -4,
+                               1959, -4, 1961, -4};       // NOLINT
 static const uint16_t kToUppercaseMultiStrings5Size = 1;  // NOLINT
 static const MultiCharacterSpecialCase<3> kToUppercaseMultiStrings7[12] = {  // NOLINT
   {{70, 70, kSentinel}}, {{70, 73, kSentinel}}, {{70, 76, kSentinel}}, {{70, 70, 73}},  // NOLINT
@@ -1180,69 +1825,195 @@
 
 static const MultiCharacterSpecialCase<1> kEcma262CanonicalizeMultiStrings0[1] = {  // NOLINT
   {{kSentinel}} }; // NOLINT
-static const uint16_t kEcma262CanonicalizeTable0Size = 488;  // NOLINT
-static const int32_t kEcma262CanonicalizeTable0[976] = {
-  1073741921, -128, 122, -128, 181, 2972, 1073742048, -128, 246, -128, 1073742072, -128, 254, -128, 255, 484,  // NOLINT
-  257, -4, 259, -4, 261, -4, 263, -4, 265, -4, 267, -4, 269, -4, 271, -4,  // NOLINT
-  273, -4, 275, -4, 277, -4, 279, -4, 281, -4, 283, -4, 285, -4, 287, -4,  // NOLINT
-  289, -4, 291, -4, 293, -4, 295, -4, 297, -4, 299, -4, 301, -4, 303, -4,  // NOLINT
-  307, -4, 309, -4, 311, -4, 314, -4, 316, -4, 318, -4, 320, -4, 322, -4,  // NOLINT
-  324, -4, 326, -4, 328, -4, 331, -4, 333, -4, 335, -4, 337, -4, 339, -4,  // NOLINT
-  341, -4, 343, -4, 345, -4, 347, -4, 349, -4, 351, -4, 353, -4, 355, -4,  // NOLINT
-  357, -4, 359, -4, 361, -4, 363, -4, 365, -4, 367, -4, 369, -4, 371, -4,  // NOLINT
-  373, -4, 375, -4, 378, -4, 380, -4, 382, -4, 384, 780, 387, -4, 389, -4,  // NOLINT
-  392, -4, 396, -4, 402, -4, 405, 388, 409, -4, 410, 652, 414, 520, 417, -4,  // NOLINT
-  419, -4, 421, -4, 424, -4, 429, -4, 432, -4, 436, -4, 438, -4, 441, -4,  // NOLINT
-  445, -4, 447, 224, 453, -4, 454, -8, 456, -4, 457, -8, 459, -4, 460, -8,  // NOLINT
-  462, -4, 464, -4, 466, -4, 468, -4, 470, -4, 472, -4, 474, -4, 476, -4,  // NOLINT
-  477, -316, 479, -4, 481, -4, 483, -4, 485, -4, 487, -4, 489, -4, 491, -4,  // NOLINT
-  493, -4, 495, -4, 498, -4, 499, -8, 501, -4, 505, -4, 507, -4, 509, -4,  // NOLINT
-  511, -4, 513, -4, 515, -4, 517, -4, 519, -4, 521, -4, 523, -4, 525, -4,  // NOLINT
-  527, -4, 529, -4, 531, -4, 533, -4, 535, -4, 537, -4, 539, -4, 541, -4,  // NOLINT
-  543, -4, 547, -4, 549, -4, 551, -4, 553, -4, 555, -4, 557, -4, 559, -4,  // NOLINT
-  561, -4, 563, -4, 572, -4, 1073742399, 43260, 576, 43260, 578, -4, 583, -4, 585, -4,  // NOLINT
-  587, -4, 589, -4, 591, -4, 592, 43132, 593, 43120, 594, 43128, 595, -840, 596, -824,  // NOLINT
-  1073742422, -820, 599, -820, 601, -808, 603, -812, 608, -820, 611, -828, 613, 169120, 614, 169232,  // NOLINT
-  616, -836, 617, -844, 619, 42972, 623, -844, 625, 42996, 626, -852, 629, -856, 637, 42908,  // NOLINT
-  640, -872, 643, -872, 648, -872, 649, -276, 1073742474, -868, 651, -868, 652, -284, 658, -876,  // NOLINT
-  837, 336, 881, -4, 883, -4, 887, -4, 1073742715, 520, 893, 520, 940, -152, 1073742765, -148,  // NOLINT
-  943, -148, 1073742769, -128, 961, -128, 962, -124, 1073742787, -128, 971, -128, 972, -256, 1073742797, -252,  // NOLINT
-  974, -252, 976, -248, 977, -228, 981, -188, 982, -216, 983, -32, 985, -4, 987, -4,  // NOLINT
-  989, -4, 991, -4, 993, -4, 995, -4, 997, -4, 999, -4, 1001, -4, 1003, -4,  // NOLINT
-  1005, -4, 1007, -4, 1008, -344, 1009, -320, 1010, 28, 1013, -384, 1016, -4, 1019, -4,  // NOLINT
-  1073742896, -128, 1103, -128, 1073742928, -320, 1119, -320, 1121, -4, 1123, -4, 1125, -4, 1127, -4,  // NOLINT
-  1129, -4, 1131, -4, 1133, -4, 1135, -4, 1137, -4, 1139, -4, 1141, -4, 1143, -4,  // NOLINT
-  1145, -4, 1147, -4, 1149, -4, 1151, -4, 1153, -4, 1163, -4, 1165, -4, 1167, -4,  // NOLINT
-  1169, -4, 1171, -4, 1173, -4, 1175, -4, 1177, -4, 1179, -4, 1181, -4, 1183, -4,  // NOLINT
-  1185, -4, 1187, -4, 1189, -4, 1191, -4, 1193, -4, 1195, -4, 1197, -4, 1199, -4,  // NOLINT
-  1201, -4, 1203, -4, 1205, -4, 1207, -4, 1209, -4, 1211, -4, 1213, -4, 1215, -4,  // NOLINT
-  1218, -4, 1220, -4, 1222, -4, 1224, -4, 1226, -4, 1228, -4, 1230, -4, 1231, -60,  // NOLINT
-  1233, -4, 1235, -4, 1237, -4, 1239, -4, 1241, -4, 1243, -4, 1245, -4, 1247, -4,  // NOLINT
-  1249, -4, 1251, -4, 1253, -4, 1255, -4, 1257, -4, 1259, -4, 1261, -4, 1263, -4,  // NOLINT
-  1265, -4, 1267, -4, 1269, -4, 1271, -4, 1273, -4, 1275, -4, 1277, -4, 1279, -4,  // NOLINT
-  1281, -4, 1283, -4, 1285, -4, 1287, -4, 1289, -4, 1291, -4, 1293, -4, 1295, -4,  // NOLINT
-  1297, -4, 1299, -4, 1301, -4, 1303, -4, 1305, -4, 1307, -4, 1309, -4, 1311, -4,  // NOLINT
-  1313, -4, 1315, -4, 1317, -4, 1319, -4, 1073743201, -192, 1414, -192, 7545, 141328, 7549, 15256,  // NOLINT
-  7681, -4, 7683, -4, 7685, -4, 7687, -4, 7689, -4, 7691, -4, 7693, -4, 7695, -4,  // NOLINT
-  7697, -4, 7699, -4, 7701, -4, 7703, -4, 7705, -4, 7707, -4, 7709, -4, 7711, -4,  // NOLINT
-  7713, -4, 7715, -4, 7717, -4, 7719, -4, 7721, -4, 7723, -4, 7725, -4, 7727, -4,  // NOLINT
-  7729, -4, 7731, -4, 7733, -4, 7735, -4, 7737, -4, 7739, -4, 7741, -4, 7743, -4,  // NOLINT
-  7745, -4, 7747, -4, 7749, -4, 7751, -4, 7753, -4, 7755, -4, 7757, -4, 7759, -4,  // NOLINT
-  7761, -4, 7763, -4, 7765, -4, 7767, -4, 7769, -4, 7771, -4, 7773, -4, 7775, -4,  // NOLINT
-  7777, -4, 7779, -4, 7781, -4, 7783, -4, 7785, -4, 7787, -4, 7789, -4, 7791, -4,  // NOLINT
-  7793, -4, 7795, -4, 7797, -4, 7799, -4, 7801, -4, 7803, -4, 7805, -4, 7807, -4,  // NOLINT
-  7809, -4, 7811, -4, 7813, -4, 7815, -4, 7817, -4, 7819, -4, 7821, -4, 7823, -4,  // NOLINT
-  7825, -4, 7827, -4, 7829, -4, 7835, -236, 7841, -4, 7843, -4, 7845, -4, 7847, -4,  // NOLINT
-  7849, -4, 7851, -4, 7853, -4, 7855, -4, 7857, -4, 7859, -4, 7861, -4, 7863, -4,  // NOLINT
-  7865, -4, 7867, -4, 7869, -4, 7871, -4, 7873, -4, 7875, -4, 7877, -4, 7879, -4,  // NOLINT
-  7881, -4, 7883, -4, 7885, -4, 7887, -4, 7889, -4, 7891, -4, 7893, -4, 7895, -4,  // NOLINT
-  7897, -4, 7899, -4, 7901, -4, 7903, -4, 7905, -4, 7907, -4, 7909, -4, 7911, -4,  // NOLINT
-  7913, -4, 7915, -4, 7917, -4, 7919, -4, 7921, -4, 7923, -4, 7925, -4, 7927, -4,  // NOLINT
-  7929, -4, 7931, -4, 7933, -4, 7935, -4, 1073749760, 32, 7943, 32, 1073749776, 32, 7957, 32,  // NOLINT
-  1073749792, 32, 7975, 32, 1073749808, 32, 7991, 32, 1073749824, 32, 8005, 32, 8017, 32, 8019, 32,  // NOLINT
-  8021, 32, 8023, 32, 1073749856, 32, 8039, 32, 1073749872, 296, 8049, 296, 1073749874, 344, 8053, 344,  // NOLINT
-  1073749878, 400, 8055, 400, 1073749880, 512, 8057, 512, 1073749882, 448, 8059, 448, 1073749884, 504, 8061, 504,  // NOLINT
-  1073749936, 32, 8113, 32, 8126, -28820, 1073749968, 32, 8145, 32, 1073749984, 32, 8161, 32, 8165, 28 };  // NOLINT
+static const uint16_t kEcma262CanonicalizeTable0Size = 498;  // NOLINT
+static const int32_t kEcma262CanonicalizeTable0[996] = {
+    1073741921, -128,   122,        -128,   181,        2972,
+    1073742048, -128,   246,        -128,   1073742072, -128,
+    254,        -128,   255,        484,  // NOLINT
+    257,        -4,     259,        -4,     261,        -4,
+    263,        -4,     265,        -4,     267,        -4,
+    269,        -4,     271,        -4,  // NOLINT
+    273,        -4,     275,        -4,     277,        -4,
+    279,        -4,     281,        -4,     283,        -4,
+    285,        -4,     287,        -4,  // NOLINT
+    289,        -4,     291,        -4,     293,        -4,
+    295,        -4,     297,        -4,     299,        -4,
+    301,        -4,     303,        -4,  // NOLINT
+    307,        -4,     309,        -4,     311,        -4,
+    314,        -4,     316,        -4,     318,        -4,
+    320,        -4,     322,        -4,  // NOLINT
+    324,        -4,     326,        -4,     328,        -4,
+    331,        -4,     333,        -4,     335,        -4,
+    337,        -4,     339,        -4,  // NOLINT
+    341,        -4,     343,        -4,     345,        -4,
+    347,        -4,     349,        -4,     351,        -4,
+    353,        -4,     355,        -4,  // NOLINT
+    357,        -4,     359,        -4,     361,        -4,
+    363,        -4,     365,        -4,     367,        -4,
+    369,        -4,     371,        -4,  // NOLINT
+    373,        -4,     375,        -4,     378,        -4,
+    380,        -4,     382,        -4,     384,        780,
+    387,        -4,     389,        -4,  // NOLINT
+    392,        -4,     396,        -4,     402,        -4,
+    405,        388,    409,        -4,     410,        652,
+    414,        520,    417,        -4,  // NOLINT
+    419,        -4,     421,        -4,     424,        -4,
+    429,        -4,     432,        -4,     436,        -4,
+    438,        -4,     441,        -4,  // NOLINT
+    445,        -4,     447,        224,    453,        -4,
+    454,        -8,     456,        -4,     457,        -8,
+    459,        -4,     460,        -8,  // NOLINT
+    462,        -4,     464,        -4,     466,        -4,
+    468,        -4,     470,        -4,     472,        -4,
+    474,        -4,     476,        -4,  // NOLINT
+    477,        -316,   479,        -4,     481,        -4,
+    483,        -4,     485,        -4,     487,        -4,
+    489,        -4,     491,        -4,  // NOLINT
+    493,        -4,     495,        -4,     498,        -4,
+    499,        -8,     501,        -4,     505,        -4,
+    507,        -4,     509,        -4,  // NOLINT
+    511,        -4,     513,        -4,     515,        -4,
+    517,        -4,     519,        -4,     521,        -4,
+    523,        -4,     525,        -4,  // NOLINT
+    527,        -4,     529,        -4,     531,        -4,
+    533,        -4,     535,        -4,     537,        -4,
+    539,        -4,     541,        -4,  // NOLINT
+    543,        -4,     547,        -4,     549,        -4,
+    551,        -4,     553,        -4,     555,        -4,
+    557,        -4,     559,        -4,  // NOLINT
+    561,        -4,     563,        -4,     572,        -4,
+    1073742399, 43260,  576,        43260,  578,        -4,
+    583,        -4,     585,        -4,  // NOLINT
+    587,        -4,     589,        -4,     591,        -4,
+    592,        43132,  593,        43120,  594,        43128,
+    595,        -840,   596,        -824,  // NOLINT
+    1073742422, -820,   599,        -820,   601,        -808,
+    603,        -812,   604,        169276, 608,        -820,
+    609,        169260, 611,        -828,  // NOLINT
+    613,        169120, 614,        169232, 616,        -836,
+    617,        -844,   619,        42972,  620,        169220,
+    623,        -844,   625,        42996,  // NOLINT
+    626,        -852,   629,        -856,   637,        42908,
+    640,        -872,   643,        -872,   647,        169128,
+    648,        -872,   649,        -276,  // NOLINT
+    1073742474, -868,   651,        -868,   652,        -284,
+    658,        -876,   670,        169032, 837,        336,
+    881,        -4,     883,        -4,  // NOLINT
+    887,        -4,     1073742715, 520,    893,        520,
+    940,        -152,   1073742765, -148,   943,        -148,
+    1073742769, -128,   961,        -128,  // NOLINT
+    962,        -124,   1073742787, -128,   971,        -128,
+    972,        -256,   1073742797, -252,   974,        -252,
+    976,        -248,   977,        -228,  // NOLINT
+    981,        -188,   982,        -216,   983,        -32,
+    985,        -4,     987,        -4,     989,        -4,
+    991,        -4,     993,        -4,  // NOLINT
+    995,        -4,     997,        -4,     999,        -4,
+    1001,       -4,     1003,       -4,     1005,       -4,
+    1007,       -4,     1008,       -344,  // NOLINT
+    1009,       -320,   1010,       28,     1011,       -464,
+    1013,       -384,   1016,       -4,     1019,       -4,
+    1073742896, -128,   1103,       -128,  // NOLINT
+    1073742928, -320,   1119,       -320,   1121,       -4,
+    1123,       -4,     1125,       -4,     1127,       -4,
+    1129,       -4,     1131,       -4,  // NOLINT
+    1133,       -4,     1135,       -4,     1137,       -4,
+    1139,       -4,     1141,       -4,     1143,       -4,
+    1145,       -4,     1147,       -4,  // NOLINT
+    1149,       -4,     1151,       -4,     1153,       -4,
+    1163,       -4,     1165,       -4,     1167,       -4,
+    1169,       -4,     1171,       -4,  // NOLINT
+    1173,       -4,     1175,       -4,     1177,       -4,
+    1179,       -4,     1181,       -4,     1183,       -4,
+    1185,       -4,     1187,       -4,  // NOLINT
+    1189,       -4,     1191,       -4,     1193,       -4,
+    1195,       -4,     1197,       -4,     1199,       -4,
+    1201,       -4,     1203,       -4,  // NOLINT
+    1205,       -4,     1207,       -4,     1209,       -4,
+    1211,       -4,     1213,       -4,     1215,       -4,
+    1218,       -4,     1220,       -4,  // NOLINT
+    1222,       -4,     1224,       -4,     1226,       -4,
+    1228,       -4,     1230,       -4,     1231,       -60,
+    1233,       -4,     1235,       -4,  // NOLINT
+    1237,       -4,     1239,       -4,     1241,       -4,
+    1243,       -4,     1245,       -4,     1247,       -4,
+    1249,       -4,     1251,       -4,  // NOLINT
+    1253,       -4,     1255,       -4,     1257,       -4,
+    1259,       -4,     1261,       -4,     1263,       -4,
+    1265,       -4,     1267,       -4,  // NOLINT
+    1269,       -4,     1271,       -4,     1273,       -4,
+    1275,       -4,     1277,       -4,     1279,       -4,
+    1281,       -4,     1283,       -4,  // NOLINT
+    1285,       -4,     1287,       -4,     1289,       -4,
+    1291,       -4,     1293,       -4,     1295,       -4,
+    1297,       -4,     1299,       -4,  // NOLINT
+    1301,       -4,     1303,       -4,     1305,       -4,
+    1307,       -4,     1309,       -4,     1311,       -4,
+    1313,       -4,     1315,       -4,  // NOLINT
+    1317,       -4,     1319,       -4,     1321,       -4,
+    1323,       -4,     1325,       -4,     1327,       -4,
+    1073743201, -192,   1414,       -192,  // NOLINT
+    7545,       141328, 7549,       15256,  7681,       -4,
+    7683,       -4,     7685,       -4,     7687,       -4,
+    7689,       -4,     7691,       -4,  // NOLINT
+    7693,       -4,     7695,       -4,     7697,       -4,
+    7699,       -4,     7701,       -4,     7703,       -4,
+    7705,       -4,     7707,       -4,  // NOLINT
+    7709,       -4,     7711,       -4,     7713,       -4,
+    7715,       -4,     7717,       -4,     7719,       -4,
+    7721,       -4,     7723,       -4,  // NOLINT
+    7725,       -4,     7727,       -4,     7729,       -4,
+    7731,       -4,     7733,       -4,     7735,       -4,
+    7737,       -4,     7739,       -4,  // NOLINT
+    7741,       -4,     7743,       -4,     7745,       -4,
+    7747,       -4,     7749,       -4,     7751,       -4,
+    7753,       -4,     7755,       -4,  // NOLINT
+    7757,       -4,     7759,       -4,     7761,       -4,
+    7763,       -4,     7765,       -4,     7767,       -4,
+    7769,       -4,     7771,       -4,  // NOLINT
+    7773,       -4,     7775,       -4,     7777,       -4,
+    7779,       -4,     7781,       -4,     7783,       -4,
+    7785,       -4,     7787,       -4,  // NOLINT
+    7789,       -4,     7791,       -4,     7793,       -4,
+    7795,       -4,     7797,       -4,     7799,       -4,
+    7801,       -4,     7803,       -4,  // NOLINT
+    7805,       -4,     7807,       -4,     7809,       -4,
+    7811,       -4,     7813,       -4,     7815,       -4,
+    7817,       -4,     7819,       -4,  // NOLINT
+    7821,       -4,     7823,       -4,     7825,       -4,
+    7827,       -4,     7829,       -4,     7835,       -236,
+    7841,       -4,     7843,       -4,  // NOLINT
+    7845,       -4,     7847,       -4,     7849,       -4,
+    7851,       -4,     7853,       -4,     7855,       -4,
+    7857,       -4,     7859,       -4,  // NOLINT
+    7861,       -4,     7863,       -4,     7865,       -4,
+    7867,       -4,     7869,       -4,     7871,       -4,
+    7873,       -4,     7875,       -4,  // NOLINT
+    7877,       -4,     7879,       -4,     7881,       -4,
+    7883,       -4,     7885,       -4,     7887,       -4,
+    7889,       -4,     7891,       -4,  // NOLINT
+    7893,       -4,     7895,       -4,     7897,       -4,
+    7899,       -4,     7901,       -4,     7903,       -4,
+    7905,       -4,     7907,       -4,  // NOLINT
+    7909,       -4,     7911,       -4,     7913,       -4,
+    7915,       -4,     7917,       -4,     7919,       -4,
+    7921,       -4,     7923,       -4,  // NOLINT
+    7925,       -4,     7927,       -4,     7929,       -4,
+    7931,       -4,     7933,       -4,     7935,       -4,
+    1073749760, 32,     7943,       32,  // NOLINT
+    1073749776, 32,     7957,       32,     1073749792, 32,
+    7975,       32,     1073749808, 32,     7991,       32,
+    1073749824, 32,     8005,       32,  // NOLINT
+    8017,       32,     8019,       32,     8021,       32,
+    8023,       32,     1073749856, 32,     8039,       32,
+    1073749872, 296,    8049,       296,  // NOLINT
+    1073749874, 344,    8053,       344,    1073749878, 400,
+    8055,       400,    1073749880, 512,    8057,       512,
+    1073749882, 448,    8059,       448,  // NOLINT
+    1073749884, 504,    8061,       504,    1073749936, 32,
+    8113,       32,     8126,       -28820, 1073749968, 32,
+    8145,       32,     1073749984, 32,                           // NOLINT
+    8161,       32,     8165,       28};                          // NOLINT
 static const uint16_t kEcma262CanonicalizeMultiStrings0Size = 1;  // NOLINT
 static const MultiCharacterSpecialCase<1> kEcma262CanonicalizeMultiStrings1[1] = {  // NOLINT
   {{kSentinel}} }; // NOLINT
@@ -1261,19 +2032,32 @@
 static const uint16_t kEcma262CanonicalizeMultiStrings1Size = 1;  // NOLINT
 static const MultiCharacterSpecialCase<1> kEcma262CanonicalizeMultiStrings5[1] = {  // NOLINT
   {{kSentinel}} }; // NOLINT
-static const uint16_t kEcma262CanonicalizeTable5Size = 88;  // NOLINT
-static const int32_t kEcma262CanonicalizeTable5[176] = {
-  1601, -4, 1603, -4, 1605, -4, 1607, -4, 1609, -4, 1611, -4, 1613, -4, 1615, -4,  // NOLINT
-  1617, -4, 1619, -4, 1621, -4, 1623, -4, 1625, -4, 1627, -4, 1629, -4, 1631, -4,  // NOLINT
-  1633, -4, 1635, -4, 1637, -4, 1639, -4, 1641, -4, 1643, -4, 1645, -4, 1665, -4,  // NOLINT
-  1667, -4, 1669, -4, 1671, -4, 1673, -4, 1675, -4, 1677, -4, 1679, -4, 1681, -4,  // NOLINT
-  1683, -4, 1685, -4, 1687, -4, 1827, -4, 1829, -4, 1831, -4, 1833, -4, 1835, -4,  // NOLINT
-  1837, -4, 1839, -4, 1843, -4, 1845, -4, 1847, -4, 1849, -4, 1851, -4, 1853, -4,  // NOLINT
-  1855, -4, 1857, -4, 1859, -4, 1861, -4, 1863, -4, 1865, -4, 1867, -4, 1869, -4,  // NOLINT
-  1871, -4, 1873, -4, 1875, -4, 1877, -4, 1879, -4, 1881, -4, 1883, -4, 1885, -4,  // NOLINT
-  1887, -4, 1889, -4, 1891, -4, 1893, -4, 1895, -4, 1897, -4, 1899, -4, 1901, -4,  // NOLINT
-  1903, -4, 1914, -4, 1916, -4, 1919, -4, 1921, -4, 1923, -4, 1925, -4, 1927, -4,  // NOLINT
-  1932, -4, 1937, -4, 1939, -4, 1953, -4, 1955, -4, 1957, -4, 1959, -4, 1961, -4 };  // NOLINT
+static const uint16_t kEcma262CanonicalizeTable5Size = 95;  // NOLINT
+static const int32_t kEcma262CanonicalizeTable5
+    [190] = {1601, -4, 1603, -4, 1605, -4, 1607, -4,
+             1609, -4, 1611, -4, 1613, -4, 1615, -4,  // NOLINT
+             1617, -4, 1619, -4, 1621, -4, 1623, -4,
+             1625, -4, 1627, -4, 1629, -4, 1631, -4,  // NOLINT
+             1633, -4, 1635, -4, 1637, -4, 1639, -4,
+             1641, -4, 1643, -4, 1645, -4, 1665, -4,  // NOLINT
+             1667, -4, 1669, -4, 1671, -4, 1673, -4,
+             1675, -4, 1677, -4, 1679, -4, 1681, -4,  // NOLINT
+             1683, -4, 1685, -4, 1687, -4, 1689, -4,
+             1691, -4, 1827, -4, 1829, -4, 1831, -4,  // NOLINT
+             1833, -4, 1835, -4, 1837, -4, 1839, -4,
+             1843, -4, 1845, -4, 1847, -4, 1849, -4,  // NOLINT
+             1851, -4, 1853, -4, 1855, -4, 1857, -4,
+             1859, -4, 1861, -4, 1863, -4, 1865, -4,  // NOLINT
+             1867, -4, 1869, -4, 1871, -4, 1873, -4,
+             1875, -4, 1877, -4, 1879, -4, 1881, -4,  // NOLINT
+             1883, -4, 1885, -4, 1887, -4, 1889, -4,
+             1891, -4, 1893, -4, 1895, -4, 1897, -4,  // NOLINT
+             1899, -4, 1901, -4, 1903, -4, 1914, -4,
+             1916, -4, 1919, -4, 1921, -4, 1923, -4,  // NOLINT
+             1925, -4, 1927, -4, 1932, -4, 1937, -4,
+             1939, -4, 1943, -4, 1945, -4, 1947, -4,  // NOLINT
+             1949, -4, 1951, -4, 1953, -4, 1955, -4,
+             1957, -4, 1959, -4, 1961, -4};                       // NOLINT
 static const uint16_t kEcma262CanonicalizeMultiStrings5Size = 1;  // NOLINT
 static const MultiCharacterSpecialCase<1> kEcma262CanonicalizeMultiStrings7[1] = {  // NOLINT
   {{kSentinel}} }; // NOLINT
@@ -1319,259 +2103,895 @@
   }
 }
 
-static const MultiCharacterSpecialCase<4> kEcma262UnCanonicalizeMultiStrings0[497] = {  // NOLINT
-  {{65, 97, kSentinel}}, {{90, 122, kSentinel}}, {{181, 924, 956, kSentinel}}, {{192, 224, kSentinel}},  // NOLINT
-  {{214, 246, kSentinel}}, {{216, 248, kSentinel}}, {{222, 254, kSentinel}}, {{255, 376, kSentinel}},  // NOLINT
-  {{256, 257, kSentinel}}, {{258, 259, kSentinel}}, {{260, 261, kSentinel}}, {{262, 263, kSentinel}},  // NOLINT
-  {{264, 265, kSentinel}}, {{266, 267, kSentinel}}, {{268, 269, kSentinel}}, {{270, 271, kSentinel}},  // NOLINT
-  {{272, 273, kSentinel}}, {{274, 275, kSentinel}}, {{276, 277, kSentinel}}, {{278, 279, kSentinel}},  // NOLINT
-  {{280, 281, kSentinel}}, {{282, 283, kSentinel}}, {{284, 285, kSentinel}}, {{286, 287, kSentinel}},  // NOLINT
-  {{288, 289, kSentinel}}, {{290, 291, kSentinel}}, {{292, 293, kSentinel}}, {{294, 295, kSentinel}},  // NOLINT
-  {{296, 297, kSentinel}}, {{298, 299, kSentinel}}, {{300, 301, kSentinel}}, {{302, 303, kSentinel}},  // NOLINT
-  {{306, 307, kSentinel}}, {{308, 309, kSentinel}}, {{310, 311, kSentinel}}, {{313, 314, kSentinel}},  // NOLINT
-  {{315, 316, kSentinel}}, {{317, 318, kSentinel}}, {{319, 320, kSentinel}}, {{321, 322, kSentinel}},  // NOLINT
-  {{323, 324, kSentinel}}, {{325, 326, kSentinel}}, {{327, 328, kSentinel}}, {{330, 331, kSentinel}},  // NOLINT
-  {{332, 333, kSentinel}}, {{334, 335, kSentinel}}, {{336, 337, kSentinel}}, {{338, 339, kSentinel}},  // NOLINT
-  {{340, 341, kSentinel}}, {{342, 343, kSentinel}}, {{344, 345, kSentinel}}, {{346, 347, kSentinel}},  // NOLINT
-  {{348, 349, kSentinel}}, {{350, 351, kSentinel}}, {{352, 353, kSentinel}}, {{354, 355, kSentinel}},  // NOLINT
-  {{356, 357, kSentinel}}, {{358, 359, kSentinel}}, {{360, 361, kSentinel}}, {{362, 363, kSentinel}},  // NOLINT
-  {{364, 365, kSentinel}}, {{366, 367, kSentinel}}, {{368, 369, kSentinel}}, {{370, 371, kSentinel}},  // NOLINT
-  {{372, 373, kSentinel}}, {{374, 375, kSentinel}}, {{377, 378, kSentinel}}, {{379, 380, kSentinel}},  // NOLINT
-  {{381, 382, kSentinel}}, {{384, 579, kSentinel}}, {{385, 595, kSentinel}}, {{386, 387, kSentinel}},  // NOLINT
-  {{388, 389, kSentinel}}, {{390, 596, kSentinel}}, {{391, 392, kSentinel}}, {{393, 598, kSentinel}},  // NOLINT
-  {{394, 599, kSentinel}}, {{395, 396, kSentinel}}, {{398, 477, kSentinel}}, {{399, 601, kSentinel}},  // NOLINT
-  {{400, 603, kSentinel}}, {{401, 402, kSentinel}}, {{403, 608, kSentinel}}, {{404, 611, kSentinel}},  // NOLINT
-  {{405, 502, kSentinel}}, {{406, 617, kSentinel}}, {{407, 616, kSentinel}}, {{408, 409, kSentinel}},  // NOLINT
-  {{410, 573, kSentinel}}, {{412, 623, kSentinel}}, {{413, 626, kSentinel}}, {{414, 544, kSentinel}},  // NOLINT
-  {{415, 629, kSentinel}}, {{416, 417, kSentinel}}, {{418, 419, kSentinel}}, {{420, 421, kSentinel}},  // NOLINT
-  {{422, 640, kSentinel}}, {{423, 424, kSentinel}}, {{425, 643, kSentinel}}, {{428, 429, kSentinel}},  // NOLINT
-  {{430, 648, kSentinel}}, {{431, 432, kSentinel}}, {{433, 650, kSentinel}}, {{434, 651, kSentinel}},  // NOLINT
-  {{435, 436, kSentinel}}, {{437, 438, kSentinel}}, {{439, 658, kSentinel}}, {{440, 441, kSentinel}},  // NOLINT
-  {{444, 445, kSentinel}}, {{447, 503, kSentinel}}, {{452, 453, 454, kSentinel}}, {{455, 456, 457, kSentinel}},  // NOLINT
-  {{458, 459, 460, kSentinel}}, {{461, 462, kSentinel}}, {{463, 464, kSentinel}}, {{465, 466, kSentinel}},  // NOLINT
-  {{467, 468, kSentinel}}, {{469, 470, kSentinel}}, {{471, 472, kSentinel}}, {{473, 474, kSentinel}},  // NOLINT
-  {{475, 476, kSentinel}}, {{478, 479, kSentinel}}, {{480, 481, kSentinel}}, {{482, 483, kSentinel}},  // NOLINT
-  {{484, 485, kSentinel}}, {{486, 487, kSentinel}}, {{488, 489, kSentinel}}, {{490, 491, kSentinel}},  // NOLINT
-  {{492, 493, kSentinel}}, {{494, 495, kSentinel}}, {{497, 498, 499, kSentinel}}, {{500, 501, kSentinel}},  // NOLINT
-  {{504, 505, kSentinel}}, {{506, 507, kSentinel}}, {{508, 509, kSentinel}}, {{510, 511, kSentinel}},  // NOLINT
-  {{512, 513, kSentinel}}, {{514, 515, kSentinel}}, {{516, 517, kSentinel}}, {{518, 519, kSentinel}},  // NOLINT
-  {{520, 521, kSentinel}}, {{522, 523, kSentinel}}, {{524, 525, kSentinel}}, {{526, 527, kSentinel}},  // NOLINT
-  {{528, 529, kSentinel}}, {{530, 531, kSentinel}}, {{532, 533, kSentinel}}, {{534, 535, kSentinel}},  // NOLINT
-  {{536, 537, kSentinel}}, {{538, 539, kSentinel}}, {{540, 541, kSentinel}}, {{542, 543, kSentinel}},  // NOLINT
-  {{546, 547, kSentinel}}, {{548, 549, kSentinel}}, {{550, 551, kSentinel}}, {{552, 553, kSentinel}},  // NOLINT
-  {{554, 555, kSentinel}}, {{556, 557, kSentinel}}, {{558, 559, kSentinel}}, {{560, 561, kSentinel}},  // NOLINT
-  {{562, 563, kSentinel}}, {{570, 11365, kSentinel}}, {{571, 572, kSentinel}}, {{574, 11366, kSentinel}},  // NOLINT
-  {{575, 11390, kSentinel}}, {{576, 11391, kSentinel}}, {{577, 578, kSentinel}}, {{580, 649, kSentinel}},  // NOLINT
-  {{581, 652, kSentinel}}, {{582, 583, kSentinel}}, {{584, 585, kSentinel}}, {{586, 587, kSentinel}},  // NOLINT
-  {{588, 589, kSentinel}}, {{590, 591, kSentinel}}, {{592, 11375, kSentinel}}, {{593, 11373, kSentinel}},  // NOLINT
-  {{594, 11376, kSentinel}}, {{613, 42893, kSentinel}}, {{614, 42922, kSentinel}}, {{619, 11362, kSentinel}},  // NOLINT
-  {{625, 11374, kSentinel}}, {{637, 11364, kSentinel}}, {{837, 921, 953, 8126}}, {{880, 881, kSentinel}},  // NOLINT
-  {{882, 883, kSentinel}}, {{886, 887, kSentinel}}, {{891, 1021, kSentinel}}, {{893, 1023, kSentinel}},  // NOLINT
-  {{902, 940, kSentinel}}, {{904, 941, kSentinel}}, {{906, 943, kSentinel}}, {{908, 972, kSentinel}},  // NOLINT
-  {{910, 973, kSentinel}}, {{911, 974, kSentinel}}, {{913, 945, kSentinel}}, {{914, 946, 976, kSentinel}},  // NOLINT
-  {{915, 947, kSentinel}}, {{916, 948, kSentinel}}, {{917, 949, 1013, kSentinel}}, {{918, 950, kSentinel}},  // NOLINT
-  {{919, 951, kSentinel}}, {{920, 952, 977, kSentinel}}, {{922, 954, 1008, kSentinel}}, {{923, 955, kSentinel}},  // NOLINT
-  {{925, 957, kSentinel}}, {{927, 959, kSentinel}}, {{928, 960, 982, kSentinel}}, {{929, 961, 1009, kSentinel}},  // NOLINT
-  {{931, 962, 963, kSentinel}}, {{932, 964, kSentinel}}, {{933, 965, kSentinel}}, {{934, 966, 981, kSentinel}},  // NOLINT
-  {{935, 967, kSentinel}}, {{939, 971, kSentinel}}, {{975, 983, kSentinel}}, {{984, 985, kSentinel}},  // NOLINT
-  {{986, 987, kSentinel}}, {{988, 989, kSentinel}}, {{990, 991, kSentinel}}, {{992, 993, kSentinel}},  // NOLINT
-  {{994, 995, kSentinel}}, {{996, 997, kSentinel}}, {{998, 999, kSentinel}}, {{1000, 1001, kSentinel}},  // NOLINT
-  {{1002, 1003, kSentinel}}, {{1004, 1005, kSentinel}}, {{1006, 1007, kSentinel}}, {{1010, 1017, kSentinel}},  // NOLINT
-  {{1015, 1016, kSentinel}}, {{1018, 1019, kSentinel}}, {{1024, 1104, kSentinel}}, {{1039, 1119, kSentinel}},  // NOLINT
-  {{1040, 1072, kSentinel}}, {{1071, 1103, kSentinel}}, {{1120, 1121, kSentinel}}, {{1122, 1123, kSentinel}},  // NOLINT
-  {{1124, 1125, kSentinel}}, {{1126, 1127, kSentinel}}, {{1128, 1129, kSentinel}}, {{1130, 1131, kSentinel}},  // NOLINT
-  {{1132, 1133, kSentinel}}, {{1134, 1135, kSentinel}}, {{1136, 1137, kSentinel}}, {{1138, 1139, kSentinel}},  // NOLINT
-  {{1140, 1141, kSentinel}}, {{1142, 1143, kSentinel}}, {{1144, 1145, kSentinel}}, {{1146, 1147, kSentinel}},  // NOLINT
-  {{1148, 1149, kSentinel}}, {{1150, 1151, kSentinel}}, {{1152, 1153, kSentinel}}, {{1162, 1163, kSentinel}},  // NOLINT
-  {{1164, 1165, kSentinel}}, {{1166, 1167, kSentinel}}, {{1168, 1169, kSentinel}}, {{1170, 1171, kSentinel}},  // NOLINT
-  {{1172, 1173, kSentinel}}, {{1174, 1175, kSentinel}}, {{1176, 1177, kSentinel}}, {{1178, 1179, kSentinel}},  // NOLINT
-  {{1180, 1181, kSentinel}}, {{1182, 1183, kSentinel}}, {{1184, 1185, kSentinel}}, {{1186, 1187, kSentinel}},  // NOLINT
-  {{1188, 1189, kSentinel}}, {{1190, 1191, kSentinel}}, {{1192, 1193, kSentinel}}, {{1194, 1195, kSentinel}},  // NOLINT
-  {{1196, 1197, kSentinel}}, {{1198, 1199, kSentinel}}, {{1200, 1201, kSentinel}}, {{1202, 1203, kSentinel}},  // NOLINT
-  {{1204, 1205, kSentinel}}, {{1206, 1207, kSentinel}}, {{1208, 1209, kSentinel}}, {{1210, 1211, kSentinel}},  // NOLINT
-  {{1212, 1213, kSentinel}}, {{1214, 1215, kSentinel}}, {{1216, 1231, kSentinel}}, {{1217, 1218, kSentinel}},  // NOLINT
-  {{1219, 1220, kSentinel}}, {{1221, 1222, kSentinel}}, {{1223, 1224, kSentinel}}, {{1225, 1226, kSentinel}},  // NOLINT
-  {{1227, 1228, kSentinel}}, {{1229, 1230, kSentinel}}, {{1232, 1233, kSentinel}}, {{1234, 1235, kSentinel}},  // NOLINT
-  {{1236, 1237, kSentinel}}, {{1238, 1239, kSentinel}}, {{1240, 1241, kSentinel}}, {{1242, 1243, kSentinel}},  // NOLINT
-  {{1244, 1245, kSentinel}}, {{1246, 1247, kSentinel}}, {{1248, 1249, kSentinel}}, {{1250, 1251, kSentinel}},  // NOLINT
-  {{1252, 1253, kSentinel}}, {{1254, 1255, kSentinel}}, {{1256, 1257, kSentinel}}, {{1258, 1259, kSentinel}},  // NOLINT
-  {{1260, 1261, kSentinel}}, {{1262, 1263, kSentinel}}, {{1264, 1265, kSentinel}}, {{1266, 1267, kSentinel}},  // NOLINT
-  {{1268, 1269, kSentinel}}, {{1270, 1271, kSentinel}}, {{1272, 1273, kSentinel}}, {{1274, 1275, kSentinel}},  // NOLINT
-  {{1276, 1277, kSentinel}}, {{1278, 1279, kSentinel}}, {{1280, 1281, kSentinel}}, {{1282, 1283, kSentinel}},  // NOLINT
-  {{1284, 1285, kSentinel}}, {{1286, 1287, kSentinel}}, {{1288, 1289, kSentinel}}, {{1290, 1291, kSentinel}},  // NOLINT
-  {{1292, 1293, kSentinel}}, {{1294, 1295, kSentinel}}, {{1296, 1297, kSentinel}}, {{1298, 1299, kSentinel}},  // NOLINT
-  {{1300, 1301, kSentinel}}, {{1302, 1303, kSentinel}}, {{1304, 1305, kSentinel}}, {{1306, 1307, kSentinel}},  // NOLINT
-  {{1308, 1309, kSentinel}}, {{1310, 1311, kSentinel}}, {{1312, 1313, kSentinel}}, {{1314, 1315, kSentinel}},  // NOLINT
-  {{1316, 1317, kSentinel}}, {{1318, 1319, kSentinel}}, {{1329, 1377, kSentinel}}, {{1366, 1414, kSentinel}},  // NOLINT
-  {{4256, 11520, kSentinel}}, {{4293, 11557, kSentinel}}, {{4295, 11559, kSentinel}}, {{4301, 11565, kSentinel}},  // NOLINT
-  {{7545, 42877, kSentinel}}, {{7549, 11363, kSentinel}}, {{7680, 7681, kSentinel}}, {{7682, 7683, kSentinel}},  // NOLINT
-  {{7684, 7685, kSentinel}}, {{7686, 7687, kSentinel}}, {{7688, 7689, kSentinel}}, {{7690, 7691, kSentinel}},  // NOLINT
-  {{7692, 7693, kSentinel}}, {{7694, 7695, kSentinel}}, {{7696, 7697, kSentinel}}, {{7698, 7699, kSentinel}},  // NOLINT
-  {{7700, 7701, kSentinel}}, {{7702, 7703, kSentinel}}, {{7704, 7705, kSentinel}}, {{7706, 7707, kSentinel}},  // NOLINT
-  {{7708, 7709, kSentinel}}, {{7710, 7711, kSentinel}}, {{7712, 7713, kSentinel}}, {{7714, 7715, kSentinel}},  // NOLINT
-  {{7716, 7717, kSentinel}}, {{7718, 7719, kSentinel}}, {{7720, 7721, kSentinel}}, {{7722, 7723, kSentinel}},  // NOLINT
-  {{7724, 7725, kSentinel}}, {{7726, 7727, kSentinel}}, {{7728, 7729, kSentinel}}, {{7730, 7731, kSentinel}},  // NOLINT
-  {{7732, 7733, kSentinel}}, {{7734, 7735, kSentinel}}, {{7736, 7737, kSentinel}}, {{7738, 7739, kSentinel}},  // NOLINT
-  {{7740, 7741, kSentinel}}, {{7742, 7743, kSentinel}}, {{7744, 7745, kSentinel}}, {{7746, 7747, kSentinel}},  // NOLINT
-  {{7748, 7749, kSentinel}}, {{7750, 7751, kSentinel}}, {{7752, 7753, kSentinel}}, {{7754, 7755, kSentinel}},  // NOLINT
-  {{7756, 7757, kSentinel}}, {{7758, 7759, kSentinel}}, {{7760, 7761, kSentinel}}, {{7762, 7763, kSentinel}},  // NOLINT
-  {{7764, 7765, kSentinel}}, {{7766, 7767, kSentinel}}, {{7768, 7769, kSentinel}}, {{7770, 7771, kSentinel}},  // NOLINT
-  {{7772, 7773, kSentinel}}, {{7774, 7775, kSentinel}}, {{7776, 7777, 7835, kSentinel}}, {{7778, 7779, kSentinel}},  // NOLINT
-  {{7780, 7781, kSentinel}}, {{7782, 7783, kSentinel}}, {{7784, 7785, kSentinel}}, {{7786, 7787, kSentinel}},  // NOLINT
-  {{7788, 7789, kSentinel}}, {{7790, 7791, kSentinel}}, {{7792, 7793, kSentinel}}, {{7794, 7795, kSentinel}},  // NOLINT
-  {{7796, 7797, kSentinel}}, {{7798, 7799, kSentinel}}, {{7800, 7801, kSentinel}}, {{7802, 7803, kSentinel}},  // NOLINT
-  {{7804, 7805, kSentinel}}, {{7806, 7807, kSentinel}}, {{7808, 7809, kSentinel}}, {{7810, 7811, kSentinel}},  // NOLINT
-  {{7812, 7813, kSentinel}}, {{7814, 7815, kSentinel}}, {{7816, 7817, kSentinel}}, {{7818, 7819, kSentinel}},  // NOLINT
-  {{7820, 7821, kSentinel}}, {{7822, 7823, kSentinel}}, {{7824, 7825, kSentinel}}, {{7826, 7827, kSentinel}},  // NOLINT
-  {{7828, 7829, kSentinel}}, {{7840, 7841, kSentinel}}, {{7842, 7843, kSentinel}}, {{7844, 7845, kSentinel}},  // NOLINT
-  {{7846, 7847, kSentinel}}, {{7848, 7849, kSentinel}}, {{7850, 7851, kSentinel}}, {{7852, 7853, kSentinel}},  // NOLINT
-  {{7854, 7855, kSentinel}}, {{7856, 7857, kSentinel}}, {{7858, 7859, kSentinel}}, {{7860, 7861, kSentinel}},  // NOLINT
-  {{7862, 7863, kSentinel}}, {{7864, 7865, kSentinel}}, {{7866, 7867, kSentinel}}, {{7868, 7869, kSentinel}},  // NOLINT
-  {{7870, 7871, kSentinel}}, {{7872, 7873, kSentinel}}, {{7874, 7875, kSentinel}}, {{7876, 7877, kSentinel}},  // NOLINT
-  {{7878, 7879, kSentinel}}, {{7880, 7881, kSentinel}}, {{7882, 7883, kSentinel}}, {{7884, 7885, kSentinel}},  // NOLINT
-  {{7886, 7887, kSentinel}}, {{7888, 7889, kSentinel}}, {{7890, 7891, kSentinel}}, {{7892, 7893, kSentinel}},  // NOLINT
-  {{7894, 7895, kSentinel}}, {{7896, 7897, kSentinel}}, {{7898, 7899, kSentinel}}, {{7900, 7901, kSentinel}},  // NOLINT
-  {{7902, 7903, kSentinel}}, {{7904, 7905, kSentinel}}, {{7906, 7907, kSentinel}}, {{7908, 7909, kSentinel}},  // NOLINT
-  {{7910, 7911, kSentinel}}, {{7912, 7913, kSentinel}}, {{7914, 7915, kSentinel}}, {{7916, 7917, kSentinel}},  // NOLINT
-  {{7918, 7919, kSentinel}}, {{7920, 7921, kSentinel}}, {{7922, 7923, kSentinel}}, {{7924, 7925, kSentinel}},  // NOLINT
-  {{7926, 7927, kSentinel}}, {{7928, 7929, kSentinel}}, {{7930, 7931, kSentinel}}, {{7932, 7933, kSentinel}},  // NOLINT
-  {{7934, 7935, kSentinel}}, {{7936, 7944, kSentinel}}, {{7943, 7951, kSentinel}}, {{7952, 7960, kSentinel}},  // NOLINT
-  {{7957, 7965, kSentinel}}, {{7968, 7976, kSentinel}}, {{7975, 7983, kSentinel}}, {{7984, 7992, kSentinel}},  // NOLINT
-  {{7991, 7999, kSentinel}}, {{8000, 8008, kSentinel}}, {{8005, 8013, kSentinel}}, {{8017, 8025, kSentinel}},  // NOLINT
-  {{8019, 8027, kSentinel}}, {{8021, 8029, kSentinel}}, {{8023, 8031, kSentinel}}, {{8032, 8040, kSentinel}},  // NOLINT
-  {{8039, 8047, kSentinel}}, {{8048, 8122, kSentinel}}, {{8049, 8123, kSentinel}}, {{8050, 8136, kSentinel}},  // NOLINT
-  {{8053, 8139, kSentinel}}, {{8054, 8154, kSentinel}}, {{8055, 8155, kSentinel}}, {{8056, 8184, kSentinel}},  // NOLINT
-  {{8057, 8185, kSentinel}}, {{8058, 8170, kSentinel}}, {{8059, 8171, kSentinel}}, {{8060, 8186, kSentinel}},  // NOLINT
-  {{8061, 8187, kSentinel}}, {{8112, 8120, kSentinel}}, {{8113, 8121, kSentinel}}, {{8144, 8152, kSentinel}},  // NOLINT
-  {{8145, 8153, kSentinel}}, {{8160, 8168, kSentinel}}, {{8161, 8169, kSentinel}}, {{8165, 8172, kSentinel}},  // NOLINT
-  {{kSentinel}} }; // NOLINT
-static const uint16_t kEcma262UnCanonicalizeTable0Size = 990;  // NOLINT
-static const int32_t kEcma262UnCanonicalizeTable0[1980] = {
-  1073741889, 1, 90, 5, 1073741921, 1, 122, 5, 181, 9, 1073742016, 13, 214, 17, 1073742040, 21,  // NOLINT
-  222, 25, 1073742048, 13, 246, 17, 1073742072, 21, 254, 25, 255, 29, 256, 33, 257, 33,  // NOLINT
-  258, 37, 259, 37, 260, 41, 261, 41, 262, 45, 263, 45, 264, 49, 265, 49,  // NOLINT
-  266, 53, 267, 53, 268, 57, 269, 57, 270, 61, 271, 61, 272, 65, 273, 65,  // NOLINT
-  274, 69, 275, 69, 276, 73, 277, 73, 278, 77, 279, 77, 280, 81, 281, 81,  // NOLINT
-  282, 85, 283, 85, 284, 89, 285, 89, 286, 93, 287, 93, 288, 97, 289, 97,  // NOLINT
-  290, 101, 291, 101, 292, 105, 293, 105, 294, 109, 295, 109, 296, 113, 297, 113,  // NOLINT
-  298, 117, 299, 117, 300, 121, 301, 121, 302, 125, 303, 125, 306, 129, 307, 129,  // NOLINT
-  308, 133, 309, 133, 310, 137, 311, 137, 313, 141, 314, 141, 315, 145, 316, 145,  // NOLINT
-  317, 149, 318, 149, 319, 153, 320, 153, 321, 157, 322, 157, 323, 161, 324, 161,  // NOLINT
-  325, 165, 326, 165, 327, 169, 328, 169, 330, 173, 331, 173, 332, 177, 333, 177,  // NOLINT
-  334, 181, 335, 181, 336, 185, 337, 185, 338, 189, 339, 189, 340, 193, 341, 193,  // NOLINT
-  342, 197, 343, 197, 344, 201, 345, 201, 346, 205, 347, 205, 348, 209, 349, 209,  // NOLINT
-  350, 213, 351, 213, 352, 217, 353, 217, 354, 221, 355, 221, 356, 225, 357, 225,  // NOLINT
-  358, 229, 359, 229, 360, 233, 361, 233, 362, 237, 363, 237, 364, 241, 365, 241,  // NOLINT
-  366, 245, 367, 245, 368, 249, 369, 249, 370, 253, 371, 253, 372, 257, 373, 257,  // NOLINT
-  374, 261, 375, 261, 376, 29, 377, 265, 378, 265, 379, 269, 380, 269, 381, 273,  // NOLINT
-  382, 273, 384, 277, 385, 281, 386, 285, 387, 285, 388, 289, 389, 289, 390, 293,  // NOLINT
-  391, 297, 392, 297, 1073742217, 301, 394, 305, 395, 309, 396, 309, 398, 313, 399, 317,  // NOLINT
-  400, 321, 401, 325, 402, 325, 403, 329, 404, 333, 405, 337, 406, 341, 407, 345,  // NOLINT
-  408, 349, 409, 349, 410, 353, 412, 357, 413, 361, 414, 365, 415, 369, 416, 373,  // NOLINT
-  417, 373, 418, 377, 419, 377, 420, 381, 421, 381, 422, 385, 423, 389, 424, 389,  // NOLINT
-  425, 393, 428, 397, 429, 397, 430, 401, 431, 405, 432, 405, 1073742257, 409, 434, 413,  // NOLINT
-  435, 417, 436, 417, 437, 421, 438, 421, 439, 425, 440, 429, 441, 429, 444, 433,  // NOLINT
-  445, 433, 447, 437, 452, 441, 453, 441, 454, 441, 455, 445, 456, 445, 457, 445,  // NOLINT
-  458, 449, 459, 449, 460, 449, 461, 453, 462, 453, 463, 457, 464, 457, 465, 461,  // NOLINT
-  466, 461, 467, 465, 468, 465, 469, 469, 470, 469, 471, 473, 472, 473, 473, 477,  // NOLINT
-  474, 477, 475, 481, 476, 481, 477, 313, 478, 485, 479, 485, 480, 489, 481, 489,  // NOLINT
-  482, 493, 483, 493, 484, 497, 485, 497, 486, 501, 487, 501, 488, 505, 489, 505,  // NOLINT
-  490, 509, 491, 509, 492, 513, 493, 513, 494, 517, 495, 517, 497, 521, 498, 521,  // NOLINT
-  499, 521, 500, 525, 501, 525, 502, 337, 503, 437, 504, 529, 505, 529, 506, 533,  // NOLINT
-  507, 533, 508, 537, 509, 537, 510, 541, 511, 541, 512, 545, 513, 545, 514, 549,  // NOLINT
-  515, 549, 516, 553, 517, 553, 518, 557, 519, 557, 520, 561, 521, 561, 522, 565,  // NOLINT
-  523, 565, 524, 569, 525, 569, 526, 573, 527, 573, 528, 577, 529, 577, 530, 581,  // NOLINT
-  531, 581, 532, 585, 533, 585, 534, 589, 535, 589, 536, 593, 537, 593, 538, 597,  // NOLINT
-  539, 597, 540, 601, 541, 601, 542, 605, 543, 605, 544, 365, 546, 609, 547, 609,  // NOLINT
-  548, 613, 549, 613, 550, 617, 551, 617, 552, 621, 553, 621, 554, 625, 555, 625,  // NOLINT
-  556, 629, 557, 629, 558, 633, 559, 633, 560, 637, 561, 637, 562, 641, 563, 641,  // NOLINT
-  570, 645, 571, 649, 572, 649, 573, 353, 574, 653, 1073742399, 657, 576, 661, 577, 665,  // NOLINT
-  578, 665, 579, 277, 580, 669, 581, 673, 582, 677, 583, 677, 584, 681, 585, 681,  // NOLINT
-  586, 685, 587, 685, 588, 689, 589, 689, 590, 693, 591, 693, 592, 697, 593, 701,  // NOLINT
-  594, 705, 595, 281, 596, 293, 1073742422, 301, 599, 305, 601, 317, 603, 321, 608, 329,  // NOLINT
-  611, 333, 613, 709, 614, 713, 616, 345, 617, 341, 619, 717, 623, 357, 625, 721,  // NOLINT
-  626, 361, 629, 369, 637, 725, 640, 385, 643, 393, 648, 401, 649, 669, 1073742474, 409,  // NOLINT
-  651, 413, 652, 673, 658, 425, 837, 729, 880, 733, 881, 733, 882, 737, 883, 737,  // NOLINT
-  886, 741, 887, 741, 1073742715, 745, 893, 749, 902, 753, 1073742728, 757, 906, 761, 908, 765,  // NOLINT
-  1073742734, 769, 911, 773, 913, 777, 914, 781, 1073742739, 785, 916, 789, 917, 793, 1073742742, 797,  // NOLINT
-  919, 801, 920, 805, 921, 729, 922, 809, 923, 813, 924, 9, 1073742749, 817, 927, 821,  // NOLINT
-  928, 825, 929, 829, 931, 833, 1073742756, 837, 933, 841, 934, 845, 1073742759, 849, 939, 853,  // NOLINT
-  940, 753, 1073742765, 757, 943, 761, 945, 777, 946, 781, 1073742771, 785, 948, 789, 949, 793,  // NOLINT
-  1073742774, 797, 951, 801, 952, 805, 953, 729, 954, 809, 955, 813, 956, 9, 1073742781, 817,  // NOLINT
-  959, 821, 960, 825, 961, 829, 962, 833, 963, 833, 1073742788, 837, 965, 841, 966, 845,  // NOLINT
-  1073742791, 849, 971, 853, 972, 765, 1073742797, 769, 974, 773, 975, 857, 976, 781, 977, 805,  // NOLINT
-  981, 845, 982, 825, 983, 857, 984, 861, 985, 861, 986, 865, 987, 865, 988, 869,  // NOLINT
-  989, 869, 990, 873, 991, 873, 992, 877, 993, 877, 994, 881, 995, 881, 996, 885,  // NOLINT
-  997, 885, 998, 889, 999, 889, 1000, 893, 1001, 893, 1002, 897, 1003, 897, 1004, 901,  // NOLINT
-  1005, 901, 1006, 905, 1007, 905, 1008, 809, 1009, 829, 1010, 909, 1013, 793, 1015, 913,  // NOLINT
-  1016, 913, 1017, 909, 1018, 917, 1019, 917, 1073742845, 745, 1023, 749, 1073742848, 921, 1039, 925,  // NOLINT
-  1073742864, 929, 1071, 933, 1073742896, 929, 1103, 933, 1073742928, 921, 1119, 925, 1120, 937, 1121, 937,  // NOLINT
-  1122, 941, 1123, 941, 1124, 945, 1125, 945, 1126, 949, 1127, 949, 1128, 953, 1129, 953,  // NOLINT
-  1130, 957, 1131, 957, 1132, 961, 1133, 961, 1134, 965, 1135, 965, 1136, 969, 1137, 969,  // NOLINT
-  1138, 973, 1139, 973, 1140, 977, 1141, 977, 1142, 981, 1143, 981, 1144, 985, 1145, 985,  // NOLINT
-  1146, 989, 1147, 989, 1148, 993, 1149, 993, 1150, 997, 1151, 997, 1152, 1001, 1153, 1001,  // NOLINT
-  1162, 1005, 1163, 1005, 1164, 1009, 1165, 1009, 1166, 1013, 1167, 1013, 1168, 1017, 1169, 1017,  // NOLINT
-  1170, 1021, 1171, 1021, 1172, 1025, 1173, 1025, 1174, 1029, 1175, 1029, 1176, 1033, 1177, 1033,  // NOLINT
-  1178, 1037, 1179, 1037, 1180, 1041, 1181, 1041, 1182, 1045, 1183, 1045, 1184, 1049, 1185, 1049,  // NOLINT
-  1186, 1053, 1187, 1053, 1188, 1057, 1189, 1057, 1190, 1061, 1191, 1061, 1192, 1065, 1193, 1065,  // NOLINT
-  1194, 1069, 1195, 1069, 1196, 1073, 1197, 1073, 1198, 1077, 1199, 1077, 1200, 1081, 1201, 1081,  // NOLINT
-  1202, 1085, 1203, 1085, 1204, 1089, 1205, 1089, 1206, 1093, 1207, 1093, 1208, 1097, 1209, 1097,  // NOLINT
-  1210, 1101, 1211, 1101, 1212, 1105, 1213, 1105, 1214, 1109, 1215, 1109, 1216, 1113, 1217, 1117,  // NOLINT
-  1218, 1117, 1219, 1121, 1220, 1121, 1221, 1125, 1222, 1125, 1223, 1129, 1224, 1129, 1225, 1133,  // NOLINT
-  1226, 1133, 1227, 1137, 1228, 1137, 1229, 1141, 1230, 1141, 1231, 1113, 1232, 1145, 1233, 1145,  // NOLINT
-  1234, 1149, 1235, 1149, 1236, 1153, 1237, 1153, 1238, 1157, 1239, 1157, 1240, 1161, 1241, 1161,  // NOLINT
-  1242, 1165, 1243, 1165, 1244, 1169, 1245, 1169, 1246, 1173, 1247, 1173, 1248, 1177, 1249, 1177,  // NOLINT
-  1250, 1181, 1251, 1181, 1252, 1185, 1253, 1185, 1254, 1189, 1255, 1189, 1256, 1193, 1257, 1193,  // NOLINT
-  1258, 1197, 1259, 1197, 1260, 1201, 1261, 1201, 1262, 1205, 1263, 1205, 1264, 1209, 1265, 1209,  // NOLINT
-  1266, 1213, 1267, 1213, 1268, 1217, 1269, 1217, 1270, 1221, 1271, 1221, 1272, 1225, 1273, 1225,  // NOLINT
-  1274, 1229, 1275, 1229, 1276, 1233, 1277, 1233, 1278, 1237, 1279, 1237, 1280, 1241, 1281, 1241,  // NOLINT
-  1282, 1245, 1283, 1245, 1284, 1249, 1285, 1249, 1286, 1253, 1287, 1253, 1288, 1257, 1289, 1257,  // NOLINT
-  1290, 1261, 1291, 1261, 1292, 1265, 1293, 1265, 1294, 1269, 1295, 1269, 1296, 1273, 1297, 1273,  // NOLINT
-  1298, 1277, 1299, 1277, 1300, 1281, 1301, 1281, 1302, 1285, 1303, 1285, 1304, 1289, 1305, 1289,  // NOLINT
-  1306, 1293, 1307, 1293, 1308, 1297, 1309, 1297, 1310, 1301, 1311, 1301, 1312, 1305, 1313, 1305,  // NOLINT
-  1314, 1309, 1315, 1309, 1316, 1313, 1317, 1313, 1318, 1317, 1319, 1317, 1073743153, 1321, 1366, 1325,  // NOLINT
-  1073743201, 1321, 1414, 1325, 1073746080, 1329, 4293, 1333, 4295, 1337, 4301, 1341, 7545, 1345, 7549, 1349,  // NOLINT
-  7680, 1353, 7681, 1353, 7682, 1357, 7683, 1357, 7684, 1361, 7685, 1361, 7686, 1365, 7687, 1365,  // NOLINT
-  7688, 1369, 7689, 1369, 7690, 1373, 7691, 1373, 7692, 1377, 7693, 1377, 7694, 1381, 7695, 1381,  // NOLINT
-  7696, 1385, 7697, 1385, 7698, 1389, 7699, 1389, 7700, 1393, 7701, 1393, 7702, 1397, 7703, 1397,  // NOLINT
-  7704, 1401, 7705, 1401, 7706, 1405, 7707, 1405, 7708, 1409, 7709, 1409, 7710, 1413, 7711, 1413,  // NOLINT
-  7712, 1417, 7713, 1417, 7714, 1421, 7715, 1421, 7716, 1425, 7717, 1425, 7718, 1429, 7719, 1429,  // NOLINT
-  7720, 1433, 7721, 1433, 7722, 1437, 7723, 1437, 7724, 1441, 7725, 1441, 7726, 1445, 7727, 1445,  // NOLINT
-  7728, 1449, 7729, 1449, 7730, 1453, 7731, 1453, 7732, 1457, 7733, 1457, 7734, 1461, 7735, 1461,  // NOLINT
-  7736, 1465, 7737, 1465, 7738, 1469, 7739, 1469, 7740, 1473, 7741, 1473, 7742, 1477, 7743, 1477,  // NOLINT
-  7744, 1481, 7745, 1481, 7746, 1485, 7747, 1485, 7748, 1489, 7749, 1489, 7750, 1493, 7751, 1493,  // NOLINT
-  7752, 1497, 7753, 1497, 7754, 1501, 7755, 1501, 7756, 1505, 7757, 1505, 7758, 1509, 7759, 1509,  // NOLINT
-  7760, 1513, 7761, 1513, 7762, 1517, 7763, 1517, 7764, 1521, 7765, 1521, 7766, 1525, 7767, 1525,  // NOLINT
-  7768, 1529, 7769, 1529, 7770, 1533, 7771, 1533, 7772, 1537, 7773, 1537, 7774, 1541, 7775, 1541,  // NOLINT
-  7776, 1545, 7777, 1545, 7778, 1549, 7779, 1549, 7780, 1553, 7781, 1553, 7782, 1557, 7783, 1557,  // NOLINT
-  7784, 1561, 7785, 1561, 7786, 1565, 7787, 1565, 7788, 1569, 7789, 1569, 7790, 1573, 7791, 1573,  // NOLINT
-  7792, 1577, 7793, 1577, 7794, 1581, 7795, 1581, 7796, 1585, 7797, 1585, 7798, 1589, 7799, 1589,  // NOLINT
-  7800, 1593, 7801, 1593, 7802, 1597, 7803, 1597, 7804, 1601, 7805, 1601, 7806, 1605, 7807, 1605,  // NOLINT
-  7808, 1609, 7809, 1609, 7810, 1613, 7811, 1613, 7812, 1617, 7813, 1617, 7814, 1621, 7815, 1621,  // NOLINT
-  7816, 1625, 7817, 1625, 7818, 1629, 7819, 1629, 7820, 1633, 7821, 1633, 7822, 1637, 7823, 1637,  // NOLINT
-  7824, 1641, 7825, 1641, 7826, 1645, 7827, 1645, 7828, 1649, 7829, 1649, 7835, 1545, 7840, 1653,  // NOLINT
-  7841, 1653, 7842, 1657, 7843, 1657, 7844, 1661, 7845, 1661, 7846, 1665, 7847, 1665, 7848, 1669,  // NOLINT
-  7849, 1669, 7850, 1673, 7851, 1673, 7852, 1677, 7853, 1677, 7854, 1681, 7855, 1681, 7856, 1685,  // NOLINT
-  7857, 1685, 7858, 1689, 7859, 1689, 7860, 1693, 7861, 1693, 7862, 1697, 7863, 1697, 7864, 1701,  // NOLINT
-  7865, 1701, 7866, 1705, 7867, 1705, 7868, 1709, 7869, 1709, 7870, 1713, 7871, 1713, 7872, 1717,  // NOLINT
-  7873, 1717, 7874, 1721, 7875, 1721, 7876, 1725, 7877, 1725, 7878, 1729, 7879, 1729, 7880, 1733,  // NOLINT
-  7881, 1733, 7882, 1737, 7883, 1737, 7884, 1741, 7885, 1741, 7886, 1745, 7887, 1745, 7888, 1749,  // NOLINT
-  7889, 1749, 7890, 1753, 7891, 1753, 7892, 1757, 7893, 1757, 7894, 1761, 7895, 1761, 7896, 1765,  // NOLINT
-  7897, 1765, 7898, 1769, 7899, 1769, 7900, 1773, 7901, 1773, 7902, 1777, 7903, 1777, 7904, 1781,  // NOLINT
-  7905, 1781, 7906, 1785, 7907, 1785, 7908, 1789, 7909, 1789, 7910, 1793, 7911, 1793, 7912, 1797,  // NOLINT
-  7913, 1797, 7914, 1801, 7915, 1801, 7916, 1805, 7917, 1805, 7918, 1809, 7919, 1809, 7920, 1813,  // NOLINT
-  7921, 1813, 7922, 1817, 7923, 1817, 7924, 1821, 7925, 1821, 7926, 1825, 7927, 1825, 7928, 1829,  // NOLINT
-  7929, 1829, 7930, 1833, 7931, 1833, 7932, 1837, 7933, 1837, 7934, 1841, 7935, 1841, 1073749760, 1845,  // NOLINT
-  7943, 1849, 1073749768, 1845, 7951, 1849, 1073749776, 1853, 7957, 1857, 1073749784, 1853, 7965, 1857, 1073749792, 1861,  // NOLINT
-  7975, 1865, 1073749800, 1861, 7983, 1865, 1073749808, 1869, 7991, 1873, 1073749816, 1869, 7999, 1873, 1073749824, 1877,  // NOLINT
-  8005, 1881, 1073749832, 1877, 8013, 1881, 8017, 1885, 8019, 1889, 8021, 1893, 8023, 1897, 8025, 1885,  // NOLINT
-  8027, 1889, 8029, 1893, 8031, 1897, 1073749856, 1901, 8039, 1905, 1073749864, 1901, 8047, 1905, 1073749872, 1909,  // NOLINT
-  8049, 1913, 1073749874, 1917, 8053, 1921, 1073749878, 1925, 8055, 1929, 1073749880, 1933, 8057, 1937, 1073749882, 1941,  // NOLINT
-  8059, 1945, 1073749884, 1949, 8061, 1953, 1073749936, 1957, 8113, 1961, 1073749944, 1957, 8121, 1961, 1073749946, 1909,  // NOLINT
-  8123, 1913, 8126, 729, 1073749960, 1917, 8139, 1921, 1073749968, 1965, 8145, 1969, 1073749976, 1965, 8153, 1969,  // NOLINT
-  1073749978, 1925, 8155, 1929, 1073749984, 1973, 8161, 1977, 8165, 1981, 1073749992, 1973, 8169, 1977, 1073749994, 1941,  // NOLINT
-  8171, 1945, 8172, 1981, 1073750008, 1933, 8185, 1937, 1073750010, 1949, 8187, 1953 };  // NOLINT
-static const uint16_t kEcma262UnCanonicalizeMultiStrings0Size = 497;  // NOLINT
+static const MultiCharacterSpecialCase<4>
+    kEcma262UnCanonicalizeMultiStrings0[507] = {  // NOLINT
+        {{65, 97, kSentinel}},
+        {{90, 122, kSentinel}},
+        {{181, 924, 956, kSentinel}},
+        {{192, 224, kSentinel}},  // NOLINT
+        {{214, 246, kSentinel}},
+        {{216, 248, kSentinel}},
+        {{222, 254, kSentinel}},
+        {{255, 376, kSentinel}},  // NOLINT
+        {{256, 257, kSentinel}},
+        {{258, 259, kSentinel}},
+        {{260, 261, kSentinel}},
+        {{262, 263, kSentinel}},  // NOLINT
+        {{264, 265, kSentinel}},
+        {{266, 267, kSentinel}},
+        {{268, 269, kSentinel}},
+        {{270, 271, kSentinel}},  // NOLINT
+        {{272, 273, kSentinel}},
+        {{274, 275, kSentinel}},
+        {{276, 277, kSentinel}},
+        {{278, 279, kSentinel}},  // NOLINT
+        {{280, 281, kSentinel}},
+        {{282, 283, kSentinel}},
+        {{284, 285, kSentinel}},
+        {{286, 287, kSentinel}},  // NOLINT
+        {{288, 289, kSentinel}},
+        {{290, 291, kSentinel}},
+        {{292, 293, kSentinel}},
+        {{294, 295, kSentinel}},  // NOLINT
+        {{296, 297, kSentinel}},
+        {{298, 299, kSentinel}},
+        {{300, 301, kSentinel}},
+        {{302, 303, kSentinel}},  // NOLINT
+        {{306, 307, kSentinel}},
+        {{308, 309, kSentinel}},
+        {{310, 311, kSentinel}},
+        {{313, 314, kSentinel}},  // NOLINT
+        {{315, 316, kSentinel}},
+        {{317, 318, kSentinel}},
+        {{319, 320, kSentinel}},
+        {{321, 322, kSentinel}},  // NOLINT
+        {{323, 324, kSentinel}},
+        {{325, 326, kSentinel}},
+        {{327, 328, kSentinel}},
+        {{330, 331, kSentinel}},  // NOLINT
+        {{332, 333, kSentinel}},
+        {{334, 335, kSentinel}},
+        {{336, 337, kSentinel}},
+        {{338, 339, kSentinel}},  // NOLINT
+        {{340, 341, kSentinel}},
+        {{342, 343, kSentinel}},
+        {{344, 345, kSentinel}},
+        {{346, 347, kSentinel}},  // NOLINT
+        {{348, 349, kSentinel}},
+        {{350, 351, kSentinel}},
+        {{352, 353, kSentinel}},
+        {{354, 355, kSentinel}},  // NOLINT
+        {{356, 357, kSentinel}},
+        {{358, 359, kSentinel}},
+        {{360, 361, kSentinel}},
+        {{362, 363, kSentinel}},  // NOLINT
+        {{364, 365, kSentinel}},
+        {{366, 367, kSentinel}},
+        {{368, 369, kSentinel}},
+        {{370, 371, kSentinel}},  // NOLINT
+        {{372, 373, kSentinel}},
+        {{374, 375, kSentinel}},
+        {{377, 378, kSentinel}},
+        {{379, 380, kSentinel}},  // NOLINT
+        {{381, 382, kSentinel}},
+        {{384, 579, kSentinel}},
+        {{385, 595, kSentinel}},
+        {{386, 387, kSentinel}},  // NOLINT
+        {{388, 389, kSentinel}},
+        {{390, 596, kSentinel}},
+        {{391, 392, kSentinel}},
+        {{393, 598, kSentinel}},  // NOLINT
+        {{394, 599, kSentinel}},
+        {{395, 396, kSentinel}},
+        {{398, 477, kSentinel}},
+        {{399, 601, kSentinel}},  // NOLINT
+        {{400, 603, kSentinel}},
+        {{401, 402, kSentinel}},
+        {{403, 608, kSentinel}},
+        {{404, 611, kSentinel}},  // NOLINT
+        {{405, 502, kSentinel}},
+        {{406, 617, kSentinel}},
+        {{407, 616, kSentinel}},
+        {{408, 409, kSentinel}},  // NOLINT
+        {{410, 573, kSentinel}},
+        {{412, 623, kSentinel}},
+        {{413, 626, kSentinel}},
+        {{414, 544, kSentinel}},  // NOLINT
+        {{415, 629, kSentinel}},
+        {{416, 417, kSentinel}},
+        {{418, 419, kSentinel}},
+        {{420, 421, kSentinel}},  // NOLINT
+        {{422, 640, kSentinel}},
+        {{423, 424, kSentinel}},
+        {{425, 643, kSentinel}},
+        {{428, 429, kSentinel}},  // NOLINT
+        {{430, 648, kSentinel}},
+        {{431, 432, kSentinel}},
+        {{433, 650, kSentinel}},
+        {{434, 651, kSentinel}},  // NOLINT
+        {{435, 436, kSentinel}},
+        {{437, 438, kSentinel}},
+        {{439, 658, kSentinel}},
+        {{440, 441, kSentinel}},  // NOLINT
+        {{444, 445, kSentinel}},
+        {{447, 503, kSentinel}},
+        {{452, 453, 454, kSentinel}},
+        {{455, 456, 457, kSentinel}},  // NOLINT
+        {{458, 459, 460, kSentinel}},
+        {{461, 462, kSentinel}},
+        {{463, 464, kSentinel}},
+        {{465, 466, kSentinel}},  // NOLINT
+        {{467, 468, kSentinel}},
+        {{469, 470, kSentinel}},
+        {{471, 472, kSentinel}},
+        {{473, 474, kSentinel}},  // NOLINT
+        {{475, 476, kSentinel}},
+        {{478, 479, kSentinel}},
+        {{480, 481, kSentinel}},
+        {{482, 483, kSentinel}},  // NOLINT
+        {{484, 485, kSentinel}},
+        {{486, 487, kSentinel}},
+        {{488, 489, kSentinel}},
+        {{490, 491, kSentinel}},  // NOLINT
+        {{492, 493, kSentinel}},
+        {{494, 495, kSentinel}},
+        {{497, 498, 499, kSentinel}},
+        {{500, 501, kSentinel}},  // NOLINT
+        {{504, 505, kSentinel}},
+        {{506, 507, kSentinel}},
+        {{508, 509, kSentinel}},
+        {{510, 511, kSentinel}},  // NOLINT
+        {{512, 513, kSentinel}},
+        {{514, 515, kSentinel}},
+        {{516, 517, kSentinel}},
+        {{518, 519, kSentinel}},  // NOLINT
+        {{520, 521, kSentinel}},
+        {{522, 523, kSentinel}},
+        {{524, 525, kSentinel}},
+        {{526, 527, kSentinel}},  // NOLINT
+        {{528, 529, kSentinel}},
+        {{530, 531, kSentinel}},
+        {{532, 533, kSentinel}},
+        {{534, 535, kSentinel}},  // NOLINT
+        {{536, 537, kSentinel}},
+        {{538, 539, kSentinel}},
+        {{540, 541, kSentinel}},
+        {{542, 543, kSentinel}},  // NOLINT
+        {{546, 547, kSentinel}},
+        {{548, 549, kSentinel}},
+        {{550, 551, kSentinel}},
+        {{552, 553, kSentinel}},  // NOLINT
+        {{554, 555, kSentinel}},
+        {{556, 557, kSentinel}},
+        {{558, 559, kSentinel}},
+        {{560, 561, kSentinel}},  // NOLINT
+        {{562, 563, kSentinel}},
+        {{570, 11365, kSentinel}},
+        {{571, 572, kSentinel}},
+        {{574, 11366, kSentinel}},  // NOLINT
+        {{575, 11390, kSentinel}},
+        {{576, 11391, kSentinel}},
+        {{577, 578, kSentinel}},
+        {{580, 649, kSentinel}},  // NOLINT
+        {{581, 652, kSentinel}},
+        {{582, 583, kSentinel}},
+        {{584, 585, kSentinel}},
+        {{586, 587, kSentinel}},  // NOLINT
+        {{588, 589, kSentinel}},
+        {{590, 591, kSentinel}},
+        {{592, 11375, kSentinel}},
+        {{593, 11373, kSentinel}},  // NOLINT
+        {{594, 11376, kSentinel}},
+        {{604, 42923, kSentinel}},
+        {{609, 42924, kSentinel}},
+        {{613, 42893, kSentinel}},  // NOLINT
+        {{614, 42922, kSentinel}},
+        {{619, 11362, kSentinel}},
+        {{620, 42925, kSentinel}},
+        {{625, 11374, kSentinel}},  // NOLINT
+        {{637, 11364, kSentinel}},
+        {{647, 42929, kSentinel}},
+        {{670, 42928, kSentinel}},
+        {{837, 921, 953, 8126}},  // NOLINT
+        {{880, 881, kSentinel}},
+        {{882, 883, kSentinel}},
+        {{886, 887, kSentinel}},
+        {{891, 1021, kSentinel}},  // NOLINT
+        {{893, 1023, kSentinel}},
+        {{895, 1011, kSentinel}},
+        {{902, 940, kSentinel}},
+        {{904, 941, kSentinel}},  // NOLINT
+        {{906, 943, kSentinel}},
+        {{908, 972, kSentinel}},
+        {{910, 973, kSentinel}},
+        {{911, 974, kSentinel}},  // NOLINT
+        {{913, 945, kSentinel}},
+        {{914, 946, 976, kSentinel}},
+        {{915, 947, kSentinel}},
+        {{916, 948, kSentinel}},  // NOLINT
+        {{917, 949, 1013, kSentinel}},
+        {{918, 950, kSentinel}},
+        {{919, 951, kSentinel}},
+        {{920, 952, 977, kSentinel}},  // NOLINT
+        {{922, 954, 1008, kSentinel}},
+        {{923, 955, kSentinel}},
+        {{925, 957, kSentinel}},
+        {{927, 959, kSentinel}},  // NOLINT
+        {{928, 960, 982, kSentinel}},
+        {{929, 961, 1009, kSentinel}},
+        {{931, 962, 963, kSentinel}},
+        {{932, 964, kSentinel}},  // NOLINT
+        {{933, 965, kSentinel}},
+        {{934, 966, 981, kSentinel}},
+        {{935, 967, kSentinel}},
+        {{939, 971, kSentinel}},  // NOLINT
+        {{975, 983, kSentinel}},
+        {{984, 985, kSentinel}},
+        {{986, 987, kSentinel}},
+        {{988, 989, kSentinel}},  // NOLINT
+        {{990, 991, kSentinel}},
+        {{992, 993, kSentinel}},
+        {{994, 995, kSentinel}},
+        {{996, 997, kSentinel}},  // NOLINT
+        {{998, 999, kSentinel}},
+        {{1000, 1001, kSentinel}},
+        {{1002, 1003, kSentinel}},
+        {{1004, 1005, kSentinel}},  // NOLINT
+        {{1006, 1007, kSentinel}},
+        {{1010, 1017, kSentinel}},
+        {{1015, 1016, kSentinel}},
+        {{1018, 1019, kSentinel}},  // NOLINT
+        {{1024, 1104, kSentinel}},
+        {{1039, 1119, kSentinel}},
+        {{1040, 1072, kSentinel}},
+        {{1071, 1103, kSentinel}},  // NOLINT
+        {{1120, 1121, kSentinel}},
+        {{1122, 1123, kSentinel}},
+        {{1124, 1125, kSentinel}},
+        {{1126, 1127, kSentinel}},  // NOLINT
+        {{1128, 1129, kSentinel}},
+        {{1130, 1131, kSentinel}},
+        {{1132, 1133, kSentinel}},
+        {{1134, 1135, kSentinel}},  // NOLINT
+        {{1136, 1137, kSentinel}},
+        {{1138, 1139, kSentinel}},
+        {{1140, 1141, kSentinel}},
+        {{1142, 1143, kSentinel}},  // NOLINT
+        {{1144, 1145, kSentinel}},
+        {{1146, 1147, kSentinel}},
+        {{1148, 1149, kSentinel}},
+        {{1150, 1151, kSentinel}},  // NOLINT
+        {{1152, 1153, kSentinel}},
+        {{1162, 1163, kSentinel}},
+        {{1164, 1165, kSentinel}},
+        {{1166, 1167, kSentinel}},  // NOLINT
+        {{1168, 1169, kSentinel}},
+        {{1170, 1171, kSentinel}},
+        {{1172, 1173, kSentinel}},
+        {{1174, 1175, kSentinel}},  // NOLINT
+        {{1176, 1177, kSentinel}},
+        {{1178, 1179, kSentinel}},
+        {{1180, 1181, kSentinel}},
+        {{1182, 1183, kSentinel}},  // NOLINT
+        {{1184, 1185, kSentinel}},
+        {{1186, 1187, kSentinel}},
+        {{1188, 1189, kSentinel}},
+        {{1190, 1191, kSentinel}},  // NOLINT
+        {{1192, 1193, kSentinel}},
+        {{1194, 1195, kSentinel}},
+        {{1196, 1197, kSentinel}},
+        {{1198, 1199, kSentinel}},  // NOLINT
+        {{1200, 1201, kSentinel}},
+        {{1202, 1203, kSentinel}},
+        {{1204, 1205, kSentinel}},
+        {{1206, 1207, kSentinel}},  // NOLINT
+        {{1208, 1209, kSentinel}},
+        {{1210, 1211, kSentinel}},
+        {{1212, 1213, kSentinel}},
+        {{1214, 1215, kSentinel}},  // NOLINT
+        {{1216, 1231, kSentinel}},
+        {{1217, 1218, kSentinel}},
+        {{1219, 1220, kSentinel}},
+        {{1221, 1222, kSentinel}},  // NOLINT
+        {{1223, 1224, kSentinel}},
+        {{1225, 1226, kSentinel}},
+        {{1227, 1228, kSentinel}},
+        {{1229, 1230, kSentinel}},  // NOLINT
+        {{1232, 1233, kSentinel}},
+        {{1234, 1235, kSentinel}},
+        {{1236, 1237, kSentinel}},
+        {{1238, 1239, kSentinel}},  // NOLINT
+        {{1240, 1241, kSentinel}},
+        {{1242, 1243, kSentinel}},
+        {{1244, 1245, kSentinel}},
+        {{1246, 1247, kSentinel}},  // NOLINT
+        {{1248, 1249, kSentinel}},
+        {{1250, 1251, kSentinel}},
+        {{1252, 1253, kSentinel}},
+        {{1254, 1255, kSentinel}},  // NOLINT
+        {{1256, 1257, kSentinel}},
+        {{1258, 1259, kSentinel}},
+        {{1260, 1261, kSentinel}},
+        {{1262, 1263, kSentinel}},  // NOLINT
+        {{1264, 1265, kSentinel}},
+        {{1266, 1267, kSentinel}},
+        {{1268, 1269, kSentinel}},
+        {{1270, 1271, kSentinel}},  // NOLINT
+        {{1272, 1273, kSentinel}},
+        {{1274, 1275, kSentinel}},
+        {{1276, 1277, kSentinel}},
+        {{1278, 1279, kSentinel}},  // NOLINT
+        {{1280, 1281, kSentinel}},
+        {{1282, 1283, kSentinel}},
+        {{1284, 1285, kSentinel}},
+        {{1286, 1287, kSentinel}},  // NOLINT
+        {{1288, 1289, kSentinel}},
+        {{1290, 1291, kSentinel}},
+        {{1292, 1293, kSentinel}},
+        {{1294, 1295, kSentinel}},  // NOLINT
+        {{1296, 1297, kSentinel}},
+        {{1298, 1299, kSentinel}},
+        {{1300, 1301, kSentinel}},
+        {{1302, 1303, kSentinel}},  // NOLINT
+        {{1304, 1305, kSentinel}},
+        {{1306, 1307, kSentinel}},
+        {{1308, 1309, kSentinel}},
+        {{1310, 1311, kSentinel}},  // NOLINT
+        {{1312, 1313, kSentinel}},
+        {{1314, 1315, kSentinel}},
+        {{1316, 1317, kSentinel}},
+        {{1318, 1319, kSentinel}},  // NOLINT
+        {{1320, 1321, kSentinel}},
+        {{1322, 1323, kSentinel}},
+        {{1324, 1325, kSentinel}},
+        {{1326, 1327, kSentinel}},  // NOLINT
+        {{1329, 1377, kSentinel}},
+        {{1366, 1414, kSentinel}},
+        {{4256, 11520, kSentinel}},
+        {{4293, 11557, kSentinel}},  // NOLINT
+        {{4295, 11559, kSentinel}},
+        {{4301, 11565, kSentinel}},
+        {{7545, 42877, kSentinel}},
+        {{7549, 11363, kSentinel}},  // NOLINT
+        {{7680, 7681, kSentinel}},
+        {{7682, 7683, kSentinel}},
+        {{7684, 7685, kSentinel}},
+        {{7686, 7687, kSentinel}},  // NOLINT
+        {{7688, 7689, kSentinel}},
+        {{7690, 7691, kSentinel}},
+        {{7692, 7693, kSentinel}},
+        {{7694, 7695, kSentinel}},  // NOLINT
+        {{7696, 7697, kSentinel}},
+        {{7698, 7699, kSentinel}},
+        {{7700, 7701, kSentinel}},
+        {{7702, 7703, kSentinel}},  // NOLINT
+        {{7704, 7705, kSentinel}},
+        {{7706, 7707, kSentinel}},
+        {{7708, 7709, kSentinel}},
+        {{7710, 7711, kSentinel}},  // NOLINT
+        {{7712, 7713, kSentinel}},
+        {{7714, 7715, kSentinel}},
+        {{7716, 7717, kSentinel}},
+        {{7718, 7719, kSentinel}},  // NOLINT
+        {{7720, 7721, kSentinel}},
+        {{7722, 7723, kSentinel}},
+        {{7724, 7725, kSentinel}},
+        {{7726, 7727, kSentinel}},  // NOLINT
+        {{7728, 7729, kSentinel}},
+        {{7730, 7731, kSentinel}},
+        {{7732, 7733, kSentinel}},
+        {{7734, 7735, kSentinel}},  // NOLINT
+        {{7736, 7737, kSentinel}},
+        {{7738, 7739, kSentinel}},
+        {{7740, 7741, kSentinel}},
+        {{7742, 7743, kSentinel}},  // NOLINT
+        {{7744, 7745, kSentinel}},
+        {{7746, 7747, kSentinel}},
+        {{7748, 7749, kSentinel}},
+        {{7750, 7751, kSentinel}},  // NOLINT
+        {{7752, 7753, kSentinel}},
+        {{7754, 7755, kSentinel}},
+        {{7756, 7757, kSentinel}},
+        {{7758, 7759, kSentinel}},  // NOLINT
+        {{7760, 7761, kSentinel}},
+        {{7762, 7763, kSentinel}},
+        {{7764, 7765, kSentinel}},
+        {{7766, 7767, kSentinel}},  // NOLINT
+        {{7768, 7769, kSentinel}},
+        {{7770, 7771, kSentinel}},
+        {{7772, 7773, kSentinel}},
+        {{7774, 7775, kSentinel}},  // NOLINT
+        {{7776, 7777, 7835, kSentinel}},
+        {{7778, 7779, kSentinel}},
+        {{7780, 7781, kSentinel}},
+        {{7782, 7783, kSentinel}},  // NOLINT
+        {{7784, 7785, kSentinel}},
+        {{7786, 7787, kSentinel}},
+        {{7788, 7789, kSentinel}},
+        {{7790, 7791, kSentinel}},  // NOLINT
+        {{7792, 7793, kSentinel}},
+        {{7794, 7795, kSentinel}},
+        {{7796, 7797, kSentinel}},
+        {{7798, 7799, kSentinel}},  // NOLINT
+        {{7800, 7801, kSentinel}},
+        {{7802, 7803, kSentinel}},
+        {{7804, 7805, kSentinel}},
+        {{7806, 7807, kSentinel}},  // NOLINT
+        {{7808, 7809, kSentinel}},
+        {{7810, 7811, kSentinel}},
+        {{7812, 7813, kSentinel}},
+        {{7814, 7815, kSentinel}},  // NOLINT
+        {{7816, 7817, kSentinel}},
+        {{7818, 7819, kSentinel}},
+        {{7820, 7821, kSentinel}},
+        {{7822, 7823, kSentinel}},  // NOLINT
+        {{7824, 7825, kSentinel}},
+        {{7826, 7827, kSentinel}},
+        {{7828, 7829, kSentinel}},
+        {{7840, 7841, kSentinel}},  // NOLINT
+        {{7842, 7843, kSentinel}},
+        {{7844, 7845, kSentinel}},
+        {{7846, 7847, kSentinel}},
+        {{7848, 7849, kSentinel}},  // NOLINT
+        {{7850, 7851, kSentinel}},
+        {{7852, 7853, kSentinel}},
+        {{7854, 7855, kSentinel}},
+        {{7856, 7857, kSentinel}},  // NOLINT
+        {{7858, 7859, kSentinel}},
+        {{7860, 7861, kSentinel}},
+        {{7862, 7863, kSentinel}},
+        {{7864, 7865, kSentinel}},  // NOLINT
+        {{7866, 7867, kSentinel}},
+        {{7868, 7869, kSentinel}},
+        {{7870, 7871, kSentinel}},
+        {{7872, 7873, kSentinel}},  // NOLINT
+        {{7874, 7875, kSentinel}},
+        {{7876, 7877, kSentinel}},
+        {{7878, 7879, kSentinel}},
+        {{7880, 7881, kSentinel}},  // NOLINT
+        {{7882, 7883, kSentinel}},
+        {{7884, 7885, kSentinel}},
+        {{7886, 7887, kSentinel}},
+        {{7888, 7889, kSentinel}},  // NOLINT
+        {{7890, 7891, kSentinel}},
+        {{7892, 7893, kSentinel}},
+        {{7894, 7895, kSentinel}},
+        {{7896, 7897, kSentinel}},  // NOLINT
+        {{7898, 7899, kSentinel}},
+        {{7900, 7901, kSentinel}},
+        {{7902, 7903, kSentinel}},
+        {{7904, 7905, kSentinel}},  // NOLINT
+        {{7906, 7907, kSentinel}},
+        {{7908, 7909, kSentinel}},
+        {{7910, 7911, kSentinel}},
+        {{7912, 7913, kSentinel}},  // NOLINT
+        {{7914, 7915, kSentinel}},
+        {{7916, 7917, kSentinel}},
+        {{7918, 7919, kSentinel}},
+        {{7920, 7921, kSentinel}},  // NOLINT
+        {{7922, 7923, kSentinel}},
+        {{7924, 7925, kSentinel}},
+        {{7926, 7927, kSentinel}},
+        {{7928, 7929, kSentinel}},  // NOLINT
+        {{7930, 7931, kSentinel}},
+        {{7932, 7933, kSentinel}},
+        {{7934, 7935, kSentinel}},
+        {{7936, 7944, kSentinel}},  // NOLINT
+        {{7943, 7951, kSentinel}},
+        {{7952, 7960, kSentinel}},
+        {{7957, 7965, kSentinel}},
+        {{7968, 7976, kSentinel}},  // NOLINT
+        {{7975, 7983, kSentinel}},
+        {{7984, 7992, kSentinel}},
+        {{7991, 7999, kSentinel}},
+        {{8000, 8008, kSentinel}},  // NOLINT
+        {{8005, 8013, kSentinel}},
+        {{8017, 8025, kSentinel}},
+        {{8019, 8027, kSentinel}},
+        {{8021, 8029, kSentinel}},  // NOLINT
+        {{8023, 8031, kSentinel}},
+        {{8032, 8040, kSentinel}},
+        {{8039, 8047, kSentinel}},
+        {{8048, 8122, kSentinel}},  // NOLINT
+        {{8049, 8123, kSentinel}},
+        {{8050, 8136, kSentinel}},
+        {{8053, 8139, kSentinel}},
+        {{8054, 8154, kSentinel}},  // NOLINT
+        {{8055, 8155, kSentinel}},
+        {{8056, 8184, kSentinel}},
+        {{8057, 8185, kSentinel}},
+        {{8058, 8170, kSentinel}},  // NOLINT
+        {{8059, 8171, kSentinel}},
+        {{8060, 8186, kSentinel}},
+        {{8061, 8187, kSentinel}},
+        {{8112, 8120, kSentinel}},  // NOLINT
+        {{8113, 8121, kSentinel}},
+        {{8144, 8152, kSentinel}},
+        {{8145, 8153, kSentinel}},
+        {{8160, 8168, kSentinel}},  // NOLINT
+        {{8161, 8169, kSentinel}},
+        {{8165, 8172, kSentinel}},
+        {{kSentinel}}};                                         // NOLINT
+static const uint16_t kEcma262UnCanonicalizeTable0Size = 1005;  // NOLINT
+static const int32_t kEcma262UnCanonicalizeTable0[2010] = {
+    1073741889, 1,    90,         5,    1073741921, 1,
+    122,        5,    181,        9,    1073742016, 13,
+    214,        17,   1073742040, 21,  // NOLINT
+    222,        25,   1073742048, 13,   246,        17,
+    1073742072, 21,   254,        25,   255,        29,
+    256,        33,   257,        33,  // NOLINT
+    258,        37,   259,        37,   260,        41,
+    261,        41,   262,        45,   263,        45,
+    264,        49,   265,        49,  // NOLINT
+    266,        53,   267,        53,   268,        57,
+    269,        57,   270,        61,   271,        61,
+    272,        65,   273,        65,  // NOLINT
+    274,        69,   275,        69,   276,        73,
+    277,        73,   278,        77,   279,        77,
+    280,        81,   281,        81,  // NOLINT
+    282,        85,   283,        85,   284,        89,
+    285,        89,   286,        93,   287,        93,
+    288,        97,   289,        97,  // NOLINT
+    290,        101,  291,        101,  292,        105,
+    293,        105,  294,        109,  295,        109,
+    296,        113,  297,        113,  // NOLINT
+    298,        117,  299,        117,  300,        121,
+    301,        121,  302,        125,  303,        125,
+    306,        129,  307,        129,  // NOLINT
+    308,        133,  309,        133,  310,        137,
+    311,        137,  313,        141,  314,        141,
+    315,        145,  316,        145,  // NOLINT
+    317,        149,  318,        149,  319,        153,
+    320,        153,  321,        157,  322,        157,
+    323,        161,  324,        161,  // NOLINT
+    325,        165,  326,        165,  327,        169,
+    328,        169,  330,        173,  331,        173,
+    332,        177,  333,        177,  // NOLINT
+    334,        181,  335,        181,  336,        185,
+    337,        185,  338,        189,  339,        189,
+    340,        193,  341,        193,  // NOLINT
+    342,        197,  343,        197,  344,        201,
+    345,        201,  346,        205,  347,        205,
+    348,        209,  349,        209,  // NOLINT
+    350,        213,  351,        213,  352,        217,
+    353,        217,  354,        221,  355,        221,
+    356,        225,  357,        225,  // NOLINT
+    358,        229,  359,        229,  360,        233,
+    361,        233,  362,        237,  363,        237,
+    364,        241,  365,        241,  // NOLINT
+    366,        245,  367,        245,  368,        249,
+    369,        249,  370,        253,  371,        253,
+    372,        257,  373,        257,  // NOLINT
+    374,        261,  375,        261,  376,        29,
+    377,        265,  378,        265,  379,        269,
+    380,        269,  381,        273,  // NOLINT
+    382,        273,  384,        277,  385,        281,
+    386,        285,  387,        285,  388,        289,
+    389,        289,  390,        293,  // NOLINT
+    391,        297,  392,        297,  1073742217, 301,
+    394,        305,  395,        309,  396,        309,
+    398,        313,  399,        317,  // NOLINT
+    400,        321,  401,        325,  402,        325,
+    403,        329,  404,        333,  405,        337,
+    406,        341,  407,        345,  // NOLINT
+    408,        349,  409,        349,  410,        353,
+    412,        357,  413,        361,  414,        365,
+    415,        369,  416,        373,  // NOLINT
+    417,        373,  418,        377,  419,        377,
+    420,        381,  421,        381,  422,        385,
+    423,        389,  424,        389,  // NOLINT
+    425,        393,  428,        397,  429,        397,
+    430,        401,  431,        405,  432,        405,
+    1073742257, 409,  434,        413,  // NOLINT
+    435,        417,  436,        417,  437,        421,
+    438,        421,  439,        425,  440,        429,
+    441,        429,  444,        433,  // NOLINT
+    445,        433,  447,        437,  452,        441,
+    453,        441,  454,        441,  455,        445,
+    456,        445,  457,        445,  // NOLINT
+    458,        449,  459,        449,  460,        449,
+    461,        453,  462,        453,  463,        457,
+    464,        457,  465,        461,  // NOLINT
+    466,        461,  467,        465,  468,        465,
+    469,        469,  470,        469,  471,        473,
+    472,        473,  473,        477,  // NOLINT
+    474,        477,  475,        481,  476,        481,
+    477,        313,  478,        485,  479,        485,
+    480,        489,  481,        489,  // NOLINT
+    482,        493,  483,        493,  484,        497,
+    485,        497,  486,        501,  487,        501,
+    488,        505,  489,        505,  // NOLINT
+    490,        509,  491,        509,  492,        513,
+    493,        513,  494,        517,  495,        517,
+    497,        521,  498,        521,  // NOLINT
+    499,        521,  500,        525,  501,        525,
+    502,        337,  503,        437,  504,        529,
+    505,        529,  506,        533,  // NOLINT
+    507,        533,  508,        537,  509,        537,
+    510,        541,  511,        541,  512,        545,
+    513,        545,  514,        549,  // NOLINT
+    515,        549,  516,        553,  517,        553,
+    518,        557,  519,        557,  520,        561,
+    521,        561,  522,        565,  // NOLINT
+    523,        565,  524,        569,  525,        569,
+    526,        573,  527,        573,  528,        577,
+    529,        577,  530,        581,  // NOLINT
+    531,        581,  532,        585,  533,        585,
+    534,        589,  535,        589,  536,        593,
+    537,        593,  538,        597,  // NOLINT
+    539,        597,  540,        601,  541,        601,
+    542,        605,  543,        605,  544,        365,
+    546,        609,  547,        609,  // NOLINT
+    548,        613,  549,        613,  550,        617,
+    551,        617,  552,        621,  553,        621,
+    554,        625,  555,        625,  // NOLINT
+    556,        629,  557,        629,  558,        633,
+    559,        633,  560,        637,  561,        637,
+    562,        641,  563,        641,  // NOLINT
+    570,        645,  571,        649,  572,        649,
+    573,        353,  574,        653,  1073742399, 657,
+    576,        661,  577,        665,  // NOLINT
+    578,        665,  579,        277,  580,        669,
+    581,        673,  582,        677,  583,        677,
+    584,        681,  585,        681,  // NOLINT
+    586,        685,  587,        685,  588,        689,
+    589,        689,  590,        693,  591,        693,
+    592,        697,  593,        701,  // NOLINT
+    594,        705,  595,        281,  596,        293,
+    1073742422, 301,  599,        305,  601,        317,
+    603,        321,  604,        709,  // NOLINT
+    608,        329,  609,        713,  611,        333,
+    613,        717,  614,        721,  616,        345,
+    617,        341,  619,        725,  // NOLINT
+    620,        729,  623,        357,  625,        733,
+    626,        361,  629,        369,  637,        737,
+    640,        385,  643,        393,  // NOLINT
+    647,        741,  648,        401,  649,        669,
+    1073742474, 409,  651,        413,  652,        673,
+    658,        425,  670,        745,  // NOLINT
+    837,        749,  880,        753,  881,        753,
+    882,        757,  883,        757,  886,        761,
+    887,        761,  1073742715, 765,  // NOLINT
+    893,        769,  895,        773,  902,        777,
+    1073742728, 781,  906,        785,  908,        789,
+    1073742734, 793,  911,        797,  // NOLINT
+    913,        801,  914,        805,  1073742739, 809,
+    916,        813,  917,        817,  1073742742, 821,
+    919,        825,  920,        829,  // NOLINT
+    921,        749,  922,        833,  923,        837,
+    924,        9,    1073742749, 841,  927,        845,
+    928,        849,  929,        853,  // NOLINT
+    931,        857,  1073742756, 861,  933,        865,
+    934,        869,  1073742759, 873,  939,        877,
+    940,        777,  1073742765, 781,  // NOLINT
+    943,        785,  945,        801,  946,        805,
+    1073742771, 809,  948,        813,  949,        817,
+    1073742774, 821,  951,        825,  // NOLINT
+    952,        829,  953,        749,  954,        833,
+    955,        837,  956,        9,    1073742781, 841,
+    959,        845,  960,        849,  // NOLINT
+    961,        853,  962,        857,  963,        857,
+    1073742788, 861,  965,        865,  966,        869,
+    1073742791, 873,  971,        877,  // NOLINT
+    972,        789,  1073742797, 793,  974,        797,
+    975,        881,  976,        805,  977,        829,
+    981,        869,  982,        849,  // NOLINT
+    983,        881,  984,        885,  985,        885,
+    986,        889,  987,        889,  988,        893,
+    989,        893,  990,        897,  // NOLINT
+    991,        897,  992,        901,  993,        901,
+    994,        905,  995,        905,  996,        909,
+    997,        909,  998,        913,  // NOLINT
+    999,        913,  1000,       917,  1001,       917,
+    1002,       921,  1003,       921,  1004,       925,
+    1005,       925,  1006,       929,  // NOLINT
+    1007,       929,  1008,       833,  1009,       853,
+    1010,       933,  1011,       773,  1013,       817,
+    1015,       937,  1016,       937,  // NOLINT
+    1017,       933,  1018,       941,  1019,       941,
+    1073742845, 765,  1023,       769,  1073742848, 945,
+    1039,       949,  1073742864, 953,  // NOLINT
+    1071,       957,  1073742896, 953,  1103,       957,
+    1073742928, 945,  1119,       949,  1120,       961,
+    1121,       961,  1122,       965,  // NOLINT
+    1123,       965,  1124,       969,  1125,       969,
+    1126,       973,  1127,       973,  1128,       977,
+    1129,       977,  1130,       981,  // NOLINT
+    1131,       981,  1132,       985,  1133,       985,
+    1134,       989,  1135,       989,  1136,       993,
+    1137,       993,  1138,       997,  // NOLINT
+    1139,       997,  1140,       1001, 1141,       1001,
+    1142,       1005, 1143,       1005, 1144,       1009,
+    1145,       1009, 1146,       1013,  // NOLINT
+    1147,       1013, 1148,       1017, 1149,       1017,
+    1150,       1021, 1151,       1021, 1152,       1025,
+    1153,       1025, 1162,       1029,  // NOLINT
+    1163,       1029, 1164,       1033, 1165,       1033,
+    1166,       1037, 1167,       1037, 1168,       1041,
+    1169,       1041, 1170,       1045,  // NOLINT
+    1171,       1045, 1172,       1049, 1173,       1049,
+    1174,       1053, 1175,       1053, 1176,       1057,
+    1177,       1057, 1178,       1061,  // NOLINT
+    1179,       1061, 1180,       1065, 1181,       1065,
+    1182,       1069, 1183,       1069, 1184,       1073,
+    1185,       1073, 1186,       1077,  // NOLINT
+    1187,       1077, 1188,       1081, 1189,       1081,
+    1190,       1085, 1191,       1085, 1192,       1089,
+    1193,       1089, 1194,       1093,  // NOLINT
+    1195,       1093, 1196,       1097, 1197,       1097,
+    1198,       1101, 1199,       1101, 1200,       1105,
+    1201,       1105, 1202,       1109,  // NOLINT
+    1203,       1109, 1204,       1113, 1205,       1113,
+    1206,       1117, 1207,       1117, 1208,       1121,
+    1209,       1121, 1210,       1125,  // NOLINT
+    1211,       1125, 1212,       1129, 1213,       1129,
+    1214,       1133, 1215,       1133, 1216,       1137,
+    1217,       1141, 1218,       1141,  // NOLINT
+    1219,       1145, 1220,       1145, 1221,       1149,
+    1222,       1149, 1223,       1153, 1224,       1153,
+    1225,       1157, 1226,       1157,  // NOLINT
+    1227,       1161, 1228,       1161, 1229,       1165,
+    1230,       1165, 1231,       1137, 1232,       1169,
+    1233,       1169, 1234,       1173,  // NOLINT
+    1235,       1173, 1236,       1177, 1237,       1177,
+    1238,       1181, 1239,       1181, 1240,       1185,
+    1241,       1185, 1242,       1189,  // NOLINT
+    1243,       1189, 1244,       1193, 1245,       1193,
+    1246,       1197, 1247,       1197, 1248,       1201,
+    1249,       1201, 1250,       1205,  // NOLINT
+    1251,       1205, 1252,       1209, 1253,       1209,
+    1254,       1213, 1255,       1213, 1256,       1217,
+    1257,       1217, 1258,       1221,  // NOLINT
+    1259,       1221, 1260,       1225, 1261,       1225,
+    1262,       1229, 1263,       1229, 1264,       1233,
+    1265,       1233, 1266,       1237,  // NOLINT
+    1267,       1237, 1268,       1241, 1269,       1241,
+    1270,       1245, 1271,       1245, 1272,       1249,
+    1273,       1249, 1274,       1253,  // NOLINT
+    1275,       1253, 1276,       1257, 1277,       1257,
+    1278,       1261, 1279,       1261, 1280,       1265,
+    1281,       1265, 1282,       1269,  // NOLINT
+    1283,       1269, 1284,       1273, 1285,       1273,
+    1286,       1277, 1287,       1277, 1288,       1281,
+    1289,       1281, 1290,       1285,  // NOLINT
+    1291,       1285, 1292,       1289, 1293,       1289,
+    1294,       1293, 1295,       1293, 1296,       1297,
+    1297,       1297, 1298,       1301,  // NOLINT
+    1299,       1301, 1300,       1305, 1301,       1305,
+    1302,       1309, 1303,       1309, 1304,       1313,
+    1305,       1313, 1306,       1317,  // NOLINT
+    1307,       1317, 1308,       1321, 1309,       1321,
+    1310,       1325, 1311,       1325, 1312,       1329,
+    1313,       1329, 1314,       1333,  // NOLINT
+    1315,       1333, 1316,       1337, 1317,       1337,
+    1318,       1341, 1319,       1341, 1320,       1345,
+    1321,       1345, 1322,       1349,  // NOLINT
+    1323,       1349, 1324,       1353, 1325,       1353,
+    1326,       1357, 1327,       1357, 1073743153, 1361,
+    1366,       1365, 1073743201, 1361,  // NOLINT
+    1414,       1365, 1073746080, 1369, 4293,       1373,
+    4295,       1377, 4301,       1381, 7545,       1385,
+    7549,       1389, 7680,       1393,  // NOLINT
+    7681,       1393, 7682,       1397, 7683,       1397,
+    7684,       1401, 7685,       1401, 7686,       1405,
+    7687,       1405, 7688,       1409,  // NOLINT
+    7689,       1409, 7690,       1413, 7691,       1413,
+    7692,       1417, 7693,       1417, 7694,       1421,
+    7695,       1421, 7696,       1425,  // NOLINT
+    7697,       1425, 7698,       1429, 7699,       1429,
+    7700,       1433, 7701,       1433, 7702,       1437,
+    7703,       1437, 7704,       1441,  // NOLINT
+    7705,       1441, 7706,       1445, 7707,       1445,
+    7708,       1449, 7709,       1449, 7710,       1453,
+    7711,       1453, 7712,       1457,  // NOLINT
+    7713,       1457, 7714,       1461, 7715,       1461,
+    7716,       1465, 7717,       1465, 7718,       1469,
+    7719,       1469, 7720,       1473,  // NOLINT
+    7721,       1473, 7722,       1477, 7723,       1477,
+    7724,       1481, 7725,       1481, 7726,       1485,
+    7727,       1485, 7728,       1489,  // NOLINT
+    7729,       1489, 7730,       1493, 7731,       1493,
+    7732,       1497, 7733,       1497, 7734,       1501,
+    7735,       1501, 7736,       1505,  // NOLINT
+    7737,       1505, 7738,       1509, 7739,       1509,
+    7740,       1513, 7741,       1513, 7742,       1517,
+    7743,       1517, 7744,       1521,  // NOLINT
+    7745,       1521, 7746,       1525, 7747,       1525,
+    7748,       1529, 7749,       1529, 7750,       1533,
+    7751,       1533, 7752,       1537,  // NOLINT
+    7753,       1537, 7754,       1541, 7755,       1541,
+    7756,       1545, 7757,       1545, 7758,       1549,
+    7759,       1549, 7760,       1553,  // NOLINT
+    7761,       1553, 7762,       1557, 7763,       1557,
+    7764,       1561, 7765,       1561, 7766,       1565,
+    7767,       1565, 7768,       1569,  // NOLINT
+    7769,       1569, 7770,       1573, 7771,       1573,
+    7772,       1577, 7773,       1577, 7774,       1581,
+    7775,       1581, 7776,       1585,  // NOLINT
+    7777,       1585, 7778,       1589, 7779,       1589,
+    7780,       1593, 7781,       1593, 7782,       1597,
+    7783,       1597, 7784,       1601,  // NOLINT
+    7785,       1601, 7786,       1605, 7787,       1605,
+    7788,       1609, 7789,       1609, 7790,       1613,
+    7791,       1613, 7792,       1617,  // NOLINT
+    7793,       1617, 7794,       1621, 7795,       1621,
+    7796,       1625, 7797,       1625, 7798,       1629,
+    7799,       1629, 7800,       1633,  // NOLINT
+    7801,       1633, 7802,       1637, 7803,       1637,
+    7804,       1641, 7805,       1641, 7806,       1645,
+    7807,       1645, 7808,       1649,  // NOLINT
+    7809,       1649, 7810,       1653, 7811,       1653,
+    7812,       1657, 7813,       1657, 7814,       1661,
+    7815,       1661, 7816,       1665,  // NOLINT
+    7817,       1665, 7818,       1669, 7819,       1669,
+    7820,       1673, 7821,       1673, 7822,       1677,
+    7823,       1677, 7824,       1681,  // NOLINT
+    7825,       1681, 7826,       1685, 7827,       1685,
+    7828,       1689, 7829,       1689, 7835,       1585,
+    7840,       1693, 7841,       1693,  // NOLINT
+    7842,       1697, 7843,       1697, 7844,       1701,
+    7845,       1701, 7846,       1705, 7847,       1705,
+    7848,       1709, 7849,       1709,  // NOLINT
+    7850,       1713, 7851,       1713, 7852,       1717,
+    7853,       1717, 7854,       1721, 7855,       1721,
+    7856,       1725, 7857,       1725,  // NOLINT
+    7858,       1729, 7859,       1729, 7860,       1733,
+    7861,       1733, 7862,       1737, 7863,       1737,
+    7864,       1741, 7865,       1741,  // NOLINT
+    7866,       1745, 7867,       1745, 7868,       1749,
+    7869,       1749, 7870,       1753, 7871,       1753,
+    7872,       1757, 7873,       1757,  // NOLINT
+    7874,       1761, 7875,       1761, 7876,       1765,
+    7877,       1765, 7878,       1769, 7879,       1769,
+    7880,       1773, 7881,       1773,  // NOLINT
+    7882,       1777, 7883,       1777, 7884,       1781,
+    7885,       1781, 7886,       1785, 7887,       1785,
+    7888,       1789, 7889,       1789,  // NOLINT
+    7890,       1793, 7891,       1793, 7892,       1797,
+    7893,       1797, 7894,       1801, 7895,       1801,
+    7896,       1805, 7897,       1805,  // NOLINT
+    7898,       1809, 7899,       1809, 7900,       1813,
+    7901,       1813, 7902,       1817, 7903,       1817,
+    7904,       1821, 7905,       1821,  // NOLINT
+    7906,       1825, 7907,       1825, 7908,       1829,
+    7909,       1829, 7910,       1833, 7911,       1833,
+    7912,       1837, 7913,       1837,  // NOLINT
+    7914,       1841, 7915,       1841, 7916,       1845,
+    7917,       1845, 7918,       1849, 7919,       1849,
+    7920,       1853, 7921,       1853,  // NOLINT
+    7922,       1857, 7923,       1857, 7924,       1861,
+    7925,       1861, 7926,       1865, 7927,       1865,
+    7928,       1869, 7929,       1869,  // NOLINT
+    7930,       1873, 7931,       1873, 7932,       1877,
+    7933,       1877, 7934,       1881, 7935,       1881,
+    1073749760, 1885, 7943,       1889,  // NOLINT
+    1073749768, 1885, 7951,       1889, 1073749776, 1893,
+    7957,       1897, 1073749784, 1893, 7965,       1897,
+    1073749792, 1901, 7975,       1905,  // NOLINT
+    1073749800, 1901, 7983,       1905, 1073749808, 1909,
+    7991,       1913, 1073749816, 1909, 7999,       1913,
+    1073749824, 1917, 8005,       1921,  // NOLINT
+    1073749832, 1917, 8013,       1921, 8017,       1925,
+    8019,       1929, 8021,       1933, 8023,       1937,
+    8025,       1925, 8027,       1929,  // NOLINT
+    8029,       1933, 8031,       1937, 1073749856, 1941,
+    8039,       1945, 1073749864, 1941, 8047,       1945,
+    1073749872, 1949, 8049,       1953,  // NOLINT
+    1073749874, 1957, 8053,       1961, 1073749878, 1965,
+    8055,       1969, 1073749880, 1973, 8057,       1977,
+    1073749882, 1981, 8059,       1985,  // NOLINT
+    1073749884, 1989, 8061,       1993, 1073749936, 1997,
+    8113,       2001, 1073749944, 1997, 8121,       2001,
+    1073749946, 1949, 8123,       1953,  // NOLINT
+    8126,       749,  1073749960, 1957, 8139,       1961,
+    1073749968, 2005, 8145,       2009, 1073749976, 2005,
+    8153,       2009, 1073749978, 1965,  // NOLINT
+    8155,       1969, 1073749984, 2013, 8161,       2017,
+    8165,       2021, 1073749992, 2013, 8169,       2017,
+    1073749994, 1981, 8171,       1985,  // NOLINT
+    8172,       2021, 1073750008, 1973, 8185,       1977,
+    1073750010, 1989, 8187,       1993};                              // NOLINT
+static const uint16_t kEcma262UnCanonicalizeMultiStrings0Size = 507;  // NOLINT
 static const MultiCharacterSpecialCase<2> kEcma262UnCanonicalizeMultiStrings1[83] = {  // NOLINT
   {{8498, 8526}}, {{8544, 8560}}, {{8559, 8575}}, {{8579, 8580}},  // NOLINT
   {{9398, 9424}}, {{9423, 9449}}, {{11264, 11312}}, {{11310, 11358}},  // NOLINT
@@ -1616,56 +3036,165 @@
   3297, 293, 3298, 297, 3299, 297, 3307, 301, 3308, 301, 3309, 305, 3310, 305, 3314, 309,  // NOLINT
   3315, 309, 1073745152, 313, 3365, 317, 3367, 321, 3373, 325 };  // NOLINT
 static const uint16_t kEcma262UnCanonicalizeMultiStrings1Size = 83;  // NOLINT
-static const MultiCharacterSpecialCase<2> kEcma262UnCanonicalizeMultiStrings5[92] = {  // NOLINT
-  {{42560, 42561}}, {{42562, 42563}}, {{42564, 42565}}, {{42566, 42567}},  // NOLINT
-  {{42568, 42569}}, {{42570, 42571}}, {{42572, 42573}}, {{42574, 42575}},  // NOLINT
-  {{42576, 42577}}, {{42578, 42579}}, {{42580, 42581}}, {{42582, 42583}},  // NOLINT
-  {{42584, 42585}}, {{42586, 42587}}, {{42588, 42589}}, {{42590, 42591}},  // NOLINT
-  {{42592, 42593}}, {{42594, 42595}}, {{42596, 42597}}, {{42598, 42599}},  // NOLINT
-  {{42600, 42601}}, {{42602, 42603}}, {{42604, 42605}}, {{42624, 42625}},  // NOLINT
-  {{42626, 42627}}, {{42628, 42629}}, {{42630, 42631}}, {{42632, 42633}},  // NOLINT
-  {{42634, 42635}}, {{42636, 42637}}, {{42638, 42639}}, {{42640, 42641}},  // NOLINT
-  {{42642, 42643}}, {{42644, 42645}}, {{42646, 42647}}, {{42786, 42787}},  // NOLINT
-  {{42788, 42789}}, {{42790, 42791}}, {{42792, 42793}}, {{42794, 42795}},  // NOLINT
-  {{42796, 42797}}, {{42798, 42799}}, {{42802, 42803}}, {{42804, 42805}},  // NOLINT
-  {{42806, 42807}}, {{42808, 42809}}, {{42810, 42811}}, {{42812, 42813}},  // NOLINT
-  {{42814, 42815}}, {{42816, 42817}}, {{42818, 42819}}, {{42820, 42821}},  // NOLINT
-  {{42822, 42823}}, {{42824, 42825}}, {{42826, 42827}}, {{42828, 42829}},  // NOLINT
-  {{42830, 42831}}, {{42832, 42833}}, {{42834, 42835}}, {{42836, 42837}},  // NOLINT
-  {{42838, 42839}}, {{42840, 42841}}, {{42842, 42843}}, {{42844, 42845}},  // NOLINT
-  {{42846, 42847}}, {{42848, 42849}}, {{42850, 42851}}, {{42852, 42853}},  // NOLINT
-  {{42854, 42855}}, {{42856, 42857}}, {{42858, 42859}}, {{42860, 42861}},  // NOLINT
-  {{42862, 42863}}, {{42873, 42874}}, {{42875, 42876}}, {{7545, 42877}},  // NOLINT
-  {{42878, 42879}}, {{42880, 42881}}, {{42882, 42883}}, {{42884, 42885}},  // NOLINT
-  {{42886, 42887}}, {{42891, 42892}}, {{613, 42893}}, {{42896, 42897}},  // NOLINT
-  {{42898, 42899}}, {{42912, 42913}}, {{42914, 42915}}, {{42916, 42917}},  // NOLINT
-  {{42918, 42919}}, {{42920, 42921}}, {{614, 42922}}, {{kSentinel}} }; // NOLINT
-static const uint16_t kEcma262UnCanonicalizeTable5Size = 179;  // NOLINT
-static const int32_t kEcma262UnCanonicalizeTable5[358] = {
-  1600, 1, 1601, 1, 1602, 5, 1603, 5, 1604, 9, 1605, 9, 1606, 13, 1607, 13,  // NOLINT
-  1608, 17, 1609, 17, 1610, 21, 1611, 21, 1612, 25, 1613, 25, 1614, 29, 1615, 29,  // NOLINT
-  1616, 33, 1617, 33, 1618, 37, 1619, 37, 1620, 41, 1621, 41, 1622, 45, 1623, 45,  // NOLINT
-  1624, 49, 1625, 49, 1626, 53, 1627, 53, 1628, 57, 1629, 57, 1630, 61, 1631, 61,  // NOLINT
-  1632, 65, 1633, 65, 1634, 69, 1635, 69, 1636, 73, 1637, 73, 1638, 77, 1639, 77,  // NOLINT
-  1640, 81, 1641, 81, 1642, 85, 1643, 85, 1644, 89, 1645, 89, 1664, 93, 1665, 93,  // NOLINT
-  1666, 97, 1667, 97, 1668, 101, 1669, 101, 1670, 105, 1671, 105, 1672, 109, 1673, 109,  // NOLINT
-  1674, 113, 1675, 113, 1676, 117, 1677, 117, 1678, 121, 1679, 121, 1680, 125, 1681, 125,  // NOLINT
-  1682, 129, 1683, 129, 1684, 133, 1685, 133, 1686, 137, 1687, 137, 1826, 141, 1827, 141,  // NOLINT
-  1828, 145, 1829, 145, 1830, 149, 1831, 149, 1832, 153, 1833, 153, 1834, 157, 1835, 157,  // NOLINT
-  1836, 161, 1837, 161, 1838, 165, 1839, 165, 1842, 169, 1843, 169, 1844, 173, 1845, 173,  // NOLINT
-  1846, 177, 1847, 177, 1848, 181, 1849, 181, 1850, 185, 1851, 185, 1852, 189, 1853, 189,  // NOLINT
-  1854, 193, 1855, 193, 1856, 197, 1857, 197, 1858, 201, 1859, 201, 1860, 205, 1861, 205,  // NOLINT
-  1862, 209, 1863, 209, 1864, 213, 1865, 213, 1866, 217, 1867, 217, 1868, 221, 1869, 221,  // NOLINT
-  1870, 225, 1871, 225, 1872, 229, 1873, 229, 1874, 233, 1875, 233, 1876, 237, 1877, 237,  // NOLINT
-  1878, 241, 1879, 241, 1880, 245, 1881, 245, 1882, 249, 1883, 249, 1884, 253, 1885, 253,  // NOLINT
-  1886, 257, 1887, 257, 1888, 261, 1889, 261, 1890, 265, 1891, 265, 1892, 269, 1893, 269,  // NOLINT
-  1894, 273, 1895, 273, 1896, 277, 1897, 277, 1898, 281, 1899, 281, 1900, 285, 1901, 285,  // NOLINT
-  1902, 289, 1903, 289, 1913, 293, 1914, 293, 1915, 297, 1916, 297, 1917, 301, 1918, 305,  // NOLINT
-  1919, 305, 1920, 309, 1921, 309, 1922, 313, 1923, 313, 1924, 317, 1925, 317, 1926, 321,  // NOLINT
-  1927, 321, 1931, 325, 1932, 325, 1933, 329, 1936, 333, 1937, 333, 1938, 337, 1939, 337,  // NOLINT
-  1952, 341, 1953, 341, 1954, 345, 1955, 345, 1956, 349, 1957, 349, 1958, 353, 1959, 353,  // NOLINT
-  1960, 357, 1961, 357, 1962, 361 };  // NOLINT
-static const uint16_t kEcma262UnCanonicalizeMultiStrings5Size = 92;  // NOLINT
+static const MultiCharacterSpecialCase<2>
+    kEcma262UnCanonicalizeMultiStrings5[104] = {  // NOLINT
+        {{42560, 42561}},
+        {{42562, 42563}},
+        {{42564, 42565}},
+        {{42566, 42567}},  // NOLINT
+        {{42568, 42569}},
+        {{42570, 42571}},
+        {{42572, 42573}},
+        {{42574, 42575}},  // NOLINT
+        {{42576, 42577}},
+        {{42578, 42579}},
+        {{42580, 42581}},
+        {{42582, 42583}},  // NOLINT
+        {{42584, 42585}},
+        {{42586, 42587}},
+        {{42588, 42589}},
+        {{42590, 42591}},  // NOLINT
+        {{42592, 42593}},
+        {{42594, 42595}},
+        {{42596, 42597}},
+        {{42598, 42599}},  // NOLINT
+        {{42600, 42601}},
+        {{42602, 42603}},
+        {{42604, 42605}},
+        {{42624, 42625}},  // NOLINT
+        {{42626, 42627}},
+        {{42628, 42629}},
+        {{42630, 42631}},
+        {{42632, 42633}},  // NOLINT
+        {{42634, 42635}},
+        {{42636, 42637}},
+        {{42638, 42639}},
+        {{42640, 42641}},  // NOLINT
+        {{42642, 42643}},
+        {{42644, 42645}},
+        {{42646, 42647}},
+        {{42648, 42649}},  // NOLINT
+        {{42650, 42651}},
+        {{42786, 42787}},
+        {{42788, 42789}},
+        {{42790, 42791}},  // NOLINT
+        {{42792, 42793}},
+        {{42794, 42795}},
+        {{42796, 42797}},
+        {{42798, 42799}},  // NOLINT
+        {{42802, 42803}},
+        {{42804, 42805}},
+        {{42806, 42807}},
+        {{42808, 42809}},  // NOLINT
+        {{42810, 42811}},
+        {{42812, 42813}},
+        {{42814, 42815}},
+        {{42816, 42817}},  // NOLINT
+        {{42818, 42819}},
+        {{42820, 42821}},
+        {{42822, 42823}},
+        {{42824, 42825}},  // NOLINT
+        {{42826, 42827}},
+        {{42828, 42829}},
+        {{42830, 42831}},
+        {{42832, 42833}},  // NOLINT
+        {{42834, 42835}},
+        {{42836, 42837}},
+        {{42838, 42839}},
+        {{42840, 42841}},  // NOLINT
+        {{42842, 42843}},
+        {{42844, 42845}},
+        {{42846, 42847}},
+        {{42848, 42849}},  // NOLINT
+        {{42850, 42851}},
+        {{42852, 42853}},
+        {{42854, 42855}},
+        {{42856, 42857}},  // NOLINT
+        {{42858, 42859}},
+        {{42860, 42861}},
+        {{42862, 42863}},
+        {{42873, 42874}},  // NOLINT
+        {{42875, 42876}},
+        {{7545, 42877}},
+        {{42878, 42879}},
+        {{42880, 42881}},  // NOLINT
+        {{42882, 42883}},
+        {{42884, 42885}},
+        {{42886, 42887}},
+        {{42891, 42892}},  // NOLINT
+        {{613, 42893}},
+        {{42896, 42897}},
+        {{42898, 42899}},
+        {{42902, 42903}},  // NOLINT
+        {{42904, 42905}},
+        {{42906, 42907}},
+        {{42908, 42909}},
+        {{42910, 42911}},  // NOLINT
+        {{42912, 42913}},
+        {{42914, 42915}},
+        {{42916, 42917}},
+        {{42918, 42919}},  // NOLINT
+        {{42920, 42921}},
+        {{614, 42922}},
+        {{604, 42923}},
+        {{609, 42924}},  // NOLINT
+        {{620, 42925}},
+        {{670, 42928}},
+        {{647, 42929}},
+        {{kSentinel}}};                                        // NOLINT
+static const uint16_t kEcma262UnCanonicalizeTable5Size = 198;  // NOLINT
+static const int32_t kEcma262UnCanonicalizeTable5
+    [396] = {1600, 1,   1601, 1,   1602, 5,   1603, 5,
+             1604, 9,   1605, 9,   1606, 13,  1607, 13,  // NOLINT
+             1608, 17,  1609, 17,  1610, 21,  1611, 21,
+             1612, 25,  1613, 25,  1614, 29,  1615, 29,  // NOLINT
+             1616, 33,  1617, 33,  1618, 37,  1619, 37,
+             1620, 41,  1621, 41,  1622, 45,  1623, 45,  // NOLINT
+             1624, 49,  1625, 49,  1626, 53,  1627, 53,
+             1628, 57,  1629, 57,  1630, 61,  1631, 61,  // NOLINT
+             1632, 65,  1633, 65,  1634, 69,  1635, 69,
+             1636, 73,  1637, 73,  1638, 77,  1639, 77,  // NOLINT
+             1640, 81,  1641, 81,  1642, 85,  1643, 85,
+             1644, 89,  1645, 89,  1664, 93,  1665, 93,  // NOLINT
+             1666, 97,  1667, 97,  1668, 101, 1669, 101,
+             1670, 105, 1671, 105, 1672, 109, 1673, 109,  // NOLINT
+             1674, 113, 1675, 113, 1676, 117, 1677, 117,
+             1678, 121, 1679, 121, 1680, 125, 1681, 125,  // NOLINT
+             1682, 129, 1683, 129, 1684, 133, 1685, 133,
+             1686, 137, 1687, 137, 1688, 141, 1689, 141,  // NOLINT
+             1690, 145, 1691, 145, 1826, 149, 1827, 149,
+             1828, 153, 1829, 153, 1830, 157, 1831, 157,  // NOLINT
+             1832, 161, 1833, 161, 1834, 165, 1835, 165,
+             1836, 169, 1837, 169, 1838, 173, 1839, 173,  // NOLINT
+             1842, 177, 1843, 177, 1844, 181, 1845, 181,
+             1846, 185, 1847, 185, 1848, 189, 1849, 189,  // NOLINT
+             1850, 193, 1851, 193, 1852, 197, 1853, 197,
+             1854, 201, 1855, 201, 1856, 205, 1857, 205,  // NOLINT
+             1858, 209, 1859, 209, 1860, 213, 1861, 213,
+             1862, 217, 1863, 217, 1864, 221, 1865, 221,  // NOLINT
+             1866, 225, 1867, 225, 1868, 229, 1869, 229,
+             1870, 233, 1871, 233, 1872, 237, 1873, 237,  // NOLINT
+             1874, 241, 1875, 241, 1876, 245, 1877, 245,
+             1878, 249, 1879, 249, 1880, 253, 1881, 253,  // NOLINT
+             1882, 257, 1883, 257, 1884, 261, 1885, 261,
+             1886, 265, 1887, 265, 1888, 269, 1889, 269,  // NOLINT
+             1890, 273, 1891, 273, 1892, 277, 1893, 277,
+             1894, 281, 1895, 281, 1896, 285, 1897, 285,  // NOLINT
+             1898, 289, 1899, 289, 1900, 293, 1901, 293,
+             1902, 297, 1903, 297, 1913, 301, 1914, 301,  // NOLINT
+             1915, 305, 1916, 305, 1917, 309, 1918, 313,
+             1919, 313, 1920, 317, 1921, 317, 1922, 321,  // NOLINT
+             1923, 321, 1924, 325, 1925, 325, 1926, 329,
+             1927, 329, 1931, 333, 1932, 333, 1933, 337,  // NOLINT
+             1936, 341, 1937, 341, 1938, 345, 1939, 345,
+             1942, 349, 1943, 349, 1944, 353, 1945, 353,  // NOLINT
+             1946, 357, 1947, 357, 1948, 361, 1949, 361,
+             1950, 365, 1951, 365, 1952, 369, 1953, 369,  // NOLINT
+             1954, 373, 1955, 373, 1956, 377, 1957, 377,
+             1958, 381, 1959, 381, 1960, 385, 1961, 385,  // NOLINT
+             1962, 389, 1963, 393, 1964, 397, 1965, 401,
+             1968, 405, 1969, 409};                                   // NOLINT
+static const uint16_t kEcma262UnCanonicalizeMultiStrings5Size = 104;  // NOLINT
 static const MultiCharacterSpecialCase<2> kEcma262UnCanonicalizeMultiStrings7[3] = {  // NOLINT
   {{65313, 65345}}, {{65338, 65370}}, {{kSentinel}} }; // NOLINT
 static const uint16_t kEcma262UnCanonicalizeTable7Size = 4;  // NOLINT
@@ -1772,55 +3301,96 @@
 const uchar UnicodeData::kMaxCodePoint = 65533;
 
 int UnicodeData::GetByteCount() {
-  return kUppercaseTable0Size * sizeof(int32_t)  // NOLINT
-      + kUppercaseTable1Size * sizeof(int32_t)  // NOLINT
-      + kUppercaseTable5Size * sizeof(int32_t)  // NOLINT
-      + kUppercaseTable7Size * sizeof(int32_t)  // NOLINT
-      + kLowercaseTable0Size * sizeof(int32_t)  // NOLINT
-      + kLowercaseTable1Size * sizeof(int32_t)  // NOLINT
-      + kLowercaseTable5Size * sizeof(int32_t)  // NOLINT
-      + kLowercaseTable7Size * sizeof(int32_t)  // NOLINT
-      + kLetterTable0Size * sizeof(int32_t)  // NOLINT
-      + kLetterTable1Size * sizeof(int32_t)  // NOLINT
-      + kLetterTable2Size * sizeof(int32_t)  // NOLINT
-      + kLetterTable3Size * sizeof(int32_t)  // NOLINT
-      + kLetterTable4Size * sizeof(int32_t)  // NOLINT
-      + kLetterTable5Size * sizeof(int32_t)  // NOLINT
-      + kLetterTable6Size * sizeof(int32_t)  // NOLINT
-      + kLetterTable7Size * sizeof(int32_t)  // NOLINT
-      + kNumberTable0Size * sizeof(int32_t)  // NOLINT
-      + kNumberTable5Size * sizeof(int32_t)  // NOLINT
-      + kNumberTable7Size * sizeof(int32_t)  // NOLINT
-      + kWhiteSpaceTable0Size * sizeof(int32_t)  // NOLINT
-      + kWhiteSpaceTable1Size * sizeof(int32_t)  // NOLINT
-      + kLineTerminatorTable0Size * sizeof(int32_t)  // NOLINT
-      + kLineTerminatorTable1Size * sizeof(int32_t)  // NOLINT
-      + kCombiningMarkTable0Size * sizeof(int32_t)  // NOLINT
-      + kCombiningMarkTable1Size * sizeof(int32_t)  // NOLINT
-      + kCombiningMarkTable5Size * sizeof(int32_t)  // NOLINT
-      + kCombiningMarkTable7Size * sizeof(int32_t)  // NOLINT
-      + kConnectorPunctuationTable0Size * sizeof(int32_t)  // NOLINT
-      + kConnectorPunctuationTable1Size * sizeof(int32_t)  // NOLINT
-      + kConnectorPunctuationTable7Size * sizeof(int32_t)  // NOLINT
-      + kToLowercaseMultiStrings0Size * sizeof(MultiCharacterSpecialCase<2>)  // NOLINT
-      + kToLowercaseMultiStrings1Size * sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
-      + kToLowercaseMultiStrings5Size * sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
-      + kToLowercaseMultiStrings7Size * sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
-      + kToUppercaseMultiStrings0Size * sizeof(MultiCharacterSpecialCase<3>)  // NOLINT
-      + kToUppercaseMultiStrings1Size * sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
-      + kToUppercaseMultiStrings5Size * sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
-      + kToUppercaseMultiStrings7Size * sizeof(MultiCharacterSpecialCase<3>)  // NOLINT
-      + kEcma262CanonicalizeMultiStrings0Size * sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
-      + kEcma262CanonicalizeMultiStrings1Size * sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
-      + kEcma262CanonicalizeMultiStrings5Size * sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
-      + kEcma262CanonicalizeMultiStrings7Size * sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
-      + kEcma262UnCanonicalizeMultiStrings0Size * sizeof(MultiCharacterSpecialCase<4>)  // NOLINT
-      + kEcma262UnCanonicalizeMultiStrings1Size * sizeof(MultiCharacterSpecialCase<2>)  // NOLINT
-      + kEcma262UnCanonicalizeMultiStrings5Size * sizeof(MultiCharacterSpecialCase<2>)  // NOLINT
-      + kEcma262UnCanonicalizeMultiStrings7Size * sizeof(MultiCharacterSpecialCase<2>)  // NOLINT
-      + kCanonicalizationRangeMultiStrings0Size * sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
-      + kCanonicalizationRangeMultiStrings1Size * sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
-      + kCanonicalizationRangeMultiStrings7Size * sizeof(MultiCharacterSpecialCase<1>); // NOLINT
+  return kUppercaseTable0Size * sizeof(int32_t)         // NOLINT
+         + kUppercaseTable1Size * sizeof(int32_t)       // NOLINT
+         + kUppercaseTable5Size * sizeof(int32_t)       // NOLINT
+         + kUppercaseTable7Size * sizeof(int32_t)       // NOLINT
+         + kLowercaseTable0Size * sizeof(int32_t)       // NOLINT
+         + kLowercaseTable1Size * sizeof(int32_t)       // NOLINT
+         + kLowercaseTable5Size * sizeof(int32_t)       // NOLINT
+         + kLowercaseTable7Size * sizeof(int32_t)       // NOLINT
+         + kLetterTable0Size * sizeof(int32_t)          // NOLINT
+         + kLetterTable1Size * sizeof(int32_t)          // NOLINT
+         + kLetterTable2Size * sizeof(int32_t)          // NOLINT
+         + kLetterTable3Size * sizeof(int32_t)          // NOLINT
+         + kLetterTable4Size * sizeof(int32_t)          // NOLINT
+         + kLetterTable5Size * sizeof(int32_t)          // NOLINT
+         + kLetterTable6Size * sizeof(int32_t)          // NOLINT
+         + kLetterTable7Size * sizeof(int32_t)          // NOLINT
+         + kID_StartTable0Size * sizeof(int32_t)        // NOLINT
+         + kID_StartTable1Size * sizeof(int32_t)        // NOLINT
+         + kID_StartTable2Size * sizeof(int32_t)        // NOLINT
+         + kID_StartTable3Size * sizeof(int32_t)        // NOLINT
+         + kID_StartTable4Size * sizeof(int32_t)        // NOLINT
+         + kID_StartTable5Size * sizeof(int32_t)        // NOLINT
+         + kID_StartTable6Size * sizeof(int32_t)        // NOLINT
+         + kID_StartTable7Size * sizeof(int32_t)        // NOLINT
+         + kID_ContinueTable0Size * sizeof(int32_t)     // NOLINT
+         + kID_ContinueTable1Size * sizeof(int32_t)     // NOLINT
+         + kID_ContinueTable5Size * sizeof(int32_t)     // NOLINT
+         + kID_ContinueTable7Size * sizeof(int32_t)     // NOLINT
+         + kWhiteSpaceTable0Size * sizeof(int32_t)      // NOLINT
+         + kWhiteSpaceTable1Size * sizeof(int32_t)      // NOLINT
+         + kWhiteSpaceTable7Size * sizeof(int32_t)      // NOLINT
+         + kLineTerminatorTable0Size * sizeof(int32_t)  // NOLINT
+         + kLineTerminatorTable1Size * sizeof(int32_t)  // NOLINT
+         +
+         kToLowercaseMultiStrings0Size *
+             sizeof(MultiCharacterSpecialCase<2>)  // NOLINT
+         +
+         kToLowercaseMultiStrings1Size *
+             sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
+         +
+         kToLowercaseMultiStrings5Size *
+             sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
+         +
+         kToLowercaseMultiStrings7Size *
+             sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
+         +
+         kToUppercaseMultiStrings0Size *
+             sizeof(MultiCharacterSpecialCase<3>)  // NOLINT
+         +
+         kToUppercaseMultiStrings1Size *
+             sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
+         +
+         kToUppercaseMultiStrings5Size *
+             sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
+         +
+         kToUppercaseMultiStrings7Size *
+             sizeof(MultiCharacterSpecialCase<3>)  // NOLINT
+         +
+         kEcma262CanonicalizeMultiStrings0Size *
+             sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
+         +
+         kEcma262CanonicalizeMultiStrings1Size *
+             sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
+         +
+         kEcma262CanonicalizeMultiStrings5Size *
+             sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
+         +
+         kEcma262CanonicalizeMultiStrings7Size *
+             sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
+         +
+         kEcma262UnCanonicalizeMultiStrings0Size *
+             sizeof(MultiCharacterSpecialCase<4>)  // NOLINT
+         +
+         kEcma262UnCanonicalizeMultiStrings1Size *
+             sizeof(MultiCharacterSpecialCase<2>)  // NOLINT
+         +
+         kEcma262UnCanonicalizeMultiStrings5Size *
+             sizeof(MultiCharacterSpecialCase<2>)  // NOLINT
+         +
+         kEcma262UnCanonicalizeMultiStrings7Size *
+             sizeof(MultiCharacterSpecialCase<2>)  // NOLINT
+         +
+         kCanonicalizationRangeMultiStrings0Size *
+             sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
+         +
+         kCanonicalizationRangeMultiStrings1Size *
+             sizeof(MultiCharacterSpecialCase<1>)  // NOLINT
+         +
+         kCanonicalizationRangeMultiStrings7Size *
+             sizeof(MultiCharacterSpecialCase<1>);  // NOLINT
 }
 
-}  // namespace unicode
+}  // namespace unibrow
diff --git a/src/unicode.h b/src/unicode.h
index e2d6b96..1666814 100644
--- a/src/unicode.h
+++ b/src/unicode.h
@@ -7,6 +7,7 @@
 
 #include <sys/types.h>
 #include "src/globals.h"
+#include "src/utils.h"
 /**
  * \file
  * Definitions and convenience functions for working with unicode.
@@ -28,22 +29,33 @@
  public:
   inline Predicate() { }
   inline bool get(uchar c);
+
  private:
   friend class Test;
   bool CalculateValue(uchar c);
-  struct CacheEntry {
-    inline CacheEntry() : code_point_(0), value_(0) { }
+  class CacheEntry {
+   public:
+    inline CacheEntry()
+        : bit_field_(CodePointField::encode(0) | ValueField::encode(0)) {}
     inline CacheEntry(uchar code_point, bool value)
-      : code_point_(code_point),
-        value_(value) { }
-    uchar code_point_ : 21;
-    bool value_ : 1;
+        : bit_field_(CodePointField::encode(code_point) |
+                     ValueField::encode(value)) {}
+
+    uchar code_point() const { return CodePointField::decode(bit_field_); }
+    bool value() const { return ValueField::decode(bit_field_); }
+
+   private:
+    class CodePointField : public v8::internal::BitField<uchar, 0, 21> {};
+    class ValueField : public v8::internal::BitField<bool, 21, 1> {};
+
+    uint32_t bit_field_;
   };
   static const int kSize = size;
   static const int kMask = kSize - 1;
   CacheEntry entries_[kSize];
 };
 
+
 // A cache used in case conversion.  It caches the value for characters
 // that either have no mapping or map to a single character independent
 // of context.  Characters that map to more than one character or that
@@ -70,6 +82,7 @@
   CacheEntry entries_[kSize];
 };
 
+
 class UnicodeData {
  private:
   friend class Test;
@@ -77,6 +90,7 @@
   static const uchar kMaxCodePoint;
 };
 
+
 class Utf16 {
  public:
   static inline bool IsSurrogatePair(int lead, int trail) {
@@ -113,14 +127,6 @@
   }
 };
 
-class Latin1 {
- public:
-  static const unsigned kMaxChar = 0xff;
-  // Returns 0 if character does not convert to single latin-1 character
-  // or if the character doesn't not convert back to latin-1 via inverse
-  // operation (upper to lower, etc).
-  static inline uint16_t ConvertNonLatin1ToLatin1(uint16_t);
-};
 
 class Utf8 {
  public:
@@ -155,45 +161,6 @@
                               unsigned* cursor);
 };
 
-
-class Utf8DecoderBase {
- public:
-  // Initialization done in subclass.
-  inline Utf8DecoderBase();
-  inline Utf8DecoderBase(uint16_t* buffer,
-                         unsigned buffer_length,
-                         const uint8_t* stream,
-                         unsigned stream_length);
-  inline unsigned Utf16Length() const { return utf16_length_; }
- protected:
-  // This reads all characters and sets the utf16_length_.
-  // The first buffer_length utf16 chars are cached in the buffer.
-  void Reset(uint16_t* buffer,
-             unsigned buffer_length,
-             const uint8_t* stream,
-             unsigned stream_length);
-  static void WriteUtf16Slow(const uint8_t* stream,
-                             uint16_t* data,
-                             unsigned length);
-  const uint8_t* unbuffered_start_;
-  unsigned utf16_length_;
-  bool last_byte_of_buffer_unused_;
- private:
-  DISALLOW_COPY_AND_ASSIGN(Utf8DecoderBase);
-};
-
-template <unsigned kBufferSize>
-class Utf8Decoder : public Utf8DecoderBase {
- public:
-  inline Utf8Decoder() {}
-  inline Utf8Decoder(const char* stream, unsigned length);
-  inline void Reset(const char* stream, unsigned length);
-  inline unsigned WriteUtf16(uint16_t* data, unsigned length) const;
- private:
-  uint16_t buffer_[kBufferSize];
-};
-
-
 struct Uppercase {
   static bool Is(uchar c);
 };
@@ -203,7 +170,10 @@
 struct Letter {
   static bool Is(uchar c);
 };
-struct Number {
+struct ID_Start {
+  static bool Is(uchar c);
+};
+struct ID_Continue {
   static bool Is(uchar c);
 };
 struct WhiteSpace {
@@ -212,12 +182,6 @@
 struct LineTerminator {
   static bool Is(uchar c);
 };
-struct CombiningMark {
-  static bool Is(uchar c);
-};
-struct ConnectorPunctuation {
-  static bool Is(uchar c);
-};
 struct ToLowercase {
   static const int kMaxWidth = 3;
   static const bool kIsToLower = true;
diff --git a/src/unique.h b/src/unique.h
index 619c3c9..321eb36 100644
--- a/src/unique.h
+++ b/src/unique.h
@@ -5,9 +5,11 @@
 #ifndef V8_HYDROGEN_UNIQUE_H_
 #define V8_HYDROGEN_UNIQUE_H_
 
+#include <ostream>  // NOLINT(readability/streams)
+
+#include "src/base/functional.h"
 #include "src/handles-inl.h"  // TODO(everyone): Fix our inl.h crap
 #include "src/objects-inl.h"  // TODO(everyone): Fix our inl.h crap
-#include "src/string-stream.h"
 #include "src/utils.h"
 #include "src/zone.h"
 
@@ -81,6 +83,11 @@
     return raw_address_ != other.raw_address_;
   }
 
+  friend inline size_t hash_value(Unique<T> const& unique) {
+    DCHECK(unique.IsInitialized());
+    return base::hash<void*>()(unique.raw_address_);
+  }
+
   inline intptr_t Hashcode() const {
     DCHECK(IsInitialized());
     return reinterpret_cast<intptr_t>(raw_address_);
@@ -110,7 +117,7 @@
 
   // TODO(titzer): this is a hack to migrate to Unique<T> incrementally.
   static Unique<T> CreateUninitialized(Handle<T> handle) {
-    return Unique<T>(reinterpret_cast<Address>(NULL), handle);
+    return Unique<T>(NULL, handle);
   }
 
   static Unique<T> CreateImmovable(Handle<T> handle) {
@@ -128,6 +135,11 @@
   friend class SideEffectsTracker;
 };
 
+template <typename T>
+inline std::ostream& operator<<(std::ostream& os, Unique<T> uniq) {
+  return os << Brief(*uniq.handle());
+}
+
 
 template <typename T>
 class UniqueSet FINAL : public ZoneObject {
diff --git a/src/uri.h b/src/uri.h
deleted file mode 100644
index 75f2605..0000000
--- a/src/uri.h
+++ /dev/null
@@ -1,290 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_URI_H_
-#define V8_URI_H_
-
-#include "src/v8.h"
-
-#include "src/conversions.h"
-#include "src/string-search.h"
-#include "src/utils.h"
-
-namespace v8 {
-namespace internal {
-
-
-template <typename Char>
-static INLINE(Vector<const Char> GetCharVector(Handle<String> string));
-
-
-template <>
-Vector<const uint8_t> GetCharVector(Handle<String> string) {
-  String::FlatContent flat = string->GetFlatContent();
-  DCHECK(flat.IsOneByte());
-  return flat.ToOneByteVector();
-}
-
-
-template <>
-Vector<const uc16> GetCharVector(Handle<String> string) {
-  String::FlatContent flat = string->GetFlatContent();
-  DCHECK(flat.IsTwoByte());
-  return flat.ToUC16Vector();
-}
-
-
-class URIUnescape : public AllStatic {
- public:
-  template<typename Char>
-  MUST_USE_RESULT static MaybeHandle<String> Unescape(Isolate* isolate,
-                                                      Handle<String> source);
-
- private:
-  static const signed char kHexValue['g'];
-
-  template<typename Char>
-  MUST_USE_RESULT static MaybeHandle<String> UnescapeSlow(
-      Isolate* isolate, Handle<String> string, int start_index);
-
-  static INLINE(int TwoDigitHex(uint16_t character1, uint16_t character2));
-
-  template <typename Char>
-  static INLINE(int UnescapeChar(Vector<const Char> vector,
-                                 int i,
-                                 int length,
-                                 int* step));
-};
-
-
-const signed char URIUnescape::kHexValue[] = {
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
-    -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, 10, 11, 12, 13, 14, 15 };
-
-
-template<typename Char>
-MaybeHandle<String> URIUnescape::Unescape(Isolate* isolate,
-                                          Handle<String> source) {
-  int index;
-  { DisallowHeapAllocation no_allocation;
-    StringSearch<uint8_t, Char> search(isolate, STATIC_CHAR_VECTOR("%"));
-    index = search.Search(GetCharVector<Char>(source), 0);
-    if (index < 0) return source;
-  }
-  return UnescapeSlow<Char>(isolate, source, index);
-}
-
-
-template <typename Char>
-MaybeHandle<String> URIUnescape::UnescapeSlow(
-    Isolate* isolate, Handle<String> string, int start_index) {
-  bool one_byte = true;
-  int length = string->length();
-
-  int unescaped_length = 0;
-  { DisallowHeapAllocation no_allocation;
-    Vector<const Char> vector = GetCharVector<Char>(string);
-    for (int i = start_index; i < length; unescaped_length++) {
-      int step;
-      if (UnescapeChar(vector, i, length, &step) >
-              String::kMaxOneByteCharCode) {
-        one_byte = false;
-      }
-      i += step;
-    }
-  }
-
-  DCHECK(start_index < length);
-  Handle<String> first_part =
-      isolate->factory()->NewProperSubString(string, 0, start_index);
-
-  int dest_position = 0;
-  Handle<String> second_part;
-  DCHECK(unescaped_length <= String::kMaxLength);
-  if (one_byte) {
-    Handle<SeqOneByteString> dest = isolate->factory()->NewRawOneByteString(
-        unescaped_length).ToHandleChecked();
-    DisallowHeapAllocation no_allocation;
-    Vector<const Char> vector = GetCharVector<Char>(string);
-    for (int i = start_index; i < length; dest_position++) {
-      int step;
-      dest->SeqOneByteStringSet(dest_position,
-                                UnescapeChar(vector, i, length, &step));
-      i += step;
-    }
-    second_part = dest;
-  } else {
-    Handle<SeqTwoByteString> dest = isolate->factory()->NewRawTwoByteString(
-        unescaped_length).ToHandleChecked();
-    DisallowHeapAllocation no_allocation;
-    Vector<const Char> vector = GetCharVector<Char>(string);
-    for (int i = start_index; i < length; dest_position++) {
-      int step;
-      dest->SeqTwoByteStringSet(dest_position,
-                                UnescapeChar(vector, i, length, &step));
-      i += step;
-    }
-    second_part = dest;
-  }
-  return isolate->factory()->NewConsString(first_part, second_part);
-}
-
-
-int URIUnescape::TwoDigitHex(uint16_t character1, uint16_t character2) {
-  if (character1 > 'f') return -1;
-  int hi = kHexValue[character1];
-  if (hi == -1) return -1;
-  if (character2 > 'f') return -1;
-  int lo = kHexValue[character2];
-  if (lo == -1) return -1;
-  return (hi << 4) + lo;
-}
-
-
-template <typename Char>
-int URIUnescape::UnescapeChar(Vector<const Char> vector,
-                              int i,
-                              int length,
-                              int* step) {
-  uint16_t character = vector[i];
-  int32_t hi = 0;
-  int32_t lo = 0;
-  if (character == '%' &&
-      i <= length - 6 &&
-      vector[i + 1] == 'u' &&
-      (hi = TwoDigitHex(vector[i + 2],
-                        vector[i + 3])) != -1 &&
-      (lo = TwoDigitHex(vector[i + 4],
-                        vector[i + 5])) != -1) {
-    *step = 6;
-    return (hi << 8) + lo;
-  } else if (character == '%' &&
-      i <= length - 3 &&
-      (lo = TwoDigitHex(vector[i + 1],
-                        vector[i + 2])) != -1) {
-    *step = 3;
-    return lo;
-  } else {
-    *step = 1;
-    return character;
-  }
-}
-
-
-class URIEscape : public AllStatic {
- public:
-  template<typename Char>
-  MUST_USE_RESULT static MaybeHandle<String> Escape(Isolate* isolate,
-                                                    Handle<String> string);
-
- private:
-  static const char kHexChars[17];
-  static const char kNotEscaped[256];
-
-  static bool IsNotEscaped(uint16_t c) { return kNotEscaped[c] != 0; }
-};
-
-
-const char URIEscape::kHexChars[] = "0123456789ABCDEF";
-
-
-// kNotEscaped is generated by the following:
-//
-// #!/bin/perl
-// for (my $i = 0; $i < 256; $i++) {
-//   print "\n" if $i % 16 == 0;
-//   my $c = chr($i);
-//   my $escaped = 1;
-//   $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
-//   print $escaped ? "0, " : "1, ";
-// }
-
-const char URIEscape::kNotEscaped[] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
-    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
-
-template<typename Char>
-MaybeHandle<String> URIEscape::Escape(Isolate* isolate, Handle<String> string) {
-  DCHECK(string->IsFlat());
-  int escaped_length = 0;
-  int length = string->length();
-
-  { DisallowHeapAllocation no_allocation;
-    Vector<const Char> vector = GetCharVector<Char>(string);
-    for (int i = 0; i < length; i++) {
-      uint16_t c = vector[i];
-      if (c >= 256) {
-        escaped_length += 6;
-      } else if (IsNotEscaped(c)) {
-        escaped_length++;
-      } else {
-        escaped_length += 3;
-      }
-
-      // We don't allow strings that are longer than a maximal length.
-      DCHECK(String::kMaxLength < 0x7fffffff - 6);  // Cannot overflow.
-      if (escaped_length > String::kMaxLength) break;  // Provoke exception.
-    }
-  }
-
-  // No length change implies no change.  Return original string if no change.
-  if (escaped_length == length) return string;
-
-  Handle<SeqOneByteString> dest;
-  ASSIGN_RETURN_ON_EXCEPTION(
-      isolate, dest,
-      isolate->factory()->NewRawOneByteString(escaped_length),
-      String);
-  int dest_position = 0;
-
-  { DisallowHeapAllocation no_allocation;
-    Vector<const Char> vector = GetCharVector<Char>(string);
-    for (int i = 0; i < length; i++) {
-      uint16_t c = vector[i];
-      if (c >= 256) {
-        dest->SeqOneByteStringSet(dest_position, '%');
-        dest->SeqOneByteStringSet(dest_position+1, 'u');
-        dest->SeqOneByteStringSet(dest_position+2, kHexChars[c >> 12]);
-        dest->SeqOneByteStringSet(dest_position+3, kHexChars[(c >> 8) & 0xf]);
-        dest->SeqOneByteStringSet(dest_position+4, kHexChars[(c >> 4) & 0xf]);
-        dest->SeqOneByteStringSet(dest_position+5, kHexChars[c & 0xf]);
-        dest_position += 6;
-      } else if (IsNotEscaped(c)) {
-        dest->SeqOneByteStringSet(dest_position, c);
-        dest_position++;
-      } else {
-        dest->SeqOneByteStringSet(dest_position, '%');
-        dest->SeqOneByteStringSet(dest_position+1, kHexChars[c >> 4]);
-        dest->SeqOneByteStringSet(dest_position+2, kHexChars[c & 0xf]);
-        dest_position += 3;
-      }
-    }
-  }
-
-  return dest;
-}
-
-} }  // namespace v8::internal
-
-#endif  // V8_URI_H_
diff --git a/src/utils.cc b/src/utils.cc
index 165855a..40c8b40 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -7,6 +7,7 @@
 
 #include "src/v8.h"
 
+#include "src/base/functional.h"
 #include "src/base/logging.h"
 #include "src/base/platform/platform.h"
 #include "src/utils.h"
@@ -77,6 +78,17 @@
 }
 
 
+size_t hash_value(BailoutId id) {
+  base::hash<int> h;
+  return h(id.id_);
+}
+
+
+std::ostream& operator<<(std::ostream& os, BailoutId id) {
+  return os << id.id_;
+}
+
+
 void PrintF(const char* format, ...) {
   va_list arguments;
   va_start(arguments, format);
diff --git a/src/utils.h b/src/utils.h
index 2991815..525c6f8 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -61,7 +61,6 @@
   }
   DCHECK_EQ(1 << bits, original_x);
   return bits;
-  return 0;
 }
 
 
@@ -157,7 +156,7 @@
 
 // Floor(-0.0) == 0.0
 inline double Floor(double x) {
-#ifdef _MSC_VER
+#if V8_CC_MSVC
   if (x == 0) return x;  // Fix for issue 3477.
 #endif
   return std::floor(x);
@@ -231,6 +230,14 @@
 };
 
 
+template <class T, int shift, int size>
+class BitField8 : public BitFieldBase<T, shift, size, uint8_t> {};
+
+
+template <class T, int shift, int size>
+class BitField16 : public BitFieldBase<T, shift, size, uint16_t> {};
+
+
 template<class T, int shift, int size>
 class BitField : public BitFieldBase<T, shift, size, uint32_t> { };
 
@@ -240,6 +247,46 @@
 
 
 // ----------------------------------------------------------------------------
+// BitSetComputer is a help template for encoding and decoding information for
+// a variable number of items in an array.
+//
+// To encode boolean data in a smi array you would use:
+// typedef BitSetComputer<bool, 1, kSmiValueSize, uint32_t> BoolComputer;
+//
+template <class T, int kBitsPerItem, int kBitsPerWord, class U>
+class BitSetComputer {
+ public:
+  static const int kItemsPerWord = kBitsPerWord / kBitsPerItem;
+  static const int kMask = (1 << kBitsPerItem) - 1;
+
+  // The number of array elements required to embed T information for each item.
+  static int word_count(int items) {
+    if (items == 0) return 0;
+    return (items - 1) / kItemsPerWord + 1;
+  }
+
+  // The array index to look at for item.
+  static int index(int base_index, int item) {
+    return base_index + item / kItemsPerWord;
+  }
+
+  // Extract T data for a given item from data.
+  static T decode(U data, int item) {
+    return static_cast<T>((data >> shift(item)) & kMask);
+  }
+
+  // Return the encoding for a store of value for item in previous.
+  static U encode(U previous, int item, T value) {
+    int shift_value = shift(item);
+    int set_bits = (static_cast<int>(value) << shift_value);
+    return (previous & ~(kMask << shift_value)) | set_bits;
+  }
+
+  static int shift(int item) { return (item % kItemsPerWord) * kBitsPerItem; }
+};
+
+
+// ----------------------------------------------------------------------------
 // Hash function.
 
 static const uint32_t kZeroHashSeed = 0;
@@ -816,7 +863,7 @@
   // compute the length of the input string.
   void AddString(const char* s);
 
-  // Add the first 'n' characters of the given string 's' to the
+  // Add the first 'n' characters of the given 0-terminated string 's' to the
   // builder. The input string must have enough characters.
   void AddSubstring(const char* s, int n);
 
@@ -952,6 +999,33 @@
 };
 
 
+template <int dummy_parameter>
+class VectorSlot {
+ public:
+  explicit VectorSlot(int id) : id_(id) {}
+  int ToInt() const { return id_; }
+
+  static VectorSlot Invalid() { return VectorSlot(kInvalidSlot); }
+  bool IsInvalid() const { return id_ == kInvalidSlot; }
+
+  VectorSlot next() const {
+    DCHECK(id_ != kInvalidSlot);
+    return VectorSlot(id_ + 1);
+  }
+
+  bool operator==(const VectorSlot& other) const { return id_ == other.id_; }
+
+ private:
+  static const int kInvalidSlot = -1;
+
+  int id_;
+};
+
+
+typedef VectorSlot<0> FeedbackVectorSlot;
+typedef VectorSlot<1> FeedbackVectorICSlot;
+
+
 class BailoutId {
  public:
   explicit BailoutId(int id) : id_(id) { }
@@ -966,6 +1040,8 @@
   bool IsNone() const { return id_ == kNoneId; }
   bool operator==(const BailoutId& other) const { return id_ == other.id_; }
   bool operator!=(const BailoutId& other) const { return id_ != other.id_; }
+  friend size_t hash_value(BailoutId);
+  friend std::ostream& operator<<(std::ostream&, BailoutId);
 
  private:
   static const int kNoneId = -1;
diff --git a/src/v8.cc b/src/v8.cc
index 62c3da4..b04ccc0 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -18,10 +18,12 @@
 #include "src/hydrogen.h"
 #include "src/isolate.h"
 #include "src/lithium-allocator.h"
+#include "src/natives.h"
 #include "src/objects.h"
 #include "src/runtime-profiler.h"
 #include "src/sampler.h"
 #include "src/serialize.h"
+#include "src/snapshot.h"
 
 
 namespace v8 {
@@ -29,6 +31,11 @@
 
 V8_DECLARE_ONCE(init_once);
 
+#ifdef V8_USE_EXTERNAL_STARTUP_DATA
+V8_DECLARE_ONCE(init_natives_once);
+V8_DECLARE_ONCE(init_snapshot_once);
+#endif
+
 v8::ArrayBuffer::Allocator* V8::array_buffer_allocator_ = NULL;
 v8::Platform* V8::platform_ = NULL;
 
@@ -117,4 +124,21 @@
   return platform_;
 }
 
+
+void V8::SetNativesBlob(StartupData* natives_blob) {
+#ifdef V8_USE_EXTERNAL_STARTUP_DATA
+  base::CallOnce(&init_natives_once, &SetNativesFromFile, natives_blob);
+#else
+  CHECK(false);
+#endif
+}
+
+
+void V8::SetSnapshotBlob(StartupData* snapshot_blob) {
+#ifdef V8_USE_EXTERNAL_STARTUP_DATA
+  base::CallOnce(&init_snapshot_once, &SetSnapshotFromFile, snapshot_blob);
+#else
+  CHECK(false);
+#endif
+}
 } }  // namespace v8::internal
diff --git a/src/v8.h b/src/v8.h
index 13c33e1..4267434 100644
--- a/src/v8.h
+++ b/src/v8.h
@@ -9,8 +9,8 @@
 #ifndef V8_V8_H_
 #define V8_V8_H_
 
-#if defined(GOOGLE3)
-// Google3 special flag handling.
+#if defined(GOOGLE3) || defined(DCHECK_ALWAYS_ON)
+// Google3 and Chromium special flag handling.
 #if defined(DEBUG) && defined(NDEBUG)
 // V8 only uses DEBUG and whenever it is set we are building a debug
 // version of V8. We do not use NDEBUG and simply undef it here for
@@ -82,6 +82,9 @@
   static void ShutdownPlatform();
   static v8::Platform* GetCurrentPlatform();
 
+  static void SetNativesBlob(StartupData* natives_blob);
+  static void SetSnapshotBlob(StartupData* snapshot_blob);
+
  private:
   static void InitializeOncePerProcessImpl();
   static void InitializeOncePerProcess();
diff --git a/src/v8natives.js b/src/v8natives.js
index 782b953..ac96f63 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -163,19 +163,9 @@
 function GlobalEval(x) {
   if (!IS_STRING(x)) return x;
 
-  // For consistency with JSC we require the global object passed to
-  // eval to be the global object from which 'eval' originated. This
-  // is not mandated by the spec.
-  // We only throw if the global has been detached, since we need the
-  // receiver as this-value for the call.
-  if (!%IsAttachedGlobal(global)) {
-    throw new $EvalError('The "this" value passed to eval must ' +
-                         'be the global object from which eval originated');
-  }
-
   var global_proxy = %GlobalProxy(global);
 
-  var f = %CompileString(x, false);
+  var f = %CompileString(x, false, 0);
   if (!IS_FUNCTION(f)) return f;
 
   return %_CallFunction(global_proxy, f);
@@ -215,8 +205,9 @@
 // ----------------------------------------------------------------------------
 // Object
 
+var DefaultObjectToString = NoSideEffectsObjectToString;
 // ECMA-262 - 15.2.4.2
-function ObjectToString() {
+function NoSideEffectsObjectToString() {
   if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
   if (IS_NULL(this)) return "[object Null]";
   return "[object " + %_ClassOf(ToObject(this)) + "]";
@@ -238,7 +229,7 @@
 
 // ECMA-262 - 15.2.4.5
 function ObjectHasOwnProperty(V) {
-  if (%IsJSProxy(this)) {
+  if (%_IsJSProxy(this)) {
     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
     if (IS_SYMBOL(V)) return false;
 
@@ -251,8 +242,8 @@
 
 // ECMA-262 - 15.2.4.6
 function ObjectIsPrototypeOf(V) {
-  CHECK_OBJECT_COERCIBLE(this, "Object.prototype.isPrototypeOf");
   if (!IS_SPEC_OBJECT(V)) return false;
+  CHECK_OBJECT_COERCIBLE(this, "Object.prototype.isPrototypeOf");
   return %IsInPrototypeChain(this, V);
 }
 
@@ -260,7 +251,7 @@
 // ECMA-262 - 15.2.4.6
 function ObjectPropertyIsEnumerable(V) {
   var P = ToName(V);
-  if (%IsJSProxy(this)) {
+  if (%_IsJSProxy(this)) {
     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
     if (IS_SYMBOL(V)) return false;
 
@@ -325,10 +316,8 @@
 
 
 function ObjectKeys(obj) {
-  if (!IS_SPEC_OBJECT(obj)) {
-    throw MakeTypeError("called_on_non_object", ["Object.keys"]);
-  }
-  if (%IsJSProxy(obj)) {
+  obj = ToObject(obj);
+  if (%_IsJSProxy(obj)) {
     var handler = %GetHandler(obj);
     var names = CallTrap0(handler, "keys", DerivedKeysTrap);
     return ToNameArray(names, "keys", false);
@@ -502,67 +491,68 @@
     "set_",
     "hasSetter_"
   ), $Array(
-    "toString", function() {
+    "toString", function PropertyDescriptor_ToString() {
       return "[object PropertyDescriptor]";
     },
-    "setValue", function(value) {
+    "setValue", function PropertyDescriptor_SetValue(value) {
       this.value_ = value;
       this.hasValue_ = true;
     },
-    "getValue", function() {
+    "getValue", function PropertyDescriptor_GetValue() {
       return this.value_;
     },
-    "hasValue", function() {
+    "hasValue", function PropertyDescriptor_HasValue() {
       return this.hasValue_;
     },
-    "setEnumerable", function(enumerable) {
+    "setEnumerable", function PropertyDescriptor_SetEnumerable(enumerable) {
       this.enumerable_ = enumerable;
         this.hasEnumerable_ = true;
     },
-    "isEnumerable", function () {
+    "isEnumerable", function PropertyDescriptor_IsEnumerable() {
       return this.enumerable_;
     },
-    "hasEnumerable", function() {
+    "hasEnumerable", function PropertyDescriptor_HasEnumerable() {
       return this.hasEnumerable_;
     },
-    "setWritable", function(writable) {
+    "setWritable", function PropertyDescriptor_SetWritable(writable) {
       this.writable_ = writable;
       this.hasWritable_ = true;
     },
-    "isWritable", function() {
+    "isWritable", function PropertyDescriptor_IsWritable() {
       return this.writable_;
     },
-    "hasWritable", function() {
+    "hasWritable", function PropertyDescriptor_HasWritable() {
       return this.hasWritable_;
     },
-    "setConfigurable", function(configurable) {
+    "setConfigurable",
+    function PropertyDescriptor_SetConfigurable(configurable) {
       this.configurable_ = configurable;
       this.hasConfigurable_ = true;
     },
-    "hasConfigurable", function() {
+    "hasConfigurable", function PropertyDescriptor_HasConfigurable() {
       return this.hasConfigurable_;
     },
-    "isConfigurable", function() {
+    "isConfigurable", function PropertyDescriptor_IsConfigurable() {
       return this.configurable_;
     },
-    "setGet", function(get) {
+    "setGet", function PropertyDescriptor_SetGetter(get) {
       this.get_ = get;
-        this.hasGetter_ = true;
+      this.hasGetter_ = true;
     },
-    "getGet", function() {
+    "getGet", function PropertyDescriptor_GetGetter() {
       return this.get_;
     },
-    "hasGetter", function() {
+    "hasGetter", function PropertyDescriptor_HasGetter() {
       return this.hasGetter_;
     },
-    "setSet", function(set) {
+    "setSet", function PropertyDescriptor_SetSetter(set) {
       this.set_ = set;
       this.hasSetter_ = true;
     },
-    "getSet", function() {
+    "getSet", function PropertyDescriptor_GetSetter() {
       return this.set_;
     },
-    "hasSetter", function() {
+    "hasSetter", function PropertyDescriptor_HasSetter() {
       return this.hasSetter_;
   }));
 
@@ -624,7 +614,7 @@
 // ES5 section 8.12.1.
 function GetOwnPropertyJS(obj, v) {
   var p = ToName(v);
-  if (%IsJSProxy(obj)) {
+  if (%_IsJSProxy(obj)) {
     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
     if (IS_SYMBOL(v)) return UNDEFINED;
 
@@ -897,15 +887,6 @@
         break;
       }
     }
-    // Make sure the below call to DefineObjectProperty() doesn't overwrite
-    // any magic "length" property by removing the value.
-    // TODO(mstarzinger): This hack should be removed once we have addressed the
-    // respective TODO in Runtime_DefineDataPropertyUnchecked.
-    // For the time being, we need a hack to prevent Object.observe from
-    // generating two change records.
-    obj.length = new_length;
-    desc.value_ = UNDEFINED;
-    desc.hasValue_ = false;
     threw = !DefineObjectProperty(obj, "length", desc, should_throw) || threw;
     if (emit_splice) {
       EndPerformSplice(obj);
@@ -964,7 +945,7 @@
 
 // ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
 function DefineOwnProperty(obj, p, desc, should_throw) {
-  if (%IsJSProxy(obj)) {
+  if (%_IsJSProxy(obj)) {
     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
     if (IS_SYMBOL(p)) return false;
 
@@ -983,7 +964,7 @@
   if (!IS_SPEC_OBJECT(obj)) {
     throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
   }
-  return %GetPrototype(obj);
+  return %_GetPrototype(obj);
 }
 
 // ES6 section 19.1.2.19.
@@ -1038,24 +1019,21 @@
 }
 
 
-function ObjectGetOwnPropertyKeys(obj, symbolsOnly) {
+function ObjectGetOwnPropertyKeys(obj, filter) {
   var nameArrays = new InternalArray();
-  var filter = symbolsOnly ?
-      PROPERTY_ATTRIBUTES_STRING | PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL :
-      PROPERTY_ATTRIBUTES_SYMBOLIC;
+  filter |= PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL;
+  var interceptorInfo = %GetInterceptorInfo(obj);
 
   // Find all the indexed properties.
 
   // Only get own element names if we want to include string keys.
-  if (!symbolsOnly) {
+  if ((filter & PROPERTY_ATTRIBUTES_STRING) === 0) {
     var ownElementNames = %GetOwnElementNames(obj);
     for (var i = 0; i < ownElementNames.length; ++i) {
       ownElementNames[i] = %_NumberToString(ownElementNames[i]);
     }
     nameArrays.push(ownElementNames);
-
     // Get names for indexed interceptor properties.
-    var interceptorInfo = %GetInterceptorInfo(obj);
     if ((interceptorInfo & 1) != 0) {
       var indexedInterceptorNames = %GetIndexedInterceptorElementNames(obj);
       if (!IS_UNDEFINED(indexedInterceptorNames)) {
@@ -1089,10 +1067,12 @@
     var j = 0;
     for (var i = 0; i < propertyNames.length; ++i) {
       var name = propertyNames[i];
-      if (symbolsOnly) {
-        if (!IS_SYMBOL(name) || IS_PRIVATE(name)) continue;
+      if (IS_SYMBOL(name)) {
+        if ((filter & PROPERTY_ATTRIBUTES_SYMBOLIC) || IS_PRIVATE(name)) {
+          continue;
+        }
       } else {
-        if (IS_SYMBOL(name)) continue;
+        if (filter & PROPERTY_ATTRIBUTES_STRING) continue;
         name = ToString(name);
       }
       if (seenKeys[name]) continue;
@@ -1108,17 +1088,15 @@
 
 // ES5 section 15.2.3.4.
 function ObjectGetOwnPropertyNames(obj) {
-  if (!IS_SPEC_OBJECT(obj)) {
-    throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
-  }
+  obj = ToObject(obj);
   // Special handling for proxies.
-  if (%IsJSProxy(obj)) {
+  if (%_IsJSProxy(obj)) {
     var handler = %GetHandler(obj);
     var names = CallTrap0(handler, "getOwnPropertyNames", UNDEFINED);
     return ToNameArray(names, "getOwnPropertyNames", false);
   }
 
-  return ObjectGetOwnPropertyKeys(obj, false);
+  return ObjectGetOwnPropertyKeys(obj, PROPERTY_ATTRIBUTES_SYMBOLIC);
 }
 
 
@@ -1140,7 +1118,7 @@
     throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
   }
   var name = ToName(p);
-  if (%IsJSProxy(obj)) {
+  if (%_IsJSProxy(obj)) {
     // Clone the attributes object for protection.
     // TODO(rossberg): not spec'ed yet, so not sure if this should involve
     // non-own properties as it does (or non-enumerable ones, as it doesn't?).
@@ -1245,23 +1223,30 @@
 
 
 // ES5 section 15.2.3.8.
-function ObjectSeal(obj) {
+function ObjectSealJS(obj) {
   if (!IS_SPEC_OBJECT(obj)) {
     throw MakeTypeError("called_on_non_object", ["Object.seal"]);
   }
-  if (%IsJSProxy(obj)) {
-    ProxyFix(obj);
-  }
-  var names = ObjectGetOwnPropertyNames(obj);
-  for (var i = 0; i < names.length; i++) {
-    var name = names[i];
-    var desc = GetOwnPropertyJS(obj, name);
-    if (desc.isConfigurable()) {
-      desc.setConfigurable(false);
-      DefineOwnProperty(obj, name, desc, true);
+  var isProxy = %_IsJSProxy(obj);
+  if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) {
+    if (isProxy) {
+      ProxyFix(obj);
     }
+    var names = ObjectGetOwnPropertyNames(obj);
+    for (var i = 0; i < names.length; i++) {
+      var name = names[i];
+      var desc = GetOwnPropertyJS(obj, name);
+      if (desc.isConfigurable()) {
+        desc.setConfigurable(false);
+        DefineOwnProperty(obj, name, desc, true);
+      }
+    }
+    %PreventExtensions(obj);
+  } else {
+    // TODO(adamk): Is it worth going to this fast path if the
+    // object's properties are already in dictionary mode?
+    %ObjectSeal(obj);
   }
-  %PreventExtensions(obj);
   return obj;
 }
 
@@ -1271,7 +1256,7 @@
   if (!IS_SPEC_OBJECT(obj)) {
     throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
   }
-  var isProxy = %IsJSProxy(obj);
+  var isProxy = %_IsJSProxy(obj);
   if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) {
     if (isProxy) {
       ProxyFix(obj);
@@ -1301,7 +1286,7 @@
   if (!IS_SPEC_OBJECT(obj)) {
     throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
   }
-  if (%IsJSProxy(obj)) {
+  if (%_IsJSProxy(obj)) {
     ProxyFix(obj);
   }
   %PreventExtensions(obj);
@@ -1314,7 +1299,7 @@
   if (!IS_SPEC_OBJECT(obj)) {
     throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
   }
-  if (%IsJSProxy(obj)) {
+  if (%_IsJSProxy(obj)) {
     return false;
   }
   if (%IsExtensible(obj)) {
@@ -1337,7 +1322,7 @@
   if (!IS_SPEC_OBJECT(obj)) {
     throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
   }
-  if (%IsJSProxy(obj)) {
+  if (%_IsJSProxy(obj)) {
     return false;
   }
   if (%IsExtensible(obj)) {
@@ -1359,26 +1344,22 @@
   if (!IS_SPEC_OBJECT(obj)) {
     throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
   }
-  if (%IsJSProxy(obj)) {
+  if (%_IsJSProxy(obj)) {
     return true;
   }
   return %IsExtensible(obj);
 }
 
 
-// Harmony egal.
+// ECMA-262, Edition 6, section 19.1.2.10
 function ObjectIs(obj1, obj2) {
-  if (obj1 === obj2) {
-    return (obj1 !== 0) || (1 / obj1 === 1 / obj2);
-  } else {
-    return (obj1 !== obj1) && (obj2 !== obj2);
-  }
+  return SameValue(obj1, obj2);
 }
 
 
 // ECMA-262, Edition 6, section B.2.2.1.1
 function ObjectGetProto() {
-  return %GetPrototype(ToObject(this));
+  return %_GetPrototype(ToObject(this));
 }
 
 
@@ -1416,7 +1397,7 @@
 
   // Set up non-enumerable functions on the Object.prototype object.
   InstallFunctions($Object.prototype, DONT_ENUM, $Array(
-    "toString", ObjectToString,
+    "toString", NoSideEffectsObjectToString,
     "toLocaleString", ObjectToLocaleString,
     "valueOf", ObjectValueOf,
     "hasOwnProperty", ObjectHasOwnProperty,
@@ -1447,7 +1428,7 @@
     "isFrozen", ObjectIsFrozen,
     "isSealed", ObjectIsSealed,
     "preventExtensions", ObjectPreventExtension,
-    "seal", ObjectSeal
+    "seal", ObjectSealJS
     // deliverChangeRecords, getNotifier, observe and unobserve are added
     // in object-observe.js.
   ));
@@ -1739,6 +1720,11 @@
     throw new $TypeError('Function.prototype.toString is not generic');
   }
 
+  var classSource = %ClassGetSourceCode(func);
+  if (IS_STRING(classSource)) {
+    return classSource;
+  }
+
   var source = %FunctionGetSourceCode(func);
   if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
     var name = %FunctionGetName(func);
@@ -1830,7 +1816,7 @@
 }
 
 
-function NewFunctionString(arguments, function_token) {
+function NewFunctionFromString(arguments, function_token) {
   var n = arguments.length;
   var p = '';
   if (n > 1) {
@@ -1847,21 +1833,20 @@
     // If the formal parameters include an unbalanced block comment, the
     // function must be rejected. Since JavaScript does not allow nested
     // comments we can include a trailing block comment to catch this.
-    p += '\n/' + '**/';
+    p += '\n\x2f**\x2f';
   }
   var body = (n > 0) ? ToString(arguments[n - 1]) : '';
-  return '(' + function_token + '(' + p + ') {\n' + body + '\n})';
+  var head = '(' + function_token + '(' + p + ') {\n';
+  var src = head + body + '\n})';
+  var global_proxy = %GlobalProxy(global);
+  var f = %_CallFunction(global_proxy, %CompileString(src, true, head.length));
+  %FunctionMarkNameShouldPrintAsAnonymous(f);
+  return f;
 }
 
 
 function FunctionConstructor(arg1) {  // length == 1
-  var source = NewFunctionString(arguments, 'function');
-  var global_proxy = %GlobalProxy(global);
-  // Compile the string in the constructor and not a helper so that errors
-  // appear to come from here.
-  var f = %_CallFunction(global_proxy, %CompileString(source, true));
-  %FunctionMarkNameShouldPrintAsAnonymous(f);
-  return f;
+  return NewFunctionFromString(arguments, 'function');
 }
 
 
diff --git a/src/v8threads.cc b/src/v8threads.cc
index a46b289..e2d9d49 100644
--- a/src/v8threads.cc
+++ b/src/v8threads.cc
@@ -14,34 +14,29 @@
 namespace v8 {
 
 
+namespace {
+
 // Track whether this V8 instance has ever called v8::Locker. This allows the
 // API code to verify that the lock is always held when V8 is being entered.
-bool Locker::active_ = false;
+base::Atomic32 g_locker_was_ever_used_ = 0;
+
+}  // namespace
 
 
 // Once the Locker is initialized, the current thread will be guaranteed to have
 // the lock for a given isolate.
 void Locker::Initialize(v8::Isolate* isolate) {
   DCHECK(isolate != NULL);
-  has_lock_= false;
+  has_lock_ = false;
   top_level_ = true;
   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
   // Record that the Locker has been used at least once.
-  active_ = true;
+  base::NoBarrier_Store(&g_locker_was_ever_used_, 1);
   // Get the big lock if necessary.
   if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
     isolate_->thread_manager()->Lock();
     has_lock_ = true;
 
-    // Make sure that V8 is initialized.  Archiving of threads interferes
-    // with deserialization by adding additional root pointers, so we must
-    // initialize here, before anyone can call ~Locker() or Unlocker().
-    if (!isolate_->IsInitialized()) {
-      isolate_->Enter();
-      V8::Initialize();
-      isolate_->Exit();
-    }
-
     // This may be a locker within an unlocker in which case we have to
     // get the saved state for this thread and restore it.
     if (isolate_->thread_manager()->RestoreThread()) {
@@ -64,7 +59,7 @@
 
 
 bool Locker::IsActive() {
-  return active_;
+  return !!base::NoBarrier_Load(&g_locker_was_ever_used_);
 }
 
 
diff --git a/src/variables.cc b/src/variables.cc
index 6588312..3b1559d 100644
--- a/src/variables.cc
+++ b/src/variables.cc
@@ -60,7 +60,7 @@
   // activation frame.
   return (IsDynamicVariableMode(mode_) ||
           (IsDeclaredVariableMode(mode_) && !IsLexicalVariableMode(mode_)))
-      && scope_ != NULL && scope_->is_global_scope();
+      && scope_ != NULL && scope_->is_script_scope();
 }
 
 
diff --git a/src/variables.h b/src/variables.h
index a8cf5e3..93bfb4a 100644
--- a/src/variables.h
+++ b/src/variables.h
@@ -64,7 +64,7 @@
 
   // The source code for an eval() call may refer to a variable that is
   // in an outer scope about which we don't know anything (it may not
-  // be the global scope). scope() is NULL in that case. Currently the
+  // be the script scope). scope() is NULL in that case. Currently the
   // scope is only used to follow the context chain length.
   Scope* scope() const { return scope_; }
 
diff --git a/src/vector.h b/src/vector.h
index d3ba775..a4fdb10 100644
--- a/src/vector.h
+++ b/src/vector.h
@@ -58,6 +58,10 @@
 
   T& last() { return start_[length_ - 1]; }
 
+  typedef T* iterator;
+  inline iterator begin() const { return &start_[0]; }
+  inline iterator end() const { return &start_[length_]; }
+
   // Returns a clone of this vector with a new backing store.
   Vector<T> Clone() const {
     T* result = NewArray<T>(length_);
diff --git a/src/version.cc b/src/version.cc
index 0502ba1..edcf2be 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -32,10 +32,10 @@
 // These macros define the version number for the current version.
 // NOTE these macros are used by some of the tool scripts and the build
 // system so their names cannot be changed without changing the scripts.
-#define MAJOR_VERSION     3
-#define MINOR_VERSION     29
-#define BUILD_NUMBER      88
-#define PATCH_LEVEL       18
+#define MAJOR_VERSION     4
+#define MINOR_VERSION     1
+#define BUILD_NUMBER      0
+#define PATCH_LEVEL       21
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
 #define IS_CANDIDATE_VERSION 0
diff --git a/src/version.h b/src/version.h
index 4f60005..dbcec1b 100644
--- a/src/version.h
+++ b/src/version.h
@@ -5,6 +5,8 @@
 #ifndef V8_VERSION_H_
 #define V8_VERSION_H_
 
+#include "src/base/functional.h"
+
 namespace v8 {
 namespace internal {
 
@@ -16,7 +18,10 @@
   static int GetBuild() { return build_; }
   static int GetPatch() { return patch_; }
   static bool IsCandidate() { return candidate_; }
-  static int Hash() { return (major_ << 20) ^ (minor_ << 10) ^ patch_; }
+  static uint32_t Hash() {
+    return static_cast<uint32_t>(
+        base::hash_combine(major_, minor_, build_, patch_));
+  }
 
   // Calculate the V8 version string.
   static void GetString(Vector<char> str);
diff --git a/src/vm-state.h b/src/vm-state.h
index a72180c..9838b87 100644
--- a/src/vm-state.h
+++ b/src/vm-state.h
@@ -11,6 +11,11 @@
 namespace v8 {
 namespace internal {
 
+// Logging and profiling.  A StateTag represents a possible state of
+// the VM. The logger maintains a stack of these. Creating a VMState
+// object enters a state by pushing on the stack, and destroying a
+// VMState object leaves a state by popping the current state from the
+// stack.
 template <StateTag Tag>
 class VMState BASE_EMBEDDED {
  public:
diff --git a/src/weak-collection.js b/src/weak-collection.js
index 1160176..a44c3d7 100644
--- a/src/weak-collection.js
+++ b/src/weak-collection.js
@@ -96,16 +96,6 @@
 }
 
 
-function WeakMapClear() {
-  if (!IS_WEAKMAP(this)) {
-    throw MakeTypeError('incompatible_method_receiver',
-                        ['WeakMap.prototype.clear', this]);
-  }
-  // Replace the internal table with a new empty table.
-  %WeakCollectionInitialize(this);
-}
-
-
 // -------------------------------------------------------------------
 
 function SetUpWeakMap() {
@@ -114,14 +104,15 @@
   %SetCode($WeakMap, WeakMapConstructor);
   %FunctionSetPrototype($WeakMap, new $Object());
   %AddNamedProperty($WeakMap.prototype, "constructor", $WeakMap, DONT_ENUM);
+  %AddNamedProperty(
+      $WeakMap.prototype, symbolToStringTag, "WeakMap", DONT_ENUM | READ_ONLY);
 
   // Set up the non-enumerable functions on the WeakMap prototype object.
   InstallFunctions($WeakMap.prototype, DONT_ENUM, $Array(
     "get", WeakMapGet,
     "set", WeakMapSet,
     "has", WeakMapHas,
-    "delete", WeakMapDelete,
-    "clear", WeakMapClear
+    "delete", WeakMapDelete
   ));
 }
 
@@ -196,16 +187,6 @@
 }
 
 
-function WeakSetClear() {
-  if (!IS_WEAKSET(this)) {
-    throw MakeTypeError('incompatible_method_receiver',
-                        ['WeakSet.prototype.clear', this]);
-  }
-  // Replace the internal table with a new empty table.
-  %WeakCollectionInitialize(this);
-}
-
-
 // -------------------------------------------------------------------
 
 function SetUpWeakSet() {
@@ -214,13 +195,14 @@
   %SetCode($WeakSet, WeakSetConstructor);
   %FunctionSetPrototype($WeakSet, new $Object());
   %AddNamedProperty($WeakSet.prototype, "constructor", $WeakSet, DONT_ENUM);
+  %AddNamedProperty(
+      $WeakSet.prototype, symbolToStringTag, "WeakSet", DONT_ENUM | READ_ONLY);
 
   // Set up the non-enumerable functions on the WeakSet prototype object.
   InstallFunctions($WeakSet.prototype, DONT_ENUM, $Array(
     "add", WeakSetAdd,
     "has", WeakSetHas,
-    "delete", WeakSetDelete,
-    "clear", WeakSetClear
+    "delete", WeakSetDelete
   ));
 }
 
diff --git a/src/x64/assembler-x64-inl.h b/src/x64/assembler-x64-inl.h
index b64bbfb..caf7af6 100644
--- a/src/x64/assembler-x64-inl.h
+++ b/src/x64/assembler-x64-inl.h
@@ -179,11 +179,75 @@
 }
 
 
+void Assembler::emit_optional_rex_32(XMMRegister rm_reg) {
+  if (rm_reg.high_bit()) emit(0x41);
+}
+
+
 void Assembler::emit_optional_rex_32(const Operand& op) {
   if (op.rex_ != 0) emit(0x40 | op.rex_);
 }
 
 
+// byte 1 of 3-byte VEX
+void Assembler::emit_vex3_byte1(XMMRegister reg, XMMRegister rm,
+                                LeadingOpcode m) {
+  byte rxb = ~((reg.high_bit() << 2) | rm.high_bit()) << 5;
+  emit(rxb | m);
+}
+
+
+// byte 1 of 3-byte VEX
+void Assembler::emit_vex3_byte1(XMMRegister reg, const Operand& rm,
+                                LeadingOpcode m) {
+  byte rxb = ~((reg.high_bit() << 2) | rm.rex_) << 5;
+  emit(rxb | m);
+}
+
+
+// byte 1 of 2-byte VEX
+void Assembler::emit_vex2_byte1(XMMRegister reg, XMMRegister v, VectorLength l,
+                                SIMDPrefix pp) {
+  byte rv = ~((reg.high_bit() << 4) | v.code()) << 3;
+  emit(rv | l | pp);
+}
+
+
+// byte 2 of 3-byte VEX
+void Assembler::emit_vex3_byte2(VexW w, XMMRegister v, VectorLength l,
+                                SIMDPrefix pp) {
+  emit(w | ((~v.code() & 0xf) << 3) | l | pp);
+}
+
+
+void Assembler::emit_vex_prefix(XMMRegister reg, XMMRegister vreg,
+                                XMMRegister rm, VectorLength l, SIMDPrefix pp,
+                                LeadingOpcode mm, VexW w) {
+  if (rm.high_bit() || mm != k0F || w != kW0) {
+    emit_vex3_byte0();
+    emit_vex3_byte1(reg, rm, mm);
+    emit_vex3_byte2(w, vreg, l, pp);
+  } else {
+    emit_vex2_byte0();
+    emit_vex2_byte1(reg, vreg, l, pp);
+  }
+}
+
+
+void Assembler::emit_vex_prefix(XMMRegister reg, XMMRegister vreg,
+                                const Operand& rm, VectorLength l,
+                                SIMDPrefix pp, LeadingOpcode mm, VexW w) {
+  if (rm.rex_ || mm != k0F || w != kW0) {
+    emit_vex3_byte0();
+    emit_vex3_byte1(reg, rm, mm);
+    emit_vex3_byte2(w, vreg, l, pp);
+  } else {
+    emit_vex2_byte0();
+    emit_vex2_byte1(reg, vreg, l, pp);
+  }
+}
+
+
 Address Assembler::target_address_at(Address pc,
                                      ConstantPoolArray* constant_pool) {
   return Memory::int32_at(pc) + pc + 4;
diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc
index 4f8d5b1..fd722b2 100644
--- a/src/x64/assembler-x64.cc
+++ b/src/x64/assembler-x64.cc
@@ -2,13 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/v8.h"
+#include "src/x64/assembler-x64.h"
+
+#if V8_OS_MACOSX
+#include <sys/sysctl.h>
+#endif
 
 #if V8_TARGET_ARCH_X64
 
 #include "src/base/bits.h"
 #include "src/macro-assembler.h"
-#include "src/serialize.h"
+#include "src/v8.h"
 
 namespace v8 {
 namespace internal {
@@ -16,6 +20,29 @@
 // -----------------------------------------------------------------------------
 // Implementation of CpuFeatures
 
+namespace {
+
+bool EnableAVX() {
+#if V8_OS_MACOSX
+  // Mac OS X 10.9 has a bug where AVX transitions were indeed being caused by
+  // ISRs, so we detect Mac OS X 10.9 here and disable AVX in that case.
+  char buffer[128];
+  size_t buffer_size = arraysize(buffer);
+  int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
+  if (sysctl(ctl_name, 2, buffer, &buffer_size, nullptr, 0) != 0) {
+    V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version");
+  }
+  // The buffer now contains a string of the form XX.YY.ZZ, where
+  // XX is the major kernel version component. 13.x.x (Mavericks) is
+  // affected by this bug, so disable AVX there.
+  if (memcmp(buffer, "13.", 3) == 0) return false;
+#endif  // V8_OS_MACOSX
+  return FLAG_enable_avx;
+}
+
+}  // namespace
+
+
 void CpuFeatures::ProbeImpl(bool cross_compile) {
   base::CPU cpu;
   CHECK(cpu.has_sse2());  // SSE2 support is mandatory.
@@ -27,12 +54,19 @@
   if (cpu.has_sse41() && FLAG_enable_sse4_1) supported_ |= 1u << SSE4_1;
   if (cpu.has_sse3() && FLAG_enable_sse3) supported_ |= 1u << SSE3;
   // SAHF is not generally available in long mode.
-  if (cpu.has_sahf() && FLAG_enable_sahf) supported_|= 1u << SAHF;
+  if (cpu.has_sahf() && FLAG_enable_sahf) supported_ |= 1u << SAHF;
+  if (cpu.has_avx() && EnableAVX()) supported_ |= 1u << AVX;
+  if (cpu.has_fma3() && FLAG_enable_fma3) supported_ |= 1u << FMA3;
 }
 
 
 void CpuFeatures::PrintTarget() { }
-void CpuFeatures::PrintFeatures() { }
+void CpuFeatures::PrintFeatures() {
+  printf("SSE3=%d SSE4_1=%d SAHF=%d AVX=%d FMA3=%d\n",
+         CpuFeatures::IsSupported(SSE3), CpuFeatures::IsSupported(SSE4_1),
+         CpuFeatures::IsSupported(SAHF), CpuFeatures::IsSupported(AVX),
+         CpuFeatures::IsSupported(FMA3));
+}
 
 
 // -----------------------------------------------------------------------------
@@ -617,6 +651,24 @@
 }
 
 
+void Assembler::shift(Operand dst, Immediate shift_amount, int subcode,
+                      int size) {
+  EnsureSpace ensure_space(this);
+  DCHECK(size == kInt64Size ? is_uint6(shift_amount.value_)
+                            : is_uint5(shift_amount.value_));
+  if (shift_amount.value_ == 1) {
+    emit_rex(dst, size);
+    emit(0xD1);
+    emit_operand(subcode, dst);
+  } else {
+    emit_rex(dst, size);
+    emit(0xC1);
+    emit_operand(subcode, dst);
+    emit(shift_amount.value_);
+  }
+}
+
+
 void Assembler::shift(Register dst, int subcode, int size) {
   EnsureSpace ensure_space(this);
   emit_rex(dst, size);
@@ -625,6 +677,14 @@
 }
 
 
+void Assembler::shift(Operand dst, int subcode, int size) {
+  EnsureSpace ensure_space(this);
+  emit_rex(dst, size);
+  emit(0xD3);
+  emit_operand(subcode, dst);
+}
+
+
 void Assembler::bt(const Operand& dst, Register src) {
   EnsureSpace ensure_space(this);
   emit_rex_64(src, dst);
@@ -909,6 +969,14 @@
 }
 
 
+void Assembler::emit_imul(const Operand& src, int size) {
+  EnsureSpace ensure_space(this);
+  emit_rex(src, size);
+  emit(0xF7);
+  emit_operand(0x5, src);
+}
+
+
 void Assembler::emit_imul(Register dst, Register src, int size) {
   EnsureSpace ensure_space(this);
   emit_rex(dst, src, size);
@@ -942,6 +1010,22 @@
 }
 
 
+void Assembler::emit_imul(Register dst, const Operand& src, Immediate imm,
+                          int size) {
+  EnsureSpace ensure_space(this);
+  emit_rex(dst, src, size);
+  if (is_int8(imm.value_)) {
+    emit(0x6B);
+    emit_operand(dst, src);
+    emit(imm.value_);
+  } else {
+    emit(0x69);
+    emit_operand(dst, src);
+    emitl(imm.value_);
+  }
+}
+
+
 void Assembler::emit_inc(Register dst, int size) {
   EnsureSpace ensure_space(this);
   emit_rex(dst, size);
@@ -1333,6 +1417,20 @@
 }
 
 
+void Assembler::movsxbl(Register dst, Register src) {
+  EnsureSpace ensure_space(this);
+  if (!src.is_byte_register()) {
+    // Register is not one of al, bl, cl, dl.  Its encoding needs REX.
+    emit_rex_32(dst, src);
+  } else {
+    emit_optional_rex_32(dst, src);
+  }
+  emit(0x0F);
+  emit(0xBE);
+  emit_modrm(dst, src);
+}
+
+
 void Assembler::movsxbl(Register dst, const Operand& src) {
   EnsureSpace ensure_space(this);
   emit_optional_rex_32(dst, src);
@@ -1351,6 +1449,15 @@
 }
 
 
+void Assembler::movsxwl(Register dst, Register src) {
+  EnsureSpace ensure_space(this);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0xBF);
+  emit_modrm(dst, src);
+}
+
+
 void Assembler::movsxwl(Register dst, const Operand& src) {
   EnsureSpace ensure_space(this);
   emit_optional_rex_32(dst, src);
@@ -1457,7 +1564,23 @@
 }
 
 
-void Assembler::mul(Register src) {
+void Assembler::mull(Register src) {
+  EnsureSpace ensure_space(this);
+  emit_optional_rex_32(src);
+  emit(0xF7);
+  emit_modrm(0x4, src);
+}
+
+
+void Assembler::mull(const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit_optional_rex_32(src);
+  emit(0xF7);
+  emit_operand(0x4, src);
+}
+
+
+void Assembler::mulq(Register src) {
   EnsureSpace ensure_space(this);
   emit_rex_64(src);
   emit(0xF7);
@@ -2549,6 +2672,104 @@
 }
 
 
+void Assembler::addss(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x58);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::addss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x58);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::subss(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5C);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::subss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5C);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::mulss(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x59);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::mulss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x59);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::divss(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5E);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::divss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5E);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::ucomiss(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit_optional_rex_32(dst, src);
+  emit(0x0f);
+  emit(0x2e);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::ucomiss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit_optional_rex_32(dst, src);
+  emit(0x0f);
+  emit(0x2e);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::movss(XMMRegister dst, const Operand& src) {
   EnsureSpace ensure_space(this);
   emit(0xF3);  // single
@@ -2572,6 +2793,7 @@
 void Assembler::psllq(XMMRegister reg, byte imm8) {
   EnsureSpace ensure_space(this);
   emit(0x66);
+  emit_optional_rex_32(reg);
   emit(0x0F);
   emit(0x73);
   emit_sse_operand(rsi, reg);  // rsi == 6
@@ -2579,6 +2801,39 @@
 }
 
 
+void Assembler::psrlq(XMMRegister reg, byte imm8) {
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(reg);
+  emit(0x0F);
+  emit(0x73);
+  emit_sse_operand(rdx, reg);  // rdx == 2
+  emit(imm8);
+}
+
+
+void Assembler::pslld(XMMRegister reg, byte imm8) {
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(reg);
+  emit(0x0F);
+  emit(0x72);
+  emit_sse_operand(rsi, reg);  // rsi == 6
+  emit(imm8);
+}
+
+
+void Assembler::psrld(XMMRegister reg, byte imm8) {
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(reg);
+  emit(0x0F);
+  emit(0x72);
+  emit_sse_operand(rdx, reg);  // rdx == 2
+  emit(imm8);
+}
+
+
 void Assembler::cvttss2si(Register dst, const Operand& src) {
   EnsureSpace ensure_space(this);
   emit(0xF3);
@@ -2669,6 +2924,16 @@
 }
 
 
+void Assembler::cvtqsi2sd(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF2);
+  emit_rex_64(dst, src);
+  emit(0x0F);
+  emit(0x2A);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::cvtqsi2sd(XMMRegister dst, Register src) {
   EnsureSpace ensure_space(this);
   emit(0xF2);
@@ -2709,6 +2974,16 @@
 }
 
 
+void Assembler::cvtsd2ss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF2);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5A);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::cvtsd2si(Register dst, XMMRegister src) {
   EnsureSpace ensure_space(this);
   emit(0xF2);
@@ -2779,6 +3054,16 @@
 }
 
 
+void Assembler::subsd(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF2);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5C);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::divsd(XMMRegister dst, XMMRegister src) {
   EnsureSpace ensure_space(this);
   emit(0xF2);
@@ -2789,6 +3074,16 @@
 }
 
 
+void Assembler::divsd(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF2);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5E);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::andpd(XMMRegister dst, XMMRegister src) {
   EnsureSpace ensure_space(this);
   emit(0x66);
@@ -2904,6 +3199,77 @@
 }
 
 
+void Assembler::pcmpeqd(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x76);
+  emit_sse_operand(dst, src);
+}
+
+
+// AVX instructions
+void Assembler::vfmasd(byte op, XMMRegister dst, XMMRegister src1,
+                       XMMRegister src2) {
+  DCHECK(IsEnabled(FMA3));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(dst, src1, src2, kLIG, k66, k0F38, kW1);
+  emit(op);
+  emit_sse_operand(dst, src2);
+}
+
+
+void Assembler::vfmasd(byte op, XMMRegister dst, XMMRegister src1,
+                       const Operand& src2) {
+  DCHECK(IsEnabled(FMA3));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(dst, src1, src2, kLIG, k66, k0F38, kW1);
+  emit(op);
+  emit_sse_operand(dst, src2);
+}
+
+
+void Assembler::vfmass(byte op, XMMRegister dst, XMMRegister src1,
+                       XMMRegister src2) {
+  DCHECK(IsEnabled(FMA3));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(dst, src1, src2, kLIG, k66, k0F38, kW0);
+  emit(op);
+  emit_sse_operand(dst, src2);
+}
+
+
+void Assembler::vfmass(byte op, XMMRegister dst, XMMRegister src1,
+                       const Operand& src2) {
+  DCHECK(IsEnabled(FMA3));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(dst, src1, src2, kLIG, k66, k0F38, kW0);
+  emit(op);
+  emit_sse_operand(dst, src2);
+}
+
+
+void Assembler::vsd(byte op, XMMRegister dst, XMMRegister src1,
+                    XMMRegister src2) {
+  DCHECK(IsEnabled(AVX));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(dst, src1, src2, kLIG, kF2, k0F, kWIG);
+  emit(op);
+  emit_sse_operand(dst, src2);
+}
+
+
+void Assembler::vsd(byte op, XMMRegister dst, XMMRegister src1,
+                    const Operand& src2) {
+  DCHECK(IsEnabled(AVX));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(dst, src1, src2, kLIG, kF2, k0F, kWIG);
+  emit(op);
+  emit_sse_operand(dst, src2);
+}
+
+
 void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
   Register ireg = { reg.code() };
   emit_operand(ireg, adr);
diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h
index b2a97cc..2ebae3b 100644
--- a/src/x64/assembler-x64.h
+++ b/src/x64/assembler-x64.h
@@ -200,6 +200,11 @@
     return kMaxNumAllocatableRegisters;
   }
 
+  // TODO(turbofan): Proper support for float32.
+  static int NumAllocatableAliasedRegisters() {
+    return NumAllocatableRegisters();
+  }
+
   static int ToAllocationIndex(XMMRegister reg) {
     DCHECK(reg.code() != 0);
     return reg.code() - 1;
@@ -726,8 +731,10 @@
   void movq(Register dst, int64_t value);
   void movq(Register dst, uint64_t value);
 
+  void movsxbl(Register dst, Register src);
   void movsxbl(Register dst, const Operand& src);
   void movsxbq(Register dst, const Operand& src);
+  void movsxwl(Register dst, Register src);
   void movsxwl(Register dst, const Operand& src);
   void movsxwq(Register dst, const Operand& src);
   void movsxlq(Register dst, Register src);
@@ -805,33 +812,48 @@
   // Sign-extends eax into edx:eax.
   void cdq();
 
+  // Multiply eax by src, put the result in edx:eax.
+  void mull(Register src);
+  void mull(const Operand& src);
   // Multiply rax by src, put the result in rdx:rax.
-  void mul(Register src);
+  void mulq(Register src);
 
-#define DECLARE_SHIFT_INSTRUCTION(instruction, subcode)     \
-  void instruction##p(Register dst, Immediate imm8) {       \
-    shift(dst, imm8, subcode, kPointerSize);                \
-  }                                                         \
-                                                            \
-  void instruction##l(Register dst, Immediate imm8) {       \
-    shift(dst, imm8, subcode, kInt32Size);                  \
-  }                                                         \
-                                                            \
-  void instruction##q(Register dst, Immediate imm8) {       \
-    shift(dst, imm8, subcode, kInt64Size);                  \
-  }                                                         \
-                                                            \
-  void instruction##p_cl(Register dst) {                    \
-    shift(dst, subcode, kPointerSize);                      \
-  }                                                         \
-                                                            \
-  void instruction##l_cl(Register dst) {                    \
-    shift(dst, subcode, kInt32Size);                        \
-  }                                                         \
-                                                            \
-  void instruction##q_cl(Register dst) {                    \
-    shift(dst, subcode, kInt64Size);                        \
-  }
+#define DECLARE_SHIFT_INSTRUCTION(instruction, subcode)                       \
+  void instruction##p(Register dst, Immediate imm8) {                         \
+    shift(dst, imm8, subcode, kPointerSize);                                  \
+  }                                                                           \
+                                                                              \
+  void instruction##l(Register dst, Immediate imm8) {                         \
+    shift(dst, imm8, subcode, kInt32Size);                                    \
+  }                                                                           \
+                                                                              \
+  void instruction##q(Register dst, Immediate imm8) {                         \
+    shift(dst, imm8, subcode, kInt64Size);                                    \
+  }                                                                           \
+                                                                              \
+  void instruction##p(Operand dst, Immediate imm8) {                          \
+    shift(dst, imm8, subcode, kPointerSize);                                  \
+  }                                                                           \
+                                                                              \
+  void instruction##l(Operand dst, Immediate imm8) {                          \
+    shift(dst, imm8, subcode, kInt32Size);                                    \
+  }                                                                           \
+                                                                              \
+  void instruction##q(Operand dst, Immediate imm8) {                          \
+    shift(dst, imm8, subcode, kInt64Size);                                    \
+  }                                                                           \
+                                                                              \
+  void instruction##p_cl(Register dst) { shift(dst, subcode, kPointerSize); } \
+                                                                              \
+  void instruction##l_cl(Register dst) { shift(dst, subcode, kInt32Size); }   \
+                                                                              \
+  void instruction##q_cl(Register dst) { shift(dst, subcode, kInt64Size); }   \
+                                                                              \
+  void instruction##p_cl(Operand dst) { shift(dst, subcode, kPointerSize); }  \
+                                                                              \
+  void instruction##l_cl(Operand dst) { shift(dst, subcode, kInt32Size); }    \
+                                                                              \
+  void instruction##q_cl(Operand dst) { shift(dst, subcode, kInt64Size); }
   SHIFT_INSTRUCTION_LIST(DECLARE_SHIFT_INSTRUCTION)
 #undef DECLARE_SHIFT_INSTRUCTION
 
@@ -992,6 +1014,17 @@
   void sahf();
 
   // SSE instructions
+  void addss(XMMRegister dst, XMMRegister src);
+  void addss(XMMRegister dst, const Operand& src);
+  void subss(XMMRegister dst, XMMRegister src);
+  void subss(XMMRegister dst, const Operand& src);
+  void mulss(XMMRegister dst, XMMRegister src);
+  void mulss(XMMRegister dst, const Operand& src);
+  void divss(XMMRegister dst, XMMRegister src);
+  void divss(XMMRegister dst, const Operand& src);
+
+  void ucomiss(XMMRegister dst, XMMRegister src);
+  void ucomiss(XMMRegister dst, const Operand& src);
   void movaps(XMMRegister dst, XMMRegister src);
   void movss(XMMRegister dst, const Operand& src);
   void movss(const Operand& dst, XMMRegister src);
@@ -1044,6 +1077,9 @@
   void movapd(XMMRegister dst, XMMRegister src);
 
   void psllq(XMMRegister reg, byte imm8);
+  void psrlq(XMMRegister reg, byte imm8);
+  void pslld(XMMRegister reg, byte imm8);
+  void psrld(XMMRegister reg, byte imm8);
 
   void cvttsd2si(Register dst, const Operand& src);
   void cvttsd2si(Register dst, XMMRegister src);
@@ -1059,6 +1095,7 @@
   void cvtss2sd(XMMRegister dst, XMMRegister src);
   void cvtss2sd(XMMRegister dst, const Operand& src);
   void cvtsd2ss(XMMRegister dst, XMMRegister src);
+  void cvtsd2ss(XMMRegister dst, const Operand& src);
 
   void cvtsd2si(Register dst, XMMRegister src);
   void cvtsd2siq(Register dst, XMMRegister src);
@@ -1066,9 +1103,11 @@
   void addsd(XMMRegister dst, XMMRegister src);
   void addsd(XMMRegister dst, const Operand& src);
   void subsd(XMMRegister dst, XMMRegister src);
+  void subsd(XMMRegister dst, const Operand& src);
   void mulsd(XMMRegister dst, XMMRegister src);
   void mulsd(XMMRegister dst, const Operand& src);
   void divsd(XMMRegister dst, XMMRegister src);
+  void divsd(XMMRegister dst, const Operand& src);
 
   void andpd(XMMRegister dst, XMMRegister src);
   void orpd(XMMRegister dst, XMMRegister src);
@@ -1079,6 +1118,7 @@
   void ucomisd(XMMRegister dst, XMMRegister src);
   void ucomisd(XMMRegister dst, const Operand& src);
   void cmpltsd(XMMRegister dst, XMMRegister src);
+  void pcmpeqd(XMMRegister dst, XMMRegister src);
 
   void movmskpd(Register dst, XMMRegister src);
 
@@ -1094,6 +1134,184 @@
 
   void roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode);
 
+  // AVX instruction
+  void vfmadd132sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmasd(0x99, dst, src1, src2);
+  }
+  void vfmadd213sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmasd(0xa9, dst, src1, src2);
+  }
+  void vfmadd231sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmasd(0xb9, dst, src1, src2);
+  }
+  void vfmadd132sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0x99, dst, src1, src2);
+  }
+  void vfmadd213sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xa9, dst, src1, src2);
+  }
+  void vfmadd231sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xb9, dst, src1, src2);
+  }
+  void vfmsub132sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmasd(0x9b, dst, src1, src2);
+  }
+  void vfmsub213sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmasd(0xab, dst, src1, src2);
+  }
+  void vfmsub231sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmasd(0xbb, dst, src1, src2);
+  }
+  void vfmsub132sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0x9b, dst, src1, src2);
+  }
+  void vfmsub213sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xab, dst, src1, src2);
+  }
+  void vfmsub231sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xbb, dst, src1, src2);
+  }
+  void vfnmadd132sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmasd(0x9d, dst, src1, src2);
+  }
+  void vfnmadd213sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmasd(0xad, dst, src1, src2);
+  }
+  void vfnmadd231sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmasd(0xbd, dst, src1, src2);
+  }
+  void vfnmadd132sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0x9d, dst, src1, src2);
+  }
+  void vfnmadd213sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xad, dst, src1, src2);
+  }
+  void vfnmadd231sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xbd, dst, src1, src2);
+  }
+  void vfnmsub132sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmasd(0x9f, dst, src1, src2);
+  }
+  void vfnmsub213sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmasd(0xaf, dst, src1, src2);
+  }
+  void vfnmsub231sd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmasd(0xbf, dst, src1, src2);
+  }
+  void vfnmsub132sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0x9f, dst, src1, src2);
+  }
+  void vfnmsub213sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xaf, dst, src1, src2);
+  }
+  void vfnmsub231sd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmasd(0xbf, dst, src1, src2);
+  }
+  void vfmasd(byte op, XMMRegister dst, XMMRegister src1, XMMRegister src2);
+  void vfmasd(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);
+
+  void vfmadd132ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmass(0x99, dst, src1, src2);
+  }
+  void vfmadd213ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmass(0xa9, dst, src1, src2);
+  }
+  void vfmadd231ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmass(0xb9, dst, src1, src2);
+  }
+  void vfmadd132ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0x99, dst, src1, src2);
+  }
+  void vfmadd213ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xa9, dst, src1, src2);
+  }
+  void vfmadd231ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xb9, dst, src1, src2);
+  }
+  void vfmsub132ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmass(0x9b, dst, src1, src2);
+  }
+  void vfmsub213ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmass(0xab, dst, src1, src2);
+  }
+  void vfmsub231ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmass(0xbb, dst, src1, src2);
+  }
+  void vfmsub132ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0x9b, dst, src1, src2);
+  }
+  void vfmsub213ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xab, dst, src1, src2);
+  }
+  void vfmsub231ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xbb, dst, src1, src2);
+  }
+  void vfnmadd132ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmass(0x9d, dst, src1, src2);
+  }
+  void vfnmadd213ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmass(0xad, dst, src1, src2);
+  }
+  void vfnmadd231ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmass(0xbd, dst, src1, src2);
+  }
+  void vfnmadd132ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0x9d, dst, src1, src2);
+  }
+  void vfnmadd213ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xad, dst, src1, src2);
+  }
+  void vfnmadd231ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xbd, dst, src1, src2);
+  }
+  void vfnmsub132ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmass(0x9f, dst, src1, src2);
+  }
+  void vfnmsub213ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmass(0xaf, dst, src1, src2);
+  }
+  void vfnmsub231ss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vfmass(0xbf, dst, src1, src2);
+  }
+  void vfnmsub132ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0x9f, dst, src1, src2);
+  }
+  void vfnmsub213ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xaf, dst, src1, src2);
+  }
+  void vfnmsub231ss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vfmass(0xbf, dst, src1, src2);
+  }
+  void vfmass(byte op, XMMRegister dst, XMMRegister src1, XMMRegister src2);
+  void vfmass(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);
+
+  void vaddsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vsd(0x58, dst, src1, src2);
+  }
+  void vaddsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vsd(0x58, dst, src1, src2);
+  }
+  void vsubsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vsd(0x5c, dst, src1, src2);
+  }
+  void vsubsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vsd(0x5c, dst, src1, src2);
+  }
+  void vmulsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vsd(0x59, dst, src1, src2);
+  }
+  void vmulsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vsd(0x59, dst, src1, src2);
+  }
+  void vdivsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vsd(0x5e, dst, src1, src2);
+  }
+  void vdivsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vsd(0x5e, dst, src1, src2);
+  }
+  void vsd(byte op, XMMRegister dst, XMMRegister src1, XMMRegister src2);
+  void vsd(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);
+
   // Debugging
   void Print();
 
@@ -1253,6 +1471,7 @@
   // Optionally do as emit_rex_32(Register) if the register number has
   // the high bit set.
   inline void emit_optional_rex_32(Register rm_reg);
+  inline void emit_optional_rex_32(XMMRegister rm_reg);
 
   // Optionally do as emit_rex_32(const Operand&) if the operand register
   // numbers have a high bit set.
@@ -1286,6 +1505,28 @@
     }
   }
 
+  // Emit vex prefix
+  enum SIMDPrefix { kNone = 0x0, k66 = 0x1, kF3 = 0x2, kF2 = 0x3 };
+  enum VectorLength { kL128 = 0x0, kL256 = 0x4, kLIG = kL128 };
+  enum VexW { kW0 = 0x0, kW1 = 0x80, kWIG = kW0 };
+  enum LeadingOpcode { k0F = 0x1, k0F38 = 0x2, k0F3A = 0x2 };
+
+  void emit_vex2_byte0() { emit(0xc5); }
+  inline void emit_vex2_byte1(XMMRegister reg, XMMRegister v, VectorLength l,
+                              SIMDPrefix pp);
+  void emit_vex3_byte0() { emit(0xc4); }
+  inline void emit_vex3_byte1(XMMRegister reg, XMMRegister rm, LeadingOpcode m);
+  inline void emit_vex3_byte1(XMMRegister reg, const Operand& rm,
+                              LeadingOpcode m);
+  inline void emit_vex3_byte2(VexW w, XMMRegister v, VectorLength l,
+                              SIMDPrefix pp);
+  inline void emit_vex_prefix(XMMRegister reg, XMMRegister v, XMMRegister rm,
+                              VectorLength l, SIMDPrefix pp, LeadingOpcode m,
+                              VexW w);
+  inline void emit_vex_prefix(XMMRegister reg, XMMRegister v, const Operand& rm,
+                              VectorLength l, SIMDPrefix pp, LeadingOpcode m,
+                              VexW w);
+
   // Emit the ModR/M byte, and optionally the SIB byte and
   // 1- or 4-byte offset for a memory operand.  Also encodes
   // the second operand of the operation, a register or operation
@@ -1360,9 +1601,11 @@
                                int size);
 
   // Emit machine code for a shift operation.
+  void shift(Operand dst, Immediate shift_amount, int subcode, int size);
   void shift(Register dst, Immediate shift_amount, int subcode, int size);
   // Shift dst by cl % 64 bits.
   void shift(Register dst, int subcode, int size);
+  void shift(Operand dst, int subcode, int size);
 
   void emit_farith(int b1, int b2, int i);
 
@@ -1446,9 +1689,11 @@
   // Signed multiply instructions.
   // rdx:rax = rax * src when size is 64 or edx:eax = eax * src when size is 32.
   void emit_imul(Register src, int size);
+  void emit_imul(const Operand& src, int size);
   void emit_imul(Register dst, Register src, int size);
   void emit_imul(Register dst, const Operand& src, int size);
   void emit_imul(Register dst, Register src, Immediate imm, int size);
+  void emit_imul(Register dst, const Operand& src, Immediate imm, int size);
 
   void emit_inc(Register dst, int size);
   void emit_inc(const Operand& dst, int size);
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index 194d8a6..ef3df65 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -158,22 +158,20 @@
       // rax: initial map
       __ CmpInstanceType(rax, JS_FUNCTION_TYPE);
       __ j(equal, &rt_call);
-
       if (!is_api_function) {
         Label allocate;
         // The code below relies on these assumptions.
-        STATIC_ASSERT(JSFunction::kNoSlackTracking == 0);
-        STATIC_ASSERT(Map::ConstructionCount::kShift +
-                      Map::ConstructionCount::kSize == 32);
+        STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32);
         // Check if slack tracking is enabled.
         __ movl(rsi, FieldOperand(rax, Map::kBitField3Offset));
-        __ shrl(rsi, Immediate(Map::ConstructionCount::kShift));
-        __ j(zero, &allocate);  // JSFunction::kNoSlackTracking
+        __ shrl(rsi, Immediate(Map::Counter::kShift));
+        __ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd));
+        __ j(less, &allocate);
         // Decrease generous allocation count.
         __ subl(FieldOperand(rax, Map::kBitField3Offset),
-                Immediate(1 << Map::ConstructionCount::kShift));
+                Immediate(1 << Map::Counter::kShift));
 
-        __ cmpl(rsi, Immediate(JSFunction::kFinishSlackTracking));
+        __ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd));
         __ j(not_equal, &allocate);
 
         __ Push(rax);
@@ -184,7 +182,7 @@
 
         __ Pop(rdi);
         __ Pop(rax);
-        __ xorl(rsi, rsi);  // JSFunction::kNoSlackTracking
+        __ movl(rsi, Immediate(Map::kSlackTrackingCounterEnd - 1));
 
         __ bind(&allocate);
       }
@@ -222,8 +220,8 @@
         Label no_inobject_slack_tracking;
 
         // Check if slack tracking is enabled.
-        __ cmpl(rsi, Immediate(JSFunction::kNoSlackTracking));
-        __ j(equal, &no_inobject_slack_tracking);
+        __ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd));
+        __ j(less, &no_inobject_slack_tracking);
 
         // Allocate object with a slack.
         __ movzxbp(rsi,
@@ -1075,14 +1073,19 @@
 
     // Use inline caching to speed up access to arguments.
     if (FLAG_vector_ics) {
-      __ Move(VectorLoadICDescriptor::SlotRegister(), Smi::FromInt(0));
+      // TODO(mvstanton): Vector-based ics need additional infrastructure to
+      // be embedded here. For now, just call the runtime.
+      __ Push(receiver);
+      __ Push(key);
+      __ CallRuntime(Runtime::kGetProperty, 2);
+    } else {
+      Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code();
+      __ Call(ic, RelocInfo::CODE_TARGET);
+      // It is important that we do not have a test instruction after the
+      // call.  A test instruction after the call is used to indicate that
+      // we have generated an inline version of the keyed load.  In this
+      // case, we know that we are not generating a test instruction next.
     }
-    Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code();
-    __ Call(ic, RelocInfo::CODE_TARGET);
-    // It is important that we do not have a test instruction after the
-    // call.  A test instruction after the call is used to indicate that
-    // we have generated an inline version of the keyed load.  In this
-    // case, we know that we are not generating a test instruction next.
 
     // Push the nth argument.
     __ Push(rax);
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index a625269..f327b50 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -14,7 +14,7 @@
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -524,6 +524,11 @@
 void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
   Label miss;
   Register receiver = LoadDescriptor::ReceiverRegister();
+  // Ensure that the vector and slot registers won't be clobbered before
+  // calling the miss handler.
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(r8, r9, VectorLoadICDescriptor::VectorRegister(),
+                     VectorLoadICDescriptor::SlotRegister()));
 
   NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, r8,
                                                           r9, &miss);
@@ -867,6 +872,40 @@
 }
 
 
+void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
+  // Return address is on the stack.
+  Label miss;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register index = LoadDescriptor::NameRegister();
+  Register scratch = rdi;
+  Register result = rax;
+  DCHECK(!scratch.is(receiver) && !scratch.is(index));
+  DCHECK(!FLAG_vector_ics ||
+         (!scratch.is(VectorLoadICDescriptor::VectorRegister()) &&
+          result.is(VectorLoadICDescriptor::SlotRegister())));
+
+  // StringCharAtGenerator doesn't use the result register until it's passed
+  // the different miss possibilities. If it did, we would have a conflict
+  // when FLAG_vector_ics is true.
+  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
+                                          &miss,  // When not a string.
+                                          &miss,  // When not a number.
+                                          &miss,  // When index out of range.
+                                          STRING_INDEX_IS_ARRAY_INDEX,
+                                          RECEIVER_IS_STRING);
+  char_at_generator.GenerateFast(masm);
+  __ ret(0);
+
+  StubRuntimeCallHelper call_helper;
+  char_at_generator.GenerateSlow(masm, call_helper);
+
+  __ bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
   // rsp[0]  : return address
   // rsp[8]  : number of parameters
@@ -2059,6 +2098,10 @@
   // rdi - function
   // rdx - slot id
   Isolate* isolate = masm->isolate();
+  const int with_types_offset =
+      FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
+  const int generic_offset =
+      FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
   Label slow, non_function, wrap, cont;
   Label have_js_function;
@@ -2100,27 +2143,64 @@
   }
 
   __ bind(&extra_checks_or_miss);
-  Label miss;
+  Label uninitialized, miss;
 
   __ movp(rcx, FieldOperand(rbx, rdx, times_pointer_size,
                             FixedArray::kHeaderSize));
   __ Cmp(rcx, TypeFeedbackVector::MegamorphicSentinel(isolate));
   __ j(equal, &slow_start);
-  __ Cmp(rcx, TypeFeedbackVector::UninitializedSentinel(isolate));
-  __ j(equal, &miss);
 
-  if (!FLAG_trace_ic) {
-    // We are going megamorphic. If the feedback is a JSFunction, it is fine
-    // to handle it here. More complex cases are dealt with in the runtime.
-    __ AssertNotSmi(rcx);
-    __ CmpObjectType(rcx, JS_FUNCTION_TYPE, rcx);
-    __ j(not_equal, &miss);
-    __ Move(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
-            TypeFeedbackVector::MegamorphicSentinel(isolate));
-    __ jmp(&slow_start);
+  // The following cases attempt to handle MISS cases without going to the
+  // runtime.
+  if (FLAG_trace_ic) {
+    __ jmp(&miss);
   }
 
-  // We are here because tracing is on or we are going monomorphic.
+  __ Cmp(rcx, TypeFeedbackVector::UninitializedSentinel(isolate));
+  __ j(equal, &uninitialized);
+
+  // We are going megamorphic. If the feedback is a JSFunction, it is fine
+  // to handle it here. More complex cases are dealt with in the runtime.
+  __ AssertNotSmi(rcx);
+  __ CmpObjectType(rcx, JS_FUNCTION_TYPE, rcx);
+  __ j(not_equal, &miss);
+  __ Move(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
+          TypeFeedbackVector::MegamorphicSentinel(isolate));
+  // We have to update statistics for runtime profiling.
+  __ SmiAddConstant(FieldOperand(rbx, with_types_offset), Smi::FromInt(-1));
+  __ SmiAddConstant(FieldOperand(rbx, generic_offset), Smi::FromInt(1));
+  __ jmp(&slow_start);
+
+  __ bind(&uninitialized);
+
+  // We are going monomorphic, provided we actually have a JSFunction.
+  __ JumpIfSmi(rdi, &miss);
+
+  // Goto miss case if we do not have a function.
+  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
+  __ j(not_equal, &miss);
+
+  // Make sure the function is not the Array() function, which requires special
+  // behavior on MISS.
+  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, rcx);
+  __ cmpp(rdi, rcx);
+  __ j(equal, &miss);
+
+  // Update stats.
+  __ SmiAddConstant(FieldOperand(rbx, with_types_offset), Smi::FromInt(1));
+
+  // Store the function.
+  __ movp(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
+          rdi);
+
+  // Update the write barrier.
+  __ movp(rax, rdi);
+  __ RecordWriteArray(rbx, rax, rdx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+  __ jmp(&have_js_function);
+
+  // We are here because tracing is on or we encountered a MISS case we can't
+  // handle here.
   __ bind(&miss);
   GenerateMiss(masm);
 
@@ -2711,14 +2791,16 @@
 
 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
   // If the receiver is a smi trigger the non-string case.
-  __ JumpIfSmi(object_, receiver_not_string_);
+  if (check_mode_ == RECEIVER_IS_UNKNOWN) {
+    __ JumpIfSmi(object_, receiver_not_string_);
 
-  // Fetch the instance type of the receiver into result register.
-  __ movp(result_, FieldOperand(object_, HeapObject::kMapOffset));
-  __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
-  // If the receiver is not a string trigger the non-string case.
-  __ testb(result_, Immediate(kIsNotStringMask));
-  __ j(not_zero, receiver_not_string_);
+    // Fetch the instance type of the receiver into result register.
+    __ movp(result_, FieldOperand(object_, HeapObject::kMapOffset));
+    __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
+    // If the receiver is not a string trigger the non-string case.
+    __ testb(result_, Immediate(kIsNotStringMask));
+    __ j(not_zero, receiver_not_string_);
+  }
 
   // If the index is non-smi trigger the non-smi case.
   __ JumpIfNotSmi(index_, &index_not_smi_);
@@ -3076,14 +3158,62 @@
   // rbx: instance type
   // rcx: sub string length (smi)
   // rdx: from index (smi)
-  StringCharAtGenerator generator(
-      rax, rdx, rcx, rax, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
+  StringCharAtGenerator generator(rax, rdx, rcx, rax, &runtime, &runtime,
+                                  &runtime, STRING_INDEX_IS_NUMBER,
+                                  RECEIVER_IS_STRING);
   generator.GenerateFast(masm);
   __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize);
   generator.SkipSlow(masm, &runtime);
 }
 
 
+void ToNumberStub::Generate(MacroAssembler* masm) {
+  // The ToNumber stub takes one argument in rax.
+  Label not_smi;
+  __ JumpIfNotSmi(rax, &not_smi, Label::kNear);
+  __ Ret();
+  __ bind(&not_smi);
+
+  Label not_heap_number;
+  __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
+                 Heap::kHeapNumberMapRootIndex);
+  __ j(not_equal, &not_heap_number, Label::kNear);
+  __ Ret();
+  __ bind(&not_heap_number);
+
+  Label not_string, slow_string;
+  __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdi);
+  // rax: object
+  // rdi: object map
+  __ j(above_equal, &not_string, Label::kNear);
+  // Check if string has a cached array index.
+  __ testl(FieldOperand(rax, String::kHashFieldOffset),
+           Immediate(String::kContainsCachedArrayIndexMask));
+  __ j(not_zero, &slow_string, Label::kNear);
+  __ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
+  __ IndexFromHash(rax, rax);
+  __ Ret();
+  __ bind(&slow_string);
+  __ PopReturnAddressTo(rcx);     // Pop return address.
+  __ Push(rax);                   // Push argument.
+  __ PushReturnAddressFrom(rcx);  // Push return address.
+  __ TailCallRuntime(Runtime::kStringToNumber, 1, 1);
+  __ bind(&not_string);
+
+  Label not_oddball;
+  __ CmpInstanceType(rdi, ODDBALL_TYPE);
+  __ j(not_equal, &not_oddball, Label::kNear);
+  __ movp(rax, FieldOperand(rax, Oddball::kToNumberOffset));
+  __ Ret();
+  __ bind(&not_oddball);
+
+  __ PopReturnAddressTo(rcx);     // Pop return address.
+  __ Push(rax);                   // Push argument.
+  __ PushReturnAddressFrom(rcx);  // Push return address.
+  __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
+}
+
+
 void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm,
                                                    Register left,
                                                    Register right,
diff --git a/src/x64/code-stubs-x64.h b/src/x64/code-stubs-x64.h
index d17fa1b..0efcf7f 100644
--- a/src/x64/code-stubs-x64.h
+++ b/src/x64/code-stubs-x64.h
@@ -71,7 +71,7 @@
                                      Register r0,
                                      Register r1);
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
  private:
   static const int kInlinedProbes = 4;
@@ -134,7 +134,7 @@
     INCREMENTAL_COMPACTION
   };
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
   static const byte kTwoByteNopInstruction = 0x3c;  // Cmpb al, #imm8.
   static const byte kTwoByteJumpInstruction = 0xeb;  // Jmp #imm8.
@@ -313,9 +313,9 @@
     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
   };
 
-  virtual Major MajorKey() const FINAL OVERRIDE { return RecordWrite; }
+  Major MajorKey() const FINAL { return RecordWrite; }
 
-  virtual void Generate(MacroAssembler* masm) OVERRIDE;
+  void Generate(MacroAssembler* masm) OVERRIDE;
   void GenerateIncremental(MacroAssembler* masm, Mode mode);
   void CheckNeedsToInformIncrementalMarker(
       MacroAssembler* masm,
@@ -323,7 +323,7 @@
       Mode mode);
   void InformIncrementalMarker(MacroAssembler* masm);
 
-  void Activate(Code* code) {
+  void Activate(Code* code) OVERRIDE {
     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
   }
 
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index 44e1618..ceee954 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -397,6 +397,20 @@
   __ LoadRoot(rdi, Heap::kTheHoleValueRootIndex);
   // rsi: the-hole NaN
   // rdi: pointer to the-hole
+
+  // Allocating heap numbers in the loop below can fail and cause a jump to
+  // gc_required. We can't leave a partly initialized FixedArray behind,
+  // so pessimistically fill it with holes now.
+  Label initialization_loop, initialization_loop_entry;
+  __ jmp(&initialization_loop_entry, Label::kNear);
+  __ bind(&initialization_loop);
+  __ movp(FieldOperand(r11, r9, times_pointer_size, FixedArray::kHeaderSize),
+          rdi);
+  __ bind(&initialization_loop_entry);
+  __ decp(r9);
+  __ j(not_sign, &initialization_loop);
+
+  __ SmiToInteger32(r9, FieldOperand(r8, FixedDoubleArray::kLengthOffset));
   __ jmp(&entry);
 
   // Call into runtime if GC is required.
diff --git a/src/x64/debug-x64.cc b/src/x64/debug-x64.cc
index c8b7c22..c8f9456 100644
--- a/src/x64/debug-x64.cc
+++ b/src/x64/debug-x64.cc
@@ -164,7 +164,11 @@
   // Register state for IC load call (from ic-x64.cc).
   Register receiver = LoadDescriptor::ReceiverRegister();
   Register name = LoadDescriptor::NameRegister();
-  Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit(), 0, false);
+  RegList regs = receiver.bit() | name.bit();
+  if (FLAG_vector_ics) {
+    regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
+  }
+  Generate_DebugBreakCallHelper(masm, regs, 0, false);
 }
 
 
diff --git a/src/x64/deoptimizer-x64.cc b/src/x64/deoptimizer-x64.cc
index 16b0cdc..54fe9b0 100644
--- a/src/x64/deoptimizer-x64.cc
+++ b/src/x64/deoptimizer-x64.cc
@@ -23,6 +23,12 @@
 }
 
 
+void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
+  // Empty because there is no need for relocation information for the code
+  // patching in Deoptimizer::PatchCodeForDeoptimization below.
+}
+
+
 void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
   // Invalidate the relocation information, as it will become invalid by the
   // code patching below, and is not needed any more.
diff --git a/src/x64/disasm-x64.cc b/src/x64/disasm-x64.cc
index 2b8fc2d..75adc89 100644
--- a/src/x64/disasm-x64.cc
+++ b/src/x64/disasm-x64.cc
@@ -148,6 +148,8 @@
   ESCAPE_PREFIX = 0x0F,
   OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
   ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
+  VEX3_PREFIX = 0xC4,
+  VEX2_PREFIX = 0xC5,
   REPNE_PREFIX = 0xF2,
   REP_PREFIX = 0xF3,
   REPEQ_PREFIX = REP_PREFIX
@@ -252,7 +254,7 @@
     LAZY_INSTANCE_INITIALIZER;
 
 
-static InstructionDesc cmov_instructions[16] = {
+static const InstructionDesc cmov_instructions[16] = {
   {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
   {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
   {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
@@ -290,11 +292,14 @@
                       ABORT_ON_UNIMPLEMENTED_OPCODE)
       : converter_(converter),
         tmp_buffer_pos_(0),
-        abort_on_unimplemented_(
-            unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE),
+        abort_on_unimplemented_(unimplemented_action ==
+                                ABORT_ON_UNIMPLEMENTED_OPCODE),
         rex_(0),
         operand_size_(0),
         group_1_prefix_(0),
+        vex_byte0_(0),
+        vex_byte1_(0),
+        vex_byte2_(0),
         byte_size_operand_(false),
         instruction_table_(instruction_table.Pointer()) {
     tmp_buffer_[0] = '\0';
@@ -323,6 +328,9 @@
   byte rex_;
   byte operand_size_;  // 0x66 or (if no group 3 prefix is present) 0x0.
   byte group_1_prefix_;  // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
+  byte vex_byte0_;       // 0xc4 or 0xc5
+  byte vex_byte1_;
+  byte vex_byte2_;  // only for 3 bytes vex prefix
   // Byte size operand override.
   bool byte_size_operand_;
   const InstructionTable* const instruction_table_;
@@ -345,6 +353,51 @@
 
   bool rex_w() { return (rex_ & 0x08) != 0; }
 
+  bool vex_128() {
+    DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
+    byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
+    return (checked & 4) != 1;
+  }
+
+  bool vex_66() {
+    DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
+    byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
+    return (checked & 3) == 1;
+  }
+
+  bool vex_f3() {
+    DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
+    byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
+    return (checked & 3) == 2;
+  }
+
+  bool vex_f2() {
+    DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
+    byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
+    return (checked & 3) == 3;
+  }
+
+  bool vex_0f() {
+    if (vex_byte0_ == VEX2_PREFIX) return true;
+    return (vex_byte1_ & 3) == 1;
+  }
+
+  bool vex_0f38() {
+    if (vex_byte0_ == VEX2_PREFIX) return false;
+    return (vex_byte1_ & 3) == 2;
+  }
+
+  bool vex_0f3a() {
+    if (vex_byte0_ == VEX2_PREFIX) return false;
+    return (vex_byte1_ & 3) == 3;
+  }
+
+  int vex_vreg() {
+    DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
+    byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
+    return ~(checked >> 3) & 0xf;
+  }
+
   OperandSize operand_size() {
     if (byte_size_operand_) return OPERAND_BYTE_SIZE;
     if (rex_w()) return OPERAND_QUADWORD_SIZE;
@@ -356,6 +409,8 @@
     return "bwlq"[operand_size()];
   }
 
+  char float_size_code() { return "sd"[rex_w()]; }
+
   const char* NameOfCPURegister(int reg) const {
     return converter_.NameOfCPURegister(reg);
   }
@@ -414,6 +469,7 @@
   int FPUInstruction(byte* data);
   int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
   int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
+  int AVXInstruction(byte* data);
   void AppendToBuffer(const char* format, ...);
 
   void UnimplementedInstruction() {
@@ -709,65 +765,62 @@
 
 int DisassemblerX64::ShiftInstruction(byte* data) {
   byte op = *data & (~1);
+  int count = 1;
   if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
     UnimplementedInstruction();
-    return 1;
+    return count;
   }
-  byte modrm = *(data + 1);
-  int mod, regop, rm;
-  get_modrm(modrm, &mod, &regop, &rm);
-  regop &= 0x7;  // The REX.R bit does not affect the operation.
-  int imm8 = -1;
-  int num_bytes = 2;
-  if (mod != 3) {
-    UnimplementedInstruction();
-    return num_bytes;
+  // Print mneumonic.
+  {
+    byte modrm = *(data + count);
+    int mod, regop, rm;
+    get_modrm(modrm, &mod, &regop, &rm);
+    regop &= 0x7;  // The REX.R bit does not affect the operation.
+    const char* mnem = NULL;
+    switch (regop) {
+      case 0:
+        mnem = "rol";
+        break;
+      case 1:
+        mnem = "ror";
+        break;
+      case 2:
+        mnem = "rcl";
+        break;
+      case 3:
+        mnem = "rcr";
+        break;
+      case 4:
+        mnem = "shl";
+        break;
+      case 5:
+        mnem = "shr";
+        break;
+      case 7:
+        mnem = "sar";
+        break;
+      default:
+        UnimplementedInstruction();
+        return count + 1;
+    }
+    DCHECK_NE(NULL, mnem);
+    AppendToBuffer("%s%c ", mnem, operand_size_code());
   }
-  const char* mnem = NULL;
-  switch (regop) {
-    case 0:
-      mnem = "rol";
-      break;
-    case 1:
-      mnem = "ror";
-      break;
-    case 2:
-      mnem = "rcl";
-      break;
-    case 3:
-      mnem = "rcr";
-      break;
-    case 4:
-      mnem = "shl";
-      break;
-    case 5:
-      mnem = "shr";
-      break;
-    case 7:
-      mnem = "sar";
-      break;
-    default:
-      UnimplementedInstruction();
-      return num_bytes;
-  }
-  DCHECK_NE(NULL, mnem);
-  if (op == 0xD0) {
-    imm8 = 1;
-  } else if (op == 0xC0) {
-    imm8 = *(data + 2);
-    num_bytes = 3;
-  }
-  AppendToBuffer("%s%c %s,",
-                 mnem,
-                 operand_size_code(),
-                 byte_size_operand_ ? NameOfByteCPURegister(rm)
-                                    : NameOfCPURegister(rm));
+  count += PrintRightOperand(data + count);
   if (op == 0xD2) {
-    AppendToBuffer("cl");
+    AppendToBuffer(", cl");
   } else {
-    AppendToBuffer("%d", imm8);
+    int imm8 = -1;
+    if (op == 0xD0) {
+      imm8 = 1;
+    } else {
+      DCHECK_EQ(0xC0, op);
+      imm8 = *(data + count);
+      count++;
+    }
+    AppendToBuffer(", %d", imm8);
   }
-  return num_bytes;
+  return count;
 }
 
 
@@ -814,6 +867,111 @@
 }
 
 
+int DisassemblerX64::AVXInstruction(byte* data) {
+  byte opcode = *data;
+  byte* current = data + 1;
+  if (vex_66() && vex_0f38()) {
+    int mod, regop, rm, vvvv = vex_vreg();
+    get_modrm(*current, &mod, &regop, &rm);
+    switch (opcode) {
+      case 0x99:
+        AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xa9:
+        AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xb9:
+        AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x9b:
+        AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xab:
+        AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xbb:
+        AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x9d:
+        AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xad:
+        AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xbd:
+        AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x9f:
+        AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xaf:
+        AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0xbf:
+        AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
+                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      default:
+        UnimplementedInstruction();
+    }
+  } else if (vex_f2() && vex_0f()) {
+    int mod, regop, rm, vvvv = vex_vreg();
+    get_modrm(*current, &mod, &regop, &rm);
+    switch (opcode) {
+      case 0x58:
+        AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x59:
+        AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x5c:
+        AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x5e:
+        AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      default:
+        UnimplementedInstruction();
+    }
+  } else {
+    UnimplementedInstruction();
+  }
+
+  return static_cast<int>(current - data);
+}
+
+
 // Returns number of bytes used, including *data.
 int DisassemblerX64::FPUInstruction(byte* data) {
   byte escape_opcode = *data;
@@ -1069,10 +1227,15 @@
       } else if (opcode == 0x50) {
         AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
         current += PrintRightXMMOperand(current);
+      } else if (opcode == 0x72) {
+        current += 1;
+        AppendToBuffer("%s,%s,%d", (regop == 6) ? "pslld" : "psrld",
+                       NameOfXMMRegister(rm), *current & 0x7f);
+        current += 1;
       } else if (opcode == 0x73) {
         current += 1;
-        DCHECK(regop == 6);
-        AppendToBuffer("psllq,%s,%d", NameOfXMMRegister(rm), *current & 0x7f);
+        AppendToBuffer("%s,%s,%d", (regop == 6) ? "psllq" : "psrlq",
+                       NameOfXMMRegister(rm), *current & 0x7f);
         current += 1;
       } else {
         const char* mnemonic = "?";
@@ -1086,6 +1249,8 @@
           mnemonic = "ucomisd";
         } else if (opcode == 0x2F) {
           mnemonic = "comisd";
+        } else if (opcode == 0x76) {
+          mnemonic = "pcmpeqd";
         } else {
           UnimplementedInstruction();
         }
@@ -1185,6 +1350,16 @@
       AppendToBuffer("cvttss2si%c %s,",
           operand_size_code(), NameOfCPURegister(regop));
       current += PrintRightXMMOperand(current);
+    } else if (opcode == 0x58) {
+      int mod, regop, rm;
+      get_modrm(*current, &mod, &regop, &rm);
+      AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
+      current += PrintRightXMMOperand(current);
+    } else if (opcode == 0x59) {
+      int mod, regop, rm;
+      get_modrm(*current, &mod, &regop, &rm);
+      AppendToBuffer("mulss %s,", NameOfXMMRegister(regop));
+      current += PrintRightXMMOperand(current);
     } else if (opcode == 0x5A) {
       // CVTSS2SD:
       // Convert scalar single-precision FP to scalar double-precision FP.
@@ -1192,6 +1367,16 @@
       get_modrm(*current, &mod, &regop, &rm);
       AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
       current += PrintRightXMMOperand(current);
+    } else if (opcode == 0x5c) {
+      int mod, regop, rm;
+      get_modrm(*current, &mod, &regop, &rm);
+      AppendToBuffer("subss %s,", NameOfXMMRegister(regop));
+      current += PrintRightXMMOperand(current);
+    } else if (opcode == 0x5e) {
+      int mod, regop, rm;
+      get_modrm(*current, &mod, &regop, &rm);
+      AppendToBuffer("divss %s,", NameOfXMMRegister(regop));
+      current += PrintRightXMMOperand(current);
     } else if (opcode == 0x7E) {
       int mod, regop, rm;
       get_modrm(*current, &mod, &regop, &rm);
@@ -1230,6 +1415,11 @@
     current += PrintRightXMMOperand(current);
     AppendToBuffer(",%s", NameOfXMMRegister(regop));
 
+  } else if (opcode == 0x2e) {
+    int mod, regop, rm;
+    get_modrm(*current, &mod, &regop, &rm);
+    AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
+    current += PrintRightXMMOperand(current);
   } else if (opcode == 0xA2) {
     // CPUID
     AppendToBuffer("%s", mnemonic);
@@ -1383,99 +1573,114 @@
       if (rex_w()) AppendToBuffer("REX.W ");
     } else if ((current & 0xFE) == 0xF2) {  // Group 1 prefix (0xF2 or 0xF3).
       group_1_prefix_ = current;
+    } else if (current == VEX3_PREFIX) {
+      vex_byte0_ = current;
+      vex_byte1_ = *(data + 1);
+      vex_byte2_ = *(data + 2);
+      setRex(0x40 | (~(vex_byte1_ >> 5) & 7) | ((vex_byte2_ >> 4) & 8));
+      data += 2;
+    } else if (current == VEX2_PREFIX) {
+      vex_byte0_ = current;
+      vex_byte1_ = *(data + 1);
+      setRex(0x40 | (~(vex_byte1_ >> 5) & 4));
+      data++;
     } else {  // Not a prefix - an opcode.
       break;
     }
     data++;
   }
 
-  const InstructionDesc& idesc = instruction_table_->Get(current);
-  byte_size_operand_ = idesc.byte_size_operation;
-  switch (idesc.type) {
-    case ZERO_OPERANDS_INSTR:
-      if (current >= 0xA4 && current <= 0xA7) {
-        // String move or compare operations.
-        if (group_1_prefix_ == REP_PREFIX) {
-          // REP.
-          AppendToBuffer("rep ");
+  // Decode AVX instructions.
+  if (vex_byte0_ != 0) {
+    processed = true;
+    data += AVXInstruction(data);
+  } else {
+    const InstructionDesc& idesc = instruction_table_->Get(current);
+    byte_size_operand_ = idesc.byte_size_operation;
+    switch (idesc.type) {
+      case ZERO_OPERANDS_INSTR:
+        if (current >= 0xA4 && current <= 0xA7) {
+          // String move or compare operations.
+          if (group_1_prefix_ == REP_PREFIX) {
+            // REP.
+            AppendToBuffer("rep ");
+          }
+          if (rex_w()) AppendToBuffer("REX.W ");
+          AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
+        } else {
+          AppendToBuffer("%s", idesc.mnem, operand_size_code());
         }
-        if (rex_w()) AppendToBuffer("REX.W ");
-        AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
-      } else {
-        AppendToBuffer("%s", idesc.mnem, operand_size_code());
+        data++;
+        break;
+
+      case TWO_OPERANDS_INSTR:
+        data++;
+        data += PrintOperands(idesc.mnem, idesc.op_order_, data);
+        break;
+
+      case JUMP_CONDITIONAL_SHORT_INSTR:
+        data += JumpConditionalShort(data);
+        break;
+
+      case REGISTER_INSTR:
+        AppendToBuffer("%s%c %s", idesc.mnem, operand_size_code(),
+                       NameOfCPURegister(base_reg(current & 0x07)));
+        data++;
+        break;
+      case PUSHPOP_INSTR:
+        AppendToBuffer("%s %s", idesc.mnem,
+                       NameOfCPURegister(base_reg(current & 0x07)));
+        data++;
+        break;
+      case MOVE_REG_INSTR: {
+        byte* addr = NULL;
+        switch (operand_size()) {
+          case OPERAND_WORD_SIZE:
+            addr =
+                reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
+            data += 3;
+            break;
+          case OPERAND_DOUBLEWORD_SIZE:
+            addr =
+                reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1));
+            data += 5;
+            break;
+          case OPERAND_QUADWORD_SIZE:
+            addr =
+                reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
+            data += 9;
+            break;
+          default:
+            UNREACHABLE();
+        }
+        AppendToBuffer("mov%c %s,%s", operand_size_code(),
+                       NameOfCPURegister(base_reg(current & 0x07)),
+                       NameOfAddress(addr));
+        break;
       }
-      data++;
-      break;
 
-    case TWO_OPERANDS_INSTR:
-      data++;
-      data += PrintOperands(idesc.mnem, idesc.op_order_, data);
-      break;
-
-    case JUMP_CONDITIONAL_SHORT_INSTR:
-      data += JumpConditionalShort(data);
-      break;
-
-    case REGISTER_INSTR:
-      AppendToBuffer("%s%c %s",
-                     idesc.mnem,
-                     operand_size_code(),
-                     NameOfCPURegister(base_reg(current & 0x07)));
-      data++;
-      break;
-    case PUSHPOP_INSTR:
-      AppendToBuffer("%s %s",
-                     idesc.mnem,
-                     NameOfCPURegister(base_reg(current & 0x07)));
-      data++;
-      break;
-    case MOVE_REG_INSTR: {
-      byte* addr = NULL;
-      switch (operand_size()) {
-        case OPERAND_WORD_SIZE:
-          addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
-          data += 3;
-          break;
-        case OPERAND_DOUBLEWORD_SIZE:
-          addr =
-              reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1));
-          data += 5;
-          break;
-        case OPERAND_QUADWORD_SIZE:
-          addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
-          data += 9;
-          break;
-        default:
-          UNREACHABLE();
+      case CALL_JUMP_INSTR: {
+        byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
+        AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
+        data += 5;
+        break;
       }
-      AppendToBuffer("mov%c %s,%s",
-                     operand_size_code(),
-                     NameOfCPURegister(base_reg(current & 0x07)),
-                     NameOfAddress(addr));
-      break;
+
+      case SHORT_IMMEDIATE_INSTR: {
+        byte* addr =
+            reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
+        AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
+        data += 5;
+        break;
+      }
+
+      case NO_INSTR:
+        processed = false;
+        break;
+
+      default:
+        UNIMPLEMENTED();  // This type is not implemented.
     }
-
-    case CALL_JUMP_INSTR: {
-      byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
-      AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
-      data += 5;
-      break;
-    }
-
-    case SHORT_IMMEDIATE_INSTR: {
-      byte* addr =
-          reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
-      AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
-      data += 5;
-      break;
-    }
-
-    case NO_INSTR:
-      processed = false;
-      break;
-
-    default:
-      UNIMPLEMENTED();  // This type is not implemented.
   }
 
   // The first byte didn't match any of the simple opcodes, so we
@@ -1489,15 +1694,15 @@
 
       case 0x69:  // fall through
       case 0x6B: {
-        int mod, regop, rm;
-        get_modrm(*(data + 1), &mod, &regop, &rm);
-        int32_t imm = *data == 0x6B ? *(data + 2)
-            : *reinterpret_cast<int32_t*>(data + 2);
-        AppendToBuffer("imul%c %s,%s,0x%x",
-                       operand_size_code(),
-                       NameOfCPURegister(regop),
-                       NameOfCPURegister(rm), imm);
-        data += 2 + (*data == 0x6B ? 1 : 4);
+        int count = 1;
+        count += PrintOperands("imul", REG_OPER_OP_ORDER, data + count);
+        AppendToBuffer(",0x");
+        if (*data == 0x69) {
+          count += PrintImmediate(data + count, operand_size());
+        } else {
+          count += PrintImmediate(data + count, OPERAND_BYTE_SIZE);
+        }
+        data += count;
         break;
       }
 
@@ -1811,19 +2016,19 @@
 //------------------------------------------------------------------------------
 
 
-static const char* cpu_regs[16] = {
+static const char* const cpu_regs[16] = {
   "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
 };
 
 
-static const char* byte_cpu_regs[16] = {
+static const char* const byte_cpu_regs[16] = {
   "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
   "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
 };
 
 
-static const char* xmm_regs[16] = {
+static const char* const xmm_regs[16] = {
   "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
   "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
 };
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 0f787b2..24747ee 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -187,10 +187,10 @@
     Comment cmnt(masm_, "[ Allocate context");
     bool need_write_barrier = true;
     // Argument to NewContext is the function, which is still in rdi.
-    if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
+    if (FLAG_harmony_scoping && info->scope()->is_script_scope()) {
       __ Push(rdi);
       __ Push(info->scope()->GetScopeInfo());
-      __ CallRuntime(Runtime::kNewGlobalContext, 2);
+      __ CallRuntime(Runtime::kNewScriptContext, 2);
     } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
       FastNewContextStub stub(isolate(), heap_slots);
       __ CallStub(&stub);
@@ -895,7 +895,7 @@
   EmitDebugCheckDeclarationContext(variable);
 
   // Load instance object.
-  __ LoadContext(rax, scope_->ContextChainLength(scope_->GlobalScope()));
+  __ LoadContext(rax, scope_->ContextChainLength(scope_->ScriptScope()));
   __ movp(rax, ContextOperand(rax, variable->interface()->Index()));
   __ movp(rax, ContextOperand(rax, Context::EXTENSION_INDEX));
 
@@ -1058,7 +1058,7 @@
 
 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
   Comment cmnt(masm_, "[ ForInStatement");
-  int slot = stmt->ForInFeedbackSlot();
+  FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
   SetStatementPosition(stmt);
 
   Label loop, exit;
@@ -1067,6 +1067,7 @@
 
   // Get the object to enumerate over. If the object is null or undefined, skip
   // over the loop.  See ECMA-262 version 5, section 12.6.4.
+  SetExpressionPosition(stmt->enumerable());
   VisitForAccumulatorValue(stmt->enumerable());
   __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
   __ j(equal, &exit);
@@ -1086,6 +1087,7 @@
   __ Push(rax);
   __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
   __ bind(&done_convert);
+  PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
   __ Push(rax);
 
   // Check for proxies.
@@ -1110,6 +1112,7 @@
   __ bind(&call_runtime);
   __ Push(rax);  // Duplicate the enumerable object on the stack.
   __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
+  PrepareForBailoutForId(stmt->EnumId(), TOS_REG);
 
   // If we got a map from the runtime call, we can do a fast
   // modification check. Otherwise, we got a fixed array, and we have
@@ -1149,7 +1152,8 @@
 
   // No need for a write barrier, we are storing a Smi in the feedback vector.
   __ Move(rbx, FeedbackVector());
-  __ Move(FieldOperand(rbx, FixedArray::OffsetOfElementAt(slot)),
+  int vector_index = FeedbackVector()->GetIndex(slot);
+  __ Move(FieldOperand(rbx, FixedArray::OffsetOfElementAt(vector_index)),
           TypeFeedbackVector::MegamorphicSentinel(isolate()));
   __ Move(rbx, Smi::FromInt(1));  // Smi indicates slow check
   __ movp(rcx, Operand(rsp, 0 * kPointerSize));  // Get enumerated object
@@ -1167,6 +1171,8 @@
   // Generate code for doing the condition check.
   PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
   __ bind(&loop);
+  SetExpressionPosition(stmt->each());
+
   __ movp(rax, Operand(rsp, 0 * kPointerSize));  // Get the current index.
   __ cmpp(rax, Operand(rsp, 1 * kPointerSize));  // Compare to the array length.
   __ j(above_equal, loop_statement.break_label());
@@ -1236,48 +1242,6 @@
 }
 
 
-void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
-  Comment cmnt(masm_, "[ ForOfStatement");
-  SetStatementPosition(stmt);
-
-  Iteration loop_statement(this, stmt);
-  increment_loop_depth();
-
-  // var iterator = iterable[Symbol.iterator]();
-  VisitForEffect(stmt->assign_iterator());
-
-  // Loop entry.
-  __ bind(loop_statement.continue_label());
-
-  // result = iterator.next()
-  VisitForEffect(stmt->next_result());
-
-  // if (result.done) break;
-  Label result_not_done;
-  VisitForControl(stmt->result_done(),
-                  loop_statement.break_label(),
-                  &result_not_done,
-                  &result_not_done);
-  __ bind(&result_not_done);
-
-  // each = result.value
-  VisitForEffect(stmt->assign_each());
-
-  // Generate code for the body of the loop.
-  Visit(stmt->body());
-
-  // Check stack before looping.
-  PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
-  EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
-  __ jmp(loop_statement.continue_label());
-
-  // Exit and decrement the loop depth.
-  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
-  __ bind(loop_statement.break_label());
-  decrement_loop_depth();
-}
-
-
 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
                                        bool pretenure) {
   // Use the fast case closure allocation code that allocates in new
@@ -1321,7 +1285,14 @@
   Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
   __ Move(LoadDescriptor::NameRegister(), home_object_symbol);
 
-  CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  if (FLAG_vector_ics) {
+    __ Move(VectorLoadICDescriptor::SlotRegister(),
+            SmiFromSlot(expr->HomeObjectFeedbackSlot()));
+    CallLoadIC(NOT_CONTEXTUAL);
+  } else {
+    CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  }
+
 
   __ Cmp(rax, isolate()->factory()->undefined_value());
   Label done;
@@ -1331,6 +1302,19 @@
 }
 
 
+void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
+                                                  int offset) {
+  if (NeedsHomeObject(initializer)) {
+    __ movp(StoreDescriptor::ReceiverRegister(), Operand(rsp, 0));
+    __ Move(StoreDescriptor::NameRegister(),
+            isolate()->factory()->home_object_symbol());
+    __ movp(StoreDescriptor::ValueRegister(),
+            Operand(rsp, offset * kPointerSize));
+    CallStoreIC();
+  }
+}
+
+
 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
                                                       TypeofState typeof_state,
                                                       Label* slow) {
@@ -1386,7 +1370,7 @@
   __ Move(LoadDescriptor::NameRegister(), proxy->var()->name());
   if (FLAG_vector_ics) {
     __ Move(VectorLoadICDescriptor::SlotRegister(),
-            Smi::FromInt(proxy->VariableFeedbackSlot()));
+            SmiFromSlot(proxy->VariableFeedbackSlot()));
   }
 
   ContextualMode mode = (typeof_state == INSIDE_TYPEOF)
@@ -1472,7 +1456,7 @@
       __ movp(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
       if (FLAG_vector_ics) {
         __ Move(VectorLoadICDescriptor::SlotRegister(),
-                Smi::FromInt(proxy->VariableFeedbackSlot()));
+                SmiFromSlot(proxy->VariableFeedbackSlot()));
       }
       CallLoadIC(CONTEXTUAL);
       context()->Plug(rax);
@@ -1655,6 +1639,7 @@
     FastCloneShallowObjectStub stub(isolate(), properties_count);
     __ CallStub(&stub);
   }
+  PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
 
   // If result_saved is true the result is on top of the stack.  If
   // result_saved is false the result is in rax.
@@ -1683,6 +1668,8 @@
         DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
         // Fall through.
       case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             VisitForAccumulatorValue(value);
@@ -1691,6 +1678,14 @@
             __ movp(StoreDescriptor::ReceiverRegister(), Operand(rsp, 0));
             CallStoreIC(key->LiteralFeedbackId());
             PrepareForBailoutForId(key->id(), NO_REGISTERS);
+
+            if (NeedsHomeObject(value)) {
+              __ movp(StoreDescriptor::ReceiverRegister(), rax);
+              __ Move(StoreDescriptor::NameRegister(),
+                      isolate()->factory()->home_object_symbol());
+              __ movp(StoreDescriptor::ValueRegister(), Operand(rsp, 0));
+              CallStoreIC();
+            }
           } else {
             VisitForEffect(value);
           }
@@ -1700,6 +1695,7 @@
         VisitForStackValue(key);
         VisitForStackValue(value);
         if (property->emit_store()) {
+          EmitSetHomeObjectIfNeeded(value, 2);
           __ Push(Smi::FromInt(SLOPPY));  // Strict mode
           __ CallRuntime(Runtime::kSetProperty, 4);
         } else {
@@ -1710,7 +1706,7 @@
         __ Push(Operand(rsp, 0));  // Duplicate receiver.
         VisitForStackValue(value);
         if (property->emit_store()) {
-          __ CallRuntime(Runtime::kSetPrototype, 2);
+          __ CallRuntime(Runtime::kInternalSetPrototype, 2);
         } else {
           __ Drop(2);
         }
@@ -1732,7 +1728,9 @@
     __ Push(Operand(rsp, 0));  // Duplicate receiver.
     VisitForStackValue(it->first);
     EmitAccessor(it->second->getter);
+    EmitSetHomeObjectIfNeeded(it->second->getter, 2);
     EmitAccessor(it->second->setter);
+    EmitSetHomeObjectIfNeeded(it->second->setter, 3);
     __ Push(Smi::FromInt(NONE));
     __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
   }
@@ -1847,16 +1845,8 @@
 
   Comment cmnt(masm_, "[ Assignment");
 
-  // Left-hand side can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* property = expr->target()->AsProperty();
-  if (property != NULL) {
-    assign_type = (property->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(property);
 
   // Evaluate LHS expression.
   switch (assign_type) {
@@ -1872,6 +1862,27 @@
         VisitForStackValue(property->obj());
       }
       break;
+    case NAMED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Push(result_register());
+      if (expr->is_compound()) {
+        __ Push(MemOperand(rsp, kPointerSize));
+        __ Push(result_register());
+      }
+      break;
+    case KEYED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForAccumulatorValue(property->key());
+      __ Push(result_register());
+      if (expr->is_compound()) {
+        __ Push(MemOperand(rsp, 2 * kPointerSize));
+        __ Push(MemOperand(rsp, 2 * kPointerSize));
+        __ Push(result_register());
+      }
+      break;
     case KEYED_PROPERTY: {
       if (expr->is_compound()) {
         VisitForStackValue(property->obj());
@@ -1899,6 +1910,14 @@
           EmitNamedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
           break;
+        case NAMED_SUPER_PROPERTY:
+          EmitNamedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
+        case KEYED_SUPER_PROPERTY:
+          EmitKeyedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
         case KEYED_PROPERTY:
           EmitKeyedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
@@ -1944,6 +1963,14 @@
     case NAMED_PROPERTY:
       EmitNamedPropertyAssignment(expr);
       break;
+    case NAMED_SUPER_PROPERTY:
+      EmitNamedSuperPropertyStore(property);
+      context()->Plug(rax);
+      break;
+    case KEYED_SUPER_PROPERTY:
+      EmitKeyedSuperPropertyStore(property);
+      context()->Plug(rax);
+      break;
     case KEYED_PROPERTY:
       EmitKeyedPropertyAssignment(expr);
       break;
@@ -2077,7 +2104,7 @@
       __ movp(load_receiver, Operand(rsp, kPointerSize));
       if (FLAG_vector_ics) {
         __ Move(VectorLoadICDescriptor::SlotRegister(),
-                Smi::FromInt(expr->KeyedLoadFeedbackSlot()));
+                SmiFromSlot(expr->KeyedLoadFeedbackSlot()));
       }
       Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
       CallIC(ic, TypeFeedbackId::None());
@@ -2096,7 +2123,7 @@
       __ LoadRoot(load_name, Heap::kdone_stringRootIndex);  // "done"
       if (FLAG_vector_ics) {
         __ Move(VectorLoadICDescriptor::SlotRegister(),
-                Smi::FromInt(expr->DoneFeedbackSlot()));
+                SmiFromSlot(expr->DoneFeedbackSlot()));
       }
       CallLoadIC(NOT_CONTEXTUAL);                           // rax=result.done
       Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
@@ -2109,7 +2136,7 @@
       __ LoadRoot(load_name, Heap::kvalue_stringRootIndex);  // "value"
       if (FLAG_vector_ics) {
         __ Move(VectorLoadICDescriptor::SlotRegister(),
-                Smi::FromInt(expr->ValueFeedbackSlot()));
+                SmiFromSlot(expr->ValueFeedbackSlot()));
       }
       CallLoadIC(NOT_CONTEXTUAL);                        // result.value in rax
       context()->DropAndPlug(2, rax);                    // drop iter and g
@@ -2130,15 +2157,6 @@
   VisitForAccumulatorValue(value);
   __ Pop(rbx);
 
-  // Check generator state.
-  Label wrong_state, closed_state, done;
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
-  __ SmiCompare(FieldOperand(rbx, JSGeneratorObject::kContinuationOffset),
-                Smi::FromInt(0));
-  __ j(equal, &closed_state);
-  __ j(less, &wrong_state);
-
   // Load suspended function and context.
   __ movp(rsi, FieldOperand(rbx, JSGeneratorObject::kContextOffset));
   __ movp(rdi, FieldOperand(rbx, JSGeneratorObject::kFunctionOffset));
@@ -2160,7 +2178,7 @@
 
   // Enter a new JavaScript frame, and initialize its slots as they were when
   // the generator was suspended.
-  Label resume_frame;
+  Label resume_frame, done;
   __ bind(&push_frame);
   __ call(&resume_frame);
   __ jmp(&done);
@@ -2207,25 +2225,6 @@
   // Not reached: the runtime call returns elsewhere.
   __ Abort(kGeneratorFailedToResume);
 
-  // Reach here when generator is closed.
-  __ bind(&closed_state);
-  if (resume_mode == JSGeneratorObject::NEXT) {
-    // Return completed iterator result when generator is closed.
-    __ PushRoot(Heap::kUndefinedValueRootIndex);
-    // Pop value from top-of-stack slot; box result into result register.
-    EmitCreateIteratorResult(true);
-  } else {
-    // Throw the provided value.
-    __ Push(rax);
-    __ CallRuntime(Runtime::kThrow, 1);
-  }
-  __ jmp(&done);
-
-  // Throw error if we attempt to operate on a running generator.
-  __ bind(&wrong_state);
-  __ Push(rbx);
-  __ CallRuntime(Runtime::kThrowGeneratorStateError, 1);
-
   __ bind(&done);
   context()->Plug(result_register());
 }
@@ -2235,22 +2234,25 @@
   Label gc_required;
   Label allocated;
 
-  Handle<Map> map(isolate()->native_context()->iterator_result_map());
+  const int instance_size = 5 * kPointerSize;
+  DCHECK_EQ(isolate()->native_context()->iterator_result_map()->instance_size(),
+            instance_size);
 
-  __ Allocate(map->instance_size(), rax, rcx, rdx, &gc_required, TAG_OBJECT);
+  __ Allocate(instance_size, rax, rcx, rdx, &gc_required, TAG_OBJECT);
   __ jmp(&allocated);
 
   __ bind(&gc_required);
-  __ Push(Smi::FromInt(map->instance_size()));
+  __ Push(Smi::FromInt(instance_size));
   __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
   __ movp(context_register(),
           Operand(rbp, StandardFrameConstants::kContextOffset));
 
   __ bind(&allocated);
-  __ Move(rbx, map);
+  __ movp(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
+  __ movp(rbx, FieldOperand(rbx, GlobalObject::kNativeContextOffset));
+  __ movp(rbx, ContextOperand(rbx, Context::ITERATOR_RESULT_MAP_INDEX));
   __ Pop(rcx);
   __ Move(rdx, isolate()->factory()->ToBoolean(done));
-  DCHECK_EQ(map->instance_size(), 5 * kPointerSize);
   __ movp(FieldOperand(rax, HeapObject::kMapOffset), rbx);
   __ Move(FieldOperand(rax, JSObject::kPropertiesOffset),
           isolate()->factory()->empty_fixed_array());
@@ -2271,10 +2273,12 @@
 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
+  DCHECK(!prop->IsSuperAccess());
+
   __ Move(LoadDescriptor::NameRegister(), key->value());
   if (FLAG_vector_ics) {
     __ Move(VectorLoadICDescriptor::SlotRegister(),
-            Smi::FromInt(prop->PropertyFeedbackSlot()));
+            SmiFromSlot(prop->PropertyFeedbackSlot()));
     CallLoadIC(NOT_CONTEXTUAL);
   } else {
     CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
@@ -2283,15 +2287,12 @@
 
 
 void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
   DCHECK(!key->value()->IsSmi());
   DCHECK(prop->IsSuperAccess());
 
-  SuperReference* super_ref = prop->obj()->AsSuperReference();
-  EmitLoadHomeObject(super_ref);
-  __ Push(rax);
-  VisitForStackValue(super_ref->this_var());
   __ Push(key->value());
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 }
@@ -2302,7 +2303,7 @@
   Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
   if (FLAG_vector_ics) {
     __ Move(VectorLoadICDescriptor::SlotRegister(),
-            Smi::FromInt(prop->PropertyFeedbackSlot()));
+            SmiFromSlot(prop->PropertyFeedbackSlot()));
     CallIC(ic);
   } else {
     CallIC(ic, prop->PropertyFeedbackId());
@@ -2310,6 +2311,14 @@
 }
 
 
+void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object, key.
+  SetSourcePosition(prop->position());
+
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+}
+
+
 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
                                               Token::Value op,
                                               OverwriteMode mode,
@@ -2371,6 +2380,61 @@
 }
 
 
+void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
+  // Constructor is in rax.
+  DCHECK(lit != NULL);
+  __ Push(rax);
+
+  // No access check is needed here since the constructor is created by the
+  // class literal.
+  Register scratch = rbx;
+  __ movp(scratch, FieldOperand(rax, JSFunction::kPrototypeOrInitialMapOffset));
+  __ Push(scratch);
+
+  for (int i = 0; i < lit->properties()->length(); i++) {
+    ObjectLiteral::Property* property = lit->properties()->at(i);
+    Literal* key = property->key()->AsLiteral();
+    Expression* value = property->value();
+    DCHECK(key != NULL);
+
+    if (property->is_static()) {
+      __ Push(Operand(rsp, kPointerSize));  // constructor
+    } else {
+      __ Push(Operand(rsp, 0));  // prototype
+    }
+    VisitForStackValue(key);
+    VisitForStackValue(value);
+    EmitSetHomeObjectIfNeeded(value, 2);
+
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT:
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+      case ObjectLiteral::Property::COMPUTED:
+      case ObjectLiteral::Property::PROTOTYPE:
+        __ CallRuntime(Runtime::kDefineClassMethod, 3);
+        break;
+
+      case ObjectLiteral::Property::GETTER:
+        __ CallRuntime(Runtime::kDefineClassGetter, 3);
+        break;
+
+      case ObjectLiteral::Property::SETTER:
+        __ CallRuntime(Runtime::kDefineClassSetter, 3);
+        break;
+
+      default:
+        UNREACHABLE();
+    }
+  }
+
+  // prototype
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+
+  // constructor
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+}
+
+
 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
                                      Token::Value op,
                                      OverwriteMode mode) {
@@ -2386,16 +2450,8 @@
 void FullCodeGenerator::EmitAssignment(Expression* expr) {
   DCHECK(expr->IsValidReferenceExpression());
 
-  // Left-hand side can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* prop = expr->AsProperty();
-  if (prop != NULL) {
-    assign_type = (prop->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(prop);
 
   switch (assign_type) {
     case VARIABLE: {
@@ -2414,6 +2470,42 @@
       CallStoreIC();
       break;
     }
+    case NAMED_SUPER_PROPERTY: {
+      __ Push(rax);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      // stack: value, this; rax: home_object
+      Register scratch = rcx;
+      Register scratch2 = rdx;
+      __ Move(scratch, result_register());               // home_object
+      __ movp(rax, MemOperand(rsp, kPointerSize));       // value
+      __ movp(scratch2, MemOperand(rsp, 0));             // this
+      __ movp(MemOperand(rsp, kPointerSize), scratch2);  // this
+      __ movp(MemOperand(rsp, 0), scratch);              // home_object
+      // stack: this, home_object; rax: value
+      EmitNamedSuperPropertyStore(prop);
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      __ Push(rax);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForAccumulatorValue(prop->key());
+      Register scratch = rcx;
+      Register scratch2 = rdx;
+      __ movp(scratch2, MemOperand(rsp, 2 * kPointerSize));  // value
+      // stack: value, this, home_object; rax: key, rdx: value
+      __ movp(scratch, MemOperand(rsp, kPointerSize));  // this
+      __ movp(MemOperand(rsp, 2 * kPointerSize), scratch);
+      __ movp(scratch, MemOperand(rsp, 0));  // home_object
+      __ movp(MemOperand(rsp, kPointerSize), scratch);
+      __ movp(MemOperand(rsp, 0), rax);
+      __ Move(rax, scratch2);
+      // stack: this, home_object, key; rax: value.
+      EmitKeyedSuperPropertyStore(prop);
+      break;
+    }
     case KEYED_PROPERTY: {
       __ Push(rax);  // Preserve value.
       VisitForStackValue(prop->obj());
@@ -2504,8 +2596,9 @@
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
+  } else if (IsSignallingAssignmentToConst(var, op, strict_mode())) {
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
   }
-  // Non-initializing assignments to consts are ignored.
 }
 
 
@@ -2526,6 +2619,35 @@
 }
 
 
+void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // rax : value
+  // stack : receiver ('this'), home_object
+  DCHECK(prop != NULL);
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(key != NULL);
+
+  __ Push(key->value());
+  __ Push(rax);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
+                                          : Runtime::kStoreToSuper_Sloppy),
+                 4);
+}
+
+
+void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // rax : value
+  // stack : receiver ('this'), home_object, key
+  DCHECK(prop != NULL);
+
+  __ Push(rax);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict
+                                          : Runtime::kStoreKeyedToSuper_Sloppy),
+                 4);
+}
+
+
 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
   // Assignment to a property, using a keyed store IC.
 
@@ -2553,16 +2675,27 @@
       __ movp(LoadDescriptor::ReceiverRegister(), rax);
       EmitNamedPropertyLoad(expr);
     } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
       EmitNamedSuperPropertyLoad(expr);
     }
     PrepareForBailoutForId(expr->LoadId(), TOS_REG);
     context()->Plug(rax);
   } else {
-    VisitForStackValue(expr->obj());
-    VisitForAccumulatorValue(expr->key());
-    __ Move(LoadDescriptor::NameRegister(), rax);
-    __ Pop(LoadDescriptor::ReceiverRegister());
-    EmitKeyedPropertyLoad(expr);
+    if (!expr->IsSuperAccess()) {
+      VisitForStackValue(expr->obj());
+      VisitForAccumulatorValue(expr->key());
+      __ Move(LoadDescriptor::NameRegister(), rax);
+      __ Pop(LoadDescriptor::ReceiverRegister());
+      EmitKeyedPropertyLoad(expr);
+    } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForStackValue(expr->key());
+      EmitKeyedSuperPropertyLoad(expr);
+    }
     context()->Plug(rax);
   }
 }
@@ -2621,15 +2754,15 @@
   __ Push(rax);
   VisitForAccumulatorValue(super_ref->this_var());
   __ Push(rax);
-  __ Push(Operand(rsp, kPointerSize));
   __ Push(rax);
+  __ Push(Operand(rsp, kPointerSize * 2));
   __ Push(key->value());
 
   // Stack here:
   //  - home_object
   //  - this (receiver)
-  //  - home_object <-- LoadFromSuper will pop here and below.
-  //  - this (receiver)
+  //  - this (receiver) <-- LoadFromSuper will pop here and below.
+  //  - home_object
   //  - key
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 
@@ -2666,6 +2799,41 @@
 }
 
 
+void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
+  Expression* callee = expr->expression();
+  DCHECK(callee->IsProperty());
+  Property* prop = callee->AsProperty();
+  DCHECK(prop->IsSuperAccess());
+
+  SetSourcePosition(prop->position());
+  // Load the function from the receiver.
+  SuperReference* super_ref = prop->obj()->AsSuperReference();
+  EmitLoadHomeObject(super_ref);
+  __ Push(rax);
+  VisitForAccumulatorValue(super_ref->this_var());
+  __ Push(rax);
+  __ Push(rax);
+  __ Push(Operand(rsp, kPointerSize * 2));
+  VisitForStackValue(prop->key());
+
+  // Stack here:
+  //  - home_object
+  //  - this (receiver)
+  //  - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
+  //  - home_object
+  //  - key
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+
+  // Replace home_object with target function.
+  __ movp(Operand(rsp, kPointerSize), rax);
+
+  // Stack here:
+  // - target function
+  // - this (receiver)
+  EmitCall(expr, CallICState::METHOD);
+}
+
+
 void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
   // Load the arguments.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2680,7 +2848,7 @@
   SetSourcePosition(expr->position());
   Handle<Code> ic = CallIC::initialize_stub(
       isolate(), arg_count, call_type);
-  __ Move(rdx, Smi::FromInt(expr->CallFeedbackSlot()));
+  __ Move(rdx, SmiFromSlot(expr->CallFeedbackSlot()));
   __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
   // Don't assign a type feedback id to the IC, since type feedback is provided
   // by the vector above.
@@ -2721,6 +2889,13 @@
 }
 
 
+void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
+  DCHECK(super_ref != NULL);
+  __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+  __ CallRuntime(Runtime::kGetPrototype, 1);
+}
+
+
 void FullCodeGenerator::VisitCall(Call* expr) {
 #ifdef DEBUG
   // We want to verify that RecordJSReturnSite gets called on all paths
@@ -2756,6 +2931,8 @@
       // rdx (receiver). Touch up the stack with the right values.
       __ movp(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
       __ movp(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
+
+      PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
     }
     // Record source position for debugger.
     SetSourcePosition(expr->position());
@@ -2787,6 +2964,7 @@
     __ CallRuntime(Runtime::kLoadLookupSlot, 2);
     __ Push(rax);  // Function.
     __ Push(rdx);  // Receiver.
+    PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
 
     // If fast case code has been generated, emit code to push the function
     // and receiver and have the slow path jump around this code.
@@ -2808,9 +2986,12 @@
   } else if (call_type == Call::PROPERTY_CALL) {
     Property* property = callee->AsProperty();
     bool is_named_call = property->key()->IsPropertyName();
-    // super.x() is handled in EmitCallWithLoadIC.
-    if (property->IsSuperAccess() && is_named_call) {
-      EmitSuperCallWithLoadIC(expr);
+    if (property->IsSuperAccess()) {
+      if (is_named_call) {
+        EmitSuperCallWithLoadIC(expr);
+      } else {
+        EmitKeyedSuperCallWithLoadIC(expr);
+      }
     } else {
       {
         PreservePositionScope scope(masm()->positions_recorder());
@@ -2822,6 +3003,12 @@
         EmitKeyedCallWithLoadIC(expr, property->key());
       }
     }
+  } else if (call_type == Call::SUPER_CALL) {
+    SuperReference* super_ref = callee->AsSuperReference();
+    EmitLoadSuperConstructor(super_ref);
+    __ Push(result_register());
+    VisitForStackValue(super_ref->this_var());
+    EmitCall(expr, CallICState::METHOD);
   } else {
     DCHECK(call_type == Call::OTHER_CALL);
     // Call to an arbitrary expression not handled specially above.
@@ -2849,7 +3036,12 @@
   // Push constructor on the stack.  If it's not a function it's used as
   // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
   // ignored.
-  VisitForStackValue(expr->expression());
+  if (expr->expression()->IsSuperReference()) {
+    EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
+    __ Push(result_register());
+  } else {
+    VisitForStackValue(expr->expression());
+  }
 
   // Push the arguments ("left-to-right") on the stack.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2869,12 +3061,12 @@
   // Record call targets in unoptimized code, but not in the snapshot.
   if (FLAG_pretenuring_call_new) {
     EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
-    DCHECK(expr->AllocationSiteFeedbackSlot() ==
-           expr->CallNewFeedbackSlot() + 1);
+    DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
+           expr->CallNewFeedbackSlot().ToInt() + 1);
   }
 
   __ Move(rbx, FeedbackVector());
-  __ Move(rdx, Smi::FromInt(expr->CallNewFeedbackSlot()));
+  __ Move(rdx, SmiFromSlot(expr->CallNewFeedbackSlot()));
 
   CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
@@ -3181,6 +3373,31 @@
 }
 
 
+void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ JumpIfSmi(rax, if_false);
+  Register map = rbx;
+  __ movp(map, FieldOperand(rax, HeapObject::kMapOffset));
+  __ CmpInstanceType(map, FIRST_JS_PROXY_TYPE);
+  __ j(less, if_false);
+  __ CmpInstanceType(map, LAST_JS_PROXY_TYPE);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(less_equal, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
 
 void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
   DCHECK(expr->arguments()->length() == 0);
@@ -4146,7 +4363,7 @@
     __ Move(LoadDescriptor::NameRegister(), expr->name());
     if (FLAG_vector_ics) {
       __ Move(VectorLoadICDescriptor::SlotRegister(),
-              Smi::FromInt(expr->CallRuntimeFeedbackSlot()));
+              SmiFromSlot(expr->CallRuntimeFeedbackSlot()));
       CallLoadIC(NOT_CONTEXTUAL);
     } else {
       CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
@@ -4304,17 +4521,8 @@
   Comment cmnt(masm_, "[ CountOperation");
   SetSourcePosition(expr->position());
 
-  // Expression can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* prop = expr->expression()->AsProperty();
-  // In case of a property we use the uninitialized expression context
-  // of the key to detect a named property.
-  if (prop != NULL) {
-    assign_type =
-        (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(prop);
 
   // Evaluate expression and get value.
   if (assign_type == VARIABLE) {
@@ -4326,18 +4534,50 @@
     if (expr->is_postfix() && !context()->IsEffect()) {
       __ Push(Smi::FromInt(0));
     }
-    if (assign_type == NAMED_PROPERTY) {
-      VisitForStackValue(prop->obj());
-      __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
-      EmitNamedPropertyLoad(prop);
-    } else {
-      VisitForStackValue(prop->obj());
-      VisitForStackValue(prop->key());
-      // Leave receiver on stack
-      __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, kPointerSize));
-      // Copy of key, needed for later store.
-      __ movp(LoadDescriptor::NameRegister(), Operand(rsp, 0));
-      EmitKeyedPropertyLoad(prop);
+    switch (assign_type) {
+      case NAMED_PROPERTY: {
+        VisitForStackValue(prop->obj());
+        __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, 0));
+        EmitNamedPropertyLoad(prop);
+        break;
+      }
+
+      case NAMED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        __ Push(result_register());
+        __ Push(MemOperand(rsp, kPointerSize));
+        __ Push(result_register());
+        EmitNamedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        __ Push(result_register());
+        VisitForAccumulatorValue(prop->key());
+        __ Push(result_register());
+        __ Push(MemOperand(rsp, 2 * kPointerSize));
+        __ Push(MemOperand(rsp, 2 * kPointerSize));
+        __ Push(result_register());
+        EmitKeyedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_PROPERTY: {
+        VisitForStackValue(prop->obj());
+        VisitForStackValue(prop->key());
+        // Leave receiver on stack
+        __ movp(LoadDescriptor::ReceiverRegister(), Operand(rsp, kPointerSize));
+        // Copy of key, needed for later store.
+        __ movp(LoadDescriptor::NameRegister(), Operand(rsp, 0));
+        EmitKeyedPropertyLoad(prop);
+        break;
+      }
+
+      case VARIABLE:
+        UNREACHABLE();
     }
   }
 
@@ -4369,9 +4609,15 @@
           case NAMED_PROPERTY:
             __ movp(Operand(rsp, kPointerSize), rax);
             break;
+          case NAMED_SUPER_PROPERTY:
+            __ movp(Operand(rsp, 2 * kPointerSize), rax);
+            break;
           case KEYED_PROPERTY:
             __ movp(Operand(rsp, 2 * kPointerSize), rax);
             break;
+          case KEYED_SUPER_PROPERTY:
+            __ movp(Operand(rsp, 3 * kPointerSize), rax);
+            break;
         }
       }
     }
@@ -4404,9 +4650,15 @@
         case NAMED_PROPERTY:
           __ movp(Operand(rsp, kPointerSize), rax);
           break;
+        case NAMED_SUPER_PROPERTY:
+          __ movp(Operand(rsp, 2 * kPointerSize), rax);
+          break;
         case KEYED_PROPERTY:
           __ movp(Operand(rsp, 2 * kPointerSize), rax);
           break;
+        case KEYED_SUPER_PROPERTY:
+          __ movp(Operand(rsp, 3 * kPointerSize), rax);
+          break;
       }
     }
   }
@@ -4463,6 +4715,28 @@
       }
       break;
     }
+    case NAMED_SUPER_PROPERTY: {
+      EmitNamedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(rax);
+      }
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      EmitKeyedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(rax);
+      }
+      break;
+    }
     case KEYED_PROPERTY: {
       __ Pop(StoreDescriptor::NameRegister());
       __ Pop(StoreDescriptor::ReceiverRegister());
@@ -4494,7 +4768,7 @@
     __ movp(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
     if (FLAG_vector_ics) {
       __ Move(VectorLoadICDescriptor::SlotRegister(),
-              Smi::FromInt(proxy->VariableFeedbackSlot()));
+              SmiFromSlot(proxy->VariableFeedbackSlot()));
     }
     // Use a regular load, not a contextual load, to avoid a reference
     // error.
@@ -4728,7 +5002,7 @@
 
 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
   Scope* declaration_scope = scope()->DeclarationScope();
-  if (declaration_scope->is_global_scope() ||
+  if (declaration_scope->is_script_scope() ||
       declaration_scope->is_module_scope()) {
     // Contexts nested in the native context have a canonical empty function
     // as their closure, not the anonymous closure containing the global
diff --git a/src/x64/interface-descriptors-x64.cc b/src/x64/interface-descriptors-x64.cc
index 84fdca4..f19979d 100644
--- a/src/x64/interface-descriptors-x64.cc
+++ b/src/x64/interface-descriptors-x64.cc
@@ -29,6 +29,9 @@
 const Register StoreDescriptor::ValueRegister() { return rax; }
 
 
+const Register StoreTransitionDescriptor::MapRegister() { return rbx; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() {
   return rbx;
 }
@@ -152,6 +155,15 @@
 }
 
 
+void AllocateHeapNumberDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // register state
+  // rsi -- context
+  Register registers[] = {rsi};
+  data->Initialize(arraysize(registers), registers, nullptr);
+}
+
+
 void ArrayConstructorConstantArgCountDescriptor::Initialize(
     CallInterfaceDescriptorData* data) {
   // register state
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 1981d55..10f2bb8 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -30,9 +30,9 @@
         deopt_mode_(mode) { }
   virtual ~SafepointGenerator() {}
 
-  virtual void BeforeCall(int call_size) const OVERRIDE {}
+  void BeforeCall(int call_size) const OVERRIDE {}
 
-  virtual void AfterCall() const OVERRIDE {
+  void AfterCall() const OVERRIDE {
     codegen_->RecordSafepoint(pointers_, deopt_mode_);
   }
 
@@ -2676,10 +2676,10 @@
     DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
                                   LInstanceOfKnownGlobal* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
     Label* map_check() { return &map_check_; }
    private:
     LInstanceOfKnownGlobal* instr_;
@@ -2822,6 +2822,7 @@
     __ Ret((ToInteger32(instr->constant_parameter_count()) + 1) * kPointerSize,
            rcx);
   } else {
+    DCHECK(info()->IsStub());  // Functions would need to drop one more value.
     Register reg = ToRegister(instr->parameter_count());
     // The argument count parameter is a smi
     __ SmiToInteger32(reg, reg);
@@ -2850,13 +2851,18 @@
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
-  Register vector = ToRegister(instr->temp_vector());
-  DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
-  __ Move(vector, instr->hydrogen()->feedback_vector());
+  Register vector_register = ToRegister(instr->temp_vector());
+  Register slot_register = VectorLoadICDescriptor::SlotRegister();
+  DCHECK(vector_register.is(VectorLoadICDescriptor::VectorRegister()));
+  DCHECK(slot_register.is(rax));
+
+  AllowDeferredHandleDereference vector_structure_check;
+  Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+  __ Move(vector_register, vector);
   // No need to allocate this register.
-  DCHECK(VectorLoadICDescriptor::SlotRegister().is(rax));
-  __ Move(VectorLoadICDescriptor::SlotRegister(),
-          Smi::FromInt(instr->hydrogen()->slot()));
+  FeedbackVectorICSlot slot = instr->hydrogen()->slot();
+  int index = vector->GetIndex(slot);
+  __ Move(slot_register, Smi::FromInt(index));
 }
 
 
@@ -2871,7 +2877,7 @@
     EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
   }
   ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), mode).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -2974,6 +2980,7 @@
 
   Register object = ToRegister(instr->object());
   if (instr->hydrogen()->representation().IsDouble()) {
+    DCHECK(access.IsInobject());
     XMMRegister result = ToDoubleRegister(instr->result());
     __ movsd(result, FieldOperand(object, offset));
     return;
@@ -3013,7 +3020,8 @@
   if (FLAG_vector_ics) {
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic =
+      CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3272,11 +3280,9 @@
     return Operand(elements_pointer_reg,
                    (constant_value << shift_size) + offset);
   } else {
-    // Take the tag bit into account while computing the shift size.
-    if (key_representation.IsSmi() && (shift_size >= 1)) {
-      DCHECK(SmiValuesAre31Bits());
-      shift_size -= kSmiTagSize;
-    }
+    // Guaranteed by ArrayInstructionInterface::KeyedAccessIndexRequirement().
+    DCHECK(key_representation.IsInteger32());
+
     ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
     return Operand(elements_pointer_reg,
                    ToRegister(key),
@@ -3295,7 +3301,7 @@
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
+  Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3535,43 +3541,67 @@
   Register name = ToRegister(instr->name());
   DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
   DCHECK(name.is(LoadDescriptor::NameRegister()));
-
-  Register scratch = rbx;
+  Register scratch = rdi;
   DCHECK(!scratch.is(receiver) && !scratch.is(name));
+  DCHECK(!FLAG_vector_ics ||
+         !AreAliased(ToRegister(instr->slot()), ToRegister(instr->vector()),
+                     scratch));
 
   // Important for the tail-call.
   bool must_teardown_frame = NeedsEagerFrame();
 
-  // The probe will tail call to a handler if found.
-  isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
-                                         must_teardown_frame, receiver, name,
-                                         scratch, no_reg);
+  if (!instr->hydrogen()->is_just_miss()) {
+    // The probe will tail call to a handler if found.
+    DCHECK(!instr->hydrogen()->is_keyed_load());
+    isolate()->stub_cache()->GenerateProbe(
+        masm(), Code::LOAD_IC, instr->hydrogen()->flags(), must_teardown_frame,
+        receiver, name, scratch, no_reg);
+  }
 
   // Tail call to miss if we ended up here.
   if (must_teardown_frame) __ leave();
-  LoadIC::GenerateMiss(masm());
+  if (instr->hydrogen()->is_keyed_load()) {
+    KeyedLoadIC::GenerateMiss(masm());
+  } else {
+    LoadIC::GenerateMiss(masm());
+  }
 }
 
 
 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
   DCHECK(ToRegister(instr->result()).is(rax));
 
-  LPointerMap* pointers = instr->pointer_map();
-  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+  if (instr->hydrogen()->IsTailCall()) {
+    if (NeedsEagerFrame()) __ leave();
 
-  if (instr->target()->IsConstantOperand()) {
-    LConstantOperand* target = LConstantOperand::cast(instr->target());
-    Handle<Code> code = Handle<Code>::cast(ToHandle(target));
-    generator.BeforeCall(__ CallSize(code));
-    __ call(code, RelocInfo::CODE_TARGET);
+    if (instr->target()->IsConstantOperand()) {
+      LConstantOperand* target = LConstantOperand::cast(instr->target());
+      Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+      __ jmp(code, RelocInfo::CODE_TARGET);
+    } else {
+      DCHECK(instr->target()->IsRegister());
+      Register target = ToRegister(instr->target());
+      __ addp(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
+      __ jmp(target);
+    }
   } else {
-    DCHECK(instr->target()->IsRegister());
-    Register target = ToRegister(instr->target());
-    generator.BeforeCall(__ CallSize(target));
-    __ addp(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
-    __ call(target);
+    LPointerMap* pointers = instr->pointer_map();
+    SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+
+    if (instr->target()->IsConstantOperand()) {
+      LConstantOperand* target = LConstantOperand::cast(instr->target());
+      Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+      generator.BeforeCall(__ CallSize(code));
+      __ call(code, RelocInfo::CODE_TARGET);
+    } else {
+      DCHECK(instr->target()->IsRegister());
+      Register target = ToRegister(instr->target());
+      generator.BeforeCall(__ CallSize(target));
+      __ addp(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
+      __ call(target);
+    }
+    generator.AfterCall();
   }
-  generator.AfterCall();
 }
 
 
@@ -3680,10 +3710,11 @@
    public:
     DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LMathAbs* instr_;
   };
@@ -4119,7 +4150,7 @@
   DCHECK(!representation.IsSmi() ||
          !instr->value()->IsConstantOperand() ||
          IsInteger32Constant(LConstantOperand::cast(instr->value())));
-  if (representation.IsDouble()) {
+  if (!FLAG_unbox_double_fields && representation.IsDouble()) {
     DCHECK(access.IsInobject());
     DCHECK(!hinstr->has_transition());
     DCHECK(!hinstr->NeedsWriteBarrier());
@@ -4169,7 +4200,12 @@
 
   Operand operand = FieldOperand(write_register, offset);
 
-  if (instr->value()->IsRegister()) {
+  if (FLAG_unbox_double_fields && representation.IsDouble()) {
+    DCHECK(access.IsInobject());
+    XMMRegister value = ToDoubleRegister(instr->value());
+    __ movsd(operand, value);
+
+  } else if (instr->value()->IsRegister()) {
     Register value = ToRegister(instr->value());
     __ Store(operand, value, representation);
   } else {
@@ -4543,10 +4579,9 @@
    public:
     DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredStringCharCodeAt(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredStringCharCodeAt(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStringCharCodeAt* instr_;
   };
@@ -4598,10 +4633,11 @@
    public:
     DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredStringCharFromCode(instr_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStringCharFromCode* instr_;
   };
@@ -4670,11 +4706,12 @@
    public:
     DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredNumberTagIU(instr_, instr_->value(), instr_->temp1(),
                                        instr_->temp2(), SIGNED_INT32);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagI* instr_;
   };
@@ -4700,11 +4737,12 @@
    public:
     DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredNumberTagIU(instr_, instr_->value(), instr_->temp1(),
                                        instr_->temp2(), UNSIGNED_INT32);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagU* instr_;
   };
@@ -4787,10 +4825,9 @@
    public:
     DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredNumberTagD(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredNumberTagD(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagD* instr_;
   };
@@ -4983,10 +5020,9 @@
    public:
     DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredTaggedToI(instr_, done());
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredTaggedToI(instr_, done()); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LTaggedToI* instr_;
   };
@@ -5173,11 +5209,12 @@
         : LDeferredCode(codegen), instr_(instr), object_(object) {
       SetExit(check_maps());
     }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredInstanceMigration(instr_, object_);
     }
     Label* check_maps() { return &check_maps_; }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LCheckMaps* instr_;
     Label check_maps_;
@@ -5302,10 +5339,9 @@
    public:
     DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredAllocate(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredAllocate(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LAllocate* instr_;
   };
@@ -5675,10 +5711,9 @@
    public:
     DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredStackCheck(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredStackCheck(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStackCheck* instr_;
   };
@@ -5822,10 +5857,11 @@
           object_(object),
           index_(index) {
     }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredLoadMutableDouble(instr_, object_, index_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LLoadFieldByIndex* instr_;
     Register object_;
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 69f50b1..c1831af 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <sstream>
+
 #include "src/v8.h"
 
 #if V8_TARGET_ARCH_X64
@@ -360,9 +362,9 @@
 
 void LStoreNamedField::PrintDataTo(StringStream* stream) {
   object()->PrintTo(stream);
-  OStringStream os;
+  std::ostringstream os;
   os << hydrogen()->access() << " <- ";
-  stream->Add(os.c_str());
+  stream->Add(os.str().c_str());
   value()->PrintTo(stream);
 }
 
@@ -720,11 +722,7 @@
     // Shift operations can only deoptimize if we do a logical shift by 0 and
     // the result cannot be truncated to int32.
     if (op == Token::SHR && constant_value == 0) {
-      if (FLAG_opt_safe_uint32_operations) {
-        does_deopt = !instr->CheckFlag(HInstruction::kUint32);
-      } else {
-        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32);
-      }
+      does_deopt = !instr->CheckFlag(HInstruction::kUint32);
     }
 
     LInstruction* result =
@@ -1120,9 +1118,17 @@
       UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
   LOperand* name_register =
       UseFixed(instr->name(), LoadDescriptor::NameRegister());
+  LOperand* slot = NULL;
+  LOperand* vector = NULL;
+  if (FLAG_vector_ics) {
+    slot = UseFixed(instr->slot(), VectorLoadICDescriptor::SlotRegister());
+    vector =
+        UseFixed(instr->vector(), VectorLoadICDescriptor::VectorRegister());
+  }
+
   // Not marked as call. It can't deoptimize, and it never returns.
   return new (zone()) LTailCallThroughMegamorphicCache(
-      context, receiver_register, name_register);
+      context, receiver_register, name_register, slot, vector);
 }
 
 
@@ -2069,7 +2075,7 @@
   LOperand* global_object =
       UseFixed(instr->global_object(), LoadDescriptor::ReceiverRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
 
@@ -2142,7 +2148,7 @@
   LOperand* object =
       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
   LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(
@@ -2235,7 +2241,7 @@
       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
   LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
 
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 30b994e..8b7a5bc 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -163,17 +163,13 @@
   V(WrapReceiver)
 
 
-#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)                        \
-  virtual Opcode opcode() const FINAL OVERRIDE {                      \
-    return LInstruction::k##type;                                           \
-  }                                                                         \
-  virtual void CompileToNative(LCodeGen* generator) FINAL OVERRIDE;   \
-  virtual const char* Mnemonic() const FINAL OVERRIDE {               \
-    return mnemonic;                                                        \
-  }                                                                         \
-  static L##type* cast(LInstruction* instr) {                               \
-    DCHECK(instr->Is##type());                                              \
-    return reinterpret_cast<L##type*>(instr);                               \
+#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)            \
+  Opcode opcode() const FINAL { return LInstruction::k##type; } \
+  void CompileToNative(LCodeGen* generator) FINAL;              \
+  const char* Mnemonic() const FINAL { return mnemonic; }       \
+  static L##type* cast(LInstruction* instr) {                   \
+    DCHECK(instr->Is##type());                                  \
+    return reinterpret_cast<L##type*>(instr);                   \
   }
 
 
@@ -292,14 +288,11 @@
  public:
   // Allow 0 or 1 output operands.
   STATIC_ASSERT(R == 0 || R == 1);
-  virtual bool HasResult() const FINAL OVERRIDE {
-    return R != 0 && result() != NULL;
-  }
+  bool HasResult() const FINAL { return R != 0 && result() != NULL; }
   void set_result(LOperand* operand) { results_[0] = operand; }
-  LOperand* result() const { return results_[0]; }
+  LOperand* result() const OVERRIDE { return results_[0]; }
 
-  virtual bool MustSignExtendResult(
-      LPlatformChunk* chunk) const FINAL OVERRIDE;
+  bool MustSignExtendResult(LPlatformChunk* chunk) const FINAL;
 
  protected:
   EmbeddedContainer<LOperand*, R> results_;
@@ -317,11 +310,11 @@
 
  private:
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return I; }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return I; }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return T; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return temps_[i]; }
+  int TempCount() FINAL { return T; }
+  LOperand* TempAt(int i) FINAL { return temps_[i]; }
 };
 
 
@@ -336,8 +329,8 @@
   }
 
   // Can't use the DECLARE-macro here because of sub-classes.
-  virtual bool IsGap() const FINAL OVERRIDE { return true; }
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsGap() const FINAL { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   static LGap* cast(LInstruction* instr) {
     DCHECK(instr->IsGap());
     return reinterpret_cast<LGap*>(instr);
@@ -378,7 +371,7 @@
  public:
   explicit LInstructionGap(HBasicBlock* block) : LGap(block) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
     return !IsRedundant();
   }
 
@@ -390,10 +383,10 @@
  public:
   explicit LGoto(HBasicBlock* block) : block_(block) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
   DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
-  virtual bool IsControl() const OVERRIDE { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsControl() const OVERRIDE { return true; }
 
   int block_id() const { return block_->block_id(); }
 
@@ -436,7 +429,7 @@
 
 class LDeoptimize FINAL : public LTemplateInstruction<0, 0, 0> {
  public:
-  virtual bool IsControl() const OVERRIDE { return true; }
+  bool IsControl() const OVERRIDE { return true; }
   DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
   DECLARE_HYDROGEN_ACCESSOR(Deoptimize)
 };
@@ -447,12 +440,10 @@
   explicit LLabel(HBasicBlock* block)
       : LGap(block), replacement_(NULL) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(Label, "label")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int block_id() const { return block()->block_id(); }
   bool is_loop_header() const { return block()->IsLoopHeader(); }
@@ -470,9 +461,7 @@
 
 class LParameter FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter")
 };
 
@@ -491,19 +480,23 @@
 
 
 class LTailCallThroughMegamorphicCache FINAL
-    : public LTemplateInstruction<0, 3, 0> {
+    : public LTemplateInstruction<0, 5, 0> {
  public:
   explicit LTailCallThroughMegamorphicCache(LOperand* context,
-                                            LOperand* receiver,
-                                            LOperand* name) {
+                                            LOperand* receiver, LOperand* name,
+                                            LOperand* slot, LOperand* vector) {
     inputs_[0] = context;
     inputs_[1] = receiver;
     inputs_[2] = name;
+    inputs_[3] = slot;
+    inputs_[4] = vector;
   }
 
   LOperand* context() { return inputs_[0]; }
   LOperand* receiver() { return inputs_[1]; }
   LOperand* name() { return inputs_[2]; }
+  LOperand* slot() { return inputs_[3]; }
+  LOperand* vector() { return inputs_[4]; }
 
   DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
                                "tail-call-through-megamorphic-cache")
@@ -513,9 +506,7 @@
 
 class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown-osr-value")
 };
 
@@ -525,7 +516,7 @@
  public:
   LControlInstruction() : false_label_(NULL), true_label_(NULL) { }
 
-  virtual bool IsControl() const FINAL OVERRIDE { return true; }
+  bool IsControl() const FINAL { return true; }
 
   int SuccessorCount() { return hydrogen()->SuccessorCount(); }
   HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); }
@@ -614,7 +605,7 @@
 
   DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -855,7 +846,7 @@
     return hydrogen()->representation().IsDouble();
   }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1030,7 +1021,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1047,7 +1038,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1062,7 +1053,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1080,7 +1071,7 @@
                                "is-undetectable-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1102,7 +1093,7 @@
                                "string-compare-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Token::Value op() const { return hydrogen()->token(); }
 };
@@ -1120,7 +1111,7 @@
                                "has-instance-type-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1150,7 +1141,7 @@
                                "has-cached-array-index-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1170,7 +1161,7 @@
                                "class-of-test-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1376,7 +1367,7 @@
   DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
   DECLARE_HYDROGEN_ACCESSOR(Branch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1528,11 +1519,9 @@
   LOperand* left() { return inputs_[0]; }
   LOperand* right() { return inputs_[1]; }
 
-  virtual Opcode opcode() const OVERRIDE {
-    return LInstruction::kArithmeticD;
-  }
-  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
-  virtual const char* Mnemonic() const OVERRIDE;
+  Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticD; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
 
  private:
   Token::Value op_;
@@ -1556,11 +1545,9 @@
   LOperand* left() { return inputs_[1]; }
   LOperand* right() { return inputs_[2]; }
 
-  virtual Opcode opcode() const OVERRIDE {
-    return LInstruction::kArithmeticT;
-  }
-  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
-  virtual const char* Mnemonic() const OVERRIDE;
+  Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticT; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
 
  private:
   Token::Value op_;
@@ -1686,7 +1673,7 @@
   }
   LOperand* elements() { return inputs_[0]; }
   LOperand* key() { return inputs_[1]; }
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   uint32_t base_offset() const { return hydrogen()->base_offset(); }
   ElementsKind elements_kind() const {
     return hydrogen()->elements_kind();
@@ -1770,7 +1757,7 @@
 
   int slot_index() { return hydrogen()->slot_index(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1791,7 +1778,7 @@
 
   int slot_index() { return hydrogen()->slot_index(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1830,7 +1817,7 @@
   LOperand* function() { return inputs_[0]; }
   LOperand* code_object() { return inputs_[1]; }
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry, "store-code-entry")
   DECLARE_HYDROGEN_ACCESSOR(StoreCodeEntry)
@@ -1847,7 +1834,7 @@
   LOperand* base_object() const { return inputs_[0]; }
   LOperand* offset() const { return inputs_[1]; }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object")
 };
@@ -1891,7 +1878,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallJSFunction, "call-js-function")
   DECLARE_HYDROGEN_ACCESSOR(CallJSFunction)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1913,18 +1900,18 @@
  private:
   DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 
   ZoneList<LOperand*> inputs_;
 
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return inputs_.length(); }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return inputs_.length(); }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return 0; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return NULL; }
+  int TempCount() FINAL { return 0; }
+  LOperand* TempAt(int i) FINAL { return NULL; }
 };
 
 
@@ -1941,7 +1928,7 @@
   DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function")
   DECLARE_HYDROGEN_ACCESSOR(InvokeFunction)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1976,7 +1963,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
   DECLARE_HYDROGEN_ACCESSOR(CallNew)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1995,7 +1982,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
   DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -2012,7 +1999,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
   DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
 
-  virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
+  bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
     return save_doubles() == kDontSaveFPRegs;
   }
 
@@ -2198,7 +2185,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
   DECLARE_HYDROGEN_ACCESSOR(StoreNamedField)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Representation representation() const {
     return hydrogen()->field_representation();
@@ -2221,7 +2208,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
   DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Handle<Object> name() const { return hydrogen()->name(); }
   StrictMode strict_mode() { return hydrogen()->strict_mode(); }
@@ -2251,7 +2238,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed")
   DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
   uint32_t base_offset() const { return hydrogen()->base_offset(); }
 };
@@ -2277,7 +2264,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
   DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   StrictMode strict_mode() { return hydrogen()->strict_mode(); }
 };
@@ -2304,7 +2291,7 @@
                                "transition-elements-kind")
   DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Handle<Map> original_map() { return hydrogen()->original_map().handle(); }
   Handle<Map> transitioned_map() {
@@ -2593,7 +2580,7 @@
 
   Handle<String> type_literal() { return hydrogen()->type_literal(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -2615,9 +2602,7 @@
  public:
   LOsrEntry() {}
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry")
 };
 
@@ -2827,7 +2812,7 @@
 
   // An input operand in register, stack slot or a constant operand.
   // Will not be moved to a register even if one is freely available.
-  virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE;
+  MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE;
 
   // Temporary operand that must be in a register.
   MUST_USE_RESULT LUnallocated* TempRegister();
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 5033303..5b897de 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -2743,6 +2743,57 @@
 }
 
 
+void MacroAssembler::Move(XMMRegister dst, uint32_t src) {
+  if (src == 0) {
+    xorps(dst, dst);
+  } else {
+    unsigned cnt = base::bits::CountPopulation32(src);
+    unsigned nlz = base::bits::CountLeadingZeros32(src);
+    unsigned ntz = base::bits::CountTrailingZeros32(src);
+    if (nlz + cnt + ntz == 32) {
+      pcmpeqd(dst, dst);
+      if (ntz == 0) {
+        psrld(dst, 32 - cnt);
+      } else {
+        pslld(dst, 32 - cnt);
+        if (nlz != 0) psrld(dst, nlz);
+      }
+    } else {
+      movl(kScratchRegister, Immediate(src));
+      movq(dst, kScratchRegister);
+    }
+  }
+}
+
+
+void MacroAssembler::Move(XMMRegister dst, uint64_t src) {
+  uint32_t lower = static_cast<uint32_t>(src);
+  uint32_t upper = static_cast<uint32_t>(src >> 32);
+  if (upper == 0) {
+    Move(dst, lower);
+  } else {
+    unsigned cnt = base::bits::CountPopulation64(src);
+    unsigned nlz = base::bits::CountLeadingZeros64(src);
+    unsigned ntz = base::bits::CountTrailingZeros64(src);
+    if (nlz + cnt + ntz == 64) {
+      pcmpeqd(dst, dst);
+      if (ntz == 0) {
+        psrlq(dst, 64 - cnt);
+      } else {
+        psllq(dst, 64 - cnt);
+        if (nlz != 0) psrlq(dst, nlz);
+      }
+    } else if (lower == 0) {
+      Move(dst, upper);
+      psllq(dst, 32);
+    } else {
+      movq(kScratchRegister, src);
+      movq(dst, kScratchRegister);
+    }
+  }
+}
+
+
 void MacroAssembler::Cmp(Register dst, Handle<Object> source) {
   AllowDeferredHandleDereference smi_check;
   if (source->IsSmi()) {
@@ -2801,6 +2852,21 @@
 }
 
 
+void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
+                                  Register scratch) {
+  Move(scratch, cell, RelocInfo::EMBEDDED_OBJECT);
+  cmpp(value, FieldOperand(scratch, WeakCell::kValueOffset));
+}
+
+
+void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
+                                   Label* miss) {
+  Move(value, cell, RelocInfo::EMBEDDED_OBJECT);
+  movp(value, FieldOperand(value, WeakCell::kValueOffset));
+  JumpIfSmi(value, miss);
+}
+
+
 void MacroAssembler::Drop(int stack_elements) {
   if (stack_elements > 0) {
     addp(rsp, Immediate(stack_elements * kPointerSize));
@@ -3564,18 +3630,17 @@
 }
 
 
-void MacroAssembler::DispatchMap(Register obj,
-                                 Register unused,
-                                 Handle<Map> map,
-                                 Handle<Code> success,
-                                 SmiCheckType smi_check_type) {
+void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
+                                     Register scratch2, Handle<WeakCell> cell,
+                                     Handle<Code> success,
+                                     SmiCheckType smi_check_type) {
   Label fail;
   if (smi_check_type == DO_SMI_CHECK) {
     JumpIfSmi(obj, &fail);
   }
-  Cmp(FieldOperand(obj, HeapObject::kMapOffset), map);
+  movq(scratch1, FieldOperand(obj, HeapObject::kMapOffset));
+  CmpWeakValue(scratch1, cell, scratch2);
   j(equal, success, RelocInfo::CODE_TARGET);
-
   bind(&fail);
 }
 
@@ -3984,6 +4049,13 @@
 }
 
 
+void MacroAssembler::EnterFrame(StackFrame::Type type,
+                                bool load_constant_pool_pointer_reg) {
+  // Out-of-line constant pool not implemented on x64.
+  UNREACHABLE();
+}
+
+
 void MacroAssembler::EnterFrame(StackFrame::Type type) {
   pushq(rbp);
   movp(rbp, rsp);
@@ -4035,6 +4107,7 @@
 
   Store(ExternalReference(Isolate::kCEntryFPAddress, isolate()), rbp);
   Store(ExternalReference(Isolate::kContextAddress, isolate()), rsi);
+  Store(ExternalReference(Isolate::kCFunctionAddress, isolate()), rbx);
 }
 
 
@@ -4308,10 +4381,10 @@
   }
 
   bind(&done);
-  // Check that the value is a normal propety.
+  // Check that the value is a field property.
   const int kDetailsOffset =
       SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
-  DCHECK_EQ(NORMAL, 0);
+  DCHECK_EQ(FIELD, 0);
   Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
        Smi::FromInt(PropertyDetails::TypeField::kMask));
   j(not_zero, miss);
@@ -5054,18 +5127,6 @@
 }
 
 
-void MacroAssembler::CheckMapDeprecated(Handle<Map> map,
-                                        Register scratch,
-                                        Label* if_deprecated) {
-  if (map->CanBeDeprecated()) {
-    Move(scratch, map);
-    movl(scratch, FieldOperand(scratch, Map::kBitField3Offset));
-    andl(scratch, Immediate(Map::Deprecated::kMask));
-    j(not_zero, if_deprecated);
-  }
-}
-
-
 void MacroAssembler::JumpIfBlack(Register object,
                                  Register bitmap_scratch,
                                  Register mask_scratch,
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index d051773..4656665 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -175,10 +175,6 @@
                      Label* condition_met,
                      Label::Distance condition_met_distance = Label::kFar);
 
-  void CheckMapDeprecated(Handle<Map> map,
-                          Register scratch,
-                          Label* if_deprecated);
-
   // Check if object is in new space.  Jumps if the object is not in new space.
   // The register scratch can be object itself, but scratch will be clobbered.
   void JumpIfNotInNewSpace(Register object,
@@ -847,6 +843,13 @@
   // Load a global cell into a register.
   void LoadGlobalCell(Register dst, Handle<Cell> cell);
 
+  // Compare the given value and the value of weak cell.
+  void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
+
+  // Load the value of the weak cell in the value register. Branch to the given
+  // miss label if the weak cell was cleared.
+  void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
+
   // Emit code to discard a non-negative number of pointer-sized elements
   // from the stack, clobbering only the rsp register.
   void Drop(int stack_elements);
@@ -888,6 +891,9 @@
     movp(dst, reinterpret_cast<void*>(value.location()), rmode);
   }
 
+  void Move(XMMRegister dst, uint32_t src);
+  void Move(XMMRegister dst, uint64_t src);
+
   // Control Flow
   void Jump(Address destination, RelocInfo::Mode rmode);
   void Jump(ExternalReference ext);
@@ -986,14 +992,12 @@
                 Label* fail,
                 SmiCheckType smi_check_type);
 
-  // Check if the map of an object is equal to a specified map and branch to a
-  // specified target if equal. Skip the smi check if not required (object is
-  // known to be a heap object)
-  void DispatchMap(Register obj,
-                   Register unused,
-                   Handle<Map> map,
-                   Handle<Code> success,
-                   SmiCheckType smi_check_type);
+  // Check if the map of an object is equal to a specified weak map and branch
+  // to a specified target if equal. Skip the smi check if not required
+  // (object is known to be a heap object)
+  void DispatchWeakMap(Register obj, Register scratch1, Register scratch2,
+                       Handle<WeakCell> cell, Handle<Code> success,
+                       SmiCheckType smi_check_type);
 
   // Check if the object in register heap_object is a string. Afterwards the
   // register map contains the object map and the register instance_type
@@ -1438,6 +1442,7 @@
 
   // Activation support.
   void EnterFrame(StackFrame::Type type);
+  void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
   void LeaveFrame(StackFrame::Type type);
 
   // Expects object in rax and returns map with validated enum cache
diff --git a/src/x87/assembler-x87.cc b/src/x87/assembler-x87.cc
index 9e1c883..4177156 100644
--- a/src/x87/assembler-x87.cc
+++ b/src/x87/assembler-x87.cc
@@ -915,24 +915,24 @@
 }
 
 
-void Assembler::ror(Register dst, uint8_t imm8) {
+void Assembler::ror(const Operand& dst, uint8_t imm8) {
   EnsureSpace ensure_space(this);
   DCHECK(is_uint5(imm8));  // illegal shift count
   if (imm8 == 1) {
     EMIT(0xD1);
-    EMIT(0xC8 | dst.code());
+    emit_operand(ecx, dst);
   } else {
     EMIT(0xC1);
-    EMIT(0xC8 | dst.code());
+    emit_operand(ecx, dst);
     EMIT(imm8);
   }
 }
 
 
-void Assembler::ror_cl(Register dst) {
+void Assembler::ror_cl(const Operand& dst) {
   EnsureSpace ensure_space(this);
   EMIT(0xD3);
-  EMIT(0xC8 | dst.code());
+  emit_operand(ecx, dst);
 }
 
 
@@ -1897,11 +1897,6 @@
 }
 
 
-void Assembler::Print() {
-  Disassembler::Decode(isolate(), stdout, buffer_, pc_);
-}
-
-
 void Assembler::RecordJSReturn() {
   positions_recorder()->WriteRecordedPositions();
   EnsureSpace ensure_space(this);
diff --git a/src/x87/assembler-x87.h b/src/x87/assembler-x87.h
index d37c9d7..1da632f 100644
--- a/src/x87/assembler-x87.h
+++ b/src/x87/assembler-x87.h
@@ -148,6 +148,13 @@
     return kMaxNumAllocatableRegisters;
   }
 
+
+  // TODO(turbofan): Proper support for float32.
+  static int NumAllocatableAliasedRegisters() {
+    return NumAllocatableRegisters();
+  }
+
+
   static int ToAllocationIndex(X87Register reg) {
     return reg.code_;
   }
@@ -718,8 +725,11 @@
 
   void rcl(Register dst, uint8_t imm8);
   void rcr(Register dst, uint8_t imm8);
-  void ror(Register dst, uint8_t imm8);
-  void ror_cl(Register dst);
+
+  void ror(Register dst, uint8_t imm8) { ror(Operand(dst), imm8); }
+  void ror(const Operand& dst, uint8_t imm8);
+  void ror_cl(Register dst) { ror_cl(Operand(dst)); }
+  void ror_cl(const Operand& dst);
 
   void sar(Register dst, uint8_t imm8) { sar(Operand(dst), imm8); }
   void sar(const Operand& dst, uint8_t imm8);
@@ -909,9 +919,6 @@
 
   // TODO(lrn): Need SFENCE for movnt?
 
-  // Debugging
-  void Print();
-
   // Check the code size generated from label to here.
   int SizeOfCodeGeneratedSince(Label* label) {
     return pc_offset() - label->pos();
diff --git a/src/x87/builtins-x87.cc b/src/x87/builtins-x87.cc
index d631175..51bb3a7 100644
--- a/src/x87/builtins-x87.cc
+++ b/src/x87/builtins-x87.cc
@@ -160,18 +160,17 @@
       if (!is_api_function) {
         Label allocate;
         // The code below relies on these assumptions.
-        STATIC_ASSERT(JSFunction::kNoSlackTracking == 0);
-        STATIC_ASSERT(Map::ConstructionCount::kShift +
-                      Map::ConstructionCount::kSize == 32);
+        STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32);
         // Check if slack tracking is enabled.
         __ mov(esi, FieldOperand(eax, Map::kBitField3Offset));
-        __ shr(esi, Map::ConstructionCount::kShift);
-        __ j(zero, &allocate);  // JSFunction::kNoSlackTracking
+        __ shr(esi, Map::Counter::kShift);
+        __ cmp(esi, Map::kSlackTrackingCounterEnd);
+        __ j(less, &allocate);
         // Decrease generous allocation count.
         __ sub(FieldOperand(eax, Map::kBitField3Offset),
-               Immediate(1 << Map::ConstructionCount::kShift));
+               Immediate(1 << Map::Counter::kShift));
 
-        __ cmp(esi, JSFunction::kFinishSlackTracking);
+        __ cmp(esi, Map::kSlackTrackingCounterEnd);
         __ j(not_equal, &allocate);
 
         __ push(eax);
@@ -182,7 +181,7 @@
 
         __ pop(edi);
         __ pop(eax);
-        __ xor_(esi, esi);  // JSFunction::kNoSlackTracking
+        __ mov(esi, Map::kSlackTrackingCounterEnd - 1);
 
         __ bind(&allocate);
       }
@@ -219,8 +218,8 @@
         Label no_inobject_slack_tracking;
 
         // Check if slack tracking is enabled.
-        __ cmp(esi, JSFunction::kNoSlackTracking);
-        __ j(equal, &no_inobject_slack_tracking);
+        __ cmp(esi, Map::kSlackTrackingCounterEnd);
+        __ j(less, &no_inobject_slack_tracking);
 
         // Allocate object with a slack.
         __ movzx_b(esi,
@@ -1002,17 +1001,21 @@
     __ bind(&loop);
     __ mov(receiver, Operand(ebp, kArgumentsOffset));  // load arguments
 
-    // Use inline caching to speed up access to arguments.
     if (FLAG_vector_ics) {
-      __ mov(VectorLoadICDescriptor::SlotRegister(),
-             Immediate(Smi::FromInt(0)));
+      // TODO(mvstanton): Vector-based ics need additional infrastructure to
+      // be embedded here. For now, just call the runtime.
+      __ push(receiver);
+      __ push(key);
+      __ CallRuntime(Runtime::kGetProperty, 2);
+    } else {
+      // Use inline caching to speed up access to arguments.
+      Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code();
+      __ call(ic, RelocInfo::CODE_TARGET);
+      // It is important that we do not have a test instruction after the
+      // call.  A test instruction after the call is used to indicate that
+      // we have generated an inline version of the keyed load.  In this
+      // case, we know that we are not generating a test instruction next.
     }
-    Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code();
-    __ call(ic, RelocInfo::CODE_TARGET);
-    // It is important that we do not have a test instruction after the
-    // call.  A test instruction after the call is used to indicate that
-    // we have generated an inline version of the keyed load.  In this
-    // case, we know that we are not generating a test instruction next.
 
     // Push the nth argument.
     __ push(eax);
diff --git a/src/x87/code-stubs-x87.cc b/src/x87/code-stubs-x87.cc
index d4c383b..1264dd9 100644
--- a/src/x87/code-stubs-x87.cc
+++ b/src/x87/code-stubs-x87.cc
@@ -15,7 +15,7 @@
 #include "src/isolate.h"
 #include "src/jsregexp.h"
 #include "src/regexp-macro-assembler.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 
 namespace v8 {
 namespace internal {
@@ -333,8 +333,19 @@
   Label miss;
   Register receiver = LoadDescriptor::ReceiverRegister();
 
-  NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, eax,
-                                                          ebx, &miss);
+  if (FLAG_vector_ics) {
+    // With careful management, we won't have to save slot and vector on
+    // the stack. Simply handle the possibly missing case first.
+    // TODO(mvstanton): this code can be more efficient.
+    __ cmp(FieldOperand(receiver, JSFunction::kPrototypeOrInitialMapOffset),
+           Immediate(isolate()->factory()->the_hole_value()));
+    __ j(equal, &miss);
+    __ TryGetFunctionPrototype(receiver, eax, ebx, &miss);
+    __ ret(0);
+  } else {
+    NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, eax,
+                                                            ebx, &miss);
+  }
   __ bind(&miss);
   PropertyAccessCompiler::TailCallBuiltin(
       masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
@@ -371,6 +382,42 @@
 }
 
 
+void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
+  // Return address is on the stack.
+  Label miss;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register index = LoadDescriptor::NameRegister();
+  Register scratch = edi;
+  DCHECK(!scratch.is(receiver) && !scratch.is(index));
+  Register result = eax;
+  DCHECK(!result.is(scratch));
+  DCHECK(!FLAG_vector_ics ||
+         (!scratch.is(VectorLoadICDescriptor::VectorRegister()) &&
+          result.is(VectorLoadICDescriptor::SlotRegister())));
+
+  // StringCharAtGenerator doesn't use the result register until it's passed
+  // the different miss possibilities. If it did, we would have a conflict
+  // when FLAG_vector_ics is true.
+
+  StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
+                                          &miss,  // When not a string.
+                                          &miss,  // When not a number.
+                                          &miss,  // When index out of range.
+                                          STRING_INDEX_IS_ARRAY_INDEX,
+                                          RECEIVER_IS_STRING);
+  char_at_generator.GenerateFast(masm);
+  __ ret(0);
+
+  StubRuntimeCallHelper call_helper;
+  char_at_generator.GenerateSlow(masm, call_helper);
+
+  __ bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
   // The key is in edx and the parameter count is in eax.
   DCHECK(edx.is(ArgumentsAccessReadDescriptor::index()));
@@ -1871,6 +1918,10 @@
   // edi - function
   // edx - slot id
   Isolate* isolate = masm->isolate();
+  const int with_types_offset =
+      FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
+  const int generic_offset =
+      FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
   Label extra_checks_or_miss, slow_start;
   Label slow, non_function, wrap, cont;
   Label have_js_function;
@@ -1910,28 +1961,66 @@
   }
 
   __ bind(&extra_checks_or_miss);
-  Label miss;
+  Label uninitialized, miss;
 
   __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size,
                            FixedArray::kHeaderSize));
   __ cmp(ecx, Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
   __ j(equal, &slow_start);
-  __ cmp(ecx, Immediate(TypeFeedbackVector::UninitializedSentinel(isolate)));
-  __ j(equal, &miss);
 
-  if (!FLAG_trace_ic) {
-    // We are going megamorphic. If the feedback is a JSFunction, it is fine
-    // to handle it here. More complex cases are dealt with in the runtime.
-    __ AssertNotSmi(ecx);
-    __ CmpObjectType(ecx, JS_FUNCTION_TYPE, ecx);
-    __ j(not_equal, &miss);
-    __ mov(FieldOperand(ebx, edx, times_half_pointer_size,
-                        FixedArray::kHeaderSize),
-           Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
-    __ jmp(&slow_start);
+  // The following cases attempt to handle MISS cases without going to the
+  // runtime.
+  if (FLAG_trace_ic) {
+    __ jmp(&miss);
   }
 
-  // We are here because tracing is on or we are going monomorphic.
+  __ cmp(ecx, Immediate(TypeFeedbackVector::UninitializedSentinel(isolate)));
+  __ j(equal, &uninitialized);
+
+  // We are going megamorphic. If the feedback is a JSFunction, it is fine
+  // to handle it here. More complex cases are dealt with in the runtime.
+  __ AssertNotSmi(ecx);
+  __ CmpObjectType(ecx, JS_FUNCTION_TYPE, ecx);
+  __ j(not_equal, &miss);
+  __ mov(
+      FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize),
+      Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
+  // We have to update statistics for runtime profiling.
+  __ sub(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1)));
+  __ add(FieldOperand(ebx, generic_offset), Immediate(Smi::FromInt(1)));
+  __ jmp(&slow_start);
+
+  __ bind(&uninitialized);
+
+  // We are going monomorphic, provided we actually have a JSFunction.
+  __ JumpIfSmi(edi, &miss);
+
+  // Goto miss case if we do not have a function.
+  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
+  __ j(not_equal, &miss);
+
+  // Make sure the function is not the Array() function, which requires special
+  // behavior on MISS.
+  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx);
+  __ cmp(edi, ecx);
+  __ j(equal, &miss);
+
+  // Update stats.
+  __ add(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1)));
+
+  // Store the function.
+  __ mov(
+      FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize),
+      edi);
+
+  // Update the write barrier.
+  __ mov(eax, edi);
+  __ RecordWriteArray(ebx, eax, edx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+  __ jmp(&have_js_function);
+
+  // We are here because tracing is on or we encountered a MISS case we can't
+  // handle here.
   __ bind(&miss);
   GenerateMiss(masm);
 
@@ -2437,18 +2526,18 @@
 
 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
   // If the receiver is a smi trigger the non-string case.
-  STATIC_ASSERT(kSmiTag == 0);
-  __ JumpIfSmi(object_, receiver_not_string_);
+  if (check_mode_ == RECEIVER_IS_UNKNOWN) {
+    __ JumpIfSmi(object_, receiver_not_string_);
 
-  // Fetch the instance type of the receiver into result register.
-  __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
-  __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
-  // If the receiver is not a string trigger the non-string case.
-  __ test(result_, Immediate(kIsNotStringMask));
-  __ j(not_zero, receiver_not_string_);
+    // Fetch the instance type of the receiver into result register.
+    __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
+    __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
+    // If the receiver is not a string trigger the non-string case.
+    __ test(result_, Immediate(kIsNotStringMask));
+    __ j(not_zero, receiver_not_string_);
+  }
 
   // If the index is non-smi trigger the non-smi case.
-  STATIC_ASSERT(kSmiTag == 0);
   __ JumpIfNotSmi(index_, &index_not_smi_);
   __ bind(&got_smi_index_);
 
@@ -2817,14 +2906,61 @@
   // ebx: instance type
   // ecx: sub string length (smi)
   // edx: from index (smi)
-  StringCharAtGenerator generator(
-      eax, edx, ecx, eax, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
+  StringCharAtGenerator generator(eax, edx, ecx, eax, &runtime, &runtime,
+                                  &runtime, STRING_INDEX_IS_NUMBER,
+                                  RECEIVER_IS_STRING);
   generator.GenerateFast(masm);
   __ ret(3 * kPointerSize);
   generator.SkipSlow(masm, &runtime);
 }
 
 
+void ToNumberStub::Generate(MacroAssembler* masm) {
+  // The ToNumber stub takes one argument in eax.
+  Label not_smi;
+  __ JumpIfNotSmi(eax, &not_smi, Label::kNear);
+  __ Ret();
+  __ bind(&not_smi);
+
+  Label not_heap_number;
+  __ CompareMap(eax, masm->isolate()->factory()->heap_number_map());
+  __ j(not_equal, &not_heap_number, Label::kNear);
+  __ Ret();
+  __ bind(&not_heap_number);
+
+  Label not_string, slow_string;
+  __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edi);
+  // eax: object
+  // edi: object map
+  __ j(above_equal, &not_string, Label::kNear);
+  // Check if string has a cached array index.
+  __ test(FieldOperand(eax, String::kHashFieldOffset),
+          Immediate(String::kContainsCachedArrayIndexMask));
+  __ j(not_zero, &slow_string, Label::kNear);
+  __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
+  __ IndexFromHash(eax, eax);
+  __ Ret();
+  __ bind(&slow_string);
+  __ pop(ecx);   // Pop return address.
+  __ push(eax);  // Push argument.
+  __ push(ecx);  // Push return address.
+  __ TailCallRuntime(Runtime::kStringToNumber, 1, 1);
+  __ bind(&not_string);
+
+  Label not_oddball;
+  __ CmpInstanceType(edi, ODDBALL_TYPE);
+  __ j(not_equal, &not_oddball, Label::kNear);
+  __ mov(eax, FieldOperand(eax, Oddball::kToNumberOffset));
+  __ Ret();
+  __ bind(&not_oddball);
+
+  __ pop(ecx);   // Pop return address.
+  __ push(eax);  // Push argument.
+  __ push(ecx);  // Push return address.
+  __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
+}
+
+
 void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm,
                                                    Register left,
                                                    Register right,
diff --git a/src/x87/code-stubs-x87.h b/src/x87/code-stubs-x87.h
index 03ff477..a079b6f 100644
--- a/src/x87/code-stubs-x87.h
+++ b/src/x87/code-stubs-x87.h
@@ -76,7 +76,7 @@
                                      Register r0,
                                      Register r1);
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
  private:
   static const int kInlinedProbes = 4;
@@ -139,7 +139,7 @@
     INCREMENTAL_COMPACTION
   };
 
-  virtual bool SometimesSetsUpAFrame() { return false; }
+  bool SometimesSetsUpAFrame() OVERRIDE { return false; }
 
   static const byte kTwoByteNopInstruction = 0x3c;  // Cmpb al, #imm8.
   static const byte kTwoByteJumpInstruction = 0xeb;  // Jmp #imm8.
@@ -328,9 +328,9 @@
     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
   };
 
-  virtual inline Major MajorKey() const FINAL OVERRIDE { return RecordWrite; }
+  inline Major MajorKey() const FINAL { return RecordWrite; }
 
-  virtual void Generate(MacroAssembler* masm) OVERRIDE;
+  void Generate(MacroAssembler* masm) OVERRIDE;
   void GenerateIncremental(MacroAssembler* masm, Mode mode);
   void CheckNeedsToInformIncrementalMarker(
       MacroAssembler* masm,
@@ -338,7 +338,7 @@
       Mode mode);
   void InformIncrementalMarker(MacroAssembler* masm);
 
-  void Activate(Code* code) {
+  void Activate(Code* code) OVERRIDE {
     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
   }
 
diff --git a/src/x87/codegen-x87.cc b/src/x87/codegen-x87.cc
index e33959e..1321461 100644
--- a/src/x87/codegen-x87.cc
+++ b/src/x87/codegen-x87.cc
@@ -380,6 +380,19 @@
   __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx);
   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
 
+  // Allocating heap numbers in the loop below can fail and cause a jump to
+  // gc_required. We can't leave a partly initialized FixedArray behind,
+  // so pessimistically fill it with holes now.
+  Label initialization_loop, initialization_loop_entry;
+  __ jmp(&initialization_loop_entry, Label::kNear);
+  __ bind(&initialization_loop);
+  __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize),
+         masm->isolate()->factory()->the_hole_value());
+  __ bind(&initialization_loop_entry);
+  __ sub(ebx, Immediate(Smi::FromInt(1)));
+  __ j(not_sign, &initialization_loop);
+
+  __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
   __ jmp(&entry);
 
   // ebx: target map
diff --git a/src/x87/debug-x87.cc b/src/x87/debug-x87.cc
index 92c23ab..cdbcbad 100644
--- a/src/x87/debug-x87.cc
+++ b/src/x87/debug-x87.cc
@@ -182,7 +182,11 @@
   // Register state for IC load call (from ic-x87.cc).
   Register receiver = LoadDescriptor::ReceiverRegister();
   Register name = LoadDescriptor::NameRegister();
-  Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit(), 0, false);
+  RegList regs = receiver.bit() | name.bit();
+  if (FLAG_vector_ics) {
+    regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
+  }
+  Generate_DebugBreakCallHelper(masm, regs, 0, false);
 }
 
 
diff --git a/src/x87/deoptimizer-x87.cc b/src/x87/deoptimizer-x87.cc
index a76c7a7..0e53a0e 100644
--- a/src/x87/deoptimizer-x87.cc
+++ b/src/x87/deoptimizer-x87.cc
@@ -27,7 +27,7 @@
   HandleScope scope(isolate);
 
   // Compute the size of relocation information needed for the code
-  // patching in Deoptimizer::DeoptimizeFunction.
+  // patching in Deoptimizer::PatchCodeForDeoptimization below.
   int min_reloc_size = 0;
   int prev_pc_offset = 0;
   DeoptimizationInputData* deopt_data =
diff --git a/src/x87/disasm-x87.cc b/src/x87/disasm-x87.cc
index 908e8b0..8c77d77 100644
--- a/src/x87/disasm-x87.cc
+++ b/src/x87/disasm-x87.cc
@@ -1698,17 +1698,17 @@
 //------------------------------------------------------------------------------
 
 
-static const char* cpu_regs[8] = {
+static const char* const cpu_regs[8] = {
   "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
 };
 
 
-static const char* byte_cpu_regs[8] = {
+static const char* const byte_cpu_regs[8] = {
   "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
 };
 
 
-static const char* xmm_regs[8] = {
+static const char* const xmm_regs[8] = {
   "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
 };
 
diff --git a/src/x87/full-codegen-x87.cc b/src/x87/full-codegen-x87.cc
index c159edd..0f292cc 100644
--- a/src/x87/full-codegen-x87.cc
+++ b/src/x87/full-codegen-x87.cc
@@ -188,10 +188,10 @@
     Comment cmnt(masm_, "[ Allocate context");
     bool need_write_barrier = true;
     // Argument to NewContext is the function, which is still in edi.
-    if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
+    if (FLAG_harmony_scoping && info->scope()->is_script_scope()) {
       __ push(edi);
       __ Push(info->scope()->GetScopeInfo());
-      __ CallRuntime(Runtime::kNewGlobalContext, 2);
+      __ CallRuntime(Runtime::kNewScriptContext, 2);
     } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
       FastNewContextStub stub(isolate(), heap_slots);
       __ CallStub(&stub);
@@ -865,7 +865,7 @@
   EmitDebugCheckDeclarationContext(variable);
 
   // Load instance object.
-  __ LoadContext(eax, scope_->ContextChainLength(scope_->GlobalScope()));
+  __ LoadContext(eax, scope_->ContextChainLength(scope_->ScriptScope()));
   __ mov(eax, ContextOperand(eax, variable->interface()->Index()));
   __ mov(eax, ContextOperand(eax, Context::EXTENSION_INDEX));
 
@@ -1024,7 +1024,7 @@
 
 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
   Comment cmnt(masm_, "[ ForInStatement");
-  int slot = stmt->ForInFeedbackSlot();
+  FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
 
   SetStatementPosition(stmt);
 
@@ -1034,6 +1034,7 @@
 
   // Get the object to enumerate over. If the object is null or undefined, skip
   // over the loop.  See ECMA-262 version 5, section 12.6.4.
+  SetExpressionPosition(stmt->enumerable());
   VisitForAccumulatorValue(stmt->enumerable());
   __ cmp(eax, isolate()->factory()->undefined_value());
   __ j(equal, &exit);
@@ -1051,6 +1052,7 @@
   __ push(eax);
   __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
   __ bind(&done_convert);
+  PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG);
   __ push(eax);
 
   // Check for proxies.
@@ -1072,6 +1074,7 @@
   __ bind(&call_runtime);
   __ push(eax);
   __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
+  PrepareForBailoutForId(stmt->EnumId(), TOS_REG);
   __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
          isolate()->factory()->meta_map());
   __ j(not_equal, &fixed_array);
@@ -1106,7 +1109,8 @@
 
   // No need for a write barrier, we are storing a Smi in the feedback vector.
   __ LoadHeapObject(ebx, FeedbackVector());
-  __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(slot)),
+  int vector_index = FeedbackVector()->GetIndex(slot);
+  __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(vector_index)),
          Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate())));
 
   __ mov(ebx, Immediate(Smi::FromInt(1)));  // Smi indicates slow check
@@ -1125,6 +1129,8 @@
   // Generate code for doing the condition check.
   PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
   __ bind(&loop);
+  SetExpressionPosition(stmt->each());
+
   __ mov(eax, Operand(esp, 0 * kPointerSize));  // Get the current index.
   __ cmp(eax, Operand(esp, 1 * kPointerSize));  // Compare to the array length.
   __ j(above_equal, loop_statement.break_label());
@@ -1191,48 +1197,6 @@
 }
 
 
-void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
-  Comment cmnt(masm_, "[ ForOfStatement");
-  SetStatementPosition(stmt);
-
-  Iteration loop_statement(this, stmt);
-  increment_loop_depth();
-
-  // var iterator = iterable[Symbol.iterator]();
-  VisitForEffect(stmt->assign_iterator());
-
-  // Loop entry.
-  __ bind(loop_statement.continue_label());
-
-  // result = iterator.next()
-  VisitForEffect(stmt->next_result());
-
-  // if (result.done) break;
-  Label result_not_done;
-  VisitForControl(stmt->result_done(),
-                  loop_statement.break_label(),
-                  &result_not_done,
-                  &result_not_done);
-  __ bind(&result_not_done);
-
-  // each = result.value
-  VisitForEffect(stmt->assign_each());
-
-  // Generate code for the body of the loop.
-  Visit(stmt->body());
-
-  // Check stack before looping.
-  PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
-  EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
-  __ jmp(loop_statement.continue_label());
-
-  // Exit and decrement the loop depth.
-  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
-  __ bind(loop_statement.break_label());
-  decrement_loop_depth();
-}
-
-
 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
                                        bool pretenure) {
   // Use the fast case closure allocation code that allocates in new
@@ -1276,7 +1240,13 @@
   Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
   __ mov(LoadDescriptor::NameRegister(), home_object_symbol);
 
-  CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  if (FLAG_vector_ics) {
+    __ mov(VectorLoadICDescriptor::SlotRegister(),
+           Immediate(SmiFromSlot(expr->HomeObjectFeedbackSlot())));
+    CallLoadIC(NOT_CONTEXTUAL);
+  } else {
+    CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+  }
 
   __ cmp(eax, isolate()->factory()->undefined_value());
   Label done;
@@ -1286,6 +1256,19 @@
 }
 
 
+void FullCodeGenerator::EmitSetHomeObjectIfNeeded(Expression* initializer,
+                                                  int offset) {
+  if (NeedsHomeObject(initializer)) {
+    __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
+    __ mov(StoreDescriptor::NameRegister(),
+           Immediate(isolate()->factory()->home_object_symbol()));
+    __ mov(StoreDescriptor::ValueRegister(),
+           Operand(esp, offset * kPointerSize));
+    CallStoreIC();
+  }
+}
+
+
 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
                                                       TypeofState typeof_state,
                                                       Label* slow) {
@@ -1340,7 +1323,7 @@
   __ mov(LoadDescriptor::NameRegister(), proxy->var()->name());
   if (FLAG_vector_ics) {
     __ mov(VectorLoadICDescriptor::SlotRegister(),
-           Immediate(Smi::FromInt(proxy->VariableFeedbackSlot())));
+           Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
   }
 
   ContextualMode mode = (typeof_state == INSIDE_TYPEOF)
@@ -1427,7 +1410,7 @@
       __ mov(LoadDescriptor::NameRegister(), var->name());
       if (FLAG_vector_ics) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
-               Immediate(Smi::FromInt(proxy->VariableFeedbackSlot())));
+               Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
       }
       CallLoadIC(CONTEXTUAL);
       context()->Plug(eax);
@@ -1611,6 +1594,7 @@
     FastCloneShallowObjectStub stub(isolate(), properties_count);
     __ CallStub(&stub);
   }
+  PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
 
   // If result_saved is true the result is on top of the stack.  If
   // result_saved is false the result is in eax.
@@ -1639,6 +1623,8 @@
         DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
         // Fall through.
       case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             VisitForAccumulatorValue(value);
@@ -1647,6 +1633,14 @@
             __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0));
             CallStoreIC(key->LiteralFeedbackId());
             PrepareForBailoutForId(key->id(), NO_REGISTERS);
+
+            if (NeedsHomeObject(value)) {
+              __ mov(StoreDescriptor::ReceiverRegister(), eax);
+              __ mov(StoreDescriptor::NameRegister(),
+                     Immediate(isolate()->factory()->home_object_symbol()));
+              __ mov(StoreDescriptor::ValueRegister(), Operand(esp, 0));
+              CallStoreIC();
+            }
           } else {
             VisitForEffect(value);
           }
@@ -1656,6 +1650,7 @@
         VisitForStackValue(key);
         VisitForStackValue(value);
         if (property->emit_store()) {
+          EmitSetHomeObjectIfNeeded(value, 2);
           __ push(Immediate(Smi::FromInt(SLOPPY)));  // Strict mode
           __ CallRuntime(Runtime::kSetProperty, 4);
         } else {
@@ -1666,7 +1661,7 @@
         __ push(Operand(esp, 0));  // Duplicate receiver.
         VisitForStackValue(value);
         if (property->emit_store()) {
-          __ CallRuntime(Runtime::kSetPrototype, 2);
+          __ CallRuntime(Runtime::kInternalSetPrototype, 2);
         } else {
           __ Drop(2);
         }
@@ -1688,7 +1683,9 @@
     __ push(Operand(esp, 0));  // Duplicate receiver.
     VisitForStackValue(it->first);
     EmitAccessor(it->second->getter);
+    EmitSetHomeObjectIfNeeded(it->second->getter, 2);
     EmitAccessor(it->second->setter);
+    EmitSetHomeObjectIfNeeded(it->second->setter, 3);
     __ push(Immediate(Smi::FromInt(NONE)));
     __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
   }
@@ -1801,22 +1798,23 @@
 
   Comment cmnt(masm_, "[ Assignment");
 
-  // Left-hand side can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* property = expr->target()->AsProperty();
-  if (property != NULL) {
-    assign_type = (property->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(property);
 
   // Evaluate LHS expression.
   switch (assign_type) {
     case VARIABLE:
       // Nothing to do here.
       break;
+    case NAMED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ push(result_register());
+      if (expr->is_compound()) {
+        __ push(MemOperand(esp, kPointerSize));
+        __ push(result_register());
+      }
+      break;
     case NAMED_PROPERTY:
       if (expr->is_compound()) {
         // We need the receiver both on the stack and in the register.
@@ -1826,6 +1824,18 @@
         VisitForStackValue(property->obj());
       }
       break;
+    case KEYED_SUPER_PROPERTY:
+      VisitForStackValue(property->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(property->obj()->AsSuperReference());
+      __ Push(result_register());
+      VisitForAccumulatorValue(property->key());
+      __ Push(result_register());
+      if (expr->is_compound()) {
+        __ push(MemOperand(esp, 2 * kPointerSize));
+        __ push(MemOperand(esp, 2 * kPointerSize));
+        __ push(result_register());
+      }
+      break;
     case KEYED_PROPERTY: {
       if (expr->is_compound()) {
         VisitForStackValue(property->obj());
@@ -1850,10 +1860,18 @@
           EmitVariableLoad(expr->target()->AsVariableProxy());
           PrepareForBailout(expr->target(), TOS_REG);
           break;
+        case NAMED_SUPER_PROPERTY:
+          EmitNamedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
         case NAMED_PROPERTY:
           EmitNamedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
           break;
+        case KEYED_SUPER_PROPERTY:
+          EmitKeyedSuperPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
         case KEYED_PROPERTY:
           EmitKeyedPropertyLoad(property);
           PrepareForBailoutForId(property->LoadId(), TOS_REG);
@@ -1899,6 +1917,14 @@
     case NAMED_PROPERTY:
       EmitNamedPropertyAssignment(expr);
       break;
+    case NAMED_SUPER_PROPERTY:
+      EmitNamedSuperPropertyStore(property);
+      context()->Plug(result_register());
+      break;
+    case KEYED_SUPER_PROPERTY:
+      EmitKeyedSuperPropertyStore(property);
+      context()->Plug(result_register());
+      break;
     case KEYED_PROPERTY:
       EmitKeyedPropertyAssignment(expr);
       break;
@@ -2031,7 +2057,7 @@
       __ mov(load_receiver, Operand(esp, kPointerSize));
       if (FLAG_vector_ics) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
-               Immediate(Smi::FromInt(expr->KeyedLoadFeedbackSlot())));
+               Immediate(SmiFromSlot(expr->KeyedLoadFeedbackSlot())));
       }
       Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
       CallIC(ic, TypeFeedbackId::None());
@@ -2051,7 +2077,7 @@
              isolate()->factory()->done_string());       // "done"
       if (FLAG_vector_ics) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
-               Immediate(Smi::FromInt(expr->DoneFeedbackSlot())));
+               Immediate(SmiFromSlot(expr->DoneFeedbackSlot())));
       }
       CallLoadIC(NOT_CONTEXTUAL);                        // result.done in eax
       Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
@@ -2065,7 +2091,7 @@
              isolate()->factory()->value_string());       // "value"
       if (FLAG_vector_ics) {
         __ mov(VectorLoadICDescriptor::SlotRegister(),
-               Immediate(Smi::FromInt(expr->ValueFeedbackSlot())));
+               Immediate(SmiFromSlot(expr->ValueFeedbackSlot())));
       }
       CallLoadIC(NOT_CONTEXTUAL);                         // result.value in eax
       context()->DropAndPlug(2, eax);                     // drop iter and g
@@ -2086,15 +2112,6 @@
   VisitForAccumulatorValue(value);
   __ pop(ebx);
 
-  // Check generator state.
-  Label wrong_state, closed_state, done;
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
-  STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
-  __ cmp(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset),
-         Immediate(Smi::FromInt(0)));
-  __ j(equal, &closed_state);
-  __ j(less, &wrong_state);
-
   // Load suspended function and context.
   __ mov(esi, FieldOperand(ebx, JSGeneratorObject::kContextOffset));
   __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
@@ -2116,7 +2133,7 @@
 
   // Enter a new JavaScript frame, and initialize its slots as they were when
   // the generator was suspended.
-  Label resume_frame;
+  Label resume_frame, done;
   __ bind(&push_frame);
   __ call(&resume_frame);
   __ jmp(&done);
@@ -2163,25 +2180,6 @@
   // Not reached: the runtime call returns elsewhere.
   __ Abort(kGeneratorFailedToResume);
 
-  // Reach here when generator is closed.
-  __ bind(&closed_state);
-  if (resume_mode == JSGeneratorObject::NEXT) {
-    // Return completed iterator result when generator is closed.
-    __ push(Immediate(isolate()->factory()->undefined_value()));
-    // Pop value from top-of-stack slot; box result into result register.
-    EmitCreateIteratorResult(true);
-  } else {
-    // Throw the provided value.
-    __ push(eax);
-    __ CallRuntime(Runtime::kThrow, 1);
-  }
-  __ jmp(&done);
-
-  // Throw error if we attempt to operate on a running generator.
-  __ bind(&wrong_state);
-  __ push(ebx);
-  __ CallRuntime(Runtime::kThrowGeneratorStateError, 1);
-
   __ bind(&done);
   context()->Plug(result_register());
 }
@@ -2229,10 +2227,12 @@
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
   DCHECK(!key->value()->IsSmi());
+  DCHECK(!prop->IsSuperAccess());
+
   __ mov(LoadDescriptor::NameRegister(), Immediate(key->value()));
   if (FLAG_vector_ics) {
     __ mov(VectorLoadICDescriptor::SlotRegister(),
-           Immediate(Smi::FromInt(prop->PropertyFeedbackSlot())));
+           Immediate(SmiFromSlot(prop->PropertyFeedbackSlot())));
     CallLoadIC(NOT_CONTEXTUAL);
   } else {
     CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
@@ -2241,15 +2241,12 @@
 
 
 void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object.
   SetSourcePosition(prop->position());
   Literal* key = prop->key()->AsLiteral();
   DCHECK(!key->value()->IsSmi());
   DCHECK(prop->IsSuperAccess());
 
-  SuperReference* super_ref = prop->obj()->AsSuperReference();
-  EmitLoadHomeObject(super_ref);
-  __ push(eax);
-  VisitForStackValue(super_ref->this_var());
   __ push(Immediate(key->value()));
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 }
@@ -2260,7 +2257,7 @@
   Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
   if (FLAG_vector_ics) {
     __ mov(VectorLoadICDescriptor::SlotRegister(),
-           Immediate(Smi::FromInt(prop->PropertyFeedbackSlot())));
+           Immediate(SmiFromSlot(prop->PropertyFeedbackSlot())));
     CallIC(ic);
   } else {
     CallIC(ic, prop->PropertyFeedbackId());
@@ -2268,6 +2265,14 @@
 }
 
 
+void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
+  // Stack: receiver, home_object, key.
+  SetSourcePosition(prop->position());
+
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+}
+
+
 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
                                               Token::Value op,
                                               OverwriteMode mode,
@@ -2363,6 +2368,61 @@
 }
 
 
+void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
+  // Constructor is in eax.
+  DCHECK(lit != NULL);
+  __ push(eax);
+
+  // No access check is needed here since the constructor is created by the
+  // class literal.
+  Register scratch = ebx;
+  __ mov(scratch, FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset));
+  __ Push(scratch);
+
+  for (int i = 0; i < lit->properties()->length(); i++) {
+    ObjectLiteral::Property* property = lit->properties()->at(i);
+    Literal* key = property->key()->AsLiteral();
+    Expression* value = property->value();
+    DCHECK(key != NULL);
+
+    if (property->is_static()) {
+      __ push(Operand(esp, kPointerSize));  // constructor
+    } else {
+      __ push(Operand(esp, 0));  // prototype
+    }
+    VisitForStackValue(key);
+    VisitForStackValue(value);
+    EmitSetHomeObjectIfNeeded(value, 2);
+
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT:
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+      case ObjectLiteral::Property::COMPUTED:
+      case ObjectLiteral::Property::PROTOTYPE:
+        __ CallRuntime(Runtime::kDefineClassMethod, 3);
+        break;
+
+      case ObjectLiteral::Property::GETTER:
+        __ CallRuntime(Runtime::kDefineClassGetter, 3);
+        break;
+
+      case ObjectLiteral::Property::SETTER:
+        __ CallRuntime(Runtime::kDefineClassSetter, 3);
+        break;
+
+      default:
+        UNREACHABLE();
+    }
+  }
+
+  // prototype
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+
+  // constructor
+  __ CallRuntime(Runtime::kToFastProperties, 1);
+}
+
+
 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
                                      Token::Value op,
                                      OverwriteMode mode) {
@@ -2378,16 +2438,8 @@
 void FullCodeGenerator::EmitAssignment(Expression* expr) {
   DCHECK(expr->IsValidReferenceExpression());
 
-  // Left-hand side can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* prop = expr->AsProperty();
-  if (prop != NULL) {
-    assign_type = (prop->key()->IsPropertyName())
-        ? NAMED_PROPERTY
-        : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(prop);
 
   switch (assign_type) {
     case VARIABLE: {
@@ -2406,6 +2458,42 @@
       CallStoreIC();
       break;
     }
+    case NAMED_SUPER_PROPERTY: {
+      __ push(eax);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      // stack: value, this; eax: home_object
+      Register scratch = ecx;
+      Register scratch2 = edx;
+      __ mov(scratch, result_register());               // home_object
+      __ mov(eax, MemOperand(esp, kPointerSize));       // value
+      __ mov(scratch2, MemOperand(esp, 0));             // this
+      __ mov(MemOperand(esp, kPointerSize), scratch2);  // this
+      __ mov(MemOperand(esp, 0), scratch);              // home_object
+      // stack: this, home_object. eax: value
+      EmitNamedSuperPropertyStore(prop);
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      __ push(eax);
+      VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(prop->obj()->AsSuperReference());
+      __ push(result_register());
+      VisitForAccumulatorValue(prop->key());
+      Register scratch = ecx;
+      Register scratch2 = edx;
+      __ mov(scratch2, MemOperand(esp, 2 * kPointerSize));  // value
+      // stack: value, this, home_object; eax: key, edx: value
+      __ mov(scratch, MemOperand(esp, kPointerSize));  // this
+      __ mov(MemOperand(esp, 2 * kPointerSize), scratch);
+      __ mov(scratch, MemOperand(esp, 0));  // home_object
+      __ mov(MemOperand(esp, kPointerSize), scratch);
+      __ mov(MemOperand(esp, 0), eax);
+      __ mov(eax, scratch2);
+      // stack: this, home_object, key; eax: value.
+      EmitKeyedSuperPropertyStore(prop);
+      break;
+    }
     case KEYED_PROPERTY: {
       __ push(eax);  // Preserve value.
       VisitForStackValue(prop->obj());
@@ -2474,7 +2562,6 @@
     __ CallRuntime(Runtime::kThrowReferenceError, 1);
     __ bind(&assign);
     EmitStoreToStackLocalOrContextSlot(var, location);
-
   } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
     if (var->IsLookupSlot()) {
       // Assignment to var.
@@ -2496,8 +2583,9 @@
       }
       EmitStoreToStackLocalOrContextSlot(var, location);
     }
+  } else if (IsSignallingAssignmentToConst(var, op, strict_mode())) {
+    __ CallRuntime(Runtime::kThrowConstAssignError, 0);
   }
-  // Non-initializing assignments to consts are ignored.
 }
 
 
@@ -2520,6 +2608,34 @@
 }
 
 
+void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // eax : value
+  // stack : receiver ('this'), home_object
+  DCHECK(prop != NULL);
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(key != NULL);
+
+  __ push(Immediate(key->value()));
+  __ push(eax);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreToSuper_Strict
+                                          : Runtime::kStoreToSuper_Sloppy),
+                 4);
+}
+
+
+void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
+  // Assignment to named property of super.
+  // eax : value
+  // stack : receiver ('this'), home_object, key
+
+  __ push(eax);
+  __ CallRuntime((strict_mode() == STRICT ? Runtime::kStoreKeyedToSuper_Strict
+                                          : Runtime::kStoreKeyedToSuper_Sloppy),
+                 4);
+}
+
+
 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
   // Assignment to a property, using a keyed store IC.
   // eax               : value
@@ -2549,16 +2665,27 @@
       __ Move(LoadDescriptor::ReceiverRegister(), result_register());
       EmitNamedPropertyLoad(expr);
     } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ push(result_register());
       EmitNamedSuperPropertyLoad(expr);
     }
     PrepareForBailoutForId(expr->LoadId(), TOS_REG);
     context()->Plug(eax);
   } else {
-    VisitForStackValue(expr->obj());
-    VisitForAccumulatorValue(expr->key());
-    __ pop(LoadDescriptor::ReceiverRegister());                  // Object.
-    __ Move(LoadDescriptor::NameRegister(), result_register());  // Key.
-    EmitKeyedPropertyLoad(expr);
+    if (!expr->IsSuperAccess()) {
+      VisitForStackValue(expr->obj());
+      VisitForAccumulatorValue(expr->key());
+      __ pop(LoadDescriptor::ReceiverRegister());                  // Object.
+      __ Move(LoadDescriptor::NameRegister(), result_register());  // Key.
+      EmitKeyedPropertyLoad(expr);
+    } else {
+      VisitForStackValue(expr->obj()->AsSuperReference()->this_var());
+      EmitLoadHomeObject(expr->obj()->AsSuperReference());
+      __ push(result_register());
+      VisitForStackValue(expr->key());
+      EmitKeyedSuperPropertyLoad(expr);
+    }
     context()->Plug(eax);
   }
 }
@@ -2617,14 +2744,14 @@
   __ push(eax);
   VisitForAccumulatorValue(super_ref->this_var());
   __ push(eax);
-  __ push(Operand(esp, kPointerSize));
   __ push(eax);
+  __ push(Operand(esp, kPointerSize * 2));
   __ push(Immediate(key->value()));
   // Stack here:
   //  - home_object
   //  - this (receiver)
-  //  - home_object <-- LoadFromSuper will pop here and below.
-  //  - this (receiver)
+  //  - this (receiver) <-- LoadFromSuper will pop here and below.
+  //  - home_object
   //  - key
   __ CallRuntime(Runtime::kLoadFromSuper, 3);
 
@@ -2661,6 +2788,40 @@
 }
 
 
+void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
+  Expression* callee = expr->expression();
+  DCHECK(callee->IsProperty());
+  Property* prop = callee->AsProperty();
+  DCHECK(prop->IsSuperAccess());
+
+  SetSourcePosition(prop->position());
+  // Load the function from the receiver.
+  SuperReference* super_ref = callee->AsProperty()->obj()->AsSuperReference();
+  EmitLoadHomeObject(super_ref);
+  __ push(eax);
+  VisitForAccumulatorValue(super_ref->this_var());
+  __ push(eax);
+  __ push(eax);
+  __ push(Operand(esp, kPointerSize * 2));
+  VisitForStackValue(prop->key());
+  // Stack here:
+  //  - home_object
+  //  - this (receiver)
+  //  - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
+  //  - home_object
+  //  - key
+  __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3);
+
+  // Replace home_object with target function.
+  __ mov(Operand(esp, kPointerSize), eax);
+
+  // Stack here:
+  // - target function
+  // - this (receiver)
+  EmitCall(expr, CallICState::METHOD);
+}
+
+
 void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
   // Load the arguments.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2675,7 +2836,7 @@
   SetSourcePosition(expr->position());
   Handle<Code> ic = CallIC::initialize_stub(
       isolate(), arg_count, call_type);
-  __ Move(edx, Immediate(Smi::FromInt(expr->CallFeedbackSlot())));
+  __ Move(edx, Immediate(SmiFromSlot(expr->CallFeedbackSlot())));
   __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
   // Don't assign a type feedback id to the IC, since type feedback is provided
   // by the vector above.
@@ -2713,6 +2874,13 @@
 }
 
 
+void FullCodeGenerator::EmitLoadSuperConstructor(SuperReference* super_ref) {
+  DCHECK(super_ref != NULL);
+  __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+  __ CallRuntime(Runtime::kGetPrototype, 1);
+}
+
+
 void FullCodeGenerator::VisitCall(Call* expr) {
 #ifdef DEBUG
   // We want to verify that RecordJSReturnSite gets called on all paths
@@ -2748,6 +2916,8 @@
       // edx (receiver). Touch up the stack with the right values.
       __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
       __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
+
+      PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
     }
     // Record source position for debugger.
     SetSourcePosition(expr->position());
@@ -2779,6 +2949,7 @@
     __ CallRuntime(Runtime::kLoadLookupSlot, 2);
     __ push(eax);  // Function.
     __ push(edx);  // Receiver.
+    PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
 
     // If fast case code has been generated, emit code to push the function
     // and receiver and have the slow path jump around this code.
@@ -2801,9 +2972,12 @@
   } else if (call_type == Call::PROPERTY_CALL) {
     Property* property = callee->AsProperty();
     bool is_named_call = property->key()->IsPropertyName();
-    // super.x() is handled in EmitCallWithLoadIC.
-    if (property->IsSuperAccess() && is_named_call) {
-      EmitSuperCallWithLoadIC(expr);
+    if (property->IsSuperAccess()) {
+      if (is_named_call) {
+        EmitSuperCallWithLoadIC(expr);
+      } else {
+        EmitKeyedSuperCallWithLoadIC(expr);
+      }
     } else {
       {
         PreservePositionScope scope(masm()->positions_recorder());
@@ -2815,6 +2989,12 @@
         EmitKeyedCallWithLoadIC(expr, property->key());
       }
     }
+  } else if (call_type == Call::SUPER_CALL) {
+    SuperReference* super_ref = callee->AsSuperReference();
+    EmitLoadSuperConstructor(super_ref);
+    __ push(result_register());
+    VisitForStackValue(super_ref->this_var());
+    EmitCall(expr, CallICState::METHOD);
   } else {
     DCHECK(call_type == Call::OTHER_CALL);
     // Call to an arbitrary expression not handled specially above.
@@ -2842,7 +3022,12 @@
   // Push constructor on the stack.  If it's not a function it's used as
   // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
   // ignored.
-  VisitForStackValue(expr->expression());
+  if (expr->expression()->IsSuperReference()) {
+    EmitLoadSuperConstructor(expr->expression()->AsSuperReference());
+    __ push(result_register());
+  } else {
+    VisitForStackValue(expr->expression());
+  }
 
   // Push the arguments ("left-to-right") on the stack.
   ZoneList<Expression*>* args = expr->arguments();
@@ -2862,12 +3047,12 @@
   // Record call targets in unoptimized code.
   if (FLAG_pretenuring_call_new) {
     EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
-    DCHECK(expr->AllocationSiteFeedbackSlot() ==
-           expr->CallNewFeedbackSlot() + 1);
+    DCHECK(expr->AllocationSiteFeedbackSlot().ToInt() ==
+           expr->CallNewFeedbackSlot().ToInt() + 1);
   }
 
   __ LoadHeapObject(ebx, FeedbackVector());
-  __ mov(edx, Immediate(Smi::FromInt(expr->CallNewFeedbackSlot())));
+  __ mov(edx, Immediate(SmiFromSlot(expr->CallNewFeedbackSlot())));
 
   CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
   __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
@@ -3181,6 +3366,31 @@
 }
 
 
+void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
+                         &if_false, &fall_through);
+
+  __ JumpIfSmi(eax, if_false);
+  Register map = ebx;
+  __ mov(map, FieldOperand(eax, HeapObject::kMapOffset));
+  __ CmpInstanceType(map, FIRST_JS_PROXY_TYPE);
+  __ j(less, if_false);
+  __ CmpInstanceType(map, LAST_JS_PROXY_TYPE);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(less_equal, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
 
 void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
   DCHECK(expr->arguments()->length() == 0);
@@ -4118,7 +4328,7 @@
     __ mov(LoadDescriptor::NameRegister(), Immediate(expr->name()));
     if (FLAG_vector_ics) {
       __ mov(VectorLoadICDescriptor::SlotRegister(),
-             Immediate(Smi::FromInt(expr->CallRuntimeFeedbackSlot())));
+             Immediate(SmiFromSlot(expr->CallRuntimeFeedbackSlot())));
       CallLoadIC(NOT_CONTEXTUAL);
     } else {
       CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
@@ -4279,17 +4489,8 @@
   Comment cmnt(masm_, "[ CountOperation");
   SetSourcePosition(expr->position());
 
-  // Expression can only be a property, a global or a (parameter or local)
-  // slot.
-  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
-  LhsKind assign_type = VARIABLE;
   Property* prop = expr->expression()->AsProperty();
-  // In case of a property we use the uninitialized expression context
-  // of the key to detect a named property.
-  if (prop != NULL) {
-    assign_type =
-        (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
-  }
+  LhsKind assign_type = GetAssignType(prop);
 
   // Evaluate expression and get value.
   if (assign_type == VARIABLE) {
@@ -4301,18 +4502,50 @@
     if (expr->is_postfix() && !context()->IsEffect()) {
       __ push(Immediate(Smi::FromInt(0)));
     }
-    if (assign_type == NAMED_PROPERTY) {
-      // Put the object both on the stack and in the register.
-      VisitForStackValue(prop->obj());
-      __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
-      EmitNamedPropertyLoad(prop);
-    } else {
-      VisitForStackValue(prop->obj());
-      VisitForStackValue(prop->key());
-      __ mov(LoadDescriptor::ReceiverRegister(),
-             Operand(esp, kPointerSize));                       // Object.
-      __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0));  // Key.
-      EmitKeyedPropertyLoad(prop);
+    switch (assign_type) {
+      case NAMED_PROPERTY: {
+        // Put the object both on the stack and in the register.
+        VisitForStackValue(prop->obj());
+        __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0));
+        EmitNamedPropertyLoad(prop);
+        break;
+      }
+
+      case NAMED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        __ push(result_register());
+        __ push(MemOperand(esp, kPointerSize));
+        __ push(result_register());
+        EmitNamedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_SUPER_PROPERTY: {
+        VisitForStackValue(prop->obj()->AsSuperReference()->this_var());
+        EmitLoadHomeObject(prop->obj()->AsSuperReference());
+        __ push(result_register());
+        VisitForAccumulatorValue(prop->key());
+        __ push(result_register());
+        __ push(MemOperand(esp, 2 * kPointerSize));
+        __ push(MemOperand(esp, 2 * kPointerSize));
+        __ push(result_register());
+        EmitKeyedSuperPropertyLoad(prop);
+        break;
+      }
+
+      case KEYED_PROPERTY: {
+        VisitForStackValue(prop->obj());
+        VisitForStackValue(prop->key());
+        __ mov(LoadDescriptor::ReceiverRegister(),
+               Operand(esp, kPointerSize));                       // Object.
+        __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0));  // Key.
+        EmitKeyedPropertyLoad(prop);
+        break;
+      }
+
+      case VARIABLE:
+        UNREACHABLE();
     }
   }
 
@@ -4344,9 +4577,15 @@
           case NAMED_PROPERTY:
             __ mov(Operand(esp, kPointerSize), eax);
             break;
+          case NAMED_SUPER_PROPERTY:
+            __ mov(Operand(esp, 2 * kPointerSize), eax);
+            break;
           case KEYED_PROPERTY:
             __ mov(Operand(esp, 2 * kPointerSize), eax);
             break;
+          case KEYED_SUPER_PROPERTY:
+            __ mov(Operand(esp, 3 * kPointerSize), eax);
+            break;
         }
       }
     }
@@ -4382,9 +4621,15 @@
         case NAMED_PROPERTY:
           __ mov(Operand(esp, kPointerSize), eax);
           break;
+        case NAMED_SUPER_PROPERTY:
+          __ mov(Operand(esp, 2 * kPointerSize), eax);
+          break;
         case KEYED_PROPERTY:
           __ mov(Operand(esp, 2 * kPointerSize), eax);
           break;
+        case KEYED_SUPER_PROPERTY:
+          __ mov(Operand(esp, 3 * kPointerSize), eax);
+          break;
       }
     }
   }
@@ -4441,6 +4686,28 @@
       }
       break;
     }
+    case NAMED_SUPER_PROPERTY: {
+      EmitNamedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(eax);
+      }
+      break;
+    }
+    case KEYED_SUPER_PROPERTY: {
+      EmitKeyedSuperPropertyStore(prop);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(eax);
+      }
+      break;
+    }
     case KEYED_PROPERTY: {
       __ pop(StoreDescriptor::NameRegister());
       __ pop(StoreDescriptor::ReceiverRegister());
@@ -4473,7 +4740,7 @@
     __ mov(LoadDescriptor::NameRegister(), Immediate(proxy->name()));
     if (FLAG_vector_ics) {
       __ mov(VectorLoadICDescriptor::SlotRegister(),
-             Immediate(Smi::FromInt(proxy->VariableFeedbackSlot())));
+             Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
     }
     // Use a regular load, not a contextual load, to avoid a reference
     // error.
@@ -4708,7 +4975,7 @@
 
 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
   Scope* declaration_scope = scope()->DeclarationScope();
-  if (declaration_scope->is_global_scope() ||
+  if (declaration_scope->is_script_scope() ||
       declaration_scope->is_module_scope()) {
     // Contexts nested in the native context have a canonical empty function
     // as their closure, not the anonymous closure containing the global
diff --git a/src/x87/interface-descriptors-x87.cc b/src/x87/interface-descriptors-x87.cc
index 8dfad36..26ce4dc 100644
--- a/src/x87/interface-descriptors-x87.cc
+++ b/src/x87/interface-descriptors-x87.cc
@@ -29,6 +29,9 @@
 const Register StoreDescriptor::ValueRegister() { return eax; }
 
 
+const Register StoreTransitionDescriptor::MapRegister() { return ebx; }
+
+
 const Register ElementTransitionAndStoreDescriptor::MapRegister() {
   return ebx;
 }
@@ -152,6 +155,15 @@
 }
 
 
+void AllocateHeapNumberDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // register state
+  // esi -- context
+  Register registers[] = {esi};
+  data->Initialize(arraysize(registers), registers, nullptr);
+}
+
+
 void ArrayConstructorConstantArgCountDescriptor::Initialize(
     CallInterfaceDescriptorData* data) {
   // register state
diff --git a/src/x87/lithium-codegen-x87.cc b/src/x87/lithium-codegen-x87.cc
index a5bc5ea..c292bb9 100644
--- a/src/x87/lithium-codegen-x87.cc
+++ b/src/x87/lithium-codegen-x87.cc
@@ -32,9 +32,9 @@
         deopt_mode_(mode) {}
   virtual ~SafepointGenerator() {}
 
-  virtual void BeforeCall(int call_size) const OVERRIDE {}
+  void BeforeCall(int call_size) const OVERRIDE {}
 
-  virtual void AfterCall() const OVERRIDE {
+  void AfterCall() const OVERRIDE {
     codegen_->RecordSafepoint(pointers_, deopt_mode_);
   }
 
@@ -2924,10 +2924,10 @@
                                   LInstanceOfKnownGlobal* instr,
                                   const X87Stack& x87_stack)
         : LDeferredCode(codegen, x87_stack), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
     Label* map_check() { return &map_check_; }
    private:
     LInstanceOfKnownGlobal* instr_;
@@ -3050,6 +3050,7 @@
     }
     __ Ret((parameter_count + extra_value_count) * kPointerSize, ecx);
   } else {
+    DCHECK(info()->IsStub());  // Functions would need to drop one more value.
     Register reg = ToRegister(instr->parameter_count());
     // The argument count parameter is a smi
     __ SmiUntag(reg);
@@ -3124,13 +3125,18 @@
 template <class T>
 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
   DCHECK(FLAG_vector_ics);
-  Register vector = ToRegister(instr->temp_vector());
-  DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
-  __ mov(vector, instr->hydrogen()->feedback_vector());
+  Register vector_register = ToRegister(instr->temp_vector());
+  Register slot_register = VectorLoadICDescriptor::SlotRegister();
+  DCHECK(vector_register.is(VectorLoadICDescriptor::VectorRegister()));
+  DCHECK(slot_register.is(eax));
+
+  AllowDeferredHandleDereference vector_structure_check;
+  Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+  __ mov(vector_register, vector);
   // No need to allocate this register.
-  DCHECK(VectorLoadICDescriptor::SlotRegister().is(eax));
-  __ mov(VectorLoadICDescriptor::SlotRegister(),
-         Immediate(Smi::FromInt(instr->hydrogen()->slot())));
+  FeedbackVectorICSlot slot = instr->hydrogen()->slot();
+  int index = vector->GetIndex(slot);
+  __ mov(slot_register, Immediate(Smi::FromInt(index)));
 }
 
 
@@ -3145,7 +3151,7 @@
     EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
   }
   ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), mode).code();
+  Handle<Code> ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3275,7 +3281,8 @@
   if (FLAG_vector_ics) {
     EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
   }
-  Handle<Code> ic = CodeFactory::LoadIC(isolate(), NOT_CONTEXTUAL).code();
+  Handle<Code> ic =
+      CodeFactory::LoadICInOptimizedCode(isolate(), NOT_CONTEXTUAL).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3498,7 +3505,7 @@
     EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
   }
 
-  Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
+  Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate()).code();
   CallCode(ic, RelocInfo::CODE_TARGET, instr);
 }
 
@@ -3734,45 +3741,81 @@
   Register name = ToRegister(instr->name());
   DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
   DCHECK(name.is(LoadDescriptor::NameRegister()));
+  Register slot = FLAG_vector_ics ? ToRegister(instr->slot()) : no_reg;
+  Register vector = FLAG_vector_ics ? ToRegister(instr->vector()) : no_reg;
 
   Register scratch = ebx;
-  Register extra = eax;
+  Register extra = edi;
+  DCHECK(!extra.is(slot) && !extra.is(vector));
   DCHECK(!scratch.is(receiver) && !scratch.is(name));
   DCHECK(!extra.is(receiver) && !extra.is(name));
 
   // Important for the tail-call.
   bool must_teardown_frame = NeedsEagerFrame();
 
-  // The probe will tail call to a handler if found.
-  isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
-                                         must_teardown_frame, receiver, name,
-                                         scratch, extra);
+  if (!instr->hydrogen()->is_just_miss()) {
+    if (FLAG_vector_ics) {
+      __ push(slot);
+      __ push(vector);
+    }
+
+    // The probe will tail call to a handler if found.
+    // If --vector-ics is on, then it knows to pop the two args first.
+    DCHECK(!instr->hydrogen()->is_keyed_load());
+    isolate()->stub_cache()->GenerateProbe(
+        masm(), Code::LOAD_IC, instr->hydrogen()->flags(), must_teardown_frame,
+        receiver, name, scratch, extra);
+
+    if (FLAG_vector_ics) {
+      __ pop(vector);
+      __ pop(slot);
+    }
+  }
 
   // Tail call to miss if we ended up here.
   if (must_teardown_frame) __ leave();
-  LoadIC::GenerateMiss(masm());
+  if (instr->hydrogen()->is_keyed_load()) {
+    KeyedLoadIC::GenerateMiss(masm());
+  } else {
+    LoadIC::GenerateMiss(masm());
+  }
 }
 
 
 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
   DCHECK(ToRegister(instr->result()).is(eax));
 
-  LPointerMap* pointers = instr->pointer_map();
-  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+  if (instr->hydrogen()->IsTailCall()) {
+    if (NeedsEagerFrame()) __ leave();
 
-  if (instr->target()->IsConstantOperand()) {
-    LConstantOperand* target = LConstantOperand::cast(instr->target());
-    Handle<Code> code = Handle<Code>::cast(ToHandle(target));
-    generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
-    __ call(code, RelocInfo::CODE_TARGET);
+    if (instr->target()->IsConstantOperand()) {
+      LConstantOperand* target = LConstantOperand::cast(instr->target());
+      Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+      __ jmp(code, RelocInfo::CODE_TARGET);
+    } else {
+      DCHECK(instr->target()->IsRegister());
+      Register target = ToRegister(instr->target());
+      __ add(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
+      __ jmp(target);
+    }
   } else {
-    DCHECK(instr->target()->IsRegister());
-    Register target = ToRegister(instr->target());
-    generator.BeforeCall(__ CallSize(Operand(target)));
-    __ add(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
-    __ call(target);
+    LPointerMap* pointers = instr->pointer_map();
+    SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+
+    if (instr->target()->IsConstantOperand()) {
+      LConstantOperand* target = LConstantOperand::cast(instr->target());
+      Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+      generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
+      __ call(code, RelocInfo::CODE_TARGET);
+    } else {
+      DCHECK(instr->target()->IsRegister());
+      Register target = ToRegister(instr->target());
+      generator.BeforeCall(__ CallSize(Operand(target)));
+      __ add(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
+      __ call(target);
+    }
+    generator.AfterCall();
   }
-  generator.AfterCall();
 }
 
 
@@ -3869,10 +3912,11 @@
                                     LMathAbs* instr,
                                     const X87Stack& x87_stack)
         : LDeferredCode(codegen, x87_stack), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LMathAbs* instr_;
   };
@@ -4777,10 +4821,9 @@
                              LStringCharCodeAt* instr,
                              const X87Stack& x87_stack)
         : LDeferredCode(codegen, x87_stack), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredStringCharCodeAt(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredStringCharCodeAt(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStringCharCodeAt* instr_;
   };
@@ -4836,10 +4879,11 @@
                                LStringCharFromCode* instr,
                                const X87Stack& x87_stack)
         : LDeferredCode(codegen, x87_stack), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredStringCharFromCode(instr_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStringCharFromCode* instr_;
   };
@@ -4925,11 +4969,12 @@
                        LNumberTagI* instr,
                        const X87Stack& x87_stack)
         : LDeferredCode(codegen, x87_stack), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredNumberTagIU(instr_, instr_->value(), instr_->temp(),
                                        SIGNED_INT32);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagI* instr_;
   };
@@ -4953,11 +4998,12 @@
                        LNumberTagU* instr,
                        const X87Stack& x87_stack)
         : LDeferredCode(codegen, x87_stack), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredNumberTagIU(instr_, instr_->value(), instr_->temp(),
                                        UNSIGNED_INT32);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagU* instr_;
   };
@@ -5042,10 +5088,9 @@
                        LNumberTagD* instr,
                        const X87Stack& x87_stack)
         : LDeferredCode(codegen, x87_stack), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredNumberTagD(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredNumberTagD(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LNumberTagD* instr_;
   };
@@ -5288,10 +5333,9 @@
                       LTaggedToI* instr,
                       const X87Stack& x87_stack)
         : LDeferredCode(codegen, x87_stack), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredTaggedToI(instr_, done());
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredTaggedToI(instr_, done()); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LTaggedToI* instr_;
   };
@@ -5353,9 +5397,8 @@
     Label lost_precision, is_nan, minus_zero, done;
     X87Register input_reg = ToX87Register(input);
     X87Fxch(input_reg);
-    Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
     __ X87TOSToI(result_reg, instr->hydrogen()->GetMinusZeroMode(),
-                 &lost_precision, &is_nan, &minus_zero, dist);
+                 &lost_precision, &is_nan, &minus_zero);
     __ jmp(&done);
     __ bind(&lost_precision);
     DeoptimizeIf(no_condition, instr, "lost precision");
@@ -5378,9 +5421,8 @@
   Label lost_precision, is_nan, minus_zero, done;
   X87Register input_reg = ToX87Register(input);
   X87Fxch(input_reg);
-  Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
   __ X87TOSToI(result_reg, instr->hydrogen()->GetMinusZeroMode(),
-               &lost_precision, &is_nan, &minus_zero, dist);
+               &lost_precision, &is_nan, &minus_zero);
   __ jmp(&done);
   __ bind(&lost_precision);
   DeoptimizeIf(no_condition, instr, "lost precision");
@@ -5494,11 +5536,12 @@
         : LDeferredCode(codegen, x87_stack), instr_(instr), object_(object) {
       SetExit(check_maps());
     }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredInstanceMigration(instr_, object_);
     }
     Label* check_maps() { return &check_maps_; }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LCheckMaps* instr_;
     Label check_maps_;
@@ -5717,10 +5760,9 @@
                      LAllocate* instr,
                      const X87Stack& x87_stack)
         : LDeferredCode(codegen, x87_stack), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredAllocate(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredAllocate(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LAllocate* instr_;
   };
@@ -6086,10 +6128,9 @@
                        LStackCheck* instr,
                        const X87Stack& x87_stack)
         : LDeferredCode(codegen, x87_stack), instr_(instr) { }
-    virtual void Generate() OVERRIDE {
-      codegen()->DoDeferredStackCheck(instr_);
-    }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    void Generate() OVERRIDE { codegen()->DoDeferredStackCheck(instr_); }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LStackCheck* instr_;
   };
@@ -6237,10 +6278,11 @@
           object_(object),
           index_(index) {
     }
-    virtual void Generate() OVERRIDE {
+    void Generate() OVERRIDE {
       codegen()->DoDeferredLoadMutableDouble(instr_, object_, index_);
     }
-    virtual LInstruction* instr() OVERRIDE { return instr_; }
+    LInstruction* instr() OVERRIDE { return instr_; }
+
    private:
     LLoadFieldByIndex* instr_;
     Register object_;
diff --git a/src/x87/lithium-x87.cc b/src/x87/lithium-x87.cc
index 9304b89..3a52dc4 100644
--- a/src/x87/lithium-x87.cc
+++ b/src/x87/lithium-x87.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <sstream>
+
 #include "src/v8.h"
 
 #if V8_TARGET_ARCH_X87
@@ -376,9 +378,9 @@
 
 void LStoreNamedField::PrintDataTo(StringStream* stream) {
   object()->PrintTo(stream);
-  OStringStream os;
+  std::ostringstream os;
   os << hydrogen()->access() << " <- ";
-  stream->Add(os.c_str());
+  stream->Add(os.str().c_str());
   value()->PrintTo(stream);
 }
 
@@ -736,11 +738,7 @@
     // Shift operations can only deoptimize if we do a logical shift by 0 and
     // the result cannot be truncated to int32.
     if (op == Token::SHR && constant_value == 0) {
-      if (FLAG_opt_safe_uint32_operations) {
-        does_deopt = !instr->CheckFlag(HInstruction::kUint32);
-      } else {
-        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32);
-      }
+      does_deopt = !instr->CheckFlag(HInstruction::kUint32);
     }
 
     LInstruction* result =
@@ -1159,9 +1157,17 @@
       UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
   LOperand* name_register =
       UseFixed(instr->name(), LoadDescriptor::NameRegister());
+  LOperand* slot = NULL;
+  LOperand* vector = NULL;
+  if (FLAG_vector_ics) {
+    slot = UseFixed(instr->slot(), VectorLoadICDescriptor::SlotRegister());
+    vector =
+        UseFixed(instr->vector(), VectorLoadICDescriptor::VectorRegister());
+  }
+
   // Not marked as call. It can't deoptimize, and it never returns.
   return new (zone()) LTailCallThroughMegamorphicCache(
-      context, receiver_register, name_register);
+      context, receiver_register, name_register, slot, vector);
 }
 
 
@@ -2115,7 +2121,7 @@
   LOperand* global_object =
       UseFixed(instr->global_object(), LoadDescriptor::ReceiverRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
 
@@ -2176,7 +2182,7 @@
   LOperand* object =
       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
   LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(
@@ -2241,7 +2247,7 @@
       UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
   LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
   LOperand* vector = NULL;
-  if (FLAG_vector_ics) {
+  if (instr->HasVectorAndSlot()) {
     vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
   }
   LLoadKeyedGeneric* result =
diff --git a/src/x87/lithium-x87.h b/src/x87/lithium-x87.h
index dbb18ec..5d27fcb 100644
--- a/src/x87/lithium-x87.h
+++ b/src/x87/lithium-x87.h
@@ -168,17 +168,13 @@
   V(WrapReceiver)
 
 
-#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)                        \
-  virtual Opcode opcode() const FINAL OVERRIDE {                      \
-    return LInstruction::k##type;                                           \
-  }                                                                         \
-  virtual void CompileToNative(LCodeGen* generator) FINAL OVERRIDE;   \
-  virtual const char* Mnemonic() const FINAL OVERRIDE {               \
-    return mnemonic;                                                        \
-  }                                                                         \
-  static L##type* cast(LInstruction* instr) {                               \
-    DCHECK(instr->Is##type());                                              \
-    return reinterpret_cast<L##type*>(instr);                               \
+#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)            \
+  Opcode opcode() const FINAL { return LInstruction::k##type; } \
+  void CompileToNative(LCodeGen* generator) FINAL;              \
+  const char* Mnemonic() const FINAL { return mnemonic; }       \
+  static L##type* cast(LInstruction* instr) {                   \
+    DCHECK(instr->Is##type());                                  \
+    return reinterpret_cast<L##type*>(instr);                   \
   }
 
 
@@ -297,11 +293,9 @@
  public:
   // Allow 0 or 1 output operands.
   STATIC_ASSERT(R == 0 || R == 1);
-  virtual bool HasResult() const FINAL OVERRIDE {
-    return R != 0 && result() != NULL;
-  }
+  bool HasResult() const FINAL { return R != 0 && result() != NULL; }
   void set_result(LOperand* operand) { results_[0] = operand; }
-  LOperand* result() const { return results_[0]; }
+  LOperand* result() const OVERRIDE { return results_[0]; }
 
  protected:
   EmbeddedContainer<LOperand*, R> results_;
@@ -319,11 +313,11 @@
 
  private:
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return I; }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return I; }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return T; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return temps_[i]; }
+  int TempCount() FINAL { return T; }
+  LOperand* TempAt(int i) FINAL { return temps_[i]; }
 };
 
 
@@ -337,8 +331,8 @@
   }
 
   // Can't use the DECLARE-macro here because of sub-classes.
-  virtual bool IsGap() const FINAL OVERRIDE { return true; }
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsGap() const FINAL { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   static LGap* cast(LInstruction* instr) {
     DCHECK(instr->IsGap());
     return reinterpret_cast<LGap*>(instr);
@@ -378,7 +372,7 @@
  public:
   explicit LInstructionGap(HBasicBlock* block) : LGap(block) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
     return !IsRedundant();
   }
 
@@ -390,9 +384,7 @@
  public:
   explicit LClobberDoubles(Isolate* isolate) { }
 
-  virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
-    return true;
-  }
+  bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE { return true; }
 
   DECLARE_CONCRETE_INSTRUCTION(ClobberDoubles, "clobber-d")
 };
@@ -402,13 +394,13 @@
  public:
   explicit LGoto(HBasicBlock* block) : block_(block) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
   DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
-  virtual bool IsControl() const OVERRIDE { return true; }
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+  bool IsControl() const OVERRIDE { return true; }
 
   int block_id() const { return block_->block_id(); }
-  virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
+  bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
     return false;
   }
 
@@ -444,7 +436,7 @@
 
 class LDeoptimize FINAL : public LTemplateInstruction<0, 0, 0> {
  public:
-  virtual bool IsControl() const OVERRIDE { return true; }
+  bool IsControl() const OVERRIDE { return true; }
   DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
   DECLARE_HYDROGEN_ACCESSOR(Deoptimize)
 };
@@ -455,12 +447,10 @@
   explicit LLabel(HBasicBlock* block)
       : LGap(block), replacement_(NULL) { }
 
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(Label, "label")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int block_id() const { return block()->block_id(); }
   bool is_loop_header() const { return block()->IsLoopHeader(); }
@@ -478,9 +468,7 @@
 
 class LParameter FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter")
 };
 
@@ -499,19 +487,23 @@
 
 
 class LTailCallThroughMegamorphicCache FINAL
-    : public LTemplateInstruction<0, 3, 0> {
+    : public LTemplateInstruction<0, 5, 0> {
  public:
-  explicit LTailCallThroughMegamorphicCache(LOperand* context,
-                                            LOperand* receiver,
-                                            LOperand* name) {
+  LTailCallThroughMegamorphicCache(LOperand* context, LOperand* receiver,
+                                   LOperand* name, LOperand* slot,
+                                   LOperand* vector) {
     inputs_[0] = context;
     inputs_[1] = receiver;
     inputs_[2] = name;
+    inputs_[3] = slot;
+    inputs_[4] = vector;
   }
 
   LOperand* context() { return inputs_[0]; }
   LOperand* receiver() { return inputs_[1]; }
   LOperand* name() { return inputs_[2]; }
+  LOperand* slot() { return inputs_[3]; }
+  LOperand* vector() { return inputs_[4]; }
 
   DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
                                "tail-call-through-megamorphic-cache")
@@ -521,9 +513,7 @@
 
 class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown-osr-value")
 };
 
@@ -533,7 +523,7 @@
  public:
   LControlInstruction() : false_label_(NULL), true_label_(NULL) { }
 
-  virtual bool IsControl() const FINAL OVERRIDE { return true; }
+  bool IsControl() const FINAL { return true; }
 
   int SuccessorCount() { return hydrogen()->SuccessorCount(); }
   HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); }
@@ -626,7 +616,7 @@
 
   DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -875,7 +865,7 @@
     return hydrogen()->representation().IsDouble();
   }
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1052,7 +1042,7 @@
 
   DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1069,7 +1059,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1084,7 +1074,7 @@
   DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1102,7 +1092,7 @@
                                "is-undetectable-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1122,7 +1112,7 @@
                                "string-compare-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Token::Value op() const { return hydrogen()->token(); }
 };
@@ -1142,7 +1132,7 @@
                                "has-instance-type-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1171,7 +1161,7 @@
   DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch,
                                "has-cached-array-index-and-branch")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1204,7 +1194,7 @@
                                "class-of-test-and-branch")
   DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1399,7 +1389,7 @@
   DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
   DECLARE_HYDROGEN_ACCESSOR(Branch)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1552,11 +1542,9 @@
 
   Token::Value op() const { return op_; }
 
-  virtual Opcode opcode() const OVERRIDE {
-    return LInstruction::kArithmeticD;
-  }
-  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
-  virtual const char* Mnemonic() const OVERRIDE;
+  Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticD; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
 
  private:
   Token::Value op_;
@@ -1579,11 +1567,9 @@
   LOperand* left() { return inputs_[1]; }
   LOperand* right() { return inputs_[2]; }
 
-  virtual Opcode opcode() const OVERRIDE {
-    return LInstruction::kArithmeticT;
-  }
-  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
-  virtual const char* Mnemonic() const OVERRIDE;
+  Opcode opcode() const OVERRIDE { return LInstruction::kArithmeticT; }
+  void CompileToNative(LCodeGen* generator) OVERRIDE;
+  const char* Mnemonic() const OVERRIDE;
 
   Token::Value op() const { return op_; }
 
@@ -1696,7 +1682,7 @@
   DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed")
   DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   uint32_t base_offset() const { return hydrogen()->base_offset(); }
   bool key_is_smi() {
     return hydrogen()->key()->representation().IsTagged();
@@ -1794,7 +1780,7 @@
 
   int slot_index() { return hydrogen()->slot_index(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1815,7 +1801,7 @@
 
   int slot_index() { return hydrogen()->slot_index(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -1854,7 +1840,7 @@
   LOperand* function() { return inputs_[0]; }
   LOperand* code_object() { return inputs_[1]; }
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry, "store-code-entry")
   DECLARE_HYDROGEN_ACCESSOR(StoreCodeEntry)
@@ -1871,7 +1857,7 @@
   LOperand* base_object() const { return inputs_[0]; }
   LOperand* offset() const { return inputs_[1]; }
 
-  virtual void PrintDataTo(StringStream* stream);
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object")
 };
@@ -1915,7 +1901,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallJSFunction, "call-js-function")
   DECLARE_HYDROGEN_ACCESSOR(CallJSFunction)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -1937,18 +1923,18 @@
  private:
   DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 
   ZoneList<LOperand*> inputs_;
 
   // Iterator support.
-  virtual int InputCount() FINAL OVERRIDE { return inputs_.length(); }
-  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+  int InputCount() FINAL { return inputs_.length(); }
+  LOperand* InputAt(int i) FINAL { return inputs_[i]; }
 
-  virtual int TempCount() FINAL OVERRIDE { return 0; }
-  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return NULL; }
+  int TempCount() FINAL { return 0; }
+  LOperand* TempAt(int i) FINAL { return NULL; }
 };
 
 
@@ -1965,7 +1951,7 @@
   DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function")
   DECLARE_HYDROGEN_ACCESSOR(InvokeFunction)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -2001,7 +1987,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
   DECLARE_HYDROGEN_ACCESSOR(CallNew)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -2020,7 +2006,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
   DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   int arity() const { return hydrogen()->argument_count() - 1; }
 };
@@ -2037,7 +2023,7 @@
   DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
   DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
 
-  virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
+  bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
     return save_doubles() == kDontSaveFPRegs;
   }
 
@@ -2225,7 +2211,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
   DECLARE_HYDROGEN_ACCESSOR(StoreNamedField)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
@@ -2244,7 +2230,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
   DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   Handle<Object> name() const { return hydrogen()->name(); }
   StrictMode strict_mode() { return hydrogen()->strict_mode(); }
 };
@@ -2275,7 +2261,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed")
   DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
   uint32_t base_offset() const { return hydrogen()->base_offset(); }
   bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
 };
@@ -2301,7 +2287,7 @@
   DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
   DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   StrictMode strict_mode() { return hydrogen()->strict_mode(); }
 };
@@ -2328,7 +2314,7 @@
                                "transition-elements-kind")
   DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind)
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 
   Handle<Map> original_map() { return hydrogen()->original_map().handle(); }
   Handle<Map> transitioned_map() {
@@ -2628,15 +2614,13 @@
 
   Handle<String> type_literal() { return hydrogen()->type_literal(); }
 
-  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  void PrintDataTo(StringStream* stream) OVERRIDE;
 };
 
 
 class LOsrEntry FINAL : public LTemplateInstruction<0, 0, 0> {
  public:
-  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
-    return false;
-  }
+  bool HasInterestingComment(LCodeGen* gen) const OVERRIDE { return false; }
   DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry")
 };
 
@@ -2843,7 +2827,7 @@
 
   // An input operand in register, stack slot or a constant operand.
   // Will not be moved to a register even if one is freely available.
-  virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE;
+  MUST_USE_RESULT LOperand* UseAny(HValue* value) OVERRIDE;
 
   // Temporary operand that must be in a register.
   MUST_USE_RESULT LUnallocated* TempRegister();
diff --git a/src/x87/macro-assembler-x87.cc b/src/x87/macro-assembler-x87.cc
index a1fa331..008b2af 100644
--- a/src/x87/macro-assembler-x87.cc
+++ b/src/x87/macro-assembler-x87.cc
@@ -13,7 +13,7 @@
 #include "src/cpu-profiler.h"
 #include "src/debug.h"
 #include "src/isolate-inl.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 #include "src/serialize.h"
 
 namespace v8 {
@@ -278,7 +278,7 @@
 }
 
 
-void MacroAssembler::LoadUint32NoSSE2(Register src) {
+void MacroAssembler::LoadUint32NoSSE2(const Operand& src) {
   Label done;
   push(src);
   fild_s(Operand(esp, 0));
@@ -654,16 +654,16 @@
 }
 
 
-void MacroAssembler::DispatchMap(Register obj,
-                                 Register unused,
-                                 Handle<Map> map,
-                                 Handle<Code> success,
-                                 SmiCheckType smi_check_type) {
+void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
+                                     Register scratch2, Handle<WeakCell> cell,
+                                     Handle<Code> success,
+                                     SmiCheckType smi_check_type) {
   Label fail;
   if (smi_check_type == DO_SMI_CHECK) {
     JumpIfSmi(obj, &fail);
   }
-  cmp(FieldOperand(obj, HeapObject::kMapOffset), Immediate(map));
+  mov(scratch1, FieldOperand(obj, HeapObject::kMapOffset));
+  CmpWeakValue(scratch1, cell, scratch2);
   j(equal, success);
 
   bind(&fail);
@@ -867,6 +867,13 @@
 }
 
 
+void MacroAssembler::EnterFrame(StackFrame::Type type,
+                                bool load_constant_pool_pointer_reg) {
+  // Out-of-line constant pool not implemented on x87.
+  UNREACHABLE();
+}
+
+
 void MacroAssembler::EnterFrame(StackFrame::Type type) {
   push(ebp);
   mov(ebp, esp);
@@ -906,8 +913,10 @@
   // Save the frame pointer and the context in top.
   ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate());
   ExternalReference context_address(Isolate::kContextAddress, isolate());
+  ExternalReference c_function_address(Isolate::kCFunctionAddress, isolate());
   mov(Operand::StaticVariable(c_entry_fp_address), ebp);
   mov(Operand::StaticVariable(context_address), esi);
+  mov(Operand::StaticVariable(c_function_address), ebx);
 }
 
 
@@ -1312,10 +1321,10 @@
   }
 
   bind(&done);
-  // Check that the value is a normal propety.
+  // Check that the value is a field property.
   const int kDetailsOffset =
       SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
-  DCHECK_EQ(NORMAL, 0);
+  DCHECK_EQ(FIELD, 0);
   test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
        Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
   j(not_zero, miss);
@@ -2535,6 +2544,21 @@
 }
 
 
+void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
+                                  Register scratch) {
+  mov(scratch, cell);
+  cmp(value, FieldOperand(scratch, WeakCell::kValueOffset));
+}
+
+
+void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
+                                   Label* miss) {
+  mov(value, cell);
+  mov(value, FieldOperand(value, WeakCell::kValueOffset));
+  JumpIfSmi(value, miss);
+}
+
+
 void MacroAssembler::Ret() {
   ret(0);
 }
@@ -3063,18 +3087,6 @@
 }
 
 
-void MacroAssembler::CheckMapDeprecated(Handle<Map> map,
-                                        Register scratch,
-                                        Label* if_deprecated) {
-  if (map->CanBeDeprecated()) {
-    mov(scratch, map);
-    mov(scratch, FieldOperand(scratch, Map::kBitField3Offset));
-    and_(scratch, Immediate(Map::Deprecated::kMask));
-    j(not_zero, if_deprecated);
-  }
-}
-
-
 void MacroAssembler::JumpIfBlack(Register object,
                                  Register scratch0,
                                  Register scratch1,
diff --git a/src/x87/macro-assembler-x87.h b/src/x87/macro-assembler-x87.h
index c9e9087..b797265 100644
--- a/src/x87/macro-assembler-x87.h
+++ b/src/x87/macro-assembler-x87.h
@@ -93,10 +93,6 @@
       Label* condition_met,
       Label::Distance condition_met_distance = Label::kFar);
 
-  void CheckMapDeprecated(Handle<Map> map,
-                          Register scratch,
-                          Label* if_deprecated);
-
   // Check if object is in new space.  Jumps if the object is not in new space.
   // The register scratch can be object itself, but scratch will be clobbered.
   void JumpIfNotInNewSpace(Register object,
@@ -277,6 +273,9 @@
     }
   }
 
+  void CmpWeakValue(Register value, Handle<WeakCell> cell, Register scratch);
+  void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
+
   // ---------------------------------------------------------------------------
   // JavaScript invokes
 
@@ -379,14 +378,12 @@
                 Label* fail,
                 SmiCheckType smi_check_type);
 
-  // Check if the map of an object is equal to a specified map and branch to a
-  // specified target if equal. Skip the smi check if not required (object is
-  // known to be a heap object)
-  void DispatchMap(Register obj,
-                   Register unused,
-                   Handle<Map> map,
-                   Handle<Code> success,
-                   SmiCheckType smi_check_type);
+  // Check if the map of an object is equal to a specified weak map and branch
+  // to a specified target if equal. Skip the smi check if not required
+  // (object is known to be a heap object)
+  void DispatchWeakMap(Register obj, Register scratch1, Register scratch2,
+                       Handle<WeakCell> cell, Handle<Code> success,
+                       SmiCheckType smi_check_type);
 
   // Check if the object in register heap_object is a string. Afterwards the
   // register map contains the object map and the register instance_type
@@ -458,7 +455,10 @@
     j(not_carry, is_smi);
   }
 
-  void LoadUint32NoSSE2(Register src);
+  void LoadUint32NoSSE2(Register src) {
+    LoadUint32NoSSE2(Operand(src));
+  }
+  void LoadUint32NoSSE2(const Operand& src);
 
   // Jump the register contains a smi.
   inline void JumpIfSmi(Register value,
@@ -904,6 +904,7 @@
 
   // Activation support.
   void EnterFrame(StackFrame::Type type);
+  void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
   void LeaveFrame(StackFrame::Type type);
 
   // Expects object in eax and returns map with validated enum cache
diff --git a/src/zone-allocator.h b/src/zone-allocator.h
index ab0ae9c..1eb69b8 100644
--- a/src/zone-allocator.h
+++ b/src/zone-allocator.h
@@ -50,10 +50,10 @@
   }
   void destroy(pointer p) { p->~T(); }
 
-  bool operator==(zone_allocator const& other) {
+  bool operator==(zone_allocator const& other) const {
     return zone_ == other.zone_;
   }
-  bool operator!=(zone_allocator const& other) {
+  bool operator!=(zone_allocator const& other) const {
     return zone_ != other.zone_;
   }
 
diff --git a/src/zone-containers.h b/src/zone-containers.h
index 2ee1780..b0ff7b6 100644
--- a/src/zone-containers.h
+++ b/src/zone-containers.h
@@ -6,7 +6,9 @@
 #define V8_ZONE_CONTAINERS_H_
 
 #include <deque>
+#include <list>
 #include <queue>
+#include <stack>
 #include <vector>
 
 #include "src/zone-allocator.h"
@@ -17,42 +19,75 @@
 // A wrapper subclass for std::vector to make it easy to construct one
 // that uses a zone allocator.
 template <typename T>
-class ZoneVector : public std::vector<T, zone_allocator<T> > {
+class ZoneVector : public std::vector<T, zone_allocator<T>> {
  public:
   // Constructs an empty vector.
   explicit ZoneVector(Zone* zone)
-      : std::vector<T, zone_allocator<T> >(zone_allocator<T>(zone)) {}
+      : std::vector<T, zone_allocator<T>>(zone_allocator<T>(zone)) {}
+
+  // Constructs a new vector and fills it with {size} elements, each
+  // constructed via the default constructor.
+  ZoneVector(int size, Zone* zone)
+      : std::vector<T, zone_allocator<T>>(size, T(), zone_allocator<T>(zone)) {}
 
   // Constructs a new vector and fills it with {size} elements, each
   // having the value {def}.
   ZoneVector(int size, T def, Zone* zone)
-      : std::vector<T, zone_allocator<T> >(size, def, zone_allocator<T>(zone)) {
-  }
+      : std::vector<T, zone_allocator<T>>(size, def, zone_allocator<T>(zone)) {}
 };
 
+
 // A wrapper subclass std::deque to make it easy to construct one
 // that uses a zone allocator.
 template <typename T>
-class ZoneDeque : public std::deque<T, zone_allocator<T> > {
+class ZoneDeque : public std::deque<T, zone_allocator<T>> {
  public:
+  // Constructs an empty deque.
   explicit ZoneDeque(Zone* zone)
-      : std::deque<T, zone_allocator<T> >(zone_allocator<T>(zone)) {}
+      : std::deque<T, zone_allocator<T>>(zone_allocator<T>(zone)) {}
 };
 
+
+// A wrapper subclass std::list to make it easy to construct one
+// that uses a zone allocator.
+// TODO(mstarzinger): This should be renamed to ZoneList once we got rid of our
+// own home-grown ZoneList that actually is a ZoneVector.
+template <typename T>
+class ZoneLinkedList : public std::list<T, zone_allocator<T>> {
+ public:
+  // Constructs an empty list.
+  explicit ZoneLinkedList(Zone* zone)
+      : std::list<T, zone_allocator<T>>(zone_allocator<T>(zone)) {}
+};
+
+
 // A wrapper subclass for std::queue to make it easy to construct one
 // that uses a zone allocator.
 template <typename T>
-class ZoneQueue : public std::queue<T, std::deque<T, zone_allocator<T> > > {
+class ZoneQueue : public std::queue<T, ZoneDeque<T>> {
  public:
   // Constructs an empty queue.
   explicit ZoneQueue(Zone* zone)
-      : std::queue<T, std::deque<T, zone_allocator<T> > >(
-            std::deque<T, zone_allocator<T> >(zone_allocator<T>(zone))) {}
+      : std::queue<T, ZoneDeque<T>>(ZoneDeque<T>(zone)) {}
 };
 
+
+// A wrapper subclass for std::stack to make it easy to construct one that uses
+// a zone allocator.
+template <typename T>
+class ZoneStack : public std::stack<T, ZoneDeque<T>> {
+ public:
+  // Constructs an empty stack.
+  explicit ZoneStack(Zone* zone)
+      : std::stack<T, ZoneDeque<T>>(ZoneDeque<T>(zone)) {}
+};
+
+
 // Typedefs to shorten commonly used vectors.
 typedef ZoneVector<bool> BoolVector;
 typedef ZoneVector<int> IntVector;
-} }  // namespace v8::internal
+
+}  // namespace internal
+}  // namespace v8
 
 #endif  // V8_ZONE_CONTAINERS_H_
diff --git a/src/zone-inl.h b/src/zone-inl.h
index cf037b5..63efe16 100644
--- a/src/zone-inl.h
+++ b/src/zone-inl.h
@@ -31,7 +31,6 @@
 
 void Zone::adjust_segment_bytes_allocated(int delta) {
   segment_bytes_allocated_ += delta;
-  isolate_->counters()->zone_segment_bytes()->Set(segment_bytes_allocated_);
 }
 
 
diff --git a/src/zone.cc b/src/zone.cc
index 48d8c7b..eb2e532 100644
--- a/src/zone.cc
+++ b/src/zone.cc
@@ -150,6 +150,7 @@
     position_ = limit_ = 0;
   }
 
+  allocation_size_ = 0;
   // Update the head segment to be the kept segment (if any).
   segment_head_ = keep;
 }
diff --git a/test/benchmarks/testcfg.py b/test/benchmarks/testcfg.py
index 6607bef..29e0c37 100644
--- a/test/benchmarks/testcfg.py
+++ b/test/benchmarks/testcfg.py
@@ -186,7 +186,7 @@
     # Both --nocrankshaft and --stressopt are very slow. Add TF but without
     # always opt to match the way the benchmarks are run for performance
     # testing.
-    return [[], ["--turbo-filter=*"]]
+    return [[], ["--turbo-asm", "--turbo-filter=*"]]
 
 
 def GetSuite(name, root):
diff --git a/test/cctest/cctest.cc b/test/cctest/cctest.cc
index f03710a..170aa5a 100644
--- a/test/cctest/cctest.cc
+++ b/test/cctest/cctest.cc
@@ -34,12 +34,12 @@
 #include "test/cctest/profiler-extension.h"
 #include "test/cctest/trace-extension.h"
 
-#if (defined(_WIN32) || defined(_WIN64))
+#if V8_OS_WIN
 #include <windows.h>  // NOLINT
-#if defined(_MSC_VER)
+#if V8_CC_MSVC
 #include <crtdbg.h>
-#endif  // defined(_MSC_VER)
-#endif  // defined(_WIN32) || defined(_WIN64)
+#endif
+#endif
 
 enum InitializationState {kUnset, kUnintialized, kInitialized};
 static InitializationState initialization_state_  = kUnset;
@@ -47,7 +47,7 @@
 
 CcTest* CcTest::last_ = NULL;
 bool CcTest::initialize_called_ = false;
-bool CcTest::isolate_used_ = false;
+v8::base::Atomic32 CcTest::isolate_used_ = 0;
 v8::Isolate* CcTest::isolate_ = NULL;
 
 
@@ -145,12 +145,12 @@
 
 
 int main(int argc, char* argv[]) {
-#if (defined(_WIN32) || defined(_WIN64))
+#if V8_OS_WIN
   UINT new_flags =
       SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
   UINT existing_flags = SetErrorMode(new_flags);
   SetErrorMode(existing_flags | new_flags);
-#if defined(_MSC_VER)
+#if V8_CC_MSVC
   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
@@ -158,8 +158,8 @@
   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
   _set_error_mode(_OUT_TO_STDERR);
-#endif  // _MSC_VER
-#endif  // defined(_WIN32) || defined(_WIN64)
+#endif  // V8_CC_MSVC
+#endif  // V8_OS_WIN
 
   v8::V8::InitializeICU();
   v8::Platform* platform = v8::platform::CreateDefaultPlatform();
diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp
index 6a57763..4d1c467 100644
--- a/test/cctest/cctest.gyp
+++ b/test/cctest/cctest.gyp
@@ -53,22 +53,27 @@
         'compiler/graph-tester.h',
         'compiler/simplified-graph-builder.cc',
         'compiler/simplified-graph-builder.h',
+        'compiler/test-basic-block-profiler.cc',
         'compiler/test-branch-combine.cc',
         'compiler/test-changes-lowering.cc',
         'compiler/test-codegen-deopt.cc',
+        'compiler/test-control-reducer.cc',
         'compiler/test-gap-resolver.cc',
         'compiler/test-graph-reducer.cc',
+        'compiler/test-graph-visualizer.cc',
         'compiler/test-instruction.cc',
         'compiler/test-js-context-specialization.cc',
         'compiler/test-js-constant-cache.cc',
         'compiler/test-js-typed-lowering.cc',
+        'compiler/test-jump-threading.cc',
         'compiler/test-linkage.cc',
+        'compiler/test-loop-assignment-analysis.cc',
+        'compiler/test-loop-analysis.cc',
         'compiler/test-machine-operator-reducer.cc',
         'compiler/test-node-algorithm.cc',
         'compiler/test-node-cache.cc',
         'compiler/test-node.cc',
         'compiler/test-operator.cc',
-        'compiler/test-phi-reducer.cc',
         'compiler/test-pipeline.cc',
         'compiler/test-representation-change.cc',
         'compiler/test-run-deopt.cc',
@@ -80,10 +85,12 @@
         'compiler/test-run-jsops.cc',
         'compiler/test-run-machops.cc',
         'compiler/test-run-properties.cc',
+        'compiler/test-run-stackcheck.cc',
         'compiler/test-run-variables.cc',
         'compiler/test-schedule.cc',
         'compiler/test-scheduler.cc',
         'compiler/test-simplified-lowering.cc',
+        'compiler/test-typer.cc',
         'cctest.cc',
         'gay-fixed.cc',
         'gay-precision.cc',
@@ -97,13 +104,13 @@
         'test-atomicops.cc',
         'test-bignum.cc',
         'test-bignum-dtoa.cc',
+        'test-bit-vector.cc',
         'test-checks.cc',
         'test-circular-queue.cc',
         'test-compiler.cc',
         'test-constantpool.cc',
         'test-conversions.cc',
         'test-cpu-profiler.cc',
-        'test-dataflow.cc',
         'test-date.cc',
         'test-debug.cc',
         'test-declarative-accessors.cc',
@@ -114,6 +121,7 @@
         'test-double.cc',
         'test-dtoa.cc',
         'test-fast-dtoa.cc',
+        'test-feedback-vector.cc',
         'test-fixed-dtoa.cc',
         'test-flags.cc',
         'test-func-name-inference.cc',
@@ -134,7 +142,6 @@
         'test-mementos.cc',
         'test-object-observe.cc',
         'test-ordered-hash-table.cc',
-        'test-ostreams.cc',
         'test-parsing.cc',
         'test-platform.cc',
         'test-profile-generator.cc',
@@ -142,6 +149,7 @@
         'test-regexp.cc',
         'test-reloc-info.cc',
         'test-representation.cc',
+        'test-sampler-api.cc',
         'test-serialize.cc',
         'test-spaces.cc',
         'test-strings.cc',
@@ -149,8 +157,10 @@
         'test-strtod.cc',
         'test-thread-termination.cc',
         'test-threads.cc',
+        'test-transitions.cc',
         'test-types.cc',
         'test-unbound-queue.cc',
+        'test-unboxed-doubles.cc',
         'test-unique.cc',
         'test-unscopables-hidden-prototype.cc',
         'test-utils.cc',
@@ -250,13 +260,14 @@
           # cctest can't be built against a shared library, so we need to
           # depend on the underlying static target in that case.
           'conditions': [
-            ['v8_use_snapshot=="true"', {
+            ['v8_use_snapshot=="true" and v8_use_external_startup_data==0', {
               'dependencies': ['../../tools/gyp/v8.gyp:v8_snapshot'],
-            },
-            {
-              'dependencies': [
-                '../../tools/gyp/v8.gyp:v8_nosnapshot',
-              ],
+            }],
+            ['v8_use_snapshot=="true" and v8_use_external_startup_data==1', {
+              'dependencies': ['../../tools/gyp/v8.gyp:v8_external_snapshot'],
+            }],
+            ['v8_use_snapshot!="true"', {
+              'dependencies': ['../../tools/gyp/v8.gyp:v8_nosnapshot'],
             }],
           ],
         }, {
@@ -294,7 +305,6 @@
             '../../tools/js2c.py',
             '<@(_outputs)',
             'TEST',  # type
-            'off',  # compression
             '<@(file_list)',
           ],
         }
diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h
index 6d27074..a8239d2 100644
--- a/test/cctest/cctest.h
+++ b/test/cctest/cctest.h
@@ -117,7 +117,7 @@
 
   static v8::Isolate* isolate() {
     CHECK(isolate_ != NULL);
-    isolate_used_ = true;
+    v8::base::NoBarrier_Store(&isolate_used_, 1);
     return isolate_;
   }
 
@@ -149,7 +149,7 @@
   // TODO(dcarney): Remove.
   // This must be called first in a test.
   static void InitializeVM() {
-    CHECK(!isolate_used_);
+    CHECK(!v8::base::NoBarrier_Load(&isolate_used_));
     CHECK(!initialize_called_);
     initialize_called_ = true;
     v8::HandleScope handle_scope(CcTest::isolate());
@@ -181,7 +181,7 @@
   static CcTest* last_;
   static v8::Isolate* isolate_;
   static bool initialize_called_;
-  static bool isolate_used_;
+  static v8::base::Atomic32 isolate_used_;
 };
 
 // Switches between all the Api tests using the threading support.
@@ -481,15 +481,31 @@
 
 
 // Helper function that simulates a full new-space in the heap.
-static inline void SimulateFullSpace(v8::internal::NewSpace* space) {
-  int new_linear_size = static_cast<int>(
-      *space->allocation_limit_address() - *space->allocation_top_address());
-  if (new_linear_size == 0) return;
+static inline bool FillUpOnePage(v8::internal::NewSpace* space) {
   v8::internal::AllocationResult allocation =
-      space->AllocateRaw(new_linear_size);
+      space->AllocateRaw(v8::internal::Page::kMaxRegularHeapObjectSize);
+  if (allocation.IsRetry()) return false;
   v8::internal::FreeListNode* node =
       v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
-  node->set_size(space->heap(), new_linear_size);
+  node->set_size(space->heap(), v8::internal::Page::kMaxRegularHeapObjectSize);
+  return true;
+}
+
+
+static inline void SimulateFullSpace(v8::internal::NewSpace* space) {
+  int new_linear_size = static_cast<int>(*space->allocation_limit_address() -
+                                         *space->allocation_top_address());
+  if (new_linear_size > 0) {
+    // Fill up the current page.
+    v8::internal::AllocationResult allocation =
+        space->AllocateRaw(new_linear_size);
+    v8::internal::FreeListNode* node =
+        v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
+    node->set_size(space->heap(), new_linear_size);
+  }
+  // Fill up all remaining pages.
+  while (FillUpOnePage(space))
+    ;
 }
 
 
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index 5198af6..cc5414d 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -29,6 +29,7 @@
 [ALWAYS, {
   # All tests prefixed with 'Bug' are expected to fail.
   'test-api/Bug*': [FAIL],
+  'test-serialize/Bug*': [FAIL],
 
   ##############################################################################
 
@@ -80,58 +81,14 @@
   ##############################################################################
   # TurboFan compiler failures.
 
-  # TODO(sigurds): The schedule is borked with multiple inlinees,
-  # and cannot handle free-floating loops yet
-  'test-run-inlining/InlineTwiceDependentDiamond': [SKIP],
-  'test-run-inlining/InlineTwiceDependentDiamondDifferent': [SKIP],
-  'test-run-inlining/InlineLoop': [SKIP],
-
   # Some tests are just too slow to run for now.
   'test-api/Threading*': [PASS, NO_VARIANTS],
   'test-heap/IncrementalMarkingStepMakesBigProgressWithLargeObjects': [PASS, NO_VARIANTS],
   'test-heap-profiler/ManyLocalsInSharedContext': [PASS, NO_VARIANTS],
   'test-debug/ThreadedDebugging': [PASS, NO_VARIANTS],
   'test-debug/DebugBreakLoop': [PASS, NO_VARIANTS],
-
-  # Support for breakpoints requires using LoadICs and StoreICs.
-  'test-debug/BreakPointICStore': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointICLoad': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointICCall': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointICCallWithGC': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointConstructCallWithGC': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointReturn': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointThroughJavaScript': [PASS, NO_VARIANTS],
-  'test-debug/ScriptBreakPointByNameThroughJavaScript': [PASS, NO_VARIANTS],
-  'test-debug/ScriptBreakPointByIdThroughJavaScript': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepLinear': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepKeyedLoadLoop': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepKeyedStoreLoop': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepNamedLoadLoop': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepNamedStoreLoop': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepLinearMixedICs': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepDeclarations': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepLocals': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepIf': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepSwitch': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepWhile': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepDoWhile': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepFor': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepForContinue': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepForBreak': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepForIn': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepWith': [PASS, NO_VARIANTS],
-  'test-debug/DebugConditional': [PASS, NO_VARIANTS],
-  'test-debug/StepInOutSimple': [PASS, NO_VARIANTS],
-  'test-debug/StepInOutTree': [PASS, NO_VARIANTS],
-  'test-debug/StepInOutBranch': [PASS, NO_VARIANTS],
-  'test-debug/DebugBreak': [PASS, NO_VARIANTS],
-  'test-debug/DebugBreakStackInspection': [PASS, NO_VARIANTS],
-  'test-debug/BreakMessageWhenMessageHandlerIsReset': [PASS, NO_VARIANTS],
-  'test-debug/NoDebugBreakInAfterCompileMessageHandler': [PASS, NO_VARIANTS],
-  'test-debug/DisableBreak': [PASS, NO_VARIANTS],
-  'test-debug/RegExpDebugBreak': [PASS, NO_VARIANTS],
-  'test-debug/DebugBreakFunctionApply': [PASS, NO_VARIANTS],
-  'test-debug/DeoptimizeDuringDebugBreak': [PASS, NO_VARIANTS],
+  # BUG(3742).
+  'test-mark-compact/MarkCompactCollector': [PASS, ['arch==arm', NO_VARIANTS]],
 
   # Support for %GetFrameDetails is missing and requires checkpoints.
   'test-api/Regress385349': [PASS, NO_VARIANTS],
@@ -148,6 +105,17 @@
   'test-debug/CallingContextIsNotDebugContext': [PASS, NO_VARIANTS],
   'test-debug/DebugEventContext': [PASS, NO_VARIANTS],
   'test-debug/DebugBreakInline': [PASS, NO_VARIANTS],
+  'test-debug/BreakMessageWhenMessageHandlerIsReset': [PASS, NO_VARIANTS],
+  'test-debug/DebugBreak': [PASS, NO_VARIANTS],
+  'test-debug/DebugBreakFunctionApply': [PASS, NO_VARIANTS],
+  'test-debug/DebugBreakStackInspection': [PASS, NO_VARIANTS],
+  'test-debug/DeoptimizeDuringDebugBreak': [PASS, NO_VARIANTS],
+  'test-debug/DisableBreak': [PASS, NO_VARIANTS],
+  'test-debug/NoDebugBreakInAfterCompileMessageHandler': [PASS, NO_VARIANTS],
+  'test-debug/RegExpDebugBreak': [PASS, NO_VARIANTS],
+
+  # TODO(titzer): Triggers bug in late control reduction.
+  'test-run-inlining/InlineLoopGuardedEmpty': [SKIP],
 
   ############################################################################
   # Slow tests.
@@ -298,6 +266,19 @@
 }],  # 'arch == mipsel or arch == mips'
 
 ##############################################################################
+['arch == mips', {
+  # Too slow with TF.
+  'test-api/ExternalArrays': [PASS, NO_VARIANTS],
+
+  # TODO(mips-team): Currently fails on mips board.
+  'test-simplified-lowering/RunNumberMultiply_TruncatingToUint32': [SKIP],
+  'test-parsing/TooManyArguments': [SKIP],
+  'test-api/Threading3': [SKIP],
+  'test-api/RequestInterruptTestWithNativeAccessor': [SKIP],
+  'test-api/RequestInterruptTestWithAccessor': [SKIP],
+}],  # 'arch == mips'
+
+##############################################################################
 ['arch == mips64el', {
 
   # BUG(2657): Test sometimes times out on MIPS simulator.
@@ -334,12 +315,6 @@
   'test-log/LogAccessorCallbacks': [SKIP],
   'test-log/LogCallbacks': [SKIP],
   'test-log/ProfLazyMode': [SKIP],
-
-  # platform-tls.h does not contain an ANDROID-related header.
-  'test-platform-tls/FastTLS': [SKIP],
-
-  # This test times out.
-  'test-threads/ThreadJoinSelf': [SKIP],
 }],  # 'arch == android_arm or arch == android_ia32'
 
 ##############################################################################
diff --git a/test/cctest/compiler/call-tester.h b/test/cctest/compiler/call-tester.h
index e864160..cad171e 100644
--- a/test/cctest/compiler/call-tester.h
+++ b/test/cctest/compiler/call-tester.h
@@ -207,7 +207,43 @@
         Simulator::CallArgument::End()};
     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
   }
-#elif USE_SIMULATOR && V8_TARGET_ARCH_ARM
+#elif USE_SIMULATOR && V8_TARGET_ARCH_MIPS64
+  uintptr_t CallSimulator(byte* f, int64_t p1 = 0, int64_t p2 = 0,
+                          int64_t p3 = 0, int64_t p4 = 0) {
+    Simulator* simulator = Simulator::current(isolate_);
+    return static_cast<uintptr_t>(simulator->Call(f, 4, p1, p2, p3, p4));
+  }
+
+  template <typename R, typename F>
+  R DoCall(F* f) {
+    return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f)));
+  }
+  template <typename R, typename F, typename P1>
+  R DoCall(F* f, P1 p1) {
+    return ReturnValueTraits<R>::Cast(
+        CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
+  }
+  template <typename R, typename F, typename P1, typename P2>
+  R DoCall(F* f, P1 p1, P2 p2) {
+    return ReturnValueTraits<R>::Cast(
+        CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
+                      ParameterTraits<P2>::Cast(p2)));
+  }
+  template <typename R, typename F, typename P1, typename P2, typename P3>
+  R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
+    return ReturnValueTraits<R>::Cast(CallSimulator(
+        FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
+        ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
+  }
+  template <typename R, typename F, typename P1, typename P2, typename P3,
+            typename P4>
+  R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
+    return ReturnValueTraits<R>::Cast(CallSimulator(
+        FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
+        ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
+        ParameterTraits<P4>::Cast(p4)));
+  }
+#elif USE_SIMULATOR && (V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS)
   uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0,
                           int32_t p3 = 0, int32_t p4 = 0) {
     Simulator* simulator = Simulator::current(isolate_);
diff --git a/test/cctest/compiler/codegen-tester.cc b/test/cctest/compiler/codegen-tester.cc
index b1874f5..5311001 100644
--- a/test/cctest/compiler/codegen-tester.cc
+++ b/test/cctest/compiler/codegen-tester.cc
@@ -14,7 +14,6 @@
 TEST(CompareWrapper) {
   // Who tests the testers?
   // If CompareWrapper is broken, then test expectations will be broken.
-  RawMachineAssemblerTester<int32_t> m;
   CompareWrapper wWord32Equal(IrOpcode::kWord32Equal);
   CompareWrapper wInt32LessThan(IrOpcode::kInt32LessThan);
   CompareWrapper wInt32LessThanOrEqual(IrOpcode::kInt32LessThanOrEqual);
@@ -477,10 +476,10 @@
 
 
 TEST(RunHeapNumberConstant) {
-  RawMachineAssemblerTester<Object*> m;
-  Handle<Object> number = m.isolate()->factory()->NewHeapNumber(100.5);
+  RawMachineAssemblerTester<HeapObject*> m;
+  Handle<HeapObject> number = m.isolate()->factory()->NewHeapNumber(100.5);
   m.Return(m.HeapConstant(number));
-  Object* result = m.Call();
+  HeapObject* result = m.Call();
   CHECK_EQ(result, *number);
 }
 
diff --git a/test/cctest/compiler/codegen-tester.h b/test/cctest/compiler/codegen-tester.h
index 6aa5bae..283d533 100644
--- a/test/cctest/compiler/codegen-tester.h
+++ b/test/cctest/compiler/codegen-tester.h
@@ -7,6 +7,7 @@
 
 #include "src/v8.h"
 
+#include "src/compiler/instruction-selector.h"
 #include "src/compiler/pipeline.h"
 #include "src/compiler/raw-machine-assembler.h"
 #include "src/simulator.h"
@@ -23,7 +24,9 @@
  public:
   MachineAssemblerTester(MachineType return_type, MachineType p0,
                          MachineType p1, MachineType p2, MachineType p3,
-                         MachineType p4)
+                         MachineType p4,
+                         MachineOperatorBuilder::Flags flags =
+                             MachineOperatorBuilder::Flag::kNoFlags)
       : HandleAndZoneScope(),
         CallHelper(
             main_isolate(),
@@ -31,7 +34,7 @@
         MachineAssembler(
             new (main_zone()) Graph(main_zone()),
             MakeMachineSignature(main_zone(), return_type, p0, p1, p2, p3, p4),
-            kMachPtr) {}
+            kMachPtr, flags) {}
 
   Node* LoadFromPointer(void* address, MachineType rep, int32_t offset = 0) {
     return this->Load(rep, this->PointerConstant(address),
@@ -65,10 +68,8 @@
       Schedule* schedule = this->Export();
       CallDescriptor* call_descriptor = this->call_descriptor();
       Graph* graph = this->graph();
-      CompilationInfo info(graph->zone()->isolate(), graph->zone());
-      Linkage linkage(&info, call_descriptor);
-      Pipeline pipeline(&info);
-      code_ = pipeline.GenerateCodeForMachineGraph(&linkage, graph, schedule);
+      code_ =
+          Pipeline::GenerateCodeForTesting(call_descriptor, graph, schedule);
     }
     return this->code_.ToHandleChecked()->entry();
   }
@@ -89,8 +90,8 @@
                             MachineType p3 = kMachNone,
                             MachineType p4 = kMachNone)
       : MachineAssemblerTester<RawMachineAssembler>(
-            ReturnValueTraits<ReturnType>::Representation(), p0, p1, p2, p3,
-            p4) {}
+            ReturnValueTraits<ReturnType>::Representation(), p0, p1, p2, p3, p4,
+            InstructionSelector::SupportedMachineOperatorFlags()) {}
 
   template <typename Ci, typename Fn>
   void Run(const Ci& ci, const Fn& fn) {
diff --git a/test/cctest/compiler/function-tester.h b/test/cctest/compiler/function-tester.h
index c869f00..7e16eea 100644
--- a/test/cctest/compiler/function-tester.h
+++ b/test/cctest/compiler/function-tester.h
@@ -8,7 +8,9 @@
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
 
+#include "src/ast-numbering.h"
 #include "src/compiler.h"
+#include "src/compiler/linkage.h"
 #include "src/compiler/pipeline.h"
 #include "src/execution.h"
 #include "src/full-codegen.h"
@@ -37,52 +39,16 @@
     CHECK_EQ(0, flags_ & ~supported_flags);
   }
 
+  explicit FunctionTester(Graph* graph)
+      : isolate(main_isolate()),
+        function(NewFunction("(function(a,b){})")),
+        flags_(0) {
+    CompileGraph(graph);
+  }
+
   Isolate* isolate;
   Handle<JSFunction> function;
 
-  Handle<JSFunction> Compile(Handle<JSFunction> function) {
-#if V8_TURBOFAN_TARGET
-    CompilationInfoWithZone info(function);
-
-    CHECK(Parser::Parse(&info));
-    info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
-    if (flags_ & CompilationInfo::kContextSpecializing) {
-      info.MarkAsContextSpecializing();
-    }
-    if (flags_ & CompilationInfo::kInliningEnabled) {
-      info.MarkAsInliningEnabled();
-    }
-    if (flags_ & CompilationInfo::kTypingEnabled) {
-      info.MarkAsTypingEnabled();
-    }
-    CHECK(Rewriter::Rewrite(&info));
-    CHECK(Scope::Analyze(&info));
-    CHECK(Compiler::EnsureDeoptimizationSupport(&info));
-
-    Pipeline pipeline(&info);
-    Handle<Code> code = pipeline.GenerateCode();
-    if (FLAG_turbo_deoptimization) {
-      info.context()->native_context()->AddOptimizedCode(*code);
-    }
-
-    CHECK(!code.is_null());
-    function->ReplaceCode(*code);
-#elif USE_CRANKSHAFT
-    Handle<Code> unoptimized = Handle<Code>(function->code());
-    Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized,
-                                                   Compiler::NOT_CONCURRENT);
-    CHECK(!code.is_null());
-#if ENABLE_DISASSEMBLER
-    if (FLAG_print_opt_code) {
-      CodeTracer::Scope tracing_scope(isolate->GetCodeTracer());
-      code->Disassemble("test code", tracing_scope.file());
-    }
-#endif
-    function->ReplaceCode(*code);
-#endif
-    return function;
-  }
-
   MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b) {
     Handle<Object> args[] = {a, b};
     return Execution::Call(isolate, function, undefined(), 2, args, false);
@@ -183,8 +149,78 @@
 
   Handle<Object> false_value() { return isolate->factory()->false_value(); }
 
+  Handle<JSFunction> Compile(Handle<JSFunction> function) {
+// TODO(titzer): make this method private.
+#if V8_TURBOFAN_TARGET
+    CompilationInfoWithZone info(function);
+
+    CHECK(Parser::Parse(&info));
+    info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
+    if (flags_ & CompilationInfo::kContextSpecializing) {
+      info.MarkAsContextSpecializing();
+    }
+    if (flags_ & CompilationInfo::kInliningEnabled) {
+      info.MarkAsInliningEnabled();
+    }
+    if (flags_ & CompilationInfo::kTypingEnabled) {
+      info.MarkAsTypingEnabled();
+    }
+    CHECK(Compiler::Analyze(&info));
+    CHECK(Compiler::EnsureDeoptimizationSupport(&info));
+
+    Pipeline pipeline(&info);
+    Handle<Code> code = pipeline.GenerateCode();
+    if (FLAG_turbo_deoptimization) {
+      info.context()->native_context()->AddOptimizedCode(*code);
+    }
+
+    CHECK(!code.is_null());
+    function->ReplaceCode(*code);
+#elif USE_CRANKSHAFT
+    Handle<Code> unoptimized = Handle<Code>(function->code());
+    Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized,
+                                                   Compiler::NOT_CONCURRENT);
+    CHECK(!code.is_null());
+#if ENABLE_DISASSEMBLER
+    if (FLAG_print_opt_code) {
+      CodeTracer::Scope tracing_scope(isolate->GetCodeTracer());
+      code->Disassemble("test code", tracing_scope.file());
+    }
+#endif
+    function->ReplaceCode(*code);
+#endif
+    return function;
+  }
+
+  static Handle<JSFunction> ForMachineGraph(Graph* graph) {
+    JSFunction* p = NULL;
+    {  // because of the implicit handle scope of FunctionTester.
+      FunctionTester f(graph);
+      p = *f.function;
+    }
+    return Handle<JSFunction>(p);  // allocated in outer handle scope.
+  }
+
  private:
   uint32_t flags_;
+
+  // Compile the given machine graph instead of the source of the function
+  // and replace the JSFunction's code with the result.
+  Handle<JSFunction> CompileGraph(Graph* graph) {
+    CHECK(Pipeline::SupportedTarget());
+    CompilationInfoWithZone info(function);
+
+    CHECK(Parser::Parse(&info));
+    info.SetOptimizing(BailoutId::None(),
+                       Handle<Code>(function->shared()->code()));
+    CHECK(Compiler::Analyze(&info));
+    CHECK(Compiler::EnsureDeoptimizationSupport(&info));
+
+    Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, graph);
+    CHECK(!code.is_null());
+    function->ReplaceCode(*code);
+    return function;
+  }
 };
 }
 }
diff --git a/test/cctest/compiler/graph-builder-tester.cc b/test/cctest/compiler/graph-builder-tester.cc
index bfa8226..b0f470b 100644
--- a/test/cctest/compiler/graph-builder-tester.cc
+++ b/test/cctest/compiler/graph-builder-tester.cc
@@ -35,11 +35,9 @@
   if (!Pipeline::SupportedBackend()) return NULL;
   if (code_.is_null()) {
     Zone* zone = graph_->zone();
-    CompilationInfo info(zone->isolate(), zone);
-    Linkage linkage(&info,
-                    Linkage::GetSimplifiedCDescriptor(zone, machine_sig_));
-    Pipeline pipeline(&info);
-    code_ = pipeline.GenerateCodeForMachineGraph(&linkage, graph_);
+    CallDescriptor* desc =
+        Linkage::GetSimplifiedCDescriptor(zone, machine_sig_);
+    code_ = Pipeline::GenerateCodeForTesting(desc, graph_);
   }
   return code_.ToHandleChecked()->entry();
 }
diff --git a/test/cctest/compiler/graph-builder-tester.h b/test/cctest/compiler/graph-builder-tester.h
index df79250..772de4d 100644
--- a/test/cctest/compiler/graph-builder-tester.h
+++ b/test/cctest/compiler/graph-builder-tester.h
@@ -27,8 +27,8 @@
 
  protected:
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) FINAL {
-    return graph()->NewNode(op, value_input_count, value_inputs);
+                         Node** value_inputs, bool incomplete) FINAL {
+    return graph()->NewNode(op, value_input_count, value_inputs, incomplete);
   }
 };
 
@@ -61,6 +61,7 @@
   explicit GraphAndBuilders(Zone* zone)
       : main_graph_(new (zone) Graph(zone)),
         main_common_(zone),
+        main_machine_(zone),
         main_simplified_(zone) {}
 
  protected:
diff --git a/test/cctest/compiler/simplified-graph-builder.cc b/test/cctest/compiler/simplified-graph-builder.cc
index c44d5ed..baa03fb 100644
--- a/test/cctest/compiler/simplified-graph-builder.cc
+++ b/test/cctest/compiler/simplified-graph-builder.cc
@@ -5,7 +5,6 @@
 #include "test/cctest/compiler/simplified-graph-builder.h"
 
 #include "src/compiler/operator-properties.h"
-#include "src/compiler/operator-properties-inl.h"
 
 namespace v8 {
 namespace internal {
@@ -45,20 +44,20 @@
 
 Node* SimplifiedGraphBuilder::MakeNode(const Operator* op,
                                        int value_input_count,
-                                       Node** value_inputs) {
-  DCHECK(op->InputCount() == value_input_count);
+                                       Node** value_inputs, bool incomplete) {
+  DCHECK(op->ValueInputCount() == value_input_count);
 
   DCHECK(!OperatorProperties::HasContextInput(op));
   DCHECK(!OperatorProperties::HasFrameStateInput(op));
-  bool has_control = OperatorProperties::GetControlInputCount(op) == 1;
-  bool has_effect = OperatorProperties::GetEffectInputCount(op) == 1;
+  bool has_control = op->ControlInputCount() == 1;
+  bool has_effect = op->EffectInputCount() == 1;
 
-  DCHECK(OperatorProperties::GetControlInputCount(op) < 2);
-  DCHECK(OperatorProperties::GetEffectInputCount(op) < 2);
+  DCHECK(op->ControlInputCount() < 2);
+  DCHECK(op->EffectInputCount() < 2);
 
   Node* result = NULL;
   if (!has_control && !has_effect) {
-    result = graph()->NewNode(op, value_input_count, value_inputs);
+    result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
   } else {
     int input_count_with_deps = value_input_count;
     if (has_control) ++input_count_with_deps;
@@ -72,14 +71,12 @@
     if (has_control) {
       *current_input++ = graph()->start();
     }
-    result = graph()->NewNode(op, input_count_with_deps, buffer);
+    result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
     if (has_effect) {
       effect_ = result;
     }
-    if (OperatorProperties::HasControlOutput(result->op())) {
-      // This graph builder does not support control flow.
-      UNREACHABLE();
-    }
+    // This graph builder does not support control flow.
+    CHECK_EQ(0, op->ControlOutputCount());
   }
 
   return result;
diff --git a/test/cctest/compiler/simplified-graph-builder.h b/test/cctest/compiler/simplified-graph-builder.h
index 1b637b7..537094a 100644
--- a/test/cctest/compiler/simplified-graph-builder.h
+++ b/test/cctest/compiler/simplified-graph-builder.h
@@ -45,8 +45,8 @@
   Node* Int32Constant(int32_t value) {
     return NewNode(common()->Int32Constant(value));
   }
-  Node* HeapConstant(Handle<Object> object) {
-    Unique<Object> val = Unique<Object>::CreateUninitialized(object);
+  Node* HeapConstant(Handle<HeapObject> object) {
+    Unique<HeapObject> val = Unique<HeapObject>::CreateUninitialized(object);
     return NewNode(common()->HeapConstant(val));
   }
 
@@ -127,19 +127,17 @@
   Node* StoreField(const FieldAccess& access, Node* object, Node* value) {
     return NewNode(simplified()->StoreField(access), object, value);
   }
-  Node* LoadElement(const ElementAccess& access, Node* object, Node* index,
-                    Node* length) {
-    return NewNode(simplified()->LoadElement(access), object, index, length);
+  Node* LoadElement(const ElementAccess& access, Node* object, Node* index) {
+    return NewNode(simplified()->LoadElement(access), object, index);
   }
   Node* StoreElement(const ElementAccess& access, Node* object, Node* index,
-                     Node* length, Node* value) {
-    return NewNode(simplified()->StoreElement(access), object, index, length,
-                   value);
+                     Node* value) {
+    return NewNode(simplified()->StoreElement(access), object, index, value);
   }
 
  protected:
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) FINAL;
+                         Node** value_inputs, bool incomplete) FINAL;
 
  private:
   Node* effect_;
diff --git a/test/cctest/compiler/test-basic-block-profiler.cc b/test/cctest/compiler/test-basic-block-profiler.cc
new file mode 100644
index 0000000..703fc17
--- /dev/null
+++ b/test/cctest/compiler/test-basic-block-profiler.cc
@@ -0,0 +1,114 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/basic-block-profiler.h"
+#include "test/cctest/cctest.h"
+#include "test/cctest/compiler/codegen-tester.h"
+
+#if V8_TURBOFAN_TARGET
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+typedef RawMachineAssembler::Label MLabel;
+
+class BasicBlockProfilerTest : public RawMachineAssemblerTester<int32_t> {
+ public:
+  BasicBlockProfilerTest() : RawMachineAssemblerTester<int32_t>(kMachInt32) {
+    FLAG_turbo_profiling = true;
+  }
+
+  void ResetCounts() { isolate()->basic_block_profiler()->ResetCounts(); }
+
+  void Expect(size_t size, uint32_t* expected) {
+    CHECK_NE(NULL, isolate()->basic_block_profiler());
+    const BasicBlockProfiler::DataList* l =
+        isolate()->basic_block_profiler()->data_list();
+    CHECK_NE(0, static_cast<int>(l->size()));
+    const BasicBlockProfiler::Data* data = l->back();
+    CHECK_EQ(static_cast<int>(size), static_cast<int>(data->n_blocks()));
+    const uint32_t* counts = data->counts();
+    for (size_t i = 0; i < size; ++i) {
+      CHECK_EQ(static_cast<int>(expected[i]), static_cast<int>(counts[i]));
+    }
+  }
+};
+
+
+TEST(ProfileDiamond) {
+  BasicBlockProfilerTest m;
+
+  MLabel blocka, blockb, end;
+  m.Branch(m.Parameter(0), &blocka, &blockb);
+  m.Bind(&blocka);
+  m.Goto(&end);
+  m.Bind(&blockb);
+  m.Goto(&end);
+  m.Bind(&end);
+  m.Return(m.Int32Constant(0));
+
+  m.GenerateCode();
+  {
+    uint32_t expected[] = {0, 0, 0, 0};
+    m.Expect(arraysize(expected), expected);
+  }
+
+  m.Call(0);
+  {
+    uint32_t expected[] = {1, 1, 0, 1};
+    m.Expect(arraysize(expected), expected);
+  }
+
+  m.ResetCounts();
+
+  m.Call(1);
+  {
+    uint32_t expected[] = {1, 0, 1, 1};
+    m.Expect(arraysize(expected), expected);
+  }
+
+  m.Call(0);
+  {
+    uint32_t expected[] = {2, 1, 1, 2};
+    m.Expect(arraysize(expected), expected);
+  }
+}
+
+
+TEST(ProfileLoop) {
+  BasicBlockProfilerTest m;
+
+  MLabel header, body, end;
+  Node* one = m.Int32Constant(1);
+  m.Goto(&header);
+
+  m.Bind(&header);
+  Node* count = m.Phi(kMachInt32, m.Parameter(0), one);
+  m.Branch(count, &body, &end);
+
+  m.Bind(&body);
+  count->ReplaceInput(1, m.Int32Sub(count, one));
+  m.Goto(&header);
+
+  m.Bind(&end);
+  m.Return(one);
+
+  m.GenerateCode();
+  {
+    uint32_t expected[] = {0, 0, 0, 0};
+    m.Expect(arraysize(expected), expected);
+  }
+
+  uint32_t runs[] = {0, 1, 500, 10000};
+  for (size_t i = 0; i < arraysize(runs); i++) {
+    m.ResetCounts();
+    CHECK_EQ(1, m.Call(static_cast<int>(runs[i])));
+    uint32_t expected[] = {1, runs[i] + 1, runs[i], 1};
+    m.Expect(arraysize(expected), expected);
+  }
+}
+
+#endif  // V8_TURBOFAN_TARGET
diff --git a/test/cctest/compiler/test-changes-lowering.cc b/test/cctest/compiler/test-changes-lowering.cc
index 06308a0..5795754 100644
--- a/test/cctest/compiler/test-changes-lowering.cc
+++ b/test/cctest/compiler/test-changes-lowering.cc
@@ -6,10 +6,11 @@
 
 #include "src/compiler/change-lowering.h"
 #include "src/compiler/control-builders.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/pipeline.h"
+#include "src/compiler/select-lowering.h"
+#include "src/compiler/simplified-lowering.h"
 #include "src/compiler/typer.h"
 #include "src/compiler/verifier.h"
 #include "src/execution.h"
@@ -19,6 +20,7 @@
 #include "src/scopes.h"
 #include "test/cctest/cctest.h"
 #include "test/cctest/compiler/codegen-tester.h"
+#include "test/cctest/compiler/function-tester.h"
 #include "test/cctest/compiler/graph-builder-tester.h"
 #include "test/cctest/compiler/value-helper.h"
 
@@ -30,13 +32,10 @@
  public:
   explicit ChangesLoweringTester(MachineType p0 = kMachNone)
       : GraphBuilderTester<ReturnType>(p0),
-        typer(this->zone()),
         javascript(this->zone()),
-        jsgraph(this->graph(), this->common(), &javascript, &typer,
-                this->machine()),
+        jsgraph(this->graph(), this->common(), &javascript, this->machine()),
         function(Handle<JSFunction>::null()) {}
 
-  Typer typer;
   JSOperatorBuilder javascript;
   JSGraph jsgraph;
   Handle<JSFunction> function;
@@ -45,29 +44,10 @@
 
   template <typename T>
   T* CallWithPotentialGC() {
-    // TODO(titzer): we need to wrap the code in a JSFunction and call it via
-    // Execution::Call() so that the GC knows about the frame, can walk it,
-    // relocate the code object if necessary, etc.
-    // This is pretty ugly and at the least should be moved up to helpers.
+    // TODO(titzer): we wrap the code in a JSFunction here to reuse the
+    // JSEntryStub; that could be done with a special prologue or other stub.
     if (function.is_null()) {
-      function =
-          v8::Utils::OpenHandle(*v8::Handle<v8::Function>::Cast(CompileRun(
-              "(function() { 'use strict'; return 2.7123; })")));
-      CompilationInfoWithZone info(function);
-      CHECK(Parser::Parse(&info));
-      info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
-      CHECK(Rewriter::Rewrite(&info));
-      CHECK(Scope::Analyze(&info));
-      CHECK_NE(NULL, info.scope());
-      Handle<ScopeInfo> scope_info =
-          ScopeInfo::Create(info.scope(), info.zone());
-      info.shared_info()->set_scope_info(*scope_info);
-      Pipeline pipeline(&info);
-      Linkage linkage(&info);
-      Handle<Code> code =
-          pipeline.GenerateCodeForMachineGraph(&linkage, this->graph());
-      CHECK(!code.is_null());
-      function->ReplaceCode(*code);
+      function = FunctionTester::ForMachineGraph(this->graph());
     }
     Handle<Object>* args = NULL;
     MaybeHandle<Object> result =
@@ -132,9 +112,9 @@
                          void* location) {
     // We build a graph by hand here, because the raw machine assembler
     // does not add the correct control and effect nodes.
-    Node* load =
-        this->graph()->NewNode(load_op, this->PointerConstant(location),
-                               this->Int32Constant(0), this->start());
+    Node* load = this->graph()->NewNode(
+        load_op, this->PointerConstant(location), this->Int32Constant(0),
+        this->start(), this->start());
     Node* change = this->graph()->NewNode(op, load);
     Node* ret = this->graph()->NewNode(this->common()->Return(), change,
                                        this->start(), this->start());
@@ -146,12 +126,16 @@
   void LowerChange(Node* change) {
     // Run the graph reducer with changes lowering on a single node.
     CompilationInfo info(this->isolate(), this->zone());
-    Linkage linkage(&info);
-    ChangeLowering lowering(&jsgraph, &linkage);
-    GraphReducer reducer(this->graph());
-    reducer.AddReducer(&lowering);
+    Linkage linkage(this->zone(), &info);
+    Typer typer(this->graph(), info.context());
+    typer.Run();
+    ChangeLowering change_lowering(&jsgraph, &linkage);
+    SelectLowering select_lowering(this->graph(), this->common());
+    GraphReducer reducer(this->graph(), this->zone());
+    reducer.AddReducer(&change_lowering);
+    reducer.AddReducer(&select_lowering);
     reducer.ReduceNode(change);
-    Verifier::Run(this->graph());
+    Verifier::Run(this->graph(), Verifier::UNTYPED);
   }
 
   Factory* factory() { return this->isolate()->factory(); }
diff --git a/test/cctest/compiler/test-codegen-deopt.cc b/test/cctest/compiler/test-codegen-deopt.cc
index 8217229..56afe7b 100644
--- a/test/cctest/compiler/test-codegen-deopt.cc
+++ b/test/cctest/compiler/test-codegen-deopt.cc
@@ -16,6 +16,7 @@
 #include "src/compiler/register-allocator.h"
 #include "src/compiler/schedule.h"
 
+#include "src/ast-numbering.h"
 #include "src/full-codegen.h"
 #include "src/parser.h"
 #include "src/rewriter.h"
@@ -30,6 +31,7 @@
 #if V8_TURBOFAN_TARGET
 
 typedef RawMachineAssembler::Label MLabel;
+typedef v8::internal::compiler::InstructionSequence TestInstrSeq;
 
 static Handle<JSFunction> NewFunction(const char* source) {
   return v8::Utils::OpenHandle(
@@ -46,8 +48,7 @@
         bailout_id(-1) {
     CHECK(Parser::Parse(&info));
     info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
-    CHECK(Rewriter::Rewrite(&info));
-    CHECK(Scope::Analyze(&info));
+    CHECK(Compiler::Analyze(&info));
     CHECK(Compiler::EnsureDeoptimizationSupport(&info));
 
     DCHECK(info.shared_info()->has_deoptimization_support());
@@ -55,38 +56,14 @@
     graph = new (scope_->main_zone()) Graph(scope_->main_zone());
   }
 
-  virtual ~DeoptCodegenTester() { delete code; }
+  virtual ~DeoptCodegenTester() {}
 
   void GenerateCodeFromSchedule(Schedule* schedule) {
     OFStream os(stdout);
     if (FLAG_trace_turbo) {
       os << *schedule;
     }
-
-    // Initialize the codegen and generate code.
-    Linkage* linkage = new (scope_->main_zone()) Linkage(&info);
-    code = new v8::internal::compiler::InstructionSequence(linkage, graph,
-                                                           schedule);
-    SourcePositionTable source_positions(graph);
-    InstructionSelector selector(code, &source_positions);
-    selector.SelectInstructions();
-
-    if (FLAG_trace_turbo) {
-      os << "----- Instruction sequence before register allocation -----\n"
-         << *code;
-    }
-
-    RegisterAllocator allocator(code);
-    CHECK(allocator.Allocate());
-
-    if (FLAG_trace_turbo) {
-      os << "----- Instruction sequence after register allocation -----\n"
-         << *code;
-    }
-
-    compiler::CodeGenerator generator(code);
-    result_code = generator.GenerateCode();
-
+    result_code = Pipeline::GenerateCodeForTesting(&info, graph, schedule);
 #ifdef OBJECT_PRINT
     if (FLAG_print_opt_code || FLAG_trace_turbo) {
       result_code->Print();
@@ -101,7 +78,7 @@
   CompilationInfo info;
   BailoutId bailout_id;
   Handle<Code> result_code;
-  v8::internal::compiler::InstructionSequence* code;
+  TestInstrSeq* code;
   Graph* graph;
 };
 
@@ -129,13 +106,13 @@
 
     Handle<JSFunction> deopt_function =
         NewFunction("function deopt() { %DeoptimizeFunction(foo); }; deopt");
-    Unique<Object> deopt_fun_constant =
-        Unique<Object>::CreateUninitialized(deopt_function);
+    Unique<JSFunction> deopt_fun_constant =
+        Unique<JSFunction>::CreateUninitialized(deopt_function);
     Node* deopt_fun_node = m.NewNode(common.HeapConstant(deopt_fun_constant));
 
     Handle<Context> caller_context(function->context(), CcTest::i_isolate());
-    Unique<Object> caller_context_constant =
-        Unique<Object>::CreateUninitialized(caller_context);
+    Unique<Context> caller_context_constant =
+        Unique<Context>::CreateUninitialized(caller_context);
     Node* caller_context_node =
         m.NewNode(common.HeapConstant(caller_context_constant));
 
@@ -145,12 +122,13 @@
     Node* stack = m.NewNode(common.StateValues(0));
 
     Node* state_node = m.NewNode(
-        common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters,
-        locals, stack, caller_context_node, m.UndefinedConstant());
+        common.FrameState(JS_FRAME, bailout_id,
+                          OutputFrameStateCombine::Ignore()),
+        parameters, locals, stack, caller_context_node, m.UndefinedConstant());
 
     Handle<Context> context(deopt_function->context(), CcTest::i_isolate());
-    Unique<Object> context_constant =
-        Unique<Object>::CreateUninitialized(context);
+    Unique<Context> context_constant =
+        Unique<Context>::CreateUninitialized(context);
     Node* context_node = m.NewNode(common.HeapConstant(context_constant));
 
     m.CallJS0(deopt_fun_node, m.UndefinedConstant(), context_node, state_node);
@@ -244,13 +222,13 @@
     CSignature1<Object*, Object*> sig;
     RawMachineAssembler m(graph, &sig);
 
-    Unique<Object> this_fun_constant =
-        Unique<Object>::CreateUninitialized(function);
+    Unique<HeapObject> this_fun_constant =
+        Unique<HeapObject>::CreateUninitialized(function);
     Node* this_fun_node = m.NewNode(common.HeapConstant(this_fun_constant));
 
     Handle<Context> context(function->context(), CcTest::i_isolate());
-    Unique<Object> context_constant =
-        Unique<Object>::CreateUninitialized(context);
+    Unique<HeapObject> context_constant =
+        Unique<HeapObject>::CreateUninitialized(context);
     Node* context_node = m.NewNode(common.HeapConstant(context_constant));
 
     bailout_id = GetCallBailoutId();
@@ -259,8 +237,9 @@
     Node* stack = m.NewNode(common.StateValues(0));
 
     Node* state_node = m.NewNode(
-        common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters,
-        locals, stack, context_node, m.UndefinedConstant());
+        common.FrameState(JS_FRAME, bailout_id,
+                          OutputFrameStateCombine::Ignore()),
+        parameters, locals, stack, context_node, m.UndefinedConstant());
 
     m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, context_node,
                    state_node);
diff --git a/test/cctest/compiler/test-control-reducer.cc b/test/cctest/compiler/test-control-reducer.cc
new file mode 100644
index 0000000..03aa50b
--- /dev/null
+++ b/test/cctest/compiler/test-control-reducer.cc
@@ -0,0 +1,1678 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/base/bits.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/control-reducer.h"
+#include "src/compiler/graph-inl.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/node-properties-inl.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+static const size_t kNumLeafs = 4;
+
+// TODO(titzer): convert this whole file into unit tests.
+
+static int CheckInputs(Node* node, Node* i0 = NULL, Node* i1 = NULL,
+                       Node* i2 = NULL) {
+  int count = 3;
+  if (i2 == NULL) count = 2;
+  if (i1 == NULL) count = 1;
+  if (i0 == NULL) count = 0;
+  CHECK_EQ(count, node->InputCount());
+  if (i0 != NULL) CHECK_EQ(i0, node->InputAt(0));
+  if (i1 != NULL) CHECK_EQ(i1, node->InputAt(1));
+  if (i2 != NULL) CHECK_EQ(i2, node->InputAt(2));
+  return count;
+}
+
+
+static int CheckMerge(Node* node, Node* i0 = NULL, Node* i1 = NULL,
+                      Node* i2 = NULL) {
+  CHECK_EQ(IrOpcode::kMerge, node->opcode());
+  int count = CheckInputs(node, i0, i1, i2);
+  CHECK_EQ(count, node->op()->ControlInputCount());
+  return count;
+}
+
+
+static int CheckLoop(Node* node, Node* i0 = NULL, Node* i1 = NULL,
+                     Node* i2 = NULL) {
+  CHECK_EQ(IrOpcode::kLoop, node->opcode());
+  int count = CheckInputs(node, i0, i1, i2);
+  CHECK_EQ(count, node->op()->ControlInputCount());
+  return count;
+}
+
+
+bool IsUsedBy(Node* a, Node* b) {
+  for (UseIter i = a->uses().begin(); i != a->uses().end(); ++i) {
+    if (b == *i) return true;
+  }
+  return false;
+}
+
+
+// A helper for all tests dealing with ControlTester.
+class ControlReducerTester : HandleAndZoneScope {
+ public:
+  ControlReducerTester()
+      : isolate(main_isolate()),
+        common(main_zone()),
+        graph(main_zone()),
+        jsgraph(&graph, &common, NULL, NULL),
+        start(graph.NewNode(common.Start(1))),
+        end(graph.NewNode(common.End(), start)),
+        p0(graph.NewNode(common.Parameter(0), start)),
+        zero(jsgraph.Int32Constant(0)),
+        one(jsgraph.OneConstant()),
+        half(jsgraph.Constant(0.5)),
+        self(graph.NewNode(common.Int32Constant(0xaabbccdd))),
+        dead(graph.NewNode(common.Dead())) {
+    graph.SetEnd(end);
+    graph.SetStart(start);
+    leaf[0] = zero;
+    leaf[1] = one;
+    leaf[2] = half;
+    leaf[3] = p0;
+  }
+
+  Isolate* isolate;
+  CommonOperatorBuilder common;
+  Graph graph;
+  JSGraph jsgraph;
+  Node* start;
+  Node* end;
+  Node* p0;
+  Node* zero;
+  Node* one;
+  Node* half;
+  Node* self;
+  Node* dead;
+  Node* leaf[kNumLeafs];
+
+  Node* Phi(Node* a) {
+    return SetSelfReferences(graph.NewNode(op(1, false), a, start));
+  }
+
+  Node* Phi(Node* a, Node* b) {
+    return SetSelfReferences(graph.NewNode(op(2, false), a, b, start));
+  }
+
+  Node* Phi(Node* a, Node* b, Node* c) {
+    return SetSelfReferences(graph.NewNode(op(3, false), a, b, c, start));
+  }
+
+  Node* Phi(Node* a, Node* b, Node* c, Node* d) {
+    return SetSelfReferences(graph.NewNode(op(4, false), a, b, c, d, start));
+  }
+
+  Node* EffectPhi(Node* a) {
+    return SetSelfReferences(graph.NewNode(op(1, true), a, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b) {
+    return SetSelfReferences(graph.NewNode(op(2, true), a, b, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b, Node* c) {
+    return SetSelfReferences(graph.NewNode(op(3, true), a, b, c, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b, Node* c, Node* d) {
+    return SetSelfReferences(graph.NewNode(op(4, true), a, b, c, d, start));
+  }
+
+  Node* SetSelfReferences(Node* node) {
+    for (Edge edge : node->input_edges()) {
+      if (edge.to() == self) node->ReplaceInput(edge.index(), node);
+    }
+    return node;
+  }
+
+  const Operator* op(int count, bool effect) {
+    return effect ? common.EffectPhi(count) : common.Phi(kMachAnyTagged, count);
+  }
+
+  void Trim() { ControlReducer::TrimGraph(main_zone(), &jsgraph); }
+
+  void ReduceGraph() {
+    ControlReducer::ReduceGraph(main_zone(), &jsgraph, &common);
+  }
+
+  // Checks one-step reduction of a phi.
+  void ReducePhi(Node* expect, Node* phi) {
+    Node* result = ControlReducer::ReducePhiForTesting(&jsgraph, &common, phi);
+    CHECK_EQ(expect, result);
+    ReducePhiIterative(expect, phi);  // iterative should give the same result.
+  }
+
+  void ReducePhiIterative(Node* expect, Node* phi) {
+    p0->ReplaceInput(0, start);  // hack: parameters may be trimmed.
+    Node* ret = graph.NewNode(common.Return(), phi, start, start);
+    Node* end = graph.NewNode(common.End(), ret);
+    graph.SetEnd(end);
+    ControlReducer::ReduceGraph(main_zone(), &jsgraph, &common);
+    CheckInputs(end, ret);
+    CheckInputs(ret, expect, start, start);
+  }
+
+  void ReduceMerge(Node* expect, Node* merge) {
+    Node* result =
+        ControlReducer::ReduceMergeForTesting(&jsgraph, &common, merge);
+    CHECK_EQ(expect, result);
+  }
+
+  void ReduceMergeIterative(Node* expect, Node* merge) {
+    p0->ReplaceInput(0, start);  // hack: parameters may be trimmed.
+    Node* end = graph.NewNode(common.End(), merge);
+    graph.SetEnd(end);
+    ReduceGraph();
+    CheckInputs(end, expect);
+  }
+
+  void ReduceBranch(Node* expect, Node* branch) {
+    Node* result =
+        ControlReducer::ReduceBranchForTesting(&jsgraph, &common, branch);
+    CHECK_EQ(expect, result);
+  }
+
+  Node* Return(Node* val, Node* effect, Node* control) {
+    Node* ret = graph.NewNode(common.Return(), val, effect, control);
+    end->ReplaceInput(0, ret);
+    return ret;
+  }
+};
+
+
+TEST(Trim1_live) {
+  ControlReducerTester T;
+  CHECK(IsUsedBy(T.start, T.p0));
+  T.graph.SetEnd(T.p0);
+  T.Trim();
+  CHECK(IsUsedBy(T.start, T.p0));
+  CheckInputs(T.p0, T.start);
+}
+
+
+TEST(Trim1_dead) {
+  ControlReducerTester T;
+  CHECK(IsUsedBy(T.start, T.p0));
+  T.Trim();
+  CHECK(!IsUsedBy(T.start, T.p0));
+  CHECK_EQ(NULL, T.p0->InputAt(0));
+}
+
+
+TEST(Trim2_live) {
+  ControlReducerTester T;
+  Node* phi =
+      T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start);
+  CHECK(IsUsedBy(T.one, phi));
+  CHECK(IsUsedBy(T.half, phi));
+  CHECK(IsUsedBy(T.start, phi));
+  T.graph.SetEnd(phi);
+  T.Trim();
+  CHECK(IsUsedBy(T.one, phi));
+  CHECK(IsUsedBy(T.half, phi));
+  CHECK(IsUsedBy(T.start, phi));
+  CheckInputs(phi, T.one, T.half, T.start);
+}
+
+
+TEST(Trim2_dead) {
+  ControlReducerTester T;
+  Node* phi =
+      T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start);
+  CHECK(IsUsedBy(T.one, phi));
+  CHECK(IsUsedBy(T.half, phi));
+  CHECK(IsUsedBy(T.start, phi));
+  T.Trim();
+  CHECK(!IsUsedBy(T.one, phi));
+  CHECK(!IsUsedBy(T.half, phi));
+  CHECK(!IsUsedBy(T.start, phi));
+  CHECK_EQ(NULL, phi->InputAt(0));
+  CHECK_EQ(NULL, phi->InputAt(1));
+  CHECK_EQ(NULL, phi->InputAt(2));
+}
+
+
+TEST(Trim_chain1) {
+  ControlReducerTester T;
+  const int kDepth = 15;
+  Node* live[kDepth];
+  Node* dead[kDepth];
+  Node* end = T.start;
+  for (int i = 0; i < kDepth; i++) {
+    live[i] = end = T.graph.NewNode(T.common.Merge(1), end);
+    dead[i] = T.graph.NewNode(T.common.Merge(1), end);
+  }
+  // end         -> live[last] ->  live[last-1] -> ... -> start
+  //     dead[last] ^ dead[last-1] ^ ...                  ^
+  T.graph.SetEnd(end);
+  T.Trim();
+  for (int i = 0; i < kDepth; i++) {
+    CHECK(!IsUsedBy(live[i], dead[i]));
+    CHECK_EQ(NULL, dead[i]->InputAt(0));
+    CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0));
+  }
+}
+
+
+TEST(Trim_chain2) {
+  ControlReducerTester T;
+  const int kDepth = 15;
+  Node* live[kDepth];
+  Node* dead[kDepth];
+  Node* l = T.start;
+  Node* d = T.start;
+  for (int i = 0; i < kDepth; i++) {
+    live[i] = l = T.graph.NewNode(T.common.Merge(1), l);
+    dead[i] = d = T.graph.NewNode(T.common.Merge(1), d);
+  }
+  // end -> live[last] -> live[last-1] -> ... -> start
+  //        dead[last] -> dead[last-1] -> ... -> start
+  T.graph.SetEnd(l);
+  T.Trim();
+  CHECK(!IsUsedBy(T.start, dead[0]));
+  for (int i = 0; i < kDepth; i++) {
+    CHECK_EQ(i == 0 ? NULL : dead[i - 1], dead[i]->InputAt(0));
+    CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0));
+  }
+}
+
+
+TEST(Trim_cycle1) {
+  ControlReducerTester T;
+  Node* loop = T.graph.NewNode(T.common.Loop(1), T.start, T.start);
+  loop->ReplaceInput(1, loop);
+  Node* end = T.graph.NewNode(T.common.End(), loop);
+  T.graph.SetEnd(end);
+
+  CHECK(IsUsedBy(T.start, loop));
+  CHECK(IsUsedBy(loop, end));
+  CHECK(IsUsedBy(loop, loop));
+
+  T.Trim();
+
+  // nothing should have happened to the loop itself.
+  CHECK(IsUsedBy(T.start, loop));
+  CHECK(IsUsedBy(loop, end));
+  CHECK(IsUsedBy(loop, loop));
+  CheckInputs(loop, T.start, loop);
+  CheckInputs(end, loop);
+}
+
+
+TEST(Trim_cycle2) {
+  ControlReducerTester T;
+  Node* loop = T.graph.NewNode(T.common.Loop(2), T.start, T.start);
+  loop->ReplaceInput(1, loop);
+  Node* end = T.graph.NewNode(T.common.End(), loop);
+  Node* phi =
+      T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, loop);
+  T.graph.SetEnd(end);
+
+  CHECK(IsUsedBy(T.start, loop));
+  CHECK(IsUsedBy(loop, end));
+  CHECK(IsUsedBy(loop, loop));
+  CHECK(IsUsedBy(loop, phi));
+  CHECK(IsUsedBy(T.one, phi));
+  CHECK(IsUsedBy(T.half, phi));
+
+  T.Trim();
+
+  // nothing should have happened to the loop itself.
+  CHECK(IsUsedBy(T.start, loop));
+  CHECK(IsUsedBy(loop, end));
+  CHECK(IsUsedBy(loop, loop));
+  CheckInputs(loop, T.start, loop);
+  CheckInputs(end, loop);
+
+  // phi should have been trimmed away.
+  CHECK(!IsUsedBy(loop, phi));
+  CHECK(!IsUsedBy(T.one, phi));
+  CHECK(!IsUsedBy(T.half, phi));
+  CHECK_EQ(NULL, phi->InputAt(0));
+  CHECK_EQ(NULL, phi->InputAt(1));
+  CHECK_EQ(NULL, phi->InputAt(2));
+}
+
+
+void CheckTrimConstant(ControlReducerTester* T, Node* k) {
+  Node* phi = T->graph.NewNode(T->common.Phi(kMachInt32, 1), k, T->start);
+  CHECK(IsUsedBy(k, phi));
+  T->Trim();
+  CHECK(!IsUsedBy(k, phi));
+  CHECK_EQ(NULL, phi->InputAt(0));
+  CHECK_EQ(NULL, phi->InputAt(1));
+}
+
+
+TEST(Trim_constants) {
+  ControlReducerTester T;
+  int32_t int32_constants[] = {
+      0, -1,  -2,  2,  2,  3,  3,  4,  4,  5,  5,  4,  5,  6, 6, 7, 8, 7, 8, 9,
+      0, -11, -12, 12, 12, 13, 13, 14, 14, 15, 15, 14, 15, 6, 6, 7, 8, 7, 8, 9};
+
+  for (size_t i = 0; i < arraysize(int32_constants); i++) {
+    CheckTrimConstant(&T, T.jsgraph.Int32Constant(int32_constants[i]));
+    CheckTrimConstant(&T, T.jsgraph.Float64Constant(int32_constants[i]));
+    CheckTrimConstant(&T, T.jsgraph.Constant(int32_constants[i]));
+  }
+
+  Node* other_constants[] = {
+      T.jsgraph.UndefinedConstant(), T.jsgraph.TheHoleConstant(),
+      T.jsgraph.TrueConstant(),      T.jsgraph.FalseConstant(),
+      T.jsgraph.NullConstant(),      T.jsgraph.ZeroConstant(),
+      T.jsgraph.OneConstant(),       T.jsgraph.NaNConstant(),
+      T.jsgraph.Constant(21),        T.jsgraph.Constant(22.2)};
+
+  for (size_t i = 0; i < arraysize(other_constants); i++) {
+    CheckTrimConstant(&T, other_constants[i]);
+  }
+}
+
+
+TEST(CReducePhi1) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0]));
+  R.ReducePhi(R.leaf[1], R.Phi(R.leaf[1]));
+  R.ReducePhi(R.leaf[2], R.Phi(R.leaf[2]));
+  R.ReducePhi(R.leaf[3], R.Phi(R.leaf[3]));
+}
+
+
+TEST(CReducePhi1_dead) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0], R.dead));
+  R.ReducePhi(R.leaf[1], R.Phi(R.leaf[1], R.dead));
+  R.ReducePhi(R.leaf[2], R.Phi(R.leaf[2], R.dead));
+  R.ReducePhi(R.leaf[3], R.Phi(R.leaf[3], R.dead));
+
+  R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.leaf[0]));
+  R.ReducePhi(R.leaf[1], R.Phi(R.dead, R.leaf[1]));
+  R.ReducePhi(R.leaf[2], R.Phi(R.dead, R.leaf[2]));
+  R.ReducePhi(R.leaf[3], R.Phi(R.dead, R.leaf[3]));
+}
+
+
+TEST(CReducePhi1_dead2) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0], R.dead, R.dead));
+  R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.leaf[0], R.dead));
+  R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.dead, R.leaf[0]));
+}
+
+
+TEST(CReducePhi2a) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(a, a));
+  }
+}
+
+
+TEST(CReducePhi2b) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(R.self, a));
+    R.ReducePhi(a, R.Phi(a, R.self));
+  }
+}
+
+
+TEST(CReducePhi2c) {
+  ControlReducerTester R;
+
+  for (size_t i = 1; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i], *b = R.leaf[0];
+    Node* phi1 = R.Phi(b, a);
+    R.ReducePhi(phi1, phi1);
+
+    Node* phi2 = R.Phi(a, b);
+    R.ReducePhi(phi2, phi2);
+  }
+}
+
+
+TEST(CReducePhi2_dead) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(a, a, R.dead));
+    R.ReducePhi(a, R.Phi(a, R.dead, a));
+    R.ReducePhi(a, R.Phi(R.dead, a, a));
+  }
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(R.self, a));
+    R.ReducePhi(a, R.Phi(a, R.self));
+    R.ReducePhi(a, R.Phi(R.self, a, R.dead));
+    R.ReducePhi(a, R.Phi(a, R.self, R.dead));
+  }
+
+  for (size_t i = 1; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i], *b = R.leaf[0];
+    Node* phi1 = R.Phi(b, a, R.dead);
+    R.ReducePhi(phi1, phi1);
+
+    Node* phi2 = R.Phi(a, b, R.dead);
+    R.ReducePhi(phi2, phi2);
+  }
+}
+
+
+TEST(CReducePhi3) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(a, a, a));
+  }
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(R.self, a, a));
+    R.ReducePhi(a, R.Phi(a, R.self, a));
+    R.ReducePhi(a, R.Phi(a, a, R.self));
+  }
+
+  for (size_t i = 1; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i], *b = R.leaf[0];
+    Node* phi1 = R.Phi(b, a, a);
+    R.ReducePhi(phi1, phi1);
+
+    Node* phi2 = R.Phi(a, b, a);
+    R.ReducePhi(phi2, phi2);
+
+    Node* phi3 = R.Phi(a, a, b);
+    R.ReducePhi(phi3, phi3);
+  }
+}
+
+
+TEST(CReducePhi4) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(a, a, a, a));
+  }
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(R.self, a, a, a));
+    R.ReducePhi(a, R.Phi(a, R.self, a, a));
+    R.ReducePhi(a, R.Phi(a, a, R.self, a));
+    R.ReducePhi(a, R.Phi(a, a, a, R.self));
+
+    R.ReducePhi(a, R.Phi(R.self, R.self, a, a));
+    R.ReducePhi(a, R.Phi(a, R.self, R.self, a));
+    R.ReducePhi(a, R.Phi(a, a, R.self, R.self));
+    R.ReducePhi(a, R.Phi(R.self, a, a, R.self));
+  }
+
+  for (size_t i = 1; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i], *b = R.leaf[0];
+    Node* phi1 = R.Phi(b, a, a, a);
+    R.ReducePhi(phi1, phi1);
+
+    Node* phi2 = R.Phi(a, b, a, a);
+    R.ReducePhi(phi2, phi2);
+
+    Node* phi3 = R.Phi(a, a, b, a);
+    R.ReducePhi(phi3, phi3);
+
+    Node* phi4 = R.Phi(a, a, a, b);
+    R.ReducePhi(phi4, phi4);
+  }
+}
+
+
+TEST(CReducePhi_iterative1) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.leaf[0], R.Phi(R.leaf[0])));
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0]), R.leaf[0]));
+}
+
+
+TEST(CReducePhi_iterative2) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0]), R.Phi(R.leaf[0])));
+}
+
+
+TEST(CReducePhi_iterative3) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0],
+                       R.Phi(R.leaf[0], R.Phi(R.leaf[0], R.leaf[0])));
+  R.ReducePhiIterative(R.leaf[0],
+                       R.Phi(R.Phi(R.leaf[0], R.leaf[0]), R.leaf[0]));
+}
+
+
+TEST(CReducePhi_iterative4) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.leaf[0]),
+                                        R.Phi(R.leaf[0], R.leaf[0])));
+
+  Node* p1 = R.Phi(R.leaf[0], R.leaf[0]);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p1, p1));
+
+  Node* p2 = R.Phi(R.leaf[0], R.leaf[0], R.leaf[0]);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p2, p2, p2));
+
+  Node* p3 = R.Phi(R.leaf[0], R.leaf[0], R.leaf[0]);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p3, p3, R.leaf[0]));
+}
+
+
+TEST(CReducePhi_iterative_self1) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.leaf[0], R.Phi(R.leaf[0], R.self)));
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.self), R.leaf[0]));
+}
+
+
+TEST(CReducePhi_iterative_self2) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(
+      R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.self), R.Phi(R.leaf[0], R.self)));
+  R.ReducePhiIterative(
+      R.leaf[0], R.Phi(R.Phi(R.self, R.leaf[0]), R.Phi(R.self, R.leaf[0])));
+
+  Node* p1 = R.Phi(R.leaf[0], R.self);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p1, p1));
+
+  Node* p2 = R.Phi(R.self, R.leaf[0]);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p2, p2));
+}
+
+
+TEST(EReducePhi1) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0]));
+  R.ReducePhi(R.leaf[1], R.EffectPhi(R.leaf[1]));
+  R.ReducePhi(R.leaf[2], R.EffectPhi(R.leaf[2]));
+  R.ReducePhi(R.leaf[3], R.EffectPhi(R.leaf[3]));
+}
+
+
+TEST(EReducePhi1_dead) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0], R.dead));
+  R.ReducePhi(R.leaf[1], R.EffectPhi(R.leaf[1], R.dead));
+  R.ReducePhi(R.leaf[2], R.EffectPhi(R.leaf[2], R.dead));
+  R.ReducePhi(R.leaf[3], R.EffectPhi(R.leaf[3], R.dead));
+
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.leaf[0]));
+  R.ReducePhi(R.leaf[1], R.EffectPhi(R.dead, R.leaf[1]));
+  R.ReducePhi(R.leaf[2], R.EffectPhi(R.dead, R.leaf[2]));
+  R.ReducePhi(R.leaf[3], R.EffectPhi(R.dead, R.leaf[3]));
+}
+
+
+TEST(EReducePhi1_dead2) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0], R.dead, R.dead));
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.leaf[0], R.dead));
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.dead, R.leaf[0]));
+}
+
+
+TEST(CMergeReduce_simple1) {
+  ControlReducerTester R;
+
+  Node* merge = R.graph.NewNode(R.common.Merge(1), R.start);
+  R.ReduceMerge(R.start, merge);
+}
+
+
+TEST(CMergeReduce_simple2) {
+  ControlReducerTester R;
+
+  Node* merge1 = R.graph.NewNode(R.common.Merge(1), R.start);
+  Node* merge2 = R.graph.NewNode(R.common.Merge(1), merge1);
+  R.ReduceMerge(merge1, merge2);
+  R.ReduceMergeIterative(R.start, merge2);
+}
+
+
+TEST(CMergeReduce_none1) {
+  ControlReducerTester R;
+
+  Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, R.start);
+  R.ReduceMerge(merge, merge);
+}
+
+
+TEST(CMergeReduce_none2) {
+  ControlReducerTester R;
+
+  Node* t = R.graph.NewNode(R.common.IfTrue(), R.start);
+  Node* f = R.graph.NewNode(R.common.IfFalse(), R.start);
+  Node* merge = R.graph.NewNode(R.common.Merge(2), t, f);
+  R.ReduceMerge(merge, merge);
+}
+
+
+TEST(CMergeReduce_self3) {
+  ControlReducerTester R;
+
+  Node* merge =
+      R.SetSelfReferences(R.graph.NewNode(R.common.Merge(2), R.start, R.self));
+  R.ReduceMerge(merge, merge);
+}
+
+
+TEST(CMergeReduce_dead1) {
+  ControlReducerTester R;
+
+  Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, R.dead);
+  R.ReduceMerge(R.start, merge);
+}
+
+
+TEST(CMergeReduce_dead2) {
+  ControlReducerTester R;
+
+  Node* merge1 = R.graph.NewNode(R.common.Merge(1), R.start);
+  Node* merge2 = R.graph.NewNode(R.common.Merge(2), merge1, R.dead);
+  R.ReduceMerge(merge1, merge2);
+  R.ReduceMergeIterative(R.start, merge2);
+}
+
+
+TEST(CMergeReduce_dead_rm1a) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
+    merge->ReplaceInput(i, R.dead);
+    R.ReduceMerge(merge, merge);
+    CheckMerge(merge, R.start, R.start);
+  }
+}
+
+
+TEST(CMergeReduce_dead_rm1b) {
+  ControlReducerTester R;
+
+  Node* t = R.graph.NewNode(R.common.IfTrue(), R.start);
+  Node* f = R.graph.NewNode(R.common.IfFalse(), R.start);
+  for (int i = 0; i < 2; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead);
+    for (int j = i + 1; j < 3; j++) {
+      merge->ReplaceInput(i, t);
+      merge->ReplaceInput(j, f);
+      R.ReduceMerge(merge, merge);
+      CheckMerge(merge, t, f);
+    }
+  }
+}
+
+
+TEST(CMergeReduce_dead_rm2) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead);
+    merge->ReplaceInput(i, R.start);
+    R.ReduceMerge(R.start, merge);
+  }
+}
+
+
+TEST(CLoopReduce_dead_rm1) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* loop = R.graph.NewNode(R.common.Loop(3), R.dead, R.start, R.start);
+    R.ReduceMerge(loop, loop);
+    CheckLoop(loop, R.start, R.start);
+  }
+}
+
+
+TEST(CMergeReduce_edit_phi1) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
+    merge->ReplaceInput(i, R.dead);
+    Node* phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 3), R.leaf[0],
+                                R.leaf[1], R.leaf[2], merge);
+    R.ReduceMerge(merge, merge);
+    CHECK_EQ(IrOpcode::kPhi, phi->opcode());
+    CHECK_EQ(2, phi->op()->ValueInputCount());
+    CHECK_EQ(3, phi->InputCount());
+    CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0));
+    CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1));
+    CHECK_EQ(merge, phi->InputAt(2));
+  }
+}
+
+
+TEST(CMergeReduce_edit_effect_phi1) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
+    merge->ReplaceInput(i, R.dead);
+    Node* phi = R.graph.NewNode(R.common.EffectPhi(3), R.leaf[0], R.leaf[1],
+                                R.leaf[2], merge);
+    R.ReduceMerge(merge, merge);
+    CHECK_EQ(IrOpcode::kEffectPhi, phi->opcode());
+    CHECK_EQ(0, phi->op()->ValueInputCount());
+    CHECK_EQ(2, phi->op()->EffectInputCount());
+    CHECK_EQ(3, phi->InputCount());
+    CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0));
+    CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1));
+    CHECK_EQ(merge, phi->InputAt(2));
+  }
+}
+
+
+static const int kSelectorSize = 4;
+
+// Helper to select K of N nodes according to a mask, useful for the test below.
+struct Selector {
+  int mask;
+  int count;
+  explicit Selector(int m) {
+    mask = m;
+    count = v8::base::bits::CountPopulation32(m);
+  }
+  bool is_selected(int i) { return (mask & (1 << i)) != 0; }
+  void CheckNode(Node* node, IrOpcode::Value opcode, Node** inputs,
+                 Node* control) {
+    CHECK_EQ(opcode, node->opcode());
+    CHECK_EQ(count + (control != NULL ? 1 : 0), node->InputCount());
+    int index = 0;
+    for (int i = 0; i < kSelectorSize; i++) {
+      if (mask & (1 << i)) {
+        CHECK_EQ(inputs[i], node->InputAt(index++));
+      }
+    }
+    CHECK_EQ(count, index);
+    if (control != NULL) CHECK_EQ(control, node->InputAt(index++));
+  }
+  int single_index() {
+    CHECK_EQ(1, count);
+    return WhichPowerOf2(mask);
+  }
+};
+
+
+TEST(CMergeReduce_exhaustive_4) {
+  ControlReducerTester R;
+  Node* controls[] = {
+      R.graph.NewNode(R.common.Start(1)), R.graph.NewNode(R.common.Start(2)),
+      R.graph.NewNode(R.common.Start(3)), R.graph.NewNode(R.common.Start(4))};
+  Node* values[] = {R.jsgraph.Int32Constant(11), R.jsgraph.Int32Constant(22),
+                    R.jsgraph.Int32Constant(33), R.jsgraph.Int32Constant(44)};
+  Node* effects[] = {
+      R.jsgraph.Float64Constant(123.4), R.jsgraph.Float64Constant(223.4),
+      R.jsgraph.Float64Constant(323.4), R.jsgraph.Float64Constant(423.4)};
+
+  for (int mask = 0; mask < (1 << (kSelectorSize - 1)); mask++) {
+    // Reduce a single merge with a given mask.
+    Node* merge = R.graph.NewNode(R.common.Merge(4), controls[0], controls[1],
+                                  controls[2], controls[3]);
+    Node* phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 4), values[0],
+                                values[1], values[2], values[3], merge);
+    Node* ephi = R.graph.NewNode(R.common.EffectPhi(4), effects[0], effects[1],
+                                 effects[2], effects[3], merge);
+
+    Node* phi_use =
+        R.graph.NewNode(R.common.Phi(kMachAnyTagged, 1), phi, R.start);
+    Node* ephi_use = R.graph.NewNode(R.common.EffectPhi(1), ephi, R.start);
+
+    Selector selector(mask);
+
+    for (int i = 0; i < kSelectorSize; i++) {  // set up dead merge inputs.
+      if (!selector.is_selected(i)) merge->ReplaceInput(i, R.dead);
+    }
+
+    Node* result =
+        ControlReducer::ReduceMergeForTesting(&R.jsgraph, &R.common, merge);
+
+    int count = selector.count;
+    if (count == 0) {
+      // result should be dead.
+      CHECK_EQ(IrOpcode::kDead, result->opcode());
+    } else if (count == 1) {
+      // merge should be replaced with one of the controls.
+      CHECK_EQ(controls[selector.single_index()], result);
+      // Phis should have been directly replaced.
+      CHECK_EQ(values[selector.single_index()], phi_use->InputAt(0));
+      CHECK_EQ(effects[selector.single_index()], ephi_use->InputAt(0));
+    } else {
+      // Otherwise, nodes should be edited in place.
+      CHECK_EQ(merge, result);
+      selector.CheckNode(merge, IrOpcode::kMerge, controls, NULL);
+      selector.CheckNode(phi, IrOpcode::kPhi, values, merge);
+      selector.CheckNode(ephi, IrOpcode::kEffectPhi, effects, merge);
+      CHECK_EQ(phi, phi_use->InputAt(0));
+      CHECK_EQ(ephi, ephi_use->InputAt(0));
+      CHECK_EQ(count, phi->op()->ValueInputCount());
+      CHECK_EQ(count + 1, phi->InputCount());
+      CHECK_EQ(count, ephi->op()->EffectInputCount());
+      CHECK_EQ(count + 1, ephi->InputCount());
+    }
+  }
+}
+
+
+TEST(CMergeReduce_edit_many_phis1) {
+  ControlReducerTester R;
+
+  const int kPhiCount = 10;
+  Node* phis[kPhiCount];
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
+    merge->ReplaceInput(i, R.dead);
+    for (int j = 0; j < kPhiCount; j++) {
+      phis[j] = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 3), R.leaf[0],
+                                R.leaf[1], R.leaf[2], merge);
+    }
+    R.ReduceMerge(merge, merge);
+    for (int j = 0; j < kPhiCount; j++) {
+      Node* phi = phis[j];
+      CHECK_EQ(IrOpcode::kPhi, phi->opcode());
+      CHECK_EQ(2, phi->op()->ValueInputCount());
+      CHECK_EQ(3, phi->InputCount());
+      CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0));
+      CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1));
+      CHECK_EQ(merge, phi->InputAt(2));
+    }
+  }
+}
+
+
+TEST(CMergeReduce_simple_chain1) {
+  ControlReducerTester R;
+  for (int i = 0; i < 5; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(1), R.start);
+    for (int j = 0; j < i; j++) {
+      merge = R.graph.NewNode(R.common.Merge(1), merge);
+    }
+    R.ReduceMergeIterative(R.start, merge);
+  }
+}
+
+
+TEST(CMergeReduce_dead_chain1) {
+  ControlReducerTester R;
+  for (int i = 0; i < 5; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(1), R.dead);
+    for (int j = 0; j < i; j++) {
+      merge = R.graph.NewNode(R.common.Merge(1), merge);
+    }
+    Node* end = R.graph.NewNode(R.common.End(), merge);
+    R.graph.SetEnd(end);
+    R.ReduceGraph();
+    CHECK(merge->IsDead());
+    CHECK_EQ(NULL, end->InputAt(0));  // end dies.
+  }
+}
+
+
+TEST(CMergeReduce_dead_chain2) {
+  ControlReducerTester R;
+  for (int i = 0; i < 5; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(1), R.start);
+    for (int j = 0; j < i; j++) {
+      merge = R.graph.NewNode(R.common.Merge(2), merge, R.dead);
+    }
+    R.ReduceMergeIterative(R.start, merge);
+  }
+}
+
+
+struct Branch {
+  Node* branch;
+  Node* if_true;
+  Node* if_false;
+
+  Branch(ControlReducerTester& R, Node* cond, Node* control = NULL) {
+    if (control == NULL) control = R.start;
+    branch = R.graph.NewNode(R.common.Branch(), cond, control);
+    if_true = R.graph.NewNode(R.common.IfTrue(), branch);
+    if_false = R.graph.NewNode(R.common.IfFalse(), branch);
+  }
+};
+
+
+// TODO(titzer): use the diamonds from src/compiler/diamond.h here.
+struct Diamond {
+  Node* branch;
+  Node* if_true;
+  Node* if_false;
+  Node* merge;
+  Node* phi;
+
+  Diamond(ControlReducerTester& R, Node* cond) {
+    branch = R.graph.NewNode(R.common.Branch(), cond, R.start);
+    if_true = R.graph.NewNode(R.common.IfTrue(), branch);
+    if_false = R.graph.NewNode(R.common.IfFalse(), branch);
+    merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false);
+    phi = NULL;
+  }
+
+  Diamond(ControlReducerTester& R, Node* cond, Node* tv, Node* fv) {
+    branch = R.graph.NewNode(R.common.Branch(), cond, R.start);
+    if_true = R.graph.NewNode(R.common.IfTrue(), branch);
+    if_false = R.graph.NewNode(R.common.IfFalse(), branch);
+    merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false);
+    phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 2), tv, fv, merge);
+  }
+
+  void chain(Diamond& that) { branch->ReplaceInput(1, that.merge); }
+
+  // Nest {this} into either the if_true or if_false branch of {that}.
+  void nest(Diamond& that, bool if_true) {
+    if (if_true) {
+      branch->ReplaceInput(1, that.if_true);
+      that.merge->ReplaceInput(0, merge);
+    } else {
+      branch->ReplaceInput(1, that.if_false);
+      that.merge->ReplaceInput(1, merge);
+    }
+  }
+};
+
+
+struct While {
+  Node* branch;
+  Node* if_true;
+  Node* exit;
+  Node* loop;
+
+  While(ControlReducerTester& R, Node* cond) {
+    loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start);
+    branch = R.graph.NewNode(R.common.Branch(), cond, loop);
+    if_true = R.graph.NewNode(R.common.IfTrue(), branch);
+    exit = R.graph.NewNode(R.common.IfFalse(), branch);
+    loop->ReplaceInput(1, if_true);
+  }
+
+  void chain(Node* control) { loop->ReplaceInput(0, control); }
+};
+
+
+TEST(CBranchReduce_none1) {
+  ControlReducerTester R;
+  Diamond d(R, R.p0);
+  R.ReduceBranch(d.branch, d.branch);
+}
+
+
+TEST(CBranchReduce_none2) {
+  ControlReducerTester R;
+  Diamond d1(R, R.p0);
+  Diamond d2(R, R.p0);
+  d2.chain(d1);
+  R.ReduceBranch(d2.branch, d2.branch);
+}
+
+
+TEST(CBranchReduce_true) {
+  ControlReducerTester R;
+  Node* true_values[] = {
+      R.one,                               R.jsgraph.Int32Constant(2),
+      R.jsgraph.Int32Constant(0x7fffffff), R.jsgraph.Constant(1.0),
+      R.jsgraph.Constant(22.1),            R.jsgraph.TrueConstant()};
+
+  for (size_t i = 0; i < arraysize(true_values); i++) {
+    Diamond d(R, true_values[i]);
+    Node* true_use = R.graph.NewNode(R.common.Merge(1), d.if_true);
+    Node* false_use = R.graph.NewNode(R.common.Merge(1), d.if_false);
+    R.ReduceBranch(R.start, d.branch);
+    CHECK_EQ(R.start, true_use->InputAt(0));
+    CHECK_EQ(IrOpcode::kDead, false_use->InputAt(0)->opcode());
+    CHECK(d.if_true->IsDead());   // replaced
+    CHECK(d.if_false->IsDead());  // replaced
+  }
+}
+
+
+TEST(CBranchReduce_false) {
+  ControlReducerTester R;
+  Node* false_values[] = {R.zero, R.jsgraph.Constant(0.0),
+                          R.jsgraph.Constant(-0.0), R.jsgraph.FalseConstant()};
+
+  for (size_t i = 0; i < arraysize(false_values); i++) {
+    Diamond d(R, false_values[i]);
+    Node* true_use = R.graph.NewNode(R.common.Merge(1), d.if_true);
+    Node* false_use = R.graph.NewNode(R.common.Merge(1), d.if_false);
+    R.ReduceBranch(R.start, d.branch);
+    CHECK_EQ(R.start, false_use->InputAt(0));
+    CHECK_EQ(IrOpcode::kDead, true_use->InputAt(0)->opcode());
+    CHECK(d.if_true->IsDead());   // replaced
+    CHECK(d.if_false->IsDead());  // replaced
+  }
+}
+
+
+TEST(CDiamondReduce_true) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one);
+  R.ReduceMergeIterative(R.start, d1.merge);
+}
+
+
+TEST(CDiamondReduce_false) {
+  ControlReducerTester R;
+  Diamond d2(R, R.zero);
+  R.ReduceMergeIterative(R.start, d2.merge);
+}
+
+
+TEST(CChainedDiamondsReduce_true_false) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one);
+  Diamond d2(R, R.zero);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(R.start, d2.merge);
+}
+
+
+TEST(CChainedDiamondsReduce_x_false) {
+  ControlReducerTester R;
+  Diamond d1(R, R.p0);
+  Diamond d2(R, R.zero);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(d1.merge, d2.merge);
+}
+
+
+TEST(CChainedDiamondsReduce_false_x) {
+  ControlReducerTester R;
+  Diamond d1(R, R.zero);
+  Diamond d2(R, R.p0);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(d2.merge, d2.merge);
+  CheckInputs(d2.branch, R.p0, R.start);
+}
+
+
+TEST(CChainedDiamondsReduce_phi1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.zero, R.one, R.zero);  // foldable branch, phi.
+  Diamond d2(R, d1.phi);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(R.start, d2.merge);
+}
+
+
+TEST(CChainedDiamondsReduce_phi2) {
+  ControlReducerTester R;
+  Diamond d1(R, R.p0, R.one, R.one);  // redundant phi.
+  Diamond d2(R, d1.phi);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(d1.merge, d2.merge);
+}
+
+
+TEST(CNestedDiamondsReduce_true_true_false) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one);
+  Diamond d2(R, R.zero);
+  d2.nest(d1, true);
+
+  R.ReduceMergeIterative(R.start, d1.merge);
+}
+
+
+TEST(CNestedDiamondsReduce_false_true_false) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one);
+  Diamond d2(R, R.zero);
+  d2.nest(d1, false);
+
+  R.ReduceMergeIterative(R.start, d1.merge);
+}
+
+
+TEST(CNestedDiamonds_xyz) {
+  ControlReducerTester R;
+
+  for (int a = 0; a < 2; a++) {
+    for (int b = 0; b < 2; b++) {
+      for (int c = 0; c < 2; c++) {
+        Diamond d1(R, R.jsgraph.Int32Constant(a));
+        Diamond d2(R, R.jsgraph.Int32Constant(b));
+        d2.nest(d1, c);
+
+        R.ReduceMergeIterative(R.start, d1.merge);
+      }
+    }
+  }
+}
+
+
+TEST(CDeadLoop1) {
+  ControlReducerTester R;
+
+  Node* loop = R.graph.NewNode(R.common.Loop(1), R.start);
+  Branch b(R, R.p0, loop);
+  loop->ReplaceInput(0, b.if_true);  // loop is not connected to start.
+  Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, b.if_false);
+  R.ReduceMergeIterative(R.start, merge);
+  CHECK(b.if_true->IsDead());
+  CHECK(b.if_false->IsDead());
+}
+
+
+TEST(CDeadLoop2) {
+  ControlReducerTester R;
+
+  While w(R, R.p0);
+  Diamond d(R, R.zero);
+  // if (0) { while (p0) ; } else { }
+  w.branch->ReplaceInput(1, d.if_true);
+  d.merge->ReplaceInput(0, w.exit);
+
+  R.ReduceMergeIterative(R.start, d.merge);
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+}
+
+
+TEST(CNonTermLoop1) {
+  ControlReducerTester R;
+  Node* loop =
+      R.SetSelfReferences(R.graph.NewNode(R.common.Loop(2), R.start, R.self));
+  R.ReduceGraph();
+  Node* end = R.graph.end();
+  CheckLoop(loop, R.start, loop);
+  Node* merge = end->InputAt(0);
+  CheckMerge(merge, R.start, loop);
+}
+
+
+TEST(CNonTermLoop2) {
+  ControlReducerTester R;
+  Diamond d(R, R.p0);
+  Node* loop = R.SetSelfReferences(
+      R.graph.NewNode(R.common.Loop(2), d.if_false, R.self));
+  d.merge->ReplaceInput(1, R.dead);
+  Node* end = R.graph.end();
+  end->ReplaceInput(0, d.merge);
+  R.ReduceGraph();
+  CHECK_EQ(end, R.graph.end());
+  CheckLoop(loop, d.if_false, loop);
+  Node* merge = end->InputAt(0);
+  CheckMerge(merge, d.if_true, loop);
+}
+
+
+TEST(NonTermLoop3) {
+  ControlReducerTester R;
+  Node* loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start);
+  Branch b(R, R.one, loop);
+  loop->ReplaceInput(1, b.if_true);
+  Node* end = R.graph.end();
+  end->ReplaceInput(0, b.if_false);
+
+  R.ReduceGraph();
+
+  CHECK_EQ(end, R.graph.end());
+  CheckInputs(end, loop);
+  CheckInputs(loop, R.start, loop);
+}
+
+
+TEST(CNonTermLoop_terminate1) {
+  ControlReducerTester R;
+  Node* loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start);
+  Node* effect = R.SetSelfReferences(
+      R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop));
+  Branch b(R, R.one, loop);
+  loop->ReplaceInput(1, b.if_true);
+  Node* end = R.graph.end();
+  end->ReplaceInput(0, b.if_false);
+
+  R.ReduceGraph();
+
+  CHECK_EQ(end, R.graph.end());
+  CheckLoop(loop, R.start, loop);
+  Node* terminate = end->InputAt(0);
+  CHECK_EQ(IrOpcode::kTerminate, terminate->opcode());
+  CHECK_EQ(2, terminate->InputCount());
+  CHECK_EQ(1, terminate->op()->EffectInputCount());
+  CHECK_EQ(1, terminate->op()->ControlInputCount());
+  CheckInputs(terminate, effect, loop);
+}
+
+
+TEST(CNonTermLoop_terminate2) {
+  ControlReducerTester R;
+  Node* loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start);
+  Node* effect1 = R.SetSelfReferences(
+      R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop));
+  Node* effect2 = R.SetSelfReferences(
+      R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop));
+  Branch b(R, R.one, loop);
+  loop->ReplaceInput(1, b.if_true);
+  Node* end = R.graph.end();
+  end->ReplaceInput(0, b.if_false);
+
+  R.ReduceGraph();
+
+  CheckLoop(loop, R.start, loop);
+  CHECK_EQ(end, R.graph.end());
+  Node* terminate = end->InputAt(0);
+  CHECK_EQ(IrOpcode::kTerminate, terminate->opcode());
+  CHECK_EQ(3, terminate->InputCount());
+  CHECK_EQ(2, terminate->op()->EffectInputCount());
+  CHECK_EQ(1, terminate->op()->ControlInputCount());
+  Node* e0 = terminate->InputAt(0);
+  Node* e1 = terminate->InputAt(1);
+  CHECK(e0 == effect1 || e1 == effect1);
+  CHECK(e0 == effect2 || e1 == effect2);
+  CHECK_EQ(loop, terminate->InputAt(2));
+}
+
+
+TEST(CNonTermLoop_terminate_m1) {
+  ControlReducerTester R;
+  Node* loop =
+      R.SetSelfReferences(R.graph.NewNode(R.common.Loop(2), R.start, R.self));
+  Node* effect = R.SetSelfReferences(
+      R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop));
+  R.ReduceGraph();
+  Node* end = R.graph.end();
+  CHECK_EQ(R.start, loop->InputAt(0));
+  CHECK_EQ(loop, loop->InputAt(1));
+  Node* merge = end->InputAt(0);
+  CHECK_EQ(IrOpcode::kMerge, merge->opcode());
+  CHECK_EQ(2, merge->InputCount());
+  CHECK_EQ(2, merge->op()->ControlInputCount());
+  CHECK_EQ(R.start, merge->InputAt(0));
+
+  Node* terminate = merge->InputAt(1);
+  CHECK_EQ(IrOpcode::kTerminate, terminate->opcode());
+  CHECK_EQ(2, terminate->InputCount());
+  CHECK_EQ(1, terminate->op()->EffectInputCount());
+  CHECK_EQ(1, terminate->op()->ControlInputCount());
+  CHECK_EQ(effect, terminate->InputAt(0));
+  CHECK_EQ(loop, terminate->InputAt(1));
+}
+
+
+TEST(CNonTermLoop_big1) {
+  ControlReducerTester R;
+  Branch b1(R, R.p0);
+  Node* rt = R.graph.NewNode(R.common.Return(), R.one, R.start, b1.if_true);
+
+  Branch b2(R, R.p0, b1.if_false);
+  Node* rf = R.graph.NewNode(R.common.Return(), R.zero, R.start, b2.if_true);
+  Node* loop = R.SetSelfReferences(
+      R.graph.NewNode(R.common.Loop(2), b2.if_false, R.self));
+  Node* merge = R.graph.NewNode(R.common.Merge(2), rt, rf);
+  R.end->ReplaceInput(0, merge);
+
+  R.ReduceGraph();
+
+  CheckInputs(R.end, merge);
+  CheckInputs(merge, rt, rf, loop);
+  CheckInputs(loop, b2.if_false, loop);
+}
+
+
+TEST(CNonTermLoop_big2) {
+  ControlReducerTester R;
+  Branch b1(R, R.p0);
+  Node* rt = R.graph.NewNode(R.common.Return(), R.one, R.start, b1.if_true);
+
+  Branch b2(R, R.zero, b1.if_false);
+  Node* rf = R.graph.NewNode(R.common.Return(), R.zero, R.start, b2.if_true);
+  Node* loop = R.SetSelfReferences(
+      R.graph.NewNode(R.common.Loop(2), b2.if_false, R.self));
+  Node* merge = R.graph.NewNode(R.common.Merge(2), rt, rf);
+  R.end->ReplaceInput(0, merge);
+
+  R.ReduceGraph();
+
+  Node* new_merge = R.end->InputAt(0);  // old merge was reduced.
+  CHECK_NE(merge, new_merge);
+  CheckInputs(new_merge, rt, loop);
+  CheckInputs(loop, b1.if_false, loop);
+  CHECK(merge->IsDead());
+  CHECK(rf->IsDead());
+  CHECK(b2.if_true->IsDead());
+}
+
+
+TEST(Return1) {
+  ControlReducerTester R;
+  Node* ret = R.Return(R.one, R.start, R.start);
+  R.ReduceGraph();
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.one, R.start, R.start);
+}
+
+
+TEST(Return2) {
+  ControlReducerTester R;
+  Diamond d(R, R.one);
+  Node* ret = R.Return(R.half, R.start, d.merge);
+  R.ReduceGraph();
+  CHECK(d.branch->IsDead());
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+  CHECK(d.merge->IsDead());
+
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.half, R.start, R.start);
+}
+
+
+TEST(Return_true1) {
+  ControlReducerTester R;
+  Diamond d(R, R.one, R.half, R.zero);
+  Node* ret = R.Return(d.phi, R.start, d.merge);
+  R.ReduceGraph();
+  CHECK(d.branch->IsDead());
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+  CHECK(d.merge->IsDead());
+  CHECK(d.phi->IsDead());
+
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.half, R.start, R.start);
+}
+
+
+TEST(Return_false1) {
+  ControlReducerTester R;
+  Diamond d(R, R.zero, R.one, R.half);
+  Node* ret = R.Return(d.phi, R.start, d.merge);
+  R.ReduceGraph();
+  CHECK(d.branch->IsDead());
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+  CHECK(d.merge->IsDead());
+  CHECK(d.phi->IsDead());
+
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.half, R.start, R.start);
+}
+
+
+void CheckDeadDiamond(Diamond& d) {
+  CHECK(d.branch->IsDead());
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+  CHECK(d.merge->IsDead());
+  if (d.phi != NULL) CHECK(d.phi->IsDead());
+}
+
+
+void CheckLiveDiamond(Diamond& d, bool live_phi = true) {
+  CheckInputs(d.merge, d.if_true, d.if_false);
+  CheckInputs(d.if_true, d.branch);
+  CheckInputs(d.if_false, d.branch);
+  if (d.phi != NULL) {
+    if (live_phi) {
+      CHECK_EQ(3, d.phi->InputCount());
+      CHECK_EQ(d.merge, d.phi->InputAt(2));
+    } else {
+      CHECK(d.phi->IsDead());
+    }
+  }
+}
+
+
+TEST(Return_effect1) {
+  ControlReducerTester R;
+  Diamond d(R, R.one);
+  Node* e1 = R.jsgraph.Float64Constant(-100.1);
+  Node* e2 = R.jsgraph.Float64Constant(+100.1);
+  Node* effect = R.graph.NewNode(R.common.EffectPhi(2), e1, e2, d.merge);
+  Node* ret = R.Return(R.p0, effect, d.merge);
+  R.ReduceGraph();
+  CheckDeadDiamond(d);
+  CHECK(effect->IsDead());
+
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.p0, e1, R.start);
+}
+
+
+TEST(Return_nested_diamonds1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.p0, R.one, R.zero);
+  Diamond d2(R, R.p0);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // nothing should happen.
+
+  CheckInputs(ret, d1.phi, R.start, d1.merge);
+  CheckInputs(d1.phi, R.one, R.zero, d1.merge);
+  CheckInputs(d1.merge, d2.merge, d3.merge);
+  CheckLiveDiamond(d2);
+  CheckLiveDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one, R.one, R.zero);
+  Diamond d2(R, R.p0);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true.
+
+  CheckInputs(ret, R.one, R.start, d2.merge);
+  CheckInputs(d2.branch, R.p0, R.start);
+  CheckDeadDiamond(d1);
+  CheckLiveDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_false1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.zero, R.one, R.zero);
+  Diamond d2(R, R.p0);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded false.
+
+  CheckInputs(ret, R.zero, R.start, d3.merge);
+  CheckInputs(d3.branch, R.p0, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckLiveDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true_true1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one, R.one, R.zero);
+  Diamond d2(R, R.one);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 and d2 both get folded true.
+
+  CheckInputs(ret, R.one, R.start, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true_false1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one, R.one, R.zero);
+  Diamond d2(R, R.zero);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true and d2 gets folded false.
+
+  CheckInputs(ret, R.one, R.start, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds2) {
+  ControlReducerTester R;
+  Node* x2 = R.jsgraph.Float64Constant(11.1);
+  Node* y2 = R.jsgraph.Float64Constant(22.2);
+  Node* x3 = R.jsgraph.Float64Constant(33.3);
+  Node* y3 = R.jsgraph.Float64Constant(44.4);
+
+  Diamond d2(R, R.p0, x2, y2);
+  Diamond d3(R, R.p0, x3, y3);
+  Diamond d1(R, R.p0, d2.phi, d3.phi);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // nothing should happen.
+
+  CheckInputs(ret, d1.phi, R.start, d1.merge);
+  CheckInputs(d1.phi, d2.phi, d3.phi, d1.merge);
+  CheckInputs(d1.merge, d2.merge, d3.merge);
+  CheckLiveDiamond(d2);
+  CheckLiveDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true2) {
+  ControlReducerTester R;
+  Node* x2 = R.jsgraph.Float64Constant(11.1);
+  Node* y2 = R.jsgraph.Float64Constant(22.2);
+  Node* x3 = R.jsgraph.Float64Constant(33.3);
+  Node* y3 = R.jsgraph.Float64Constant(44.4);
+
+  Diamond d2(R, R.p0, x2, y2);
+  Diamond d3(R, R.p0, x3, y3);
+  Diamond d1(R, R.one, d2.phi, d3.phi);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true.
+
+  CheckInputs(ret, d2.phi, R.start, d2.merge);
+  CheckInputs(d2.branch, R.p0, R.start);
+  CheckDeadDiamond(d1);
+  CheckLiveDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true_true2) {
+  ControlReducerTester R;
+  Node* x2 = R.jsgraph.Float64Constant(11.1);
+  Node* y2 = R.jsgraph.Float64Constant(22.2);
+  Node* x3 = R.jsgraph.Float64Constant(33.3);
+  Node* y3 = R.jsgraph.Float64Constant(44.4);
+
+  Diamond d2(R, R.one, x2, y2);
+  Diamond d3(R, R.p0, x3, y3);
+  Diamond d1(R, R.one, d2.phi, d3.phi);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true.
+
+  CheckInputs(ret, x2, R.start, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true_false2) {
+  ControlReducerTester R;
+  Node* x2 = R.jsgraph.Float64Constant(11.1);
+  Node* y2 = R.jsgraph.Float64Constant(22.2);
+  Node* x3 = R.jsgraph.Float64Constant(33.3);
+  Node* y3 = R.jsgraph.Float64Constant(44.4);
+
+  Diamond d2(R, R.zero, x2, y2);
+  Diamond d3(R, R.p0, x3, y3);
+  Diamond d1(R, R.one, d2.phi, d3.phi);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true.
+
+  CheckInputs(ret, y2, R.start, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckDeadDiamond(d3);
+}
diff --git a/test/cctest/compiler/test-gap-resolver.cc b/test/cctest/compiler/test-gap-resolver.cc
index 6239f2a..ea6f4ee 100644
--- a/test/cctest/compiler/test-gap-resolver.cc
+++ b/test/cctest/compiler/test-gap-resolver.cc
@@ -58,13 +58,16 @@
     return Value(op->kind(), op->index());
   }
 
-  friend OStream& operator<<(OStream& os, const InterpreterState& is) {
+  friend std::ostream& operator<<(std::ostream& os,
+                                  const InterpreterState& is) {
     for (OperandMap::const_iterator it = is.values_.begin();
          it != is.values_.end(); ++it) {
       if (it != is.values_.begin()) os << " ";
       InstructionOperand source(it->first.first, it->first.second);
       InstructionOperand destination(it->second.first, it->second.second);
-      os << MoveOperands(&source, &destination);
+      MoveOperands mo(&source, &destination);
+      PrintableMoveOperands pmo = {RegisterConfiguration::ArchDefault(), &mo};
+      os << pmo;
     }
     return os;
   }
diff --git a/test/cctest/compiler/test-graph-reducer.cc b/test/cctest/compiler/test-graph-reducer.cc
index eabfd22..70b57b9 100644
--- a/test/cctest/compiler/test-graph-reducer.cc
+++ b/test/cctest/compiler/test-graph-reducer.cc
@@ -5,7 +5,6 @@
 #include "src/v8.h"
 
 #include "graph-tester.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph-reducer.h"
 
 using namespace v8::internal;
@@ -21,15 +20,15 @@
 const uint8_t OPCODE_C1 = 31;
 const uint8_t OPCODE_C2 = 32;
 
-static SimpleOperator OPA0(OPCODE_A0, Operator::kNoWrite, 0, 0, "opa0");
-static SimpleOperator OPA1(OPCODE_A1, Operator::kNoWrite, 1, 0, "opa1");
-static SimpleOperator OPA2(OPCODE_A2, Operator::kNoWrite, 2, 0, "opa2");
-static SimpleOperator OPB0(OPCODE_B0, Operator::kNoWrite, 0, 0, "opa0");
-static SimpleOperator OPB1(OPCODE_B1, Operator::kNoWrite, 1, 0, "opa1");
-static SimpleOperator OPB2(OPCODE_B2, Operator::kNoWrite, 2, 0, "opa2");
-static SimpleOperator OPC0(OPCODE_C0, Operator::kNoWrite, 0, 0, "opc0");
-static SimpleOperator OPC1(OPCODE_C1, Operator::kNoWrite, 1, 0, "opc1");
-static SimpleOperator OPC2(OPCODE_C2, Operator::kNoWrite, 2, 0, "opc2");
+static Operator OPA0(OPCODE_A0, Operator::kNoWrite, "opa0", 0, 0, 0, 0, 0, 0);
+static Operator OPA1(OPCODE_A1, Operator::kNoWrite, "opa1", 1, 0, 0, 0, 0, 0);
+static Operator OPA2(OPCODE_A2, Operator::kNoWrite, "opa2", 2, 0, 0, 0, 0, 0);
+static Operator OPB0(OPCODE_B0, Operator::kNoWrite, "opa0", 0, 0, 0, 0, 0, 0);
+static Operator OPB1(OPCODE_B1, Operator::kNoWrite, "opa1", 1, 0, 0, 0, 0, 0);
+static Operator OPB2(OPCODE_B2, Operator::kNoWrite, "opa2", 2, 0, 0, 0, 0, 0);
+static Operator OPC0(OPCODE_C0, Operator::kNoWrite, "opc0", 0, 0, 0, 0, 0, 0);
+static Operator OPC1(OPCODE_C1, Operator::kNoWrite, "opc1", 1, 0, 0, 0, 0, 0);
+static Operator OPC2(OPCODE_C2, Operator::kNoWrite, "opc2", 2, 0, 0, 0, 0, 0);
 
 
 // Replaces all "A" operators with "B" operators without creating new nodes.
@@ -202,7 +201,7 @@
   Node* end = graph.NewNode(&OPA1, n1);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   ReducerRecorder recorder(graph.zone());
   reducer.AddReducer(&recorder);
   reducer.ReduceGraph();
@@ -220,7 +219,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   ReducerRecorder recorder(graph.zone());
   reducer.AddReducer(&recorder);
   reducer.ReduceGraph();
@@ -238,7 +237,7 @@
   Node* end = graph.NewNode(&OPA1, n1);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   InPlaceABReducer r;
   reducer.AddReducer(&r);
 
@@ -263,7 +262,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   InPlaceABReducer r;
   reducer.AddReducer(&r);
 
@@ -293,7 +292,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   NewABReducer r(&graph);
   reducer.AddReducer(&r);
 
@@ -330,7 +329,7 @@
   graph.SetEnd(end);
   CHECK_EQ(1, graph.NodeCount());
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   A0Wrapper r(&graph);
   reducer.AddReducer(&r);
 
@@ -352,7 +351,7 @@
   graph.SetEnd(end);
   CHECK_EQ(1, graph.NodeCount());
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   B0Wrapper r(&graph);
   reducer.AddReducer(&r);
 
@@ -379,7 +378,7 @@
   Node* end = graph.NewNode(&OPA1, n1);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   A1Forwarder r;
   reducer.AddReducer(&r);
 
@@ -403,7 +402,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   A1Forwarder r;
   reducer.AddReducer(&r);
 
@@ -434,7 +433,7 @@
     }
     graph.SetEnd(end);
 
-    GraphReducer reducer(&graph);
+    GraphReducer reducer(&graph, graph.zone());
     A1Forwarder r;
     reducer.AddReducer(&r);
 
@@ -458,7 +457,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   InPlaceABReducer r;
   B1Forwarder f;
   reducer.AddReducer(&r);
@@ -501,7 +500,7 @@
 
     graph.SetEnd(end);
 
-    GraphReducer reducer(&graph);
+    GraphReducer reducer(&graph, graph.zone());
     reducer.AddReducer(&r);
 
     int before = graph.NodeCount();
@@ -560,7 +559,7 @@
 
         GenDAG(&graph, p3, p2, p1);
 
-        GraphReducer reducer(&graph);
+        GraphReducer reducer(&graph, graph.zone());
         AB2Sorter r1;
         A1Forwarder r2;
         InPlaceABReducer r3;
@@ -599,7 +598,7 @@
     Node* end = graph.NewNode(&OPA1, n1);
     graph.SetEnd(end);
 
-    GraphReducer reducer(&graph);
+    GraphReducer reducer(&graph, graph.zone());
     InPlaceABReducer abr;
     InPlaceBCReducer bcr;
     if (i == 0) {
@@ -621,41 +620,3 @@
     }
   }
 }
-
-
-// Tests that a reducer is only applied once.
-class OneTimeReducer : public Reducer {
- public:
-  OneTimeReducer(Reducer* reducer, Zone* zone)
-      : reducer_(reducer),
-        nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)) {}
-  virtual Reduction Reduce(Node* node) {
-    CHECK_EQ(0, static_cast<int>(nodes_.count(node)));
-    nodes_.insert(node);
-    return reducer_->Reduce(node);
-  }
-  Reducer* reducer_;
-  NodeSet nodes_;
-};
-
-
-TEST(OneTimeReduce1) {
-  GraphTester graph;
-
-  Node* n1 = graph.NewNode(&OPA0);
-  Node* end = graph.NewNode(&OPA1, n1);
-  graph.SetEnd(end);
-
-  GraphReducer reducer(&graph);
-  InPlaceABReducer r;
-  OneTimeReducer once(&r, graph.zone());
-  reducer.AddReducer(&once);
-
-  // Tests A* => B* with in-place updates. Should only be applied once.
-  int before = graph.NodeCount();
-  reducer.ReduceGraph();
-  CHECK_EQ(before, graph.NodeCount());
-  CHECK_EQ(&OPB0, n1->op());
-  CHECK_EQ(&OPB1, end->op());
-  CHECK_EQ(n1, end->InputAt(0));
-}
diff --git a/test/cctest/compiler/test-graph-visualizer.cc b/test/cctest/compiler/test-graph-visualizer.cc
new file mode 100644
index 0000000..ce3e6b7
--- /dev/null
+++ b/test/cctest/compiler/test-graph-visualizer.cc
@@ -0,0 +1,90 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/graph-visualizer.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/node.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/schedule.h"
+#include "src/compiler/scheduler.h"
+#include "src/compiler/verifier.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+TEST(NodeWithNullInputReachableFromEnd) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(0));
+  graph.SetStart(start);
+  Node* k = graph.NewNode(common.Int32Constant(0));
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 1), k, start);
+  phi->ReplaceInput(0, NULL);
+  graph.SetEnd(phi);
+
+  OFStream os(stdout);
+  os << AsDOT(graph);
+  os << AsJSON(graph);
+}
+
+
+TEST(NodeWithNullControlReachableFromEnd) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(0));
+  graph.SetStart(start);
+  Node* k = graph.NewNode(common.Int32Constant(0));
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 1), k, start);
+  phi->ReplaceInput(1, NULL);
+  graph.SetEnd(phi);
+
+  OFStream os(stdout);
+  os << AsDOT(graph);
+  os << AsJSON(graph);
+}
+
+
+TEST(NodeWithNullInputReachableFromStart) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(0));
+  graph.SetStart(start);
+  Node* k = graph.NewNode(common.Int32Constant(0));
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 1), k, start);
+  phi->ReplaceInput(0, NULL);
+  graph.SetEnd(start);
+
+  OFStream os(stdout);
+  os << AsDOT(graph);
+  os << AsJSON(graph);
+}
+
+
+TEST(NodeWithNullControlReachableFromStart) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(0));
+  graph.SetStart(start);
+  Node* merge = graph.NewNode(common.Merge(2), start, start);
+  merge->ReplaceInput(1, NULL);
+  graph.SetEnd(merge);
+
+  OFStream os(stdout);
+  os << AsDOT(graph);
+  os << AsJSON(graph);
+}
diff --git a/test/cctest/compiler/test-instruction.cc b/test/cctest/compiler/test-instruction.cc
index a9feaac..294812f 100644
--- a/test/cctest/compiler/test-instruction.cc
+++ b/test/cctest/compiler/test-instruction.cc
@@ -31,12 +31,11 @@
         graph(zone()),
         schedule(zone()),
         info(static_cast<HydrogenCodeStub*>(NULL), main_isolate()),
-        linkage(&info),
+        linkage(zone(), &info),
         common(zone()),
+        machine(zone()),
         code(NULL) {}
 
-  ~InstructionTester() { delete code; }
-
   Isolate* isolate;
   Graph graph;
   Schedule schedule;
@@ -51,10 +50,12 @@
   void allocCode() {
     if (schedule.rpo_order()->size() == 0) {
       // Compute the RPO order.
-      Scheduler::ComputeSpecialRPO(&schedule);
+      Scheduler::ComputeSpecialRPO(main_zone(), &schedule);
       DCHECK(schedule.rpo_order()->size() > 0);
     }
-    code = new TestInstrSeq(&linkage, &graph, &schedule);
+    InstructionBlocks* instruction_blocks =
+        TestInstrSeq::InstructionBlocksFor(main_zone(), &schedule);
+    code = new (main_zone()) TestInstrSeq(main_zone(), instruction_blocks);
   }
 
   Node* Int32Constant(int32_t val) {
@@ -81,10 +82,10 @@
     return node;
   }
 
-  int NewInstr(BasicBlock* block) {
+  int NewInstr() {
     InstructionCode opcode = static_cast<InstructionCode>(110);
     TestInstr* instr = TestInstr::New(zone(), opcode);
-    return code->AddInstruction(instr, block);
+    return code->AddInstruction(instr);
   }
 
   UnallocatedOperand* NewUnallocated(int vreg) {
@@ -93,6 +94,21 @@
     unallocated->set_virtual_register(vreg);
     return unallocated;
   }
+
+  InstructionBlock* BlockAt(BasicBlock* block) {
+    return code->InstructionBlockAt(block->GetRpoNumber());
+  }
+  BasicBlock* GetBasicBlock(int instruction_index) {
+    const InstructionBlock* block =
+        code->GetInstructionBlock(instruction_index);
+    return schedule.rpo_order()->at(block->rpo_number().ToSize());
+  }
+  int first_instruction_index(BasicBlock* block) {
+    return BlockAt(block)->first_instruction_index();
+  }
+  int last_instruction_index(BasicBlock* block) {
+    return BlockAt(block)->last_instruction_index();
+  }
 };
 
 
@@ -112,17 +128,16 @@
 
   R.allocCode();
 
-  CHECK_EQ(R.graph.NodeCount(), R.code->ValueCount());
-
   BasicBlockVector* blocks = R.schedule.rpo_order();
-  CHECK_EQ(static_cast<int>(blocks->size()), R.code->BasicBlockCount());
+  CHECK_EQ(static_cast<int>(blocks->size()), R.code->InstructionBlockCount());
 
   int index = 0;
   for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end();
        i++, index++) {
     BasicBlock* block = *i;
-    CHECK_EQ(block, R.code->BlockAt(index));
-    CHECK_EQ(-1, R.code->GetLoopEnd(block));
+    CHECK_EQ(block->rpo_number(), R.BlockAt(block)->rpo_number().ToInt());
+    CHECK_EQ(block->id().ToInt(), R.BlockAt(block)->id().ToInt());
+    CHECK_EQ(NULL, block->loop_end());
   }
 }
 
@@ -141,47 +156,47 @@
 
   R.allocCode();
 
-  R.code->StartBlock(b0);
-  int i0 = R.NewInstr(b0);
-  int i1 = R.NewInstr(b0);
-  R.code->EndBlock(b0);
-  R.code->StartBlock(b1);
-  int i2 = R.NewInstr(b1);
-  int i3 = R.NewInstr(b1);
-  int i4 = R.NewInstr(b1);
-  int i5 = R.NewInstr(b1);
-  R.code->EndBlock(b1);
-  R.code->StartBlock(b2);
-  int i6 = R.NewInstr(b2);
-  int i7 = R.NewInstr(b2);
-  int i8 = R.NewInstr(b2);
-  R.code->EndBlock(b2);
-  R.code->StartBlock(b3);
-  R.code->EndBlock(b3);
+  R.code->StartBlock(b0->GetRpoNumber());
+  int i0 = R.NewInstr();
+  int i1 = R.NewInstr();
+  R.code->EndBlock(b0->GetRpoNumber());
+  R.code->StartBlock(b1->GetRpoNumber());
+  int i2 = R.NewInstr();
+  int i3 = R.NewInstr();
+  int i4 = R.NewInstr();
+  int i5 = R.NewInstr();
+  R.code->EndBlock(b1->GetRpoNumber());
+  R.code->StartBlock(b2->GetRpoNumber());
+  int i6 = R.NewInstr();
+  int i7 = R.NewInstr();
+  int i8 = R.NewInstr();
+  R.code->EndBlock(b2->GetRpoNumber());
+  R.code->StartBlock(b3->GetRpoNumber());
+  R.code->EndBlock(b3->GetRpoNumber());
 
-  CHECK_EQ(b0, R.code->GetBasicBlock(i0));
-  CHECK_EQ(b0, R.code->GetBasicBlock(i1));
+  CHECK_EQ(b0, R.GetBasicBlock(i0));
+  CHECK_EQ(b0, R.GetBasicBlock(i1));
 
-  CHECK_EQ(b1, R.code->GetBasicBlock(i2));
-  CHECK_EQ(b1, R.code->GetBasicBlock(i3));
-  CHECK_EQ(b1, R.code->GetBasicBlock(i4));
-  CHECK_EQ(b1, R.code->GetBasicBlock(i5));
+  CHECK_EQ(b1, R.GetBasicBlock(i2));
+  CHECK_EQ(b1, R.GetBasicBlock(i3));
+  CHECK_EQ(b1, R.GetBasicBlock(i4));
+  CHECK_EQ(b1, R.GetBasicBlock(i5));
 
-  CHECK_EQ(b2, R.code->GetBasicBlock(i6));
-  CHECK_EQ(b2, R.code->GetBasicBlock(i7));
-  CHECK_EQ(b2, R.code->GetBasicBlock(i8));
+  CHECK_EQ(b2, R.GetBasicBlock(i6));
+  CHECK_EQ(b2, R.GetBasicBlock(i7));
+  CHECK_EQ(b2, R.GetBasicBlock(i8));
 
-  CHECK_EQ(b0, R.code->GetBasicBlock(b0->first_instruction_index()));
-  CHECK_EQ(b0, R.code->GetBasicBlock(b0->last_instruction_index()));
+  CHECK_EQ(b0, R.GetBasicBlock(R.first_instruction_index(b0)));
+  CHECK_EQ(b0, R.GetBasicBlock(R.last_instruction_index(b0)));
 
-  CHECK_EQ(b1, R.code->GetBasicBlock(b1->first_instruction_index()));
-  CHECK_EQ(b1, R.code->GetBasicBlock(b1->last_instruction_index()));
+  CHECK_EQ(b1, R.GetBasicBlock(R.first_instruction_index(b1)));
+  CHECK_EQ(b1, R.GetBasicBlock(R.last_instruction_index(b1)));
 
-  CHECK_EQ(b2, R.code->GetBasicBlock(b2->first_instruction_index()));
-  CHECK_EQ(b2, R.code->GetBasicBlock(b2->last_instruction_index()));
+  CHECK_EQ(b2, R.GetBasicBlock(R.first_instruction_index(b2)));
+  CHECK_EQ(b2, R.GetBasicBlock(R.last_instruction_index(b2)));
 
-  CHECK_EQ(b3, R.code->GetBasicBlock(b3->first_instruction_index()));
-  CHECK_EQ(b3, R.code->GetBasicBlock(b3->last_instruction_index()));
+  CHECK_EQ(b3, R.GetBasicBlock(R.first_instruction_index(b3)));
+  CHECK_EQ(b3, R.GetBasicBlock(R.last_instruction_index(b3)));
 }
 
 
@@ -194,10 +209,10 @@
   R.allocCode();
   TestInstr* i0 = TestInstr::New(R.zone(), 100);
   TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
-  R.code->StartBlock(b0);
-  R.code->AddInstruction(i0, b0);
-  R.code->AddInstruction(g, b0);
-  R.code->EndBlock(b0);
+  R.code->StartBlock(b0->GetRpoNumber());
+  R.code->AddInstruction(i0);
+  R.code->AddInstruction(g);
+  R.code->EndBlock(b0->GetRpoNumber());
 
   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
 
@@ -221,17 +236,17 @@
   R.allocCode();
   TestInstr* i0 = TestInstr::New(R.zone(), 100);
   TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
-  R.code->StartBlock(b0);
-  R.code->AddInstruction(i0, b0);
-  R.code->AddInstruction(g, b0);
-  R.code->EndBlock(b0);
+  R.code->StartBlock(b0->GetRpoNumber());
+  R.code->AddInstruction(i0);
+  R.code->AddInstruction(g);
+  R.code->EndBlock(b0->GetRpoNumber());
 
   TestInstr* i1 = TestInstr::New(R.zone(), 102);
   TestInstr* g1 = TestInstr::New(R.zone(), 104)->MarkAsControl();
-  R.code->StartBlock(b1);
-  R.code->AddInstruction(i1, b1);
-  R.code->AddInstruction(g1, b1);
-  R.code->EndBlock(b1);
+  R.code->StartBlock(b1->GetRpoNumber());
+  R.code->AddInstruction(i1);
+  R.code->AddInstruction(g1);
+  R.code->EndBlock(b1->GetRpoNumber());
 
   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
 
@@ -262,10 +277,10 @@
   R.allocCode();
   TestInstr* i0 = TestInstr::New(R.zone(), 100);
   TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
-  R.code->StartBlock(b0);
-  R.code->AddInstruction(i0, b0);
-  R.code->AddInstruction(g, b0);
-  R.code->EndBlock(b0);
+  R.code->StartBlock(b0->GetRpoNumber());
+  R.code->AddInstruction(i0);
+  R.code->AddInstruction(g);
+  R.code->EndBlock(b0->GetRpoNumber());
 
   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
 
diff --git a/test/cctest/compiler/test-js-constant-cache.cc b/test/cctest/compiler/test-js-constant-cache.cc
index eb0975e..8588f66 100644
--- a/test/cctest/compiler/test-js-constant-cache.cc
+++ b/test/cctest/compiler/test-js-constant-cache.cc
@@ -4,6 +4,7 @@
 
 #include "src/v8.h"
 
+#include "src/assembler.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/typer.h"
@@ -20,8 +21,8 @@
       : main_graph_(zone),
         main_common_(zone),
         main_javascript_(zone),
-        main_typer_(zone),
-        main_machine_() {}
+        main_typer_(&main_graph_, MaybeHandle<Context>()),
+        main_machine_(zone) {}
   Graph main_graph_;
   CommonOperatorBuilder main_common_;
   JSOperatorBuilder main_javascript_;
@@ -30,14 +31,19 @@
 };
 
 
+// TODO(dcarney): JSConstantCacheTester inherits from JSGraph???
 class JSConstantCacheTester : public HandleAndZoneScope,
                               public JSCacheTesterHelper,
                               public JSGraph {
  public:
   JSConstantCacheTester()
       : JSCacheTesterHelper(main_zone()),
-        JSGraph(&main_graph_, &main_common_, &main_javascript_, &main_typer_,
-                &main_machine_) {}
+        JSGraph(&main_graph_, &main_common_, &main_javascript_,
+                &main_machine_) {
+    main_graph_.SetStart(main_graph_.NewNode(common()->Start(0)));
+    main_graph_.SetEnd(main_graph_.NewNode(common()->End()));
+    main_typer_.Run();
+  }
 
   Type* upper(Node* node) { return NodeProperties::GetBounds(node).upper; }
 
@@ -227,7 +233,7 @@
   FOR_FLOAT64_INPUTS(i) {
     double value = *i;
     Node* node = T.Constant(value);
-    CHECK(T.upper(node)->Equals(Type::Of(value, T.main_zone())));
+    CHECK(T.upper(node)->Is(Type::Of(value, T.main_zone())));
   }
 }
 
@@ -289,3 +295,180 @@
 TEST(ExternalReferences) {
   // TODO(titzer): test canonicalization of external references.
 }
+
+
+static bool Contains(NodeVector* nodes, Node* n) {
+  for (size_t i = 0; i < nodes->size(); i++) {
+    if (nodes->at(i) == n) return true;
+  }
+  return false;
+}
+
+
+static void CheckGetCachedNodesContains(JSConstantCacheTester* T, Node* n) {
+  NodeVector nodes(T->main_zone());
+  T->GetCachedNodes(&nodes);
+  CHECK(Contains(&nodes, n));
+}
+
+
+TEST(JSGraph_GetCachedNodes1) {
+  JSConstantCacheTester T;
+  CheckGetCachedNodesContains(&T, T.TrueConstant());
+  CheckGetCachedNodesContains(&T, T.UndefinedConstant());
+  CheckGetCachedNodesContains(&T, T.TheHoleConstant());
+  CheckGetCachedNodesContains(&T, T.TrueConstant());
+  CheckGetCachedNodesContains(&T, T.FalseConstant());
+  CheckGetCachedNodesContains(&T, T.NullConstant());
+  CheckGetCachedNodesContains(&T, T.ZeroConstant());
+  CheckGetCachedNodesContains(&T, T.OneConstant());
+  CheckGetCachedNodesContains(&T, T.NaNConstant());
+}
+
+
+TEST(JSGraph_GetCachedNodes_int32) {
+  JSConstantCacheTester T;
+
+  int32_t constants[] = {0,  1,  1,   1,   1,   2,   3,   4,  11, 12, 13,
+                         14, 55, -55, -44, -33, -22, -11, 16, 16, 17, 17,
+                         18, 18, 19,  19,  20,  20,  21,  21, 22, 23, 24,
+                         25, 15, 30,  31,  45,  46,  47,  48};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.Int32Constant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_float64) {
+  JSConstantCacheTester T;
+
+  double constants[] = {0,   11.1, 12.2,  13,    14,   55.5, -55.5, -44.4,
+                        -33, -22,  -11,   0,     11.1, 11.1, 12.3,  12.3,
+                        11,  11,   -33.3, -33.3, -22,  -11};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.Float64Constant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_int64) {
+  JSConstantCacheTester T;
+
+  int32_t constants[] = {0,   11,  12, 13, 14, 55, -55, -44, -33,
+                         -22, -11, 16, 16, 17, 17, 18,  18,  19,
+                         19,  20,  20, 21, 21, 22, 23,  24,  25};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.Int64Constant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_number) {
+  JSConstantCacheTester T;
+
+  double constants[] = {0,   11.1, 12.2,  13,    14,   55.5, -55.5, -44.4,
+                        -33, -22,  -11,   0,     11.1, 11.1, 12.3,  12.3,
+                        11,  11,   -33.3, -33.3, -22,  -11};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.Constant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_external) {
+  JSConstantCacheTester T;
+
+  ExternalReference constants[] = {ExternalReference::address_of_min_int(),
+                                   ExternalReference::address_of_min_int(),
+                                   ExternalReference::address_of_min_int(),
+                                   ExternalReference::address_of_one_half(),
+                                   ExternalReference::address_of_one_half(),
+                                   ExternalReference::address_of_min_int(),
+                                   ExternalReference::address_of_the_hole_nan(),
+                                   ExternalReference::address_of_one_half()};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.ExternalConstant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_together) {
+  JSConstantCacheTester T;
+
+  Node* constants[] = {
+      T.TrueConstant(),
+      T.UndefinedConstant(),
+      T.TheHoleConstant(),
+      T.TrueConstant(),
+      T.FalseConstant(),
+      T.NullConstant(),
+      T.ZeroConstant(),
+      T.OneConstant(),
+      T.NaNConstant(),
+      T.Int32Constant(0),
+      T.Int32Constant(1),
+      T.Int64Constant(-2),
+      T.Int64Constant(-4),
+      T.Float64Constant(0.9),
+      T.Float64Constant(V8_INFINITY),
+      T.Constant(0.99),
+      T.Constant(1.11),
+      T.ExternalConstant(ExternalReference::address_of_one_half())};
+
+  NodeVector nodes(T.main_zone());
+  T.GetCachedNodes(&nodes);
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    CHECK(Contains(&nodes, constants[i]));
+  }
+}
diff --git a/test/cctest/compiler/test-js-context-specialization.cc b/test/cctest/compiler/test-js-context-specialization.cc
index 47c660a..fb7bd94 100644
--- a/test/cctest/compiler/test-js-context-specialization.cc
+++ b/test/cctest/compiler/test-js-context-specialization.cc
@@ -7,7 +7,6 @@
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/source-position.h"
-#include "src/compiler/typer.h"
 #include "test/cctest/cctest.h"
 #include "test/cctest/compiler/function-tester.h"
 #include "test/cctest/compiler/graph-builder-tester.h"
@@ -22,10 +21,9 @@
       : DirectGraphBuilder(new (main_zone()) Graph(main_zone())),
         common_(main_zone()),
         javascript_(main_zone()),
-        machine_(),
+        machine_(main_zone()),
         simplified_(main_zone()),
-        typer_(main_zone()),
-        jsgraph_(graph(), common(), &javascript_, &typer_, &machine_),
+        jsgraph_(graph(), common(), &javascript_, &machine_),
         info_(main_isolate(), main_zone()) {}
 
   Factory* factory() { return main_isolate()->factory(); }
@@ -40,7 +38,6 @@
   JSOperatorBuilder javascript_;
   MachineOperatorBuilder machine_;
   SimplifiedOperatorBuilder simplified_;
-  Typer typer_;
   JSGraph jsgraph_;
   CompilationInfo info_;
 };
@@ -95,8 +92,8 @@
     HeapObjectMatcher<Context> match(new_context_input);
     CHECK_EQ(*native, *match.Value().handle());
     ContextAccess access = OpParameter<ContextAccess>(r.replacement());
-    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index());
-    CHECK_EQ(0, access.depth());
+    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast<int>(access.index()));
+    CHECK_EQ(0, static_cast<int>(access.depth()));
     CHECK_EQ(false, access.immutable());
   }
 
@@ -175,8 +172,8 @@
     HeapObjectMatcher<Context> match(new_context_input);
     CHECK_EQ(*native, *match.Value().handle());
     ContextAccess access = OpParameter<ContextAccess>(r.replacement());
-    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index());
-    CHECK_EQ(0, access.depth());
+    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast<int>(access.index()));
+    CHECK_EQ(0, static_cast<int>(access.depth()));
     CHECK_EQ(false, access.immutable());
   }
 }
@@ -206,7 +203,7 @@
   JSContextSpecializer spec(t.info(), t.jsgraph(), const_context);
 
   {
-    // Check that SpecializeToContext() replaces values and forwards effects
+    // Check that specialization replaces values and forwards effects
     // correctly, and folds values from constant and non-constant contexts
     Node* effect_in = start;
     Node* load = t.NewNode(t.javascript()->LoadContext(0, slot, true),
@@ -232,8 +229,10 @@
     CheckEffectInput(effect_in, load);
     CheckEffectInput(load, effect_use);
 
-    // Perform the substitution on the entire graph.
-    spec.SpecializeToContext();
+    // Perform the reduction on the entire graph.
+    GraphReducer graph_reducer(t.graph(), t.main_zone());
+    graph_reducer.AddReducer(&spec);
+    graph_reducer.ReduceGraph();
 
     // Effects should have been forwarded (not replaced with a value).
     CheckEffectInput(effect_in, effect_use);
diff --git a/test/cctest/compiler/test-js-typed-lowering.cc b/test/cctest/compiler/test-js-typed-lowering.cc
index cf126c2..3023837 100644
--- a/test/cctest/compiler/test-js-typed-lowering.cc
+++ b/test/cctest/compiler/test-js-typed-lowering.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/v8.h"
-#include "test/cctest/cctest.h"
-
 #include "src/compiler/graph-inl.h"
+#include "src/compiler/js-graph.h"
 #include "src/compiler/js-typed-lowering.h"
+#include "src/compiler/machine-operator.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/opcodes.h"
 #include "src/compiler/typer.h"
+#include "test/cctest/cctest.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
@@ -21,14 +21,15 @@
         binop(NULL),
         unop(NULL),
         javascript(main_zone()),
+        machine(main_zone()),
         simplified(main_zone()),
         common(main_zone()),
         graph(main_zone()),
-        typer(main_zone()),
+        typer(&graph, MaybeHandle<Context>()),
         context_node(NULL) {
-    typer.DecorateGraph(&graph);
-    Node* s = graph.NewNode(common.Start(num_parameters));
-    graph.SetStart(s);
+    graph.SetStart(graph.NewNode(common.Start(num_parameters)));
+    graph.SetEnd(graph.NewNode(common.End()));
+    typer.Run();
   }
 
   Isolate* isolate;
@@ -49,13 +50,14 @@
   }
 
   Node* UndefinedConstant() {
-    Unique<Object> unique =
-        Unique<Object>::CreateImmovable(isolate->factory()->undefined_value());
+    Unique<HeapObject> unique = Unique<HeapObject>::CreateImmovable(
+        isolate->factory()->undefined_value());
     return graph.NewNode(common.HeapConstant(unique));
   }
 
-  Node* HeapConstant(Handle<Object> constant) {
-    Unique<Object> unique = Unique<Object>::CreateUninitialized(constant);
+  Node* HeapConstant(Handle<HeapObject> constant) {
+    Unique<HeapObject> unique =
+        Unique<HeapObject>::CreateUninitialized(constant);
     return graph.NewNode(common.HeapConstant(unique));
   }
 
@@ -65,15 +67,16 @@
     Node* stack = graph.NewNode(common.StateValues(0));
 
     Node* state_node =
-        graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0), kIgnoreOutput),
+        graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0),
+                                        OutputFrameStateCombine::Ignore()),
                       parameters, locals, stack, context, UndefinedConstant());
 
     return state_node;
   }
 
   Node* reduce(Node* node) {
-    JSGraph jsgraph(&graph, &common, &javascript, &typer, &machine);
-    JSTypedLowering reducer(&jsgraph);
+    JSGraph jsgraph(&graph, &common, &javascript, &machine);
+    JSTypedLowering reducer(&jsgraph, main_zone());
     Reduction reduction = reducer.Reduce(node);
     if (reduction.Changed()) return reduction.replacement();
     return node;
@@ -164,17 +167,19 @@
 
 
 static Type* kInt32Types[] = {
-    Type::UnsignedSmall(),   Type::OtherSignedSmall(), Type::OtherUnsigned31(),
-    Type::OtherUnsigned32(), Type::OtherSigned32(),    Type::SignedSmall(),
-    Type::Signed32(),        Type::Unsigned32(),       Type::Integral32()};
+    Type::UnsignedSmall(),       Type::NegativeSigned32(),
+    Type::NonNegativeSigned32(), Type::SignedSmall(),
+    Type::Signed32(),            Type::Unsigned32(),
+    Type::Integral32()};
 
 
 static Type* kNumberTypes[] = {
-    Type::UnsignedSmall(),   Type::OtherSignedSmall(), Type::OtherUnsigned31(),
-    Type::OtherUnsigned32(), Type::OtherSigned32(),    Type::SignedSmall(),
-    Type::Signed32(),        Type::Unsigned32(),       Type::Integral32(),
-    Type::MinusZero(),       Type::NaN(),              Type::OtherNumber(),
-    Type::OrderedNumber(),   Type::Number()};
+    Type::UnsignedSmall(),       Type::NegativeSigned32(),
+    Type::NonNegativeSigned32(), Type::SignedSmall(),
+    Type::Signed32(),            Type::Unsigned32(),
+    Type::Integral32(),          Type::MinusZero(),
+    Type::NaN(),                 Type::OrderedNumber(),
+    Type::PlainNumber(),         Type::Number()};
 
 
 static Type* kJSTypes[] = {Type::Undefined(), Type::Null(),   Type::Boolean(),
@@ -260,16 +265,15 @@
 
 static void CheckToI32(Node* old_input, Node* new_input, bool is_signed) {
   Type* old_type = NodeProperties::GetBounds(old_input).upper;
+  Type* new_type = NodeProperties::GetBounds(new_input).upper;
   Type* expected_type = I32Type(is_signed);
+  CHECK(new_type->Is(expected_type));
   if (old_type->Is(expected_type)) {
     CHECK_EQ(old_input, new_input);
   } else if (new_input->opcode() == IrOpcode::kNumberConstant) {
-    CHECK(NodeProperties::GetBounds(new_input).upper->Is(expected_type));
     double v = OpParameter<double>(new_input);
     double e = static_cast<double>(is_signed ? FastD2I(v) : FastD2UI(v));
     CHECK_EQ(e, v);
-  } else {
-    CHECK_EQ(NumberToI32(is_signed), new_input->opcode());
   }
 }
 
@@ -302,12 +306,13 @@
 TEST(Int32BitwiseShifts) {
   JSBitwiseShiftTypedLoweringTester R;
 
-  Type* types[] = {
-      Type::SignedSmall(), Type::UnsignedSmall(), Type::OtherSigned32(),
-      Type::Unsigned32(),  Type::Signed32(),      Type::MinusZero(),
-      Type::NaN(),         Type::OtherNumber(),   Type::Undefined(),
-      Type::Null(),        Type::Boolean(),       Type::Number(),
-      Type::String(),      Type::Object()};
+  Type* types[] = {Type::SignedSmall(),      Type::UnsignedSmall(),
+                   Type::NegativeSigned32(), Type::NonNegativeSigned32(),
+                   Type::Unsigned32(),       Type::Signed32(),
+                   Type::MinusZero(),        Type::NaN(),
+                   Type::Undefined(),        Type::Null(),
+                   Type::Boolean(),          Type::Number(),
+                   Type::PlainNumber(),      Type::String()};
 
   for (size_t i = 0; i < arraysize(types); ++i) {
     Node* p0 = R.Parameter(types[i], 0);
@@ -325,9 +330,13 @@
 
         CheckToI32(p0, r0, R.signedness[k]);
 
-        R.CheckPureBinop(IrOpcode::kWord32And, r1);
-        CheckToI32(p1, r1->InputAt(0), R.signedness[k + 1]);
-        R.CheckInt32Constant(0x1F, r1->InputAt(1));
+        if (r1->opcode() == IrOpcode::kWord32And) {
+          R.CheckPureBinop(IrOpcode::kWord32And, r1);
+          CheckToI32(p1, r1->InputAt(0), R.signedness[k + 1]);
+          R.CheckInt32Constant(0x1F, r1->InputAt(1));
+        } else {
+          CheckToI32(p1, r1, R.signedness[k]);
+        }
       }
     }
   }
@@ -363,11 +372,11 @@
   JSBitwiseTypedLoweringTester R;
 
   Type* types[] = {
-      Type::SignedSmall(), Type::UnsignedSmall(), Type::OtherSigned32(),
-      Type::Unsigned32(),  Type::Signed32(),      Type::MinusZero(),
-      Type::NaN(),         Type::OtherNumber(),   Type::Undefined(),
-      Type::Null(),        Type::Boolean(),       Type::Number(),
-      Type::String(),      Type::Object()};
+      Type::SignedSmall(),   Type::UnsignedSmall(), Type::Unsigned32(),
+      Type::Signed32(),      Type::MinusZero(),     Type::NaN(),
+      Type::OrderedNumber(), Type::PlainNumber(),   Type::Undefined(),
+      Type::Null(),          Type::Boolean(),       Type::Number(),
+      Type::String()};
 
   for (size_t i = 0; i < arraysize(types); ++i) {
     Node* p0 = R.Parameter(types[i], 0);
@@ -498,20 +507,6 @@
     CHECK_EQ(IrOpcode::kParameter, r->opcode());
   }
 
-  {  // ToBoolean(ordered-number)
-    Node* r = R.ReduceUnop(op, Type::OrderedNumber());
-    CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
-    Node* i = r->InputAt(0);
-    CHECK_EQ(IrOpcode::kNumberEqual, i->opcode());
-    // ToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0))
-  }
-
-  {  // ToBoolean(string)
-    Node* r = R.ReduceUnop(op, Type::String());
-    // TODO(titzer): test will break with better js-typed-lowering
-    CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
-  }
-
   {  // ToBoolean(object)
     Node* r = R.ReduceUnop(op, Type::DetectableObject());
     R.CheckTrue(r);
@@ -524,39 +519,7 @@
 
   {  // ToBoolean(object)
     Node* r = R.ReduceUnop(op, Type::Object());
-    CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
-  }
-}
-
-
-TEST(JSToBoolean_replacement) {
-  JSTypedLoweringTester R;
-
-  Type* types[] = {Type::Null(),             Type::Undefined(),
-                   Type::Boolean(),          Type::OrderedNumber(),
-                   Type::DetectableObject(), Type::Undetectable()};
-
-  for (size_t i = 0; i < arraysize(types); i++) {
-    Node* n = R.Parameter(types[i]);
-    Node* c = R.graph.NewNode(R.javascript.ToBoolean(), n, R.context(),
-                              R.start(), R.start());
-    Node* effect_use = R.UseForEffect(c);
-    Node* add = R.graph.NewNode(R.simplified.ReferenceEqual(Type::Any()), n, c);
-
-    R.CheckEffectInput(c, effect_use);
-    Node* r = R.reduce(c);
-
-    if (types[i]->Is(Type::Boolean())) {
-      CHECK_EQ(n, r);
-    } else if (types[i]->Is(Type::OrderedNumber())) {
-      CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
-    } else {
-      CHECK_EQ(IrOpcode::kHeapConstant, r->opcode());
-    }
-
-    CHECK_EQ(n, add->InputAt(0));
-    CHECK_EQ(r, add->InputAt(1));
-    R.CheckEffectInput(R.start(), effect_use);
+    CHECK_EQ(IrOpcode::kAnyToBoolean, r->opcode());
   }
 }
 
@@ -690,33 +653,22 @@
       R.javascript.GreaterThan(),        R.simplified.NumberLessThan(),
       R.javascript.GreaterThanOrEqual(), R.simplified.NumberLessThanOrEqual()};
 
-  for (size_t i = 0; i < arraysize(kJSTypes); i++) {
-    Type* t0 = kJSTypes[i];
-    // Skip Type::String and Type::Receiver which might coerce into a string.
-    if (t0->Is(Type::String()) || t0->Is(Type::Receiver())) continue;
-    Node* p0 = R.Parameter(t0, 0);
+  Node* const p0 = R.Parameter(Type::Number(), 0);
+  Node* const p1 = R.Parameter(Type::Number(), 1);
 
-    for (size_t j = 0; j < arraysize(kJSTypes); j++) {
-      Type* t1 = kJSTypes[j];
-      // Skip Type::String and Type::Receiver which might coerce into a string.
-      if (t1->Is(Type::String()) || t0->Is(Type::Receiver())) continue;
-      Node* p1 = R.Parameter(t1, 1);
+  for (size_t k = 0; k < arraysize(ops); k += 2) {
+    Node* cmp = R.Binop(ops[k], p0, p1);
+    Node* r = R.reduce(cmp);
 
-      for (size_t k = 0; k < arraysize(ops); k += 2) {
-        Node* cmp = R.Binop(ops[k], p0, p1);
-        Node* r = R.reduce(cmp);
-
-        R.CheckPureBinop(ops[k + 1], r);
-        if (k >= 4) {
-          // GreaterThan and GreaterThanOrEqual commute the inputs
-          // and use the LessThan and LessThanOrEqual operators.
-          CheckIsConvertedToNumber(p1, r->InputAt(0));
-          CheckIsConvertedToNumber(p0, r->InputAt(1));
-        } else {
-          CheckIsConvertedToNumber(p0, r->InputAt(0));
-          CheckIsConvertedToNumber(p1, r->InputAt(1));
-        }
-      }
+    R.CheckPureBinop(ops[k + 1], r);
+    if (k >= 4) {
+      // GreaterThan and GreaterThanOrEqual commute the inputs
+      // and use the LessThan and LessThanOrEqual operators.
+      CheckIsConvertedToNumber(p1, r->InputAt(0));
+      CheckIsConvertedToNumber(p0, r->InputAt(1));
+    } else {
+      CheckIsConvertedToNumber(p0, r->InputAt(0));
+      CheckIsConvertedToNumber(p1, r->InputAt(1));
     }
   }
 }
@@ -753,51 +705,18 @@
 }
 
 
-TEST(ObjectComparison) {
-  JSTypedLoweringTester R;
-
-  Node* p0 = R.Parameter(Type::Number(), 0);
-  Node* p1 = R.Parameter(Type::Object(), 1);
-
-  Node* cmp = R.Binop(R.javascript.LessThan(), p0, p1);
-  Node* effect_use = R.UseForEffect(cmp);
-
-  R.CheckEffectInput(R.start(), cmp);
-  R.CheckEffectInput(cmp, effect_use);
-
-  Node* r = R.reduce(cmp);
-
-  R.CheckPureBinop(R.simplified.NumberLessThan(), r);
-
-  Node* i0 = r->InputAt(0);
-  Node* i1 = r->InputAt(1);
-
-  CHECK_EQ(p0, i0);
-  CHECK_NE(p1, i1);
-  CHECK_EQ(IrOpcode::kParameter, i0->opcode());
-  CHECK_EQ(IrOpcode::kJSToNumber, i1->opcode());
-
-  // Check effect chain is correct.
-  R.CheckEffectInput(R.start(), i1);
-  R.CheckEffectInput(i1, effect_use);
-}
-
-
 TEST(UnaryNot) {
   JSTypedLoweringTester R;
   const Operator* opnot = R.javascript.UnaryNot();
 
   for (size_t i = 0; i < arraysize(kJSTypes); i++) {
     Node* orig = R.Unop(opnot, R.Parameter(kJSTypes[i]));
-    Node* use = R.graph.NewNode(R.common.Return(), orig);
     Node* r = R.reduce(orig);
-    // TODO(titzer): test will break if/when js-typed-lowering constant folds.
-    CHECK_EQ(IrOpcode::kBooleanNot, use->InputAt(0)->opcode());
 
     if (r == orig && orig->opcode() == IrOpcode::kJSToBoolean) {
       // The original node was turned into a ToBoolean.
       CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
-    } else {
+    } else if (r->opcode() != IrOpcode::kHeapConstant) {
       CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
     }
   }
@@ -852,7 +771,7 @@
     if (effect_use != NULL) {
       R.CheckEffectInput(R.start(), effect_use);
       // Check that value uses of ToNumber() do not go to start().
-      for (int i = 0; i < effect_use->op()->InputCount(); i++) {
+      for (int i = 0; i < effect_use->op()->ValueInputCount(); i++) {
         CHECK_NE(R.start(), effect_use->InputAt(i));
       }
     }
@@ -904,9 +823,9 @@
   Node* CheckConverted(IrOpcode::Value opcode, Node* node, bool effects) {
     CHECK_EQ(opcode, node->opcode());
     if (effects) {
-      CHECK_LT(0, OperatorProperties::GetEffectInputCount(node->op()));
+      CHECK_LT(0, node->op()->EffectInputCount());
     } else {
-      CHECK_EQ(0, OperatorProperties::GetEffectInputCount(node->op()));
+      CHECK_EQ(0, node->op()->EffectInputCount());
     }
     return node;
   }
@@ -1030,7 +949,7 @@
   };
 
   for (size_t j = 0; j < arraysize(ops); j += 2) {
-    BinopEffectsTester B(ops[j], Type::Object(), Type::String());
+    BinopEffectsTester B(ops[j], Type::Symbol(), Type::Symbol());
     CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode());
 
     Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true);
@@ -1103,8 +1022,8 @@
     CHECK_EQ(B.p1, i0->InputAt(0));
     CHECK_EQ(B.p0, i1->InputAt(0));
 
-    // But effects should be ordered start -> i1 -> i0 -> effect_use
-    B.CheckEffectOrdering(i1, i0);
+    // But effects should be ordered start -> i1 -> effect_use
+    B.CheckEffectOrdering(i1);
   }
 
   for (size_t j = 0; j < arraysize(ops); j += 2) {
@@ -1166,7 +1085,7 @@
 
   for (int j = 0; j < R.kNumberOps; j += 2) {
     bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
-    BinopEffectsTester B(R.ops[j], Type::Number(), Type::Object());
+    BinopEffectsTester B(R.ops[j], Type::Number(), Type::Primitive());
 
     B.R.CheckPureBinop(B.result->opcode(), B.result);
 
@@ -1183,7 +1102,7 @@
 
   for (int j = 0; j < R.kNumberOps; j += 2) {
     bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
-    BinopEffectsTester B(R.ops[j], Type::Object(), Type::Number());
+    BinopEffectsTester B(R.ops[j], Type::Primitive(), Type::Number());
 
     B.R.CheckPureBinop(B.result->opcode(), B.result);
 
@@ -1200,7 +1119,7 @@
 
   for (int j = 0; j < R.kNumberOps; j += 2) {
     bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
-    BinopEffectsTester B(R.ops[j], Type::Object(), Type::Object());
+    BinopEffectsTester B(R.ops[j], Type::Primitive(), Type::Primitive());
 
     B.R.CheckPureBinop(B.result->opcode(), B.result);
 
@@ -1218,33 +1137,6 @@
 }
 
 
-TEST(UnaryNotEffects) {
-  JSTypedLoweringTester R;
-  const Operator* opnot = R.javascript.UnaryNot();
-
-  for (size_t i = 0; i < arraysize(kJSTypes); i++) {
-    Node* p0 = R.Parameter(kJSTypes[i], 0);
-    Node* orig = R.Unop(opnot, p0);
-    Node* effect_use = R.UseForEffect(orig);
-    Node* value_use = R.graph.NewNode(R.common.Return(), orig);
-    Node* r = R.reduce(orig);
-    // TODO(titzer): test will break if/when js-typed-lowering constant folds.
-    CHECK_EQ(IrOpcode::kBooleanNot, value_use->InputAt(0)->opcode());
-
-    if (r == orig && orig->opcode() == IrOpcode::kJSToBoolean) {
-      // The original node was turned into a ToBoolean, which has an effect.
-      CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
-      R.CheckEffectInput(R.start(), orig);
-      R.CheckEffectInput(orig, effect_use);
-    } else {
-      // effect should have been removed from this node.
-      CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
-      R.CheckEffectInput(R.start(), effect_use);
-    }
-  }
-}
-
-
 TEST(Int32AddNarrowing) {
   {
     JSBitwiseTypedLoweringTester R;
@@ -1263,11 +1155,7 @@
             Node* r = R.reduce(or_node);
 
             CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
-            CHECK_EQ(IrOpcode::kInt32Add, add_node->opcode());
-            bool is_signed = l ? R.signedness[o] : R.signedness[o + 1];
-
-            Type* add_type = NodeProperties::GetBounds(add_node).upper;
-            CHECK(add_type->Is(I32Type(is_signed)));
+            CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
           }
         }
       }
@@ -1290,40 +1178,33 @@
             Node* r = R.reduce(or_node);
 
             CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
-            CHECK_EQ(IrOpcode::kInt32Add, add_node->opcode());
-            bool is_signed = l ? R.signedness[o] : R.signedness[o + 1];
-
-            Type* add_type = NodeProperties::GetBounds(add_node).upper;
-            CHECK(add_type->Is(I32Type(is_signed)));
+            CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
           }
         }
       }
     }
   }
-}
+  {
+    JSBitwiseTypedLoweringTester R;
 
+    for (int o = 0; o < R.kNumberOps; o += 2) {
+      Node* n0 = R.Parameter(I32Type(R.signedness[o]));
+      Node* n1 = R.Parameter(I32Type(R.signedness[o + 1]));
+      Node* one = R.graph.NewNode(R.common.NumberConstant(1));
 
-TEST(Int32AddNarrowingNotOwned) {
-  JSBitwiseTypedLoweringTester R;
-
-  for (int o = 0; o < R.kNumberOps; o += 2) {
-    Node* n0 = R.Parameter(I32Type(R.signedness[o]));
-    Node* n1 = R.Parameter(I32Type(R.signedness[o + 1]));
-    Node* one = R.graph.NewNode(R.common.NumberConstant(1));
-
-    Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1);
-    Node* or_node = R.Binop(R.ops[o], add_node, one);
-    Node* other_use = R.Binop(R.simplified.NumberAdd(), add_node, one);
-    Node* r = R.reduce(or_node);
-    CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
-    // Should not be reduced to Int32Add because of the other number add.
-    CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
-    // Conversion to int32 should be done.
-    CheckToI32(add_node, r->InputAt(0), R.signedness[o]);
-    CheckToI32(one, r->InputAt(1), R.signedness[o + 1]);
-    // The other use should also not be touched.
-    CHECK_EQ(add_node, other_use->InputAt(0));
-    CHECK_EQ(one, other_use->InputAt(1));
+      Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1);
+      Node* or_node = R.Binop(R.ops[o], add_node, one);
+      Node* other_use = R.Binop(R.simplified.NumberAdd(), add_node, one);
+      Node* r = R.reduce(or_node);
+      CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
+      CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
+      // Conversion to int32 should be done.
+      CheckToI32(add_node, r->InputAt(0), R.signedness[o]);
+      CheckToI32(one, r->InputAt(1), R.signedness[o + 1]);
+      // The other use should also not be touched.
+      CHECK_EQ(add_node, other_use->InputAt(0));
+      CHECK_EQ(one, other_use->InputAt(1));
+    }
   }
 }
 
diff --git a/test/cctest/compiler/test-jump-threading.cc b/test/cctest/compiler/test-jump-threading.cc
new file mode 100644
index 0000000..74bf43d
--- /dev/null
+++ b/test/cctest/compiler/test-jump-threading.cc
@@ -0,0 +1,764 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/compiler/instruction.h"
+#include "src/compiler/instruction-codes.h"
+#include "src/compiler/jump-threading.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+typedef BasicBlock::RpoNumber RpoNumber;
+
+class TestCode : public HandleAndZoneScope {
+ public:
+  TestCode()
+      : HandleAndZoneScope(),
+        blocks_(main_zone()),
+        sequence_(main_zone(), &blocks_),
+        rpo_number_(RpoNumber::FromInt(0)),
+        current_(NULL) {}
+
+  ZoneVector<InstructionBlock*> blocks_;
+  InstructionSequence sequence_;
+  RpoNumber rpo_number_;
+  InstructionBlock* current_;
+
+  int Jump(int target) {
+    Start();
+    InstructionOperand* ops[] = {UseRpo(target)};
+    sequence_.AddInstruction(Instruction::New(main_zone(), kArchJmp, 0, NULL, 1,
+                                              ops, 0, NULL)->MarkAsControl());
+    int pos = static_cast<int>(sequence_.instructions().size() - 1);
+    End();
+    return pos;
+  }
+  void Fallthru() {
+    Start();
+    End();
+  }
+  int Branch(int ttarget, int ftarget) {
+    Start();
+    InstructionOperand* ops[] = {UseRpo(ttarget), UseRpo(ftarget)};
+    InstructionCode code = 119 | FlagsModeField::encode(kFlags_branch) |
+                           FlagsConditionField::encode(kEqual);
+    sequence_.AddInstruction(Instruction::New(main_zone(), code, 0, NULL, 2,
+                                              ops, 0, NULL)->MarkAsControl());
+    int pos = static_cast<int>(sequence_.instructions().size() - 1);
+    End();
+    return pos;
+  }
+  void Nop() {
+    Start();
+    sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
+  }
+  void RedundantMoves() {
+    Start();
+    sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
+    int index = static_cast<int>(sequence_.instructions().size()) - 1;
+    sequence_.AddGapMove(index, RegisterOperand::Create(13, main_zone()),
+                         RegisterOperand::Create(13, main_zone()));
+  }
+  void NonRedundantMoves() {
+    Start();
+    sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
+    int index = static_cast<int>(sequence_.instructions().size()) - 1;
+    sequence_.AddGapMove(index, ImmediateOperand::Create(11, main_zone()),
+                         RegisterOperand::Create(11, main_zone()));
+  }
+  void Other() {
+    Start();
+    sequence_.AddInstruction(Instruction::New(main_zone(), 155));
+  }
+  void End() {
+    Start();
+    sequence_.EndBlock(current_->rpo_number());
+    current_ = NULL;
+    rpo_number_ = RpoNumber::FromInt(rpo_number_.ToInt() + 1);
+  }
+  InstructionOperand* UseRpo(int num) {
+    int index = sequence_.AddImmediate(Constant(RpoNumber::FromInt(num)));
+    return ImmediateOperand::Create(index, main_zone());
+  }
+  void Start(bool deferred = false) {
+    if (current_ == NULL) {
+      current_ = new (main_zone()) InstructionBlock(
+          main_zone(), BasicBlock::Id::FromInt(rpo_number_.ToInt()),
+          rpo_number_, RpoNumber::Invalid(), RpoNumber::Invalid(), deferred);
+      blocks_.push_back(current_);
+      sequence_.StartBlock(rpo_number_);
+    }
+  }
+  void Defer() {
+    CHECK(current_ == NULL);
+    Start(true);
+  }
+};
+
+
+void VerifyForwarding(TestCode& code, int count, int* expected) {
+  Zone local_zone(code.main_isolate());
+  ZoneVector<RpoNumber> result(&local_zone);
+  JumpThreading::ComputeForwarding(&local_zone, result, &code.sequence_);
+
+  CHECK(count == static_cast<int>(result.size()));
+  for (int i = 0; i < count; i++) {
+    CHECK(expected[i] == result[i].ToInt());
+  }
+}
+
+
+TEST(FwEmpty1) {
+  TestCode code;
+
+  // B0
+  code.Jump(1);
+  // B1
+  code.Jump(2);
+  // B2
+  code.End();
+
+  static int expected[] = {2, 2, 2};
+  VerifyForwarding(code, 3, expected);
+}
+
+
+TEST(FwEmptyN) {
+  for (int i = 0; i < 9; i++) {
+    TestCode code;
+
+    // B0
+    code.Jump(1);
+    // B1
+    for (int j = 0; j < i; j++) code.Nop();
+    code.Jump(2);
+    // B2
+    code.End();
+
+    static int expected[] = {2, 2, 2};
+    VerifyForwarding(code, 3, expected);
+  }
+}
+
+
+TEST(FwNone1) {
+  TestCode code;
+
+  // B0
+  code.End();
+
+  static int expected[] = {0};
+  VerifyForwarding(code, 1, expected);
+}
+
+
+TEST(FwMoves1) {
+  TestCode code;
+
+  // B0
+  code.RedundantMoves();
+  code.End();
+
+  static int expected[] = {0};
+  VerifyForwarding(code, 1, expected);
+}
+
+
+TEST(FwMoves2) {
+  TestCode code;
+
+  // B0
+  code.RedundantMoves();
+  code.Fallthru();
+  // B1
+  code.End();
+
+  static int expected[] = {1, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwMoves2b) {
+  TestCode code;
+
+  // B0
+  code.NonRedundantMoves();
+  code.Fallthru();
+  // B1
+  code.End();
+
+  static int expected[] = {0, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwOther2) {
+  TestCode code;
+
+  // B0
+  code.Other();
+  code.Fallthru();
+  // B1
+  code.End();
+
+  static int expected[] = {0, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwNone2a) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.End();
+
+  static int expected[] = {1, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwNone2b) {
+  TestCode code;
+
+  // B0
+  code.Jump(1);
+  // B1
+  code.End();
+
+  static int expected[] = {1, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwLoop1) {
+  TestCode code;
+
+  // B0
+  code.Jump(0);
+
+  static int expected[] = {0};
+  VerifyForwarding(code, 1, expected);
+}
+
+
+TEST(FwLoop2) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Jump(0);
+
+  static int expected[] = {0, 0};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwLoop3) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(0);
+
+  static int expected[] = {0, 0, 0};
+  VerifyForwarding(code, 3, expected);
+}
+
+
+TEST(FwLoop1b) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Jump(1);
+
+  static int expected[] = {1, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwLoop2b) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(1);
+
+  static int expected[] = {1, 1, 1};
+  VerifyForwarding(code, 3, expected);
+}
+
+
+TEST(FwLoop3b) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Fallthru();
+  // B3
+  code.Jump(1);
+
+  static int expected[] = {1, 1, 1, 1};
+  VerifyForwarding(code, 4, expected);
+}
+
+
+TEST(FwLoop2_1a) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Fallthru();
+  // B3
+  code.Jump(1);
+  // B4
+  code.Jump(2);
+
+  static int expected[] = {1, 1, 1, 1, 1};
+  VerifyForwarding(code, 5, expected);
+}
+
+
+TEST(FwLoop2_1b) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(4);
+  // B3
+  code.Jump(1);
+  // B4
+  code.Jump(2);
+
+  static int expected[] = {2, 2, 2, 2, 2};
+  VerifyForwarding(code, 5, expected);
+}
+
+
+TEST(FwLoop2_1c) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(4);
+  // B3
+  code.Jump(2);
+  // B4
+  code.Jump(1);
+
+  static int expected[] = {1, 1, 1, 1, 1};
+  VerifyForwarding(code, 5, expected);
+}
+
+
+TEST(FwLoop2_1d) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(1);
+  // B3
+  code.Jump(1);
+  // B4
+  code.Jump(1);
+
+  static int expected[] = {1, 1, 1, 1, 1};
+  VerifyForwarding(code, 5, expected);
+}
+
+
+TEST(FwLoop3_1a) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Fallthru();
+  // B3
+  code.Jump(2);
+  // B4
+  code.Jump(1);
+  // B5
+  code.Jump(0);
+
+  static int expected[] = {2, 2, 2, 2, 2, 2};
+  VerifyForwarding(code, 6, expected);
+}
+
+
+TEST(FwDiamonds) {
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      TestCode code;
+      // B0
+      code.Branch(1, 2);
+      // B1
+      if (i) code.Other();
+      code.Jump(3);
+      // B2
+      if (j) code.Other();
+      code.Jump(3);
+      // B3
+      code.End();
+
+      int expected[] = {0, i ? 1 : 3, j ? 2 : 3, 3};
+      VerifyForwarding(code, 4, expected);
+    }
+  }
+}
+
+
+TEST(FwDiamonds2) {
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      for (int k = 0; k < 2; k++) {
+        TestCode code;
+        // B0
+        code.Branch(1, 2);
+        // B1
+        if (i) code.Other();
+        code.Jump(3);
+        // B2
+        if (j) code.Other();
+        code.Jump(3);
+        // B3
+        if (k) code.NonRedundantMoves();
+        code.Jump(4);
+        // B4
+        code.End();
+
+        int merge = k ? 3 : 4;
+        int expected[] = {0, i ? 1 : merge, j ? 2 : merge, merge, 4};
+        VerifyForwarding(code, 5, expected);
+      }
+    }
+  }
+}
+
+
+TEST(FwDoubleDiamonds) {
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      for (int x = 0; x < 2; x++) {
+        for (int y = 0; y < 2; y++) {
+          TestCode code;
+          // B0
+          code.Branch(1, 2);
+          // B1
+          if (i) code.Other();
+          code.Jump(3);
+          // B2
+          if (j) code.Other();
+          code.Jump(3);
+          // B3
+          code.Branch(4, 5);
+          // B4
+          if (x) code.Other();
+          code.Jump(6);
+          // B5
+          if (y) code.Other();
+          code.Jump(6);
+          // B6
+          code.End();
+
+          int expected[] = {0,         i ? 1 : 3, j ? 2 : 3, 3,
+                            x ? 4 : 6, y ? 5 : 6, 6};
+          VerifyForwarding(code, 7, expected);
+        }
+      }
+    }
+  }
+}
+
+template <int kSize>
+void RunPermutationsRecursive(int outer[kSize], int start,
+                              void (*run)(int*, int)) {
+  int permutation[kSize];
+
+  for (int i = 0; i < kSize; i++) permutation[i] = outer[i];
+
+  int count = kSize - start;
+  if (count == 0) return run(permutation, kSize);
+  for (int i = start; i < kSize; i++) {
+    permutation[start] = outer[i];
+    permutation[i] = outer[start];
+    RunPermutationsRecursive<kSize>(permutation, start + 1, run);
+    permutation[i] = outer[i];
+    permutation[start] = outer[start];
+  }
+}
+
+
+template <int kSize>
+void RunAllPermutations(void (*run)(int*, int)) {
+  int permutation[kSize];
+  for (int i = 0; i < kSize; i++) permutation[i] = i;
+  RunPermutationsRecursive<kSize>(permutation, 0, run);
+}
+
+
+void PrintPermutation(int* permutation, int size) {
+  printf("{ ");
+  for (int i = 0; i < size; i++) {
+    if (i > 0) printf(", ");
+    printf("%d", permutation[i]);
+  }
+  printf(" }\n");
+}
+
+
+int find(int x, int* permutation, int size) {
+  for (int i = 0; i < size; i++) {
+    if (permutation[i] == x) return i;
+  }
+  return size;
+}
+
+
+void RunPermutedChain(int* permutation, int size) {
+  TestCode code;
+  int cur = -1;
+  for (int i = 0; i < size; i++) {
+    code.Jump(find(cur + 1, permutation, size) + 1);
+    cur = permutation[i];
+  }
+  code.Jump(find(cur + 1, permutation, size) + 1);
+  code.End();
+
+  int expected[] = {size + 1, size + 1, size + 1, size + 1,
+                    size + 1, size + 1, size + 1};
+  VerifyForwarding(code, size + 2, expected);
+}
+
+
+TEST(FwPermuted_chain) {
+  RunAllPermutations<3>(RunPermutedChain);
+  RunAllPermutations<4>(RunPermutedChain);
+  RunAllPermutations<5>(RunPermutedChain);
+}
+
+
+void RunPermutedDiamond(int* permutation, int size) {
+  TestCode code;
+  int br = 1 + find(0, permutation, size);
+  code.Jump(br);
+  for (int i = 0; i < size; i++) {
+    switch (permutation[i]) {
+      case 0:
+        code.Branch(1 + find(1, permutation, size),
+                    1 + find(2, permutation, size));
+        break;
+      case 1:
+        code.Jump(1 + find(3, permutation, size));
+        break;
+      case 2:
+        code.Jump(1 + find(3, permutation, size));
+        break;
+      case 3:
+        code.Jump(5);
+        break;
+    }
+  }
+  code.End();
+
+  int expected[] = {br, 5, 5, 5, 5, 5};
+  expected[br] = br;
+  VerifyForwarding(code, 6, expected);
+}
+
+
+TEST(FwPermuted_diamond) { RunAllPermutations<4>(RunPermutedDiamond); }
+
+
+void ApplyForwarding(TestCode& code, int size, int* forward) {
+  ZoneVector<RpoNumber> vector(code.main_zone());
+  for (int i = 0; i < size; i++) {
+    vector.push_back(RpoNumber::FromInt(forward[i]));
+  }
+  JumpThreading::ApplyForwarding(vector, &code.sequence_);
+}
+
+
+void CheckJump(TestCode& code, int pos, int target) {
+  Instruction* instr = code.sequence_.InstructionAt(pos);
+  CHECK_EQ(kArchJmp, instr->arch_opcode());
+  CHECK_EQ(1, static_cast<int>(instr->InputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->TempCount()));
+  CHECK_EQ(target, code.sequence_.InputRpo(instr, 0).ToInt());
+}
+
+
+void CheckNop(TestCode& code, int pos) {
+  Instruction* instr = code.sequence_.InstructionAt(pos);
+  CHECK_EQ(kArchNop, instr->arch_opcode());
+  CHECK_EQ(0, static_cast<int>(instr->InputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->TempCount()));
+}
+
+
+void CheckBranch(TestCode& code, int pos, int t1, int t2) {
+  Instruction* instr = code.sequence_.InstructionAt(pos);
+  CHECK_EQ(2, static_cast<int>(instr->InputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->TempCount()));
+  CHECK_EQ(t1, code.sequence_.InputRpo(instr, 0).ToInt());
+  CHECK_EQ(t2, code.sequence_.InputRpo(instr, 1).ToInt());
+}
+
+
+void CheckAssemblyOrder(TestCode& code, int size, int* expected) {
+  int i = 0;
+  for (auto const block : code.sequence_.instruction_blocks()) {
+    CHECK_EQ(expected[i++], block->ao_number().ToInt());
+  }
+}
+
+
+TEST(Rewire1) {
+  TestCode code;
+
+  // B0
+  int j1 = code.Jump(1);
+  // B1
+  int j2 = code.Jump(2);
+  // B2
+  code.End();
+
+  static int forward[] = {2, 2, 2};
+  ApplyForwarding(code, 3, forward);
+  CheckJump(code, j1, 2);
+  CheckNop(code, j2);
+
+  static int assembly[] = {0, 1, 1};
+  CheckAssemblyOrder(code, 3, assembly);
+}
+
+
+TEST(Rewire1_deferred) {
+  TestCode code;
+
+  // B0
+  int j1 = code.Jump(1);
+  // B1
+  int j2 = code.Jump(2);
+  // B2
+  code.Defer();
+  int j3 = code.Jump(3);
+  // B3
+  code.End();
+
+  static int forward[] = {3, 3, 3, 3};
+  ApplyForwarding(code, 4, forward);
+  CheckJump(code, j1, 3);
+  CheckNop(code, j2);
+  CheckNop(code, j3);
+
+  static int assembly[] = {0, 1, 2, 1};
+  CheckAssemblyOrder(code, 4, assembly);
+}
+
+
+TEST(Rewire2_deferred) {
+  TestCode code;
+
+  // B0
+  code.Other();
+  int j1 = code.Jump(1);
+  // B1
+  code.Defer();
+  code.Fallthru();
+  // B2
+  code.Defer();
+  int j2 = code.Jump(3);
+  // B3
+  code.End();
+
+  static int forward[] = {0, 1, 2, 3};
+  ApplyForwarding(code, 4, forward);
+  CheckJump(code, j1, 1);
+  CheckJump(code, j2, 3);
+
+  static int assembly[] = {0, 2, 3, 1};
+  CheckAssemblyOrder(code, 4, assembly);
+}
+
+
+TEST(Rewire_diamond) {
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      TestCode code;
+      // B0
+      int j1 = code.Jump(1);
+      // B1
+      int b1 = code.Branch(2, 3);
+      // B2
+      int j2 = code.Jump(4);
+      // B3
+      int j3 = code.Jump(4);
+      // B5
+      code.End();
+
+      int forward[] = {0, 1, i ? 4 : 2, j ? 4 : 3, 4};
+      ApplyForwarding(code, 5, forward);
+      CheckJump(code, j1, 1);
+      CheckBranch(code, b1, i ? 4 : 2, j ? 4 : 3);
+      if (i) {
+        CheckNop(code, j2);
+      } else {
+        CheckJump(code, j2, 4);
+      }
+      if (j) {
+        CheckNop(code, j3);
+      } else {
+        CheckJump(code, j3, 4);
+      }
+
+      int assembly[] = {0, 1, 2, 3, 4};
+      if (i) {
+        for (int k = 3; k < 5; k++) assembly[k]--;
+      }
+      if (j) {
+        for (int k = 4; k < 5; k++) assembly[k]--;
+      }
+      CheckAssemblyOrder(code, 5, assembly);
+    }
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/cctest/compiler/test-linkage.cc b/test/cctest/compiler/test-linkage.cc
index ff65d6e..117caf2 100644
--- a/test/cctest/compiler/test-linkage.cc
+++ b/test/cctest/compiler/test-linkage.cc
@@ -8,7 +8,6 @@
 #include "src/zone.h"
 
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/linkage.h"
 #include "src/compiler/machine-operator.h"
@@ -23,8 +22,8 @@
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
-                                     0, 0, "dummy");
+static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
+                               "dummy", 0, 0, 0, 0, 0, 0);
 
 // So we can get a real JS function.
 static Handle<JSFunction> Compile(const char* source) {
@@ -45,7 +44,7 @@
   InitializedHandleScope handles;
   Handle<JSFunction> function = Compile("a + b");
   CompilationInfoWithZone info(function);
-  Linkage linkage(&info);
+  Linkage linkage(info.zone(), &info);
 }
 
 
@@ -60,13 +59,13 @@
     Handle<JSFunction> function = v8::Utils::OpenHandle(
         *v8::Handle<v8::Function>::Cast(CompileRun(sources[i])));
     CompilationInfoWithZone info(function);
-    Linkage linkage(&info);
+    Linkage linkage(info.zone(), &info);
 
     CallDescriptor* descriptor = linkage.GetIncomingDescriptor();
     CHECK_NE(NULL, descriptor);
 
-    CHECK_EQ(1 + i, descriptor->JSParameterCount());
-    CHECK_EQ(1, descriptor->ReturnCount());
+    CHECK_EQ(1 + i, static_cast<int>(descriptor->JSParameterCount()));
+    CHECK_EQ(1, static_cast<int>(descriptor->ReturnCount()));
     CHECK_EQ(Operator::kNoProperties, descriptor->properties());
     CHECK_EQ(true, descriptor->IsJSFunctionCall());
   }
@@ -76,7 +75,7 @@
 TEST(TestLinkageCodeStubIncoming) {
   Isolate* isolate = CcTest::InitIsolateOnce();
   CompilationInfoWithZone info(static_cast<HydrogenCodeStub*>(NULL), isolate);
-  Linkage linkage(&info);
+  Linkage linkage(info.zone(), &info);
   // TODO(titzer): test linkage creation with a bonafide code stub.
   // this just checks current behavior.
   CHECK_EQ(NULL, linkage.GetIncomingDescriptor());
@@ -87,13 +86,14 @@
   HandleAndZoneScope handles;
   Handle<JSFunction> function = Compile("a + c");
   CompilationInfoWithZone info(function);
-  Linkage linkage(&info);
+  Linkage linkage(info.zone(), &info);
 
   for (int i = 0; i < 32; i++) {
-    CallDescriptor* descriptor = linkage.GetJSCallDescriptor(i);
+    CallDescriptor* descriptor =
+        linkage.GetJSCallDescriptor(i, CallDescriptor::kNoFlags);
     CHECK_NE(NULL, descriptor);
-    CHECK_EQ(i, descriptor->JSParameterCount());
-    CHECK_EQ(1, descriptor->ReturnCount());
+    CHECK_EQ(i, static_cast<int>(descriptor->JSParameterCount()));
+    CHECK_EQ(1, static_cast<int>(descriptor->ReturnCount()));
     CHECK_EQ(Operator::kNoProperties, descriptor->properties());
     CHECK_EQ(true, descriptor->IsJSFunctionCall());
   }
diff --git a/test/cctest/compiler/test-loop-analysis.cc b/test/cctest/compiler/test-loop-analysis.cc
new file mode 100644
index 0000000..9c11268
--- /dev/null
+++ b/test/cctest/compiler/test-loop-analysis.cc
@@ -0,0 +1,862 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/graph-visualizer.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/loop-analysis.h"
+#include "src/compiler/node.h"
+#include "src/compiler/opcodes.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/schedule.h"
+#include "src/compiler/scheduler.h"
+#include "src/compiler/simplified-operator.h"
+#include "src/compiler/verifier.h"
+#include "test/cctest/cctest.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+static Operator kIntAdd(IrOpcode::kInt32Add, Operator::kPure, "Int32Add", 2, 0,
+                        0, 1, 0, 0);
+static Operator kIntLt(IrOpcode::kInt32LessThan, Operator::kPure,
+                       "Int32LessThan", 2, 0, 0, 1, 0, 0);
+static Operator kStore(IrOpcode::kStore, Operator::kNoProperties, "Store", 0, 2,
+                       1, 0, 1, 0);
+
+static const int kNumLeafs = 4;
+
+// A helper for all tests dealing with LoopFinder.
+class LoopFinderTester : HandleAndZoneScope {
+ public:
+  LoopFinderTester()
+      : isolate(main_isolate()),
+        common(main_zone()),
+        graph(main_zone()),
+        jsgraph(&graph, &common, NULL, NULL),
+        start(graph.NewNode(common.Start(1))),
+        end(graph.NewNode(common.End(), start)),
+        p0(graph.NewNode(common.Parameter(0), start)),
+        zero(jsgraph.Int32Constant(0)),
+        one(jsgraph.OneConstant()),
+        half(jsgraph.Constant(0.5)),
+        self(graph.NewNode(common.Int32Constant(0xaabbccdd))),
+        dead(graph.NewNode(common.Dead())),
+        loop_tree(NULL) {
+    graph.SetEnd(end);
+    graph.SetStart(start);
+    leaf[0] = zero;
+    leaf[1] = one;
+    leaf[2] = half;
+    leaf[3] = p0;
+  }
+
+  Isolate* isolate;
+  CommonOperatorBuilder common;
+  Graph graph;
+  JSGraph jsgraph;
+  Node* start;
+  Node* end;
+  Node* p0;
+  Node* zero;
+  Node* one;
+  Node* half;
+  Node* self;
+  Node* dead;
+  Node* leaf[kNumLeafs];
+  LoopTree* loop_tree;
+
+  Node* Phi(Node* a) {
+    return SetSelfReferences(graph.NewNode(op(1, false), a, start));
+  }
+
+  Node* Phi(Node* a, Node* b) {
+    return SetSelfReferences(graph.NewNode(op(2, false), a, b, start));
+  }
+
+  Node* Phi(Node* a, Node* b, Node* c) {
+    return SetSelfReferences(graph.NewNode(op(3, false), a, b, c, start));
+  }
+
+  Node* Phi(Node* a, Node* b, Node* c, Node* d) {
+    return SetSelfReferences(graph.NewNode(op(4, false), a, b, c, d, start));
+  }
+
+  Node* EffectPhi(Node* a) {
+    return SetSelfReferences(graph.NewNode(op(1, true), a, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b) {
+    return SetSelfReferences(graph.NewNode(op(2, true), a, b, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b, Node* c) {
+    return SetSelfReferences(graph.NewNode(op(3, true), a, b, c, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b, Node* c, Node* d) {
+    return SetSelfReferences(graph.NewNode(op(4, true), a, b, c, d, start));
+  }
+
+  Node* SetSelfReferences(Node* node) {
+    for (Edge edge : node->input_edges()) {
+      if (edge.to() == self) node->ReplaceInput(edge.index(), node);
+    }
+    return node;
+  }
+
+  const Operator* op(int count, bool effect) {
+    return effect ? common.EffectPhi(count) : common.Phi(kMachAnyTagged, count);
+  }
+
+  Node* Return(Node* val, Node* effect, Node* control) {
+    Node* ret = graph.NewNode(common.Return(), val, effect, control);
+    end->ReplaceInput(0, ret);
+    return ret;
+  }
+
+  LoopTree* GetLoopTree() {
+    if (loop_tree == NULL) {
+      if (FLAG_trace_turbo_graph) {
+        OFStream os(stdout);
+        os << AsRPO(graph);
+      }
+      Zone zone(isolate);
+      loop_tree = LoopFinder::BuildLoopTree(&graph, &zone);
+    }
+    return loop_tree;
+  }
+
+  void CheckLoop(Node** header, int header_count, Node** body, int body_count) {
+    LoopTree* tree = GetLoopTree();
+    LoopTree::Loop* loop = tree->ContainingLoop(header[0]);
+    CHECK_NE(NULL, loop);
+
+    CHECK(header_count == static_cast<int>(loop->HeaderSize()));
+    for (int i = 0; i < header_count; i++) {
+      // Each header node should be in the loop.
+      CHECK_EQ(loop, tree->ContainingLoop(header[i]));
+      CheckRangeContains(tree->HeaderNodes(loop), header[i]);
+    }
+
+    CHECK_EQ(body_count, static_cast<int>(loop->BodySize()));
+    for (int i = 0; i < body_count; i++) {
+      // Each body node should be contained in the loop.
+      CHECK(tree->Contains(loop, body[i]));
+      CheckRangeContains(tree->BodyNodes(loop), body[i]);
+    }
+  }
+
+  void CheckRangeContains(NodeRange range, Node* node) {
+    // O(n) ftw.
+    CHECK_NE(range.end(), std::find(range.begin(), range.end(), node));
+  }
+
+  void CheckNestedLoops(Node** chain, int chain_count) {
+    LoopTree* tree = GetLoopTree();
+    for (int i = 0; i < chain_count; i++) {
+      Node* header = chain[i];
+      // Each header should be in a loop.
+      LoopTree::Loop* loop = tree->ContainingLoop(header);
+      CHECK_NE(NULL, loop);
+      // Check parentage.
+      LoopTree::Loop* parent =
+          i == 0 ? NULL : tree->ContainingLoop(chain[i - 1]);
+      CHECK_EQ(parent, loop->parent());
+      for (int j = i - 1; j >= 0; j--) {
+        // This loop should be nested inside all the outer loops.
+        Node* outer_header = chain[j];
+        LoopTree::Loop* outer = tree->ContainingLoop(outer_header);
+        CHECK(tree->Contains(outer, header));
+        CHECK(!tree->Contains(loop, outer_header));
+      }
+    }
+  }
+};
+
+
+struct While {
+  LoopFinderTester& t;
+  Node* branch;
+  Node* if_true;
+  Node* exit;
+  Node* loop;
+
+  While(LoopFinderTester& R, Node* cond) : t(R) {
+    loop = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+    branch = t.graph.NewNode(t.common.Branch(), cond, loop);
+    if_true = t.graph.NewNode(t.common.IfTrue(), branch);
+    exit = t.graph.NewNode(t.common.IfFalse(), branch);
+    loop->ReplaceInput(1, if_true);
+  }
+
+  void chain(Node* control) { loop->ReplaceInput(0, control); }
+  void nest(While& that) {
+    that.loop->ReplaceInput(1, exit);
+    this->loop->ReplaceInput(0, that.if_true);
+  }
+};
+
+
+struct Counter {
+  Node* base;
+  Node* inc;
+  Node* phi;
+  Node* add;
+
+  Counter(While& w, int32_t b, int32_t k)
+      : base(w.t.jsgraph.Int32Constant(b)), inc(w.t.jsgraph.Int32Constant(k)) {
+    Build(w);
+  }
+
+  Counter(While& w, Node* b, Node* k) : base(b), inc(k) { Build(w); }
+
+  void Build(While& w) {
+    phi = w.t.graph.NewNode(w.t.op(2, false), base, base, w.loop);
+    add = w.t.graph.NewNode(&kIntAdd, phi, inc);
+    phi->ReplaceInput(1, add);
+  }
+};
+
+
+struct StoreLoop {
+  Node* base;
+  Node* val;
+  Node* phi;
+  Node* store;
+
+  explicit StoreLoop(While& w)
+      : base(w.t.jsgraph.Int32Constant(12)),
+        val(w.t.jsgraph.Int32Constant(13)) {
+    Build(w);
+  }
+
+  StoreLoop(While& w, Node* b, Node* v) : base(b), val(v) { Build(w); }
+
+  void Build(While& w) {
+    phi = w.t.graph.NewNode(w.t.op(2, true), base, base, w.loop);
+    store = w.t.graph.NewNode(&kStore, phi, val, w.loop);
+    phi->ReplaceInput(1, store);
+  }
+};
+
+
+TEST(LaLoop1) {
+  // One loop.
+  LoopFinderTester t;
+  While w(t, t.p0);
+  t.Return(t.p0, t.start, w.exit);
+
+  Node* chain[] = {w.loop};
+  t.CheckNestedLoops(chain, 1);
+
+  Node* header[] = {w.loop};
+  Node* body[] = {w.branch, w.if_true};
+  t.CheckLoop(header, 1, body, 2);
+}
+
+
+TEST(LaLoop1c) {
+  // One loop with a counter.
+  LoopFinderTester t;
+  While w(t, t.p0);
+  Counter c(w, 0, 1);
+  t.Return(c.phi, t.start, w.exit);
+
+  Node* chain[] = {w.loop};
+  t.CheckNestedLoops(chain, 1);
+
+  Node* header[] = {w.loop, c.phi};
+  Node* body[] = {w.branch, w.if_true, c.add};
+  t.CheckLoop(header, 2, body, 3);
+}
+
+
+TEST(LaLoop1e) {
+  // One loop with an effect phi.
+  LoopFinderTester t;
+  While w(t, t.p0);
+  StoreLoop c(w);
+  t.Return(t.p0, c.phi, w.exit);
+
+  Node* chain[] = {w.loop};
+  t.CheckNestedLoops(chain, 1);
+
+  Node* header[] = {w.loop, c.phi};
+  Node* body[] = {w.branch, w.if_true, c.store};
+  t.CheckLoop(header, 2, body, 3);
+}
+
+
+TEST(LaLoop1d) {
+  // One loop with two counters.
+  LoopFinderTester t;
+  While w(t, t.p0);
+  Counter c1(w, 0, 1);
+  Counter c2(w, 1, 1);
+  t.Return(t.graph.NewNode(&kIntAdd, c1.phi, c2.phi), t.start, w.exit);
+
+  Node* chain[] = {w.loop};
+  t.CheckNestedLoops(chain, 1);
+
+  Node* header[] = {w.loop, c1.phi, c2.phi};
+  Node* body[] = {w.branch, w.if_true, c1.add, c2.add};
+  t.CheckLoop(header, 3, body, 4);
+}
+
+
+TEST(LaLoop2) {
+  // One loop following another.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  w2.chain(w1.exit);
+  t.Return(t.p0, t.start, w2.exit);
+
+  {
+    Node* chain[] = {w1.loop};
+    t.CheckNestedLoops(chain, 1);
+
+    Node* header[] = {w1.loop};
+    Node* body[] = {w1.branch, w1.if_true};
+    t.CheckLoop(header, 1, body, 2);
+  }
+
+  {
+    Node* chain[] = {w2.loop};
+    t.CheckNestedLoops(chain, 1);
+
+    Node* header[] = {w2.loop};
+    Node* body[] = {w2.branch, w2.if_true};
+    t.CheckLoop(header, 1, body, 2);
+  }
+}
+
+
+TEST(LaLoop2c) {
+  // One loop following another, each with counters.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  Counter c1(w1, 0, 1);
+  Counter c2(w2, 0, 1);
+  w2.chain(w1.exit);
+  t.Return(t.graph.NewNode(&kIntAdd, c1.phi, c2.phi), t.start, w2.exit);
+
+  {
+    Node* chain[] = {w1.loop};
+    t.CheckNestedLoops(chain, 1);
+
+    Node* header[] = {w1.loop, c1.phi};
+    Node* body[] = {w1.branch, w1.if_true, c1.add};
+    t.CheckLoop(header, 2, body, 3);
+  }
+
+  {
+    Node* chain[] = {w2.loop};
+    t.CheckNestedLoops(chain, 1);
+
+    Node* header[] = {w2.loop, c2.phi};
+    Node* body[] = {w2.branch, w2.if_true, c2.add};
+    t.CheckLoop(header, 2, body, 3);
+  }
+}
+
+
+TEST(LaLoop2cc) {
+  // One loop following another; second loop uses phi from first.
+  for (int i = 0; i < 8; i++) {
+    LoopFinderTester t;
+    While w1(t, t.p0);
+    While w2(t, t.p0);
+    Counter c1(w1, 0, 1);
+
+    // various usage scenarios for the second loop.
+    Counter c2(w2, i & 1 ? t.p0 : c1.phi, i & 2 ? t.p0 : c1.phi);
+    if (i & 3) w2.branch->ReplaceInput(0, c1.phi);
+
+    w2.chain(w1.exit);
+    t.Return(t.graph.NewNode(&kIntAdd, c1.phi, c2.phi), t.start, w2.exit);
+
+    {
+      Node* chain[] = {w1.loop};
+      t.CheckNestedLoops(chain, 1);
+
+      Node* header[] = {w1.loop, c1.phi};
+      Node* body[] = {w1.branch, w1.if_true, c1.add};
+      t.CheckLoop(header, 2, body, 3);
+    }
+
+    {
+      Node* chain[] = {w2.loop};
+      t.CheckNestedLoops(chain, 1);
+
+      Node* header[] = {w2.loop, c2.phi};
+      Node* body[] = {w2.branch, w2.if_true, c2.add};
+      t.CheckLoop(header, 2, body, 3);
+    }
+  }
+}
+
+
+TEST(LaNestedLoop1) {
+  // One loop nested in another.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  w2.nest(w1);
+  t.Return(t.p0, t.start, w1.exit);
+
+  Node* chain[] = {w1.loop, w2.loop};
+  t.CheckNestedLoops(chain, 2);
+
+  Node* h1[] = {w1.loop};
+  Node* b1[] = {w1.branch, w1.if_true, w2.loop, w2.branch, w2.if_true, w2.exit};
+  t.CheckLoop(h1, 1, b1, 6);
+
+  Node* h2[] = {w2.loop};
+  Node* b2[] = {w2.branch, w2.if_true};
+  t.CheckLoop(h2, 1, b2, 2);
+}
+
+
+TEST(LaNestedLoop1c) {
+  // One loop nested in another, each with a counter.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  Counter c1(w1, 0, 1);
+  Counter c2(w2, 0, 1);
+  w2.branch->ReplaceInput(0, c2.phi);
+  w2.nest(w1);
+  t.Return(c1.phi, t.start, w1.exit);
+
+  Node* chain[] = {w1.loop, w2.loop};
+  t.CheckNestedLoops(chain, 2);
+
+  Node* h1[] = {w1.loop, c1.phi};
+  Node* b1[] = {w1.branch, w1.if_true, w2.loop, w2.branch, w2.if_true,
+                w2.exit,   c2.phi,     c1.add,  c2.add};
+  t.CheckLoop(h1, 2, b1, 9);
+
+  Node* h2[] = {w2.loop, c2.phi};
+  Node* b2[] = {w2.branch, w2.if_true, c2.add};
+  t.CheckLoop(h2, 2, b2, 3);
+}
+
+
+TEST(LaNestedLoop2) {
+  // Two loops nested in an outer loop.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  While w3(t, t.p0);
+  w2.nest(w1);
+  w3.nest(w1);
+  w3.chain(w2.exit);
+  t.Return(t.p0, t.start, w1.exit);
+
+  Node* chain1[] = {w1.loop, w2.loop};
+  t.CheckNestedLoops(chain1, 2);
+
+  Node* chain2[] = {w1.loop, w3.loop};
+  t.CheckNestedLoops(chain2, 2);
+
+  Node* h1[] = {w1.loop};
+  Node* b1[] = {w1.branch, w1.if_true, w2.loop,   w2.branch,  w2.if_true,
+                w2.exit,   w3.loop,    w3.branch, w3.if_true, w3.exit};
+  t.CheckLoop(h1, 1, b1, 10);
+
+  Node* h2[] = {w2.loop};
+  Node* b2[] = {w2.branch, w2.if_true};
+  t.CheckLoop(h2, 1, b2, 2);
+
+  Node* h3[] = {w3.loop};
+  Node* b3[] = {w3.branch, w3.if_true};
+  t.CheckLoop(h3, 1, b3, 2);
+}
+
+
+TEST(LaNestedLoop3) {
+  // Three nested loops.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  While w3(t, t.p0);
+  w2.loop->ReplaceInput(0, w1.if_true);
+  w3.loop->ReplaceInput(0, w2.if_true);
+  w2.loop->ReplaceInput(1, w3.exit);
+  w1.loop->ReplaceInput(1, w2.exit);
+  t.Return(t.p0, t.start, w1.exit);
+
+  Node* chain[] = {w1.loop, w2.loop, w3.loop};
+  t.CheckNestedLoops(chain, 3);
+
+  Node* h1[] = {w1.loop};
+  Node* b1[] = {w1.branch, w1.if_true, w2.loop,   w2.branch,  w2.if_true,
+                w2.exit,   w3.loop,    w3.branch, w3.if_true, w3.exit};
+  t.CheckLoop(h1, 1, b1, 10);
+
+  Node* h2[] = {w2.loop};
+  Node* b2[] = {w2.branch, w2.if_true, w3.loop, w3.branch, w3.if_true, w3.exit};
+  t.CheckLoop(h2, 1, b2, 6);
+
+  Node* h3[] = {w3.loop};
+  Node* b3[] = {w3.branch, w3.if_true};
+  t.CheckLoop(h3, 1, b3, 2);
+}
+
+
+TEST(LaNestedLoop3c) {
+  // Three nested loops with counters.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  Counter c1(w1, 0, 1);
+  While w2(t, t.p0);
+  Counter c2(w2, 0, 1);
+  While w3(t, t.p0);
+  Counter c3(w3, 0, 1);
+  w2.loop->ReplaceInput(0, w1.if_true);
+  w3.loop->ReplaceInput(0, w2.if_true);
+  w2.loop->ReplaceInput(1, w3.exit);
+  w1.loop->ReplaceInput(1, w2.exit);
+  w1.branch->ReplaceInput(0, c1.phi);
+  w2.branch->ReplaceInput(0, c2.phi);
+  w3.branch->ReplaceInput(0, c3.phi);
+  t.Return(c1.phi, t.start, w1.exit);
+
+  Node* chain[] = {w1.loop, w2.loop, w3.loop};
+  t.CheckNestedLoops(chain, 3);
+
+  Node* h1[] = {w1.loop, c1.phi};
+  Node* b1[] = {w1.branch, w1.if_true, c1.add,    c2.add,     c2.add,
+                c2.phi,    c3.phi,     w2.loop,   w2.branch,  w2.if_true,
+                w2.exit,   w3.loop,    w3.branch, w3.if_true, w3.exit};
+  t.CheckLoop(h1, 2, b1, 15);
+
+  Node* h2[] = {w2.loop, c2.phi};
+  Node* b2[] = {w2.branch, w2.if_true, c2.add,     c3.add, c3.phi,
+                w3.loop,   w3.branch,  w3.if_true, w3.exit};
+  t.CheckLoop(h2, 2, b2, 9);
+
+  Node* h3[] = {w3.loop, c3.phi};
+  Node* b3[] = {w3.branch, w3.if_true, c3.add};
+  t.CheckLoop(h3, 2, b3, 3);
+}
+
+
+TEST(LaMultipleExit1) {
+  const int kMaxExits = 10;
+  Node* merge[1 + kMaxExits];
+  Node* body[2 * kMaxExits];
+
+  // A single loop with {i} exits.
+  for (int i = 1; i < kMaxExits; i++) {
+    LoopFinderTester t;
+    Node* cond = t.p0;
+
+    int merge_count = 0;
+    int body_count = 0;
+    Node* loop = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+    Node* last = loop;
+
+    for (int e = 0; e < i; e++) {
+      Node* branch = t.graph.NewNode(t.common.Branch(), cond, last);
+      Node* if_true = t.graph.NewNode(t.common.IfTrue(), branch);
+      Node* exit = t.graph.NewNode(t.common.IfFalse(), branch);
+      last = if_true;
+
+      body[body_count++] = branch;
+      body[body_count++] = if_true;
+      merge[merge_count++] = exit;
+    }
+
+    loop->ReplaceInput(1, last);  // form loop backedge.
+    Node* end = t.graph.NewNode(t.common.Merge(i), i, merge);  // form exit.
+    t.graph.SetEnd(end);
+
+    Node* h[] = {loop};
+    t.CheckLoop(h, 1, body, body_count);
+  }
+}
+
+
+TEST(LaMultipleBackedge1) {
+  const int kMaxBackedges = 10;
+  Node* loop_inputs[1 + kMaxBackedges];
+  Node* body[3 * kMaxBackedges];
+
+  // A single loop with {i} backedges.
+  for (int i = 1; i < kMaxBackedges; i++) {
+    LoopFinderTester t;
+
+    for (int j = 0; j <= i; j++) loop_inputs[j] = t.start;
+    Node* loop = t.graph.NewNode(t.common.Loop(1 + i), 1 + i, loop_inputs);
+
+    Node* cond = t.p0;
+    int body_count = 0;
+    Node* exit = loop;
+
+    for (int b = 0; b < i; b++) {
+      Node* branch = t.graph.NewNode(t.common.Branch(), cond, exit);
+      Node* if_true = t.graph.NewNode(t.common.IfTrue(), branch);
+      Node* if_false = t.graph.NewNode(t.common.IfFalse(), branch);
+      exit = if_false;
+
+      body[body_count++] = branch;
+      body[body_count++] = if_true;
+      if (b != (i - 1)) body[body_count++] = if_false;
+
+      loop->ReplaceInput(1 + b, if_true);
+    }
+
+    t.graph.SetEnd(exit);
+
+    Node* h[] = {loop};
+    t.CheckLoop(h, 1, body, body_count);
+  }
+}
+
+
+TEST(LaEdgeMatrix1) {
+  // Test various kinds of extra edges added to a simple loop.
+  for (int i = 0; i < 3; i++) {
+    for (int j = 0; j < 3; j++) {
+      for (int k = 0; k < 3; k++) {
+        LoopFinderTester t;
+
+        Node* p1 = t.jsgraph.Int32Constant(11);
+        Node* p2 = t.jsgraph.Int32Constant(22);
+        Node* p3 = t.jsgraph.Int32Constant(33);
+
+        Node* loop = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+        Node* phi =
+            t.graph.NewNode(t.common.Phi(kMachInt32, 2), t.one, p1, loop);
+        Node* cond = t.graph.NewNode(&kIntAdd, phi, p2);
+        Node* branch = t.graph.NewNode(t.common.Branch(), cond, loop);
+        Node* if_true = t.graph.NewNode(t.common.IfTrue(), branch);
+        Node* exit = t.graph.NewNode(t.common.IfFalse(), branch);
+        loop->ReplaceInput(1, if_true);
+        Node* ret = t.graph.NewNode(t.common.Return(), p3, t.start, exit);
+        t.graph.SetEnd(ret);
+
+        Node* choices[] = {p1, phi, cond};
+        p1->ReplaceUses(choices[i]);
+        p2->ReplaceUses(choices[j]);
+        p3->ReplaceUses(choices[k]);
+
+        Node* header[] = {loop, phi};
+        Node* body[] = {cond, branch, if_true};
+        t.CheckLoop(header, 2, body, 3);
+      }
+    }
+  }
+}
+
+
+void RunEdgeMatrix2(int i) {
+  DCHECK(i >= 0 && i < 5);
+  for (int j = 0; j < 5; j++) {
+    for (int k = 0; k < 5; k++) {
+      LoopFinderTester t;
+
+      Node* p1 = t.jsgraph.Int32Constant(11);
+      Node* p2 = t.jsgraph.Int32Constant(22);
+      Node* p3 = t.jsgraph.Int32Constant(33);
+
+      // outer loop.
+      Node* loop1 = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+      Node* phi1 =
+          t.graph.NewNode(t.common.Phi(kMachInt32, 2), t.one, p1, loop1);
+      Node* cond1 = t.graph.NewNode(&kIntAdd, phi1, t.one);
+      Node* branch1 = t.graph.NewNode(t.common.Branch(), cond1, loop1);
+      Node* if_true1 = t.graph.NewNode(t.common.IfTrue(), branch1);
+      Node* exit1 = t.graph.NewNode(t.common.IfFalse(), branch1);
+
+      // inner loop.
+      Node* loop2 = t.graph.NewNode(t.common.Loop(2), if_true1, t.start);
+      Node* phi2 =
+          t.graph.NewNode(t.common.Phi(kMachInt32, 2), t.one, p2, loop2);
+      Node* cond2 = t.graph.NewNode(&kIntAdd, phi2, p3);
+      Node* branch2 = t.graph.NewNode(t.common.Branch(), cond2, loop2);
+      Node* if_true2 = t.graph.NewNode(t.common.IfTrue(), branch2);
+      Node* exit2 = t.graph.NewNode(t.common.IfFalse(), branch2);
+      loop2->ReplaceInput(1, if_true2);
+      loop1->ReplaceInput(1, exit2);
+
+      Node* ret = t.graph.NewNode(t.common.Return(), phi1, t.start, exit1);
+      t.graph.SetEnd(ret);
+
+      Node* choices[] = {p1, phi1, cond1, phi2, cond2};
+      p1->ReplaceUses(choices[i]);
+      p2->ReplaceUses(choices[j]);
+      p3->ReplaceUses(choices[k]);
+
+      Node* header1[] = {loop1, phi1};
+      Node* body1[] = {cond1, branch1, if_true1, exit2,   loop2,
+                       phi2,  cond2,   branch2,  if_true2};
+      t.CheckLoop(header1, 2, body1, 9);
+
+      Node* header2[] = {loop2, phi2};
+      Node* body2[] = {cond2, branch2, if_true2};
+      t.CheckLoop(header2, 2, body2, 3);
+
+      Node* chain[] = {loop1, loop2};
+      t.CheckNestedLoops(chain, 2);
+    }
+  }
+}
+
+
+TEST(LaEdgeMatrix2_0) { RunEdgeMatrix2(0); }
+
+
+TEST(LaEdgeMatrix2_1) { RunEdgeMatrix2(1); }
+
+
+TEST(LaEdgeMatrix2_2) { RunEdgeMatrix2(2); }
+
+
+TEST(LaEdgeMatrix2_3) { RunEdgeMatrix2(3); }
+
+
+TEST(LaEdgeMatrix2_4) { RunEdgeMatrix2(4); }
+
+
+// Generates a triply-nested loop with extra edges between the phis and
+// conditions according to the edge choice parameters.
+void RunEdgeMatrix3(int c1a, int c1b, int c1c,    // line break
+                    int c2a, int c2b, int c2c,    // line break
+                    int c3a, int c3b, int c3c) {  // line break
+  LoopFinderTester t;
+
+  Node* p1a = t.jsgraph.Int32Constant(11);
+  Node* p1b = t.jsgraph.Int32Constant(22);
+  Node* p1c = t.jsgraph.Int32Constant(33);
+  Node* p2a = t.jsgraph.Int32Constant(44);
+  Node* p2b = t.jsgraph.Int32Constant(55);
+  Node* p2c = t.jsgraph.Int32Constant(66);
+  Node* p3a = t.jsgraph.Int32Constant(77);
+  Node* p3b = t.jsgraph.Int32Constant(88);
+  Node* p3c = t.jsgraph.Int32Constant(99);
+
+  // L1 depth = 0
+  Node* loop1 = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+  Node* phi1 = t.graph.NewNode(t.common.Phi(kMachInt32, 2), p1a, p1c, loop1);
+  Node* cond1 = t.graph.NewNode(&kIntAdd, phi1, p1b);
+  Node* branch1 = t.graph.NewNode(t.common.Branch(), cond1, loop1);
+  Node* if_true1 = t.graph.NewNode(t.common.IfTrue(), branch1);
+  Node* exit1 = t.graph.NewNode(t.common.IfFalse(), branch1);
+
+  // L2 depth = 1
+  Node* loop2 = t.graph.NewNode(t.common.Loop(2), if_true1, t.start);
+  Node* phi2 = t.graph.NewNode(t.common.Phi(kMachInt32, 2), p2a, p2c, loop2);
+  Node* cond2 = t.graph.NewNode(&kIntAdd, phi2, p2b);
+  Node* branch2 = t.graph.NewNode(t.common.Branch(), cond2, loop2);
+  Node* if_true2 = t.graph.NewNode(t.common.IfTrue(), branch2);
+  Node* exit2 = t.graph.NewNode(t.common.IfFalse(), branch2);
+
+  // L3 depth = 2
+  Node* loop3 = t.graph.NewNode(t.common.Loop(2), if_true2, t.start);
+  Node* phi3 = t.graph.NewNode(t.common.Phi(kMachInt32, 2), p3a, p3c, loop3);
+  Node* cond3 = t.graph.NewNode(&kIntAdd, phi3, p3b);
+  Node* branch3 = t.graph.NewNode(t.common.Branch(), cond3, loop3);
+  Node* if_true3 = t.graph.NewNode(t.common.IfTrue(), branch3);
+  Node* exit3 = t.graph.NewNode(t.common.IfFalse(), branch3);
+
+  loop3->ReplaceInput(1, if_true3);
+  loop2->ReplaceInput(1, exit3);
+  loop1->ReplaceInput(1, exit2);
+
+  Node* ret = t.graph.NewNode(t.common.Return(), phi1, t.start, exit1);
+  t.graph.SetEnd(ret);
+
+  // Mutate the graph according to the edge choices.
+
+  Node* o1[] = {t.one};
+  Node* o2[] = {t.one, phi1, cond1};
+  Node* o3[] = {t.one, phi1, cond1, phi2, cond2};
+
+  p1a->ReplaceUses(o1[c1a]);
+  p1b->ReplaceUses(o1[c1b]);
+
+  p2a->ReplaceUses(o2[c2a]);
+  p2b->ReplaceUses(o2[c2b]);
+
+  p3a->ReplaceUses(o3[c3a]);
+  p3b->ReplaceUses(o3[c3b]);
+
+  Node* l2[] = {phi1, cond1, phi2, cond2};
+  Node* l3[] = {phi1, cond1, phi2, cond2, phi3, cond3};
+
+  p1c->ReplaceUses(l2[c1c]);
+  p2c->ReplaceUses(l3[c2c]);
+  p3c->ReplaceUses(l3[c3c]);
+
+  // Run the tests and verify loop structure.
+
+  Node* chain[] = {loop1, loop2, loop3};
+  t.CheckNestedLoops(chain, 3);
+
+  Node* header1[] = {loop1, phi1};
+  Node* body1[] = {cond1, branch1, if_true1, exit2,    loop2,
+                   phi2,  cond2,   branch2,  if_true2, exit3,
+                   loop3, phi3,    cond3,    branch3,  if_true3};
+  t.CheckLoop(header1, 2, body1, 15);
+
+  Node* header2[] = {loop2, phi2};
+  Node* body2[] = {cond2, branch2, if_true2, exit3,   loop3,
+                   phi3,  cond3,   branch3,  if_true3};
+  t.CheckLoop(header2, 2, body2, 9);
+
+  Node* header3[] = {loop3, phi3};
+  Node* body3[] = {cond3, branch3, if_true3};
+  t.CheckLoop(header3, 2, body3, 3);
+}
+
+
+// Runs all combinations with a fixed {i}.
+void RunEdgeMatrix3_i(int i) {
+  for (int a = 0; a < 1; a++) {
+    for (int b = 0; b < 1; b++) {
+      for (int c = 0; c < 4; c++) {
+        for (int d = 0; d < 3; d++) {
+          for (int e = 0; e < 3; e++) {
+            for (int f = 0; f < 6; f++) {
+              for (int g = 0; g < 5; g++) {
+                for (int h = 0; h < 5; h++) {
+                  RunEdgeMatrix3(a, b, c, d, e, f, g, h, i);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+
+// Test all possible legal triply-nested loops with conditions and phis.
+TEST(LaEdgeMatrix3_0) { RunEdgeMatrix3_i(0); }
+
+
+TEST(LaEdgeMatrix3_1) { RunEdgeMatrix3_i(1); }
+
+
+TEST(LaEdgeMatrix3_2) { RunEdgeMatrix3_i(2); }
+
+
+TEST(LaEdgeMatrix3_3) { RunEdgeMatrix3_i(3); }
+
+
+TEST(LaEdgeMatrix3_4) { RunEdgeMatrix3_i(4); }
+
+
+TEST(LaEdgeMatrix3_5) { RunEdgeMatrix3_i(5); }
diff --git a/test/cctest/compiler/test-loop-assignment-analysis.cc b/test/cctest/compiler/test-loop-assignment-analysis.cc
new file mode 100644
index 0000000..aabd95b
--- /dev/null
+++ b/test/cctest/compiler/test-loop-assignment-analysis.cc
@@ -0,0 +1,294 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/ast-loop-assignment-analyzer.h"
+#include "src/parser.h"
+#include "src/rewriter.h"
+#include "src/scopes.h"
+#include "test/cctest/cctest.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+namespace {
+const int kBufferSize = 1024;
+
+struct TestHelper : public HandleAndZoneScope {
+  Handle<JSFunction> function;
+  LoopAssignmentAnalysis* result;
+
+  explicit TestHelper(const char* body)
+      : function(Handle<JSFunction>::null()), result(NULL) {
+    ScopedVector<char> program(kBufferSize);
+    SNPrintF(program, "function f(a,b,c) { %s; } f;", body);
+    v8::Local<v8::Value> v = CompileRun(program.start());
+    Handle<Object> obj = v8::Utils::OpenHandle(*v);
+    function = Handle<JSFunction>::cast(obj);
+  }
+
+  void CheckLoopAssignedCount(int expected, const char* var_name) {
+    // TODO(titzer): don't scope analyze every single time.
+    CompilationInfo info(function, main_zone());
+
+    CHECK(Parser::Parse(&info));
+    CHECK(Rewriter::Rewrite(&info));
+    CHECK(Scope::Analyze(&info));
+
+    Scope* scope = info.function()->scope();
+    AstValueFactory* factory = info.ast_value_factory();
+    CHECK_NE(NULL, scope);
+
+    if (result == NULL) {
+      AstLoopAssignmentAnalyzer analyzer(main_zone(), &info);
+      result = analyzer.Analyze();
+      CHECK_NE(NULL, result);
+    }
+
+    const i::AstRawString* name = factory->GetOneByteString(var_name);
+
+    i::Variable* var = scope->Lookup(name);
+    CHECK_NE(NULL, var);
+
+    if (var->location() == Variable::UNALLOCATED) {
+      CHECK_EQ(0, expected);
+    } else {
+      CHECK(var->IsStackAllocated());
+      CHECK_EQ(expected, result->GetAssignmentCountForTesting(scope, var));
+    }
+  }
+};
+}
+
+
+TEST(SimpleLoop1) {
+  TestHelper f("var x = 0; while (x) ;");
+
+  f.CheckLoopAssignedCount(0, "x");
+}
+
+
+TEST(SimpleLoop2) {
+  const char* loops[] = {
+      "while (x) { var x = 0; }",            "for(;;) { var x = 0; }",
+      "for(;x;) { var x = 0; }",             "for(;x;x) { var x = 0; }",
+      "for(var i = x; x; x) { var x = 0; }", "for(y in 0) { var x = 0; }",
+      "for(y of 0) { var x = 0; }",          "for(var x = 0; x; x++) { }",
+      "for(var x = 0; x++;) { }",            "var x; for(;x;x++) { }",
+      "var x; do { x = 1; } while (0);",     "do { var x = 1; } while (0);"};
+
+  for (size_t i = 0; i < arraysize(loops); i++) {
+    TestHelper f(loops[i]);
+    f.CheckLoopAssignedCount(1, "x");
+  }
+}
+
+
+TEST(ForInOf1) {
+  const char* loops[] = {
+      "for(x in 0) { }", "for(x of 0) { }",
+  };
+
+  for (size_t i = 0; i < arraysize(loops); i++) {
+    TestHelper f(loops[i]);
+    f.CheckLoopAssignedCount(0, "x");
+  }
+}
+
+
+TEST(Param1) {
+  TestHelper f("while (1) a = 0;");
+
+  f.CheckLoopAssignedCount(1, "a");
+  f.CheckLoopAssignedCount(0, "b");
+  f.CheckLoopAssignedCount(0, "c");
+}
+
+
+TEST(Param2) {
+  TestHelper f("for (;;) b = 0;");
+
+  f.CheckLoopAssignedCount(0, "a");
+  f.CheckLoopAssignedCount(1, "b");
+  f.CheckLoopAssignedCount(0, "c");
+}
+
+
+TEST(Param2b) {
+  TestHelper f("a; b; c; for (;;) b = 0;");
+
+  f.CheckLoopAssignedCount(0, "a");
+  f.CheckLoopAssignedCount(1, "b");
+  f.CheckLoopAssignedCount(0, "c");
+}
+
+
+TEST(Param3) {
+  TestHelper f("for(x in 0) c = 0;");
+
+  f.CheckLoopAssignedCount(0, "a");
+  f.CheckLoopAssignedCount(0, "b");
+  f.CheckLoopAssignedCount(1, "c");
+}
+
+
+TEST(Param3b) {
+  TestHelper f("a; b; c; for(x in 0) c = 0;");
+
+  f.CheckLoopAssignedCount(0, "a");
+  f.CheckLoopAssignedCount(0, "b");
+  f.CheckLoopAssignedCount(1, "c");
+}
+
+
+TEST(NestedLoop1) {
+  TestHelper f("while (x) { while (x) { var x = 0; } }");
+
+  f.CheckLoopAssignedCount(2, "x");
+}
+
+
+TEST(NestedLoop2) {
+  TestHelper f("while (0) { while (0) { var x = 0; } }");
+
+  f.CheckLoopAssignedCount(2, "x");
+}
+
+
+TEST(NestedLoop3) {
+  TestHelper f("while (0) { var y = 1; while (0) { var x = 0; } }");
+
+  f.CheckLoopAssignedCount(2, "x");
+  f.CheckLoopAssignedCount(1, "y");
+}
+
+
+TEST(NestedInc1) {
+  const char* loops[] = {
+      "while (1) a(b++);",
+      "while (1) a(0, b++);",
+      "while (1) a(0, 0, b++);",
+      "while (1) a(b++, 1, 1);",
+      "while (1) a(++b);",
+      "while (1) a + (b++);",
+      "while (1) (b++) + a;",
+      "while (1) a + c(b++);",
+      "while (1) throw b++;",
+      "while (1) switch (b++) {} ;",
+      "while (1) switch (a) {case (b++): 0; } ;",
+      "while (1) switch (a) {case b: b++; } ;",
+      "while (1) a == (b++);",
+      "while (1) a === (b++);",
+      "while (1) +(b++);",
+      "while (1) ~(b++);",
+      "while (1) new a(b++);",
+      "while (1) (b++).f;",
+      "while (1) a[b++];",
+      "while (1) (b++)();",
+      "while (1) [b++];",
+      "while (1) [0,b++];",
+      "while (1) var y = [11,b++,12];",
+      "while (1) var y = {f:11,g:(b++),h:12};",
+      "while (1) try {b++;} finally {};",
+      "while (1) try {} finally {b++};",
+      "while (1) try {b++;} catch (e) {};",
+      "while (1) try {} catch (e) {b++};",
+      "while (1) return b++;",
+      "while (1) (b++) ? b : b;",
+      "while (1) b ? (b++) : b;",
+      "while (1) b ? b : (b++);",
+  };
+
+  for (size_t i = 0; i < arraysize(loops); i++) {
+    TestHelper f(loops[i]);
+    f.CheckLoopAssignedCount(1, "b");
+  }
+}
+
+
+TEST(NestedAssign1) {
+  const char* loops[] = {
+      "while (1) a(b=1);",
+      "while (1) a(0, b=1);",
+      "while (1) a(0, 0, b=1);",
+      "while (1) a(b=1, 1, 1);",
+      "while (1) a + (b=1);",
+      "while (1) (b=1) + a;",
+      "while (1) a + c(b=1);",
+      "while (1) throw b=1;",
+      "while (1) switch (b=1) {} ;",
+      "while (1) switch (a) {case b=1: 0; } ;",
+      "while (1) switch (a) {case b: b=1; } ;",
+      "while (1) a == (b=1);",
+      "while (1) a === (b=1);",
+      "while (1) +(b=1);",
+      "while (1) ~(b=1);",
+      "while (1) new a(b=1);",
+      "while (1) (b=1).f;",
+      "while (1) a[b=1];",
+      "while (1) (b=1)();",
+      "while (1) [b=1];",
+      "while (1) [0,b=1];",
+      "while (1) var z = [11,b=1,12];",
+      "while (1) var y = {f:11,g:(b=1),h:12};",
+      "while (1) try {b=1;} finally {};",
+      "while (1) try {} finally {b=1};",
+      "while (1) try {b=1;} catch (e) {};",
+      "while (1) try {} catch (e) {b=1};",
+      "while (1) return b=1;",
+      "while (1) (b=1) ? b : b;",
+      "while (1) b ? (b=1) : b;",
+      "while (1) b ? b : (b=1);",
+  };
+
+  for (size_t i = 0; i < arraysize(loops); i++) {
+    TestHelper f(loops[i]);
+    f.CheckLoopAssignedCount(1, "b");
+  }
+}
+
+
+TEST(NestedLoops3) {
+  TestHelper f("var x, y, z, w; while (x++) while (y++) while (z++) ; w;");
+
+  f.CheckLoopAssignedCount(1, "x");
+  f.CheckLoopAssignedCount(2, "y");
+  f.CheckLoopAssignedCount(3, "z");
+  f.CheckLoopAssignedCount(0, "w");
+}
+
+
+TEST(NestedLoops3b) {
+  TestHelper f(
+      "var x, y, z, w;"
+      "while (1) { x=1; while (1) { y=1; while (1) z=1; } }"
+      "w;");
+
+  f.CheckLoopAssignedCount(1, "x");
+  f.CheckLoopAssignedCount(2, "y");
+  f.CheckLoopAssignedCount(3, "z");
+  f.CheckLoopAssignedCount(0, "w");
+}
+
+
+TEST(NestedLoops3c) {
+  TestHelper f(
+      "var x, y, z, w;"
+      "while (1) {"
+      "  x++;"
+      "  while (1) {"
+      "    y++;"
+      "    while (1) z++;"
+      "  }"
+      "  while (1) {"
+      "    y++;"
+      "    while (1) z++;"
+      "  }"
+      "}"
+      "w;");
+
+  f.CheckLoopAssignedCount(1, "x");
+  f.CheckLoopAssignedCount(3, "y");
+  f.CheckLoopAssignedCount(5, "z");
+  f.CheckLoopAssignedCount(0, "w");
+}
diff --git a/test/cctest/compiler/test-machine-operator-reducer.cc b/test/cctest/compiler/test-machine-operator-reducer.cc
index eca1f3c..648e1b9 100644
--- a/test/cctest/compiler/test-machine-operator-reducer.cc
+++ b/test/cctest/compiler/test-machine-operator-reducer.cc
@@ -5,9 +5,11 @@
 #include "test/cctest/cctest.h"
 
 #include "src/base/utils/random-number-generator.h"
+#include "src/codegen.h"
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/machine-operator-reducer.h"
+#include "src/compiler/operator-properties.h"
 #include "src/compiler/typer.h"
 #include "test/cctest/compiler/value-helper.h"
 
@@ -49,15 +51,18 @@
 
 class ReducerTester : public HandleAndZoneScope {
  public:
-  explicit ReducerTester(int num_parameters = 0)
+  explicit ReducerTester(
+      int num_parameters = 0,
+      MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags)
       : isolate(main_isolate()),
         binop(NULL),
         unop(NULL),
+        machine(main_zone(), kMachPtr, flags),
         common(main_zone()),
         graph(main_zone()),
         javascript(main_zone()),
-        typer(main_zone()),
-        jsgraph(&graph, &common, &javascript, &typer, &machine),
+        typer(&graph, MaybeHandle<Context>()),
+        jsgraph(&graph, &common, &javascript, &machine),
         maxuint32(Constant<int32_t>(kMaxUInt32)) {
     Node* s = graph.NewNode(common.Start(num_parameters));
     graph.SetStart(s);
@@ -96,7 +101,7 @@
   template <typename T>
   void CheckFoldBinop(volatile T expect, Node* a, Node* b) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, a, b);
+    Node* n = CreateBinopNode(a, b);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction reduction = reducer.Reduce(n);
     CHECK(reduction.Changed());
@@ -108,7 +113,7 @@
   // the {expect} node.
   void CheckBinop(Node* expect, Node* a, Node* b) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, a, b);
+    Node* n = CreateBinopNode(a, b);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction reduction = reducer.Reduce(n);
     CHECK(reduction.Changed());
@@ -120,7 +125,7 @@
   void CheckFoldBinop(Node* left_expect, Node* right_expect, Node* left,
                       Node* right) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, left, right);
+    Node* n = CreateBinopNode(left, right);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction reduction = reducer.Reduce(n);
     CHECK(reduction.Changed());
@@ -135,7 +140,7 @@
   void CheckFoldBinop(volatile T left_expect, const Operator* op_expect,
                       Node* right_expect, Node* left, Node* right) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, left, right);
+    Node* n = CreateBinopNode(left, right);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction r = reducer.Reduce(n);
     CHECK(r.Changed());
@@ -150,11 +155,13 @@
   void CheckFoldBinop(Node* left_expect, const Operator* op_expect,
                       volatile T right_expect, Node* left, Node* right) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, left, right);
+    Node* n = CreateBinopNode(left, right);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction r = reducer.Reduce(n);
     CHECK(r.Changed());
     CHECK_EQ(op_expect->opcode(), r.replacement()->op()->opcode());
+    CHECK_EQ(OperatorProperties::GetTotalInputCount(op_expect),
+             r.replacement()->InputCount());
     CHECK_EQ(left_expect, r.replacement()->InputAt(0));
     CHECK_EQ(right_expect, ValueOf<T>(r.replacement()->InputAt(1)->op()));
   }
@@ -167,7 +174,7 @@
     Node* p = Parameter();
     Node* k = Constant<T>(constant);
     {
-      Node* n = graph.NewNode(binop, k, p);
+      Node* n = CreateBinopNode(k, p);
       MachineOperatorReducer reducer(&jsgraph);
       Reduction reduction = reducer.Reduce(n);
       CHECK(!reduction.Changed() || reduction.replacement() == n);
@@ -175,7 +182,7 @@
       CHECK_EQ(k, n->InputAt(1));
     }
     {
-      Node* n = graph.NewNode(binop, p, k);
+      Node* n = CreateBinopNode(p, k);
       MachineOperatorReducer reducer(&jsgraph);
       Reduction reduction = reducer.Reduce(n);
       CHECK(!reduction.Changed());
@@ -191,7 +198,7 @@
     CHECK(!binop->HasProperty(Operator::kCommutative));
     Node* p = Parameter();
     Node* k = Constant<T>(constant);
-    Node* n = graph.NewNode(binop, k, p);
+    Node* n = CreateBinopNode(k, p);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction reduction = reducer.Reduce(n);
     CHECK(!reduction.Changed());
@@ -202,6 +209,15 @@
   Node* Parameter(int32_t index = 0) {
     return graph.NewNode(common.Parameter(index), graph.start());
   }
+
+ private:
+  Node* CreateBinopNode(Node* left, Node* right) {
+    if (binop->ControlInputCount() > 0) {
+      return graph.NewNode(binop, left, right, graph.start());
+    } else {
+      return graph.NewNode(binop, left, right);
+    }
+  }
 };
 
 
@@ -343,7 +359,36 @@
 }
 
 
-TEST(ReduceWord32Equal) {
+static void CheckJsShift(ReducerTester* R) {
+  DCHECK(R->machine.Word32ShiftIsSafe());
+
+  Node* x = R->Parameter(0);
+  Node* y = R->Parameter(1);
+  Node* thirty_one = R->Constant<int32_t>(0x1f);
+  Node* y_and_thirty_one =
+      R->graph.NewNode(R->machine.Word32And(), y, thirty_one);
+
+  // If the underlying machine shift instructions 'and' their right operand
+  // with 0x1f then:  x << (y & 0x1f) => x << y
+  R->CheckFoldBinop(x, y, x, y_and_thirty_one);
+}
+
+
+TEST(ReduceJsShifts) {
+  ReducerTester R(0, MachineOperatorBuilder::kWord32ShiftIsSafe);
+
+  R.binop = R.machine.Word32Shl();
+  CheckJsShift(&R);
+
+  R.binop = R.machine.Word32Shr();
+  CheckJsShift(&R);
+
+  R.binop = R.machine.Word32Sar();
+  CheckJsShift(&R);
+}
+
+
+TEST(Word32Equal) {
   ReducerTester R;
   R.binop = R.machine.Word32Equal();
 
@@ -476,9 +521,9 @@
 }
 
 
-TEST(ReduceInt32UDiv) {
+TEST(ReduceUint32Div) {
   ReducerTester R;
-  R.binop = R.machine.Int32UDiv();
+  R.binop = R.machine.Uint32Div();
 
   FOR_UINT32_INPUTS(pl) {
     FOR_UINT32_INPUTS(pr) {
@@ -529,9 +574,9 @@
 }
 
 
-TEST(ReduceInt32UMod) {
+TEST(ReduceUint32Mod) {
   ReducerTester R;
-  R.binop = R.machine.Int32UMod();
+  R.binop = R.machine.Uint32Mod();
 
   FOR_INT32_INPUTS(pl) {
     FOR_INT32_INPUTS(pr) {
@@ -687,9 +732,9 @@
          pr != nans.end(); ++pr) {
       Node* nan1 = R->Constant<double>(*pl);
       Node* nan2 = R->Constant<double>(*pr);
-      R->CheckBinop(nan1, x, nan1);     // x % NaN => NaN
-      R->CheckBinop(nan1, nan1, x);     // NaN % x => NaN
-      R->CheckBinop(nan1, nan2, nan1);  // NaN % NaN => NaN
+      R->CheckBinop(nan1, x, nan1);     // x op NaN => NaN
+      R->CheckBinop(nan1, nan1, x);     // NaN op x => NaN
+      R->CheckBinop(nan1, nan2, nan1);  // NaN op NaN => NaN
     }
   }
 }
@@ -706,8 +751,15 @@
     }
   }
 
-  FOR_FLOAT64_INPUTS(i) { R.CheckPutConstantOnRight(*i); }
-  // TODO(titzer): CheckNans(&R);
+  FOR_FLOAT64_INPUTS(i) {
+    Double tmp(*i);
+    if (!tmp.IsSpecial() || tmp.IsInfinite()) {
+      // Don't check NaNs as they are reduced more.
+      R.CheckPutConstantOnRight(*i);
+    }
+  }
+
+  CheckNans(&R);
 }
 
 
@@ -721,7 +773,13 @@
       R.CheckFoldBinop<double>(x - y, x, y);
     }
   }
-  // TODO(titzer): CheckNans(&R);
+
+  Node* zero = R.Constant<double>(0.0);
+  Node* x = R.Parameter();
+
+  R.CheckBinop(x, x, zero);  // x - 0.0 => x
+
+  CheckNans(&R);
 }
 
 
@@ -783,6 +841,11 @@
     }
   }
 
+  Node* x = R.Parameter();
+  Node* zero = R.Constant<double>(0.0);
+
+  R.CheckFoldBinop<double>(v8::base::OS::nan_value(), x, zero);
+
   CheckNans(&R);
 }
 
@@ -800,9 +863,9 @@
 // TODO(titzer): test MachineOperatorReducer for Int64Mul
 // TODO(titzer): test MachineOperatorReducer for Int64UMul
 // TODO(titzer): test MachineOperatorReducer for Int64Div
-// TODO(titzer): test MachineOperatorReducer for Int64UDiv
+// TODO(titzer): test MachineOperatorReducer for Uint64Div
 // TODO(titzer): test MachineOperatorReducer for Int64Mod
-// TODO(titzer): test MachineOperatorReducer for Int64UMod
+// TODO(titzer): test MachineOperatorReducer for Uint64Mod
 // TODO(titzer): test MachineOperatorReducer for Int64Neg
 // TODO(titzer): test MachineOperatorReducer for ChangeInt32ToFloat64
 // TODO(titzer): test MachineOperatorReducer for ChangeFloat64ToInt32
diff --git a/test/cctest/compiler/test-node-algorithm.cc b/test/cctest/compiler/test-node-algorithm.cc
index 10f98a6..842d182 100644
--- a/test/cctest/compiler/test-node-algorithm.cc
+++ b/test/cctest/compiler/test-node-algorithm.cc
@@ -8,25 +8,23 @@
 
 #include "graph-tester.h"
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/graph-visualizer.h"
+#include "src/compiler/node.h"
 #include "src/compiler/operator.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
-                                     0, 0, "dummy");
+static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
+                               "dummy", 0, 0, 0, 1, 0, 0);
 
 class PreNodeVisitor : public NullNodeVisitor {
  public:
-  GenericGraphVisit::Control Pre(Node* node) {
+  void Pre(Node* node) {
     printf("NODE ID: %d\n", node->id());
     nodes_.push_back(node);
-    return GenericGraphVisit::CONTINUE;
   }
   std::vector<Node*> nodes_;
 };
@@ -34,45 +32,14 @@
 
 class PostNodeVisitor : public NullNodeVisitor {
  public:
-  GenericGraphVisit::Control Post(Node* node) {
+  void Post(Node* node) {
     printf("NODE ID: %d\n", node->id());
     nodes_.push_back(node);
-    return GenericGraphVisit::CONTINUE;
   }
   std::vector<Node*> nodes_;
 };
 
 
-TEST(TestUseNodeVisitEmpty) {
-  GraphWithStartNodeTester graph;
-
-  PreNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(1, static_cast<int>(node_visitor.nodes_.size()));
-}
-
-
-TEST(TestUseNodePreOrderVisitSimple) {
-  GraphWithStartNodeTester graph;
-  Node* n2 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n3 = graph.NewNode(&dummy_operator, n2);
-  Node* n4 = graph.NewNode(&dummy_operator, n2, n3);
-  Node* n5 = graph.NewNode(&dummy_operator, n4, n2);
-  graph.SetEnd(n5);
-
-  PreNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(5, static_cast<int>(node_visitor.nodes_.size()));
-  CHECK(graph.start()->id() == node_visitor.nodes_[0]->id());
-  CHECK(n2->id() == node_visitor.nodes_[1]->id());
-  CHECK(n3->id() == node_visitor.nodes_[2]->id());
-  CHECK(n4->id() == node_visitor.nodes_[3]->id());
-  CHECK(n5->id() == node_visitor.nodes_[4]->id());
-}
-
-
 TEST(TestInputNodePreOrderVisitSimple) {
   GraphWithStartNodeTester graph;
   Node* n2 = graph.NewNode(&dummy_operator, graph.start());
@@ -92,223 +59,6 @@
 }
 
 
-TEST(TestUseNodePostOrderVisitSimple) {
-  GraphWithStartNodeTester graph;
-  Node* n2 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n3 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n4 = graph.NewNode(&dummy_operator, n2);
-  Node* n5 = graph.NewNode(&dummy_operator, n2);
-  Node* n6 = graph.NewNode(&dummy_operator, n2);
-  Node* n7 = graph.NewNode(&dummy_operator, n3);
-  Node* end_dependencies[4] = {n4, n5, n6, n7};
-  Node* n8 = graph.NewNode(&dummy_operator, 4, end_dependencies);
-  graph.SetEnd(n8);
-
-  PostNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(8, static_cast<int>(node_visitor.nodes_.size()));
-  CHECK(graph.end()->id() == node_visitor.nodes_[0]->id());
-  CHECK(n4->id() == node_visitor.nodes_[1]->id());
-  CHECK(n5->id() == node_visitor.nodes_[2]->id());
-  CHECK(n6->id() == node_visitor.nodes_[3]->id());
-  CHECK(n2->id() == node_visitor.nodes_[4]->id());
-  CHECK(n7->id() == node_visitor.nodes_[5]->id());
-  CHECK(n3->id() == node_visitor.nodes_[6]->id());
-  CHECK(graph.start()->id() == node_visitor.nodes_[7]->id());
-}
-
-
-TEST(TestUseNodePostOrderVisitLong) {
-  GraphWithStartNodeTester graph;
-  Node* n2 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n3 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n4 = graph.NewNode(&dummy_operator, n2);
-  Node* n5 = graph.NewNode(&dummy_operator, n2);
-  Node* n6 = graph.NewNode(&dummy_operator, n3);
-  Node* n7 = graph.NewNode(&dummy_operator, n3);
-  Node* n8 = graph.NewNode(&dummy_operator, n5);
-  Node* n9 = graph.NewNode(&dummy_operator, n5);
-  Node* n10 = graph.NewNode(&dummy_operator, n9);
-  Node* n11 = graph.NewNode(&dummy_operator, n9);
-  Node* end_dependencies[6] = {n4, n8, n10, n11, n6, n7};
-  Node* n12 = graph.NewNode(&dummy_operator, 6, end_dependencies);
-  graph.SetEnd(n12);
-
-  PostNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(12, static_cast<int>(node_visitor.nodes_.size()));
-  CHECK(graph.end()->id() == node_visitor.nodes_[0]->id());
-  CHECK(n4->id() == node_visitor.nodes_[1]->id());
-  CHECK(n8->id() == node_visitor.nodes_[2]->id());
-  CHECK(n10->id() == node_visitor.nodes_[3]->id());
-  CHECK(n11->id() == node_visitor.nodes_[4]->id());
-  CHECK(n9->id() == node_visitor.nodes_[5]->id());
-  CHECK(n5->id() == node_visitor.nodes_[6]->id());
-  CHECK(n2->id() == node_visitor.nodes_[7]->id());
-  CHECK(n6->id() == node_visitor.nodes_[8]->id());
-  CHECK(n7->id() == node_visitor.nodes_[9]->id());
-  CHECK(n3->id() == node_visitor.nodes_[10]->id());
-  CHECK(graph.start()->id() == node_visitor.nodes_[11]->id());
-}
-
-
-TEST(TestUseNodePreOrderVisitCycle) {
-  GraphWithStartNodeTester graph;
-  Node* n0 = graph.start_node();
-  Node* n1 = graph.NewNode(&dummy_operator, n0);
-  Node* n2 = graph.NewNode(&dummy_operator, n1);
-  n0->AppendInput(graph.main_zone(), n2);
-  graph.SetStart(n0);
-  graph.SetEnd(n2);
-
-  PreNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(3, static_cast<int>(node_visitor.nodes_.size()));
-  CHECK(n0->id() == node_visitor.nodes_[0]->id());
-  CHECK(n1->id() == node_visitor.nodes_[1]->id());
-  CHECK(n2->id() == node_visitor.nodes_[2]->id());
-}
-
-
-struct ReenterNodeVisitor : NullNodeVisitor {
-  GenericGraphVisit::Control Pre(Node* node) {
-    printf("[%d] PRE NODE: %d\n", static_cast<int>(nodes_.size()), node->id());
-    nodes_.push_back(node->id());
-    int size = static_cast<int>(nodes_.size());
-    switch (node->id()) {
-      case 0:
-        return size < 6 ? GenericGraphVisit::REENTER : GenericGraphVisit::SKIP;
-      case 1:
-        return size < 4 ? GenericGraphVisit::DEFER
-                        : GenericGraphVisit::CONTINUE;
-      default:
-        return GenericGraphVisit::REENTER;
-    }
-  }
-
-  GenericGraphVisit::Control Post(Node* node) {
-    printf("[%d] POST NODE: %d\n", static_cast<int>(nodes_.size()), node->id());
-    nodes_.push_back(-node->id());
-    return node->id() == 4 ? GenericGraphVisit::REENTER
-                           : GenericGraphVisit::CONTINUE;
-  }
-
-  void PreEdge(Node* from, int index, Node* to) {
-    printf("[%d] PRE EDGE: %d-%d\n", static_cast<int>(edges_.size()),
-           from->id(), to->id());
-    edges_.push_back(std::make_pair(from->id(), to->id()));
-  }
-
-  void PostEdge(Node* from, int index, Node* to) {
-    printf("[%d] POST EDGE: %d-%d\n", static_cast<int>(edges_.size()),
-           from->id(), to->id());
-    edges_.push_back(std::make_pair(-from->id(), -to->id()));
-  }
-
-  std::vector<int> nodes_;
-  std::vector<std::pair<int, int> > edges_;
-};
-
-
-TEST(TestUseNodeReenterVisit) {
-  GraphWithStartNodeTester graph;
-  Node* n0 = graph.start_node();
-  Node* n1 = graph.NewNode(&dummy_operator, n0);
-  Node* n2 = graph.NewNode(&dummy_operator, n0);
-  Node* n3 = graph.NewNode(&dummy_operator, n2);
-  Node* n4 = graph.NewNode(&dummy_operator, n0);
-  Node* n5 = graph.NewNode(&dummy_operator, n4);
-  n0->AppendInput(graph.main_zone(), n3);
-  graph.SetStart(n0);
-  graph.SetEnd(n5);
-
-  ReenterNodeVisitor visitor;
-  graph.VisitNodeUsesFromStart(&visitor);
-
-  CHECK_EQ(22, static_cast<int>(visitor.nodes_.size()));
-  CHECK_EQ(24, static_cast<int>(visitor.edges_.size()));
-
-  CHECK(n0->id() == visitor.nodes_[0]);
-  CHECK(n0->id() == visitor.edges_[0].first);
-  CHECK(n1->id() == visitor.edges_[0].second);
-  CHECK(n1->id() == visitor.nodes_[1]);
-  // N1 is deferred.
-  CHECK(-n1->id() == visitor.edges_[1].second);
-  CHECK(-n0->id() == visitor.edges_[1].first);
-  CHECK(n0->id() == visitor.edges_[2].first);
-  CHECK(n2->id() == visitor.edges_[2].second);
-  CHECK(n2->id() == visitor.nodes_[2]);
-  CHECK(n2->id() == visitor.edges_[3].first);
-  CHECK(n3->id() == visitor.edges_[3].second);
-  CHECK(n3->id() == visitor.nodes_[3]);
-  // Circle back to N0, which we may reenter for now.
-  CHECK(n3->id() == visitor.edges_[4].first);
-  CHECK(n0->id() == visitor.edges_[4].second);
-  CHECK(n0->id() == visitor.nodes_[4]);
-  CHECK(n0->id() == visitor.edges_[5].first);
-  CHECK(n1->id() == visitor.edges_[5].second);
-  CHECK(n1->id() == visitor.nodes_[5]);
-  // This time N1 is no longer deferred.
-  CHECK(-n1->id() == visitor.nodes_[6]);
-  CHECK(-n1->id() == visitor.edges_[6].second);
-  CHECK(-n0->id() == visitor.edges_[6].first);
-  CHECK(n0->id() == visitor.edges_[7].first);
-  CHECK(n2->id() == visitor.edges_[7].second);
-  CHECK(n2->id() == visitor.nodes_[7]);
-  CHECK(n2->id() == visitor.edges_[8].first);
-  CHECK(n3->id() == visitor.edges_[8].second);
-  CHECK(n3->id() == visitor.nodes_[8]);
-  CHECK(n3->id() == visitor.edges_[9].first);
-  CHECK(n0->id() == visitor.edges_[9].second);
-  CHECK(n0->id() == visitor.nodes_[9]);
-  // This time we break at N0 and skip it.
-  CHECK(-n0->id() == visitor.edges_[10].second);
-  CHECK(-n3->id() == visitor.edges_[10].first);
-  CHECK(-n3->id() == visitor.nodes_[10]);
-  CHECK(-n3->id() == visitor.edges_[11].second);
-  CHECK(-n2->id() == visitor.edges_[11].first);
-  CHECK(-n2->id() == visitor.nodes_[11]);
-  CHECK(-n2->id() == visitor.edges_[12].second);
-  CHECK(-n0->id() == visitor.edges_[12].first);
-  CHECK(n0->id() == visitor.edges_[13].first);
-  CHECK(n4->id() == visitor.edges_[13].second);
-  CHECK(n4->id() == visitor.nodes_[12]);
-  CHECK(n4->id() == visitor.edges_[14].first);
-  CHECK(n5->id() == visitor.edges_[14].second);
-  CHECK(n5->id() == visitor.nodes_[13]);
-  CHECK(-n5->id() == visitor.nodes_[14]);
-  CHECK(-n5->id() == visitor.edges_[15].second);
-  CHECK(-n4->id() == visitor.edges_[15].first);
-  CHECK(-n4->id() == visitor.nodes_[15]);
-  CHECK(-n4->id() == visitor.edges_[16].second);
-  CHECK(-n0->id() == visitor.edges_[16].first);
-  CHECK(-n0->id() == visitor.nodes_[16]);
-  CHECK(-n0->id() == visitor.edges_[17].second);
-  CHECK(-n3->id() == visitor.edges_[17].first);
-  CHECK(-n3->id() == visitor.nodes_[17]);
-  CHECK(-n3->id() == visitor.edges_[18].second);
-  CHECK(-n2->id() == visitor.edges_[18].first);
-  CHECK(-n2->id() == visitor.nodes_[18]);
-  CHECK(-n2->id() == visitor.edges_[19].second);
-  CHECK(-n0->id() == visitor.edges_[19].first);
-  // N4 may be reentered.
-  CHECK(n0->id() == visitor.edges_[20].first);
-  CHECK(n4->id() == visitor.edges_[20].second);
-  CHECK(n4->id() == visitor.nodes_[19]);
-  CHECK(n4->id() == visitor.edges_[21].first);
-  CHECK(n5->id() == visitor.edges_[21].second);
-  CHECK(-n5->id() == visitor.edges_[22].second);
-  CHECK(-n4->id() == visitor.edges_[22].first);
-  CHECK(-n4->id() == visitor.nodes_[20]);
-  CHECK(-n4->id() == visitor.edges_[23].second);
-  CHECK(-n0->id() == visitor.edges_[23].first);
-  CHECK(-n0->id() == visitor.nodes_[21]);
-}
-
-
 TEST(TestPrintNodeGraphToNodeGraphviz) {
   GraphWithStartNodeTester graph;
   Node* n2 = graph.NewNode(&dummy_operator, graph.start());
diff --git a/test/cctest/compiler/test-node-cache.cc b/test/cctest/compiler/test-node-cache.cc
index 3569386..a48adb9 100644
--- a/test/cctest/compiler/test-node-cache.cc
+++ b/test/cctest/compiler/test-node-cache.cc
@@ -115,46 +115,61 @@
 }
 
 
-TEST(PtrConstant_back_to_back) {
-  GraphTester graph;
-  PtrNodeCache cache;
-  int32_t buffer[50];
+static bool Contains(NodeVector* nodes, Node* n) {
+  for (size_t i = 0; i < nodes->size(); i++) {
+    if (nodes->at(i) == n) return true;
+  }
+  return false;
+}
 
-  for (int32_t* p = buffer;
-       (p - buffer) < static_cast<ptrdiff_t>(arraysize(buffer)); p++) {
-    Node** pos = cache.Find(graph.zone(), p);
-    CHECK_NE(NULL, pos);
-    for (int j = 0; j < 3; j++) {
-      Node** npos = cache.Find(graph.zone(), p);
-      CHECK_EQ(pos, npos);
+
+TEST(NodeCache_GetCachedNodes_int32) {
+  GraphTester graph;
+  Int32NodeCache cache;
+  CommonOperatorBuilder common(graph.zone());
+
+  int32_t constants[] = {0, 311, 12,  13,  14,  555, -555, -44, -33, -22, -11,
+                         0, 311, 311, 412, 412, 11,  11,   -33, -33, -22, -11};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int32_t k = constants[i];
+    Node** pos = cache.Find(graph.zone(), k);
+    if (*pos != NULL) {
+      NodeVector nodes(graph.zone());
+      cache.GetCachedNodes(&nodes);
+      CHECK(Contains(&nodes, *pos));
+    } else {
+      NodeVector nodes(graph.zone());
+      Node* n = graph.NewNode(common.Int32Constant(k));
+      *pos = n;
+      cache.GetCachedNodes(&nodes);
+      CHECK(Contains(&nodes, n));
     }
   }
 }
 
 
-TEST(PtrConstant_hits) {
+TEST(NodeCache_GetCachedNodes_int64) {
   GraphTester graph;
-  PtrNodeCache cache;
-  const int32_t kSize = 50;
-  int32_t buffer[kSize];
-  Node* nodes[kSize];
+  Int64NodeCache cache;
   CommonOperatorBuilder common(graph.zone());
 
-  for (size_t i = 0; i < arraysize(buffer); i++) {
-    int k = static_cast<int>(i);
-    int32_t* p = &buffer[i];
-    nodes[i] = graph.NewNode(common.Int32Constant(k));
-    *cache.Find(graph.zone(), p) = nodes[i];
-  }
+  int64_t constants[] = {0, 311, 12,  13,  14,  555, -555, -44, -33, -22, -11,
+                         0, 311, 311, 412, 412, 11,  11,   -33, -33, -22, -11};
 
-  int hits = 0;
-  for (size_t i = 0; i < arraysize(buffer); i++) {
-    int32_t* p = &buffer[i];
-    Node** pos = cache.Find(graph.zone(), p);
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int64_t k = constants[i];
+    Node** pos = cache.Find(graph.zone(), k);
     if (*pos != NULL) {
-      CHECK_EQ(nodes[i], *pos);
-      hits++;
+      NodeVector nodes(graph.zone());
+      cache.GetCachedNodes(&nodes);
+      CHECK(Contains(&nodes, *pos));
+    } else {
+      NodeVector nodes(graph.zone());
+      Node* n = graph.NewNode(common.Int64Constant(k));
+      *pos = n;
+      cache.GetCachedNodes(&nodes);
+      CHECK(Contains(&nodes, n));
     }
   }
-  CHECK_LT(4, hits);
 }
diff --git a/test/cctest/compiler/test-node.cc b/test/cctest/compiler/test-node.cc
index 28d807e..eafabd3 100644
--- a/test/cctest/compiler/test-node.cc
+++ b/test/cctest/compiler/test-node.cc
@@ -7,15 +7,14 @@
 #include "src/v8.h"
 
 #include "graph-tester.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/node.h"
 #include "src/compiler/operator.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
-                                     0, 0, "dummy");
+static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
+                               "dummy", 0, 0, 0, 1, 0, 0);
 
 TEST(NodeAllocation) {
   GraphTester graph;
@@ -93,10 +92,8 @@
 TEST(NodeUseIteratorEmpty) {
   GraphTester graph;
   Node* n1 = graph.NewNode(&dummy_operator);
-  Node::Uses::iterator i(n1->uses().begin());
   int use_count = 0;
-  for (; i != n1->uses().end(); ++i) {
-    Node::Edge edge(i.edge());
+  for (Edge const edge : n1->use_edges()) {
     USE(edge);
     use_count++;
   }
@@ -366,31 +363,31 @@
   Node* n1 = graph.NewNode(&dummy_operator, n0);
   Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
 
-  Node::Inputs inputs(n2->inputs());
-  Node::Inputs::iterator current = inputs.begin();
+  Node::InputEdges inputs(n2->input_edges());
+  Node::InputEdges::iterator current = inputs.begin();
   CHECK(current != inputs.end());
-  CHECK(*current == n0);
+  CHECK((*current).to() == n0);
   ++current;
   CHECK(current != inputs.end());
-  CHECK(*current == n1);
+  CHECK((*current).to() == n1);
   ++current;
   CHECK(current == inputs.end());
 
   Node* n3 = graph.NewNode(&dummy_operator);
   n2->AppendInput(graph.zone(), n3);
-  inputs = n2->inputs();
+  inputs = n2->input_edges();
   current = inputs.begin();
   CHECK(current != inputs.end());
-  CHECK(*current == n0);
-  CHECK_EQ(0, current.index());
+  CHECK((*current).to() == n0);
+  CHECK_EQ(0, (*current).index());
   ++current;
   CHECK(current != inputs.end());
-  CHECK(*current == n1);
-  CHECK_EQ(1, current.index());
+  CHECK((*current).to() == n1);
+  CHECK_EQ(1, (*current).index());
   ++current;
   CHECK(current != inputs.end());
-  CHECK(*current == n3);
-  CHECK_EQ(2, current.index());
+  CHECK((*current).to() == n3);
+  CHECK_EQ(2, (*current).index());
   ++current;
   CHECK(current == inputs.end());
 }
diff --git a/test/cctest/compiler/test-operator.cc b/test/cctest/compiler/test-operator.cc
index af75d67..39f660f 100644
--- a/test/cctest/compiler/test-operator.cc
+++ b/test/cctest/compiler/test-operator.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <sstream>
+
 #include "src/v8.h"
 
 #include "src/compiler/operator.h"
@@ -10,44 +12,45 @@
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-#define NaN (v8::base::OS::nan_value())
-#define Infinity (std::numeric_limits<double>::infinity())
+#define NONE Operator::kNoProperties
+#define FOLD Operator::kFoldable
 
-TEST(TestOperatorMnemonic) {
-  SimpleOperator op1(10, Operator::kNoProperties, 0, 0, "ThisOne");
+
+TEST(TestOperator_Mnemonic) {
+  Operator op1(10, NONE, "ThisOne", 0, 0, 0, 0, 0, 0);
   CHECK_EQ(0, strcmp(op1.mnemonic(), "ThisOne"));
 
-  SimpleOperator op2(11, Operator::kNoProperties, 0, 0, "ThatOne");
+  Operator op2(11, NONE, "ThatOne", 0, 0, 0, 0, 0, 0);
   CHECK_EQ(0, strcmp(op2.mnemonic(), "ThatOne"));
 
-  Operator1<int> op3(12, Operator::kNoProperties, 0, 1, "Mnemonic1", 12333);
+  Operator1<int> op3(12, NONE, "Mnemonic1", 0, 0, 0, 1, 0, 0, 12333);
   CHECK_EQ(0, strcmp(op3.mnemonic(), "Mnemonic1"));
 
-  Operator1<double> op4(13, Operator::kNoProperties, 0, 1, "TheOther", 99.9);
+  Operator1<double> op4(13, NONE, "TheOther", 0, 0, 0, 1, 0, 0, 99.9);
   CHECK_EQ(0, strcmp(op4.mnemonic(), "TheOther"));
 }
 
 
-TEST(TestSimpleOperatorHash) {
-  SimpleOperator op1(17, Operator::kNoProperties, 0, 0, "Another");
-  CHECK_EQ(17, op1.HashCode());
+TEST(TestOperator_Hash) {
+  Operator op1(17, NONE, "Another", 0, 0, 0, 0, 0, 0);
+  CHECK_EQ(17, static_cast<int>(op1.HashCode()));
 
-  SimpleOperator op2(18, Operator::kNoProperties, 0, 0, "Falsch");
-  CHECK_EQ(18, op2.HashCode());
+  Operator op2(18, NONE, "Falsch", 0, 0, 0, 0, 0, 0);
+  CHECK_EQ(18, static_cast<int>(op2.HashCode()));
 }
 
 
-TEST(TestSimpleOperatorEquals) {
-  SimpleOperator op1a(19, Operator::kNoProperties, 0, 0, "Another1");
-  SimpleOperator op1b(19, Operator::kFoldable, 2, 2, "Another2");
+TEST(TestOperator_Equals) {
+  Operator op1a(19, NONE, "Another1", 0, 0, 0, 0, 0, 0);
+  Operator op1b(19, FOLD, "Another2", 2, 0, 0, 2, 0, 0);
 
   CHECK(op1a.Equals(&op1a));
   CHECK(op1a.Equals(&op1b));
   CHECK(op1b.Equals(&op1a));
   CHECK(op1b.Equals(&op1b));
 
-  SimpleOperator op2a(20, Operator::kNoProperties, 0, 0, "Falsch1");
-  SimpleOperator op2b(20, Operator::kFoldable, 1, 1, "Falsch2");
+  Operator op2a(20, NONE, "Falsch1", 0, 0, 0, 0, 0, 0);
+  Operator op2b(20, FOLD, "Falsch2", 1, 0, 0, 1, 0, 0);
 
   CHECK(op2a.Equals(&op2a));
   CHECK(op2a.Equals(&op2b));
@@ -67,52 +70,52 @@
 
 
 static SmartArrayPointer<const char> OperatorToString(Operator* op) {
-  OStringStream os;
+  std::ostringstream os;
   os << *op;
-  return SmartArrayPointer<const char>(StrDup(os.c_str()));
+  return SmartArrayPointer<const char>(StrDup(os.str().c_str()));
 }
 
 
-TEST(TestSimpleOperatorPrint) {
-  SimpleOperator op1a(19, Operator::kNoProperties, 0, 0, "Another1");
-  SimpleOperator op1b(19, Operator::kFoldable, 2, 2, "Another2");
+TEST(TestOperator_Print) {
+  Operator op1a(19, NONE, "Another1", 0, 0, 0, 0, 0, 0);
+  Operator op1b(19, FOLD, "Another2", 2, 0, 0, 2, 0, 0);
 
   CHECK_EQ("Another1", OperatorToString(&op1a).get());
   CHECK_EQ("Another2", OperatorToString(&op1b).get());
 
-  SimpleOperator op2a(20, Operator::kNoProperties, 0, 0, "Flog1");
-  SimpleOperator op2b(20, Operator::kFoldable, 1, 1, "Flog2");
+  Operator op2a(20, NONE, "Flog1", 0, 0, 0, 0, 0, 0);
+  Operator op2b(20, FOLD, "Flog2", 1, 0, 0, 1, 0, 0);
 
   CHECK_EQ("Flog1", OperatorToString(&op2a).get());
   CHECK_EQ("Flog2", OperatorToString(&op2b).get());
 }
 
 
-TEST(TestOperator1intHash) {
-  Operator1<int> op1a(23, Operator::kNoProperties, 0, 0, "Wolfie", 11);
-  Operator1<int> op1b(23, Operator::kFoldable, 2, 2, "Doggie", 11);
+TEST(TestOperator1int_Hash) {
+  Operator1<int> op1a(23, NONE, "Wolfie", 0, 0, 0, 0, 0, 0, 11);
+  Operator1<int> op1b(23, FOLD, "Doggie", 2, 0, 0, 2, 0, 0, 11);
 
-  CHECK_EQ(op1a.HashCode(), op1b.HashCode());
+  CHECK(op1a.HashCode() == op1b.HashCode());
 
-  Operator1<int> op2a(24, Operator::kNoProperties, 0, 0, "Arfie", 3);
-  Operator1<int> op2b(24, Operator::kNoProperties, 0, 0, "Arfie", 4);
+  Operator1<int> op2a(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, 3);
+  Operator1<int> op2b(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, 4);
 
-  CHECK_NE(op1a.HashCode(), op2a.HashCode());
-  CHECK_NE(op2a.HashCode(), op2b.HashCode());
+  CHECK(op1a.HashCode() != op2a.HashCode());
+  CHECK(op2a.HashCode() != op2b.HashCode());
 }
 
 
-TEST(TestOperator1intEquals) {
-  Operator1<int> op1a(23, Operator::kNoProperties, 0, 0, "Scratchy", 11);
-  Operator1<int> op1b(23, Operator::kFoldable, 2, 2, "Scratchy", 11);
+TEST(TestOperator1int_Equals) {
+  Operator1<int> op1a(23, NONE, "Scratchy", 0, 0, 0, 0, 0, 0, 11);
+  Operator1<int> op1b(23, FOLD, "Scratchy", 2, 0, 0, 2, 0, 0, 11);
 
   CHECK(op1a.Equals(&op1a));
   CHECK(op1a.Equals(&op1b));
   CHECK(op1b.Equals(&op1a));
   CHECK(op1b.Equals(&op1b));
 
-  Operator1<int> op2a(24, Operator::kNoProperties, 0, 0, "Im", 3);
-  Operator1<int> op2b(24, Operator::kNoProperties, 0, 0, "Im", 4);
+  Operator1<int> op2a(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 3);
+  Operator1<int> op2b(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 4);
 
   CHECK(op2a.Equals(&op2a));
   CHECK(!op2a.Equals(&op2b));
@@ -129,7 +132,7 @@
   CHECK(!op2b.Equals(&op1a));
   CHECK(!op2b.Equals(&op1b));
 
-  SimpleOperator op3(25, Operator::kNoProperties, 0, 0, "Weepy");
+  Operator op3(25, NONE, "Weepy", 0, 0, 0, 0, 0, 0);
 
   CHECK(!op1a.Equals(&op3));
   CHECK(!op1b.Equals(&op3));
@@ -143,46 +146,55 @@
 }
 
 
-TEST(TestOperator1intPrint) {
-  Operator1<int> op1(12, Operator::kNoProperties, 0, 1, "Op1Test", 0);
+TEST(TestOperator1int_Print) {
+  Operator1<int> op1(12, NONE, "Op1Test", 0, 0, 0, 1, 0, 0, 0);
   CHECK_EQ("Op1Test[0]", OperatorToString(&op1).get());
 
-  Operator1<int> op2(12, Operator::kNoProperties, 0, 1, "Op1Test", 66666666);
+  Operator1<int> op2(12, NONE, "Op1Test", 0, 0, 0, 1, 0, 0, 66666666);
   CHECK_EQ("Op1Test[66666666]", OperatorToString(&op2).get());
 
-  Operator1<int> op3(12, Operator::kNoProperties, 0, 1, "FooBar", 2347);
+  Operator1<int> op3(12, NONE, "FooBar", 0, 0, 0, 1, 0, 0, 2347);
   CHECK_EQ("FooBar[2347]", OperatorToString(&op3).get());
 
-  Operator1<int> op4(12, Operator::kNoProperties, 0, 1, "BarFoo", -879);
+  Operator1<int> op4(12, NONE, "BarFoo", 0, 0, 0, 1, 0, 0, -879);
   CHECK_EQ("BarFoo[-879]", OperatorToString(&op4).get());
 }
 
 
-TEST(TestOperator1doubleHash) {
-  Operator1<double> op1a(23, Operator::kNoProperties, 0, 0, "Wolfie", 11.77);
-  Operator1<double> op1b(23, Operator::kFoldable, 2, 2, "Doggie", 11.77);
+TEST(TestOperator1double_Hash) {
+  Operator1<double> op1a(23, NONE, "Wolfie", 0, 0, 0, 0, 0, 0, 11.77);
+  Operator1<double> op1b(23, FOLD, "Doggie", 2, 0, 0, 2, 0, 0, 11.77);
 
-  CHECK_EQ(op1a.HashCode(), op1b.HashCode());
+  CHECK(op1a.HashCode() == op1b.HashCode());
 
-  Operator1<double> op2a(24, Operator::kNoProperties, 0, 0, "Arfie", -6.7);
-  Operator1<double> op2b(24, Operator::kNoProperties, 0, 0, "Arfie", -6.8);
+  Operator1<double> op2a(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, -6.7);
+  Operator1<double> op2b(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, -6.8);
 
-  CHECK_NE(op1a.HashCode(), op2a.HashCode());
-  CHECK_NE(op2a.HashCode(), op2b.HashCode());
+  CHECK(op1a.HashCode() != op2a.HashCode());
+  CHECK(op2a.HashCode() != op2b.HashCode());
 }
 
 
-TEST(TestOperator1doubleEquals) {
-  Operator1<double> op1a(23, Operator::kNoProperties, 0, 0, "Scratchy", 11.77);
-  Operator1<double> op1b(23, Operator::kFoldable, 2, 2, "Scratchy", 11.77);
+TEST(TestOperator1doublePrint) {
+  Operator1<double> op1a(23, NONE, "Canary", 0, 0, 0, 0, 0, 0, 0.5);
+  Operator1<double> op1b(23, FOLD, "Finch", 2, 0, 0, 2, 0, 0, -1.5);
+
+  CHECK_EQ("Canary[0.5]", OperatorToString(&op1a).get());
+  CHECK_EQ("Finch[-1.5]", OperatorToString(&op1b).get());
+}
+
+
+TEST(TestOperator1double_Equals) {
+  Operator1<double> op1a(23, NONE, "Scratchy", 0, 0, 0, 0, 0, 0, 11.77);
+  Operator1<double> op1b(23, FOLD, "Scratchy", 2, 0, 0, 2, 0, 0, 11.77);
 
   CHECK(op1a.Equals(&op1a));
   CHECK(op1a.Equals(&op1b));
   CHECK(op1b.Equals(&op1a));
   CHECK(op1b.Equals(&op1b));
 
-  Operator1<double> op2a(24, Operator::kNoProperties, 0, 0, "Im", 3.1);
-  Operator1<double> op2b(24, Operator::kNoProperties, 0, 0, "Im", 3.2);
+  Operator1<double> op2a(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 3.1);
+  Operator1<double> op2b(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 3.2);
 
   CHECK(op2a.Equals(&op2a));
   CHECK(!op2a.Equals(&op2b));
@@ -199,7 +211,7 @@
   CHECK(!op2b.Equals(&op1a));
   CHECK(!op2b.Equals(&op1b));
 
-  SimpleOperator op3(25, Operator::kNoProperties, 0, 0, "Weepy");
+  Operator op3(25, NONE, "Weepy", 0, 0, 0, 0, 0, 0);
 
   CHECK(!op1a.Equals(&op3));
   CHECK(!op1b.Equals(&op3));
@@ -211,8 +223,8 @@
   CHECK(!op3.Equals(&op2a));
   CHECK(!op3.Equals(&op2b));
 
-  Operator1<double> op4a(24, Operator::kNoProperties, 0, 0, "Bashful", NaN);
-  Operator1<double> op4b(24, Operator::kNoProperties, 0, 0, "Bashful", NaN);
+  Operator1<double> op4a(24, NONE, "Bashful", 0, 0, 0, 0, 0, 0, 1.0);
+  Operator1<double> op4b(24, NONE, "Bashful", 0, 0, 0, 0, 0, 0, 1.0);
 
   CHECK(op4a.Equals(&op4a));
   CHECK(op4a.Equals(&op4b));
@@ -226,19 +238,46 @@
 }
 
 
-TEST(TestOperator1doublePrint) {
-  Operator1<double> op1(12, Operator::kNoProperties, 0, 1, "Op1Test", 0);
-  CHECK_EQ("Op1Test[0]", OperatorToString(&op1).get());
+TEST(TestOpParameter_Operator1double) {
+  double values[] = {7777.5, -66, 0, 11, 0.1};
 
-  Operator1<double> op2(12, Operator::kNoProperties, 0, 1, "Op1Test", 7.3);
-  CHECK_EQ("Op1Test[7.3]", OperatorToString(&op2).get());
+  for (size_t i = 0; i < arraysize(values); i++) {
+    Operator1<double> op(33, NONE, "Scurvy", 0, 0, 0, 0, 0, 0, values[i]);
+    CHECK_EQ(values[i], OpParameter<double>(&op));
+  }
+}
 
-  Operator1<double> op3(12, Operator::kNoProperties, 0, 1, "FooBar", 2e+123);
-  CHECK_EQ("FooBar[2e+123]", OperatorToString(&op3).get());
 
-  Operator1<double> op4(12, Operator::kNoProperties, 0, 1, "BarFoo", Infinity);
-  CHECK_EQ("BarFoo[inf]", OperatorToString(&op4).get());
+TEST(TestOpParameter_Operator1float) {
+  float values[] = {// thanks C++.
+                    static_cast<float>(7777.5), static_cast<float>(-66),
+                    static_cast<float>(0), static_cast<float>(11),
+                    static_cast<float>(0.1)};
 
-  Operator1<double> op5(12, Operator::kNoProperties, 0, 1, "BarFoo", NaN);
-  CHECK_EQ("BarFoo[nan]", OperatorToString(&op5).get());
+  for (size_t i = 0; i < arraysize(values); i++) {
+    Operator1<float> op(33, NONE, "Scurvy", 0, 0, 0, 0, 0, 0, values[i]);
+    CHECK_EQ(values[i], OpParameter<float>(&op));
+  }
+}
+
+
+TEST(TestOpParameter_Operator1int) {
+  int values[] = {7777, -66, 0, 11, 1, 0x666aff};
+
+  for (size_t i = 0; i < arraysize(values); i++) {
+    Operator1<int> op(33, NONE, "Scurvy", 0, 0, 0, 0, 0, 0, values[i]);
+    CHECK_EQ(values[i], OpParameter<int>(&op));
+  }
+}
+
+
+TEST(Operator_CountsOrder) {
+  Operator op(29, NONE, "Flashy", 11, 22, 33, 44, 55, 66);
+  CHECK_EQ(11, op.ValueInputCount());
+  CHECK_EQ(22, op.EffectInputCount());
+  CHECK_EQ(33, op.ControlInputCount());
+
+  CHECK_EQ(44, op.ValueOutputCount());
+  CHECK_EQ(55, op.EffectOutputCount());
+  CHECK_EQ(66, op.ControlOutputCount());
 }
diff --git a/test/cctest/compiler/test-phi-reducer.cc b/test/cctest/compiler/test-phi-reducer.cc
deleted file mode 100644
index 7d2fab6..0000000
--- a/test/cctest/compiler/test-phi-reducer.cc
+++ /dev/null
@@ -1,230 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/v8.h"
-#include "test/cctest/cctest.h"
-
-#include "src/compiler/common-operator.h"
-#include "src/compiler/graph-inl.h"
-#include "src/compiler/phi-reducer.h"
-
-using namespace v8::internal;
-using namespace v8::internal::compiler;
-
-class PhiReducerTester : HandleAndZoneScope {
- public:
-  explicit PhiReducerTester(int num_parameters = 0)
-      : isolate(main_isolate()),
-        common(main_zone()),
-        graph(main_zone()),
-        self(graph.NewNode(common.Start(num_parameters))),
-        dead(graph.NewNode(common.Dead())) {
-    graph.SetStart(self);
-  }
-
-  Isolate* isolate;
-  CommonOperatorBuilder common;
-  Graph graph;
-  Node* self;
-  Node* dead;
-
-  void CheckReduce(Node* expect, Node* phi) {
-    PhiReducer reducer;
-    Reduction reduction = reducer.Reduce(phi);
-    if (expect == phi) {
-      CHECK(!reduction.Changed());
-    } else {
-      CHECK(reduction.Changed());
-      CHECK_EQ(expect, reduction.replacement());
-    }
-  }
-
-  Node* Int32Constant(int32_t val) {
-    return graph.NewNode(common.Int32Constant(val));
-  }
-
-  Node* Float64Constant(double val) {
-    return graph.NewNode(common.Float64Constant(val));
-  }
-
-  Node* Parameter(int32_t index = 0) {
-    return graph.NewNode(common.Parameter(index), graph.start());
-  }
-
-  Node* Phi(Node* a) {
-    return SetSelfReferences(graph.NewNode(common.Phi(kMachAnyTagged, 1), a));
-  }
-
-  Node* Phi(Node* a, Node* b) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 2), a, b));
-  }
-
-  Node* Phi(Node* a, Node* b, Node* c) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 3), a, b, c));
-  }
-
-  Node* Phi(Node* a, Node* b, Node* c, Node* d) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 4), a, b, c, d));
-  }
-
-  Node* PhiWithControl(Node* a, Node* control) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 1), a, control));
-  }
-
-  Node* PhiWithControl(Node* a, Node* b, Node* control) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 2), a, b, control));
-  }
-
-  Node* SetSelfReferences(Node* node) {
-    Node::Inputs inputs = node->inputs();
-    for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
-         ++iter) {
-      Node* input = *iter;
-      if (input == self) node->ReplaceInput(iter.index(), node);
-    }
-    return node;
-  }
-};
-
-
-TEST(PhiReduce1) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    R.CheckReduce(singles[i], R.Phi(singles[i]));
-  }
-}
-
-
-TEST(PhiReduce2) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(a, a));
-  }
-
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(R.self, a));
-    R.CheckReduce(a, R.Phi(a, R.self));
-  }
-
-  for (size_t i = 1; i < arraysize(singles); i++) {
-    Node* a = singles[i], *b = singles[0];
-    Node* phi1 = R.Phi(b, a);
-    R.CheckReduce(phi1, phi1);
-
-    Node* phi2 = R.Phi(a, b);
-    R.CheckReduce(phi2, phi2);
-  }
-}
-
-
-TEST(PhiReduce3) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(a, a, a));
-  }
-
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(R.self, a, a));
-    R.CheckReduce(a, R.Phi(a, R.self, a));
-    R.CheckReduce(a, R.Phi(a, a, R.self));
-  }
-
-  for (size_t i = 1; i < arraysize(singles); i++) {
-    Node* a = singles[i], *b = singles[0];
-    Node* phi1 = R.Phi(b, a, a);
-    R.CheckReduce(phi1, phi1);
-
-    Node* phi2 = R.Phi(a, b, a);
-    R.CheckReduce(phi2, phi2);
-
-    Node* phi3 = R.Phi(a, a, b);
-    R.CheckReduce(phi3, phi3);
-  }
-}
-
-
-TEST(PhiReduce4) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(a, a, a, a));
-  }
-
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(R.self, a, a, a));
-    R.CheckReduce(a, R.Phi(a, R.self, a, a));
-    R.CheckReduce(a, R.Phi(a, a, R.self, a));
-    R.CheckReduce(a, R.Phi(a, a, a, R.self));
-
-    R.CheckReduce(a, R.Phi(R.self, R.self, a, a));
-    R.CheckReduce(a, R.Phi(a, R.self, R.self, a));
-    R.CheckReduce(a, R.Phi(a, a, R.self, R.self));
-    R.CheckReduce(a, R.Phi(R.self, a, a, R.self));
-  }
-
-  for (size_t i = 1; i < arraysize(singles); i++) {
-    Node* a = singles[i], *b = singles[0];
-    Node* phi1 = R.Phi(b, a, a, a);
-    R.CheckReduce(phi1, phi1);
-
-    Node* phi2 = R.Phi(a, b, a, a);
-    R.CheckReduce(phi2, phi2);
-
-    Node* phi3 = R.Phi(a, a, b, a);
-    R.CheckReduce(phi3, phi3);
-
-    Node* phi4 = R.Phi(a, a, a, b);
-    R.CheckReduce(phi4, phi4);
-  }
-}
-
-
-TEST(PhiReduceShouldIgnoreControlNodes) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); ++i) {
-    R.CheckReduce(singles[i], R.PhiWithControl(singles[i], R.dead));
-    R.CheckReduce(singles[i], R.PhiWithControl(R.self, singles[i], R.dead));
-    R.CheckReduce(singles[i], R.PhiWithControl(singles[i], R.self, R.dead));
-  }
-}
diff --git a/test/cctest/compiler/test-pipeline.cc b/test/cctest/compiler/test-pipeline.cc
index f0b750a..98b0bae 100644
--- a/test/cctest/compiler/test-pipeline.cc
+++ b/test/cctest/compiler/test-pipeline.cc
@@ -5,6 +5,7 @@
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
 
+#include "src/ast-numbering.h"
 #include "src/compiler.h"
 #include "src/compiler/pipeline.h"
 #include "src/handles.h"
@@ -22,10 +23,7 @@
       *v8::Handle<v8::Function>::Cast(CompileRun(source)));
   CompilationInfoWithZone info(function);
 
-  CHECK(Parser::Parse(&info));
-  CHECK(Rewriter::Rewrite(&info));
-  CHECK(Scope::Analyze(&info));
-  CHECK_NE(NULL, info.scope());
+  CHECK(Compiler::ParseAndAnalyze(&info));
 
   Pipeline pipeline(&info);
 #if V8_TURBOFAN_TARGET
diff --git a/test/cctest/compiler/test-representation-change.cc b/test/cctest/compiler/test-representation-change.cc
index 6c9026b..2dc3029 100644
--- a/test/cctest/compiler/test-representation-change.cc
+++ b/test/cctest/compiler/test-representation-change.cc
@@ -7,10 +7,10 @@
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
 #include "test/cctest/compiler/graph-builder-tester.h"
+#include "test/cctest/compiler/value-helper.h"
 
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/representation-change.h"
-#include "src/compiler/typer.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
@@ -24,16 +24,13 @@
  public:
   explicit RepresentationChangerTester(int num_parameters = 0)
       : GraphAndBuilders(main_zone()),
-        typer_(main_zone()),
         javascript_(main_zone()),
-        jsgraph_(main_graph_, &main_common_, &javascript_, &typer_,
-                 &main_machine_),
+        jsgraph_(main_graph_, &main_common_, &javascript_, &main_machine_),
         changer_(&jsgraph_, &main_simplified_, main_isolate()) {
     Node* s = graph()->NewNode(common()->Start(num_parameters));
     graph()->SetStart(s);
   }
 
-  Typer typer_;
   JSOperatorBuilder javascript_;
   JSGraph jsgraph_;
   RepresentationChanger changer_;
@@ -51,6 +48,24 @@
     CHECK_EQ(expected, m.Value());
   }
 
+  void CheckUint32Constant(Node* n, uint32_t expected) {
+    Uint32Matcher m(n);
+    CHECK(m.HasValue());
+    CHECK_EQ(static_cast<int>(expected), static_cast<int>(m.Value()));
+  }
+
+  void CheckFloat64Constant(Node* n, double expected) {
+    Float64Matcher m(n);
+    CHECK(m.HasValue());
+    CHECK_EQ(expected, m.Value());
+  }
+
+  void CheckFloat32Constant(Node* n, float expected) {
+    CHECK_EQ(IrOpcode::kFloat32Constant, n->opcode());
+    float fval = OpParameter<float>(n->op());
+    CHECK_EQ(expected, fval);
+  }
+
   void CheckHeapConstant(Node* n, HeapObject* expected) {
     HeapObjectMatcher<HeapObject> m(n);
     CHECK(m.HasValue());
@@ -88,28 +103,8 @@
 }  // namespace v8::internal::compiler
 
 
-// TODO(titzer): add kRepFloat32 when fully supported.
-static const MachineType all_reps[] = {kRepBit, kRepWord32, kRepWord64,
-                                       kRepFloat64, kRepTagged};
-
-
-// TODO(titzer): lift this to ValueHelper
-static const double double_inputs[] = {
-    0.0,   -0.0,    1.0,    -1.0,        0.1,         1.4,    -1.7,
-    2,     5,       6,      982983,      888,         -999.8, 3.1e7,
-    -2e66, 2.3e124, -12e73, V8_INFINITY, -V8_INFINITY};
-
-
-static const int32_t int32_inputs[] = {
-    0,      1,                                -1,
-    2,      5,                                6,
-    982983, 888,                              -999,
-    65535,  static_cast<int32_t>(0xFFFFFFFF), static_cast<int32_t>(0x80000000)};
-
-
-static const uint32_t uint32_inputs[] = {
-    0,      1,   static_cast<uint32_t>(-1),   2,     5,          6,
-    982983, 888, static_cast<uint32_t>(-999), 65535, 0xFFFFFFFF, 0x80000000};
+static const MachineType all_reps[] = {kRepBit,     kRepWord32,  kRepWord64,
+                                       kRepFloat32, kRepFloat64, kRepTagged};
 
 
 TEST(BoolToBit_constant) {
@@ -142,24 +137,234 @@
 TEST(ToTagged_constant) {
   RepresentationChangerTester r;
 
-  for (size_t i = 0; i < arraysize(double_inputs); i++) {
-    Node* n = r.jsgraph()->Float64Constant(double_inputs[i]);
-    Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged);
-    r.CheckNumberConstant(c, double_inputs[i]);
+  {
+    FOR_FLOAT64_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
   }
 
-  for (size_t i = 0; i < arraysize(int32_inputs); i++) {
-    Node* n = r.jsgraph()->Int32Constant(int32_inputs[i]);
-    Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
-                                                kRepTagged);
-    r.CheckNumberConstant(c, static_cast<double>(int32_inputs[i]));
+  {
+    FOR_FLOAT64_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
   }
 
-  for (size_t i = 0; i < arraysize(uint32_inputs); i++) {
-    Node* n = r.jsgraph()->Int32Constant(uint32_inputs[i]);
-    Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
-                                                kRepTagged);
-    r.CheckNumberConstant(c, static_cast<double>(uint32_inputs[i]));
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
+                                                  kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
+                                                  kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
+  }
+}
+
+
+TEST(ToFloat64_constant) {
+  RepresentationChangerTester r;
+
+  {
+    FOR_FLOAT64_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepFloat64);
+      CHECK_EQ(n, c);
+    }
+  }
+
+  {
+    FOR_FLOAT64_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepTagged, kRepFloat64);
+      r.CheckFloat64Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepFloat64);
+      r.CheckFloat64Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
+                                                  kRepFloat64);
+      r.CheckFloat64Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
+                                                  kRepFloat64);
+      r.CheckFloat64Constant(c, *i);
+    }
+  }
+}
+
+
+static bool IsFloat32Int32(int32_t val) {
+  return val >= -(1 << 23) && val <= (1 << 23);
+}
+
+
+static bool IsFloat32Uint32(uint32_t val) { return val <= (1 << 23); }
+
+
+TEST(ToFloat32_constant) {
+  RepresentationChangerTester r;
+
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepFloat32);
+      CHECK_EQ(n, c);
+    }
+  }
+
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepTagged, kRepFloat32);
+      r.CheckFloat32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepFloat32);
+      r.CheckFloat32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      if (!IsFloat32Int32(*i)) continue;
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
+                                                  kRepFloat32);
+      r.CheckFloat32Constant(c, static_cast<float>(*i));
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      if (!IsFloat32Uint32(*i)) continue;
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
+                                                  kRepFloat32);
+      r.CheckFloat32Constant(c, static_cast<float>(*i));
+    }
+  }
+}
+
+
+TEST(ToInt32_constant) {
+  RepresentationChangerTester r;
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
+                                                  kRepWord32);
+      r.CheckInt32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      if (!IsFloat32Int32(*i)) continue;
+      Node* n = r.jsgraph()->Float32Constant(static_cast<float>(*i));
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32 | kTypeInt32,
+                                                  kRepWord32);
+      r.CheckInt32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64 | kTypeInt32,
+                                                  kRepWord32);
+      r.CheckInt32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepTagged | kTypeInt32,
+                                                  kRepWord32);
+      r.CheckInt32Constant(c, *i);
+    }
+  }
+}
+
+
+TEST(ToUint32_constant) {
+  RepresentationChangerTester r;
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
+                                                  kRepWord32);
+      r.CheckUint32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      if (!IsFloat32Uint32(*i)) continue;
+      Node* n = r.jsgraph()->Float32Constant(static_cast<float>(*i));
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32 | kTypeUint32,
+                                                  kRepWord32);
+      r.CheckUint32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64 | kTypeUint32,
+                                                  kRepWord32);
+      r.CheckUint32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(static_cast<double>(*i));
+      Node* c = r.changer()->GetRepresentationFor(n, kRepTagged | kTypeUint32,
+                                                  kRepWord32);
+      r.CheckUint32Constant(c, *i);
+    }
   }
 }
 
@@ -177,6 +382,23 @@
 }
 
 
+static void CheckTwoChanges(IrOpcode::Value expected2,
+                            IrOpcode::Value expected1, MachineTypeUnion from,
+                            MachineTypeUnion to) {
+  RepresentationChangerTester r;
+
+  Node* n = r.Parameter();
+  Node* c1 = r.changer()->GetRepresentationFor(n, from, to);
+
+  CHECK_NE(c1, n);
+  CHECK_EQ(expected1, c1->opcode());
+  Node* c2 = c1->InputAt(0);
+  CHECK_NE(c2, n);
+  CHECK_EQ(expected2, c2->opcode());
+  CHECK_EQ(n, c2->InputAt(0));
+}
+
+
 TEST(SingleChanges) {
   CheckChange(IrOpcode::kChangeBoolToBit, kRepTagged, kRepBit);
   CheckChange(IrOpcode::kChangeBitToBool, kRepBit, kRepTagged);
@@ -202,6 +424,28 @@
               kRepWord32);
   CheckChange(IrOpcode::kChangeFloat64ToUint32, kRepFloat64 | kTypeUint32,
               kRepWord32);
+
+  CheckChange(IrOpcode::kTruncateFloat64ToFloat32, kRepFloat64, kRepFloat32);
+
+  // Int32,Uint32 <-> Float32 require two changes.
+  CheckTwoChanges(IrOpcode::kChangeInt32ToFloat64,
+                  IrOpcode::kTruncateFloat64ToFloat32, kRepWord32 | kTypeInt32,
+                  kRepFloat32);
+  CheckTwoChanges(IrOpcode::kChangeUint32ToFloat64,
+                  IrOpcode::kTruncateFloat64ToFloat32, kRepWord32 | kTypeUint32,
+                  kRepFloat32);
+  CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
+                  IrOpcode::kChangeFloat64ToInt32, kRepFloat32 | kTypeInt32,
+                  kRepWord32);
+  CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
+                  IrOpcode::kChangeFloat64ToUint32, kRepFloat32 | kTypeUint32,
+                  kRepWord32);
+
+  // Float32 <-> Tagged require two changes.
+  CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
+                  IrOpcode::kChangeFloat64ToTagged, kRepFloat32, kRepTagged);
+  CheckTwoChanges(IrOpcode::kChangeTaggedToFloat64,
+                  IrOpcode::kTruncateFloat64ToFloat32, kRepTagged, kRepFloat32);
 }
 
 
@@ -215,6 +459,11 @@
               kRepWord32 | kTypeUint32);
   CheckChange(IrOpcode::kChangeInt32ToFloat64, kRepWord32, kRepFloat64);
   CheckChange(IrOpcode::kChangeFloat64ToInt32, kRepFloat64, kRepWord32);
+
+  CheckTwoChanges(IrOpcode::kChangeInt32ToFloat64,
+                  IrOpcode::kTruncateFloat64ToFloat32, kRepWord32, kRepFloat32);
+  CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
+                  IrOpcode::kChangeFloat64ToInt32, kRepFloat32, kRepWord32);
 }
 
 
@@ -295,11 +544,4 @@
       r.CheckTypeError(all_reps[i] | all_reps[j], kRepTagged);
     }
   }
-
-  // TODO(titzer): Float32 representation changes trigger type errors now.
-  // Enforce current behavior to test all paths through representation changer.
-  for (size_t i = 0; i < arraysize(all_reps); i++) {
-    r.CheckTypeError(all_reps[i], kRepFloat32);
-    r.CheckTypeError(kRepFloat32, all_reps[i]);
-  }
 }
diff --git a/test/cctest/compiler/test-run-inlining.cc b/test/cctest/compiler/test-run-inlining.cc
index ad82fec..19b96ba 100644
--- a/test/cctest/compiler/test-run-inlining.cc
+++ b/test/cctest/compiler/test-run-inlining.cc
@@ -25,7 +25,8 @@
     frames_seen++;
     it.Advance();
   }
-  CHECK_EQ(args[0]->ToInt32()->Value(), topmost->GetInlineCount());
+  CHECK_EQ(args[0]->ToInt32(args.GetIsolate())->Value(),
+           topmost->GetInlineCount());
 }
 
 
@@ -37,16 +38,20 @@
 }
 
 
+static uint32_t kInlineFlags = CompilationInfo::kInliningEnabled |
+                               CompilationInfo::kContextSpecializing |
+                               CompilationInfo::kTypingEnabled;
+
+
 TEST(SimpleInlining) {
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function(){"
-      "function foo(s) { AssertInlineCount(2); return s; };"
-      "function bar(s, t) { return foo(s); };"
-      "return bar;})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      "  function foo(s) { AssertInlineCount(2); return s; };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(1), T.Val(1), T.Val(2));
@@ -57,13 +62,11 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function(){"
-      "function foo(s) { %DeoptimizeFunction(bar); return "
-      "s; };"
-      "function bar(s, t) { return foo(s); };"
-      "return bar;})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      "  function foo(s) { %DeoptimizeFunction(bar); return s; };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(1), T.Val(1), T.Val(2));
@@ -74,13 +77,11 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "function foo(s) { AssertInlineCount(2); var x = 12; return s + x; };"
-      "function bar(s, t) { return foo(s); };"
-      "return bar;"
+      "  function foo(s) { AssertInlineCount(2); var x = 12; return s + x; };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(13), T.Val(1), T.Val(2));
@@ -91,16 +92,14 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "function foo(s) { "
-      "  AssertInlineCount(2); %DeoptimizeFunction(bar); var x = 12;"
-      "  return s + x;"
-      "};"
-      "function bar(s, t) { return foo(s); };"
-      "return bar;"
+      "  function foo(s) {"
+      "    AssertInlineCount(2); %DeoptimizeFunction(bar); var x = 12;"
+      "    return s + x;"
+      "  };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(13), T.Val(1), T.Val(2));
@@ -111,14 +110,12 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "var f = (function () {"
-      "var x = 42;"
-      "function bar(s) { return x + s; };"
-      "return (function (s) { return bar(s); });"
+      "  var x = 42;"
+      "  function bar(s) { return x + s; };"
+      "  return (function (s) { return bar(s); });"
       "})();"
-      "(function (s) { return f(s)})",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      "(function (s) { return f(s) })",
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
@@ -132,12 +129,10 @@
   FunctionTester T(
       "var x = 42;"
       "(function () {"
-      "function bar(s, t) { return eval(\"AssertInlineCount(1); x\") };"
-      "return bar;"
+      "  function bar(s, t) { return eval(\"AssertInlineCount(1); x\") };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42), T.Val("x"), T.undefined());
@@ -148,13 +143,11 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 42;"
-      "function bar(s, t, u, v) { AssertInlineCount(2); return x + s; };"
-      "return (function (s,t) { return bar(s); });"
+      "  var x = 42;"
+      "  function bar(s, t, u, v) { AssertInlineCount(2); return x + s; };"
+      "  return (function (s,t) { return bar(s); });"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
@@ -165,16 +158,14 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "function foo(s,t,u,v) { AssertInlineCount(2); %DeoptimizeFunction(bar); "
-      "return baz(); };"
-      "function bar() { return foo(11); };"
-      "function baz() { return foo.arguments.length == 1 && "
-      "                        foo.arguments[0] == 11 ; }"
-      "return bar;"
+      "  function foo(s,t,u,v) { AssertInlineCount(2);"
+      "                          %DeoptimizeFunction(bar); return baz(); };"
+      "  function bar() { return foo(11); };"
+      "  function baz() { return foo.arguments.length == 1 &&"
+      "                          foo.arguments[0] == 11; }"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
@@ -185,14 +176,12 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 42;"
-      "function foo(s) { AssertInlineCount(2); return x + s; };"
-      "function bar(s,t) { return foo(s,t,13); };"
-      "return bar;"
+      "  var x = 42;"
+      "  function foo(s) { AssertInlineCount(2); return x + s; };"
+      "  function bar(s,t) { return foo(s,t,13); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
@@ -203,18 +192,16 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "function foo(s) { AssertInlineCount(2); %DeoptimizeFunction(bar); "
-      "return baz(); };"
-      "function bar() { return foo(13, 14, 15); };"
-      "function baz() { return foo.arguments.length == 3 && "
-      "                        foo.arguments[0] == 13 && "
-      "                        foo.arguments[1] == 14 && "
-      "                        foo.arguments[2] == 15; }"
-      "return bar;"
+      "  function foo(s) { AssertInlineCount(2); %DeoptimizeFunction(bar);"
+      "                    return baz(); };"
+      "  function bar() { return foo(13, 14, 15); };"
+      "  function baz() { return foo.arguments.length == 3 &&"
+      "                          foo.arguments[0] == 13 &&"
+      "                          foo.arguments[1] == 14 &&"
+      "                          foo.arguments[2] == 15; }"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
@@ -225,13 +212,11 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 42;"
-      "function bar(s) { AssertInlineCount(2); return x + s; };"
-      "return (function (s,t) { return bar(s) + bar(t); });"
+      "  var x = 42;"
+      "  function bar(s) { AssertInlineCount(2); return x + s; };"
+      "  return (function (s,t) { return bar(s) + bar(t); });"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(2 * 42 + 12 + 4), T.Val(12), T.Val(4));
@@ -242,14 +227,12 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 42;"
-      "function foo(s) { AssertInlineCount(2); return x + s; };"
-      "function bar(s,t) { return foo(foo(s)); };"
-      "return bar;"
+      "  var x = 42;"
+      "  function foo(s) { AssertInlineCount(2); return x + s; };"
+      "  function bar(s,t) { return foo(foo(s)); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42 + 42 + 12), T.Val(12), T.Val(4));
@@ -260,15 +243,13 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 41;"
-      "function foo(s) { AssertInlineCount(2); if (s % 2 == 0) {"
-      "                  return x - s } else { return x + s; } };"
-      "function bar(s,t) { return foo(foo(s)); };"
-      "return bar;"
+      "  var x = 41;"
+      "  function foo(s) { AssertInlineCount(2); if (s % 2 == 0) {"
+      "                    return x - s } else { return x + s; } };"
+      "  function bar(s,t) { return foo(foo(s)); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(-11), T.Val(11), T.Val(4));
@@ -279,34 +260,60 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 41;"
-      "function foo(s,t) { AssertInlineCount(2); if (s % 2 == 0) {"
-      "                    return x - s * t } else { return x + s * t; } };"
-      "function bar(s,t) { return foo(foo(s, 3), 5); };"
-      "return bar;"
+      "  var x = 41;"
+      "  function foo(s,t) { AssertInlineCount(2); if (s % 2 == 0) {"
+      "                      return x - s * t } else { return x + s * t; } };"
+      "  function bar(s,t) { return foo(foo(s, 3), 5); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(-329), T.Val(11), T.Val(4));
 }
 
 
-TEST(InlineLoop) {
+TEST(InlineLoopGuardedEmpty) {
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 41;"
-      "function foo(s) { AssertInlineCount(2); while (s > 0) {"
-      "                  s = s - 1; }; return s; };"
-      "function bar(s,t) { return foo(foo(s)); };"
-      "return bar;"
+      "  function foo(s) { AssertInlineCount(2); if (s) while (s); return s; };"
+      "  function bar(s,t) { return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4));
+}
+
+
+TEST(InlineLoopGuardedOnce) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s,t) { AssertInlineCount(2); if (t > 0) while (s > 0) {"
+      "                      s = s - 1; }; return s; };"
+      "  function bar(s,t) { return foo(s,t); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.Val(0.0), T.Val(11), T.Val(4));
+}
+
+
+TEST(InlineLoopGuardedTwice) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s,t) { AssertInlineCount(2); if (t > 0) while (s > 0) {"
+      "                      s = s - 1; }; return s; };"
+      "  function bar(s,t) { return foo(foo(s,t),t); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(0.0), T.Val(11), T.Val(4));
@@ -317,15 +324,13 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = Object.create({}, { y: { value:42, writable:false } });"
-      "function foo(s) { 'use strict';"
-      "                   x.y = 9; };"
-      "function bar(s,t) { return foo(s); };"
-      "return bar;"
+      "  var x = Object.create({}, { y: { value:42, writable:false } });"
+      "  function foo(s) { 'use strict';"
+      "                     x.y = 9; };"
+      "  function bar(s,t) { return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckThrows(T.undefined(), T.undefined());
@@ -336,18 +341,100 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = Object.create({}, { y: { value:42, writable:false } });"
-      "function foo(s) { x.y = 9; return x.y; };"
-      "function bar(s,t) { \'use strict\'; return foo(s); };"
-      "return bar;"
+      "  var x = Object.create({}, { y: { value:42, writable:false } });"
+      "  function foo(s) { x.y = 9; return x.y; };"
+      "  function bar(s,t) { \'use strict\'; return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42), T.undefined(), T.undefined());
 }
 
 
+TEST(InlineIntrinsicIsSmi) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  var x = 42;"
+      "  function bar(s,t) { return %_IsSmi(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(4));
+}
+
+
+TEST(InlineIntrinsicIsNonNegativeSmi) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  var x = 42;"
+      "  function bar(s,t) { return %_IsNonNegativeSmi(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(4));
+}
+
+
+TEST(InlineIntrinsicIsArray) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  var x = [1,2,3];"
+      "  function bar(s,t) { return %_IsArray(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(4));
+
+  FunctionTester T2(
+      "(function () {"
+      "  var x = 32;"
+      "  function bar(s,t) { return %_IsArray(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  T2.CheckCall(T.false_value(), T.Val(12), T.Val(4));
+
+  FunctionTester T3(
+      "(function () {"
+      "  var x = bar;"
+      "  function bar(s,t) { return %_IsArray(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  T3.CheckCall(T.false_value(), T.Val(12), T.Val(4));
+}
+
+
+TEST(InlineWithArguments) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s,t,u) { AssertInlineCount(2);"
+      "    return foo.arguments.length == 3 &&"
+      "           foo.arguments[0] == 13 &&"
+      "           foo.arguments[1] == 14 &&"
+      "           foo.arguments[2] == 15;"
+      "  }"
+      "  function bar() { return foo(13, 14, 15); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
+}
+
 #endif  // V8_TURBOFAN_TARGET
diff --git a/test/cctest/compiler/test-run-intrinsics.cc b/test/cctest/compiler/test-run-intrinsics.cc
index a1b5676..76cbb8f 100644
--- a/test/cctest/compiler/test-run-intrinsics.cc
+++ b/test/cctest/compiler/test-run-intrinsics.cc
@@ -8,10 +8,12 @@
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
-
+uint32_t flags = CompilationInfo::kInliningEnabled;
 
 TEST(IsSmi) {
-  FunctionTester T("(function(a) { return %_IsSmi(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsSmi(a); })", flags);
 
   T.CheckTrue(T.Val(1));
   T.CheckFalse(T.Val(1.1));
@@ -23,7 +25,9 @@
 
 
 TEST(IsNonNegativeSmi) {
-  FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })", flags);
 
   T.CheckTrue(T.Val(1));
   T.CheckFalse(T.Val(1.1));
@@ -35,7 +39,9 @@
 
 
 TEST(IsMinusZero) {
-  FunctionTester T("(function(a) { return %_IsMinusZero(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsMinusZero(a); })", flags);
 
   T.CheckFalse(T.Val(1));
   T.CheckFalse(T.Val(1.1));
@@ -47,7 +53,9 @@
 
 
 TEST(IsArray) {
-  FunctionTester T("(function(a) { return %_IsArray(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsArray(a); })", flags);
 
   T.CheckFalse(T.NewObject("(function() {})"));
   T.CheckTrue(T.NewObject("([1])"));
@@ -61,7 +69,9 @@
 
 
 TEST(IsObject) {
-  FunctionTester T("(function(a) { return %_IsObject(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsObject(a); })", flags);
 
   T.CheckFalse(T.NewObject("(function() {})"));
   T.CheckTrue(T.NewObject("([1])"));
@@ -75,7 +85,9 @@
 
 
 TEST(IsFunction) {
-  FunctionTester T("(function(a) { return %_IsFunction(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsFunction(a); })", flags);
 
   T.CheckTrue(T.NewObject("(function() {})"));
   T.CheckFalse(T.NewObject("([1])"));
@@ -89,7 +101,9 @@
 
 
 TEST(IsRegExp) {
-  FunctionTester T("(function(a) { return %_IsRegExp(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsRegExp(a); })", flags);
 
   T.CheckFalse(T.NewObject("(function() {})"));
   T.CheckFalse(T.NewObject("([1])"));
@@ -103,7 +117,9 @@
 
 
 TEST(ClassOf) {
-  FunctionTester T("(function(a) { return %_ClassOf(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_ClassOf(a); })", flags);
 
   T.CheckCall(T.Val("Function"), T.NewObject("(function() {})"));
   T.CheckCall(T.Val("Array"), T.NewObject("([1])"));
@@ -117,7 +133,9 @@
 
 
 TEST(ObjectEquals) {
-  FunctionTester T("(function(a,b) { return %_ObjectEquals(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_ObjectEquals(a,b); })", flags);
   CompileRun("var o = {}");
 
   T.CheckTrue(T.NewObject("(o)"), T.NewObject("(o)"));
@@ -130,7 +148,9 @@
 
 
 TEST(ValueOf) {
-  FunctionTester T("(function(a) { return %_ValueOf(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_ValueOf(a); })", flags);
 
   T.CheckCall(T.Val("a"), T.Val("a"));
   T.CheckCall(T.Val("b"), T.NewObject("(new String('b'))"));
@@ -140,7 +160,9 @@
 
 
 TEST(SetValueOf) {
-  FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })", flags);
 
   T.CheckCall(T.Val("a"), T.NewObject("(new String)"), T.Val("a"));
   T.CheckCall(T.Val(123), T.NewObject("(new Number)"), T.Val(123));
@@ -149,7 +171,9 @@
 
 
 TEST(StringCharFromCode) {
-  FunctionTester T("(function(a) { return %_StringCharFromCode(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_StringCharFromCode(a); })", flags);
 
   T.CheckCall(T.Val("a"), T.Val(97));
   T.CheckCall(T.Val("\xE2\x9D\x8A"), T.Val(0x274A));
@@ -158,7 +182,9 @@
 
 
 TEST(StringCharAt) {
-  FunctionTester T("(function(a,b) { return %_StringCharAt(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringCharAt(a,b); })", flags);
 
   T.CheckCall(T.Val("e"), T.Val("huge fan!"), T.Val(3));
   T.CheckCall(T.Val("f"), T.Val("\xE2\x9D\x8A fan!"), T.Val(2));
@@ -167,7 +193,10 @@
 
 
 TEST(StringCharCodeAt) {
-  FunctionTester T("(function(a,b) { return %_StringCharCodeAt(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringCharCodeAt(a,b); })",
+                   flags);
 
   T.CheckCall(T.Val('e'), T.Val("huge fan!"), T.Val(3));
   T.CheckCall(T.Val('f'), T.Val("\xE2\x9D\x8A fan!"), T.Val(2));
@@ -176,7 +205,9 @@
 
 
 TEST(StringAdd) {
-  FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags);
 
   T.CheckCall(T.Val("aaabbb"), T.Val("aaa"), T.Val("bbb"));
   T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val(""));
@@ -185,7 +216,9 @@
 
 
 TEST(StringSubString) {
-  FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })", flags);
 
   T.CheckCall(T.Val("aaa"), T.Val("aaabbb"), T.Val(0.0));
   T.CheckCall(T.Val("abb"), T.Val("aaabbb"), T.Val(2));
@@ -194,7 +227,9 @@
 
 
 TEST(StringCompare) {
-  FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })", flags);
 
   T.CheckCall(T.Val(-1), T.Val("aaa"), T.Val("bbb"));
   T.CheckCall(T.Val(0.0), T.Val("bbb"), T.Val("bbb"));
@@ -203,7 +238,10 @@
 
 
 TEST(CallFunction) {
-  FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })",
+                   flags);
   CompileRun("function f(a,b,c) { return a + b + c + this.d; }");
 
   T.CheckCall(T.Val(129), T.NewObject("({d:123})"), T.NewObject("f"));
diff --git a/test/cctest/compiler/test-run-jsbranches.cc b/test/cctest/compiler/test-run-jsbranches.cc
index df2fcdc..7a4a0b3 100644
--- a/test/cctest/compiler/test-run-jsbranches.cc
+++ b/test/cctest/compiler/test-run-jsbranches.cc
@@ -280,3 +280,78 @@
   T.CheckCall(T.Val(2), T.Val(2), T.false_value());
   T.CheckCall(T.undefined(), T.Val(1), T.null());
 }
+
+
+TEST(IfTrue) {
+  FunctionTester T("(function(a,b) { if (true) return a; return b; })");
+
+  T.CheckCall(T.Val(55), T.Val(55), T.Val(11));
+  T.CheckCall(T.Val(666), T.Val(666), T.Val(-444));
+}
+
+
+TEST(TernaryTrue) {
+  FunctionTester T("(function(a,b) { return true ? a : b; })");
+
+  T.CheckCall(T.Val(77), T.Val(77), T.Val(11));
+  T.CheckCall(T.Val(111), T.Val(111), T.Val(-444));
+}
+
+
+TEST(IfFalse) {
+  FunctionTester T("(function(a,b) { if (false) return a; return b; })");
+
+  T.CheckCall(T.Val(11), T.Val(22), T.Val(11));
+  T.CheckCall(T.Val(-555), T.Val(333), T.Val(-555));
+}
+
+
+TEST(TernaryFalse) {
+  FunctionTester T("(function(a,b) { return false ? a : b; })");
+
+  T.CheckCall(T.Val(99), T.Val(33), T.Val(99));
+  T.CheckCall(T.Val(-99), T.Val(-33), T.Val(-99));
+}
+
+
+TEST(WhileTrue) {
+  FunctionTester T("(function(a,b) { while (true) return a; return b; })");
+
+  T.CheckCall(T.Val(551), T.Val(551), T.Val(111));
+  T.CheckCall(T.Val(661), T.Val(661), T.Val(-444));
+}
+
+
+TEST(WhileFalse) {
+  FunctionTester T("(function(a,b) { while (false) return a; return b; })");
+
+  T.CheckCall(T.Val(115), T.Val(551), T.Val(115));
+  T.CheckCall(T.Val(-445), T.Val(661), T.Val(-445));
+}
+
+
+TEST(DoWhileTrue) {
+  FunctionTester T(
+      "(function(a,b) { do { return a; } while (true); return b; })");
+
+  T.CheckCall(T.Val(7551), T.Val(7551), T.Val(7111));
+  T.CheckCall(T.Val(7661), T.Val(7661), T.Val(-7444));
+}
+
+
+TEST(DoWhileFalse) {
+  FunctionTester T(
+      "(function(a,b) { do { "
+      "; } while (false); return b; })");
+
+  T.CheckCall(T.Val(8115), T.Val(8551), T.Val(8115));
+  T.CheckCall(T.Val(-8445), T.Val(8661), T.Val(-8445));
+}
+
+
+TEST(EmptyFor) {
+  FunctionTester T("(function(a,b) { if (a) for(;;) ; return b; })");
+
+  T.CheckCall(T.Val(8126.1), T.Val(0.0), T.Val(8126.1));
+  T.CheckCall(T.Val(1123.1), T.Val(0.0), T.Val(1123.1));
+}
diff --git a/test/cctest/compiler/test-run-machops.cc b/test/cctest/compiler/test-run-machops.cc
index 985e0f8..974d4ce 100644
--- a/test/cctest/compiler/test-run-machops.cc
+++ b/test/cctest/compiler/test-run-machops.cc
@@ -2,11 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <cmath>
 #include <functional>
 #include <limits>
 
 #include "src/base/bits.h"
-#include "src/compiler/generic-node-inl.h"
+#include "src/codegen.h"
 #include "test/cctest/cctest.h"
 #include "test/cctest/compiler/codegen-tester.h"
 #include "test/cctest/compiler/value-helper.h"
@@ -58,25 +59,25 @@
 TEST(CodeGenInt32Binop) {
   RawMachineAssemblerTester<void> m;
 
-  const Operator* ops[] = {
+  const Operator* kOps[] = {
       m.machine()->Word32And(),      m.machine()->Word32Or(),
       m.machine()->Word32Xor(),      m.machine()->Word32Shl(),
       m.machine()->Word32Shr(),      m.machine()->Word32Sar(),
       m.machine()->Word32Equal(),    m.machine()->Int32Add(),
       m.machine()->Int32Sub(),       m.machine()->Int32Mul(),
-      m.machine()->Int32Div(),       m.machine()->Int32UDiv(),
-      m.machine()->Int32Mod(),       m.machine()->Int32UMod(),
+      m.machine()->Int32MulHigh(),   m.machine()->Int32Div(),
+      m.machine()->Uint32Div(),      m.machine()->Int32Mod(),
+      m.machine()->Uint32Mod(),      m.machine()->Uint32MulHigh(),
       m.machine()->Int32LessThan(),  m.machine()->Int32LessThanOrEqual(),
-      m.machine()->Uint32LessThan(), m.machine()->Uint32LessThanOrEqual(),
-      NULL};
+      m.machine()->Uint32LessThan(), m.machine()->Uint32LessThanOrEqual()};
 
-  for (int i = 0; ops[i] != NULL; i++) {
+  for (size_t i = 0; i < arraysize(kOps); ++i) {
     for (int j = 0; j < 8; j++) {
       for (int k = 0; k < 8; k++) {
         RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
         Node* a = Int32Input(&m, j);
         Node* b = Int32Input(&m, k);
-        m.Return(m.NewNode(ops[i], a, b));
+        m.Return(m.NewNode(kOps[i], a, b));
         m.GenerateCode();
       }
     }
@@ -127,51 +128,6 @@
 }
 
 
-TEST(RunRedundantBranch1) {
-  RawMachineAssemblerTester<int32_t> m;
-  int constant = 944777;
-
-  MLabel blocka;
-  m.Branch(m.Int32Constant(0), &blocka, &blocka);
-  m.Bind(&blocka);
-  m.Return(m.Int32Constant(constant));
-
-  CHECK_EQ(constant, m.Call());
-}
-
-
-TEST(RunRedundantBranch2) {
-  RawMachineAssemblerTester<int32_t> m;
-  int constant = 955777;
-
-  MLabel blocka, blockb;
-  m.Branch(m.Int32Constant(0), &blocka, &blocka);
-  m.Bind(&blockb);
-  m.Goto(&blocka);
-  m.Bind(&blocka);
-  m.Return(m.Int32Constant(constant));
-
-  CHECK_EQ(constant, m.Call());
-}
-
-
-TEST(RunRedundantBranch3) {
-  RawMachineAssemblerTester<int32_t> m;
-  int constant = 966777;
-
-  MLabel blocka, blockb, blockc;
-  m.Branch(m.Int32Constant(0), &blocka, &blockc);
-  m.Bind(&blocka);
-  m.Branch(m.Int32Constant(0), &blockb, &blockb);
-  m.Bind(&blockc);
-  m.Goto(&blockb);
-  m.Bind(&blockb);
-  m.Return(m.Int32Constant(constant));
-
-  CHECK_EQ(constant, m.Call());
-}
-
-
 TEST(RunDiamond2) {
   RawMachineAssemblerTester<int32_t> m;
 
@@ -571,6 +527,142 @@
 }
 
 
+TEST(RunInt32AddAndWord32EqualP) {
+  {
+    RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Parameter(0),
+                        m.Word32Equal(m.Parameter(1), m.Parameter(2))));
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>(bit_cast<uint32_t>(*i) + (*j == *k));
+          CHECK_EQ(expected, m.Call(*i, *j, *k));
+        }
+      }
+    }
+  }
+  {
+    RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Word32Equal(m.Parameter(0), m.Parameter(1)),
+                        m.Parameter(2)));
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>((*i == *j) + bit_cast<uint32_t>(*k));
+          CHECK_EQ(expected, m.Call(*i, *j, *k));
+        }
+      }
+    }
+  }
+}
+
+
+TEST(RunInt32AddAndWord32EqualImm) {
+  {
+    FOR_INT32_INPUTS(i) {
+      RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Int32Constant(*i),
+                          m.Word32Equal(m.Parameter(0), m.Parameter(1))));
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>(bit_cast<uint32_t>(*i) + (*j == *k));
+          CHECK_EQ(expected, m.Call(*j, *k));
+        }
+      }
+    }
+  }
+  {
+    FOR_INT32_INPUTS(i) {
+      RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Word32Equal(m.Int32Constant(*i), m.Parameter(0)),
+                          m.Parameter(1)));
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>((*i == *j) + bit_cast<uint32_t>(*k));
+          CHECK_EQ(expected, m.Call(*j, *k));
+        }
+      }
+    }
+  }
+}
+
+
+TEST(RunInt32AddAndWord32NotEqualP) {
+  {
+    RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Parameter(0),
+                        m.Word32NotEqual(m.Parameter(1), m.Parameter(2))));
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>(bit_cast<uint32_t>(*i) + (*j != *k));
+          CHECK_EQ(expected, m.Call(*i, *j, *k));
+        }
+      }
+    }
+  }
+  {
+    RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Word32NotEqual(m.Parameter(0), m.Parameter(1)),
+                        m.Parameter(2)));
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>((*i != *j) + bit_cast<uint32_t>(*k));
+          CHECK_EQ(expected, m.Call(*i, *j, *k));
+        }
+      }
+    }
+  }
+}
+
+
+TEST(RunInt32AddAndWord32NotEqualImm) {
+  {
+    FOR_INT32_INPUTS(i) {
+      RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Int32Constant(*i),
+                          m.Word32NotEqual(m.Parameter(0), m.Parameter(1))));
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>(bit_cast<uint32_t>(*i) + (*j != *k));
+          CHECK_EQ(expected, m.Call(*j, *k));
+        }
+      }
+    }
+  }
+  {
+    FOR_INT32_INPUTS(i) {
+      RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Word32NotEqual(m.Int32Constant(*i), m.Parameter(0)),
+                          m.Parameter(1)));
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>((*i != *j) + bit_cast<uint32_t>(*k));
+          CHECK_EQ(expected, m.Call(*j, *k));
+        }
+      }
+    }
+  }
+}
+
+
 TEST(RunInt32AddAndWord32SarP) {
   {
     RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32, kMachUint32);
@@ -1233,6 +1325,20 @@
 }
 
 
+TEST(RunInt32MulHighP) {
+  RawMachineAssemblerTester<int32_t> m;
+  Int32BinopTester bt(&m);
+  bt.AddReturn(m.Int32MulHigh(bt.param0, bt.param1));
+  FOR_INT32_INPUTS(i) {
+    FOR_INT32_INPUTS(j) {
+      int32_t expected = static_cast<int32_t>(
+          (static_cast<int64_t>(*i) * static_cast<int64_t>(*j)) >> 32);
+      CHECK_EQ(expected, bt.call(*i, *j));
+    }
+  }
+}
+
+
 TEST(RunInt32MulImm) {
   {
     FOR_UINT32_INPUTS(i) {
@@ -1259,6 +1365,22 @@
 
 TEST(RunInt32MulAndInt32AddP) {
   {
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        RawMachineAssemblerTester<int32_t> m(kMachInt32);
+        int32_t p0 = *i;
+        int32_t p1 = *j;
+        m.Return(m.Int32Add(m.Int32Constant(p0),
+                            m.Int32Mul(m.Parameter(0), m.Int32Constant(p1))));
+        FOR_INT32_INPUTS(k) {
+          int32_t p2 = *k;
+          int expected = p0 + static_cast<int32_t>(p1 * p2);
+          CHECK_EQ(expected, m.Call(p2));
+        }
+      }
+    }
+  }
+  {
     RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
     m.Return(
         m.Int32Add(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
@@ -1347,6 +1469,20 @@
 }
 
 
+TEST(RunUint32MulHighP) {
+  RawMachineAssemblerTester<int32_t> m;
+  Int32BinopTester bt(&m);
+  bt.AddReturn(m.Uint32MulHigh(bt.param0, bt.param1));
+  FOR_UINT32_INPUTS(i) {
+    FOR_UINT32_INPUTS(j) {
+      int32_t expected = bit_cast<int32_t>(static_cast<uint32_t>(
+          (static_cast<uint64_t>(*i) * static_cast<uint64_t>(*j)) >> 32));
+      CHECK_EQ(expected, bt.call(bit_cast<int32_t>(*i), bit_cast<int32_t>(*j)));
+    }
+  }
+}
+
+
 TEST(RunInt32DivP) {
   {
     RawMachineAssemblerTester<int32_t> m;
@@ -1381,11 +1517,11 @@
 }
 
 
-TEST(RunInt32UDivP) {
+TEST(RunUint32DivP) {
   {
     RawMachineAssemblerTester<int32_t> m;
     Int32BinopTester bt(&m);
-    bt.AddReturn(m.Int32UDiv(bt.param0, bt.param1));
+    bt.AddReturn(m.Uint32Div(bt.param0, bt.param1));
     FOR_UINT32_INPUTS(i) {
       FOR_UINT32_INPUTS(j) {
         uint32_t p0 = *i;
@@ -1400,7 +1536,7 @@
   {
     RawMachineAssemblerTester<int32_t> m;
     Int32BinopTester bt(&m);
-    bt.AddReturn(m.Int32Add(bt.param0, m.Int32UDiv(bt.param0, bt.param1)));
+    bt.AddReturn(m.Int32Add(bt.param0, m.Uint32Div(bt.param0, bt.param1)));
     FOR_UINT32_INPUTS(i) {
       FOR_UINT32_INPUTS(j) {
         uint32_t p0 = *i;
@@ -1449,11 +1585,11 @@
 }
 
 
-TEST(RunInt32UModP) {
+TEST(RunUint32ModP) {
   {
     RawMachineAssemblerTester<int32_t> m;
     Int32BinopTester bt(&m);
-    bt.AddReturn(m.Int32UMod(bt.param0, bt.param1));
+    bt.AddReturn(m.Uint32Mod(bt.param0, bt.param1));
     FOR_UINT32_INPUTS(i) {
       FOR_UINT32_INPUTS(j) {
         uint32_t p0 = *i;
@@ -1468,7 +1604,7 @@
   {
     RawMachineAssemblerTester<int32_t> m;
     Int32BinopTester bt(&m);
-    bt.AddReturn(m.Int32Add(bt.param0, m.Int32UMod(bt.param0, bt.param1)));
+    bt.AddReturn(m.Int32Add(bt.param0, m.Uint32Mod(bt.param0, bt.param1)));
     FOR_UINT32_INPUTS(i) {
       FOR_UINT32_INPUTS(j) {
         uint32_t p0 = *i;
@@ -2658,22 +2794,23 @@
 TEST(RunDeadInt32Binops) {
   RawMachineAssemblerTester<int32_t> m;
 
-  const Operator* ops[] = {
-      m.machine()->Word32And(),             m.machine()->Word32Or(),
-      m.machine()->Word32Xor(),             m.machine()->Word32Shl(),
-      m.machine()->Word32Shr(),             m.machine()->Word32Sar(),
-      m.machine()->Word32Ror(),             m.machine()->Word32Equal(),
-      m.machine()->Int32Add(),              m.machine()->Int32Sub(),
-      m.machine()->Int32Mul(),              m.machine()->Int32Div(),
-      m.machine()->Int32UDiv(),             m.machine()->Int32Mod(),
-      m.machine()->Int32UMod(),             m.machine()->Int32LessThan(),
-      m.machine()->Int32LessThanOrEqual(),  m.machine()->Uint32LessThan(),
-      m.machine()->Uint32LessThanOrEqual(), NULL};
+  const Operator* kOps[] = {
+      m.machine()->Word32And(),            m.machine()->Word32Or(),
+      m.machine()->Word32Xor(),            m.machine()->Word32Shl(),
+      m.machine()->Word32Shr(),            m.machine()->Word32Sar(),
+      m.machine()->Word32Ror(),            m.machine()->Word32Equal(),
+      m.machine()->Int32Add(),             m.machine()->Int32Sub(),
+      m.machine()->Int32Mul(),             m.machine()->Int32MulHigh(),
+      m.machine()->Int32Div(),             m.machine()->Uint32Div(),
+      m.machine()->Int32Mod(),             m.machine()->Uint32Mod(),
+      m.machine()->Uint32MulHigh(),        m.machine()->Int32LessThan(),
+      m.machine()->Int32LessThanOrEqual(), m.machine()->Uint32LessThan(),
+      m.machine()->Uint32LessThanOrEqual()};
 
-  for (int i = 0; ops[i] != NULL; i++) {
+  for (size_t i = 0; i < arraysize(kOps); ++i) {
     RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
-    int constant = 0x55555 + i;
-    m.NewNode(ops[i], m.Parameter(0), m.Parameter(1));
+    int32_t constant = static_cast<int32_t>(0x55555 + i);
+    m.NewNode(kOps[i], m.Parameter(0), m.Parameter(1));
     m.Return(m.Int32Constant(constant));
 
     CHECK_EQ(constant, m.Call(1, 1));
@@ -3102,6 +3239,38 @@
 }
 
 
+TEST(RunChangeUint32ToFloat64_spilled) {
+  RawMachineAssemblerTester<int32_t> m;
+  const int kNumInputs = 32;
+  int32_t magic = 0x786234;
+  uint32_t input[kNumInputs];
+  double result[kNumInputs];
+  Node* input_node[kNumInputs];
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input_node[i] =
+        m.Load(kMachUint32, m.PointerConstant(&input), m.Int32Constant(i * 4));
+  }
+
+  for (int i = 0; i < kNumInputs; i++) {
+    m.Store(kMachFloat64, m.PointerConstant(&result), m.Int32Constant(i * 8),
+            m.ChangeUint32ToFloat64(input_node[i]));
+  }
+
+  m.Return(m.Int32Constant(magic));
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input[i] = 100 + i;
+  }
+
+  CHECK_EQ(magic, m.Call());
+
+  for (int i = 0; i < kNumInputs; i++) {
+    CHECK_EQ(result[i], static_cast<double>(100 + i));
+  }
+}
+
+
 TEST(RunChangeFloat64ToInt32_A) {
   RawMachineAssemblerTester<int32_t> m;
   int32_t magic = 0x786234;
@@ -3272,6 +3441,38 @@
 }
 
 
+TEST(RunTruncateFloat64ToFloat32_spilled) {
+  RawMachineAssemblerTester<uint32_t> m;
+  const int kNumInputs = 32;
+  int32_t magic = 0x786234;
+  double input[kNumInputs];
+  float result[kNumInputs];
+  Node* input_node[kNumInputs];
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input_node[i] =
+        m.Load(kMachFloat64, m.PointerConstant(&input), m.Int32Constant(i * 8));
+  }
+
+  for (int i = 0; i < kNumInputs; i++) {
+    m.Store(kMachFloat32, m.PointerConstant(&result), m.Int32Constant(i * 4),
+            m.TruncateFloat64ToFloat32(input_node[i]));
+  }
+
+  m.Return(m.Int32Constant(magic));
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input[i] = 0.1 + i;
+  }
+
+  CHECK_EQ(magic, m.Call());
+
+  for (int i = 0; i < kNumInputs; i++) {
+    CHECK_EQ(result[i], DoubleToFloat32(input[i]));
+  }
+}
+
+
 TEST(RunDeadChangeFloat64ToInt32) {
   RawMachineAssemblerTester<int32_t> m;
   const int magic = 0x88abcda4;
@@ -4242,4 +4443,249 @@
   }
 }
 
+
+TEST(RunChangeFloat32ToFloat64) {
+  double actual = 0.0f;
+  float expected = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  m.StoreToPointer(
+      &actual, kMachFloat64,
+      m.ChangeFloat32ToFloat64(m.LoadFromPointer(&expected, kMachFloat32)));
+  m.Return(m.Int32Constant(0));
+  FOR_FLOAT32_INPUTS(i) {
+    expected = *i;
+    CHECK_EQ(0, m.Call());
+    CHECK_EQ(expected, actual);
+  }
+}
+
+
+TEST(RunChangeFloat32ToFloat64_spilled) {
+  RawMachineAssemblerTester<int32_t> m;
+  const int kNumInputs = 32;
+  int32_t magic = 0x786234;
+  float input[kNumInputs];
+  double result[kNumInputs];
+  Node* input_node[kNumInputs];
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input_node[i] =
+        m.Load(kMachFloat32, m.PointerConstant(&input), m.Int32Constant(i * 4));
+  }
+
+  for (int i = 0; i < kNumInputs; i++) {
+    m.Store(kMachFloat64, m.PointerConstant(&result), m.Int32Constant(i * 8),
+            m.ChangeFloat32ToFloat64(input_node[i]));
+  }
+
+  m.Return(m.Int32Constant(magic));
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input[i] = 100.9f + i;
+  }
+
+  CHECK_EQ(magic, m.Call());
+
+  for (int i = 0; i < kNumInputs; i++) {
+    CHECK_EQ(result[i], static_cast<double>(input[i]));
+  }
+}
+
+
+TEST(RunTruncateFloat64ToFloat32) {
+  float actual = 0.0f;
+  double input = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  m.StoreToPointer(
+      &actual, kMachFloat32,
+      m.TruncateFloat64ToFloat32(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  FOR_FLOAT64_INPUTS(i) {
+    input = *i;
+    volatile double expected = DoubleToFloat32(input);
+    CHECK_EQ(0, m.Call());
+    CHECK_EQ(expected, actual);
+  }
+}
+
+
+TEST(RunFloat32Constant) {
+  FOR_FLOAT32_INPUTS(i) {
+    float expected = *i;
+    float actual = *i;
+    RawMachineAssemblerTester<int32_t> m;
+    m.StoreToPointer(&actual, kMachFloat32, m.Float32Constant(expected));
+    m.Return(m.Int32Constant(0));
+    CHECK_EQ(0, m.Call());
+    CHECK_EQ(expected, actual);
+  }
+}
+
+
+static double two_30 = 1 << 30;             // 2^30 is a smi boundary.
+static double two_52 = two_30 * (1 << 22);  // 2^52 is a precision boundary.
+static double kValues[] = {0.1,
+                           0.2,
+                           0.49999999999999994,
+                           0.5,
+                           0.7,
+                           1.0 - std::numeric_limits<double>::epsilon(),
+                           -0.1,
+                           -0.49999999999999994,
+                           -0.5,
+                           -0.7,
+                           1.1,
+                           1.0 + std::numeric_limits<double>::epsilon(),
+                           1.5,
+                           1.7,
+                           -1,
+                           -1 + std::numeric_limits<double>::epsilon(),
+                           -1 - std::numeric_limits<double>::epsilon(),
+                           -1.1,
+                           -1.5,
+                           -1.7,
+                           std::numeric_limits<double>::min(),
+                           -std::numeric_limits<double>::min(),
+                           std::numeric_limits<double>::max(),
+                           -std::numeric_limits<double>::max(),
+                           std::numeric_limits<double>::infinity(),
+                           -std::numeric_limits<double>::infinity(),
+                           two_30,
+                           two_30 + 0.1,
+                           two_30 + 0.5,
+                           two_30 + 0.7,
+                           two_30 - 1,
+                           two_30 - 1 + 0.1,
+                           two_30 - 1 + 0.5,
+                           two_30 - 1 + 0.7,
+                           -two_30,
+                           -two_30 + 0.1,
+                           -two_30 + 0.5,
+                           -two_30 + 0.7,
+                           -two_30 + 1,
+                           -two_30 + 1 + 0.1,
+                           -two_30 + 1 + 0.5,
+                           -two_30 + 1 + 0.7,
+                           two_52,
+                           two_52 + 0.1,
+                           two_52 + 0.5,
+                           two_52 + 0.5,
+                           two_52 + 0.7,
+                           two_52 + 0.7,
+                           two_52 - 1,
+                           two_52 - 1 + 0.1,
+                           two_52 - 1 + 0.5,
+                           two_52 - 1 + 0.7,
+                           -two_52,
+                           -two_52 + 0.1,
+                           -two_52 + 0.5,
+                           -two_52 + 0.7,
+                           -two_52 + 1,
+                           -two_52 + 1 + 0.1,
+                           -two_52 + 1 + 0.5,
+                           -two_52 + 1 + 0.7,
+                           two_30,
+                           two_30 - 0.1,
+                           two_30 - 0.5,
+                           two_30 - 0.7,
+                           two_30 - 1,
+                           two_30 - 1 - 0.1,
+                           two_30 - 1 - 0.5,
+                           two_30 - 1 - 0.7,
+                           -two_30,
+                           -two_30 - 0.1,
+                           -two_30 - 0.5,
+                           -two_30 - 0.7,
+                           -two_30 + 1,
+                           -two_30 + 1 - 0.1,
+                           -two_30 + 1 - 0.5,
+                           -two_30 + 1 - 0.7,
+                           two_52,
+                           two_52 - 0.1,
+                           two_52 - 0.5,
+                           two_52 - 0.5,
+                           two_52 - 0.7,
+                           two_52 - 0.7,
+                           two_52 - 1,
+                           two_52 - 1 - 0.1,
+                           two_52 - 1 - 0.5,
+                           two_52 - 1 - 0.7,
+                           -two_52,
+                           -two_52 - 0.1,
+                           -two_52 - 0.5,
+                           -two_52 - 0.7,
+                           -two_52 + 1,
+                           -two_52 + 1 - 0.1,
+                           -two_52 + 1 - 0.5,
+                           -two_52 + 1 - 0.7};
+
+
+TEST(RunFloat64Floor) {
+  double input = -1.0;
+  double result = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  if (!m.machine()->HasFloat64Floor()) return;
+  m.StoreToPointer(&result, kMachFloat64,
+                   m.Float64Floor(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  for (size_t i = 0; i < arraysize(kValues); ++i) {
+    input = kValues[i];
+    CHECK_EQ(0, m.Call());
+    double expected = std::floor(kValues[i]);
+    CHECK_EQ(expected, result);
+  }
+}
+
+
+TEST(RunFloat64Ceil) {
+  double input = -1.0;
+  double result = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  if (!m.machine()->HasFloat64Ceil()) return;
+  m.StoreToPointer(&result, kMachFloat64,
+                   m.Float64Ceil(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  for (size_t i = 0; i < arraysize(kValues); ++i) {
+    input = kValues[i];
+    CHECK_EQ(0, m.Call());
+    double expected = std::ceil(kValues[i]);
+    CHECK_EQ(expected, result);
+  }
+}
+
+
+TEST(RunFloat64RoundTruncate) {
+  double input = -1.0;
+  double result = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  if (!m.machine()->HasFloat64Ceil()) return;
+  m.StoreToPointer(
+      &result, kMachFloat64,
+      m.Float64RoundTruncate(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  for (size_t i = 0; i < arraysize(kValues); ++i) {
+    input = kValues[i];
+    CHECK_EQ(0, m.Call());
+    double expected = trunc(kValues[i]);
+    CHECK_EQ(expected, result);
+  }
+}
+
+
+TEST(RunFloat64RoundTiesAway) {
+  double input = -1.0;
+  double result = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  if (!m.machine()->HasFloat64RoundTiesAway()) return;
+  m.StoreToPointer(
+      &result, kMachFloat64,
+      m.Float64RoundTiesAway(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  for (size_t i = 0; i < arraysize(kValues); ++i) {
+    input = kValues[i];
+    CHECK_EQ(0, m.Call());
+    double expected = round(kValues[i]);
+    CHECK_EQ(expected, result);
+  }
+}
 #endif  // V8_TURBOFAN_TARGET
diff --git a/test/cctest/compiler/test-run-stackcheck.cc b/test/cctest/compiler/test-run-stackcheck.cc
new file mode 100644
index 0000000..8c1664b
--- /dev/null
+++ b/test/cctest/compiler/test-run-stackcheck.cc
@@ -0,0 +1,18 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "test/cctest/compiler/function-tester.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+TEST(TerminateAtMethodEntry) {
+  FunctionTester T("(function(a,b) { return 23; })");
+
+  T.CheckCall(T.Val(23));
+  T.isolate->stack_guard()->RequestTerminateExecution();
+  T.CheckThrows(T.undefined(), T.undefined());
+}
diff --git a/test/cctest/compiler/test-schedule.cc b/test/cctest/compiler/test-schedule.cc
index 6c05c05..1eb3547 100644
--- a/test/cctest/compiler/test-schedule.cc
+++ b/test/cctest/compiler/test-schedule.cc
@@ -5,7 +5,6 @@
 #include "src/v8.h"
 
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/machine-operator.h"
 #include "src/compiler/node.h"
@@ -16,26 +15,25 @@
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
-                                     0, 0, "dummy");
+static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
+                               "dummy", 0, 0, 0, 0, 0, 0);
 
 TEST(TestScheduleAllocation) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
 
   CHECK_NE(NULL, schedule.start());
-  CHECK_EQ(schedule.start(), *(schedule.all_blocks().begin()));
+  CHECK_EQ(schedule.start(), schedule.GetBlockById(BasicBlock::Id::FromInt(0)));
 }
 
 
 TEST(TestScheduleAddNode) {
   HandleAndZoneScope scope;
+  Schedule schedule(scope.main_zone());
   Graph graph(scope.main_zone());
   Node* n0 = graph.NewNode(&dummy_operator);
   Node* n1 = graph.NewNode(&dummy_operator);
 
-  Schedule schedule(scope.main_zone());
-
   BasicBlock* entry = schedule.start();
   schedule.AddNode(entry, n0);
   schedule.AddNode(entry, n1);
@@ -51,50 +49,49 @@
 
 TEST(TestScheduleAddGoto) {
   HandleAndZoneScope scope;
-
   Schedule schedule(scope.main_zone());
+
   BasicBlock* entry = schedule.start();
   BasicBlock* next = schedule.NewBasicBlock();
 
   schedule.AddGoto(entry, next);
 
-  CHECK_EQ(0, entry->PredecessorCount());
-  CHECK_EQ(1, entry->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(1, static_cast<int>(entry->SuccessorCount()));
   CHECK_EQ(next, entry->SuccessorAt(0));
 
-  CHECK_EQ(1, next->PredecessorCount());
+  CHECK_EQ(1, static_cast<int>(next->PredecessorCount()));
   CHECK_EQ(entry, next->PredecessorAt(0));
-  CHECK_EQ(0, next->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(next->SuccessorCount()));
 }
 
 
 TEST(TestScheduleAddBranch) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
-
-  BasicBlock* entry = schedule.start();
-  BasicBlock* tblock = schedule.NewBasicBlock();
-  BasicBlock* fblock = schedule.NewBasicBlock();
-
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
   Node* n0 = graph.NewNode(&dummy_operator);
   Node* b = graph.NewNode(common.Branch(), n0);
 
+  BasicBlock* entry = schedule.start();
+  BasicBlock* tblock = schedule.NewBasicBlock();
+  BasicBlock* fblock = schedule.NewBasicBlock();
+
   schedule.AddBranch(entry, b, tblock, fblock);
 
-  CHECK_EQ(0, entry->PredecessorCount());
-  CHECK_EQ(2, entry->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(2, static_cast<int>(entry->SuccessorCount()));
   CHECK_EQ(tblock, entry->SuccessorAt(0));
   CHECK_EQ(fblock, entry->SuccessorAt(1));
 
-  CHECK_EQ(1, tblock->PredecessorCount());
+  CHECK_EQ(1, static_cast<int>(tblock->PredecessorCount()));
   CHECK_EQ(entry, tblock->PredecessorAt(0));
-  CHECK_EQ(0, tblock->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(tblock->SuccessorCount()));
 
-  CHECK_EQ(1, fblock->PredecessorCount());
+  CHECK_EQ(1, static_cast<int>(fblock->PredecessorCount()));
   CHECK_EQ(entry, fblock->PredecessorAt(0));
-  CHECK_EQ(0, fblock->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(fblock->SuccessorCount()));
 }
 
 
@@ -106,8 +103,8 @@
   BasicBlock* entry = schedule.start();
   schedule.AddReturn(entry, n0);
 
-  CHECK_EQ(0, entry->PredecessorCount());
-  CHECK_EQ(1, entry->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(1, static_cast<int>(entry->SuccessorCount()));
   CHECK_EQ(schedule.end(), entry->SuccessorAt(0));
 }
 
@@ -120,18 +117,53 @@
   BasicBlock* entry = schedule.start();
   schedule.AddThrow(entry, n0);
 
-  CHECK_EQ(0, entry->PredecessorCount());
-  CHECK_EQ(1, entry->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(1, static_cast<int>(entry->SuccessorCount()));
   CHECK_EQ(schedule.end(), entry->SuccessorAt(0));
 }
 
 
+TEST(TestScheduleInsertBranch) {
+  HandleAndZoneScope scope;
+  Schedule schedule(scope.main_zone());
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+  Node* n0 = graph.NewNode(&dummy_operator);
+  Node* n1 = graph.NewNode(&dummy_operator);
+  Node* b = graph.NewNode(common.Branch(), n1);
+
+  BasicBlock* entry = schedule.start();
+  BasicBlock* tblock = schedule.NewBasicBlock();
+  BasicBlock* fblock = schedule.NewBasicBlock();
+  BasicBlock* merge = schedule.NewBasicBlock();
+  schedule.AddReturn(entry, n0);
+  schedule.AddGoto(tblock, merge);
+  schedule.AddGoto(fblock, merge);
+
+  schedule.InsertBranch(entry, merge, b, tblock, fblock);
+
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(2, static_cast<int>(entry->SuccessorCount()));
+  CHECK_EQ(tblock, entry->SuccessorAt(0));
+  CHECK_EQ(fblock, entry->SuccessorAt(1));
+
+  CHECK_EQ(2, static_cast<int>(merge->PredecessorCount()));
+  CHECK_EQ(1, static_cast<int>(merge->SuccessorCount()));
+  CHECK_EQ(schedule.end(), merge->SuccessorAt(0));
+
+  CHECK_EQ(1, static_cast<int>(schedule.end()->PredecessorCount()));
+  CHECK_EQ(0, static_cast<int>(schedule.end()->SuccessorCount()));
+  CHECK_EQ(merge, schedule.end()->PredecessorAt(0));
+}
+
+
 TEST(BuildMulNodeGraph) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
-  MachineOperatorBuilder machine;
+  // TODO(titzer): use test operators.
+  MachineOperatorBuilder machine(scope.main_zone());
 
   Node* start = graph.NewNode(common.Start(0));
   graph.SetStart(start);
diff --git a/test/cctest/compiler/test-scheduler.cc b/test/cctest/compiler/test-scheduler.cc
index cf33123..1b79ed5 100644
--- a/test/cctest/compiler/test-scheduler.cc
+++ b/test/cctest/compiler/test-scheduler.cc
@@ -3,31 +3,71 @@
 // found in the LICENSE file.
 
 #include "src/v8.h"
-#include "test/cctest/cctest.h"
 
+#include "src/compiler/access-builder.h"
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node-inl.h"
-#include "src/compiler/generic-node.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/graph-visualizer.h"
 #include "src/compiler/js-operator.h"
-#include "src/compiler/machine-operator.h"
 #include "src/compiler/node.h"
+#include "src/compiler/opcodes.h"
 #include "src/compiler/operator.h"
 #include "src/compiler/schedule.h"
 #include "src/compiler/scheduler.h"
+#include "src/compiler/simplified-operator.h"
 #include "src/compiler/verifier.h"
+#include "test/cctest/cctest.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
+Operator kIntAdd(IrOpcode::kInt32Add, Operator::kPure, "Int32Add", 2, 0, 0, 1,
+                 0, 0);
+
 // TODO(titzer): pull RPO tests out to their own file.
+static void CheckRPONumbers(BasicBlockVector* order, size_t expected,
+                            bool loops_allowed) {
+  CHECK(expected == order->size());
+  for (int i = 0; i < static_cast<int>(order->size()); i++) {
+    CHECK(order->at(i)->rpo_number() == i);
+    if (!loops_allowed) {
+      CHECK_EQ(NULL, order->at(i)->loop_end());
+      CHECK_EQ(NULL, order->at(i)->loop_header());
+    }
+  }
+}
+
+
+static void CheckLoop(BasicBlockVector* order, BasicBlock** blocks,
+                      int body_size) {
+  BasicBlock* header = blocks[0];
+  BasicBlock* end = header->loop_end();
+  CHECK_NE(NULL, end);
+  CHECK_GT(end->rpo_number(), 0);
+  CHECK_EQ(body_size, end->rpo_number() - header->rpo_number());
+  for (int i = 0; i < body_size; i++) {
+    CHECK_GE(blocks[i]->rpo_number(), header->rpo_number());
+    CHECK_LT(blocks[i]->rpo_number(), end->rpo_number());
+    CHECK(header->LoopContains(blocks[i]));
+    CHECK(header->IsLoopHeader() || blocks[i]->loop_header() == header);
+  }
+  if (header->rpo_number() > 0) {
+    CHECK_NE(order->at(header->rpo_number() - 1)->loop_header(), header);
+  }
+  if (end->rpo_number() < static_cast<int>(order->size())) {
+    CHECK_NE(order->at(end->rpo_number())->loop_header(), header);
+  }
+}
+
+
 struct TestLoop {
   int count;
   BasicBlock** nodes;
   BasicBlock* header() { return nodes[0]; }
   BasicBlock* last() { return nodes[count - 1]; }
   ~TestLoop() { delete[] nodes; }
+
+  void Check(BasicBlockVector* order) { CheckLoop(order, nodes, count); }
 };
 
 
@@ -37,36 +77,15 @@
   loop->nodes = new BasicBlock* [count];
   for (int i = 0; i < count; i++) {
     loop->nodes[i] = schedule->NewBasicBlock();
-    if (i > 0) schedule->AddSuccessor(loop->nodes[i - 1], loop->nodes[i]);
+    if (i > 0) {
+      schedule->AddSuccessorForTesting(loop->nodes[i - 1], loop->nodes[i]);
+    }
   }
-  schedule->AddSuccessor(loop->nodes[count - 1], loop->nodes[0]);
+  schedule->AddSuccessorForTesting(loop->nodes[count - 1], loop->nodes[0]);
   return loop;
 }
 
 
-static void CheckRPONumbers(BasicBlockVector* order, int expected,
-                            bool loops_allowed) {
-  CHECK_EQ(expected, static_cast<int>(order->size()));
-  for (int i = 0; i < static_cast<int>(order->size()); i++) {
-    CHECK(order->at(i)->rpo_number_ == i);
-    if (!loops_allowed) CHECK_LT(order->at(i)->loop_end_, 0);
-  }
-}
-
-
-static void CheckLoopContains(BasicBlock** blocks, int body_size) {
-  BasicBlock* header = blocks[0];
-  CHECK_GT(header->loop_end_, 0);
-  CHECK_EQ(body_size, (header->loop_end_ - header->rpo_number_));
-  for (int i = 0; i < body_size; i++) {
-    int num = blocks[i]->rpo_number_;
-    CHECK(num >= header->rpo_number_ && num < header->loop_end_);
-    CHECK(header->LoopContains(blocks[i]));
-    CHECK(header->IsLoopHeader() || blocks[i]->loop_header_ == header);
-  }
-}
-
-
 static int GetScheduledNodeCount(Schedule* schedule) {
   int node_count = 0;
   for (BasicBlockVectorIter i = schedule->rpo_order()->begin();
@@ -76,7 +95,7 @@
          ++j) {
       ++node_count;
     }
-    BasicBlock::Control control = block->control_;
+    BasicBlock::Control control = block->control();
     if (control != BasicBlock::kNone) {
       ++node_count;
     }
@@ -91,11 +110,11 @@
     os << AsDOT(*graph);
   }
 
-  Schedule* schedule = Scheduler::ComputeSchedule(graph);
+  Schedule* schedule = Scheduler::ComputeSchedule(graph->zone(), graph);
 
   if (FLAG_trace_turbo_scheduler) {
     OFStream os(stdout);
-    os << *schedule << endl;
+    os << *schedule << std::endl;
   }
   ScheduleVerifier::Run(schedule);
   CHECK_EQ(expected, GetScheduledNodeCount(schedule));
@@ -107,7 +126,8 @@
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 1, false);
   CHECK_EQ(schedule.start(), order->at(0));
 }
@@ -118,7 +138,8 @@
   Schedule schedule(scope.main_zone());
 
   schedule.AddGoto(schedule.start(), schedule.end());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 2, false);
   CHECK_EQ(schedule.start(), order->at(0));
   CHECK_EQ(schedule.end(), order->at(1));
@@ -134,18 +155,18 @@
     BasicBlock* last = schedule.start();
     for (int j = 0; j < i; j++) {
       BasicBlock* block = schedule.NewBasicBlock();
+      block->set_deferred(i & 1);
       schedule.AddGoto(last, block);
       last = block;
     }
-    BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+    BasicBlockVector* order =
+        Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
     CheckRPONumbers(order, 1 + i, false);
 
-    Schedule::BasicBlocks blocks(schedule.all_blocks());
-    for (Schedule::BasicBlocks::iterator iter = blocks.begin();
-         iter != blocks.end(); ++iter) {
-      BasicBlock* block = *iter;
-      if (block->rpo_number_ >= 0 && block->SuccessorCount() == 1) {
-        CHECK(block->rpo_number_ + 1 == block->SuccessorAt(0)->rpo_number_);
+    for (size_t i = 0; i < schedule.BasicBlockCount(); i++) {
+      BasicBlock* block = schedule.GetBlockById(BasicBlock::Id::FromSize(i));
+      if (block->rpo_number() >= 0 && block->SuccessorCount() == 1) {
+        CHECK(block->rpo_number() + 1 == block->SuccessorAt(0)->rpo_number());
       }
     }
   }
@@ -155,23 +176,26 @@
 TEST(RPOSelfLoop) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
-  schedule.AddSuccessor(schedule.start(), schedule.start());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  schedule.AddSuccessorForTesting(schedule.start(), schedule.start());
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 1, true);
   BasicBlock* loop[] = {schedule.start()};
-  CheckLoopContains(loop, 1);
+  CheckLoop(order, loop, 1);
 }
 
 
 TEST(RPOEntryLoop) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
-  schedule.AddSuccessor(schedule.start(), schedule.end());
-  schedule.AddSuccessor(schedule.end(), schedule.start());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlock* body = schedule.NewBasicBlock();
+  schedule.AddSuccessorForTesting(schedule.start(), body);
+  schedule.AddSuccessorForTesting(body, schedule.start());
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 2, true);
-  BasicBlock* loop[] = {schedule.start(), schedule.end()};
-  CheckLoopContains(loop, 2);
+  BasicBlock* loop[] = {schedule.start(), body};
+  CheckLoop(order, loop, 2);
 }
 
 
@@ -179,10 +203,11 @@
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
   SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2));
-  schedule.AddSuccessor(schedule.start(), loop1->header());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  schedule.AddSuccessorForTesting(schedule.start(), loop1->header());
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 3, true);
-  CheckLoopContains(loop1->nodes, loop1->count);
+  loop1->Check(order);
 }
 
 
@@ -190,11 +215,12 @@
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
   SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2));
-  schedule.AddSuccessor(schedule.start(), loop1->header());
-  schedule.AddSuccessor(loop1->last(), schedule.start());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  schedule.AddSuccessorForTesting(schedule.start(), loop1->header());
+  schedule.AddSuccessorForTesting(loop1->last(), schedule.start());
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 3, true);
-  CheckLoopContains(loop1->nodes, loop1->count);
+  loop1->Check(order);
 }
 
 
@@ -207,18 +233,19 @@
   BasicBlock* C = schedule.NewBasicBlock();
   BasicBlock* D = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(A, C);
-  schedule.AddSuccessor(B, D);
-  schedule.AddSuccessor(C, D);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(A, C);
+  schedule.AddSuccessorForTesting(B, D);
+  schedule.AddSuccessorForTesting(C, D);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 4, false);
 
-  CHECK_EQ(0, A->rpo_number_);
-  CHECK((B->rpo_number_ == 1 && C->rpo_number_ == 2) ||
-        (B->rpo_number_ == 2 && C->rpo_number_ == 1));
-  CHECK_EQ(3, D->rpo_number_);
+  CHECK_EQ(0, A->rpo_number());
+  CHECK((B->rpo_number() == 1 && C->rpo_number() == 2) ||
+        (B->rpo_number() == 2 && C->rpo_number() == 1));
+  CHECK_EQ(3, D->rpo_number());
 }
 
 
@@ -231,15 +258,16 @@
   BasicBlock* C = schedule.NewBasicBlock();
   BasicBlock* D = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(C, B);
-  schedule.AddSuccessor(C, D);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(C, B);
+  schedule.AddSuccessorForTesting(C, D);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 4, true);
   BasicBlock* loop[] = {B, C};
-  CheckLoopContains(loop, 2);
+  CheckLoop(order, loop, 2);
 }
 
 
@@ -252,15 +280,16 @@
   BasicBlock* C = schedule.NewBasicBlock();
   BasicBlock* D = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(C, B);
-  schedule.AddSuccessor(B, D);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(C, B);
+  schedule.AddSuccessorForTesting(B, D);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 4, true);
   BasicBlock* loop[] = {B, C};
-  CheckLoopContains(loop, 2);
+  CheckLoop(order, loop, 2);
 }
 
 
@@ -277,32 +306,33 @@
     BasicBlock* F = schedule.NewBasicBlock();
     BasicBlock* G = schedule.end();
 
-    schedule.AddSuccessor(A, B);
-    schedule.AddSuccessor(B, C);
-    schedule.AddSuccessor(C, D);
-    schedule.AddSuccessor(D, E);
-    schedule.AddSuccessor(E, F);
-    schedule.AddSuccessor(F, B);
-    schedule.AddSuccessor(B, G);
+    schedule.AddSuccessorForTesting(A, B);
+    schedule.AddSuccessorForTesting(B, C);
+    schedule.AddSuccessorForTesting(C, D);
+    schedule.AddSuccessorForTesting(D, E);
+    schedule.AddSuccessorForTesting(E, F);
+    schedule.AddSuccessorForTesting(F, B);
+    schedule.AddSuccessorForTesting(B, G);
 
     // Throw in extra backedges from time to time.
-    if (i == 1) schedule.AddSuccessor(B, B);
-    if (i == 2) schedule.AddSuccessor(C, B);
-    if (i == 3) schedule.AddSuccessor(D, B);
-    if (i == 4) schedule.AddSuccessor(E, B);
-    if (i == 5) schedule.AddSuccessor(F, B);
+    if (i == 1) schedule.AddSuccessorForTesting(B, B);
+    if (i == 2) schedule.AddSuccessorForTesting(C, B);
+    if (i == 3) schedule.AddSuccessorForTesting(D, B);
+    if (i == 4) schedule.AddSuccessorForTesting(E, B);
+    if (i == 5) schedule.AddSuccessorForTesting(F, B);
 
     // Throw in extra loop exits from time to time.
-    if (i == 6) schedule.AddSuccessor(B, G);
-    if (i == 7) schedule.AddSuccessor(C, G);
-    if (i == 8) schedule.AddSuccessor(D, G);
-    if (i == 9) schedule.AddSuccessor(E, G);
-    if (i == 10) schedule.AddSuccessor(F, G);
+    if (i == 6) schedule.AddSuccessorForTesting(B, G);
+    if (i == 7) schedule.AddSuccessorForTesting(C, G);
+    if (i == 8) schedule.AddSuccessorForTesting(D, G);
+    if (i == 9) schedule.AddSuccessorForTesting(E, G);
+    if (i == 10) schedule.AddSuccessorForTesting(F, G);
 
-    BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+    BasicBlockVector* order =
+        Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
     CheckRPONumbers(order, 7, true);
     BasicBlock* loop[] = {B, C, D, E, F};
-    CheckLoopContains(loop, 5);
+    CheckLoop(order, loop, 5);
   }
 }
 
@@ -318,21 +348,22 @@
   BasicBlock* E = schedule.NewBasicBlock();
   BasicBlock* F = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(C, D);
-  schedule.AddSuccessor(D, C);
-  schedule.AddSuccessor(D, E);
-  schedule.AddSuccessor(E, B);
-  schedule.AddSuccessor(E, F);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(C, D);
+  schedule.AddSuccessorForTesting(D, C);
+  schedule.AddSuccessorForTesting(D, E);
+  schedule.AddSuccessorForTesting(E, B);
+  schedule.AddSuccessorForTesting(E, F);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 6, true);
   BasicBlock* loop1[] = {B, C, D, E};
-  CheckLoopContains(loop1, 4);
+  CheckLoop(order, loop1, 4);
 
   BasicBlock* loop2[] = {C, D};
-  CheckLoopContains(loop2, 2);
+  CheckLoop(order, loop2, 2);
 }
 
 
@@ -349,28 +380,29 @@
   BasicBlock* G = schedule.NewBasicBlock();
   BasicBlock* H = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(C, D);
-  schedule.AddSuccessor(D, E);
-  schedule.AddSuccessor(E, F);
-  schedule.AddSuccessor(F, G);
-  schedule.AddSuccessor(G, H);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(C, D);
+  schedule.AddSuccessorForTesting(D, E);
+  schedule.AddSuccessorForTesting(E, F);
+  schedule.AddSuccessorForTesting(F, G);
+  schedule.AddSuccessorForTesting(G, H);
 
-  schedule.AddSuccessor(E, D);
-  schedule.AddSuccessor(F, C);
-  schedule.AddSuccessor(G, B);
+  schedule.AddSuccessorForTesting(E, D);
+  schedule.AddSuccessorForTesting(F, C);
+  schedule.AddSuccessorForTesting(G, B);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 8, true);
   BasicBlock* loop1[] = {B, C, D, E, F, G};
-  CheckLoopContains(loop1, 6);
+  CheckLoop(order, loop1, 6);
 
   BasicBlock* loop2[] = {C, D, E, F};
-  CheckLoopContains(loop2, 4);
+  CheckLoop(order, loop2, 4);
 
   BasicBlock* loop3[] = {D, E};
-  CheckLoopContains(loop3, 2);
+  CheckLoop(order, loop3, 2);
 }
 
 
@@ -384,17 +416,18 @@
   BasicBlock* A = schedule.start();
   BasicBlock* E = schedule.end();
 
-  schedule.AddSuccessor(A, loop1->header());
-  schedule.AddSuccessor(loop1->header(), loop2->header());
-  schedule.AddSuccessor(loop2->last(), E);
+  schedule.AddSuccessorForTesting(A, loop1->header());
+  schedule.AddSuccessorForTesting(loop1->header(), loop2->header());
+  schedule.AddSuccessorForTesting(loop2->last(), E);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
 
-  CheckLoopContains(loop1->nodes, loop1->count);
+  CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
+           static_cast<int>(order->size()));
 
-  CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size()));
-  CheckLoopContains(loop1->nodes, loop1->count);
-  CheckLoopContains(loop2->nodes, loop2->count);
+  loop1->Check(order);
+  loop2->Check(order);
 }
 
 
@@ -409,18 +442,18 @@
   BasicBlock* S = schedule.NewBasicBlock();
   BasicBlock* E = schedule.end();
 
-  schedule.AddSuccessor(A, loop1->header());
-  schedule.AddSuccessor(loop1->header(), S);
-  schedule.AddSuccessor(S, loop2->header());
-  schedule.AddSuccessor(loop2->last(), E);
+  schedule.AddSuccessorForTesting(A, loop1->header());
+  schedule.AddSuccessorForTesting(loop1->header(), S);
+  schedule.AddSuccessorForTesting(S, loop2->header());
+  schedule.AddSuccessorForTesting(loop2->last(), E);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
 
-  CheckLoopContains(loop1->nodes, loop1->count);
-
-  CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size()));
-  CheckLoopContains(loop1->nodes, loop1->count);
-  CheckLoopContains(loop2->nodes, loop2->count);
+  CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
+           static_cast<int>(order->size()));
+  loop1->Check(order);
+  loop2->Check(order);
 }
 
 
@@ -435,15 +468,16 @@
       BasicBlock* A = schedule.start();
       BasicBlock* E = schedule.end();
 
-      schedule.AddSuccessor(A, loop1->header());
-      schedule.AddSuccessor(loop1->nodes[exit], loop2->header());
-      schedule.AddSuccessor(loop2->nodes[exit], E);
-      BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
-      CheckLoopContains(loop1->nodes, loop1->count);
+      schedule.AddSuccessorForTesting(A, loop1->header());
+      schedule.AddSuccessorForTesting(loop1->nodes[exit], loop2->header());
+      schedule.AddSuccessorForTesting(loop2->nodes[exit], E);
+      BasicBlockVector* order =
+          Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
 
-      CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size()));
-      CheckLoopContains(loop1->nodes, loop1->count);
-      CheckLoopContains(loop2->nodes, loop2->count);
+      CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
+               static_cast<int>(order->size()));
+      loop1->Check(order);
+      loop2->Check(order);
     }
   }
 }
@@ -461,23 +495,23 @@
   BasicBlock* C = schedule.NewBasicBlock();
   BasicBlock* E = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, loop1->header());
-  schedule.AddSuccessor(loop1->header(), loop2->header());
-  schedule.AddSuccessor(loop2->last(), C);
-  schedule.AddSuccessor(C, E);
-  schedule.AddSuccessor(C, B);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, loop1->header());
+  schedule.AddSuccessorForTesting(loop1->header(), loop2->header());
+  schedule.AddSuccessorForTesting(loop2->last(), C);
+  schedule.AddSuccessorForTesting(C, E);
+  schedule.AddSuccessorForTesting(C, B);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
 
-  CheckLoopContains(loop1->nodes, loop1->count);
-
-  CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size()));
-  CheckLoopContains(loop1->nodes, loop1->count);
-  CheckLoopContains(loop2->nodes, loop2->count);
+  CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
+           static_cast<int>(order->size()));
+  loop1->Check(order);
+  loop2->Check(order);
 
   BasicBlock* loop3[] = {B, loop1->nodes[0], loop2->nodes[0], C};
-  CheckLoopContains(loop3, 4);
+  CheckLoop(order, loop3, 4);
 }
 
 
@@ -492,15 +526,16 @@
       BasicBlock* E = schedule.end();
 
       SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
-      schedule.AddSuccessor(A, loop1->header());
-      schedule.AddSuccessor(loop1->last(), E);
+      schedule.AddSuccessorForTesting(A, loop1->header());
+      schedule.AddSuccessorForTesting(loop1->last(), E);
 
-      schedule.AddSuccessor(loop1->nodes[i], loop1->header());
-      schedule.AddSuccessor(loop1->nodes[j], E);
+      schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header());
+      schedule.AddSuccessorForTesting(loop1->nodes[j], E);
 
-      BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+      BasicBlockVector* order =
+          Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
       CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-      CheckLoopContains(loop1->nodes, loop1->count);
+      loop1->Check(order);
     }
   }
 }
@@ -518,16 +553,17 @@
       BasicBlock* E = schedule.end();
 
       SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
-      schedule.AddSuccessor(A, loop1->header());
-      schedule.AddSuccessor(loop1->last(), E);
+      schedule.AddSuccessorForTesting(A, loop1->header());
+      schedule.AddSuccessorForTesting(loop1->last(), E);
 
-      schedule.AddSuccessor(loop1->nodes[i], loop1->header());
-      schedule.AddSuccessor(loop1->nodes[j], D);
-      schedule.AddSuccessor(D, E);
+      schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header());
+      schedule.AddSuccessorForTesting(loop1->nodes[j], D);
+      schedule.AddSuccessorForTesting(D, E);
 
-      BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+      BasicBlockVector* order =
+          Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
       CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-      CheckLoopContains(loop1->nodes, loop1->count);
+      loop1->Check(order);
     }
   }
 }
@@ -543,18 +579,19 @@
     BasicBlock* E = schedule.end();
 
     SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
-    schedule.AddSuccessor(A, loop1->header());
-    schedule.AddSuccessor(loop1->last(), E);
+    schedule.AddSuccessorForTesting(A, loop1->header());
+    schedule.AddSuccessorForTesting(loop1->last(), E);
 
     for (int j = 0; j < size; j++) {
       BasicBlock* O = schedule.NewBasicBlock();
-      schedule.AddSuccessor(loop1->nodes[j], O);
-      schedule.AddSuccessor(O, E);
+      schedule.AddSuccessorForTesting(loop1->nodes[j], O);
+      schedule.AddSuccessorForTesting(O, E);
     }
 
-    BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+    BasicBlockVector* order =
+        Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
     CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-    CheckLoopContains(loop1->nodes, loop1->count);
+    loop1->Check(order);
   }
 }
 
@@ -568,22 +605,23 @@
     BasicBlock* A = schedule.start();
     BasicBlock* E = schedule.end();
     SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
-    schedule.AddSuccessor(A, loop1->header());
-    schedule.AddSuccessor(loop1->last(), E);
+    schedule.AddSuccessorForTesting(A, loop1->header());
+    schedule.AddSuccessorForTesting(loop1->last(), E);
 
     TestLoop** loopN = new TestLoop* [size];
     for (int j = 0; j < size; j++) {
       loopN[j] = CreateLoop(&schedule, 2);
-      schedule.AddSuccessor(loop1->nodes[j], loopN[j]->header());
-      schedule.AddSuccessor(loopN[j]->last(), E);
+      schedule.AddSuccessorForTesting(loop1->nodes[j], loopN[j]->header());
+      schedule.AddSuccessorForTesting(loopN[j]->last(), E);
     }
 
-    BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+    BasicBlockVector* order =
+        Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
     CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-    CheckLoopContains(loop1->nodes, loop1->count);
+    loop1->Check(order);
 
     for (int j = 0; j < size; j++) {
-      CheckLoopContains(loopN[j]->nodes, loopN[j]->count);
+      loopN[j]->Check(order);
       delete loopN[j];
     }
     delete[] loopN;
@@ -598,22 +636,23 @@
   BasicBlock* A = schedule.start();
   BasicBlock* B = schedule.NewBasicBlock();
   BasicBlock* C = schedule.NewBasicBlock();
-  BasicBlock* D = schedule.end();
+  BasicBlock* D = schedule.NewBasicBlock();
   BasicBlock* E = schedule.NewBasicBlock();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(B, D);
-  schedule.AddSuccessor(B, E);
-  schedule.AddSuccessor(C, B);
-  schedule.AddSuccessor(D, B);
-  schedule.AddSuccessor(E, B);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(B, D);
+  schedule.AddSuccessorForTesting(B, E);
+  schedule.AddSuccessorForTesting(C, B);
+  schedule.AddSuccessorForTesting(D, B);
+  schedule.AddSuccessorForTesting(E, B);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 5, true);
 
   BasicBlock* loop1[] = {B, C, D, E};
-  CheckLoopContains(loop1, 4);
+  CheckLoop(order, loop1, 4);
 }
 
 
@@ -624,7 +663,7 @@
   graph.SetStart(graph.NewNode(builder.Start(0)));
   graph.SetEnd(graph.NewNode(builder.End(), graph.start()));
 
-  USE(Scheduler::ComputeSchedule(&graph));
+  USE(Scheduler::ComputeSchedule(scope.main_zone(), &graph));
 }
 
 
@@ -639,7 +678,7 @@
 
   graph.SetEnd(graph.NewNode(builder.End(), ret));
 
-  USE(Scheduler::ComputeSchedule(&graph));
+  USE(Scheduler::ComputeSchedule(scope.main_zone(), &graph));
 }
 
 
@@ -678,9 +717,10 @@
   JSOperatorBuilder js_builder(scope.main_zone());
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b, c, y) {
@@ -823,9 +863,10 @@
   JSOperatorBuilder js_builder(scope.main_zone());
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b) {
@@ -935,9 +976,10 @@
   JSOperatorBuilder js_builder(scope.main_zone());
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b, c) {
@@ -1182,9 +1224,10 @@
   JSOperatorBuilder js_builder(scope.main_zone());
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b, c) {
@@ -1509,12 +1552,12 @@
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common_builder(scope.main_zone());
   JSOperatorBuilder js_builder(scope.main_zone());
-  MachineOperatorBuilder machine_builder;
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b, c) {
@@ -1544,7 +1587,7 @@
   Node* n20 = graph.NewNode(op, nil, nil, nil, nil, nil);
   USE(n20);
   n20->ReplaceInput(0, n9);
-  op = machine_builder.Int32Add();
+  op = &kIntAdd;
   Node* n19 = graph.NewNode(op, nil, nil);
   USE(n19);
   op = common_builder.Phi(kMachAnyTagged, 2);
@@ -1668,7 +1711,6 @@
   HandleAndZoneScope scope;
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
-  MachineOperatorBuilder machine;
 
   Node* start = graph.NewNode(common.Start(2));
   graph.SetStart(start);
@@ -1677,7 +1719,7 @@
   Node* p1 = graph.NewNode(common.Parameter(1), start);
   Node* d1 = CreateDiamond(&graph, &common, p0);
   Node* d2 = CreateDiamond(&graph, &common, p1);
-  Node* add = graph.NewNode(machine.Int32Add(), d1, d2);
+  Node* add = graph.NewNode(&kIntAdd, d1, d2);
   Node* ret = graph.NewNode(common.Return(), add, start, start);
   Node* end = graph.NewNode(common.End(), ret, start);
 
@@ -1691,7 +1733,6 @@
   HandleAndZoneScope scope;
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
-  MachineOperatorBuilder machine;
 
   Node* start = graph.NewNode(common.Start(2));
   graph.SetStart(start);
@@ -1700,7 +1741,7 @@
   Node* p1 = graph.NewNode(common.Parameter(1), start);
   Node* d1 = CreateDiamond(&graph, &common, p0);
   Node* d2 = CreateDiamond(&graph, &common, p1);
-  Node* add = graph.NewNode(machine.Int32Add(), d1, d2);
+  Node* add = graph.NewNode(&kIntAdd, d1, d2);
   Node* d3 = CreateDiamond(&graph, &common, add);
   Node* ret = graph.NewNode(common.Return(), d3, start, start);
   Node* end = graph.NewNode(common.End(), ret, start);
@@ -1710,4 +1751,374 @@
   ComputeAndVerifySchedule(33, &graph);
 }
 
+
+TEST(NestedFloatingDiamonds) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+  SimplifiedOperatorBuilder simplified(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* fv = graph.NewNode(common.Int32Constant(7));
+  Node* br = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  Node* map = graph.NewNode(
+      simplified.LoadElement(AccessBuilder::ForFixedArrayElement()), p0, p0, p0,
+      start, f);
+  Node* br1 = graph.NewNode(common.Branch(), map, graph.start());
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+  Node* m1 = graph.NewNode(common.Merge(2), t1, f1);
+  Node* ttrue = graph.NewNode(common.Int32Constant(1));
+  Node* ffalse = graph.NewNode(common.Int32Constant(0));
+  Node* phi1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), ttrue, ffalse, m1);
+
+
+  Node* m = graph.NewNode(common.Merge(2), t, f);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), fv, phi1, m);
+  Node* ephi1 = graph.NewNode(common.EffectPhi(2), start, map, m);
+
+  Node* ret = graph.NewNode(common.Return(), phi, ephi1, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(23, &graph);
+}
+
+
+TEST(NestedFloatingDiamondWithChain) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+  Node* p1 = graph.NewNode(common.Parameter(1), start);
+  Node* c = graph.NewNode(common.Int32Constant(7));
+
+  Node* brA1 = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* tA1 = graph.NewNode(common.IfTrue(), brA1);
+  Node* fA1 = graph.NewNode(common.IfFalse(), brA1);
+  Node* mA1 = graph.NewNode(common.Merge(2), tA1, fA1);
+  Node* phiA1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p1, mA1);
+
+  Node* brB1 = graph.NewNode(common.Branch(), p1, graph.start());
+  Node* tB1 = graph.NewNode(common.IfTrue(), brB1);
+  Node* fB1 = graph.NewNode(common.IfFalse(), brB1);
+  Node* mB1 = graph.NewNode(common.Merge(2), tB1, fB1);
+  Node* phiB1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p1, mB1);
+
+  Node* brA2 = graph.NewNode(common.Branch(), phiB1, mA1);
+  Node* tA2 = graph.NewNode(common.IfTrue(), brA2);
+  Node* fA2 = graph.NewNode(common.IfFalse(), brA2);
+  Node* mA2 = graph.NewNode(common.Merge(2), tA2, fA2);
+  Node* phiA2 = graph.NewNode(common.Phi(kMachAnyTagged, 2), phiB1, c, mA2);
+
+  Node* brB2 = graph.NewNode(common.Branch(), phiA1, mB1);
+  Node* tB2 = graph.NewNode(common.IfTrue(), brB2);
+  Node* fB2 = graph.NewNode(common.IfFalse(), brB2);
+  Node* mB2 = graph.NewNode(common.Merge(2), tB2, fB2);
+  Node* phiB2 = graph.NewNode(common.Phi(kMachAnyTagged, 2), phiA1, c, mB2);
+
+  Node* add = graph.NewNode(&kIntAdd, phiA2, phiB2);
+  Node* ret = graph.NewNode(common.Return(), add, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(35, &graph);
+}
+
+
+TEST(NestedFloatingDiamondWithLoop) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* fv = graph.NewNode(common.Int32Constant(7));
+  Node* br = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  Node* loop = graph.NewNode(common.Loop(2), f, start);
+  Node* ind = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+
+  Node* add = graph.NewNode(&kIntAdd, ind, fv);
+  Node* br1 = graph.NewNode(common.Branch(), add, loop);
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+
+  loop->ReplaceInput(1, t1);  // close loop.
+  ind->ReplaceInput(1, ind);  // close induction variable.
+
+  Node* m = graph.NewNode(common.Merge(2), t, f1);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), fv, ind, m);
+
+  Node* ret = graph.NewNode(common.Return(), phi, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(20, &graph);
+}
+
+
+TEST(LoopedFloatingDiamond1) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* c = graph.NewNode(common.Int32Constant(7));
+  Node* loop = graph.NewNode(common.Loop(2), start, start);
+  Node* ind = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+  Node* add = graph.NewNode(&kIntAdd, ind, c);
+
+  Node* br = graph.NewNode(common.Branch(), add, loop);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  Node* br1 = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+  Node* m1 = graph.NewNode(common.Merge(2), t1, f1);
+  Node* phi1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), add, p0, m1);
+
+  loop->ReplaceInput(1, t);    // close loop.
+  ind->ReplaceInput(1, phi1);  // close induction variable.
+
+  Node* ret = graph.NewNode(common.Return(), ind, start, f);
+  Node* end = graph.NewNode(common.End(), ret, f);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(20, &graph);
+}
+
+
+TEST(LoopedFloatingDiamond2) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* c = graph.NewNode(common.Int32Constant(7));
+  Node* loop = graph.NewNode(common.Loop(2), start, start);
+  Node* ind = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+
+  Node* br1 = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+  Node* m1 = graph.NewNode(common.Merge(2), t1, f1);
+  Node* phi1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), c, ind, m1);
+
+  Node* add = graph.NewNode(&kIntAdd, ind, phi1);
+
+  Node* br = graph.NewNode(common.Branch(), add, loop);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  loop->ReplaceInput(1, t);   // close loop.
+  ind->ReplaceInput(1, add);  // close induction variable.
+
+  Node* ret = graph.NewNode(common.Return(), ind, start, f);
+  Node* end = graph.NewNode(common.End(), ret, f);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(20, &graph);
+}
+
+
+TEST(LoopedFloatingDiamond3) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* c = graph.NewNode(common.Int32Constant(7));
+  Node* loop = graph.NewNode(common.Loop(2), start, start);
+  Node* ind = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+
+  Node* br1 = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+
+  Node* loop1 = graph.NewNode(common.Loop(2), t1, start);
+  Node* ind1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+
+  Node* add1 = graph.NewNode(&kIntAdd, ind1, c);
+  Node* br2 = graph.NewNode(common.Branch(), add1, loop1);
+  Node* t2 = graph.NewNode(common.IfTrue(), br2);
+  Node* f2 = graph.NewNode(common.IfFalse(), br2);
+
+  loop1->ReplaceInput(1, t2);   // close inner loop.
+  ind1->ReplaceInput(1, ind1);  // close inner induction variable.
+
+  Node* m1 = graph.NewNode(common.Merge(2), f1, f2);
+  Node* phi1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), c, ind1, m1);
+
+  Node* add = graph.NewNode(&kIntAdd, ind, phi1);
+
+  Node* br = graph.NewNode(common.Branch(), add, loop);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  loop->ReplaceInput(1, t);   // close loop.
+  ind->ReplaceInput(1, add);  // close induction variable.
+
+  Node* ret = graph.NewNode(common.Return(), ind, start, f);
+  Node* end = graph.NewNode(common.End(), ret, f);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(28, &graph);
+}
+
+
+TEST(PhisPushedDownToDifferentBranches) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+  Node* p1 = graph.NewNode(common.Parameter(1), start);
+
+  Node* v1 = graph.NewNode(common.Int32Constant(1));
+  Node* v2 = graph.NewNode(common.Int32Constant(2));
+  Node* v3 = graph.NewNode(common.Int32Constant(3));
+  Node* v4 = graph.NewNode(common.Int32Constant(4));
+  Node* br = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+  Node* m = graph.NewNode(common.Merge(2), t, f);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), v1, v2, m);
+  Node* phi2 = graph.NewNode(common.Phi(kMachAnyTagged, 2), v3, v4, m);
+
+  Node* br2 = graph.NewNode(common.Branch(), p1, graph.start());
+  Node* t2 = graph.NewNode(common.IfTrue(), br2);
+  Node* f2 = graph.NewNode(common.IfFalse(), br2);
+  Node* m2 = graph.NewNode(common.Merge(2), t2, f2);
+  Node* phi3 = graph.NewNode(common.Phi(kMachAnyTagged, 2), phi, phi2, m2);
+
+  Node* ret = graph.NewNode(common.Return(), phi3, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(24, &graph);
+}
+
+
+TEST(BranchHintTrue) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(1));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+  Node* tv = graph.NewNode(common.Int32Constant(6));
+  Node* fv = graph.NewNode(common.Int32Constant(7));
+  Node* br = graph.NewNode(common.Branch(BranchHint::kTrue), p0, start);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+  Node* m = graph.NewNode(common.Merge(2), t, f);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), tv, fv, m);
+  Node* ret = graph.NewNode(common.Return(), phi, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  Schedule* schedule = ComputeAndVerifySchedule(13, &graph);
+  // Make sure the false block is marked as deferred.
+  CHECK(!schedule->block(t)->deferred());
+  CHECK(schedule->block(f)->deferred());
+}
+
+
+TEST(BranchHintFalse) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(1));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+  Node* tv = graph.NewNode(common.Int32Constant(6));
+  Node* fv = graph.NewNode(common.Int32Constant(7));
+  Node* br = graph.NewNode(common.Branch(BranchHint::kFalse), p0, start);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+  Node* m = graph.NewNode(common.Merge(2), t, f);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), tv, fv, m);
+  Node* ret = graph.NewNode(common.Return(), phi, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  Schedule* schedule = ComputeAndVerifySchedule(13, &graph);
+  // Make sure the true block is marked as deferred.
+  CHECK(schedule->block(t)->deferred());
+  CHECK(!schedule->block(f)->deferred());
+}
+
+
+TEST(ScheduleTerminate) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(1));
+  graph.SetStart(start);
+
+  Node* loop = graph.NewNode(common.Loop(2), start, start);
+  loop->ReplaceInput(1, loop);  // self loop, NTL.
+
+  Node* effect = graph.NewNode(common.EffectPhi(1), start, loop);
+  effect->ReplaceInput(0, effect);
+
+  Node* terminate = graph.NewNode(common.Terminate(1), effect, loop);
+  Node* end = graph.NewNode(common.End(), terminate);
+
+  graph.SetEnd(end);
+
+  Schedule* schedule = ComputeAndVerifySchedule(6, &graph);
+  BasicBlock* block = schedule->block(loop);
+  CHECK_NE(NULL, loop);
+  CHECK_EQ(block, schedule->block(effect));
+  CHECK_GE(block->rpo_number(), 0);
+}
+
 #endif
diff --git a/test/cctest/compiler/test-simplified-lowering.cc b/test/cctest/compiler/test-simplified-lowering.cc
index 96fb965..147aa32 100644
--- a/test/cctest/compiler/test-simplified-lowering.cc
+++ b/test/cctest/compiler/test-simplified-lowering.cc
@@ -5,8 +5,9 @@
 #include <limits>
 
 #include "src/compiler/access-builder.h"
+#include "src/compiler/change-lowering.h"
 #include "src/compiler/control-builders.h"
-#include "src/compiler/generic-node-inl.h"
+#include "src/compiler/graph-reducer.h"
 #include "src/compiler/graph-visualizer.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/pipeline.h"
@@ -35,11 +36,10 @@
                            MachineType p3 = kMachNone,
                            MachineType p4 = kMachNone)
       : GraphBuilderTester<ReturnType>(p0, p1, p2, p3, p4),
-        typer(this->zone()),
+        typer(this->graph(), MaybeHandle<Context>()),
         javascript(this->zone()),
-        jsgraph(this->graph(), this->common(), &javascript, &typer,
-                this->machine()),
-        lowering(&jsgraph) {}
+        jsgraph(this->graph(), this->common(), &javascript, this->machine()),
+        lowering(&jsgraph, this->zone()) {}
 
   Typer typer;
   JSOperatorBuilder javascript;
@@ -48,16 +48,40 @@
 
   void LowerAllNodes() {
     this->End();
+    typer.Run();
     lowering.LowerAllNodes();
   }
 
+  void LowerAllNodesAndLowerChanges() {
+    this->End();
+    typer.Run();
+    lowering.LowerAllNodes();
+
+    Zone* zone = this->zone();
+    CompilationInfo info(zone->isolate(), zone);
+    Linkage linkage(
+        zone, Linkage::GetSimplifiedCDescriptor(zone, this->machine_sig_));
+    ChangeLowering lowering(&jsgraph, &linkage);
+    GraphReducer reducer(this->graph(), this->zone());
+    reducer.AddReducer(&lowering);
+    reducer.ReduceGraph();
+    Verifier::Run(this->graph());
+  }
+
+  void CheckNumberCall(double expected, double input) {
+    // TODO(titzer): make calls to NewNumber work in cctests.
+    if (expected <= Smi::kMinValue) return;
+    if (expected >= Smi::kMaxValue) return;
+    Handle<Object> num = factory()->NewNumber(input);
+    Object* result = this->Call(*num);
+    CHECK(factory()->NewNumber(expected)->SameValue(result));
+  }
+
   Factory* factory() { return this->isolate()->factory(); }
   Heap* heap() { return this->isolate()->heap(); }
 };
 
 
-#ifndef V8_TARGET_ARCH_ARM64
-// TODO(titzer): these result in a stub call that doesn't work on ARM64.
 // TODO(titzer): factor these tests out to test-run-simplifiedops.cc.
 // TODO(titzer): test tagged representation for input to NumberToInt32.
 TEST(RunNumberToInt32_float64) {
@@ -68,6 +92,7 @@
   FieldAccess load = {kUntaggedBase, 0, Handle<Name>(), Type::Number(),
                       kMachFloat64};
   Node* loaded = t.LoadField(load, t.PointerConstant(&input));
+  NodeProperties::SetBounds(loaded, Bounds(Type::Number()));
   Node* convert = t.NumberToInt32(loaded);
   FieldAccess store = {kUntaggedBase, 0, Handle<Name>(), Type::Signed32(),
                        kMachInt32};
@@ -96,6 +121,7 @@
   FieldAccess load = {kUntaggedBase, 0, Handle<Name>(), Type::Number(),
                       kMachFloat64};
   Node* loaded = t.LoadField(load, t.PointerConstant(&input));
+  NodeProperties::SetBounds(loaded, Bounds(Type::Number()));
   Node* convert = t.NumberToUint32(loaded);
   FieldAccess store = {kUntaggedBase, 0, Handle<Name>(), Type::Unsigned32(),
                        kMachUint32};
@@ -113,7 +139,6 @@
     }
   }
 }
-#endif
 
 
 // Create a simple JSObject with a unique map.
@@ -207,10 +232,8 @@
 TEST(RunLoadStoreFixedArrayIndex) {
   SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
   ElementAccess access = AccessBuilder::ForFixedArrayElement();
-  Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0),
-                             t.Int32Constant(2));
-  t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), t.Int32Constant(2),
-                 load);
+  Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0));
+  t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), load);
   t.Return(load);
 
   t.LowerAllNodes();
@@ -235,14 +258,13 @@
   const int index = 12;
   const int array_length = 2 * index;
   ElementAccess buffer_access =
-      AccessBuilder::ForBackingStoreElement(kMachInt8);
+      AccessBuilder::ForTypedArrayElement(v8::kExternalInt8Array, true);
   Node* backing_store = t.LoadField(
       AccessBuilder::ForJSArrayBufferBackingStore(), t.Parameter(0));
   Node* load =
-      t.LoadElement(buffer_access, backing_store, t.Int32Constant(index),
-                    t.Int32Constant(array_length));
+      t.LoadElement(buffer_access, backing_store, t.Int32Constant(index));
   t.StoreElement(buffer_access, backing_store, t.Int32Constant(index + 1),
-                 t.Int32Constant(array_length), load);
+                 load);
   t.Return(t.jsgraph.TrueConstant());
 
   t.LowerAllNodes();
@@ -329,9 +351,8 @@
                               kMachAnyTagged};
 
       SimplifiedLoweringTester<Object*> t;
-      Node* load = t.LoadElement(
-          access, t.PointerConstant(smis), t.Int32Constant(static_cast<int>(j)),
-          t.Int32Constant(static_cast<int>(arraysize(smis))));
+      Node* load = t.LoadElement(access, t.PointerConstant(smis),
+                                 t.Int32Constant(static_cast<int>(j)));
       t.Return(load);
       t.LowerAllNodes();
 
@@ -360,8 +381,7 @@
       SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
       Node* p0 = t.Parameter(0);
       t.StoreElement(access, t.PointerConstant(smis),
-                     t.Int32Constant(static_cast<int>(j)),
-                     t.Int32Constant(static_cast<int>(arraysize(smis))), p0);
+                     t.Int32Constant(static_cast<int>(j)), p0);
       t.Return(p0);
       t.LowerAllNodes();
 
@@ -427,10 +447,8 @@
 
     SimplifiedLoweringTester<Object*> t;
     Node* ptr = GetBaseNode(&t);
-    Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index),
-                               t.Int32Constant(static_cast<int>(num_elements)));
-    t.StoreElement(access, ptr, t.Int32Constant(to_index),
-                   t.Int32Constant(static_cast<int>(num_elements)), load);
+    Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index));
+    t.StoreElement(access, ptr, t.Int32Constant(to_index), load);
     t.Return(t.jsgraph.TrueConstant());
     t.LowerAllNodes();
     t.GenerateCode();
@@ -648,9 +666,9 @@
   explicit TestingGraph(Type* p0_type, Type* p1_type = Type::None(),
                         Type* p2_type = Type::None())
       : GraphAndBuilders(main_zone()),
-        typer(main_zone()),
+        typer(graph(), MaybeHandle<Context>()),
         javascript(main_zone()),
-        jsgraph(graph(), common(), &javascript, &typer, machine()) {
+        jsgraph(graph(), common(), &javascript, machine()) {
     start = graph()->NewNode(common()->Start(2));
     graph()->SetStart(start);
     ret =
@@ -660,6 +678,7 @@
     p0 = graph()->NewNode(common()->Parameter(0), start);
     p1 = graph()->NewNode(common()->Parameter(1), start);
     p2 = graph()->NewNode(common()->Parameter(2), start);
+    typer.Run();
     NodeProperties::SetBounds(p0, Bounds(p0_type));
     NodeProperties::SetBounds(p1, Bounds(p1_type));
     NodeProperties::SetBounds(p2, Bounds(p2_type));
@@ -679,10 +698,7 @@
     CHECK_EQ(expected, node->opcode());
   }
 
-  void Lower() {
-    SimplifiedLowering lowering(&jsgraph);
-    lowering.LowerAllNodes();
-  }
+  void Lower() { SimplifiedLowering(&jsgraph, jsgraph.zone()).LowerAllNodes(); }
 
   // Inserts the node as the return value of the graph.
   Node* Return(Node* node) {
@@ -718,6 +734,17 @@
     }
   }
 
+  Node* ExampleWithTypeAndRep(Type* type, MachineType mach_type) {
+    FieldAccess access = {kUntaggedBase, 0, Handle<Name>::null(), type,
+                          mach_type};
+    // TODO(titzer): using loads here just to force the representation is ugly.
+    Node* node = graph()->NewNode(simplified()->LoadField(access),
+                                  jsgraph.IntPtrConstant(0), graph()->start(),
+                                  graph()->start());
+    NodeProperties::SetBounds(node, Bounds(type));
+    return node;
+  }
+
   Node* Use(Node* node, MachineType type) {
     if (type & kTypeInt32) {
       return graph()->NewNode(machine()->Int32LessThan(), node,
@@ -731,6 +758,9 @@
     } else if (type & kRepWord64) {
       return graph()->NewNode(machine()->Int64LessThan(), node,
                               Int64Constant(1));
+    } else if (type & kRepWord32) {
+      return graph()->NewNode(machine()->Word32Equal(), node,
+                              jsgraph.Int32Constant(1));
     } else {
       return graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), node,
                               jsgraph.TrueConstant());
@@ -757,6 +787,50 @@
 };
 
 
+TEST(LowerAnyToBoolean_bit_bit) {
+  // AnyToBoolean(x: kRepBit) used as kRepBit
+  HandleAndZoneScope scope;
+  Factory* f = scope.main_zone()->isolate()->factory();
+  Handle<Object> zero = f->NewNumber(0);
+  Handle<Object> one = f->NewNumber(1);
+  Type* singleton_zero = Type::Constant(zero, scope.main_zone());
+  Type* singleton_one = Type::Constant(one, scope.main_zone());
+  Type* zero_one_range = Type::Range(zero, one, scope.main_zone());
+  static Type* kTypes[] = {
+      singleton_zero, singleton_one, zero_one_range, Type::Boolean(),
+      Type::Union(Type::Boolean(), singleton_zero, scope.main_zone()),
+      Type::Union(Type::Boolean(), singleton_one, scope.main_zone()),
+      Type::Union(Type::Boolean(), zero_one_range, scope.main_zone())};
+  for (Type* type : kTypes) {
+    TestingGraph t(type);
+    Node* x = t.ExampleWithTypeAndRep(type, kRepBit);
+    Node* cnv = t.graph()->NewNode(t.simplified()->AnyToBoolean(), x);
+    Node* use = t.Branch(cnv);
+    t.Lower();
+    CHECK_EQ(x, use->InputAt(0));
+  }
+}
+
+
+#if V8_TURBOFAN_TARGET
+
+TEST(LowerAnyToBoolean_tagged_tagged) {
+  // AnyToBoolean(x: kRepTagged) used as kRepTagged
+  TestingGraph t(Type::Any());
+  Node* x = t.p0;
+  Node* cnv = t.graph()->NewNode(t.simplified()->AnyToBoolean(), x);
+  Node* use = t.Use(cnv, kRepTagged);
+  t.Return(use);
+  t.Lower();
+  CHECK_EQ(IrOpcode::kCall, cnv->opcode());
+  CHECK_EQ(IrOpcode::kHeapConstant, cnv->InputAt(0)->opcode());
+  CHECK_EQ(x, cnv->InputAt(1));
+  CHECK_EQ(t.jsgraph.NoContextConstant(), cnv->InputAt(2));
+}
+
+#endif
+
+
 TEST(LowerBooleanNot_bit_bit) {
   // BooleanNot(x: kRepBit) used as kRepBit
   TestingGraph t(Type::Boolean());
@@ -765,7 +839,7 @@
   Node* use = t.Branch(inv);
   t.Lower();
   Node* cmp = use->InputAt(0);
-  CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
+  CHECK_EQ(t.machine()->Word32Equal()->opcode(), cmp->opcode());
   CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
   Node* f = t.jsgraph.Int32Constant(0);
   CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
@@ -782,7 +856,7 @@
   t.Lower();
   CHECK_EQ(IrOpcode::kChangeBitToBool, use->InputAt(0)->opcode());
   Node* cmp = use->InputAt(0)->InputAt(0);
-  CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
+  CHECK_EQ(t.machine()->Word32Equal()->opcode(), cmp->opcode());
   CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
   Node* f = t.jsgraph.Int32Constant(0);
   CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
@@ -921,24 +995,50 @@
 
 
 TEST(LowerNumberAddSub_to_int32) {
-  TestingGraph t(Type::Signed32(), Type::Signed32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
-                                t.simplified()->NumberAdd(),
-                                t.simplified()->NumberToInt32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
-                                t.simplified()->NumberSubtract(),
-                                t.simplified()->NumberToInt32());
+  HandleAndZoneScope scope;
+  Factory* f = scope.main_zone()->isolate()->factory();
+  Type* small_range =
+      Type::Range(f->NewNumber(1), f->NewNumber(10), scope.main_zone());
+  Type* large_range =
+      Type::Range(f->NewNumber(-1e+13), f->NewNumber(1e+14), scope.main_zone());
+  static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
+                          large_range};
+
+  for (size_t i = 0; i < arraysize(types); i++) {
+    for (size_t j = 0; j < arraysize(types); j++) {
+      TestingGraph t(types[i], types[j]);
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
+                                    t.simplified()->NumberAdd(),
+                                    t.simplified()->NumberToInt32());
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
+                                    t.simplified()->NumberSubtract(),
+                                    t.simplified()->NumberToInt32());
+    }
+  }
 }
 
 
 TEST(LowerNumberAddSub_to_uint32) {
-  TestingGraph t(Type::Unsigned32(), Type::Unsigned32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
-                                t.simplified()->NumberAdd(),
-                                t.simplified()->NumberToUint32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
-                                t.simplified()->NumberSubtract(),
-                                t.simplified()->NumberToUint32());
+  HandleAndZoneScope scope;
+  Factory* f = scope.main_zone()->isolate()->factory();
+  Type* small_range =
+      Type::Range(f->NewNumber(1), f->NewNumber(10), scope.main_zone());
+  Type* large_range =
+      Type::Range(f->NewNumber(-1e+13), f->NewNumber(1e+14), scope.main_zone());
+  static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
+                          large_range};
+
+  for (size_t i = 0; i < arraysize(types); i++) {
+    for (size_t j = 0; j < arraysize(types); j++) {
+      TestingGraph t(types[i], types[j]);
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
+                                    t.simplified()->NumberAdd(),
+                                    t.simplified()->NumberToUint32());
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
+                                    t.simplified()->NumberSubtract(),
+                                    t.simplified()->NumberToUint32());
+    }
+  }
 }
 
 
@@ -958,8 +1058,10 @@
     TestingGraph t(test_types[i], test_types[i]);
 
     t.CheckLoweringBinop(IrOpcode::kFloat64Div, t.simplified()->NumberDivide());
-    t.CheckLoweringBinop(IrOpcode::kFloat64Mod,
-                         t.simplified()->NumberModulus());
+    if (!test_types[i]->Is(Type::Unsigned32())) {
+      t.CheckLoweringBinop(IrOpcode::kFloat64Mod,
+                           t.simplified()->NumberModulus());
+    }
   }
 }
 
@@ -1006,7 +1108,7 @@
 TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32) {
   // NumberToInt32(x: kRepFloat64) used as kMachInt32
   TestingGraph t(Type::Number());
-  Node* p0 = t.ExampleWithOutput(kMachFloat64);
+  Node* p0 = t.ExampleWithTypeAndRep(Type::Number(), kMachFloat64);
   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), p0);
   Node* use = t.Use(trunc, kMachInt32);
   t.Return(use);
@@ -1030,17 +1132,6 @@
 }
 
 
-TEST(LowerNumberToInt32_to_ChangeFloat64ToTagged) {
-  // TODO(titzer): NumberToInt32(x: kRepFloat64 | kTypeInt32) used as kRepTagged
-}
-
-
-TEST(LowerNumberToInt32_to_ChangeFloat64ToInt32) {
-  // TODO(titzer): NumberToInt32(x: kRepFloat64 | kTypeInt32) used as kRepWord32
-  // | kTypeInt32
-}
-
-
 TEST(LowerNumberToUint32_to_nop) {
   // NumberToUint32(x: kRepTagged | kTypeUint32) used as kRepTagged
   TestingGraph t(Type::Unsigned32());
@@ -1078,6 +1169,8 @@
   // NumberToUint32(x: kRepFloat64) used as kMachUint32
   TestingGraph t(Type::Number());
   Node* p0 = t.ExampleWithOutput(kMachFloat64);
+  // TODO(titzer): run the typer here, or attach machine type to param.
+  NodeProperties::SetBounds(p0, Bounds(Type::Number()));
   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), p0);
   Node* use = t.Use(trunc, kMachUint32);
   t.Return(use);
@@ -1101,20 +1194,67 @@
 }
 
 
-TEST(LowerNumberToUint32_to_ChangeFloat64ToTagged) {
-  // TODO(titzer): NumberToUint32(x: kRepFloat64 | kTypeUint32) used as
-  // kRepTagged
+TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32_uint32) {
+  // NumberToUint32(x: kRepFloat64) used as kRepWord32
+  TestingGraph t(Type::Unsigned32());
+  Node* input = t.ExampleWithTypeAndRep(Type::Number(), kMachFloat64);
+  Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), input);
+  Node* use = t.Use(trunc, kRepWord32);
+  t.Return(use);
+  t.Lower();
+  CheckChangeOf(IrOpcode::kTruncateFloat64ToInt32, input, use->InputAt(0));
 }
 
 
-TEST(LowerNumberToUint32_to_ChangeFloat64ToUint32) {
-  // TODO(titzer): NumberToUint32(x: kRepFloat64 | kTypeUint32) used as
-  // kRepWord32
+TEST(LowerNumberToUI32_of_Float64_used_as_word32) {
+  // NumberTo(Int,Uint)32(x: kRepFloat64 | kType(Int,Uint)32) used as
+  // kType(Int,Uint)32 | kRepWord32
+  Type* types[] = {Type::Signed32(), Type::Unsigned32()};
+  MachineType mach[] = {kTypeInt32, kTypeUint32, kMachNone};
+
+  for (int i = 0; i < 2; i++) {
+    for (int u = 0; u < 3; u++) {
+      TestingGraph t(types[i]);
+      Node* input = t.ExampleWithTypeAndRep(
+          types[i], static_cast<MachineType>(kRepFloat64 | mach[i]));
+      const Operator* op = i == 0 ? t.simplified()->NumberToInt32()
+                                  : t.simplified()->NumberToUint32();
+      Node* trunc = t.graph()->NewNode(op, input);
+      Node* use = t.Use(trunc, static_cast<MachineType>(kRepWord32 | mach[u]));
+      t.Return(use);
+      t.Lower();
+      IrOpcode::Value opcode = i == 0 ? IrOpcode::kChangeFloat64ToInt32
+                                      : IrOpcode::kChangeFloat64ToUint32;
+      CheckChangeOf(opcode, input, use->InputAt(0));
+    }
+  }
 }
 
 
-TEST(LowerNumberToUint32_to_TruncateFloat64ToUint32) {
-  // TODO(titzer): NumberToUint32(x: kRepFloat64) used as kRepWord32
+TEST(LowerNumberToUI32_of_Float64_used_as_tagged) {
+  // NumberTo(Int,Uint)32(x: kRepFloat64 | kType(Int,Uint)32) used as
+  // kType(Int,Uint)32 | kRepTagged
+  Type* types[] = {Type::Signed32(), Type::Unsigned32(), Type::Any()};
+  MachineType mach[] = {kTypeInt32, kTypeUint32, kMachNone};
+
+  for (int i = 0; i < 2; i++) {
+    for (int u = 0; u < 3; u++) {
+      TestingGraph t(types[i]);
+      Node* input = t.ExampleWithTypeAndRep(
+          types[i], static_cast<MachineType>(kRepFloat64 | mach[i]));
+      const Operator* op = i == 0 ? t.simplified()->NumberToInt32()
+                                  : t.simplified()->NumberToUint32();
+      Node* trunc = t.graph()->NewNode(op, input);
+      // TODO(titzer): we use the store here to force the representation.
+      FieldAccess access = {kTaggedBase, 0, Handle<Name>(), types[u],
+                            static_cast<MachineType>(mach[u] | kRepTagged)};
+      Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
+                                       trunc, t.start, t.start);
+      t.Effect(store);
+      t.Lower();
+      CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, input, store->InputAt(2));
+    }
+  }
 }
 
 
@@ -1268,45 +1408,54 @@
 }
 
 
+namespace {
+
 void CheckFieldAccessArithmetic(FieldAccess access, Node* load_or_store) {
-  Int32Matcher index = Int32Matcher(load_or_store->InputAt(1));
-  CHECK(index.Is(access.offset - access.tag()));
+  IntPtrMatcher mindex(load_or_store->InputAt(1));
+  CHECK(mindex.Is(access.offset - access.tag()));
 }
 
 
 Node* CheckElementAccessArithmetic(ElementAccess access, Node* load_or_store) {
-  Int32BinopMatcher index(load_or_store->InputAt(1));
-  CHECK_EQ(IrOpcode::kInt32Add, index.node()->opcode());
-  CHECK(index.right().Is(access.header_size - access.tag()));
+  Node* index = load_or_store->InputAt(1);
+  if (kPointerSize == 8) {
+    CHECK_EQ(IrOpcode::kChangeUint32ToUint64, index->opcode());
+    index = index->InputAt(0);
+  }
 
-  int element_size = ElementSizeOf(access.machine_type);
+  Int32BinopMatcher mindex(index);
+  CHECK_EQ(IrOpcode::kInt32Add, mindex.node()->opcode());
+  CHECK(mindex.right().Is(access.header_size - access.tag()));
 
-  if (element_size != 1) {
-    Int32BinopMatcher mul(index.left().node());
-    CHECK_EQ(IrOpcode::kInt32Mul, mul.node()->opcode());
-    CHECK(mul.right().Is(element_size));
-    return mul.left().node();
+  const int element_size_shift = ElementSizeLog2Of(access.machine_type);
+  if (element_size_shift) {
+    Int32BinopMatcher shl(mindex.left().node());
+    CHECK_EQ(IrOpcode::kWord32Shl, shl.node()->opcode());
+    CHECK(shl.right().Is(element_size_shift));
+    return shl.left().node();
   } else {
-    return index.left().node();
+    return mindex.left().node();
   }
 }
 
 
-static const MachineType machine_reps[] = {
-    kRepBit,    kMachInt8,    kMachInt16,    kMachInt32,
-    kMachInt64, kMachFloat64, kMachAnyTagged};
+const MachineType kMachineReps[] = {kRepBit,       kMachInt8,  kMachInt16,
+                                    kMachInt32,    kMachInt64, kMachFloat64,
+                                    kMachAnyTagged};
+
+}  // namespace
 
 
 TEST(LowerLoadField_to_load) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                          Handle<Name>::null(), Type::Any(), machine_reps[i]};
+                          Handle<Name>::null(), Type::Any(), kMachineReps[i]};
 
     Node* load =
         t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
-    Node* use = t.Use(load, machine_reps[i]);
+    Node* use = t.Use(load, kMachineReps[i]);
     t.Return(use);
     t.Lower();
     CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1314,7 +1463,7 @@
     CheckFieldAccessArithmetic(access, load);
 
     MachineType rep = OpParameter<MachineType>(load);
-    CHECK_EQ(machine_reps[i], rep);
+    CHECK_EQ(kMachineReps[i], rep);
   }
 }
 
@@ -1322,12 +1471,12 @@
 TEST(LowerStoreField_to_store) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                          Handle<Name>::null(), Type::Any(), machine_reps[i]};
+                          Handle<Name>::null(), Type::Any(), kMachineReps[i]};
 
 
-    Node* val = t.ExampleWithOutput(machine_reps[i]);
+    Node* val = t.ExampleWithOutput(kMachineReps[i]);
     Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
                                      val, t.start, t.start);
     t.Effect(store);
@@ -1337,10 +1486,10 @@
     CheckFieldAccessArithmetic(access, store);
 
     StoreRepresentation rep = OpParameter<StoreRepresentation>(store);
-    if (machine_reps[i] & kRepTagged) {
+    if (kMachineReps[i] & kRepTagged) {
       CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
     }
-    CHECK_EQ(machine_reps[i], rep.machine_type());
+    CHECK_EQ(kMachineReps[i], rep.machine_type());
   }
 }
 
@@ -1348,14 +1497,13 @@
 TEST(LowerLoadElement_to_load) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
     ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                            Type::Any(), machine_reps[i]};
+                            Type::Any(), kMachineReps[i]};
 
-    Node* load =
-        t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, t.p1,
-                           t.jsgraph.Int32Constant(1024), t.start);
-    Node* use = t.Use(load, machine_reps[i]);
+    Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
+                                    t.p1, t.start, t.start);
+    Node* use = t.Use(load, kMachineReps[i]);
     t.Return(use);
     t.Lower();
     CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1363,7 +1511,7 @@
     CheckElementAccessArithmetic(access, load);
 
     MachineType rep = OpParameter<MachineType>(load);
-    CHECK_EQ(machine_reps[i], rep);
+    CHECK_EQ(kMachineReps[i], rep);
   }
 }
 
@@ -1371,14 +1519,13 @@
 TEST(LowerStoreElement_to_store) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
     ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                            Type::Any(), machine_reps[i]};
+                            Type::Any(), kMachineReps[i]};
 
-    Node* val = t.ExampleWithOutput(machine_reps[i]);
+    Node* val = t.ExampleWithOutput(kMachineReps[i]);
     Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
-                                     t.p1, t.jsgraph.Int32Constant(1024), val,
-                                     t.start, t.start);
+                                     t.p1, val, t.start, t.start);
     t.Effect(store);
     t.Lower();
     CHECK_EQ(IrOpcode::kStore, store->opcode());
@@ -1386,10 +1533,10 @@
     CheckElementAccessArithmetic(access, store);
 
     StoreRepresentation rep = OpParameter<StoreRepresentation>(store);
-    if (machine_reps[i] & kRepTagged) {
+    if (kMachineReps[i] & kRepTagged) {
       CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
     }
-    CHECK_EQ(machine_reps[i], rep.machine_type());
+    CHECK_EQ(kMachineReps[i], rep.machine_type());
   }
 }
 
@@ -1397,12 +1544,12 @@
 TEST(InsertChangeForLoadElementIndex) {
   // LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length) =>
   //   Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k))
-  TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
+  TestingGraph t(Type::Any(), Type::Signed32());
   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachAnyTagged};
 
   Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
-                                  t.p1, t.p2, t.start);
+                                  t.p1, t.start, t.start);
   t.Return(load);
   t.Lower();
   CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1416,12 +1563,12 @@
 TEST(InsertChangeForStoreElementIndex) {
   // StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length, val) =>
   //   Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val)
-  TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
+  TestingGraph t(Type::Any(), Type::Signed32());
   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachAnyTagged};
 
   Node* store =
-      t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1, t.p2,
+      t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1,
                          t.jsgraph.TrueConstant(), t.start, t.start);
   t.Effect(store);
   t.Lower();
@@ -1440,7 +1587,7 @@
                           kMachFloat64};
 
   Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
-                                  t.p1, t.p1, t.start);
+                                  t.p1, t.start, t.start);
   t.Return(load);
   t.Lower();
   CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1467,13 +1614,13 @@
 
 TEST(InsertChangeForStoreElement) {
   // TODO(titzer): test all load/store representation change insertions.
-  TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
+  TestingGraph t(Type::Any(), Type::Signed32());
   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachFloat64};
 
-  Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
-                                   t.jsgraph.Int32Constant(0), t.p2, t.p1,
-                                   t.start, t.start);
+  Node* store =
+      t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
+                         t.jsgraph.Int32Constant(0), t.p1, t.start, t.start);
   t.Effect(store);
   t.Lower();
 
@@ -1504,10 +1651,11 @@
   TestingGraph t(Type::Any(), Type::Signed32());
   static const MachineType kMachineTypes[] = {kMachInt32, kMachUint32,
                                               kMachFloat64};
+  Type* kTypes[] = {Type::Signed32(), Type::Unsigned32(), Type::Number()};
 
   for (size_t i = 0; i < arraysize(kMachineTypes); i++) {
     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                          Handle<Name>::null(), Type::Any(), kMachineTypes[i]};
+                          Handle<Name>::null(), kTypes[i], kMachineTypes[i]};
 
     Node* load0 =
         t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
@@ -1525,36 +1673,405 @@
 }
 
 
-// TODO(titzer): this tests current behavior of assuming an implicit
-// representation change in loading float32s. Fix when float32 is fully
-// supported.
-TEST(ImplicitFloat32ToFloat64InLoads) {
-  TestingGraph t(Type::Any());
+TEST(RunNumberDivide_minus_1_TruncatingToInt32) {
+  SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+  Node* num = t.NumberToInt32(t.Parameter(0));
+  Node* div = t.NumberDivide(num, t.jsgraph.Constant(-1));
+  Node* trunc = t.NumberToInt32(div);
+  t.Return(trunc);
 
-  FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                        Handle<Name>::null(), Type::Any(), kMachFloat32};
+  if (Pipeline::SupportedTarget()) {
+    t.LowerAllNodesAndLowerChanges();
+    t.GenerateCode();
 
-  Node* load =
-      t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
-  t.Return(load);
-  t.Lower();
-  CHECK_EQ(IrOpcode::kLoad, load->opcode());
-  CHECK_EQ(t.p0, load->InputAt(0));
-  CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0));
+    FOR_INT32_INPUTS(i) {
+      int32_t x = 0 - *i;
+      t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+    }
+  }
 }
 
 
-TEST(ImplicitFloat64ToFloat32InStores) {
-  TestingGraph t(Type::Any(), Type::Signed32());
-  FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                        Handle<Name>::null(), Type::Any(), kMachFloat32};
+TEST(NumberMultiply_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000};
 
-  Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
-                                   t.p1, t.start, t.start);
-  t.Effect(store);
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
+    Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mul);
+    t.Return(trunc);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Mul, mul->opcode());
+  }
+}
+
+
+TEST(RunNumberMultiply_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000, 3000999};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    double k = static_cast<double>(constants[i]);
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToInt32(t.Parameter(0));
+    Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToInt32(mul);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_INT32_INPUTS(i) {
+        int32_t x = DoubleToInt32(static_cast<double>(*i) * k);
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(RunNumberMultiply_TruncatingToUint32) {
+  uint32_t constants[] = {0, 1, 2, 3, 4, 100, 1000, 1024, 2048, 3000999};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    double k = static_cast<double>(constants[i]);
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToUint32(t.Parameter(0));
+    Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToUint32(mul);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_UINT32_INPUTS(i) {
+        uint32_t x = DoubleToUint32(static_cast<double>(*i) * k);
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(RunNumberDivide_2_TruncatingToUint32) {
+  SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+  Node* num = t.NumberToUint32(t.Parameter(0));
+  Node* div = t.NumberDivide(num, t.jsgraph.Constant(2));
+  Node* trunc = t.NumberToUint32(div);
+  t.Return(trunc);
+
+  if (Pipeline::SupportedTarget()) {
+    t.LowerAllNodesAndLowerChanges();
+    t.GenerateCode();
+
+    FOR_UINT32_INPUTS(i) {
+      uint32_t x = DoubleToUint32(static_cast<double>(*i / 2.0));
+      t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+    }
+  }
+}
+
+
+TEST(NumberMultiply_ConstantOutOfRange) {
+  TestingGraph t(Type::Signed32());
+  Node* k = t.jsgraph.Constant(1000000023);
+  Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
+  Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mul);
+  t.Return(trunc);
   t.Lower();
 
-  CHECK_EQ(IrOpcode::kStore, store->opcode());
-  CHECK_EQ(t.p0, store->InputAt(0));
-  CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(2));
+  CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode());
+}
+
+
+TEST(NumberMultiply_NonTruncating) {
+  TestingGraph t(Type::Signed32());
+  Node* k = t.jsgraph.Constant(111);
+  Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
+  t.Return(mul);
+  t.Lower();
+
+  CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode());
+}
+
+
+TEST(NumberDivide_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Div, use->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberDivide_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToInt32(t.Parameter(0));
+    Node* div = t.NumberDivide(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToInt32(div);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_INT32_INPUTS(i) {
+        if (*i == INT_MAX) continue;  // exclude max int.
+        int32_t x = DoubleToInt32(static_cast<double>(*i) / k);
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberDivide_TruncatingToUint32) {
+  double constants[] = {1, 3, 100, 1000, 100998348};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Unsigned32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachUint32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kUint32Div, use->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberDivide_TruncatingToUint32) {
+  uint32_t constants[] = {100, 10, 1, 1, 2, 4, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    uint32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToUint32(t.Parameter(0));
+    Node* div = t.NumberDivide(num, t.jsgraph.Constant(static_cast<double>(k)));
+    Node* trunc = t.NumberToUint32(div);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_UINT32_INPUTS(i) {
+        uint32_t x = *i / k;
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberDivide_BadConstants) {
+  {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(-1);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Sub, use->InputAt(0)->opcode());
+  }
+
+  {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(0);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode());
+    CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0)));
+  }
+
+  {
+    TestingGraph t(Type::Unsigned32());
+    Node* k = t.jsgraph.Constant(0);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachUint32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode());
+    CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0)));
+  }
+}
+
+
+TEST(NumberModulus_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+    Node* use = t.Use(mod, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Mod, use->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberModulus_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToInt32(t.Parameter(0));
+    Node* mod = t.NumberModulus(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToInt32(mod);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_INT32_INPUTS(i) {
+        if (*i == INT_MAX) continue;  // exclude max int.
+        int32_t x = DoubleToInt32(std::fmod(static_cast<double>(*i), k));
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberModulus_TruncatingToUint32) {
+  double constants[] = {1, 3, 100, 1000, 100998348};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Unsigned32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+    Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), mod);
+    Node* ret = t.Return(trunc);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kUint32Mod, ret->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberModulus_TruncatingToUint32) {
+  uint32_t constants[] = {1, 2, 100, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    uint32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToUint32(t.Parameter(0));
+    Node* mod =
+        t.NumberModulus(num, t.jsgraph.Constant(static_cast<double>(k)));
+    Node* trunc = t.NumberToUint32(mod);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_UINT32_INPUTS(i) {
+        uint32_t x = *i % k;
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberModulus_Int32) {
+  int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+    t.Return(mod);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kFloat64Mod, mod->opcode());  // Pesky -0 behavior.
+  }
+}
+
+
+TEST(NumberModulus_Uint32) {
+  const double kConstants[] = {2, 100, 1000, 1024, 2048};
+  const MachineType kTypes[] = {kMachInt32, kMachUint32};
+
+  for (auto const type : kTypes) {
+    for (auto const c : kConstants) {
+      TestingGraph t(Type::Unsigned32());
+      Node* k = t.jsgraph.Constant(c);
+      Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+      Node* use = t.Use(mod, type);
+      t.Return(use);
+      t.Lower();
+
+      CHECK_EQ(IrOpcode::kUint32Mod, use->InputAt(0)->opcode());
+    }
+  }
+}
+
+
+TEST(PhiRepresentation) {
+  HandleAndZoneScope scope;
+  Zone* z = scope.main_zone();
+
+  struct TestData {
+    Type* arg1;
+    Type* arg2;
+    MachineType use;
+    MachineTypeUnion expected;
+  };
+
+  TestData test_data[] = {
+      {Type::Signed32(), Type::Unsigned32(), kMachInt32,
+       kRepWord32 | kTypeNumber},
+      {Type::Signed32(), Type::Unsigned32(), kMachUint32,
+       kRepWord32 | kTypeNumber},
+      {Type::Signed32(), Type::Signed32(), kMachInt32, kMachInt32},
+      {Type::Unsigned32(), Type::Unsigned32(), kMachInt32, kMachUint32},
+      {Type::Number(), Type::Signed32(), kMachInt32, kMachFloat64},
+      {Type::Signed32(), Type::String(), kMachInt32, kMachAnyTagged}};
+
+  for (auto const d : test_data) {
+    TestingGraph t(d.arg1, d.arg2, Type::Boolean());
+
+    Node* br = t.graph()->NewNode(t.common()->Branch(), t.p2, t.start);
+    Node* tb = t.graph()->NewNode(t.common()->IfTrue(), br);
+    Node* fb = t.graph()->NewNode(t.common()->IfFalse(), br);
+    Node* m = t.graph()->NewNode(t.common()->Merge(2), tb, fb);
+
+    Node* phi =
+        t.graph()->NewNode(t.common()->Phi(kMachAnyTagged, 2), t.p0, t.p1, m);
+
+    Bounds phi_bounds = Bounds::Either(Bounds(d.arg1), Bounds(d.arg2), z);
+    NodeProperties::SetBounds(phi, phi_bounds);
+
+    Node* use = t.Use(phi, d.use);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(d.expected, OpParameter<MachineType>(phi));
+  }
 }
diff --git a/test/cctest/compiler/test-typer.cc b/test/cctest/compiler/test-typer.cc
new file mode 100644
index 0000000..5f7f55a
--- /dev/null
+++ b/test/cctest/compiler/test-typer.cc
@@ -0,0 +1,380 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <functional>
+
+#include "src/codegen.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/typer.h"
+#include "test/cctest/cctest.h"
+#include "test/cctest/compiler/graph-builder-tester.h"
+#include "test/cctest/types-fuzz.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+
+// TODO(titzer): generate a large set of deterministic inputs for these tests.
+class TyperTester : public HandleAndZoneScope, public GraphAndBuilders {
+ public:
+  TyperTester()
+      : GraphAndBuilders(main_zone()),
+        types_(main_zone(), isolate()),
+        typer_(graph(), MaybeHandle<Context>()),
+        javascript_(main_zone()) {
+    Node* s = graph()->NewNode(common()->Start(3));
+    graph()->SetStart(s);
+    context_node_ = graph()->NewNode(common()->Parameter(2), graph()->start());
+    rng_ = isolate()->random_number_generator();
+
+    integers.push_back(0);
+    integers.push_back(0);
+    integers.push_back(-1);
+    integers.push_back(+1);
+    integers.push_back(-V8_INFINITY);
+    integers.push_back(+V8_INFINITY);
+    for (int i = 0; i < 5; ++i) {
+      double x = rng_->NextInt();
+      integers.push_back(x);
+      x *= rng_->NextInt();
+      if (!IsMinusZero(x)) integers.push_back(x);
+    }
+
+    int32s.push_back(0);
+    int32s.push_back(0);
+    int32s.push_back(-1);
+    int32s.push_back(+1);
+    int32s.push_back(kMinInt);
+    int32s.push_back(kMaxInt);
+    for (int i = 0; i < 10; ++i) {
+      int32s.push_back(rng_->NextInt());
+    }
+  }
+
+  Types<Type, Type*, Zone> types_;
+  Typer typer_;
+  JSOperatorBuilder javascript_;
+  Node* context_node_;
+  v8::base::RandomNumberGenerator* rng_;
+  std::vector<double> integers;
+  std::vector<double> int32s;
+
+  Isolate* isolate() { return main_isolate(); }
+  Graph* graph() { return main_graph_; }
+  CommonOperatorBuilder* common() { return &main_common_; }
+
+  Node* Parameter(int index = 0) {
+    return graph()->NewNode(common()->Parameter(index), graph()->start());
+  }
+
+  Type* TypeBinaryOp(const Operator* op, Type* lhs, Type* rhs) {
+    Node* p0 = Parameter(0);
+    Node* p1 = Parameter(1);
+    NodeProperties::SetBounds(p0, Bounds(lhs));
+    NodeProperties::SetBounds(p1, Bounds(rhs));
+    Node* n = graph()->NewNode(
+        op, p0, p1, context_node_, graph()->start(), graph()->start());
+    return NodeProperties::GetBounds(n).upper;
+  }
+
+  Type* RandomRange(bool int32 = false) {
+    std::vector<double>& numbers = int32 ? int32s : integers;
+    double i = numbers[rng_->NextInt(static_cast<int>(numbers.size()))];
+    double j = numbers[rng_->NextInt(static_cast<int>(numbers.size()))];
+    return NewRange(i, j);
+  }
+
+  Type* NewRange(double i, double j) {
+    Factory* f = isolate()->factory();
+    i::Handle<i::Object> min = f->NewNumber(i);
+    i::Handle<i::Object> max = f->NewNumber(j);
+    if (min->Number() > max->Number()) std::swap(min, max);
+    return Type::Range(min, max, main_zone());
+  }
+
+  double RandomInt(double min, double max) {
+    switch (rng_->NextInt(4)) {
+      case 0: return min;
+      case 1: return max;
+      default: break;
+    }
+    if (min == +V8_INFINITY) return +V8_INFINITY;
+    if (max == -V8_INFINITY) return -V8_INFINITY;
+    if (min == -V8_INFINITY && max == +V8_INFINITY) {
+      return rng_->NextInt() * static_cast<double>(rng_->NextInt());
+    }
+    double result = nearbyint(min + (max - min) * rng_->NextDouble());
+    if (IsMinusZero(result)) return 0;
+    if (std::isnan(result)) return rng_->NextInt(2) ? min : max;
+    DCHECK(min <= result && result <= max);
+    return result;
+  }
+
+  double RandomInt(Type::RangeType* range) {
+    return RandomInt(range->Min()->Number(), range->Max()->Number());
+  }
+
+  // Careful, this function runs O(max_width^5) trials.
+  template <class BinaryFunction>
+  void TestBinaryArithOpCloseToZero(const Operator* op, BinaryFunction opfun,
+                                    int max_width) {
+    const int min_min = -2 - max_width / 2;
+    const int max_min = 2 + max_width / 2;
+    for (int width = 0; width < max_width; width++) {
+      for (int lmin = min_min; lmin <= max_min; lmin++) {
+        for (int rmin = min_min; rmin <= max_min; rmin++) {
+          Type* r1 = NewRange(lmin, lmin + width);
+          Type* r2 = NewRange(rmin, rmin + width);
+          Type* expected_type = TypeBinaryOp(op, r1, r2);
+
+          for (int x1 = lmin; x1 < lmin + width; x1++) {
+            for (int x2 = rmin; x2 < rmin + width; x2++) {
+              double result_value = opfun(x1, x2);
+              Type* result_type = Type::Constant(
+                  isolate()->factory()->NewNumber(result_value), main_zone());
+              CHECK(result_type->Is(expected_type));
+            }
+          }
+        }
+      }
+    }
+  }
+
+  template <class BinaryFunction>
+  void TestBinaryArithOp(const Operator* op, BinaryFunction opfun) {
+    TestBinaryArithOpCloseToZero(op, opfun, 8);
+    for (int i = 0; i < 100; ++i) {
+      Type::RangeType* r1 = RandomRange()->AsRange();
+      Type::RangeType* r2 = RandomRange()->AsRange();
+      Type* expected_type = TypeBinaryOp(op, r1, r2);
+      for (int i = 0; i < 10; i++) {
+        double x1 = RandomInt(r1);
+        double x2 = RandomInt(r2);
+        double result_value = opfun(x1, x2);
+        Type* result_type = Type::Constant(
+            isolate()->factory()->NewNumber(result_value), main_zone());
+        CHECK(result_type->Is(expected_type));
+      }
+    }
+  }
+
+  template <class BinaryFunction>
+  void TestBinaryCompareOp(const Operator* op, BinaryFunction opfun) {
+    for (int i = 0; i < 100; ++i) {
+      Type::RangeType* r1 = RandomRange()->AsRange();
+      Type::RangeType* r2 = RandomRange()->AsRange();
+      Type* expected_type = TypeBinaryOp(op, r1, r2);
+      for (int i = 0; i < 10; i++) {
+        double x1 = RandomInt(r1);
+        double x2 = RandomInt(r2);
+        bool result_value = opfun(x1, x2);
+        Type* result_type =
+            Type::Constant(result_value ? isolate()->factory()->true_value()
+                                        : isolate()->factory()->false_value(),
+                           main_zone());
+        CHECK(result_type->Is(expected_type));
+      }
+    }
+  }
+
+  template <class BinaryFunction>
+  void TestBinaryBitOp(const Operator* op, BinaryFunction opfun) {
+    for (int i = 0; i < 100; ++i) {
+      Type::RangeType* r1 = RandomRange(true)->AsRange();
+      Type::RangeType* r2 = RandomRange(true)->AsRange();
+      Type* expected_type = TypeBinaryOp(op, r1, r2);
+      for (int i = 0; i < 10; i++) {
+        int32_t x1 = static_cast<int32_t>(RandomInt(r1));
+        int32_t x2 = static_cast<int32_t>(RandomInt(r2));
+        double result_value = opfun(x1, x2);
+        Type* result_type = Type::Constant(
+            isolate()->factory()->NewNumber(result_value), main_zone());
+        CHECK(result_type->Is(expected_type));
+      }
+    }
+  }
+
+  Type* RandomSubtype(Type* type) {
+    Type* subtype;
+    do {
+      subtype = types_.Fuzz();
+    } while (!subtype->Is(type));
+    return subtype;
+  }
+
+  void TestBinaryMonotonicity(const Operator* op) {
+    for (int i = 0; i < 50; ++i) {
+      Type* type1 = types_.Fuzz();
+      Type* type2 = types_.Fuzz();
+      Type* type = TypeBinaryOp(op, type1, type2);
+      Type* subtype1 = RandomSubtype(type1);;
+      Type* subtype2 = RandomSubtype(type2);;
+      Type* subtype = TypeBinaryOp(op, subtype1, subtype2);
+      CHECK(subtype->Is(type));
+    }
+  }
+};
+
+
+static int32_t shift_left(int32_t x, int32_t y) { return x << y; }
+static int32_t shift_right(int32_t x, int32_t y) { return x >> y; }
+static int32_t bit_or(int32_t x, int32_t y) { return x | y; }
+static int32_t bit_and(int32_t x, int32_t y) { return x & y; }
+static int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; }
+
+
+//------------------------------------------------------------------------------
+// Soundness
+//   For simplicity, we currently only test soundness on expression operators
+//   that have a direct equivalent in C++.  Also, testing is currently limited
+//   to ranges as input types.
+
+
+TEST(TypeJSAdd) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Add(), std::plus<double>());
+}
+
+
+TEST(TypeJSSubtract) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Subtract(), std::minus<double>());
+}
+
+
+TEST(TypeJSMultiply) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Multiply(), std::multiplies<double>());
+}
+
+
+TEST(TypeJSDivide) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Divide(), std::divides<double>());
+}
+
+
+TEST(TypeJSModulus) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Modulus(), modulo);
+}
+
+
+TEST(TypeJSBitwiseOr) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.BitwiseOr(), bit_or);
+}
+
+
+TEST(TypeJSBitwiseAnd) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.BitwiseAnd(), bit_and);
+}
+
+
+TEST(TypeJSBitwiseXor) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.BitwiseXor(), bit_xor);
+}
+
+
+TEST(TypeJSShiftLeft) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.ShiftLeft(), shift_left);
+}
+
+
+TEST(TypeJSShiftRight) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.ShiftRight(), shift_right);
+}
+
+
+TEST(TypeJSLessThan) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.LessThan(), std::less<double>());
+}
+
+
+TEST(TypeJSLessThanOrEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(
+      t.javascript_.LessThanOrEqual(), std::less_equal<double>());
+}
+
+
+TEST(TypeJSGreaterThan) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.GreaterThan(), std::greater<double>());
+}
+
+
+TEST(TypeJSGreaterThanOrEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(
+      t.javascript_.GreaterThanOrEqual(), std::greater_equal<double>());
+}
+
+
+TEST(TypeJSEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.Equal(), std::equal_to<double>());
+}
+
+
+TEST(TypeJSNotEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.NotEqual(), std::not_equal_to<double>());
+}
+
+
+// For numbers there's no difference between strict and non-strict equality.
+TEST(TypeJSStrictEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.StrictEqual(), std::equal_to<double>());
+}
+
+
+TEST(TypeJSStrictNotEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(
+      t.javascript_.StrictNotEqual(), std::not_equal_to<double>());
+}
+
+
+//------------------------------------------------------------------------------
+// Monotonicity
+
+
+// List should be in sync with JS_SIMPLE_BINOP_LIST.
+#define JSBINOP_LIST(V) \
+  V(Equal) \
+  V(NotEqual) \
+  V(StrictEqual) \
+  V(StrictNotEqual) \
+  V(LessThan) \
+  V(GreaterThan) \
+  V(LessThanOrEqual) \
+  V(GreaterThanOrEqual) \
+  V(BitwiseOr) \
+  V(BitwiseXor) \
+  V(BitwiseAnd) \
+  V(ShiftLeft) \
+  V(ShiftRight) \
+  V(ShiftRightLogical) \
+  V(Add) \
+  V(Subtract) \
+  V(Multiply) \
+  V(Divide) \
+  V(Modulus)
+
+
+#define TEST_FUNC(name)                             \
+  TEST(Monotonicity_##name) {                       \
+    TyperTester t;                                  \
+    t.TestBinaryMonotonicity(t.javascript_.name()); \
+  }
+JSBINOP_LIST(TEST_FUNC)
+#undef TEST_FUNC
diff --git a/test/cctest/compiler/value-helper.h b/test/cctest/compiler/value-helper.h
index b5da982..218a773 100644
--- a/test/cctest/compiler/value-helper.h
+++ b/test/cctest/compiler/value-helper.h
@@ -60,6 +60,45 @@
     CheckHeapConstant(isolate_->heap()->false_value(), node);
   }
 
+  static std::vector<float> float32_vector() {
+    static const float kValues[] = {
+        -std::numeric_limits<float>::infinity(), -2.70497e+38f, -1.4698e+37f,
+        -1.22813e+35f,                           -1.20555e+35f, -1.34584e+34f,
+        -1.0079e+32f,                            -6.49364e+26f, -3.06077e+25f,
+        -1.46821e+25f,                           -1.17658e+23f, -1.9617e+22f,
+        -2.7357e+20f,                            -1.48708e+13f, -1.89633e+12f,
+        -4.66622e+11f,                           -2.22581e+11f, -1.45381e+10f,
+        -1.3956e+09f,                            -1.32951e+09f, -1.30721e+09f,
+        -1.19756e+09f,                           -9.26822e+08f, -6.35647e+08f,
+        -4.00037e+08f,                           -1.81227e+08f, -5.09256e+07f,
+        -964300.0f,                              -192446.0f,    -28455.0f,
+        -27194.0f,                               -26401.0f,     -20575.0f,
+        -17069.0f,                               -9167.0f,      -960.178f,
+        -113.0f,                                 -62.0f,        -15.0f,
+        -7.0f,                                   -0.0256635f,   -4.60374e-07f,
+        -3.63759e-10f,                           -4.30175e-14f, -5.27385e-15f,
+        -1.48084e-15f,                           -1.05755e-19f, -3.2995e-21f,
+        -1.67354e-23f,                           -1.11885e-23f, -1.78506e-30f,
+        -5.07594e-31f,                           -3.65799e-31f, -1.43718e-34f,
+        -1.27126e-38f,                           -0.0f,         0.0f,
+        1.17549e-38f,                            1.56657e-37f,  4.08512e-29f,
+        3.31357e-28f,                            6.25073e-22f,  4.1723e-13f,
+        1.44343e-09f,                            5.27004e-08f,  9.48298e-08f,
+        5.57888e-07f,                            4.89988e-05f,  0.244326f,
+        12.4895f,                                19.0f,         47.0f,
+        106.0f,                                  538.324f,      564.536f,
+        819.124f,                                7048.0f,       12611.0f,
+        19878.0f,                                20309.0f,      797056.0f,
+        1.77219e+09f,                            1.51116e+11f,  4.18193e+13f,
+        3.59167e+16f,                            3.38211e+19f,  2.67488e+20f,
+        1.78831e+21f,                            9.20914e+21f,  8.35654e+23f,
+        1.4495e+24f,                             5.94015e+25f,  4.43608e+30f,
+        2.44502e+33f,                            2.61152e+33f,  1.38178e+37f,
+        1.71306e+37f,                            3.31899e+38f,  3.40282e+38f,
+        std::numeric_limits<float>::infinity()};
+    return std::vector<float>(&kValues[0], &kValues[arraysize(kValues)]);
+  }
+
   static std::vector<double> float64_vector() {
     static const double nan = v8::base::OS::nan_value();
     static const double values[] = {
@@ -82,6 +121,8 @@
   static const std::vector<uint32_t> uint32_vector() {
     static const uint32_t kValues[] = {
         0x00000000, 0x00000001, 0xffffffff, 0x1b09788b, 0x04c5fce8, 0xcc0de5bf,
+        // This row is useful for testing lea optimizations on intel.
+        0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000008, 0x00000009,
         0x273a798e, 0x187937a3, 0xece3af83, 0x5495a16b, 0x0b668ecc, 0x11223344,
         0x0000009e, 0x00000043, 0x0000af73, 0x0000116b, 0x00658ecc, 0x002b3b4c,
         0x88776655, 0x70000000, 0x07200000, 0x7fffffff, 0x56123761, 0x7fffff00,
@@ -117,6 +158,7 @@
 
 #define FOR_INT32_INPUTS(var) FOR_INPUTS(int32_t, int32, var)
 #define FOR_UINT32_INPUTS(var) FOR_INPUTS(uint32_t, uint32, var)
+#define FOR_FLOAT32_INPUTS(var) FOR_INPUTS(float, float32, var)
 #define FOR_FLOAT64_INPUTS(var) FOR_INPUTS(double, float64, var)
 
 #define FOR_INT32_SHIFTS(var) for (int32_t var = 0; var < 32; var++)
diff --git a/test/cctest/test-accessors.cc b/test/cctest/test-accessors.cc
index 5bf61c8..5f452ea 100644
--- a/test/cctest/test-accessors.cc
+++ b/test/cctest/test-accessors.cc
@@ -38,6 +38,7 @@
 using ::v8::Value;
 using ::v8::Context;
 using ::v8::Local;
+using ::v8::Name;
 using ::v8::String;
 using ::v8::Script;
 using ::v8::Function;
@@ -513,7 +514,7 @@
 }
 
 
-void JSONStringifyGetter(Local<String> name,
+void JSONStringifyGetter(Local<Name> name,
                          const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(v8_str("crbug-161028"));
 }
@@ -525,8 +526,8 @@
   v8::HandleScope scope(isolate);
 
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(
-      JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator));
   env->Global()->Set(v8_str("obj"), obj->NewInstance());
   v8::Handle<v8::String> expected = v8_str("{\"regress\":\"crbug-161028\"}");
   CHECK(CompileRun("JSON.stringify(obj)")->Equals(expected));
@@ -577,3 +578,30 @@
   CHECK(v8::Utils::OpenHandle(*CompileRun("getter()"))->IsJSGlobalProxy());
   CHECK(v8::Utils::OpenHandle(*CompileRun("set_value"))->IsJSGlobalProxy());
 }
+
+
+static void EmptyGetter(Local<Name> name,
+                        const v8::PropertyCallbackInfo<v8::Value>& info) {
+  ApiTestFuzzer::Fuzz();
+}
+
+
+static void OneProperty(Local<String> name,
+                        const v8::PropertyCallbackInfo<v8::Value>& info) {
+  ApiTestFuzzer::Fuzz();
+  info.GetReturnValue().Set(v8_num(1));
+}
+
+
+THREADED_TEST(Regress433458) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(EmptyGetter));
+  obj->SetNativeDataProperty(v8_str("prop"), OneProperty);
+  env->Global()->Set(v8_str("obj"), obj->NewInstance());
+  CompileRun(
+      "Object.defineProperty(obj, 'prop', { writable: false });"
+      "Object.defineProperty(obj, 'prop', { writable: true });");
+}
diff --git a/test/cctest/test-alloc.cc b/test/cctest/test-alloc.cc
index d647a31..2e071ac 100644
--- a/test/cctest/test-alloc.cc
+++ b/test/cctest/test-alloc.cc
@@ -86,7 +86,7 @@
       Builtins::kIllegal)).ToObjectChecked();
 
   // Return success.
-  return Smi::FromInt(42);
+  return heap->true_value();
 }
 
 
@@ -100,7 +100,7 @@
   v8::Handle<v8::Context> env = v8::Context::New(CcTest::isolate());
   env->Enter();
   Handle<Object> o = Test();
-  CHECK(o->IsSmi() && Smi::cast(*o)->value() == 42);
+  CHECK(o->IsTrue());
   env->Exit();
 }
 
@@ -162,7 +162,7 @@
   // Call the accessor through JavaScript.
   v8::Handle<v8::Value> result = v8::Script::Compile(
       v8::String::NewFromUtf8(CcTest::isolate(), "(new Foo).get"))->Run();
-  CHECK_EQ(42, result->Int32Value());
+  CHECK_EQ(true, result->BooleanValue());
   env->Exit();
 }
 
@@ -198,7 +198,8 @@
   const size_t code_range_size = 32*MB;
   CcTest::InitializeVM();
   CodeRange code_range(reinterpret_cast<Isolate*>(CcTest::isolate()));
-  code_range.SetUp(code_range_size);
+  code_range.SetUp(code_range_size +
+                   kReservedCodeRangePages * v8::base::OS::CommitPageSize());
   size_t current_allocated = 0;
   size_t total_allocated = 0;
   List< ::Block> blocks(1000);
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 0e80384..06cf553 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -185,7 +185,8 @@
 }
 
 
-static void TestSignature(const char* loop_js, Local<Value> receiver) {
+static void TestSignature(const char* loop_js, Local<Value> receiver,
+                          v8::Isolate* isolate) {
   i::ScopedVector<char> source(200);
   i::SNPrintF(source,
               "for (var i = 0; i < 10; i++) {"
@@ -202,7 +203,7 @@
     CHECK_EQ(10, signature_callback_count);
   } else {
     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
-             try_catch.Exception()->ToString());
+             try_catch.Exception()->ToString(isolate));
   }
 }
 
@@ -267,17 +268,17 @@
     i::SNPrintF(
         source, "var test_object = %s; test_object", test_objects[i]);
     Local<Value> test_object = CompileRun(source.start());
-    TestSignature("test_object.prop();", test_object);
-    TestSignature("test_object.accessor;", test_object);
-    TestSignature("test_object[accessor_key];", test_object);
-    TestSignature("test_object.accessor = 1;", test_object);
-    TestSignature("test_object[accessor_key] = 1;", test_object);
+    TestSignature("test_object.prop();", test_object, isolate);
+    TestSignature("test_object.accessor;", test_object, isolate);
+    TestSignature("test_object[accessor_key];", test_object, isolate);
+    TestSignature("test_object.accessor = 1;", test_object, isolate);
+    TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
     if (i >= bad_signature_start_offset) test_object = Local<Value>();
-    TestSignature("test_object.prop_sig();", test_object);
-    TestSignature("test_object.accessor_sig;", test_object);
-    TestSignature("test_object[accessor_sig_key];", test_object);
-    TestSignature("test_object.accessor_sig = 1;", test_object);
-    TestSignature("test_object[accessor_sig_key] = 1;", test_object);
+    TestSignature("test_object.prop_sig();", test_object, isolate);
+    TestSignature("test_object.accessor_sig;", test_object, isolate);
+    TestSignature("test_object[accessor_sig_key];", test_object, isolate);
+    TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
+    TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
   }
 }
 
@@ -356,7 +357,7 @@
   v8::Isolate* isolate = env->GetIsolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
-  Local<String> undef_str = undef->ToString();
+  Local<String> undef_str = undef->ToString(isolate);
   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
   undef_str->WriteUtf8(value);
   CHECK_EQ(0, strcmp(value, "undefined"));
@@ -742,6 +743,58 @@
 }
 
 
+class RandomLengthResource : public v8::String::ExternalStringResource {
+ public:
+  explicit RandomLengthResource(int length) : length_(length) {}
+  virtual const uint16_t* data() const { return string_; }
+  virtual size_t length() const { return length_; }
+
+ private:
+  uint16_t string_[10];
+  int length_;
+};
+
+
+class RandomLengthOneByteResource
+    : public v8::String::ExternalOneByteStringResource {
+ public:
+  explicit RandomLengthOneByteResource(int length) : length_(length) {}
+  virtual const char* data() const { return string_; }
+  virtual size_t length() const { return length_; }
+
+ private:
+  char string_[10];
+  int length_;
+};
+
+
+THREADED_TEST(NewExternalForVeryLongString) {
+  {
+    LocalContext env;
+    v8::HandleScope scope(env->GetIsolate());
+    v8::TryCatch try_catch;
+    RandomLengthOneByteResource r(1 << 30);
+    v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
+    CHECK(str.IsEmpty());
+    CHECK(try_catch.HasCaught());
+    String::Utf8Value exception_value(try_catch.Exception());
+    CHECK_EQ("RangeError: Invalid string length", *exception_value);
+  }
+
+  {
+    LocalContext env;
+    v8::HandleScope scope(env->GetIsolate());
+    v8::TryCatch try_catch;
+    RandomLengthResource r(1 << 30);
+    v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
+    CHECK(str.IsEmpty());
+    CHECK(try_catch.HasCaught());
+    String::Utf8Value exception_value(try_catch.Exception());
+    CHECK_EQ("RangeError: Invalid string length", *exception_value);
+  }
+}
+
+
 THREADED_TEST(ScavengeExternalString) {
   i::FLAG_stress_compaction = false;
   i::FLAG_gc_global = false;
@@ -934,7 +987,7 @@
   // If CPU profiler is active check that when API callback is invoked
   // VMState is set to EXTERNAL.
   if (isolate->cpu_profiler()->is_profiling()) {
-    CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
+    CHECK_EQ(v8::EXTERNAL, isolate->current_vm_state());
     CHECK(isolate->external_callback_scope());
     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
   }
@@ -1181,7 +1234,8 @@
 
 THREADED_PROFILED_TEST(FastReturnValues) {
   LocalContext env;
-  v8::HandleScope scope(CcTest::isolate());
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
   v8::Handle<v8::Value> value;
   // check int32_t and uint32_t
   int32_t int_values[] = {
@@ -1206,13 +1260,13 @@
   // check double
   value = TestFastReturnValues<double>();
   CHECK(value->IsNumber());
-  CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
+  CHECK_EQ(kFastReturnValueDouble, value->ToNumber(isolate)->Value());
   // check bool values
   for (int i = 0; i < 2; i++) {
     fast_return_value_bool = i == 0;
     value = TestFastReturnValues<bool>();
     CHECK(value->IsBoolean());
-    CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
+    CHECK_EQ(fast_return_value_bool, value->ToBoolean(isolate)->Value());
   }
   // check oddballs
   ReturnValueOddball oddballs[] = {
@@ -1542,6 +1596,34 @@
 }
 
 
+THREADED_TEST(IsGeneratorFunctionOrObject) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+
+  CompileRun("function *gen() { yield 1; }\nfunction func() {}");
+  v8::Handle<Value> gen = CompileRun("gen");
+  v8::Handle<Value> genObj = CompileRun("gen()");
+  v8::Handle<Value> object = CompileRun("{a:42}");
+  v8::Handle<Value> func = CompileRun("func");
+
+  CHECK(gen->IsGeneratorFunction());
+  CHECK(gen->IsFunction());
+  CHECK(!gen->IsGeneratorObject());
+
+  CHECK(!genObj->IsGeneratorFunction());
+  CHECK(!genObj->IsFunction());
+  CHECK(genObj->IsGeneratorObject());
+
+  CHECK(!object->IsGeneratorFunction());
+  CHECK(!object->IsFunction());
+  CHECK(!object->IsGeneratorObject());
+
+  CHECK(!func->IsGeneratorFunction());
+  CHECK(func->IsFunction());
+  CHECK(!func->IsGeneratorObject());
+}
+
+
 THREADED_TEST(ArgumentsObject) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
@@ -1904,7 +1986,7 @@
 int echo_named_call_count;
 
 
-static void EchoNamedProperty(Local<String> name,
+static void EchoNamedProperty(Local<Name> name,
                               const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK_EQ(v8_str("data"), info.Data());
@@ -1946,18 +2028,41 @@
   SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
 }
 
-void EmptyInterceptorGetter(Local<String> name,
-                            const v8::PropertyCallbackInfo<v8::Value>& info) {
+void SymbolAccessorGetterReturnsDefault(
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+  CHECK(name->IsSymbol());
+  Local<Symbol> sym = Local<Symbol>::Cast(name);
+  if (sym->Name()->IsUndefined()) return;
+  info.GetReturnValue().Set(info.Data());
 }
 
-void EmptyInterceptorSetter(Local<String> name,
-                            Local<Value> value,
-                            const v8::PropertyCallbackInfo<v8::Value>& info) {
+static void ThrowingSymbolAccessorGetter(
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+  info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
 }
 
-void InterceptorGetter(Local<String> name,
-                       const v8::PropertyCallbackInfo<v8::Value>& info) {
-  // Intercept names that start with 'interceptor_'.
+
+void EmptyInterceptorGetter(Local<Name> name,
+                            const v8::PropertyCallbackInfo<v8::Value>& info) {}
+
+
+void EmptyInterceptorSetter(Local<Name> name, Local<Value> value,
+                            const v8::PropertyCallbackInfo<v8::Value>& info) {}
+
+
+void EmptyGenericInterceptorGetter(
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
+
+
+void EmptyGenericInterceptorSetter(
+    Local<Name> name, Local<Value> value,
+    const v8::PropertyCallbackInfo<v8::Value>& info) {}
+
+
+void StringInterceptorGetter(
+    Local<String> name,
+    const v8::PropertyCallbackInfo<v8::Value>&
+        info) {  // Intercept names that start with 'interceptor_'.
   String::Utf8Value utf8(name);
   char* name_str = *utf8;
   char prefix[] = "interceptor_";
@@ -1969,9 +2074,9 @@
   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
 }
 
-void InterceptorSetter(Local<String> name,
-                       Local<Value> value,
-                       const v8::PropertyCallbackInfo<v8::Value>& info) {
+
+void StringInterceptorSetter(Local<String> name, Local<Value> value,
+                             const v8::PropertyCallbackInfo<v8::Value>& info) {
   // Intercept accesses that set certain integer values, for which the name does
   // not start with 'accessor_'.
   String::Utf8Value utf8(name);
@@ -1990,6 +2095,57 @@
   }
 }
 
+void InterceptorGetter(Local<Name> generic_name,
+                       const v8::PropertyCallbackInfo<v8::Value>& info) {
+  if (generic_name->IsSymbol()) return;
+  StringInterceptorGetter(Local<String>::Cast(generic_name), info);
+}
+
+void InterceptorSetter(Local<Name> generic_name, Local<Value> value,
+                       const v8::PropertyCallbackInfo<v8::Value>& info) {
+  if (generic_name->IsSymbol()) return;
+  StringInterceptorSetter(Local<String>::Cast(generic_name), value, info);
+}
+
+void GenericInterceptorGetter(Local<Name> generic_name,
+                              const v8::PropertyCallbackInfo<v8::Value>& info) {
+  Local<String> str;
+  if (generic_name->IsSymbol()) {
+    Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
+    if (name->IsUndefined()) return;
+    str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
+  } else {
+    Local<String> name = Local<String>::Cast(generic_name);
+    String::Utf8Value utf8(name);
+    char* name_str = *utf8;
+    if (*name_str == '_') return;
+    str = String::Concat(v8_str("_str_"), name);
+  }
+
+  Handle<Object> self = Handle<Object>::Cast(info.This());
+  info.GetReturnValue().Set(self->Get(str));
+}
+
+void GenericInterceptorSetter(Local<Name> generic_name, Local<Value> value,
+                              const v8::PropertyCallbackInfo<v8::Value>& info) {
+  Local<String> str;
+  if (generic_name->IsSymbol()) {
+    Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
+    if (name->IsUndefined()) return;
+    str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
+  } else {
+    Local<String> name = Local<String>::Cast(generic_name);
+    String::Utf8Value utf8(name);
+    char* name_str = *utf8;
+    if (*name_str == '_') return;
+    str = String::Concat(v8_str("_str_"), name);
+  }
+
+  Handle<Object> self = Handle<Object>::Cast(info.This());
+  self->Set(str, value);
+  info.GetReturnValue().Set(value);
+}
+
 void AddAccessor(Handle<FunctionTemplate> templ,
                  Handle<String> name,
                  v8::AccessorGetterCallback getter,
@@ -2011,6 +2167,13 @@
   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
 }
 
+void AddInterceptor(Handle<FunctionTemplate> templ,
+                    v8::GenericNamedPropertyGetterCallback getter,
+                    v8::GenericNamedPropertySetterCallback setter) {
+  templ->InstanceTemplate()->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(getter, setter));
+}
+
 
 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
   v8::HandleScope scope(CcTest::isolate());
@@ -2030,6 +2193,62 @@
 }
 
 
+THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
+  LocalContext env;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
+  Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
+  v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
+
+  child->Inherit(parent);
+  AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
+  AddInterceptor(child, StringInterceptorGetter, StringInterceptorSetter);
+
+  env->Global()->Set(v8_str("Child"), child->GetFunction());
+  env->Global()->Set(v8_str("age"), age);
+  CompileRun(
+      "var child = new Child;"
+      "child[age] = 10;");
+  ExpectInt32("child[age]", 10);
+  ExpectBoolean("child.hasOwnProperty('age')", false);
+  ExpectBoolean("child.hasOwnProperty('accessor_age')", true);
+}
+
+
+THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
+  LocalContext env;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
+  Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
+  v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
+  v8::Local<v8::Symbol> anon = v8::Symbol::New(isolate);
+
+  child->Inherit(parent);
+  AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
+  AddInterceptor(child, GenericInterceptorGetter, GenericInterceptorSetter);
+
+  env->Global()->Set(v8_str("Child"), child->GetFunction());
+  env->Global()->Set(v8_str("age"), age);
+  env->Global()->Set(v8_str("anon"), anon);
+  CompileRun(
+      "var child = new Child;"
+      "child[age] = 10;");
+  ExpectInt32("child[age]", 10);
+  ExpectInt32("child._sym_age", 10);
+
+  // Check that it also sees strings.
+  CompileRun("child.foo = 47");
+  ExpectInt32("child.foo", 47);
+  ExpectInt32("child._str_foo", 47);
+
+  // Check that the interceptor can punt (in this case, on anonymous symbols).
+  CompileRun("child[anon] = 31337");
+  ExpectInt32("child[anon]", 31337);
+}
+
+
 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
@@ -2275,9 +2494,8 @@
   v8::HandleScope scope(CcTest::isolate());
   v8::Handle<v8::FunctionTemplate> templ =
       v8::FunctionTemplate::New(CcTest::isolate());
-  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
-                                                     0, 0, 0, 0,
-                                                     v8_str("data"));
+  templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      EchoNamedProperty, 0, 0, 0, 0, v8_str("data")));
   LocalContext env;
   env->Global()->Set(v8_str("obj"),
                      templ->GetFunction()->NewInstance());
@@ -2312,9 +2530,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
-  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
-                                                       0, 0, 0, 0,
-                                                       v8_num(637));
+  templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      EchoIndexedProperty, 0, 0, 0, 0, v8_num(637)));
   LocalContext env;
   env->Global()->Set(v8_str("obj"),
                      templ->GetFunction()->NewInstance());
@@ -2334,8 +2551,7 @@
 }
 
 static void CheckThisNamedPropertyHandler(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
@@ -2352,8 +2568,7 @@
 
 
 void CheckThisNamedPropertySetter(
-    Local<String> property,
-    Local<Value> value,
+    Local<Name> property, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
   ApiTestFuzzer::Fuzz();
@@ -2370,8 +2585,7 @@
 
 
 void CheckThisNamedPropertyQuery(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
@@ -2388,8 +2602,7 @@
 
 
 void CheckThisNamedPropertyDeleter(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Boolean>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
@@ -2419,19 +2632,15 @@
 
   // Set up a prototype chain with three interceptors.
   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
-  templ->InstanceTemplate()->SetIndexedPropertyHandler(
-      CheckThisIndexedPropertyHandler,
-      CheckThisIndexedPropertySetter,
-      CheckThisIndexedPropertyQuery,
-      CheckThisIndexedPropertyDeleter,
-      CheckThisIndexedPropertyEnumerator);
+  templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
+      CheckThisIndexedPropertyQuery, CheckThisIndexedPropertyDeleter,
+      CheckThisIndexedPropertyEnumerator));
 
-  templ->InstanceTemplate()->SetNamedPropertyHandler(
-      CheckThisNamedPropertyHandler,
-      CheckThisNamedPropertySetter,
-      CheckThisNamedPropertyQuery,
-      CheckThisNamedPropertyDeleter,
-      CheckThisNamedPropertyEnumerator);
+  templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
+      CheckThisNamedPropertyQuery, CheckThisNamedPropertyDeleter,
+      CheckThisNamedPropertyEnumerator));
 
   bottom = templ->GetFunction()->NewInstance();
   Local<v8::Object> top = templ->GetFunction()->NewInstance();
@@ -2463,8 +2672,7 @@
 
 
 static void PrePropertyHandlerGet(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("pre")->Equals(key)) {
     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
@@ -2473,8 +2681,7 @@
 
 
 static void PrePropertyHandlerQuery(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   if (v8_str("pre")->Equals(key)) {
     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
   }
@@ -2485,9 +2692,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
-  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
-                                                    0,
-                                                    PrePropertyHandlerQuery);
+  desc->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      PrePropertyHandlerGet, 0, PrePropertyHandlerQuery));
   LocalContext env(NULL, desc->InstanceTemplate());
   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
   v8::Handle<Value> result_pre = CompileRun("pre");
@@ -2560,16 +2766,17 @@
 
 
 static void ThrowingPropertyHandlerGet(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
+  // Since this interceptor is used on "with" objects, the runtime will look up
+  // @@unscopables.  Punt.
+  if (key->IsSymbol()) return;
   ApiTestFuzzer::Fuzz();
   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
 }
 
 
 static void ThrowingPropertyHandlerSet(
-    Local<String> key,
-    Local<Value>,
+    Local<Name> key, Local<Value>,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetIsolate()->ThrowException(key);
   info.GetReturnValue().SetUndefined();  // not the same as empty handle
@@ -2580,8 +2787,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
-                               ThrowingPropertyHandlerSet);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
   LocalContext env;
   env->Global()->Set(v8_str("obj"), obj->NewInstance());
   v8::Handle<Value> otto = CompileRun(
@@ -2749,6 +2956,16 @@
 }
 
 
+THREADED_TEST(GetIsolate) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  Local<v8::Object> obj = v8::Object::New(isolate);
+  CHECK_EQ(isolate, obj->GetIsolate());
+  CHECK_EQ(isolate, CcTest::global()->GetIsolate());
+}
+
+
 THREADED_TEST(IdentityHash) {
   LocalContext env;
   v8::Isolate* isolate = env->GetIsolate();
@@ -2813,6 +3030,53 @@
 }
 
 
+TEST(SymbolIdentityHash) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  {
+    Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
+    int hash = symbol->GetIdentityHash();
+    int hash1 = symbol->GetIdentityHash();
+    CHECK_EQ(hash, hash1);
+    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+    int hash3 = symbol->GetIdentityHash();
+    CHECK_EQ(hash, hash3);
+  }
+
+  {
+    v8::Handle<v8::Symbol> js_symbol =
+        CompileRun("Symbol('foo')").As<v8::Symbol>();
+    int hash = js_symbol->GetIdentityHash();
+    int hash1 = js_symbol->GetIdentityHash();
+    CHECK_EQ(hash, hash1);
+    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+    int hash3 = js_symbol->GetIdentityHash();
+    CHECK_EQ(hash, hash3);
+  }
+}
+
+
+TEST(StringIdentityHash) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  Local<v8::String> str = v8::String::NewFromUtf8(isolate, "str1");
+  int hash = str->GetIdentityHash();
+  int hash1 = str->GetIdentityHash();
+  CHECK_EQ(hash, hash1);
+  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+  int hash3 = str->GetIdentityHash();
+  CHECK_EQ(hash, hash3);
+
+  Local<v8::String> str2 = v8::String::NewFromUtf8(isolate, "str1");
+  int hash4 = str2->GetIdentityHash();
+  CHECK_EQ(hash, hash4);
+}
+
+
 THREADED_TEST(SymbolProperties) {
   LocalContext env;
   v8::Isolate* isolate = env->GetIsolate();
@@ -3195,6 +3459,24 @@
 }
 
 
+THREADED_TEST(ArrayBuffer_DisableNeuter) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope handle_scope(isolate);
+
+  i::ScopedVector<uint8_t> my_data(100);
+  memset(my_data.start(), 0, 100);
+  Local<v8::ArrayBuffer> ab =
+      v8::ArrayBuffer::New(isolate, my_data.start(), 100);
+  CHECK(ab->IsNeuterable());
+
+  i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
+  buf->set_is_neuterable(false);
+
+  CHECK(!ab->IsNeuterable());
+}
+
+
 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
@@ -3411,7 +3693,7 @@
 
 static bool interceptor_for_hidden_properties_called;
 static void InterceptorForHiddenProperties(
-    Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   interceptor_for_hidden_properties_called = true;
 }
 
@@ -3428,7 +3710,8 @@
   // Associate an interceptor with an object and start setting hidden values.
   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
-  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
+  instance_templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorForHiddenProperties));
   Local<v8::Function> function = fun_templ->GetFunction();
   Local<v8::Object> obj = function->NewInstance();
   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
@@ -4144,6 +4427,45 @@
 }
 
 
+THREADED_TEST(WeakRootsSurviveTwoRoundsOfGC) {
+  LocalContext env;
+  v8::Isolate* iso = env->GetIsolate();
+  HandleScope scope(iso);
+
+  WeakCallCounter counter(1234);
+
+  WeakCallCounterAndPersistent<Value> weak_obj(&counter);
+
+  // Create a weak object that references a internalized string.
+  {
+    HandleScope scope(iso);
+    weak_obj.handle.Reset(iso, Object::New(iso));
+    weak_obj.handle.SetWeak(&weak_obj, &WeakPointerCallback);
+    CHECK(weak_obj.handle.IsWeak());
+    Local<Object>::New(iso, weak_obj.handle.As<Object>())->Set(
+        v8_str("x"),
+        String::NewFromUtf8(iso, "magic cookie", String::kInternalizedString));
+  }
+  // Do a single full GC
+  i::Isolate* i_iso = reinterpret_cast<v8::internal::Isolate*>(iso);
+  i::Heap* heap = i_iso->heap();
+  heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+
+  // We should have received the weak callback.
+  CHECK_EQ(1, counter.NumberOfWeakCalls());
+
+  // Check that the string is still alive.
+  {
+    HandleScope scope(iso);
+    i::MaybeHandle<i::String> magic_string =
+        i::StringTable::LookupStringIfExists(
+            i_iso,
+            v8::Utils::OpenHandle(*String::NewFromUtf8(iso, "magic cookie")));
+    magic_string.Check();
+  }
+}
+
+
 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
 // on the buildbots, so was made non-threaded for the time being.
 TEST(ApiObjectGroupsCycleForScavenger) {
@@ -4266,13 +4588,14 @@
 
 TEST(TryCatchCustomException) {
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
   v8::TryCatch try_catch;
   CompileRun("function CustomError() { this.a = 'b'; }"
              "(function f() { throw new CustomError(); })();");
   CHECK(try_catch.HasCaught());
-  CHECK(try_catch.Exception()->ToObject()->
-            Get(v8_str("a"))->Equals(v8_str("b")));
+  CHECK(try_catch.Exception()->ToObject(isolate)->Get(v8_str("a"))->Equals(
+      v8_str("b")));
 }
 
 
@@ -4766,49 +5089,51 @@
 
 THREADED_TEST(ConversionNumber) {
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
   // Very large number.
   CompileRun("var obj = Math.pow(2,32) * 1237;");
   Local<Value> obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
-  CHECK_EQ(0, obj->ToInt32()->Value());
-  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
+  CHECK_EQ(5312874545152.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(0, obj->ToInt32(isolate)->Value());
+  CHECK(0u ==
+        obj->ToUint32(isolate)->Value());  // NOLINT - no CHECK_EQ for unsigned.
   // Large number.
   CompileRun("var obj = -1234567890123;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
-  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
-  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(-1234567890123.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(-1912276171, obj->ToInt32(isolate)->Value());
+  CHECK(2382691125u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Small positive integer.
   CompileRun("var obj = 42;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(42.0, obj->ToNumber()->Value());
-  CHECK_EQ(42, obj->ToInt32()->Value());
-  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(42.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(42, obj->ToInt32(isolate)->Value());
+  CHECK(42u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Negative integer.
   CompileRun("var obj = -37;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(-37.0, obj->ToNumber()->Value());
-  CHECK_EQ(-37, obj->ToInt32()->Value());
-  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(-37.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(-37, obj->ToInt32(isolate)->Value());
+  CHECK(4294967259u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Positive non-int32 integer.
   CompileRun("var obj = 0x81234567;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
-  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
-  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(2166572391.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(-2128394905, obj->ToInt32(isolate)->Value());
+  CHECK(2166572391u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Fraction.
   CompileRun("var obj = 42.3;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(42.3, obj->ToNumber()->Value());
-  CHECK_EQ(42, obj->ToInt32()->Value());
-  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(42.3, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(42, obj->ToInt32(isolate)->Value());
+  CHECK(42u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Large negative fraction.
   CompileRun("var obj = -5726623061.75;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
-  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
-  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(-5726623061.75, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(-1431655765, obj->ToInt32(isolate)->Value());
+  CHECK(2863311531u == obj->ToUint32(isolate)->Value());  // NOLINT
 }
 
 
@@ -4873,29 +5198,29 @@
     "var obj = new TestClass();");
   Local<Value> obj = env->Global()->Get(v8_str("obj"));
 
-  v8::TryCatch try_catch;
+  v8::TryCatch try_catch(isolate);
 
-  Local<Value> to_string_result = obj->ToString();
+  Local<Value> to_string_result = obj->ToString(isolate);
   CHECK(to_string_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_number_result = obj->ToNumber();
+  Local<Value> to_number_result = obj->ToNumber(isolate);
   CHECK(to_number_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_integer_result = obj->ToInteger();
+  Local<Value> to_integer_result = obj->ToInteger(isolate);
   CHECK(to_integer_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_uint32_result = obj->ToUint32();
+  Local<Value> to_uint32_result = obj->ToUint32(isolate);
   CHECK(to_uint32_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_int32_result = obj->ToInt32();
+  Local<Value> to_int32_result = obj->ToInt32(isolate);
   CHECK(to_int32_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
+  Local<Value> to_object_result = v8::Undefined(isolate)->ToObject(isolate);
   CHECK(to_object_result.IsEmpty());
   CHECK(try_catch.HasCaught());
   try_catch.Reset();
@@ -4931,7 +5256,7 @@
   }
   v8::HandleScope scope(args.GetIsolate());
   v8::TryCatch try_catch;
-  Local<Value> result = CompileRun(args[0]->ToString());
+  Local<Value> result = CompileRun(args[0]->ToString(args.GetIsolate()));
   CHECK(!try_catch.HasCaught() || result.IsEmpty());
   args.GetReturnValue().Set(try_catch.HasCaught());
 }
@@ -5980,7 +6305,7 @@
 }
 
 
-static void XPropertyGetter(Local<String> property,
+static void XPropertyGetter(Local<Name> property,
                             const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK(info.Data()->IsUndefined());
@@ -5992,7 +6317,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(XPropertyGetter);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   Local<Script> script = v8_compile("obj.x");
@@ -6007,7 +6332,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(XPropertyGetter);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
   LocalContext context;
   // Create an object with a named interceptor.
   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
@@ -6041,7 +6366,7 @@
 
   context1->Enter();
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(XPropertyGetter);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
   // Create an object with a named interceptor.
   v8::Local<v8::Object> object = templ->NewInstance();
   context1->Global()->Set(v8_str("interceptor_obj"), object);
@@ -6076,8 +6401,7 @@
 
 
 static void SetXOnPrototypeGetter(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
   // Set x on the prototype object and do not handle the get request.
   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
   proto.As<v8::Object>()->Set(v8_str("x"),
@@ -6094,7 +6418,8 @@
       v8::FunctionTemplate::New(isolate);
   Local<v8::ObjectTemplate> instance_template
       = function_template->InstanceTemplate();
-  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
+  instance_template->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(SetXOnPrototypeGetter));
   LocalContext context;
   context->Global()->Set(v8_str("F"), function_template->GetFunction());
   // Create an instance of F and introduce a map transition for x.
@@ -6130,8 +6455,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
-                                   IndexedPropertySetter);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      IndexedPropertyGetter, IndexedPropertySetter));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   Local<Script> getter_script = v8_compile(
@@ -6196,11 +6521,9 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
-                                   UnboxedDoubleIndexedPropertySetter,
-                                   0,
-                                   0,
-                                   UnboxedDoubleIndexedPropertyEnumerator);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      UnboxedDoubleIndexedPropertyGetter, UnboxedDoubleIndexedPropertySetter, 0,
+      0, UnboxedDoubleIndexedPropertyEnumerator));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   // When obj is created, force it to be Stored in a FastDoubleArray.
@@ -6210,7 +6533,7 @@
       "for (x in obj) {key_count++;};"
       "obj;");
   Local<Value> result = create_unboxed_double_script->Run();
-  CHECK(result->ToObject()->HasRealIndexedProperty(2000));
+  CHECK(result->ToObject(isolate)->HasRealIndexedProperty(2000));
   Local<Script> key_count_check = v8_compile("key_count;");
   result = key_count_check->Run();
   CHECK_EQ(v8_num(40013), result);
@@ -6252,11 +6575,9 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
-                                   0,
-                                   0,
-                                   0,
-                                   SloppyArgsIndexedPropertyEnumerator);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      SloppyIndexedPropertyGetter, 0, 0, 0,
+      SloppyArgsIndexedPropertyEnumerator));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   Local<Script> create_args_script = v8_compile(
@@ -6278,7 +6599,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
@@ -6300,7 +6622,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
@@ -6324,7 +6647,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6352,7 +6676,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6390,7 +6715,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6414,7 +6740,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6454,7 +6781,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6484,7 +6812,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6515,7 +6844,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6546,7 +6876,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -7371,14 +7702,175 @@
 };
 
 
-static void DisposeAndSetFlag(
-    const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
-  data.GetParameter()->handle.Reset();
+static void SetFlag(const v8::PhantomCallbackData<FlagAndPersistent>& data) {
   data.GetParameter()->flag = true;
 }
 
 
+static void IndependentWeakHandle(bool global_gc, bool interlinked) {
+  v8::Isolate* iso = CcTest::isolate();
+  v8::HandleScope scope(iso);
+  v8::Handle<Context> context = Context::New(iso);
+  Context::Scope context_scope(context);
+
+  FlagAndPersistent object_a, object_b;
+
+  intptr_t big_heap_size;
+
+  {
+    v8::HandleScope handle_scope(iso);
+    Local<Object> a(v8::Object::New(iso));
+    Local<Object> b(v8::Object::New(iso));
+    object_a.handle.Reset(iso, a);
+    object_b.handle.Reset(iso, b);
+    if (interlinked) {
+      a->Set(v8_str("x"), b);
+      b->Set(v8_str("x"), a);
+    }
+    if (global_gc) {
+      CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
+    } else {
+      CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+    }
+    // We are relying on this creating a big flag array and reserving the space
+    // up front.
+    v8::Handle<Value> big_array = CompileRun("new Array(50000)");
+    a->Set(v8_str("y"), big_array);
+    big_heap_size = CcTest::heap()->SizeOfObjects();
+  }
+
+  object_a.flag = false;
+  object_b.flag = false;
+  object_a.handle.SetPhantom(&object_a, &SetFlag);
+  object_b.handle.SetPhantom(&object_b, &SetFlag);
+  CHECK(!object_b.handle.IsIndependent());
+  object_a.handle.MarkIndependent();
+  object_b.handle.MarkIndependent();
+  CHECK(object_b.handle.IsIndependent());
+  if (global_gc) {
+    CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
+  } else {
+    CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+  }
+  // A single GC should be enough to reclaim the memory, since we are using
+  // phantom handles.
+  CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 200000);
+  CHECK(object_a.flag);
+  CHECK(object_b.flag);
+}
+
+
 THREADED_TEST(IndependentWeakHandle) {
+  IndependentWeakHandle(false, false);
+  IndependentWeakHandle(false, true);
+  IndependentWeakHandle(true, false);
+  IndependentWeakHandle(true, true);
+}
+
+
+class Trivial {
+ public:
+  explicit Trivial(int x) : x_(x) {}
+
+  int x() { return x_; }
+  void set_x(int x) { x_ = x; }
+
+ private:
+  int x_;
+};
+
+
+class Trivial2 {
+ public:
+  Trivial2(int x, int y) : y_(y), x_(x) {}
+
+  int x() { return x_; }
+  void set_x(int x) { x_ = x; }
+
+  int y() { return y_; }
+  void set_y(int y) { y_ = y; }
+
+ private:
+  int y_;
+  int x_;
+};
+
+
+void CheckInternalFields(
+    const v8::InternalFieldsCallbackData<Trivial, Trivial2>& data) {
+  Trivial* t1 = data.GetInternalField1();
+  Trivial2* t2 = data.GetInternalField2();
+  CHECK_EQ(42, t1->x());
+  CHECK_EQ(103, t2->x());
+  t1->set_x(1729);
+  t2->set_x(33550336);
+}
+
+
+void InternalFieldCallback(bool global_gc) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
+  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
+  Trivial* t1;
+  Trivial2* t2;
+  instance_templ->SetInternalFieldCount(2);
+  {
+    v8::HandleScope scope(isolate);
+    Local<v8::Object> obj = templ->GetFunction()->NewInstance();
+    v8::Persistent<v8::Object> handle(isolate, obj);
+    CHECK_EQ(2, obj->InternalFieldCount());
+    CHECK(obj->GetInternalField(0)->IsUndefined());
+    t1 = new Trivial(42);
+    t2 = new Trivial2(103, 9);
+
+    obj->SetAlignedPointerInInternalField(0, t1);
+    t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
+    CHECK_EQ(42, t1->x());
+
+    obj->SetAlignedPointerInInternalField(1, t2);
+    t2 =
+        reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
+    CHECK_EQ(103, t2->x());
+
+    handle.SetPhantom(CheckInternalFields, 0, 1);
+    if (!global_gc) {
+      handle.MarkIndependent();
+    }
+  }
+  if (global_gc) {
+    CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
+  } else {
+    CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+  }
+
+  CHECK_EQ(1729, t1->x());
+  CHECK_EQ(33550336, t2->x());
+
+  delete t1;
+  delete t2;
+}
+
+
+THREADED_TEST(InternalFieldCallback) {
+  InternalFieldCallback(false);
+  InternalFieldCallback(true);
+}
+
+
+static void ResetUseValueAndSetFlag(
+    const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
+  // Blink will reset the handle, and then use the other handle, so they
+  // can't use the same backing slot.
+  data.GetParameter()->handle.Reset();
+  data.GetValue()->IsBoolean();  // Make sure the handle still works.
+  data.GetParameter()->flag = true;
+}
+
+
+static void ResetWeakHandle(bool global_gc) {
   v8::Isolate* iso = CcTest::isolate();
   v8::HandleScope scope(iso);
   v8::Handle<Context> context = Context::New(iso);
@@ -7388,24 +7880,44 @@
 
   {
     v8::HandleScope handle_scope(iso);
-    object_a.handle.Reset(iso, v8::Object::New(iso));
-    object_b.handle.Reset(iso, v8::Object::New(iso));
+    Local<Object> a(v8::Object::New(iso));
+    Local<Object> b(v8::Object::New(iso));
+    object_a.handle.Reset(iso, a);
+    object_b.handle.Reset(iso, b);
+    if (global_gc) {
+      CcTest::heap()->CollectAllGarbage(
+          TestHeap::Heap::kAbortIncrementalMarkingMask);
+    } else {
+      CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+    }
   }
 
   object_a.flag = false;
   object_b.flag = false;
-  object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
-  object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
-  CHECK(!object_b.handle.IsIndependent());
-  object_a.handle.MarkIndependent();
-  object_b.handle.MarkIndependent();
-  CHECK(object_b.handle.IsIndependent());
-  CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+  object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag);
+  object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag);
+  if (!global_gc) {
+    object_a.handle.MarkIndependent();
+    object_b.handle.MarkIndependent();
+    CHECK(object_b.handle.IsIndependent());
+  }
+  if (global_gc) {
+    CcTest::heap()->CollectAllGarbage(
+        TestHeap::Heap::kAbortIncrementalMarkingMask);
+  } else {
+    CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+  }
   CHECK(object_a.flag);
   CHECK(object_b.flag);
 }
 
 
+THREADED_TEST(ResetWeakHandle) {
+  ResetWeakHandle(false);
+  ResetWeakHandle(true);
+}
+
+
 static void InvokeScavenge() {
   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
 }
@@ -7533,9 +8045,8 @@
 }
 
 
-static void NoBlockGetterX(Local<String> name,
-                           const v8::PropertyCallbackInfo<v8::Value>&) {
-}
+static void NoBlockGetterX(Local<Name> name,
+                           const v8::PropertyCallbackInfo<v8::Value>&) {}
 
 
 static void NoBlockGetterI(uint32_t index,
@@ -7543,7 +8054,7 @@
 }
 
 
-static void PDeleter(Local<String> name,
+static void PDeleter(Local<Name> name,
                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   if (!name->Equals(v8_str("foo"))) {
     return;  // not intercepted
@@ -7567,8 +8078,10 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
-  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX, NULL,
+                                                        NULL, PDeleter, NULL));
+  obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      NoBlockGetterI, NULL, NULL, IDeleter, NULL));
   LocalContext context;
   context->Global()->Set(v8_str("k"), obj->NewInstance());
   CompileRun(
@@ -7590,7 +8103,7 @@
 }
 
 
-static void GetK(Local<String> name,
+static void GetK(Local<Name> name,
                  const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (name->Equals(v8_str("foo")) ||
@@ -7631,8 +8144,10 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
-  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
+  obj->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(GetK, NULL, NULL, NULL, NamedEnum));
+  obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      IndexedGetK, NULL, NULL, NULL, IndexedEnum));
   LocalContext context;
   context->Global()->Set(v8_str("k"), obj->NewInstance());
   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
@@ -7724,7 +8239,7 @@
 }
 
 
-static void PGetter2(Local<String> name,
+static void PGetter2(Local<Name> name,
                      const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   p_getter_count2++;
@@ -7761,7 +8276,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(PGetter2);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
   p_getter_count2 = 0;
   RunHolderTest(obj);
   CHECK_EQ(40, p_getter_count2);
@@ -8419,6 +8934,85 @@
 }
 
 
+static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  ApiTestFuzzer::Fuzz();
+  v8::Handle<String> foo = v8_str("foo");
+  v8::Handle<String> message = v8_str("message");
+  v8::Handle<Value> error = v8::Exception::Error(foo);
+  CHECK(error->IsObject());
+  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
+  info.GetIsolate()->ThrowException(error);
+  info.GetReturnValue().SetUndefined();
+}
+
+
+THREADED_TEST(ExceptionCreateMessage) {
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  v8::Handle<String> foo_str = v8_str("foo");
+  v8::Handle<String> message_str = v8_str("message");
+
+  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
+
+  Local<v8::FunctionTemplate> fun =
+      v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
+  v8::Local<v8::Object> global = context->Global();
+  global->Set(v8_str("throwV8Exception"), fun->GetFunction());
+
+  TryCatch try_catch;
+  CompileRun(
+      "function f1() {\n"
+      "  throwV8Exception();\n"
+      "};\n"
+      "f1();");
+  CHECK(try_catch.HasCaught());
+
+  v8::Handle<v8::Value> error = try_catch.Exception();
+  CHECK(error->IsObject());
+  CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
+
+  v8::Handle<v8::Message> message = v8::Exception::CreateMessage(error);
+  CHECK(!message.IsEmpty());
+  CHECK_EQ(2, message->GetLineNumber());
+  CHECK_EQ(2, message->GetStartColumn());
+
+  v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
+  CHECK(!stackTrace.IsEmpty());
+  CHECK_EQ(2, stackTrace->GetFrameCount());
+
+  stackTrace = v8::Exception::GetStackTrace(error);
+  CHECK(!stackTrace.IsEmpty());
+  CHECK_EQ(2, stackTrace->GetFrameCount());
+
+  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
+
+  // Now check message location when SetCaptureStackTraceForUncaughtExceptions
+  // is false.
+  try_catch.Reset();
+
+  CompileRun(
+      "function f2() {\n"
+      "  return throwV8Exception();\n"
+      "};\n"
+      "f2();");
+  CHECK(try_catch.HasCaught());
+
+  error = try_catch.Exception();
+  CHECK(error->IsObject());
+  CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
+
+  message = v8::Exception::CreateMessage(error);
+  CHECK(!message.IsEmpty());
+  CHECK_EQ(2, message->GetLineNumber());
+  CHECK_EQ(9, message->GetStartColumn());
+
+  // Should be empty stack trace.
+  stackTrace = message->GetStackTrace();
+  CHECK(stackTrace.IsEmpty());
+  CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
+}
+
+
 static void YGetter(Local<String> name,
                     const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
@@ -8532,6 +9126,33 @@
   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
 }
 
+
+TEST(ApiUncaughtExceptionInObjectObserve) {
+  v8::internal::FLAG_stack_size = 150;
+  report_count = 0;
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
+  CompileRun(
+      "var obj = {};"
+      "var observe_count = 0;"
+      "function observer1() { ++observe_count; };"
+      "function observer2() { ++observe_count; };"
+      "function observer_throws() { throw new Error(); };"
+      "function stack_overflow() { return (function f(x) { f(x+1); })(0); };"
+      "Object.observe(obj, observer_throws.bind());"
+      "Object.observe(obj, observer1);"
+      "Object.observe(obj, stack_overflow);"
+      "Object.observe(obj, observer2);"
+      "Object.observe(obj, observer_throws.bind());"
+      "obj.foo = 'bar';");
+  CHECK_EQ(3, report_count);
+  ExpectInt32("observe_count", 2);
+  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
+}
+
+
 static const char* script_resource_name = "ExceptionInNativeScript.js";
 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
                                                 v8::Handle<Value>) {
@@ -8603,7 +9224,7 @@
 
 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
   v8::HandleScope scope(args.GetIsolate());
-  CompileRun(args[0]->ToString());
+  CompileRun(args[0]->ToString(args.GetIsolate()));
 }
 
 
@@ -8877,11 +9498,11 @@
   CHECK(indexed_security_check_with_gc_called);
 
   named_security_check_with_gc_called = false;
-  CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
+  CHECK(CompileRun("obj.foo")->ToString(isolate)->Equals(v8_str("1001")));
   CHECK(named_security_check_with_gc_called);
 
   indexed_security_check_with_gc_called = false;
-  CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
+  CHECK(CompileRun("obj[0]")->ToString(isolate)->Equals(v8_str("1002")));
   CHECK(indexed_security_check_with_gc_called);
 }
 
@@ -9609,20 +10230,52 @@
   LocalContext env;
   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
 
-  v8::TryCatch try_catch;
-  CompileRun(
-      "function f() { return super.hasOwnProperty; };"
-      "var m = f.toMethod(prohibited);"
-      "m();");
-  CHECK(try_catch.HasCaught());
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "function f() { return super.hasOwnProperty; };"
+        "var m = f.toMethod(prohibited);"
+        "m();");
+    CHECK(try_catch.HasCaught());
+  }
+
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "function f() { return super[42]; };"
+        "var m = f.toMethod(prohibited);"
+        "m();");
+    CHECK(try_catch.HasCaught());
+  }
+
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "function f() { super.hasOwnProperty = function () {}; };"
+        "var m = f.toMethod(prohibited);"
+        "m();");
+    CHECK(try_catch.HasCaught());
+  }
+
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
+        "function f() { "
+        "     'use strict';"
+        "     super.x = function () {}; "
+        "};"
+        "var m = f.toMethod(prohibited);"
+        "m();");
+    CHECK(try_catch.HasCaught());
+  }
 }
 
 
 static void IndexedPropertyEnumerator(
     const v8::PropertyCallbackInfo<v8::Array>& info) {
-  v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
+  v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 1);
   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
-  result->Set(1, v8::Object::New(info.GetIsolate()));
   info.GetReturnValue().Set(result);
 }
 
@@ -9631,7 +10284,7 @@
     const v8::PropertyCallbackInfo<v8::Array>& info) {
   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
   result->Set(0, v8_str("x"));
-  result->Set(1, v8::Object::New(info.GetIsolate()));
+  result->Set(1, v8::Symbol::GetIterator(info.GetIsolate()));
   info.GetReturnValue().Set(result);
 }
 
@@ -9644,10 +10297,10 @@
 
   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
-  obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
-                                          IndexedPropertyEnumerator);
-  obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
-                                        NamedPropertyEnumerator);
+  obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      NULL, NULL, NULL, NULL, IndexedPropertyEnumerator));
+  obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      NULL, NULL, NULL, NULL, NamedPropertyEnumerator));
 
   LocalContext context;
   v8::Handle<v8::Object> global = context->Global();
@@ -9657,13 +10310,26 @@
       CompileRun("Object.getOwnPropertyNames(object)");
   CHECK(result->IsArray());
   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
-  CHECK_EQ(3, result_array->Length());
+  CHECK_EQ(2, result_array->Length());
   CHECK(result_array->Get(0)->IsString());
   CHECK(result_array->Get(1)->IsString());
-  CHECK(result_array->Get(2)->IsString());
   CHECK_EQ(v8_str("7"), result_array->Get(0));
-  CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
-  CHECK_EQ(v8_str("x"), result_array->Get(2));
+  CHECK_EQ(v8_str("x"), result_array->Get(1));
+
+  result = CompileRun("var ret = []; for (var k in object) ret.push(k); ret");
+  CHECK(result->IsArray());
+  result_array = v8::Handle<v8::Array>::Cast(result);
+  CHECK_EQ(2, result_array->Length());
+  CHECK(result_array->Get(0)->IsString());
+  CHECK(result_array->Get(1)->IsString());
+  CHECK_EQ(v8_str("7"), result_array->Get(0));
+  CHECK_EQ(v8_str("x"), result_array->Get(1));
+
+  result = CompileRun("Object.getOwnPropertySymbols(object)");
+  CHECK(result->IsArray());
+  result_array = v8::Handle<v8::Array>::Cast(result);
+  CHECK_EQ(1, result_array->Length());
+  CHECK_EQ(result_array->Get(0), v8::Symbol::GetIterator(isolate));
 }
 
 
@@ -9937,15 +10603,13 @@
 
 
 static void AccessControlNamedGetter(
-    Local<String>,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(42);
 }
 
 
 static void AccessControlNamedSetter(
-    Local<String>,
-    Local<Value> value,
+    Local<Name>, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(value);
 }
@@ -9984,10 +10648,10 @@
       v8::ObjectTemplate::New(isolate);
   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
                                            IndexedAccessCounter);
-  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
-                                           AccessControlNamedSetter);
-  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
-                                             AccessControlIndexedSetter);
+  object_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      AccessControlNamedGetter, AccessControlNamedSetter));
+  object_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      AccessControlIndexedGetter, AccessControlIndexedSetter));
   Local<v8::Object> object = object_template->NewInstance();
 
   v8::HandleScope scope1(isolate);
@@ -10069,8 +10733,7 @@
 
 
 static void GlobalObjectInstancePropertiesGet(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Value>&) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
   ApiTestFuzzer::Fuzz();
 }
 
@@ -10082,8 +10745,8 @@
   Local<Value> global_object;
 
   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
-  t->InstanceTemplate()->SetNamedPropertyHandler(
-      GlobalObjectInstancePropertiesGet);
+  t->InstanceTemplate()->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
   instance_template->Set(v8_str("x"), v8_num(42));
   instance_template->Set(v8_str("f"),
@@ -10207,9 +10870,8 @@
 }
 
 
-static void ShadowNamedGet(Local<String> key,
-                           const v8::PropertyCallbackInfo<v8::Value>&) {
-}
+static void ShadowNamedGet(Local<Name> key,
+                           const v8::PropertyCallbackInfo<v8::Value>&) {}
 
 
 THREADED_TEST(ShadowObject) {
@@ -10221,8 +10883,10 @@
   LocalContext context(NULL, global_template);
 
   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
-  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
-  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
+  t->InstanceTemplate()->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
+  t->InstanceTemplate()->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
   Local<ObjectTemplate> proto = t->PrototypeTemplate();
   Local<ObjectTemplate> instance = t->InstanceTemplate();
 
@@ -10709,7 +11373,7 @@
         "(function() { var o = new obj('tipli'); return o.a; })()");
     CHECK(!try_catch.HasCaught());
     CHECK(value->IsString());
-    String::Utf8Value string_value1(value->ToString());
+    String::Utf8Value string_value1(value->ToString(isolate));
     CHECK_EQ("tipli", *string_value1);
 
     Local<Value> args2[] = { v8_str("tipli") };
@@ -10719,7 +11383,7 @@
     value = object2->Get(v8_str("a"));
     CHECK(!try_catch.HasCaught());
     CHECK(value->IsString());
-    String::Utf8Value string_value2(value->ToString());
+    String::Utf8Value string_value2(value->ToString(isolate));
     CHECK_EQ("tipli", *string_value2);
 
     // Call the Object's constructor with a Boolean.
@@ -10982,8 +11646,7 @@
 
 
 // Test that calling eval in a context which has been detached from
-// its global throws an exception.  This behavior is consistent with
-// other JavaScript implementations.
+// its global proxy works.
 THREADED_TEST(EvalInDetachedGlobal) {
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
@@ -11011,8 +11674,7 @@
   context0->DetachGlobal();
   v8::TryCatch catcher;
   x_value = CompileRun("fun('x')");
-  CHECK(x_value.IsEmpty());
-  CHECK(catcher.HasCaught());
+  CHECK_EQ(42, x_value->Int32Value());
   context1->Exit();
 }
 
@@ -11330,8 +11992,7 @@
 
 
 static void InterceptorHasOwnPropertyGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
 }
 
@@ -11342,7 +12003,8 @@
   v8::HandleScope scope(isolate);
   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
-  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
+  instance_templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetter));
   Local<Function> function = fun_templ->GetFunction();
   context->Global()->Set(v8_str("constructor"), function);
   v8::Handle<Value> value = CompileRun(
@@ -11361,8 +12023,7 @@
 
 
 static void InterceptorHasOwnPropertyGetterGC(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
 }
@@ -11374,7 +12035,8 @@
   v8::HandleScope scope(isolate);
   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
-  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
+  instance_templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetterGC));
   Local<Function> function = fun_templ->GetFunction();
   context->Global()->Set(v8_str("constructor"), function);
   // Let's first make some stuff so we can be sure to get a good GC.
@@ -11398,18 +12060,14 @@
 }
 
 
-typedef void (*NamedPropertyGetter)(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Value>& info);
-
-
-static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
-                                   const char* source,
-                                   int expected) {
+static void CheckInterceptorLoadIC(
+    v8::GenericNamedPropertyGetterCallback getter, const char* source,
+    int expected) {
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(getter, 0, 0, 0, 0,
+                                                          v8_str("data")));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(source);
@@ -11418,8 +12076,7 @@
 
 
 static void InterceptorLoadICGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   v8::Isolate* isolate = CcTest::isolate();
   CHECK_EQ(isolate, info.GetIsolate());
@@ -11445,8 +12102,7 @@
 // (those cases are special cased to get better performance).
 
 static void InterceptorLoadXICGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   info.GetReturnValue().Set(
       v8_str("x")->Equals(name) ?
@@ -11561,8 +12217,7 @@
 
 static int interceptor_load_not_handled_calls = 0;
 static void InterceptorLoadNotHandled(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ++interceptor_load_not_handled_calls;
 }
 
@@ -11623,7 +12278,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   templ->SetAccessor(v8_str("y"), Return239Callback);
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
@@ -11653,7 +12309,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ_o->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   templ_p->SetAccessor(v8_str("y"), Return239Callback);
 
@@ -11687,7 +12344,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   templ->SetAccessor(v8_str("y"), Return239Callback);
 
   LocalContext context;
@@ -11716,7 +12374,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ_o->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   templ_p->SetAccessor(v8_str("y"), Return239Callback);
 
@@ -11745,7 +12404,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ_o->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
 
@@ -11778,7 +12438,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ_o->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
 
@@ -11804,8 +12465,7 @@
 
 
 static void InterceptorLoadICGetter0(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK(v8_str("x")->Equals(name));
   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
@@ -11820,8 +12480,7 @@
 
 
 static void InterceptorStoreICSetter(
-    Local<String> key,
-    Local<Value> value,
+    Local<Name> key, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   CHECK(v8_str("x")->Equals(key));
   CHECK_EQ(42, value->Int32Value());
@@ -11834,9 +12493,9 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
-                                 InterceptorStoreICSetter,
-                                 0, 0, 0, v8_str("data"));
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      InterceptorLoadICGetter, InterceptorStoreICSetter, 0, 0, 0,
+      v8_str("data")));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   CompileRun(
@@ -11850,7 +12509,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -11869,8 +12529,7 @@
 v8::Handle<Value> call_ic_function3;
 
 static void InterceptorCallICGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK(v8_str("x")->Equals(name));
   info.GetReturnValue().Set(call_ic_function);
@@ -11882,7 +12541,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   call_ic_function =
@@ -11902,7 +12562,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -11917,8 +12577,7 @@
 
 static v8::Handle<Value> call_ic_function4;
 static void InterceptorCallICGetter4(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK(v8_str("x")->Equals(name));
   info.GetReturnValue().Set(call_ic_function4);
@@ -11932,7 +12591,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter4));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   call_ic_function4 =
@@ -11953,7 +12613,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -11981,7 +12641,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -11998,8 +12658,7 @@
 
 static v8::Handle<Value> call_ic_function5;
 static void InterceptorCallICGetter5(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name))
     info.GetReturnValue().Set(call_ic_function5);
@@ -12013,7 +12672,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter5));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   call_ic_function5 =
@@ -12032,8 +12692,7 @@
 
 static v8::Handle<Value> call_ic_function6;
 static void InterceptorCallICGetter6(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name))
     info.GetReturnValue().Set(call_ic_function6);
@@ -12047,7 +12706,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter6));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   call_ic_function6 =
@@ -12078,7 +12738,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -12109,7 +12769,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -12135,7 +12795,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+  templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
 
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
@@ -12160,8 +12820,7 @@
 }
 
 static void InterceptorCallICFastApi(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
   int* call_count =
@@ -12350,9 +13009,9 @@
   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   proto_templ->Set(v8_str("method"), method_templ);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12380,9 +13039,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12413,9 +13072,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12452,9 +13111,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12491,9 +13150,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12515,7 +13174,7 @@
   CHECK(try_catch.HasCaught());
   // TODO(verwaest): Adjust message.
   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
-           try_catch.Exception()->ToString());
+           try_catch.Exception()->ToString(isolate));
   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   CHECK_GE(interceptor_call_count, 50);
 }
@@ -12534,9 +13193,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12557,7 +13216,7 @@
       "}");
   CHECK(try_catch.HasCaught());
   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
-           try_catch.Exception()->ToString());
+           try_catch.Exception()->ToString(isolate));
   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   CHECK_GE(interceptor_call_count, 50);
 }
@@ -12690,7 +13349,7 @@
   CHECK(try_catch.HasCaught());
   // TODO(verwaest): Adjust message.
   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
-           try_catch.Exception()->ToString());
+           try_catch.Exception()->ToString(isolate));
   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 }
 
@@ -12728,7 +13387,7 @@
       "}");
   CHECK(try_catch.HasCaught());
   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
-           try_catch.Exception()->ToString());
+           try_catch.Exception()->ToString(isolate));
   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 }
 
@@ -12736,8 +13395,7 @@
 v8::Handle<Value> keyed_call_ic_function;
 
 static void InterceptorKeyedCallICGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name)) {
     info.GetReturnValue().Set(keyed_call_ic_function);
@@ -12751,7 +13409,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   CompileRun(
@@ -12776,7 +13434,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorKeyedCallICGetter));
   LocalContext context;
   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
   keyed_call_ic_function =
@@ -12804,7 +13463,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   CompileRun(
@@ -12830,7 +13489,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+  templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 
@@ -12856,7 +13515,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+  templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
 
@@ -12879,7 +13538,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+  templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 
@@ -12900,8 +13559,7 @@
 static int interceptor_call_count = 0;
 
 static void InterceptorICRefErrorGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
     info.GetReturnValue().Set(call_ic_function2);
@@ -12916,7 +13574,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorICRefErrorGetter));
   LocalContext context(0, templ, v8::Handle<Value>());
   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
   v8::Handle<Value> value = CompileRun(
@@ -12944,8 +13603,7 @@
 static int interceptor_ic_exception_get_count = 0;
 
 static void InterceptorICExceptionGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
     info.GetReturnValue().Set(call_ic_function3);
@@ -12964,7 +13622,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorICExceptionGetter));
   LocalContext context(0, templ, v8::Handle<Value>());
   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
   v8::Handle<Value> value = CompileRun(
@@ -12992,9 +13651,8 @@
 static int interceptor_ic_exception_set_count = 0;
 
 static void InterceptorICExceptionSetter(
-      Local<String> key,
-      Local<Value> value,
-      const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> key, Local<Value> value,
+    const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (++interceptor_ic_exception_set_count > 20) {
     info.GetIsolate()->ThrowException(v8_num(42));
@@ -13009,7 +13667,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(0, InterceptorICExceptionSetter));
   LocalContext context(0, templ, v8::Handle<Value>());
   v8::Handle<Value> value = CompileRun(
     "function f() {"
@@ -13028,8 +13687,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(
-      static_cast<v8::NamedPropertyGetterCallback>(0));
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      static_cast<v8::GenericNamedPropertyGetterCallback>(0)));
   LocalContext context;
   templ->Set(CcTest::isolate(), "x", v8_num(42));
   v8::Handle<v8::Object> obj = templ->NewInstance();
@@ -13045,8 +13704,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(
-      static_cast<v8::IndexedPropertyGetterCallback>(0));
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      static_cast<v8::IndexedPropertyGetterCallback>(0)));
   LocalContext context;
   templ->Set(CcTest::isolate(), "42", v8_num(42));
   v8::Handle<v8::Object> obj = templ->NewInstance();
@@ -13061,7 +13720,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
-  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ->InstanceTemplate()->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   LocalContext env;
   env->Global()->Set(v8_str("obj"),
                      templ->GetFunction()->NewInstance());
@@ -13315,7 +13975,7 @@
 
   // Normal ToString call should call replaced Object.prototype.toString
   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
-  Local<String> value = instance->ToString();
+  Local<String> value = instance->ToString(isolate);
   CHECK(value->IsString() && value->Equals(customized_tostring));
 
   // ObjectProtoToString should not call replace toString function.
@@ -13333,9 +13993,127 @@
 }
 
 
-THREADED_TEST(ObjectGetConstructorName) {
+TEST(ObjectProtoToStringES6) {
+  // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
+  i::FLAG_harmony_tostring = true;
   LocalContext context;
-  v8::HandleScope scope(context->GetIsolate());
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
+  templ->SetClassName(v8_str("MyClass"));
+
+  Local<String> customized_tostring = v8_str("customized toString");
+
+  // Replace Object.prototype.toString
+  CompileRun(
+      "Object.prototype.toString = function() {"
+      "  return 'customized toString';"
+      "}");
+
+  // Normal ToString call should call replaced Object.prototype.toString
+  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
+  Local<String> value = instance->ToString(isolate);
+  CHECK(value->IsString() && value->Equals(customized_tostring));
+
+  // ObjectProtoToString should not call replace toString function.
+  value = instance->ObjectProtoToString();
+  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
+
+  // Check global
+  value = context->Global()->ObjectProtoToString();
+  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
+
+  // Check ordinary object
+  Local<Value> object = CompileRun("new Object()");
+  value = object.As<v8::Object>()->ObjectProtoToString();
+  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
+
+  // Check that ES6 semantics using @@toStringTag work
+  Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
+
+#define TEST_TOSTRINGTAG(type, tag, expected)                \
+  do {                                                       \
+    object = CompileRun("new " #type "()");                  \
+    object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
+    value = object.As<v8::Object>()->ObjectProtoToString();  \
+    CHECK(value->IsString() &&                               \
+          value->Equals(v8_str("[object " #expected "]")));  \
+  } while (0)
+
+  TEST_TOSTRINGTAG(Array, Object, Object);
+  TEST_TOSTRINGTAG(Object, Arguments, ~Arguments);
+  TEST_TOSTRINGTAG(Object, Array, ~Array);
+  TEST_TOSTRINGTAG(Object, Boolean, ~Boolean);
+  TEST_TOSTRINGTAG(Object, Date, ~Date);
+  TEST_TOSTRINGTAG(Object, Error, ~Error);
+  TEST_TOSTRINGTAG(Object, Function, ~Function);
+  TEST_TOSTRINGTAG(Object, Number, ~Number);
+  TEST_TOSTRINGTAG(Object, RegExp, ~RegExp);
+  TEST_TOSTRINGTAG(Object, String, ~String);
+  TEST_TOSTRINGTAG(Object, Foo, Foo);
+
+#undef TEST_TOSTRINGTAG
+
+  // @@toStringTag getter throws
+  Local<Value> obj = v8::Object::New(isolate);
+  obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value.IsEmpty());
+    CHECK(try_catch.HasCaught());
+  }
+
+  // @@toStringTag getter does not throw
+  obj = v8::Object::New(isolate);
+  obj.As<v8::Object>()->SetAccessor(
+      toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
+    CHECK(!try_catch.HasCaught());
+  }
+
+  // JS @@toStringTag value
+  obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
+    CHECK(!try_catch.HasCaught());
+  }
+
+  // JS @@toStringTag getter throws
+  obj = CompileRun(
+      "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
+      "  get: function() { throw 'Test'; }"
+      "}); obj");
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value.IsEmpty());
+    CHECK(try_catch.HasCaught());
+  }
+
+  // JS @@toStringTag getter does not throw
+  obj = CompileRun(
+      "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
+      "  get: function() { return 'Test'; }"
+      "}); obj");
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
+    CHECK(!try_catch.HasCaught());
+  }
+}
+
+
+THREADED_TEST(ObjectGetConstructorName) {
+  v8::Isolate* isolate = CcTest::isolate();
+  LocalContext context;
+  v8::HandleScope scope(isolate);
   v8_compile("function Parent() {};"
              "function Child() {};"
              "Child.prototype = new Parent();"
@@ -13345,16 +14123,17 @@
              "var x = new outer.inner();")->Run();
 
   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
-  CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
-      v8_str("Parent")));
+  CHECK(p->IsObject() &&
+        p->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Parent")));
 
   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
-  CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
-      v8_str("Child")));
+  CHECK(c->IsObject() &&
+        c->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Child")));
 
   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
-  CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
-      v8_str("outer.inner")));
+  CHECK(x->IsObject() &&
+        x->ToObject(isolate)->GetConstructorName()->Equals(
+            v8_str("outer.inner")));
 }
 
 
@@ -13902,7 +14681,7 @@
   v8::Local<Context> env = Context::New(isolate);
   env->Enter();
   v8::Handle<Value> value = NestedScope(env);
-  v8::Handle<String> str(value->ToString());
+  v8::Handle<String> str(value->ToString(isolate));
   CHECK(!str.IsEmpty());
   env->Exit();
 }
@@ -14744,7 +15523,7 @@
   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
   CHECK_EQ(0, props->Length());
   for (uint32_t i = 0; i < props->Length(); i++) {
-    printf("p[%d]\n", i);
+    printf("p[%u]\n", i);
   }
 }
 
@@ -15291,7 +16070,7 @@
 #ifndef V8_INTERPRETED_REGEXP
 
 struct RegExpInterruptionData {
-  int loop_count;
+  v8::base::Atomic32 loop_count;
   UC16VectorResource* string_resource;
   v8::Persistent<v8::String> string;
 } regexp_interruption_data;
@@ -15303,9 +16082,10 @@
       : Thread(Options("TimeoutThread")), isolate_(isolate) {}
 
   virtual void Run() {
-    for (regexp_interruption_data.loop_count = 0;
-         regexp_interruption_data.loop_count < 7;
-         regexp_interruption_data.loop_count++) {
+    for (v8::base::NoBarrier_Store(&regexp_interruption_data.loop_count, 0);
+         v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) < 7;
+         v8::base::NoBarrier_AtomicIncrement(
+             &regexp_interruption_data.loop_count, 1)) {
       v8::base::OS::Sleep(50);  // Wait a bit before requesting GC.
       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
     }
@@ -15319,7 +16099,9 @@
 
 
 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
-  if (regexp_interruption_data.loop_count != 2) return;
+  if (v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) != 2) {
+    return;
+  }
   v8::HandleScope scope(CcTest::isolate());
   v8::Local<v8::String> string = v8::Local<v8::String>::New(
       CcTest::isolate(), regexp_interruption_data.string);
@@ -15407,9 +16189,14 @@
   force_set_set_count++;
 }
 
+static void ForceSetInterceptGetter(
+    v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+  CHECK(name->IsString());
+  ForceSetGetter(Local<String>::Cast(name), info);
+}
+
 static void ForceSetInterceptSetter(
-    v8::Local<v8::String> name,
-    v8::Local<v8::Value> value,
+    v8::Local<v8::Name> name, v8::Local<v8::Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   force_set_set_count++;
   info.GetReturnValue().SetUndefined();
@@ -15469,7 +16256,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      ForceSetInterceptGetter, ForceSetInterceptSetter));
   LocalContext context(NULL, templ);
   v8::Handle<v8::Object> global = context->Global();
 
@@ -15537,7 +16325,7 @@
 
 
 static void ForceDeleteDeleter(
-    v8::Local<v8::String> name,
+    v8::Local<v8::Name> name,
     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   force_delete_interceptor_count++;
   if (pass_on_delete) return;
@@ -15552,7 +16340,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(0, 0, 0, ForceDeleteDeleter));
   LocalContext context(NULL, templ);
   v8::Handle<v8::Object> global = context->Global();
 
@@ -16195,8 +16984,8 @@
   }
   v8::Handle<v8::ObjectTemplate> templ =
       v8::ObjectTemplate::New(context->GetIsolate());
-  templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
-                                   NotHandledIndexedPropertySetter);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      NotHandledIndexedPropertyGetter, NotHandledIndexedPropertySetter));
   v8::Handle<v8::Object> obj = templ->NewInstance();
   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
   context->Global()->Set(v8_str("pixels"), obj);
@@ -17335,6 +18124,7 @@
 static void StackTraceForUncaughtExceptionListener(
     v8::Handle<v8::Message> message,
     v8::Handle<Value>) {
+  report_count++;
   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
   CHECK_EQ(2, stack_trace->GetFrameCount());
   checkStackFrame("origin", "foo", 2, 3, false, false,
@@ -17365,6 +18155,38 @@
   Function::Cast(*trouble)->Call(global, 0, NULL);
   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
+  CHECK_EQ(1, report_count);
+}
+
+
+TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
+  report_count = 0;
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+
+  // Create an Error object first.
+  CompileRunWithOrigin(
+      "function foo() {\n"
+      "e=new Error('err');\n"
+      "};\n"
+      "function bar() {\n"
+      "  foo();\n"
+      "};\n"
+      "var e;",
+      "origin");
+  v8::Local<v8::Object> global = env->Global();
+  Local<Value> trouble = global->Get(v8_str("bar"));
+  CHECK(trouble->IsFunction());
+  Function::Cast(*trouble)->Call(global, 0, NULL);
+
+  // Enable capturing detailed stack trace late, and throw the exception.
+  // The detailed stack trace should be extracted from the simple stack.
+  v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
+  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
+  CompileRunWithOrigin("throw e", "origin");
+  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
+  v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
+  CHECK_EQ(1, report_count);
 }
 
 
@@ -17519,6 +18341,343 @@
 }
 
 
+v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
+int promise_reject_counter = 0;
+int promise_revoke_counter = 0;
+int promise_reject_line_number = -1;
+int promise_reject_frame_count = -1;
+
+void PromiseRejectCallback(v8::PromiseRejectMessage message) {
+  if (message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
+    promise_reject_counter++;
+    CcTest::global()->Set(v8_str("rejected"), message.GetPromise());
+    CcTest::global()->Set(v8_str("value"), message.GetValue());
+    v8::Handle<v8::StackTrace> stack_trace =
+        v8::Exception::CreateMessage(message.GetValue())->GetStackTrace();
+    if (!stack_trace.IsEmpty()) {
+      promise_reject_frame_count = stack_trace->GetFrameCount();
+      if (promise_reject_frame_count > 0) {
+        CHECK(stack_trace->GetFrame(0)->GetScriptName()->Equals(v8_str("pro")));
+        promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
+      } else {
+        promise_reject_line_number = -1;
+      }
+    }
+  } else {
+    promise_revoke_counter++;
+    CcTest::global()->Set(v8_str("revoked"), message.GetPromise());
+    CHECK(message.GetValue().IsEmpty());
+  }
+}
+
+
+v8::Handle<v8::Promise> GetPromise(const char* name) {
+  return v8::Handle<v8::Promise>::Cast(CcTest::global()->Get(v8_str(name)));
+}
+
+
+v8::Handle<v8::Value> RejectValue() {
+  return CcTest::global()->Get(v8_str("value"));
+}
+
+
+void ResetPromiseStates() {
+  promise_reject_counter = 0;
+  promise_revoke_counter = 0;
+  promise_reject_line_number = -1;
+  promise_reject_frame_count = -1;
+  CcTest::global()->Set(v8_str("rejected"), v8_str(""));
+  CcTest::global()->Set(v8_str("value"), v8_str(""));
+  CcTest::global()->Set(v8_str("revoked"), v8_str(""));
+}
+
+
+TEST(PromiseRejectCallback) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  isolate->SetPromiseRejectCallback(PromiseRejectCallback);
+
+  ResetPromiseStates();
+
+  // Create promise p0.
+  CompileRun(
+      "var reject;            \n"
+      "var p0 = new Promise(  \n"
+      "  function(res, rej) { \n"
+      "    reject = rej;      \n"
+      "  }                    \n"
+      ");                     \n");
+  CHECK(!GetPromise("p0")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Add resolve handler (and default reject handler) to p0.
+  CompileRun("var p1 = p0.then(function(){});");
+  CHECK(GetPromise("p0")->HasHandler());
+  CHECK(!GetPromise("p1")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Reject p0.
+  CompileRun("reject('ppp');");
+  CHECK(GetPromise("p0")->HasHandler());
+  CHECK(!GetPromise("p1")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("p1")));
+  CHECK(RejectValue()->Equals(v8_str("ppp")));
+
+  // Reject p0 again. Callback is not triggered again.
+  CompileRun("reject();");
+  CHECK(GetPromise("p0")->HasHandler());
+  CHECK(!GetPromise("p1")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Add resolve handler to p1.
+  CompileRun("var p2 = p1.then(function(){});");
+  CHECK(GetPromise("p0")->HasHandler());
+  CHECK(GetPromise("p1")->HasHandler());
+  CHECK(!GetPromise("p2")->HasHandler());
+  CHECK_EQ(2, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("p2")));
+  CHECK(RejectValue()->Equals(v8_str("ppp")));
+  CHECK(GetPromise("revoked")->Equals(GetPromise("p1")));
+
+  ResetPromiseStates();
+
+  // Create promise q0.
+  CompileRun(
+      "var q0 = new Promise(  \n"
+      "  function(res, rej) { \n"
+      "    reject = rej;      \n"
+      "  }                    \n"
+      ");                     \n");
+  CHECK(!GetPromise("q0")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Add reject handler to q0.
+  CompileRun("var q1 = q0.catch(function() {});");
+  CHECK(GetPromise("q0")->HasHandler());
+  CHECK(!GetPromise("q1")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Reject q0.
+  CompileRun("reject('qq')");
+  CHECK(GetPromise("q0")->HasHandler());
+  CHECK(!GetPromise("q1")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Add a new reject handler, which rejects by returning Promise.reject().
+  // The returned promise q_ triggers a reject callback at first, only to
+  // revoke it when returning it causes q2 to be rejected.
+  CompileRun(
+      "var q_;"
+      "var q2 = q0.catch(               \n"
+      "   function() {                  \n"
+      "     q_ = Promise.reject('qqq'); \n"
+      "     return q_;                  \n"
+      "   }                             \n"
+      ");                               \n");
+  CHECK(GetPromise("q0")->HasHandler());
+  CHECK(!GetPromise("q1")->HasHandler());
+  CHECK(!GetPromise("q2")->HasHandler());
+  CHECK(GetPromise("q_")->HasHandler());
+  CHECK_EQ(2, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("q2")));
+  CHECK(GetPromise("revoked")->Equals(GetPromise("q_")));
+  CHECK(RejectValue()->Equals(v8_str("qqq")));
+
+  // Add a reject handler to the resolved q1, which rejects by throwing.
+  CompileRun(
+      "var q3 = q1.then(  \n"
+      "   function() {    \n"
+      "     throw 'qqqq'; \n"
+      "   }               \n"
+      ");                 \n");
+  CHECK(GetPromise("q0")->HasHandler());
+  CHECK(GetPromise("q1")->HasHandler());
+  CHECK(!GetPromise("q2")->HasHandler());
+  CHECK(!GetPromise("q3")->HasHandler());
+  CHECK_EQ(3, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("q3")));
+  CHECK(RejectValue()->Equals(v8_str("qqqq")));
+
+  ResetPromiseStates();
+
+  // Create promise r0, which has three handlers, two of which handle rejects.
+  CompileRun(
+      "var r0 = new Promise(             \n"
+      "  function(res, rej) {            \n"
+      "    reject = rej;                 \n"
+      "  }                               \n"
+      ");                                \n"
+      "var r1 = r0.catch(function() {}); \n"
+      "var r2 = r0.then(function() {});  \n"
+      "var r3 = r0.then(function() {},   \n"
+      "                 function() {});  \n");
+  CHECK(GetPromise("r0")->HasHandler());
+  CHECK(!GetPromise("r1")->HasHandler());
+  CHECK(!GetPromise("r2")->HasHandler());
+  CHECK(!GetPromise("r3")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Reject r0.
+  CompileRun("reject('rrr')");
+  CHECK(GetPromise("r0")->HasHandler());
+  CHECK(!GetPromise("r1")->HasHandler());
+  CHECK(!GetPromise("r2")->HasHandler());
+  CHECK(!GetPromise("r3")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("r2")));
+  CHECK(RejectValue()->Equals(v8_str("rrr")));
+
+  // Add reject handler to r2.
+  CompileRun("var r4 = r2.catch(function() {});");
+  CHECK(GetPromise("r0")->HasHandler());
+  CHECK(!GetPromise("r1")->HasHandler());
+  CHECK(GetPromise("r2")->HasHandler());
+  CHECK(!GetPromise("r3")->HasHandler());
+  CHECK(!GetPromise("r4")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK(GetPromise("revoked")->Equals(GetPromise("r2")));
+  CHECK(RejectValue()->Equals(v8_str("rrr")));
+
+  // Add reject handlers to r4.
+  CompileRun("var r5 = r4.then(function() {}, function() {});");
+  CHECK(GetPromise("r0")->HasHandler());
+  CHECK(!GetPromise("r1")->HasHandler());
+  CHECK(GetPromise("r2")->HasHandler());
+  CHECK(!GetPromise("r3")->HasHandler());
+  CHECK(GetPromise("r4")->HasHandler());
+  CHECK(!GetPromise("r5")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+
+  ResetPromiseStates();
+
+  // Create promise s0, which has three handlers, none of which handle rejects.
+  CompileRun(
+      "var s0 = new Promise(            \n"
+      "  function(res, rej) {           \n"
+      "    reject = rej;                \n"
+      "  }                              \n"
+      ");                               \n"
+      "var s1 = s0.then(function() {}); \n"
+      "var s2 = s0.then(function() {}); \n"
+      "var s3 = s0.then(function() {}); \n");
+  CHECK(GetPromise("s0")->HasHandler());
+  CHECK(!GetPromise("s1")->HasHandler());
+  CHECK(!GetPromise("s2")->HasHandler());
+  CHECK(!GetPromise("s3")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Reject s0.
+  CompileRun("reject('sss')");
+  CHECK(GetPromise("s0")->HasHandler());
+  CHECK(!GetPromise("s1")->HasHandler());
+  CHECK(!GetPromise("s2")->HasHandler());
+  CHECK(!GetPromise("s3")->HasHandler());
+  CHECK_EQ(3, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK(RejectValue()->Equals(v8_str("sss")));
+
+  // Test stack frames.
+  V8::SetCaptureStackTraceForUncaughtExceptions(true);
+
+  ResetPromiseStates();
+
+  // Create promise t0, which is rejected in the constructor with an error.
+  CompileRunWithOrigin(
+      "var t0 = new Promise(  \n"
+      "  function(res, rej) { \n"
+      "    reference_error;   \n"
+      "  }                    \n"
+      ");                     \n",
+      "pro", 0, 0);
+  CHECK(!GetPromise("t0")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK_EQ(2, promise_reject_frame_count);
+  CHECK_EQ(3, promise_reject_line_number);
+
+  ResetPromiseStates();
+
+  // Create promise u0 and chain u1 to it, which is rejected via throw.
+  CompileRunWithOrigin(
+      "var u0 = Promise.resolve();        \n"
+      "var u1 = u0.then(                  \n"
+      "           function() {            \n"
+      "             (function() {         \n"
+      "                throw new Error(); \n"
+      "              })();                \n"
+      "           }                       \n"
+      "         );                        \n",
+      "pro", 0, 0);
+  CHECK(GetPromise("u0")->HasHandler());
+  CHECK(!GetPromise("u1")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK_EQ(2, promise_reject_frame_count);
+  CHECK_EQ(5, promise_reject_line_number);
+
+  // Throw in u3, which handles u1's rejection.
+  CompileRunWithOrigin(
+      "function f() {                \n"
+      "  return (function() {        \n"
+      "    return new Error();       \n"
+      "  })();                       \n"
+      "}                             \n"
+      "var u2 = Promise.reject(f()); \n"
+      "var u3 = u1.catch(            \n"
+      "           function() {       \n"
+      "             return u2;       \n"
+      "           }                  \n"
+      "         );                   \n",
+      "pro", 0, 0);
+  CHECK(GetPromise("u0")->HasHandler());
+  CHECK(GetPromise("u1")->HasHandler());
+  CHECK(GetPromise("u2")->HasHandler());
+  CHECK(!GetPromise("u3")->HasHandler());
+  CHECK_EQ(3, promise_reject_counter);
+  CHECK_EQ(2, promise_revoke_counter);
+  CHECK_EQ(3, promise_reject_frame_count);
+  CHECK_EQ(3, promise_reject_line_number);
+
+  ResetPromiseStates();
+
+  // Create promise rejected promise v0, which is incorrectly handled by v1
+  // via chaining cycle.
+  CompileRunWithOrigin(
+      "var v0 = Promise.reject(); \n"
+      "var v1 = v0.catch(         \n"
+      "           function() {    \n"
+      "             return v1;    \n"
+      "           }               \n"
+      "         );                \n",
+      "pro", 0, 0);
+  CHECK(GetPromise("v0")->HasHandler());
+  CHECK(!GetPromise("v1")->HasHandler());
+  CHECK_EQ(2, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK_EQ(0, promise_reject_frame_count);
+  CHECK_EQ(-1, promise_reject_line_number);
+}
+
+
 void AnalyzeStackOfEvalWithSourceURL(
     const v8::FunctionCallbackInfo<v8::Value>& args) {
   v8::HandleScope scope(args.GetIsolate());
@@ -17835,40 +18994,6 @@
 }
 
 
-TEST(Regress2107) {
-  const intptr_t MB = 1024 * 1024;
-  const int kIdlePauseInMs = 1000;
-  LocalContext env;
-  v8::Isolate* isolate = env->GetIsolate();
-  v8::HandleScope scope(env->GetIsolate());
-  intptr_t initial_size = CcTest::heap()->SizeOfObjects();
-  // Send idle notification to start a round of incremental GCs.
-  env->GetIsolate()->IdleNotification(kIdlePauseInMs);
-  // Emulate 7 page reloads.
-  for (int i = 0; i < 7; i++) {
-    {
-      v8::HandleScope inner_scope(env->GetIsolate());
-      v8::Local<v8::Context> ctx = v8::Context::New(isolate);
-      ctx->Enter();
-      CreateGarbageInOldSpace();
-      ctx->Exit();
-    }
-    env->GetIsolate()->ContextDisposedNotification();
-    env->GetIsolate()->IdleNotification(kIdlePauseInMs);
-  }
-  // Create garbage and check that idle notification still collects it.
-  CreateGarbageInOldSpace();
-  intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
-  CHECK_GT(size_with_garbage, initial_size + MB);
-  bool finished = false;
-  for (int i = 0; i < 200 && !finished; i++) {
-    finished = env->GetIsolate()->IdleNotification(kIdlePauseInMs);
-  }
-  intptr_t final_size = CcTest::heap()->SizeOfObjects();
-  CHECK_LT(final_size, initial_size + 1);
-}
-
-
 TEST(Regress2333) {
   LocalContext env;
   for (int i = 0; i < 3; i++) {
@@ -17998,10 +19123,11 @@
 
 
 TEST(ExternalizeOldSpaceTwoByteCons) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(isolate);
   v8::Local<v8::String> cons =
-      CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
+      CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
   CcTest::heap()->CollectAllAvailableGarbage();
   CHECK(CcTest::heap()->old_pointer_space()->Contains(
@@ -18020,10 +19146,11 @@
 
 
 TEST(ExternalizeOldSpaceOneByteCons) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(isolate);
   v8::Local<v8::String> cons =
-      CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
+      CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
   CcTest::heap()->CollectAllAvailableGarbage();
   CHECK(CcTest::heap()->old_pointer_space()->Contains(
@@ -18042,8 +19169,9 @@
 
 
 TEST(VisitExternalStrings) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(isolate);
   const char* string = "Some string";
   uint16_t* two_byte_string = AsciiToTwoByteString(string);
   TestResource* resource[4];
@@ -18113,7 +19241,7 @@
     const char* s = "One string to test them all";
     TestOneByteResource* inscription =
         new TestOneByteResource(i::StrDup(s), &destroyed);
-    v8::Local<v8::String> ring = CompileRun("ring")->ToString();
+    v8::Local<v8::String> ring = CompileRun("ring")->ToString(isolate);
     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
     ring->MakeExternal(inscription);
     // Ring is still alive.  Orcs are roaming freely across our lands.
@@ -18128,6 +19256,9 @@
 
 
 TEST(ExternalInternalizedStringCollectedAtGC) {
+  // TODO(mvstanton): vector ics need weak support.
+  if (i::FLAG_vector_ics) return;
+
   int destroyed = 0;
   { LocalContext env;
     v8::HandleScope handle_scope(env->GetIsolate());
@@ -18135,7 +19266,7 @@
     const char* s = "One string to test them all";
     TestOneByteResource* inscription =
         new TestOneByteResource(i::StrDup(s), &destroyed);
-    v8::Local<v8::String> ring = CompileRun("ring")->ToString();
+    v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
     ring->MakeExternal(inscription);
     // Ring is still alive.  Orcs are roaming freely across our lands.
@@ -18274,7 +19405,7 @@
     const v8::FunctionCallbackInfo<v8::Value>& args) {
   v8::HandleScope scope(args.GetIsolate());
   v8::TryCatch tc;
-  v8::Handle<v8::String> str(args[0]->ToString());
+  v8::Handle<v8::String> str(args[0]->ToString(args.GetIsolate()));
   USE(str);
   if (tc.HasCaught())
     tc.ReThrow();
@@ -18625,7 +19756,7 @@
 }
 
 
-void FooGetInterceptor(Local<String> name,
+void FooGetInterceptor(Local<Name> name,
                        const v8::PropertyCallbackInfo<v8::Value>& info) {
   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
@@ -18634,8 +19765,7 @@
 }
 
 
-void FooSetInterceptor(Local<String> name,
-                       Local<Value> value,
+void FooSetInterceptor(Local<Name> name, Local<Value> value,
                        const v8::PropertyCallbackInfo<v8::Value>& info) {
   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
@@ -18681,15 +19811,13 @@
 
 
 static void NamedPropertyGetterWhichReturns42(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(v8_num(42));
 }
 
 
 static void NamedPropertySetterWhichSetsYOnThisTo23(
-    Local<String> name,
-    Local<Value> value,
+    Local<Name> name, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   if (name->Equals(v8_str("x"))) {
     Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
@@ -18701,8 +19829,9 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
-                                 NamedPropertySetterWhichSetsYOnThisTo23);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      NamedPropertyGetterWhichReturns42,
+      NamedPropertySetterWhichSetsYOnThisTo23));
   LocalContext context;
   context->Global()->Set(v8_str("P"), templ->NewInstance());
   CompileRun("function C1() {"
@@ -19860,7 +20989,7 @@
   CHECK_EQ(42, object.WrapperClassId());
 
   Visitor42 visitor(&object);
-  v8::V8::VisitHandlesWithClassIds(&visitor);
+  v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
   CHECK_EQ(1, visitor.counter_);
 
   object.Reset();
@@ -19994,8 +21123,8 @@
 }
 
 
-static void Getter(v8::Local<v8::String> property,
-                   const v8::PropertyCallbackInfo<v8::Value>& info ) {
+static void Getter(v8::Local<v8::Name> property,
+                   const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(v8_str("42!"));
 }
 
@@ -20014,7 +21143,8 @@
   v8::Context::Scope context_scope(context.local());
 
   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
-  tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
+  tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL,
+                                                         NULL, Enumerator));
   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
         "var result = []; for (var k in o) result.push(k); result"));
@@ -20159,8 +21289,7 @@
 
 
 void HasOwnPropertyNamedPropertyGetter(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
 }
 
@@ -20172,15 +21301,13 @@
 
 
 void HasOwnPropertyNamedPropertyQuery(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
 }
 
 
 void HasOwnPropertyNamedPropertyQuery2(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
 }
 
@@ -20209,7 +21336,7 @@
         "Bar.prototype = new Foo();"
         "new Bar();");
     CHECK(value->IsObject());
-    Handle<Object> object = value->ToObject();
+    Handle<Object> object = value->ToObject(isolate);
     CHECK(object->Has(v8_str("foo")));
     CHECK(!object->HasOwnProperty(v8_str("foo")));
     CHECK(object->HasOwnProperty(v8_str("bar")));
@@ -20219,7 +21346,8 @@
   }
   { // Check named getter interceptors.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
+    templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+        HasOwnPropertyNamedPropertyGetter));
     Handle<Object> instance = templ->NewInstance();
     CHECK(!instance->HasOwnProperty(v8_str("42")));
     CHECK(instance->HasOwnProperty(v8_str("foo")));
@@ -20227,7 +21355,8 @@
   }
   { // Check indexed getter interceptors.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
+    templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+        HasOwnPropertyIndexedPropertyGetter));
     Handle<Object> instance = templ->NewInstance();
     CHECK(instance->HasOwnProperty(v8_str("42")));
     CHECK(!instance->HasOwnProperty(v8_str("43")));
@@ -20235,14 +21364,16 @@
   }
   { // Check named query interceptors.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
+    templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+        0, 0, HasOwnPropertyNamedPropertyQuery));
     Handle<Object> instance = templ->NewInstance();
     CHECK(instance->HasOwnProperty(v8_str("foo")));
     CHECK(!instance->HasOwnProperty(v8_str("bar")));
   }
   { // Check indexed query interceptors.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
+    templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+        0, 0, HasOwnPropertyIndexedPropertyQuery));
     Handle<Object> instance = templ->NewInstance();
     CHECK(instance->HasOwnProperty(v8_str("42")));
     CHECK(!instance->HasOwnProperty(v8_str("41")));
@@ -20256,9 +21387,9 @@
   }
   { // Check that query wins on disagreement.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
-                                   0,
-                                   HasOwnPropertyNamedPropertyQuery2);
+    templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+        HasOwnPropertyNamedPropertyGetter, 0,
+        HasOwnPropertyNamedPropertyQuery2));
     Handle<Object> instance = templ->NewInstance();
     CHECK(!instance->HasOwnProperty(v8_str("foo")));
     CHECK(instance->HasOwnProperty(v8_str("bar")));
@@ -20270,9 +21401,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(NULL,
-                                   NULL,
-                                   HasOwnPropertyIndexedPropertyQuery);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      NULL, NULL, HasOwnPropertyIndexedPropertyQuery));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
@@ -20417,29 +21547,40 @@
 }
 
 
+static int CountLiveMapsInMapCache(i::Context* context) {
+  i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache());
+  int length = map_cache->length();
+  int count = 0;
+  for (int i = 0; i < length; i++) {
+    i::Object* value = map_cache->get(i);
+    if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++;
+  }
+  return count;
+}
+
+
 THREADED_TEST(Regress1516) {
   LocalContext context;
   v8::HandleScope scope(context->GetIsolate());
 
+  // Object with 20 properties is not a common case, so it should be removed
+  // from the cache after GC.
   { v8::HandleScope temp_scope(context->GetIsolate());
-    CompileRun("({'a': 0})");
+    CompileRun(
+        "({"
+        "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
+        "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
+        "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
+        "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
+        "})");
   }
 
-  int elements;
-  { i::MapCache* map_cache =
-        i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
-    elements = map_cache->NumberOfElements();
-    CHECK_LE(1, elements);
-  }
+  int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
+  CHECK_LE(1, elements);
 
-  CcTest::heap()->CollectAllGarbage(
-      i::Heap::kAbortIncrementalMarkingMask);
-  { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
-    if (raw_map_cache != CcTest::heap()->undefined_value()) {
-      i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
-      CHECK_GT(elements, map_cache->NumberOfElements());
-    }
-  }
+  CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+
+  CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
 }
 
 
@@ -20448,12 +21589,11 @@
                                                 v8::AccessType type,
                                                 Local<Value> data) {
   // Only block read access to __proto__.
-  if (type == v8::ACCESS_GET &&
-      name->IsString() &&
-      name->ToString()->Length() == 9 &&
-      name->ToString()->Utf8Length() == 9) {
+  if (type == v8::ACCESS_GET && name->IsString() &&
+      name.As<v8::String>()->Length() == 9 &&
+      name.As<v8::String>()->Utf8Length() == 9) {
     char buffer[10];
-    CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
+    CHECK_EQ(10, name.As<v8::String>()->WriteUtf8(buffer));
     return strncmp(buffer, "__proto__", 9) != 0;
   }
 
@@ -20500,8 +21640,7 @@
       context->Global();
 
   // Global object, the  prototype of proxy_object. No security checks.
-  Local<Object> global_object =
-      proxy_object->GetPrototype()->ToObject();
+  Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate);
 
   // Hidden prototype without security check.
   Local<Object> hidden_prototype =
@@ -20545,7 +21684,7 @@
 
   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
   CHECK(result5->Equals(
-      object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
+      object_with_hidden->GetPrototype()->ToObject(isolate)->GetPrototype()));
 
   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
   CHECK(result6.IsEmpty());
@@ -20581,8 +21720,8 @@
                          const char* code) {
   Local<Value> result = CompileRun(code);
   CHECK(result->IsObject());
-  CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
-  CHECK(expected_result->Equals(result->ToObject()->Get(0)));
+  CHECK(expected_receiver->Equals(result.As<v8::Object>()->Get(1)));
+  CHECK(expected_result->Equals(result.As<v8::Object>()->Get(0)));
 }
 
 
@@ -20970,8 +22109,8 @@
   Handle<Object> exec_state = event_details.GetExecutionState();
   Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
   CompileRun("function f(id) { new FrameDetails(id, 0); }");
-  Handle<Function> fun = Handle<Function>::Cast(
-      CcTest::global()->Get(v8_str("f"))->ToObject());
+  Handle<Function> fun =
+      Handle<Function>::Cast(CcTest::global()->Get(v8_str("f")));
   fun->Call(CcTest::global(), 1, &break_id);
 }
 
@@ -20995,7 +22134,7 @@
 }
 
 
-#ifdef DEBUG
+#ifdef ENABLE_DISASSEMBLER
 static int probes_counter = 0;
 static int misses_counter = 0;
 static int updates_counter = 0;
@@ -21029,7 +22168,7 @@
 
 
 static void StubCacheHelper(bool primary) {
-#ifdef DEBUG
+#ifdef ENABLE_DISASSEMBLER
   i::FLAG_native_code_counters = true;
   if (primary) {
     i::FLAG_test_primary_stub_cache = true;
@@ -21376,7 +22515,8 @@
   LocalContext context;
   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
   if (interceptor) {
-    templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
+    templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
+                                                            FooSetInterceptor));
   } else {
     templ->SetAccessor(v8_str("foo"),
                        GetterWhichReturns42,
@@ -21782,7 +22922,8 @@
 
 
 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
-  args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
+  args[0]->ToObject(args.GetIsolate())->HasOwnProperty(
+      args[1]->ToString(args.GetIsolate()));
 }
 
 
@@ -21998,8 +23139,6 @@
 
     TestBody();
 
-    isolate_->ClearInterrupt();
-
     // Verify we arrived here because interruptor was called
     // not due to a bug causing us to exit the loop too early.
     CHECK(!should_continue());
@@ -22149,7 +23288,8 @@
     proto->Set(v8_str("shouldContinue"), Function::New(
         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
-    instance_template->SetNamedPropertyHandler(EmptyInterceptor);
+    instance_template->SetHandler(
+        v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
 
     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
 
@@ -22158,9 +23298,7 @@
 
  private:
   static void EmptyInterceptor(
-      Local<String> property,
-      const v8::PropertyCallbackInfo<v8::Value>& info) {
-  }
+      Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
 };
 
 
@@ -22249,10 +23387,9 @@
 }
 
 
-class ClearInterruptFromAnotherThread
-    : public RequestInterruptTestBase {
+class RequestMultipleInterrupts : public RequestInterruptTestBase {
  public:
-  ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
+  RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
 
   virtual void StartInterruptThread() {
     i_thread.Start();
@@ -22269,39 +23406,33 @@
  private:
   class InterruptThread : public v8::base::Thread {
    public:
-    explicit InterruptThread(ClearInterruptFromAnotherThread* test)
+    enum { NUM_INTERRUPTS = 10 };
+    explicit InterruptThread(RequestMultipleInterrupts* test)
         : Thread(Options("RequestInterruptTest")), test_(test) {}
 
     virtual void Run() {
       test_->sem_.Wait();
-      test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
-      test_->sem_.Wait();
-      test_->isolate_->ClearInterrupt();
-      test_->sem2_.Signal();
+      for (int i = 0; i < NUM_INTERRUPTS; i++) {
+        test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
+      }
     }
 
     static void OnInterrupt(v8::Isolate* isolate, void* data) {
-      ClearInterruptFromAnotherThread* test =
-          reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
-      test->sem_.Signal();
-      bool success = test->sem2_.WaitFor(v8::base::TimeDelta::FromSeconds(2));
-      // Crash instead of timeout to make this failure more prominent.
-      CHECK(success);
-      test->should_continue_ = false;
+      RequestMultipleInterrupts* test =
+          reinterpret_cast<RequestMultipleInterrupts*>(data);
+      test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
     }
 
    private:
-     ClearInterruptFromAnotherThread* test_;
+    RequestMultipleInterrupts* test_;
   };
 
   InterruptThread i_thread;
-  v8::base::Semaphore sem2_;
+  int counter_;
 };
 
 
-TEST(ClearInterruptFromAnotherThread) {
-  ClearInterruptFromAnotherThread().RunTest();
-}
+TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
 
 
 static Local<Value> function_new_expected_env;
@@ -22606,6 +23737,7 @@
   Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
   Handle<v8::Promise> p = pr->GetPromise();
   Handle<v8::Promise> r = rr->GetPromise();
+  CHECK_EQ(isolate, p->GetIsolate());
 
   // IsPromise predicate.
   CHECK(p->IsPromise());
@@ -22867,10 +23999,8 @@
   CHECK_EQ(13, line_number);
 }
 
-
-void SourceURLHelper(const char* source, const char* expected_source_url,
-                     const char* expected_source_mapping_url) {
-  Local<Script> script = v8_compile(source);
+void CheckMagicComments(Handle<Script> script, const char* expected_source_url,
+                        const char* expected_source_mapping_url) {
   if (expected_source_url != NULL) {
     v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
     CHECK_EQ(expected_source_url, *url);
@@ -22886,6 +24016,12 @@
   }
 }
 
+void SourceURLHelper(const char* source, const char* expected_source_url,
+                     const char* expected_source_mapping_url) {
+  Local<Script> script = v8_compile(source);
+  CheckMagicComments(script, expected_source_url, expected_source_mapping_url);
+}
+
 
 TEST(ScriptSourceURLAndSourceMappingURL) {
   LocalContext env;
@@ -23077,7 +24213,9 @@
 void RunStreamingTest(const char** chunks,
                       v8::ScriptCompiler::StreamedSource::Encoding encoding =
                           v8::ScriptCompiler::StreamedSource::ONE_BYTE,
-                      bool expected_success = true) {
+                      bool expected_success = true,
+                      const char* expected_source_url = NULL,
+                      const char* expected_source_mapping_url = NULL) {
   LocalContext env;
   v8::Isolate* isolate = env->GetIsolate();
   v8::HandleScope scope(isolate);
@@ -23106,6 +24244,8 @@
     v8::Handle<Value> result(script->Run());
     // All scripts are supposed to return the fixed value 13 when ran.
     CHECK_EQ(13, result->Int32Value());
+    CheckMagicComments(script, expected_source_url,
+                       expected_source_mapping_url);
   } else {
     CHECK(script.IsEmpty());
     CHECK(try_catch.HasCaught());
@@ -23170,14 +24310,14 @@
 
 
 TEST(StreamingUtf8Script) {
-  // We'd want to write \uc481 instead of \xeb\x91\x80, but Windows compilers
+  // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
   // don't like it.
   const char* chunk1 =
       "function foo() {\n"
       "  // This function will contain an UTF-8 character which is not in\n"
       "  // ASCII.\n"
-      "  var foob\xeb\x91\x80r = 13;\n"
-      "  return foob\xeb\x91\x80r;\n"
+      "  var foob\xec\x92\x81r = 13;\n"
+      "  return foob\xec\x92\x81r;\n"
       "}\n";
   const char* chunks[] = {chunk1, "foo(); ", NULL};
   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
@@ -23188,7 +24328,7 @@
   // A sanity check to prove that the approach of splitting UTF-8
   // characters is correct. Here is an UTF-8 character which will take three
   // bytes.
-  const char* reference = "\xeb\x91\x80";
+  const char* reference = "\xec\x92\x81";
   CHECK(3u == strlen(reference));  // NOLINT - no CHECK_EQ for unsigned.
 
   char chunk1[] =
@@ -23198,7 +24338,7 @@
       "  var foob";
   char chunk2[] =
       "XXXr = 13;\n"
-      "  return foob\xeb\x91\x80r;\n"
+      "  return foob\xec\x92\x81r;\n"
       "}\n";
   for (int i = 0; i < 3; ++i) {
     chunk2[i] = reference[i];
@@ -23211,7 +24351,7 @@
 TEST(StreamingUtf8ScriptWithSplitCharacters) {
   // Stream data where a multi-byte UTF-8 character is split between two data
   // chunks.
-  const char* reference = "\xeb\x91\x80";
+  const char* reference = "\xec\x92\x81";
   char chunk1[] =
       "function foo() {\n"
       "  // This function will contain an UTF-8 character which is not in\n"
@@ -23219,7 +24359,7 @@
       "  var foobX";
   char chunk2[] =
       "XXr = 13;\n"
-      "  return foob\xeb\x91\x80r;\n"
+      "  return foob\xec\x92\x81r;\n"
       "}\n";
   chunk1[strlen(chunk1) - 1] = reference[0];
   chunk2[0] = reference[1];
@@ -23235,7 +24375,7 @@
   // Case 1: a chunk contains only bytes for a split character (and no other
   // data). This kind of a chunk would be exceptionally small, but we should
   // still decode it correctly.
-  const char* reference = "\xeb\x91\x80";
+  const char* reference = "\xec\x92\x81";
   // The small chunk is at the beginning of the split character
   {
     char chunk1[] =
@@ -23246,7 +24386,7 @@
     char chunk2[] = "XX";
     char chunk3[] =
         "Xr = 13;\n"
-        "  return foob\xeb\x91\x80r;\n"
+        "  return foob\xec\x92\x81r;\n"
         "}\n";
     chunk2[0] = reference[0];
     chunk2[1] = reference[1];
@@ -23264,7 +24404,7 @@
     char chunk2[] = "XX";
     char chunk3[] =
         "r = 13;\n"
-        "  return foob\xeb\x91\x80r;\n"
+        "  return foob\xec\x92\x81r;\n"
         "}\n";
     chunk1[strlen(chunk1) - 1] = reference[0];
     chunk2[0] = reference[1];
@@ -23276,8 +24416,8 @@
   // decoded correctly and not just ignored.
   {
     char chunk1[] =
-        "var foob\xeb\x91\x80 = 13;\n"
-        "foob\xeb\x91\x80";
+        "var foob\xec\x92\x81 = 13;\n"
+        "foob\xec\x92\x81";
     const char* chunks[] = {chunk1, NULL};
     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
   }
@@ -23288,7 +24428,7 @@
   // Test cases where a UTF-8 character is split over several chunks. Those
   // cases are not supported (the embedder should give the data in big enough
   // chunks), but we shouldn't crash, just produce a parse error.
-  const char* reference = "\xeb\x91\x80";
+  const char* reference = "\xec\x92\x81";
   char chunk1[] =
       "function foo() {\n"
       "  // This function will contain an UTF-8 character which is not in\n"
@@ -23297,7 +24437,7 @@
   char chunk2[] = "X";
   char chunk3[] =
       "Xr = 13;\n"
-      "  return foob\xeb\x91\x80r;\n"
+      "  return foob\xec\x92\x81r;\n"
       "}\n";
   chunk1[strlen(chunk1) - 1] = reference[0];
   chunk2[0] = reference[1];
@@ -23332,6 +24472,7 @@
   const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
   CHECK(cached_data != NULL);
   CHECK(cached_data->data != NULL);
+  CHECK(!cached_data->rejected);
   CHECK_GT(cached_data->length, 0);
 }
 
@@ -23339,7 +24480,7 @@
 TEST(StreamingScriptWithInvalidUtf8) {
   // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
   // chunk don't produce a crash.
-  const char* reference = "\xeb\x91\x80\x80\x80";
+  const char* reference = "\xec\x92\x81\x80\x80";
   char chunk1[] =
       "function foo() {\n"
       "  // This function will contain an UTF-8 character which is not in\n"
@@ -23347,10 +24488,274 @@
       "  var foobXXXXX";  // Too many bytes which look like incomplete chars!
   char chunk2[] =
       "r = 13;\n"
-      "  return foob\xeb\x91\x80\x80\x80r;\n"
+      "  return foob\xec\x92\x81\x80\x80r;\n"
       "}\n";
   for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
 
   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
 }
+
+
+TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
+  // Regression test: Stream data where there are several multi-byte UTF-8
+  // characters in a sequence and one of them is split between two data chunks.
+  const char* reference = "\xec\x92\x81";
+  char chunk1[] =
+      "function foo() {\n"
+      "  // This function will contain an UTF-8 character which is not in\n"
+      "  // ASCII.\n"
+      "  var foob\xec\x92\x81X";
+  char chunk2[] =
+      "XXr = 13;\n"
+      "  return foob\xec\x92\x81\xec\x92\x81r;\n"
+      "}\n";
+  chunk1[strlen(chunk1) - 1] = reference[0];
+  chunk2[0] = reference[1];
+  chunk2[1] = reference[2];
+  const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+}
+
+
+TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
+  // Another regression test, similar to the previous one. The difference is
+  // that the split character is not the last one in the sequence.
+  const char* reference = "\xec\x92\x81";
+  char chunk1[] =
+      "function foo() {\n"
+      "  // This function will contain an UTF-8 character which is not in\n"
+      "  // ASCII.\n"
+      "  var foobX";
+  char chunk2[] =
+      "XX\xec\x92\x81r = 13;\n"
+      "  return foob\xec\x92\x81\xec\x92\x81r;\n"
+      "}\n";
+  chunk1[strlen(chunk1) - 1] = reference[0];
+  chunk2[0] = reference[1];
+  chunk2[1] = reference[2];
+  const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+}
+
+
+void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
+  const char* garbage = "garbage garbage garbage garbage garbage garbage";
+  const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
+  int length = 16;
+  v8::ScriptCompiler::CachedData* cached_data =
+      new v8::ScriptCompiler::CachedData(data, length);
+  DCHECK(!cached_data->rejected);
+  v8::ScriptOrigin origin(v8_str("origin"));
+  v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
+  v8::Handle<v8::Script> script =
+      v8::ScriptCompiler::Compile(CcTest::isolate(), &source, option);
+  CHECK(cached_data->rejected);
+  CHECK_EQ(42, script->Run()->Int32Value());
+}
+
+
+TEST(InvalidCacheData) {
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  LocalContext context;
+  TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
+  TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
+}
+
+
+TEST(ParserCacheRejectedGracefully) {
+  i::FLAG_min_preparse_length = 0;
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  LocalContext context;
+  // Produce valid cached data.
+  v8::ScriptOrigin origin(v8_str("origin"));
+  v8::Local<v8::String> source_str = v8_str("function foo() {}");
+  v8::ScriptCompiler::Source source(source_str, origin);
+  v8::Handle<v8::Script> script = v8::ScriptCompiler::Compile(
+      CcTest::isolate(), &source, v8::ScriptCompiler::kProduceParserCache);
+  CHECK(!script.IsEmpty());
+  const v8::ScriptCompiler::CachedData* original_cached_data =
+      source.GetCachedData();
+  CHECK(original_cached_data != NULL);
+  CHECK(original_cached_data->data != NULL);
+  CHECK(!original_cached_data->rejected);
+  CHECK_GT(original_cached_data->length, 0);
+  // Recompiling the same script with it won't reject the data.
+  {
+    v8::ScriptCompiler::Source source_with_cached_data(
+        source_str, origin,
+        new v8::ScriptCompiler::CachedData(original_cached_data->data,
+                                           original_cached_data->length));
+    v8::Handle<v8::Script> script =
+        v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
+                                    v8::ScriptCompiler::kConsumeParserCache);
+    CHECK(!script.IsEmpty());
+    const v8::ScriptCompiler::CachedData* new_cached_data =
+        source_with_cached_data.GetCachedData();
+    CHECK(new_cached_data != NULL);
+    CHECK(!new_cached_data->rejected);
+  }
+  // Compile an incompatible script with the cached data. The new script doesn't
+  // have the same starting position for the function as the old one, so the old
+  // cached data will be incompatible with it and will be rejected.
+  {
+    v8::Local<v8::String> incompatible_source_str =
+        v8_str("   function foo() {}");
+    v8::ScriptCompiler::Source source_with_cached_data(
+        incompatible_source_str, origin,
+        new v8::ScriptCompiler::CachedData(original_cached_data->data,
+                                           original_cached_data->length));
+    v8::Handle<v8::Script> script =
+        v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
+                                    v8::ScriptCompiler::kConsumeParserCache);
+    CHECK(!script.IsEmpty());
+    const v8::ScriptCompiler::CachedData* new_cached_data =
+        source_with_cached_data.GetCachedData();
+    CHECK(new_cached_data != NULL);
+    CHECK(new_cached_data->rejected);
+  }
+}
+
+
+TEST(StringConcatOverflow) {
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  RandomLengthOneByteResource* r =
+      new RandomLengthOneByteResource(i::String::kMaxLength);
+  v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r);
+  CHECK(!str.IsEmpty());
+  v8::TryCatch try_catch;
+  v8::Local<v8::String> result = v8::String::Concat(str, str);
+  CHECK(result.IsEmpty());
+  CHECK(!try_catch.HasCaught());
+}
+
+
+TEST(TurboAsmDisablesNeuter) {
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  LocalContext context;
+#if V8_TURBOFAN_TARGET
+  bool should_be_neuterable = !i::FLAG_turbo_asm;
+#else
+  bool should_be_neuterable = true;
+#endif
+  const char* load =
+      "function Module(stdlib, foreign, heap) {"
+      "  'use asm';"
+      "  var MEM32 = new stdlib.Int32Array(heap);"
+      "  function load() { return MEM32[0]; }"
+      "  return { load: load };"
+      "}"
+      "var buffer = new ArrayBuffer(4);"
+      "Module(this, {}, buffer).load();"
+      "buffer";
+
+  v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
+  CHECK_EQ(should_be_neuterable, result->IsNeuterable());
+
+  const char* store =
+      "function Module(stdlib, foreign, heap) {"
+      "  'use asm';"
+      "  var MEM32 = new stdlib.Int32Array(heap);"
+      "  function store() { MEM32[0] = 0; }"
+      "  return { store: store };"
+      "}"
+      "var buffer = new ArrayBuffer(4);"
+      "Module(this, {}, buffer).store();"
+      "buffer";
+
+  result = CompileRun(store).As<v8::ArrayBuffer>();
+  CHECK_EQ(should_be_neuterable, result->IsNeuterable());
+}
+
+
+TEST(GetPrototypeAccessControl) {
+  i::FLAG_allow_natives_syntax = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext env;
+
+  v8::Handle<v8::ObjectTemplate> obj_template =
+      v8::ObjectTemplate::New(isolate);
+  obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
+                                        BlockEverythingIndexed);
+
+  env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
+
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "function f() { %_GetPrototype(prohibited); }"
+        "%OptimizeFunctionOnNextCall(f);"
+        "f();");
+    CHECK(try_catch.HasCaught());
+  }
+}
+
+
+TEST(GetPrototypeHidden) {
+  i::FLAG_allow_natives_syntax = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext env;
+
+  Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
+  t->SetHiddenPrototype(true);
+  Handle<Object> proto = t->GetFunction()->NewInstance();
+  Handle<Object> object = Object::New(isolate);
+  Handle<Object> proto2 = Object::New(isolate);
+  object->SetPrototype(proto);
+  proto->SetPrototype(proto2);
+
+  env->Global()->Set(v8_str("object"), object);
+  env->Global()->Set(v8_str("proto"), proto);
+  env->Global()->Set(v8_str("proto2"), proto2);
+
+  v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
+  CHECK(result->Equals(proto2));
+
+  result = CompileRun(
+      "function f() { return %_GetPrototype(object); }"
+      "%OptimizeFunctionOnNextCall(f);"
+      "f()");
+  CHECK(result->Equals(proto2));
+}
+
+
+TEST(ClassPrototypeCreationContext) {
+  i::FLAG_harmony_classes = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext env;
+
+  Handle<Object> result = Handle<Object>::Cast(
+      CompileRun("'use strict'; class Example { }; Example.prototype"));
+  CHECK(env.local() == result->CreationContext());
+}
+
+
+TEST(SimpleStreamingScriptWithSourceURL) {
+  const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
+                          "//# sourceURL=bar2.js\n", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
+                   "bar2.js");
+}
+
+
+TEST(StreamingScriptWithSplitSourceURL) {
+  const char* chunks[] = {"function foo() { ret", "urn 13; } f",
+                          "oo();\n//# sourceURL=b", "ar2.js\n", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
+                   "bar2.js");
+}
+
+
+TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
+  const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
+                          " sourceMappingURL=bar2.js\n", "foo();", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL,
+                   "bar2.js");
+}
diff --git a/test/cctest/test-assembler-arm.cc b/test/cctest/test-assembler-arm.cc
index ed9563d..2bcf022 100644
--- a/test/cctest/test-assembler-arm.cc
+++ b/test/cctest/test-assembler-arm.cc
@@ -25,6 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#include <iostream>  // NOLINT(readability/streams)
+
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
 
@@ -34,6 +36,7 @@
 #include "src/factory.h"
 #include "src/ostreams.h"
 
+using namespace v8::base;
 using namespace v8::internal;
 
 
@@ -1372,14 +1375,14 @@
   __ pkhtb(r2, r0, Operand(r1, ASR, 8));
   __ str(r2, MemOperand(r4, OFFSET_OF(T, dst1)));
 
-  __ uxtb16(r2, Operand(r0, ROR, 8));
+  __ uxtb16(r2, r0, 8);
   __ str(r2, MemOperand(r4, OFFSET_OF(T, dst2)));
 
-  __ uxtb(r2, Operand(r0, ROR, 8));
+  __ uxtb(r2, r0, 8);
   __ str(r2, MemOperand(r4, OFFSET_OF(T, dst3)));
 
   __ ldr(r0, MemOperand(r4, OFFSET_OF(T, src2)));
-  __ uxtab(r2, r0, Operand(r1, ROR, 8));
+  __ uxtab(r2, r0, r1, 8);
   __ str(r2, MemOperand(r4, OFFSET_OF(T, dst4)));
 
   __ ldm(ia_w, sp, r4.bit() | pc.bit());
@@ -1439,21 +1442,19 @@
     CHECK_EQ(expected_, t.result);
 
 
-TEST(18) {
+TEST(sdiv) {
   // Test the sdiv.
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   HandleScope scope(isolate);
-
-  typedef struct {
-    uint32_t dividend;
-    uint32_t divisor;
-    uint32_t result;
-  } T;
-  T t;
-
   Assembler assm(isolate, NULL, 0);
 
+  struct T {
+    int32_t dividend;
+    int32_t divisor;
+    int32_t result;
+  } t;
+
   if (CpuFeatures::IsSupported(SUDIV)) {
     CpuFeatureScope scope(&assm, SUDIV);
 
@@ -1477,6 +1478,8 @@
 #endif
     F3 f = FUNCTION_CAST<F3>(code->entry());
     Object* dummy;
+    TEST_SDIV(0, kMinInt, 0);
+    TEST_SDIV(0, 1024, 0);
     TEST_SDIV(1073741824, kMinInt, -2);
     TEST_SDIV(kMinInt, kMinInt, -1);
     TEST_SDIV(5, 10, 2);
@@ -1495,6 +1498,322 @@
 #undef TEST_SDIV
 
 
+#define TEST_UDIV(expected_, dividend_, divisor_) \
+  t.dividend = dividend_;                         \
+  t.divisor = divisor_;                           \
+  t.result = 0;                                   \
+  dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); \
+  CHECK_EQ(expected_, t.result);
+
+
+TEST(udiv) {
+  // Test the udiv.
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  Assembler assm(isolate, NULL, 0);
+
+  struct T {
+    uint32_t dividend;
+    uint32_t divisor;
+    uint32_t result;
+  } t;
+
+  if (CpuFeatures::IsSupported(SUDIV)) {
+    CpuFeatureScope scope(&assm, SUDIV);
+
+    __ mov(r3, Operand(r0));
+
+    __ ldr(r0, MemOperand(r3, OFFSET_OF(T, dividend)));
+    __ ldr(r1, MemOperand(r3, OFFSET_OF(T, divisor)));
+
+    __ sdiv(r2, r0, r1);
+    __ str(r2, MemOperand(r3, OFFSET_OF(T, result)));
+
+    __ bx(lr);
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef DEBUG
+    OFStream os(stdout);
+    code->Print(os);
+#endif
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+    Object* dummy;
+    TEST_UDIV(0, 0, 0);
+    TEST_UDIV(0, 1024, 0);
+    TEST_UDIV(5, 10, 2);
+    TEST_UDIV(3, 10, 3);
+    USE(dummy);
+  }
+}
+
+
+#undef TEST_UDIV
+
+
+TEST(smmla) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ smmla(r1, r1, r2, r3);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt(), z = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, z, 0);
+    CHECK_EQ(bits::SignedMulHighAndAdd32(x, y, z), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(smmul) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ smmul(r1, r1, r2);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(bits::SignedMulHigh32(x, y), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(sxtb) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ sxtb(r1, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<int8_t>(x)), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(sxtab) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ sxtab(r1, r2, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<int8_t>(x)) + y, r);
+    USE(dummy);
+  }
+}
+
+
+TEST(sxth) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ sxth(r1, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<int16_t>(x)), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(sxtah) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ sxtah(r1, r2, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<int16_t>(x)) + y, r);
+    USE(dummy);
+  }
+}
+
+
+TEST(uxtb) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ uxtb(r1, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<uint8_t>(x)), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(uxtab) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ uxtab(r1, r2, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<uint8_t>(x)) + y, r);
+    USE(dummy);
+  }
+}
+
+
+TEST(uxth) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ uxth(r1, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<uint16_t>(x)), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(uxtah) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ uxtah(r1, r2, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<uint16_t>(x)) + y, r);
+    USE(dummy);
+  }
+}
+
+
 TEST(code_relative_offset) {
   // Test extracting the offset of a label from the beginning of the code
   // in a register.
@@ -1565,4 +1884,100 @@
   CHECK_EQ(42, res);
 }
 
+
+TEST(ARMv8_vrintX) {
+  // Test the vrintX floating point instructions.
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+
+  typedef struct {
+    double input;
+    double ar;
+    double nr;
+    double mr;
+    double pr;
+    double zr;
+  } T;
+  T t;
+
+  // Create a function that accepts &t, and loads, manipulates, and stores
+  // the doubles and floats.
+  Assembler assm(isolate, NULL, 0);
+  Label L, C;
+
+
+  if (CpuFeatures::IsSupported(ARMv8)) {
+    CpuFeatureScope scope(&assm, ARMv8);
+
+    __ mov(ip, Operand(sp));
+    __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
+
+    __ mov(r4, Operand(r0));
+
+    // Test vrinta
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrinta(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, ar));
+
+    // Test vrintn
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrintn(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, nr));
+
+    // Test vrintp
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrintp(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, pr));
+
+    // Test vrintm
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrintm(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, mr));
+
+    // Test vrintz
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrintz(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, zr));
+
+    __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef DEBUG
+    OFStream os(stdout);
+    code->Print(os);
+#endif
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+
+    Object* dummy = nullptr;
+    USE(dummy);
+
+#define CHECK_VRINT(input_val, ares, nres, mres, pres, zres) \
+  t.input = input_val;                                       \
+  dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);            \
+  CHECK_EQ(ares, t.ar);                                      \
+  CHECK_EQ(nres, t.nr);                                      \
+  CHECK_EQ(mres, t.mr);                                      \
+  CHECK_EQ(pres, t.pr);                                      \
+  CHECK_EQ(zres, t.zr);
+
+    CHECK_VRINT(-0.5, -1.0, -0.0, -1.0, -0.0, -0.0)
+    CHECK_VRINT(-0.6, -1.0, -1.0, -1.0, -0.0, -0.0)
+    CHECK_VRINT(-1.1, -1.0, -1.0, -2.0, -1.0, -1.0)
+    CHECK_VRINT(0.5, 1.0, 0.0, 0.0, 1.0, 0.0)
+    CHECK_VRINT(0.6, 1.0, 1.0, 0.0, 1.0, 0.0)
+    CHECK_VRINT(1.1, 1.0, 1.0, 1.0, 2.0, 1.0)
+    double inf = std::numeric_limits<double>::infinity();
+    CHECK_VRINT(inf, inf, inf, inf, inf, inf)
+    CHECK_VRINT(-inf, -inf, -inf, -inf, -inf, -inf)
+    CHECK_VRINT(-0.0, -0.0, -0.0, -0.0, -0.0, -0.0)
+    double nan = std::numeric_limits<double>::quiet_NaN();
+    CHECK_VRINT(nan, nan, nan, nan, nan, nan)
+
+#undef CHECK_VRINT
+  }
+}
 #undef __
diff --git a/test/cctest/test-assembler-arm64.cc b/test/cctest/test-assembler-arm64.cc
index 587a4ce..108152e 100644
--- a/test/cctest/test-assembler-arm64.cc
+++ b/test/cctest/test-assembler-arm64.cc
@@ -6554,6 +6554,95 @@
 }
 
 
+TEST(frintp) {
+  INIT_V8();
+  SETUP();
+
+  START();
+  __ Fmov(s16, 1.0);
+  __ Fmov(s17, 1.1);
+  __ Fmov(s18, 1.5);
+  __ Fmov(s19, 1.9);
+  __ Fmov(s20, 2.5);
+  __ Fmov(s21, -1.5);
+  __ Fmov(s22, -2.5);
+  __ Fmov(s23, kFP32PositiveInfinity);
+  __ Fmov(s24, kFP32NegativeInfinity);
+  __ Fmov(s25, 0.0);
+  __ Fmov(s26, -0.0);
+  __ Fmov(s27, -0.2);
+
+  __ Frintp(s0, s16);
+  __ Frintp(s1, s17);
+  __ Frintp(s2, s18);
+  __ Frintp(s3, s19);
+  __ Frintp(s4, s20);
+  __ Frintp(s5, s21);
+  __ Frintp(s6, s22);
+  __ Frintp(s7, s23);
+  __ Frintp(s8, s24);
+  __ Frintp(s9, s25);
+  __ Frintp(s10, s26);
+  __ Frintp(s11, s27);
+
+  __ Fmov(d16, -0.5);
+  __ Fmov(d17, -0.8);
+  __ Fmov(d18, 1.5);
+  __ Fmov(d19, 1.9);
+  __ Fmov(d20, 2.5);
+  __ Fmov(d21, -1.5);
+  __ Fmov(d22, -2.5);
+  __ Fmov(d23, kFP32PositiveInfinity);
+  __ Fmov(d24, kFP32NegativeInfinity);
+  __ Fmov(d25, 0.0);
+  __ Fmov(d26, -0.0);
+  __ Fmov(d27, -0.2);
+
+  __ Frintp(d12, d16);
+  __ Frintp(d13, d17);
+  __ Frintp(d14, d18);
+  __ Frintp(d15, d19);
+  __ Frintp(d16, d20);
+  __ Frintp(d17, d21);
+  __ Frintp(d18, d22);
+  __ Frintp(d19, d23);
+  __ Frintp(d20, d24);
+  __ Frintp(d21, d25);
+  __ Frintp(d22, d26);
+  __ Frintp(d23, d27);
+  END();
+
+  RUN();
+
+  CHECK_EQUAL_FP32(1.0, s0);
+  CHECK_EQUAL_FP32(2.0, s1);
+  CHECK_EQUAL_FP32(2.0, s2);
+  CHECK_EQUAL_FP32(2.0, s3);
+  CHECK_EQUAL_FP32(3.0, s4);
+  CHECK_EQUAL_FP32(-1.0, s5);
+  CHECK_EQUAL_FP32(-2.0, s6);
+  CHECK_EQUAL_FP32(kFP32PositiveInfinity, s7);
+  CHECK_EQUAL_FP32(kFP32NegativeInfinity, s8);
+  CHECK_EQUAL_FP32(0.0, s9);
+  CHECK_EQUAL_FP32(-0.0, s10);
+  CHECK_EQUAL_FP32(-0.0, s11);
+  CHECK_EQUAL_FP64(-0.0, d12);
+  CHECK_EQUAL_FP64(-0.0, d13);
+  CHECK_EQUAL_FP64(2.0, d14);
+  CHECK_EQUAL_FP64(2.0, d15);
+  CHECK_EQUAL_FP64(3.0, d16);
+  CHECK_EQUAL_FP64(-1.0, d17);
+  CHECK_EQUAL_FP64(-2.0, d18);
+  CHECK_EQUAL_FP64(kFP64PositiveInfinity, d19);
+  CHECK_EQUAL_FP64(kFP64NegativeInfinity, d20);
+  CHECK_EQUAL_FP64(0.0, d21);
+  CHECK_EQUAL_FP64(-0.0, d22);
+  CHECK_EQUAL_FP64(-0.0, d23);
+
+  TEARDOWN();
+}
+
+
 TEST(frintz) {
   INIT_V8();
   SETUP();
diff --git a/test/cctest/test-assembler-ia32.cc b/test/cctest/test-assembler-ia32.cc
index e8c7f95..f59c3c4 100644
--- a/test/cctest/test-assembler-ia32.cc
+++ b/test/cctest/test-assembler-ia32.cc
@@ -170,11 +170,10 @@
   assm.GetCode(&desc);
   Handle<Code> code = isolate->factory()->NewCode(
       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
-  // don't print the code - our disassembler can't handle cvttss2si
-  // instead print bytes
-  Disassembler::Dump(stdout,
-                     code->instruction_start(),
-                     code->instruction_start() + code->instruction_size());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
   F3 f = FUNCTION_CAST<F3>(code->entry());
   int res = f(static_cast<float>(-3.1415));
   ::printf("f() = %d\n", res);
@@ -200,11 +199,10 @@
   assm.GetCode(&desc);
   Handle<Code> code = isolate->factory()->NewCode(
       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
-  // don't print the code - our disassembler can't handle cvttsd2si
-  // instead print bytes
-  Disassembler::Dump(stdout,
-                     code->instruction_start(),
-                     code->instruction_start() + code->instruction_size());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
   F4 f = FUNCTION_CAST<F4>(code->entry());
   int res = f(2.718281828);
   ::printf("f() = %d\n", res);
@@ -261,13 +259,9 @@
   assm.GetCode(&desc);
   Handle<Code> code = isolate->factory()->NewCode(
       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
-#ifdef DEBUG
-  ::printf("\n---\n");
-  // don't print the code - our disassembler can't handle SSE instructions
-  // instead print bytes
-  Disassembler::Dump(stdout,
-                     code->instruction_start(),
-                     code->instruction_start() + code->instruction_size());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
 #endif
   F5 f = FUNCTION_CAST<F5>(code->entry());
   double res = f(2.2, 1.1);
@@ -595,4 +589,458 @@
 }
 
 
+typedef int (*F9)(double x, double y, double z);
+TEST(AssemblerX64FMA_sd) {
+  CcTest::InitializeVM();
+  if (!CpuFeatures::IsSupported(FMA3)) return;
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  MacroAssembler assm(isolate, buffer, sizeof buffer);
+  {
+    CpuFeatureScope fscope(&assm, FMA3);
+    Label exit;
+    __ movsd(xmm0, Operand(esp, 1 * kPointerSize));
+    __ movsd(xmm1, Operand(esp, 3 * kPointerSize));
+    __ movsd(xmm2, Operand(esp, 5 * kPointerSize));
+    // argument in xmm0, xmm1 and xmm2
+    // xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ addsd(xmm3, xmm2);  // Expected result in xmm3
+
+    __ sub(esp, Immediate(kDoubleSize));  // For memory operand
+    // vfmadd132sd
+    __ mov(eax, Immediate(1));  // Test number
+    __ movaps(xmm4, xmm0);
+    __ vfmadd132sd(xmm4, xmm2, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfmadd213sd(xmm4, xmm0, xmm2);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfmadd231sd(xmm4, xmm0, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmadd132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfmadd132sd(xmm4, xmm2, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movsd(Operand(esp, 0), xmm2);
+    __ vfmadd213sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfmadd231sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ subsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfmsub132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfmsub132sd(xmm4, xmm2, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfmsub213sd(xmm4, xmm0, xmm2);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfmsub231sd(xmm4, xmm0, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmsub132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfmsub132sd(xmm4, xmm2, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movsd(Operand(esp, 0), xmm2);
+    __ vfmsub213sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfmsub231sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ Move(xmm4, (uint64_t)1 << 63);
+    __ xorpd(xmm3, xmm4);
+    __ addsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmadd132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfnmadd132sd(xmm4, xmm2, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfnmadd213sd(xmm4, xmm0, xmm2);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfnmadd231sd(xmm4, xmm0, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmadd132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfnmadd132sd(xmm4, xmm2, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movsd(Operand(esp, 0), xmm2);
+    __ vfnmadd213sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfnmadd231sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ Move(xmm4, (uint64_t)1 << 63);
+    __ xorpd(xmm3, xmm4);
+    __ subsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmsub132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfnmsub132sd(xmm4, xmm2, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfnmsub213sd(xmm4, xmm0, xmm2);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfnmsub231sd(xmm4, xmm0, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmsub132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfnmsub132sd(xmm4, xmm2, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movsd(Operand(esp, 0), xmm2);
+    __ vfnmsub213sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfnmsub231sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    __ xor_(eax, eax);
+    __ bind(&exit);
+    __ add(esp, Immediate(kDoubleSize));
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F9 f = FUNCTION_CAST<F9>(code->entry());
+  CHECK_EQ(0, f(0.000092662107262076, -2.460774966188315, -1.0958787393627414));
+}
+
+
+typedef int (*F10)(float x, float y, float z);
+TEST(AssemblerX64FMA_ss) {
+  CcTest::InitializeVM();
+  if (!CpuFeatures::IsSupported(FMA3)) return;
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  MacroAssembler assm(isolate, buffer, sizeof buffer);
+  {
+    CpuFeatureScope fscope(&assm, FMA3);
+    Label exit;
+    __ movss(xmm0, Operand(esp, 1 * kPointerSize));
+    __ movss(xmm1, Operand(esp, 2 * kPointerSize));
+    __ movss(xmm2, Operand(esp, 3 * kPointerSize));
+    // arguments in xmm0, xmm1 and xmm2
+    // xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ addss(xmm3, xmm2);  // Expected result in xmm3
+
+    __ sub(esp, Immediate(kDoubleSize));  // For memory operand
+    // vfmadd132ss
+    __ mov(eax, Immediate(1));  // Test number
+    __ movaps(xmm4, xmm0);
+    __ vfmadd132ss(xmm4, xmm2, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfmadd213ss(xmm4, xmm0, xmm2);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfmadd231ss(xmm4, xmm0, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmadd132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfmadd132ss(xmm4, xmm2, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movss(Operand(esp, 0), xmm2);
+    __ vfmadd213ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfmadd231ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ subss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfmsub132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfmsub132ss(xmm4, xmm2, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfmsub213ss(xmm4, xmm0, xmm2);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfmsub231ss(xmm4, xmm0, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmsub132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfmsub132ss(xmm4, xmm2, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movss(Operand(esp, 0), xmm2);
+    __ vfmsub213ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfmsub231ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ Move(xmm4, (uint32_t)1 << 31);
+    __ xorps(xmm3, xmm4);
+    __ addss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmadd132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfnmadd132ss(xmm4, xmm2, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfnmadd213ss(xmm4, xmm0, xmm2);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfnmadd231ss(xmm4, xmm0, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmadd132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfnmadd132ss(xmm4, xmm2, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movss(Operand(esp, 0), xmm2);
+    __ vfnmadd213ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfnmadd231ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ Move(xmm4, (uint32_t)1 << 31);
+    __ xorps(xmm3, xmm4);
+    __ subss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmsub132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfnmsub132ss(xmm4, xmm2, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfnmsub213ss(xmm4, xmm0, xmm2);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfnmsub231ss(xmm4, xmm0, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmsub132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfnmsub132ss(xmm4, xmm2, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movss(Operand(esp, 0), xmm2);
+    __ vfnmsub213ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfnmsub231ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    __ xor_(eax, eax);
+    __ bind(&exit);
+    __ add(esp, Immediate(kDoubleSize));
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F10 f = FUNCTION_CAST<F10>(code->entry());
+  CHECK_EQ(0, f(9.26621069e-05f, -2.4607749f, -1.09587872f));
+}
 #undef __
diff --git a/test/cctest/test-assembler-x64.cc b/test/cctest/test-assembler-x64.cc
index 3d305b6..23d0be6 100644
--- a/test/cctest/test-assembler-x64.cc
+++ b/test/cctest/test-assembler-x64.cc
@@ -736,4 +736,454 @@
   F6 f = FUNCTION_CAST<F6>(code->entry());
   CHECK_EQ(2, f(1.0, 2.0));
 }
+
+
+typedef int (*F7)(double x, double y, double z);
+TEST(AssemblerX64FMA_sd) {
+  CcTest::InitializeVM();
+  if (!CpuFeatures::IsSupported(FMA3)) return;
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  MacroAssembler assm(isolate, buffer, sizeof buffer);
+  {
+    CpuFeatureScope fscope(&assm, FMA3);
+    Label exit;
+    // argument in xmm0, xmm1 and xmm2
+    // xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ addsd(xmm3, xmm2);  // Expected result in xmm3
+
+    __ subq(rsp, Immediate(kDoubleSize));  // For memory operand
+    // vfmadd132sd
+    __ movl(rax, Immediate(1));  // Test number
+    __ movaps(xmm8, xmm0);
+    __ vfmadd132sd(xmm8, xmm2, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfmadd213sd(xmm8, xmm0, xmm2);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfmadd231sd(xmm8, xmm0, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmadd132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfmadd132sd(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movsd(Operand(rsp, 0), xmm2);
+    __ vfmadd213sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfmadd231sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ subsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfmsub132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfmsub132sd(xmm8, xmm2, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfmsub213sd(xmm8, xmm0, xmm2);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfmsub231sd(xmm8, xmm0, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmsub132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfmsub132sd(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movsd(Operand(rsp, 0), xmm2);
+    __ vfmsub213sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfmsub231sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ Move(xmm4, (uint64_t)1 << 63);
+    __ xorpd(xmm3, xmm4);
+    __ addsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmadd132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfnmadd132sd(xmm8, xmm2, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfnmadd213sd(xmm8, xmm0, xmm2);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfnmadd231sd(xmm8, xmm0, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmadd132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfnmadd132sd(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movsd(Operand(rsp, 0), xmm2);
+    __ vfnmadd213sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfnmadd231sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ Move(xmm4, (uint64_t)1 << 63);
+    __ xorpd(xmm3, xmm4);
+    __ subsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmsub132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfnmsub132sd(xmm8, xmm2, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfnmsub213sd(xmm8, xmm0, xmm2);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfnmsub231sd(xmm8, xmm0, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmsub132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfnmsub132sd(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movsd(Operand(rsp, 0), xmm2);
+    __ vfnmsub213sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfnmsub231sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    __ xorl(rax, rax);
+    __ bind(&exit);
+    __ addq(rsp, Immediate(kDoubleSize));
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F7 f = FUNCTION_CAST<F7>(code->entry());
+  CHECK_EQ(0, f(0.000092662107262076, -2.460774966188315, -1.0958787393627414));
+}
+
+
+typedef int (*F8)(float x, float y, float z);
+TEST(AssemblerX64FMA_ss) {
+  CcTest::InitializeVM();
+  if (!CpuFeatures::IsSupported(FMA3)) return;
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  MacroAssembler assm(isolate, buffer, sizeof buffer);
+  {
+    CpuFeatureScope fscope(&assm, FMA3);
+    Label exit;
+    // arguments in xmm0, xmm1 and xmm2
+    // xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ addss(xmm3, xmm2);  // Expected result in xmm3
+
+    __ subq(rsp, Immediate(kDoubleSize));  // For memory operand
+    // vfmadd132ss
+    __ movl(rax, Immediate(1));  // Test number
+    __ movaps(xmm8, xmm0);
+    __ vfmadd132ss(xmm8, xmm2, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfmadd213ss(xmm8, xmm0, xmm2);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfmadd231ss(xmm8, xmm0, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmadd132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfmadd132ss(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movss(Operand(rsp, 0), xmm2);
+    __ vfmadd213ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfmadd231ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ subss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfmsub132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfmsub132ss(xmm8, xmm2, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfmsub213ss(xmm8, xmm0, xmm2);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfmsub231ss(xmm8, xmm0, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmsub132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfmsub132ss(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movss(Operand(rsp, 0), xmm2);
+    __ vfmsub213ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfmsub231ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ Move(xmm4, (uint32_t)1 << 31);
+    __ xorps(xmm3, xmm4);
+    __ addss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmadd132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfnmadd132ss(xmm8, xmm2, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfnmadd213ss(xmm8, xmm0, xmm2);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfnmadd231ss(xmm8, xmm0, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmadd132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfnmadd132ss(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movss(Operand(rsp, 0), xmm2);
+    __ vfnmadd213ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfnmadd231ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ Move(xmm4, (uint32_t)1 << 31);
+    __ xorps(xmm3, xmm4);
+    __ subss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmsub132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfnmsub132ss(xmm8, xmm2, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfnmsub213ss(xmm8, xmm0, xmm2);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfnmsub231ss(xmm8, xmm0, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmsub132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfnmsub132ss(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movss(Operand(rsp, 0), xmm2);
+    __ vfnmsub213ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfnmsub231ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    __ xorl(rax, rax);
+    __ bind(&exit);
+    __ addq(rsp, Immediate(kDoubleSize));
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F8 f = FUNCTION_CAST<F8>(code->entry());
+  CHECK_EQ(0, f(9.26621069e-05f, -2.4607749f, -1.09587872f));
+}
 #undef __
diff --git a/test/cctest/test-ast.cc b/test/cctest/test-ast.cc
index 24819df..096d5c7 100644
--- a/test/cctest/test-ast.cc
+++ b/test/cctest/test-ast.cc
@@ -40,8 +40,8 @@
 
   Isolate* isolate = CcTest::i_isolate();
   Zone zone(isolate);
-  AstNode::IdGen id_gen;
-  AstNodeFactory<AstNullVisitor> factory(&zone, NULL, &id_gen);
+  AstValueFactory value_factory(&zone, 0);
+  AstNodeFactory factory(&value_factory);
   AstNode* node = factory.NewEmptyStatement(RelocInfo::kNoPosition);
   list->Add(node);
   CHECK_EQ(1, list->length());
diff --git a/test/cctest/test-bit-vector.cc b/test/cctest/test-bit-vector.cc
new file mode 100644
index 0000000..ac00fab
--- /dev/null
+++ b/test/cctest/test-bit-vector.cc
@@ -0,0 +1,121 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "src/v8.h"
+
+#include "src/bit-vector.h"
+#include "test/cctest/cctest.h"
+
+using namespace v8::internal;
+
+TEST(BitVector) {
+  Zone zone(CcTest::i_isolate());
+  {
+    BitVector v(15, &zone);
+    v.Add(1);
+    CHECK(v.Contains(1));
+    v.Remove(0);
+    CHECK(!v.Contains(0));
+    v.Add(0);
+    v.Add(1);
+    BitVector w(15, &zone);
+    w.Add(1);
+    v.Intersect(w);
+    CHECK(!v.Contains(0));
+    CHECK(v.Contains(1));
+  }
+
+  {
+    BitVector v(64, &zone);
+    v.Add(27);
+    v.Add(30);
+    v.Add(31);
+    v.Add(33);
+    BitVector::Iterator iter(&v);
+    CHECK_EQ(27, iter.Current());
+    iter.Advance();
+    CHECK_EQ(30, iter.Current());
+    iter.Advance();
+    CHECK_EQ(31, iter.Current());
+    iter.Advance();
+    CHECK_EQ(33, iter.Current());
+    iter.Advance();
+    CHECK(iter.Done());
+  }
+
+  {
+    BitVector v(15, &zone);
+    v.Add(0);
+    BitVector w(15, &zone);
+    w.Add(1);
+    v.Union(w);
+    CHECK(v.Contains(0));
+    CHECK(v.Contains(1));
+  }
+
+  {
+    BitVector v(15, &zone);
+    v.Add(0);
+    BitVector w(15, &zone);
+    w.CopyFrom(v);
+    CHECK(w.Contains(0));
+    w.Add(1);
+    BitVector u(w, &zone);
+    CHECK(u.Contains(0));
+    CHECK(u.Contains(1));
+    v.Union(w);
+    CHECK(v.Contains(0));
+    CHECK(v.Contains(1));
+  }
+
+  {
+    BitVector v(35, &zone);
+    v.Add(0);
+    BitVector w(35, &zone);
+    w.Add(33);
+    v.Union(w);
+    CHECK(v.Contains(0));
+    CHECK(v.Contains(33));
+  }
+
+  {
+    BitVector v(35, &zone);
+    v.Add(32);
+    v.Add(33);
+    BitVector w(35, &zone);
+    w.Add(33);
+    v.Intersect(w);
+    CHECK(!v.Contains(32));
+    CHECK(v.Contains(33));
+    BitVector r(35, &zone);
+    r.CopyFrom(v);
+    CHECK(!r.Contains(32));
+    CHECK(r.Contains(33));
+  }
+}
diff --git a/test/cctest/test-code-stubs-mips64.cc b/test/cctest/test-code-stubs-mips64.cc
index 025a8ba..1f7df38 100644
--- a/test/cctest/test-code-stubs-mips64.cc
+++ b/test/cctest/test-code-stubs-mips64.cc
@@ -104,7 +104,7 @@
   for (--reg_num; reg_num >= 2; --reg_num) {
     Register reg = Register::from_code(reg_num);
     if (!reg.is(destination_reg)) {
-      __ lw(at, MemOperand(sp, 0));
+      __ ld(at, MemOperand(sp, 0));
       __ Assert(eq, kRegisterWasClobbered, reg, Operand(at));
       __ Daddu(sp, sp, Operand(kPointerSize));
     }
diff --git a/test/cctest/test-compiler.cc b/test/cctest/test-compiler.cc
index 4d6e005..a05231e 100644
--- a/test/cctest/test-compiler.cc
+++ b/test/cctest/test-compiler.cc
@@ -306,12 +306,15 @@
   // We shouldn't have deoptimization support. We want to recompile and
   // verify that our feedback vector preserves information.
   CHECK(!f->shared()->has_deoptimization_support());
-  Handle<FixedArray> feedback_vector(f->shared()->feedback_vector());
+  Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector());
 
   // Verify that we gathered feedback.
-  int expected_count = FLAG_vector_ics ? 2 : 1;
-  CHECK_EQ(expected_count, feedback_vector->length());
-  CHECK(feedback_vector->get(expected_count - 1)->IsJSFunction());
+  int expected_slots = 0;
+  int expected_ic_slots = 1;
+  CHECK_EQ(expected_slots, feedback_vector->Slots());
+  CHECK_EQ(expected_ic_slots, feedback_vector->ICSlots());
+  FeedbackVectorICSlot slot_for_a(0);
+  CHECK(feedback_vector->Get(slot_for_a)->IsJSFunction());
 
   CompileRun("%OptimizeFunctionOnNextCall(f); f(fun1);");
 
@@ -319,8 +322,7 @@
   // of the full code.
   CHECK(f->IsOptimized());
   CHECK(f->shared()->has_deoptimization_support());
-  CHECK(f->shared()->feedback_vector()->
-        get(expected_count - 1)->IsJSFunction());
+  CHECK(f->shared()->feedback_vector()->Get(slot_for_a)->IsJSFunction());
 }
 
 
@@ -346,16 +348,19 @@
           *v8::Handle<v8::Function>::Cast(
               CcTest::global()->Get(v8_str("morphing_call"))));
 
-  int expected_count = FLAG_vector_ics ? 2 : 1;
-  CHECK_EQ(expected_count, f->shared()->feedback_vector()->length());
-  // And yet it's not compiled.
+  // Not compiled, and so no feedback vector allocated yet.
   CHECK(!f->shared()->is_compiled());
+  CHECK_EQ(0, f->shared()->feedback_vector()->Slots());
+  CHECK_EQ(0, f->shared()->feedback_vector()->ICSlots());
 
   CompileRun("morphing_call();");
 
-  // The vector should have the same size despite the new scoping.
-  CHECK_EQ(expected_count, f->shared()->feedback_vector()->length());
+  // Now a feedback vector is allocated.
   CHECK(f->shared()->is_compiled());
+  int expected_slots = 0;
+  int expected_ic_slots = FLAG_vector_ics ? 2 : 1;
+  CHECK_EQ(expected_slots, f->shared()->feedback_vector()->Slots());
+  CHECK_EQ(expected_ic_slots, f->shared()->feedback_vector()->ICSlots());
 }
 
 
diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
index 8d429d2..0e2dd91 100644
--- a/test/cctest/test-cpu-profiler.cc
+++ b/test/cctest/test-cpu-profiler.cc
@@ -1064,6 +1064,104 @@
 }
 
 
+// This tests checks distribution of the samples through the source lines.
+TEST(TickLines) {
+  CcTest::InitializeVM();
+  LocalContext env;
+  i::FLAG_turbo_source_positions = true;
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+  i::HandleScope scope(isolate);
+
+  i::EmbeddedVector<char, 512> script;
+
+  const char* func_name = "func";
+  i::SNPrintF(script,
+              "function %s() {\n"
+              "  var n = 0;\n"
+              "  var m = 100*100;\n"
+              "  while (m > 1) {\n"
+              "    m--;\n"
+              "    n += m * m * m;\n"
+              "  }\n"
+              "}\n"
+              "%s();\n",
+              func_name, func_name);
+
+  CompileRun(script.start());
+
+  i::Handle<i::JSFunction> func = v8::Utils::OpenHandle(
+      *v8::Local<v8::Function>::Cast((*env)->Global()->Get(v8_str(func_name))));
+  CHECK_NE(NULL, func->shared());
+  CHECK_NE(NULL, func->shared()->code());
+  i::Code* code = NULL;
+  if (func->code()->is_optimized_code()) {
+    code = func->code();
+  } else {
+    CHECK(func->shared()->code() == func->code() || !i::FLAG_crankshaft);
+    code = func->shared()->code();
+  }
+  CHECK_NE(NULL, code);
+  i::Address code_address = code->instruction_start();
+  CHECK_NE(NULL, code_address);
+
+  CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
+  profiles->StartProfiling("", false);
+  ProfileGenerator generator(profiles);
+  ProfilerEventsProcessor* processor = new ProfilerEventsProcessor(
+      &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100));
+  processor->Start();
+  CpuProfiler profiler(isolate, profiles, &generator, processor);
+
+  // Enqueue code creation events.
+  i::Handle<i::String> str = factory->NewStringFromAsciiChecked(func_name);
+  int line = 1;
+  int column = 1;
+  profiler.CodeCreateEvent(i::Logger::FUNCTION_TAG, code, func->shared(), NULL,
+                           *str, line, column);
+
+  // Enqueue a tick event to enable code events processing.
+  EnqueueTickSampleEvent(processor, code_address);
+
+  processor->StopSynchronously();
+
+  CpuProfile* profile = profiles->StopProfiling("");
+  CHECK_NE(NULL, profile);
+
+  // Check the state of profile generator.
+  CodeEntry* func_entry = generator.code_map()->FindEntry(code_address);
+  CHECK_NE(NULL, func_entry);
+  CHECK_EQ(func_name, func_entry->name());
+  const i::JITLineInfoTable* line_info = func_entry->line_info();
+  CHECK_NE(NULL, line_info);
+  CHECK(!line_info->empty());
+
+  // Check the hit source lines using V8 Public APIs.
+  const i::ProfileTree* tree = profile->top_down();
+  ProfileNode* root = tree->root();
+  CHECK_NE(NULL, root);
+  ProfileNode* func_node = root->FindChild(func_entry);
+  CHECK_NE(NULL, func_node);
+
+  // Add 10 faked ticks to source line #5.
+  int hit_line = 5;
+  int hit_count = 10;
+  for (int i = 0; i < hit_count; i++) func_node->IncrementLineTicks(hit_line);
+
+  unsigned int line_count = func_node->GetHitLineCount();
+  CHECK_EQ(2, line_count);  // Expect two hit source lines - #1 and #5.
+  ScopedVector<v8::CpuProfileNode::LineTick> entries(line_count);
+  CHECK(func_node->GetLineTicks(&entries[0], line_count));
+  int value = 0;
+  for (int i = 0; i < entries.length(); i++)
+    if (entries[i].line == hit_line) {
+      value = entries[i].hit_count;
+      break;
+    }
+  CHECK_EQ(hit_count, value);
+}
+
+
 static const char* call_function_test_source = "function bar(iterations) {\n"
 "}\n"
 "function start(duration) {\n"
diff --git a/test/cctest/test-dataflow.cc b/test/cctest/test-dataflow.cc
deleted file mode 100644
index 43d950d..0000000
--- a/test/cctest/test-dataflow.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <stdlib.h>
-
-#include "src/v8.h"
-
-#include "src/data-flow.h"
-#include "test/cctest/cctest.h"
-
-using namespace v8::internal;
-
-TEST(BitVector) {
-  Zone zone(CcTest::i_isolate());
-  {
-    BitVector v(15, &zone);
-    v.Add(1);
-    CHECK(v.Contains(1));
-    v.Remove(0);
-    CHECK(!v.Contains(0));
-    v.Add(0);
-    v.Add(1);
-    BitVector w(15, &zone);
-    w.Add(1);
-    v.Intersect(w);
-    CHECK(!v.Contains(0));
-    CHECK(v.Contains(1));
-  }
-
-  {
-    BitVector v(64, &zone);
-    v.Add(27);
-    v.Add(30);
-    v.Add(31);
-    v.Add(33);
-    BitVector::Iterator iter(&v);
-    CHECK_EQ(27, iter.Current());
-    iter.Advance();
-    CHECK_EQ(30, iter.Current());
-    iter.Advance();
-    CHECK_EQ(31, iter.Current());
-    iter.Advance();
-    CHECK_EQ(33, iter.Current());
-    iter.Advance();
-    CHECK(iter.Done());
-  }
-
-  {
-    BitVector v(15, &zone);
-    v.Add(0);
-    BitVector w(15, &zone);
-    w.Add(1);
-    v.Union(w);
-    CHECK(v.Contains(0));
-    CHECK(v.Contains(1));
-  }
-
-  {
-    BitVector v(15, &zone);
-    v.Add(0);
-    BitVector w(15, &zone);
-    w = v;
-    CHECK(w.Contains(0));
-    w.Add(1);
-    BitVector u(w, &zone);
-    CHECK(u.Contains(0));
-    CHECK(u.Contains(1));
-    v.Union(w);
-    CHECK(v.Contains(0));
-    CHECK(v.Contains(1));
-  }
-
-  {
-    BitVector v(35, &zone);
-    v.Add(0);
-    BitVector w(35, &zone);
-    w.Add(33);
-    v.Union(w);
-    CHECK(v.Contains(0));
-    CHECK(v.Contains(33));
-  }
-
-  {
-    BitVector v(35, &zone);
-    v.Add(32);
-    v.Add(33);
-    BitVector w(35, &zone);
-    w.Add(33);
-    v.Intersect(w);
-    CHECK(!v.Contains(32));
-    CHECK(v.Contains(33));
-    BitVector r(35, &zone);
-    r.CopyFrom(v);
-    CHECK(!r.Contains(32));
-    CHECK(r.Contains(33));
-  }
-}
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index 2f0674a..c3c65fd 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -621,7 +621,7 @@
         last_function_hit[0] = '\0';
       } else {
         CHECK(result->IsString());
-        v8::Handle<v8::String> function_name(result->ToString());
+        v8::Handle<v8::String> function_name(result.As<v8::String>());
         function_name->WriteUtf8(last_function_hit);
       }
     }
@@ -656,7 +656,7 @@
         last_script_name_hit[0] = '\0';
       } else {
         CHECK(result->IsString());
-        v8::Handle<v8::String> script_name(result->ToString());
+        v8::Handle<v8::String> script_name(result.As<v8::String>());
         script_name->WriteUtf8(last_script_name_hit);
       }
     }
@@ -775,7 +775,7 @@
       v8::Handle<v8::Value> result =
           evaluate_check_function->Call(exec_state, argc, argv);
       if (!result->IsTrue()) {
-        v8::String::Utf8Value utf8(checks[i].expected->ToString());
+        v8::String::Utf8Value utf8(checks[i].expected);
         V8_Fatal(__FILE__, __LINE__, "%s != %s", checks[i].expr, *utf8);
       }
     }
@@ -849,7 +849,7 @@
     v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
                                                              argc, argv);
     CHECK(result->IsString());
-    v8::String::Utf8Value function_name(result->ToString());
+    v8::String::Utf8Value function_name(result->ToString(CcTest::isolate()));
     CHECK_EQ(1, StrLength(*function_name));
     CHECK_EQ((*function_name)[0],
               expected_step_sequence[break_point_hit_count]);
@@ -2860,7 +2860,7 @@
   foo->Call(env->Global(), kArgc, args);
 
   // With stepping all break locations are hit.
-  CHECK_EQ(35, break_point_hit_count);
+  CHECK_EQ(45, break_point_hit_count);
 
   v8::Debug::SetDebugEventListener(NULL);
   CheckDebuggerUnloaded();
@@ -2908,7 +2908,7 @@
   foo->Call(env->Global(), kArgc, args);
 
   // With stepping all break locations are hit.
-  CHECK_EQ(34, break_point_hit_count);
+  CHECK_EQ(44, break_point_hit_count);
 
   v8::Debug::SetDebugEventListener(NULL);
   CheckDebuggerUnloaded();
@@ -2952,7 +2952,7 @@
   foo->Call(env->Global(), 0, NULL);
 
   // With stepping all break locations are hit.
-  CHECK_EQ(55, break_point_hit_count);
+  CHECK_EQ(65, break_point_hit_count);
 
   v8::Debug::SetDebugEventListener(NULL);
   CheckDebuggerUnloaded();
@@ -2995,9 +2995,7 @@
 
 
 // Test of the stepping mechanism for named load in a loop.
-TEST(DebugStepNamedStoreLoop) {
-  DoDebugStepNamedStoreLoop(24);
-}
+TEST(DebugStepNamedStoreLoop) { DoDebugStepNamedStoreLoop(34); }
 
 
 // Test the stepping mechanism with different ICs.
@@ -3330,14 +3328,14 @@
   break_point_hit_count = 0;
   v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
   foo->Call(env->Global(), argc, argv_10);
-  CHECK_EQ(23, break_point_hit_count);
+  CHECK_EQ(45, break_point_hit_count);
 
   // Looping 100 times.
   step_action = StepIn;
   break_point_hit_count = 0;
   v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
   foo->Call(env->Global(), argc, argv_100);
-  CHECK_EQ(203, break_point_hit_count);
+  CHECK_EQ(405, break_point_hit_count);
 
   // Get rid of the debug event listener.
   v8::Debug::SetDebugEventListener(NULL);
@@ -3381,7 +3379,7 @@
   v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
   result = foo->Call(env->Global(), argc, argv_10);
   CHECK_EQ(5, result->Int32Value());
-  CHECK_EQ(52, break_point_hit_count);
+  CHECK_EQ(62, break_point_hit_count);
 
   // Looping 100 times.
   step_action = StepIn;
@@ -3389,7 +3387,7 @@
   v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
   result = foo->Call(env->Global(), argc, argv_100);
   CHECK_EQ(50, result->Int32Value());
-  CHECK_EQ(457, break_point_hit_count);
+  CHECK_EQ(557, break_point_hit_count);
 
   // Get rid of the debug event listener.
   v8::Debug::SetDebugEventListener(NULL);
@@ -3434,7 +3432,7 @@
   v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
   result = foo->Call(env->Global(), argc, argv_10);
   CHECK_EQ(9, result->Int32Value());
-  CHECK_EQ(55, break_point_hit_count);
+  CHECK_EQ(64, break_point_hit_count);
 
   // Looping 100 times.
   step_action = StepIn;
@@ -3442,7 +3440,7 @@
   v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
   result = foo->Call(env->Global(), argc, argv_100);
   CHECK_EQ(99, result->Int32Value());
-  CHECK_EQ(505, break_point_hit_count);
+  CHECK_EQ(604, break_point_hit_count);
 
   // Get rid of the debug event listener.
   v8::Debug::SetDebugEventListener(NULL);
@@ -3473,7 +3471,7 @@
   step_action = StepIn;
   break_point_hit_count = 0;
   foo->Call(env->Global(), 0, NULL);
-  CHECK_EQ(6, break_point_hit_count);
+  CHECK_EQ(8, break_point_hit_count);
 
   // Create a function for testing stepping. Run it to allow it to get
   // optimized.
@@ -3490,7 +3488,7 @@
   step_action = StepIn;
   break_point_hit_count = 0;
   foo->Call(env->Global(), 0, NULL);
-  CHECK_EQ(8, break_point_hit_count);
+  CHECK_EQ(10, break_point_hit_count);
 
   // Get rid of the debug event listener.
   v8::Debug::SetDebugEventListener(NULL);
@@ -4352,9 +4350,10 @@
 }
 
 
-static void NamedGetter(v8::Local<v8::String> name,
+static void NamedGetter(v8::Local<v8::Name> name,
                         const v8::PropertyCallbackInfo<v8::Value>& info) {
-  v8::String::Utf8Value n(name);
+  if (name->IsSymbol()) return;
+  v8::String::Utf8Value n(v8::Local<v8::String>::Cast(name));
   if (strcmp(*n, "a") == 0) {
     info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "AA"));
     return;
@@ -4387,26 +4386,26 @@
 
   // Create object with named interceptor.
   v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
-  named->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
+  named->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      NamedGetter, NULL, NULL, NULL, NamedEnum));
   env->Global()->Set(
       v8::String::NewFromUtf8(isolate, "intercepted_named"),
       named->NewInstance());
 
   // Create object with indexed interceptor.
   v8::Handle<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New(isolate);
-  indexed->SetIndexedPropertyHandler(IndexedGetter,
-                                     NULL,
-                                     NULL,
-                                     NULL,
-                                     IndexedEnum);
+  indexed->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      IndexedGetter, NULL, NULL, NULL, IndexedEnum));
   env->Global()->Set(
       v8::String::NewFromUtf8(isolate, "intercepted_indexed"),
       indexed->NewInstance());
 
   // Create object with both named and indexed interceptor.
   v8::Handle<v8::ObjectTemplate> both = v8::ObjectTemplate::New(isolate);
-  both->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
-  both->SetIndexedPropertyHandler(IndexedGetter, NULL, NULL, NULL, IndexedEnum);
+  both->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      NamedGetter, NULL, NULL, NULL, NamedEnum));
+  both->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      IndexedGetter, NULL, NULL, NULL, IndexedEnum));
   env->Global()->Set(
       v8::String::NewFromUtf8(isolate, "intercepted_both"),
       both->NewInstance());
@@ -5264,6 +5263,7 @@
 
     CompileRun(source);
   }
+  threaded_debugging_barriers.barrier_4.Wait();
   isolate_->Dispose();
 }
 
@@ -5285,6 +5285,7 @@
   threaded_debugging_barriers.barrier_2.Wait();
   v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer));
   v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer));
+  threaded_debugging_barriers.barrier_4.Wait();
 }
 
 
@@ -5388,6 +5389,7 @@
     breakpoints_barriers->barrier_2.Wait();
     CompileRun(source_2);
   }
+  breakpoints_barriers->barrier_4.Wait();
   isolate_->Dispose();
 }
 
@@ -5503,6 +5505,7 @@
   CHECK_EQ(116, evaluate_int_result);
   // 9: Continue evaluation of source2, reach end.
   v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_8, buffer));
+  breakpoints_barriers->barrier_4.Wait();
 }
 
 
@@ -6157,7 +6160,8 @@
         last_function_hit[0] = '\0';
       } else {
         CHECK(result->IsString());
-        v8::Handle<v8::String> function_name(result->ToString());
+        v8::Handle<v8::String> function_name(
+            result->ToString(CcTest::isolate()));
         function_name->WriteUtf8(last_function_hit);
       }
     }
@@ -7040,7 +7044,8 @@
       if (!result->IsUndefined()) {
         char fn[80];
         CHECK(result->IsString());
-        v8::Handle<v8::String> function_name(result->ToString());
+        v8::Handle<v8::String> function_name(
+            result->ToString(CcTest::isolate()));
         function_name->WriteUtf8(fn);
         if (strcmp(fn, "bar") == 0) {
           i::Deoptimizer::DeoptimizeAll(CcTest::i_isolate());
@@ -7105,12 +7110,12 @@
         v8::Handle<v8::Value> result =
             frame_function_name->Call(exec_state, argc, argv);
         CHECK(result->IsString());
-        v8::Handle<v8::String> function_name(result->ToString());
+        v8::Handle<v8::String> function_name(result->ToString(isolate));
         CHECK(function_name->Equals(v8::String::NewFromUtf8(isolate, "loop")));
         // Get the name of the first argument in frame i.
         result = frame_argument_name->Call(exec_state, argc, argv);
         CHECK(result->IsString());
-        v8::Handle<v8::String> argument_name(result->ToString());
+        v8::Handle<v8::String> argument_name(result->ToString(isolate));
         CHECK(argument_name->Equals(v8::String::NewFromUtf8(isolate, "count")));
         // Get the value of the first argument in frame i. If the
         // funtion is optimized the value will be undefined, otherwise
@@ -7123,7 +7128,7 @@
         // Get the name of the first local variable.
         result = frame_local_name->Call(exec_state, argc, argv);
         CHECK(result->IsString());
-        v8::Handle<v8::String> local_name(result->ToString());
+        v8::Handle<v8::String> local_name(result->ToString(isolate));
         CHECK(local_name->Equals(v8::String::NewFromUtf8(isolate, "local")));
         // Get the value of the first local variable. If the function
         // is optimized the value will be undefined, otherwise it will
@@ -7518,3 +7523,159 @@
   CompileRun("while (true);");
   CHECK(try_catch.HasTerminated());
 }
+
+
+static void DebugEventExpectNoException(
+    const v8::Debug::EventDetails& event_details) {
+  v8::DebugEvent event = event_details.GetEvent();
+  CHECK_NE(v8::Exception, event);
+}
+
+
+static void TryCatchWrappedThrowCallback(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  v8::TryCatch try_catch;
+  CompileRun("throw 'rejection';");
+  CHECK(try_catch.HasCaught());
+}
+
+
+TEST(DebugPromiseInterceptedByTryCatch) {
+  DebugLocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Debug::SetDebugEventListener(&DebugEventExpectNoException);
+  ChangeBreakOnException(false, true);
+
+  v8::Handle<v8::FunctionTemplate> fun =
+      v8::FunctionTemplate::New(isolate, TryCatchWrappedThrowCallback);
+  env->Global()->Set(v8_str("fun"), fun->GetFunction());
+
+  CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
+  CompileRun(
+      "var r;"
+      "p.chain(function() { r = 'resolved'; },"
+      "        function() { r = 'rejected'; });");
+  CHECK(CompileRun("r")->Equals(v8_str("resolved")));
+}
+
+
+static int exception_event_counter = 0;
+
+
+static void DebugEventCountException(
+    const v8::Debug::EventDetails& event_details) {
+  v8::DebugEvent event = event_details.GetEvent();
+  if (event == v8::Exception) exception_event_counter++;
+}
+
+
+static void ThrowCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
+  CompileRun("throw 'rejection';");
+}
+
+
+TEST(DebugPromiseRejectedByCallback) {
+  DebugLocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Debug::SetDebugEventListener(&DebugEventCountException);
+  ChangeBreakOnException(false, true);
+  exception_event_counter = 0;
+
+  v8::Handle<v8::FunctionTemplate> fun =
+      v8::FunctionTemplate::New(isolate, ThrowCallback);
+  env->Global()->Set(v8_str("fun"), fun->GetFunction());
+
+  CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
+  CompileRun(
+      "var r;"
+      "p.chain(function() { r = 'resolved'; },"
+      "        function(e) { r = 'rejected' + e; });");
+  CHECK(CompileRun("r")->Equals(v8_str("rejectedrejection")));
+  CHECK_EQ(1, exception_event_counter);
+}
+
+
+TEST(DebugBreakOnExceptionInObserveCallback) {
+  DebugLocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Debug::SetDebugEventListener(&DebugEventCountException);
+  // Break on uncaught exception
+  ChangeBreakOnException(false, true);
+  exception_event_counter = 0;
+
+  v8::Handle<v8::FunctionTemplate> fun =
+      v8::FunctionTemplate::New(isolate, ThrowCallback);
+  env->Global()->Set(v8_str("fun"), fun->GetFunction());
+
+  CompileRun(
+      "var obj = {};"
+      "var callbackRan = false;"
+      "Object.observe(obj, function() {"
+      "   callbackRan = true;"
+      "   throw Error('foo');"
+      "});"
+      "obj.prop = 1");
+  CHECK(CompileRun("callbackRan")->BooleanValue());
+  CHECK_EQ(1, exception_event_counter);
+}
+
+
+static void DebugHarmonyScopingListener(
+    const v8::Debug::EventDetails& event_details) {
+  v8::DebugEvent event = event_details.GetEvent();
+  if (event != v8::Break) return;
+
+  int break_id = CcTest::i_isolate()->debug()->break_id();
+
+  char script[128];
+  i::Vector<char> script_vector(script, sizeof(script));
+  SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id);
+  ExpectInt32(script, 1);
+
+  SNPrintF(script_vector, "var frame = new FrameMirror(%d, 0);", break_id);
+  CompileRun(script);
+  ExpectInt32("frame.evaluate('x').value_", 1);
+  ExpectInt32("frame.evaluate('y').value_", 2);
+
+  CompileRun("var allScopes = frame.allScopes()");
+  ExpectInt32("allScopes.length", 2);
+
+  ExpectBoolean("allScopes[0].scopeType() === ScopeType.Script", true);
+
+  ExpectInt32("allScopes[0].scopeObject().value_.x", 1);
+
+  ExpectInt32("allScopes[0].scopeObject().value_.y", 2);
+
+  CompileRun("allScopes[0].setVariableValue('x', 5);");
+  CompileRun("allScopes[0].setVariableValue('y', 6);");
+  ExpectInt32("frame.evaluate('x + y').value_", 11);
+}
+
+
+TEST(DebugBreakInLexicalScopes) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_allow_natives_syntax = true;
+
+  DebugLocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Debug::SetDebugEventListener(DebugHarmonyScopingListener);
+
+  CompileRun(
+      "'use strict';            \n"
+      "let x = 1;               \n");
+  ExpectInt32(
+      "'use strict';            \n"
+      "let y = 2;               \n"
+      "debugger;                \n"
+      "x * y",
+      30);
+  ExpectInt32(
+      "x = 1; y = 2; \n"
+      "debugger;"
+      "x * y",
+      30);
+}
diff --git a/test/cctest/test-decls.cc b/test/cctest/test-decls.cc
index 34f0b69..06afdd2 100644
--- a/test/cctest/test-decls.cc
+++ b/test/cctest/test-decls.cc
@@ -70,9 +70,9 @@
   int query_count() const { return query_count_; }
 
  protected:
-  virtual v8::Handle<Value> Get(Local<String> key);
-  virtual v8::Handle<Value> Set(Local<String> key, Local<Value> value);
-  virtual v8::Handle<Integer> Query(Local<String> key);
+  virtual v8::Handle<Value> Get(Local<Name> key);
+  virtual v8::Handle<Value> Set(Local<Name> key, Local<Value> value);
+  virtual v8::Handle<Integer> Query(Local<Name> key);
 
   void InitializeIfNeeded();
 
@@ -88,12 +88,11 @@
 
   // The handlers are called as static functions that forward
   // to the instance specific virtual methods.
-  static void HandleGet(Local<String> key,
+  static void HandleGet(Local<Name> key,
                         const v8::PropertyCallbackInfo<v8::Value>& info);
-  static void HandleSet(Local<String> key,
-                        Local<Value> value,
+  static void HandleSet(Local<Name> key, Local<Value> value,
                         const v8::PropertyCallbackInfo<v8::Value>& info);
-  static void HandleQuery(Local<String> key,
+  static void HandleQuery(Local<Name> key,
                           const v8::PropertyCallbackInfo<v8::Integer>& info);
 
   v8::Isolate* isolate() const { return CcTest::isolate(); }
@@ -122,11 +121,8 @@
   HandleScope scope(isolate);
   Local<FunctionTemplate> function = FunctionTemplate::New(isolate);
   Local<Value> data = External::New(CcTest::isolate(), this);
-  GetHolder(function)->SetNamedPropertyHandler(&HandleGet,
-                                               &HandleSet,
-                                               &HandleQuery,
-                                               0, 0,
-                                               data);
+  GetHolder(function)->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      &HandleGet, &HandleSet, &HandleQuery, 0, 0, data));
   Local<Context> context = Context::New(isolate,
                                         0,
                                         function->InstanceTemplate(),
@@ -178,8 +174,7 @@
 
 
 void DeclarationContext::HandleGet(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
   DeclarationContext* context = GetInstance(info.Data());
   context->get_count_++;
   info.GetReturnValue().Set(context->Get(key));
@@ -187,8 +182,7 @@
 
 
 void DeclarationContext::HandleSet(
-    Local<String> key,
-    Local<Value> value,
+    Local<Name> key, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   DeclarationContext* context = GetInstance(info.Data());
   context->set_count_++;
@@ -197,8 +191,7 @@
 
 
 void DeclarationContext::HandleQuery(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   DeclarationContext* context = GetInstance(info.Data());
   context->query_count_++;
   info.GetReturnValue().Set(context->Query(key));
@@ -211,18 +204,17 @@
 }
 
 
-v8::Handle<Value> DeclarationContext::Get(Local<String> key) {
+v8::Handle<Value> DeclarationContext::Get(Local<Name> key) {
   return v8::Handle<Value>();
 }
 
 
-v8::Handle<Value> DeclarationContext::Set(Local<String> key,
-                                          Local<Value> value) {
+v8::Handle<Value> DeclarationContext::Set(Local<Name> key, Local<Value> value) {
   return v8::Handle<Value>();
 }
 
 
-v8::Handle<Integer> DeclarationContext::Query(Local<String> key) {
+v8::Handle<Integer> DeclarationContext::Query(Local<Name> key) {
   return v8::Handle<Integer>();
 }
 
@@ -272,7 +264,7 @@
 
 class AbsentPropertyContext: public DeclarationContext {
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     return v8::Handle<Integer>();
   }
 };
@@ -336,7 +328,7 @@
   AppearingPropertyContext() : state_(DECLARE) { }
 
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     switch (state_) {
       case DECLARE:
         // Force declaration by returning that the
@@ -405,7 +397,7 @@
  public:
   ExistsInPrototypeContext() { InitializeIfNeeded(); }
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     // Let it seem that the property exists in the prototype object.
     return Integer::New(isolate(), v8::None);
   }
@@ -464,7 +456,7 @@
 
 class AbsentInPrototypeContext: public DeclarationContext {
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     // Let it seem that the property is absent in the prototype object.
     return Handle<Integer>();
   }
@@ -499,7 +491,7 @@
   }
 
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     // Let it seem that the property exists in the hidden prototype object.
     return Integer::New(isolate(), v8::None);
   }
@@ -644,34 +636,212 @@
 }
 
 
-TEST(CrossScriptReferencesHarmony) {
+TEST(CrossScriptReferences_Simple) {
+  i::FLAG_harmony_scoping = true;
   i::FLAG_use_strict = true;
+
+  v8::Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+
+  {
+    SimpleContext context;
+    context.Check("let x = 1; x", EXPECT_RESULT, Number::New(isolate, 1));
+    context.Check("let x = 5; x", EXPECT_EXCEPTION);
+  }
+}
+
+
+TEST(CrossScriptReferences_Simple2) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_use_strict = true;
+
+  v8::Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+
+  for (int k = 0; k < 100; k++) {
+    SimpleContext context;
+    bool cond = (k % 2) == 0;
+    if (cond) {
+      context.Check("let x = 1; x", EXPECT_RESULT, Number::New(isolate, 1));
+      context.Check("let z = 4; z", EXPECT_RESULT, Number::New(isolate, 4));
+    } else {
+      context.Check("let z = 1; z", EXPECT_RESULT, Number::New(isolate, 1));
+      context.Check("let x = 4; x", EXPECT_RESULT, Number::New(isolate, 4));
+    }
+    context.Check("let y = 2; x", EXPECT_RESULT,
+                  Number::New(isolate, cond ? 1 : 4));
+  }
+}
+
+
+TEST(CrossScriptReferencesHarmony) {
   i::FLAG_harmony_scoping = true;
   i::FLAG_harmony_modules = true;
 
   v8::Isolate* isolate = CcTest::isolate();
   HandleScope scope(isolate);
 
+  // Check that simple cross-script global scope access works.
   const char* decs[] = {
-    "var x = 1; x", "x", "this.x",
-    "function x() { return 1 }; x()", "x()", "this.x()",
-    "let x = 1; x", "x", "this.x",
-    "const x = 1; x", "x", "this.x",
-    "module x { export let a = 1 }; x.a", "x.a", "this.x.a",
+    "'use strict'; var x = 1; x", "x",
+    "'use strict'; function x() { return 1 }; x()", "x()",
+    "'use strict'; let x = 1; x", "x",
+    "'use strict'; const x = 1; x", "x",
+    "'use strict'; module x { export let a = 1 }; x.a", "x.a",
     NULL
   };
 
-  for (int i = 0; decs[i] != NULL; i += 3) {
+  for (int i = 0; decs[i] != NULL; i += 2) {
     SimpleContext context;
     context.Check(decs[i], EXPECT_RESULT, Number::New(isolate, 1));
     context.Check(decs[i+1], EXPECT_RESULT, Number::New(isolate, 1));
-    // TODO(rossberg): The current ES6 draft spec does not reflect lexical
-    // bindings on the global object. However, this will probably change, in
-    // which case we reactivate the following test.
-    if (i/3 < 2) {
-      context.Check(decs[i+2], EXPECT_RESULT, Number::New(isolate, 1));
-    }
   }
+
+  // Check that cross-script global scope access works with late declarations.
+  {
+    SimpleContext context;
+    context.Check("function d0() { return x0 }",  // dynamic lookup
+                  EXPECT_RESULT, Undefined(isolate));
+    context.Check("this.x0 = -1;"
+                  "d0()",
+                  EXPECT_RESULT, Number::New(isolate, -1));
+    context.Check("'use strict';"
+                  "function f0() { let y = 10; return x0 + y }"
+                  "function g0() { let y = 10; return eval('x0 + y') }"
+                  "function h0() { let y = 10; return (1,eval)('x0') + y }"
+                  "x0 + f0() + g0() + h0()",
+                  EXPECT_RESULT, Number::New(isolate, 26));
+
+    context.Check("'use strict';"
+                  "let x1 = 1;"
+                  "function f1() { let y = 10; return x1 + y }"
+                  "function g1() { let y = 10; return eval('x1 + y') }"
+                  "function h1() { let y = 10; return (1,eval)('x1') + y }"
+                  "function i1() { "
+                  "  let y = 10; return (typeof x2 === 'undefined' ? 0 : 2) + y"
+                  "}"
+                  "function j1() { let y = 10; return eval('x2 + y') }"
+                  "function k1() { let y = 10; return (1,eval)('x2') + y }"
+                  "function cl() { "
+                  "  let y = 10; "
+                  "  return { "
+                  "    f: function(){ return x1 + y },"
+                  "    g: function(){ return eval('x1 + y') },"
+                  "    h: function(){ return (1,eval)('x1') + y },"
+                  "    i: function(){"
+                  "      return (typeof x2 == 'undefined' ? 0 : 2) + y"
+                  "    },"
+                  "    j: function(){ return eval('x2 + y') },"
+                  "    k: function(){ return (1,eval)('x2') + y },"
+                  "  }"
+                  "}"
+                  "let o = cl();"
+                  "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("o.f() + o.g() + o.h();",
+                  EXPECT_RESULT, Number::New(isolate, 33));
+    context.Check("i1() + o.i();",
+                  EXPECT_RESULT, Number::New(isolate, 20));
+
+    context.Check("'use strict';"
+                  "let x2 = 2;"
+                  "function f2() { let y = 20; return x2 + y }"
+                  "function g2() { let y = 20; return eval('x2 + y') }"
+                  "function h2() { let y = 20; return (1,eval)('x2') + y }"
+                  "function i2() { let y = 20; return x1 + y }"
+                  "function j2() { let y = 20; return eval('x1 + y') }"
+                  "function k2() { let y = 20; return (1,eval)('x1') + y }"
+                  "x2 + eval('x2') + (1,eval)('x2') + f2() + g2() + h2();",
+                  EXPECT_RESULT, Number::New(isolate, 72));
+    context.Check("x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("i1() + j1() + k1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("i2() + j2() + k2();",
+                  EXPECT_RESULT, Number::New(isolate, 63));
+    context.Check("o.f() + o.g() + o.h();",
+                  EXPECT_RESULT, Number::New(isolate, 33));
+    context.Check("o.i() + o.j() + o.k();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("i1() + o.i();",
+                  EXPECT_RESULT, Number::New(isolate, 24));
+
+    context.Check("'use strict';"
+                  "let x0 = 100;"
+                  "x0 + eval('x0') + (1,eval)('x0') + "
+                  "    d0() + f0() + g0() + h0();",
+                  EXPECT_RESULT, Number::New(isolate, 730));
+    context.Check("x0 + eval('x0') + (1,eval)('x0') + "
+                  "    d0() + f0() + g0() + h0();",
+                  EXPECT_RESULT, Number::New(isolate, 730));
+    context.Check("delete this.x0;"
+                  "x0 + eval('x0') + (1,eval)('x0') + "
+                  "    d0() + f0() + g0() + h0();",
+                  EXPECT_RESULT, Number::New(isolate, 730));
+    context.Check("this.x1 = 666;"
+                  "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("delete this.x1;"
+                  "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+  }
+
+  // Check that caching does respect scopes.
+  {
+    SimpleContext context;
+    const char* script1 = "(function(){ return y1 })()";
+    const char* script2 = "(function(){ return y2 })()";
+
+    context.Check(script1, EXPECT_EXCEPTION);
+    context.Check("this.y1 = 1; this.y2 = 2; 0;",
+                  EXPECT_RESULT, Number::New(isolate, 0));
+    context.Check(script1,
+                  EXPECT_RESULT, Number::New(isolate, 1));
+    context.Check("'use strict'; let y1 = 3; 0;",
+                  EXPECT_RESULT, Number::New(isolate, 0));
+    context.Check(script1,
+                  EXPECT_RESULT, Number::New(isolate, 3));
+    context.Check("y1 = 4;",
+                  EXPECT_RESULT, Number::New(isolate, 4));
+    context.Check(script1,
+                  EXPECT_RESULT, Number::New(isolate, 4));
+
+    context.Check(script2,
+                  EXPECT_RESULT, Number::New(isolate, 2));
+    context.Check("'use strict'; let y2 = 5; 0;",
+                  EXPECT_RESULT, Number::New(isolate, 0));
+    context.Check(script1,
+                  EXPECT_RESULT, Number::New(isolate, 4));
+    context.Check(script2,
+                  EXPECT_RESULT, Number::New(isolate, 5));
+  }
+}
+
+
+TEST(GlobalLexicalOSR) {
+  i::FLAG_use_strict = true;
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_harmony_modules = true;
+
+  v8::Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+  SimpleContext context;
+
+  context.Check("'use strict';"
+                "let x = 1; x;",
+                EXPECT_RESULT, Number::New(isolate, 1));
+  context.Check("'use strict';"
+                "let y = 2*x;"
+                "++x;"
+                "let z = 0;"
+                "const limit = 100000;"
+                "for (var i = 0; i < limit; ++i) {"
+                "  z += x + y;"
+                "}"
+                "z;",
+                EXPECT_RESULT, Number::New(isolate, 400000));
 }
 
 
@@ -704,12 +874,280 @@
       SimpleContext context;
       context.Check(firsts[i], EXPECT_RESULT,
                     Number::New(CcTest::isolate(), 1));
-      // TODO(rossberg): All tests should actually be errors in Harmony,
-      // but we currently do not detect the cases where the first declaration
-      // is not lexical.
-      context.Check(seconds[j],
-                    i < 2 ? EXPECT_RESULT : EXPECT_ERROR,
-                    Number::New(CcTest::isolate(), 2));
+      bool success_case = i < 2 && j < 2;
+      Local<Value> success_result;
+      if (success_case) success_result = Number::New(CcTest::isolate(), 2);
+
+      context.Check(seconds[j], success_case ? EXPECT_RESULT : EXPECT_EXCEPTION,
+                    success_result);
     }
   }
 }
+
+
+TEST(CrossScriptDynamicLookup) {
+  i::FLAG_harmony_scoping = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    Local<String> undefined_string = String::NewFromUtf8(
+        CcTest::isolate(), "undefined", String::kInternalizedString);
+    Local<String> number_string = String::NewFromUtf8(
+        CcTest::isolate(), "number", String::kInternalizedString);
+
+    context.Check(
+        "function f(o) { with(o) { return x; } }"
+        "function g(o) { with(o) { x = 15; } }"
+        "function h(o) { with(o) { return typeof x; } }",
+        EXPECT_RESULT, Undefined(CcTest::isolate()));
+    context.Check("h({})", EXPECT_RESULT, undefined_string);
+    context.Check(
+        "'use strict';"
+        "let x = 1;"
+        "f({})",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+    context.Check(
+        "'use strict';"
+        "g({});0",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
+    context.Check("f({})", EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check("h({})", EXPECT_RESULT, number_string);
+  }
+}
+
+
+TEST(CrossScriptGlobal) {
+  i::FLAG_harmony_scoping = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+  {
+    SimpleContext context;
+
+    context.Check(
+        "var global = this;"
+        "global.x = 255;"
+        "x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 255));
+    context.Check(
+        "'use strict';"
+        "let x = 1;"
+        "global.x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 255));
+    context.Check("global.x = 15; x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 1));
+    context.Check("x = 221; global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 15));
+    context.Check(
+        "z = 15;"
+        "function f() { return z; };"
+        "for (var k = 0; k < 3; k++) { f(); }"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check(
+        "'use strict';"
+        "let z = 5; f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    context.Check(
+        "function f() { konst = 10; return konst; };"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 10));
+    context.Check(
+        "'use strict';"
+        "const konst = 255;"
+        "f()",
+        EXPECT_EXCEPTION);
+  }
+}
+
+
+TEST(CrossScriptStaticLookupUndeclared) {
+  i::FLAG_harmony_scoping = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    Local<String> undefined_string = String::NewFromUtf8(
+        CcTest::isolate(), "undefined", String::kInternalizedString);
+    Local<String> number_string = String::NewFromUtf8(
+        CcTest::isolate(), "number", String::kInternalizedString);
+
+    context.Check(
+        "function f(o) { return x; }"
+        "function g(v) { x = v; }"
+        "function h(o) { return typeof x; }",
+        EXPECT_RESULT, Undefined(CcTest::isolate()));
+    context.Check("h({})", EXPECT_RESULT, undefined_string);
+    context.Check(
+        "'use strict';"
+        "let x = 1;"
+        "f({})",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+    context.Check(
+        "'use strict';"
+        "g(15);x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check("h({})", EXPECT_RESULT, number_string);
+    context.Check("f({})", EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check("h({})", EXPECT_RESULT, number_string);
+  }
+}
+
+
+TEST(CrossScriptLoadICs) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_allow_natives_syntax = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    context.Check(
+        "x = 15;"
+        "function f() { return x; }"
+        "function g() { return x; }"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    for (int k = 0; k < 3; k++) {
+      context.Check("g()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    }
+    for (int k = 0; k < 3; k++) {
+      context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(g); g()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 5));
+    context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 5));
+  }
+  {
+    SimpleContext context;
+    context.Check(
+        "x = 15;"
+        "function f() { return x; }"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 15));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 5));
+  }
+}
+
+
+TEST(CrossScriptStoreICs) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_allow_natives_syntax = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    context.Check(
+        "var global = this;"
+        "x = 15;"
+        "function f(v) { x = v; }"
+        "function g(v) { x = v; }"
+        "f(10); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 10));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f(7); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 7));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    for (int k = 0; k < 3; k++) {
+      context.Check("g(31); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 31));
+    }
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f(32); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 32));
+    }
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    context.Check("%OptimizeFunctionOnNextCall(g); g(18); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 18));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    context.Check("%OptimizeFunctionOnNextCall(f); f(33); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 33));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+  }
+  {
+    SimpleContext context;
+    context.Check(
+        "var global = this;"
+        "x = 15;"
+        "function f(v) { x = v; }"
+        "f(10); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 10));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f(18); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 18));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(f); f(20); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f(8); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 8));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f(13); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 13));
+    }
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+    context.Check("%OptimizeFunctionOnNextCall(f); f(41); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 41));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+  }
+}
+
+
+TEST(CrossScriptAssignmentToConst) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_allow_natives_syntax = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+
+    context.Check("function f() { x = 27; }", EXPECT_RESULT,
+                  Undefined(CcTest::isolate()));
+    context.Check("'use strict';const x = 1; x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 1));
+    context.Check("f();", EXPECT_EXCEPTION);
+    context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+    context.Check("f();", EXPECT_EXCEPTION);
+    context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+    context.Check("%OptimizeFunctionOnNextCall(f);f();", EXPECT_EXCEPTION);
+    context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+  }
+}
diff --git a/test/cctest/test-disasm-arm.cc b/test/cctest/test-disasm-arm.cc
index c1f6ce2..095c636 100644
--- a/test/cctest/test-disasm-arm.cc
+++ b/test/cctest/test-disasm-arm.cc
@@ -410,16 +410,40 @@
             "e6843895       pkhbt r3, r4, r5, lsl #17");
     COMPARE(pkhtb(r3, r4, Operand(r5, ASR, 17)),
             "e68438d5       pkhtb r3, r4, r5, asr #17");
-    COMPARE(uxtb(r9, Operand(r10, ROR, 0)),
-            "e6ef907a       uxtb r9, r10");
-    COMPARE(uxtb(r3, Operand(r4, ROR, 8)),
-            "e6ef3474       uxtb r3, r4, ror #8");
-    COMPARE(uxtab(r3, r4, Operand(r5, ROR, 8)),
-            "e6e43475       uxtab r3, r4, r5, ror #8");
-    COMPARE(uxtb16(r3, Operand(r4, ROR, 8)),
-            "e6cf3474       uxtb16 r3, r4, ror #8");
+
+    COMPARE(sxtb(r1, r7, 0, eq), "06af1077       sxtbeq r1, r7");
+    COMPARE(sxtb(r0, r0, 8, ne), "16af0470       sxtbne r0, r0, ror #8");
+    COMPARE(sxtb(r9, r10, 16), "e6af987a       sxtb r9, r10, ror #16");
+    COMPARE(sxtb(r4, r3, 24), "e6af4c73       sxtb r4, r3, ror #24");
+
+    COMPARE(sxtab(r3, r4, r5), "e6a43075       sxtab r3, r4, r5");
+
+    COMPARE(sxth(r5, r0), "e6bf5070       sxth r5, r0");
+    COMPARE(sxth(r5, r9, 8), "e6bf5479       sxth r5, r9, ror #8");
+    COMPARE(sxth(r5, r9, 16, hi), "86bf5879       sxthhi r5, r9, ror #16");
+    COMPARE(sxth(r8, r9, 24, cc), "36bf8c79       sxthcc r8, r9, ror #24");
+
+    COMPARE(sxtah(r3, r4, r5, 16), "e6b43875       sxtah r3, r4, r5, ror #16");
+
+    COMPARE(uxtb(r9, r10), "e6ef907a       uxtb r9, r10");
+    COMPARE(uxtb(r3, r4, 8), "e6ef3474       uxtb r3, r4, ror #8");
+
+    COMPARE(uxtab(r3, r4, r5, 8), "e6e43475       uxtab r3, r4, r5, ror #8");
+
+    COMPARE(uxtb16(r3, r4, 8), "e6cf3474       uxtb16 r3, r4, ror #8");
+
+    COMPARE(uxth(r9, r10), "e6ff907a       uxth r9, r10");
+    COMPARE(uxth(r3, r4, 8), "e6ff3474       uxth r3, r4, ror #8");
+
+    COMPARE(uxtah(r3, r4, r5, 24), "e6f43c75       uxtah r3, r4, r5, ror #24");
   }
 
+  COMPARE(smmla(r0, r1, r2, r3), "e7503211       smmla r0, r1, r2, r3");
+  COMPARE(smmla(r10, r9, r8, r7), "e75a7819       smmla r10, r9, r8, r7");
+
+  COMPARE(smmul(r0, r1, r2), "e750f211       smmul r0, r1, r2");
+  COMPARE(smmul(r8, r9, r10), "e758fa19       smmul r8, r9, r10");
+
   VERIFY_RUN();
 }
 
@@ -680,6 +704,30 @@
 }
 
 
+TEST(ARMv8_vrintX_disasm) {
+  SET_UP();
+
+  if (CpuFeatures::IsSupported(ARMv8)) {
+    COMPARE(vrinta(d0, d0), "feb80b40       vrinta.f64.f64 d0, d0");
+    COMPARE(vrinta(d2, d3), "feb82b43       vrinta.f64.f64 d2, d3");
+
+    COMPARE(vrintp(d0, d0), "feba0b40       vrintp.f64.f64 d0, d0");
+    COMPARE(vrintp(d2, d3), "feba2b43       vrintp.f64.f64 d2, d3");
+
+    COMPARE(vrintn(d0, d0), "feb90b40       vrintn.f64.f64 d0, d0");
+    COMPARE(vrintn(d2, d3), "feb92b43       vrintn.f64.f64 d2, d3");
+
+    COMPARE(vrintm(d0, d0), "febb0b40       vrintm.f64.f64 d0, d0");
+    COMPARE(vrintm(d2, d3), "febb2b43       vrintm.f64.f64 d2, d3");
+
+    COMPARE(vrintz(d0, d0), "eeb60bc0       vrintz.f64.f64 d0, d0");
+    COMPARE(vrintz(d2, d3, ne), "1eb62bc3       vrintzne.f64.f64 d2, d3");
+  }
+
+  VERIFY_RUN();
+}
+
+
 TEST(Neon) {
   SET_UP();
 
diff --git a/test/cctest/test-disasm-arm64.cc b/test/cctest/test-disasm-arm64.cc
index fb01347..208f1f5 100644
--- a/test/cctest/test-disasm-arm64.cc
+++ b/test/cctest/test-disasm-arm64.cc
@@ -1408,6 +1408,10 @@
   COMPARE(frintn(s31, s30), "frintn s31, s30");
   COMPARE(frintn(d12, d13), "frintn d12, d13");
   COMPARE(frintn(d31, d30), "frintn d31, d30");
+  COMPARE(frintp(s10, s11), "frintp s10, s11");
+  COMPARE(frintp(s31, s30), "frintp s31, s30");
+  COMPARE(frintp(d12, d13), "frintp d12, d13");
+  COMPARE(frintp(d31, d30), "frintp d31, d30");
   COMPARE(frintz(s10, s11), "frintz s10, s11");
   COMPARE(frintz(s31, s30), "frintz s31, s30");
   COMPARE(frintz(d12, d13), "frintz d12, d13");
diff --git a/test/cctest/test-disasm-ia32.cc b/test/cctest/test-disasm-ia32.cc
index 49088f6..a2eaa15 100644
--- a/test/cctest/test-disasm-ia32.cc
+++ b/test/cctest/test-disasm-ia32.cc
@@ -51,7 +51,7 @@
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   HandleScope scope(isolate);
-  v8::internal::byte buffer[2048];
+  v8::internal::byte buffer[4096];
   Assembler assm(isolate, buffer, sizeof buffer);
   DummyStaticFunction(NULL);  // just bloody use it (DELETE; debugging)
 
@@ -201,6 +201,12 @@
   __ rcl(edx, 7);
   __ rcr(edx, 1);
   __ rcr(edx, 7);
+  __ ror(edx, 1);
+  __ ror(edx, 6);
+  __ ror_cl(edx);
+  __ ror(Operand(ebx, ecx, times_4, 10000), 1);
+  __ ror(Operand(ebx, ecx, times_4, 10000), 6);
+  __ ror_cl(Operand(ebx, ecx, times_4, 10000));
   __ sar(edx, 1);
   __ sar(edx, 6);
   __ sar_cl(edx);
@@ -383,6 +389,8 @@
     // Move operation
     __ movaps(xmm0, xmm1);
     __ shufps(xmm0, xmm0, 0x0);
+    __ cvtsd2ss(xmm0, xmm1);
+    __ cvtsd2ss(xmm0, Operand(ebx, ecx, times_4, 10000));
 
     // logic operation
     __ andps(xmm0, xmm1);
@@ -393,6 +401,14 @@
     __ xorps(xmm0, Operand(ebx, ecx, times_4, 10000));
 
     // Arithmetic operation
+    __ addss(xmm1, xmm0);
+    __ addss(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ mulss(xmm1, xmm0);
+    __ mulss(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ subss(xmm1, xmm0);
+    __ subss(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ divss(xmm1, xmm0);
+    __ divss(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ addps(xmm1, xmm0);
     __ addps(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ subps(xmm1, xmm0);
@@ -401,10 +417,15 @@
     __ mulps(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ divps(xmm1, xmm0);
     __ divps(xmm1, Operand(ebx, ecx, times_4, 10000));
+
+    __ ucomiss(xmm0, xmm1);
+    __ ucomiss(xmm0, Operand(ebx, ecx, times_4, 10000));
   }
   {
     __ cvttss2si(edx, Operand(ebx, ecx, times_4, 10000));
     __ cvtsi2sd(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ cvtss2sd(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ cvtss2sd(xmm1, xmm0);
     __ movsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ movsd(Operand(ebx, ecx, times_4, 10000), xmm1);
     // 128 bit move instructions.
@@ -414,10 +435,13 @@
     __ movdqu(Operand(ebx, ecx, times_4, 10000), xmm0);
 
     __ addsd(xmm1, xmm0);
+    __ addsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ mulsd(xmm1, xmm0);
+    __ mulsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ subsd(xmm1, xmm0);
     __ subsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ divsd(xmm1, xmm0);
+    __ divsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ ucomisd(xmm0, xmm1);
     __ cmpltsd(xmm0, xmm1);
 
@@ -458,6 +482,83 @@
     }
   }
 
+  // AVX instruction
+  {
+    if (CpuFeatures::IsSupported(AVX)) {
+      CpuFeatureScope scope(&assm, AVX);
+      __ vaddsd(xmm0, xmm1, xmm2);
+      __ vaddsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vmulsd(xmm0, xmm1, xmm2);
+      __ vmulsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vsubsd(xmm0, xmm1, xmm2);
+      __ vsubsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vdivsd(xmm0, xmm1, xmm2);
+      __ vdivsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+    }
+  }
+
+  // FMA3 instruction
+  {
+    if (CpuFeatures::IsSupported(FMA3)) {
+      CpuFeatureScope scope(&assm, FMA3);
+      __ vfmadd132sd(xmm0, xmm1, xmm2);
+      __ vfmadd132sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmadd213sd(xmm0, xmm1, xmm2);
+      __ vfmadd213sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmadd231sd(xmm0, xmm1, xmm2);
+      __ vfmadd231sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfmsub132sd(xmm0, xmm1, xmm2);
+      __ vfmsub132sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmsub213sd(xmm0, xmm1, xmm2);
+      __ vfmsub213sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmsub231sd(xmm0, xmm1, xmm2);
+      __ vfmsub231sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfnmadd132sd(xmm0, xmm1, xmm2);
+      __ vfnmadd132sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmadd213sd(xmm0, xmm1, xmm2);
+      __ vfnmadd213sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmadd231sd(xmm0, xmm1, xmm2);
+      __ vfnmadd231sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfnmsub132sd(xmm0, xmm1, xmm2);
+      __ vfnmsub132sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmsub213sd(xmm0, xmm1, xmm2);
+      __ vfnmsub213sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmsub231sd(xmm0, xmm1, xmm2);
+      __ vfnmsub231sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfmadd132ss(xmm0, xmm1, xmm2);
+      __ vfmadd132ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmadd213ss(xmm0, xmm1, xmm2);
+      __ vfmadd213ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmadd231ss(xmm0, xmm1, xmm2);
+      __ vfmadd231ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfmsub132ss(xmm0, xmm1, xmm2);
+      __ vfmsub132ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmsub213ss(xmm0, xmm1, xmm2);
+      __ vfmsub213ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmsub231ss(xmm0, xmm1, xmm2);
+      __ vfmsub231ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfnmadd132ss(xmm0, xmm1, xmm2);
+      __ vfnmadd132ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmadd213ss(xmm0, xmm1, xmm2);
+      __ vfnmadd213ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmadd231ss(xmm0, xmm1, xmm2);
+      __ vfnmadd231ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfnmsub132ss(xmm0, xmm1, xmm2);
+      __ vfnmsub132ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmsub213ss(xmm0, xmm1, xmm2);
+      __ vfnmsub213ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmsub231ss(xmm0, xmm1, xmm2);
+      __ vfnmsub231ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+    }
+  }
+
   // xchg.
   {
     __ xchg(eax, eax);
diff --git a/test/cctest/test-disasm-x64.cc b/test/cctest/test-disasm-x64.cc
index e756ce2..6cd58ec 100644
--- a/test/cctest/test-disasm-x64.cc
+++ b/test/cctest/test-disasm-x64.cc
@@ -51,7 +51,7 @@
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   HandleScope scope(isolate);
-  v8::internal::byte buffer[2048];
+  v8::internal::byte buffer[4096];
   Assembler assm(isolate, buffer, sizeof buffer);
   DummyStaticFunction(NULL);  // just bloody use it (DELETE; debugging)
 
@@ -117,6 +117,26 @@
   __ imulq(rdx, rcx);
   __ shld(rdx, rcx);
   __ shrd(rdx, rcx);
+  __ shlq(Operand(rdi, rax, times_4, 100), Immediate(1));
+  __ shlq(Operand(rdi, rax, times_4, 100), Immediate(6));
+  __ shlq(Operand(r15, 0), Immediate(1));
+  __ shlq(Operand(r15, 0), Immediate(6));
+  __ shlq_cl(Operand(r15, 0));
+  __ shlq_cl(Operand(r15, 0));
+  __ shlq_cl(Operand(rdi, rax, times_4, 100));
+  __ shlq_cl(Operand(rdi, rax, times_4, 100));
+  __ shlq(rdx, Immediate(1));
+  __ shlq(rdx, Immediate(6));
+  __ shll(Operand(rdi, rax, times_4, 100), Immediate(1));
+  __ shll(Operand(rdi, rax, times_4, 100), Immediate(6));
+  __ shll(Operand(r15, 0), Immediate(1));
+  __ shll(Operand(r15, 0), Immediate(6));
+  __ shll_cl(Operand(r15, 0));
+  __ shll_cl(Operand(r15, 0));
+  __ shll_cl(Operand(rdi, rax, times_4, 100));
+  __ shll_cl(Operand(rdi, rax, times_4, 100));
+  __ shll(rdx, Immediate(1));
+  __ shll(rdx, Immediate(6));
   __ bts(Operand(rdx, 0), rcx);
   __ bts(Operand(rbx, rcx, times_4, 0), rcx);
   __ nop();
@@ -159,14 +179,22 @@
 
   __ nop();
   __ idivq(rdx);
-  __ mul(rdx);
+  __ mull(rdx);
+  __ mulq(rdx);
   __ negq(rdx);
   __ notq(rdx);
   __ testq(Operand(rbx, rcx, times_4, 10000), rdx);
 
-  __ imulq(rdx, Operand(rbx, rcx, times_4, 10000));
   __ imulq(rdx, rcx, Immediate(12));
   __ imulq(rdx, rcx, Immediate(1000));
+  __ imulq(rdx, Operand(rbx, rcx, times_4, 10000));
+  __ imulq(rdx, Operand(rbx, rcx, times_4, 10000), Immediate(12));
+  __ imulq(rdx, Operand(rbx, rcx, times_4, 10000), Immediate(1000));
+  __ imull(r15, rcx, Immediate(12));
+  __ imull(r15, rcx, Immediate(1000));
+  __ imull(r15, Operand(rbx, rcx, times_4, 10000));
+  __ imull(r15, Operand(rbx, rcx, times_4, 10000), Immediate(12));
+  __ imull(r15, Operand(rbx, rcx, times_4, 10000), Immediate(1000));
 
   __ incq(rdx);
   __ incq(Operand(rbx, rcx, times_4, 10000));
@@ -353,6 +381,8 @@
     // Move operation
     __ cvttss2si(rdx, Operand(rbx, rcx, times_4, 10000));
     __ cvttss2si(rdx, xmm1);
+    __ cvtsd2ss(xmm0, xmm1);
+    __ cvtsd2ss(xmm0, Operand(rbx, rcx, times_4, 10000));
     __ movaps(xmm0, xmm1);
 
     // logic operation
@@ -364,6 +394,14 @@
     __ xorps(xmm0, Operand(rbx, rcx, times_4, 10000));
 
     // Arithmetic operation
+    __ addss(xmm1, xmm0);
+    __ addss(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ mulss(xmm1, xmm0);
+    __ mulss(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ subss(xmm1, xmm0);
+    __ subss(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ divss(xmm1, xmm0);
+    __ divss(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ addps(xmm1, xmm0);
     __ addps(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ subps(xmm1, xmm0);
@@ -372,6 +410,9 @@
     __ mulps(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ divps(xmm1, xmm0);
     __ divps(xmm1, Operand(rbx, rcx, times_4, 10000));
+
+    __ ucomiss(xmm0, xmm1);
+    __ ucomiss(xmm0, Operand(rbx, rcx, times_4, 10000));
   }
   // SSE 2 instructions
   {
@@ -379,6 +420,8 @@
     __ cvttsd2si(rdx, xmm1);
     __ cvttsd2siq(rdx, xmm1);
     __ cvttsd2siq(rdx, Operand(rbx, rcx, times_4, 10000));
+    __ cvtqsi2sd(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ cvtqsi2sd(xmm1, rdx);
     __ movsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ movsd(Operand(rbx, rcx, times_4, 10000), xmm1);
     // 128 bit move instructions.
@@ -386,12 +429,23 @@
     __ movdqa(Operand(rbx, rcx, times_4, 10000), xmm0);
 
     __ addsd(xmm1, xmm0);
+    __ addsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ mulsd(xmm1, xmm0);
+    __ mulsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ subsd(xmm1, xmm0);
+    __ subsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ divsd(xmm1, xmm0);
+    __ divsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ ucomisd(xmm0, xmm1);
 
     __ andpd(xmm0, xmm1);
+
+    __ pslld(xmm0, 6);
+    __ psrld(xmm0, 6);
+    __ psllq(xmm0, 6);
+    __ psrlq(xmm0, 6);
+
+    __ pcmpeqd(xmm1, xmm0);
   }
 
   // cmov.
@@ -421,6 +475,89 @@
     }
   }
 
+  // AVX instruction
+  {
+    if (CpuFeatures::IsSupported(AVX)) {
+      CpuFeatureScope scope(&assm, AVX);
+      __ vaddsd(xmm0, xmm1, xmm2);
+      __ vaddsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vmulsd(xmm0, xmm1, xmm2);
+      __ vmulsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vsubsd(xmm0, xmm1, xmm2);
+      __ vsubsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vdivsd(xmm0, xmm1, xmm2);
+      __ vdivsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+    }
+  }
+
+  // FMA3 instruction
+  {
+    if (CpuFeatures::IsSupported(FMA3)) {
+      CpuFeatureScope scope(&assm, FMA3);
+      __ vfmadd132sd(xmm0, xmm1, xmm2);
+      __ vfmadd132sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmadd213sd(xmm0, xmm1, xmm2);
+      __ vfmadd213sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmadd231sd(xmm0, xmm1, xmm2);
+      __ vfmadd231sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfmadd132sd(xmm9, xmm10, xmm11);
+      __ vfmadd132sd(xmm9, xmm10, Operand(r9, r11, times_4, 10000));
+      __ vfmadd213sd(xmm9, xmm10, xmm11);
+      __ vfmadd213sd(xmm9, xmm10, Operand(r9, r11, times_4, 10000));
+      __ vfmadd231sd(xmm9, xmm10, xmm11);
+      __ vfmadd231sd(xmm9, xmm10, Operand(r9, r11, times_4, 10000));
+
+      __ vfmsub132sd(xmm0, xmm1, xmm2);
+      __ vfmsub132sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmsub213sd(xmm0, xmm1, xmm2);
+      __ vfmsub213sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmsub231sd(xmm0, xmm1, xmm2);
+      __ vfmsub231sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfnmadd132sd(xmm0, xmm1, xmm2);
+      __ vfnmadd132sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmadd213sd(xmm0, xmm1, xmm2);
+      __ vfnmadd213sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmadd231sd(xmm0, xmm1, xmm2);
+      __ vfnmadd231sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfnmsub132sd(xmm0, xmm1, xmm2);
+      __ vfnmsub132sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmsub213sd(xmm0, xmm1, xmm2);
+      __ vfnmsub213sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmsub231sd(xmm0, xmm1, xmm2);
+      __ vfnmsub231sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfmadd132ss(xmm0, xmm1, xmm2);
+      __ vfmadd132ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmadd213ss(xmm0, xmm1, xmm2);
+      __ vfmadd213ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmadd231ss(xmm0, xmm1, xmm2);
+      __ vfmadd231ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfmsub132ss(xmm0, xmm1, xmm2);
+      __ vfmsub132ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmsub213ss(xmm0, xmm1, xmm2);
+      __ vfmsub213ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmsub231ss(xmm0, xmm1, xmm2);
+      __ vfmsub231ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfnmadd132ss(xmm0, xmm1, xmm2);
+      __ vfnmadd132ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmadd213ss(xmm0, xmm1, xmm2);
+      __ vfnmadd213ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmadd231ss(xmm0, xmm1, xmm2);
+      __ vfnmadd231ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfnmsub132ss(xmm0, xmm1, xmm2);
+      __ vfnmsub132ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmsub213ss(xmm0, xmm1, xmm2);
+      __ vfnmsub213ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmsub231ss(xmm0, xmm1, xmm2);
+      __ vfnmsub231ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+    }
+  }
   // xchg.
   {
     __ xchgq(rax, rax);
diff --git a/test/cctest/test-disasm-x87.cc b/test/cctest/test-disasm-x87.cc
index 6cd33e5..e9b0dc5 100644
--- a/test/cctest/test-disasm-x87.cc
+++ b/test/cctest/test-disasm-x87.cc
@@ -201,6 +201,12 @@
   __ rcl(edx, 7);
   __ rcr(edx, 1);
   __ rcr(edx, 7);
+  __ ror(edx, 1);
+  __ ror(edx, 6);
+  __ ror_cl(edx);
+  __ ror(Operand(ebx, ecx, times_4, 10000), 1);
+  __ ror(Operand(ebx, ecx, times_4, 10000), 6);
+  __ ror_cl(Operand(ebx, ecx, times_4, 10000));
   __ sar(edx, 1);
   __ sar(edx, 6);
   __ sar_cl(edx);
diff --git a/test/cctest/test-feedback-vector.cc b/test/cctest/test-feedback-vector.cc
new file mode 100644
index 0000000..fa2f195
--- /dev/null
+++ b/test/cctest/test-feedback-vector.cc
@@ -0,0 +1,308 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/api.h"
+#include "src/debug.h"
+#include "src/execution.h"
+#include "src/factory.h"
+#include "src/global-handles.h"
+#include "src/macro-assembler.h"
+#include "src/objects.h"
+
+using namespace v8::internal;
+
+namespace {
+
+TEST(VectorStructure) {
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  // Empty vectors are the empty fixed array.
+  FeedbackVectorSpec empty;
+  Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(empty);
+  CHECK(Handle<FixedArray>::cast(vector)
+            .is_identical_to(factory->empty_fixed_array()));
+  // Which can nonetheless be queried.
+  CHECK_EQ(0, vector->ic_with_type_info_count());
+  CHECK_EQ(0, vector->ic_generic_count());
+  CHECK_EQ(0, vector->Slots());
+  CHECK_EQ(0, vector->ICSlots());
+
+  FeedbackVectorSpec one_slot(1, 0);
+  vector = factory->NewTypeFeedbackVector(one_slot);
+  CHECK_EQ(1, vector->Slots());
+  CHECK_EQ(0, vector->ICSlots());
+
+  FeedbackVectorSpec one_icslot(0, 1);
+  if (FLAG_vector_ics) {
+    one_icslot.SetKind(0, Code::CALL_IC);
+  }
+  vector = factory->NewTypeFeedbackVector(one_icslot);
+  CHECK_EQ(0, vector->Slots());
+  CHECK_EQ(1, vector->ICSlots());
+
+  FeedbackVectorSpec spec(3, 5);
+  if (FLAG_vector_ics) {
+    for (int i = 0; i < 5; i++) spec.SetKind(i, Code::CALL_IC);
+  }
+  vector = factory->NewTypeFeedbackVector(spec);
+  CHECK_EQ(3, vector->Slots());
+  CHECK_EQ(5, vector->ICSlots());
+
+  int metadata_length = vector->ic_metadata_length();
+  if (!FLAG_vector_ics) {
+    CHECK_EQ(0, metadata_length);
+  } else {
+    CHECK(metadata_length > 0);
+  }
+
+  int index = vector->GetIndex(FeedbackVectorSlot(0));
+
+  CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length, index);
+  CHECK(FeedbackVectorSlot(0) == vector->ToSlot(index));
+
+  index = vector->GetIndex(FeedbackVectorICSlot(0));
+  CHECK_EQ(index,
+           TypeFeedbackVector::kReservedIndexCount + metadata_length + 3);
+  CHECK(FeedbackVectorICSlot(0) == vector->ToICSlot(index));
+
+  CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 + 5,
+           vector->length());
+}
+
+
+// IC slots need an encoding to recognize what is in there.
+TEST(VectorICMetadata) {
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  if (!FLAG_vector_ics) {
+    // If FLAG_vector_ics is false, we only store CALL_ICs in the vector, so
+    // there is no need for metadata to describe the slots.
+    return;
+  }
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  FeedbackVectorSpec spec(10, 3 * 10);
+  // Set metadata.
+  for (int i = 0; i < 30; i++) {
+    Code::Kind kind;
+    if (i % 3 == 0) {
+      kind = Code::CALL_IC;
+    } else if (i % 3 == 1) {
+      kind = Code::LOAD_IC;
+    } else {
+      kind = Code::KEYED_LOAD_IC;
+    }
+    spec.SetKind(i, kind);
+  }
+
+  Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec);
+  CHECK_EQ(10, vector->Slots());
+  CHECK_EQ(3 * 10, vector->ICSlots());
+
+  // Meanwhile set some feedback values and type feedback values to
+  // verify the data structure remains intact.
+  vector->change_ic_with_type_info_count(100);
+  vector->change_ic_generic_count(3333);
+  vector->Set(FeedbackVectorSlot(0), *vector);
+
+  // Verify the metadata is correctly set up from the spec.
+  for (int i = 0; i < 30; i++) {
+    Code::Kind kind = vector->GetKind(FeedbackVectorICSlot(i));
+    if (i % 3 == 0) {
+      CHECK_EQ(Code::CALL_IC, kind);
+    } else if (i % 3 == 1) {
+      CHECK_EQ(Code::LOAD_IC, kind);
+    } else {
+      CHECK_EQ(Code::KEYED_LOAD_IC, kind);
+    }
+  }
+}
+
+
+TEST(VectorSlotClearing) {
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  // We only test clearing FeedbackVectorSlots, not FeedbackVectorICSlots.
+  // The reason is that FeedbackVectorICSlots need a full code environment
+  // to fully test (See VectorICProfilerStatistics test below).
+  FeedbackVectorSpec spec(5, 0);
+  Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec);
+
+  // Fill with information
+  vector->Set(FeedbackVectorSlot(0), Smi::FromInt(1));
+  vector->Set(FeedbackVectorSlot(1), *factory->fixed_array_map());
+  Handle<AllocationSite> site = factory->NewAllocationSite();
+  vector->Set(FeedbackVectorSlot(2), *site);
+
+  vector->ClearSlots(NULL);
+
+  // The feedback vector slots are cleared. AllocationSites are granted
+  // an exemption from clearing, as are smis.
+  CHECK_EQ(Smi::FromInt(1), vector->Get(FeedbackVectorSlot(0)));
+  CHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(isolate),
+           vector->Get(FeedbackVectorSlot(1)));
+  CHECK(vector->Get(FeedbackVectorSlot(2))->IsAllocationSite());
+}
+
+
+TEST(VectorICProfilerStatistics) {
+  if (i::FLAG_always_opt) return;
+  CcTest::InitializeVM();
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+
+  // Make sure function f has a call that uses a type feedback slot.
+  CompileRun(
+      "function fun() {};"
+      "function f(a) { a(); } f(fun);");
+  Handle<JSFunction> f = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+  // There should be one IC.
+  Code* code = f->shared()->code();
+  TypeFeedbackInfo* feedback_info =
+      TypeFeedbackInfo::cast(code->type_feedback_info());
+  CHECK_EQ(1, feedback_info->ic_total_count());
+  CHECK_EQ(0, feedback_info->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_info->ic_generic_count());
+  TypeFeedbackVector* feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_vector->ic_generic_count());
+
+  // Now send the information generic.
+  CompileRun("f(Object);");
+  feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(1, feedback_vector->ic_generic_count());
+
+  // A collection will make the site uninitialized again.
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_vector->ic_generic_count());
+
+  // The Array function is special. A call to array remains monomorphic
+  // and isn't cleared by gc because an AllocationSite is being held.
+  CompileRun("f(Array);");
+  feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_vector->ic_generic_count());
+
+  int ic_slot = 0;
+  CHECK(
+      feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_vector->ic_generic_count());
+  CHECK(
+      feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
+}
+
+
+TEST(VectorCallICStates) {
+  if (i::FLAG_always_opt) return;
+  CcTest::InitializeVM();
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+
+  // Make sure function f has a call that uses a type feedback slot.
+  CompileRun(
+      "function foo() { return 17; }"
+      "function f(a) { a(); } f(foo);");
+  Handle<JSFunction> f = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+  // There should be one IC.
+  Handle<TypeFeedbackVector> feedback_vector =
+      Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
+  FeedbackVectorICSlot slot(0);
+  CallICNexus nexus(feedback_vector, slot);
+  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
+  // CallIC doesn't return map feedback.
+  CHECK_EQ(NULL, nexus.FindFirstMap());
+
+  CompileRun("f(function() { return 16; })");
+  CHECK_EQ(GENERIC, nexus.StateFromFeedback());
+
+  // After a collection, state should be reset to UNINITIALIZED.
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  CHECK_EQ(UNINITIALIZED, nexus.StateFromFeedback());
+
+  // Array is special. It will remain monomorphic across gcs and it contains an
+  // AllocationSite.
+  CompileRun("f(Array)");
+  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
+  CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot))->IsAllocationSite());
+
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
+}
+
+
+TEST(VectorLoadICStates) {
+  if (i::FLAG_always_opt || !i::FLAG_vector_ics) return;
+  CcTest::InitializeVM();
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+
+  // Make sure function f has a call that uses a type feedback slot.
+  CompileRun(
+      "var o = { foo: 3 };"
+      "function f(a) { return a.foo; } f(o);");
+  Handle<JSFunction> f = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+  // There should be one IC.
+  Handle<TypeFeedbackVector> feedback_vector =
+      Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
+  FeedbackVectorICSlot slot(0);
+  LoadICNexus nexus(feedback_vector, slot);
+  CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
+
+  CompileRun("f(o)");
+  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
+  // Verify that the monomorphic map is the one we expect.
+  Handle<JSObject> o = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Object>::Cast(CcTest::global()->Get(v8_str("o"))));
+  CHECK_EQ(o->map(), nexus.FindFirstMap());
+
+  // Now go polymorphic.
+  CompileRun("f({ blarg: 3, foo: 2 })");
+  CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
+
+  CompileRun(
+      "delete o.foo;"
+      "f(o)");
+  CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
+
+  CompileRun("f({ blarg: 3, torino: 10, foo: 2 })");
+  CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
+  MapHandleList maps;
+  nexus.FindAllMaps(&maps);
+  CHECK_EQ(4, maps.length());
+
+  // Finally driven megamorphic.
+  CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })");
+  CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
+  CHECK_EQ(NULL, nexus.FindFirstMap());
+
+  // After a collection, state should not be reset to PREMONOMORPHIC.
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
+}
+}
diff --git a/test/cctest/test-func-name-inference.cc b/test/cctest/test-func-name-inference.cc
index bc503b5..7f3dafc 100644
--- a/test/cctest/test-func-name-inference.cc
+++ b/test/cctest/test-func-name-inference.cc
@@ -30,7 +30,7 @@
 
 #include "src/api.h"
 #include "src/debug.h"
-#include "src/runtime.h"
+#include "src/string-search.h"
 #include "test/cctest/cctest.h"
 
 
@@ -46,13 +46,13 @@
 using ::v8::internal::SmartArrayPointer;
 using ::v8::internal::SharedFunctionInfo;
 using ::v8::internal::String;
+using ::v8::internal::Vector;
 
 
 static void CheckFunctionName(v8::Handle<v8::Script> script,
                               const char* func_pos_src,
                               const char* ref_inferred_name) {
   Isolate* isolate = CcTest::i_isolate();
-  Factory* factory = isolate->factory();
 
   // Get script source.
   Handle<Object> obj = v8::Utils::OpenHandle(*script);
@@ -69,12 +69,14 @@
   Handle<String> script_src(String::cast(i_script->source()));
 
   // Find the position of a given func source substring in the source.
-  Handle<String> func_pos_str =
-      factory->NewStringFromAsciiChecked(func_pos_src);
-  int func_pos = Runtime::StringMatch(isolate,
-                                      script_src,
-                                      func_pos_str,
-                                      0);
+  int func_pos;
+  {
+    i::DisallowHeapAllocation no_gc;
+    Vector<const uint8_t> func_pos_str = i::OneByteVector(func_pos_src);
+    String::FlatContent script_content = script_src->GetFlatContent();
+    func_pos = SearchString(isolate, script_content.ToOneByteVector(),
+                            func_pos_str, 0);
+  }
   CHECK_NE(0, func_pos);
 
   // Obtain SharedFunctionInfo for the function.
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index 8f9b484..94a5be4 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -890,9 +890,10 @@
 }  // namespace
 
 TEST(HeapSnapshotJSONSerialization) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
-  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+  v8::HandleScope scope(isolate);
+  v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
 
 #define STRING_LITERAL_FOR_TEST \
   "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
@@ -923,7 +924,7 @@
 
   // Verify that snapshot object has required fields.
   v8::Local<v8::Object> parsed_snapshot =
-      env->Global()->Get(v8_str("parsed"))->ToObject();
+      env->Global()->Get(v8_str("parsed"))->ToObject(isolate);
   CHECK(parsed_snapshot->Has(v8_str("snapshot")));
   CHECK(parsed_snapshot->Has(v8_str("nodes")));
   CHECK(parsed_snapshot->Has(v8_str("edges")));
@@ -979,17 +980,18 @@
       "  \"s\", property_type)");
   CHECK(!string_obj_pos_val.IsEmpty());
   int string_obj_pos =
-      static_cast<int>(string_obj_pos_val->ToNumber()->Value());
+      static_cast<int>(string_obj_pos_val->ToNumber(isolate)->Value());
   v8::Local<v8::Object> nodes_array =
-      parsed_snapshot->Get(v8_str("nodes"))->ToObject();
+      parsed_snapshot->Get(v8_str("nodes"))->ToObject(isolate);
   int string_index = static_cast<int>(
-      nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value());
+      nodes_array->Get(string_obj_pos + 1)->ToNumber(isolate)->Value());
   CHECK_GT(string_index, 0);
   v8::Local<v8::Object> strings_array =
-      parsed_snapshot->Get(v8_str("strings"))->ToObject();
-  v8::Local<v8::String> string = strings_array->Get(string_index)->ToString();
+      parsed_snapshot->Get(v8_str("strings"))->ToObject(isolate);
+  v8::Local<v8::String> string =
+      strings_array->Get(string_index)->ToString(isolate);
   v8::Local<v8::String> ref_string =
-      CompileRun(STRING_LITERAL_FOR_TEST)->ToString();
+      CompileRun(STRING_LITERAL_FOR_TEST)->ToString(isolate);
 #undef STRING_LITERAL_FOR_TEST
   CHECK_EQ(*v8::String::Utf8Value(ref_string),
            *v8::String::Utf8Value(string));
@@ -1719,9 +1721,6 @@
   const v8::HeapGraphNode* native_context =
       GetProperty(global, v8::HeapGraphEdge::kInternal, "native_context");
   CHECK_NE(NULL, native_context);
-  const v8::HeapGraphNode* global_context =
-      GetProperty(global, v8::HeapGraphEdge::kInternal, "global_context");
-  CHECK_NE(NULL, global_context);
   const v8::HeapGraphNode* global_proxy =
       GetProperty(global, v8::HeapGraphEdge::kInternal, "global_proxy");
   CHECK_NE(NULL, global_proxy);
@@ -1917,6 +1916,47 @@
 }
 
 
+TEST(FastCaseRedefinedAccessors) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+
+  CompileRun(
+      "var obj1 = {};\n"
+      "Object.defineProperty(obj1, 'prop', { "
+      "  get: function() { return 42; },\n"
+      "  set: function(value) { return this.prop_ = value; },\n"
+      "  configurable: true,\n"
+      "  enumerable: true,\n"
+      "});\n"
+      "Object.defineProperty(obj1, 'prop', { "
+      "  get: function() { return 153; },\n"
+      "  set: function(value) { return this.prop_ = value; },\n"
+      "  configurable: true,\n"
+      "  enumerable: true,\n"
+      "});\n");
+  v8::Local<v8::Object> js_global =
+      env->Global()->GetPrototype().As<v8::Object>();
+  i::Handle<i::JSObject> js_obj1 =
+      v8::Utils::OpenHandle(*js_global->Get(v8_str("obj1")).As<v8::Object>());
+  USE(js_obj1);
+
+  const v8::HeapSnapshot* snapshot =
+      heap_profiler->TakeHeapSnapshot(v8_str("fastCaseAccessors"));
+  CHECK(ValidateSnapshot(snapshot));
+  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+  CHECK_NE(NULL, global);
+  const v8::HeapGraphNode* obj1 =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
+  CHECK_NE(NULL, obj1);
+  const v8::HeapGraphNode* func;
+  func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get prop");
+  CHECK_NE(NULL, func);
+  func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set prop");
+  CHECK_NE(NULL, func);
+}
+
+
 TEST(SlowCaseAccessors) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
@@ -1952,9 +1992,10 @@
 
 
 TEST(HiddenPropertiesFastCase) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
-  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+  v8::HandleScope scope(isolate);
+  v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
 
   CompileRun(
       "function C(x) { this.a = this; this.b = x; }\n"
@@ -1973,7 +2014,7 @@
   v8::Handle<v8::Value> cHandle =
       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c"));
   CHECK(!cHandle.IsEmpty() && cHandle->IsObject());
-  cHandle->ToObject()->SetHiddenValue(v8_str("key"), v8_str("val"));
+  cHandle->ToObject(isolate)->SetHiddenValue(v8_str("key"), v8_str("val"));
 
   snapshot = heap_profiler->TakeHeapSnapshot(
       v8_str("HiddenPropertiesFastCase2"));
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index e526761..f8a7df2 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -1375,6 +1375,98 @@
 }
 
 
+TEST(CompilationCacheCachingBehavior) {
+  // If we do not flush code, or have the compilation cache turned off, this
+  // test is invalid.
+  if (!FLAG_flush_code || !FLAG_flush_code_incrementally ||
+      !FLAG_compilation_cache) {
+    return;
+  }
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  Heap* heap = isolate->heap();
+  CompilationCache* compilation_cache = isolate->compilation_cache();
+
+  v8::HandleScope scope(CcTest::isolate());
+  const char* raw_source =
+      "function foo() {"
+      "  var x = 42;"
+      "  var y = 42;"
+      "  var z = x + y;"
+      "};"
+      "foo()";
+  Handle<String> source = factory->InternalizeUtf8String(raw_source);
+  Handle<Context> native_context = isolate->native_context();
+
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun(raw_source);
+  }
+
+  // On first compilation, only a hash is inserted in the code cache. We can't
+  // find that value.
+  MaybeHandle<SharedFunctionInfo> info = compilation_cache->LookupScript(
+      source, Handle<Object>(), 0, 0, true, native_context);
+  CHECK(info.is_null());
+
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun(raw_source);
+  }
+
+  // On second compilation, the hash is replaced by a real cache entry mapping
+  // the source to the shared function info containing the code.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(!info.is_null());
+
+  heap->CollectAllGarbage(Heap::kNoGCFlags);
+
+  // On second compilation, the hash is replaced by a real cache entry mapping
+  // the source to the shared function info containing the code.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(!info.is_null());
+
+  while (!info.ToHandleChecked()->code()->IsOld()) {
+    info.ToHandleChecked()->code()->MakeOlder(NO_MARKING_PARITY);
+  }
+
+  heap->CollectAllGarbage(Heap::kNoGCFlags);
+  // Ensure code aging cleared the entry from the cache.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(info.is_null());
+
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun(raw_source);
+  }
+
+  // On first compilation, only a hash is inserted in the code cache. We can't
+  // find that value.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(info.is_null());
+
+  for (int i = 0; i < CompilationCacheTable::kHashGenerations; i++) {
+    compilation_cache->MarkCompactPrologue();
+  }
+
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun(raw_source);
+  }
+
+  // If we aged the cache before caching the script, ensure that we didn't cache
+  // on next compilation.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(info.is_null());
+}
+
+
 // Count the number of native contexts in the weak list of native contexts.
 int CountNativeContexts() {
   int count = 0;
@@ -1487,7 +1579,7 @@
   }
 
   // Force compilation cache cleanup.
-  CcTest::heap()->NotifyContextDisposed();
+  CcTest::heap()->NotifyContextDisposed(true);
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
   // Dispose the native contexts one by one.
@@ -1602,6 +1694,64 @@
 }
 
 
+TEST(TestSizeOfRegExpCode) {
+  if (!FLAG_regexp_optimization) return;
+
+  v8::V8::Initialize();
+
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+
+  LocalContext context;
+
+  // Adjust source below and this check to match
+  // RegExpImple::kRegExpTooLargeToOptimize.
+  DCHECK_EQ(i::RegExpImpl::kRegExpTooLargeToOptimize, 10 * KB);
+
+  // Compile a regexp that is much larger if we are using regexp optimizations.
+  CompileRun(
+      "var reg_exp_source = '(?:a|bc|def|ghij|klmno|pqrstu)';"
+      "var half_size_reg_exp;"
+      "while (reg_exp_source.length < 10 * 1024) {"
+      "  half_size_reg_exp = reg_exp_source;"
+      "  reg_exp_source = reg_exp_source + reg_exp_source;"
+      "}"
+      // Flatten string.
+      "reg_exp_source.match(/f/);");
+
+  // Get initial heap size after several full GCs, which will stabilize
+  // the heap size and return with sweeping finished completely.
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector();
+  if (collector->sweeping_in_progress()) {
+    collector->EnsureSweepingCompleted();
+  }
+  int initial_size = static_cast<int>(CcTest::heap()->SizeOfObjects());
+
+  CompileRun("'foo'.match(reg_exp_source);");
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  int size_with_regexp = static_cast<int>(CcTest::heap()->SizeOfObjects());
+
+  CompileRun("'foo'.match(half_size_reg_exp);");
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  int size_with_optimized_regexp =
+      static_cast<int>(CcTest::heap()->SizeOfObjects());
+
+  int size_of_regexp_code = size_with_regexp - initial_size;
+
+  CHECK_LE(size_of_regexp_code, 1 * MB);
+
+  // Small regexp is half the size, but compiles to more than twice the code
+  // due to the optimization steps.
+  CHECK_GE(size_with_optimized_regexp,
+           size_with_regexp + size_of_regexp_code * 2);
+}
+
+
 TEST(TestSizeOfObjects) {
   v8::V8::Initialize();
 
@@ -2183,6 +2333,48 @@
 }
 
 
+TEST(IdleNotificationFinishMarking) {
+  i::FLAG_allow_natives_syntax = true;
+  CcTest::InitializeVM();
+  SimulateFullSpace(CcTest::heap()->old_pointer_space());
+  IncrementalMarking* marking = CcTest::heap()->incremental_marking();
+  marking->Abort();
+  marking->Start();
+
+  CHECK_EQ(CcTest::heap()->gc_count(), 0);
+
+  // TODO(hpayer): We cannot write proper unit test right now for heap.
+  // The ideal test would call kMaxIdleMarkingDelayCounter to test the
+  // marking delay counter.
+
+  // Perform a huge incremental marking step but don't complete marking.
+  intptr_t bytes_processed = 0;
+  do {
+    bytes_processed =
+        marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
+                      IncrementalMarking::FORCE_MARKING,
+                      IncrementalMarking::DO_NOT_FORCE_COMPLETION);
+    CHECK(!marking->IsIdleMarkingDelayCounterLimitReached());
+  } while (bytes_processed);
+
+  // The next invocations of incremental marking are not going to complete
+  // marking
+  // since the completion threshold is not reached
+  for (size_t i = 0; i < IncrementalMarking::kMaxIdleMarkingDelayCounter - 2;
+       i++) {
+    marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
+                  IncrementalMarking::FORCE_MARKING,
+                  IncrementalMarking::DO_NOT_FORCE_COMPLETION);
+    CHECK(!marking->IsIdleMarkingDelayCounterLimitReached());
+  }
+
+  // The next idle notification has to finish incremental marking.
+  const int kLongIdleTime = 1000000;
+  CcTest::isolate()->IdleNotification(kLongIdleTime);
+  CHECK_EQ(CcTest::heap()->gc_count(), 1);
+}
+
+
 // Test that HAllocateObject will always return an object in new-space.
 TEST(OptimizedAllocationAlwaysInNewSpace) {
   i::FLAG_allow_natives_syntax = true;
@@ -2204,7 +2396,8 @@
       "f(1); f(2); f(3);"
       "%OptimizeFunctionOnNextCall(f);"
       "f(4);");
-  CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
+  CHECK_EQ(
+      4, res.As<v8::Object>()->GetRealNamedProperty(v8_str("x"))->Int32Value());
 
   Handle<JSObject> o =
       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
@@ -2342,12 +2535,21 @@
   FieldIndex idx1 = FieldIndex::ForPropertyIndex(o->map(), 0);
   FieldIndex idx2 = FieldIndex::ForPropertyIndex(o->map(), 1);
   CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(idx1)));
-  CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(idx2)));
+  if (!o->IsUnboxedDoubleField(idx2)) {
+    CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(idx2)));
+  } else {
+    CHECK_EQ(1.1, o->RawFastDoublePropertyAt(idx2));
+  }
 
   JSObject* inner_object =
       reinterpret_cast<JSObject*>(o->RawFastPropertyAt(idx1));
   CHECK(CcTest::heap()->InOldPointerSpace(inner_object));
-  CHECK(CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(idx1)));
+  if (!inner_object->IsUnboxedDoubleField(idx1)) {
+    CHECK(
+        CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(idx1)));
+  } else {
+    CHECK_EQ(2.2, inner_object->RawFastDoublePropertyAt(idx1));
+  }
   CHECK(CcTest::heap()->InOldPointerSpace(
       inner_object->RawFastPropertyAt(idx2)));
 }
@@ -2806,6 +3008,7 @@
              "root = new F");
   root = GetByName("root");
   AddPropertyTo(2, root, "funny");
+  CcTest::heap()->CollectGarbage(NEW_SPACE);
 
   // Count number of live transitions after marking.  Note that one transition
   // is left, because 'o' still holds an instance of one transition target.
@@ -2832,6 +3035,7 @@
 
   root = GetByName("root");
   AddPropertyTo(2, root, "funny");
+  CcTest::heap()->CollectGarbage(NEW_SPACE);
 
   // Count number of live transitions after marking.  Note that one transition
   // is left, because 'o' still holds an instance of one transition target.
@@ -3076,7 +3280,7 @@
 
   OFStream os(stdout);
   g->shared()->Print(os);
-  os << endl;
+  os << std::endl;
 }
 #endif  // OBJECT_PRINT
 
@@ -3147,22 +3351,20 @@
 
   Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector());
 
-  int expected_length = FLAG_vector_ics ? 4 : 2;
-  CHECK_EQ(expected_length, feedback_vector->length());
-  for (int i = 0; i < expected_length; i++) {
-    if ((i % 2) == 1) {
-      CHECK(feedback_vector->get(i)->IsJSFunction());
-    }
-  }
+  int expected_slots = 2;
+  CHECK_EQ(expected_slots, feedback_vector->ICSlots());
+  int slot1 = 0;
+  int slot2 = 1;
+  CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot1))->IsJSFunction());
+  CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot2))->IsJSFunction());
 
   SimulateIncrementalMarking(CcTest::heap());
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
-  CHECK_EQ(expected_length, feedback_vector->length());
-  for (int i = 0; i < expected_length; i++) {
-    CHECK_EQ(feedback_vector->get(i),
-             *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
-  }
+  CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(slot1)),
+           *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
+  CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(slot2)),
+           *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
 }
 
 
@@ -3181,6 +3383,25 @@
 }
 
 
+static void CheckVectorIC(Handle<JSFunction> f, int ic_slot_index,
+                          InlineCacheState desired_state) {
+  Handle<TypeFeedbackVector> vector =
+      Handle<TypeFeedbackVector>(f->shared()->feedback_vector());
+  FeedbackVectorICSlot slot(ic_slot_index);
+  LoadICNexus nexus(vector, slot);
+  CHECK(nexus.StateFromFeedback() == desired_state);
+}
+
+
+static void CheckVectorICCleared(Handle<JSFunction> f, int ic_slot_index) {
+  Handle<TypeFeedbackVector> vector =
+      Handle<TypeFeedbackVector>(f->shared()->feedback_vector());
+  FeedbackVectorICSlot slot(ic_slot_index);
+  LoadICNexus nexus(vector, slot);
+  CHECK(IC::IsCleared(&nexus));
+}
+
+
 TEST(IncrementalMarkingPreservesMonomorphicIC) {
   if (i::FLAG_always_opt) return;
   CcTest::InitializeVM();
@@ -3196,13 +3417,23 @@
               CcTest::global()->Get(v8_str("f"))));
 
   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(ic_before->ic_state() == MONOMORPHIC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, MONOMORPHIC);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_before->ic_state() == MONOMORPHIC);
+  }
 
   SimulateIncrementalMarking(CcTest::heap());
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(ic_after->ic_state() == MONOMORPHIC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, MONOMORPHIC);
+    CHECK(ic_after->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_after->ic_state() == MONOMORPHIC);
+  }
 }
 
 
@@ -3228,7 +3459,12 @@
               CcTest::global()->Get(v8_str("f"))));
 
   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(ic_before->ic_state() == MONOMORPHIC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, MONOMORPHIC);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_before->ic_state() == MONOMORPHIC);
+  }
 
   // Fire context dispose notification.
   CcTest::isolate()->ContextDisposedNotification();
@@ -3236,7 +3472,60 @@
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(IC::IsCleared(ic_after));
+  if (FLAG_vector_ics) {
+    CheckVectorICCleared(f, 0);
+    CHECK(ic_after->ic_state() == DEFAULT);
+  } else {
+    CHECK(IC::IsCleared(ic_after));
+  }
+}
+
+
+TEST(IncrementalMarkingPreservesPolymorphicIC) {
+  if (i::FLAG_always_opt) return;
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  v8::Local<v8::Value> obj1, obj2;
+
+  {
+    LocalContext env;
+    CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
+    obj1 = env->Global()->Get(v8_str("obj"));
+  }
+
+  {
+    LocalContext env;
+    CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
+    obj2 = env->Global()->Get(v8_str("obj"));
+  }
+
+  // Prepare function f that contains a polymorphic IC for objects
+  // originating from two different native contexts.
+  CcTest::global()->Set(v8_str("obj1"), obj1);
+  CcTest::global()->Set(v8_str("obj2"), obj2);
+  CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
+  Handle<JSFunction> f = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+
+  Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, POLYMORPHIC);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_before->ic_state() == POLYMORPHIC);
+  }
+
+  // Fire context dispose notification.
+  SimulateIncrementalMarking(CcTest::heap());
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+
+  Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, POLYMORPHIC);
+    CHECK(ic_after->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_after->ic_state() == POLYMORPHIC);
+  }
 }
 
 
@@ -3269,7 +3558,12 @@
               CcTest::global()->Get(v8_str("f"))));
 
   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(ic_before->ic_state() == POLYMORPHIC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, POLYMORPHIC);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_before->ic_state() == POLYMORPHIC);
+  }
 
   // Fire context dispose notification.
   CcTest::isolate()->ContextDisposedNotification();
@@ -3277,7 +3571,12 @@
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(IC::IsCleared(ic_after));
+  if (FLAG_vector_ics) {
+    CheckVectorICCleared(f, 0);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(IC::IsCleared(ic_after));
+  }
 }
 
 
@@ -4021,8 +4320,9 @@
                "bar%d();"
                "bar%d();"
                "bar%d();"
-               "%%OptimizeFunctionOnNextCall(bar%d);"
-               "bar%d();", i, i, i, i, i, i, i, i);
+               "%%OptimizeFwunctionOnNextCall(bar%d);"
+               "bar%d();",
+               i, i, i, i, i, i, i, i);
       CompileRun(source.start());
     }
     heap->CollectAllGarbage(i::Heap::kNoGCFlags);
@@ -4154,7 +4454,7 @@
   v8::Persistent<v8::Object> garbage;
   {
     v8::HandleScope scope(isolate);
-    garbage.Reset(isolate, CompileRun(source)->ToObject());
+    garbage.Reset(isolate, CompileRun(source)->ToObject(isolate));
   }
   weak_ic_cleared = false;
   garbage.SetWeak(static_cast<void*>(&garbage), &ClearWeakIC);
@@ -4181,6 +4481,25 @@
 }
 
 
+TEST(WeakMapInPolymorphicLoadIC) {
+  CheckWeakness(
+      "function loadIC(obj) {"
+      "  return obj.name;"
+      "}"
+      " (function() {"
+      "   var proto = {'name' : 'weak'};"
+      "   var obj = Object.create(proto);"
+      "   loadIC(obj);"
+      "   loadIC(obj);"
+      "   loadIC(obj);"
+      "   var poly = Object.create(proto);"
+      "   poly.x = true;"
+      "   loadIC(poly);"
+      "   return proto;"
+      " })();");
+}
+
+
 TEST(WeakMapInMonomorphicKeyedLoadIC) {
   CheckWeakness("function keyedLoadIC(obj, field) {"
                 "  return obj[field];"
@@ -4196,6 +4515,25 @@
 }
 
 
+TEST(WeakMapInPolymorphicKeyedLoadIC) {
+  CheckWeakness(
+      "function keyedLoadIC(obj, field) {"
+      "  return obj[field];"
+      "}"
+      " (function() {"
+      "   var proto = {'name' : 'weak'};"
+      "   var obj = Object.create(proto);"
+      "   keyedLoadIC(obj, 'name');"
+      "   keyedLoadIC(obj, 'name');"
+      "   keyedLoadIC(obj, 'name');"
+      "   var poly = Object.create(proto);"
+      "   poly.x = true;"
+      "   keyedLoadIC(poly, 'name');"
+      "   return proto;"
+      " })();");
+}
+
+
 TEST(WeakMapInMonomorphicStoreIC) {
   CheckWeakness("function storeIC(obj, value) {"
                 "  obj.name = value;"
@@ -4211,6 +4549,25 @@
 }
 
 
+TEST(WeakMapInPolymorphicStoreIC) {
+  CheckWeakness(
+      "function storeIC(obj, value) {"
+      "  obj.name = value;"
+      "}"
+      " (function() {"
+      "   var proto = {'name' : 'weak'};"
+      "   var obj = Object.create(proto);"
+      "   storeIC(obj, 'x');"
+      "   storeIC(obj, 'x');"
+      "   storeIC(obj, 'x');"
+      "   var poly = Object.create(proto);"
+      "   poly.x = true;"
+      "   storeIC(poly, 'x');"
+      "   return proto;"
+      " })();");
+}
+
+
 TEST(WeakMapInMonomorphicKeyedStoreIC) {
   CheckWeakness("function keyedStoreIC(obj, field, value) {"
                 "  obj[field] = value;"
@@ -4226,6 +4583,25 @@
 }
 
 
+TEST(WeakMapInPolymorphicKeyedStoreIC) {
+  CheckWeakness(
+      "function keyedStoreIC(obj, field, value) {"
+      "  obj[field] = value;"
+      "}"
+      " (function() {"
+      "   var proto = {'name' : 'weak'};"
+      "   var obj = Object.create(proto);"
+      "   keyedStoreIC(obj, 'x');"
+      "   keyedStoreIC(obj, 'x');"
+      "   keyedStoreIC(obj, 'x');"
+      "   var poly = Object.create(proto);"
+      "   poly.x = true;"
+      "   keyedStoreIC(poly, 'x');"
+      "   return proto;"
+      " })();");
+}
+
+
 TEST(WeakMapInMonomorphicCompareNilIC) {
   CheckWeakness("function compareNilIC(obj) {"
                 "  return obj == null;"
@@ -4241,6 +4617,160 @@
 }
 
 
+Handle<JSFunction> GetFunctionByName(Isolate* isolate, const char* name) {
+  Handle<String> str = isolate->factory()->InternalizeUtf8String(name);
+  Handle<Object> obj =
+      Object::GetProperty(isolate->global_object(), str).ToHandleChecked();
+  return Handle<JSFunction>::cast(obj);
+}
+
+
+void CheckIC(Code* code, Code::Kind kind, InlineCacheState state) {
+  Code* ic = FindFirstIC(code, kind);
+  CHECK(ic->is_inline_cache_stub());
+  CHECK(ic->ic_state() == state);
+}
+
+
+TEST(MonomorphicStaysMonomorphicAfterGC) {
+  if (FLAG_always_opt) return;
+  // TODO(mvstanton): vector ics need weak support!
+  if (FLAG_vector_ics) return;
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  v8::HandleScope scope(CcTest::isolate());
+  CompileRun(
+      "function loadIC(obj) {"
+      "  return obj.name;"
+      "}"
+      "function testIC() {"
+      "  var proto = {'name' : 'weak'};"
+      "  var obj = Object.create(proto);"
+      "  loadIC(obj);"
+      "  loadIC(obj);"
+      "  loadIC(obj);"
+      "  return proto;"
+      "};");
+  Handle<JSFunction> loadIC = GetFunctionByName(isolate, "loadIC");
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun("(testIC())");
+  }
+  heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
+  CheckIC(loadIC->code(), Code::LOAD_IC, MONOMORPHIC);
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun("(testIC())");
+  }
+  CheckIC(loadIC->code(), Code::LOAD_IC, MONOMORPHIC);
+}
+
+
+TEST(PolymorphicStaysPolymorphicAfterGC) {
+  if (FLAG_always_opt) return;
+  // TODO(mvstanton): vector ics need weak support!
+  if (FLAG_vector_ics) return;
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  v8::HandleScope scope(CcTest::isolate());
+  CompileRun(
+      "function loadIC(obj) {"
+      "  return obj.name;"
+      "}"
+      "function testIC() {"
+      "  var proto = {'name' : 'weak'};"
+      "  var obj = Object.create(proto);"
+      "  loadIC(obj);"
+      "  loadIC(obj);"
+      "  loadIC(obj);"
+      "  var poly = Object.create(proto);"
+      "  poly.x = true;"
+      "  loadIC(poly);"
+      "  return proto;"
+      "};");
+  Handle<JSFunction> loadIC = GetFunctionByName(isolate, "loadIC");
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun("(testIC())");
+  }
+  heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
+  CheckIC(loadIC->code(), Code::LOAD_IC, POLYMORPHIC);
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun("(testIC())");
+  }
+  CheckIC(loadIC->code(), Code::LOAD_IC, POLYMORPHIC);
+}
+
+
+TEST(WeakCell) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::internal::Heap* heap = CcTest::heap();
+  v8::internal::Factory* factory = isolate->factory();
+
+  HandleScope outer_scope(isolate);
+  Handle<WeakCell> weak_cell1;
+  {
+    HandleScope inner_scope(isolate);
+    Handle<HeapObject> value = factory->NewFixedArray(1, NOT_TENURED);
+    weak_cell1 = inner_scope.CloseAndEscape(factory->NewWeakCell(value));
+  }
+
+  Handle<FixedArray> survivor = factory->NewFixedArray(1, NOT_TENURED);
+  Handle<WeakCell> weak_cell2;
+  {
+    HandleScope inner_scope(isolate);
+    weak_cell2 = inner_scope.CloseAndEscape(factory->NewWeakCell(survivor));
+  }
+  CHECK(weak_cell1->value()->IsFixedArray());
+  CHECK_EQ(*survivor, weak_cell2->value());
+  heap->CollectGarbage(NEW_SPACE);
+  CHECK(weak_cell1->value()->IsFixedArray());
+  CHECK_EQ(*survivor, weak_cell2->value());
+  heap->CollectGarbage(NEW_SPACE);
+  CHECK(weak_cell1->value()->IsFixedArray());
+  CHECK_EQ(*survivor, weak_cell2->value());
+  heap->CollectAllAvailableGarbage();
+  CHECK(weak_cell1->cleared());
+  CHECK_EQ(*survivor, weak_cell2->value());
+}
+
+
+TEST(WeakCellsWithIncrementalMarking) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::internal::Heap* heap = CcTest::heap();
+  v8::internal::Factory* factory = isolate->factory();
+
+  const int N = 16;
+  HandleScope outer_scope(isolate);
+  Handle<FixedArray> survivor = factory->NewFixedArray(1, NOT_TENURED);
+  Handle<WeakCell> weak_cells[N];
+
+  for (int i = 0; i < N; i++) {
+    HandleScope inner_scope(isolate);
+    Handle<HeapObject> value =
+        i == 0 ? survivor : factory->NewFixedArray(1, NOT_TENURED);
+    Handle<WeakCell> weak_cell = factory->NewWeakCell(value);
+    CHECK(weak_cell->value()->IsFixedArray());
+    IncrementalMarking* marking = heap->incremental_marking();
+    if (marking->IsStopped()) marking->Start();
+    marking->Step(128, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
+    heap->CollectGarbage(NEW_SPACE);
+    CHECK(weak_cell->value()->IsFixedArray());
+    weak_cells[i] = inner_scope.CloseAndEscape(weak_cell);
+  }
+  heap->CollectAllGarbage(Heap::kNoGCFlags);
+  CHECK_EQ(*survivor, weak_cells[0]->value());
+  for (int i = 1; i < N; i++) {
+    CHECK(weak_cells[i]->cleared());
+  }
+}
+
+
 #ifdef DEBUG
 TEST(AddInstructionChangesNewSpacePromotion) {
   i::FLAG_allow_natives_syntax = true;
@@ -4320,7 +4850,7 @@
   CcTest::InitializeVM();
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope hscope(isolate);
-  v8::Handle<v8::ObjectTemplate> global =v8::ObjectTemplate::New(isolate);
+  v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
   global->Set(v8::String::NewFromUtf8(isolate, "interrupt"),
               v8::FunctionTemplate::New(isolate, RequestInterrupt));
   v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
@@ -4333,7 +4863,7 @@
       "eval('function f() {' + locals + 'return function() { return v0; }; }');"
       "interrupt();"  // This triggers a fake stack overflow in f.
       "f()()");
-  CHECK_EQ(42.0, result->ToNumber()->Value());
+  CHECK_EQ(42.0, result->ToNumber(isolate)->Value());
 }
 
 
@@ -4502,6 +5032,63 @@
 }
 
 
+TEST(Regress3631) {
+  i::FLAG_expose_gc = true;
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  IncrementalMarking* marking = CcTest::heap()->incremental_marking();
+  v8::Local<v8::Value> result = CompileRun(
+      "var weak_map = new WeakMap();"
+      "var future_keys = [];"
+      "for (var i = 0; i < 50; i++) {"
+      "  var key = {'k' : i + 0.1};"
+      "  weak_map.set(key, 1);"
+      "  future_keys.push({'x' : i + 0.2});"
+      "}"
+      "weak_map");
+  if (marking->IsStopped()) {
+    marking->Start();
+  }
+  // Incrementally mark the backing store.
+  Handle<JSObject> obj =
+      v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(result));
+  Handle<JSWeakCollection> weak_map(reinterpret_cast<JSWeakCollection*>(*obj));
+  while (!Marking::IsBlack(
+             Marking::MarkBitFrom(HeapObject::cast(weak_map->table()))) &&
+         !marking->IsStopped()) {
+    marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
+  }
+  // Stash the backing store in a handle.
+  Handle<Object> save(weak_map->table(), isolate);
+  // The following line will update the backing store.
+  CompileRun(
+      "for (var i = 0; i < 50; i++) {"
+      "  weak_map.set(future_keys[i], i);"
+      "}");
+  heap->incremental_marking()->set_should_hurry(true);
+  heap->CollectGarbage(OLD_POINTER_SPACE);
+}
+
+
+TEST(Regress442710) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  Factory* factory = isolate->factory();
+
+  HandleScope sc(isolate);
+  Handle<GlobalObject> global(CcTest::i_isolate()->context()->global_object());
+  Handle<JSArray> array = factory->NewJSArray(2);
+
+  Handle<String> name = factory->InternalizeUtf8String("testArray");
+  JSReceiver::SetProperty(global, name, array, SLOPPY).Check();
+  CompileRun("testArray[0] = 1; testArray[1] = 2; testArray.shift();");
+  heap->CollectGarbage(OLD_POINTER_SPACE);
+}
+
+
 #ifdef DEBUG
 TEST(PathTracer) {
   CcTest::InitializeVM();
diff --git a/test/cctest/test-lockers.cc b/test/cctest/test-lockers.cc
index ed315ce..dc5404e 100644
--- a/test/cctest/test-lockers.cc
+++ b/test/cctest/test-lockers.cc
@@ -141,6 +141,7 @@
 
   void Join() {
     semaphore_.Wait();
+    thread_.Join();
   }
 
   virtual void Run() = 0;
diff --git a/test/cctest/test-log-stack-tracer.cc b/test/cctest/test-log-stack-tracer.cc
index 334a201..714ad69 100644
--- a/test/cctest/test-log-stack-tracer.cc
+++ b/test/cctest/test-log-stack-tracer.cc
@@ -235,9 +235,9 @@
 
 static void CFuncDoTrace(byte dummy_parameter) {
   Address fp;
-#ifdef __GNUC__
+#if V8_HAS_BUILTIN_FRAME_ADDRESS
   fp = reinterpret_cast<Address>(__builtin_frame_address(0));
-#elif defined _MSC_VER
+#elif V8_CC_MSVC
   // Approximate a frame pointer address. We compile without base pointers,
   // so we can't trust ebp/rbp.
   fp = &dummy_parameter - 2 * sizeof(void*);  // NOLINT
diff --git a/test/cctest/test-log.cc b/test/cctest/test-log.cc
index 482f89f..eee3e13 100644
--- a/test/cctest/test-log.cc
+++ b/test/cctest/test-log.cc
@@ -42,6 +42,7 @@
 #include "src/natives.h"
 #include "src/utils.h"
 #include "src/v8threads.h"
+#include "src/version.h"
 #include "src/vm-state-inl.h"
 #include "test/cctest/cctest.h"
 
@@ -477,10 +478,9 @@
         isolate, log.start(), v8::String::kNormalString, log.length());
     initialize_logger.env()->Global()->Set(v8_str("_log"), log_str);
 
-    i::Vector<const unsigned char> source = TestSources::GetScriptsSource();
+    i::Vector<const char> source = TestSources::GetScriptsSource();
     v8::Handle<v8::String> source_str = v8::String::NewFromUtf8(
-        isolate, reinterpret_cast<const char*>(source.start()),
-        v8::String::kNormalString, source.length());
+        isolate, source.start(), v8::String::kNormalString, source.length());
     v8::TryCatch try_catch;
     v8::Handle<v8::Script> script = CompileWithOrigin(source_str, "");
     if (script.IsEmpty()) {
@@ -496,7 +496,7 @@
     }
     // The result either be a "true" literal or problem description.
     if (!result->IsTrue()) {
-      v8::Local<v8::String> s = result->ToString();
+      v8::Local<v8::String> s = result->ToString(isolate);
       i::ScopedVector<char> data(s->Utf8Length() + 1);
       CHECK_NE(NULL, data.start());
       s->WriteUtf8(data.start());
@@ -508,3 +508,23 @@
   }
   isolate->Dispose();
 }
+
+
+TEST(LogVersion) {
+  v8::Isolate* isolate;
+  {
+    ScopedLoggerInitializer initialize_logger;
+    isolate = initialize_logger.isolate();
+    bool exists = false;
+    i::Vector<const char> log(
+        i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true));
+    CHECK(exists);
+    i::EmbeddedVector<char, 100> ref_data;
+    i::SNPrintF(ref_data, "v8-version,%d,%d,%d,%d,%d", i::Version::GetMajor(),
+                i::Version::GetMinor(), i::Version::GetBuild(),
+                i::Version::GetPatch(), i::Version::IsCandidate());
+    CHECK_NE(NULL, StrNStr(log.start(), ref_data.start(), log.length()));
+    log.Dispose();
+  }
+  isolate->Dispose();
+}
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index c7d6531..64d995d 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -446,7 +446,7 @@
     bool write_permission = (buffer[position++] == 'w');
     CHECK(buffer[position] == '-' || buffer[position] == 'x');
     bool execute_permission = (buffer[position++] == 'x');
-    CHECK(buffer[position] == '-' || buffer[position] == 'p');
+    CHECK(buffer[position] == 's' || buffer[position] == 'p');
     bool private_mapping = (buffer[position++] == 'p');
     CHECK_EQ(buffer[position++], ' ');
     uintptr_t offset = ReadLong(buffer, &position, 16);
diff --git a/test/cctest/test-object-observe.cc b/test/cctest/test-object-observe.cc
index d208a26..2766a4f 100644
--- a/test/cctest/test-object-observe.cc
+++ b/test/cctest/test-object-observe.cc
@@ -130,6 +130,59 @@
 }
 
 
+TEST(DeliveryCallbackThrows) {
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
+  CompileRun(
+      "var obj = {};"
+      "var ordering = [];"
+      "function observer1() { ordering.push(1); };"
+      "function observer2() { ordering.push(2); };"
+      "function observer_throws() {"
+      "  ordering.push(0);"
+      "  throw new Error();"
+      "  ordering.push(-1);"
+      "};"
+      "Object.observe(obj, observer_throws.bind());"
+      "Object.observe(obj, observer1);"
+      "Object.observe(obj, observer_throws.bind());"
+      "Object.observe(obj, observer2);"
+      "Object.observe(obj, observer_throws.bind());"
+      "obj.foo = 'bar';");
+  CHECK_EQ(5, CompileRun("ordering.length")->Int32Value());
+  CHECK_EQ(0, CompileRun("ordering[0]")->Int32Value());
+  CHECK_EQ(1, CompileRun("ordering[1]")->Int32Value());
+  CHECK_EQ(0, CompileRun("ordering[2]")->Int32Value());
+  CHECK_EQ(2, CompileRun("ordering[3]")->Int32Value());
+  CHECK_EQ(0, CompileRun("ordering[4]")->Int32Value());
+}
+
+
+TEST(DeliveryChangesMutationInCallback) {
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
+  CompileRun(
+      "var obj = {};"
+      "var ordering = [];"
+      "function observer1(records) {"
+      "  ordering.push(100 + records.length);"
+      "  records.push(11);"
+      "  records.push(22);"
+      "};"
+      "function observer2(records) {"
+      "  ordering.push(200 + records.length);"
+      "  records.push(33);"
+      "  records.push(44);"
+      "};"
+      "Object.observe(obj, observer1);"
+      "Object.observe(obj, observer2);"
+      "obj.foo = 'bar';");
+  CHECK_EQ(2, CompileRun("ordering.length")->Int32Value());
+  CHECK_EQ(101, CompileRun("ordering[0]")->Int32Value());
+  CHECK_EQ(201, CompileRun("ordering[1]")->Int32Value());
+}
+
+
 TEST(DeliveryOrderingReentrant) {
   HandleScope scope(CcTest::isolate());
   LocalContext context(CcTest::isolate());
@@ -709,3 +762,76 @@
   CcTest::isolate()->ContextDisposedNotification();
   CheckSurvivingGlobalObjectsCount(1);
 }
+
+
+static void ObserverCallback(const FunctionCallbackInfo<Value>& args) {
+  *static_cast<int*>(Handle<External>::Cast(args.Data())->Value()) =
+      Handle<Array>::Cast(args[0])->Length();
+}
+
+
+TEST(ObjectObserveCallsCppFunction) {
+  Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+  LocalContext context(isolate);
+  int numRecordsSent = 0;
+  Handle<Function> observer =
+      Function::New(CcTest::isolate(), ObserverCallback,
+                    External::New(isolate, &numRecordsSent));
+  context->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "observer"),
+                         observer);
+  CompileRun(
+      "var obj = {};"
+      "Object.observe(obj, observer);"
+      "obj.foo = 1;"
+      "obj.bar = 2;");
+  CHECK_EQ(2, numRecordsSent);
+}
+
+
+TEST(ObjectObserveCallsFunctionTemplateInstance) {
+  Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+  LocalContext context(isolate);
+  int numRecordsSent = 0;
+  Handle<FunctionTemplate> tmpl = FunctionTemplate::New(
+      isolate, ObserverCallback, External::New(isolate, &numRecordsSent));
+  context->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "observer"),
+                         tmpl->GetFunction());
+  CompileRun(
+      "var obj = {};"
+      "Object.observe(obj, observer);"
+      "obj.foo = 1;"
+      "obj.bar = 2;");
+  CHECK_EQ(2, numRecordsSent);
+}
+
+
+static void AccessorGetter(Local<String> property,
+                           const PropertyCallbackInfo<Value>& info) {
+  info.GetReturnValue().Set(Integer::New(info.GetIsolate(), 42));
+}
+
+
+static void AccessorSetter(Local<String> property, Local<Value> value,
+                           const PropertyCallbackInfo<void>& info) {
+  info.GetReturnValue().SetUndefined();
+}
+
+
+TEST(APIAccessorsShouldNotNotify) {
+  Isolate* isolate = CcTest::isolate();
+  HandleScope handle_scope(isolate);
+  LocalContext context(isolate);
+  Handle<Object> object = Object::New(isolate);
+  object->SetAccessor(String::NewFromUtf8(isolate, "accessor"), &AccessorGetter,
+                      &AccessorSetter);
+  context->Global()->Set(String::NewFromUtf8(isolate, "obj"), object);
+  CompileRun(
+      "var records = null;"
+      "Object.observe(obj, function(r) { records = r });"
+      "obj.accessor = 43;");
+  CHECK(CompileRun("records")->IsNull());
+  CompileRun("Object.defineProperty(obj, 'accessor', { value: 44 });");
+  CHECK(CompileRun("records")->IsNull());
+}
diff --git a/test/cctest/test-ostreams.cc b/test/cctest/test-ostreams.cc
deleted file mode 100644
index c83f96d..0000000
--- a/test/cctest/test-ostreams.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <string.h>
-#include <limits>
-
-#include "include/v8stdint.h"
-#include "src/ostreams.h"
-#include "test/cctest/cctest.h"
-
-using namespace v8::internal;
-
-
-TEST(OStringStreamConstructor) {
-  OStringStream oss;
-  const size_t expected_size = 0;
-  CHECK(expected_size == oss.size());
-  CHECK_GT(oss.capacity(), 0);
-  CHECK_NE(NULL, oss.data());
-  CHECK_EQ("", oss.c_str());
-}
-
-
-#define TEST_STRING            \
-  "Ash nazg durbatuluk, "      \
-  "ash nazg gimbatul, "        \
-  "ash nazg thrakatuluk, "     \
-  "agh burzum-ishi krimpatul."
-
-TEST(OStringStreamGrow) {
-  OStringStream oss;
-  const int repeat = 30;
-  size_t len = strlen(TEST_STRING);
-  for (int i = 0; i < repeat; ++i) {
-    oss.write(TEST_STRING, len);
-  }
-  const char* expected =
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING;
-  const size_t expected_len = len * repeat;
-  CHECK(expected_len == oss.size());
-  CHECK_GT(oss.capacity(), 0);
-  CHECK_EQ(0, strncmp(expected, oss.data(), expected_len));
-  CHECK_EQ(expected, oss.c_str());
-}
-
-
-template <class T>
-static void check(const char* expected, T value) {
-  OStringStream oss;
-  oss << value << " " << hex << value;
-  CHECK_EQ(expected, oss.c_str());
-}
-
-
-TEST(NumericFormatting) {
-  check<bool>("0 0", false);
-  check<bool>("1 1", true);
-
-  check<int16_t>("-12345 cfc7", -12345);
-  check<int16_t>("-32768 8000", std::numeric_limits<int16_t>::min());
-  check<int16_t>("32767 7fff", std::numeric_limits<int16_t>::max());
-
-  check<uint16_t>("34567 8707", 34567);
-  check<uint16_t>("0 0", std::numeric_limits<uint16_t>::min());
-  check<uint16_t>("65535 ffff", std::numeric_limits<uint16_t>::max());
-
-  check<int32_t>("-1234567 ffed2979", -1234567);
-  check<int32_t>("-2147483648 80000000", std::numeric_limits<int32_t>::min());
-  check<int32_t>("2147483647 7fffffff", std::numeric_limits<int32_t>::max());
-
-  check<uint32_t>("3456789 34bf15", 3456789);
-  check<uint32_t>("0 0", std::numeric_limits<uint32_t>::min());
-  check<uint32_t>("4294967295 ffffffff", std::numeric_limits<uint32_t>::max());
-
-  check<int64_t>("-1234567 ffffffffffed2979", -1234567);
-  check<int64_t>("-9223372036854775808 8000000000000000",
-                 std::numeric_limits<int64_t>::min());
-  check<int64_t>("9223372036854775807 7fffffffffffffff",
-                 std::numeric_limits<int64_t>::max());
-
-  check<uint64_t>("3456789 34bf15", 3456789);
-  check<uint64_t>("0 0", std::numeric_limits<uint64_t>::min());
-  check<uint64_t>("18446744073709551615 ffffffffffffffff",
-                  std::numeric_limits<uint64_t>::max());
-
-  check<float>("0 0", 0.0f);
-  check<float>("123 123", 123.0f);
-  check<float>("-0.5 -0.5", -0.5f);
-  check<float>("1.25 1.25", 1.25f);
-  check<float>("0.0625 0.0625", 6.25e-2f);
-
-  check<double>("0 0", 0.0);
-  check<double>("123 123", 123.0);
-  check<double>("-0.5 -0.5", -0.5);
-  check<double>("1.25 1.25", 1.25);
-  check<double>("0.0625 0.0625", 6.25e-2);
-}
-
-
-TEST(CharacterOutput) {
-  check<char>("a a", 'a');
-  check<signed char>("B B", 'B');
-  check<unsigned char>("9 9", '9');
-  check<const char*>("bye bye", "bye");
-
-  OStringStream os;
-  os.put('H').write("ello", 4);
-  CHECK_EQ("Hello", os.c_str());
-}
-
-
-TEST(Manipulators) {
-  OStringStream os;
-  os << 123 << hex << 123 << endl << 123 << dec << 123 << 123;
-  CHECK_EQ("1237b\n7b123123", os.c_str());
-}
-
-
-class MiscStuff {
- public:
-  MiscStuff(int i, double d, const char* s) : i_(i), d_(d), s_(s) { }
-
- private:
-  friend OStream& operator<<(OStream& os, const MiscStuff& m);
-
-  int i_;
-  double d_;
-  const char* s_;
-};
-
-
-OStream& operator<<(OStream& os, const MiscStuff& m) {
-  return os << "{i:" << m.i_ << ", d:" << m.d_ << ", s:'" << m.s_ << "'}";
-}
-
-
-TEST(CustomOutput) {
-  OStringStream os;
-  MiscStuff m(123, 4.5, "Hurz!");
-  os << m;
-  CHECK_EQ("{i:123, d:4.5, s:'Hurz!'}", os.c_str());
-}
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index 72f2298..08caeab 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -31,6 +31,8 @@
 
 #include "src/v8.h"
 
+#include "src/ast.h"
+#include "src/ast-numbering.h"
 #include "src/ast-value-factory.h"
 #include "src/compiler.h"
 #include "src/execution.h"
@@ -317,8 +319,8 @@
 
     i::PreParser preparser(&scanner, &log, stack_limit);
     preparser.set_allow_lazy(true);
-    preparser.set_allow_natives_syntax(true);
-    preparser.set_allow_arrow_functions(true);
+    preparser.set_allow_natives(true);
+    preparser.set_allow_harmony_arrow_functions(true);
     i::PreParser::PreParseResult result = preparser.PreParseProgram();
     CHECK_EQ(i::PreParser::kPreParseSuccess, result);
     CHECK(!log.HasError());
@@ -452,14 +454,14 @@
   i::PreParser::PreParseResult result = preparser.PreParseProgram();
   CHECK_EQ(i::PreParser::kPreParseSuccess, result);
   i::ScriptData* sd = log.GetScriptData();
-  i::ParseData pd(sd);
-  pd.Initialize();
+  i::ParseData* pd = i::ParseData::FromCachedData(sd);
+  pd->Initialize();
 
   int first_function =
       static_cast<int>(strstr(program, "function") - program);
   int first_lbrace = first_function + i::StrLength("function () ");
   CHECK_EQ('{', program[first_lbrace]);
-  i::FunctionEntry entry1 = pd.GetFunctionEntry(first_lbrace);
+  i::FunctionEntry entry1 = pd->GetFunctionEntry(first_lbrace);
   CHECK(!entry1.is_valid());
 
   int second_function =
@@ -467,10 +469,11 @@
   int second_lbrace =
       second_function + i::StrLength("function () ");
   CHECK_EQ('{', program[second_lbrace]);
-  i::FunctionEntry entry2 = pd.GetFunctionEntry(second_lbrace);
+  i::FunctionEntry entry2 = pd->GetFunctionEntry(second_lbrace);
   CHECK(entry2.is_valid());
   CHECK_EQ('}', program[entry2.end_pos() - 1]);
   delete sd;
+  delete pd;
 }
 
 
@@ -496,7 +499,7 @@
 
   i::PreParser preparser(&scanner, &log, stack_limit);
   preparser.set_allow_lazy(true);
-  preparser.set_allow_arrow_functions(true);
+  preparser.set_allow_harmony_arrow_functions(true);
   i::PreParser::PreParseResult result = preparser.PreParseProgram();
   CHECK_EQ(i::PreParser::kPreParseStackOverflow, result);
 }
@@ -917,6 +920,142 @@
 }
 
 
+TEST(ScopeUsesArgumentsSuperThis) {
+  static const struct {
+    const char* prefix;
+    const char* suffix;
+  } surroundings[] = {
+    { "function f() {", "}" },
+    { "var f = () => {", "}" },
+  };
+
+  enum Expected {
+    NONE = 0,
+    ARGUMENTS = 1,
+    SUPER_PROPERTY = 2,
+    SUPER_CONSTRUCTOR_CALL = 4,
+    THIS = 8,
+    INNER_ARGUMENTS = 16,
+    INNER_SUPER_PROPERTY = 32,
+    INNER_SUPER_CONSTRUCTOR_CALL = 64,
+    INNER_THIS = 128
+  };
+
+  static const struct {
+    const char* body;
+    int expected;
+  } source_data[] = {
+        {"", NONE},
+        {"return this", THIS},
+        {"return arguments", ARGUMENTS},
+        {"return super()", SUPER_CONSTRUCTOR_CALL},
+        {"return super.x", SUPER_PROPERTY},
+        {"return arguments[0]", ARGUMENTS},
+        {"return this + arguments[0]", ARGUMENTS | THIS},
+        {"return this + arguments[0] + super.x",
+         ARGUMENTS | SUPER_PROPERTY | THIS},
+        {"return x => this + x", INNER_THIS},
+        {"return x => super() + x", INNER_SUPER_CONSTRUCTOR_CALL},
+        {"this.foo = 42;", THIS},
+        {"this.foo();", THIS},
+        {"if (foo()) { this.f() }", THIS},
+        {"if (foo()) { super.f() }", SUPER_PROPERTY},
+        {"if (arguments.length) { this.f() }", ARGUMENTS | THIS},
+        {"while (true) { this.f() }", THIS},
+        {"while (true) { super.f() }", SUPER_PROPERTY},
+        {"if (true) { while (true) this.foo(arguments) }", ARGUMENTS | THIS},
+        // Multiple nesting levels must work as well.
+        {"while (true) { while (true) { while (true) return this } }", THIS},
+        {"while (true) { while (true) { while (true) return super() } }",
+         SUPER_CONSTRUCTOR_CALL},
+        {"if (1) { return () => { while (true) new this() } }", INNER_THIS},
+        {"if (1) { return () => { while (true) new super() } }", NONE},
+        {"if (1) { return () => { while (true) new new super() } }", NONE},
+        // Note that propagation of the inner_uses_this() value does not
+        // cross boundaries of normal functions onto parent scopes.
+        {"return function (x) { return this + x }", NONE},
+        {"return function (x) { return super() + x }", NONE},
+        {"var x = function () { this.foo = 42 };", NONE},
+        {"var x = function () { super.foo = 42 };", NONE},
+        {"if (1) { return function () { while (true) new this() } }", NONE},
+        {"if (1) { return function () { while (true) new super() } }", NONE},
+        {"return function (x) { return () => this }", NONE},
+        {"return function (x) { return () => super() }", NONE},
+        // Flags must be correctly set when using block scoping.
+        {"\"use strict\"; while (true) { let x; this, arguments; }",
+         INNER_ARGUMENTS | INNER_THIS},
+        {"\"use strict\"; while (true) { let x; this, super(), arguments; }",
+         INNER_ARGUMENTS | INNER_SUPER_CONSTRUCTOR_CALL | INNER_THIS},
+        {"\"use strict\"; if (foo()) { let x; this.f() }", INNER_THIS},
+        {"\"use strict\"; if (foo()) { let x; super.f() }",
+         INNER_SUPER_PROPERTY},
+        {"\"use strict\"; if (1) {"
+         "  let x; return function () { return this + super() + arguments }"
+         "}",
+         NONE},
+    };
+
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+
+  v8::HandleScope handles(CcTest::isolate());
+  v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
+  v8::Context::Scope context_scope(context);
+
+  isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
+                                        128 * 1024);
+
+  for (unsigned j = 0; j < arraysize(surroundings); ++j) {
+    for (unsigned i = 0; i < arraysize(source_data); ++i) {
+      int kProgramByteSize = i::StrLength(surroundings[j].prefix) +
+                             i::StrLength(surroundings[j].suffix) +
+                             i::StrLength(source_data[i].body);
+      i::ScopedVector<char> program(kProgramByteSize + 1);
+      i::SNPrintF(program, "%s%s%s", surroundings[j].prefix,
+                  source_data[i].body, surroundings[j].suffix);
+      i::Handle<i::String> source =
+          factory->NewStringFromUtf8(i::CStrVector(program.start()))
+              .ToHandleChecked();
+      i::Handle<i::Script> script = factory->NewScript(source);
+      i::CompilationInfoWithZone info(script);
+      i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(),
+                                         isolate->heap()->HashSeed(),
+                                         isolate->unicode_cache()};
+      i::Parser parser(&info, &parse_info);
+      parser.set_allow_harmony_arrow_functions(true);
+      parser.set_allow_harmony_classes(true);
+      parser.set_allow_harmony_scoping(true);
+      info.MarkAsGlobal();
+      parser.Parse();
+      CHECK(i::Rewriter::Rewrite(&info));
+      CHECK(i::Scope::Analyze(&info));
+      CHECK(info.function() != NULL);
+
+      i::Scope* script_scope = info.function()->scope();
+      CHECK(script_scope->is_script_scope());
+      CHECK_EQ(1, script_scope->inner_scopes()->length());
+
+      i::Scope* scope = script_scope->inner_scopes()->at(0);
+      CHECK_EQ((source_data[i].expected & ARGUMENTS) != 0,
+               scope->uses_arguments());
+      CHECK_EQ((source_data[i].expected & SUPER_PROPERTY) != 0,
+               scope->uses_super_property());
+      CHECK_EQ((source_data[i].expected & SUPER_CONSTRUCTOR_CALL) != 0,
+               scope->uses_super_constructor_call());
+      CHECK_EQ((source_data[i].expected & THIS) != 0, scope->uses_this());
+      CHECK_EQ((source_data[i].expected & INNER_ARGUMENTS) != 0,
+               scope->inner_uses_arguments());
+      CHECK_EQ((source_data[i].expected & INNER_SUPER_PROPERTY) != 0,
+               scope->inner_uses_super_property());
+      CHECK_EQ((source_data[i].expected & INNER_SUPER_CONSTRUCTOR_CALL) != 0,
+               scope->inner_uses_super_constructor_call());
+      CHECK_EQ((source_data[i].expected & INNER_THIS) != 0,
+               scope->inner_uses_this());
+    }
+  }
+}
+
+
 TEST(ScopePositions) {
   v8::internal::FLAG_harmony_scoping = true;
 
@@ -974,11 +1113,10 @@
       "    infunction;\n"
       "  }", "\n"
       "  more;", i::FUNCTION_SCOPE, i::SLOPPY },
-    // TODO(aperez): Change to use i::ARROW_SCOPE when implemented
     { "  start;\n", "(a,b) => a + b", "; more;",
-      i::FUNCTION_SCOPE, i::SLOPPY },
+      i::ARROW_SCOPE, i::SLOPPY },
     { "  start;\n", "(a,b) => { return a+b; }", "\nmore;",
-      i::FUNCTION_SCOPE, i::SLOPPY },
+      i::ARROW_SCOPE, i::SLOPPY },
     { "  start;\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
       i::FUNCTION_SCOPE, i::SLOPPY },
@@ -1137,7 +1275,7 @@
     i::Parser parser(&info, &parse_info);
     parser.set_allow_lazy(true);
     parser.set_allow_harmony_scoping(true);
-    parser.set_allow_arrow_functions(true);
+    parser.set_allow_harmony_arrow_functions(true);
     info.MarkAsGlobal();
     info.SetStrictMode(source_data[i].strict_mode);
     parser.Parse();
@@ -1145,7 +1283,7 @@
 
     // Check scope types and positions.
     i::Scope* scope = info.function()->scope();
-    CHECK(scope->is_global_scope());
+    CHECK(scope->is_script_scope());
     CHECK_EQ(scope->start_position(), 0);
     CHECK_EQ(scope->end_position(), kProgramSize);
     CHECK_EQ(scope->inner_scopes()->length(), 1);
@@ -1211,13 +1349,16 @@
 
 enum ParserFlag {
   kAllowLazy,
-  kAllowNativesSyntax,
+  kAllowNatives,
   kAllowHarmonyScoping,
-  kAllowModules,
+  kAllowHarmonyModules,
   kAllowHarmonyNumericLiterals,
-  kAllowArrowFunctions,
-  kAllowClasses,
-  kAllowHarmonyObjectLiterals
+  kAllowHarmonyArrowFunctions,
+  kAllowHarmonyClasses,
+  kAllowHarmonyObjectLiterals,
+  kAllowHarmonyTemplates,
+  kAllowHarmonySloppy,
+  kAllowHarmonyUnicode
 };
 
 
@@ -1231,15 +1372,19 @@
 void SetParserFlags(i::ParserBase<Traits>* parser,
                     i::EnumSet<ParserFlag> flags) {
   parser->set_allow_lazy(flags.Contains(kAllowLazy));
-  parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax));
+  parser->set_allow_natives(flags.Contains(kAllowNatives));
   parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping));
-  parser->set_allow_modules(flags.Contains(kAllowModules));
+  parser->set_allow_harmony_modules(flags.Contains(kAllowHarmonyModules));
   parser->set_allow_harmony_numeric_literals(
       flags.Contains(kAllowHarmonyNumericLiterals));
   parser->set_allow_harmony_object_literals(
       flags.Contains(kAllowHarmonyObjectLiterals));
-  parser->set_allow_arrow_functions(flags.Contains(kAllowArrowFunctions));
-  parser->set_allow_classes(flags.Contains(kAllowClasses));
+  parser->set_allow_harmony_arrow_functions(
+      flags.Contains(kAllowHarmonyArrowFunctions));
+  parser->set_allow_harmony_classes(flags.Contains(kAllowHarmonyClasses));
+  parser->set_allow_harmony_templates(flags.Contains(kAllowHarmonyTemplates));
+  parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy));
+  parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode));
 }
 
 
@@ -1250,6 +1395,8 @@
   i::Factory* factory = isolate->factory();
 
   uintptr_t stack_limit = isolate->stack_guard()->real_climit();
+  int preparser_materialized_literals = -1;
+  int parser_materialized_literals = -2;
 
   // Preparse the data.
   i::CompleteParserRecorder log;
@@ -1259,7 +1406,8 @@
     i::PreParser preparser(&scanner, &log, stack_limit);
     SetParserFlags(&preparser, flags);
     scanner.Initialize(&stream);
-    i::PreParser::PreParseResult result = preparser.PreParseProgram();
+    i::PreParser::PreParseResult result = preparser.PreParseProgram(
+        &preparser_materialized_literals);
     CHECK_EQ(i::PreParser::kPreParseSuccess, result);
   }
 
@@ -1278,6 +1426,9 @@
     info.MarkAsGlobal();
     parser.Parse();
     function = info.function();
+    if (function) {
+      parser_materialized_literals = function->materialized_literal_count();
+    }
   }
 
   // Check that preparsing fails iff parsing fails.
@@ -1343,6 +1494,15 @@
         "However, parser and preparser succeeded",
         source->ToCString().get());
     CHECK(false);
+  } else if (preparser_materialized_literals != parser_materialized_literals) {
+    v8::base::OS::Print(
+        "Preparser materialized literals (%d) differ from Parser materialized "
+        "literals (%d) on:\n"
+        "\t%s\n"
+        "However, parser and preparser succeeded",
+        preparser_materialized_literals, parser_materialized_literals,
+        source->ToCString().get());
+    CHECK(false);
   }
 }
 
@@ -1352,7 +1512,9 @@
                     size_t varying_flags_length,
                     ParserSyncTestResult result = kSuccessOrError,
                     const ParserFlag* always_true_flags = NULL,
-                    size_t always_true_flags_length = 0) {
+                    size_t always_true_flags_length = 0,
+                    const ParserFlag* always_false_flags = NULL,
+                    size_t always_false_flags_length = 0) {
   i::Handle<i::String> str =
       CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source);
   for (int bits = 0; bits < (1 << varying_flags_length); bits++) {
@@ -1365,6 +1527,10 @@
          ++flag_index) {
       flags.Add(always_true_flags[flag_index]);
     }
+    for (size_t flag_index = 0; flag_index < always_false_flags_length;
+         ++flag_index) {
+      flags.Remove(always_false_flags[flag_index]);
+    }
     TestParserSyncWithFlags(str, flags, result);
   }
 }
@@ -1399,7 +1565,7 @@
     "if (false) {} else ;",
     "if (false) {} else {}",
     "if (false) {} else 12",
-    "if (false) ;"
+    "if (false) ;",
     "if (false) {}",
     "if (false) 12",
     "do {} while (false)",
@@ -1419,8 +1585,8 @@
     "with ({}) ;",
     "with ({}) {}",
     "with ({}) 12",
-    "switch ({}) { default: }"
-    "label3: "
+    "switch ({}) { default: }",
+    "label3: ",
     "throw",
     "throw  12",
     "throw\n12",
@@ -1447,16 +1613,6 @@
   CcTest::i_isolate()->stack_guard()->SetStackLimit(
       i::GetCurrentStackPosition() - 128 * 1024);
 
-  static const ParserFlag flags1[] = {
-    kAllowArrowFunctions,
-    kAllowClasses,
-    kAllowHarmonyNumericLiterals,
-    kAllowHarmonyObjectLiterals,
-    kAllowHarmonyScoping,
-    kAllowLazy,
-    kAllowModules,
-  };
-
   for (int i = 0; context_data[i][0] != NULL; ++i) {
     for (int j = 0; statement_data[j] != NULL; ++j) {
       for (int k = 0; termination_data[k] != NULL; ++k) {
@@ -1476,7 +1632,7 @@
             termination_data[k],
             context_data[i][1]);
         CHECK(length == kProgramSize);
-        TestParserSync(program.start(), flags1, arraysize(flags1));
+        TestParserSync(program.start(), NULL, 0);
       }
     }
   }
@@ -1488,7 +1644,7 @@
   TestParserSync("0o1234", flags2, arraysize(flags2));
   TestParserSync("0b1011", flags2, arraysize(flags2));
 
-  static const ParserFlag flags3[] = { kAllowNativesSyntax };
+  static const ParserFlag flags3[] = { kAllowNatives };
   TestParserSync("%DebugPrint(123)", flags3, arraysize(flags3));
 }
 
@@ -1522,7 +1678,9 @@
                        const ParserFlag* flags = NULL,
                        int flags_len = 0,
                        const ParserFlag* always_true_flags = NULL,
-                       int always_true_flags_len = 0) {
+                       int always_true_len = 0,
+                       const ParserFlag* always_false_flags = NULL,
+                       int always_false_len = 0) {
   v8::HandleScope handles(CcTest::isolate());
   v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
   v8::Context::Scope context_scope(context);
@@ -1530,36 +1688,32 @@
   CcTest::i_isolate()->stack_guard()->SetStackLimit(
       i::GetCurrentStackPosition() - 128 * 1024);
 
+  // Experimental feature flags should not go here; pass the flags as
+  // always_true_flags if the test needs them.
   static const ParserFlag default_flags[] = {
-    kAllowArrowFunctions,
-    kAllowClasses,
-    kAllowHarmonyNumericLiterals,
-    kAllowHarmonyObjectLiterals,
-    kAllowHarmonyScoping,
     kAllowLazy,
-    kAllowModules,
-    kAllowNativesSyntax,
+    kAllowNatives,
   };
   ParserFlag* generated_flags = NULL;
   if (flags == NULL) {
     flags = default_flags;
     flags_len = arraysize(default_flags);
-    if (always_true_flags != NULL) {
-      // Remove always_true_flags from default_flags.
-      CHECK(always_true_flags_len < flags_len);
-      generated_flags = new ParserFlag[flags_len - always_true_flags_len];
+    if (always_true_flags != NULL || always_false_flags != NULL) {
+      // Remove always_true/false_flags from default_flags (if present).
+      CHECK((always_true_flags != NULL) == (always_true_len > 0));
+      CHECK((always_false_flags != NULL) == (always_false_len > 0));
+      generated_flags = new ParserFlag[flags_len + always_true_len];
       int flag_index = 0;
       for (int i = 0; i < flags_len; ++i) {
         bool use_flag = true;
-        for (int j = 0; j < always_true_flags_len; ++j) {
-          if (flags[i] == always_true_flags[j]) {
-            use_flag = false;
-            break;
-          }
+        for (int j = 0; use_flag && j < always_true_len; ++j) {
+          if (flags[i] == always_true_flags[j]) use_flag = false;
+        }
+        for (int j = 0; use_flag && j < always_false_len; ++j) {
+          if (flags[i] == always_false_flags[j]) use_flag = false;
         }
         if (use_flag) generated_flags[flag_index++] = flags[i];
       }
-      CHECK(flag_index == flags_len - always_true_flags_len);
       flags_len = flag_index;
       flags = generated_flags;
     }
@@ -1584,7 +1738,9 @@
                      flags_len,
                      result,
                      always_true_flags,
-                     always_true_flags_len);
+                     always_true_len,
+                     always_false_flags,
+                     always_false_len);
     }
   }
   delete[] generated_flags;
@@ -1691,45 +1847,70 @@
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
 
 
+#define FUTURE_STRICT_RESERVED_WORDS(V) \
+  V(implements)                         \
+  V(interface)                          \
+  V(let)                                \
+  V(package)                            \
+  V(private)                            \
+  V(protected)                          \
+  V(public)                             \
+  V(static)                             \
+  V(yield)
+
+
+#define LIMITED_FUTURE_STRICT_RESERVED_WORDS(V) \
+  V(implements)                                 \
+  V(let)                                        \
+  V(static)                                     \
+  V(yield)
+
+
+#define FUTURE_STRICT_RESERVED_STATEMENTS(NAME) \
+  "var " #NAME ";",                             \
+  "var foo, " #NAME ";",                        \
+  "try { } catch (" #NAME ") { }",              \
+  "function " #NAME "() { }",                   \
+  "(function " #NAME "() { })",                 \
+  "function foo(" #NAME ") { }",                \
+  "function foo(bar, " #NAME ") { }",           \
+  #NAME " = 1;",                                \
+  #NAME " += 1;",                               \
+  "var foo = " #NAME " = 1;",                   \
+  "++" #NAME ";",                               \
+  #NAME " ++;",
+
+
 TEST(ErrorsFutureStrictReservedWords) {
   // Tests that both preparsing and parsing produce the right kind of errors for
   // using future strict reserved words as identifiers. Without the strict mode,
   // it's ok to use future strict reserved words as identifiers. With the strict
   // mode, it isn't.
   const char* context_data[][2] = {
-    { "\"use strict\";", "" },
     { "function test_func() {\"use strict\"; ", "}"},
     { "() => { \"use strict\"; ", "}" },
     { NULL, NULL }
   };
 
-  const char* statement_data[] = {
-    "var interface;",
-    "var foo, interface;",
-    "try { } catch (interface) { }",
-    "function interface() { }",
-    "function foo(interface) { }",
-    "function foo(bar, interface) { }",
-    "interface = 1;",
-    "var foo = interface = 1;",
-    "++interface;",
-    "interface++;",
-    "var yield = 13;",
+  const char* statement_data[] {
+    LIMITED_FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
-  RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
-                    arraysize(always_flags));
+  RunParserSyncTest(context_data, statement_data, kError);
+  RunParserSyncTest(context_data, statement_data, kError);
 }
 
 
+#undef LIMITED_FUTURE_STRICT_RESERVED_WORDS
+
+
 TEST(NoErrorsFutureStrictReservedWords) {
   const char* context_data[][2] = {
     { "", "" },
@@ -1739,23 +1920,18 @@
   };
 
   const char* statement_data[] = {
-    "var interface;",
-    "var foo, interface;",
-    "try { } catch (interface) { }",
-    "function interface() { }",
-    "function foo(interface) { }",
-    "function foo(bar, interface) { }",
-    "interface = 1;",
-    "var foo = interface = 1;",
-    "++interface;",
-    "interface++;",
-    "var yield = 13;",
+    FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
+
+  static const ParserFlag classes_flags[] = {
+      kAllowHarmonyArrowFunctions, kAllowHarmonyClasses, kAllowHarmonyScoping};
+  RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+                    classes_flags, arraysize(classes_flags));
 }
 
 
@@ -2135,12 +2311,13 @@
     { NULL, NULL }
   };
 
+#define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
   const char* statement_data[] = {
     "super: while(true) { break super; }",
-    "interface: while(true) { break interface; }",
-    "yield: while(true) { break yield; }",
+    FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
     NULL
   };
+#undef LABELLED_WHILE
 
   RunParserSyncTest(context_data, statement_data, kError);
 }
@@ -2165,7 +2342,28 @@
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
+  RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(NoErrorsFutureStrictReservedAsLabelsSloppy) {
+  const char* context_data[][2] = {
+    { "", ""},
+    { "function test_func() {", "}" },
+    { "() => {", "}" },
+    { NULL, NULL }
+  };
+
+#define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
+  const char* statement_data[] {
+    FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
+    NULL
+  };
+#undef LABELLED_WHILE
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -2285,17 +2483,18 @@
     i::ScriptData* sd = NULL;
     info.SetCachedData(&sd, v8::ScriptCompiler::kProduceParserCache);
     i::Parser::Parse(&info, true);
-    i::ParseData pd(sd);
+    i::ParseData* pd = i::ParseData::FromCachedData(sd);
 
-    if (pd.FunctionCount() != test_cases[i].functions) {
+    if (pd->FunctionCount() != test_cases[i].functions) {
       v8::base::OS::Print(
           "Expected preparse data for program:\n"
           "\t%s\n"
           "to contain %d functions, however, received %d functions.\n",
-          program, test_cases[i].functions, pd.FunctionCount());
+          program, test_cases[i].functions, pd->FunctionCount());
       CHECK(false);
     }
     delete sd;
+    delete pd;
   }
 }
 
@@ -2416,9 +2615,9 @@
     NULL
   };
 
-  // This test requires kAllowNativesSyntax to succeed.
+  // This test requires kAllowNatives to succeed.
   static const ParserFlag always_true_flags[] = {
-    kAllowNativesSyntax
+    kAllowNatives
   };
 
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
@@ -2904,11 +3103,11 @@
   const i::AstRawString* name = avf.GetOneByteString("result");
   i::Handle<i::String> str = name->string();
   CHECK(str->IsInternalizedString());
-  i::Scope* global_scope =
-      new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
-  global_scope->Initialize();
-  i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
-  DCHECK(s != global_scope);
+  i::Scope* script_scope =
+      new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+  script_scope->Initialize();
+  i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+  DCHECK(s != script_scope);
   DCHECK(name != NULL);
 
   // Get result from h's function context (that is f's context)
@@ -2951,11 +3150,11 @@
   i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
   avf.Internalize(isolate);
 
-  i::Scope* global_scope =
-      new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
-  global_scope->Initialize();
-  i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
-  DCHECK(s != global_scope);
+  i::Scope* script_scope =
+      new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+  script_scope->Initialize();
+  i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+  DCHECK(s != script_scope);
   const i::AstRawString* name_x = avf.GetOneByteString("x");
 
   // Get result from f's function context (that is g's outer context)
@@ -2998,11 +3197,11 @@
   i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
   avf.Internalize(isolate);
 
-  i::Scope* global_scope =
-      new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
-  global_scope->Initialize();
-  i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
-  DCHECK(s != global_scope);
+  i::Scope* script_scope =
+      new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+  script_scope->Initialize();
+  i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+  DCHECK(s != script_scope);
   const i::AstRawString* name_x = avf.GetOneByteString("x");
   const i::AstRawString* name_f = avf.GetOneByteString("f");
   const i::AstRawString* name_y = avf.GetOneByteString("y");
@@ -3156,8 +3355,7 @@
           i::Parser parser(&info, &parse_info);
           parser.set_allow_harmony_scoping(true);
           CHECK(parser.Parse());
-          CHECK(i::Rewriter::Rewrite(&info));
-          CHECK(i::Scope::Analyze(&info));
+          CHECK(i::Compiler::Analyze(&info));
           CHECK(info.function() != NULL);
 
           i::Scope* scope = info.function()->scope();
@@ -3304,7 +3502,7 @@
 
   // The test is quite slow, so run it with a reduced set of flags.
   static const ParserFlag flags[] = {kAllowLazy, kAllowHarmonyScoping};
-  static const ParserFlag always_flags[] = { kAllowArrowFunctions };
+  static const ParserFlag always_flags[] = { kAllowHarmonyArrowFunctions };
   RunParserSyncTest(context_data, statement_data, kError, flags,
                     arraysize(flags), always_flags, arraysize(always_flags));
 }
@@ -3358,7 +3556,7 @@
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3383,7 +3581,7 @@
     "z.super",  // Ok, property lookup.
     NULL};
 
-  static const ParserFlag always_flags[] = {kAllowClasses};
+  static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3402,7 +3600,7 @@
     "f(super)",
     NULL};
 
-  static const ParserFlag always_flags[] = {kAllowClasses};
+  static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
   RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3585,7 +3783,8 @@
     "class name extends class base {} {}",
     NULL};
 
-  static const ParserFlag always_flags[] = {kAllowClasses};
+  static const ParserFlag always_flags[] = {
+      kAllowHarmonyClasses, kAllowHarmonySloppy};
   RunParserSyncTest(context_data, class_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3604,7 +3803,8 @@
     "class name extends class base {} {}",
     NULL};
 
-  static const ParserFlag always_flags[] = {kAllowClasses};
+  static const ParserFlag always_flags[] = {
+      kAllowHarmonyClasses, kAllowHarmonySloppy};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3648,8 +3848,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3706,8 +3907,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3737,8 +3939,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3774,8 +3977,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyNumericLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyNumericLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3804,8 +4008,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_name, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3837,8 +4042,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_name, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3855,11 +4061,19 @@
     "static get prototype() {}",
     "static set prototype(_) {}",
     "static *prototype() {}",
+    "static 'prototype'() {}",
+    "static *'prototype'() {}",
+    "static prot\\u006ftype() {}",
+    "static 'prot\\u006ftype'() {}",
+    "static get 'prot\\u006ftype'() {}",
+    "static set 'prot\\u006ftype'(_) {}",
+    "static *'prot\\u006ftype'() {}",
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3875,11 +4089,19 @@
     "get constructor() {}",
     "get constructor(_) {}",
     "*constructor() {}",
+    "get 'constructor'() {}",
+    "*'constructor'() {}",
+    "get c\\u006fnstructor() {}",
+    "*c\\u006fnstructor() {}",
+    "get 'c\\u006fnstructor'() {}",
+    "get 'c\\u006fnstructor'(_) {}",
+    "*'c\\u006fnstructor'() {}",
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3900,8 +4122,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3909,9 +4132,6 @@
 
 
 TEST(ClassMultipleConstructorErrors) {
-  // We currently do not allow any duplicate properties in class bodies. This
-  // test ensures that when we change that we still throw on duplicate
-  // constructors.
   const char* context_data[][2] = {{"class C {", "}"},
                                    {"(class {", "});"},
                                    {NULL, NULL}};
@@ -3921,17 +4141,16 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
 
 
-// TODO(arv): We should allow duplicate property names.
-// https://code.google.com/p/v8/issues/detail?id=3570
-DISABLED_TEST(ClassMultiplePropertyNamesNoErrors) {
+TEST(ClassMultiplePropertyNamesNoErrors) {
   const char* context_data[][2] = {{"class C {", "}"},
                                    {"(class {", "});"},
                                    {NULL, NULL}};
@@ -3940,11 +4159,14 @@
     "constructor() {}; static constructor() {}",
     "m() {}; static m() {}",
     "m() {}; m() {}",
+    "static m() {}; static m() {}",
+    "get m() {}; set m(_) {}; get m() {}; set m(_) {};",
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3963,9 +4185,422 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
+
+
+TEST(ObjectLiteralPropertyShorthandKeywordsError) {
+  const char* context_data[][2] = {{"({", "});"},
+                                   {"'use strict'; ({", "});"},
+                                   {NULL, NULL}};
+
+  const char* name_data[] = {
+    "break",
+    "case",
+    "catch",
+    "class",
+    "const",
+    "continue",
+    "debugger",
+    "default",
+    "delete",
+    "do",
+    "else",
+    "enum",
+    "export",
+    "extends",
+    "false",
+    "finally",
+    "for",
+    "function",
+    "if",
+    "import",
+    "in",
+    "instanceof",
+    "new",
+    "null",
+    "return",
+    "super",
+    "switch",
+    "this",
+    "throw",
+    "true",
+    "try",
+    "typeof",
+    "var",
+    "void",
+    "while",
+    "with",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, name_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ObjectLiteralPropertyShorthandStrictKeywords) {
+  const char* context_data[][2] = {{"({", "});"},
+                                   {NULL, NULL}};
+
+  const char* name_data[] = {
+    "implements",
+    "interface",
+    "let",
+    "package",
+    "private",
+    "protected",
+    "public",
+    "static",
+    "yield",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+
+  const char* context_strict_data[][2] = {{"'use strict'; ({", "});"},
+                                          {NULL, NULL}};
+  RunParserSyncTest(context_strict_data, name_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ObjectLiteralPropertyShorthandError) {
+  const char* context_data[][2] = {{"({", "});"},
+                                   {"'use strict'; ({", "});"},
+                                   {NULL, NULL}};
+
+  const char* name_data[] = {
+    "1",
+    "1.2",
+    "0",
+    "0.1",
+    "1.0",
+    "1e1",
+    "0x1",
+    "\"s\"",
+    "'s'",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, name_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ObjectLiteralPropertyShorthandYieldInGeneratorError) {
+  const char* context_data[][2] = {{"", ""},
+                                   {NULL, NULL}};
+
+  const char* name_data[] = {
+    "function* g() { ({yield}); }",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, name_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ConstParsingInForIn) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "for(const x = 1; ; ) {}",
+      "for(const x = 1, y = 2;;){}",
+      "for(const x in [1,2,3]) {}",
+      "for(const x of [1,2,3]) {}",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyScoping};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(ConstParsingInForInError) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "for(const x,y = 1; ; ) {}",
+      "for(const x = 4 in [1,2,3]) {}",
+      "for(const x = 4, y in [1,2,3]) {}",
+      "for(const x = 4 of [1,2,3]) {}",
+      "for(const x = 4, y of [1,2,3]) {}",
+      "for(const x = 1, y = 2 in []) {}",
+      "for(const x,y in []) {}",
+      "for(const x = 1, y = 2 of []) {}",
+      "for(const x,y of []) {}",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyScoping};
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(InvalidUnicodeEscapes) {
+  const char* context_data[][2] = {{"", ""},
+                                   {"'use strict';", ""},
+                                   {NULL, NULL}};
+  const char* data[] = {
+    "var foob\\u123r = 0;",
+    "var \\u123roo = 0;",
+    "\"foob\\u123rr\"",
+    // No escapes allowed in regexp flags
+    "/regex/\\u0069g",
+    "/regex/\\u006g",
+    // Braces gone wrong
+    "var foob\\u{c481r = 0;",
+    "var foob\\uc481}r = 0;",
+    "var \\u{0052oo = 0;",
+    "var \\u0052}oo = 0;",
+    "\"foob\\u{c481r\"",
+    "var foob\\u{}ar = 0;",
+    // Too high value for the unicode escape
+    "\"\\u{110000}\"",
+    // Not an unicode escape
+    "var foob\\v1234r = 0;",
+    "var foob\\U1234r = 0;",
+    "var foob\\v{1234}r = 0;",
+    "var foob\\U{1234}r = 0;",
+    NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyUnicode};
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(UnicodeEscapes) {
+  const char* context_data[][2] = {{"", ""},
+                                   {"'use strict';", ""},
+                                   {NULL, NULL}};
+  const char* data[] = {
+    // Identifier starting with escape
+    "var \\u0052oo = 0;",
+    "var \\u{0052}oo = 0;",
+    "var \\u{52}oo = 0;",
+    "var \\u{00000000052}oo = 0;",
+    // Identifier with an escape but not starting with an escape
+    "var foob\\uc481r = 0;",
+    "var foob\\u{c481}r = 0;",
+    // String with an escape
+    "\"foob\\uc481r\"",
+    "\"foob\\{uc481}r\"",
+    // This character is a valid unicode character, representable as a surrogate
+    // pair, not representable as 4 hex digits.
+    "\"foo\\u{10e6d}\"",
+    // Max value for the unicode escape
+    "\"\\u{10ffff}\"",
+    NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyUnicode};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(ScanTemplateLiterals) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';"
+                                    "  var a, b, c; return ", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "``",
+      "`no-subst-template`",
+      "`template-head${a}`",
+      "`${a}`",
+      "`${a}template-tail`",
+      "`template-head${a}template-tail`",
+      "`${a}${b}${c}`",
+      "`a${a}b${b}c${c}`",
+      "`${a}a${b}b${c}c`",
+      "`foo\n\nbar\r\nbaz`",
+      "`foo\n\n${  bar  }\r\nbaz`",
+      "`foo${a /* comment */}`",
+      "`foo${a // comment\n}`",
+      "`foo${a \n}`",
+      "`foo${a \r\n}`",
+      "`foo${a \r}`",
+      "`foo${/* comment */ a}`",
+      "`foo${// comment\na}`",
+      "`foo${\n a}`",
+      "`foo${\r\n a}`",
+      "`foo${\r a}`",
+      "`foo${'a' in a}`",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(ScanTaggedTemplateLiterals) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';"
+                                    "  function tag() {}"
+                                    "  var a, b, c; return ", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "tag ``",
+      "tag `no-subst-template`",
+      "tag`template-head${a}`",
+      "tag `${a}`",
+      "tag `${a}template-tail`",
+      "tag   `template-head${a}template-tail`",
+      "tag\n`${a}${b}${c}`",
+      "tag\r\n`a${a}b${b}c${c}`",
+      "tag    `${a}a${b}b${c}c`",
+      "tag\t`foo\n\nbar\r\nbaz`",
+      "tag\r`foo\n\n${  bar  }\r\nbaz`",
+      "tag`foo${a /* comment */}`",
+      "tag`foo${a // comment\n}`",
+      "tag`foo${a \n}`",
+      "tag`foo${a \r\n}`",
+      "tag`foo${a \r}`",
+      "tag`foo${/* comment */ a}`",
+      "tag`foo${// comment\na}`",
+      "tag`foo${\n a}`",
+      "tag`foo${\r\n a}`",
+      "tag`foo${\r a}`",
+      "tag`foo${'a' in a}`",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(TemplateMaterializedLiterals) {
+  const char* context_data[][2] = {
+    {
+      "'use strict';\n"
+      "function tag() {}\n"
+      "var a, b, c;\n"
+      "(", ")"
+    },
+    {NULL, NULL}
+  };
+
+  const char* data[] = {
+    "tag``",
+    "tag`a`",
+    "tag`a${1}b`",
+    "tag`a${1}b${2}c`",
+    "``",
+    "`a`",
+    "`a${1}b`",
+    "`a${1}b${2}c`",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(ScanUnterminatedTemplateLiterals) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';"
+                                    "  var a, b, c; return ", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "`no-subst-template",
+      "`template-head${a}",
+      "`${a}template-tail",
+      "`template-head${a}template-tail",
+      "`${a}${b}${c}",
+      "`a${a}b${b}c${c}",
+      "`${a}a${b}b${c}c",
+      "`foo\n\nbar\r\nbaz",
+      "`foo\n\n${  bar  }\r\nbaz",
+      "`foo${a /* comment } */`",
+      "`foo${a /* comment } `*/",
+      "`foo${a // comment}`",
+      "`foo${a \n`",
+      "`foo${a \r\n`",
+      "`foo${a \r`",
+      "`foo${/* comment */ a`",
+      "`foo${// commenta}`",
+      "`foo${\n a`",
+      "`foo${\r\n a`",
+      "`foo${\r a`",
+      "`foo${fn(}`",
+      "`foo${1 if}`",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(TemplateLiteralsIllegalTokens) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';"
+                                    "  var a, b, c; return ", "}"},
+                                   {NULL, NULL}};
+  const char* data[] = {
+      "`hello\\x`",
+      "`hello\\x${1}`",
+      "`hello${1}\\x`",
+      "`hello${1}\\x${2}`",
+      "`hello\\x\n`",
+      "`hello\\x\n${1}`",
+      "`hello${1}\\x\n`",
+      "`hello${1}\\x\n${2}`",
+      NULL};
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(LexicalScopingSloppyMode) {
+  const char* context_data[][2] = {
+      {"", ""},
+      {"function f() {", "}"},
+      {"{", "}"},
+      {NULL, NULL}};
+  const char* bad_data[] = {
+    "let x = 1;",
+    "for(let x = 1;;){}",
+    "for(let x of []){}",
+    "for(let x in []){}",
+    "class C {}",
+    "class C extends D {}",
+    "(class {})",
+    "(class extends D {})",
+    "(class C {})",
+    "(class C extends D {})",
+    NULL};
+  static const ParserFlag always_true_flags[] = {
+      kAllowHarmonyScoping, kAllowHarmonyClasses};
+  static const ParserFlag always_false_flags[] = {kAllowHarmonySloppy};
+  RunParserSyncTest(context_data, bad_data, kError, NULL, 0,
+                    always_true_flags, arraysize(always_true_flags),
+                    always_false_flags, arraysize(always_false_flags));
+
+  const char* good_data[] = {
+    "let = 1;",
+    "for(let = 1;;){}",
+    NULL};
+  RunParserSyncTest(context_data, good_data, kSuccess, NULL, 0,
+                    always_true_flags, arraysize(always_true_flags),
+                    always_false_flags, arraysize(always_false_flags));
+}
diff --git a/test/cctest/test-platform.cc b/test/cctest/test-platform.cc
index 100a5a7..90926d1 100644
--- a/test/cctest/test-platform.cc
+++ b/test/cctest/test-platform.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "include/v8stdint.h"
+#include <stdint.h>
 #include "src/base/build_config.h"
 #include "src/base/platform/platform.h"
 #include "test/cctest/cctest.h"
diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc
index 9d1d52e..4a572c8 100644
--- a/test/cctest/test-regexp.cc
+++ b/test/cctest/test-regexp.cc
@@ -25,8 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-
-#include <stdlib.h>
+#include <cstdlib>
+#include <sstream>
 
 #include "src/v8.h"
 
@@ -103,9 +103,9 @@
       &reader, false, &result, &zone));
   CHECK(result.tree != NULL);
   CHECK(result.error.is_null());
-  OStringStream os;
+  std::ostringstream os;
   result.tree->Print(os, &zone);
-  CHECK_EQ(expected, os.c_str());
+  CHECK_EQ(expected, os.str().c_str());
 }
 
 
@@ -435,11 +435,11 @@
   // Check that we don't allow more than kMaxCapture captures
   const int kMaxCaptures = 1 << 16;  // Must match RegExpParser::kMaxCaptures.
   const char* kTooManyCaptures = "Too many captures";
-  OStringStream os;
+  std::ostringstream os;
   for (int i = 0; i <= kMaxCaptures; i++) {
     os << "()";
   }
-  ExpectError(os.c_str(), kTooManyCaptures);
+  ExpectError(os.str().c_str(), kTooManyCaptures);
 }
 
 
diff --git a/test/cctest/test-sampler-api.cc b/test/cctest/test-sampler-api.cc
new file mode 100644
index 0000000..2f6f92e
--- /dev/null
+++ b/test/cctest/test-sampler-api.cc
@@ -0,0 +1,245 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Tests the sampling API in include/v8.h
+
+#include <map>
+#include <string>
+#include "include/v8.h"
+#include "src/simulator.h"
+#include "test/cctest/cctest.h"
+
+namespace {
+
+class Sample {
+ public:
+  enum { kFramesLimit = 255 };
+
+  Sample() {}
+
+  typedef const void* const* const_iterator;
+  const_iterator begin() const { return data_.start(); }
+  const_iterator end() const { return &data_[data_.length()]; }
+
+  int size() const { return data_.length(); }
+  v8::internal::Vector<void*>& data() { return data_; }
+
+ private:
+  v8::internal::EmbeddedVector<void*, kFramesLimit> data_;
+};
+
+
+#if defined(USE_SIMULATOR)
+class SimulatorHelper {
+ public:
+  inline bool Init(v8::Isolate* isolate) {
+    simulator_ = reinterpret_cast<v8::internal::Isolate*>(isolate)
+                     ->thread_local_top()
+                     ->simulator_;
+    // Check if there is active simulator.
+    return simulator_ != NULL;
+  }
+
+  inline void FillRegisters(v8::RegisterState* state) {
+#if V8_TARGET_ARCH_ARM
+    state->pc = reinterpret_cast<void*>(simulator_->get_pc());
+    state->sp = reinterpret_cast<void*>(
+        simulator_->get_register(v8::internal::Simulator::sp));
+    state->fp = reinterpret_cast<void*>(
+        simulator_->get_register(v8::internal::Simulator::r11));
+#elif V8_TARGET_ARCH_ARM64
+    if (simulator_->sp() == 0 || simulator_->fp() == 0) {
+      // It's possible that the simulator is interrupted while it is updating
+      // the sp or fp register. ARM64 simulator does this in two steps:
+      // first setting it to zero and then setting it to a new value.
+      // Bailout if sp/fp doesn't contain the new value.
+      return;
+    }
+    state->pc = reinterpret_cast<void*>(simulator_->pc());
+    state->sp = reinterpret_cast<void*>(simulator_->sp());
+    state->fp = reinterpret_cast<void*>(simulator_->fp());
+#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
+    state->pc = reinterpret_cast<void*>(simulator_->get_pc());
+    state->sp = reinterpret_cast<void*>(
+        simulator_->get_register(v8::internal::Simulator::sp));
+    state->fp = reinterpret_cast<void*>(
+        simulator_->get_register(v8::internal::Simulator::fp));
+#endif
+  }
+
+ private:
+  v8::internal::Simulator* simulator_;
+};
+#endif  // USE_SIMULATOR
+
+
+class SamplingTestHelper {
+ public:
+  struct CodeEventEntry {
+    std::string name;
+    const void* code_start;
+    size_t code_len;
+  };
+  typedef std::map<const void*, CodeEventEntry> CodeEntries;
+
+  explicit SamplingTestHelper(const std::string& test_function)
+      : sample_is_taken_(false), isolate_(CcTest::isolate()) {
+    DCHECK_EQ(NULL, instance_);
+    instance_ = this;
+    v8::HandleScope scope(isolate_);
+    v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
+    global->Set(v8::String::NewFromUtf8(isolate_, "CollectSample"),
+                v8::FunctionTemplate::New(isolate_, CollectSample));
+    LocalContext env(isolate_, NULL, global);
+    isolate_->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
+                                     JitCodeEventHandler);
+    v8::Script::Compile(
+        v8::String::NewFromUtf8(isolate_, test_function.c_str()))->Run();
+  }
+
+  ~SamplingTestHelper() {
+    isolate_->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
+    instance_ = NULL;
+  }
+
+  Sample& sample() { return sample_; }
+
+  const CodeEventEntry* FindEventEntry(const void* address) {
+    CodeEntries::const_iterator it = code_entries_.upper_bound(address);
+    if (it == code_entries_.begin()) return NULL;
+    const CodeEventEntry& entry = (--it)->second;
+    const void* code_end =
+        static_cast<const uint8_t*>(entry.code_start) + entry.code_len;
+    return address < code_end ? &entry : NULL;
+  }
+
+ private:
+  static void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args) {
+    instance_->DoCollectSample();
+  }
+
+  static void JitCodeEventHandler(const v8::JitCodeEvent* event) {
+    instance_->DoJitCodeEventHandler(event);
+  }
+
+  // The JavaScript calls this function when on full stack depth.
+  void DoCollectSample() {
+    v8::RegisterState state;
+#if defined(USE_SIMULATOR)
+    SimulatorHelper simulator_helper;
+    if (!simulator_helper.Init(isolate_)) return;
+    simulator_helper.FillRegisters(&state);
+#else
+    state.pc = NULL;
+    state.fp = &state;
+    state.sp = &state;
+#endif
+    v8::SampleInfo info;
+    isolate_->GetStackSample(state, sample_.data().start(),
+                             static_cast<size_t>(sample_.size()), &info);
+    size_t frames_count = info.frames_count;
+    CHECK_LE(frames_count, static_cast<size_t>(sample_.size()));
+    sample_.data().Truncate(static_cast<int>(frames_count));
+    sample_is_taken_ = true;
+  }
+
+  void DoJitCodeEventHandler(const v8::JitCodeEvent* event) {
+    if (sample_is_taken_) return;
+    switch (event->type) {
+      case v8::JitCodeEvent::CODE_ADDED: {
+        CodeEventEntry entry;
+        entry.name = std::string(event->name.str, event->name.len);
+        entry.code_start = event->code_start;
+        entry.code_len = event->code_len;
+        code_entries_.insert(std::make_pair(entry.code_start, entry));
+        break;
+      }
+      case v8::JitCodeEvent::CODE_MOVED: {
+        CodeEntries::iterator it = code_entries_.find(event->code_start);
+        CHECK(it != code_entries_.end());
+        code_entries_.erase(it);
+        CodeEventEntry entry;
+        entry.name = std::string(event->name.str, event->name.len);
+        entry.code_start = event->new_code_start;
+        entry.code_len = event->code_len;
+        code_entries_.insert(std::make_pair(entry.code_start, entry));
+        break;
+      }
+      case v8::JitCodeEvent::CODE_REMOVED:
+        code_entries_.erase(event->code_start);
+        break;
+      default:
+        break;
+    }
+  }
+
+  Sample sample_;
+  bool sample_is_taken_;
+  v8::Isolate* isolate_;
+  CodeEntries code_entries_;
+
+  static SamplingTestHelper* instance_;
+};
+
+SamplingTestHelper* SamplingTestHelper::instance_;
+
+}  // namespace
+
+
+// A JavaScript function which takes stack depth
+// (minimum value 2) as an argument.
+// When at the bottom of the recursion,
+// the JavaScript code calls into C++ test code,
+// waiting for the sampler to take a sample.
+static const char* test_function =
+    "function func(depth) {"
+    "  if (depth == 2) CollectSample();"
+    "  else return func(depth - 1);"
+    "}";
+
+
+TEST(StackDepthIsConsistent) {
+  SamplingTestHelper helper(std::string(test_function) + "func(8);");
+  CHECK_EQ(8, helper.sample().size());
+}
+
+
+TEST(StackDepthDoesNotExceedMaxValue) {
+  SamplingTestHelper helper(std::string(test_function) + "func(300);");
+  CHECK_EQ(Sample::kFramesLimit, helper.sample().size());
+}
+
+
+// The captured sample should have three pc values.
+// They should fall in the range where the compiled code resides.
+// The expected stack is:
+// bottom of stack [{anon script}, outer, inner] top of stack
+//                              ^      ^       ^
+// sample.stack indices         2      1       0
+TEST(StackFramesConsistent) {
+  // Note: The arguments.callee stuff is there so that the
+  //       functions are not optimized away.
+  const char* test_script =
+      "function test_sampler_api_inner() {"
+      "  CollectSample();"
+      "  return arguments.callee.toString();"
+      "}"
+      "function test_sampler_api_outer() {"
+      "  return test_sampler_api_inner() + arguments.callee.toString();"
+      "}"
+      "test_sampler_api_outer();";
+
+  SamplingTestHelper helper(test_script);
+  Sample& sample = helper.sample();
+  CHECK_EQ(3, sample.size());
+
+  const SamplingTestHelper::CodeEventEntry* entry;
+  entry = helper.FindEventEntry(sample.begin()[0]);
+  CHECK_NE(NULL, entry);
+  CHECK(std::string::npos != entry->name.find("test_sampler_api_inner"));
+
+  entry = helper.FindEventEntry(sample.begin()[1]);
+  CHECK_NE(NULL, entry);
+  CHECK(std::string::npos != entry->name.find("test_sampler_api_outer"));
+}
diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc
index 94b400e..45da250 100644
--- a/test/cctest/test-serialize.cc
+++ b/test/cctest/test-serialize.cc
@@ -37,7 +37,7 @@
 #include "src/heap/spaces.h"
 #include "src/natives.h"
 #include "src/objects.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 #include "src/scopeinfo.h"
 #include "src/serialize.h"
 #include "src/snapshot.h"
@@ -114,82 +114,27 @@
 }
 
 
-class FileByteSink : public SnapshotByteSink {
- public:
-  explicit FileByteSink(const char* snapshot_file) {
-    fp_ = v8::base::OS::FOpen(snapshot_file, "wb");
-    file_name_ = snapshot_file;
-    if (fp_ == NULL) {
-      PrintF("Unable to write to snapshot file \"%s\"\n", snapshot_file);
-      exit(1);
-    }
+void WritePayload(const Vector<const byte>& payload, const char* file_name) {
+  FILE* file = v8::base::OS::FOpen(file_name, "wb");
+  if (file == NULL) {
+    PrintF("Unable to write to snapshot file \"%s\"\n", file_name);
+    exit(1);
   }
-  virtual ~FileByteSink() {
-    if (fp_ != NULL) {
-      fclose(fp_);
-    }
+  size_t written = fwrite(payload.begin(), 1, payload.length(), file);
+  if (written != static_cast<size_t>(payload.length())) {
+    i::PrintF("Writing snapshot file failed.. Aborting.\n");
+    exit(1);
   }
-  virtual void Put(byte b, const char* description) {
-    if (fp_ != NULL) {
-      fputc(b, fp_);
-    }
-  }
-  virtual int Position() {
-    return ftell(fp_);
-  }
-  void WriteSpaceUsed(
-      int new_space_used,
-      int pointer_space_used,
-      int data_space_used,
-      int code_space_used,
-      int map_space_used,
-      int cell_space_used,
-      int property_cell_space_used);
-
- private:
-  FILE* fp_;
-  const char* file_name_;
-};
-
-
-void FileByteSink::WriteSpaceUsed(
-      int new_space_used,
-      int pointer_space_used,
-      int data_space_used,
-      int code_space_used,
-      int map_space_used,
-      int cell_space_used,
-      int property_cell_space_used) {
-  int file_name_length = StrLength(file_name_) + 10;
-  Vector<char> name = Vector<char>::New(file_name_length + 1);
-  SNPrintF(name, "%s.size", file_name_);
-  FILE* fp = v8::base::OS::FOpen(name.start(), "w");
-  name.Dispose();
-  fprintf(fp, "new %d\n", new_space_used);
-  fprintf(fp, "pointer %d\n", pointer_space_used);
-  fprintf(fp, "data %d\n", data_space_used);
-  fprintf(fp, "code %d\n", code_space_used);
-  fprintf(fp, "map %d\n", map_space_used);
-  fprintf(fp, "cell %d\n", cell_space_used);
-  fprintf(fp, "property cell %d\n", property_cell_space_used);
-  fclose(fp);
+  fclose(file);
 }
 
 
 static bool WriteToFile(Isolate* isolate, const char* snapshot_file) {
-  FileByteSink file(snapshot_file);
-  StartupSerializer ser(isolate, &file);
+  SnapshotByteSink sink;
+  StartupSerializer ser(isolate, &sink);
   ser.Serialize();
-
-  file.WriteSpaceUsed(
-      ser.CurrentAllocationAddress(NEW_SPACE),
-      ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
-      ser.CurrentAllocationAddress(OLD_DATA_SPACE),
-      ser.CurrentAllocationAddress(CODE_SPACE),
-      ser.CurrentAllocationAddress(MAP_SPACE),
-      ser.CurrentAllocationAddress(CELL_SPACE),
-      ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
-
+  SnapshotData snapshot_data(sink, ser);
+  WritePayload(snapshot_data.RawData(), snapshot_file);
   return true;
 }
 
@@ -206,7 +151,7 @@
   }
 
   Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
-  internal_isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "serialize");
+  internal_isolate->heap()->CollectAllAvailableGarbage("serialize");
   WriteToFile(internal_isolate, FLAG_testing_serialization_file);
 }
 
@@ -237,51 +182,14 @@
 //----------------------------------------------------------------------------
 // Tests that the heap can be deserialized.
 
-
-static void ReserveSpaceForSnapshot(Deserializer* deserializer,
-                                    const char* file_name) {
-  int file_name_length = StrLength(file_name) + 10;
-  Vector<char> name = Vector<char>::New(file_name_length + 1);
-  SNPrintF(name, "%s.size", file_name);
-  FILE* fp = v8::base::OS::FOpen(name.start(), "r");
-  name.Dispose();
-  int new_size, pointer_size, data_size, code_size, map_size, cell_size,
-      property_cell_size;
-#ifdef _MSC_VER
-  // Avoid warning about unsafe fscanf from MSVC.
-  // Please note that this is only fine if %c and %s are not being used.
-#define fscanf fscanf_s
-#endif
-  CHECK_EQ(1, fscanf(fp, "new %d\n", &new_size));
-  CHECK_EQ(1, fscanf(fp, "pointer %d\n", &pointer_size));
-  CHECK_EQ(1, fscanf(fp, "data %d\n", &data_size));
-  CHECK_EQ(1, fscanf(fp, "code %d\n", &code_size));
-  CHECK_EQ(1, fscanf(fp, "map %d\n", &map_size));
-  CHECK_EQ(1, fscanf(fp, "cell %d\n", &cell_size));
-  CHECK_EQ(1, fscanf(fp, "property cell %d\n", &property_cell_size));
-#ifdef _MSC_VER
-#undef fscanf
-#endif
-  fclose(fp);
-  deserializer->set_reservation(NEW_SPACE, new_size);
-  deserializer->set_reservation(OLD_POINTER_SPACE, pointer_size);
-  deserializer->set_reservation(OLD_DATA_SPACE, data_size);
-  deserializer->set_reservation(CODE_SPACE, code_size);
-  deserializer->set_reservation(MAP_SPACE, map_size);
-  deserializer->set_reservation(CELL_SPACE, cell_size);
-  deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_size);
-}
-
-
 v8::Isolate* InitializeFromFile(const char* snapshot_file) {
   int len;
   byte* str = ReadBytes(snapshot_file, &len);
   if (!str) return NULL;
   v8::Isolate* v8_isolate = NULL;
   {
-    SnapshotByteSource source(str, len);
-    Deserializer deserializer(&source);
-    ReserveSpaceForSnapshot(&deserializer, snapshot_file);
+    SnapshotData snapshot_data(Vector<const byte>(str, len));
+    Deserializer deserializer(&snapshot_data);
     Isolate* isolate = Isolate::NewForTesting();
     v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     v8::Isolate::Scope isolate_scope(v8_isolate);
@@ -440,32 +348,23 @@
       }
       env.Reset();
 
-      FileByteSink startup_sink(startup_name.start());
+      SnapshotByteSink startup_sink;
       StartupSerializer startup_serializer(isolate, &startup_sink);
       startup_serializer.SerializeStrongReferences();
 
-      FileByteSink partial_sink(FLAG_testing_serialization_file);
-      PartialSerializer p_ser(isolate, &startup_serializer, &partial_sink);
-      p_ser.Serialize(&raw_foo);
+      SnapshotByteSink partial_sink;
+      PartialSerializer partial_serializer(isolate, &startup_serializer,
+                                           &partial_sink);
+      partial_serializer.Serialize(&raw_foo);
+
       startup_serializer.SerializeWeakReferences();
 
-      partial_sink.WriteSpaceUsed(
-          p_ser.CurrentAllocationAddress(NEW_SPACE),
-          p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
-          p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
-          p_ser.CurrentAllocationAddress(CODE_SPACE),
-          p_ser.CurrentAllocationAddress(MAP_SPACE),
-          p_ser.CurrentAllocationAddress(CELL_SPACE),
-          p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+      SnapshotData startup_snapshot(startup_sink, startup_serializer);
+      SnapshotData partial_snapshot(partial_sink, partial_serializer);
 
-      startup_sink.WriteSpaceUsed(
-          startup_serializer.CurrentAllocationAddress(NEW_SPACE),
-          startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE),
-          startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE),
-          startup_serializer.CurrentAllocationAddress(CODE_SPACE),
-          startup_serializer.CurrentAllocationAddress(MAP_SPACE),
-          startup_serializer.CurrentAllocationAddress(CELL_SPACE),
-          startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+      WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
+      WritePayload(startup_snapshot.RawData(), startup_name.start());
+
       startup_name.Dispose();
     }
     v8_isolate->Exit();
@@ -494,9 +393,8 @@
       Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
       Object* root;
       {
-        SnapshotByteSource source(snapshot, snapshot_size);
-        Deserializer deserializer(&source);
-        ReserveSpaceForSnapshot(&deserializer, file_name);
+        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+        Deserializer deserializer(&snapshot_data);
         deserializer.DeserializePartial(isolate, &root);
         CHECK(root->IsString());
       }
@@ -506,9 +404,8 @@
 
       Object* root2;
       {
-        SnapshotByteSource source(snapshot, snapshot_size);
-        Deserializer deserializer(&source);
-        ReserveSpaceForSnapshot(&deserializer, file_name);
+        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+        Deserializer deserializer(&snapshot_data);
         deserializer.DeserializePartial(isolate, &root2);
         CHECK(root2->IsString());
         CHECK(*root_handle == root2);
@@ -563,32 +460,22 @@
 
       env.Reset();
 
-      FileByteSink startup_sink(startup_name.start());
+      SnapshotByteSink startup_sink;
       StartupSerializer startup_serializer(isolate, &startup_sink);
       startup_serializer.SerializeStrongReferences();
 
-      FileByteSink partial_sink(FLAG_testing_serialization_file);
-      PartialSerializer p_ser(isolate, &startup_serializer, &partial_sink);
-      p_ser.Serialize(&raw_context);
+      SnapshotByteSink partial_sink;
+      PartialSerializer partial_serializer(isolate, &startup_serializer,
+                                           &partial_sink);
+      partial_serializer.Serialize(&raw_context);
       startup_serializer.SerializeWeakReferences();
 
-      partial_sink.WriteSpaceUsed(
-          p_ser.CurrentAllocationAddress(NEW_SPACE),
-          p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
-          p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
-          p_ser.CurrentAllocationAddress(CODE_SPACE),
-          p_ser.CurrentAllocationAddress(MAP_SPACE),
-          p_ser.CurrentAllocationAddress(CELL_SPACE),
-          p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+      SnapshotData startup_snapshot(startup_sink, startup_serializer);
+      SnapshotData partial_snapshot(partial_sink, partial_serializer);
 
-      startup_sink.WriteSpaceUsed(
-          startup_serializer.CurrentAllocationAddress(NEW_SPACE),
-          startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE),
-          startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE),
-          startup_serializer.CurrentAllocationAddress(CODE_SPACE),
-          startup_serializer.CurrentAllocationAddress(MAP_SPACE),
-          startup_serializer.CurrentAllocationAddress(CELL_SPACE),
-          startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+      WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
+      WritePayload(startup_snapshot.RawData(), startup_name.start());
+
       startup_name.Dispose();
     }
     v8_isolate->Dispose();
@@ -616,9 +503,8 @@
       Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
       Object* root;
       {
-        SnapshotByteSource source(snapshot, snapshot_size);
-        Deserializer deserializer(&source);
-        ReserveSpaceForSnapshot(&deserializer, file_name);
+        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+        Deserializer deserializer(&snapshot_data);
         deserializer.DeserializePartial(isolate, &root);
         CHECK(root->IsContext());
       }
@@ -628,9 +514,8 @@
 
       Object* root2;
       {
-        SnapshotByteSource source(snapshot, snapshot_size);
-        Deserializer deserializer(&source);
-        ReserveSpaceForSnapshot(&deserializer, file_name);
+        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+        Deserializer deserializer(&snapshot_data);
         deserializer.DeserializePartial(isolate, &root2);
         CHECK(root2->IsContext());
         CHECK(*root_handle != root2);
@@ -786,6 +671,432 @@
 }
 
 
+Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head,
+                                      Vector<const uint8_t> body,
+                                      Vector<const uint8_t> tail, int repeats) {
+  int source_length = head.length() + body.length() * repeats + tail.length();
+  uint8_t* source = NewArray<uint8_t>(static_cast<size_t>(source_length));
+  CopyChars(source, head.start(), head.length());
+  for (int i = 0; i < repeats; i++) {
+    CopyChars(source + head.length() + i * body.length(), body.start(),
+              body.length());
+  }
+  CopyChars(source + head.length() + repeats * body.length(), tail.start(),
+            tail.length());
+  return Vector<const uint8_t>(const_cast<const uint8_t*>(source),
+                               source_length);
+}
+
+
+TEST(SerializeToplevelLargeCodeObject) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  Vector<const uint8_t> source =
+      ConstructSource(STATIC_CHAR_VECTOR("var j=1; try { if (j) throw 1;"),
+                      STATIC_CHAR_VECTOR("for(var i=0;i<1;i++)j++;"),
+                      STATIC_CHAR_VECTOR("} catch (e) { j=7; } j"), 10000);
+  Handle<String> source_str =
+      isolate->factory()->NewStringFromOneByte(source).ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_str, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  CHECK(isolate->heap()->InSpace(orig->code(), LO_SPACE));
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_str, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      isolate->factory()->NewFunctionFromSharedFunctionInfo(
+          copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  int result_int;
+  CHECK(copy_result->ToInt32(&result_int));
+  CHECK_EQ(7, result_int);
+
+  delete cache;
+  source.Dispose();
+}
+
+
+TEST(SerializeToplevelLargeStrings) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* f = isolate->factory();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  Vector<const uint8_t> source_s = ConstructSource(
+      STATIC_CHAR_VECTOR("var s = \""), STATIC_CHAR_VECTOR("abcdef"),
+      STATIC_CHAR_VECTOR("\";"), 1000000);
+  Vector<const uint8_t> source_t = ConstructSource(
+      STATIC_CHAR_VECTOR("var t = \""), STATIC_CHAR_VECTOR("uvwxyz"),
+      STATIC_CHAR_VECTOR("\"; s + t"), 999999);
+  Handle<String> source_str =
+      f->NewConsString(f->NewStringFromOneByte(source_s).ToHandleChecked(),
+                       f->NewStringFromOneByte(source_t).ToHandleChecked())
+          .ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_str, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_str, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      isolate->factory()->NewFunctionFromSharedFunctionInfo(
+          copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  CHECK_EQ(6 * 1999999, Handle<String>::cast(copy_result)->length());
+  Handle<Object> property = JSObject::GetDataProperty(
+      isolate->global_object(), f->NewStringFromAsciiChecked("s"));
+  CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
+  property = JSObject::GetDataProperty(isolate->global_object(),
+                                       f->NewStringFromAsciiChecked("t"));
+  CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
+  // Make sure we do not serialize too much, e.g. include the source string.
+  CHECK_LT(cache->length(), 13000000);
+
+  delete cache;
+  source_s.Dispose();
+  source_t.Dispose();
+}
+
+
+TEST(SerializeToplevelThreeBigStrings) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* f = isolate->factory();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  Vector<const uint8_t> source_a =
+      ConstructSource(STATIC_CHAR_VECTOR("var a = \""), STATIC_CHAR_VECTOR("a"),
+                      STATIC_CHAR_VECTOR("\";"), 700000);
+  Handle<String> source_a_str =
+      f->NewStringFromOneByte(source_a).ToHandleChecked();
+
+  Vector<const uint8_t> source_b =
+      ConstructSource(STATIC_CHAR_VECTOR("var b = \""), STATIC_CHAR_VECTOR("b"),
+                      STATIC_CHAR_VECTOR("\";"), 600000);
+  Handle<String> source_b_str =
+      f->NewStringFromOneByte(source_b).ToHandleChecked();
+
+  Vector<const uint8_t> source_c =
+      ConstructSource(STATIC_CHAR_VECTOR("var c = \""), STATIC_CHAR_VECTOR("c"),
+                      STATIC_CHAR_VECTOR("\";"), 500000);
+  Handle<String> source_c_str =
+      f->NewStringFromOneByte(source_c).ToHandleChecked();
+
+  Handle<String> source_str =
+      f->NewConsString(
+             f->NewConsString(source_a_str, source_b_str).ToHandleChecked(),
+             source_c_str).ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_str, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_str, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      isolate->factory()->NewFunctionFromSharedFunctionInfo(
+          copy, isolate->native_context());
+
+  USE(Execution::Call(isolate, copy_fun, global, 0, NULL));
+
+  CHECK_EQ(600000 + 700000, CompileRun("(a + b).length")->Int32Value());
+  CHECK_EQ(500000 + 600000, CompileRun("(b + c).length")->Int32Value());
+  Heap* heap = isolate->heap();
+  CHECK(heap->InSpace(
+      *v8::Utils::OpenHandle(*CompileRun("a")->ToString(CcTest::isolate())),
+      OLD_DATA_SPACE));
+  CHECK(heap->InSpace(
+      *v8::Utils::OpenHandle(*CompileRun("b")->ToString(CcTest::isolate())),
+      OLD_DATA_SPACE));
+  CHECK(heap->InSpace(
+      *v8::Utils::OpenHandle(*CompileRun("c")->ToString(CcTest::isolate())),
+      OLD_DATA_SPACE));
+
+  delete cache;
+  source_a.Dispose();
+  source_b.Dispose();
+  source_c.Dispose();
+}
+
+
+class SerializerOneByteResource
+    : public v8::String::ExternalOneByteStringResource {
+ public:
+  SerializerOneByteResource(const char* data, size_t length)
+      : data_(data), length_(length) {}
+  virtual const char* data() const { return data_; }
+  virtual size_t length() const { return length_; }
+
+ private:
+  const char* data_;
+  size_t length_;
+};
+
+
+class SerializerTwoByteResource : public v8::String::ExternalStringResource {
+ public:
+  SerializerTwoByteResource(const char* data, size_t length)
+      : data_(AsciiToTwoByteString(data)), length_(length) {}
+  ~SerializerTwoByteResource() { DeleteArray<const uint16_t>(data_); }
+
+  virtual const uint16_t* data() const { return data_; }
+  virtual size_t length() const { return length_; }
+
+ private:
+  const uint16_t* data_;
+  size_t length_;
+};
+
+
+TEST(SerializeToplevelExternalString) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  // Obtain external internalized one-byte string.
+  SerializerOneByteResource one_byte_resource("one_byte", 8);
+  Handle<String> one_byte_string =
+      isolate->factory()->NewStringFromAsciiChecked("one_byte");
+  one_byte_string = isolate->factory()->InternalizeString(one_byte_string);
+  one_byte_string->MakeExternal(&one_byte_resource);
+  CHECK(one_byte_string->IsExternalOneByteString());
+  CHECK(one_byte_string->IsInternalizedString());
+
+  // Obtain external internalized two-byte string.
+  SerializerTwoByteResource two_byte_resource("two_byte", 8);
+  Handle<String> two_byte_string =
+      isolate->factory()->NewStringFromAsciiChecked("two_byte");
+  two_byte_string = isolate->factory()->InternalizeString(two_byte_string);
+  two_byte_string->MakeExternal(&two_byte_resource);
+  CHECK(two_byte_string->IsExternalTwoByteString());
+  CHECK(two_byte_string->IsInternalizedString());
+
+  const char* source =
+      "var o = {}               \n"
+      "o.one_byte = 7;          \n"
+      "o.two_byte = 8;          \n"
+      "o.one_byte + o.two_byte; \n";
+  Handle<String> source_string = isolate->factory()
+                                     ->NewStringFromUtf8(CStrVector(source))
+                                     .ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_string, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_string, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      isolate->factory()->NewFunctionFromSharedFunctionInfo(
+          copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  CHECK_EQ(15.0f, copy_result->Number());
+
+  delete cache;
+}
+
+
+TEST(SerializeToplevelLargeExternalString) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  Factory* f = isolate->factory();
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  // Create a huge external internalized string to use as variable name.
+  Vector<const uint8_t> string =
+      ConstructSource(STATIC_CHAR_VECTOR(""), STATIC_CHAR_VECTOR("abcdef"),
+                      STATIC_CHAR_VECTOR(""), 999999);
+  Handle<String> name = f->NewStringFromOneByte(string).ToHandleChecked();
+  SerializerOneByteResource one_byte_resource(
+      reinterpret_cast<const char*>(string.start()), string.length());
+  name = f->InternalizeString(name);
+  name->MakeExternal(&one_byte_resource);
+  CHECK(name->IsExternalOneByteString());
+  CHECK(name->IsInternalizedString());
+  CHECK(isolate->heap()->InSpace(*name, LO_SPACE));
+
+  // Create the source, which is "var <literal> = 42; <literal>".
+  Handle<String> source_str =
+      f->NewConsString(
+             f->NewConsString(f->NewStringFromAsciiChecked("var "), name)
+                 .ToHandleChecked(),
+             f->NewConsString(f->NewStringFromAsciiChecked(" = 42; "), name)
+                 .ToHandleChecked()).ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_str, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_str, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  CHECK_EQ(42.0f, copy_result->Number());
+
+  delete cache;
+  string.Dispose();
+}
+
+
+TEST(SerializeToplevelExternalScriptName) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  Factory* f = isolate->factory();
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  const char* source =
+      "var a = [1, 2, 3, 4];"
+      "a.reduce(function(x, y) { return x + y }, 0)";
+
+  Handle<String> source_string =
+      f->NewStringFromUtf8(CStrVector(source)).ToHandleChecked();
+
+  const SerializerOneByteResource one_byte_resource("one_byte", 8);
+  Handle<String> name =
+      f->NewExternalStringFromOneByte(&one_byte_resource).ToHandleChecked();
+  CHECK(name->IsExternalOneByteString());
+  CHECK(!name->IsInternalizedString());
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_string, name, 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_string, name, 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  CHECK_EQ(10.0f, copy_result->Number());
+
+  delete cache;
+}
+
+
+static bool toplevel_test_code_event_found = false;
+
+
+static void SerializerCodeEventListener(const v8::JitCodeEvent* event) {
+  if (event->type == v8::JitCodeEvent::CODE_ADDED &&
+      memcmp(event->name.str, "Script:~test", 12) == 0) {
+    toplevel_test_code_event_found = true;
+  }
+}
+
+
 TEST(SerializeToplevelIsolates) {
   FLAG_serialize_toplevel = true;
 
@@ -805,6 +1116,7 @@
     v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
         isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
     const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
+    CHECK(data);
     // Persist cached data.
     uint8_t* buffer = NewArray<uint8_t>(data->length);
     MemCopy(buffer, data->data, data->length);
@@ -812,11 +1124,14 @@
         buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
 
     v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
-    CHECK(result->ToString()->Equals(v8_str("abcdef")));
+    CHECK(result->ToString(isolate1)->Equals(v8_str("abcdef")));
   }
   isolate1->Dispose();
 
   v8::Isolate* isolate2 = v8::Isolate::New();
+  isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
+                                   SerializerCodeEventListener);
+  toplevel_test_code_event_found = false;
   {
     v8::Isolate::Scope iscope(isolate2);
     v8::HandleScope scope(isolate2);
@@ -832,8 +1147,125 @@
       script = v8::ScriptCompiler::CompileUnbound(
           isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache);
     }
+    CHECK(!cache->rejected);
     v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
-    CHECK(result->ToString()->Equals(v8_str("abcdef")));
+    CHECK(result->ToString(isolate2)->Equals(v8_str("abcdef")));
+  }
+  DCHECK(toplevel_test_code_event_found);
+  isolate2->Dispose();
+}
+
+
+TEST(SerializeToplevelFlagChange) {
+  FLAG_serialize_toplevel = true;
+
+  const char* source = "function f() { return 'abc'; }; f() + 'def'";
+  v8::ScriptCompiler::CachedData* cache;
+
+  v8::Isolate* isolate1 = v8::Isolate::New();
+  {
+    v8::Isolate::Scope iscope(isolate1);
+    v8::HandleScope scope(isolate1);
+    v8::Local<v8::Context> context = v8::Context::New(isolate1);
+    v8::Context::Scope context_scope(context);
+
+    v8::Local<v8::String> source_str = v8_str(source);
+    v8::ScriptOrigin origin(v8_str("test"));
+    v8::ScriptCompiler::Source source(source_str, origin);
+    v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
+        isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
+    const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
+    CHECK(data);
+    // Persist cached data.
+    uint8_t* buffer = NewArray<uint8_t>(data->length);
+    MemCopy(buffer, data->data, data->length);
+    cache = new v8::ScriptCompiler::CachedData(
+        buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
+
+    v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
+    CHECK(result->ToString(isolate1)->Equals(v8_str("abcdef")));
+  }
+  isolate1->Dispose();
+
+  v8::Isolate* isolate2 = v8::Isolate::New();
+  FLAG_allow_natives_syntax = true;  // Flag change should trigger cache reject.
+  {
+    v8::Isolate::Scope iscope(isolate2);
+    v8::HandleScope scope(isolate2);
+    v8::Local<v8::Context> context = v8::Context::New(isolate2);
+    v8::Context::Scope context_scope(context);
+
+    v8::Local<v8::String> source_str = v8_str(source);
+    v8::ScriptOrigin origin(v8_str("test"));
+    v8::ScriptCompiler::Source source(source_str, origin, cache);
+    v8::ScriptCompiler::CompileUnbound(isolate2, &source,
+                                       v8::ScriptCompiler::kConsumeCodeCache);
+    CHECK(cache->rejected);
+  }
+  isolate2->Dispose();
+}
+
+
+TEST(SerializeWithHarmonyScoping) {
+  FLAG_serialize_toplevel = true;
+  FLAG_harmony_scoping = true;
+
+  const char* source1 = "'use strict'; let x = 'X'";
+  const char* source2 = "'use strict'; let y = 'Y'";
+  const char* source3 = "'use strict'; x + y";
+
+  v8::ScriptCompiler::CachedData* cache;
+
+  v8::Isolate* isolate1 = v8::Isolate::New();
+  {
+    v8::Isolate::Scope iscope(isolate1);
+    v8::HandleScope scope(isolate1);
+    v8::Local<v8::Context> context = v8::Context::New(isolate1);
+    v8::Context::Scope context_scope(context);
+
+    CompileRun(source1);
+    CompileRun(source2);
+
+    v8::Local<v8::String> source_str = v8_str(source3);
+    v8::ScriptOrigin origin(v8_str("test"));
+    v8::ScriptCompiler::Source source(source_str, origin);
+    v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
+        isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
+    const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
+    CHECK(data);
+    // Persist cached data.
+    uint8_t* buffer = NewArray<uint8_t>(data->length);
+    MemCopy(buffer, data->data, data->length);
+    cache = new v8::ScriptCompiler::CachedData(
+        buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
+
+    v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
+    CHECK(result->ToString(isolate1)->Equals(v8_str("XY")));
+  }
+  isolate1->Dispose();
+
+  v8::Isolate* isolate2 = v8::Isolate::New();
+  {
+    v8::Isolate::Scope iscope(isolate2);
+    v8::HandleScope scope(isolate2);
+    v8::Local<v8::Context> context = v8::Context::New(isolate2);
+    v8::Context::Scope context_scope(context);
+
+    // Reverse order of prior running scripts.
+    CompileRun(source2);
+    CompileRun(source1);
+
+    v8::Local<v8::String> source_str = v8_str(source3);
+    v8::ScriptOrigin origin(v8_str("test"));
+    v8::ScriptCompiler::Source source(source_str, origin, cache);
+    v8::Local<v8::UnboundScript> script;
+    {
+      DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
+      script = v8::ScriptCompiler::CompileUnbound(
+          isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache);
+    }
+    v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
+    CHECK(result->ToString(isolate2)->Equals(v8_str("XY")));
   }
   isolate2->Dispose();
 }
diff --git a/test/cctest/test-spaces.cc b/test/cctest/test-spaces.cc
index d09c128..a84b867 100644
--- a/test/cctest/test-spaces.cc
+++ b/test/cctest/test-spaces.cc
@@ -27,6 +27,7 @@
 
 #include <stdlib.h>
 
+#include "src/base/platform/platform.h"
 #include "src/snapshot.h"
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
@@ -212,11 +213,17 @@
   TestMemoryAllocatorScope test_allocator_scope(isolate, memory_allocator);
   CodeRange* code_range = new CodeRange(isolate);
   const size_t code_range_size = 4 * MB;
-  if (!code_range->SetUp(code_range_size)) return;
+  if (!code_range->SetUp(
+          code_range_size +
+          RoundUp(v8::base::OS::CommitPageSize() * kReservedCodeRangePages,
+                  MemoryChunk::kAlignment) +
+          v8::internal::MemoryAllocator::CodePageAreaSize())) {
+    return;
+  }
   Address address;
   size_t size;
-  address = code_range->AllocateRawMemory(code_range_size - MB,
-                                          code_range_size - MB, &size);
+  address = code_range->AllocateRawMemory(code_range_size - 2 * MB,
+                                          code_range_size - 2 * MB, &size);
   CHECK(address != NULL);
   Address null_address;
   size_t null_size;
@@ -450,3 +457,55 @@
   // No large objects required to perform the above steps.
   CHECK(isolate->heap()->lo_space()->IsEmpty());
 }
+
+
+static inline void FillCurrentPage(v8::internal::NewSpace* space) {
+  int new_linear_size = static_cast<int>(*space->allocation_limit_address() -
+                                         *space->allocation_top_address());
+  if (new_linear_size == 0) return;
+  v8::internal::AllocationResult allocation =
+      space->AllocateRaw(new_linear_size);
+  v8::internal::FreeListNode* node =
+      v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
+  node->set_size(space->heap(), new_linear_size);
+}
+
+
+UNINITIALIZED_TEST(NewSpaceGrowsToTargetCapacity) {
+  FLAG_target_semi_space_size = 2;
+  if (FLAG_optimize_for_size) return;
+
+  v8::Isolate* isolate = v8::Isolate::New();
+  {
+    v8::Isolate::Scope isolate_scope(isolate);
+    v8::HandleScope handle_scope(isolate);
+    v8::Context::New(isolate)->Enter();
+
+    Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
+
+    NewSpace* new_space = i_isolate->heap()->new_space();
+
+    // This test doesn't work if we start with a non-default new space
+    // configuration.
+    if (new_space->InitialTotalCapacity() == Page::kPageSize) {
+      CHECK(new_space->CommittedMemory() == new_space->InitialTotalCapacity());
+
+      // Fill up the first (and only) page of the semi space.
+      FillCurrentPage(new_space);
+
+      // Try to allocate out of the new space. A new page should be added and
+      // the
+      // allocation should succeed.
+      v8::internal::AllocationResult allocation = new_space->AllocateRaw(80);
+      CHECK(!allocation.IsRetry());
+      CHECK(new_space->CommittedMemory() == 2 * Page::kPageSize);
+
+      // Turn the allocation into a proper object so isolate teardown won't
+      // crash.
+      v8::internal::FreeListNode* node =
+          v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
+      node->set_size(new_space->heap(), 80);
+    }
+  }
+  isolate->Dispose();
+}
diff --git a/test/cctest/test-strings.cc b/test/cctest/test-strings.cc
index ef13c4d..d1f23f7 100644
--- a/test/cctest/test-strings.cc
+++ b/test/cctest/test-strings.cc
@@ -37,6 +37,7 @@
 #include "src/api.h"
 #include "src/factory.h"
 #include "src/objects.h"
+#include "src/unicode-decoder.h"
 #include "test/cctest/cctest.h"
 
 // Adapted from http://en.wikipedia.org/wiki/Multiply-with-carry
@@ -356,10 +357,10 @@
 
 void AccumulateStatsWithOperator(
     ConsString* cons_string, ConsStringStats* stats) {
-  ConsStringIteratorOp op(cons_string);
+  ConsStringIterator iter(cons_string);
   String* string;
   int offset;
-  while (NULL != (string = op.Next(&offset))) {
+  while (NULL != (string = iter.Next(&offset))) {
     // Accumulate stats.
     CHECK_EQ(0, offset);
     stats->leaves_++;
@@ -523,13 +524,10 @@
 }
 
 
-static ConsStringIteratorOp cons_string_iterator_op_1;
-static ConsStringIteratorOp cons_string_iterator_op_2;
-
 static void Traverse(Handle<String> s1, Handle<String> s2) {
   int i = 0;
-  StringCharacterStream character_stream_1(*s1, &cons_string_iterator_op_1);
-  StringCharacterStream character_stream_2(*s2, &cons_string_iterator_op_2);
+  StringCharacterStream character_stream_1(*s1);
+  StringCharacterStream character_stream_2(*s2);
   while (character_stream_1.HasMore()) {
     CHECK(character_stream_2.HasMore());
     uint16_t c = character_stream_1.GetNext();
@@ -545,8 +543,8 @@
 
 static void TraverseFirst(Handle<String> s1, Handle<String> s2, int chars) {
   int i = 0;
-  StringCharacterStream character_stream_1(*s1, &cons_string_iterator_op_1);
-  StringCharacterStream character_stream_2(*s2, &cons_string_iterator_op_2);
+  StringCharacterStream character_stream_1(*s1);
+  StringCharacterStream character_stream_2(*s2);
   while (character_stream_1.HasMore() && i < chars) {
     CHECK(character_stream_2.HasMore());
     uint16_t c = character_stream_1.GetNext();
@@ -615,10 +613,8 @@
     if (offset < 0) offset = 0;
     // Want to test the offset == length case.
     if (offset > length) offset = length;
-    StringCharacterStream flat_stream(
-        flat_string, &cons_string_iterator_op_1, offset);
-    StringCharacterStream cons_stream(
-        cons_string, &cons_string_iterator_op_2, offset);
+    StringCharacterStream flat_stream(flat_string, offset);
+    StringCharacterStream cons_stream(cons_string, offset);
     for (int i = offset; i < length; i++) {
       uint16_t c = flat_string->Get(i);
       CHECK(flat_stream.HasMore());
@@ -634,14 +630,11 @@
 
 static inline void PrintStats(const ConsStringGenerationData& data) {
 #ifdef DEBUG
-printf(
-    "%s: [%d], %s: [%d], %s: [%d], %s: [%d], %s: [%d], %s: [%d]\n",
-    "leaves", data.stats_.leaves_,
-    "empty", data.stats_.empty_leaves_,
-    "chars", data.stats_.chars_,
-    "lefts", data.stats_.left_traversals_,
-    "rights", data.stats_.right_traversals_,
-    "early_terminations", data.early_terminations_);
+  printf("%s: [%u], %s: [%u], %s: [%u], %s: [%u], %s: [%u], %s: [%u]\n",
+         "leaves", data.stats_.leaves_, "empty", data.stats_.empty_leaves_,
+         "chars", data.stats_.chars_, "lefts", data.stats_.left_traversals_,
+         "rights", data.stats_.right_traversals_, "early_terminations",
+         data.early_terminations_);
 #endif
 }
 
@@ -1027,11 +1020,13 @@
   // into a two-byte external string.  Check that JSON.stringify works.
   v8::HandleScope handle_scope(CcTest::isolate());
   v8::Handle<v8::String> underlying =
-      CompileRun("var underlying = 'abcdefghijklmnopqrstuvwxyz';"
-                 "underlying")->ToString();
-  v8::Handle<v8::String> slice =
-      CompileRun("var slice = underlying.slice(1);"
-                 "slice")->ToString();
+      CompileRun(
+          "var underlying = 'abcdefghijklmnopqrstuvwxyz';"
+          "underlying")->ToString(CcTest::isolate());
+  v8::Handle<v8::String> slice = CompileRun(
+                                     "var slice = '';"
+                                     "slice = underlying.slice(1);"
+                                     "slice")->ToString(CcTest::isolate());
   CHECK(v8::Utils::OpenHandle(*slice)->IsSlicedString());
   CHECK(v8::Utils::OpenHandle(*underlying)->IsSeqOneByteString());
 
@@ -1089,7 +1084,7 @@
     CHECK_EQ(results[i]->IsNumber(), result->IsNumber());
     if (result->IsNumber()) {
       CHECK_EQ(Object::ToSmi(isolate, results[i]).ToHandleChecked()->value(),
-               result->ToInt32()->Value());
+               result->ToInt32(CcTest::isolate())->Value());
     }
   }
 }
@@ -1189,7 +1184,7 @@
   v8::Local<v8::Value> result;
   Handle<String> string;
   const char* init = "var str = 'abcdefghijklmnopqrstuvwxyz';";
-  const char* slice = "var slice = str.slice(1,-1); slice";
+  const char* slice = "var slice = ''; slice = str.slice(1,-1); slice";
   const char* slice_from_slice = "slice.slice(1,-1);";
 
   CompileRun(init);
@@ -1292,6 +1287,42 @@
 }
 
 
+namespace {
+
+int* global_use_counts = NULL;
+
+void MockUseCounterCallback(v8::Isolate* isolate,
+                            v8::Isolate::UseCounterFeature feature) {
+  ++global_use_counts[feature];
+}
+}
+
+
+TEST(CountBreakIterator) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  LocalContext context;
+  int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
+  global_use_counts = use_counts;
+  CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
+  CHECK_EQ(0, use_counts[v8::Isolate::kBreakIterator]);
+  v8::Local<v8::Value> result = CompileRun(
+      "(function() {"
+      "  if (!this.Intl) return 0;"
+      "  var iterator = Intl.v8BreakIterator(['en']);"
+      "  iterator.adoptText('Now is the time');"
+      "  iterator.next();"
+      "  return iterator.next();"
+      "})();");
+  CHECK(result->IsNumber());
+  int uses = result->ToInt32(CcTest::isolate())->Value() == 0 ? 0 : 1;
+  CHECK_EQ(uses, use_counts[v8::Isolate::kBreakIterator]);
+  // Make sure GC cleans up the break iterator, so we don't get a memory leak
+  // reported by ASAN.
+  CcTest::isolate()->LowMemoryNotification();
+}
+
+
 TEST(StringReplaceAtomTwoByteResult) {
   CcTest::InitializeVM();
   v8::HandleScope scope(CcTest::isolate());
diff --git a/test/cctest/test-transitions.cc b/test/cctest/test-transitions.cc
new file mode 100644
index 0000000..6bcdb35
--- /dev/null
+++ b/test/cctest/test-transitions.cc
@@ -0,0 +1,301 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdlib.h>
+#include <utility>
+
+#include "src/v8.h"
+
+#include "src/compilation-cache.h"
+#include "src/execution.h"
+#include "src/factory.h"
+#include "src/global-handles.h"
+#include "test/cctest/cctest.h"
+
+using namespace v8::internal;
+
+
+//
+// Helper functions.
+//
+
+static void ConnectTransition(Handle<Map> parent,
+                              Handle<TransitionArray> transitions,
+                              Handle<Map> child) {
+  if (!parent->HasTransitionArray() || *transitions != parent->transitions()) {
+    parent->set_transitions(*transitions);
+  }
+  child->SetBackPointer(*parent);
+}
+
+
+static void CheckPropertyDetailsFieldsConsistency(PropertyType type,
+                                                  PropertyKind kind,
+                                                  PropertyLocation location) {
+  int type_value = PropertyDetails::TypeField::encode(type);
+  int kind_location_value = PropertyDetails::KindField::encode(kind) |
+                            PropertyDetails::LocationField::encode(location);
+  CHECK_EQ(type_value, kind_location_value);
+}
+
+
+TEST(PropertyDetailsFieldsConsistency) {
+  CheckPropertyDetailsFieldsConsistency(FIELD, DATA, IN_OBJECT);
+  CheckPropertyDetailsFieldsConsistency(CONSTANT, DATA, IN_DESCRIPTOR);
+  CheckPropertyDetailsFieldsConsistency(ACCESSOR_FIELD, ACCESSOR, IN_OBJECT);
+  CheckPropertyDetailsFieldsConsistency(CALLBACKS, ACCESSOR, IN_DESCRIPTOR);
+}
+
+
+TEST(TransitionArray_SimpleFieldTransitions) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  Handle<String> name1 = factory->InternalizeUtf8String("foo");
+  Handle<String> name2 = factory->InternalizeUtf8String("bar");
+  PropertyAttributes attributes = NONE;
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  Handle<Map> map1 =
+      Map::CopyWithField(map0, name1, handle(HeapType::Any(), isolate),
+                         attributes, Representation::Tagged(),
+                         OMIT_TRANSITION).ToHandleChecked();
+  Handle<Map> map2 =
+      Map::CopyWithField(map0, name2, handle(HeapType::Any(), isolate),
+                         attributes, Representation::Tagged(),
+                         OMIT_TRANSITION).ToHandleChecked();
+
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  int transition;
+  transitions =
+      transitions->Insert(map0, name1, map1, SIMPLE_PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map1);
+  CHECK(transitions->IsSimpleTransition());
+  transition = transitions->Search(DATA, *name1, attributes);
+  CHECK_EQ(TransitionArray::kSimpleTransitionIndex, transition);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transitions =
+      transitions->Insert(map0, name2, map2, SIMPLE_PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map2);
+  CHECK(transitions->IsFullTransitionArray());
+
+  transition = transitions->Search(DATA, *name1, attributes);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transition = transitions->Search(DATA, *name2, attributes);
+  CHECK_EQ(*name2, transitions->GetKey(transition));
+  CHECK_EQ(*map2, transitions->GetTarget(transition));
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
+
+
+TEST(TransitionArray_FullFieldTransitions) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  Handle<String> name1 = factory->InternalizeUtf8String("foo");
+  Handle<String> name2 = factory->InternalizeUtf8String("bar");
+  PropertyAttributes attributes = NONE;
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  Handle<Map> map1 =
+      Map::CopyWithField(map0, name1, handle(HeapType::Any(), isolate),
+                         attributes, Representation::Tagged(),
+                         OMIT_TRANSITION).ToHandleChecked();
+  Handle<Map> map2 =
+      Map::CopyWithField(map0, name2, handle(HeapType::Any(), isolate),
+                         attributes, Representation::Tagged(),
+                         OMIT_TRANSITION).ToHandleChecked();
+
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  int transition;
+  transitions = transitions->Insert(map0, name1, map1, PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map1);
+  CHECK(transitions->IsFullTransitionArray());
+  transition = transitions->Search(DATA, *name1, attributes);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transitions = transitions->Insert(map0, name2, map2, PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map2);
+  CHECK(transitions->IsFullTransitionArray());
+
+  transition = transitions->Search(DATA, *name1, attributes);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transition = transitions->Search(DATA, *name2, attributes);
+  CHECK_EQ(*name2, transitions->GetKey(transition));
+  CHECK_EQ(*map2, transitions->GetTarget(transition));
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
+
+
+TEST(TransitionArray_DifferentFieldNames) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  const int PROPS_COUNT = 10;
+  Handle<String> names[PROPS_COUNT];
+  Handle<Map> maps[PROPS_COUNT];
+  PropertyAttributes attributes = NONE;
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  for (int i = 0; i < PROPS_COUNT; i++) {
+    EmbeddedVector<char, 64> buffer;
+    SNPrintF(buffer, "prop%d", i);
+    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
+    Handle<Map> map =
+        Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate),
+                           attributes, Representation::Tagged(),
+                           OMIT_TRANSITION).ToHandleChecked();
+    names[i] = name;
+    maps[i] = map;
+
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
+  }
+
+  for (int i = 0; i < PROPS_COUNT; i++) {
+    int transition = transitions->Search(DATA, *names[i], attributes);
+    CHECK_EQ(*names[i], transitions->GetKey(transition));
+    CHECK_EQ(*maps[i], transitions->GetTarget(transition));
+  }
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
+
+
+TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
+  STATIC_ASSERT(ATTRS_COUNT == 8);
+  Handle<Map> attr_maps[ATTRS_COUNT];
+  Handle<String> name = factory->InternalizeUtf8String("foo");
+
+  // Add transitions for same field name but different attributes.
+  for (int i = 0; i < ATTRS_COUNT; i++) {
+    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
+
+    Handle<Map> map =
+        Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate),
+                           attributes, Representation::Tagged(),
+                           OMIT_TRANSITION).ToHandleChecked();
+    attr_maps[i] = map;
+
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
+  }
+
+  // Ensure that transitions for |name| field are valid.
+  for (int i = 0; i < ATTRS_COUNT; i++) {
+    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
+
+    int transition = transitions->Search(DATA, *name, attributes);
+    CHECK_EQ(*name, transitions->GetKey(transition));
+    CHECK_EQ(*attr_maps[i], transitions->GetTarget(transition));
+  }
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
+
+
+TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  const int PROPS_COUNT = 10;
+  Handle<String> names[PROPS_COUNT];
+  Handle<Map> maps[PROPS_COUNT];
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  // Some number of fields.
+  for (int i = 0; i < PROPS_COUNT; i++) {
+    EmbeddedVector<char, 64> buffer;
+    SNPrintF(buffer, "prop%d", i);
+    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
+    Handle<Map> map =
+        Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate), NONE,
+                           Representation::Tagged(),
+                           OMIT_TRANSITION).ToHandleChecked();
+    names[i] = name;
+    maps[i] = map;
+
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
+  }
+
+  const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
+  STATIC_ASSERT(ATTRS_COUNT == 8);
+  Handle<Map> attr_maps[ATTRS_COUNT];
+  Handle<String> name = factory->InternalizeUtf8String("foo");
+
+  // Add transitions for same field name but different attributes.
+  for (int i = 0; i < ATTRS_COUNT; i++) {
+    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
+
+    Handle<Map> map =
+        Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate),
+                           attributes, Representation::Tagged(),
+                           OMIT_TRANSITION).ToHandleChecked();
+    attr_maps[i] = map;
+
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
+  }
+
+  // Ensure that transitions for |name| field are valid.
+  for (int i = 0; i < ATTRS_COUNT; i++) {
+    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
+
+    int transition = transitions->Search(DATA, *name, attributes);
+    CHECK_EQ(*name, transitions->GetKey(transition));
+    CHECK_EQ(*attr_maps[i], transitions->GetTarget(transition));
+  }
+
+  // Ensure that info about the other fields still valid.
+  for (int i = 0; i < PROPS_COUNT; i++) {
+    int transition = transitions->Search(DATA, *names[i], NONE);
+    CHECK_EQ(*names[i], transitions->GetKey(transition));
+    CHECK_EQ(*maps[i], transitions->GetTarget(transition));
+  }
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
diff --git a/test/cctest/test-types.cc b/test/cctest/test-types.cc
index 0cd2472..ebef527 100644
--- a/test/cctest/test-types.cc
+++ b/test/cctest/test-types.cc
@@ -8,12 +8,27 @@
 #include "src/isolate-inl.h"
 #include "src/types.h"
 #include "test/cctest/cctest.h"
+#include "test/cctest/types-fuzz.h"
 
 using namespace v8::internal;
 
+
 // Testing auxiliaries (breaking the Type abstraction).
+
+
+static bool IsInteger(double x) {
+  return nearbyint(x) == x && !i::IsMinusZero(x);  // Allows for infinities.
+}
+
+
+static bool IsInteger(i::Object* x) {
+  return x->IsNumber() && IsInteger(x->Number());
+}
+
+
 typedef uint32_t bitset;
 
+
 struct ZoneRep {
   typedef void* Struct;
 
@@ -76,262 +91,6 @@
 };
 
 
-template<class Type, class TypeHandle, class Region>
-class Types {
- public:
-  Types(Region* region, Isolate* isolate)
-      : region_(region), rng_(isolate->random_number_generator()) {
-    #define DECLARE_TYPE(name, value) \
-      name = Type::name(region); \
-      types.push_back(name);
-    PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
-    #undef DECLARE_TYPE
-
-    object_map = isolate->factory()->NewMap(
-        JS_OBJECT_TYPE, JSObject::kHeaderSize);
-    array_map = isolate->factory()->NewMap(
-        JS_ARRAY_TYPE, JSArray::kSize);
-    number_map = isolate->factory()->NewMap(
-        HEAP_NUMBER_TYPE, HeapNumber::kSize);
-    uninitialized_map = isolate->factory()->uninitialized_map();
-    ObjectClass = Type::Class(object_map, region);
-    ArrayClass = Type::Class(array_map, region);
-    NumberClass = Type::Class(number_map, region);
-    UninitializedClass = Type::Class(uninitialized_map, region);
-
-    maps.push_back(object_map);
-    maps.push_back(array_map);
-    maps.push_back(uninitialized_map);
-    for (MapVector::iterator it = maps.begin(); it != maps.end(); ++it) {
-      types.push_back(Type::Class(*it, region));
-    }
-
-    smi = handle(Smi::FromInt(666), isolate);
-    signed32 = isolate->factory()->NewHeapNumber(0x40000000);
-    object1 = isolate->factory()->NewJSObjectFromMap(object_map);
-    object2 = isolate->factory()->NewJSObjectFromMap(object_map);
-    array = isolate->factory()->NewJSArray(20);
-    uninitialized = isolate->factory()->uninitialized_value();
-    SmiConstant = Type::Constant(smi, region);
-    Signed32Constant = Type::Constant(signed32, region);
-    ObjectConstant1 = Type::Constant(object1, region);
-    ObjectConstant2 = Type::Constant(object2, region);
-    ArrayConstant = Type::Constant(array, region);
-    UninitializedConstant = Type::Constant(uninitialized, region);
-
-    values.push_back(smi);
-    values.push_back(signed32);
-    values.push_back(object1);
-    values.push_back(object2);
-    values.push_back(array);
-    values.push_back(uninitialized);
-    for (ValueVector::iterator it = values.begin(); it != values.end(); ++it) {
-      types.push_back(Type::Constant(*it, region));
-    }
-
-    integers.push_back(isolate->factory()->NewNumber(-V8_INFINITY));
-    integers.push_back(isolate->factory()->NewNumber(+V8_INFINITY));
-    integers.push_back(isolate->factory()->NewNumber(-rng_->NextInt(10)));
-    integers.push_back(isolate->factory()->NewNumber(+rng_->NextInt(10)));
-    for (int i = 0; i < 10; ++i) {
-      double x = rng_->NextInt();
-      integers.push_back(isolate->factory()->NewNumber(x));
-      x *= rng_->NextInt();
-      if (!IsMinusZero(x)) integers.push_back(isolate->factory()->NewNumber(x));
-    }
-
-    NumberArray = Type::Array(Number, region);
-    StringArray = Type::Array(String, region);
-    AnyArray = Type::Array(Any, region);
-
-    SignedFunction1 = Type::Function(SignedSmall, SignedSmall, region);
-    NumberFunction1 = Type::Function(Number, Number, region);
-    NumberFunction2 = Type::Function(Number, Number, Number, region);
-    MethodFunction = Type::Function(String, Object, 0, region);
-
-    for (int i = 0; i < 30; ++i) {
-      types.push_back(Fuzz());
-    }
-  }
-
-  Handle<i::Map> object_map;
-  Handle<i::Map> array_map;
-  Handle<i::Map> number_map;
-  Handle<i::Map> uninitialized_map;
-
-  Handle<i::Smi> smi;
-  Handle<i::HeapNumber> signed32;
-  Handle<i::JSObject> object1;
-  Handle<i::JSObject> object2;
-  Handle<i::JSArray> array;
-  Handle<i::Oddball> uninitialized;
-
-  #define DECLARE_TYPE(name, value) TypeHandle name;
-  BITSET_TYPE_LIST(DECLARE_TYPE)
-  #undef DECLARE_TYPE
-
-  TypeHandle ObjectClass;
-  TypeHandle ArrayClass;
-  TypeHandle NumberClass;
-  TypeHandle UninitializedClass;
-
-  TypeHandle SmiConstant;
-  TypeHandle Signed32Constant;
-  TypeHandle ObjectConstant1;
-  TypeHandle ObjectConstant2;
-  TypeHandle ArrayConstant;
-  TypeHandle UninitializedConstant;
-
-  TypeHandle NumberArray;
-  TypeHandle StringArray;
-  TypeHandle AnyArray;
-
-  TypeHandle SignedFunction1;
-  TypeHandle NumberFunction1;
-  TypeHandle NumberFunction2;
-  TypeHandle MethodFunction;
-
-  typedef std::vector<TypeHandle> TypeVector;
-  typedef std::vector<Handle<i::Map> > MapVector;
-  typedef std::vector<Handle<i::Object> > ValueVector;
-
-  TypeVector types;
-  MapVector maps;
-  ValueVector values;
-  ValueVector integers;  // "Integer" values used for range limits.
-
-  TypeHandle Of(Handle<i::Object> value) {
-    return Type::Of(value, region_);
-  }
-
-  TypeHandle NowOf(Handle<i::Object> value) {
-    return Type::NowOf(value, region_);
-  }
-
-  TypeHandle Class(Handle<i::Map> map) {
-    return Type::Class(map, region_);
-  }
-
-  TypeHandle Constant(Handle<i::Object> value) {
-    return Type::Constant(value, region_);
-  }
-
-  TypeHandle Range(Handle<i::Object> min, Handle<i::Object> max) {
-    return Type::Range(min, max, region_);
-  }
-
-  TypeHandle Context(TypeHandle outer) {
-    return Type::Context(outer, region_);
-  }
-
-  TypeHandle Array1(TypeHandle element) {
-    return Type::Array(element, region_);
-  }
-
-  TypeHandle Function0(TypeHandle result, TypeHandle receiver) {
-    return Type::Function(result, receiver, 0, region_);
-  }
-
-  TypeHandle Function1(TypeHandle result, TypeHandle receiver, TypeHandle arg) {
-    TypeHandle type = Type::Function(result, receiver, 1, region_);
-    type->AsFunction()->InitParameter(0, arg);
-    return type;
-  }
-
-  TypeHandle Function2(TypeHandle result, TypeHandle arg1, TypeHandle arg2) {
-    return Type::Function(result, arg1, arg2, region_);
-  }
-
-  TypeHandle Union(TypeHandle t1, TypeHandle t2) {
-    return Type::Union(t1, t2, region_);
-  }
-  TypeHandle Intersect(TypeHandle t1, TypeHandle t2) {
-    return Type::Intersect(t1, t2, region_);
-  }
-
-  template<class Type2, class TypeHandle2>
-  TypeHandle Convert(TypeHandle2 t) {
-    return Type::template Convert<Type2>(t, region_);
-  }
-
-  TypeHandle Random() {
-    return types[rng_->NextInt(static_cast<int>(types.size()))];
-  }
-
-  TypeHandle Fuzz(int depth = 4) {
-    switch (rng_->NextInt(depth == 0 ? 3 : 20)) {
-      case 0: {  // bitset
-        int n = 0
-        #define COUNT_BITSET_TYPES(type, value) + 1
-        PROPER_BITSET_TYPE_LIST(COUNT_BITSET_TYPES)
-        #undef COUNT_BITSET_TYPES
-        ;
-        int i = rng_->NextInt(n);
-        #define PICK_BITSET_TYPE(type, value) \
-          if (i-- == 0) return Type::type(region_);
-        PROPER_BITSET_TYPE_LIST(PICK_BITSET_TYPE)
-        #undef PICK_BITSET_TYPE
-        UNREACHABLE();
-      }
-      case 1: {  // class
-        int i = rng_->NextInt(static_cast<int>(maps.size()));
-        return Type::Class(maps[i], region_);
-      }
-      case 2: {  // constant
-        int i = rng_->NextInt(static_cast<int>(values.size()));
-        return Type::Constant(values[i], region_);
-      }
-      case 3: {  // range
-        int i = rng_->NextInt(static_cast<int>(integers.size()));
-        int j = rng_->NextInt(static_cast<int>(integers.size()));
-        i::Handle<i::Object> min = integers[i];
-        i::Handle<i::Object> max = integers[j];
-        if (min->Number() > max->Number()) std::swap(min, max);
-        return Type::Range(min, max, region_);
-      }
-      case 4: {  // context
-        int depth = rng_->NextInt(3);
-        TypeHandle type = Type::Internal(region_);
-        for (int i = 0; i < depth; ++i) type = Type::Context(type, region_);
-        return type;
-      }
-      case 5: {  // array
-        TypeHandle element = Fuzz(depth / 2);
-        return Type::Array(element, region_);
-      }
-      case 6:
-      case 7: {  // function
-        TypeHandle result = Fuzz(depth / 2);
-        TypeHandle receiver = Fuzz(depth / 2);
-        int arity = rng_->NextInt(3);
-        TypeHandle type = Type::Function(result, receiver, arity, region_);
-        for (int i = 0; i < type->AsFunction()->Arity(); ++i) {
-          TypeHandle parameter = Fuzz(depth / 2);
-          type->AsFunction()->InitParameter(i, parameter);
-        }
-        return type;
-      }
-      default: {  // union
-        int n = rng_->NextInt(10);
-        TypeHandle type = None;
-        for (int i = 0; i < n; ++i) {
-          TypeHandle operand = Fuzz(depth - 1);
-          type = Type::Union(type, operand, region_);
-        }
-        return type;
-      }
-    }
-    UNREACHABLE();
-  }
-
-  Region* region() { return region_; }
-
- private:
-  Region* region_;
-  v8::base::RandomNumberGenerator* rng_;
-};
-
-
 template<class Type, class TypeHandle, class Region, class Rep>
 struct Tests : Rep {
   typedef Types<Type, TypeHandle, Region> TypesInstance;
@@ -535,39 +294,55 @@
     CHECK(T.Constant(fac->NewNumber(0))->Is(T.UnsignedSmall));
     CHECK(T.Constant(fac->NewNumber(1))->Is(T.UnsignedSmall));
     CHECK(T.Constant(fac->NewNumber(0x3fffffff))->Is(T.UnsignedSmall));
-    CHECK(T.Constant(fac->NewNumber(-1))->Is(T.OtherSignedSmall));
-    CHECK(T.Constant(fac->NewNumber(-0x3fffffff))->Is(T.OtherSignedSmall));
-    CHECK(T.Constant(fac->NewNumber(-0x40000000))->Is(T.OtherSignedSmall));
+    CHECK(T.Constant(fac->NewNumber(-1))->Is(T.NegativeSignedSmall));
+    CHECK(T.Constant(fac->NewNumber(-0x3fffffff))->Is(T.NegativeSignedSmall));
+    CHECK(T.Constant(fac->NewNumber(-0x40000000))->Is(T.NegativeSignedSmall));
     if (SmiValuesAre31Bits()) {
-      CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.OtherUnsigned31));
-      CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.OtherUnsigned31));
-      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSigned32));
-      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSigned32));
-      CHECK(T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSigned32));
+      CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.NonNegativeSigned32));
+      CHECK(!T.Constant(fac->NewNumber(0x40000000))->Is(T.UnsignedSmall));
+      CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.NonNegativeSigned32));
+      CHECK(!T.Constant(fac->NewNumber(0x7fffffff))->Is(T.UnsignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.NegativeSigned32));
+      CHECK(
+          !T.Constant(fac->NewNumber(-0x40000001))->Is(T.NegativeSignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.NegativeSigned32));
+      CHECK(!T.Constant(fac->NewNumber(-0x7fffffff - 1))
+                 ->Is(T.NegativeSignedSmall));
     } else {
       CHECK(SmiValuesAre32Bits());
       CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.UnsignedSmall));
       CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.UnsignedSmall));
-      CHECK(!T.Constant(fac->NewNumber(0x40000000))->Is(T.OtherUnsigned31));
-      CHECK(!T.Constant(fac->NewNumber(0x7fffffff))->Is(T.OtherUnsigned31));
-      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSignedSmall));
-      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSignedSmall));
-      CHECK(T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSignedSmall));
-      CHECK(!T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSigned32));
-      CHECK(!T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSigned32));
-      CHECK(!T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSigned32));
+      CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.NonNegativeSigned32));
+      CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.NonNegativeSigned32));
+      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.NegativeSignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.NegativeSignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff - 1))
+                ->Is(T.NegativeSignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.NegativeSigned32));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.NegativeSigned32));
+      CHECK(
+          T.Constant(fac->NewNumber(-0x7fffffff - 1))->Is(T.NegativeSigned32));
     }
-    CHECK(T.Constant(fac->NewNumber(0x80000000u))->Is(T.OtherUnsigned32));
-    CHECK(T.Constant(fac->NewNumber(0xffffffffu))->Is(T.OtherUnsigned32));
-    CHECK(T.Constant(fac->NewNumber(0xffffffffu+1.0))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(-0x7fffffff-2.0))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(0.1))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(-10.1))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(10e60))->Is(T.OtherNumber));
+    CHECK(T.Constant(fac->NewNumber(0x80000000u))->Is(T.Unsigned32));
+    CHECK(!T.Constant(fac->NewNumber(0x80000000u))->Is(T.NonNegativeSigned32));
+    CHECK(T.Constant(fac->NewNumber(0xffffffffu))->Is(T.Unsigned32));
+    CHECK(!T.Constant(fac->NewNumber(0xffffffffu))->Is(T.NonNegativeSigned32));
+    CHECK(T.Constant(fac->NewNumber(0xffffffffu + 1.0))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(0xffffffffu + 1.0))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(-0x7fffffff - 2.0))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(-0x7fffffff - 2.0))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(0.1))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(0.1))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(-10.1))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(-10.1))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(10e60))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(10e60))->Is(T.Integral32));
     CHECK(T.Constant(fac->NewNumber(-1.0*0.0))->Is(T.MinusZero));
     CHECK(T.Constant(fac->NewNumber(v8::base::OS::nan_value()))->Is(T.NaN));
-    CHECK(T.Constant(fac->NewNumber(V8_INFINITY))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.OtherNumber));
+    CHECK(T.Constant(fac->NewNumber(V8_INFINITY))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(V8_INFINITY))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.Integral32));
   }
 
   void Range() {
@@ -598,11 +373,11 @@
     // Range(min1, max1) = Range(min2, max2) <=> min1 = min2 /\ max1 = max2
     for (ValueIterator i1 = T.integers.begin();
         i1 != T.integers.end(); ++i1) {
-      for (ValueIterator j1 = T.integers.begin();
+      for (ValueIterator j1 = i1;
           j1 != T.integers.end(); ++j1) {
         for (ValueIterator i2 = T.integers.begin();
             i2 != T.integers.end(); ++i2) {
-          for (ValueIterator j2 = T.integers.begin();
+          for (ValueIterator j2 = i2;
               j2 != T.integers.end(); ++j2) {
             i::Handle<i::Object> min1 = *i1;
             i::Handle<i::Object> max1 = *j1;
@@ -619,6 +394,33 @@
     }
   }
 
+  void Context() {
+    // Constructor
+    for (int i = 0; i < 20; ++i) {
+      TypeHandle type = T.Random();
+      TypeHandle context = T.Context(type);
+      CHECK(context->Iscontext());
+    }
+
+    // Attributes
+    for (int i = 0; i < 20; ++i) {
+      TypeHandle type = T.Random();
+      TypeHandle context = T.Context(type);
+      CheckEqual(type, context->AsContext()->Outer());
+    }
+
+    // Functionality & Injectivity: Context(T1) = Context(T2) iff T1 = T2
+    for (int i = 0; i < 20; ++i) {
+      for (int j = 0; j < 20; ++j) {
+        TypeHandle type1 = T.Random();
+        TypeHandle type2 = T.Random();
+        TypeHandle context1 = T.Context(type1);
+        TypeHandle context2 = T.Context(type2);
+        CHECK(Equal(context1, context2) == Equal(type1, type2));
+      }
+    }
+  }
+
   void Array() {
     // Constructor
     for (int i = 0; i < 20; ++i) {
@@ -803,6 +605,66 @@
     }
   }
 
+  void MinMax() {
+    Factory* fac = isolate->factory();
+
+    // If b is regular numeric bitset, then Range(b->Min(), b->Max())->Is(b).
+    // TODO(neis): Need to ignore representation for this to be true.
+    /*
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (this->IsBitset(type) && type->Is(T.Number) &&
+          !type->Is(T.None) && !type->Is(T.NaN)) {
+        TypeHandle range = T.Range(
+            isolate->factory()->NewNumber(type->Min()),
+            isolate->factory()->NewNumber(type->Max()));
+        CHECK(range->Is(type));
+      }
+    }
+    */
+
+    // If b is regular numeric bitset, then b->Min() and b->Max() are integers.
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (this->IsBitset(type) && type->Is(T.Number) && !type->Is(T.NaN)) {
+        CHECK(IsInteger(type->Min()) && IsInteger(type->Max()));
+      }
+    }
+
+    // If b1 and b2 are regular numeric bitsets with b1->Is(b2), then
+    // b1->Min() >= b2->Min() and b1->Max() <= b2->Max().
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+        TypeHandle type1 = *it1;
+        TypeHandle type2 = *it2;
+        if (this->IsBitset(type1) && type1->Is(type2) && type2->Is(T.Number) &&
+            !type1->Is(T.NaN) && !type2->Is(T.NaN)) {
+          CHECK(type1->Min() >= type2->Min());
+          CHECK(type1->Max() <= type2->Max());
+        }
+      }
+    }
+
+    // Lub(Range(x,y))->Min() <= x and y <= Lub(Range(x,y))->Max()
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (type->IsRange()) {
+        TypeHandle lub = Rep::BitsetType::New(
+            Rep::BitsetType::Lub(type), T.region());
+        CHECK(lub->Min() <= type->Min() && type->Max() <= lub->Max());
+      }
+    }
+
+    // Rangification: If T->Is(Range(-inf,+inf)) and !T->Is(None), then
+    // T->Is(Range(T->Min(), T->Max())).
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      CHECK(!(type->Is(T.Integer) && !type->Is(T.None)) ||
+            type->Is(T.Range(fac->NewNumber(type->Min()),
+                             fac->NewNumber(type->Max()))));
+    }
+  }
+
   void BitsetGlb() {
     // Lower: (T->BitsetGlb())->Is(T)
     for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
@@ -871,7 +733,7 @@
     }
   }
 
-  void Is() {
+  void Is1() {
     // Least Element (Bottom): None->Is(T)
     for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
       TypeHandle type = *it;
@@ -923,6 +785,26 @@
       }
     }
 
+    // (In-)Compatibilities.
+    for (TypeIterator i = T.types.begin(); i != T.types.end(); ++i) {
+      for (TypeIterator j = T.types.begin(); j != T.types.end(); ++j) {
+        TypeHandle type1 = *i;
+        TypeHandle type2 = *j;
+        CHECK(!type1->Is(type2) || this->IsBitset(type2) ||
+              this->IsUnion(type2) || this->IsUnion(type1) ||
+              (type1->IsClass() && type2->IsClass()) ||
+              (type1->IsConstant() && type2->IsConstant()) ||
+              (type1->IsConstant() && type2->IsRange()) ||
+              (type1->IsRange() && type2->IsRange()) ||
+              (type1->IsContext() && type2->IsContext()) ||
+              (type1->IsArray() && type2->IsArray()) ||
+              (type1->IsFunction() && type2->IsFunction()) ||
+              type1->Equals(T.None));
+      }
+    }
+  }
+
+  void Is2() {
     // Class(M1)->Is(Class(M2)) iff M1 = M2
     for (MapIterator mt1 = T.maps.begin(); mt1 != T.maps.end(); ++mt1) {
       for (MapIterator mt2 = T.maps.begin(); mt2 != T.maps.end(); ++mt2) {
@@ -934,26 +816,14 @@
       }
     }
 
-    // Constant(V1)->Is(Constant(V2)) iff V1 = V2
-    for (ValueIterator vt1 = T.values.begin(); vt1 != T.values.end(); ++vt1) {
-      for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) {
-        Handle<i::Object> value1 = *vt1;
-        Handle<i::Object> value2 = *vt2;
-        TypeHandle const_type1 = T.Constant(value1);
-        TypeHandle const_type2 = T.Constant(value2);
-        CHECK(const_type1->Is(const_type2) == (*value1 == *value2));
-      }
-    }
-
-    // Range(min1, max1)->Is(Range(min2, max2)) iff
-    // min1 >= min2 /\ max1 <= max2
+    // Range(X1, Y1)->Is(Range(X2, Y2)) iff X1 >= X2 /\ Y1 <= Y2
     for (ValueIterator i1 = T.integers.begin();
         i1 != T.integers.end(); ++i1) {
-      for (ValueIterator j1 = T.integers.begin();
+      for (ValueIterator j1 = i1;
           j1 != T.integers.end(); ++j1) {
         for (ValueIterator i2 = T.integers.begin();
              i2 != T.integers.end(); ++i2) {
-          for (ValueIterator j2 = T.integers.begin();
+          for (ValueIterator j2 = i2;
                j2 != T.integers.end(); ++j2) {
             i::Handle<i::Object> min1 = *i1;
             i::Handle<i::Object> max1 = *j1;
@@ -964,13 +834,24 @@
             TypeHandle type1 = T.Range(min1, max1);
             TypeHandle type2 = T.Range(min2, max2);
             CHECK(type1->Is(type2) ==
-                (min2->Number() <= min1->Number() &&
+                (min1->Number() >= min2->Number() &&
                  max1->Number() <= max2->Number()));
           }
         }
       }
     }
 
+    // Constant(V1)->Is(Constant(V2)) iff V1 = V2
+    for (ValueIterator vt1 = T.values.begin(); vt1 != T.values.end(); ++vt1) {
+      for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) {
+        Handle<i::Object> value1 = *vt1;
+        Handle<i::Object> value2 = *vt2;
+        TypeHandle const_type1 = T.Constant(value1);
+        TypeHandle const_type2 = T.Constant(value2);
+        CHECK(const_type1->Is(const_type2) == (*value1 == *value2));
+      }
+    }
+
     // Context(T1)->Is(Context(T2)) iff T1 = T2
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1007,25 +888,45 @@
       }
     }
 
-    // (In-)Compatibilities.
-    for (TypeIterator i = T.types.begin(); i != T.types.end(); ++i) {
-      for (TypeIterator j = T.types.begin(); j != T.types.end(); ++j) {
-        TypeHandle type1 = *i;
-        TypeHandle type2 = *j;
-        CHECK(!type1->Is(type2) || this->IsBitset(type2) ||
-              this->IsUnion(type2) || this->IsUnion(type1) ||
-              (type1->IsClass() && type2->IsClass()) ||
-              (type1->IsConstant() && type2->IsConstant()) ||
-              (type1->IsConstant() && type2->IsRange()) ||
-              (type1->IsRange() && type2->IsRange()) ||
-              (type1->IsContext() && type2->IsContext()) ||
-              (type1->IsArray() && type2->IsArray()) ||
-              (type1->IsFunction() && type2->IsFunction()) ||
-              type1->Equals(T.None));
+
+    // Range-specific subtyping
+
+    // If IsInteger(v) then Constant(v)->Is(Range(v, v)).
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (type->IsConstant() && IsInteger(*type->AsConstant()->Value())) {
+        CHECK(type->Is(
+            T.Range(type->AsConstant()->Value(), type->AsConstant()->Value())));
       }
     }
 
-    // Basic types
+    // If Constant(x)->Is(Range(min,max)) then IsInteger(v) and min <= x <= max.
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+        TypeHandle type1 = *it1;
+        TypeHandle type2 = *it2;
+        if (type1->IsConstant() && type2->IsRange() && type1->Is(type2)) {
+          double x = type1->AsConstant()->Value()->Number();
+          double min = type2->AsRange()->Min()->Number();
+          double max = type2->AsRange()->Max()->Number();
+          CHECK(IsInteger(x) && min <= x && x <= max);
+        }
+      }
+    }
+
+    // Lub(Range(x,y))->Is(T.Union(T.Integral32, T.OtherNumber))
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (type->IsRange()) {
+        TypeHandle lub = Rep::BitsetType::New(
+            Rep::BitsetType::Lub(type), T.region());
+        CHECK(lub->Is(T.PlainNumber));
+      }
+    }
+
+
+    // Subtyping between concrete basic types
+
     CheckUnordered(T.Boolean, T.Null);
     CheckUnordered(T.Undefined, T.Null);
     CheckUnordered(T.Boolean, T.Undefined);
@@ -1049,12 +950,12 @@
 
     CheckSub(T.Object, T.Receiver);
     CheckSub(T.Array, T.Object);
-    CheckSub(T.Function, T.Object);
     CheckSub(T.Proxy, T.Receiver);
     CheckUnordered(T.Object, T.Proxy);
-    CheckUnordered(T.Array, T.Function);
 
-    // Structural types
+
+    // Subtyping between concrete structural types
+
     CheckSub(T.ObjectClass, T.Object);
     CheckSub(T.ArrayClass, T.Object);
     CheckSub(T.ArrayClass, T.Array);
@@ -1086,7 +987,7 @@
     CheckSub(T.NumberArray, T.Object);
     CheckUnordered(T.StringArray, T.AnyArray);
 
-    CheckSub(T.MethodFunction, T.Function);
+    CheckSub(T.MethodFunction, T.Object);
     CheckSub(T.NumberFunction1, T.Object);
     CheckUnordered(T.SignedFunction1, T.NumberFunction1);
     CheckUnordered(T.NumberFunction1, T.NumberFunction2);
@@ -1372,10 +1273,8 @@
     CheckDisjoint(T.InternalizedString, T.Symbol);
     CheckOverlap(T.Object, T.Receiver);
     CheckOverlap(T.Array, T.Object);
-    CheckOverlap(T.Function, T.Object);
     CheckOverlap(T.Proxy, T.Receiver);
     CheckDisjoint(T.Object, T.Proxy);
-    CheckDisjoint(T.Array, T.Function);
 
     // Structural types
     CheckOverlap(T.ObjectClass, T.Object);
@@ -1399,7 +1298,7 @@
     CheckOverlap(T.NumberArray, T.Array);
     CheckDisjoint(T.NumberArray, T.AnyArray);
     CheckDisjoint(T.NumberArray, T.StringArray);
-    CheckOverlap(T.MethodFunction, T.Function);
+    CheckOverlap(T.MethodFunction, T.Object);
     CheckDisjoint(T.SignedFunction1, T.NumberFunction1);
     CheckDisjoint(T.SignedFunction1, T.NumberFunction2);
     CheckDisjoint(T.NumberFunction1, T.NumberFunction2);
@@ -1443,7 +1342,9 @@
     }
 
     // Associativity: Union(T1, Union(T2, T3)) = Union(Union(T1, T2), T3)
-    // This does NOT hold!
+    // This does NOT hold!  For example:
+    // (Unsigned32 \/ Range(0,5)) \/ Range(-5,0) = Unsigned32 \/ Range(-5,0)
+    // Unsigned32 \/ (Range(0,5) \/ Range(-5,0)) = Unsigned32 \/ Range(-5,5)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1483,7 +1384,9 @@
     }
 
     // Monotonicity: T1->Is(T2) implies Union(T1, T3)->Is(Union(T2, T3))
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Range(-5,-1) <= Signed32
+    // Range(-5,-1) \/ Range(1,5) = Range(-5,5) </= Signed32 \/ Range(1,5)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1502,8 +1405,10 @@
 
   void Union2() {
     // Monotonicity: T1->Is(T3) and T2->Is(T3) implies Union(T1, T2)->Is(T3)
-    // This does NOT hold.  TODO(neis): Could fix this by splitting
-    // OtherNumber into a negative and a positive part.
+    // This does NOT hold.  For example:
+    // Range(-2^33, -2^33) <= OtherNumber
+    // Range(2^33, 2^33) <= OtherNumber
+    // Range(-2^33, 2^33) </= OtherNumber
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1523,7 +1428,7 @@
     // Monotonicity: T1->Is(T2) or T1->Is(T3) implies T1->Is(Union(T2, T3))
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
-        for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) {
+        for (TypeIterator it3 = it2; it3 != T.types.end(); ++it3) {
           TypeHandle type1 = *it1;
           TypeHandle type2 = *it2;
           TypeHandle type3 = *it3;
@@ -1563,11 +1468,11 @@
     CheckDisjoint(T.Union(T.NumberArray, T.String), T.Number);
 
     // Bitset-function
-    CHECK(this->IsBitset(T.Union(T.MethodFunction, T.Function)));
+    CHECK(this->IsBitset(T.Union(T.MethodFunction, T.Object)));
     CHECK(this->IsUnion(T.Union(T.NumberFunction1, T.Number)));
 
-    CheckEqual(T.Union(T.MethodFunction, T.Function), T.Function);
-    CheckUnordered(T.Union(T.NumberFunction1, T.String), T.Function);
+    CheckEqual(T.Union(T.MethodFunction, T.Object), T.Object);
+    CheckUnordered(T.Union(T.NumberFunction1, T.String), T.Object);
     CheckOverlap(T.Union(T.NumberFunction2, T.String), T.Object);
     CheckDisjoint(T.Union(T.NumberFunction1, T.String), T.Number);
 
@@ -1635,7 +1540,7 @@
     CheckEqual(
         T.Union(T.NumberFunction1, T.NumberFunction2),
         T.Union(T.NumberFunction2, T.NumberFunction1));
-    CheckSub(T.Union(T.SignedFunction1, T.MethodFunction), T.Function);
+    CheckSub(T.Union(T.SignedFunction1, T.MethodFunction), T.Object);
 
     // Union-union
     CheckEqual(
@@ -1685,7 +1590,11 @@
 
     // Associativity:
     // Intersect(T1, Intersect(T2, T3)) = Intersect(Intersect(T1, T2), T3)
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // (Class(..stringy1..) /\ Class(..stringy2..)) /\ Constant(..string..) =
+    // None
+    // Class(..stringy1..) /\ (Class(..stringy2..) /\ Constant(..string..)) =
+    // Constant(..string..)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1704,7 +1613,11 @@
     */
 
     // Join: Intersect(T1, T2)->Is(T1) and Intersect(T1, T2)->Is(T2)
-    // This does NOT hold.  Not even the disjunction.
+    // This does NOT hold.  For example:
+    // Class(..stringy..) /\ Constant(..string..) = Constant(..string..)
+    // Currently, not even the disjunction holds:
+    // Class(Internal/TaggedPtr) /\ (Any/Untagged \/ Context(..)) =
+    // Class(Internal/TaggedPtr) \/ Context(..)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1728,7 +1641,10 @@
     }
 
     // Monotonicity: T1->Is(T2) implies Intersect(T1, T3)->Is(Intersect(T2, T3))
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Class(OtherObject/TaggedPtr) <= Any/TaggedPtr
+    // Class(OtherObject/TaggedPtr) /\ Any/UntaggedInt1 = Class(..)
+    // Any/TaggedPtr /\ Any/UntaggedInt1 = None
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1745,7 +1661,10 @@
     */
 
     // Monotonicity: T1->Is(T3) or T2->Is(T3) implies Intersect(T1, T2)->Is(T3)
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Class(..stringy..) <= Class(..stringy..)
+    // Class(..stringy..) /\ Constant(..string..) = Constant(..string..)
+    // Constant(..string..) </= Class(..stringy..)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1762,8 +1681,6 @@
     */
 
     // Monotonicity: T1->Is(T2) and T1->Is(T3) implies T1->Is(Intersect(T2, T3))
-    // This does NOT hold.
-    /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
         for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) {
@@ -1776,7 +1693,6 @@
         }
       }
     }
-    */
 
     // Bitset-class
     CheckEqual(T.Intersect(T.ObjectClass, T.Object), T.ObjectClass);
@@ -1785,11 +1701,11 @@
 
     // Bitset-array
     CheckEqual(T.Intersect(T.NumberArray, T.Object), T.NumberArray);
-    CheckEqual(T.Intersect(T.AnyArray, T.Function), T.None);
+    CheckEqual(T.Intersect(T.AnyArray, T.Proxy), T.None);
 
     // Bitset-function
     CheckEqual(T.Intersect(T.MethodFunction, T.Object), T.MethodFunction);
-    CheckEqual(T.Intersect(T.NumberFunction1, T.Array), T.None);
+    CheckEqual(T.Intersect(T.NumberFunction1, T.Proxy), T.None);
 
     // Bitset-union
     CheckEqual(
@@ -1880,7 +1796,11 @@
 
   void Distributivity() {
     // Union(T1, Intersect(T2, T3)) = Intersect(Union(T1, T2), Union(T1, T3))
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Untagged \/ (Untagged /\ Class(../Tagged)) = Untagged \/ Class(../Tagged)
+    // (Untagged \/ Untagged) /\ (Untagged \/ Class(../Tagged)) =
+    // Untagged /\ (Untagged \/ Class(../Tagged)) = Untagged
+    // because Untagged <= Untagged \/ Class(../Tagged)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1900,7 +1820,10 @@
     */
 
     // Intersect(T1, Union(T2, T3)) = Union(Intersect(T1, T2), Intersect(T1,T3))
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Untagged /\ (Untagged \/ Class(../Tagged)) = Untagged
+    // (Untagged /\ Untagged) \/ (Untagged /\ Class(../Tagged)) =
+    // Untagged \/ Class(../Tagged)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1920,6 +1843,32 @@
     */
   }
 
+  void GetRange() {
+    // GetRange(Range(a, b)) = Range(a, b).
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      TypeHandle type1 = *it1;
+      if (type1->IsRange()) {
+        typename Type::RangeType* range = type1->GetRange();
+        CHECK(type1->Min() == range->Min()->Number());
+        CHECK(type1->Max() == range->Max()->Number());
+      }
+    }
+
+    // GetRange(Union(Constant(x), Range(min,max))) == Range(min, max).
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+        TypeHandle type1 = *it1;
+        TypeHandle type2 = *it2;
+        if (type1->IsConstant() && type2->IsRange()) {
+          TypeHandle u = T.Union(type1, type2);
+
+          CHECK(type2->Min() == u->GetRange()->Min()->Number());
+          CHECK(type2->Max() == u->GetRange()->Max()->Number());
+        }
+      }
+    }
+  }
+
   template<class Type2, class TypeHandle2, class Region2, class Rep2>
   void Convert() {
     Types<Type2, TypeHandle2, Region2> T2(
@@ -2012,6 +1961,13 @@
 }
 
 
+TEST(MinMax) {
+  CcTest::InitializeVM();
+  ZoneTests().MinMax();
+  HeapTests().MinMax();
+}
+
+
 TEST(BitsetGlb) {
   CcTest::InitializeVM();
   ZoneTests().BitsetGlb();
@@ -2026,10 +1982,17 @@
 }
 
 
-TEST(Is) {
+TEST(Is1) {
   CcTest::InitializeVM();
-  ZoneTests().Is();
-  HeapTests().Is();
+  ZoneTests().Is1();
+  HeapTests().Is1();
+}
+
+
+TEST(Is2) {
+  CcTest::InitializeVM();
+  ZoneTests().Is2();
+  HeapTests().Is2();
 }
 
 
@@ -2098,13 +2061,18 @@
 }
 
 
-/*
 TEST(Distributivity) {
   CcTest::InitializeVM();
   ZoneTests().Distributivity();
   HeapTests().Distributivity();
 }
-*/
+
+
+TEST(GetRange) {
+  CcTest::InitializeVM();
+  ZoneTests().GetRange();
+  HeapTests().GetRange();
+}
 
 
 TEST(Convert) {
diff --git a/test/cctest/test-unboxed-doubles.cc b/test/cctest/test-unboxed-doubles.cc
new file mode 100644
index 0000000..a12bf47
--- /dev/null
+++ b/test/cctest/test-unboxed-doubles.cc
@@ -0,0 +1,1162 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdlib.h>
+#include <utility>
+
+#include "src/v8.h"
+
+#include "src/compilation-cache.h"
+#include "src/execution.h"
+#include "src/factory.h"
+#include "src/global-handles.h"
+#include "src/ic/ic.h"
+#include "src/macro-assembler.h"
+#include "test/cctest/cctest.h"
+
+using namespace v8::base;
+using namespace v8::internal;
+
+#if (V8_DOUBLE_FIELDS_UNBOXING)
+
+
+static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) {
+  if (obj->IsUnboxedDoubleField(field_index)) {
+    return obj->RawFastDoublePropertyAt(field_index);
+  } else {
+    Object* value = obj->RawFastPropertyAt(field_index);
+    DCHECK(value->IsMutableHeapNumber());
+    return HeapNumber::cast(value)->value();
+  }
+}
+
+const int kNumberOfBits = 32;
+
+
+enum TestPropertyKind {
+  PROP_CONSTANT,
+  PROP_SMI,
+  PROP_DOUBLE,
+  PROP_TAGGED,
+  PROP_KIND_NUMBER
+};
+
+static Representation representations[PROP_KIND_NUMBER] = {
+    Representation::None(), Representation::Smi(), Representation::Double(),
+    Representation::Tagged()};
+
+
+static Handle<DescriptorArray> CreateDescriptorArray(Isolate* isolate,
+                                                     TestPropertyKind* props,
+                                                     int kPropsCount) {
+  Factory* factory = isolate->factory();
+
+  Handle<String> func_name = factory->InternalizeUtf8String("func");
+  Handle<JSFunction> func = factory->NewFunction(func_name);
+
+  Handle<DescriptorArray> descriptors =
+      DescriptorArray::Allocate(isolate, 0, kPropsCount);
+
+  int next_field_offset = 0;
+  for (int i = 0; i < kPropsCount; i++) {
+    EmbeddedVector<char, 64> buffer;
+    SNPrintF(buffer, "prop%d", i);
+    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
+
+    TestPropertyKind kind = props[i];
+
+    if (kind == PROP_CONSTANT) {
+      ConstantDescriptor d(name, func, NONE);
+      descriptors->Append(&d);
+
+    } else {
+      FieldDescriptor f(name, next_field_offset, NONE, representations[kind]);
+      next_field_offset += f.GetDetails().field_width_in_words();
+      descriptors->Append(&f);
+    }
+  }
+  return descriptors;
+}
+
+
+TEST(LayoutDescriptorBasicFast) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
+
+  CHECK(!layout_desc->IsSlowLayout());
+  CHECK(layout_desc->IsFastPointerLayout());
+  CHECK_EQ(kSmiValueSize, layout_desc->capacity());
+
+  for (int i = 0; i < kSmiValueSize + 13; i++) {
+    CHECK_EQ(true, layout_desc->IsTagged(i));
+  }
+  CHECK_EQ(true, layout_desc->IsTagged(-1));
+  CHECK_EQ(true, layout_desc->IsTagged(-12347));
+  CHECK_EQ(true, layout_desc->IsTagged(15635));
+  CHECK(layout_desc->IsFastPointerLayout());
+
+  for (int i = 0; i < kSmiValueSize; i++) {
+    layout_desc = layout_desc->SetTaggedForTesting(i, false);
+    CHECK_EQ(false, layout_desc->IsTagged(i));
+    layout_desc = layout_desc->SetTaggedForTesting(i, true);
+    CHECK_EQ(true, layout_desc->IsTagged(i));
+  }
+  CHECK(layout_desc->IsFastPointerLayout());
+
+  int sequence_length;
+  CHECK_EQ(true, layout_desc->IsTagged(0, std::numeric_limits<int>::max(),
+                                       &sequence_length));
+  CHECK_EQ(std::numeric_limits<int>::max(), sequence_length);
+
+  CHECK_EQ(true, layout_desc->IsTagged(0, 7, &sequence_length));
+  CHECK_EQ(7, sequence_length);
+}
+
+
+TEST(LayoutDescriptorBasicSlow) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    // All properties tagged.
+    props[i] = PROP_TAGGED;
+  }
+
+  {
+    Handle<DescriptorArray> descriptors =
+        CreateDescriptorArray(isolate, props, kPropsCount);
+
+    Handle<Map> map = Map::Create(isolate, kPropsCount);
+
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK_EQ(kSmiValueSize, layout_descriptor->capacity());
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  props[0] = PROP_DOUBLE;
+  props[kPropsCount - 1] = PROP_DOUBLE;
+
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  {
+    int inobject_properties = kPropsCount - 1;
+    Handle<Map> map = Map::Create(isolate, inobject_properties);
+
+    // Should be fast as the only double property is the first one.
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(!layout_descriptor->IsSlowLayout());
+    CHECK(!layout_descriptor->IsFastPointerLayout());
+
+    CHECK_EQ(false, layout_descriptor->IsTagged(0));
+    for (int i = 1; i < kPropsCount; i++) {
+      CHECK_EQ(true, layout_descriptor->IsTagged(i));
+    }
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    int inobject_properties = kPropsCount;
+    Handle<Map> map = Map::Create(isolate, inobject_properties);
+
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(layout_descriptor->IsSlowLayout());
+    CHECK(!layout_descriptor->IsFastPointerLayout());
+    CHECK(layout_descriptor->capacity() > kSmiValueSize);
+
+    CHECK_EQ(false, layout_descriptor->IsTagged(0));
+    CHECK_EQ(false, layout_descriptor->IsTagged(kPropsCount - 1));
+    for (int i = 1; i < kPropsCount - 1; i++) {
+      CHECK_EQ(true, layout_descriptor->IsTagged(i));
+    }
+
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+
+    // Here we have truly slow layout descriptor, so play with the bits.
+    CHECK_EQ(true, layout_descriptor->IsTagged(-1));
+    CHECK_EQ(true, layout_descriptor->IsTagged(-12347));
+    CHECK_EQ(true, layout_descriptor->IsTagged(15635));
+
+    LayoutDescriptor* layout_desc = *layout_descriptor;
+    // Play with the bits but leave it in consistent state with map at the end.
+    for (int i = 1; i < kPropsCount - 1; i++) {
+      layout_desc = layout_desc->SetTaggedForTesting(i, false);
+      CHECK_EQ(false, layout_desc->IsTagged(i));
+      layout_desc = layout_desc->SetTaggedForTesting(i, true);
+      CHECK_EQ(true, layout_desc->IsTagged(i));
+    }
+    CHECK(layout_desc->IsSlowLayout());
+    CHECK(!layout_desc->IsFastPointerLayout());
+
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+}
+
+
+static void TestLayoutDescriptorQueries(int layout_descriptor_length,
+                                        int* bit_flip_positions,
+                                        int max_sequence_length) {
+  Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::NewForTesting(
+      CcTest::i_isolate(), layout_descriptor_length);
+  layout_descriptor_length = layout_descriptor->capacity();
+  LayoutDescriptor* layout_desc = *layout_descriptor;
+
+  {
+    // Fill in the layout descriptor.
+    int cur_bit_flip_index = 0;
+    bool tagged = true;
+    for (int i = 0; i < layout_descriptor_length; i++) {
+      if (i == bit_flip_positions[cur_bit_flip_index]) {
+        tagged = !tagged;
+        ++cur_bit_flip_index;
+        CHECK(i < bit_flip_positions[cur_bit_flip_index]);  // check test data
+      }
+      layout_desc = layout_desc->SetTaggedForTesting(i, tagged);
+    }
+  }
+
+  if (layout_desc->IsFastPointerLayout()) {
+    return;
+  }
+
+  {
+    // Check queries.
+    int cur_bit_flip_index = 0;
+    bool tagged = true;
+    for (int i = 0; i < layout_descriptor_length; i++) {
+      if (i == bit_flip_positions[cur_bit_flip_index]) {
+        tagged = !tagged;
+        ++cur_bit_flip_index;
+      }
+      CHECK_EQ(tagged, layout_desc->IsTagged(i));
+
+      int next_bit_flip_position = bit_flip_positions[cur_bit_flip_index];
+      int expected_sequence_length;
+      if (next_bit_flip_position < layout_desc->capacity()) {
+        expected_sequence_length = next_bit_flip_position - i;
+      } else {
+        expected_sequence_length = tagged ? std::numeric_limits<int>::max()
+                                          : (layout_desc->capacity() - i);
+      }
+      expected_sequence_length =
+          Min(expected_sequence_length, max_sequence_length);
+      int sequence_length;
+      CHECK_EQ(tagged,
+               layout_desc->IsTagged(i, max_sequence_length, &sequence_length));
+      CHECK(sequence_length > 0);
+
+      CHECK_EQ(expected_sequence_length, sequence_length);
+    }
+
+    int sequence_length;
+    CHECK_EQ(true,
+             layout_desc->IsTagged(layout_descriptor_length,
+                                   max_sequence_length, &sequence_length));
+    CHECK_EQ(max_sequence_length, sequence_length);
+  }
+}
+
+
+static void TestLayoutDescriptorQueriesFast(int max_sequence_length) {
+  {
+    LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
+    int sequence_length;
+    for (int i = 0; i < kNumberOfBits; i++) {
+      CHECK_EQ(true,
+               layout_desc->IsTagged(i, max_sequence_length, &sequence_length));
+      CHECK(sequence_length > 0);
+      CHECK_EQ(max_sequence_length, sequence_length);
+    }
+  }
+
+  {
+    int bit_flip_positions[] = {1000};
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {0, 1000};
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[kNumberOfBits + 1];
+    for (int i = 0; i <= kNumberOfBits; i++) {
+      bit_flip_positions[i] = i;
+    }
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {3, 7, 8, 10, 15, 21, 30, 1000};
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {0,  1,  2,  3,  5,  7,  9,
+                                12, 15, 18, 22, 26, 29, 1000};
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+}
+
+
+TEST(LayoutDescriptorQueriesFastLimited7) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesFast(7);
+}
+
+
+TEST(LayoutDescriptorQueriesFastLimited13) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesFast(13);
+}
+
+
+TEST(LayoutDescriptorQueriesFastUnlimited) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesFast(std::numeric_limits<int>::max());
+}
+
+
+static void TestLayoutDescriptorQueriesSlow(int max_sequence_length) {
+  {
+    int bit_flip_positions[] = {10000};
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {0, 10000};
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[kMaxNumberOfDescriptors + 1];
+    for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
+      bit_flip_positions[i] = i;
+    }
+    bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {3,  7,  8,  10, 15,  21,   30,
+                                37, 54, 80, 99, 383, 10000};
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {0,   10,  20,  30,  50,  70,  90,
+                                120, 150, 180, 220, 260, 290, 10000};
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[kMaxNumberOfDescriptors + 1];
+    int cur = 0;
+    for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
+      bit_flip_positions[i] = cur;
+      cur = (cur + 1) * 2;
+    }
+    CHECK(cur < 10000);
+    bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[kMaxNumberOfDescriptors + 1];
+    int cur = 3;
+    for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
+      bit_flip_positions[i] = cur;
+      cur = (cur + 1) * 2;
+    }
+    CHECK(cur < 10000);
+    bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+}
+
+
+TEST(LayoutDescriptorQueriesSlowLimited7) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesSlow(7);
+}
+
+
+TEST(LayoutDescriptorQueriesSlowLimited13) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesSlow(13);
+}
+
+
+TEST(LayoutDescriptorQueriesSlowLimited42) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesSlow(42);
+}
+
+
+TEST(LayoutDescriptorQueriesSlowUnlimited) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesSlow(std::numeric_limits<int>::max());
+}
+
+
+TEST(LayoutDescriptorCreateNewFast) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  TestPropertyKind props[] = {
+      PROP_CONSTANT,
+      PROP_TAGGED,  // field #0
+      PROP_CONSTANT,
+      PROP_DOUBLE,  // field #1
+      PROP_CONSTANT,
+      PROP_TAGGED,  // field #2
+      PROP_CONSTANT,
+  };
+  const int kPropsCount = arraysize(props);
+
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  {
+    Handle<Map> map = Map::Create(isolate, 0);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    Handle<Map> map = Map::Create(isolate, 1);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    Handle<Map> map = Map::Create(isolate, 2);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(!layout_descriptor->IsSlowLayout());
+    CHECK_EQ(true, layout_descriptor->IsTagged(0));
+    CHECK_EQ(false, layout_descriptor->IsTagged(1));
+    CHECK_EQ(true, layout_descriptor->IsTagged(2));
+    CHECK_EQ(true, layout_descriptor->IsTagged(125));
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+}
+
+
+TEST(LayoutDescriptorCreateNewSlow) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
+  }
+
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  {
+    Handle<Map> map = Map::Create(isolate, 0);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    Handle<Map> map = Map::Create(isolate, 1);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    Handle<Map> map = Map::Create(isolate, 2);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(!layout_descriptor->IsSlowLayout());
+    CHECK_EQ(true, layout_descriptor->IsTagged(0));
+    CHECK_EQ(false, layout_descriptor->IsTagged(1));
+    CHECK_EQ(true, layout_descriptor->IsTagged(2));
+    CHECK_EQ(true, layout_descriptor->IsTagged(125));
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    int inobject_properties = kPropsCount / 2;
+    Handle<Map> map = Map::Create(isolate, inobject_properties);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(layout_descriptor->IsSlowLayout());
+    for (int i = 0; i < inobject_properties; i++) {
+      // PROP_DOUBLE has index 1 among FIELD properties.
+      const bool tagged = (i % (PROP_KIND_NUMBER - 1)) != 1;
+      CHECK_EQ(tagged, layout_descriptor->IsTagged(i));
+    }
+    // Every property after inobject_properties must be tagged.
+    for (int i = inobject_properties; i < kPropsCount; i++) {
+      CHECK_EQ(true, layout_descriptor->IsTagged(i));
+    }
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+
+    // Now test LayoutDescriptor::cast_gc_safe().
+    Handle<LayoutDescriptor> layout_descriptor_copy =
+        LayoutDescriptor::New(map, descriptors, kPropsCount);
+
+    LayoutDescriptor* layout_desc = *layout_descriptor;
+    CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
+    CHECK_EQ(layout_desc, LayoutDescriptor::cast_gc_safe(layout_desc));
+    CHECK(layout_descriptor->IsFixedTypedArrayBase());
+    // Now make it look like a forwarding pointer to layout_descriptor_copy.
+    MapWord map_word = layout_desc->map_word();
+    CHECK(!map_word.IsForwardingAddress());
+    layout_desc->set_map_word(
+        MapWord::FromForwardingAddress(*layout_descriptor_copy));
+    CHECK(layout_desc->map_word().IsForwardingAddress());
+    CHECK_EQ(*layout_descriptor_copy,
+             LayoutDescriptor::cast_gc_safe(layout_desc));
+
+    // Restore it back.
+    layout_desc->set_map_word(map_word);
+    CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
+  }
+}
+
+
+static Handle<LayoutDescriptor> TestLayoutDescriptorAppend(
+    Isolate* isolate, int inobject_properties, TestPropertyKind* props,
+    int kPropsCount) {
+  Factory* factory = isolate->factory();
+
+  Handle<String> func_name = factory->InternalizeUtf8String("func");
+  Handle<JSFunction> func = factory->NewFunction(func_name);
+
+  Handle<DescriptorArray> descriptors =
+      DescriptorArray::Allocate(isolate, 0, kPropsCount);
+
+  Handle<Map> map = Map::Create(isolate, inobject_properties);
+  map->InitializeDescriptors(*descriptors,
+                             LayoutDescriptor::FastPointerLayout());
+
+  int next_field_offset = 0;
+  for (int i = 0; i < kPropsCount; i++) {
+    EmbeddedVector<char, 64> buffer;
+    SNPrintF(buffer, "prop%d", i);
+    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
+
+    Handle<LayoutDescriptor> layout_descriptor;
+    TestPropertyKind kind = props[i];
+    if (kind == PROP_CONSTANT) {
+      ConstantDescriptor d(name, func, NONE);
+      layout_descriptor = LayoutDescriptor::Append(map, d.GetDetails());
+      descriptors->Append(&d);
+
+    } else {
+      FieldDescriptor f(name, next_field_offset, NONE, representations[kind]);
+      int field_width_in_words = f.GetDetails().field_width_in_words();
+      next_field_offset += field_width_in_words;
+      layout_descriptor = LayoutDescriptor::Append(map, f.GetDetails());
+      descriptors->Append(&f);
+
+      int field_index = f.GetDetails().field_index();
+      bool is_inobject = field_index < map->inobject_properties();
+      for (int bit = 0; bit < field_width_in_words; bit++) {
+        CHECK_EQ(is_inobject && (kind == PROP_DOUBLE),
+                 !layout_descriptor->IsTagged(field_index + bit));
+      }
+      CHECK(layout_descriptor->IsTagged(next_field_offset));
+    }
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+  }
+  Handle<LayoutDescriptor> layout_descriptor(map->layout_descriptor(), isolate);
+  DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  return layout_descriptor;
+}
+
+
+TEST(LayoutDescriptorAppend) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
+  }
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
+                                                 props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+}
+
+
+TEST(LayoutDescriptorAppendAllDoubles) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_DOUBLE;
+  }
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize + 1,
+                                                 props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
+                                                 props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  {
+    // Ensure layout descriptor switches into slow mode at the right moment.
+    layout_descriptor =
+        TestLayoutDescriptorAppend(isolate, kPropsCount, props, kSmiValueSize);
+    CHECK(!layout_descriptor->IsSlowLayout());
+
+    layout_descriptor = TestLayoutDescriptorAppend(isolate, kPropsCount, props,
+                                                   kSmiValueSize + 1);
+    CHECK(layout_descriptor->IsSlowLayout());
+  }
+}
+
+
+static Handle<LayoutDescriptor> TestLayoutDescriptorAppendIfFastOrUseFull(
+    Isolate* isolate, int inobject_properties,
+    Handle<DescriptorArray> descriptors, int number_of_descriptors) {
+  Handle<Map> map = Map::Create(isolate, inobject_properties);
+
+  Handle<LayoutDescriptor> full_layout_descriptor = LayoutDescriptor::New(
+      map, descriptors, descriptors->number_of_descriptors());
+
+  int nof = 0;
+  bool switched_to_slow_mode = false;
+
+  for (int i = 0; i < number_of_descriptors; i++) {
+    PropertyDetails details = descriptors->GetDetails(i);
+
+    // This method calls LayoutDescriptor::AppendIfFastOrUseFull() internally
+    // and does all the required map-descriptors related book keeping.
+    map = Map::CopyInstallDescriptorsForTesting(map, i, descriptors,
+                                                full_layout_descriptor);
+
+    LayoutDescriptor* layout_desc = map->layout_descriptor();
+
+    if (layout_desc->IsSlowLayout()) {
+      switched_to_slow_mode = true;
+      CHECK_EQ(*full_layout_descriptor, layout_desc);
+    } else {
+      CHECK(!switched_to_slow_mode);
+      if (details.type() == FIELD) {
+        nof++;
+        int field_index = details.field_index();
+        int field_width_in_words = details.field_width_in_words();
+
+        bool is_inobject = field_index < map->inobject_properties();
+        for (int bit = 0; bit < field_width_in_words; bit++) {
+          CHECK_EQ(is_inobject && details.representation().IsDouble(),
+                   !layout_desc->IsTagged(field_index + bit));
+        }
+        CHECK(layout_desc->IsTagged(field_index + field_width_in_words));
+      }
+    }
+    DCHECK(map->layout_descriptor()->IsConsistentWithMap(*map));
+  }
+
+  Handle<LayoutDescriptor> layout_descriptor(map->GetLayoutDescriptor(),
+                                             isolate);
+  DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  return layout_descriptor;
+}
+
+
+TEST(LayoutDescriptorAppendIfFastOrUseFull) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, 0, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, 13, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize * 2, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kPropsCount, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+}
+
+
+TEST(LayoutDescriptorAppendIfFastOrUseFullAllDoubles) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_DOUBLE;
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, 0, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, 13, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize + 1, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize * 2, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kPropsCount, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  {
+    // Ensure layout descriptor switches into slow mode at the right moment.
+    layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+        isolate, kPropsCount, descriptors, kSmiValueSize);
+    CHECK(!layout_descriptor->IsSlowLayout());
+
+    layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+        isolate, kPropsCount, descriptors, kSmiValueSize + 1);
+    CHECK(layout_descriptor->IsSlowLayout());
+  }
+}
+
+
+TEST(Regress436816) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  v8::HandleScope scope(CcTest::isolate());
+
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_DOUBLE;
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  Handle<Map> map = Map::Create(isolate, kPropsCount);
+  Handle<LayoutDescriptor> layout_descriptor =
+      LayoutDescriptor::New(map, descriptors, kPropsCount);
+  map->InitializeDescriptors(*descriptors, *layout_descriptor);
+
+  Handle<JSObject> object = factory->NewJSObjectFromMap(map, TENURED);
+
+  Address fake_address = reinterpret_cast<Address>(~kHeapObjectTagMask);
+  HeapObject* fake_object = HeapObject::FromAddress(fake_address);
+  CHECK(fake_object->IsHeapObject());
+
+  double boom_value = bit_cast<double>(fake_object);
+  for (int i = 0; i < kPropsCount; i++) {
+    FieldIndex index = FieldIndex::ForDescriptor(*map, i);
+    CHECK(map->IsUnboxedDoubleField(index));
+    object->RawFastDoublePropertyAtPut(index, boom_value);
+  }
+  CHECK(object->HasFastProperties());
+  CHECK(!object->map()->HasFastPointerLayout());
+
+  Handle<Map> normalized_map =
+      Map::Normalize(map, KEEP_INOBJECT_PROPERTIES, "testing");
+  JSObject::MigrateToMap(object, normalized_map);
+  CHECK(!object->HasFastProperties());
+  CHECK(object->map()->HasFastPointerLayout());
+
+  // Trigger GCs and heap verification.
+  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+}
+
+
+TEST(DoScavenge) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  v8::HandleScope scope(CcTest::isolate());
+
+  CompileRun(
+      "function A() {"
+      "  this.x = 42.5;"
+      "  this.o = {};"
+      "};"
+      "var o = new A();");
+
+  Handle<String> obj_name = factory->InternalizeUtf8String("o");
+
+  Handle<Object> obj_value =
+      Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked();
+  CHECK(obj_value->IsJSObject());
+  Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
+
+  {
+    // Ensure the object is properly set up.
+    Map* map = obj->map();
+    DescriptorArray* descriptors = map->instance_descriptors();
+    CHECK(map->NumberOfOwnDescriptors() == 2);
+    CHECK(descriptors->GetDetails(0).representation().IsDouble());
+    CHECK(descriptors->GetDetails(1).representation().IsHeapObject());
+    FieldIndex field_index = FieldIndex::ForDescriptor(map, 0);
+    CHECK(field_index.is_inobject() && field_index.is_double());
+    CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
+    CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
+  }
+  CHECK(isolate->heap()->new_space()->Contains(*obj));
+
+  // Trigger GCs so that the newly allocated object moves to old gen.
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
+
+  // Create temp object in the new space.
+  Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED);
+  CHECK(isolate->heap()->new_space()->Contains(*temp));
+
+  // Construct a double value that looks like a pointer to the new space object
+  // and store it into the obj.
+  Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize;
+  double boom_value = bit_cast<double>(fake_object);
+
+  FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0);
+  Handle<HeapNumber> boom_number = factory->NewHeapNumber(boom_value, MUTABLE);
+  obj->FastPropertyAtPut(field_index, *boom_number);
+
+  // Now the object moves to old gen and it has a double field that looks like
+  // a pointer to a from semi-space.
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
+
+  CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
+
+  CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
+}
+
+
+static void TestLayoutDescriptorHelper(Isolate* isolate,
+                                       int inobject_properties,
+                                       Handle<DescriptorArray> descriptors,
+                                       int number_of_descriptors) {
+  Handle<Map> map = Map::Create(isolate, inobject_properties);
+
+  Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
+      map, descriptors, descriptors->number_of_descriptors());
+  map->InitializeDescriptors(*descriptors, *layout_descriptor);
+  DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+
+  LayoutDescriptorHelper helper(*map);
+  bool all_fields_tagged = true;
+
+  int instance_size = map->instance_size();
+
+  int end_offset = instance_size * 2;
+  int first_non_tagged_field_offset = end_offset;
+  for (int i = 0; i < number_of_descriptors; i++) {
+    PropertyDetails details = descriptors->GetDetails(i);
+    if (details.type() != FIELD) continue;
+    FieldIndex index = FieldIndex::ForDescriptor(*map, i);
+    if (!index.is_inobject()) continue;
+    all_fields_tagged &= !details.representation().IsDouble();
+    bool expected_tagged = !index.is_double();
+    if (!expected_tagged) {
+      first_non_tagged_field_offset =
+          Min(first_non_tagged_field_offset, index.offset());
+    }
+
+    int end_of_region_offset;
+    CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
+    CHECK_EQ(expected_tagged, helper.IsTagged(index.offset(), instance_size,
+                                              &end_of_region_offset));
+    CHECK(end_of_region_offset > 0);
+    CHECK(end_of_region_offset % kPointerSize == 0);
+    CHECK(end_of_region_offset <= instance_size);
+
+    for (int offset = index.offset(); offset < end_of_region_offset;
+         offset += kPointerSize) {
+      CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
+    }
+    if (end_of_region_offset < instance_size) {
+      CHECK_EQ(!expected_tagged, helper.IsTagged(end_of_region_offset));
+    } else {
+      CHECK_EQ(true, helper.IsTagged(end_of_region_offset));
+    }
+  }
+
+  for (int offset = 0; offset < JSObject::kHeaderSize; offset += kPointerSize) {
+    // Header queries
+    CHECK_EQ(true, helper.IsTagged(offset));
+    int end_of_region_offset;
+    CHECK_EQ(true, helper.IsTagged(offset, end_offset, &end_of_region_offset));
+    CHECK_EQ(first_non_tagged_field_offset, end_of_region_offset);
+
+    // Out of bounds queries
+    CHECK_EQ(true, helper.IsTagged(offset + instance_size));
+  }
+
+  CHECK_EQ(all_fields_tagged, helper.all_fields_tagged());
+}
+
+
+TEST(LayoutDescriptorHelperMixed) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
+                             kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
+}
+
+
+TEST(LayoutDescriptorHelperAllTagged) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_TAGGED;
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
+                             kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
+}
+
+
+TEST(LayoutDescriptorHelperAllDoubles) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_DOUBLE;
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
+                             kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
+}
+
+
+TEST(StoreBufferScanOnScavenge) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  v8::HandleScope scope(CcTest::isolate());
+
+  CompileRun(
+      "function A() {"
+      "  this.x = 42.5;"
+      "  this.o = {};"
+      "};"
+      "var o = new A();");
+
+  Handle<String> obj_name = factory->InternalizeUtf8String("o");
+
+  Handle<Object> obj_value =
+      Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked();
+  CHECK(obj_value->IsJSObject());
+  Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
+
+  {
+    // Ensure the object is properly set up.
+    Map* map = obj->map();
+    DescriptorArray* descriptors = map->instance_descriptors();
+    CHECK(map->NumberOfOwnDescriptors() == 2);
+    CHECK(descriptors->GetDetails(0).representation().IsDouble());
+    CHECK(descriptors->GetDetails(1).representation().IsHeapObject());
+    FieldIndex field_index = FieldIndex::ForDescriptor(map, 0);
+    CHECK(field_index.is_inobject() && field_index.is_double());
+    CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
+    CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
+  }
+  CHECK(isolate->heap()->new_space()->Contains(*obj));
+
+  // Trigger GCs so that the newly allocated object moves to old gen.
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
+
+  CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
+
+  // Create temp object in the new space.
+  Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED);
+  CHECK(isolate->heap()->new_space()->Contains(*temp));
+
+  // Construct a double value that looks like a pointer to the new space object
+  // and store it into the obj.
+  Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize;
+  double boom_value = bit_cast<double>(fake_object);
+
+  FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0);
+  Handle<HeapNumber> boom_number = factory->NewHeapNumber(boom_value, MUTABLE);
+  obj->FastPropertyAtPut(field_index, *boom_number);
+
+  // Enforce scan on scavenge for the obj's page.
+  MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
+  chunk->set_scan_on_scavenge(true);
+
+  // Trigger GCs and force evacuation. Should not crash there.
+  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+
+  CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
+}
+
+#endif
diff --git a/test/cctest/test-utils.cc b/test/cctest/test-utils.cc
index 9ea8b2b..05a12f5 100644
--- a/test/cctest/test-utils.cc
+++ b/test/cctest/test-utils.cc
@@ -76,6 +76,47 @@
 }
 
 
+TEST(BitSetComputer) {
+  typedef BitSetComputer<bool, 1, kSmiValueSize, uint32_t> BoolComputer;
+  CHECK_EQ(0, BoolComputer::word_count(0));
+  CHECK_EQ(1, BoolComputer::word_count(8));
+  CHECK_EQ(2, BoolComputer::word_count(50));
+  CHECK_EQ(0, BoolComputer::index(0, 8));
+  CHECK_EQ(100, BoolComputer::index(100, 8));
+  CHECK_EQ(1, BoolComputer::index(0, 40));
+  uint32_t data = 0;
+  data = BoolComputer::encode(data, 1, true);
+  data = BoolComputer::encode(data, 4, true);
+  CHECK_EQ(true, BoolComputer::decode(data, 1));
+  CHECK_EQ(true, BoolComputer::decode(data, 4));
+  CHECK_EQ(false, BoolComputer::decode(data, 0));
+  CHECK_EQ(false, BoolComputer::decode(data, 2));
+  CHECK_EQ(false, BoolComputer::decode(data, 3));
+
+  // Lets store 2 bits per item with 3000 items and verify the values are
+  // correct.
+  typedef BitSetComputer<unsigned char, 2, 8, unsigned char> TwoBits;
+  const int words = 750;
+  CHECK_EQ(words, TwoBits::word_count(3000));
+  const int offset = 10;
+  Vector<unsigned char> buffer = Vector<unsigned char>::New(offset + words);
+  memset(buffer.start(), 0, sizeof(unsigned char) * buffer.length());
+  for (int i = 0; i < words; i++) {
+    const int index = TwoBits::index(offset, i);
+    unsigned char data = buffer[index];
+    data = TwoBits::encode(data, i, i % 4);
+    buffer[index] = data;
+  }
+
+  for (int i = 0; i < words; i++) {
+    const int index = TwoBits::index(offset, i);
+    unsigned char data = buffer[index];
+    CHECK_EQ(i % 4, TwoBits::decode(data, i));
+  }
+  buffer.Dispose();
+}
+
+
 TEST(SNPrintF) {
   // Make sure that strings that are truncated because of too small
   // buffers are zero-terminated anyway.
@@ -222,8 +263,6 @@
 }
 
 
-// TODO(svenpanne) Unconditionally test this when our infrastructure is fixed.
-#if !V8_OS_NACL
 TEST(CPlusPlus11Features) {
   struct S {
     bool x;
@@ -256,4 +295,3 @@
     j += 11;
   }
 }
-#endif
diff --git a/test/cctest/test-weakmaps.cc b/test/cctest/test-weakmaps.cc
index bb412a8..6c19cb8 100644
--- a/test/cctest/test-weakmaps.cc
+++ b/test/cctest/test-weakmaps.cc
@@ -97,19 +97,20 @@
   }
   CHECK(!global_handles->IsWeak(key.location()));
 
-  // Put entry into weak map.
+  // Put two chained entries into weak map.
   {
     HandleScope scope(isolate);
-    PutIntoWeakMap(weakmap,
-                   Handle<JSObject>(JSObject::cast(*key)),
-                   Handle<Smi>(Smi::FromInt(23), isolate));
+    Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+    Handle<JSObject> object = factory->NewJSObjectFromMap(map);
+    PutIntoWeakMap(weakmap, Handle<JSObject>(JSObject::cast(*key)), object);
+    PutIntoWeakMap(weakmap, object, Handle<Smi>(Smi::FromInt(23), isolate));
   }
-  CHECK_EQ(1, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
+  CHECK_EQ(2, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
 
   // Force a full GC.
   heap->CollectAllGarbage(false);
   CHECK_EQ(0, NumberOfWeakCalls);
-  CHECK_EQ(1, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
+  CHECK_EQ(2, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
   CHECK_EQ(
       0, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
 
@@ -128,14 +129,14 @@
   // weak references whereas the second one will also clear weak maps.
   heap->CollectAllGarbage(false);
   CHECK_EQ(1, NumberOfWeakCalls);
-  CHECK_EQ(1, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
+  CHECK_EQ(2, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
   CHECK_EQ(
       0, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
   heap->CollectAllGarbage(false);
   CHECK_EQ(1, NumberOfWeakCalls);
   CHECK_EQ(0, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
-  CHECK_EQ(
-      1, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
+  CHECK_EQ(2,
+           ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
 }
 
 
diff --git a/test/cctest/trace-extension.cc b/test/cctest/trace-extension.cc
index 8f390e4..0a1ff87 100644
--- a/test/cctest/trace-extension.cc
+++ b/test/cctest/trace-extension.cc
@@ -91,7 +91,8 @@
   // sp is only used to define stack high bound
   regs.sp =
       reinterpret_cast<Address>(trace_env.sample) - 10240;
-  trace_env.sample->Init(CcTest::i_isolate(), regs);
+  trace_env.sample->Init(CcTest::i_isolate(), regs,
+                         TickSample::kSkipCEntryFrame);
 }
 
 
diff --git a/test/cctest/types-fuzz.h b/test/cctest/types-fuzz.h
new file mode 100644
index 0000000..4eac64c
--- /dev/null
+++ b/test/cctest/types-fuzz.h
@@ -0,0 +1,311 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_TEST_CCTEST_TYPES_H_
+#define V8_TEST_CCTEST_TYPES_H_
+
+#include "src/v8.h"
+
+namespace v8 {
+namespace internal {
+
+
+template<class Type, class TypeHandle, class Region>
+class Types {
+ public:
+  Types(Region* region, Isolate* isolate)
+      : region_(region), rng_(isolate->random_number_generator()) {
+    #define DECLARE_TYPE(name, value) \
+      name = Type::name(region);      \
+      types.push_back(name);
+    PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
+    #undef DECLARE_TYPE
+
+    object_map = isolate->factory()->NewMap(
+        JS_OBJECT_TYPE, JSObject::kHeaderSize);
+    array_map = isolate->factory()->NewMap(
+        JS_ARRAY_TYPE, JSArray::kSize);
+    number_map = isolate->factory()->NewMap(
+        HEAP_NUMBER_TYPE, HeapNumber::kSize);
+    uninitialized_map = isolate->factory()->uninitialized_map();
+    ObjectClass = Type::Class(object_map, region);
+    ArrayClass = Type::Class(array_map, region);
+    NumberClass = Type::Class(number_map, region);
+    UninitializedClass = Type::Class(uninitialized_map, region);
+
+    maps.push_back(object_map);
+    maps.push_back(array_map);
+    maps.push_back(uninitialized_map);
+    for (MapVector::iterator it = maps.begin(); it != maps.end(); ++it) {
+      types.push_back(Type::Class(*it, region));
+    }
+
+    smi = handle(Smi::FromInt(666), isolate);
+    signed32 = isolate->factory()->NewHeapNumber(0x40000000);
+    object1 = isolate->factory()->NewJSObjectFromMap(object_map);
+    object2 = isolate->factory()->NewJSObjectFromMap(object_map);
+    array = isolate->factory()->NewJSArray(20);
+    uninitialized = isolate->factory()->uninitialized_value();
+    SmiConstant = Type::Constant(smi, region);
+    Signed32Constant = Type::Constant(signed32, region);
+    ObjectConstant1 = Type::Constant(object1, region);
+    ObjectConstant2 = Type::Constant(object2, region);
+    ArrayConstant = Type::Constant(array, region);
+    UninitializedConstant = Type::Constant(uninitialized, region);
+
+    values.push_back(smi);
+    values.push_back(signed32);
+    values.push_back(object1);
+    values.push_back(object2);
+    values.push_back(array);
+    values.push_back(uninitialized);
+    for (ValueVector::iterator it = values.begin(); it != values.end(); ++it) {
+      types.push_back(Type::Constant(*it, region));
+    }
+
+    integers.push_back(isolate->factory()->NewNumber(-V8_INFINITY));
+    integers.push_back(isolate->factory()->NewNumber(+V8_INFINITY));
+    integers.push_back(isolate->factory()->NewNumber(-rng_->NextInt(10)));
+    integers.push_back(isolate->factory()->NewNumber(+rng_->NextInt(10)));
+    for (int i = 0; i < 10; ++i) {
+      double x = rng_->NextInt();
+      integers.push_back(isolate->factory()->NewNumber(x));
+      x *= rng_->NextInt();
+      if (!IsMinusZero(x)) integers.push_back(isolate->factory()->NewNumber(x));
+    }
+
+    Integer = Type::Range(isolate->factory()->NewNumber(-V8_INFINITY),
+                          isolate->factory()->NewNumber(+V8_INFINITY), region);
+
+    NumberArray = Type::Array(Number, region);
+    StringArray = Type::Array(String, region);
+    AnyArray = Type::Array(Any, region);
+
+    SignedFunction1 = Type::Function(SignedSmall, SignedSmall, region);
+    NumberFunction1 = Type::Function(Number, Number, region);
+    NumberFunction2 = Type::Function(Number, Number, Number, region);
+    MethodFunction = Type::Function(String, Object, 0, region);
+
+    for (int i = 0; i < 30; ++i) {
+      types.push_back(Fuzz());
+    }
+  }
+
+  Handle<i::Map> object_map;
+  Handle<i::Map> array_map;
+  Handle<i::Map> number_map;
+  Handle<i::Map> uninitialized_map;
+
+  Handle<i::Smi> smi;
+  Handle<i::HeapNumber> signed32;
+  Handle<i::JSObject> object1;
+  Handle<i::JSObject> object2;
+  Handle<i::JSArray> array;
+  Handle<i::Oddball> uninitialized;
+
+  #define DECLARE_TYPE(name, value) TypeHandle name;
+  PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
+  #undef DECLARE_TYPE
+
+  TypeHandle ObjectClass;
+  TypeHandle ArrayClass;
+  TypeHandle NumberClass;
+  TypeHandle UninitializedClass;
+
+  TypeHandle SmiConstant;
+  TypeHandle Signed32Constant;
+  TypeHandle ObjectConstant1;
+  TypeHandle ObjectConstant2;
+  TypeHandle ArrayConstant;
+  TypeHandle UninitializedConstant;
+
+  TypeHandle Integer;
+
+  TypeHandle NumberArray;
+  TypeHandle StringArray;
+  TypeHandle AnyArray;
+
+  TypeHandle SignedFunction1;
+  TypeHandle NumberFunction1;
+  TypeHandle NumberFunction2;
+  TypeHandle MethodFunction;
+
+  typedef std::vector<TypeHandle> TypeVector;
+  typedef std::vector<Handle<i::Map> > MapVector;
+  typedef std::vector<Handle<i::Object> > ValueVector;
+
+  TypeVector types;
+  MapVector maps;
+  ValueVector values;
+  ValueVector integers;  // "Integer" values used for range limits.
+
+  TypeHandle Of(Handle<i::Object> value) {
+    return Type::Of(value, region_);
+  }
+
+  TypeHandle NowOf(Handle<i::Object> value) {
+    return Type::NowOf(value, region_);
+  }
+
+  TypeHandle Class(Handle<i::Map> map) {
+    return Type::Class(map, region_);
+  }
+
+  TypeHandle Constant(Handle<i::Object> value) {
+    return Type::Constant(value, region_);
+  }
+
+  TypeHandle Range(Handle<i::Object> min, Handle<i::Object> max) {
+    return Type::Range(min, max, region_);
+  }
+
+  TypeHandle Context(TypeHandle outer) {
+    return Type::Context(outer, region_);
+  }
+
+  TypeHandle Array1(TypeHandle element) {
+    return Type::Array(element, region_);
+  }
+
+  TypeHandle Function0(TypeHandle result, TypeHandle receiver) {
+    return Type::Function(result, receiver, 0, region_);
+  }
+
+  TypeHandle Function1(TypeHandle result, TypeHandle receiver, TypeHandle arg) {
+    TypeHandle type = Type::Function(result, receiver, 1, region_);
+    type->AsFunction()->InitParameter(0, arg);
+    return type;
+  }
+
+  TypeHandle Function2(TypeHandle result, TypeHandle arg1, TypeHandle arg2) {
+    return Type::Function(result, arg1, arg2, region_);
+  }
+
+  TypeHandle Union(TypeHandle t1, TypeHandle t2) {
+    return Type::Union(t1, t2, region_);
+  }
+  TypeHandle Intersect(TypeHandle t1, TypeHandle t2) {
+    return Type::Intersect(t1, t2, region_);
+  }
+
+  template<class Type2, class TypeHandle2>
+  TypeHandle Convert(TypeHandle2 t) {
+    return Type::template Convert<Type2>(t, region_);
+  }
+
+  TypeHandle Random() {
+    return types[rng_->NextInt(static_cast<int>(types.size()))];
+  }
+
+  TypeHandle Fuzz(int depth = 4) {
+    switch (rng_->NextInt(depth == 0 ? 3 : 20)) {
+      case 0: {  // bitset
+        #define COUNT_BITSET_TYPES(type, value) + 1
+        int n = 0 PROPER_BITSET_TYPE_LIST(COUNT_BITSET_TYPES);
+        #undef COUNT_BITSET_TYPES
+        // Pick a bunch of named bitsets and return their intersection.
+        TypeHandle result = Type::Any(region_);
+        for (int i = 0, m = 1 + rng_->NextInt(3); i < m; ++i) {
+          int j = rng_->NextInt(n);
+          #define PICK_BITSET_TYPE(type, value) \
+            if (j-- == 0) { \
+              TypeHandle tmp = Type::Intersect( \
+                  result, Type::type(region_), region_); \
+              if (tmp->Is(Type::None()) && i != 0) { \
+                break; \
+              } else { \
+                result = tmp; \
+                continue; \
+              } \
+            }
+          PROPER_BITSET_TYPE_LIST(PICK_BITSET_TYPE)
+          #undef PICK_BITSET_TYPE
+        }
+        return result;
+      }
+      case 1: {  // class
+        int i = rng_->NextInt(static_cast<int>(maps.size()));
+        return Type::Class(maps[i], region_);
+      }
+      case 2: {  // constant
+        int i = rng_->NextInt(static_cast<int>(values.size()));
+        return Type::Constant(values[i], region_);
+      }
+      case 3: {  // range
+        int i = rng_->NextInt(static_cast<int>(integers.size()));
+        int j = rng_->NextInt(static_cast<int>(integers.size()));
+        i::Handle<i::Object> min = integers[i];
+        i::Handle<i::Object> max = integers[j];
+        if (min->Number() > max->Number()) std::swap(min, max);
+        return Type::Range(min, max, region_);
+      }
+      case 4: {  // context
+        int depth = rng_->NextInt(3);
+        TypeHandle type = Type::Internal(region_);
+        for (int i = 0; i < depth; ++i) type = Type::Context(type, region_);
+        return type;
+      }
+      case 5: {  // array
+        TypeHandle element = Fuzz(depth / 2);
+        return Type::Array(element, region_);
+      }
+      case 6:
+      case 7: {  // function
+        TypeHandle result = Fuzz(depth / 2);
+        TypeHandle receiver = Fuzz(depth / 2);
+        int arity = rng_->NextInt(3);
+        TypeHandle type = Type::Function(result, receiver, arity, region_);
+        for (int i = 0; i < type->AsFunction()->Arity(); ++i) {
+          TypeHandle parameter = Fuzz(depth / 2);
+          type->AsFunction()->InitParameter(i, parameter);
+        }
+        return type;
+      }
+      default: {  // union
+        int n = rng_->NextInt(10);
+        TypeHandle type = None;
+        for (int i = 0; i < n; ++i) {
+          TypeHandle operand = Fuzz(depth - 1);
+          type = Type::Union(type, operand, region_);
+        }
+        return type;
+      }
+    }
+    UNREACHABLE();
+  }
+
+  Region* region() { return region_; }
+
+ private:
+  Region* region_;
+  v8::base::RandomNumberGenerator* rng_;
+};
+
+
+} }  // namespace v8::internal
+
+#endif
diff --git a/test/compiler-unittests/compiler-unittests.status b/test/compiler-unittests/compiler-unittests.status
deleted file mode 100644
index d439913..0000000
--- a/test/compiler-unittests/compiler-unittests.status
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2014 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-[
-]
diff --git a/test/fuzz-natives/base.js b/test/fuzz-natives/base.js
deleted file mode 100644
index d1f721d..0000000
--- a/test/fuzz-natives/base.js
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Flags: --allow-natives-syntax
-
-// TODO(jkummerow): There are many ways to improve these tests, e.g.:
-// - more variance in randomized inputs
-// - better time complexity management
-// - better code readability and documentation of intentions.
-
-var RUN_WITH_ALL_ARGUMENT_ENTRIES = false;
-var kOnManyArgumentsRemove = 5;
-
-function makeArguments() {
-  var result = [ ];
-  result.push(17);
-  result.push(-31);
-  result.push(new Array(100));
-  var a = %NormalizeElements([]);
-  a.length = 100003;
-  result.push(a);
-  result.push(Number.MIN_VALUE);
-  result.push("whoops");
-  result.push("x");
-  result.push({"x": 1, "y": 2});
-  var slowCaseObj = {"a": 3, "b": 4, "c": 5};
-  delete slowCaseObj.c;
-  result.push(slowCaseObj);
-  result.push(function () { return 8; });
-  return result;
-}
-
-var kArgObjects = makeArguments().length;
-
-function makeFunction(name, argc) {
-  var args = [];
-  for (var i = 0; i < argc; i++)
-    args.push("x" + i);
-  var argsStr = args.join(", ");
-  return new Function(argsStr,
-                      "return %" + name + "(" + argsStr + ");");
-}
-
-function testArgumentCount(name, argc) {
-  for (var i = 0; i < 10; i++) {
-    var func = null;
-    try {
-      func = makeFunction(name, i);
-    } catch (e) {
-      if (e != "SyntaxError: Illegal access") throw e;
-    }
-    if (func === null && i == argc) {
-      throw "unexpected exception";
-    }
-    var args = [ ];
-    for (var j = 0; j < i; j++)
-      args.push(0);
-    try {
-      func.apply(void 0, args);
-    } catch (e) {
-      // we don't care what happens as long as we don't crash
-    }
-  }
-}
-
-function testArgumentTypes(name, argc) {
-  var type = 0;
-  var hasMore = true;
-  var func = makeFunction(name, argc);
-  while (hasMore) {
-    var argPool = makeArguments();
-    // When we have 5 or more arguments we lower the amount of tests cases
-    // by randomly removing kOnManyArgumentsRemove entries
-    var numArguments = RUN_WITH_ALL_ARGUMENT_ENTRIES ?
-      kArgObjects : kArgObjects - kOnManyArgumentsRemove;
-    if (kArgObjects >= 5 && !RUN_WITH_ALL_ARGUMENT_ENTRIES) {
-      for (var i = 0; i < kOnManyArgumentsRemove; i++) {
-        var rand = Math.floor(Math.random() * (kArgObjects - i));
-        argPool.splice(rand, 1);
-      }
-    }
-    var current = type;
-    hasMore = false;
-    var argList = [ ];
-    for (var i = 0; i < argc; i++) {
-      var index = current % numArguments;
-      current = (current / numArguments) << 0;
-      if (index != (numArguments - 1))
-        hasMore = true;
-      argList.push(argPool[index]);
-    }
-    try {
-      func.apply(void 0, argList);
-    } catch (e) {
-      // we don't care what happens as long as we don't crash
-    }
-    type++;
-  }
-}
-
-testArgumentCount(NAME, ARGC);
-testArgumentTypes(NAME, ARGC);
diff --git a/test/fuzz-natives/fuzz-natives.status b/test/fuzz-natives/fuzz-natives.status
deleted file mode 100644
index c81188a..0000000
--- a/test/fuzz-natives/fuzz-natives.status
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright 2014 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-[
-[ALWAYS, {
-  # These are designed to crash:
-  "Abort": [SKIP],
-  "AbortJS": [SKIP],
-  "SystemBreak": [SKIP],
-  "_DebugBreakInOptimizedCode": [SKIP],
-
-  # varargs.
-  "Call": [SKIP],
-  "_CallFunction": [SKIP],
-
-  # Implemented in the parser, not callable.
-  "IS_VAR": [SKIP],
-
-  # Compile-time ASSERTs.
-  "_DateField": [SKIP],
-  "_GetFromCache": [SKIP],
-
-  # Riddled with ASSERTs.
-  "CompileForOnStackReplacement": [SKIP],
-
-  # Too slow for fuzzing.
-  "SetAllocationTimeout": [SKIP],
-
-  # TODO(jkummerow): Fix these and un-blacklist them!
-  "CreateDateTimeFormat": [SKIP],
-  "CreateNumberFormat": [SKIP],
-
-  # TODO(danno): Fix these internal function that are only callable form stubs
-  # and un-blacklist them!
-  "CompileLazy": [SKIP],
-  "NotifyDeoptimized": [SKIP],
-  "NotifyStubFailure": [SKIP],
-  "NewSloppyArguments": [SKIP],
-  "NewStrictArguments": [SKIP],
-  "ArrayConstructor": [SKIP],
-  "InternalArrayConstructor": [SKIP],
-  "FinalizeInstanceSize": [SKIP],
-  "PromoteScheduledException": [SKIP],
-  "NewFunctionContext": [SKIP],
-  "PushWithContext": [SKIP],
-  "PushCatchContext": [SKIP],
-  "PushModuleContext": [SKIP],
-  "LoadLookupSlot": [SKIP],
-  "LoadLookupSlotNoReferenceError": [SKIP],
-  "ResolvePossiblyDirectEval": [SKIP],
-  "ForInInit": [SKIP],
-  "ForInNext": [SKIP],
-
-  # TODO(jkummerow): Figure out what to do about inlined functions.
-  "_GeneratorNext": [SKIP],
-  "_GeneratorThrow": [SKIP],
-  "_GetCachedArrayIndex": [SKIP],
-  "_HasCachedArrayIndex": [SKIP],
-  "_IsStringWrapperSafeForDefaultValueOf": [SKIP],
-  "_OneByteSeqStringSetChar": [SKIP],
-  "_RegExpConstructResult": [SKIP],
-  "_TwoByteSeqStringSetChar": [SKIP],
-
-  # These are slow.
-  "DebugEvaluate": [PASS, SLOW],
-  "DebugReferencedBy": [PASS, SLOW],
-  "SetAccessorProperty": [PASS, SLOW],
-  "SetScopeVariableValue": [PASS, SLOW],
-}]  # ALWAYS
-]
diff --git a/test/fuzz-natives/testcfg.py b/test/fuzz-natives/testcfg.py
deleted file mode 100644
index 5e00b40..0000000
--- a/test/fuzz-natives/testcfg.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright 2014 the V8 project authors. 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
-
-from testrunner.local import commands
-from testrunner.local import testsuite
-from testrunner.local import utils
-from testrunner.objects import testcase
-
-class FuzzNativesTestSuite(testsuite.TestSuite):
-
-  def __init__(self, name, root):
-    super(FuzzNativesTestSuite, self).__init__(name, root)
-
-  def ListTests(self, context):
-    shell = os.path.abspath(os.path.join(context.shell_dir, self.shell()))
-    if utils.IsWindows():
-      shell += ".exe"
-    output = commands.Execute(
-        context.command_prefix +
-        [shell, "--allow-natives-syntax", "-e",
-         "try { var natives = %ListNatives();"
-         "  for (var n in natives) { print(natives[n]); }"
-         "} catch(e) {}"] +
-        context.extra_flags)
-    if output.exit_code != 0:
-      print output.stdout
-      print output.stderr
-      assert False, "Failed to get natives list."
-    tests = []
-    for line in output.stdout.strip().split():
-      try:
-        (name, argc) = line.split(",")
-        flags = ["--allow-natives-syntax",
-                 "-e", "var NAME = '%s', ARGC = %s;" % (name, argc)]
-        test = testcase.TestCase(self, name, flags)
-        tests.append(test)
-      except:
-        # Work-around: If parsing didn't work, it might have been due to output
-        # caused by other d8 flags.
-        pass
-    return tests
-
-  def GetFlagsForTestCase(self, testcase, context):
-    name = testcase.path
-    basefile = os.path.join(self.root, "base.js")
-    return testcase.flags + [basefile] + context.mode_flags
-
-def GetSuite(name, root):
-  return FuzzNativesTestSuite(name, root)
diff --git a/test/heap-unittests/heap-unittests.status b/test/heap-unittests/heap-unittests.status
deleted file mode 100644
index d439913..0000000
--- a/test/heap-unittests/heap-unittests.status
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2014 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-[
-]
diff --git a/test/intl/general/smp-identifier.js b/test/intl/general/smp-identifier.js
new file mode 100644
index 0000000..8a8d2e6
--- /dev/null
+++ b/test/intl/general/smp-identifier.js
@@ -0,0 +1,43 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function toSurrogatePair(c) {
+  return String.fromCharCode(((c - 0x10000) >>> 10) & 0x3FF | 0xD800) +
+         String.fromCharCode(c & 0x3FF | 0xDC00);
+}
+
+function testIdStart(c, is_id_start) {
+  var source = "var " + toSurrogatePair(c);
+  print(source);
+  if (is_id_start) {
+    assertDoesNotThrow(source);
+  } else {
+    assertThrows(source);
+  }
+}
+
+function testIdPart(c, is_id_start) {
+  var source = "var v" + toSurrogatePair(c);
+  print(source);
+  if (is_id_start) {
+    assertDoesNotThrow(source);
+  } else {
+    assertThrows(source);
+  }
+}
+
+[0x10403, 0x1043C, 0x16F9C, 0x10048, 0x1014D].forEach(function(c) {
+  testIdStart(c, true);
+  testIdPart(c, true);
+});
+
+[0x101FD, 0x11002, 0x104A9].forEach(function(c) {
+  testIdStart(c, false);
+  testIdPart(c, true);
+});
+
+[0x10111, 0x1F4A9].forEach(function(c) {
+  testIdStart(c, false);
+  testIdPart(c, false);
+});
diff --git a/test/js-perf-test/Classes/default-constructor.js b/test/js-perf-test/Classes/default-constructor.js
new file mode 100644
index 0000000..49dcaa6
--- /dev/null
+++ b/test/js-perf-test/Classes/default-constructor.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+'use strict';
+
+var DefaultConstructorBenchmark = new BenchmarkSuite('DefaultConstructor',
+    [100], [
+      new Benchmark('NoSuperClass', false, false, 0, NoSuperClass),
+      new Benchmark('WithSuperClass', false, false, 0, WithSuperClass),
+      new Benchmark('WithSuperClassArguments', false, false, 0,
+                    WithSuperClassArguments),
+    ]);
+
+
+class BaseClass {}
+
+
+class DerivedClass extends BaseClass {}
+
+
+function NoSuperClass() {
+  return new BaseClass();
+}
+
+
+function WithSuperClass() {
+  return new DerivedClass();
+}
+
+
+function WithSuperClassArguments() {
+  return new DerivedClass(0, 1, 2, 3, 4);
+}
diff --git a/test/js-perf-test/Classes/run.js b/test/js-perf-test/Classes/run.js
new file mode 100644
index 0000000..5d48b32
--- /dev/null
+++ b/test/js-perf-test/Classes/run.js
@@ -0,0 +1,28 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+load('../base.js');
+load('super.js');
+load('default-constructor.js');
+
+
+var success = true;
+
+function PrintResult(name, result) {
+  print(name + '-Classes(Score): ' + result);
+}
+
+
+function PrintError(name, error) {
+  PrintResult(name, error);
+  success = false;
+}
+
+
+BenchmarkSuite.config.doWarmup = undefined;
+BenchmarkSuite.config.doDeterministic = undefined;
+
+BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
+                           NotifyError: PrintError });
diff --git a/test/js-perf-test/Classes/super.js b/test/js-perf-test/Classes/super.js
new file mode 100644
index 0000000..a9ec766
--- /dev/null
+++ b/test/js-perf-test/Classes/super.js
@@ -0,0 +1,59 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+'use strict';
+
+var SuperBenchmark = new BenchmarkSuite('Super', [100], [
+     new Benchmark('SuperMethodCall', false, false, 0, SuperMethodCall),
+     new Benchmark('SuperGetterCall', false, false, 0, SuperGetterCall),
+     new Benchmark('SuperSetterCall', false, false, 0, SuperSetterCall),
+]);
+
+
+function Base() { }
+Base.prototype = {
+  constructor: Base,
+  get x() {
+    return this._x++;
+  },
+  set x(v) {
+    this._x += v;
+    return this._x;
+  }
+}
+
+Base.prototype.f = function() {
+  return this._x++;
+}.toMethod(Base.prototype);
+
+function Derived() {
+  this._x = 1;
+}
+Derived.prototype = Object.create(Base.prototype);
+Object.setPrototypeOf(Derived, Base);
+
+Derived.prototype.SuperCall = function() {
+  return super.f();
+}.toMethod(Derived.prototype);
+
+Derived.prototype.GetterCall = function() {
+  return super.x;
+}.toMethod(Derived.prototype);
+
+Derived.prototype.SetterCall = function() {
+  return super.x = 5;
+}.toMethod(Derived.prototype);
+
+var derived = new Derived();
+
+function SuperMethodCall() {
+  return derived.SuperCall();
+}
+
+function SuperGetterCall() {
+  return derived.GetterCall();
+}
+
+function SuperSetterCall() {
+  return derived.SetterCall();
+}
diff --git a/test/js-perf-test/Collections/common.js b/test/js-perf-test/Collections/common.js
new file mode 100644
index 0000000..3ea3933
--- /dev/null
+++ b/test/js-perf-test/Collections/common.js
@@ -0,0 +1,31 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+var N = 10;
+var keys;
+
+
+function SetupSmiKeys() {
+  keys = new Array(N * 2);
+  for (var i = 0; i < N * 2; i++) {
+    keys[i] = i;
+  }
+}
+
+
+function SetupStringKeys() {
+  keys = new Array(N * 2);
+  for (var i = 0; i < N * 2; i++) {
+    keys[i] = 's' + i;
+  }
+}
+
+
+function SetupObjectKeys() {
+  keys = new Array(N * 2);
+  for (var i = 0; i < N * 2; i++) {
+    keys[i] = {};
+  }
+}
diff --git a/test/js-perf-test/Collections/map.js b/test/js-perf-test/Collections/map.js
new file mode 100644
index 0000000..4f55798
--- /dev/null
+++ b/test/js-perf-test/Collections/map.js
@@ -0,0 +1,217 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+var MapSmiBenchmark = new BenchmarkSuite('Map-Smi', [1000], [
+  new Benchmark('Set', false, false, 0, MapSetSmi, MapSetupSmiBase, MapTearDown),
+  new Benchmark('Has', false, false, 0, MapHasSmi, MapSetupSmi, MapTearDown),
+  new Benchmark('Get', false, false, 0, MapGetSmi, MapSetupSmi, MapTearDown),
+  new Benchmark('Delete', false, false, 0, MapDeleteSmi, MapSetupSmi, MapTearDown),
+]);
+
+
+var MapStringBenchmark = new BenchmarkSuite('Map-String', [1000], [
+  new Benchmark('Set', false, false, 0, MapSetString, MapSetupStringBase, MapTearDown),
+  new Benchmark('Has', false, false, 0, MapHasString, MapSetupString, MapTearDown),
+  new Benchmark('Get', false, false, 0, MapGetString, MapSetupString, MapTearDown),
+  new Benchmark('Delete', false, false, 0, MapDeleteString, MapSetupString, MapTearDown),
+]);
+
+
+var MapObjectBenchmark = new BenchmarkSuite('Map-Object', [1000], [
+  new Benchmark('Set', false, false, 0, MapSetObject, MapSetupObjectBase, MapTearDown),
+  new Benchmark('Has', false, false, 0, MapHasObject, MapSetupObject, MapTearDown),
+  new Benchmark('Get', false, false, 0, MapGetObject, MapSetupObject, MapTearDown),
+  new Benchmark('Delete', false, false, 0, MapDeleteObject, MapSetupObject, MapTearDown),
+]);
+
+
+var MapIterationBenchmark = new BenchmarkSuite('Map-Iteration', [1000], [
+  new Benchmark('ForEach', false, false, 0, MapForEach, MapSetupSmi, MapTearDown),
+]);
+
+
+var map;
+
+
+function MapSetupSmiBase() {
+  SetupSmiKeys();
+  map = new Map;
+}
+
+
+function MapSetupSmi() {
+  MapSetupSmiBase();
+  MapSetSmi();
+}
+
+
+function MapSetupStringBase() {
+  SetupStringKeys();
+  map = new Map;
+}
+
+
+function MapSetupString() {
+  MapSetupStringBase();
+  MapSetString();
+}
+
+
+function MapSetupObjectBase() {
+  SetupObjectKeys();
+  map = new Map;
+}
+
+
+function MapSetupObject() {
+  MapSetupObjectBase();
+  MapSetObject();
+}
+
+
+function MapTearDown() {
+  map = null;
+}
+
+
+function MapSetSmi() {
+  for (var i = 0; i < N; i++) {
+    map.set(keys[i], i);
+  }
+}
+
+
+function MapHasSmi() {
+  for (var i = 0; i < N; i++) {
+    if (!map.has(keys[i])) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (map.has(keys[i])) {
+      throw new Error();
+    }
+  }
+}
+
+
+function MapGetSmi() {
+  for (var i = 0; i < N; i++) {
+    if (map.get(keys[i]) !== i) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (map.get(keys[i]) !== undefined) {
+      throw new Error();
+    }
+  }
+}
+
+
+function MapDeleteSmi() {
+  // This is run more than once per setup so we will end up deleting items
+  // more than once. Therefore, we do not the return value of delete.
+  for (var i = 0; i < N; i++) {
+    map.delete(keys[i]);
+  }
+}
+
+
+function MapSetString() {
+  for (var i = 0; i < N; i++) {
+    map.set(keys[i], i);
+  }
+}
+
+
+function MapHasString() {
+  for (var i = 0; i < N; i++) {
+    if (!map.has(keys[i])) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (map.has(keys[i])) {
+      throw new Error();
+    }
+  }
+}
+
+
+function MapGetString() {
+  for (var i = 0; i < N; i++) {
+    if (map.get(keys[i]) !== i) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (map.get(keys[i]) !== undefined) {
+      throw new Error();
+    }
+  }
+}
+
+
+function MapDeleteString() {
+  // This is run more than once per setup so we will end up deleting items
+  // more than once. Therefore, we do not the return value of delete.
+  for (var i = 0; i < N; i++) {
+    map.delete(keys[i]);
+  }
+}
+
+
+function MapSetObject() {
+  for (var i = 0; i < N; i++) {
+    map.set(keys[i], i);
+  }
+}
+
+
+function MapHasObject() {
+  for (var i = 0; i < N; i++) {
+    if (!map.has(keys[i])) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (map.has(keys[i])) {
+      throw new Error();
+    }
+  }
+}
+
+
+function MapGetObject() {
+  for (var i = 0; i < N; i++) {
+    if (map.get(keys[i]) !== i) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (map.get(keys[i]) !== undefined) {
+      throw new Error();
+    }
+  }
+}
+
+
+function MapDeleteObject() {
+  // This is run more than once per setup so we will end up deleting items
+  // more than once. Therefore, we do not the return value of delete.
+  for (var i = 0; i < N; i++) {
+    map.delete(keys[i]);
+  }
+}
+
+
+function MapForEach() {
+  map.forEach(function(v, k) {
+    if (v !== k) {
+      throw new Error();
+    }
+  });
+}
diff --git a/test/js-perf-test/Collections/run.js b/test/js-perf-test/Collections/run.js
new file mode 100644
index 0000000..50f1ee1
--- /dev/null
+++ b/test/js-perf-test/Collections/run.js
@@ -0,0 +1,31 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+load('../base.js');
+load('common.js');
+load('map.js');
+load('set.js');
+load('weakmap.js');
+load('weakset.js');
+
+
+var success = true;
+
+function PrintResult(name, result) {
+  print(name + '-Collections(Score): ' + result);
+}
+
+
+function PrintError(name, error) {
+  PrintResult(name, error);
+  success = false;
+}
+
+
+BenchmarkSuite.config.doWarmup = undefined;
+BenchmarkSuite.config.doDeterministic = undefined;
+
+BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
+                           NotifyError: PrintError });
diff --git a/test/js-perf-test/Collections/set.js b/test/js-perf-test/Collections/set.js
new file mode 100644
index 0000000..3be27f5
--- /dev/null
+++ b/test/js-perf-test/Collections/set.js
@@ -0,0 +1,172 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+var SetSmiBenchmark = new BenchmarkSuite('Set-Smi', [1000], [
+  new Benchmark('Set', false, false, 0, SetAddSmi, SetSetupSmiBase, SetTearDown),
+  new Benchmark('Has', false, false, 0, SetHasSmi, SetSetupSmi, SetTearDown),
+  new Benchmark('Delete', false, false, 0, SetDeleteSmi, SetSetupSmi, SetTearDown),
+]);
+
+
+var SetStringBenchmark = new BenchmarkSuite('Set-String', [1000], [
+  new Benchmark('Set', false, false, 0, SetAddString, SetSetupStringBase, SetTearDown),
+  new Benchmark('Has', false, false, 0, SetHasString, SetSetupString, SetTearDown),
+  new Benchmark('Delete', false, false, 0, SetDeleteString, SetSetupString, SetTearDown),
+]);
+
+
+var SetObjectBenchmark = new BenchmarkSuite('Set-Object', [1000], [
+  new Benchmark('Set', false, false, 0, SetAddObject, SetSetupObjectBase, SetTearDown),
+  new Benchmark('Has', false, false, 0, SetHasObject, SetSetupObject, SetTearDown),
+  new Benchmark('Delete', false, false, 0, SetDeleteObject, SetSetupObject, SetTearDown),
+]);
+
+
+var SetIterationBenchmark = new BenchmarkSuite('Set-Iteration', [1000], [
+  new Benchmark('ForEach', false, false, 0, SetForEach, SetSetupSmi, SetTearDown),
+]);
+
+
+var set;
+
+
+function SetSetupSmiBase() {
+  SetupSmiKeys();
+  set = new Set;
+}
+
+
+function SetSetupSmi() {
+  SetSetupSmiBase();
+  SetAddSmi();
+}
+
+
+function SetSetupStringBase() {
+  SetupStringKeys();
+  set = new Set;
+}
+
+
+function SetSetupString() {
+  SetSetupStringBase();
+  SetAddString();
+}
+
+
+function SetSetupObjectBase() {
+  SetupObjectKeys();
+  set = new Set;
+}
+
+
+function SetSetupObject() {
+  SetSetupObjectBase();
+  SetAddObject();
+}
+
+
+function SetTearDown() {
+  set = null;
+}
+
+
+function SetAddSmi() {
+  for (var i = 0; i < N; i++) {
+    set.add(keys[i], i);
+  }
+}
+
+
+function SetHasSmi() {
+  for (var i = 0; i < N; i++) {
+    if (!set.has(keys[i])) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (set.has(keys[i])) {
+      throw new Error();
+    }
+  }
+}
+
+
+function SetDeleteSmi() {
+  // This is run more than once per setup so we will end up deleting items
+  // more than once. Therefore, we do not the return value of delete.
+  for (var i = 0; i < N; i++) {
+    set.delete(keys[i]);
+  }
+}
+
+
+function SetAddString() {
+  for (var i = 0; i < N; i++) {
+    set.add(keys[i], i);
+  }
+}
+
+
+function SetHasString() {
+  for (var i = 0; i < N; i++) {
+    if (!set.has(keys[i])) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (set.has(keys[i])) {
+      throw new Error();
+    }
+  }
+}
+
+
+function SetDeleteString() {
+  // This is run more than once per setup so we will end up deleting items
+  // more than once. Therefore, we do not the return value of delete.
+  for (var i = 0; i < N; i++) {
+    set.delete(keys[i]);
+  }
+}
+
+
+function SetAddObject() {
+  for (var i = 0; i < N; i++) {
+    set.add(keys[i], i);
+  }
+}
+
+
+function SetHasObject() {
+  for (var i = 0; i < N; i++) {
+    if (!set.has(keys[i])) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (set.has(keys[i])) {
+      throw new Error();
+    }
+  }
+}
+
+
+function SetDeleteObject() {
+  // This is run more than once per setup so we will end up deleting items
+  // more than once. Therefore, we do not the return value of delete.
+  for (var i = 0; i < N; i++) {
+    set.delete(keys[i]);
+  }
+}
+
+
+function SetForEach() {
+  set.forEach(function(v, k) {
+    if (v !== k) {
+      throw new Error();
+    }
+  });
+}
diff --git a/test/js-perf-test/Collections/weakmap.js b/test/js-perf-test/Collections/weakmap.js
new file mode 100644
index 0000000..9aa265f
--- /dev/null
+++ b/test/js-perf-test/Collections/weakmap.js
@@ -0,0 +1,79 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+var MapBenchmark = new BenchmarkSuite('WeakMap', [1000], [
+  new Benchmark('Set', false, false, 0, WeakMapSet, WeakMapSetupBase,
+      WeakMapTearDown),
+  new Benchmark('Has', false, false, 0, WeakMapHas, WeakMapSetup,
+      WeakMapTearDown),
+  new Benchmark('Get', false, false, 0, WeakMapGet, WeakMapSetup,
+      WeakMapTearDown),
+  new Benchmark('Delete', false, false, 0, WeakMapDelete, WeakMapSetup,
+      WeakMapTearDown),
+]);
+
+
+var wm;
+
+
+function WeakMapSetupBase() {
+  SetupObjectKeys();
+  wm = new WeakMap;
+}
+
+
+function WeakMapSetup() {
+  WeakMapSetupBase();
+  WeakMapSet();
+}
+
+
+function WeakMapTearDown() {
+  wm = null;
+}
+
+
+function WeakMapSet() {
+  for (var i = 0; i < N; i++) {
+    wm.set(keys[i], i);
+  }
+}
+
+
+function WeakMapHas() {
+  for (var i = 0; i < N; i++) {
+    if (!wm.has(keys[i])) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (wm.has(keys[i])) {
+      throw new Error();
+    }
+  }
+}
+
+
+function WeakMapGet() {
+  for (var i = 0; i < N; i++) {
+    if (wm.get(keys[i]) !== i) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (wm.get(keys[i]) !== undefined) {
+      throw new Error();
+    }
+  }
+}
+
+
+function WeakMapDelete() {
+  // This is run more than once per setup so we will end up deleting items
+  // more than once. Therefore, we do not the return value of delete.
+  for (var i = 0; i < N; i++) {
+    wm.delete(keys[i]);
+  }
+}
diff --git a/test/js-perf-test/Collections/weakset.js b/test/js-perf-test/Collections/weakset.js
new file mode 100644
index 0000000..2936477
--- /dev/null
+++ b/test/js-perf-test/Collections/weakset.js
@@ -0,0 +1,63 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+var SetBenchmark = new BenchmarkSuite('WeakSet', [1000], [
+  new Benchmark('Add', false, false, 0, WeakSetAdd, WeakSetSetupBase,
+      WeakSetTearDown),
+  new Benchmark('Has', false, false, 0, WeakSetHas, WeakSetSetup,
+      WeakSetTearDown),
+  new Benchmark('Delete', false, false, 0, WeakSetDelete, WeakSetSetup,
+      WeakSetTearDown),
+]);
+
+
+var ws;
+
+
+function WeakSetSetupBase() {
+  SetupObjectKeys();
+  ws = new WeakSet;
+}
+
+
+function WeakSetSetup() {
+  WeakSetSetupBase();
+  WeakSetAdd();
+}
+
+
+function WeakSetTearDown() {
+  ws = null;
+}
+
+
+function WeakSetAdd() {
+  for (var i = 0; i < N; i++) {
+    ws.add(keys[i]);
+  }
+}
+
+
+function WeakSetHas() {
+  for (var i = 0; i < N; i++) {
+    if (!ws.has(keys[i])) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (ws.has(keys[i])) {
+      throw new Error();
+    }
+  }
+}
+
+
+function WeakSetDelete() {
+  // This is run more than once per setup so we will end up deleting items
+  // more than once. Therefore, we do not the return value of delete.
+  for (var i = 0; i < N; i++) {
+    ws.delete(keys[i]);
+  }
+}
diff --git a/test/js-perf-test/Iterators/forof.js b/test/js-perf-test/Iterators/forof.js
new file mode 100644
index 0000000..1877ebe
--- /dev/null
+++ b/test/js-perf-test/Iterators/forof.js
@@ -0,0 +1,94 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+new BenchmarkSuite('ForOf', [1000], [
+  new Benchmark('ArrayValues', false, false, 0,
+                ForOf, ForOfArraySetup, ForOfTearDown),
+  new Benchmark('ArrayKeys', false, false, 0,
+                ForOf, ForOfArrayKeysSetup, ForOfTearDown),
+  new Benchmark('ArrayEntries', false, false, 0,
+                ForOf, ForOfArrayEntriesSetup, ForOfTearDown),
+  new Benchmark('Uint8Array', false, false, 0,
+                ForOf, ForOfUint8ArraySetup, ForOfTearDown),
+  new Benchmark('Float64Array', false, false, 0,
+                ForOf, ForOfFloat64ArraySetup, ForOfTearDown),
+  new Benchmark('String', false, false, 0,
+                ForOf, ForOfStringSetup, ForOfTearDown),
+]);
+
+
+var iterable;
+var N = 100;
+var expected, result;
+
+
+function ForOfArraySetupHelper(constructor) {
+  iterable = new constructor(N);
+  for (var i = 0; i < N; i++) iterable[i] = i;
+  expected = N - 1;
+}
+
+
+function ForOfArraySetup() {
+  ForOfArraySetupHelper(Array);
+  // Default iterator is values().
+}
+
+
+function ForOfArrayKeysSetup() {
+  ForOfArraySetupHelper(Array);
+  iterable = iterable.keys();
+}
+
+
+function ForOfArrayEntriesSetup() {
+  ForOfArraySetupHelper(Array);
+  iterable = iterable.entries();
+  expected = [N-1, N-1];
+}
+
+
+function ForOfUint8ArraySetup() {
+  ForOfArraySetupHelper(Uint8Array);
+}
+
+
+function ForOfFloat64ArraySetup() {
+  ForOfArraySetupHelper(Float64Array);
+}
+
+
+function ForOfStringSetup() {
+  iterable = "abcdefhijklmnopqrstuvwxyzABCDEFHIJKLMNOPQRSTUVWXYZ0123456789";
+  expected = "9";
+}
+
+
+function Equals(expected, actual) {
+  if (expected === actual) return true;
+  if (typeof expected !== typeof actual) return false;
+  if (typeof expected !== 'object') return false;
+  for (var k of Object.keys(expected)) {
+    if (!(k in actual)) return false;
+    if (!Equals(expected[k], actual[k])) return false;
+  }
+  for (var k of Object.keys(actual)) {
+    if (!(k in expected)) return false;
+  }
+  return true;
+}
+
+function ForOfTearDown() {
+  iterable = null;
+  if (!Equals(expected, result)) {
+    throw new Error("Bad result: " + result);
+  }
+}
+
+
+function ForOf() {
+  for (var x of iterable) {
+    result = x;
+  }
+}
diff --git a/test/js-perf-test/Iterators/run.js b/test/js-perf-test/Iterators/run.js
new file mode 100644
index 0000000..ff4897f
--- /dev/null
+++ b/test/js-perf-test/Iterators/run.js
@@ -0,0 +1,27 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+load('../base.js');
+load('forof.js');
+
+
+var success = true;
+
+function PrintResult(name, result) {
+  print(name + '-Iterators(Score): ' + result);
+}
+
+
+function PrintError(name, error) {
+  PrintResult(name, error);
+  success = false;
+}
+
+
+BenchmarkSuite.config.doWarmup = undefined;
+BenchmarkSuite.config.doDeterministic = undefined;
+
+BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
+                           NotifyError: PrintError });
diff --git a/test/js-perf-test/JSTests.json b/test/js-perf-test/JSTests.json
new file mode 100644
index 0000000..0a99ad4
--- /dev/null
+++ b/test/js-perf-test/JSTests.json
@@ -0,0 +1,86 @@
+{
+  "name": "JSTests",
+  "run_count": 5,
+  "run_count_android_arm": 3,
+  "run_count_android_arm64": 3,
+  "units": "score",
+  "total": true,
+  "resources": ["base.js"],
+  "tests": [
+    {
+      "name": "Classes",
+      "path": ["Classes"],
+      "main": "run.js",
+      "resources": ["super.js", "default-constructor.js"],
+      "flags": ["--harmony-classes"],
+      "results_regexp": "^%s\\-Classes\\(Score\\): (.+)$",
+      "tests": [
+        {"name": "Super"},
+        {"name": "DefaultConstructor"}
+      ]
+    },
+    {
+      "name": "Collections",
+      "path": ["Collections"],
+      "main": "run.js",
+      "resources": [
+        "common.js",
+        "map.js",
+        "run.js",
+        "set.js",
+        "weakmap.js",
+        "weakset.js"
+      ],
+      "results_regexp": "^%s\\-Collections\\(Score\\): (.+)$",
+      "tests": [
+        {"name": "Map-Smi"},
+        {"name": "Map-String"},
+        {"name": "Map-Object"},
+        {"name": "Map-Iteration"},
+        {"name": "Set-Smi"},
+        {"name": "Set-String"},
+        {"name": "Set-Object"},
+        {"name": "Set-Iteration"},
+        {"name": "WeakMap"},
+        {"name": "WeakSet"}
+      ]
+    },
+    {
+      "name": "Iterators",
+      "path": ["Iterators"],
+      "main": "run.js",
+      "resources": ["forof.js"],
+      "results_regexp": "^%s\\-Iterators\\(Score\\): (.+)$",
+      "tests": [
+        {"name": "ForOf"}
+      ]
+    },
+    {
+      "name": "Strings",
+      "path": ["Strings"],
+      "main": "run.js",
+      "resources": ["harmony-string.js"],
+      "flags": ["--harmony-strings"],
+      "results_regexp": "^%s\\-Strings\\(Score\\): (.+)$",
+      "tests": [
+        {"name": "StringFunctions"}
+      ]
+    },
+    {
+      "name": "Templates",
+      "path": ["Templates"],
+      "main": "run.js",
+      "resources": ["templates.js"],
+      "flags": ["--harmony-templates"],
+      "run_count": 5,
+      "units": "score",
+      "results_regexp": "^%s\\-Templates\\(Score\\): (.+)$",
+      "total": true,
+      "tests": [
+        {"name": "Untagged"},
+        {"name": "LargeUntagged"},
+        {"name": "Tagged"}
+      ]
+    }
+  ]
+}
diff --git a/test/js-perf-test/Strings/harmony-string.js b/test/js-perf-test/Strings/harmony-string.js
new file mode 100644
index 0000000..c2eac4e
--- /dev/null
+++ b/test/js-perf-test/Strings/harmony-string.js
@@ -0,0 +1,111 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+new BenchmarkSuite('StringFunctions', [1000], [
+  new Benchmark('StringRepeat', false, false, 0,
+                Repeat, RepeatSetup, RepeatTearDown),
+  new Benchmark('StringStartsWith', false, false, 0,
+                StartsWith, WithSetup, WithTearDown),
+  new Benchmark('StringEndsWith', false, false, 0,
+                EndsWith, WithSetup, WithTearDown),
+  new Benchmark('StringIncludes', false, false, 0,
+                Includes, IncludesSetup, WithTearDown),
+  new Benchmark('StringFromCodePoint', false, false, 0,
+                FromCodePoint, FromCodePointSetup, FromCodePointTearDown),
+  new Benchmark('StringCodePointAt', false, false, 0,
+                CodePointAt, CodePointAtSetup, CodePointAtTearDown),
+]);
+
+
+var result;
+
+var stringRepeatSource = "abc";
+
+function RepeatSetup() {
+  result = undefined;
+}
+
+function Repeat() {
+  result = stringRepeatSource.repeat(500);
+}
+
+function RepeatTearDown() {
+  var expected = "";
+  for(var i = 0; i < 1000; i++) {
+    expected += stringRepeatSource;
+  }
+  return result === expected;
+}
+
+
+var str;
+var substr;
+
+function WithSetup() {
+  str = "abc".repeat(500);
+  substr = "abc".repeat(200);
+  result = undefined;
+}
+
+function WithTearDown() {
+  return !!result;
+}
+
+function StartsWith() {
+  result = str.startsWith(substr);
+}
+
+function EndsWith() {
+  result = str.endsWith(substr);
+}
+
+function IncludesSetup() {
+  str = "def".repeat(100) + "abc".repeat(100) + "qqq".repeat(100);
+  substr = "abc".repeat(100);
+}
+
+function Includes() {
+  result = str.includes(substr);
+}
+
+var MAX_CODE_POINT = 0xFFFFF;
+
+function FromCodePointSetup() {
+  result = new Array(MAX_CODE_POINT + 1);
+}
+
+function FromCodePoint() {
+  for (var i = 0; i <= MAX_CODE_POINT; i++) {
+    result[i] = String.fromCodePoint(i);
+  }
+}
+
+function FromCodePointTearDown() {
+  for (var i = 0; i <= MAX_CODE_POINT; i++) {
+    if (i !== result[i].codePointAt(0)) return false;
+  }
+  return true;
+}
+
+
+var allCodePoints;
+
+function CodePointAtSetup() {
+  allCodePoints = new Array(MAX_CODE_POINT + 1);
+  for (var i = 0; i <= MAX_CODE_POINT; i++) {
+    allCodePoints = String.fromCodePoint(i);
+  }
+  result = undefined;
+}
+
+function CodePointAt() {
+  result = 0;
+  for (var i = 0; i <= MAX_CODE_POINT; i++) {
+    result += allCodePoints.codePointAt(i);
+  }
+}
+
+function CodePointAtTearDown() {
+  return result === MAX_CODE_POINT * (MAX_CODE_POINT + 1) / 2;
+}
diff --git a/test/js-perf-test/Strings/run.js b/test/js-perf-test/Strings/run.js
new file mode 100644
index 0000000..79ca26e
--- /dev/null
+++ b/test/js-perf-test/Strings/run.js
@@ -0,0 +1,27 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+load('../base.js');
+load('harmony-string.js');
+
+
+var success = true;
+
+function PrintResult(name, result) {
+  print(name + '-Strings(Score): ' + result);
+}
+
+
+function PrintError(name, error) {
+  PrintResult(name, error);
+  success = false;
+}
+
+
+BenchmarkSuite.config.doWarmup = undefined;
+BenchmarkSuite.config.doDeterministic = undefined;
+
+BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
+                           NotifyError: PrintError });
diff --git a/test/js-perf-test/Templates/run.js b/test/js-perf-test/Templates/run.js
new file mode 100644
index 0000000..73f1edd
--- /dev/null
+++ b/test/js-perf-test/Templates/run.js
@@ -0,0 +1,27 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+load('../base.js');
+load('templates.js');
+
+
+var success = true;
+
+function PrintResult(name, result) {
+  print(name + '-Templates(Score): ' + result);
+}
+
+
+function PrintError(name, error) {
+  PrintResult(name, error);
+  success = false;
+}
+
+
+BenchmarkSuite.config.doWarmup = undefined;
+BenchmarkSuite.config.doDeterministic = undefined;
+
+BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
+                           NotifyError: PrintError });
diff --git a/test/js-perf-test/Templates/templates.js b/test/js-perf-test/Templates/templates.js
new file mode 100644
index 0000000..4034ce7
--- /dev/null
+++ b/test/js-perf-test/Templates/templates.js
@@ -0,0 +1,87 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+new BenchmarkSuite('Untagged', [1000], [
+  new Benchmark('Untagged-Simple', false, false, 0,
+                Untagged, UntaggedSetup, UntaggedTearDown),
+]);
+
+new BenchmarkSuite('LargeUntagged', [1000], [
+  new Benchmark('Untagged-Large', false, false, 0,
+                UntaggedLarge, UntaggedLargeSetup, UntaggedLargeTearDown),
+]);
+
+new BenchmarkSuite('Tagged', [1000], [
+  new Benchmark('TaggedRawSimple', false, false, 0,
+                TaggedRaw, TaggedRawSetup, TaggedRawTearDown),
+]);
+
+var result;
+var SUBJECT = 'Bob';
+var TARGET = 'Mary';
+var OBJECT = 'apple';
+
+function UntaggedSetup() {
+  result = undefined;
+}
+
+function Untagged() {
+  result = `${SUBJECT} gives ${TARGET} an ${OBJECT}.`;
+}
+
+function UntaggedTearDown() {
+  var expected = '' + SUBJECT + ' gives ' + TARGET + ' an ' + OBJECT + '.';
+  return result === expected;
+}
+
+
+// ----------------------------------------------------------------------------
+
+function UntaggedLargeSetup() {
+  result = undefined;
+}
+
+function UntaggedLarge() {
+  result = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
+ aliquam, elit euismod vestibulum ${0}lacinia, arcu odio sagittis mauris, id
+ blandit dolor felis pretium nisl. Maecenas porttitor, nunc ut accumsan mollis,
+ arcu metus rutrum arcu, ${1}ut varius dolor lorem nec risus. Integer convallis
+ tristique ante, non pretium ante suscipit at. Sed egestas massa enim, convallis
+ fermentum neque vehicula ac. Donec imperdiet a tortor ac semper. Morbi accumsan
+ quam nec erat viverra iaculis. ${2}Donec a scelerisque cras amet.`;
+}
+
+function UntaggedLargeTearDown() {
+  var expected = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
+      "Vivamus\n aliquam, elit euismod vestibulum " + 0 + "lacinia, arcu odio" +
+      " sagittis mauris, id\n blandit dolor felis pretium nisl. Maecenas " +
+      "porttitor, nunc ut accumsan mollis,\n arcu metus rutrum arcu, " + 1 +
+      "ut varius dolor lorem nec risus. Integer convallis\n tristique ante, " +
+      "non pretium ante suscipit at. Sed egestas massa enim, convallis\n " +
+      "fermentum neque vehicula ac. Donec imperdiet a tortor ac semper. Morbi" +
+      " accumsan\n quam nec erat viverra iaculis. " + 2 + "Donec a " +
+      "scelerisque cras amet.";
+  return result === expected;
+}
+
+
+// ----------------------------------------------------------------------------
+
+
+function TaggedRawSetup() {
+  result = undefined;
+}
+
+function TaggedRaw() {
+  result = String.raw `${SUBJECT} gives ${TARGET} an ${OBJECT} \ud83c\udf4f.`;
+}
+
+function TaggedRawTearDown() {
+  var expected =
+      '' + SUBJECT + ' gives ' + TARGET + ' an ' + OBJECT + ' \\ud83c\\udf4f.';
+  return result === expected;
+}
+
+
+// ----------------------------------------------------------------------------
diff --git a/test/perf-test/Collections/base.js b/test/js-perf-test/base.js
similarity index 100%
rename from test/perf-test/Collections/base.js
rename to test/js-perf-test/base.js
diff --git a/test/libplatform-unittests/libplatform-unittests.status b/test/libplatform-unittests/libplatform-unittests.status
deleted file mode 100644
index d439913..0000000
--- a/test/libplatform-unittests/libplatform-unittests.status
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2014 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-[
-]
diff --git a/test/message/single-function-literal.js b/test/message/single-function-literal.js
index 96d3bd6..fd73491 100644
--- a/test/message/single-function-literal.js
+++ b/test/message/single-function-literal.js
@@ -27,6 +27,6 @@
 
 // Flags: --allow-natives-syntax
 var single_function_good = "(function() { return 5; })";
-%CompileString(single_function_good, true);
+%CompileString(single_function_good, true, 0);
 var single_function_bad = "(function() { return 5; })();";
-%CompileString(single_function_bad, true);
+%CompileString(single_function_bad, true, 0);
diff --git a/test/message/super-constructor-extra-statement.js b/test/message/super-constructor-extra-statement.js
new file mode 100644
index 0000000..e8ffe2d
--- /dev/null
+++ b/test/message/super-constructor-extra-statement.js
@@ -0,0 +1,15 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-classes
+'use strict';
+
+class C {
+  constructor() {
+    var x;
+    super(x);
+  }
+}
+
+var c = new C();
diff --git a/test/message/super-constructor-extra-statement.out b/test/message/super-constructor-extra-statement.out
new file mode 100644
index 0000000..cbe1e07
--- /dev/null
+++ b/test/message/super-constructor-extra-statement.out
@@ -0,0 +1,8 @@
+# Copyright 2014 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+*%(basename)s:10: TypeError: A 'super' constructor call may only appear as the first statement of a function, and its arguments may not access 'this'. Other forms are not yet supported.
+    var x;
+    
+TypeError: A 'super' constructor call may only appear as the first statement of a function, and its arguments may not access 'this'. Other forms are not yet supported.
+    at *%(basename)s:15:9
diff --git a/test/message/super-constructor.js b/test/message/super-constructor.js
new file mode 100644
index 0000000..430dc58
--- /dev/null
+++ b/test/message/super-constructor.js
@@ -0,0 +1,14 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-classes
+'use strict';
+
+class C {
+  constructor() {
+    super(this.x);
+  }
+}
+
+var c = new C();
diff --git a/test/message/super-constructor.out b/test/message/super-constructor.out
new file mode 100644
index 0000000..bc3a699
--- /dev/null
+++ b/test/message/super-constructor.out
@@ -0,0 +1,8 @@
+# Copyright 2014 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+*%(basename)s:10: TypeError: A 'super' constructor call may only appear as the first statement of a function, and its arguments may not access 'this'. Other forms are not yet supported.
+    super(this.x);
+     
+TypeError: A 'super' constructor call may only appear as the first statement of a function, and its arguments may not access 'this'. Other forms are not yet supported.
+    at *%(basename)s:14:9
diff --git a/test/message/testcfg.py b/test/message/testcfg.py
index b472f9c..5d6ab84 100644
--- a/test/message/testcfg.py
+++ b/test/message/testcfg.py
@@ -75,6 +75,7 @@
   def _IgnoreLine(self, string):
     """Ignore empty lines, valgrind output, Android output."""
     if not string: return True
+    if not string.strip(): return True
     return (string.startswith("==") or string.startswith("**") or
             string.startswith("ANDROID") or
             # These five patterns appear in normal Native Client output.
diff --git a/test/mjsunit/array-iteration.js b/test/mjsunit/array-iteration.js
index d11f984..1324074 100644
--- a/test/mjsunit/array-iteration.js
+++ b/test/mjsunit/array-iteration.js
@@ -68,6 +68,23 @@
   assertEquals(3, count);
   for (var i in a) assertEquals(2, a[i]);
 
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  a = [];
+  [1, 2].filter(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  [1, 2].filter(function() { a.push(this) }, {});
+  assertEquals(a[0], a[1]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  a = [];
+  [1, 2].filter(function() { 'use strict'; a.push(this); }, "");
+  assertEquals("", a[0]);
+  assertEquals(a[0], a[1]);
+
 })();
 
 
@@ -109,6 +126,23 @@
   a.forEach(function(n) { count++; });
   assertEquals(1, count);
 
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  a = [];
+  [1, 2].forEach(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  [1, 2].forEach(function() { a.push(this) }, {});
+  assertEquals(a[0], a[1]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  a = [];
+  [1, 2].forEach(function() { 'use strict'; a.push(this); }, "");
+  assertEquals("", a[0]);
+  assertEquals(a[0], a[1]);
+
 })();
 
 
@@ -149,6 +183,23 @@
   assertTrue(a.every(function(n) { count++; return n == 2; }));
   assertEquals(2, count);
 
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  a = [];
+  [1, 2].every(function() { a.push(this); return true; }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  [1, 2].every(function() { a.push(this); return true; }, {});
+  assertEquals(a[0], a[1]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  a = [];
+  [1, 2].every(function() { 'use strict'; a.push(this); return true; }, "");
+  assertEquals("", a[0]);
+  assertEquals(a[0], a[1]);
+
 })();
 
 //
@@ -186,6 +237,23 @@
   a = a.map(function(n) { return 2*n; });
   for (var i in a) assertEquals(4, a[i]);
 
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  a = [];
+  [1, 2].map(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  [1, 2].map(function() { a.push(this) }, {});
+  assertEquals(a[0], a[1]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  a = [];
+  [1, 2].map(function() { 'use strict'; a.push(this); }, "");
+  assertEquals("", a[0]);
+  assertEquals(a[0], a[1]);
+
 })();
 
 //
@@ -224,4 +292,21 @@
   assertTrue(a.some(function(n) { count++; return n == 2; }));
   assertEquals(2, count);
 
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  a = [];
+  [1, 2].some(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  [1, 2].some(function() { a.push(this) }, {});
+  assertEquals(a[0], a[1]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  a = [];
+  [1, 2].some(function() { 'use strict'; a.push(this); }, "");
+  assertEquals("", a[0]);
+  assertEquals(a[0], a[1]);
+
 })();
diff --git a/test/mjsunit/array-methods-read-only-length.js b/test/mjsunit/array-methods-read-only-length.js
new file mode 100644
index 0000000..2943b16
--- /dev/null
+++ b/test/mjsunit/array-methods-read-only-length.js
@@ -0,0 +1,166 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function testAdd(mode) {
+  var a = [];
+  Object.defineProperty(a, "length", { writable : false});
+
+  function check(f) {
+    assertThrows(function() { f(a) }, TypeError);
+    assertFalse(0 in a);
+    assertEquals(0, a.length);
+  }
+
+  function push(a) {
+    a.push(3);
+  }
+
+  if (mode == "fast properties") %ToFastProperties(a);
+
+  check(push);
+  check(push);
+  check(push);
+  %OptimizeFunctionOnNextCall(push);
+  check(push);
+
+  function unshift(a) {
+    a.unshift(3);
+  }
+
+  check(unshift);
+  check(unshift);
+  check(unshift);
+  %OptimizeFunctionOnNextCall(unshift);
+  check(unshift);
+
+  function splice(a) {
+    a.splice(0, 0, 3);
+  }
+
+  check(splice);
+  check(splice);
+  check(splice);
+  %OptimizeFunctionOnNextCall(splice);
+  check(splice);
+}
+
+testAdd("fast properties");
+
+testAdd("normalized");
+
+function testRemove(a, mode) {
+  Object.defineProperty(a, "length", { writable : false});
+
+  function check(f) {
+    assertThrows(function() { f(a) }, TypeError);
+    assertEquals(3, a.length);
+  }
+
+  if (mode == "fast properties") %ToFastProperties(a);
+
+  function pop(a) {
+    a.pop();
+  }
+
+  check(pop);
+  check(pop);
+  check(pop);
+  %OptimizeFunctionOnNextCall(pop);
+  check(pop);
+
+  function shift(a) {
+    a.shift();
+  }
+
+  check(shift);
+  check(shift);
+  check(shift);
+  %OptimizeFunctionOnNextCall(shift);
+  check(shift);
+
+  function splice(a) {
+    a.splice(0, 1);
+  }
+
+  check(splice);
+  check(splice);
+  check(splice);
+  %OptimizeFunctionOnNextCall(splice);
+  check(splice);
+
+  %ClearFunctionTypeFeedback(pop);
+  %ClearFunctionTypeFeedback(shift);
+  %ClearFunctionTypeFeedback(splice);
+}
+
+for (var i = 0; i < 3; i++) {
+  var a = [1, 2, 3];
+  if (i == 1) {
+    a = [1, 2, 3.5];
+  } else if (i == 2) {
+    a = [1, 2, "string"];
+  }
+  testRemove(a, "fast properties");
+  testRemove(a, "normalized");
+}
+
+var b = [];
+Object.defineProperty(b.__proto__, "0", {
+  set : function(v) {
+    b.x = v;
+    Object.defineProperty(b, "length", { writable : false });
+  },
+  get: function() {
+    return b.x;
+  }
+});
+
+b = [];
+try {
+  b.push(3, 4, 5);
+} catch(e) { }
+assertFalse(1 in b);
+assertFalse(2 in b);
+assertEquals(0, b.length);
+
+b = [];
+try {
+  b.unshift(3, 4, 5);
+} catch(e) { }
+assertFalse(1 in b);
+assertFalse(2 in b);
+assertEquals(0, b.length);
+
+b = [1, 2];
+try {
+  b.unshift(3, 4, 5);
+} catch(e) { }
+assertEquals(3, b[0]);
+assertEquals(4, b[1]);
+assertEquals(5, b[2]);
+assertEquals(1, b[3]);
+assertEquals(2, b[4]);
+assertEquals(5, b.length);
+
+b = [1, 2];
+
+Object.defineProperty(b.__proto__, "4", {
+  set : function(v) {
+    b.z = v;
+    Object.defineProperty(b, "length", { writable : false });
+  },
+  get: function() {
+    return b.z;
+  }
+});
+
+try {
+  b.unshift(3, 4, 5);
+} catch(e) { }
+
+assertFalse(2 in b);
+assertFalse(3 in b);
+assertEquals(2, b.length);
diff --git a/test/mjsunit/array-natives-elements.js b/test/mjsunit/array-natives-elements.js
index d63346d..a19a931 100644
--- a/test/mjsunit/array-natives-elements.js
+++ b/test/mjsunit/array-natives-elements.js
@@ -274,14 +274,11 @@
   assertEquals([1,1,2,3], a4);
   a4 = [1,2,3];
   a4.unshift(1.1);
-  // TODO(verwaest): We'll want to support double unshifting as well.
-  // assertTrue(%HasFastDoubleElements(a4));
-  assertTrue(%HasFastObjectElements(a4));
+  assertTrue(%HasFastDoubleElements(a4));
   assertEquals([1.1,1,2,3], a4);
   a4 = [1.1,2,3];
   a4.unshift(1);
-  // assertTrue(%HasFastDoubleElements(a4));
-  assertTrue(%HasFastObjectElements(a4));
+  assertTrue(%HasFastDoubleElements(a4));
   assertEquals([1,1.1,2,3], a4);
   a4 = [{},2,3];
   a4.unshift(1);
diff --git a/test/mjsunit/array-push-unshift-read-only-length.js b/test/mjsunit/array-push-unshift-read-only-length.js
deleted file mode 100644
index 67aa397..0000000
--- a/test/mjsunit/array-push-unshift-read-only-length.js
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Flags: --allow-natives-syntax
-
-function test(mode) {
-  var a = [];
-  Object.defineProperty(a, "length", { writable : false});
-
-  function check(f) {
-    try {
-      f(a);
-    } catch(e) { }
-    assertFalse(0 in a);
-    assertEquals(0, a.length);
-  }
-
-  function push(a) {
-    a.push(3);
-  }
-
-  if (mode == "fast properties") %ToFastProperties(a);
-
-  check(push);
-  check(push);
-  check(push);
-  %OptimizeFunctionOnNextCall(push);
-  check(push);
-
-  function unshift(a) {
-    a.unshift(3);
-  }
-
-  check(unshift);
-  check(unshift);
-  check(unshift);
-  %OptimizeFunctionOnNextCall(unshift);
-  check(unshift);
-}
-
-test("fast properties");
-
-test("normalized");
-
-var b = [];
-Object.defineProperty(b.__proto__, "0", {
-  set : function(v) {
-    b.x = v;
-    Object.defineProperty(b, "length", { writable : false });
-  },
-  get: function() {
-    return b.x;
-  }
-});
-
-b = [];
-try {
-  b.push(3, 4, 5);
-} catch(e) { }
-assertFalse(1 in b);
-assertFalse(2 in b);
-assertEquals(0, b.length);
-
-b = [];
-try {
-  b.unshift(3, 4, 5);
-} catch(e) { }
-assertFalse(1 in b);
-assertFalse(2 in b);
-assertEquals(0, b.length);
-
-b = [1, 2];
-try {
-  b.unshift(3, 4, 5);
-} catch(e) { }
-assertEquals(3, b[0]);
-assertEquals(4, b[1]);
-assertEquals(5, b[2]);
-assertEquals(1, b[3]);
-assertEquals(2, b[4]);
-assertEquals(5, b.length);
-
-b = [1, 2];
-
-Object.defineProperty(b.__proto__, "4", {
-  set : function(v) {
-    b.z = v;
-    Object.defineProperty(b, "length", { writable : false });
-  },
-  get: function() {
-    return b.z;
-  }
-});
-
-try {
-  b.unshift(3, 4, 5);
-} catch(e) { }
-
-// TODO(ulan): According to the ECMA-262 unshift should throw an exception
-// when moving b[0] to b[3] (see 15.4.4.13 step 6.d.ii). This is difficult
-// to do with our current implementation of SmartMove() in src/array.js and
-// it will regress performance. Uncomment the following line once acceptable
-// solution is found:
-// assertFalse(2 in b);
-// assertFalse(3 in b);
-// assertEquals(2, b.length);
diff --git a/test/mjsunit/array-reduce.js b/test/mjsunit/array-reduce.js
index 429f348..94e5144 100644
--- a/test/mjsunit/array-reduce.js
+++ b/test/mjsunit/array-reduce.js
@@ -521,3 +521,13 @@
             [3, 3, 2, [1, 2, 3, 4, 4, 5], 6],
             [6, 4, 3, [1, 2, 3, 4, 4, 5, 6], 10],
            ], arr, extender, 0);
+
+var arr = [];
+Object.defineProperty(arr, "0", { get: function() { delete this[0] },
+  configurable: true });
+assertEquals(undefined, arr.reduce(function(val) { return val }));
+
+var arr = [];
+Object.defineProperty(arr, "0", { get: function() { delete this[0] },
+  configurable: true});
+assertEquals(undefined, arr.reduceRight(function(val) { return val }));
diff --git a/test/mjsunit/array-shift2.js b/test/mjsunit/array-shift2.js
index 73d8cd4..75233ff 100644
--- a/test/mjsunit/array-shift2.js
+++ b/test/mjsunit/array-shift2.js
@@ -12,7 +12,17 @@
   array.shift();
   return array;
 }
-assertEquals(["element 1",2], test(["0",,2]));
-assertEquals(["element 1",{}], test([{},,{}]));
+
+var result = test(["0",,2]);
+assertEquals(["element 1","element 1"], result);
+assertTrue(result.hasOwnProperty("0"));
+assertFalse(result.hasOwnProperty("1"));
+result = test([{},,{}]);
+assertEquals(["element 1","element 1"], result);
+assertTrue(result.hasOwnProperty("0"));
+assertFalse(result.hasOwnProperty("1"));
 %OptimizeFunctionOnNextCall(test);
-assertEquals(["element 1",0], test([{},,0]));
+result = test([{},,0]);
+assertEquals(["element 1","element 1"], result);
+assertTrue(result.hasOwnProperty("0"));
+assertFalse(result.hasOwnProperty("1"));
diff --git a/test/mjsunit/array-shift4.js b/test/mjsunit/array-shift4.js
new file mode 100644
index 0000000..669b11a
--- /dev/null
+++ b/test/mjsunit/array-shift4.js
@@ -0,0 +1,24 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+// Inlining shift with holey smi arrays shouldn't deopt just because it
+// encounters the hole on the copy step.
+function doShift(a) {
+  var x = a.shift();
+  return x;
+}
+
+function makeArray() {
+  var a = [1, 2,, 3];
+  a[0] = 2;
+  return a;
+}
+
+doShift(makeArray());
+doShift(makeArray());
+%OptimizeFunctionOnNextCall(doShift);
+doShift(makeArray());
+assertOptimized(doShift);
diff --git a/test/mjsunit/array-unshift.js b/test/mjsunit/array-unshift.js
index 0eb299a..50aab4f 100644
--- a/test/mjsunit/array-unshift.js
+++ b/test/mjsunit/array-unshift.js
@@ -37,9 +37,7 @@
 })();
 
 
-// Check that unshift with no args has a side-effect of
-// filling the holes with elements from the prototype
-// (if present, of course)
+// Check that unshift with no args has no side-effects.
 (function() {
   var len = 3;
   var array = new Array(len);
@@ -65,15 +63,15 @@
   assertTrue(delete Array.prototype[0]);
   assertTrue(delete Array.prototype[2]);
 
-  // unshift makes array own 0 and 2...
-  assertTrue(array.hasOwnProperty(0));
+  // array still owns nothing...
+  assertFalse(array.hasOwnProperty(0));
   assertFalse(array.hasOwnProperty(1));
-  assertTrue(array.hasOwnProperty(2));
+  assertFalse(array.hasOwnProperty(2));
 
   // ... so they are not affected be delete.
-  assertEquals(array[0], at0);
+  assertEquals(array[0], undefined);
   assertEquals(array[1], undefined);
-  assertEquals(array[2], at2);
+  assertEquals(array[2], undefined);
 })();
 
 
@@ -115,9 +113,7 @@
   assertTrue(delete Array.prototype[7]);
 })();
 
-// Check that unshift with no args has a side-effect of
-// filling the holes with elements from the prototype
-// (if present, of course)
+// Check that unshift with no args has no side-effects.
 (function() {
   var len = 3;
   var array = new Array(len);
@@ -142,12 +138,12 @@
 
   assertEquals(len, array.unshift());
 
-  // unshift makes array own 0 and 2...
-  assertTrue(array.hasOwnProperty(0));
+  // array still owns nothing.
+  assertFalse(array.hasOwnProperty(0));
   assertFalse(array.hasOwnProperty(1));
-  assertTrue(array.hasOwnProperty(2));
+  assertFalse(array.hasOwnProperty(2));
 
-  // ... so they are not affected be delete.
+  // ... but still sees values from array_proto.
   assertEquals(array[0], at0);
   assertEquals(array[1], undefined);
   assertEquals(array[2], at2);
diff --git a/test/mjsunit/asm/do-while-false.js b/test/mjsunit/asm/do-while-false.js
new file mode 100644
index 0000000..ba906a0
--- /dev/null
+++ b/test/mjsunit/asm/do-while-false.js
@@ -0,0 +1,78 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module() {
+  "use asm";
+
+  function d0() {
+    do { } while(false);
+    return 110;
+  }
+
+  function d1() {
+    do { return 111; } while(false);
+    return 112;
+  }
+
+  function d2() {
+    do { break; } while(false);
+    return 113;
+  }
+
+  function d3(a) {
+    a = a | 0;
+    do { if (a) return 114; } while(false);
+    return 115;
+  }
+
+  function d4(a) {
+    a = a | 0;
+    do { if (a) return 116; else break; } while(false);
+    return 117;
+  }
+
+  function d5(a) {
+    a = a | 0;
+    do { if (a) return 118; } while(false);
+    return 119;
+  }
+
+  function d6(a) {
+    a = a | 0;
+    do {
+      if (a == 0) return 120;
+      if (a == 1) break;
+      if (a == 2) return 122;
+      if (a == 3) continue;
+      if (a == 4) return 124;
+    } while(false);
+    return 125;
+  }
+
+  return {d0: d0, d1: d1, d2: d2, d3: d3, d4: d4, d5: d5, d6: d6};
+}
+
+var m = Module();
+
+assertEquals(110, m.d0());
+
+assertEquals(111, m.d1());
+
+assertEquals(113, m.d2());
+
+assertEquals(114, m.d3(1));
+assertEquals(115, m.d3(0));
+
+assertEquals(116, m.d4(1));
+assertEquals(117, m.d4(0));
+
+assertEquals(118, m.d5(1));
+assertEquals(119, m.d5(0));
+
+assertEquals(120, m.d6(0));
+assertEquals(125, m.d6(1));
+assertEquals(122, m.d6(2));
+assertEquals(125, m.d6(3));
+assertEquals(124, m.d6(4));
+assertEquals(125, m.d6(5));
diff --git a/test/mjsunit/asm/do-while.js b/test/mjsunit/asm/do-while.js
new file mode 100644
index 0000000..214be64
--- /dev/null
+++ b/test/mjsunit/asm/do-while.js
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, buffer) {
+  "use asm";
+  function f(i) {
+    var j;
+    i = i|0;
+    do {
+      if (i > 0) {
+        j = i != 0;
+        i = (i - 1) | 0;
+      } else {
+        j = 0;
+      }
+    } while (j);
+    return i;
+  }
+  return {f:f};
+}
+
+var m = Module(this, {}, new ArrayBuffer(64*1024));
+
+assertEquals(-1, m.f("-1"));
+assertEquals(0, m.f(-Math.infinity));
+assertEquals(0, m.f(undefined));
+assertEquals(0, m.f(0));
+assertEquals(0, m.f(1));
+assertEquals(0, m.f(100));
diff --git a/test/mjsunit/asm/embenchen/box2d.js b/test/mjsunit/asm/embenchen/box2d.js
new file mode 100644
index 0000000..9bb029e
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/box2d.js
@@ -0,0 +1,20322 @@
+var EXPECTED_OUTPUT =
+  /frame averages: .+ \+- .+, range: .+ to .+ \n/;
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertTrue(EXPECTED_OUTPUT.test(Module.printBuffer));
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+var __ZTVN10__cxxabiv117__class_type_infoE = 7024;
+var __ZTVN10__cxxabiv120__si_class_type_infoE = 7064;
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(7731);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232,118,72,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,114,114,111,114,58,32,37,100,92,110,0,0,0,0,0,102,114,97,109,101,32,97,118,101,114,97,103,101,115,58,32,37,46,51,102,32,43,45,32,37,46,51,102,44,32,114,97,110,103,101,58,32,37,46,51,102,32,116,111,32,37,46,51,102,32,10,0,0,0,0,0,105,102,32,40,77,111,100,117,108,101,46,114,101,112,111,114,116,67,111,109,112,108,101,116,105,111,110,41,32,77,111,100,117,108,101,46,114,101,112,111,114,116,67,111,109,112,108,101,116,105,111,110,40,41,0,0,114,101,115,112,111,110,115,105,118,101,32,109,97,105,110,32,108,111,111,112,0,0,0,0,0,0,0,0,56,1,0,0,1,0,0,0,2,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,49,49,98,50,69,100,103,101,83,104,97,112,101,0,0,0,55,98,50,83,104,97,112,101,0,0,0,0,0,0,0,0,120,27,0,0,32,1,0,0,160,27,0,0,16,1,0,0,48,1,0,0,0,0,0,0,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,83,104,97,112,101,115,47,98,50,80,111,108,121,103,111,110,83,104,97,112,101,46,99,112,112,0,0,0,0,0,0,0,48,46,48,102,32,60,61,32,108,111,119,101,114,32,38,38,32,108,111,119,101,114,32,60,61,32,105,110,112,117,116,46,109,97,120,70,114,97,99,116,105,111,110,0,0,0,0,0,82,97,121,67,97,115,116,0,109,95,118,101,114,116,101,120,67,111,117,110,116,32,62,61,32,51,0,0,0,0,0,0,67,111,109,112,117,116,101,77,97,115,115,0,0,0,0,0,97,114,101,97,32,62,32,49,46,49,57,50,48,57,50,57,48,101,45,48,55,70,0,0,0,0,0,0,48,2,0,0,3,0,0,0,4,0,0,0,2,0,0,0,2,0,0,0,2,0,0,0,2,0,0,0,2,0,0,0,2,0,0,0,49,52,98,50,80,111,108,121,103,111,110,83,104,97,112,101,0,0,0,0,0,0,0,0,160,27,0,0,24,2,0,0,48,1,0,0,0,0,0,0,16,0,0,0,32,0,0,0,64,0,0,0,96,0,0,0,128,0,0,0,160,0,0,0,192,0,0,0,224,0,0,0,0,1,0,0,64,1,0,0,128,1,0,0,192,1,0,0,0,2,0,0,128,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,106,32,60,32,98,50,95,98,108,111,99,107,83,105,122,101,115,0,0,0,0,0,0,0,66,111,120,50,68,47,67,111,109,109,111,110,47,98,50,66,108,111,99,107,65,108,108,111,99,97,116,111,114,46,99,112,112,0,0,0,0,0,0,0,98,50,66,108,111,99,107,65,108,108,111,99,97,116,111,114,0,0,0,0,0,0,0,0,48,32,60,32,115,105,122,101,0,0,0,0,0,0,0,0,65,108,108,111,99,97,116,101,0,0,0,0,0,0,0,0,48,32,60,61,32,105,110,100,101,120,32,38,38,32,105,110,100,101,120,32,60,32,98,50,95,98,108,111,99,107,83,105,122,101,115,0,0,0,0,0,98,108,111,99,107,67,111,117,110,116,32,42,32,98,108,111,99,107,83,105,122,101,32,60,61,32,98,50,95,99,104,117,110,107,83,105,122,101,0,0,70,114,101,101,0,0,0,0,98,100,45,62,112,111,115,105,116,105,111,110,46,73,115,86,97,108,105,100,40,41,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,98,50,66,111,100,121,46,99,112,112,0,0,0,0,0,0,0,98,50,66,111,100,121,0,0,98,100,45,62,108,105,110,101,97,114,86,101,108,111,99,105,116,121,46,73,115,86,97,108,105,100,40,41,0,0,0,0,98,50,73,115,86,97,108,105,100,40,98,100,45,62,97,110,103,108,101,41,0,0,0,0,98,50,73,115,86,97,108,105,100,40,98,100,45,62,97,110,103,117,108,97,114,86,101,108,111,99,105,116,121,41,0,0,98,50,73,115,86,97,108,105,100,40,98,100,45,62,97,110,103,117,108,97,114,68,97,109,112,105,110,103,41,32,38,38,32,98,100,45,62,97,110,103,117,108,97,114,68,97,109,112,105,110,103,32,62,61,32,48,46,48,102,0,0,0,0,0,98,50,73,115,86,97,108,105,100,40,98,100,45,62,108,105,110,101,97,114,68,97,109,112,105,110,103,41,32,38,38,32,98,100,45,62,108,105,110,101,97,114,68,97,109,112,105,110,103,32,62,61,32,48,46,48,102,0,0,0,0,0,0,0,109,95,119,111,114,108,100,45,62,73,115,76,111,99,107,101,100,40,41,32,61,61,32,102,97,108,115,101,0,0,0,0,67,114,101,97,116,101,70,105,120,116,117,114,101,0,0,0,109,95,116,121,112,101,32,61,61,32,98,50,95,100,121,110,97,109,105,99,66,111,100,121,0,0,0,0,0,0,0,0,82,101,115,101,116,77,97,115,115,68,97,116,97,0,0,0,109,95,73,32,62,32,48,46,48,102,0,0,0,0,0,0,0,10,0,0,0,0,0,0,240,7,0,0,0,0,0,0,48,32,60,61,32,112,114,111,120,121,73,100,32,38,38,32,112,114,111,120,121,73,100,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,0,0,0,0,0,0,46,47,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,68,121,110,97,109,105,99,84,114,101,101,46,104,0,0,0,0,0,0,0,71,101,116,85,115,101,114,68,97,116,97,0,0,0,0,0,71,101,116,70,97,116,65,65,66,66,0,0,0,0,0,0,0,0,0,0,32,8,0,0,5,0,0,0,6,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,49,55,98,50,67,111,110,116,97,99,116,76,105,115,116,101,110,101,114,0,0,0,0,0,120,27,0,0,8,8,0,0,109,95,112,114,111,120,121,67,111,117,110,116,32,61,61,32,48,0,0,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,98,50,70,105,120,116,117,114,101,46,99,112,112,0,0,0,0,67,114,101,97,116,101,80,114,111,120,105,101,115,0,0,0,73,115,76,111,99,107,101,100,40,41,32,61,61,32,102,97,108,115,101,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,98,50,87,111,114,108,100,46,99,112,112,0,0,0,0,0,0,67,114,101,97,116,101,66,111,100,121,0,0,0,0,0,0,98,45,62,73,115,65,99,116,105,118,101,40,41,32,61,61,32,116,114,117,101,0,0,0,83,111,108,118,101,0,0,0,115,116,97,99,107,67,111,117,110,116,32,60,32,115,116,97,99,107,83,105,122,101,0,0,116,121,112,101,65,32,61,61,32,98,50,95,100,121,110,97,109,105,99,66,111,100,121,32,124,124,32,116,121,112,101,66,32,61,61,32,98,50,95,100,121,110,97,109,105,99,66,111,100,121,0,0,0,0,0,0,83,111,108,118,101,84,79,73,0,0,0,0,0,0,0,0,97,108,112,104,97,48,32,60,32,49,46,48,102,0,0,0,46,47,66,111,120,50,68,47,67,111,109,109,111,110,47,98,50,77,97,116,104,46,104,0,65,100,118,97,110,99,101,0,109,95,106,111,105,110,116,67,111,117,110,116,32,60,32,109,95,106,111,105,110,116,67,97,112,97,99,105,116,121,0,0,46,47,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,98,50,73,115,108,97,110,100,46,104,0,0,0,0,0,65,100,100,0,0,0,0,0,109,95,99,111,110,116,97,99,116,67,111,117,110,116,32,60,32,109,95,99,111,110,116,97,99,116,67,97,112,97,99,105,116,121,0,0,0,0,0,0,109,95,98,111,100,121,67,111,117,110,116,32,60,32,109,95,98,111,100,121,67,97,112,97,99,105,116,121,0,0,0,0,0,0,0,0,40,10,0,0,7,0,0,0,8,0,0,0,3,0,0,0,0,0,0,0,49,53,98,50,67,111,110,116,97,99,116,70,105,108,116,101,114,0,0,0,0,0,0,0,120,27,0,0,16,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,32,60,61,32,105,110,100,101,120,32,38,38,32,105,110,100,101,120,32,60,32,99,104,97,105,110,45,62,109,95,99,111,117,110,116,0,0,0,0,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,68,105,115,116,97,110,99,101,46,99,112,112,0,0,83,101,116,0,0,0,0,0,102,97,108,115,101,0,0,0,98,50,68,105,115,116,97,110,99,101,0,0,0,0,0,0,71,101,116,77,101,116,114,105,99,0,0,0,0,0,0,0,71,101,116,87,105,116,110,101,115,115,80,111,105,110,116,115,0,0,0,0,0,0,0,0,48,32,60,61,32,105,110,100,101,120,32,38,38,32,105,110,100,101,120,32,60,32,109,95,99,111,117,110,116,0,0,0,46,47,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,68,105,115,116,97,110,99,101,46,104,0,0,71,101,116,86,101,114,116,101,120,0,0,0,0,0,0,0,71,101,116,67,108,111,115,101,115,116,80,111,105,110,116,0,99,97,99,104,101,45,62,99,111,117,110,116,32,60,61,32,51,0,0,0,0,0,0,0,82,101,97,100,67,97,99,104,101,0,0,0,0,0,0,0,109,95,110,111,100,101,67,111,117,110,116,32,61,61,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,0,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,68,121,110,97,109,105,99,84,114,101,101,46,99,112,112,0,0,0,0,0,0,0,65,108,108,111,99,97,116,101,78,111,100,101,0,0,0,0,48,32,60,61,32,110,111,100,101,73,100,32,38,38,32,110,111,100,101,73,100,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,70,114,101,101,78,111,100,101,0,0,0,0,0,0,0,0,48,32,60,32,109,95,110,111,100,101,67,111,117,110,116,0,48,32,60,61,32,112,114,111,120,121,73,100,32,38,38,32,112,114,111,120,121,73,100,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,0,0,0,0,0,0,109,95,110,111,100,101,115,91,112,114,111,120,121,73,100,93,46,73,115,76,101,97,102,40,41,0,0,0,0,0,0,0,77,111,118,101,80,114,111,120,121,0,0,0,0,0,0,0,99,104,105,108,100,49,32,33,61,32,40,45,49,41,0,0,73,110,115,101,114,116,76,101,97,102,0,0,0,0,0,0,99,104,105,108,100,50,32,33,61,32,40,45,49,41,0,0,105,65,32,33,61,32,40,45,49,41,0,0,0,0,0,0,66,97,108,97,110,99,101,0,48,32,60,61,32,105,66,32,38,38,32,105,66,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,48,32,60,61,32,105,67,32,38,38,32,105,67,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,48,32,60,61,32,105,70,32,38,38,32,105,70,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,48,32,60,61,32,105,71,32,38,38,32,105,71,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,109,95,110,111,100,101,115,91,67,45,62,112,97,114,101,110,116,93,46,99,104,105,108,100,50,32,61,61,32,105,65,0,48,32,60,61,32,105,68,32,38,38,32,105,68,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,48,32,60,61,32,105,69,32,38,38,32,105,69,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,109,95,110,111,100,101,115,91,66,45,62,112,97,114,101,110,116,93,46,99,104,105,108,100,50,32,61,61,32,105,65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,116,97,114,103,101,116,32,62,32,116,111,108,101,114,97,110,99,101,0,0,0,0,0,0,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,84,105,109,101,79,102,73,109,112,97,99,116,46,99,112,112,0,0,0,0,0,0,98,50,84,105,109,101,79,102,73,109,112,97,99,116,0,0,102,97,108,115,101,0,0,0,69,118,97,108,117,97,116,101,0,0,0,0,0,0,0,0,48,32,60,61,32,105,110,100,101,120,32,38,38,32,105,110,100,101,120,32,60,32,109,95,99,111,117,110,116,0,0,0,46,47,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,68,105,115,116,97,110,99,101,46,104,0,0,71,101,116,86,101,114,116,101,120,0,0,0,0,0,0,0,70,105,110,100,77,105,110,83,101,112,97,114,97,116,105,111,110,0,0,0,0,0,0,0,48,32,60,32,99,111,117,110,116,32,38,38,32,99,111,117,110,116,32,60,32,51,0,0,73,110,105,116,105,97,108,105,122,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,109,95,105,110,100,101,120,32,61,61,32,48,0,0,0,0,66,111,120,50,68,47,67,111,109,109,111,110,47,98,50,83,116,97,99,107,65,108,108,111,99,97,116,111,114,46,99,112,112,0,0,0,0,0,0,0,126,98,50,83,116,97,99,107,65,108,108,111,99,97,116,111,114,0,0,0,0,0,0,0,109,95,101,110,116,114,121,67,111,117,110,116,32,61,61,32,48,0,0,0,0,0,0,0,109,95,101,110,116,114,121,67,111,117,110,116,32,60,32,98,50,95,109,97,120,83,116,97,99,107,69,110,116,114,105,101,115,0,0,0,0,0,0,0,65,108,108,111,99,97,116,101,0,0,0,0,0,0,0,0,109,95,101,110,116,114,121,67,111,117,110,116,32,62,32,48,0,0,0,0,0,0,0,0,70,114,101,101,0,0,0,0,112,32,61,61,32,101,110,116,114,121,45,62,100,97,116,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,32,60,61,32,116,121,112,101,49,32,38,38,32,116,121,112,101,49,32,60,32,98,50,83,104,97,112,101,58,58,101,95,116,121,112,101,67,111,117,110,116,0,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,67,111,110,116,97,99,116,46,99,112,112,0,0,0,48,32,60,61,32,116,121,112,101,50,32,38,38,32,116,121,112,101,50,32,60,32,98,50,83,104,97,112,101,58,58,101,95,116,121,112,101,67,111,117,110,116,0,0,0,0,0,0,67,114,101,97,116,101,0,0,115,95,105,110,105,116,105,97,108,105,122,101,100,32,61,61,32,116,114,117,101,0,0,0,68,101,115,116,114,111,121,0,48,32,60,61,32,116,121,112,101,65,32,38,38,32,116,121,112,101,66,32,60,32,98,50,83,104,97,112,101,58,58,101,95,116,121,112,101,67,111,117,110,116,0,0,0,0,0,0,0,0,0,0,120,17,0,0,1,0,0,0,9,0,0,0,10,0,0,0,0,0,0,0,57,98,50,67,111,110,116,97,99,116,0,0,0,0,0,0,120,27,0,0,104,17,0,0,0,0,0,0,104,18,0,0,3,0,0,0,11,0,0,0,12,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,65,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,101,100,103,101,0,0,0,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,69,100,103,101,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,46,99,112,112,0,0,0,0,0,0,98,50,69,100,103,101,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,0,0,109,95,102,105,120,116,117,114,101,66,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,99,105,114,99,108,101,0,0,0,0,0,0,50,50,98,50,69,100,103,101,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,0,0,0,0,0,0,0,0,160,27,0,0,72,18,0,0,120,17,0,0,0,0,0,0,0,0,0,0,96,19,0,0,4,0,0,0,13,0,0,0,14,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,65,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,101,100,103,101,0,0,0,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,69,100,103,101,65,110,100,80,111,108,121,103,111,110,67,111,110,116,97,99,116,46,99,112,112,0,0,0,0,0,98,50,69,100,103,101,65,110,100,80,111,108,121,103,111,110,67,111,110,116,97,99,116,0,109,95,102,105,120,116,117,114,101,66,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,112,111,108,121,103,111,110,0,0,0,0,0,50,51,98,50,69,100,103,101,65,110,100,80,111,108,121,103,111,110,67,111,110,116,97,99,116,0,0,0,0,0,0,0,160,27,0,0,64,19,0,0,120,17,0,0,0,0,0,0,0,0,0,0,96,20,0,0,5,0,0,0,15,0,0,0,16,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,65,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,112,111,108,121,103,111,110,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,80,111,108,121,103,111,110,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,46,99,112,112,0,0,0,98,50,80,111,108,121,103,111,110,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,66,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,99,105,114,99,108,101,0,0,0,0,0,0,50,53,98,50,80,111,108,121,103,111,110,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,0,0,0,0,0,160,27,0,0,64,20,0,0,120,17,0,0,0,0,0,0,0,0,0,0,72,21,0,0,6,0,0,0,17,0,0,0,18,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,65,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,112,111,108,121,103,111,110,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,80,111,108,121,103,111,110,67,111,110,116,97,99,116,46,99,112,112,0,0,0,0,98,50,80,111,108,121,103,111,110,67,111,110,116,97,99,116,0,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,66,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,112,111,108,121,103,111,110,0,0,0,0,0,49,54,98,50,80,111,108,121,103,111,110,67,111,110,116,97,99,116,0,0,0,0,0,0,160,27,0,0,48,21,0,0,120,17,0,0,0,0,0,0,116,111,105,73,110,100,101,120,65,32,60,32,109,95,98,111,100,121,67,111,117,110,116,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,98,50,73,115,108,97,110,100,46,99,112,112,0,0,0,0,0,83,111,108,118,101,84,79,73,0,0,0,0,0,0,0,0,116,111,105,73,110,100,101,120,66,32,60,32,109,95,98,111,100,121,67,111,117,110,116,0,100,101,110,32,62,32,48,46,48,102,0,0,0,0,0,0,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,67,111,108,108,105,100,101,69,100,103,101,46,99,112,112,0,0,0,0,0,0,0,98,50,67,111,108,108,105,100,101,69,100,103,101,65,110,100,67,105,114,99,108,101,0,0,48,32,60,61,32,101,100,103,101,49,32,38,38,32,101,100,103,101,49,32,60,32,112,111,108,121,49,45,62,109,95,118,101,114,116,101,120,67,111,117,110,116,0,0,0,0,0,0,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,67,111,108,108,105,100,101,80,111,108,121,103,111,110,46,99,112,112,0,0,0,0,98,50,70,105,110,100,73,110,99,105,100,101,110,116,69,100,103,101,0,0,0,0,0,0,98,50,69,100,103,101,83,101,112,97,114,97,116,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,120,23,0,0,7,0,0,0,19,0,0,0,20,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,65,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,99,104,97,105,110,0,0,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,67,104,97,105,110,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,46,99,112,112,0,0,0,0,0,98,50,67,104,97,105,110,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,0,109,95,102,105,120,116,117,114,101,66,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,99,105,114,99,108,101,0,0,0,0,0,0,50,51,98,50,67,104,97,105,110,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,0,0,0,0,0,0,0,160,27,0,0,88,23,0,0,120,17,0,0,0,0,0,0,0,0,0,0,120,24,0,0,8,0,0,0,21,0,0,0,22,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,65,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,99,104,97,105,110,0,0,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,67,104,97,105,110,65,110,100,80,111,108,121,103,111,110,67,111,110,116,97,99,116,46,99,112,112,0,0,0,0,98,50,67,104,97,105,110,65,110,100,80,111,108,121,103,111,110,67,111,110,116,97,99,116,0,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,66,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,112,111,108,121,103,111,110,0,0,0,0,0,50,52,98,50,67,104,97,105,110,65,110,100,80,111,108,121,103,111,110,67,111,110,116,97,99,116,0,0,0,0,0,0,160,27,0,0,88,24,0,0,120,17,0,0,0,0,0,0,0,0,0,0,88,25,0,0,9,0,0,0,23,0,0,0,24,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,65,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,99,105,114,99,108,101,0,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,67,105,114,99,108,101,67,111,110,116,97,99,116,46,99,112,112,0,0,0,0,0,98,50,67,105,114,99,108,101,67,111,110,116,97,99,116,0,109,95,102,105,120,116,117,114,101,66,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,99,105,114,99,108,101,0,0,0,0,0,0,49,53,98,50,67,105,114,99,108,101,67,111,110,116,97,99,116,0,0,0,0,0,0,0,160,27,0,0,64,25,0,0,120,17,0,0,0,0,0,0,112,111,105,110,116,67,111,117,110,116,32,62,32,48,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,67,111,110,116,97,99,116,83,111,108,118,101,114,46,99,112,112,0,0,0,0,0,98,50,67,111,110,116,97,99,116,83,111,108,118,101,114,0,109,97,110,105,102,111,108,100,45,62,112,111,105,110,116,67,111,117,110,116,32,62,32,48,0,0,0,0,0,0,0,0,73,110,105,116,105,97,108,105,122,101,86,101,108,111,99,105,116,121,67,111,110,115,116,114,97,105,110,116,115,0,0,0,112,111,105,110,116,67,111,117,110,116,32,61,61,32,49,32,124,124,32,112,111,105,110,116,67,111,117,110,116,32,61,61,32,50,0,0,0,0,0,0,83,111,108,118,101,86,101,108,111,99,105,116,121,67,111,110,115,116,114,97,105,110,116,115,0,0,0,0,0,0,0,0,97,46,120,32,62,61,32,48,46,48,102,32,38,38,32,97,46,121,32,62,61,32,48,46,48,102,0,0,0,0,0,0,112,99,45,62,112,111,105,110,116,67,111,117,110,116,32,62,32,48,0,0,0,0,0,0,73,110,105,116,105,97,108,105,122,101,0,0,0,0,0,0,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,83,104,97,112,101,115,47,98,50,67,104,97,105,110,83,104,97,112,101,46,99,112,112,0,48,32,60,61,32,105,110,100,101,120,32,38,38,32,105,110,100,101,120,32,60,32,109,95,99,111,117,110,116,32,45,32,49,0,0,0,0,0,0,0,71,101,116,67,104,105,108,100,69,100,103,101,0,0,0,0,83,116,57,116,121,112,101,95,105,110,102,111,0,0,0,0,120,27,0,0,232,26,0,0,78,49,48,95,95,99,120,120,97,98,105,118,49,49,54,95,95,115,104,105,109,95,116,121,112,101,95,105,110,102,111,69,0,0,0,0,0,0,0,0,160,27,0,0,0,27,0,0,248,26,0,0,0,0,0,0,78,49,48,95,95,99,120,120,97,98,105,118,49,49,55,95,95,99,108,97,115,115,95,116,121,112,101,95,105,110,102,111,69,0,0,0,0,0,0,0,160,27,0,0,56,27,0,0,40,27,0,0,0,0,0,0,0,0,0,0,96,27,0,0,25,0,0,0,26,0,0,0,27,0,0,0,28,0,0,0,4,0,0,0,1,0,0,0,1,0,0,0,10,0,0,0,0,0,0,0,232,27,0,0,25,0,0,0,29,0,0,0,27,0,0,0,28,0,0,0,4,0,0,0,2,0,0,0,2,0,0,0,11,0,0,0,78,49,48,95,95,99,120,120,97,98,105,118,49,50,48,95,95,115,105,95,99,108,97,115,115,95,116,121,112,101,95,105,110,102,111,69,0,0,0,0,160,27,0,0,192,27,0,0,96,27,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,30,0,0,30,0,0,0,31,0,0,0,3,0,0,0,0,0,0,0,115,116,100,58,58,98,97,100,95,97,108,108,111,99,0,0,83,116,57,98,97,100,95,97,108,108,111,99,0,0,0,0,160,27,0,0,24,30,0,0,0,0,0,0,0,0,0,0], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+  function _emscripten_set_main_loop(func, fps, simulateInfiniteLoop, arg) {
+      Module['noExitRuntime'] = true;
+
+      Browser.mainLoop.runner = function Browser_mainLoop_runner() {
+        if (ABORT) return;
+        if (Browser.mainLoop.queue.length > 0) {
+          var start = Date.now();
+          var blocker = Browser.mainLoop.queue.shift();
+          blocker.func(blocker.arg);
+          if (Browser.mainLoop.remainingBlockers) {
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var next = remaining%1 == 0 ? remaining-1 : Math.floor(remaining);
+            if (blocker.counted) {
+              Browser.mainLoop.remainingBlockers = next;
+            } else {
+              // not counted, but move the progress along a tiny bit
+              next = next + 0.5; // do not steal all the next one's progress
+              Browser.mainLoop.remainingBlockers = (8*remaining + next)/9;
+            }
+          }
+          console.log('main loop blocker "' + blocker.name + '" took ' + (Date.now() - start) + ' ms'); //, left: ' + Browser.mainLoop.remainingBlockers);
+          Browser.mainLoop.updateStatus();
+          setTimeout(Browser.mainLoop.runner, 0);
+          return;
+        }
+        if (Browser.mainLoop.shouldPause) {
+          // catch pauses from non-main loop sources
+          Browser.mainLoop.paused = true;
+          Browser.mainLoop.shouldPause = false;
+          return;
+        }
+
+        // Signal GL rendering layer that processing of a new frame is about to start. This helps it optimize
+        // VBO double-buffering and reduce GPU stalls.
+
+        if (Browser.mainLoop.method === 'timeout' && Module.ctx) {
+          Module.printErr('Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!');
+          Browser.mainLoop.method = ''; // just warn once per call to set main loop
+        }
+
+        if (Module['preMainLoop']) {
+          Module['preMainLoop']();
+        }
+
+        try {
+          if (typeof arg !== 'undefined') {
+            Runtime.dynCall('vi', func, [arg]);
+          } else {
+            Runtime.dynCall('v', func);
+          }
+        } catch (e) {
+          if (e instanceof ExitStatus) {
+            return;
+          } else {
+            if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+            throw e;
+          }
+        }
+
+        if (Module['postMainLoop']) {
+          Module['postMainLoop']();
+        }
+
+        if (Browser.mainLoop.shouldPause) {
+          // catch pauses from the main loop itself
+          Browser.mainLoop.paused = true;
+          Browser.mainLoop.shouldPause = false;
+          return;
+        }
+        Browser.mainLoop.scheduler();
+      }
+      if (fps && fps > 0) {
+        Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler() {
+          setTimeout(Browser.mainLoop.runner, 1000/fps); // doing this each time means that on exception, we stop
+        };
+        Browser.mainLoop.method = 'timeout';
+      } else {
+        Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler() {
+          Browser.requestAnimationFrame(Browser.mainLoop.runner);
+        };
+        Browser.mainLoop.method = 'rAF';
+      }
+      Browser.mainLoop.scheduler();
+
+      if (simulateInfiniteLoop) {
+        throw 'SimulateInfiniteLoop';
+      }
+    }
+
+  var _cosf=Math_cos;
+
+  function ___cxa_pure_virtual() {
+      ABORT = true;
+      throw 'Pure virtual function called!';
+    }
+
+  function _time(ptr) {
+      var ret = Math.floor(Date.now()/1000);
+      if (ptr) {
+        HEAP32[((ptr)>>2)]=ret;
+      }
+      return ret;
+    }
+
+  function ___assert_fail(condition, filename, line, func) {
+      ABORT = true;
+      throw 'Assertion failed: ' + Pointer_stringify(condition) + ', at: ' + [filename ? Pointer_stringify(filename) : 'unknown filename', line, func ? Pointer_stringify(func) : 'unknown function'] + ' at ' + stackTrace();
+    }
+
+
+  function __ZSt18uncaught_exceptionv() { // std::uncaught_exception()
+      return !!__ZSt18uncaught_exceptionv.uncaught_exception;
+    }
+
+
+
+  function ___cxa_is_number_type(type) {
+      var isNumber = false;
+      try { if (type == __ZTIi) isNumber = true } catch(e){}
+      try { if (type == __ZTIj) isNumber = true } catch(e){}
+      try { if (type == __ZTIl) isNumber = true } catch(e){}
+      try { if (type == __ZTIm) isNumber = true } catch(e){}
+      try { if (type == __ZTIx) isNumber = true } catch(e){}
+      try { if (type == __ZTIy) isNumber = true } catch(e){}
+      try { if (type == __ZTIf) isNumber = true } catch(e){}
+      try { if (type == __ZTId) isNumber = true } catch(e){}
+      try { if (type == __ZTIe) isNumber = true } catch(e){}
+      try { if (type == __ZTIc) isNumber = true } catch(e){}
+      try { if (type == __ZTIa) isNumber = true } catch(e){}
+      try { if (type == __ZTIh) isNumber = true } catch(e){}
+      try { if (type == __ZTIs) isNumber = true } catch(e){}
+      try { if (type == __ZTIt) isNumber = true } catch(e){}
+      return isNumber;
+    }function ___cxa_does_inherit(definiteType, possibilityType, possibility) {
+      if (possibility == 0) return false;
+      if (possibilityType == 0 || possibilityType == definiteType)
+        return true;
+      var possibility_type_info;
+      if (___cxa_is_number_type(possibilityType)) {
+        possibility_type_info = possibilityType;
+      } else {
+        var possibility_type_infoAddr = HEAP32[((possibilityType)>>2)] - 8;
+        possibility_type_info = HEAP32[((possibility_type_infoAddr)>>2)];
+      }
+      switch (possibility_type_info) {
+      case 0: // possibility is a pointer
+        // See if definite type is a pointer
+        var definite_type_infoAddr = HEAP32[((definiteType)>>2)] - 8;
+        var definite_type_info = HEAP32[((definite_type_infoAddr)>>2)];
+        if (definite_type_info == 0) {
+          // Also a pointer; compare base types of pointers
+          var defPointerBaseAddr = definiteType+8;
+          var defPointerBaseType = HEAP32[((defPointerBaseAddr)>>2)];
+          var possPointerBaseAddr = possibilityType+8;
+          var possPointerBaseType = HEAP32[((possPointerBaseAddr)>>2)];
+          return ___cxa_does_inherit(defPointerBaseType, possPointerBaseType, possibility);
+        } else
+          return false; // one pointer and one non-pointer
+      case 1: // class with no base class
+        return false;
+      case 2: // class with base class
+        var parentTypeAddr = possibilityType + 8;
+        var parentType = HEAP32[((parentTypeAddr)>>2)];
+        return ___cxa_does_inherit(definiteType, parentType, possibility);
+      default:
+        return false; // some unencountered type
+      }
+    }
+
+
+
+  var ___cxa_last_thrown_exception=0;function ___resumeException(ptr) {
+      if (!___cxa_last_thrown_exception) { ___cxa_last_thrown_exception = ptr; }
+      throw ptr + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";
+    }
+
+  var ___cxa_exception_header_size=8;function ___cxa_find_matching_catch(thrown, throwntype) {
+      if (thrown == -1) thrown = ___cxa_last_thrown_exception;
+      header = thrown - ___cxa_exception_header_size;
+      if (throwntype == -1) throwntype = HEAP32[((header)>>2)];
+      var typeArray = Array.prototype.slice.call(arguments, 2);
+
+      // If throwntype is a pointer, this means a pointer has been
+      // thrown. When a pointer is thrown, actually what's thrown
+      // is a pointer to the pointer. We'll dereference it.
+      if (throwntype != 0 && !___cxa_is_number_type(throwntype)) {
+        var throwntypeInfoAddr= HEAP32[((throwntype)>>2)] - 8;
+        var throwntypeInfo= HEAP32[((throwntypeInfoAddr)>>2)];
+        if (throwntypeInfo == 0)
+          thrown = HEAP32[((thrown)>>2)];
+      }
+      // The different catch blocks are denoted by different types.
+      // Due to inheritance, those types may not precisely match the
+      // type of the thrown object. Find one which matches, and
+      // return the type of the catch block which should be called.
+      for (var i = 0; i < typeArray.length; i++) {
+        if (___cxa_does_inherit(typeArray[i], throwntype, thrown))
+          return ((asm["setTempRet0"](typeArray[i]),thrown)|0);
+      }
+      // Shouldn't happen unless we have bogus data in typeArray
+      // or encounter a type for which emscripten doesn't have suitable
+      // typeinfo defined. Best-efforts match just in case.
+      return ((asm["setTempRet0"](throwntype),thrown)|0);
+    }function ___cxa_throw(ptr, type, destructor) {
+      if (!___cxa_throw.initialized) {
+        try {
+          HEAP32[((__ZTVN10__cxxabiv119__pointer_type_infoE)>>2)]=0; // Workaround for libcxxabi integration bug
+        } catch(e){}
+        try {
+          HEAP32[((__ZTVN10__cxxabiv117__class_type_infoE)>>2)]=1; // Workaround for libcxxabi integration bug
+        } catch(e){}
+        try {
+          HEAP32[((__ZTVN10__cxxabiv120__si_class_type_infoE)>>2)]=2; // Workaround for libcxxabi integration bug
+        } catch(e){}
+        ___cxa_throw.initialized = true;
+      }
+      var header = ptr - ___cxa_exception_header_size;
+      HEAP32[((header)>>2)]=type;
+      HEAP32[(((header)+(4))>>2)]=destructor;
+      ___cxa_last_thrown_exception = ptr;
+      if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) {
+        __ZSt18uncaught_exceptionv.uncaught_exception = 1;
+      } else {
+        __ZSt18uncaught_exceptionv.uncaught_exception++;
+      }
+      throw ptr + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";
+    }
+
+
+  Module["_memset"] = _memset;
+
+
+
+  function __exit(status) {
+      // void _exit(int status);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/exit.html
+      Module['exit'](status);
+    }function _exit(status) {
+      __exit(status);
+    }function __ZSt9terminatev() {
+      _exit(-1234);
+    }
+
+  function _abort() {
+      Module['abort']();
+    }
+
+
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+  var _sinf=Math_sin;
+
+
+  var _sqrtf=Math_sqrt;
+
+  var _floorf=Math_floor;
+
+
+  function _fputs(s, stream) {
+      // int fputs(const char *restrict s, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputs.html
+      var fd = _fileno(stream);
+      return _write(fd, s, _strlen(s));
+    }
+
+  function _fputc(c, stream) {
+      // int fputc(int c, FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html
+      var chr = unSign(c & 0xFF);
+      HEAP8[((_fputc.ret)|0)]=chr;
+      var fd = _fileno(stream);
+      var ret = _write(fd, _fputc.ret, 1);
+      if (ret == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return -1;
+      } else {
+        return chr;
+      }
+    }function _puts(s) {
+      // int puts(const char *s);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/puts.html
+      // NOTE: puts() always writes an extra newline.
+      var stdout = HEAP32[((_stdout)>>2)];
+      var ret = _fputs(s, stdout);
+      if (ret < 0) {
+        return ret;
+      } else {
+        var newlineRet = _fputc(10, stdout);
+        return (newlineRet < 0) ? -1 : ret + 1;
+      }
+    }
+
+  function _clock() {
+      if (_clock.start === undefined) _clock.start = Date.now();
+      return Math.floor((Date.now() - _clock.start) * (1000000/1000));
+    }
+
+
+  var ___cxa_caught_exceptions=[];function ___cxa_begin_catch(ptr) {
+      __ZSt18uncaught_exceptionv.uncaught_exception--;
+      ___cxa_caught_exceptions.push(___cxa_last_thrown_exception);
+      return ptr;
+    }
+
+  function ___errno_location() {
+      return ___errno_state;
+    }
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+
+  function __ZNSt9exceptionD2Ev() {}
+
+  var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+    Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+    Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+    // just add the mouse delta to the current absolut mouse position
+    // FIXME: ideally this should be clamped against the canvas size and zero
+    Browser.mouseX += Browser.mouseMovementX;
+    Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+  function _sbrk(bytes) {
+      // Implement a Linux-like 'memory area' for our 'process'.
+      // Changes the size of the memory area by |bytes|; returns the
+      // address of the previous top ('break') of the memory area
+      // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
+      var self = _sbrk;
+      if (!self.called) {
+        DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
+        self.called = true;
+        assert(Runtime.dynamicAlloc);
+        self.alloc = Runtime.dynamicAlloc;
+        Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
+      }
+      var ret = DYNAMICTOP;
+      if (bytes != 0) self.alloc(bytes);
+      return ret;  // Previous break location.
+    }
+
+  function _sysconf(name) {
+      // long sysconf(int name);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
+      switch(name) {
+        case 30: return PAGE_SIZE;
+        case 132:
+        case 133:
+        case 12:
+        case 137:
+        case 138:
+        case 15:
+        case 235:
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 149:
+        case 13:
+        case 10:
+        case 236:
+        case 153:
+        case 9:
+        case 21:
+        case 22:
+        case 159:
+        case 154:
+        case 14:
+        case 77:
+        case 78:
+        case 139:
+        case 80:
+        case 81:
+        case 79:
+        case 82:
+        case 68:
+        case 67:
+        case 164:
+        case 11:
+        case 29:
+        case 47:
+        case 48:
+        case 95:
+        case 52:
+        case 51:
+        case 46:
+          return 200809;
+        case 27:
+        case 246:
+        case 127:
+        case 128:
+        case 23:
+        case 24:
+        case 160:
+        case 161:
+        case 181:
+        case 182:
+        case 242:
+        case 183:
+        case 184:
+        case 243:
+        case 244:
+        case 245:
+        case 165:
+        case 178:
+        case 179:
+        case 49:
+        case 50:
+        case 168:
+        case 169:
+        case 175:
+        case 170:
+        case 171:
+        case 172:
+        case 97:
+        case 76:
+        case 32:
+        case 173:
+        case 35:
+          return -1;
+        case 176:
+        case 177:
+        case 7:
+        case 155:
+        case 8:
+        case 157:
+        case 125:
+        case 126:
+        case 92:
+        case 93:
+        case 129:
+        case 130:
+        case 131:
+        case 94:
+        case 91:
+          return 1;
+        case 74:
+        case 60:
+        case 69:
+        case 70:
+        case 4:
+          return 1024;
+        case 31:
+        case 42:
+        case 72:
+          return 32;
+        case 87:
+        case 26:
+        case 33:
+          return 2147483647;
+        case 34:
+        case 1:
+          return 47839;
+        case 38:
+        case 36:
+          return 99;
+        case 43:
+        case 37:
+          return 2048;
+        case 0: return 2097152;
+        case 3: return 65536;
+        case 28: return 32768;
+        case 44: return 32767;
+        case 75: return 16384;
+        case 39: return 1000;
+        case 89: return 700;
+        case 71: return 256;
+        case 40: return 255;
+        case 2: return 100;
+        case 180: return 64;
+        case 25: return 20;
+        case 5: return 16;
+        case 6: return 6;
+        case 73: return 4;
+        case 84: return 1;
+      }
+      ___setErrNo(ERRNO_CODES.EINVAL);
+      return -1;
+    }
+
+  function _emscripten_run_script(ptr) {
+      eval(Pointer_stringify(ptr));
+    }
+
+
+  function _malloc(bytes) {
+      /* Over-allocate to make sure it is byte-aligned by 8.
+       * This will leak memory, but this is only the dummy
+       * implementation (replaced by dlmalloc normally) so
+       * not an issue.
+       */
+      var ptr = Runtime.dynamicAlloc(bytes + 8);
+      return (ptr+8) & 0xFFFFFFF8;
+    }
+  Module["_malloc"] = _malloc;function ___cxa_allocate_exception(size) {
+      var ptr = _malloc(size + ___cxa_exception_header_size);
+      return ptr + ___cxa_exception_header_size;
+    }
+
+  function _emscripten_cancel_main_loop() {
+      Browser.mainLoop.scheduler = null;
+      Browser.mainLoop.shouldPause = true;
+    }
+
+  var __ZTISt9exception=allocate([allocate([1,0,0,0,0,0,0], "i8", ALLOC_STATIC)+8, 0], "i32", ALLOC_STATIC);
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+_fputc.ret = allocate([0], "i8", ALLOC_STATIC);
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function invoke_iiii(index,a1,a2,a3) {
+  try {
+    return Module["dynCall_iiii"](index,a1,a2,a3);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_viiiii(index,a1,a2,a3,a4,a5) {
+  try {
+    Module["dynCall_viiiii"](index,a1,a2,a3,a4,a5);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_vi(index,a1) {
+  try {
+    Module["dynCall_vi"](index,a1);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_vii(index,a1,a2) {
+  try {
+    Module["dynCall_vii"](index,a1,a2);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_ii(index,a1) {
+  try {
+    return Module["dynCall_ii"](index,a1);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_viii(index,a1,a2,a3) {
+  try {
+    Module["dynCall_viii"](index,a1,a2,a3);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_v(index) {
+  try {
+    Module["dynCall_v"](index);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_viid(index,a1,a2,a3) {
+  try {
+    Module["dynCall_viid"](index,a1,a2,a3);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_viiiiii(index,a1,a2,a3,a4,a5,a6) {
+  try {
+    Module["dynCall_viiiiii"](index,a1,a2,a3,a4,a5,a6);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_iii(index,a1,a2) {
+  try {
+    return Module["dynCall_iii"](index,a1,a2);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_iiiiii(index,a1,a2,a3,a4,a5) {
+  try {
+    return Module["dynCall_iiiiii"](index,a1,a2,a3,a4,a5);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_viiii(index,a1,a2,a3,a4) {
+  try {
+    Module["dynCall_viiii"](index,a1,a2,a3,a4);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+  var __ZTISt9exception=env.__ZTISt9exception|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var invoke_iiii=env.invoke_iiii;
+  var invoke_viiiii=env.invoke_viiiii;
+  var invoke_vi=env.invoke_vi;
+  var invoke_vii=env.invoke_vii;
+  var invoke_ii=env.invoke_ii;
+  var invoke_viii=env.invoke_viii;
+  var invoke_v=env.invoke_v;
+  var invoke_viid=env.invoke_viid;
+  var invoke_viiiiii=env.invoke_viiiiii;
+  var invoke_iii=env.invoke_iii;
+  var invoke_iiiiii=env.invoke_iiiiii;
+  var invoke_viiii=env.invoke_viiii;
+  var ___cxa_throw=env.___cxa_throw;
+  var _emscripten_run_script=env._emscripten_run_script;
+  var _cosf=env._cosf;
+  var _send=env._send;
+  var __ZSt9terminatev=env.__ZSt9terminatev;
+  var __reallyNegative=env.__reallyNegative;
+  var ___cxa_is_number_type=env.___cxa_is_number_type;
+  var ___assert_fail=env.___assert_fail;
+  var ___cxa_allocate_exception=env.___cxa_allocate_exception;
+  var ___cxa_find_matching_catch=env.___cxa_find_matching_catch;
+  var _fflush=env._fflush;
+  var _pwrite=env._pwrite;
+  var ___setErrNo=env.___setErrNo;
+  var _sbrk=env._sbrk;
+  var ___cxa_begin_catch=env.___cxa_begin_catch;
+  var _sinf=env._sinf;
+  var _fileno=env._fileno;
+  var ___resumeException=env.___resumeException;
+  var __ZSt18uncaught_exceptionv=env.__ZSt18uncaught_exceptionv;
+  var _sysconf=env._sysconf;
+  var _clock=env._clock;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _puts=env._puts;
+  var _mkport=env._mkport;
+  var _floorf=env._floorf;
+  var _sqrtf=env._sqrtf;
+  var _write=env._write;
+  var _emscripten_set_main_loop=env._emscripten_set_main_loop;
+  var ___errno_location=env.___errno_location;
+  var __ZNSt9exceptionD2Ev=env.__ZNSt9exceptionD2Ev;
+  var _printf=env._printf;
+  var ___cxa_does_inherit=env.___cxa_does_inherit;
+  var __exit=env.__exit;
+  var _fputc=env._fputc;
+  var _abort=env._abort;
+  var _fwrite=env._fwrite;
+  var _time=env._time;
+  var _fprintf=env._fprintf;
+  var _emscripten_cancel_main_loop=env._emscripten_cancel_main_loop;
+  var __formatString=env.__formatString;
+  var _fputs=env._fputs;
+  var _exit=env._exit;
+  var ___cxa_pure_virtual=env.___cxa_pure_virtual;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _malloc(i12) {
+ i12 = i12 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0;
+ i1 = STACKTOP;
+ do {
+  if (i12 >>> 0 < 245) {
+   if (i12 >>> 0 < 11) {
+    i12 = 16;
+   } else {
+    i12 = i12 + 11 & -8;
+   }
+   i20 = i12 >>> 3;
+   i18 = HEAP32[1790] | 0;
+   i21 = i18 >>> i20;
+   if ((i21 & 3 | 0) != 0) {
+    i6 = (i21 & 1 ^ 1) + i20 | 0;
+    i5 = i6 << 1;
+    i3 = 7200 + (i5 << 2) | 0;
+    i5 = 7200 + (i5 + 2 << 2) | 0;
+    i7 = HEAP32[i5 >> 2] | 0;
+    i2 = i7 + 8 | 0;
+    i4 = HEAP32[i2 >> 2] | 0;
+    do {
+     if ((i3 | 0) != (i4 | 0)) {
+      if (i4 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i8 = i4 + 12 | 0;
+      if ((HEAP32[i8 >> 2] | 0) == (i7 | 0)) {
+       HEAP32[i8 >> 2] = i3;
+       HEAP32[i5 >> 2] = i4;
+       break;
+      } else {
+       _abort();
+      }
+     } else {
+      HEAP32[1790] = i18 & ~(1 << i6);
+     }
+    } while (0);
+    i32 = i6 << 3;
+    HEAP32[i7 + 4 >> 2] = i32 | 3;
+    i32 = i7 + (i32 | 4) | 0;
+    HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+    i32 = i2;
+    STACKTOP = i1;
+    return i32 | 0;
+   }
+   if (i12 >>> 0 > (HEAP32[7168 >> 2] | 0) >>> 0) {
+    if ((i21 | 0) != 0) {
+     i7 = 2 << i20;
+     i7 = i21 << i20 & (i7 | 0 - i7);
+     i7 = (i7 & 0 - i7) + -1 | 0;
+     i2 = i7 >>> 12 & 16;
+     i7 = i7 >>> i2;
+     i6 = i7 >>> 5 & 8;
+     i7 = i7 >>> i6;
+     i5 = i7 >>> 2 & 4;
+     i7 = i7 >>> i5;
+     i4 = i7 >>> 1 & 2;
+     i7 = i7 >>> i4;
+     i3 = i7 >>> 1 & 1;
+     i3 = (i6 | i2 | i5 | i4 | i3) + (i7 >>> i3) | 0;
+     i7 = i3 << 1;
+     i4 = 7200 + (i7 << 2) | 0;
+     i7 = 7200 + (i7 + 2 << 2) | 0;
+     i5 = HEAP32[i7 >> 2] | 0;
+     i2 = i5 + 8 | 0;
+     i6 = HEAP32[i2 >> 2] | 0;
+     do {
+      if ((i4 | 0) != (i6 | 0)) {
+       if (i6 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       i8 = i6 + 12 | 0;
+       if ((HEAP32[i8 >> 2] | 0) == (i5 | 0)) {
+        HEAP32[i8 >> 2] = i4;
+        HEAP32[i7 >> 2] = i6;
+        break;
+       } else {
+        _abort();
+       }
+      } else {
+       HEAP32[1790] = i18 & ~(1 << i3);
+      }
+     } while (0);
+     i6 = i3 << 3;
+     i4 = i6 - i12 | 0;
+     HEAP32[i5 + 4 >> 2] = i12 | 3;
+     i3 = i5 + i12 | 0;
+     HEAP32[i5 + (i12 | 4) >> 2] = i4 | 1;
+     HEAP32[i5 + i6 >> 2] = i4;
+     i6 = HEAP32[7168 >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      i5 = HEAP32[7180 >> 2] | 0;
+      i8 = i6 >>> 3;
+      i9 = i8 << 1;
+      i6 = 7200 + (i9 << 2) | 0;
+      i7 = HEAP32[1790] | 0;
+      i8 = 1 << i8;
+      if ((i7 & i8 | 0) != 0) {
+       i7 = 7200 + (i9 + 2 << 2) | 0;
+       i8 = HEAP32[i7 >> 2] | 0;
+       if (i8 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i28 = i7;
+        i27 = i8;
+       }
+      } else {
+       HEAP32[1790] = i7 | i8;
+       i28 = 7200 + (i9 + 2 << 2) | 0;
+       i27 = i6;
+      }
+      HEAP32[i28 >> 2] = i5;
+      HEAP32[i27 + 12 >> 2] = i5;
+      HEAP32[i5 + 8 >> 2] = i27;
+      HEAP32[i5 + 12 >> 2] = i6;
+     }
+     HEAP32[7168 >> 2] = i4;
+     HEAP32[7180 >> 2] = i3;
+     i32 = i2;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i18 = HEAP32[7164 >> 2] | 0;
+    if ((i18 | 0) != 0) {
+     i2 = (i18 & 0 - i18) + -1 | 0;
+     i31 = i2 >>> 12 & 16;
+     i2 = i2 >>> i31;
+     i30 = i2 >>> 5 & 8;
+     i2 = i2 >>> i30;
+     i32 = i2 >>> 2 & 4;
+     i2 = i2 >>> i32;
+     i6 = i2 >>> 1 & 2;
+     i2 = i2 >>> i6;
+     i3 = i2 >>> 1 & 1;
+     i3 = HEAP32[7464 + ((i30 | i31 | i32 | i6 | i3) + (i2 >>> i3) << 2) >> 2] | 0;
+     i2 = (HEAP32[i3 + 4 >> 2] & -8) - i12 | 0;
+     i6 = i3;
+     while (1) {
+      i5 = HEAP32[i6 + 16 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       i5 = HEAP32[i6 + 20 >> 2] | 0;
+       if ((i5 | 0) == 0) {
+        break;
+       }
+      }
+      i6 = (HEAP32[i5 + 4 >> 2] & -8) - i12 | 0;
+      i4 = i6 >>> 0 < i2 >>> 0;
+      i2 = i4 ? i6 : i2;
+      i6 = i5;
+      i3 = i4 ? i5 : i3;
+     }
+     i6 = HEAP32[7176 >> 2] | 0;
+     if (i3 >>> 0 < i6 >>> 0) {
+      _abort();
+     }
+     i4 = i3 + i12 | 0;
+     if (!(i3 >>> 0 < i4 >>> 0)) {
+      _abort();
+     }
+     i5 = HEAP32[i3 + 24 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     do {
+      if ((i7 | 0) == (i3 | 0)) {
+       i8 = i3 + 20 | 0;
+       i7 = HEAP32[i8 >> 2] | 0;
+       if ((i7 | 0) == 0) {
+        i8 = i3 + 16 | 0;
+        i7 = HEAP32[i8 >> 2] | 0;
+        if ((i7 | 0) == 0) {
+         i26 = 0;
+         break;
+        }
+       }
+       while (1) {
+        i10 = i7 + 20 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) != 0) {
+         i7 = i9;
+         i8 = i10;
+         continue;
+        }
+        i10 = i7 + 16 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) == 0) {
+         break;
+        } else {
+         i7 = i9;
+         i8 = i10;
+        }
+       }
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i8 >> 2] = 0;
+        i26 = i7;
+        break;
+       }
+      } else {
+       i8 = HEAP32[i3 + 8 >> 2] | 0;
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       }
+       i6 = i8 + 12 | 0;
+       if ((HEAP32[i6 >> 2] | 0) != (i3 | 0)) {
+        _abort();
+       }
+       i9 = i7 + 8 | 0;
+       if ((HEAP32[i9 >> 2] | 0) == (i3 | 0)) {
+        HEAP32[i6 >> 2] = i7;
+        HEAP32[i9 >> 2] = i8;
+        i26 = i7;
+        break;
+       } else {
+        _abort();
+       }
+      }
+     } while (0);
+     do {
+      if ((i5 | 0) != 0) {
+       i7 = HEAP32[i3 + 28 >> 2] | 0;
+       i6 = 7464 + (i7 << 2) | 0;
+       if ((i3 | 0) == (HEAP32[i6 >> 2] | 0)) {
+        HEAP32[i6 >> 2] = i26;
+        if ((i26 | 0) == 0) {
+         HEAP32[7164 >> 2] = HEAP32[7164 >> 2] & ~(1 << i7);
+         break;
+        }
+       } else {
+        if (i5 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        i6 = i5 + 16 | 0;
+        if ((HEAP32[i6 >> 2] | 0) == (i3 | 0)) {
+         HEAP32[i6 >> 2] = i26;
+        } else {
+         HEAP32[i5 + 20 >> 2] = i26;
+        }
+        if ((i26 | 0) == 0) {
+         break;
+        }
+       }
+       if (i26 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       HEAP32[i26 + 24 >> 2] = i5;
+       i5 = HEAP32[i3 + 16 >> 2] | 0;
+       do {
+        if ((i5 | 0) != 0) {
+         if (i5 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i26 + 16 >> 2] = i5;
+          HEAP32[i5 + 24 >> 2] = i26;
+          break;
+         }
+        }
+       } while (0);
+       i5 = HEAP32[i3 + 20 >> 2] | 0;
+       if ((i5 | 0) != 0) {
+        if (i5 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i26 + 20 >> 2] = i5;
+         HEAP32[i5 + 24 >> 2] = i26;
+         break;
+        }
+       }
+      }
+     } while (0);
+     if (i2 >>> 0 < 16) {
+      i32 = i2 + i12 | 0;
+      HEAP32[i3 + 4 >> 2] = i32 | 3;
+      i32 = i3 + (i32 + 4) | 0;
+      HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+     } else {
+      HEAP32[i3 + 4 >> 2] = i12 | 3;
+      HEAP32[i3 + (i12 | 4) >> 2] = i2 | 1;
+      HEAP32[i3 + (i2 + i12) >> 2] = i2;
+      i6 = HEAP32[7168 >> 2] | 0;
+      if ((i6 | 0) != 0) {
+       i5 = HEAP32[7180 >> 2] | 0;
+       i8 = i6 >>> 3;
+       i9 = i8 << 1;
+       i6 = 7200 + (i9 << 2) | 0;
+       i7 = HEAP32[1790] | 0;
+       i8 = 1 << i8;
+       if ((i7 & i8 | 0) != 0) {
+        i7 = 7200 + (i9 + 2 << 2) | 0;
+        i8 = HEAP32[i7 >> 2] | 0;
+        if (i8 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         i25 = i7;
+         i24 = i8;
+        }
+       } else {
+        HEAP32[1790] = i7 | i8;
+        i25 = 7200 + (i9 + 2 << 2) | 0;
+        i24 = i6;
+       }
+       HEAP32[i25 >> 2] = i5;
+       HEAP32[i24 + 12 >> 2] = i5;
+       HEAP32[i5 + 8 >> 2] = i24;
+       HEAP32[i5 + 12 >> 2] = i6;
+      }
+      HEAP32[7168 >> 2] = i2;
+      HEAP32[7180 >> 2] = i4;
+     }
+     i32 = i3 + 8 | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+   }
+  } else {
+   if (!(i12 >>> 0 > 4294967231)) {
+    i24 = i12 + 11 | 0;
+    i12 = i24 & -8;
+    i26 = HEAP32[7164 >> 2] | 0;
+    if ((i26 | 0) != 0) {
+     i25 = 0 - i12 | 0;
+     i24 = i24 >>> 8;
+     if ((i24 | 0) != 0) {
+      if (i12 >>> 0 > 16777215) {
+       i27 = 31;
+      } else {
+       i31 = (i24 + 1048320 | 0) >>> 16 & 8;
+       i32 = i24 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i27 = (i32 + 245760 | 0) >>> 16 & 2;
+       i27 = 14 - (i30 | i31 | i27) + (i32 << i27 >>> 15) | 0;
+       i27 = i12 >>> (i27 + 7 | 0) & 1 | i27 << 1;
+      }
+     } else {
+      i27 = 0;
+     }
+     i30 = HEAP32[7464 + (i27 << 2) >> 2] | 0;
+     L126 : do {
+      if ((i30 | 0) == 0) {
+       i29 = 0;
+       i24 = 0;
+      } else {
+       if ((i27 | 0) == 31) {
+        i24 = 0;
+       } else {
+        i24 = 25 - (i27 >>> 1) | 0;
+       }
+       i29 = 0;
+       i28 = i12 << i24;
+       i24 = 0;
+       while (1) {
+        i32 = HEAP32[i30 + 4 >> 2] & -8;
+        i31 = i32 - i12 | 0;
+        if (i31 >>> 0 < i25 >>> 0) {
+         if ((i32 | 0) == (i12 | 0)) {
+          i25 = i31;
+          i29 = i30;
+          i24 = i30;
+          break L126;
+         } else {
+          i25 = i31;
+          i24 = i30;
+         }
+        }
+        i31 = HEAP32[i30 + 20 >> 2] | 0;
+        i30 = HEAP32[i30 + (i28 >>> 31 << 2) + 16 >> 2] | 0;
+        i29 = (i31 | 0) == 0 | (i31 | 0) == (i30 | 0) ? i29 : i31;
+        if ((i30 | 0) == 0) {
+         break;
+        } else {
+         i28 = i28 << 1;
+        }
+       }
+      }
+     } while (0);
+     if ((i29 | 0) == 0 & (i24 | 0) == 0) {
+      i32 = 2 << i27;
+      i26 = i26 & (i32 | 0 - i32);
+      if ((i26 | 0) == 0) {
+       break;
+      }
+      i32 = (i26 & 0 - i26) + -1 | 0;
+      i28 = i32 >>> 12 & 16;
+      i32 = i32 >>> i28;
+      i27 = i32 >>> 5 & 8;
+      i32 = i32 >>> i27;
+      i30 = i32 >>> 2 & 4;
+      i32 = i32 >>> i30;
+      i31 = i32 >>> 1 & 2;
+      i32 = i32 >>> i31;
+      i29 = i32 >>> 1 & 1;
+      i29 = HEAP32[7464 + ((i27 | i28 | i30 | i31 | i29) + (i32 >>> i29) << 2) >> 2] | 0;
+     }
+     if ((i29 | 0) != 0) {
+      while (1) {
+       i27 = (HEAP32[i29 + 4 >> 2] & -8) - i12 | 0;
+       i26 = i27 >>> 0 < i25 >>> 0;
+       i25 = i26 ? i27 : i25;
+       i24 = i26 ? i29 : i24;
+       i26 = HEAP32[i29 + 16 >> 2] | 0;
+       if ((i26 | 0) != 0) {
+        i29 = i26;
+        continue;
+       }
+       i29 = HEAP32[i29 + 20 >> 2] | 0;
+       if ((i29 | 0) == 0) {
+        break;
+       }
+      }
+     }
+     if ((i24 | 0) != 0 ? i25 >>> 0 < ((HEAP32[7168 >> 2] | 0) - i12 | 0) >>> 0 : 0) {
+      i4 = HEAP32[7176 >> 2] | 0;
+      if (i24 >>> 0 < i4 >>> 0) {
+       _abort();
+      }
+      i2 = i24 + i12 | 0;
+      if (!(i24 >>> 0 < i2 >>> 0)) {
+       _abort();
+      }
+      i3 = HEAP32[i24 + 24 >> 2] | 0;
+      i6 = HEAP32[i24 + 12 >> 2] | 0;
+      do {
+       if ((i6 | 0) == (i24 | 0)) {
+        i6 = i24 + 20 | 0;
+        i5 = HEAP32[i6 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         i6 = i24 + 16 | 0;
+         i5 = HEAP32[i6 >> 2] | 0;
+         if ((i5 | 0) == 0) {
+          i22 = 0;
+          break;
+         }
+        }
+        while (1) {
+         i8 = i5 + 20 | 0;
+         i7 = HEAP32[i8 >> 2] | 0;
+         if ((i7 | 0) != 0) {
+          i5 = i7;
+          i6 = i8;
+          continue;
+         }
+         i7 = i5 + 16 | 0;
+         i8 = HEAP32[i7 >> 2] | 0;
+         if ((i8 | 0) == 0) {
+          break;
+         } else {
+          i5 = i8;
+          i6 = i7;
+         }
+        }
+        if (i6 >>> 0 < i4 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i6 >> 2] = 0;
+         i22 = i5;
+         break;
+        }
+       } else {
+        i5 = HEAP32[i24 + 8 >> 2] | 0;
+        if (i5 >>> 0 < i4 >>> 0) {
+         _abort();
+        }
+        i7 = i5 + 12 | 0;
+        if ((HEAP32[i7 >> 2] | 0) != (i24 | 0)) {
+         _abort();
+        }
+        i4 = i6 + 8 | 0;
+        if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+         HEAP32[i7 >> 2] = i6;
+         HEAP32[i4 >> 2] = i5;
+         i22 = i6;
+         break;
+        } else {
+         _abort();
+        }
+       }
+      } while (0);
+      do {
+       if ((i3 | 0) != 0) {
+        i4 = HEAP32[i24 + 28 >> 2] | 0;
+        i5 = 7464 + (i4 << 2) | 0;
+        if ((i24 | 0) == (HEAP32[i5 >> 2] | 0)) {
+         HEAP32[i5 >> 2] = i22;
+         if ((i22 | 0) == 0) {
+          HEAP32[7164 >> 2] = HEAP32[7164 >> 2] & ~(1 << i4);
+          break;
+         }
+        } else {
+         if (i3 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+          _abort();
+         }
+         i4 = i3 + 16 | 0;
+         if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+          HEAP32[i4 >> 2] = i22;
+         } else {
+          HEAP32[i3 + 20 >> 2] = i22;
+         }
+         if ((i22 | 0) == 0) {
+          break;
+         }
+        }
+        if (i22 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        HEAP32[i22 + 24 >> 2] = i3;
+        i3 = HEAP32[i24 + 16 >> 2] | 0;
+        do {
+         if ((i3 | 0) != 0) {
+          if (i3 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i22 + 16 >> 2] = i3;
+           HEAP32[i3 + 24 >> 2] = i22;
+           break;
+          }
+         }
+        } while (0);
+        i3 = HEAP32[i24 + 20 >> 2] | 0;
+        if ((i3 | 0) != 0) {
+         if (i3 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i22 + 20 >> 2] = i3;
+          HEAP32[i3 + 24 >> 2] = i22;
+          break;
+         }
+        }
+       }
+      } while (0);
+      L204 : do {
+       if (!(i25 >>> 0 < 16)) {
+        HEAP32[i24 + 4 >> 2] = i12 | 3;
+        HEAP32[i24 + (i12 | 4) >> 2] = i25 | 1;
+        HEAP32[i24 + (i25 + i12) >> 2] = i25;
+        i4 = i25 >>> 3;
+        if (i25 >>> 0 < 256) {
+         i6 = i4 << 1;
+         i3 = 7200 + (i6 << 2) | 0;
+         i5 = HEAP32[1790] | 0;
+         i4 = 1 << i4;
+         if ((i5 & i4 | 0) != 0) {
+          i5 = 7200 + (i6 + 2 << 2) | 0;
+          i4 = HEAP32[i5 >> 2] | 0;
+          if (i4 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           i21 = i5;
+           i20 = i4;
+          }
+         } else {
+          HEAP32[1790] = i5 | i4;
+          i21 = 7200 + (i6 + 2 << 2) | 0;
+          i20 = i3;
+         }
+         HEAP32[i21 >> 2] = i2;
+         HEAP32[i20 + 12 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i20;
+         HEAP32[i24 + (i12 + 12) >> 2] = i3;
+         break;
+        }
+        i3 = i25 >>> 8;
+        if ((i3 | 0) != 0) {
+         if (i25 >>> 0 > 16777215) {
+          i3 = 31;
+         } else {
+          i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+          i32 = i3 << i31;
+          i30 = (i32 + 520192 | 0) >>> 16 & 4;
+          i32 = i32 << i30;
+          i3 = (i32 + 245760 | 0) >>> 16 & 2;
+          i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+          i3 = i25 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+         }
+        } else {
+         i3 = 0;
+        }
+        i6 = 7464 + (i3 << 2) | 0;
+        HEAP32[i24 + (i12 + 28) >> 2] = i3;
+        HEAP32[i24 + (i12 + 20) >> 2] = 0;
+        HEAP32[i24 + (i12 + 16) >> 2] = 0;
+        i4 = HEAP32[7164 >> 2] | 0;
+        i5 = 1 << i3;
+        if ((i4 & i5 | 0) == 0) {
+         HEAP32[7164 >> 2] = i4 | i5;
+         HEAP32[i6 >> 2] = i2;
+         HEAP32[i24 + (i12 + 24) >> 2] = i6;
+         HEAP32[i24 + (i12 + 12) >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i2;
+         break;
+        }
+        i4 = HEAP32[i6 >> 2] | 0;
+        if ((i3 | 0) == 31) {
+         i3 = 0;
+        } else {
+         i3 = 25 - (i3 >>> 1) | 0;
+        }
+        L225 : do {
+         if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i25 | 0)) {
+          i3 = i25 << i3;
+          while (1) {
+           i6 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+           i5 = HEAP32[i6 >> 2] | 0;
+           if ((i5 | 0) == 0) {
+            break;
+           }
+           if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i25 | 0)) {
+            i18 = i5;
+            break L225;
+           } else {
+            i3 = i3 << 1;
+            i4 = i5;
+           }
+          }
+          if (i6 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i6 >> 2] = i2;
+           HEAP32[i24 + (i12 + 24) >> 2] = i4;
+           HEAP32[i24 + (i12 + 12) >> 2] = i2;
+           HEAP32[i24 + (i12 + 8) >> 2] = i2;
+           break L204;
+          }
+         } else {
+          i18 = i4;
+         }
+        } while (0);
+        i4 = i18 + 8 | 0;
+        i3 = HEAP32[i4 >> 2] | 0;
+        i5 = HEAP32[7176 >> 2] | 0;
+        if (i18 >>> 0 < i5 >>> 0) {
+         _abort();
+        }
+        if (i3 >>> 0 < i5 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i3 + 12 >> 2] = i2;
+         HEAP32[i4 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i3;
+         HEAP32[i24 + (i12 + 12) >> 2] = i18;
+         HEAP32[i24 + (i12 + 24) >> 2] = 0;
+         break;
+        }
+       } else {
+        i32 = i25 + i12 | 0;
+        HEAP32[i24 + 4 >> 2] = i32 | 3;
+        i32 = i24 + (i32 + 4) | 0;
+        HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+       }
+      } while (0);
+      i32 = i24 + 8 | 0;
+      STACKTOP = i1;
+      return i32 | 0;
+     }
+    }
+   } else {
+    i12 = -1;
+   }
+  }
+ } while (0);
+ i18 = HEAP32[7168 >> 2] | 0;
+ if (!(i12 >>> 0 > i18 >>> 0)) {
+  i3 = i18 - i12 | 0;
+  i2 = HEAP32[7180 >> 2] | 0;
+  if (i3 >>> 0 > 15) {
+   HEAP32[7180 >> 2] = i2 + i12;
+   HEAP32[7168 >> 2] = i3;
+   HEAP32[i2 + (i12 + 4) >> 2] = i3 | 1;
+   HEAP32[i2 + i18 >> 2] = i3;
+   HEAP32[i2 + 4 >> 2] = i12 | 3;
+  } else {
+   HEAP32[7168 >> 2] = 0;
+   HEAP32[7180 >> 2] = 0;
+   HEAP32[i2 + 4 >> 2] = i18 | 3;
+   i32 = i2 + (i18 + 4) | 0;
+   HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+  }
+  i32 = i2 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i18 = HEAP32[7172 >> 2] | 0;
+ if (i12 >>> 0 < i18 >>> 0) {
+  i31 = i18 - i12 | 0;
+  HEAP32[7172 >> 2] = i31;
+  i32 = HEAP32[7184 >> 2] | 0;
+  HEAP32[7184 >> 2] = i32 + i12;
+  HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+  HEAP32[i32 + 4 >> 2] = i12 | 3;
+  i32 = i32 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ do {
+  if ((HEAP32[1908] | 0) == 0) {
+   i18 = _sysconf(30) | 0;
+   if ((i18 + -1 & i18 | 0) == 0) {
+    HEAP32[7640 >> 2] = i18;
+    HEAP32[7636 >> 2] = i18;
+    HEAP32[7644 >> 2] = -1;
+    HEAP32[7648 >> 2] = -1;
+    HEAP32[7652 >> 2] = 0;
+    HEAP32[7604 >> 2] = 0;
+    HEAP32[1908] = (_time(0) | 0) & -16 ^ 1431655768;
+    break;
+   } else {
+    _abort();
+   }
+  }
+ } while (0);
+ i20 = i12 + 48 | 0;
+ i25 = HEAP32[7640 >> 2] | 0;
+ i21 = i12 + 47 | 0;
+ i22 = i25 + i21 | 0;
+ i25 = 0 - i25 | 0;
+ i18 = i22 & i25;
+ if (!(i18 >>> 0 > i12 >>> 0)) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i24 = HEAP32[7600 >> 2] | 0;
+ if ((i24 | 0) != 0 ? (i31 = HEAP32[7592 >> 2] | 0, i32 = i31 + i18 | 0, i32 >>> 0 <= i31 >>> 0 | i32 >>> 0 > i24 >>> 0) : 0) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ L269 : do {
+  if ((HEAP32[7604 >> 2] & 4 | 0) == 0) {
+   i26 = HEAP32[7184 >> 2] | 0;
+   L271 : do {
+    if ((i26 | 0) != 0) {
+     i24 = 7608 | 0;
+     while (1) {
+      i27 = HEAP32[i24 >> 2] | 0;
+      if (!(i27 >>> 0 > i26 >>> 0) ? (i23 = i24 + 4 | 0, (i27 + (HEAP32[i23 >> 2] | 0) | 0) >>> 0 > i26 >>> 0) : 0) {
+       break;
+      }
+      i24 = HEAP32[i24 + 8 >> 2] | 0;
+      if ((i24 | 0) == 0) {
+       i13 = 182;
+       break L271;
+      }
+     }
+     if ((i24 | 0) != 0) {
+      i25 = i22 - (HEAP32[7172 >> 2] | 0) & i25;
+      if (i25 >>> 0 < 2147483647) {
+       i13 = _sbrk(i25 | 0) | 0;
+       i26 = (i13 | 0) == ((HEAP32[i24 >> 2] | 0) + (HEAP32[i23 >> 2] | 0) | 0);
+       i22 = i13;
+       i24 = i25;
+       i23 = i26 ? i13 : -1;
+       i25 = i26 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i13 = 182;
+     }
+    } else {
+     i13 = 182;
+    }
+   } while (0);
+   do {
+    if ((i13 | 0) == 182) {
+     i23 = _sbrk(0) | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i24 = i23;
+      i22 = HEAP32[7636 >> 2] | 0;
+      i25 = i22 + -1 | 0;
+      if ((i25 & i24 | 0) == 0) {
+       i25 = i18;
+      } else {
+       i25 = i18 - i24 + (i25 + i24 & 0 - i22) | 0;
+      }
+      i24 = HEAP32[7592 >> 2] | 0;
+      i26 = i24 + i25 | 0;
+      if (i25 >>> 0 > i12 >>> 0 & i25 >>> 0 < 2147483647) {
+       i22 = HEAP32[7600 >> 2] | 0;
+       if ((i22 | 0) != 0 ? i26 >>> 0 <= i24 >>> 0 | i26 >>> 0 > i22 >>> 0 : 0) {
+        i25 = 0;
+        break;
+       }
+       i22 = _sbrk(i25 | 0) | 0;
+       i13 = (i22 | 0) == (i23 | 0);
+       i24 = i25;
+       i23 = i13 ? i23 : -1;
+       i25 = i13 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i25 = 0;
+     }
+    }
+   } while (0);
+   L291 : do {
+    if ((i13 | 0) == 191) {
+     i13 = 0 - i24 | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i17 = i23;
+      i14 = i25;
+      i13 = 202;
+      break L269;
+     }
+     do {
+      if ((i22 | 0) != (-1 | 0) & i24 >>> 0 < 2147483647 & i24 >>> 0 < i20 >>> 0 ? (i19 = HEAP32[7640 >> 2] | 0, i19 = i21 - i24 + i19 & 0 - i19, i19 >>> 0 < 2147483647) : 0) {
+       if ((_sbrk(i19 | 0) | 0) == (-1 | 0)) {
+        _sbrk(i13 | 0) | 0;
+        break L291;
+       } else {
+        i24 = i19 + i24 | 0;
+        break;
+       }
+      }
+     } while (0);
+     if ((i22 | 0) != (-1 | 0)) {
+      i17 = i22;
+      i14 = i24;
+      i13 = 202;
+      break L269;
+     }
+    }
+   } while (0);
+   HEAP32[7604 >> 2] = HEAP32[7604 >> 2] | 4;
+   i13 = 199;
+  } else {
+   i25 = 0;
+   i13 = 199;
+  }
+ } while (0);
+ if ((((i13 | 0) == 199 ? i18 >>> 0 < 2147483647 : 0) ? (i17 = _sbrk(i18 | 0) | 0, i16 = _sbrk(0) | 0, (i16 | 0) != (-1 | 0) & (i17 | 0) != (-1 | 0) & i17 >>> 0 < i16 >>> 0) : 0) ? (i15 = i16 - i17 | 0, i14 = i15 >>> 0 > (i12 + 40 | 0) >>> 0, i14) : 0) {
+  i14 = i14 ? i15 : i25;
+  i13 = 202;
+ }
+ if ((i13 | 0) == 202) {
+  i15 = (HEAP32[7592 >> 2] | 0) + i14 | 0;
+  HEAP32[7592 >> 2] = i15;
+  if (i15 >>> 0 > (HEAP32[7596 >> 2] | 0) >>> 0) {
+   HEAP32[7596 >> 2] = i15;
+  }
+  i15 = HEAP32[7184 >> 2] | 0;
+  L311 : do {
+   if ((i15 | 0) != 0) {
+    i21 = 7608 | 0;
+    while (1) {
+     i16 = HEAP32[i21 >> 2] | 0;
+     i19 = i21 + 4 | 0;
+     i20 = HEAP32[i19 >> 2] | 0;
+     if ((i17 | 0) == (i16 + i20 | 0)) {
+      i13 = 214;
+      break;
+     }
+     i18 = HEAP32[i21 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i21 = i18;
+     }
+    }
+    if (((i13 | 0) == 214 ? (HEAP32[i21 + 12 >> 2] & 8 | 0) == 0 : 0) ? i15 >>> 0 >= i16 >>> 0 & i15 >>> 0 < i17 >>> 0 : 0) {
+     HEAP32[i19 >> 2] = i20 + i14;
+     i2 = (HEAP32[7172 >> 2] | 0) + i14 | 0;
+     i3 = i15 + 8 | 0;
+     if ((i3 & 7 | 0) == 0) {
+      i3 = 0;
+     } else {
+      i3 = 0 - i3 & 7;
+     }
+     i32 = i2 - i3 | 0;
+     HEAP32[7184 >> 2] = i15 + i3;
+     HEAP32[7172 >> 2] = i32;
+     HEAP32[i15 + (i3 + 4) >> 2] = i32 | 1;
+     HEAP32[i15 + (i2 + 4) >> 2] = 40;
+     HEAP32[7188 >> 2] = HEAP32[7648 >> 2];
+     break;
+    }
+    if (i17 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+     HEAP32[7176 >> 2] = i17;
+    }
+    i19 = i17 + i14 | 0;
+    i16 = 7608 | 0;
+    while (1) {
+     if ((HEAP32[i16 >> 2] | 0) == (i19 | 0)) {
+      i13 = 224;
+      break;
+     }
+     i18 = HEAP32[i16 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i16 = i18;
+     }
+    }
+    if ((i13 | 0) == 224 ? (HEAP32[i16 + 12 >> 2] & 8 | 0) == 0 : 0) {
+     HEAP32[i16 >> 2] = i17;
+     i6 = i16 + 4 | 0;
+     HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i14;
+     i6 = i17 + 8 | 0;
+     if ((i6 & 7 | 0) == 0) {
+      i6 = 0;
+     } else {
+      i6 = 0 - i6 & 7;
+     }
+     i7 = i17 + (i14 + 8) | 0;
+     if ((i7 & 7 | 0) == 0) {
+      i13 = 0;
+     } else {
+      i13 = 0 - i7 & 7;
+     }
+     i15 = i17 + (i13 + i14) | 0;
+     i8 = i6 + i12 | 0;
+     i7 = i17 + i8 | 0;
+     i10 = i15 - (i17 + i6) - i12 | 0;
+     HEAP32[i17 + (i6 + 4) >> 2] = i12 | 3;
+     L348 : do {
+      if ((i15 | 0) != (HEAP32[7184 >> 2] | 0)) {
+       if ((i15 | 0) == (HEAP32[7180 >> 2] | 0)) {
+        i32 = (HEAP32[7168 >> 2] | 0) + i10 | 0;
+        HEAP32[7168 >> 2] = i32;
+        HEAP32[7180 >> 2] = i7;
+        HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+        HEAP32[i17 + (i32 + i8) >> 2] = i32;
+        break;
+       }
+       i12 = i14 + 4 | 0;
+       i18 = HEAP32[i17 + (i12 + i13) >> 2] | 0;
+       if ((i18 & 3 | 0) == 1) {
+        i11 = i18 & -8;
+        i16 = i18 >>> 3;
+        do {
+         if (!(i18 >>> 0 < 256)) {
+          i9 = HEAP32[i17 + ((i13 | 24) + i14) >> 2] | 0;
+          i19 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          do {
+           if ((i19 | 0) == (i15 | 0)) {
+            i19 = i13 | 16;
+            i18 = i17 + (i12 + i19) | 0;
+            i16 = HEAP32[i18 >> 2] | 0;
+            if ((i16 | 0) == 0) {
+             i18 = i17 + (i19 + i14) | 0;
+             i16 = HEAP32[i18 >> 2] | 0;
+             if ((i16 | 0) == 0) {
+              i5 = 0;
+              break;
+             }
+            }
+            while (1) {
+             i20 = i16 + 20 | 0;
+             i19 = HEAP32[i20 >> 2] | 0;
+             if ((i19 | 0) != 0) {
+              i16 = i19;
+              i18 = i20;
+              continue;
+             }
+             i19 = i16 + 16 | 0;
+             i20 = HEAP32[i19 >> 2] | 0;
+             if ((i20 | 0) == 0) {
+              break;
+             } else {
+              i16 = i20;
+              i18 = i19;
+             }
+            }
+            if (i18 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i18 >> 2] = 0;
+             i5 = i16;
+             break;
+            }
+           } else {
+            i18 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+            if (i18 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i18 + 12 | 0;
+            if ((HEAP32[i16 >> 2] | 0) != (i15 | 0)) {
+             _abort();
+            }
+            i20 = i19 + 8 | 0;
+            if ((HEAP32[i20 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i19;
+             HEAP32[i20 >> 2] = i18;
+             i5 = i19;
+             break;
+            } else {
+             _abort();
+            }
+           }
+          } while (0);
+          if ((i9 | 0) != 0) {
+           i16 = HEAP32[i17 + (i14 + 28 + i13) >> 2] | 0;
+           i18 = 7464 + (i16 << 2) | 0;
+           if ((i15 | 0) == (HEAP32[i18 >> 2] | 0)) {
+            HEAP32[i18 >> 2] = i5;
+            if ((i5 | 0) == 0) {
+             HEAP32[7164 >> 2] = HEAP32[7164 >> 2] & ~(1 << i16);
+             break;
+            }
+           } else {
+            if (i9 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i9 + 16 | 0;
+            if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i5;
+            } else {
+             HEAP32[i9 + 20 >> 2] = i5;
+            }
+            if ((i5 | 0) == 0) {
+             break;
+            }
+           }
+           if (i5 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           HEAP32[i5 + 24 >> 2] = i9;
+           i15 = i13 | 16;
+           i9 = HEAP32[i17 + (i15 + i14) >> 2] | 0;
+           do {
+            if ((i9 | 0) != 0) {
+             if (i9 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+              _abort();
+             } else {
+              HEAP32[i5 + 16 >> 2] = i9;
+              HEAP32[i9 + 24 >> 2] = i5;
+              break;
+             }
+            }
+           } while (0);
+           i9 = HEAP32[i17 + (i12 + i15) >> 2] | 0;
+           if ((i9 | 0) != 0) {
+            if (i9 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i5 + 20 >> 2] = i9;
+             HEAP32[i9 + 24 >> 2] = i5;
+             break;
+            }
+           }
+          }
+         } else {
+          i5 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+          i12 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          i18 = 7200 + (i16 << 1 << 2) | 0;
+          if ((i5 | 0) != (i18 | 0)) {
+           if (i5 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           if ((HEAP32[i5 + 12 >> 2] | 0) != (i15 | 0)) {
+            _abort();
+           }
+          }
+          if ((i12 | 0) == (i5 | 0)) {
+           HEAP32[1790] = HEAP32[1790] & ~(1 << i16);
+           break;
+          }
+          if ((i12 | 0) != (i18 | 0)) {
+           if (i12 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           i16 = i12 + 8 | 0;
+           if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+            i9 = i16;
+           } else {
+            _abort();
+           }
+          } else {
+           i9 = i12 + 8 | 0;
+          }
+          HEAP32[i5 + 12 >> 2] = i12;
+          HEAP32[i9 >> 2] = i5;
+         }
+        } while (0);
+        i15 = i17 + ((i11 | i13) + i14) | 0;
+        i10 = i11 + i10 | 0;
+       }
+       i5 = i15 + 4 | 0;
+       HEAP32[i5 >> 2] = HEAP32[i5 >> 2] & -2;
+       HEAP32[i17 + (i8 + 4) >> 2] = i10 | 1;
+       HEAP32[i17 + (i10 + i8) >> 2] = i10;
+       i5 = i10 >>> 3;
+       if (i10 >>> 0 < 256) {
+        i10 = i5 << 1;
+        i2 = 7200 + (i10 << 2) | 0;
+        i9 = HEAP32[1790] | 0;
+        i5 = 1 << i5;
+        if ((i9 & i5 | 0) != 0) {
+         i9 = 7200 + (i10 + 2 << 2) | 0;
+         i5 = HEAP32[i9 >> 2] | 0;
+         if (i5 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          i3 = i9;
+          i4 = i5;
+         }
+        } else {
+         HEAP32[1790] = i9 | i5;
+         i3 = 7200 + (i10 + 2 << 2) | 0;
+         i4 = i2;
+        }
+        HEAP32[i3 >> 2] = i7;
+        HEAP32[i4 + 12 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        break;
+       }
+       i3 = i10 >>> 8;
+       if ((i3 | 0) != 0) {
+        if (i10 >>> 0 > 16777215) {
+         i3 = 31;
+        } else {
+         i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+         i32 = i3 << i31;
+         i30 = (i32 + 520192 | 0) >>> 16 & 4;
+         i32 = i32 << i30;
+         i3 = (i32 + 245760 | 0) >>> 16 & 2;
+         i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+         i3 = i10 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+        }
+       } else {
+        i3 = 0;
+       }
+       i4 = 7464 + (i3 << 2) | 0;
+       HEAP32[i17 + (i8 + 28) >> 2] = i3;
+       HEAP32[i17 + (i8 + 20) >> 2] = 0;
+       HEAP32[i17 + (i8 + 16) >> 2] = 0;
+       i9 = HEAP32[7164 >> 2] | 0;
+       i5 = 1 << i3;
+       if ((i9 & i5 | 0) == 0) {
+        HEAP32[7164 >> 2] = i9 | i5;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 24) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i7;
+        break;
+       }
+       i4 = HEAP32[i4 >> 2] | 0;
+       if ((i3 | 0) == 31) {
+        i3 = 0;
+       } else {
+        i3 = 25 - (i3 >>> 1) | 0;
+       }
+       L444 : do {
+        if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i10 | 0)) {
+         i3 = i10 << i3;
+         while (1) {
+          i5 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+          i9 = HEAP32[i5 >> 2] | 0;
+          if ((i9 | 0) == 0) {
+           break;
+          }
+          if ((HEAP32[i9 + 4 >> 2] & -8 | 0) == (i10 | 0)) {
+           i2 = i9;
+           break L444;
+          } else {
+           i3 = i3 << 1;
+           i4 = i9;
+          }
+         }
+         if (i5 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i5 >> 2] = i7;
+          HEAP32[i17 + (i8 + 24) >> 2] = i4;
+          HEAP32[i17 + (i8 + 12) >> 2] = i7;
+          HEAP32[i17 + (i8 + 8) >> 2] = i7;
+          break L348;
+         }
+        } else {
+         i2 = i4;
+        }
+       } while (0);
+       i4 = i2 + 8 | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       i5 = HEAP32[7176 >> 2] | 0;
+       if (i2 >>> 0 < i5 >>> 0) {
+        _abort();
+       }
+       if (i3 >>> 0 < i5 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i3 + 12 >> 2] = i7;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i3;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        HEAP32[i17 + (i8 + 24) >> 2] = 0;
+        break;
+       }
+      } else {
+       i32 = (HEAP32[7172 >> 2] | 0) + i10 | 0;
+       HEAP32[7172 >> 2] = i32;
+       HEAP32[7184 >> 2] = i7;
+       HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+      }
+     } while (0);
+     i32 = i17 + (i6 | 8) | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i3 = 7608 | 0;
+    while (1) {
+     i2 = HEAP32[i3 >> 2] | 0;
+     if (!(i2 >>> 0 > i15 >>> 0) ? (i11 = HEAP32[i3 + 4 >> 2] | 0, i10 = i2 + i11 | 0, i10 >>> 0 > i15 >>> 0) : 0) {
+      break;
+     }
+     i3 = HEAP32[i3 + 8 >> 2] | 0;
+    }
+    i3 = i2 + (i11 + -39) | 0;
+    if ((i3 & 7 | 0) == 0) {
+     i3 = 0;
+    } else {
+     i3 = 0 - i3 & 7;
+    }
+    i2 = i2 + (i11 + -47 + i3) | 0;
+    i2 = i2 >>> 0 < (i15 + 16 | 0) >>> 0 ? i15 : i2;
+    i3 = i2 + 8 | 0;
+    i4 = i17 + 8 | 0;
+    if ((i4 & 7 | 0) == 0) {
+     i4 = 0;
+    } else {
+     i4 = 0 - i4 & 7;
+    }
+    i32 = i14 + -40 - i4 | 0;
+    HEAP32[7184 >> 2] = i17 + i4;
+    HEAP32[7172 >> 2] = i32;
+    HEAP32[i17 + (i4 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[7188 >> 2] = HEAP32[7648 >> 2];
+    HEAP32[i2 + 4 >> 2] = 27;
+    HEAP32[i3 + 0 >> 2] = HEAP32[7608 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[7612 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[7616 >> 2];
+    HEAP32[i3 + 12 >> 2] = HEAP32[7620 >> 2];
+    HEAP32[7608 >> 2] = i17;
+    HEAP32[7612 >> 2] = i14;
+    HEAP32[7620 >> 2] = 0;
+    HEAP32[7616 >> 2] = i3;
+    i4 = i2 + 28 | 0;
+    HEAP32[i4 >> 2] = 7;
+    if ((i2 + 32 | 0) >>> 0 < i10 >>> 0) {
+     while (1) {
+      i3 = i4 + 4 | 0;
+      HEAP32[i3 >> 2] = 7;
+      if ((i4 + 8 | 0) >>> 0 < i10 >>> 0) {
+       i4 = i3;
+      } else {
+       break;
+      }
+     }
+    }
+    if ((i2 | 0) != (i15 | 0)) {
+     i2 = i2 - i15 | 0;
+     i3 = i15 + (i2 + 4) | 0;
+     HEAP32[i3 >> 2] = HEAP32[i3 >> 2] & -2;
+     HEAP32[i15 + 4 >> 2] = i2 | 1;
+     HEAP32[i15 + i2 >> 2] = i2;
+     i3 = i2 >>> 3;
+     if (i2 >>> 0 < 256) {
+      i4 = i3 << 1;
+      i2 = 7200 + (i4 << 2) | 0;
+      i5 = HEAP32[1790] | 0;
+      i3 = 1 << i3;
+      if ((i5 & i3 | 0) != 0) {
+       i4 = 7200 + (i4 + 2 << 2) | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       if (i3 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i7 = i4;
+        i8 = i3;
+       }
+      } else {
+       HEAP32[1790] = i5 | i3;
+       i7 = 7200 + (i4 + 2 << 2) | 0;
+       i8 = i2;
+      }
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i8 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i8;
+      HEAP32[i15 + 12 >> 2] = i2;
+      break;
+     }
+     i3 = i2 >>> 8;
+     if ((i3 | 0) != 0) {
+      if (i2 >>> 0 > 16777215) {
+       i3 = 31;
+      } else {
+       i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+       i32 = i3 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i3 = (i32 + 245760 | 0) >>> 16 & 2;
+       i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+       i3 = i2 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+      }
+     } else {
+      i3 = 0;
+     }
+     i7 = 7464 + (i3 << 2) | 0;
+     HEAP32[i15 + 28 >> 2] = i3;
+     HEAP32[i15 + 20 >> 2] = 0;
+     HEAP32[i15 + 16 >> 2] = 0;
+     i4 = HEAP32[7164 >> 2] | 0;
+     i5 = 1 << i3;
+     if ((i4 & i5 | 0) == 0) {
+      HEAP32[7164 >> 2] = i4 | i5;
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i7;
+      HEAP32[i15 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i15;
+      break;
+     }
+     i4 = HEAP32[i7 >> 2] | 0;
+     if ((i3 | 0) == 31) {
+      i3 = 0;
+     } else {
+      i3 = 25 - (i3 >>> 1) | 0;
+     }
+     L499 : do {
+      if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i2 | 0)) {
+       i3 = i2 << i3;
+       while (1) {
+        i7 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+        i5 = HEAP32[i7 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         break;
+        }
+        if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i2 | 0)) {
+         i6 = i5;
+         break L499;
+        } else {
+         i3 = i3 << 1;
+         i4 = i5;
+        }
+       }
+       if (i7 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i7 >> 2] = i15;
+        HEAP32[i15 + 24 >> 2] = i4;
+        HEAP32[i15 + 12 >> 2] = i15;
+        HEAP32[i15 + 8 >> 2] = i15;
+        break L311;
+       }
+      } else {
+       i6 = i4;
+      }
+     } while (0);
+     i4 = i6 + 8 | 0;
+     i3 = HEAP32[i4 >> 2] | 0;
+     i2 = HEAP32[7176 >> 2] | 0;
+     if (i6 >>> 0 < i2 >>> 0) {
+      _abort();
+     }
+     if (i3 >>> 0 < i2 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i3 + 12 >> 2] = i15;
+      HEAP32[i4 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i3;
+      HEAP32[i15 + 12 >> 2] = i6;
+      HEAP32[i15 + 24 >> 2] = 0;
+      break;
+     }
+    }
+   } else {
+    i32 = HEAP32[7176 >> 2] | 0;
+    if ((i32 | 0) == 0 | i17 >>> 0 < i32 >>> 0) {
+     HEAP32[7176 >> 2] = i17;
+    }
+    HEAP32[7608 >> 2] = i17;
+    HEAP32[7612 >> 2] = i14;
+    HEAP32[7620 >> 2] = 0;
+    HEAP32[7196 >> 2] = HEAP32[1908];
+    HEAP32[7192 >> 2] = -1;
+    i2 = 0;
+    do {
+     i32 = i2 << 1;
+     i31 = 7200 + (i32 << 2) | 0;
+     HEAP32[7200 + (i32 + 3 << 2) >> 2] = i31;
+     HEAP32[7200 + (i32 + 2 << 2) >> 2] = i31;
+     i2 = i2 + 1 | 0;
+    } while ((i2 | 0) != 32);
+    i2 = i17 + 8 | 0;
+    if ((i2 & 7 | 0) == 0) {
+     i2 = 0;
+    } else {
+     i2 = 0 - i2 & 7;
+    }
+    i32 = i14 + -40 - i2 | 0;
+    HEAP32[7184 >> 2] = i17 + i2;
+    HEAP32[7172 >> 2] = i32;
+    HEAP32[i17 + (i2 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[7188 >> 2] = HEAP32[7648 >> 2];
+   }
+  } while (0);
+  i2 = HEAP32[7172 >> 2] | 0;
+  if (i2 >>> 0 > i12 >>> 0) {
+   i31 = i2 - i12 | 0;
+   HEAP32[7172 >> 2] = i31;
+   i32 = HEAP32[7184 >> 2] | 0;
+   HEAP32[7184 >> 2] = i32 + i12;
+   HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+   HEAP32[i32 + 4 >> 2] = i12 | 3;
+   i32 = i32 + 8 | 0;
+   STACKTOP = i1;
+   return i32 | 0;
+  }
+ }
+ HEAP32[(___errno_location() | 0) >> 2] = 12;
+ i32 = 0;
+ STACKTOP = i1;
+ return i32 | 0;
+}
+function __ZN12b2EPCollider7CollideEP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK14b2PolygonShapeS7_(i12, i2, i16, i5, i8, i6) {
+ i12 = i12 | 0;
+ i2 = i2 | 0;
+ i16 = i16 | 0;
+ i5 = i5 | 0;
+ i8 = i8 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i7 = 0, i9 = 0, i10 = 0, i11 = 0, i13 = 0, i14 = 0, i15 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, d22 = 0.0, d23 = 0.0, d24 = 0.0, d25 = 0.0, d26 = 0.0, d27 = 0.0, d28 = 0.0, i29 = 0, d30 = 0.0, d31 = 0.0, d32 = 0.0, d33 = 0.0, i34 = 0, i35 = 0, d36 = 0.0, d37 = 0.0, i38 = 0, d39 = 0.0, i40 = 0, i41 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 144 | 0;
+ i18 = i1 + 128 | 0;
+ i11 = i1 + 24 | 0;
+ i9 = i1 + 72 | 0;
+ i10 = i1 + 48 | 0;
+ i3 = i1;
+ i4 = i12 + 132 | 0;
+ d28 = +HEAPF32[i5 + 12 >> 2];
+ d37 = +HEAPF32[i6 + 8 >> 2];
+ d23 = +HEAPF32[i5 + 8 >> 2];
+ d27 = +HEAPF32[i6 + 12 >> 2];
+ d22 = d28 * d37 - d23 * d27;
+ d27 = d37 * d23 + d28 * d27;
+ d37 = +d22;
+ d26 = +d27;
+ d25 = +HEAPF32[i6 >> 2] - +HEAPF32[i5 >> 2];
+ d36 = +HEAPF32[i6 + 4 >> 2] - +HEAPF32[i5 + 4 >> 2];
+ d24 = d28 * d25 + d23 * d36;
+ d25 = d28 * d36 - d23 * d25;
+ d23 = +d24;
+ d36 = +d25;
+ i5 = i4;
+ HEAPF32[i5 >> 2] = d23;
+ HEAPF32[i5 + 4 >> 2] = d36;
+ i5 = i12 + 140 | 0;
+ HEAPF32[i5 >> 2] = d37;
+ HEAPF32[i5 + 4 >> 2] = d26;
+ i5 = i12 + 144 | 0;
+ d26 = +HEAPF32[i8 + 12 >> 2];
+ i7 = i12 + 140 | 0;
+ d37 = +HEAPF32[i8 + 16 >> 2];
+ d24 = d24 + (d27 * d26 - d22 * d37);
+ i6 = i12 + 136 | 0;
+ d25 = d26 * d22 + d27 * d37 + d25;
+ d37 = +d24;
+ d27 = +d25;
+ i34 = i12 + 148 | 0;
+ HEAPF32[i34 >> 2] = d37;
+ HEAPF32[i34 + 4 >> 2] = d27;
+ i34 = i16 + 28 | 0;
+ i29 = HEAP32[i34 >> 2] | 0;
+ i34 = HEAP32[i34 + 4 >> 2] | 0;
+ i14 = i12 + 156 | 0;
+ HEAP32[i14 >> 2] = i29;
+ HEAP32[i14 + 4 >> 2] = i34;
+ i14 = i12 + 164 | 0;
+ i17 = i16 + 12 | 0;
+ i40 = HEAP32[i17 >> 2] | 0;
+ i17 = HEAP32[i17 + 4 >> 2] | 0;
+ i13 = i14;
+ HEAP32[i13 >> 2] = i40;
+ HEAP32[i13 + 4 >> 2] = i17;
+ i13 = i12 + 172 | 0;
+ i20 = i16 + 20 | 0;
+ i41 = HEAP32[i20 >> 2] | 0;
+ i20 = HEAP32[i20 + 4 >> 2] | 0;
+ i38 = i13;
+ HEAP32[i38 >> 2] = i41;
+ HEAP32[i38 + 4 >> 2] = i20;
+ i38 = i16 + 36 | 0;
+ i35 = HEAP32[i38 >> 2] | 0;
+ i38 = HEAP32[i38 + 4 >> 2] | 0;
+ i19 = i12 + 180 | 0;
+ HEAP32[i19 >> 2] = i35;
+ HEAP32[i19 + 4 >> 2] = i38;
+ i19 = (HEAP8[i16 + 44 | 0] | 0) != 0;
+ i21 = (HEAP8[i16 + 45 | 0] | 0) != 0;
+ d27 = (HEAP32[tempDoublePtr >> 2] = i41, +HEAPF32[tempDoublePtr >> 2]);
+ d37 = (HEAP32[tempDoublePtr >> 2] = i40, +HEAPF32[tempDoublePtr >> 2]);
+ d22 = d27 - d37;
+ d26 = (HEAP32[tempDoublePtr >> 2] = i20, +HEAPF32[tempDoublePtr >> 2]);
+ i20 = i12 + 168 | 0;
+ d36 = (HEAP32[tempDoublePtr >> 2] = i17, +HEAPF32[tempDoublePtr >> 2]);
+ d23 = d26 - d36;
+ d28 = +Math_sqrt(+(d22 * d22 + d23 * d23));
+ d33 = (HEAP32[tempDoublePtr >> 2] = i29, +HEAPF32[tempDoublePtr >> 2]);
+ d32 = (HEAP32[tempDoublePtr >> 2] = i34, +HEAPF32[tempDoublePtr >> 2]);
+ d31 = (HEAP32[tempDoublePtr >> 2] = i35, +HEAPF32[tempDoublePtr >> 2]);
+ d30 = (HEAP32[tempDoublePtr >> 2] = i38, +HEAPF32[tempDoublePtr >> 2]);
+ if (!(d28 < 1.1920928955078125e-7)) {
+  d39 = 1.0 / d28;
+  d22 = d22 * d39;
+  d23 = d23 * d39;
+ }
+ i16 = i12 + 196 | 0;
+ d28 = -d22;
+ HEAPF32[i16 >> 2] = d23;
+ i17 = i12 + 200 | 0;
+ HEAPF32[i17 >> 2] = d28;
+ d28 = (d24 - d37) * d23 + (d25 - d36) * d28;
+ if (i19) {
+  d37 = d37 - d33;
+  d36 = d36 - d32;
+  d39 = +Math_sqrt(+(d37 * d37 + d36 * d36));
+  if (!(d39 < 1.1920928955078125e-7)) {
+   d39 = 1.0 / d39;
+   d37 = d37 * d39;
+   d36 = d36 * d39;
+  }
+  d39 = -d37;
+  HEAPF32[i12 + 188 >> 2] = d36;
+  HEAPF32[i12 + 192 >> 2] = d39;
+  i29 = d23 * d37 - d22 * d36 >= 0.0;
+  d32 = (d24 - d33) * d36 + (d25 - d32) * d39;
+ } else {
+  i29 = 0;
+  d32 = 0.0;
+ }
+ L10 : do {
+  if (!i21) {
+   if (!i19) {
+    i41 = d28 >= 0.0;
+    HEAP8[i12 + 248 | 0] = i41 & 1;
+    i19 = i12 + 212 | 0;
+    if (i41) {
+     i15 = 64;
+     break;
+    } else {
+     i15 = 65;
+     break;
+    }
+   }
+   i19 = d32 >= 0.0;
+   if (i29) {
+    if (!i19) {
+     i41 = d28 >= 0.0;
+     HEAP8[i12 + 248 | 0] = i41 & 1;
+     i19 = i12 + 212 | 0;
+     if (!i41) {
+      d37 = +-d23;
+      d39 = +d22;
+      i38 = i19;
+      HEAPF32[i38 >> 2] = d37;
+      HEAPF32[i38 + 4 >> 2] = d39;
+      i38 = i16;
+      i40 = HEAP32[i38 >> 2] | 0;
+      i38 = HEAP32[i38 + 4 >> 2] | 0;
+      i41 = i12 + 228 | 0;
+      HEAP32[i41 >> 2] = i40;
+      HEAP32[i41 + 4 >> 2] = i38;
+      i41 = i12 + 236 | 0;
+      HEAPF32[i41 >> 2] = -(HEAP32[tempDoublePtr >> 2] = i40, +HEAPF32[tempDoublePtr >> 2]);
+      HEAPF32[i41 + 4 >> 2] = d39;
+      break;
+     }
+    } else {
+     HEAP8[i12 + 248 | 0] = 1;
+     i19 = i12 + 212 | 0;
+    }
+    i41 = i16;
+    i40 = HEAP32[i41 + 4 >> 2] | 0;
+    i38 = i19;
+    HEAP32[i38 >> 2] = HEAP32[i41 >> 2];
+    HEAP32[i38 + 4 >> 2] = i40;
+    i38 = i12 + 188 | 0;
+    i40 = HEAP32[i38 + 4 >> 2] | 0;
+    i41 = i12 + 228 | 0;
+    HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+    HEAP32[i41 + 4 >> 2] = i40;
+    d37 = +-+HEAPF32[i16 >> 2];
+    d39 = +-+HEAPF32[i17 >> 2];
+    i41 = i12 + 236 | 0;
+    HEAPF32[i41 >> 2] = d37;
+    HEAPF32[i41 + 4 >> 2] = d39;
+    break;
+   } else {
+    if (i19) {
+     i41 = d28 >= 0.0;
+     HEAP8[i12 + 248 | 0] = i41 & 1;
+     i19 = i12 + 212 | 0;
+     if (i41) {
+      i38 = i16;
+      i41 = HEAP32[i38 >> 2] | 0;
+      i38 = HEAP32[i38 + 4 >> 2] | 0;
+      i40 = i19;
+      HEAP32[i40 >> 2] = i41;
+      HEAP32[i40 + 4 >> 2] = i38;
+      i40 = i12 + 228 | 0;
+      HEAP32[i40 >> 2] = i41;
+      HEAP32[i40 + 4 >> 2] = i38;
+      d37 = +-(HEAP32[tempDoublePtr >> 2] = i41, +HEAPF32[tempDoublePtr >> 2]);
+      d39 = +d22;
+      i41 = i12 + 236 | 0;
+      HEAPF32[i41 >> 2] = d37;
+      HEAPF32[i41 + 4 >> 2] = d39;
+      break;
+     }
+    } else {
+     HEAP8[i12 + 248 | 0] = 0;
+     i19 = i12 + 212 | 0;
+    }
+    d39 = +-d23;
+    d37 = +d22;
+    i38 = i19;
+    HEAPF32[i38 >> 2] = d39;
+    HEAPF32[i38 + 4 >> 2] = d37;
+    i38 = i16;
+    i40 = HEAP32[i38 + 4 >> 2] | 0;
+    i41 = i12 + 228 | 0;
+    HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+    HEAP32[i41 + 4 >> 2] = i40;
+    d37 = +-+HEAPF32[i12 + 188 >> 2];
+    d39 = +-+HEAPF32[i12 + 192 >> 2];
+    i41 = i12 + 236 | 0;
+    HEAPF32[i41 >> 2] = d37;
+    HEAPF32[i41 + 4 >> 2] = d39;
+    break;
+   }
+  } else {
+   d33 = d31 - d27;
+   d31 = d30 - d26;
+   d30 = +Math_sqrt(+(d33 * d33 + d31 * d31));
+   if (d30 < 1.1920928955078125e-7) {
+    d30 = d33;
+   } else {
+    d39 = 1.0 / d30;
+    d30 = d33 * d39;
+    d31 = d31 * d39;
+   }
+   d39 = -d30;
+   i34 = i12 + 204 | 0;
+   HEAPF32[i34 >> 2] = d31;
+   i35 = i12 + 208 | 0;
+   HEAPF32[i35 >> 2] = d39;
+   i38 = d22 * d31 - d23 * d30 > 0.0;
+   d24 = (d24 - d27) * d31 + (d25 - d26) * d39;
+   if (!i19) {
+    i19 = d28 >= 0.0;
+    if (!i21) {
+     HEAP8[i12 + 248 | 0] = i19 & 1;
+     i15 = i12 + 212 | 0;
+     if (i19) {
+      i19 = i15;
+      i15 = 64;
+      break;
+     } else {
+      i19 = i15;
+      i15 = 65;
+      break;
+     }
+    }
+    if (i38) {
+     if (!i19) {
+      i41 = d24 >= 0.0;
+      HEAP8[i12 + 248 | 0] = i41 & 1;
+      i19 = i12 + 212 | 0;
+      if (!i41) {
+       d37 = +-d23;
+       d39 = +d22;
+       i38 = i19;
+       HEAPF32[i38 >> 2] = d37;
+       HEAPF32[i38 + 4 >> 2] = d39;
+       i38 = i12 + 228 | 0;
+       HEAPF32[i38 >> 2] = d37;
+       HEAPF32[i38 + 4 >> 2] = d39;
+       i38 = i16;
+       i40 = HEAP32[i38 + 4 >> 2] | 0;
+       i41 = i12 + 236 | 0;
+       HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+       HEAP32[i41 + 4 >> 2] = i40;
+       break;
+      }
+     } else {
+      HEAP8[i12 + 248 | 0] = 1;
+      i19 = i12 + 212 | 0;
+     }
+     i41 = i16;
+     i40 = HEAP32[i41 + 4 >> 2] | 0;
+     i38 = i19;
+     HEAP32[i38 >> 2] = HEAP32[i41 >> 2];
+     HEAP32[i38 + 4 >> 2] = i40;
+     d37 = +-+HEAPF32[i16 >> 2];
+     d39 = +-+HEAPF32[i17 >> 2];
+     i38 = i12 + 228 | 0;
+     HEAPF32[i38 >> 2] = d37;
+     HEAPF32[i38 + 4 >> 2] = d39;
+     i38 = i12 + 204 | 0;
+     i40 = HEAP32[i38 + 4 >> 2] | 0;
+     i41 = i12 + 236 | 0;
+     HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+     HEAP32[i41 + 4 >> 2] = i40;
+     break;
+    } else {
+     if (i19) {
+      i41 = d24 >= 0.0;
+      HEAP8[i12 + 248 | 0] = i41 & 1;
+      i19 = i12 + 212 | 0;
+      if (i41) {
+       i40 = i16;
+       i38 = HEAP32[i40 >> 2] | 0;
+       i40 = HEAP32[i40 + 4 >> 2] | 0;
+       i41 = i19;
+       HEAP32[i41 >> 2] = i38;
+       HEAP32[i41 + 4 >> 2] = i40;
+       d37 = +-(HEAP32[tempDoublePtr >> 2] = i38, +HEAPF32[tempDoublePtr >> 2]);
+       d39 = +d22;
+       i41 = i12 + 228 | 0;
+       HEAPF32[i41 >> 2] = d37;
+       HEAPF32[i41 + 4 >> 2] = d39;
+       i41 = i12 + 236 | 0;
+       HEAP32[i41 >> 2] = i38;
+       HEAP32[i41 + 4 >> 2] = i40;
+       break;
+      }
+     } else {
+      HEAP8[i12 + 248 | 0] = 0;
+      i19 = i12 + 212 | 0;
+     }
+     d39 = +-d23;
+     d37 = +d22;
+     i38 = i19;
+     HEAPF32[i38 >> 2] = d39;
+     HEAPF32[i38 + 4 >> 2] = d37;
+     d37 = +-+HEAPF32[i12 + 204 >> 2];
+     d39 = +-+HEAPF32[i12 + 208 >> 2];
+     i38 = i12 + 228 | 0;
+     HEAPF32[i38 >> 2] = d37;
+     HEAPF32[i38 + 4 >> 2] = d39;
+     i38 = i16;
+     i40 = HEAP32[i38 + 4 >> 2] | 0;
+     i41 = i12 + 236 | 0;
+     HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+     HEAP32[i41 + 4 >> 2] = i40;
+     break;
+    }
+   }
+   if (i29 & i38) {
+    if (!(d32 >= 0.0) & !(d28 >= 0.0)) {
+     i41 = d24 >= 0.0;
+     HEAP8[i12 + 248 | 0] = i41 & 1;
+     i19 = i12 + 212 | 0;
+     if (!i41) {
+      d37 = +-d23;
+      d39 = +d22;
+      i41 = i19;
+      HEAPF32[i41 >> 2] = d37;
+      HEAPF32[i41 + 4 >> 2] = d39;
+      i41 = i12 + 228 | 0;
+      HEAPF32[i41 >> 2] = d37;
+      HEAPF32[i41 + 4 >> 2] = d39;
+      i41 = i12 + 236 | 0;
+      HEAPF32[i41 >> 2] = d37;
+      HEAPF32[i41 + 4 >> 2] = d39;
+      break;
+     }
+    } else {
+     HEAP8[i12 + 248 | 0] = 1;
+     i19 = i12 + 212 | 0;
+    }
+    i38 = i16;
+    i40 = HEAP32[i38 + 4 >> 2] | 0;
+    i41 = i19;
+    HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+    HEAP32[i41 + 4 >> 2] = i40;
+    i41 = i12 + 188 | 0;
+    i40 = HEAP32[i41 + 4 >> 2] | 0;
+    i38 = i12 + 228 | 0;
+    HEAP32[i38 >> 2] = HEAP32[i41 >> 2];
+    HEAP32[i38 + 4 >> 2] = i40;
+    i38 = i12 + 204 | 0;
+    i40 = HEAP32[i38 + 4 >> 2] | 0;
+    i41 = i12 + 236 | 0;
+    HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+    HEAP32[i41 + 4 >> 2] = i40;
+    break;
+   }
+   if (i29) {
+    do {
+     if (!(d32 >= 0.0)) {
+      if (d28 >= 0.0) {
+       i41 = d24 >= 0.0;
+       HEAP8[i12 + 248 | 0] = i41 & 1;
+       i19 = i12 + 212 | 0;
+       if (i41) {
+        break;
+       }
+      } else {
+       HEAP8[i12 + 248 | 0] = 0;
+       i19 = i12 + 212 | 0;
+      }
+      d37 = +-d23;
+      d39 = +d22;
+      i41 = i19;
+      HEAPF32[i41 >> 2] = d37;
+      HEAPF32[i41 + 4 >> 2] = d39;
+      d39 = +-+HEAPF32[i34 >> 2];
+      d37 = +-+HEAPF32[i35 >> 2];
+      i41 = i12 + 228 | 0;
+      HEAPF32[i41 >> 2] = d39;
+      HEAPF32[i41 + 4 >> 2] = d37;
+      d37 = +-+HEAPF32[i16 >> 2];
+      d39 = +-+HEAPF32[i17 >> 2];
+      i41 = i12 + 236 | 0;
+      HEAPF32[i41 >> 2] = d37;
+      HEAPF32[i41 + 4 >> 2] = d39;
+      break L10;
+     } else {
+      HEAP8[i12 + 248 | 0] = 1;
+      i19 = i12 + 212 | 0;
+     }
+    } while (0);
+    i38 = i16;
+    i40 = HEAP32[i38 + 4 >> 2] | 0;
+    i41 = i19;
+    HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+    HEAP32[i41 + 4 >> 2] = i40;
+    i41 = i12 + 188 | 0;
+    i40 = HEAP32[i41 + 4 >> 2] | 0;
+    i38 = i12 + 228 | 0;
+    HEAP32[i38 >> 2] = HEAP32[i41 >> 2];
+    HEAP32[i38 + 4 >> 2] = i40;
+    i38 = i16;
+    i40 = HEAP32[i38 + 4 >> 2] | 0;
+    i41 = i12 + 236 | 0;
+    HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+    HEAP32[i41 + 4 >> 2] = i40;
+    break;
+   }
+   if (!i38) {
+    if (!(!(d32 >= 0.0) | !(d28 >= 0.0))) {
+     i41 = d24 >= 0.0;
+     HEAP8[i12 + 248 | 0] = i41 & 1;
+     i19 = i12 + 212 | 0;
+     if (i41) {
+      i40 = i16;
+      i38 = HEAP32[i40 >> 2] | 0;
+      i40 = HEAP32[i40 + 4 >> 2] | 0;
+      i41 = i19;
+      HEAP32[i41 >> 2] = i38;
+      HEAP32[i41 + 4 >> 2] = i40;
+      i41 = i12 + 228 | 0;
+      HEAP32[i41 >> 2] = i38;
+      HEAP32[i41 + 4 >> 2] = i40;
+      i41 = i12 + 236 | 0;
+      HEAP32[i41 >> 2] = i38;
+      HEAP32[i41 + 4 >> 2] = i40;
+      break;
+     }
+    } else {
+     HEAP8[i12 + 248 | 0] = 0;
+     i19 = i12 + 212 | 0;
+    }
+    d37 = +-d23;
+    d39 = +d22;
+    i41 = i19;
+    HEAPF32[i41 >> 2] = d37;
+    HEAPF32[i41 + 4 >> 2] = d39;
+    d39 = +-+HEAPF32[i34 >> 2];
+    d37 = +-+HEAPF32[i35 >> 2];
+    i41 = i12 + 228 | 0;
+    HEAPF32[i41 >> 2] = d39;
+    HEAPF32[i41 + 4 >> 2] = d37;
+    d37 = +-+HEAPF32[i12 + 188 >> 2];
+    d39 = +-+HEAPF32[i12 + 192 >> 2];
+    i41 = i12 + 236 | 0;
+    HEAPF32[i41 >> 2] = d37;
+    HEAPF32[i41 + 4 >> 2] = d39;
+    break;
+   }
+   do {
+    if (!(d24 >= 0.0)) {
+     if (d32 >= 0.0) {
+      i41 = d28 >= 0.0;
+      HEAP8[i12 + 248 | 0] = i41 & 1;
+      i19 = i12 + 212 | 0;
+      if (i41) {
+       break;
+      }
+     } else {
+      HEAP8[i12 + 248 | 0] = 0;
+      i19 = i12 + 212 | 0;
+     }
+     d37 = +-d23;
+     d39 = +d22;
+     i41 = i19;
+     HEAPF32[i41 >> 2] = d37;
+     HEAPF32[i41 + 4 >> 2] = d39;
+     d39 = +-+HEAPF32[i16 >> 2];
+     d37 = +-+HEAPF32[i17 >> 2];
+     i41 = i12 + 228 | 0;
+     HEAPF32[i41 >> 2] = d39;
+     HEAPF32[i41 + 4 >> 2] = d37;
+     d37 = +-+HEAPF32[i12 + 188 >> 2];
+     d39 = +-+HEAPF32[i12 + 192 >> 2];
+     i41 = i12 + 236 | 0;
+     HEAPF32[i41 >> 2] = d37;
+     HEAPF32[i41 + 4 >> 2] = d39;
+     break L10;
+    } else {
+     HEAP8[i12 + 248 | 0] = 1;
+     i19 = i12 + 212 | 0;
+    }
+   } while (0);
+   i38 = i16;
+   i40 = HEAP32[i38 + 4 >> 2] | 0;
+   i41 = i19;
+   HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+   HEAP32[i41 + 4 >> 2] = i40;
+   i41 = i16;
+   i40 = HEAP32[i41 + 4 >> 2] | 0;
+   i38 = i12 + 228 | 0;
+   HEAP32[i38 >> 2] = HEAP32[i41 >> 2];
+   HEAP32[i38 + 4 >> 2] = i40;
+   i38 = i12 + 204 | 0;
+   i40 = HEAP32[i38 + 4 >> 2] | 0;
+   i41 = i12 + 236 | 0;
+   HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+   HEAP32[i41 + 4 >> 2] = i40;
+  }
+ } while (0);
+ if ((i15 | 0) == 64) {
+  i38 = i16;
+  i41 = HEAP32[i38 >> 2] | 0;
+  i38 = HEAP32[i38 + 4 >> 2] | 0;
+  i40 = i19;
+  HEAP32[i40 >> 2] = i41;
+  HEAP32[i40 + 4 >> 2] = i38;
+  d37 = +-(HEAP32[tempDoublePtr >> 2] = i41, +HEAPF32[tempDoublePtr >> 2]);
+  d39 = +d22;
+  i41 = i12 + 228 | 0;
+  HEAPF32[i41 >> 2] = d37;
+  HEAPF32[i41 + 4 >> 2] = d39;
+  i41 = i12 + 236 | 0;
+  HEAPF32[i41 >> 2] = d37;
+  HEAPF32[i41 + 4 >> 2] = d39;
+ } else if ((i15 | 0) == 65) {
+  d37 = +-d23;
+  d39 = +d22;
+  i40 = i19;
+  HEAPF32[i40 >> 2] = d37;
+  HEAPF32[i40 + 4 >> 2] = d39;
+  i40 = i16;
+  i38 = HEAP32[i40 >> 2] | 0;
+  i40 = HEAP32[i40 + 4 >> 2] | 0;
+  i41 = i12 + 228 | 0;
+  HEAP32[i41 >> 2] = i38;
+  HEAP32[i41 + 4 >> 2] = i40;
+  i41 = i12 + 236 | 0;
+  HEAP32[i41 >> 2] = i38;
+  HEAP32[i41 + 4 >> 2] = i40;
+ }
+ i21 = i8 + 148 | 0;
+ i34 = i12 + 128 | 0;
+ HEAP32[i34 >> 2] = HEAP32[i21 >> 2];
+ if ((HEAP32[i21 >> 2] | 0) > 0) {
+  i19 = 0;
+  do {
+   d33 = +HEAPF32[i5 >> 2];
+   d37 = +HEAPF32[i8 + (i19 << 3) + 20 >> 2];
+   d39 = +HEAPF32[i7 >> 2];
+   d36 = +HEAPF32[i8 + (i19 << 3) + 24 >> 2];
+   d32 = +(+HEAPF32[i4 >> 2] + (d33 * d37 - d39 * d36));
+   d36 = +(d37 * d39 + d33 * d36 + +HEAPF32[i6 >> 2]);
+   i41 = i12 + (i19 << 3) | 0;
+   HEAPF32[i41 >> 2] = d32;
+   HEAPF32[i41 + 4 >> 2] = d36;
+   d36 = +HEAPF32[i5 >> 2];
+   d32 = +HEAPF32[i8 + (i19 << 3) + 84 >> 2];
+   d33 = +HEAPF32[i7 >> 2];
+   d39 = +HEAPF32[i8 + (i19 << 3) + 88 >> 2];
+   d37 = +(d36 * d32 - d33 * d39);
+   d39 = +(d32 * d33 + d36 * d39);
+   i41 = i12 + (i19 << 3) + 64 | 0;
+   HEAPF32[i41 >> 2] = d37;
+   HEAPF32[i41 + 4 >> 2] = d39;
+   i19 = i19 + 1 | 0;
+  } while ((i19 | 0) < (HEAP32[i21 >> 2] | 0));
+ }
+ i21 = i12 + 244 | 0;
+ HEAPF32[i21 >> 2] = .019999999552965164;
+ i19 = i2 + 60 | 0;
+ HEAP32[i19 >> 2] = 0;
+ i29 = i12 + 248 | 0;
+ i35 = HEAP32[i34 >> 2] | 0;
+ if ((i35 | 0) <= 0) {
+  STACKTOP = i1;
+  return;
+ }
+ d23 = +HEAPF32[i12 + 164 >> 2];
+ d26 = +HEAPF32[i20 >> 2];
+ d24 = +HEAPF32[i12 + 212 >> 2];
+ d27 = +HEAPF32[i12 + 216 >> 2];
+ d22 = 3.4028234663852886e+38;
+ i20 = 0;
+ do {
+  d25 = d24 * (+HEAPF32[i12 + (i20 << 3) >> 2] - d23) + d27 * (+HEAPF32[i12 + (i20 << 3) + 4 >> 2] - d26);
+  d22 = d25 < d22 ? d25 : d22;
+  i20 = i20 + 1 | 0;
+ } while ((i20 | 0) != (i35 | 0));
+ if (d22 > .019999999552965164) {
+  STACKTOP = i1;
+  return;
+ }
+ __ZN12b2EPCollider24ComputePolygonSeparationEv(i18, i12);
+ i20 = HEAP32[i18 >> 2] | 0;
+ if ((i20 | 0) != 0) {
+  d23 = +HEAPF32[i18 + 8 >> 2];
+  if (d23 > +HEAPF32[i21 >> 2]) {
+   STACKTOP = i1;
+   return;
+  }
+  if (d23 > d22 * .9800000190734863 + .0010000000474974513) {
+   i18 = HEAP32[i18 + 4 >> 2] | 0;
+   i35 = i2 + 56 | 0;
+   if ((i20 | 0) == 1) {
+    i18 = i11;
+    i15 = 77;
+   } else {
+    HEAP32[i35 >> 2] = 2;
+    i40 = i14;
+    i41 = HEAP32[i40 + 4 >> 2] | 0;
+    i38 = i11;
+    HEAP32[i38 >> 2] = HEAP32[i40 >> 2];
+    HEAP32[i38 + 4 >> 2] = i41;
+    i38 = i11 + 8 | 0;
+    HEAP8[i38] = 0;
+    i41 = i18 & 255;
+    HEAP8[i38 + 1 | 0] = i41;
+    HEAP8[i38 + 2 | 0] = 0;
+    HEAP8[i38 + 3 | 0] = 1;
+    i38 = i13;
+    i40 = HEAP32[i38 + 4 >> 2] | 0;
+    i13 = i11 + 12 | 0;
+    HEAP32[i13 >> 2] = HEAP32[i38 >> 2];
+    HEAP32[i13 + 4 >> 2] = i40;
+    i13 = i11 + 20 | 0;
+    HEAP8[i13] = 0;
+    HEAP8[i13 + 1 | 0] = i41;
+    HEAP8[i13 + 2 | 0] = 0;
+    HEAP8[i13 + 3 | 0] = 1;
+    HEAP32[i9 >> 2] = i18;
+    i13 = i18 + 1 | 0;
+    i16 = (i13 | 0) < (HEAP32[i34 >> 2] | 0) ? i13 : 0;
+    HEAP32[i9 + 4 >> 2] = i16;
+    i17 = i12 + (i18 << 3) | 0;
+    i13 = HEAP32[i17 >> 2] | 0;
+    i17 = HEAP32[i17 + 4 >> 2] | 0;
+    i29 = i9 + 8 | 0;
+    HEAP32[i29 >> 2] = i13;
+    HEAP32[i29 + 4 >> 2] = i17;
+    i16 = i12 + (i16 << 3) | 0;
+    i29 = HEAP32[i16 >> 2] | 0;
+    i16 = HEAP32[i16 + 4 >> 2] | 0;
+    i20 = i9 + 16 | 0;
+    HEAP32[i20 >> 2] = i29;
+    HEAP32[i20 + 4 >> 2] = i16;
+    i20 = i12 + (i18 << 3) + 64 | 0;
+    i12 = HEAP32[i20 >> 2] | 0;
+    i20 = HEAP32[i20 + 4 >> 2] | 0;
+    i14 = i9 + 24 | 0;
+    HEAP32[i14 >> 2] = i12;
+    HEAP32[i14 + 4 >> 2] = i20;
+    i14 = 0;
+   }
+  } else {
+   i15 = 75;
+  }
+ } else {
+  i15 = 75;
+ }
+ if ((i15 | 0) == 75) {
+  i18 = i11;
+  i35 = i2 + 56 | 0;
+  i15 = 77;
+ }
+ do {
+  if ((i15 | 0) == 77) {
+   HEAP32[i35 >> 2] = 1;
+   i15 = HEAP32[i34 >> 2] | 0;
+   if ((i15 | 0) > 1) {
+    d23 = +HEAPF32[i12 + 216 >> 2];
+    d22 = +HEAPF32[i12 + 212 >> 2];
+    i34 = 0;
+    d24 = d22 * +HEAPF32[i12 + 64 >> 2] + d23 * +HEAPF32[i12 + 68 >> 2];
+    i35 = 1;
+    while (1) {
+     d25 = d22 * +HEAPF32[i12 + (i35 << 3) + 64 >> 2] + d23 * +HEAPF32[i12 + (i35 << 3) + 68 >> 2];
+     i20 = d25 < d24;
+     i34 = i20 ? i35 : i34;
+     i35 = i35 + 1 | 0;
+     if ((i35 | 0) < (i15 | 0)) {
+      d24 = i20 ? d25 : d24;
+     } else {
+      break;
+     }
+    }
+   } else {
+    i34 = 0;
+   }
+   i20 = i34 + 1 | 0;
+   i40 = (i20 | 0) < (i15 | 0) ? i20 : 0;
+   i41 = i12 + (i34 << 3) | 0;
+   i38 = HEAP32[i41 + 4 >> 2] | 0;
+   i35 = i11;
+   HEAP32[i35 >> 2] = HEAP32[i41 >> 2];
+   HEAP32[i35 + 4 >> 2] = i38;
+   i35 = i11 + 8 | 0;
+   HEAP8[i35] = 0;
+   HEAP8[i35 + 1 | 0] = i34;
+   HEAP8[i35 + 2 | 0] = 1;
+   HEAP8[i35 + 3 | 0] = 0;
+   i35 = i12 + (i40 << 3) | 0;
+   i38 = HEAP32[i35 + 4 >> 2] | 0;
+   i41 = i11 + 12 | 0;
+   HEAP32[i41 >> 2] = HEAP32[i35 >> 2];
+   HEAP32[i41 + 4 >> 2] = i38;
+   i41 = i11 + 20 | 0;
+   HEAP8[i41] = 0;
+   HEAP8[i41 + 1 | 0] = i40;
+   HEAP8[i41 + 2 | 0] = 1;
+   HEAP8[i41 + 3 | 0] = 0;
+   if ((HEAP8[i29] | 0) == 0) {
+    HEAP32[i9 >> 2] = 1;
+    HEAP32[i9 + 4 >> 2] = 0;
+    i11 = i13;
+    i13 = HEAP32[i11 >> 2] | 0;
+    i11 = HEAP32[i11 + 4 >> 2] | 0;
+    i29 = i9 + 8 | 0;
+    HEAP32[i29 >> 2] = i13;
+    HEAP32[i29 + 4 >> 2] = i11;
+    i29 = HEAP32[i14 >> 2] | 0;
+    i14 = HEAP32[i14 + 4 >> 2] | 0;
+    i12 = i9 + 16 | 0;
+    HEAP32[i12 >> 2] = i29;
+    HEAP32[i12 + 4 >> 2] = i14;
+    i12 = (HEAPF32[tempDoublePtr >> 2] = -+HEAPF32[i16 >> 2], HEAP32[tempDoublePtr >> 2] | 0);
+    i20 = (HEAPF32[tempDoublePtr >> 2] = -+HEAPF32[i17 >> 2], HEAP32[tempDoublePtr >> 2] | 0);
+    i16 = i9 + 24 | 0;
+    HEAP32[i16 >> 2] = i12;
+    HEAP32[i16 + 4 >> 2] = i20;
+    i16 = i14;
+    i17 = i11;
+    i11 = i18;
+    i18 = 1;
+    i14 = 1;
+    break;
+   } else {
+    HEAP32[i9 >> 2] = 0;
+    HEAP32[i9 + 4 >> 2] = 1;
+    i17 = i14;
+    i11 = HEAP32[i17 >> 2] | 0;
+    i17 = HEAP32[i17 + 4 >> 2] | 0;
+    i29 = i9 + 8 | 0;
+    HEAP32[i29 >> 2] = i11;
+    HEAP32[i29 + 4 >> 2] = i17;
+    i29 = HEAP32[i13 >> 2] | 0;
+    i13 = HEAP32[i13 + 4 >> 2] | 0;
+    i20 = i9 + 16 | 0;
+    HEAP32[i20 >> 2] = i29;
+    HEAP32[i20 + 4 >> 2] = i13;
+    i20 = i16;
+    i12 = HEAP32[i20 >> 2] | 0;
+    i20 = HEAP32[i20 + 4 >> 2] | 0;
+    i16 = i9 + 24 | 0;
+    HEAP32[i16 >> 2] = i12;
+    HEAP32[i16 + 4 >> 2] = i20;
+    i16 = i13;
+    i13 = i11;
+    i11 = i18;
+    i18 = 0;
+    i14 = 1;
+    break;
+   }
+  }
+ } while (0);
+ d30 = (HEAP32[tempDoublePtr >> 2] = i20, +HEAPF32[tempDoublePtr >> 2]);
+ d39 = (HEAP32[tempDoublePtr >> 2] = i12, +HEAPF32[tempDoublePtr >> 2]);
+ d31 = (HEAP32[tempDoublePtr >> 2] = i13, +HEAPF32[tempDoublePtr >> 2]);
+ d32 = (HEAP32[tempDoublePtr >> 2] = i17, +HEAPF32[tempDoublePtr >> 2]);
+ d33 = (HEAP32[tempDoublePtr >> 2] = i29, +HEAPF32[tempDoublePtr >> 2]);
+ d37 = (HEAP32[tempDoublePtr >> 2] = i16, +HEAPF32[tempDoublePtr >> 2]);
+ i41 = i9 + 32 | 0;
+ i16 = i9 + 24 | 0;
+ i13 = i9 + 28 | 0;
+ d39 = -d39;
+ HEAPF32[i41 >> 2] = d30;
+ HEAPF32[i9 + 36 >> 2] = d39;
+ i20 = i9 + 44 | 0;
+ d36 = -d30;
+ i17 = i20;
+ HEAPF32[i17 >> 2] = d36;
+ HEAP32[i17 + 4 >> 2] = i12;
+ i17 = i9 + 8 | 0;
+ i15 = i9 + 12 | 0;
+ d39 = d30 * d31 + d32 * d39;
+ HEAPF32[i9 + 40 >> 2] = d39;
+ i29 = i9 + 52 | 0;
+ HEAPF32[i29 >> 2] = d33 * d36 + (HEAP32[tempDoublePtr >> 2] = i12, +HEAPF32[tempDoublePtr >> 2]) * d37;
+ if ((__Z19b2ClipSegmentToLineP12b2ClipVertexPKS_RK6b2Vec2fi(i10, i11, i41, d39, i18) | 0) < 2) {
+  STACKTOP = i1;
+  return;
+ }
+ if ((__Z19b2ClipSegmentToLineP12b2ClipVertexPKS_RK6b2Vec2fi(i3, i10, i20, +HEAPF32[i29 >> 2], HEAP32[i9 + 4 >> 2] | 0) | 0) < 2) {
+  STACKTOP = i1;
+  return;
+ }
+ i10 = i2 + 40 | 0;
+ if (i14) {
+  i40 = i16;
+  i41 = HEAP32[i40 >> 2] | 0;
+  i40 = HEAP32[i40 + 4 >> 2] | 0;
+  i35 = i10;
+  HEAP32[i35 >> 2] = i41;
+  HEAP32[i35 + 4 >> 2] = i40;
+  i35 = i17;
+  i40 = HEAP32[i35 >> 2] | 0;
+  i35 = HEAP32[i35 + 4 >> 2] | 0;
+  i38 = i2 + 48 | 0;
+  HEAP32[i38 >> 2] = i40;
+  HEAP32[i38 + 4 >> 2] = i35;
+  d23 = (HEAP32[tempDoublePtr >> 2] = i40, +HEAPF32[tempDoublePtr >> 2]);
+  d22 = (HEAP32[tempDoublePtr >> 2] = i41, +HEAPF32[tempDoublePtr >> 2]);
+  d24 = +HEAPF32[i15 >> 2];
+  d25 = +HEAPF32[i13 >> 2];
+  d28 = +HEAPF32[i3 >> 2];
+  d27 = +HEAPF32[i3 + 4 >> 2];
+  d26 = +HEAPF32[i21 >> 2];
+  if (!((d28 - d23) * d22 + (d27 - d24) * d25 <= d26)) {
+   d28 = d26;
+   i8 = 0;
+  } else {
+   d37 = d28 - +HEAPF32[i4 >> 2];
+   d36 = d27 - +HEAPF32[i6 >> 2];
+   d33 = +HEAPF32[i5 >> 2];
+   d28 = +HEAPF32[i7 >> 2];
+   d39 = +(d37 * d33 + d36 * d28);
+   d28 = +(d33 * d36 - d37 * d28);
+   i8 = i2;
+   HEAPF32[i8 >> 2] = d39;
+   HEAPF32[i8 + 4 >> 2] = d28;
+   HEAP32[i2 + 16 >> 2] = HEAP32[i3 + 8 >> 2];
+   d28 = +HEAPF32[i21 >> 2];
+   i8 = 1;
+  }
+  d26 = +HEAPF32[i3 + 12 >> 2];
+  d27 = +HEAPF32[i3 + 16 >> 2];
+  if ((d26 - d23) * d22 + (d27 - d24) * d25 <= d28) {
+   d36 = d26 - +HEAPF32[i4 >> 2];
+   d33 = d27 - +HEAPF32[i6 >> 2];
+   d32 = +HEAPF32[i5 >> 2];
+   d39 = +HEAPF32[i7 >> 2];
+   d37 = +(d36 * d32 + d33 * d39);
+   d39 = +(d32 * d33 - d36 * d39);
+   i41 = i2 + (i8 * 20 | 0) | 0;
+   HEAPF32[i41 >> 2] = d37;
+   HEAPF32[i41 + 4 >> 2] = d39;
+   HEAP32[i2 + (i8 * 20 | 0) + 16 >> 2] = HEAP32[i3 + 20 >> 2];
+   i8 = i8 + 1 | 0;
+  }
+ } else {
+  i38 = HEAP32[i9 >> 2] | 0;
+  i35 = i8 + (i38 << 3) + 84 | 0;
+  i41 = HEAP32[i35 + 4 >> 2] | 0;
+  i40 = i10;
+  HEAP32[i40 >> 2] = HEAP32[i35 >> 2];
+  HEAP32[i40 + 4 >> 2] = i41;
+  i38 = i8 + (i38 << 3) + 20 | 0;
+  i40 = HEAP32[i38 + 4 >> 2] | 0;
+  i41 = i2 + 48 | 0;
+  HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+  HEAP32[i41 + 4 >> 2] = i40;
+  d22 = +HEAPF32[i17 >> 2];
+  d23 = +HEAPF32[i16 >> 2];
+  d24 = +HEAPF32[i15 >> 2];
+  d25 = +HEAPF32[i13 >> 2];
+  d26 = +HEAPF32[i21 >> 2];
+  if (!((+HEAPF32[i3 >> 2] - d22) * d23 + (+HEAPF32[i3 + 4 >> 2] - d24) * d25 <= d26)) {
+   i8 = 0;
+  } else {
+   i40 = i3;
+   i8 = HEAP32[i40 + 4 >> 2] | 0;
+   i41 = i2;
+   HEAP32[i41 >> 2] = HEAP32[i40 >> 2];
+   HEAP32[i41 + 4 >> 2] = i8;
+   i41 = i3 + 8 | 0;
+   i8 = i2 + 16 | 0;
+   HEAP8[i8 + 2 | 0] = HEAP8[i41 + 3 | 0] | 0;
+   HEAP8[i8 + 3 | 0] = HEAP8[i41 + 2 | 0] | 0;
+   HEAP8[i8] = HEAP8[i41 + 1 | 0] | 0;
+   HEAP8[i8 + 1 | 0] = HEAP8[i41] | 0;
+   d26 = +HEAPF32[i21 >> 2];
+   i8 = 1;
+  }
+  i4 = i3 + 12 | 0;
+  if ((+HEAPF32[i4 >> 2] - d22) * d23 + (+HEAPF32[i3 + 16 >> 2] - d24) * d25 <= d26) {
+   i38 = i4;
+   i41 = HEAP32[i38 + 4 >> 2] | 0;
+   i40 = i2 + (i8 * 20 | 0) | 0;
+   HEAP32[i40 >> 2] = HEAP32[i38 >> 2];
+   HEAP32[i40 + 4 >> 2] = i41;
+   i40 = i3 + 20 | 0;
+   i41 = i2 + (i8 * 20 | 0) + 16 | 0;
+   HEAP8[i41 + 2 | 0] = HEAP8[i40 + 3 | 0] | 0;
+   HEAP8[i41 + 3 | 0] = HEAP8[i40 + 2 | 0] | 0;
+   HEAP8[i41] = HEAP8[i40 + 1 | 0] | 0;
+   HEAP8[i41 + 1 | 0] = HEAP8[i40] | 0;
+   i8 = i8 + 1 | 0;
+  }
+ }
+ HEAP32[i19 >> 2] = i8;
+ STACKTOP = i1;
+ return;
+}
+function __ZN7b2World8SolveTOIERK10b2TimeStep(i30, i11) {
+ i30 = i30 | 0;
+ i11 = i11 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0, i38 = 0, i39 = 0, i40 = 0, i41 = 0, d42 = 0.0, i43 = 0, i44 = 0, i45 = 0, i46 = 0, i47 = 0, i48 = 0, i49 = 0, i50 = 0, i51 = 0, i52 = 0, i53 = 0, i54 = 0, i55 = 0, i56 = 0, i57 = 0, i58 = 0, i59 = 0, i60 = 0, i61 = 0, i62 = 0, i63 = 0, i64 = 0, i65 = 0, i66 = 0, d67 = 0.0, d68 = 0.0, d69 = 0.0, d70 = 0.0, d71 = 0.0, d72 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 336 | 0;
+ i3 = i1 + 284 | 0;
+ i6 = i1 + 152 | 0;
+ i5 = i1 + 144 | 0;
+ i4 = i1 + 108 | 0;
+ i8 = i1 + 72 | 0;
+ i7 = i1 + 64 | 0;
+ i14 = i1 + 24 | 0;
+ i9 = i1;
+ i10 = i30 + 102872 | 0;
+ i13 = i30 + 102944 | 0;
+ __ZN8b2IslandC2EiiiP16b2StackAllocatorP17b2ContactListener(i3, 64, 32, 0, i30 + 68 | 0, HEAP32[i13 >> 2] | 0);
+ i2 = i30 + 102995 | 0;
+ if ((HEAP8[i2] | 0) != 0) {
+  i15 = HEAP32[i30 + 102952 >> 2] | 0;
+  if ((i15 | 0) != 0) {
+   do {
+    i66 = i15 + 4 | 0;
+    HEAP16[i66 >> 1] = HEAP16[i66 >> 1] & 65534;
+    HEAPF32[i15 + 60 >> 2] = 0.0;
+    i15 = HEAP32[i15 + 96 >> 2] | 0;
+   } while ((i15 | 0) != 0);
+  }
+  i15 = i30 + 102932 | 0;
+  i16 = HEAP32[i15 >> 2] | 0;
+  if ((i16 | 0) != 0) {
+   do {
+    i66 = i16 + 4 | 0;
+    HEAP32[i66 >> 2] = HEAP32[i66 >> 2] & -34;
+    HEAP32[i16 + 128 >> 2] = 0;
+    HEAPF32[i16 + 132 >> 2] = 1.0;
+    i16 = HEAP32[i16 + 12 >> 2] | 0;
+   } while ((i16 | 0) != 0);
+  }
+ } else {
+  i15 = i30 + 102932 | 0;
+ }
+ i25 = i3 + 28 | 0;
+ i26 = i3 + 36 | 0;
+ i27 = i3 + 32 | 0;
+ i28 = i3 + 40 | 0;
+ i29 = i3 + 8 | 0;
+ i24 = i3 + 44 | 0;
+ i23 = i3 + 12 | 0;
+ i22 = i7 + 4 | 0;
+ i21 = i9 + 4 | 0;
+ i20 = i9 + 8 | 0;
+ i19 = i9 + 16 | 0;
+ i18 = i11 + 12 | 0;
+ i17 = i9 + 12 | 0;
+ i16 = i9 + 20 | 0;
+ i39 = i30 + 102994 | 0;
+ i37 = i6 + 16 | 0;
+ i36 = i6 + 20 | 0;
+ i35 = i6 + 24 | 0;
+ i34 = i6 + 44 | 0;
+ i33 = i6 + 48 | 0;
+ i32 = i6 + 52 | 0;
+ i41 = i6 + 28 | 0;
+ i31 = i6 + 56 | 0;
+ i40 = i6 + 92 | 0;
+ i30 = i6 + 128 | 0;
+ i38 = i5 + 4 | 0;
+ L11 : while (1) {
+  i47 = HEAP32[i15 >> 2] | 0;
+  if ((i47 | 0) == 0) {
+   i4 = 36;
+   break;
+  } else {
+   d42 = 1.0;
+   i44 = 0;
+  }
+  do {
+   i48 = i47 + 4 | 0;
+   i43 = HEAP32[i48 >> 2] | 0;
+   do {
+    if ((i43 & 4 | 0) != 0 ? (HEAP32[i47 + 128 >> 2] | 0) <= 8 : 0) {
+     if ((i43 & 32 | 0) == 0) {
+      i43 = HEAP32[i47 + 48 >> 2] | 0;
+      i45 = HEAP32[i47 + 52 >> 2] | 0;
+      if ((HEAP8[i43 + 38 | 0] | 0) != 0) {
+       break;
+      }
+      if ((HEAP8[i45 + 38 | 0] | 0) != 0) {
+       break;
+      }
+      i46 = HEAP32[i43 + 8 >> 2] | 0;
+      i50 = HEAP32[i45 + 8 >> 2] | 0;
+      i53 = HEAP32[i46 >> 2] | 0;
+      i52 = HEAP32[i50 >> 2] | 0;
+      if (!((i53 | 0) == 2 | (i52 | 0) == 2)) {
+       i4 = 16;
+       break L11;
+      }
+      i51 = HEAP16[i46 + 4 >> 1] | 0;
+      i49 = HEAP16[i50 + 4 >> 1] | 0;
+      if (!((i51 & 2) != 0 & (i53 | 0) != 0 | (i49 & 2) != 0 & (i52 | 0) != 0)) {
+       break;
+      }
+      if (!((i51 & 8) != 0 | (i53 | 0) != 2 | ((i49 & 8) != 0 | (i52 | 0) != 2))) {
+       break;
+      }
+      i51 = i46 + 28 | 0;
+      i52 = i46 + 60 | 0;
+      d68 = +HEAPF32[i52 >> 2];
+      i49 = i50 + 28 | 0;
+      i53 = i50 + 60 | 0;
+      d67 = +HEAPF32[i53 >> 2];
+      if (!(d68 < d67)) {
+       if (d67 < d68) {
+        if (!(d67 < 1.0)) {
+         i4 = 25;
+         break L11;
+        }
+        d67 = (d68 - d67) / (1.0 - d67);
+        i66 = i50 + 36 | 0;
+        d69 = 1.0 - d67;
+        d71 = +(+HEAPF32[i66 >> 2] * d69 + d67 * +HEAPF32[i50 + 44 >> 2]);
+        d70 = +(d69 * +HEAPF32[i50 + 40 >> 2] + d67 * +HEAPF32[i50 + 48 >> 2]);
+        HEAPF32[i66 >> 2] = d71;
+        HEAPF32[i66 + 4 >> 2] = d70;
+        i66 = i50 + 52 | 0;
+        HEAPF32[i66 >> 2] = d69 * +HEAPF32[i66 >> 2] + d67 * +HEAPF32[i50 + 56 >> 2];
+        HEAPF32[i53 >> 2] = d68;
+        d67 = d68;
+       } else {
+        d67 = d68;
+       }
+      } else {
+       if (!(d68 < 1.0)) {
+        i4 = 21;
+        break L11;
+       }
+       d71 = (d67 - d68) / (1.0 - d68);
+       i66 = i46 + 36 | 0;
+       d70 = 1.0 - d71;
+       d68 = +(+HEAPF32[i66 >> 2] * d70 + d71 * +HEAPF32[i46 + 44 >> 2]);
+       d69 = +(d70 * +HEAPF32[i46 + 40 >> 2] + d71 * +HEAPF32[i46 + 48 >> 2]);
+       HEAPF32[i66 >> 2] = d68;
+       HEAPF32[i66 + 4 >> 2] = d69;
+       i66 = i46 + 52 | 0;
+       HEAPF32[i66 >> 2] = d70 * +HEAPF32[i66 >> 2] + d71 * +HEAPF32[i46 + 56 >> 2];
+       HEAPF32[i52 >> 2] = d67;
+      }
+      if (!(d67 < 1.0)) {
+       i4 = 28;
+       break L11;
+      }
+      i66 = HEAP32[i47 + 56 >> 2] | 0;
+      i46 = HEAP32[i47 + 60 >> 2] | 0;
+      HEAP32[i37 >> 2] = 0;
+      HEAP32[i36 >> 2] = 0;
+      HEAPF32[i35 >> 2] = 0.0;
+      HEAP32[i34 >> 2] = 0;
+      HEAP32[i33 >> 2] = 0;
+      HEAPF32[i32 >> 2] = 0.0;
+      __ZN15b2DistanceProxy3SetEPK7b2Shapei(i6, HEAP32[i43 + 12 >> 2] | 0, i66);
+      __ZN15b2DistanceProxy3SetEPK7b2Shapei(i41, HEAP32[i45 + 12 >> 2] | 0, i46);
+      i43 = i31 + 0 | 0;
+      i45 = i51 + 0 | 0;
+      i46 = i43 + 36 | 0;
+      do {
+       HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+       i43 = i43 + 4 | 0;
+       i45 = i45 + 4 | 0;
+      } while ((i43 | 0) < (i46 | 0));
+      i43 = i40 + 0 | 0;
+      i45 = i49 + 0 | 0;
+      i46 = i43 + 36 | 0;
+      do {
+       HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+       i43 = i43 + 4 | 0;
+       i45 = i45 + 4 | 0;
+      } while ((i43 | 0) < (i46 | 0));
+      HEAPF32[i30 >> 2] = 1.0;
+      __Z14b2TimeOfImpactP11b2TOIOutputPK10b2TOIInput(i5, i6);
+      if ((HEAP32[i5 >> 2] | 0) == 3) {
+       d67 = d67 + (1.0 - d67) * +HEAPF32[i38 >> 2];
+       d67 = d67 < 1.0 ? d67 : 1.0;
+      } else {
+       d67 = 1.0;
+      }
+      HEAPF32[i47 + 132 >> 2] = d67;
+      HEAP32[i48 >> 2] = HEAP32[i48 >> 2] | 32;
+     } else {
+      d67 = +HEAPF32[i47 + 132 >> 2];
+     }
+     if (d67 < d42) {
+      d42 = d67;
+      i44 = i47;
+     }
+    }
+   } while (0);
+   i47 = HEAP32[i47 + 12 >> 2] | 0;
+  } while ((i47 | 0) != 0);
+  if ((i44 | 0) == 0 | d42 > .9999988079071045) {
+   i4 = 36;
+   break;
+  }
+  i47 = HEAP32[(HEAP32[i44 + 48 >> 2] | 0) + 8 >> 2] | 0;
+  i48 = HEAP32[(HEAP32[i44 + 52 >> 2] | 0) + 8 >> 2] | 0;
+  i49 = i47 + 28 | 0;
+  i43 = i4 + 0 | 0;
+  i45 = i49 + 0 | 0;
+  i46 = i43 + 36 | 0;
+  do {
+   HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+   i43 = i43 + 4 | 0;
+   i45 = i45 + 4 | 0;
+  } while ((i43 | 0) < (i46 | 0));
+  i50 = i48 + 28 | 0;
+  i43 = i8 + 0 | 0;
+  i45 = i50 + 0 | 0;
+  i46 = i43 + 36 | 0;
+  do {
+   HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+   i43 = i43 + 4 | 0;
+   i45 = i45 + 4 | 0;
+  } while ((i43 | 0) < (i46 | 0));
+  i43 = i47 + 60 | 0;
+  d67 = +HEAPF32[i43 >> 2];
+  if (!(d67 < 1.0)) {
+   i4 = 38;
+   break;
+  }
+  d70 = (d42 - d67) / (1.0 - d67);
+  i57 = i47 + 36 | 0;
+  d67 = 1.0 - d70;
+  i52 = i47 + 44 | 0;
+  i53 = i47 + 48 | 0;
+  d71 = +HEAPF32[i57 >> 2] * d67 + d70 * +HEAPF32[i52 >> 2];
+  d72 = d67 * +HEAPF32[i47 + 40 >> 2] + d70 * +HEAPF32[i53 >> 2];
+  d69 = +d71;
+  d68 = +d72;
+  HEAPF32[i57 >> 2] = d69;
+  HEAPF32[i57 + 4 >> 2] = d68;
+  i57 = i47 + 52 | 0;
+  i51 = i47 + 56 | 0;
+  d70 = d67 * +HEAPF32[i57 >> 2] + d70 * +HEAPF32[i51 >> 2];
+  HEAPF32[i57 >> 2] = d70;
+  HEAPF32[i43 >> 2] = d42;
+  i57 = i47 + 44 | 0;
+  HEAPF32[i57 >> 2] = d69;
+  HEAPF32[i57 + 4 >> 2] = d68;
+  HEAPF32[i51 >> 2] = d70;
+  d68 = +Math_sin(+d70);
+  i57 = i47 + 20 | 0;
+  HEAPF32[i57 >> 2] = d68;
+  d70 = +Math_cos(+d70);
+  i56 = i47 + 24 | 0;
+  HEAPF32[i56 >> 2] = d70;
+  i58 = i47 + 12 | 0;
+  i55 = i47 + 28 | 0;
+  d69 = +HEAPF32[i55 >> 2];
+  i54 = i47 + 32 | 0;
+  d67 = +HEAPF32[i54 >> 2];
+  d71 = +(d71 - (d70 * d69 - d68 * d67));
+  d67 = +(d72 - (d68 * d69 + d70 * d67));
+  i43 = i58;
+  HEAPF32[i43 >> 2] = d71;
+  HEAPF32[i43 + 4 >> 2] = d67;
+  i43 = i48 + 60 | 0;
+  d67 = +HEAPF32[i43 >> 2];
+  if (!(d67 < 1.0)) {
+   i4 = 40;
+   break;
+  }
+  d70 = (d42 - d67) / (1.0 - d67);
+  i64 = i48 + 36 | 0;
+  d72 = 1.0 - d70;
+  i61 = i48 + 44 | 0;
+  i60 = i48 + 48 | 0;
+  d71 = +HEAPF32[i64 >> 2] * d72 + d70 * +HEAPF32[i61 >> 2];
+  d67 = d72 * +HEAPF32[i48 + 40 >> 2] + d70 * +HEAPF32[i60 >> 2];
+  d69 = +d71;
+  d68 = +d67;
+  HEAPF32[i64 >> 2] = d69;
+  HEAPF32[i64 + 4 >> 2] = d68;
+  i64 = i48 + 52 | 0;
+  i59 = i48 + 56 | 0;
+  d70 = d72 * +HEAPF32[i64 >> 2] + d70 * +HEAPF32[i59 >> 2];
+  HEAPF32[i64 >> 2] = d70;
+  HEAPF32[i43 >> 2] = d42;
+  i64 = i48 + 44 | 0;
+  HEAPF32[i64 >> 2] = d69;
+  HEAPF32[i64 + 4 >> 2] = d68;
+  HEAPF32[i59 >> 2] = d70;
+  d68 = +Math_sin(+d70);
+  i64 = i48 + 20 | 0;
+  HEAPF32[i64 >> 2] = d68;
+  d70 = +Math_cos(+d70);
+  i63 = i48 + 24 | 0;
+  HEAPF32[i63 >> 2] = d70;
+  i65 = i48 + 12 | 0;
+  i62 = i48 + 28 | 0;
+  d69 = +HEAPF32[i62 >> 2];
+  i66 = i48 + 32 | 0;
+  d72 = +HEAPF32[i66 >> 2];
+  d71 = +(d71 - (d70 * d69 - d68 * d72));
+  d72 = +(d67 - (d68 * d69 + d70 * d72));
+  i43 = i65;
+  HEAPF32[i43 >> 2] = d71;
+  HEAPF32[i43 + 4 >> 2] = d72;
+  __ZN9b2Contact6UpdateEP17b2ContactListener(i44, HEAP32[i13 >> 2] | 0);
+  i43 = i44 + 4 | 0;
+  i45 = HEAP32[i43 >> 2] | 0;
+  HEAP32[i43 >> 2] = i45 & -33;
+  i46 = i44 + 128 | 0;
+  HEAP32[i46 >> 2] = (HEAP32[i46 >> 2] | 0) + 1;
+  if ((i45 & 6 | 0) != 6) {
+   HEAP32[i43 >> 2] = i45 & -37;
+   i43 = i49 + 0 | 0;
+   i45 = i4 + 0 | 0;
+   i46 = i43 + 36 | 0;
+   do {
+    HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+    i43 = i43 + 4 | 0;
+    i45 = i45 + 4 | 0;
+   } while ((i43 | 0) < (i46 | 0));
+   i43 = i50 + 0 | 0;
+   i45 = i8 + 0 | 0;
+   i46 = i43 + 36 | 0;
+   do {
+    HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+    i43 = i43 + 4 | 0;
+    i45 = i45 + 4 | 0;
+   } while ((i43 | 0) < (i46 | 0));
+   d69 = +HEAPF32[i51 >> 2];
+   d71 = +Math_sin(+d69);
+   HEAPF32[i57 >> 2] = d71;
+   d69 = +Math_cos(+d69);
+   HEAPF32[i56 >> 2] = d69;
+   d72 = +HEAPF32[i55 >> 2];
+   d70 = +HEAPF32[i54 >> 2];
+   d68 = +(+HEAPF32[i52 >> 2] - (d69 * d72 - d71 * d70));
+   d70 = +(+HEAPF32[i53 >> 2] - (d71 * d72 + d69 * d70));
+   HEAPF32[i58 >> 2] = d68;
+   HEAPF32[i58 + 4 >> 2] = d70;
+   d70 = +HEAPF32[i59 >> 2];
+   d68 = +Math_sin(+d70);
+   HEAPF32[i64 >> 2] = d68;
+   d70 = +Math_cos(+d70);
+   HEAPF32[i63 >> 2] = d70;
+   d69 = +HEAPF32[i62 >> 2];
+   d72 = +HEAPF32[i66 >> 2];
+   d71 = +(+HEAPF32[i61 >> 2] - (d70 * d69 - d68 * d72));
+   d72 = +(+HEAPF32[i60 >> 2] - (d68 * d69 + d70 * d72));
+   i66 = i65;
+   HEAPF32[i66 >> 2] = d71;
+   HEAPF32[i66 + 4 >> 2] = d72;
+   continue;
+  }
+  i45 = i47 + 4 | 0;
+  i46 = HEAPU16[i45 >> 1] | 0;
+  if ((i46 & 2 | 0) == 0) {
+   HEAP16[i45 >> 1] = i46 | 2;
+   HEAPF32[i47 + 144 >> 2] = 0.0;
+  }
+  i46 = i48 + 4 | 0;
+  i49 = HEAPU16[i46 >> 1] | 0;
+  if ((i49 & 2 | 0) == 0) {
+   HEAP16[i46 >> 1] = i49 | 2;
+   HEAPF32[i48 + 144 >> 2] = 0.0;
+  }
+  HEAP32[i25 >> 2] = 0;
+  HEAP32[i26 >> 2] = 0;
+  HEAP32[i27 >> 2] = 0;
+  if ((HEAP32[i28 >> 2] | 0) <= 0) {
+   i4 = 48;
+   break;
+  }
+  i49 = i47 + 8 | 0;
+  HEAP32[i49 >> 2] = 0;
+  i51 = HEAP32[i25 >> 2] | 0;
+  HEAP32[(HEAP32[i29 >> 2] | 0) + (i51 << 2) >> 2] = i47;
+  i51 = i51 + 1 | 0;
+  HEAP32[i25 >> 2] = i51;
+  if ((i51 | 0) >= (HEAP32[i28 >> 2] | 0)) {
+   i4 = 50;
+   break;
+  }
+  i50 = i48 + 8 | 0;
+  HEAP32[i50 >> 2] = i51;
+  i51 = HEAP32[i25 >> 2] | 0;
+  HEAP32[(HEAP32[i29 >> 2] | 0) + (i51 << 2) >> 2] = i48;
+  HEAP32[i25 >> 2] = i51 + 1;
+  i51 = HEAP32[i26 >> 2] | 0;
+  if ((i51 | 0) >= (HEAP32[i24 >> 2] | 0)) {
+   i4 = 52;
+   break;
+  }
+  HEAP32[i26 >> 2] = i51 + 1;
+  HEAP32[(HEAP32[i23 >> 2] | 0) + (i51 << 2) >> 2] = i44;
+  HEAP16[i45 >> 1] = HEAPU16[i45 >> 1] | 1;
+  HEAP16[i46 >> 1] = HEAPU16[i46 >> 1] | 1;
+  HEAP32[i43 >> 2] = HEAP32[i43 >> 2] | 1;
+  HEAP32[i7 >> 2] = i47;
+  HEAP32[i22 >> 2] = i48;
+  i44 = 1;
+  while (1) {
+   L58 : do {
+    if ((HEAP32[i47 >> 2] | 0) == 2 ? (i12 = HEAP32[i47 + 112 >> 2] | 0, (i12 | 0) != 0) : 0) {
+     i47 = i47 + 4 | 0;
+     i51 = i12;
+     do {
+      if ((HEAP32[i25 >> 2] | 0) == (HEAP32[i28 >> 2] | 0)) {
+       break L58;
+      }
+      if ((HEAP32[i26 >> 2] | 0) == (HEAP32[i24 >> 2] | 0)) {
+       break L58;
+      }
+      i52 = HEAP32[i51 + 4 >> 2] | 0;
+      i53 = i52 + 4 | 0;
+      do {
+       if ((HEAP32[i53 >> 2] & 1 | 0) == 0) {
+        i48 = HEAP32[i51 >> 2] | 0;
+        if (((HEAP32[i48 >> 2] | 0) == 2 ? (HEAP16[i47 >> 1] & 8) == 0 : 0) ? (HEAP16[i48 + 4 >> 1] & 8) == 0 : 0) {
+         break;
+        }
+        if ((HEAP8[(HEAP32[i52 + 48 >> 2] | 0) + 38 | 0] | 0) == 0 ? (HEAP8[(HEAP32[i52 + 52 >> 2] | 0) + 38 | 0] | 0) == 0 : 0) {
+         i54 = i48 + 28 | 0;
+         i43 = i14 + 0 | 0;
+         i45 = i54 + 0 | 0;
+         i46 = i43 + 36 | 0;
+         do {
+          HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+          i43 = i43 + 4 | 0;
+          i45 = i45 + 4 | 0;
+         } while ((i43 | 0) < (i46 | 0));
+         i43 = i48 + 4 | 0;
+         if ((HEAP16[i43 >> 1] & 1) == 0) {
+          i45 = i48 + 60 | 0;
+          d67 = +HEAPF32[i45 >> 2];
+          if (!(d67 < 1.0)) {
+           i4 = 67;
+           break L11;
+          }
+          d70 = (d42 - d67) / (1.0 - d67);
+          i65 = i48 + 36 | 0;
+          d72 = 1.0 - d70;
+          d71 = +HEAPF32[i65 >> 2] * d72 + d70 * +HEAPF32[i48 + 44 >> 2];
+          d67 = d72 * +HEAPF32[i48 + 40 >> 2] + d70 * +HEAPF32[i48 + 48 >> 2];
+          d69 = +d71;
+          d68 = +d67;
+          HEAPF32[i65 >> 2] = d69;
+          HEAPF32[i65 + 4 >> 2] = d68;
+          i65 = i48 + 52 | 0;
+          i66 = i48 + 56 | 0;
+          d70 = d72 * +HEAPF32[i65 >> 2] + d70 * +HEAPF32[i66 >> 2];
+          HEAPF32[i65 >> 2] = d70;
+          HEAPF32[i45 >> 2] = d42;
+          i65 = i48 + 44 | 0;
+          HEAPF32[i65 >> 2] = d69;
+          HEAPF32[i65 + 4 >> 2] = d68;
+          HEAPF32[i66 >> 2] = d70;
+          d68 = +Math_sin(+d70);
+          HEAPF32[i48 + 20 >> 2] = d68;
+          d70 = +Math_cos(+d70);
+          HEAPF32[i48 + 24 >> 2] = d70;
+          d69 = +HEAPF32[i48 + 28 >> 2];
+          d72 = +HEAPF32[i48 + 32 >> 2];
+          d71 = +(d71 - (d70 * d69 - d68 * d72));
+          d72 = +(d67 - (d68 * d69 + d70 * d72));
+          i66 = i48 + 12 | 0;
+          HEAPF32[i66 >> 2] = d71;
+          HEAPF32[i66 + 4 >> 2] = d72;
+         }
+         __ZN9b2Contact6UpdateEP17b2ContactListener(i52, HEAP32[i13 >> 2] | 0);
+         i45 = HEAP32[i53 >> 2] | 0;
+         if ((i45 & 4 | 0) == 0) {
+          i43 = i54 + 0 | 0;
+          i45 = i14 + 0 | 0;
+          i46 = i43 + 36 | 0;
+          do {
+           HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+           i43 = i43 + 4 | 0;
+           i45 = i45 + 4 | 0;
+          } while ((i43 | 0) < (i46 | 0));
+          d70 = +HEAPF32[i48 + 56 >> 2];
+          d68 = +Math_sin(+d70);
+          HEAPF32[i48 + 20 >> 2] = d68;
+          d70 = +Math_cos(+d70);
+          HEAPF32[i48 + 24 >> 2] = d70;
+          d69 = +HEAPF32[i48 + 28 >> 2];
+          d72 = +HEAPF32[i48 + 32 >> 2];
+          d71 = +(+HEAPF32[i48 + 44 >> 2] - (d70 * d69 - d68 * d72));
+          d72 = +(+HEAPF32[i48 + 48 >> 2] - (d68 * d69 + d70 * d72));
+          i66 = i48 + 12 | 0;
+          HEAPF32[i66 >> 2] = d71;
+          HEAPF32[i66 + 4 >> 2] = d72;
+          break;
+         }
+         if ((i45 & 2 | 0) == 0) {
+          i43 = i54 + 0 | 0;
+          i45 = i14 + 0 | 0;
+          i46 = i43 + 36 | 0;
+          do {
+           HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+           i43 = i43 + 4 | 0;
+           i45 = i45 + 4 | 0;
+          } while ((i43 | 0) < (i46 | 0));
+          d70 = +HEAPF32[i48 + 56 >> 2];
+          d68 = +Math_sin(+d70);
+          HEAPF32[i48 + 20 >> 2] = d68;
+          d70 = +Math_cos(+d70);
+          HEAPF32[i48 + 24 >> 2] = d70;
+          d69 = +HEAPF32[i48 + 28 >> 2];
+          d72 = +HEAPF32[i48 + 32 >> 2];
+          d71 = +(+HEAPF32[i48 + 44 >> 2] - (d70 * d69 - d68 * d72));
+          d72 = +(+HEAPF32[i48 + 48 >> 2] - (d68 * d69 + d70 * d72));
+          i66 = i48 + 12 | 0;
+          HEAPF32[i66 >> 2] = d71;
+          HEAPF32[i66 + 4 >> 2] = d72;
+          break;
+         }
+         HEAP32[i53 >> 2] = i45 | 1;
+         i45 = HEAP32[i26 >> 2] | 0;
+         if ((i45 | 0) >= (HEAP32[i24 >> 2] | 0)) {
+          i4 = 74;
+          break L11;
+         }
+         HEAP32[i26 >> 2] = i45 + 1;
+         HEAP32[(HEAP32[i23 >> 2] | 0) + (i45 << 2) >> 2] = i52;
+         i45 = HEAPU16[i43 >> 1] | 0;
+         if ((i45 & 1 | 0) == 0) {
+          HEAP16[i43 >> 1] = i45 | 1;
+          if ((HEAP32[i48 >> 2] | 0) != 0 ? (i45 & 2 | 0) == 0 : 0) {
+           HEAP16[i43 >> 1] = i45 | 3;
+           HEAPF32[i48 + 144 >> 2] = 0.0;
+          }
+          i43 = HEAP32[i25 >> 2] | 0;
+          if ((i43 | 0) >= (HEAP32[i28 >> 2] | 0)) {
+           i4 = 80;
+           break L11;
+          }
+          HEAP32[i48 + 8 >> 2] = i43;
+          i66 = HEAP32[i25 >> 2] | 0;
+          HEAP32[(HEAP32[i29 >> 2] | 0) + (i66 << 2) >> 2] = i48;
+          HEAP32[i25 >> 2] = i66 + 1;
+         }
+        }
+       }
+      } while (0);
+      i51 = HEAP32[i51 + 12 >> 2] | 0;
+     } while ((i51 | 0) != 0);
+    }
+   } while (0);
+   if ((i44 | 0) >= 2) {
+    break;
+   }
+   i47 = HEAP32[i7 + (i44 << 2) >> 2] | 0;
+   i44 = i44 + 1 | 0;
+  }
+  d72 = (1.0 - d42) * +HEAPF32[i11 >> 2];
+  HEAPF32[i9 >> 2] = d72;
+  HEAPF32[i21 >> 2] = 1.0 / d72;
+  HEAPF32[i20 >> 2] = 1.0;
+  HEAP32[i19 >> 2] = 20;
+  HEAP32[i17 >> 2] = HEAP32[i18 >> 2];
+  HEAP8[i16] = 0;
+  __ZN8b2Island8SolveTOIERK10b2TimeStepii(i3, i9, HEAP32[i49 >> 2] | 0, HEAP32[i50 >> 2] | 0);
+  i44 = HEAP32[i25 >> 2] | 0;
+  if ((i44 | 0) > 0) {
+   i43 = 0;
+   do {
+    i45 = HEAP32[(HEAP32[i29 >> 2] | 0) + (i43 << 2) >> 2] | 0;
+    i66 = i45 + 4 | 0;
+    HEAP16[i66 >> 1] = HEAP16[i66 >> 1] & 65534;
+    if ((HEAP32[i45 >> 2] | 0) == 2) {
+     __ZN6b2Body19SynchronizeFixturesEv(i45);
+     i44 = HEAP32[i45 + 112 >> 2] | 0;
+     if ((i44 | 0) != 0) {
+      do {
+       i66 = (HEAP32[i44 + 4 >> 2] | 0) + 4 | 0;
+       HEAP32[i66 >> 2] = HEAP32[i66 >> 2] & -34;
+       i44 = HEAP32[i44 + 12 >> 2] | 0;
+      } while ((i44 | 0) != 0);
+     }
+     i44 = HEAP32[i25 >> 2] | 0;
+    }
+    i43 = i43 + 1 | 0;
+   } while ((i43 | 0) < (i44 | 0));
+  }
+  __ZN16b2ContactManager15FindNewContactsEv(i10);
+  if ((HEAP8[i39] | 0) != 0) {
+   i4 = 92;
+   break;
+  }
+ }
+ if ((i4 | 0) == 16) {
+  ___assert_fail(2288, 2184, 641, 2344);
+ } else if ((i4 | 0) == 21) {
+  ___assert_fail(2360, 2376, 723, 2400);
+ } else if ((i4 | 0) == 25) {
+  ___assert_fail(2360, 2376, 723, 2400);
+ } else if ((i4 | 0) == 28) {
+  ___assert_fail(2360, 2184, 676, 2344);
+ } else if ((i4 | 0) == 36) {
+  HEAP8[i2] = 1;
+  __ZN8b2IslandD2Ev(i3);
+  STACKTOP = i1;
+  return;
+ } else if ((i4 | 0) == 38) {
+  ___assert_fail(2360, 2376, 723, 2400);
+ } else if ((i4 | 0) == 40) {
+  ___assert_fail(2360, 2376, 723, 2400);
+ } else if ((i4 | 0) == 48) {
+  ___assert_fail(2520, 2440, 54, 2472);
+ } else if ((i4 | 0) == 50) {
+  ___assert_fail(2520, 2440, 54, 2472);
+ } else if ((i4 | 0) == 52) {
+  ___assert_fail(2480, 2440, 62, 2472);
+ } else if ((i4 | 0) == 67) {
+  ___assert_fail(2360, 2376, 723, 2400);
+ } else if ((i4 | 0) == 74) {
+  ___assert_fail(2480, 2440, 62, 2472);
+ } else if ((i4 | 0) == 80) {
+  ___assert_fail(2520, 2440, 54, 2472);
+ } else if ((i4 | 0) == 92) {
+  HEAP8[i2] = 0;
+  __ZN8b2IslandD2Ev(i3);
+  STACKTOP = i1;
+  return;
+ }
+}
+function __ZNSt3__16__sortIRPFbRK6b2PairS3_EPS1_EEvT0_S8_T_(i5, i8, i1) {
+ i5 = i5 | 0;
+ i8 = i8 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i3;
+ L1 : while (1) {
+  i7 = i8;
+  i4 = i8 + -12 | 0;
+  L3 : while (1) {
+   i9 = i5;
+   i11 = i7 - i9 | 0;
+   switch ((i11 | 0) / 12 | 0 | 0) {
+   case 4:
+    {
+     i6 = 14;
+     break L1;
+    }
+   case 2:
+    {
+     i6 = 4;
+     break L1;
+    }
+   case 3:
+    {
+     i6 = 6;
+     break L1;
+    }
+   case 5:
+    {
+     i6 = 15;
+     break L1;
+    }
+   case 1:
+   case 0:
+    {
+     i6 = 67;
+     break L1;
+    }
+   default:
+    {}
+   }
+   if ((i11 | 0) < 372) {
+    i6 = 21;
+    break L1;
+   }
+   i12 = (i11 | 0) / 24 | 0;
+   i10 = i5 + (i12 * 12 | 0) | 0;
+   do {
+    if ((i11 | 0) > 11988) {
+     i14 = (i11 | 0) / 48 | 0;
+     i11 = i5 + (i14 * 12 | 0) | 0;
+     i14 = i5 + ((i14 + i12 | 0) * 12 | 0) | 0;
+     i12 = __ZNSt3__17__sort4IRPFbRK6b2PairS3_EPS1_EEjT0_S8_S8_S8_T_(i5, i11, i10, i14, i1) | 0;
+     if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i14) | 0) {
+      HEAP32[i2 + 0 >> 2] = HEAP32[i14 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i14 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i14 + 8 >> 2];
+      HEAP32[i14 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+      HEAP32[i14 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+      HEAP32[i14 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+      HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i13 = i12 + 1 | 0;
+      if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i14, i10) | 0) {
+       HEAP32[i2 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+       HEAP32[i2 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+       HEAP32[i2 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+       HEAP32[i10 + 0 >> 2] = HEAP32[i14 + 0 >> 2];
+       HEAP32[i10 + 4 >> 2] = HEAP32[i14 + 4 >> 2];
+       HEAP32[i10 + 8 >> 2] = HEAP32[i14 + 8 >> 2];
+       HEAP32[i14 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+       HEAP32[i14 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+       HEAP32[i14 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+       i13 = i12 + 2 | 0;
+       if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i10, i11) | 0) {
+        HEAP32[i2 + 0 >> 2] = HEAP32[i11 + 0 >> 2];
+        HEAP32[i2 + 4 >> 2] = HEAP32[i11 + 4 >> 2];
+        HEAP32[i2 + 8 >> 2] = HEAP32[i11 + 8 >> 2];
+        HEAP32[i11 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+        HEAP32[i11 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+        HEAP32[i11 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+        HEAP32[i10 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+        HEAP32[i10 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+        HEAP32[i10 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+        if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i11, i5) | 0) {
+         HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+         HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+         HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+         HEAP32[i5 + 0 >> 2] = HEAP32[i11 + 0 >> 2];
+         HEAP32[i5 + 4 >> 2] = HEAP32[i11 + 4 >> 2];
+         HEAP32[i5 + 8 >> 2] = HEAP32[i11 + 8 >> 2];
+         HEAP32[i11 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+         HEAP32[i11 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+         HEAP32[i11 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+         i12 = i12 + 4 | 0;
+        } else {
+         i12 = i12 + 3 | 0;
+        }
+       } else {
+        i12 = i13;
+       }
+      } else {
+       i12 = i13;
+      }
+     }
+    } else {
+     i15 = FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i10, i5) | 0;
+     i11 = FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i10) | 0;
+     if (!i15) {
+      if (!i11) {
+       i12 = 0;
+       break;
+      }
+      HEAP32[i2 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+      HEAP32[i10 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+      HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i10, i5) | 0)) {
+       i12 = 1;
+       break;
+      }
+      HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+      HEAP32[i5 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+      HEAP32[i5 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+      HEAP32[i5 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+      HEAP32[i10 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i12 = 2;
+      break;
+     }
+     if (i11) {
+      HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+      HEAP32[i5 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+      HEAP32[i5 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+      HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+      HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i12 = 1;
+      break;
+     }
+     HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+     HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+     HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+     HEAP32[i5 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+     HEAP32[i5 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+     HEAP32[i5 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+     HEAP32[i10 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+     HEAP32[i10 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+     HEAP32[i10 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+     if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i10) | 0) {
+      HEAP32[i2 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+      HEAP32[i10 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+      HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i12 = 2;
+     } else {
+      i12 = 1;
+     }
+    }
+   } while (0);
+   do {
+    if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i10) | 0) {
+     i13 = i4;
+    } else {
+     i13 = i4;
+     while (1) {
+      i13 = i13 + -12 | 0;
+      if ((i5 | 0) == (i13 | 0)) {
+       break;
+      }
+      if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i13, i10) | 0) {
+       i6 = 50;
+       break;
+      }
+     }
+     if ((i6 | 0) == 50) {
+      i6 = 0;
+      HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+      HEAP32[i5 + 0 >> 2] = HEAP32[i13 + 0 >> 2];
+      HEAP32[i5 + 4 >> 2] = HEAP32[i13 + 4 >> 2];
+      HEAP32[i5 + 8 >> 2] = HEAP32[i13 + 8 >> 2];
+      HEAP32[i13 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i13 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i13 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i12 = i12 + 1 | 0;
+      break;
+     }
+     i10 = i5 + 12 | 0;
+     if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i4) | 0)) {
+      if ((i10 | 0) == (i4 | 0)) {
+       i6 = 67;
+       break L1;
+      }
+      while (1) {
+       i9 = i10 + 12 | 0;
+       if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i10) | 0) {
+        break;
+       }
+       if ((i9 | 0) == (i4 | 0)) {
+        i6 = 67;
+        break L1;
+       } else {
+        i10 = i9;
+       }
+      }
+      HEAP32[i2 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+      HEAP32[i10 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+      HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i10 = i9;
+     }
+     if ((i10 | 0) == (i4 | 0)) {
+      i6 = 67;
+      break L1;
+     } else {
+      i9 = i4;
+     }
+     while (1) {
+      while (1) {
+       i11 = i10 + 12 | 0;
+       if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i10) | 0) {
+        break;
+       } else {
+        i10 = i11;
+       }
+      }
+      do {
+       i9 = i9 + -12 | 0;
+      } while (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i9) | 0);
+      if (!(i10 >>> 0 < i9 >>> 0)) {
+       i5 = i10;
+       continue L3;
+      }
+      HEAP32[i2 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+      HEAP32[i10 + 0 >> 2] = HEAP32[i9 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i9 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i9 + 8 >> 2];
+      HEAP32[i9 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i9 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i9 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i10 = i11;
+     }
+    }
+   } while (0);
+   i11 = i5 + 12 | 0;
+   L47 : do {
+    if (i11 >>> 0 < i13 >>> 0) {
+     while (1) {
+      i15 = i11;
+      while (1) {
+       i11 = i15 + 12 | 0;
+       if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i15, i10) | 0) {
+        i15 = i11;
+       } else {
+        i14 = i13;
+        break;
+       }
+      }
+      do {
+       i14 = i14 + -12 | 0;
+      } while (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i14, i10) | 0));
+      if (i15 >>> 0 > i14 >>> 0) {
+       i11 = i15;
+       break L47;
+      }
+      HEAP32[i2 + 0 >> 2] = HEAP32[i15 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i15 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i15 + 8 >> 2];
+      HEAP32[i15 + 0 >> 2] = HEAP32[i14 + 0 >> 2];
+      HEAP32[i15 + 4 >> 2] = HEAP32[i14 + 4 >> 2];
+      HEAP32[i15 + 8 >> 2] = HEAP32[i14 + 8 >> 2];
+      HEAP32[i14 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i14 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i14 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i13 = i14;
+      i10 = (i10 | 0) == (i15 | 0) ? i14 : i10;
+      i12 = i12 + 1 | 0;
+     }
+    }
+   } while (0);
+   if ((i11 | 0) != (i10 | 0) ? FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i10, i11) | 0 : 0) {
+    HEAP32[i2 + 0 >> 2] = HEAP32[i11 + 0 >> 2];
+    HEAP32[i2 + 4 >> 2] = HEAP32[i11 + 4 >> 2];
+    HEAP32[i2 + 8 >> 2] = HEAP32[i11 + 8 >> 2];
+    HEAP32[i11 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+    HEAP32[i11 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+    HEAP32[i11 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+    HEAP32[i10 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+    HEAP32[i10 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+    HEAP32[i10 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+    i12 = i12 + 1 | 0;
+   }
+   if ((i12 | 0) == 0) {
+    i12 = __ZNSt3__127__insertion_sort_incompleteIRPFbRK6b2PairS3_EPS1_EEbT0_S8_T_(i5, i11, i1) | 0;
+    i10 = i11 + 12 | 0;
+    if (__ZNSt3__127__insertion_sort_incompleteIRPFbRK6b2PairS3_EPS1_EEbT0_S8_T_(i10, i8, i1) | 0) {
+     i6 = 62;
+     break;
+    }
+    if (i12) {
+     i5 = i10;
+     continue;
+    }
+   }
+   i15 = i11;
+   if ((i15 - i9 | 0) >= (i7 - i15 | 0)) {
+    i6 = 66;
+    break;
+   }
+   __ZNSt3__16__sortIRPFbRK6b2PairS3_EPS1_EEvT0_S8_T_(i5, i11, i1);
+   i5 = i11 + 12 | 0;
+  }
+  if ((i6 | 0) == 62) {
+   i6 = 0;
+   if (i12) {
+    i6 = 67;
+    break;
+   } else {
+    i8 = i11;
+    continue;
+   }
+  } else if ((i6 | 0) == 66) {
+   i6 = 0;
+   __ZNSt3__16__sortIRPFbRK6b2PairS3_EPS1_EEvT0_S8_T_(i11 + 12 | 0, i8, i1);
+   i8 = i11;
+   continue;
+  }
+ }
+ if ((i6 | 0) == 4) {
+  if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i5) | 0)) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+  HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+  HEAP32[i5 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+  HEAP32[i5 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+  HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+  HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+  HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+  HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+  STACKTOP = i3;
+  return;
+ } else if ((i6 | 0) == 6) {
+  i6 = i5 + 12 | 0;
+  i15 = FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i6, i5) | 0;
+  i7 = FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i6) | 0;
+  if (!i15) {
+   if (!i7) {
+    STACKTOP = i3;
+    return;
+   }
+   HEAP32[i2 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+   HEAP32[i2 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+   HEAP32[i2 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   HEAP32[i6 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+   HEAP32[i6 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+   HEAP32[i6 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+   HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+   HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+   HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+   if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i6, i5) | 0)) {
+    STACKTOP = i3;
+    return;
+   }
+   HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+   HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+   HEAP32[i5 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+   HEAP32[i5 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   HEAP32[i6 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+   HEAP32[i6 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+   HEAP32[i6 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+   STACKTOP = i3;
+   return;
+  }
+  if (i7) {
+   HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+   HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+   HEAP32[i5 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+   HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+   HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+   HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+   HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+  HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+  HEAP32[i5 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+  HEAP32[i5 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+  HEAP32[i5 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+  HEAP32[i6 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+  HEAP32[i6 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+  HEAP32[i6 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+  if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i6) | 0)) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i2 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+  HEAP32[i2 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+  HEAP32[i6 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+  HEAP32[i6 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+  HEAP32[i6 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+  HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+  HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+  HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+  STACKTOP = i3;
+  return;
+ } else if ((i6 | 0) == 14) {
+  __ZNSt3__17__sort4IRPFbRK6b2PairS3_EPS1_EEjT0_S8_S8_S8_T_(i5, i5 + 12 | 0, i5 + 24 | 0, i4, i1) | 0;
+  STACKTOP = i3;
+  return;
+ } else if ((i6 | 0) == 15) {
+  i6 = i5 + 12 | 0;
+  i7 = i5 + 24 | 0;
+  i8 = i5 + 36 | 0;
+  __ZNSt3__17__sort4IRPFbRK6b2PairS3_EPS1_EEjT0_S8_S8_S8_T_(i5, i6, i7, i8, i1) | 0;
+  if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i8) | 0)) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i2 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+  HEAP32[i2 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+  HEAP32[i8 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+  HEAP32[i8 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+  HEAP32[i8 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+  HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+  HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+  HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+  if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i8, i7) | 0)) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i2 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+  HEAP32[i2 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+  HEAP32[i7 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+  HEAP32[i7 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+  HEAP32[i7 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+  HEAP32[i8 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+  HEAP32[i8 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+  HEAP32[i8 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+  if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i7, i6) | 0)) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i2 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+  HEAP32[i2 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+  HEAP32[i6 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+  HEAP32[i6 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+  HEAP32[i6 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+  HEAP32[i7 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+  HEAP32[i7 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+  HEAP32[i7 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+  if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i6, i5) | 0)) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+  HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+  HEAP32[i5 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+  HEAP32[i5 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+  HEAP32[i5 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+  HEAP32[i6 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+  HEAP32[i6 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+  HEAP32[i6 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+  STACKTOP = i3;
+  return;
+ } else if ((i6 | 0) == 21) {
+  __ZNSt3__118__insertion_sort_3IRPFbRK6b2PairS3_EPS1_EEvT0_S8_T_(i5, i8, i1);
+  STACKTOP = i3;
+  return;
+ } else if ((i6 | 0) == 67) {
+  STACKTOP = i3;
+  return;
+ }
+}
+function _free(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i1 = STACKTOP;
+ if ((i7 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i15 = i7 + -8 | 0;
+ i16 = HEAP32[7176 >> 2] | 0;
+ if (i15 >>> 0 < i16 >>> 0) {
+  _abort();
+ }
+ i13 = HEAP32[i7 + -4 >> 2] | 0;
+ i12 = i13 & 3;
+ if ((i12 | 0) == 1) {
+  _abort();
+ }
+ i8 = i13 & -8;
+ i6 = i7 + (i8 + -8) | 0;
+ do {
+  if ((i13 & 1 | 0) == 0) {
+   i19 = HEAP32[i15 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   i15 = -8 - i19 | 0;
+   i13 = i7 + i15 | 0;
+   i12 = i19 + i8 | 0;
+   if (i13 >>> 0 < i16 >>> 0) {
+    _abort();
+   }
+   if ((i13 | 0) == (HEAP32[7180 >> 2] | 0)) {
+    i2 = i7 + (i8 + -4) | 0;
+    if ((HEAP32[i2 >> 2] & 3 | 0) != 3) {
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    HEAP32[7168 >> 2] = i12;
+    HEAP32[i2 >> 2] = HEAP32[i2 >> 2] & -2;
+    HEAP32[i7 + (i15 + 4) >> 2] = i12 | 1;
+    HEAP32[i6 >> 2] = i12;
+    STACKTOP = i1;
+    return;
+   }
+   i18 = i19 >>> 3;
+   if (i19 >>> 0 < 256) {
+    i2 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+    i11 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+    i14 = 7200 + (i18 << 1 << 2) | 0;
+    if ((i2 | 0) != (i14 | 0)) {
+     if (i2 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i2 + 12 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+    }
+    if ((i11 | 0) == (i2 | 0)) {
+     HEAP32[1790] = HEAP32[1790] & ~(1 << i18);
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    if ((i11 | 0) != (i14 | 0)) {
+     if (i11 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i14 = i11 + 8 | 0;
+     if ((HEAP32[i14 >> 2] | 0) == (i13 | 0)) {
+      i17 = i14;
+     } else {
+      _abort();
+     }
+    } else {
+     i17 = i11 + 8 | 0;
+    }
+    HEAP32[i2 + 12 >> 2] = i11;
+    HEAP32[i17 >> 2] = i2;
+    i2 = i13;
+    i11 = i12;
+    break;
+   }
+   i17 = HEAP32[i7 + (i15 + 24) >> 2] | 0;
+   i18 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+   do {
+    if ((i18 | 0) == (i13 | 0)) {
+     i19 = i7 + (i15 + 20) | 0;
+     i18 = HEAP32[i19 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      i19 = i7 + (i15 + 16) | 0;
+      i18 = HEAP32[i19 >> 2] | 0;
+      if ((i18 | 0) == 0) {
+       i14 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i21 = i18 + 20 | 0;
+      i20 = HEAP32[i21 >> 2] | 0;
+      if ((i20 | 0) != 0) {
+       i18 = i20;
+       i19 = i21;
+       continue;
+      }
+      i20 = i18 + 16 | 0;
+      i21 = HEAP32[i20 >> 2] | 0;
+      if ((i21 | 0) == 0) {
+       break;
+      } else {
+       i18 = i21;
+       i19 = i20;
+      }
+     }
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i19 >> 2] = 0;
+      i14 = i18;
+      break;
+     }
+    } else {
+     i19 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i16 = i19 + 12 | 0;
+     if ((HEAP32[i16 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+     i20 = i18 + 8 | 0;
+     if ((HEAP32[i20 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i18;
+      HEAP32[i20 >> 2] = i19;
+      i14 = i18;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i17 | 0) != 0) {
+    i18 = HEAP32[i7 + (i15 + 28) >> 2] | 0;
+    i16 = 7464 + (i18 << 2) | 0;
+    if ((i13 | 0) == (HEAP32[i16 >> 2] | 0)) {
+     HEAP32[i16 >> 2] = i14;
+     if ((i14 | 0) == 0) {
+      HEAP32[7164 >> 2] = HEAP32[7164 >> 2] & ~(1 << i18);
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     if (i17 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i16 = i17 + 16 | 0;
+     if ((HEAP32[i16 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i14;
+     } else {
+      HEAP32[i17 + 20 >> 2] = i14;
+     }
+     if ((i14 | 0) == 0) {
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    }
+    if (i14 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i14 + 24 >> 2] = i17;
+    i16 = HEAP32[i7 + (i15 + 16) >> 2] | 0;
+    do {
+     if ((i16 | 0) != 0) {
+      if (i16 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i14 + 16 >> 2] = i16;
+       HEAP32[i16 + 24 >> 2] = i14;
+       break;
+      }
+     }
+    } while (0);
+    i15 = HEAP32[i7 + (i15 + 20) >> 2] | 0;
+    if ((i15 | 0) != 0) {
+     if (i15 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i14 + 20 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i14;
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     i2 = i13;
+     i11 = i12;
+    }
+   } else {
+    i2 = i13;
+    i11 = i12;
+   }
+  } else {
+   i2 = i15;
+   i11 = i8;
+  }
+ } while (0);
+ if (!(i2 >>> 0 < i6 >>> 0)) {
+  _abort();
+ }
+ i12 = i7 + (i8 + -4) | 0;
+ i13 = HEAP32[i12 >> 2] | 0;
+ if ((i13 & 1 | 0) == 0) {
+  _abort();
+ }
+ if ((i13 & 2 | 0) == 0) {
+  if ((i6 | 0) == (HEAP32[7184 >> 2] | 0)) {
+   i21 = (HEAP32[7172 >> 2] | 0) + i11 | 0;
+   HEAP32[7172 >> 2] = i21;
+   HEAP32[7184 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   if ((i2 | 0) != (HEAP32[7180 >> 2] | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[7180 >> 2] = 0;
+   HEAP32[7168 >> 2] = 0;
+   STACKTOP = i1;
+   return;
+  }
+  if ((i6 | 0) == (HEAP32[7180 >> 2] | 0)) {
+   i21 = (HEAP32[7168 >> 2] | 0) + i11 | 0;
+   HEAP32[7168 >> 2] = i21;
+   HEAP32[7180 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   HEAP32[i2 + i21 >> 2] = i21;
+   STACKTOP = i1;
+   return;
+  }
+  i11 = (i13 & -8) + i11 | 0;
+  i12 = i13 >>> 3;
+  do {
+   if (!(i13 >>> 0 < 256)) {
+    i10 = HEAP32[i7 + (i8 + 16) >> 2] | 0;
+    i15 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    do {
+     if ((i15 | 0) == (i6 | 0)) {
+      i13 = i7 + (i8 + 12) | 0;
+      i12 = HEAP32[i13 >> 2] | 0;
+      if ((i12 | 0) == 0) {
+       i13 = i7 + (i8 + 8) | 0;
+       i12 = HEAP32[i13 >> 2] | 0;
+       if ((i12 | 0) == 0) {
+        i9 = 0;
+        break;
+       }
+      }
+      while (1) {
+       i14 = i12 + 20 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) != 0) {
+        i12 = i15;
+        i13 = i14;
+        continue;
+       }
+       i14 = i12 + 16 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) == 0) {
+        break;
+       } else {
+        i12 = i15;
+        i13 = i14;
+       }
+      }
+      if (i13 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 >> 2] = 0;
+       i9 = i12;
+       break;
+      }
+     } else {
+      i13 = HEAP32[i7 + i8 >> 2] | 0;
+      if (i13 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i14 = i13 + 12 | 0;
+      if ((HEAP32[i14 >> 2] | 0) != (i6 | 0)) {
+       _abort();
+      }
+      i12 = i15 + 8 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i14 >> 2] = i15;
+       HEAP32[i12 >> 2] = i13;
+       i9 = i15;
+       break;
+      } else {
+       _abort();
+      }
+     }
+    } while (0);
+    if ((i10 | 0) != 0) {
+     i12 = HEAP32[i7 + (i8 + 20) >> 2] | 0;
+     i13 = 7464 + (i12 << 2) | 0;
+     if ((i6 | 0) == (HEAP32[i13 >> 2] | 0)) {
+      HEAP32[i13 >> 2] = i9;
+      if ((i9 | 0) == 0) {
+       HEAP32[7164 >> 2] = HEAP32[7164 >> 2] & ~(1 << i12);
+       break;
+      }
+     } else {
+      if (i10 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i12 = i10 + 16 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i12 >> 2] = i9;
+      } else {
+       HEAP32[i10 + 20 >> 2] = i9;
+      }
+      if ((i9 | 0) == 0) {
+       break;
+      }
+     }
+     if (i9 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     HEAP32[i9 + 24 >> 2] = i10;
+     i6 = HEAP32[i7 + (i8 + 8) >> 2] | 0;
+     do {
+      if ((i6 | 0) != 0) {
+       if (i6 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i9 + 16 >> 2] = i6;
+        HEAP32[i6 + 24 >> 2] = i9;
+        break;
+       }
+      }
+     } while (0);
+     i6 = HEAP32[i7 + (i8 + 12) >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      if (i6 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i9 + 20 >> 2] = i6;
+       HEAP32[i6 + 24 >> 2] = i9;
+       break;
+      }
+     }
+    }
+   } else {
+    i9 = HEAP32[i7 + i8 >> 2] | 0;
+    i7 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    i8 = 7200 + (i12 << 1 << 2) | 0;
+    if ((i9 | 0) != (i8 | 0)) {
+     if (i9 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i9 + 12 >> 2] | 0) != (i6 | 0)) {
+      _abort();
+     }
+    }
+    if ((i7 | 0) == (i9 | 0)) {
+     HEAP32[1790] = HEAP32[1790] & ~(1 << i12);
+     break;
+    }
+    if ((i7 | 0) != (i8 | 0)) {
+     if (i7 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i8 = i7 + 8 | 0;
+     if ((HEAP32[i8 >> 2] | 0) == (i6 | 0)) {
+      i10 = i8;
+     } else {
+      _abort();
+     }
+    } else {
+     i10 = i7 + 8 | 0;
+    }
+    HEAP32[i9 + 12 >> 2] = i7;
+    HEAP32[i10 >> 2] = i9;
+   }
+  } while (0);
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+  if ((i2 | 0) == (HEAP32[7180 >> 2] | 0)) {
+   HEAP32[7168 >> 2] = i11;
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  HEAP32[i12 >> 2] = i13 & -2;
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+ }
+ i6 = i11 >>> 3;
+ if (i11 >>> 0 < 256) {
+  i7 = i6 << 1;
+  i3 = 7200 + (i7 << 2) | 0;
+  i8 = HEAP32[1790] | 0;
+  i6 = 1 << i6;
+  if ((i8 & i6 | 0) != 0) {
+   i6 = 7200 + (i7 + 2 << 2) | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if (i7 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+    _abort();
+   } else {
+    i4 = i6;
+    i5 = i7;
+   }
+  } else {
+   HEAP32[1790] = i8 | i6;
+   i4 = 7200 + (i7 + 2 << 2) | 0;
+   i5 = i3;
+  }
+  HEAP32[i4 >> 2] = i2;
+  HEAP32[i5 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i5;
+  HEAP32[i2 + 12 >> 2] = i3;
+  STACKTOP = i1;
+  return;
+ }
+ i4 = i11 >>> 8;
+ if ((i4 | 0) != 0) {
+  if (i11 >>> 0 > 16777215) {
+   i4 = 31;
+  } else {
+   i20 = (i4 + 1048320 | 0) >>> 16 & 8;
+   i21 = i4 << i20;
+   i19 = (i21 + 520192 | 0) >>> 16 & 4;
+   i21 = i21 << i19;
+   i4 = (i21 + 245760 | 0) >>> 16 & 2;
+   i4 = 14 - (i19 | i20 | i4) + (i21 << i4 >>> 15) | 0;
+   i4 = i11 >>> (i4 + 7 | 0) & 1 | i4 << 1;
+  }
+ } else {
+  i4 = 0;
+ }
+ i5 = 7464 + (i4 << 2) | 0;
+ HEAP32[i2 + 28 >> 2] = i4;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ i7 = HEAP32[7164 >> 2] | 0;
+ i6 = 1 << i4;
+ L199 : do {
+  if ((i7 & i6 | 0) != 0) {
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((i4 | 0) == 31) {
+    i4 = 0;
+   } else {
+    i4 = 25 - (i4 >>> 1) | 0;
+   }
+   L204 : do {
+    if ((HEAP32[i5 + 4 >> 2] & -8 | 0) != (i11 | 0)) {
+     i4 = i11 << i4;
+     i7 = i5;
+     while (1) {
+      i6 = i7 + (i4 >>> 31 << 2) + 16 | 0;
+      i5 = HEAP32[i6 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       break;
+      }
+      if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i11 | 0)) {
+       i3 = i5;
+       break L204;
+      } else {
+       i4 = i4 << 1;
+       i7 = i5;
+      }
+     }
+     if (i6 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i6 >> 2] = i2;
+      HEAP32[i2 + 24 >> 2] = i7;
+      HEAP32[i2 + 12 >> 2] = i2;
+      HEAP32[i2 + 8 >> 2] = i2;
+      break L199;
+     }
+    } else {
+     i3 = i5;
+    }
+   } while (0);
+   i5 = i3 + 8 | 0;
+   i4 = HEAP32[i5 >> 2] | 0;
+   i6 = HEAP32[7176 >> 2] | 0;
+   if (i3 >>> 0 < i6 >>> 0) {
+    _abort();
+   }
+   if (i4 >>> 0 < i6 >>> 0) {
+    _abort();
+   } else {
+    HEAP32[i4 + 12 >> 2] = i2;
+    HEAP32[i5 >> 2] = i2;
+    HEAP32[i2 + 8 >> 2] = i4;
+    HEAP32[i2 + 12 >> 2] = i3;
+    HEAP32[i2 + 24 >> 2] = 0;
+    break;
+   }
+  } else {
+   HEAP32[7164 >> 2] = i7 | i6;
+   HEAP32[i5 >> 2] = i2;
+   HEAP32[i2 + 24 >> 2] = i5;
+   HEAP32[i2 + 12 >> 2] = i2;
+   HEAP32[i2 + 8 >> 2] = i2;
+  }
+ } while (0);
+ i21 = (HEAP32[7192 >> 2] | 0) + -1 | 0;
+ HEAP32[7192 >> 2] = i21;
+ if ((i21 | 0) == 0) {
+  i2 = 7616 | 0;
+ } else {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i2 = HEAP32[i2 >> 2] | 0;
+  if ((i2 | 0) == 0) {
+   break;
+  } else {
+   i2 = i2 + 8 | 0;
+  }
+ }
+ HEAP32[7192 >> 2] = -1;
+ STACKTOP = i1;
+ return;
+}
+function __ZNSt3__127__insertion_sort_incompleteIRPFbRK6b2PairS3_EPS1_EEbT0_S8_T_(i3, i4, i2) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i7 = i1 + 12 | 0;
+ i6 = i1;
+ switch ((i4 - i3 | 0) / 12 | 0 | 0) {
+ case 5:
+  {
+   i6 = i3 + 12 | 0;
+   i8 = i3 + 24 | 0;
+   i5 = i3 + 36 | 0;
+   i4 = i4 + -12 | 0;
+   __ZNSt3__17__sort4IRPFbRK6b2PairS3_EPS1_EEjT0_S8_S8_S8_T_(i3, i6, i8, i5, i2) | 0;
+   if (!(FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i4, i5) | 0)) {
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+   HEAP32[i5 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+   HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+   HEAP32[i4 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i4 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i4 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   if (!(FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i5, i8) | 0)) {
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+   HEAP32[i8 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+   HEAP32[i8 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i8 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+   HEAP32[i5 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i5 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   if (!(FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i8, i6) | 0)) {
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   HEAP32[i6 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+   HEAP32[i6 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+   HEAP32[i6 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+   HEAP32[i8 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i8 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i8 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   if (!(FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i6, i3) | 0)) {
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+   HEAP32[i3 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+   HEAP32[i3 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+   HEAP32[i3 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   HEAP32[i6 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i6 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i6 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   i10 = 1;
+   STACKTOP = i1;
+   return i10 | 0;
+  }
+ case 4:
+  {
+   __ZNSt3__17__sort4IRPFbRK6b2PairS3_EPS1_EEjT0_S8_S8_S8_T_(i3, i3 + 12 | 0, i3 + 24 | 0, i4 + -12 | 0, i2) | 0;
+   i10 = 1;
+   STACKTOP = i1;
+   return i10 | 0;
+  }
+ case 3:
+  {
+   i5 = i3 + 12 | 0;
+   i4 = i4 + -12 | 0;
+   i10 = FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i5, i3) | 0;
+   i6 = FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i4, i5) | 0;
+   if (!i10) {
+    if (!i6) {
+     i10 = 1;
+     STACKTOP = i1;
+     return i10 | 0;
+    }
+    HEAP32[i7 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+    HEAP32[i5 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+    HEAP32[i5 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+    HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+    HEAP32[i4 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i4 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i4 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    if (!(FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i5, i3) | 0)) {
+     i10 = 1;
+     STACKTOP = i1;
+     return i10 | 0;
+    }
+    HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+    HEAP32[i3 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+    HEAP32[i5 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i5 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i5 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   if (i6) {
+    HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+    HEAP32[i3 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+    HEAP32[i4 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i4 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i4 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+   HEAP32[i3 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+   HEAP32[i3 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i3 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+   HEAP32[i5 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i5 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   if (!(FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i4, i5) | 0)) {
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+   HEAP32[i5 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+   HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+   HEAP32[i4 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i4 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i4 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   i10 = 1;
+   STACKTOP = i1;
+   return i10 | 0;
+  }
+ case 2:
+  {
+   i4 = i4 + -12 | 0;
+   if (!(FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i4, i3) | 0)) {
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+   HEAP32[i3 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+   HEAP32[i3 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+   HEAP32[i3 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+   HEAP32[i4 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i4 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i4 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   i10 = 1;
+   STACKTOP = i1;
+   return i10 | 0;
+  }
+ case 1:
+ case 0:
+  {
+   i10 = 1;
+   STACKTOP = i1;
+   return i10 | 0;
+  }
+ default:
+  {
+   i9 = i3 + 24 | 0;
+   i10 = i3 + 12 | 0;
+   i11 = FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i10, i3) | 0;
+   i8 = FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i9, i10) | 0;
+   do {
+    if (i11) {
+     if (i8) {
+      HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+      HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+      HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+      HEAP32[i3 + 0 >> 2] = HEAP32[i9 + 0 >> 2];
+      HEAP32[i3 + 4 >> 2] = HEAP32[i9 + 4 >> 2];
+      HEAP32[i3 + 8 >> 2] = HEAP32[i9 + 8 >> 2];
+      HEAP32[i9 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+      HEAP32[i9 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+      HEAP32[i9 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+      break;
+     }
+     HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+     HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+     HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+     HEAP32[i3 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+     HEAP32[i3 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+     HEAP32[i3 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+     HEAP32[i10 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+     HEAP32[i10 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+     HEAP32[i10 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+     if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i9, i10) | 0) {
+      HEAP32[i7 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+      HEAP32[i7 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+      HEAP32[i7 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+      HEAP32[i10 + 0 >> 2] = HEAP32[i9 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i9 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i9 + 8 >> 2];
+      HEAP32[i9 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+      HEAP32[i9 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+      HEAP32[i9 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+     }
+    } else {
+     if (i8) {
+      HEAP32[i7 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+      HEAP32[i7 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+      HEAP32[i7 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+      HEAP32[i10 + 0 >> 2] = HEAP32[i9 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i9 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i9 + 8 >> 2];
+      HEAP32[i9 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+      HEAP32[i9 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+      HEAP32[i9 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+      if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i10, i3) | 0) {
+       HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+       HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+       HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+       HEAP32[i3 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+       HEAP32[i3 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+       HEAP32[i3 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+       HEAP32[i10 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+       HEAP32[i10 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+       HEAP32[i10 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+      }
+     }
+    }
+   } while (0);
+   i7 = i3 + 36 | 0;
+   if ((i7 | 0) == (i4 | 0)) {
+    i11 = 1;
+    STACKTOP = i1;
+    return i11 | 0;
+   }
+   i8 = 0;
+   while (1) {
+    if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i7, i9) | 0) {
+     HEAP32[i6 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+     HEAP32[i6 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+     HEAP32[i6 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+     i10 = i7;
+     while (1) {
+      HEAP32[i10 + 0 >> 2] = HEAP32[i9 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i9 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i9 + 8 >> 2];
+      if ((i9 | 0) == (i3 | 0)) {
+       break;
+      }
+      i10 = i9 + -12 | 0;
+      if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i6, i10) | 0) {
+       i11 = i9;
+       i9 = i10;
+       i10 = i11;
+      } else {
+       break;
+      }
+     }
+     HEAP32[i9 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+     HEAP32[i9 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+     HEAP32[i9 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+     i8 = i8 + 1 | 0;
+     if ((i8 | 0) == 8) {
+      break;
+     }
+    }
+    i9 = i7 + 12 | 0;
+    if ((i9 | 0) == (i4 | 0)) {
+     i2 = 1;
+     i5 = 35;
+     break;
+    } else {
+     i11 = i7;
+     i7 = i9;
+     i9 = i11;
+    }
+   }
+   if ((i5 | 0) == 35) {
+    STACKTOP = i1;
+    return i2 | 0;
+   }
+   i11 = (i7 + 12 | 0) == (i4 | 0);
+   STACKTOP = i1;
+   return i11 | 0;
+  }
+ }
+ return 0;
+}
+function __ZN13b2DynamicTree7BalanceEi(i11, i6) {
+ i11 = i11 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, d19 = 0.0, i20 = 0, i21 = 0, d22 = 0.0, d23 = 0.0, d24 = 0.0, d25 = 0.0;
+ i1 = STACKTOP;
+ if ((i6 | 0) == -1) {
+  ___assert_fail(3216, 2944, 382, 3232);
+ }
+ i5 = HEAP32[i11 + 4 >> 2] | 0;
+ i13 = i5 + (i6 * 36 | 0) | 0;
+ i18 = i5 + (i6 * 36 | 0) + 24 | 0;
+ i8 = HEAP32[i18 >> 2] | 0;
+ if ((i8 | 0) == -1) {
+  i21 = i6;
+  STACKTOP = i1;
+  return i21 | 0;
+ }
+ i2 = i5 + (i6 * 36 | 0) + 32 | 0;
+ if ((HEAP32[i2 >> 2] | 0) < 2) {
+  i21 = i6;
+  STACKTOP = i1;
+  return i21 | 0;
+ }
+ i20 = i5 + (i6 * 36 | 0) + 28 | 0;
+ i7 = HEAP32[i20 >> 2] | 0;
+ if (!((i8 | 0) > -1)) {
+  ___assert_fail(3240, 2944, 392, 3232);
+ }
+ i12 = HEAP32[i11 + 12 >> 2] | 0;
+ if ((i8 | 0) >= (i12 | 0)) {
+  ___assert_fail(3240, 2944, 392, 3232);
+ }
+ if (!((i7 | 0) > -1 & (i7 | 0) < (i12 | 0))) {
+  ___assert_fail(3272, 2944, 393, 3232);
+ }
+ i9 = i5 + (i8 * 36 | 0) | 0;
+ i10 = i5 + (i7 * 36 | 0) | 0;
+ i3 = i5 + (i7 * 36 | 0) + 32 | 0;
+ i4 = i5 + (i8 * 36 | 0) + 32 | 0;
+ i14 = (HEAP32[i3 >> 2] | 0) - (HEAP32[i4 >> 2] | 0) | 0;
+ if ((i14 | 0) > 1) {
+  i21 = i5 + (i7 * 36 | 0) + 24 | 0;
+  i14 = HEAP32[i21 >> 2] | 0;
+  i18 = i5 + (i7 * 36 | 0) + 28 | 0;
+  i15 = HEAP32[i18 >> 2] | 0;
+  i16 = i5 + (i14 * 36 | 0) | 0;
+  i17 = i5 + (i15 * 36 | 0) | 0;
+  if (!((i14 | 0) > -1 & (i14 | 0) < (i12 | 0))) {
+   ___assert_fail(3304, 2944, 407, 3232);
+  }
+  if (!((i15 | 0) > -1 & (i15 | 0) < (i12 | 0))) {
+   ___assert_fail(3336, 2944, 408, 3232);
+  }
+  HEAP32[i21 >> 2] = i6;
+  i21 = i5 + (i6 * 36 | 0) + 20 | 0;
+  i12 = i5 + (i7 * 36 | 0) + 20 | 0;
+  HEAP32[i12 >> 2] = HEAP32[i21 >> 2];
+  HEAP32[i21 >> 2] = i7;
+  i12 = HEAP32[i12 >> 2] | 0;
+  do {
+   if (!((i12 | 0) == -1)) {
+    i11 = i5 + (i12 * 36 | 0) + 24 | 0;
+    if ((HEAP32[i11 >> 2] | 0) == (i6 | 0)) {
+     HEAP32[i11 >> 2] = i7;
+     break;
+    }
+    i11 = i5 + (i12 * 36 | 0) + 28 | 0;
+    if ((HEAP32[i11 >> 2] | 0) == (i6 | 0)) {
+     HEAP32[i11 >> 2] = i7;
+     break;
+    } else {
+     ___assert_fail(3368, 2944, 424, 3232);
+    }
+   } else {
+    HEAP32[i11 >> 2] = i7;
+   }
+  } while (0);
+  i11 = i5 + (i14 * 36 | 0) + 32 | 0;
+  i12 = i5 + (i15 * 36 | 0) + 32 | 0;
+  if ((HEAP32[i11 >> 2] | 0) > (HEAP32[i12 >> 2] | 0)) {
+   HEAP32[i18 >> 2] = i14;
+   HEAP32[i20 >> 2] = i15;
+   HEAP32[i5 + (i15 * 36 | 0) + 20 >> 2] = i6;
+   d19 = +HEAPF32[i9 >> 2];
+   d22 = +HEAPF32[i17 >> 2];
+   d19 = d19 < d22 ? d19 : d22;
+   d23 = +HEAPF32[i5 + (i8 * 36 | 0) + 4 >> 2];
+   d22 = +HEAPF32[i5 + (i15 * 36 | 0) + 4 >> 2];
+   d24 = +d19;
+   d23 = +(d23 < d22 ? d23 : d22);
+   i21 = i13;
+   HEAPF32[i21 >> 2] = d24;
+   HEAPF32[i21 + 4 >> 2] = d23;
+   d23 = +HEAPF32[i5 + (i8 * 36 | 0) + 8 >> 2];
+   d24 = +HEAPF32[i5 + (i15 * 36 | 0) + 8 >> 2];
+   d22 = +HEAPF32[i5 + (i8 * 36 | 0) + 12 >> 2];
+   d25 = +HEAPF32[i5 + (i15 * 36 | 0) + 12 >> 2];
+   d23 = +(d23 > d24 ? d23 : d24);
+   d24 = +(d22 > d25 ? d22 : d25);
+   i21 = i5 + (i6 * 36 | 0) + 8 | 0;
+   HEAPF32[i21 >> 2] = d23;
+   HEAPF32[i21 + 4 >> 2] = d24;
+   d24 = +HEAPF32[i16 >> 2];
+   d22 = +HEAPF32[i5 + (i6 * 36 | 0) + 4 >> 2];
+   d23 = +HEAPF32[i5 + (i14 * 36 | 0) + 4 >> 2];
+   d19 = +(d19 < d24 ? d19 : d24);
+   d22 = +(d22 < d23 ? d22 : d23);
+   i21 = i10;
+   HEAPF32[i21 >> 2] = d19;
+   HEAPF32[i21 + 4 >> 2] = d22;
+   d22 = +HEAPF32[i5 + (i6 * 36 | 0) + 8 >> 2];
+   d19 = +HEAPF32[i5 + (i14 * 36 | 0) + 8 >> 2];
+   d23 = +HEAPF32[i5 + (i6 * 36 | 0) + 12 >> 2];
+   d24 = +HEAPF32[i5 + (i14 * 36 | 0) + 12 >> 2];
+   d19 = +(d22 > d19 ? d22 : d19);
+   d25 = +(d23 > d24 ? d23 : d24);
+   i5 = i5 + (i7 * 36 | 0) + 8 | 0;
+   HEAPF32[i5 >> 2] = d19;
+   HEAPF32[i5 + 4 >> 2] = d25;
+   i4 = HEAP32[i4 >> 2] | 0;
+   i5 = HEAP32[i12 >> 2] | 0;
+   i4 = ((i4 | 0) > (i5 | 0) ? i4 : i5) + 1 | 0;
+   HEAP32[i2 >> 2] = i4;
+   i2 = HEAP32[i11 >> 2] | 0;
+   i2 = (i4 | 0) > (i2 | 0) ? i4 : i2;
+  } else {
+   HEAP32[i18 >> 2] = i15;
+   HEAP32[i20 >> 2] = i14;
+   HEAP32[i5 + (i14 * 36 | 0) + 20 >> 2] = i6;
+   d19 = +HEAPF32[i9 >> 2];
+   d22 = +HEAPF32[i16 >> 2];
+   d19 = d19 < d22 ? d19 : d22;
+   d23 = +HEAPF32[i5 + (i8 * 36 | 0) + 4 >> 2];
+   d24 = +HEAPF32[i5 + (i14 * 36 | 0) + 4 >> 2];
+   d22 = +d19;
+   d23 = +(d23 < d24 ? d23 : d24);
+   i21 = i13;
+   HEAPF32[i21 >> 2] = d22;
+   HEAPF32[i21 + 4 >> 2] = d23;
+   d23 = +HEAPF32[i5 + (i8 * 36 | 0) + 8 >> 2];
+   d24 = +HEAPF32[i5 + (i14 * 36 | 0) + 8 >> 2];
+   d22 = +HEAPF32[i5 + (i8 * 36 | 0) + 12 >> 2];
+   d25 = +HEAPF32[i5 + (i14 * 36 | 0) + 12 >> 2];
+   d23 = +(d23 > d24 ? d23 : d24);
+   d24 = +(d22 > d25 ? d22 : d25);
+   i21 = i5 + (i6 * 36 | 0) + 8 | 0;
+   HEAPF32[i21 >> 2] = d23;
+   HEAPF32[i21 + 4 >> 2] = d24;
+   d24 = +HEAPF32[i17 >> 2];
+   d22 = +HEAPF32[i5 + (i6 * 36 | 0) + 4 >> 2];
+   d23 = +HEAPF32[i5 + (i15 * 36 | 0) + 4 >> 2];
+   d19 = +(d19 < d24 ? d19 : d24);
+   d23 = +(d22 < d23 ? d22 : d23);
+   i21 = i10;
+   HEAPF32[i21 >> 2] = d19;
+   HEAPF32[i21 + 4 >> 2] = d23;
+   d23 = +HEAPF32[i5 + (i6 * 36 | 0) + 8 >> 2];
+   d19 = +HEAPF32[i5 + (i15 * 36 | 0) + 8 >> 2];
+   d22 = +HEAPF32[i5 + (i6 * 36 | 0) + 12 >> 2];
+   d24 = +HEAPF32[i5 + (i15 * 36 | 0) + 12 >> 2];
+   d19 = +(d23 > d19 ? d23 : d19);
+   d25 = +(d22 > d24 ? d22 : d24);
+   i5 = i5 + (i7 * 36 | 0) + 8 | 0;
+   HEAPF32[i5 >> 2] = d19;
+   HEAPF32[i5 + 4 >> 2] = d25;
+   i4 = HEAP32[i4 >> 2] | 0;
+   i5 = HEAP32[i11 >> 2] | 0;
+   i4 = ((i4 | 0) > (i5 | 0) ? i4 : i5) + 1 | 0;
+   HEAP32[i2 >> 2] = i4;
+   i2 = HEAP32[i12 >> 2] | 0;
+   i2 = (i4 | 0) > (i2 | 0) ? i4 : i2;
+  }
+  HEAP32[i3 >> 2] = i2 + 1;
+  i21 = i7;
+  STACKTOP = i1;
+  return i21 | 0;
+ }
+ if (!((i14 | 0) < -1)) {
+  i21 = i6;
+  STACKTOP = i1;
+  return i21 | 0;
+ }
+ i21 = i5 + (i8 * 36 | 0) + 24 | 0;
+ i14 = HEAP32[i21 >> 2] | 0;
+ i20 = i5 + (i8 * 36 | 0) + 28 | 0;
+ i15 = HEAP32[i20 >> 2] | 0;
+ i17 = i5 + (i14 * 36 | 0) | 0;
+ i16 = i5 + (i15 * 36 | 0) | 0;
+ if (!((i14 | 0) > -1 & (i14 | 0) < (i12 | 0))) {
+  ___assert_fail(3400, 2944, 467, 3232);
+ }
+ if (!((i15 | 0) > -1 & (i15 | 0) < (i12 | 0))) {
+  ___assert_fail(3432, 2944, 468, 3232);
+ }
+ HEAP32[i21 >> 2] = i6;
+ i21 = i5 + (i6 * 36 | 0) + 20 | 0;
+ i12 = i5 + (i8 * 36 | 0) + 20 | 0;
+ HEAP32[i12 >> 2] = HEAP32[i21 >> 2];
+ HEAP32[i21 >> 2] = i8;
+ i12 = HEAP32[i12 >> 2] | 0;
+ do {
+  if (!((i12 | 0) == -1)) {
+   i11 = i5 + (i12 * 36 | 0) + 24 | 0;
+   if ((HEAP32[i11 >> 2] | 0) == (i6 | 0)) {
+    HEAP32[i11 >> 2] = i8;
+    break;
+   }
+   i11 = i5 + (i12 * 36 | 0) + 28 | 0;
+   if ((HEAP32[i11 >> 2] | 0) == (i6 | 0)) {
+    HEAP32[i11 >> 2] = i8;
+    break;
+   } else {
+    ___assert_fail(3464, 2944, 484, 3232);
+   }
+  } else {
+   HEAP32[i11 >> 2] = i8;
+  }
+ } while (0);
+ i12 = i5 + (i14 * 36 | 0) + 32 | 0;
+ i11 = i5 + (i15 * 36 | 0) + 32 | 0;
+ if ((HEAP32[i12 >> 2] | 0) > (HEAP32[i11 >> 2] | 0)) {
+  HEAP32[i20 >> 2] = i14;
+  HEAP32[i18 >> 2] = i15;
+  HEAP32[i5 + (i15 * 36 | 0) + 20 >> 2] = i6;
+  d19 = +HEAPF32[i10 >> 2];
+  d22 = +HEAPF32[i16 >> 2];
+  d19 = d19 < d22 ? d19 : d22;
+  d23 = +HEAPF32[i5 + (i7 * 36 | 0) + 4 >> 2];
+  d22 = +HEAPF32[i5 + (i15 * 36 | 0) + 4 >> 2];
+  d24 = +d19;
+  d23 = +(d23 < d22 ? d23 : d22);
+  i21 = i13;
+  HEAPF32[i21 >> 2] = d24;
+  HEAPF32[i21 + 4 >> 2] = d23;
+  d23 = +HEAPF32[i5 + (i7 * 36 | 0) + 8 >> 2];
+  d22 = +HEAPF32[i5 + (i15 * 36 | 0) + 8 >> 2];
+  d24 = +HEAPF32[i5 + (i7 * 36 | 0) + 12 >> 2];
+  d25 = +HEAPF32[i5 + (i15 * 36 | 0) + 12 >> 2];
+  d22 = +(d23 > d22 ? d23 : d22);
+  d24 = +(d24 > d25 ? d24 : d25);
+  i21 = i5 + (i6 * 36 | 0) + 8 | 0;
+  HEAPF32[i21 >> 2] = d22;
+  HEAPF32[i21 + 4 >> 2] = d24;
+  d24 = +HEAPF32[i17 >> 2];
+  d23 = +HEAPF32[i5 + (i6 * 36 | 0) + 4 >> 2];
+  d22 = +HEAPF32[i5 + (i14 * 36 | 0) + 4 >> 2];
+  d19 = +(d19 < d24 ? d19 : d24);
+  d22 = +(d23 < d22 ? d23 : d22);
+  i21 = i9;
+  HEAPF32[i21 >> 2] = d19;
+  HEAPF32[i21 + 4 >> 2] = d22;
+  d22 = +HEAPF32[i5 + (i6 * 36 | 0) + 8 >> 2];
+  d23 = +HEAPF32[i5 + (i14 * 36 | 0) + 8 >> 2];
+  d19 = +HEAPF32[i5 + (i6 * 36 | 0) + 12 >> 2];
+  d24 = +HEAPF32[i5 + (i14 * 36 | 0) + 12 >> 2];
+  d22 = +(d22 > d23 ? d22 : d23);
+  d25 = +(d19 > d24 ? d19 : d24);
+  i5 = i5 + (i8 * 36 | 0) + 8 | 0;
+  HEAPF32[i5 >> 2] = d22;
+  HEAPF32[i5 + 4 >> 2] = d25;
+  i3 = HEAP32[i3 >> 2] | 0;
+  i5 = HEAP32[i11 >> 2] | 0;
+  i3 = ((i3 | 0) > (i5 | 0) ? i3 : i5) + 1 | 0;
+  HEAP32[i2 >> 2] = i3;
+  i2 = HEAP32[i12 >> 2] | 0;
+  i2 = (i3 | 0) > (i2 | 0) ? i3 : i2;
+ } else {
+  HEAP32[i20 >> 2] = i15;
+  HEAP32[i18 >> 2] = i14;
+  HEAP32[i5 + (i14 * 36 | 0) + 20 >> 2] = i6;
+  d19 = +HEAPF32[i10 >> 2];
+  d22 = +HEAPF32[i17 >> 2];
+  d19 = d19 < d22 ? d19 : d22;
+  d23 = +HEAPF32[i5 + (i7 * 36 | 0) + 4 >> 2];
+  d24 = +HEAPF32[i5 + (i14 * 36 | 0) + 4 >> 2];
+  d22 = +d19;
+  d24 = +(d23 < d24 ? d23 : d24);
+  i21 = i13;
+  HEAPF32[i21 >> 2] = d22;
+  HEAPF32[i21 + 4 >> 2] = d24;
+  d24 = +HEAPF32[i5 + (i7 * 36 | 0) + 8 >> 2];
+  d23 = +HEAPF32[i5 + (i14 * 36 | 0) + 8 >> 2];
+  d22 = +HEAPF32[i5 + (i7 * 36 | 0) + 12 >> 2];
+  d25 = +HEAPF32[i5 + (i14 * 36 | 0) + 12 >> 2];
+  d23 = +(d24 > d23 ? d24 : d23);
+  d24 = +(d22 > d25 ? d22 : d25);
+  i21 = i5 + (i6 * 36 | 0) + 8 | 0;
+  HEAPF32[i21 >> 2] = d23;
+  HEAPF32[i21 + 4 >> 2] = d24;
+  d24 = +HEAPF32[i16 >> 2];
+  d23 = +HEAPF32[i5 + (i6 * 36 | 0) + 4 >> 2];
+  d22 = +HEAPF32[i5 + (i15 * 36 | 0) + 4 >> 2];
+  d19 = +(d19 < d24 ? d19 : d24);
+  d22 = +(d23 < d22 ? d23 : d22);
+  i21 = i9;
+  HEAPF32[i21 >> 2] = d19;
+  HEAPF32[i21 + 4 >> 2] = d22;
+  d22 = +HEAPF32[i5 + (i6 * 36 | 0) + 8 >> 2];
+  d23 = +HEAPF32[i5 + (i15 * 36 | 0) + 8 >> 2];
+  d19 = +HEAPF32[i5 + (i6 * 36 | 0) + 12 >> 2];
+  d24 = +HEAPF32[i5 + (i15 * 36 | 0) + 12 >> 2];
+  d22 = +(d22 > d23 ? d22 : d23);
+  d25 = +(d19 > d24 ? d19 : d24);
+  i5 = i5 + (i8 * 36 | 0) + 8 | 0;
+  HEAPF32[i5 >> 2] = d22;
+  HEAPF32[i5 + 4 >> 2] = d25;
+  i3 = HEAP32[i3 >> 2] | 0;
+  i5 = HEAP32[i12 >> 2] | 0;
+  i3 = ((i3 | 0) > (i5 | 0) ? i3 : i5) + 1 | 0;
+  HEAP32[i2 >> 2] = i3;
+  i2 = HEAP32[i11 >> 2] | 0;
+  i2 = (i3 | 0) > (i2 | 0) ? i3 : i2;
+ }
+ HEAP32[i4 >> 2] = i2 + 1;
+ i21 = i8;
+ STACKTOP = i1;
+ return i21 | 0;
+}
+function __Z10b2DistanceP16b2DistanceOutputP14b2SimplexCachePK15b2DistanceInput(i2, i5, i3) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i6 = 0, d7 = 0.0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, i20 = 0, d21 = 0.0, d22 = 0.0, i23 = 0, d24 = 0.0, d25 = 0.0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, d36 = 0.0, d37 = 0.0, d38 = 0.0, i39 = 0, i40 = 0, i41 = 0, i42 = 0, d43 = 0.0, d44 = 0.0, d45 = 0.0, i46 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 176 | 0;
+ i11 = i1 + 152 | 0;
+ i10 = i1 + 136 | 0;
+ i4 = i1 + 24 | 0;
+ i14 = i1 + 12 | 0;
+ i15 = i1;
+ HEAP32[652] = (HEAP32[652] | 0) + 1;
+ i9 = i3 + 28 | 0;
+ i31 = i3 + 56 | 0;
+ HEAP32[i11 + 0 >> 2] = HEAP32[i31 + 0 >> 2];
+ HEAP32[i11 + 4 >> 2] = HEAP32[i31 + 4 >> 2];
+ HEAP32[i11 + 8 >> 2] = HEAP32[i31 + 8 >> 2];
+ HEAP32[i11 + 12 >> 2] = HEAP32[i31 + 12 >> 2];
+ i31 = i3 + 72 | 0;
+ HEAP32[i10 + 0 >> 2] = HEAP32[i31 + 0 >> 2];
+ HEAP32[i10 + 4 >> 2] = HEAP32[i31 + 4 >> 2];
+ HEAP32[i10 + 8 >> 2] = HEAP32[i31 + 8 >> 2];
+ HEAP32[i10 + 12 >> 2] = HEAP32[i31 + 12 >> 2];
+ __ZN9b2Simplex9ReadCacheEPK14b2SimplexCachePK15b2DistanceProxyRK11b2TransformS5_S8_(i4, i5, i3, i11, i9, i10);
+ i9 = i4 + 108 | 0;
+ i31 = HEAP32[i9 >> 2] | 0;
+ if ((i31 | 0) == 3 | (i31 | 0) == 2 | (i31 | 0) == 1) {
+  i8 = i4 + 16 | 0;
+  i6 = i4 + 20 | 0;
+  d17 = +HEAPF32[i11 + 12 >> 2];
+  d18 = +HEAPF32[i11 + 8 >> 2];
+  i13 = i3 + 16 | 0;
+  i12 = i3 + 20 | 0;
+  d16 = +HEAPF32[i11 >> 2];
+  d21 = +HEAPF32[i11 + 4 >> 2];
+  d19 = +HEAPF32[i10 + 12 >> 2];
+  d22 = +HEAPF32[i10 + 8 >> 2];
+  i23 = i3 + 44 | 0;
+  i20 = i3 + 48 | 0;
+  d24 = +HEAPF32[i10 >> 2];
+  d25 = +HEAPF32[i10 + 4 >> 2];
+  i11 = i4 + 52 | 0;
+  i10 = i4 + 56 | 0;
+  i30 = i4 + 16 | 0;
+  i27 = i4 + 36 | 0;
+  i26 = i4 + 52 | 0;
+  i29 = i4 + 24 | 0;
+  i28 = i4 + 60 | 0;
+  i33 = 0;
+  L3 : while (1) {
+   i32 = (i31 | 0) > 0;
+   if (i32) {
+    i34 = 0;
+    do {
+     HEAP32[i14 + (i34 << 2) >> 2] = HEAP32[i4 + (i34 * 36 | 0) + 28 >> 2];
+     HEAP32[i15 + (i34 << 2) >> 2] = HEAP32[i4 + (i34 * 36 | 0) + 32 >> 2];
+     i34 = i34 + 1 | 0;
+    } while ((i34 | 0) != (i31 | 0));
+   }
+   do {
+    if ((i31 | 0) == 2) {
+     i46 = i30;
+     d45 = +HEAPF32[i46 >> 2];
+     d36 = +HEAPF32[i46 + 4 >> 2];
+     i46 = i26;
+     d38 = +HEAPF32[i46 >> 2];
+     d37 = +HEAPF32[i46 + 4 >> 2];
+     d43 = d38 - d45;
+     d44 = d37 - d36;
+     d36 = d45 * d43 + d36 * d44;
+     if (d36 >= -0.0) {
+      HEAPF32[i29 >> 2] = 1.0;
+      HEAP32[i9 >> 2] = 1;
+      i35 = 17;
+      break;
+     }
+     d37 = d38 * d43 + d37 * d44;
+     if (!(d37 <= 0.0)) {
+      d45 = 1.0 / (d37 - d36);
+      HEAPF32[i29 >> 2] = d37 * d45;
+      HEAPF32[i28 >> 2] = -(d36 * d45);
+      HEAP32[i9 >> 2] = 2;
+      i35 = 18;
+      break;
+     } else {
+      HEAPF32[i28 >> 2] = 1.0;
+      HEAP32[i9 >> 2] = 1;
+      i34 = i4 + 0 | 0;
+      i39 = i27 + 0 | 0;
+      i35 = i34 + 36 | 0;
+      do {
+       HEAP32[i34 >> 2] = HEAP32[i39 >> 2];
+       i34 = i34 + 4 | 0;
+       i39 = i39 + 4 | 0;
+      } while ((i34 | 0) < (i35 | 0));
+      i35 = 17;
+      break;
+     }
+    } else if ((i31 | 0) == 3) {
+     __ZN9b2Simplex6Solve3Ev(i4);
+     i34 = HEAP32[i9 >> 2] | 0;
+     if ((i34 | 0) == 1) {
+      i35 = 17;
+     } else if ((i34 | 0) == 0) {
+      i35 = 15;
+      break L3;
+     } else if ((i34 | 0) == 2) {
+      i35 = 18;
+     } else if ((i34 | 0) == 3) {
+      i35 = 42;
+      break L3;
+     } else {
+      i35 = 16;
+      break L3;
+     }
+    } else if ((i31 | 0) == 1) {
+     i35 = 17;
+    } else {
+     i35 = 13;
+     break L3;
+    }
+   } while (0);
+   do {
+    if ((i35 | 0) == 17) {
+     d36 = -+HEAPF32[i8 >> 2];
+     d37 = -+HEAPF32[i6 >> 2];
+     i34 = 1;
+    } else if ((i35 | 0) == 18) {
+     d44 = +HEAPF32[i8 >> 2];
+     d37 = +HEAPF32[i11 >> 2] - d44;
+     d45 = +HEAPF32[i6 >> 2];
+     d36 = +HEAPF32[i10 >> 2] - d45;
+     if (d44 * d36 - d37 * d45 > 0.0) {
+      d36 = -d36;
+      i34 = 2;
+      break;
+     } else {
+      d37 = -d37;
+      i34 = 2;
+      break;
+     }
+    }
+   } while (0);
+   if (d37 * d37 + d36 * d36 < 1.4210854715202004e-14) {
+    i35 = 42;
+    break;
+   }
+   i39 = i4 + (i34 * 36 | 0) | 0;
+   d44 = -d36;
+   d45 = -d37;
+   d43 = d17 * d44 + d18 * d45;
+   d44 = d17 * d45 - d18 * d44;
+   i40 = HEAP32[i13 >> 2] | 0;
+   i41 = HEAP32[i12 >> 2] | 0;
+   if ((i41 | 0) > 1) {
+    i42 = 0;
+    d45 = d44 * +HEAPF32[i40 + 4 >> 2] + d43 * +HEAPF32[i40 >> 2];
+    i46 = 1;
+    while (1) {
+     d38 = d43 * +HEAPF32[i40 + (i46 << 3) >> 2] + d44 * +HEAPF32[i40 + (i46 << 3) + 4 >> 2];
+     i35 = d38 > d45;
+     i42 = i35 ? i46 : i42;
+     i46 = i46 + 1 | 0;
+     if ((i46 | 0) == (i41 | 0)) {
+      break;
+     } else {
+      d45 = i35 ? d38 : d45;
+     }
+    }
+    i35 = i4 + (i34 * 36 | 0) + 28 | 0;
+    HEAP32[i35 >> 2] = i42;
+    if (!((i42 | 0) > -1)) {
+     i35 = 28;
+     break;
+    }
+   } else {
+    i35 = i4 + (i34 * 36 | 0) + 28 | 0;
+    HEAP32[i35 >> 2] = 0;
+    i42 = 0;
+   }
+   if ((i41 | 0) <= (i42 | 0)) {
+    i35 = 28;
+    break;
+   }
+   d45 = +HEAPF32[i40 + (i42 << 3) >> 2];
+   d43 = +HEAPF32[i40 + (i42 << 3) + 4 >> 2];
+   d38 = d16 + (d17 * d45 - d18 * d43);
+   d44 = +d38;
+   d43 = +(d45 * d18 + d17 * d43 + d21);
+   i40 = i39;
+   HEAPF32[i40 >> 2] = d44;
+   HEAPF32[i40 + 4 >> 2] = d43;
+   d43 = d36 * d19 + d37 * d22;
+   d44 = d37 * d19 - d36 * d22;
+   i40 = HEAP32[i23 >> 2] | 0;
+   i39 = HEAP32[i20 >> 2] | 0;
+   if ((i39 | 0) > 1) {
+    i41 = 0;
+    d37 = d44 * +HEAPF32[i40 + 4 >> 2] + d43 * +HEAPF32[i40 >> 2];
+    i42 = 1;
+    while (1) {
+     d36 = d43 * +HEAPF32[i40 + (i42 << 3) >> 2] + d44 * +HEAPF32[i40 + (i42 << 3) + 4 >> 2];
+     i46 = d36 > d37;
+     i41 = i46 ? i42 : i41;
+     i42 = i42 + 1 | 0;
+     if ((i42 | 0) == (i39 | 0)) {
+      break;
+     } else {
+      d37 = i46 ? d36 : d37;
+     }
+    }
+    i42 = i4 + (i34 * 36 | 0) + 32 | 0;
+    HEAP32[i42 >> 2] = i41;
+    if (!((i41 | 0) > -1)) {
+     i35 = 35;
+     break;
+    }
+   } else {
+    i42 = i4 + (i34 * 36 | 0) + 32 | 0;
+    HEAP32[i42 >> 2] = 0;
+    i41 = 0;
+   }
+   if ((i39 | 0) <= (i41 | 0)) {
+    i35 = 35;
+    break;
+   }
+   d37 = +HEAPF32[i40 + (i41 << 3) >> 2];
+   d45 = +HEAPF32[i40 + (i41 << 3) + 4 >> 2];
+   d44 = d24 + (d19 * d37 - d22 * d45);
+   d43 = +d44;
+   d45 = +(d37 * d22 + d19 * d45 + d25);
+   i46 = i4 + (i34 * 36 | 0) + 8 | 0;
+   HEAPF32[i46 >> 2] = d43;
+   HEAPF32[i46 + 4 >> 2] = d45;
+   d44 = +(d44 - d38);
+   d45 = +(+HEAPF32[i4 + (i34 * 36 | 0) + 12 >> 2] - +HEAPF32[i4 + (i34 * 36 | 0) + 4 >> 2]);
+   i46 = i4 + (i34 * 36 | 0) + 16 | 0;
+   HEAPF32[i46 >> 2] = d44;
+   HEAPF32[i46 + 4 >> 2] = d45;
+   i33 = i33 + 1 | 0;
+   HEAP32[654] = (HEAP32[654] | 0) + 1;
+   if (i32) {
+    i34 = HEAP32[i35 >> 2] | 0;
+    i32 = 0;
+    do {
+     if ((i34 | 0) == (HEAP32[i14 + (i32 << 2) >> 2] | 0) ? (HEAP32[i42 >> 2] | 0) == (HEAP32[i15 + (i32 << 2) >> 2] | 0) : 0) {
+      i35 = 42;
+      break L3;
+     }
+     i32 = i32 + 1 | 0;
+    } while ((i32 | 0) < (i31 | 0));
+   }
+   i31 = (HEAP32[i9 >> 2] | 0) + 1 | 0;
+   HEAP32[i9 >> 2] = i31;
+   if ((i33 | 0) >= 20) {
+    i35 = 42;
+    break;
+   }
+  }
+  if ((i35 | 0) == 13) {
+   ___assert_fail(2712, 2672, 498, 2720);
+  } else if ((i35 | 0) == 15) {
+   ___assert_fail(2712, 2672, 194, 2856);
+  } else if ((i35 | 0) == 16) {
+   ___assert_fail(2712, 2672, 207, 2856);
+  } else if ((i35 | 0) == 28) {
+   ___assert_fail(2776, 2808, 103, 2840);
+  } else if ((i35 | 0) == 35) {
+   ___assert_fail(2776, 2808, 103, 2840);
+  } else if ((i35 | 0) == 42) {
+   i12 = HEAP32[656] | 0;
+   HEAP32[656] = (i12 | 0) > (i33 | 0) ? i12 : i33;
+   i14 = i2 + 8 | 0;
+   __ZNK9b2Simplex16GetWitnessPointsEP6b2Vec2S1_(i4, i2, i14);
+   d44 = +HEAPF32[i2 >> 2] - +HEAPF32[i14 >> 2];
+   i13 = i2 + 4 | 0;
+   i12 = i2 + 12 | 0;
+   d45 = +HEAPF32[i13 >> 2] - +HEAPF32[i12 >> 2];
+   i15 = i2 + 16 | 0;
+   HEAPF32[i15 >> 2] = +Math_sqrt(+(d44 * d44 + d45 * d45));
+   HEAP32[i2 + 20 >> 2] = i33;
+   i9 = HEAP32[i9 >> 2] | 0;
+   if ((i9 | 0) == 2) {
+    d45 = +HEAPF32[i8 >> 2] - +HEAPF32[i11 >> 2];
+    d7 = +HEAPF32[i6 >> 2] - +HEAPF32[i10 >> 2];
+    d7 = +Math_sqrt(+(d45 * d45 + d7 * d7));
+   } else if ((i9 | 0) == 3) {
+    d7 = +HEAPF32[i8 >> 2];
+    d45 = +HEAPF32[i6 >> 2];
+    d7 = (+HEAPF32[i11 >> 2] - d7) * (+HEAPF32[i4 + 92 >> 2] - d45) - (+HEAPF32[i10 >> 2] - d45) * (+HEAPF32[i4 + 88 >> 2] - d7);
+   } else if ((i9 | 0) == 1) {
+    d7 = 0.0;
+   } else if ((i9 | 0) == 0) {
+    ___assert_fail(2712, 2672, 246, 2736);
+   } else {
+    ___assert_fail(2712, 2672, 259, 2736);
+   }
+   HEAPF32[i5 >> 2] = d7;
+   HEAP16[i5 + 4 >> 1] = i9;
+   i6 = 0;
+   do {
+    HEAP8[i5 + i6 + 6 | 0] = HEAP32[i4 + (i6 * 36 | 0) + 28 >> 2];
+    HEAP8[i5 + i6 + 9 | 0] = HEAP32[i4 + (i6 * 36 | 0) + 32 >> 2];
+    i6 = i6 + 1 | 0;
+   } while ((i6 | 0) < (i9 | 0));
+   if ((HEAP8[i3 + 88 | 0] | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   d7 = +HEAPF32[i3 + 24 >> 2];
+   d16 = +HEAPF32[i3 + 52 >> 2];
+   d18 = +HEAPF32[i15 >> 2];
+   d17 = d7 + d16;
+   if (!(d18 > d17 & d18 > 1.1920928955078125e-7)) {
+    d44 = +((+HEAPF32[i2 >> 2] + +HEAPF32[i14 >> 2]) * .5);
+    d45 = +((+HEAPF32[i13 >> 2] + +HEAPF32[i12 >> 2]) * .5);
+    i46 = i2;
+    HEAPF32[i46 >> 2] = d44;
+    HEAPF32[i46 + 4 >> 2] = d45;
+    i46 = i14;
+    HEAPF32[i46 >> 2] = d44;
+    HEAPF32[i46 + 4 >> 2] = d45;
+    HEAPF32[i15 >> 2] = 0.0;
+    STACKTOP = i1;
+    return;
+   }
+   HEAPF32[i15 >> 2] = d18 - d17;
+   d18 = +HEAPF32[i14 >> 2];
+   d21 = +HEAPF32[i2 >> 2];
+   d24 = d18 - d21;
+   d17 = +HEAPF32[i12 >> 2];
+   d19 = +HEAPF32[i13 >> 2];
+   d22 = d17 - d19;
+   d25 = +Math_sqrt(+(d24 * d24 + d22 * d22));
+   if (!(d25 < 1.1920928955078125e-7)) {
+    d45 = 1.0 / d25;
+    d24 = d24 * d45;
+    d22 = d22 * d45;
+   }
+   HEAPF32[i2 >> 2] = d7 * d24 + d21;
+   HEAPF32[i13 >> 2] = d7 * d22 + d19;
+   HEAPF32[i14 >> 2] = d18 - d16 * d24;
+   HEAPF32[i12 >> 2] = d17 - d16 * d22;
+   STACKTOP = i1;
+   return;
+  }
+ } else if ((i31 | 0) == 0) {
+  ___assert_fail(2712, 2672, 194, 2856);
+ } else {
+  ___assert_fail(2712, 2672, 207, 2856);
+ }
+}
+function __ZN8b2Island5SolveEP9b2ProfileRK10b2TimeStepRK6b2Vec2b(i4, i8, i11, i17, i7) {
+ i4 = i4 | 0;
+ i8 = i8 | 0;
+ i11 = i11 | 0;
+ i17 = i17 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, d5 = 0.0, i6 = 0, i9 = 0, i10 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i18 = 0, i19 = 0, i20 = 0, d21 = 0.0, i22 = 0, d23 = 0.0, d24 = 0.0, d25 = 0.0, d26 = 0.0, d27 = 0.0, d28 = 0.0, d29 = 0.0, i30 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 160 | 0;
+ i6 = i3 + 128 | 0;
+ i9 = i3 + 148 | 0;
+ i10 = i3 + 96 | 0;
+ i16 = i3 + 52 | 0;
+ i2 = i3;
+ __ZN7b2TimerC2Ev(i9);
+ d5 = +HEAPF32[i11 >> 2];
+ i1 = i4 + 28 | 0;
+ if ((HEAP32[i1 >> 2] | 0) > 0) {
+  i13 = i4 + 8 | 0;
+  i12 = i17 + 4 | 0;
+  i15 = i4 + 20 | 0;
+  i14 = i4 + 24 | 0;
+  i19 = 0;
+  do {
+   i22 = HEAP32[(HEAP32[i13 >> 2] | 0) + (i19 << 2) >> 2] | 0;
+   i18 = i22 + 44 | 0;
+   i20 = HEAP32[i18 >> 2] | 0;
+   i18 = HEAP32[i18 + 4 >> 2] | 0;
+   d21 = +HEAPF32[i22 + 56 >> 2];
+   i30 = i22 + 64 | 0;
+   d27 = +HEAPF32[i30 >> 2];
+   d24 = +HEAPF32[i30 + 4 >> 2];
+   d23 = +HEAPF32[i22 + 72 >> 2];
+   i30 = i22 + 36 | 0;
+   HEAP32[i30 >> 2] = i20;
+   HEAP32[i30 + 4 >> 2] = i18;
+   HEAPF32[i22 + 52 >> 2] = d21;
+   if ((HEAP32[i22 >> 2] | 0) == 2) {
+    d25 = +HEAPF32[i22 + 140 >> 2];
+    d26 = +HEAPF32[i22 + 120 >> 2];
+    d28 = 1.0 - d5 * +HEAPF32[i22 + 132 >> 2];
+    d28 = d28 < 1.0 ? d28 : 1.0;
+    d28 = d28 < 0.0 ? 0.0 : d28;
+    d29 = 1.0 - d5 * +HEAPF32[i22 + 136 >> 2];
+    d29 = d29 < 1.0 ? d29 : 1.0;
+    d27 = (d27 + d5 * (d25 * +HEAPF32[i17 >> 2] + d26 * +HEAPF32[i22 + 76 >> 2])) * d28;
+    d24 = (d24 + d5 * (d25 * +HEAPF32[i12 >> 2] + d26 * +HEAPF32[i22 + 80 >> 2])) * d28;
+    d23 = (d23 + d5 * +HEAPF32[i22 + 128 >> 2] * +HEAPF32[i22 + 84 >> 2]) * (d29 < 0.0 ? 0.0 : d29);
+   }
+   i30 = (HEAP32[i15 >> 2] | 0) + (i19 * 12 | 0) | 0;
+   HEAP32[i30 >> 2] = i20;
+   HEAP32[i30 + 4 >> 2] = i18;
+   HEAPF32[(HEAP32[i15 >> 2] | 0) + (i19 * 12 | 0) + 8 >> 2] = d21;
+   d28 = +d27;
+   d29 = +d24;
+   i30 = (HEAP32[i14 >> 2] | 0) + (i19 * 12 | 0) | 0;
+   HEAPF32[i30 >> 2] = d28;
+   HEAPF32[i30 + 4 >> 2] = d29;
+   HEAPF32[(HEAP32[i14 >> 2] | 0) + (i19 * 12 | 0) + 8 >> 2] = d23;
+   i19 = i19 + 1 | 0;
+  } while ((i19 | 0) < (HEAP32[i1 >> 2] | 0));
+ } else {
+  i14 = i4 + 24 | 0;
+  i15 = i4 + 20 | 0;
+ }
+ HEAP32[i10 + 0 >> 2] = HEAP32[i11 + 0 >> 2];
+ HEAP32[i10 + 4 >> 2] = HEAP32[i11 + 4 >> 2];
+ HEAP32[i10 + 8 >> 2] = HEAP32[i11 + 8 >> 2];
+ HEAP32[i10 + 12 >> 2] = HEAP32[i11 + 12 >> 2];
+ HEAP32[i10 + 16 >> 2] = HEAP32[i11 + 16 >> 2];
+ HEAP32[i10 + 20 >> 2] = HEAP32[i11 + 20 >> 2];
+ i22 = HEAP32[i15 >> 2] | 0;
+ HEAP32[i10 + 24 >> 2] = i22;
+ i30 = HEAP32[i14 >> 2] | 0;
+ HEAP32[i10 + 28 >> 2] = i30;
+ HEAP32[i16 + 0 >> 2] = HEAP32[i11 + 0 >> 2];
+ HEAP32[i16 + 4 >> 2] = HEAP32[i11 + 4 >> 2];
+ HEAP32[i16 + 8 >> 2] = HEAP32[i11 + 8 >> 2];
+ HEAP32[i16 + 12 >> 2] = HEAP32[i11 + 12 >> 2];
+ HEAP32[i16 + 16 >> 2] = HEAP32[i11 + 16 >> 2];
+ HEAP32[i16 + 20 >> 2] = HEAP32[i11 + 20 >> 2];
+ i13 = i4 + 12 | 0;
+ HEAP32[i16 + 24 >> 2] = HEAP32[i13 >> 2];
+ i12 = i4 + 36 | 0;
+ HEAP32[i16 + 28 >> 2] = HEAP32[i12 >> 2];
+ HEAP32[i16 + 32 >> 2] = i22;
+ HEAP32[i16 + 36 >> 2] = i30;
+ HEAP32[i16 + 40 >> 2] = HEAP32[i4 >> 2];
+ __ZN15b2ContactSolverC2EP18b2ContactSolverDef(i2, i16);
+ __ZN15b2ContactSolver29InitializeVelocityConstraintsEv(i2);
+ if ((HEAP8[i11 + 20 | 0] | 0) != 0) {
+  __ZN15b2ContactSolver9WarmStartEv(i2);
+ }
+ i16 = i4 + 32 | 0;
+ if ((HEAP32[i16 >> 2] | 0) > 0) {
+  i18 = i4 + 16 | 0;
+  i17 = 0;
+  do {
+   i30 = HEAP32[(HEAP32[i18 >> 2] | 0) + (i17 << 2) >> 2] | 0;
+   FUNCTION_TABLE_vii[HEAP32[(HEAP32[i30 >> 2] | 0) + 28 >> 2] & 15](i30, i10);
+   i17 = i17 + 1 | 0;
+  } while ((i17 | 0) < (HEAP32[i16 >> 2] | 0));
+ }
+ HEAPF32[i8 + 12 >> 2] = +__ZNK7b2Timer15GetMillisecondsEv(i9);
+ i17 = i11 + 12 | 0;
+ if ((HEAP32[i17 >> 2] | 0) > 0) {
+  i20 = i4 + 16 | 0;
+  i19 = 0;
+  do {
+   if ((HEAP32[i16 >> 2] | 0) > 0) {
+    i18 = 0;
+    do {
+     i30 = HEAP32[(HEAP32[i20 >> 2] | 0) + (i18 << 2) >> 2] | 0;
+     FUNCTION_TABLE_vii[HEAP32[(HEAP32[i30 >> 2] | 0) + 32 >> 2] & 15](i30, i10);
+     i18 = i18 + 1 | 0;
+    } while ((i18 | 0) < (HEAP32[i16 >> 2] | 0));
+   }
+   __ZN15b2ContactSolver24SolveVelocityConstraintsEv(i2);
+   i19 = i19 + 1 | 0;
+  } while ((i19 | 0) < (HEAP32[i17 >> 2] | 0));
+ }
+ __ZN15b2ContactSolver13StoreImpulsesEv(i2);
+ HEAPF32[i8 + 16 >> 2] = +__ZNK7b2Timer15GetMillisecondsEv(i9);
+ if ((HEAP32[i1 >> 2] | 0) > 0) {
+  i19 = HEAP32[i14 >> 2] | 0;
+  i18 = 0;
+  do {
+   i30 = HEAP32[i15 >> 2] | 0;
+   i17 = i30 + (i18 * 12 | 0) | 0;
+   i22 = i17;
+   d23 = +HEAPF32[i22 >> 2];
+   d21 = +HEAPF32[i22 + 4 >> 2];
+   d24 = +HEAPF32[i30 + (i18 * 12 | 0) + 8 >> 2];
+   i30 = i19 + (i18 * 12 | 0) | 0;
+   d26 = +HEAPF32[i30 >> 2];
+   d27 = +HEAPF32[i30 + 4 >> 2];
+   d25 = +HEAPF32[i19 + (i18 * 12 | 0) + 8 >> 2];
+   d29 = d5 * d26;
+   d28 = d5 * d27;
+   d28 = d29 * d29 + d28 * d28;
+   if (d28 > 4.0) {
+    d29 = 2.0 / +Math_sqrt(+d28);
+    d26 = d26 * d29;
+    d27 = d27 * d29;
+   }
+   d28 = d5 * d25;
+   if (d28 * d28 > 2.4674012660980225) {
+    if (!(d28 > 0.0)) {
+     d28 = -d28;
+    }
+    d25 = d25 * (1.5707963705062866 / d28);
+   }
+   d29 = +(d23 + d5 * d26);
+   d28 = +(d21 + d5 * d27);
+   i19 = i17;
+   HEAPF32[i19 >> 2] = d29;
+   HEAPF32[i19 + 4 >> 2] = d28;
+   HEAPF32[(HEAP32[i15 >> 2] | 0) + (i18 * 12 | 0) + 8 >> 2] = d24 + d5 * d25;
+   d28 = +d26;
+   d29 = +d27;
+   i19 = (HEAP32[i14 >> 2] | 0) + (i18 * 12 | 0) | 0;
+   HEAPF32[i19 >> 2] = d28;
+   HEAPF32[i19 + 4 >> 2] = d29;
+   i19 = HEAP32[i14 >> 2] | 0;
+   HEAPF32[i19 + (i18 * 12 | 0) + 8 >> 2] = d25;
+   i18 = i18 + 1 | 0;
+  } while ((i18 | 0) < (HEAP32[i1 >> 2] | 0));
+ }
+ i11 = i11 + 16 | 0;
+ L41 : do {
+  if ((HEAP32[i11 >> 2] | 0) > 0) {
+   i17 = i4 + 16 | 0;
+   i19 = 0;
+   while (1) {
+    i18 = __ZN15b2ContactSolver24SolvePositionConstraintsEv(i2) | 0;
+    if ((HEAP32[i16 >> 2] | 0) > 0) {
+     i20 = 0;
+     i22 = 1;
+     do {
+      i30 = HEAP32[(HEAP32[i17 >> 2] | 0) + (i20 << 2) >> 2] | 0;
+      i22 = i22 & (FUNCTION_TABLE_iii[HEAP32[(HEAP32[i30 >> 2] | 0) + 36 >> 2] & 3](i30, i10) | 0);
+      i20 = i20 + 1 | 0;
+     } while ((i20 | 0) < (HEAP32[i16 >> 2] | 0));
+    } else {
+     i22 = 1;
+    }
+    i19 = i19 + 1 | 0;
+    if (i18 & i22) {
+     i10 = 0;
+     break L41;
+    }
+    if ((i19 | 0) >= (HEAP32[i11 >> 2] | 0)) {
+     i10 = 1;
+     break;
+    }
+   }
+  } else {
+   i10 = 1;
+  }
+ } while (0);
+ if ((HEAP32[i1 >> 2] | 0) > 0) {
+  i11 = i4 + 8 | 0;
+  i16 = 0;
+  do {
+   i30 = HEAP32[(HEAP32[i11 >> 2] | 0) + (i16 << 2) >> 2] | 0;
+   i22 = (HEAP32[i15 >> 2] | 0) + (i16 * 12 | 0) | 0;
+   i20 = HEAP32[i22 >> 2] | 0;
+   i22 = HEAP32[i22 + 4 >> 2] | 0;
+   i17 = i30 + 44 | 0;
+   HEAP32[i17 >> 2] = i20;
+   HEAP32[i17 + 4 >> 2] = i22;
+   d27 = +HEAPF32[(HEAP32[i15 >> 2] | 0) + (i16 * 12 | 0) + 8 >> 2];
+   HEAPF32[i30 + 56 >> 2] = d27;
+   i17 = (HEAP32[i14 >> 2] | 0) + (i16 * 12 | 0) | 0;
+   i18 = HEAP32[i17 + 4 >> 2] | 0;
+   i19 = i30 + 64 | 0;
+   HEAP32[i19 >> 2] = HEAP32[i17 >> 2];
+   HEAP32[i19 + 4 >> 2] = i18;
+   HEAPF32[i30 + 72 >> 2] = +HEAPF32[(HEAP32[i14 >> 2] | 0) + (i16 * 12 | 0) + 8 >> 2];
+   d25 = +Math_sin(+d27);
+   HEAPF32[i30 + 20 >> 2] = d25;
+   d27 = +Math_cos(+d27);
+   HEAPF32[i30 + 24 >> 2] = d27;
+   d26 = +HEAPF32[i30 + 28 >> 2];
+   d29 = +HEAPF32[i30 + 32 >> 2];
+   d28 = (HEAP32[tempDoublePtr >> 2] = i20, +HEAPF32[tempDoublePtr >> 2]) - (d27 * d26 - d25 * d29);
+   d29 = (HEAP32[tempDoublePtr >> 2] = i22, +HEAPF32[tempDoublePtr >> 2]) - (d25 * d26 + d27 * d29);
+   d28 = +d28;
+   d29 = +d29;
+   i30 = i30 + 12 | 0;
+   HEAPF32[i30 >> 2] = d28;
+   HEAPF32[i30 + 4 >> 2] = d29;
+   i16 = i16 + 1 | 0;
+  } while ((i16 | 0) < (HEAP32[i1 >> 2] | 0));
+ }
+ HEAPF32[i8 + 20 >> 2] = +__ZNK7b2Timer15GetMillisecondsEv(i9);
+ i9 = HEAP32[i2 + 40 >> 2] | 0;
+ i8 = i4 + 4 | 0;
+ if ((HEAP32[i8 >> 2] | 0) != 0 ? (HEAP32[i12 >> 2] | 0) > 0 : 0) {
+  i11 = i6 + 16 | 0;
+  i14 = 0;
+  do {
+   i15 = HEAP32[(HEAP32[i13 >> 2] | 0) + (i14 << 2) >> 2] | 0;
+   i16 = HEAP32[i9 + (i14 * 152 | 0) + 144 >> 2] | 0;
+   HEAP32[i11 >> 2] = i16;
+   if ((i16 | 0) > 0) {
+    i17 = 0;
+    do {
+     HEAPF32[i6 + (i17 << 2) >> 2] = +HEAPF32[i9 + (i14 * 152 | 0) + (i17 * 36 | 0) + 16 >> 2];
+     HEAPF32[i6 + (i17 << 2) + 8 >> 2] = +HEAPF32[i9 + (i14 * 152 | 0) + (i17 * 36 | 0) + 20 >> 2];
+     i17 = i17 + 1 | 0;
+    } while ((i17 | 0) != (i16 | 0));
+   }
+   i30 = HEAP32[i8 >> 2] | 0;
+   FUNCTION_TABLE_viii[HEAP32[(HEAP32[i30 >> 2] | 0) + 20 >> 2] & 3](i30, i15, i6);
+   i14 = i14 + 1 | 0;
+  } while ((i14 | 0) < (HEAP32[i12 >> 2] | 0));
+ }
+ if (!i7) {
+  __ZN15b2ContactSolverD2Ev(i2);
+  STACKTOP = i3;
+  return;
+ }
+ i7 = HEAP32[i1 >> 2] | 0;
+ i6 = (i7 | 0) > 0;
+ if (i6) {
+  i8 = HEAP32[i4 + 8 >> 2] | 0;
+  i9 = 0;
+  d21 = 3.4028234663852886e+38;
+  do {
+   i11 = HEAP32[i8 + (i9 << 2) >> 2] | 0;
+   do {
+    if ((HEAP32[i11 >> 2] | 0) != 0) {
+     if ((!((HEAP16[i11 + 4 >> 1] & 4) == 0) ? (d29 = +HEAPF32[i11 + 72 >> 2], !(d29 * d29 > .001218469929881394)) : 0) ? (d28 = +HEAPF32[i11 + 64 >> 2], d29 = +HEAPF32[i11 + 68 >> 2], !(d28 * d28 + d29 * d29 > 9999999747378752.0e-20)) : 0) {
+      i30 = i11 + 144 | 0;
+      d23 = d5 + +HEAPF32[i30 >> 2];
+      HEAPF32[i30 >> 2] = d23;
+      d21 = d21 < d23 ? d21 : d23;
+      break;
+     }
+     HEAPF32[i11 + 144 >> 2] = 0.0;
+     d21 = 0.0;
+    }
+   } while (0);
+   i9 = i9 + 1 | 0;
+  } while ((i9 | 0) < (i7 | 0));
+ } else {
+  d21 = 3.4028234663852886e+38;
+ }
+ if (!(d21 >= .5) | i10 | i6 ^ 1) {
+  __ZN15b2ContactSolverD2Ev(i2);
+  STACKTOP = i3;
+  return;
+ }
+ i4 = i4 + 8 | 0;
+ i6 = 0;
+ do {
+  i30 = HEAP32[(HEAP32[i4 >> 2] | 0) + (i6 << 2) >> 2] | 0;
+  i22 = i30 + 4 | 0;
+  HEAP16[i22 >> 1] = HEAP16[i22 >> 1] & 65533;
+  HEAPF32[i30 + 144 >> 2] = 0.0;
+  i30 = i30 + 64 | 0;
+  HEAP32[i30 + 0 >> 2] = 0;
+  HEAP32[i30 + 4 >> 2] = 0;
+  HEAP32[i30 + 8 >> 2] = 0;
+  HEAP32[i30 + 12 >> 2] = 0;
+  HEAP32[i30 + 16 >> 2] = 0;
+  HEAP32[i30 + 20 >> 2] = 0;
+  i6 = i6 + 1 | 0;
+ } while ((i6 | 0) < (HEAP32[i1 >> 2] | 0));
+ __ZN15b2ContactSolverD2Ev(i2);
+ STACKTOP = i3;
+ return;
+}
+function __ZN15b2ContactSolver24SolveVelocityConstraintsEv(i4) {
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, d9 = 0.0, d10 = 0.0, d11 = 0.0, d12 = 0.0, d13 = 0.0, d14 = 0.0, d15 = 0.0, d16 = 0.0, d17 = 0.0, d18 = 0.0, i19 = 0, d20 = 0.0, d21 = 0.0, i22 = 0, d23 = 0.0, d24 = 0.0, d25 = 0.0, d26 = 0.0, d27 = 0.0, d28 = 0.0, d29 = 0.0, d30 = 0.0, d31 = 0.0, i32 = 0, i33 = 0, d34 = 0.0, d35 = 0.0, d36 = 0.0, d37 = 0.0, d38 = 0.0, d39 = 0.0, d40 = 0.0, i41 = 0, i42 = 0, d43 = 0.0, d44 = 0.0;
+ i1 = STACKTOP;
+ i2 = i4 + 48 | 0;
+ if ((HEAP32[i2 >> 2] | 0) <= 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i3 = i4 + 40 | 0;
+ i4 = i4 + 28 | 0;
+ i42 = HEAP32[i4 >> 2] | 0;
+ i5 = 0;
+ L4 : while (1) {
+  i19 = HEAP32[i3 >> 2] | 0;
+  i22 = i19 + (i5 * 152 | 0) | 0;
+  i8 = HEAP32[i19 + (i5 * 152 | 0) + 112 >> 2] | 0;
+  i6 = HEAP32[i19 + (i5 * 152 | 0) + 116 >> 2] | 0;
+  d12 = +HEAPF32[i19 + (i5 * 152 | 0) + 120 >> 2];
+  d10 = +HEAPF32[i19 + (i5 * 152 | 0) + 128 >> 2];
+  d11 = +HEAPF32[i19 + (i5 * 152 | 0) + 124 >> 2];
+  d9 = +HEAPF32[i19 + (i5 * 152 | 0) + 132 >> 2];
+  i32 = i19 + (i5 * 152 | 0) + 144 | 0;
+  i33 = HEAP32[i32 >> 2] | 0;
+  i7 = i42 + (i8 * 12 | 0) | 0;
+  i41 = i7;
+  d21 = +HEAPF32[i41 >> 2];
+  d20 = +HEAPF32[i41 + 4 >> 2];
+  i41 = i42 + (i6 * 12 | 0) | 0;
+  d14 = +HEAPF32[i41 >> 2];
+  d13 = +HEAPF32[i41 + 4 >> 2];
+  i41 = i19 + (i5 * 152 | 0) + 72 | 0;
+  d17 = +HEAPF32[i41 >> 2];
+  d16 = +HEAPF32[i41 + 4 >> 2];
+  d23 = -d17;
+  d24 = +HEAPF32[i19 + (i5 * 152 | 0) + 136 >> 2];
+  if ((i33 + -1 | 0) >>> 0 < 2) {
+   i41 = 0;
+   d18 = +HEAPF32[i42 + (i8 * 12 | 0) + 8 >> 2];
+   d15 = +HEAPF32[i42 + (i6 * 12 | 0) + 8 >> 2];
+  } else {
+   i2 = 4;
+   break;
+  }
+  do {
+   d30 = +HEAPF32[i19 + (i5 * 152 | 0) + (i41 * 36 | 0) + 12 >> 2];
+   d25 = +HEAPF32[i19 + (i5 * 152 | 0) + (i41 * 36 | 0) + 8 >> 2];
+   d26 = +HEAPF32[i19 + (i5 * 152 | 0) + (i41 * 36 | 0) + 4 >> 2];
+   d27 = +HEAPF32[i19 + (i5 * 152 | 0) + (i41 * 36 | 0) >> 2];
+   d34 = d24 * +HEAPF32[i19 + (i5 * 152 | 0) + (i41 * 36 | 0) + 16 >> 2];
+   i42 = i19 + (i5 * 152 | 0) + (i41 * 36 | 0) + 20 | 0;
+   d28 = +HEAPF32[i42 >> 2];
+   d31 = d28 - +HEAPF32[i19 + (i5 * 152 | 0) + (i41 * 36 | 0) + 28 >> 2] * (d16 * (d14 - d15 * d30 - d21 + d18 * d26) + (d13 + d15 * d25 - d20 - d18 * d27) * d23);
+   d29 = -d34;
+   d31 = d31 < d34 ? d31 : d34;
+   d40 = d31 < d29 ? d29 : d31;
+   d39 = d40 - d28;
+   HEAPF32[i42 >> 2] = d40;
+   d40 = d16 * d39;
+   d39 = d39 * d23;
+   d21 = d21 - d12 * d40;
+   d20 = d20 - d12 * d39;
+   d18 = d18 - d10 * (d27 * d39 - d26 * d40);
+   d14 = d14 + d11 * d40;
+   d13 = d13 + d11 * d39;
+   d15 = d15 + d9 * (d25 * d39 - d30 * d40);
+   i41 = i41 + 1 | 0;
+  } while ((i41 | 0) != (i33 | 0));
+  do {
+   if ((HEAP32[i32 >> 2] | 0) != 1) {
+    i32 = i19 + (i5 * 152 | 0) + 16 | 0;
+    d31 = +HEAPF32[i32 >> 2];
+    i33 = i19 + (i5 * 152 | 0) + 52 | 0;
+    d34 = +HEAPF32[i33 >> 2];
+    if (!(d31 >= 0.0) | !(d34 >= 0.0)) {
+     i2 = 9;
+     break L4;
+    }
+    d23 = +HEAPF32[i19 + (i5 * 152 | 0) + 12 >> 2];
+    d24 = +HEAPF32[i19 + (i5 * 152 | 0) + 8 >> 2];
+    d26 = +HEAPF32[i19 + (i5 * 152 | 0) + 4 >> 2];
+    d30 = +HEAPF32[i22 >> 2];
+    d27 = +HEAPF32[i19 + (i5 * 152 | 0) + 48 >> 2];
+    d25 = +HEAPF32[i19 + (i5 * 152 | 0) + 44 >> 2];
+    d28 = +HEAPF32[i19 + (i5 * 152 | 0) + 40 >> 2];
+    d29 = +HEAPF32[i19 + (i5 * 152 | 0) + 36 >> 2];
+    d37 = +HEAPF32[i19 + (i5 * 152 | 0) + 104 >> 2];
+    d38 = +HEAPF32[i19 + (i5 * 152 | 0) + 100 >> 2];
+    d35 = d17 * (d14 - d15 * d23 - d21 + d18 * d26) + d16 * (d13 + d15 * d24 - d20 - d18 * d30) - +HEAPF32[i19 + (i5 * 152 | 0) + 32 >> 2] - (d31 * +HEAPF32[i19 + (i5 * 152 | 0) + 96 >> 2] + d34 * d37);
+    d36 = d17 * (d14 - d15 * d27 - d21 + d18 * d28) + d16 * (d13 + d15 * d25 - d20 - d18 * d29) - +HEAPF32[i19 + (i5 * 152 | 0) + 68 >> 2] - (d31 * d38 + d34 * +HEAPF32[i19 + (i5 * 152 | 0) + 108 >> 2]);
+    d44 = +HEAPF32[i19 + (i5 * 152 | 0) + 80 >> 2] * d35 + +HEAPF32[i19 + (i5 * 152 | 0) + 88 >> 2] * d36;
+    d43 = d35 * +HEAPF32[i19 + (i5 * 152 | 0) + 84 >> 2] + d36 * +HEAPF32[i19 + (i5 * 152 | 0) + 92 >> 2];
+    d40 = -d44;
+    d39 = -d43;
+    if (!(!(d44 <= -0.0) | !(d43 <= -0.0))) {
+     d37 = d40 - d31;
+     d43 = d39 - d34;
+     d38 = d17 * d37;
+     d37 = d16 * d37;
+     d44 = d17 * d43;
+     d43 = d16 * d43;
+     d35 = d38 + d44;
+     d36 = d37 + d43;
+     HEAPF32[i32 >> 2] = d40;
+     HEAPF32[i33 >> 2] = d39;
+     d21 = d21 - d12 * d35;
+     d20 = d20 - d12 * d36;
+     d14 = d14 + d11 * d35;
+     d13 = d13 + d11 * d36;
+     d18 = d18 - d10 * (d30 * d37 - d26 * d38 + (d29 * d43 - d28 * d44));
+     d15 = d15 + d9 * (d24 * d37 - d23 * d38 + (d25 * d43 - d27 * d44));
+     break;
+    }
+    d44 = d35 * +HEAPF32[i19 + (i5 * 152 | 0) + 24 >> 2];
+    d39 = -d44;
+    if (d44 <= -0.0 ? d36 + d38 * d39 >= 0.0 : 0) {
+     d38 = d39 - d31;
+     d43 = 0.0 - d34;
+     d40 = d17 * d38;
+     d38 = d16 * d38;
+     d44 = d17 * d43;
+     d43 = d16 * d43;
+     d36 = d44 + d40;
+     d37 = d43 + d38;
+     HEAPF32[i32 >> 2] = d39;
+     HEAPF32[i33 >> 2] = 0.0;
+     d21 = d21 - d12 * d36;
+     d20 = d20 - d12 * d37;
+     d14 = d14 + d11 * d36;
+     d13 = d13 + d11 * d37;
+     d18 = d18 - d10 * (d38 * d30 - d40 * d26 + (d43 * d29 - d44 * d28));
+     d15 = d15 + d9 * (d38 * d24 - d40 * d23 + (d43 * d25 - d44 * d27));
+     break;
+    }
+    d44 = d36 * +HEAPF32[i19 + (i5 * 152 | 0) + 60 >> 2];
+    d38 = -d44;
+    if (d44 <= -0.0 ? d35 + d37 * d38 >= 0.0 : 0) {
+     d39 = 0.0 - d31;
+     d43 = d38 - d34;
+     d40 = d17 * d39;
+     d39 = d16 * d39;
+     d44 = d17 * d43;
+     d43 = d16 * d43;
+     d36 = d40 + d44;
+     d37 = d39 + d43;
+     HEAPF32[i32 >> 2] = 0.0;
+     HEAPF32[i33 >> 2] = d38;
+     d21 = d21 - d12 * d36;
+     d20 = d20 - d12 * d37;
+     d14 = d14 + d11 * d36;
+     d13 = d13 + d11 * d37;
+     d18 = d18 - d10 * (d39 * d30 - d40 * d26 + (d43 * d29 - d44 * d28));
+     d15 = d15 + d9 * (d39 * d24 - d40 * d23 + (d43 * d25 - d44 * d27));
+     break;
+    }
+    if (!(!(d35 >= 0.0) | !(d36 >= 0.0))) {
+     d39 = 0.0 - d31;
+     d43 = 0.0 - d34;
+     d40 = d17 * d39;
+     d39 = d16 * d39;
+     d44 = d17 * d43;
+     d43 = d16 * d43;
+     d37 = d40 + d44;
+     d38 = d39 + d43;
+     HEAPF32[i32 >> 2] = 0.0;
+     HEAPF32[i33 >> 2] = 0.0;
+     d21 = d21 - d12 * d37;
+     d20 = d20 - d12 * d38;
+     d14 = d14 + d11 * d37;
+     d13 = d13 + d11 * d38;
+     d18 = d18 - d10 * (d39 * d30 - d40 * d26 + (d43 * d29 - d44 * d28));
+     d15 = d15 + d9 * (d39 * d24 - d40 * d23 + (d43 * d25 - d44 * d27));
+    }
+   } else {
+    d23 = +HEAPF32[i19 + (i5 * 152 | 0) + 12 >> 2];
+    d24 = +HEAPF32[i19 + (i5 * 152 | 0) + 8 >> 2];
+    d25 = +HEAPF32[i19 + (i5 * 152 | 0) + 4 >> 2];
+    d26 = +HEAPF32[i22 >> 2];
+    i22 = i19 + (i5 * 152 | 0) + 16 | 0;
+    d27 = +HEAPF32[i22 >> 2];
+    d28 = d27 - +HEAPF32[i19 + (i5 * 152 | 0) + 24 >> 2] * (d17 * (d14 - d15 * d23 - d21 + d18 * d25) + d16 * (d13 + d15 * d24 - d20 - d18 * d26) - +HEAPF32[i19 + (i5 * 152 | 0) + 32 >> 2]);
+    d44 = d28 > 0.0 ? d28 : 0.0;
+    d43 = d44 - d27;
+    HEAPF32[i22 >> 2] = d44;
+    d44 = d17 * d43;
+    d43 = d16 * d43;
+    d21 = d21 - d12 * d44;
+    d20 = d20 - d12 * d43;
+    d14 = d14 + d11 * d44;
+    d13 = d13 + d11 * d43;
+    d18 = d18 - d10 * (d26 * d43 - d25 * d44);
+    d15 = d15 + d9 * (d24 * d43 - d23 * d44);
+   }
+  } while (0);
+  d44 = +d21;
+  d43 = +d20;
+  i42 = i7;
+  HEAPF32[i42 >> 2] = d44;
+  HEAPF32[i42 + 4 >> 2] = d43;
+  i42 = HEAP32[i4 >> 2] | 0;
+  HEAPF32[i42 + (i8 * 12 | 0) + 8 >> 2] = d18;
+  d43 = +d14;
+  d44 = +d13;
+  i42 = i42 + (i6 * 12 | 0) | 0;
+  HEAPF32[i42 >> 2] = d43;
+  HEAPF32[i42 + 4 >> 2] = d44;
+  i42 = HEAP32[i4 >> 2] | 0;
+  HEAPF32[i42 + (i6 * 12 | 0) + 8 >> 2] = d15;
+  i5 = i5 + 1 | 0;
+  if ((i5 | 0) >= (HEAP32[i2 >> 2] | 0)) {
+   i2 = 21;
+   break;
+  }
+ }
+ if ((i2 | 0) == 4) {
+  ___assert_fail(6648, 6520, 311, 6688);
+ } else if ((i2 | 0) == 9) {
+  ___assert_fail(6720, 6520, 406, 6688);
+ } else if ((i2 | 0) == 21) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function __Z14b2TimeOfImpactP11b2TOIOutputPK10b2TOIInput(i3, i11) {
+ i3 = i3 | 0;
+ i11 = i11 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i12 = 0, i13 = 0, d14 = 0.0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, d28 = 0.0, i29 = 0, d30 = 0.0, d31 = 0.0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0, i38 = 0, i39 = 0, d40 = 0.0, i41 = 0, d42 = 0.0, d43 = 0.0, i44 = 0, i45 = 0, d46 = 0.0, i47 = 0, d48 = 0.0, d49 = 0.0, d50 = 0.0, d51 = 0.0, i52 = 0, d53 = 0.0, d54 = 0.0, d55 = 0.0, d56 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 320 | 0;
+ i12 = i1 + 276 | 0;
+ i10 = i1 + 240 | 0;
+ i13 = i1 + 228 | 0;
+ i5 = i1 + 136 | 0;
+ i7 = i1 + 112 | 0;
+ i8 = i1 + 8 | 0;
+ i9 = i1 + 4 | 0;
+ i4 = i1;
+ HEAP32[874] = (HEAP32[874] | 0) + 1;
+ HEAP32[i3 >> 2] = 0;
+ i19 = i11 + 128 | 0;
+ i2 = i3 + 4 | 0;
+ HEAPF32[i2 >> 2] = +HEAPF32[i19 >> 2];
+ i6 = i11 + 28 | 0;
+ i16 = i12 + 0 | 0;
+ i15 = i11 + 56 | 0;
+ i17 = i16 + 36 | 0;
+ do {
+  HEAP32[i16 >> 2] = HEAP32[i15 >> 2];
+  i16 = i16 + 4 | 0;
+  i15 = i15 + 4 | 0;
+ } while ((i16 | 0) < (i17 | 0));
+ i16 = i10 + 0 | 0;
+ i15 = i11 + 92 | 0;
+ i17 = i16 + 36 | 0;
+ do {
+  HEAP32[i16 >> 2] = HEAP32[i15 >> 2];
+  i16 = i16 + 4 | 0;
+  i15 = i15 + 4 | 0;
+ } while ((i16 | 0) < (i17 | 0));
+ i15 = i12 + 24 | 0;
+ d42 = +HEAPF32[i15 >> 2];
+ d43 = +Math_floor(+(d42 / 6.2831854820251465)) * 6.2831854820251465;
+ d42 = d42 - d43;
+ HEAPF32[i15 >> 2] = d42;
+ i16 = i12 + 28 | 0;
+ d43 = +HEAPF32[i16 >> 2] - d43;
+ HEAPF32[i16 >> 2] = d43;
+ i17 = i10 + 24 | 0;
+ d46 = +HEAPF32[i17 >> 2];
+ d40 = +Math_floor(+(d46 / 6.2831854820251465)) * 6.2831854820251465;
+ d46 = d46 - d40;
+ HEAPF32[i17 >> 2] = d46;
+ i18 = i10 + 28 | 0;
+ d40 = +HEAPF32[i18 >> 2] - d40;
+ HEAPF32[i18 >> 2] = d40;
+ d14 = +HEAPF32[i19 >> 2];
+ d28 = +HEAPF32[i11 + 24 >> 2] + +HEAPF32[i11 + 52 >> 2] + -.014999999664723873;
+ d28 = d28 < .004999999888241291 ? .004999999888241291 : d28;
+ if (!(d28 > .0012499999720603228)) {
+  ___assert_fail(3536, 3560, 280, 3600);
+ }
+ HEAP16[i13 + 4 >> 1] = 0;
+ HEAP32[i5 + 0 >> 2] = HEAP32[i11 + 0 >> 2];
+ HEAP32[i5 + 4 >> 2] = HEAP32[i11 + 4 >> 2];
+ HEAP32[i5 + 8 >> 2] = HEAP32[i11 + 8 >> 2];
+ HEAP32[i5 + 12 >> 2] = HEAP32[i11 + 12 >> 2];
+ HEAP32[i5 + 16 >> 2] = HEAP32[i11 + 16 >> 2];
+ HEAP32[i5 + 20 >> 2] = HEAP32[i11 + 20 >> 2];
+ HEAP32[i5 + 24 >> 2] = HEAP32[i11 + 24 >> 2];
+ i38 = i5 + 28 | 0;
+ HEAP32[i38 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+ HEAP32[i38 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+ HEAP32[i38 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+ HEAP32[i38 + 12 >> 2] = HEAP32[i6 + 12 >> 2];
+ HEAP32[i38 + 16 >> 2] = HEAP32[i6 + 16 >> 2];
+ HEAP32[i38 + 20 >> 2] = HEAP32[i6 + 20 >> 2];
+ HEAP32[i38 + 24 >> 2] = HEAP32[i6 + 24 >> 2];
+ HEAP8[i5 + 88 | 0] = 0;
+ i38 = i12 + 8 | 0;
+ i27 = i12 + 12 | 0;
+ i29 = i12 + 16 | 0;
+ i22 = i12 + 20 | 0;
+ i32 = i12 + 4 | 0;
+ i34 = i10 + 8 | 0;
+ i36 = i10 + 12 | 0;
+ i35 = i10 + 16 | 0;
+ i37 = i10 + 20 | 0;
+ i33 = i10 + 4 | 0;
+ i26 = i5 + 56 | 0;
+ i25 = i5 + 64 | 0;
+ i24 = i5 + 68 | 0;
+ i23 = i5 + 72 | 0;
+ i20 = i5 + 80 | 0;
+ i19 = i5 + 84 | 0;
+ i21 = i7 + 16 | 0;
+ d30 = d28 + .0012499999720603228;
+ d31 = d28 + -.0012499999720603228;
+ d48 = d40;
+ i39 = 0;
+ d40 = 0.0;
+ L4 : while (1) {
+  d56 = 1.0 - d40;
+  d49 = d56 * d42 + d40 * d43;
+  d43 = +Math_sin(+d49);
+  d49 = +Math_cos(+d49);
+  d55 = +HEAPF32[i12 >> 2];
+  d54 = +HEAPF32[i32 >> 2];
+  d42 = d56 * d46 + d40 * d48;
+  d53 = +Math_sin(+d42);
+  d42 = +Math_cos(+d42);
+  d46 = +HEAPF32[i10 >> 2];
+  d51 = +HEAPF32[i33 >> 2];
+  d50 = d56 * +HEAPF32[i34 >> 2] + d40 * +HEAPF32[i35 >> 2] - (d42 * d46 - d53 * d51);
+  d51 = d56 * +HEAPF32[i36 >> 2] + d40 * +HEAPF32[i37 >> 2] - (d53 * d46 + d42 * d51);
+  d46 = +(d56 * +HEAPF32[i38 >> 2] + d40 * +HEAPF32[i29 >> 2] - (d49 * d55 - d43 * d54));
+  d48 = +(d56 * +HEAPF32[i27 >> 2] + d40 * +HEAPF32[i22 >> 2] - (d43 * d55 + d49 * d54));
+  i52 = i26;
+  HEAPF32[i52 >> 2] = d46;
+  HEAPF32[i52 + 4 >> 2] = d48;
+  HEAPF32[i25 >> 2] = d43;
+  HEAPF32[i24 >> 2] = d49;
+  d50 = +d50;
+  d51 = +d51;
+  i52 = i23;
+  HEAPF32[i52 >> 2] = d50;
+  HEAPF32[i52 + 4 >> 2] = d51;
+  HEAPF32[i20 >> 2] = d53;
+  HEAPF32[i19 >> 2] = d42;
+  __Z10b2DistanceP16b2DistanceOutputP14b2SimplexCachePK15b2DistanceInput(i7, i13, i5);
+  d42 = +HEAPF32[i21 >> 2];
+  if (d42 <= 0.0) {
+   i4 = 5;
+   break;
+  }
+  if (d42 < d30) {
+   i4 = 7;
+   break;
+  }
+  +__ZN20b2SeparationFunction10InitializeEPK14b2SimplexCachePK15b2DistanceProxyRK7b2SweepS5_S8_f(i8, i13, i11, i12, i6, i10, d40);
+  i41 = 0;
+  d42 = d14;
+  do {
+   d50 = +__ZNK20b2SeparationFunction17FindMinSeparationEPiS0_f(i8, i9, i4, d42);
+   if (d50 > d30) {
+    i4 = 10;
+    break L4;
+   }
+   if (d50 > d31) {
+    d40 = d42;
+    break;
+   }
+   i45 = HEAP32[i9 >> 2] | 0;
+   i44 = HEAP32[i4 >> 2] | 0;
+   d48 = +__ZNK20b2SeparationFunction8EvaluateEiif(i8, i45, i44, d40);
+   if (d48 < d31) {
+    i4 = 13;
+    break L4;
+   }
+   if (!(d48 <= d30)) {
+    d43 = d40;
+    d46 = d42;
+    i47 = 0;
+   } else {
+    i4 = 15;
+    break L4;
+   }
+   while (1) {
+    if ((i47 & 1 | 0) == 0) {
+     d49 = (d43 + d46) * .5;
+    } else {
+     d49 = d43 + (d28 - d48) * (d46 - d43) / (d50 - d48);
+    }
+    d51 = +__ZNK20b2SeparationFunction8EvaluateEiif(i8, i45, i44, d49);
+    d53 = d51 - d28;
+    if (!(d53 > 0.0)) {
+     d53 = -d53;
+    }
+    if (d53 < .0012499999720603228) {
+     d42 = d49;
+     break;
+    }
+    i52 = d51 > d28;
+    i47 = i47 + 1 | 0;
+    HEAP32[880] = (HEAP32[880] | 0) + 1;
+    if ((i47 | 0) == 50) {
+     i47 = 50;
+     break;
+    } else {
+     d43 = i52 ? d49 : d43;
+     d46 = i52 ? d46 : d49;
+     d48 = i52 ? d51 : d48;
+     d50 = i52 ? d50 : d51;
+    }
+   }
+   i44 = HEAP32[882] | 0;
+   HEAP32[882] = (i44 | 0) > (i47 | 0) ? i44 : i47;
+   i41 = i41 + 1 | 0;
+  } while ((i41 | 0) != 8);
+  i39 = i39 + 1 | 0;
+  HEAP32[876] = (HEAP32[876] | 0) + 1;
+  if ((i39 | 0) == 20) {
+   i4 = 27;
+   break;
+  }
+  d42 = +HEAPF32[i15 >> 2];
+  d43 = +HEAPF32[i16 >> 2];
+  d46 = +HEAPF32[i17 >> 2];
+  d48 = +HEAPF32[i18 >> 2];
+ }
+ if ((i4 | 0) == 5) {
+  HEAP32[i3 >> 2] = 2;
+  HEAPF32[i2 >> 2] = 0.0;
+  i2 = HEAP32[878] | 0;
+  i52 = (i2 | 0) > (i39 | 0);
+  i52 = i52 ? i2 : i39;
+  HEAP32[878] = i52;
+  STACKTOP = i1;
+  return;
+ } else if ((i4 | 0) == 7) {
+  HEAP32[i3 >> 2] = 3;
+  HEAPF32[i2 >> 2] = d40;
+  i2 = HEAP32[878] | 0;
+  i52 = (i2 | 0) > (i39 | 0);
+  i52 = i52 ? i2 : i39;
+  HEAP32[878] = i52;
+  STACKTOP = i1;
+  return;
+ } else if ((i4 | 0) == 10) {
+  HEAP32[i3 >> 2] = 4;
+  HEAPF32[i2 >> 2] = d14;
+ } else if ((i4 | 0) == 13) {
+  HEAP32[i3 >> 2] = 1;
+  HEAPF32[i2 >> 2] = d40;
+ } else if ((i4 | 0) == 15) {
+  HEAP32[i3 >> 2] = 3;
+  HEAPF32[i2 >> 2] = d40;
+ } else if ((i4 | 0) == 27) {
+  HEAP32[i3 >> 2] = 1;
+  HEAPF32[i2 >> 2] = d40;
+  i39 = 20;
+  i2 = HEAP32[878] | 0;
+  i52 = (i2 | 0) > (i39 | 0);
+  i52 = i52 ? i2 : i39;
+  HEAP32[878] = i52;
+  STACKTOP = i1;
+  return;
+ }
+ HEAP32[876] = (HEAP32[876] | 0) + 1;
+ i39 = i39 + 1 | 0;
+ i2 = HEAP32[878] | 0;
+ i52 = (i2 | 0) > (i39 | 0);
+ i52 = i52 ? i2 : i39;
+ HEAP32[878] = i52;
+ STACKTOP = i1;
+ return;
+}
+function __ZN7b2World5SolveERK10b2TimeStep(i5, i15) {
+ i5 = i5 | 0;
+ i15 = i15 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0, i38 = 0, d39 = 0.0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 96 | 0;
+ i4 = i3 + 32 | 0;
+ i9 = i3;
+ i2 = i3 + 84 | 0;
+ i11 = i5 + 103008 | 0;
+ HEAPF32[i11 >> 2] = 0.0;
+ i14 = i5 + 103012 | 0;
+ HEAPF32[i14 >> 2] = 0.0;
+ i8 = i5 + 103016 | 0;
+ HEAPF32[i8 >> 2] = 0.0;
+ i16 = i5 + 102960 | 0;
+ i1 = i5 + 102872 | 0;
+ i6 = i5 + 68 | 0;
+ __ZN8b2IslandC2EiiiP16b2StackAllocatorP17b2ContactListener(i4, HEAP32[i16 >> 2] | 0, HEAP32[i5 + 102936 >> 2] | 0, HEAP32[i5 + 102964 >> 2] | 0, i6, HEAP32[i5 + 102944 >> 2] | 0);
+ i7 = i5 + 102952 | 0;
+ i17 = HEAP32[i7 >> 2] | 0;
+ if ((i17 | 0) != 0) {
+  do {
+   i38 = i17 + 4 | 0;
+   HEAP16[i38 >> 1] = HEAP16[i38 >> 1] & 65534;
+   i17 = HEAP32[i17 + 96 >> 2] | 0;
+  } while ((i17 | 0) != 0);
+ }
+ i17 = HEAP32[i5 + 102932 >> 2] | 0;
+ if ((i17 | 0) != 0) {
+  do {
+   i38 = i17 + 4 | 0;
+   HEAP32[i38 >> 2] = HEAP32[i38 >> 2] & -2;
+   i17 = HEAP32[i17 + 12 >> 2] | 0;
+  } while ((i17 | 0) != 0);
+ }
+ i17 = HEAP32[i5 + 102956 >> 2] | 0;
+ if ((i17 | 0) != 0) {
+  do {
+   HEAP8[i17 + 60 | 0] = 0;
+   i17 = HEAP32[i17 + 12 >> 2] | 0;
+  } while ((i17 | 0) != 0);
+ }
+ i24 = HEAP32[i16 >> 2] | 0;
+ i16 = __ZN16b2StackAllocator8AllocateEi(i6, i24 << 2) | 0;
+ i32 = HEAP32[i7 >> 2] | 0;
+ L13 : do {
+  if ((i32 | 0) != 0) {
+   i18 = i4 + 28 | 0;
+   i30 = i4 + 36 | 0;
+   i27 = i4 + 32 | 0;
+   i17 = i4 + 40 | 0;
+   i23 = i4 + 8 | 0;
+   i29 = i4 + 48 | 0;
+   i28 = i4 + 16 | 0;
+   i26 = i4 + 44 | 0;
+   i31 = i4 + 12 | 0;
+   i25 = i5 + 102968 | 0;
+   i22 = i5 + 102976 | 0;
+   i21 = i9 + 12 | 0;
+   i20 = i9 + 16 | 0;
+   i19 = i9 + 20 | 0;
+   L15 : while (1) {
+    i33 = i32 + 4 | 0;
+    i34 = HEAP16[i33 >> 1] | 0;
+    if ((i34 & 35) == 34 ? (HEAP32[i32 >> 2] | 0) != 0 : 0) {
+     HEAP32[i18 >> 2] = 0;
+     HEAP32[i30 >> 2] = 0;
+     HEAP32[i27 >> 2] = 0;
+     HEAP32[i16 >> 2] = i32;
+     HEAP16[i33 >> 1] = i34 & 65535 | 1;
+     i35 = 1;
+     do {
+      i35 = i35 + -1 | 0;
+      i33 = HEAP32[i16 + (i35 << 2) >> 2] | 0;
+      i34 = i33 + 4 | 0;
+      i36 = HEAP16[i34 >> 1] | 0;
+      if ((i36 & 32) == 0) {
+       i8 = 13;
+       break L15;
+      }
+      i37 = HEAP32[i18 >> 2] | 0;
+      if ((i37 | 0) >= (HEAP32[i17 >> 2] | 0)) {
+       i8 = 15;
+       break L15;
+      }
+      HEAP32[i33 + 8 >> 2] = i37;
+      i38 = HEAP32[i18 >> 2] | 0;
+      HEAP32[(HEAP32[i23 >> 2] | 0) + (i38 << 2) >> 2] = i33;
+      HEAP32[i18 >> 2] = i38 + 1;
+      i36 = i36 & 65535;
+      if ((i36 & 2 | 0) == 0) {
+       HEAP16[i34 >> 1] = i36 | 2;
+       HEAPF32[i33 + 144 >> 2] = 0.0;
+      }
+      if ((HEAP32[i33 >> 2] | 0) != 0) {
+       i34 = HEAP32[i33 + 112 >> 2] | 0;
+       if ((i34 | 0) != 0) {
+        do {
+         i38 = HEAP32[i34 + 4 >> 2] | 0;
+         i36 = i38 + 4 | 0;
+         if (((HEAP32[i36 >> 2] & 7 | 0) == 6 ? (HEAP8[(HEAP32[i38 + 48 >> 2] | 0) + 38 | 0] | 0) == 0 : 0) ? (HEAP8[(HEAP32[i38 + 52 >> 2] | 0) + 38 | 0] | 0) == 0 : 0) {
+          i37 = HEAP32[i30 >> 2] | 0;
+          if ((i37 | 0) >= (HEAP32[i26 >> 2] | 0)) {
+           i8 = 25;
+           break L15;
+          }
+          HEAP32[i30 >> 2] = i37 + 1;
+          HEAP32[(HEAP32[i31 >> 2] | 0) + (i37 << 2) >> 2] = i38;
+          HEAP32[i36 >> 2] = HEAP32[i36 >> 2] | 1;
+          i38 = HEAP32[i34 >> 2] | 0;
+          i36 = i38 + 4 | 0;
+          i37 = HEAP16[i36 >> 1] | 0;
+          if ((i37 & 1) == 0) {
+           if ((i35 | 0) >= (i24 | 0)) {
+            i8 = 28;
+            break L15;
+           }
+           HEAP32[i16 + (i35 << 2) >> 2] = i38;
+           HEAP16[i36 >> 1] = i37 & 65535 | 1;
+           i35 = i35 + 1 | 0;
+          }
+         }
+         i34 = HEAP32[i34 + 12 >> 2] | 0;
+        } while ((i34 | 0) != 0);
+       }
+       i33 = HEAP32[i33 + 108 >> 2] | 0;
+       if ((i33 | 0) != 0) {
+        do {
+         i37 = i33 + 4 | 0;
+         i36 = HEAP32[i37 >> 2] | 0;
+         if ((HEAP8[i36 + 60 | 0] | 0) == 0 ? (i10 = HEAP32[i33 >> 2] | 0, i13 = i10 + 4 | 0, i12 = HEAP16[i13 >> 1] | 0, !((i12 & 32) == 0)) : 0) {
+          i34 = HEAP32[i27 >> 2] | 0;
+          if ((i34 | 0) >= (HEAP32[i29 >> 2] | 0)) {
+           i8 = 35;
+           break L15;
+          }
+          HEAP32[i27 >> 2] = i34 + 1;
+          HEAP32[(HEAP32[i28 >> 2] | 0) + (i34 << 2) >> 2] = i36;
+          HEAP8[(HEAP32[i37 >> 2] | 0) + 60 | 0] = 1;
+          if ((i12 & 1) == 0) {
+           if ((i35 | 0) >= (i24 | 0)) {
+            i8 = 38;
+            break L15;
+           }
+           HEAP32[i16 + (i35 << 2) >> 2] = i10;
+           HEAP16[i13 >> 1] = i12 & 65535 | 1;
+           i35 = i35 + 1 | 0;
+          }
+         }
+         i33 = HEAP32[i33 + 12 >> 2] | 0;
+        } while ((i33 | 0) != 0);
+       }
+      }
+     } while ((i35 | 0) > 0);
+     __ZN8b2Island5SolveEP9b2ProfileRK10b2TimeStepRK6b2Vec2b(i4, i9, i15, i25, (HEAP8[i22] | 0) != 0);
+     HEAPF32[i11 >> 2] = +HEAPF32[i21 >> 2] + +HEAPF32[i11 >> 2];
+     HEAPF32[i14 >> 2] = +HEAPF32[i20 >> 2] + +HEAPF32[i14 >> 2];
+     HEAPF32[i8 >> 2] = +HEAPF32[i19 >> 2] + +HEAPF32[i8 >> 2];
+     i35 = HEAP32[i18 >> 2] | 0;
+     if ((i35 | 0) > 0) {
+      i33 = HEAP32[i23 >> 2] | 0;
+      i36 = 0;
+      do {
+       i34 = HEAP32[i33 + (i36 << 2) >> 2] | 0;
+       if ((HEAP32[i34 >> 2] | 0) == 0) {
+        i38 = i34 + 4 | 0;
+        HEAP16[i38 >> 1] = HEAP16[i38 >> 1] & 65534;
+       }
+       i36 = i36 + 1 | 0;
+      } while ((i36 | 0) < (i35 | 0));
+     }
+    }
+    i32 = HEAP32[i32 + 96 >> 2] | 0;
+    if ((i32 | 0) == 0) {
+     break L13;
+    }
+   }
+   if ((i8 | 0) == 13) {
+    ___assert_fail(2232, 2184, 445, 2256);
+   } else if ((i8 | 0) == 15) {
+    ___assert_fail(2520, 2440, 54, 2472);
+   } else if ((i8 | 0) == 25) {
+    ___assert_fail(2480, 2440, 62, 2472);
+   } else if ((i8 | 0) == 28) {
+    ___assert_fail(2264, 2184, 495, 2256);
+   } else if ((i8 | 0) == 35) {
+    ___assert_fail(2408, 2440, 68, 2472);
+   } else if ((i8 | 0) == 38) {
+    ___assert_fail(2264, 2184, 524, 2256);
+   }
+  }
+ } while (0);
+ __ZN16b2StackAllocator4FreeEPv(i6, i16);
+ __ZN7b2TimerC2Ev(i2);
+ i6 = HEAP32[i7 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  __ZN16b2ContactManager15FindNewContactsEv(i1);
+  d39 = +__ZNK7b2Timer15GetMillisecondsEv(i2);
+  i38 = i5 + 103020 | 0;
+  HEAPF32[i38 >> 2] = d39;
+  __ZN8b2IslandD2Ev(i4);
+  STACKTOP = i3;
+  return;
+ }
+ do {
+  if (!((HEAP16[i6 + 4 >> 1] & 1) == 0) ? (HEAP32[i6 >> 2] | 0) != 0 : 0) {
+   __ZN6b2Body19SynchronizeFixturesEv(i6);
+  }
+  i6 = HEAP32[i6 + 96 >> 2] | 0;
+ } while ((i6 | 0) != 0);
+ __ZN16b2ContactManager15FindNewContactsEv(i1);
+ d39 = +__ZNK7b2Timer15GetMillisecondsEv(i2);
+ i38 = i5 + 103020 | 0;
+ HEAPF32[i38 >> 2] = d39;
+ __ZN8b2IslandD2Ev(i4);
+ STACKTOP = i3;
+ return;
+}
+function __ZN15b2ContactSolver29InitializeVelocityConstraintsEv(i10) {
+ i10 = i10 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, d21 = 0.0, d22 = 0.0, d23 = 0.0, d24 = 0.0, d25 = 0.0, d26 = 0.0, d27 = 0.0, d28 = 0.0, d29 = 0.0, d30 = 0.0, i31 = 0, d32 = 0.0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0, d38 = 0.0, d39 = 0.0, d40 = 0.0, d41 = 0.0, i42 = 0, d43 = 0.0, d44 = 0.0, d45 = 0.0, d46 = 0.0, d47 = 0.0, d48 = 0.0, i49 = 0, i50 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i8 = i1 + 40 | 0;
+ i3 = i1 + 24 | 0;
+ i5 = i1;
+ i4 = i10 + 48 | 0;
+ if ((HEAP32[i4 >> 2] | 0) <= 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i9 = i10 + 40 | 0;
+ i2 = i10 + 36 | 0;
+ i7 = i10 + 44 | 0;
+ i6 = i10 + 24 | 0;
+ i13 = i10 + 28 | 0;
+ i14 = i8 + 8 | 0;
+ i12 = i8 + 12 | 0;
+ i11 = i3 + 8 | 0;
+ i10 = i3 + 12 | 0;
+ i16 = 0;
+ while (1) {
+  i15 = HEAP32[i9 >> 2] | 0;
+  i33 = HEAP32[i2 >> 2] | 0;
+  i31 = HEAP32[(HEAP32[i7 >> 2] | 0) + (HEAP32[i15 + (i16 * 152 | 0) + 148 >> 2] << 2) >> 2] | 0;
+  i35 = HEAP32[i15 + (i16 * 152 | 0) + 112 >> 2] | 0;
+  i42 = HEAP32[i15 + (i16 * 152 | 0) + 116 >> 2] | 0;
+  d30 = +HEAPF32[i15 + (i16 * 152 | 0) + 120 >> 2];
+  d24 = +HEAPF32[i15 + (i16 * 152 | 0) + 124 >> 2];
+  d17 = +HEAPF32[i15 + (i16 * 152 | 0) + 128 >> 2];
+  d18 = +HEAPF32[i15 + (i16 * 152 | 0) + 132 >> 2];
+  i36 = i33 + (i16 * 88 | 0) + 48 | 0;
+  d39 = +HEAPF32[i36 >> 2];
+  d40 = +HEAPF32[i36 + 4 >> 2];
+  i36 = i33 + (i16 * 88 | 0) + 56 | 0;
+  d41 = +HEAPF32[i36 >> 2];
+  d43 = +HEAPF32[i36 + 4 >> 2];
+  i36 = HEAP32[i6 >> 2] | 0;
+  i37 = i36 + (i35 * 12 | 0) | 0;
+  d26 = +HEAPF32[i37 >> 2];
+  d27 = +HEAPF32[i37 + 4 >> 2];
+  d32 = +HEAPF32[i36 + (i35 * 12 | 0) + 8 >> 2];
+  i37 = HEAP32[i13 >> 2] | 0;
+  i34 = i37 + (i35 * 12 | 0) | 0;
+  d22 = +HEAPF32[i34 >> 2];
+  d25 = +HEAPF32[i34 + 4 >> 2];
+  d23 = +HEAPF32[i37 + (i35 * 12 | 0) + 8 >> 2];
+  i35 = i36 + (i42 * 12 | 0) | 0;
+  d28 = +HEAPF32[i35 >> 2];
+  d29 = +HEAPF32[i35 + 4 >> 2];
+  d38 = +HEAPF32[i36 + (i42 * 12 | 0) + 8 >> 2];
+  i36 = i37 + (i42 * 12 | 0) | 0;
+  d20 = +HEAPF32[i36 >> 2];
+  d19 = +HEAPF32[i36 + 4 >> 2];
+  d21 = +HEAPF32[i37 + (i42 * 12 | 0) + 8 >> 2];
+  if ((HEAP32[i31 + 124 >> 2] | 0) <= 0) {
+   i2 = 4;
+   break;
+  }
+  d44 = +HEAPF32[i33 + (i16 * 88 | 0) + 80 >> 2];
+  d45 = +HEAPF32[i33 + (i16 * 88 | 0) + 76 >> 2];
+  d47 = +Math_sin(+d32);
+  HEAPF32[i14 >> 2] = d47;
+  d48 = +Math_cos(+d32);
+  HEAPF32[i12 >> 2] = d48;
+  d32 = +Math_sin(+d38);
+  HEAPF32[i11 >> 2] = d32;
+  d38 = +Math_cos(+d38);
+  HEAPF32[i10 >> 2] = d38;
+  d46 = +(d26 - (d39 * d48 - d40 * d47));
+  d40 = +(d27 - (d40 * d48 + d39 * d47));
+  i37 = i8;
+  HEAPF32[i37 >> 2] = d46;
+  HEAPF32[i37 + 4 >> 2] = d40;
+  d40 = +(d28 - (d41 * d38 - d43 * d32));
+  d43 = +(d29 - (d43 * d38 + d41 * d32));
+  i37 = i3;
+  HEAPF32[i37 >> 2] = d40;
+  HEAPF32[i37 + 4 >> 2] = d43;
+  __ZN15b2WorldManifold10InitializeEPK10b2ManifoldRK11b2TransformfS5_f(i5, i31 + 64 | 0, i8, d45, i3, d44);
+  i37 = i15 + (i16 * 152 | 0) + 72 | 0;
+  i42 = i5;
+  i33 = HEAP32[i42 + 4 >> 2] | 0;
+  i31 = i37;
+  HEAP32[i31 >> 2] = HEAP32[i42 >> 2];
+  HEAP32[i31 + 4 >> 2] = i33;
+  i31 = i15 + (i16 * 152 | 0) + 144 | 0;
+  i33 = HEAP32[i31 >> 2] | 0;
+  do {
+   if ((i33 | 0) > 0) {
+    i36 = i15 + (i16 * 152 | 0) + 76 | 0;
+    d32 = d30 + d24;
+    i35 = i15 + (i16 * 152 | 0) + 140 | 0;
+    i34 = 0;
+    do {
+     i49 = i5 + (i34 << 3) + 8 | 0;
+     d41 = +HEAPF32[i49 >> 2] - d26;
+     i42 = i5 + (i34 << 3) + 12 | 0;
+     d39 = +d41;
+     d40 = +(+HEAPF32[i42 >> 2] - d27);
+     i50 = i15 + (i16 * 152 | 0) + (i34 * 36 | 0) | 0;
+     HEAPF32[i50 >> 2] = d39;
+     HEAPF32[i50 + 4 >> 2] = d40;
+     d40 = +HEAPF32[i49 >> 2] - d28;
+     d39 = +d40;
+     d47 = +(+HEAPF32[i42 >> 2] - d29);
+     i42 = i15 + (i16 * 152 | 0) + (i34 * 36 | 0) + 8 | 0;
+     HEAPF32[i42 >> 2] = d39;
+     HEAPF32[i42 + 4 >> 2] = d47;
+     d47 = +HEAPF32[i36 >> 2];
+     d39 = +HEAPF32[i15 + (i16 * 152 | 0) + (i34 * 36 | 0) + 4 >> 2];
+     d43 = +HEAPF32[i37 >> 2];
+     d48 = d41 * d47 - d39 * d43;
+     d38 = +HEAPF32[i15 + (i16 * 152 | 0) + (i34 * 36 | 0) + 12 >> 2];
+     d43 = d47 * d40 - d43 * d38;
+     d43 = d32 + d48 * d17 * d48 + d43 * d18 * d43;
+     if (d43 > 0.0) {
+      d43 = 1.0 / d43;
+     } else {
+      d43 = 0.0;
+     }
+     HEAPF32[i15 + (i16 * 152 | 0) + (i34 * 36 | 0) + 24 >> 2] = d43;
+     d43 = +HEAPF32[i36 >> 2];
+     d47 = -+HEAPF32[i37 >> 2];
+     d48 = d41 * d47 - d43 * d39;
+     d43 = d40 * d47 - d43 * d38;
+     d43 = d32 + d48 * d17 * d48 + d43 * d18 * d43;
+     if (d43 > 0.0) {
+      d43 = 1.0 / d43;
+     } else {
+      d43 = 0.0;
+     }
+     HEAPF32[i15 + (i16 * 152 | 0) + (i34 * 36 | 0) + 28 >> 2] = d43;
+     i42 = i15 + (i16 * 152 | 0) + (i34 * 36 | 0) + 32 | 0;
+     HEAPF32[i42 >> 2] = 0.0;
+     d38 = +HEAPF32[i37 >> 2] * (d20 - d21 * d38 - d22 + d23 * d39) + +HEAPF32[i36 >> 2] * (d19 + d21 * d40 - d25 - d23 * d41);
+     if (d38 < -1.0) {
+      HEAPF32[i42 >> 2] = -(d38 * +HEAPF32[i35 >> 2]);
+     }
+     i34 = i34 + 1 | 0;
+    } while ((i34 | 0) != (i33 | 0));
+    if ((HEAP32[i31 >> 2] | 0) == 2) {
+     d45 = +HEAPF32[i15 + (i16 * 152 | 0) + 76 >> 2];
+     d20 = +HEAPF32[i37 >> 2];
+     d44 = +HEAPF32[i15 + (i16 * 152 | 0) >> 2] * d45 - +HEAPF32[i15 + (i16 * 152 | 0) + 4 >> 2] * d20;
+     d19 = d45 * +HEAPF32[i15 + (i16 * 152 | 0) + 8 >> 2] - d20 * +HEAPF32[i15 + (i16 * 152 | 0) + 12 >> 2];
+     d47 = d45 * +HEAPF32[i15 + (i16 * 152 | 0) + 36 >> 2] - d20 * +HEAPF32[i15 + (i16 * 152 | 0) + 40 >> 2];
+     d20 = d45 * +HEAPF32[i15 + (i16 * 152 | 0) + 44 >> 2] - d20 * +HEAPF32[i15 + (i16 * 152 | 0) + 48 >> 2];
+     d45 = d30 + d24;
+     d46 = d17 * d44;
+     d48 = d18 * d19;
+     d19 = d45 + d44 * d46 + d19 * d48;
+     d18 = d45 + d47 * d17 * d47 + d20 * d18 * d20;
+     d17 = d45 + d46 * d47 + d48 * d20;
+     d20 = d19 * d18 - d17 * d17;
+     if (!(d19 * d19 < d20 * 1.0e3)) {
+      HEAP32[i31 >> 2] = 1;
+      break;
+     }
+     HEAPF32[i15 + (i16 * 152 | 0) + 96 >> 2] = d19;
+     HEAPF32[i15 + (i16 * 152 | 0) + 100 >> 2] = d17;
+     HEAPF32[i15 + (i16 * 152 | 0) + 104 >> 2] = d17;
+     HEAPF32[i15 + (i16 * 152 | 0) + 108 >> 2] = d18;
+     if (d20 != 0.0) {
+      d20 = 1.0 / d20;
+     }
+     d48 = -(d20 * d17);
+     HEAPF32[i15 + (i16 * 152 | 0) + 80 >> 2] = d18 * d20;
+     HEAPF32[i15 + (i16 * 152 | 0) + 84 >> 2] = d48;
+     HEAPF32[i15 + (i16 * 152 | 0) + 88 >> 2] = d48;
+     HEAPF32[i15 + (i16 * 152 | 0) + 92 >> 2] = d19 * d20;
+    }
+   }
+  } while (0);
+  i16 = i16 + 1 | 0;
+  if ((i16 | 0) >= (HEAP32[i4 >> 2] | 0)) {
+   i2 = 21;
+   break;
+  }
+ }
+ if ((i2 | 0) == 4) {
+  ___assert_fail(6584, 6520, 168, 6616);
+ } else if ((i2 | 0) == 21) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function __Z17b2CollidePolygonsP10b2ManifoldPK14b2PolygonShapeRK11b2TransformS3_S6_(i5, i27, i28, i24, i14) {
+ i5 = i5 | 0;
+ i27 = i27 | 0;
+ i28 = i28 | 0;
+ i24 = i24 | 0;
+ i14 = i14 | 0;
+ var i1 = 0, i2 = 0, d3 = 0.0, i4 = 0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d9 = 0.0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, d15 = 0.0, d16 = 0.0, i17 = 0, d18 = 0.0, d19 = 0.0, i20 = 0, d21 = 0.0, d22 = 0.0, d23 = 0.0, d25 = 0.0, d26 = 0.0, d29 = 0.0, d30 = 0.0, i31 = 0, d32 = 0.0, i33 = 0, i34 = 0, d35 = 0.0, d36 = 0.0, d37 = 0.0, d38 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 96 | 0;
+ i17 = i1 + 92 | 0;
+ i20 = i1 + 88 | 0;
+ i13 = i1;
+ i11 = i1 + 80 | 0;
+ i12 = i1 + 56 | 0;
+ i4 = i1 + 32 | 0;
+ i10 = i1 + 24 | 0;
+ i2 = i5 + 60 | 0;
+ HEAP32[i2 >> 2] = 0;
+ d3 = +HEAPF32[i27 + 8 >> 2] + +HEAPF32[i24 + 8 >> 2];
+ HEAP32[i17 >> 2] = 0;
+ d7 = +__ZL19b2FindMaxSeparationPiPK14b2PolygonShapeRK11b2TransformS2_S5_(i17, i27, i28, i24, i14);
+ if (d7 > d3) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP32[i20 >> 2] = 0;
+ d6 = +__ZL19b2FindMaxSeparationPiPK14b2PolygonShapeRK11b2TransformS2_S5_(i20, i24, i14, i27, i28);
+ if (d6 > d3) {
+  STACKTOP = i1;
+  return;
+ }
+ if (d6 > d7 * .9800000190734863 + .0010000000474974513) {
+  d18 = +HEAPF32[i14 >> 2];
+  d19 = +HEAPF32[i14 + 4 >> 2];
+  d15 = +HEAPF32[i14 + 8 >> 2];
+  d16 = +HEAPF32[i14 + 12 >> 2];
+  d9 = +HEAPF32[i28 >> 2];
+  d6 = +HEAPF32[i28 + 4 >> 2];
+  d7 = +HEAPF32[i28 + 8 >> 2];
+  d8 = +HEAPF32[i28 + 12 >> 2];
+  i17 = HEAP32[i20 >> 2] | 0;
+  HEAP32[i5 + 56 >> 2] = 2;
+  i14 = 1;
+  i20 = i24;
+ } else {
+  d18 = +HEAPF32[i28 >> 2];
+  d19 = +HEAPF32[i28 + 4 >> 2];
+  d15 = +HEAPF32[i28 + 8 >> 2];
+  d16 = +HEAPF32[i28 + 12 >> 2];
+  d9 = +HEAPF32[i14 >> 2];
+  d6 = +HEAPF32[i14 + 4 >> 2];
+  d7 = +HEAPF32[i14 + 8 >> 2];
+  d8 = +HEAPF32[i14 + 12 >> 2];
+  i17 = HEAP32[i17 >> 2] | 0;
+  HEAP32[i5 + 56 >> 2] = 1;
+  i14 = 0;
+  i20 = i27;
+  i27 = i24;
+ }
+ i28 = HEAP32[i27 + 148 >> 2] | 0;
+ if (!((i17 | 0) > -1)) {
+  ___assert_fail(5640, 5688, 151, 5728);
+ }
+ i24 = HEAP32[i20 + 148 >> 2] | 0;
+ if ((i24 | 0) <= (i17 | 0)) {
+  ___assert_fail(5640, 5688, 151, 5728);
+ }
+ d21 = +HEAPF32[i20 + (i17 << 3) + 84 >> 2];
+ d36 = +HEAPF32[i20 + (i17 << 3) + 88 >> 2];
+ d22 = d16 * d21 - d15 * d36;
+ d36 = d15 * d21 + d16 * d36;
+ d21 = d8 * d22 + d7 * d36;
+ d22 = d8 * d36 - d7 * d22;
+ if ((i28 | 0) > 0) {
+  i33 = 0;
+  i34 = 0;
+  d23 = 3.4028234663852886e+38;
+  while (1) {
+   d25 = d21 * +HEAPF32[i27 + (i33 << 3) + 84 >> 2] + d22 * +HEAPF32[i27 + (i33 << 3) + 88 >> 2];
+   i31 = d25 < d23;
+   i34 = i31 ? i33 : i34;
+   i33 = i33 + 1 | 0;
+   if ((i33 | 0) == (i28 | 0)) {
+    break;
+   } else {
+    d23 = i31 ? d25 : d23;
+   }
+  }
+ } else {
+  i34 = 0;
+ }
+ i31 = i34 + 1 | 0;
+ i33 = (i31 | 0) < (i28 | 0) ? i31 : 0;
+ d35 = +HEAPF32[i27 + (i34 << 3) + 20 >> 2];
+ d32 = +HEAPF32[i27 + (i34 << 3) + 24 >> 2];
+ d36 = +(d9 + (d8 * d35 - d7 * d32));
+ d32 = +(d6 + (d7 * d35 + d8 * d32));
+ i31 = i13;
+ HEAPF32[i31 >> 2] = d36;
+ HEAPF32[i31 + 4 >> 2] = d32;
+ i31 = i17 & 255;
+ i28 = i13 + 8 | 0;
+ HEAP8[i28] = i31;
+ HEAP8[i28 + 1 | 0] = i34;
+ HEAP8[i28 + 2 | 0] = 1;
+ HEAP8[i28 + 3 | 0] = 0;
+ d32 = +HEAPF32[i27 + (i33 << 3) + 20 >> 2];
+ d36 = +HEAPF32[i27 + (i33 << 3) + 24 >> 2];
+ d35 = +(d9 + (d8 * d32 - d7 * d36));
+ d36 = +(d6 + (d7 * d32 + d8 * d36));
+ i27 = i13 + 12 | 0;
+ HEAPF32[i27 >> 2] = d35;
+ HEAPF32[i27 + 4 >> 2] = d36;
+ i27 = i13 + 20 | 0;
+ HEAP8[i27] = i31;
+ HEAP8[i27 + 1 | 0] = i33;
+ HEAP8[i27 + 2 | 0] = 1;
+ HEAP8[i27 + 3 | 0] = 0;
+ i27 = i17 + 1 | 0;
+ i24 = (i27 | 0) < (i24 | 0) ? i27 : 0;
+ i34 = i20 + (i17 << 3) + 20 | 0;
+ d26 = +HEAPF32[i34 >> 2];
+ d25 = +HEAPF32[i34 + 4 >> 2];
+ i34 = i20 + (i24 << 3) + 20 | 0;
+ d30 = +HEAPF32[i34 >> 2];
+ d29 = +HEAPF32[i34 + 4 >> 2];
+ d32 = d30 - d26;
+ d35 = d29 - d25;
+ d21 = +Math_sqrt(+(d32 * d32 + d35 * d35));
+ if (!(d21 < 1.1920928955078125e-7)) {
+  d36 = 1.0 / d21;
+  d32 = d32 * d36;
+  d35 = d35 * d36;
+ }
+ d36 = d16 * d32 - d15 * d35;
+ d21 = d16 * d35 + d15 * d32;
+ HEAPF32[i11 >> 2] = d36;
+ HEAPF32[i11 + 4 >> 2] = d21;
+ d22 = -d36;
+ d38 = d18 + (d16 * d26 - d15 * d25);
+ d37 = d19 + (d15 * d26 + d16 * d25);
+ d23 = d38 * d21 + d37 * d22;
+ HEAPF32[i10 >> 2] = d22;
+ HEAPF32[i10 + 4 >> 2] = -d21;
+ if ((__Z19b2ClipSegmentToLineP12b2ClipVertexPKS_RK6b2Vec2fi(i12, i13, i10, d3 - (d38 * d36 + d37 * d21), i17) | 0) < 2) {
+  STACKTOP = i1;
+  return;
+ }
+ if ((__Z19b2ClipSegmentToLineP12b2ClipVertexPKS_RK6b2Vec2fi(i4, i12, i11, d3 + ((d18 + (d16 * d30 - d15 * d29)) * d36 + (d19 + (d15 * d30 + d16 * d29)) * d21), i24) | 0) < 2) {
+  STACKTOP = i1;
+  return;
+ }
+ d16 = +d35;
+ d15 = +-d32;
+ i10 = i5 + 40 | 0;
+ HEAPF32[i10 >> 2] = d16;
+ HEAPF32[i10 + 4 >> 2] = d15;
+ d15 = +((d26 + d30) * .5);
+ d16 = +((d25 + d29) * .5);
+ i10 = i5 + 48 | 0;
+ HEAPF32[i10 >> 2] = d15;
+ HEAPF32[i10 + 4 >> 2] = d16;
+ d16 = +HEAPF32[i4 >> 2];
+ d15 = +HEAPF32[i4 + 4 >> 2];
+ i10 = !(d21 * d16 + d15 * d22 - d23 <= d3);
+ if (i14 << 24 >> 24 == 0) {
+  if (i10) {
+   i10 = 0;
+  } else {
+   d38 = d16 - d9;
+   d36 = d15 - d6;
+   d37 = +(d8 * d38 + d7 * d36);
+   d38 = +(d8 * d36 - d7 * d38);
+   i10 = i5;
+   HEAPF32[i10 >> 2] = d37;
+   HEAPF32[i10 + 4 >> 2] = d38;
+   HEAP32[i5 + 16 >> 2] = HEAP32[i4 + 8 >> 2];
+   i10 = 1;
+  }
+  d16 = +HEAPF32[i4 + 12 >> 2];
+  d15 = +HEAPF32[i4 + 16 >> 2];
+  if (d21 * d16 + d15 * d22 - d23 <= d3) {
+   d38 = d16 - d9;
+   d36 = d15 - d6;
+   d37 = +(d8 * d38 + d7 * d36);
+   d38 = +(d8 * d36 - d7 * d38);
+   i34 = i5 + (i10 * 20 | 0) | 0;
+   HEAPF32[i34 >> 2] = d37;
+   HEAPF32[i34 + 4 >> 2] = d38;
+   HEAP32[i5 + (i10 * 20 | 0) + 16 >> 2] = HEAP32[i4 + 20 >> 2];
+   i10 = i10 + 1 | 0;
+  }
+ } else {
+  if (i10) {
+   i10 = 0;
+  } else {
+   d38 = d16 - d9;
+   d36 = d15 - d6;
+   d37 = +(d8 * d38 + d7 * d36);
+   d38 = +(d8 * d36 - d7 * d38);
+   i10 = i5;
+   HEAPF32[i10 >> 2] = d37;
+   HEAPF32[i10 + 4 >> 2] = d38;
+   i10 = i5 + 16 | 0;
+   i34 = HEAP32[i4 + 8 >> 2] | 0;
+   HEAP32[i10 >> 2] = i34;
+   HEAP8[i10] = i34 >>> 8;
+   HEAP8[i10 + 1 | 0] = i34;
+   HEAP8[i10 + 2 | 0] = i34 >>> 24;
+   HEAP8[i10 + 3 | 0] = i34 >>> 16;
+   i10 = 1;
+  }
+  d16 = +HEAPF32[i4 + 12 >> 2];
+  d15 = +HEAPF32[i4 + 16 >> 2];
+  if (d21 * d16 + d15 * d22 - d23 <= d3) {
+   d38 = d16 - d9;
+   d36 = d15 - d6;
+   d37 = +(d8 * d38 + d7 * d36);
+   d38 = +(d8 * d36 - d7 * d38);
+   i34 = i5 + (i10 * 20 | 0) | 0;
+   HEAPF32[i34 >> 2] = d37;
+   HEAPF32[i34 + 4 >> 2] = d38;
+   i34 = i5 + (i10 * 20 | 0) + 16 | 0;
+   i33 = HEAP32[i4 + 20 >> 2] | 0;
+   HEAP32[i34 >> 2] = i33;
+   HEAP8[i34] = i33 >>> 8;
+   HEAP8[i34 + 1 | 0] = i33;
+   HEAP8[i34 + 2 | 0] = i33 >>> 24;
+   HEAP8[i34 + 3 | 0] = i33 >>> 16;
+   i10 = i10 + 1 | 0;
+  }
+ }
+ HEAP32[i2 >> 2] = i10;
+ STACKTOP = i1;
+ return;
+}
+function __ZN8b2Island8SolveTOIERK10b2TimeStepii(i4, i11, i15, i18) {
+ i4 = i4 | 0;
+ i11 = i11 | 0;
+ i15 = i15 | 0;
+ i18 = i18 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, d12 = 0.0, d13 = 0.0, d14 = 0.0, d16 = 0.0, d17 = 0.0, d19 = 0.0, d20 = 0.0, d21 = 0.0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, d26 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 128 | 0;
+ i2 = i1 + 96 | 0;
+ i10 = i1 + 52 | 0;
+ i3 = i1;
+ i6 = i4 + 28 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ if ((i5 | 0) <= (i15 | 0)) {
+  ___assert_fail(5464, 5488, 386, 5520);
+ }
+ if ((i5 | 0) <= (i18 | 0)) {
+  ___assert_fail(5536, 5488, 387, 5520);
+ }
+ if ((i5 | 0) > 0) {
+  i9 = i4 + 8 | 0;
+  i8 = i4 + 20 | 0;
+  i7 = i4 + 24 | 0;
+  i22 = 0;
+  while (1) {
+   i23 = HEAP32[(HEAP32[i9 >> 2] | 0) + (i22 << 2) >> 2] | 0;
+   i5 = i23 + 44 | 0;
+   i24 = HEAP32[i5 + 4 >> 2] | 0;
+   i25 = (HEAP32[i8 >> 2] | 0) + (i22 * 12 | 0) | 0;
+   HEAP32[i25 >> 2] = HEAP32[i5 >> 2];
+   HEAP32[i25 + 4 >> 2] = i24;
+   HEAPF32[(HEAP32[i8 >> 2] | 0) + (i22 * 12 | 0) + 8 >> 2] = +HEAPF32[i23 + 56 >> 2];
+   i25 = i23 + 64 | 0;
+   i24 = HEAP32[i25 + 4 >> 2] | 0;
+   i5 = (HEAP32[i7 >> 2] | 0) + (i22 * 12 | 0) | 0;
+   HEAP32[i5 >> 2] = HEAP32[i25 >> 2];
+   HEAP32[i5 + 4 >> 2] = i24;
+   i5 = HEAP32[i7 >> 2] | 0;
+   HEAPF32[i5 + (i22 * 12 | 0) + 8 >> 2] = +HEAPF32[i23 + 72 >> 2];
+   i22 = i22 + 1 | 0;
+   if ((i22 | 0) >= (HEAP32[i6 >> 2] | 0)) {
+    i22 = i5;
+    break;
+   }
+  }
+ } else {
+  i8 = i4 + 20 | 0;
+  i22 = HEAP32[i4 + 24 >> 2] | 0;
+ }
+ i5 = i4 + 12 | 0;
+ HEAP32[i10 + 24 >> 2] = HEAP32[i5 >> 2];
+ i7 = i4 + 36 | 0;
+ HEAP32[i10 + 28 >> 2] = HEAP32[i7 >> 2];
+ HEAP32[i10 + 40 >> 2] = HEAP32[i4 >> 2];
+ HEAP32[i10 + 0 >> 2] = HEAP32[i11 + 0 >> 2];
+ HEAP32[i10 + 4 >> 2] = HEAP32[i11 + 4 >> 2];
+ HEAP32[i10 + 8 >> 2] = HEAP32[i11 + 8 >> 2];
+ HEAP32[i10 + 12 >> 2] = HEAP32[i11 + 12 >> 2];
+ HEAP32[i10 + 16 >> 2] = HEAP32[i11 + 16 >> 2];
+ HEAP32[i10 + 20 >> 2] = HEAP32[i11 + 20 >> 2];
+ HEAP32[i10 + 32 >> 2] = HEAP32[i8 >> 2];
+ i9 = i4 + 24 | 0;
+ HEAP32[i10 + 36 >> 2] = i22;
+ __ZN15b2ContactSolverC2EP18b2ContactSolverDef(i3, i10);
+ i10 = i11 + 16 | 0;
+ L13 : do {
+  if ((HEAP32[i10 >> 2] | 0) > 0) {
+   i22 = 0;
+   do {
+    i22 = i22 + 1 | 0;
+    if (__ZN15b2ContactSolver27SolveTOIPositionConstraintsEii(i3, i15, i18) | 0) {
+     break L13;
+    }
+   } while ((i22 | 0) < (HEAP32[i10 >> 2] | 0));
+  }
+ } while (0);
+ i10 = i4 + 8 | 0;
+ i24 = (HEAP32[i8 >> 2] | 0) + (i15 * 12 | 0) | 0;
+ i25 = HEAP32[i24 + 4 >> 2] | 0;
+ i23 = (HEAP32[(HEAP32[i10 >> 2] | 0) + (i15 << 2) >> 2] | 0) + 36 | 0;
+ HEAP32[i23 >> 2] = HEAP32[i24 >> 2];
+ HEAP32[i23 + 4 >> 2] = i25;
+ i23 = HEAP32[i8 >> 2] | 0;
+ i25 = HEAP32[i10 >> 2] | 0;
+ HEAPF32[(HEAP32[i25 + (i15 << 2) >> 2] | 0) + 52 >> 2] = +HEAPF32[i23 + (i15 * 12 | 0) + 8 >> 2];
+ i23 = i23 + (i18 * 12 | 0) | 0;
+ i24 = HEAP32[i23 + 4 >> 2] | 0;
+ i25 = (HEAP32[i25 + (i18 << 2) >> 2] | 0) + 36 | 0;
+ HEAP32[i25 >> 2] = HEAP32[i23 >> 2];
+ HEAP32[i25 + 4 >> 2] = i24;
+ HEAPF32[(HEAP32[(HEAP32[i10 >> 2] | 0) + (i18 << 2) >> 2] | 0) + 52 >> 2] = +HEAPF32[(HEAP32[i8 >> 2] | 0) + (i18 * 12 | 0) + 8 >> 2];
+ __ZN15b2ContactSolver29InitializeVelocityConstraintsEv(i3);
+ i18 = i11 + 12 | 0;
+ if ((HEAP32[i18 >> 2] | 0) > 0) {
+  i15 = 0;
+  do {
+   __ZN15b2ContactSolver24SolveVelocityConstraintsEv(i3);
+   i15 = i15 + 1 | 0;
+  } while ((i15 | 0) < (HEAP32[i18 >> 2] | 0));
+ }
+ d16 = +HEAPF32[i11 >> 2];
+ if ((HEAP32[i6 >> 2] | 0) > 0) {
+  i15 = 0;
+  do {
+   i25 = HEAP32[i8 >> 2] | 0;
+   i11 = i25 + (i15 * 12 | 0) | 0;
+   i24 = i11;
+   d12 = +HEAPF32[i24 >> 2];
+   d14 = +HEAPF32[i24 + 4 >> 2];
+   d13 = +HEAPF32[i25 + (i15 * 12 | 0) + 8 >> 2];
+   i25 = HEAP32[i9 >> 2] | 0;
+   i24 = i25 + (i15 * 12 | 0) | 0;
+   d19 = +HEAPF32[i24 >> 2];
+   d20 = +HEAPF32[i24 + 4 >> 2];
+   d17 = +HEAPF32[i25 + (i15 * 12 | 0) + 8 >> 2];
+   d26 = d16 * d19;
+   d21 = d16 * d20;
+   d21 = d26 * d26 + d21 * d21;
+   if (d21 > 4.0) {
+    d26 = 2.0 / +Math_sqrt(+d21);
+    d19 = d19 * d26;
+    d20 = d20 * d26;
+   }
+   d21 = d16 * d17;
+   if (d21 * d21 > 2.4674012660980225) {
+    if (!(d21 > 0.0)) {
+     d21 = -d21;
+    }
+    d17 = d17 * (1.5707963705062866 / d21);
+   }
+   d21 = d12 + d16 * d19;
+   d14 = d14 + d16 * d20;
+   d26 = d13 + d16 * d17;
+   d12 = +d21;
+   d13 = +d14;
+   i25 = i11;
+   HEAPF32[i25 >> 2] = d12;
+   HEAPF32[i25 + 4 >> 2] = d13;
+   HEAPF32[(HEAP32[i8 >> 2] | 0) + (i15 * 12 | 0) + 8 >> 2] = d26;
+   d19 = +d19;
+   d20 = +d20;
+   i25 = (HEAP32[i9 >> 2] | 0) + (i15 * 12 | 0) | 0;
+   HEAPF32[i25 >> 2] = d19;
+   HEAPF32[i25 + 4 >> 2] = d20;
+   HEAPF32[(HEAP32[i9 >> 2] | 0) + (i15 * 12 | 0) + 8 >> 2] = d17;
+   i25 = HEAP32[(HEAP32[i10 >> 2] | 0) + (i15 << 2) >> 2] | 0;
+   i24 = i25 + 44 | 0;
+   HEAPF32[i24 >> 2] = d12;
+   HEAPF32[i24 + 4 >> 2] = d13;
+   HEAPF32[i25 + 56 >> 2] = d26;
+   i24 = i25 + 64 | 0;
+   HEAPF32[i24 >> 2] = d19;
+   HEAPF32[i24 + 4 >> 2] = d20;
+   HEAPF32[i25 + 72 >> 2] = d17;
+   d17 = +Math_sin(+d26);
+   HEAPF32[i25 + 20 >> 2] = d17;
+   d20 = +Math_cos(+d26);
+   HEAPF32[i25 + 24 >> 2] = d20;
+   d19 = +HEAPF32[i25 + 28 >> 2];
+   d26 = +HEAPF32[i25 + 32 >> 2];
+   d21 = +(d21 - (d20 * d19 - d17 * d26));
+   d26 = +(d14 - (d17 * d19 + d20 * d26));
+   i25 = i25 + 12 | 0;
+   HEAPF32[i25 >> 2] = d21;
+   HEAPF32[i25 + 4 >> 2] = d26;
+   i15 = i15 + 1 | 0;
+  } while ((i15 | 0) < (HEAP32[i6 >> 2] | 0));
+ }
+ i6 = HEAP32[i3 + 40 >> 2] | 0;
+ i4 = i4 + 4 | 0;
+ if ((HEAP32[i4 >> 2] | 0) == 0) {
+  __ZN15b2ContactSolverD2Ev(i3);
+  STACKTOP = i1;
+  return;
+ }
+ if ((HEAP32[i7 >> 2] | 0) <= 0) {
+  __ZN15b2ContactSolverD2Ev(i3);
+  STACKTOP = i1;
+  return;
+ }
+ i8 = i2 + 16 | 0;
+ i9 = 0;
+ do {
+  i10 = HEAP32[(HEAP32[i5 >> 2] | 0) + (i9 << 2) >> 2] | 0;
+  i11 = HEAP32[i6 + (i9 * 152 | 0) + 144 >> 2] | 0;
+  HEAP32[i8 >> 2] = i11;
+  if ((i11 | 0) > 0) {
+   i15 = 0;
+   do {
+    HEAPF32[i2 + (i15 << 2) >> 2] = +HEAPF32[i6 + (i9 * 152 | 0) + (i15 * 36 | 0) + 16 >> 2];
+    HEAPF32[i2 + (i15 << 2) + 8 >> 2] = +HEAPF32[i6 + (i9 * 152 | 0) + (i15 * 36 | 0) + 20 >> 2];
+    i15 = i15 + 1 | 0;
+   } while ((i15 | 0) != (i11 | 0));
+  }
+  i25 = HEAP32[i4 >> 2] | 0;
+  FUNCTION_TABLE_viii[HEAP32[(HEAP32[i25 >> 2] | 0) + 20 >> 2] & 3](i25, i10, i2);
+  i9 = i9 + 1 | 0;
+ } while ((i9 | 0) < (HEAP32[i7 >> 2] | 0));
+ __ZN15b2ContactSolverD2Ev(i3);
+ STACKTOP = i1;
+ return;
+}
+function __ZN20b2SeparationFunction10InitializeEPK14b2SimplexCachePK15b2DistanceProxyRK7b2SweepS5_S8_f(i2, i11, i13, i21, i12, i24, d9) {
+ i2 = i2 | 0;
+ i11 = i11 | 0;
+ i13 = i13 | 0;
+ i21 = i21 | 0;
+ i12 = i12 | 0;
+ i24 = i24 | 0;
+ d9 = +d9;
+ var i1 = 0, d3 = 0.0, d4 = 0.0, d5 = 0.0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d10 = 0.0, i14 = 0, d15 = 0.0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, d22 = 0.0, i23 = 0, i25 = 0, i26 = 0, i27 = 0, d28 = 0.0, d29 = 0.0;
+ i1 = STACKTOP;
+ HEAP32[i2 >> 2] = i13;
+ HEAP32[i2 + 4 >> 2] = i12;
+ i14 = HEAP16[i11 + 4 >> 1] | 0;
+ if (!(i14 << 16 >> 16 != 0 & (i14 & 65535) < 3)) {
+  ___assert_fail(3744, 3560, 50, 3768);
+ }
+ i23 = i2 + 8 | 0;
+ i25 = i23 + 0 | 0;
+ i27 = i21 + 0 | 0;
+ i26 = i25 + 36 | 0;
+ do {
+  HEAP32[i25 >> 2] = HEAP32[i27 >> 2];
+  i25 = i25 + 4 | 0;
+  i27 = i27 + 4 | 0;
+ } while ((i25 | 0) < (i26 | 0));
+ i21 = i2 + 44 | 0;
+ i25 = i21 + 0 | 0;
+ i27 = i24 + 0 | 0;
+ i26 = i25 + 36 | 0;
+ do {
+  HEAP32[i25 >> 2] = HEAP32[i27 >> 2];
+  i25 = i25 + 4 | 0;
+  i27 = i27 + 4 | 0;
+ } while ((i25 | 0) < (i26 | 0));
+ d19 = 1.0 - d9;
+ d4 = d19 * +HEAPF32[i2 + 32 >> 2] + +HEAPF32[i2 + 36 >> 2] * d9;
+ d3 = +Math_sin(+d4);
+ d4 = +Math_cos(+d4);
+ d7 = +HEAPF32[i23 >> 2];
+ d5 = +HEAPF32[i2 + 12 >> 2];
+ d8 = d19 * +HEAPF32[i2 + 16 >> 2] + +HEAPF32[i2 + 24 >> 2] * d9 - (d4 * d7 - d3 * d5);
+ d5 = d19 * +HEAPF32[i2 + 20 >> 2] + +HEAPF32[i2 + 28 >> 2] * d9 - (d3 * d7 + d4 * d5);
+ d7 = d19 * +HEAPF32[i2 + 68 >> 2] + +HEAPF32[i2 + 72 >> 2] * d9;
+ d6 = +Math_sin(+d7);
+ d7 = +Math_cos(+d7);
+ d20 = +HEAPF32[i21 >> 2];
+ d22 = +HEAPF32[i2 + 48 >> 2];
+ d10 = d19 * +HEAPF32[i2 + 52 >> 2] + +HEAPF32[i2 + 60 >> 2] * d9 - (d7 * d20 - d6 * d22);
+ d9 = d19 * +HEAPF32[i2 + 56 >> 2] + +HEAPF32[i2 + 64 >> 2] * d9 - (d6 * d20 + d7 * d22);
+ if (i14 << 16 >> 16 == 1) {
+  HEAP32[i2 + 80 >> 2] = 0;
+  i14 = HEAPU8[i11 + 6 | 0] | 0;
+  if ((HEAP32[i13 + 20 >> 2] | 0) <= (i14 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i27 = (HEAP32[i13 + 16 >> 2] | 0) + (i14 << 3) | 0;
+  d15 = +HEAPF32[i27 >> 2];
+  d16 = +HEAPF32[i27 + 4 >> 2];
+  i11 = HEAPU8[i11 + 9 | 0] | 0;
+  if ((HEAP32[i12 + 20 >> 2] | 0) <= (i11 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i11 = (HEAP32[i12 + 16 >> 2] | 0) + (i11 << 3) | 0;
+  d20 = +HEAPF32[i11 >> 2];
+  d22 = +HEAPF32[i11 + 4 >> 2];
+  i11 = i2 + 92 | 0;
+  d8 = d10 + (d7 * d20 - d6 * d22) - (d8 + (d4 * d15 - d3 * d16));
+  d4 = d9 + (d6 * d20 + d7 * d22) - (d5 + (d3 * d15 + d4 * d16));
+  d22 = +d8;
+  d3 = +d4;
+  i27 = i11;
+  HEAPF32[i27 >> 2] = d22;
+  HEAPF32[i27 + 4 >> 2] = d3;
+  d3 = +Math_sqrt(+(d8 * d8 + d4 * d4));
+  if (d3 < 1.1920928955078125e-7) {
+   d22 = 0.0;
+   STACKTOP = i1;
+   return +d22;
+  }
+  d22 = 1.0 / d3;
+  HEAPF32[i11 >> 2] = d8 * d22;
+  HEAPF32[i2 + 96 >> 2] = d4 * d22;
+  d22 = d3;
+  STACKTOP = i1;
+  return +d22;
+ }
+ i14 = i11 + 6 | 0;
+ i21 = i11 + 7 | 0;
+ i23 = i2 + 80 | 0;
+ if ((HEAP8[i14] | 0) == (HEAP8[i21] | 0)) {
+  HEAP32[i23 >> 2] = 2;
+  i23 = HEAPU8[i11 + 9 | 0] | 0;
+  i21 = HEAP32[i12 + 20 >> 2] | 0;
+  if ((i21 | 0) <= (i23 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i12 = HEAP32[i12 + 16 >> 2] | 0;
+  i27 = i12 + (i23 << 3) | 0;
+  d16 = +HEAPF32[i27 >> 2];
+  d15 = +HEAPF32[i27 + 4 >> 2];
+  i11 = HEAPU8[i11 + 10 | 0] | 0;
+  if ((i21 | 0) <= (i11 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i11 = i12 + (i11 << 3) | 0;
+  d20 = +HEAPF32[i11 >> 2];
+  d18 = +HEAPF32[i11 + 4 >> 2];
+  i11 = i2 + 92 | 0;
+  d22 = d20 - d16;
+  d19 = d18 - d15;
+  d17 = -d22;
+  d29 = +d19;
+  d28 = +d17;
+  i27 = i11;
+  HEAPF32[i27 >> 2] = d29;
+  HEAPF32[i27 + 4 >> 2] = d28;
+  d22 = +Math_sqrt(+(d19 * d19 + d22 * d22));
+  if (!(d22 < 1.1920928955078125e-7)) {
+   d29 = 1.0 / d22;
+   d19 = d19 * d29;
+   HEAPF32[i11 >> 2] = d19;
+   d17 = d29 * d17;
+   HEAPF32[i2 + 96 >> 2] = d17;
+  }
+  d16 = (d16 + d20) * .5;
+  d15 = (d15 + d18) * .5;
+  d28 = +d16;
+  d29 = +d15;
+  i2 = i2 + 84 | 0;
+  HEAPF32[i2 >> 2] = d28;
+  HEAPF32[i2 + 4 >> 2] = d29;
+  i2 = HEAPU8[i14] | 0;
+  if ((HEAP32[i13 + 20 >> 2] | 0) <= (i2 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i27 = (HEAP32[i13 + 16 >> 2] | 0) + (i2 << 3) | 0;
+  d28 = +HEAPF32[i27 >> 2];
+  d29 = +HEAPF32[i27 + 4 >> 2];
+  d3 = (d7 * d19 - d6 * d17) * (d8 + (d4 * d28 - d3 * d29) - (d10 + (d7 * d16 - d6 * d15))) + (d6 * d19 + d7 * d17) * (d5 + (d3 * d28 + d4 * d29) - (d9 + (d6 * d16 + d7 * d15)));
+  if (!(d3 < 0.0)) {
+   d29 = d3;
+   STACKTOP = i1;
+   return +d29;
+  }
+  d28 = +-d19;
+  d29 = +-d17;
+  i27 = i11;
+  HEAPF32[i27 >> 2] = d28;
+  HEAPF32[i27 + 4 >> 2] = d29;
+  d29 = -d3;
+  STACKTOP = i1;
+  return +d29;
+ } else {
+  HEAP32[i23 >> 2] = 1;
+  i23 = HEAPU8[i14] | 0;
+  i14 = HEAP32[i13 + 20 >> 2] | 0;
+  if ((i14 | 0) <= (i23 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i13 = HEAP32[i13 + 16 >> 2] | 0;
+  i27 = i13 + (i23 << 3) | 0;
+  d16 = +HEAPF32[i27 >> 2];
+  d15 = +HEAPF32[i27 + 4 >> 2];
+  i21 = HEAPU8[i21] | 0;
+  if ((i14 | 0) <= (i21 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i13 = i13 + (i21 << 3) | 0;
+  d20 = +HEAPF32[i13 >> 2];
+  d18 = +HEAPF32[i13 + 4 >> 2];
+  i13 = i2 + 92 | 0;
+  d22 = d20 - d16;
+  d19 = d18 - d15;
+  d17 = -d22;
+  d28 = +d19;
+  d29 = +d17;
+  i27 = i13;
+  HEAPF32[i27 >> 2] = d28;
+  HEAPF32[i27 + 4 >> 2] = d29;
+  d22 = +Math_sqrt(+(d19 * d19 + d22 * d22));
+  if (!(d22 < 1.1920928955078125e-7)) {
+   d29 = 1.0 / d22;
+   d19 = d19 * d29;
+   HEAPF32[i13 >> 2] = d19;
+   d17 = d29 * d17;
+   HEAPF32[i2 + 96 >> 2] = d17;
+  }
+  d16 = (d16 + d20) * .5;
+  d15 = (d15 + d18) * .5;
+  d28 = +d16;
+  d29 = +d15;
+  i2 = i2 + 84 | 0;
+  HEAPF32[i2 >> 2] = d28;
+  HEAPF32[i2 + 4 >> 2] = d29;
+  i2 = HEAPU8[i11 + 9 | 0] | 0;
+  if ((HEAP32[i12 + 20 >> 2] | 0) <= (i2 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i27 = (HEAP32[i12 + 16 >> 2] | 0) + (i2 << 3) | 0;
+  d28 = +HEAPF32[i27 >> 2];
+  d29 = +HEAPF32[i27 + 4 >> 2];
+  d3 = (d4 * d19 - d3 * d17) * (d10 + (d7 * d28 - d6 * d29) - (d8 + (d4 * d16 - d3 * d15))) + (d3 * d19 + d4 * d17) * (d9 + (d6 * d28 + d7 * d29) - (d5 + (d3 * d16 + d4 * d15)));
+  if (!(d3 < 0.0)) {
+   d29 = d3;
+   STACKTOP = i1;
+   return +d29;
+  }
+  d28 = +-d19;
+  d29 = +-d17;
+  i27 = i13;
+  HEAPF32[i27 >> 2] = d28;
+  HEAPF32[i27 + 4 >> 2] = d29;
+  d29 = -d3;
+  STACKTOP = i1;
+  return +d29;
+ }
+ return 0.0;
+}
+function __ZNK20b2SeparationFunction17FindMinSeparationEPiS0_f(i12, i10, i9, d5) {
+ i12 = i12 | 0;
+ i10 = i10 | 0;
+ i9 = i9 | 0;
+ d5 = +d5;
+ var i1 = 0, d2 = 0.0, d3 = 0.0, d4 = 0.0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d11 = 0.0, d13 = 0.0, d14 = 0.0, i15 = 0, i16 = 0, d17 = 0.0, d18 = 0.0, i19 = 0, d20 = 0.0, d21 = 0.0, i22 = 0, d23 = 0.0, d24 = 0.0, i25 = 0, i26 = 0, i27 = 0;
+ i1 = STACKTOP;
+ d21 = 1.0 - d5;
+ d6 = d21 * +HEAPF32[i12 + 32 >> 2] + +HEAPF32[i12 + 36 >> 2] * d5;
+ d7 = +Math_sin(+d6);
+ d6 = +Math_cos(+d6);
+ d3 = +HEAPF32[i12 + 8 >> 2];
+ d8 = +HEAPF32[i12 + 12 >> 2];
+ d11 = d21 * +HEAPF32[i12 + 16 >> 2] + +HEAPF32[i12 + 24 >> 2] * d5 - (d6 * d3 - d7 * d8);
+ d8 = d21 * +HEAPF32[i12 + 20 >> 2] + +HEAPF32[i12 + 28 >> 2] * d5 - (d7 * d3 + d6 * d8);
+ d3 = d21 * +HEAPF32[i12 + 68 >> 2] + +HEAPF32[i12 + 72 >> 2] * d5;
+ d2 = +Math_sin(+d3);
+ d3 = +Math_cos(+d3);
+ d23 = +HEAPF32[i12 + 44 >> 2];
+ d24 = +HEAPF32[i12 + 48 >> 2];
+ d4 = d21 * +HEAPF32[i12 + 52 >> 2] + +HEAPF32[i12 + 60 >> 2] * d5 - (d3 * d23 - d2 * d24);
+ d5 = d21 * +HEAPF32[i12 + 56 >> 2] + +HEAPF32[i12 + 64 >> 2] * d5 - (d2 * d23 + d3 * d24);
+ i19 = HEAP32[i12 + 80 >> 2] | 0;
+ if ((i19 | 0) == 1) {
+  d23 = +HEAPF32[i12 + 92 >> 2];
+  d14 = +HEAPF32[i12 + 96 >> 2];
+  d13 = d6 * d23 - d7 * d14;
+  d14 = d7 * d23 + d6 * d14;
+  d23 = +HEAPF32[i12 + 84 >> 2];
+  d24 = +HEAPF32[i12 + 88 >> 2];
+  d11 = d11 + (d6 * d23 - d7 * d24);
+  d6 = d8 + (d7 * d23 + d6 * d24);
+  d7 = -d13;
+  d24 = -d14;
+  d8 = d3 * d7 + d2 * d24;
+  d7 = d3 * d24 - d2 * d7;
+  HEAP32[i10 >> 2] = -1;
+  i25 = i12 + 4 | 0;
+  i22 = HEAP32[i25 >> 2] | 0;
+  i19 = HEAP32[i22 + 16 >> 2] | 0;
+  i22 = HEAP32[i22 + 20 >> 2] | 0;
+  if ((i22 | 0) > 1) {
+   i10 = 0;
+   d18 = d7 * +HEAPF32[i19 + 4 >> 2] + d8 * +HEAPF32[i19 >> 2];
+   i12 = 1;
+   while (1) {
+    d17 = d8 * +HEAPF32[i19 + (i12 << 3) >> 2] + d7 * +HEAPF32[i19 + (i12 << 3) + 4 >> 2];
+    i16 = d17 > d18;
+    i10 = i16 ? i12 : i10;
+    i12 = i12 + 1 | 0;
+    if ((i12 | 0) == (i22 | 0)) {
+     break;
+    } else {
+     d18 = i16 ? d17 : d18;
+    }
+   }
+   HEAP32[i9 >> 2] = i10;
+   if ((i10 | 0) > -1) {
+    i15 = i10;
+   } else {
+    ___assert_fail(3640, 3672, 103, 3704);
+   }
+  } else {
+   HEAP32[i9 >> 2] = 0;
+   i15 = 0;
+  }
+  i9 = HEAP32[i25 >> 2] | 0;
+  if ((HEAP32[i9 + 20 >> 2] | 0) <= (i15 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i27 = (HEAP32[i9 + 16 >> 2] | 0) + (i15 << 3) | 0;
+  d23 = +HEAPF32[i27 >> 2];
+  d24 = +HEAPF32[i27 + 4 >> 2];
+  d24 = d13 * (d4 + (d3 * d23 - d2 * d24) - d11) + d14 * (d5 + (d2 * d23 + d3 * d24) - d6);
+  STACKTOP = i1;
+  return +d24;
+ } else if ((i19 | 0) == 0) {
+  d13 = +HEAPF32[i12 + 92 >> 2];
+  d14 = +HEAPF32[i12 + 96 >> 2];
+  d21 = d6 * d13 + d7 * d14;
+  d24 = d6 * d14 - d7 * d13;
+  d17 = -d13;
+  d23 = -d14;
+  d18 = d3 * d17 + d2 * d23;
+  d17 = d3 * d23 - d2 * d17;
+  i15 = HEAP32[i12 >> 2] | 0;
+  i16 = HEAP32[i15 + 16 >> 2] | 0;
+  i15 = i15 + 20 | 0;
+  i19 = HEAP32[i15 >> 2] | 0;
+  if ((i19 | 0) > 1) {
+   i25 = 0;
+   d23 = d24 * +HEAPF32[i16 + 4 >> 2] + d21 * +HEAPF32[i16 >> 2];
+   i26 = 1;
+   while (1) {
+    d20 = d21 * +HEAPF32[i16 + (i26 << 3) >> 2] + d24 * +HEAPF32[i16 + (i26 << 3) + 4 >> 2];
+    i22 = d20 > d23;
+    i25 = i22 ? i26 : i25;
+    i26 = i26 + 1 | 0;
+    if ((i26 | 0) == (i19 | 0)) {
+     break;
+    } else {
+     d23 = i22 ? d20 : d23;
+    }
+   }
+  } else {
+   i25 = 0;
+  }
+  HEAP32[i10 >> 2] = i25;
+  i19 = HEAP32[i12 + 4 >> 2] | 0;
+  i12 = HEAP32[i19 + 16 >> 2] | 0;
+  i19 = i19 + 20 | 0;
+  i25 = HEAP32[i19 >> 2] | 0;
+  if ((i25 | 0) > 1) {
+   i27 = 0;
+   d20 = d17 * +HEAPF32[i12 + 4 >> 2] + d18 * +HEAPF32[i12 >> 2];
+   i26 = 1;
+   while (1) {
+    d21 = d18 * +HEAPF32[i12 + (i26 << 3) >> 2] + d17 * +HEAPF32[i12 + (i26 << 3) + 4 >> 2];
+    i22 = d21 > d20;
+    i27 = i22 ? i26 : i27;
+    i26 = i26 + 1 | 0;
+    if ((i26 | 0) == (i25 | 0)) {
+     break;
+    } else {
+     d20 = i22 ? d21 : d20;
+    }
+   }
+  } else {
+   i27 = 0;
+  }
+  HEAP32[i9 >> 2] = i27;
+  i9 = HEAP32[i10 >> 2] | 0;
+  if (!((i9 | 0) > -1)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  if ((HEAP32[i15 >> 2] | 0) <= (i9 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i26 = i16 + (i9 << 3) | 0;
+  d18 = +HEAPF32[i26 >> 2];
+  d17 = +HEAPF32[i26 + 4 >> 2];
+  if (!((i27 | 0) > -1)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  if ((HEAP32[i19 >> 2] | 0) <= (i27 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i27 = i12 + (i27 << 3) | 0;
+  d23 = +HEAPF32[i27 >> 2];
+  d24 = +HEAPF32[i27 + 4 >> 2];
+  d24 = d13 * (d4 + (d3 * d23 - d2 * d24) - (d11 + (d6 * d18 - d7 * d17))) + d14 * (d5 + (d2 * d23 + d3 * d24) - (d8 + (d7 * d18 + d6 * d17)));
+  STACKTOP = i1;
+  return +d24;
+ } else if ((i19 | 0) == 2) {
+  d23 = +HEAPF32[i12 + 92 >> 2];
+  d13 = +HEAPF32[i12 + 96 >> 2];
+  d14 = d3 * d23 - d2 * d13;
+  d13 = d2 * d23 + d3 * d13;
+  d23 = +HEAPF32[i12 + 84 >> 2];
+  d24 = +HEAPF32[i12 + 88 >> 2];
+  d4 = d4 + (d3 * d23 - d2 * d24);
+  d2 = d5 + (d2 * d23 + d3 * d24);
+  d3 = -d14;
+  d24 = -d13;
+  d5 = d6 * d3 + d7 * d24;
+  d3 = d6 * d24 - d7 * d3;
+  HEAP32[i9 >> 2] = -1;
+  i22 = HEAP32[i12 >> 2] | 0;
+  i15 = HEAP32[i22 + 16 >> 2] | 0;
+  i22 = HEAP32[i22 + 20 >> 2] | 0;
+  if ((i22 | 0) > 1) {
+   i9 = 0;
+   d17 = d3 * +HEAPF32[i15 + 4 >> 2] + d5 * +HEAPF32[i15 >> 2];
+   i19 = 1;
+   while (1) {
+    d18 = d5 * +HEAPF32[i15 + (i19 << 3) >> 2] + d3 * +HEAPF32[i15 + (i19 << 3) + 4 >> 2];
+    i25 = d18 > d17;
+    i9 = i25 ? i19 : i9;
+    i19 = i19 + 1 | 0;
+    if ((i19 | 0) == (i22 | 0)) {
+     break;
+    } else {
+     d17 = i25 ? d18 : d17;
+    }
+   }
+   HEAP32[i10 >> 2] = i9;
+   if ((i9 | 0) > -1) {
+    i16 = i9;
+   } else {
+    ___assert_fail(3640, 3672, 103, 3704);
+   }
+  } else {
+   HEAP32[i10 >> 2] = 0;
+   i16 = 0;
+  }
+  i9 = HEAP32[i12 >> 2] | 0;
+  if ((HEAP32[i9 + 20 >> 2] | 0) <= (i16 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i27 = (HEAP32[i9 + 16 >> 2] | 0) + (i16 << 3) | 0;
+  d23 = +HEAPF32[i27 >> 2];
+  d24 = +HEAPF32[i27 + 4 >> 2];
+  d24 = d14 * (d11 + (d6 * d23 - d7 * d24) - d4) + d13 * (d8 + (d7 * d23 + d6 * d24) - d2);
+  STACKTOP = i1;
+  return +d24;
+ } else {
+  ___assert_fail(3616, 3560, 183, 3720);
+ }
+ return 0.0;
+}
+function __ZN13b2DynamicTree10InsertLeafEi(i3, i4) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, d5 = 0.0, d6 = 0.0, d7 = 0.0, d8 = 0.0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, d13 = 0.0, d14 = 0.0, d15 = 0.0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, d21 = 0.0, d22 = 0.0, d23 = 0.0, i24 = 0;
+ i1 = STACKTOP;
+ i11 = i3 + 24 | 0;
+ HEAP32[i11 >> 2] = (HEAP32[i11 >> 2] | 0) + 1;
+ i11 = HEAP32[i3 >> 2] | 0;
+ if ((i11 | 0) == -1) {
+  HEAP32[i3 >> 2] = i4;
+  HEAP32[(HEAP32[i3 + 4 >> 2] | 0) + (i4 * 36 | 0) + 20 >> 2] = -1;
+  STACKTOP = i1;
+  return;
+ }
+ i2 = i3 + 4 | 0;
+ i9 = HEAP32[i2 >> 2] | 0;
+ d8 = +HEAPF32[i9 + (i4 * 36 | 0) >> 2];
+ d7 = +HEAPF32[i9 + (i4 * 36 | 0) + 4 >> 2];
+ d6 = +HEAPF32[i9 + (i4 * 36 | 0) + 8 >> 2];
+ d5 = +HEAPF32[i9 + (i4 * 36 | 0) + 12 >> 2];
+ i10 = HEAP32[i9 + (i11 * 36 | 0) + 24 >> 2] | 0;
+ L5 : do {
+  if (!((i10 | 0) == -1)) {
+   do {
+    i12 = HEAP32[i9 + (i11 * 36 | 0) + 28 >> 2] | 0;
+    d14 = +HEAPF32[i9 + (i11 * 36 | 0) + 8 >> 2];
+    d15 = +HEAPF32[i9 + (i11 * 36 | 0) >> 2];
+    d17 = +HEAPF32[i9 + (i11 * 36 | 0) + 12 >> 2];
+    d16 = +HEAPF32[i9 + (i11 * 36 | 0) + 4 >> 2];
+    d21 = ((d14 > d6 ? d14 : d6) - (d15 < d8 ? d15 : d8) + ((d17 > d5 ? d17 : d5) - (d16 < d7 ? d16 : d7))) * 2.0;
+    d13 = d21 * 2.0;
+    d14 = (d21 - (d14 - d15 + (d17 - d16)) * 2.0) * 2.0;
+    d21 = +HEAPF32[i9 + (i10 * 36 | 0) >> 2];
+    d16 = d8 < d21 ? d8 : d21;
+    d17 = +HEAPF32[i9 + (i10 * 36 | 0) + 4 >> 2];
+    d18 = d7 < d17 ? d7 : d17;
+    d19 = +HEAPF32[i9 + (i10 * 36 | 0) + 8 >> 2];
+    d20 = d6 > d19 ? d6 : d19;
+    d15 = +HEAPF32[i9 + (i10 * 36 | 0) + 12 >> 2];
+    d22 = d5 > d15 ? d5 : d15;
+    if ((HEAP32[i9 + (i10 * 36 | 0) + 24 >> 2] | 0) == -1) {
+     d15 = (d20 - d16 + (d22 - d18)) * 2.0;
+    } else {
+     d15 = (d20 - d16 + (d22 - d18)) * 2.0 - (d19 - d21 + (d15 - d17)) * 2.0;
+    }
+    d15 = d14 + d15;
+    d17 = +HEAPF32[i9 + (i12 * 36 | 0) >> 2];
+    d18 = d8 < d17 ? d8 : d17;
+    d23 = +HEAPF32[i9 + (i12 * 36 | 0) + 4 >> 2];
+    d22 = d7 < d23 ? d7 : d23;
+    d21 = +HEAPF32[i9 + (i12 * 36 | 0) + 8 >> 2];
+    d20 = d6 > d21 ? d6 : d21;
+    d19 = +HEAPF32[i9 + (i12 * 36 | 0) + 12 >> 2];
+    d16 = d5 > d19 ? d5 : d19;
+    if ((HEAP32[i9 + (i12 * 36 | 0) + 24 >> 2] | 0) == -1) {
+     d16 = (d20 - d18 + (d16 - d22)) * 2.0;
+    } else {
+     d16 = (d20 - d18 + (d16 - d22)) * 2.0 - (d21 - d17 + (d19 - d23)) * 2.0;
+    }
+    d14 = d14 + d16;
+    if (d13 < d15 & d13 < d14) {
+     break L5;
+    }
+    i11 = d15 < d14 ? i10 : i12;
+    i10 = HEAP32[i9 + (i11 * 36 | 0) + 24 >> 2] | 0;
+   } while (!((i10 | 0) == -1));
+  }
+ } while (0);
+ i9 = HEAP32[i9 + (i11 * 36 | 0) + 20 >> 2] | 0;
+ i10 = __ZN13b2DynamicTree12AllocateNodeEv(i3) | 0;
+ i12 = HEAP32[i2 >> 2] | 0;
+ HEAP32[i12 + (i10 * 36 | 0) + 20 >> 2] = i9;
+ HEAP32[i12 + (i10 * 36 | 0) + 16 >> 2] = 0;
+ i12 = HEAP32[i2 >> 2] | 0;
+ d14 = +HEAPF32[i12 + (i11 * 36 | 0) >> 2];
+ d13 = +HEAPF32[i12 + (i11 * 36 | 0) + 4 >> 2];
+ d8 = +(d8 < d14 ? d8 : d14);
+ d7 = +(d7 < d13 ? d7 : d13);
+ i24 = i12 + (i10 * 36 | 0) | 0;
+ HEAPF32[i24 >> 2] = d8;
+ HEAPF32[i24 + 4 >> 2] = d7;
+ d8 = +HEAPF32[i12 + (i11 * 36 | 0) + 8 >> 2];
+ d7 = +HEAPF32[i12 + (i11 * 36 | 0) + 12 >> 2];
+ d6 = +(d6 > d8 ? d6 : d8);
+ d23 = +(d5 > d7 ? d5 : d7);
+ i12 = i12 + (i10 * 36 | 0) + 8 | 0;
+ HEAPF32[i12 >> 2] = d6;
+ HEAPF32[i12 + 4 >> 2] = d23;
+ i12 = HEAP32[i2 >> 2] | 0;
+ HEAP32[i12 + (i10 * 36 | 0) + 32 >> 2] = (HEAP32[i12 + (i11 * 36 | 0) + 32 >> 2] | 0) + 1;
+ if ((i9 | 0) == -1) {
+  HEAP32[i12 + (i10 * 36 | 0) + 24 >> 2] = i11;
+  HEAP32[i12 + (i10 * 36 | 0) + 28 >> 2] = i4;
+  HEAP32[i12 + (i11 * 36 | 0) + 20 >> 2] = i10;
+  i24 = i12 + (i4 * 36 | 0) + 20 | 0;
+  HEAP32[i24 >> 2] = i10;
+  HEAP32[i3 >> 2] = i10;
+  i10 = HEAP32[i24 >> 2] | 0;
+ } else {
+  i24 = i12 + (i9 * 36 | 0) + 24 | 0;
+  if ((HEAP32[i24 >> 2] | 0) == (i11 | 0)) {
+   HEAP32[i24 >> 2] = i10;
+  } else {
+   HEAP32[i12 + (i9 * 36 | 0) + 28 >> 2] = i10;
+  }
+  HEAP32[i12 + (i10 * 36 | 0) + 24 >> 2] = i11;
+  HEAP32[i12 + (i10 * 36 | 0) + 28 >> 2] = i4;
+  HEAP32[i12 + (i11 * 36 | 0) + 20 >> 2] = i10;
+  HEAP32[i12 + (i4 * 36 | 0) + 20 >> 2] = i10;
+ }
+ if ((i10 | 0) == -1) {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i9 = __ZN13b2DynamicTree7BalanceEi(i3, i10) | 0;
+  i4 = HEAP32[i2 >> 2] | 0;
+  i11 = HEAP32[i4 + (i9 * 36 | 0) + 24 >> 2] | 0;
+  i10 = HEAP32[i4 + (i9 * 36 | 0) + 28 >> 2] | 0;
+  if ((i11 | 0) == -1) {
+   i2 = 20;
+   break;
+  }
+  if ((i10 | 0) == -1) {
+   i2 = 22;
+   break;
+  }
+  i12 = HEAP32[i4 + (i11 * 36 | 0) + 32 >> 2] | 0;
+  i24 = HEAP32[i4 + (i10 * 36 | 0) + 32 >> 2] | 0;
+  HEAP32[i4 + (i9 * 36 | 0) + 32 >> 2] = ((i12 | 0) > (i24 | 0) ? i12 : i24) + 1;
+  d7 = +HEAPF32[i4 + (i11 * 36 | 0) >> 2];
+  d8 = +HEAPF32[i4 + (i10 * 36 | 0) >> 2];
+  d5 = +HEAPF32[i4 + (i11 * 36 | 0) + 4 >> 2];
+  d6 = +HEAPF32[i4 + (i10 * 36 | 0) + 4 >> 2];
+  d7 = +(d7 < d8 ? d7 : d8);
+  d5 = +(d5 < d6 ? d5 : d6);
+  i24 = i4 + (i9 * 36 | 0) | 0;
+  HEAPF32[i24 >> 2] = d7;
+  HEAPF32[i24 + 4 >> 2] = d5;
+  d5 = +HEAPF32[i4 + (i11 * 36 | 0) + 8 >> 2];
+  d6 = +HEAPF32[i4 + (i10 * 36 | 0) + 8 >> 2];
+  d7 = +HEAPF32[i4 + (i11 * 36 | 0) + 12 >> 2];
+  d8 = +HEAPF32[i4 + (i10 * 36 | 0) + 12 >> 2];
+  d5 = +(d5 > d6 ? d5 : d6);
+  d23 = +(d7 > d8 ? d7 : d8);
+  i10 = i4 + (i9 * 36 | 0) + 8 | 0;
+  HEAPF32[i10 >> 2] = d5;
+  HEAPF32[i10 + 4 >> 2] = d23;
+  i10 = HEAP32[(HEAP32[i2 >> 2] | 0) + (i9 * 36 | 0) + 20 >> 2] | 0;
+  if ((i10 | 0) == -1) {
+   i2 = 24;
+   break;
+  }
+ }
+ if ((i2 | 0) == 20) {
+  ___assert_fail(3168, 2944, 307, 3184);
+ } else if ((i2 | 0) == 22) {
+  ___assert_fail(3200, 2944, 308, 3184);
+ } else if ((i2 | 0) == 24) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function __ZN15b2ContactSolverC2EP18b2ContactSolverDef(i7, i5) {
+ i7 = i7 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, d15 = 0.0, d16 = 0.0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0;
+ i1 = STACKTOP;
+ HEAP32[i7 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+ HEAP32[i7 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+ HEAP32[i7 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+ HEAP32[i7 + 12 >> 2] = HEAP32[i5 + 12 >> 2];
+ HEAP32[i7 + 16 >> 2] = HEAP32[i5 + 16 >> 2];
+ HEAP32[i7 + 20 >> 2] = HEAP32[i5 + 20 >> 2];
+ i14 = HEAP32[i5 + 40 >> 2] | 0;
+ i9 = i7 + 32 | 0;
+ HEAP32[i9 >> 2] = i14;
+ i2 = HEAP32[i5 + 28 >> 2] | 0;
+ i4 = i7 + 48 | 0;
+ HEAP32[i4 >> 2] = i2;
+ i3 = i7 + 36 | 0;
+ HEAP32[i3 >> 2] = __ZN16b2StackAllocator8AllocateEi(i14, i2 * 88 | 0) | 0;
+ i2 = i7 + 40 | 0;
+ HEAP32[i2 >> 2] = __ZN16b2StackAllocator8AllocateEi(HEAP32[i9 >> 2] | 0, (HEAP32[i4 >> 2] | 0) * 152 | 0) | 0;
+ HEAP32[i7 + 24 >> 2] = HEAP32[i5 + 32 >> 2];
+ HEAP32[i7 + 28 >> 2] = HEAP32[i5 + 36 >> 2];
+ i9 = HEAP32[i5 + 24 >> 2] | 0;
+ i5 = i7 + 44 | 0;
+ HEAP32[i5 >> 2] = i9;
+ if ((HEAP32[i4 >> 2] | 0) <= 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i6 = i7 + 20 | 0;
+ i7 = i7 + 8 | 0;
+ i8 = 0;
+ while (1) {
+  i10 = HEAP32[i9 + (i8 << 2) >> 2] | 0;
+  i11 = HEAP32[i10 + 48 >> 2] | 0;
+  i12 = HEAP32[i10 + 52 >> 2] | 0;
+  i14 = HEAP32[i11 + 8 >> 2] | 0;
+  i13 = HEAP32[i12 + 8 >> 2] | 0;
+  i9 = HEAP32[i10 + 124 >> 2] | 0;
+  if ((i9 | 0) <= 0) {
+   i2 = 4;
+   break;
+  }
+  d15 = +HEAPF32[(HEAP32[i12 + 12 >> 2] | 0) + 8 >> 2];
+  d16 = +HEAPF32[(HEAP32[i11 + 12 >> 2] | 0) + 8 >> 2];
+  i12 = HEAP32[i2 >> 2] | 0;
+  HEAPF32[i12 + (i8 * 152 | 0) + 136 >> 2] = +HEAPF32[i10 + 136 >> 2];
+  HEAPF32[i12 + (i8 * 152 | 0) + 140 >> 2] = +HEAPF32[i10 + 140 >> 2];
+  i22 = i14 + 8 | 0;
+  HEAP32[i12 + (i8 * 152 | 0) + 112 >> 2] = HEAP32[i22 >> 2];
+  i21 = i13 + 8 | 0;
+  HEAP32[i12 + (i8 * 152 | 0) + 116 >> 2] = HEAP32[i21 >> 2];
+  i19 = i14 + 120 | 0;
+  HEAPF32[i12 + (i8 * 152 | 0) + 120 >> 2] = +HEAPF32[i19 >> 2];
+  i20 = i13 + 120 | 0;
+  HEAPF32[i12 + (i8 * 152 | 0) + 124 >> 2] = +HEAPF32[i20 >> 2];
+  i18 = i14 + 128 | 0;
+  HEAPF32[i12 + (i8 * 152 | 0) + 128 >> 2] = +HEAPF32[i18 >> 2];
+  i17 = i13 + 128 | 0;
+  HEAPF32[i12 + (i8 * 152 | 0) + 132 >> 2] = +HEAPF32[i17 >> 2];
+  HEAP32[i12 + (i8 * 152 | 0) + 148 >> 2] = i8;
+  HEAP32[i12 + (i8 * 152 | 0) + 144 >> 2] = i9;
+  i11 = i12 + (i8 * 152 | 0) + 80 | 0;
+  HEAP32[i11 + 0 >> 2] = 0;
+  HEAP32[i11 + 4 >> 2] = 0;
+  HEAP32[i11 + 8 >> 2] = 0;
+  HEAP32[i11 + 12 >> 2] = 0;
+  HEAP32[i11 + 16 >> 2] = 0;
+  HEAP32[i11 + 20 >> 2] = 0;
+  HEAP32[i11 + 24 >> 2] = 0;
+  HEAP32[i11 + 28 >> 2] = 0;
+  i11 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i11 + (i8 * 88 | 0) + 32 >> 2] = HEAP32[i22 >> 2];
+  HEAP32[i11 + (i8 * 88 | 0) + 36 >> 2] = HEAP32[i21 >> 2];
+  HEAPF32[i11 + (i8 * 88 | 0) + 40 >> 2] = +HEAPF32[i19 >> 2];
+  HEAPF32[i11 + (i8 * 88 | 0) + 44 >> 2] = +HEAPF32[i20 >> 2];
+  i20 = i14 + 28 | 0;
+  i14 = HEAP32[i20 + 4 >> 2] | 0;
+  i19 = i11 + (i8 * 88 | 0) + 48 | 0;
+  HEAP32[i19 >> 2] = HEAP32[i20 >> 2];
+  HEAP32[i19 + 4 >> 2] = i14;
+  i19 = i13 + 28 | 0;
+  i14 = HEAP32[i19 + 4 >> 2] | 0;
+  i13 = i11 + (i8 * 88 | 0) + 56 | 0;
+  HEAP32[i13 >> 2] = HEAP32[i19 >> 2];
+  HEAP32[i13 + 4 >> 2] = i14;
+  HEAPF32[i11 + (i8 * 88 | 0) + 64 >> 2] = +HEAPF32[i18 >> 2];
+  HEAPF32[i11 + (i8 * 88 | 0) + 68 >> 2] = +HEAPF32[i17 >> 2];
+  i13 = i10 + 104 | 0;
+  i14 = HEAP32[i13 + 4 >> 2] | 0;
+  i17 = i11 + (i8 * 88 | 0) + 16 | 0;
+  HEAP32[i17 >> 2] = HEAP32[i13 >> 2];
+  HEAP32[i17 + 4 >> 2] = i14;
+  i17 = i10 + 112 | 0;
+  i14 = HEAP32[i17 + 4 >> 2] | 0;
+  i13 = i11 + (i8 * 88 | 0) + 24 | 0;
+  HEAP32[i13 >> 2] = HEAP32[i17 >> 2];
+  HEAP32[i13 + 4 >> 2] = i14;
+  HEAP32[i11 + (i8 * 88 | 0) + 84 >> 2] = i9;
+  HEAPF32[i11 + (i8 * 88 | 0) + 76 >> 2] = d16;
+  HEAPF32[i11 + (i8 * 88 | 0) + 80 >> 2] = d15;
+  HEAP32[i11 + (i8 * 88 | 0) + 72 >> 2] = HEAP32[i10 + 120 >> 2];
+  i13 = 0;
+  do {
+   i14 = i10 + (i13 * 20 | 0) + 64 | 0;
+   if ((HEAP8[i6] | 0) == 0) {
+    HEAPF32[i12 + (i8 * 152 | 0) + (i13 * 36 | 0) + 16 >> 2] = 0.0;
+    HEAPF32[i12 + (i8 * 152 | 0) + (i13 * 36 | 0) + 20 >> 2] = 0.0;
+   } else {
+    HEAPF32[i12 + (i8 * 152 | 0) + (i13 * 36 | 0) + 16 >> 2] = +HEAPF32[i7 >> 2] * +HEAPF32[i10 + (i13 * 20 | 0) + 72 >> 2];
+    HEAPF32[i12 + (i8 * 152 | 0) + (i13 * 36 | 0) + 20 >> 2] = +HEAPF32[i7 >> 2] * +HEAPF32[i10 + (i13 * 20 | 0) + 76 >> 2];
+   }
+   i20 = i12 + (i8 * 152 | 0) + (i13 * 36 | 0) | 0;
+   HEAPF32[i12 + (i8 * 152 | 0) + (i13 * 36 | 0) + 24 >> 2] = 0.0;
+   HEAPF32[i12 + (i8 * 152 | 0) + (i13 * 36 | 0) + 28 >> 2] = 0.0;
+   HEAPF32[i12 + (i8 * 152 | 0) + (i13 * 36 | 0) + 32 >> 2] = 0.0;
+   i22 = i11 + (i8 * 88 | 0) + (i13 << 3) | 0;
+   HEAP32[i20 + 0 >> 2] = 0;
+   HEAP32[i20 + 4 >> 2] = 0;
+   HEAP32[i20 + 8 >> 2] = 0;
+   HEAP32[i20 + 12 >> 2] = 0;
+   i20 = i14;
+   i21 = HEAP32[i20 + 4 >> 2] | 0;
+   HEAP32[i22 >> 2] = HEAP32[i20 >> 2];
+   HEAP32[i22 + 4 >> 2] = i21;
+   i13 = i13 + 1 | 0;
+  } while ((i13 | 0) != (i9 | 0));
+  i8 = i8 + 1 | 0;
+  if ((i8 | 0) >= (HEAP32[i4 >> 2] | 0)) {
+   i2 = 12;
+   break;
+  }
+  i9 = HEAP32[i5 >> 2] | 0;
+ }
+ if ((i2 | 0) == 4) {
+  ___assert_fail(6504, 6520, 71, 6568);
+ } else if ((i2 | 0) == 12) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function __Z25b2CollidePolygonAndCircleP10b2ManifoldPK14b2PolygonShapeRK11b2TransformPK13b2CircleShapeS6_(i1, i4, i11, i9, i10) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i11 = i11 | 0;
+ i9 = i9 | 0;
+ i10 = i10 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, d6 = 0.0, d7 = 0.0, d8 = 0.0, i12 = 0, d13 = 0.0, d14 = 0.0, i15 = 0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, d21 = 0.0, i22 = 0;
+ i3 = STACKTOP;
+ i5 = i1 + 60 | 0;
+ HEAP32[i5 >> 2] = 0;
+ i2 = i9 + 12 | 0;
+ d20 = +HEAPF32[i10 + 12 >> 2];
+ d7 = +HEAPF32[i2 >> 2];
+ d6 = +HEAPF32[i10 + 8 >> 2];
+ d21 = +HEAPF32[i9 + 16 >> 2];
+ d8 = +HEAPF32[i10 >> 2] + (d20 * d7 - d6 * d21) - +HEAPF32[i11 >> 2];
+ d21 = d7 * d6 + d20 * d21 + +HEAPF32[i10 + 4 >> 2] - +HEAPF32[i11 + 4 >> 2];
+ d20 = +HEAPF32[i11 + 12 >> 2];
+ d6 = +HEAPF32[i11 + 8 >> 2];
+ d7 = d8 * d20 + d21 * d6;
+ d6 = d20 * d21 - d8 * d6;
+ d8 = +HEAPF32[i4 + 8 >> 2] + +HEAPF32[i9 + 8 >> 2];
+ i12 = HEAP32[i4 + 148 >> 2] | 0;
+ do {
+  if ((i12 | 0) > 0) {
+   i10 = 0;
+   i9 = 0;
+   d13 = -3.4028234663852886e+38;
+   while (1) {
+    d14 = (d7 - +HEAPF32[i4 + (i10 << 3) + 20 >> 2]) * +HEAPF32[i4 + (i10 << 3) + 84 >> 2] + (d6 - +HEAPF32[i4 + (i10 << 3) + 24 >> 2]) * +HEAPF32[i4 + (i10 << 3) + 88 >> 2];
+    if (d14 > d8) {
+     i10 = 19;
+     break;
+    }
+    i11 = d14 > d13;
+    d13 = i11 ? d14 : d13;
+    i9 = i11 ? i10 : i9;
+    i10 = i10 + 1 | 0;
+    if ((i10 | 0) >= (i12 | 0)) {
+     i10 = 4;
+     break;
+    }
+   }
+   if ((i10 | 0) == 4) {
+    i22 = d13 < 1.1920928955078125e-7;
+    break;
+   } else if ((i10 | 0) == 19) {
+    STACKTOP = i3;
+    return;
+   }
+  } else {
+   i9 = 0;
+   i22 = 1;
+  }
+ } while (0);
+ i15 = i9 + 1 | 0;
+ i11 = i4 + (i9 << 3) + 20 | 0;
+ i10 = HEAP32[i11 >> 2] | 0;
+ i11 = HEAP32[i11 + 4 >> 2] | 0;
+ d14 = (HEAP32[tempDoublePtr >> 2] = i10, +HEAPF32[tempDoublePtr >> 2]);
+ d13 = (HEAP32[tempDoublePtr >> 2] = i11, +HEAPF32[tempDoublePtr >> 2]);
+ i12 = i4 + (((i15 | 0) < (i12 | 0) ? i15 : 0) << 3) + 20 | 0;
+ i15 = HEAP32[i12 >> 2] | 0;
+ i12 = HEAP32[i12 + 4 >> 2] | 0;
+ d21 = (HEAP32[tempDoublePtr >> 2] = i15, +HEAPF32[tempDoublePtr >> 2]);
+ d18 = (HEAP32[tempDoublePtr >> 2] = i12, +HEAPF32[tempDoublePtr >> 2]);
+ if (i22) {
+  HEAP32[i5 >> 2] = 1;
+  HEAP32[i1 + 56 >> 2] = 1;
+  i22 = i4 + (i9 << 3) + 84 | 0;
+  i15 = HEAP32[i22 + 4 >> 2] | 0;
+  i12 = i1 + 40 | 0;
+  HEAP32[i12 >> 2] = HEAP32[i22 >> 2];
+  HEAP32[i12 + 4 >> 2] = i15;
+  d20 = +((d14 + d21) * .5);
+  d21 = +((d13 + d18) * .5);
+  i12 = i1 + 48 | 0;
+  HEAPF32[i12 >> 2] = d20;
+  HEAPF32[i12 + 4 >> 2] = d21;
+  i12 = i2;
+  i15 = HEAP32[i12 + 4 >> 2] | 0;
+  i22 = i1;
+  HEAP32[i22 >> 2] = HEAP32[i12 >> 2];
+  HEAP32[i22 + 4 >> 2] = i15;
+  HEAP32[i1 + 16 >> 2] = 0;
+  STACKTOP = i3;
+  return;
+ }
+ d16 = d7 - d14;
+ d20 = d6 - d13;
+ d19 = d7 - d21;
+ d17 = d6 - d18;
+ if (d16 * (d21 - d14) + d20 * (d18 - d13) <= 0.0) {
+  if (d16 * d16 + d20 * d20 > d8 * d8) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i5 >> 2] = 1;
+  HEAP32[i1 + 56 >> 2] = 1;
+  i4 = i1 + 40 | 0;
+  d21 = +d16;
+  d6 = +d20;
+  i22 = i4;
+  HEAPF32[i22 >> 2] = d21;
+  HEAPF32[i22 + 4 >> 2] = d6;
+  d6 = +Math_sqrt(+(d16 * d16 + d20 * d20));
+  if (!(d6 < 1.1920928955078125e-7)) {
+   d21 = 1.0 / d6;
+   HEAPF32[i4 >> 2] = d16 * d21;
+   HEAPF32[i1 + 44 >> 2] = d20 * d21;
+  }
+  i12 = i1 + 48 | 0;
+  HEAP32[i12 >> 2] = i10;
+  HEAP32[i12 + 4 >> 2] = i11;
+  i12 = i2;
+  i15 = HEAP32[i12 + 4 >> 2] | 0;
+  i22 = i1;
+  HEAP32[i22 >> 2] = HEAP32[i12 >> 2];
+  HEAP32[i22 + 4 >> 2] = i15;
+  HEAP32[i1 + 16 >> 2] = 0;
+  STACKTOP = i3;
+  return;
+ }
+ if (!(d19 * (d14 - d21) + d17 * (d13 - d18) <= 0.0)) {
+  d14 = (d14 + d21) * .5;
+  d13 = (d13 + d18) * .5;
+  i10 = i4 + (i9 << 3) + 84 | 0;
+  if ((d7 - d14) * +HEAPF32[i10 >> 2] + (d6 - d13) * +HEAPF32[i4 + (i9 << 3) + 88 >> 2] > d8) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i5 >> 2] = 1;
+  HEAP32[i1 + 56 >> 2] = 1;
+  i22 = i10;
+  i15 = HEAP32[i22 + 4 >> 2] | 0;
+  i12 = i1 + 40 | 0;
+  HEAP32[i12 >> 2] = HEAP32[i22 >> 2];
+  HEAP32[i12 + 4 >> 2] = i15;
+  d20 = +d14;
+  d21 = +d13;
+  i12 = i1 + 48 | 0;
+  HEAPF32[i12 >> 2] = d20;
+  HEAPF32[i12 + 4 >> 2] = d21;
+  i12 = i2;
+  i15 = HEAP32[i12 + 4 >> 2] | 0;
+  i22 = i1;
+  HEAP32[i22 >> 2] = HEAP32[i12 >> 2];
+  HEAP32[i22 + 4 >> 2] = i15;
+  HEAP32[i1 + 16 >> 2] = 0;
+  STACKTOP = i3;
+  return;
+ }
+ if (d19 * d19 + d17 * d17 > d8 * d8) {
+  STACKTOP = i3;
+  return;
+ }
+ HEAP32[i5 >> 2] = 1;
+ HEAP32[i1 + 56 >> 2] = 1;
+ i4 = i1 + 40 | 0;
+ d21 = +d19;
+ d6 = +d17;
+ i22 = i4;
+ HEAPF32[i22 >> 2] = d21;
+ HEAPF32[i22 + 4 >> 2] = d6;
+ d6 = +Math_sqrt(+(d19 * d19 + d17 * d17));
+ if (!(d6 < 1.1920928955078125e-7)) {
+  d21 = 1.0 / d6;
+  HEAPF32[i4 >> 2] = d19 * d21;
+  HEAPF32[i1 + 44 >> 2] = d17 * d21;
+ }
+ i22 = i1 + 48 | 0;
+ HEAP32[i22 >> 2] = i15;
+ HEAP32[i22 + 4 >> 2] = i12;
+ i12 = i2;
+ i15 = HEAP32[i12 + 4 >> 2] | 0;
+ i22 = i1;
+ HEAP32[i22 >> 2] = HEAP32[i12 >> 2];
+ HEAP32[i22 + 4 >> 2] = i15;
+ HEAP32[i1 + 16 >> 2] = 0;
+ STACKTOP = i3;
+ return;
+}
+function __ZN15b2WorldManifold10InitializeEPK10b2ManifoldRK11b2TransformfS5_f(i1, i5, i7, d4, i8, d3) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i7 = i7 | 0;
+ d4 = +d4;
+ i8 = i8 | 0;
+ d3 = +d3;
+ var i2 = 0, i6 = 0, d9 = 0.0, d10 = 0.0, i11 = 0, i12 = 0, i13 = 0, d14 = 0.0, d15 = 0.0, i16 = 0, d17 = 0.0, d18 = 0.0, d19 = 0.0, i20 = 0, d21 = 0.0, d22 = 0.0;
+ i2 = STACKTOP;
+ i6 = i5 + 60 | 0;
+ if ((HEAP32[i6 >> 2] | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i11 = HEAP32[i5 + 56 >> 2] | 0;
+ if ((i11 | 0) == 2) {
+  i13 = i8 + 12 | 0;
+  d17 = +HEAPF32[i13 >> 2];
+  d18 = +HEAPF32[i5 + 40 >> 2];
+  i16 = i8 + 8 | 0;
+  d19 = +HEAPF32[i16 >> 2];
+  d15 = +HEAPF32[i5 + 44 >> 2];
+  d14 = d17 * d18 - d19 * d15;
+  d15 = d18 * d19 + d17 * d15;
+  d17 = +d14;
+  d19 = +d15;
+  i12 = i1;
+  HEAPF32[i12 >> 2] = d17;
+  HEAPF32[i12 + 4 >> 2] = d19;
+  d19 = +HEAPF32[i13 >> 2];
+  d17 = +HEAPF32[i5 + 48 >> 2];
+  d18 = +HEAPF32[i16 >> 2];
+  d10 = +HEAPF32[i5 + 52 >> 2];
+  d9 = +HEAPF32[i8 >> 2] + (d19 * d17 - d18 * d10);
+  d10 = d17 * d18 + d19 * d10 + +HEAPF32[i8 + 4 >> 2];
+  if ((HEAP32[i6 >> 2] | 0) > 0) {
+   i8 = i7 + 12 | 0;
+   i11 = i7 + 8 | 0;
+   i12 = i7 + 4 | 0;
+   i13 = i1 + 4 | 0;
+   i16 = 0;
+   do {
+    d18 = +HEAPF32[i8 >> 2];
+    d22 = +HEAPF32[i5 + (i16 * 20 | 0) >> 2];
+    d21 = +HEAPF32[i11 >> 2];
+    d17 = +HEAPF32[i5 + (i16 * 20 | 0) + 4 >> 2];
+    d19 = +HEAPF32[i7 >> 2] + (d18 * d22 - d21 * d17);
+    d17 = d22 * d21 + d18 * d17 + +HEAPF32[i12 >> 2];
+    d18 = d3 - (d14 * (d19 - d9) + (d17 - d10) * d15);
+    d19 = +((d19 - d14 * d4 + (d19 + d14 * d18)) * .5);
+    d14 = +((d17 - d15 * d4 + (d17 + d15 * d18)) * .5);
+    i20 = i1 + (i16 << 3) + 8 | 0;
+    HEAPF32[i20 >> 2] = d19;
+    HEAPF32[i20 + 4 >> 2] = d14;
+    i16 = i16 + 1 | 0;
+    d14 = +HEAPF32[i1 >> 2];
+    d15 = +HEAPF32[i13 >> 2];
+   } while ((i16 | 0) < (HEAP32[i6 >> 2] | 0));
+  }
+  d21 = +-d14;
+  d22 = +-d15;
+  i20 = i1;
+  HEAPF32[i20 >> 2] = d21;
+  HEAPF32[i20 + 4 >> 2] = d22;
+  STACKTOP = i2;
+  return;
+ } else if ((i11 | 0) == 1) {
+  i16 = i7 + 12 | 0;
+  d19 = +HEAPF32[i16 >> 2];
+  d21 = +HEAPF32[i5 + 40 >> 2];
+  i20 = i7 + 8 | 0;
+  d22 = +HEAPF32[i20 >> 2];
+  d15 = +HEAPF32[i5 + 44 >> 2];
+  d14 = d19 * d21 - d22 * d15;
+  d15 = d21 * d22 + d19 * d15;
+  d19 = +d14;
+  d22 = +d15;
+  i13 = i1;
+  HEAPF32[i13 >> 2] = d19;
+  HEAPF32[i13 + 4 >> 2] = d22;
+  d22 = +HEAPF32[i16 >> 2];
+  d19 = +HEAPF32[i5 + 48 >> 2];
+  d21 = +HEAPF32[i20 >> 2];
+  d10 = +HEAPF32[i5 + 52 >> 2];
+  d9 = +HEAPF32[i7 >> 2] + (d22 * d19 - d21 * d10);
+  d10 = d19 * d21 + d22 * d10 + +HEAPF32[i7 + 4 >> 2];
+  if ((HEAP32[i6 >> 2] | 0) <= 0) {
+   STACKTOP = i2;
+   return;
+  }
+  i12 = i8 + 12 | 0;
+  i11 = i8 + 8 | 0;
+  i7 = i8 + 4 | 0;
+  i13 = i1 + 4 | 0;
+  i16 = 0;
+  while (1) {
+   d22 = +HEAPF32[i12 >> 2];
+   d17 = +HEAPF32[i5 + (i16 * 20 | 0) >> 2];
+   d18 = +HEAPF32[i11 >> 2];
+   d19 = +HEAPF32[i5 + (i16 * 20 | 0) + 4 >> 2];
+   d21 = +HEAPF32[i8 >> 2] + (d22 * d17 - d18 * d19);
+   d19 = d17 * d18 + d22 * d19 + +HEAPF32[i7 >> 2];
+   d22 = d4 - (d14 * (d21 - d9) + (d19 - d10) * d15);
+   d21 = +((d21 - d14 * d3 + (d21 + d14 * d22)) * .5);
+   d22 = +((d19 - d15 * d3 + (d19 + d15 * d22)) * .5);
+   i20 = i1 + (i16 << 3) + 8 | 0;
+   HEAPF32[i20 >> 2] = d21;
+   HEAPF32[i20 + 4 >> 2] = d22;
+   i16 = i16 + 1 | 0;
+   if ((i16 | 0) >= (HEAP32[i6 >> 2] | 0)) {
+    break;
+   }
+   d14 = +HEAPF32[i1 >> 2];
+   d15 = +HEAPF32[i13 >> 2];
+  }
+  STACKTOP = i2;
+  return;
+ } else if ((i11 | 0) == 0) {
+  HEAPF32[i1 >> 2] = 1.0;
+  i6 = i1 + 4 | 0;
+  HEAPF32[i6 >> 2] = 0.0;
+  d21 = +HEAPF32[i7 + 12 >> 2];
+  d22 = +HEAPF32[i5 + 48 >> 2];
+  d19 = +HEAPF32[i7 + 8 >> 2];
+  d10 = +HEAPF32[i5 + 52 >> 2];
+  d9 = +HEAPF32[i7 >> 2] + (d21 * d22 - d19 * d10);
+  d10 = d22 * d19 + d21 * d10 + +HEAPF32[i7 + 4 >> 2];
+  d21 = +HEAPF32[i8 + 12 >> 2];
+  d19 = +HEAPF32[i5 >> 2];
+  d22 = +HEAPF32[i8 + 8 >> 2];
+  d15 = +HEAPF32[i5 + 4 >> 2];
+  d14 = +HEAPF32[i8 >> 2] + (d21 * d19 - d22 * d15);
+  d15 = d19 * d22 + d21 * d15 + +HEAPF32[i8 + 4 >> 2];
+  d21 = d9 - d14;
+  d22 = d10 - d15;
+  if (d21 * d21 + d22 * d22 > 1.4210854715202004e-14) {
+   d19 = d14 - d9;
+   d17 = d15 - d10;
+   d22 = +d19;
+   d18 = +d17;
+   i20 = i1;
+   HEAPF32[i20 >> 2] = d22;
+   HEAPF32[i20 + 4 >> 2] = d18;
+   d18 = +Math_sqrt(+(d19 * d19 + d17 * d17));
+   if (!(d18 < 1.1920928955078125e-7)) {
+    d22 = 1.0 / d18;
+    d19 = d19 * d22;
+    HEAPF32[i1 >> 2] = d19;
+    d17 = d17 * d22;
+    HEAPF32[i6 >> 2] = d17;
+   }
+  } else {
+   d19 = 1.0;
+   d17 = 0.0;
+  }
+  d21 = +((d9 + d19 * d4 + (d14 - d19 * d3)) * .5);
+  d22 = +((d10 + d17 * d4 + (d15 - d17 * d3)) * .5);
+  i20 = i1 + 8 | 0;
+  HEAPF32[i20 >> 2] = d21;
+  HEAPF32[i20 + 4 >> 2] = d22;
+  STACKTOP = i2;
+  return;
+ } else {
+  STACKTOP = i2;
+  return;
+ }
+}
+function _main(i3, i2) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i4 = 0, i5 = 0, d6 = 0.0, d7 = 0.0, i8 = 0, i9 = 0, d10 = 0.0, d11 = 0.0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, d22 = 0.0, d23 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 240 | 0;
+ i5 = i1;
+ i12 = i1 + 224 | 0;
+ i4 = i1 + 168 | 0;
+ i9 = i1 + 160 | 0;
+ i8 = i1 + 152 | 0;
+ L1 : do {
+  if ((i3 | 0) > 1) {
+   i14 = HEAP8[HEAP32[i2 + 4 >> 2] | 0] | 0;
+   switch (i14 | 0) {
+   case 49:
+    {
+     HEAP32[2] = 5;
+     HEAP32[4] = 35;
+     i15 = 35;
+     i14 = 5;
+     break L1;
+    }
+   case 50:
+    {
+     HEAP32[2] = 32;
+     HEAP32[4] = 161;
+     i15 = 161;
+     i14 = 32;
+     break L1;
+    }
+   case 51:
+    {
+     i13 = 5;
+     break L1;
+    }
+   case 52:
+    {
+     HEAP32[2] = 320;
+     HEAP32[4] = 2331;
+     i15 = 2331;
+     i14 = 320;
+     break L1;
+    }
+   case 53:
+    {
+     HEAP32[2] = 640;
+     HEAP32[4] = 5661;
+     i15 = 5661;
+     i14 = 640;
+     break L1;
+    }
+   case 48:
+    {
+     i20 = 0;
+     STACKTOP = i1;
+     return i20 | 0;
+    }
+   default:
+    {
+     HEAP32[i5 >> 2] = i14 + -48;
+     _printf(80, i5 | 0) | 0;
+     i20 = -1;
+     STACKTOP = i1;
+     return i20 | 0;
+    }
+   }
+  } else {
+   i13 = 5;
+  }
+ } while (0);
+ if ((i13 | 0) == 5) {
+  HEAP32[2] = 64;
+  HEAP32[4] = 333;
+  i15 = 333;
+  i14 = 64;
+ }
+ i13 = i15 + i14 | 0;
+ HEAP32[4] = i13;
+ HEAP32[2] = 0;
+ HEAP32[8] = __Znaj(i13 >>> 0 > 1073741823 ? -1 : i13 << 2) | 0;
+ HEAPF32[i12 >> 2] = 0.0;
+ HEAPF32[i12 + 4 >> 2] = -10.0;
+ i15 = __Znwj(103028) | 0;
+ __ZN7b2WorldC2ERK6b2Vec2(i15, i12);
+ HEAP32[6] = i15;
+ __ZN7b2World16SetAllowSleepingEb(i15, 0);
+ HEAP32[i5 + 44 >> 2] = 0;
+ i15 = i5 + 4 | 0;
+ i14 = i5 + 36 | 0;
+ HEAP32[i15 + 0 >> 2] = 0;
+ HEAP32[i15 + 4 >> 2] = 0;
+ HEAP32[i15 + 8 >> 2] = 0;
+ HEAP32[i15 + 12 >> 2] = 0;
+ HEAP32[i15 + 16 >> 2] = 0;
+ HEAP32[i15 + 20 >> 2] = 0;
+ HEAP32[i15 + 24 >> 2] = 0;
+ HEAP32[i15 + 28 >> 2] = 0;
+ HEAP8[i14] = 1;
+ HEAP8[i5 + 37 | 0] = 1;
+ HEAP8[i5 + 38 | 0] = 0;
+ HEAP8[i5 + 39 | 0] = 0;
+ HEAP32[i5 >> 2] = 0;
+ HEAP8[i5 + 40 | 0] = 1;
+ HEAPF32[i5 + 48 >> 2] = 1.0;
+ i14 = __ZN7b2World10CreateBodyEPK9b2BodyDef(HEAP32[6] | 0, i5) | 0;
+ HEAP32[i4 >> 2] = 240;
+ HEAP32[i4 + 4 >> 2] = 1;
+ HEAPF32[i4 + 8 >> 2] = .009999999776482582;
+ i15 = i4 + 28 | 0;
+ HEAP32[i15 + 0 >> 2] = 0;
+ HEAP32[i15 + 4 >> 2] = 0;
+ HEAP32[i15 + 8 >> 2] = 0;
+ HEAP32[i15 + 12 >> 2] = 0;
+ HEAP16[i15 + 16 >> 1] = 0;
+ HEAPF32[i9 >> 2] = -40.0;
+ HEAPF32[i9 + 4 >> 2] = 0.0;
+ HEAPF32[i8 >> 2] = 40.0;
+ HEAPF32[i8 + 4 >> 2] = 0.0;
+ __ZN11b2EdgeShape3SetERK6b2Vec2S2_(i4, i9, i8);
+ __ZN6b2Body13CreateFixtureEPK7b2Shapef(i14, i4, 0.0) | 0;
+ HEAP32[i5 >> 2] = 504;
+ HEAP32[i5 + 4 >> 2] = 2;
+ HEAPF32[i5 + 8 >> 2] = .009999999776482582;
+ HEAP32[i5 + 148 >> 2] = 0;
+ HEAPF32[i5 + 12 >> 2] = 0.0;
+ HEAPF32[i5 + 16 >> 2] = 0.0;
+ __ZN14b2PolygonShape8SetAsBoxEff(i5, .5, .5);
+ i14 = i4 + 44 | 0;
+ i15 = i4 + 4 | 0;
+ i8 = i4 + 36 | 0;
+ i17 = i4 + 37 | 0;
+ i18 = i4 + 38 | 0;
+ i19 = i4 + 39 | 0;
+ i20 = i4 + 40 | 0;
+ i13 = i4 + 48 | 0;
+ i12 = i4 + 4 | 0;
+ d11 = -7.0;
+ d10 = .75;
+ i9 = 0;
+ while (1) {
+  d7 = d11;
+  d6 = d10;
+  i16 = i9;
+  while (1) {
+   HEAP32[i14 >> 2] = 0;
+   HEAP32[i15 + 0 >> 2] = 0;
+   HEAP32[i15 + 4 >> 2] = 0;
+   HEAP32[i15 + 8 >> 2] = 0;
+   HEAP32[i15 + 12 >> 2] = 0;
+   HEAP32[i15 + 16 >> 2] = 0;
+   HEAP32[i15 + 20 >> 2] = 0;
+   HEAP32[i15 + 24 >> 2] = 0;
+   HEAP32[i15 + 28 >> 2] = 0;
+   HEAP8[i8] = 1;
+   HEAP8[i17] = 1;
+   HEAP8[i18] = 0;
+   HEAP8[i19] = 0;
+   HEAP8[i20] = 1;
+   HEAPF32[i13 >> 2] = 1.0;
+   HEAP32[i4 >> 2] = 2;
+   d23 = +d7;
+   d22 = +d6;
+   i21 = i12;
+   HEAPF32[i21 >> 2] = d23;
+   HEAPF32[i21 + 4 >> 2] = d22;
+   i21 = __ZN7b2World10CreateBodyEPK9b2BodyDef(HEAP32[6] | 0, i4) | 0;
+   __ZN6b2Body13CreateFixtureEPK7b2Shapef(i21, i5, 5.0) | 0;
+   HEAP32[14] = i21;
+   i16 = i16 + 1 | 0;
+   if ((i16 | 0) >= 40) {
+    break;
+   } else {
+    d7 = d7 + 1.125;
+    d6 = d6 + 0.0;
+   }
+  }
+  i9 = i9 + 1 | 0;
+  if ((i9 | 0) >= 40) {
+   break;
+  } else {
+   d11 = d11 + .5625;
+   d10 = d10 + 1.0;
+  }
+ }
+ if ((HEAP32[2] | 0) > 0) {
+  i4 = 0;
+  do {
+   __ZN7b2World4StepEfii(HEAP32[6] | 0, .01666666753590107, 3, 3);
+   i4 = i4 + 1 | 0;
+  } while ((i4 | 0) < (HEAP32[2] | 0));
+ }
+ if ((i3 | 0) > 2) {
+  i21 = (HEAP8[HEAP32[i2 + 8 >> 2] | 0] | 0) + -48 | 0;
+  HEAP32[18] = i21;
+  if ((i21 | 0) != 0) {
+   _puts(208) | 0;
+   _emscripten_set_main_loop(2, 60, 1);
+   i21 = 0;
+   STACKTOP = i1;
+   return i21 | 0;
+  }
+ } else {
+  HEAP32[18] = 0;
+ }
+ while (1) {
+  __Z4iterv();
+  if ((HEAP32[16] | 0) > (HEAP32[4] | 0)) {
+   i2 = 0;
+   break;
+  }
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function __ZN9b2Simplex9ReadCacheEPK14b2SimplexCachePK15b2DistanceProxyRK11b2TransformS5_S8_(i2, i11, i10, i4, i3, i5) {
+ i2 = i2 | 0;
+ i11 = i11 | 0;
+ i10 = i10 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i6 = 0, i7 = 0, d8 = 0.0, i9 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, d24 = 0.0, d25 = 0.0, i26 = 0, d27 = 0.0, d28 = 0.0, d29 = 0.0, d30 = 0.0, d31 = 0.0, d32 = 0.0;
+ i1 = STACKTOP;
+ i13 = HEAP16[i11 + 4 >> 1] | 0;
+ if (!((i13 & 65535) < 4)) {
+  ___assert_fail(2872, 2672, 102, 2896);
+ }
+ i12 = i13 & 65535;
+ i6 = i2 + 108 | 0;
+ HEAP32[i6 >> 2] = i12;
+ L4 : do {
+  if (!(i13 << 16 >> 16 == 0)) {
+   i17 = i10 + 20 | 0;
+   i21 = i10 + 16 | 0;
+   i13 = i3 + 20 | 0;
+   i14 = i3 + 16 | 0;
+   i15 = i4 + 12 | 0;
+   i16 = i4 + 8 | 0;
+   i12 = i4 + 4 | 0;
+   i18 = i5 + 12 | 0;
+   i19 = i5 + 8 | 0;
+   i20 = i5 + 4 | 0;
+   i22 = 0;
+   while (1) {
+    i26 = HEAPU8[i11 + i22 + 6 | 0] | 0;
+    HEAP32[i2 + (i22 * 36 | 0) + 28 >> 2] = i26;
+    i23 = HEAPU8[i11 + i22 + 9 | 0] | 0;
+    HEAP32[i2 + (i22 * 36 | 0) + 32 >> 2] = i23;
+    if ((HEAP32[i17 >> 2] | 0) <= (i26 | 0)) {
+     i9 = 6;
+     break;
+    }
+    i26 = (HEAP32[i21 >> 2] | 0) + (i26 << 3) | 0;
+    d25 = +HEAPF32[i26 >> 2];
+    d24 = +HEAPF32[i26 + 4 >> 2];
+    if ((HEAP32[i13 >> 2] | 0) <= (i23 | 0)) {
+     i9 = 8;
+     break;
+    }
+    i23 = (HEAP32[i14 >> 2] | 0) + (i23 << 3) | 0;
+    d29 = +HEAPF32[i23 >> 2];
+    d31 = +HEAPF32[i23 + 4 >> 2];
+    d32 = +HEAPF32[i15 >> 2];
+    d30 = +HEAPF32[i16 >> 2];
+    d27 = +HEAPF32[i4 >> 2] + (d25 * d32 - d24 * d30);
+    d28 = +d27;
+    d30 = +(d24 * d32 + d25 * d30 + +HEAPF32[i12 >> 2]);
+    i23 = i2 + (i22 * 36 | 0) | 0;
+    HEAPF32[i23 >> 2] = d28;
+    HEAPF32[i23 + 4 >> 2] = d30;
+    d30 = +HEAPF32[i18 >> 2];
+    d25 = +HEAPF32[i19 >> 2];
+    d24 = +HEAPF32[i5 >> 2] + (d29 * d30 - d31 * d25);
+    d28 = +d24;
+    d25 = +(d31 * d30 + d29 * d25 + +HEAPF32[i20 >> 2]);
+    i23 = i2 + (i22 * 36 | 0) + 8 | 0;
+    HEAPF32[i23 >> 2] = d28;
+    HEAPF32[i23 + 4 >> 2] = d25;
+    d24 = +(d24 - d27);
+    d25 = +(+HEAPF32[i2 + (i22 * 36 | 0) + 12 >> 2] - +HEAPF32[i2 + (i22 * 36 | 0) + 4 >> 2]);
+    i23 = i2 + (i22 * 36 | 0) + 16 | 0;
+    HEAPF32[i23 >> 2] = d24;
+    HEAPF32[i23 + 4 >> 2] = d25;
+    HEAPF32[i2 + (i22 * 36 | 0) + 24 >> 2] = 0.0;
+    i22 = i22 + 1 | 0;
+    i23 = HEAP32[i6 >> 2] | 0;
+    if ((i22 | 0) >= (i23 | 0)) {
+     i7 = i23;
+     break L4;
+    }
+   }
+   if ((i9 | 0) == 6) {
+    ___assert_fail(2776, 2808, 103, 2840);
+   } else if ((i9 | 0) == 8) {
+    ___assert_fail(2776, 2808, 103, 2840);
+   }
+  } else {
+   i7 = i12;
+  }
+ } while (0);
+ do {
+  if ((i7 | 0) > 1) {
+   d24 = +HEAPF32[i11 >> 2];
+   if ((i7 | 0) == 2) {
+    d32 = +HEAPF32[i2 + 16 >> 2] - +HEAPF32[i2 + 52 >> 2];
+    d8 = +HEAPF32[i2 + 20 >> 2] - +HEAPF32[i2 + 56 >> 2];
+    d8 = +Math_sqrt(+(d32 * d32 + d8 * d8));
+   } else if ((i7 | 0) == 3) {
+    d8 = +HEAPF32[i2 + 16 >> 2];
+    d32 = +HEAPF32[i2 + 20 >> 2];
+    d8 = (+HEAPF32[i2 + 52 >> 2] - d8) * (+HEAPF32[i2 + 92 >> 2] - d32) - (+HEAPF32[i2 + 56 >> 2] - d32) * (+HEAPF32[i2 + 88 >> 2] - d8);
+   } else {
+    ___assert_fail(2712, 2672, 259, 2736);
+   }
+   if (!(d8 < d24 * .5) ? !(d24 * 2.0 < d8 | d8 < 1.1920928955078125e-7) : 0) {
+    i9 = 18;
+    break;
+   }
+   HEAP32[i6 >> 2] = 0;
+  } else {
+   i9 = 18;
+  }
+ } while (0);
+ if ((i9 | 0) == 18 ? (i7 | 0) != 0 : 0) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP32[i2 + 28 >> 2] = 0;
+ HEAP32[i2 + 32 >> 2] = 0;
+ if ((HEAP32[i10 + 20 >> 2] | 0) <= 0) {
+  ___assert_fail(2776, 2808, 103, 2840);
+ }
+ i26 = HEAP32[i10 + 16 >> 2] | 0;
+ d8 = +HEAPF32[i26 >> 2];
+ d24 = +HEAPF32[i26 + 4 >> 2];
+ if ((HEAP32[i3 + 20 >> 2] | 0) <= 0) {
+  ___assert_fail(2776, 2808, 103, 2840);
+ }
+ i26 = HEAP32[i3 + 16 >> 2] | 0;
+ d27 = +HEAPF32[i26 >> 2];
+ d25 = +HEAPF32[i26 + 4 >> 2];
+ d30 = +HEAPF32[i4 + 12 >> 2];
+ d32 = +HEAPF32[i4 + 8 >> 2];
+ d31 = +HEAPF32[i4 >> 2] + (d8 * d30 - d24 * d32);
+ d32 = d24 * d30 + d8 * d32 + +HEAPF32[i4 + 4 >> 2];
+ d30 = +d31;
+ d28 = +d32;
+ i26 = i2;
+ HEAPF32[i26 >> 2] = d30;
+ HEAPF32[i26 + 4 >> 2] = d28;
+ d28 = +HEAPF32[i5 + 12 >> 2];
+ d30 = +HEAPF32[i5 + 8 >> 2];
+ d29 = +HEAPF32[i5 >> 2] + (d27 * d28 - d25 * d30);
+ d30 = d25 * d28 + d27 * d30 + +HEAPF32[i5 + 4 >> 2];
+ d27 = +d29;
+ d28 = +d30;
+ i26 = i2 + 8 | 0;
+ HEAPF32[i26 >> 2] = d27;
+ HEAPF32[i26 + 4 >> 2] = d28;
+ d31 = +(d29 - d31);
+ d32 = +(d30 - d32);
+ i26 = i2 + 16 | 0;
+ HEAPF32[i26 >> 2] = d31;
+ HEAPF32[i26 + 4 >> 2] = d32;
+ HEAP32[i6 >> 2] = 1;
+ STACKTOP = i1;
+ return;
+}
+function __ZNSt3__17__sort4IRPFbRK6b2PairS3_EPS1_EEjT0_S8_S8_S8_T_(i6, i7, i5, i4, i1) {
+ i6 = i6 | 0;
+ i7 = i7 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i9 = FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i7, i6) | 0;
+ i8 = FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i7) | 0;
+ do {
+  if (i9) {
+   if (i8) {
+    HEAP32[i3 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+    HEAP32[i6 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+    HEAP32[i6 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+    HEAP32[i6 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+    HEAP32[i5 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+    HEAP32[i5 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+    HEAP32[i5 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+    i8 = 1;
+    break;
+   }
+   HEAP32[i3 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+   HEAP32[i3 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+   HEAP32[i3 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   HEAP32[i6 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i6 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i6 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+   if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i7) | 0) {
+    HEAP32[i3 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    HEAP32[i7 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+    HEAP32[i5 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+    HEAP32[i5 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+    HEAP32[i5 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+    i8 = 2;
+   } else {
+    i8 = 1;
+   }
+  } else {
+   if (i8) {
+    HEAP32[i3 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    HEAP32[i7 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+    HEAP32[i5 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+    HEAP32[i5 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+    HEAP32[i5 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+    if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i7, i6) | 0) {
+     HEAP32[i3 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+     HEAP32[i3 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+     HEAP32[i3 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+     HEAP32[i6 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+     HEAP32[i6 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+     HEAP32[i6 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+     HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+     HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+     HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+     i8 = 2;
+    } else {
+     i8 = 1;
+    }
+   } else {
+    i8 = 0;
+   }
+  }
+ } while (0);
+ if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i5) | 0)) {
+  i9 = i8;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ HEAP32[i3 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+ HEAP32[i3 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+ HEAP32[i3 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+ HEAP32[i5 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+ HEAP32[i5 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+ HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+ HEAP32[i4 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+ HEAP32[i4 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+ HEAP32[i4 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+ if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i7) | 0)) {
+  i9 = i8 + 1 | 0;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ HEAP32[i3 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+ HEAP32[i3 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+ HEAP32[i3 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+ HEAP32[i7 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+ HEAP32[i7 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+ HEAP32[i7 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+ HEAP32[i5 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+ HEAP32[i5 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+ HEAP32[i5 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+ if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i7, i6) | 0)) {
+  i9 = i8 + 2 | 0;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ HEAP32[i3 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+ HEAP32[i3 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+ HEAP32[i3 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+ HEAP32[i6 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+ HEAP32[i6 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+ HEAP32[i6 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+ HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+ HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+ HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+ i9 = i8 + 3 | 0;
+ STACKTOP = i2;
+ return i9 | 0;
+}
+function __ZN15b2ContactSolver27SolveTOIPositionConstraintsEii(i9, i2, i5) {
+ i9 = i9 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, d21 = 0.0, d22 = 0.0, d23 = 0.0, d24 = 0.0, d25 = 0.0, d26 = 0.0, d27 = 0.0, d28 = 0.0, d29 = 0.0, d30 = 0.0, d31 = 0.0, d32 = 0.0, d33 = 0.0, d34 = 0.0, d35 = 0.0, d36 = 0.0, i37 = 0, d38 = 0.0, d39 = 0.0, d40 = 0.0, d41 = 0.0, d42 = 0.0, d43 = 0.0, d44 = 0.0, d45 = 0.0, i46 = 0, d47 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i8 = i1 + 40 | 0;
+ i3 = i1 + 24 | 0;
+ i4 = i1;
+ i6 = i9 + 48 | 0;
+ if ((HEAP32[i6 >> 2] | 0) <= 0) {
+  d45 = 0.0;
+  i37 = d45 >= -.007499999832361937;
+  STACKTOP = i1;
+  return i37 | 0;
+ }
+ i7 = i9 + 36 | 0;
+ i14 = i9 + 24 | 0;
+ i9 = i8 + 8 | 0;
+ i15 = i8 + 12 | 0;
+ i10 = i3 + 8 | 0;
+ i11 = i3 + 12 | 0;
+ i12 = i4 + 8 | 0;
+ i13 = i4 + 16 | 0;
+ i16 = 0;
+ d34 = 0.0;
+ do {
+  i37 = HEAP32[i7 >> 2] | 0;
+  i19 = i37 + (i16 * 88 | 0) | 0;
+  i17 = HEAP32[i37 + (i16 * 88 | 0) + 32 >> 2] | 0;
+  i18 = HEAP32[i37 + (i16 * 88 | 0) + 36 >> 2] | 0;
+  i20 = i37 + (i16 * 88 | 0) + 48 | 0;
+  d21 = +HEAPF32[i20 >> 2];
+  d22 = +HEAPF32[i20 + 4 >> 2];
+  i20 = i37 + (i16 * 88 | 0) + 56 | 0;
+  d23 = +HEAPF32[i20 >> 2];
+  d24 = +HEAPF32[i20 + 4 >> 2];
+  i20 = HEAP32[i37 + (i16 * 88 | 0) + 84 >> 2] | 0;
+  if ((i17 | 0) == (i2 | 0) | (i17 | 0) == (i5 | 0)) {
+   d26 = +HEAPF32[i37 + (i16 * 88 | 0) + 64 >> 2];
+   d27 = +HEAPF32[i37 + (i16 * 88 | 0) + 40 >> 2];
+  } else {
+   d26 = 0.0;
+   d27 = 0.0;
+  }
+  d25 = +HEAPF32[i37 + (i16 * 88 | 0) + 44 >> 2];
+  d28 = +HEAPF32[i37 + (i16 * 88 | 0) + 68 >> 2];
+  i37 = HEAP32[i14 >> 2] | 0;
+  i46 = i37 + (i17 * 12 | 0) | 0;
+  d33 = +HEAPF32[i46 >> 2];
+  d35 = +HEAPF32[i46 + 4 >> 2];
+  d29 = +HEAPF32[i37 + (i17 * 12 | 0) + 8 >> 2];
+  i46 = i37 + (i18 * 12 | 0) | 0;
+  d32 = +HEAPF32[i46 >> 2];
+  d36 = +HEAPF32[i46 + 4 >> 2];
+  d31 = +HEAPF32[i37 + (i18 * 12 | 0) + 8 >> 2];
+  if ((i20 | 0) > 0) {
+   d30 = d27 + d25;
+   i37 = 0;
+   do {
+    d38 = +Math_sin(+d29);
+    HEAPF32[i9 >> 2] = d38;
+    d44 = +Math_cos(+d29);
+    HEAPF32[i15 >> 2] = d44;
+    d43 = +Math_sin(+d31);
+    HEAPF32[i10 >> 2] = d43;
+    d41 = +Math_cos(+d31);
+    HEAPF32[i11 >> 2] = d41;
+    d40 = +(d33 - (d21 * d44 - d22 * d38));
+    d38 = +(d35 - (d22 * d44 + d21 * d38));
+    i46 = i8;
+    HEAPF32[i46 >> 2] = d40;
+    HEAPF32[i46 + 4 >> 2] = d38;
+    d38 = +(d32 - (d23 * d41 - d24 * d43));
+    d43 = +(d36 - (d24 * d41 + d23 * d43));
+    i46 = i3;
+    HEAPF32[i46 >> 2] = d38;
+    HEAPF32[i46 + 4 >> 2] = d43;
+    __ZN24b2PositionSolverManifold10InitializeEP27b2ContactPositionConstraintRK11b2TransformS4_i(i4, i19, i8, i3, i37);
+    i46 = i4;
+    d43 = +HEAPF32[i46 >> 2];
+    d38 = +HEAPF32[i46 + 4 >> 2];
+    i46 = i12;
+    d41 = +HEAPF32[i46 >> 2];
+    d40 = +HEAPF32[i46 + 4 >> 2];
+    d44 = +HEAPF32[i13 >> 2];
+    d39 = d41 - d33;
+    d42 = d40 - d35;
+    d41 = d41 - d32;
+    d40 = d40 - d36;
+    d34 = d34 < d44 ? d34 : d44;
+    d44 = (d44 + .004999999888241291) * .75;
+    d44 = d44 < 0.0 ? d44 : 0.0;
+    d45 = d38 * d39 - d43 * d42;
+    d47 = d38 * d41 - d43 * d40;
+    d45 = d47 * d28 * d47 + (d30 + d45 * d26 * d45);
+    if (d45 > 0.0) {
+     d44 = -(d44 < -.20000000298023224 ? -.20000000298023224 : d44) / d45;
+    } else {
+     d44 = 0.0;
+    }
+    d47 = d43 * d44;
+    d45 = d38 * d44;
+    d33 = d33 - d27 * d47;
+    d35 = d35 - d27 * d45;
+    d29 = d29 - d26 * (d39 * d45 - d42 * d47);
+    d32 = d32 + d25 * d47;
+    d36 = d36 + d25 * d45;
+    d31 = d31 + d28 * (d41 * d45 - d40 * d47);
+    i37 = i37 + 1 | 0;
+   } while ((i37 | 0) != (i20 | 0));
+   i37 = HEAP32[i14 >> 2] | 0;
+  }
+  d47 = +d33;
+  d45 = +d35;
+  i46 = i37 + (i17 * 12 | 0) | 0;
+  HEAPF32[i46 >> 2] = d47;
+  HEAPF32[i46 + 4 >> 2] = d45;
+  i46 = HEAP32[i14 >> 2] | 0;
+  HEAPF32[i46 + (i17 * 12 | 0) + 8 >> 2] = d29;
+  d45 = +d32;
+  d47 = +d36;
+  i46 = i46 + (i18 * 12 | 0) | 0;
+  HEAPF32[i46 >> 2] = d45;
+  HEAPF32[i46 + 4 >> 2] = d47;
+  HEAPF32[(HEAP32[i14 >> 2] | 0) + (i18 * 12 | 0) + 8 >> 2] = d31;
+  i16 = i16 + 1 | 0;
+ } while ((i16 | 0) < (HEAP32[i6 >> 2] | 0));
+ i46 = d34 >= -.007499999832361937;
+ STACKTOP = i1;
+ return i46 | 0;
+}
+function __ZN15b2ContactSolver24SolvePositionConstraintsEv(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, i21 = 0, d22 = 0.0, d23 = 0.0, d24 = 0.0, d25 = 0.0, i26 = 0, d27 = 0.0, d28 = 0.0, d29 = 0.0, d30 = 0.0, d31 = 0.0, d32 = 0.0, d33 = 0.0, d34 = 0.0, i35 = 0, d36 = 0.0, d37 = 0.0, d38 = 0.0, d39 = 0.0, d40 = 0.0, d41 = 0.0, d42 = 0.0, d43 = 0.0, i44 = 0, d45 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i4 = i1 + 40 | 0;
+ i5 = i1 + 24 | 0;
+ i3 = i1;
+ i2 = i7 + 48 | 0;
+ if ((HEAP32[i2 >> 2] | 0) <= 0) {
+  d43 = 0.0;
+  i35 = d43 >= -.014999999664723873;
+  STACKTOP = i1;
+  return i35 | 0;
+ }
+ i6 = i7 + 36 | 0;
+ i9 = i7 + 24 | 0;
+ i13 = i4 + 8 | 0;
+ i7 = i4 + 12 | 0;
+ i8 = i5 + 8 | 0;
+ i12 = i5 + 12 | 0;
+ i10 = i3 + 8 | 0;
+ i11 = i3 + 16 | 0;
+ i35 = HEAP32[i9 >> 2] | 0;
+ i15 = 0;
+ d32 = 0.0;
+ do {
+  i21 = HEAP32[i6 >> 2] | 0;
+  i26 = i21 + (i15 * 88 | 0) | 0;
+  i16 = HEAP32[i21 + (i15 * 88 | 0) + 32 >> 2] | 0;
+  i14 = HEAP32[i21 + (i15 * 88 | 0) + 36 >> 2] | 0;
+  i44 = i21 + (i15 * 88 | 0) + 48 | 0;
+  d22 = +HEAPF32[i44 >> 2];
+  d23 = +HEAPF32[i44 + 4 >> 2];
+  d25 = +HEAPF32[i21 + (i15 * 88 | 0) + 40 >> 2];
+  d18 = +HEAPF32[i21 + (i15 * 88 | 0) + 64 >> 2];
+  i44 = i21 + (i15 * 88 | 0) + 56 | 0;
+  d24 = +HEAPF32[i44 >> 2];
+  d19 = +HEAPF32[i44 + 4 >> 2];
+  d17 = +HEAPF32[i21 + (i15 * 88 | 0) + 44 >> 2];
+  d20 = +HEAPF32[i21 + (i15 * 88 | 0) + 68 >> 2];
+  i21 = HEAP32[i21 + (i15 * 88 | 0) + 84 >> 2] | 0;
+  i44 = i35 + (i16 * 12 | 0) | 0;
+  d28 = +HEAPF32[i44 >> 2];
+  d33 = +HEAPF32[i44 + 4 >> 2];
+  d29 = +HEAPF32[i35 + (i16 * 12 | 0) + 8 >> 2];
+  i44 = i35 + (i14 * 12 | 0) | 0;
+  d30 = +HEAPF32[i44 >> 2];
+  d34 = +HEAPF32[i44 + 4 >> 2];
+  d31 = +HEAPF32[i35 + (i14 * 12 | 0) + 8 >> 2];
+  if ((i21 | 0) > 0) {
+   d27 = d25 + d17;
+   i35 = 0;
+   do {
+    d41 = +Math_sin(+d29);
+    HEAPF32[i13 >> 2] = d41;
+    d42 = +Math_cos(+d29);
+    HEAPF32[i7 >> 2] = d42;
+    d39 = +Math_sin(+d31);
+    HEAPF32[i8 >> 2] = d39;
+    d38 = +Math_cos(+d31);
+    HEAPF32[i12 >> 2] = d38;
+    d40 = +(d28 - (d22 * d42 - d23 * d41));
+    d41 = +(d33 - (d23 * d42 + d22 * d41));
+    i44 = i4;
+    HEAPF32[i44 >> 2] = d40;
+    HEAPF32[i44 + 4 >> 2] = d41;
+    d41 = +(d30 - (d24 * d38 - d19 * d39));
+    d39 = +(d34 - (d19 * d38 + d24 * d39));
+    i44 = i5;
+    HEAPF32[i44 >> 2] = d41;
+    HEAPF32[i44 + 4 >> 2] = d39;
+    __ZN24b2PositionSolverManifold10InitializeEP27b2ContactPositionConstraintRK11b2TransformS4_i(i3, i26, i4, i5, i35);
+    i44 = i3;
+    d39 = +HEAPF32[i44 >> 2];
+    d41 = +HEAPF32[i44 + 4 >> 2];
+    i44 = i10;
+    d38 = +HEAPF32[i44 >> 2];
+    d40 = +HEAPF32[i44 + 4 >> 2];
+    d42 = +HEAPF32[i11 >> 2];
+    d36 = d38 - d28;
+    d37 = d40 - d33;
+    d38 = d38 - d30;
+    d40 = d40 - d34;
+    d32 = d32 < d42 ? d32 : d42;
+    d42 = (d42 + .004999999888241291) * .20000000298023224;
+    d43 = d42 < 0.0 ? d42 : 0.0;
+    d42 = d41 * d36 - d39 * d37;
+    d45 = d41 * d38 - d39 * d40;
+    d42 = d45 * d20 * d45 + (d27 + d42 * d18 * d42);
+    if (d42 > 0.0) {
+     d42 = -(d43 < -.20000000298023224 ? -.20000000298023224 : d43) / d42;
+    } else {
+     d42 = 0.0;
+    }
+    d45 = d39 * d42;
+    d43 = d41 * d42;
+    d28 = d28 - d25 * d45;
+    d33 = d33 - d25 * d43;
+    d29 = d29 - d18 * (d36 * d43 - d37 * d45);
+    d30 = d30 + d17 * d45;
+    d34 = d34 + d17 * d43;
+    d31 = d31 + d20 * (d38 * d43 - d40 * d45);
+    i35 = i35 + 1 | 0;
+   } while ((i35 | 0) != (i21 | 0));
+   i35 = HEAP32[i9 >> 2] | 0;
+  }
+  d45 = +d28;
+  d43 = +d33;
+  i35 = i35 + (i16 * 12 | 0) | 0;
+  HEAPF32[i35 >> 2] = d45;
+  HEAPF32[i35 + 4 >> 2] = d43;
+  i35 = HEAP32[i9 >> 2] | 0;
+  HEAPF32[i35 + (i16 * 12 | 0) + 8 >> 2] = d29;
+  d43 = +d30;
+  d45 = +d34;
+  i35 = i35 + (i14 * 12 | 0) | 0;
+  HEAPF32[i35 >> 2] = d43;
+  HEAPF32[i35 + 4 >> 2] = d45;
+  i35 = HEAP32[i9 >> 2] | 0;
+  HEAPF32[i35 + (i14 * 12 | 0) + 8 >> 2] = d31;
+  i15 = i15 + 1 | 0;
+ } while ((i15 | 0) < (HEAP32[i2 >> 2] | 0));
+ i44 = d32 >= -.014999999664723873;
+ STACKTOP = i1;
+ return i44 | 0;
+}
+function __Z22b2CollideEdgeAndCircleP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK13b2CircleShapeS6_(i1, i7, i6, i22, i5) {
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ i6 = i6 | 0;
+ i22 = i22 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, d12 = 0.0, d13 = 0.0, i14 = 0, i15 = 0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, d21 = 0.0, d23 = 0.0, d24 = 0.0;
+ i4 = STACKTOP;
+ i2 = i1 + 60 | 0;
+ HEAP32[i2 >> 2] = 0;
+ i3 = i22 + 12 | 0;
+ d9 = +HEAPF32[i5 + 12 >> 2];
+ d23 = +HEAPF32[i3 >> 2];
+ d17 = +HEAPF32[i5 + 8 >> 2];
+ d18 = +HEAPF32[i22 + 16 >> 2];
+ d21 = +HEAPF32[i5 >> 2] + (d9 * d23 - d17 * d18) - +HEAPF32[i6 >> 2];
+ d18 = d23 * d17 + d9 * d18 + +HEAPF32[i5 + 4 >> 2] - +HEAPF32[i6 + 4 >> 2];
+ d9 = +HEAPF32[i6 + 12 >> 2];
+ d17 = +HEAPF32[i6 + 8 >> 2];
+ d23 = d21 * d9 + d18 * d17;
+ d17 = d9 * d18 - d21 * d17;
+ i6 = i7 + 12 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ i6 = HEAP32[i6 + 4 >> 2] | 0;
+ d21 = (HEAP32[tempDoublePtr >> 2] = i5, +HEAPF32[tempDoublePtr >> 2]);
+ d18 = (HEAP32[tempDoublePtr >> 2] = i6, +HEAPF32[tempDoublePtr >> 2]);
+ i15 = i7 + 20 | 0;
+ i14 = HEAP32[i15 >> 2] | 0;
+ i15 = HEAP32[i15 + 4 >> 2] | 0;
+ d9 = (HEAP32[tempDoublePtr >> 2] = i14, +HEAPF32[tempDoublePtr >> 2]);
+ d10 = (HEAP32[tempDoublePtr >> 2] = i15, +HEAPF32[tempDoublePtr >> 2]);
+ d8 = d9 - d21;
+ d16 = d10 - d18;
+ d19 = d8 * (d9 - d23) + d16 * (d10 - d17);
+ d13 = d23 - d21;
+ d12 = d17 - d18;
+ d20 = d13 * d8 + d12 * d16;
+ d11 = +HEAPF32[i7 + 8 >> 2] + +HEAPF32[i22 + 8 >> 2];
+ if (d20 <= 0.0) {
+  if (d13 * d13 + d12 * d12 > d11 * d11) {
+   STACKTOP = i4;
+   return;
+  }
+  if ((HEAP8[i7 + 44 | 0] | 0) != 0 ? (i22 = i7 + 28 | 0, d24 = +HEAPF32[i22 >> 2], (d21 - d23) * (d21 - d24) + (d18 - d17) * (d18 - +HEAPF32[i22 + 4 >> 2]) > 0.0) : 0) {
+   STACKTOP = i4;
+   return;
+  }
+  HEAP32[i2 >> 2] = 1;
+  HEAP32[i1 + 56 >> 2] = 0;
+  HEAPF32[i1 + 40 >> 2] = 0.0;
+  HEAPF32[i1 + 44 >> 2] = 0.0;
+  i14 = i1 + 48 | 0;
+  HEAP32[i14 >> 2] = i5;
+  HEAP32[i14 + 4 >> 2] = i6;
+  i14 = i1 + 16 | 0;
+  HEAP32[i14 >> 2] = 0;
+  HEAP8[i14] = 0;
+  HEAP8[i14 + 1 | 0] = 0;
+  HEAP8[i14 + 2 | 0] = 0;
+  HEAP8[i14 + 3 | 0] = 0;
+  i14 = i3;
+  i15 = HEAP32[i14 + 4 >> 2] | 0;
+  i22 = i1;
+  HEAP32[i22 >> 2] = HEAP32[i14 >> 2];
+  HEAP32[i22 + 4 >> 2] = i15;
+  STACKTOP = i4;
+  return;
+ }
+ if (d19 <= 0.0) {
+  d8 = d23 - d9;
+  d12 = d17 - d10;
+  if (d8 * d8 + d12 * d12 > d11 * d11) {
+   STACKTOP = i4;
+   return;
+  }
+  if ((HEAP8[i7 + 45 | 0] | 0) != 0 ? (i22 = i7 + 36 | 0, d24 = +HEAPF32[i22 >> 2], d8 * (d24 - d9) + d12 * (+HEAPF32[i22 + 4 >> 2] - d10) > 0.0) : 0) {
+   STACKTOP = i4;
+   return;
+  }
+  HEAP32[i2 >> 2] = 1;
+  HEAP32[i1 + 56 >> 2] = 0;
+  HEAPF32[i1 + 40 >> 2] = 0.0;
+  HEAPF32[i1 + 44 >> 2] = 0.0;
+  i22 = i1 + 48 | 0;
+  HEAP32[i22 >> 2] = i14;
+  HEAP32[i22 + 4 >> 2] = i15;
+  i14 = i1 + 16 | 0;
+  HEAP32[i14 >> 2] = 0;
+  HEAP8[i14] = 1;
+  HEAP8[i14 + 1 | 0] = 0;
+  HEAP8[i14 + 2 | 0] = 0;
+  HEAP8[i14 + 3 | 0] = 0;
+  i14 = i3;
+  i15 = HEAP32[i14 + 4 >> 2] | 0;
+  i22 = i1;
+  HEAP32[i22 >> 2] = HEAP32[i14 >> 2];
+  HEAP32[i22 + 4 >> 2] = i15;
+  STACKTOP = i4;
+  return;
+ }
+ d24 = d8 * d8 + d16 * d16;
+ if (!(d24 > 0.0)) {
+  ___assert_fail(5560, 5576, 127, 5616);
+ }
+ d24 = 1.0 / d24;
+ d23 = d23 - (d21 * d19 + d9 * d20) * d24;
+ d24 = d17 - (d18 * d19 + d10 * d20) * d24;
+ if (d23 * d23 + d24 * d24 > d11 * d11) {
+  STACKTOP = i4;
+  return;
+ }
+ d9 = -d16;
+ if (d8 * d12 + d13 * d9 < 0.0) {
+  d8 = -d8;
+ } else {
+  d16 = d9;
+ }
+ d9 = +Math_sqrt(+(d8 * d8 + d16 * d16));
+ if (!(d9 < 1.1920928955078125e-7)) {
+  d24 = 1.0 / d9;
+  d16 = d16 * d24;
+  d8 = d8 * d24;
+ }
+ HEAP32[i2 >> 2] = 1;
+ HEAP32[i1 + 56 >> 2] = 1;
+ d23 = +d16;
+ d24 = +d8;
+ i14 = i1 + 40 | 0;
+ HEAPF32[i14 >> 2] = d23;
+ HEAPF32[i14 + 4 >> 2] = d24;
+ i14 = i1 + 48 | 0;
+ HEAP32[i14 >> 2] = i5;
+ HEAP32[i14 + 4 >> 2] = i6;
+ i14 = i1 + 16 | 0;
+ HEAP32[i14 >> 2] = 0;
+ HEAP8[i14] = 0;
+ HEAP8[i14 + 1 | 0] = 0;
+ HEAP8[i14 + 2 | 0] = 1;
+ HEAP8[i14 + 3 | 0] = 0;
+ i14 = i3;
+ i15 = HEAP32[i14 + 4 >> 2] | 0;
+ i22 = i1;
+ HEAP32[i22 >> 2] = HEAP32[i14 >> 2];
+ HEAP32[i22 + 4 >> 2] = i15;
+ STACKTOP = i4;
+ return;
+}
+function __ZN6b2BodyC2EPK9b2BodyDefP7b2World(i1, i2, i5) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, d13 = 0.0;
+ i3 = STACKTOP;
+ i9 = i2 + 4 | 0;
+ d13 = +HEAPF32[i9 >> 2];
+ if (!(d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf)) {
+  ___assert_fail(1496, 1520, 27, 1552);
+ }
+ d13 = +HEAPF32[i2 + 8 >> 2];
+ if (!(d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf)) {
+  ___assert_fail(1496, 1520, 27, 1552);
+ }
+ i6 = i2 + 16 | 0;
+ d13 = +HEAPF32[i6 >> 2];
+ if (!(d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf)) {
+  ___assert_fail(1560, 1520, 28, 1552);
+ }
+ d13 = +HEAPF32[i2 + 20 >> 2];
+ if (!(d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf)) {
+  ___assert_fail(1560, 1520, 28, 1552);
+ }
+ i7 = i2 + 12 | 0;
+ d13 = +HEAPF32[i7 >> 2];
+ if (!(d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf)) {
+  ___assert_fail(1592, 1520, 29, 1552);
+ }
+ i8 = i2 + 24 | 0;
+ d13 = +HEAPF32[i8 >> 2];
+ if (!(d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf)) {
+  ___assert_fail(1616, 1520, 30, 1552);
+ }
+ i4 = i2 + 32 | 0;
+ d13 = +HEAPF32[i4 >> 2];
+ if (!(d13 >= 0.0) | d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf ^ 1) {
+  ___assert_fail(1648, 1520, 31, 1552);
+ }
+ i10 = i2 + 28 | 0;
+ d13 = +HEAPF32[i10 >> 2];
+ if (!(d13 >= 0.0) | d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf ^ 1) {
+  ___assert_fail(1712, 1520, 32, 1552);
+ }
+ i11 = i1 + 4 | 0;
+ i12 = (HEAP8[i2 + 39 | 0] | 0) == 0 ? 0 : 8;
+ HEAP16[i11 >> 1] = i12;
+ if ((HEAP8[i2 + 38 | 0] | 0) != 0) {
+  i12 = (i12 & 65535 | 16) & 65535;
+  HEAP16[i11 >> 1] = i12;
+ }
+ if ((HEAP8[i2 + 36 | 0] | 0) != 0) {
+  i12 = (i12 & 65535 | 4) & 65535;
+  HEAP16[i11 >> 1] = i12;
+ }
+ if ((HEAP8[i2 + 37 | 0] | 0) != 0) {
+  i12 = (i12 & 65535 | 2) & 65535;
+  HEAP16[i11 >> 1] = i12;
+ }
+ if ((HEAP8[i2 + 40 | 0] | 0) != 0) {
+  HEAP16[i11 >> 1] = i12 & 65535 | 32;
+ }
+ HEAP32[i1 + 88 >> 2] = i5;
+ i11 = i9;
+ i12 = HEAP32[i11 >> 2] | 0;
+ i11 = HEAP32[i11 + 4 >> 2] | 0;
+ i9 = i1 + 12 | 0;
+ HEAP32[i9 >> 2] = i12;
+ HEAP32[i9 + 4 >> 2] = i11;
+ d13 = +HEAPF32[i7 >> 2];
+ HEAPF32[i1 + 20 >> 2] = +Math_sin(+d13);
+ HEAPF32[i1 + 24 >> 2] = +Math_cos(+d13);
+ HEAPF32[i1 + 28 >> 2] = 0.0;
+ HEAPF32[i1 + 32 >> 2] = 0.0;
+ i9 = i1 + 36 | 0;
+ HEAP32[i9 >> 2] = i12;
+ HEAP32[i9 + 4 >> 2] = i11;
+ i9 = i1 + 44 | 0;
+ HEAP32[i9 >> 2] = i12;
+ HEAP32[i9 + 4 >> 2] = i11;
+ HEAPF32[i1 + 52 >> 2] = +HEAPF32[i7 >> 2];
+ HEAPF32[i1 + 56 >> 2] = +HEAPF32[i7 >> 2];
+ HEAPF32[i1 + 60 >> 2] = 0.0;
+ HEAP32[i1 + 108 >> 2] = 0;
+ HEAP32[i1 + 112 >> 2] = 0;
+ HEAP32[i1 + 92 >> 2] = 0;
+ HEAP32[i1 + 96 >> 2] = 0;
+ i9 = i6;
+ i11 = HEAP32[i9 + 4 >> 2] | 0;
+ i12 = i1 + 64 | 0;
+ HEAP32[i12 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i12 + 4 >> 2] = i11;
+ HEAPF32[i1 + 72 >> 2] = +HEAPF32[i8 >> 2];
+ HEAPF32[i1 + 132 >> 2] = +HEAPF32[i10 >> 2];
+ HEAPF32[i1 + 136 >> 2] = +HEAPF32[i4 >> 2];
+ HEAPF32[i1 + 140 >> 2] = +HEAPF32[i2 + 48 >> 2];
+ HEAPF32[i1 + 76 >> 2] = 0.0;
+ HEAPF32[i1 + 80 >> 2] = 0.0;
+ HEAPF32[i1 + 84 >> 2] = 0.0;
+ HEAPF32[i1 + 144 >> 2] = 0.0;
+ i12 = HEAP32[i2 >> 2] | 0;
+ HEAP32[i1 >> 2] = i12;
+ i4 = i1 + 116 | 0;
+ if ((i12 | 0) == 2) {
+  HEAPF32[i4 >> 2] = 1.0;
+  HEAPF32[i1 + 120 >> 2] = 1.0;
+  i11 = i1 + 124 | 0;
+  HEAPF32[i11 >> 2] = 0.0;
+  i11 = i1 + 128 | 0;
+  HEAPF32[i11 >> 2] = 0.0;
+  i11 = i2 + 44 | 0;
+  i11 = HEAP32[i11 >> 2] | 0;
+  i12 = i1 + 148 | 0;
+  HEAP32[i12 >> 2] = i11;
+  i12 = i1 + 100 | 0;
+  HEAP32[i12 >> 2] = 0;
+  i12 = i1 + 104 | 0;
+  HEAP32[i12 >> 2] = 0;
+  STACKTOP = i3;
+  return;
+ } else {
+  HEAPF32[i4 >> 2] = 0.0;
+  HEAPF32[i1 + 120 >> 2] = 0.0;
+  i11 = i1 + 124 | 0;
+  HEAPF32[i11 >> 2] = 0.0;
+  i11 = i1 + 128 | 0;
+  HEAPF32[i11 >> 2] = 0.0;
+  i11 = i2 + 44 | 0;
+  i11 = HEAP32[i11 >> 2] | 0;
+  i12 = i1 + 148 | 0;
+  HEAP32[i12 >> 2] = i11;
+  i12 = i1 + 100 | 0;
+  HEAP32[i12 >> 2] = 0;
+  i12 = i1 + 104 | 0;
+  HEAP32[i12 >> 2] = 0;
+  STACKTOP = i3;
+  return;
+ }
+}
+function __ZN24b2PositionSolverManifold10InitializeEP27b2ContactPositionConstraintRK11b2TransformS4_i(i2, i1, i13, i12, i15) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ i13 = i13 | 0;
+ i12 = i12 | 0;
+ i15 = i15 | 0;
+ var i3 = 0, d4 = 0.0, d5 = 0.0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, i14 = 0, d16 = 0.0, d17 = 0.0, d18 = 0.0, i19 = 0, i20 = 0;
+ i3 = STACKTOP;
+ if ((HEAP32[i1 + 84 >> 2] | 0) <= 0) {
+  ___assert_fail(6752, 6520, 617, 6776);
+ }
+ i14 = HEAP32[i1 + 72 >> 2] | 0;
+ if ((i14 | 0) == 1) {
+  i19 = i13 + 12 | 0;
+  d5 = +HEAPF32[i19 >> 2];
+  d6 = +HEAPF32[i1 + 16 >> 2];
+  i14 = i13 + 8 | 0;
+  d7 = +HEAPF32[i14 >> 2];
+  d9 = +HEAPF32[i1 + 20 >> 2];
+  d4 = d5 * d6 - d7 * d9;
+  d9 = d6 * d7 + d5 * d9;
+  d5 = +d4;
+  d7 = +d9;
+  i20 = i2;
+  HEAPF32[i20 >> 2] = d5;
+  HEAPF32[i20 + 4 >> 2] = d7;
+  d7 = +HEAPF32[i19 >> 2];
+  d5 = +HEAPF32[i1 + 24 >> 2];
+  d6 = +HEAPF32[i14 >> 2];
+  d8 = +HEAPF32[i1 + 28 >> 2];
+  d16 = +HEAPF32[i12 + 12 >> 2];
+  d18 = +HEAPF32[i1 + (i15 << 3) >> 2];
+  d17 = +HEAPF32[i12 + 8 >> 2];
+  d11 = +HEAPF32[i1 + (i15 << 3) + 4 >> 2];
+  d10 = +HEAPF32[i12 >> 2] + (d16 * d18 - d17 * d11);
+  d11 = d18 * d17 + d16 * d11 + +HEAPF32[i12 + 4 >> 2];
+  HEAPF32[i2 + 16 >> 2] = d4 * (d10 - (+HEAPF32[i13 >> 2] + (d7 * d5 - d6 * d8))) + (d11 - (d5 * d6 + d7 * d8 + +HEAPF32[i13 + 4 >> 2])) * d9 - +HEAPF32[i1 + 76 >> 2] - +HEAPF32[i1 + 80 >> 2];
+  d10 = +d10;
+  d11 = +d11;
+  i15 = i2 + 8 | 0;
+  HEAPF32[i15 >> 2] = d10;
+  HEAPF32[i15 + 4 >> 2] = d11;
+  STACKTOP = i3;
+  return;
+ } else if ((i14 | 0) == 2) {
+  i19 = i12 + 12 | 0;
+  d7 = +HEAPF32[i19 >> 2];
+  d8 = +HEAPF32[i1 + 16 >> 2];
+  i20 = i12 + 8 | 0;
+  d9 = +HEAPF32[i20 >> 2];
+  d18 = +HEAPF32[i1 + 20 >> 2];
+  d17 = d7 * d8 - d9 * d18;
+  d18 = d8 * d9 + d7 * d18;
+  d7 = +d17;
+  d9 = +d18;
+  i14 = i2;
+  HEAPF32[i14 >> 2] = d7;
+  HEAPF32[i14 + 4 >> 2] = d9;
+  d9 = +HEAPF32[i19 >> 2];
+  d7 = +HEAPF32[i1 + 24 >> 2];
+  d8 = +HEAPF32[i20 >> 2];
+  d10 = +HEAPF32[i1 + 28 >> 2];
+  d6 = +HEAPF32[i13 + 12 >> 2];
+  d4 = +HEAPF32[i1 + (i15 << 3) >> 2];
+  d5 = +HEAPF32[i13 + 8 >> 2];
+  d16 = +HEAPF32[i1 + (i15 << 3) + 4 >> 2];
+  d11 = +HEAPF32[i13 >> 2] + (d6 * d4 - d5 * d16);
+  d16 = d4 * d5 + d6 * d16 + +HEAPF32[i13 + 4 >> 2];
+  HEAPF32[i2 + 16 >> 2] = d17 * (d11 - (+HEAPF32[i12 >> 2] + (d9 * d7 - d8 * d10))) + (d16 - (d7 * d8 + d9 * d10 + +HEAPF32[i12 + 4 >> 2])) * d18 - +HEAPF32[i1 + 76 >> 2] - +HEAPF32[i1 + 80 >> 2];
+  d11 = +d11;
+  d16 = +d16;
+  i20 = i2 + 8 | 0;
+  HEAPF32[i20 >> 2] = d11;
+  HEAPF32[i20 + 4 >> 2] = d16;
+  d17 = +-d17;
+  d18 = +-d18;
+  i20 = i2;
+  HEAPF32[i20 >> 2] = d17;
+  HEAPF32[i20 + 4 >> 2] = d18;
+  STACKTOP = i3;
+  return;
+ } else if ((i14 | 0) == 0) {
+  d7 = +HEAPF32[i13 + 12 >> 2];
+  d8 = +HEAPF32[i1 + 24 >> 2];
+  d18 = +HEAPF32[i13 + 8 >> 2];
+  d6 = +HEAPF32[i1 + 28 >> 2];
+  d4 = +HEAPF32[i13 >> 2] + (d7 * d8 - d18 * d6);
+  d6 = d8 * d18 + d7 * d6 + +HEAPF32[i13 + 4 >> 2];
+  d7 = +HEAPF32[i12 + 12 >> 2];
+  d18 = +HEAPF32[i1 >> 2];
+  d8 = +HEAPF32[i12 + 8 >> 2];
+  d9 = +HEAPF32[i1 + 4 >> 2];
+  d5 = +HEAPF32[i12 >> 2] + (d7 * d18 - d8 * d9);
+  d9 = d18 * d8 + d7 * d9 + +HEAPF32[i12 + 4 >> 2];
+  d7 = d5 - d4;
+  d8 = d9 - d6;
+  d18 = +d7;
+  d10 = +d8;
+  i20 = i2;
+  HEAPF32[i20 >> 2] = d18;
+  HEAPF32[i20 + 4 >> 2] = d10;
+  d10 = +Math_sqrt(+(d7 * d7 + d8 * d8));
+  if (d10 < 1.1920928955078125e-7) {
+   d10 = d7;
+   d11 = d8;
+  } else {
+   d11 = 1.0 / d10;
+   d10 = d7 * d11;
+   HEAPF32[i2 >> 2] = d10;
+   d11 = d8 * d11;
+   HEAPF32[i2 + 4 >> 2] = d11;
+  }
+  d17 = +((d4 + d5) * .5);
+  d18 = +((d6 + d9) * .5);
+  i20 = i2 + 8 | 0;
+  HEAPF32[i20 >> 2] = d17;
+  HEAPF32[i20 + 4 >> 2] = d18;
+  HEAPF32[i2 + 16 >> 2] = d7 * d10 + d8 * d11 - +HEAPF32[i1 + 76 >> 2] - +HEAPF32[i1 + 80 >> 2];
+  STACKTOP = i3;
+  return;
+ } else {
+  STACKTOP = i3;
+  return;
+ }
+}
+function __ZNSt3__118__insertion_sort_3IRPFbRK6b2PairS3_EPS1_EEvT0_S8_T_(i5, i1, i2) {
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i6 = i4 + 12 | 0;
+ i3 = i4;
+ i7 = i5 + 24 | 0;
+ i8 = i5 + 12 | 0;
+ i10 = FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i8, i5) | 0;
+ i9 = FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i7, i8) | 0;
+ do {
+  if (i10) {
+   if (i9) {
+    HEAP32[i6 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+    HEAP32[i6 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+    HEAP32[i6 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+    HEAP32[i5 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i5 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i5 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    HEAP32[i7 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+    break;
+   }
+   HEAP32[i6 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+   HEAP32[i6 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i6 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+   HEAP32[i5 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+   HEAP32[i5 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+   HEAP32[i8 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+   HEAP32[i8 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+   HEAP32[i8 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i7, i8) | 0) {
+    HEAP32[i6 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+    HEAP32[i6 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+    HEAP32[i6 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+    HEAP32[i8 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i8 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i8 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    HEAP32[i7 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   }
+  } else {
+   if (i9) {
+    HEAP32[i6 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+    HEAP32[i6 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+    HEAP32[i6 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+    HEAP32[i8 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i8 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i8 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    HEAP32[i7 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+    if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i8, i5) | 0) {
+     HEAP32[i6 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+     HEAP32[i6 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+     HEAP32[i6 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+     HEAP32[i5 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+     HEAP32[i5 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+     HEAP32[i5 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+     HEAP32[i8 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+     HEAP32[i8 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+     HEAP32[i8 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+    }
+   }
+  }
+ } while (0);
+ i6 = i5 + 36 | 0;
+ if ((i6 | 0) == (i1 | 0)) {
+  STACKTOP = i4;
+  return;
+ }
+ while (1) {
+  if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i6, i7) | 0) {
+   HEAP32[i3 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+   HEAP32[i3 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+   HEAP32[i3 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   i8 = i6;
+   while (1) {
+    HEAP32[i8 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i8 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i8 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    if ((i7 | 0) == (i5 | 0)) {
+     break;
+    }
+    i8 = i7 + -12 | 0;
+    if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i3, i8) | 0) {
+     i10 = i7;
+     i7 = i8;
+     i8 = i10;
+    } else {
+     break;
+    }
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+  }
+  i7 = i6 + 12 | 0;
+  if ((i7 | 0) == (i1 | 0)) {
+   break;
+  } else {
+   i10 = i6;
+   i6 = i7;
+   i7 = i10;
+  }
+ }
+ STACKTOP = i4;
+ return;
+}
+function __ZNK20b2SeparationFunction8EvaluateEiif(i10, i12, i11, d9) {
+ i10 = i10 | 0;
+ i12 = i12 | 0;
+ i11 = i11 | 0;
+ d9 = +d9;
+ var d1 = 0.0, d2 = 0.0, d3 = 0.0, d4 = 0.0, d5 = 0.0, d6 = 0.0, i7 = 0, d8 = 0.0, d13 = 0.0, d14 = 0.0, d15 = 0.0, d16 = 0.0, i17 = 0, d18 = 0.0, d19 = 0.0;
+ i7 = STACKTOP;
+ d14 = 1.0 - d9;
+ d3 = d14 * +HEAPF32[i10 + 32 >> 2] + +HEAPF32[i10 + 36 >> 2] * d9;
+ d4 = +Math_sin(+d3);
+ d3 = +Math_cos(+d3);
+ d5 = +HEAPF32[i10 + 8 >> 2];
+ d6 = +HEAPF32[i10 + 12 >> 2];
+ d2 = d14 * +HEAPF32[i10 + 16 >> 2] + +HEAPF32[i10 + 24 >> 2] * d9 - (d3 * d5 - d4 * d6);
+ d6 = d14 * +HEAPF32[i10 + 20 >> 2] + +HEAPF32[i10 + 28 >> 2] * d9 - (d4 * d5 + d3 * d6);
+ d5 = d14 * +HEAPF32[i10 + 68 >> 2] + +HEAPF32[i10 + 72 >> 2] * d9;
+ d1 = +Math_sin(+d5);
+ d5 = +Math_cos(+d5);
+ d15 = +HEAPF32[i10 + 44 >> 2];
+ d16 = +HEAPF32[i10 + 48 >> 2];
+ d8 = d14 * +HEAPF32[i10 + 52 >> 2] + +HEAPF32[i10 + 60 >> 2] * d9 - (d5 * d15 - d1 * d16);
+ d9 = d14 * +HEAPF32[i10 + 56 >> 2] + +HEAPF32[i10 + 64 >> 2] * d9 - (d1 * d15 + d5 * d16);
+ i17 = HEAP32[i10 + 80 >> 2] | 0;
+ if ((i17 | 0) == 0) {
+  d14 = +HEAPF32[i10 + 92 >> 2];
+  d13 = +HEAPF32[i10 + 96 >> 2];
+  i17 = HEAP32[i10 >> 2] | 0;
+  if (!((i12 | 0) > -1)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  if ((HEAP32[i17 + 20 >> 2] | 0) <= (i12 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i17 = (HEAP32[i17 + 16 >> 2] | 0) + (i12 << 3) | 0;
+  d15 = +HEAPF32[i17 >> 2];
+  d16 = +HEAPF32[i17 + 4 >> 2];
+  i10 = HEAP32[i10 + 4 >> 2] | 0;
+  if (!((i11 | 0) > -1)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  if ((HEAP32[i10 + 20 >> 2] | 0) <= (i11 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i17 = (HEAP32[i10 + 16 >> 2] | 0) + (i11 << 3) | 0;
+  d19 = +HEAPF32[i17 >> 2];
+  d18 = +HEAPF32[i17 + 4 >> 2];
+  d16 = d14 * (d8 + (d5 * d19 - d1 * d18) - (d2 + (d3 * d15 - d4 * d16))) + d13 * (d9 + (d1 * d19 + d5 * d18) - (d6 + (d4 * d15 + d3 * d16)));
+  STACKTOP = i7;
+  return +d16;
+ } else if ((i17 | 0) == 1) {
+  d14 = +HEAPF32[i10 + 92 >> 2];
+  d13 = +HEAPF32[i10 + 96 >> 2];
+  d16 = +HEAPF32[i10 + 84 >> 2];
+  d15 = +HEAPF32[i10 + 88 >> 2];
+  i10 = HEAP32[i10 + 4 >> 2] | 0;
+  if (!((i11 | 0) > -1)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  if ((HEAP32[i10 + 20 >> 2] | 0) <= (i11 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i17 = (HEAP32[i10 + 16 >> 2] | 0) + (i11 << 3) | 0;
+  d18 = +HEAPF32[i17 >> 2];
+  d19 = +HEAPF32[i17 + 4 >> 2];
+  d19 = (d3 * d14 - d4 * d13) * (d8 + (d5 * d18 - d1 * d19) - (d2 + (d3 * d16 - d4 * d15))) + (d4 * d14 + d3 * d13) * (d9 + (d1 * d18 + d5 * d19) - (d6 + (d4 * d16 + d3 * d15)));
+  STACKTOP = i7;
+  return +d19;
+ } else if ((i17 | 0) == 2) {
+  d16 = +HEAPF32[i10 + 92 >> 2];
+  d15 = +HEAPF32[i10 + 96 >> 2];
+  d14 = +HEAPF32[i10 + 84 >> 2];
+  d13 = +HEAPF32[i10 + 88 >> 2];
+  i10 = HEAP32[i10 >> 2] | 0;
+  if (!((i12 | 0) > -1)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  if ((HEAP32[i10 + 20 >> 2] | 0) <= (i12 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i17 = (HEAP32[i10 + 16 >> 2] | 0) + (i12 << 3) | 0;
+  d18 = +HEAPF32[i17 >> 2];
+  d19 = +HEAPF32[i17 + 4 >> 2];
+  d19 = (d5 * d16 - d1 * d15) * (d2 + (d3 * d18 - d4 * d19) - (d8 + (d5 * d14 - d1 * d13))) + (d1 * d16 + d5 * d15) * (d6 + (d4 * d18 + d3 * d19) - (d9 + (d1 * d14 + d5 * d13)));
+  STACKTOP = i7;
+  return +d19;
+ } else {
+  ___assert_fail(3616, 3560, 242, 3624);
+ }
+ return 0.0;
+}
+function __ZN6b2Body13ResetMassDataEv(i2) {
+ i2 = i2 | 0;
+ var d1 = 0.0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, d14 = 0.0, d15 = 0.0, d16 = 0.0, i17 = 0, d18 = 0.0, d19 = 0.0, i20 = 0, d21 = 0.0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i10 = i3;
+ i8 = i2 + 116 | 0;
+ i9 = i2 + 120 | 0;
+ i4 = i2 + 124 | 0;
+ i5 = i2 + 128 | 0;
+ i6 = i2 + 28 | 0;
+ HEAPF32[i6 >> 2] = 0.0;
+ HEAPF32[i2 + 32 >> 2] = 0.0;
+ HEAP32[i8 + 0 >> 2] = 0;
+ HEAP32[i8 + 4 >> 2] = 0;
+ HEAP32[i8 + 8 >> 2] = 0;
+ HEAP32[i8 + 12 >> 2] = 0;
+ i11 = HEAP32[i2 >> 2] | 0;
+ if ((i11 | 0) == 2) {
+  i17 = 3784;
+  d16 = +HEAPF32[i17 >> 2];
+  d18 = +HEAPF32[i17 + 4 >> 2];
+  i17 = HEAP32[i2 + 100 >> 2] | 0;
+  if ((i17 | 0) != 0) {
+   i11 = i10 + 4 | 0;
+   i12 = i10 + 8 | 0;
+   i13 = i10 + 12 | 0;
+   d14 = 0.0;
+   d15 = 0.0;
+   do {
+    d19 = +HEAPF32[i17 >> 2];
+    if (!(d19 == 0.0)) {
+     i20 = HEAP32[i17 + 12 >> 2] | 0;
+     FUNCTION_TABLE_viid[HEAP32[(HEAP32[i20 >> 2] | 0) + 28 >> 2] & 3](i20, i10, d19);
+     d14 = +HEAPF32[i10 >> 2];
+     d15 = d14 + +HEAPF32[i8 >> 2];
+     HEAPF32[i8 >> 2] = d15;
+     d16 = d16 + d14 * +HEAPF32[i11 >> 2];
+     d18 = d18 + d14 * +HEAPF32[i12 >> 2];
+     d14 = +HEAPF32[i13 >> 2] + +HEAPF32[i4 >> 2];
+     HEAPF32[i4 >> 2] = d14;
+    }
+    i17 = HEAP32[i17 + 4 >> 2] | 0;
+   } while ((i17 | 0) != 0);
+   if (d15 > 0.0) {
+    d19 = 1.0 / d15;
+    HEAPF32[i9 >> 2] = d19;
+    d16 = d16 * d19;
+    d18 = d18 * d19;
+   } else {
+    i7 = 11;
+   }
+  } else {
+   d14 = 0.0;
+   i7 = 11;
+  }
+  if ((i7 | 0) == 11) {
+   HEAPF32[i8 >> 2] = 1.0;
+   HEAPF32[i9 >> 2] = 1.0;
+   d15 = 1.0;
+  }
+  do {
+   if (d14 > 0.0 ? (HEAP16[i2 + 4 >> 1] & 16) == 0 : 0) {
+    d14 = d14 - (d18 * d18 + d16 * d16) * d15;
+    HEAPF32[i4 >> 2] = d14;
+    if (d14 > 0.0) {
+     d1 = 1.0 / d14;
+     break;
+    } else {
+     ___assert_fail(1872, 1520, 319, 1856);
+    }
+   } else {
+    i7 = 17;
+   }
+  } while (0);
+  if ((i7 | 0) == 17) {
+   HEAPF32[i4 >> 2] = 0.0;
+   d1 = 0.0;
+  }
+  HEAPF32[i5 >> 2] = d1;
+  i20 = i2 + 44 | 0;
+  i17 = i20;
+  d19 = +HEAPF32[i17 >> 2];
+  d14 = +HEAPF32[i17 + 4 >> 2];
+  d21 = +d16;
+  d1 = +d18;
+  i17 = i6;
+  HEAPF32[i17 >> 2] = d21;
+  HEAPF32[i17 + 4 >> 2] = d1;
+  d1 = +HEAPF32[i2 + 24 >> 2];
+  d21 = +HEAPF32[i2 + 20 >> 2];
+  d15 = +HEAPF32[i2 + 12 >> 2] + (d1 * d16 - d21 * d18);
+  d16 = d16 * d21 + d1 * d18 + +HEAPF32[i2 + 16 >> 2];
+  d1 = +d15;
+  d18 = +d16;
+  HEAPF32[i20 >> 2] = d1;
+  HEAPF32[i20 + 4 >> 2] = d18;
+  i20 = i2 + 36 | 0;
+  HEAPF32[i20 >> 2] = d1;
+  HEAPF32[i20 + 4 >> 2] = d18;
+  d18 = +HEAPF32[i2 + 72 >> 2];
+  i20 = i2 + 64 | 0;
+  HEAPF32[i20 >> 2] = +HEAPF32[i20 >> 2] - d18 * (d16 - d14);
+  i20 = i2 + 68 | 0;
+  HEAPF32[i20 >> 2] = d18 * (d15 - d19) + +HEAPF32[i20 >> 2];
+  STACKTOP = i3;
+  return;
+ } else if ((i11 | 0) == 1 | (i11 | 0) == 0) {
+  i17 = i2 + 12 | 0;
+  i13 = HEAP32[i17 >> 2] | 0;
+  i17 = HEAP32[i17 + 4 >> 2] | 0;
+  i20 = i2 + 36 | 0;
+  HEAP32[i20 >> 2] = i13;
+  HEAP32[i20 + 4 >> 2] = i17;
+  i20 = i2 + 44 | 0;
+  HEAP32[i20 >> 2] = i13;
+  HEAP32[i20 + 4 >> 2] = i17;
+  HEAPF32[i2 + 52 >> 2] = +HEAPF32[i2 + 56 >> 2];
+  STACKTOP = i3;
+  return;
+ } else {
+  ___assert_fail(1824, 1520, 284, 1856);
+ }
+}
+function __ZN9b2Contact6UpdateEP17b2ContactListener(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i2 = i3;
+ i10 = i1 + 64 | 0;
+ i6 = i2 + 0 | 0;
+ i7 = i10 + 0 | 0;
+ i5 = i6 + 64 | 0;
+ do {
+  HEAP32[i6 >> 2] = HEAP32[i7 >> 2];
+  i6 = i6 + 4 | 0;
+  i7 = i7 + 4 | 0;
+ } while ((i6 | 0) < (i5 | 0));
+ i6 = i1 + 4 | 0;
+ i11 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i6 >> 2] = i11 | 4;
+ i11 = i11 >>> 1;
+ i14 = HEAP32[i1 + 48 >> 2] | 0;
+ i15 = HEAP32[i1 + 52 >> 2] | 0;
+ i5 = (HEAP8[i15 + 38 | 0] | HEAP8[i14 + 38 | 0]) << 24 >> 24 != 0;
+ i8 = HEAP32[i14 + 8 >> 2] | 0;
+ i7 = HEAP32[i15 + 8 >> 2] | 0;
+ i12 = i8 + 12 | 0;
+ i13 = i7 + 12 | 0;
+ if (!i5) {
+  FUNCTION_TABLE_viiii[HEAP32[HEAP32[i1 >> 2] >> 2] & 15](i1, i10, i12, i13);
+  i12 = i1 + 124 | 0;
+  i10 = (HEAP32[i12 >> 2] | 0) > 0;
+  L4 : do {
+   if (i10) {
+    i19 = HEAP32[i2 + 60 >> 2] | 0;
+    if ((i19 | 0) > 0) {
+     i18 = 0;
+    } else {
+     i9 = 0;
+     while (1) {
+      HEAPF32[i1 + (i9 * 20 | 0) + 72 >> 2] = 0.0;
+      HEAPF32[i1 + (i9 * 20 | 0) + 76 >> 2] = 0.0;
+      i9 = i9 + 1 | 0;
+      if ((i9 | 0) >= (HEAP32[i12 >> 2] | 0)) {
+       break L4;
+      }
+     }
+    }
+    do {
+     i16 = i1 + (i18 * 20 | 0) + 72 | 0;
+     HEAPF32[i16 >> 2] = 0.0;
+     i15 = i1 + (i18 * 20 | 0) + 76 | 0;
+     HEAPF32[i15 >> 2] = 0.0;
+     i14 = HEAP32[i1 + (i18 * 20 | 0) + 80 >> 2] | 0;
+     i17 = 0;
+     while (1) {
+      i13 = i17 + 1 | 0;
+      if ((HEAP32[i2 + (i17 * 20 | 0) + 16 >> 2] | 0) == (i14 | 0)) {
+       i9 = 7;
+       break;
+      }
+      if ((i13 | 0) < (i19 | 0)) {
+       i17 = i13;
+      } else {
+       break;
+      }
+     }
+     if ((i9 | 0) == 7) {
+      i9 = 0;
+      HEAPF32[i16 >> 2] = +HEAPF32[i2 + (i17 * 20 | 0) + 8 >> 2];
+      HEAPF32[i15 >> 2] = +HEAPF32[i2 + (i17 * 20 | 0) + 12 >> 2];
+     }
+     i18 = i18 + 1 | 0;
+    } while ((i18 | 0) < (HEAP32[i12 >> 2] | 0));
+   }
+  } while (0);
+  i9 = i11 & 1;
+  if (i10 ^ (i9 | 0) != 0) {
+   i11 = i8 + 4 | 0;
+   i12 = HEAPU16[i11 >> 1] | 0;
+   if ((i12 & 2 | 0) == 0) {
+    HEAP16[i11 >> 1] = i12 | 2;
+    HEAPF32[i8 + 144 >> 2] = 0.0;
+   }
+   i8 = i7 + 4 | 0;
+   i11 = HEAPU16[i8 >> 1] | 0;
+   if ((i11 & 2 | 0) == 0) {
+    HEAP16[i8 >> 1] = i11 | 2;
+    HEAPF32[i7 + 144 >> 2] = 0.0;
+   }
+  }
+ } else {
+  i10 = __Z13b2TestOverlapPK7b2ShapeiS1_iRK11b2TransformS4_(HEAP32[i14 + 12 >> 2] | 0, HEAP32[i1 + 56 >> 2] | 0, HEAP32[i15 + 12 >> 2] | 0, HEAP32[i1 + 60 >> 2] | 0, i12, i13) | 0;
+  HEAP32[i1 + 124 >> 2] = 0;
+  i9 = i11 & 1;
+ }
+ i7 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i6 >> 2] = i10 ? i7 | 2 : i7 & -3;
+ i8 = (i9 | 0) == 0;
+ i6 = i10 ^ 1;
+ i7 = (i4 | 0) == 0;
+ if (!(i8 ^ 1 | i6 | i7)) {
+  FUNCTION_TABLE_vii[HEAP32[(HEAP32[i4 >> 2] | 0) + 8 >> 2] & 15](i4, i1);
+ }
+ if (!(i8 | i10 | i7)) {
+  FUNCTION_TABLE_vii[HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] & 15](i4, i1);
+ }
+ if (i5 | i6 | i7) {
+  STACKTOP = i3;
+  return;
+ }
+ FUNCTION_TABLE_viii[HEAP32[(HEAP32[i4 >> 2] | 0) + 16 >> 2] & 3](i4, i1, i2);
+ STACKTOP = i3;
+ return;
+}
+function __ZN13b2DynamicTree10RemoveLeafEi(i1, i12) {
+ i1 = i1 | 0;
+ i12 = i12 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, i13 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[i1 >> 2] | 0) == (i12 | 0)) {
+  HEAP32[i1 >> 2] = -1;
+  STACKTOP = i2;
+  return;
+ }
+ i3 = i1 + 4 | 0;
+ i5 = HEAP32[i3 >> 2] | 0;
+ i6 = HEAP32[i5 + (i12 * 36 | 0) + 20 >> 2] | 0;
+ i4 = i5 + (i6 * 36 | 0) + 20 | 0;
+ i7 = HEAP32[i4 >> 2] | 0;
+ i13 = HEAP32[i5 + (i6 * 36 | 0) + 24 >> 2] | 0;
+ if ((i13 | 0) == (i12 | 0)) {
+  i13 = HEAP32[i5 + (i6 * 36 | 0) + 28 >> 2] | 0;
+ }
+ if ((i7 | 0) == -1) {
+  HEAP32[i1 >> 2] = i13;
+  HEAP32[i5 + (i13 * 36 | 0) + 20 >> 2] = -1;
+  if (!((i6 | 0) > -1)) {
+   ___assert_fail(3e3, 2944, 97, 3040);
+  }
+  if ((HEAP32[i1 + 12 >> 2] | 0) <= (i6 | 0)) {
+   ___assert_fail(3e3, 2944, 97, 3040);
+  }
+  i3 = i1 + 8 | 0;
+  if ((HEAP32[i3 >> 2] | 0) <= 0) {
+   ___assert_fail(3056, 2944, 98, 3040);
+  }
+  i13 = i1 + 16 | 0;
+  HEAP32[i4 >> 2] = HEAP32[i13 >> 2];
+  HEAP32[i5 + (i6 * 36 | 0) + 32 >> 2] = -1;
+  HEAP32[i13 >> 2] = i6;
+  HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + -1;
+  STACKTOP = i2;
+  return;
+ }
+ i12 = i5 + (i7 * 36 | 0) + 24 | 0;
+ if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+  HEAP32[i12 >> 2] = i13;
+ } else {
+  HEAP32[i5 + (i7 * 36 | 0) + 28 >> 2] = i13;
+ }
+ HEAP32[i5 + (i13 * 36 | 0) + 20 >> 2] = i7;
+ if (!((i6 | 0) > -1)) {
+  ___assert_fail(3e3, 2944, 97, 3040);
+ }
+ if ((HEAP32[i1 + 12 >> 2] | 0) <= (i6 | 0)) {
+  ___assert_fail(3e3, 2944, 97, 3040);
+ }
+ i12 = i1 + 8 | 0;
+ if ((HEAP32[i12 >> 2] | 0) <= 0) {
+  ___assert_fail(3056, 2944, 98, 3040);
+ }
+ i13 = i1 + 16 | 0;
+ HEAP32[i4 >> 2] = HEAP32[i13 >> 2];
+ HEAP32[i5 + (i6 * 36 | 0) + 32 >> 2] = -1;
+ HEAP32[i13 >> 2] = i6;
+ HEAP32[i12 >> 2] = (HEAP32[i12 >> 2] | 0) + -1;
+ do {
+  i4 = __ZN13b2DynamicTree7BalanceEi(i1, i7) | 0;
+  i7 = HEAP32[i3 >> 2] | 0;
+  i6 = HEAP32[i7 + (i4 * 36 | 0) + 24 >> 2] | 0;
+  i5 = HEAP32[i7 + (i4 * 36 | 0) + 28 >> 2] | 0;
+  d10 = +HEAPF32[i7 + (i6 * 36 | 0) >> 2];
+  d11 = +HEAPF32[i7 + (i5 * 36 | 0) >> 2];
+  d9 = +HEAPF32[i7 + (i6 * 36 | 0) + 4 >> 2];
+  d8 = +HEAPF32[i7 + (i5 * 36 | 0) + 4 >> 2];
+  d10 = +(d10 < d11 ? d10 : d11);
+  d11 = +(d9 < d8 ? d9 : d8);
+  i13 = i7 + (i4 * 36 | 0) | 0;
+  HEAPF32[i13 >> 2] = d10;
+  HEAPF32[i13 + 4 >> 2] = d11;
+  d11 = +HEAPF32[i7 + (i6 * 36 | 0) + 8 >> 2];
+  d10 = +HEAPF32[i7 + (i5 * 36 | 0) + 8 >> 2];
+  d9 = +HEAPF32[i7 + (i6 * 36 | 0) + 12 >> 2];
+  d8 = +HEAPF32[i7 + (i5 * 36 | 0) + 12 >> 2];
+  d10 = +(d11 > d10 ? d11 : d10);
+  d11 = +(d9 > d8 ? d9 : d8);
+  i7 = i7 + (i4 * 36 | 0) + 8 | 0;
+  HEAPF32[i7 >> 2] = d10;
+  HEAPF32[i7 + 4 >> 2] = d11;
+  i7 = HEAP32[i3 >> 2] | 0;
+  i6 = HEAP32[i7 + (i6 * 36 | 0) + 32 >> 2] | 0;
+  i5 = HEAP32[i7 + (i5 * 36 | 0) + 32 >> 2] | 0;
+  HEAP32[i7 + (i4 * 36 | 0) + 32 >> 2] = ((i6 | 0) > (i5 | 0) ? i6 : i5) + 1;
+  i7 = HEAP32[i7 + (i4 * 36 | 0) + 20 >> 2] | 0;
+ } while (!((i7 | 0) == -1));
+ STACKTOP = i2;
+ return;
+}
+function __ZN9b2Simplex6Solve3Ev(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, d4 = 0.0, d5 = 0.0, d6 = 0.0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, d12 = 0.0, d13 = 0.0, d14 = 0.0, d15 = 0.0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, d21 = 0.0, i22 = 0;
+ i1 = STACKTOP;
+ i2 = i7 + 16 | 0;
+ d17 = +HEAPF32[i2 >> 2];
+ d15 = +HEAPF32[i2 + 4 >> 2];
+ i2 = i7 + 36 | 0;
+ i3 = i7 + 52 | 0;
+ d14 = +HEAPF32[i3 >> 2];
+ d16 = +HEAPF32[i3 + 4 >> 2];
+ i3 = i7 + 72 | 0;
+ i22 = i7 + 88 | 0;
+ d18 = +HEAPF32[i22 >> 2];
+ d11 = +HEAPF32[i22 + 4 >> 2];
+ d20 = d14 - d17;
+ d10 = d16 - d15;
+ d9 = d17 * d20 + d15 * d10;
+ d8 = d14 * d20 + d16 * d10;
+ d4 = d18 - d17;
+ d19 = d11 - d15;
+ d6 = d17 * d4 + d15 * d19;
+ d5 = d18 * d4 + d11 * d19;
+ d21 = d18 - d14;
+ d12 = d11 - d16;
+ d13 = d14 * d21 + d16 * d12;
+ d12 = d18 * d21 + d11 * d12;
+ d4 = d20 * d19 - d10 * d4;
+ d10 = (d14 * d11 - d16 * d18) * d4;
+ d11 = (d15 * d18 - d17 * d11) * d4;
+ d4 = (d17 * d16 - d15 * d14) * d4;
+ if (!(!(d9 >= -0.0) | !(d6 >= -0.0))) {
+  HEAPF32[i7 + 24 >> 2] = 1.0;
+  HEAP32[i7 + 108 >> 2] = 1;
+  STACKTOP = i1;
+  return;
+ }
+ if (!(!(d9 < -0.0) | !(d8 > 0.0) | !(d4 <= 0.0))) {
+  d21 = 1.0 / (d8 - d9);
+  HEAPF32[i7 + 24 >> 2] = d8 * d21;
+  HEAPF32[i7 + 60 >> 2] = -(d9 * d21);
+  HEAP32[i7 + 108 >> 2] = 2;
+  STACKTOP = i1;
+  return;
+ }
+ if (!(!(d6 < -0.0) | !(d5 > 0.0) | !(d11 <= 0.0))) {
+  d21 = 1.0 / (d5 - d6);
+  HEAPF32[i7 + 24 >> 2] = d5 * d21;
+  HEAPF32[i7 + 96 >> 2] = -(d6 * d21);
+  HEAP32[i7 + 108 >> 2] = 2;
+  i7 = i2 + 0 | 0;
+  i3 = i3 + 0 | 0;
+  i2 = i7 + 36 | 0;
+  do {
+   HEAP32[i7 >> 2] = HEAP32[i3 >> 2];
+   i7 = i7 + 4 | 0;
+   i3 = i3 + 4 | 0;
+  } while ((i7 | 0) < (i2 | 0));
+  STACKTOP = i1;
+  return;
+ }
+ if (!(!(d8 <= 0.0) | !(d13 >= -0.0))) {
+  HEAPF32[i7 + 60 >> 2] = 1.0;
+  HEAP32[i7 + 108 >> 2] = 1;
+  i7 = i7 + 0 | 0;
+  i3 = i2 + 0 | 0;
+  i2 = i7 + 36 | 0;
+  do {
+   HEAP32[i7 >> 2] = HEAP32[i3 >> 2];
+   i7 = i7 + 4 | 0;
+   i3 = i3 + 4 | 0;
+  } while ((i7 | 0) < (i2 | 0));
+  STACKTOP = i1;
+  return;
+ }
+ if (!(!(d5 <= 0.0) | !(d12 <= 0.0))) {
+  HEAPF32[i7 + 96 >> 2] = 1.0;
+  HEAP32[i7 + 108 >> 2] = 1;
+  i7 = i7 + 0 | 0;
+  i3 = i3 + 0 | 0;
+  i2 = i7 + 36 | 0;
+  do {
+   HEAP32[i7 >> 2] = HEAP32[i3 >> 2];
+   i7 = i7 + 4 | 0;
+   i3 = i3 + 4 | 0;
+  } while ((i7 | 0) < (i2 | 0));
+  STACKTOP = i1;
+  return;
+ }
+ if (!(d13 < -0.0) | !(d12 > 0.0) | !(d10 <= 0.0)) {
+  d21 = 1.0 / (d4 + (d10 + d11));
+  HEAPF32[i7 + 24 >> 2] = d10 * d21;
+  HEAPF32[i7 + 60 >> 2] = d11 * d21;
+  HEAPF32[i7 + 96 >> 2] = d4 * d21;
+  HEAP32[i7 + 108 >> 2] = 3;
+  STACKTOP = i1;
+  return;
+ } else {
+  d21 = 1.0 / (d12 - d13);
+  HEAPF32[i7 + 60 >> 2] = d12 * d21;
+  HEAPF32[i7 + 96 >> 2] = -(d13 * d21);
+  HEAP32[i7 + 108 >> 2] = 2;
+  i7 = i7 + 0 | 0;
+  i3 = i3 + 0 | 0;
+  i2 = i7 + 36 | 0;
+  do {
+   HEAP32[i7 >> 2] = HEAP32[i3 >> 2];
+   i7 = i7 + 4 | 0;
+   i3 = i3 + 4 | 0;
+  } while ((i7 | 0) < (i2 | 0));
+  STACKTOP = i1;
+  return;
+ }
+}
+function __ZN16b2ContactManager7CollideEv(i3) {
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0;
+ i2 = STACKTOP;
+ i8 = HEAP32[i3 + 60 >> 2] | 0;
+ if ((i8 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i7 = i3 + 12 | 0;
+ i6 = i3 + 4 | 0;
+ i5 = i3 + 72 | 0;
+ i4 = i3 + 68 | 0;
+ L4 : while (1) {
+  i12 = HEAP32[i8 + 48 >> 2] | 0;
+  i10 = HEAP32[i8 + 52 >> 2] | 0;
+  i11 = HEAP32[i8 + 56 >> 2] | 0;
+  i9 = HEAP32[i8 + 60 >> 2] | 0;
+  i15 = HEAP32[i12 + 8 >> 2] | 0;
+  i13 = HEAP32[i10 + 8 >> 2] | 0;
+  i16 = i8 + 4 | 0;
+  do {
+   if ((HEAP32[i16 >> 2] & 8 | 0) == 0) {
+    i1 = 11;
+   } else {
+    if (!(__ZNK6b2Body13ShouldCollideEPKS_(i13, i15) | 0)) {
+     i16 = HEAP32[i8 + 12 >> 2] | 0;
+     __ZN16b2ContactManager7DestroyEP9b2Contact(i3, i8);
+     i8 = i16;
+     break;
+    }
+    i14 = HEAP32[i4 >> 2] | 0;
+    if ((i14 | 0) != 0 ? !(FUNCTION_TABLE_iiii[HEAP32[(HEAP32[i14 >> 2] | 0) + 8 >> 2] & 7](i14, i12, i10) | 0) : 0) {
+     i16 = HEAP32[i8 + 12 >> 2] | 0;
+     __ZN16b2ContactManager7DestroyEP9b2Contact(i3, i8);
+     i8 = i16;
+     break;
+    }
+    HEAP32[i16 >> 2] = HEAP32[i16 >> 2] & -9;
+    i1 = 11;
+   }
+  } while (0);
+  do {
+   if ((i1 | 0) == 11) {
+    i1 = 0;
+    if ((HEAP16[i15 + 4 >> 1] & 2) == 0) {
+     i14 = 0;
+    } else {
+     i14 = (HEAP32[i15 >> 2] | 0) != 0;
+    }
+    if ((HEAP16[i13 + 4 >> 1] & 2) == 0) {
+     i13 = 0;
+    } else {
+     i13 = (HEAP32[i13 >> 2] | 0) != 0;
+    }
+    if (!(i14 | i13)) {
+     i8 = HEAP32[i8 + 12 >> 2] | 0;
+     break;
+    }
+    i11 = HEAP32[(HEAP32[i12 + 24 >> 2] | 0) + (i11 * 28 | 0) + 24 >> 2] | 0;
+    i9 = HEAP32[(HEAP32[i10 + 24 >> 2] | 0) + (i9 * 28 | 0) + 24 >> 2] | 0;
+    if (!((i11 | 0) > -1)) {
+     i1 = 19;
+     break L4;
+    }
+    i10 = HEAP32[i7 >> 2] | 0;
+    if ((i10 | 0) <= (i11 | 0)) {
+     i1 = 19;
+     break L4;
+    }
+    i12 = HEAP32[i6 >> 2] | 0;
+    if (!((i9 | 0) > -1 & (i10 | 0) > (i9 | 0))) {
+     i1 = 21;
+     break L4;
+    }
+    if (+HEAPF32[i12 + (i9 * 36 | 0) >> 2] - +HEAPF32[i12 + (i11 * 36 | 0) + 8 >> 2] > 0.0 | +HEAPF32[i12 + (i9 * 36 | 0) + 4 >> 2] - +HEAPF32[i12 + (i11 * 36 | 0) + 12 >> 2] > 0.0 | +HEAPF32[i12 + (i11 * 36 | 0) >> 2] - +HEAPF32[i12 + (i9 * 36 | 0) + 8 >> 2] > 0.0 | +HEAPF32[i12 + (i11 * 36 | 0) + 4 >> 2] - +HEAPF32[i12 + (i9 * 36 | 0) + 12 >> 2] > 0.0) {
+     i16 = HEAP32[i8 + 12 >> 2] | 0;
+     __ZN16b2ContactManager7DestroyEP9b2Contact(i3, i8);
+     i8 = i16;
+     break;
+    } else {
+     __ZN9b2Contact6UpdateEP17b2ContactListener(i8, HEAP32[i5 >> 2] | 0);
+     i8 = HEAP32[i8 + 12 >> 2] | 0;
+     break;
+    }
+   }
+  } while (0);
+  if ((i8 | 0) == 0) {
+   i1 = 25;
+   break;
+  }
+ }
+ if ((i1 | 0) == 19) {
+  ___assert_fail(1904, 1952, 159, 2008);
+ } else if ((i1 | 0) == 21) {
+  ___assert_fail(1904, 1952, 159, 2008);
+ } else if ((i1 | 0) == 25) {
+  STACKTOP = i2;
+  return;
+ }
+}
+function __ZN16b2ContactManager7AddPairEPvS0_(i1, i5, i6) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i5 + 16 >> 2] | 0;
+ i3 = HEAP32[i6 + 16 >> 2] | 0;
+ i5 = HEAP32[i5 + 20 >> 2] | 0;
+ i6 = HEAP32[i6 + 20 >> 2] | 0;
+ i8 = HEAP32[i4 + 8 >> 2] | 0;
+ i7 = HEAP32[i3 + 8 >> 2] | 0;
+ if ((i8 | 0) == (i7 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i10 = HEAP32[i7 + 112 >> 2] | 0;
+ L4 : do {
+  if ((i10 | 0) != 0) {
+   while (1) {
+    if ((HEAP32[i10 >> 2] | 0) == (i8 | 0)) {
+     i9 = HEAP32[i10 + 4 >> 2] | 0;
+     i12 = HEAP32[i9 + 48 >> 2] | 0;
+     i13 = HEAP32[i9 + 52 >> 2] | 0;
+     i11 = HEAP32[i9 + 56 >> 2] | 0;
+     i9 = HEAP32[i9 + 60 >> 2] | 0;
+     if ((i12 | 0) == (i4 | 0) & (i13 | 0) == (i3 | 0) & (i11 | 0) == (i5 | 0) & (i9 | 0) == (i6 | 0)) {
+      i9 = 22;
+      break;
+     }
+     if ((i12 | 0) == (i3 | 0) & (i13 | 0) == (i4 | 0) & (i11 | 0) == (i6 | 0) & (i9 | 0) == (i5 | 0)) {
+      i9 = 22;
+      break;
+     }
+    }
+    i10 = HEAP32[i10 + 12 >> 2] | 0;
+    if ((i10 | 0) == 0) {
+     break L4;
+    }
+   }
+   if ((i9 | 0) == 22) {
+    STACKTOP = i2;
+    return;
+   }
+  }
+ } while (0);
+ if (!(__ZNK6b2Body13ShouldCollideEPKS_(i7, i8) | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i7 = HEAP32[i1 + 68 >> 2] | 0;
+ if ((i7 | 0) != 0 ? !(FUNCTION_TABLE_iiii[HEAP32[(HEAP32[i7 >> 2] | 0) + 8 >> 2] & 7](i7, i4, i3) | 0) : 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i5 = __ZN9b2Contact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i4, i5, i3, i6, HEAP32[i1 + 76 >> 2] | 0) | 0;
+ if ((i5 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i4 = HEAP32[(HEAP32[i5 + 48 >> 2] | 0) + 8 >> 2] | 0;
+ i3 = HEAP32[(HEAP32[i5 + 52 >> 2] | 0) + 8 >> 2] | 0;
+ HEAP32[i5 + 8 >> 2] = 0;
+ i7 = i1 + 60 | 0;
+ HEAP32[i5 + 12 >> 2] = HEAP32[i7 >> 2];
+ i6 = HEAP32[i7 >> 2] | 0;
+ if ((i6 | 0) != 0) {
+  HEAP32[i6 + 8 >> 2] = i5;
+ }
+ HEAP32[i7 >> 2] = i5;
+ i8 = i5 + 16 | 0;
+ HEAP32[i5 + 20 >> 2] = i5;
+ HEAP32[i8 >> 2] = i3;
+ HEAP32[i5 + 24 >> 2] = 0;
+ i6 = i4 + 112 | 0;
+ HEAP32[i5 + 28 >> 2] = HEAP32[i6 >> 2];
+ i7 = HEAP32[i6 >> 2] | 0;
+ if ((i7 | 0) != 0) {
+  HEAP32[i7 + 8 >> 2] = i8;
+ }
+ HEAP32[i6 >> 2] = i8;
+ i6 = i5 + 32 | 0;
+ HEAP32[i5 + 36 >> 2] = i5;
+ HEAP32[i6 >> 2] = i4;
+ HEAP32[i5 + 40 >> 2] = 0;
+ i7 = i3 + 112 | 0;
+ HEAP32[i5 + 44 >> 2] = HEAP32[i7 >> 2];
+ i5 = HEAP32[i7 >> 2] | 0;
+ if ((i5 | 0) != 0) {
+  HEAP32[i5 + 8 >> 2] = i6;
+ }
+ HEAP32[i7 >> 2] = i6;
+ i5 = i4 + 4 | 0;
+ i6 = HEAPU16[i5 >> 1] | 0;
+ if ((i6 & 2 | 0) == 0) {
+  HEAP16[i5 >> 1] = i6 | 2;
+  HEAPF32[i4 + 144 >> 2] = 0.0;
+ }
+ i4 = i3 + 4 | 0;
+ i5 = HEAPU16[i4 >> 1] | 0;
+ if ((i5 & 2 | 0) == 0) {
+  HEAP16[i4 >> 1] = i5 | 2;
+  HEAPF32[i3 + 144 >> 2] = 0.0;
+ }
+ i13 = i1 + 64 | 0;
+ HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + 1;
+ STACKTOP = i2;
+ return;
+}
+function __ZN12b2BroadPhase11UpdatePairsI16b2ContactManagerEEvPT_(i5, i2) {
+ i5 = i5 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i6 = i3;
+ i1 = i5 + 52 | 0;
+ HEAP32[i1 >> 2] = 0;
+ i4 = i5 + 40 | 0;
+ i12 = HEAP32[i4 >> 2] | 0;
+ do {
+  if ((i12 | 0) > 0) {
+   i9 = i5 + 32 | 0;
+   i11 = i5 + 56 | 0;
+   i8 = i5 + 12 | 0;
+   i10 = i5 + 4 | 0;
+   i13 = 0;
+   while (1) {
+    i14 = HEAP32[(HEAP32[i9 >> 2] | 0) + (i13 << 2) >> 2] | 0;
+    HEAP32[i11 >> 2] = i14;
+    if (!((i14 | 0) == -1)) {
+     if (!((i14 | 0) > -1)) {
+      i8 = 6;
+      break;
+     }
+     if ((HEAP32[i8 >> 2] | 0) <= (i14 | 0)) {
+      i8 = 6;
+      break;
+     }
+     __ZNK13b2DynamicTree5QueryI12b2BroadPhaseEEvPT_RK6b2AABB(i5, i5, (HEAP32[i10 >> 2] | 0) + (i14 * 36 | 0) | 0);
+     i12 = HEAP32[i4 >> 2] | 0;
+    }
+    i13 = i13 + 1 | 0;
+    if ((i13 | 0) >= (i12 | 0)) {
+     i8 = 9;
+     break;
+    }
+   }
+   if ((i8 | 0) == 6) {
+    ___assert_fail(1904, 1952, 159, 2008);
+   } else if ((i8 | 0) == 9) {
+    i7 = HEAP32[i1 >> 2] | 0;
+    break;
+   }
+  } else {
+   i7 = 0;
+  }
+ } while (0);
+ HEAP32[i4 >> 2] = 0;
+ i4 = i5 + 44 | 0;
+ i14 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i6 >> 2] = 3;
+ __ZNSt3__16__sortIRPFbRK6b2PairS3_EPS1_EEvT0_S8_T_(i14, i14 + (i7 * 12 | 0) | 0, i6);
+ if ((HEAP32[i1 >> 2] | 0) <= 0) {
+  STACKTOP = i3;
+  return;
+ }
+ i6 = i5 + 12 | 0;
+ i7 = i5 + 4 | 0;
+ i9 = 0;
+ L18 : while (1) {
+  i8 = HEAP32[i4 >> 2] | 0;
+  i5 = i8 + (i9 * 12 | 0) | 0;
+  i10 = HEAP32[i5 >> 2] | 0;
+  if (!((i10 | 0) > -1)) {
+   i8 = 14;
+   break;
+  }
+  i12 = HEAP32[i6 >> 2] | 0;
+  if ((i12 | 0) <= (i10 | 0)) {
+   i8 = 14;
+   break;
+  }
+  i11 = HEAP32[i7 >> 2] | 0;
+  i8 = i8 + (i9 * 12 | 0) + 4 | 0;
+  i13 = HEAP32[i8 >> 2] | 0;
+  if (!((i13 | 0) > -1 & (i12 | 0) > (i13 | 0))) {
+   i8 = 16;
+   break;
+  }
+  __ZN16b2ContactManager7AddPairEPvS0_(i2, HEAP32[i11 + (i10 * 36 | 0) + 16 >> 2] | 0, HEAP32[i11 + (i13 * 36 | 0) + 16 >> 2] | 0);
+  i10 = HEAP32[i1 >> 2] | 0;
+  while (1) {
+   i9 = i9 + 1 | 0;
+   if ((i9 | 0) >= (i10 | 0)) {
+    i8 = 21;
+    break L18;
+   }
+   i11 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i11 + (i9 * 12 | 0) >> 2] | 0) != (HEAP32[i5 >> 2] | 0)) {
+    continue L18;
+   }
+   if ((HEAP32[i11 + (i9 * 12 | 0) + 4 >> 2] | 0) != (HEAP32[i8 >> 2] | 0)) {
+    continue L18;
+   }
+  }
+ }
+ if ((i8 | 0) == 14) {
+  ___assert_fail(1904, 1952, 153, 1992);
+ } else if ((i8 | 0) == 16) {
+  ___assert_fail(1904, 1952, 153, 1992);
+ } else if ((i8 | 0) == 21) {
+  STACKTOP = i3;
+  return;
+ }
+}
+function __ZNK13b2DynamicTree5QueryI12b2BroadPhaseEEvPT_RK6b2AABB(i9, i4, i7) {
+ i9 = i9 | 0;
+ i4 = i4 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 1040 | 0;
+ i3 = i2;
+ i1 = i3 + 4 | 0;
+ HEAP32[i3 >> 2] = i1;
+ i5 = i3 + 1028 | 0;
+ HEAP32[i5 >> 2] = 0;
+ i6 = i3 + 1032 | 0;
+ HEAP32[i6 >> 2] = 256;
+ i14 = HEAP32[i3 >> 2] | 0;
+ HEAP32[i14 + (HEAP32[i5 >> 2] << 2) >> 2] = HEAP32[i9 >> 2];
+ i15 = HEAP32[i5 >> 2] | 0;
+ i16 = i15 + 1 | 0;
+ HEAP32[i5 >> 2] = i16;
+ L1 : do {
+  if ((i15 | 0) > -1) {
+   i9 = i9 + 4 | 0;
+   i11 = i7 + 4 | 0;
+   i12 = i7 + 8 | 0;
+   i10 = i7 + 12 | 0;
+   while (1) {
+    i16 = i16 + -1 | 0;
+    HEAP32[i5 >> 2] = i16;
+    i13 = HEAP32[i14 + (i16 << 2) >> 2] | 0;
+    do {
+     if (!((i13 | 0) == -1) ? (i8 = HEAP32[i9 >> 2] | 0, !(+HEAPF32[i7 >> 2] - +HEAPF32[i8 + (i13 * 36 | 0) + 8 >> 2] > 0.0 | +HEAPF32[i11 >> 2] - +HEAPF32[i8 + (i13 * 36 | 0) + 12 >> 2] > 0.0 | +HEAPF32[i8 + (i13 * 36 | 0) >> 2] - +HEAPF32[i12 >> 2] > 0.0 | +HEAPF32[i8 + (i13 * 36 | 0) + 4 >> 2] - +HEAPF32[i10 >> 2] > 0.0)) : 0) {
+      i15 = i8 + (i13 * 36 | 0) + 24 | 0;
+      if ((HEAP32[i15 >> 2] | 0) == -1) {
+       if (!(__ZN12b2BroadPhase13QueryCallbackEi(i4, i13) | 0)) {
+        break L1;
+       }
+       i16 = HEAP32[i5 >> 2] | 0;
+       break;
+      }
+      if ((i16 | 0) == (HEAP32[i6 >> 2] | 0) ? (HEAP32[i6 >> 2] = i16 << 1, i16 = __Z7b2Alloci(i16 << 3) | 0, HEAP32[i3 >> 2] = i16, _memcpy(i16 | 0, i14 | 0, HEAP32[i5 >> 2] << 2 | 0) | 0, (i14 | 0) != (i1 | 0)) : 0) {
+       __Z6b2FreePv(i14);
+      }
+      i14 = HEAP32[i3 >> 2] | 0;
+      HEAP32[i14 + (HEAP32[i5 >> 2] << 2) >> 2] = HEAP32[i15 >> 2];
+      i15 = (HEAP32[i5 >> 2] | 0) + 1 | 0;
+      HEAP32[i5 >> 2] = i15;
+      i13 = i8 + (i13 * 36 | 0) + 28 | 0;
+      if ((i15 | 0) == (HEAP32[i6 >> 2] | 0) ? (HEAP32[i6 >> 2] = i15 << 1, i16 = __Z7b2Alloci(i15 << 3) | 0, HEAP32[i3 >> 2] = i16, _memcpy(i16 | 0, i14 | 0, HEAP32[i5 >> 2] << 2 | 0) | 0, (i14 | 0) != (i1 | 0)) : 0) {
+       __Z6b2FreePv(i14);
+      }
+      HEAP32[(HEAP32[i3 >> 2] | 0) + (HEAP32[i5 >> 2] << 2) >> 2] = HEAP32[i13 >> 2];
+      i16 = (HEAP32[i5 >> 2] | 0) + 1 | 0;
+      HEAP32[i5 >> 2] = i16;
+     }
+    } while (0);
+    if ((i16 | 0) <= 0) {
+     break L1;
+    }
+    i14 = HEAP32[i3 >> 2] | 0;
+   }
+  }
+ } while (0);
+ i4 = HEAP32[i3 >> 2] | 0;
+ if ((i4 | 0) == (i1 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ __Z6b2FreePv(i4);
+ HEAP32[i3 >> 2] = 0;
+ STACKTOP = i2;
+ return;
+}
+function __ZN15b2ContactSolver9WarmStartEv(i4) {
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, d10 = 0.0, d11 = 0.0, d12 = 0.0, i13 = 0, d14 = 0.0, d15 = 0.0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, d21 = 0.0, i22 = 0, d23 = 0.0, i24 = 0, d25 = 0.0, d26 = 0.0, d27 = 0.0;
+ i1 = STACKTOP;
+ i2 = i4 + 48 | 0;
+ if ((HEAP32[i2 >> 2] | 0) <= 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i3 = i4 + 40 | 0;
+ i5 = i4 + 28 | 0;
+ i22 = HEAP32[i5 >> 2] | 0;
+ i8 = 0;
+ do {
+  i9 = HEAP32[i3 >> 2] | 0;
+  i7 = HEAP32[i9 + (i8 * 152 | 0) + 112 >> 2] | 0;
+  i6 = HEAP32[i9 + (i8 * 152 | 0) + 116 >> 2] | 0;
+  d10 = +HEAPF32[i9 + (i8 * 152 | 0) + 120 >> 2];
+  d14 = +HEAPF32[i9 + (i8 * 152 | 0) + 128 >> 2];
+  d12 = +HEAPF32[i9 + (i8 * 152 | 0) + 124 >> 2];
+  d11 = +HEAPF32[i9 + (i8 * 152 | 0) + 132 >> 2];
+  i13 = HEAP32[i9 + (i8 * 152 | 0) + 144 >> 2] | 0;
+  i4 = i22 + (i7 * 12 | 0) | 0;
+  i24 = i4;
+  d17 = +HEAPF32[i24 >> 2];
+  d19 = +HEAPF32[i24 + 4 >> 2];
+  d20 = +HEAPF32[i22 + (i7 * 12 | 0) + 8 >> 2];
+  i24 = i22 + (i6 * 12 | 0) | 0;
+  d21 = +HEAPF32[i24 >> 2];
+  d23 = +HEAPF32[i24 + 4 >> 2];
+  d18 = +HEAPF32[i22 + (i6 * 12 | 0) + 8 >> 2];
+  i22 = i9 + (i8 * 152 | 0) + 72 | 0;
+  d15 = +HEAPF32[i22 >> 2];
+  d16 = +HEAPF32[i22 + 4 >> 2];
+  if ((i13 | 0) > 0) {
+   i22 = 0;
+   do {
+    d27 = +HEAPF32[i9 + (i8 * 152 | 0) + (i22 * 36 | 0) + 16 >> 2];
+    d25 = +HEAPF32[i9 + (i8 * 152 | 0) + (i22 * 36 | 0) + 20 >> 2];
+    d26 = d15 * d27 + d16 * d25;
+    d25 = d16 * d27 - d15 * d25;
+    d20 = d20 - d14 * (+HEAPF32[i9 + (i8 * 152 | 0) + (i22 * 36 | 0) >> 2] * d25 - +HEAPF32[i9 + (i8 * 152 | 0) + (i22 * 36 | 0) + 4 >> 2] * d26);
+    d17 = d17 - d10 * d26;
+    d19 = d19 - d10 * d25;
+    d18 = d18 + d11 * (d25 * +HEAPF32[i9 + (i8 * 152 | 0) + (i22 * 36 | 0) + 8 >> 2] - d26 * +HEAPF32[i9 + (i8 * 152 | 0) + (i22 * 36 | 0) + 12 >> 2]);
+    d21 = d21 + d12 * d26;
+    d23 = d23 + d12 * d25;
+    i22 = i22 + 1 | 0;
+   } while ((i22 | 0) != (i13 | 0));
+  }
+  d27 = +d17;
+  d26 = +d19;
+  i22 = i4;
+  HEAPF32[i22 >> 2] = d27;
+  HEAPF32[i22 + 4 >> 2] = d26;
+  i22 = HEAP32[i5 >> 2] | 0;
+  HEAPF32[i22 + (i7 * 12 | 0) + 8 >> 2] = d20;
+  d26 = +d21;
+  d27 = +d23;
+  i22 = i22 + (i6 * 12 | 0) | 0;
+  HEAPF32[i22 >> 2] = d26;
+  HEAPF32[i22 + 4 >> 2] = d27;
+  i22 = HEAP32[i5 >> 2] | 0;
+  HEAPF32[i22 + (i6 * 12 | 0) + 8 >> 2] = d18;
+  i8 = i8 + 1 | 0;
+ } while ((i8 | 0) < (HEAP32[i2 >> 2] | 0));
+ STACKTOP = i1;
+ return;
+}
+function __ZNK14b2PolygonShape7RayCastEP15b2RayCastOutputRK14b2RayCastInputRK11b2Transformi(i1, i5, i8, i7, i4) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i8 = i8 | 0;
+ i7 = i7 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, d3 = 0.0, i6 = 0, d9 = 0.0, d10 = 0.0, d11 = 0.0, d12 = 0.0, d13 = 0.0, i14 = 0, i15 = 0, i16 = 0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0;
+ i4 = STACKTOP;
+ d10 = +HEAPF32[i7 >> 2];
+ d9 = +HEAPF32[i8 >> 2] - d10;
+ d18 = +HEAPF32[i7 + 4 >> 2];
+ d11 = +HEAPF32[i8 + 4 >> 2] - d18;
+ i6 = i7 + 12 | 0;
+ d17 = +HEAPF32[i6 >> 2];
+ i7 = i7 + 8 | 0;
+ d19 = +HEAPF32[i7 >> 2];
+ d12 = d9 * d17 + d11 * d19;
+ d9 = d17 * d11 - d9 * d19;
+ d10 = +HEAPF32[i8 + 8 >> 2] - d10;
+ d18 = +HEAPF32[i8 + 12 >> 2] - d18;
+ d11 = d17 * d10 + d19 * d18 - d12;
+ d10 = d17 * d18 - d19 * d10 - d9;
+ i8 = i8 + 16 | 0;
+ i14 = HEAP32[i1 + 148 >> 2] | 0;
+ do {
+  if ((i14 | 0) > 0) {
+   i16 = 0;
+   i15 = -1;
+   d13 = 0.0;
+   d17 = +HEAPF32[i8 >> 2];
+   L3 : while (1) {
+    d20 = +HEAPF32[i1 + (i16 << 3) + 84 >> 2];
+    d19 = +HEAPF32[i1 + (i16 << 3) + 88 >> 2];
+    d18 = (+HEAPF32[i1 + (i16 << 3) + 20 >> 2] - d12) * d20 + (+HEAPF32[i1 + (i16 << 3) + 24 >> 2] - d9) * d19;
+    d19 = d11 * d20 + d10 * d19;
+    do {
+     if (d19 == 0.0) {
+      if (d18 < 0.0) {
+       i1 = 0;
+       i14 = 18;
+       break L3;
+      }
+     } else {
+      if (d19 < 0.0 ? d18 < d13 * d19 : 0) {
+       i15 = i16;
+       d13 = d18 / d19;
+       break;
+      }
+      if (d19 > 0.0 ? d18 < d17 * d19 : 0) {
+       d17 = d18 / d19;
+      }
+     }
+    } while (0);
+    i16 = i16 + 1 | 0;
+    if (d17 < d13) {
+     i1 = 0;
+     i14 = 18;
+     break;
+    }
+    if ((i16 | 0) >= (i14 | 0)) {
+     i14 = 13;
+     break;
+    }
+   }
+   if ((i14 | 0) == 13) {
+    if (d13 >= 0.0) {
+     i2 = i15;
+     d3 = d13;
+     break;
+    }
+    ___assert_fail(376, 328, 249, 424);
+   } else if ((i14 | 0) == 18) {
+    STACKTOP = i4;
+    return i1 | 0;
+   }
+  } else {
+   i2 = -1;
+   d3 = 0.0;
+  }
+ } while (0);
+ if (!(d3 <= +HEAPF32[i8 >> 2])) {
+  ___assert_fail(376, 328, 249, 424);
+ }
+ if (!((i2 | 0) > -1)) {
+  i16 = 0;
+  STACKTOP = i4;
+  return i16 | 0;
+ }
+ HEAPF32[i5 + 8 >> 2] = d3;
+ d18 = +HEAPF32[i6 >> 2];
+ d13 = +HEAPF32[i1 + (i2 << 3) + 84 >> 2];
+ d17 = +HEAPF32[i7 >> 2];
+ d20 = +HEAPF32[i1 + (i2 << 3) + 88 >> 2];
+ d19 = +(d18 * d13 - d17 * d20);
+ d20 = +(d13 * d17 + d18 * d20);
+ i16 = i5;
+ HEAPF32[i16 >> 2] = d19;
+ HEAPF32[i16 + 4 >> 2] = d20;
+ i16 = 1;
+ STACKTOP = i4;
+ return i16 | 0;
+}
+function __ZN7b2World4StepEfii(i1, d9, i11, i12) {
+ i1 = i1 | 0;
+ d9 = +d9;
+ i11 = i11 | 0;
+ i12 = i12 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i10 = 0, i13 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i3 = i4 + 27 | 0;
+ i5 = i4;
+ i8 = i4 + 26 | 0;
+ i10 = i4 + 25 | 0;
+ i7 = i4 + 24 | 0;
+ __ZN7b2TimerC2Ev(i3);
+ i2 = i1 + 102868 | 0;
+ i13 = HEAP32[i2 >> 2] | 0;
+ if ((i13 & 1 | 0) != 0) {
+  __ZN16b2ContactManager15FindNewContactsEv(i1 + 102872 | 0);
+  i13 = HEAP32[i2 >> 2] & -2;
+  HEAP32[i2 >> 2] = i13;
+ }
+ HEAP32[i2 >> 2] = i13 | 2;
+ HEAPF32[i5 >> 2] = d9;
+ HEAP32[i5 + 12 >> 2] = i11;
+ HEAP32[i5 + 16 >> 2] = i12;
+ if (d9 > 0.0) {
+  HEAPF32[i5 + 4 >> 2] = 1.0 / d9;
+ } else {
+  HEAPF32[i5 + 4 >> 2] = 0.0;
+ }
+ i11 = i1 + 102988 | 0;
+ HEAPF32[i5 + 8 >> 2] = +HEAPF32[i11 >> 2] * d9;
+ HEAP8[i5 + 20 | 0] = HEAP8[i1 + 102992 | 0] | 0;
+ __ZN7b2TimerC2Ev(i8);
+ __ZN16b2ContactManager7CollideEv(i1 + 102872 | 0);
+ HEAPF32[i1 + 103e3 >> 2] = +__ZNK7b2Timer15GetMillisecondsEv(i8);
+ if ((HEAP8[i1 + 102995 | 0] | 0) != 0 ? +HEAPF32[i5 >> 2] > 0.0 : 0) {
+  __ZN7b2TimerC2Ev(i10);
+  __ZN7b2World5SolveERK10b2TimeStep(i1, i5);
+  HEAPF32[i1 + 103004 >> 2] = +__ZNK7b2Timer15GetMillisecondsEv(i10);
+ }
+ if ((HEAP8[i1 + 102993 | 0] | 0) != 0) {
+  d9 = +HEAPF32[i5 >> 2];
+  if (d9 > 0.0) {
+   __ZN7b2TimerC2Ev(i7);
+   __ZN7b2World8SolveTOIERK10b2TimeStep(i1, i5);
+   HEAPF32[i1 + 103024 >> 2] = +__ZNK7b2Timer15GetMillisecondsEv(i7);
+   i6 = 12;
+  }
+ } else {
+  i6 = 12;
+ }
+ if ((i6 | 0) == 12) {
+  d9 = +HEAPF32[i5 >> 2];
+ }
+ if (d9 > 0.0) {
+  HEAPF32[i11 >> 2] = +HEAPF32[i5 + 4 >> 2];
+ }
+ i5 = HEAP32[i2 >> 2] | 0;
+ if ((i5 & 4 | 0) == 0) {
+  i13 = i5 & -3;
+  HEAP32[i2 >> 2] = i13;
+  d9 = +__ZNK7b2Timer15GetMillisecondsEv(i3);
+  i13 = i1 + 102996 | 0;
+  HEAPF32[i13 >> 2] = d9;
+  STACKTOP = i4;
+  return;
+ }
+ i6 = HEAP32[i1 + 102952 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  i13 = i5 & -3;
+  HEAP32[i2 >> 2] = i13;
+  d9 = +__ZNK7b2Timer15GetMillisecondsEv(i3);
+  i13 = i1 + 102996 | 0;
+  HEAPF32[i13 >> 2] = d9;
+  STACKTOP = i4;
+  return;
+ }
+ do {
+  HEAPF32[i6 + 76 >> 2] = 0.0;
+  HEAPF32[i6 + 80 >> 2] = 0.0;
+  HEAPF32[i6 + 84 >> 2] = 0.0;
+  i6 = HEAP32[i6 + 96 >> 2] | 0;
+ } while ((i6 | 0) != 0);
+ i13 = i5 & -3;
+ HEAP32[i2 >> 2] = i13;
+ d9 = +__ZNK7b2Timer15GetMillisecondsEv(i3);
+ i13 = i1 + 102996 | 0;
+ HEAPF32[i13 >> 2] = d9;
+ STACKTOP = i4;
+ return;
+}
+function __ZL19b2FindMaxSeparationPiPK14b2PolygonShapeRK11b2TransformS2_S5_(i1, i5, i6, i3, i4) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i7 = 0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, i12 = 0, i13 = 0, i14 = 0, d15 = 0.0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0;
+ i2 = STACKTOP;
+ i7 = HEAP32[i5 + 148 >> 2] | 0;
+ d17 = +HEAPF32[i4 + 12 >> 2];
+ d19 = +HEAPF32[i3 + 12 >> 2];
+ d18 = +HEAPF32[i4 + 8 >> 2];
+ d16 = +HEAPF32[i3 + 16 >> 2];
+ d15 = +HEAPF32[i6 + 12 >> 2];
+ d10 = +HEAPF32[i5 + 12 >> 2];
+ d8 = +HEAPF32[i6 + 8 >> 2];
+ d9 = +HEAPF32[i5 + 16 >> 2];
+ d11 = +HEAPF32[i4 >> 2] + (d17 * d19 - d18 * d16) - (+HEAPF32[i6 >> 2] + (d15 * d10 - d8 * d9));
+ d9 = d19 * d18 + d17 * d16 + +HEAPF32[i4 + 4 >> 2] - (d10 * d8 + d15 * d9 + +HEAPF32[i6 + 4 >> 2]);
+ d10 = d15 * d11 + d8 * d9;
+ d8 = d15 * d9 - d11 * d8;
+ if ((i7 | 0) > 0) {
+  i14 = 0;
+  i13 = 0;
+  d9 = -3.4028234663852886e+38;
+  while (1) {
+   d11 = d10 * +HEAPF32[i5 + (i13 << 3) + 84 >> 2] + d8 * +HEAPF32[i5 + (i13 << 3) + 88 >> 2];
+   i12 = d11 > d9;
+   i14 = i12 ? i13 : i14;
+   i13 = i13 + 1 | 0;
+   if ((i13 | 0) == (i7 | 0)) {
+    break;
+   } else {
+    d9 = i12 ? d11 : d9;
+   }
+  }
+ } else {
+  i14 = 0;
+ }
+ d9 = +__ZL16b2EdgeSeparationPK14b2PolygonShapeRK11b2TransformiS1_S4_(i5, i6, i14, i3, i4);
+ i12 = ((i14 | 0) > 0 ? i14 : i7) + -1 | 0;
+ d8 = +__ZL16b2EdgeSeparationPK14b2PolygonShapeRK11b2TransformiS1_S4_(i5, i6, i12, i3, i4);
+ i13 = i14 + 1 | 0;
+ i13 = (i13 | 0) < (i7 | 0) ? i13 : 0;
+ d10 = +__ZL16b2EdgeSeparationPK14b2PolygonShapeRK11b2TransformiS1_S4_(i5, i6, i13, i3, i4);
+ if (d8 > d9 & d8 > d10) {
+  while (1) {
+   i13 = ((i12 | 0) > 0 ? i12 : i7) + -1 | 0;
+   d9 = +__ZL16b2EdgeSeparationPK14b2PolygonShapeRK11b2TransformiS1_S4_(i5, i6, i13, i3, i4);
+   if (d9 > d8) {
+    i12 = i13;
+    d8 = d9;
+   } else {
+    break;
+   }
+  }
+  HEAP32[i1 >> 2] = i12;
+  STACKTOP = i2;
+  return +d8;
+ }
+ if (d10 > d9) {
+  i12 = i13;
+  d8 = d10;
+ } else {
+  d19 = d9;
+  HEAP32[i1 >> 2] = i14;
+  STACKTOP = i2;
+  return +d19;
+ }
+ while (1) {
+  i13 = i12 + 1 | 0;
+  i13 = (i13 | 0) < (i7 | 0) ? i13 : 0;
+  d9 = +__ZL16b2EdgeSeparationPK14b2PolygonShapeRK11b2TransformiS1_S4_(i5, i6, i13, i3, i4);
+  if (d9 > d8) {
+   i12 = i13;
+   d8 = d9;
+  } else {
+   break;
+  }
+ }
+ HEAP32[i1 >> 2] = i12;
+ STACKTOP = i2;
+ return +d8;
+}
+function __ZN9b2Fixture11SynchronizeEP12b2BroadPhaseRK11b2TransformS4_(i10, i8, i7, i2) {
+ i10 = i10 | 0;
+ i8 = i8 | 0;
+ i7 = i7 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i9 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, d23 = 0.0, d24 = 0.0, d25 = 0.0, d26 = 0.0, i27 = 0;
+ i9 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i5 = i9 + 24 | 0;
+ i6 = i9 + 8 | 0;
+ i3 = i9;
+ i4 = i10 + 28 | 0;
+ if ((HEAP32[i4 >> 2] | 0) <= 0) {
+  STACKTOP = i9;
+  return;
+ }
+ i1 = i10 + 24 | 0;
+ i18 = i10 + 12 | 0;
+ i19 = i5 + 4 | 0;
+ i20 = i6 + 4 | 0;
+ i13 = i5 + 8 | 0;
+ i14 = i6 + 8 | 0;
+ i15 = i5 + 12 | 0;
+ i16 = i6 + 12 | 0;
+ i11 = i2 + 4 | 0;
+ i22 = i7 + 4 | 0;
+ i12 = i3 + 4 | 0;
+ i21 = 0;
+ do {
+  i10 = HEAP32[i1 >> 2] | 0;
+  i27 = HEAP32[i18 >> 2] | 0;
+  i17 = i10 + (i21 * 28 | 0) + 20 | 0;
+  FUNCTION_TABLE_viiii[HEAP32[(HEAP32[i27 >> 2] | 0) + 24 >> 2] & 15](i27, i5, i7, HEAP32[i17 >> 2] | 0);
+  i27 = HEAP32[i18 >> 2] | 0;
+  FUNCTION_TABLE_viiii[HEAP32[(HEAP32[i27 >> 2] | 0) + 24 >> 2] & 15](i27, i6, i2, HEAP32[i17 >> 2] | 0);
+  i17 = i10 + (i21 * 28 | 0) | 0;
+  d25 = +HEAPF32[i5 >> 2];
+  d26 = +HEAPF32[i6 >> 2];
+  d24 = +HEAPF32[i19 >> 2];
+  d23 = +HEAPF32[i20 >> 2];
+  d25 = +(d25 < d26 ? d25 : d26);
+  d26 = +(d24 < d23 ? d24 : d23);
+  i27 = i17;
+  HEAPF32[i27 >> 2] = d25;
+  HEAPF32[i27 + 4 >> 2] = d26;
+  d25 = +HEAPF32[i13 >> 2];
+  d26 = +HEAPF32[i14 >> 2];
+  d23 = +HEAPF32[i15 >> 2];
+  d24 = +HEAPF32[i16 >> 2];
+  d25 = +(d25 > d26 ? d25 : d26);
+  d26 = +(d23 > d24 ? d23 : d24);
+  i27 = i10 + (i21 * 28 | 0) + 8 | 0;
+  HEAPF32[i27 >> 2] = d25;
+  HEAPF32[i27 + 4 >> 2] = d26;
+  d26 = +HEAPF32[i11 >> 2] - +HEAPF32[i22 >> 2];
+  HEAPF32[i3 >> 2] = +HEAPF32[i2 >> 2] - +HEAPF32[i7 >> 2];
+  HEAPF32[i12 >> 2] = d26;
+  __ZN12b2BroadPhase9MoveProxyEiRK6b2AABBRK6b2Vec2(i8, HEAP32[i10 + (i21 * 28 | 0) + 24 >> 2] | 0, i17, i3);
+  i21 = i21 + 1 | 0;
+ } while ((i21 | 0) < (HEAP32[i4 >> 2] | 0));
+ STACKTOP = i9;
+ return;
+}
+function __ZN12b2EPCollider24ComputePolygonSeparationEv(i2, i9) {
+ i2 = i2 | 0;
+ i9 = i9 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, d6 = 0.0, d7 = 0.0, i8 = 0, d10 = 0.0, d11 = 0.0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, i20 = 0, d21 = 0.0, d22 = 0.0, d23 = 0.0, d24 = 0.0, d25 = 0.0, d26 = 0.0;
+ i15 = STACKTOP;
+ HEAP32[i2 >> 2] = 0;
+ i3 = i2 + 4 | 0;
+ HEAP32[i3 >> 2] = -1;
+ i4 = i2 + 8 | 0;
+ HEAPF32[i4 >> 2] = -3.4028234663852886e+38;
+ d7 = +HEAPF32[i9 + 216 >> 2];
+ d6 = +HEAPF32[i9 + 212 >> 2];
+ i5 = HEAP32[i9 + 128 >> 2] | 0;
+ if ((i5 | 0) <= 0) {
+  STACKTOP = i15;
+  return;
+ }
+ d17 = +HEAPF32[i9 + 164 >> 2];
+ d18 = +HEAPF32[i9 + 168 >> 2];
+ d11 = +HEAPF32[i9 + 172 >> 2];
+ d10 = +HEAPF32[i9 + 176 >> 2];
+ d16 = +HEAPF32[i9 + 244 >> 2];
+ i12 = i9 + 228 | 0;
+ i13 = i9 + 232 | 0;
+ i14 = i9 + 236 | 0;
+ i1 = i9 + 240 | 0;
+ d19 = -3.4028234663852886e+38;
+ i20 = 0;
+ while (1) {
+  d23 = +HEAPF32[i9 + (i20 << 3) + 64 >> 2];
+  d21 = -d23;
+  d22 = -+HEAPF32[i9 + (i20 << 3) + 68 >> 2];
+  d26 = +HEAPF32[i9 + (i20 << 3) >> 2];
+  d25 = +HEAPF32[i9 + (i20 << 3) + 4 >> 2];
+  d24 = (d26 - d17) * d21 + (d25 - d18) * d22;
+  d25 = (d26 - d11) * d21 + (d25 - d10) * d22;
+  d24 = d24 < d25 ? d24 : d25;
+  if (d24 > d16) {
+   break;
+  }
+  if (!(d7 * d23 + d6 * d22 >= 0.0)) {
+   if (!((d21 - +HEAPF32[i12 >> 2]) * d6 + (d22 - +HEAPF32[i13 >> 2]) * d7 < -.03490658849477768) & d24 > d19) {
+    i8 = 8;
+   }
+  } else {
+   if (!((d21 - +HEAPF32[i14 >> 2]) * d6 + (d22 - +HEAPF32[i1 >> 2]) * d7 < -.03490658849477768) & d24 > d19) {
+    i8 = 8;
+   }
+  }
+  if ((i8 | 0) == 8) {
+   i8 = 0;
+   HEAP32[i2 >> 2] = 2;
+   HEAP32[i3 >> 2] = i20;
+   HEAPF32[i4 >> 2] = d24;
+   d19 = d24;
+  }
+  i20 = i20 + 1 | 0;
+  if ((i20 | 0) >= (i5 | 0)) {
+   i8 = 10;
+   break;
+  }
+ }
+ if ((i8 | 0) == 10) {
+  STACKTOP = i15;
+  return;
+ }
+ HEAP32[i2 >> 2] = 2;
+ HEAP32[i3 >> 2] = i20;
+ HEAPF32[i4 >> 2] = d24;
+ STACKTOP = i15;
+ return;
+}
+function __ZNK11b2EdgeShape7RayCastEP15b2RayCastOutputRK14b2RayCastInputRK11b2Transformi(i17, i1, i2, i18, i3) {
+ i17 = i17 | 0;
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i18 = i18 | 0;
+ i3 = i3 | 0;
+ var d4 = 0.0, d5 = 0.0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, d12 = 0.0, d13 = 0.0, d14 = 0.0, d15 = 0.0, d16 = 0.0;
+ i3 = STACKTOP;
+ d6 = +HEAPF32[i18 >> 2];
+ d7 = +HEAPF32[i2 >> 2] - d6;
+ d9 = +HEAPF32[i18 + 4 >> 2];
+ d4 = +HEAPF32[i2 + 4 >> 2] - d9;
+ d11 = +HEAPF32[i18 + 12 >> 2];
+ d5 = +HEAPF32[i18 + 8 >> 2];
+ d8 = d7 * d11 + d4 * d5;
+ d7 = d11 * d4 - d7 * d5;
+ d6 = +HEAPF32[i2 + 8 >> 2] - d6;
+ d9 = +HEAPF32[i2 + 12 >> 2] - d9;
+ d4 = d11 * d6 + d5 * d9 - d8;
+ d6 = d11 * d9 - d5 * d6 - d7;
+ i18 = i17 + 12 | 0;
+ d5 = +HEAPF32[i18 >> 2];
+ d9 = +HEAPF32[i18 + 4 >> 2];
+ i18 = i17 + 20 | 0;
+ d11 = +HEAPF32[i18 >> 2];
+ d11 = d11 - d5;
+ d12 = +HEAPF32[i18 + 4 >> 2] - d9;
+ d15 = -d11;
+ d10 = d11 * d11 + d12 * d12;
+ d13 = +Math_sqrt(+d10);
+ if (d13 < 1.1920928955078125e-7) {
+  d13 = d12;
+ } else {
+  d16 = 1.0 / d13;
+  d13 = d12 * d16;
+  d15 = d16 * d15;
+ }
+ d14 = (d9 - d7) * d15 + (d5 - d8) * d13;
+ d16 = d6 * d15 + d4 * d13;
+ if (d16 == 0.0) {
+  i18 = 0;
+  STACKTOP = i3;
+  return i18 | 0;
+ }
+ d16 = d14 / d16;
+ if (d16 < 0.0) {
+  i18 = 0;
+  STACKTOP = i3;
+  return i18 | 0;
+ }
+ if (+HEAPF32[i2 + 16 >> 2] < d16 | d10 == 0.0) {
+  i18 = 0;
+  STACKTOP = i3;
+  return i18 | 0;
+ }
+ d12 = (d11 * (d8 + d4 * d16 - d5) + d12 * (d7 + d6 * d16 - d9)) / d10;
+ if (d12 < 0.0 | d12 > 1.0) {
+  i18 = 0;
+  STACKTOP = i3;
+  return i18 | 0;
+ }
+ HEAPF32[i1 + 8 >> 2] = d16;
+ if (d14 > 0.0) {
+  d14 = +-d13;
+  d16 = +-d15;
+  i18 = i1;
+  HEAPF32[i18 >> 2] = d14;
+  HEAPF32[i18 + 4 >> 2] = d16;
+  i18 = 1;
+  STACKTOP = i3;
+  return i18 | 0;
+ } else {
+  d14 = +d13;
+  d16 = +d15;
+  i18 = i1;
+  HEAPF32[i18 >> 2] = d14;
+  HEAPF32[i18 + 4 >> 2] = d16;
+  i18 = 1;
+  STACKTOP = i3;
+  return i18 | 0;
+ }
+ return 0;
+}
+function ___dynamic_cast(i7, i6, i11, i5) {
+ i7 = i7 | 0;
+ i6 = i6 | 0;
+ i11 = i11 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i8 = 0, i9 = 0, i10 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i2 = i1;
+ i3 = HEAP32[i7 >> 2] | 0;
+ i4 = i7 + (HEAP32[i3 + -8 >> 2] | 0) | 0;
+ i3 = HEAP32[i3 + -4 >> 2] | 0;
+ HEAP32[i2 >> 2] = i11;
+ HEAP32[i2 + 4 >> 2] = i7;
+ HEAP32[i2 + 8 >> 2] = i6;
+ HEAP32[i2 + 12 >> 2] = i5;
+ i9 = i2 + 16 | 0;
+ i10 = i2 + 20 | 0;
+ i6 = i2 + 24 | 0;
+ i8 = i2 + 28 | 0;
+ i5 = i2 + 32 | 0;
+ i7 = i2 + 40 | 0;
+ i12 = (i3 | 0) == (i11 | 0);
+ i13 = i9 + 0 | 0;
+ i11 = i13 + 36 | 0;
+ do {
+  HEAP32[i13 >> 2] = 0;
+  i13 = i13 + 4 | 0;
+ } while ((i13 | 0) < (i11 | 0));
+ HEAP16[i9 + 36 >> 1] = 0;
+ HEAP8[i9 + 38 | 0] = 0;
+ if (i12) {
+  HEAP32[i2 + 48 >> 2] = 1;
+  FUNCTION_TABLE_viiiiii[HEAP32[(HEAP32[i3 >> 2] | 0) + 20 >> 2] & 3](i3, i2, i4, i4, 1, 0);
+  i13 = (HEAP32[i6 >> 2] | 0) == 1 ? i4 : 0;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ FUNCTION_TABLE_viiiii[HEAP32[(HEAP32[i3 >> 2] | 0) + 24 >> 2] & 3](i3, i2, i4, 1, 0);
+ i2 = HEAP32[i2 + 36 >> 2] | 0;
+ if ((i2 | 0) == 0) {
+  if ((HEAP32[i7 >> 2] | 0) != 1) {
+   i13 = 0;
+   STACKTOP = i1;
+   return i13 | 0;
+  }
+  if ((HEAP32[i8 >> 2] | 0) != 1) {
+   i13 = 0;
+   STACKTOP = i1;
+   return i13 | 0;
+  }
+  i13 = (HEAP32[i5 >> 2] | 0) == 1 ? HEAP32[i10 >> 2] | 0 : 0;
+  STACKTOP = i1;
+  return i13 | 0;
+ } else if ((i2 | 0) == 1) {
+  if ((HEAP32[i6 >> 2] | 0) != 1) {
+   if ((HEAP32[i7 >> 2] | 0) != 0) {
+    i13 = 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+   if ((HEAP32[i8 >> 2] | 0) != 1) {
+    i13 = 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+   if ((HEAP32[i5 >> 2] | 0) != 1) {
+    i13 = 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+  }
+  i13 = HEAP32[i9 >> 2] | 0;
+  STACKTOP = i1;
+  return i13 | 0;
+ } else {
+  i13 = 0;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ return 0;
+}
+function __ZNK14b2PolygonShape11ComputeMassEP10b2MassDataf(i4, i1, d2) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ d2 = +d2;
+ var i3 = 0, i5 = 0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, i12 = 0, d13 = 0.0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, d18 = 0.0, i19 = 0, d20 = 0.0, d21 = 0.0, d22 = 0.0, d23 = 0.0;
+ i3 = STACKTOP;
+ i5 = HEAP32[i4 + 148 >> 2] | 0;
+ if ((i5 | 0) > 2) {
+  d7 = 0.0;
+  d6 = 0.0;
+  i12 = 0;
+ } else {
+  ___assert_fail(432, 328, 306, 456);
+ }
+ do {
+  d6 = d6 + +HEAPF32[i4 + (i12 << 3) + 20 >> 2];
+  d7 = d7 + +HEAPF32[i4 + (i12 << 3) + 24 >> 2];
+  i12 = i12 + 1 | 0;
+ } while ((i12 | 0) < (i5 | 0));
+ d11 = 1.0 / +(i5 | 0);
+ d6 = d6 * d11;
+ d11 = d7 * d11;
+ i16 = i4 + 20 | 0;
+ i19 = i4 + 24 | 0;
+ d9 = 0.0;
+ d10 = 0.0;
+ d7 = 0.0;
+ d8 = 0.0;
+ i17 = 0;
+ do {
+  d18 = +HEAPF32[i4 + (i17 << 3) + 20 >> 2] - d6;
+  d13 = +HEAPF32[i4 + (i17 << 3) + 24 >> 2] - d11;
+  i17 = i17 + 1 | 0;
+  i12 = (i17 | 0) < (i5 | 0);
+  if (i12) {
+   i14 = i4 + (i17 << 3) + 20 | 0;
+   i15 = i4 + (i17 << 3) + 24 | 0;
+  } else {
+   i14 = i16;
+   i15 = i19;
+  }
+  d21 = +HEAPF32[i14 >> 2] - d6;
+  d20 = +HEAPF32[i15 >> 2] - d11;
+  d22 = d18 * d20 - d13 * d21;
+  d23 = d22 * .5;
+  d8 = d8 + d23;
+  d23 = d23 * .3333333432674408;
+  d9 = d9 + (d18 + d21) * d23;
+  d10 = d10 + (d13 + d20) * d23;
+  d7 = d7 + d22 * .0833333358168602 * (d21 * d21 + (d18 * d18 + d18 * d21) + (d20 * d20 + (d13 * d13 + d13 * d20)));
+ } while (i12);
+ d13 = d8 * d2;
+ HEAPF32[i1 >> 2] = d13;
+ if (d8 > 1.1920928955078125e-7) {
+  d23 = 1.0 / d8;
+  d22 = d9 * d23;
+  d23 = d10 * d23;
+  d20 = d6 + d22;
+  d21 = d11 + d23;
+  d11 = +d20;
+  d18 = +d21;
+  i19 = i1 + 4 | 0;
+  HEAPF32[i19 >> 2] = d11;
+  HEAPF32[i19 + 4 >> 2] = d18;
+  HEAPF32[i1 + 12 >> 2] = d7 * d2 + d13 * (d20 * d20 + d21 * d21 - (d22 * d22 + d23 * d23));
+  STACKTOP = i3;
+  return;
+ } else {
+  ___assert_fail(472, 328, 352, 456);
+ }
+}
+function __ZN16b2ContactManager7DestroyEP9b2Contact(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i3 = STACKTOP;
+ i5 = HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 8 >> 2] | 0;
+ i4 = HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 8 >> 2] | 0;
+ i6 = HEAP32[i1 + 72 >> 2] | 0;
+ if ((i6 | 0) != 0 ? (HEAP32[i2 + 4 >> 2] & 2 | 0) != 0 : 0) {
+  FUNCTION_TABLE_vii[HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] & 15](i6, i2);
+ }
+ i7 = i2 + 8 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ i6 = i2 + 12 | 0;
+ if ((i8 | 0) != 0) {
+  HEAP32[i8 + 12 >> 2] = HEAP32[i6 >> 2];
+ }
+ i8 = HEAP32[i6 >> 2] | 0;
+ if ((i8 | 0) != 0) {
+  HEAP32[i8 + 8 >> 2] = HEAP32[i7 >> 2];
+ }
+ i7 = i1 + 60 | 0;
+ if ((HEAP32[i7 >> 2] | 0) == (i2 | 0)) {
+  HEAP32[i7 >> 2] = HEAP32[i6 >> 2];
+ }
+ i7 = i2 + 24 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ i6 = i2 + 28 | 0;
+ if ((i8 | 0) != 0) {
+  HEAP32[i8 + 12 >> 2] = HEAP32[i6 >> 2];
+ }
+ i8 = HEAP32[i6 >> 2] | 0;
+ if ((i8 | 0) != 0) {
+  HEAP32[i8 + 8 >> 2] = HEAP32[i7 >> 2];
+ }
+ i5 = i5 + 112 | 0;
+ if ((i2 + 16 | 0) == (HEAP32[i5 >> 2] | 0)) {
+  HEAP32[i5 >> 2] = HEAP32[i6 >> 2];
+ }
+ i6 = i2 + 40 | 0;
+ i7 = HEAP32[i6 >> 2] | 0;
+ i5 = i2 + 44 | 0;
+ if ((i7 | 0) != 0) {
+  HEAP32[i7 + 12 >> 2] = HEAP32[i5 >> 2];
+ }
+ i7 = HEAP32[i5 >> 2] | 0;
+ if ((i7 | 0) != 0) {
+  HEAP32[i7 + 8 >> 2] = HEAP32[i6 >> 2];
+ }
+ i4 = i4 + 112 | 0;
+ if ((i2 + 32 | 0) != (HEAP32[i4 >> 2] | 0)) {
+  i8 = i1 + 76 | 0;
+  i8 = HEAP32[i8 >> 2] | 0;
+  __ZN9b2Contact7DestroyEPS_P16b2BlockAllocator(i2, i8);
+  i8 = i1 + 64 | 0;
+  i7 = HEAP32[i8 >> 2] | 0;
+  i7 = i7 + -1 | 0;
+  HEAP32[i8 >> 2] = i7;
+  STACKTOP = i3;
+  return;
+ }
+ HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+ i8 = i1 + 76 | 0;
+ i8 = HEAP32[i8 >> 2] | 0;
+ __ZN9b2Contact7DestroyEPS_P16b2BlockAllocator(i2, i8);
+ i8 = i1 + 64 | 0;
+ i7 = HEAP32[i8 >> 2] | 0;
+ i7 = i7 + -1 | 0;
+ HEAP32[i8 >> 2] = i7;
+ STACKTOP = i3;
+ return;
+}
+function __ZNK10__cxxabiv120__si_class_type_info16search_below_dstEPNS_19__dynamic_cast_infoEPKvib(i6, i3, i4, i8, i7) {
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i8 = i8 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ if ((i6 | 0) == (HEAP32[i3 + 8 >> 2] | 0)) {
+  if ((HEAP32[i3 + 4 >> 2] | 0) != (i4 | 0)) {
+   STACKTOP = i1;
+   return;
+  }
+  i2 = i3 + 28 | 0;
+  if ((HEAP32[i2 >> 2] | 0) == 1) {
+   STACKTOP = i1;
+   return;
+  }
+  HEAP32[i2 >> 2] = i8;
+  STACKTOP = i1;
+  return;
+ }
+ if ((i6 | 0) != (HEAP32[i3 >> 2] | 0)) {
+  i9 = HEAP32[i6 + 8 >> 2] | 0;
+  FUNCTION_TABLE_viiiii[HEAP32[(HEAP32[i9 >> 2] | 0) + 24 >> 2] & 3](i9, i3, i4, i8, i7);
+  STACKTOP = i1;
+  return;
+ }
+ if ((HEAP32[i3 + 16 >> 2] | 0) != (i4 | 0) ? (i5 = i3 + 20 | 0, (HEAP32[i5 >> 2] | 0) != (i4 | 0)) : 0) {
+  HEAP32[i3 + 32 >> 2] = i8;
+  i8 = i3 + 44 | 0;
+  if ((HEAP32[i8 >> 2] | 0) == 4) {
+   STACKTOP = i1;
+   return;
+  }
+  i9 = i3 + 52 | 0;
+  HEAP8[i9] = 0;
+  i10 = i3 + 53 | 0;
+  HEAP8[i10] = 0;
+  i6 = HEAP32[i6 + 8 >> 2] | 0;
+  FUNCTION_TABLE_viiiiii[HEAP32[(HEAP32[i6 >> 2] | 0) + 20 >> 2] & 3](i6, i3, i4, i4, 1, i7);
+  if ((HEAP8[i10] | 0) != 0) {
+   if ((HEAP8[i9] | 0) == 0) {
+    i6 = 1;
+    i2 = 13;
+   }
+  } else {
+   i6 = 0;
+   i2 = 13;
+  }
+  do {
+   if ((i2 | 0) == 13) {
+    HEAP32[i5 >> 2] = i4;
+    i10 = i3 + 40 | 0;
+    HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + 1;
+    if ((HEAP32[i3 + 36 >> 2] | 0) == 1 ? (HEAP32[i3 + 24 >> 2] | 0) == 2 : 0) {
+     HEAP8[i3 + 54 | 0] = 1;
+     if (i6) {
+      break;
+     }
+    } else {
+     i2 = 16;
+    }
+    if ((i2 | 0) == 16 ? i6 : 0) {
+     break;
+    }
+    HEAP32[i8 >> 2] = 4;
+    STACKTOP = i1;
+    return;
+   }
+  } while (0);
+  HEAP32[i8 >> 2] = 3;
+  STACKTOP = i1;
+  return;
+ }
+ if ((i8 | 0) != 1) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP32[i3 + 32 >> 2] = 1;
+ STACKTOP = i1;
+ return;
+}
+function __ZN16b2BlockAllocator8AllocateEi(i4, i2) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i1 = STACKTOP;
+ if ((i2 | 0) == 0) {
+  i9 = 0;
+  STACKTOP = i1;
+  return i9 | 0;
+ }
+ if ((i2 | 0) <= 0) {
+  ___assert_fail(1376, 1312, 104, 1392);
+ }
+ if ((i2 | 0) > 640) {
+  i9 = __Z7b2Alloci(i2) | 0;
+  STACKTOP = i1;
+  return i9 | 0;
+ }
+ i9 = HEAP8[632 + i2 | 0] | 0;
+ i5 = i9 & 255;
+ if (!((i9 & 255) < 14)) {
+  ___assert_fail(1408, 1312, 112, 1392);
+ }
+ i2 = i4 + (i5 << 2) + 12 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ if ((i3 | 0) != 0) {
+  HEAP32[i2 >> 2] = HEAP32[i3 >> 2];
+  i9 = i3;
+  STACKTOP = i1;
+  return i9 | 0;
+ }
+ i3 = i4 + 4 | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ i7 = i4 + 8 | 0;
+ if ((i6 | 0) == (HEAP32[i7 >> 2] | 0)) {
+  i9 = HEAP32[i4 >> 2] | 0;
+  i6 = i6 + 128 | 0;
+  HEAP32[i7 >> 2] = i6;
+  i6 = __Z7b2Alloci(i6 << 3) | 0;
+  HEAP32[i4 >> 2] = i6;
+  _memcpy(i6 | 0, i9 | 0, HEAP32[i3 >> 2] << 3 | 0) | 0;
+  _memset((HEAP32[i4 >> 2] | 0) + (HEAP32[i3 >> 2] << 3) | 0, 0, 1024) | 0;
+  __Z6b2FreePv(i9);
+  i6 = HEAP32[i3 >> 2] | 0;
+ }
+ i9 = HEAP32[i4 >> 2] | 0;
+ i7 = __Z7b2Alloci(16384) | 0;
+ i4 = i9 + (i6 << 3) + 4 | 0;
+ HEAP32[i4 >> 2] = i7;
+ i5 = HEAP32[576 + (i5 << 2) >> 2] | 0;
+ HEAP32[i9 + (i6 << 3) >> 2] = i5;
+ i6 = 16384 / (i5 | 0) | 0;
+ if ((Math_imul(i6, i5) | 0) >= 16385) {
+  ___assert_fail(1448, 1312, 140, 1392);
+ }
+ i6 = i6 + -1 | 0;
+ if ((i6 | 0) > 0) {
+  i9 = 0;
+  while (1) {
+   i8 = i9 + 1 | 0;
+   HEAP32[i7 + (Math_imul(i9, i5) | 0) >> 2] = i7 + (Math_imul(i8, i5) | 0);
+   i7 = HEAP32[i4 >> 2] | 0;
+   if ((i8 | 0) == (i6 | 0)) {
+    break;
+   } else {
+    i9 = i8;
+   }
+  }
+ }
+ HEAP32[i7 + (Math_imul(i6, i5) | 0) >> 2] = 0;
+ HEAP32[i2 >> 2] = HEAP32[HEAP32[i4 >> 2] >> 2];
+ HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + 1;
+ i9 = HEAP32[i4 >> 2] | 0;
+ STACKTOP = i1;
+ return i9 | 0;
+}
+function __ZN9b2Contact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i4, i5, i1, i3, i6) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ if ((HEAP8[4200] | 0) == 0) {
+  HEAP32[1002] = 3;
+  HEAP32[4012 >> 2] = 3;
+  HEAP8[4016 | 0] = 1;
+  HEAP32[4104 >> 2] = 4;
+  HEAP32[4108 >> 2] = 4;
+  HEAP8[4112 | 0] = 1;
+  HEAP32[4032 >> 2] = 4;
+  HEAP32[4036 >> 2] = 4;
+  HEAP8[4040 | 0] = 0;
+  HEAP32[4128 >> 2] = 5;
+  HEAP32[4132 >> 2] = 5;
+  HEAP8[4136 | 0] = 1;
+  HEAP32[4056 >> 2] = 6;
+  HEAP32[4060 >> 2] = 6;
+  HEAP8[4064 | 0] = 1;
+  HEAP32[4020 >> 2] = 6;
+  HEAP32[4024 >> 2] = 6;
+  HEAP8[4028 | 0] = 0;
+  HEAP32[4080 >> 2] = 7;
+  HEAP32[4084 >> 2] = 7;
+  HEAP8[4088 | 0] = 1;
+  HEAP32[4116 >> 2] = 7;
+  HEAP32[4120 >> 2] = 7;
+  HEAP8[4124 | 0] = 0;
+  HEAP32[4152 >> 2] = 8;
+  HEAP32[4156 >> 2] = 8;
+  HEAP8[4160 | 0] = 1;
+  HEAP32[4044 >> 2] = 8;
+  HEAP32[4048 >> 2] = 8;
+  HEAP8[4052 | 0] = 0;
+  HEAP32[4176 >> 2] = 9;
+  HEAP32[4180 >> 2] = 9;
+  HEAP8[4184 | 0] = 1;
+  HEAP32[4140 >> 2] = 9;
+  HEAP32[4144 >> 2] = 9;
+  HEAP8[4148 | 0] = 0;
+  HEAP8[4200] = 1;
+ }
+ i7 = HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 4 >> 2] | 0;
+ i8 = HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 4 >> 2] | 0;
+ if (!(i7 >>> 0 < 4)) {
+  ___assert_fail(4208, 4256, 80, 4344);
+ }
+ if (!(i8 >>> 0 < 4)) {
+  ___assert_fail(4296, 4256, 81, 4344);
+ }
+ i9 = HEAP32[4008 + (i7 * 48 | 0) + (i8 * 12 | 0) >> 2] | 0;
+ if ((i9 | 0) == 0) {
+  i9 = 0;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ if ((HEAP8[4008 + (i7 * 48 | 0) + (i8 * 12 | 0) + 8 | 0] | 0) == 0) {
+  i9 = FUNCTION_TABLE_iiiiii[i9 & 15](i1, i3, i4, i5, i6) | 0;
+  STACKTOP = i2;
+  return i9 | 0;
+ } else {
+  i9 = FUNCTION_TABLE_iiiiii[i9 & 15](i4, i5, i1, i3, i6) | 0;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ return 0;
+}
+function __ZN13b2DynamicTree9MoveProxyEiRK6b2AABBRK6b2Vec2(i1, i2, i13, i9) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i13 = i13 | 0;
+ i9 = i9 | 0;
+ var i3 = 0, i4 = 0, d5 = 0.0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d10 = 0.0, d11 = 0.0, i12 = 0;
+ i4 = STACKTOP;
+ if (!((i2 | 0) > -1)) {
+  ___assert_fail(3072, 2944, 135, 3152);
+ }
+ if ((HEAP32[i1 + 12 >> 2] | 0) <= (i2 | 0)) {
+  ___assert_fail(3072, 2944, 135, 3152);
+ }
+ i3 = i1 + 4 | 0;
+ i12 = HEAP32[i3 >> 2] | 0;
+ if (!((HEAP32[i12 + (i2 * 36 | 0) + 24 >> 2] | 0) == -1)) {
+  ___assert_fail(3120, 2944, 137, 3152);
+ }
+ if (((+HEAPF32[i12 + (i2 * 36 | 0) >> 2] <= +HEAPF32[i13 >> 2] ? +HEAPF32[i12 + (i2 * 36 | 0) + 4 >> 2] <= +HEAPF32[i13 + 4 >> 2] : 0) ? +HEAPF32[i13 + 8 >> 2] <= +HEAPF32[i12 + (i2 * 36 | 0) + 8 >> 2] : 0) ? +HEAPF32[i13 + 12 >> 2] <= +HEAPF32[i12 + (i2 * 36 | 0) + 12 >> 2] : 0) {
+  i13 = 0;
+  STACKTOP = i4;
+  return i13 | 0;
+ }
+ __ZN13b2DynamicTree10RemoveLeafEi(i1, i2);
+ i12 = i13;
+ d6 = +HEAPF32[i12 >> 2];
+ d8 = +HEAPF32[i12 + 4 >> 2];
+ i13 = i13 + 8 | 0;
+ d10 = +HEAPF32[i13 >> 2];
+ d6 = d6 + -.10000000149011612;
+ d8 = d8 + -.10000000149011612;
+ d10 = d10 + .10000000149011612;
+ d5 = +HEAPF32[i13 + 4 >> 2] + .10000000149011612;
+ d11 = +HEAPF32[i9 >> 2] * 2.0;
+ d7 = +HEAPF32[i9 + 4 >> 2] * 2.0;
+ if (d11 < 0.0) {
+  d6 = d6 + d11;
+ } else {
+  d10 = d11 + d10;
+ }
+ if (d7 < 0.0) {
+  d8 = d8 + d7;
+ } else {
+  d5 = d7 + d5;
+ }
+ i13 = HEAP32[i3 >> 2] | 0;
+ d7 = +d6;
+ d11 = +d8;
+ i12 = i13 + (i2 * 36 | 0) | 0;
+ HEAPF32[i12 >> 2] = d7;
+ HEAPF32[i12 + 4 >> 2] = d11;
+ d10 = +d10;
+ d11 = +d5;
+ i13 = i13 + (i2 * 36 | 0) + 8 | 0;
+ HEAPF32[i13 >> 2] = d10;
+ HEAPF32[i13 + 4 >> 2] = d11;
+ __ZN13b2DynamicTree10InsertLeafEi(i1, i2);
+ i13 = 1;
+ STACKTOP = i4;
+ return i13 | 0;
+}
+function __ZNK9b2Simplex16GetWitnessPointsEP6b2Vec2S1_(i1, i4, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, d6 = 0.0, d7 = 0.0, d8 = 0.0, i9 = 0, i10 = 0, d11 = 0.0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i1 + 108 >> 2] | 0;
+ if ((i3 | 0) == 2) {
+  i9 = i1 + 24 | 0;
+  d7 = +HEAPF32[i9 >> 2];
+  i3 = i1 + 60 | 0;
+  d8 = +HEAPF32[i3 >> 2];
+  d6 = +(d7 * +HEAPF32[i1 >> 2] + d8 * +HEAPF32[i1 + 36 >> 2]);
+  d8 = +(d7 * +HEAPF32[i1 + 4 >> 2] + d8 * +HEAPF32[i1 + 40 >> 2]);
+  HEAPF32[i4 >> 2] = d6;
+  HEAPF32[i4 + 4 >> 2] = d8;
+  d8 = +HEAPF32[i9 >> 2];
+  d6 = +HEAPF32[i3 >> 2];
+  d7 = +(d8 * +HEAPF32[i1 + 8 >> 2] + d6 * +HEAPF32[i1 + 44 >> 2]);
+  d6 = +(d8 * +HEAPF32[i1 + 12 >> 2] + d6 * +HEAPF32[i1 + 48 >> 2]);
+  HEAPF32[i5 >> 2] = d7;
+  HEAPF32[i5 + 4 >> 2] = d6;
+  STACKTOP = i2;
+  return;
+ } else if ((i3 | 0) == 1) {
+  i10 = i1;
+  i9 = HEAP32[i10 + 4 >> 2] | 0;
+  i3 = i4;
+  HEAP32[i3 >> 2] = HEAP32[i10 >> 2];
+  HEAP32[i3 + 4 >> 2] = i9;
+  i3 = i1 + 8 | 0;
+  i4 = HEAP32[i3 + 4 >> 2] | 0;
+  i9 = i5;
+  HEAP32[i9 >> 2] = HEAP32[i3 >> 2];
+  HEAP32[i9 + 4 >> 2] = i4;
+  STACKTOP = i2;
+  return;
+ } else if ((i3 | 0) == 0) {
+  ___assert_fail(2712, 2672, 217, 2752);
+ } else if ((i3 | 0) == 3) {
+  d11 = +HEAPF32[i1 + 24 >> 2];
+  d6 = +HEAPF32[i1 + 60 >> 2];
+  d8 = +HEAPF32[i1 + 96 >> 2];
+  d7 = +(d11 * +HEAPF32[i1 >> 2] + d6 * +HEAPF32[i1 + 36 >> 2] + d8 * +HEAPF32[i1 + 72 >> 2]);
+  d8 = +(d11 * +HEAPF32[i1 + 4 >> 2] + d6 * +HEAPF32[i1 + 40 >> 2] + d8 * +HEAPF32[i1 + 76 >> 2]);
+  i10 = i4;
+  HEAPF32[i10 >> 2] = d7;
+  HEAPF32[i10 + 4 >> 2] = d8;
+  i10 = i5;
+  HEAPF32[i10 >> 2] = d7;
+  HEAPF32[i10 + 4 >> 2] = d8;
+  STACKTOP = i2;
+  return;
+ } else {
+  ___assert_fail(2712, 2672, 236, 2752);
+ }
+}
+function __ZNK12b2ChainShape12GetChildEdgeEP11b2EdgeShapei(i4, i3, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i2 = STACKTOP;
+ if (!((i1 | 0) > -1)) {
+  ___assert_fail(6832, 6792, 89, 6872);
+ }
+ i5 = i4 + 16 | 0;
+ if (((HEAP32[i5 >> 2] | 0) + -1 | 0) <= (i1 | 0)) {
+  ___assert_fail(6832, 6792, 89, 6872);
+ }
+ HEAP32[i3 + 4 >> 2] = 1;
+ HEAPF32[i3 + 8 >> 2] = +HEAPF32[i4 + 8 >> 2];
+ i6 = i4 + 12 | 0;
+ i7 = (HEAP32[i6 >> 2] | 0) + (i1 << 3) | 0;
+ i8 = HEAP32[i7 + 4 >> 2] | 0;
+ i9 = i3 + 12 | 0;
+ HEAP32[i9 >> 2] = HEAP32[i7 >> 2];
+ HEAP32[i9 + 4 >> 2] = i8;
+ i9 = (HEAP32[i6 >> 2] | 0) + (i1 + 1 << 3) | 0;
+ i8 = HEAP32[i9 + 4 >> 2] | 0;
+ i7 = i3 + 20 | 0;
+ HEAP32[i7 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i7 + 4 >> 2] = i8;
+ i7 = i3 + 28 | 0;
+ if ((i1 | 0) > 0) {
+  i10 = (HEAP32[i6 >> 2] | 0) + (i1 + -1 << 3) | 0;
+  i8 = HEAP32[i10 + 4 >> 2] | 0;
+  i9 = i7;
+  HEAP32[i9 >> 2] = HEAP32[i10 >> 2];
+  HEAP32[i9 + 4 >> 2] = i8;
+  HEAP8[i3 + 44 | 0] = 1;
+ } else {
+  i8 = i4 + 20 | 0;
+  i9 = HEAP32[i8 + 4 >> 2] | 0;
+  i10 = i7;
+  HEAP32[i10 >> 2] = HEAP32[i8 >> 2];
+  HEAP32[i10 + 4 >> 2] = i9;
+  HEAP8[i3 + 44 | 0] = HEAP8[i4 + 36 | 0] | 0;
+ }
+ i7 = i3 + 36 | 0;
+ if (((HEAP32[i5 >> 2] | 0) + -2 | 0) > (i1 | 0)) {
+  i8 = (HEAP32[i6 >> 2] | 0) + (i1 + 2 << 3) | 0;
+  i9 = HEAP32[i8 + 4 >> 2] | 0;
+  i10 = i7;
+  HEAP32[i10 >> 2] = HEAP32[i8 >> 2];
+  HEAP32[i10 + 4 >> 2] = i9;
+  HEAP8[i3 + 45 | 0] = 1;
+  STACKTOP = i2;
+  return;
+ } else {
+  i8 = i4 + 28 | 0;
+  i9 = HEAP32[i8 + 4 >> 2] | 0;
+  i10 = i7;
+  HEAP32[i10 >> 2] = HEAP32[i8 >> 2];
+  HEAP32[i10 + 4 >> 2] = i9;
+  HEAP8[i3 + 45 | 0] = HEAP8[i4 + 37 | 0] | 0;
+  STACKTOP = i2;
+  return;
+ }
+}
+function __ZN15b2DistanceProxy3SetEPK7b2Shapei(i3, i1, i5) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 4 >> 2] | 0;
+ if ((i4 | 0) == 1) {
+  HEAP32[i3 + 16 >> 2] = i1 + 12;
+  HEAP32[i3 + 20 >> 2] = 2;
+  HEAPF32[i3 + 24 >> 2] = +HEAPF32[i1 + 8 >> 2];
+  STACKTOP = i2;
+  return;
+ } else if ((i4 | 0) == 3) {
+  if (!((i5 | 0) > -1)) {
+   ___assert_fail(2632, 2672, 53, 2704);
+  }
+  i4 = i1 + 16 | 0;
+  if ((HEAP32[i4 >> 2] | 0) <= (i5 | 0)) {
+   ___assert_fail(2632, 2672, 53, 2704);
+  }
+  i7 = i1 + 12 | 0;
+  i9 = (HEAP32[i7 >> 2] | 0) + (i5 << 3) | 0;
+  i8 = HEAP32[i9 + 4 >> 2] | 0;
+  i6 = i3;
+  HEAP32[i6 >> 2] = HEAP32[i9 >> 2];
+  HEAP32[i6 + 4 >> 2] = i8;
+  i6 = i5 + 1 | 0;
+  i5 = i3 + 8 | 0;
+  i7 = HEAP32[i7 >> 2] | 0;
+  if ((i6 | 0) < (HEAP32[i4 >> 2] | 0)) {
+   i7 = i7 + (i6 << 3) | 0;
+   i8 = HEAP32[i7 + 4 >> 2] | 0;
+   i9 = i5;
+   HEAP32[i9 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i9 + 4 >> 2] = i8;
+  } else {
+   i8 = HEAP32[i7 + 4 >> 2] | 0;
+   i9 = i5;
+   HEAP32[i9 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i9 + 4 >> 2] = i8;
+  }
+  HEAP32[i3 + 16 >> 2] = i3;
+  HEAP32[i3 + 20 >> 2] = 2;
+  HEAPF32[i3 + 24 >> 2] = +HEAPF32[i1 + 8 >> 2];
+  STACKTOP = i2;
+  return;
+ } else if ((i4 | 0) == 2) {
+  HEAP32[i3 + 16 >> 2] = i1 + 20;
+  HEAP32[i3 + 20 >> 2] = HEAP32[i1 + 148 >> 2];
+  HEAPF32[i3 + 24 >> 2] = +HEAPF32[i1 + 8 >> 2];
+  STACKTOP = i2;
+  return;
+ } else if ((i4 | 0) == 0) {
+  HEAP32[i3 + 16 >> 2] = i1 + 12;
+  HEAP32[i3 + 20 >> 2] = 1;
+  HEAPF32[i3 + 24 >> 2] = +HEAPF32[i1 + 8 >> 2];
+  STACKTOP = i2;
+  return;
+ } else {
+  ___assert_fail(2712, 2672, 81, 2704);
+ }
+}
+function __ZL16b2EdgeSeparationPK14b2PolygonShapeRK11b2TransformiS1_S4_(i2, i7, i4, i5, i6) {
+ i2 = i2 | 0;
+ i7 = i7 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var d1 = 0.0, d3 = 0.0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, i12 = 0, i13 = 0, d14 = 0.0, d15 = 0.0, d16 = 0.0, d17 = 0.0, i18 = 0, i19 = 0, i20 = 0;
+ i12 = STACKTOP;
+ i13 = HEAP32[i5 + 148 >> 2] | 0;
+ if (!((i4 | 0) > -1)) {
+  ___assert_fail(5640, 5688, 32, 5752);
+ }
+ if ((HEAP32[i2 + 148 >> 2] | 0) <= (i4 | 0)) {
+  ___assert_fail(5640, 5688, 32, 5752);
+ }
+ d11 = +HEAPF32[i7 + 12 >> 2];
+ d9 = +HEAPF32[i2 + (i4 << 3) + 84 >> 2];
+ d1 = +HEAPF32[i7 + 8 >> 2];
+ d3 = +HEAPF32[i2 + (i4 << 3) + 88 >> 2];
+ d8 = d11 * d9 - d1 * d3;
+ d3 = d9 * d1 + d11 * d3;
+ d9 = +HEAPF32[i6 + 12 >> 2];
+ d10 = +HEAPF32[i6 + 8 >> 2];
+ d16 = d9 * d8 + d10 * d3;
+ d14 = d9 * d3 - d8 * d10;
+ if ((i13 | 0) > 0) {
+  i19 = 0;
+  i20 = 0;
+  d15 = 3.4028234663852886e+38;
+  while (1) {
+   d17 = d16 * +HEAPF32[i5 + (i19 << 3) + 20 >> 2] + d14 * +HEAPF32[i5 + (i19 << 3) + 24 >> 2];
+   i18 = d17 < d15;
+   i20 = i18 ? i19 : i20;
+   i19 = i19 + 1 | 0;
+   if ((i19 | 0) == (i13 | 0)) {
+    break;
+   } else {
+    d15 = i18 ? d17 : d15;
+   }
+  }
+ } else {
+  i20 = 0;
+ }
+ d16 = +HEAPF32[i2 + (i4 << 3) + 20 >> 2];
+ d17 = +HEAPF32[i2 + (i4 << 3) + 24 >> 2];
+ d14 = +HEAPF32[i5 + (i20 << 3) + 20 >> 2];
+ d15 = +HEAPF32[i5 + (i20 << 3) + 24 >> 2];
+ STACKTOP = i12;
+ return +(d8 * (+HEAPF32[i6 >> 2] + (d9 * d14 - d10 * d15) - (+HEAPF32[i7 >> 2] + (d11 * d16 - d1 * d17))) + d3 * (d14 * d10 + d9 * d15 + +HEAPF32[i6 + 4 >> 2] - (d16 * d1 + d11 * d17 + +HEAPF32[i7 + 4 >> 2])));
+}
+function __Z4iterv() {
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, d5 = 0.0, d6 = 0.0, d7 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i2 = i1;
+ i3 = i1 + 32 | 0;
+ i4 = HEAP32[16] | 0;
+ if ((i4 | 0) >= (HEAP32[4] | 0)) {
+  HEAP32[16] = i4 + 1;
+  __Z7measurePl(i3, HEAP32[8] | 0);
+  d7 = +HEAPF32[i3 + 4 >> 2];
+  d6 = +(HEAP32[10] | 0) / 1.0e6 * 1.0e3;
+  d5 = +(HEAP32[12] | 0) / 1.0e6 * 1.0e3;
+  HEAPF64[tempDoublePtr >> 3] = +HEAPF32[i3 >> 2];
+  HEAP32[i2 >> 2] = HEAP32[tempDoublePtr >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+  i4 = i2 + 8 | 0;
+  HEAPF64[tempDoublePtr >> 3] = d7;
+  HEAP32[i4 >> 2] = HEAP32[tempDoublePtr >> 2];
+  HEAP32[i4 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+  i4 = i2 + 16 | 0;
+  HEAPF64[tempDoublePtr >> 3] = d6;
+  HEAP32[i4 >> 2] = HEAP32[tempDoublePtr >> 2];
+  HEAP32[i4 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+  i4 = i2 + 24 | 0;
+  HEAPF64[tempDoublePtr >> 3] = d5;
+  HEAP32[i4 >> 2] = HEAP32[tempDoublePtr >> 2];
+  HEAP32[i4 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+  _printf(96, i2 | 0) | 0;
+  _emscripten_run_script(152);
+  if ((HEAP32[18] | 0) == 0) {
+   STACKTOP = i1;
+   return;
+  }
+  _emscripten_cancel_main_loop();
+  STACKTOP = i1;
+  return;
+ }
+ i3 = _clock() | 0;
+ __ZN7b2World4StepEfii(HEAP32[6] | 0, .01666666753590107, 3, 3);
+ i3 = (_clock() | 0) - i3 | 0;
+ i2 = HEAP32[16] | 0;
+ HEAP32[(HEAP32[8] | 0) + (i2 << 2) >> 2] = i3;
+ if ((i3 | 0) < (HEAP32[10] | 0)) {
+  HEAP32[10] = i3;
+ }
+ if ((i3 | 0) > (HEAP32[12] | 0)) {
+  HEAP32[12] = i3;
+ }
+ HEAP32[16] = i2 + 1;
+ STACKTOP = i1;
+ return;
+}
+function __ZN13b2DynamicTree12AllocateNodeEv(i5) {
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i2 = i5 + 16 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ if ((i3 | 0) == -1) {
+  i4 = i5 + 8 | 0;
+  i6 = HEAP32[i4 >> 2] | 0;
+  i3 = i5 + 12 | 0;
+  if ((i6 | 0) != (HEAP32[i3 >> 2] | 0)) {
+   ___assert_fail(2912, 2944, 61, 2984);
+  }
+  i5 = i5 + 4 | 0;
+  i7 = HEAP32[i5 >> 2] | 0;
+  HEAP32[i3 >> 2] = i6 << 1;
+  i6 = __Z7b2Alloci(i6 * 72 | 0) | 0;
+  HEAP32[i5 >> 2] = i6;
+  _memcpy(i6 | 0, i7 | 0, (HEAP32[i4 >> 2] | 0) * 36 | 0) | 0;
+  __Z6b2FreePv(i7);
+  i6 = HEAP32[i4 >> 2] | 0;
+  i7 = (HEAP32[i3 >> 2] | 0) + -1 | 0;
+  i5 = HEAP32[i5 >> 2] | 0;
+  if ((i6 | 0) < (i7 | 0)) {
+   i7 = i6;
+   while (1) {
+    i6 = i7 + 1 | 0;
+    HEAP32[i5 + (i7 * 36 | 0) + 20 >> 2] = i6;
+    HEAP32[i5 + (i7 * 36 | 0) + 32 >> 2] = -1;
+    i7 = (HEAP32[i3 >> 2] | 0) + -1 | 0;
+    if ((i6 | 0) < (i7 | 0)) {
+     i7 = i6;
+    } else {
+     break;
+    }
+   }
+  }
+  HEAP32[i5 + (i7 * 36 | 0) + 20 >> 2] = -1;
+  HEAP32[i5 + (((HEAP32[i3 >> 2] | 0) + -1 | 0) * 36 | 0) + 32 >> 2] = -1;
+  i3 = HEAP32[i4 >> 2] | 0;
+  HEAP32[i2 >> 2] = i3;
+ } else {
+  i4 = i5 + 8 | 0;
+  i5 = HEAP32[i5 + 4 >> 2] | 0;
+ }
+ i7 = i5 + (i3 * 36 | 0) + 20 | 0;
+ HEAP32[i2 >> 2] = HEAP32[i7 >> 2];
+ HEAP32[i7 >> 2] = -1;
+ HEAP32[i5 + (i3 * 36 | 0) + 24 >> 2] = -1;
+ HEAP32[i5 + (i3 * 36 | 0) + 28 >> 2] = -1;
+ HEAP32[i5 + (i3 * 36 | 0) + 32 >> 2] = 0;
+ HEAP32[i5 + (i3 * 36 | 0) + 16 >> 2] = 0;
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + 1;
+ STACKTOP = i1;
+ return i3 | 0;
+}
+function __ZN9b2Fixture6CreateEP16b2BlockAllocatorP6b2BodyPK12b2FixtureDef(i1, i5, i4, i3) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i6 = 0, i7 = 0, d8 = 0.0;
+ i2 = STACKTOP;
+ HEAP32[i1 + 40 >> 2] = HEAP32[i3 + 4 >> 2];
+ HEAPF32[i1 + 16 >> 2] = +HEAPF32[i3 + 8 >> 2];
+ HEAPF32[i1 + 20 >> 2] = +HEAPF32[i3 + 12 >> 2];
+ HEAP32[i1 + 8 >> 2] = i4;
+ HEAP32[i1 + 4 >> 2] = 0;
+ i4 = i1 + 32 | 0;
+ i6 = i3 + 22 | 0;
+ HEAP16[i4 + 0 >> 1] = HEAP16[i6 + 0 >> 1] | 0;
+ HEAP16[i4 + 2 >> 1] = HEAP16[i6 + 2 >> 1] | 0;
+ HEAP16[i4 + 4 >> 1] = HEAP16[i6 + 4 >> 1] | 0;
+ HEAP8[i1 + 38 | 0] = HEAP8[i3 + 20 | 0] | 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ i4 = FUNCTION_TABLE_iii[HEAP32[(HEAP32[i4 >> 2] | 0) + 8 >> 2] & 3](i4, i5) | 0;
+ HEAP32[i1 + 12 >> 2] = i4;
+ i4 = FUNCTION_TABLE_ii[HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] & 3](i4) | 0;
+ i6 = __ZN16b2BlockAllocator8AllocateEi(i5, i4 * 28 | 0) | 0;
+ i5 = i1 + 24 | 0;
+ HEAP32[i5 >> 2] = i6;
+ if ((i4 | 0) > 0) {
+  i7 = 0;
+ } else {
+  i7 = i1 + 28 | 0;
+  HEAP32[i7 >> 2] = 0;
+  i7 = i3 + 16 | 0;
+  d8 = +HEAPF32[i7 >> 2];
+  HEAPF32[i1 >> 2] = d8;
+  STACKTOP = i2;
+  return;
+ }
+ do {
+  HEAP32[i6 + (i7 * 28 | 0) + 16 >> 2] = 0;
+  i6 = HEAP32[i5 >> 2] | 0;
+  HEAP32[i6 + (i7 * 28 | 0) + 24 >> 2] = -1;
+  i7 = i7 + 1 | 0;
+ } while ((i7 | 0) != (i4 | 0));
+ i7 = i1 + 28 | 0;
+ HEAP32[i7 >> 2] = 0;
+ i7 = i3 + 16 | 0;
+ d8 = +HEAPF32[i7 >> 2];
+ HEAPF32[i1 >> 2] = d8;
+ STACKTOP = i2;
+ return;
+}
+function __Z19b2ClipSegmentToLineP12b2ClipVertexPKS_RK6b2Vec2fi(i4, i1, i5, d9, i2) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ d9 = +d9;
+ i2 = i2 | 0;
+ var i3 = 0, i6 = 0, d7 = 0.0, i8 = 0, i10 = 0, d11 = 0.0, d12 = 0.0, i13 = 0;
+ i3 = STACKTOP;
+ d12 = +HEAPF32[i5 >> 2];
+ d11 = +HEAPF32[i5 + 4 >> 2];
+ i5 = i1 + 4 | 0;
+ d7 = d12 * +HEAPF32[i1 >> 2] + d11 * +HEAPF32[i5 >> 2] - d9;
+ i6 = i1 + 12 | 0;
+ i8 = i1 + 16 | 0;
+ d9 = d12 * +HEAPF32[i6 >> 2] + d11 * +HEAPF32[i8 >> 2] - d9;
+ if (!(d7 <= 0.0)) {
+  i10 = 0;
+ } else {
+  HEAP32[i4 + 0 >> 2] = HEAP32[i1 + 0 >> 2];
+  HEAP32[i4 + 4 >> 2] = HEAP32[i1 + 4 >> 2];
+  HEAP32[i4 + 8 >> 2] = HEAP32[i1 + 8 >> 2];
+  i10 = 1;
+ }
+ if (d9 <= 0.0) {
+  i13 = i10 + 1 | 0;
+  i10 = i4 + (i10 * 12 | 0) | 0;
+  HEAP32[i10 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+  HEAP32[i10 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+  HEAP32[i10 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+  i10 = i13;
+ }
+ if (!(d7 * d9 < 0.0)) {
+  i13 = i10;
+  STACKTOP = i3;
+  return i13 | 0;
+ }
+ d9 = d7 / (d7 - d9);
+ d11 = +HEAPF32[i1 >> 2];
+ d12 = +HEAPF32[i5 >> 2];
+ d11 = +(d11 + d9 * (+HEAPF32[i6 >> 2] - d11));
+ d12 = +(d12 + d9 * (+HEAPF32[i8 >> 2] - d12));
+ i13 = i4 + (i10 * 12 | 0) | 0;
+ HEAPF32[i13 >> 2] = d11;
+ HEAPF32[i13 + 4 >> 2] = d12;
+ i13 = i4 + (i10 * 12 | 0) + 8 | 0;
+ HEAP8[i13] = i2;
+ HEAP8[i13 + 1 | 0] = HEAP8[i1 + 9 | 0] | 0;
+ HEAP8[i13 + 2 | 0] = 0;
+ HEAP8[i13 + 3 | 0] = 1;
+ i13 = i10 + 1 | 0;
+ STACKTOP = i3;
+ return i13 | 0;
+}
+function __Z16b2CollideCirclesP10b2ManifoldPK13b2CircleShapeRK11b2TransformS3_S6_(i1, i7, i8, i6, i9) {
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ i8 = i8 | 0;
+ i6 = i6 | 0;
+ i9 = i9 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, d10 = 0.0, d11 = 0.0, d12 = 0.0, d13 = 0.0, d14 = 0.0, d15 = 0.0, d16 = 0.0, d17 = 0.0, d18 = 0.0;
+ i2 = STACKTOP;
+ i4 = i1 + 60 | 0;
+ HEAP32[i4 >> 2] = 0;
+ i3 = i7 + 12 | 0;
+ d10 = +HEAPF32[i8 + 12 >> 2];
+ d14 = +HEAPF32[i3 >> 2];
+ d13 = +HEAPF32[i8 + 8 >> 2];
+ d11 = +HEAPF32[i7 + 16 >> 2];
+ i5 = i6 + 12 | 0;
+ d16 = +HEAPF32[i9 + 12 >> 2];
+ d18 = +HEAPF32[i5 >> 2];
+ d17 = +HEAPF32[i9 + 8 >> 2];
+ d15 = +HEAPF32[i6 + 16 >> 2];
+ d12 = +HEAPF32[i9 >> 2] + (d16 * d18 - d17 * d15) - (+HEAPF32[i8 >> 2] + (d10 * d14 - d13 * d11));
+ d11 = d18 * d17 + d16 * d15 + +HEAPF32[i9 + 4 >> 2] - (d14 * d13 + d10 * d11 + +HEAPF32[i8 + 4 >> 2]);
+ d10 = +HEAPF32[i7 + 8 >> 2] + +HEAPF32[i6 + 8 >> 2];
+ if (d12 * d12 + d11 * d11 > d10 * d10) {
+  STACKTOP = i2;
+  return;
+ }
+ HEAP32[i1 + 56 >> 2] = 0;
+ i9 = i3;
+ i8 = HEAP32[i9 + 4 >> 2] | 0;
+ i7 = i1 + 48 | 0;
+ HEAP32[i7 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i7 + 4 >> 2] = i8;
+ HEAPF32[i1 + 40 >> 2] = 0.0;
+ HEAPF32[i1 + 44 >> 2] = 0.0;
+ HEAP32[i4 >> 2] = 1;
+ i7 = i5;
+ i8 = HEAP32[i7 + 4 >> 2] | 0;
+ i9 = i1;
+ HEAP32[i9 >> 2] = HEAP32[i7 >> 2];
+ HEAP32[i9 + 4 >> 2] = i8;
+ HEAP32[i1 + 16 >> 2] = 0;
+ STACKTOP = i2;
+ return;
+}
+function __ZNK14b2PolygonShape11ComputeAABBEP6b2AABBRK11b2Transformi(i1, i2, i7, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i7 = i7 | 0;
+ i3 = i3 | 0;
+ var d4 = 0.0, d5 = 0.0, d6 = 0.0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, d12 = 0.0, i13 = 0, d14 = 0.0, d15 = 0.0, d16 = 0.0;
+ i3 = STACKTOP;
+ d4 = +HEAPF32[i7 + 12 >> 2];
+ d15 = +HEAPF32[i1 + 20 >> 2];
+ d5 = +HEAPF32[i7 + 8 >> 2];
+ d12 = +HEAPF32[i1 + 24 >> 2];
+ d6 = +HEAPF32[i7 >> 2];
+ d9 = d6 + (d4 * d15 - d5 * d12);
+ d8 = +HEAPF32[i7 + 4 >> 2];
+ d12 = d15 * d5 + d4 * d12 + d8;
+ i7 = HEAP32[i1 + 148 >> 2] | 0;
+ if ((i7 | 0) > 1) {
+  d10 = d9;
+  d11 = d12;
+  i13 = 1;
+  do {
+   d16 = +HEAPF32[i1 + (i13 << 3) + 20 >> 2];
+   d14 = +HEAPF32[i1 + (i13 << 3) + 24 >> 2];
+   d15 = d6 + (d4 * d16 - d5 * d14);
+   d14 = d16 * d5 + d4 * d14 + d8;
+   d10 = d10 < d15 ? d10 : d15;
+   d11 = d11 < d14 ? d11 : d14;
+   d9 = d9 > d15 ? d9 : d15;
+   d12 = d12 > d14 ? d12 : d14;
+   i13 = i13 + 1 | 0;
+  } while ((i13 | 0) < (i7 | 0));
+ } else {
+  d11 = d12;
+  d10 = d9;
+ }
+ d16 = +HEAPF32[i1 + 8 >> 2];
+ d14 = +(d10 - d16);
+ d15 = +(d11 - d16);
+ i13 = i2;
+ HEAPF32[i13 >> 2] = d14;
+ HEAPF32[i13 + 4 >> 2] = d15;
+ d15 = +(d9 + d16);
+ d16 = +(d12 + d16);
+ i13 = i2 + 8 | 0;
+ HEAPF32[i13 >> 2] = d15;
+ HEAPF32[i13 + 4 >> 2] = d16;
+ STACKTOP = i3;
+ return;
+}
+function __ZNK10__cxxabiv120__si_class_type_info16search_above_dstEPNS_19__dynamic_cast_infoEPKvS4_ib(i5, i1, i4, i6, i3, i7) {
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((i5 | 0) != (HEAP32[i1 + 8 >> 2] | 0)) {
+  i5 = HEAP32[i5 + 8 >> 2] | 0;
+  FUNCTION_TABLE_viiiiii[HEAP32[(HEAP32[i5 >> 2] | 0) + 20 >> 2] & 3](i5, i1, i4, i6, i3, i7);
+  STACKTOP = i2;
+  return;
+ }
+ HEAP8[i1 + 53 | 0] = 1;
+ if ((HEAP32[i1 + 4 >> 2] | 0) != (i6 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ HEAP8[i1 + 52 | 0] = 1;
+ i5 = i1 + 16 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  HEAP32[i5 >> 2] = i4;
+  HEAP32[i1 + 24 >> 2] = i3;
+  HEAP32[i1 + 36 >> 2] = 1;
+  if (!((HEAP32[i1 + 48 >> 2] | 0) == 1 & (i3 | 0) == 1)) {
+   STACKTOP = i2;
+   return;
+  }
+  HEAP8[i1 + 54 | 0] = 1;
+  STACKTOP = i2;
+  return;
+ }
+ if ((i6 | 0) != (i4 | 0)) {
+  i7 = i1 + 36 | 0;
+  HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + 1;
+  HEAP8[i1 + 54 | 0] = 1;
+  STACKTOP = i2;
+  return;
+ }
+ i4 = i1 + 24 | 0;
+ i5 = HEAP32[i4 >> 2] | 0;
+ if ((i5 | 0) == 2) {
+  HEAP32[i4 >> 2] = i3;
+ } else {
+  i3 = i5;
+ }
+ if (!((HEAP32[i1 + 48 >> 2] | 0) == 1 & (i3 | 0) == 1)) {
+  STACKTOP = i2;
+  return;
+ }
+ HEAP8[i1 + 54 | 0] = 1;
+ STACKTOP = i2;
+ return;
+}
+function __ZN6b2Body13CreateFixtureEPK12b2FixtureDef(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i3 = STACKTOP;
+ i2 = i1 + 88 | 0;
+ i4 = HEAP32[i2 >> 2] | 0;
+ if ((HEAP32[i4 + 102868 >> 2] & 2 | 0) != 0) {
+  ___assert_fail(1776, 1520, 153, 1808);
+ }
+ i6 = __ZN16b2BlockAllocator8AllocateEi(i4, 44) | 0;
+ if ((i6 | 0) == 0) {
+  i6 = 0;
+ } else {
+  __ZN9b2FixtureC2Ev(i6);
+ }
+ __ZN9b2Fixture6CreateEP16b2BlockAllocatorP6b2BodyPK12b2FixtureDef(i6, i4, i1, i5);
+ if (!((HEAP16[i1 + 4 >> 1] & 32) == 0)) {
+  __ZN9b2Fixture13CreateProxiesEP12b2BroadPhaseRK11b2Transform(i6, (HEAP32[i2 >> 2] | 0) + 102872 | 0, i1 + 12 | 0);
+ }
+ i5 = i1 + 100 | 0;
+ HEAP32[i6 + 4 >> 2] = HEAP32[i5 >> 2];
+ HEAP32[i5 >> 2] = i6;
+ i5 = i1 + 104 | 0;
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 1;
+ HEAP32[i6 + 8 >> 2] = i1;
+ if (!(+HEAPF32[i6 >> 2] > 0.0)) {
+  i5 = HEAP32[i2 >> 2] | 0;
+  i5 = i5 + 102868 | 0;
+  i4 = HEAP32[i5 >> 2] | 0;
+  i4 = i4 | 1;
+  HEAP32[i5 >> 2] = i4;
+  STACKTOP = i3;
+  return i6 | 0;
+ }
+ __ZN6b2Body13ResetMassDataEv(i1);
+ i5 = HEAP32[i2 >> 2] | 0;
+ i5 = i5 + 102868 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ i4 = i4 | 1;
+ HEAP32[i5 >> 2] = i4;
+ STACKTOP = i3;
+ return i6 | 0;
+}
+function __Z13b2TestOverlapPK7b2ShapeiS1_iRK11b2TransformS4_(i6, i5, i4, i3, i2, i1) {
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i8 = STACKTOP;
+ STACKTOP = STACKTOP + 128 | 0;
+ i9 = i8 + 36 | 0;
+ i10 = i8 + 24 | 0;
+ i7 = i8;
+ HEAP32[i9 + 16 >> 2] = 0;
+ HEAP32[i9 + 20 >> 2] = 0;
+ HEAPF32[i9 + 24 >> 2] = 0.0;
+ HEAP32[i9 + 44 >> 2] = 0;
+ HEAP32[i9 + 48 >> 2] = 0;
+ HEAPF32[i9 + 52 >> 2] = 0.0;
+ __ZN15b2DistanceProxy3SetEPK7b2Shapei(i9, i6, i5);
+ __ZN15b2DistanceProxy3SetEPK7b2Shapei(i9 + 28 | 0, i4, i3);
+ i6 = i9 + 56 | 0;
+ HEAP32[i6 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+ HEAP32[i6 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+ HEAP32[i6 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+ HEAP32[i6 + 12 >> 2] = HEAP32[i2 + 12 >> 2];
+ i6 = i9 + 72 | 0;
+ HEAP32[i6 + 0 >> 2] = HEAP32[i1 + 0 >> 2];
+ HEAP32[i6 + 4 >> 2] = HEAP32[i1 + 4 >> 2];
+ HEAP32[i6 + 8 >> 2] = HEAP32[i1 + 8 >> 2];
+ HEAP32[i6 + 12 >> 2] = HEAP32[i1 + 12 >> 2];
+ HEAP8[i9 + 88 | 0] = 1;
+ HEAP16[i10 + 4 >> 1] = 0;
+ __Z10b2DistanceP16b2DistanceOutputP14b2SimplexCachePK15b2DistanceInput(i7, i10, i9);
+ STACKTOP = i8;
+ return +HEAPF32[i7 + 16 >> 2] < 11920928955078125.0e-22 | 0;
+}
+function __ZNK10__cxxabiv117__class_type_info16search_above_dstEPNS_19__dynamic_cast_infoEPKvS4_ib(i6, i1, i4, i5, i2, i3) {
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i3 = STACKTOP;
+ if ((HEAP32[i1 + 8 >> 2] | 0) != (i6 | 0)) {
+  STACKTOP = i3;
+  return;
+ }
+ HEAP8[i1 + 53 | 0] = 1;
+ if ((HEAP32[i1 + 4 >> 2] | 0) != (i5 | 0)) {
+  STACKTOP = i3;
+  return;
+ }
+ HEAP8[i1 + 52 | 0] = 1;
+ i5 = i1 + 16 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  HEAP32[i5 >> 2] = i4;
+  HEAP32[i1 + 24 >> 2] = i2;
+  HEAP32[i1 + 36 >> 2] = 1;
+  if (!((HEAP32[i1 + 48 >> 2] | 0) == 1 & (i2 | 0) == 1)) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP8[i1 + 54 | 0] = 1;
+  STACKTOP = i3;
+  return;
+ }
+ if ((i6 | 0) != (i4 | 0)) {
+  i6 = i1 + 36 | 0;
+  HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 1;
+  HEAP8[i1 + 54 | 0] = 1;
+  STACKTOP = i3;
+  return;
+ }
+ i4 = i1 + 24 | 0;
+ i5 = HEAP32[i4 >> 2] | 0;
+ if ((i5 | 0) == 2) {
+  HEAP32[i4 >> 2] = i2;
+ } else {
+  i2 = i5;
+ }
+ if (!((HEAP32[i1 + 48 >> 2] | 0) == 1 & (i2 | 0) == 1)) {
+  STACKTOP = i3;
+  return;
+ }
+ HEAP8[i1 + 54 | 0] = 1;
+ STACKTOP = i3;
+ return;
+}
+function __ZNK11b2EdgeShape5CloneEP16b2BlockAllocator(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i3, 48) | 0;
+ if ((i3 | 0) == 0) {
+  i3 = 0;
+ } else {
+  HEAP32[i3 >> 2] = 240;
+  HEAP32[i3 + 4 >> 2] = 1;
+  HEAPF32[i3 + 8 >> 2] = .009999999776482582;
+  i4 = i3 + 28 | 0;
+  HEAP32[i4 + 0 >> 2] = 0;
+  HEAP32[i4 + 4 >> 2] = 0;
+  HEAP32[i4 + 8 >> 2] = 0;
+  HEAP32[i4 + 12 >> 2] = 0;
+  HEAP16[i4 + 16 >> 1] = 0;
+ }
+ i6 = i1 + 4 | 0;
+ i5 = HEAP32[i6 + 4 >> 2] | 0;
+ i4 = i3 + 4 | 0;
+ HEAP32[i4 >> 2] = HEAP32[i6 >> 2];
+ HEAP32[i4 + 4 >> 2] = i5;
+ i4 = i3 + 12 | 0;
+ i1 = i1 + 12 | 0;
+ HEAP32[i4 + 0 >> 2] = HEAP32[i1 + 0 >> 2];
+ HEAP32[i4 + 4 >> 2] = HEAP32[i1 + 4 >> 2];
+ HEAP32[i4 + 8 >> 2] = HEAP32[i1 + 8 >> 2];
+ HEAP32[i4 + 12 >> 2] = HEAP32[i1 + 12 >> 2];
+ HEAP32[i4 + 16 >> 2] = HEAP32[i1 + 16 >> 2];
+ HEAP32[i4 + 20 >> 2] = HEAP32[i1 + 20 >> 2];
+ HEAP32[i4 + 24 >> 2] = HEAP32[i1 + 24 >> 2];
+ HEAP32[i4 + 28 >> 2] = HEAP32[i1 + 28 >> 2];
+ HEAP16[i4 + 32 >> 1] = HEAP16[i1 + 32 >> 1] | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function __ZN7b2WorldC2ERK6b2Vec2(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i3 = STACKTOP;
+ __ZN16b2BlockAllocatorC2Ev(i1);
+ __ZN16b2StackAllocatorC2Ev(i1 + 68 | 0);
+ __ZN16b2ContactManagerC2Ev(i1 + 102872 | 0);
+ i6 = i1 + 102968 | 0;
+ HEAP32[i1 + 102980 >> 2] = 0;
+ HEAP32[i1 + 102984 >> 2] = 0;
+ i4 = i1 + 102952 | 0;
+ i5 = i1 + 102992 | 0;
+ HEAP32[i4 + 0 >> 2] = 0;
+ HEAP32[i4 + 4 >> 2] = 0;
+ HEAP32[i4 + 8 >> 2] = 0;
+ HEAP32[i4 + 12 >> 2] = 0;
+ HEAP8[i5] = 1;
+ HEAP8[i1 + 102993 | 0] = 1;
+ HEAP8[i1 + 102994 | 0] = 0;
+ HEAP8[i1 + 102995 | 0] = 1;
+ HEAP8[i1 + 102976 | 0] = 1;
+ i5 = i2;
+ i4 = HEAP32[i5 + 4 >> 2] | 0;
+ i2 = i6;
+ HEAP32[i2 >> 2] = HEAP32[i5 >> 2];
+ HEAP32[i2 + 4 >> 2] = i4;
+ HEAP32[i1 + 102868 >> 2] = 4;
+ HEAPF32[i1 + 102988 >> 2] = 0.0;
+ HEAP32[i1 + 102948 >> 2] = i1;
+ i2 = i1 + 102996 | 0;
+ HEAP32[i2 + 0 >> 2] = 0;
+ HEAP32[i2 + 4 >> 2] = 0;
+ HEAP32[i2 + 8 >> 2] = 0;
+ HEAP32[i2 + 12 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 24 >> 2] = 0;
+ HEAP32[i2 + 28 >> 2] = 0;
+ STACKTOP = i3;
+ return;
+}
+function __ZNK10__cxxabiv117__class_type_info16search_below_dstEPNS_19__dynamic_cast_infoEPKvib(i6, i3, i4, i1, i2) {
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i5 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[i3 + 8 >> 2] | 0) == (i6 | 0)) {
+  if ((HEAP32[i3 + 4 >> 2] | 0) != (i4 | 0)) {
+   STACKTOP = i2;
+   return;
+  }
+  i3 = i3 + 28 | 0;
+  if ((HEAP32[i3 >> 2] | 0) == 1) {
+   STACKTOP = i2;
+   return;
+  }
+  HEAP32[i3 >> 2] = i1;
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP32[i3 >> 2] | 0) != (i6 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP32[i3 + 16 >> 2] | 0) != (i4 | 0) ? (i5 = i3 + 20 | 0, (HEAP32[i5 >> 2] | 0) != (i4 | 0)) : 0) {
+  HEAP32[i3 + 32 >> 2] = i1;
+  HEAP32[i5 >> 2] = i4;
+  i6 = i3 + 40 | 0;
+  HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 1;
+  if ((HEAP32[i3 + 36 >> 2] | 0) == 1 ? (HEAP32[i3 + 24 >> 2] | 0) == 2 : 0) {
+   HEAP8[i3 + 54 | 0] = 1;
+  }
+  HEAP32[i3 + 44 >> 2] = 4;
+  STACKTOP = i2;
+  return;
+ }
+ if ((i1 | 0) != 1) {
+  STACKTOP = i2;
+  return;
+ }
+ HEAP32[i3 + 32 >> 2] = 1;
+ STACKTOP = i2;
+ return;
+}
+function __ZN9b2Contact7DestroyEPS_P16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i3 = STACKTOP;
+ if ((HEAP8[4200] | 0) == 0) {
+  ___assert_fail(4352, 4256, 103, 4376);
+ }
+ i4 = HEAP32[i1 + 48 >> 2] | 0;
+ if ((HEAP32[i1 + 124 >> 2] | 0) > 0) {
+  i7 = HEAP32[i4 + 8 >> 2] | 0;
+  i6 = i7 + 4 | 0;
+  i5 = HEAPU16[i6 >> 1] | 0;
+  if ((i5 & 2 | 0) == 0) {
+   HEAP16[i6 >> 1] = i5 | 2;
+   HEAPF32[i7 + 144 >> 2] = 0.0;
+  }
+  i7 = HEAP32[i1 + 52 >> 2] | 0;
+  i6 = HEAP32[i7 + 8 >> 2] | 0;
+  i5 = i6 + 4 | 0;
+  i8 = HEAPU16[i5 >> 1] | 0;
+  if ((i8 & 2 | 0) == 0) {
+   HEAP16[i5 >> 1] = i8 | 2;
+   HEAPF32[i6 + 144 >> 2] = 0.0;
+  }
+ } else {
+  i7 = HEAP32[i1 + 52 >> 2] | 0;
+ }
+ i4 = HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 4 >> 2] | 0;
+ i5 = HEAP32[(HEAP32[i7 + 12 >> 2] | 0) + 4 >> 2] | 0;
+ if ((i4 | 0) > -1 & (i5 | 0) < 4) {
+  FUNCTION_TABLE_vii[HEAP32[4008 + (i4 * 48 | 0) + (i5 * 12 | 0) + 4 >> 2] & 15](i1, i2);
+  STACKTOP = i3;
+  return;
+ } else {
+  ___assert_fail(4384, 4256, 114, 4376);
+ }
+}
+function __ZN9b2Fixture13CreateProxiesEP12b2BroadPhaseRK11b2Transform(i5, i4, i1) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i2 = STACKTOP;
+ i3 = i5 + 28 | 0;
+ if ((HEAP32[i3 >> 2] | 0) != 0) {
+  ___assert_fail(2088, 2112, 124, 2144);
+ }
+ i6 = i5 + 12 | 0;
+ i8 = HEAP32[i6 >> 2] | 0;
+ i8 = FUNCTION_TABLE_ii[HEAP32[(HEAP32[i8 >> 2] | 0) + 12 >> 2] & 3](i8) | 0;
+ HEAP32[i3 >> 2] = i8;
+ if ((i8 | 0) <= 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i7 = i5 + 24 | 0;
+ i8 = 0;
+ do {
+  i9 = HEAP32[i7 >> 2] | 0;
+  i10 = i9 + (i8 * 28 | 0) | 0;
+  i11 = HEAP32[i6 >> 2] | 0;
+  FUNCTION_TABLE_viiii[HEAP32[(HEAP32[i11 >> 2] | 0) + 24 >> 2] & 15](i11, i10, i1, i8);
+  HEAP32[i9 + (i8 * 28 | 0) + 24 >> 2] = __ZN12b2BroadPhase11CreateProxyERK6b2AABBPv(i4, i10, i10) | 0;
+  HEAP32[i9 + (i8 * 28 | 0) + 16 >> 2] = i5;
+  HEAP32[i9 + (i8 * 28 | 0) + 20 >> 2] = i8;
+  i8 = i8 + 1 | 0;
+ } while ((i8 | 0) < (HEAP32[i3 >> 2] | 0));
+ STACKTOP = i2;
+ return;
+}
+function __ZNK10__cxxabiv117__class_type_info9can_catchEPKNS_16__shim_type_infoERPv(i1, i5, i4) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i3 = i2;
+ if ((i1 | 0) == (i5 | 0)) {
+  i7 = 1;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ if ((i5 | 0) == 0) {
+  i7 = 0;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ i5 = ___dynamic_cast(i5, 6952, 7008, 0) | 0;
+ if ((i5 | 0) == 0) {
+  i7 = 0;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ i7 = i3 + 0 | 0;
+ i6 = i7 + 56 | 0;
+ do {
+  HEAP32[i7 >> 2] = 0;
+  i7 = i7 + 4 | 0;
+ } while ((i7 | 0) < (i6 | 0));
+ HEAP32[i3 >> 2] = i5;
+ HEAP32[i3 + 8 >> 2] = i1;
+ HEAP32[i3 + 12 >> 2] = -1;
+ HEAP32[i3 + 48 >> 2] = 1;
+ FUNCTION_TABLE_viiii[HEAP32[(HEAP32[i5 >> 2] | 0) + 28 >> 2] & 15](i5, i3, HEAP32[i4 >> 2] | 0, 1);
+ if ((HEAP32[i3 + 24 >> 2] | 0) != 1) {
+  i7 = 0;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ HEAP32[i4 >> 2] = HEAP32[i3 + 16 >> 2];
+ i7 = 1;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function __ZN8b2IslandC2EiiiP16b2StackAllocatorP17b2ContactListener(i1, i4, i3, i2, i5, i6) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i7 = 0, i8 = 0;
+ i7 = STACKTOP;
+ i8 = i1 + 40 | 0;
+ HEAP32[i8 >> 2] = i4;
+ HEAP32[i1 + 44 >> 2] = i3;
+ HEAP32[i1 + 48 >> 2] = i2;
+ HEAP32[i1 + 28 >> 2] = 0;
+ HEAP32[i1 + 36 >> 2] = 0;
+ HEAP32[i1 + 32 >> 2] = 0;
+ HEAP32[i1 >> 2] = i5;
+ HEAP32[i1 + 4 >> 2] = i6;
+ HEAP32[i1 + 8 >> 2] = __ZN16b2StackAllocator8AllocateEi(i5, i4 << 2) | 0;
+ HEAP32[i1 + 12 >> 2] = __ZN16b2StackAllocator8AllocateEi(HEAP32[i1 >> 2] | 0, i3 << 2) | 0;
+ HEAP32[i1 + 16 >> 2] = __ZN16b2StackAllocator8AllocateEi(HEAP32[i1 >> 2] | 0, i2 << 2) | 0;
+ HEAP32[i1 + 24 >> 2] = __ZN16b2StackAllocator8AllocateEi(HEAP32[i1 >> 2] | 0, (HEAP32[i8 >> 2] | 0) * 12 | 0) | 0;
+ HEAP32[i1 + 20 >> 2] = __ZN16b2StackAllocator8AllocateEi(HEAP32[i1 >> 2] | 0, (HEAP32[i8 >> 2] | 0) * 12 | 0) | 0;
+ STACKTOP = i7;
+ return;
+}
+function __ZNK11b2EdgeShape11ComputeAABBEP6b2AABBRK11b2Transformi(i8, i1, i10, i2) {
+ i8 = i8 | 0;
+ i1 = i1 | 0;
+ i10 = i10 | 0;
+ i2 = i2 | 0;
+ var d3 = 0.0, d4 = 0.0, d5 = 0.0, d6 = 0.0, d7 = 0.0, d9 = 0.0, d11 = 0.0, d12 = 0.0;
+ i2 = STACKTOP;
+ d7 = +HEAPF32[i10 + 12 >> 2];
+ d9 = +HEAPF32[i8 + 12 >> 2];
+ d11 = +HEAPF32[i10 + 8 >> 2];
+ d3 = +HEAPF32[i8 + 16 >> 2];
+ d6 = +HEAPF32[i10 >> 2];
+ d5 = d6 + (d7 * d9 - d11 * d3);
+ d12 = +HEAPF32[i10 + 4 >> 2];
+ d3 = d9 * d11 + d7 * d3 + d12;
+ d9 = +HEAPF32[i8 + 20 >> 2];
+ d4 = +HEAPF32[i8 + 24 >> 2];
+ d6 = d6 + (d7 * d9 - d11 * d4);
+ d4 = d12 + (d11 * d9 + d7 * d4);
+ d7 = +HEAPF32[i8 + 8 >> 2];
+ d9 = +((d5 < d6 ? d5 : d6) - d7);
+ d12 = +((d3 < d4 ? d3 : d4) - d7);
+ i10 = i1;
+ HEAPF32[i10 >> 2] = d9;
+ HEAPF32[i10 + 4 >> 2] = d12;
+ d5 = +(d7 + (d5 > d6 ? d5 : d6));
+ d12 = +(d7 + (d3 > d4 ? d3 : d4));
+ i10 = i1 + 8 | 0;
+ HEAPF32[i10 >> 2] = d5;
+ HEAPF32[i10 + 4 >> 2] = d12;
+ STACKTOP = i2;
+ return;
+}
+function __ZNK14b2PolygonShape9TestPointERK11b2TransformRK6b2Vec2(i2, i3, i6) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, d4 = 0.0, d5 = 0.0, i7 = 0, d8 = 0.0, d9 = 0.0, d10 = 0.0;
+ i1 = STACKTOP;
+ d8 = +HEAPF32[i6 >> 2] - +HEAPF32[i3 >> 2];
+ d9 = +HEAPF32[i6 + 4 >> 2] - +HEAPF32[i3 + 4 >> 2];
+ d10 = +HEAPF32[i3 + 12 >> 2];
+ d5 = +HEAPF32[i3 + 8 >> 2];
+ d4 = d8 * d10 + d9 * d5;
+ d5 = d10 * d9 - d8 * d5;
+ i3 = HEAP32[i2 + 148 >> 2] | 0;
+ if ((i3 | 0) > 0) {
+  i6 = 0;
+ } else {
+  i7 = 1;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ while (1) {
+  i7 = i6 + 1 | 0;
+  if ((d4 - +HEAPF32[i2 + (i6 << 3) + 20 >> 2]) * +HEAPF32[i2 + (i6 << 3) + 84 >> 2] + (d5 - +HEAPF32[i2 + (i6 << 3) + 24 >> 2]) * +HEAPF32[i2 + (i6 << 3) + 88 >> 2] > 0.0) {
+   i3 = 0;
+   i2 = 4;
+   break;
+  }
+  if ((i7 | 0) < (i3 | 0)) {
+   i6 = i7;
+  } else {
+   i3 = 1;
+   i2 = 4;
+   break;
+  }
+ }
+ if ((i2 | 0) == 4) {
+  STACKTOP = i1;
+  return i3 | 0;
+ }
+ return 0;
+}
+function __ZN16b2StackAllocator8AllocateEi(i4, i5) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ i3 = i4 + 102796 | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ if ((i6 | 0) >= 32) {
+  ___assert_fail(3896, 3808, 38, 3936);
+ }
+ i1 = i4 + (i6 * 12 | 0) + 102412 | 0;
+ HEAP32[i4 + (i6 * 12 | 0) + 102416 >> 2] = i5;
+ i7 = i4 + 102400 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ if ((i8 + i5 | 0) > 102400) {
+  HEAP32[i1 >> 2] = __Z7b2Alloci(i5) | 0;
+  HEAP8[i4 + (i6 * 12 | 0) + 102420 | 0] = 1;
+ } else {
+  HEAP32[i1 >> 2] = i4 + i8;
+  HEAP8[i4 + (i6 * 12 | 0) + 102420 | 0] = 0;
+  HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + i5;
+ }
+ i6 = i4 + 102404 | 0;
+ i5 = (HEAP32[i6 >> 2] | 0) + i5 | 0;
+ HEAP32[i6 >> 2] = i5;
+ i4 = i4 + 102408 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i4 >> 2] = (i6 | 0) > (i5 | 0) ? i6 : i5;
+ HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + 1;
+ STACKTOP = i2;
+ return HEAP32[i1 >> 2] | 0;
+}
+function __ZN12b2BroadPhase13QueryCallbackEi(i5, i1) {
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ i4 = i5 + 56 | 0;
+ i7 = HEAP32[i4 >> 2] | 0;
+ if ((i7 | 0) == (i1 | 0)) {
+  STACKTOP = i2;
+  return 1;
+ }
+ i3 = i5 + 52 | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ i8 = i5 + 48 | 0;
+ i5 = i5 + 44 | 0;
+ if ((i6 | 0) == (HEAP32[i8 >> 2] | 0)) {
+  i7 = HEAP32[i5 >> 2] | 0;
+  HEAP32[i8 >> 2] = i6 << 1;
+  i6 = __Z7b2Alloci(i6 * 24 | 0) | 0;
+  HEAP32[i5 >> 2] = i6;
+  _memcpy(i6 | 0, i7 | 0, (HEAP32[i3 >> 2] | 0) * 12 | 0) | 0;
+  __Z6b2FreePv(i7);
+  i7 = HEAP32[i4 >> 2] | 0;
+  i6 = HEAP32[i3 >> 2] | 0;
+ }
+ i5 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 + (i6 * 12 | 0) >> 2] = (i7 | 0) > (i1 | 0) ? i1 : i7;
+ i4 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i5 + ((HEAP32[i3 >> 2] | 0) * 12 | 0) + 4 >> 2] = (i4 | 0) < (i1 | 0) ? i1 : i4;
+ HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + 1;
+ STACKTOP = i2;
+ return 1;
+}
+function __ZNK10__cxxabiv120__si_class_type_info27has_unambiguous_public_baseEPNS_19__dynamic_cast_infoEPvi(i5, i4, i3, i1) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i6 = 0;
+ i2 = STACKTOP;
+ if ((i5 | 0) != (HEAP32[i4 + 8 >> 2] | 0)) {
+  i6 = HEAP32[i5 + 8 >> 2] | 0;
+  FUNCTION_TABLE_viiii[HEAP32[(HEAP32[i6 >> 2] | 0) + 28 >> 2] & 15](i6, i4, i3, i1);
+  STACKTOP = i2;
+  return;
+ }
+ i5 = i4 + 16 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  HEAP32[i5 >> 2] = i3;
+  HEAP32[i4 + 24 >> 2] = i1;
+  HEAP32[i4 + 36 >> 2] = 1;
+  STACKTOP = i2;
+  return;
+ }
+ if ((i6 | 0) != (i3 | 0)) {
+  i6 = i4 + 36 | 0;
+  HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 1;
+  HEAP32[i4 + 24 >> 2] = 2;
+  HEAP8[i4 + 54 | 0] = 1;
+  STACKTOP = i2;
+  return;
+ }
+ i3 = i4 + 24 | 0;
+ if ((HEAP32[i3 >> 2] | 0) != 2) {
+  STACKTOP = i2;
+  return;
+ }
+ HEAP32[i3 >> 2] = i1;
+ STACKTOP = i2;
+ return;
+}
+function __ZN6b2Body19SynchronizeFixturesEv(i5) {
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d9 = 0.0, d10 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ d8 = +HEAPF32[i5 + 52 >> 2];
+ d9 = +Math_sin(+d8);
+ HEAPF32[i3 + 8 >> 2] = d9;
+ d8 = +Math_cos(+d8);
+ HEAPF32[i3 + 12 >> 2] = d8;
+ d10 = +HEAPF32[i5 + 28 >> 2];
+ d6 = +HEAPF32[i5 + 32 >> 2];
+ d7 = +(+HEAPF32[i5 + 36 >> 2] - (d8 * d10 - d9 * d6));
+ d6 = +(+HEAPF32[i5 + 40 >> 2] - (d10 * d9 + d8 * d6));
+ i2 = i3;
+ HEAPF32[i2 >> 2] = d7;
+ HEAPF32[i2 + 4 >> 2] = d6;
+ i2 = (HEAP32[i5 + 88 >> 2] | 0) + 102872 | 0;
+ i4 = HEAP32[i5 + 100 >> 2] | 0;
+ if ((i4 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i5 = i5 + 12 | 0;
+ do {
+  __ZN9b2Fixture11SynchronizeEP12b2BroadPhaseRK11b2TransformS4_(i4, i2, i3, i5);
+  i4 = HEAP32[i4 + 4 >> 2] | 0;
+ } while ((i4 | 0) != 0);
+ STACKTOP = i1;
+ return;
+}
+function __ZN13b2DynamicTreeC2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i4 = STACKTOP;
+ HEAP32[i1 >> 2] = -1;
+ i3 = i1 + 12 | 0;
+ HEAP32[i3 >> 2] = 16;
+ HEAP32[i1 + 8 >> 2] = 0;
+ i6 = __Z7b2Alloci(576) | 0;
+ i2 = i1 + 4 | 0;
+ HEAP32[i2 >> 2] = i6;
+ _memset(i6 | 0, 0, (HEAP32[i3 >> 2] | 0) * 36 | 0) | 0;
+ i6 = (HEAP32[i3 >> 2] | 0) + -1 | 0;
+ i2 = HEAP32[i2 >> 2] | 0;
+ if ((i6 | 0) > 0) {
+  i6 = 0;
+  while (1) {
+   i5 = i6 + 1 | 0;
+   HEAP32[i2 + (i6 * 36 | 0) + 20 >> 2] = i5;
+   HEAP32[i2 + (i6 * 36 | 0) + 32 >> 2] = -1;
+   i6 = (HEAP32[i3 >> 2] | 0) + -1 | 0;
+   if ((i5 | 0) < (i6 | 0)) {
+    i6 = i5;
+   } else {
+    break;
+   }
+  }
+ }
+ HEAP32[i2 + (i6 * 36 | 0) + 20 >> 2] = -1;
+ HEAP32[i2 + (((HEAP32[i3 >> 2] | 0) + -1 | 0) * 36 | 0) + 32 >> 2] = -1;
+ HEAP32[i1 + 16 >> 2] = 0;
+ HEAP32[i1 + 20 >> 2] = 0;
+ HEAP32[i1 + 24 >> 2] = 0;
+ STACKTOP = i4;
+ return;
+}
+function __Z7measurePl(i1, i9) {
+ i1 = i1 | 0;
+ i9 = i9 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, d5 = 0.0, d6 = 0.0, i7 = 0, d8 = 0.0, i10 = 0, d11 = 0.0;
+ i2 = STACKTOP;
+ i3 = HEAP32[4] | 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + ((4 * i3 | 0) + 15 & -16) | 0;
+ i7 = (i3 | 0) > 0;
+ if (i7) {
+  i10 = 0;
+  d6 = 0.0;
+  do {
+   d8 = +(HEAP32[i9 + (i10 << 2) >> 2] | 0) / 1.0e6 * 1.0e3;
+   HEAPF32[i4 + (i10 << 2) >> 2] = d8;
+   d6 = d6 + d8;
+   i10 = i10 + 1 | 0;
+  } while ((i10 | 0) < (i3 | 0));
+  d5 = +(i3 | 0);
+  d6 = d6 / d5;
+  HEAPF32[i1 >> 2] = d6;
+  if (i7) {
+   i7 = 0;
+   d8 = 0.0;
+   do {
+    d11 = +HEAPF32[i4 + (i7 << 2) >> 2] - d6;
+    d8 = d8 + d11 * d11;
+    i7 = i7 + 1 | 0;
+   } while ((i7 | 0) < (i3 | 0));
+  } else {
+   d8 = 0.0;
+  }
+ } else {
+  d5 = +(i3 | 0);
+  HEAPF32[i1 >> 2] = 0.0 / d5;
+  d8 = 0.0;
+ }
+ HEAPF32[i1 + 4 >> 2] = +Math_sqrt(+(d8 / d5));
+ STACKTOP = i2;
+ return;
+}
+function __ZN13b2DynamicTree11CreateProxyERK6b2AABBPv(i1, i3, i2) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i4 = 0, i5 = 0, i6 = 0, d7 = 0.0, d8 = 0.0, i9 = 0;
+ i5 = STACKTOP;
+ i4 = __ZN13b2DynamicTree12AllocateNodeEv(i1) | 0;
+ i6 = i1 + 4 | 0;
+ d7 = +(+HEAPF32[i3 >> 2] + -.10000000149011612);
+ d8 = +(+HEAPF32[i3 + 4 >> 2] + -.10000000149011612);
+ i9 = (HEAP32[i6 >> 2] | 0) + (i4 * 36 | 0) | 0;
+ HEAPF32[i9 >> 2] = d7;
+ HEAPF32[i9 + 4 >> 2] = d8;
+ d8 = +(+HEAPF32[i3 + 8 >> 2] + .10000000149011612);
+ d7 = +(+HEAPF32[i3 + 12 >> 2] + .10000000149011612);
+ i3 = (HEAP32[i6 >> 2] | 0) + (i4 * 36 | 0) + 8 | 0;
+ HEAPF32[i3 >> 2] = d8;
+ HEAPF32[i3 + 4 >> 2] = d7;
+ HEAP32[(HEAP32[i6 >> 2] | 0) + (i4 * 36 | 0) + 16 >> 2] = i2;
+ HEAP32[(HEAP32[i6 >> 2] | 0) + (i4 * 36 | 0) + 32 >> 2] = 0;
+ __ZN13b2DynamicTree10InsertLeafEi(i1, i4);
+ STACKTOP = i5;
+ return i4 | 0;
+}
+function __ZN16b2BlockAllocatorC2Ev(i3) {
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i4 = i3 + 8 | 0;
+ HEAP32[i4 >> 2] = 128;
+ HEAP32[i3 + 4 >> 2] = 0;
+ i5 = __Z7b2Alloci(1024) | 0;
+ HEAP32[i3 >> 2] = i5;
+ _memset(i5 | 0, 0, HEAP32[i4 >> 2] << 3 | 0) | 0;
+ i4 = i3 + 12 | 0;
+ i3 = i4 + 56 | 0;
+ do {
+  HEAP32[i4 >> 2] = 0;
+  i4 = i4 + 4 | 0;
+ } while ((i4 | 0) < (i3 | 0));
+ if ((HEAP8[1280] | 0) == 0) {
+  i3 = 1;
+  i4 = 0;
+ } else {
+  STACKTOP = i2;
+  return;
+ }
+ do {
+  if ((i4 | 0) >= 14) {
+   i1 = 3;
+   break;
+  }
+  if ((i3 | 0) > (HEAP32[576 + (i4 << 2) >> 2] | 0)) {
+   i4 = i4 + 1 | 0;
+   HEAP8[632 + i3 | 0] = i4;
+  } else {
+   HEAP8[632 + i3 | 0] = i4;
+  }
+  i3 = i3 + 1 | 0;
+ } while ((i3 | 0) < 641);
+ if ((i1 | 0) == 3) {
+  ___assert_fail(1288, 1312, 73, 1352);
+ }
+ HEAP8[1280] = 1;
+ STACKTOP = i2;
+ return;
+}
+function __ZN24b2ChainAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_(i2, i4, i3, i1) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i6 = i5;
+ i7 = HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 12 >> 2] | 0;
+ HEAP32[i6 >> 2] = 240;
+ HEAP32[i6 + 4 >> 2] = 1;
+ HEAPF32[i6 + 8 >> 2] = .009999999776482582;
+ i8 = i6 + 28 | 0;
+ HEAP32[i8 + 0 >> 2] = 0;
+ HEAP32[i8 + 4 >> 2] = 0;
+ HEAP32[i8 + 8 >> 2] = 0;
+ HEAP32[i8 + 12 >> 2] = 0;
+ HEAP16[i8 + 16 >> 1] = 0;
+ __ZNK12b2ChainShape12GetChildEdgeEP11b2EdgeShapei(i7, i6, HEAP32[i2 + 56 >> 2] | 0);
+ __Z23b2CollideEdgeAndPolygonP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK14b2PolygonShapeS6_(i4, i6, i3, HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 12 >> 2] | 0, i1);
+ STACKTOP = i5;
+ return;
+}
+function __ZN23b2ChainAndCircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_(i2, i4, i3, i1) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i6 = i5;
+ i7 = HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 12 >> 2] | 0;
+ HEAP32[i6 >> 2] = 240;
+ HEAP32[i6 + 4 >> 2] = 1;
+ HEAPF32[i6 + 8 >> 2] = .009999999776482582;
+ i8 = i6 + 28 | 0;
+ HEAP32[i8 + 0 >> 2] = 0;
+ HEAP32[i8 + 4 >> 2] = 0;
+ HEAP32[i8 + 8 >> 2] = 0;
+ HEAP32[i8 + 12 >> 2] = 0;
+ HEAP16[i8 + 16 >> 1] = 0;
+ __ZNK12b2ChainShape12GetChildEdgeEP11b2EdgeShapei(i7, i6, HEAP32[i2 + 56 >> 2] | 0);
+ __Z22b2CollideEdgeAndCircleP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK13b2CircleShapeS6_(i4, i6, i3, HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 12 >> 2] | 0, i1);
+ STACKTOP = i5;
+ return;
+}
+function __ZN15b2ContactSolver13StoreImpulsesEv(i4) {
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i1 = STACKTOP;
+ i2 = HEAP32[i4 + 48 >> 2] | 0;
+ if ((i2 | 0) <= 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i3 = HEAP32[i4 + 40 >> 2] | 0;
+ i4 = HEAP32[i4 + 44 >> 2] | 0;
+ i5 = 0;
+ do {
+  i6 = HEAP32[i4 + (HEAP32[i3 + (i5 * 152 | 0) + 148 >> 2] << 2) >> 2] | 0;
+  i7 = HEAP32[i3 + (i5 * 152 | 0) + 144 >> 2] | 0;
+  if ((i7 | 0) > 0) {
+   i8 = 0;
+   do {
+    HEAPF32[i6 + (i8 * 20 | 0) + 72 >> 2] = +HEAPF32[i3 + (i5 * 152 | 0) + (i8 * 36 | 0) + 16 >> 2];
+    HEAPF32[i6 + (i8 * 20 | 0) + 76 >> 2] = +HEAPF32[i3 + (i5 * 152 | 0) + (i8 * 36 | 0) + 20 >> 2];
+    i8 = i8 + 1 | 0;
+   } while ((i8 | 0) < (i7 | 0));
+  }
+  i5 = i5 + 1 | 0;
+ } while ((i5 | 0) < (i2 | 0));
+ STACKTOP = i1;
+ return;
+}
+function __ZN16b2StackAllocator4FreeEPv(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i3 = STACKTOP;
+ i2 = i1 + 102796 | 0;
+ i4 = HEAP32[i2 >> 2] | 0;
+ if ((i4 | 0) <= 0) {
+  ___assert_fail(3952, 3808, 63, 3976);
+ }
+ i6 = i4 + -1 | 0;
+ if ((HEAP32[i1 + (i6 * 12 | 0) + 102412 >> 2] | 0) != (i5 | 0)) {
+  ___assert_fail(3984, 3808, 65, 3976);
+ }
+ if ((HEAP8[i1 + (i6 * 12 | 0) + 102420 | 0] | 0) == 0) {
+  i5 = i1 + (i6 * 12 | 0) + 102416 | 0;
+  i6 = i1 + 102400 | 0;
+  HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) - (HEAP32[i5 >> 2] | 0);
+ } else {
+  __Z6b2FreePv(i5);
+  i5 = i1 + (i6 * 12 | 0) + 102416 | 0;
+  i4 = HEAP32[i2 >> 2] | 0;
+ }
+ i6 = i1 + 102404 | 0;
+ HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) - (HEAP32[i5 >> 2] | 0);
+ HEAP32[i2 >> 2] = i4 + -1;
+ STACKTOP = i3;
+ return;
+}
+function __ZNK10__cxxabiv117__class_type_info27has_unambiguous_public_baseEPNS_19__dynamic_cast_infoEPvi(i5, i4, i3, i2) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i6 = 0;
+ i1 = STACKTOP;
+ if ((HEAP32[i4 + 8 >> 2] | 0) != (i5 | 0)) {
+  STACKTOP = i1;
+  return;
+ }
+ i5 = i4 + 16 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  HEAP32[i5 >> 2] = i3;
+  HEAP32[i4 + 24 >> 2] = i2;
+  HEAP32[i4 + 36 >> 2] = 1;
+  STACKTOP = i1;
+  return;
+ }
+ if ((i6 | 0) != (i3 | 0)) {
+  i6 = i4 + 36 | 0;
+  HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 1;
+  HEAP32[i4 + 24 >> 2] = 2;
+  HEAP8[i4 + 54 | 0] = 1;
+  STACKTOP = i1;
+  return;
+ }
+ i3 = i4 + 24 | 0;
+ if ((HEAP32[i3 >> 2] | 0) != 2) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP32[i3 >> 2] = i2;
+ STACKTOP = i1;
+ return;
+}
+function __ZN12b2BroadPhase11CreateProxyERK6b2AABBPv(i2, i4, i3) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i3 = __ZN13b2DynamicTree11CreateProxyERK6b2AABBPv(i2, i4, i3) | 0;
+ i4 = i2 + 28 | 0;
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + 1;
+ i4 = i2 + 40 | 0;
+ i5 = HEAP32[i4 >> 2] | 0;
+ i6 = i2 + 36 | 0;
+ i2 = i2 + 32 | 0;
+ if ((i5 | 0) == (HEAP32[i6 >> 2] | 0)) {
+  i7 = HEAP32[i2 >> 2] | 0;
+  HEAP32[i6 >> 2] = i5 << 1;
+  i5 = __Z7b2Alloci(i5 << 3) | 0;
+  HEAP32[i2 >> 2] = i5;
+  _memcpy(i5 | 0, i7 | 0, HEAP32[i4 >> 2] << 2 | 0) | 0;
+  __Z6b2FreePv(i7);
+  i5 = HEAP32[i4 >> 2] | 0;
+ }
+ HEAP32[(HEAP32[i2 >> 2] | 0) + (i5 << 2) >> 2] = i3;
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + 1;
+ STACKTOP = i1;
+ return i3 | 0;
+}
+function __ZN9b2ContactC2EP9b2FixtureiS1_i(i1, i4, i6, i3, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i7 = 0, d8 = 0.0, d9 = 0.0;
+ i2 = STACKTOP;
+ HEAP32[i1 >> 2] = 4440;
+ HEAP32[i1 + 4 >> 2] = 4;
+ HEAP32[i1 + 48 >> 2] = i4;
+ HEAP32[i1 + 52 >> 2] = i3;
+ HEAP32[i1 + 56 >> 2] = i6;
+ HEAP32[i1 + 60 >> 2] = i5;
+ HEAP32[i1 + 124 >> 2] = 0;
+ HEAP32[i1 + 128 >> 2] = 0;
+ i5 = i4 + 16 | 0;
+ i6 = i1 + 8 | 0;
+ i7 = i6 + 40 | 0;
+ do {
+  HEAP32[i6 >> 2] = 0;
+  i6 = i6 + 4 | 0;
+ } while ((i6 | 0) < (i7 | 0));
+ HEAPF32[i1 + 136 >> 2] = +Math_sqrt(+(+HEAPF32[i5 >> 2] * +HEAPF32[i3 + 16 >> 2]));
+ d8 = +HEAPF32[i4 + 20 >> 2];
+ d9 = +HEAPF32[i3 + 20 >> 2];
+ HEAPF32[i1 + 140 >> 2] = d8 > d9 ? d8 : d9;
+ STACKTOP = i2;
+ return;
+}
+function __ZN12b2BroadPhase9MoveProxyEiRK6b2AABBRK6b2Vec2(i3, i1, i5, i4) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ if (!(__ZN13b2DynamicTree9MoveProxyEiRK6b2AABBRK6b2Vec2(i3, i1, i5, i4) | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i4 = i3 + 40 | 0;
+ i5 = HEAP32[i4 >> 2] | 0;
+ i6 = i3 + 36 | 0;
+ i3 = i3 + 32 | 0;
+ if ((i5 | 0) == (HEAP32[i6 >> 2] | 0)) {
+  i7 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i6 >> 2] = i5 << 1;
+  i5 = __Z7b2Alloci(i5 << 3) | 0;
+  HEAP32[i3 >> 2] = i5;
+  _memcpy(i5 | 0, i7 | 0, HEAP32[i4 >> 2] << 2 | 0) | 0;
+  __Z6b2FreePv(i7);
+  i5 = HEAP32[i4 >> 2] | 0;
+ }
+ HEAP32[(HEAP32[i3 >> 2] | 0) + (i5 << 2) >> 2] = i1;
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + 1;
+ STACKTOP = i2;
+ return;
+}
+function __ZN24b2ChainAndPolygonContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i1, i3, i4, i5, i6) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i6 = __ZN16b2BlockAllocator8AllocateEi(i6, 144) | 0;
+ if ((i6 | 0) == 0) {
+  i6 = 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ __ZN9b2ContactC2EP9b2FixtureiS1_i(i6, i1, i3, i4, i5);
+ HEAP32[i6 >> 2] = 6032;
+ if ((HEAP32[(HEAP32[(HEAP32[i6 + 48 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) != 3) {
+  ___assert_fail(6048, 6096, 43, 6152);
+ }
+ if ((HEAP32[(HEAP32[(HEAP32[i6 + 52 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) == 2) {
+  STACKTOP = i2;
+  return i6 | 0;
+ } else {
+  ___assert_fail(6184, 6096, 44, 6152);
+ }
+ return 0;
+}
+function __ZN23b2ChainAndCircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i1, i3, i4, i5, i6) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i6 = __ZN16b2BlockAllocator8AllocateEi(i6, 144) | 0;
+ if ((i6 | 0) == 0) {
+  i6 = 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ __ZN9b2ContactC2EP9b2FixtureiS1_i(i6, i1, i3, i4, i5);
+ HEAP32[i6 >> 2] = 5784;
+ if ((HEAP32[(HEAP32[(HEAP32[i6 + 48 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) != 3) {
+  ___assert_fail(5800, 5848, 43, 5904);
+ }
+ if ((HEAP32[(HEAP32[(HEAP32[i6 + 52 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) == 0) {
+  STACKTOP = i2;
+  return i6 | 0;
+ } else {
+  ___assert_fail(5928, 5848, 44, 5904);
+ }
+ return 0;
+}
+function __ZN25b2PolygonAndCircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i1, i4, i2, i5, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ i4 = STACKTOP;
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i3, 144) | 0;
+ if ((i3 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i4;
+  return i5 | 0;
+ }
+ __ZN9b2ContactC2EP9b2FixtureiS1_i(i3, i1, 0, i2, 0);
+ HEAP32[i3 >> 2] = 4984;
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 48 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) != 2) {
+  ___assert_fail(5e3, 5048, 41, 5104);
+ }
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 52 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) == 0) {
+  i5 = i3;
+  STACKTOP = i4;
+  return i5 | 0;
+ } else {
+  ___assert_fail(5136, 5048, 42, 5104);
+ }
+ return 0;
+}
+function __ZN23b2EdgeAndPolygonContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i1, i4, i2, i5, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ i4 = STACKTOP;
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i3, 144) | 0;
+ if ((i3 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i4;
+  return i5 | 0;
+ }
+ __ZN9b2ContactC2EP9b2FixtureiS1_i(i3, i1, 0, i2, 0);
+ HEAP32[i3 >> 2] = 4736;
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 48 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) != 1) {
+  ___assert_fail(4752, 4800, 41, 4856);
+ }
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 52 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) == 2) {
+  i5 = i3;
+  STACKTOP = i4;
+  return i5 | 0;
+ } else {
+  ___assert_fail(4880, 4800, 42, 4856);
+ }
+ return 0;
+}
+function __ZN22b2EdgeAndCircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i1, i4, i2, i5, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ i4 = STACKTOP;
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i3, 144) | 0;
+ if ((i3 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i4;
+  return i5 | 0;
+ }
+ __ZN9b2ContactC2EP9b2FixtureiS1_i(i3, i1, 0, i2, 0);
+ HEAP32[i3 >> 2] = 4488;
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 48 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) != 1) {
+  ___assert_fail(4504, 4552, 41, 4608);
+ }
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 52 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) == 0) {
+  i5 = i3;
+  STACKTOP = i4;
+  return i5 | 0;
+ } else {
+  ___assert_fail(4632, 4552, 42, 4608);
+ }
+ return 0;
+}
+function __ZN14b2PolygonShape8SetAsBoxEff(i1, d3, d2) {
+ i1 = i1 | 0;
+ d3 = +d3;
+ d2 = +d2;
+ var d4 = 0.0, d5 = 0.0;
+ HEAP32[i1 + 148 >> 2] = 4;
+ d4 = -d3;
+ d5 = -d2;
+ HEAPF32[i1 + 20 >> 2] = d4;
+ HEAPF32[i1 + 24 >> 2] = d5;
+ HEAPF32[i1 + 28 >> 2] = d3;
+ HEAPF32[i1 + 32 >> 2] = d5;
+ HEAPF32[i1 + 36 >> 2] = d3;
+ HEAPF32[i1 + 40 >> 2] = d2;
+ HEAPF32[i1 + 44 >> 2] = d4;
+ HEAPF32[i1 + 48 >> 2] = d2;
+ HEAPF32[i1 + 84 >> 2] = 0.0;
+ HEAPF32[i1 + 88 >> 2] = -1.0;
+ HEAPF32[i1 + 92 >> 2] = 1.0;
+ HEAPF32[i1 + 96 >> 2] = 0.0;
+ HEAPF32[i1 + 100 >> 2] = 0.0;
+ HEAPF32[i1 + 104 >> 2] = 1.0;
+ HEAPF32[i1 + 108 >> 2] = -1.0;
+ HEAPF32[i1 + 112 >> 2] = 0.0;
+ HEAPF32[i1 + 12 >> 2] = 0.0;
+ HEAPF32[i1 + 16 >> 2] = 0.0;
+ return;
+}
+function __ZN16b2PolygonContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i1, i4, i2, i5, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ i4 = STACKTOP;
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i3, 144) | 0;
+ if ((i3 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i4;
+  return i5 | 0;
+ }
+ __ZN9b2ContactC2EP9b2FixtureiS1_i(i3, i1, 0, i2, 0);
+ HEAP32[i3 >> 2] = 5240;
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 48 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) != 2) {
+  ___assert_fail(5256, 5304, 44, 5352);
+ }
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 52 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) == 2) {
+  i5 = i3;
+  STACKTOP = i4;
+  return i5 | 0;
+ } else {
+  ___assert_fail(5376, 5304, 45, 5352);
+ }
+ return 0;
+}
+function __ZN15b2CircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i1, i4, i2, i5, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ i4 = STACKTOP;
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i3, 144) | 0;
+ if ((i3 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i4;
+  return i5 | 0;
+ }
+ __ZN9b2ContactC2EP9b2FixtureiS1_i(i3, i1, 0, i2, 0);
+ HEAP32[i3 >> 2] = 6288;
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 48 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) != 0) {
+  ___assert_fail(6304, 6352, 44, 6400);
+ }
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 52 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) == 0) {
+  i5 = i3;
+  STACKTOP = i4;
+  return i5 | 0;
+ } else {
+  ___assert_fail(6416, 6352, 45, 6400);
+ }
+ return 0;
+}
+function __ZN7b2World10CreateBodyEPK9b2BodyDef(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i5 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[i1 + 102868 >> 2] & 2 | 0) != 0) {
+  ___assert_fail(2160, 2184, 109, 2216);
+ }
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i1, 152) | 0;
+ if ((i3 | 0) == 0) {
+  i3 = 0;
+ } else {
+  __ZN6b2BodyC2EPK9b2BodyDefP7b2World(i3, i4, i1);
+ }
+ HEAP32[i3 + 92 >> 2] = 0;
+ i4 = i1 + 102952 | 0;
+ HEAP32[i3 + 96 >> 2] = HEAP32[i4 >> 2];
+ i5 = HEAP32[i4 >> 2] | 0;
+ if ((i5 | 0) != 0) {
+  HEAP32[i5 + 92 >> 2] = i3;
+ }
+ HEAP32[i4 >> 2] = i3;
+ i5 = i1 + 102960 | 0;
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 1;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function __ZNK6b2Body13ShouldCollideEPKS_(i4, i2) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ if ((HEAP32[i4 >> 2] | 0) != 2 ? (HEAP32[i2 >> 2] | 0) != 2 : 0) {
+  i2 = 0;
+ } else {
+  i3 = 3;
+ }
+ L3 : do {
+  if ((i3 | 0) == 3) {
+   i3 = HEAP32[i4 + 108 >> 2] | 0;
+   if ((i3 | 0) == 0) {
+    i2 = 1;
+   } else {
+    while (1) {
+     if ((HEAP32[i3 >> 2] | 0) == (i2 | 0) ? (HEAP8[(HEAP32[i3 + 4 >> 2] | 0) + 61 | 0] | 0) == 0 : 0) {
+      i2 = 0;
+      break L3;
+     }
+     i3 = HEAP32[i3 + 12 >> 2] | 0;
+     if ((i3 | 0) == 0) {
+      i2 = 1;
+      break;
+     }
+    }
+   }
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function __ZNK14b2PolygonShape5CloneEP16b2BlockAllocator(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i3, 152) | 0;
+ if ((i3 | 0) == 0) {
+  i3 = 0;
+ } else {
+  HEAP32[i3 >> 2] = 504;
+  HEAP32[i3 + 4 >> 2] = 2;
+  HEAPF32[i3 + 8 >> 2] = .009999999776482582;
+  HEAP32[i3 + 148 >> 2] = 0;
+  HEAPF32[i3 + 12 >> 2] = 0.0;
+  HEAPF32[i3 + 16 >> 2] = 0.0;
+ }
+ i6 = i1 + 4 | 0;
+ i5 = HEAP32[i6 + 4 >> 2] | 0;
+ i4 = i3 + 4 | 0;
+ HEAP32[i4 >> 2] = HEAP32[i6 >> 2];
+ HEAP32[i4 + 4 >> 2] = i5;
+ _memcpy(i3 + 12 | 0, i1 + 12 | 0, 140) | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function __ZN7b2World16SetAllowSleepingEb(i2, i4) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i3 = i2 + 102976 | 0;
+ if ((i4 & 1 | 0) == (HEAPU8[i3] | 0 | 0)) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP8[i3] = i4 & 1;
+ if (i4) {
+  STACKTOP = i1;
+  return;
+ }
+ i2 = HEAP32[i2 + 102952 >> 2] | 0;
+ if ((i2 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ do {
+  i3 = i2 + 4 | 0;
+  i4 = HEAPU16[i3 >> 1] | 0;
+  if ((i4 & 2 | 0) == 0) {
+   HEAP16[i3 >> 1] = i4 | 2;
+   HEAPF32[i2 + 144 >> 2] = 0.0;
+  }
+  i2 = HEAP32[i2 + 96 >> 2] | 0;
+ } while ((i2 | 0) != 0);
+ STACKTOP = i1;
+ return;
+}
+function __ZN16b2BlockAllocator4FreeEPvi(i3, i1, i4) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((i4 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((i4 | 0) <= 0) {
+  ___assert_fail(1376, 1312, 164, 1488);
+ }
+ if ((i4 | 0) > 640) {
+  __Z6b2FreePv(i1);
+  STACKTOP = i2;
+  return;
+ }
+ i4 = HEAP8[632 + i4 | 0] | 0;
+ if (!((i4 & 255) < 14)) {
+  ___assert_fail(1408, 1312, 173, 1488);
+ }
+ i4 = i3 + ((i4 & 255) << 2) + 12 | 0;
+ HEAP32[i1 >> 2] = HEAP32[i4 >> 2];
+ HEAP32[i4 >> 2] = i1;
+ STACKTOP = i2;
+ return;
+}
+function __ZN15b2ContactFilter13ShouldCollideEP9b2FixtureS1_(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ i3 = STACKTOP;
+ i4 = HEAP16[i2 + 36 >> 1] | 0;
+ if (!(i4 << 16 >> 16 != (HEAP16[i1 + 36 >> 1] | 0) | i4 << 16 >> 16 == 0)) {
+  i4 = i4 << 16 >> 16 > 0;
+  STACKTOP = i3;
+  return i4 | 0;
+ }
+ if ((HEAP16[i1 + 32 >> 1] & HEAP16[i2 + 34 >> 1]) << 16 >> 16 == 0) {
+  i4 = 0;
+  STACKTOP = i3;
+  return i4 | 0;
+ }
+ i4 = (HEAP16[i1 + 34 >> 1] & HEAP16[i2 + 32 >> 1]) << 16 >> 16 != 0;
+ STACKTOP = i3;
+ return i4 | 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function __ZN6b2Body13CreateFixtureEPK7b2Shapef(i1, i3, d2) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ d2 = +d2;
+ var i4 = 0, i5 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i5 = i4;
+ HEAP16[i5 + 22 >> 1] = 1;
+ HEAP16[i5 + 24 >> 1] = -1;
+ HEAP16[i5 + 26 >> 1] = 0;
+ HEAP32[i5 + 4 >> 2] = 0;
+ HEAPF32[i5 + 8 >> 2] = .20000000298023224;
+ HEAPF32[i5 + 12 >> 2] = 0.0;
+ HEAP8[i5 + 20 | 0] = 0;
+ HEAP32[i5 >> 2] = i3;
+ HEAPF32[i5 + 16 >> 2] = d2;
+ i3 = __ZN6b2Body13CreateFixtureEPK12b2FixtureDef(i1, i5) | 0;
+ STACKTOP = i4;
+ return i3 | 0;
+}
+function __Znwj(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i2 = (i2 | 0) == 0 ? 1 : i2;
+ while (1) {
+  i3 = _malloc(i2) | 0;
+  if ((i3 | 0) != 0) {
+   i2 = 6;
+   break;
+  }
+  i3 = HEAP32[1914] | 0;
+  HEAP32[1914] = i3 + 0;
+  if ((i3 | 0) == 0) {
+   i2 = 5;
+   break;
+  }
+  FUNCTION_TABLE_v[i3 & 3]();
+ }
+ if ((i2 | 0) == 5) {
+  i3 = ___cxa_allocate_exception(4) | 0;
+  HEAP32[i3 >> 2] = 7672;
+  ___cxa_throw(i3 | 0, 7720, 30);
+ } else if ((i2 | 0) == 6) {
+  STACKTOP = i1;
+  return i3 | 0;
+ }
+ return 0;
+}
+function __ZN8b2IslandD2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZN16b2StackAllocator4FreeEPv(HEAP32[i1 >> 2] | 0, HEAP32[i1 + 20 >> 2] | 0);
+ __ZN16b2StackAllocator4FreeEPv(HEAP32[i1 >> 2] | 0, HEAP32[i1 + 24 >> 2] | 0);
+ __ZN16b2StackAllocator4FreeEPv(HEAP32[i1 >> 2] | 0, HEAP32[i1 + 16 >> 2] | 0);
+ __ZN16b2StackAllocator4FreeEPv(HEAP32[i1 >> 2] | 0, HEAP32[i1 + 12 >> 2] | 0);
+ __ZN16b2StackAllocator4FreeEPv(HEAP32[i1 >> 2] | 0, HEAP32[i1 + 8 >> 2] | 0);
+ STACKTOP = i2;
+ return;
+}
+function __ZN16b2BlockAllocatorD2Ev(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i1 = STACKTOP;
+ i3 = i2 + 4 | 0;
+ i4 = HEAP32[i2 >> 2] | 0;
+ if ((HEAP32[i3 >> 2] | 0) > 0) {
+  i5 = 0;
+ } else {
+  i5 = i4;
+  __Z6b2FreePv(i5);
+  STACKTOP = i1;
+  return;
+ }
+ do {
+  __Z6b2FreePv(HEAP32[i4 + (i5 << 3) + 4 >> 2] | 0);
+  i5 = i5 + 1 | 0;
+  i4 = HEAP32[i2 >> 2] | 0;
+ } while ((i5 | 0) < (HEAP32[i3 >> 2] | 0));
+ __Z6b2FreePv(i4);
+ STACKTOP = i1;
+ return;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function __ZNK11b2EdgeShape11ComputeMassEP10b2MassDataf(i2, i1, d3) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ d3 = +d3;
+ var i4 = 0, d5 = 0.0;
+ i4 = STACKTOP;
+ HEAPF32[i1 >> 2] = 0.0;
+ d5 = +((+HEAPF32[i2 + 12 >> 2] + +HEAPF32[i2 + 20 >> 2]) * .5);
+ d3 = +((+HEAPF32[i2 + 16 >> 2] + +HEAPF32[i2 + 24 >> 2]) * .5);
+ i2 = i1 + 4 | 0;
+ HEAPF32[i2 >> 2] = d5;
+ HEAPF32[i2 + 4 >> 2] = d3;
+ HEAPF32[i1 + 12 >> 2] = 0.0;
+ STACKTOP = i4;
+ return;
+}
+function __ZN11b2EdgeShape3SetERK6b2Vec2S2_(i1, i3, i2) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i4 = 0, i5 = 0;
+ i5 = i3;
+ i3 = HEAP32[i5 + 4 >> 2] | 0;
+ i4 = i1 + 12 | 0;
+ HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+ HEAP32[i4 + 4 >> 2] = i3;
+ i4 = i2;
+ i2 = HEAP32[i4 + 4 >> 2] | 0;
+ i3 = i1 + 20 | 0;
+ HEAP32[i3 >> 2] = HEAP32[i4 >> 2];
+ HEAP32[i3 + 4 >> 2] = i2;
+ HEAP8[i1 + 44 | 0] = 0;
+ HEAP8[i1 + 45 | 0] = 0;
+ return;
+}
+function __ZN25b2PolygonAndCircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_(i2, i4, i3, i1) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0;
+ i5 = STACKTOP;
+ __Z25b2CollidePolygonAndCircleP10b2ManifoldPK14b2PolygonShapeRK11b2TransformPK13b2CircleShapeS6_(i4, HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 12 >> 2] | 0, i3, HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 12 >> 2] | 0, i1);
+ STACKTOP = i5;
+ return;
+}
+function __ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_(i2, i4, i3, i1) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0;
+ i5 = STACKTOP;
+ __Z23b2CollideEdgeAndPolygonP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK14b2PolygonShapeS6_(i4, HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 12 >> 2] | 0, i3, HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 12 >> 2] | 0, i1);
+ STACKTOP = i5;
+ return;
+}
+function __ZN22b2EdgeAndCircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_(i2, i4, i3, i1) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0;
+ i5 = STACKTOP;
+ __Z22b2CollideEdgeAndCircleP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK13b2CircleShapeS6_(i4, HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 12 >> 2] | 0, i3, HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 12 >> 2] | 0, i1);
+ STACKTOP = i5;
+ return;
+}
+function __Z23b2CollideEdgeAndPolygonP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK14b2PolygonShapeS6_(i5, i4, i3, i2, i1) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i6 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 256 | 0;
+ __ZN12b2EPCollider7CollideEP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK14b2PolygonShapeS7_(i6, i5, i4, i3, i2, i1);
+ STACKTOP = i6;
+ return;
+}
+function __ZN16b2PolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_(i2, i4, i3, i1) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0;
+ i5 = STACKTOP;
+ __Z17b2CollidePolygonsP10b2ManifoldPK14b2PolygonShapeRK11b2TransformS3_S6_(i4, HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 12 >> 2] | 0, i3, HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 12 >> 2] | 0, i1);
+ STACKTOP = i5;
+ return;
+}
+function __ZN15b2CircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_(i2, i4, i3, i1) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0;
+ i5 = STACKTOP;
+ __Z16b2CollideCirclesP10b2ManifoldPK13b2CircleShapeRK11b2TransformS3_S6_(i4, HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 12 >> 2] | 0, i3, HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 12 >> 2] | 0, i1);
+ STACKTOP = i5;
+ return;
+}
+function __Z14b2PairLessThanRK6b2PairS1_(i2, i5) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i2 >> 2] | 0;
+ i3 = HEAP32[i5 >> 2] | 0;
+ if ((i4 | 0) >= (i3 | 0)) {
+  if ((i4 | 0) == (i3 | 0)) {
+   i2 = (HEAP32[i2 + 4 >> 2] | 0) < (HEAP32[i5 + 4 >> 2] | 0);
+  } else {
+   i2 = 0;
+  }
+ } else {
+  i2 = 1;
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function __ZN9b2FixtureC2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ HEAP16[i1 + 32 >> 1] = 1;
+ HEAP16[i1 + 34 >> 1] = -1;
+ HEAP16[i1 + 36 >> 1] = 0;
+ HEAP32[i1 + 40 >> 2] = 0;
+ HEAP32[i1 + 24 >> 2] = 0;
+ HEAP32[i1 + 28 >> 2] = 0;
+ HEAP32[i1 + 0 >> 2] = 0;
+ HEAP32[i1 + 4 >> 2] = 0;
+ HEAP32[i1 + 8 >> 2] = 0;
+ HEAP32[i1 + 12 >> 2] = 0;
+ STACKTOP = i2;
+ return;
+}
+function __ZN12b2BroadPhaseC2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZN13b2DynamicTreeC2Ev(i1);
+ HEAP32[i1 + 28 >> 2] = 0;
+ HEAP32[i1 + 48 >> 2] = 16;
+ HEAP32[i1 + 52 >> 2] = 0;
+ HEAP32[i1 + 44 >> 2] = __Z7b2Alloci(192) | 0;
+ HEAP32[i1 + 36 >> 2] = 16;
+ HEAP32[i1 + 40 >> 2] = 0;
+ HEAP32[i1 + 32 >> 2] = __Z7b2Alloci(64) | 0;
+ STACKTOP = i2;
+ return;
+}
+function __ZN16b2StackAllocatorD2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[i1 + 102400 >> 2] | 0) != 0) {
+  ___assert_fail(3792, 3808, 32, 3848);
+ }
+ if ((HEAP32[i1 + 102796 >> 2] | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ } else {
+  ___assert_fail(3872, 3808, 33, 3848);
+ }
+}
+function __ZN15b2ContactSolverD2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = i1 + 32 | 0;
+ __ZN16b2StackAllocator4FreeEPv(HEAP32[i3 >> 2] | 0, HEAP32[i1 + 40 >> 2] | 0);
+ __ZN16b2StackAllocator4FreeEPv(HEAP32[i3 >> 2] | 0, HEAP32[i1 + 36 >> 2] | 0);
+ STACKTOP = i2;
+ return;
+}
+function __ZN25b2PolygonAndCircleContact7DestroyEP9b2ContactP16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ FUNCTION_TABLE_vi[HEAP32[(HEAP32[i1 >> 2] | 0) + 4 >> 2] & 31](i1);
+ __ZN16b2BlockAllocator4FreeEPvi(i2, i1, 144);
+ STACKTOP = i3;
+ return;
+}
+function __ZN24b2ChainAndPolygonContact7DestroyEP9b2ContactP16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ FUNCTION_TABLE_vi[HEAP32[(HEAP32[i1 >> 2] | 0) + 4 >> 2] & 31](i1);
+ __ZN16b2BlockAllocator4FreeEPvi(i2, i1, 144);
+ STACKTOP = i3;
+ return;
+}
+function __ZN23b2EdgeAndPolygonContact7DestroyEP9b2ContactP16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ FUNCTION_TABLE_vi[HEAP32[(HEAP32[i1 >> 2] | 0) + 4 >> 2] & 31](i1);
+ __ZN16b2BlockAllocator4FreeEPvi(i2, i1, 144);
+ STACKTOP = i3;
+ return;
+}
+function __ZN23b2ChainAndCircleContact7DestroyEP9b2ContactP16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ FUNCTION_TABLE_vi[HEAP32[(HEAP32[i1 >> 2] | 0) + 4 >> 2] & 31](i1);
+ __ZN16b2BlockAllocator4FreeEPvi(i2, i1, 144);
+ STACKTOP = i3;
+ return;
+}
+function __ZN22b2EdgeAndCircleContact7DestroyEP9b2ContactP16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ FUNCTION_TABLE_vi[HEAP32[(HEAP32[i1 >> 2] | 0) + 4 >> 2] & 31](i1);
+ __ZN16b2BlockAllocator4FreeEPvi(i2, i1, 144);
+ STACKTOP = i3;
+ return;
+}
+function __ZN16b2ContactManagerC2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZN12b2BroadPhaseC2Ev(i1);
+ HEAP32[i1 + 60 >> 2] = 0;
+ HEAP32[i1 + 64 >> 2] = 0;
+ HEAP32[i1 + 68 >> 2] = 1888;
+ HEAP32[i1 + 72 >> 2] = 1896;
+ HEAP32[i1 + 76 >> 2] = 0;
+ STACKTOP = i2;
+ return;
+}
+function __ZN16b2PolygonContact7DestroyEP9b2ContactP16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ FUNCTION_TABLE_vi[HEAP32[(HEAP32[i1 >> 2] | 0) + 4 >> 2] & 31](i1);
+ __ZN16b2BlockAllocator4FreeEPvi(i2, i1, 144);
+ STACKTOP = i3;
+ return;
+}
+function __ZN15b2CircleContact7DestroyEP9b2ContactP16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ FUNCTION_TABLE_vi[HEAP32[(HEAP32[i1 >> 2] | 0) + 4 >> 2] & 31](i1);
+ __ZN16b2BlockAllocator4FreeEPvi(i2, i1, 144);
+ STACKTOP = i3;
+ return;
+}
+function dynCall_viiiiii(i7, i6, i5, i4, i3, i2, i1) {
+ i7 = i7 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_viiiiii[i7 & 3](i6 | 0, i5 | 0, i4 | 0, i3 | 0, i2 | 0, i1 | 0);
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function dynCall_iiiiii(i6, i5, i4, i3, i2, i1) {
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iiiiii[i6 & 15](i5 | 0, i4 | 0, i3 | 0, i2 | 0, i1 | 0) | 0;
+}
+function dynCall_viiiii(i6, i5, i4, i3, i2, i1) {
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_viiiii[i6 & 3](i5 | 0, i4 | 0, i3 | 0, i2 | 0, i1 | 0);
+}
+function __ZN16b2ContactManager15FindNewContactsEv(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZN12b2BroadPhase11UpdatePairsI16b2ContactManagerEEvPT_(i1, i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN16b2StackAllocatorC2Ev(i1) {
+ i1 = i1 | 0;
+ HEAP32[i1 + 102400 >> 2] = 0;
+ HEAP32[i1 + 102404 >> 2] = 0;
+ HEAP32[i1 + 102408 >> 2] = 0;
+ HEAP32[i1 + 102796 >> 2] = 0;
+ return;
+}
+function dynCall_viiii(i5, i4, i3, i2, i1) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_viiii[i5 & 15](i4 | 0, i3 | 0, i2 | 0, i1 | 0);
+}
+function dynCall_iiii(i4, i3, i2, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iiii[i4 & 7](i3 | 0, i2 | 0, i1 | 0) | 0;
+}
+function dynCall_viii(i4, i3, i2, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_viii[i4 & 3](i3 | 0, i2 | 0, i1 | 0);
+}
+function __ZNSt9bad_allocD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZNSt9exceptionD2Ev(i1 | 0);
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function __ZN13b2DynamicTreeD2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __Z6b2FreePv(HEAP32[i1 + 4 >> 2] | 0);
+ STACKTOP = i2;
+ return;
+}
+function dynCall_viid(i4, i3, i2, d1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ d1 = +d1;
+ FUNCTION_TABLE_viid[i4 & 3](i3 | 0, i2 | 0, +d1);
+}
+function __ZN17b2ContactListener9PostSolveEP9b2ContactPK16b2ContactImpulse(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ return;
+}
+function __ZN10__cxxabiv120__si_class_type_infoD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN10__cxxabiv117__class_type_infoD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZNSt9bad_allocD2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZNSt9exceptionD2Ev(i1 | 0);
+ STACKTOP = i2;
+ return;
+}
+function dynCall_iii(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iii[i3 & 3](i2 | 0, i1 | 0) | 0;
+}
+function b8(i1, i2, i3, i4, i5, i6) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ abort(8);
+}
+function __ZN25b2PolygonAndCircleContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN17b2ContactListener8PreSolveEP9b2ContactPK10b2Manifold(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ return;
+}
+function __ZN24b2ChainAndPolygonContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN23b2EdgeAndPolygonContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN23b2ChainAndCircleContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZNK11b2EdgeShape9TestPointERK11b2TransformRK6b2Vec2(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ return 0;
+}
+function __ZN22b2EdgeAndCircleContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZdlPv(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((i1 | 0) != 0) {
+  _free(i1);
+ }
+ STACKTOP = i2;
+ return;
+}
+function b10(i1, i2, i3, i4, i5) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ abort(10);
+ return 0;
+}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function __Z7b2Alloci(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _malloc(i1) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function __ZN17b2ContactListenerD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN16b2PolygonContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function dynCall_vii(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_vii[i3 & 15](i2 | 0, i1 | 0);
+}
+function __ZN15b2ContactFilterD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN15b2CircleContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN14b2PolygonShapeD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __Znaj(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = __Znwj(i1) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function __ZN11b2EdgeShapeD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN9b2ContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function b1(i1, i2, i3, i4, i5) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ abort(1);
+}
+function __Z6b2FreePv(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _free(i1);
+ STACKTOP = i2;
+ return;
+}
+function ___clang_call_terminate(i1) {
+ i1 = i1 | 0;
+ ___cxa_begin_catch(i1 | 0) | 0;
+ __ZSt9terminatev();
+}
+function __ZN17b2ContactListener12BeginContactEP9b2Contact(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ return;
+}
+function dynCall_ii(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_ii[i2 & 3](i1 | 0) | 0;
+}
+function __ZN17b2ContactListener10EndContactEP9b2Contact(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ return;
+}
+function b11(i1, i2, i3, i4) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ abort(11);
+}
+function dynCall_vi(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_vi[i2 & 31](i1 | 0);
+}
+function b0(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ abort(0);
+ return 0;
+}
+function __ZNK10__cxxabiv116__shim_type_info5noop2Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZNK10__cxxabiv116__shim_type_info5noop1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function b5(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ abort(5);
+}
+function __ZNK14b2PolygonShape13GetChildCountEv(i1) {
+ i1 = i1 | 0;
+ return 1;
+}
+function __ZN10__cxxabiv116__shim_type_infoD2Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function b7(i1, i2, d3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ d3 = +d3;
+ abort(7);
+}
+function __ZNK11b2EdgeShape13GetChildCountEv(i1) {
+ i1 = i1 | 0;
+ return 1;
+}
+function __ZNK7b2Timer15GetMillisecondsEv(i1) {
+ i1 = i1 | 0;
+ return 0.0;
+}
+function __ZN25b2PolygonAndCircleContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN24b2ChainAndPolygonContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function b9(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ abort(9);
+ return 0;
+}
+function __ZN23b2EdgeAndPolygonContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN23b2ChainAndCircleContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN22b2EdgeAndCircleContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function dynCall_v(i1) {
+ i1 = i1 | 0;
+ FUNCTION_TABLE_v[i1 & 3]();
+}
+function __ZNKSt9bad_alloc4whatEv(i1) {
+ i1 = i1 | 0;
+ return 7688;
+}
+function ___cxa_pure_virtual__wrapper() {
+ ___cxa_pure_virtual();
+}
+function __ZN17b2ContactListenerD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN16b2PolygonContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN15b2ContactFilterD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN15b2CircleContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN14b2PolygonShapeD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function b3(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ abort(3);
+}
+function runPostSets() {
+ HEAP32[1932] = __ZTISt9exception;
+}
+function __ZN11b2EdgeShapeD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZNSt9type_infoD2Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN7b2Timer5ResetEv(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function __ZN9b2ContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN7b2TimerC2Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function b4(i1) {
+ i1 = i1 | 0;
+ abort(4);
+ return 0;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+function b2(i1) {
+ i1 = i1 | 0;
+ abort(2);
+}
+function b6() {
+ abort(6);
+}
+
+// EMSCRIPTEN_END_FUNCS
+  var FUNCTION_TABLE_iiii = [b0,__ZNK11b2EdgeShape9TestPointERK11b2TransformRK6b2Vec2,__ZNK14b2PolygonShape9TestPointERK11b2TransformRK6b2Vec2,__ZN15b2ContactFilter13ShouldCollideEP9b2FixtureS1_,__ZNK10__cxxabiv117__class_type_info9can_catchEPKNS_16__shim_type_infoERPv,b0,b0,b0];
+  var FUNCTION_TABLE_viiiii = [b1,__ZNK10__cxxabiv117__class_type_info16search_below_dstEPNS_19__dynamic_cast_infoEPKvib,__ZNK10__cxxabiv120__si_class_type_info16search_below_dstEPNS_19__dynamic_cast_infoEPKvib,b1];
+  var FUNCTION_TABLE_vi = [b2,__ZN11b2EdgeShapeD1Ev,__ZN11b2EdgeShapeD0Ev,__ZN14b2PolygonShapeD1Ev,__ZN14b2PolygonShapeD0Ev,__ZN17b2ContactListenerD1Ev,__ZN17b2ContactListenerD0Ev,__ZN15b2ContactFilterD1Ev,__ZN15b2ContactFilterD0Ev,__ZN9b2ContactD1Ev,__ZN9b2ContactD0Ev,__ZN22b2EdgeAndCircleContactD1Ev,__ZN22b2EdgeAndCircleContactD0Ev,__ZN23b2EdgeAndPolygonContactD1Ev,__ZN23b2EdgeAndPolygonContactD0Ev,__ZN25b2PolygonAndCircleContactD1Ev,__ZN25b2PolygonAndCircleContactD0Ev,__ZN16b2PolygonContactD1Ev,__ZN16b2PolygonContactD0Ev,__ZN23b2ChainAndCircleContactD1Ev,__ZN23b2ChainAndCircleContactD0Ev,__ZN24b2ChainAndPolygonContactD1Ev,__ZN24b2ChainAndPolygonContactD0Ev,__ZN15b2CircleContactD1Ev,__ZN15b2CircleContactD0Ev,__ZN10__cxxabiv116__shim_type_infoD2Ev,__ZN10__cxxabiv117__class_type_infoD0Ev,__ZNK10__cxxabiv116__shim_type_info5noop1Ev,__ZNK10__cxxabiv116__shim_type_info5noop2Ev
+  ,__ZN10__cxxabiv120__si_class_type_infoD0Ev,__ZNSt9bad_allocD2Ev,__ZNSt9bad_allocD0Ev];
+  var FUNCTION_TABLE_vii = [b3,__ZN17b2ContactListener12BeginContactEP9b2Contact,__ZN17b2ContactListener10EndContactEP9b2Contact,__ZN15b2CircleContact7DestroyEP9b2ContactP16b2BlockAllocator,__ZN25b2PolygonAndCircleContact7DestroyEP9b2ContactP16b2BlockAllocator,__ZN16b2PolygonContact7DestroyEP9b2ContactP16b2BlockAllocator,__ZN22b2EdgeAndCircleContact7DestroyEP9b2ContactP16b2BlockAllocator,__ZN23b2EdgeAndPolygonContact7DestroyEP9b2ContactP16b2BlockAllocator,__ZN23b2ChainAndCircleContact7DestroyEP9b2ContactP16b2BlockAllocator,__ZN24b2ChainAndPolygonContact7DestroyEP9b2ContactP16b2BlockAllocator,b3,b3,b3,b3,b3,b3];
+  var FUNCTION_TABLE_ii = [b4,__ZNK11b2EdgeShape13GetChildCountEv,__ZNK14b2PolygonShape13GetChildCountEv,__ZNKSt9bad_alloc4whatEv];
+  var FUNCTION_TABLE_viii = [b5,__ZN17b2ContactListener8PreSolveEP9b2ContactPK10b2Manifold,__ZN17b2ContactListener9PostSolveEP9b2ContactPK16b2ContactImpulse,b5];
+  var FUNCTION_TABLE_v = [b6,___cxa_pure_virtual__wrapper,__Z4iterv,b6];
+  var FUNCTION_TABLE_viid = [b7,__ZNK11b2EdgeShape11ComputeMassEP10b2MassDataf,__ZNK14b2PolygonShape11ComputeMassEP10b2MassDataf,b7];
+  var FUNCTION_TABLE_viiiiii = [b8,__ZNK10__cxxabiv117__class_type_info16search_above_dstEPNS_19__dynamic_cast_infoEPKvS4_ib,__ZNK10__cxxabiv120__si_class_type_info16search_above_dstEPNS_19__dynamic_cast_infoEPKvS4_ib,b8];
+  var FUNCTION_TABLE_iii = [b9,__ZNK11b2EdgeShape5CloneEP16b2BlockAllocator,__ZNK14b2PolygonShape5CloneEP16b2BlockAllocator,__Z14b2PairLessThanRK6b2PairS1_];
+  var FUNCTION_TABLE_iiiiii = [b10,__ZNK11b2EdgeShape7RayCastEP15b2RayCastOutputRK14b2RayCastInputRK11b2Transformi,__ZNK14b2PolygonShape7RayCastEP15b2RayCastOutputRK14b2RayCastInputRK11b2Transformi,__ZN15b2CircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator,__ZN25b2PolygonAndCircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator,__ZN16b2PolygonContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator,__ZN22b2EdgeAndCircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator,__ZN23b2EdgeAndPolygonContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator,__ZN23b2ChainAndCircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator,__ZN24b2ChainAndPolygonContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator,b10,b10,b10,b10,b10,b10];
+  var FUNCTION_TABLE_viiii = [b11,__ZNK11b2EdgeShape11ComputeAABBEP6b2AABBRK11b2Transformi,__ZNK14b2PolygonShape11ComputeAABBEP6b2AABBRK11b2Transformi,__ZN22b2EdgeAndCircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_,__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_,__ZN25b2PolygonAndCircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_,__ZN16b2PolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_,__ZN23b2ChainAndCircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_,__ZN24b2ChainAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_,__ZN15b2CircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_,__ZNK10__cxxabiv117__class_type_info27has_unambiguous_public_baseEPNS_19__dynamic_cast_infoEPvi,__ZNK10__cxxabiv120__si_class_type_info27has_unambiguous_public_baseEPNS_19__dynamic_cast_infoEPvi,b11,b11,b11,b11];
+
+  return { _strlen: _strlen, _free: _free, _main: _main, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9, dynCall_iiii: dynCall_iiii, dynCall_viiiii: dynCall_viiiii, dynCall_vi: dynCall_vi, dynCall_vii: dynCall_vii, dynCall_ii: dynCall_ii, dynCall_viii: dynCall_viii, dynCall_v: dynCall_v, dynCall_viid: dynCall_viid, dynCall_viiiiii: dynCall_viiiiii, dynCall_iii: dynCall_iii, dynCall_iiiiii: dynCall_iiiiii, dynCall_viiii: dynCall_viiii };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "invoke_iiii": invoke_iiii, "invoke_viiiii": invoke_viiiii, "invoke_vi": invoke_vi, "invoke_vii": invoke_vii, "invoke_ii": invoke_ii, "invoke_viii": invoke_viii, "invoke_v": invoke_v, "invoke_viid": invoke_viid, "invoke_viiiiii": invoke_viiiiii, "invoke_iii": invoke_iii, "invoke_iiiiii": invoke_iiiiii, "invoke_viiii": invoke_viiii, "___cxa_throw": ___cxa_throw, "_emscripten_run_script": _emscripten_run_script, "_cosf": _cosf, "_send": _send, "__ZSt9terminatev": __ZSt9terminatev, "__reallyNegative": __reallyNegative, "___cxa_is_number_type": ___cxa_is_number_type, "___assert_fail": ___assert_fail, "___cxa_allocate_exception": ___cxa_allocate_exception, "___cxa_find_matching_catch": ___cxa_find_matching_catch, "_fflush": _fflush, "_pwrite": _pwrite, "___setErrNo": ___setErrNo, "_sbrk": _sbrk, "___cxa_begin_catch": ___cxa_begin_catch, "_sinf": _sinf, "_fileno": _fileno, "___resumeException": ___resumeException, "__ZSt18uncaught_exceptionv": __ZSt18uncaught_exceptionv, "_sysconf": _sysconf, "_clock": _clock, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_puts": _puts, "_mkport": _mkport, "_floorf": _floorf, "_sqrtf": _sqrtf, "_write": _write, "_emscripten_set_main_loop": _emscripten_set_main_loop, "___errno_location": ___errno_location, "__ZNSt9exceptionD2Ev": __ZNSt9exceptionD2Ev, "_printf": _printf, "___cxa_does_inherit": ___cxa_does_inherit, "__exit": __exit, "_fputc": _fputc, "_abort": _abort, "_fwrite": _fwrite, "_time": _time, "_fprintf": _fprintf, "_emscripten_cancel_main_loop": _emscripten_cancel_main_loop, "__formatString": __formatString, "_fputs": _fputs, "_exit": _exit, "___cxa_pure_virtual": ___cxa_pure_virtual, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity, "__ZTISt9exception": __ZTISt9exception }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _free = Module["_free"] = asm["_free"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var _malloc = Module["_malloc"] = asm["_malloc"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+var dynCall_iiii = Module["dynCall_iiii"] = asm["dynCall_iiii"];
+var dynCall_viiiii = Module["dynCall_viiiii"] = asm["dynCall_viiiii"];
+var dynCall_vi = Module["dynCall_vi"] = asm["dynCall_vi"];
+var dynCall_vii = Module["dynCall_vii"] = asm["dynCall_vii"];
+var dynCall_ii = Module["dynCall_ii"] = asm["dynCall_ii"];
+var dynCall_viii = Module["dynCall_viii"] = asm["dynCall_viii"];
+var dynCall_v = Module["dynCall_v"] = asm["dynCall_v"];
+var dynCall_viid = Module["dynCall_viid"] = asm["dynCall_viid"];
+var dynCall_viiiiii = Module["dynCall_viiiiii"] = asm["dynCall_viiiiii"];
+var dynCall_iii = Module["dynCall_iii"] = asm["dynCall_iii"];
+var dynCall_iiiiii = Module["dynCall_iiiiii"] = asm["dynCall_iiiiii"];
+var dynCall_viiii = Module["dynCall_viiii"] = asm["dynCall_viiii"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/copy.js b/test/mjsunit/asm/embenchen/copy.js
new file mode 100644
index 0000000..bf8d177
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/copy.js
@@ -0,0 +1,5976 @@
+var EXPECTED_OUTPUT = 'sum:8930\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(27);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([101,114,114,111,114,58,32,37,100,92,110,0,0,0,0,0,115,117,109,58,37,100,10,0], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+  function _malloc(bytes) {
+      /* Over-allocate to make sure it is byte-aligned by 8.
+       * This will leak memory, but this is only the dummy
+       * implementation (replaced by dlmalloc normally) so
+       * not an issue.
+       */
+      var ptr = Runtime.dynamicAlloc(bytes + 8);
+      return (ptr+8) & 0xFFFFFFF8;
+    }
+  Module["_malloc"] = _malloc;
+
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+    Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+    Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+    // just add the mouse delta to the current absolut mouse position
+    // FIXME: ideally this should be clamped against the canvas size and zero
+    Browser.mouseX += Browser.mouseMovementX;
+    Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+
+
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+
+  Module["_memset"] = _memset;
+
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+
+  function _free() {
+  }
+  Module["_free"] = _free;
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var _free=env._free;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _printf=env._printf;
+  var _send=env._send;
+  var _pwrite=env._pwrite;
+  var __reallyNegative=env.__reallyNegative;
+  var _fwrite=env._fwrite;
+  var _malloc=env._malloc;
+  var _mkport=env._mkport;
+  var _fprintf=env._fprintf;
+  var ___setErrNo=env.___setErrNo;
+  var __formatString=env.__formatString;
+  var _fileno=env._fileno;
+  var _fflush=env._fflush;
+  var _write=env._write;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _main(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ L1 : do {
+  if ((i3 | 0) > 1) {
+   i3 = HEAP8[HEAP32[i5 + 4 >> 2] | 0] | 0;
+   switch (i3 | 0) {
+   case 50:
+    {
+     i3 = 625;
+     break L1;
+    }
+   case 51:
+    {
+     i4 = 4;
+     break L1;
+    }
+   case 52:
+    {
+     i3 = 6250;
+     break L1;
+    }
+   case 53:
+    {
+     i3 = 12500;
+     break L1;
+    }
+   case 49:
+    {
+     i3 = 75;
+     break L1;
+    }
+   case 48:
+    {
+     i12 = 0;
+     STACKTOP = i1;
+     return i12 | 0;
+    }
+   default:
+    {
+     HEAP32[i2 >> 2] = i3 + -48;
+     _printf(8, i2 | 0) | 0;
+     i12 = -1;
+     STACKTOP = i1;
+     return i12 | 0;
+    }
+   }
+  } else {
+   i4 = 4;
+  }
+ } while (0);
+ if ((i4 | 0) == 4) {
+  i3 = 1250;
+ }
+ i4 = 0;
+ i12 = 0;
+ do {
+  i9 = (i4 | 0) % 10 | 0;
+  i5 = i9 + i4 | 0;
+  i6 = (i4 | 0) % 255 | 0;
+  i8 = (i4 | 0) % 15 | 0;
+  i10 = ((i4 | 0) % 120 | 0 | 0) % 1024 | 0;
+  i11 = ((i4 | 0) % 1024 | 0) + i4 | 0;
+  i5 = ((i5 | 0) % 1024 | 0) + i5 | 0;
+  i8 = ((i8 | 0) % 1024 | 0) + i8 | 0;
+  i6 = (((i6 | 0) % 1024 | 0) + i6 + i10 | 0) % 1024 | 0;
+  i7 = 0;
+  do {
+   i17 = i7 << 1;
+   i14 = (i7 | 0) % 120 | 0;
+   i18 = (i17 | 0) % 1024 | 0;
+   i19 = (i9 + i7 | 0) % 1024 | 0;
+   i16 = ((i7 | 0) % 255 | 0 | 0) % 1024 | 0;
+   i15 = (i7 | 0) % 1024 | 0;
+   i13 = ((i7 | 0) % 15 | 0 | 0) % 1024 | 0;
+   i12 = (((i19 + i18 + i16 + i10 + i15 + i13 + ((i11 + i19 | 0) % 1024 | 0) + ((i5 + i18 | 0) % 1024 | 0) + ((i18 + i17 + i16 | 0) % 1024 | 0) + i6 + ((i8 + i15 | 0) % 1024 | 0) + ((((i14 | 0) % 1024 | 0) + i14 + i13 | 0) % 1024 | 0) | 0) % 100 | 0) + i12 | 0) % 10240 | 0;
+   i7 = i7 + 1 | 0;
+  } while ((i7 | 0) != 5e4);
+  i4 = i4 + 1 | 0;
+ } while ((i4 | 0) < (i3 | 0));
+ HEAP32[i2 >> 2] = i12;
+ _printf(24, i2 | 0) | 0;
+ i19 = 0;
+ STACKTOP = i1;
+ return i19 | 0;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function runPostSets() {}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+
+// EMSCRIPTEN_END_FUNCS
+
+
+  return { _strlen: _strlen, _memcpy: _memcpy, _main: _main, _memset: _memset, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9 };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "_free": _free, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_printf": _printf, "_send": _send, "_pwrite": _pwrite, "__reallyNegative": __reallyNegative, "_fwrite": _fwrite, "_malloc": _malloc, "_mkport": _mkport, "_fprintf": _fprintf, "___setErrNo": ___setErrNo, "__formatString": __formatString, "_fileno": _fileno, "_fflush": _fflush, "_write": _write, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/corrections.js b/test/mjsunit/asm/embenchen/corrections.js
new file mode 100644
index 0000000..05cdc4c
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/corrections.js
@@ -0,0 +1,5983 @@
+var EXPECTED_OUTPUT = 'final: 40006013:58243.\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(35);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([101,114,114,111,114,58,32,37,100,92,110,0,0,0,0,0,102,105,110,97,108,58,32,37,100,58,37,100,46,10,0,0], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+  function _malloc(bytes) {
+      /* Over-allocate to make sure it is byte-aligned by 8.
+       * This will leak memory, but this is only the dummy
+       * implementation (replaced by dlmalloc normally) so
+       * not an issue.
+       */
+      var ptr = Runtime.dynamicAlloc(bytes + 8);
+      return (ptr+8) & 0xFFFFFFF8;
+    }
+  Module["_malloc"] = _malloc;
+
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+            Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+            Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+            // just add the mouse delta to the current absolut mouse position
+            // FIXME: ideally this should be clamped against the canvas size and zero
+            Browser.mouseX += Browser.mouseMovementX;
+            Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+
+
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+
+  Module["_memset"] = _memset;
+
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+
+  function _free() {
+  }
+  Module["_free"] = _free;
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var _free=env._free;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _printf=env._printf;
+  var _send=env._send;
+  var _pwrite=env._pwrite;
+  var __reallyNegative=env.__reallyNegative;
+  var _fwrite=env._fwrite;
+  var _malloc=env._malloc;
+  var _mkport=env._mkport;
+  var _fprintf=env._fprintf;
+  var ___setErrNo=env.___setErrNo;
+  var __formatString=env.__formatString;
+  var _fileno=env._fileno;
+  var _fflush=env._fflush;
+  var _write=env._write;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _main(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ L1 : do {
+  if ((i3 | 0) > 1) {
+   i3 = HEAP8[HEAP32[i5 + 4 >> 2] | 0] | 0;
+   switch (i3 | 0) {
+   case 50:
+    {
+     i3 = 3500;
+     break L1;
+    }
+   case 51:
+    {
+     i4 = 4;
+     break L1;
+    }
+   case 52:
+    {
+     i3 = 35e3;
+     break L1;
+    }
+   case 53:
+    {
+     i3 = 7e4;
+     break L1;
+    }
+   case 49:
+    {
+     i3 = 550;
+     break L1;
+    }
+   case 48:
+    {
+     i11 = 0;
+     STACKTOP = i1;
+     return i11 | 0;
+    }
+   default:
+    {
+     HEAP32[i2 >> 2] = i3 + -48;
+     _printf(8, i2 | 0) | 0;
+     i11 = -1;
+     STACKTOP = i1;
+     return i11 | 0;
+    }
+   }
+  } else {
+   i4 = 4;
+  }
+ } while (0);
+ if ((i4 | 0) == 4) {
+  i3 = 7e3;
+ }
+ i11 = 0;
+ i8 = 0;
+ i5 = 0;
+ while (1) {
+  i6 = ((i5 | 0) % 5 | 0) + 1 | 0;
+  i4 = ((i5 | 0) % 3 | 0) + 1 | 0;
+  i7 = 0;
+  while (1) {
+   i11 = ((i7 | 0) / (i6 | 0) | 0) + i11 | 0;
+   if (i11 >>> 0 > 1e3) {
+    i11 = (i11 >>> 0) / (i4 >>> 0) | 0;
+   }
+   if ((i7 & 3 | 0) == 0) {
+    i11 = i11 + (Math_imul((i7 & 7 | 0) == 0 ? 1 : -1, i7) | 0) | 0;
+   }
+   i10 = i11 << 16 >> 16;
+   i10 = (Math_imul(i10, i10) | 0) & 255;
+   i9 = i10 + (i8 & 65535) | 0;
+   i7 = i7 + 1 | 0;
+   if ((i7 | 0) == 2e4) {
+    break;
+   } else {
+    i8 = i9;
+   }
+  }
+  i5 = i5 + 1 | 0;
+  if ((i5 | 0) < (i3 | 0)) {
+   i8 = i9;
+  } else {
+   break;
+  }
+ }
+ HEAP32[i2 >> 2] = i11;
+ HEAP32[i2 + 4 >> 2] = i8 + i10 & 65535;
+ _printf(24, i2 | 0) | 0;
+ i11 = 0;
+ STACKTOP = i1;
+ return i11 | 0;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function runPostSets() {}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+
+// EMSCRIPTEN_END_FUNCS
+
+
+  return { _strlen: _strlen, _memcpy: _memcpy, _main: _main, _memset: _memset, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9 };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "_free": _free, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_printf": _printf, "_send": _send, "_pwrite": _pwrite, "__reallyNegative": __reallyNegative, "_fwrite": _fwrite, "_malloc": _malloc, "_mkport": _mkport, "_fprintf": _fprintf, "___setErrNo": ___setErrNo, "__formatString": __formatString, "_fileno": _fileno, "_fflush": _fflush, "_write": _write, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/fannkuch.js b/test/mjsunit/asm/embenchen/fannkuch.js
new file mode 100644
index 0000000..64bd491
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/fannkuch.js
@@ -0,0 +1,8435 @@
+var EXPECTED_OUTPUT =
+  '123456789\n' +
+  '213456789\n' +
+  '231456789\n' +
+  '321456789\n' +
+  '312456789\n' +
+  '132456789\n' +
+  '234156789\n' +
+  '324156789\n' +
+  '342156789\n' +
+  '432156789\n' +
+  '423156789\n' +
+  '243156789\n' +
+  '341256789\n' +
+  '431256789\n' +
+  '413256789\n' +
+  '143256789\n' +
+  '134256789\n' +
+  '314256789\n' +
+  '412356789\n' +
+  '142356789\n' +
+  '124356789\n' +
+  '214356789\n' +
+  '241356789\n' +
+  '421356789\n' +
+  '234516789\n' +
+  '324516789\n' +
+  '342516789\n' +
+  '432516789\n' +
+  '423516789\n' +
+  '243516789\n' +
+  'Pfannkuchen(9) = 30.\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(547);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([101,114,114,111,114,58,32,37,100,10,0,0,0,0,0,0,80,102,97,110,110,107,117,99,104,101,110,40,37,100,41,32,61,32,37,100,46,10,0,0,37,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+
+  function _fputc(c, stream) {
+      // int fputc(int c, FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html
+      var chr = unSign(c & 0xFF);
+      HEAP8[((_fputc.ret)|0)]=chr;
+      var fd = _fileno(stream);
+      var ret = _write(fd, _fputc.ret, 1);
+      if (ret == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return -1;
+      } else {
+        return chr;
+      }
+    }function _putchar(c) {
+      // int putchar(int c);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/putchar.html
+      return _fputc(c, HEAP32[((_stdout)>>2)]);
+    }
+
+  function _sbrk(bytes) {
+      // Implement a Linux-like 'memory area' for our 'process'.
+      // Changes the size of the memory area by |bytes|; returns the
+      // address of the previous top ('break') of the memory area
+      // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
+      var self = _sbrk;
+      if (!self.called) {
+        DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
+        self.called = true;
+        assert(Runtime.dynamicAlloc);
+        self.alloc = Runtime.dynamicAlloc;
+        Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
+      }
+      var ret = DYNAMICTOP;
+      if (bytes != 0) self.alloc(bytes);
+      return ret;  // Previous break location.
+    }
+
+  function _sysconf(name) {
+      // long sysconf(int name);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
+      switch(name) {
+        case 30: return PAGE_SIZE;
+        case 132:
+        case 133:
+        case 12:
+        case 137:
+        case 138:
+        case 15:
+        case 235:
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 149:
+        case 13:
+        case 10:
+        case 236:
+        case 153:
+        case 9:
+        case 21:
+        case 22:
+        case 159:
+        case 154:
+        case 14:
+        case 77:
+        case 78:
+        case 139:
+        case 80:
+        case 81:
+        case 79:
+        case 82:
+        case 68:
+        case 67:
+        case 164:
+        case 11:
+        case 29:
+        case 47:
+        case 48:
+        case 95:
+        case 52:
+        case 51:
+        case 46:
+          return 200809;
+        case 27:
+        case 246:
+        case 127:
+        case 128:
+        case 23:
+        case 24:
+        case 160:
+        case 161:
+        case 181:
+        case 182:
+        case 242:
+        case 183:
+        case 184:
+        case 243:
+        case 244:
+        case 245:
+        case 165:
+        case 178:
+        case 179:
+        case 49:
+        case 50:
+        case 168:
+        case 169:
+        case 175:
+        case 170:
+        case 171:
+        case 172:
+        case 97:
+        case 76:
+        case 32:
+        case 173:
+        case 35:
+          return -1;
+        case 176:
+        case 177:
+        case 7:
+        case 155:
+        case 8:
+        case 157:
+        case 125:
+        case 126:
+        case 92:
+        case 93:
+        case 129:
+        case 130:
+        case 131:
+        case 94:
+        case 91:
+          return 1;
+        case 74:
+        case 60:
+        case 69:
+        case 70:
+        case 4:
+          return 1024;
+        case 31:
+        case 42:
+        case 72:
+          return 32;
+        case 87:
+        case 26:
+        case 33:
+          return 2147483647;
+        case 34:
+        case 1:
+          return 47839;
+        case 38:
+        case 36:
+          return 99;
+        case 43:
+        case 37:
+          return 2048;
+        case 0: return 2097152;
+        case 3: return 65536;
+        case 28: return 32768;
+        case 44: return 32767;
+        case 75: return 16384;
+        case 39: return 1000;
+        case 89: return 700;
+        case 71: return 256;
+        case 40: return 255;
+        case 2: return 100;
+        case 180: return 64;
+        case 25: return 20;
+        case 5: return 16;
+        case 6: return 6;
+        case 73: return 4;
+        case 84: return 1;
+      }
+      ___setErrNo(ERRNO_CODES.EINVAL);
+      return -1;
+    }
+
+
+  Module["_memset"] = _memset;
+
+  function ___errno_location() {
+      return ___errno_state;
+    }
+
+  function _abort() {
+      Module['abort']();
+    }
+
+  var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+            Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+            Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+            // just add the mouse delta to the current absolut mouse position
+            // FIXME: ideally this should be clamped against the canvas size and zero
+            Browser.mouseX += Browser.mouseMovementX;
+            Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+  function _time(ptr) {
+      var ret = Math.floor(Date.now()/1000);
+      if (ptr) {
+        HEAP32[((ptr)>>2)]=ret;
+      }
+      return ret;
+    }
+
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+_fputc.ret = allocate([0], "i8", ALLOC_STATIC);
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var _fflush=env._fflush;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _putchar=env._putchar;
+  var _fputc=env._fputc;
+  var _send=env._send;
+  var _pwrite=env._pwrite;
+  var _abort=env._abort;
+  var __reallyNegative=env.__reallyNegative;
+  var _fwrite=env._fwrite;
+  var _sbrk=env._sbrk;
+  var _mkport=env._mkport;
+  var _fprintf=env._fprintf;
+  var ___setErrNo=env.___setErrNo;
+  var __formatString=env.__formatString;
+  var _fileno=env._fileno;
+  var _printf=env._printf;
+  var _time=env._time;
+  var _sysconf=env._sysconf;
+  var _write=env._write;
+  var ___errno_location=env.___errno_location;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _malloc(i12) {
+ i12 = i12 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0;
+ i1 = STACKTOP;
+ do {
+  if (i12 >>> 0 < 245) {
+   if (i12 >>> 0 < 11) {
+    i12 = 16;
+   } else {
+    i12 = i12 + 11 & -8;
+   }
+   i20 = i12 >>> 3;
+   i18 = HEAP32[14] | 0;
+   i21 = i18 >>> i20;
+   if ((i21 & 3 | 0) != 0) {
+    i6 = (i21 & 1 ^ 1) + i20 | 0;
+    i5 = i6 << 1;
+    i3 = 96 + (i5 << 2) | 0;
+    i5 = 96 + (i5 + 2 << 2) | 0;
+    i7 = HEAP32[i5 >> 2] | 0;
+    i2 = i7 + 8 | 0;
+    i4 = HEAP32[i2 >> 2] | 0;
+    do {
+     if ((i3 | 0) != (i4 | 0)) {
+      if (i4 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i8 = i4 + 12 | 0;
+      if ((HEAP32[i8 >> 2] | 0) == (i7 | 0)) {
+       HEAP32[i8 >> 2] = i3;
+       HEAP32[i5 >> 2] = i4;
+       break;
+      } else {
+       _abort();
+      }
+     } else {
+      HEAP32[14] = i18 & ~(1 << i6);
+     }
+    } while (0);
+    i32 = i6 << 3;
+    HEAP32[i7 + 4 >> 2] = i32 | 3;
+    i32 = i7 + (i32 | 4) | 0;
+    HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+    i32 = i2;
+    STACKTOP = i1;
+    return i32 | 0;
+   }
+   if (i12 >>> 0 > (HEAP32[64 >> 2] | 0) >>> 0) {
+    if ((i21 | 0) != 0) {
+     i7 = 2 << i20;
+     i7 = i21 << i20 & (i7 | 0 - i7);
+     i7 = (i7 & 0 - i7) + -1 | 0;
+     i2 = i7 >>> 12 & 16;
+     i7 = i7 >>> i2;
+     i6 = i7 >>> 5 & 8;
+     i7 = i7 >>> i6;
+     i5 = i7 >>> 2 & 4;
+     i7 = i7 >>> i5;
+     i4 = i7 >>> 1 & 2;
+     i7 = i7 >>> i4;
+     i3 = i7 >>> 1 & 1;
+     i3 = (i6 | i2 | i5 | i4 | i3) + (i7 >>> i3) | 0;
+     i7 = i3 << 1;
+     i4 = 96 + (i7 << 2) | 0;
+     i7 = 96 + (i7 + 2 << 2) | 0;
+     i5 = HEAP32[i7 >> 2] | 0;
+     i2 = i5 + 8 | 0;
+     i6 = HEAP32[i2 >> 2] | 0;
+     do {
+      if ((i4 | 0) != (i6 | 0)) {
+       if (i6 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       i8 = i6 + 12 | 0;
+       if ((HEAP32[i8 >> 2] | 0) == (i5 | 0)) {
+        HEAP32[i8 >> 2] = i4;
+        HEAP32[i7 >> 2] = i6;
+        break;
+       } else {
+        _abort();
+       }
+      } else {
+       HEAP32[14] = i18 & ~(1 << i3);
+      }
+     } while (0);
+     i6 = i3 << 3;
+     i4 = i6 - i12 | 0;
+     HEAP32[i5 + 4 >> 2] = i12 | 3;
+     i3 = i5 + i12 | 0;
+     HEAP32[i5 + (i12 | 4) >> 2] = i4 | 1;
+     HEAP32[i5 + i6 >> 2] = i4;
+     i6 = HEAP32[64 >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      i5 = HEAP32[76 >> 2] | 0;
+      i8 = i6 >>> 3;
+      i9 = i8 << 1;
+      i6 = 96 + (i9 << 2) | 0;
+      i7 = HEAP32[14] | 0;
+      i8 = 1 << i8;
+      if ((i7 & i8 | 0) != 0) {
+       i7 = 96 + (i9 + 2 << 2) | 0;
+       i8 = HEAP32[i7 >> 2] | 0;
+       if (i8 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i28 = i7;
+        i27 = i8;
+       }
+      } else {
+       HEAP32[14] = i7 | i8;
+       i28 = 96 + (i9 + 2 << 2) | 0;
+       i27 = i6;
+      }
+      HEAP32[i28 >> 2] = i5;
+      HEAP32[i27 + 12 >> 2] = i5;
+      HEAP32[i5 + 8 >> 2] = i27;
+      HEAP32[i5 + 12 >> 2] = i6;
+     }
+     HEAP32[64 >> 2] = i4;
+     HEAP32[76 >> 2] = i3;
+     i32 = i2;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i18 = HEAP32[60 >> 2] | 0;
+    if ((i18 | 0) != 0) {
+     i2 = (i18 & 0 - i18) + -1 | 0;
+     i31 = i2 >>> 12 & 16;
+     i2 = i2 >>> i31;
+     i30 = i2 >>> 5 & 8;
+     i2 = i2 >>> i30;
+     i32 = i2 >>> 2 & 4;
+     i2 = i2 >>> i32;
+     i6 = i2 >>> 1 & 2;
+     i2 = i2 >>> i6;
+     i3 = i2 >>> 1 & 1;
+     i3 = HEAP32[360 + ((i30 | i31 | i32 | i6 | i3) + (i2 >>> i3) << 2) >> 2] | 0;
+     i2 = (HEAP32[i3 + 4 >> 2] & -8) - i12 | 0;
+     i6 = i3;
+     while (1) {
+      i5 = HEAP32[i6 + 16 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       i5 = HEAP32[i6 + 20 >> 2] | 0;
+       if ((i5 | 0) == 0) {
+        break;
+       }
+      }
+      i6 = (HEAP32[i5 + 4 >> 2] & -8) - i12 | 0;
+      i4 = i6 >>> 0 < i2 >>> 0;
+      i2 = i4 ? i6 : i2;
+      i6 = i5;
+      i3 = i4 ? i5 : i3;
+     }
+     i6 = HEAP32[72 >> 2] | 0;
+     if (i3 >>> 0 < i6 >>> 0) {
+      _abort();
+     }
+     i4 = i3 + i12 | 0;
+     if (!(i3 >>> 0 < i4 >>> 0)) {
+      _abort();
+     }
+     i5 = HEAP32[i3 + 24 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     do {
+      if ((i7 | 0) == (i3 | 0)) {
+       i8 = i3 + 20 | 0;
+       i7 = HEAP32[i8 >> 2] | 0;
+       if ((i7 | 0) == 0) {
+        i8 = i3 + 16 | 0;
+        i7 = HEAP32[i8 >> 2] | 0;
+        if ((i7 | 0) == 0) {
+         i26 = 0;
+         break;
+        }
+       }
+       while (1) {
+        i10 = i7 + 20 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) != 0) {
+         i7 = i9;
+         i8 = i10;
+         continue;
+        }
+        i10 = i7 + 16 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) == 0) {
+         break;
+        } else {
+         i7 = i9;
+         i8 = i10;
+        }
+       }
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i8 >> 2] = 0;
+        i26 = i7;
+        break;
+       }
+      } else {
+       i8 = HEAP32[i3 + 8 >> 2] | 0;
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       }
+       i6 = i8 + 12 | 0;
+       if ((HEAP32[i6 >> 2] | 0) != (i3 | 0)) {
+        _abort();
+       }
+       i9 = i7 + 8 | 0;
+       if ((HEAP32[i9 >> 2] | 0) == (i3 | 0)) {
+        HEAP32[i6 >> 2] = i7;
+        HEAP32[i9 >> 2] = i8;
+        i26 = i7;
+        break;
+       } else {
+        _abort();
+       }
+      }
+     } while (0);
+     do {
+      if ((i5 | 0) != 0) {
+       i7 = HEAP32[i3 + 28 >> 2] | 0;
+       i6 = 360 + (i7 << 2) | 0;
+       if ((i3 | 0) == (HEAP32[i6 >> 2] | 0)) {
+        HEAP32[i6 >> 2] = i26;
+        if ((i26 | 0) == 0) {
+         HEAP32[60 >> 2] = HEAP32[60 >> 2] & ~(1 << i7);
+         break;
+        }
+       } else {
+        if (i5 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        i6 = i5 + 16 | 0;
+        if ((HEAP32[i6 >> 2] | 0) == (i3 | 0)) {
+         HEAP32[i6 >> 2] = i26;
+        } else {
+         HEAP32[i5 + 20 >> 2] = i26;
+        }
+        if ((i26 | 0) == 0) {
+         break;
+        }
+       }
+       if (i26 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       HEAP32[i26 + 24 >> 2] = i5;
+       i5 = HEAP32[i3 + 16 >> 2] | 0;
+       do {
+        if ((i5 | 0) != 0) {
+         if (i5 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i26 + 16 >> 2] = i5;
+          HEAP32[i5 + 24 >> 2] = i26;
+          break;
+         }
+        }
+       } while (0);
+       i5 = HEAP32[i3 + 20 >> 2] | 0;
+       if ((i5 | 0) != 0) {
+        if (i5 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i26 + 20 >> 2] = i5;
+         HEAP32[i5 + 24 >> 2] = i26;
+         break;
+        }
+       }
+      }
+     } while (0);
+     if (i2 >>> 0 < 16) {
+      i32 = i2 + i12 | 0;
+      HEAP32[i3 + 4 >> 2] = i32 | 3;
+      i32 = i3 + (i32 + 4) | 0;
+      HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+     } else {
+      HEAP32[i3 + 4 >> 2] = i12 | 3;
+      HEAP32[i3 + (i12 | 4) >> 2] = i2 | 1;
+      HEAP32[i3 + (i2 + i12) >> 2] = i2;
+      i6 = HEAP32[64 >> 2] | 0;
+      if ((i6 | 0) != 0) {
+       i5 = HEAP32[76 >> 2] | 0;
+       i8 = i6 >>> 3;
+       i9 = i8 << 1;
+       i6 = 96 + (i9 << 2) | 0;
+       i7 = HEAP32[14] | 0;
+       i8 = 1 << i8;
+       if ((i7 & i8 | 0) != 0) {
+        i7 = 96 + (i9 + 2 << 2) | 0;
+        i8 = HEAP32[i7 >> 2] | 0;
+        if (i8 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         i25 = i7;
+         i24 = i8;
+        }
+       } else {
+        HEAP32[14] = i7 | i8;
+        i25 = 96 + (i9 + 2 << 2) | 0;
+        i24 = i6;
+       }
+       HEAP32[i25 >> 2] = i5;
+       HEAP32[i24 + 12 >> 2] = i5;
+       HEAP32[i5 + 8 >> 2] = i24;
+       HEAP32[i5 + 12 >> 2] = i6;
+      }
+      HEAP32[64 >> 2] = i2;
+      HEAP32[76 >> 2] = i4;
+     }
+     i32 = i3 + 8 | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+   }
+  } else {
+   if (!(i12 >>> 0 > 4294967231)) {
+    i24 = i12 + 11 | 0;
+    i12 = i24 & -8;
+    i26 = HEAP32[60 >> 2] | 0;
+    if ((i26 | 0) != 0) {
+     i25 = 0 - i12 | 0;
+     i24 = i24 >>> 8;
+     if ((i24 | 0) != 0) {
+      if (i12 >>> 0 > 16777215) {
+       i27 = 31;
+      } else {
+       i31 = (i24 + 1048320 | 0) >>> 16 & 8;
+       i32 = i24 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i27 = (i32 + 245760 | 0) >>> 16 & 2;
+       i27 = 14 - (i30 | i31 | i27) + (i32 << i27 >>> 15) | 0;
+       i27 = i12 >>> (i27 + 7 | 0) & 1 | i27 << 1;
+      }
+     } else {
+      i27 = 0;
+     }
+     i30 = HEAP32[360 + (i27 << 2) >> 2] | 0;
+     L126 : do {
+      if ((i30 | 0) == 0) {
+       i29 = 0;
+       i24 = 0;
+      } else {
+       if ((i27 | 0) == 31) {
+        i24 = 0;
+       } else {
+        i24 = 25 - (i27 >>> 1) | 0;
+       }
+       i29 = 0;
+       i28 = i12 << i24;
+       i24 = 0;
+       while (1) {
+        i32 = HEAP32[i30 + 4 >> 2] & -8;
+        i31 = i32 - i12 | 0;
+        if (i31 >>> 0 < i25 >>> 0) {
+         if ((i32 | 0) == (i12 | 0)) {
+          i25 = i31;
+          i29 = i30;
+          i24 = i30;
+          break L126;
+         } else {
+          i25 = i31;
+          i24 = i30;
+         }
+        }
+        i31 = HEAP32[i30 + 20 >> 2] | 0;
+        i30 = HEAP32[i30 + (i28 >>> 31 << 2) + 16 >> 2] | 0;
+        i29 = (i31 | 0) == 0 | (i31 | 0) == (i30 | 0) ? i29 : i31;
+        if ((i30 | 0) == 0) {
+         break;
+        } else {
+         i28 = i28 << 1;
+        }
+       }
+      }
+     } while (0);
+     if ((i29 | 0) == 0 & (i24 | 0) == 0) {
+      i32 = 2 << i27;
+      i26 = i26 & (i32 | 0 - i32);
+      if ((i26 | 0) == 0) {
+       break;
+      }
+      i32 = (i26 & 0 - i26) + -1 | 0;
+      i28 = i32 >>> 12 & 16;
+      i32 = i32 >>> i28;
+      i27 = i32 >>> 5 & 8;
+      i32 = i32 >>> i27;
+      i30 = i32 >>> 2 & 4;
+      i32 = i32 >>> i30;
+      i31 = i32 >>> 1 & 2;
+      i32 = i32 >>> i31;
+      i29 = i32 >>> 1 & 1;
+      i29 = HEAP32[360 + ((i27 | i28 | i30 | i31 | i29) + (i32 >>> i29) << 2) >> 2] | 0;
+     }
+     if ((i29 | 0) != 0) {
+      while (1) {
+       i27 = (HEAP32[i29 + 4 >> 2] & -8) - i12 | 0;
+       i26 = i27 >>> 0 < i25 >>> 0;
+       i25 = i26 ? i27 : i25;
+       i24 = i26 ? i29 : i24;
+       i26 = HEAP32[i29 + 16 >> 2] | 0;
+       if ((i26 | 0) != 0) {
+        i29 = i26;
+        continue;
+       }
+       i29 = HEAP32[i29 + 20 >> 2] | 0;
+       if ((i29 | 0) == 0) {
+        break;
+       }
+      }
+     }
+     if ((i24 | 0) != 0 ? i25 >>> 0 < ((HEAP32[64 >> 2] | 0) - i12 | 0) >>> 0 : 0) {
+      i4 = HEAP32[72 >> 2] | 0;
+      if (i24 >>> 0 < i4 >>> 0) {
+       _abort();
+      }
+      i2 = i24 + i12 | 0;
+      if (!(i24 >>> 0 < i2 >>> 0)) {
+       _abort();
+      }
+      i3 = HEAP32[i24 + 24 >> 2] | 0;
+      i6 = HEAP32[i24 + 12 >> 2] | 0;
+      do {
+       if ((i6 | 0) == (i24 | 0)) {
+        i6 = i24 + 20 | 0;
+        i5 = HEAP32[i6 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         i6 = i24 + 16 | 0;
+         i5 = HEAP32[i6 >> 2] | 0;
+         if ((i5 | 0) == 0) {
+          i22 = 0;
+          break;
+         }
+        }
+        while (1) {
+         i8 = i5 + 20 | 0;
+         i7 = HEAP32[i8 >> 2] | 0;
+         if ((i7 | 0) != 0) {
+          i5 = i7;
+          i6 = i8;
+          continue;
+         }
+         i7 = i5 + 16 | 0;
+         i8 = HEAP32[i7 >> 2] | 0;
+         if ((i8 | 0) == 0) {
+          break;
+         } else {
+          i5 = i8;
+          i6 = i7;
+         }
+        }
+        if (i6 >>> 0 < i4 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i6 >> 2] = 0;
+         i22 = i5;
+         break;
+        }
+       } else {
+        i5 = HEAP32[i24 + 8 >> 2] | 0;
+        if (i5 >>> 0 < i4 >>> 0) {
+         _abort();
+        }
+        i7 = i5 + 12 | 0;
+        if ((HEAP32[i7 >> 2] | 0) != (i24 | 0)) {
+         _abort();
+        }
+        i4 = i6 + 8 | 0;
+        if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+         HEAP32[i7 >> 2] = i6;
+         HEAP32[i4 >> 2] = i5;
+         i22 = i6;
+         break;
+        } else {
+         _abort();
+        }
+       }
+      } while (0);
+      do {
+       if ((i3 | 0) != 0) {
+        i4 = HEAP32[i24 + 28 >> 2] | 0;
+        i5 = 360 + (i4 << 2) | 0;
+        if ((i24 | 0) == (HEAP32[i5 >> 2] | 0)) {
+         HEAP32[i5 >> 2] = i22;
+         if ((i22 | 0) == 0) {
+          HEAP32[60 >> 2] = HEAP32[60 >> 2] & ~(1 << i4);
+          break;
+         }
+        } else {
+         if (i3 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+          _abort();
+         }
+         i4 = i3 + 16 | 0;
+         if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+          HEAP32[i4 >> 2] = i22;
+         } else {
+          HEAP32[i3 + 20 >> 2] = i22;
+         }
+         if ((i22 | 0) == 0) {
+          break;
+         }
+        }
+        if (i22 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        HEAP32[i22 + 24 >> 2] = i3;
+        i3 = HEAP32[i24 + 16 >> 2] | 0;
+        do {
+         if ((i3 | 0) != 0) {
+          if (i3 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i22 + 16 >> 2] = i3;
+           HEAP32[i3 + 24 >> 2] = i22;
+           break;
+          }
+         }
+        } while (0);
+        i3 = HEAP32[i24 + 20 >> 2] | 0;
+        if ((i3 | 0) != 0) {
+         if (i3 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i22 + 20 >> 2] = i3;
+          HEAP32[i3 + 24 >> 2] = i22;
+          break;
+         }
+        }
+       }
+      } while (0);
+      L204 : do {
+       if (!(i25 >>> 0 < 16)) {
+        HEAP32[i24 + 4 >> 2] = i12 | 3;
+        HEAP32[i24 + (i12 | 4) >> 2] = i25 | 1;
+        HEAP32[i24 + (i25 + i12) >> 2] = i25;
+        i4 = i25 >>> 3;
+        if (i25 >>> 0 < 256) {
+         i6 = i4 << 1;
+         i3 = 96 + (i6 << 2) | 0;
+         i5 = HEAP32[14] | 0;
+         i4 = 1 << i4;
+         if ((i5 & i4 | 0) != 0) {
+          i5 = 96 + (i6 + 2 << 2) | 0;
+          i4 = HEAP32[i5 >> 2] | 0;
+          if (i4 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           i21 = i5;
+           i20 = i4;
+          }
+         } else {
+          HEAP32[14] = i5 | i4;
+          i21 = 96 + (i6 + 2 << 2) | 0;
+          i20 = i3;
+         }
+         HEAP32[i21 >> 2] = i2;
+         HEAP32[i20 + 12 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i20;
+         HEAP32[i24 + (i12 + 12) >> 2] = i3;
+         break;
+        }
+        i3 = i25 >>> 8;
+        if ((i3 | 0) != 0) {
+         if (i25 >>> 0 > 16777215) {
+          i3 = 31;
+         } else {
+          i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+          i32 = i3 << i31;
+          i30 = (i32 + 520192 | 0) >>> 16 & 4;
+          i32 = i32 << i30;
+          i3 = (i32 + 245760 | 0) >>> 16 & 2;
+          i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+          i3 = i25 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+         }
+        } else {
+         i3 = 0;
+        }
+        i6 = 360 + (i3 << 2) | 0;
+        HEAP32[i24 + (i12 + 28) >> 2] = i3;
+        HEAP32[i24 + (i12 + 20) >> 2] = 0;
+        HEAP32[i24 + (i12 + 16) >> 2] = 0;
+        i4 = HEAP32[60 >> 2] | 0;
+        i5 = 1 << i3;
+        if ((i4 & i5 | 0) == 0) {
+         HEAP32[60 >> 2] = i4 | i5;
+         HEAP32[i6 >> 2] = i2;
+         HEAP32[i24 + (i12 + 24) >> 2] = i6;
+         HEAP32[i24 + (i12 + 12) >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i2;
+         break;
+        }
+        i4 = HEAP32[i6 >> 2] | 0;
+        if ((i3 | 0) == 31) {
+         i3 = 0;
+        } else {
+         i3 = 25 - (i3 >>> 1) | 0;
+        }
+        L225 : do {
+         if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i25 | 0)) {
+          i3 = i25 << i3;
+          while (1) {
+           i6 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+           i5 = HEAP32[i6 >> 2] | 0;
+           if ((i5 | 0) == 0) {
+            break;
+           }
+           if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i25 | 0)) {
+            i18 = i5;
+            break L225;
+           } else {
+            i3 = i3 << 1;
+            i4 = i5;
+           }
+          }
+          if (i6 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i6 >> 2] = i2;
+           HEAP32[i24 + (i12 + 24) >> 2] = i4;
+           HEAP32[i24 + (i12 + 12) >> 2] = i2;
+           HEAP32[i24 + (i12 + 8) >> 2] = i2;
+           break L204;
+          }
+         } else {
+          i18 = i4;
+         }
+        } while (0);
+        i4 = i18 + 8 | 0;
+        i3 = HEAP32[i4 >> 2] | 0;
+        i5 = HEAP32[72 >> 2] | 0;
+        if (i18 >>> 0 < i5 >>> 0) {
+         _abort();
+        }
+        if (i3 >>> 0 < i5 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i3 + 12 >> 2] = i2;
+         HEAP32[i4 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i3;
+         HEAP32[i24 + (i12 + 12) >> 2] = i18;
+         HEAP32[i24 + (i12 + 24) >> 2] = 0;
+         break;
+        }
+       } else {
+        i32 = i25 + i12 | 0;
+        HEAP32[i24 + 4 >> 2] = i32 | 3;
+        i32 = i24 + (i32 + 4) | 0;
+        HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+       }
+      } while (0);
+      i32 = i24 + 8 | 0;
+      STACKTOP = i1;
+      return i32 | 0;
+     }
+    }
+   } else {
+    i12 = -1;
+   }
+  }
+ } while (0);
+ i18 = HEAP32[64 >> 2] | 0;
+ if (!(i12 >>> 0 > i18 >>> 0)) {
+  i3 = i18 - i12 | 0;
+  i2 = HEAP32[76 >> 2] | 0;
+  if (i3 >>> 0 > 15) {
+   HEAP32[76 >> 2] = i2 + i12;
+   HEAP32[64 >> 2] = i3;
+   HEAP32[i2 + (i12 + 4) >> 2] = i3 | 1;
+   HEAP32[i2 + i18 >> 2] = i3;
+   HEAP32[i2 + 4 >> 2] = i12 | 3;
+  } else {
+   HEAP32[64 >> 2] = 0;
+   HEAP32[76 >> 2] = 0;
+   HEAP32[i2 + 4 >> 2] = i18 | 3;
+   i32 = i2 + (i18 + 4) | 0;
+   HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+  }
+  i32 = i2 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i18 = HEAP32[68 >> 2] | 0;
+ if (i12 >>> 0 < i18 >>> 0) {
+  i31 = i18 - i12 | 0;
+  HEAP32[68 >> 2] = i31;
+  i32 = HEAP32[80 >> 2] | 0;
+  HEAP32[80 >> 2] = i32 + i12;
+  HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+  HEAP32[i32 + 4 >> 2] = i12 | 3;
+  i32 = i32 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ do {
+  if ((HEAP32[132] | 0) == 0) {
+   i18 = _sysconf(30) | 0;
+   if ((i18 + -1 & i18 | 0) == 0) {
+    HEAP32[536 >> 2] = i18;
+    HEAP32[532 >> 2] = i18;
+    HEAP32[540 >> 2] = -1;
+    HEAP32[544 >> 2] = -1;
+    HEAP32[548 >> 2] = 0;
+    HEAP32[500 >> 2] = 0;
+    HEAP32[132] = (_time(0) | 0) & -16 ^ 1431655768;
+    break;
+   } else {
+    _abort();
+   }
+  }
+ } while (0);
+ i20 = i12 + 48 | 0;
+ i25 = HEAP32[536 >> 2] | 0;
+ i21 = i12 + 47 | 0;
+ i22 = i25 + i21 | 0;
+ i25 = 0 - i25 | 0;
+ i18 = i22 & i25;
+ if (!(i18 >>> 0 > i12 >>> 0)) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i24 = HEAP32[496 >> 2] | 0;
+ if ((i24 | 0) != 0 ? (i31 = HEAP32[488 >> 2] | 0, i32 = i31 + i18 | 0, i32 >>> 0 <= i31 >>> 0 | i32 >>> 0 > i24 >>> 0) : 0) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ L269 : do {
+  if ((HEAP32[500 >> 2] & 4 | 0) == 0) {
+   i26 = HEAP32[80 >> 2] | 0;
+   L271 : do {
+    if ((i26 | 0) != 0) {
+     i24 = 504 | 0;
+     while (1) {
+      i27 = HEAP32[i24 >> 2] | 0;
+      if (!(i27 >>> 0 > i26 >>> 0) ? (i23 = i24 + 4 | 0, (i27 + (HEAP32[i23 >> 2] | 0) | 0) >>> 0 > i26 >>> 0) : 0) {
+       break;
+      }
+      i24 = HEAP32[i24 + 8 >> 2] | 0;
+      if ((i24 | 0) == 0) {
+       i13 = 182;
+       break L271;
+      }
+     }
+     if ((i24 | 0) != 0) {
+      i25 = i22 - (HEAP32[68 >> 2] | 0) & i25;
+      if (i25 >>> 0 < 2147483647) {
+       i13 = _sbrk(i25 | 0) | 0;
+       i26 = (i13 | 0) == ((HEAP32[i24 >> 2] | 0) + (HEAP32[i23 >> 2] | 0) | 0);
+       i22 = i13;
+       i24 = i25;
+       i23 = i26 ? i13 : -1;
+       i25 = i26 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i13 = 182;
+     }
+    } else {
+     i13 = 182;
+    }
+   } while (0);
+   do {
+    if ((i13 | 0) == 182) {
+     i23 = _sbrk(0) | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i24 = i23;
+      i22 = HEAP32[532 >> 2] | 0;
+      i25 = i22 + -1 | 0;
+      if ((i25 & i24 | 0) == 0) {
+       i25 = i18;
+      } else {
+       i25 = i18 - i24 + (i25 + i24 & 0 - i22) | 0;
+      }
+      i24 = HEAP32[488 >> 2] | 0;
+      i26 = i24 + i25 | 0;
+      if (i25 >>> 0 > i12 >>> 0 & i25 >>> 0 < 2147483647) {
+       i22 = HEAP32[496 >> 2] | 0;
+       if ((i22 | 0) != 0 ? i26 >>> 0 <= i24 >>> 0 | i26 >>> 0 > i22 >>> 0 : 0) {
+        i25 = 0;
+        break;
+       }
+       i22 = _sbrk(i25 | 0) | 0;
+       i13 = (i22 | 0) == (i23 | 0);
+       i24 = i25;
+       i23 = i13 ? i23 : -1;
+       i25 = i13 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i25 = 0;
+     }
+    }
+   } while (0);
+   L291 : do {
+    if ((i13 | 0) == 191) {
+     i13 = 0 - i24 | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i17 = i23;
+      i14 = i25;
+      i13 = 202;
+      break L269;
+     }
+     do {
+      if ((i22 | 0) != (-1 | 0) & i24 >>> 0 < 2147483647 & i24 >>> 0 < i20 >>> 0 ? (i19 = HEAP32[536 >> 2] | 0, i19 = i21 - i24 + i19 & 0 - i19, i19 >>> 0 < 2147483647) : 0) {
+       if ((_sbrk(i19 | 0) | 0) == (-1 | 0)) {
+        _sbrk(i13 | 0) | 0;
+        break L291;
+       } else {
+        i24 = i19 + i24 | 0;
+        break;
+       }
+      }
+     } while (0);
+     if ((i22 | 0) != (-1 | 0)) {
+      i17 = i22;
+      i14 = i24;
+      i13 = 202;
+      break L269;
+     }
+    }
+   } while (0);
+   HEAP32[500 >> 2] = HEAP32[500 >> 2] | 4;
+   i13 = 199;
+  } else {
+   i25 = 0;
+   i13 = 199;
+  }
+ } while (0);
+ if ((((i13 | 0) == 199 ? i18 >>> 0 < 2147483647 : 0) ? (i17 = _sbrk(i18 | 0) | 0, i16 = _sbrk(0) | 0, (i16 | 0) != (-1 | 0) & (i17 | 0) != (-1 | 0) & i17 >>> 0 < i16 >>> 0) : 0) ? (i15 = i16 - i17 | 0, i14 = i15 >>> 0 > (i12 + 40 | 0) >>> 0, i14) : 0) {
+  i14 = i14 ? i15 : i25;
+  i13 = 202;
+ }
+ if ((i13 | 0) == 202) {
+  i15 = (HEAP32[488 >> 2] | 0) + i14 | 0;
+  HEAP32[488 >> 2] = i15;
+  if (i15 >>> 0 > (HEAP32[492 >> 2] | 0) >>> 0) {
+   HEAP32[492 >> 2] = i15;
+  }
+  i15 = HEAP32[80 >> 2] | 0;
+  L311 : do {
+   if ((i15 | 0) != 0) {
+    i21 = 504 | 0;
+    while (1) {
+     i16 = HEAP32[i21 >> 2] | 0;
+     i19 = i21 + 4 | 0;
+     i20 = HEAP32[i19 >> 2] | 0;
+     if ((i17 | 0) == (i16 + i20 | 0)) {
+      i13 = 214;
+      break;
+     }
+     i18 = HEAP32[i21 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i21 = i18;
+     }
+    }
+    if (((i13 | 0) == 214 ? (HEAP32[i21 + 12 >> 2] & 8 | 0) == 0 : 0) ? i15 >>> 0 >= i16 >>> 0 & i15 >>> 0 < i17 >>> 0 : 0) {
+     HEAP32[i19 >> 2] = i20 + i14;
+     i2 = (HEAP32[68 >> 2] | 0) + i14 | 0;
+     i3 = i15 + 8 | 0;
+     if ((i3 & 7 | 0) == 0) {
+      i3 = 0;
+     } else {
+      i3 = 0 - i3 & 7;
+     }
+     i32 = i2 - i3 | 0;
+     HEAP32[80 >> 2] = i15 + i3;
+     HEAP32[68 >> 2] = i32;
+     HEAP32[i15 + (i3 + 4) >> 2] = i32 | 1;
+     HEAP32[i15 + (i2 + 4) >> 2] = 40;
+     HEAP32[84 >> 2] = HEAP32[544 >> 2];
+     break;
+    }
+    if (i17 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+     HEAP32[72 >> 2] = i17;
+    }
+    i19 = i17 + i14 | 0;
+    i16 = 504 | 0;
+    while (1) {
+     if ((HEAP32[i16 >> 2] | 0) == (i19 | 0)) {
+      i13 = 224;
+      break;
+     }
+     i18 = HEAP32[i16 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i16 = i18;
+     }
+    }
+    if ((i13 | 0) == 224 ? (HEAP32[i16 + 12 >> 2] & 8 | 0) == 0 : 0) {
+     HEAP32[i16 >> 2] = i17;
+     i6 = i16 + 4 | 0;
+     HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i14;
+     i6 = i17 + 8 | 0;
+     if ((i6 & 7 | 0) == 0) {
+      i6 = 0;
+     } else {
+      i6 = 0 - i6 & 7;
+     }
+     i7 = i17 + (i14 + 8) | 0;
+     if ((i7 & 7 | 0) == 0) {
+      i13 = 0;
+     } else {
+      i13 = 0 - i7 & 7;
+     }
+     i15 = i17 + (i13 + i14) | 0;
+     i8 = i6 + i12 | 0;
+     i7 = i17 + i8 | 0;
+     i10 = i15 - (i17 + i6) - i12 | 0;
+     HEAP32[i17 + (i6 + 4) >> 2] = i12 | 3;
+     L348 : do {
+      if ((i15 | 0) != (HEAP32[80 >> 2] | 0)) {
+       if ((i15 | 0) == (HEAP32[76 >> 2] | 0)) {
+        i32 = (HEAP32[64 >> 2] | 0) + i10 | 0;
+        HEAP32[64 >> 2] = i32;
+        HEAP32[76 >> 2] = i7;
+        HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+        HEAP32[i17 + (i32 + i8) >> 2] = i32;
+        break;
+       }
+       i12 = i14 + 4 | 0;
+       i18 = HEAP32[i17 + (i12 + i13) >> 2] | 0;
+       if ((i18 & 3 | 0) == 1) {
+        i11 = i18 & -8;
+        i16 = i18 >>> 3;
+        do {
+         if (!(i18 >>> 0 < 256)) {
+          i9 = HEAP32[i17 + ((i13 | 24) + i14) >> 2] | 0;
+          i19 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          do {
+           if ((i19 | 0) == (i15 | 0)) {
+            i19 = i13 | 16;
+            i18 = i17 + (i12 + i19) | 0;
+            i16 = HEAP32[i18 >> 2] | 0;
+            if ((i16 | 0) == 0) {
+             i18 = i17 + (i19 + i14) | 0;
+             i16 = HEAP32[i18 >> 2] | 0;
+             if ((i16 | 0) == 0) {
+              i5 = 0;
+              break;
+             }
+            }
+            while (1) {
+             i20 = i16 + 20 | 0;
+             i19 = HEAP32[i20 >> 2] | 0;
+             if ((i19 | 0) != 0) {
+              i16 = i19;
+              i18 = i20;
+              continue;
+             }
+             i19 = i16 + 16 | 0;
+             i20 = HEAP32[i19 >> 2] | 0;
+             if ((i20 | 0) == 0) {
+              break;
+             } else {
+              i16 = i20;
+              i18 = i19;
+             }
+            }
+            if (i18 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i18 >> 2] = 0;
+             i5 = i16;
+             break;
+            }
+           } else {
+            i18 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+            if (i18 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i18 + 12 | 0;
+            if ((HEAP32[i16 >> 2] | 0) != (i15 | 0)) {
+             _abort();
+            }
+            i20 = i19 + 8 | 0;
+            if ((HEAP32[i20 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i19;
+             HEAP32[i20 >> 2] = i18;
+             i5 = i19;
+             break;
+            } else {
+             _abort();
+            }
+           }
+          } while (0);
+          if ((i9 | 0) != 0) {
+           i16 = HEAP32[i17 + (i14 + 28 + i13) >> 2] | 0;
+           i18 = 360 + (i16 << 2) | 0;
+           if ((i15 | 0) == (HEAP32[i18 >> 2] | 0)) {
+            HEAP32[i18 >> 2] = i5;
+            if ((i5 | 0) == 0) {
+             HEAP32[60 >> 2] = HEAP32[60 >> 2] & ~(1 << i16);
+             break;
+            }
+           } else {
+            if (i9 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i9 + 16 | 0;
+            if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i5;
+            } else {
+             HEAP32[i9 + 20 >> 2] = i5;
+            }
+            if ((i5 | 0) == 0) {
+             break;
+            }
+           }
+           if (i5 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           HEAP32[i5 + 24 >> 2] = i9;
+           i15 = i13 | 16;
+           i9 = HEAP32[i17 + (i15 + i14) >> 2] | 0;
+           do {
+            if ((i9 | 0) != 0) {
+             if (i9 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+              _abort();
+             } else {
+              HEAP32[i5 + 16 >> 2] = i9;
+              HEAP32[i9 + 24 >> 2] = i5;
+              break;
+             }
+            }
+           } while (0);
+           i9 = HEAP32[i17 + (i12 + i15) >> 2] | 0;
+           if ((i9 | 0) != 0) {
+            if (i9 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i5 + 20 >> 2] = i9;
+             HEAP32[i9 + 24 >> 2] = i5;
+             break;
+            }
+           }
+          }
+         } else {
+          i5 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+          i12 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          i18 = 96 + (i16 << 1 << 2) | 0;
+          if ((i5 | 0) != (i18 | 0)) {
+           if (i5 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           if ((HEAP32[i5 + 12 >> 2] | 0) != (i15 | 0)) {
+            _abort();
+           }
+          }
+          if ((i12 | 0) == (i5 | 0)) {
+           HEAP32[14] = HEAP32[14] & ~(1 << i16);
+           break;
+          }
+          if ((i12 | 0) != (i18 | 0)) {
+           if (i12 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           i16 = i12 + 8 | 0;
+           if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+            i9 = i16;
+           } else {
+            _abort();
+           }
+          } else {
+           i9 = i12 + 8 | 0;
+          }
+          HEAP32[i5 + 12 >> 2] = i12;
+          HEAP32[i9 >> 2] = i5;
+         }
+        } while (0);
+        i15 = i17 + ((i11 | i13) + i14) | 0;
+        i10 = i11 + i10 | 0;
+       }
+       i5 = i15 + 4 | 0;
+       HEAP32[i5 >> 2] = HEAP32[i5 >> 2] & -2;
+       HEAP32[i17 + (i8 + 4) >> 2] = i10 | 1;
+       HEAP32[i17 + (i10 + i8) >> 2] = i10;
+       i5 = i10 >>> 3;
+       if (i10 >>> 0 < 256) {
+        i10 = i5 << 1;
+        i2 = 96 + (i10 << 2) | 0;
+        i9 = HEAP32[14] | 0;
+        i5 = 1 << i5;
+        if ((i9 & i5 | 0) != 0) {
+         i9 = 96 + (i10 + 2 << 2) | 0;
+         i5 = HEAP32[i9 >> 2] | 0;
+         if (i5 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          i3 = i9;
+          i4 = i5;
+         }
+        } else {
+         HEAP32[14] = i9 | i5;
+         i3 = 96 + (i10 + 2 << 2) | 0;
+         i4 = i2;
+        }
+        HEAP32[i3 >> 2] = i7;
+        HEAP32[i4 + 12 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        break;
+       }
+       i3 = i10 >>> 8;
+       if ((i3 | 0) != 0) {
+        if (i10 >>> 0 > 16777215) {
+         i3 = 31;
+        } else {
+         i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+         i32 = i3 << i31;
+         i30 = (i32 + 520192 | 0) >>> 16 & 4;
+         i32 = i32 << i30;
+         i3 = (i32 + 245760 | 0) >>> 16 & 2;
+         i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+         i3 = i10 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+        }
+       } else {
+        i3 = 0;
+       }
+       i4 = 360 + (i3 << 2) | 0;
+       HEAP32[i17 + (i8 + 28) >> 2] = i3;
+       HEAP32[i17 + (i8 + 20) >> 2] = 0;
+       HEAP32[i17 + (i8 + 16) >> 2] = 0;
+       i9 = HEAP32[60 >> 2] | 0;
+       i5 = 1 << i3;
+       if ((i9 & i5 | 0) == 0) {
+        HEAP32[60 >> 2] = i9 | i5;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 24) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i7;
+        break;
+       }
+       i4 = HEAP32[i4 >> 2] | 0;
+       if ((i3 | 0) == 31) {
+        i3 = 0;
+       } else {
+        i3 = 25 - (i3 >>> 1) | 0;
+       }
+       L444 : do {
+        if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i10 | 0)) {
+         i3 = i10 << i3;
+         while (1) {
+          i5 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+          i9 = HEAP32[i5 >> 2] | 0;
+          if ((i9 | 0) == 0) {
+           break;
+          }
+          if ((HEAP32[i9 + 4 >> 2] & -8 | 0) == (i10 | 0)) {
+           i2 = i9;
+           break L444;
+          } else {
+           i3 = i3 << 1;
+           i4 = i9;
+          }
+         }
+         if (i5 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i5 >> 2] = i7;
+          HEAP32[i17 + (i8 + 24) >> 2] = i4;
+          HEAP32[i17 + (i8 + 12) >> 2] = i7;
+          HEAP32[i17 + (i8 + 8) >> 2] = i7;
+          break L348;
+         }
+        } else {
+         i2 = i4;
+        }
+       } while (0);
+       i4 = i2 + 8 | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       i5 = HEAP32[72 >> 2] | 0;
+       if (i2 >>> 0 < i5 >>> 0) {
+        _abort();
+       }
+       if (i3 >>> 0 < i5 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i3 + 12 >> 2] = i7;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i3;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        HEAP32[i17 + (i8 + 24) >> 2] = 0;
+        break;
+       }
+      } else {
+       i32 = (HEAP32[68 >> 2] | 0) + i10 | 0;
+       HEAP32[68 >> 2] = i32;
+       HEAP32[80 >> 2] = i7;
+       HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+      }
+     } while (0);
+     i32 = i17 + (i6 | 8) | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i3 = 504 | 0;
+    while (1) {
+     i2 = HEAP32[i3 >> 2] | 0;
+     if (!(i2 >>> 0 > i15 >>> 0) ? (i11 = HEAP32[i3 + 4 >> 2] | 0, i10 = i2 + i11 | 0, i10 >>> 0 > i15 >>> 0) : 0) {
+      break;
+     }
+     i3 = HEAP32[i3 + 8 >> 2] | 0;
+    }
+    i3 = i2 + (i11 + -39) | 0;
+    if ((i3 & 7 | 0) == 0) {
+     i3 = 0;
+    } else {
+     i3 = 0 - i3 & 7;
+    }
+    i2 = i2 + (i11 + -47 + i3) | 0;
+    i2 = i2 >>> 0 < (i15 + 16 | 0) >>> 0 ? i15 : i2;
+    i3 = i2 + 8 | 0;
+    i4 = i17 + 8 | 0;
+    if ((i4 & 7 | 0) == 0) {
+     i4 = 0;
+    } else {
+     i4 = 0 - i4 & 7;
+    }
+    i32 = i14 + -40 - i4 | 0;
+    HEAP32[80 >> 2] = i17 + i4;
+    HEAP32[68 >> 2] = i32;
+    HEAP32[i17 + (i4 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[84 >> 2] = HEAP32[544 >> 2];
+    HEAP32[i2 + 4 >> 2] = 27;
+    HEAP32[i3 + 0 >> 2] = HEAP32[504 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[508 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[512 >> 2];
+    HEAP32[i3 + 12 >> 2] = HEAP32[516 >> 2];
+    HEAP32[504 >> 2] = i17;
+    HEAP32[508 >> 2] = i14;
+    HEAP32[516 >> 2] = 0;
+    HEAP32[512 >> 2] = i3;
+    i4 = i2 + 28 | 0;
+    HEAP32[i4 >> 2] = 7;
+    if ((i2 + 32 | 0) >>> 0 < i10 >>> 0) {
+     while (1) {
+      i3 = i4 + 4 | 0;
+      HEAP32[i3 >> 2] = 7;
+      if ((i4 + 8 | 0) >>> 0 < i10 >>> 0) {
+       i4 = i3;
+      } else {
+       break;
+      }
+     }
+    }
+    if ((i2 | 0) != (i15 | 0)) {
+     i2 = i2 - i15 | 0;
+     i3 = i15 + (i2 + 4) | 0;
+     HEAP32[i3 >> 2] = HEAP32[i3 >> 2] & -2;
+     HEAP32[i15 + 4 >> 2] = i2 | 1;
+     HEAP32[i15 + i2 >> 2] = i2;
+     i3 = i2 >>> 3;
+     if (i2 >>> 0 < 256) {
+      i4 = i3 << 1;
+      i2 = 96 + (i4 << 2) | 0;
+      i5 = HEAP32[14] | 0;
+      i3 = 1 << i3;
+      if ((i5 & i3 | 0) != 0) {
+       i4 = 96 + (i4 + 2 << 2) | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       if (i3 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i7 = i4;
+        i8 = i3;
+       }
+      } else {
+       HEAP32[14] = i5 | i3;
+       i7 = 96 + (i4 + 2 << 2) | 0;
+       i8 = i2;
+      }
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i8 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i8;
+      HEAP32[i15 + 12 >> 2] = i2;
+      break;
+     }
+     i3 = i2 >>> 8;
+     if ((i3 | 0) != 0) {
+      if (i2 >>> 0 > 16777215) {
+       i3 = 31;
+      } else {
+       i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+       i32 = i3 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i3 = (i32 + 245760 | 0) >>> 16 & 2;
+       i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+       i3 = i2 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+      }
+     } else {
+      i3 = 0;
+     }
+     i7 = 360 + (i3 << 2) | 0;
+     HEAP32[i15 + 28 >> 2] = i3;
+     HEAP32[i15 + 20 >> 2] = 0;
+     HEAP32[i15 + 16 >> 2] = 0;
+     i4 = HEAP32[60 >> 2] | 0;
+     i5 = 1 << i3;
+     if ((i4 & i5 | 0) == 0) {
+      HEAP32[60 >> 2] = i4 | i5;
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i7;
+      HEAP32[i15 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i15;
+      break;
+     }
+     i4 = HEAP32[i7 >> 2] | 0;
+     if ((i3 | 0) == 31) {
+      i3 = 0;
+     } else {
+      i3 = 25 - (i3 >>> 1) | 0;
+     }
+     L499 : do {
+      if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i2 | 0)) {
+       i3 = i2 << i3;
+       while (1) {
+        i7 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+        i5 = HEAP32[i7 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         break;
+        }
+        if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i2 | 0)) {
+         i6 = i5;
+         break L499;
+        } else {
+         i3 = i3 << 1;
+         i4 = i5;
+        }
+       }
+       if (i7 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i7 >> 2] = i15;
+        HEAP32[i15 + 24 >> 2] = i4;
+        HEAP32[i15 + 12 >> 2] = i15;
+        HEAP32[i15 + 8 >> 2] = i15;
+        break L311;
+       }
+      } else {
+       i6 = i4;
+      }
+     } while (0);
+     i4 = i6 + 8 | 0;
+     i3 = HEAP32[i4 >> 2] | 0;
+     i2 = HEAP32[72 >> 2] | 0;
+     if (i6 >>> 0 < i2 >>> 0) {
+      _abort();
+     }
+     if (i3 >>> 0 < i2 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i3 + 12 >> 2] = i15;
+      HEAP32[i4 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i3;
+      HEAP32[i15 + 12 >> 2] = i6;
+      HEAP32[i15 + 24 >> 2] = 0;
+      break;
+     }
+    }
+   } else {
+    i32 = HEAP32[72 >> 2] | 0;
+    if ((i32 | 0) == 0 | i17 >>> 0 < i32 >>> 0) {
+     HEAP32[72 >> 2] = i17;
+    }
+    HEAP32[504 >> 2] = i17;
+    HEAP32[508 >> 2] = i14;
+    HEAP32[516 >> 2] = 0;
+    HEAP32[92 >> 2] = HEAP32[132];
+    HEAP32[88 >> 2] = -1;
+    i2 = 0;
+    do {
+     i32 = i2 << 1;
+     i31 = 96 + (i32 << 2) | 0;
+     HEAP32[96 + (i32 + 3 << 2) >> 2] = i31;
+     HEAP32[96 + (i32 + 2 << 2) >> 2] = i31;
+     i2 = i2 + 1 | 0;
+    } while ((i2 | 0) != 32);
+    i2 = i17 + 8 | 0;
+    if ((i2 & 7 | 0) == 0) {
+     i2 = 0;
+    } else {
+     i2 = 0 - i2 & 7;
+    }
+    i32 = i14 + -40 - i2 | 0;
+    HEAP32[80 >> 2] = i17 + i2;
+    HEAP32[68 >> 2] = i32;
+    HEAP32[i17 + (i2 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[84 >> 2] = HEAP32[544 >> 2];
+   }
+  } while (0);
+  i2 = HEAP32[68 >> 2] | 0;
+  if (i2 >>> 0 > i12 >>> 0) {
+   i31 = i2 - i12 | 0;
+   HEAP32[68 >> 2] = i31;
+   i32 = HEAP32[80 >> 2] | 0;
+   HEAP32[80 >> 2] = i32 + i12;
+   HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+   HEAP32[i32 + 4 >> 2] = i12 | 3;
+   i32 = i32 + 8 | 0;
+   STACKTOP = i1;
+   return i32 | 0;
+  }
+ }
+ HEAP32[(___errno_location() | 0) >> 2] = 12;
+ i32 = 0;
+ STACKTOP = i1;
+ return i32 | 0;
+}
+function _free(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i1 = STACKTOP;
+ if ((i7 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i15 = i7 + -8 | 0;
+ i16 = HEAP32[72 >> 2] | 0;
+ if (i15 >>> 0 < i16 >>> 0) {
+  _abort();
+ }
+ i13 = HEAP32[i7 + -4 >> 2] | 0;
+ i12 = i13 & 3;
+ if ((i12 | 0) == 1) {
+  _abort();
+ }
+ i8 = i13 & -8;
+ i6 = i7 + (i8 + -8) | 0;
+ do {
+  if ((i13 & 1 | 0) == 0) {
+   i19 = HEAP32[i15 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   i15 = -8 - i19 | 0;
+   i13 = i7 + i15 | 0;
+   i12 = i19 + i8 | 0;
+   if (i13 >>> 0 < i16 >>> 0) {
+    _abort();
+   }
+   if ((i13 | 0) == (HEAP32[76 >> 2] | 0)) {
+    i2 = i7 + (i8 + -4) | 0;
+    if ((HEAP32[i2 >> 2] & 3 | 0) != 3) {
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    HEAP32[64 >> 2] = i12;
+    HEAP32[i2 >> 2] = HEAP32[i2 >> 2] & -2;
+    HEAP32[i7 + (i15 + 4) >> 2] = i12 | 1;
+    HEAP32[i6 >> 2] = i12;
+    STACKTOP = i1;
+    return;
+   }
+   i18 = i19 >>> 3;
+   if (i19 >>> 0 < 256) {
+    i2 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+    i11 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+    i14 = 96 + (i18 << 1 << 2) | 0;
+    if ((i2 | 0) != (i14 | 0)) {
+     if (i2 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i2 + 12 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+    }
+    if ((i11 | 0) == (i2 | 0)) {
+     HEAP32[14] = HEAP32[14] & ~(1 << i18);
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    if ((i11 | 0) != (i14 | 0)) {
+     if (i11 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i14 = i11 + 8 | 0;
+     if ((HEAP32[i14 >> 2] | 0) == (i13 | 0)) {
+      i17 = i14;
+     } else {
+      _abort();
+     }
+    } else {
+     i17 = i11 + 8 | 0;
+    }
+    HEAP32[i2 + 12 >> 2] = i11;
+    HEAP32[i17 >> 2] = i2;
+    i2 = i13;
+    i11 = i12;
+    break;
+   }
+   i17 = HEAP32[i7 + (i15 + 24) >> 2] | 0;
+   i18 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+   do {
+    if ((i18 | 0) == (i13 | 0)) {
+     i19 = i7 + (i15 + 20) | 0;
+     i18 = HEAP32[i19 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      i19 = i7 + (i15 + 16) | 0;
+      i18 = HEAP32[i19 >> 2] | 0;
+      if ((i18 | 0) == 0) {
+       i14 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i21 = i18 + 20 | 0;
+      i20 = HEAP32[i21 >> 2] | 0;
+      if ((i20 | 0) != 0) {
+       i18 = i20;
+       i19 = i21;
+       continue;
+      }
+      i20 = i18 + 16 | 0;
+      i21 = HEAP32[i20 >> 2] | 0;
+      if ((i21 | 0) == 0) {
+       break;
+      } else {
+       i18 = i21;
+       i19 = i20;
+      }
+     }
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i19 >> 2] = 0;
+      i14 = i18;
+      break;
+     }
+    } else {
+     i19 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i16 = i19 + 12 | 0;
+     if ((HEAP32[i16 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+     i20 = i18 + 8 | 0;
+     if ((HEAP32[i20 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i18;
+      HEAP32[i20 >> 2] = i19;
+      i14 = i18;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i17 | 0) != 0) {
+    i18 = HEAP32[i7 + (i15 + 28) >> 2] | 0;
+    i16 = 360 + (i18 << 2) | 0;
+    if ((i13 | 0) == (HEAP32[i16 >> 2] | 0)) {
+     HEAP32[i16 >> 2] = i14;
+     if ((i14 | 0) == 0) {
+      HEAP32[60 >> 2] = HEAP32[60 >> 2] & ~(1 << i18);
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     if (i17 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i16 = i17 + 16 | 0;
+     if ((HEAP32[i16 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i14;
+     } else {
+      HEAP32[i17 + 20 >> 2] = i14;
+     }
+     if ((i14 | 0) == 0) {
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    }
+    if (i14 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i14 + 24 >> 2] = i17;
+    i16 = HEAP32[i7 + (i15 + 16) >> 2] | 0;
+    do {
+     if ((i16 | 0) != 0) {
+      if (i16 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i14 + 16 >> 2] = i16;
+       HEAP32[i16 + 24 >> 2] = i14;
+       break;
+      }
+     }
+    } while (0);
+    i15 = HEAP32[i7 + (i15 + 20) >> 2] | 0;
+    if ((i15 | 0) != 0) {
+     if (i15 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i14 + 20 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i14;
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     i2 = i13;
+     i11 = i12;
+    }
+   } else {
+    i2 = i13;
+    i11 = i12;
+   }
+  } else {
+   i2 = i15;
+   i11 = i8;
+  }
+ } while (0);
+ if (!(i2 >>> 0 < i6 >>> 0)) {
+  _abort();
+ }
+ i12 = i7 + (i8 + -4) | 0;
+ i13 = HEAP32[i12 >> 2] | 0;
+ if ((i13 & 1 | 0) == 0) {
+  _abort();
+ }
+ if ((i13 & 2 | 0) == 0) {
+  if ((i6 | 0) == (HEAP32[80 >> 2] | 0)) {
+   i21 = (HEAP32[68 >> 2] | 0) + i11 | 0;
+   HEAP32[68 >> 2] = i21;
+   HEAP32[80 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   if ((i2 | 0) != (HEAP32[76 >> 2] | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[76 >> 2] = 0;
+   HEAP32[64 >> 2] = 0;
+   STACKTOP = i1;
+   return;
+  }
+  if ((i6 | 0) == (HEAP32[76 >> 2] | 0)) {
+   i21 = (HEAP32[64 >> 2] | 0) + i11 | 0;
+   HEAP32[64 >> 2] = i21;
+   HEAP32[76 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   HEAP32[i2 + i21 >> 2] = i21;
+   STACKTOP = i1;
+   return;
+  }
+  i11 = (i13 & -8) + i11 | 0;
+  i12 = i13 >>> 3;
+  do {
+   if (!(i13 >>> 0 < 256)) {
+    i10 = HEAP32[i7 + (i8 + 16) >> 2] | 0;
+    i15 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    do {
+     if ((i15 | 0) == (i6 | 0)) {
+      i13 = i7 + (i8 + 12) | 0;
+      i12 = HEAP32[i13 >> 2] | 0;
+      if ((i12 | 0) == 0) {
+       i13 = i7 + (i8 + 8) | 0;
+       i12 = HEAP32[i13 >> 2] | 0;
+       if ((i12 | 0) == 0) {
+        i9 = 0;
+        break;
+       }
+      }
+      while (1) {
+       i14 = i12 + 20 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) != 0) {
+        i12 = i15;
+        i13 = i14;
+        continue;
+       }
+       i14 = i12 + 16 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) == 0) {
+        break;
+       } else {
+        i12 = i15;
+        i13 = i14;
+       }
+      }
+      if (i13 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 >> 2] = 0;
+       i9 = i12;
+       break;
+      }
+     } else {
+      i13 = HEAP32[i7 + i8 >> 2] | 0;
+      if (i13 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i14 = i13 + 12 | 0;
+      if ((HEAP32[i14 >> 2] | 0) != (i6 | 0)) {
+       _abort();
+      }
+      i12 = i15 + 8 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i14 >> 2] = i15;
+       HEAP32[i12 >> 2] = i13;
+       i9 = i15;
+       break;
+      } else {
+       _abort();
+      }
+     }
+    } while (0);
+    if ((i10 | 0) != 0) {
+     i12 = HEAP32[i7 + (i8 + 20) >> 2] | 0;
+     i13 = 360 + (i12 << 2) | 0;
+     if ((i6 | 0) == (HEAP32[i13 >> 2] | 0)) {
+      HEAP32[i13 >> 2] = i9;
+      if ((i9 | 0) == 0) {
+       HEAP32[60 >> 2] = HEAP32[60 >> 2] & ~(1 << i12);
+       break;
+      }
+     } else {
+      if (i10 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i12 = i10 + 16 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i12 >> 2] = i9;
+      } else {
+       HEAP32[i10 + 20 >> 2] = i9;
+      }
+      if ((i9 | 0) == 0) {
+       break;
+      }
+     }
+     if (i9 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     HEAP32[i9 + 24 >> 2] = i10;
+     i6 = HEAP32[i7 + (i8 + 8) >> 2] | 0;
+     do {
+      if ((i6 | 0) != 0) {
+       if (i6 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i9 + 16 >> 2] = i6;
+        HEAP32[i6 + 24 >> 2] = i9;
+        break;
+       }
+      }
+     } while (0);
+     i6 = HEAP32[i7 + (i8 + 12) >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      if (i6 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i9 + 20 >> 2] = i6;
+       HEAP32[i6 + 24 >> 2] = i9;
+       break;
+      }
+     }
+    }
+   } else {
+    i9 = HEAP32[i7 + i8 >> 2] | 0;
+    i7 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    i8 = 96 + (i12 << 1 << 2) | 0;
+    if ((i9 | 0) != (i8 | 0)) {
+     if (i9 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i9 + 12 >> 2] | 0) != (i6 | 0)) {
+      _abort();
+     }
+    }
+    if ((i7 | 0) == (i9 | 0)) {
+     HEAP32[14] = HEAP32[14] & ~(1 << i12);
+     break;
+    }
+    if ((i7 | 0) != (i8 | 0)) {
+     if (i7 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i8 = i7 + 8 | 0;
+     if ((HEAP32[i8 >> 2] | 0) == (i6 | 0)) {
+      i10 = i8;
+     } else {
+      _abort();
+     }
+    } else {
+     i10 = i7 + 8 | 0;
+    }
+    HEAP32[i9 + 12 >> 2] = i7;
+    HEAP32[i10 >> 2] = i9;
+   }
+  } while (0);
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+  if ((i2 | 0) == (HEAP32[76 >> 2] | 0)) {
+   HEAP32[64 >> 2] = i11;
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  HEAP32[i12 >> 2] = i13 & -2;
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+ }
+ i6 = i11 >>> 3;
+ if (i11 >>> 0 < 256) {
+  i7 = i6 << 1;
+  i3 = 96 + (i7 << 2) | 0;
+  i8 = HEAP32[14] | 0;
+  i6 = 1 << i6;
+  if ((i8 & i6 | 0) != 0) {
+   i6 = 96 + (i7 + 2 << 2) | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if (i7 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+    _abort();
+   } else {
+    i4 = i6;
+    i5 = i7;
+   }
+  } else {
+   HEAP32[14] = i8 | i6;
+   i4 = 96 + (i7 + 2 << 2) | 0;
+   i5 = i3;
+  }
+  HEAP32[i4 >> 2] = i2;
+  HEAP32[i5 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i5;
+  HEAP32[i2 + 12 >> 2] = i3;
+  STACKTOP = i1;
+  return;
+ }
+ i4 = i11 >>> 8;
+ if ((i4 | 0) != 0) {
+  if (i11 >>> 0 > 16777215) {
+   i4 = 31;
+  } else {
+   i20 = (i4 + 1048320 | 0) >>> 16 & 8;
+   i21 = i4 << i20;
+   i19 = (i21 + 520192 | 0) >>> 16 & 4;
+   i21 = i21 << i19;
+   i4 = (i21 + 245760 | 0) >>> 16 & 2;
+   i4 = 14 - (i19 | i20 | i4) + (i21 << i4 >>> 15) | 0;
+   i4 = i11 >>> (i4 + 7 | 0) & 1 | i4 << 1;
+  }
+ } else {
+  i4 = 0;
+ }
+ i5 = 360 + (i4 << 2) | 0;
+ HEAP32[i2 + 28 >> 2] = i4;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ i7 = HEAP32[60 >> 2] | 0;
+ i6 = 1 << i4;
+ L199 : do {
+  if ((i7 & i6 | 0) != 0) {
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((i4 | 0) == 31) {
+    i4 = 0;
+   } else {
+    i4 = 25 - (i4 >>> 1) | 0;
+   }
+   L205 : do {
+    if ((HEAP32[i5 + 4 >> 2] & -8 | 0) != (i11 | 0)) {
+     i4 = i11 << i4;
+     i7 = i5;
+     while (1) {
+      i6 = i7 + (i4 >>> 31 << 2) + 16 | 0;
+      i5 = HEAP32[i6 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       break;
+      }
+      if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i11 | 0)) {
+       i3 = i5;
+       break L205;
+      } else {
+       i4 = i4 << 1;
+       i7 = i5;
+      }
+     }
+     if (i6 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i6 >> 2] = i2;
+      HEAP32[i2 + 24 >> 2] = i7;
+      HEAP32[i2 + 12 >> 2] = i2;
+      HEAP32[i2 + 8 >> 2] = i2;
+      break L199;
+     }
+    } else {
+     i3 = i5;
+    }
+   } while (0);
+   i5 = i3 + 8 | 0;
+   i4 = HEAP32[i5 >> 2] | 0;
+   i6 = HEAP32[72 >> 2] | 0;
+   if (i3 >>> 0 < i6 >>> 0) {
+    _abort();
+   }
+   if (i4 >>> 0 < i6 >>> 0) {
+    _abort();
+   } else {
+    HEAP32[i4 + 12 >> 2] = i2;
+    HEAP32[i5 >> 2] = i2;
+    HEAP32[i2 + 8 >> 2] = i4;
+    HEAP32[i2 + 12 >> 2] = i3;
+    HEAP32[i2 + 24 >> 2] = 0;
+    break;
+   }
+  } else {
+   HEAP32[60 >> 2] = i7 | i6;
+   HEAP32[i5 >> 2] = i2;
+   HEAP32[i2 + 24 >> 2] = i5;
+   HEAP32[i2 + 12 >> 2] = i2;
+   HEAP32[i2 + 8 >> 2] = i2;
+  }
+ } while (0);
+ i21 = (HEAP32[88 >> 2] | 0) + -1 | 0;
+ HEAP32[88 >> 2] = i21;
+ if ((i21 | 0) == 0) {
+  i2 = 512 | 0;
+ } else {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i2 = HEAP32[i2 >> 2] | 0;
+  if ((i2 | 0) == 0) {
+   break;
+  } else {
+   i2 = i2 + 8 | 0;
+  }
+ }
+ HEAP32[88 >> 2] = -1;
+ STACKTOP = i1;
+ return;
+}
+function __Z15fannkuch_workerPv(i9) {
+ i9 = i9 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0;
+ i3 = STACKTOP;
+ i7 = HEAP32[i9 + 4 >> 2] | 0;
+ i6 = i7 << 2;
+ i5 = _malloc(i6) | 0;
+ i2 = _malloc(i6) | 0;
+ i6 = _malloc(i6) | 0;
+ i10 = (i7 | 0) > 0;
+ if (i10) {
+  i8 = 0;
+  do {
+   HEAP32[i5 + (i8 << 2) >> 2] = i8;
+   i8 = i8 + 1 | 0;
+  } while ((i8 | 0) != (i7 | 0));
+  i8 = i7 + -1 | 0;
+  i17 = HEAP32[i9 >> 2] | 0;
+  HEAP32[i5 + (i17 << 2) >> 2] = i8;
+  i9 = i5 + (i8 << 2) | 0;
+  HEAP32[i9 >> 2] = i17;
+  if (i10) {
+   i10 = i7 << 2;
+   i11 = 0;
+   i12 = i7;
+   L7 : while (1) {
+    if ((i12 | 0) > 1) {
+     while (1) {
+      i13 = i12 + -1 | 0;
+      HEAP32[i6 + (i13 << 2) >> 2] = i12;
+      if ((i13 | 0) > 1) {
+       i12 = i13;
+      } else {
+       i12 = 1;
+       break;
+      }
+     }
+    }
+    i13 = HEAP32[i5 >> 2] | 0;
+    if ((i13 | 0) != 0 ? (HEAP32[i9 >> 2] | 0) != (i8 | 0) : 0) {
+     _memcpy(i2 | 0, i5 | 0, i10 | 0) | 0;
+     i15 = 0;
+     i14 = HEAP32[i2 >> 2] | 0;
+     while (1) {
+      i17 = i14 + -1 | 0;
+      if ((i17 | 0) > 1) {
+       i16 = 1;
+       do {
+        i20 = i2 + (i16 << 2) | 0;
+        i19 = HEAP32[i20 >> 2] | 0;
+        i18 = i2 + (i17 << 2) | 0;
+        HEAP32[i20 >> 2] = HEAP32[i18 >> 2];
+        HEAP32[i18 >> 2] = i19;
+        i16 = i16 + 1 | 0;
+        i17 = i17 + -1 | 0;
+       } while ((i16 | 0) < (i17 | 0));
+      }
+      i15 = i15 + 1 | 0;
+      i20 = i2 + (i14 << 2) | 0;
+      i16 = HEAP32[i20 >> 2] | 0;
+      HEAP32[i20 >> 2] = i14;
+      if ((i16 | 0) == 0) {
+       break;
+      } else {
+       i14 = i16;
+      }
+     }
+     i11 = (i11 | 0) < (i15 | 0) ? i15 : i11;
+    }
+    if ((i12 | 0) >= (i8 | 0)) {
+     i8 = 34;
+     break;
+    }
+    while (1) {
+     if ((i12 | 0) > 0) {
+      i14 = 0;
+      while (1) {
+       i15 = i14 + 1 | 0;
+       HEAP32[i5 + (i14 << 2) >> 2] = HEAP32[i5 + (i15 << 2) >> 2];
+       if ((i15 | 0) == (i12 | 0)) {
+        i14 = i12;
+        break;
+       } else {
+        i14 = i15;
+       }
+      }
+     } else {
+      i14 = 0;
+     }
+     HEAP32[i5 + (i14 << 2) >> 2] = i13;
+     i14 = i6 + (i12 << 2) | 0;
+     i20 = (HEAP32[i14 >> 2] | 0) + -1 | 0;
+     HEAP32[i14 >> 2] = i20;
+     i14 = i12 + 1 | 0;
+     if ((i20 | 0) > 0) {
+      continue L7;
+     }
+     if ((i14 | 0) >= (i8 | 0)) {
+      i8 = 34;
+      break L7;
+     }
+     i13 = HEAP32[i5 >> 2] | 0;
+     i12 = i14;
+    }
+   }
+   if ((i8 | 0) == 34) {
+    _free(i5);
+    _free(i2);
+    _free(i6);
+    STACKTOP = i3;
+    return i11 | 0;
+   }
+  } else {
+   i1 = i9;
+   i4 = i8;
+  }
+ } else {
+  i4 = i7 + -1 | 0;
+  i20 = HEAP32[i9 >> 2] | 0;
+  HEAP32[i5 + (i20 << 2) >> 2] = i4;
+  i1 = i5 + (i4 << 2) | 0;
+  HEAP32[i1 >> 2] = i20;
+ }
+ i11 = 0;
+ L36 : while (1) {
+  if ((i7 | 0) > 1) {
+   while (1) {
+    i8 = i7 + -1 | 0;
+    HEAP32[i6 + (i8 << 2) >> 2] = i7;
+    if ((i8 | 0) > 1) {
+     i7 = i8;
+    } else {
+     i7 = 1;
+     break;
+    }
+   }
+  }
+  i8 = HEAP32[i5 >> 2] | 0;
+  if ((i8 | 0) != 0 ? (HEAP32[i1 >> 2] | 0) != (i4 | 0) : 0) {
+   i10 = 0;
+   i9 = HEAP32[i2 >> 2] | 0;
+   while (1) {
+    i13 = i9 + -1 | 0;
+    if ((i13 | 0) > 1) {
+     i12 = 1;
+     do {
+      i18 = i2 + (i12 << 2) | 0;
+      i19 = HEAP32[i18 >> 2] | 0;
+      i20 = i2 + (i13 << 2) | 0;
+      HEAP32[i18 >> 2] = HEAP32[i20 >> 2];
+      HEAP32[i20 >> 2] = i19;
+      i12 = i12 + 1 | 0;
+      i13 = i13 + -1 | 0;
+     } while ((i12 | 0) < (i13 | 0));
+    }
+    i10 = i10 + 1 | 0;
+    i20 = i2 + (i9 << 2) | 0;
+    i12 = HEAP32[i20 >> 2] | 0;
+    HEAP32[i20 >> 2] = i9;
+    if ((i12 | 0) == 0) {
+     break;
+    } else {
+     i9 = i12;
+    }
+   }
+   i11 = (i11 | 0) < (i10 | 0) ? i10 : i11;
+  }
+  if ((i7 | 0) >= (i4 | 0)) {
+   i8 = 34;
+   break;
+  }
+  while (1) {
+   if ((i7 | 0) > 0) {
+    i9 = 0;
+    while (1) {
+     i10 = i9 + 1 | 0;
+     HEAP32[i5 + (i9 << 2) >> 2] = HEAP32[i5 + (i10 << 2) >> 2];
+     if ((i10 | 0) == (i7 | 0)) {
+      i9 = i7;
+      break;
+     } else {
+      i9 = i10;
+     }
+    }
+   } else {
+    i9 = 0;
+   }
+   HEAP32[i5 + (i9 << 2) >> 2] = i8;
+   i9 = i6 + (i7 << 2) | 0;
+   i20 = (HEAP32[i9 >> 2] | 0) + -1 | 0;
+   HEAP32[i9 >> 2] = i20;
+   i9 = i7 + 1 | 0;
+   if ((i20 | 0) > 0) {
+    continue L36;
+   }
+   if ((i9 | 0) >= (i4 | 0)) {
+    i8 = 34;
+    break L36;
+   }
+   i8 = HEAP32[i5 >> 2] | 0;
+   i7 = i9;
+  }
+ }
+ if ((i8 | 0) == 34) {
+  _free(i5);
+  _free(i2);
+  _free(i6);
+  STACKTOP = i3;
+  return i11 | 0;
+ }
+ return 0;
+}
+function _main(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i1 = i2;
+ L1 : do {
+  if ((i3 | 0) > 1) {
+   i3 = HEAP8[HEAP32[i5 + 4 >> 2] | 0] | 0;
+   switch (i3 | 0) {
+   case 50:
+    {
+     i3 = 10;
+     break L1;
+    }
+   case 51:
+    {
+     i4 = 4;
+     break L1;
+    }
+   case 52:
+    {
+     i3 = 11;
+     break L1;
+    }
+   case 53:
+    {
+     i3 = 12;
+     break L1;
+    }
+   case 49:
+    {
+     i3 = 9;
+     break L1;
+    }
+   case 48:
+    {
+     i11 = 0;
+     STACKTOP = i2;
+     return i11 | 0;
+    }
+   default:
+    {
+     HEAP32[i1 >> 2] = i3 + -48;
+     _printf(8, i1 | 0) | 0;
+     i11 = -1;
+     STACKTOP = i2;
+     return i11 | 0;
+    }
+   }
+  } else {
+   i4 = 4;
+  }
+ } while (0);
+ if ((i4 | 0) == 4) {
+  i3 = 11;
+ }
+ i5 = i3 + -1 | 0;
+ i6 = 0;
+ i7 = 0;
+ while (1) {
+  i4 = _malloc(12) | 0;
+  HEAP32[i4 >> 2] = i7;
+  HEAP32[i4 + 4 >> 2] = i3;
+  HEAP32[i4 + 8 >> 2] = i6;
+  i7 = i7 + 1 | 0;
+  if ((i7 | 0) == (i5 | 0)) {
+   break;
+  } else {
+   i6 = i4;
+  }
+ }
+ i5 = i3 << 2;
+ i6 = _malloc(i5) | 0;
+ i5 = _malloc(i5) | 0;
+ i7 = 0;
+ do {
+  HEAP32[i6 + (i7 << 2) >> 2] = i7;
+  i7 = i7 + 1 | 0;
+ } while ((i7 | 0) != (i3 | 0));
+ i8 = i3;
+ i7 = 30;
+ L19 : do {
+  i9 = 0;
+  do {
+   HEAP32[i1 >> 2] = (HEAP32[i6 + (i9 << 2) >> 2] | 0) + 1;
+   _printf(48, i1 | 0) | 0;
+   i9 = i9 + 1 | 0;
+  } while ((i9 | 0) != (i3 | 0));
+  _putchar(10) | 0;
+  i7 = i7 + -1 | 0;
+  if ((i8 | 0) <= 1) {
+   if ((i8 | 0) == (i3 | 0)) {
+    break;
+   }
+  } else {
+   while (1) {
+    i9 = i8 + -1 | 0;
+    HEAP32[i5 + (i9 << 2) >> 2] = i8;
+    if ((i9 | 0) > 1) {
+     i8 = i9;
+    } else {
+     i8 = 1;
+     break;
+    }
+   }
+  }
+  while (1) {
+   i9 = HEAP32[i6 >> 2] | 0;
+   if ((i8 | 0) > 0) {
+    i11 = 0;
+    while (1) {
+     i10 = i11 + 1 | 0;
+     HEAP32[i6 + (i11 << 2) >> 2] = HEAP32[i6 + (i10 << 2) >> 2];
+     if ((i10 | 0) == (i8 | 0)) {
+      i10 = i8;
+      break;
+     } else {
+      i11 = i10;
+     }
+    }
+   } else {
+    i10 = 0;
+   }
+   HEAP32[i6 + (i10 << 2) >> 2] = i9;
+   i9 = i5 + (i8 << 2) | 0;
+   i11 = (HEAP32[i9 >> 2] | 0) + -1 | 0;
+   HEAP32[i9 >> 2] = i11;
+   i9 = i8 + 1 | 0;
+   if ((i11 | 0) > 0) {
+    break;
+   }
+   if ((i9 | 0) == (i3 | 0)) {
+    break L19;
+   } else {
+    i8 = i9;
+   }
+  }
+ } while ((i7 | 0) != 0);
+ _free(i6);
+ _free(i5);
+ if ((i4 | 0) == 0) {
+  i5 = 0;
+ } else {
+  i5 = 0;
+  while (1) {
+   i6 = __Z15fannkuch_workerPv(i4) | 0;
+   i5 = (i5 | 0) < (i6 | 0) ? i6 : i5;
+   i6 = HEAP32[i4 + 8 >> 2] | 0;
+   _free(i4);
+   if ((i6 | 0) == 0) {
+    break;
+   } else {
+    i4 = i6;
+   }
+  }
+ }
+ HEAP32[i1 >> 2] = i3;
+ HEAP32[i1 + 4 >> 2] = i5;
+ _printf(24, i1 | 0) | 0;
+ i11 = 0;
+ STACKTOP = i2;
+ return i11 | 0;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function runPostSets() {}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+
+// EMSCRIPTEN_END_FUNCS
+
+
+  return { _strlen: _strlen, _free: _free, _main: _main, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9 };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "_fflush": _fflush, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_putchar": _putchar, "_fputc": _fputc, "_send": _send, "_pwrite": _pwrite, "_abort": _abort, "__reallyNegative": __reallyNegative, "_fwrite": _fwrite, "_sbrk": _sbrk, "_mkport": _mkport, "_fprintf": _fprintf, "___setErrNo": ___setErrNo, "__formatString": __formatString, "_fileno": _fileno, "_printf": _printf, "_time": _time, "_sysconf": _sysconf, "_write": _write, "___errno_location": ___errno_location, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _free = Module["_free"] = asm["_free"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var _malloc = Module["_malloc"] = asm["_malloc"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/fasta.js b/test/mjsunit/asm/embenchen/fasta.js
new file mode 100644
index 0000000..8c66354
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/fasta.js
@@ -0,0 +1,8605 @@
+var EXPECTED_OUTPUT =
+  'GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA\n' +
+  'TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT\n' +
+  'AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG\n' +
+  'GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG\n' +
+  'CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT\n' +
+  'GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA\n' +
+  'GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA\n' +
+  'TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG\n' +
+  'AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA\n' +
+  'GCCTGGGCGA\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(1155);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([38,2,0,0,0,0,0,0,42,0,0,0,0,0,0,0,97,0,0,0,113,61,138,62,0,0,0,0,99,0,0,0,143,194,245,61,0,0,0,0,103,0,0,0,143,194,245,61,0,0,0,0,116,0,0,0,113,61,138,62,0,0,0,0,66,0,0,0,10,215,163,60,0,0,0,0,68,0,0,0,10,215,163,60,0,0,0,0,72,0,0,0,10,215,163,60,0,0,0,0,75,0,0,0,10,215,163,60,0,0,0,0,77,0,0,0,10,215,163,60,0,0,0,0,78,0,0,0,10,215,163,60,0,0,0,0,82,0,0,0,10,215,163,60,0,0,0,0,83,0,0,0,10,215,163,60,0,0,0,0,86,0,0,0,10,215,163,60,0,0,0,0,87,0,0,0,10,215,163,60,0,0,0,0,89,0,0,0,10,215,163,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,97,0,0,0,233,28,155,62,0,0,0,0,99,0,0,0,114,189,74,62,0,0,0,0,103,0,0,0,215,73,74,62,0,0,0,0,116,0,0,0,114,95,154,62,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,114,114,111,114,58,32,37,100,10,0,0,0,0,0,0,71,71,67,67,71,71,71,67,71,67,71,71,84,71,71,67,84,67,65,67,71,67,67,84,71,84,65,65,84,67,67,67,65,71,67,65,67,84,84,84,71,71,71,65,71,71,67,67,71,65,71,71,67,71,71,71,67,71,71,65,84,67,65,67,67,84,71,65,71,71,84,67,65,71,71,65,71,84,84,67,71,65,71,65,67,67,65,71,67,67,84,71,71,67,67,65,65,67,65,84,71,71,84,71,65,65,65,67,67,67,67,71,84,67,84,67,84,65,67,84,65,65,65,65,65,84,65,67,65,65,65,65,65,84,84,65,71,67,67,71,71,71,67,71,84,71,71,84,71,71,67,71,67,71,67,71,67,67,84,71,84,65,65,84,67,67,67,65,71,67,84,65,67,84,67,71,71,71,65,71,71,67,84,71,65,71,71,67,65,71,71,65,71,65,65,84,67,71,67,84,84,71,65,65,67,67,67,71,71,71,65,71,71,67,71,71,65,71,71,84,84,71,67,65,71,84,71,65,71,67,67,71,65,71,65,84,67,71,67,71,67,67,65,67,84,71,67,65,67,84,67,67,65,71,67,67,84,71,71,71,67,71,65,67,65,71,65,71,67,71,65,71,65,67,84,67,67,71,84,67,84,67,65,65,65,65,65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,120,4,0,0,1,0,0,0,2,0,0,0,1,0,0,0,0,0,0,0,115,116,100,58,58,98,97,100,95,97,108,108,111,99,0,0,83,116,57,98,97,100,95,97,108,108,111,99,0,0,0,0,8,0,0,0,104,4,0,0,0,0,0,0,0,0,0,0], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};function _sysconf(name) {
+      // long sysconf(int name);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
+      switch(name) {
+        case 30: return PAGE_SIZE;
+        case 132:
+        case 133:
+        case 12:
+        case 137:
+        case 138:
+        case 15:
+        case 235:
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 149:
+        case 13:
+        case 10:
+        case 236:
+        case 153:
+        case 9:
+        case 21:
+        case 22:
+        case 159:
+        case 154:
+        case 14:
+        case 77:
+        case 78:
+        case 139:
+        case 80:
+        case 81:
+        case 79:
+        case 82:
+        case 68:
+        case 67:
+        case 164:
+        case 11:
+        case 29:
+        case 47:
+        case 48:
+        case 95:
+        case 52:
+        case 51:
+        case 46:
+          return 200809;
+        case 27:
+        case 246:
+        case 127:
+        case 128:
+        case 23:
+        case 24:
+        case 160:
+        case 161:
+        case 181:
+        case 182:
+        case 242:
+        case 183:
+        case 184:
+        case 243:
+        case 244:
+        case 245:
+        case 165:
+        case 178:
+        case 179:
+        case 49:
+        case 50:
+        case 168:
+        case 169:
+        case 175:
+        case 170:
+        case 171:
+        case 172:
+        case 97:
+        case 76:
+        case 32:
+        case 173:
+        case 35:
+          return -1;
+        case 176:
+        case 177:
+        case 7:
+        case 155:
+        case 8:
+        case 157:
+        case 125:
+        case 126:
+        case 92:
+        case 93:
+        case 129:
+        case 130:
+        case 131:
+        case 94:
+        case 91:
+          return 1;
+        case 74:
+        case 60:
+        case 69:
+        case 70:
+        case 4:
+          return 1024;
+        case 31:
+        case 42:
+        case 72:
+          return 32;
+        case 87:
+        case 26:
+        case 33:
+          return 2147483647;
+        case 34:
+        case 1:
+          return 47839;
+        case 38:
+        case 36:
+          return 99;
+        case 43:
+        case 37:
+          return 2048;
+        case 0: return 2097152;
+        case 3: return 65536;
+        case 28: return 32768;
+        case 44: return 32767;
+        case 75: return 16384;
+        case 39: return 1000;
+        case 89: return 700;
+        case 71: return 256;
+        case 40: return 255;
+        case 2: return 100;
+        case 180: return 64;
+        case 25: return 20;
+        case 5: return 16;
+        case 6: return 6;
+        case 73: return 4;
+        case 84: return 1;
+      }
+      ___setErrNo(ERRNO_CODES.EINVAL);
+      return -1;
+    }
+
+
+  function __ZSt18uncaught_exceptionv() { // std::uncaught_exception()
+      return !!__ZSt18uncaught_exceptionv.uncaught_exception;
+    }
+
+
+
+  function ___cxa_is_number_type(type) {
+      var isNumber = false;
+      try { if (type == __ZTIi) isNumber = true } catch(e){}
+      try { if (type == __ZTIj) isNumber = true } catch(e){}
+      try { if (type == __ZTIl) isNumber = true } catch(e){}
+      try { if (type == __ZTIm) isNumber = true } catch(e){}
+      try { if (type == __ZTIx) isNumber = true } catch(e){}
+      try { if (type == __ZTIy) isNumber = true } catch(e){}
+      try { if (type == __ZTIf) isNumber = true } catch(e){}
+      try { if (type == __ZTId) isNumber = true } catch(e){}
+      try { if (type == __ZTIe) isNumber = true } catch(e){}
+      try { if (type == __ZTIc) isNumber = true } catch(e){}
+      try { if (type == __ZTIa) isNumber = true } catch(e){}
+      try { if (type == __ZTIh) isNumber = true } catch(e){}
+      try { if (type == __ZTIs) isNumber = true } catch(e){}
+      try { if (type == __ZTIt) isNumber = true } catch(e){}
+      return isNumber;
+    }function ___cxa_does_inherit(definiteType, possibilityType, possibility) {
+      if (possibility == 0) return false;
+      if (possibilityType == 0 || possibilityType == definiteType)
+        return true;
+      var possibility_type_info;
+      if (___cxa_is_number_type(possibilityType)) {
+        possibility_type_info = possibilityType;
+      } else {
+        var possibility_type_infoAddr = HEAP32[((possibilityType)>>2)] - 8;
+        possibility_type_info = HEAP32[((possibility_type_infoAddr)>>2)];
+      }
+      switch (possibility_type_info) {
+      case 0: // possibility is a pointer
+        // See if definite type is a pointer
+        var definite_type_infoAddr = HEAP32[((definiteType)>>2)] - 8;
+        var definite_type_info = HEAP32[((definite_type_infoAddr)>>2)];
+        if (definite_type_info == 0) {
+          // Also a pointer; compare base types of pointers
+          var defPointerBaseAddr = definiteType+8;
+          var defPointerBaseType = HEAP32[((defPointerBaseAddr)>>2)];
+          var possPointerBaseAddr = possibilityType+8;
+          var possPointerBaseType = HEAP32[((possPointerBaseAddr)>>2)];
+          return ___cxa_does_inherit(defPointerBaseType, possPointerBaseType, possibility);
+        } else
+          return false; // one pointer and one non-pointer
+      case 1: // class with no base class
+        return false;
+      case 2: // class with base class
+        var parentTypeAddr = possibilityType + 8;
+        var parentType = HEAP32[((parentTypeAddr)>>2)];
+        return ___cxa_does_inherit(definiteType, parentType, possibility);
+      default:
+        return false; // some unencountered type
+      }
+    }
+
+
+
+  var ___cxa_last_thrown_exception=0;function ___resumeException(ptr) {
+      if (!___cxa_last_thrown_exception) { ___cxa_last_thrown_exception = ptr; }
+      throw ptr + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";
+    }
+
+  var ___cxa_exception_header_size=8;function ___cxa_find_matching_catch(thrown, throwntype) {
+      if (thrown == -1) thrown = ___cxa_last_thrown_exception;
+      header = thrown - ___cxa_exception_header_size;
+      if (throwntype == -1) throwntype = HEAP32[((header)>>2)];
+      var typeArray = Array.prototype.slice.call(arguments, 2);
+
+      // If throwntype is a pointer, this means a pointer has been
+      // thrown. When a pointer is thrown, actually what's thrown
+      // is a pointer to the pointer. We'll dereference it.
+      if (throwntype != 0 && !___cxa_is_number_type(throwntype)) {
+        var throwntypeInfoAddr= HEAP32[((throwntype)>>2)] - 8;
+        var throwntypeInfo= HEAP32[((throwntypeInfoAddr)>>2)];
+        if (throwntypeInfo == 0)
+          thrown = HEAP32[((thrown)>>2)];
+      }
+      // The different catch blocks are denoted by different types.
+      // Due to inheritance, those types may not precisely match the
+      // type of the thrown object. Find one which matches, and
+      // return the type of the catch block which should be called.
+      for (var i = 0; i < typeArray.length; i++) {
+        if (___cxa_does_inherit(typeArray[i], throwntype, thrown))
+          return ((asm["setTempRet0"](typeArray[i]),thrown)|0);
+      }
+      // Shouldn't happen unless we have bogus data in typeArray
+      // or encounter a type for which emscripten doesn't have suitable
+      // typeinfo defined. Best-efforts match just in case.
+      return ((asm["setTempRet0"](throwntype),thrown)|0);
+    }function ___cxa_throw(ptr, type, destructor) {
+      if (!___cxa_throw.initialized) {
+        try {
+          HEAP32[((__ZTVN10__cxxabiv119__pointer_type_infoE)>>2)]=0; // Workaround for libcxxabi integration bug
+        } catch(e){}
+        try {
+          HEAP32[((__ZTVN10__cxxabiv117__class_type_infoE)>>2)]=1; // Workaround for libcxxabi integration bug
+        } catch(e){}
+        try {
+          HEAP32[((__ZTVN10__cxxabiv120__si_class_type_infoE)>>2)]=2; // Workaround for libcxxabi integration bug
+        } catch(e){}
+        ___cxa_throw.initialized = true;
+      }
+      var header = ptr - ___cxa_exception_header_size;
+      HEAP32[((header)>>2)]=type;
+      HEAP32[(((header)+(4))>>2)]=destructor;
+      ___cxa_last_thrown_exception = ptr;
+      if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) {
+        __ZSt18uncaught_exceptionv.uncaught_exception = 1;
+      } else {
+        __ZSt18uncaught_exceptionv.uncaught_exception++;
+      }
+      throw ptr + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";
+    }
+
+
+  Module["_memset"] = _memset;
+
+  function _abort() {
+      Module['abort']();
+    }
+
+
+
+
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+  var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+
+
+  function _fputs(s, stream) {
+      // int fputs(const char *restrict s, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputs.html
+      var fd = _fileno(stream);
+      return _write(fd, s, _strlen(s));
+    }
+
+  function _fputc(c, stream) {
+      // int fputc(int c, FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html
+      var chr = unSign(c & 0xFF);
+      HEAP8[((_fputc.ret)|0)]=chr;
+      var fd = _fileno(stream);
+      var ret = _write(fd, _fputc.ret, 1);
+      if (ret == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return -1;
+      } else {
+        return chr;
+      }
+    }function _puts(s) {
+      // int puts(const char *s);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/puts.html
+      // NOTE: puts() always writes an extra newline.
+      var stdout = HEAP32[((_stdout)>>2)];
+      var ret = _fputs(s, stdout);
+      if (ret < 0) {
+        return ret;
+      } else {
+        var newlineRet = _fputc(10, stdout);
+        return (newlineRet < 0) ? -1 : ret + 1;
+      }
+    }
+
+  function _sbrk(bytes) {
+      // Implement a Linux-like 'memory area' for our 'process'.
+      // Changes the size of the memory area by |bytes|; returns the
+      // address of the previous top ('break') of the memory area
+      // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
+      var self = _sbrk;
+      if (!self.called) {
+        DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
+        self.called = true;
+        assert(Runtime.dynamicAlloc);
+        self.alloc = Runtime.dynamicAlloc;
+        Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
+      }
+      var ret = DYNAMICTOP;
+      if (bytes != 0) self.alloc(bytes);
+      return ret;  // Previous break location.
+    }
+
+  function ___errno_location() {
+      return ___errno_state;
+    }
+
+  function __ZNSt9exceptionD2Ev() {}
+
+  var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+            Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+            Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+            // just add the mouse delta to the current absolut mouse position
+            // FIXME: ideally this should be clamped against the canvas size and zero
+            Browser.mouseX += Browser.mouseMovementX;
+            Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+  function _time(ptr) {
+      var ret = Math.floor(Date.now()/1000);
+      if (ptr) {
+        HEAP32[((ptr)>>2)]=ret;
+      }
+      return ret;
+    }
+
+
+  function _malloc(bytes) {
+      /* Over-allocate to make sure it is byte-aligned by 8.
+       * This will leak memory, but this is only the dummy
+       * implementation (replaced by dlmalloc normally) so
+       * not an issue.
+       */
+      var ptr = Runtime.dynamicAlloc(bytes + 8);
+      return (ptr+8) & 0xFFFFFFF8;
+    }
+  Module["_malloc"] = _malloc;function ___cxa_allocate_exception(size) {
+      var ptr = _malloc(size + ___cxa_exception_header_size);
+      return ptr + ___cxa_exception_header_size;
+    }
+
+  var __ZTISt9exception=allocate([allocate([1,0,0,0,0,0,0], "i8", ALLOC_STATIC)+8, 0], "i32", ALLOC_STATIC);
+
+  function __ZTVN10__cxxabiv120__si_class_type_infoE() {
+  Module['printErr']('missing function: _ZTVN10__cxxabiv120__si_class_type_infoE'); abort(-1);
+  }
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+_fputc.ret = allocate([0], "i8", ALLOC_STATIC);
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function invoke_ii(index,a1) {
+  try {
+    return Module["dynCall_ii"](index,a1);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_vi(index,a1) {
+  try {
+    Module["dynCall_vi"](index,a1);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_v(index) {
+  try {
+    Module["dynCall_v"](index);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+  var __ZTISt9exception=env.__ZTISt9exception|0;
+  var __ZTVN10__cxxabiv120__si_class_type_infoE=env.__ZTVN10__cxxabiv120__si_class_type_infoE|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var invoke_ii=env.invoke_ii;
+  var invoke_vi=env.invoke_vi;
+  var invoke_v=env.invoke_v;
+  var _send=env._send;
+  var ___setErrNo=env.___setErrNo;
+  var ___cxa_is_number_type=env.___cxa_is_number_type;
+  var ___cxa_allocate_exception=env.___cxa_allocate_exception;
+  var ___cxa_find_matching_catch=env.___cxa_find_matching_catch;
+  var _fflush=env._fflush;
+  var _time=env._time;
+  var _pwrite=env._pwrite;
+  var __reallyNegative=env.__reallyNegative;
+  var _sbrk=env._sbrk;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _fileno=env._fileno;
+  var ___resumeException=env.___resumeException;
+  var __ZSt18uncaught_exceptionv=env.__ZSt18uncaught_exceptionv;
+  var _sysconf=env._sysconf;
+  var _puts=env._puts;
+  var _mkport=env._mkport;
+  var _write=env._write;
+  var ___errno_location=env.___errno_location;
+  var __ZNSt9exceptionD2Ev=env.__ZNSt9exceptionD2Ev;
+  var _fputc=env._fputc;
+  var ___cxa_throw=env.___cxa_throw;
+  var _abort=env._abort;
+  var _fwrite=env._fwrite;
+  var ___cxa_does_inherit=env.___cxa_does_inherit;
+  var _fprintf=env._fprintf;
+  var __formatString=env.__formatString;
+  var _fputs=env._fputs;
+  var _printf=env._printf;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _malloc(i12) {
+ i12 = i12 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0;
+ i1 = STACKTOP;
+ do {
+  if (i12 >>> 0 < 245) {
+   if (i12 >>> 0 < 11) {
+    i12 = 16;
+   } else {
+    i12 = i12 + 11 & -8;
+   }
+   i20 = i12 >>> 3;
+   i18 = HEAP32[146] | 0;
+   i21 = i18 >>> i20;
+   if ((i21 & 3 | 0) != 0) {
+    i6 = (i21 & 1 ^ 1) + i20 | 0;
+    i5 = i6 << 1;
+    i3 = 624 + (i5 << 2) | 0;
+    i5 = 624 + (i5 + 2 << 2) | 0;
+    i7 = HEAP32[i5 >> 2] | 0;
+    i2 = i7 + 8 | 0;
+    i4 = HEAP32[i2 >> 2] | 0;
+    do {
+     if ((i3 | 0) != (i4 | 0)) {
+      if (i4 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i8 = i4 + 12 | 0;
+      if ((HEAP32[i8 >> 2] | 0) == (i7 | 0)) {
+       HEAP32[i8 >> 2] = i3;
+       HEAP32[i5 >> 2] = i4;
+       break;
+      } else {
+       _abort();
+      }
+     } else {
+      HEAP32[146] = i18 & ~(1 << i6);
+     }
+    } while (0);
+    i32 = i6 << 3;
+    HEAP32[i7 + 4 >> 2] = i32 | 3;
+    i32 = i7 + (i32 | 4) | 0;
+    HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+    i32 = i2;
+    STACKTOP = i1;
+    return i32 | 0;
+   }
+   if (i12 >>> 0 > (HEAP32[592 >> 2] | 0) >>> 0) {
+    if ((i21 | 0) != 0) {
+     i7 = 2 << i20;
+     i7 = i21 << i20 & (i7 | 0 - i7);
+     i7 = (i7 & 0 - i7) + -1 | 0;
+     i2 = i7 >>> 12 & 16;
+     i7 = i7 >>> i2;
+     i6 = i7 >>> 5 & 8;
+     i7 = i7 >>> i6;
+     i5 = i7 >>> 2 & 4;
+     i7 = i7 >>> i5;
+     i4 = i7 >>> 1 & 2;
+     i7 = i7 >>> i4;
+     i3 = i7 >>> 1 & 1;
+     i3 = (i6 | i2 | i5 | i4 | i3) + (i7 >>> i3) | 0;
+     i7 = i3 << 1;
+     i4 = 624 + (i7 << 2) | 0;
+     i7 = 624 + (i7 + 2 << 2) | 0;
+     i5 = HEAP32[i7 >> 2] | 0;
+     i2 = i5 + 8 | 0;
+     i6 = HEAP32[i2 >> 2] | 0;
+     do {
+      if ((i4 | 0) != (i6 | 0)) {
+       if (i6 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       i8 = i6 + 12 | 0;
+       if ((HEAP32[i8 >> 2] | 0) == (i5 | 0)) {
+        HEAP32[i8 >> 2] = i4;
+        HEAP32[i7 >> 2] = i6;
+        break;
+       } else {
+        _abort();
+       }
+      } else {
+       HEAP32[146] = i18 & ~(1 << i3);
+      }
+     } while (0);
+     i6 = i3 << 3;
+     i4 = i6 - i12 | 0;
+     HEAP32[i5 + 4 >> 2] = i12 | 3;
+     i3 = i5 + i12 | 0;
+     HEAP32[i5 + (i12 | 4) >> 2] = i4 | 1;
+     HEAP32[i5 + i6 >> 2] = i4;
+     i6 = HEAP32[592 >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      i5 = HEAP32[604 >> 2] | 0;
+      i8 = i6 >>> 3;
+      i9 = i8 << 1;
+      i6 = 624 + (i9 << 2) | 0;
+      i7 = HEAP32[146] | 0;
+      i8 = 1 << i8;
+      if ((i7 & i8 | 0) != 0) {
+       i7 = 624 + (i9 + 2 << 2) | 0;
+       i8 = HEAP32[i7 >> 2] | 0;
+       if (i8 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i28 = i7;
+        i27 = i8;
+       }
+      } else {
+       HEAP32[146] = i7 | i8;
+       i28 = 624 + (i9 + 2 << 2) | 0;
+       i27 = i6;
+      }
+      HEAP32[i28 >> 2] = i5;
+      HEAP32[i27 + 12 >> 2] = i5;
+      HEAP32[i5 + 8 >> 2] = i27;
+      HEAP32[i5 + 12 >> 2] = i6;
+     }
+     HEAP32[592 >> 2] = i4;
+     HEAP32[604 >> 2] = i3;
+     i32 = i2;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i18 = HEAP32[588 >> 2] | 0;
+    if ((i18 | 0) != 0) {
+     i2 = (i18 & 0 - i18) + -1 | 0;
+     i31 = i2 >>> 12 & 16;
+     i2 = i2 >>> i31;
+     i30 = i2 >>> 5 & 8;
+     i2 = i2 >>> i30;
+     i32 = i2 >>> 2 & 4;
+     i2 = i2 >>> i32;
+     i6 = i2 >>> 1 & 2;
+     i2 = i2 >>> i6;
+     i3 = i2 >>> 1 & 1;
+     i3 = HEAP32[888 + ((i30 | i31 | i32 | i6 | i3) + (i2 >>> i3) << 2) >> 2] | 0;
+     i2 = (HEAP32[i3 + 4 >> 2] & -8) - i12 | 0;
+     i6 = i3;
+     while (1) {
+      i5 = HEAP32[i6 + 16 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       i5 = HEAP32[i6 + 20 >> 2] | 0;
+       if ((i5 | 0) == 0) {
+        break;
+       }
+      }
+      i6 = (HEAP32[i5 + 4 >> 2] & -8) - i12 | 0;
+      i4 = i6 >>> 0 < i2 >>> 0;
+      i2 = i4 ? i6 : i2;
+      i6 = i5;
+      i3 = i4 ? i5 : i3;
+     }
+     i6 = HEAP32[600 >> 2] | 0;
+     if (i3 >>> 0 < i6 >>> 0) {
+      _abort();
+     }
+     i4 = i3 + i12 | 0;
+     if (!(i3 >>> 0 < i4 >>> 0)) {
+      _abort();
+     }
+     i5 = HEAP32[i3 + 24 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     do {
+      if ((i7 | 0) == (i3 | 0)) {
+       i8 = i3 + 20 | 0;
+       i7 = HEAP32[i8 >> 2] | 0;
+       if ((i7 | 0) == 0) {
+        i8 = i3 + 16 | 0;
+        i7 = HEAP32[i8 >> 2] | 0;
+        if ((i7 | 0) == 0) {
+         i26 = 0;
+         break;
+        }
+       }
+       while (1) {
+        i10 = i7 + 20 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) != 0) {
+         i7 = i9;
+         i8 = i10;
+         continue;
+        }
+        i10 = i7 + 16 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) == 0) {
+         break;
+        } else {
+         i7 = i9;
+         i8 = i10;
+        }
+       }
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i8 >> 2] = 0;
+        i26 = i7;
+        break;
+       }
+      } else {
+       i8 = HEAP32[i3 + 8 >> 2] | 0;
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       }
+       i6 = i8 + 12 | 0;
+       if ((HEAP32[i6 >> 2] | 0) != (i3 | 0)) {
+        _abort();
+       }
+       i9 = i7 + 8 | 0;
+       if ((HEAP32[i9 >> 2] | 0) == (i3 | 0)) {
+        HEAP32[i6 >> 2] = i7;
+        HEAP32[i9 >> 2] = i8;
+        i26 = i7;
+        break;
+       } else {
+        _abort();
+       }
+      }
+     } while (0);
+     do {
+      if ((i5 | 0) != 0) {
+       i7 = HEAP32[i3 + 28 >> 2] | 0;
+       i6 = 888 + (i7 << 2) | 0;
+       if ((i3 | 0) == (HEAP32[i6 >> 2] | 0)) {
+        HEAP32[i6 >> 2] = i26;
+        if ((i26 | 0) == 0) {
+         HEAP32[588 >> 2] = HEAP32[588 >> 2] & ~(1 << i7);
+         break;
+        }
+       } else {
+        if (i5 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        i6 = i5 + 16 | 0;
+        if ((HEAP32[i6 >> 2] | 0) == (i3 | 0)) {
+         HEAP32[i6 >> 2] = i26;
+        } else {
+         HEAP32[i5 + 20 >> 2] = i26;
+        }
+        if ((i26 | 0) == 0) {
+         break;
+        }
+       }
+       if (i26 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       HEAP32[i26 + 24 >> 2] = i5;
+       i5 = HEAP32[i3 + 16 >> 2] | 0;
+       do {
+        if ((i5 | 0) != 0) {
+         if (i5 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i26 + 16 >> 2] = i5;
+          HEAP32[i5 + 24 >> 2] = i26;
+          break;
+         }
+        }
+       } while (0);
+       i5 = HEAP32[i3 + 20 >> 2] | 0;
+       if ((i5 | 0) != 0) {
+        if (i5 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i26 + 20 >> 2] = i5;
+         HEAP32[i5 + 24 >> 2] = i26;
+         break;
+        }
+       }
+      }
+     } while (0);
+     if (i2 >>> 0 < 16) {
+      i32 = i2 + i12 | 0;
+      HEAP32[i3 + 4 >> 2] = i32 | 3;
+      i32 = i3 + (i32 + 4) | 0;
+      HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+     } else {
+      HEAP32[i3 + 4 >> 2] = i12 | 3;
+      HEAP32[i3 + (i12 | 4) >> 2] = i2 | 1;
+      HEAP32[i3 + (i2 + i12) >> 2] = i2;
+      i6 = HEAP32[592 >> 2] | 0;
+      if ((i6 | 0) != 0) {
+       i5 = HEAP32[604 >> 2] | 0;
+       i8 = i6 >>> 3;
+       i9 = i8 << 1;
+       i6 = 624 + (i9 << 2) | 0;
+       i7 = HEAP32[146] | 0;
+       i8 = 1 << i8;
+       if ((i7 & i8 | 0) != 0) {
+        i7 = 624 + (i9 + 2 << 2) | 0;
+        i8 = HEAP32[i7 >> 2] | 0;
+        if (i8 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         i25 = i7;
+         i24 = i8;
+        }
+       } else {
+        HEAP32[146] = i7 | i8;
+        i25 = 624 + (i9 + 2 << 2) | 0;
+        i24 = i6;
+       }
+       HEAP32[i25 >> 2] = i5;
+       HEAP32[i24 + 12 >> 2] = i5;
+       HEAP32[i5 + 8 >> 2] = i24;
+       HEAP32[i5 + 12 >> 2] = i6;
+      }
+      HEAP32[592 >> 2] = i2;
+      HEAP32[604 >> 2] = i4;
+     }
+     i32 = i3 + 8 | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+   }
+  } else {
+   if (!(i12 >>> 0 > 4294967231)) {
+    i24 = i12 + 11 | 0;
+    i12 = i24 & -8;
+    i26 = HEAP32[588 >> 2] | 0;
+    if ((i26 | 0) != 0) {
+     i25 = 0 - i12 | 0;
+     i24 = i24 >>> 8;
+     if ((i24 | 0) != 0) {
+      if (i12 >>> 0 > 16777215) {
+       i27 = 31;
+      } else {
+       i31 = (i24 + 1048320 | 0) >>> 16 & 8;
+       i32 = i24 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i27 = (i32 + 245760 | 0) >>> 16 & 2;
+       i27 = 14 - (i30 | i31 | i27) + (i32 << i27 >>> 15) | 0;
+       i27 = i12 >>> (i27 + 7 | 0) & 1 | i27 << 1;
+      }
+     } else {
+      i27 = 0;
+     }
+     i30 = HEAP32[888 + (i27 << 2) >> 2] | 0;
+     L126 : do {
+      if ((i30 | 0) == 0) {
+       i29 = 0;
+       i24 = 0;
+      } else {
+       if ((i27 | 0) == 31) {
+        i24 = 0;
+       } else {
+        i24 = 25 - (i27 >>> 1) | 0;
+       }
+       i29 = 0;
+       i28 = i12 << i24;
+       i24 = 0;
+       while (1) {
+        i32 = HEAP32[i30 + 4 >> 2] & -8;
+        i31 = i32 - i12 | 0;
+        if (i31 >>> 0 < i25 >>> 0) {
+         if ((i32 | 0) == (i12 | 0)) {
+          i25 = i31;
+          i29 = i30;
+          i24 = i30;
+          break L126;
+         } else {
+          i25 = i31;
+          i24 = i30;
+         }
+        }
+        i31 = HEAP32[i30 + 20 >> 2] | 0;
+        i30 = HEAP32[i30 + (i28 >>> 31 << 2) + 16 >> 2] | 0;
+        i29 = (i31 | 0) == 0 | (i31 | 0) == (i30 | 0) ? i29 : i31;
+        if ((i30 | 0) == 0) {
+         break;
+        } else {
+         i28 = i28 << 1;
+        }
+       }
+      }
+     } while (0);
+     if ((i29 | 0) == 0 & (i24 | 0) == 0) {
+      i32 = 2 << i27;
+      i26 = i26 & (i32 | 0 - i32);
+      if ((i26 | 0) == 0) {
+       break;
+      }
+      i32 = (i26 & 0 - i26) + -1 | 0;
+      i28 = i32 >>> 12 & 16;
+      i32 = i32 >>> i28;
+      i27 = i32 >>> 5 & 8;
+      i32 = i32 >>> i27;
+      i30 = i32 >>> 2 & 4;
+      i32 = i32 >>> i30;
+      i31 = i32 >>> 1 & 2;
+      i32 = i32 >>> i31;
+      i29 = i32 >>> 1 & 1;
+      i29 = HEAP32[888 + ((i27 | i28 | i30 | i31 | i29) + (i32 >>> i29) << 2) >> 2] | 0;
+     }
+     if ((i29 | 0) != 0) {
+      while (1) {
+       i27 = (HEAP32[i29 + 4 >> 2] & -8) - i12 | 0;
+       i26 = i27 >>> 0 < i25 >>> 0;
+       i25 = i26 ? i27 : i25;
+       i24 = i26 ? i29 : i24;
+       i26 = HEAP32[i29 + 16 >> 2] | 0;
+       if ((i26 | 0) != 0) {
+        i29 = i26;
+        continue;
+       }
+       i29 = HEAP32[i29 + 20 >> 2] | 0;
+       if ((i29 | 0) == 0) {
+        break;
+       }
+      }
+     }
+     if ((i24 | 0) != 0 ? i25 >>> 0 < ((HEAP32[592 >> 2] | 0) - i12 | 0) >>> 0 : 0) {
+      i4 = HEAP32[600 >> 2] | 0;
+      if (i24 >>> 0 < i4 >>> 0) {
+       _abort();
+      }
+      i2 = i24 + i12 | 0;
+      if (!(i24 >>> 0 < i2 >>> 0)) {
+       _abort();
+      }
+      i3 = HEAP32[i24 + 24 >> 2] | 0;
+      i6 = HEAP32[i24 + 12 >> 2] | 0;
+      do {
+       if ((i6 | 0) == (i24 | 0)) {
+        i6 = i24 + 20 | 0;
+        i5 = HEAP32[i6 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         i6 = i24 + 16 | 0;
+         i5 = HEAP32[i6 >> 2] | 0;
+         if ((i5 | 0) == 0) {
+          i22 = 0;
+          break;
+         }
+        }
+        while (1) {
+         i8 = i5 + 20 | 0;
+         i7 = HEAP32[i8 >> 2] | 0;
+         if ((i7 | 0) != 0) {
+          i5 = i7;
+          i6 = i8;
+          continue;
+         }
+         i7 = i5 + 16 | 0;
+         i8 = HEAP32[i7 >> 2] | 0;
+         if ((i8 | 0) == 0) {
+          break;
+         } else {
+          i5 = i8;
+          i6 = i7;
+         }
+        }
+        if (i6 >>> 0 < i4 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i6 >> 2] = 0;
+         i22 = i5;
+         break;
+        }
+       } else {
+        i5 = HEAP32[i24 + 8 >> 2] | 0;
+        if (i5 >>> 0 < i4 >>> 0) {
+         _abort();
+        }
+        i7 = i5 + 12 | 0;
+        if ((HEAP32[i7 >> 2] | 0) != (i24 | 0)) {
+         _abort();
+        }
+        i4 = i6 + 8 | 0;
+        if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+         HEAP32[i7 >> 2] = i6;
+         HEAP32[i4 >> 2] = i5;
+         i22 = i6;
+         break;
+        } else {
+         _abort();
+        }
+       }
+      } while (0);
+      do {
+       if ((i3 | 0) != 0) {
+        i4 = HEAP32[i24 + 28 >> 2] | 0;
+        i5 = 888 + (i4 << 2) | 0;
+        if ((i24 | 0) == (HEAP32[i5 >> 2] | 0)) {
+         HEAP32[i5 >> 2] = i22;
+         if ((i22 | 0) == 0) {
+          HEAP32[588 >> 2] = HEAP32[588 >> 2] & ~(1 << i4);
+          break;
+         }
+        } else {
+         if (i3 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+          _abort();
+         }
+         i4 = i3 + 16 | 0;
+         if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+          HEAP32[i4 >> 2] = i22;
+         } else {
+          HEAP32[i3 + 20 >> 2] = i22;
+         }
+         if ((i22 | 0) == 0) {
+          break;
+         }
+        }
+        if (i22 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        HEAP32[i22 + 24 >> 2] = i3;
+        i3 = HEAP32[i24 + 16 >> 2] | 0;
+        do {
+         if ((i3 | 0) != 0) {
+          if (i3 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i22 + 16 >> 2] = i3;
+           HEAP32[i3 + 24 >> 2] = i22;
+           break;
+          }
+         }
+        } while (0);
+        i3 = HEAP32[i24 + 20 >> 2] | 0;
+        if ((i3 | 0) != 0) {
+         if (i3 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i22 + 20 >> 2] = i3;
+          HEAP32[i3 + 24 >> 2] = i22;
+          break;
+         }
+        }
+       }
+      } while (0);
+      L204 : do {
+       if (!(i25 >>> 0 < 16)) {
+        HEAP32[i24 + 4 >> 2] = i12 | 3;
+        HEAP32[i24 + (i12 | 4) >> 2] = i25 | 1;
+        HEAP32[i24 + (i25 + i12) >> 2] = i25;
+        i4 = i25 >>> 3;
+        if (i25 >>> 0 < 256) {
+         i6 = i4 << 1;
+         i3 = 624 + (i6 << 2) | 0;
+         i5 = HEAP32[146] | 0;
+         i4 = 1 << i4;
+         if ((i5 & i4 | 0) != 0) {
+          i5 = 624 + (i6 + 2 << 2) | 0;
+          i4 = HEAP32[i5 >> 2] | 0;
+          if (i4 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           i21 = i5;
+           i20 = i4;
+          }
+         } else {
+          HEAP32[146] = i5 | i4;
+          i21 = 624 + (i6 + 2 << 2) | 0;
+          i20 = i3;
+         }
+         HEAP32[i21 >> 2] = i2;
+         HEAP32[i20 + 12 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i20;
+         HEAP32[i24 + (i12 + 12) >> 2] = i3;
+         break;
+        }
+        i3 = i25 >>> 8;
+        if ((i3 | 0) != 0) {
+         if (i25 >>> 0 > 16777215) {
+          i3 = 31;
+         } else {
+          i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+          i32 = i3 << i31;
+          i30 = (i32 + 520192 | 0) >>> 16 & 4;
+          i32 = i32 << i30;
+          i3 = (i32 + 245760 | 0) >>> 16 & 2;
+          i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+          i3 = i25 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+         }
+        } else {
+         i3 = 0;
+        }
+        i6 = 888 + (i3 << 2) | 0;
+        HEAP32[i24 + (i12 + 28) >> 2] = i3;
+        HEAP32[i24 + (i12 + 20) >> 2] = 0;
+        HEAP32[i24 + (i12 + 16) >> 2] = 0;
+        i4 = HEAP32[588 >> 2] | 0;
+        i5 = 1 << i3;
+        if ((i4 & i5 | 0) == 0) {
+         HEAP32[588 >> 2] = i4 | i5;
+         HEAP32[i6 >> 2] = i2;
+         HEAP32[i24 + (i12 + 24) >> 2] = i6;
+         HEAP32[i24 + (i12 + 12) >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i2;
+         break;
+        }
+        i4 = HEAP32[i6 >> 2] | 0;
+        if ((i3 | 0) == 31) {
+         i3 = 0;
+        } else {
+         i3 = 25 - (i3 >>> 1) | 0;
+        }
+        L225 : do {
+         if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i25 | 0)) {
+          i3 = i25 << i3;
+          while (1) {
+           i6 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+           i5 = HEAP32[i6 >> 2] | 0;
+           if ((i5 | 0) == 0) {
+            break;
+           }
+           if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i25 | 0)) {
+            i18 = i5;
+            break L225;
+           } else {
+            i3 = i3 << 1;
+            i4 = i5;
+           }
+          }
+          if (i6 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i6 >> 2] = i2;
+           HEAP32[i24 + (i12 + 24) >> 2] = i4;
+           HEAP32[i24 + (i12 + 12) >> 2] = i2;
+           HEAP32[i24 + (i12 + 8) >> 2] = i2;
+           break L204;
+          }
+         } else {
+          i18 = i4;
+         }
+        } while (0);
+        i4 = i18 + 8 | 0;
+        i3 = HEAP32[i4 >> 2] | 0;
+        i5 = HEAP32[600 >> 2] | 0;
+        if (i18 >>> 0 < i5 >>> 0) {
+         _abort();
+        }
+        if (i3 >>> 0 < i5 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i3 + 12 >> 2] = i2;
+         HEAP32[i4 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i3;
+         HEAP32[i24 + (i12 + 12) >> 2] = i18;
+         HEAP32[i24 + (i12 + 24) >> 2] = 0;
+         break;
+        }
+       } else {
+        i32 = i25 + i12 | 0;
+        HEAP32[i24 + 4 >> 2] = i32 | 3;
+        i32 = i24 + (i32 + 4) | 0;
+        HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+       }
+      } while (0);
+      i32 = i24 + 8 | 0;
+      STACKTOP = i1;
+      return i32 | 0;
+     }
+    }
+   } else {
+    i12 = -1;
+   }
+  }
+ } while (0);
+ i18 = HEAP32[592 >> 2] | 0;
+ if (!(i12 >>> 0 > i18 >>> 0)) {
+  i3 = i18 - i12 | 0;
+  i2 = HEAP32[604 >> 2] | 0;
+  if (i3 >>> 0 > 15) {
+   HEAP32[604 >> 2] = i2 + i12;
+   HEAP32[592 >> 2] = i3;
+   HEAP32[i2 + (i12 + 4) >> 2] = i3 | 1;
+   HEAP32[i2 + i18 >> 2] = i3;
+   HEAP32[i2 + 4 >> 2] = i12 | 3;
+  } else {
+   HEAP32[592 >> 2] = 0;
+   HEAP32[604 >> 2] = 0;
+   HEAP32[i2 + 4 >> 2] = i18 | 3;
+   i32 = i2 + (i18 + 4) | 0;
+   HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+  }
+  i32 = i2 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i18 = HEAP32[596 >> 2] | 0;
+ if (i12 >>> 0 < i18 >>> 0) {
+  i31 = i18 - i12 | 0;
+  HEAP32[596 >> 2] = i31;
+  i32 = HEAP32[608 >> 2] | 0;
+  HEAP32[608 >> 2] = i32 + i12;
+  HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+  HEAP32[i32 + 4 >> 2] = i12 | 3;
+  i32 = i32 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ do {
+  if ((HEAP32[264] | 0) == 0) {
+   i18 = _sysconf(30) | 0;
+   if ((i18 + -1 & i18 | 0) == 0) {
+    HEAP32[1064 >> 2] = i18;
+    HEAP32[1060 >> 2] = i18;
+    HEAP32[1068 >> 2] = -1;
+    HEAP32[1072 >> 2] = -1;
+    HEAP32[1076 >> 2] = 0;
+    HEAP32[1028 >> 2] = 0;
+    HEAP32[264] = (_time(0) | 0) & -16 ^ 1431655768;
+    break;
+   } else {
+    _abort();
+   }
+  }
+ } while (0);
+ i20 = i12 + 48 | 0;
+ i25 = HEAP32[1064 >> 2] | 0;
+ i21 = i12 + 47 | 0;
+ i22 = i25 + i21 | 0;
+ i25 = 0 - i25 | 0;
+ i18 = i22 & i25;
+ if (!(i18 >>> 0 > i12 >>> 0)) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i24 = HEAP32[1024 >> 2] | 0;
+ if ((i24 | 0) != 0 ? (i31 = HEAP32[1016 >> 2] | 0, i32 = i31 + i18 | 0, i32 >>> 0 <= i31 >>> 0 | i32 >>> 0 > i24 >>> 0) : 0) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ L269 : do {
+  if ((HEAP32[1028 >> 2] & 4 | 0) == 0) {
+   i26 = HEAP32[608 >> 2] | 0;
+   L271 : do {
+    if ((i26 | 0) != 0) {
+     i24 = 1032 | 0;
+     while (1) {
+      i27 = HEAP32[i24 >> 2] | 0;
+      if (!(i27 >>> 0 > i26 >>> 0) ? (i23 = i24 + 4 | 0, (i27 + (HEAP32[i23 >> 2] | 0) | 0) >>> 0 > i26 >>> 0) : 0) {
+       break;
+      }
+      i24 = HEAP32[i24 + 8 >> 2] | 0;
+      if ((i24 | 0) == 0) {
+       i13 = 182;
+       break L271;
+      }
+     }
+     if ((i24 | 0) != 0) {
+      i25 = i22 - (HEAP32[596 >> 2] | 0) & i25;
+      if (i25 >>> 0 < 2147483647) {
+       i13 = _sbrk(i25 | 0) | 0;
+       i26 = (i13 | 0) == ((HEAP32[i24 >> 2] | 0) + (HEAP32[i23 >> 2] | 0) | 0);
+       i22 = i13;
+       i24 = i25;
+       i23 = i26 ? i13 : -1;
+       i25 = i26 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i13 = 182;
+     }
+    } else {
+     i13 = 182;
+    }
+   } while (0);
+   do {
+    if ((i13 | 0) == 182) {
+     i23 = _sbrk(0) | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i24 = i23;
+      i22 = HEAP32[1060 >> 2] | 0;
+      i25 = i22 + -1 | 0;
+      if ((i25 & i24 | 0) == 0) {
+       i25 = i18;
+      } else {
+       i25 = i18 - i24 + (i25 + i24 & 0 - i22) | 0;
+      }
+      i24 = HEAP32[1016 >> 2] | 0;
+      i26 = i24 + i25 | 0;
+      if (i25 >>> 0 > i12 >>> 0 & i25 >>> 0 < 2147483647) {
+       i22 = HEAP32[1024 >> 2] | 0;
+       if ((i22 | 0) != 0 ? i26 >>> 0 <= i24 >>> 0 | i26 >>> 0 > i22 >>> 0 : 0) {
+        i25 = 0;
+        break;
+       }
+       i22 = _sbrk(i25 | 0) | 0;
+       i13 = (i22 | 0) == (i23 | 0);
+       i24 = i25;
+       i23 = i13 ? i23 : -1;
+       i25 = i13 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i25 = 0;
+     }
+    }
+   } while (0);
+   L291 : do {
+    if ((i13 | 0) == 191) {
+     i13 = 0 - i24 | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i17 = i23;
+      i14 = i25;
+      i13 = 202;
+      break L269;
+     }
+     do {
+      if ((i22 | 0) != (-1 | 0) & i24 >>> 0 < 2147483647 & i24 >>> 0 < i20 >>> 0 ? (i19 = HEAP32[1064 >> 2] | 0, i19 = i21 - i24 + i19 & 0 - i19, i19 >>> 0 < 2147483647) : 0) {
+       if ((_sbrk(i19 | 0) | 0) == (-1 | 0)) {
+        _sbrk(i13 | 0) | 0;
+        break L291;
+       } else {
+        i24 = i19 + i24 | 0;
+        break;
+       }
+      }
+     } while (0);
+     if ((i22 | 0) != (-1 | 0)) {
+      i17 = i22;
+      i14 = i24;
+      i13 = 202;
+      break L269;
+     }
+    }
+   } while (0);
+   HEAP32[1028 >> 2] = HEAP32[1028 >> 2] | 4;
+   i13 = 199;
+  } else {
+   i25 = 0;
+   i13 = 199;
+  }
+ } while (0);
+ if ((((i13 | 0) == 199 ? i18 >>> 0 < 2147483647 : 0) ? (i17 = _sbrk(i18 | 0) | 0, i16 = _sbrk(0) | 0, (i16 | 0) != (-1 | 0) & (i17 | 0) != (-1 | 0) & i17 >>> 0 < i16 >>> 0) : 0) ? (i15 = i16 - i17 | 0, i14 = i15 >>> 0 > (i12 + 40 | 0) >>> 0, i14) : 0) {
+  i14 = i14 ? i15 : i25;
+  i13 = 202;
+ }
+ if ((i13 | 0) == 202) {
+  i15 = (HEAP32[1016 >> 2] | 0) + i14 | 0;
+  HEAP32[1016 >> 2] = i15;
+  if (i15 >>> 0 > (HEAP32[1020 >> 2] | 0) >>> 0) {
+   HEAP32[1020 >> 2] = i15;
+  }
+  i15 = HEAP32[608 >> 2] | 0;
+  L311 : do {
+   if ((i15 | 0) != 0) {
+    i21 = 1032 | 0;
+    while (1) {
+     i16 = HEAP32[i21 >> 2] | 0;
+     i19 = i21 + 4 | 0;
+     i20 = HEAP32[i19 >> 2] | 0;
+     if ((i17 | 0) == (i16 + i20 | 0)) {
+      i13 = 214;
+      break;
+     }
+     i18 = HEAP32[i21 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i21 = i18;
+     }
+    }
+    if (((i13 | 0) == 214 ? (HEAP32[i21 + 12 >> 2] & 8 | 0) == 0 : 0) ? i15 >>> 0 >= i16 >>> 0 & i15 >>> 0 < i17 >>> 0 : 0) {
+     HEAP32[i19 >> 2] = i20 + i14;
+     i2 = (HEAP32[596 >> 2] | 0) + i14 | 0;
+     i3 = i15 + 8 | 0;
+     if ((i3 & 7 | 0) == 0) {
+      i3 = 0;
+     } else {
+      i3 = 0 - i3 & 7;
+     }
+     i32 = i2 - i3 | 0;
+     HEAP32[608 >> 2] = i15 + i3;
+     HEAP32[596 >> 2] = i32;
+     HEAP32[i15 + (i3 + 4) >> 2] = i32 | 1;
+     HEAP32[i15 + (i2 + 4) >> 2] = 40;
+     HEAP32[612 >> 2] = HEAP32[1072 >> 2];
+     break;
+    }
+    if (i17 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+     HEAP32[600 >> 2] = i17;
+    }
+    i19 = i17 + i14 | 0;
+    i16 = 1032 | 0;
+    while (1) {
+     if ((HEAP32[i16 >> 2] | 0) == (i19 | 0)) {
+      i13 = 224;
+      break;
+     }
+     i18 = HEAP32[i16 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i16 = i18;
+     }
+    }
+    if ((i13 | 0) == 224 ? (HEAP32[i16 + 12 >> 2] & 8 | 0) == 0 : 0) {
+     HEAP32[i16 >> 2] = i17;
+     i6 = i16 + 4 | 0;
+     HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i14;
+     i6 = i17 + 8 | 0;
+     if ((i6 & 7 | 0) == 0) {
+      i6 = 0;
+     } else {
+      i6 = 0 - i6 & 7;
+     }
+     i7 = i17 + (i14 + 8) | 0;
+     if ((i7 & 7 | 0) == 0) {
+      i13 = 0;
+     } else {
+      i13 = 0 - i7 & 7;
+     }
+     i15 = i17 + (i13 + i14) | 0;
+     i8 = i6 + i12 | 0;
+     i7 = i17 + i8 | 0;
+     i10 = i15 - (i17 + i6) - i12 | 0;
+     HEAP32[i17 + (i6 + 4) >> 2] = i12 | 3;
+     L348 : do {
+      if ((i15 | 0) != (HEAP32[608 >> 2] | 0)) {
+       if ((i15 | 0) == (HEAP32[604 >> 2] | 0)) {
+        i32 = (HEAP32[592 >> 2] | 0) + i10 | 0;
+        HEAP32[592 >> 2] = i32;
+        HEAP32[604 >> 2] = i7;
+        HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+        HEAP32[i17 + (i32 + i8) >> 2] = i32;
+        break;
+       }
+       i12 = i14 + 4 | 0;
+       i18 = HEAP32[i17 + (i12 + i13) >> 2] | 0;
+       if ((i18 & 3 | 0) == 1) {
+        i11 = i18 & -8;
+        i16 = i18 >>> 3;
+        do {
+         if (!(i18 >>> 0 < 256)) {
+          i9 = HEAP32[i17 + ((i13 | 24) + i14) >> 2] | 0;
+          i19 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          do {
+           if ((i19 | 0) == (i15 | 0)) {
+            i19 = i13 | 16;
+            i18 = i17 + (i12 + i19) | 0;
+            i16 = HEAP32[i18 >> 2] | 0;
+            if ((i16 | 0) == 0) {
+             i18 = i17 + (i19 + i14) | 0;
+             i16 = HEAP32[i18 >> 2] | 0;
+             if ((i16 | 0) == 0) {
+              i5 = 0;
+              break;
+             }
+            }
+            while (1) {
+             i20 = i16 + 20 | 0;
+             i19 = HEAP32[i20 >> 2] | 0;
+             if ((i19 | 0) != 0) {
+              i16 = i19;
+              i18 = i20;
+              continue;
+             }
+             i19 = i16 + 16 | 0;
+             i20 = HEAP32[i19 >> 2] | 0;
+             if ((i20 | 0) == 0) {
+              break;
+             } else {
+              i16 = i20;
+              i18 = i19;
+             }
+            }
+            if (i18 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i18 >> 2] = 0;
+             i5 = i16;
+             break;
+            }
+           } else {
+            i18 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+            if (i18 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i18 + 12 | 0;
+            if ((HEAP32[i16 >> 2] | 0) != (i15 | 0)) {
+             _abort();
+            }
+            i20 = i19 + 8 | 0;
+            if ((HEAP32[i20 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i19;
+             HEAP32[i20 >> 2] = i18;
+             i5 = i19;
+             break;
+            } else {
+             _abort();
+            }
+           }
+          } while (0);
+          if ((i9 | 0) != 0) {
+           i16 = HEAP32[i17 + (i14 + 28 + i13) >> 2] | 0;
+           i18 = 888 + (i16 << 2) | 0;
+           if ((i15 | 0) == (HEAP32[i18 >> 2] | 0)) {
+            HEAP32[i18 >> 2] = i5;
+            if ((i5 | 0) == 0) {
+             HEAP32[588 >> 2] = HEAP32[588 >> 2] & ~(1 << i16);
+             break;
+            }
+           } else {
+            if (i9 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i9 + 16 | 0;
+            if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i5;
+            } else {
+             HEAP32[i9 + 20 >> 2] = i5;
+            }
+            if ((i5 | 0) == 0) {
+             break;
+            }
+           }
+           if (i5 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           HEAP32[i5 + 24 >> 2] = i9;
+           i15 = i13 | 16;
+           i9 = HEAP32[i17 + (i15 + i14) >> 2] | 0;
+           do {
+            if ((i9 | 0) != 0) {
+             if (i9 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+              _abort();
+             } else {
+              HEAP32[i5 + 16 >> 2] = i9;
+              HEAP32[i9 + 24 >> 2] = i5;
+              break;
+             }
+            }
+           } while (0);
+           i9 = HEAP32[i17 + (i12 + i15) >> 2] | 0;
+           if ((i9 | 0) != 0) {
+            if (i9 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i5 + 20 >> 2] = i9;
+             HEAP32[i9 + 24 >> 2] = i5;
+             break;
+            }
+           }
+          }
+         } else {
+          i5 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+          i12 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          i18 = 624 + (i16 << 1 << 2) | 0;
+          if ((i5 | 0) != (i18 | 0)) {
+           if (i5 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           if ((HEAP32[i5 + 12 >> 2] | 0) != (i15 | 0)) {
+            _abort();
+           }
+          }
+          if ((i12 | 0) == (i5 | 0)) {
+           HEAP32[146] = HEAP32[146] & ~(1 << i16);
+           break;
+          }
+          if ((i12 | 0) != (i18 | 0)) {
+           if (i12 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           i16 = i12 + 8 | 0;
+           if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+            i9 = i16;
+           } else {
+            _abort();
+           }
+          } else {
+           i9 = i12 + 8 | 0;
+          }
+          HEAP32[i5 + 12 >> 2] = i12;
+          HEAP32[i9 >> 2] = i5;
+         }
+        } while (0);
+        i15 = i17 + ((i11 | i13) + i14) | 0;
+        i10 = i11 + i10 | 0;
+       }
+       i5 = i15 + 4 | 0;
+       HEAP32[i5 >> 2] = HEAP32[i5 >> 2] & -2;
+       HEAP32[i17 + (i8 + 4) >> 2] = i10 | 1;
+       HEAP32[i17 + (i10 + i8) >> 2] = i10;
+       i5 = i10 >>> 3;
+       if (i10 >>> 0 < 256) {
+        i10 = i5 << 1;
+        i2 = 624 + (i10 << 2) | 0;
+        i9 = HEAP32[146] | 0;
+        i5 = 1 << i5;
+        if ((i9 & i5 | 0) != 0) {
+         i9 = 624 + (i10 + 2 << 2) | 0;
+         i5 = HEAP32[i9 >> 2] | 0;
+         if (i5 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          i3 = i9;
+          i4 = i5;
+         }
+        } else {
+         HEAP32[146] = i9 | i5;
+         i3 = 624 + (i10 + 2 << 2) | 0;
+         i4 = i2;
+        }
+        HEAP32[i3 >> 2] = i7;
+        HEAP32[i4 + 12 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        break;
+       }
+       i3 = i10 >>> 8;
+       if ((i3 | 0) != 0) {
+        if (i10 >>> 0 > 16777215) {
+         i3 = 31;
+        } else {
+         i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+         i32 = i3 << i31;
+         i30 = (i32 + 520192 | 0) >>> 16 & 4;
+         i32 = i32 << i30;
+         i3 = (i32 + 245760 | 0) >>> 16 & 2;
+         i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+         i3 = i10 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+        }
+       } else {
+        i3 = 0;
+       }
+       i4 = 888 + (i3 << 2) | 0;
+       HEAP32[i17 + (i8 + 28) >> 2] = i3;
+       HEAP32[i17 + (i8 + 20) >> 2] = 0;
+       HEAP32[i17 + (i8 + 16) >> 2] = 0;
+       i9 = HEAP32[588 >> 2] | 0;
+       i5 = 1 << i3;
+       if ((i9 & i5 | 0) == 0) {
+        HEAP32[588 >> 2] = i9 | i5;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 24) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i7;
+        break;
+       }
+       i4 = HEAP32[i4 >> 2] | 0;
+       if ((i3 | 0) == 31) {
+        i3 = 0;
+       } else {
+        i3 = 25 - (i3 >>> 1) | 0;
+       }
+       L444 : do {
+        if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i10 | 0)) {
+         i3 = i10 << i3;
+         while (1) {
+          i5 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+          i9 = HEAP32[i5 >> 2] | 0;
+          if ((i9 | 0) == 0) {
+           break;
+          }
+          if ((HEAP32[i9 + 4 >> 2] & -8 | 0) == (i10 | 0)) {
+           i2 = i9;
+           break L444;
+          } else {
+           i3 = i3 << 1;
+           i4 = i9;
+          }
+         }
+         if (i5 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i5 >> 2] = i7;
+          HEAP32[i17 + (i8 + 24) >> 2] = i4;
+          HEAP32[i17 + (i8 + 12) >> 2] = i7;
+          HEAP32[i17 + (i8 + 8) >> 2] = i7;
+          break L348;
+         }
+        } else {
+         i2 = i4;
+        }
+       } while (0);
+       i4 = i2 + 8 | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       i5 = HEAP32[600 >> 2] | 0;
+       if (i2 >>> 0 < i5 >>> 0) {
+        _abort();
+       }
+       if (i3 >>> 0 < i5 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i3 + 12 >> 2] = i7;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i3;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        HEAP32[i17 + (i8 + 24) >> 2] = 0;
+        break;
+       }
+      } else {
+       i32 = (HEAP32[596 >> 2] | 0) + i10 | 0;
+       HEAP32[596 >> 2] = i32;
+       HEAP32[608 >> 2] = i7;
+       HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+      }
+     } while (0);
+     i32 = i17 + (i6 | 8) | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i3 = 1032 | 0;
+    while (1) {
+     i2 = HEAP32[i3 >> 2] | 0;
+     if (!(i2 >>> 0 > i15 >>> 0) ? (i11 = HEAP32[i3 + 4 >> 2] | 0, i10 = i2 + i11 | 0, i10 >>> 0 > i15 >>> 0) : 0) {
+      break;
+     }
+     i3 = HEAP32[i3 + 8 >> 2] | 0;
+    }
+    i3 = i2 + (i11 + -39) | 0;
+    if ((i3 & 7 | 0) == 0) {
+     i3 = 0;
+    } else {
+     i3 = 0 - i3 & 7;
+    }
+    i2 = i2 + (i11 + -47 + i3) | 0;
+    i2 = i2 >>> 0 < (i15 + 16 | 0) >>> 0 ? i15 : i2;
+    i3 = i2 + 8 | 0;
+    i4 = i17 + 8 | 0;
+    if ((i4 & 7 | 0) == 0) {
+     i4 = 0;
+    } else {
+     i4 = 0 - i4 & 7;
+    }
+    i32 = i14 + -40 - i4 | 0;
+    HEAP32[608 >> 2] = i17 + i4;
+    HEAP32[596 >> 2] = i32;
+    HEAP32[i17 + (i4 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[612 >> 2] = HEAP32[1072 >> 2];
+    HEAP32[i2 + 4 >> 2] = 27;
+    HEAP32[i3 + 0 >> 2] = HEAP32[1032 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[1036 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[1040 >> 2];
+    HEAP32[i3 + 12 >> 2] = HEAP32[1044 >> 2];
+    HEAP32[1032 >> 2] = i17;
+    HEAP32[1036 >> 2] = i14;
+    HEAP32[1044 >> 2] = 0;
+    HEAP32[1040 >> 2] = i3;
+    i4 = i2 + 28 | 0;
+    HEAP32[i4 >> 2] = 7;
+    if ((i2 + 32 | 0) >>> 0 < i10 >>> 0) {
+     while (1) {
+      i3 = i4 + 4 | 0;
+      HEAP32[i3 >> 2] = 7;
+      if ((i4 + 8 | 0) >>> 0 < i10 >>> 0) {
+       i4 = i3;
+      } else {
+       break;
+      }
+     }
+    }
+    if ((i2 | 0) != (i15 | 0)) {
+     i2 = i2 - i15 | 0;
+     i3 = i15 + (i2 + 4) | 0;
+     HEAP32[i3 >> 2] = HEAP32[i3 >> 2] & -2;
+     HEAP32[i15 + 4 >> 2] = i2 | 1;
+     HEAP32[i15 + i2 >> 2] = i2;
+     i3 = i2 >>> 3;
+     if (i2 >>> 0 < 256) {
+      i4 = i3 << 1;
+      i2 = 624 + (i4 << 2) | 0;
+      i5 = HEAP32[146] | 0;
+      i3 = 1 << i3;
+      if ((i5 & i3 | 0) != 0) {
+       i4 = 624 + (i4 + 2 << 2) | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       if (i3 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i7 = i4;
+        i8 = i3;
+       }
+      } else {
+       HEAP32[146] = i5 | i3;
+       i7 = 624 + (i4 + 2 << 2) | 0;
+       i8 = i2;
+      }
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i8 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i8;
+      HEAP32[i15 + 12 >> 2] = i2;
+      break;
+     }
+     i3 = i2 >>> 8;
+     if ((i3 | 0) != 0) {
+      if (i2 >>> 0 > 16777215) {
+       i3 = 31;
+      } else {
+       i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+       i32 = i3 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i3 = (i32 + 245760 | 0) >>> 16 & 2;
+       i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+       i3 = i2 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+      }
+     } else {
+      i3 = 0;
+     }
+     i7 = 888 + (i3 << 2) | 0;
+     HEAP32[i15 + 28 >> 2] = i3;
+     HEAP32[i15 + 20 >> 2] = 0;
+     HEAP32[i15 + 16 >> 2] = 0;
+     i4 = HEAP32[588 >> 2] | 0;
+     i5 = 1 << i3;
+     if ((i4 & i5 | 0) == 0) {
+      HEAP32[588 >> 2] = i4 | i5;
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i7;
+      HEAP32[i15 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i15;
+      break;
+     }
+     i4 = HEAP32[i7 >> 2] | 0;
+     if ((i3 | 0) == 31) {
+      i3 = 0;
+     } else {
+      i3 = 25 - (i3 >>> 1) | 0;
+     }
+     L499 : do {
+      if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i2 | 0)) {
+       i3 = i2 << i3;
+       while (1) {
+        i7 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+        i5 = HEAP32[i7 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         break;
+        }
+        if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i2 | 0)) {
+         i6 = i5;
+         break L499;
+        } else {
+         i3 = i3 << 1;
+         i4 = i5;
+        }
+       }
+       if (i7 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i7 >> 2] = i15;
+        HEAP32[i15 + 24 >> 2] = i4;
+        HEAP32[i15 + 12 >> 2] = i15;
+        HEAP32[i15 + 8 >> 2] = i15;
+        break L311;
+       }
+      } else {
+       i6 = i4;
+      }
+     } while (0);
+     i4 = i6 + 8 | 0;
+     i3 = HEAP32[i4 >> 2] | 0;
+     i2 = HEAP32[600 >> 2] | 0;
+     if (i6 >>> 0 < i2 >>> 0) {
+      _abort();
+     }
+     if (i3 >>> 0 < i2 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i3 + 12 >> 2] = i15;
+      HEAP32[i4 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i3;
+      HEAP32[i15 + 12 >> 2] = i6;
+      HEAP32[i15 + 24 >> 2] = 0;
+      break;
+     }
+    }
+   } else {
+    i32 = HEAP32[600 >> 2] | 0;
+    if ((i32 | 0) == 0 | i17 >>> 0 < i32 >>> 0) {
+     HEAP32[600 >> 2] = i17;
+    }
+    HEAP32[1032 >> 2] = i17;
+    HEAP32[1036 >> 2] = i14;
+    HEAP32[1044 >> 2] = 0;
+    HEAP32[620 >> 2] = HEAP32[264];
+    HEAP32[616 >> 2] = -1;
+    i2 = 0;
+    do {
+     i32 = i2 << 1;
+     i31 = 624 + (i32 << 2) | 0;
+     HEAP32[624 + (i32 + 3 << 2) >> 2] = i31;
+     HEAP32[624 + (i32 + 2 << 2) >> 2] = i31;
+     i2 = i2 + 1 | 0;
+    } while ((i2 | 0) != 32);
+    i2 = i17 + 8 | 0;
+    if ((i2 & 7 | 0) == 0) {
+     i2 = 0;
+    } else {
+     i2 = 0 - i2 & 7;
+    }
+    i32 = i14 + -40 - i2 | 0;
+    HEAP32[608 >> 2] = i17 + i2;
+    HEAP32[596 >> 2] = i32;
+    HEAP32[i17 + (i2 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[612 >> 2] = HEAP32[1072 >> 2];
+   }
+  } while (0);
+  i2 = HEAP32[596 >> 2] | 0;
+  if (i2 >>> 0 > i12 >>> 0) {
+   i31 = i2 - i12 | 0;
+   HEAP32[596 >> 2] = i31;
+   i32 = HEAP32[608 >> 2] | 0;
+   HEAP32[608 >> 2] = i32 + i12;
+   HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+   HEAP32[i32 + 4 >> 2] = i12 | 3;
+   i32 = i32 + 8 | 0;
+   STACKTOP = i1;
+   return i32 | 0;
+  }
+ }
+ HEAP32[(___errno_location() | 0) >> 2] = 12;
+ i32 = 0;
+ STACKTOP = i1;
+ return i32 | 0;
+}
+function _free(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i1 = STACKTOP;
+ if ((i7 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i15 = i7 + -8 | 0;
+ i16 = HEAP32[600 >> 2] | 0;
+ if (i15 >>> 0 < i16 >>> 0) {
+  _abort();
+ }
+ i13 = HEAP32[i7 + -4 >> 2] | 0;
+ i12 = i13 & 3;
+ if ((i12 | 0) == 1) {
+  _abort();
+ }
+ i8 = i13 & -8;
+ i6 = i7 + (i8 + -8) | 0;
+ do {
+  if ((i13 & 1 | 0) == 0) {
+   i19 = HEAP32[i15 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   i15 = -8 - i19 | 0;
+   i13 = i7 + i15 | 0;
+   i12 = i19 + i8 | 0;
+   if (i13 >>> 0 < i16 >>> 0) {
+    _abort();
+   }
+   if ((i13 | 0) == (HEAP32[604 >> 2] | 0)) {
+    i2 = i7 + (i8 + -4) | 0;
+    if ((HEAP32[i2 >> 2] & 3 | 0) != 3) {
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    HEAP32[592 >> 2] = i12;
+    HEAP32[i2 >> 2] = HEAP32[i2 >> 2] & -2;
+    HEAP32[i7 + (i15 + 4) >> 2] = i12 | 1;
+    HEAP32[i6 >> 2] = i12;
+    STACKTOP = i1;
+    return;
+   }
+   i18 = i19 >>> 3;
+   if (i19 >>> 0 < 256) {
+    i2 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+    i11 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+    i14 = 624 + (i18 << 1 << 2) | 0;
+    if ((i2 | 0) != (i14 | 0)) {
+     if (i2 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i2 + 12 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+    }
+    if ((i11 | 0) == (i2 | 0)) {
+     HEAP32[146] = HEAP32[146] & ~(1 << i18);
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    if ((i11 | 0) != (i14 | 0)) {
+     if (i11 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i14 = i11 + 8 | 0;
+     if ((HEAP32[i14 >> 2] | 0) == (i13 | 0)) {
+      i17 = i14;
+     } else {
+      _abort();
+     }
+    } else {
+     i17 = i11 + 8 | 0;
+    }
+    HEAP32[i2 + 12 >> 2] = i11;
+    HEAP32[i17 >> 2] = i2;
+    i2 = i13;
+    i11 = i12;
+    break;
+   }
+   i17 = HEAP32[i7 + (i15 + 24) >> 2] | 0;
+   i18 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+   do {
+    if ((i18 | 0) == (i13 | 0)) {
+     i19 = i7 + (i15 + 20) | 0;
+     i18 = HEAP32[i19 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      i19 = i7 + (i15 + 16) | 0;
+      i18 = HEAP32[i19 >> 2] | 0;
+      if ((i18 | 0) == 0) {
+       i14 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i21 = i18 + 20 | 0;
+      i20 = HEAP32[i21 >> 2] | 0;
+      if ((i20 | 0) != 0) {
+       i18 = i20;
+       i19 = i21;
+       continue;
+      }
+      i20 = i18 + 16 | 0;
+      i21 = HEAP32[i20 >> 2] | 0;
+      if ((i21 | 0) == 0) {
+       break;
+      } else {
+       i18 = i21;
+       i19 = i20;
+      }
+     }
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i19 >> 2] = 0;
+      i14 = i18;
+      break;
+     }
+    } else {
+     i19 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i16 = i19 + 12 | 0;
+     if ((HEAP32[i16 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+     i20 = i18 + 8 | 0;
+     if ((HEAP32[i20 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i18;
+      HEAP32[i20 >> 2] = i19;
+      i14 = i18;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i17 | 0) != 0) {
+    i18 = HEAP32[i7 + (i15 + 28) >> 2] | 0;
+    i16 = 888 + (i18 << 2) | 0;
+    if ((i13 | 0) == (HEAP32[i16 >> 2] | 0)) {
+     HEAP32[i16 >> 2] = i14;
+     if ((i14 | 0) == 0) {
+      HEAP32[588 >> 2] = HEAP32[588 >> 2] & ~(1 << i18);
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     if (i17 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i16 = i17 + 16 | 0;
+     if ((HEAP32[i16 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i14;
+     } else {
+      HEAP32[i17 + 20 >> 2] = i14;
+     }
+     if ((i14 | 0) == 0) {
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    }
+    if (i14 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i14 + 24 >> 2] = i17;
+    i16 = HEAP32[i7 + (i15 + 16) >> 2] | 0;
+    do {
+     if ((i16 | 0) != 0) {
+      if (i16 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i14 + 16 >> 2] = i16;
+       HEAP32[i16 + 24 >> 2] = i14;
+       break;
+      }
+     }
+    } while (0);
+    i15 = HEAP32[i7 + (i15 + 20) >> 2] | 0;
+    if ((i15 | 0) != 0) {
+     if (i15 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i14 + 20 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i14;
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     i2 = i13;
+     i11 = i12;
+    }
+   } else {
+    i2 = i13;
+    i11 = i12;
+   }
+  } else {
+   i2 = i15;
+   i11 = i8;
+  }
+ } while (0);
+ if (!(i2 >>> 0 < i6 >>> 0)) {
+  _abort();
+ }
+ i12 = i7 + (i8 + -4) | 0;
+ i13 = HEAP32[i12 >> 2] | 0;
+ if ((i13 & 1 | 0) == 0) {
+  _abort();
+ }
+ if ((i13 & 2 | 0) == 0) {
+  if ((i6 | 0) == (HEAP32[608 >> 2] | 0)) {
+   i21 = (HEAP32[596 >> 2] | 0) + i11 | 0;
+   HEAP32[596 >> 2] = i21;
+   HEAP32[608 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   if ((i2 | 0) != (HEAP32[604 >> 2] | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[604 >> 2] = 0;
+   HEAP32[592 >> 2] = 0;
+   STACKTOP = i1;
+   return;
+  }
+  if ((i6 | 0) == (HEAP32[604 >> 2] | 0)) {
+   i21 = (HEAP32[592 >> 2] | 0) + i11 | 0;
+   HEAP32[592 >> 2] = i21;
+   HEAP32[604 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   HEAP32[i2 + i21 >> 2] = i21;
+   STACKTOP = i1;
+   return;
+  }
+  i11 = (i13 & -8) + i11 | 0;
+  i12 = i13 >>> 3;
+  do {
+   if (!(i13 >>> 0 < 256)) {
+    i10 = HEAP32[i7 + (i8 + 16) >> 2] | 0;
+    i15 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    do {
+     if ((i15 | 0) == (i6 | 0)) {
+      i13 = i7 + (i8 + 12) | 0;
+      i12 = HEAP32[i13 >> 2] | 0;
+      if ((i12 | 0) == 0) {
+       i13 = i7 + (i8 + 8) | 0;
+       i12 = HEAP32[i13 >> 2] | 0;
+       if ((i12 | 0) == 0) {
+        i9 = 0;
+        break;
+       }
+      }
+      while (1) {
+       i14 = i12 + 20 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) != 0) {
+        i12 = i15;
+        i13 = i14;
+        continue;
+       }
+       i14 = i12 + 16 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) == 0) {
+        break;
+       } else {
+        i12 = i15;
+        i13 = i14;
+       }
+      }
+      if (i13 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 >> 2] = 0;
+       i9 = i12;
+       break;
+      }
+     } else {
+      i13 = HEAP32[i7 + i8 >> 2] | 0;
+      if (i13 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i14 = i13 + 12 | 0;
+      if ((HEAP32[i14 >> 2] | 0) != (i6 | 0)) {
+       _abort();
+      }
+      i12 = i15 + 8 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i14 >> 2] = i15;
+       HEAP32[i12 >> 2] = i13;
+       i9 = i15;
+       break;
+      } else {
+       _abort();
+      }
+     }
+    } while (0);
+    if ((i10 | 0) != 0) {
+     i12 = HEAP32[i7 + (i8 + 20) >> 2] | 0;
+     i13 = 888 + (i12 << 2) | 0;
+     if ((i6 | 0) == (HEAP32[i13 >> 2] | 0)) {
+      HEAP32[i13 >> 2] = i9;
+      if ((i9 | 0) == 0) {
+       HEAP32[588 >> 2] = HEAP32[588 >> 2] & ~(1 << i12);
+       break;
+      }
+     } else {
+      if (i10 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i12 = i10 + 16 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i12 >> 2] = i9;
+      } else {
+       HEAP32[i10 + 20 >> 2] = i9;
+      }
+      if ((i9 | 0) == 0) {
+       break;
+      }
+     }
+     if (i9 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     HEAP32[i9 + 24 >> 2] = i10;
+     i6 = HEAP32[i7 + (i8 + 8) >> 2] | 0;
+     do {
+      if ((i6 | 0) != 0) {
+       if (i6 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i9 + 16 >> 2] = i6;
+        HEAP32[i6 + 24 >> 2] = i9;
+        break;
+       }
+      }
+     } while (0);
+     i6 = HEAP32[i7 + (i8 + 12) >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      if (i6 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i9 + 20 >> 2] = i6;
+       HEAP32[i6 + 24 >> 2] = i9;
+       break;
+      }
+     }
+    }
+   } else {
+    i9 = HEAP32[i7 + i8 >> 2] | 0;
+    i7 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    i8 = 624 + (i12 << 1 << 2) | 0;
+    if ((i9 | 0) != (i8 | 0)) {
+     if (i9 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i9 + 12 >> 2] | 0) != (i6 | 0)) {
+      _abort();
+     }
+    }
+    if ((i7 | 0) == (i9 | 0)) {
+     HEAP32[146] = HEAP32[146] & ~(1 << i12);
+     break;
+    }
+    if ((i7 | 0) != (i8 | 0)) {
+     if (i7 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i8 = i7 + 8 | 0;
+     if ((HEAP32[i8 >> 2] | 0) == (i6 | 0)) {
+      i10 = i8;
+     } else {
+      _abort();
+     }
+    } else {
+     i10 = i7 + 8 | 0;
+    }
+    HEAP32[i9 + 12 >> 2] = i7;
+    HEAP32[i10 >> 2] = i9;
+   }
+  } while (0);
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+  if ((i2 | 0) == (HEAP32[604 >> 2] | 0)) {
+   HEAP32[592 >> 2] = i11;
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  HEAP32[i12 >> 2] = i13 & -2;
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+ }
+ i6 = i11 >>> 3;
+ if (i11 >>> 0 < 256) {
+  i7 = i6 << 1;
+  i3 = 624 + (i7 << 2) | 0;
+  i8 = HEAP32[146] | 0;
+  i6 = 1 << i6;
+  if ((i8 & i6 | 0) != 0) {
+   i6 = 624 + (i7 + 2 << 2) | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if (i7 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+    _abort();
+   } else {
+    i4 = i6;
+    i5 = i7;
+   }
+  } else {
+   HEAP32[146] = i8 | i6;
+   i4 = 624 + (i7 + 2 << 2) | 0;
+   i5 = i3;
+  }
+  HEAP32[i4 >> 2] = i2;
+  HEAP32[i5 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i5;
+  HEAP32[i2 + 12 >> 2] = i3;
+  STACKTOP = i1;
+  return;
+ }
+ i4 = i11 >>> 8;
+ if ((i4 | 0) != 0) {
+  if (i11 >>> 0 > 16777215) {
+   i4 = 31;
+  } else {
+   i20 = (i4 + 1048320 | 0) >>> 16 & 8;
+   i21 = i4 << i20;
+   i19 = (i21 + 520192 | 0) >>> 16 & 4;
+   i21 = i21 << i19;
+   i4 = (i21 + 245760 | 0) >>> 16 & 2;
+   i4 = 14 - (i19 | i20 | i4) + (i21 << i4 >>> 15) | 0;
+   i4 = i11 >>> (i4 + 7 | 0) & 1 | i4 << 1;
+  }
+ } else {
+  i4 = 0;
+ }
+ i5 = 888 + (i4 << 2) | 0;
+ HEAP32[i2 + 28 >> 2] = i4;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ i7 = HEAP32[588 >> 2] | 0;
+ i6 = 1 << i4;
+ L199 : do {
+  if ((i7 & i6 | 0) != 0) {
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((i4 | 0) == 31) {
+    i4 = 0;
+   } else {
+    i4 = 25 - (i4 >>> 1) | 0;
+   }
+   L204 : do {
+    if ((HEAP32[i5 + 4 >> 2] & -8 | 0) != (i11 | 0)) {
+     i4 = i11 << i4;
+     i7 = i5;
+     while (1) {
+      i6 = i7 + (i4 >>> 31 << 2) + 16 | 0;
+      i5 = HEAP32[i6 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       break;
+      }
+      if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i11 | 0)) {
+       i3 = i5;
+       break L204;
+      } else {
+       i4 = i4 << 1;
+       i7 = i5;
+      }
+     }
+     if (i6 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i6 >> 2] = i2;
+      HEAP32[i2 + 24 >> 2] = i7;
+      HEAP32[i2 + 12 >> 2] = i2;
+      HEAP32[i2 + 8 >> 2] = i2;
+      break L199;
+     }
+    } else {
+     i3 = i5;
+    }
+   } while (0);
+   i5 = i3 + 8 | 0;
+   i4 = HEAP32[i5 >> 2] | 0;
+   i6 = HEAP32[600 >> 2] | 0;
+   if (i3 >>> 0 < i6 >>> 0) {
+    _abort();
+   }
+   if (i4 >>> 0 < i6 >>> 0) {
+    _abort();
+   } else {
+    HEAP32[i4 + 12 >> 2] = i2;
+    HEAP32[i5 >> 2] = i2;
+    HEAP32[i2 + 8 >> 2] = i4;
+    HEAP32[i2 + 12 >> 2] = i3;
+    HEAP32[i2 + 24 >> 2] = 0;
+    break;
+   }
+  } else {
+   HEAP32[588 >> 2] = i7 | i6;
+   HEAP32[i5 >> 2] = i2;
+   HEAP32[i2 + 24 >> 2] = i5;
+   HEAP32[i2 + 12 >> 2] = i2;
+   HEAP32[i2 + 8 >> 2] = i2;
+  }
+ } while (0);
+ i21 = (HEAP32[616 >> 2] | 0) + -1 | 0;
+ HEAP32[616 >> 2] = i21;
+ if ((i21 | 0) == 0) {
+  i2 = 1040 | 0;
+ } else {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i2 = HEAP32[i2 >> 2] | 0;
+  if ((i2 | 0) == 0) {
+   break;
+  } else {
+   i2 = i2 + 8 | 0;
+  }
+ }
+ HEAP32[616 >> 2] = -1;
+ STACKTOP = i1;
+ return;
+}
+function _main(i7, i8) {
+ i7 = i7 | 0;
+ i8 = i8 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, d9 = 0.0, d10 = 0.0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 4272 | 0;
+ i3 = i2;
+ i5 = i2 + 4248 | 0;
+ i4 = i2 + 2128 | 0;
+ i1 = i2 + 8 | 0;
+ L1 : do {
+  if ((i7 | 0) > 1) {
+   i7 = HEAP8[HEAP32[i8 + 4 >> 2] | 0] | 0;
+   switch (i7 | 0) {
+   case 50:
+    {
+     i3 = 95e5;
+     break L1;
+    }
+   case 51:
+    {
+     i6 = 4;
+     break L1;
+    }
+   case 52:
+    {
+     i3 = 95e6;
+     break L1;
+    }
+   case 53:
+    {
+     i3 = 19e7;
+     break L1;
+    }
+   case 49:
+    {
+     i3 = 95e4;
+     break L1;
+    }
+   case 48:
+    {
+     i8 = 0;
+     STACKTOP = i2;
+     return i8 | 0;
+    }
+   default:
+    {
+     HEAP32[i3 >> 2] = i7 + -48;
+     _printf(280, i3 | 0) | 0;
+     i8 = -1;
+     STACKTOP = i2;
+     return i8 | 0;
+    }
+   }
+  } else {
+   i6 = 4;
+  }
+ } while (0);
+ if ((i6 | 0) == 4) {
+  i3 = 19e6;
+ }
+ HEAP32[i5 + 8 >> 2] = 0;
+ HEAP32[i5 + 4 >> 2] = 287;
+ i8 = __Znaj(347) | 0;
+ HEAP32[i5 >> 2] = i8;
+ _memcpy(i8 | 0, 296, 287) | 0;
+ i8 = i8 + 287 | 0;
+ i7 = 296 | 0;
+ i6 = i8 + 60 | 0;
+ do {
+  HEAP8[i8] = HEAP8[i7] | 0;
+  i8 = i8 + 1 | 0;
+  i7 = i7 + 1 | 0;
+ } while ((i8 | 0) < (i6 | 0));
+ i7 = i3 << 1;
+ while (1) {
+  i6 = i7 >>> 0 < 60 ? i7 : 60;
+  __ZN14RotatingString5writeEj(i5, i6);
+  if ((i7 | 0) == (i6 | 0)) {
+   break;
+  } else {
+   i7 = i7 - i6 | 0;
+  }
+ }
+ i5 = HEAP32[i5 >> 2] | 0;
+ if ((i5 | 0) != 0) {
+  __ZdaPv(i5);
+ }
+ if ((HEAP32[6] | 0) == 0) {
+  i6 = 24;
+  i5 = 0;
+ } else {
+  i5 = 24;
+  d9 = 0.0;
+  while (1) {
+   i6 = i5 + 4 | 0;
+   d9 = d9 + +HEAPF32[i6 >> 2];
+   d10 = d9 < 1.0 ? d9 : 1.0;
+   HEAPF32[i6 >> 2] = d10;
+   HEAP32[i5 + 8 >> 2] = ~~(d10 * 512.0) >>> 0;
+   i5 = i5 + 12 | 0;
+   if ((HEAP32[i5 >> 2] | 0) == 0) {
+    i6 = 24;
+    i5 = 0;
+    break;
+   }
+  }
+ }
+ do {
+  while (1) {
+   i8 = HEAP32[i6 + 8 >> 2] | 0;
+   if (i5 >>> 0 > i8 >>> 0 & (i8 | 0) != 0) {
+    i6 = i6 + 12 | 0;
+   } else {
+    break;
+   }
+  }
+  HEAP32[i4 + (i5 << 2) >> 2] = i6;
+  i5 = i5 + 1 | 0;
+ } while ((i5 | 0) != 513);
+ HEAP32[i4 + 2116 >> 2] = 0;
+ __Z9makeFastaI10RandomizedEvPKcS2_jRT_(0, 0, i3 * 3 | 0, i4);
+ if ((HEAP32[54] | 0) == 0) {
+  i5 = 216;
+  i4 = 0;
+ } else {
+  i5 = 216;
+  d9 = 0.0;
+  while (1) {
+   i4 = i5 + 4 | 0;
+   d9 = d9 + +HEAPF32[i4 >> 2];
+   d10 = d9 < 1.0 ? d9 : 1.0;
+   HEAPF32[i4 >> 2] = d10;
+   HEAP32[i5 + 8 >> 2] = ~~(d10 * 512.0) >>> 0;
+   i5 = i5 + 12 | 0;
+   if ((HEAP32[i5 >> 2] | 0) == 0) {
+    i5 = 216;
+    i4 = 0;
+    break;
+   }
+  }
+ }
+ do {
+  while (1) {
+   i8 = HEAP32[i5 + 8 >> 2] | 0;
+   if (i4 >>> 0 > i8 >>> 0 & (i8 | 0) != 0) {
+    i5 = i5 + 12 | 0;
+   } else {
+    break;
+   }
+  }
+  HEAP32[i1 + (i4 << 2) >> 2] = i5;
+  i4 = i4 + 1 | 0;
+ } while ((i4 | 0) != 513);
+ HEAP32[i1 + 2116 >> 2] = 0;
+ __Z9makeFastaI10RandomizedEvPKcS2_jRT_(0, 0, i3 * 5 | 0, i1);
+ i8 = 0;
+ STACKTOP = i2;
+ return i8 | 0;
+}
+function __Z9makeFastaI10RandomizedEvPKcS2_jRT_(i3, i2, i6, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i4 = 0, i5 = 0, i7 = 0, d8 = 0.0, i9 = 0;
+ i2 = STACKTOP;
+ if ((i6 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i4 = i1 + 2116 | 0;
+ i3 = i1 + 2052 | 0;
+ while (1) {
+  i5 = i6 >>> 0 < 60 ? i6 : 60;
+  if ((i5 | 0) != 0) {
+   i7 = 0;
+   do {
+    i9 = ((((HEAP32[4] | 0) * 3877 | 0) + 29573 | 0) >>> 0) % 139968 | 0;
+    HEAP32[4] = i9;
+    d8 = +(i9 >>> 0) / 139968.0;
+    i9 = HEAP32[i1 + (~~(d8 * 512.0) >>> 0 << 2) >> 2] | 0;
+    while (1) {
+     if (+HEAPF32[i9 + 4 >> 2] < d8) {
+      i9 = i9 + 12 | 0;
+     } else {
+      break;
+     }
+    }
+    HEAP8[i1 + i7 + 2052 | 0] = HEAP32[i9 >> 2];
+    i7 = i7 + 1 | 0;
+   } while ((i7 | 0) != (i5 | 0));
+  }
+  HEAP8[i1 + i5 + 2052 | 0] = 10;
+  i9 = i5 + 1 | 0;
+  HEAP8[i1 + i9 + 2052 | 0] = 0;
+  HEAP32[i4 >> 2] = i9;
+  i9 = _strlen(i3 | 0) | 0;
+  i7 = HEAP32[2] | 0;
+  if ((i9 | 0) > (i7 | 0)) {
+   if ((i7 | 0) > 0) {
+    HEAP8[i1 + i7 + 2052 | 0] = 0;
+    _puts(i3 | 0) | 0;
+    HEAP8[i1 + (HEAP32[2] | 0) + 2052 | 0] = 122;
+    HEAP32[2] = 0;
+   }
+  } else {
+   _puts(i3 | 0) | 0;
+   HEAP32[2] = (HEAP32[2] | 0) - i9;
+  }
+  if ((i6 | 0) == (i5 | 0)) {
+   break;
+  } else {
+   i6 = i6 - i5 | 0;
+  }
+ }
+ STACKTOP = i2;
+ return;
+}
+function __ZN14RotatingString5writeEj(i3, i4) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i5 = __Znaj(i4 + 2 | 0) | 0;
+ i2 = i3 + 8 | 0;
+ _memcpy(i5 | 0, (HEAP32[i3 >> 2] | 0) + (HEAP32[i2 >> 2] | 0) | 0, i4 | 0) | 0;
+ HEAP8[i5 + i4 | 0] = 0;
+ i7 = _strlen(i5 | 0) | 0;
+ i6 = HEAP32[2] | 0;
+ if ((i7 | 0) > (i6 | 0)) {
+  if ((i6 | 0) > 0) {
+   HEAP8[i5 + i6 | 0] = 0;
+   _puts(i5 | 0) | 0;
+   HEAP32[2] = 0;
+   i6 = 6;
+  } else {
+   i6 = 5;
+  }
+ } else {
+  _puts(i5 | 0) | 0;
+  HEAP32[2] = (HEAP32[2] | 0) - i7;
+  i6 = 5;
+ }
+ if ((i6 | 0) == 5 ? (i5 | 0) != 0 : 0) {
+  i6 = 6;
+ }
+ if ((i6 | 0) == 6) {
+  __ZdlPv(i5);
+ }
+ i4 = (HEAP32[i2 >> 2] | 0) + i4 | 0;
+ HEAP32[i2 >> 2] = i4;
+ i3 = HEAP32[i3 + 4 >> 2] | 0;
+ if (!(i4 >>> 0 > i3 >>> 0)) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP32[i2 >> 2] = i4 - i3;
+ STACKTOP = i1;
+ return;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function __Znwj(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i2 = (i2 | 0) == 0 ? 1 : i2;
+ while (1) {
+  i3 = _malloc(i2) | 0;
+  if ((i3 | 0) != 0) {
+   i2 = 6;
+   break;
+  }
+  i3 = HEAP32[270] | 0;
+  HEAP32[270] = i3 + 0;
+  if ((i3 | 0) == 0) {
+   i2 = 5;
+   break;
+  }
+  FUNCTION_TABLE_v[i3 & 0]();
+ }
+ if ((i2 | 0) == 5) {
+  i3 = ___cxa_allocate_exception(4) | 0;
+  HEAP32[i3 >> 2] = 1096;
+  ___cxa_throw(i3 | 0, 1144, 1);
+ } else if ((i2 | 0) == 6) {
+  STACKTOP = i1;
+  return i3 | 0;
+ }
+ return 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function __ZNSt9bad_allocD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZNSt9exceptionD2Ev(i1 | 0);
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function __ZNSt9bad_allocD2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZNSt9exceptionD2Ev(i1 | 0);
+ STACKTOP = i2;
+ return;
+}
+function __ZdlPv(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((i1 | 0) != 0) {
+  _free(i1);
+ }
+ STACKTOP = i2;
+ return;
+}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function __Znaj(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = __Znwj(i1) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function runPostSets() {
+ HEAP32[286] = __ZTVN10__cxxabiv120__si_class_type_infoE;
+ HEAP32[288] = __ZTISt9exception;
+}
+function dynCall_ii(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_ii[i2 & 1](i1 | 0) | 0;
+}
+function __ZdaPv(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function dynCall_vi(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_vi[i2 & 3](i1 | 0);
+}
+function dynCall_v(i1) {
+ i1 = i1 | 0;
+ FUNCTION_TABLE_v[i1 & 0]();
+}
+function __ZNKSt9bad_alloc4whatEv(i1) {
+ i1 = i1 | 0;
+ return 1112;
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function b0(i1) {
+ i1 = i1 | 0;
+ abort(0);
+ return 0;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+function b1(i1) {
+ i1 = i1 | 0;
+ abort(1);
+}
+function b2() {
+ abort(2);
+}
+
+// EMSCRIPTEN_END_FUNCS
+  var FUNCTION_TABLE_ii = [b0,__ZNKSt9bad_alloc4whatEv];
+  var FUNCTION_TABLE_vi = [b1,__ZNSt9bad_allocD2Ev,__ZNSt9bad_allocD0Ev,b1];
+  var FUNCTION_TABLE_v = [b2];
+
+  return { _strlen: _strlen, _free: _free, _main: _main, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9, dynCall_ii: dynCall_ii, dynCall_vi: dynCall_vi, dynCall_v: dynCall_v };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "invoke_ii": invoke_ii, "invoke_vi": invoke_vi, "invoke_v": invoke_v, "_send": _send, "___setErrNo": ___setErrNo, "___cxa_is_number_type": ___cxa_is_number_type, "___cxa_allocate_exception": ___cxa_allocate_exception, "___cxa_find_matching_catch": ___cxa_find_matching_catch, "_fflush": _fflush, "_time": _time, "_pwrite": _pwrite, "__reallyNegative": __reallyNegative, "_sbrk": _sbrk, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_fileno": _fileno, "___resumeException": ___resumeException, "__ZSt18uncaught_exceptionv": __ZSt18uncaught_exceptionv, "_sysconf": _sysconf, "_puts": _puts, "_mkport": _mkport, "_write": _write, "___errno_location": ___errno_location, "__ZNSt9exceptionD2Ev": __ZNSt9exceptionD2Ev, "_fputc": _fputc, "___cxa_throw": ___cxa_throw, "_abort": _abort, "_fwrite": _fwrite, "___cxa_does_inherit": ___cxa_does_inherit, "_fprintf": _fprintf, "__formatString": __formatString, "_fputs": _fputs, "_printf": _printf, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity, "__ZTISt9exception": __ZTISt9exception, "__ZTVN10__cxxabiv120__si_class_type_infoE": __ZTVN10__cxxabiv120__si_class_type_infoE }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _free = Module["_free"] = asm["_free"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var _malloc = Module["_malloc"] = asm["_malloc"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+var dynCall_ii = Module["dynCall_ii"] = asm["dynCall_ii"];
+var dynCall_vi = Module["dynCall_vi"] = asm["dynCall_vi"];
+var dynCall_v = Module["dynCall_v"] = asm["dynCall_v"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/lua_binarytrees.js b/test/mjsunit/asm/embenchen/lua_binarytrees.js
new file mode 100644
index 0000000..e3a5d8c
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/lua_binarytrees.js
@@ -0,0 +1,42710 @@
+var EXPECTED_OUTPUT =
+  'stretch tree of depth 10\t check: -1\n' +
+  '1448\t trees of depth 4\t check: -1448\n' +
+  '362\t trees of depth 6\t check: -362\n' +
+  '90\t trees of depth 8\t check: -90\n' +
+  'long lived tree of depth 9\t check: -1\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+
+var Module;
+if (typeof Module === 'undefined') Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');
+if (!Module.expectedDataFileDownloads) {
+  Module.expectedDataFileDownloads = 0;
+  Module.finishedDataFileDownloads = 0;
+}
+Module.expectedDataFileDownloads++;
+(function() {
+
+  function runWithFS() {
+
+function assert(check, msg) {
+  if (!check) throw msg + new Error().stack;
+}
+Module['FS_createDataFile']('/', 'binarytrees.lua', [45, 45, 32, 84, 104, 101, 32, 67, 111, 109, 112, 117, 116, 101, 114, 32, 76, 97, 110, 103, 117, 97, 103, 101, 32, 66, 101, 110, 99, 104, 109, 97, 114, 107, 115, 32, 71, 97, 109, 101, 10, 45, 45, 32, 104, 116, 116, 112, 58, 47, 47, 98, 101, 110, 99, 104, 109, 97, 114, 107, 115, 103, 97, 109, 101, 46, 97, 108, 105, 111, 116, 104, 46, 100, 101, 98, 105, 97, 110, 46, 111, 114, 103, 47, 10, 45, 45, 32, 99, 111, 110, 116, 114, 105, 98, 117, 116, 101, 100, 32, 98, 121, 32, 77, 105, 107, 101, 32, 80, 97, 108, 108, 10, 10, 108, 111, 99, 97, 108, 32, 102, 117, 110, 99, 116, 105, 111, 110, 32, 66, 111, 116, 116, 111, 109, 85, 112, 84, 114, 101, 101, 40, 105, 116, 101, 109, 44, 32, 100, 101, 112, 116, 104, 41, 10, 32, 32, 105, 102, 32, 100, 101, 112, 116, 104, 32, 62, 32, 48, 32, 116, 104, 101, 110, 10, 32, 32, 32, 32, 108, 111, 99, 97, 108, 32, 105, 32, 61, 32, 105, 116, 101, 109, 32, 43, 32, 105, 116, 101, 109, 10, 32, 32, 32, 32, 100, 101, 112, 116, 104, 32, 61, 32, 100, 101, 112, 116, 104, 32, 45, 32, 49, 10, 32, 32, 32, 32, 108, 111, 99, 97, 108, 32, 108, 101, 102, 116, 44, 32, 114, 105, 103, 104, 116, 32, 61, 32, 66, 111, 116, 116, 111, 109, 85, 112, 84, 114, 101, 101, 40, 105, 45, 49, 44, 32, 100, 101, 112, 116, 104, 41, 44, 32, 66, 111, 116, 116, 111, 109, 85, 112, 84, 114, 101, 101, 40, 105, 44, 32, 100, 101, 112, 116, 104, 41, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 123, 32, 105, 116, 101, 109, 44, 32, 108, 101, 102, 116, 44, 32, 114, 105, 103, 104, 116, 32, 125, 10, 32, 32, 101, 108, 115, 101, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 123, 32, 105, 116, 101, 109, 32, 125, 10, 32, 32, 101, 110, 100, 10, 101, 110, 100, 10, 10, 108, 111, 99, 97, 108, 32, 102, 117, 110, 99, 116, 105, 111, 110, 32, 73, 116, 101, 109, 67, 104, 101, 99, 107, 40, 116, 114, 101, 101, 41, 10, 32, 32, 105, 102, 32, 116, 114, 101, 101, 91, 50, 93, 32, 116, 104, 101, 110, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 116, 114, 101, 101, 91, 49, 93, 32, 43, 32, 73, 116, 101, 109, 67, 104, 101, 99, 107, 40, 116, 114, 101, 101, 91, 50, 93, 41, 32, 45, 32, 73, 116, 101, 109, 67, 104, 101, 99, 107, 40, 116, 114, 101, 101, 91, 51, 93, 41, 10, 32, 32, 101, 108, 115, 101, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 116, 114, 101, 101, 91, 49, 93, 10, 32, 32, 101, 110, 100, 10, 101, 110, 100, 10, 10, 108, 111, 99, 97, 108, 32, 78, 32, 61, 32, 116, 111, 110, 117, 109, 98, 101, 114, 40, 97, 114, 103, 32, 97, 110, 100, 32, 97, 114, 103, 91, 49, 93, 41, 32, 111, 114, 32, 52, 10, 10, 105, 102, 32, 78, 32, 61, 61, 32, 48, 32, 116, 104, 101, 110, 10, 32, 32, 78, 32, 61, 32, 48, 10, 101, 108, 115, 101, 105, 102, 32, 78, 32, 61, 61, 32, 49, 32, 116, 104, 101, 110, 10, 32, 32, 78, 32, 61, 32, 57, 46, 53, 10, 101, 108, 115, 101, 105, 102, 32, 78, 32, 61, 61, 32, 50, 32, 116, 104, 101, 110, 10, 32, 32, 78, 32, 61, 32, 49, 49, 46, 57, 57, 10, 101, 108, 115, 101, 105, 102, 32, 78, 32, 61, 61, 32, 51, 32, 116, 104, 101, 110, 10, 32, 32, 78, 32, 61, 32, 49, 50, 46, 56, 53, 10, 101, 108, 115, 101, 105, 102, 32, 78, 32, 61, 61, 32, 52, 32, 116, 104, 101, 110, 10, 32, 32, 78, 32, 61, 32, 49, 52, 46, 55, 50, 10, 101, 108, 115, 101, 105, 102, 32, 78, 32, 61, 61, 32, 53, 32, 116, 104, 101, 110, 10, 32, 32, 78, 32, 61, 32, 49, 53, 46, 56, 50, 10, 101, 110, 100, 10, 10, 108, 111, 99, 97, 108, 32, 109, 105, 110, 100, 101, 112, 116, 104, 32, 61, 32, 52, 10, 108, 111, 99, 97, 108, 32, 109, 97, 120, 100, 101, 112, 116, 104, 32, 61, 32, 109, 105, 110, 100, 101, 112, 116, 104, 32, 43, 32, 50, 10, 105, 102, 32, 109, 97, 120, 100, 101, 112, 116, 104, 32, 60, 32, 78, 32, 116, 104, 101, 110, 32, 109, 97, 120, 100, 101, 112, 116, 104, 32, 61, 32, 78, 32, 101, 110, 100, 10, 10, 100, 111, 10, 32, 32, 108, 111, 99, 97, 108, 32, 115, 116, 114, 101, 116, 99, 104, 100, 101, 112, 116, 104, 32, 61, 32, 109, 97, 120, 100, 101, 112, 116, 104, 32, 43, 32, 49, 10, 32, 32, 108, 111, 99, 97, 108, 32, 115, 116, 114, 101, 116, 99, 104, 116, 114, 101, 101, 32, 61, 32, 66, 111, 116, 116, 111, 109, 85, 112, 84, 114, 101, 101, 40, 48, 44, 32, 115, 116, 114, 101, 116, 99, 104, 100, 101, 112, 116, 104, 41, 10, 32, 32, 105, 111, 46, 119, 114, 105, 116, 101, 40, 115, 116, 114, 105, 110, 103, 46, 102, 111, 114, 109, 97, 116, 40, 34, 115, 116, 114, 101, 116, 99, 104, 32, 116, 114, 101, 101, 32, 111, 102, 32, 100, 101, 112, 116, 104, 32, 37, 100, 92, 116, 32, 99, 104, 101, 99, 107, 58, 32, 37, 100, 92, 110, 34, 44, 10, 32, 32, 32, 32, 115, 116, 114, 101, 116, 99, 104, 100, 101, 112, 116, 104, 44, 32, 73, 116, 101, 109, 67, 104, 101, 99, 107, 40, 115, 116, 114, 101, 116, 99, 104, 116, 114, 101, 101, 41, 41, 41, 10, 101, 110, 100, 10, 10, 108, 111, 99, 97, 108, 32, 108, 111, 110, 103, 108, 105, 118, 101, 100, 116, 114, 101, 101, 32, 61, 32, 66, 111, 116, 116, 111, 109, 85, 112, 84, 114, 101, 101, 40, 48, 44, 32, 109, 97, 120, 100, 101, 112, 116, 104, 41, 10, 10, 102, 111, 114, 32, 100, 101, 112, 116, 104, 61, 109, 105, 110, 100, 101, 112, 116, 104, 44, 109, 97, 120, 100, 101, 112, 116, 104, 44, 50, 32, 100, 111, 10, 32, 32, 108, 111, 99, 97, 108, 32, 105, 116, 101, 114, 97, 116, 105, 111, 110, 115, 32, 61, 32, 50, 32, 94, 32, 40, 109, 97, 120, 100, 101, 112, 116, 104, 32, 45, 32, 100, 101, 112, 116, 104, 32, 43, 32, 109, 105, 110, 100, 101, 112, 116, 104, 41, 10, 32, 32, 108, 111, 99, 97, 108, 32, 99, 104, 101, 99, 107, 32, 61, 32, 48, 10, 32, 32, 102, 111, 114, 32, 105, 61, 49, 44, 105, 116, 101, 114, 97, 116, 105, 111, 110, 115, 32, 100, 111, 10, 32, 32, 32, 32, 99, 104, 101, 99, 107, 32, 61, 32, 99, 104, 101, 99, 107, 32, 43, 32, 73, 116, 101, 109, 67, 104, 101, 99, 107, 40, 66, 111, 116, 116, 111, 109, 85, 112, 84, 114, 101, 101, 40, 49, 44, 32, 100, 101, 112, 116, 104, 41, 41, 32, 43, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 73, 116, 101, 109, 67, 104, 101, 99, 107, 40, 66, 111, 116, 116, 111, 109, 85, 112, 84, 114, 101, 101, 40, 45, 49, 44, 32, 100, 101, 112, 116, 104, 41, 41, 10, 32, 32, 101, 110, 100, 10, 32, 32, 105, 111, 46, 119, 114, 105, 116, 101, 40, 115, 116, 114, 105, 110, 103, 46, 102, 111, 114, 109, 97, 116, 40, 34, 37, 100, 92, 116, 32, 116, 114, 101, 101, 115, 32, 111, 102, 32, 100, 101, 112, 116, 104, 32, 37, 100, 92, 116, 32, 99, 104, 101, 99, 107, 58, 32, 37, 100, 92, 110, 34, 44, 10, 32, 32, 32, 32, 105, 116, 101, 114, 97, 116, 105, 111, 110, 115, 42, 50, 44, 32, 100, 101, 112, 116, 104, 44, 32, 99, 104, 101, 99, 107, 41, 41, 10, 101, 110, 100, 10, 10, 105, 111, 46, 119, 114, 105, 116, 101, 40, 115, 116, 114, 105, 110, 103, 46, 102, 111, 114, 109, 97, 116, 40, 34, 108, 111, 110, 103, 32, 108, 105, 118, 101, 100, 32, 116, 114, 101, 101, 32, 111, 102, 32, 100, 101, 112, 116, 104, 32, 37, 100, 92, 116, 32, 99, 104, 101, 99, 107, 58, 32, 37, 100, 92, 110, 34, 44, 10, 32, 32, 109, 97, 120, 100, 101, 112, 116, 104, 44, 32, 73, 116, 101, 109, 67, 104, 101, 99, 107, 40, 108, 111, 110, 103, 108, 105, 118, 101, 100, 116, 114, 101, 101, 41, 41, 41, 10], true, true);
+
+  }
+  if (Module['calledRun']) {
+    runWithFS();
+  } else {
+    if (!Module['preRun']) Module['preRun'] = [];
+    Module["preRun"].push(runWithFS); // FS is not initialized yet, wait for it
+  }
+
+})();
+
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(13467);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([99,97,110,110,111,116,32,99,114,101,97,116,101,32,115,116,97,116,101,58,32,110,111,116,32,101,110,111,117,103,104,32,109,101,109,111,114,121,0,0,40,101,114,114,111,114,32,111,98,106,101,99,116,32,105,115,32,110,111,116,32,97,32,115,116,114,105,110,103,41,0,0,88,0,0,0,0,0,0,0,108,117,97,0,0,0,0,0,76,85,65,95,78,79,69,78,86,0,0,0,0,0,0,0,116,111,111,32,109,97,110,121,32,114,101,115,117,108,116,115,32,116,111,32,112,114,105,110,116,0,0,0,0,0,0,0,112,114,105,110,116,0,0,0,101,114,114,111,114,32,99,97,108,108,105,110,103,32,39,112,114,105,110,116,39,32,40,37,115,41,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,105,110,116,101,114,114,117,112,116,101,100,33,0,0,0,0,95,95,116,111,115,116,114,105,110,103,0,0,0,0,0,0,40,110,111,32,101,114,114,111,114,32,109,101,115,115,97,103,101,41,0,0,0,0,0,0,61,115,116,100,105,110,0,0,60,101,111,102,62,0,0,0,114,101,116,117,114,110,32,37,115,0,0,0,0,0,0,0,95,80,82,79,77,80,84,0,95,80,82,79,77,80,84,50,0,0,0,0,0,0,0,0,62,32,0,0,0,0,0,0,62,62,32,0,0,0,0,0,97,114,103,0,0,0,0,0,45,0,0,0,0,0,0,0,45,45,0,0,0,0,0,0,116,111,111,32,109,97,110,121,32,97,114,103,117,109,101,110,116,115,32,116,111,32,115,99,114,105,112,116,0,0,0,0,61,40,99,111,109,109,97,110,100,32,108,105,110,101,41,0,114,101,113,117,105,114,101,0,61,76,85,65,95,73,78,73,84,95,53,95,50,0,0,0,61,76,85,65,95,73,78,73,84,0,0,0,0,0,0,0,76,117,97,32,53,46,50,46,50,32,32,67,111,112,121,114,105,103,104,116,32,40,67,41,32,49,57,57,52,45,50,48,49,51,32,76,117,97,46,111,114,103,44,32,80,85,67,45,82,105,111,0,0,0,0,0,37,115,58,32,0,0,0,0,39,37,115,39,32,110,101,101,100,115,32,97,114,103,117,109,101,110,116,10,0,0,0,0,117,110,114,101,99,111,103,110,105,122,101,100,32,111,112,116,105,111,110,32,39,37,115,39,10,0,0,0,0,0,0,0,117,115,97,103,101,58,32,37,115,32,91,111,112,116,105,111,110,115,93,32,91,115,99,114,105,112,116,32,91,97,114,103,115,93,93,10,65,118,97,105,108,97,98,108,101,32,111,112,116,105,111,110,115,32,97,114,101,58,10,32,32,45,101,32,115,116,97,116,32,32,101,120,101,99,117,116,101,32,115,116,114,105,110,103,32,39,115,116,97,116,39,10,32,32,45,105,32,32,32,32,32,32,32,101,110,116,101,114,32,105,110,116,101,114,97,99,116,105,118,101,32,109,111,100,101,32,97,102,116,101,114,32,101,120,101,99,117,116,105,110,103,32,39,115,99,114,105,112,116,39,10,32,32,45,108,32,110,97,109,101,32,32,114,101,113,117,105,114,101,32,108,105,98,114,97,114,121,32,39,110,97,109,101,39,10,32,32,45,118,32,32,32,32,32,32,32,115,104,111,119,32,118,101,114,115,105,111,110,32,105,110,102,111,114,109,97,116,105,111,110,10,32,32,45,69,32,32,32,32,32,32,32,105,103,110,111,114,101,32,101,110,118,105,114,111,110,109,101,110,116,32,118,97,114,105,97,98,108,101,115,10,32,32,45,45,32,32,32,32,32,32,32,115,116,111,112,32,104,97,110,100,108,105,110,103,32,111,112,116,105,111,110,115,10,32,32,45,32,32,32,32,32,32,32,32,115,116,111,112,32,104,97,110,100,108,105,110,103,32,111,112,116,105,111,110,115,32,97,110,100,32,101,120,101,99,117,116,101,32,115,116,100,105,110,10,0,0,0,0,0,0,0,37,115,10,0,0,0,0,0,0,0,0,0,0,96,127,64,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,115,10,0,0,0,0,0,115,116,97,99,107,32,116,114,97,99,101,98,97,99,107,58,0,0,0,0,0,0,0,0,10,9,46,46,46,0,0,0,83,108,110,116,0,0,0,0,10,9,37,115,58,0,0,0,37,100,58,0,0,0,0,0,32,105,110,32,0,0,0,0,10,9,40,46,46,46,116,97,105,108,32,99,97,108,108,115,46,46,46,41,0,0,0,0,98,97,100,32,97,114,103,117,109,101,110,116,32,35,37,100,32,40,37,115,41,0,0,0,110,0,0,0,0,0,0,0,109,101,116,104,111,100,0,0,99,97,108,108,105,110,103,32,39,37,115,39,32,111,110,32,98,97,100,32,115,101,108,102,32,40,37,115,41,0,0,0,63,0,0,0,0,0,0,0,98,97,100,32,97,114,103,117,109,101,110,116,32,35,37,100,32,116,111,32,39,37,115,39,32,40,37,115,41,0,0,0,83,108,0,0,0,0,0,0,37,115,58,37,100,58,32,0,0,0,0,0,0,0,0,0,37,115,58,32,37,115,0,0,101,120,105,116,0,0,0,0,105,110,118,97,108,105,100,32,111,112,116,105,111,110,32,39,37,115,39,0,0,0,0,0,115,116,97,99,107,32,111,118,101,114,102,108,111,119,32,40,37,115,41,0,0,0,0,0,115,116,97,99,107,32,111,118,101,114,102,108,111,119,0,0,118,97,108,117,101,32,101,120,112,101,99,116,101,100,0,0,98,117,102,102,101,114,32,116,111,111,32,108,97,114,103,101,0,0,0,0,0,0,0,0,61,115,116,100,105,110,0,0,64,37,115,0,0,0,0,0,114,0,0,0,0,0,0,0,111,112,101,110,0,0,0,0,114,98,0,0,0,0,0,0,114,101,111,112,101,110,0,0,114,101,97,100,0,0,0,0,111,98,106,101,99,116,32,108,101,110,103,116,104,32,105,115,32,110,111,116,32,97,32,110,117,109,98,101,114,0,0,0,95,95,116,111,115,116,114,105,110,103,0,0,0,0,0,0,116,114,117,101,0,0,0,0,102,97,108,115,101,0,0,0,110,105,108,0,0,0,0,0,37,115,58,32,37,112,0,0,95,76,79,65,68,69,68,0,110,97,109,101,32,99,111,110,102,108,105,99,116,32,102,111,114,32,109,111,100,117,108,101,32,39,37,115,39,0,0,0,116,111,111,32,109,97,110,121,32,117,112,118,97,108,117,101,115,0,0,0,0,0,0,0,109,117,108,116,105,112,108,101,32,76,117,97,32,86,77,115,32,100,101,116,101,99,116,101,100,0,0,0,0,0,0,0,118,101,114,115,105,111,110,32,109,105,115,109,97,116,99,104,58,32,97,112,112,46,32,110,101,101,100,115,32,37,102,44,32,76,117,97,32,99,111,114,101,32,112,114,111,118,105,100,101,115,32,37,102,0,0,0,98,97,100,32,99,111,110,118,101,114,115,105,111,110,32,110,117,109,98,101,114,45,62,105,110,116,59,32,109,117,115,116,32,114,101,99,111,109,112,105,108,101,32,76,117,97,32,119,105,116,104,32,112,114,111,112,101,114,32,115,101,116,116,105,110,103,115,0,0,0,0,0,80,65,78,73,67,58,32,117,110,112,114,111,116,101,99,116,101,100,32,101,114,114,111,114,32,105,110,32,99,97,108,108,32,116,111,32,76,117,97,32,65,80,73,32,40,37,115,41,10,0,0,0,0,0,0,0,239,187,191,0,0,0,0,0,99,97,110,110,111,116,32,37,115,32,37,115,58,32,37,115,0,0,0,0,0,0,0,0,37,115,32,101,120,112,101,99,116,101,100,44,32,103,111,116,32,37,115,0,0,0,0,0,102,0,0,0,0,0,0,0,46,0,0,0,0,0,0,0,102,117,110,99,116,105,111,110,32,39,37,115,39,0,0,0,109,97,105,110,32,99,104,117,110,107,0,0,0,0,0,0,102,117,110,99,116,105,111,110,32,60,37,115,58,37,100,62,0,0,0,0,0,0,0,0,97,116,116,101,109,112,116,32,116,111,32,37,115,32,37,115,32,39,37,115,39,32,40,97,32,37,115,32,118,97,108,117,101,41,0,0,0,0,0,0,97,116,116,101,109,112,116,32,116,111,32,37,115,32,97,32,37,115,32,118,97,108,117,101,0,0,0,0,0,0,0,0,99,111,110,99,97,116,101,110,97,116,101,0,0,0,0,0,112,101,114,102,111,114,109,32,97,114,105,116,104,109,101,116,105,99,32,111,110,0,0,0,97,116,116,101,109,112,116,32,116,111,32,99,111,109,112,97,114,101,32,116,119,111,32,37,115,32,118,97,108,117,101,115,0,0,0,0,0,0,0,0,97,116,116,101,109,112,116,32,116,111,32,99,111,109,112,97,114,101,32,37,115,32,119,105,116,104,32,37,115,0,0,0,37,115,58,37,100,58,32,37,115,0,0,0,0,0,0,0,108,111,99,97,108,0,0,0,95,69,78,86,0,0,0,0,103,108,111,98,97,108,0,0,102,105,101,108,100,0,0,0,117,112,118,97,108,117,101,0,99,111,110,115,116,97,110,116,0,0,0,0,0,0,0,0,109,101,116,104,111,100,0,0,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,102,111,114,32,105,116,101,114,97,116,111,114,0,0,0,0,109,101,116,97,109,101,116,104,111,100,0,0,0,0,0,0,61,91,67,93,0,0,0,0,67,0,0,0,0,0,0,0,61,63,0,0,0,0,0,0,109,97,105,110,0,0,0,0,76,117,97,0,0,0,0,0,40,42,116,101,109,112,111,114,97,114,121,41,0,0,0,0,40,42,118,97,114,97,114,103,41,0,0,0,0,0,0,0,115,116,97,99,107,32,111,118,101,114,102,108,111,119,0,0,67,32,115,116,97,99,107,32,111,118,101,114,102,108,111,119,0,0,0,0,0,0,0,0,97,116,116,101,109,112,116,32,116,111,32,121,105,101,108,100,32,97,99,114,111,115,115,32,97,32,67,45,99,97,108,108,32,98,111,117,110,100,97,114,121,0,0,0,0,0,0,0,97,116,116,101,109,112,116,32,116,111,32,121,105,101,108,100,32,102,114,111,109,32,111,117,116,115,105,100,101,32,97,32,99,111,114,111,117,116,105,110,101,0,0,0,0,0,0,0,98,105,110,97,114,121,0,0,116,101,120,116,0,0,0,0,97,116,116,101,109,112,116,32,116,111,32,108,111,97,100,32,97,32,37,115,32,99,104,117,110,107,32,40,109,111,100,101,32,105,115,32,39,37,115,39,41,0,0,0,0,0,0,0,101,114,114,111,114,32,105,110,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103,0,99,97,110,110,111,116,32,114,101,115,117,109,101,32,110,111,110,45,115,117,115,112,101,110,100,101,100,32,99,111,114,111,117,116,105,110,101,0,0,0,99,97,110,110,111,116,32,114,101,115,117,109,101,32,100,101,97,100,32,99,111,114,111,117,116,105,110,101,0,0,0,0,99,97,108,108,0,0,0,0,110,111,32,109,101,115,115,97,103,101,0,0,0,0,0,0,101,114,114,111,114,32,105,110,32,95,95,103,99,32,109,101,116,97,109,101,116,104,111,100,32,40,37,115,41,0,0,0,95,80,82,69,76,79,65,68,0,0,0,0,0,0,0,0,95,71,0,0,0,0,0,0,112,97,99,107,97,103,101,0,99,111,114,111,117,116,105,110,101,0,0,0,0,0,0,0,116,97,98,108,101,0,0,0,105,111,0,0,0,0,0,0,111,115,0,0,0,0,0,0,115,116,114,105,110,103,0,0,98,105,116,51,50,0,0,0,109,97,116,104,0,0,0,0,100,101,98,117,103,0,0,0,144,11,0,0,1,0,0,0,152,11,0,0,2,0,0,0,48,13,0,0,3,0,0,0,160,11,0,0,4,0,0,0,56,13,0,0,5,0,0,0,64,13,0,0,6,0,0,0,72,13,0,0,7,0,0,0,168,11,0,0,8,0,0,0,80,13,0,0,9,0,0,0,88,13,0,0,10,0,0,0,192,11,0,0,11,0,0,0,0,0,0,0,0,0,0,0,95,73,79,95,105,110,112,117,116,0,0,0,0,0,0,0,115,116,100,105,110,0,0,0,95,73,79,95,111,117,116,112,117,116,0,0,0,0,0,0,115,116,100,111,117,116,0,0,115,116,100,101,114,114,0,0,70,73,76,69,42,0,0,0,99,97,110,110,111,116,32,99,108,111,115,101,32,115,116,97,110,100,97,114,100,32,102,105,108,101,0,0,0,0,0,0,95,95,105,110,100,101,120,0,144,11,0,0,1,0,0,0,152,11,0,0,12,0,0,0,160,11,0,0,13,0,0,0,168,11,0,0,14,0,0,0,176,11,0,0,15,0,0,0,184,11,0,0,16,0,0,0,192,11,0,0,17,0,0,0,200,11,0,0,18,0,0,0,208,11,0,0,19,0,0,0,0,0,0,0,0,0,0,0,99,108,111,115,101,0,0,0,102,108,117,115,104,0,0,0,108,105,110,101,115,0,0,0,114,101,97,100,0,0,0,0,115,101,101,107,0,0,0,0,115,101,116,118,98,117,102,0,119,114,105,116,101,0,0,0,95,95,103,99,0,0,0,0,95,95,116,111,115,116,114,105,110,103,0,0,0,0,0,0,102,105,108,101,32,40,99,108,111,115,101,100,41,0,0,0,102,105,108,101,32,40,37,112,41,0,0,0,0,0,0,0,37,46,49,52,103,0,0,0,97,116,116,101,109,112,116,32,116,111,32,117,115,101,32,97,32,99,108,111,115,101,100,32,102,105,108,101,0,0,0,0,2,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,72,12,0,0,80,12,0,0,88,12,0,0,0,0,0,0,110,111,0,0,0,0,0,0,102,117,108,108,0,0,0,0,108,105,110,101,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,128,12,0,0,136,12,0,0,144,12,0,0,0,0,0,0,115,101,116,0,0,0,0,0,99,117,114,0,0,0,0,0,101,110,100,0,0,0,0,0,110,111,116,32,97,110,32,105,110,116,101,103,101,114,32,105,110,32,112,114,111,112,101,114,32,114,97,110,103,101,0,0,116,111,111,32,109,97,110,121,32,97,114,103,117,109,101,110,116,115,0,0,0,0,0,0,105,110,118,97,108,105,100,32,111,112,116,105,111,110,0,0,105,110,118,97,108,105,100,32,102,111,114,109,97,116,0,0,37,108,102,0,0,0,0,0,116,111,111,32,109,97,110,121,32,111,112,116,105,111,110,115,0,0,0,0,0,0,0,0,102,105,108,101,32,105,115,32,97,108,114,101,97,100,121,32,99,108,111,115,101,100,0,0,37,115,0,0,0,0,0,0,105,110,112,117,116,0,0,0,111,112,101,110,0,0,0,0,111,117,116,112,117,116,0,0,112,111,112,101,110,0,0,0,116,109,112,102,105,108,101,0,116,121,112,101,0,0,0,0,115,116,97,110,100,97,114,100,32,37,115,32,102,105,108,101,32,105,115,32,99,108,111,115,101,100,0,0,0,0,0,0,99,108,111,115,101,100,32,102,105,108,101,0,0,0,0,0,102,105,108,101,0,0,0,0,114,0,0,0,0,0,0,0,39,112,111,112,101,110,39,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,0,0,119,0,0,0,0,0,0,0,99,97,110,110,111,116,32,111,112,101,110,32,102,105,108,101,32,39,37,115,39,32,40,37,115,41,0,0,0,0,0,0,114,119,97,0,0,0,0,0,105,110,118,97,108,105,100,32,109,111,100,101,0,0,0,0,240,14,0,0,20,0,0,0,248,14,0,0,21,0,0,0,0,15,0,0,22,0,0,0,8,15,0,0,23,0,0,0,16,15,0,0,24,0,0,0,24,15,0,0,25,0,0,0,32,15,0,0,26,0,0,0,40,15,0,0,27,0,0,0,48,15,0,0,28,0,0,0,56,15,0,0,29,0,0,0,64,15,0,0,30,0,0,0,72,15,0,0,31,0,0,0,80,15,0,0,32,0,0,0,88,15,0,0,33,0,0,0,96,15,0,0,34,0,0,0,104,15,0,0,35,0,0,0,112,15,0,0,36,0,0,0,120,15,0,0,37,0,0,0,128,15,0,0,38,0,0,0,136,15,0,0,39,0,0,0,144,15,0,0,40,0,0,0,152,15,0,0,41,0,0,0,160,15,0,0,42,0,0,0,176,15,0,0,43,0,0,0,184,15,0,0,44,0,0,0,192,15,0,0,45,0,0,0,200,15,0,0,46,0,0,0,208,15,0,0,47,0,0,0,0,0,0,0,0,0,0,0,112,105,0,0,0,0,0,0,104,117,103,101,0,0,0,0,97,98,115,0,0,0,0,0,97,99,111,115,0,0,0,0,97,115,105,110,0,0,0,0,97,116,97,110,50,0,0,0,97,116,97,110,0,0,0,0,99,101,105,108,0,0,0,0,99,111,115,104,0,0,0,0,99,111,115,0,0,0,0,0,100,101,103,0,0,0,0,0,101,120,112,0,0,0,0,0,102,108,111,111,114,0,0,0,102,109,111,100,0,0,0,0,102,114,101,120,112,0,0,0,108,100,101,120,112,0,0,0,108,111,103,49,48,0,0,0,108,111,103,0,0,0,0,0,109,97,120,0,0,0,0,0,109,105,110,0,0,0,0,0,109,111,100,102,0,0,0,0,112,111,119,0,0,0,0,0,114,97,100,0,0,0,0,0,114,97,110,100,111,109,0,0,114,97,110,100,111,109,115,101,101,100,0,0,0,0,0,0,115,105,110,104,0,0,0,0,115,105,110,0,0,0,0,0,115,113,114,116,0,0,0,0,116,97,110,104,0,0,0,0,116,97,110,0,0,0,0,0,105,110,116,101,114,118,97,108,32,105,115,32,101,109,112,116,121,0,0,0,0,0,0,0,119,114,111,110,103,32,110,117,109,98,101,114,32,111,102,32,97,114,103,117,109,101,110,116,115,0,0,0,0,0,0,0,116,111,111,32,109,97,110,121,32,37,115,32,40,108,105,109,105,116,32,105,115,32,37,100,41,0,0,0,0,0,0,0,109,101,109,111,114,121,32,97,108,108,111,99,97,116,105,111,110,32,101,114,114,111,114,58,32,98,108,111,99,107,32,116,111,111,32,98,105,103,0,0,95,67,76,73,66,83,0,0,95,95,103,99,0,0,0,0,16,20,0,0,48,0,0,0,24,20,0,0,49,0,0,0,40,20,0,0,50,0,0,0,0,0,0,0,0,0,0,0,108,111,97,100,101,114,115,0,115,101,97,114,99,104,101,114,115,0,0,0,0,0,0,0,112,97,116,104,0,0,0,0,76,85,65,95,80,65,84,72,95,53,95,50,0,0,0,0,76,85,65,95,80,65,84,72,0,0,0,0,0,0,0,0,47,117,115,114,47,108,111,99,97,108,47,115,104,97,114,101,47,108,117,97,47,53,46,50,47,63,46,108,117,97,59,47,117,115,114,47,108,111,99,97,108,47,115,104,97,114,101,47,108,117,97,47,53,46,50,47,63,47,105,110,105,116,46,108,117,97,59,47,117,115,114,47,108,111,99,97,108,47,108,105,98,47,108,117,97,47,53,46,50,47,63,46,108,117,97,59,47,117,115,114,47,108,111,99,97,108,47,108,105,98,47,108,117,97,47,53,46,50,47,63,47,105,110,105,116,46,108,117,97,59,46,47,63,46,108,117,97,0,0,0,0,0,0,0,99,112,97,116,104,0,0,0,76,85,65,95,67,80,65,84,72,95,53,95,50,0,0,0,76,85,65,95,67,80,65,84,72,0,0,0,0,0,0,0,47,117,115,114,47,108,111,99,97,108,47,108,105,98,47,108,117,97,47,53,46,50,47,63,46,115,111,59,47,117,115,114,47,108,111,99,97,108,47,108,105,98,47,108,117,97,47,53,46,50,47,108,111,97,100,97,108,108,46,115,111,59,46,47,63,46,115,111,0,0,0,0,47,10,59,10,63,10,33,10,45,10,0,0,0,0,0,0,99,111,110,102,105,103,0,0,95,76,79,65,68,69,68,0,108,111,97,100,101,100,0,0,95,80,82,69,76,79,65,68,0,0,0,0,0,0,0,0,112,114,101,108,111,97,100,0,32,18,0,0,51,0,0,0,40,18,0,0,52,0,0,0,0,0,0,0,0,0,0,0,109,111,100,117,108,101,0,0,114,101,113,117,105,114,101,0,39,112,97,99,107,97,103,101,46,115,101,97,114,99,104,101,114,115,39,32,109,117,115,116,32,98,101,32,97,32,116,97,98,108,101,0,0,0,0,0,109,111,100,117,108,101,32,39,37,115,39,32,110,111,116,32,102,111,117,110,100,58,37,115,0,0,0,0,0,0,0,0,95,78,65,77,69,0,0,0,102,0,0,0,0,0,0,0,39,109,111,100,117,108,101,39,32,110,111,116,32,99,97,108,108,101,100,32,102,114,111,109,32,97,32,76,117,97,32,102,117,110,99,116,105,111,110,0,95,77,0,0,0,0,0,0,95,80,65,67,75,65,71,69,0,0,0,0,0,0,0,0,59,59,0,0,0,0,0,0,59,1,59,0,0,0,0,0,1,0,0,0,0,0,0,0,76,85,65,95,78,79,69,78,86,0,0,0,0,0,0,0,47,0,0,0,0,0,0,0,10,9,110,111,32,109,111,100,117,108,101,32,39,37,115,39,32,105,110,32,102,105,108,101,32,39,37,115,39,0,0,0,101,114,114,111,114,32,108,111,97,100,105,110,103,32,109,111,100,117,108,101,32,39,37,115,39,32,102,114,111,109,32,102,105,108,101,32,39,37,115,39,58,10,9,37,115,0,0,0,46,0,0,0,0,0,0,0,95,0,0,0,0,0,0,0,108,117,97,111,112,101,110,95,37,115,0,0,0,0,0,0,100,121,110,97,109,105,99,32,108,105,98,114,97,114,105,101,115,32,110,111,116,32,101,110,97,98,108,101,100,59,32,99,104,101,99,107,32,121,111,117,114,32,76,117,97,32,105,110,115,116,97,108,108,97,116,105,111,110,0,0,0,0,0,0,39,112,97,99,107,97,103,101,46,37,115,39,32,109,117,115,116,32,98,101,32,97,32,115,116,114,105,110,103,0,0,0,63,0,0,0,0,0,0,0,10,9,110,111,32,102,105,108,101,32,39,37,115,39,0,0,114,0,0,0,0,0,0,0,10,9,110,111,32,102,105,101,108,100,32,112,97,99,107,97,103,101,46,112,114,101,108,111,97,100,91,39,37,115,39,93,0,0,0,0,0,0,0,0,108,111,97,100,108,105,98,0,115,101,97,114,99,104,112,97,116,104,0,0,0,0,0,0,115,101,101,97,108,108,0,0,95,95,105,110,100,101,120,0,97,98,115,101,110,116,0,0,105,110,105,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,110,78,0,0,0,0,0,0,120,88,0,0,0,0,0,0,40,110,117,108,108,41,0,0,37,112,0,0,0,0,0,0,37,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,111,112,116,105,111,110,32,39,37,37,37,99,39,32,116,111,32,39,108,117,97,95,112,117,115,104,102,115,116,114,105,110,103,39,0,0,0,0,0,0,46,46,46,0,0,0,0,0,91,115,116,114,105,110,103,32,34,0,0,0,0,0,0,0,34,93,0,0,0,0,0,0,96,113,65,84,80,80,92,108,60,16,60,84,108,124,124,124,124,124,124,96,96,96,104,34,188,188,188,132,228,84,84,16,98,98,4,98,20,81,80,23,88,22,0,0,53,0,0,0,96,22,0,0,54,0,0,0,104,22,0,0,55,0,0,0,120,22,0,0,56,0,0,0,128,22,0,0,57,0,0,0,136,22,0,0,58,0,0,0,144,22,0,0,59,0,0,0,152,22,0,0,60,0,0,0,160,22,0,0,61,0,0,0,176,22,0,0,62,0,0,0,184,22,0,0,63,0,0,0,0,0,0,0,0,0,0,0,99,108,111,99,107,0,0,0,100,97,116,101,0,0,0,0,100,105,102,102,116,105,109,101,0,0,0,0,0,0,0,0,101,120,101,99,117,116,101,0,101,120,105,116,0,0,0,0,103,101,116,101,110,118,0,0,114,101,109,111,118,101,0,0,114,101,110,97,109,101,0,0,115,101,116,108,111,99,97,108,101,0,0,0,0,0,0,0,116,105,109,101,0,0,0,0,116,109,112,110,97,109,101,0,117,110,97,98,108,101,32,116,111,32,103,101,110,101,114,97,116,101,32,97,32,117,110,105,113,117,101,32,102,105,108,101,110,97,109,101,0,0,0,0,115,101,99,0,0,0,0,0,109,105,110,0,0,0,0,0,104,111,117,114,0,0,0,0,100,97,121,0,0,0,0,0,109,111,110,116,104,0,0,0,121,101,97,114,0,0,0,0,105,115,100,115,116,0,0,0,102,105,101,108,100,32,39,37,115,39,32,109,105,115,115,105,110,103,32,105,110,32,100,97,116,101,32,116,97,98,108,101,0,0,0,0,0,0,0,0,6,0,0,0,3,0,0,0,0,0,0,0,4,0,0,0,1,0,0,0,2,0,0,0,128,23,0,0,136,23,0,0,144,23,0,0,152,23,0,0,168,23,0,0,176,22,0,0,0,0,0,0,0,0,0,0,97,108,108,0,0,0,0,0,99,111,108,108,97,116,101,0,99,116,121,112,101,0,0,0,109,111,110,101,116,97,114,121,0,0,0,0,0,0,0,0,110,117,109,101,114,105,99,0,37,99,0,0,0,0,0,0,42,116,0,0,0,0,0,0,119,100,97,121,0,0,0,0,121,100,97,121,0,0,0,0,97,65,98,66,99,100,72,73,106,109,77,112,83,85,119,87,120,88,121,89,122,37,0,0,105,110,118,97,108,105,100,32,99,111,110,118,101,114,115,105,111,110,32,115,112,101,99,105,102,105,101,114,32,39,37,37,37,115,39,0,0,0,0,0,60,37,115,62,32,97,116,32,108,105,110,101,32,37,100,32,110,111,116,32,105,110,115,105,100,101,32,97,32,108,111,111,112,0,0,0,0,0,0,0,110,111,32,118,105,115,105,98,108,101,32,108,97,98,101,108,32,39,37,115,39,32,102,111,114,32,60,103,111,116,111,62,32,97,116,32,108,105,110,101,32,37,100,0,0,0,0,0,60,103,111,116,111,32,37,115,62,32,97,116,32,108,105,110,101,32,37,100,32,106,117,109,112,115,32,105,110,116,111,32,116,104,101,32,115,99,111,112,101,32,111,102,32,108,111,99,97,108,32,39,37,115,39,0,98,114,101,97,107,0,0,0,108,97,98,101,108,115,47,103,111,116,111,115,0,0,0,0,37,115,32,101,120,112,101,99,116,101,100,0,0,0,0,0,115,121,110,116,97,120,32,101,114,114,111,114,0,0,0,0,67,32,108,101,118,101,108,115,0,0,0,0,0,0,0,0,6,6,6,6,7,7,7,7,7,7,10,9,5,4,3,3,3,3,3,3,3,3,3,3,3,3,2,2,1,1,0,0,99,97,110,110,111,116,32,117,115,101,32,39,46,46,46,39,32,111,117,116,115,105,100,101,32,97,32,118,97,114,97,114,103,32,102,117,110,99,116,105,111,110,0,0,0,0,0,0,115,101,108,102,0,0,0,0,60,110,97,109,101,62,32,111,114,32,39,46,46,46,39,32,101,120,112,101,99,116,101,100,0,0,0,0,0,0,0,0,108,111,99,97,108,32,118,97,114,105,97,98,108,101,115,0,102,117,110,99,116,105,111,110,115,0,0,0,0,0,0,0,105,116,101,109,115,32,105,110,32,97,32,99,111,110,115,116,114,117,99,116,111,114,0,0,109,97,105,110,32,102,117,110,99,116,105,111,110,0,0,0,102,117,110,99,116,105,111,110,32,97,116,32,108,105,110,101,32,37,100,0,0,0,0,0,116,111,111,32,109,97,110,121,32,37,115,32,40,108,105,109,105,116,32,105,115,32,37,100,41,32,105,110,32,37,115,0,102,117,110,99,116,105,111,110,32,97,114,103,117,109,101,110,116,115,32,101,120,112,101,99,116,101,100,0,0,0,0,0,117,110,101,120,112,101,99,116,101,100,32,115,121,109,98,111,108,0,0,0,0,0,0,0,108,97,98,101,108,32,39,37,115,39,32,97,108,114,101,97,100,121,32,100,101,102,105,110,101,100,32,111,110,32,108,105,110,101,32,37,100,0,0,0,39,61,39,32,111,114,32,39,105,110,39,32,101,120,112,101,99,116,101,100,0,0,0,0,40,102,111,114,32,103,101,110,101,114,97,116,111,114,41,0,40,102,111,114,32,115,116,97,116,101,41,0,0,0,0,0,40,102,111,114,32,99,111,110,116,114,111,108,41,0,0,0,40,102,111,114,32,105,110,100,101,120,41,0,0,0,0,0,40,102,111,114,32,108,105,109,105,116,41,0,0,0,0,0,40,102,111,114,32,115,116,101,112,41,0,0,0,0,0,0,37,115,32,101,120,112,101,99,116,101,100,32,40,116,111,32,99,108,111,115,101,32,37,115,32,97,116,32,108,105,110,101,32,37,100,41,0,0,0,0,117,112,118,97,108,117,101,115,0,0,0,0,0,0,0,0,110,111,116,32,101,110,111,117,103,104,32,109,101,109,111,114,121,0,0,0,0,0,0,0,144,27,0,0,64,0,0,0,152,27,0,0,65,0,0,0,160,27,0,0,66,0,0,0,168,27,0,0,67,0,0,0,176,27,0,0,68,0,0,0,184,27,0,0,69,0,0,0,192,27,0,0,70,0,0,0,200,27,0,0,71,0,0,0,208,27,0,0,72,0,0,0,216,27,0,0,73,0,0,0,224,27,0,0,74,0,0,0,232,27,0,0,75,0,0,0,240,27,0,0,76,0,0,0,248,27,0,0,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,95,95,105,110,100,101,120,0,98,121,116,101,0,0,0,0,99,104,97,114,0,0,0,0,100,117,109,112,0,0,0,0,102,105,110,100,0,0,0,0,102,111,114,109,97,116,0,0,103,109,97,116,99,104,0,0,103,115,117,98,0,0,0,0,108,101,110,0,0,0,0,0,108,111,119,101,114,0,0,0,109,97,116,99,104,0,0,0,114,101,112,0,0,0,0,0,114,101,118,101,114,115,101,0,115,117,98,0,0,0,0,0,117,112,112,101,114,0,0,0,114,101,115,117,108,116,105,110,103,32,115,116,114,105,110,103,32,116,111,111,32,108,97,114,103,101,0,0,0,0,0,0,116,111,111,32,109,97,110,121,32,99,97,112,116,117,114,101,115,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,99,97,112,116,117,114,101,32,105,110,100,101,120,0,0,0,117,110,102,105,110,105,115,104,101,100,32,99,97,112,116,117,114,101,0,0,0,0,0,0,112,97,116,116,101,114,110,32,116,111,111,32,99,111,109,112,108,101,120,0,0,0,0,0,109,105,115,115,105,110,103,32,39,91,39,32,97,102,116,101,114,32,39,37,37,102,39,32,105,110,32,112,97,116,116,101,114,110,0,0,0,0,0,0,105,110,118,97,108,105,100,32,99,97,112,116,117,114,101,32,105,110,100,101,120,32,37,37,37,100,0,0,0,0,0,0,109,97,108,102,111,114,109,101,100,32,112,97,116,116,101,114,110,32,40,101,110,100,115,32,119,105,116,104,32,39,37,37,39,41,0,0,0,0,0,0,109,97,108,102,111,114,109,101,100,32,112,97,116,116,101,114,110,32,40,109,105,115,115,105,110,103,32,39,93,39,41,0,109,97,108,102,111,114,109,101,100,32,112,97,116,116,101,114,110,32,40,109,105,115,115,105,110,103,32,97,114,103,117,109,101,110,116,115,32,116,111,32,39,37,37,98,39,41,0,0,105,110,118,97,108,105,100,32,112,97,116,116,101,114,110,32,99,97,112,116,117,114,101,0,94,36,42,43,63,46,40,91,37,45,0,0,0,0,0,0,115,116,114,105,110,103,47,102,117,110,99,116,105,111,110,47,116,97,98,108,101,32,101,120,112,101,99,116,101,100,0,0,105,110,118,97,108,105,100,32,114,101,112,108,97,99,101,109,101,110,116,32,118,97,108,117,101,32,40,97,32,37,115,41,0,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,117,115,101,32,111,102,32,39,37,99,39,32,105,110,32,114,101,112,108,97,99,101,109,101,110,116,32,115,116,114,105,110,103,0,0,0,0,0,0,0,110,111,32,118,97,108,117,101,0,0,0,0,0,0,0,0,110,111,116,32,97,32,110,117,109,98,101,114,32,105,110,32,112,114,111,112,101,114,32,114,97,110,103,101,0,0,0,0,110,111,116,32,97,32,110,111,110,45,110,101,103,97,116,105,118,101,32,110,117,109,98,101,114,32,105,110,32,112,114,111,112,101,114,32,114,97,110,103,101,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,111,112,116,105,111,110,32,39,37,37,37,99,39,32,116,111,32,39,102,111,114,109,97,116,39,0,0,0,0,0,0,0,92,37,100,0,0,0,0,0,92,37,48,51,100,0,0,0,45,43,32,35,48,0,0,0,105,110,118,97,108,105,100,32,102,111,114,109,97,116,32,40,114,101,112,101,97,116,101,100,32,102,108,97,103,115,41,0,105,110,118,97,108,105,100,32,102,111,114,109,97,116,32,40,119,105,100,116,104,32,111,114,32,112,114,101,99,105,115,105,111,110,32,116,111,111,32,108,111,110,103,41,0,0,0,0,117,110,97,98,108,101,32,116,111,32,100,117,109,112,32,103,105,118,101,110,32,102,117,110,99,116,105,111,110,0,0,0,118,97,108,117,101,32,111,117,116,32,111,102,32,114,97,110,103,101,0,0,0,0,0,0,115,116,114,105,110,103,32,115,108,105,99,101,32,116,111,111,32,108,111,110,103,0,0,0,116,97,98,108,101,32,105,110,100,101,120,32,105,115,32,110,105,108,0,0,0,0,0,0,116,97,98,108,101,32,105,110,100,101,120,32,105,115,32,78,97,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,116,97,98,108,101,32,111,118,101,114,102,108,111,119,0,0,105,110,118,97,108,105,100,32,107,101,121,32,116,111,32,39,110,101,120,116,39,0,0,0,224,31,0,0,78,0,0,0,232,31,0,0,79,0,0,0,240,31,0,0,80,0,0,0,248,31,0,0,81,0,0,0,216,31,0,0,82,0,0,0,0,32,0,0,83,0,0,0,8,32,0,0,84,0,0,0,0,0,0,0,0,0,0,0,117,110,112,97,99,107,0,0,99,111,110,99,97,116,0,0,109,97,120,110,0,0,0,0,105,110,115,101,114,116,0,0,112,97,99,107,0,0,0,0,114,101,109,111,118,101,0,0,115,111,114,116,0,0,0,0,0,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,111,114,100,101,114,32,102,117,110,99,116,105,111,110,32,102,111,114,32,115,111,114,116,105,110,103,0,0,0,0,0,0,112,111,115,105,116,105,111,110,32,111,117,116,32,111,102,32,98,111,117,110,100,115,0,0,116,111,111,32,109,97,110,121,32,114,101,115,117,108,116,115,32,116,111,32,117,110,112,97,99,107,0,0,0,0,0,0,110,0,0,0,0,0,0,0,119,114,111,110,103,32,110,117,109,98,101,114,32,111,102,32,97,114,103,117,109,101,110,116,115,32,116,111,32,39,105,110,115,101,114,116,39,0,0,0,105,110,118,97,108,105,100,32,118,97,108,117,101,32,40,37,115,41,32,97,116,32,105,110,100,101,120,32,37,100,32,105,110,32,116,97,98,108,101,32,102,111,114,32,39,99,111,110,99,97,116,39,0,0,0,0,110,111,32,118,97,108,117,101,0,0,0,0,0,0,0,0,110,105,108,0,0,0,0,0,98,111,111,108,101,97,110,0,117,115,101,114,100,97,116,97,0,0,0,0,0,0,0,0,110,117,109,98,101,114,0,0,115,116,114,105,110,103,0,0,116,97,98,108,101,0,0,0,102,117,110,99,116,105,111,110,0,0,0,0,0,0,0,0,116,104,114,101,97,100,0,0,112,114,111,116,111,0,0,0,117,112,118,97,108,0,0,0,224,32,0,0,240,32,0,0,248,32,0,0,0,33,0,0,16,33,0,0,24,33,0,0,32,33,0,0,40,33,0,0,0,33,0,0,56,33,0,0,64,33,0,0,72,33,0,0,200,33,0,0,208,33,0,0,224,33,0,0,232,33,0,0,240,33,0,0,248,33,0,0,0,34,0,0,8,34,0,0,16,34,0,0,24,34,0,0,32,34,0,0,40,34,0,0,48,34,0,0,56,34,0,0,64,34,0,0,72,34,0,0,88,34,0,0,0,0,0,0,95,95,105,110,100,101,120,0,95,95,110,101,119,105,110,100,101,120,0,0,0,0,0,0,95,95,103,99,0,0,0,0,95,95,109,111,100,101,0,0,95,95,108,101,110,0,0,0,95,95,101,113,0,0,0,0,95,95,97,100,100,0,0,0,95,95,115,117,98,0,0,0,95,95,109,117,108,0,0,0,95,95,100,105,118,0,0,0,95,95,109,111,100,0,0,0,95,95,112,111,119,0,0,0,95,95,117,110,109,0,0,0,95,95,108,116,0,0,0,0,95,95,108,101,0,0,0,0,95,95,99,111,110,99,97,116,0,0,0,0,0,0,0,0,95,95,99,97,108,108,0,0,98,105,110,97,114,121,32,115,116,114,105,110,103,0,0,0,25,147,13,10,26,10,0,0,116,114,117,110,99,97,116,101,100,0,0,0,0,0,0,0,37,115,58,32,37,115,32,112,114,101,99,111,109,112,105,108,101,100,32,99,104,117,110,107,0,0,0,0,0,0,0,0,99,111,114,114,117,112,116,101,100,0,0,0,0,0,0,0,110,111,116,32,97,0,0,0,118,101,114,115,105,111,110,32,109,105,115,109,97,116,99,104,32,105,110,0,0,0,0,0,105,110,99,111,109,112,97,116,105,98,108,101,0,0,0,0,37,46,49,52,103,0,0,0,105,110,100,101,120,0,0,0,108,111,111,112,32,105,110,32,103,101,116,116,97,98,108,101,0,0,0,0,0,0,0,0,108,111,111,112,32,105,110,32,115,101,116,116,97,98,108,101,0,0,0,0,0,0,0,0,115,116,114,105,110,103,32,108,101,110,103,116,104,32,111,118,101,114,102,108,111,119,0,0,103,101,116,32,108,101,110,103,116,104,32,111,102,0,0,0,39,102,111,114,39,32,105,110,105,116,105,97,108,32,118,97,108,117,101,32,109,117,115,116,32,98,101,32,97,32,110,117,109,98,101,114,0,0,0,0,39,102,111,114,39,32,108,105,109,105,116,32,109,117,115,116,32,98,101,32,97,32,110,117,109,98,101,114,0,0,0,0,39,102,111,114,39,32,115,116,101,112,32,109,117,115,116,32,98,101,32,97,32,110,117,109,98,101,114,0,0,0,0,0,95,71,0,0,0,0,0,0,152,36,0,0,85,0,0,0,160,36,0,0,86,0,0,0,176,36,0,0,87,0,0,0,184,36,0,0,88,0,0,0,192,36,0,0,89,0,0,0,208,36,0,0,90,0,0,0,216,36,0,0,91,0,0,0,232,36,0,0,92,0,0,0,240,36,0,0,92,0,0,0,0,37,0,0,93,0,0,0,8,37,0,0,94,0,0,0,16,37,0,0,95,0,0,0,24,37,0,0,96,0,0,0,32,37,0,0,97,0,0,0,48,37,0,0,98,0,0,0,56,37,0,0,99,0,0,0,64,37,0,0,100,0,0,0,72,37,0,0,101,0,0,0,80,37,0,0,102,0,0,0,96,37,0,0,103,0,0,0,112,37,0,0,104,0,0,0,128,37,0,0,105,0,0,0,136,37,0,0,106,0,0,0,0,0,0,0,0,0,0,0,76,117,97,32,53,46,50,0,95,86,69,82,83,73,79,78,0,0,0,0,0,0,0,0,97,115,115,101,114,116,0,0,99,111,108,108,101,99,116,103,97,114,98,97,103,101,0,0,100,111,102,105,108,101,0,0,101,114,114,111,114,0,0,0,103,101,116,109,101,116,97,116,97,98,108,101,0,0,0,0,105,112,97,105,114,115,0,0,108,111,97,100,102,105,108,101,0,0,0,0,0,0,0,0,108,111,97,100,0,0,0,0,108,111,97,100,115,116,114,105,110,103,0,0,0,0,0,0,110,101,120,116,0,0,0,0,112,97,105,114,115,0,0,0,112,99,97,108,108,0,0,0,112,114,105,110,116,0,0,0,114,97,119,101,113,117,97,108,0,0,0,0,0,0,0,0,114,97,119,108,101,110,0,0,114,97,119,103,101,116,0,0,114,97,119,115,101,116,0,0,115,101,108,101,99,116,0,0,115,101,116,109,101,116,97,116,97,98,108,101,0,0,0,0,116,111,110,117,109,98,101,114,0,0,0,0,0,0,0,0,116,111,115,116,114,105,110,103,0,0,0,0,0,0,0,0,116,121,112,101,0,0,0,0,120,112,99,97,108,108,0,0,118,97,108,117,101,32,101,120,112,101,99,116,101,100,0,0,115,116,97,99,107,32,111,118,101,114,102,108,111,119,0,0,98,97,115,101,32,111,117,116,32,111,102,32,114,97,110,103,101,0,0,0,0,0,0,0,32,12,10,13,9,11,0,0,110,105,108,32,111,114,32,116,97,98,108,101,32,101,120,112,101,99,116,101,100,0,0,0,95,95,109,101,116,97,116,97,98,108,101,0,0,0,0,0,99,97,110,110,111,116,32,99,104,97,110,103,101,32,97,32,112,114,111,116,101,99,116,101,100,32,109,101,116,97,116,97,98,108,101,0,0,0,0,0,105,110,100,101,120,32,111,117,116,32,111,102,32,114,97,110,103,101,0,0,0,0,0,0,116,97,98,108,101,32,111,114,32,115,116,114,105,110,103,32,101,120,112,101,99,116,101,100,0,0,0,0,0,0,0,0,39,116,111,115,116,114,105,110,103,39,32,109,117,115,116,32,114,101,116,117,114,110,32,97,32,115,116,114,105,110,103,32,116,111,32,39,112,114,105,110,116,39,0,0,0,0,0,0,95,95,112,97,105,114,115,0,98,116,0,0,0,0,0,0,61,40,108,111,97,100,41,0,116,111,111,32,109,97,110,121,32,110,101,115,116,101,100,32,102,117,110,99,116,105,111,110,115,0,0,0,0,0,0,0,114,101,97,100,101,114,32,102,117,110,99,116,105,111,110,32,109,117,115,116,32,114,101,116,117,114,110,32,97,32,115,116,114,105,110,103,0,0,0,0,95,95,105,112,97,105,114,115,0,0,0,0,0,0,0,0,40,39,0,0,48,39,0,0,56,39,0,0,64,39,0,0,72,39,0,0,80,39,0,0,96,39,0,0,112,39,0,0,128,39,0,0,144,39,0,0,160,39,0,0,0,0,0,0,115,116,111,112,0,0,0,0,114,101,115,116,97,114,116,0,99,111,108,108,101,99,116,0,99,111,117,110,116,0,0,0,115,116,101,112,0,0,0,0,115,101,116,112,97,117,115,101,0,0,0,0,0,0,0,0,115,101,116,115,116,101,112,109,117,108,0,0,0,0,0,0,115,101,116,109,97,106,111,114,105,110,99,0,0,0,0,0,105,115,114,117,110,110,105,110,103,0,0,0,0,0,0,0,103,101,110,101,114,97,116,105,111,110,97,108,0,0,0,0,105,110,99,114,101,109,101,110,116,97,108,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,5,0,0,0,6,0,0,0,7,0,0,0,8,0,0,0,9,0,0,0,10,0,0,0,11,0,0,0,0,0,0,0,37,115,0,0,0,0,0,0,97,115,115,101,114,116,105,111,110,32,102,97,105,108,101,100,33,0,0,0,0,0,0,0,104,40,0,0,107], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+/* memory initializer */ allocate([112,40,0,0,108,0,0,0,120,40,0,0,109,0,0,0,128,40,0,0,110,0,0,0,136,40,0,0,111,0,0,0,144,40,0,0,112,0,0,0,152,40,0,0,113,0,0,0,160,40,0,0,114,0,0,0,168,40,0,0,115,0,0,0,176,40,0,0,116,0,0,0,184,40,0,0,117,0,0,0,192,40,0,0,118,0,0,0,0,0,0,0,0,0,0,0,97,114,115,104,105,102,116,0,98,97,110,100,0,0,0,0,98,110,111,116,0,0,0,0,98,111,114,0,0,0,0,0,98,120,111,114,0,0,0,0,98,116,101,115,116,0,0,0,101,120,116,114,97,99,116,0,108,114,111,116,97,116,101,0,108,115,104,105,102,116,0,0,114,101,112,108,97,99,101,0,114,114,111,116,97,116,101,0,114,115,104,105,102,116,0,0,102,105,101,108,100,32,99,97,110,110,111,116,32,98,101,32,110,101,103,97,116,105,118,101,0,0,0,0,0,0,0,0,119,105,100,116,104,32,109,117,115,116,32,98,101,32,112,111,115,105,116,105,118,101,0,0,116,114,121,105,110,103,32,116,111,32,97,99,99,101,115,115,32,110,111,110,45,101,120,105,115,116,101,110,116,32,98,105,116,115,0,0,0,0,0,0,102,117,110,99,116,105,111,110,32,111,114,32,101,120,112,114,101,115,115,105,111,110,32,116,111,111,32,99,111,109,112,108,101,120,0,0,0,0,0,0,99,111,110,115,116,114,117,99,116,111,114,32,116,111,111,32,108,111,110,103,0,0,0,0,99,111,110,115,116,97,110,116,115,0,0,0,0,0,0,0,111,112,99,111,100,101,115,0,99,111,110,116,114,111,108,32,115,116,114,117,99,116,117,114,101,32,116,111,111,32,108,111,110,103,0,0,0,0,0,0,216,41,0,0,119,0,0,0,224,41,0,0,120,0,0,0,232,41,0,0,121,0,0,0,240,41,0,0,122,0,0,0,248,41,0,0,123,0,0,0,0,42,0,0,124,0,0,0,0,0,0,0,0,0,0,0,99,114,101,97,116,101,0,0,114,101,115,117,109,101,0,0,114,117,110,110,105,110,103,0,115,116,97,116,117,115,0,0,119,114,97,112,0,0,0,0,121,105,101,108,100,0,0,0,116,111,111,32,109,97,110,121,32,97,114,103,117,109,101,110,116,115,32,116,111,32,114,101,115,117,109,101,0,0,0,0,99,97,110,110,111,116,32,114,101,115,117,109,101,32,100,101,97,100,32,99,111,114,111,117,116,105,110,101,0,0,0,0,116,111,111,32,109,97,110,121,32,114,101,115,117,108,116,115,32,116,111,32,114,101,115,117,109,101,0,0,0,0,0,0,99,111,114,111,117,116,105,110,101,32,101,120,112,101,99,116,101,100,0,0,0,0,0,0,115,117,115,112,101,110,100,101,100,0,0,0,0,0,0,0,110,111,114,109,97,108,0,0,100,101,97,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,8,8,8,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,22,22,22,22,22,22,22,22,22,22,4,4,4,4,4,4,4,21,21,21,21,21,21,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,5,4,21,21,21,21,21,21,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,44,0,0,125,0,0,0,56,44,0,0,126,0,0,0,72,44,0,0,127,0,0,0,80,44,0,0,128,0,0,0,88,44,0,0,129,0,0,0,104,44,0,0,130,0,0,0,120,44,0,0,131,0,0,0,136,44,0,0,132,0,0,0,152,44,0,0,133,0,0,0,168,44,0,0,134,0,0,0,184,44,0,0,135,0,0,0,200,44,0,0,136,0,0,0,208,44,0,0,137,0,0,0,224,44,0,0,138,0,0,0,240,44,0,0,139,0,0,0,0,45,0,0,140,0,0,0,0,0,0,0,0,0,0,0,100,101,98,117,103,0,0,0,103,101,116,117,115,101,114,118,97,108,117,101,0,0,0,0,103,101,116,104,111,111,107,0,103,101,116,105,110,102,111,0,103,101,116,108,111,99,97,108,0,0,0,0,0,0,0,0,103,101,116,114,101,103,105,115,116,114,121,0,0,0,0,0,103,101,116,109,101,116,97,116,97,98,108,101,0,0,0,0,103,101,116,117,112,118,97,108,117,101,0,0,0,0,0,0,117,112,118,97,108,117,101,106,111,105,110,0,0,0,0,0,117,112,118,97,108,117,101,105,100,0,0,0,0,0,0,0,115,101,116,117,115,101,114,118,97,108,117,101,0,0,0,0,115,101,116,104,111,111,107,0,115,101,116,108,111,99,97,108,0,0,0,0,0,0,0,0,115,101,116,109,101,116,97,116,97,98,108,101,0,0,0,0,115,101,116,117,112,118,97,108,117,101,0,0,0,0,0,0,116,114,97,99,101,98,97,99,107,0,0,0,0,0,0,0,110,105,108,32,111,114,32,116,97,98,108,101,32,101,120,112,101,99,116,101,100,0,0,0,108,101,118,101,108,32,111,117,116,32,111,102,32,114,97,110,103,101,0,0,0,0,0,0,95,72,75,69,89,0,0,0,107,0,0,0,0,0,0,0,95,95,109,111,100,101,0,0,112,45,0,0,120,45,0,0,128,45,0,0,136,45,0,0,144,45,0,0,0,0,0,0,99,97,108,108,0,0,0,0,114,101,116,117,114,110,0,0,108,105,110,101,0,0,0,0,99,111,117,110,116,0,0,0,116,97,105,108,32,99,97,108,108,0,0,0,0,0,0,0,102,117,108,108,32,117,115,101,114,100,97,116,97,32,101,120,112,101,99,116,101,100,44,32,103,111,116,32,108,105,103,104,116,32,117,115,101,114,100,97,116,97,0,0,0,0,0,0,62,117,0,0,0,0,0,0,105,110,118,97,108,105,100,32,117,112,118,97,108,117,101,32,105,110,100,101,120,0,0,0,76,117,97,32,102,117,110,99,116,105,111,110,32,101,120,112,101,99,116,101,100,0,0,0,102,108,110,83,116,117,0,0,62,37,115,0,0,0,0,0,102,117,110,99,116,105,111,110,32,111,114,32,108,101,118,101,108,32,101,120,112,101,99,116,101,100,0,0,0,0,0,0,105,110,118,97,108,105,100,32,111,112,116,105,111,110,0,0,115,111,117,114,99,101,0,0,115,104,111,114,116,95,115,114,99,0,0,0,0,0,0,0,108,105,110,101,100,101,102,105,110,101,100,0,0,0,0,0,108,97,115,116,108,105,110,101,100,101,102,105,110,101,100,0,119,104,97,116,0,0,0,0,99,117,114,114,101,110,116,108,105,110,101,0,0,0,0,0,110,117,112,115,0,0,0,0,110,112,97,114,97,109,115,0,105,115,118,97,114,97,114,103,0,0,0,0,0,0,0,0,110,97,109,101,0,0,0,0,110,97,109,101,119,104,97,116,0,0,0,0,0,0,0,0,105,115,116,97,105,108,99,97,108,108,0,0,0,0,0,0,97,99,116,105,118,101,108,105,110,101,115,0,0,0,0,0,102,117,110,99,0,0,0,0,101,120,116,101,114,110,97,108,32,104,111,111,107,0,0,0,108,117,97,95,100,101,98,117,103,62,32,0,0,0,0,0,99,111,110,116,10,0,0,0,61,40,100,101,98,117,103,32,99,111,109,109,97,110,100,41,0,0,0,0,0,0,0,0,37,115,10,0,0,0,0,0,80,49,0,0,88,49,0,0,96,49,0,0,104,49,0,0,112,49,0,0,120,49,0,0,128,49,0,0,136,49,0,0,144,49,0,0,160,49,0,0,168,49,0,0,176,49,0,0,184,49,0,0,192,49,0,0,200,49,0,0,208,49,0,0,216,49,0,0,224,49,0,0,232,49,0,0,240,49,0,0,248,49,0,0,0,50,0,0,8,50,0,0,16,50,0,0,24,50,0,0,32,50,0,0,40,50,0,0,48,50,0,0,56,50,0,0,64,50,0,0,72,50,0,0,88,50,0,0,96,50,0,0,0,0,0,0,39,37,99,39,0,0,0,0,99,104,97,114,40,37,100,41,0,0,0,0,0,0,0,0,39,37,115,39,0,0,0,0,95,69,78,86,0,0,0,0,105,110,118,97,108,105,100,32,108,111,110,103,32,115,116,114,105,110,103,32,100,101,108,105,109,105,116,101,114,0,0,0,46,0,0,0,0,0,0,0,69,101,0,0,0,0,0,0,88,120,0,0,0,0,0,0,80,112,0,0,0,0,0,0,43,45,0,0,0,0,0,0,109,97,108,102,111,114,109,101,100,32,110,117,109,98,101,114,0,0,0,0,0,0,0,0,108,101,120,105,99,97,108,32,101,108,101,109,101,110,116,32,116,111,111,32,108,111,110,103,0,0,0,0,0,0,0,0,117,110,102,105,110,105,115,104,101,100,32,115,116,114,105,110,103,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,0,100,101,99,105,109,97,108,32,101,115,99,97,112,101,32,116,111,111,32,108,97,114,103,101,0,0,0,0,0,0,0,0,104,101,120,97,100,101,99,105,109,97,108,32,100,105,103,105,116,32,101,120,112,101,99,116,101,100,0,0,0,0,0,0,117,110,102,105,110,105,115,104,101,100,32,108,111,110,103,32,115,116,114,105,110,103,0,0,117,110,102,105,110,105,115,104,101,100,32,108,111,110,103,32,99,111,109,109,101,110,116,0,99,104,117,110,107,32,104,97,115,32,116,111,111,32,109,97,110,121,32,108,105,110,101,115,0,0,0,0,0,0,0,0,37,115,58,37,100,58,32,37,115,0,0,0,0,0,0,0,37,115,32,110,101,97,114,32,37,115,0,0,0,0,0,0,97,110,100,0,0,0,0,0,98,114,101,97,107,0,0,0,100,111,0,0,0,0,0,0,101,108,115,101,0,0,0,0,101,108,115,101,105,102,0,0,101,110,100,0,0,0,0,0,102,97,108,115,101,0,0,0,102,111,114,0,0,0,0,0,102,117,110,99,116,105,111,110,0,0,0,0,0,0,0,0,103,111,116,111,0,0,0,0,105,102,0,0,0,0,0,0,105,110,0,0,0,0,0,0,108,111,99,97,108,0,0,0,110,105,108,0,0,0,0,0,110,111,116,0,0,0,0,0,111,114,0,0,0,0,0,0,114,101,112,101,97,116,0,0,114,101,116,117,114,110,0,0,116,104,101,110,0,0,0,0,116,114,117,101,0,0,0,0,117,110,116,105,108,0,0,0,119,104,105,108,101,0,0,0,46,46,0,0,0,0,0,0,46,46,46,0,0,0,0,0,61,61,0,0,0,0,0,0,62,61,0,0,0,0,0,0,60,61,0,0,0,0,0,0,126,61,0,0,0,0,0,0,58,58,0,0,0,0,0,0,60,101,111,102,62,0,0,0,60,110,117,109,98,101,114,62,0,0,0,0,0,0,0,0,60,110,97,109,101,62,0,0,60,115,116,114,105,110,103,62,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,105,110,102,105,110,105,116,121,0,0,0,0,0,0,0,0,110,97,110,0,0,0,0,0,95,112,137,0,255,9,47,15,10,0,0,0,100,0,0,0,232,3,0,0,16,39,0,0,160,134,1,0,64,66,15,0,128,150,152,0,0,225,245,5], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE+10240);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+
+
+  Module["_rand_r"] = _rand_r;
+
+  var ___rand_seed=allocate([0x0273459b, 0, 0, 0], "i32", ALLOC_STATIC);
+  Module["_rand"] = _rand;
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};
+
+  function _lseek(fildes, offset, whence) {
+      // off_t lseek(int fildes, off_t offset, int whence);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/lseek.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        return FS.llseek(stream, offset, whence);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fseek(stream, offset, whence) {
+      // int fseek(FILE *stream, long offset, int whence);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fseek.html
+      var fd = _fileno(stream);
+      var ret = _lseek(fd, offset, whence);
+      if (ret == -1) {
+        return -1;
+      }
+      stream = FS.getStreamFromPtr(stream);
+      stream.eof = false;
+      return 0;
+    }
+
+
+  Module["_i64Subtract"] = _i64Subtract;
+
+
+  Module["_i64Add"] = _i64Add;
+
+  function _setlocale(category, locale) {
+      if (!_setlocale.ret) _setlocale.ret = allocate([0], 'i8', ALLOC_NORMAL);
+      return _setlocale.ret;
+    }
+
+
+  function _close(fildes) {
+      // int close(int fildes);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/close.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        FS.close(stream);
+        return 0;
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fsync(fildes) {
+      // int fsync(int fildes);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fsync.html
+      var stream = FS.getStream(fildes);
+      if (stream) {
+        // We write directly to the file system, so there's nothing to do here.
+        return 0;
+      } else {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+    }function _fclose(stream) {
+      // int fclose(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fclose.html
+      var fd = _fileno(stream);
+      _fsync(fd);
+      return _close(fd);
+    }
+
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _recv(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _read(fd, buf, len);
+    }
+
+  function _pread(fildes, buf, nbyte, offset) {
+      // ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/read.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.read(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _read(fildes, buf, nbyte) {
+      // ssize_t read(int fildes, void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/read.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.read(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _fread(ptr, size, nitems, stream) {
+      // size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fread.html
+      var bytesToRead = nitems * size;
+      if (bytesToRead == 0) {
+        return 0;
+      }
+      var bytesRead = 0;
+      var streamObj = FS.getStreamFromPtr(stream);
+      if (!streamObj) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return 0;
+      }
+      while (streamObj.ungotten.length && bytesToRead > 0) {
+        HEAP8[((ptr++)|0)]=streamObj.ungotten.pop();
+        bytesToRead--;
+        bytesRead++;
+      }
+      var err = _read(streamObj.fd, ptr, bytesToRead);
+      if (err == -1) {
+        if (streamObj) streamObj.error = true;
+        return 0;
+      }
+      bytesRead += err;
+      if (bytesRead < bytesToRead) streamObj.eof = true;
+      return Math.floor(bytesRead / size);
+    }
+
+  function _toupper(chr) {
+      if (chr >= 97 && chr <= 122) {
+        return chr - 97 + 65;
+      } else {
+        return chr;
+      }
+    }
+
+
+
+  function _open(path, oflag, varargs) {
+      // int open(const char *path, int oflag, ...);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html
+      var mode = HEAP32[((varargs)>>2)];
+      path = Pointer_stringify(path);
+      try {
+        var stream = FS.open(path, oflag, mode);
+        return stream.fd;
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _fopen(filename, mode) {
+      // FILE *fopen(const char *restrict filename, const char *restrict mode);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fopen.html
+      var flags;
+      mode = Pointer_stringify(mode);
+      if (mode[0] == 'r') {
+        if (mode.indexOf('+') != -1) {
+          flags = 2;
+        } else {
+          flags = 0;
+        }
+      } else if (mode[0] == 'w') {
+        if (mode.indexOf('+') != -1) {
+          flags = 2;
+        } else {
+          flags = 1;
+        }
+        flags |= 64;
+        flags |= 512;
+      } else if (mode[0] == 'a') {
+        if (mode.indexOf('+') != -1) {
+          flags = 2;
+        } else {
+          flags = 1;
+        }
+        flags |= 64;
+        flags |= 1024;
+      } else {
+        ___setErrNo(ERRNO_CODES.EINVAL);
+        return 0;
+      }
+      var fd = _open(filename, flags, allocate([0x1FF, 0, 0, 0], 'i32', ALLOC_STACK));  // All creation permissions.
+      return fd === -1 ? 0 : FS.getPtrForStream(FS.getStream(fd));
+    }
+
+  var _emscripten_check_longjmp=true;
+
+
+
+  function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _fputc(c, stream) {
+      // int fputc(int c, FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html
+      var chr = unSign(c & 0xFF);
+      HEAP8[((_fputc.ret)|0)]=chr;
+      var fd = _fileno(stream);
+      var ret = _write(fd, _fputc.ret, 1);
+      if (ret == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return -1;
+      } else {
+        return chr;
+      }
+    }
+
+  var _log=Math_log;
+
+  var _emscripten_postinvoke=true;
+
+
+  function _putchar(c) {
+      // int putchar(int c);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/putchar.html
+      return _fputc(c, HEAP32[((_stdout)>>2)]);
+    }
+  Module["_saveSetjmp"] = _saveSetjmp;
+
+  function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+  function _system(command) {
+      // int system(const char *command);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/system.html
+      // Can't call external programs.
+      ___setErrNo(ERRNO_CODES.EAGAIN);
+      return -1;
+    }
+
+  function _frexp(x, exp_addr) {
+      var sig = 0, exp_ = 0;
+      if (x !== 0) {
+        var sign = 1;
+        if (x < 0) {
+          x = -x;
+          sign = -1;
+        }
+        var raw_exp = Math.log(x)/Math.log(2);
+        exp_ = Math.ceil(raw_exp);
+        if (exp_ === raw_exp) exp_ += 1;
+        sig = sign*x/Math.pow(2, exp_);
+      }
+      HEAP32[((exp_addr)>>2)]=exp_;
+      return sig;
+    }
+
+
+
+  var _tzname=allocate(8, "i32*", ALLOC_STATIC);
+
+  var _daylight=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _timezone=allocate(1, "i32*", ALLOC_STATIC);function _tzset() {
+      // TODO: Use (malleable) environment variables instead of system settings.
+      if (_tzset.called) return;
+      _tzset.called = true;
+
+      HEAP32[((_timezone)>>2)]=-(new Date()).getTimezoneOffset() * 60;
+
+      var winter = new Date(2000, 0, 1);
+      var summer = new Date(2000, 6, 1);
+      HEAP32[((_daylight)>>2)]=Number(winter.getTimezoneOffset() != summer.getTimezoneOffset());
+
+      var winterName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | winter.toString().match(/\(([A-Z]+)\)/)[1];
+      var summerName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | summer.toString().match(/\(([A-Z]+)\)/)[1];
+      var winterNamePtr = allocate(intArrayFromString(winterName), 'i8', ALLOC_NORMAL);
+      var summerNamePtr = allocate(intArrayFromString(summerName), 'i8', ALLOC_NORMAL);
+      HEAP32[((_tzname)>>2)]=winterNamePtr;
+      HEAP32[(((_tzname)+(4))>>2)]=summerNamePtr;
+    }function _mktime(tmPtr) {
+      _tzset();
+      var year = HEAP32[(((tmPtr)+(20))>>2)];
+      var timestamp = new Date(year >= 1900 ? year : year + 1900,
+                               HEAP32[(((tmPtr)+(16))>>2)],
+                               HEAP32[(((tmPtr)+(12))>>2)],
+                               HEAP32[(((tmPtr)+(8))>>2)],
+                               HEAP32[(((tmPtr)+(4))>>2)],
+                               HEAP32[((tmPtr)>>2)],
+                               0).getTime() / 1000;
+      HEAP32[(((tmPtr)+(24))>>2)]=new Date(timestamp).getDay();
+      var yday = Math.round((timestamp - (new Date(year, 0, 1)).getTime()) / (1000 * 60 * 60 * 24));
+      HEAP32[(((tmPtr)+(28))>>2)]=yday;
+      return timestamp;
+    }
+
+  function _isalpha(chr) {
+      return (chr >= 97 && chr <= 122) ||
+             (chr >= 65 && chr <= 90);
+    }
+
+
+  function _malloc(bytes) {
+      /* Over-allocate to make sure it is byte-aligned by 8.
+       * This will leak memory, but this is only the dummy
+       * implementation (replaced by dlmalloc normally) so
+       * not an issue.
+       */
+      var ptr = Runtime.dynamicAlloc(bytes + 8);
+      return (ptr+8) & 0xFFFFFFF8;
+    }
+  Module["_malloc"] = _malloc;function _tmpnam(s, dir, prefix) {
+      // char *tmpnam(char *s);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/tmpnam.html
+      // NOTE: The dir and prefix arguments are for internal use only.
+      var folder = FS.findObject(dir || '/tmp');
+      if (!folder || !folder.isFolder) {
+        dir = '/tmp';
+        folder = FS.findObject(dir);
+        if (!folder || !folder.isFolder) return 0;
+      }
+      var name = prefix || 'file';
+      do {
+        name += String.fromCharCode(65 + Math.floor(Math.random() * 25));
+      } while (name in folder.contents);
+      var result = dir + '/' + name;
+      if (!_tmpnam.buffer) _tmpnam.buffer = _malloc(256);
+      if (!s) s = _tmpnam.buffer;
+      writeAsciiToMemory(result, s);
+      return s;
+    }
+
+  var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+            Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+            Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+            // just add the mouse delta to the current absolut mouse position
+            // FIXME: ideally this should be clamped against the canvas size and zero
+            Browser.mouseX += Browser.mouseMovementX;
+            Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+  function _log10(x) {
+      return Math.log(x) / Math.LN10;
+    }
+
+  function _isspace(chr) {
+      return (chr == 32) || (chr >= 9 && chr <= 13);
+    }
+
+
+  var ___tm_current=allocate(44, "i8", ALLOC_STATIC);
+
+
+  var ___tm_timezone=allocate(intArrayFromString("GMT"), "i8", ALLOC_STATIC);function _localtime_r(time, tmPtr) {
+      _tzset();
+      var date = new Date(HEAP32[((time)>>2)]*1000);
+      HEAP32[((tmPtr)>>2)]=date.getSeconds();
+      HEAP32[(((tmPtr)+(4))>>2)]=date.getMinutes();
+      HEAP32[(((tmPtr)+(8))>>2)]=date.getHours();
+      HEAP32[(((tmPtr)+(12))>>2)]=date.getDate();
+      HEAP32[(((tmPtr)+(16))>>2)]=date.getMonth();
+      HEAP32[(((tmPtr)+(20))>>2)]=date.getFullYear()-1900;
+      HEAP32[(((tmPtr)+(24))>>2)]=date.getDay();
+
+      var start = new Date(date.getFullYear(), 0, 1);
+      var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
+      HEAP32[(((tmPtr)+(28))>>2)]=yday;
+      HEAP32[(((tmPtr)+(36))>>2)]=start.getTimezoneOffset() * 60;
+
+      var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset());
+      HEAP32[(((tmPtr)+(32))>>2)]=dst;
+
+      HEAP32[(((tmPtr)+(40))>>2)]=___tm_timezone;
+
+      return tmPtr;
+    }function _localtime(time) {
+      return _localtime_r(time, ___tm_current);
+    }
+
+  function _srand(seed) {
+      HEAP32[((___rand_seed)>>2)]=seed
+    }
+
+  var _emscripten_prep_setjmp=true;
+
+
+
+
+  Module["_testSetjmp"] = _testSetjmp;function _longjmp(env, value) {
+      asm['setThrew'](env, value || 1);
+      throw 'longjmp';
+    }function _emscripten_longjmp(env, value) {
+      _longjmp(env, value);
+    }
+
+  var _ceil=Math_ceil;
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+
+  var _llvm_pow_f64=Math_pow;
+
+
+
+  Module["_strlen"] = _strlen;function _fputs(s, stream) {
+      // int fputs(const char *restrict s, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputs.html
+      var fd = _fileno(stream);
+      return _write(fd, s, _strlen(s));
+    }
+
+  function _sbrk(bytes) {
+      // Implement a Linux-like 'memory area' for our 'process'.
+      // Changes the size of the memory area by |bytes|; returns the
+      // address of the previous top ('break') of the memory area
+      // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
+      var self = _sbrk;
+      if (!self.called) {
+        DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
+        self.called = true;
+        assert(Runtime.dynamicAlloc);
+        self.alloc = Runtime.dynamicAlloc;
+        Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
+      }
+      var ret = DYNAMICTOP;
+      if (bytes != 0) self.alloc(bytes);
+      return ret;  // Previous break location.
+    }
+
+
+  function _sinh(x) {
+      var p = Math.pow(Math.E, x);
+      return (p - (1 / p)) / 2;
+    }
+
+  function _cosh(x) {
+      var p = Math.pow(Math.E, x);
+      return (p + (1 / p)) / 2;
+    }function _tanh(x) {
+      return _sinh(x) / _cosh(x);
+    }
+
+  function _signal(sig, func) {
+      // TODO
+      return 0;
+    }
+
+
+
+  function __getFloat(text) {
+      return /^[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?/.exec(text);
+    }function __scanString(format, get, unget, varargs) {
+      if (!__scanString.whiteSpace) {
+        __scanString.whiteSpace = {};
+        __scanString.whiteSpace[32] = 1;
+        __scanString.whiteSpace[9] = 1;
+        __scanString.whiteSpace[10] = 1;
+        __scanString.whiteSpace[11] = 1;
+        __scanString.whiteSpace[12] = 1;
+        __scanString.whiteSpace[13] = 1;
+      }
+      // Supports %x, %4x, %d.%d, %lld, %s, %f, %lf.
+      // TODO: Support all format specifiers.
+      format = Pointer_stringify(format);
+      var soFar = 0;
+      if (format.indexOf('%n') >= 0) {
+        // need to track soFar
+        var _get = get;
+        get = function get() {
+          soFar++;
+          return _get();
+        }
+        var _unget = unget;
+        unget = function unget() {
+          soFar--;
+          return _unget();
+        }
+      }
+      var formatIndex = 0;
+      var argsi = 0;
+      var fields = 0;
+      var argIndex = 0;
+      var next;
+
+      mainLoop:
+      for (var formatIndex = 0; formatIndex < format.length;) {
+        if (format[formatIndex] === '%' && format[formatIndex+1] == 'n') {
+          var argPtr = HEAP32[(((varargs)+(argIndex))>>2)];
+          argIndex += Runtime.getAlignSize('void*', null, true);
+          HEAP32[((argPtr)>>2)]=soFar;
+          formatIndex += 2;
+          continue;
+        }
+
+        if (format[formatIndex] === '%') {
+          var nextC = format.indexOf('c', formatIndex+1);
+          if (nextC > 0) {
+            var maxx = 1;
+            if (nextC > formatIndex+1) {
+              var sub = format.substring(formatIndex+1, nextC);
+              maxx = parseInt(sub);
+              if (maxx != sub) maxx = 0;
+            }
+            if (maxx) {
+              var argPtr = HEAP32[(((varargs)+(argIndex))>>2)];
+              argIndex += Runtime.getAlignSize('void*', null, true);
+              fields++;
+              for (var i = 0; i < maxx; i++) {
+                next = get();
+                HEAP8[((argPtr++)|0)]=next;
+                if (next === 0) return i > 0 ? fields : fields-1; // we failed to read the full length of this field
+              }
+              formatIndex += nextC - formatIndex + 1;
+              continue;
+            }
+          }
+        }
+
+        // handle %[...]
+        if (format[formatIndex] === '%' && format.indexOf('[', formatIndex+1) > 0) {
+          var match = /\%([0-9]*)\[(\^)?(\]?[^\]]*)\]/.exec(format.substring(formatIndex));
+          if (match) {
+            var maxNumCharacters = parseInt(match[1]) || Infinity;
+            var negateScanList = (match[2] === '^');
+            var scanList = match[3];
+
+            // expand "middle" dashs into character sets
+            var middleDashMatch;
+            while ((middleDashMatch = /([^\-])\-([^\-])/.exec(scanList))) {
+              var rangeStartCharCode = middleDashMatch[1].charCodeAt(0);
+              var rangeEndCharCode = middleDashMatch[2].charCodeAt(0);
+              for (var expanded = ''; rangeStartCharCode <= rangeEndCharCode; expanded += String.fromCharCode(rangeStartCharCode++));
+              scanList = scanList.replace(middleDashMatch[1] + '-' + middleDashMatch[2], expanded);
+            }
+
+            var argPtr = HEAP32[(((varargs)+(argIndex))>>2)];
+            argIndex += Runtime.getAlignSize('void*', null, true);
+            fields++;
+
+            for (var i = 0; i < maxNumCharacters; i++) {
+              next = get();
+              if (negateScanList) {
+                if (scanList.indexOf(String.fromCharCode(next)) < 0) {
+                  HEAP8[((argPtr++)|0)]=next;
+                } else {
+                  unget();
+                  break;
+                }
+              } else {
+                if (scanList.indexOf(String.fromCharCode(next)) >= 0) {
+                  HEAP8[((argPtr++)|0)]=next;
+                } else {
+                  unget();
+                  break;
+                }
+              }
+            }
+
+            // write out null-terminating character
+            HEAP8[((argPtr++)|0)]=0;
+            formatIndex += match[0].length;
+
+            continue;
+          }
+        }
+        // remove whitespace
+        while (1) {
+          next = get();
+          if (next == 0) return fields;
+          if (!(next in __scanString.whiteSpace)) break;
+        }
+        unget();
+
+        if (format[formatIndex] === '%') {
+          formatIndex++;
+          var suppressAssignment = false;
+          if (format[formatIndex] == '*') {
+            suppressAssignment = true;
+            formatIndex++;
+          }
+          var maxSpecifierStart = formatIndex;
+          while (format[formatIndex].charCodeAt(0) >= 48 &&
+                 format[formatIndex].charCodeAt(0) <= 57) {
+            formatIndex++;
+          }
+          var max_;
+          if (formatIndex != maxSpecifierStart) {
+            max_ = parseInt(format.slice(maxSpecifierStart, formatIndex), 10);
+          }
+          var long_ = false;
+          var half = false;
+          var longLong = false;
+          if (format[formatIndex] == 'l') {
+            long_ = true;
+            formatIndex++;
+            if (format[formatIndex] == 'l') {
+              longLong = true;
+              formatIndex++;
+            }
+          } else if (format[formatIndex] == 'h') {
+            half = true;
+            formatIndex++;
+          }
+          var type = format[formatIndex];
+          formatIndex++;
+          var curr = 0;
+          var buffer = [];
+          // Read characters according to the format. floats are trickier, they may be in an unfloat state in the middle, then be a valid float later
+          if (type == 'f' || type == 'e' || type == 'g' ||
+              type == 'F' || type == 'E' || type == 'G') {
+            next = get();
+            while (next > 0 && (!(next in __scanString.whiteSpace)))  {
+              buffer.push(String.fromCharCode(next));
+              next = get();
+            }
+            var m = __getFloat(buffer.join(''));
+            var last = m ? m[0].length : 0;
+            for (var i = 0; i < buffer.length - last + 1; i++) {
+              unget();
+            }
+            buffer.length = last;
+          } else {
+            next = get();
+            var first = true;
+
+            // Strip the optional 0x prefix for %x.
+            if ((type == 'x' || type == 'X') && (next == 48)) {
+              var peek = get();
+              if (peek == 120 || peek == 88) {
+                next = get();
+              } else {
+                unget();
+              }
+            }
+
+            while ((curr < max_ || isNaN(max_)) && next > 0) {
+              if (!(next in __scanString.whiteSpace) && // stop on whitespace
+                  (type == 's' ||
+                   ((type === 'd' || type == 'u' || type == 'i') && ((next >= 48 && next <= 57) ||
+                                                                     (first && next == 45))) ||
+                   ((type === 'x' || type === 'X') && (next >= 48 && next <= 57 ||
+                                     next >= 97 && next <= 102 ||
+                                     next >= 65 && next <= 70))) &&
+                  (formatIndex >= format.length || next !== format[formatIndex].charCodeAt(0))) { // Stop when we read something that is coming up
+                buffer.push(String.fromCharCode(next));
+                next = get();
+                curr++;
+                first = false;
+              } else {
+                break;
+              }
+            }
+            unget();
+          }
+          if (buffer.length === 0) return 0;  // Failure.
+          if (suppressAssignment) continue;
+
+          var text = buffer.join('');
+          var argPtr = HEAP32[(((varargs)+(argIndex))>>2)];
+          argIndex += Runtime.getAlignSize('void*', null, true);
+          switch (type) {
+            case 'd': case 'u': case 'i':
+              if (half) {
+                HEAP16[((argPtr)>>1)]=parseInt(text, 10);
+              } else if (longLong) {
+                (tempI64 = [parseInt(text, 10)>>>0,(tempDouble=parseInt(text, 10),(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((argPtr)>>2)]=tempI64[0],HEAP32[(((argPtr)+(4))>>2)]=tempI64[1]);
+              } else {
+                HEAP32[((argPtr)>>2)]=parseInt(text, 10);
+              }
+              break;
+            case 'X':
+            case 'x':
+              HEAP32[((argPtr)>>2)]=parseInt(text, 16);
+              break;
+            case 'F':
+            case 'f':
+            case 'E':
+            case 'e':
+            case 'G':
+            case 'g':
+            case 'E':
+              // fallthrough intended
+              if (long_) {
+                HEAPF64[((argPtr)>>3)]=parseFloat(text);
+              } else {
+                HEAPF32[((argPtr)>>2)]=parseFloat(text);
+              }
+              break;
+            case 's':
+              var array = intArrayFromString(text);
+              for (var j = 0; j < array.length; j++) {
+                HEAP8[(((argPtr)+(j))|0)]=array[j];
+              }
+              break;
+          }
+          fields++;
+        } else if (format[formatIndex].charCodeAt(0) in __scanString.whiteSpace) {
+          next = get();
+          while (next in __scanString.whiteSpace) {
+            if (next <= 0) break mainLoop;  // End of input.
+            next = get();
+          }
+          unget(next);
+          formatIndex++;
+        } else {
+          // Not a specifier.
+          next = get();
+          if (format[formatIndex].charCodeAt(0) !== next) {
+            unget(next);
+            break mainLoop;
+          }
+          formatIndex++;
+        }
+      }
+      return fields;
+    }
+
+  function _fgetc(stream) {
+      // int fgetc(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fgetc.html
+      var streamObj = FS.getStreamFromPtr(stream);
+      if (!streamObj) return -1;
+      if (streamObj.eof || streamObj.error) return -1;
+      var ret = _fread(_fgetc.ret, 1, 1, stream);
+      if (ret == 0) {
+        return -1;
+      } else if (ret == -1) {
+        streamObj.error = true;
+        return -1;
+      } else {
+        return HEAPU8[((_fgetc.ret)|0)];
+      }
+    }
+
+  function _ungetc(c, stream) {
+      // int ungetc(int c, FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/ungetc.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) {
+        return -1;
+      }
+      if (c === -1) {
+        // do nothing for EOF character
+        return c;
+      }
+      c = unSign(c & 0xFF);
+      stream.ungotten.push(c);
+      stream.eof = false;
+      return c;
+    }function _fscanf(stream, format, varargs) {
+      // int fscanf(FILE *restrict stream, const char *restrict format, ... );
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html
+      var streamObj = FS.getStreamFromPtr(stream);
+      if (!streamObj) {
+        return -1;
+      }
+      var buffer = [];
+      function get() {
+        var c = _fgetc(stream);
+        buffer.push(c);
+        return c;
+      };
+      function unget() {
+        _ungetc(buffer.pop(), stream);
+      };
+      return __scanString(format, get, unget, varargs);
+    }
+
+  var _emscripten_preinvoke=true;
+
+  function _localeconv() {
+      // %struct.timeval = type { char* decimal point, other stuff... }
+      // var indexes = Runtime.calculateStructAlignment({ fields: ['i32', 'i32'] });
+      var me = _localeconv;
+      if (!me.ret) {
+      // These are defaults from the "C" locale
+        me.ret = allocate([
+          allocate(intArrayFromString('.'), 'i8', ALLOC_NORMAL),0,0,0, // decimal_point
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // thousands_sep
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // grouping
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // int_curr_symbol
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // currency_symbol
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // mon_decimal_point
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // mon_thousands_sep
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // mon_grouping
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // positive_sign
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0 // negative_sign
+        ], 'i8*', ALLOC_NORMAL); // Allocate strings in lconv, still don't allocate chars
+      }
+      return me.ret;
+    }
+
+
+  function _unlink(path) {
+      // int unlink(const char *path);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/unlink.html
+      path = Pointer_stringify(path);
+      try {
+        FS.unlink(path);
+        return 0;
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _rmdir(path) {
+      // int rmdir(const char *path);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/rmdir.html
+      path = Pointer_stringify(path);
+      try {
+        FS.rmdir(path);
+        return 0;
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _remove(path) {
+      // int remove(const char *path);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/remove.html
+      var ret = _unlink(path);
+      if (ret == -1) ret = _rmdir(path);
+      return ret;
+    }
+
+  function _freopen(filename, mode, stream) {
+      // FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/freopen.html
+      if (!filename) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (!streamObj) {
+          ___setErrNo(ERRNO_CODES.EBADF);
+          return 0;
+        }
+        if (_freopen.buffer) _free(_freopen.buffer);
+        filename = intArrayFromString(streamObj.path);
+        filename = allocate(filename, 'i8', ALLOC_NORMAL);
+      }
+      _fclose(stream);
+      return _fopen(filename, mode);
+    }
+
+
+  function _rename(old_path, new_path) {
+      // int rename(const char *old, const char *new);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/rename.html
+      old_path = Pointer_stringify(old_path);
+      new_path = Pointer_stringify(new_path);
+      try {
+        FS.rename(old_path, new_path);
+        return 0;
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _tmpfile() {
+      // FILE *tmpfile(void);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/tmpfile.html
+      // TODO: Delete the created file on closing.
+      if (_tmpfile.mode) {
+        _tmpfile.mode = allocate(intArrayFromString('w+'), 'i8', ALLOC_NORMAL);
+      }
+      return _fopen(_tmpnam(0), _tmpfile.mode);
+    }
+
+  function _sysconf(name) {
+      // long sysconf(int name);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
+      switch(name) {
+        case 30: return PAGE_SIZE;
+        case 132:
+        case 133:
+        case 12:
+        case 137:
+        case 138:
+        case 15:
+        case 235:
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 149:
+        case 13:
+        case 10:
+        case 236:
+        case 153:
+        case 9:
+        case 21:
+        case 22:
+        case 159:
+        case 154:
+        case 14:
+        case 77:
+        case 78:
+        case 139:
+        case 80:
+        case 81:
+        case 79:
+        case 82:
+        case 68:
+        case 67:
+        case 164:
+        case 11:
+        case 29:
+        case 47:
+        case 48:
+        case 95:
+        case 52:
+        case 51:
+        case 46:
+          return 200809;
+        case 27:
+        case 246:
+        case 127:
+        case 128:
+        case 23:
+        case 24:
+        case 160:
+        case 161:
+        case 181:
+        case 182:
+        case 242:
+        case 183:
+        case 184:
+        case 243:
+        case 244:
+        case 245:
+        case 165:
+        case 178:
+        case 179:
+        case 49:
+        case 50:
+        case 168:
+        case 169:
+        case 175:
+        case 170:
+        case 171:
+        case 172:
+        case 97:
+        case 76:
+        case 32:
+        case 173:
+        case 35:
+          return -1;
+        case 176:
+        case 177:
+        case 7:
+        case 155:
+        case 8:
+        case 157:
+        case 125:
+        case 126:
+        case 92:
+        case 93:
+        case 129:
+        case 130:
+        case 131:
+        case 94:
+        case 91:
+          return 1;
+        case 74:
+        case 60:
+        case 69:
+        case 70:
+        case 4:
+          return 1024;
+        case 31:
+        case 42:
+        case 72:
+          return 32;
+        case 87:
+        case 26:
+        case 33:
+          return 2147483647;
+        case 34:
+        case 1:
+          return 47839;
+        case 38:
+        case 36:
+          return 99;
+        case 43:
+        case 37:
+          return 2048;
+        case 0: return 2097152;
+        case 3: return 65536;
+        case 28: return 32768;
+        case 44: return 32767;
+        case 75: return 16384;
+        case 39: return 1000;
+        case 89: return 700;
+        case 71: return 256;
+        case 40: return 255;
+        case 2: return 100;
+        case 180: return 64;
+        case 25: return 20;
+        case 5: return 16;
+        case 6: return 6;
+        case 73: return 4;
+        case 84: return 1;
+      }
+      ___setErrNo(ERRNO_CODES.EINVAL);
+      return -1;
+    }
+
+
+  function ___errno_location() {
+      return ___errno_state;
+    }
+
+
+  Module["_memset"] = _memset;
+
+
+
+  Module["_bitshift64Shl"] = _bitshift64Shl;
+
+  function _abort() {
+      Module['abort']();
+    }
+
+
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var origArg = currArg;
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], null); else
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], true); else
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (argSize == 8 && i64Math) {
+                  if (origArg[1]) {
+                    argText = (origArg[1]>>>0).toString(16);
+                    var lower = (origArg[0]>>>0).toString(16);
+                    while (lower.length < 8) lower = '0' + lower;
+                    argText += lower;
+                  } else {
+                    argText = (origArg[0]>>>0).toString(16);
+                  }
+                } else
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }
+
+  function _fgets(s, n, stream) {
+      // char *fgets(char *restrict s, int n, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fgets.html
+      var streamObj = FS.getStreamFromPtr(stream);
+      if (!streamObj) return 0;
+      if (streamObj.error || streamObj.eof) return 0;
+      var byte_;
+      for (var i = 0; i < n - 1 && byte_ != 10; i++) {
+        byte_ = _fgetc(stream);
+        if (byte_ == -1) {
+          if (streamObj.error || (streamObj.eof && i == 0)) return 0;
+          else if (streamObj.eof) break;
+        }
+        HEAP8[(((s)+(i))|0)]=byte_;
+      }
+      HEAP8[(((s)+(i))|0)]=0;
+      return s;
+    }
+
+  var _tan=Math_tan;
+
+  function _ispunct(chr) {
+      return (chr >= 33 && chr <= 47) ||
+             (chr >= 58 && chr <= 64) ||
+             (chr >= 91 && chr <= 96) ||
+             (chr >= 123 && chr <= 126);
+    }
+
+  function _feof(stream) {
+      // int feof(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/feof.html
+      stream = FS.getStreamFromPtr(stream);
+      return Number(stream && stream.eof);
+    }
+
+
+  Module["_tolower"] = _tolower;
+
+  var _asin=Math_asin;
+
+  function _clearerr(stream) {
+      // void clearerr(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/clearerr.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) {
+        return;
+      }
+      stream.eof = false;
+      stream.error = false;
+    }
+
+  var _fabs=Math_abs;
+
+  function _clock() {
+      if (_clock.start === undefined) _clock.start = Date.now();
+      return Math.floor((Date.now() - _clock.start) * (1000000/1000));
+    }
+
+
+  var _getc=_fgetc;
+
+  function _modf(x, intpart) {
+      HEAPF64[((intpart)>>3)]=Math.floor(x);
+      return x - HEAPF64[((intpart)>>3)];
+    }
+
+  var _sqrt=Math_sqrt;
+
+  function _isxdigit(chr) {
+      return (chr >= 48 && chr <= 57) ||
+             (chr >= 97 && chr <= 102) ||
+             (chr >= 65 && chr <= 70);
+    }
+
+  function _ftell(stream) {
+      // long ftell(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/ftell.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      if (FS.isChrdev(stream.node.mode)) {
+        ___setErrNo(ERRNO_CODES.ESPIPE);
+        return -1;
+      } else {
+        return stream.position;
+      }
+    }
+
+
+  function __exit(status) {
+      // void _exit(int status);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/exit.html
+      Module['exit'](status);
+    }function _exit(status) {
+      __exit(status);
+    }
+
+
+  function _snprintf(s, n, format, varargs) {
+      // int snprintf(char *restrict s, size_t n, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var limit = (n === undefined) ? result.length
+                                    : Math.min(result.length, Math.max(n - 1, 0));
+      if (s < 0) {
+        s = -s;
+        var buf = _malloc(limit+1);
+        HEAP32[((s)>>2)]=buf;
+        s = buf;
+      }
+      for (var i = 0; i < limit; i++) {
+        HEAP8[(((s)+(i))|0)]=result[i];
+      }
+      if (limit < n || (n === undefined)) HEAP8[(((s)+(i))|0)]=0;
+      return result.length;
+    }function _sprintf(s, format, varargs) {
+      // int sprintf(char *restrict s, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      return _snprintf(s, undefined, format, varargs);
+    }
+
+  var _emscripten_get_longjmp_result=true;
+
+  var _sin=Math_sin;
+
+
+  function _fmod(x, y) {
+      return x % y;
+    }var _fmodl=_fmod;
+
+
+
+  var _atan=Math_atan;
+
+  function _ferror(stream) {
+      // int ferror(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/ferror.html
+      stream = FS.getStreamFromPtr(stream);
+      return Number(stream && stream.error);
+    }
+
+  function _time(ptr) {
+      var ret = Math.floor(Date.now()/1000);
+      if (ptr) {
+        HEAP32[((ptr)>>2)]=ret;
+      }
+      return ret;
+    }
+
+  function _copysign(a, b) {
+      return __reallyNegative(a) === __reallyNegative(b) ? a : -a;
+    }
+
+
+  function _gmtime_r(time, tmPtr) {
+      var date = new Date(HEAP32[((time)>>2)]*1000);
+      HEAP32[((tmPtr)>>2)]=date.getUTCSeconds();
+      HEAP32[(((tmPtr)+(4))>>2)]=date.getUTCMinutes();
+      HEAP32[(((tmPtr)+(8))>>2)]=date.getUTCHours();
+      HEAP32[(((tmPtr)+(12))>>2)]=date.getUTCDate();
+      HEAP32[(((tmPtr)+(16))>>2)]=date.getUTCMonth();
+      HEAP32[(((tmPtr)+(20))>>2)]=date.getUTCFullYear()-1900;
+      HEAP32[(((tmPtr)+(24))>>2)]=date.getUTCDay();
+      HEAP32[(((tmPtr)+(36))>>2)]=0;
+      HEAP32[(((tmPtr)+(32))>>2)]=0;
+      var start = new Date(date); // define date using UTC, start from Jan 01 00:00:00 UTC
+      start.setUTCDate(1);
+      start.setUTCMonth(0);
+      start.setUTCHours(0);
+      start.setUTCMinutes(0);
+      start.setUTCSeconds(0);
+      start.setUTCMilliseconds(0);
+      var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
+      HEAP32[(((tmPtr)+(28))>>2)]=yday;
+      HEAP32[(((tmPtr)+(40))>>2)]=___tm_timezone;
+
+      return tmPtr;
+    }function _gmtime(time) {
+      return _gmtime_r(time, ___tm_current);
+    }
+
+  function _isgraph(chr) {
+      return 0x20 < chr && chr < 0x7F;
+    }
+
+
+
+  function _strerror_r(errnum, strerrbuf, buflen) {
+      if (errnum in ERRNO_MESSAGES) {
+        if (ERRNO_MESSAGES[errnum].length > buflen - 1) {
+          return ___setErrNo(ERRNO_CODES.ERANGE);
+        } else {
+          var msg = ERRNO_MESSAGES[errnum];
+          writeAsciiToMemory(msg, strerrbuf);
+          return 0;
+        }
+      } else {
+        return ___setErrNo(ERRNO_CODES.EINVAL);
+      }
+    }function _strerror(errnum) {
+      if (!_strerror.buffer) _strerror.buffer = _malloc(256);
+      _strerror_r(errnum, _strerror.buffer, 256);
+      return _strerror.buffer;
+    }
+
+
+
+
+
+  var _environ=allocate(1, "i32*", ALLOC_STATIC);var ___environ=_environ;function ___buildEnvironment(env) {
+      // WARNING: Arbitrary limit!
+      var MAX_ENV_VALUES = 64;
+      var TOTAL_ENV_SIZE = 1024;
+
+      // Statically allocate memory for the environment.
+      var poolPtr;
+      var envPtr;
+      if (!___buildEnvironment.called) {
+        ___buildEnvironment.called = true;
+        // Set default values. Use string keys for Closure Compiler compatibility.
+        ENV['USER'] = 'root';
+        ENV['PATH'] = '/';
+        ENV['PWD'] = '/';
+        ENV['HOME'] = '/home/emscripten';
+        ENV['LANG'] = 'en_US.UTF-8';
+        ENV['_'] = './this.program';
+        // Allocate memory.
+        poolPtr = allocate(TOTAL_ENV_SIZE, 'i8', ALLOC_STATIC);
+        envPtr = allocate(MAX_ENV_VALUES * 4,
+                          'i8*', ALLOC_STATIC);
+        HEAP32[((envPtr)>>2)]=poolPtr;
+        HEAP32[((_environ)>>2)]=envPtr;
+      } else {
+        envPtr = HEAP32[((_environ)>>2)];
+        poolPtr = HEAP32[((envPtr)>>2)];
+      }
+
+      // Collect key=value lines.
+      var strings = [];
+      var totalSize = 0;
+      for (var key in env) {
+        if (typeof env[key] === 'string') {
+          var line = key + '=' + env[key];
+          strings.push(line);
+          totalSize += line.length;
+        }
+      }
+      if (totalSize > TOTAL_ENV_SIZE) {
+        throw new Error('Environment size exceeded TOTAL_ENV_SIZE!');
+      }
+
+      // Make new.
+      var ptrSize = 4;
+      for (var i = 0; i < strings.length; i++) {
+        var line = strings[i];
+        writeAsciiToMemory(line, poolPtr);
+        HEAP32[(((envPtr)+(i * ptrSize))>>2)]=poolPtr;
+        poolPtr += line.length + 1;
+      }
+      HEAP32[(((envPtr)+(strings.length * ptrSize))>>2)]=0;
+    }var ENV={};function _getenv(name) {
+      // char *getenv(const char *name);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/getenv.html
+      if (name === 0) return 0;
+      name = Pointer_stringify(name);
+      if (!ENV.hasOwnProperty(name)) return 0;
+
+      if (_getenv.ret) _free(_getenv.ret);
+      _getenv.ret = allocate(intArrayFromString(ENV[name]), 'i8', ALLOC_NORMAL);
+      return _getenv.ret;
+    }
+
+  var _emscripten_setjmp=true;
+
+  var _cos=Math_cos;
+
+  function _isalnum(chr) {
+      return (chr >= 48 && chr <= 57) ||
+             (chr >= 97 && chr <= 122) ||
+             (chr >= 65 && chr <= 90);
+    }
+
+  var _BItoD=true;
+
+  function _difftime(time1, time0) {
+      return time1 - time0;
+    }
+
+  var _floor=Math_floor;
+
+  function _iscntrl(chr) {
+      return (0 <= chr && chr <= 0x1F) || chr === 0x7F;
+    }
+
+  var _atan2=Math_atan2;
+
+  function _setvbuf(stream, buf, type, size) {
+      // int setvbuf(FILE *restrict stream, char *restrict buf, int type, size_t size);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/setvbuf.html
+      // TODO: Implement custom buffering.
+      return 0;
+    }
+
+  var _exp=Math_exp;
+
+  var _copysignl=_copysign;
+
+  function _islower(chr) {
+      return chr >= 97 && chr <= 122;
+    }
+
+  var _acos=Math_acos;
+
+  function _isupper(chr) {
+      return chr >= 65 && chr <= 90;
+    }
+
+
+  function __isLeapYear(year) {
+        return year%4 === 0 && (year%100 !== 0 || year%400 === 0);
+    }
+
+  function __arraySum(array, index) {
+      var sum = 0;
+      for (var i = 0; i <= index; sum += array[i++]);
+      return sum;
+    }
+
+
+  var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];
+
+  var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date, days) {
+      var newDate = new Date(date.getTime());
+      while(days > 0) {
+        var leap = __isLeapYear(newDate.getFullYear());
+        var currentMonth = newDate.getMonth();
+        var daysInCurrentMonth = (leap ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[currentMonth];
+
+        if (days > daysInCurrentMonth-newDate.getDate()) {
+          // we spill over to next month
+          days -= (daysInCurrentMonth-newDate.getDate()+1);
+          newDate.setDate(1);
+          if (currentMonth < 11) {
+            newDate.setMonth(currentMonth+1)
+          } else {
+            newDate.setMonth(0);
+            newDate.setFullYear(newDate.getFullYear()+1);
+          }
+        } else {
+          // we stay in current month
+          newDate.setDate(newDate.getDate()+days);
+          return newDate;
+        }
+      }
+
+      return newDate;
+    }function _strftime(s, maxsize, format, tm) {
+      // size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/strftime.html
+
+      var date = {
+        tm_sec: HEAP32[((tm)>>2)],
+        tm_min: HEAP32[(((tm)+(4))>>2)],
+        tm_hour: HEAP32[(((tm)+(8))>>2)],
+        tm_mday: HEAP32[(((tm)+(12))>>2)],
+        tm_mon: HEAP32[(((tm)+(16))>>2)],
+        tm_year: HEAP32[(((tm)+(20))>>2)],
+        tm_wday: HEAP32[(((tm)+(24))>>2)],
+        tm_yday: HEAP32[(((tm)+(28))>>2)],
+        tm_isdst: HEAP32[(((tm)+(32))>>2)]
+      };
+
+      var pattern = Pointer_stringify(format);
+
+      // expand format
+      var EXPANSION_RULES_1 = {
+        '%c': '%a %b %d %H:%M:%S %Y',     // Replaced by the locale's appropriate date and time representation - e.g., Mon Aug  3 14:02:01 2013
+        '%D': '%m/%d/%y',                 // Equivalent to %m / %d / %y
+        '%F': '%Y-%m-%d',                 // Equivalent to %Y - %m - %d
+        '%h': '%b',                       // Equivalent to %b
+        '%r': '%I:%M:%S %p',              // Replaced by the time in a.m. and p.m. notation
+        '%R': '%H:%M',                    // Replaced by the time in 24-hour notation
+        '%T': '%H:%M:%S',                 // Replaced by the time
+        '%x': '%m/%d/%y',                 // Replaced by the locale's appropriate date representation
+        '%X': '%H:%M:%S',                 // Replaced by the locale's appropriate date representation
+      };
+      for (var rule in EXPANSION_RULES_1) {
+        pattern = pattern.replace(new RegExp(rule, 'g'), EXPANSION_RULES_1[rule]);
+      }
+
+      var WEEKDAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
+      var MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
+
+      function leadingSomething(value, digits, character) {
+        var str = typeof value === 'number' ? value.toString() : (value || '');
+        while (str.length < digits) {
+          str = character[0]+str;
+        }
+        return str;
+      };
+
+      function leadingNulls(value, digits) {
+        return leadingSomething(value, digits, '0');
+      };
+
+      function compareByDay(date1, date2) {
+        function sgn(value) {
+          return value < 0 ? -1 : (value > 0 ? 1 : 0);
+        };
+
+        var compare;
+        if ((compare = sgn(date1.getFullYear()-date2.getFullYear())) === 0) {
+          if ((compare = sgn(date1.getMonth()-date2.getMonth())) === 0) {
+            compare = sgn(date1.getDate()-date2.getDate());
+          }
+        }
+        return compare;
+      };
+
+      function getFirstWeekStartDate(janFourth) {
+          switch (janFourth.getDay()) {
+            case 0: // Sunday
+              return new Date(janFourth.getFullYear()-1, 11, 29);
+            case 1: // Monday
+              return janFourth;
+            case 2: // Tuesday
+              return new Date(janFourth.getFullYear(), 0, 3);
+            case 3: // Wednesday
+              return new Date(janFourth.getFullYear(), 0, 2);
+            case 4: // Thursday
+              return new Date(janFourth.getFullYear(), 0, 1);
+            case 5: // Friday
+              return new Date(janFourth.getFullYear()-1, 11, 31);
+            case 6: // Saturday
+              return new Date(janFourth.getFullYear()-1, 11, 30);
+          }
+      };
+
+      function getWeekBasedYear(date) {
+          var thisDate = __addDays(new Date(date.tm_year+1900, 0, 1), date.tm_yday);
+
+          var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4);
+          var janFourthNextYear = new Date(thisDate.getFullYear()+1, 0, 4);
+
+          var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear);
+          var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear);
+
+          if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) {
+            // this date is after the start of the first week of this year
+            if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) {
+              return thisDate.getFullYear()+1;
+            } else {
+              return thisDate.getFullYear();
+            }
+          } else {
+            return thisDate.getFullYear()-1;
+          }
+      };
+
+      var EXPANSION_RULES_2 = {
+        '%a': function(date) {
+          return WEEKDAYS[date.tm_wday].substring(0,3);
+        },
+        '%A': function(date) {
+          return WEEKDAYS[date.tm_wday];
+        },
+        '%b': function(date) {
+          return MONTHS[date.tm_mon].substring(0,3);
+        },
+        '%B': function(date) {
+          return MONTHS[date.tm_mon];
+        },
+        '%C': function(date) {
+          var year = date.tm_year+1900;
+          return leadingNulls(Math.floor(year/100),2);
+        },
+        '%d': function(date) {
+          return leadingNulls(date.tm_mday, 2);
+        },
+        '%e': function(date) {
+          return leadingSomething(date.tm_mday, 2, ' ');
+        },
+        '%g': function(date) {
+          // %g, %G, and %V give values according to the ISO 8601:2000 standard week-based year.
+          // In this system, weeks begin on a Monday and week 1 of the year is the week that includes
+          // January 4th, which is also the week that includes the first Thursday of the year, and
+          // is also the first week that contains at least four days in the year.
+          // If the first Monday of January is the 2nd, 3rd, or 4th, the preceding days are part of
+          // the last week of the preceding year; thus, for Saturday 2nd January 1999,
+          // %G is replaced by 1998 and %V is replaced by 53. If December 29th, 30th,
+          // or 31st is a Monday, it and any following days are part of week 1 of the following year.
+          // Thus, for Tuesday 30th December 1997, %G is replaced by 1998 and %V is replaced by 01.
+
+          return getWeekBasedYear(date).toString().substring(2);
+        },
+        '%G': function(date) {
+          return getWeekBasedYear(date);
+        },
+        '%H': function(date) {
+          return leadingNulls(date.tm_hour, 2);
+        },
+        '%I': function(date) {
+          return leadingNulls(date.tm_hour < 13 ? date.tm_hour : date.tm_hour-12, 2);
+        },
+        '%j': function(date) {
+          // Day of the year (001-366)
+          return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, date.tm_mon-1), 3);
+        },
+        '%m': function(date) {
+          return leadingNulls(date.tm_mon+1, 2);
+        },
+        '%M': function(date) {
+          return leadingNulls(date.tm_min, 2);
+        },
+        '%n': function() {
+          return '\n';
+        },
+        '%p': function(date) {
+          if (date.tm_hour > 0 && date.tm_hour < 13) {
+            return 'AM';
+          } else {
+            return 'PM';
+          }
+        },
+        '%S': function(date) {
+          return leadingNulls(date.tm_sec, 2);
+        },
+        '%t': function() {
+          return '\t';
+        },
+        '%u': function(date) {
+          var day = new Date(date.tm_year+1900, date.tm_mon+1, date.tm_mday, 0, 0, 0, 0);
+          return day.getDay() || 7;
+        },
+        '%U': function(date) {
+          // Replaced by the week number of the year as a decimal number [00,53].
+          // The first Sunday of January is the first day of week 1;
+          // days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
+          var janFirst = new Date(date.tm_year+1900, 0, 1);
+          var firstSunday = janFirst.getDay() === 0 ? janFirst : __addDays(janFirst, 7-janFirst.getDay());
+          var endDate = new Date(date.tm_year+1900, date.tm_mon, date.tm_mday);
+
+          // is target date after the first Sunday?
+          if (compareByDay(firstSunday, endDate) < 0) {
+            // calculate difference in days between first Sunday and endDate
+            var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth()-1)-31;
+            var firstSundayUntilEndJanuary = 31-firstSunday.getDate();
+            var days = firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();
+            return leadingNulls(Math.ceil(days/7), 2);
+          }
+
+          return compareByDay(firstSunday, janFirst) === 0 ? '01': '00';
+        },
+        '%V': function(date) {
+          // Replaced by the week number of the year (Monday as the first day of the week)
+          // as a decimal number [01,53]. If the week containing 1 January has four
+          // or more days in the new year, then it is considered week 1.
+          // Otherwise, it is the last week of the previous year, and the next week is week 1.
+          // Both January 4th and the first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday]
+          var janFourthThisYear = new Date(date.tm_year+1900, 0, 4);
+          var janFourthNextYear = new Date(date.tm_year+1901, 0, 4);
+
+          var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear);
+          var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear);
+
+          var endDate = __addDays(new Date(date.tm_year+1900, 0, 1), date.tm_yday);
+
+          if (compareByDay(endDate, firstWeekStartThisYear) < 0) {
+            // if given date is before this years first week, then it belongs to the 53rd week of last year
+            return '53';
+          }
+
+          if (compareByDay(firstWeekStartNextYear, endDate) <= 0) {
+            // if given date is after next years first week, then it belongs to the 01th week of next year
+            return '01';
+          }
+
+          // given date is in between CW 01..53 of this calendar year
+          var daysDifference;
+          if (firstWeekStartThisYear.getFullYear() < date.tm_year+1900) {
+            // first CW of this year starts last year
+            daysDifference = date.tm_yday+32-firstWeekStartThisYear.getDate()
+          } else {
+            // first CW of this year starts this year
+            daysDifference = date.tm_yday+1-firstWeekStartThisYear.getDate();
+          }
+          return leadingNulls(Math.ceil(daysDifference/7), 2);
+        },
+        '%w': function(date) {
+          var day = new Date(date.tm_year+1900, date.tm_mon+1, date.tm_mday, 0, 0, 0, 0);
+          return day.getDay();
+        },
+        '%W': function(date) {
+          // Replaced by the week number of the year as a decimal number [00,53].
+          // The first Monday of January is the first day of week 1;
+          // days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
+          var janFirst = new Date(date.tm_year, 0, 1);
+          var firstMonday = janFirst.getDay() === 1 ? janFirst : __addDays(janFirst, janFirst.getDay() === 0 ? 1 : 7-janFirst.getDay()+1);
+          var endDate = new Date(date.tm_year+1900, date.tm_mon, date.tm_mday);
+
+          // is target date after the first Monday?
+          if (compareByDay(firstMonday, endDate) < 0) {
+            var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth()-1)-31;
+            var firstMondayUntilEndJanuary = 31-firstMonday.getDate();
+            var days = firstMondayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();
+            return leadingNulls(Math.ceil(days/7), 2);
+          }
+          return compareByDay(firstMonday, janFirst) === 0 ? '01': '00';
+        },
+        '%y': function(date) {
+          // Replaced by the last two digits of the year as a decimal number [00,99]. [ tm_year]
+          return (date.tm_year+1900).toString().substring(2);
+        },
+        '%Y': function(date) {
+          // Replaced by the year as a decimal number (for example, 1997). [ tm_year]
+          return date.tm_year+1900;
+        },
+        '%z': function(date) {
+          // Replaced by the offset from UTC in the ISO 8601:2000 standard format ( +hhmm or -hhmm ),
+          // or by no characters if no timezone is determinable.
+          // For example, "-0430" means 4 hours 30 minutes behind UTC (west of Greenwich).
+          // If tm_isdst is zero, the standard time offset is used.
+          // If tm_isdst is greater than zero, the daylight savings time offset is used.
+          // If tm_isdst is negative, no characters are returned.
+          // FIXME: we cannot determine time zone (or can we?)
+          return '';
+        },
+        '%Z': function(date) {
+          // Replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists. [ tm_isdst]
+          // FIXME: we cannot determine time zone (or can we?)
+          return '';
+        },
+        '%%': function() {
+          return '%';
+        }
+      };
+      for (var rule in EXPANSION_RULES_2) {
+        if (pattern.indexOf(rule) >= 0) {
+          pattern = pattern.replace(new RegExp(rule, 'g'), EXPANSION_RULES_2[rule](date));
+        }
+      }
+
+      var bytes = intArrayFromString(pattern, false);
+      if (bytes.length > maxsize) {
+        return 0;
+      }
+
+      writeArrayToMemory(bytes, s);
+      return bytes.length-1;
+    }
+
+
+
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+_fputc.ret = allocate([0], "i8", ALLOC_STATIC);
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+_fgetc.ret = allocate([0], "i8", ALLOC_STATIC);
+___buildEnvironment(ENV);
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+ var ctlz_i8 = allocate([8,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "i8", ALLOC_DYNAMIC);
+ var cttz_i8 = allocate([8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0], "i8", ALLOC_DYNAMIC);
+
+var Math_min = Math.min;
+function invoke_iiii(index,a1,a2,a3) {
+  try {
+    return Module["dynCall_iiii"](index,a1,a2,a3);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_vi(index,a1) {
+  try {
+    Module["dynCall_vi"](index,a1);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_vii(index,a1,a2) {
+  try {
+    Module["dynCall_vii"](index,a1,a2);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_ii(index,a1) {
+  try {
+    return Module["dynCall_ii"](index,a1);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_iiiii(index,a1,a2,a3,a4) {
+  try {
+    return Module["dynCall_iiiii"](index,a1,a2,a3,a4);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_iii(index,a1,a2) {
+  try {
+    return Module["dynCall_iii"](index,a1,a2);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+  var cttz_i8=env.cttz_i8|0;
+  var ctlz_i8=env.ctlz_i8|0;
+  var ___rand_seed=env.___rand_seed|0;
+  var _stderr=env._stderr|0;
+  var _stdin=env._stdin|0;
+  var _stdout=env._stdout|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var invoke_iiii=env.invoke_iiii;
+  var invoke_vi=env.invoke_vi;
+  var invoke_vii=env.invoke_vii;
+  var invoke_ii=env.invoke_ii;
+  var invoke_iiiii=env.invoke_iiiii;
+  var invoke_iii=env.invoke_iii;
+  var _isalnum=env._isalnum;
+  var _fabs=env._fabs;
+  var _frexp=env._frexp;
+  var _exp=env._exp;
+  var _fread=env._fread;
+  var __reallyNegative=env.__reallyNegative;
+  var _longjmp=env._longjmp;
+  var __addDays=env.__addDays;
+  var _fsync=env._fsync;
+  var _signal=env._signal;
+  var _rename=env._rename;
+  var _sbrk=env._sbrk;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _sinh=env._sinh;
+  var _sysconf=env._sysconf;
+  var _close=env._close;
+  var _ferror=env._ferror;
+  var _clock=env._clock;
+  var _cos=env._cos;
+  var _tanh=env._tanh;
+  var _unlink=env._unlink;
+  var _write=env._write;
+  var __isLeapYear=env.__isLeapYear;
+  var _ftell=env._ftell;
+  var _isupper=env._isupper;
+  var _gmtime_r=env._gmtime_r;
+  var _islower=env._islower;
+  var _tmpnam=env._tmpnam;
+  var _tmpfile=env._tmpfile;
+  var _send=env._send;
+  var _abort=env._abort;
+  var _setvbuf=env._setvbuf;
+  var _atan2=env._atan2;
+  var _setlocale=env._setlocale;
+  var _isgraph=env._isgraph;
+  var _modf=env._modf;
+  var _strerror_r=env._strerror_r;
+  var _fscanf=env._fscanf;
+  var ___setErrNo=env.___setErrNo;
+  var _isalpha=env._isalpha;
+  var _srand=env._srand;
+  var _mktime=env._mktime;
+  var _putchar=env._putchar;
+  var _gmtime=env._gmtime;
+  var _localeconv=env._localeconv;
+  var _sprintf=env._sprintf;
+  var _localtime=env._localtime;
+  var _read=env._read;
+  var _fwrite=env._fwrite;
+  var _time=env._time;
+  var _fprintf=env._fprintf;
+  var _exit=env._exit;
+  var _freopen=env._freopen;
+  var _llvm_pow_f64=env._llvm_pow_f64;
+  var _fgetc=env._fgetc;
+  var _fmod=env._fmod;
+  var _lseek=env._lseek;
+  var _rmdir=env._rmdir;
+  var _asin=env._asin;
+  var _floor=env._floor;
+  var _pwrite=env._pwrite;
+  var _localtime_r=env._localtime_r;
+  var _tzset=env._tzset;
+  var _open=env._open;
+  var _remove=env._remove;
+  var _snprintf=env._snprintf;
+  var __scanString=env.__scanString;
+  var _strftime=env._strftime;
+  var _fseek=env._fseek;
+  var _iscntrl=env._iscntrl;
+  var _isxdigit=env._isxdigit;
+  var _fclose=env._fclose;
+  var _log=env._log;
+  var _recv=env._recv;
+  var _tan=env._tan;
+  var _copysign=env._copysign;
+  var __getFloat=env.__getFloat;
+  var _fputc=env._fputc;
+  var _ispunct=env._ispunct;
+  var _ceil=env._ceil;
+  var _isspace=env._isspace;
+  var _fopen=env._fopen;
+  var _sin=env._sin;
+  var _acos=env._acos;
+  var _cosh=env._cosh;
+  var ___buildEnvironment=env.___buildEnvironment;
+  var _difftime=env._difftime;
+  var _ungetc=env._ungetc;
+  var _system=env._system;
+  var _fflush=env._fflush;
+  var _log10=env._log10;
+  var _fileno=env._fileno;
+  var __exit=env.__exit;
+  var __arraySum=env.__arraySum;
+  var _fgets=env._fgets;
+  var _atan=env._atan;
+  var _pread=env._pread;
+  var _mkport=env._mkport;
+  var _toupper=env._toupper;
+  var _feof=env._feof;
+  var ___errno_location=env.___errno_location;
+  var _clearerr=env._clearerr;
+  var _getenv=env._getenv;
+  var _strerror=env._strerror;
+  var _emscripten_longjmp=env._emscripten_longjmp;
+  var __formatString=env.__formatString;
+  var _fputs=env._fputs;
+  var _sqrt=env._sqrt;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _malloc(i12) {
+ i12 = i12 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0;
+ i1 = STACKTOP;
+ do {
+  if (i12 >>> 0 < 245) {
+   if (i12 >>> 0 < 11) {
+    i12 = 16;
+   } else {
+    i12 = i12 + 11 & -8;
+   }
+   i20 = i12 >>> 3;
+   i18 = HEAP32[3228] | 0;
+   i21 = i18 >>> i20;
+   if ((i21 & 3 | 0) != 0) {
+    i6 = (i21 & 1 ^ 1) + i20 | 0;
+    i5 = i6 << 1;
+    i3 = 12952 + (i5 << 2) | 0;
+    i5 = 12952 + (i5 + 2 << 2) | 0;
+    i7 = HEAP32[i5 >> 2] | 0;
+    i2 = i7 + 8 | 0;
+    i4 = HEAP32[i2 >> 2] | 0;
+    do {
+     if ((i3 | 0) != (i4 | 0)) {
+      if (i4 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i8 = i4 + 12 | 0;
+      if ((HEAP32[i8 >> 2] | 0) == (i7 | 0)) {
+       HEAP32[i8 >> 2] = i3;
+       HEAP32[i5 >> 2] = i4;
+       break;
+      } else {
+       _abort();
+      }
+     } else {
+      HEAP32[3228] = i18 & ~(1 << i6);
+     }
+    } while (0);
+    i32 = i6 << 3;
+    HEAP32[i7 + 4 >> 2] = i32 | 3;
+    i32 = i7 + (i32 | 4) | 0;
+    HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+    i32 = i2;
+    STACKTOP = i1;
+    return i32 | 0;
+   }
+   if (i12 >>> 0 > (HEAP32[12920 >> 2] | 0) >>> 0) {
+    if ((i21 | 0) != 0) {
+     i7 = 2 << i20;
+     i7 = i21 << i20 & (i7 | 0 - i7);
+     i7 = (i7 & 0 - i7) + -1 | 0;
+     i2 = i7 >>> 12 & 16;
+     i7 = i7 >>> i2;
+     i6 = i7 >>> 5 & 8;
+     i7 = i7 >>> i6;
+     i5 = i7 >>> 2 & 4;
+     i7 = i7 >>> i5;
+     i4 = i7 >>> 1 & 2;
+     i7 = i7 >>> i4;
+     i3 = i7 >>> 1 & 1;
+     i3 = (i6 | i2 | i5 | i4 | i3) + (i7 >>> i3) | 0;
+     i7 = i3 << 1;
+     i4 = 12952 + (i7 << 2) | 0;
+     i7 = 12952 + (i7 + 2 << 2) | 0;
+     i5 = HEAP32[i7 >> 2] | 0;
+     i2 = i5 + 8 | 0;
+     i6 = HEAP32[i2 >> 2] | 0;
+     do {
+      if ((i4 | 0) != (i6 | 0)) {
+       if (i6 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       i8 = i6 + 12 | 0;
+       if ((HEAP32[i8 >> 2] | 0) == (i5 | 0)) {
+        HEAP32[i8 >> 2] = i4;
+        HEAP32[i7 >> 2] = i6;
+        break;
+       } else {
+        _abort();
+       }
+      } else {
+       HEAP32[3228] = i18 & ~(1 << i3);
+      }
+     } while (0);
+     i6 = i3 << 3;
+     i4 = i6 - i12 | 0;
+     HEAP32[i5 + 4 >> 2] = i12 | 3;
+     i3 = i5 + i12 | 0;
+     HEAP32[i5 + (i12 | 4) >> 2] = i4 | 1;
+     HEAP32[i5 + i6 >> 2] = i4;
+     i6 = HEAP32[12920 >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      i5 = HEAP32[12932 >> 2] | 0;
+      i8 = i6 >>> 3;
+      i9 = i8 << 1;
+      i6 = 12952 + (i9 << 2) | 0;
+      i7 = HEAP32[3228] | 0;
+      i8 = 1 << i8;
+      if ((i7 & i8 | 0) != 0) {
+       i7 = 12952 + (i9 + 2 << 2) | 0;
+       i8 = HEAP32[i7 >> 2] | 0;
+       if (i8 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i28 = i7;
+        i27 = i8;
+       }
+      } else {
+       HEAP32[3228] = i7 | i8;
+       i28 = 12952 + (i9 + 2 << 2) | 0;
+       i27 = i6;
+      }
+      HEAP32[i28 >> 2] = i5;
+      HEAP32[i27 + 12 >> 2] = i5;
+      HEAP32[i5 + 8 >> 2] = i27;
+      HEAP32[i5 + 12 >> 2] = i6;
+     }
+     HEAP32[12920 >> 2] = i4;
+     HEAP32[12932 >> 2] = i3;
+     i32 = i2;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i18 = HEAP32[12916 >> 2] | 0;
+    if ((i18 | 0) != 0) {
+     i2 = (i18 & 0 - i18) + -1 | 0;
+     i31 = i2 >>> 12 & 16;
+     i2 = i2 >>> i31;
+     i30 = i2 >>> 5 & 8;
+     i2 = i2 >>> i30;
+     i32 = i2 >>> 2 & 4;
+     i2 = i2 >>> i32;
+     i6 = i2 >>> 1 & 2;
+     i2 = i2 >>> i6;
+     i3 = i2 >>> 1 & 1;
+     i3 = HEAP32[13216 + ((i30 | i31 | i32 | i6 | i3) + (i2 >>> i3) << 2) >> 2] | 0;
+     i2 = (HEAP32[i3 + 4 >> 2] & -8) - i12 | 0;
+     i6 = i3;
+     while (1) {
+      i5 = HEAP32[i6 + 16 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       i5 = HEAP32[i6 + 20 >> 2] | 0;
+       if ((i5 | 0) == 0) {
+        break;
+       }
+      }
+      i6 = (HEAP32[i5 + 4 >> 2] & -8) - i12 | 0;
+      i4 = i6 >>> 0 < i2 >>> 0;
+      i2 = i4 ? i6 : i2;
+      i6 = i5;
+      i3 = i4 ? i5 : i3;
+     }
+     i6 = HEAP32[12928 >> 2] | 0;
+     if (i3 >>> 0 < i6 >>> 0) {
+      _abort();
+     }
+     i4 = i3 + i12 | 0;
+     if (!(i3 >>> 0 < i4 >>> 0)) {
+      _abort();
+     }
+     i5 = HEAP32[i3 + 24 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     do {
+      if ((i7 | 0) == (i3 | 0)) {
+       i8 = i3 + 20 | 0;
+       i7 = HEAP32[i8 >> 2] | 0;
+       if ((i7 | 0) == 0) {
+        i8 = i3 + 16 | 0;
+        i7 = HEAP32[i8 >> 2] | 0;
+        if ((i7 | 0) == 0) {
+         i26 = 0;
+         break;
+        }
+       }
+       while (1) {
+        i10 = i7 + 20 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) != 0) {
+         i7 = i9;
+         i8 = i10;
+         continue;
+        }
+        i10 = i7 + 16 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) == 0) {
+         break;
+        } else {
+         i7 = i9;
+         i8 = i10;
+        }
+       }
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i8 >> 2] = 0;
+        i26 = i7;
+        break;
+       }
+      } else {
+       i8 = HEAP32[i3 + 8 >> 2] | 0;
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       }
+       i6 = i8 + 12 | 0;
+       if ((HEAP32[i6 >> 2] | 0) != (i3 | 0)) {
+        _abort();
+       }
+       i9 = i7 + 8 | 0;
+       if ((HEAP32[i9 >> 2] | 0) == (i3 | 0)) {
+        HEAP32[i6 >> 2] = i7;
+        HEAP32[i9 >> 2] = i8;
+        i26 = i7;
+        break;
+       } else {
+        _abort();
+       }
+      }
+     } while (0);
+     do {
+      if ((i5 | 0) != 0) {
+       i7 = HEAP32[i3 + 28 >> 2] | 0;
+       i6 = 13216 + (i7 << 2) | 0;
+       if ((i3 | 0) == (HEAP32[i6 >> 2] | 0)) {
+        HEAP32[i6 >> 2] = i26;
+        if ((i26 | 0) == 0) {
+         HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i7);
+         break;
+        }
+       } else {
+        if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        i6 = i5 + 16 | 0;
+        if ((HEAP32[i6 >> 2] | 0) == (i3 | 0)) {
+         HEAP32[i6 >> 2] = i26;
+        } else {
+         HEAP32[i5 + 20 >> 2] = i26;
+        }
+        if ((i26 | 0) == 0) {
+         break;
+        }
+       }
+       if (i26 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       HEAP32[i26 + 24 >> 2] = i5;
+       i5 = HEAP32[i3 + 16 >> 2] | 0;
+       do {
+        if ((i5 | 0) != 0) {
+         if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i26 + 16 >> 2] = i5;
+          HEAP32[i5 + 24 >> 2] = i26;
+          break;
+         }
+        }
+       } while (0);
+       i5 = HEAP32[i3 + 20 >> 2] | 0;
+       if ((i5 | 0) != 0) {
+        if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i26 + 20 >> 2] = i5;
+         HEAP32[i5 + 24 >> 2] = i26;
+         break;
+        }
+       }
+      }
+     } while (0);
+     if (i2 >>> 0 < 16) {
+      i32 = i2 + i12 | 0;
+      HEAP32[i3 + 4 >> 2] = i32 | 3;
+      i32 = i3 + (i32 + 4) | 0;
+      HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+     } else {
+      HEAP32[i3 + 4 >> 2] = i12 | 3;
+      HEAP32[i3 + (i12 | 4) >> 2] = i2 | 1;
+      HEAP32[i3 + (i2 + i12) >> 2] = i2;
+      i6 = HEAP32[12920 >> 2] | 0;
+      if ((i6 | 0) != 0) {
+       i5 = HEAP32[12932 >> 2] | 0;
+       i8 = i6 >>> 3;
+       i9 = i8 << 1;
+       i6 = 12952 + (i9 << 2) | 0;
+       i7 = HEAP32[3228] | 0;
+       i8 = 1 << i8;
+       if ((i7 & i8 | 0) != 0) {
+        i7 = 12952 + (i9 + 2 << 2) | 0;
+        i8 = HEAP32[i7 >> 2] | 0;
+        if (i8 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         i25 = i7;
+         i24 = i8;
+        }
+       } else {
+        HEAP32[3228] = i7 | i8;
+        i25 = 12952 + (i9 + 2 << 2) | 0;
+        i24 = i6;
+       }
+       HEAP32[i25 >> 2] = i5;
+       HEAP32[i24 + 12 >> 2] = i5;
+       HEAP32[i5 + 8 >> 2] = i24;
+       HEAP32[i5 + 12 >> 2] = i6;
+      }
+      HEAP32[12920 >> 2] = i2;
+      HEAP32[12932 >> 2] = i4;
+     }
+     i32 = i3 + 8 | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+   }
+  } else {
+   if (!(i12 >>> 0 > 4294967231)) {
+    i24 = i12 + 11 | 0;
+    i12 = i24 & -8;
+    i26 = HEAP32[12916 >> 2] | 0;
+    if ((i26 | 0) != 0) {
+     i25 = 0 - i12 | 0;
+     i24 = i24 >>> 8;
+     if ((i24 | 0) != 0) {
+      if (i12 >>> 0 > 16777215) {
+       i27 = 31;
+      } else {
+       i31 = (i24 + 1048320 | 0) >>> 16 & 8;
+       i32 = i24 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i27 = (i32 + 245760 | 0) >>> 16 & 2;
+       i27 = 14 - (i30 | i31 | i27) + (i32 << i27 >>> 15) | 0;
+       i27 = i12 >>> (i27 + 7 | 0) & 1 | i27 << 1;
+      }
+     } else {
+      i27 = 0;
+     }
+     i30 = HEAP32[13216 + (i27 << 2) >> 2] | 0;
+     L126 : do {
+      if ((i30 | 0) == 0) {
+       i29 = 0;
+       i24 = 0;
+      } else {
+       if ((i27 | 0) == 31) {
+        i24 = 0;
+       } else {
+        i24 = 25 - (i27 >>> 1) | 0;
+       }
+       i29 = 0;
+       i28 = i12 << i24;
+       i24 = 0;
+       while (1) {
+        i32 = HEAP32[i30 + 4 >> 2] & -8;
+        i31 = i32 - i12 | 0;
+        if (i31 >>> 0 < i25 >>> 0) {
+         if ((i32 | 0) == (i12 | 0)) {
+          i25 = i31;
+          i29 = i30;
+          i24 = i30;
+          break L126;
+         } else {
+          i25 = i31;
+          i24 = i30;
+         }
+        }
+        i31 = HEAP32[i30 + 20 >> 2] | 0;
+        i30 = HEAP32[i30 + (i28 >>> 31 << 2) + 16 >> 2] | 0;
+        i29 = (i31 | 0) == 0 | (i31 | 0) == (i30 | 0) ? i29 : i31;
+        if ((i30 | 0) == 0) {
+         break;
+        } else {
+         i28 = i28 << 1;
+        }
+       }
+      }
+     } while (0);
+     if ((i29 | 0) == 0 & (i24 | 0) == 0) {
+      i32 = 2 << i27;
+      i26 = i26 & (i32 | 0 - i32);
+      if ((i26 | 0) == 0) {
+       break;
+      }
+      i32 = (i26 & 0 - i26) + -1 | 0;
+      i28 = i32 >>> 12 & 16;
+      i32 = i32 >>> i28;
+      i27 = i32 >>> 5 & 8;
+      i32 = i32 >>> i27;
+      i30 = i32 >>> 2 & 4;
+      i32 = i32 >>> i30;
+      i31 = i32 >>> 1 & 2;
+      i32 = i32 >>> i31;
+      i29 = i32 >>> 1 & 1;
+      i29 = HEAP32[13216 + ((i27 | i28 | i30 | i31 | i29) + (i32 >>> i29) << 2) >> 2] | 0;
+     }
+     if ((i29 | 0) != 0) {
+      while (1) {
+       i27 = (HEAP32[i29 + 4 >> 2] & -8) - i12 | 0;
+       i26 = i27 >>> 0 < i25 >>> 0;
+       i25 = i26 ? i27 : i25;
+       i24 = i26 ? i29 : i24;
+       i26 = HEAP32[i29 + 16 >> 2] | 0;
+       if ((i26 | 0) != 0) {
+        i29 = i26;
+        continue;
+       }
+       i29 = HEAP32[i29 + 20 >> 2] | 0;
+       if ((i29 | 0) == 0) {
+        break;
+       }
+      }
+     }
+     if ((i24 | 0) != 0 ? i25 >>> 0 < ((HEAP32[12920 >> 2] | 0) - i12 | 0) >>> 0 : 0) {
+      i4 = HEAP32[12928 >> 2] | 0;
+      if (i24 >>> 0 < i4 >>> 0) {
+       _abort();
+      }
+      i2 = i24 + i12 | 0;
+      if (!(i24 >>> 0 < i2 >>> 0)) {
+       _abort();
+      }
+      i3 = HEAP32[i24 + 24 >> 2] | 0;
+      i6 = HEAP32[i24 + 12 >> 2] | 0;
+      do {
+       if ((i6 | 0) == (i24 | 0)) {
+        i6 = i24 + 20 | 0;
+        i5 = HEAP32[i6 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         i6 = i24 + 16 | 0;
+         i5 = HEAP32[i6 >> 2] | 0;
+         if ((i5 | 0) == 0) {
+          i22 = 0;
+          break;
+         }
+        }
+        while (1) {
+         i8 = i5 + 20 | 0;
+         i7 = HEAP32[i8 >> 2] | 0;
+         if ((i7 | 0) != 0) {
+          i5 = i7;
+          i6 = i8;
+          continue;
+         }
+         i7 = i5 + 16 | 0;
+         i8 = HEAP32[i7 >> 2] | 0;
+         if ((i8 | 0) == 0) {
+          break;
+         } else {
+          i5 = i8;
+          i6 = i7;
+         }
+        }
+        if (i6 >>> 0 < i4 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i6 >> 2] = 0;
+         i22 = i5;
+         break;
+        }
+       } else {
+        i5 = HEAP32[i24 + 8 >> 2] | 0;
+        if (i5 >>> 0 < i4 >>> 0) {
+         _abort();
+        }
+        i7 = i5 + 12 | 0;
+        if ((HEAP32[i7 >> 2] | 0) != (i24 | 0)) {
+         _abort();
+        }
+        i4 = i6 + 8 | 0;
+        if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+         HEAP32[i7 >> 2] = i6;
+         HEAP32[i4 >> 2] = i5;
+         i22 = i6;
+         break;
+        } else {
+         _abort();
+        }
+       }
+      } while (0);
+      do {
+       if ((i3 | 0) != 0) {
+        i4 = HEAP32[i24 + 28 >> 2] | 0;
+        i5 = 13216 + (i4 << 2) | 0;
+        if ((i24 | 0) == (HEAP32[i5 >> 2] | 0)) {
+         HEAP32[i5 >> 2] = i22;
+         if ((i22 | 0) == 0) {
+          HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i4);
+          break;
+         }
+        } else {
+         if (i3 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+          _abort();
+         }
+         i4 = i3 + 16 | 0;
+         if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+          HEAP32[i4 >> 2] = i22;
+         } else {
+          HEAP32[i3 + 20 >> 2] = i22;
+         }
+         if ((i22 | 0) == 0) {
+          break;
+         }
+        }
+        if (i22 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        HEAP32[i22 + 24 >> 2] = i3;
+        i3 = HEAP32[i24 + 16 >> 2] | 0;
+        do {
+         if ((i3 | 0) != 0) {
+          if (i3 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i22 + 16 >> 2] = i3;
+           HEAP32[i3 + 24 >> 2] = i22;
+           break;
+          }
+         }
+        } while (0);
+        i3 = HEAP32[i24 + 20 >> 2] | 0;
+        if ((i3 | 0) != 0) {
+         if (i3 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i22 + 20 >> 2] = i3;
+          HEAP32[i3 + 24 >> 2] = i22;
+          break;
+         }
+        }
+       }
+      } while (0);
+      L204 : do {
+       if (!(i25 >>> 0 < 16)) {
+        HEAP32[i24 + 4 >> 2] = i12 | 3;
+        HEAP32[i24 + (i12 | 4) >> 2] = i25 | 1;
+        HEAP32[i24 + (i25 + i12) >> 2] = i25;
+        i4 = i25 >>> 3;
+        if (i25 >>> 0 < 256) {
+         i6 = i4 << 1;
+         i3 = 12952 + (i6 << 2) | 0;
+         i5 = HEAP32[3228] | 0;
+         i4 = 1 << i4;
+         if ((i5 & i4 | 0) != 0) {
+          i5 = 12952 + (i6 + 2 << 2) | 0;
+          i4 = HEAP32[i5 >> 2] | 0;
+          if (i4 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           i21 = i5;
+           i20 = i4;
+          }
+         } else {
+          HEAP32[3228] = i5 | i4;
+          i21 = 12952 + (i6 + 2 << 2) | 0;
+          i20 = i3;
+         }
+         HEAP32[i21 >> 2] = i2;
+         HEAP32[i20 + 12 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i20;
+         HEAP32[i24 + (i12 + 12) >> 2] = i3;
+         break;
+        }
+        i3 = i25 >>> 8;
+        if ((i3 | 0) != 0) {
+         if (i25 >>> 0 > 16777215) {
+          i3 = 31;
+         } else {
+          i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+          i32 = i3 << i31;
+          i30 = (i32 + 520192 | 0) >>> 16 & 4;
+          i32 = i32 << i30;
+          i3 = (i32 + 245760 | 0) >>> 16 & 2;
+          i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+          i3 = i25 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+         }
+        } else {
+         i3 = 0;
+        }
+        i6 = 13216 + (i3 << 2) | 0;
+        HEAP32[i24 + (i12 + 28) >> 2] = i3;
+        HEAP32[i24 + (i12 + 20) >> 2] = 0;
+        HEAP32[i24 + (i12 + 16) >> 2] = 0;
+        i4 = HEAP32[12916 >> 2] | 0;
+        i5 = 1 << i3;
+        if ((i4 & i5 | 0) == 0) {
+         HEAP32[12916 >> 2] = i4 | i5;
+         HEAP32[i6 >> 2] = i2;
+         HEAP32[i24 + (i12 + 24) >> 2] = i6;
+         HEAP32[i24 + (i12 + 12) >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i2;
+         break;
+        }
+        i4 = HEAP32[i6 >> 2] | 0;
+        if ((i3 | 0) == 31) {
+         i3 = 0;
+        } else {
+         i3 = 25 - (i3 >>> 1) | 0;
+        }
+        L225 : do {
+         if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i25 | 0)) {
+          i3 = i25 << i3;
+          while (1) {
+           i6 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+           i5 = HEAP32[i6 >> 2] | 0;
+           if ((i5 | 0) == 0) {
+            break;
+           }
+           if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i25 | 0)) {
+            i18 = i5;
+            break L225;
+           } else {
+            i3 = i3 << 1;
+            i4 = i5;
+           }
+          }
+          if (i6 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i6 >> 2] = i2;
+           HEAP32[i24 + (i12 + 24) >> 2] = i4;
+           HEAP32[i24 + (i12 + 12) >> 2] = i2;
+           HEAP32[i24 + (i12 + 8) >> 2] = i2;
+           break L204;
+          }
+         } else {
+          i18 = i4;
+         }
+        } while (0);
+        i4 = i18 + 8 | 0;
+        i3 = HEAP32[i4 >> 2] | 0;
+        i5 = HEAP32[12928 >> 2] | 0;
+        if (i18 >>> 0 < i5 >>> 0) {
+         _abort();
+        }
+        if (i3 >>> 0 < i5 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i3 + 12 >> 2] = i2;
+         HEAP32[i4 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i3;
+         HEAP32[i24 + (i12 + 12) >> 2] = i18;
+         HEAP32[i24 + (i12 + 24) >> 2] = 0;
+         break;
+        }
+       } else {
+        i32 = i25 + i12 | 0;
+        HEAP32[i24 + 4 >> 2] = i32 | 3;
+        i32 = i24 + (i32 + 4) | 0;
+        HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+       }
+      } while (0);
+      i32 = i24 + 8 | 0;
+      STACKTOP = i1;
+      return i32 | 0;
+     }
+    }
+   } else {
+    i12 = -1;
+   }
+  }
+ } while (0);
+ i18 = HEAP32[12920 >> 2] | 0;
+ if (!(i12 >>> 0 > i18 >>> 0)) {
+  i3 = i18 - i12 | 0;
+  i2 = HEAP32[12932 >> 2] | 0;
+  if (i3 >>> 0 > 15) {
+   HEAP32[12932 >> 2] = i2 + i12;
+   HEAP32[12920 >> 2] = i3;
+   HEAP32[i2 + (i12 + 4) >> 2] = i3 | 1;
+   HEAP32[i2 + i18 >> 2] = i3;
+   HEAP32[i2 + 4 >> 2] = i12 | 3;
+  } else {
+   HEAP32[12920 >> 2] = 0;
+   HEAP32[12932 >> 2] = 0;
+   HEAP32[i2 + 4 >> 2] = i18 | 3;
+   i32 = i2 + (i18 + 4) | 0;
+   HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+  }
+  i32 = i2 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i18 = HEAP32[12924 >> 2] | 0;
+ if (i12 >>> 0 < i18 >>> 0) {
+  i31 = i18 - i12 | 0;
+  HEAP32[12924 >> 2] = i31;
+  i32 = HEAP32[12936 >> 2] | 0;
+  HEAP32[12936 >> 2] = i32 + i12;
+  HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+  HEAP32[i32 + 4 >> 2] = i12 | 3;
+  i32 = i32 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ do {
+  if ((HEAP32[3346] | 0) == 0) {
+   i18 = _sysconf(30) | 0;
+   if ((i18 + -1 & i18 | 0) == 0) {
+    HEAP32[13392 >> 2] = i18;
+    HEAP32[13388 >> 2] = i18;
+    HEAP32[13396 >> 2] = -1;
+    HEAP32[13400 >> 2] = -1;
+    HEAP32[13404 >> 2] = 0;
+    HEAP32[13356 >> 2] = 0;
+    HEAP32[3346] = (_time(0) | 0) & -16 ^ 1431655768;
+    break;
+   } else {
+    _abort();
+   }
+  }
+ } while (0);
+ i20 = i12 + 48 | 0;
+ i25 = HEAP32[13392 >> 2] | 0;
+ i21 = i12 + 47 | 0;
+ i22 = i25 + i21 | 0;
+ i25 = 0 - i25 | 0;
+ i18 = i22 & i25;
+ if (!(i18 >>> 0 > i12 >>> 0)) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i24 = HEAP32[13352 >> 2] | 0;
+ if ((i24 | 0) != 0 ? (i31 = HEAP32[13344 >> 2] | 0, i32 = i31 + i18 | 0, i32 >>> 0 <= i31 >>> 0 | i32 >>> 0 > i24 >>> 0) : 0) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ L269 : do {
+  if ((HEAP32[13356 >> 2] & 4 | 0) == 0) {
+   i26 = HEAP32[12936 >> 2] | 0;
+   L271 : do {
+    if ((i26 | 0) != 0) {
+     i24 = 13360 | 0;
+     while (1) {
+      i27 = HEAP32[i24 >> 2] | 0;
+      if (!(i27 >>> 0 > i26 >>> 0) ? (i23 = i24 + 4 | 0, (i27 + (HEAP32[i23 >> 2] | 0) | 0) >>> 0 > i26 >>> 0) : 0) {
+       break;
+      }
+      i24 = HEAP32[i24 + 8 >> 2] | 0;
+      if ((i24 | 0) == 0) {
+       i13 = 182;
+       break L271;
+      }
+     }
+     if ((i24 | 0) != 0) {
+      i25 = i22 - (HEAP32[12924 >> 2] | 0) & i25;
+      if (i25 >>> 0 < 2147483647) {
+       i13 = _sbrk(i25 | 0) | 0;
+       i26 = (i13 | 0) == ((HEAP32[i24 >> 2] | 0) + (HEAP32[i23 >> 2] | 0) | 0);
+       i22 = i13;
+       i24 = i25;
+       i23 = i26 ? i13 : -1;
+       i25 = i26 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i13 = 182;
+     }
+    } else {
+     i13 = 182;
+    }
+   } while (0);
+   do {
+    if ((i13 | 0) == 182) {
+     i23 = _sbrk(0) | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i24 = i23;
+      i22 = HEAP32[13388 >> 2] | 0;
+      i25 = i22 + -1 | 0;
+      if ((i25 & i24 | 0) == 0) {
+       i25 = i18;
+      } else {
+       i25 = i18 - i24 + (i25 + i24 & 0 - i22) | 0;
+      }
+      i24 = HEAP32[13344 >> 2] | 0;
+      i26 = i24 + i25 | 0;
+      if (i25 >>> 0 > i12 >>> 0 & i25 >>> 0 < 2147483647) {
+       i22 = HEAP32[13352 >> 2] | 0;
+       if ((i22 | 0) != 0 ? i26 >>> 0 <= i24 >>> 0 | i26 >>> 0 > i22 >>> 0 : 0) {
+        i25 = 0;
+        break;
+       }
+       i22 = _sbrk(i25 | 0) | 0;
+       i13 = (i22 | 0) == (i23 | 0);
+       i24 = i25;
+       i23 = i13 ? i23 : -1;
+       i25 = i13 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i25 = 0;
+     }
+    }
+   } while (0);
+   L291 : do {
+    if ((i13 | 0) == 191) {
+     i13 = 0 - i24 | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i17 = i23;
+      i14 = i25;
+      i13 = 202;
+      break L269;
+     }
+     do {
+      if ((i22 | 0) != (-1 | 0) & i24 >>> 0 < 2147483647 & i24 >>> 0 < i20 >>> 0 ? (i19 = HEAP32[13392 >> 2] | 0, i19 = i21 - i24 + i19 & 0 - i19, i19 >>> 0 < 2147483647) : 0) {
+       if ((_sbrk(i19 | 0) | 0) == (-1 | 0)) {
+        _sbrk(i13 | 0) | 0;
+        break L291;
+       } else {
+        i24 = i19 + i24 | 0;
+        break;
+       }
+      }
+     } while (0);
+     if ((i22 | 0) != (-1 | 0)) {
+      i17 = i22;
+      i14 = i24;
+      i13 = 202;
+      break L269;
+     }
+    }
+   } while (0);
+   HEAP32[13356 >> 2] = HEAP32[13356 >> 2] | 4;
+   i13 = 199;
+  } else {
+   i25 = 0;
+   i13 = 199;
+  }
+ } while (0);
+ if ((((i13 | 0) == 199 ? i18 >>> 0 < 2147483647 : 0) ? (i17 = _sbrk(i18 | 0) | 0, i16 = _sbrk(0) | 0, (i16 | 0) != (-1 | 0) & (i17 | 0) != (-1 | 0) & i17 >>> 0 < i16 >>> 0) : 0) ? (i15 = i16 - i17 | 0, i14 = i15 >>> 0 > (i12 + 40 | 0) >>> 0, i14) : 0) {
+  i14 = i14 ? i15 : i25;
+  i13 = 202;
+ }
+ if ((i13 | 0) == 202) {
+  i15 = (HEAP32[13344 >> 2] | 0) + i14 | 0;
+  HEAP32[13344 >> 2] = i15;
+  if (i15 >>> 0 > (HEAP32[13348 >> 2] | 0) >>> 0) {
+   HEAP32[13348 >> 2] = i15;
+  }
+  i15 = HEAP32[12936 >> 2] | 0;
+  L311 : do {
+   if ((i15 | 0) != 0) {
+    i21 = 13360 | 0;
+    while (1) {
+     i16 = HEAP32[i21 >> 2] | 0;
+     i19 = i21 + 4 | 0;
+     i20 = HEAP32[i19 >> 2] | 0;
+     if ((i17 | 0) == (i16 + i20 | 0)) {
+      i13 = 214;
+      break;
+     }
+     i18 = HEAP32[i21 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i21 = i18;
+     }
+    }
+    if (((i13 | 0) == 214 ? (HEAP32[i21 + 12 >> 2] & 8 | 0) == 0 : 0) ? i15 >>> 0 >= i16 >>> 0 & i15 >>> 0 < i17 >>> 0 : 0) {
+     HEAP32[i19 >> 2] = i20 + i14;
+     i2 = (HEAP32[12924 >> 2] | 0) + i14 | 0;
+     i3 = i15 + 8 | 0;
+     if ((i3 & 7 | 0) == 0) {
+      i3 = 0;
+     } else {
+      i3 = 0 - i3 & 7;
+     }
+     i32 = i2 - i3 | 0;
+     HEAP32[12936 >> 2] = i15 + i3;
+     HEAP32[12924 >> 2] = i32;
+     HEAP32[i15 + (i3 + 4) >> 2] = i32 | 1;
+     HEAP32[i15 + (i2 + 4) >> 2] = 40;
+     HEAP32[12940 >> 2] = HEAP32[13400 >> 2];
+     break;
+    }
+    if (i17 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+     HEAP32[12928 >> 2] = i17;
+    }
+    i19 = i17 + i14 | 0;
+    i16 = 13360 | 0;
+    while (1) {
+     if ((HEAP32[i16 >> 2] | 0) == (i19 | 0)) {
+      i13 = 224;
+      break;
+     }
+     i18 = HEAP32[i16 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i16 = i18;
+     }
+    }
+    if ((i13 | 0) == 224 ? (HEAP32[i16 + 12 >> 2] & 8 | 0) == 0 : 0) {
+     HEAP32[i16 >> 2] = i17;
+     i6 = i16 + 4 | 0;
+     HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i14;
+     i6 = i17 + 8 | 0;
+     if ((i6 & 7 | 0) == 0) {
+      i6 = 0;
+     } else {
+      i6 = 0 - i6 & 7;
+     }
+     i7 = i17 + (i14 + 8) | 0;
+     if ((i7 & 7 | 0) == 0) {
+      i13 = 0;
+     } else {
+      i13 = 0 - i7 & 7;
+     }
+     i15 = i17 + (i13 + i14) | 0;
+     i8 = i6 + i12 | 0;
+     i7 = i17 + i8 | 0;
+     i10 = i15 - (i17 + i6) - i12 | 0;
+     HEAP32[i17 + (i6 + 4) >> 2] = i12 | 3;
+     L348 : do {
+      if ((i15 | 0) != (HEAP32[12936 >> 2] | 0)) {
+       if ((i15 | 0) == (HEAP32[12932 >> 2] | 0)) {
+        i32 = (HEAP32[12920 >> 2] | 0) + i10 | 0;
+        HEAP32[12920 >> 2] = i32;
+        HEAP32[12932 >> 2] = i7;
+        HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+        HEAP32[i17 + (i32 + i8) >> 2] = i32;
+        break;
+       }
+       i12 = i14 + 4 | 0;
+       i18 = HEAP32[i17 + (i12 + i13) >> 2] | 0;
+       if ((i18 & 3 | 0) == 1) {
+        i11 = i18 & -8;
+        i16 = i18 >>> 3;
+        do {
+         if (!(i18 >>> 0 < 256)) {
+          i9 = HEAP32[i17 + ((i13 | 24) + i14) >> 2] | 0;
+          i19 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          do {
+           if ((i19 | 0) == (i15 | 0)) {
+            i19 = i13 | 16;
+            i18 = i17 + (i12 + i19) | 0;
+            i16 = HEAP32[i18 >> 2] | 0;
+            if ((i16 | 0) == 0) {
+             i18 = i17 + (i19 + i14) | 0;
+             i16 = HEAP32[i18 >> 2] | 0;
+             if ((i16 | 0) == 0) {
+              i5 = 0;
+              break;
+             }
+            }
+            while (1) {
+             i20 = i16 + 20 | 0;
+             i19 = HEAP32[i20 >> 2] | 0;
+             if ((i19 | 0) != 0) {
+              i16 = i19;
+              i18 = i20;
+              continue;
+             }
+             i19 = i16 + 16 | 0;
+             i20 = HEAP32[i19 >> 2] | 0;
+             if ((i20 | 0) == 0) {
+              break;
+             } else {
+              i16 = i20;
+              i18 = i19;
+             }
+            }
+            if (i18 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i18 >> 2] = 0;
+             i5 = i16;
+             break;
+            }
+           } else {
+            i18 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+            if (i18 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i18 + 12 | 0;
+            if ((HEAP32[i16 >> 2] | 0) != (i15 | 0)) {
+             _abort();
+            }
+            i20 = i19 + 8 | 0;
+            if ((HEAP32[i20 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i19;
+             HEAP32[i20 >> 2] = i18;
+             i5 = i19;
+             break;
+            } else {
+             _abort();
+            }
+           }
+          } while (0);
+          if ((i9 | 0) != 0) {
+           i16 = HEAP32[i17 + (i14 + 28 + i13) >> 2] | 0;
+           i18 = 13216 + (i16 << 2) | 0;
+           if ((i15 | 0) == (HEAP32[i18 >> 2] | 0)) {
+            HEAP32[i18 >> 2] = i5;
+            if ((i5 | 0) == 0) {
+             HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i16);
+             break;
+            }
+           } else {
+            if (i9 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i9 + 16 | 0;
+            if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i5;
+            } else {
+             HEAP32[i9 + 20 >> 2] = i5;
+            }
+            if ((i5 | 0) == 0) {
+             break;
+            }
+           }
+           if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           HEAP32[i5 + 24 >> 2] = i9;
+           i15 = i13 | 16;
+           i9 = HEAP32[i17 + (i15 + i14) >> 2] | 0;
+           do {
+            if ((i9 | 0) != 0) {
+             if (i9 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+              _abort();
+             } else {
+              HEAP32[i5 + 16 >> 2] = i9;
+              HEAP32[i9 + 24 >> 2] = i5;
+              break;
+             }
+            }
+           } while (0);
+           i9 = HEAP32[i17 + (i12 + i15) >> 2] | 0;
+           if ((i9 | 0) != 0) {
+            if (i9 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i5 + 20 >> 2] = i9;
+             HEAP32[i9 + 24 >> 2] = i5;
+             break;
+            }
+           }
+          }
+         } else {
+          i5 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+          i12 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          i18 = 12952 + (i16 << 1 << 2) | 0;
+          if ((i5 | 0) != (i18 | 0)) {
+           if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           if ((HEAP32[i5 + 12 >> 2] | 0) != (i15 | 0)) {
+            _abort();
+           }
+          }
+          if ((i12 | 0) == (i5 | 0)) {
+           HEAP32[3228] = HEAP32[3228] & ~(1 << i16);
+           break;
+          }
+          if ((i12 | 0) != (i18 | 0)) {
+           if (i12 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           i16 = i12 + 8 | 0;
+           if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+            i9 = i16;
+           } else {
+            _abort();
+           }
+          } else {
+           i9 = i12 + 8 | 0;
+          }
+          HEAP32[i5 + 12 >> 2] = i12;
+          HEAP32[i9 >> 2] = i5;
+         }
+        } while (0);
+        i15 = i17 + ((i11 | i13) + i14) | 0;
+        i10 = i11 + i10 | 0;
+       }
+       i5 = i15 + 4 | 0;
+       HEAP32[i5 >> 2] = HEAP32[i5 >> 2] & -2;
+       HEAP32[i17 + (i8 + 4) >> 2] = i10 | 1;
+       HEAP32[i17 + (i10 + i8) >> 2] = i10;
+       i5 = i10 >>> 3;
+       if (i10 >>> 0 < 256) {
+        i10 = i5 << 1;
+        i2 = 12952 + (i10 << 2) | 0;
+        i9 = HEAP32[3228] | 0;
+        i5 = 1 << i5;
+        if ((i9 & i5 | 0) != 0) {
+         i9 = 12952 + (i10 + 2 << 2) | 0;
+         i5 = HEAP32[i9 >> 2] | 0;
+         if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          i3 = i9;
+          i4 = i5;
+         }
+        } else {
+         HEAP32[3228] = i9 | i5;
+         i3 = 12952 + (i10 + 2 << 2) | 0;
+         i4 = i2;
+        }
+        HEAP32[i3 >> 2] = i7;
+        HEAP32[i4 + 12 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        break;
+       }
+       i3 = i10 >>> 8;
+       if ((i3 | 0) != 0) {
+        if (i10 >>> 0 > 16777215) {
+         i3 = 31;
+        } else {
+         i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+         i32 = i3 << i31;
+         i30 = (i32 + 520192 | 0) >>> 16 & 4;
+         i32 = i32 << i30;
+         i3 = (i32 + 245760 | 0) >>> 16 & 2;
+         i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+         i3 = i10 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+        }
+       } else {
+        i3 = 0;
+       }
+       i4 = 13216 + (i3 << 2) | 0;
+       HEAP32[i17 + (i8 + 28) >> 2] = i3;
+       HEAP32[i17 + (i8 + 20) >> 2] = 0;
+       HEAP32[i17 + (i8 + 16) >> 2] = 0;
+       i9 = HEAP32[12916 >> 2] | 0;
+       i5 = 1 << i3;
+       if ((i9 & i5 | 0) == 0) {
+        HEAP32[12916 >> 2] = i9 | i5;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 24) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i7;
+        break;
+       }
+       i4 = HEAP32[i4 >> 2] | 0;
+       if ((i3 | 0) == 31) {
+        i3 = 0;
+       } else {
+        i3 = 25 - (i3 >>> 1) | 0;
+       }
+       L445 : do {
+        if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i10 | 0)) {
+         i3 = i10 << i3;
+         while (1) {
+          i5 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+          i9 = HEAP32[i5 >> 2] | 0;
+          if ((i9 | 0) == 0) {
+           break;
+          }
+          if ((HEAP32[i9 + 4 >> 2] & -8 | 0) == (i10 | 0)) {
+           i2 = i9;
+           break L445;
+          } else {
+           i3 = i3 << 1;
+           i4 = i9;
+          }
+         }
+         if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i5 >> 2] = i7;
+          HEAP32[i17 + (i8 + 24) >> 2] = i4;
+          HEAP32[i17 + (i8 + 12) >> 2] = i7;
+          HEAP32[i17 + (i8 + 8) >> 2] = i7;
+          break L348;
+         }
+        } else {
+         i2 = i4;
+        }
+       } while (0);
+       i4 = i2 + 8 | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       i5 = HEAP32[12928 >> 2] | 0;
+       if (i2 >>> 0 < i5 >>> 0) {
+        _abort();
+       }
+       if (i3 >>> 0 < i5 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i3 + 12 >> 2] = i7;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i3;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        HEAP32[i17 + (i8 + 24) >> 2] = 0;
+        break;
+       }
+      } else {
+       i32 = (HEAP32[12924 >> 2] | 0) + i10 | 0;
+       HEAP32[12924 >> 2] = i32;
+       HEAP32[12936 >> 2] = i7;
+       HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+      }
+     } while (0);
+     i32 = i17 + (i6 | 8) | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i3 = 13360 | 0;
+    while (1) {
+     i2 = HEAP32[i3 >> 2] | 0;
+     if (!(i2 >>> 0 > i15 >>> 0) ? (i11 = HEAP32[i3 + 4 >> 2] | 0, i10 = i2 + i11 | 0, i10 >>> 0 > i15 >>> 0) : 0) {
+      break;
+     }
+     i3 = HEAP32[i3 + 8 >> 2] | 0;
+    }
+    i3 = i2 + (i11 + -39) | 0;
+    if ((i3 & 7 | 0) == 0) {
+     i3 = 0;
+    } else {
+     i3 = 0 - i3 & 7;
+    }
+    i2 = i2 + (i11 + -47 + i3) | 0;
+    i2 = i2 >>> 0 < (i15 + 16 | 0) >>> 0 ? i15 : i2;
+    i3 = i2 + 8 | 0;
+    i4 = i17 + 8 | 0;
+    if ((i4 & 7 | 0) == 0) {
+     i4 = 0;
+    } else {
+     i4 = 0 - i4 & 7;
+    }
+    i32 = i14 + -40 - i4 | 0;
+    HEAP32[12936 >> 2] = i17 + i4;
+    HEAP32[12924 >> 2] = i32;
+    HEAP32[i17 + (i4 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[12940 >> 2] = HEAP32[13400 >> 2];
+    HEAP32[i2 + 4 >> 2] = 27;
+    HEAP32[i3 + 0 >> 2] = HEAP32[13360 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[13364 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[13368 >> 2];
+    HEAP32[i3 + 12 >> 2] = HEAP32[13372 >> 2];
+    HEAP32[13360 >> 2] = i17;
+    HEAP32[13364 >> 2] = i14;
+    HEAP32[13372 >> 2] = 0;
+    HEAP32[13368 >> 2] = i3;
+    i4 = i2 + 28 | 0;
+    HEAP32[i4 >> 2] = 7;
+    if ((i2 + 32 | 0) >>> 0 < i10 >>> 0) {
+     while (1) {
+      i3 = i4 + 4 | 0;
+      HEAP32[i3 >> 2] = 7;
+      if ((i4 + 8 | 0) >>> 0 < i10 >>> 0) {
+       i4 = i3;
+      } else {
+       break;
+      }
+     }
+    }
+    if ((i2 | 0) != (i15 | 0)) {
+     i2 = i2 - i15 | 0;
+     i3 = i15 + (i2 + 4) | 0;
+     HEAP32[i3 >> 2] = HEAP32[i3 >> 2] & -2;
+     HEAP32[i15 + 4 >> 2] = i2 | 1;
+     HEAP32[i15 + i2 >> 2] = i2;
+     i3 = i2 >>> 3;
+     if (i2 >>> 0 < 256) {
+      i4 = i3 << 1;
+      i2 = 12952 + (i4 << 2) | 0;
+      i5 = HEAP32[3228] | 0;
+      i3 = 1 << i3;
+      if ((i5 & i3 | 0) != 0) {
+       i4 = 12952 + (i4 + 2 << 2) | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       if (i3 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i7 = i4;
+        i8 = i3;
+       }
+      } else {
+       HEAP32[3228] = i5 | i3;
+       i7 = 12952 + (i4 + 2 << 2) | 0;
+       i8 = i2;
+      }
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i8 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i8;
+      HEAP32[i15 + 12 >> 2] = i2;
+      break;
+     }
+     i3 = i2 >>> 8;
+     if ((i3 | 0) != 0) {
+      if (i2 >>> 0 > 16777215) {
+       i3 = 31;
+      } else {
+       i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+       i32 = i3 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i3 = (i32 + 245760 | 0) >>> 16 & 2;
+       i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+       i3 = i2 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+      }
+     } else {
+      i3 = 0;
+     }
+     i7 = 13216 + (i3 << 2) | 0;
+     HEAP32[i15 + 28 >> 2] = i3;
+     HEAP32[i15 + 20 >> 2] = 0;
+     HEAP32[i15 + 16 >> 2] = 0;
+     i4 = HEAP32[12916 >> 2] | 0;
+     i5 = 1 << i3;
+     if ((i4 & i5 | 0) == 0) {
+      HEAP32[12916 >> 2] = i4 | i5;
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i7;
+      HEAP32[i15 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i15;
+      break;
+     }
+     i4 = HEAP32[i7 >> 2] | 0;
+     if ((i3 | 0) == 31) {
+      i3 = 0;
+     } else {
+      i3 = 25 - (i3 >>> 1) | 0;
+     }
+     L499 : do {
+      if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i2 | 0)) {
+       i3 = i2 << i3;
+       while (1) {
+        i7 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+        i5 = HEAP32[i7 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         break;
+        }
+        if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i2 | 0)) {
+         i6 = i5;
+         break L499;
+        } else {
+         i3 = i3 << 1;
+         i4 = i5;
+        }
+       }
+       if (i7 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i7 >> 2] = i15;
+        HEAP32[i15 + 24 >> 2] = i4;
+        HEAP32[i15 + 12 >> 2] = i15;
+        HEAP32[i15 + 8 >> 2] = i15;
+        break L311;
+       }
+      } else {
+       i6 = i4;
+      }
+     } while (0);
+     i4 = i6 + 8 | 0;
+     i3 = HEAP32[i4 >> 2] | 0;
+     i2 = HEAP32[12928 >> 2] | 0;
+     if (i6 >>> 0 < i2 >>> 0) {
+      _abort();
+     }
+     if (i3 >>> 0 < i2 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i3 + 12 >> 2] = i15;
+      HEAP32[i4 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i3;
+      HEAP32[i15 + 12 >> 2] = i6;
+      HEAP32[i15 + 24 >> 2] = 0;
+      break;
+     }
+    }
+   } else {
+    i32 = HEAP32[12928 >> 2] | 0;
+    if ((i32 | 0) == 0 | i17 >>> 0 < i32 >>> 0) {
+     HEAP32[12928 >> 2] = i17;
+    }
+    HEAP32[13360 >> 2] = i17;
+    HEAP32[13364 >> 2] = i14;
+    HEAP32[13372 >> 2] = 0;
+    HEAP32[12948 >> 2] = HEAP32[3346];
+    HEAP32[12944 >> 2] = -1;
+    i2 = 0;
+    do {
+     i32 = i2 << 1;
+     i31 = 12952 + (i32 << 2) | 0;
+     HEAP32[12952 + (i32 + 3 << 2) >> 2] = i31;
+     HEAP32[12952 + (i32 + 2 << 2) >> 2] = i31;
+     i2 = i2 + 1 | 0;
+    } while ((i2 | 0) != 32);
+    i2 = i17 + 8 | 0;
+    if ((i2 & 7 | 0) == 0) {
+     i2 = 0;
+    } else {
+     i2 = 0 - i2 & 7;
+    }
+    i32 = i14 + -40 - i2 | 0;
+    HEAP32[12936 >> 2] = i17 + i2;
+    HEAP32[12924 >> 2] = i32;
+    HEAP32[i17 + (i2 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[12940 >> 2] = HEAP32[13400 >> 2];
+   }
+  } while (0);
+  i2 = HEAP32[12924 >> 2] | 0;
+  if (i2 >>> 0 > i12 >>> 0) {
+   i31 = i2 - i12 | 0;
+   HEAP32[12924 >> 2] = i31;
+   i32 = HEAP32[12936 >> 2] | 0;
+   HEAP32[12936 >> 2] = i32 + i12;
+   HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+   HEAP32[i32 + 4 >> 2] = i12 | 3;
+   i32 = i32 + 8 | 0;
+   STACKTOP = i1;
+   return i32 | 0;
+  }
+ }
+ HEAP32[(___errno_location() | 0) >> 2] = 12;
+ i32 = 0;
+ STACKTOP = i1;
+ return i32 | 0;
+}
+function _llex(i2, i3) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i12 = i1;
+ i4 = i2 + 60 | 0;
+ HEAP32[(HEAP32[i4 >> 2] | 0) + 4 >> 2] = 0;
+ i5 = i2 + 56 | 0;
+ L1 : while (1) {
+  i13 = HEAP32[i2 >> 2] | 0;
+  L3 : while (1) {
+   switch (i13 | 0) {
+   case 11:
+   case 9:
+   case 12:
+   case 32:
+    {
+     break;
+    }
+   case 91:
+    {
+     i9 = 25;
+     break L1;
+    }
+   case 62:
+    {
+     i9 = 45;
+     break L1;
+    }
+   case 46:
+    {
+     i9 = 161;
+     break L1;
+    }
+   case 13:
+   case 10:
+    {
+     i9 = 4;
+     break L3;
+    }
+   case 45:
+    {
+     break L3;
+    }
+   case 61:
+    {
+     i9 = 29;
+     break L1;
+    }
+   case 39:
+   case 34:
+    {
+     i9 = 69;
+     break L1;
+    }
+   case 126:
+    {
+     i9 = 53;
+     break L1;
+    }
+   case 60:
+    {
+     i9 = 37;
+     break L1;
+    }
+   case 58:
+    {
+     i9 = 61;
+     break L1;
+    }
+   case 57:
+   case 56:
+   case 55:
+   case 54:
+   case 53:
+   case 52:
+   case 51:
+   case 50:
+   case 49:
+   case 48:
+    {
+     i20 = i13;
+     break L1;
+    }
+   case -1:
+    {
+     i2 = 286;
+     i9 = 306;
+     break L1;
+    }
+   default:
+    {
+     i9 = 283;
+     break L1;
+    }
+   }
+   i13 = HEAP32[i5 >> 2] | 0;
+   i27 = HEAP32[i13 >> 2] | 0;
+   HEAP32[i13 >> 2] = i27 + -1;
+   if ((i27 | 0) == 0) {
+    i13 = _luaZ_fill(i13) | 0;
+   } else {
+    i27 = i13 + 4 | 0;
+    i13 = HEAP32[i27 >> 2] | 0;
+    HEAP32[i27 >> 2] = i13 + 1;
+    i13 = HEAPU8[i13] | 0;
+   }
+   HEAP32[i2 >> 2] = i13;
+  }
+  if ((i9 | 0) == 4) {
+   i9 = 0;
+   _inclinenumber(i2);
+   continue;
+  }
+  i13 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i13 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i13 = _luaZ_fill(i13) | 0;
+  } else {
+   i27 = i13 + 4 | 0;
+   i13 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i13 + 1;
+   i13 = HEAPU8[i13] | 0;
+  }
+  HEAP32[i2 >> 2] = i13;
+  if ((i13 | 0) != 45) {
+   i2 = 45;
+   i9 = 306;
+   break;
+  }
+  i13 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i13 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i13 = _luaZ_fill(i13) | 0;
+  } else {
+   i27 = i13 + 4 | 0;
+   i13 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i13 + 1;
+   i13 = HEAPU8[i13] | 0;
+  }
+  HEAP32[i2 >> 2] = i13;
+  do {
+   if ((i13 | 0) == 91) {
+    i13 = _skip_sep(i2) | 0;
+    HEAP32[(HEAP32[i4 >> 2] | 0) + 4 >> 2] = 0;
+    if ((i13 | 0) > -1) {
+     _read_long_string(i2, 0, i13);
+     HEAP32[(HEAP32[i4 >> 2] | 0) + 4 >> 2] = 0;
+     continue L1;
+    } else {
+     i13 = HEAP32[i2 >> 2] | 0;
+     break;
+    }
+   }
+  } while (0);
+  while (1) {
+   if ((i13 | 0) == -1 | (i13 | 0) == 13 | (i13 | 0) == 10) {
+    continue L1;
+   }
+   i13 = HEAP32[i5 >> 2] | 0;
+   i27 = HEAP32[i13 >> 2] | 0;
+   HEAP32[i13 >> 2] = i27 + -1;
+   if ((i27 | 0) == 0) {
+    i13 = _luaZ_fill(i13) | 0;
+   } else {
+    i27 = i13 + 4 | 0;
+    i13 = HEAP32[i27 >> 2] | 0;
+    HEAP32[i27 >> 2] = i13 + 1;
+    i13 = HEAPU8[i13] | 0;
+   }
+   HEAP32[i2 >> 2] = i13;
+  }
+ }
+ if ((i9 | 0) == 25) {
+  i9 = _skip_sep(i2) | 0;
+  if ((i9 | 0) > -1) {
+   _read_long_string(i2, i3, i9);
+   i27 = 289;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  if ((i9 | 0) == -1) {
+   i27 = 91;
+   STACKTOP = i1;
+   return i27 | 0;
+  } else {
+   _lexerror(i2, 12272, 289);
+  }
+ } else if ((i9 | 0) == 29) {
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  if ((i3 | 0) != 61) {
+   i27 = 61;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  i27 = 281;
+  STACKTOP = i1;
+  return i27 | 0;
+ } else if ((i9 | 0) == 37) {
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  if ((i3 | 0) != 61) {
+   i27 = 60;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  i27 = 283;
+  STACKTOP = i1;
+  return i27 | 0;
+ } else if ((i9 | 0) == 45) {
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  if ((i3 | 0) != 61) {
+   i27 = 62;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  i27 = 282;
+  STACKTOP = i1;
+  return i27 | 0;
+ } else if ((i9 | 0) == 53) {
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  if ((i3 | 0) != 61) {
+   i27 = 126;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  i27 = 284;
+  STACKTOP = i1;
+  return i27 | 0;
+ } else if ((i9 | 0) == 61) {
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  if ((i3 | 0) != 58) {
+   i27 = 58;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  i27 = 285;
+  STACKTOP = i1;
+  return i27 | 0;
+ } else if ((i9 | 0) == 69) {
+  i14 = HEAP32[i4 >> 2] | 0;
+  i7 = i14 + 4 | 0;
+  i15 = HEAP32[i7 >> 2] | 0;
+  i8 = i14 + 8 | 0;
+  i6 = HEAP32[i8 >> 2] | 0;
+  do {
+   if ((i15 + 1 | 0) >>> 0 > i6 >>> 0) {
+    if (i6 >>> 0 > 2147483645) {
+     _lexerror(i2, 12368, 0);
+    }
+    i16 = i6 << 1;
+    i15 = HEAP32[i2 + 52 >> 2] | 0;
+    if ((i16 | 0) == -2) {
+     _luaM_toobig(i15);
+    } else {
+     i24 = _luaM_realloc_(i15, HEAP32[i14 >> 2] | 0, i6, i16) | 0;
+     HEAP32[i14 >> 2] = i24;
+     HEAP32[i8 >> 2] = i16;
+     i23 = HEAP32[i7 >> 2] | 0;
+     break;
+    }
+   } else {
+    i23 = i15;
+    i24 = HEAP32[i14 >> 2] | 0;
+   }
+  } while (0);
+  i6 = i13 & 255;
+  HEAP32[i7 >> 2] = i23 + 1;
+  HEAP8[i24 + i23 | 0] = i6;
+  i7 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i7 >> 2] | 0;
+  HEAP32[i7 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i14 = _luaZ_fill(i7) | 0;
+  } else {
+   i27 = i7 + 4 | 0;
+   i14 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i14 + 1;
+   i14 = HEAPU8[i14] | 0;
+  }
+  HEAP32[i2 >> 2] = i14;
+  L139 : do {
+   if ((i14 | 0) != (i13 | 0)) {
+    i7 = i2 + 52 | 0;
+    L141 : while (1) {
+     L143 : do {
+      if ((i14 | 0) == 92) {
+       i8 = HEAP32[i5 >> 2] | 0;
+       i27 = HEAP32[i8 >> 2] | 0;
+       HEAP32[i8 >> 2] = i27 + -1;
+       if ((i27 | 0) == 0) {
+        i8 = _luaZ_fill(i8) | 0;
+       } else {
+        i27 = i8 + 4 | 0;
+        i8 = HEAP32[i27 >> 2] | 0;
+        HEAP32[i27 >> 2] = i8 + 1;
+        i8 = HEAPU8[i8] | 0;
+       }
+       HEAP32[i2 >> 2] = i8;
+       switch (i8 | 0) {
+       case 13:
+       case 10:
+        {
+         _inclinenumber(i2);
+         i8 = 10;
+         break;
+        }
+       case 39:
+       case 34:
+       case 92:
+        {
+         i9 = 124;
+         break;
+        }
+       case 122:
+        {
+         i8 = HEAP32[i5 >> 2] | 0;
+         i27 = HEAP32[i8 >> 2] | 0;
+         HEAP32[i8 >> 2] = i27 + -1;
+         if ((i27 | 0) == 0) {
+          i14 = _luaZ_fill(i8) | 0;
+         } else {
+          i27 = i8 + 4 | 0;
+          i14 = HEAP32[i27 >> 2] | 0;
+          HEAP32[i27 >> 2] = i14 + 1;
+          i14 = HEAPU8[i14] | 0;
+         }
+         HEAP32[i2 >> 2] = i14;
+         if ((HEAP8[i14 + 10913 | 0] & 8) == 0) {
+          break L143;
+         }
+         while (1) {
+          if ((i14 | 0) == 13 | (i14 | 0) == 10) {
+           _inclinenumber(i2);
+           i14 = HEAP32[i2 >> 2] | 0;
+          } else {
+           i8 = HEAP32[i5 >> 2] | 0;
+           i27 = HEAP32[i8 >> 2] | 0;
+           HEAP32[i8 >> 2] = i27 + -1;
+           if ((i27 | 0) == 0) {
+            i14 = _luaZ_fill(i8) | 0;
+           } else {
+            i27 = i8 + 4 | 0;
+            i14 = HEAP32[i27 >> 2] | 0;
+            HEAP32[i27 >> 2] = i14 + 1;
+            i14 = HEAPU8[i14] | 0;
+           }
+           HEAP32[i2 >> 2] = i14;
+          }
+          if ((HEAP8[i14 + 10913 | 0] & 8) == 0) {
+           break L143;
+          }
+         }
+        }
+       case 118:
+        {
+         i8 = 11;
+         i9 = 124;
+         break;
+        }
+       case 120:
+        {
+         HEAP32[i12 >> 2] = 120;
+         i14 = 1;
+         i8 = 0;
+         while (1) {
+          i9 = HEAP32[i5 >> 2] | 0;
+          i27 = HEAP32[i9 >> 2] | 0;
+          HEAP32[i9 >> 2] = i27 + -1;
+          if ((i27 | 0) == 0) {
+           i9 = _luaZ_fill(i9) | 0;
+          } else {
+           i27 = i9 + 4 | 0;
+           i9 = HEAP32[i27 >> 2] | 0;
+           HEAP32[i27 >> 2] = i9 + 1;
+           i9 = HEAPU8[i9] | 0;
+          }
+          HEAP32[i2 >> 2] = i9;
+          HEAP32[i12 + (i14 << 2) >> 2] = i9;
+          if ((HEAP8[i9 + 10913 | 0] & 16) == 0) {
+           i9 = 100;
+           break L141;
+          }
+          i8 = (_luaO_hexavalue(i9) | 0) + (i8 << 4) | 0;
+          i14 = i14 + 1 | 0;
+          if ((i14 | 0) >= 3) {
+           i9 = 124;
+           break;
+          }
+         }
+         break;
+        }
+       case -1:
+        {
+         i14 = -1;
+         break L143;
+        }
+       case 98:
+        {
+         i8 = 8;
+         i9 = 124;
+         break;
+        }
+       case 102:
+        {
+         i8 = 12;
+         i9 = 124;
+         break;
+        }
+       case 110:
+        {
+         i8 = 10;
+         i9 = 124;
+         break;
+        }
+       case 114:
+        {
+         i8 = 13;
+         i9 = 124;
+         break;
+        }
+       case 116:
+        {
+         i8 = 9;
+         i9 = 124;
+         break;
+        }
+       case 97:
+        {
+         i8 = 7;
+         i9 = 124;
+         break;
+        }
+       default:
+        {
+         if ((HEAP8[i8 + 10913 | 0] & 2) == 0) {
+          i9 = 116;
+          break L141;
+         } else {
+          i15 = i8;
+          i14 = 0;
+          i8 = 0;
+         }
+         do {
+          if ((HEAP8[i15 + 10913 | 0] & 2) == 0) {
+           break;
+          }
+          HEAP32[i12 + (i14 << 2) >> 2] = i15;
+          i8 = i15 + -48 + (i8 * 10 | 0) | 0;
+          i15 = HEAP32[i5 >> 2] | 0;
+          i27 = HEAP32[i15 >> 2] | 0;
+          HEAP32[i15 >> 2] = i27 + -1;
+          if ((i27 | 0) == 0) {
+           i15 = _luaZ_fill(i15) | 0;
+          } else {
+           i27 = i15 + 4 | 0;
+           i15 = HEAP32[i27 >> 2] | 0;
+           HEAP32[i27 >> 2] = i15 + 1;
+           i15 = HEAPU8[i15] | 0;
+          }
+          HEAP32[i2 >> 2] = i15;
+          i14 = i14 + 1 | 0;
+         } while ((i14 | 0) < 3);
+         if ((i8 | 0) > 255) {
+          i9 = 123;
+          break L141;
+         }
+        }
+       }
+       if ((i9 | 0) == 124) {
+        i9 = 0;
+        i14 = HEAP32[i5 >> 2] | 0;
+        i27 = HEAP32[i14 >> 2] | 0;
+        HEAP32[i14 >> 2] = i27 + -1;
+        if ((i27 | 0) == 0) {
+         i14 = _luaZ_fill(i14) | 0;
+        } else {
+         i27 = i14 + 4 | 0;
+         i14 = HEAP32[i27 >> 2] | 0;
+         HEAP32[i27 >> 2] = i14 + 1;
+         i14 = HEAPU8[i14] | 0;
+        }
+        HEAP32[i2 >> 2] = i14;
+       }
+       i15 = HEAP32[i4 >> 2] | 0;
+       i14 = i15 + 4 | 0;
+       i18 = HEAP32[i14 >> 2] | 0;
+       i16 = i15 + 8 | 0;
+       i17 = HEAP32[i16 >> 2] | 0;
+       if ((i18 + 1 | 0) >>> 0 > i17 >>> 0) {
+        if (i17 >>> 0 > 2147483645) {
+         i9 = 131;
+         break L141;
+        }
+        i18 = i17 << 1;
+        i19 = HEAP32[i7 >> 2] | 0;
+        if ((i18 | 0) == -2) {
+         i9 = 133;
+         break L141;
+        }
+        i27 = _luaM_realloc_(i19, HEAP32[i15 >> 2] | 0, i17, i18) | 0;
+        HEAP32[i15 >> 2] = i27;
+        HEAP32[i16 >> 2] = i18;
+        i18 = HEAP32[i14 >> 2] | 0;
+        i15 = i27;
+       } else {
+        i15 = HEAP32[i15 >> 2] | 0;
+       }
+       HEAP32[i14 >> 2] = i18 + 1;
+       HEAP8[i15 + i18 | 0] = i8;
+       i14 = HEAP32[i2 >> 2] | 0;
+      } else if ((i14 | 0) == -1) {
+       i9 = 82;
+       break L141;
+      } else if ((i14 | 0) == 13 | (i14 | 0) == 10) {
+       i9 = 83;
+       break L141;
+      } else {
+       i15 = HEAP32[i4 >> 2] | 0;
+       i8 = i15 + 4 | 0;
+       i18 = HEAP32[i8 >> 2] | 0;
+       i17 = i15 + 8 | 0;
+       i16 = HEAP32[i17 >> 2] | 0;
+       if ((i18 + 1 | 0) >>> 0 > i16 >>> 0) {
+        if (i16 >>> 0 > 2147483645) {
+         i9 = 139;
+         break L141;
+        }
+        i19 = i16 << 1;
+        i18 = HEAP32[i7 >> 2] | 0;
+        if ((i19 | 0) == -2) {
+         i9 = 141;
+         break L141;
+        }
+        i27 = _luaM_realloc_(i18, HEAP32[i15 >> 2] | 0, i16, i19) | 0;
+        HEAP32[i15 >> 2] = i27;
+        HEAP32[i17 >> 2] = i19;
+        i18 = HEAP32[i8 >> 2] | 0;
+        i15 = i27;
+       } else {
+        i15 = HEAP32[i15 >> 2] | 0;
+       }
+       HEAP32[i8 >> 2] = i18 + 1;
+       HEAP8[i15 + i18 | 0] = i14;
+       i8 = HEAP32[i5 >> 2] | 0;
+       i27 = HEAP32[i8 >> 2] | 0;
+       HEAP32[i8 >> 2] = i27 + -1;
+       if ((i27 | 0) == 0) {
+        i14 = _luaZ_fill(i8) | 0;
+       } else {
+        i27 = i8 + 4 | 0;
+        i14 = HEAP32[i27 >> 2] | 0;
+        HEAP32[i27 >> 2] = i14 + 1;
+        i14 = HEAPU8[i14] | 0;
+       }
+       HEAP32[i2 >> 2] = i14;
+      }
+     } while (0);
+     if ((i14 | 0) == (i13 | 0)) {
+      break L139;
+     }
+    }
+    if ((i9 | 0) == 82) {
+     _lexerror(i2, 12400, 286);
+    } else if ((i9 | 0) == 83) {
+     _lexerror(i2, 12400, 289);
+    } else if ((i9 | 0) == 100) {
+     _escerror(i2, i12, i14 + 1 | 0, 12480);
+    } else if ((i9 | 0) == 116) {
+     _escerror(i2, i2, 1, 12424);
+    } else if ((i9 | 0) == 123) {
+     _escerror(i2, i12, i14, 12448);
+    } else if ((i9 | 0) == 131) {
+     _lexerror(i2, 12368, 0);
+    } else if ((i9 | 0) == 133) {
+     _luaM_toobig(i19);
+    } else if ((i9 | 0) == 139) {
+     _lexerror(i2, 12368, 0);
+    } else if ((i9 | 0) == 141) {
+     _luaM_toobig(i18);
+    }
+   }
+  } while (0);
+  i7 = HEAP32[i4 >> 2] | 0;
+  i8 = i7 + 4 | 0;
+  i13 = HEAP32[i8 >> 2] | 0;
+  i12 = i7 + 8 | 0;
+  i9 = HEAP32[i12 >> 2] | 0;
+  do {
+   if ((i13 + 1 | 0) >>> 0 > i9 >>> 0) {
+    if (i9 >>> 0 > 2147483645) {
+     _lexerror(i2, 12368, 0);
+    }
+    i14 = i9 << 1;
+    i13 = HEAP32[i2 + 52 >> 2] | 0;
+    if ((i14 | 0) == -2) {
+     _luaM_toobig(i13);
+    } else {
+     i11 = _luaM_realloc_(i13, HEAP32[i7 >> 2] | 0, i9, i14) | 0;
+     HEAP32[i7 >> 2] = i11;
+     HEAP32[i12 >> 2] = i14;
+     i10 = HEAP32[i8 >> 2] | 0;
+     break;
+    }
+   } else {
+    i10 = i13;
+    i11 = HEAP32[i7 >> 2] | 0;
+   }
+  } while (0);
+  HEAP32[i8 >> 2] = i10 + 1;
+  HEAP8[i11 + i10 | 0] = i6;
+  i5 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i5 >> 2] | 0;
+  HEAP32[i5 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i5 = _luaZ_fill(i5) | 0;
+  } else {
+   i27 = i5 + 4 | 0;
+   i5 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i5 + 1;
+   i5 = HEAPU8[i5] | 0;
+  }
+  HEAP32[i2 >> 2] = i5;
+  i5 = HEAP32[i4 >> 2] | 0;
+  i4 = HEAP32[i2 + 52 >> 2] | 0;
+  i5 = _luaS_newlstr(i4, (HEAP32[i5 >> 2] | 0) + 1 | 0, (HEAP32[i5 + 4 >> 2] | 0) + -2 | 0) | 0;
+  i6 = i4 + 8 | 0;
+  i7 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i7 + 16;
+  HEAP32[i7 >> 2] = i5;
+  HEAP32[i7 + 8 >> 2] = HEAPU8[i5 + 4 | 0] | 64;
+  i7 = _luaH_set(i4, HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 4 >> 2] | 0, (HEAP32[i6 >> 2] | 0) + -16 | 0) | 0;
+  i2 = i7 + 8 | 0;
+  if ((HEAP32[i2 >> 2] | 0) == 0 ? (HEAP32[i7 >> 2] = 1, HEAP32[i2 >> 2] = 1, (HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) : 0) {
+   _luaC_step(i4);
+  }
+  HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + -16;
+  HEAP32[i3 >> 2] = i5;
+  i27 = 289;
+  STACKTOP = i1;
+  return i27 | 0;
+ } else if ((i9 | 0) == 161) {
+  i10 = HEAP32[i4 >> 2] | 0;
+  i9 = i10 + 4 | 0;
+  i13 = HEAP32[i9 >> 2] | 0;
+  i12 = i10 + 8 | 0;
+  i11 = HEAP32[i12 >> 2] | 0;
+  do {
+   if ((i13 + 1 | 0) >>> 0 > i11 >>> 0) {
+    if (i11 >>> 0 > 2147483645) {
+     _lexerror(i2, 12368, 0);
+    }
+    i13 = i11 << 1;
+    i20 = HEAP32[i2 + 52 >> 2] | 0;
+    if ((i13 | 0) == -2) {
+     _luaM_toobig(i20);
+    } else {
+     i25 = _luaM_realloc_(i20, HEAP32[i10 >> 2] | 0, i11, i13) | 0;
+     HEAP32[i10 >> 2] = i25;
+     HEAP32[i12 >> 2] = i13;
+     i26 = HEAP32[i9 >> 2] | 0;
+     break;
+    }
+   } else {
+    i26 = i13;
+    i25 = HEAP32[i10 >> 2] | 0;
+   }
+  } while (0);
+  HEAP32[i9 >> 2] = i26 + 1;
+  HEAP8[i25 + i26 | 0] = 46;
+  i9 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i9 >> 2] | 0;
+  HEAP32[i9 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i20 = _luaZ_fill(i9) | 0;
+  } else {
+   i27 = i9 + 4 | 0;
+   i20 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i20 + 1;
+   i20 = HEAPU8[i20] | 0;
+  }
+  HEAP32[i2 >> 2] = i20;
+  if ((i20 | 0) != 0 ? (_memchr(12304, i20, 2) | 0) != 0 : 0) {
+   i6 = HEAP32[i4 >> 2] | 0;
+   i3 = i6 + 4 | 0;
+   i9 = HEAP32[i3 >> 2] | 0;
+   i8 = i6 + 8 | 0;
+   i7 = HEAP32[i8 >> 2] | 0;
+   do {
+    if ((i9 + 1 | 0) >>> 0 > i7 >>> 0) {
+     if (i7 >>> 0 > 2147483645) {
+      _lexerror(i2, 12368, 0);
+     }
+     i9 = i7 << 1;
+     i10 = HEAP32[i2 + 52 >> 2] | 0;
+     if ((i9 | 0) == -2) {
+      _luaM_toobig(i10);
+     } else {
+      i21 = _luaM_realloc_(i10, HEAP32[i6 >> 2] | 0, i7, i9) | 0;
+      HEAP32[i6 >> 2] = i21;
+      HEAP32[i8 >> 2] = i9;
+      i22 = HEAP32[i3 >> 2] | 0;
+      break;
+     }
+    } else {
+     i22 = i9;
+     i21 = HEAP32[i6 >> 2] | 0;
+    }
+   } while (0);
+   HEAP32[i3 >> 2] = i22 + 1;
+   HEAP8[i21 + i22 | 0] = i20;
+   i3 = HEAP32[i5 >> 2] | 0;
+   i27 = HEAP32[i3 >> 2] | 0;
+   HEAP32[i3 >> 2] = i27 + -1;
+   if ((i27 | 0) == 0) {
+    i3 = _luaZ_fill(i3) | 0;
+   } else {
+    i27 = i3 + 4 | 0;
+    i3 = HEAP32[i27 >> 2] | 0;
+    HEAP32[i27 >> 2] = i3 + 1;
+    i3 = HEAPU8[i3] | 0;
+   }
+   HEAP32[i2 >> 2] = i3;
+   if ((i3 | 0) == 0) {
+    i27 = 279;
+    STACKTOP = i1;
+    return i27 | 0;
+   }
+   if ((_memchr(12304, i3, 2) | 0) == 0) {
+    i27 = 279;
+    STACKTOP = i1;
+    return i27 | 0;
+   }
+   i6 = HEAP32[i4 >> 2] | 0;
+   i7 = i6 + 4 | 0;
+   i9 = HEAP32[i7 >> 2] | 0;
+   i8 = i6 + 8 | 0;
+   i4 = HEAP32[i8 >> 2] | 0;
+   do {
+    if ((i9 + 1 | 0) >>> 0 > i4 >>> 0) {
+     if (i4 >>> 0 > 2147483645) {
+      _lexerror(i2, 12368, 0);
+     }
+     i10 = i4 << 1;
+     i9 = HEAP32[i2 + 52 >> 2] | 0;
+     if ((i10 | 0) == -2) {
+      _luaM_toobig(i9);
+     } else {
+      i18 = _luaM_realloc_(i9, HEAP32[i6 >> 2] | 0, i4, i10) | 0;
+      HEAP32[i6 >> 2] = i18;
+      HEAP32[i8 >> 2] = i10;
+      i19 = HEAP32[i7 >> 2] | 0;
+      break;
+     }
+    } else {
+     i19 = i9;
+     i18 = HEAP32[i6 >> 2] | 0;
+    }
+   } while (0);
+   HEAP32[i7 >> 2] = i19 + 1;
+   HEAP8[i18 + i19 | 0] = i3;
+   i3 = HEAP32[i5 >> 2] | 0;
+   i27 = HEAP32[i3 >> 2] | 0;
+   HEAP32[i3 >> 2] = i27 + -1;
+   if ((i27 | 0) == 0) {
+    i3 = _luaZ_fill(i3) | 0;
+   } else {
+    i27 = i3 + 4 | 0;
+    i3 = HEAP32[i27 >> 2] | 0;
+    HEAP32[i27 >> 2] = i3 + 1;
+    i3 = HEAPU8[i3] | 0;
+   }
+   HEAP32[i2 >> 2] = i3;
+   i27 = 280;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  if ((HEAP8[i20 + 10913 | 0] & 2) == 0) {
+   i27 = 46;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+ } else if ((i9 | 0) == 283) {
+  if ((HEAP8[i13 + 10913 | 0] & 1) == 0) {
+   i3 = HEAP32[i5 >> 2] | 0;
+   i27 = HEAP32[i3 >> 2] | 0;
+   HEAP32[i3 >> 2] = i27 + -1;
+   if ((i27 | 0) == 0) {
+    i3 = _luaZ_fill(i3) | 0;
+   } else {
+    i27 = i3 + 4 | 0;
+    i3 = HEAP32[i27 >> 2] | 0;
+    HEAP32[i27 >> 2] = i3 + 1;
+    i3 = HEAPU8[i3] | 0;
+   }
+   HEAP32[i2 >> 2] = i3;
+   i27 = i13;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i10 = i2 + 52 | 0;
+  while (1) {
+   i11 = HEAP32[i4 >> 2] | 0;
+   i9 = i11 + 4 | 0;
+   i12 = HEAP32[i9 >> 2] | 0;
+   i19 = i11 + 8 | 0;
+   i18 = HEAP32[i19 >> 2] | 0;
+   if ((i12 + 1 | 0) >>> 0 > i18 >>> 0) {
+    if (i18 >>> 0 > 2147483645) {
+     i9 = 288;
+     break;
+    }
+    i21 = i18 << 1;
+    i12 = HEAP32[i10 >> 2] | 0;
+    if ((i21 | 0) == -2) {
+     i9 = 290;
+     break;
+    }
+    i27 = _luaM_realloc_(i12, HEAP32[i11 >> 2] | 0, i18, i21) | 0;
+    HEAP32[i11 >> 2] = i27;
+    HEAP32[i19 >> 2] = i21;
+    i12 = HEAP32[i9 >> 2] | 0;
+    i11 = i27;
+   } else {
+    i11 = HEAP32[i11 >> 2] | 0;
+   }
+   HEAP32[i9 >> 2] = i12 + 1;
+   HEAP8[i11 + i12 | 0] = i13;
+   i9 = HEAP32[i5 >> 2] | 0;
+   i27 = HEAP32[i9 >> 2] | 0;
+   HEAP32[i9 >> 2] = i27 + -1;
+   if ((i27 | 0) == 0) {
+    i13 = _luaZ_fill(i9) | 0;
+   } else {
+    i27 = i9 + 4 | 0;
+    i13 = HEAP32[i27 >> 2] | 0;
+    HEAP32[i27 >> 2] = i13 + 1;
+    i13 = HEAPU8[i13] | 0;
+   }
+   HEAP32[i2 >> 2] = i13;
+   if ((HEAP8[i13 + 10913 | 0] & 3) == 0) {
+    i9 = 296;
+    break;
+   }
+  }
+  if ((i9 | 0) == 288) {
+   _lexerror(i2, 12368, 0);
+  } else if ((i9 | 0) == 290) {
+   _luaM_toobig(i12);
+  } else if ((i9 | 0) == 296) {
+   i6 = HEAP32[i4 >> 2] | 0;
+   i4 = HEAP32[i10 >> 2] | 0;
+   i6 = _luaS_newlstr(i4, HEAP32[i6 >> 2] | 0, HEAP32[i6 + 4 >> 2] | 0) | 0;
+   i7 = i4 + 8 | 0;
+   i8 = HEAP32[i7 >> 2] | 0;
+   HEAP32[i7 >> 2] = i8 + 16;
+   HEAP32[i8 >> 2] = i6;
+   i5 = i6 + 4 | 0;
+   HEAP32[i8 + 8 >> 2] = HEAPU8[i5] | 64;
+   i8 = _luaH_set(i4, HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 4 >> 2] | 0, (HEAP32[i7 >> 2] | 0) + -16 | 0) | 0;
+   i2 = i8 + 8 | 0;
+   if ((HEAP32[i2 >> 2] | 0) == 0 ? (HEAP32[i8 >> 2] = 1, HEAP32[i2 >> 2] = 1, (HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) : 0) {
+    _luaC_step(i4);
+   }
+   HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + -16;
+   HEAP32[i3 >> 2] = i6;
+   if ((HEAP8[i5] | 0) != 4) {
+    i27 = 288;
+    STACKTOP = i1;
+    return i27 | 0;
+   }
+   i2 = HEAP8[i6 + 6 | 0] | 0;
+   if (i2 << 24 >> 24 == 0) {
+    i27 = 288;
+    STACKTOP = i1;
+    return i27 | 0;
+   }
+   i27 = i2 & 255 | 256;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+ } else if ((i9 | 0) == 306) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ i9 = HEAP32[i4 >> 2] | 0;
+ i12 = i9 + 4 | 0;
+ i13 = HEAP32[i12 >> 2] | 0;
+ i11 = i9 + 8 | 0;
+ i10 = HEAP32[i11 >> 2] | 0;
+ do {
+  if ((i13 + 1 | 0) >>> 0 > i10 >>> 0) {
+   if (i10 >>> 0 > 2147483645) {
+    _lexerror(i2, 12368, 0);
+   }
+   i18 = i10 << 1;
+   i13 = HEAP32[i2 + 52 >> 2] | 0;
+   if ((i18 | 0) == -2) {
+    _luaM_toobig(i13);
+   } else {
+    i16 = _luaM_realloc_(i13, HEAP32[i9 >> 2] | 0, i10, i18) | 0;
+    HEAP32[i9 >> 2] = i16;
+    HEAP32[i11 >> 2] = i18;
+    i17 = HEAP32[i12 >> 2] | 0;
+    break;
+   }
+  } else {
+   i17 = i13;
+   i16 = HEAP32[i9 >> 2] | 0;
+  }
+ } while (0);
+ HEAP32[i12 >> 2] = i17 + 1;
+ HEAP8[i16 + i17 | 0] = i20;
+ i9 = HEAP32[i5 >> 2] | 0;
+ i27 = HEAP32[i9 >> 2] | 0;
+ HEAP32[i9 >> 2] = i27 + -1;
+ if ((i27 | 0) == 0) {
+  i9 = _luaZ_fill(i9) | 0;
+ } else {
+  i27 = i9 + 4 | 0;
+  i9 = HEAP32[i27 >> 2] | 0;
+  HEAP32[i27 >> 2] = i9 + 1;
+  i9 = HEAPU8[i9] | 0;
+ }
+ HEAP32[i2 >> 2] = i9;
+ if ((i20 | 0) == 48) {
+  if ((i9 | 0) != 0) {
+   if ((_memchr(12320, i9, 3) | 0) == 0) {
+    i15 = i9;
+    i9 = 12312;
+   } else {
+    i10 = HEAP32[i4 >> 2] | 0;
+    i13 = i10 + 4 | 0;
+    i16 = HEAP32[i13 >> 2] | 0;
+    i11 = i10 + 8 | 0;
+    i12 = HEAP32[i11 >> 2] | 0;
+    do {
+     if ((i16 + 1 | 0) >>> 0 > i12 >>> 0) {
+      if (i12 >>> 0 > 2147483645) {
+       _lexerror(i2, 12368, 0);
+      }
+      i17 = i12 << 1;
+      i16 = HEAP32[i2 + 52 >> 2] | 0;
+      if ((i17 | 0) == -2) {
+       _luaM_toobig(i16);
+      } else {
+       i15 = _luaM_realloc_(i16, HEAP32[i10 >> 2] | 0, i12, i17) | 0;
+       HEAP32[i10 >> 2] = i15;
+       HEAP32[i11 >> 2] = i17;
+       i14 = HEAP32[i13 >> 2] | 0;
+       break;
+      }
+     } else {
+      i14 = i16;
+      i15 = HEAP32[i10 >> 2] | 0;
+     }
+    } while (0);
+    HEAP32[i13 >> 2] = i14 + 1;
+    HEAP8[i15 + i14 | 0] = i9;
+    i9 = HEAP32[i5 >> 2] | 0;
+    i27 = HEAP32[i9 >> 2] | 0;
+    HEAP32[i9 >> 2] = i27 + -1;
+    if ((i27 | 0) == 0) {
+     i15 = _luaZ_fill(i9) | 0;
+    } else {
+     i27 = i9 + 4 | 0;
+     i15 = HEAP32[i27 >> 2] | 0;
+     HEAP32[i27 >> 2] = i15 + 1;
+     i15 = HEAPU8[i15] | 0;
+    }
+    HEAP32[i2 >> 2] = i15;
+    i9 = 12328;
+   }
+  } else {
+   i15 = 0;
+   i9 = 12312;
+  }
+ } else {
+  i15 = i9;
+  i9 = 12312;
+ }
+ i10 = i2 + 52 | 0;
+ while (1) {
+  if ((i15 | 0) != 0) {
+   if ((_memchr(i9, i15, 3) | 0) != 0) {
+    i12 = HEAP32[i4 >> 2] | 0;
+    i11 = i12 + 4 | 0;
+    i16 = HEAP32[i11 >> 2] | 0;
+    i14 = i12 + 8 | 0;
+    i13 = HEAP32[i14 >> 2] | 0;
+    if ((i16 + 1 | 0) >>> 0 > i13 >>> 0) {
+     if (i13 >>> 0 > 2147483645) {
+      i9 = 227;
+      break;
+     }
+     i17 = i13 << 1;
+     i16 = HEAP32[i10 >> 2] | 0;
+     if ((i17 | 0) == -2) {
+      i9 = 229;
+      break;
+     }
+     i27 = _luaM_realloc_(i16, HEAP32[i12 >> 2] | 0, i13, i17) | 0;
+     HEAP32[i12 >> 2] = i27;
+     HEAP32[i14 >> 2] = i17;
+     i16 = HEAP32[i11 >> 2] | 0;
+     i12 = i27;
+    } else {
+     i12 = HEAP32[i12 >> 2] | 0;
+    }
+    HEAP32[i11 >> 2] = i16 + 1;
+    HEAP8[i12 + i16 | 0] = i15;
+    i11 = HEAP32[i5 >> 2] | 0;
+    i27 = HEAP32[i11 >> 2] | 0;
+    HEAP32[i11 >> 2] = i27 + -1;
+    if ((i27 | 0) == 0) {
+     i15 = _luaZ_fill(i11) | 0;
+    } else {
+     i27 = i11 + 4 | 0;
+     i15 = HEAP32[i27 >> 2] | 0;
+     HEAP32[i27 >> 2] = i15 + 1;
+     i15 = HEAPU8[i15] | 0;
+    }
+    HEAP32[i2 >> 2] = i15;
+    if ((i15 | 0) != 0) {
+     if ((_memchr(12336, i15, 3) | 0) != 0) {
+      i12 = HEAP32[i4 >> 2] | 0;
+      i11 = i12 + 4 | 0;
+      i16 = HEAP32[i11 >> 2] | 0;
+      i14 = i12 + 8 | 0;
+      i13 = HEAP32[i14 >> 2] | 0;
+      if ((i16 + 1 | 0) >>> 0 > i13 >>> 0) {
+       if (i13 >>> 0 > 2147483645) {
+        i9 = 239;
+        break;
+       }
+       i17 = i13 << 1;
+       i16 = HEAP32[i10 >> 2] | 0;
+       if ((i17 | 0) == -2) {
+        i9 = 241;
+        break;
+       }
+       i27 = _luaM_realloc_(i16, HEAP32[i12 >> 2] | 0, i13, i17) | 0;
+       HEAP32[i12 >> 2] = i27;
+       HEAP32[i14 >> 2] = i17;
+       i16 = HEAP32[i11 >> 2] | 0;
+       i12 = i27;
+      } else {
+       i12 = HEAP32[i12 >> 2] | 0;
+      }
+      HEAP32[i11 >> 2] = i16 + 1;
+      HEAP8[i12 + i16 | 0] = i15;
+      i11 = HEAP32[i5 >> 2] | 0;
+      i27 = HEAP32[i11 >> 2] | 0;
+      HEAP32[i11 >> 2] = i27 + -1;
+      if ((i27 | 0) == 0) {
+       i15 = _luaZ_fill(i11) | 0;
+      } else {
+       i27 = i11 + 4 | 0;
+       i15 = HEAP32[i27 >> 2] | 0;
+       HEAP32[i27 >> 2] = i15 + 1;
+       i15 = HEAPU8[i15] | 0;
+      }
+      HEAP32[i2 >> 2] = i15;
+     }
+    } else {
+     i15 = 0;
+    }
+   }
+  } else {
+   i15 = 0;
+  }
+  i12 = HEAP32[i4 >> 2] | 0;
+  i11 = i12 + 4 | 0;
+  i17 = HEAP32[i11 >> 2] | 0;
+  i14 = i12 + 8 | 0;
+  i13 = HEAP32[i14 >> 2] | 0;
+  i16 = (i17 + 1 | 0) >>> 0 > i13 >>> 0;
+  if (!((HEAP8[i15 + 10913 | 0] & 16) != 0 | (i15 | 0) == 46)) {
+   i9 = 259;
+   break;
+  }
+  if (i16) {
+   if (i13 >>> 0 > 2147483645) {
+    i9 = 251;
+    break;
+   }
+   i17 = i13 << 1;
+   i16 = HEAP32[i10 >> 2] | 0;
+   if ((i17 | 0) == -2) {
+    i9 = 253;
+    break;
+   }
+   i27 = _luaM_realloc_(i16, HEAP32[i12 >> 2] | 0, i13, i17) | 0;
+   HEAP32[i12 >> 2] = i27;
+   HEAP32[i14 >> 2] = i17;
+   i17 = HEAP32[i11 >> 2] | 0;
+   i12 = i27;
+  } else {
+   i12 = HEAP32[i12 >> 2] | 0;
+  }
+  HEAP32[i11 >> 2] = i17 + 1;
+  HEAP8[i12 + i17 | 0] = i15;
+  i11 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i11 >> 2] | 0;
+  HEAP32[i11 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i15 = _luaZ_fill(i11) | 0;
+  } else {
+   i27 = i11 + 4 | 0;
+   i15 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i15 + 1;
+   i15 = HEAPU8[i15] | 0;
+  }
+  HEAP32[i2 >> 2] = i15;
+ }
+ if ((i9 | 0) == 227) {
+  _lexerror(i2, 12368, 0);
+ } else if ((i9 | 0) == 229) {
+  _luaM_toobig(i16);
+ } else if ((i9 | 0) == 239) {
+  _lexerror(i2, 12368, 0);
+ } else if ((i9 | 0) == 241) {
+  _luaM_toobig(i16);
+ } else if ((i9 | 0) == 251) {
+  _lexerror(i2, 12368, 0);
+ } else if ((i9 | 0) == 253) {
+  _luaM_toobig(i16);
+ } else if ((i9 | 0) == 259) {
+  do {
+   if (i16) {
+    if (i13 >>> 0 > 2147483645) {
+     _lexerror(i2, 12368, 0);
+    }
+    i5 = i13 << 1;
+    i9 = HEAP32[i10 >> 2] | 0;
+    if ((i5 | 0) == -2) {
+     _luaM_toobig(i9);
+    } else {
+     i7 = _luaM_realloc_(i9, HEAP32[i12 >> 2] | 0, i13, i5) | 0;
+     HEAP32[i12 >> 2] = i7;
+     HEAP32[i14 >> 2] = i5;
+     i8 = HEAP32[i11 >> 2] | 0;
+     break;
+    }
+   } else {
+    i8 = i17;
+    i7 = HEAP32[i12 >> 2] | 0;
+   }
+  } while (0);
+  HEAP32[i11 >> 2] = i8 + 1;
+  HEAP8[i7 + i8 | 0] = 0;
+  i5 = i2 + 76 | 0;
+  i7 = HEAP8[i5] | 0;
+  i10 = HEAP32[i4 >> 2] | 0;
+  i8 = HEAP32[i10 >> 2] | 0;
+  i10 = HEAP32[i10 + 4 >> 2] | 0;
+  if ((i10 | 0) == 0) {
+   i7 = -1;
+  } else {
+   do {
+    i10 = i10 + -1 | 0;
+    i9 = i8 + i10 | 0;
+    if ((HEAP8[i9] | 0) == 46) {
+     HEAP8[i9] = i7;
+    }
+   } while ((i10 | 0) != 0);
+   i7 = HEAP32[i4 >> 2] | 0;
+   i8 = HEAP32[i7 >> 2] | 0;
+   i7 = (HEAP32[i7 + 4 >> 2] | 0) + -1 | 0;
+  }
+  if ((_luaO_str2d(i8, i7, i3) | 0) != 0) {
+   i27 = 287;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i9 = HEAP8[i5] | 0;
+  i8 = HEAP8[HEAP32[(_localeconv() | 0) >> 2] | 0] | 0;
+  HEAP8[i5] = i8;
+  i10 = HEAP32[i4 >> 2] | 0;
+  i7 = HEAP32[i10 >> 2] | 0;
+  i10 = HEAP32[i10 + 4 >> 2] | 0;
+  if ((i10 | 0) == 0) {
+   i8 = -1;
+  } else {
+   do {
+    i10 = i10 + -1 | 0;
+    i11 = i7 + i10 | 0;
+    if ((HEAP8[i11] | 0) == i9 << 24 >> 24) {
+     HEAP8[i11] = i8;
+    }
+   } while ((i10 | 0) != 0);
+   i8 = HEAP32[i4 >> 2] | 0;
+   i7 = HEAP32[i8 >> 2] | 0;
+   i8 = (HEAP32[i8 + 4 >> 2] | 0) + -1 | 0;
+  }
+  if ((_luaO_str2d(i7, i8, i3) | 0) != 0) {
+   i27 = 287;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i1 = HEAP8[i5] | 0;
+  i4 = HEAP32[i4 >> 2] | 0;
+  i3 = HEAP32[i4 >> 2] | 0;
+  i4 = HEAP32[i4 + 4 >> 2] | 0;
+  if ((i4 | 0) == 0) {
+   _lexerror(i2, 12344, 287);
+  } else {
+   i6 = i4;
+  }
+  do {
+   i6 = i6 + -1 | 0;
+   i4 = i3 + i6 | 0;
+   if ((HEAP8[i4] | 0) == i1 << 24 >> 24) {
+    HEAP8[i4] = 46;
+   }
+  } while ((i6 | 0) != 0);
+  _lexerror(i2, 12344, 287);
+ }
+ return 0;
+}
+function _luaV_execute(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, d37 = 0.0, d38 = 0.0, d39 = 0.0;
+ i12 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i13 = i12 + 24 | 0;
+ i10 = i12 + 16 | 0;
+ i9 = i12 + 8 | 0;
+ i8 = i12;
+ i3 = i1 + 16 | 0;
+ i4 = i1 + 40 | 0;
+ i6 = i1 + 12 | 0;
+ i5 = i1 + 8 | 0;
+ i11 = i1 + 24 | 0;
+ i17 = i1 + 48 | 0;
+ i2 = i1 + 20 | 0;
+ i16 = i1 + 6 | 0;
+ i7 = i1 + 44 | 0;
+ i19 = HEAP32[i3 >> 2] | 0;
+ L1 : while (1) {
+  i22 = HEAP32[HEAP32[i19 >> 2] >> 2] | 0;
+  i18 = i22 + 12 | 0;
+  i23 = HEAP32[(HEAP32[i18 >> 2] | 0) + 8 >> 2] | 0;
+  i20 = i19 + 24 | 0;
+  i21 = i19 + 28 | 0;
+  i22 = i22 + 16 | 0;
+  i24 = i19 + 4 | 0;
+  i25 = HEAP32[i20 >> 2] | 0;
+  L3 : while (1) {
+   i28 = HEAP32[i21 >> 2] | 0;
+   HEAP32[i21 >> 2] = i28 + 4;
+   i28 = HEAP32[i28 >> 2] | 0;
+   i27 = HEAP8[i4] | 0;
+   do {
+    if (!((i27 & 12) == 0)) {
+     i26 = (HEAP32[i17 >> 2] | 0) + -1 | 0;
+     HEAP32[i17 >> 2] = i26;
+     i26 = (i26 | 0) == 0;
+     if (!i26 ? (i27 & 4) == 0 : 0) {
+      break;
+     }
+     i25 = HEAP32[i3 >> 2] | 0;
+     i29 = i27 & 255;
+     if ((i29 & 8 | 0) == 0 | i26 ^ 1) {
+      i27 = 0;
+     } else {
+      HEAP32[i17 >> 2] = HEAP32[i7 >> 2];
+      i27 = 1;
+     }
+     i26 = i25 + 18 | 0;
+     i30 = HEAPU8[i26] | 0;
+     if ((i30 & 128 | 0) == 0) {
+      if (i27) {
+       _luaD_hook(i1, 3, -1);
+      }
+      do {
+       if ((i29 & 4 | 0) == 0) {
+        i29 = i25 + 28 | 0;
+       } else {
+        i34 = HEAP32[(HEAP32[HEAP32[i25 >> 2] >> 2] | 0) + 12 >> 2] | 0;
+        i29 = i25 + 28 | 0;
+        i32 = HEAP32[i29 >> 2] | 0;
+        i35 = HEAP32[i34 + 12 >> 2] | 0;
+        i33 = (i32 - i35 >> 2) + -1 | 0;
+        i34 = HEAP32[i34 + 20 >> 2] | 0;
+        i31 = (i34 | 0) == 0;
+        if (i31) {
+         i30 = 0;
+        } else {
+         i30 = HEAP32[i34 + (i33 << 2) >> 2] | 0;
+        }
+        if ((i33 | 0) != 0 ? (i14 = HEAP32[i2 >> 2] | 0, i32 >>> 0 > i14 >>> 0) : 0) {
+         if (i31) {
+          i31 = 0;
+         } else {
+          i31 = HEAP32[i34 + ((i14 - i35 >> 2) + -1 << 2) >> 2] | 0;
+         }
+         if ((i30 | 0) == (i31 | 0)) {
+          break;
+         }
+        }
+        _luaD_hook(i1, 2, i30);
+       }
+      } while (0);
+      HEAP32[i2 >> 2] = HEAP32[i29 >> 2];
+      if ((HEAP8[i16] | 0) == 1) {
+       i15 = 23;
+       break L1;
+      }
+     } else {
+      HEAP8[i26] = i30 & 127;
+     }
+     i25 = HEAP32[i20 >> 2] | 0;
+    }
+   } while (0);
+   i26 = i28 >>> 6 & 255;
+   i27 = i25 + (i26 << 4) | 0;
+   switch (i28 & 63 | 0) {
+   case 9:
+    {
+     i28 = HEAP32[i22 + (i28 >>> 23 << 2) >> 2] | 0;
+     i35 = HEAP32[i28 + 8 >> 2] | 0;
+     i33 = i27;
+     i34 = HEAP32[i33 + 4 >> 2] | 0;
+     i36 = i35;
+     HEAP32[i36 >> 2] = HEAP32[i33 >> 2];
+     HEAP32[i36 + 4 >> 2] = i34;
+     i36 = i25 + (i26 << 4) + 8 | 0;
+     HEAP32[i35 + 8 >> 2] = HEAP32[i36 >> 2];
+     if ((HEAP32[i36 >> 2] & 64 | 0) == 0) {
+      continue L3;
+     }
+     i26 = HEAP32[i27 >> 2] | 0;
+     if ((HEAP8[i26 + 5 | 0] & 3) == 0) {
+      continue L3;
+     }
+     if ((HEAP8[i28 + 5 | 0] & 4) == 0) {
+      continue L3;
+     }
+     _luaC_barrier_(i1, i28, i26);
+     continue L3;
+    }
+   case 10:
+    {
+     i26 = i28 >>> 23;
+     if ((i26 & 256 | 0) == 0) {
+      i26 = i25 + (i26 << 4) | 0;
+     } else {
+      i26 = i23 + ((i26 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i25 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i25 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     _luaV_settable(i1, i27, i26, i25);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 17:
+    {
+     i29 = i28 >>> 23;
+     if ((i29 & 256 | 0) == 0) {
+      i29 = i25 + (i29 << 4) | 0;
+     } else {
+      i29 = i23 + ((i29 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i28 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i28 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     if ((HEAP32[i29 + 8 >> 2] | 0) == 3 ? (HEAP32[i28 + 8 >> 2] | 0) == 3 : 0) {
+      d37 = +HEAPF64[i29 >> 3];
+      d38 = +HEAPF64[i28 >> 3];
+      HEAPF64[i27 >> 3] = d37 - d38 * +Math_floor(+(d37 / d38));
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+      continue L3;
+     }
+     _luaV_arith(i1, i27, i29, i28, 10);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 23:
+    {
+     if ((i26 | 0) != 0) {
+      _luaF_close(i1, (HEAP32[i20 >> 2] | 0) + (i26 + -1 << 4) | 0);
+     }
+     HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + ((i28 >>> 14) + -131071 << 2);
+     continue L3;
+    }
+   case 24:
+    {
+     i27 = i28 >>> 23;
+     if ((i27 & 256 | 0) == 0) {
+      i27 = i25 + (i27 << 4) | 0;
+     } else {
+      i27 = i23 + ((i27 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i25 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i25 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     if ((HEAP32[i27 + 8 >> 2] | 0) == (HEAP32[i25 + 8 >> 2] | 0)) {
+      i27 = (_luaV_equalobj_(i1, i27, i25) | 0) != 0;
+     } else {
+      i27 = 0;
+     }
+     i25 = HEAP32[i21 >> 2] | 0;
+     if ((i27 & 1 | 0) == (i26 | 0)) {
+      i26 = HEAP32[i25 >> 2] | 0;
+      i27 = i26 >>> 6 & 255;
+      if ((i27 | 0) != 0) {
+       _luaF_close(i1, (HEAP32[i20 >> 2] | 0) + (i27 + -1 << 4) | 0);
+       i25 = HEAP32[i21 >> 2] | 0;
+      }
+      i25 = i25 + ((i26 >>> 14) + -131070 << 2) | 0;
+     } else {
+      i25 = i25 + 4 | 0;
+     }
+     HEAP32[i21 >> 2] = i25;
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 18:
+    {
+     i29 = i28 >>> 23;
+     if ((i29 & 256 | 0) == 0) {
+      i29 = i25 + (i29 << 4) | 0;
+     } else {
+      i29 = i23 + ((i29 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i28 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i28 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     if ((HEAP32[i29 + 8 >> 2] | 0) == 3 ? (HEAP32[i28 + 8 >> 2] | 0) == 3 : 0) {
+      HEAPF64[i27 >> 3] = +Math_pow(+(+HEAPF64[i29 >> 3]), +(+HEAPF64[i28 >> 3]));
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+      continue L3;
+     }
+     _luaV_arith(i1, i27, i29, i28, 11);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 1:
+    {
+     i36 = i28 >>> 14;
+     i33 = i23 + (i36 << 4) | 0;
+     i34 = HEAP32[i33 + 4 >> 2] | 0;
+     i35 = i27;
+     HEAP32[i35 >> 2] = HEAP32[i33 >> 2];
+     HEAP32[i35 + 4 >> 2] = i34;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = HEAP32[i23 + (i36 << 4) + 8 >> 2];
+     continue L3;
+    }
+   case 0:
+    {
+     i36 = i28 >>> 23;
+     i33 = i25 + (i36 << 4) | 0;
+     i34 = HEAP32[i33 + 4 >> 2] | 0;
+     i35 = i27;
+     HEAP32[i35 >> 2] = HEAP32[i33 >> 2];
+     HEAP32[i35 + 4 >> 2] = i34;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = HEAP32[i25 + (i36 << 4) + 8 >> 2];
+     continue L3;
+    }
+   case 2:
+    {
+     i36 = HEAP32[i21 >> 2] | 0;
+     HEAP32[i21 >> 2] = i36 + 4;
+     i36 = (HEAP32[i36 >> 2] | 0) >>> 6;
+     i33 = i23 + (i36 << 4) | 0;
+     i34 = HEAP32[i33 + 4 >> 2] | 0;
+     i35 = i27;
+     HEAP32[i35 >> 2] = HEAP32[i33 >> 2];
+     HEAP32[i35 + 4 >> 2] = i34;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = HEAP32[i23 + (i36 << 4) + 8 >> 2];
+     continue L3;
+    }
+   case 5:
+    {
+     i36 = HEAP32[(HEAP32[i22 + (i28 >>> 23 << 2) >> 2] | 0) + 8 >> 2] | 0;
+     i33 = i36;
+     i34 = HEAP32[i33 + 4 >> 2] | 0;
+     i35 = i27;
+     HEAP32[i35 >> 2] = HEAP32[i33 >> 2];
+     HEAP32[i35 + 4 >> 2] = i34;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = HEAP32[i36 + 8 >> 2];
+     continue L3;
+    }
+   case 3:
+    {
+     HEAP32[i27 >> 2] = i28 >>> 23;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = 1;
+     if ((i28 & 8372224 | 0) == 0) {
+      continue L3;
+     }
+     HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + 4;
+     continue L3;
+    }
+   case 7:
+    {
+     i26 = i28 >>> 14;
+     if ((i26 & 256 | 0) == 0) {
+      i26 = i25 + ((i26 & 511) << 4) | 0;
+     } else {
+      i26 = i23 + ((i26 & 255) << 4) | 0;
+     }
+     _luaV_gettable(i1, i25 + (i28 >>> 23 << 4) | 0, i26, i27);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 12:
+    {
+     i36 = i28 >>> 23;
+     i29 = i25 + (i36 << 4) | 0;
+     i26 = i26 + 1 | 0;
+     i33 = i29;
+     i34 = HEAP32[i33 + 4 >> 2] | 0;
+     i35 = i25 + (i26 << 4) | 0;
+     HEAP32[i35 >> 2] = HEAP32[i33 >> 2];
+     HEAP32[i35 + 4 >> 2] = i34;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = HEAP32[i25 + (i36 << 4) + 8 >> 2];
+     i26 = i28 >>> 14;
+     if ((i26 & 256 | 0) == 0) {
+      i25 = i25 + ((i26 & 511) << 4) | 0;
+     } else {
+      i25 = i23 + ((i26 & 255) << 4) | 0;
+     }
+     _luaV_gettable(i1, i29, i25, i27);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 13:
+    {
+     i29 = i28 >>> 23;
+     if ((i29 & 256 | 0) == 0) {
+      i29 = i25 + (i29 << 4) | 0;
+     } else {
+      i29 = i23 + ((i29 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i28 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i28 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     if ((HEAP32[i29 + 8 >> 2] | 0) == 3 ? (HEAP32[i28 + 8 >> 2] | 0) == 3 : 0) {
+      HEAPF64[i27 >> 3] = +HEAPF64[i29 >> 3] + +HEAPF64[i28 >> 3];
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+      continue L3;
+     }
+     _luaV_arith(i1, i27, i29, i28, 6);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 14:
+    {
+     i29 = i28 >>> 23;
+     if ((i29 & 256 | 0) == 0) {
+      i29 = i25 + (i29 << 4) | 0;
+     } else {
+      i29 = i23 + ((i29 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i28 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i28 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     if ((HEAP32[i29 + 8 >> 2] | 0) == 3 ? (HEAP32[i28 + 8 >> 2] | 0) == 3 : 0) {
+      HEAPF64[i27 >> 3] = +HEAPF64[i29 >> 3] - +HEAPF64[i28 >> 3];
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+      continue L3;
+     }
+     _luaV_arith(i1, i27, i29, i28, 7);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 6:
+    {
+     i26 = i28 >>> 14;
+     if ((i26 & 256 | 0) == 0) {
+      i25 = i25 + ((i26 & 511) << 4) | 0;
+     } else {
+      i25 = i23 + ((i26 & 255) << 4) | 0;
+     }
+     _luaV_gettable(i1, HEAP32[(HEAP32[i22 + (i28 >>> 23 << 2) >> 2] | 0) + 8 >> 2] | 0, i25, i27);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 4:
+    {
+     i26 = i28 >>> 23;
+     while (1) {
+      HEAP32[i27 + 8 >> 2] = 0;
+      if ((i26 | 0) == 0) {
+       continue L3;
+      } else {
+       i26 = i26 + -1 | 0;
+       i27 = i27 + 16 | 0;
+      }
+     }
+    }
+   case 8:
+    {
+     i27 = i28 >>> 23;
+     if ((i27 & 256 | 0) == 0) {
+      i27 = i25 + (i27 << 4) | 0;
+     } else {
+      i27 = i23 + ((i27 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i25 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i25 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     _luaV_settable(i1, HEAP32[(HEAP32[i22 + (i26 << 2) >> 2] | 0) + 8 >> 2] | 0, i27, i25);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 11:
+    {
+     i29 = i28 >>> 23;
+     i28 = i28 >>> 14 & 511;
+     i30 = _luaH_new(i1) | 0;
+     HEAP32[i27 >> 2] = i30;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = 69;
+     if ((i28 | i29 | 0) != 0) {
+      i36 = _luaO_fb2int(i29) | 0;
+      _luaH_resize(i1, i30, i36, _luaO_fb2int(i28) | 0);
+     }
+     if ((HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+      HEAP32[i5 >> 2] = i25 + (i26 + 1 << 4);
+      _luaC_step(i1);
+      HEAP32[i5 >> 2] = HEAP32[i24 >> 2];
+     }
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 19:
+    {
+     i36 = i28 >>> 23;
+     i28 = i25 + (i36 << 4) | 0;
+     if ((HEAP32[i25 + (i36 << 4) + 8 >> 2] | 0) == 3) {
+      HEAPF64[i27 >> 3] = -+HEAPF64[i28 >> 3];
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+      continue L3;
+     } else {
+      _luaV_arith(i1, i27, i28, i28, 12);
+      i25 = HEAP32[i20 >> 2] | 0;
+      continue L3;
+     }
+    }
+   case 15:
+    {
+     i29 = i28 >>> 23;
+     if ((i29 & 256 | 0) == 0) {
+      i29 = i25 + (i29 << 4) | 0;
+     } else {
+      i29 = i23 + ((i29 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i28 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i28 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     if ((HEAP32[i29 + 8 >> 2] | 0) == 3 ? (HEAP32[i28 + 8 >> 2] | 0) == 3 : 0) {
+      HEAPF64[i27 >> 3] = +HEAPF64[i29 >> 3] * +HEAPF64[i28 >> 3];
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+      continue L3;
+     }
+     _luaV_arith(i1, i27, i29, i28, 8);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 16:
+    {
+     i29 = i28 >>> 23;
+     if ((i29 & 256 | 0) == 0) {
+      i29 = i25 + (i29 << 4) | 0;
+     } else {
+      i29 = i23 + ((i29 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i28 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i28 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     if ((HEAP32[i29 + 8 >> 2] | 0) == 3 ? (HEAP32[i28 + 8 >> 2] | 0) == 3 : 0) {
+      HEAPF64[i27 >> 3] = +HEAPF64[i29 >> 3] / +HEAPF64[i28 >> 3];
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+      continue L3;
+     }
+     _luaV_arith(i1, i27, i29, i28, 9);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 20:
+    {
+     i29 = i28 >>> 23;
+     i28 = HEAP32[i25 + (i29 << 4) + 8 >> 2] | 0;
+     if ((i28 | 0) != 0) {
+      if ((i28 | 0) == 1) {
+       i28 = (HEAP32[i25 + (i29 << 4) >> 2] | 0) == 0;
+      } else {
+       i28 = 0;
+      }
+     } else {
+      i28 = 1;
+     }
+     HEAP32[i27 >> 2] = i28 & 1;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = 1;
+     continue L3;
+    }
+   case 21:
+    {
+     _luaV_objlen(i1, i27, i25 + (i28 >>> 23 << 4) | 0);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 22:
+    {
+     i27 = i28 >>> 23;
+     i28 = i28 >>> 14 & 511;
+     HEAP32[i5 >> 2] = i25 + (i28 + 1 << 4);
+     _luaV_concat(i1, 1 - i27 + i28 | 0);
+     i25 = HEAP32[i20 >> 2] | 0;
+     i28 = i25 + (i27 << 4) | 0;
+     i34 = i28;
+     i35 = HEAP32[i34 + 4 >> 2] | 0;
+     i36 = i25 + (i26 << 4) | 0;
+     HEAP32[i36 >> 2] = HEAP32[i34 >> 2];
+     HEAP32[i36 + 4 >> 2] = i35;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = HEAP32[i25 + (i27 << 4) + 8 >> 2];
+     if ((HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+      if (!(i26 >>> 0 < i27 >>> 0)) {
+       i28 = i25 + (i26 + 1 << 4) | 0;
+      }
+      HEAP32[i5 >> 2] = i28;
+      _luaC_step(i1);
+      HEAP32[i5 >> 2] = HEAP32[i24 >> 2];
+     }
+     i25 = HEAP32[i20 >> 2] | 0;
+     HEAP32[i5 >> 2] = HEAP32[i24 >> 2];
+     continue L3;
+    }
+   case 25:
+    {
+     i27 = i28 >>> 23;
+     if ((i27 & 256 | 0) == 0) {
+      i27 = i25 + (i27 << 4) | 0;
+     } else {
+      i27 = i23 + ((i27 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i25 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i25 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     i36 = (_luaV_lessthan(i1, i27, i25) | 0) == (i26 | 0);
+     i26 = HEAP32[i21 >> 2] | 0;
+     if (i36) {
+      i25 = HEAP32[i26 >> 2] | 0;
+      i27 = i25 >>> 6 & 255;
+      if ((i27 | 0) != 0) {
+       _luaF_close(i1, (HEAP32[i20 >> 2] | 0) + (i27 + -1 << 4) | 0);
+       i26 = HEAP32[i21 >> 2] | 0;
+      }
+      i25 = i26 + ((i25 >>> 14) + -131070 << 2) | 0;
+     } else {
+      i25 = i26 + 4 | 0;
+     }
+     HEAP32[i21 >> 2] = i25;
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 27:
+    {
+     i29 = HEAP32[i25 + (i26 << 4) + 8 >> 2] | 0;
+     i26 = (i29 | 0) == 0;
+     if ((i28 & 8372224 | 0) == 0) {
+      if (!i26) {
+       if (!((i29 | 0) == 1 ? (HEAP32[i27 >> 2] | 0) == 0 : 0)) {
+        i15 = 192;
+       }
+      }
+     } else {
+      if (!i26) {
+       if ((i29 | 0) == 1 ? (HEAP32[i27 >> 2] | 0) == 0 : 0) {
+        i15 = 192;
+       }
+      } else {
+       i15 = 192;
+      }
+     }
+     if ((i15 | 0) == 192) {
+      i15 = 0;
+      HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + 4;
+      continue L3;
+     }
+     i27 = HEAP32[i21 >> 2] | 0;
+     i26 = HEAP32[i27 >> 2] | 0;
+     i28 = i26 >>> 6 & 255;
+     if ((i28 | 0) != 0) {
+      _luaF_close(i1, (HEAP32[i20 >> 2] | 0) + (i28 + -1 << 4) | 0);
+      i27 = HEAP32[i21 >> 2] | 0;
+     }
+     HEAP32[i21 >> 2] = i27 + ((i26 >>> 14) + -131070 << 2);
+     continue L3;
+    }
+   case 26:
+    {
+     i27 = i28 >>> 23;
+     if ((i27 & 256 | 0) == 0) {
+      i27 = i25 + (i27 << 4) | 0;
+     } else {
+      i27 = i23 + ((i27 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i25 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i25 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     i36 = (_luaV_lessequal(i1, i27, i25) | 0) == (i26 | 0);
+     i26 = HEAP32[i21 >> 2] | 0;
+     if (i36) {
+      i25 = HEAP32[i26 >> 2] | 0;
+      i27 = i25 >>> 6 & 255;
+      if ((i27 | 0) != 0) {
+       _luaF_close(i1, (HEAP32[i20 >> 2] | 0) + (i27 + -1 << 4) | 0);
+       i26 = HEAP32[i21 >> 2] | 0;
+      }
+      i25 = i26 + ((i25 >>> 14) + -131070 << 2) | 0;
+     } else {
+      i25 = i26 + 4 | 0;
+     }
+     HEAP32[i21 >> 2] = i25;
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 28:
+    {
+     i30 = i28 >>> 23;
+     i29 = i25 + (i30 << 4) | 0;
+     i30 = HEAP32[i25 + (i30 << 4) + 8 >> 2] | 0;
+     i31 = (i30 | 0) == 0;
+     if ((i28 & 8372224 | 0) == 0) {
+      if (!i31) {
+       if (!((i30 | 0) == 1 ? (HEAP32[i29 >> 2] | 0) == 0 : 0)) {
+        i15 = 203;
+       }
+      }
+     } else {
+      if (!i31) {
+       if ((i30 | 0) == 1 ? (HEAP32[i29 >> 2] | 0) == 0 : 0) {
+        i15 = 203;
+       }
+      } else {
+       i15 = 203;
+      }
+     }
+     if ((i15 | 0) == 203) {
+      i15 = 0;
+      HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + 4;
+      continue L3;
+     }
+     i36 = i29;
+     i28 = HEAP32[i36 + 4 >> 2] | 0;
+     HEAP32[i27 >> 2] = HEAP32[i36 >> 2];
+     HEAP32[i27 + 4 >> 2] = i28;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = i30;
+     i27 = HEAP32[i21 >> 2] | 0;
+     i26 = HEAP32[i27 >> 2] | 0;
+     i28 = i26 >>> 6 & 255;
+     if ((i28 | 0) != 0) {
+      _luaF_close(i1, (HEAP32[i20 >> 2] | 0) + (i28 + -1 << 4) | 0);
+      i27 = HEAP32[i21 >> 2] | 0;
+     }
+     HEAP32[i21 >> 2] = i27 + ((i26 >>> 14) + -131070 << 2);
+     continue L3;
+    }
+   case 30:
+    {
+     i28 = i28 >>> 23;
+     if ((i28 | 0) != 0) {
+      HEAP32[i5 >> 2] = i25 + (i26 + i28 << 4);
+     }
+     if ((_luaD_precall(i1, i27, -1) | 0) == 0) {
+      i15 = 218;
+      break L3;
+     }
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 29:
+    {
+     i29 = i28 >>> 23;
+     i28 = i28 >>> 14 & 511;
+     if ((i29 | 0) != 0) {
+      HEAP32[i5 >> 2] = i25 + (i26 + i29 << 4);
+     }
+     if ((_luaD_precall(i1, i27, i28 + -1 | 0) | 0) == 0) {
+      i15 = 213;
+      break L3;
+     }
+     if ((i28 | 0) != 0) {
+      HEAP32[i5 >> 2] = HEAP32[i24 >> 2];
+     }
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 32:
+    {
+     d39 = +HEAPF64[i25 + (i26 + 2 << 4) >> 3];
+     d38 = d39 + +HEAPF64[i27 >> 3];
+     d37 = +HEAPF64[i25 + (i26 + 1 << 4) >> 3];
+     if (d39 > 0.0) {
+      if (!(d38 <= d37)) {
+       continue L3;
+      }
+     } else {
+      if (!(d37 <= d38)) {
+       continue L3;
+      }
+     }
+     HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + ((i28 >>> 14) + -131071 << 2);
+     HEAPF64[i27 >> 3] = d38;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+     i36 = i26 + 3 | 0;
+     HEAPF64[i25 + (i36 << 4) >> 3] = d38;
+     HEAP32[i25 + (i36 << 4) + 8 >> 2] = 3;
+     continue L3;
+    }
+   case 33:
+    {
+     i32 = i26 + 1 | 0;
+     i30 = i25 + (i32 << 4) | 0;
+     i31 = i26 + 2 | 0;
+     i29 = i25 + (i31 << 4) | 0;
+     i26 = i25 + (i26 << 4) + 8 | 0;
+     i33 = HEAP32[i26 >> 2] | 0;
+     if ((i33 | 0) != 3) {
+      if ((i33 & 15 | 0) != 4) {
+       i15 = 239;
+       break L1;
+      }
+      i36 = HEAP32[i27 >> 2] | 0;
+      if ((_luaO_str2d(i36 + 16 | 0, HEAP32[i36 + 12 >> 2] | 0, i8) | 0) == 0) {
+       i15 = 239;
+       break L1;
+      }
+      HEAPF64[i27 >> 3] = +HEAPF64[i8 >> 3];
+      HEAP32[i26 >> 2] = 3;
+      if ((i27 | 0) == 0) {
+       i15 = 239;
+       break L1;
+      }
+     }
+     i33 = i25 + (i32 << 4) + 8 | 0;
+     i32 = HEAP32[i33 >> 2] | 0;
+     if ((i32 | 0) != 3) {
+      if ((i32 & 15 | 0) != 4) {
+       i15 = 244;
+       break L1;
+      }
+      i36 = HEAP32[i30 >> 2] | 0;
+      if ((_luaO_str2d(i36 + 16 | 0, HEAP32[i36 + 12 >> 2] | 0, i9) | 0) == 0) {
+       i15 = 244;
+       break L1;
+      }
+      HEAPF64[i30 >> 3] = +HEAPF64[i9 >> 3];
+      HEAP32[i33 >> 2] = 3;
+     }
+     i31 = i25 + (i31 << 4) + 8 | 0;
+     i30 = HEAP32[i31 >> 2] | 0;
+     if ((i30 | 0) != 3) {
+      if ((i30 & 15 | 0) != 4) {
+       i15 = 249;
+       break L1;
+      }
+      i36 = HEAP32[i29 >> 2] | 0;
+      if ((_luaO_str2d(i36 + 16 | 0, HEAP32[i36 + 12 >> 2] | 0, i10) | 0) == 0) {
+       i15 = 249;
+       break L1;
+      }
+      HEAPF64[i29 >> 3] = +HEAPF64[i10 >> 3];
+      HEAP32[i31 >> 2] = 3;
+     }
+     HEAPF64[i27 >> 3] = +HEAPF64[i27 >> 3] - +HEAPF64[i29 >> 3];
+     HEAP32[i26 >> 2] = 3;
+     HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + ((i28 >>> 14) + -131071 << 2);
+     continue L3;
+    }
+   case 31:
+    {
+     i15 = 223;
+     break L3;
+    }
+   case 34:
+    {
+     i35 = i26 + 3 | 0;
+     i36 = i25 + (i35 << 4) | 0;
+     i33 = i26 + 2 | 0;
+     i34 = i26 + 5 | 0;
+     i32 = i25 + (i33 << 4) | 0;
+     i31 = HEAP32[i32 + 4 >> 2] | 0;
+     i30 = i25 + (i34 << 4) | 0;
+     HEAP32[i30 >> 2] = HEAP32[i32 >> 2];
+     HEAP32[i30 + 4 >> 2] = i31;
+     HEAP32[i25 + (i34 << 4) + 8 >> 2] = HEAP32[i25 + (i33 << 4) + 8 >> 2];
+     i34 = i26 + 1 | 0;
+     i33 = i26 + 4 | 0;
+     i30 = i25 + (i34 << 4) | 0;
+     i31 = HEAP32[i30 + 4 >> 2] | 0;
+     i32 = i25 + (i33 << 4) | 0;
+     HEAP32[i32 >> 2] = HEAP32[i30 >> 2];
+     HEAP32[i32 + 4 >> 2] = i31;
+     HEAP32[i25 + (i33 << 4) + 8 >> 2] = HEAP32[i25 + (i34 << 4) + 8 >> 2];
+     i33 = i27;
+     i34 = HEAP32[i33 + 4 >> 2] | 0;
+     i27 = i36;
+     HEAP32[i27 >> 2] = HEAP32[i33 >> 2];
+     HEAP32[i27 + 4 >> 2] = i34;
+     HEAP32[i25 + (i35 << 4) + 8 >> 2] = HEAP32[i25 + (i26 << 4) + 8 >> 2];
+     HEAP32[i5 >> 2] = i25 + (i26 + 6 << 4);
+     _luaD_call(i1, i36, i28 >>> 14 & 511, 1);
+     i36 = HEAP32[i20 >> 2] | 0;
+     HEAP32[i5 >> 2] = HEAP32[i24 >> 2];
+     i27 = HEAP32[i21 >> 2] | 0;
+     HEAP32[i21 >> 2] = i27 + 4;
+     i27 = HEAP32[i27 >> 2] | 0;
+     i25 = i36;
+     i28 = i27;
+     i27 = i36 + ((i27 >>> 6 & 255) << 4) | 0;
+     break;
+    }
+   case 35:
+    {
+     break;
+    }
+   case 36:
+    {
+     i29 = i28 >>> 23;
+     i28 = i28 >>> 14 & 511;
+     if ((i29 | 0) == 0) {
+      i29 = ((HEAP32[i5 >> 2] | 0) - i27 >> 4) + -1 | 0;
+     }
+     if ((i28 | 0) == 0) {
+      i28 = HEAP32[i21 >> 2] | 0;
+      HEAP32[i21 >> 2] = i28 + 4;
+      i28 = (HEAP32[i28 >> 2] | 0) >>> 6;
+     }
+     i27 = HEAP32[i27 >> 2] | 0;
+     i30 = i29 + -50 + (i28 * 50 | 0) | 0;
+     if ((i30 | 0) > (HEAP32[i27 + 28 >> 2] | 0)) {
+      _luaH_resizearray(i1, i27, i30);
+     }
+     if ((i29 | 0) > 0) {
+      i28 = i27 + 5 | 0;
+      while (1) {
+       i36 = i29 + i26 | 0;
+       i32 = i25 + (i36 << 4) | 0;
+       i31 = i30 + -1 | 0;
+       _luaH_setint(i1, i27, i30, i32);
+       if (((HEAP32[i25 + (i36 << 4) + 8 >> 2] & 64 | 0) != 0 ? !((HEAP8[(HEAP32[i32 >> 2] | 0) + 5 | 0] & 3) == 0) : 0) ? !((HEAP8[i28] & 4) == 0) : 0) {
+        _luaC_barrierback_(i1, i27);
+       }
+       i29 = i29 + -1 | 0;
+       if ((i29 | 0) > 0) {
+        i30 = i31;
+       } else {
+        break;
+       }
+      }
+     }
+     HEAP32[i5 >> 2] = HEAP32[i24 >> 2];
+     continue L3;
+    }
+   case 37:
+    {
+     i29 = HEAP32[(HEAP32[(HEAP32[i18 >> 2] | 0) + 16 >> 2] | 0) + (i28 >>> 14 << 2) >> 2] | 0;
+     i28 = i29 + 32 | 0;
+     i33 = HEAP32[i28 >> 2] | 0;
+     i30 = HEAP32[i29 + 40 >> 2] | 0;
+     i31 = HEAP32[i29 + 28 >> 2] | 0;
+     L323 : do {
+      if ((i33 | 0) == 0) {
+       i15 = 276;
+      } else {
+       if ((i30 | 0) > 0) {
+        i34 = i33 + 16 | 0;
+        i32 = 0;
+        while (1) {
+         i35 = HEAPU8[i31 + (i32 << 3) + 5 | 0] | 0;
+         if ((HEAP8[i31 + (i32 << 3) + 4 | 0] | 0) == 0) {
+          i36 = HEAP32[(HEAP32[i22 + (i35 << 2) >> 2] | 0) + 8 >> 2] | 0;
+         } else {
+          i36 = i25 + (i35 << 4) | 0;
+         }
+         i35 = i32 + 1 | 0;
+         if ((HEAP32[(HEAP32[i34 + (i32 << 2) >> 2] | 0) + 8 >> 2] | 0) != (i36 | 0)) {
+          i15 = 276;
+          break L323;
+         }
+         if ((i35 | 0) < (i30 | 0)) {
+          i32 = i35;
+         } else {
+          break;
+         }
+        }
+       }
+       HEAP32[i27 >> 2] = i33;
+       HEAP32[i25 + (i26 << 4) + 8 >> 2] = 70;
+      }
+     } while (0);
+     if ((i15 | 0) == 276) {
+      i15 = 0;
+      i32 = _luaF_newLclosure(i1, i30) | 0;
+      HEAP32[i32 + 12 >> 2] = i29;
+      HEAP32[i27 >> 2] = i32;
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 70;
+      if ((i30 | 0) > 0) {
+       i27 = i32 + 16 | 0;
+       i34 = 0;
+       do {
+        i33 = HEAPU8[i31 + (i34 << 3) + 5 | 0] | 0;
+        if ((HEAP8[i31 + (i34 << 3) + 4 | 0] | 0) == 0) {
+         HEAP32[i27 + (i34 << 2) >> 2] = HEAP32[i22 + (i33 << 2) >> 2];
+        } else {
+         HEAP32[i27 + (i34 << 2) >> 2] = _luaF_findupval(i1, i25 + (i33 << 4) | 0) | 0;
+        }
+        i34 = i34 + 1 | 0;
+       } while ((i34 | 0) != (i30 | 0));
+      }
+      if (!((HEAP8[i29 + 5 | 0] & 4) == 0)) {
+       _luaC_barrierproto_(i1, i29, i32);
+      }
+      HEAP32[i28 >> 2] = i32;
+     }
+     if ((HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+      HEAP32[i5 >> 2] = i25 + (i26 + 1 << 4);
+      _luaC_step(i1);
+      HEAP32[i5 >> 2] = HEAP32[i24 >> 2];
+     }
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 38:
+    {
+     i36 = i28 >>> 23;
+     i29 = i36 + -1 | 0;
+     i30 = (i25 - (HEAP32[i19 >> 2] | 0) >> 4) - (HEAPU8[(HEAP32[i18 >> 2] | 0) + 76 | 0] | 0) | 0;
+     i28 = i30 + -1 | 0;
+     if ((i36 | 0) == 0) {
+      if (((HEAP32[i11 >> 2] | 0) - (HEAP32[i5 >> 2] | 0) >> 4 | 0) <= (i28 | 0)) {
+       _luaD_growstack(i1, i28);
+      }
+      i27 = HEAP32[i20 >> 2] | 0;
+      HEAP32[i5 >> 2] = i27 + (i28 + i26 << 4);
+      i29 = i28;
+      i25 = i27;
+      i27 = i27 + (i26 << 4) | 0;
+     }
+     if ((i29 | 0) <= 0) {
+      continue L3;
+     }
+     i26 = 1 - i30 | 0;
+     i30 = 0;
+     while (1) {
+      if ((i30 | 0) < (i28 | 0)) {
+       i36 = i30 + i26 | 0;
+       i33 = i25 + (i36 << 4) | 0;
+       i34 = HEAP32[i33 + 4 >> 2] | 0;
+       i35 = i27 + (i30 << 4) | 0;
+       HEAP32[i35 >> 2] = HEAP32[i33 >> 2];
+       HEAP32[i35 + 4 >> 2] = i34;
+       HEAP32[i27 + (i30 << 4) + 8 >> 2] = HEAP32[i25 + (i36 << 4) + 8 >> 2];
+      } else {
+       HEAP32[i27 + (i30 << 4) + 8 >> 2] = 0;
+      }
+      i30 = i30 + 1 | 0;
+      if ((i30 | 0) == (i29 | 0)) {
+       continue L3;
+      }
+     }
+    }
+   default:
+    {
+     continue L3;
+    }
+   }
+   i26 = HEAP32[i27 + 24 >> 2] | 0;
+   if ((i26 | 0) == 0) {
+    continue;
+   }
+   i34 = i27 + 16 | 0;
+   i35 = HEAP32[i34 + 4 >> 2] | 0;
+   i36 = i27;
+   HEAP32[i36 >> 2] = HEAP32[i34 >> 2];
+   HEAP32[i36 + 4 >> 2] = i35;
+   HEAP32[i27 + 8 >> 2] = i26;
+   HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + ((i28 >>> 14) + -131071 << 2);
+  }
+  if ((i15 | 0) == 213) {
+   i15 = 0;
+   i19 = HEAP32[i3 >> 2] | 0;
+   i36 = i19 + 18 | 0;
+   HEAP8[i36] = HEAPU8[i36] | 4;
+   continue;
+  } else if ((i15 | 0) == 218) {
+   i15 = 0;
+   i22 = HEAP32[i3 >> 2] | 0;
+   i19 = HEAP32[i22 + 8 >> 2] | 0;
+   i23 = HEAP32[i22 >> 2] | 0;
+   i24 = HEAP32[i19 >> 2] | 0;
+   i20 = i22 + 24 | 0;
+   i21 = (HEAP32[i20 >> 2] | 0) + (HEAPU8[(HEAP32[(HEAP32[i23 >> 2] | 0) + 12 >> 2] | 0) + 76 | 0] << 4) | 0;
+   if ((HEAP32[(HEAP32[i18 >> 2] | 0) + 56 >> 2] | 0) > 0) {
+    _luaF_close(i1, HEAP32[i19 + 24 >> 2] | 0);
+   }
+   if (i23 >>> 0 < i21 >>> 0) {
+    i25 = i23;
+    i18 = 0;
+    do {
+     i34 = i25;
+     i35 = HEAP32[i34 + 4 >> 2] | 0;
+     i36 = i24 + (i18 << 4) | 0;
+     HEAP32[i36 >> 2] = HEAP32[i34 >> 2];
+     HEAP32[i36 + 4 >> 2] = i35;
+     HEAP32[i24 + (i18 << 4) + 8 >> 2] = HEAP32[i23 + (i18 << 4) + 8 >> 2];
+     i18 = i18 + 1 | 0;
+     i25 = i23 + (i18 << 4) | 0;
+    } while (i25 >>> 0 < i21 >>> 0);
+   }
+   i36 = i23;
+   HEAP32[i19 + 24 >> 2] = i24 + ((HEAP32[i20 >> 2] | 0) - i36 >> 4 << 4);
+   i36 = i24 + ((HEAP32[i5 >> 2] | 0) - i36 >> 4 << 4) | 0;
+   HEAP32[i5 >> 2] = i36;
+   HEAP32[i19 + 4 >> 2] = i36;
+   HEAP32[i19 + 28 >> 2] = HEAP32[i22 + 28 >> 2];
+   i36 = i19 + 18 | 0;
+   HEAP8[i36] = HEAPU8[i36] | 64;
+   HEAP32[i3 >> 2] = i19;
+   continue;
+  } else if ((i15 | 0) == 223) {
+   i15 = 0;
+   i20 = i28 >>> 23;
+   if ((i20 | 0) != 0) {
+    HEAP32[i5 >> 2] = i25 + (i20 + -1 + i26 << 4);
+   }
+   if ((HEAP32[(HEAP32[i18 >> 2] | 0) + 56 >> 2] | 0) > 0) {
+    _luaF_close(i1, i25);
+   }
+   i18 = _luaD_poscall(i1, i27) | 0;
+   if ((HEAP8[i19 + 18 | 0] & 4) == 0) {
+    i15 = 228;
+    break;
+   }
+   i19 = HEAP32[i3 >> 2] | 0;
+   if ((i18 | 0) == 0) {
+    continue;
+   }
+   HEAP32[i5 >> 2] = HEAP32[i19 + 4 >> 2];
+   continue;
+  }
+ }
+ if ((i15 | 0) == 23) {
+  if (!i27) {
+   i36 = HEAP32[i29 >> 2] | 0;
+   i36 = i36 + -4 | 0;
+   HEAP32[i29 >> 2] = i36;
+   i36 = HEAP8[i26] | 0;
+   i36 = i36 & 255;
+   i36 = i36 | 128;
+   i36 = i36 & 255;
+   HEAP8[i26] = i36;
+   i36 = HEAP32[i5 >> 2] | 0;
+   i36 = i36 + -16 | 0;
+   HEAP32[i25 >> 2] = i36;
+   _luaD_throw(i1, 1);
+  }
+  HEAP32[i17 >> 2] = 1;
+  i36 = HEAP32[i29 >> 2] | 0;
+  i36 = i36 + -4 | 0;
+  HEAP32[i29 >> 2] = i36;
+  i36 = HEAP8[i26] | 0;
+  i36 = i36 & 255;
+  i36 = i36 | 128;
+  i36 = i36 & 255;
+  HEAP8[i26] = i36;
+  i36 = HEAP32[i5 >> 2] | 0;
+  i36 = i36 + -16 | 0;
+  HEAP32[i25 >> 2] = i36;
+  _luaD_throw(i1, 1);
+ } else if ((i15 | 0) == 228) {
+  STACKTOP = i12;
+  return;
+ } else if ((i15 | 0) == 239) {
+  _luaG_runerror(i1, 9040, i13);
+ } else if ((i15 | 0) == 244) {
+  _luaG_runerror(i1, 9080, i13);
+ } else if ((i15 | 0) == 249) {
+  _luaG_runerror(i1, 9112, i13);
+ }
+}
+function ___floatscan(i8, i2, i11) {
+ i8 = i8 | 0;
+ i2 = i2 | 0;
+ i11 = i11 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i9 = 0, i10 = 0, i12 = 0, i13 = 0, d14 = 0.0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, d28 = 0.0, i29 = 0, d30 = 0.0, d31 = 0.0, d32 = 0.0, d33 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 512 | 0;
+ i5 = i1;
+ if ((i2 | 0) == 1) {
+  i2 = 53;
+  i3 = -1074;
+ } else if ((i2 | 0) == 2) {
+  i2 = 53;
+  i3 = -1074;
+ } else if ((i2 | 0) == 0) {
+  i2 = 24;
+  i3 = -149;
+ } else {
+  d31 = 0.0;
+  STACKTOP = i1;
+  return +d31;
+ }
+ i9 = i8 + 4 | 0;
+ i10 = i8 + 100 | 0;
+ do {
+  i4 = HEAP32[i9 >> 2] | 0;
+  if (i4 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+   HEAP32[i9 >> 2] = i4 + 1;
+   i21 = HEAPU8[i4] | 0;
+  } else {
+   i21 = ___shgetc(i8) | 0;
+  }
+ } while ((_isspace(i21 | 0) | 0) != 0);
+ do {
+  if ((i21 | 0) == 43 | (i21 | 0) == 45) {
+   i4 = 1 - (((i21 | 0) == 45) << 1) | 0;
+   i7 = HEAP32[i9 >> 2] | 0;
+   if (i7 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+    HEAP32[i9 >> 2] = i7 + 1;
+    i21 = HEAPU8[i7] | 0;
+    break;
+   } else {
+    i21 = ___shgetc(i8) | 0;
+    break;
+   }
+  } else {
+   i4 = 1;
+  }
+ } while (0);
+ i7 = 0;
+ do {
+  if ((i21 | 32 | 0) != (HEAP8[13408 + i7 | 0] | 0)) {
+   break;
+  }
+  do {
+   if (i7 >>> 0 < 7) {
+    i12 = HEAP32[i9 >> 2] | 0;
+    if (i12 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+     HEAP32[i9 >> 2] = i12 + 1;
+     i21 = HEAPU8[i12] | 0;
+     break;
+    } else {
+     i21 = ___shgetc(i8) | 0;
+     break;
+    }
+   }
+  } while (0);
+  i7 = i7 + 1 | 0;
+ } while (i7 >>> 0 < 8);
+ do {
+  if ((i7 | 0) == 3) {
+   i13 = 23;
+  } else if ((i7 | 0) != 8) {
+   i12 = (i11 | 0) == 0;
+   if (!(i7 >>> 0 < 4 | i12)) {
+    if ((i7 | 0) == 8) {
+     break;
+    } else {
+     i13 = 23;
+     break;
+    }
+   }
+   L34 : do {
+    if ((i7 | 0) == 0) {
+     i7 = 0;
+     do {
+      if ((i21 | 32 | 0) != (HEAP8[13424 + i7 | 0] | 0)) {
+       break L34;
+      }
+      do {
+       if (i7 >>> 0 < 2) {
+        i15 = HEAP32[i9 >> 2] | 0;
+        if (i15 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+         HEAP32[i9 >> 2] = i15 + 1;
+         i21 = HEAPU8[i15] | 0;
+         break;
+        } else {
+         i21 = ___shgetc(i8) | 0;
+         break;
+        }
+       }
+      } while (0);
+      i7 = i7 + 1 | 0;
+     } while (i7 >>> 0 < 3);
+    }
+   } while (0);
+   if ((i7 | 0) == 0) {
+    do {
+     if ((i21 | 0) == 48) {
+      i7 = HEAP32[i9 >> 2] | 0;
+      if (i7 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+       HEAP32[i9 >> 2] = i7 + 1;
+       i7 = HEAPU8[i7] | 0;
+      } else {
+       i7 = ___shgetc(i8) | 0;
+      }
+      if ((i7 | 32 | 0) != 120) {
+       if ((HEAP32[i10 >> 2] | 0) == 0) {
+        i21 = 48;
+        break;
+       }
+       HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+       i21 = 48;
+       break;
+      }
+      i5 = HEAP32[i9 >> 2] | 0;
+      if (i5 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+       HEAP32[i9 >> 2] = i5 + 1;
+       i21 = HEAPU8[i5] | 0;
+       i19 = 0;
+      } else {
+       i21 = ___shgetc(i8) | 0;
+       i19 = 0;
+      }
+      while (1) {
+       if ((i21 | 0) == 46) {
+        i13 = 70;
+        break;
+       } else if ((i21 | 0) != 48) {
+        i5 = 0;
+        i7 = 0;
+        i15 = 0;
+        i16 = 0;
+        i18 = 0;
+        i20 = 0;
+        d28 = 1.0;
+        i17 = 0;
+        d14 = 0.0;
+        break;
+       }
+       i5 = HEAP32[i9 >> 2] | 0;
+       if (i5 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+        HEAP32[i9 >> 2] = i5 + 1;
+        i21 = HEAPU8[i5] | 0;
+        i19 = 1;
+        continue;
+       } else {
+        i21 = ___shgetc(i8) | 0;
+        i19 = 1;
+        continue;
+       }
+      }
+      L66 : do {
+       if ((i13 | 0) == 70) {
+        i5 = HEAP32[i9 >> 2] | 0;
+        if (i5 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+         HEAP32[i9 >> 2] = i5 + 1;
+         i21 = HEAPU8[i5] | 0;
+        } else {
+         i21 = ___shgetc(i8) | 0;
+        }
+        if ((i21 | 0) == 48) {
+         i15 = -1;
+         i16 = -1;
+         while (1) {
+          i5 = HEAP32[i9 >> 2] | 0;
+          if (i5 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+           HEAP32[i9 >> 2] = i5 + 1;
+           i21 = HEAPU8[i5] | 0;
+          } else {
+           i21 = ___shgetc(i8) | 0;
+          }
+          if ((i21 | 0) != 48) {
+           i5 = 0;
+           i7 = 0;
+           i19 = 1;
+           i18 = 1;
+           i20 = 0;
+           d28 = 1.0;
+           i17 = 0;
+           d14 = 0.0;
+           break L66;
+          }
+          i29 = _i64Add(i15 | 0, i16 | 0, -1, -1) | 0;
+          i15 = i29;
+          i16 = tempRet0;
+         }
+        } else {
+         i5 = 0;
+         i7 = 0;
+         i15 = 0;
+         i16 = 0;
+         i18 = 1;
+         i20 = 0;
+         d28 = 1.0;
+         i17 = 0;
+         d14 = 0.0;
+        }
+       }
+      } while (0);
+      L79 : while (1) {
+       i24 = i21 + -48 | 0;
+       do {
+        if (!(i24 >>> 0 < 10)) {
+         i23 = i21 | 32;
+         i22 = (i21 | 0) == 46;
+         if (!((i23 + -97 | 0) >>> 0 < 6 | i22)) {
+          break L79;
+         }
+         if (i22) {
+          if ((i18 | 0) == 0) {
+           i15 = i7;
+           i16 = i5;
+           i18 = 1;
+           break;
+          } else {
+           i21 = 46;
+           break L79;
+          }
+         } else {
+          i24 = (i21 | 0) > 57 ? i23 + -87 | 0 : i24;
+          i13 = 84;
+          break;
+         }
+        } else {
+         i13 = 84;
+        }
+       } while (0);
+       if ((i13 | 0) == 84) {
+        i13 = 0;
+        do {
+         if (!((i5 | 0) < 0 | (i5 | 0) == 0 & i7 >>> 0 < 8)) {
+          if ((i5 | 0) < 0 | (i5 | 0) == 0 & i7 >>> 0 < 14) {
+           d31 = d28 * .0625;
+           d30 = d31;
+           d14 = d14 + d31 * +(i24 | 0);
+           break;
+          }
+          if ((i24 | 0) != 0 & (i20 | 0) == 0) {
+           i20 = 1;
+           d30 = d28;
+           d14 = d14 + d28 * .5;
+          } else {
+           d30 = d28;
+          }
+         } else {
+          d30 = d28;
+          i17 = i24 + (i17 << 4) | 0;
+         }
+        } while (0);
+        i7 = _i64Add(i7 | 0, i5 | 0, 1, 0) | 0;
+        i5 = tempRet0;
+        i19 = 1;
+        d28 = d30;
+       }
+       i21 = HEAP32[i9 >> 2] | 0;
+       if (i21 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+        HEAP32[i9 >> 2] = i21 + 1;
+        i21 = HEAPU8[i21] | 0;
+        continue;
+       } else {
+        i21 = ___shgetc(i8) | 0;
+        continue;
+       }
+      }
+      if ((i19 | 0) == 0) {
+       i2 = (HEAP32[i10 >> 2] | 0) == 0;
+       if (!i2) {
+        HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+       }
+       if (!i12) {
+        if (!i2 ? (i6 = HEAP32[i9 >> 2] | 0, HEAP32[i9 >> 2] = i6 + -1, (i18 | 0) != 0) : 0) {
+         HEAP32[i9 >> 2] = i6 + -2;
+        }
+       } else {
+        ___shlim(i8, 0);
+       }
+       d31 = +(i4 | 0) * 0.0;
+       STACKTOP = i1;
+       return +d31;
+      }
+      i13 = (i18 | 0) == 0;
+      i6 = i13 ? i7 : i15;
+      i13 = i13 ? i5 : i16;
+      if ((i5 | 0) < 0 | (i5 | 0) == 0 & i7 >>> 0 < 8) {
+       do {
+        i17 = i17 << 4;
+        i7 = _i64Add(i7 | 0, i5 | 0, 1, 0) | 0;
+        i5 = tempRet0;
+       } while ((i5 | 0) < 0 | (i5 | 0) == 0 & i7 >>> 0 < 8);
+      }
+      do {
+       if ((i21 | 32 | 0) == 112) {
+        i7 = _scanexp(i8, i11) | 0;
+        i5 = tempRet0;
+        if ((i7 | 0) == 0 & (i5 | 0) == -2147483648) {
+         if (i12) {
+          ___shlim(i8, 0);
+          d31 = 0.0;
+          STACKTOP = i1;
+          return +d31;
+         } else {
+          if ((HEAP32[i10 >> 2] | 0) == 0) {
+           i7 = 0;
+           i5 = 0;
+           break;
+          }
+          HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+          i7 = 0;
+          i5 = 0;
+          break;
+         }
+        }
+       } else {
+        if ((HEAP32[i10 >> 2] | 0) == 0) {
+         i7 = 0;
+         i5 = 0;
+        } else {
+         HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+         i7 = 0;
+         i5 = 0;
+        }
+       }
+      } while (0);
+      i6 = _bitshift64Shl(i6 | 0, i13 | 0, 2) | 0;
+      i6 = _i64Add(i6 | 0, tempRet0 | 0, -32, -1) | 0;
+      i5 = _i64Add(i6 | 0, tempRet0 | 0, i7 | 0, i5 | 0) | 0;
+      i6 = tempRet0;
+      if ((i17 | 0) == 0) {
+       d31 = +(i4 | 0) * 0.0;
+       STACKTOP = i1;
+       return +d31;
+      }
+      if ((i6 | 0) > 0 | (i6 | 0) == 0 & i5 >>> 0 > (0 - i3 | 0) >>> 0) {
+       HEAP32[(___errno_location() | 0) >> 2] = 34;
+       d31 = +(i4 | 0) * 1.7976931348623157e+308 * 1.7976931348623157e+308;
+       STACKTOP = i1;
+       return +d31;
+      }
+      i29 = i3 + -106 | 0;
+      i27 = ((i29 | 0) < 0) << 31 >> 31;
+      if ((i6 | 0) < (i27 | 0) | (i6 | 0) == (i27 | 0) & i5 >>> 0 < i29 >>> 0) {
+       HEAP32[(___errno_location() | 0) >> 2] = 34;
+       d31 = +(i4 | 0) * 2.2250738585072014e-308 * 2.2250738585072014e-308;
+       STACKTOP = i1;
+       return +d31;
+      }
+      if ((i17 | 0) > -1) {
+       do {
+        i17 = i17 << 1;
+        if (!(d14 >= .5)) {
+         d28 = d14;
+        } else {
+         d28 = d14 + -1.0;
+         i17 = i17 | 1;
+        }
+        d14 = d14 + d28;
+        i5 = _i64Add(i5 | 0, i6 | 0, -1, -1) | 0;
+        i6 = tempRet0;
+       } while ((i17 | 0) > -1);
+      }
+      i3 = _i64Subtract(32, 0, i3 | 0, ((i3 | 0) < 0) << 31 >> 31 | 0) | 0;
+      i3 = _i64Add(i5 | 0, i6 | 0, i3 | 0, tempRet0 | 0) | 0;
+      i29 = tempRet0;
+      if (0 > (i29 | 0) | 0 == (i29 | 0) & i2 >>> 0 > i3 >>> 0) {
+       i2 = (i3 | 0) < 0 ? 0 : i3;
+      }
+      if ((i2 | 0) < 53) {
+       d28 = +(i4 | 0);
+       d30 = +_copysign(+(+_scalbn(1.0, 84 - i2 | 0)), +d28);
+       if ((i2 | 0) < 32 & d14 != 0.0) {
+        i29 = i17 & 1;
+        i17 = (i29 ^ 1) + i17 | 0;
+        d14 = (i29 | 0) == 0 ? 0.0 : d14;
+       }
+      } else {
+       d28 = +(i4 | 0);
+       d30 = 0.0;
+      }
+      d14 = d28 * d14 + (d30 + d28 * +(i17 >>> 0)) - d30;
+      if (!(d14 != 0.0)) {
+       HEAP32[(___errno_location() | 0) >> 2] = 34;
+      }
+      d31 = +_scalbnl(d14, i5);
+      STACKTOP = i1;
+      return +d31;
+     }
+    } while (0);
+    i7 = i3 + i2 | 0;
+    i6 = 0 - i7 | 0;
+    i20 = 0;
+    while (1) {
+     if ((i21 | 0) == 46) {
+      i13 = 139;
+      break;
+     } else if ((i21 | 0) != 48) {
+      i25 = 0;
+      i22 = 0;
+      i19 = 0;
+      break;
+     }
+     i15 = HEAP32[i9 >> 2] | 0;
+     if (i15 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+      HEAP32[i9 >> 2] = i15 + 1;
+      i21 = HEAPU8[i15] | 0;
+      i20 = 1;
+      continue;
+     } else {
+      i21 = ___shgetc(i8) | 0;
+      i20 = 1;
+      continue;
+     }
+    }
+    L168 : do {
+     if ((i13 | 0) == 139) {
+      i15 = HEAP32[i9 >> 2] | 0;
+      if (i15 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+       HEAP32[i9 >> 2] = i15 + 1;
+       i21 = HEAPU8[i15] | 0;
+      } else {
+       i21 = ___shgetc(i8) | 0;
+      }
+      if ((i21 | 0) == 48) {
+       i25 = -1;
+       i22 = -1;
+       while (1) {
+        i15 = HEAP32[i9 >> 2] | 0;
+        if (i15 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+         HEAP32[i9 >> 2] = i15 + 1;
+         i21 = HEAPU8[i15] | 0;
+        } else {
+         i21 = ___shgetc(i8) | 0;
+        }
+        if ((i21 | 0) != 48) {
+         i20 = 1;
+         i19 = 1;
+         break L168;
+        }
+        i29 = _i64Add(i25 | 0, i22 | 0, -1, -1) | 0;
+        i25 = i29;
+        i22 = tempRet0;
+       }
+      } else {
+       i25 = 0;
+       i22 = 0;
+       i19 = 1;
+      }
+     }
+    } while (0);
+    HEAP32[i5 >> 2] = 0;
+    i26 = i21 + -48 | 0;
+    i27 = (i21 | 0) == 46;
+    L182 : do {
+     if (i26 >>> 0 < 10 | i27) {
+      i15 = i5 + 496 | 0;
+      i24 = 0;
+      i23 = 0;
+      i18 = 0;
+      i17 = 0;
+      i16 = 0;
+      while (1) {
+       do {
+        if (i27) {
+         if ((i19 | 0) == 0) {
+          i25 = i24;
+          i22 = i23;
+          i19 = 1;
+         } else {
+          break L182;
+         }
+        } else {
+         i27 = _i64Add(i24 | 0, i23 | 0, 1, 0) | 0;
+         i23 = tempRet0;
+         i29 = (i21 | 0) != 48;
+         if ((i17 | 0) >= 125) {
+          if (!i29) {
+           i24 = i27;
+           break;
+          }
+          HEAP32[i15 >> 2] = HEAP32[i15 >> 2] | 1;
+          i24 = i27;
+          break;
+         }
+         i20 = i5 + (i17 << 2) | 0;
+         if ((i18 | 0) != 0) {
+          i26 = i21 + -48 + ((HEAP32[i20 >> 2] | 0) * 10 | 0) | 0;
+         }
+         HEAP32[i20 >> 2] = i26;
+         i18 = i18 + 1 | 0;
+         i21 = (i18 | 0) == 9;
+         i24 = i27;
+         i20 = 1;
+         i18 = i21 ? 0 : i18;
+         i17 = (i21 & 1) + i17 | 0;
+         i16 = i29 ? i27 : i16;
+        }
+       } while (0);
+       i21 = HEAP32[i9 >> 2] | 0;
+       if (i21 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+        HEAP32[i9 >> 2] = i21 + 1;
+        i21 = HEAPU8[i21] | 0;
+       } else {
+        i21 = ___shgetc(i8) | 0;
+       }
+       i26 = i21 + -48 | 0;
+       i27 = (i21 | 0) == 46;
+       if (!(i26 >>> 0 < 10 | i27)) {
+        i13 = 162;
+        break;
+       }
+      }
+     } else {
+      i24 = 0;
+      i23 = 0;
+      i18 = 0;
+      i17 = 0;
+      i16 = 0;
+      i13 = 162;
+     }
+    } while (0);
+    if ((i13 | 0) == 162) {
+     i13 = (i19 | 0) == 0;
+     i25 = i13 ? i24 : i25;
+     i22 = i13 ? i23 : i22;
+    }
+    i13 = (i20 | 0) != 0;
+    if (i13 ? (i21 | 32 | 0) == 101 : 0) {
+     i15 = _scanexp(i8, i11) | 0;
+     i11 = tempRet0;
+     do {
+      if ((i15 | 0) == 0 & (i11 | 0) == -2147483648) {
+       if (i12) {
+        ___shlim(i8, 0);
+        d31 = 0.0;
+        STACKTOP = i1;
+        return +d31;
+       } else {
+        if ((HEAP32[i10 >> 2] | 0) == 0) {
+         i15 = 0;
+         i11 = 0;
+         break;
+        }
+        HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+        i15 = 0;
+        i11 = 0;
+        break;
+       }
+      }
+     } while (0);
+     i9 = _i64Add(i15 | 0, i11 | 0, i25 | 0, i22 | 0) | 0;
+     i22 = tempRet0;
+    } else {
+     if ((i21 | 0) > -1 ? (HEAP32[i10 >> 2] | 0) != 0 : 0) {
+      HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+      i9 = i25;
+     } else {
+      i9 = i25;
+     }
+    }
+    if (!i13) {
+     HEAP32[(___errno_location() | 0) >> 2] = 22;
+     ___shlim(i8, 0);
+     d31 = 0.0;
+     STACKTOP = i1;
+     return +d31;
+    }
+    i8 = HEAP32[i5 >> 2] | 0;
+    if ((i8 | 0) == 0) {
+     d31 = +(i4 | 0) * 0.0;
+     STACKTOP = i1;
+     return +d31;
+    }
+    do {
+     if ((i9 | 0) == (i24 | 0) & (i22 | 0) == (i23 | 0) & ((i23 | 0) < 0 | (i23 | 0) == 0 & i24 >>> 0 < 10)) {
+      if (!(i2 >>> 0 > 30) ? (i8 >>> i2 | 0) != 0 : 0) {
+       break;
+      }
+      d31 = +(i4 | 0) * +(i8 >>> 0);
+      STACKTOP = i1;
+      return +d31;
+     }
+    } while (0);
+    i29 = (i3 | 0) / -2 | 0;
+    i27 = ((i29 | 0) < 0) << 31 >> 31;
+    if ((i22 | 0) > (i27 | 0) | (i22 | 0) == (i27 | 0) & i9 >>> 0 > i29 >>> 0) {
+     HEAP32[(___errno_location() | 0) >> 2] = 34;
+     d31 = +(i4 | 0) * 1.7976931348623157e+308 * 1.7976931348623157e+308;
+     STACKTOP = i1;
+     return +d31;
+    }
+    i29 = i3 + -106 | 0;
+    i27 = ((i29 | 0) < 0) << 31 >> 31;
+    if ((i22 | 0) < (i27 | 0) | (i22 | 0) == (i27 | 0) & i9 >>> 0 < i29 >>> 0) {
+     HEAP32[(___errno_location() | 0) >> 2] = 34;
+     d31 = +(i4 | 0) * 2.2250738585072014e-308 * 2.2250738585072014e-308;
+     STACKTOP = i1;
+     return +d31;
+    }
+    if ((i18 | 0) != 0) {
+     if ((i18 | 0) < 9) {
+      i8 = i5 + (i17 << 2) | 0;
+      i10 = HEAP32[i8 >> 2] | 0;
+      do {
+       i10 = i10 * 10 | 0;
+       i18 = i18 + 1 | 0;
+      } while ((i18 | 0) != 9);
+      HEAP32[i8 >> 2] = i10;
+     }
+     i17 = i17 + 1 | 0;
+    }
+    do {
+     if ((i16 | 0) < 9 ? (i16 | 0) <= (i9 | 0) & (i9 | 0) < 18 : 0) {
+      if ((i9 | 0) == 9) {
+       d31 = +(i4 | 0) * +((HEAP32[i5 >> 2] | 0) >>> 0);
+       STACKTOP = i1;
+       return +d31;
+      }
+      if ((i9 | 0) < 9) {
+       d31 = +(i4 | 0) * +((HEAP32[i5 >> 2] | 0) >>> 0) / +(HEAP32[13440 + (8 - i9 << 2) >> 2] | 0);
+       STACKTOP = i1;
+       return +d31;
+      }
+      i10 = i2 + 27 + (Math_imul(i9, -3) | 0) | 0;
+      i8 = HEAP32[i5 >> 2] | 0;
+      if ((i10 | 0) <= 30 ? (i8 >>> i10 | 0) != 0 : 0) {
+       break;
+      }
+      d31 = +(i4 | 0) * +(i8 >>> 0) * +(HEAP32[13440 + (i9 + -10 << 2) >> 2] | 0);
+      STACKTOP = i1;
+      return +d31;
+     }
+    } while (0);
+    i8 = (i9 | 0) % 9 | 0;
+    if ((i8 | 0) == 0) {
+     i8 = 0;
+     i10 = 0;
+    } else {
+     i11 = (i9 | 0) > -1 ? i8 : i8 + 9 | 0;
+     i12 = HEAP32[13440 + (8 - i11 << 2) >> 2] | 0;
+     if ((i17 | 0) != 0) {
+      i10 = 1e9 / (i12 | 0) | 0;
+      i8 = 0;
+      i16 = 0;
+      i15 = 0;
+      while (1) {
+       i27 = i5 + (i15 << 2) | 0;
+       i13 = HEAP32[i27 >> 2] | 0;
+       i29 = ((i13 >>> 0) / (i12 >>> 0) | 0) + i16 | 0;
+       HEAP32[i27 >> 2] = i29;
+       i16 = Math_imul((i13 >>> 0) % (i12 >>> 0) | 0, i10) | 0;
+       i13 = i15 + 1 | 0;
+       if ((i15 | 0) == (i8 | 0) & (i29 | 0) == 0) {
+        i8 = i13 & 127;
+        i9 = i9 + -9 | 0;
+       }
+       if ((i13 | 0) == (i17 | 0)) {
+        break;
+       } else {
+        i15 = i13;
+       }
+      }
+      if ((i16 | 0) != 0) {
+       HEAP32[i5 + (i17 << 2) >> 2] = i16;
+       i17 = i17 + 1 | 0;
+      }
+     } else {
+      i8 = 0;
+      i17 = 0;
+     }
+     i10 = 0;
+     i9 = 9 - i11 + i9 | 0;
+    }
+    L280 : while (1) {
+     i11 = i5 + (i8 << 2) | 0;
+     if ((i9 | 0) < 18) {
+      do {
+       i13 = 0;
+       i11 = i17 + 127 | 0;
+       while (1) {
+        i11 = i11 & 127;
+        i12 = i5 + (i11 << 2) | 0;
+        i15 = _bitshift64Shl(HEAP32[i12 >> 2] | 0, 0, 29) | 0;
+        i15 = _i64Add(i15 | 0, tempRet0 | 0, i13 | 0, 0) | 0;
+        i13 = tempRet0;
+        if (i13 >>> 0 > 0 | (i13 | 0) == 0 & i15 >>> 0 > 1e9) {
+         i29 = ___udivdi3(i15 | 0, i13 | 0, 1e9, 0) | 0;
+         i15 = ___uremdi3(i15 | 0, i13 | 0, 1e9, 0) | 0;
+         i13 = i29;
+        } else {
+         i13 = 0;
+        }
+        HEAP32[i12 >> 2] = i15;
+        i12 = (i11 | 0) == (i8 | 0);
+        if (!((i11 | 0) != (i17 + 127 & 127 | 0) | i12)) {
+         i17 = (i15 | 0) == 0 ? i11 : i17;
+        }
+        if (i12) {
+         break;
+        } else {
+         i11 = i11 + -1 | 0;
+        }
+       }
+       i10 = i10 + -29 | 0;
+      } while ((i13 | 0) == 0);
+     } else {
+      if ((i9 | 0) != 18) {
+       break;
+      }
+      do {
+       if (!((HEAP32[i11 >> 2] | 0) >>> 0 < 9007199)) {
+        i9 = 18;
+        break L280;
+       }
+       i13 = 0;
+       i12 = i17 + 127 | 0;
+       while (1) {
+        i12 = i12 & 127;
+        i15 = i5 + (i12 << 2) | 0;
+        i16 = _bitshift64Shl(HEAP32[i15 >> 2] | 0, 0, 29) | 0;
+        i16 = _i64Add(i16 | 0, tempRet0 | 0, i13 | 0, 0) | 0;
+        i13 = tempRet0;
+        if (i13 >>> 0 > 0 | (i13 | 0) == 0 & i16 >>> 0 > 1e9) {
+         i29 = ___udivdi3(i16 | 0, i13 | 0, 1e9, 0) | 0;
+         i16 = ___uremdi3(i16 | 0, i13 | 0, 1e9, 0) | 0;
+         i13 = i29;
+        } else {
+         i13 = 0;
+        }
+        HEAP32[i15 >> 2] = i16;
+        i15 = (i12 | 0) == (i8 | 0);
+        if (!((i12 | 0) != (i17 + 127 & 127 | 0) | i15)) {
+         i17 = (i16 | 0) == 0 ? i12 : i17;
+        }
+        if (i15) {
+         break;
+        } else {
+         i12 = i12 + -1 | 0;
+        }
+       }
+       i10 = i10 + -29 | 0;
+      } while ((i13 | 0) == 0);
+     }
+     i8 = i8 + 127 & 127;
+     if ((i8 | 0) == (i17 | 0)) {
+      i29 = i17 + 127 & 127;
+      i17 = i5 + ((i17 + 126 & 127) << 2) | 0;
+      HEAP32[i17 >> 2] = HEAP32[i17 >> 2] | HEAP32[i5 + (i29 << 2) >> 2];
+      i17 = i29;
+     }
+     HEAP32[i5 + (i8 << 2) >> 2] = i13;
+     i9 = i9 + 9 | 0;
+    }
+    L311 : while (1) {
+     i11 = i17 + 1 & 127;
+     i12 = i5 + ((i17 + 127 & 127) << 2) | 0;
+     while (1) {
+      i15 = (i9 | 0) == 18;
+      i13 = (i9 | 0) > 27 ? 9 : 1;
+      while (1) {
+       i16 = 0;
+       while (1) {
+        i18 = i16 + i8 & 127;
+        if ((i18 | 0) == (i17 | 0)) {
+         i16 = 2;
+         break;
+        }
+        i18 = HEAP32[i5 + (i18 << 2) >> 2] | 0;
+        i19 = HEAP32[13432 + (i16 << 2) >> 2] | 0;
+        if (i18 >>> 0 < i19 >>> 0) {
+         i16 = 2;
+         break;
+        }
+        i20 = i16 + 1 | 0;
+        if (i18 >>> 0 > i19 >>> 0) {
+         break;
+        }
+        if ((i20 | 0) < 2) {
+         i16 = i20;
+        } else {
+         i16 = i20;
+         break;
+        }
+       }
+       if ((i16 | 0) == 2 & i15) {
+        break L311;
+       }
+       i10 = i13 + i10 | 0;
+       if ((i8 | 0) == (i17 | 0)) {
+        i8 = i17;
+       } else {
+        break;
+       }
+      }
+      i15 = (1 << i13) + -1 | 0;
+      i19 = 1e9 >>> i13;
+      i18 = i8;
+      i16 = 0;
+      do {
+       i27 = i5 + (i8 << 2) | 0;
+       i29 = HEAP32[i27 >> 2] | 0;
+       i20 = (i29 >>> i13) + i16 | 0;
+       HEAP32[i27 >> 2] = i20;
+       i16 = Math_imul(i29 & i15, i19) | 0;
+       i20 = (i8 | 0) == (i18 | 0) & (i20 | 0) == 0;
+       i8 = i8 + 1 & 127;
+       i9 = i20 ? i9 + -9 | 0 : i9;
+       i18 = i20 ? i8 : i18;
+      } while ((i8 | 0) != (i17 | 0));
+      if ((i16 | 0) == 0) {
+       i8 = i18;
+       continue;
+      }
+      if ((i11 | 0) != (i18 | 0)) {
+       break;
+      }
+      HEAP32[i12 >> 2] = HEAP32[i12 >> 2] | 1;
+      i8 = i18;
+     }
+     HEAP32[i5 + (i17 << 2) >> 2] = i16;
+     i8 = i18;
+     i17 = i11;
+    }
+    i9 = i8 & 127;
+    if ((i9 | 0) == (i17 | 0)) {
+     HEAP32[i5 + (i11 + -1 << 2) >> 2] = 0;
+     i17 = i11;
+    }
+    d28 = +((HEAP32[i5 + (i9 << 2) >> 2] | 0) >>> 0);
+    i9 = i8 + 1 & 127;
+    if ((i9 | 0) == (i17 | 0)) {
+     i17 = i17 + 1 & 127;
+     HEAP32[i5 + (i17 + -1 << 2) >> 2] = 0;
+    }
+    d14 = +(i4 | 0);
+    d30 = d14 * (d28 * 1.0e9 + +((HEAP32[i5 + (i9 << 2) >> 2] | 0) >>> 0));
+    i4 = i10 + 53 | 0;
+    i3 = i4 - i3 | 0;
+    if ((i3 | 0) < (i2 | 0)) {
+     i2 = (i3 | 0) < 0 ? 0 : i3;
+     i9 = 1;
+    } else {
+     i9 = 0;
+    }
+    if ((i2 | 0) < 53) {
+     d33 = +_copysign(+(+_scalbn(1.0, 105 - i2 | 0)), +d30);
+     d32 = +_fmod(+d30, +(+_scalbn(1.0, 53 - i2 | 0)));
+     d28 = d33;
+     d31 = d32;
+     d30 = d33 + (d30 - d32);
+    } else {
+     d28 = 0.0;
+     d31 = 0.0;
+    }
+    i11 = i8 + 2 & 127;
+    if ((i11 | 0) != (i17 | 0)) {
+     i5 = HEAP32[i5 + (i11 << 2) >> 2] | 0;
+     do {
+      if (!(i5 >>> 0 < 5e8)) {
+       if (i5 >>> 0 > 5e8) {
+        d31 = d14 * .75 + d31;
+        break;
+       }
+       if ((i8 + 3 & 127 | 0) == (i17 | 0)) {
+        d31 = d14 * .5 + d31;
+        break;
+       } else {
+        d31 = d14 * .75 + d31;
+        break;
+       }
+      } else {
+       if ((i5 | 0) == 0 ? (i8 + 3 & 127 | 0) == (i17 | 0) : 0) {
+        break;
+       }
+       d31 = d14 * .25 + d31;
+      }
+     } while (0);
+     if ((53 - i2 | 0) > 1 ? !(+_fmod(+d31, 1.0) != 0.0) : 0) {
+      d31 = d31 + 1.0;
+     }
+    }
+    d14 = d30 + d31 - d28;
+    do {
+     if ((i4 & 2147483647 | 0) > (-2 - i7 | 0)) {
+      if (+Math_abs(+d14) >= 9007199254740992.0) {
+       i9 = (i9 | 0) != 0 & (i2 | 0) == (i3 | 0) ? 0 : i9;
+       i10 = i10 + 1 | 0;
+       d14 = d14 * .5;
+      }
+      if ((i10 + 50 | 0) <= (i6 | 0) ? !((i9 | 0) != 0 & d31 != 0.0) : 0) {
+       break;
+      }
+      HEAP32[(___errno_location() | 0) >> 2] = 34;
+     }
+    } while (0);
+    d33 = +_scalbnl(d14, i10);
+    STACKTOP = i1;
+    return +d33;
+   } else if ((i7 | 0) == 3) {
+    i2 = HEAP32[i9 >> 2] | 0;
+    if (i2 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+     HEAP32[i9 >> 2] = i2 + 1;
+     i2 = HEAPU8[i2] | 0;
+    } else {
+     i2 = ___shgetc(i8) | 0;
+    }
+    if ((i2 | 0) == 40) {
+     i2 = 1;
+    } else {
+     if ((HEAP32[i10 >> 2] | 0) == 0) {
+      d33 = nan;
+      STACKTOP = i1;
+      return +d33;
+     }
+     HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+     d33 = nan;
+     STACKTOP = i1;
+     return +d33;
+    }
+    while (1) {
+     i3 = HEAP32[i9 >> 2] | 0;
+     if (i3 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+      HEAP32[i9 >> 2] = i3 + 1;
+      i3 = HEAPU8[i3] | 0;
+     } else {
+      i3 = ___shgetc(i8) | 0;
+     }
+     if (!((i3 + -48 | 0) >>> 0 < 10 | (i3 + -65 | 0) >>> 0 < 26) ? !((i3 + -97 | 0) >>> 0 < 26 | (i3 | 0) == 95) : 0) {
+      break;
+     }
+     i2 = i2 + 1 | 0;
+    }
+    if ((i3 | 0) == 41) {
+     d33 = nan;
+     STACKTOP = i1;
+     return +d33;
+    }
+    i3 = (HEAP32[i10 >> 2] | 0) == 0;
+    if (!i3) {
+     HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+    }
+    if (i12) {
+     HEAP32[(___errno_location() | 0) >> 2] = 22;
+     ___shlim(i8, 0);
+     d33 = 0.0;
+     STACKTOP = i1;
+     return +d33;
+    }
+    if ((i2 | 0) == 0 | i3) {
+     d33 = nan;
+     STACKTOP = i1;
+     return +d33;
+    }
+    while (1) {
+     i2 = i2 + -1 | 0;
+     HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+     if ((i2 | 0) == 0) {
+      d14 = nan;
+      break;
+     }
+    }
+    STACKTOP = i1;
+    return +d14;
+   } else {
+    if ((HEAP32[i10 >> 2] | 0) != 0) {
+     HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+    }
+    HEAP32[(___errno_location() | 0) >> 2] = 22;
+    ___shlim(i8, 0);
+    d33 = 0.0;
+    STACKTOP = i1;
+    return +d33;
+   }
+  }
+ } while (0);
+ if ((i13 | 0) == 23) {
+  i2 = (HEAP32[i10 >> 2] | 0) == 0;
+  if (!i2) {
+   HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+  }
+  if (!(i7 >>> 0 < 4 | (i11 | 0) == 0 | i2)) {
+   do {
+    HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+    i7 = i7 + -1 | 0;
+   } while (i7 >>> 0 > 3);
+  }
+ }
+ d33 = +(i4 | 0) * inf;
+ STACKTOP = i1;
+ return +d33;
+}
+function _statement(i4) {
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 160 | 0;
+ i8 = i2 + 120 | 0;
+ i24 = i2 + 96 | 0;
+ i15 = i2 + 72 | 0;
+ i25 = i2 + 48 | 0;
+ i20 = i2 + 24 | 0;
+ i21 = i2;
+ i19 = i4 + 4 | 0;
+ i6 = HEAP32[i19 >> 2] | 0;
+ i3 = i4 + 48 | 0;
+ i9 = HEAP32[i3 >> 2] | 0;
+ i1 = i4 + 52 | 0;
+ i26 = (HEAP32[i1 >> 2] | 0) + 38 | 0;
+ i27 = (HEAP16[i26 >> 1] | 0) + 1 << 16 >> 16;
+ HEAP16[i26 >> 1] = i27;
+ if ((i27 & 65535) > 200) {
+  i27 = i9 + 12 | 0;
+  i26 = HEAP32[(HEAP32[i27 >> 2] | 0) + 52 >> 2] | 0;
+  i5 = HEAP32[(HEAP32[i9 >> 2] | 0) + 64 >> 2] | 0;
+  if ((i5 | 0) == 0) {
+   i29 = 6552;
+   HEAP32[i8 >> 2] = 6360;
+   i28 = i8 + 4 | 0;
+   HEAP32[i28 >> 2] = 200;
+   i28 = i8 + 8 | 0;
+   HEAP32[i28 >> 2] = i29;
+   i28 = _luaO_pushfstring(i26, 6592, i8) | 0;
+   i29 = HEAP32[i27 >> 2] | 0;
+   _luaX_syntaxerror(i29, i28);
+  }
+  HEAP32[i8 >> 2] = i5;
+  i28 = _luaO_pushfstring(i26, 6568, i8) | 0;
+  HEAP32[i8 >> 2] = 6360;
+  i29 = i8 + 4 | 0;
+  HEAP32[i29 >> 2] = 200;
+  i29 = i8 + 8 | 0;
+  HEAP32[i29 >> 2] = i28;
+  i29 = _luaO_pushfstring(i26, 6592, i8) | 0;
+  i28 = HEAP32[i27 >> 2] | 0;
+  _luaX_syntaxerror(i28, i29);
+ }
+ i5 = i4 + 16 | 0;
+ L8 : do {
+  switch (HEAP32[i5 >> 2] | 0) {
+  case 59:
+   {
+    _luaX_next(i4);
+    break;
+   }
+  case 267:
+   {
+    HEAP32[i21 >> 2] = -1;
+    _test_then_block(i4, i21);
+    while (1) {
+     i8 = HEAP32[i5 >> 2] | 0;
+     if ((i8 | 0) == 260) {
+      i7 = 10;
+      break;
+     } else if ((i8 | 0) != 261) {
+      break;
+     }
+     _test_then_block(i4, i21);
+    }
+    if ((i7 | 0) == 10) {
+     _luaX_next(i4);
+     i7 = HEAP32[i3 >> 2] | 0;
+     HEAP8[i20 + 10 | 0] = 0;
+     HEAP8[i20 + 8 | 0] = HEAP8[i7 + 46 | 0] | 0;
+     i29 = HEAP32[(HEAP32[i7 + 12 >> 2] | 0) + 64 >> 2] | 0;
+     HEAP16[i20 + 4 >> 1] = HEAP32[i29 + 28 >> 2];
+     HEAP16[i20 + 6 >> 1] = HEAP32[i29 + 16 >> 2];
+     HEAP8[i20 + 9 | 0] = 0;
+     i29 = i7 + 16 | 0;
+     HEAP32[i20 >> 2] = HEAP32[i29 >> 2];
+     HEAP32[i29 >> 2] = i20;
+     L16 : do {
+      i8 = HEAP32[i5 >> 2] | 0;
+      switch (i8 | 0) {
+      case 277:
+      case 286:
+      case 262:
+      case 261:
+      case 260:
+       {
+        break L16;
+       }
+      default:
+       {}
+      }
+      _statement(i4);
+     } while ((i8 | 0) != 274);
+     _leaveblock(i7);
+    }
+    _check_match(i4, 262, 267, i6);
+    _luaK_patchtohere(i9, HEAP32[i21 >> 2] | 0);
+    break;
+   }
+  case 259:
+   {
+    _luaX_next(i4);
+    i7 = HEAP32[i3 >> 2] | 0;
+    HEAP8[i20 + 10 | 0] = 0;
+    HEAP8[i20 + 8 | 0] = HEAP8[i7 + 46 | 0] | 0;
+    i29 = HEAP32[(HEAP32[i7 + 12 >> 2] | 0) + 64 >> 2] | 0;
+    HEAP16[i20 + 4 >> 1] = HEAP32[i29 + 28 >> 2];
+    HEAP16[i20 + 6 >> 1] = HEAP32[i29 + 16 >> 2];
+    HEAP8[i20 + 9 | 0] = 0;
+    i29 = i7 + 16 | 0;
+    HEAP32[i20 >> 2] = HEAP32[i29 >> 2];
+    HEAP32[i29 >> 2] = i20;
+    L22 : do {
+     i8 = HEAP32[i5 >> 2] | 0;
+     switch (i8 | 0) {
+     case 277:
+     case 286:
+     case 262:
+     case 261:
+     case 260:
+      {
+       break L22;
+      }
+     default:
+      {}
+     }
+     _statement(i4);
+    } while ((i8 | 0) != 274);
+    _leaveblock(i7);
+    _check_match(i4, 262, 259, i6);
+    break;
+   }
+  case 269:
+   {
+    _luaX_next(i4);
+    i6 = HEAP32[i5 >> 2] | 0;
+    if ((i6 | 0) == 265) {
+     _luaX_next(i4);
+     i7 = HEAP32[i3 >> 2] | 0;
+     if ((HEAP32[i5 >> 2] | 0) == 288) {
+      i29 = HEAP32[i4 + 24 >> 2] | 0;
+      _luaX_next(i4);
+      _new_localvar(i4, i29);
+      i29 = HEAP32[i3 >> 2] | 0;
+      i27 = i29 + 46 | 0;
+      i28 = (HEAPU8[i27] | 0) + 1 | 0;
+      HEAP8[i27] = i28;
+      HEAP32[(HEAP32[(HEAP32[i29 >> 2] | 0) + 24 >> 2] | 0) + ((HEAP16[(HEAP32[HEAP32[(HEAP32[i29 + 12 >> 2] | 0) + 64 >> 2] >> 2] | 0) + ((i28 & 255) + -1 + (HEAP32[i29 + 40 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i29 + 20 >> 2];
+      _body(i4, i25, 0, HEAP32[i19 >> 2] | 0);
+      HEAP32[(HEAP32[(HEAP32[i7 >> 2] | 0) + 24 >> 2] | 0) + ((HEAP16[(HEAP32[HEAP32[(HEAP32[i7 + 12 >> 2] | 0) + 64 >> 2] >> 2] | 0) + ((HEAP32[i7 + 40 >> 2] | 0) + (HEAP32[i25 + 8 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i7 + 20 >> 2];
+      break L8;
+     } else {
+      _error_expected(i4, 288);
+     }
+    }
+    if ((i6 | 0) != 288) {
+     _error_expected(i4, 288);
+    }
+    i7 = i4 + 24 | 0;
+    i6 = 1;
+    while (1) {
+     i8 = HEAP32[i7 >> 2] | 0;
+     _luaX_next(i4);
+     _new_localvar(i4, i8);
+     i8 = HEAP32[i5 >> 2] | 0;
+     if ((i8 | 0) == 61) {
+      i7 = 81;
+      break;
+     } else if ((i8 | 0) != 44) {
+      i7 = 83;
+      break;
+     }
+     _luaX_next(i4);
+     if ((HEAP32[i5 >> 2] | 0) == 288) {
+      i6 = i6 + 1 | 0;
+     } else {
+      i7 = 78;
+      break;
+     }
+    }
+    do {
+     if ((i7 | 0) == 78) {
+      _error_expected(i4, 288);
+     } else if ((i7 | 0) == 81) {
+      _luaX_next(i4);
+      _subexpr(i4, i15, 0) | 0;
+      if ((HEAP32[i5 >> 2] | 0) == 44) {
+       i8 = 1;
+       do {
+        _luaX_next(i4);
+        _luaK_exp2nextreg(HEAP32[i3 >> 2] | 0, i15);
+        _subexpr(i4, i15, 0) | 0;
+        i8 = i8 + 1 | 0;
+       } while ((HEAP32[i5 >> 2] | 0) == 44);
+      } else {
+       i8 = 1;
+      }
+      i5 = HEAP32[i15 >> 2] | 0;
+      i4 = HEAP32[i3 >> 2] | 0;
+      i8 = i6 - i8 | 0;
+      if ((i5 | 0) == 0) {
+       i17 = i8;
+       i18 = i4;
+       i7 = 88;
+       break;
+      } else if (!((i5 | 0) == 13 | (i5 | 0) == 12)) {
+       _luaK_exp2nextreg(i4, i15);
+       i17 = i8;
+       i18 = i4;
+       i7 = 88;
+       break;
+      }
+      i5 = i8 + 1 | 0;
+      i5 = (i5 | 0) < 0 ? 0 : i5;
+      _luaK_setreturns(i4, i15, i5);
+      if ((i5 | 0) > 1) {
+       _luaK_reserveregs(i4, i5 + -1 | 0);
+      }
+     } else if ((i7 | 0) == 83) {
+      HEAP32[i15 >> 2] = 0;
+      i17 = i6;
+      i18 = HEAP32[i3 >> 2] | 0;
+      i7 = 88;
+     }
+    } while (0);
+    if ((i7 | 0) == 88 ? (i17 | 0) > 0 : 0) {
+     i29 = HEAPU8[i18 + 48 | 0] | 0;
+     _luaK_reserveregs(i18, i17);
+     _luaK_nil(i18, i29, i17);
+    }
+    i5 = HEAP32[i3 >> 2] | 0;
+    i4 = i5 + 46 | 0;
+    i7 = (HEAPU8[i4] | 0) + i6 | 0;
+    HEAP8[i4] = i7;
+    if ((i6 | 0) != 0 ? (i11 = i5 + 20 | 0, i14 = i5 + 40 | 0, i12 = HEAP32[(HEAP32[i5 >> 2] | 0) + 24 >> 2] | 0, i13 = HEAP32[HEAP32[(HEAP32[i5 + 12 >> 2] | 0) + 64 >> 2] >> 2] | 0, HEAP32[i12 + ((HEAP16[i13 + ((i7 & 255) - i6 + (HEAP32[i14 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i11 >> 2], i16 = i6 + -1 | 0, (i16 | 0) != 0) : 0) {
+     do {
+      HEAP32[i12 + ((HEAP16[i13 + ((HEAPU8[i4] | 0) - i16 + (HEAP32[i14 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i11 >> 2];
+      i16 = i16 + -1 | 0;
+     } while ((i16 | 0) != 0);
+    }
+    break;
+   }
+  case 264:
+   {
+    HEAP8[i24 + 10 | 0] = 1;
+    HEAP8[i24 + 8 | 0] = HEAP8[i9 + 46 | 0] | 0;
+    i29 = HEAP32[(HEAP32[i9 + 12 >> 2] | 0) + 64 >> 2] | 0;
+    HEAP16[i24 + 4 >> 1] = HEAP32[i29 + 28 >> 2];
+    HEAP16[i24 + 6 >> 1] = HEAP32[i29 + 16 >> 2];
+    HEAP8[i24 + 9 | 0] = 0;
+    i29 = i9 + 16 | 0;
+    HEAP32[i24 >> 2] = HEAP32[i29 >> 2];
+    HEAP32[i29 >> 2] = i24;
+    _luaX_next(i4);
+    if ((HEAP32[i5 >> 2] | 0) != 288) {
+     _error_expected(i4, 288);
+    }
+    i14 = i4 + 24 | 0;
+    i13 = HEAP32[i14 >> 2] | 0;
+    _luaX_next(i4);
+    i11 = HEAP32[i5 >> 2] | 0;
+    if ((i11 | 0) == 268 | (i11 | 0) == 44) {
+     i12 = HEAP32[i3 >> 2] | 0;
+     i11 = HEAPU8[i12 + 48 | 0] | 0;
+     _new_localvar(i4, _luaX_newstring(i4, 6744, 15) | 0);
+     _new_localvar(i4, _luaX_newstring(i4, 6760, 11) | 0);
+     _new_localvar(i4, _luaX_newstring(i4, 6776, 13) | 0);
+     _new_localvar(i4, i13);
+     i13 = HEAP32[i5 >> 2] | 0;
+     do {
+      if ((i13 | 0) == 44) {
+       i15 = 4;
+       while (1) {
+        _luaX_next(i4);
+        if ((HEAP32[i5 >> 2] | 0) != 288) {
+         i7 = 40;
+         break;
+        }
+        i13 = HEAP32[i14 >> 2] | 0;
+        _luaX_next(i4);
+        _new_localvar(i4, i13);
+        i13 = HEAP32[i5 >> 2] | 0;
+        if ((i13 | 0) == 44) {
+         i15 = i15 + 1 | 0;
+        } else {
+         i7 = 42;
+         break;
+        }
+       }
+       if ((i7 | 0) == 40) {
+        _error_expected(i4, 288);
+       } else if ((i7 | 0) == 42) {
+        i22 = i13;
+        i10 = i15 + -2 | 0;
+        break;
+       }
+      } else {
+       i22 = i13;
+       i10 = 1;
+      }
+     } while (0);
+     if ((i22 | 0) != 268) {
+      _error_expected(i4, 268);
+     }
+     _luaX_next(i4);
+     i13 = HEAP32[i19 >> 2] | 0;
+     _subexpr(i4, i8, 0) | 0;
+     if ((HEAP32[i5 >> 2] | 0) == 44) {
+      i14 = 1;
+      do {
+       _luaX_next(i4);
+       _luaK_exp2nextreg(HEAP32[i3 >> 2] | 0, i8);
+       _subexpr(i4, i8, 0) | 0;
+       i14 = i14 + 1 | 0;
+      } while ((HEAP32[i5 >> 2] | 0) == 44);
+     } else {
+      i14 = 1;
+     }
+     i5 = HEAP32[i3 >> 2] | 0;
+     i14 = 3 - i14 | 0;
+     i15 = HEAP32[i8 >> 2] | 0;
+     if ((i15 | 0) == 0) {
+      i7 = 51;
+     } else if ((i15 | 0) == 13 | (i15 | 0) == 12) {
+      i15 = i14 + 1 | 0;
+      i15 = (i15 | 0) < 0 ? 0 : i15;
+      _luaK_setreturns(i5, i8, i15);
+      if ((i15 | 0) > 1) {
+       _luaK_reserveregs(i5, i15 + -1 | 0);
+      }
+     } else {
+      _luaK_exp2nextreg(i5, i8);
+      i7 = 51;
+     }
+     if ((i7 | 0) == 51 ? (i14 | 0) > 0 : 0) {
+      i29 = HEAPU8[i5 + 48 | 0] | 0;
+      _luaK_reserveregs(i5, i14);
+      _luaK_nil(i5, i29, i14);
+     }
+     _luaK_checkstack(i12, 3);
+     _forbody(i4, i11, i13, i10, 0);
+    } else if ((i11 | 0) == 61) {
+     i11 = HEAP32[i3 >> 2] | 0;
+     i7 = i11 + 48 | 0;
+     i10 = HEAPU8[i7] | 0;
+     _new_localvar(i4, _luaX_newstring(i4, 6792, 11) | 0);
+     _new_localvar(i4, _luaX_newstring(i4, 6808, 11) | 0);
+     _new_localvar(i4, _luaX_newstring(i4, 6824, 10) | 0);
+     _new_localvar(i4, i13);
+     if ((HEAP32[i5 >> 2] | 0) != 61) {
+      _error_expected(i4, 61);
+     }
+     _luaX_next(i4);
+     _subexpr(i4, i8, 0) | 0;
+     _luaK_exp2nextreg(HEAP32[i3 >> 2] | 0, i8);
+     if ((HEAP32[i5 >> 2] | 0) != 44) {
+      _error_expected(i4, 44);
+     }
+     _luaX_next(i4);
+     _subexpr(i4, i8, 0) | 0;
+     _luaK_exp2nextreg(HEAP32[i3 >> 2] | 0, i8);
+     if ((HEAP32[i5 >> 2] | 0) == 44) {
+      _luaX_next(i4);
+      _subexpr(i4, i8, 0) | 0;
+      _luaK_exp2nextreg(HEAP32[i3 >> 2] | 0, i8);
+     } else {
+      i29 = HEAPU8[i7] | 0;
+      _luaK_codek(i11, i29, _luaK_numberK(i11, 1.0) | 0) | 0;
+      _luaK_reserveregs(i11, 1);
+     }
+     _forbody(i4, i10, i6, 1, 1);
+    } else {
+     _luaX_syntaxerror(i4, 6720);
+    }
+    _check_match(i4, 262, 264, i6);
+    _leaveblock(i9);
+    break;
+   }
+  case 265:
+   {
+    _luaX_next(i4);
+    if ((HEAP32[i5 >> 2] | 0) != 288) {
+     _error_expected(i4, 288);
+    }
+    i8 = HEAP32[i4 + 24 >> 2] | 0;
+    _luaX_next(i4);
+    i9 = HEAP32[i3 >> 2] | 0;
+    if ((_singlevaraux(i9, i8, i20, 1) | 0) == 0) {
+     _singlevaraux(i9, HEAP32[i4 + 72 >> 2] | 0, i20, 1) | 0;
+     i29 = _luaK_stringK(HEAP32[i3 >> 2] | 0, i8) | 0;
+     HEAP32[i25 + 16 >> 2] = -1;
+     HEAP32[i25 + 20 >> 2] = -1;
+     HEAP32[i25 >> 2] = 4;
+     HEAP32[i25 + 8 >> 2] = i29;
+     _luaK_indexed(i9, i20, i25);
+    }
+    while (1) {
+     i8 = HEAP32[i5 >> 2] | 0;
+     if ((i8 | 0) == 58) {
+      i7 = 70;
+      break;
+     } else if ((i8 | 0) != 46) {
+      i5 = 0;
+      break;
+     }
+     _fieldsel(i4, i20);
+    }
+    if ((i7 | 0) == 70) {
+     _fieldsel(i4, i20);
+     i5 = 1;
+    }
+    _body(i4, i21, i5, i6);
+    _luaK_storevar(HEAP32[i3 >> 2] | 0, i20, i21);
+    _luaK_fixline(HEAP32[i3 >> 2] | 0, i6);
+    break;
+   }
+  case 278:
+   {
+    _luaX_next(i4);
+    i7 = _luaK_getlabel(i9) | 0;
+    _subexpr(i4, i20, 0) | 0;
+    if ((HEAP32[i20 >> 2] | 0) == 1) {
+     HEAP32[i20 >> 2] = 3;
+    }
+    _luaK_goiftrue(HEAP32[i3 >> 2] | 0, i20);
+    i8 = HEAP32[i20 + 20 >> 2] | 0;
+    HEAP8[i21 + 10 | 0] = 1;
+    HEAP8[i21 + 8 | 0] = HEAP8[i9 + 46 | 0] | 0;
+    i29 = HEAP32[(HEAP32[i9 + 12 >> 2] | 0) + 64 >> 2] | 0;
+    HEAP16[i21 + 4 >> 1] = HEAP32[i29 + 28 >> 2];
+    HEAP16[i21 + 6 >> 1] = HEAP32[i29 + 16 >> 2];
+    HEAP8[i21 + 9 | 0] = 0;
+    i29 = i9 + 16 | 0;
+    HEAP32[i21 >> 2] = HEAP32[i29 >> 2];
+    HEAP32[i29 >> 2] = i21;
+    if ((HEAP32[i5 >> 2] | 0) != 259) {
+     _error_expected(i4, 259);
+    }
+    _luaX_next(i4);
+    i10 = HEAP32[i3 >> 2] | 0;
+    HEAP8[i20 + 10 | 0] = 0;
+    HEAP8[i20 + 8 | 0] = HEAP8[i10 + 46 | 0] | 0;
+    i29 = HEAP32[(HEAP32[i10 + 12 >> 2] | 0) + 64 >> 2] | 0;
+    HEAP16[i20 + 4 >> 1] = HEAP32[i29 + 28 >> 2];
+    HEAP16[i20 + 6 >> 1] = HEAP32[i29 + 16 >> 2];
+    HEAP8[i20 + 9 | 0] = 0;
+    i29 = i10 + 16 | 0;
+    HEAP32[i20 >> 2] = HEAP32[i29 >> 2];
+    HEAP32[i29 >> 2] = i20;
+    L119 : do {
+     i11 = HEAP32[i5 >> 2] | 0;
+     switch (i11 | 0) {
+     case 277:
+     case 286:
+     case 262:
+     case 261:
+     case 260:
+      {
+       break L119;
+      }
+     default:
+      {}
+     }
+     _statement(i4);
+    } while ((i11 | 0) != 274);
+    _leaveblock(i10);
+    _luaK_patchlist(i9, _luaK_jump(i9) | 0, i7);
+    _check_match(i4, 262, 278, i6);
+    _leaveblock(i9);
+    _luaK_patchtohere(i9, i8);
+    break;
+   }
+  case 273:
+   {
+    i7 = _luaK_getlabel(i9) | 0;
+    HEAP8[i24 + 10 | 0] = 1;
+    i28 = i9 + 46 | 0;
+    HEAP8[i24 + 8 | 0] = HEAP8[i28] | 0;
+    i11 = i9 + 12 | 0;
+    i29 = HEAP32[(HEAP32[i11 >> 2] | 0) + 64 >> 2] | 0;
+    HEAP16[i24 + 4 >> 1] = HEAP32[i29 + 28 >> 2];
+    HEAP16[i24 + 6 >> 1] = HEAP32[i29 + 16 >> 2];
+    HEAP8[i24 + 9 | 0] = 0;
+    i29 = i9 + 16 | 0;
+    HEAP32[i24 >> 2] = HEAP32[i29 >> 2];
+    HEAP32[i29 >> 2] = i24;
+    HEAP8[i15 + 10 | 0] = 0;
+    i10 = i15 + 8 | 0;
+    HEAP8[i10] = HEAP8[i28] | 0;
+    i11 = HEAP32[(HEAP32[i11 >> 2] | 0) + 64 >> 2] | 0;
+    HEAP16[i15 + 4 >> 1] = HEAP32[i11 + 28 >> 2];
+    HEAP16[i15 + 6 >> 1] = HEAP32[i11 + 16 >> 2];
+    i11 = i15 + 9 | 0;
+    HEAP8[i11] = 0;
+    HEAP32[i15 >> 2] = HEAP32[i29 >> 2];
+    HEAP32[i29 >> 2] = i15;
+    _luaX_next(i4);
+    L124 : do {
+     i12 = HEAP32[i5 >> 2] | 0;
+     switch (i12 | 0) {
+     case 277:
+     case 286:
+     case 262:
+     case 261:
+     case 260:
+      {
+       break L124;
+      }
+     default:
+      {}
+     }
+     _statement(i4);
+    } while ((i12 | 0) != 274);
+    _check_match(i4, 277, 273, i6);
+    _subexpr(i4, i8, 0) | 0;
+    if ((HEAP32[i8 >> 2] | 0) == 1) {
+     HEAP32[i8 >> 2] = 3;
+    }
+    _luaK_goiftrue(HEAP32[i3 >> 2] | 0, i8);
+    i4 = HEAP32[i8 + 20 >> 2] | 0;
+    if ((HEAP8[i11] | 0) != 0) {
+     _luaK_patchclose(i9, i4, HEAPU8[i10] | 0);
+    }
+    _leaveblock(i9);
+    _luaK_patchlist(i9, i4, i7);
+    _leaveblock(i9);
+    break;
+   }
+  case 285:
+   {
+    _luaX_next(i4);
+    if ((HEAP32[i5 >> 2] | 0) != 288) {
+     _error_expected(i4, 288);
+    }
+    i10 = HEAP32[i4 + 24 >> 2] | 0;
+    _luaX_next(i4);
+    i15 = HEAP32[i3 >> 2] | 0;
+    i9 = i4 + 64 | 0;
+    i14 = HEAP32[i9 >> 2] | 0;
+    i12 = i14 + 24 | 0;
+    i11 = i15 + 16 | 0;
+    i16 = HEAP16[(HEAP32[i11 >> 2] | 0) + 4 >> 1] | 0;
+    i13 = i14 + 28 | 0;
+    L138 : do {
+     if ((i16 | 0) < (HEAP32[i13 >> 2] | 0)) {
+      while (1) {
+       i17 = i16 + 1 | 0;
+       if ((_luaS_eqstr(i10, HEAP32[(HEAP32[i12 >> 2] | 0) + (i16 << 4) >> 2] | 0) | 0) != 0) {
+        break;
+       }
+       if ((i17 | 0) < (HEAP32[i13 >> 2] | 0)) {
+        i16 = i17;
+       } else {
+        break L138;
+       }
+      }
+      i28 = i15 + 12 | 0;
+      i29 = HEAP32[(HEAP32[i28 >> 2] | 0) + 52 >> 2] | 0;
+      i27 = HEAP32[(HEAP32[i12 >> 2] | 0) + (i16 << 4) + 8 >> 2] | 0;
+      HEAP32[i8 >> 2] = i10 + 16;
+      HEAP32[i8 + 4 >> 2] = i27;
+      i29 = _luaO_pushfstring(i29, 6680, i8) | 0;
+      _semerror(HEAP32[i28 >> 2] | 0, i29);
+     }
+    } while (0);
+    if ((HEAP32[i5 >> 2] | 0) != 285) {
+     _error_expected(i4, 285);
+    }
+    _luaX_next(i4);
+    i8 = HEAP32[i15 + 20 >> 2] | 0;
+    i15 = HEAP32[i13 >> 2] | 0;
+    i14 = i14 + 32 | 0;
+    if ((i15 | 0) < (HEAP32[i14 >> 2] | 0)) {
+     i14 = HEAP32[i12 >> 2] | 0;
+    } else {
+     i14 = _luaM_growaux_(HEAP32[i1 >> 2] | 0, HEAP32[i12 >> 2] | 0, i14, 16, 32767, 6312) | 0;
+     HEAP32[i12 >> 2] = i14;
+    }
+    HEAP32[i14 + (i15 << 4) >> 2] = i10;
+    i29 = HEAP32[i12 >> 2] | 0;
+    HEAP32[i29 + (i15 << 4) + 8 >> 2] = i6;
+    HEAP8[i29 + (i15 << 4) + 12 | 0] = HEAP8[(HEAP32[i3 >> 2] | 0) + 46 | 0] | 0;
+    HEAP32[(HEAP32[i12 >> 2] | 0) + (i15 << 4) + 4 >> 2] = i8;
+    HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + 1;
+    L152 : while (1) {
+     switch (HEAP32[i5 >> 2] | 0) {
+     case 285:
+     case 59:
+      {
+       break;
+      }
+     case 286:
+     case 262:
+     case 261:
+     case 260:
+      {
+       i7 = 108;
+       break L152;
+      }
+     default:
+      {
+       break L152;
+      }
+     }
+     _statement(i4);
+    }
+    if ((i7 | 0) == 108) {
+     HEAP8[(HEAP32[i12 >> 2] | 0) + (i15 << 4) + 12 | 0] = HEAP8[(HEAP32[i11 >> 2] | 0) + 8 | 0] | 0;
+    }
+    i5 = (HEAP32[i12 >> 2] | 0) + (i15 << 4) | 0;
+    i8 = HEAP32[i9 >> 2] | 0;
+    i7 = HEAP16[(HEAP32[(HEAP32[i3 >> 2] | 0) + 16 >> 2] | 0) + 6 >> 1] | 0;
+    i6 = i8 + 16 | 0;
+    if ((i7 | 0) < (HEAP32[i6 >> 2] | 0)) {
+     i8 = i8 + 12 | 0;
+     do {
+      while (1) {
+       if ((_luaS_eqstr(HEAP32[(HEAP32[i8 >> 2] | 0) + (i7 << 4) >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0) == 0) {
+        break;
+       }
+       _closegoto(i4, i7, i5);
+       if ((i7 | 0) >= (HEAP32[i6 >> 2] | 0)) {
+        break L8;
+       }
+      }
+      i7 = i7 + 1 | 0;
+     } while ((i7 | 0) < (HEAP32[i6 >> 2] | 0));
+    }
+    break;
+   }
+  case 274:
+   {
+    _luaX_next(i4);
+    i6 = HEAP32[i3 >> 2] | 0;
+    L166 : do {
+     switch (HEAP32[i5 >> 2] | 0) {
+     case 59:
+     case 277:
+     case 286:
+     case 262:
+     case 261:
+     case 260:
+      {
+       i8 = 0;
+       i7 = 0;
+       break;
+      }
+     default:
+      {
+       _subexpr(i4, i24, 0) | 0;
+       if ((HEAP32[i5 >> 2] | 0) == 44) {
+        i7 = 1;
+        do {
+         _luaX_next(i4);
+         _luaK_exp2nextreg(HEAP32[i3 >> 2] | 0, i24);
+         _subexpr(i4, i24, 0) | 0;
+         i7 = i7 + 1 | 0;
+        } while ((HEAP32[i5 >> 2] | 0) == 44);
+       } else {
+        i7 = 1;
+       }
+       if (!(((HEAP32[i24 >> 2] | 0) + -12 | 0) >>> 0 < 2)) {
+        if ((i7 | 0) == 1) {
+         i8 = _luaK_exp2anyreg(i6, i24) | 0;
+         i7 = 1;
+         break L166;
+        } else {
+         _luaK_exp2nextreg(i6, i24);
+         i8 = HEAPU8[i6 + 46 | 0] | 0;
+         break L166;
+        }
+       } else {
+        _luaK_setreturns(i6, i24, -1);
+        if ((HEAP32[i24 >> 2] | 0) == 12 & (i7 | 0) == 1) {
+         i29 = (HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i24 + 8 >> 2] << 2) | 0;
+         HEAP32[i29 >> 2] = HEAP32[i29 >> 2] & -64 | 30;
+        }
+        i8 = HEAPU8[i6 + 46 | 0] | 0;
+        i7 = -1;
+        break L166;
+       }
+      }
+     }
+    } while (0);
+    _luaK_ret(i6, i8, i7);
+    if ((HEAP32[i5 >> 2] | 0) == 59) {
+     _luaX_next(i4);
+    }
+    break;
+   }
+  case 266:
+  case 258:
+   {
+    i6 = _luaK_jump(i9) | 0;
+    i7 = HEAP32[i19 >> 2] | 0;
+    i29 = (HEAP32[i5 >> 2] | 0) == 266;
+    _luaX_next(i4);
+    do {
+     if (i29) {
+      if ((HEAP32[i5 >> 2] | 0) == 288) {
+       i23 = HEAP32[i4 + 24 >> 2] | 0;
+       _luaX_next(i4);
+       break;
+      } else {
+       _error_expected(i4, 288);
+      }
+     } else {
+      i23 = _luaS_new(HEAP32[i1 >> 2] | 0, 6304) | 0;
+     }
+    } while (0);
+    i10 = HEAP32[i4 + 64 >> 2] | 0;
+    i9 = i10 + 12 | 0;
+    i5 = i10 + 16 | 0;
+    i8 = HEAP32[i5 >> 2] | 0;
+    i10 = i10 + 20 | 0;
+    if ((i8 | 0) < (HEAP32[i10 >> 2] | 0)) {
+     i10 = HEAP32[i9 >> 2] | 0;
+    } else {
+     i10 = _luaM_growaux_(HEAP32[i1 >> 2] | 0, HEAP32[i9 >> 2] | 0, i10, 16, 32767, 6312) | 0;
+     HEAP32[i9 >> 2] = i10;
+    }
+    HEAP32[i10 + (i8 << 4) >> 2] = i23;
+    i29 = HEAP32[i9 >> 2] | 0;
+    HEAP32[i29 + (i8 << 4) + 8 >> 2] = i7;
+    HEAP8[i29 + (i8 << 4) + 12 | 0] = HEAP8[(HEAP32[i3 >> 2] | 0) + 46 | 0] | 0;
+    HEAP32[(HEAP32[i9 >> 2] | 0) + (i8 << 4) + 4 >> 2] = i6;
+    HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 1;
+    _findlabel(i4, i8) | 0;
+    break;
+   }
+  default:
+   {
+    i6 = i8 + 8 | 0;
+    _suffixedexp(i4, i6);
+    i29 = HEAP32[i5 >> 2] | 0;
+    if ((i29 | 0) == 44 | (i29 | 0) == 61) {
+     HEAP32[i8 >> 2] = 0;
+     _assignment(i4, i8, 1);
+     break L8;
+    }
+    if ((HEAP32[i6 >> 2] | 0) == 12) {
+     i29 = (HEAP32[(HEAP32[i9 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i8 + 16 >> 2] << 2) | 0;
+     HEAP32[i29 >> 2] = HEAP32[i29 >> 2] & -8372225 | 16384;
+     break L8;
+    } else {
+     _luaX_syntaxerror(i4, 6344);
+    }
+   }
+  }
+ } while (0);
+ i29 = HEAP32[i3 >> 2] | 0;
+ HEAP8[i29 + 48 | 0] = HEAP8[i29 + 46 | 0] | 0;
+ i29 = (HEAP32[i1 >> 2] | 0) + 38 | 0;
+ HEAP16[i29 >> 1] = (HEAP16[i29 >> 1] | 0) + -1 << 16 >> 16;
+ STACKTOP = i2;
+ return;
+}
+function _match(i1, i12, i11) {
+ i1 = i1 | 0;
+ i12 = i12 | 0;
+ i11 = i11 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i8 = i2;
+ i32 = HEAP32[i1 >> 2] | 0;
+ HEAP32[i1 >> 2] = i32 + -1;
+ if ((i32 | 0) == 0) {
+  _luaL_error(HEAP32[i1 + 16 >> 2] | 0, 7272, i8) | 0;
+ }
+ i14 = i1 + 12 | 0;
+ i22 = HEAP32[i14 >> 2] | 0;
+ L4 : do {
+  if ((i22 | 0) != (i11 | 0)) {
+   i3 = i1 + 8 | 0;
+   i9 = i1 + 16 | 0;
+   i16 = i1 + 4 | 0;
+   i10 = i1 + 20 | 0;
+   L6 : while (1) {
+    i19 = i12 + 1 | 0;
+    i20 = i12 + -1 | 0;
+    L8 : while (1) {
+     i23 = HEAP8[i11] | 0;
+     i21 = i23 << 24 >> 24;
+     L10 : do {
+      if ((i21 | 0) == 36) {
+       i7 = i11 + 1 | 0;
+       if ((i7 | 0) == (i22 | 0)) {
+        i7 = 23;
+        break L6;
+       } else {
+        i22 = i7;
+        i21 = i7;
+        i7 = 89;
+       }
+      } else if ((i21 | 0) == 37) {
+       i21 = i11 + 1 | 0;
+       i23 = HEAP8[i21] | 0;
+       switch (i23 << 24 >> 24 | 0) {
+       case 57:
+       case 56:
+       case 55:
+       case 54:
+       case 53:
+       case 52:
+       case 51:
+       case 50:
+       case 49:
+       case 48:
+        {
+         i7 = 69;
+         break L8;
+        }
+       case 98:
+        {
+         i7 = 25;
+         break L8;
+        }
+       case 102:
+        {
+         break;
+        }
+       default:
+        {
+         if ((i21 | 0) == (i22 | 0)) {
+          _luaL_error(HEAP32[i9 >> 2] | 0, 7368, i8) | 0;
+         }
+         i22 = i11 + 2 | 0;
+         i7 = 89;
+         break L10;
+        }
+       }
+       i22 = i11 + 2 | 0;
+       if ((HEAP8[i22] | 0) == 91) {
+        i21 = 91;
+       } else {
+        _luaL_error(HEAP32[i9 >> 2] | 0, 7296, i8) | 0;
+        i21 = HEAP8[i22] | 0;
+       }
+       i23 = i11 + 3 | 0;
+       i21 = i21 << 24 >> 24;
+       if ((i21 | 0) == 91) {
+        i21 = (HEAP8[i23] | 0) == 94 ? i11 + 4 | 0 : i23;
+        while (1) {
+         if ((i21 | 0) == (HEAP32[i14 >> 2] | 0)) {
+          _luaL_error(HEAP32[i9 >> 2] | 0, 7408, i8) | 0;
+         }
+         i11 = i21 + 1 | 0;
+         if ((HEAP8[i21] | 0) == 37) {
+          i11 = i11 >>> 0 < (HEAP32[i14 >> 2] | 0) >>> 0 ? i21 + 2 | 0 : i11;
+         }
+         if ((HEAP8[i11] | 0) == 93) {
+          break;
+         } else {
+          i21 = i11;
+         }
+        }
+        i11 = i11 + 1 | 0;
+       } else if ((i21 | 0) == 37) {
+        if ((i23 | 0) == (HEAP32[i14 >> 2] | 0)) {
+         _luaL_error(HEAP32[i9 >> 2] | 0, 7368, i8) | 0;
+        }
+        i11 = i11 + 4 | 0;
+       } else {
+        i11 = i23;
+       }
+       if ((i12 | 0) == (HEAP32[i16 >> 2] | 0)) {
+        i25 = 0;
+       } else {
+        i25 = HEAP8[i20] | 0;
+       }
+       i24 = i25 & 255;
+       i21 = i11 + -1 | 0;
+       i26 = (HEAP8[i23] | 0) == 94;
+       i28 = i26 ? i23 : i22;
+       i27 = i26 & 1;
+       i26 = i27 ^ 1;
+       i30 = i28 + 1 | 0;
+       L41 : do {
+        if (i30 >>> 0 < i21 >>> 0) {
+         while (1) {
+          i32 = HEAP8[i30] | 0;
+          i29 = i28 + 2 | 0;
+          i31 = HEAP8[i29] | 0;
+          do {
+           if (i32 << 24 >> 24 == 37) {
+            if ((_match_class(i24, i31 & 255) | 0) == 0) {
+             i28 = i29;
+            } else {
+             break L41;
+            }
+           } else {
+            if (i31 << 24 >> 24 == 45 ? (i18 = i28 + 3 | 0, i18 >>> 0 < i21 >>> 0) : 0) {
+             if ((i32 & 255) > (i25 & 255)) {
+              i28 = i18;
+              break;
+             }
+             if ((HEAPU8[i18] | 0) < (i25 & 255)) {
+              i28 = i18;
+              break;
+             } else {
+              break L41;
+             }
+            }
+            if (i32 << 24 >> 24 == i25 << 24 >> 24) {
+             break L41;
+            } else {
+             i28 = i30;
+            }
+           }
+          } while (0);
+          i30 = i28 + 1 | 0;
+          if (!(i30 >>> 0 < i21 >>> 0)) {
+           i26 = i27;
+           break;
+          }
+         }
+        } else {
+         i26 = i27;
+        }
+       } while (0);
+       if ((i26 | 0) != 0) {
+        i12 = 0;
+        break L4;
+       }
+       i24 = HEAP8[i12] | 0;
+       i25 = i24 & 255;
+       i27 = (HEAP8[i23] | 0) == 94;
+       i26 = i27 ? i23 : i22;
+       i22 = i27 & 1;
+       i23 = i22 ^ 1;
+       i30 = i26 + 1 | 0;
+       L55 : do {
+        if (i30 >>> 0 < i21 >>> 0) {
+         do {
+          i29 = HEAP8[i30] | 0;
+          i28 = i26 + 2 | 0;
+          i27 = HEAP8[i28] | 0;
+          do {
+           if (i29 << 24 >> 24 == 37) {
+            if ((_match_class(i25, i27 & 255) | 0) == 0) {
+             i26 = i28;
+            } else {
+             i22 = i23;
+             break L55;
+            }
+           } else {
+            if (i27 << 24 >> 24 == 45 ? (i17 = i26 + 3 | 0, i17 >>> 0 < i21 >>> 0) : 0) {
+             if ((i29 & 255) > (i24 & 255)) {
+              i26 = i17;
+              break;
+             }
+             if ((HEAPU8[i17] | 0) < (i24 & 255)) {
+              i26 = i17;
+              break;
+             } else {
+              i22 = i23;
+              break L55;
+             }
+            }
+            if (i29 << 24 >> 24 == i24 << 24 >> 24) {
+             i22 = i23;
+             break L55;
+            } else {
+             i26 = i30;
+            }
+           }
+          } while (0);
+          i30 = i26 + 1 | 0;
+         } while (i30 >>> 0 < i21 >>> 0);
+        }
+       } while (0);
+       if ((i22 | 0) == 0) {
+        i12 = 0;
+        break L4;
+       }
+      } else if ((i21 | 0) == 40) {
+       i7 = 7;
+       break L6;
+      } else if ((i21 | 0) != 41) {
+       i21 = i11 + 1 | 0;
+       if (i23 << 24 >> 24 == 91) {
+        i7 = (HEAP8[i21] | 0) == 94 ? i11 + 2 | 0 : i21;
+        while (1) {
+         if ((i7 | 0) == (i22 | 0)) {
+          _luaL_error(HEAP32[i9 >> 2] | 0, 7408, i8) | 0;
+         }
+         i22 = i7 + 1 | 0;
+         if ((HEAP8[i7] | 0) == 37) {
+          i7 = i22 >>> 0 < (HEAP32[i14 >> 2] | 0) >>> 0 ? i7 + 2 | 0 : i22;
+         } else {
+          i7 = i22;
+         }
+         if ((HEAP8[i7] | 0) == 93) {
+          break;
+         }
+         i22 = HEAP32[i14 >> 2] | 0;
+        }
+        i22 = i7 + 1 | 0;
+        i7 = 89;
+       } else {
+        i22 = i21;
+        i7 = 89;
+       }
+      } else {
+       i7 = 16;
+       break L6;
+      }
+     } while (0);
+     L80 : do {
+      if ((i7 | 0) == 89) {
+       i7 = 0;
+       do {
+        if ((HEAP32[i3 >> 2] | 0) >>> 0 > i12 >>> 0) {
+         i23 = HEAP8[i12] | 0;
+         i24 = i23 & 255;
+         i26 = HEAP8[i11] | 0;
+         i25 = i26 << 24 >> 24;
+         L85 : do {
+          if ((i25 | 0) == 46) {
+           i23 = HEAP8[i22] | 0;
+          } else if ((i25 | 0) == 37) {
+           i25 = _match_class(i24, HEAPU8[i21] | 0) | 0;
+           i7 = 104;
+          } else if ((i25 | 0) == 91) {
+           i7 = i22 + -1 | 0;
+           i25 = (HEAP8[i21] | 0) == 94;
+           i27 = i25 ? i21 : i11;
+           i26 = i25 & 1;
+           i25 = i26 ^ 1;
+           i30 = i27 + 1 | 0;
+           if (i30 >>> 0 < i7 >>> 0) {
+            while (1) {
+             i31 = HEAP8[i30] | 0;
+             i29 = i27 + 2 | 0;
+             i28 = HEAP8[i29] | 0;
+             do {
+              if (i31 << 24 >> 24 == 37) {
+               if ((_match_class(i24, i28 & 255) | 0) == 0) {
+                i27 = i29;
+               } else {
+                i7 = 104;
+                break L85;
+               }
+              } else {
+               if (i28 << 24 >> 24 == 45 ? (i13 = i27 + 3 | 0, i13 >>> 0 < i7 >>> 0) : 0) {
+                if ((i31 & 255) > (i23 & 255)) {
+                 i27 = i13;
+                 break;
+                }
+                if ((HEAPU8[i13] | 0) < (i23 & 255)) {
+                 i27 = i13;
+                 break;
+                } else {
+                 i7 = 104;
+                 break L85;
+                }
+               }
+               if (i31 << 24 >> 24 == i23 << 24 >> 24) {
+                i7 = 104;
+                break L85;
+               } else {
+                i27 = i30;
+               }
+              }
+             } while (0);
+             i30 = i27 + 1 | 0;
+             if (!(i30 >>> 0 < i7 >>> 0)) {
+              i25 = i26;
+              i7 = 104;
+              break;
+             }
+            }
+           } else {
+            i25 = i26;
+            i7 = 104;
+           }
+          } else {
+           i25 = i26 << 24 >> 24 == i23 << 24 >> 24 | 0;
+           i7 = 104;
+          }
+         } while (0);
+         if ((i7 | 0) == 104) {
+          i7 = 0;
+          i23 = HEAP8[i22] | 0;
+          if ((i25 | 0) == 0) {
+           break;
+          }
+         }
+         i23 = i23 << 24 >> 24;
+         if ((i23 | 0) == 45) {
+          i7 = 109;
+          break L6;
+         } else if ((i23 | 0) == 42) {
+          i7 = 112;
+          break L6;
+         } else if ((i23 | 0) == 43) {
+          break L6;
+         } else if ((i23 | 0) != 63) {
+          i12 = i19;
+          i11 = i22;
+          break L8;
+         }
+         i11 = i22 + 1 | 0;
+         i21 = _match(i1, i19, i11) | 0;
+         if ((i21 | 0) == 0) {
+          break L80;
+         } else {
+          i12 = i21;
+          break L4;
+         }
+        } else {
+         i23 = HEAP8[i22] | 0;
+        }
+       } while (0);
+       if (!(i23 << 24 >> 24 == 45 | i23 << 24 >> 24 == 63 | i23 << 24 >> 24 == 42)) {
+        i12 = 0;
+        break L4;
+       }
+       i11 = i22 + 1 | 0;
+      }
+     } while (0);
+     i22 = HEAP32[i14 >> 2] | 0;
+     if ((i11 | 0) == (i22 | 0)) {
+      break L4;
+     }
+    }
+    if ((i7 | 0) == 25) {
+     i7 = 0;
+     i21 = i11 + 2 | 0;
+     if (!((i22 + -1 | 0) >>> 0 > i21 >>> 0)) {
+      _luaL_error(HEAP32[i9 >> 2] | 0, 7440, i8) | 0;
+     }
+     i20 = HEAP8[i12] | 0;
+     if (!(i20 << 24 >> 24 == (HEAP8[i21] | 0))) {
+      i12 = 0;
+      break L4;
+     }
+     i21 = HEAP8[i11 + 3 | 0] | 0;
+     i22 = HEAP32[i3 >> 2] | 0;
+     if (i19 >>> 0 < i22 >>> 0) {
+      i24 = 1;
+     } else {
+      i12 = 0;
+      break L4;
+     }
+     while (1) {
+      i23 = HEAP8[i19] | 0;
+      if (i23 << 24 >> 24 == i21 << 24 >> 24) {
+       i24 = i24 + -1 | 0;
+       if ((i24 | 0) == 0) {
+        break;
+       }
+      } else {
+       i24 = (i23 << 24 >> 24 == i20 << 24 >> 24) + i24 | 0;
+      }
+      i12 = i19 + 1 | 0;
+      if (i12 >>> 0 < i22 >>> 0) {
+       i32 = i19;
+       i19 = i12;
+       i12 = i32;
+      } else {
+       i12 = 0;
+       break L4;
+      }
+     }
+     i12 = i12 + 2 | 0;
+     i11 = i11 + 4 | 0;
+    } else if ((i7 | 0) == 69) {
+     i7 = 0;
+     i20 = i23 & 255;
+     i19 = i20 + -49 | 0;
+     if (((i19 | 0) >= 0 ? (i19 | 0) < (HEAP32[i10 >> 2] | 0) : 0) ? (i15 = HEAP32[i1 + (i19 << 3) + 28 >> 2] | 0, !((i15 | 0) == -1)) : 0) {
+      i20 = i15;
+     } else {
+      i19 = HEAP32[i9 >> 2] | 0;
+      HEAP32[i8 >> 2] = i20 + -48;
+      i20 = _luaL_error(i19, 7336, i8) | 0;
+      i19 = i20;
+      i20 = HEAP32[i1 + (i20 << 3) + 28 >> 2] | 0;
+     }
+     if (((HEAP32[i3 >> 2] | 0) - i12 | 0) >>> 0 < i20 >>> 0) {
+      i12 = 0;
+      break L4;
+     }
+     if ((_memcmp(HEAP32[i1 + (i19 << 3) + 24 >> 2] | 0, i12, i20) | 0) != 0) {
+      i12 = 0;
+      break L4;
+     }
+     i12 = i12 + i20 | 0;
+     if ((i12 | 0) == 0) {
+      i12 = 0;
+      break L4;
+     }
+     i11 = i11 + 2 | 0;
+    }
+    i22 = HEAP32[i14 >> 2] | 0;
+    if ((i11 | 0) == (i22 | 0)) {
+     break L4;
+    }
+   }
+   if ((i7 | 0) == 7) {
+    i3 = i11 + 1 | 0;
+    if ((HEAP8[i3] | 0) == 41) {
+     i3 = HEAP32[i10 >> 2] | 0;
+     if ((i3 | 0) > 31) {
+      _luaL_error(HEAP32[i9 >> 2] | 0, 7200, i8) | 0;
+     }
+     HEAP32[i1 + (i3 << 3) + 24 >> 2] = i12;
+     HEAP32[i1 + (i3 << 3) + 28 >> 2] = -2;
+     HEAP32[i10 >> 2] = i3 + 1;
+     i12 = _match(i1, i12, i11 + 2 | 0) | 0;
+     if ((i12 | 0) != 0) {
+      break;
+     }
+     HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + -1;
+     i12 = 0;
+     break;
+    } else {
+     i4 = HEAP32[i10 >> 2] | 0;
+     if ((i4 | 0) > 31) {
+      _luaL_error(HEAP32[i9 >> 2] | 0, 7200, i8) | 0;
+     }
+     HEAP32[i1 + (i4 << 3) + 24 >> 2] = i12;
+     HEAP32[i1 + (i4 << 3) + 28 >> 2] = -1;
+     HEAP32[i10 >> 2] = i4 + 1;
+     i12 = _match(i1, i12, i3) | 0;
+     if ((i12 | 0) != 0) {
+      break;
+     }
+     HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + -1;
+     i12 = 0;
+     break;
+    }
+   } else if ((i7 | 0) == 16) {
+    i3 = i11 + 1 | 0;
+    i5 = HEAP32[i10 >> 2] | 0;
+    while (1) {
+     i4 = i5 + -1 | 0;
+     if ((i5 | 0) <= 0) {
+      i7 = 19;
+      break;
+     }
+     if ((HEAP32[i1 + (i4 << 3) + 28 >> 2] | 0) == -1) {
+      break;
+     } else {
+      i5 = i4;
+     }
+    }
+    if ((i7 | 0) == 19) {
+     i4 = _luaL_error(HEAP32[i9 >> 2] | 0, 7488, i8) | 0;
+    }
+    i5 = i1 + (i4 << 3) + 28 | 0;
+    HEAP32[i5 >> 2] = i12 - (HEAP32[i1 + (i4 << 3) + 24 >> 2] | 0);
+    i12 = _match(i1, i12, i3) | 0;
+    if ((i12 | 0) != 0) {
+     break;
+    }
+    HEAP32[i5 >> 2] = -1;
+    i12 = 0;
+    break;
+   } else if ((i7 | 0) == 23) {
+    i12 = (i12 | 0) == (HEAP32[i3 >> 2] | 0) ? i12 : 0;
+    break;
+   } else if ((i7 | 0) == 109) {
+    i4 = i22 + 1 | 0;
+    i8 = _match(i1, i12, i4) | 0;
+    if ((i8 | 0) != 0) {
+     i12 = i8;
+     break;
+    }
+    i8 = i22 + -1 | 0;
+    while (1) {
+     if (!((HEAP32[i3 >> 2] | 0) >>> 0 > i12 >>> 0)) {
+      i12 = 0;
+      break L4;
+     }
+     i9 = HEAP8[i12] | 0;
+     i10 = i9 & 255;
+     i14 = HEAP8[i11] | 0;
+     i13 = i14 << 24 >> 24;
+     L139 : do {
+      if ((i13 | 0) == 91) {
+       i6 = (HEAP8[i21] | 0) == 94;
+       i13 = i6 ? i21 : i11;
+       i6 = i6 & 1;
+       i7 = i6 ^ 1;
+       i14 = i13 + 1 | 0;
+       if (i14 >>> 0 < i8 >>> 0) {
+        while (1) {
+         i17 = HEAP8[i14] | 0;
+         i15 = i13 + 2 | 0;
+         i16 = HEAP8[i15] | 0;
+         do {
+          if (i17 << 24 >> 24 == 37) {
+           if ((_match_class(i10, i16 & 255) | 0) == 0) {
+            i13 = i15;
+           } else {
+            i6 = i7;
+            i7 = 147;
+            break L139;
+           }
+          } else {
+           if (i16 << 24 >> 24 == 45 ? (i5 = i13 + 3 | 0, i5 >>> 0 < i8 >>> 0) : 0) {
+            if ((i17 & 255) > (i9 & 255)) {
+             i13 = i5;
+             break;
+            }
+            if ((HEAPU8[i5] | 0) < (i9 & 255)) {
+             i13 = i5;
+             break;
+            } else {
+             i6 = i7;
+             i7 = 147;
+             break L139;
+            }
+           }
+           if (i17 << 24 >> 24 == i9 << 24 >> 24) {
+            i6 = i7;
+            i7 = 147;
+            break L139;
+           } else {
+            i13 = i14;
+           }
+          }
+         } while (0);
+         i14 = i13 + 1 | 0;
+         if (!(i14 >>> 0 < i8 >>> 0)) {
+          i7 = 147;
+          break;
+         }
+        }
+       } else {
+        i7 = 147;
+       }
+      } else if ((i13 | 0) == 37) {
+       i6 = _match_class(i10, HEAPU8[i21] | 0) | 0;
+       i7 = 147;
+      } else if ((i13 | 0) != 46) {
+       i6 = i14 << 24 >> 24 == i9 << 24 >> 24 | 0;
+       i7 = 147;
+      }
+     } while (0);
+     if ((i7 | 0) == 147 ? (i7 = 0, (i6 | 0) == 0) : 0) {
+      i12 = 0;
+      break L4;
+     }
+     i9 = i12 + 1 | 0;
+     i12 = _match(i1, i9, i4) | 0;
+     if ((i12 | 0) == 0) {
+      i12 = i9;
+     } else {
+      break L4;
+     }
+    }
+   } else if ((i7 | 0) == 112) {
+    i19 = i12;
+   }
+   i10 = HEAP32[i3 >> 2] | 0;
+   if (i10 >>> 0 > i19 >>> 0) {
+    i5 = i22 + -1 | 0;
+    i8 = i19;
+    i6 = 0;
+    do {
+     i8 = HEAP8[i8] | 0;
+     i9 = i8 & 255;
+     i13 = HEAP8[i11] | 0;
+     i12 = i13 << 24 >> 24;
+     L183 : do {
+      if ((i12 | 0) == 37) {
+       i10 = _match_class(i9, HEAPU8[i21] | 0) | 0;
+       i7 = 129;
+      } else if ((i12 | 0) == 91) {
+       i7 = (HEAP8[i21] | 0) == 94;
+       i12 = i7 ? i21 : i11;
+       i10 = i7 & 1;
+       i7 = i10 ^ 1;
+       i13 = i12 + 1 | 0;
+       if (i13 >>> 0 < i5 >>> 0) {
+        while (1) {
+         i14 = HEAP8[i13] | 0;
+         i16 = i12 + 2 | 0;
+         i15 = HEAP8[i16] | 0;
+         do {
+          if (i14 << 24 >> 24 == 37) {
+           if ((_match_class(i9, i15 & 255) | 0) == 0) {
+            i12 = i16;
+           } else {
+            i10 = i7;
+            i7 = 129;
+            break L183;
+           }
+          } else {
+           if (i15 << 24 >> 24 == 45 ? (i4 = i12 + 3 | 0, i4 >>> 0 < i5 >>> 0) : 0) {
+            if ((i14 & 255) > (i8 & 255)) {
+             i12 = i4;
+             break;
+            }
+            if ((HEAPU8[i4] | 0) < (i8 & 255)) {
+             i12 = i4;
+             break;
+            } else {
+             i10 = i7;
+             i7 = 129;
+             break L183;
+            }
+           }
+           if (i14 << 24 >> 24 == i8 << 24 >> 24) {
+            i10 = i7;
+            i7 = 129;
+            break L183;
+           } else {
+            i12 = i13;
+           }
+          }
+         } while (0);
+         i13 = i12 + 1 | 0;
+         if (!(i13 >>> 0 < i5 >>> 0)) {
+          i7 = 129;
+          break;
+         }
+        }
+       } else {
+        i7 = 129;
+       }
+      } else if ((i12 | 0) != 46) {
+       i10 = i13 << 24 >> 24 == i8 << 24 >> 24 | 0;
+       i7 = 129;
+      }
+     } while (0);
+     if ((i7 | 0) == 129) {
+      i7 = 0;
+      if ((i10 | 0) == 0) {
+       break;
+      }
+      i10 = HEAP32[i3 >> 2] | 0;
+     }
+     i6 = i6 + 1 | 0;
+     i8 = i19 + i6 | 0;
+    } while (i10 >>> 0 > i8 >>> 0);
+    if (!((i6 | 0) > -1)) {
+     i12 = 0;
+     break;
+    }
+   } else {
+    i6 = 0;
+   }
+   i3 = i22 + 1 | 0;
+   while (1) {
+    i12 = _match(i1, i19 + i6 | 0, i3) | 0;
+    if ((i12 | 0) != 0) {
+     break L4;
+    }
+    if ((i6 | 0) > 0) {
+     i6 = i6 + -1 | 0;
+    } else {
+     i12 = 0;
+     break;
+    }
+   }
+  }
+ } while (0);
+ HEAP32[i1 >> 2] = (HEAP32[i1 >> 2] | 0) + 1;
+ STACKTOP = i2;
+ return i12 | 0;
+}
+function _free(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i1 = STACKTOP;
+ if ((i7 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i15 = i7 + -8 | 0;
+ i16 = HEAP32[12928 >> 2] | 0;
+ if (i15 >>> 0 < i16 >>> 0) {
+  _abort();
+ }
+ i13 = HEAP32[i7 + -4 >> 2] | 0;
+ i12 = i13 & 3;
+ if ((i12 | 0) == 1) {
+  _abort();
+ }
+ i8 = i13 & -8;
+ i6 = i7 + (i8 + -8) | 0;
+ do {
+  if ((i13 & 1 | 0) == 0) {
+   i19 = HEAP32[i15 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   i15 = -8 - i19 | 0;
+   i13 = i7 + i15 | 0;
+   i12 = i19 + i8 | 0;
+   if (i13 >>> 0 < i16 >>> 0) {
+    _abort();
+   }
+   if ((i13 | 0) == (HEAP32[12932 >> 2] | 0)) {
+    i2 = i7 + (i8 + -4) | 0;
+    if ((HEAP32[i2 >> 2] & 3 | 0) != 3) {
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    HEAP32[12920 >> 2] = i12;
+    HEAP32[i2 >> 2] = HEAP32[i2 >> 2] & -2;
+    HEAP32[i7 + (i15 + 4) >> 2] = i12 | 1;
+    HEAP32[i6 >> 2] = i12;
+    STACKTOP = i1;
+    return;
+   }
+   i18 = i19 >>> 3;
+   if (i19 >>> 0 < 256) {
+    i2 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+    i11 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+    i14 = 12952 + (i18 << 1 << 2) | 0;
+    if ((i2 | 0) != (i14 | 0)) {
+     if (i2 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i2 + 12 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+    }
+    if ((i11 | 0) == (i2 | 0)) {
+     HEAP32[3228] = HEAP32[3228] & ~(1 << i18);
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    if ((i11 | 0) != (i14 | 0)) {
+     if (i11 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i14 = i11 + 8 | 0;
+     if ((HEAP32[i14 >> 2] | 0) == (i13 | 0)) {
+      i17 = i14;
+     } else {
+      _abort();
+     }
+    } else {
+     i17 = i11 + 8 | 0;
+    }
+    HEAP32[i2 + 12 >> 2] = i11;
+    HEAP32[i17 >> 2] = i2;
+    i2 = i13;
+    i11 = i12;
+    break;
+   }
+   i17 = HEAP32[i7 + (i15 + 24) >> 2] | 0;
+   i18 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+   do {
+    if ((i18 | 0) == (i13 | 0)) {
+     i19 = i7 + (i15 + 20) | 0;
+     i18 = HEAP32[i19 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      i19 = i7 + (i15 + 16) | 0;
+      i18 = HEAP32[i19 >> 2] | 0;
+      if ((i18 | 0) == 0) {
+       i14 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i21 = i18 + 20 | 0;
+      i20 = HEAP32[i21 >> 2] | 0;
+      if ((i20 | 0) != 0) {
+       i18 = i20;
+       i19 = i21;
+       continue;
+      }
+      i20 = i18 + 16 | 0;
+      i21 = HEAP32[i20 >> 2] | 0;
+      if ((i21 | 0) == 0) {
+       break;
+      } else {
+       i18 = i21;
+       i19 = i20;
+      }
+     }
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i19 >> 2] = 0;
+      i14 = i18;
+      break;
+     }
+    } else {
+     i19 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i16 = i19 + 12 | 0;
+     if ((HEAP32[i16 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+     i20 = i18 + 8 | 0;
+     if ((HEAP32[i20 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i18;
+      HEAP32[i20 >> 2] = i19;
+      i14 = i18;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i17 | 0) != 0) {
+    i18 = HEAP32[i7 + (i15 + 28) >> 2] | 0;
+    i16 = 13216 + (i18 << 2) | 0;
+    if ((i13 | 0) == (HEAP32[i16 >> 2] | 0)) {
+     HEAP32[i16 >> 2] = i14;
+     if ((i14 | 0) == 0) {
+      HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i18);
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     if (i17 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i16 = i17 + 16 | 0;
+     if ((HEAP32[i16 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i14;
+     } else {
+      HEAP32[i17 + 20 >> 2] = i14;
+     }
+     if ((i14 | 0) == 0) {
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    }
+    if (i14 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i14 + 24 >> 2] = i17;
+    i16 = HEAP32[i7 + (i15 + 16) >> 2] | 0;
+    do {
+     if ((i16 | 0) != 0) {
+      if (i16 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i14 + 16 >> 2] = i16;
+       HEAP32[i16 + 24 >> 2] = i14;
+       break;
+      }
+     }
+    } while (0);
+    i15 = HEAP32[i7 + (i15 + 20) >> 2] | 0;
+    if ((i15 | 0) != 0) {
+     if (i15 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i14 + 20 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i14;
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     i2 = i13;
+     i11 = i12;
+    }
+   } else {
+    i2 = i13;
+    i11 = i12;
+   }
+  } else {
+   i2 = i15;
+   i11 = i8;
+  }
+ } while (0);
+ if (!(i2 >>> 0 < i6 >>> 0)) {
+  _abort();
+ }
+ i12 = i7 + (i8 + -4) | 0;
+ i13 = HEAP32[i12 >> 2] | 0;
+ if ((i13 & 1 | 0) == 0) {
+  _abort();
+ }
+ if ((i13 & 2 | 0) == 0) {
+  if ((i6 | 0) == (HEAP32[12936 >> 2] | 0)) {
+   i21 = (HEAP32[12924 >> 2] | 0) + i11 | 0;
+   HEAP32[12924 >> 2] = i21;
+   HEAP32[12936 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   if ((i2 | 0) != (HEAP32[12932 >> 2] | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[12932 >> 2] = 0;
+   HEAP32[12920 >> 2] = 0;
+   STACKTOP = i1;
+   return;
+  }
+  if ((i6 | 0) == (HEAP32[12932 >> 2] | 0)) {
+   i21 = (HEAP32[12920 >> 2] | 0) + i11 | 0;
+   HEAP32[12920 >> 2] = i21;
+   HEAP32[12932 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   HEAP32[i2 + i21 >> 2] = i21;
+   STACKTOP = i1;
+   return;
+  }
+  i11 = (i13 & -8) + i11 | 0;
+  i12 = i13 >>> 3;
+  do {
+   if (!(i13 >>> 0 < 256)) {
+    i10 = HEAP32[i7 + (i8 + 16) >> 2] | 0;
+    i15 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    do {
+     if ((i15 | 0) == (i6 | 0)) {
+      i13 = i7 + (i8 + 12) | 0;
+      i12 = HEAP32[i13 >> 2] | 0;
+      if ((i12 | 0) == 0) {
+       i13 = i7 + (i8 + 8) | 0;
+       i12 = HEAP32[i13 >> 2] | 0;
+       if ((i12 | 0) == 0) {
+        i9 = 0;
+        break;
+       }
+      }
+      while (1) {
+       i14 = i12 + 20 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) != 0) {
+        i12 = i15;
+        i13 = i14;
+        continue;
+       }
+       i14 = i12 + 16 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) == 0) {
+        break;
+       } else {
+        i12 = i15;
+        i13 = i14;
+       }
+      }
+      if (i13 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 >> 2] = 0;
+       i9 = i12;
+       break;
+      }
+     } else {
+      i13 = HEAP32[i7 + i8 >> 2] | 0;
+      if (i13 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i14 = i13 + 12 | 0;
+      if ((HEAP32[i14 >> 2] | 0) != (i6 | 0)) {
+       _abort();
+      }
+      i12 = i15 + 8 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i14 >> 2] = i15;
+       HEAP32[i12 >> 2] = i13;
+       i9 = i15;
+       break;
+      } else {
+       _abort();
+      }
+     }
+    } while (0);
+    if ((i10 | 0) != 0) {
+     i12 = HEAP32[i7 + (i8 + 20) >> 2] | 0;
+     i13 = 13216 + (i12 << 2) | 0;
+     if ((i6 | 0) == (HEAP32[i13 >> 2] | 0)) {
+      HEAP32[i13 >> 2] = i9;
+      if ((i9 | 0) == 0) {
+       HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i12);
+       break;
+      }
+     } else {
+      if (i10 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i12 = i10 + 16 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i12 >> 2] = i9;
+      } else {
+       HEAP32[i10 + 20 >> 2] = i9;
+      }
+      if ((i9 | 0) == 0) {
+       break;
+      }
+     }
+     if (i9 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     HEAP32[i9 + 24 >> 2] = i10;
+     i6 = HEAP32[i7 + (i8 + 8) >> 2] | 0;
+     do {
+      if ((i6 | 0) != 0) {
+       if (i6 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i9 + 16 >> 2] = i6;
+        HEAP32[i6 + 24 >> 2] = i9;
+        break;
+       }
+      }
+     } while (0);
+     i6 = HEAP32[i7 + (i8 + 12) >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      if (i6 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i9 + 20 >> 2] = i6;
+       HEAP32[i6 + 24 >> 2] = i9;
+       break;
+      }
+     }
+    }
+   } else {
+    i9 = HEAP32[i7 + i8 >> 2] | 0;
+    i7 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    i8 = 12952 + (i12 << 1 << 2) | 0;
+    if ((i9 | 0) != (i8 | 0)) {
+     if (i9 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i9 + 12 >> 2] | 0) != (i6 | 0)) {
+      _abort();
+     }
+    }
+    if ((i7 | 0) == (i9 | 0)) {
+     HEAP32[3228] = HEAP32[3228] & ~(1 << i12);
+     break;
+    }
+    if ((i7 | 0) != (i8 | 0)) {
+     if (i7 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i8 = i7 + 8 | 0;
+     if ((HEAP32[i8 >> 2] | 0) == (i6 | 0)) {
+      i10 = i8;
+     } else {
+      _abort();
+     }
+    } else {
+     i10 = i7 + 8 | 0;
+    }
+    HEAP32[i9 + 12 >> 2] = i7;
+    HEAP32[i10 >> 2] = i9;
+   }
+  } while (0);
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+  if ((i2 | 0) == (HEAP32[12932 >> 2] | 0)) {
+   HEAP32[12920 >> 2] = i11;
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  HEAP32[i12 >> 2] = i13 & -2;
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+ }
+ i6 = i11 >>> 3;
+ if (i11 >>> 0 < 256) {
+  i7 = i6 << 1;
+  i3 = 12952 + (i7 << 2) | 0;
+  i8 = HEAP32[3228] | 0;
+  i6 = 1 << i6;
+  if ((i8 & i6 | 0) != 0) {
+   i6 = 12952 + (i7 + 2 << 2) | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if (i7 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+    _abort();
+   } else {
+    i4 = i6;
+    i5 = i7;
+   }
+  } else {
+   HEAP32[3228] = i8 | i6;
+   i4 = 12952 + (i7 + 2 << 2) | 0;
+   i5 = i3;
+  }
+  HEAP32[i4 >> 2] = i2;
+  HEAP32[i5 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i5;
+  HEAP32[i2 + 12 >> 2] = i3;
+  STACKTOP = i1;
+  return;
+ }
+ i4 = i11 >>> 8;
+ if ((i4 | 0) != 0) {
+  if (i11 >>> 0 > 16777215) {
+   i4 = 31;
+  } else {
+   i20 = (i4 + 1048320 | 0) >>> 16 & 8;
+   i21 = i4 << i20;
+   i19 = (i21 + 520192 | 0) >>> 16 & 4;
+   i21 = i21 << i19;
+   i4 = (i21 + 245760 | 0) >>> 16 & 2;
+   i4 = 14 - (i19 | i20 | i4) + (i21 << i4 >>> 15) | 0;
+   i4 = i11 >>> (i4 + 7 | 0) & 1 | i4 << 1;
+  }
+ } else {
+  i4 = 0;
+ }
+ i5 = 13216 + (i4 << 2) | 0;
+ HEAP32[i2 + 28 >> 2] = i4;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ i7 = HEAP32[12916 >> 2] | 0;
+ i6 = 1 << i4;
+ L199 : do {
+  if ((i7 & i6 | 0) != 0) {
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((i4 | 0) == 31) {
+    i4 = 0;
+   } else {
+    i4 = 25 - (i4 >>> 1) | 0;
+   }
+   L204 : do {
+    if ((HEAP32[i5 + 4 >> 2] & -8 | 0) != (i11 | 0)) {
+     i4 = i11 << i4;
+     i7 = i5;
+     while (1) {
+      i6 = i7 + (i4 >>> 31 << 2) + 16 | 0;
+      i5 = HEAP32[i6 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       break;
+      }
+      if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i11 | 0)) {
+       i3 = i5;
+       break L204;
+      } else {
+       i4 = i4 << 1;
+       i7 = i5;
+      }
+     }
+     if (i6 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i6 >> 2] = i2;
+      HEAP32[i2 + 24 >> 2] = i7;
+      HEAP32[i2 + 12 >> 2] = i2;
+      HEAP32[i2 + 8 >> 2] = i2;
+      break L199;
+     }
+    } else {
+     i3 = i5;
+    }
+   } while (0);
+   i5 = i3 + 8 | 0;
+   i4 = HEAP32[i5 >> 2] | 0;
+   i6 = HEAP32[12928 >> 2] | 0;
+   if (i3 >>> 0 < i6 >>> 0) {
+    _abort();
+   }
+   if (i4 >>> 0 < i6 >>> 0) {
+    _abort();
+   } else {
+    HEAP32[i4 + 12 >> 2] = i2;
+    HEAP32[i5 >> 2] = i2;
+    HEAP32[i2 + 8 >> 2] = i4;
+    HEAP32[i2 + 12 >> 2] = i3;
+    HEAP32[i2 + 24 >> 2] = 0;
+    break;
+   }
+  } else {
+   HEAP32[12916 >> 2] = i7 | i6;
+   HEAP32[i5 >> 2] = i2;
+   HEAP32[i2 + 24 >> 2] = i5;
+   HEAP32[i2 + 12 >> 2] = i2;
+   HEAP32[i2 + 8 >> 2] = i2;
+  }
+ } while (0);
+ i21 = (HEAP32[12944 >> 2] | 0) + -1 | 0;
+ HEAP32[12944 >> 2] = i21;
+ if ((i21 | 0) == 0) {
+  i2 = 13368 | 0;
+ } else {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i2 = HEAP32[i2 >> 2] | 0;
+  if ((i2 | 0) == 0) {
+   break;
+  } else {
+   i2 = i2 + 8 | 0;
+  }
+ }
+ HEAP32[12944 >> 2] = -1;
+ STACKTOP = i1;
+ return;
+}
+function _dispose_chunk(i6, i7) {
+ i6 = i6 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0;
+ i1 = STACKTOP;
+ i5 = i6 + i7 | 0;
+ i10 = HEAP32[i6 + 4 >> 2] | 0;
+ do {
+  if ((i10 & 1 | 0) == 0) {
+   i14 = HEAP32[i6 >> 2] | 0;
+   if ((i10 & 3 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   i10 = i6 + (0 - i14) | 0;
+   i11 = i14 + i7 | 0;
+   i15 = HEAP32[12928 >> 2] | 0;
+   if (i10 >>> 0 < i15 >>> 0) {
+    _abort();
+   }
+   if ((i10 | 0) == (HEAP32[12932 >> 2] | 0)) {
+    i2 = i6 + (i7 + 4) | 0;
+    if ((HEAP32[i2 >> 2] & 3 | 0) != 3) {
+     i2 = i10;
+     i12 = i11;
+     break;
+    }
+    HEAP32[12920 >> 2] = i11;
+    HEAP32[i2 >> 2] = HEAP32[i2 >> 2] & -2;
+    HEAP32[i6 + (4 - i14) >> 2] = i11 | 1;
+    HEAP32[i5 >> 2] = i11;
+    STACKTOP = i1;
+    return;
+   }
+   i17 = i14 >>> 3;
+   if (i14 >>> 0 < 256) {
+    i2 = HEAP32[i6 + (8 - i14) >> 2] | 0;
+    i12 = HEAP32[i6 + (12 - i14) >> 2] | 0;
+    i13 = 12952 + (i17 << 1 << 2) | 0;
+    if ((i2 | 0) != (i13 | 0)) {
+     if (i2 >>> 0 < i15 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i2 + 12 >> 2] | 0) != (i10 | 0)) {
+      _abort();
+     }
+    }
+    if ((i12 | 0) == (i2 | 0)) {
+     HEAP32[3228] = HEAP32[3228] & ~(1 << i17);
+     i2 = i10;
+     i12 = i11;
+     break;
+    }
+    if ((i12 | 0) != (i13 | 0)) {
+     if (i12 >>> 0 < i15 >>> 0) {
+      _abort();
+     }
+     i13 = i12 + 8 | 0;
+     if ((HEAP32[i13 >> 2] | 0) == (i10 | 0)) {
+      i16 = i13;
+     } else {
+      _abort();
+     }
+    } else {
+     i16 = i12 + 8 | 0;
+    }
+    HEAP32[i2 + 12 >> 2] = i12;
+    HEAP32[i16 >> 2] = i2;
+    i2 = i10;
+    i12 = i11;
+    break;
+   }
+   i16 = HEAP32[i6 + (24 - i14) >> 2] | 0;
+   i18 = HEAP32[i6 + (12 - i14) >> 2] | 0;
+   do {
+    if ((i18 | 0) == (i10 | 0)) {
+     i19 = 16 - i14 | 0;
+     i18 = i6 + (i19 + 4) | 0;
+     i17 = HEAP32[i18 >> 2] | 0;
+     if ((i17 | 0) == 0) {
+      i18 = i6 + i19 | 0;
+      i17 = HEAP32[i18 >> 2] | 0;
+      if ((i17 | 0) == 0) {
+       i13 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i19 = i17 + 20 | 0;
+      i20 = HEAP32[i19 >> 2] | 0;
+      if ((i20 | 0) != 0) {
+       i17 = i20;
+       i18 = i19;
+       continue;
+      }
+      i20 = i17 + 16 | 0;
+      i19 = HEAP32[i20 >> 2] | 0;
+      if ((i19 | 0) == 0) {
+       break;
+      } else {
+       i17 = i19;
+       i18 = i20;
+      }
+     }
+     if (i18 >>> 0 < i15 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i18 >> 2] = 0;
+      i13 = i17;
+      break;
+     }
+    } else {
+     i17 = HEAP32[i6 + (8 - i14) >> 2] | 0;
+     if (i17 >>> 0 < i15 >>> 0) {
+      _abort();
+     }
+     i19 = i17 + 12 | 0;
+     if ((HEAP32[i19 >> 2] | 0) != (i10 | 0)) {
+      _abort();
+     }
+     i15 = i18 + 8 | 0;
+     if ((HEAP32[i15 >> 2] | 0) == (i10 | 0)) {
+      HEAP32[i19 >> 2] = i18;
+      HEAP32[i15 >> 2] = i17;
+      i13 = i18;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i16 | 0) != 0) {
+    i15 = HEAP32[i6 + (28 - i14) >> 2] | 0;
+    i17 = 13216 + (i15 << 2) | 0;
+    if ((i10 | 0) == (HEAP32[i17 >> 2] | 0)) {
+     HEAP32[i17 >> 2] = i13;
+     if ((i13 | 0) == 0) {
+      HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i15);
+      i2 = i10;
+      i12 = i11;
+      break;
+     }
+    } else {
+     if (i16 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i15 = i16 + 16 | 0;
+     if ((HEAP32[i15 >> 2] | 0) == (i10 | 0)) {
+      HEAP32[i15 >> 2] = i13;
+     } else {
+      HEAP32[i16 + 20 >> 2] = i13;
+     }
+     if ((i13 | 0) == 0) {
+      i2 = i10;
+      i12 = i11;
+      break;
+     }
+    }
+    if (i13 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i13 + 24 >> 2] = i16;
+    i14 = 16 - i14 | 0;
+    i15 = HEAP32[i6 + i14 >> 2] | 0;
+    do {
+     if ((i15 | 0) != 0) {
+      if (i15 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 + 16 >> 2] = i15;
+       HEAP32[i15 + 24 >> 2] = i13;
+       break;
+      }
+     }
+    } while (0);
+    i14 = HEAP32[i6 + (i14 + 4) >> 2] | 0;
+    if ((i14 | 0) != 0) {
+     if (i14 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i13 + 20 >> 2] = i14;
+      HEAP32[i14 + 24 >> 2] = i13;
+      i2 = i10;
+      i12 = i11;
+      break;
+     }
+    } else {
+     i2 = i10;
+     i12 = i11;
+    }
+   } else {
+    i2 = i10;
+    i12 = i11;
+   }
+  } else {
+   i2 = i6;
+   i12 = i7;
+  }
+ } while (0);
+ i10 = HEAP32[12928 >> 2] | 0;
+ if (i5 >>> 0 < i10 >>> 0) {
+  _abort();
+ }
+ i11 = i6 + (i7 + 4) | 0;
+ i13 = HEAP32[i11 >> 2] | 0;
+ if ((i13 & 2 | 0) == 0) {
+  if ((i5 | 0) == (HEAP32[12936 >> 2] | 0)) {
+   i20 = (HEAP32[12924 >> 2] | 0) + i12 | 0;
+   HEAP32[12924 >> 2] = i20;
+   HEAP32[12936 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i20 | 1;
+   if ((i2 | 0) != (HEAP32[12932 >> 2] | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[12932 >> 2] = 0;
+   HEAP32[12920 >> 2] = 0;
+   STACKTOP = i1;
+   return;
+  }
+  if ((i5 | 0) == (HEAP32[12932 >> 2] | 0)) {
+   i20 = (HEAP32[12920 >> 2] | 0) + i12 | 0;
+   HEAP32[12920 >> 2] = i20;
+   HEAP32[12932 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i20 | 1;
+   HEAP32[i2 + i20 >> 2] = i20;
+   STACKTOP = i1;
+   return;
+  }
+  i12 = (i13 & -8) + i12 | 0;
+  i11 = i13 >>> 3;
+  do {
+   if (!(i13 >>> 0 < 256)) {
+    i9 = HEAP32[i6 + (i7 + 24) >> 2] | 0;
+    i11 = HEAP32[i6 + (i7 + 12) >> 2] | 0;
+    do {
+     if ((i11 | 0) == (i5 | 0)) {
+      i13 = i6 + (i7 + 20) | 0;
+      i11 = HEAP32[i13 >> 2] | 0;
+      if ((i11 | 0) == 0) {
+       i13 = i6 + (i7 + 16) | 0;
+       i11 = HEAP32[i13 >> 2] | 0;
+       if ((i11 | 0) == 0) {
+        i8 = 0;
+        break;
+       }
+      }
+      while (1) {
+       i15 = i11 + 20 | 0;
+       i14 = HEAP32[i15 >> 2] | 0;
+       if ((i14 | 0) != 0) {
+        i11 = i14;
+        i13 = i15;
+        continue;
+       }
+       i14 = i11 + 16 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) == 0) {
+        break;
+       } else {
+        i11 = i15;
+        i13 = i14;
+       }
+      }
+      if (i13 >>> 0 < i10 >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 >> 2] = 0;
+       i8 = i11;
+       break;
+      }
+     } else {
+      i13 = HEAP32[i6 + (i7 + 8) >> 2] | 0;
+      if (i13 >>> 0 < i10 >>> 0) {
+       _abort();
+      }
+      i10 = i13 + 12 | 0;
+      if ((HEAP32[i10 >> 2] | 0) != (i5 | 0)) {
+       _abort();
+      }
+      i14 = i11 + 8 | 0;
+      if ((HEAP32[i14 >> 2] | 0) == (i5 | 0)) {
+       HEAP32[i10 >> 2] = i11;
+       HEAP32[i14 >> 2] = i13;
+       i8 = i11;
+       break;
+      } else {
+       _abort();
+      }
+     }
+    } while (0);
+    if ((i9 | 0) != 0) {
+     i10 = HEAP32[i6 + (i7 + 28) >> 2] | 0;
+     i11 = 13216 + (i10 << 2) | 0;
+     if ((i5 | 0) == (HEAP32[i11 >> 2] | 0)) {
+      HEAP32[i11 >> 2] = i8;
+      if ((i8 | 0) == 0) {
+       HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i10);
+       break;
+      }
+     } else {
+      if (i9 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i10 = i9 + 16 | 0;
+      if ((HEAP32[i10 >> 2] | 0) == (i5 | 0)) {
+       HEAP32[i10 >> 2] = i8;
+      } else {
+       HEAP32[i9 + 20 >> 2] = i8;
+      }
+      if ((i8 | 0) == 0) {
+       break;
+      }
+     }
+     if (i8 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     HEAP32[i8 + 24 >> 2] = i9;
+     i5 = HEAP32[i6 + (i7 + 16) >> 2] | 0;
+     do {
+      if ((i5 | 0) != 0) {
+       if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i8 + 16 >> 2] = i5;
+        HEAP32[i5 + 24 >> 2] = i8;
+        break;
+       }
+      }
+     } while (0);
+     i5 = HEAP32[i6 + (i7 + 20) >> 2] | 0;
+     if ((i5 | 0) != 0) {
+      if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i8 + 20 >> 2] = i5;
+       HEAP32[i5 + 24 >> 2] = i8;
+       break;
+      }
+     }
+    }
+   } else {
+    i8 = HEAP32[i6 + (i7 + 8) >> 2] | 0;
+    i6 = HEAP32[i6 + (i7 + 12) >> 2] | 0;
+    i7 = 12952 + (i11 << 1 << 2) | 0;
+    if ((i8 | 0) != (i7 | 0)) {
+     if (i8 >>> 0 < i10 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i8 + 12 >> 2] | 0) != (i5 | 0)) {
+      _abort();
+     }
+    }
+    if ((i6 | 0) == (i8 | 0)) {
+     HEAP32[3228] = HEAP32[3228] & ~(1 << i11);
+     break;
+    }
+    if ((i6 | 0) != (i7 | 0)) {
+     if (i6 >>> 0 < i10 >>> 0) {
+      _abort();
+     }
+     i7 = i6 + 8 | 0;
+     if ((HEAP32[i7 >> 2] | 0) == (i5 | 0)) {
+      i9 = i7;
+     } else {
+      _abort();
+     }
+    } else {
+     i9 = i6 + 8 | 0;
+    }
+    HEAP32[i8 + 12 >> 2] = i6;
+    HEAP32[i9 >> 2] = i8;
+   }
+  } while (0);
+  HEAP32[i2 + 4 >> 2] = i12 | 1;
+  HEAP32[i2 + i12 >> 2] = i12;
+  if ((i2 | 0) == (HEAP32[12932 >> 2] | 0)) {
+   HEAP32[12920 >> 2] = i12;
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  HEAP32[i11 >> 2] = i13 & -2;
+  HEAP32[i2 + 4 >> 2] = i12 | 1;
+  HEAP32[i2 + i12 >> 2] = i12;
+ }
+ i6 = i12 >>> 3;
+ if (i12 >>> 0 < 256) {
+  i7 = i6 << 1;
+  i5 = 12952 + (i7 << 2) | 0;
+  i8 = HEAP32[3228] | 0;
+  i6 = 1 << i6;
+  if ((i8 & i6 | 0) != 0) {
+   i7 = 12952 + (i7 + 2 << 2) | 0;
+   i6 = HEAP32[i7 >> 2] | 0;
+   if (i6 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+    _abort();
+   } else {
+    i4 = i7;
+    i3 = i6;
+   }
+  } else {
+   HEAP32[3228] = i8 | i6;
+   i4 = 12952 + (i7 + 2 << 2) | 0;
+   i3 = i5;
+  }
+  HEAP32[i4 >> 2] = i2;
+  HEAP32[i3 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i3;
+  HEAP32[i2 + 12 >> 2] = i5;
+  STACKTOP = i1;
+  return;
+ }
+ i3 = i12 >>> 8;
+ if ((i3 | 0) != 0) {
+  if (i12 >>> 0 > 16777215) {
+   i3 = 31;
+  } else {
+   i19 = (i3 + 1048320 | 0) >>> 16 & 8;
+   i20 = i3 << i19;
+   i18 = (i20 + 520192 | 0) >>> 16 & 4;
+   i20 = i20 << i18;
+   i3 = (i20 + 245760 | 0) >>> 16 & 2;
+   i3 = 14 - (i18 | i19 | i3) + (i20 << i3 >>> 15) | 0;
+   i3 = i12 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+  }
+ } else {
+  i3 = 0;
+ }
+ i6 = 13216 + (i3 << 2) | 0;
+ HEAP32[i2 + 28 >> 2] = i3;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ i5 = HEAP32[12916 >> 2] | 0;
+ i4 = 1 << i3;
+ if ((i5 & i4 | 0) == 0) {
+  HEAP32[12916 >> 2] = i5 | i4;
+  HEAP32[i6 >> 2] = i2;
+  HEAP32[i2 + 24 >> 2] = i6;
+  HEAP32[i2 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i2;
+  STACKTOP = i1;
+  return;
+ }
+ i4 = HEAP32[i6 >> 2] | 0;
+ if ((i3 | 0) == 31) {
+  i3 = 0;
+ } else {
+  i3 = 25 - (i3 >>> 1) | 0;
+ }
+ L194 : do {
+  if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i12 | 0)) {
+   i3 = i12 << i3;
+   i6 = i4;
+   while (1) {
+    i5 = i6 + (i3 >>> 31 << 2) + 16 | 0;
+    i4 = HEAP32[i5 >> 2] | 0;
+    if ((i4 | 0) == 0) {
+     break;
+    }
+    if ((HEAP32[i4 + 4 >> 2] & -8 | 0) == (i12 | 0)) {
+     break L194;
+    } else {
+     i3 = i3 << 1;
+     i6 = i4;
+    }
+   }
+   if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+    _abort();
+   }
+   HEAP32[i5 >> 2] = i2;
+   HEAP32[i2 + 24 >> 2] = i6;
+   HEAP32[i2 + 12 >> 2] = i2;
+   HEAP32[i2 + 8 >> 2] = i2;
+   STACKTOP = i1;
+   return;
+  }
+ } while (0);
+ i3 = i4 + 8 | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ i5 = HEAP32[12928 >> 2] | 0;
+ if (i4 >>> 0 < i5 >>> 0) {
+  _abort();
+ }
+ if (i6 >>> 0 < i5 >>> 0) {
+  _abort();
+ }
+ HEAP32[i6 + 12 >> 2] = i2;
+ HEAP32[i3 >> 2] = i2;
+ HEAP32[i2 + 8 >> 2] = i6;
+ HEAP32[i2 + 12 >> 2] = i4;
+ HEAP32[i2 + 24 >> 2] = 0;
+ STACKTOP = i1;
+ return;
+}
+function _singlestep(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i14 = i1;
+ i3 = i2 + 12 | 0;
+ i8 = HEAP32[i3 >> 2] | 0;
+ i6 = i8 + 61 | 0;
+ switch (HEAPU8[i6] | 0) {
+ case 0:
+  {
+   if ((HEAP32[i8 + 84 >> 2] | 0) != 0) {
+    i21 = i8 + 16 | 0;
+    i22 = HEAP32[i21 >> 2] | 0;
+    _propagatemark(i8);
+    i22 = (HEAP32[i21 >> 2] | 0) - i22 | 0;
+    STACKTOP = i1;
+    return i22 | 0;
+   }
+   HEAP8[i6] = 1;
+   i6 = i8 + 20 | 0;
+   HEAP32[i6 >> 2] = HEAP32[i8 + 16 >> 2];
+   i8 = HEAP32[i3 >> 2] | 0;
+   i7 = i8 + 16 | 0;
+   i14 = HEAP32[i7 >> 2] | 0;
+   if ((i2 | 0) != 0 ? !((HEAP8[i2 + 5 | 0] & 3) == 0) : 0) {
+    _reallymarkobject(i8, i2);
+   }
+   if ((HEAP32[i8 + 48 >> 2] & 64 | 0) != 0 ? (i13 = HEAP32[i8 + 40 >> 2] | 0, !((HEAP8[i13 + 5 | 0] & 3) == 0)) : 0) {
+    _reallymarkobject(i8, i13);
+   }
+   _markmt(i8);
+   i13 = i8 + 112 | 0;
+   i15 = HEAP32[i8 + 132 >> 2] | 0;
+   if ((i15 | 0) != (i13 | 0)) {
+    do {
+     if (((HEAP8[i15 + 5 | 0] & 7) == 0 ? (i12 = HEAP32[i15 + 8 >> 2] | 0, (HEAP32[i12 + 8 >> 2] & 64 | 0) != 0) : 0) ? (i11 = HEAP32[i12 >> 2] | 0, !((HEAP8[i11 + 5 | 0] & 3) == 0)) : 0) {
+      _reallymarkobject(i8, i11);
+     }
+     i15 = HEAP32[i15 + 20 >> 2] | 0;
+    } while ((i15 | 0) != (i13 | 0));
+   }
+   i16 = i8 + 84 | 0;
+   if ((HEAP32[i16 >> 2] | 0) != 0) {
+    do {
+     _propagatemark(i8);
+    } while ((HEAP32[i16 >> 2] | 0) != 0);
+   }
+   i17 = (HEAP32[i7 >> 2] | 0) - i14 | 0;
+   i11 = i8 + 92 | 0;
+   i12 = HEAP32[i11 >> 2] | 0;
+   i21 = i8 + 88 | 0;
+   i22 = HEAP32[i21 >> 2] | 0;
+   i15 = i8 + 96 | 0;
+   i13 = HEAP32[i15 >> 2] | 0;
+   HEAP32[i15 >> 2] = 0;
+   HEAP32[i21 >> 2] = 0;
+   HEAP32[i11 >> 2] = 0;
+   HEAP32[i16 >> 2] = i22;
+   if ((i22 | 0) != 0) {
+    do {
+     _propagatemark(i8);
+    } while ((HEAP32[i16 >> 2] | 0) != 0);
+   }
+   HEAP32[i16 >> 2] = i12;
+   if ((i12 | 0) != 0) {
+    do {
+     _propagatemark(i8);
+    } while ((HEAP32[i16 >> 2] | 0) != 0);
+   }
+   HEAP32[i16 >> 2] = i13;
+   if ((i13 | 0) != 0) {
+    do {
+     _propagatemark(i8);
+    } while ((HEAP32[i16 >> 2] | 0) != 0);
+   }
+   i18 = HEAP32[i7 >> 2] | 0;
+   while (1) {
+    i13 = HEAP32[i15 >> 2] | 0;
+    HEAP32[i15 >> 2] = 0;
+    i12 = 0;
+    L42 : while (1) {
+     i14 = i13;
+     while (1) {
+      if ((i14 | 0) == 0) {
+       break L42;
+      }
+      i13 = HEAP32[i14 + 24 >> 2] | 0;
+      if ((_traverseephemeron(i8, i14) | 0) == 0) {
+       i14 = i13;
+      } else {
+       break;
+      }
+     }
+     if ((HEAP32[i16 >> 2] | 0) == 0) {
+      i12 = 1;
+      continue;
+     }
+     while (1) {
+      _propagatemark(i8);
+      if ((HEAP32[i16 >> 2] | 0) == 0) {
+       i12 = 1;
+       continue L42;
+      }
+     }
+    }
+    if ((i12 | 0) == 0) {
+     break;
+    }
+   }
+   _clearvalues(i8, HEAP32[i11 >> 2] | 0, 0);
+   i14 = i8 + 100 | 0;
+   _clearvalues(i8, HEAP32[i14 >> 2] | 0, 0);
+   i13 = HEAP32[i11 >> 2] | 0;
+   i12 = HEAP32[i14 >> 2] | 0;
+   i21 = HEAP32[i7 >> 2] | 0;
+   i20 = HEAP32[i3 >> 2] | 0;
+   i19 = i20 + 104 | 0;
+   while (1) {
+    i22 = HEAP32[i19 >> 2] | 0;
+    if ((i22 | 0) == 0) {
+     break;
+    } else {
+     i19 = i22;
+    }
+   }
+   i17 = i17 - i18 + i21 | 0;
+   i20 = i20 + 72 | 0;
+   i21 = HEAP32[i20 >> 2] | 0;
+   L55 : do {
+    if ((i21 | 0) != 0) {
+     while (1) {
+      i18 = i21;
+      while (1) {
+       i22 = i18 + 5 | 0;
+       i21 = HEAP8[i22] | 0;
+       if ((i21 & 3) == 0) {
+        break;
+       }
+       HEAP8[i22] = i21 & 255 | 8;
+       HEAP32[i20 >> 2] = HEAP32[i18 >> 2];
+       HEAP32[i18 >> 2] = HEAP32[i19 >> 2];
+       HEAP32[i19 >> 2] = i18;
+       i19 = HEAP32[i20 >> 2] | 0;
+       if ((i19 | 0) == 0) {
+        break L55;
+       } else {
+        i22 = i18;
+        i18 = i19;
+        i19 = i22;
+       }
+      }
+      i21 = HEAP32[i18 >> 2] | 0;
+      if ((i21 | 0) == 0) {
+       break;
+      } else {
+       i20 = i18;
+      }
+     }
+    }
+   } while (0);
+   i19 = HEAP32[i8 + 104 >> 2] | 0;
+   if ((i19 | 0) != 0) {
+    i18 = i8 + 60 | 0;
+    do {
+     i22 = i19 + 5 | 0;
+     HEAP8[i22] = HEAP8[i18] & 3 | HEAP8[i22] & 184;
+     _reallymarkobject(i8, i19);
+     i19 = HEAP32[i19 >> 2] | 0;
+    } while ((i19 | 0) != 0);
+   }
+   if ((HEAP32[i16 >> 2] | 0) != 0) {
+    do {
+     _propagatemark(i8);
+    } while ((HEAP32[i16 >> 2] | 0) != 0);
+   }
+   i18 = HEAP32[i7 >> 2] | 0;
+   while (1) {
+    i20 = HEAP32[i15 >> 2] | 0;
+    HEAP32[i15 >> 2] = 0;
+    i19 = 0;
+    L74 : while (1) {
+     i21 = i20;
+     while (1) {
+      if ((i21 | 0) == 0) {
+       break L74;
+      }
+      i20 = HEAP32[i21 + 24 >> 2] | 0;
+      if ((_traverseephemeron(i8, i21) | 0) == 0) {
+       i21 = i20;
+      } else {
+       break;
+      }
+     }
+     if ((HEAP32[i16 >> 2] | 0) == 0) {
+      i19 = 1;
+      continue;
+     }
+     while (1) {
+      _propagatemark(i8);
+      if ((HEAP32[i16 >> 2] | 0) == 0) {
+       i19 = 1;
+       continue L74;
+      }
+     }
+    }
+    if ((i19 | 0) == 0) {
+     break;
+    }
+   }
+   i16 = i17 - i18 | 0;
+   i15 = HEAP32[i15 >> 2] | 0;
+   if ((i15 | 0) != 0) {
+    do {
+     i22 = 1 << HEAPU8[i15 + 7 | 0];
+     i19 = HEAP32[i15 + 16 >> 2] | 0;
+     i17 = i19 + (i22 << 5) | 0;
+     if ((i22 | 0) > 0) {
+      do {
+       i18 = i19 + 8 | 0;
+       do {
+        if ((HEAP32[i18 >> 2] | 0) != 0 ? (i9 = i19 + 24 | 0, i10 = HEAP32[i9 >> 2] | 0, (i10 & 64 | 0) != 0) : 0) {
+         i20 = HEAP32[i19 + 16 >> 2] | 0;
+         if ((i10 & 15 | 0) == 4) {
+          if ((i20 | 0) == 0) {
+           break;
+          }
+          if ((HEAP8[i20 + 5 | 0] & 3) == 0) {
+           break;
+          }
+          _reallymarkobject(i8, i20);
+          break;
+         } else {
+          i20 = i20 + 5 | 0;
+          if ((HEAP8[i20] & 3) == 0) {
+           break;
+          }
+          HEAP32[i18 >> 2] = 0;
+          if ((HEAP8[i20] & 3) == 0) {
+           break;
+          }
+          HEAP32[i9 >> 2] = 11;
+          break;
+         }
+        }
+       } while (0);
+       i19 = i19 + 32 | 0;
+      } while (i19 >>> 0 < i17 >>> 0);
+     }
+     i15 = HEAP32[i15 + 24 >> 2] | 0;
+    } while ((i15 | 0) != 0);
+   }
+   i10 = HEAP32[i14 >> 2] | 0;
+   if ((i10 | 0) != 0) {
+    do {
+     i22 = 1 << HEAPU8[i10 + 7 | 0];
+     i17 = HEAP32[i10 + 16 >> 2] | 0;
+     i9 = i17 + (i22 << 5) | 0;
+     if ((i22 | 0) > 0) {
+      do {
+       i15 = i17 + 8 | 0;
+       do {
+        if ((HEAP32[i15 >> 2] | 0) != 0 ? (i5 = i17 + 24 | 0, i4 = HEAP32[i5 >> 2] | 0, (i4 & 64 | 0) != 0) : 0) {
+         i18 = HEAP32[i17 + 16 >> 2] | 0;
+         if ((i4 & 15 | 0) == 4) {
+          if ((i18 | 0) == 0) {
+           break;
+          }
+          if ((HEAP8[i18 + 5 | 0] & 3) == 0) {
+           break;
+          }
+          _reallymarkobject(i8, i18);
+          break;
+         } else {
+          i18 = i18 + 5 | 0;
+          if ((HEAP8[i18] & 3) == 0) {
+           break;
+          }
+          HEAP32[i15 >> 2] = 0;
+          if ((HEAP8[i18] & 3) == 0) {
+           break;
+          }
+          HEAP32[i5 >> 2] = 11;
+          break;
+         }
+        }
+       } while (0);
+       i17 = i17 + 32 | 0;
+      } while (i17 >>> 0 < i9 >>> 0);
+     }
+     i10 = HEAP32[i10 + 24 >> 2] | 0;
+    } while ((i10 | 0) != 0);
+   }
+   _clearvalues(i8, HEAP32[i11 >> 2] | 0, i13);
+   _clearvalues(i8, HEAP32[i14 >> 2] | 0, i12);
+   i4 = i8 + 60 | 0;
+   HEAP8[i4] = HEAPU8[i4] ^ 3;
+   i4 = i16 + (HEAP32[i7 >> 2] | 0) | 0;
+   HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i4;
+   i3 = HEAP32[i3 >> 2] | 0;
+   HEAP8[i3 + 61 | 0] = 2;
+   HEAP32[i3 + 64 >> 2] = 0;
+   i7 = i3 + 72 | 0;
+   i5 = 0;
+   do {
+    i5 = i5 + 1 | 0;
+    i6 = _sweeplist(i2, i7, 1) | 0;
+   } while ((i6 | 0) == (i7 | 0));
+   HEAP32[i3 + 80 >> 2] = i6;
+   i6 = i3 + 68 | 0;
+   i7 = 0;
+   do {
+    i7 = i7 + 1 | 0;
+    i8 = _sweeplist(i2, i6, 1) | 0;
+   } while ((i8 | 0) == (i6 | 0));
+   HEAP32[i3 + 76 >> 2] = i8;
+   i22 = ((i7 + i5 | 0) * 5 | 0) + i4 | 0;
+   STACKTOP = i1;
+   return i22 | 0;
+  }
+ case 2:
+  {
+   i3 = i8 + 64 | 0;
+   i4 = i8 + 32 | 0;
+   i8 = i8 + 24 | 0;
+   i5 = 0;
+   while (1) {
+    i10 = HEAP32[i3 >> 2] | 0;
+    i11 = i10 + i5 | 0;
+    i9 = HEAP32[i4 >> 2] | 0;
+    if ((i11 | 0) >= (i9 | 0)) {
+     i2 = i10;
+     break;
+    }
+    _sweeplist(i2, (HEAP32[i8 >> 2] | 0) + (i11 << 2) | 0, -3) | 0;
+    i5 = i5 + 1 | 0;
+    if ((i5 | 0) >= 80) {
+     i7 = 96;
+     break;
+    }
+   }
+   if ((i7 | 0) == 96) {
+    i2 = HEAP32[i3 >> 2] | 0;
+    i9 = HEAP32[i4 >> 2] | 0;
+   }
+   i22 = i2 + i5 | 0;
+   HEAP32[i3 >> 2] = i22;
+   if ((i22 | 0) >= (i9 | 0)) {
+    HEAP8[i6] = 3;
+   }
+   i22 = i5 * 5 | 0;
+   STACKTOP = i1;
+   return i22 | 0;
+  }
+ case 5:
+  {
+   i2 = i8 + 16 | 0;
+   HEAP32[i2 >> 2] = HEAP32[i8 + 32 >> 2] << 2;
+   i22 = i8 + 84 | 0;
+   i3 = i8 + 172 | 0;
+   HEAP32[i22 + 0 >> 2] = 0;
+   HEAP32[i22 + 4 >> 2] = 0;
+   HEAP32[i22 + 8 >> 2] = 0;
+   HEAP32[i22 + 12 >> 2] = 0;
+   HEAP32[i22 + 16 >> 2] = 0;
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+    _reallymarkobject(i8, i3);
+   }
+   if ((HEAP32[i8 + 48 >> 2] & 64 | 0) != 0 ? (i15 = HEAP32[i8 + 40 >> 2] | 0, !((HEAP8[i15 + 5 | 0] & 3) == 0)) : 0) {
+    _reallymarkobject(i8, i15);
+   }
+   _markmt(i8);
+   i4 = HEAP32[i8 + 104 >> 2] | 0;
+   if ((i4 | 0) != 0) {
+    i3 = i8 + 60 | 0;
+    do {
+     i22 = i4 + 5 | 0;
+     HEAP8[i22] = HEAP8[i3] & 3 | HEAP8[i22] & 184;
+     _reallymarkobject(i8, i4);
+     i4 = HEAP32[i4 >> 2] | 0;
+    } while ((i4 | 0) != 0);
+   }
+   HEAP8[i6] = 0;
+   i22 = HEAP32[i2 >> 2] | 0;
+   STACKTOP = i1;
+   return i22 | 0;
+  }
+ case 3:
+  {
+   i3 = i8 + 80 | 0;
+   i4 = HEAP32[i3 >> 2] | 0;
+   if ((i4 | 0) == 0) {
+    HEAP8[i6] = 4;
+    i22 = 0;
+    STACKTOP = i1;
+    return i22 | 0;
+   } else {
+    HEAP32[i3 >> 2] = _sweeplist(i2, i4, 80) | 0;
+    i22 = 400;
+    STACKTOP = i1;
+    return i22 | 0;
+   }
+  }
+ case 4:
+  {
+   i4 = i8 + 76 | 0;
+   i5 = HEAP32[i4 >> 2] | 0;
+   if ((i5 | 0) != 0) {
+    HEAP32[i4 >> 2] = _sweeplist(i2, i5, 80) | 0;
+    i22 = 400;
+    STACKTOP = i1;
+    return i22 | 0;
+   }
+   HEAP32[i14 >> 2] = HEAP32[i8 + 172 >> 2];
+   _sweeplist(i2, i14, 1) | 0;
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((HEAP8[i3 + 62 | 0] | 0) != 1) {
+    i4 = (HEAP32[i3 + 32 >> 2] | 0) / 2 | 0;
+    if ((HEAP32[i3 + 28 >> 2] | 0) >>> 0 < i4 >>> 0) {
+     _luaS_resize(i2, i4);
+    }
+    i21 = i3 + 144 | 0;
+    i22 = i3 + 152 | 0;
+    HEAP32[i21 >> 2] = _luaM_realloc_(i2, HEAP32[i21 >> 2] | 0, HEAP32[i22 >> 2] | 0, 0) | 0;
+    HEAP32[i22 >> 2] = 0;
+   }
+   HEAP8[i6] = 5;
+   i22 = 5;
+   STACKTOP = i1;
+   return i22 | 0;
+  }
+ default:
+  {
+   i22 = 0;
+   STACKTOP = i1;
+   return i22 | 0;
+  }
+ }
+ return 0;
+}
+function _pmain(i3) {
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ i7 = _lua_tointegerx(i3, 1, 0) | 0;
+ i4 = _lua_touserdata(i3, 2) | 0;
+ i5 = HEAP32[i4 >> 2] | 0;
+ if ((i5 | 0) != 0 ? (HEAP8[i5] | 0) != 0 : 0) {
+  HEAP32[20] = i5;
+ }
+ i12 = HEAP32[i4 + 4 >> 2] | 0;
+ do {
+  if ((i12 | 0) == 0) {
+   i5 = 0;
+   i6 = 0;
+   i8 = 0;
+   i9 = 1;
+   i10 = 1;
+  } else {
+   i9 = 0;
+   i8 = 0;
+   i11 = 0;
+   i6 = 0;
+   i5 = 1;
+   L6 : while (1) {
+    if ((HEAP8[i12] | 0) != 45) {
+     i10 = 18;
+     break;
+    }
+    switch (HEAP8[i12 + 1 | 0] | 0) {
+    case 108:
+     {
+      i10 = 12;
+      break;
+     }
+    case 69:
+     {
+      i9 = 1;
+      break;
+     }
+    case 45:
+     {
+      i10 = 7;
+      break L6;
+     }
+    case 105:
+     {
+      if ((HEAP8[i12 + 2 | 0] | 0) == 0) {
+       i11 = 1;
+       i6 = 1;
+      } else {
+       i5 = -1;
+       break L6;
+      }
+      break;
+     }
+    case 101:
+     {
+      i8 = 1;
+      i10 = 12;
+      break;
+     }
+    case 118:
+     {
+      if ((HEAP8[i12 + 2 | 0] | 0) == 0) {
+       i11 = 1;
+      } else {
+       i5 = -1;
+       break L6;
+      }
+      break;
+     }
+    case 0:
+     {
+      i10 = 18;
+      break L6;
+     }
+    default:
+     {
+      i10 = 16;
+      break L6;
+     }
+    }
+    if ((i10 | 0) == 12) {
+     i10 = 0;
+     if ((HEAP8[i12 + 2 | 0] | 0) == 0) {
+      i12 = i5 + 1 | 0;
+      i13 = HEAP32[i4 + (i12 << 2) >> 2] | 0;
+      if ((i13 | 0) == 0) {
+       i10 = 15;
+       break;
+      }
+      if ((HEAP8[i13] | 0) == 45) {
+       i10 = 15;
+       break;
+      } else {
+       i5 = i12;
+      }
+     }
+    }
+    i5 = i5 + 1 | 0;
+    i12 = HEAP32[i4 + (i5 << 2) >> 2] | 0;
+    if ((i12 | 0) == 0) {
+     i5 = 0;
+     i12 = i9;
+     i10 = 23;
+     break;
+    }
+   }
+   if ((i10 | 0) == 7) {
+    if ((HEAP8[i12 + 2 | 0] | 0) == 0) {
+     i5 = i5 + 1 | 0;
+     i5 = (HEAP32[i4 + (i5 << 2) >> 2] | 0) == 0 ? 0 : i5;
+     i10 = 18;
+    } else {
+     i5 = -1;
+    }
+   } else if ((i10 | 0) == 15) {
+    i5 = 0 - i5 | 0;
+    i10 = 18;
+   } else if ((i10 | 0) == 16) {
+    i5 = 0 - i5 | 0;
+    i10 = 18;
+   }
+   if ((i10 | 0) == 18) {
+    if ((i5 | 0) >= 0) {
+     i12 = i9;
+     i10 = 23;
+    }
+   }
+   if ((i10 | 0) == 23) {
+    if ((i11 | 0) == 0) {
+     i9 = 1;
+    } else {
+     i9 = HEAP32[_stdout >> 2] | 0;
+     _fwrite(440, 1, 51, i9 | 0) | 0;
+     _fputc(10, i9 | 0) | 0;
+     _fflush(i9 | 0) | 0;
+     i9 = 0;
+    }
+    if ((i12 | 0) == 0) {
+     i10 = 1;
+     break;
+    }
+    _lua_pushboolean(i3, 1);
+    _lua_setfield(i3, -1001e3, 96);
+    i10 = 0;
+    break;
+   }
+   i3 = HEAP32[i4 + (0 - i5 << 2) >> 2] | 0;
+   i4 = HEAP32[_stderr >> 2] | 0;
+   HEAP32[i2 >> 2] = HEAP32[20];
+   _fprintf(i4 | 0, 496, i2 | 0) | 0;
+   _fflush(i4 | 0) | 0;
+   i13 = HEAP8[i3 + 1 | 0] | 0;
+   if (i13 << 24 >> 24 == 108 | i13 << 24 >> 24 == 101) {
+    HEAP32[i2 >> 2] = i3;
+    _fprintf(i4 | 0, 504, i2 | 0) | 0;
+    _fflush(i4 | 0) | 0;
+   } else {
+    HEAP32[i2 >> 2] = i3;
+    _fprintf(i4 | 0, 528, i2 | 0) | 0;
+    _fflush(i4 | 0) | 0;
+   }
+   HEAP32[i2 >> 2] = HEAP32[20];
+   _fprintf(i4 | 0, 560, i2 | 0) | 0;
+   _fflush(i4 | 0) | 0;
+   i13 = 0;
+   STACKTOP = i1;
+   return i13 | 0;
+  }
+ } while (0);
+ _luaL_checkversion_(i3, 502.0);
+ _lua_gc(i3, 0, 0) | 0;
+ _luaL_openlibs(i3);
+ _lua_gc(i3, 1, 0) | 0;
+ do {
+  if (i10) {
+   i10 = _getenv(409 | 0) | 0;
+   if ((i10 | 0) == 0) {
+    i10 = _getenv(425 | 0) | 0;
+    if ((i10 | 0) == 0) {
+     break;
+    } else {
+     i11 = 424;
+    }
+   } else {
+    i11 = 408;
+   }
+   if ((HEAP8[i10] | 0) == 64) {
+    i13 = _luaL_loadfilex(i3, i10 + 1 | 0, 0) | 0;
+    if ((i13 | 0) == 0) {
+     i12 = _lua_gettop(i3) | 0;
+     _lua_pushcclosure(i3, 142, 0);
+     _lua_insert(i3, i12);
+     HEAP32[48] = i3;
+     _signal(2, 1) | 0;
+     i13 = _lua_pcallk(i3, 0, 0, i12, 0, 0) | 0;
+     _signal(2, 0) | 0;
+     _lua_remove(i3, i12);
+     if ((i13 | 0) == 0) {
+      break;
+     }
+    }
+    if ((_lua_type(i3, -1) | 0) == 0) {
+     i13 = 0;
+     STACKTOP = i1;
+     return i13 | 0;
+    }
+    i11 = _lua_tolstring(i3, -1, 0) | 0;
+    i12 = HEAP32[20] | 0;
+    i10 = HEAP32[_stderr >> 2] | 0;
+    if ((i12 | 0) != 0) {
+     HEAP32[i2 >> 2] = i12;
+     _fprintf(i10 | 0, 496, i2 | 0) | 0;
+     _fflush(i10 | 0) | 0;
+    }
+    HEAP32[i2 >> 2] = (i11 | 0) == 0 ? 48 : i11;
+    _fprintf(i10 | 0, 912, i2 | 0) | 0;
+    _fflush(i10 | 0) | 0;
+    _lua_settop(i3, -2);
+    _lua_gc(i3, 2, 0) | 0;
+   } else {
+    i13 = _luaL_loadbufferx(i3, i10, _strlen(i10 | 0) | 0, i11, 0) | 0;
+    if ((i13 | 0) == 0) {
+     i12 = _lua_gettop(i3) | 0;
+     _lua_pushcclosure(i3, 142, 0);
+     _lua_insert(i3, i12);
+     HEAP32[48] = i3;
+     _signal(2, 1) | 0;
+     i13 = _lua_pcallk(i3, 0, 0, i12, 0, 0) | 0;
+     _signal(2, 0) | 0;
+     _lua_remove(i3, i12);
+     if ((i13 | 0) == 0) {
+      break;
+     }
+    }
+    if ((_lua_type(i3, -1) | 0) == 0) {
+     i13 = 0;
+     STACKTOP = i1;
+     return i13 | 0;
+    }
+    i11 = _lua_tolstring(i3, -1, 0) | 0;
+    i10 = HEAP32[20] | 0;
+    i12 = HEAP32[_stderr >> 2] | 0;
+    if ((i10 | 0) != 0) {
+     HEAP32[i2 >> 2] = i10;
+     _fprintf(i12 | 0, 496, i2 | 0) | 0;
+     _fflush(i12 | 0) | 0;
+    }
+    HEAP32[i2 >> 2] = (i11 | 0) == 0 ? 48 : i11;
+    _fprintf(i12 | 0, 912, i2 | 0) | 0;
+    _fflush(i12 | 0) | 0;
+    _lua_settop(i3, -2);
+    _lua_gc(i3, 2, 0) | 0;
+   }
+   if ((i13 | 0) != 0) {
+    i13 = 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+  }
+ } while (0);
+ i7 = (i5 | 0) > 0 ? i5 : i7;
+ L67 : do {
+  if ((i7 | 0) > 1) {
+   i10 = 1;
+   while (1) {
+    i11 = HEAP32[i4 + (i10 << 2) >> 2] | 0;
+    i12 = HEAP8[i11 + 1 | 0] | 0;
+    if ((i12 | 0) == 108) {
+     i11 = i11 + 2 | 0;
+     if ((HEAP8[i11] | 0) == 0) {
+      i10 = i10 + 1 | 0;
+      i11 = HEAP32[i4 + (i10 << 2) >> 2] | 0;
+     }
+     _lua_getglobal(i3, 400);
+     _lua_pushstring(i3, i11) | 0;
+     i12 = (_lua_gettop(i3) | 0) + -1 | 0;
+     _lua_pushcclosure(i3, 142, 0);
+     _lua_insert(i3, i12);
+     HEAP32[48] = i3;
+     _signal(2, 1) | 0;
+     i13 = _lua_pcallk(i3, 1, 1, i12, 0, 0) | 0;
+     _signal(2, 0) | 0;
+     _lua_remove(i3, i12);
+     if ((i13 | 0) != 0) {
+      i10 = 58;
+      break;
+     }
+     _lua_setglobal(i3, i11);
+    } else if ((i12 | 0) == 101) {
+     i11 = i11 + 2 | 0;
+     if ((HEAP8[i11] | 0) == 0) {
+      i10 = i10 + 1 | 0;
+      i11 = HEAP32[i4 + (i10 << 2) >> 2] | 0;
+     }
+     if ((_luaL_loadbufferx(i3, i11, _strlen(i11 | 0) | 0, 384, 0) | 0) != 0) {
+      i10 = 50;
+      break;
+     }
+     i12 = _lua_gettop(i3) | 0;
+     _lua_pushcclosure(i3, 142, 0);
+     _lua_insert(i3, i12);
+     HEAP32[48] = i3;
+     _signal(2, 1) | 0;
+     i13 = _lua_pcallk(i3, 0, 0, i12, 0, 0) | 0;
+     _signal(2, 0) | 0;
+     _lua_remove(i3, i12);
+     if ((i13 | 0) != 0) {
+      i10 = 50;
+      break;
+     }
+    }
+    i10 = i10 + 1 | 0;
+    if ((i10 | 0) >= (i7 | 0)) {
+     break L67;
+    }
+   }
+   if ((i10 | 0) == 50) {
+    if ((_lua_type(i3, -1) | 0) == 0) {
+     i13 = 0;
+     STACKTOP = i1;
+     return i13 | 0;
+    }
+    i5 = _lua_tolstring(i3, -1, 0) | 0;
+    i6 = HEAP32[20] | 0;
+    i4 = HEAP32[_stderr >> 2] | 0;
+    if ((i6 | 0) != 0) {
+     HEAP32[i2 >> 2] = i6;
+     _fprintf(i4 | 0, 496, i2 | 0) | 0;
+     _fflush(i4 | 0) | 0;
+    }
+    HEAP32[i2 >> 2] = (i5 | 0) == 0 ? 48 : i5;
+    _fprintf(i4 | 0, 912, i2 | 0) | 0;
+    _fflush(i4 | 0) | 0;
+    _lua_settop(i3, -2);
+    _lua_gc(i3, 2, 0) | 0;
+    i13 = 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   } else if ((i10 | 0) == 58) {
+    if ((_lua_type(i3, -1) | 0) == 0) {
+     i13 = 0;
+     STACKTOP = i1;
+     return i13 | 0;
+    }
+    i5 = _lua_tolstring(i3, -1, 0) | 0;
+    i6 = HEAP32[20] | 0;
+    i4 = HEAP32[_stderr >> 2] | 0;
+    if ((i6 | 0) != 0) {
+     HEAP32[i2 >> 2] = i6;
+     _fprintf(i4 | 0, 496, i2 | 0) | 0;
+     _fflush(i4 | 0) | 0;
+    }
+    HEAP32[i2 >> 2] = (i5 | 0) == 0 ? 48 : i5;
+    _fprintf(i4 | 0, 912, i2 | 0) | 0;
+    _fflush(i4 | 0) | 0;
+    _lua_settop(i3, -2);
+    _lua_gc(i3, 2, 0) | 0;
+    i13 = 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+  }
+ } while (0);
+ do {
+  if ((i5 | 0) != 0) {
+   i10 = 0;
+   while (1) {
+    if ((HEAP32[i4 + (i10 << 2) >> 2] | 0) == 0) {
+     break;
+    } else {
+     i10 = i10 + 1 | 0;
+    }
+   }
+   i11 = i5 + 1 | 0;
+   i7 = i10 - i11 | 0;
+   _luaL_checkstack(i3, i7 + 3 | 0, 352);
+   if ((i11 | 0) < (i10 | 0)) {
+    i12 = i11;
+    do {
+     _lua_pushstring(i3, HEAP32[i4 + (i12 << 2) >> 2] | 0) | 0;
+     i12 = i12 + 1 | 0;
+    } while ((i12 | 0) != (i10 | 0));
+   }
+   _lua_createtable(i3, i7, i11);
+   if ((i10 | 0) > 0) {
+    i11 = 0;
+    do {
+     _lua_pushstring(i3, HEAP32[i4 + (i11 << 2) >> 2] | 0) | 0;
+     _lua_rawseti(i3, -2, i11 - i5 | 0);
+     i11 = i11 + 1 | 0;
+    } while ((i11 | 0) != (i10 | 0));
+   }
+   _lua_setglobal(i3, 328);
+   i10 = HEAP32[i4 + (i5 << 2) >> 2] | 0;
+   if ((_strcmp(i10, 336) | 0) == 0) {
+    i13 = (_strcmp(HEAP32[i4 + (i5 + -1 << 2) >> 2] | 0, 344) | 0) == 0;
+    i10 = i13 ? i10 : 0;
+   }
+   i10 = _luaL_loadfilex(i3, i10, 0) | 0;
+   i4 = ~i7;
+   _lua_insert(i3, i4);
+   if ((i10 | 0) == 0) {
+    i13 = (_lua_gettop(i3) | 0) - i7 | 0;
+    _lua_pushcclosure(i3, 142, 0);
+    _lua_insert(i3, i13);
+    HEAP32[48] = i3;
+    _signal(2, 1) | 0;
+    i10 = _lua_pcallk(i3, i7, -1, i13, 0, 0) | 0;
+    _signal(2, 0) | 0;
+    _lua_remove(i3, i13);
+    if ((i10 | 0) == 0) {
+     break;
+    }
+   } else {
+    _lua_settop(i3, i4);
+   }
+   if ((_lua_type(i3, -1) | 0) != 0) {
+    i7 = _lua_tolstring(i3, -1, 0) | 0;
+    i11 = HEAP32[20] | 0;
+    i4 = HEAP32[_stderr >> 2] | 0;
+    if ((i11 | 0) != 0) {
+     HEAP32[i2 >> 2] = i11;
+     _fprintf(i4 | 0, 496, i2 | 0) | 0;
+     _fflush(i4 | 0) | 0;
+    }
+    HEAP32[i2 >> 2] = (i7 | 0) == 0 ? 48 : i7;
+    _fprintf(i4 | 0, 912, i2 | 0) | 0;
+    _fflush(i4 | 0) | 0;
+    _lua_settop(i3, -2);
+    _lua_gc(i3, 2, 0) | 0;
+   }
+   if ((i10 | 0) != 0) {
+    i13 = 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+  }
+ } while (0);
+ if ((i6 | 0) == 0) {
+  if (!((i8 | i5 | 0) != 0 | i9 ^ 1)) {
+   i13 = HEAP32[_stdout >> 2] | 0;
+   _fwrite(440, 1, 51, i13 | 0) | 0;
+   _fputc(10, i13 | 0) | 0;
+   _fflush(i13 | 0) | 0;
+   _dotty(i3);
+  }
+ } else {
+  _dotty(i3);
+ }
+ _lua_pushboolean(i3, 1);
+ i13 = 1;
+ STACKTOP = i1;
+ return i13 | 0;
+}
+function _DumpFunction(i6, i2) {
+ i6 = i6 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i17 = i5 + 56 | 0;
+ i19 = i5 + 52 | 0;
+ i20 = i5 + 48 | 0;
+ i18 = i5;
+ i21 = i5 + 60 | 0;
+ i22 = i5 + 44 | 0;
+ i1 = i5 + 40 | 0;
+ i16 = i5 + 36 | 0;
+ i23 = i5 + 32 | 0;
+ i3 = i5 + 28 | 0;
+ i7 = i5 + 24 | 0;
+ i8 = i5 + 20 | 0;
+ i9 = i5 + 16 | 0;
+ i10 = i5 + 12 | 0;
+ i12 = i5 + 8 | 0;
+ HEAP32[i17 >> 2] = HEAP32[i6 + 64 >> 2];
+ i4 = i2 + 16 | 0;
+ i28 = HEAP32[i4 >> 2] | 0;
+ if ((i28 | 0) == 0) {
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i17, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+ }
+ HEAP32[i17 >> 2] = HEAP32[i6 + 68 >> 2];
+ if ((i28 | 0) == 0) {
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i17, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+ }
+ HEAP8[i17] = HEAP8[i6 + 76 | 0] | 0;
+ if ((i28 | 0) == 0) {
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i17, 1, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+ }
+ HEAP8[i17] = HEAP8[i6 + 77 | 0] | 0;
+ if ((i28 | 0) == 0) {
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i17, 1, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+ }
+ HEAP8[i17] = HEAP8[i6 + 78 | 0] | 0;
+ if ((i28 | 0) == 0) {
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i17, 1, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+ }
+ i25 = HEAP32[i6 + 12 >> 2] | 0;
+ i24 = HEAP32[i6 + 48 >> 2] | 0;
+ HEAP32[i23 >> 2] = i24;
+ if ((i28 | 0) == 0) {
+  i26 = i2 + 4 | 0;
+  i27 = i2 + 8 | 0;
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i26 >> 2] & 3](HEAP32[i2 >> 2] | 0, i23, 4, HEAP32[i27 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+  if ((i28 | 0) == 0) {
+   i28 = FUNCTION_TABLE_iiiii[HEAP32[i26 >> 2] & 3](HEAP32[i2 >> 2] | 0, i25, i24 << 2, HEAP32[i27 >> 2] | 0) | 0;
+   HEAP32[i4 >> 2] = i28;
+   i25 = HEAP32[i6 + 44 >> 2] | 0;
+   HEAP32[i22 >> 2] = i25;
+   if ((i28 | 0) == 0) {
+    i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i22, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i28;
+   }
+  } else {
+   i11 = 13;
+  }
+ } else {
+  i11 = 13;
+ }
+ if ((i11 | 0) == 13) {
+  i25 = HEAP32[i6 + 44 >> 2] | 0;
+  HEAP32[i22 >> 2] = i25;
+ }
+ if ((i25 | 0) > 0) {
+  i24 = i6 + 8 | 0;
+  i23 = i2 + 4 | 0;
+  i22 = i2 + 8 | 0;
+  i26 = 0;
+  do {
+   i30 = HEAP32[i24 >> 2] | 0;
+   i27 = i30 + (i26 << 4) | 0;
+   i30 = i30 + (i26 << 4) + 8 | 0;
+   i29 = HEAP32[i30 >> 2] | 0;
+   HEAP8[i17] = i29 & 15;
+   if ((i28 | 0) == 0) {
+    i28 = FUNCTION_TABLE_iiiii[HEAP32[i23 >> 2] & 3](HEAP32[i2 >> 2] | 0, i17, 1, HEAP32[i22 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i28;
+    i29 = HEAP32[i30 >> 2] | 0;
+   }
+   i29 = i29 & 15;
+   do {
+    if ((i29 | 0) == 3) {
+     HEAPF64[i18 >> 3] = +HEAPF64[i27 >> 3];
+     if ((i28 | 0) == 0) {
+      i28 = FUNCTION_TABLE_iiiii[HEAP32[i23 >> 2] & 3](HEAP32[i2 >> 2] | 0, i18, 8, HEAP32[i22 >> 2] | 0) | 0;
+      HEAP32[i4 >> 2] = i28;
+     }
+    } else if ((i29 | 0) == 1) {
+     HEAP8[i21] = HEAP32[i27 >> 2];
+     if ((i28 | 0) == 0) {
+      i28 = FUNCTION_TABLE_iiiii[HEAP32[i23 >> 2] & 3](HEAP32[i2 >> 2] | 0, i21, 1, HEAP32[i22 >> 2] | 0) | 0;
+      HEAP32[i4 >> 2] = i28;
+     }
+    } else if ((i29 | 0) == 4) {
+     i27 = HEAP32[i27 >> 2] | 0;
+     if ((i27 | 0) == 0) {
+      HEAP32[i19 >> 2] = 0;
+      if ((i28 | 0) != 0) {
+       break;
+      }
+      i28 = FUNCTION_TABLE_iiiii[HEAP32[i23 >> 2] & 3](HEAP32[i2 >> 2] | 0, i19, 4, HEAP32[i22 >> 2] | 0) | 0;
+      HEAP32[i4 >> 2] = i28;
+      break;
+     }
+     HEAP32[i20 >> 2] = (HEAP32[i27 + 12 >> 2] | 0) + 1;
+     if ((i28 | 0) == 0) {
+      i28 = FUNCTION_TABLE_iiiii[HEAP32[i23 >> 2] & 3](HEAP32[i2 >> 2] | 0, i20, 4, HEAP32[i22 >> 2] | 0) | 0;
+      HEAP32[i4 >> 2] = i28;
+      if ((i28 | 0) == 0) {
+       i28 = FUNCTION_TABLE_iiiii[HEAP32[i23 >> 2] & 3](HEAP32[i2 >> 2] | 0, i27 + 16 | 0, HEAP32[i20 >> 2] | 0, HEAP32[i22 >> 2] | 0) | 0;
+       HEAP32[i4 >> 2] = i28;
+      }
+     }
+    }
+   } while (0);
+   i26 = i26 + 1 | 0;
+  } while ((i26 | 0) != (i25 | 0));
+ }
+ i18 = HEAP32[i6 + 56 >> 2] | 0;
+ HEAP32[i17 >> 2] = i18;
+ if ((i28 | 0) == 0) {
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i17, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+ }
+ if ((i18 | 0) > 0) {
+  i17 = i6 + 16 | 0;
+  i19 = 0;
+  do {
+   _DumpFunction(HEAP32[(HEAP32[i17 >> 2] | 0) + (i19 << 2) >> 2] | 0, i2);
+   i19 = i19 + 1 | 0;
+  } while ((i19 | 0) != (i18 | 0));
+  i28 = HEAP32[i4 >> 2] | 0;
+ }
+ i17 = i6 + 40 | 0;
+ i18 = HEAP32[i17 >> 2] | 0;
+ HEAP32[i16 >> 2] = i18;
+ if ((i28 | 0) == 0) {
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i16, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+ }
+ if ((i18 | 0) > 0) {
+  i19 = i6 + 28 | 0;
+  i16 = i2 + 4 | 0;
+  i20 = i2 + 8 | 0;
+  i21 = 0;
+  do {
+   i22 = HEAP32[i19 >> 2] | 0;
+   HEAP8[i1] = HEAP8[i22 + (i21 << 3) + 4 | 0] | 0;
+   if ((i28 | 0) == 0) {
+    i28 = FUNCTION_TABLE_iiiii[HEAP32[i16 >> 2] & 3](HEAP32[i2 >> 2] | 0, i1, 1, HEAP32[i20 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i28;
+    i22 = HEAP32[i19 >> 2] | 0;
+   }
+   HEAP8[i1] = HEAP8[i22 + (i21 << 3) + 5 | 0] | 0;
+   if ((i28 | 0) == 0) {
+    i28 = FUNCTION_TABLE_iiiii[HEAP32[i16 >> 2] & 3](HEAP32[i2 >> 2] | 0, i1, 1, HEAP32[i20 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i28;
+   }
+   i21 = i21 + 1 | 0;
+  } while ((i21 | 0) != (i18 | 0));
+ }
+ i16 = i2 + 12 | 0;
+ if ((HEAP32[i16 >> 2] | 0) == 0 ? (i13 = HEAP32[i6 + 36 >> 2] | 0, (i13 | 0) != 0) : 0) {
+  HEAP32[i12 >> 2] = (HEAP32[i13 + 12 >> 2] | 0) + 1;
+  if ((i28 | 0) == 0 ? (i14 = i2 + 4 | 0, i15 = i2 + 8 | 0, i30 = FUNCTION_TABLE_iiiii[HEAP32[i14 >> 2] & 3](HEAP32[i2 >> 2] | 0, i12, 4, HEAP32[i15 >> 2] | 0) | 0, HEAP32[i4 >> 2] = i30, (i30 | 0) == 0) : 0) {
+   HEAP32[i4 >> 2] = FUNCTION_TABLE_iiiii[HEAP32[i14 >> 2] & 3](HEAP32[i2 >> 2] | 0, i13 + 16 | 0, HEAP32[i12 >> 2] | 0, HEAP32[i15 >> 2] | 0) | 0;
+  }
+ } else {
+  i12 = i10;
+  i11 = 50;
+ }
+ if ((i11 | 0) == 50) {
+  HEAP32[i10 >> 2] = 0;
+  if ((i28 | 0) == 0) {
+   HEAP32[i4 >> 2] = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i12, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  }
+ }
+ if ((HEAP32[i16 >> 2] | 0) == 0) {
+  i11 = HEAP32[i6 + 52 >> 2] | 0;
+ } else {
+  i11 = 0;
+ }
+ i10 = HEAP32[i6 + 20 >> 2] | 0;
+ HEAP32[i9 >> 2] = i11;
+ i14 = HEAP32[i4 >> 2] | 0;
+ if ((i14 | 0) == 0) {
+  i12 = i2 + 4 | 0;
+  i13 = i2 + 8 | 0;
+  i14 = FUNCTION_TABLE_iiiii[HEAP32[i12 >> 2] & 3](HEAP32[i2 >> 2] | 0, i9, 4, HEAP32[i13 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i14;
+  if ((i14 | 0) == 0) {
+   i14 = FUNCTION_TABLE_iiiii[HEAP32[i12 >> 2] & 3](HEAP32[i2 >> 2] | 0, i10, i11 << 2, HEAP32[i13 >> 2] | 0) | 0;
+   HEAP32[i4 >> 2] = i14;
+  }
+ }
+ if ((HEAP32[i16 >> 2] | 0) == 0) {
+  i9 = HEAP32[i6 + 60 >> 2] | 0;
+ } else {
+  i9 = 0;
+ }
+ HEAP32[i8 >> 2] = i9;
+ if ((i14 | 0) == 0) {
+  i14 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i8, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i14;
+ }
+ if ((i9 | 0) > 0) {
+  i10 = i6 + 24 | 0;
+  i11 = i2 + 4 | 0;
+  i8 = i2 + 8 | 0;
+  i12 = 0;
+  do {
+   i13 = HEAP32[(HEAP32[i10 >> 2] | 0) + (i12 * 12 | 0) >> 2] | 0;
+   if ((i13 | 0) == 0) {
+    HEAP32[i1 >> 2] = 0;
+    if ((i14 | 0) == 0) {
+     i14 = FUNCTION_TABLE_iiiii[HEAP32[i11 >> 2] & 3](HEAP32[i2 >> 2] | 0, i1, 4, HEAP32[i8 >> 2] | 0) | 0;
+     HEAP32[i4 >> 2] = i14;
+    }
+   } else {
+    HEAP32[i3 >> 2] = (HEAP32[i13 + 12 >> 2] | 0) + 1;
+    if ((i14 | 0) == 0) {
+     i14 = FUNCTION_TABLE_iiiii[HEAP32[i11 >> 2] & 3](HEAP32[i2 >> 2] | 0, i3, 4, HEAP32[i8 >> 2] | 0) | 0;
+     HEAP32[i4 >> 2] = i14;
+     if ((i14 | 0) == 0) {
+      i14 = FUNCTION_TABLE_iiiii[HEAP32[i11 >> 2] & 3](HEAP32[i2 >> 2] | 0, i13 + 16 | 0, HEAP32[i3 >> 2] | 0, HEAP32[i8 >> 2] | 0) | 0;
+      HEAP32[i4 >> 2] = i14;
+     }
+    }
+   }
+   i13 = HEAP32[i10 >> 2] | 0;
+   HEAP32[i1 >> 2] = HEAP32[i13 + (i12 * 12 | 0) + 4 >> 2];
+   if ((i14 | 0) == 0) {
+    i14 = FUNCTION_TABLE_iiiii[HEAP32[i11 >> 2] & 3](HEAP32[i2 >> 2] | 0, i1, 4, HEAP32[i8 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i14;
+    i13 = HEAP32[i10 >> 2] | 0;
+   }
+   HEAP32[i1 >> 2] = HEAP32[i13 + (i12 * 12 | 0) + 8 >> 2];
+   if ((i14 | 0) == 0) {
+    i14 = FUNCTION_TABLE_iiiii[HEAP32[i11 >> 2] & 3](HEAP32[i2 >> 2] | 0, i1, 4, HEAP32[i8 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i14;
+   }
+   i12 = i12 + 1 | 0;
+  } while ((i12 | 0) != (i9 | 0));
+ }
+ if ((HEAP32[i16 >> 2] | 0) == 0) {
+  i8 = HEAP32[i17 >> 2] | 0;
+ } else {
+  i8 = 0;
+ }
+ HEAP32[i7 >> 2] = i8;
+ if ((i14 | 0) == 0) {
+  i14 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i7, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i14;
+ }
+ if ((i8 | 0) <= 0) {
+  STACKTOP = i5;
+  return;
+ }
+ i7 = i6 + 28 | 0;
+ i6 = i2 + 4 | 0;
+ i9 = i2 + 8 | 0;
+ i10 = 0;
+ do {
+  i11 = HEAP32[(HEAP32[i7 >> 2] | 0) + (i10 << 3) >> 2] | 0;
+  if ((i11 | 0) == 0) {
+   HEAP32[i1 >> 2] = 0;
+   if ((i14 | 0) == 0) {
+    i14 = FUNCTION_TABLE_iiiii[HEAP32[i6 >> 2] & 3](HEAP32[i2 >> 2] | 0, i1, 4, HEAP32[i9 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i14;
+   }
+  } else {
+   HEAP32[i3 >> 2] = (HEAP32[i11 + 12 >> 2] | 0) + 1;
+   if ((i14 | 0) == 0) {
+    i14 = FUNCTION_TABLE_iiiii[HEAP32[i6 >> 2] & 3](HEAP32[i2 >> 2] | 0, i3, 4, HEAP32[i9 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i14;
+    if ((i14 | 0) == 0) {
+     i14 = FUNCTION_TABLE_iiiii[HEAP32[i6 >> 2] & 3](HEAP32[i2 >> 2] | 0, i11 + 16 | 0, HEAP32[i3 >> 2] | 0, HEAP32[i9 >> 2] | 0) | 0;
+     HEAP32[i4 >> 2] = i14;
+    }
+   }
+  }
+  i10 = i10 + 1 | 0;
+ } while ((i10 | 0) != (i8 | 0));
+ STACKTOP = i5;
+ return;
+}
+function _LoadFunction(i2, i6) {
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ i5 = i1 + 8 | 0;
+ i4 = i2 + 4 | 0;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i8 = HEAP32[i3 >> 2] | 0;
+ if ((i8 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ HEAP32[i6 + 64 >> 2] = i8;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i8 = HEAP32[i3 >> 2] | 0;
+ if ((i8 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ HEAP32[i6 + 68 >> 2] = i8;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 1) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ HEAP8[i6 + 76 | 0] = HEAP8[i3] | 0;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 1) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ HEAP8[i6 + 77 | 0] = HEAP8[i3] | 0;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 1) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ HEAP8[i6 + 78 | 0] = HEAP8[i3] | 0;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i9 = HEAP32[i3 >> 2] | 0;
+ if ((i9 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ i8 = HEAP32[i2 >> 2] | 0;
+ if ((i9 + 1 | 0) >>> 0 > 1073741823) {
+  _luaM_toobig(i8);
+ }
+ i14 = i9 << 2;
+ i13 = _luaM_realloc_(i8, 0, 0, i14) | 0;
+ HEAP32[i6 + 12 >> 2] = i13;
+ HEAP32[i6 + 48 >> 2] = i9;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i13, i14) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i8 = HEAP32[i3 >> 2] | 0;
+ if ((i8 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ i9 = HEAP32[i2 >> 2] | 0;
+ if ((i8 + 1 | 0) >>> 0 > 268435455) {
+  _luaM_toobig(i9);
+ }
+ i11 = _luaM_realloc_(i9, 0, 0, i8 << 4) | 0;
+ i9 = i6 + 8 | 0;
+ HEAP32[i9 >> 2] = i11;
+ HEAP32[i6 + 44 >> 2] = i8;
+ i12 = (i8 | 0) > 0;
+ L43 : do {
+  if (i12) {
+   i10 = 0;
+   do {
+    HEAP32[i11 + (i10 << 4) + 8 >> 2] = 0;
+    i10 = i10 + 1 | 0;
+   } while ((i10 | 0) != (i8 | 0));
+   if (i12) {
+    i10 = i2 + 8 | 0;
+    i13 = 0;
+    while (1) {
+     i12 = i11 + (i13 << 4) | 0;
+     if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 1) | 0) != 0) {
+      i9 = 34;
+      break;
+     }
+     i14 = HEAP8[i3] | 0;
+     if ((i14 | 0) == 4) {
+      if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+       i9 = 44;
+       break;
+      }
+      i14 = HEAP32[i3 >> 2] | 0;
+      if ((i14 | 0) == 0) {
+       i14 = 0;
+      } else {
+       i14 = _luaZ_openspace(HEAP32[i2 >> 2] | 0, HEAP32[i10 >> 2] | 0, i14) | 0;
+       if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i14, HEAP32[i3 >> 2] | 0) | 0) != 0) {
+        i9 = 47;
+        break;
+       }
+       i14 = _luaS_newlstr(HEAP32[i2 >> 2] | 0, i14, (HEAP32[i3 >> 2] | 0) + -1 | 0) | 0;
+      }
+      HEAP32[i12 >> 2] = i14;
+      HEAP32[i11 + (i13 << 4) + 8 >> 2] = HEAPU8[i14 + 4 | 0] | 64;
+     } else if ((i14 | 0) == 1) {
+      if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 1) | 0) != 0) {
+       i9 = 38;
+       break;
+      }
+      HEAP32[i12 >> 2] = HEAP8[i3] | 0;
+      HEAP32[i11 + (i13 << 4) + 8 >> 2] = 1;
+     } else if ((i14 | 0) == 3) {
+      if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 8) | 0) != 0) {
+       i9 = 41;
+       break;
+      }
+      HEAPF64[i12 >> 3] = +HEAPF64[i3 >> 3];
+      HEAP32[i11 + (i13 << 4) + 8 >> 2] = 3;
+     } else if ((i14 | 0) == 0) {
+      HEAP32[i11 + (i13 << 4) + 8 >> 2] = 0;
+     }
+     i13 = i13 + 1 | 0;
+     if ((i13 | 0) >= (i8 | 0)) {
+      break L43;
+     }
+     i11 = HEAP32[i9 >> 2] | 0;
+    }
+    if ((i9 | 0) == 34) {
+     _error(i2, 8824);
+    } else if ((i9 | 0) == 38) {
+     _error(i2, 8824);
+    } else if ((i9 | 0) == 41) {
+     _error(i2, 8824);
+    } else if ((i9 | 0) == 44) {
+     _error(i2, 8824);
+    } else if ((i9 | 0) == 47) {
+     _error(i2, 8824);
+    }
+   }
+  }
+ } while (0);
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i8 = HEAP32[i3 >> 2] | 0;
+ if ((i8 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ i9 = HEAP32[i2 >> 2] | 0;
+ if ((i8 + 1 | 0) >>> 0 > 1073741823) {
+  _luaM_toobig(i9);
+ }
+ i11 = _luaM_realloc_(i9, 0, 0, i8 << 2) | 0;
+ i9 = i6 + 16 | 0;
+ HEAP32[i9 >> 2] = i11;
+ HEAP32[i6 + 56 >> 2] = i8;
+ i10 = (i8 | 0) > 0;
+ if (i10) {
+  i12 = 0;
+  while (1) {
+   HEAP32[i11 + (i12 << 2) >> 2] = 0;
+   i12 = i12 + 1 | 0;
+   if ((i12 | 0) == (i8 | 0)) {
+    break;
+   }
+   i11 = HEAP32[i9 >> 2] | 0;
+  }
+  if (i10) {
+   i10 = 0;
+   do {
+    i14 = _luaF_newproto(HEAP32[i2 >> 2] | 0) | 0;
+    HEAP32[(HEAP32[i9 >> 2] | 0) + (i10 << 2) >> 2] = i14;
+    _LoadFunction(i2, HEAP32[(HEAP32[i9 >> 2] | 0) + (i10 << 2) >> 2] | 0);
+    i10 = i10 + 1 | 0;
+   } while ((i10 | 0) != (i8 | 0));
+  }
+ }
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i9 = HEAP32[i3 >> 2] | 0;
+ if ((i9 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ i8 = HEAP32[i2 >> 2] | 0;
+ if ((i9 + 1 | 0) >>> 0 > 536870911) {
+  _luaM_toobig(i8);
+ }
+ i10 = _luaM_realloc_(i8, 0, 0, i9 << 3) | 0;
+ i8 = i6 + 28 | 0;
+ HEAP32[i8 >> 2] = i10;
+ HEAP32[i6 + 40 >> 2] = i9;
+ L98 : do {
+  if ((i9 | 0) > 0) {
+   HEAP32[i10 >> 2] = 0;
+   if ((i9 | 0) == 1) {
+    i10 = 0;
+   } else {
+    i10 = 1;
+    while (1) {
+     HEAP32[(HEAP32[i8 >> 2] | 0) + (i10 << 3) >> 2] = 0;
+     i10 = i10 + 1 | 0;
+     if ((i10 | 0) == (i9 | 0)) {
+      i10 = 0;
+      break;
+     }
+    }
+   }
+   while (1) {
+    if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 1) | 0) != 0) {
+     i9 = 73;
+     break;
+    }
+    HEAP8[(HEAP32[i8 >> 2] | 0) + (i10 << 3) + 4 | 0] = HEAP8[i3] | 0;
+    if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 1) | 0) != 0) {
+     i9 = 75;
+     break;
+    }
+    HEAP8[(HEAP32[i8 >> 2] | 0) + (i10 << 3) + 5 | 0] = HEAP8[i3] | 0;
+    i10 = i10 + 1 | 0;
+    if ((i10 | 0) >= (i9 | 0)) {
+     break L98;
+    }
+   }
+   if ((i9 | 0) == 73) {
+    _error(i2, 8824);
+   } else if ((i9 | 0) == 75) {
+    _error(i2, 8824);
+   }
+  }
+ } while (0);
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i9 = HEAP32[i3 >> 2] | 0;
+ do {
+  if ((i9 | 0) != 0) {
+   i9 = _luaZ_openspace(HEAP32[i2 >> 2] | 0, HEAP32[i2 + 8 >> 2] | 0, i9) | 0;
+   if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i9, HEAP32[i3 >> 2] | 0) | 0) == 0) {
+    i7 = _luaS_newlstr(HEAP32[i2 >> 2] | 0, i9, (HEAP32[i3 >> 2] | 0) + -1 | 0) | 0;
+    break;
+   } else {
+    _error(i2, 8824);
+   }
+  } else {
+   i7 = 0;
+  }
+ } while (0);
+ HEAP32[i6 + 36 >> 2] = i7;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i7 = HEAP32[i3 >> 2] | 0;
+ if ((i7 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ i9 = HEAP32[i2 >> 2] | 0;
+ if ((i7 + 1 | 0) >>> 0 > 1073741823) {
+  _luaM_toobig(i9);
+ }
+ i14 = i7 << 2;
+ i13 = _luaM_realloc_(i9, 0, 0, i14) | 0;
+ HEAP32[i6 + 20 >> 2] = i13;
+ HEAP32[i6 + 52 >> 2] = i7;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i13, i14) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i7 = HEAP32[i3 >> 2] | 0;
+ if ((i7 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ i9 = HEAP32[i2 >> 2] | 0;
+ if ((i7 + 1 | 0) >>> 0 > 357913941) {
+  _luaM_toobig(i9);
+ }
+ i10 = _luaM_realloc_(i9, 0, 0, i7 * 12 | 0) | 0;
+ i9 = i6 + 24 | 0;
+ HEAP32[i9 >> 2] = i10;
+ HEAP32[i6 + 60 >> 2] = i7;
+ L141 : do {
+  if ((i7 | 0) > 0) {
+   HEAP32[i10 >> 2] = 0;
+   if ((i7 | 0) != 1) {
+    i6 = 1;
+    do {
+     HEAP32[(HEAP32[i9 >> 2] | 0) + (i6 * 12 | 0) >> 2] = 0;
+     i6 = i6 + 1 | 0;
+    } while ((i6 | 0) != (i7 | 0));
+   }
+   i6 = i2 + 8 | 0;
+   i10 = 0;
+   while (1) {
+    if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+     i9 = 102;
+     break;
+    }
+    i11 = HEAP32[i3 >> 2] | 0;
+    if ((i11 | 0) == 0) {
+     i11 = 0;
+    } else {
+     i11 = _luaZ_openspace(HEAP32[i2 >> 2] | 0, HEAP32[i6 >> 2] | 0, i11) | 0;
+     if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i11, HEAP32[i3 >> 2] | 0) | 0) != 0) {
+      i9 = 105;
+      break;
+     }
+     i11 = _luaS_newlstr(HEAP32[i2 >> 2] | 0, i11, (HEAP32[i3 >> 2] | 0) + -1 | 0) | 0;
+    }
+    HEAP32[(HEAP32[i9 >> 2] | 0) + (i10 * 12 | 0) >> 2] = i11;
+    if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+     i9 = 108;
+     break;
+    }
+    i11 = HEAP32[i3 >> 2] | 0;
+    if ((i11 | 0) < 0) {
+     i9 = 110;
+     break;
+    }
+    HEAP32[(HEAP32[i9 >> 2] | 0) + (i10 * 12 | 0) + 4 >> 2] = i11;
+    if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+     i9 = 112;
+     break;
+    }
+    i11 = HEAP32[i3 >> 2] | 0;
+    if ((i11 | 0) < 0) {
+     i9 = 114;
+     break;
+    }
+    HEAP32[(HEAP32[i9 >> 2] | 0) + (i10 * 12 | 0) + 8 >> 2] = i11;
+    i10 = i10 + 1 | 0;
+    if ((i10 | 0) >= (i7 | 0)) {
+     break L141;
+    }
+   }
+   if ((i9 | 0) == 102) {
+    _error(i2, 8824);
+   } else if ((i9 | 0) == 105) {
+    _error(i2, 8824);
+   } else if ((i9 | 0) == 108) {
+    _error(i2, 8824);
+   } else if ((i9 | 0) == 110) {
+    _error(i2, 8872);
+   } else if ((i9 | 0) == 112) {
+    _error(i2, 8824);
+   } else if ((i9 | 0) == 114) {
+    _error(i2, 8872);
+   }
+  }
+ } while (0);
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i5, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i6 = HEAP32[i5 >> 2] | 0;
+ if ((i6 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ if ((i6 | 0) <= 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i5 = i2 + 8 | 0;
+ i7 = 0;
+ while (1) {
+  if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+   i9 = 123;
+   break;
+  }
+  i9 = HEAP32[i3 >> 2] | 0;
+  if ((i9 | 0) == 0) {
+   i9 = 0;
+  } else {
+   i9 = _luaZ_openspace(HEAP32[i2 >> 2] | 0, HEAP32[i5 >> 2] | 0, i9) | 0;
+   if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i9, HEAP32[i3 >> 2] | 0) | 0) != 0) {
+    i9 = 126;
+    break;
+   }
+   i9 = _luaS_newlstr(HEAP32[i2 >> 2] | 0, i9, (HEAP32[i3 >> 2] | 0) + -1 | 0) | 0;
+  }
+  HEAP32[(HEAP32[i8 >> 2] | 0) + (i7 << 3) >> 2] = i9;
+  i7 = i7 + 1 | 0;
+  if ((i7 | 0) >= (i6 | 0)) {
+   i9 = 129;
+   break;
+  }
+ }
+ if ((i9 | 0) == 123) {
+  _error(i2, 8824);
+ } else if ((i9 | 0) == 126) {
+  _error(i2, 8824);
+ } else if ((i9 | 0) == 129) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function _exp2reg(i4, i1, i7) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0;
+ i5 = STACKTOP;
+ _discharge2reg(i4, i1, i7);
+ i6 = i1 + 16 | 0;
+ do {
+  if ((HEAP32[i1 >> 2] | 0) == 10 ? (i10 = HEAP32[i1 + 8 >> 2] | 0, !((i10 | 0) == -1)) : 0) {
+   i22 = HEAP32[i6 >> 2] | 0;
+   if ((i22 | 0) == -1) {
+    HEAP32[i6 >> 2] = i10;
+    break;
+   }
+   i20 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+   while (1) {
+    i19 = i20 + (i22 << 2) | 0;
+    i21 = HEAP32[i19 >> 2] | 0;
+    i23 = (i21 >>> 14) + -131071 | 0;
+    if ((i23 | 0) == -1) {
+     break;
+    }
+    i23 = i22 + 1 + i23 | 0;
+    if ((i23 | 0) == -1) {
+     break;
+    } else {
+     i22 = i23;
+    }
+   }
+   i10 = i10 + ~i22 | 0;
+   if ((((i10 | 0) > -1 ? i10 : 0 - i10 | 0) | 0) > 131071) {
+    _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10624);
+   } else {
+    HEAP32[i19 >> 2] = (i10 << 14) + 2147467264 | i21 & 16383;
+    break;
+   }
+  }
+ } while (0);
+ i21 = HEAP32[i6 >> 2] | 0;
+ i10 = i1 + 20 | 0;
+ i19 = HEAP32[i10 >> 2] | 0;
+ if ((i21 | 0) == (i19 | 0)) {
+  HEAP32[i6 >> 2] = -1;
+  HEAP32[i10 >> 2] = -1;
+  i25 = i1 + 8 | 0;
+  HEAP32[i25 >> 2] = i7;
+  HEAP32[i1 >> 2] = 6;
+  STACKTOP = i5;
+  return;
+ }
+ L18 : do {
+  if ((i21 | 0) == -1) {
+   i18 = 20;
+  } else {
+   i20 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+   while (1) {
+    i23 = i20 + (i21 << 2) | 0;
+    if ((i21 | 0) > 0 ? (i18 = HEAP32[i20 + (i21 + -1 << 2) >> 2] | 0, (HEAP8[5584 + (i18 & 63) | 0] | 0) < 0) : 0) {
+     i22 = i18;
+    } else {
+     i22 = HEAP32[i23 >> 2] | 0;
+    }
+    if ((i22 & 63 | 0) != 28) {
+     i18 = 28;
+     break L18;
+    }
+    i22 = ((HEAP32[i23 >> 2] | 0) >>> 14) + -131071 | 0;
+    if ((i22 | 0) == -1) {
+     i18 = 20;
+     break L18;
+    }
+    i21 = i21 + 1 + i22 | 0;
+    if ((i21 | 0) == -1) {
+     i18 = 20;
+     break;
+    }
+   }
+  }
+ } while (0);
+ L29 : do {
+  if ((i18 | 0) == 20) {
+   if ((i19 | 0) == -1) {
+    i15 = -1;
+    i8 = -1;
+   } else {
+    i20 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+    while (1) {
+     i21 = i20 + (i19 << 2) | 0;
+     if ((i19 | 0) > 0 ? (i17 = HEAP32[i20 + (i19 + -1 << 2) >> 2] | 0, (HEAP8[5584 + (i17 & 63) | 0] | 0) < 0) : 0) {
+      i22 = i17;
+     } else {
+      i22 = HEAP32[i21 >> 2] | 0;
+     }
+     if ((i22 & 63 | 0) != 28) {
+      i18 = 28;
+      break L29;
+     }
+     i21 = ((HEAP32[i21 >> 2] | 0) >>> 14) + -131071 | 0;
+     if ((i21 | 0) == -1) {
+      i15 = -1;
+      i8 = -1;
+      break L29;
+     }
+     i19 = i19 + 1 + i21 | 0;
+     if ((i19 | 0) == -1) {
+      i15 = -1;
+      i8 = -1;
+      break;
+     }
+    }
+   }
+  }
+ } while (0);
+ do {
+  if ((i18 | 0) == 28) {
+   i17 = i4 + 28 | 0;
+   do {
+    if ((HEAP32[i1 >> 2] | 0) != 10) {
+     i21 = HEAP32[i17 >> 2] | 0;
+     HEAP32[i17 >> 2] = -1;
+     i18 = _luaK_code(i4, 2147450903) | 0;
+     if (!((i21 | 0) == -1)) {
+      if (!((i18 | 0) == -1)) {
+       i23 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+       i22 = i18;
+       while (1) {
+        i20 = i23 + (i22 << 2) | 0;
+        i19 = HEAP32[i20 >> 2] | 0;
+        i24 = (i19 >>> 14) + -131071 | 0;
+        if ((i24 | 0) == -1) {
+         break;
+        }
+        i24 = i22 + 1 + i24 | 0;
+        if ((i24 | 0) == -1) {
+         break;
+        } else {
+         i22 = i24;
+        }
+       }
+       i21 = i21 + ~i22 | 0;
+       if ((((i21 | 0) > -1 ? i21 : 0 - i21 | 0) | 0) > 131071) {
+        _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10624);
+       } else {
+        HEAP32[i20 >> 2] = (i21 << 14) + 2147467264 | i19 & 16383;
+        i16 = i18;
+        break;
+       }
+      } else {
+       i16 = i21;
+      }
+     } else {
+      i16 = i18;
+     }
+    } else {
+     i16 = -1;
+    }
+   } while (0);
+   i24 = i4 + 20 | 0;
+   i25 = i4 + 24 | 0;
+   HEAP32[i25 >> 2] = HEAP32[i24 >> 2];
+   i19 = i7 << 6;
+   i18 = _luaK_code(i4, i19 | 16387) | 0;
+   HEAP32[i25 >> 2] = HEAP32[i24 >> 2];
+   i19 = _luaK_code(i4, i19 | 8388611) | 0;
+   HEAP32[i25 >> 2] = HEAP32[i24 >> 2];
+   if (!((i16 | 0) == -1)) {
+    i22 = HEAP32[i17 >> 2] | 0;
+    if ((i22 | 0) == -1) {
+     HEAP32[i17 >> 2] = i16;
+     i15 = i18;
+     i8 = i19;
+     break;
+    }
+    i17 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+    while (1) {
+     i21 = i17 + (i22 << 2) | 0;
+     i20 = HEAP32[i21 >> 2] | 0;
+     i23 = (i20 >>> 14) + -131071 | 0;
+     if ((i23 | 0) == -1) {
+      break;
+     }
+     i23 = i22 + 1 + i23 | 0;
+     if ((i23 | 0) == -1) {
+      break;
+     } else {
+      i22 = i23;
+     }
+    }
+    i16 = i16 + ~i22 | 0;
+    if ((((i16 | 0) > -1 ? i16 : 0 - i16 | 0) | 0) > 131071) {
+     _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10624);
+    } else {
+     HEAP32[i21 >> 2] = (i16 << 14) + 2147467264 | i20 & 16383;
+     i15 = i18;
+     i8 = i19;
+     break;
+    }
+   } else {
+    i15 = i18;
+    i8 = i19;
+   }
+  }
+ } while (0);
+ i16 = HEAP32[i4 + 20 >> 2] | 0;
+ HEAP32[i4 + 24 >> 2] = i16;
+ i22 = HEAP32[i10 >> 2] | 0;
+ L67 : do {
+  if (!((i22 | 0) == -1)) {
+   i19 = (i7 | 0) == 255;
+   i17 = i7 << 6 & 16320;
+   i18 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+   while (1) {
+    i20 = i18 + (i22 << 2) | 0;
+    i23 = HEAP32[i20 >> 2] | 0;
+    i21 = (i23 >>> 14) + -131071 | 0;
+    if ((i21 | 0) == -1) {
+     i21 = -1;
+    } else {
+     i21 = i22 + 1 + i21 | 0;
+    }
+    if ((i22 | 0) > 0 ? (i14 = i18 + (i22 + -1 << 2) | 0, i13 = HEAP32[i14 >> 2] | 0, (HEAP8[5584 + (i13 & 63) | 0] | 0) < 0) : 0) {
+     i24 = i14;
+     i25 = i13;
+    } else {
+     i24 = i20;
+     i25 = i23;
+    }
+    if ((i25 & 63 | 0) == 28) {
+     i23 = i25 >>> 23;
+     if (i19 | (i23 | 0) == (i7 | 0)) {
+      i23 = i25 & 8372224 | i23 << 6 | 27;
+     } else {
+      i23 = i25 & -16321 | i17;
+     }
+     HEAP32[i24 >> 2] = i23;
+     i22 = i16 + ~i22 | 0;
+     if ((((i22 | 0) > -1 ? i22 : 0 - i22 | 0) | 0) > 131071) {
+      i18 = 58;
+      break;
+     }
+     i22 = HEAP32[i20 >> 2] & 16383 | (i22 << 14) + 2147467264;
+    } else {
+     i22 = i15 + ~i22 | 0;
+     if ((((i22 | 0) > -1 ? i22 : 0 - i22 | 0) | 0) > 131071) {
+      i18 = 61;
+      break;
+     }
+     i22 = i23 & 16383 | (i22 << 14) + 2147467264;
+    }
+    HEAP32[i20 >> 2] = i22;
+    if ((i21 | 0) == -1) {
+     break L67;
+    } else {
+     i22 = i21;
+    }
+   }
+   if ((i18 | 0) == 58) {
+    _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10624);
+   } else if ((i18 | 0) == 61) {
+    _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10624);
+   }
+  }
+ } while (0);
+ i20 = HEAP32[i6 >> 2] | 0;
+ if ((i20 | 0) == -1) {
+  HEAP32[i6 >> 2] = -1;
+  HEAP32[i10 >> 2] = -1;
+  i25 = i1 + 8 | 0;
+  HEAP32[i25 >> 2] = i7;
+  HEAP32[i1 >> 2] = 6;
+  STACKTOP = i5;
+  return;
+ }
+ i13 = i7 << 6;
+ i15 = i13 & 16320;
+ i14 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+ if ((i7 | 0) == 255) {
+  while (1) {
+   i17 = i14 + (i20 << 2) | 0;
+   i19 = HEAP32[i17 >> 2] | 0;
+   i18 = (i19 >>> 14) + -131071 | 0;
+   if ((i18 | 0) == -1) {
+    i18 = -1;
+   } else {
+    i18 = i20 + 1 + i18 | 0;
+   }
+   if ((i20 | 0) > 0 ? (i12 = i14 + (i20 + -1 << 2) | 0, i11 = HEAP32[i12 >> 2] | 0, (HEAP8[5584 + (i11 & 63) | 0] | 0) < 0) : 0) {
+    i22 = i12;
+    i21 = i11;
+   } else {
+    i22 = i17;
+    i21 = i19;
+   }
+   if ((i21 & 63 | 0) == 28) {
+    HEAP32[i22 >> 2] = i21 & 8372224 | i21 >>> 23 << 6 | 27;
+    i19 = i16 + ~i20 | 0;
+    if ((((i19 | 0) > -1 ? i19 : 0 - i19 | 0) | 0) > 131071) {
+     i18 = 87;
+     break;
+    }
+    i19 = HEAP32[i17 >> 2] & 16383 | (i19 << 14) + 2147467264;
+   } else {
+    i20 = i8 + ~i20 | 0;
+    if ((((i20 | 0) > -1 ? i20 : 0 - i20 | 0) | 0) > 131071) {
+     i18 = 90;
+     break;
+    }
+    i19 = i19 & 16383 | (i20 << 14) + 2147467264;
+   }
+   HEAP32[i17 >> 2] = i19;
+   if ((i18 | 0) == -1) {
+    i18 = 93;
+    break;
+   } else {
+    i20 = i18;
+   }
+  }
+  if ((i18 | 0) == 87) {
+   i25 = i4 + 12 | 0;
+   i25 = HEAP32[i25 >> 2] | 0;
+   _luaX_syntaxerror(i25, 10624);
+  } else if ((i18 | 0) == 90) {
+   i25 = i4 + 12 | 0;
+   i25 = HEAP32[i25 >> 2] | 0;
+   _luaX_syntaxerror(i25, 10624);
+  } else if ((i18 | 0) == 93) {
+   HEAP32[i6 >> 2] = -1;
+   HEAP32[i10 >> 2] = -1;
+   i25 = i1 + 8 | 0;
+   HEAP32[i25 >> 2] = i7;
+   HEAP32[i1 >> 2] = 6;
+   STACKTOP = i5;
+   return;
+  }
+ } else {
+  i9 = i20;
+ }
+ while (1) {
+  i11 = i14 + (i9 << 2) | 0;
+  i17 = HEAP32[i11 >> 2] | 0;
+  i12 = (i17 >>> 14) + -131071 | 0;
+  if ((i12 | 0) == -1) {
+   i12 = -1;
+  } else {
+   i12 = i9 + 1 + i12 | 0;
+  }
+  if ((i9 | 0) > 0 ? (i3 = i14 + (i9 + -1 << 2) | 0, i2 = HEAP32[i3 >> 2] | 0, (HEAP8[5584 + (i2 & 63) | 0] | 0) < 0) : 0) {
+   i18 = i3;
+   i19 = i2;
+  } else {
+   i18 = i11;
+   i19 = i17;
+  }
+  if ((i19 & 63 | 0) == 28) {
+   if ((i19 >>> 23 | 0) == (i7 | 0)) {
+    i17 = i19 & 8372224 | i13 | 27;
+   } else {
+    i17 = i19 & -16321 | i15;
+   }
+   HEAP32[i18 >> 2] = i17;
+   i9 = i16 + ~i9 | 0;
+   if ((((i9 | 0) > -1 ? i9 : 0 - i9 | 0) | 0) > 131071) {
+    i18 = 87;
+    break;
+   }
+   i9 = HEAP32[i11 >> 2] & 16383 | (i9 << 14) + 2147467264;
+  } else {
+   i9 = i8 + ~i9 | 0;
+   if ((((i9 | 0) > -1 ? i9 : 0 - i9 | 0) | 0) > 131071) {
+    i18 = 90;
+    break;
+   }
+   i9 = i17 & 16383 | (i9 << 14) + 2147467264;
+  }
+  HEAP32[i11 >> 2] = i9;
+  if ((i12 | 0) == -1) {
+   i18 = 93;
+   break;
+  } else {
+   i9 = i12;
+  }
+ }
+ if ((i18 | 0) == 87) {
+  i25 = i4 + 12 | 0;
+  i25 = HEAP32[i25 >> 2] | 0;
+  _luaX_syntaxerror(i25, 10624);
+ } else if ((i18 | 0) == 90) {
+  i25 = i4 + 12 | 0;
+  i25 = HEAP32[i25 >> 2] | 0;
+  _luaX_syntaxerror(i25, 10624);
+ } else if ((i18 | 0) == 93) {
+  HEAP32[i6 >> 2] = -1;
+  HEAP32[i10 >> 2] = -1;
+  i25 = i1 + 8 | 0;
+  HEAP32[i25 >> 2] = i7;
+  HEAP32[i1 >> 2] = 6;
+  STACKTOP = i5;
+  return;
+ }
+}
+function _propagatemark(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i1 = STACKTOP;
+ i15 = i2 + 84 | 0;
+ i3 = HEAP32[i15 >> 2] | 0;
+ i10 = i3 + 5 | 0;
+ HEAP8[i10] = HEAPU8[i10] | 4;
+ switch (HEAPU8[i3 + 4 | 0] | 0) {
+ case 5:
+  {
+   i9 = i3 + 24 | 0;
+   HEAP32[i15 >> 2] = HEAP32[i9 >> 2];
+   i15 = i3 + 8 | 0;
+   i14 = HEAP32[i15 >> 2] | 0;
+   do {
+    if ((i14 | 0) != 0) {
+     if ((HEAP8[i14 + 6 | 0] & 8) == 0) {
+      i11 = _luaT_gettm(i14, 3, HEAP32[i2 + 196 >> 2] | 0) | 0;
+      i14 = HEAP32[i15 >> 2] | 0;
+      if ((i14 | 0) != 0) {
+       i6 = 5;
+      }
+     } else {
+      i11 = 0;
+      i6 = 5;
+     }
+     if ((i6 | 0) == 5) {
+      if (!((HEAP8[i14 + 5 | 0] & 3) == 0)) {
+       _reallymarkobject(i2, i14);
+      }
+     }
+     if (((i11 | 0) != 0 ? (HEAP32[i11 + 8 >> 2] & 15 | 0) == 4 : 0) ? (i13 = (HEAP32[i11 >> 2] | 0) + 16 | 0, i12 = _strchr(i13, 107) | 0, i12 = (i12 | 0) != 0, i13 = (_strchr(i13, 118) | 0) == 0, !(i13 & (i12 ^ 1))) : 0) {
+      HEAP8[i10] = HEAP8[i10] & 251;
+      if (i12) {
+       if (i13) {
+        _traverseephemeron(i2, i3) | 0;
+        break;
+       } else {
+        i15 = i2 + 100 | 0;
+        HEAP32[i9 >> 2] = HEAP32[i15 >> 2];
+        HEAP32[i15 >> 2] = i3;
+        break;
+       }
+      }
+      i15 = 1 << HEAPU8[i3 + 7 | 0];
+      i5 = HEAP32[i3 + 16 >> 2] | 0;
+      i4 = i5 + (i15 << 5) | 0;
+      i8 = (HEAP32[i3 + 28 >> 2] | 0) > 0 | 0;
+      if ((i15 | 0) > 0) {
+       do {
+        i12 = i5 + 8 | 0;
+        i10 = i5 + 24 | 0;
+        i11 = (HEAP32[i10 >> 2] & 64 | 0) == 0;
+        do {
+         if ((HEAP32[i12 >> 2] | 0) == 0) {
+          if (!i11 ? !((HEAP8[(HEAP32[i5 + 16 >> 2] | 0) + 5 | 0] & 3) == 0) : 0) {
+           HEAP32[i10 >> 2] = 11;
+          }
+         } else {
+          if (!i11 ? (i7 = HEAP32[i5 + 16 >> 2] | 0, !((HEAP8[i7 + 5 | 0] & 3) == 0)) : 0) {
+           _reallymarkobject(i2, i7);
+          }
+          if ((i8 | 0) == 0) {
+           i10 = HEAP32[i12 >> 2] | 0;
+           if ((i10 & 64 | 0) != 0) {
+            i8 = HEAP32[i5 >> 2] | 0;
+            if ((i10 & 15 | 0) != 4) {
+             i8 = (HEAP8[i8 + 5 | 0] & 3) != 0 | 0;
+             break;
+            }
+            if ((i8 | 0) != 0 ? !((HEAP8[i8 + 5 | 0] & 3) == 0) : 0) {
+             _reallymarkobject(i2, i8);
+             i8 = 0;
+            } else {
+             i8 = 0;
+            }
+           } else {
+            i8 = 0;
+           }
+          }
+         }
+        } while (0);
+        i5 = i5 + 32 | 0;
+       } while (i5 >>> 0 < i4 >>> 0);
+      }
+      if ((i8 | 0) == 0) {
+       i15 = i2 + 88 | 0;
+       HEAP32[i9 >> 2] = HEAP32[i15 >> 2];
+       HEAP32[i15 >> 2] = i3;
+       break;
+      } else {
+       i15 = i2 + 92 | 0;
+       HEAP32[i9 >> 2] = HEAP32[i15 >> 2];
+       HEAP32[i15 >> 2] = i3;
+       break;
+      }
+     } else {
+      i6 = 33;
+     }
+    } else {
+     i6 = 33;
+    }
+   } while (0);
+   if ((i6 | 0) == 33) {
+    i7 = i3 + 16 | 0;
+    i10 = HEAP32[i7 >> 2] | 0;
+    i6 = i10 + (1 << HEAPU8[i3 + 7 | 0] << 5) | 0;
+    i9 = i3 + 28 | 0;
+    i13 = HEAP32[i9 >> 2] | 0;
+    if ((i13 | 0) > 0) {
+     i10 = i3 + 12 | 0;
+     i11 = 0;
+     do {
+      i12 = HEAP32[i10 >> 2] | 0;
+      if ((HEAP32[i12 + (i11 << 4) + 8 >> 2] & 64 | 0) != 0 ? (i8 = HEAP32[i12 + (i11 << 4) >> 2] | 0, !((HEAP8[i8 + 5 | 0] & 3) == 0)) : 0) {
+       _reallymarkobject(i2, i8);
+       i13 = HEAP32[i9 >> 2] | 0;
+      }
+      i11 = i11 + 1 | 0;
+     } while ((i11 | 0) < (i13 | 0));
+     i7 = HEAP32[i7 >> 2] | 0;
+    } else {
+     i7 = i10;
+    }
+    if (i7 >>> 0 < i6 >>> 0) {
+     do {
+      i10 = i7 + 8 | 0;
+      i11 = HEAP32[i10 >> 2] | 0;
+      i9 = i7 + 24 | 0;
+      i8 = (HEAP32[i9 >> 2] & 64 | 0) == 0;
+      if ((i11 | 0) == 0) {
+       if (!i8 ? !((HEAP8[(HEAP32[i7 + 16 >> 2] | 0) + 5 | 0] & 3) == 0) : 0) {
+        HEAP32[i9 >> 2] = 11;
+       }
+      } else {
+       if (!i8 ? (i5 = HEAP32[i7 + 16 >> 2] | 0, !((HEAP8[i5 + 5 | 0] & 3) == 0)) : 0) {
+        _reallymarkobject(i2, i5);
+        i11 = HEAP32[i10 >> 2] | 0;
+       }
+       if ((i11 & 64 | 0) != 0 ? (i4 = HEAP32[i7 >> 2] | 0, !((HEAP8[i4 + 5 | 0] & 3) == 0)) : 0) {
+        _reallymarkobject(i2, i4);
+       }
+      }
+      i7 = i7 + 32 | 0;
+     } while (i7 >>> 0 < i6 >>> 0);
+    }
+   }
+   i3 = (HEAP32[i3 + 28 >> 2] << 4) + 32 + (32 << HEAPU8[i3 + 7 | 0]) | 0;
+   break;
+  }
+ case 8:
+  {
+   i7 = i3 + 60 | 0;
+   HEAP32[i15 >> 2] = HEAP32[i7 >> 2];
+   i4 = i2 + 88 | 0;
+   HEAP32[i7 >> 2] = HEAP32[i4 >> 2];
+   HEAP32[i4 >> 2] = i3;
+   HEAP8[i10] = HEAP8[i10] & 251;
+   i4 = i3 + 28 | 0;
+   i7 = HEAP32[i4 >> 2] | 0;
+   if ((i7 | 0) == 0) {
+    i3 = 1;
+   } else {
+    i5 = i3 + 8 | 0;
+    i6 = HEAP32[i5 >> 2] | 0;
+    if (i7 >>> 0 < i6 >>> 0) {
+     do {
+      if ((HEAP32[i7 + 8 >> 2] & 64 | 0) != 0 ? (i11 = HEAP32[i7 >> 2] | 0, !((HEAP8[i11 + 5 | 0] & 3) == 0)) : 0) {
+       _reallymarkobject(i2, i11);
+       i6 = HEAP32[i5 >> 2] | 0;
+      }
+      i7 = i7 + 16 | 0;
+     } while (i7 >>> 0 < i6 >>> 0);
+    }
+    if ((HEAP8[i2 + 61 | 0] | 0) == 1) {
+     i3 = i3 + 32 | 0;
+     i4 = (HEAP32[i4 >> 2] | 0) + (HEAP32[i3 >> 2] << 4) | 0;
+     if (i7 >>> 0 < i4 >>> 0) {
+      do {
+       HEAP32[i7 + 8 >> 2] = 0;
+       i7 = i7 + 16 | 0;
+      } while (i7 >>> 0 < i4 >>> 0);
+     }
+    } else {
+     i3 = i3 + 32 | 0;
+    }
+    i3 = (HEAP32[i3 >> 2] << 4) + 112 | 0;
+   }
+   break;
+  }
+ case 9:
+  {
+   HEAP32[i15 >> 2] = HEAP32[i3 + 72 >> 2];
+   i5 = i3 + 32 | 0;
+   i4 = HEAP32[i5 >> 2] | 0;
+   if ((i4 | 0) != 0 ? !((HEAP8[i4 + 5 | 0] & 3) == 0) : 0) {
+    HEAP32[i5 >> 2] = 0;
+   }
+   i4 = HEAP32[i3 + 36 >> 2] | 0;
+   if ((i4 | 0) != 0 ? !((HEAP8[i4 + 5 | 0] & 3) == 0) : 0) {
+    _reallymarkobject(i2, i4);
+   }
+   i4 = i3 + 44 | 0;
+   i8 = HEAP32[i4 >> 2] | 0;
+   if ((i8 | 0) > 0) {
+    i5 = i3 + 8 | 0;
+    i6 = 0;
+    do {
+     i7 = HEAP32[i5 >> 2] | 0;
+     if ((HEAP32[i7 + (i6 << 4) + 8 >> 2] & 64 | 0) != 0 ? (i9 = HEAP32[i7 + (i6 << 4) >> 2] | 0, !((HEAP8[i9 + 5 | 0] & 3) == 0)) : 0) {
+      _reallymarkobject(i2, i9);
+      i8 = HEAP32[i4 >> 2] | 0;
+     }
+     i6 = i6 + 1 | 0;
+    } while ((i6 | 0) < (i8 | 0));
+   }
+   i5 = i3 + 40 | 0;
+   i8 = HEAP32[i5 >> 2] | 0;
+   if ((i8 | 0) > 0) {
+    i6 = i3 + 28 | 0;
+    i7 = 0;
+    do {
+     i9 = HEAP32[(HEAP32[i6 >> 2] | 0) + (i7 << 3) >> 2] | 0;
+     if ((i9 | 0) != 0 ? !((HEAP8[i9 + 5 | 0] & 3) == 0) : 0) {
+      _reallymarkobject(i2, i9);
+      i8 = HEAP32[i5 >> 2] | 0;
+     }
+     i7 = i7 + 1 | 0;
+    } while ((i7 | 0) < (i8 | 0));
+   }
+   i6 = i3 + 56 | 0;
+   i8 = HEAP32[i6 >> 2] | 0;
+   if ((i8 | 0) > 0) {
+    i7 = i3 + 16 | 0;
+    i9 = 0;
+    do {
+     i10 = HEAP32[(HEAP32[i7 >> 2] | 0) + (i9 << 2) >> 2] | 0;
+     if ((i10 | 0) != 0 ? !((HEAP8[i10 + 5 | 0] & 3) == 0) : 0) {
+      _reallymarkobject(i2, i10);
+      i8 = HEAP32[i6 >> 2] | 0;
+     }
+     i9 = i9 + 1 | 0;
+    } while ((i9 | 0) < (i8 | 0));
+   }
+   i7 = i3 + 60 | 0;
+   i11 = HEAP32[i7 >> 2] | 0;
+   if ((i11 | 0) > 0) {
+    i8 = i3 + 24 | 0;
+    i9 = 0;
+    do {
+     i10 = HEAP32[(HEAP32[i8 >> 2] | 0) + (i9 * 12 | 0) >> 2] | 0;
+     if ((i10 | 0) != 0 ? !((HEAP8[i10 + 5 | 0] & 3) == 0) : 0) {
+      _reallymarkobject(i2, i10);
+      i11 = HEAP32[i7 >> 2] | 0;
+     }
+     i9 = i9 + 1 | 0;
+    } while ((i9 | 0) < (i11 | 0));
+    i8 = HEAP32[i6 >> 2] | 0;
+   }
+   i3 = (i11 * 12 | 0) + 80 + (HEAP32[i4 >> 2] << 4) + (HEAP32[i5 >> 2] << 3) + ((HEAP32[i3 + 48 >> 2] | 0) + i8 + (HEAP32[i3 + 52 >> 2] | 0) << 2) | 0;
+   break;
+  }
+ case 38:
+  {
+   HEAP32[i15 >> 2] = HEAP32[i3 + 8 >> 2];
+   i4 = i3 + 6 | 0;
+   i5 = HEAP8[i4] | 0;
+   if (i5 << 24 >> 24 == 0) {
+    i7 = i5 & 255;
+   } else {
+    i6 = 0;
+    do {
+     if ((HEAP32[i3 + (i6 << 4) + 24 >> 2] & 64 | 0) != 0 ? (i14 = HEAP32[i3 + (i6 << 4) + 16 >> 2] | 0, !((HEAP8[i14 + 5 | 0] & 3) == 0)) : 0) {
+      _reallymarkobject(i2, i14);
+      i5 = HEAP8[i4] | 0;
+     }
+     i6 = i6 + 1 | 0;
+     i7 = i5 & 255;
+    } while ((i6 | 0) < (i7 | 0));
+   }
+   i3 = (i7 << 4) + 16 | 0;
+   break;
+  }
+ case 6:
+  {
+   HEAP32[i15 >> 2] = HEAP32[i3 + 8 >> 2];
+   i4 = HEAP32[i3 + 12 >> 2] | 0;
+   if ((i4 | 0) != 0 ? !((HEAP8[i4 + 5 | 0] & 3) == 0) : 0) {
+    _reallymarkobject(i2, i4);
+   }
+   i4 = i3 + 6 | 0;
+   i6 = HEAP8[i4] | 0;
+   if (i6 << 24 >> 24 == 0) {
+    i7 = i6 & 255;
+   } else {
+    i5 = 0;
+    do {
+     i7 = HEAP32[i3 + (i5 << 2) + 16 >> 2] | 0;
+     if ((i7 | 0) != 0 ? !((HEAP8[i7 + 5 | 0] & 3) == 0) : 0) {
+      _reallymarkobject(i2, i7);
+      i6 = HEAP8[i4] | 0;
+     }
+     i5 = i5 + 1 | 0;
+     i7 = i6 & 255;
+    } while ((i5 | 0) < (i7 | 0));
+   }
+   i3 = (i7 << 2) + 16 | 0;
+   break;
+  }
+ default:
+  {
+   STACKTOP = i1;
+   return;
+  }
+ }
+ i15 = i2 + 16 | 0;
+ HEAP32[i15 >> 2] = (HEAP32[i15 >> 2] | 0) + i3;
+ STACKTOP = i1;
+ return;
+}
+function _strstr(i8, i4) {
+ i8 = i8 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i6 = i1 + 1024 | 0;
+ i2 = i1;
+ i10 = HEAP8[i4] | 0;
+ if (i10 << 24 >> 24 == 0) {
+  i20 = i8;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ i8 = _strchr(i8, i10 << 24 >> 24) | 0;
+ if ((i8 | 0) == 0) {
+  i20 = 0;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ i13 = HEAP8[i4 + 1 | 0] | 0;
+ if (i13 << 24 >> 24 == 0) {
+  i20 = i8;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ i11 = i8 + 1 | 0;
+ i9 = HEAP8[i11] | 0;
+ if (i9 << 24 >> 24 == 0) {
+  i20 = 0;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ i15 = HEAP8[i4 + 2 | 0] | 0;
+ if (i15 << 24 >> 24 == 0) {
+  i2 = i13 & 255 | (i10 & 255) << 8;
+  i3 = i9;
+  i4 = HEAPU8[i8] << 8 | i9 & 255;
+  while (1) {
+   i5 = i4 & 65535;
+   if ((i5 | 0) == (i2 | 0)) {
+    break;
+   }
+   i11 = i11 + 1 | 0;
+   i4 = HEAP8[i11] | 0;
+   if (i4 << 24 >> 24 == 0) {
+    i3 = 0;
+    break;
+   } else {
+    i3 = i4;
+    i4 = i4 & 255 | i5 << 8;
+   }
+  }
+  i20 = i3 << 24 >> 24 == 0 ? 0 : i11 + -1 | 0;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ i16 = i8 + 2 | 0;
+ i11 = HEAP8[i16] | 0;
+ if (i11 << 24 >> 24 == 0) {
+  i20 = 0;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ i18 = HEAP8[i4 + 3 | 0] | 0;
+ if (i18 << 24 >> 24 == 0) {
+  i2 = (i13 & 255) << 16 | (i10 & 255) << 24 | (i15 & 255) << 8;
+  i4 = (i11 & 255) << 8 | (i9 & 255) << 16 | HEAPU8[i8] << 24;
+  if ((i4 | 0) == (i2 | 0)) {
+   i3 = 0;
+  } else {
+   do {
+    i16 = i16 + 1 | 0;
+    i3 = HEAP8[i16] | 0;
+    i4 = (i3 & 255 | i4) << 8;
+    i3 = i3 << 24 >> 24 == 0;
+   } while (!(i3 | (i4 | 0) == (i2 | 0)));
+  }
+  i20 = i3 ? 0 : i16 + -2 | 0;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ i16 = i8 + 3 | 0;
+ i17 = HEAP8[i16] | 0;
+ if (i17 << 24 >> 24 == 0) {
+  i20 = 0;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ if ((HEAP8[i4 + 4 | 0] | 0) == 0) {
+  i2 = (i13 & 255) << 16 | (i10 & 255) << 24 | (i15 & 255) << 8 | i18 & 255;
+  i3 = (i11 & 255) << 8 | (i9 & 255) << 16 | i17 & 255 | HEAPU8[i8] << 24;
+  if ((i3 | 0) == (i2 | 0)) {
+   i4 = 0;
+  } else {
+   do {
+    i16 = i16 + 1 | 0;
+    i4 = HEAP8[i16] | 0;
+    i3 = i4 & 255 | i3 << 8;
+    i4 = i4 << 24 >> 24 == 0;
+   } while (!(i4 | (i3 | 0) == (i2 | 0)));
+  }
+  i20 = i4 ? 0 : i16 + -3 | 0;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ HEAP32[i6 + 0 >> 2] = 0;
+ HEAP32[i6 + 4 >> 2] = 0;
+ HEAP32[i6 + 8 >> 2] = 0;
+ HEAP32[i6 + 12 >> 2] = 0;
+ HEAP32[i6 + 16 >> 2] = 0;
+ HEAP32[i6 + 20 >> 2] = 0;
+ HEAP32[i6 + 24 >> 2] = 0;
+ HEAP32[i6 + 28 >> 2] = 0;
+ i9 = 0;
+ while (1) {
+  if ((HEAP8[i8 + i9 | 0] | 0) == 0) {
+   i14 = 0;
+   i12 = 80;
+   break;
+  }
+  i20 = i10 & 255;
+  i3 = i6 + (i20 >>> 5 << 2) | 0;
+  HEAP32[i3 >> 2] = HEAP32[i3 >> 2] | 1 << (i20 & 31);
+  i3 = i9 + 1 | 0;
+  HEAP32[i2 + (i20 << 2) >> 2] = i3;
+  i10 = HEAP8[i4 + i3 | 0] | 0;
+  if (i10 << 24 >> 24 == 0) {
+   break;
+  } else {
+   i9 = i3;
+  }
+ }
+ if ((i12 | 0) == 80) {
+  STACKTOP = i1;
+  return i14 | 0;
+ }
+ L49 : do {
+  if (i3 >>> 0 > 1) {
+   i14 = 1;
+   i11 = -1;
+   i12 = 0;
+   L50 : while (1) {
+    i10 = 1;
+    while (1) {
+     i13 = i14;
+     L54 : while (1) {
+      i14 = 1;
+      while (1) {
+       i15 = HEAP8[i4 + (i14 + i11) | 0] | 0;
+       i16 = HEAP8[i4 + i13 | 0] | 0;
+       if (!(i15 << 24 >> 24 == i16 << 24 >> 24)) {
+        break L54;
+       }
+       i15 = i14 + 1 | 0;
+       if ((i14 | 0) == (i10 | 0)) {
+        break;
+       }
+       i13 = i15 + i12 | 0;
+       if (i13 >>> 0 < i3 >>> 0) {
+        i14 = i15;
+       } else {
+        break L50;
+       }
+      }
+      i12 = i12 + i10 | 0;
+      i13 = i12 + 1 | 0;
+      if (!(i13 >>> 0 < i3 >>> 0)) {
+       break L50;
+      }
+     }
+     i10 = i13 - i11 | 0;
+     if (!((i15 & 255) > (i16 & 255))) {
+      break;
+     }
+     i14 = i13 + 1 | 0;
+     if (i14 >>> 0 < i3 >>> 0) {
+      i12 = i13;
+     } else {
+      break L50;
+     }
+    }
+    i14 = i12 + 2 | 0;
+    if (i14 >>> 0 < i3 >>> 0) {
+     i11 = i12;
+     i12 = i12 + 1 | 0;
+    } else {
+     i11 = i12;
+     i10 = 1;
+     break;
+    }
+   }
+   i16 = 1;
+   i12 = -1;
+   i14 = 0;
+   while (1) {
+    i13 = 1;
+    while (1) {
+     i15 = i16;
+     L69 : while (1) {
+      i18 = 1;
+      while (1) {
+       i17 = HEAP8[i4 + (i18 + i12) | 0] | 0;
+       i16 = HEAP8[i4 + i15 | 0] | 0;
+       if (!(i17 << 24 >> 24 == i16 << 24 >> 24)) {
+        break L69;
+       }
+       i16 = i18 + 1 | 0;
+       if ((i18 | 0) == (i13 | 0)) {
+        break;
+       }
+       i15 = i16 + i14 | 0;
+       if (i15 >>> 0 < i3 >>> 0) {
+        i18 = i16;
+       } else {
+        i14 = i12;
+        break L49;
+       }
+      }
+      i14 = i14 + i13 | 0;
+      i15 = i14 + 1 | 0;
+      if (!(i15 >>> 0 < i3 >>> 0)) {
+       i14 = i12;
+       break L49;
+      }
+     }
+     i13 = i15 - i12 | 0;
+     if (!((i17 & 255) < (i16 & 255))) {
+      break;
+     }
+     i16 = i15 + 1 | 0;
+     if (i16 >>> 0 < i3 >>> 0) {
+      i14 = i15;
+     } else {
+      i14 = i12;
+      break L49;
+     }
+    }
+    i16 = i14 + 2 | 0;
+    if (i16 >>> 0 < i3 >>> 0) {
+     i12 = i14;
+     i14 = i14 + 1 | 0;
+    } else {
+     i13 = 1;
+     break;
+    }
+   }
+  } else {
+   i11 = -1;
+   i14 = -1;
+   i10 = 1;
+   i13 = 1;
+  }
+ } while (0);
+ i15 = (i14 + 1 | 0) >>> 0 > (i11 + 1 | 0) >>> 0;
+ i12 = i15 ? i13 : i10;
+ i11 = i15 ? i14 : i11;
+ i10 = i11 + 1 | 0;
+ if ((_memcmp(i4, i4 + i12 | 0, i10) | 0) == 0) {
+  i15 = i3 - i12 | 0;
+  i16 = i3 | 63;
+  if ((i3 | 0) != (i12 | 0)) {
+   i14 = i8;
+   i13 = 0;
+   i17 = i8;
+   L82 : while (1) {
+    i18 = i14;
+    do {
+     if ((i17 - i18 | 0) >>> 0 < i3 >>> 0) {
+      i19 = _memchr(i17, 0, i16) | 0;
+      if ((i19 | 0) != 0) {
+       if ((i19 - i18 | 0) >>> 0 < i3 >>> 0) {
+        i14 = 0;
+        i12 = 80;
+        break L82;
+       } else {
+        i17 = i19;
+        break;
+       }
+      } else {
+       i17 = i17 + i16 | 0;
+       break;
+      }
+     }
+    } while (0);
+    i18 = HEAPU8[i14 + i9 | 0] | 0;
+    if ((1 << (i18 & 31) & HEAP32[i6 + (i18 >>> 5 << 2) >> 2] | 0) == 0) {
+     i14 = i14 + i3 | 0;
+     i13 = 0;
+     continue;
+    }
+    i20 = HEAP32[i2 + (i18 << 2) >> 2] | 0;
+    i18 = i3 - i20 | 0;
+    if ((i3 | 0) != (i20 | 0)) {
+     i14 = i14 + ((i13 | 0) != 0 & i18 >>> 0 < i12 >>> 0 ? i15 : i18) | 0;
+     i13 = 0;
+     continue;
+    }
+    i20 = i10 >>> 0 > i13 >>> 0 ? i10 : i13;
+    i18 = HEAP8[i4 + i20 | 0] | 0;
+    L96 : do {
+     if (i18 << 24 >> 24 == 0) {
+      i19 = i10;
+     } else {
+      while (1) {
+       i19 = i20 + 1 | 0;
+       if (!(i18 << 24 >> 24 == (HEAP8[i14 + i20 | 0] | 0))) {
+        break;
+       }
+       i18 = HEAP8[i4 + i19 | 0] | 0;
+       if (i18 << 24 >> 24 == 0) {
+        i19 = i10;
+        break L96;
+       } else {
+        i20 = i19;
+       }
+      }
+      i14 = i14 + (i20 - i11) | 0;
+      i13 = 0;
+      continue L82;
+     }
+    } while (0);
+    while (1) {
+     if (!(i19 >>> 0 > i13 >>> 0)) {
+      break;
+     }
+     i18 = i19 + -1 | 0;
+     if ((HEAP8[i4 + i18 | 0] | 0) == (HEAP8[i14 + i18 | 0] | 0)) {
+      i19 = i18;
+     } else {
+      break;
+     }
+    }
+    if ((i19 | 0) == (i13 | 0)) {
+     i12 = 80;
+     break;
+    }
+    i14 = i14 + i12 | 0;
+    i13 = i15;
+   }
+   if ((i12 | 0) == 80) {
+    STACKTOP = i1;
+    return i14 | 0;
+   }
+  } else {
+   i5 = i16;
+   i7 = i3;
+  }
+ } else {
+  i7 = i3 - i11 + -1 | 0;
+  i5 = i3 | 63;
+  i7 = (i11 >>> 0 > i7 >>> 0 ? i11 : i7) + 1 | 0;
+ }
+ i12 = i4 + i10 | 0;
+ i14 = i8;
+ L111 : while (1) {
+  i13 = i14;
+  do {
+   if ((i8 - i13 | 0) >>> 0 < i3 >>> 0) {
+    i15 = _memchr(i8, 0, i5) | 0;
+    if ((i15 | 0) != 0) {
+     if ((i15 - i13 | 0) >>> 0 < i3 >>> 0) {
+      i14 = 0;
+      i12 = 80;
+      break L111;
+     } else {
+      i8 = i15;
+      break;
+     }
+    } else {
+     i8 = i8 + i5 | 0;
+     break;
+    }
+   }
+  } while (0);
+  i13 = HEAPU8[i14 + i9 | 0] | 0;
+  if ((1 << (i13 & 31) & HEAP32[i6 + (i13 >>> 5 << 2) >> 2] | 0) == 0) {
+   i14 = i14 + i3 | 0;
+   continue;
+  }
+  i13 = HEAP32[i2 + (i13 << 2) >> 2] | 0;
+  if ((i3 | 0) != (i13 | 0)) {
+   i14 = i14 + (i3 - i13) | 0;
+   continue;
+  }
+  i15 = HEAP8[i12] | 0;
+  L125 : do {
+   if (i15 << 24 >> 24 == 0) {
+    i13 = i10;
+   } else {
+    i16 = i10;
+    while (1) {
+     i13 = i16 + 1 | 0;
+     if (!(i15 << 24 >> 24 == (HEAP8[i14 + i16 | 0] | 0))) {
+      break;
+     }
+     i15 = HEAP8[i4 + i13 | 0] | 0;
+     if (i15 << 24 >> 24 == 0) {
+      i13 = i10;
+      break L125;
+     } else {
+      i16 = i13;
+     }
+    }
+    i14 = i14 + (i16 - i11) | 0;
+    continue L111;
+   }
+  } while (0);
+  do {
+   if ((i13 | 0) == 0) {
+    i12 = 80;
+    break L111;
+   }
+   i13 = i13 + -1 | 0;
+  } while ((HEAP8[i4 + i13 | 0] | 0) == (HEAP8[i14 + i13 | 0] | 0));
+  i14 = i14 + i7 | 0;
+ }
+ if ((i12 | 0) == 80) {
+  STACKTOP = i1;
+  return i14 | 0;
+ }
+ return 0;
+}
+function _str_format(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, d21 = 0.0, i22 = 0;
+ i12 = STACKTOP;
+ STACKTOP = STACKTOP + 1104 | 0;
+ i4 = i12;
+ i7 = i12 + 1060 | 0;
+ i9 = i12 + 1082 | 0;
+ i20 = i12 + 1056 | 0;
+ i10 = i12 + 16 | 0;
+ i5 = i12 + 1064 | 0;
+ i6 = i12 + 8 | 0;
+ i8 = _lua_gettop(i2) | 0;
+ i16 = _luaL_checklstring(i2, 1, i20) | 0;
+ i20 = HEAP32[i20 >> 2] | 0;
+ i3 = i16 + i20 | 0;
+ _luaL_buffinit(i2, i10);
+ L1 : do {
+  if ((i20 | 0) > 0) {
+   i1 = i10 + 8 | 0;
+   i13 = i10 + 4 | 0;
+   i14 = i5 + 1 | 0;
+   i19 = 1;
+   L3 : while (1) {
+    while (1) {
+     i15 = HEAP8[i16] | 0;
+     if (i15 << 24 >> 24 == 37) {
+      i18 = i16 + 1 | 0;
+      if ((HEAP8[i18] | 0) != 37) {
+       break;
+      }
+      i15 = HEAP32[i1 >> 2] | 0;
+      if (i15 >>> 0 < (HEAP32[i13 >> 2] | 0) >>> 0) {
+       i17 = 37;
+      } else {
+       _luaL_prepbuffsize(i10, 1) | 0;
+       i15 = HEAP32[i1 >> 2] | 0;
+       i17 = HEAP8[i18] | 0;
+      }
+      HEAP32[i1 >> 2] = i15 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i15 | 0] = i17;
+      i16 = i16 + 2 | 0;
+     } else {
+      i17 = HEAP32[i1 >> 2] | 0;
+      if (!(i17 >>> 0 < (HEAP32[i13 >> 2] | 0) >>> 0)) {
+       _luaL_prepbuffsize(i10, 1) | 0;
+       i17 = HEAP32[i1 >> 2] | 0;
+       i15 = HEAP8[i16] | 0;
+      }
+      HEAP32[i1 >> 2] = i17 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i17 | 0] = i15;
+      i16 = i16 + 1 | 0;
+     }
+     if (!(i16 >>> 0 < i3 >>> 0)) {
+      break L1;
+     }
+    }
+    i17 = _luaL_prepbuffsize(i10, 512) | 0;
+    i15 = i19 + 1 | 0;
+    if ((i19 | 0) >= (i8 | 0)) {
+     _luaL_argerror(i2, i15, 7648) | 0;
+    }
+    i19 = HEAP8[i18] | 0;
+    L22 : do {
+     if (i19 << 24 >> 24 == 0) {
+      i19 = 0;
+      i20 = i18;
+     } else {
+      i20 = i18;
+      while (1) {
+       i16 = i20 + 1 | 0;
+       if ((_memchr(7800, i19 << 24 >> 24, 6) | 0) == 0) {
+        break L22;
+       }
+       i19 = HEAP8[i16] | 0;
+       if (i19 << 24 >> 24 == 0) {
+        i19 = 0;
+        i20 = i16;
+        break;
+       } else {
+        i20 = i16;
+       }
+      }
+     }
+    } while (0);
+    i16 = i18;
+    if ((i20 - i16 | 0) >>> 0 > 5) {
+     _luaL_error(i2, 7808, i4) | 0;
+     i19 = HEAP8[i20] | 0;
+    }
+    i19 = ((i19 & 255) + -48 | 0) >>> 0 < 10 ? i20 + 1 | 0 : i20;
+    i19 = ((HEAPU8[i19] | 0) + -48 | 0) >>> 0 < 10 ? i19 + 1 | 0 : i19;
+    i20 = HEAP8[i19] | 0;
+    if (i20 << 24 >> 24 == 46) {
+     i20 = i19 + 1 | 0;
+     i19 = ((HEAPU8[i20] | 0) + -48 | 0) >>> 0 < 10 ? i19 + 2 | 0 : i20;
+     i19 = ((HEAPU8[i19] | 0) + -48 | 0) >>> 0 < 10 ? i19 + 1 | 0 : i19;
+     i20 = HEAP8[i19] | 0;
+    }
+    if (((i20 & 255) + -48 | 0) >>> 0 < 10) {
+     _luaL_error(i2, 7840, i4) | 0;
+    }
+    HEAP8[i5] = 37;
+    i16 = i19 - i16 | 0;
+    _memcpy(i14 | 0, i18 | 0, i16 + 1 | 0) | 0;
+    HEAP8[i5 + (i16 + 2) | 0] = 0;
+    i16 = i19 + 1 | 0;
+    i18 = HEAP8[i19] | 0;
+    L36 : do {
+     switch (i18 | 0) {
+     case 115:
+      {
+       i18 = _luaL_tolstring(i2, i15, i6) | 0;
+       if ((_strchr(i5, 46) | 0) == 0 ? (HEAP32[i6 >> 2] | 0) >>> 0 > 99 : 0) {
+        _luaL_addvalue(i10);
+        i17 = 0;
+        break L36;
+       }
+       HEAP32[i4 >> 2] = i18;
+       i17 = _sprintf(i17 | 0, i5 | 0, i4 | 0) | 0;
+       _lua_settop(i2, -2);
+       break;
+      }
+     case 88:
+     case 120:
+     case 117:
+     case 111:
+      {
+       d21 = +_luaL_checknumber(i2, i15);
+       i18 = ~~d21 >>> 0;
+       d21 = d21 - +(i18 >>> 0);
+       if (!(d21 > -1.0 & d21 < 1.0)) {
+        _luaL_argerror(i2, i15, 7696) | 0;
+       }
+       i20 = _strlen(i5 | 0) | 0;
+       i22 = i5 + (i20 + -1) | 0;
+       i19 = HEAP8[i22] | 0;
+       HEAP8[i22] = 108;
+       HEAP8[i22 + 1 | 0] = 0;
+       HEAP8[i5 + i20 | 0] = i19;
+       HEAP8[i5 + (i20 + 1) | 0] = 0;
+       HEAP32[i4 >> 2] = i18;
+       i17 = _sprintf(i17 | 0, i5 | 0, i4 | 0) | 0;
+       break;
+      }
+     case 99:
+      {
+       HEAP32[i4 >> 2] = _luaL_checkinteger(i2, i15) | 0;
+       i17 = _sprintf(i17 | 0, i5 | 0, i4 | 0) | 0;
+       break;
+      }
+     case 113:
+      {
+       i17 = _luaL_checklstring(i2, i15, i7) | 0;
+       i18 = HEAP32[i1 >> 2] | 0;
+       if (!(i18 >>> 0 < (HEAP32[i13 >> 2] | 0) >>> 0)) {
+        _luaL_prepbuffsize(i10, 1) | 0;
+        i18 = HEAP32[i1 >> 2] | 0;
+       }
+       HEAP32[i1 >> 2] = i18 + 1;
+       HEAP8[(HEAP32[i10 >> 2] | 0) + i18 | 0] = 34;
+       i22 = HEAP32[i7 >> 2] | 0;
+       HEAP32[i7 >> 2] = i22 + -1;
+       if ((i22 | 0) != 0) {
+        while (1) {
+         i18 = HEAP8[i17] | 0;
+         do {
+          if (i18 << 24 >> 24 == 10 | i18 << 24 >> 24 == 92 | i18 << 24 >> 24 == 34) {
+           i18 = HEAP32[i1 >> 2] | 0;
+           if (!(i18 >>> 0 < (HEAP32[i13 >> 2] | 0) >>> 0)) {
+            _luaL_prepbuffsize(i10, 1) | 0;
+            i18 = HEAP32[i1 >> 2] | 0;
+           }
+           HEAP32[i1 >> 2] = i18 + 1;
+           HEAP8[(HEAP32[i10 >> 2] | 0) + i18 | 0] = 92;
+           i18 = HEAP32[i1 >> 2] | 0;
+           if (!(i18 >>> 0 < (HEAP32[i13 >> 2] | 0) >>> 0)) {
+            _luaL_prepbuffsize(i10, 1) | 0;
+            i18 = HEAP32[i1 >> 2] | 0;
+           }
+           i22 = HEAP8[i17] | 0;
+           HEAP32[i1 >> 2] = i18 + 1;
+           HEAP8[(HEAP32[i10 >> 2] | 0) + i18 | 0] = i22;
+          } else if (i18 << 24 >> 24 == 0) {
+           i18 = 0;
+           i11 = 44;
+          } else {
+           if ((_iscntrl(i18 & 255 | 0) | 0) != 0) {
+            i18 = HEAP8[i17] | 0;
+            i11 = 44;
+            break;
+           }
+           i18 = HEAP32[i1 >> 2] | 0;
+           if (!(i18 >>> 0 < (HEAP32[i13 >> 2] | 0) >>> 0)) {
+            _luaL_prepbuffsize(i10, 1) | 0;
+            i18 = HEAP32[i1 >> 2] | 0;
+           }
+           i22 = HEAP8[i17] | 0;
+           HEAP32[i1 >> 2] = i18 + 1;
+           HEAP8[(HEAP32[i10 >> 2] | 0) + i18 | 0] = i22;
+          }
+         } while (0);
+         if ((i11 | 0) == 44) {
+          i11 = 0;
+          i18 = i18 & 255;
+          if (((HEAPU8[i17 + 1 | 0] | 0) + -48 | 0) >>> 0 < 10) {
+           HEAP32[i4 >> 2] = i18;
+           _sprintf(i9 | 0, 7792, i4 | 0) | 0;
+          } else {
+           HEAP32[i4 >> 2] = i18;
+           _sprintf(i9 | 0, 7784, i4 | 0) | 0;
+          }
+          _luaL_addstring(i10, i9);
+         }
+         i22 = HEAP32[i7 >> 2] | 0;
+         HEAP32[i7 >> 2] = i22 + -1;
+         if ((i22 | 0) == 0) {
+          break;
+         } else {
+          i17 = i17 + 1 | 0;
+         }
+        }
+       }
+       i17 = HEAP32[i1 >> 2] | 0;
+       if (!(i17 >>> 0 < (HEAP32[i13 >> 2] | 0) >>> 0)) {
+        _luaL_prepbuffsize(i10, 1) | 0;
+        i17 = HEAP32[i1 >> 2] | 0;
+       }
+       HEAP32[i1 >> 2] = i17 + 1;
+       HEAP8[(HEAP32[i10 >> 2] | 0) + i17 | 0] = 34;
+       i17 = 0;
+       break;
+      }
+     case 71:
+     case 103:
+     case 102:
+     case 69:
+     case 101:
+      {
+       HEAP8[i5 + (_strlen(i5 | 0) | 0) | 0] = 0;
+       d21 = +_luaL_checknumber(i2, i15);
+       HEAPF64[tempDoublePtr >> 3] = d21;
+       HEAP32[i4 >> 2] = HEAP32[tempDoublePtr >> 2];
+       HEAP32[i4 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+       i17 = _sprintf(i17 | 0, i5 | 0, i4 | 0) | 0;
+       break;
+      }
+     case 105:
+     case 100:
+      {
+       d21 = +_luaL_checknumber(i2, i15);
+       i18 = ~~d21;
+       d21 = d21 - +(i18 | 0);
+       if (!(d21 > -1.0 & d21 < 1.0)) {
+        _luaL_argerror(i2, i15, 7664) | 0;
+       }
+       i22 = _strlen(i5 | 0) | 0;
+       i19 = i5 + (i22 + -1) | 0;
+       i20 = HEAP8[i19] | 0;
+       HEAP8[i19] = 108;
+       HEAP8[i19 + 1 | 0] = 0;
+       HEAP8[i5 + i22 | 0] = i20;
+       HEAP8[i5 + (i22 + 1) | 0] = 0;
+       HEAP32[i4 >> 2] = i18;
+       i17 = _sprintf(i17 | 0, i5 | 0, i4 | 0) | 0;
+       break;
+      }
+     default:
+      {
+       break L3;
+      }
+     }
+    } while (0);
+    HEAP32[i1 >> 2] = (HEAP32[i1 >> 2] | 0) + i17;
+    if (i16 >>> 0 < i3 >>> 0) {
+     i19 = i15;
+    } else {
+     break L1;
+    }
+   }
+   HEAP32[i4 >> 2] = i18;
+   i22 = _luaL_error(i2, 7744, i4) | 0;
+   STACKTOP = i12;
+   return i22 | 0;
+  }
+ } while (0);
+ _luaL_pushresult(i10);
+ i22 = 1;
+ STACKTOP = i12;
+ return i22 | 0;
+}
+function _luaD_precall(i3, i17, i4) {
+ i3 = i3 | 0;
+ i17 = i17 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i8 = i1;
+ i6 = i3 + 28 | 0;
+ i2 = i3 + 8 | 0;
+ i13 = i3 + 24 | 0;
+ i14 = i3 + 32 | 0;
+ while (1) {
+  i15 = HEAP32[i6 >> 2] | 0;
+  i16 = i17;
+  i12 = i15;
+  i5 = i16 - i12 | 0;
+  i11 = HEAP32[i17 + 8 >> 2] & 63;
+  if ((i11 | 0) == 38) {
+   i11 = 4;
+   break;
+  } else if ((i11 | 0) == 22) {
+   i11 = 3;
+   break;
+  } else if ((i11 | 0) == 6) {
+   i11 = 31;
+   break;
+  }
+  i11 = _luaT_gettmbyobj(i3, i17, 16) | 0;
+  i15 = i16 - (HEAP32[i6 >> 2] | 0) | 0;
+  i16 = i11 + 8 | 0;
+  if ((HEAP32[i16 >> 2] & 15 | 0) != 6) {
+   i11 = 54;
+   break;
+  }
+  i19 = HEAP32[i2 >> 2] | 0;
+  if (i19 >>> 0 > i17 >>> 0) {
+   while (1) {
+    i18 = i19 + -16 | 0;
+    i22 = i18;
+    i21 = HEAP32[i22 + 4 >> 2] | 0;
+    i20 = i19;
+    HEAP32[i20 >> 2] = HEAP32[i22 >> 2];
+    HEAP32[i20 + 4 >> 2] = i21;
+    HEAP32[i19 + 8 >> 2] = HEAP32[i19 + -8 >> 2];
+    if (i18 >>> 0 > i17 >>> 0) {
+     i19 = i18;
+    } else {
+     break;
+    }
+   }
+   i19 = HEAP32[i2 >> 2] | 0;
+  }
+  i17 = i19 + 16 | 0;
+  HEAP32[i2 >> 2] = i17;
+  if (((HEAP32[i13 >> 2] | 0) - i17 | 0) < 16) {
+   i18 = HEAP32[i14 >> 2] | 0;
+   if ((i18 | 0) > 1e6) {
+    i11 = 60;
+    break;
+   }
+   i17 = (i17 - (HEAP32[i6 >> 2] | 0) >> 4) + 5 | 0;
+   i18 = i18 << 1;
+   i18 = (i18 | 0) > 1e6 ? 1e6 : i18;
+   i17 = (i18 | 0) < (i17 | 0) ? i17 : i18;
+   if ((i17 | 0) > 1e6) {
+    i11 = 62;
+    break;
+   }
+   _luaD_reallocstack(i3, i17);
+  }
+  i22 = HEAP32[i6 >> 2] | 0;
+  i17 = i22 + i15 | 0;
+  i19 = i11;
+  i20 = HEAP32[i19 + 4 >> 2] | 0;
+  i21 = i17;
+  HEAP32[i21 >> 2] = HEAP32[i19 >> 2];
+  HEAP32[i21 + 4 >> 2] = i20;
+  HEAP32[i22 + (i15 + 8) >> 2] = HEAP32[i16 >> 2];
+ }
+ if ((i11 | 0) == 3) {
+  i10 = i17;
+ } else if ((i11 | 0) == 4) {
+  i10 = (HEAP32[i17 >> 2] | 0) + 12 | 0;
+ } else if ((i11 | 0) == 31) {
+  i10 = HEAP32[(HEAP32[i17 >> 2] | 0) + 12 >> 2] | 0;
+  i18 = HEAP32[i2 >> 2] | 0;
+  i16 = i18;
+  i11 = i10 + 78 | 0;
+  i17 = HEAPU8[i11] | 0;
+  do {
+   if (((HEAP32[i13 >> 2] | 0) - i16 >> 4 | 0) <= (i17 | 0)) {
+    i13 = HEAP32[i14 >> 2] | 0;
+    if ((i13 | 0) > 1e6) {
+     _luaD_throw(i3, 6);
+    }
+    i12 = i17 + 5 + (i16 - i12 >> 4) | 0;
+    i13 = i13 << 1;
+    i13 = (i13 | 0) > 1e6 ? 1e6 : i13;
+    i12 = (i13 | 0) < (i12 | 0) ? i12 : i13;
+    if ((i12 | 0) > 1e6) {
+     _luaD_reallocstack(i3, 1000200);
+     _luaG_runerror(i3, 2224, i8);
+    } else {
+     _luaD_reallocstack(i3, i12);
+     i7 = HEAP32[i6 >> 2] | 0;
+     i9 = HEAP32[i2 >> 2] | 0;
+     break;
+    }
+   } else {
+    i7 = i15;
+    i9 = i18;
+   }
+  } while (0);
+  i6 = i7 + i5 | 0;
+  i22 = i9 - i6 >> 4;
+  i12 = i22 + -1 | 0;
+  i8 = i10 + 76 | 0;
+  i13 = HEAP8[i8] | 0;
+  if ((i22 | 0) > (i13 & 255 | 0)) {
+   i8 = i13;
+  } else {
+   i13 = i9;
+   while (1) {
+    i9 = i13 + 16 | 0;
+    HEAP32[i2 >> 2] = i9;
+    HEAP32[i13 + 8 >> 2] = 0;
+    i12 = i12 + 1 | 0;
+    i13 = HEAP8[i8] | 0;
+    if ((i12 | 0) < (i13 & 255 | 0)) {
+     i13 = i9;
+    } else {
+     i8 = i13;
+     break;
+    }
+   }
+  }
+  if ((HEAP8[i10 + 77 | 0] | 0) != 0) {
+   i5 = i8 & 255;
+   if (!(i8 << 24 >> 24 == 0) ? (i22 = 0 - i12 | 0, HEAP32[i2 >> 2] = i9 + 16, i19 = i9 + (i22 << 4) | 0, i20 = HEAP32[i19 + 4 >> 2] | 0, i21 = i9, HEAP32[i21 >> 2] = HEAP32[i19 >> 2], HEAP32[i21 + 4 >> 2] = i20, i22 = i9 + (i22 << 4) + 8 | 0, HEAP32[i9 + 8 >> 2] = HEAP32[i22 >> 2], HEAP32[i22 >> 2] = 0, (i8 & 255) > 1) : 0) {
+    i7 = 1;
+    do {
+     i21 = HEAP32[i2 >> 2] | 0;
+     i22 = i7 - i12 | 0;
+     HEAP32[i2 >> 2] = i21 + 16;
+     i18 = i9 + (i22 << 4) | 0;
+     i19 = HEAP32[i18 + 4 >> 2] | 0;
+     i20 = i21;
+     HEAP32[i20 >> 2] = HEAP32[i18 >> 2];
+     HEAP32[i20 + 4 >> 2] = i19;
+     i22 = i9 + (i22 << 4) + 8 | 0;
+     HEAP32[i21 + 8 >> 2] = HEAP32[i22 >> 2];
+     HEAP32[i22 >> 2] = 0;
+     i7 = i7 + 1 | 0;
+    } while ((i7 | 0) < (i5 | 0));
+   }
+  } else {
+   i9 = i7 + (i5 + 16) | 0;
+  }
+  i7 = i3 + 16 | 0;
+  i5 = HEAP32[(HEAP32[i7 >> 2] | 0) + 12 >> 2] | 0;
+  if ((i5 | 0) == 0) {
+   i5 = _luaE_extendCI(i3) | 0;
+  }
+  HEAP32[i7 >> 2] = i5;
+  HEAP16[i5 + 16 >> 1] = i4;
+  HEAP32[i5 >> 2] = i6;
+  HEAP32[i5 + 24 >> 2] = i9;
+  i22 = i9 + (HEAPU8[i11] << 4) | 0;
+  HEAP32[i5 + 4 >> 2] = i22;
+  i4 = i5 + 28 | 0;
+  HEAP32[i4 >> 2] = HEAP32[i10 + 12 >> 2];
+  i6 = i5 + 18 | 0;
+  HEAP8[i6] = 1;
+  HEAP32[i2 >> 2] = i22;
+  if ((HEAP32[(HEAP32[i3 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+   _luaC_step(i3);
+  }
+  if ((HEAP8[i3 + 40 | 0] & 1) == 0) {
+   i22 = 0;
+   STACKTOP = i1;
+   return i22 | 0;
+  }
+  HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + 4;
+  i2 = HEAP32[i5 + 8 >> 2] | 0;
+  if (!((HEAP8[i2 + 18 | 0] & 1) == 0) ? (HEAP32[(HEAP32[i2 + 28 >> 2] | 0) + -4 >> 2] & 63 | 0) == 30 : 0) {
+   HEAP8[i6] = HEAPU8[i6] | 64;
+   i2 = 4;
+  } else {
+   i2 = 0;
+  }
+  _luaD_hook(i3, i2, -1);
+  HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + -4;
+  i22 = 0;
+  STACKTOP = i1;
+  return i22 | 0;
+ } else if ((i11 | 0) == 54) {
+  _luaG_typeerror(i3, i17, 2520);
+ } else if ((i11 | 0) == 60) {
+  _luaD_throw(i3, 6);
+ } else if ((i11 | 0) == 62) {
+  _luaD_reallocstack(i3, 1000200);
+  _luaG_runerror(i3, 2224, i8);
+ }
+ i7 = HEAP32[i10 >> 2] | 0;
+ i9 = HEAP32[i2 >> 2] | 0;
+ do {
+  if (((HEAP32[i13 >> 2] | 0) - i9 | 0) < 336) {
+   i10 = HEAP32[i14 >> 2] | 0;
+   if ((i10 | 0) > 1e6) {
+    _luaD_throw(i3, 6);
+   }
+   i9 = (i9 - i12 >> 4) + 25 | 0;
+   i10 = i10 << 1;
+   i10 = (i10 | 0) > 1e6 ? 1e6 : i10;
+   i9 = (i10 | 0) < (i9 | 0) ? i9 : i10;
+   if ((i9 | 0) > 1e6) {
+    _luaD_reallocstack(i3, 1000200);
+    _luaG_runerror(i3, 2224, i8);
+   } else {
+    _luaD_reallocstack(i3, i9);
+    break;
+   }
+  }
+ } while (0);
+ i8 = i3 + 16 | 0;
+ i9 = HEAP32[(HEAP32[i8 >> 2] | 0) + 12 >> 2] | 0;
+ if ((i9 | 0) == 0) {
+  i9 = _luaE_extendCI(i3) | 0;
+ }
+ HEAP32[i8 >> 2] = i9;
+ HEAP16[i9 + 16 >> 1] = i4;
+ HEAP32[i9 >> 2] = (HEAP32[i6 >> 2] | 0) + i5;
+ HEAP32[i9 + 4 >> 2] = (HEAP32[i2 >> 2] | 0) + 320;
+ HEAP8[i9 + 18 | 0] = 0;
+ if ((HEAP32[(HEAP32[i3 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i3);
+ }
+ i5 = i3 + 40 | 0;
+ if (!((HEAP8[i5] & 1) == 0)) {
+  _luaD_hook(i3, 0, -1);
+ }
+ i7 = FUNCTION_TABLE_ii[i7 & 255](i3) | 0;
+ i7 = (HEAP32[i2 >> 2] | 0) + (0 - i7 << 4) | 0;
+ i4 = HEAP32[i8 >> 2] | 0;
+ i5 = HEAPU8[i5] | 0;
+ if ((i5 & 6 | 0) == 0) {
+  i5 = i7;
+  i6 = i4 + 8 | 0;
+ } else {
+  if ((i5 & 2 | 0) == 0) {
+   i5 = i7;
+  } else {
+   i5 = i7 - (HEAP32[i6 >> 2] | 0) | 0;
+   _luaD_hook(i3, 1, -1);
+   i5 = (HEAP32[i6 >> 2] | 0) + i5 | 0;
+  }
+  i6 = i4 + 8 | 0;
+  HEAP32[i3 + 20 >> 2] = HEAP32[(HEAP32[i6 >> 2] | 0) + 28 >> 2];
+ }
+ i3 = HEAP32[i4 >> 2] | 0;
+ i4 = HEAP16[i4 + 16 >> 1] | 0;
+ HEAP32[i8 >> 2] = HEAP32[i6 >> 2];
+ L82 : do {
+  if (!(i4 << 16 >> 16 == 0)) {
+   i4 = i4 << 16 >> 16;
+   while (1) {
+    if (!(i5 >>> 0 < (HEAP32[i2 >> 2] | 0) >>> 0)) {
+     break;
+    }
+    i6 = i3 + 16 | 0;
+    i20 = i5;
+    i21 = HEAP32[i20 + 4 >> 2] | 0;
+    i22 = i3;
+    HEAP32[i22 >> 2] = HEAP32[i20 >> 2];
+    HEAP32[i22 + 4 >> 2] = i21;
+    HEAP32[i3 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+    i4 = i4 + -1 | 0;
+    if ((i4 | 0) == 0) {
+     i3 = i6;
+     break L82;
+    }
+    i5 = i5 + 16 | 0;
+    i3 = i6;
+   }
+   if ((i4 | 0) > 0) {
+    i5 = i4;
+    i6 = i3;
+    while (1) {
+     i5 = i5 + -1 | 0;
+     HEAP32[i6 + 8 >> 2] = 0;
+     if ((i5 | 0) <= 0) {
+      break;
+     } else {
+      i6 = i6 + 16 | 0;
+     }
+    }
+    i3 = i3 + (i4 << 4) | 0;
+   }
+  }
+ } while (0);
+ HEAP32[i2 >> 2] = i3;
+ i22 = 1;
+ STACKTOP = i1;
+ return i22 | 0;
+}
+function _lua_getinfo(i1, i6, i29) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ i29 = i29 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i3;
+ if ((HEAP8[i6] | 0) == 62) {
+  i10 = i1 + 8 | 0;
+  i7 = (HEAP32[i10 >> 2] | 0) + -16 | 0;
+  HEAP32[i10 >> 2] = i7;
+  i6 = i6 + 1 | 0;
+  i10 = 0;
+ } else {
+  i7 = HEAP32[i29 + 96 >> 2] | 0;
+  i10 = i7;
+  i7 = HEAP32[i7 >> 2] | 0;
+ }
+ i8 = i7 + 8 | 0;
+ if ((HEAP32[i8 >> 2] & 31 | 0) == 6) {
+  i9 = HEAP32[i7 >> 2] | 0;
+ } else {
+  i9 = 0;
+ }
+ i34 = HEAP8[i6] | 0;
+ L8 : do {
+  if (i34 << 24 >> 24 == 0) {
+   i33 = 1;
+  } else {
+   i12 = (i9 | 0) == 0;
+   i27 = i29 + 16 | 0;
+   i28 = i29 + 24 | 0;
+   i21 = i29 + 28 | 0;
+   i25 = i29 + 12 | 0;
+   i26 = i29 + 36 | 0;
+   i19 = i9 + 4 | 0;
+   i24 = i9 + 12 | 0;
+   i18 = (i10 | 0) == 0;
+   i23 = i29 + 20 | 0;
+   i17 = i10 + 18 | 0;
+   i22 = i10 + 28 | 0;
+   i15 = i29 + 32 | 0;
+   i14 = i29 + 34 | 0;
+   i13 = i29 + 33 | 0;
+   i11 = i9 + 6 | 0;
+   i16 = i29 + 35 | 0;
+   i20 = i29 + 8 | 0;
+   i30 = i29 + 4 | 0;
+   i29 = i10 + 8 | 0;
+   i31 = i1 + 12 | 0;
+   i32 = i6;
+   i33 = 1;
+   while (1) {
+    L12 : do {
+     switch (i34 << 24 >> 24 | 0) {
+     case 116:
+      {
+       if (i18) {
+        i34 = 0;
+       } else {
+        i34 = HEAPU8[i17] & 64;
+       }
+       HEAP8[i16] = i34;
+       break;
+      }
+     case 110:
+      {
+       L18 : do {
+        if ((!i18 ? (HEAP8[i17] & 64) == 0 : 0) ? (i5 = HEAP32[i29 >> 2] | 0, !((HEAP8[i5 + 18 | 0] & 1) == 0)) : 0) {
+         i36 = HEAP32[(HEAP32[HEAP32[i5 >> 2] >> 2] | 0) + 12 >> 2] | 0;
+         i35 = HEAP32[i36 + 12 >> 2] | 0;
+         i34 = ((HEAP32[i5 + 28 >> 2] | 0) - i35 >> 2) + -1 | 0;
+         i35 = HEAP32[i35 + (i34 << 2) >> 2] | 0;
+         switch (i35 & 63 | 0) {
+         case 10:
+         case 8:
+          {
+           i34 = 1;
+           i4 = 46;
+           break;
+          }
+         case 24:
+          {
+           i34 = 5;
+           i4 = 46;
+           break;
+          }
+         case 13:
+          {
+           i34 = 6;
+           i4 = 46;
+           break;
+          }
+         case 14:
+          {
+           i34 = 7;
+           i4 = 46;
+           break;
+          }
+         case 15:
+          {
+           i34 = 8;
+           i4 = 46;
+           break;
+          }
+         case 16:
+          {
+           i34 = 9;
+           i4 = 46;
+           break;
+          }
+         case 17:
+          {
+           i34 = 10;
+           i4 = 46;
+           break;
+          }
+         case 18:
+          {
+           i34 = 11;
+           i4 = 46;
+           break;
+          }
+         case 19:
+          {
+           i34 = 12;
+           i4 = 46;
+           break;
+          }
+         case 21:
+          {
+           i34 = 4;
+           i4 = 46;
+           break;
+          }
+         case 25:
+          {
+           i34 = 13;
+           i4 = 46;
+           break;
+          }
+         case 26:
+          {
+           i34 = 14;
+           i4 = 46;
+           break;
+          }
+         case 22:
+          {
+           i34 = 15;
+           i4 = 46;
+           break;
+          }
+         case 7:
+         case 6:
+         case 12:
+          {
+           i34 = 0;
+           i4 = 46;
+           break;
+          }
+         case 34:
+          {
+           i34 = 2120;
+           i35 = 2120;
+           break;
+          }
+         case 30:
+         case 29:
+          {
+           i36 = _getobjname(i36, i34, i35 >>> 6 & 255, i30) | 0;
+           HEAP32[i20 >> 2] = i36;
+           if ((i36 | 0) == 0) {
+            break L18;
+           } else {
+            break L12;
+           }
+          }
+         default:
+          {
+           i4 = 47;
+           break L18;
+          }
+         }
+         if ((i4 | 0) == 46) {
+          i4 = 0;
+          i34 = (HEAP32[(HEAP32[i31 >> 2] | 0) + (i34 << 2) + 184 >> 2] | 0) + 16 | 0;
+          i35 = 2136;
+         }
+         HEAP32[i30 >> 2] = i34;
+         HEAP32[i20 >> 2] = i35;
+         break L12;
+        } else {
+         i4 = 47;
+        }
+       } while (0);
+       if ((i4 | 0) == 47) {
+        i4 = 0;
+        HEAP32[i20 >> 2] = 0;
+       }
+       HEAP32[i20 >> 2] = 2112;
+       HEAP32[i30 >> 2] = 0;
+       break;
+      }
+     case 108:
+      {
+       if (!i18 ? !((HEAP8[i17] & 1) == 0) : 0) {
+        i35 = HEAP32[(HEAP32[HEAP32[i10 >> 2] >> 2] | 0) + 12 >> 2] | 0;
+        i34 = HEAP32[i35 + 20 >> 2] | 0;
+        if ((i34 | 0) == 0) {
+         i34 = 0;
+        } else {
+         i34 = HEAP32[i34 + (((HEAP32[i22 >> 2] | 0) - (HEAP32[i35 + 12 >> 2] | 0) >> 2) + -1 << 2) >> 2] | 0;
+        }
+       } else {
+        i34 = -1;
+       }
+       HEAP32[i23 >> 2] = i34;
+       break;
+      }
+     case 83:
+      {
+       if (!i12 ? (HEAP8[i19] | 0) != 38 : 0) {
+        i34 = HEAP32[i24 >> 2] | 0;
+        i35 = HEAP32[i34 + 36 >> 2] | 0;
+        if ((i35 | 0) == 0) {
+         i35 = 2168;
+        } else {
+         i35 = i35 + 16 | 0;
+        }
+        HEAP32[i27 >> 2] = i35;
+        i36 = HEAP32[i34 + 64 >> 2] | 0;
+        HEAP32[i28 >> 2] = i36;
+        HEAP32[i21 >> 2] = HEAP32[i34 + 68 >> 2];
+        i34 = (i36 | 0) == 0 ? 2176 : 2184;
+       } else {
+        HEAP32[i27 >> 2] = 2152;
+        HEAP32[i28 >> 2] = -1;
+        HEAP32[i21 >> 2] = -1;
+        i35 = 2152;
+        i34 = 2160;
+       }
+       HEAP32[i25 >> 2] = i34;
+       _luaO_chunkid(i26, i35, 60);
+       break;
+      }
+     case 117:
+      {
+       if (!i12) {
+        HEAP8[i15] = HEAP8[i11] | 0;
+        if ((HEAP8[i19] | 0) != 38) {
+         HEAP8[i14] = HEAP8[(HEAP32[i24 >> 2] | 0) + 77 | 0] | 0;
+         HEAP8[i13] = HEAP8[(HEAP32[i24 >> 2] | 0) + 76 | 0] | 0;
+         break L12;
+        }
+       } else {
+        HEAP8[i15] = 0;
+       }
+       HEAP8[i14] = 1;
+       HEAP8[i13] = 0;
+       break;
+      }
+     case 102:
+     case 76:
+      {
+       break;
+      }
+     default:
+      {
+       i33 = 0;
+      }
+     }
+    } while (0);
+    i32 = i32 + 1 | 0;
+    i34 = HEAP8[i32] | 0;
+    if (i34 << 24 >> 24 == 0) {
+     break L8;
+    }
+   }
+  }
+ } while (0);
+ if ((_strchr(i6, 102) | 0) != 0) {
+  i36 = i1 + 8 | 0;
+  i35 = HEAP32[i36 >> 2] | 0;
+  i31 = i7;
+  i32 = HEAP32[i31 + 4 >> 2] | 0;
+  i34 = i35;
+  HEAP32[i34 >> 2] = HEAP32[i31 >> 2];
+  HEAP32[i34 + 4 >> 2] = i32;
+  HEAP32[i35 + 8 >> 2] = HEAP32[i8 >> 2];
+  HEAP32[i36 >> 2] = (HEAP32[i36 >> 2] | 0) + 16;
+ }
+ if ((_strchr(i6, 76) | 0) == 0) {
+  STACKTOP = i3;
+  return i33 | 0;
+ }
+ if ((i9 | 0) != 0 ? (HEAP8[i9 + 4 | 0] | 0) != 38 : 0) {
+  i6 = i9 + 12 | 0;
+  i5 = HEAP32[(HEAP32[i6 >> 2] | 0) + 20 >> 2] | 0;
+  i4 = _luaH_new(i1) | 0;
+  i36 = i1 + 8 | 0;
+  i35 = HEAP32[i36 >> 2] | 0;
+  HEAP32[i35 >> 2] = i4;
+  HEAP32[i35 + 8 >> 2] = 69;
+  HEAP32[i36 >> 2] = (HEAP32[i36 >> 2] | 0) + 16;
+  HEAP32[i2 >> 2] = 1;
+  HEAP32[i2 + 8 >> 2] = 1;
+  if ((HEAP32[(HEAP32[i6 >> 2] | 0) + 52 >> 2] | 0) > 0) {
+   i7 = 0;
+  } else {
+   STACKTOP = i3;
+   return i33 | 0;
+  }
+  do {
+   _luaH_setint(i1, i4, HEAP32[i5 + (i7 << 2) >> 2] | 0, i2);
+   i7 = i7 + 1 | 0;
+  } while ((i7 | 0) < (HEAP32[(HEAP32[i6 >> 2] | 0) + 52 >> 2] | 0));
+  STACKTOP = i3;
+  return i33 | 0;
+ }
+ i36 = i1 + 8 | 0;
+ i35 = HEAP32[i36 >> 2] | 0;
+ HEAP32[i35 + 8 >> 2] = 0;
+ HEAP32[i36 >> 2] = i35 + 16;
+ STACKTOP = i3;
+ return i33 | 0;
+}
+function _read_long_string(i3, i1, i5) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0;
+ i2 = STACKTOP;
+ i14 = HEAP32[i3 >> 2] | 0;
+ i4 = i3 + 60 | 0;
+ i13 = HEAP32[i4 >> 2] | 0;
+ i15 = i13 + 4 | 0;
+ i16 = HEAP32[i15 >> 2] | 0;
+ i10 = i13 + 8 | 0;
+ i12 = HEAP32[i10 >> 2] | 0;
+ do {
+  if ((i16 + 1 | 0) >>> 0 > i12 >>> 0) {
+   if (i12 >>> 0 > 2147483645) {
+    _lexerror(i3, 12368, 0);
+   }
+   i16 = i12 << 1;
+   i17 = HEAP32[i3 + 52 >> 2] | 0;
+   if ((i16 | 0) == -2) {
+    _luaM_toobig(i17);
+   } else {
+    i8 = _luaM_realloc_(i17, HEAP32[i13 >> 2] | 0, i12, i16) | 0;
+    HEAP32[i13 >> 2] = i8;
+    HEAP32[i10 >> 2] = i16;
+    i9 = HEAP32[i15 >> 2] | 0;
+    break;
+   }
+  } else {
+   i9 = i16;
+   i8 = HEAP32[i13 >> 2] | 0;
+  }
+ } while (0);
+ HEAP32[i15 >> 2] = i9 + 1;
+ HEAP8[i8 + i9 | 0] = i14;
+ i9 = i3 + 56 | 0;
+ i8 = HEAP32[i9 >> 2] | 0;
+ i18 = HEAP32[i8 >> 2] | 0;
+ HEAP32[i8 >> 2] = i18 + -1;
+ if ((i18 | 0) == 0) {
+  i12 = _luaZ_fill(i8) | 0;
+ } else {
+  i18 = i8 + 4 | 0;
+  i12 = HEAP32[i18 >> 2] | 0;
+  HEAP32[i18 >> 2] = i12 + 1;
+  i12 = HEAPU8[i12] | 0;
+ }
+ HEAP32[i3 >> 2] = i12;
+ if ((i12 | 0) == 13 | (i12 | 0) == 10) {
+  _inclinenumber(i3);
+  i11 = 13;
+ }
+ L17 : while (1) {
+  if ((i11 | 0) == 13) {
+   i11 = 0;
+   i12 = HEAP32[i3 >> 2] | 0;
+  }
+  i8 = (i1 | 0) == 0;
+  i10 = i3 + 52 | 0;
+  L21 : do {
+   if (i8) {
+    while (1) {
+     if ((i12 | 0) == 13 | (i12 | 0) == 10) {
+      break L21;
+     } else if ((i12 | 0) == 93) {
+      i11 = 22;
+      break L21;
+     } else if ((i12 | 0) == -1) {
+      i11 = 21;
+      break L17;
+     }
+     i12 = HEAP32[i9 >> 2] | 0;
+     i18 = HEAP32[i12 >> 2] | 0;
+     HEAP32[i12 >> 2] = i18 + -1;
+     if ((i18 | 0) == 0) {
+      i12 = _luaZ_fill(i12) | 0;
+     } else {
+      i18 = i12 + 4 | 0;
+      i12 = HEAP32[i18 >> 2] | 0;
+      HEAP32[i18 >> 2] = i12 + 1;
+      i12 = HEAPU8[i12] | 0;
+     }
+     HEAP32[i3 >> 2] = i12;
+    }
+   } else {
+    while (1) {
+     if ((i12 | 0) == 13 | (i12 | 0) == 10) {
+      break L21;
+     } else if ((i12 | 0) == 93) {
+      i11 = 22;
+      break L21;
+     } else if ((i12 | 0) == -1) {
+      i11 = 21;
+      break L17;
+     }
+     i14 = HEAP32[i4 >> 2] | 0;
+     i13 = i14 + 4 | 0;
+     i17 = HEAP32[i13 >> 2] | 0;
+     i16 = i14 + 8 | 0;
+     i15 = HEAP32[i16 >> 2] | 0;
+     if ((i17 + 1 | 0) >>> 0 > i15 >>> 0) {
+      if (i15 >>> 0 > 2147483645) {
+       i11 = 46;
+       break L17;
+      }
+      i17 = i15 << 1;
+      i18 = HEAP32[i10 >> 2] | 0;
+      if ((i17 | 0) == -2) {
+       i11 = 48;
+       break L17;
+      }
+      i18 = _luaM_realloc_(i18, HEAP32[i14 >> 2] | 0, i15, i17) | 0;
+      HEAP32[i14 >> 2] = i18;
+      HEAP32[i16 >> 2] = i17;
+      i17 = HEAP32[i13 >> 2] | 0;
+      i14 = i18;
+     } else {
+      i14 = HEAP32[i14 >> 2] | 0;
+     }
+     HEAP32[i13 >> 2] = i17 + 1;
+     HEAP8[i14 + i17 | 0] = i12;
+     i12 = HEAP32[i9 >> 2] | 0;
+     i18 = HEAP32[i12 >> 2] | 0;
+     HEAP32[i12 >> 2] = i18 + -1;
+     if ((i18 | 0) == 0) {
+      i12 = _luaZ_fill(i12) | 0;
+     } else {
+      i18 = i12 + 4 | 0;
+      i12 = HEAP32[i18 >> 2] | 0;
+      HEAP32[i18 >> 2] = i12 + 1;
+      i12 = HEAPU8[i12] | 0;
+     }
+     HEAP32[i3 >> 2] = i12;
+    }
+   }
+  } while (0);
+  if ((i11 | 0) == 22) {
+   if ((_skip_sep(i3) | 0) == (i5 | 0)) {
+    i11 = 23;
+    break;
+   } else {
+    i11 = 13;
+    continue;
+   }
+  }
+  i12 = HEAP32[i4 >> 2] | 0;
+  i11 = i12 + 4 | 0;
+  i15 = HEAP32[i11 >> 2] | 0;
+  i14 = i12 + 8 | 0;
+  i13 = HEAP32[i14 >> 2] | 0;
+  if ((i15 + 1 | 0) >>> 0 > i13 >>> 0) {
+   if (i13 >>> 0 > 2147483645) {
+    i11 = 37;
+    break;
+   }
+   i15 = i13 << 1;
+   i10 = HEAP32[i10 >> 2] | 0;
+   if ((i15 | 0) == -2) {
+    i11 = 39;
+    break;
+   }
+   i10 = _luaM_realloc_(i10, HEAP32[i12 >> 2] | 0, i13, i15) | 0;
+   HEAP32[i12 >> 2] = i10;
+   HEAP32[i14 >> 2] = i15;
+   i15 = HEAP32[i11 >> 2] | 0;
+  } else {
+   i10 = HEAP32[i12 >> 2] | 0;
+  }
+  HEAP32[i11 >> 2] = i15 + 1;
+  HEAP8[i10 + i15 | 0] = 10;
+  _inclinenumber(i3);
+  if (!i8) {
+   i11 = 13;
+   continue;
+  }
+  HEAP32[(HEAP32[i4 >> 2] | 0) + 4 >> 2] = 0;
+  i11 = 13;
+ }
+ if ((i11 | 0) == 21) {
+  _lexerror(i3, (i1 | 0) != 0 ? 12512 : 12536, 286);
+ } else if ((i11 | 0) == 23) {
+  i15 = HEAP32[i3 >> 2] | 0;
+  i13 = HEAP32[i4 >> 2] | 0;
+  i14 = i13 + 4 | 0;
+  i16 = HEAP32[i14 >> 2] | 0;
+  i11 = i13 + 8 | 0;
+  i12 = HEAP32[i11 >> 2] | 0;
+  do {
+   if ((i16 + 1 | 0) >>> 0 > i12 >>> 0) {
+    if (i12 >>> 0 > 2147483645) {
+     _lexerror(i3, 12368, 0);
+    }
+    i17 = i12 << 1;
+    i16 = HEAP32[i10 >> 2] | 0;
+    if ((i17 | 0) == -2) {
+     _luaM_toobig(i16);
+    } else {
+     i6 = _luaM_realloc_(i16, HEAP32[i13 >> 2] | 0, i12, i17) | 0;
+     HEAP32[i13 >> 2] = i6;
+     HEAP32[i11 >> 2] = i17;
+     i7 = HEAP32[i14 >> 2] | 0;
+     break;
+    }
+   } else {
+    i7 = i16;
+    i6 = HEAP32[i13 >> 2] | 0;
+   }
+  } while (0);
+  HEAP32[i14 >> 2] = i7 + 1;
+  HEAP8[i6 + i7 | 0] = i15;
+  i6 = HEAP32[i9 >> 2] | 0;
+  i18 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i18 + -1;
+  if ((i18 | 0) == 0) {
+   i6 = _luaZ_fill(i6) | 0;
+  } else {
+   i18 = i6 + 4 | 0;
+   i6 = HEAP32[i18 >> 2] | 0;
+   HEAP32[i18 >> 2] = i6 + 1;
+   i6 = HEAPU8[i6] | 0;
+  }
+  HEAP32[i3 >> 2] = i6;
+  if (i8) {
+   STACKTOP = i2;
+   return;
+  }
+  i4 = HEAP32[i4 >> 2] | 0;
+  i5 = i5 + 2 | 0;
+  i6 = HEAP32[i10 >> 2] | 0;
+  i5 = _luaS_newlstr(i6, (HEAP32[i4 >> 2] | 0) + i5 | 0, (HEAP32[i4 + 4 >> 2] | 0) - (i5 << 1) | 0) | 0;
+  i4 = i6 + 8 | 0;
+  i7 = HEAP32[i4 >> 2] | 0;
+  HEAP32[i4 >> 2] = i7 + 16;
+  HEAP32[i7 >> 2] = i5;
+  HEAP32[i7 + 8 >> 2] = HEAPU8[i5 + 4 | 0] | 0 | 64;
+  i7 = _luaH_set(i6, HEAP32[(HEAP32[i3 + 48 >> 2] | 0) + 4 >> 2] | 0, (HEAP32[i4 >> 2] | 0) + -16 | 0) | 0;
+  i3 = i7 + 8 | 0;
+  if ((HEAP32[i3 >> 2] | 0) == 0 ? (HEAP32[i7 >> 2] = 1, HEAP32[i3 >> 2] = 1, (HEAP32[(HEAP32[i6 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) : 0) {
+   _luaC_step(i6);
+  }
+  HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + -16;
+  HEAP32[i1 >> 2] = i5;
+  STACKTOP = i2;
+  return;
+ } else if ((i11 | 0) == 37) {
+  _lexerror(i3, 12368, 0);
+ } else if ((i11 | 0) == 39) {
+  _luaM_toobig(i10);
+ } else if ((i11 | 0) == 46) {
+  _lexerror(i3, 12368, 0);
+ } else if ((i11 | 0) == 48) {
+  _luaM_toobig(i18);
+ }
+}
+function _try_realloc_chunk(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i2 = STACKTOP;
+ i4 = i1 + 4 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ i8 = i6 & -8;
+ i5 = i1 + i8 | 0;
+ i10 = HEAP32[12928 >> 2] | 0;
+ if (i1 >>> 0 < i10 >>> 0) {
+  _abort();
+ }
+ i12 = i6 & 3;
+ if (!((i12 | 0) != 1 & i1 >>> 0 < i5 >>> 0)) {
+  _abort();
+ }
+ i7 = i1 + (i8 | 4) | 0;
+ i13 = HEAP32[i7 >> 2] | 0;
+ if ((i13 & 1 | 0) == 0) {
+  _abort();
+ }
+ if ((i12 | 0) == 0) {
+  if (i3 >>> 0 < 256) {
+   i15 = 0;
+   STACKTOP = i2;
+   return i15 | 0;
+  }
+  if (!(i8 >>> 0 < (i3 + 4 | 0) >>> 0) ? !((i8 - i3 | 0) >>> 0 > HEAP32[13392 >> 2] << 1 >>> 0) : 0) {
+   i15 = i1;
+   STACKTOP = i2;
+   return i15 | 0;
+  }
+  i15 = 0;
+  STACKTOP = i2;
+  return i15 | 0;
+ }
+ if (!(i8 >>> 0 < i3 >>> 0)) {
+  i5 = i8 - i3 | 0;
+  if (!(i5 >>> 0 > 15)) {
+   i15 = i1;
+   STACKTOP = i2;
+   return i15 | 0;
+  }
+  HEAP32[i4 >> 2] = i6 & 1 | i3 | 2;
+  HEAP32[i1 + (i3 + 4) >> 2] = i5 | 3;
+  HEAP32[i7 >> 2] = HEAP32[i7 >> 2] | 1;
+  _dispose_chunk(i1 + i3 | 0, i5);
+  i15 = i1;
+  STACKTOP = i2;
+  return i15 | 0;
+ }
+ if ((i5 | 0) == (HEAP32[12936 >> 2] | 0)) {
+  i5 = (HEAP32[12924 >> 2] | 0) + i8 | 0;
+  if (!(i5 >>> 0 > i3 >>> 0)) {
+   i15 = 0;
+   STACKTOP = i2;
+   return i15 | 0;
+  }
+  i15 = i5 - i3 | 0;
+  HEAP32[i4 >> 2] = i6 & 1 | i3 | 2;
+  HEAP32[i1 + (i3 + 4) >> 2] = i15 | 1;
+  HEAP32[12936 >> 2] = i1 + i3;
+  HEAP32[12924 >> 2] = i15;
+  i15 = i1;
+  STACKTOP = i2;
+  return i15 | 0;
+ }
+ if ((i5 | 0) == (HEAP32[12932 >> 2] | 0)) {
+  i7 = (HEAP32[12920 >> 2] | 0) + i8 | 0;
+  if (i7 >>> 0 < i3 >>> 0) {
+   i15 = 0;
+   STACKTOP = i2;
+   return i15 | 0;
+  }
+  i5 = i7 - i3 | 0;
+  if (i5 >>> 0 > 15) {
+   HEAP32[i4 >> 2] = i6 & 1 | i3 | 2;
+   HEAP32[i1 + (i3 + 4) >> 2] = i5 | 1;
+   HEAP32[i1 + i7 >> 2] = i5;
+   i15 = i1 + (i7 + 4) | 0;
+   HEAP32[i15 >> 2] = HEAP32[i15 >> 2] & -2;
+   i3 = i1 + i3 | 0;
+  } else {
+   HEAP32[i4 >> 2] = i6 & 1 | i7 | 2;
+   i3 = i1 + (i7 + 4) | 0;
+   HEAP32[i3 >> 2] = HEAP32[i3 >> 2] | 1;
+   i3 = 0;
+   i5 = 0;
+  }
+  HEAP32[12920 >> 2] = i5;
+  HEAP32[12932 >> 2] = i3;
+  i15 = i1;
+  STACKTOP = i2;
+  return i15 | 0;
+ }
+ if ((i13 & 2 | 0) != 0) {
+  i15 = 0;
+  STACKTOP = i2;
+  return i15 | 0;
+ }
+ i7 = (i13 & -8) + i8 | 0;
+ if (i7 >>> 0 < i3 >>> 0) {
+  i15 = 0;
+  STACKTOP = i2;
+  return i15 | 0;
+ }
+ i6 = i7 - i3 | 0;
+ i12 = i13 >>> 3;
+ do {
+  if (!(i13 >>> 0 < 256)) {
+   i11 = HEAP32[i1 + (i8 + 24) >> 2] | 0;
+   i13 = HEAP32[i1 + (i8 + 12) >> 2] | 0;
+   do {
+    if ((i13 | 0) == (i5 | 0)) {
+     i13 = i1 + (i8 + 20) | 0;
+     i12 = HEAP32[i13 >> 2] | 0;
+     if ((i12 | 0) == 0) {
+      i13 = i1 + (i8 + 16) | 0;
+      i12 = HEAP32[i13 >> 2] | 0;
+      if ((i12 | 0) == 0) {
+       i9 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i15 = i12 + 20 | 0;
+      i14 = HEAP32[i15 >> 2] | 0;
+      if ((i14 | 0) != 0) {
+       i12 = i14;
+       i13 = i15;
+       continue;
+      }
+      i15 = i12 + 16 | 0;
+      i14 = HEAP32[i15 >> 2] | 0;
+      if ((i14 | 0) == 0) {
+       break;
+      } else {
+       i12 = i14;
+       i13 = i15;
+      }
+     }
+     if (i13 >>> 0 < i10 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i13 >> 2] = 0;
+      i9 = i12;
+      break;
+     }
+    } else {
+     i12 = HEAP32[i1 + (i8 + 8) >> 2] | 0;
+     if (i12 >>> 0 < i10 >>> 0) {
+      _abort();
+     }
+     i14 = i12 + 12 | 0;
+     if ((HEAP32[i14 >> 2] | 0) != (i5 | 0)) {
+      _abort();
+     }
+     i10 = i13 + 8 | 0;
+     if ((HEAP32[i10 >> 2] | 0) == (i5 | 0)) {
+      HEAP32[i14 >> 2] = i13;
+      HEAP32[i10 >> 2] = i12;
+      i9 = i13;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i11 | 0) != 0) {
+    i10 = HEAP32[i1 + (i8 + 28) >> 2] | 0;
+    i12 = 13216 + (i10 << 2) | 0;
+    if ((i5 | 0) == (HEAP32[i12 >> 2] | 0)) {
+     HEAP32[i12 >> 2] = i9;
+     if ((i9 | 0) == 0) {
+      HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i10);
+      break;
+     }
+    } else {
+     if (i11 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i10 = i11 + 16 | 0;
+     if ((HEAP32[i10 >> 2] | 0) == (i5 | 0)) {
+      HEAP32[i10 >> 2] = i9;
+     } else {
+      HEAP32[i11 + 20 >> 2] = i9;
+     }
+     if ((i9 | 0) == 0) {
+      break;
+     }
+    }
+    if (i9 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i9 + 24 >> 2] = i11;
+    i5 = HEAP32[i1 + (i8 + 16) >> 2] | 0;
+    do {
+     if ((i5 | 0) != 0) {
+      if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i9 + 16 >> 2] = i5;
+       HEAP32[i5 + 24 >> 2] = i9;
+       break;
+      }
+     }
+    } while (0);
+    i5 = HEAP32[i1 + (i8 + 20) >> 2] | 0;
+    if ((i5 | 0) != 0) {
+     if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i9 + 20 >> 2] = i5;
+      HEAP32[i5 + 24 >> 2] = i9;
+      break;
+     }
+    }
+   }
+  } else {
+   i9 = HEAP32[i1 + (i8 + 8) >> 2] | 0;
+   i8 = HEAP32[i1 + (i8 + 12) >> 2] | 0;
+   i13 = 12952 + (i12 << 1 << 2) | 0;
+   if ((i9 | 0) != (i13 | 0)) {
+    if (i9 >>> 0 < i10 >>> 0) {
+     _abort();
+    }
+    if ((HEAP32[i9 + 12 >> 2] | 0) != (i5 | 0)) {
+     _abort();
+    }
+   }
+   if ((i8 | 0) == (i9 | 0)) {
+    HEAP32[3228] = HEAP32[3228] & ~(1 << i12);
+    break;
+   }
+   if ((i8 | 0) != (i13 | 0)) {
+    if (i8 >>> 0 < i10 >>> 0) {
+     _abort();
+    }
+    i10 = i8 + 8 | 0;
+    if ((HEAP32[i10 >> 2] | 0) == (i5 | 0)) {
+     i11 = i10;
+    } else {
+     _abort();
+    }
+   } else {
+    i11 = i8 + 8 | 0;
+   }
+   HEAP32[i9 + 12 >> 2] = i8;
+   HEAP32[i11 >> 2] = i9;
+  }
+ } while (0);
+ if (i6 >>> 0 < 16) {
+  HEAP32[i4 >> 2] = i7 | HEAP32[i4 >> 2] & 1 | 2;
+  i15 = i1 + (i7 | 4) | 0;
+  HEAP32[i15 >> 2] = HEAP32[i15 >> 2] | 1;
+  i15 = i1;
+  STACKTOP = i2;
+  return i15 | 0;
+ } else {
+  HEAP32[i4 >> 2] = HEAP32[i4 >> 2] & 1 | i3 | 2;
+  HEAP32[i1 + (i3 + 4) >> 2] = i6 | 3;
+  i15 = i1 + (i7 | 4) | 0;
+  HEAP32[i15 >> 2] = HEAP32[i15 >> 2] | 1;
+  _dispose_chunk(i1 + i3 | 0, i6);
+  i15 = i1;
+  STACKTOP = i2;
+  return i15 | 0;
+ }
+ return 0;
+}
+function _luaK_posfix(i3, i16, i1, i4, i14) {
+ i3 = i3 | 0;
+ i16 = i16 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i14 = i14 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i15 = 0;
+ i2 = STACKTOP;
+ switch (i16 | 0) {
+ case 14:
+  {
+   _luaK_dischargevars(i3, i4);
+   i6 = i4 + 16 | 0;
+   i5 = HEAP32[i1 + 16 >> 2] | 0;
+   do {
+    if (!((i5 | 0) == -1)) {
+     i9 = HEAP32[i6 >> 2] | 0;
+     if ((i9 | 0) == -1) {
+      HEAP32[i6 >> 2] = i5;
+      break;
+     }
+     i7 = HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0;
+     while (1) {
+      i6 = i7 + (i9 << 2) | 0;
+      i8 = HEAP32[i6 >> 2] | 0;
+      i10 = (i8 >>> 14) + -131071 | 0;
+      if ((i10 | 0) == -1) {
+       break;
+      }
+      i10 = i9 + 1 + i10 | 0;
+      if ((i10 | 0) == -1) {
+       break;
+      } else {
+       i9 = i10;
+      }
+     }
+     i5 = i5 + ~i9 | 0;
+     if ((((i5 | 0) > -1 ? i5 : 0 - i5 | 0) | 0) > 131071) {
+      _luaX_syntaxerror(HEAP32[i3 + 12 >> 2] | 0, 10624);
+     } else {
+      HEAP32[i6 >> 2] = (i5 << 14) + 2147467264 | i8 & 16383;
+      break;
+     }
+    }
+   } while (0);
+   HEAP32[i1 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+   HEAP32[i1 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+   HEAP32[i1 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+   HEAP32[i1 + 12 >> 2] = HEAP32[i4 + 12 >> 2];
+   HEAP32[i1 + 16 >> 2] = HEAP32[i4 + 16 >> 2];
+   HEAP32[i1 + 20 >> 2] = HEAP32[i4 + 20 >> 2];
+   STACKTOP = i2;
+   return;
+  }
+ case 13:
+  {
+   _luaK_dischargevars(i3, i4);
+   i6 = i4 + 20 | 0;
+   i5 = HEAP32[i1 + 20 >> 2] | 0;
+   do {
+    if (!((i5 | 0) == -1)) {
+     i9 = HEAP32[i6 >> 2] | 0;
+     if ((i9 | 0) == -1) {
+      HEAP32[i6 >> 2] = i5;
+      break;
+     }
+     i7 = HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0;
+     while (1) {
+      i8 = i7 + (i9 << 2) | 0;
+      i6 = HEAP32[i8 >> 2] | 0;
+      i10 = (i6 >>> 14) + -131071 | 0;
+      if ((i10 | 0) == -1) {
+       break;
+      }
+      i10 = i9 + 1 + i10 | 0;
+      if ((i10 | 0) == -1) {
+       break;
+      } else {
+       i9 = i10;
+      }
+     }
+     i5 = i5 + ~i9 | 0;
+     if ((((i5 | 0) > -1 ? i5 : 0 - i5 | 0) | 0) > 131071) {
+      _luaX_syntaxerror(HEAP32[i3 + 12 >> 2] | 0, 10624);
+     } else {
+      HEAP32[i8 >> 2] = (i5 << 14) + 2147467264 | i6 & 16383;
+      break;
+     }
+    }
+   } while (0);
+   HEAP32[i1 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+   HEAP32[i1 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+   HEAP32[i1 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+   HEAP32[i1 + 12 >> 2] = HEAP32[i4 + 12 >> 2];
+   HEAP32[i1 + 16 >> 2] = HEAP32[i4 + 16 >> 2];
+   HEAP32[i1 + 20 >> 2] = HEAP32[i4 + 20 >> 2];
+   STACKTOP = i2;
+   return;
+  }
+ case 6:
+  {
+   i12 = i4 + 16 | 0;
+   i13 = i4 + 20 | 0;
+   i16 = (HEAP32[i12 >> 2] | 0) == (HEAP32[i13 >> 2] | 0);
+   _luaK_dischargevars(i3, i4);
+   do {
+    if (!i16) {
+     if ((HEAP32[i4 >> 2] | 0) == 6) {
+      i10 = HEAP32[i4 + 8 >> 2] | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (HEAP32[i13 >> 2] | 0)) {
+       break;
+      }
+      if ((i10 | 0) >= (HEAPU8[i3 + 46 | 0] | 0 | 0)) {
+       _exp2reg(i3, i4, i10);
+       break;
+      }
+     }
+     _luaK_exp2nextreg(i3, i4);
+    }
+   } while (0);
+   if ((HEAP32[i4 >> 2] | 0) == 11 ? (i5 = i4 + 8 | 0, i7 = HEAP32[i5 >> 2] | 0, i8 = (HEAP32[i3 >> 2] | 0) + 12 | 0, i9 = HEAP32[i8 >> 2] | 0, i6 = HEAP32[i9 + (i7 << 2) >> 2] | 0, (i6 & 63 | 0) == 22) : 0) {
+    i4 = i1 + 8 | 0;
+    if (((HEAP32[i1 >> 2] | 0) == 6 ? (i11 = HEAP32[i4 >> 2] | 0, (i11 & 256 | 0) == 0) : 0) ? (HEAPU8[i3 + 46 | 0] | 0 | 0) <= (i11 | 0) : 0) {
+     i6 = i3 + 48 | 0;
+     HEAP8[i6] = (HEAP8[i6] | 0) + -1 << 24 >> 24;
+     i6 = HEAP32[i5 >> 2] | 0;
+     i16 = HEAP32[i8 >> 2] | 0;
+     i9 = i16;
+     i7 = i6;
+     i6 = HEAP32[i16 + (i6 << 2) >> 2] | 0;
+    }
+    HEAP32[i9 + (i7 << 2) >> 2] = HEAP32[i4 >> 2] << 23 | i6 & 8388607;
+    HEAP32[i1 >> 2] = 11;
+    HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+    STACKTOP = i2;
+    return;
+   }
+   _luaK_exp2nextreg(i3, i4);
+   _codearith(i3, 22, i1, i4, i14);
+   STACKTOP = i2;
+   return;
+  }
+ case 9:
+ case 8:
+ case 7:
+  {
+   i7 = i16 + 17 | 0;
+   i6 = _luaK_exp2RK(i3, i1) | 0;
+   i5 = _luaK_exp2RK(i3, i4) | 0;
+   if (((HEAP32[i4 >> 2] | 0) == 6 ? (i15 = HEAP32[i4 + 8 >> 2] | 0, (i15 & 256 | 0) == 0) : 0) ? (HEAPU8[i3 + 46 | 0] | 0 | 0) <= (i15 | 0) : 0) {
+    i16 = i3 + 48 | 0;
+    HEAP8[i16] = (HEAP8[i16] | 0) + -1 << 24 >> 24;
+   }
+   i4 = i1 + 8 | 0;
+   if (((HEAP32[i1 >> 2] | 0) == 6 ? (i10 = HEAP32[i4 >> 2] | 0, (i10 & 256 | 0) == 0) : 0) ? (HEAPU8[i3 + 46 | 0] | 0 | 0) <= (i10 | 0) : 0) {
+    i16 = i3 + 48 | 0;
+    HEAP8[i16] = (HEAP8[i16] | 0) + -1 << 24 >> 24;
+   }
+   HEAP32[i4 >> 2] = _condjump(i3, i7, 1, i6, i5) | 0;
+   HEAP32[i1 >> 2] = 10;
+   STACKTOP = i2;
+   return;
+  }
+ case 12:
+ case 11:
+ case 10:
+  {
+   i7 = i16 + 14 | 0;
+   i6 = _luaK_exp2RK(i3, i1) | 0;
+   i5 = _luaK_exp2RK(i3, i4) | 0;
+   if (((HEAP32[i4 >> 2] | 0) == 6 ? (i13 = HEAP32[i4 + 8 >> 2] | 0, (i13 & 256 | 0) == 0) : 0) ? (HEAPU8[i3 + 46 | 0] | 0 | 0) <= (i13 | 0) : 0) {
+    i16 = i3 + 48 | 0;
+    HEAP8[i16] = (HEAP8[i16] | 0) + -1 << 24 >> 24;
+   }
+   i4 = i1 + 8 | 0;
+   if (((HEAP32[i1 >> 2] | 0) == 6 ? (i12 = HEAP32[i4 >> 2] | 0, (i12 & 256 | 0) == 0) : 0) ? (HEAPU8[i3 + 46 | 0] | 0 | 0) <= (i12 | 0) : 0) {
+    i16 = i3 + 48 | 0;
+    HEAP8[i16] = (HEAP8[i16] | 0) + -1 << 24 >> 24;
+   }
+   i8 = (i7 | 0) == 24;
+   HEAP32[i4 >> 2] = _condjump(i3, i7, i8 & 1 ^ 1, i8 ? i6 : i5, i8 ? i5 : i6) | 0;
+   HEAP32[i1 >> 2] = 10;
+   STACKTOP = i2;
+   return;
+  }
+ case 5:
+ case 4:
+ case 3:
+ case 2:
+ case 1:
+ case 0:
+  {
+   _codearith(i3, i16 + 13 | 0, i1, i4, i14);
+   STACKTOP = i2;
+   return;
+  }
+ default:
+  {
+   STACKTOP = i2;
+   return;
+  }
+ }
+}
+function _body(i1, i4, i13, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i13 = i13 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i3 = i6 + 12 | 0;
+ i14 = i6;
+ i2 = i1 + 48 | 0;
+ i19 = HEAP32[i2 >> 2] | 0;
+ i18 = i1 + 52 | 0;
+ i17 = HEAP32[i18 >> 2] | 0;
+ i16 = HEAP32[i19 >> 2] | 0;
+ i19 = i19 + 36 | 0;
+ i23 = i16 + 56 | 0;
+ i24 = HEAP32[i23 >> 2] | 0;
+ i15 = i16 + 16 | 0;
+ if (((HEAP32[i19 >> 2] | 0) >= (i24 | 0) ? (i21 = _luaM_growaux_(i17, HEAP32[i15 >> 2] | 0, i23, 4, 262143, 6512) | 0, HEAP32[i15 >> 2] = i21, i20 = HEAP32[i23 >> 2] | 0, (i24 | 0) < (i20 | 0)) : 0) ? (i22 = i24 + 1 | 0, HEAP32[i21 + (i24 << 2) >> 2] = 0, (i22 | 0) < (i20 | 0)) : 0) {
+  while (1) {
+   i21 = i22 + 1 | 0;
+   HEAP32[(HEAP32[i15 >> 2] | 0) + (i22 << 2) >> 2] = 0;
+   if ((i21 | 0) == (i20 | 0)) {
+    break;
+   } else {
+    i22 = i21;
+   }
+  }
+ }
+ i20 = _luaF_newproto(i17) | 0;
+ i24 = HEAP32[i19 >> 2] | 0;
+ HEAP32[i19 >> 2] = i24 + 1;
+ HEAP32[(HEAP32[i15 >> 2] | 0) + (i24 << 2) >> 2] = i20;
+ if (!((HEAP8[i20 + 5 | 0] & 3) == 0) ? !((HEAP8[i16 + 5 | 0] & 4) == 0) : 0) {
+  _luaC_barrier_(i17, i16, i20);
+ }
+ HEAP32[i3 >> 2] = i20;
+ HEAP32[i20 + 64 >> 2] = i5;
+ i16 = HEAP32[i18 >> 2] | 0;
+ HEAP32[i3 + 8 >> 2] = HEAP32[i2 >> 2];
+ i17 = i3 + 12 | 0;
+ HEAP32[i17 >> 2] = i1;
+ HEAP32[i2 >> 2] = i3;
+ HEAP32[i3 + 20 >> 2] = 0;
+ HEAP32[i3 + 24 >> 2] = 0;
+ HEAP32[i3 + 28 >> 2] = -1;
+ HEAP32[i3 + 32 >> 2] = 0;
+ HEAP32[i3 + 36 >> 2] = 0;
+ i22 = i3 + 44 | 0;
+ i15 = i1 + 64 | 0;
+ HEAP32[i22 + 0 >> 2] = 0;
+ HEAP8[i22 + 4 | 0] = 0;
+ HEAP32[i3 + 40 >> 2] = HEAP32[(HEAP32[i15 >> 2] | 0) + 4 >> 2];
+ i15 = i3 + 16 | 0;
+ HEAP32[i15 >> 2] = 0;
+ HEAP32[i20 + 36 >> 2] = HEAP32[i1 + 68 >> 2];
+ HEAP8[i20 + 78 | 0] = 2;
+ i22 = _luaH_new(i16) | 0;
+ HEAP32[i3 + 4 >> 2] = i22;
+ i23 = i16 + 8 | 0;
+ i24 = HEAP32[i23 >> 2] | 0;
+ HEAP32[i24 >> 2] = i22;
+ HEAP32[i24 + 8 >> 2] = 69;
+ i24 = (HEAP32[i23 >> 2] | 0) + 16 | 0;
+ HEAP32[i23 >> 2] = i24;
+ if (((HEAP32[i16 + 24 >> 2] | 0) - i24 | 0) < 16) {
+  _luaD_growstack(i16, 0);
+ }
+ HEAP8[i14 + 10 | 0] = 0;
+ HEAP8[i14 + 8 | 0] = HEAP8[i3 + 46 | 0] | 0;
+ i24 = HEAP32[(HEAP32[i17 >> 2] | 0) + 64 >> 2] | 0;
+ HEAP16[i14 + 4 >> 1] = HEAP32[i24 + 28 >> 2];
+ HEAP16[i14 + 6 >> 1] = HEAP32[i24 + 16 >> 2];
+ HEAP8[i14 + 9 | 0] = 0;
+ HEAP32[i14 >> 2] = HEAP32[i15 >> 2];
+ HEAP32[i15 >> 2] = i14;
+ i14 = i1 + 16 | 0;
+ if ((HEAP32[i14 >> 2] | 0) != 40) {
+  _error_expected(i1, 40);
+ }
+ _luaX_next(i1);
+ if ((i13 | 0) != 0) {
+  _new_localvar(i1, _luaX_newstring(i1, 6456, 4) | 0);
+  i24 = HEAP32[i2 >> 2] | 0;
+  i22 = i24 + 46 | 0;
+  i23 = (HEAPU8[i22] | 0) + 1 | 0;
+  HEAP8[i22] = i23;
+  HEAP32[(HEAP32[(HEAP32[i24 >> 2] | 0) + 24 >> 2] | 0) + ((HEAP16[(HEAP32[HEAP32[(HEAP32[i24 + 12 >> 2] | 0) + 64 >> 2] >> 2] | 0) + ((i23 & 255) + -1 + (HEAP32[i24 + 40 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i24 + 20 >> 2];
+ }
+ i13 = HEAP32[i2 >> 2] | 0;
+ i15 = HEAP32[i13 >> 2] | 0;
+ i16 = i15 + 77 | 0;
+ HEAP8[i16] = 0;
+ i19 = HEAP32[i14 >> 2] | 0;
+ L20 : do {
+  if ((i19 | 0) != 41) {
+   i17 = i1 + 24 | 0;
+   i18 = 0;
+   while (1) {
+    if ((i19 | 0) == 280) {
+     i17 = 18;
+     break;
+    } else if ((i19 | 0) != 288) {
+     i17 = 19;
+     break;
+    }
+    i24 = HEAP32[i17 >> 2] | 0;
+    _luaX_next(i1);
+    _new_localvar(i1, i24);
+    i18 = i18 + 1 | 0;
+    if ((HEAP8[i16] | 0) != 0) {
+     i11 = i18;
+     break L20;
+    }
+    if ((HEAP32[i14 >> 2] | 0) != 44) {
+     i11 = i18;
+     break L20;
+    }
+    _luaX_next(i1);
+    i19 = HEAP32[i14 >> 2] | 0;
+   }
+   if ((i17 | 0) == 18) {
+    _luaX_next(i1);
+    HEAP8[i16] = 1;
+    i11 = i18;
+    break;
+   } else if ((i17 | 0) == 19) {
+    _luaX_syntaxerror(i1, 6464);
+   }
+  } else {
+   i11 = 0;
+  }
+ } while (0);
+ i18 = HEAP32[i2 >> 2] | 0;
+ i16 = i18 + 46 | 0;
+ i17 = (HEAPU8[i16] | 0) + i11 | 0;
+ HEAP8[i16] = i17;
+ if ((i11 | 0) != 0 ? (i8 = i18 + 20 | 0, i9 = i18 + 40 | 0, i7 = HEAP32[(HEAP32[i18 >> 2] | 0) + 24 >> 2] | 0, i10 = HEAP32[HEAP32[(HEAP32[i18 + 12 >> 2] | 0) + 64 >> 2] >> 2] | 0, HEAP32[i7 + ((HEAP16[i10 + ((i17 & 255) - i11 + (HEAP32[i9 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i8 >> 2], i12 = i11 + -1 | 0, (i12 | 0) != 0) : 0) {
+  do {
+   HEAP32[i7 + ((HEAP16[i10 + ((HEAPU8[i16] | 0) - i12 + (HEAP32[i9 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i8 >> 2];
+   i12 = i12 + -1 | 0;
+  } while ((i12 | 0) != 0);
+ }
+ i24 = i13 + 46 | 0;
+ HEAP8[i15 + 76 | 0] = HEAP8[i24] | 0;
+ _luaK_reserveregs(i13, HEAPU8[i24] | 0);
+ if ((HEAP32[i14 >> 2] | 0) != 41) {
+  _error_expected(i1, 41);
+ }
+ _luaX_next(i1);
+ L39 : while (1) {
+  i7 = HEAP32[i14 >> 2] | 0;
+  switch (i7 | 0) {
+  case 277:
+  case 286:
+  case 262:
+  case 261:
+  case 260:
+   {
+    i17 = 30;
+    break L39;
+   }
+  default:
+   {}
+  }
+  _statement(i1);
+  if ((i7 | 0) == 274) {
+   i17 = 30;
+   break;
+  }
+ }
+ if ((i17 | 0) == 30) {
+  HEAP32[(HEAP32[i3 >> 2] | 0) + 68 >> 2] = HEAP32[i1 + 4 >> 2];
+  _check_match(i1, 262, 265, i5);
+  i24 = HEAP32[(HEAP32[i2 >> 2] | 0) + 8 >> 2] | 0;
+  i23 = _luaK_codeABx(i24, 37, 0, (HEAP32[i24 + 36 >> 2] | 0) + -1 | 0) | 0;
+  HEAP32[i4 + 16 >> 2] = -1;
+  HEAP32[i4 + 20 >> 2] = -1;
+  HEAP32[i4 >> 2] = 11;
+  HEAP32[i4 + 8 >> 2] = i23;
+  _luaK_exp2nextreg(i24, i4);
+  _close_func(i1);
+  STACKTOP = i6;
+  return;
+ }
+}
+function _luaH_newkey(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, d21 = 0.0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 144 | 0;
+ i8 = i4 + 8 | 0;
+ i10 = i4;
+ i5 = i4 + 16 | 0;
+ i6 = i1 + 8 | 0;
+ i11 = HEAP32[i6 >> 2] | 0;
+ if ((i11 | 0) == 0) {
+  _luaG_runerror(i3, 7968, i8);
+ } else if ((i11 | 0) == 3) {
+  i15 = 3;
+ }
+ if ((i15 | 0) == 3 ? (d21 = +HEAPF64[i1 >> 3], !(d21 == d21 & 0.0 == 0.0)) : 0) {
+  _luaG_runerror(i3, 7992, i8);
+ }
+ i13 = _mainposition(i2, i1) | 0;
+ i14 = i13 + 8 | 0;
+ do {
+  if ((HEAP32[i14 >> 2] | 0) != 0 | (i13 | 0) == 8016) {
+   i18 = i2 + 20 | 0;
+   i11 = i2 + 16 | 0;
+   i17 = HEAP32[i11 >> 2] | 0;
+   i16 = HEAP32[i18 >> 2] | 0;
+   while (1) {
+    if (!(i16 >>> 0 > i17 >>> 0)) {
+     break;
+    }
+    i12 = i16 + -32 | 0;
+    HEAP32[i18 >> 2] = i12;
+    if ((HEAP32[i16 + -8 >> 2] | 0) == 0) {
+     i15 = 37;
+     break;
+    } else {
+     i16 = i12;
+    }
+   }
+   if ((i15 | 0) == 37) {
+    i5 = _mainposition(i2, i13 + 16 | 0) | 0;
+    if ((i5 | 0) == (i13 | 0)) {
+     i20 = i13 + 28 | 0;
+     HEAP32[i16 + -4 >> 2] = HEAP32[i20 >> 2];
+     HEAP32[i20 >> 2] = i12;
+     break;
+    } else {
+     i7 = i5;
+    }
+    do {
+     i5 = i7 + 28 | 0;
+     i7 = HEAP32[i5 >> 2] | 0;
+    } while ((i7 | 0) != (i13 | 0));
+    HEAP32[i5 >> 2] = i12;
+    HEAP32[i12 + 0 >> 2] = HEAP32[i13 + 0 >> 2];
+    HEAP32[i12 + 4 >> 2] = HEAP32[i13 + 4 >> 2];
+    HEAP32[i12 + 8 >> 2] = HEAP32[i13 + 8 >> 2];
+    HEAP32[i12 + 12 >> 2] = HEAP32[i13 + 12 >> 2];
+    HEAP32[i12 + 16 >> 2] = HEAP32[i13 + 16 >> 2];
+    HEAP32[i12 + 20 >> 2] = HEAP32[i13 + 20 >> 2];
+    HEAP32[i12 + 24 >> 2] = HEAP32[i13 + 24 >> 2];
+    HEAP32[i12 + 28 >> 2] = HEAP32[i13 + 28 >> 2];
+    HEAP32[i13 + 28 >> 2] = 0;
+    HEAP32[i14 >> 2] = 0;
+    i12 = i13;
+    break;
+   }
+   i13 = i5 + 0 | 0;
+   i12 = i13 + 124 | 0;
+   do {
+    HEAP32[i13 >> 2] = 0;
+    i13 = i13 + 4 | 0;
+   } while ((i13 | 0) < (i12 | 0));
+   i15 = i2 + 12 | 0;
+   i13 = HEAP32[i2 + 28 >> 2] | 0;
+   i12 = 0;
+   i20 = 1;
+   i16 = 0;
+   i14 = 1;
+   while (1) {
+    if ((i14 | 0) > (i13 | 0)) {
+     if ((i20 | 0) > (i13 | 0)) {
+      break;
+     } else {
+      i19 = i13;
+     }
+    } else {
+     i19 = i14;
+    }
+    if ((i20 | 0) > (i19 | 0)) {
+     i18 = i20;
+     i17 = 0;
+    } else {
+     i18 = HEAP32[i15 >> 2] | 0;
+     i17 = 0;
+     while (1) {
+      i17 = ((HEAP32[i18 + (i20 + -1 << 4) + 8 >> 2] | 0) != 0) + i17 | 0;
+      if ((i20 | 0) >= (i19 | 0)) {
+       break;
+      } else {
+       i20 = i20 + 1 | 0;
+      }
+     }
+     i18 = i19 + 1 | 0;
+    }
+    i20 = i5 + (i16 << 2) | 0;
+    HEAP32[i20 >> 2] = (HEAP32[i20 >> 2] | 0) + i17;
+    i12 = i17 + i12 | 0;
+    i16 = i16 + 1 | 0;
+    if ((i16 | 0) < 31) {
+     i20 = i18;
+     i14 = i14 << 1;
+    } else {
+     break;
+    }
+   }
+   i14 = 0;
+   i15 = 1 << (HEAPU8[i2 + 7 | 0] | 0);
+   i13 = 0;
+   L32 : while (1) {
+    i16 = i15;
+    while (1) {
+     i15 = i16 + -1 | 0;
+     if ((i16 | 0) == 0) {
+      break L32;
+     }
+     i16 = HEAP32[i11 >> 2] | 0;
+     if ((HEAP32[i16 + (i15 << 5) + 8 >> 2] | 0) == 0) {
+      i16 = i15;
+     } else {
+      break;
+     }
+    }
+    if (((HEAP32[i16 + (i15 << 5) + 24 >> 2] | 0) == 3 ? (d21 = +HEAPF64[i16 + (i15 << 5) + 16 >> 3], HEAPF64[i10 >> 3] = d21 + 6755399441055744.0, i9 = HEAP32[i10 >> 2] | 0, +(i9 | 0) == d21) : 0) ? (i9 + -1 | 0) >>> 0 < 1073741824 : 0) {
+     i16 = i5 + ((_luaO_ceillog2(i9) | 0) << 2) | 0;
+     HEAP32[i16 >> 2] = (HEAP32[i16 >> 2] | 0) + 1;
+     i16 = 1;
+    } else {
+     i16 = 0;
+    }
+    i14 = i16 + i14 | 0;
+    i13 = i13 + 1 | 0;
+   }
+   i9 = i14 + i12 | 0;
+   if (((HEAP32[i6 >> 2] | 0) == 3 ? (d21 = +HEAPF64[i1 >> 3], HEAPF64[i8 >> 3] = d21 + 6755399441055744.0, i7 = HEAP32[i8 >> 2] | 0, +(i7 | 0) == d21) : 0) ? (i7 + -1 | 0) >>> 0 < 1073741824 : 0) {
+    i6 = i5 + ((_luaO_ceillog2(i7) | 0) << 2) | 0;
+    HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 1;
+    i6 = 1;
+   } else {
+    i6 = 0;
+   }
+   i7 = i9 + i6 | 0;
+   L49 : do {
+    if ((i7 | 0) > 0) {
+     i14 = 0;
+     i10 = 0;
+     i6 = 0;
+     i8 = 0;
+     i11 = 0;
+     i9 = 1;
+     while (1) {
+      i15 = HEAP32[i5 + (i6 << 2) >> 2] | 0;
+      if ((i15 | 0) > 0) {
+       i15 = i15 + i10 | 0;
+       i14 = (i15 | 0) > (i14 | 0);
+       i10 = i15;
+       i8 = i14 ? i9 : i8;
+       i11 = i14 ? i15 : i11;
+      }
+      if ((i10 | 0) == (i7 | 0)) {
+       break L49;
+      }
+      i9 = i9 << 1;
+      i14 = (i9 | 0) / 2 | 0;
+      if ((i14 | 0) < (i7 | 0)) {
+       i6 = i6 + 1 | 0;
+      } else {
+       break;
+      }
+     }
+    } else {
+     i8 = 0;
+     i11 = 0;
+    }
+   } while (0);
+   _luaH_resize(i3, i2, i8, i12 + 1 + i13 - i11 | 0);
+   i5 = _luaH_get(i2, i1) | 0;
+   if ((i5 | 0) != 5192) {
+    i20 = i5;
+    STACKTOP = i4;
+    return i20 | 0;
+   }
+   i20 = _luaH_newkey(i3, i2, i1) | 0;
+   STACKTOP = i4;
+   return i20 | 0;
+  } else {
+   i12 = i13;
+  }
+ } while (0);
+ i18 = i1;
+ i19 = HEAP32[i18 + 4 >> 2] | 0;
+ i20 = i12 + 16 | 0;
+ HEAP32[i20 >> 2] = HEAP32[i18 >> 2];
+ HEAP32[i20 + 4 >> 2] = i19;
+ HEAP32[i12 + 24 >> 2] = HEAP32[i6 >> 2];
+ if (((HEAP32[i6 >> 2] & 64 | 0) != 0 ? !((HEAP8[(HEAP32[i1 >> 2] | 0) + 5 | 0] & 3) == 0) : 0) ? !((HEAP8[i2 + 5 | 0] & 4) == 0) : 0) {
+  _luaC_barrierback_(i3, i2);
+ }
+ i20 = i12;
+ STACKTOP = i4;
+ return i20 | 0;
+}
+function _luaV_concat(i7, i10) {
+ i7 = i7 | 0;
+ i10 = i10 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i9 = i5;
+ i8 = i5 + 8 | 0;
+ i6 = i7 + 8 | 0;
+ i2 = i7 + 12 | 0;
+ i3 = i7 + 28 | 0;
+ i4 = i7 + 16 | 0;
+ i11 = HEAP32[i6 >> 2] | 0;
+ L1 : while (1) {
+  i14 = i11 + -32 | 0;
+  i12 = i11 + -24 | 0;
+  i17 = HEAP32[i12 >> 2] | 0;
+  i13 = i11 + -16 | 0;
+  do {
+   if ((i17 & 15 | 0) == 4 | (i17 | 0) == 3) {
+    i15 = i11 + -8 | 0;
+    i16 = HEAP32[i15 >> 2] | 0;
+    if ((i16 & 15 | 0) == 4) {
+     i16 = i13;
+    } else {
+     if ((i16 | 0) != 3) {
+      i1 = 7;
+      break;
+     }
+     HEAPF64[tempDoublePtr >> 3] = +HEAPF64[i13 >> 3];
+     HEAP32[i9 >> 2] = HEAP32[tempDoublePtr >> 2];
+     HEAP32[i9 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+     i16 = _luaS_newlstr(i7, i8, _sprintf(i8 | 0, 8936, i9 | 0) | 0) | 0;
+     HEAP32[i13 >> 2] = i16;
+     HEAP32[i15 >> 2] = HEAPU8[i16 + 4 | 0] | 0 | 64;
+     i16 = i13;
+     i17 = HEAP32[i12 >> 2] | 0;
+    }
+    i16 = HEAP32[(HEAP32[i16 >> 2] | 0) + 12 >> 2] | 0;
+    i18 = (i17 & 15 | 0) == 4;
+    if ((i16 | 0) == 0) {
+     if (i18) {
+      i12 = 2;
+      break;
+     }
+     if ((i17 | 0) != 3) {
+      i12 = 2;
+      break;
+     }
+     HEAPF64[tempDoublePtr >> 3] = +HEAPF64[i14 >> 3];
+     HEAP32[i9 >> 2] = HEAP32[tempDoublePtr >> 2];
+     HEAP32[i9 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+     i18 = _luaS_newlstr(i7, i8, _sprintf(i8 | 0, 8936, i9 | 0) | 0) | 0;
+     HEAP32[i14 >> 2] = i18;
+     HEAP32[i12 >> 2] = HEAPU8[i18 + 4 | 0] | 0 | 64;
+     i12 = 2;
+     break;
+    }
+    if (i18 ? (HEAP32[(HEAP32[i14 >> 2] | 0) + 12 >> 2] | 0) == 0 : 0) {
+     i16 = i13;
+     i17 = HEAP32[i16 + 4 >> 2] | 0;
+     i18 = i14;
+     HEAP32[i18 >> 2] = HEAP32[i16 >> 2];
+     HEAP32[i18 + 4 >> 2] = i17;
+     HEAP32[i12 >> 2] = HEAP32[i15 >> 2];
+     i12 = 2;
+     break;
+    }
+    L19 : do {
+     if ((i10 | 0) > 1) {
+      i12 = 1;
+      do {
+       i15 = ~i12;
+       i14 = i11 + (i15 << 4) | 0;
+       i15 = i11 + (i15 << 4) + 8 | 0;
+       i13 = HEAP32[i15 >> 2] | 0;
+       if ((i13 & 15 | 0) != 4) {
+        if ((i13 | 0) != 3) {
+         break L19;
+        }
+        HEAPF64[tempDoublePtr >> 3] = +HEAPF64[i14 >> 3];
+        HEAP32[i9 >> 2] = HEAP32[tempDoublePtr >> 2];
+        HEAP32[i9 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+        i18 = _luaS_newlstr(i7, i8, _sprintf(i8 | 0, 8936, i9 | 0) | 0) | 0;
+        HEAP32[i14 >> 2] = i18;
+        HEAP32[i15 >> 2] = HEAPU8[i18 + 4 | 0] | 0 | 64;
+       }
+       i13 = HEAP32[(HEAP32[i14 >> 2] | 0) + 12 >> 2] | 0;
+       if (!(i13 >>> 0 < (-3 - i16 | 0) >>> 0)) {
+        i1 = 24;
+        break L1;
+       }
+       i16 = i13 + i16 | 0;
+       i12 = i12 + 1 | 0;
+      } while ((i12 | 0) < (i10 | 0));
+     } else {
+      i12 = 1;
+     }
+    } while (0);
+    i14 = _luaZ_openspace(i7, (HEAP32[i2 >> 2] | 0) + 144 | 0, i16) | 0;
+    i15 = i12;
+    i13 = 0;
+    do {
+     i17 = HEAP32[i11 + (0 - i15 << 4) >> 2] | 0;
+     i18 = HEAP32[i17 + 12 >> 2] | 0;
+     _memcpy(i14 + i13 | 0, i17 + 16 | 0, i18 | 0) | 0;
+     i13 = i18 + i13 | 0;
+     i15 = i15 + -1 | 0;
+    } while ((i15 | 0) > 0);
+    i18 = 0 - i12 | 0;
+    i17 = _luaS_newlstr(i7, i14, i13) | 0;
+    HEAP32[i11 + (i18 << 4) >> 2] = i17;
+    HEAP32[i11 + (i18 << 4) + 8 >> 2] = HEAPU8[i17 + 4 | 0] | 0 | 64;
+   } else {
+    i1 = 7;
+   }
+  } while (0);
+  if ((i1 | 0) == 7) {
+   i1 = 0;
+   i15 = _luaT_gettmbyobj(i7, i14, 15) | 0;
+   if ((HEAP32[i15 + 8 >> 2] | 0) == 0) {
+    i15 = _luaT_gettmbyobj(i7, i13, 15) | 0;
+    if ((HEAP32[i15 + 8 >> 2] | 0) == 0) {
+     i1 = 10;
+     break;
+    }
+   }
+   i18 = i14 - (HEAP32[i3 >> 2] | 0) | 0;
+   i16 = HEAP32[i6 >> 2] | 0;
+   HEAP32[i6 >> 2] = i16 + 16;
+   i20 = i15;
+   i19 = HEAP32[i20 + 4 >> 2] | 0;
+   i17 = i16;
+   HEAP32[i17 >> 2] = HEAP32[i20 >> 2];
+   HEAP32[i17 + 4 >> 2] = i19;
+   HEAP32[i16 + 8 >> 2] = HEAP32[i15 + 8 >> 2];
+   i15 = HEAP32[i6 >> 2] | 0;
+   HEAP32[i6 >> 2] = i15 + 16;
+   i16 = i14;
+   i17 = HEAP32[i16 + 4 >> 2] | 0;
+   i14 = i15;
+   HEAP32[i14 >> 2] = HEAP32[i16 >> 2];
+   HEAP32[i14 + 4 >> 2] = i17;
+   HEAP32[i15 + 8 >> 2] = HEAP32[i12 >> 2];
+   i12 = HEAP32[i6 >> 2] | 0;
+   HEAP32[i6 >> 2] = i12 + 16;
+   i15 = i13;
+   i14 = HEAP32[i15 + 4 >> 2] | 0;
+   i17 = i12;
+   HEAP32[i17 >> 2] = HEAP32[i15 >> 2];
+   HEAP32[i17 + 4 >> 2] = i14;
+   HEAP32[i12 + 8 >> 2] = HEAP32[i11 + -8 >> 2];
+   _luaD_call(i7, (HEAP32[i6 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i4 >> 2] | 0) + 18 | 0] & 1);
+   i12 = HEAP32[i3 >> 2] | 0;
+   i17 = HEAP32[i6 >> 2] | 0;
+   i14 = i17 + -16 | 0;
+   HEAP32[i6 >> 2] = i14;
+   i15 = HEAP32[i14 + 4 >> 2] | 0;
+   i16 = i12 + i18 | 0;
+   HEAP32[i16 >> 2] = HEAP32[i14 >> 2];
+   HEAP32[i16 + 4 >> 2] = i15;
+   HEAP32[i12 + (i18 + 8) >> 2] = HEAP32[i17 + -8 >> 2];
+   i12 = 2;
+  }
+  i10 = i10 + 1 - i12 | 0;
+  i11 = (HEAP32[i6 >> 2] | 0) + (1 - i12 << 4) | 0;
+  HEAP32[i6 >> 2] = i11;
+  if ((i10 | 0) <= 1) {
+   i1 = 30;
+   break;
+  }
+ }
+ if ((i1 | 0) == 10) {
+  _luaG_concaterror(i7, i14, i13);
+ } else if ((i1 | 0) == 24) {
+  _luaG_runerror(i7, 9e3, i9);
+ } else if ((i1 | 0) == 30) {
+  STACKTOP = i5;
+  return;
+ }
+}
+function _str_gsub(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 1344 | 0;
+ i4 = i3;
+ i5 = i3 + 1336 | 0;
+ i14 = i3 + 1332 | 0;
+ i10 = i3 + 1328 | 0;
+ i6 = i3 + 1048 | 0;
+ i2 = i3 + 8 | 0;
+ i20 = _luaL_checklstring(i1, 1, i14) | 0;
+ i13 = _luaL_checklstring(i1, 2, i10) | 0;
+ i8 = _lua_type(i1, 3) | 0;
+ i9 = _luaL_optinteger(i1, 4, (HEAP32[i14 >> 2] | 0) + 1 | 0) | 0;
+ i7 = (HEAP8[i13] | 0) == 94;
+ if (!((i8 + -3 | 0) >>> 0 < 2 | (i8 | 0) == 6 | (i8 | 0) == 5)) {
+  _luaL_argerror(i1, 3, 7528) | 0;
+ }
+ _luaL_buffinit(i1, i2);
+ if (i7) {
+  i15 = (HEAP32[i10 >> 2] | 0) + -1 | 0;
+  HEAP32[i10 >> 2] = i15;
+  i13 = i13 + 1 | 0;
+ } else {
+  i15 = HEAP32[i10 >> 2] | 0;
+ }
+ i11 = i6 + 16 | 0;
+ HEAP32[i11 >> 2] = i1;
+ HEAP32[i6 >> 2] = 200;
+ i12 = i6 + 4 | 0;
+ HEAP32[i12 >> 2] = i20;
+ i10 = i6 + 8 | 0;
+ HEAP32[i10 >> 2] = i20 + (HEAP32[i14 >> 2] | 0);
+ HEAP32[i6 + 12 >> 2] = i13 + i15;
+ i14 = i6 + 20 | 0;
+ i15 = i2 + 8 | 0;
+ i18 = i2 + 4 | 0;
+ i16 = i6 + 28 | 0;
+ i17 = i6 + 24 | 0;
+ i22 = 0;
+ while (1) {
+  if (!(i22 >>> 0 < i9 >>> 0)) {
+   i19 = 48;
+   break;
+  }
+  HEAP32[i14 >> 2] = 0;
+  i21 = _match(i6, i20, i13) | 0;
+  if ((i21 | 0) != 0) {
+   i22 = i22 + 1 | 0;
+   i23 = HEAP32[i11 >> 2] | 0;
+   if ((i8 | 0) == 5) {
+    do {
+     if ((HEAP32[i14 >> 2] | 0) > 0) {
+      i24 = HEAP32[i16 >> 2] | 0;
+      if (!((i24 | 0) == -1)) {
+       i25 = HEAP32[i17 >> 2] | 0;
+       if ((i24 | 0) == -2) {
+        _lua_pushinteger(i23, i25 + 1 - (HEAP32[i12 >> 2] | 0) | 0);
+        break;
+       } else {
+        i19 = i23;
+       }
+      } else {
+       _luaL_error(i23, 7248, i4) | 0;
+       i19 = HEAP32[i11 >> 2] | 0;
+       i25 = HEAP32[i17 >> 2] | 0;
+      }
+      _lua_pushlstring(i19, i25, i24) | 0;
+     } else {
+      _lua_pushlstring(i23, i20, i21 - i20 | 0) | 0;
+     }
+    } while (0);
+    _lua_gettable(i23, 3);
+    i19 = 37;
+   } else if ((i8 | 0) != 6) {
+    i24 = _lua_tolstring(i23, 3, i5) | 0;
+    if ((HEAP32[i5 >> 2] | 0) != 0) {
+     i23 = i21 - i20 | 0;
+     i25 = 0;
+     do {
+      i26 = i24 + i25 | 0;
+      i27 = HEAP8[i26] | 0;
+      do {
+       if (i27 << 24 >> 24 == 37) {
+        i25 = i25 + 1 | 0;
+        i26 = i24 + i25 | 0;
+        i28 = HEAP8[i26] | 0;
+        i27 = i28 << 24 >> 24;
+        if (((i28 & 255) + -48 | 0) >>> 0 < 10) {
+         if (i28 << 24 >> 24 == 48) {
+          _luaL_addlstring(i2, i20, i23);
+          break;
+         } else {
+          _push_onecapture(i6, i27 + -49 | 0, i20, i21);
+          _luaL_addvalue(i2);
+          break;
+         }
+        }
+        if (!(i28 << 24 >> 24 == 37)) {
+         i28 = HEAP32[i11 >> 2] | 0;
+         HEAP32[i4 >> 2] = 37;
+         _luaL_error(i28, 7600, i4) | 0;
+        }
+        i27 = HEAP32[i15 >> 2] | 0;
+        if (!(i27 >>> 0 < (HEAP32[i18 >> 2] | 0) >>> 0)) {
+         _luaL_prepbuffsize(i2, 1) | 0;
+         i27 = HEAP32[i15 >> 2] | 0;
+        }
+        i28 = HEAP8[i26] | 0;
+        HEAP32[i15 >> 2] = i27 + 1;
+        HEAP8[(HEAP32[i2 >> 2] | 0) + i27 | 0] = i28;
+       } else {
+        i28 = HEAP32[i15 >> 2] | 0;
+        if (!(i28 >>> 0 < (HEAP32[i18 >> 2] | 0) >>> 0)) {
+         _luaL_prepbuffsize(i2, 1) | 0;
+         i28 = HEAP32[i15 >> 2] | 0;
+         i27 = HEAP8[i26] | 0;
+        }
+        HEAP32[i15 >> 2] = i28 + 1;
+        HEAP8[(HEAP32[i2 >> 2] | 0) + i28 | 0] = i27;
+       }
+      } while (0);
+      i25 = i25 + 1 | 0;
+     } while (i25 >>> 0 < (HEAP32[i5 >> 2] | 0) >>> 0);
+    }
+   } else {
+    _lua_pushvalue(i23, 3);
+    i19 = HEAP32[i14 >> 2] | 0;
+    i19 = (i19 | 0) != 0 | (i20 | 0) == 0 ? i19 : 1;
+    _luaL_checkstack(HEAP32[i11 >> 2] | 0, i19, 7200);
+    if ((i19 | 0) > 0) {
+     i24 = 0;
+     do {
+      _push_onecapture(i6, i24, i20, i21);
+      i24 = i24 + 1 | 0;
+     } while ((i24 | 0) != (i19 | 0));
+    }
+    _lua_callk(i23, i19, 1, 0, 0);
+    i19 = 37;
+   }
+   if ((i19 | 0) == 37) {
+    i19 = 0;
+    if ((_lua_toboolean(i23, -1) | 0) != 0) {
+     if ((_lua_isstring(i23, -1) | 0) == 0) {
+      HEAP32[i4 >> 2] = _lua_typename(i23, _lua_type(i23, -1) | 0) | 0;
+      _luaL_error(i23, 7560, i4) | 0;
+     }
+    } else {
+     _lua_settop(i23, -2);
+     _lua_pushlstring(i23, i20, i21 - i20 | 0) | 0;
+    }
+    _luaL_addvalue(i2);
+   }
+   if (i21 >>> 0 > i20 >>> 0) {
+    i20 = i21;
+   } else {
+    i19 = 43;
+   }
+  } else {
+   i19 = 43;
+  }
+  if ((i19 | 0) == 43) {
+   i19 = 0;
+   if (!(i20 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0)) {
+    i19 = 48;
+    break;
+   }
+   i21 = HEAP32[i15 >> 2] | 0;
+   if (!(i21 >>> 0 < (HEAP32[i18 >> 2] | 0) >>> 0)) {
+    _luaL_prepbuffsize(i2, 1) | 0;
+    i21 = HEAP32[i15 >> 2] | 0;
+   }
+   i28 = HEAP8[i20] | 0;
+   HEAP32[i15 >> 2] = i21 + 1;
+   HEAP8[(HEAP32[i2 >> 2] | 0) + i21 | 0] = i28;
+   i20 = i20 + 1 | 0;
+  }
+  if (i7) {
+   i19 = 48;
+   break;
+  }
+ }
+ if ((i19 | 0) == 48) {
+  _luaL_addlstring(i2, i20, (HEAP32[i10 >> 2] | 0) - i20 | 0);
+  _luaL_pushresult(i2);
+  _lua_pushinteger(i1, i22);
+  STACKTOP = i3;
+  return 2;
+ }
+ return 0;
+}
+function _constructor(i11, i13) {
+ i11 = i11 | 0;
+ i13 = i13 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i12 = 0, i14 = 0, i15 = 0, i16 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i10 = i5 + 40 | 0;
+ i8 = i5;
+ i12 = i11 + 48 | 0;
+ i6 = HEAP32[i12 >> 2] | 0;
+ i9 = HEAP32[i11 + 4 >> 2] | 0;
+ i2 = _luaK_codeABC(i6, 11, 0, 0, 0) | 0;
+ i7 = i8 + 36 | 0;
+ HEAP32[i7 >> 2] = 0;
+ i4 = i8 + 28 | 0;
+ HEAP32[i4 >> 2] = 0;
+ i3 = i8 + 32 | 0;
+ HEAP32[i3 >> 2] = 0;
+ i1 = i8 + 24 | 0;
+ HEAP32[i1 >> 2] = i13;
+ HEAP32[i13 + 16 >> 2] = -1;
+ HEAP32[i13 + 20 >> 2] = -1;
+ HEAP32[i13 >> 2] = 11;
+ HEAP32[i13 + 8 >> 2] = i2;
+ HEAP32[i8 + 16 >> 2] = -1;
+ HEAP32[i8 + 20 >> 2] = -1;
+ HEAP32[i8 >> 2] = 0;
+ HEAP32[i8 + 8 >> 2] = 0;
+ _luaK_exp2nextreg(HEAP32[i12 >> 2] | 0, i13);
+ i13 = i11 + 16 | 0;
+ if ((HEAP32[i13 >> 2] | 0) != 123) {
+  _error_expected(i11, 123);
+ }
+ _luaX_next(i11);
+ L4 : do {
+  if ((HEAP32[i13 >> 2] | 0) != 125) {
+   L5 : while (1) {
+    if ((HEAP32[i8 >> 2] | 0) != 0 ? (_luaK_exp2nextreg(i6, i8), HEAP32[i8 >> 2] = 0, (HEAP32[i7 >> 2] | 0) == 50) : 0) {
+     _luaK_setlist(i6, HEAP32[(HEAP32[i1 >> 2] | 0) + 8 >> 2] | 0, HEAP32[i3 >> 2] | 0, 50);
+     HEAP32[i7 >> 2] = 0;
+    }
+    i14 = HEAP32[i13 >> 2] | 0;
+    do {
+     if ((i14 | 0) == 288) {
+      if ((_luaX_lookahead(i11) | 0) == 61) {
+       _recfield(i11, i8);
+       break;
+      }
+      _subexpr(i11, i8, 0) | 0;
+      i14 = HEAP32[i12 >> 2] | 0;
+      i15 = HEAP32[i3 >> 2] | 0;
+      if ((i15 | 0) > 2147483645) {
+       i12 = 10;
+       break L5;
+      }
+      HEAP32[i3 >> 2] = i15 + 1;
+      HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + 1;
+     } else if ((i14 | 0) == 91) {
+      _recfield(i11, i8);
+     } else {
+      _subexpr(i11, i8, 0) | 0;
+      i14 = HEAP32[i12 >> 2] | 0;
+      i15 = HEAP32[i3 >> 2] | 0;
+      if ((i15 | 0) > 2147483645) {
+       i12 = 17;
+       break L5;
+      }
+      HEAP32[i3 >> 2] = i15 + 1;
+      HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + 1;
+     }
+    } while (0);
+    i14 = HEAP32[i13 >> 2] | 0;
+    if ((i14 | 0) == 44) {
+     _luaX_next(i11);
+    } else if ((i14 | 0) == 59) {
+     _luaX_next(i11);
+    } else {
+     break L4;
+    }
+    if ((HEAP32[i13 >> 2] | 0) == 125) {
+     break L4;
+    }
+   }
+   if ((i12 | 0) == 10) {
+    i12 = i14 + 12 | 0;
+    i13 = HEAP32[(HEAP32[i12 >> 2] | 0) + 52 >> 2] | 0;
+    i14 = HEAP32[(HEAP32[i14 >> 2] | 0) + 64 >> 2] | 0;
+    if ((i14 | 0) == 0) {
+     i16 = 6552;
+     HEAP32[i10 >> 2] = 6528;
+     i15 = i10 + 4 | 0;
+     HEAP32[i15 >> 2] = 2147483645;
+     i15 = i10 + 8 | 0;
+     HEAP32[i15 >> 2] = i16;
+     i15 = _luaO_pushfstring(i13, 6592, i10) | 0;
+     i16 = HEAP32[i12 >> 2] | 0;
+     _luaX_syntaxerror(i16, i15);
+    }
+    HEAP32[i10 >> 2] = i14;
+    i15 = _luaO_pushfstring(i13, 6568, i10) | 0;
+    HEAP32[i10 >> 2] = 6528;
+    i16 = i10 + 4 | 0;
+    HEAP32[i16 >> 2] = 2147483645;
+    i16 = i10 + 8 | 0;
+    HEAP32[i16 >> 2] = i15;
+    i16 = _luaO_pushfstring(i13, 6592, i10) | 0;
+    i15 = HEAP32[i12 >> 2] | 0;
+    _luaX_syntaxerror(i15, i16);
+   } else if ((i12 | 0) == 17) {
+    i13 = i14 + 12 | 0;
+    i12 = HEAP32[(HEAP32[i13 >> 2] | 0) + 52 >> 2] | 0;
+    i14 = HEAP32[(HEAP32[i14 >> 2] | 0) + 64 >> 2] | 0;
+    if ((i14 | 0) == 0) {
+     i15 = 6552;
+     HEAP32[i10 >> 2] = 6528;
+     i16 = i10 + 4 | 0;
+     HEAP32[i16 >> 2] = 2147483645;
+     i16 = i10 + 8 | 0;
+     HEAP32[i16 >> 2] = i15;
+     i16 = _luaO_pushfstring(i12, 6592, i10) | 0;
+     i15 = HEAP32[i13 >> 2] | 0;
+     _luaX_syntaxerror(i15, i16);
+    }
+    HEAP32[i10 >> 2] = i14;
+    i15 = _luaO_pushfstring(i12, 6568, i10) | 0;
+    HEAP32[i10 >> 2] = 6528;
+    i16 = i10 + 4 | 0;
+    HEAP32[i16 >> 2] = 2147483645;
+    i16 = i10 + 8 | 0;
+    HEAP32[i16 >> 2] = i15;
+    i16 = _luaO_pushfstring(i12, 6592, i10) | 0;
+    i15 = HEAP32[i13 >> 2] | 0;
+    _luaX_syntaxerror(i15, i16);
+   }
+  }
+ } while (0);
+ _check_match(i11, 125, 123, i9);
+ i9 = HEAP32[i7 >> 2] | 0;
+ do {
+  if ((i9 | 0) != 0) {
+   i10 = HEAP32[i8 >> 2] | 0;
+   if ((i10 | 0) != 0) if ((i10 | 0) == 13 | (i10 | 0) == 12) {
+    _luaK_setreturns(i6, i8, -1);
+    _luaK_setlist(i6, HEAP32[(HEAP32[i1 >> 2] | 0) + 8 >> 2] | 0, HEAP32[i3 >> 2] | 0, -1);
+    HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + -1;
+    break;
+   } else {
+    _luaK_exp2nextreg(i6, i8);
+    i9 = HEAP32[i7 >> 2] | 0;
+   }
+   _luaK_setlist(i6, HEAP32[(HEAP32[i1 >> 2] | 0) + 8 >> 2] | 0, HEAP32[i3 >> 2] | 0, i9);
+  }
+ } while (0);
+ i16 = HEAP32[(HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] | 0) + (i2 << 2) >> 2] & 8388607;
+ i16 = (_luaO_int2fb(HEAP32[i3 >> 2] | 0) | 0) << 23 | i16;
+ HEAP32[(HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] | 0) + (i2 << 2) >> 2] = i16;
+ i16 = (_luaO_int2fb(HEAP32[i4 >> 2] | 0) | 0) << 14 & 8372224 | i16 & -8372225;
+ HEAP32[(HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] | 0) + (i2 << 2) >> 2] = i16;
+ STACKTOP = i5;
+ return;
+}
+function _luaK_prefix(i4, i14, i7, i13) {
+ i4 = i4 | 0;
+ i14 = i14 | 0;
+ i7 = i7 | 0;
+ i13 = i13 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i12 = i1;
+ HEAP32[i12 + 20 >> 2] = -1;
+ HEAP32[i12 + 16 >> 2] = -1;
+ HEAP32[i12 >> 2] = 5;
+ HEAPF64[i12 + 8 >> 3] = 0.0;
+ if ((i14 | 0) == 1) {
+  _luaK_dischargevars(i4, i7);
+  switch (HEAP32[i7 >> 2] | 0) {
+  case 2:
+  case 5:
+  case 4:
+   {
+    HEAP32[i7 >> 2] = 3;
+    break;
+   }
+  case 10:
+   {
+    i13 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+    i12 = HEAP32[i7 + 8 >> 2] | 0;
+    i10 = i13 + (i12 << 2) | 0;
+    if (!((i12 | 0) > 0 ? (i11 = i13 + (i12 + -1 << 2) | 0, i9 = HEAP32[i11 >> 2] | 0, (HEAP8[5584 + (i9 & 63) | 0] | 0) < 0) : 0)) {
+     i11 = i10;
+     i9 = HEAP32[i10 >> 2] | 0;
+    }
+    HEAP32[i11 >> 2] = ((i9 & 16320 | 0) == 0) << 6 | i9 & -16321;
+    break;
+   }
+  case 6:
+   {
+    i8 = 25;
+    break;
+   }
+  case 3:
+  case 1:
+   {
+    HEAP32[i7 >> 2] = 2;
+    break;
+   }
+  case 11:
+   {
+    i12 = i4 + 48 | 0;
+    i8 = HEAP8[i12] | 0;
+    i11 = (i8 & 255) + 1 | 0;
+    i9 = (HEAP32[i4 >> 2] | 0) + 78 | 0;
+    do {
+     if (i11 >>> 0 > (HEAPU8[i9] | 0) >>> 0) {
+      if (i11 >>> 0 > 249) {
+       _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10536);
+      } else {
+       HEAP8[i9] = i11;
+       i10 = HEAP8[i12] | 0;
+       break;
+      }
+     } else {
+      i10 = i8;
+     }
+    } while (0);
+    i14 = (i10 & 255) + 1 | 0;
+    HEAP8[i12] = i14;
+    _discharge2reg(i4, i7, (i14 & 255) + -1 | 0);
+    if ((HEAP32[i7 >> 2] | 0) == 6) {
+     i8 = 25;
+    } else {
+     i9 = i7 + 8 | 0;
+     i8 = 28;
+    }
+    break;
+   }
+  default:
+   {}
+  }
+  if ((i8 | 0) == 25) {
+   i8 = i7 + 8 | 0;
+   i9 = HEAP32[i8 >> 2] | 0;
+   if ((i9 & 256 | 0) == 0 ? (HEAPU8[i4 + 46 | 0] | 0) <= (i9 | 0) : 0) {
+    i9 = i4 + 48 | 0;
+    HEAP8[i9] = (HEAP8[i9] | 0) + -1 << 24 >> 24;
+    i9 = i8;
+    i8 = 28;
+   } else {
+    i9 = i8;
+    i8 = 28;
+   }
+  }
+  if ((i8 | 0) == 28) {
+   HEAP32[i9 >> 2] = _luaK_code(i4, HEAP32[i9 >> 2] << 23 | 20) | 0;
+   HEAP32[i7 >> 2] = 11;
+  }
+  i14 = i7 + 20 | 0;
+  i8 = HEAP32[i14 >> 2] | 0;
+  i7 = i7 + 16 | 0;
+  i9 = HEAP32[i7 >> 2] | 0;
+  HEAP32[i14 >> 2] = i9;
+  HEAP32[i7 >> 2] = i8;
+  if (!((i9 | 0) == -1)) {
+   i8 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+   do {
+    i12 = i8 + (i9 << 2) | 0;
+    if ((i9 | 0) > 0 ? (i5 = i8 + (i9 + -1 << 2) | 0, i6 = HEAP32[i5 >> 2] | 0, (HEAP8[5584 + (i6 & 63) | 0] | 0) < 0) : 0) {
+     i10 = i5;
+     i11 = i6;
+    } else {
+     i10 = i12;
+     i11 = HEAP32[i12 >> 2] | 0;
+    }
+    if ((i11 & 63 | 0) == 28) {
+     HEAP32[i10 >> 2] = i11 & 8372224 | i11 >>> 23 << 6 | 27;
+    }
+    i10 = ((HEAP32[i12 >> 2] | 0) >>> 14) + -131071 | 0;
+    if ((i10 | 0) == -1) {
+     break;
+    }
+    i9 = i9 + 1 + i10 | 0;
+   } while (!((i9 | 0) == -1));
+   i8 = HEAP32[i7 >> 2] | 0;
+  }
+  if ((i8 | 0) == -1) {
+   STACKTOP = i1;
+   return;
+  }
+  i4 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+  while (1) {
+   i6 = i4 + (i8 << 2) | 0;
+   if ((i8 | 0) > 0 ? (i2 = i4 + (i8 + -1 << 2) | 0, i3 = HEAP32[i2 >> 2] | 0, (HEAP8[5584 + (i3 & 63) | 0] | 0) < 0) : 0) {
+    i7 = i2;
+    i5 = i3;
+   } else {
+    i7 = i6;
+    i5 = HEAP32[i6 >> 2] | 0;
+   }
+   if ((i5 & 63 | 0) == 28) {
+    HEAP32[i7 >> 2] = i5 & 8372224 | i5 >>> 23 << 6 | 27;
+   }
+   i5 = ((HEAP32[i6 >> 2] | 0) >>> 14) + -131071 | 0;
+   if ((i5 | 0) == -1) {
+    i8 = 54;
+    break;
+   }
+   i8 = i8 + 1 + i5 | 0;
+   if ((i8 | 0) == -1) {
+    i8 = 54;
+    break;
+   }
+  }
+  if ((i8 | 0) == 54) {
+   STACKTOP = i1;
+   return;
+  }
+ } else if ((i14 | 0) == 0) {
+  if (((HEAP32[i7 >> 2] | 0) == 5 ? (HEAP32[i7 + 16 >> 2] | 0) == -1 : 0) ? (HEAP32[i7 + 20 >> 2] | 0) == -1 : 0) {
+   i14 = i7 + 8 | 0;
+   HEAPF64[i14 >> 3] = -+HEAPF64[i14 >> 3];
+   STACKTOP = i1;
+   return;
+  }
+  _luaK_dischargevars(i4, i7);
+  if ((HEAP32[i7 >> 2] | 0) == 6) {
+   i2 = HEAP32[i7 + 8 >> 2] | 0;
+   if ((HEAP32[i7 + 16 >> 2] | 0) != (HEAP32[i7 + 20 >> 2] | 0)) {
+    if ((i2 | 0) < (HEAPU8[i4 + 46 | 0] | 0)) {
+     i8 = 10;
+    } else {
+     _exp2reg(i4, i7, i2);
+    }
+   }
+  } else {
+   i8 = 10;
+  }
+  if ((i8 | 0) == 10) {
+   _luaK_exp2nextreg(i4, i7);
+  }
+  _codearith(i4, 19, i7, i12, i13);
+  STACKTOP = i1;
+  return;
+ } else if ((i14 | 0) == 2) {
+  _luaK_dischargevars(i4, i7);
+  if ((HEAP32[i7 >> 2] | 0) == 6) {
+   i2 = HEAP32[i7 + 8 >> 2] | 0;
+   if ((HEAP32[i7 + 16 >> 2] | 0) != (HEAP32[i7 + 20 >> 2] | 0)) {
+    if ((i2 | 0) < (HEAPU8[i4 + 46 | 0] | 0)) {
+     i8 = 52;
+    } else {
+     _exp2reg(i4, i7, i2);
+    }
+   }
+  } else {
+   i8 = 52;
+  }
+  if ((i8 | 0) == 52) {
+   _luaK_exp2nextreg(i4, i7);
+  }
+  _codearith(i4, 21, i7, i12, i13);
+  STACKTOP = i1;
+  return;
+ } else {
+  STACKTOP = i1;
+  return;
+ }
+}
+function _subexpr(i6, i3, i7) {
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i11 = i2 + 24 | 0;
+ i5 = i2;
+ i4 = i6 + 48 | 0;
+ i9 = HEAP32[i4 >> 2] | 0;
+ i1 = i6 + 52 | 0;
+ i12 = (HEAP32[i1 >> 2] | 0) + 38 | 0;
+ i13 = (HEAP16[i12 >> 1] | 0) + 1 << 16 >> 16;
+ HEAP16[i12 >> 1] = i13;
+ if ((i13 & 65535) > 200) {
+  i10 = i9 + 12 | 0;
+  i12 = HEAP32[(HEAP32[i10 >> 2] | 0) + 52 >> 2] | 0;
+  i13 = HEAP32[(HEAP32[i9 >> 2] | 0) + 64 >> 2] | 0;
+  if ((i13 | 0) == 0) {
+   i15 = 6552;
+   HEAP32[i11 >> 2] = 6360;
+   i14 = i11 + 4 | 0;
+   HEAP32[i14 >> 2] = 200;
+   i14 = i11 + 8 | 0;
+   HEAP32[i14 >> 2] = i15;
+   i14 = _luaO_pushfstring(i12, 6592, i11) | 0;
+   i15 = HEAP32[i10 >> 2] | 0;
+   _luaX_syntaxerror(i15, i14);
+  }
+  HEAP32[i11 >> 2] = i13;
+  i14 = _luaO_pushfstring(i12, 6568, i11) | 0;
+  HEAP32[i11 >> 2] = 6360;
+  i15 = i11 + 4 | 0;
+  HEAP32[i15 >> 2] = 200;
+  i15 = i11 + 8 | 0;
+  HEAP32[i15 >> 2] = i14;
+  i15 = _luaO_pushfstring(i12, 6592, i11) | 0;
+  i14 = HEAP32[i10 >> 2] | 0;
+  _luaX_syntaxerror(i14, i15);
+ }
+ i10 = i6 + 16 | 0;
+ L8 : do {
+  switch (HEAP32[i10 >> 2] | 0) {
+  case 287:
+   {
+    HEAP32[i3 + 16 >> 2] = -1;
+    HEAP32[i3 + 20 >> 2] = -1;
+    HEAP32[i3 >> 2] = 5;
+    HEAP32[i3 + 8 >> 2] = 0;
+    HEAPF64[i3 + 8 >> 3] = +HEAPF64[i6 + 24 >> 3];
+    i8 = 20;
+    break;
+   }
+  case 271:
+   {
+    i9 = 1;
+    i8 = 8;
+    break;
+   }
+  case 289:
+   {
+    i8 = _luaK_stringK(i9, HEAP32[i6 + 24 >> 2] | 0) | 0;
+    HEAP32[i3 + 16 >> 2] = -1;
+    HEAP32[i3 + 20 >> 2] = -1;
+    HEAP32[i3 >> 2] = 4;
+    HEAP32[i3 + 8 >> 2] = i8;
+    i8 = 20;
+    break;
+   }
+  case 265:
+   {
+    _luaX_next(i6);
+    _body(i6, i3, 0, HEAP32[i6 + 4 >> 2] | 0);
+    break;
+   }
+  case 276:
+   {
+    HEAP32[i3 + 16 >> 2] = -1;
+    HEAP32[i3 + 20 >> 2] = -1;
+    HEAP32[i3 >> 2] = 2;
+    HEAP32[i3 + 8 >> 2] = 0;
+    i8 = 20;
+    break;
+   }
+  case 45:
+   {
+    i9 = 0;
+    i8 = 8;
+    break;
+   }
+  case 35:
+   {
+    i9 = 2;
+    i8 = 8;
+    break;
+   }
+  case 123:
+   {
+    _constructor(i6, i3);
+    break;
+   }
+  case 263:
+   {
+    HEAP32[i3 + 16 >> 2] = -1;
+    HEAP32[i3 + 20 >> 2] = -1;
+    HEAP32[i3 >> 2] = 3;
+    HEAP32[i3 + 8 >> 2] = 0;
+    i8 = 20;
+    break;
+   }
+  case 280:
+   {
+    if ((HEAP8[(HEAP32[i9 >> 2] | 0) + 77 | 0] | 0) == 0) {
+     _luaX_syntaxerror(i6, 6408);
+    } else {
+     i8 = _luaK_codeABC(i9, 38, 0, 1, 0) | 0;
+     HEAP32[i3 + 16 >> 2] = -1;
+     HEAP32[i3 + 20 >> 2] = -1;
+     HEAP32[i3 >> 2] = 13;
+     HEAP32[i3 + 8 >> 2] = i8;
+     i8 = 20;
+     break L8;
+    }
+    break;
+   }
+  case 270:
+   {
+    HEAP32[i3 + 16 >> 2] = -1;
+    HEAP32[i3 + 20 >> 2] = -1;
+    HEAP32[i3 >> 2] = 1;
+    HEAP32[i3 + 8 >> 2] = 0;
+    i8 = 20;
+    break;
+   }
+  default:
+   {
+    _suffixedexp(i6, i3);
+   }
+  }
+ } while (0);
+ if ((i8 | 0) == 8) {
+  i15 = HEAP32[i6 + 4 >> 2] | 0;
+  _luaX_next(i6);
+  _subexpr(i6, i3, 8) | 0;
+  _luaK_prefix(HEAP32[i4 >> 2] | 0, i9, i3, i15);
+ } else if ((i8 | 0) == 20) {
+  _luaX_next(i6);
+ }
+ switch (HEAP32[i10 >> 2] | 0) {
+ case 257:
+  {
+   i9 = 13;
+   break;
+  }
+ case 272:
+  {
+   i9 = 14;
+   break;
+  }
+ case 47:
+  {
+   i9 = 3;
+   break;
+  }
+ case 37:
+  {
+   i9 = 4;
+   break;
+  }
+ case 43:
+  {
+   i9 = 0;
+   break;
+  }
+ case 284:
+  {
+   i9 = 10;
+   break;
+  }
+ case 281:
+  {
+   i9 = 7;
+   break;
+  }
+ case 62:
+  {
+   i9 = 11;
+   break;
+  }
+ case 282:
+  {
+   i9 = 12;
+   break;
+  }
+ case 45:
+  {
+   i9 = 1;
+   break;
+  }
+ case 42:
+  {
+   i9 = 2;
+   break;
+  }
+ case 60:
+  {
+   i9 = 8;
+   break;
+  }
+ case 283:
+  {
+   i9 = 9;
+   break;
+  }
+ case 94:
+  {
+   i9 = 5;
+   break;
+  }
+ case 279:
+  {
+   i9 = 6;
+   break;
+  }
+ default:
+  {
+   i15 = 15;
+   i14 = HEAP32[i1 >> 2] | 0;
+   i14 = i14 + 38 | 0;
+   i13 = HEAP16[i14 >> 1] | 0;
+   i13 = i13 + -1 << 16 >> 16;
+   HEAP16[i14 >> 1] = i13;
+   STACKTOP = i2;
+   return i15 | 0;
+  }
+ }
+ i8 = i6 + 4 | 0;
+ while (1) {
+  if ((HEAPU8[6376 + (i9 << 1) | 0] | 0) <= (i7 | 0)) {
+   i8 = 39;
+   break;
+  }
+  i15 = HEAP32[i8 >> 2] | 0;
+  _luaX_next(i6);
+  _luaK_infix(HEAP32[i4 >> 2] | 0, i9, i3);
+  i10 = _subexpr(i6, i5, HEAPU8[6377 + (i9 << 1) | 0] | 0) | 0;
+  _luaK_posfix(HEAP32[i4 >> 2] | 0, i9, i3, i5, i15);
+  if ((i10 | 0) == 15) {
+   i9 = 15;
+   i8 = 39;
+   break;
+  } else {
+   i9 = i10;
+  }
+ }
+ if ((i8 | 0) == 39) {
+  i15 = HEAP32[i1 >> 2] | 0;
+  i15 = i15 + 38 | 0;
+  i14 = HEAP16[i15 >> 1] | 0;
+  i14 = i14 + -1 << 16 >> 16;
+  HEAP16[i15 >> 1] = i14;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ return 0;
+}
+function _luaV_lessequal(i5, i3, i2) {
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ i4 = i3 + 8 | 0;
+ i7 = HEAP32[i4 >> 2] | 0;
+ if ((i7 | 0) == 3) {
+  if ((HEAP32[i2 + 8 >> 2] | 0) == 3) {
+   i9 = +HEAPF64[i3 >> 3] <= +HEAPF64[i2 >> 3] | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ } else {
+  if ((i7 & 15 | 0) == 4 ? (HEAP32[i2 + 8 >> 2] & 15 | 0) == 4 : 0) {
+   i3 = HEAP32[i3 >> 2] | 0;
+   i6 = HEAP32[i2 >> 2] | 0;
+   i4 = i3 + 16 | 0;
+   i5 = i6 + 16 | 0;
+   i7 = _strcmp(i4, i5) | 0;
+   L8 : do {
+    if ((i7 | 0) == 0) {
+     i2 = HEAP32[i3 + 12 >> 2] | 0;
+     i3 = HEAP32[i6 + 12 >> 2] | 0;
+     i6 = i5;
+     while (1) {
+      i5 = _strlen(i4 | 0) | 0;
+      i7 = (i5 | 0) == (i2 | 0);
+      if ((i5 | 0) == (i3 | 0)) {
+       break;
+      }
+      if (i7) {
+       i7 = -1;
+       break L8;
+      }
+      i5 = i5 + 1 | 0;
+      i4 = i4 + i5 | 0;
+      i6 = i6 + i5 | 0;
+      i7 = _strcmp(i4, i6) | 0;
+      if ((i7 | 0) == 0) {
+       i2 = i2 - i5 | 0;
+       i3 = i3 - i5 | 0;
+      } else {
+       break L8;
+      }
+     }
+     i7 = i7 & 1 ^ 1;
+    }
+   } while (0);
+   i9 = (i7 | 0) < 1 | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ }
+ i7 = i5 + 8 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ i9 = _luaT_gettmbyobj(i5, i3, 14) | 0;
+ if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+  i9 = _luaT_gettmbyobj(i5, i2, 14) | 0;
+  if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+   i8 = HEAP32[i7 >> 2] | 0;
+   i9 = _luaT_gettmbyobj(i5, i2, 13) | 0;
+   if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+    i9 = _luaT_gettmbyobj(i5, i3, 13) | 0;
+    if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+     _luaG_ordererror(i5, i3, i2);
+    } else {
+     i6 = i9;
+    }
+   } else {
+    i6 = i9;
+   }
+   i10 = i5 + 28 | 0;
+   i9 = i8 - (HEAP32[i10 >> 2] | 0) | 0;
+   i8 = HEAP32[i7 >> 2] | 0;
+   HEAP32[i7 >> 2] = i8 + 16;
+   i13 = i6;
+   i11 = HEAP32[i13 + 4 >> 2] | 0;
+   i12 = i8;
+   HEAP32[i12 >> 2] = HEAP32[i13 >> 2];
+   HEAP32[i12 + 4 >> 2] = i11;
+   HEAP32[i8 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   i8 = HEAP32[i7 >> 2] | 0;
+   HEAP32[i7 >> 2] = i8 + 16;
+   i12 = i2;
+   i11 = HEAP32[i12 + 4 >> 2] | 0;
+   i6 = i8;
+   HEAP32[i6 >> 2] = HEAP32[i12 >> 2];
+   HEAP32[i6 + 4 >> 2] = i11;
+   HEAP32[i8 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+   i2 = HEAP32[i7 >> 2] | 0;
+   HEAP32[i7 >> 2] = i2 + 16;
+   i8 = i3;
+   i6 = HEAP32[i8 + 4 >> 2] | 0;
+   i3 = i2;
+   HEAP32[i3 >> 2] = HEAP32[i8 >> 2];
+   HEAP32[i3 + 4 >> 2] = i6;
+   HEAP32[i2 + 8 >> 2] = HEAP32[i4 >> 2];
+   _luaD_call(i5, (HEAP32[i7 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i5 + 16 >> 2] | 0) + 18 | 0] & 1);
+   i3 = HEAP32[i10 >> 2] | 0;
+   i2 = HEAP32[i7 >> 2] | 0;
+   i5 = i2 + -16 | 0;
+   HEAP32[i7 >> 2] = i5;
+   i6 = HEAP32[i5 + 4 >> 2] | 0;
+   i8 = i3 + i9 | 0;
+   HEAP32[i8 >> 2] = HEAP32[i5 >> 2];
+   HEAP32[i8 + 4 >> 2] = i6;
+   HEAP32[i3 + (i9 + 8) >> 2] = HEAP32[i2 + -8 >> 2];
+   i3 = HEAP32[i7 >> 2] | 0;
+   i2 = HEAP32[i3 + 8 >> 2] | 0;
+   if ((i2 | 0) != 0) {
+    if ((i2 | 0) == 1) {
+     i2 = (HEAP32[i3 >> 2] | 0) != 0;
+    } else {
+     i2 = 1;
+    }
+   } else {
+    i2 = 0;
+   }
+   i13 = i2 & 1 ^ 1;
+   STACKTOP = i1;
+   return i13 | 0;
+  }
+ }
+ i10 = i5 + 28 | 0;
+ i13 = i8 - (HEAP32[i10 >> 2] | 0) | 0;
+ i11 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i11 + 16;
+ i6 = i9;
+ i8 = HEAP32[i6 + 4 >> 2] | 0;
+ i12 = i11;
+ HEAP32[i12 >> 2] = HEAP32[i6 >> 2];
+ HEAP32[i12 + 4 >> 2] = i8;
+ HEAP32[i11 + 8 >> 2] = HEAP32[i9 + 8 >> 2];
+ i9 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i9 + 16;
+ i11 = i3;
+ i12 = HEAP32[i11 + 4 >> 2] | 0;
+ i3 = i9;
+ HEAP32[i3 >> 2] = HEAP32[i11 >> 2];
+ HEAP32[i3 + 4 >> 2] = i12;
+ HEAP32[i9 + 8 >> 2] = HEAP32[i4 >> 2];
+ i3 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i3 + 16;
+ i9 = i2;
+ i12 = HEAP32[i9 + 4 >> 2] | 0;
+ i11 = i3;
+ HEAP32[i11 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i11 + 4 >> 2] = i12;
+ HEAP32[i3 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+ _luaD_call(i5, (HEAP32[i7 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i5 + 16 >> 2] | 0) + 18 | 0] & 1);
+ i2 = HEAP32[i10 >> 2] | 0;
+ i3 = HEAP32[i7 >> 2] | 0;
+ i10 = i3 + -16 | 0;
+ HEAP32[i7 >> 2] = i10;
+ i11 = HEAP32[i10 + 4 >> 2] | 0;
+ i12 = i2 + i13 | 0;
+ HEAP32[i12 >> 2] = HEAP32[i10 >> 2];
+ HEAP32[i12 + 4 >> 2] = i11;
+ HEAP32[i2 + (i13 + 8) >> 2] = HEAP32[i3 + -8 >> 2];
+ i2 = HEAP32[i7 >> 2] | 0;
+ i3 = HEAP32[i2 + 8 >> 2] | 0;
+ if ((i3 | 0) != 0) {
+  if ((i3 | 0) == 1) {
+   i2 = (HEAP32[i2 >> 2] | 0) != 0;
+  } else {
+   i2 = 1;
+  }
+ } else {
+  i2 = 0;
+ }
+ i13 = i2 & 1;
+ STACKTOP = i1;
+ return i13 | 0;
+}
+function ___udivmoddi4(i6, i8, i2, i4, i1) {
+ i6 = i6 | 0;
+ i8 = i8 | 0;
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ var i3 = 0, i5 = 0, i7 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i5 = i6;
+ i9 = i8;
+ i7 = i9;
+ i10 = i2;
+ i3 = i4;
+ i11 = i3;
+ if ((i7 | 0) == 0) {
+  i2 = (i1 | 0) != 0;
+  if ((i11 | 0) == 0) {
+   if (i2) {
+    HEAP32[i1 >> 2] = (i5 >>> 0) % (i10 >>> 0);
+    HEAP32[i1 + 4 >> 2] = 0;
+   }
+   i11 = 0;
+   i12 = (i5 >>> 0) / (i10 >>> 0) >>> 0;
+   return (tempRet0 = i11, i12) | 0;
+  } else {
+   if (!i2) {
+    i11 = 0;
+    i12 = 0;
+    return (tempRet0 = i11, i12) | 0;
+   }
+   HEAP32[i1 >> 2] = i6 | 0;
+   HEAP32[i1 + 4 >> 2] = i8 & 0;
+   i11 = 0;
+   i12 = 0;
+   return (tempRet0 = i11, i12) | 0;
+  }
+ }
+ i12 = (i11 | 0) == 0;
+ do {
+  if ((i10 | 0) != 0) {
+   if (!i12) {
+    i10 = (_llvm_ctlz_i32(i11 | 0) | 0) - (_llvm_ctlz_i32(i7 | 0) | 0) | 0;
+    if (i10 >>> 0 <= 31) {
+     i11 = i10 + 1 | 0;
+     i12 = 31 - i10 | 0;
+     i8 = i10 - 31 >> 31;
+     i9 = i11;
+     i6 = i5 >>> (i11 >>> 0) & i8 | i7 << i12;
+     i8 = i7 >>> (i11 >>> 0) & i8;
+     i11 = 0;
+     i7 = i5 << i12;
+     break;
+    }
+    if ((i1 | 0) == 0) {
+     i11 = 0;
+     i12 = 0;
+     return (tempRet0 = i11, i12) | 0;
+    }
+    HEAP32[i1 >> 2] = i6 | 0;
+    HEAP32[i1 + 4 >> 2] = i9 | i8 & 0;
+    i11 = 0;
+    i12 = 0;
+    return (tempRet0 = i11, i12) | 0;
+   }
+   i11 = i10 - 1 | 0;
+   if ((i11 & i10 | 0) != 0) {
+    i12 = (_llvm_ctlz_i32(i10 | 0) | 0) + 33 - (_llvm_ctlz_i32(i7 | 0) | 0) | 0;
+    i15 = 64 - i12 | 0;
+    i10 = 32 - i12 | 0;
+    i13 = i10 >> 31;
+    i14 = i12 - 32 | 0;
+    i8 = i14 >> 31;
+    i9 = i12;
+    i6 = i10 - 1 >> 31 & i7 >>> (i14 >>> 0) | (i7 << i10 | i5 >>> (i12 >>> 0)) & i8;
+    i8 = i8 & i7 >>> (i12 >>> 0);
+    i11 = i5 << i15 & i13;
+    i7 = (i7 << i15 | i5 >>> (i14 >>> 0)) & i13 | i5 << i10 & i12 - 33 >> 31;
+    break;
+   }
+   if ((i1 | 0) != 0) {
+    HEAP32[i1 >> 2] = i11 & i5;
+    HEAP32[i1 + 4 >> 2] = 0;
+   }
+   if ((i10 | 0) == 1) {
+    i14 = i9 | i8 & 0;
+    i15 = i6 | 0 | 0;
+    return (tempRet0 = i14, i15) | 0;
+   } else {
+    i15 = _llvm_cttz_i32(i10 | 0) | 0;
+    i14 = i7 >>> (i15 >>> 0) | 0;
+    i15 = i7 << 32 - i15 | i5 >>> (i15 >>> 0) | 0;
+    return (tempRet0 = i14, i15) | 0;
+   }
+  } else {
+   if (i12) {
+    if ((i1 | 0) != 0) {
+     HEAP32[i1 >> 2] = (i7 >>> 0) % (i10 >>> 0);
+     HEAP32[i1 + 4 >> 2] = 0;
+    }
+    i14 = 0;
+    i15 = (i7 >>> 0) / (i10 >>> 0) >>> 0;
+    return (tempRet0 = i14, i15) | 0;
+   }
+   if ((i5 | 0) == 0) {
+    if ((i1 | 0) != 0) {
+     HEAP32[i1 >> 2] = 0;
+     HEAP32[i1 + 4 >> 2] = (i7 >>> 0) % (i11 >>> 0);
+    }
+    i14 = 0;
+    i15 = (i7 >>> 0) / (i11 >>> 0) >>> 0;
+    return (tempRet0 = i14, i15) | 0;
+   }
+   i10 = i11 - 1 | 0;
+   if ((i10 & i11 | 0) == 0) {
+    if ((i1 | 0) != 0) {
+     HEAP32[i1 >> 2] = i6 | 0;
+     HEAP32[i1 + 4 >> 2] = i10 & i7 | i8 & 0;
+    }
+    i14 = 0;
+    i15 = i7 >>> ((_llvm_cttz_i32(i11 | 0) | 0) >>> 0);
+    return (tempRet0 = i14, i15) | 0;
+   }
+   i10 = (_llvm_ctlz_i32(i11 | 0) | 0) - (_llvm_ctlz_i32(i7 | 0) | 0) | 0;
+   if (i10 >>> 0 <= 30) {
+    i8 = i10 + 1 | 0;
+    i15 = 31 - i10 | 0;
+    i9 = i8;
+    i6 = i7 << i15 | i5 >>> (i8 >>> 0);
+    i8 = i7 >>> (i8 >>> 0);
+    i11 = 0;
+    i7 = i5 << i15;
+    break;
+   }
+   if ((i1 | 0) == 0) {
+    i14 = 0;
+    i15 = 0;
+    return (tempRet0 = i14, i15) | 0;
+   }
+   HEAP32[i1 >> 2] = i6 | 0;
+   HEAP32[i1 + 4 >> 2] = i9 | i8 & 0;
+   i14 = 0;
+   i15 = 0;
+   return (tempRet0 = i14, i15) | 0;
+  }
+ } while (0);
+ if ((i9 | 0) == 0) {
+  i12 = i6;
+  i2 = 0;
+  i6 = 0;
+ } else {
+  i2 = i2 | 0 | 0;
+  i3 = i3 | i4 & 0;
+  i4 = _i64Add(i2, i3, -1, -1) | 0;
+  i5 = tempRet0;
+  i10 = i8;
+  i12 = i6;
+  i6 = 0;
+  while (1) {
+   i8 = i11 >>> 31 | i7 << 1;
+   i11 = i6 | i11 << 1;
+   i7 = i12 << 1 | i7 >>> 31 | 0;
+   i10 = i12 >>> 31 | i10 << 1 | 0;
+   _i64Subtract(i4, i5, i7, i10) | 0;
+   i12 = tempRet0;
+   i15 = i12 >> 31 | ((i12 | 0) < 0 ? -1 : 0) << 1;
+   i6 = i15 & 1;
+   i12 = _i64Subtract(i7, i10, i15 & i2, (((i12 | 0) < 0 ? -1 : 0) >> 31 | ((i12 | 0) < 0 ? -1 : 0) << 1) & i3) | 0;
+   i10 = tempRet0;
+   i9 = i9 - 1 | 0;
+   if ((i9 | 0) == 0) {
+    break;
+   } else {
+    i7 = i8;
+   }
+  }
+  i7 = i8;
+  i8 = i10;
+  i2 = 0;
+ }
+ i3 = 0;
+ if ((i1 | 0) != 0) {
+  HEAP32[i1 >> 2] = i12;
+  HEAP32[i1 + 4 >> 2] = i8;
+ }
+ i14 = (i11 | 0) >>> 31 | (i7 | i3) << 1 | (i3 << 1 | i11 >>> 31) & 0 | i2;
+ i15 = (i11 << 1 | 0 >>> 31) & -2 | i6;
+ return (tempRet0 = i14, i15) | 0;
+}
+function _leaveblock(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i3;
+ i7 = i1 + 16 | 0;
+ i4 = HEAP32[i7 >> 2] | 0;
+ i2 = i1 + 12 | 0;
+ i6 = HEAP32[i2 >> 2] | 0;
+ if ((HEAP32[i4 >> 2] | 0) != 0 ? (HEAP8[i4 + 9 | 0] | 0) != 0 : 0) {
+  i16 = _luaK_jump(i1) | 0;
+  _luaK_patchclose(i1, i16, HEAPU8[i4 + 8 | 0] | 0);
+  _luaK_patchtohere(i1, i16);
+ }
+ L5 : do {
+  if ((HEAP8[i4 + 10 | 0] | 0) != 0) {
+   i15 = i6 + 52 | 0;
+   i14 = _luaS_new(HEAP32[i15 >> 2] | 0, 6304) | 0;
+   i13 = i6 + 64 | 0;
+   i16 = HEAP32[i13 >> 2] | 0;
+   i10 = i16 + 24 | 0;
+   i8 = i6 + 48 | 0;
+   i11 = HEAP32[(HEAP32[i8 >> 2] | 0) + 20 >> 2] | 0;
+   i12 = i16 + 28 | 0;
+   i9 = HEAP32[i12 >> 2] | 0;
+   i16 = i16 + 32 | 0;
+   if ((i9 | 0) < (HEAP32[i16 >> 2] | 0)) {
+    i15 = HEAP32[i10 >> 2] | 0;
+   } else {
+    i15 = _luaM_growaux_(HEAP32[i15 >> 2] | 0, HEAP32[i10 >> 2] | 0, i16, 16, 32767, 6312) | 0;
+    HEAP32[i10 >> 2] = i15;
+   }
+   HEAP32[i15 + (i9 << 4) >> 2] = i14;
+   i16 = HEAP32[i10 >> 2] | 0;
+   HEAP32[i16 + (i9 << 4) + 8 >> 2] = 0;
+   HEAP8[i16 + (i9 << 4) + 12 | 0] = HEAP8[(HEAP32[i8 >> 2] | 0) + 46 | 0] | 0;
+   HEAP32[(HEAP32[i10 >> 2] | 0) + (i9 << 4) + 4 >> 2] = i11;
+   HEAP32[i12 >> 2] = (HEAP32[i12 >> 2] | 0) + 1;
+   i10 = HEAP32[i13 >> 2] | 0;
+   i9 = (HEAP32[i10 + 24 >> 2] | 0) + (i9 << 4) | 0;
+   i11 = HEAP16[(HEAP32[(HEAP32[i8 >> 2] | 0) + 16 >> 2] | 0) + 6 >> 1] | 0;
+   i8 = i10 + 16 | 0;
+   if ((i11 | 0) < (HEAP32[i8 >> 2] | 0)) {
+    i10 = i10 + 12 | 0;
+    do {
+     while (1) {
+      if ((_luaS_eqstr(HEAP32[(HEAP32[i10 >> 2] | 0) + (i11 << 4) >> 2] | 0, HEAP32[i9 >> 2] | 0) | 0) == 0) {
+       break;
+      }
+      _closegoto(i6, i11, i9);
+      if ((i11 | 0) >= (HEAP32[i8 >> 2] | 0)) {
+       break L5;
+      }
+     }
+     i11 = i11 + 1 | 0;
+    } while ((i11 | 0) < (HEAP32[i8 >> 2] | 0));
+   }
+  }
+ } while (0);
+ HEAP32[i7 >> 2] = HEAP32[i4 >> 2];
+ i7 = i4 + 8 | 0;
+ i9 = HEAP8[i7] | 0;
+ i10 = i1 + 46 | 0;
+ i8 = (HEAP32[i2 >> 2] | 0) + 64 | 0;
+ i14 = (HEAP32[i8 >> 2] | 0) + 4 | 0;
+ HEAP32[i14 >> 2] = (i9 & 255) - (HEAPU8[i10] | 0) + (HEAP32[i14 >> 2] | 0);
+ i14 = HEAP8[i10] | 0;
+ if ((i14 & 255) > (i9 & 255)) {
+  i13 = i1 + 20 | 0;
+  i11 = i1 + 40 | 0;
+  i12 = (HEAP32[i1 >> 2] | 0) + 24 | 0;
+  do {
+   i16 = HEAP32[i13 >> 2] | 0;
+   i14 = i14 + -1 << 24 >> 24;
+   HEAP8[i10] = i14;
+   HEAP32[(HEAP32[i12 >> 2] | 0) + ((HEAP16[(HEAP32[HEAP32[i8 >> 2] >> 2] | 0) + ((HEAP32[i11 >> 2] | 0) + (i14 & 255) << 1) >> 1] | 0) * 12 | 0) + 8 >> 2] = i16;
+   i14 = HEAP8[i10] | 0;
+  } while ((i14 & 255) > (i9 & 255));
+ }
+ HEAP8[i1 + 48 | 0] = i14;
+ i10 = HEAP32[i6 + 64 >> 2] | 0;
+ HEAP32[i10 + 28 >> 2] = HEAP16[i4 + 4 >> 1] | 0;
+ i9 = HEAP16[i4 + 6 >> 1] | 0;
+ if ((HEAP32[i4 >> 2] | 0) == 0) {
+  if ((i9 | 0) >= (HEAP32[i10 + 16 >> 2] | 0)) {
+   STACKTOP = i3;
+   return;
+  }
+  i10 = HEAP32[i10 + 12 >> 2] | 0;
+  i11 = HEAP32[i10 + (i9 << 4) >> 2] | 0;
+  if ((HEAP8[i11 + 4 | 0] | 0) != 4) {
+   i16 = 6200;
+   i15 = i6 + 52 | 0;
+   i15 = HEAP32[i15 >> 2] | 0;
+   i14 = i11 + 16 | 0;
+   i13 = i10 + (i9 << 4) + 8 | 0;
+   i13 = HEAP32[i13 >> 2] | 0;
+   HEAP32[i5 >> 2] = i14;
+   i14 = i5 + 4 | 0;
+   HEAP32[i14 >> 2] = i13;
+   i16 = _luaO_pushfstring(i15, i16, i5) | 0;
+   _semerror(i6, i16);
+  }
+  i16 = (HEAP8[i11 + 6 | 0] | 0) != 0 ? 6160 : 6200;
+  i15 = i6 + 52 | 0;
+  i15 = HEAP32[i15 >> 2] | 0;
+  i14 = i11 + 16 | 0;
+  i13 = i10 + (i9 << 4) + 8 | 0;
+  i13 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i5 >> 2] = i14;
+  i14 = i5 + 4 | 0;
+  HEAP32[i14 >> 2] = i13;
+  i16 = _luaO_pushfstring(i15, i16, i5) | 0;
+  _semerror(i6, i16);
+ }
+ i6 = HEAP32[i8 >> 2] | 0;
+ i5 = i6 + 16 | 0;
+ if ((i9 | 0) >= (HEAP32[i5 >> 2] | 0)) {
+  STACKTOP = i3;
+  return;
+ }
+ i6 = i6 + 12 | 0;
+ i4 = i4 + 9 | 0;
+ do {
+  i10 = HEAP32[i6 >> 2] | 0;
+  i8 = i10 + (i9 << 4) + 12 | 0;
+  i11 = HEAP8[i7] | 0;
+  i12 = i11 & 255;
+  if ((HEAPU8[i8] | 0) > (i11 & 255)) {
+   if ((HEAP8[i4] | 0) != 0) {
+    _luaK_patchclose(i1, HEAP32[i10 + (i9 << 4) + 4 >> 2] | 0, i12);
+    i11 = HEAP8[i7] | 0;
+   }
+   HEAP8[i8] = i11;
+  }
+  i9 = ((_findlabel(HEAP32[i2 >> 2] | 0, i9) | 0) == 0) + i9 | 0;
+ } while ((i9 | 0) < (HEAP32[i5 >> 2] | 0));
+ STACKTOP = i3;
+ return;
+}
+function _getobjname(i3, i7, i9, i2) {
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ i9 = i9 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ i4 = i3 + 12 | 0;
+ L1 : while (1) {
+  i13 = _luaF_getlocalname(i3, i9 + 1 | 0, i7) | 0;
+  HEAP32[i2 >> 2] = i13;
+  if ((i13 | 0) != 0) {
+   i2 = 2040;
+   i4 = 42;
+   break;
+  }
+  if ((i7 | 0) <= 0) {
+   i2 = 0;
+   i4 = 42;
+   break;
+  }
+  i6 = HEAP32[i4 >> 2] | 0;
+  i8 = 0;
+  i5 = -1;
+  do {
+   i12 = HEAP32[i6 + (i8 << 2) >> 2] | 0;
+   i13 = i12 & 63;
+   i11 = i12 >>> 6 & 255;
+   switch (i13 | 0) {
+   case 27:
+    {
+     i10 = i8;
+     i5 = (i11 | 0) == (i9 | 0) ? i8 : i5;
+     break;
+    }
+   case 30:
+   case 29:
+    {
+     i10 = i8;
+     i5 = (i11 | 0) > (i9 | 0) ? i5 : i8;
+     break;
+    }
+   case 23:
+    {
+     i10 = (i12 >>> 14) + -131071 | 0;
+     i13 = i8 + 1 + i10 | 0;
+     i10 = ((i8 | 0) >= (i13 | 0) | (i13 | 0) > (i7 | 0) ? 0 : i10) + i8 | 0;
+     break;
+    }
+   case 4:
+    {
+     if ((i11 | 0) > (i9 | 0)) {
+      i10 = i8;
+     } else {
+      i10 = i8;
+      i5 = (i11 + (i12 >>> 23) | 0) < (i9 | 0) ? i5 : i8;
+     }
+     break;
+    }
+   case 34:
+    {
+     i10 = i8;
+     i5 = (i11 + 2 | 0) > (i9 | 0) ? i5 : i8;
+     break;
+    }
+   default:
+    {
+     i10 = i8;
+     i5 = (HEAP8[5584 + i13 | 0] & 64) != 0 & (i11 | 0) == (i9 | 0) ? i8 : i5;
+    }
+   }
+   i8 = i10 + 1 | 0;
+  } while ((i8 | 0) < (i7 | 0));
+  if ((i5 | 0) == -1) {
+   i2 = 0;
+   i4 = 42;
+   break;
+  }
+  i7 = HEAP32[i6 + (i5 << 2) >> 2] | 0;
+  i9 = i7 & 63;
+  switch (i9 | 0) {
+  case 0:
+   {
+    break;
+   }
+  case 7:
+  case 6:
+   {
+    i4 = 17;
+    break L1;
+   }
+  case 5:
+   {
+    i4 = 29;
+    break L1;
+   }
+  case 1:
+   {
+    i4 = 32;
+    break L1;
+   }
+  case 2:
+   {
+    i4 = 33;
+    break L1;
+   }
+  case 12:
+   {
+    i4 = 36;
+    break L1;
+   }
+  default:
+   {
+    i2 = 0;
+    i4 = 42;
+    break L1;
+   }
+  }
+  i9 = i7 >>> 23;
+  if (i9 >>> 0 < (i7 >>> 6 & 255) >>> 0) {
+   i7 = i5;
+  } else {
+   i2 = 0;
+   i4 = 42;
+   break;
+  }
+ }
+ if ((i4 | 0) == 17) {
+  i6 = i7 >>> 14;
+  i8 = i6 & 511;
+  i7 = i7 >>> 23;
+  if ((i9 | 0) != 7) {
+   i7 = HEAP32[(HEAP32[i3 + 28 >> 2] | 0) + (i7 << 3) >> 2] | 0;
+   if ((i7 | 0) == 0) {
+    i7 = 2104;
+   } else {
+    i7 = i7 + 16 | 0;
+   }
+  } else {
+   i7 = _luaF_getlocalname(i3, i7 + 1 | 0, i5) | 0;
+  }
+  if ((i6 & 256 | 0) == 0) {
+   i3 = _getobjname(i3, i5, i8, i2) | 0;
+   if (!((i3 | 0) != 0 ? (HEAP8[i3] | 0) == 99 : 0)) {
+    i4 = 26;
+   }
+  } else {
+   i5 = i6 & 255;
+   i3 = HEAP32[i3 + 8 >> 2] | 0;
+   if ((HEAP32[i3 + (i5 << 4) + 8 >> 2] & 15 | 0) == 4) {
+    HEAP32[i2 >> 2] = (HEAP32[i3 + (i5 << 4) >> 2] | 0) + 16;
+   } else {
+    i4 = 26;
+   }
+  }
+  if ((i4 | 0) == 26) {
+   HEAP32[i2 >> 2] = 2104;
+  }
+  if ((i7 | 0) == 0) {
+   i13 = 2064;
+   STACKTOP = i1;
+   return i13 | 0;
+  }
+  i13 = (_strcmp(i7, 2048) | 0) == 0;
+  i13 = i13 ? 2056 : 2064;
+  STACKTOP = i1;
+  return i13 | 0;
+ } else if ((i4 | 0) == 29) {
+  i3 = HEAP32[(HEAP32[i3 + 28 >> 2] | 0) + (i7 >>> 23 << 3) >> 2] | 0;
+  if ((i3 | 0) == 0) {
+   i3 = 2104;
+  } else {
+   i3 = i3 + 16 | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  i13 = 2072;
+  STACKTOP = i1;
+  return i13 | 0;
+ } else if ((i4 | 0) == 32) {
+  i5 = i7 >>> 14;
+ } else if ((i4 | 0) == 33) {
+  i5 = (HEAP32[i6 + (i5 + 1 << 2) >> 2] | 0) >>> 6;
+ } else if ((i4 | 0) == 36) {
+  i4 = i7 >>> 14;
+  if ((i4 & 256 | 0) == 0) {
+   i3 = _getobjname(i3, i5, i4 & 511, i2) | 0;
+   if ((i3 | 0) != 0 ? (HEAP8[i3] | 0) == 99 : 0) {
+    i13 = 2096;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+  } else {
+   i4 = i4 & 255;
+   i3 = HEAP32[i3 + 8 >> 2] | 0;
+   if ((HEAP32[i3 + (i4 << 4) + 8 >> 2] & 15 | 0) == 4) {
+    HEAP32[i2 >> 2] = (HEAP32[i3 + (i4 << 4) >> 2] | 0) + 16;
+    i13 = 2096;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+  }
+  HEAP32[i2 >> 2] = 2104;
+  i13 = 2096;
+  STACKTOP = i1;
+  return i13 | 0;
+ } else if ((i4 | 0) == 42) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ i3 = HEAP32[i3 + 8 >> 2] | 0;
+ if ((HEAP32[i3 + (i5 << 4) + 8 >> 2] & 15 | 0) != 4) {
+  i13 = 0;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ HEAP32[i2 >> 2] = (HEAP32[i3 + (i5 << 4) >> 2] | 0) + 16;
+ i13 = 2080;
+ STACKTOP = i1;
+ return i13 | 0;
+}
+function _assignment(i2, i16, i5) {
+ i2 = i2 | 0;
+ i16 = i16 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 80 | 0;
+ i6 = i3 + 56 | 0;
+ i1 = i3 + 32 | 0;
+ i8 = i3;
+ i4 = i16 + 8 | 0;
+ if (!(((HEAP32[i4 >> 2] | 0) + -7 | 0) >>> 0 < 3)) {
+  _luaX_syntaxerror(i2, 6344);
+ }
+ i13 = i2 + 16 | 0;
+ i14 = HEAP32[i13 >> 2] | 0;
+ do {
+  if ((i14 | 0) == 44) {
+   _luaX_next(i2);
+   HEAP32[i8 >> 2] = i16;
+   i14 = i8 + 8 | 0;
+   _suffixedexp(i2, i14);
+   i15 = i2 + 48 | 0;
+   if ((HEAP32[i14 >> 2] | 0) != 9 ? (i10 = HEAP32[i15 >> 2] | 0, i11 = HEAP8[i10 + 48 | 0] | 0, i9 = i11 & 255, (i16 | 0) != 0) : 0) {
+    i13 = i8 + 16 | 0;
+    i12 = i11 & 255;
+    i18 = 0;
+    do {
+     if ((HEAP32[i16 + 8 >> 2] | 0) == 9) {
+      i17 = i16 + 16 | 0;
+      i19 = i17 + 3 | 0;
+      i20 = HEAPU8[i19] | 0;
+      i21 = HEAP32[i14 >> 2] | 0;
+      if ((i20 | 0) == (i21 | 0)) {
+       i21 = i17 + 2 | 0;
+       if ((HEAPU8[i21] | 0) == (HEAP32[i13 >> 2] | 0)) {
+        HEAP8[i19] = 7;
+        HEAP8[i21] = i11;
+        i20 = HEAP32[i14 >> 2] | 0;
+        i18 = 1;
+       }
+      } else {
+       i20 = i21;
+      }
+      if ((i20 | 0) == 7 ? (HEAP16[i17 >> 1] | 0) == (HEAP32[i13 >> 2] | 0) : 0) {
+       HEAP16[i17 >> 1] = i12;
+       i18 = 1;
+      }
+     }
+     i16 = HEAP32[i16 >> 2] | 0;
+    } while ((i16 | 0) != 0);
+    if ((i18 | 0) != 0) {
+     _luaK_codeABC(i10, (HEAP32[i14 >> 2] | 0) == 7 ? 0 : 5, i9, HEAP32[i13 >> 2] | 0, 0) | 0;
+     _luaK_reserveregs(i10, 1);
+    }
+   }
+   i9 = HEAP32[i15 >> 2] | 0;
+   if (((HEAPU16[(HEAP32[i2 + 52 >> 2] | 0) + 38 >> 1] | 0) + i5 | 0) <= 200) {
+    _assignment(i2, i8, i5 + 1 | 0);
+    i7 = i1;
+    break;
+   }
+   i8 = i9 + 12 | 0;
+   i5 = HEAP32[(HEAP32[i8 >> 2] | 0) + 52 >> 2] | 0;
+   i9 = HEAP32[(HEAP32[i9 >> 2] | 0) + 64 >> 2] | 0;
+   if ((i9 | 0) == 0) {
+    i20 = 6552;
+    HEAP32[i6 >> 2] = 6360;
+    i21 = i6 + 4 | 0;
+    HEAP32[i21 >> 2] = 200;
+    i21 = i6 + 8 | 0;
+    HEAP32[i21 >> 2] = i20;
+    i21 = _luaO_pushfstring(i5, 6592, i6) | 0;
+    i20 = HEAP32[i8 >> 2] | 0;
+    _luaX_syntaxerror(i20, i21);
+   }
+   HEAP32[i6 >> 2] = i9;
+   i20 = _luaO_pushfstring(i5, 6568, i6) | 0;
+   HEAP32[i6 >> 2] = 6360;
+   i21 = i6 + 4 | 0;
+   HEAP32[i21 >> 2] = 200;
+   i21 = i6 + 8 | 0;
+   HEAP32[i21 >> 2] = i20;
+   i21 = _luaO_pushfstring(i5, 6592, i6) | 0;
+   i20 = HEAP32[i8 >> 2] | 0;
+   _luaX_syntaxerror(i20, i21);
+  } else if ((i14 | 0) == 61) {
+   _luaX_next(i2);
+   _subexpr(i2, i1, 0) | 0;
+   i6 = i2 + 48 | 0;
+   if ((HEAP32[i13 >> 2] | 0) == 44) {
+    i9 = 1;
+    do {
+     _luaX_next(i2);
+     _luaK_exp2nextreg(HEAP32[i6 >> 2] | 0, i1);
+     _subexpr(i2, i1, 0) | 0;
+     i9 = i9 + 1 | 0;
+    } while ((HEAP32[i13 >> 2] | 0) == 44);
+   } else {
+    i9 = 1;
+   }
+   i8 = HEAP32[i6 >> 2] | 0;
+   if ((i9 | 0) == (i5 | 0)) {
+    _luaK_setoneret(i8, i1);
+    _luaK_storevar(HEAP32[i6 >> 2] | 0, i4, i1);
+    STACKTOP = i3;
+    return;
+   }
+   i7 = i5 - i9 | 0;
+   i10 = HEAP32[i1 >> 2] | 0;
+   if ((i10 | 0) == 13 | (i10 | 0) == 12) {
+    i10 = i7 + 1 | 0;
+    i10 = (i10 | 0) < 0 ? 0 : i10;
+    _luaK_setreturns(i8, i1, i10);
+    if ((i10 | 0) > 1) {
+     _luaK_reserveregs(i8, i10 + -1 | 0);
+    }
+   } else if ((i10 | 0) == 0) {
+    i12 = 30;
+   } else {
+    _luaK_exp2nextreg(i8, i1);
+    i12 = 30;
+   }
+   if ((i12 | 0) == 30 ? (i7 | 0) > 0 : 0) {
+    i21 = HEAPU8[i8 + 48 | 0] | 0;
+    _luaK_reserveregs(i8, i7);
+    _luaK_nil(i8, i21, i7);
+   }
+   if ((i9 | 0) > (i5 | 0)) {
+    i21 = (HEAP32[i6 >> 2] | 0) + 48 | 0;
+    HEAP8[i21] = i7 + (HEAPU8[i21] | 0);
+    i7 = i1;
+   } else {
+    i7 = i1;
+   }
+  } else {
+   _error_expected(i2, 61);
+  }
+ } while (0);
+ i21 = HEAP32[i2 + 48 >> 2] | 0;
+ i20 = (HEAPU8[i21 + 48 | 0] | 0) + -1 | 0;
+ HEAP32[i1 + 16 >> 2] = -1;
+ HEAP32[i1 + 20 >> 2] = -1;
+ HEAP32[i7 >> 2] = 6;
+ HEAP32[i1 + 8 >> 2] = i20;
+ _luaK_storevar(i21, i4, i1);
+ STACKTOP = i3;
+ return;
+}
+function _str_find_aux(i3, i7) {
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 288 | 0;
+ i9 = i1 + 284 | 0;
+ i5 = i1 + 280 | 0;
+ i4 = i1;
+ i2 = _luaL_checklstring(i3, 1, i9) | 0;
+ i8 = _luaL_checklstring(i3, 2, i5) | 0;
+ i12 = _luaL_optinteger(i3, 3, 1) | 0;
+ i10 = HEAP32[i9 >> 2] | 0;
+ if (!((i12 | 0) > -1)) {
+  if (i10 >>> 0 < (0 - i12 | 0) >>> 0) {
+   i12 = 1;
+  } else {
+   i12 = i12 + 1 + i10 | 0;
+   i6 = 4;
+  }
+ } else {
+  i6 = 4;
+ }
+ if ((i6 | 0) == 4) {
+  if ((i12 | 0) != 0) {
+   if (i12 >>> 0 > (i10 + 1 | 0) >>> 0) {
+    _lua_pushnil(i3);
+    i13 = 1;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+  } else {
+   i12 = 1;
+  }
+ }
+ i7 = (i7 | 0) != 0;
+ L10 : do {
+  if (i7) {
+   i13 = (_lua_toboolean(i3, 4) | 0) == 0;
+   i10 = HEAP32[i5 >> 2] | 0;
+   if (i13) {
+    i11 = 0;
+    do {
+     i13 = i8 + i11 | 0;
+     if ((_strpbrk(i13, 7512) | 0) != 0) {
+      i6 = 20;
+      break L10;
+     }
+     i11 = i11 + 1 + (_strlen(i13 | 0) | 0) | 0;
+    } while (!(i11 >>> 0 > i10 >>> 0));
+   }
+   i11 = i2 + (i12 + -1) | 0;
+   i9 = (HEAP32[i9 >> 2] | 0) - i12 + 1 | 0;
+   L17 : do {
+    if ((i10 | 0) == 0) {
+     if ((i11 | 0) == 0) {
+      break L10;
+     }
+    } else {
+     if (i10 >>> 0 > i9 >>> 0) {
+      break L10;
+     }
+     i4 = i10 + -1 | 0;
+     if ((i4 | 0) == (i9 | 0)) {
+      break L10;
+     }
+     i7 = HEAP8[i8] | 0;
+     i8 = i8 + 1 | 0;
+     i9 = i9 - i4 | 0;
+     i12 = i11;
+     while (1) {
+      i11 = _memchr(i12, i7, i9) | 0;
+      if ((i11 | 0) == 0) {
+       break L10;
+      }
+      i10 = i11 + 1 | 0;
+      if ((_memcmp(i10, i8, i4) | 0) == 0) {
+       break L17;
+      }
+      i11 = i10;
+      i9 = i12 + i9 | 0;
+      if ((i9 | 0) == (i11 | 0)) {
+       break L10;
+      } else {
+       i9 = i9 - i11 | 0;
+       i12 = i10;
+      }
+     }
+    }
+   } while (0);
+   i13 = i11 - i2 | 0;
+   _lua_pushinteger(i3, i13 + 1 | 0);
+   _lua_pushinteger(i3, i13 + (HEAP32[i5 >> 2] | 0) | 0);
+   i13 = 2;
+   STACKTOP = i1;
+   return i13 | 0;
+  } else {
+   i6 = 20;
+  }
+ } while (0);
+ L28 : do {
+  if ((i6 | 0) == 20) {
+   i6 = i2 + (i12 + -1) | 0;
+   i10 = (HEAP8[i8] | 0) == 94;
+   if (i10) {
+    i12 = (HEAP32[i5 >> 2] | 0) + -1 | 0;
+    HEAP32[i5 >> 2] = i12;
+    i8 = i8 + 1 | 0;
+   } else {
+    i12 = HEAP32[i5 >> 2] | 0;
+   }
+   i5 = i4 + 16 | 0;
+   HEAP32[i5 >> 2] = i3;
+   HEAP32[i4 >> 2] = 200;
+   HEAP32[i4 + 4 >> 2] = i2;
+   i11 = i4 + 8 | 0;
+   HEAP32[i11 >> 2] = i2 + (HEAP32[i9 >> 2] | 0);
+   HEAP32[i4 + 12 >> 2] = i8 + i12;
+   i9 = i4 + 20 | 0;
+   L34 : do {
+    if (i10) {
+     HEAP32[i9 >> 2] = 0;
+     i8 = _match(i4, i6, i8) | 0;
+     if ((i8 | 0) == 0) {
+      break L28;
+     }
+    } else {
+     while (1) {
+      HEAP32[i9 >> 2] = 0;
+      i10 = _match(i4, i6, i8) | 0;
+      if ((i10 | 0) != 0) {
+       i8 = i10;
+       break L34;
+      }
+      if (!(i6 >>> 0 < (HEAP32[i11 >> 2] | 0) >>> 0)) {
+       break L28;
+      }
+      i6 = i6 + 1 | 0;
+     }
+    }
+   } while (0);
+   if (i7) {
+    _lua_pushinteger(i3, 1 - i2 + i6 | 0);
+    _lua_pushinteger(i3, i8 - i2 | 0);
+    i2 = HEAP32[i9 >> 2] | 0;
+    _luaL_checkstack(HEAP32[i5 >> 2] | 0, i2, 7200);
+    if ((i2 | 0) > 0) {
+     i3 = 0;
+     do {
+      _push_onecapture(i4, i3, 0, 0);
+      i3 = i3 + 1 | 0;
+     } while ((i3 | 0) != (i2 | 0));
+    }
+    i13 = i2 + 2 | 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   } else {
+    i3 = HEAP32[i9 >> 2] | 0;
+    i2 = (i3 | 0) != 0 | (i6 | 0) == 0 ? i3 : 1;
+    _luaL_checkstack(HEAP32[i5 >> 2] | 0, i2, 7200);
+    if ((i2 | 0) > 0) {
+     i3 = 0;
+    } else {
+     i13 = i3;
+     STACKTOP = i1;
+     return i13 | 0;
+    }
+    do {
+     _push_onecapture(i4, i3, i6, i8);
+     i3 = i3 + 1 | 0;
+    } while ((i3 | 0) != (i2 | 0));
+    STACKTOP = i1;
+    return i2 | 0;
+   }
+  }
+ } while (0);
+ _lua_pushnil(i3);
+ i13 = 1;
+ STACKTOP = i1;
+ return i13 | 0;
+}
+function _luaO_pushvfstring(i2, i13, i10) {
+ i2 = i2 | 0;
+ i13 = i13 | 0;
+ i10 = i10 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i11 = 0, i12 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, d18 = 0.0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i7 = i3;
+ i9 = i3 + 32 | 0;
+ i8 = i3 + 8 | 0;
+ i14 = _strchr(i13, 37) | 0;
+ i6 = i2 + 24 | 0;
+ i4 = i2 + 8 | 0;
+ i15 = HEAP32[i4 >> 2] | 0;
+ i17 = (HEAP32[i6 >> 2] | 0) - i15 | 0;
+ L1 : do {
+  if ((i14 | 0) == 0) {
+   i5 = i13;
+   i11 = i17;
+   i12 = i15;
+   i1 = 0;
+  } else {
+   i16 = 0;
+   L3 : while (1) {
+    if ((i17 | 0) < 48) {
+     _luaD_growstack(i2, 2);
+     i15 = HEAP32[i4 >> 2] | 0;
+    }
+    HEAP32[i4 >> 2] = i15 + 16;
+    i13 = _luaS_newlstr(i2, i13, i14 - i13 | 0) | 0;
+    HEAP32[i15 >> 2] = i13;
+    HEAP32[i15 + 8 >> 2] = HEAPU8[i13 + 4 | 0] | 64;
+    i13 = HEAP8[i14 + 1 | 0] | 0;
+    switch (i13 | 0) {
+    case 115:
+     {
+      i17 = HEAP32[i10 >> 2] | 0;
+      i13 = HEAP32[i17 >> 2] | 0;
+      HEAP32[i10 >> 2] = i17 + 4;
+      i13 = (i13 | 0) == 0 ? 5480 : i13;
+      i15 = _strlen(i13 | 0) | 0;
+      i17 = HEAP32[i4 >> 2] | 0;
+      HEAP32[i4 >> 2] = i17 + 16;
+      i15 = _luaS_newlstr(i2, i13, i15) | 0;
+      HEAP32[i17 >> 2] = i15;
+      HEAP32[i17 + 8 >> 2] = HEAPU8[i15 + 4 | 0] | 64;
+      break;
+     }
+    case 100:
+     {
+      i17 = HEAP32[i4 >> 2] | 0;
+      HEAP32[i4 >> 2] = i17 + 16;
+      i13 = HEAP32[i10 >> 2] | 0;
+      i15 = HEAP32[i13 >> 2] | 0;
+      HEAP32[i10 >> 2] = i13 + 4;
+      HEAPF64[i17 >> 3] = +(i15 | 0);
+      HEAP32[i17 + 8 >> 2] = 3;
+      break;
+     }
+    case 37:
+     {
+      i17 = HEAP32[i4 >> 2] | 0;
+      HEAP32[i4 >> 2] = i17 + 16;
+      i15 = _luaS_newlstr(i2, 5496, 1) | 0;
+      HEAP32[i17 >> 2] = i15;
+      HEAP32[i17 + 8 >> 2] = HEAPU8[i15 + 4 | 0] | 64;
+      break;
+     }
+    case 99:
+     {
+      i15 = HEAP32[i10 >> 2] | 0;
+      i17 = HEAP32[i15 >> 2] | 0;
+      HEAP32[i10 >> 2] = i15 + 4;
+      HEAP8[i9] = i17;
+      i17 = HEAP32[i4 >> 2] | 0;
+      HEAP32[i4 >> 2] = i17 + 16;
+      i15 = _luaS_newlstr(i2, i9, 1) | 0;
+      HEAP32[i17 >> 2] = i15;
+      HEAP32[i17 + 8 >> 2] = HEAPU8[i15 + 4 | 0] | 64;
+      break;
+     }
+    case 102:
+     {
+      i17 = HEAP32[i4 >> 2] | 0;
+      HEAP32[i4 >> 2] = i17 + 16;
+      i15 = HEAP32[i10 >> 2] | 0;
+      d18 = +HEAPF64[i15 >> 3];
+      HEAP32[i10 >> 2] = i15 + 8;
+      HEAPF64[i17 >> 3] = d18;
+      HEAP32[i17 + 8 >> 2] = 3;
+      break;
+     }
+    case 112:
+     {
+      i17 = HEAP32[i10 >> 2] | 0;
+      i15 = HEAP32[i17 >> 2] | 0;
+      HEAP32[i10 >> 2] = i17 + 4;
+      HEAP32[i7 >> 2] = i15;
+      i15 = _sprintf(i8 | 0, 5488, i7 | 0) | 0;
+      i17 = HEAP32[i4 >> 2] | 0;
+      HEAP32[i4 >> 2] = i17 + 16;
+      i15 = _luaS_newlstr(i2, i8, i15) | 0;
+      HEAP32[i17 >> 2] = i15;
+      HEAP32[i17 + 8 >> 2] = HEAPU8[i15 + 4 | 0] | 64;
+      break;
+     }
+    default:
+     {
+      break L3;
+     }
+    }
+    i16 = i16 + 2 | 0;
+    i13 = i14 + 2 | 0;
+    i14 = _strchr(i13, 37) | 0;
+    i15 = HEAP32[i4 >> 2] | 0;
+    i17 = (HEAP32[i6 >> 2] | 0) - i15 | 0;
+    if ((i14 | 0) == 0) {
+     i5 = i13;
+     i11 = i17;
+     i12 = i15;
+     i1 = i16;
+     break L1;
+    }
+   }
+   HEAP32[i7 >> 2] = i13;
+   _luaG_runerror(i2, 5504, i7);
+  }
+ } while (0);
+ if ((i11 | 0) < 32) {
+  _luaD_growstack(i2, 1);
+  i12 = HEAP32[i4 >> 2] | 0;
+ }
+ i17 = _strlen(i5 | 0) | 0;
+ HEAP32[i4 >> 2] = i12 + 16;
+ i17 = _luaS_newlstr(i2, i5, i17) | 0;
+ HEAP32[i12 >> 2] = i17;
+ HEAP32[i12 + 8 >> 2] = HEAPU8[i17 + 4 | 0] | 64;
+ if ((i1 | 0) <= 0) {
+  i17 = HEAP32[i4 >> 2] | 0;
+  i17 = i17 + -16 | 0;
+  i17 = HEAP32[i17 >> 2] | 0;
+  i17 = i17 + 16 | 0;
+  STACKTOP = i3;
+  return i17 | 0;
+ }
+ _luaV_concat(i2, i1 | 1);
+ i17 = HEAP32[i4 >> 2] | 0;
+ i17 = i17 + -16 | 0;
+ i17 = HEAP32[i17 >> 2] | 0;
+ i17 = i17 + 16 | 0;
+ STACKTOP = i3;
+ return i17 | 0;
+}
+function _luaH_getn(i6) {
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, d11 = 0.0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ i3 = i6 + 28 | 0;
+ i12 = HEAP32[i3 >> 2] | 0;
+ if ((i12 | 0) != 0 ? (i4 = HEAP32[i6 + 12 >> 2] | 0, (HEAP32[i4 + (i12 + -1 << 4) + 8 >> 2] | 0) == 0) : 0) {
+  if (i12 >>> 0 > 1) {
+   i10 = 0;
+  } else {
+   i13 = 0;
+   STACKTOP = i1;
+   return i13 | 0;
+  }
+  do {
+   i2 = (i10 + i12 | 0) >>> 1;
+   i3 = (HEAP32[i4 + (i2 + -1 << 4) + 8 >> 2] | 0) == 0;
+   i12 = i3 ? i2 : i12;
+   i10 = i3 ? i10 : i2;
+  } while ((i12 - i10 | 0) >>> 0 > 1);
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ i4 = i6 + 16 | 0;
+ if ((HEAP32[i4 >> 2] | 0) == 8016) {
+  i13 = i12;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ i5 = i6 + 12 | 0;
+ i6 = i6 + 7 | 0;
+ i9 = i2 + 4 | 0;
+ i8 = i12 + 1 | 0;
+ i13 = i12;
+ i10 = i12;
+ while (1) {
+  i12 = i8 + -1 | 0;
+  L15 : do {
+   if (i12 >>> 0 < i13 >>> 0) {
+    i12 = (HEAP32[i5 >> 2] | 0) + (i12 << 4) | 0;
+   } else {
+    d11 = +(i8 | 0);
+    HEAPF64[i2 >> 3] = d11 + 1.0;
+    i13 = (HEAP32[i9 >> 2] | 0) + (HEAP32[i2 >> 2] | 0) | 0;
+    if ((i13 | 0) < 0) {
+     i12 = 0 - i13 | 0;
+     i13 = (i13 | 0) == (i12 | 0) ? 0 : i12;
+    }
+    i12 = (HEAP32[i4 >> 2] | 0) + (((i13 | 0) % ((1 << (HEAPU8[i6] | 0)) + -1 | 1 | 0) | 0) << 5) | 0;
+    while (1) {
+     if ((HEAP32[i12 + 24 >> 2] | 0) == 3 ? +HEAPF64[i12 + 16 >> 3] == d11 : 0) {
+      break;
+     }
+     i12 = HEAP32[i12 + 28 >> 2] | 0;
+     if ((i12 | 0) == 0) {
+      i12 = 5192;
+      break L15;
+     }
+    }
+   }
+  } while (0);
+  if ((HEAP32[i12 + 8 >> 2] | 0) == 0) {
+   break;
+  }
+  i10 = i8 << 1;
+  if (i10 >>> 0 > 2147483645) {
+   i7 = 21;
+   break;
+  }
+  i12 = i8;
+  i8 = i10;
+  i13 = HEAP32[i3 >> 2] | 0;
+  i10 = i12;
+ }
+ if ((i7 | 0) == 21) {
+  i8 = i2 + 4 | 0;
+  i7 = 1;
+  while (1) {
+   i10 = i7 + -1 | 0;
+   L34 : do {
+    if (i10 >>> 0 < (HEAP32[i3 >> 2] | 0) >>> 0) {
+     i9 = (HEAP32[i5 >> 2] | 0) + (i10 << 4) | 0;
+    } else {
+     d11 = +(i7 | 0);
+     HEAPF64[i2 >> 3] = d11 + 1.0;
+     i9 = (HEAP32[i8 >> 2] | 0) + (HEAP32[i2 >> 2] | 0) | 0;
+     if ((i9 | 0) < 0) {
+      i12 = 0 - i9 | 0;
+      i9 = (i9 | 0) == (i12 | 0) ? 0 : i12;
+     }
+     i9 = (HEAP32[i4 >> 2] | 0) + (((i9 | 0) % ((1 << (HEAPU8[i6] | 0)) + -1 | 1 | 0) | 0) << 5) | 0;
+     while (1) {
+      if ((HEAP32[i9 + 24 >> 2] | 0) == 3 ? +HEAPF64[i9 + 16 >> 3] == d11 : 0) {
+       break;
+      }
+      i9 = HEAP32[i9 + 28 >> 2] | 0;
+      if ((i9 | 0) == 0) {
+       i9 = 5192;
+       break L34;
+      }
+     }
+    }
+   } while (0);
+   if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+    break;
+   }
+   i7 = i7 + 1 | 0;
+  }
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ if (!((i8 - i10 | 0) >>> 0 > 1)) {
+  i13 = i10;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ i7 = i2 + 4 | 0;
+ do {
+  i9 = (i8 + i10 | 0) >>> 1;
+  i12 = i9 + -1 | 0;
+  L55 : do {
+   if (i12 >>> 0 < (HEAP32[i3 >> 2] | 0) >>> 0) {
+    i12 = (HEAP32[i5 >> 2] | 0) + (i12 << 4) | 0;
+   } else {
+    d11 = +(i9 | 0);
+    HEAPF64[i2 >> 3] = d11 + 1.0;
+    i13 = (HEAP32[i7 >> 2] | 0) + (HEAP32[i2 >> 2] | 0) | 0;
+    if ((i13 | 0) < 0) {
+     i12 = 0 - i13 | 0;
+     i13 = (i13 | 0) == (i12 | 0) ? 0 : i12;
+    }
+    i12 = (HEAP32[i4 >> 2] | 0) + (((i13 | 0) % ((1 << (HEAPU8[i6] | 0)) + -1 | 1 | 0) | 0) << 5) | 0;
+    while (1) {
+     if ((HEAP32[i12 + 24 >> 2] | 0) == 3 ? +HEAPF64[i12 + 16 >> 3] == d11 : 0) {
+      break;
+     }
+     i12 = HEAP32[i12 + 28 >> 2] | 0;
+     if ((i12 | 0) == 0) {
+      i12 = 5192;
+      break L55;
+     }
+    }
+   }
+  } while (0);
+  i12 = (HEAP32[i12 + 8 >> 2] | 0) == 0;
+  i8 = i12 ? i9 : i8;
+  i10 = i12 ? i10 : i9;
+ } while ((i8 - i10 | 0) >>> 0 > 1);
+ STACKTOP = i1;
+ return i10 | 0;
+}
+function _lua_resume(i4, i3, i7) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i1 = STACKTOP;
+ if ((i3 | 0) == 0) {
+  i5 = 1;
+ } else {
+  i5 = (HEAPU16[i3 + 38 >> 1] | 0) + 1 & 65535;
+ }
+ i3 = i4 + 38 | 0;
+ HEAP16[i3 >> 1] = i5;
+ i5 = i4 + 36 | 0;
+ HEAP16[i5 >> 1] = 0;
+ i6 = i4 + 8 | 0;
+ i13 = _luaD_rawrunprotected(i4, 4, (HEAP32[i6 >> 2] | 0) + (0 - i7 << 4) | 0) | 0;
+ if ((i13 | 0) == -1) {
+  i18 = 2;
+  HEAP16[i5 >> 1] = 1;
+  i17 = HEAP16[i3 >> 1] | 0;
+  i17 = i17 + -1 << 16 >> 16;
+  HEAP16[i3 >> 1] = i17;
+  STACKTOP = i1;
+  return i18 | 0;
+ }
+ if (!(i13 >>> 0 > 1)) {
+  i18 = i13;
+  HEAP16[i5 >> 1] = 1;
+  i17 = HEAP16[i3 >> 1] | 0;
+  i17 = i17 + -1 << 16 >> 16;
+  HEAP16[i3 >> 1] = i17;
+  STACKTOP = i1;
+  return i18 | 0;
+ }
+ i7 = i4 + 16 | 0;
+ i12 = i4 + 28 | 0;
+ i11 = i4 + 41 | 0;
+ i10 = i4 + 68 | 0;
+ i9 = i4 + 32 | 0;
+ i8 = i4 + 12 | 0;
+ L10 : while (1) {
+  i15 = HEAP32[i7 >> 2] | 0;
+  if ((i15 | 0) == 0) {
+   break;
+  }
+  while (1) {
+   i14 = i15 + 18 | 0;
+   if (!((HEAP8[i14] & 16) == 0)) {
+    break;
+   }
+   i15 = HEAP32[i15 + 8 >> 2] | 0;
+   if ((i15 | 0) == 0) {
+    break L10;
+   }
+  }
+  i16 = HEAP32[i12 >> 2] | 0;
+  i17 = HEAP32[i15 + 20 >> 2] | 0;
+  i18 = i16 + i17 | 0;
+  _luaF_close(i4, i18);
+  if ((i13 | 0) == 4) {
+   i19 = HEAP32[(HEAP32[i8 >> 2] | 0) + 180 >> 2] | 0;
+   HEAP32[i18 >> 2] = i19;
+   HEAP32[i16 + (i17 + 8) >> 2] = HEAPU8[i19 + 4 | 0] | 0 | 64;
+  } else if ((i13 | 0) == 6) {
+   i19 = _luaS_newlstr(i4, 2424, 23) | 0;
+   HEAP32[i18 >> 2] = i19;
+   HEAP32[i16 + (i17 + 8) >> 2] = HEAPU8[i19 + 4 | 0] | 0 | 64;
+  } else {
+   i19 = HEAP32[i6 >> 2] | 0;
+   i21 = i19 + -16 | 0;
+   i20 = HEAP32[i21 + 4 >> 2] | 0;
+   HEAP32[i18 >> 2] = HEAP32[i21 >> 2];
+   HEAP32[i18 + 4 >> 2] = i20;
+   HEAP32[i16 + (i17 + 8) >> 2] = HEAP32[i19 + -8 >> 2];
+  }
+  i17 = i16 + (i17 + 16) | 0;
+  HEAP32[i6 >> 2] = i17;
+  HEAP32[i7 >> 2] = i15;
+  HEAP8[i11] = HEAP8[i15 + 36 | 0] | 0;
+  HEAP16[i5 >> 1] = 0;
+  if ((i15 | 0) != 0) {
+   i16 = i15;
+   do {
+    i18 = HEAP32[i16 + 4 >> 2] | 0;
+    i17 = i17 >>> 0 < i18 >>> 0 ? i18 : i17;
+    i16 = HEAP32[i16 + 8 >> 2] | 0;
+   } while ((i16 | 0) != 0);
+  }
+  i16 = i17 - (HEAP32[i12 >> 2] | 0) | 0;
+  i17 = (i16 >> 4) + 1 | 0;
+  i17 = ((i17 | 0) / 8 | 0) + 10 + i17 | 0;
+  i17 = (i17 | 0) > 1e6 ? 1e6 : i17;
+  if ((i16 | 0) <= 15999984 ? (i17 | 0) < (HEAP32[i9 >> 2] | 0) : 0) {
+   _luaD_reallocstack(i4, i17);
+  }
+  HEAP32[i10 >> 2] = HEAP32[i15 + 32 >> 2];
+  HEAP8[i14] = HEAPU8[i14] | 0 | 32;
+  HEAP8[i15 + 37 | 0] = i13;
+  i13 = _luaD_rawrunprotected(i4, 5, 0) | 0;
+  if (!(i13 >>> 0 > 1)) {
+   i2 = 24;
+   break;
+  }
+ }
+ if ((i2 | 0) == 24) {
+  HEAP16[i5 >> 1] = 1;
+  i21 = HEAP16[i3 >> 1] | 0;
+  i21 = i21 + -1 << 16 >> 16;
+  HEAP16[i3 >> 1] = i21;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ HEAP8[i4 + 6 | 0] = i13;
+ i2 = HEAP32[i6 >> 2] | 0;
+ if ((i13 | 0) == 4) {
+  i21 = HEAP32[(HEAP32[i8 >> 2] | 0) + 180 >> 2] | 0;
+  HEAP32[i2 >> 2] = i21;
+  HEAP32[i2 + 8 >> 2] = HEAPU8[i21 + 4 | 0] | 0 | 64;
+ } else if ((i13 | 0) == 6) {
+  i21 = _luaS_newlstr(i4, 2424, 23) | 0;
+  HEAP32[i2 >> 2] = i21;
+  HEAP32[i2 + 8 >> 2] = HEAPU8[i21 + 4 | 0] | 0 | 64;
+ } else {
+  i19 = i2 + -16 | 0;
+  i20 = HEAP32[i19 + 4 >> 2] | 0;
+  i21 = i2;
+  HEAP32[i21 >> 2] = HEAP32[i19 >> 2];
+  HEAP32[i21 + 4 >> 2] = i20;
+  HEAP32[i2 + 8 >> 2] = HEAP32[i2 + -8 >> 2];
+ }
+ i21 = i2 + 16 | 0;
+ HEAP32[i6 >> 2] = i21;
+ HEAP32[(HEAP32[i7 >> 2] | 0) + 4 >> 2] = i21;
+ i21 = i13;
+ HEAP16[i5 >> 1] = 1;
+ i20 = HEAP16[i3 >> 1] | 0;
+ i20 = i20 + -1 << 16 >> 16;
+ HEAP16[i3 >> 1] = i20;
+ STACKTOP = i1;
+ return i21 | 0;
+}
+function _luaK_goiftrue(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i2 = STACKTOP;
+ _luaK_dischargevars(i1, i3);
+ i12 = HEAP32[i3 >> 2] | 0;
+ do {
+  if ((i12 | 0) == 10) {
+   i9 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+   i5 = i3 + 8 | 0;
+   i8 = HEAP32[i5 >> 2] | 0;
+   i7 = i9 + (i8 << 2) | 0;
+   if (!((i8 | 0) > 0 ? (i10 = i9 + (i8 + -1 << 2) | 0, i6 = HEAP32[i10 >> 2] | 0, (HEAP8[5584 + (i6 & 63) | 0] | 0) < 0) : 0)) {
+    i10 = i7;
+    i6 = HEAP32[i7 >> 2] | 0;
+   }
+   HEAP32[i10 >> 2] = ((i6 & 16320 | 0) == 0) << 6 | i6 & -16321;
+   i5 = HEAP32[i5 >> 2] | 0;
+   i8 = 18;
+  } else if (!((i12 | 0) == 2 | (i12 | 0) == 5 | (i12 | 0) == 4)) {
+   i5 = i3 + 8 | 0;
+   if ((i12 | 0) == 6) {
+    i8 = 14;
+   } else if ((i12 | 0) == 11 ? (i11 = HEAP32[(HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i5 >> 2] << 2) >> 2] | 0, (i11 & 63 | 0) == 20) : 0) {
+    i5 = i1 + 20 | 0;
+    HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + -1;
+    i5 = _condjump(i1, 27, i11 >>> 23, 0, 1) | 0;
+    i8 = 18;
+    break;
+   } else {
+    i8 = 9;
+   }
+   if ((i8 | 0) == 9) {
+    i12 = i1 + 48 | 0;
+    i10 = HEAP8[i12] | 0;
+    i11 = (i10 & 255) + 1 | 0;
+    i6 = (HEAP32[i1 >> 2] | 0) + 78 | 0;
+    do {
+     if (i11 >>> 0 > (HEAPU8[i6] | 0) >>> 0) {
+      if (i11 >>> 0 > 249) {
+       _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10536);
+      } else {
+       HEAP8[i6] = i11;
+       i9 = HEAP8[i12] | 0;
+       break;
+      }
+     } else {
+      i9 = i10;
+     }
+    } while (0);
+    i11 = (i9 & 255) + 1 | 0;
+    HEAP8[i12] = i11;
+    _discharge2reg(i1, i3, (i11 & 255) + -1 | 0);
+    if ((HEAP32[i3 >> 2] | 0) == 6) {
+     i8 = 14;
+    }
+   }
+   if (((i8 | 0) == 14 ? (i7 = HEAP32[i5 >> 2] | 0, (i7 & 256 | 0) == 0) : 0) ? (HEAPU8[i1 + 46 | 0] | 0) <= (i7 | 0) : 0) {
+    i12 = i1 + 48 | 0;
+    HEAP8[i12] = (HEAP8[i12] | 0) + -1 << 24 >> 24;
+   }
+   i5 = _condjump(i1, 28, 255, HEAP32[i5 >> 2] | 0, 0) | 0;
+   i8 = 18;
+  }
+ } while (0);
+ do {
+  if ((i8 | 0) == 18 ? (i4 = i3 + 20 | 0, !((i5 | 0) == -1)) : 0) {
+   i8 = HEAP32[i4 >> 2] | 0;
+   if ((i8 | 0) == -1) {
+    HEAP32[i4 >> 2] = i5;
+    break;
+   }
+   i4 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+   while (1) {
+    i7 = i4 + (i8 << 2) | 0;
+    i6 = HEAP32[i7 >> 2] | 0;
+    i9 = (i6 >>> 14) + -131071 | 0;
+    if ((i9 | 0) == -1) {
+     break;
+    }
+    i9 = i8 + 1 + i9 | 0;
+    if ((i9 | 0) == -1) {
+     break;
+    } else {
+     i8 = i9;
+    }
+   }
+   i4 = i5 + ~i8 | 0;
+   if ((((i4 | 0) > -1 ? i4 : 0 - i4 | 0) | 0) > 131071) {
+    _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+   } else {
+    HEAP32[i7 >> 2] = (i4 << 14) + 2147467264 | i6 & 16383;
+    break;
+   }
+  }
+ } while (0);
+ i3 = i3 + 16 | 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ HEAP32[i1 + 24 >> 2] = HEAP32[i1 + 20 >> 2];
+ i5 = i1 + 28 | 0;
+ if ((i4 | 0) == -1) {
+  HEAP32[i3 >> 2] = -1;
+  STACKTOP = i2;
+  return;
+ }
+ i8 = HEAP32[i5 >> 2] | 0;
+ if ((i8 | 0) == -1) {
+  HEAP32[i5 >> 2] = i4;
+  HEAP32[i3 >> 2] = -1;
+  STACKTOP = i2;
+  return;
+ }
+ i7 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+ while (1) {
+  i5 = i7 + (i8 << 2) | 0;
+  i6 = HEAP32[i5 >> 2] | 0;
+  i9 = (i6 >>> 14) + -131071 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  }
+  i9 = i8 + 1 + i9 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  } else {
+   i8 = i9;
+  }
+ }
+ i4 = i4 + ~i8 | 0;
+ if ((((i4 | 0) > -1 ? i4 : 0 - i4 | 0) | 0) > 131071) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+ }
+ HEAP32[i5 >> 2] = (i4 << 14) + 2147467264 | i6 & 16383;
+ HEAP32[i3 >> 2] = -1;
+ STACKTOP = i2;
+ return;
+}
+function _luaO_str2d(i1, i3, i5) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, d9 = 0.0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ if ((_strpbrk(i1, 5464) | 0) != 0) {
+  i13 = 0;
+  STACKTOP = i2;
+  return i13 | 0;
+ }
+ do {
+  if ((_strpbrk(i1, 5472) | 0) == 0) {
+   d9 = +_strtod(i1, i4);
+   i10 = HEAP32[i4 >> 2] | 0;
+  } else {
+   HEAP32[i4 >> 2] = i1;
+   i8 = i1;
+   while (1) {
+    i6 = HEAP8[i8] | 0;
+    i10 = i8 + 1 | 0;
+    if ((HEAP8[(i6 & 255) + 10913 | 0] & 8) == 0) {
+     break;
+    } else {
+     i8 = i10;
+    }
+   }
+   if (i6 << 24 >> 24 == 43) {
+    i6 = 0;
+    i8 = i10;
+   } else if (i6 << 24 >> 24 == 45) {
+    i6 = 1;
+    i8 = i10;
+   } else {
+    i6 = 0;
+   }
+   if ((HEAP8[i8] | 0) == 48 ? (i13 = HEAP8[i8 + 1 | 0] | 0, i13 << 24 >> 24 == 88 | i13 << 24 >> 24 == 120) : 0) {
+    i10 = i8 + 2 | 0;
+    i8 = HEAP8[i10] | 0;
+    i12 = i8 & 255;
+    i11 = HEAP8[i12 + 10913 | 0] | 0;
+    if ((i11 & 16) == 0) {
+     d9 = 0.0;
+     i11 = i8;
+     i8 = 0;
+    } else {
+     d9 = 0.0;
+     i8 = 0;
+     while (1) {
+      if ((i11 & 2) == 0) {
+       i11 = (i12 | 32) + -87 | 0;
+      } else {
+       i11 = i12 + -48 | 0;
+      }
+      d9 = d9 * 16.0 + +(i11 | 0);
+      i8 = i8 + 1 | 0;
+      i10 = i10 + 1 | 0;
+      i13 = HEAP8[i10] | 0;
+      i12 = i13 & 255;
+      i11 = HEAP8[i12 + 10913 | 0] | 0;
+      if ((i11 & 16) == 0) {
+       i11 = i13;
+       break;
+      }
+     }
+    }
+    if (i11 << 24 >> 24 == 46) {
+     i10 = i10 + 1 | 0;
+     i13 = HEAPU8[i10] | 0;
+     i11 = HEAP8[i13 + 10913 | 0] | 0;
+     if ((i11 & 16) == 0) {
+      i12 = 0;
+     } else {
+      i12 = 0;
+      do {
+       if ((i11 & 2) == 0) {
+        i11 = (i13 | 32) + -87 | 0;
+       } else {
+        i11 = i13 + -48 | 0;
+       }
+       d9 = d9 * 16.0 + +(i11 | 0);
+       i12 = i12 + 1 | 0;
+       i10 = i10 + 1 | 0;
+       i13 = HEAPU8[i10] | 0;
+       i11 = HEAP8[i13 + 10913 | 0] | 0;
+      } while (!((i11 & 16) == 0));
+     }
+    } else {
+     i12 = 0;
+    }
+    if ((i12 | i8 | 0) != 0) {
+     i8 = Math_imul(i12, -4) | 0;
+     HEAP32[i4 >> 2] = i10;
+     i13 = HEAP8[i10] | 0;
+     if (i13 << 24 >> 24 == 80 | i13 << 24 >> 24 == 112) {
+      i13 = i10 + 1 | 0;
+      i11 = HEAP8[i13] | 0;
+      if (i11 << 24 >> 24 == 45) {
+       i11 = 1;
+       i13 = i10 + 2 | 0;
+      } else if (i11 << 24 >> 24 == 43) {
+       i11 = 0;
+       i13 = i10 + 2 | 0;
+      } else {
+       i11 = 0;
+      }
+      i12 = HEAP8[i13] | 0;
+      if (!((HEAP8[(i12 & 255) + 10913 | 0] & 2) == 0)) {
+       i10 = i13;
+       i7 = 0;
+       do {
+        i10 = i10 + 1 | 0;
+        i7 = (i12 << 24 >> 24) + -48 + (i7 * 10 | 0) | 0;
+        i12 = HEAP8[i10] | 0;
+       } while (!((HEAP8[(i12 & 255) + 10913 | 0] & 2) == 0));
+       i8 = ((i11 | 0) == 0 ? i7 : 0 - i7 | 0) + i8 | 0;
+       i7 = 29;
+      }
+     } else {
+      i7 = 29;
+     }
+     if ((i7 | 0) == 29) {
+      HEAP32[i4 >> 2] = i10;
+     }
+     if ((i6 | 0) != 0) {
+      d9 = -d9;
+     }
+     d9 = +_ldexp(d9, i8);
+     break;
+    }
+   }
+   HEAPF64[i5 >> 3] = 0.0;
+   i13 = 0;
+   STACKTOP = i2;
+   return i13 | 0;
+  }
+ } while (0);
+ HEAPF64[i5 >> 3] = d9;
+ if ((i10 | 0) == (i1 | 0)) {
+  i13 = 0;
+  STACKTOP = i2;
+  return i13 | 0;
+ }
+ if (!((HEAP8[(HEAPU8[i10] | 0) + 10913 | 0] & 8) == 0)) {
+  do {
+   i10 = i10 + 1 | 0;
+  } while (!((HEAP8[(HEAPU8[i10] | 0) + 10913 | 0] & 8) == 0));
+  HEAP32[i4 >> 2] = i10;
+ }
+ i13 = (i10 | 0) == (i1 + i3 | 0) | 0;
+ STACKTOP = i2;
+ return i13 | 0;
+}
+function _luaV_equalobj_(i2, i4, i5) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ i3 = i4 + 8 | 0;
+ L1 : do {
+  switch (HEAP32[i3 >> 2] & 63 | 0) {
+  case 7:
+   {
+    i6 = HEAP32[i4 >> 2] | 0;
+    i7 = HEAP32[i5 >> 2] | 0;
+    if ((i6 | 0) == (i7 | 0)) {
+     i7 = 1;
+     STACKTOP = i1;
+     return i7 | 0;
+    }
+    if ((i2 | 0) == 0) {
+     i7 = 0;
+     STACKTOP = i1;
+     return i7 | 0;
+    } else {
+     i6 = _get_equalTM(i2, HEAP32[i6 + 8 >> 2] | 0, HEAP32[i7 + 8 >> 2] | 0) | 0;
+     break L1;
+    }
+   }
+  case 5:
+   {
+    i7 = HEAP32[i4 >> 2] | 0;
+    i6 = HEAP32[i5 >> 2] | 0;
+    if ((i7 | 0) == (i6 | 0)) {
+     i7 = 1;
+     STACKTOP = i1;
+     return i7 | 0;
+    }
+    if ((i2 | 0) == 0) {
+     i7 = 0;
+     STACKTOP = i1;
+     return i7 | 0;
+    } else {
+     i6 = _get_equalTM(i2, HEAP32[i7 + 8 >> 2] | 0, HEAP32[i6 + 8 >> 2] | 0) | 0;
+     break L1;
+    }
+   }
+  case 4:
+   {
+    i7 = (HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0) | 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  case 20:
+   {
+    i7 = _luaS_eqlngstr(HEAP32[i4 >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  case 3:
+   {
+    i7 = +HEAPF64[i4 >> 3] == +HEAPF64[i5 >> 3] | 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  case 1:
+   {
+    i7 = (HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0) | 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  case 22:
+   {
+    i7 = (HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0) | 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  case 2:
+   {
+    i7 = (HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0) | 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  case 0:
+   {
+    i7 = 1;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  default:
+   {
+    i7 = (HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0) | 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  }
+ } while (0);
+ if ((i6 | 0) == 0) {
+  i7 = 0;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ i7 = i2 + 8 | 0;
+ i10 = HEAP32[i7 >> 2] | 0;
+ i9 = i2 + 28 | 0;
+ i8 = i10 - (HEAP32[i9 >> 2] | 0) | 0;
+ HEAP32[i7 >> 2] = i10 + 16;
+ i13 = i6;
+ i12 = HEAP32[i13 + 4 >> 2] | 0;
+ i11 = i10;
+ HEAP32[i11 >> 2] = HEAP32[i13 >> 2];
+ HEAP32[i11 + 4 >> 2] = i12;
+ HEAP32[i10 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+ i10 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i10 + 16;
+ i11 = i4;
+ i4 = HEAP32[i11 + 4 >> 2] | 0;
+ i6 = i10;
+ HEAP32[i6 >> 2] = HEAP32[i11 >> 2];
+ HEAP32[i6 + 4 >> 2] = i4;
+ HEAP32[i10 + 8 >> 2] = HEAP32[i3 >> 2];
+ i3 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i3 + 16;
+ i10 = i5;
+ i6 = HEAP32[i10 + 4 >> 2] | 0;
+ i4 = i3;
+ HEAP32[i4 >> 2] = HEAP32[i10 >> 2];
+ HEAP32[i4 + 4 >> 2] = i6;
+ HEAP32[i3 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+ _luaD_call(i2, (HEAP32[i7 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i2 + 16 >> 2] | 0) + 18 | 0] & 1);
+ i2 = HEAP32[i9 >> 2] | 0;
+ i3 = HEAP32[i7 >> 2] | 0;
+ i4 = i3 + -16 | 0;
+ HEAP32[i7 >> 2] = i4;
+ i5 = HEAP32[i4 + 4 >> 2] | 0;
+ i6 = i2 + i8 | 0;
+ HEAP32[i6 >> 2] = HEAP32[i4 >> 2];
+ HEAP32[i6 + 4 >> 2] = i5;
+ HEAP32[i2 + (i8 + 8) >> 2] = HEAP32[i3 + -8 >> 2];
+ i2 = HEAP32[i7 >> 2] | 0;
+ i3 = HEAP32[i2 + 8 >> 2] | 0;
+ if ((i3 | 0) != 0) {
+  if ((i3 | 0) == 1) {
+   i2 = (HEAP32[i2 >> 2] | 0) != 0;
+  } else {
+   i2 = 1;
+  }
+ } else {
+  i2 = 0;
+ }
+ i13 = i2 & 1;
+ STACKTOP = i1;
+ return i13 | 0;
+}
+function _forbody(i1, i5, i6, i4, i9) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ i9 = i9 | 0;
+ var i2 = 0, i3 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i8 = i3 + 12 | 0;
+ i19 = i3;
+ i11 = i1 + 48 | 0;
+ i7 = HEAP32[i11 >> 2] | 0;
+ i18 = i7 + 46 | 0;
+ i22 = (HEAPU8[i18] | 0) + 3 | 0;
+ HEAP8[i18] = i22;
+ i21 = i7 + 20 | 0;
+ i17 = i7 + 12 | 0;
+ i2 = i7 + 40 | 0;
+ i20 = HEAP32[(HEAP32[i7 >> 2] | 0) + 24 >> 2] | 0;
+ i10 = HEAP32[HEAP32[(HEAP32[i17 >> 2] | 0) + 64 >> 2] >> 2] | 0;
+ HEAP32[i20 + ((HEAP16[i10 + ((i22 & 255) + -3 + (HEAP32[i2 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i21 >> 2];
+ HEAP32[i20 + ((HEAP16[i10 + ((HEAPU8[i18] | 0) + -2 + (HEAP32[i2 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i21 >> 2];
+ HEAP32[i20 + ((HEAP16[i10 + ((HEAPU8[i18] | 0) + -1 + (HEAP32[i2 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i21 >> 2];
+ i2 = i1 + 16 | 0;
+ if ((HEAP32[i2 >> 2] | 0) != 259) {
+  _error_expected(i1, 259);
+ }
+ _luaX_next(i1);
+ i10 = (i9 | 0) != 0;
+ if (i10) {
+  i9 = _luaK_codeABx(i7, 33, i5, 131070) | 0;
+ } else {
+  i9 = _luaK_jump(i7) | 0;
+ }
+ HEAP8[i19 + 10 | 0] = 0;
+ HEAP8[i19 + 8 | 0] = HEAP8[i18] | 0;
+ i17 = HEAP32[(HEAP32[i17 >> 2] | 0) + 64 >> 2] | 0;
+ HEAP16[i19 + 4 >> 1] = HEAP32[i17 + 28 >> 2];
+ HEAP16[i19 + 6 >> 1] = HEAP32[i17 + 16 >> 2];
+ HEAP8[i19 + 9 | 0] = 0;
+ i17 = i7 + 16 | 0;
+ HEAP32[i19 >> 2] = HEAP32[i17 >> 2];
+ HEAP32[i17 >> 2] = i19;
+ i19 = HEAP32[i11 >> 2] | 0;
+ i17 = i19 + 46 | 0;
+ i18 = (HEAPU8[i17] | 0) + i4 | 0;
+ HEAP8[i17] = i18;
+ if ((i4 | 0) != 0 ? (i13 = i19 + 20 | 0, i12 = i19 + 40 | 0, i14 = HEAP32[(HEAP32[i19 >> 2] | 0) + 24 >> 2] | 0, i15 = HEAP32[HEAP32[(HEAP32[i19 + 12 >> 2] | 0) + 64 >> 2] >> 2] | 0, HEAP32[i14 + ((HEAP16[i15 + ((i18 & 255) - i4 + (HEAP32[i12 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i13 >> 2], i16 = i4 + -1 | 0, (i16 | 0) != 0) : 0) {
+  do {
+   HEAP32[i14 + ((HEAP16[i15 + ((HEAPU8[i17] | 0) - i16 + (HEAP32[i12 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i13 >> 2];
+   i16 = i16 + -1 | 0;
+  } while ((i16 | 0) != 0);
+ }
+ _luaK_reserveregs(i7, i4);
+ i11 = HEAP32[i11 >> 2] | 0;
+ HEAP8[i8 + 10 | 0] = 0;
+ HEAP8[i8 + 8 | 0] = HEAP8[i11 + 46 | 0] | 0;
+ i22 = HEAP32[(HEAP32[i11 + 12 >> 2] | 0) + 64 >> 2] | 0;
+ HEAP16[i8 + 4 >> 1] = HEAP32[i22 + 28 >> 2];
+ HEAP16[i8 + 6 >> 1] = HEAP32[i22 + 16 >> 2];
+ HEAP8[i8 + 9 | 0] = 0;
+ i22 = i11 + 16 | 0;
+ HEAP32[i8 >> 2] = HEAP32[i22 >> 2];
+ HEAP32[i22 >> 2] = i8;
+ L13 : do {
+  i8 = HEAP32[i2 >> 2] | 0;
+  switch (i8 | 0) {
+  case 277:
+  case 286:
+  case 262:
+  case 261:
+  case 260:
+   {
+    break L13;
+   }
+  default:
+   {}
+  }
+  _statement(i1);
+ } while ((i8 | 0) != 274);
+ _leaveblock(i11);
+ _leaveblock(i7);
+ _luaK_patchtohere(i7, i9);
+ if (i10) {
+  i21 = _luaK_codeABx(i7, 32, i5, 131070) | 0;
+  i22 = i9 + 1 | 0;
+  _luaK_patchlist(i7, i21, i22);
+  _luaK_fixline(i7, i6);
+  STACKTOP = i3;
+  return;
+ } else {
+  _luaK_codeABC(i7, 34, i5, 0, i4) | 0;
+  _luaK_fixline(i7, i6);
+  i21 = _luaK_codeABx(i7, 35, i5 + 2 | 0, 131070) | 0;
+  i22 = i9 + 1 | 0;
+  _luaK_patchlist(i7, i21, i22);
+  _luaK_fixline(i7, i6);
+  STACKTOP = i3;
+  return;
+ }
+}
+function _dotty(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i6;
+ i4 = i6 + 4 | 0;
+ i2 = HEAP32[20] | 0;
+ HEAP32[20] = 0;
+ _lua_settop(i1, 0);
+ if ((_pushline(i1, 1) | 0) == 0) {
+  _lua_settop(i1, 0);
+  i10 = HEAP32[_stdout >> 2] | 0;
+  _fputc(10, i10 | 0) | 0;
+  _fflush(i10 | 0) | 0;
+  HEAP32[20] = i2;
+  STACKTOP = i6;
+  return;
+ }
+ i5 = HEAP32[_stderr >> 2] | 0;
+ L4 : while (1) {
+  i8 = _lua_tolstring(i1, 1, i4) | 0;
+  i8 = _luaL_loadbufferx(i1, i8, HEAP32[i4 >> 2] | 0, 256, 0) | 0;
+  L6 : do {
+   if ((i8 | 0) == 3) {
+    while (1) {
+     i8 = _lua_tolstring(i1, -1, i3) | 0;
+     i7 = HEAP32[i3 >> 2] | 0;
+     if (!(i7 >>> 0 > 4)) {
+      break;
+     }
+     if ((_strcmp(i8 + (i7 + -5) | 0, 264) | 0) != 0) {
+      break;
+     }
+     _lua_settop(i1, -2);
+     if ((_pushline(i1, 0) | 0) == 0) {
+      i7 = 23;
+      break L4;
+     }
+     _lua_pushlstring(i1, 184, 1) | 0;
+     _lua_insert(i1, -2);
+     _lua_concat(i1, 3);
+     i8 = _lua_tolstring(i1, 1, i4) | 0;
+     i8 = _luaL_loadbufferx(i1, i8, HEAP32[i4 >> 2] | 0, 256, 0) | 0;
+     if ((i8 | 0) != 3) {
+      i7 = 9;
+      break L6;
+     }
+    }
+    _lua_remove(i1, 1);
+    i8 = 3;
+    i7 = 10;
+   } else {
+    i7 = 9;
+   }
+  } while (0);
+  do {
+   if ((i7 | 0) == 9) {
+    _lua_remove(i1, 1);
+    if ((i8 | 0) == -1) {
+     i7 = 23;
+     break L4;
+    } else if ((i8 | 0) != 0) {
+     i7 = 10;
+     break;
+    }
+    i9 = _lua_gettop(i1) | 0;
+    _lua_pushcclosure(i1, 142, 0);
+    _lua_insert(i1, i9);
+    HEAP32[48] = i1;
+    _signal(2, 1) | 0;
+    i10 = _lua_pcallk(i1, 0, -1, i9, 0, 0) | 0;
+    _signal(2, 0) | 0;
+    _lua_remove(i1, i9);
+    if ((i10 | 0) == 0) {
+     i7 = 17;
+    } else {
+     i9 = 0;
+     i7 = 12;
+    }
+   }
+  } while (0);
+  if ((i7 | 0) == 10) {
+   i9 = (i8 | 0) == 0;
+   i7 = 12;
+  }
+  do {
+   if ((i7 | 0) == 12) {
+    i7 = 0;
+    if ((_lua_type(i1, -1) | 0) == 0) {
+     if (i9) {
+      i7 = 17;
+      break;
+     } else {
+      break;
+     }
+    }
+    i10 = _lua_tolstring(i1, -1, 0) | 0;
+    i8 = HEAP32[20] | 0;
+    if ((i8 | 0) != 0) {
+     HEAP32[i3 >> 2] = i8;
+     _fprintf(i5 | 0, 496, i3 | 0) | 0;
+     _fflush(i5 | 0) | 0;
+    }
+    HEAP32[i3 >> 2] = (i10 | 0) == 0 ? 48 : i10;
+    _fprintf(i5 | 0, 912, i3 | 0) | 0;
+    _fflush(i5 | 0) | 0;
+    _lua_settop(i1, -2);
+    _lua_gc(i1, 2, 0) | 0;
+    if (i9) {
+     i7 = 17;
+    }
+   }
+  } while (0);
+  if (((i7 | 0) == 17 ? (0, (_lua_gettop(i1) | 0) > 0) : 0) ? (_luaL_checkstack(i1, 20, 112), _lua_getglobal(i1, 144), _lua_insert(i1, 1), (_lua_pcallk(i1, (_lua_gettop(i1) | 0) + -1 | 0, 0, 0, 0, 0) | 0) != 0) : 0) {
+   i7 = HEAP32[20] | 0;
+   HEAP32[i3 >> 2] = _lua_tolstring(i1, -1, 0) | 0;
+   i8 = _lua_pushfstring(i1, 152, i3) | 0;
+   if ((i7 | 0) != 0) {
+    HEAP32[i3 >> 2] = i7;
+    _fprintf(i5 | 0, 496, i3 | 0) | 0;
+    _fflush(i5 | 0) | 0;
+   }
+   HEAP32[i3 >> 2] = i8;
+   _fprintf(i5 | 0, 912, i3 | 0) | 0;
+   _fflush(i5 | 0) | 0;
+  }
+  _lua_settop(i1, 0);
+  if ((_pushline(i1, 1) | 0) == 0) {
+   i7 = 23;
+   break;
+  }
+ }
+ if ((i7 | 0) == 23) {
+  _lua_settop(i1, 0);
+  i10 = HEAP32[_stdout >> 2] | 0;
+  _fputc(10, i10 | 0) | 0;
+  _fflush(i10 | 0) | 0;
+  HEAP32[20] = i2;
+  STACKTOP = i6;
+  return;
+ }
+}
+function _test_then_block(i5, i1) {
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i10 = i2 + 24 | 0;
+ i9 = i2;
+ i8 = i5 + 48 | 0;
+ i4 = HEAP32[i8 >> 2] | 0;
+ _luaX_next(i5);
+ _subexpr(i5, i9, 0) | 0;
+ i3 = i5 + 16 | 0;
+ if ((HEAP32[i3 >> 2] | 0) != 275) {
+  _error_expected(i5, 275);
+ }
+ _luaX_next(i5);
+ i14 = HEAP32[i3 >> 2] | 0;
+ do {
+  if ((i14 | 0) == 258 | (i14 | 0) == 266) {
+   _luaK_goiffalse(HEAP32[i8 >> 2] | 0, i9);
+   HEAP8[i10 + 10 | 0] = 0;
+   HEAP8[i10 + 8 | 0] = HEAP8[i4 + 46 | 0] | 0;
+   i11 = HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 64 >> 2] | 0;
+   HEAP16[i10 + 4 >> 1] = HEAP32[i11 + 28 >> 2];
+   HEAP16[i10 + 6 >> 1] = HEAP32[i11 + 16 >> 2];
+   HEAP8[i10 + 9 | 0] = 0;
+   i11 = i4 + 16 | 0;
+   HEAP32[i10 >> 2] = HEAP32[i11 >> 2];
+   HEAP32[i11 >> 2] = i10;
+   i11 = HEAP32[i9 + 16 >> 2] | 0;
+   i10 = HEAP32[i5 + 4 >> 2] | 0;
+   i14 = (HEAP32[i3 >> 2] | 0) == 266;
+   _luaX_next(i5);
+   do {
+    if (i14) {
+     if ((HEAP32[i3 >> 2] | 0) == 288) {
+      i7 = HEAP32[i5 + 24 >> 2] | 0;
+      _luaX_next(i5);
+      break;
+     } else {
+      _error_expected(i5, 288);
+     }
+    } else {
+     i7 = _luaS_new(HEAP32[i5 + 52 >> 2] | 0, 6304) | 0;
+    }
+   } while (0);
+   i14 = HEAP32[i5 + 64 >> 2] | 0;
+   i12 = i14 + 12 | 0;
+   i13 = i14 + 16 | 0;
+   i9 = HEAP32[i13 >> 2] | 0;
+   i14 = i14 + 20 | 0;
+   if ((i9 | 0) < (HEAP32[i14 >> 2] | 0)) {
+    i14 = HEAP32[i12 >> 2] | 0;
+   } else {
+    i14 = _luaM_growaux_(HEAP32[i5 + 52 >> 2] | 0, HEAP32[i12 >> 2] | 0, i14, 16, 32767, 6312) | 0;
+    HEAP32[i12 >> 2] = i14;
+   }
+   HEAP32[i14 + (i9 << 4) >> 2] = i7;
+   i14 = HEAP32[i12 >> 2] | 0;
+   HEAP32[i14 + (i9 << 4) + 8 >> 2] = i10;
+   HEAP8[i14 + (i9 << 4) + 12 | 0] = HEAP8[(HEAP32[i8 >> 2] | 0) + 46 | 0] | 0;
+   HEAP32[(HEAP32[i12 >> 2] | 0) + (i9 << 4) + 4 >> 2] = i11;
+   HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + 1;
+   _findlabel(i5, i9) | 0;
+   L18 : while (1) {
+    switch (HEAP32[i3 >> 2] | 0) {
+    case 286:
+    case 262:
+    case 261:
+    case 260:
+     {
+      break L18;
+     }
+    case 285:
+    case 59:
+     {
+      break;
+     }
+    default:
+     {
+      i6 = 16;
+      break L18;
+     }
+    }
+    _statement(i5);
+   }
+   if ((i6 | 0) == 16) {
+    i6 = _luaK_jump(i4) | 0;
+    break;
+   }
+   _leaveblock(i4);
+   STACKTOP = i2;
+   return;
+  } else {
+   _luaK_goiftrue(HEAP32[i8 >> 2] | 0, i9);
+   HEAP8[i10 + 10 | 0] = 0;
+   HEAP8[i10 + 8 | 0] = HEAP8[i4 + 46 | 0] | 0;
+   i6 = HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 64 >> 2] | 0;
+   HEAP16[i10 + 4 >> 1] = HEAP32[i6 + 28 >> 2];
+   HEAP16[i10 + 6 >> 1] = HEAP32[i6 + 16 >> 2];
+   HEAP8[i10 + 9 | 0] = 0;
+   i6 = i4 + 16 | 0;
+   HEAP32[i10 >> 2] = HEAP32[i6 >> 2];
+   HEAP32[i6 >> 2] = i10;
+   i6 = HEAP32[i9 + 20 >> 2] | 0;
+  }
+ } while (0);
+ L26 : do {
+  i7 = HEAP32[i3 >> 2] | 0;
+  switch (i7 | 0) {
+  case 277:
+  case 286:
+  case 262:
+  case 261:
+  case 260:
+   {
+    break L26;
+   }
+  default:
+   {}
+  }
+  _statement(i5);
+ } while ((i7 | 0) != 274);
+ _leaveblock(i4);
+ if (((HEAP32[i3 >> 2] | 0) + -260 | 0) >>> 0 < 2) {
+  _luaK_concat(i4, i1, _luaK_jump(i4) | 0);
+ }
+ _luaK_patchtohere(i4, i6);
+ STACKTOP = i2;
+ return;
+}
+function _luaL_gsub(i2, i13, i11, i10) {
+ i2 = i2 | 0;
+ i13 = i13 | 0;
+ i11 = i11 | 0;
+ i10 = i10 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i12 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i8 = i1;
+ i4 = i1 + 8 | 0;
+ i9 = _strlen(i11 | 0) | 0;
+ i6 = i4 + 12 | 0;
+ HEAP32[i6 >> 2] = i2;
+ i3 = i4 + 16 | 0;
+ HEAP32[i4 >> 2] = i3;
+ i5 = i4 + 8 | 0;
+ HEAP32[i5 >> 2] = 0;
+ i7 = i4 + 4 | 0;
+ HEAP32[i7 >> 2] = 1024;
+ i12 = _strstr(i13, i11) | 0;
+ if ((i12 | 0) == 0) {
+  i14 = 0;
+  i17 = 1024;
+  i16 = i2;
+ } else {
+  i14 = 0;
+  i17 = 1024;
+  i16 = i2;
+  do {
+   i15 = i12 - i13 | 0;
+   if ((i17 - i14 | 0) >>> 0 < i15 >>> 0) {
+    i17 = i17 << 1;
+    i17 = (i17 - i14 | 0) >>> 0 < i15 >>> 0 ? i14 + i15 | 0 : i17;
+    if (i17 >>> 0 < i14 >>> 0 | (i17 - i14 | 0) >>> 0 < i15 >>> 0) {
+     _luaL_error(i16, 1272, i8) | 0;
+    }
+    i14 = _lua_newuserdata(i16, i17) | 0;
+    _memcpy(i14 | 0, HEAP32[i4 >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0;
+    if ((HEAP32[i4 >> 2] | 0) != (i3 | 0)) {
+     _lua_remove(i16, -2);
+    }
+    HEAP32[i4 >> 2] = i14;
+    HEAP32[i7 >> 2] = i17;
+    i16 = i14;
+    i14 = HEAP32[i5 >> 2] | 0;
+   } else {
+    i16 = HEAP32[i4 >> 2] | 0;
+   }
+   _memcpy(i16 + i14 | 0, i13 | 0, i15 | 0) | 0;
+   i15 = (HEAP32[i5 >> 2] | 0) + i15 | 0;
+   HEAP32[i5 >> 2] = i15;
+   i13 = _strlen(i10 | 0) | 0;
+   i14 = HEAP32[i6 >> 2] | 0;
+   i16 = HEAP32[i7 >> 2] | 0;
+   if ((i16 - i15 | 0) >>> 0 < i13 >>> 0) {
+    i16 = i16 << 1;
+    i16 = (i16 - i15 | 0) >>> 0 < i13 >>> 0 ? i15 + i13 | 0 : i16;
+    if (i16 >>> 0 < i15 >>> 0 | (i16 - i15 | 0) >>> 0 < i13 >>> 0) {
+     _luaL_error(i14, 1272, i8) | 0;
+    }
+    i15 = _lua_newuserdata(i14, i16) | 0;
+    _memcpy(i15 | 0, HEAP32[i4 >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0;
+    if ((HEAP32[i4 >> 2] | 0) != (i3 | 0)) {
+     _lua_remove(i14, -2);
+    }
+    HEAP32[i4 >> 2] = i15;
+    HEAP32[i7 >> 2] = i16;
+    i14 = i15;
+    i15 = HEAP32[i5 >> 2] | 0;
+   } else {
+    i14 = HEAP32[i4 >> 2] | 0;
+   }
+   _memcpy(i14 + i15 | 0, i10 | 0, i13 | 0) | 0;
+   i14 = (HEAP32[i5 >> 2] | 0) + i13 | 0;
+   HEAP32[i5 >> 2] = i14;
+   i13 = i12 + i9 | 0;
+   i12 = _strstr(i13, i11) | 0;
+   i16 = HEAP32[i6 >> 2] | 0;
+   i17 = HEAP32[i7 >> 2] | 0;
+  } while ((i12 | 0) != 0);
+ }
+ i9 = _strlen(i13 | 0) | 0;
+ if ((i17 - i14 | 0) >>> 0 < i9 >>> 0) {
+  i10 = i17 << 1;
+  i10 = (i10 - i14 | 0) >>> 0 < i9 >>> 0 ? i14 + i9 | 0 : i10;
+  if (i10 >>> 0 < i14 >>> 0 | (i10 - i14 | 0) >>> 0 < i9 >>> 0) {
+   _luaL_error(i16, 1272, i8) | 0;
+  }
+  i8 = _lua_newuserdata(i16, i10) | 0;
+  _memcpy(i8 | 0, HEAP32[i4 >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0;
+  if ((HEAP32[i4 >> 2] | 0) != (i3 | 0)) {
+   _lua_remove(i16, -2);
+  }
+  HEAP32[i4 >> 2] = i8;
+  HEAP32[i7 >> 2] = i10;
+  i14 = HEAP32[i5 >> 2] | 0;
+ } else {
+  i8 = HEAP32[i4 >> 2] | 0;
+ }
+ _memcpy(i8 + i14 | 0, i13 | 0, i9 | 0) | 0;
+ i17 = (HEAP32[i5 >> 2] | 0) + i9 | 0;
+ HEAP32[i5 >> 2] = i17;
+ i5 = HEAP32[i6 >> 2] | 0;
+ _lua_pushlstring(i5, HEAP32[i4 >> 2] | 0, i17) | 0;
+ if ((HEAP32[i4 >> 2] | 0) == (i3 | 0)) {
+  i17 = _lua_tolstring(i2, -1, 0) | 0;
+  STACKTOP = i1;
+  return i17 | 0;
+ }
+ _lua_remove(i5, -2);
+ i17 = _lua_tolstring(i2, -1, 0) | 0;
+ STACKTOP = i1;
+ return i17 | 0;
+}
+function _luaK_goiffalse(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i2 = STACKTOP;
+ _luaK_dischargevars(i1, i3);
+ i9 = HEAP32[i3 >> 2] | 0;
+ do {
+  if ((i9 | 0) == 10) {
+   i4 = HEAP32[i3 + 8 >> 2] | 0;
+   i8 = 15;
+  } else if (!((i9 | 0) == 3 | (i9 | 0) == 1)) {
+   i4 = i3 + 8 | 0;
+   if ((i9 | 0) == 6) {
+    i8 = 11;
+   } else if ((i9 | 0) == 11 ? (i10 = HEAP32[(HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i4 >> 2] << 2) >> 2] | 0, (i10 & 63 | 0) == 20) : 0) {
+    i4 = i1 + 20 | 0;
+    HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + -1;
+    i4 = _condjump(i1, 27, i10 >>> 23, 0, 0) | 0;
+    i8 = 15;
+    break;
+   } else {
+    i8 = 6;
+   }
+   if ((i8 | 0) == 6) {
+    i9 = i1 + 48 | 0;
+    i11 = HEAP8[i9] | 0;
+    i10 = (i11 & 255) + 1 | 0;
+    i12 = (HEAP32[i1 >> 2] | 0) + 78 | 0;
+    do {
+     if (i10 >>> 0 > (HEAPU8[i12] | 0) >>> 0) {
+      if (i10 >>> 0 > 249) {
+       _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10536);
+      } else {
+       HEAP8[i12] = i10;
+       i7 = HEAP8[i9] | 0;
+       break;
+      }
+     } else {
+      i7 = i11;
+     }
+    } while (0);
+    i12 = (i7 & 255) + 1 | 0;
+    HEAP8[i9] = i12;
+    _discharge2reg(i1, i3, (i12 & 255) + -1 | 0);
+    if ((HEAP32[i3 >> 2] | 0) == 6) {
+     i8 = 11;
+    }
+   }
+   if (((i8 | 0) == 11 ? (i6 = HEAP32[i4 >> 2] | 0, (i6 & 256 | 0) == 0) : 0) ? (HEAPU8[i1 + 46 | 0] | 0 | 0) <= (i6 | 0) : 0) {
+    i12 = i1 + 48 | 0;
+    HEAP8[i12] = (HEAP8[i12] | 0) + -1 << 24 >> 24;
+   }
+   i4 = _condjump(i1, 28, 255, HEAP32[i4 >> 2] | 0, 1) | 0;
+   i8 = 15;
+  }
+ } while (0);
+ do {
+  if ((i8 | 0) == 15 ? (i5 = i3 + 16 | 0, !((i4 | 0) == -1)) : 0) {
+   i8 = HEAP32[i5 >> 2] | 0;
+   if ((i8 | 0) == -1) {
+    HEAP32[i5 >> 2] = i4;
+    break;
+   }
+   i5 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+   while (1) {
+    i7 = i5 + (i8 << 2) | 0;
+    i6 = HEAP32[i7 >> 2] | 0;
+    i9 = (i6 >>> 14) + -131071 | 0;
+    if ((i9 | 0) == -1) {
+     break;
+    }
+    i9 = i8 + 1 + i9 | 0;
+    if ((i9 | 0) == -1) {
+     break;
+    } else {
+     i8 = i9;
+    }
+   }
+   i4 = i4 + ~i8 | 0;
+   if ((((i4 | 0) > -1 ? i4 : 0 - i4 | 0) | 0) > 131071) {
+    _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+   } else {
+    HEAP32[i7 >> 2] = (i4 << 14) + 2147467264 | i6 & 16383;
+    break;
+   }
+  }
+ } while (0);
+ i3 = i3 + 20 | 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ HEAP32[i1 + 24 >> 2] = HEAP32[i1 + 20 >> 2];
+ i5 = i1 + 28 | 0;
+ if ((i4 | 0) == -1) {
+  HEAP32[i3 >> 2] = -1;
+  STACKTOP = i2;
+  return;
+ }
+ i8 = HEAP32[i5 >> 2] | 0;
+ if ((i8 | 0) == -1) {
+  HEAP32[i5 >> 2] = i4;
+  HEAP32[i3 >> 2] = -1;
+  STACKTOP = i2;
+  return;
+ }
+ i7 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+ while (1) {
+  i5 = i7 + (i8 << 2) | 0;
+  i6 = HEAP32[i5 >> 2] | 0;
+  i9 = (i6 >>> 14) + -131071 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  }
+  i9 = i8 + 1 + i9 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  } else {
+   i8 = i9;
+  }
+ }
+ i4 = i4 + ~i8 | 0;
+ if ((((i4 | 0) > -1 ? i4 : 0 - i4 | 0) | 0) > 131071) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+ }
+ HEAP32[i5 >> 2] = (i4 << 14) + 2147467264 | i6 & 16383;
+ HEAP32[i3 >> 2] = -1;
+ STACKTOP = i2;
+ return;
+}
+function _luaV_settable(i2, i11, i7, i9) {
+ i2 = i2 | 0;
+ i11 = i11 | 0;
+ i7 = i7 | 0;
+ i9 = i9 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i10 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i6;
+ i4 = i2 + 12 | 0;
+ i3 = i11;
+ i13 = HEAP32[i11 + 8 >> 2] | 0;
+ i12 = 0;
+ while (1) {
+  i11 = i3 + 8 | 0;
+  if ((i13 | 0) != 69) {
+   i14 = _luaT_gettmbyobj(i2, i3, 1) | 0;
+   i13 = HEAP32[i14 + 8 >> 2] | 0;
+   if ((i13 | 0) == 0) {
+    i1 = 16;
+    break;
+   }
+  } else {
+   i8 = HEAP32[i3 >> 2] | 0;
+   i13 = _luaH_get(i8, i7) | 0;
+   if ((HEAP32[i13 + 8 >> 2] | 0) != 0) {
+    i10 = i13;
+    break;
+   }
+   i14 = HEAP32[i8 + 8 >> 2] | 0;
+   if ((i14 | 0) == 0) {
+    i1 = 9;
+    break;
+   }
+   if (!((HEAP8[i14 + 6 | 0] & 2) == 0)) {
+    i1 = 9;
+    break;
+   }
+   i14 = _luaT_gettm(i14, 1, HEAP32[(HEAP32[i4 >> 2] | 0) + 188 >> 2] | 0) | 0;
+   if ((i14 | 0) == 0) {
+    i1 = 9;
+    break;
+   }
+   i13 = HEAP32[i14 + 8 >> 2] | 0;
+  }
+  i12 = i12 + 1 | 0;
+  if ((i13 & 15 | 0) == 6) {
+   i1 = 18;
+   break;
+  }
+  if ((i12 | 0) < 100) {
+   i3 = i14;
+  } else {
+   i1 = 19;
+   break;
+  }
+ }
+ if ((i1 | 0) == 9) {
+  if ((i13 | 0) == 5192) {
+   i10 = _luaH_newkey(i2, i8, i7) | 0;
+  } else {
+   i10 = i13;
+  }
+ } else if ((i1 | 0) == 16) {
+  _luaG_typeerror(i2, i3, 8944);
+ } else if ((i1 | 0) == 18) {
+  i13 = i2 + 8 | 0;
+  i8 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i13 >> 2] = i8 + 16;
+  i5 = i14;
+  i12 = HEAP32[i5 + 4 >> 2] | 0;
+  i10 = i8;
+  HEAP32[i10 >> 2] = HEAP32[i5 >> 2];
+  HEAP32[i10 + 4 >> 2] = i12;
+  HEAP32[i8 + 8 >> 2] = HEAP32[i14 + 8 >> 2];
+  i14 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i13 >> 2] = i14 + 16;
+  i8 = i3;
+  i10 = HEAP32[i8 + 4 >> 2] | 0;
+  i12 = i14;
+  HEAP32[i12 >> 2] = HEAP32[i8 >> 2];
+  HEAP32[i12 + 4 >> 2] = i10;
+  HEAP32[i14 + 8 >> 2] = HEAP32[i11 >> 2];
+  i14 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i13 >> 2] = i14 + 16;
+  i12 = i7;
+  i11 = HEAP32[i12 + 4 >> 2] | 0;
+  i10 = i14;
+  HEAP32[i10 >> 2] = HEAP32[i12 >> 2];
+  HEAP32[i10 + 4 >> 2] = i11;
+  HEAP32[i14 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+  i14 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i13 >> 2] = i14 + 16;
+  i10 = i9;
+  i11 = HEAP32[i10 + 4 >> 2] | 0;
+  i12 = i14;
+  HEAP32[i12 >> 2] = HEAP32[i10 >> 2];
+  HEAP32[i12 + 4 >> 2] = i11;
+  HEAP32[i14 + 8 >> 2] = HEAP32[i9 + 8 >> 2];
+  _luaD_call(i2, (HEAP32[i13 >> 2] | 0) + -64 | 0, 0, HEAP8[(HEAP32[i2 + 16 >> 2] | 0) + 18 | 0] & 1);
+  STACKTOP = i6;
+  return;
+ } else if ((i1 | 0) == 19) {
+  _luaG_runerror(i2, 8976, i5);
+ }
+ i12 = i9;
+ i13 = HEAP32[i12 + 4 >> 2] | 0;
+ i14 = i10;
+ HEAP32[i14 >> 2] = HEAP32[i12 >> 2];
+ HEAP32[i14 + 4 >> 2] = i13;
+ i14 = i9 + 8 | 0;
+ HEAP32[i10 + 8 >> 2] = HEAP32[i14 >> 2];
+ HEAP8[i8 + 6 | 0] = 0;
+ if ((HEAP32[i14 >> 2] & 64 | 0) == 0) {
+  STACKTOP = i6;
+  return;
+ }
+ if ((HEAP8[(HEAP32[i9 >> 2] | 0) + 5 | 0] & 3) == 0) {
+  STACKTOP = i6;
+  return;
+ }
+ if ((HEAP8[i8 + 5 | 0] & 4) == 0) {
+  STACKTOP = i6;
+  return;
+ }
+ _luaC_barrierback_(i2, i8);
+ STACKTOP = i6;
+ return;
+}
+function _luaK_code(i4, i5) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0;
+ i2 = STACKTOP;
+ i1 = HEAP32[i4 >> 2] | 0;
+ i7 = i4 + 28 | 0;
+ i15 = HEAP32[i7 >> 2] | 0;
+ i3 = i4 + 20 | 0;
+ i8 = HEAP32[i3 >> 2] | 0;
+ do {
+  if (!((i15 | 0) == -1)) {
+   i11 = HEAP32[i1 + 12 >> 2] | 0;
+   while (1) {
+    i12 = i11 + (i15 << 2) | 0;
+    i14 = HEAP32[i12 >> 2] | 0;
+    i13 = (i14 >>> 14) + -131071 | 0;
+    if ((i13 | 0) == -1) {
+     i13 = -1;
+    } else {
+     i13 = i15 + 1 + i13 | 0;
+    }
+    if ((i15 | 0) > 0 ? (i9 = i11 + (i15 + -1 << 2) | 0, i10 = HEAP32[i9 >> 2] | 0, (HEAP8[5584 + (i10 & 63) | 0] | 0) < 0) : 0) {
+     i17 = i9;
+     i16 = i10;
+    } else {
+     i17 = i12;
+     i16 = i14;
+    }
+    if ((i16 & 63 | 0) == 28) {
+     HEAP32[i17 >> 2] = i16 & 8372224 | i16 >>> 23 << 6 | 27;
+     i14 = i8 + ~i15 | 0;
+     if ((((i14 | 0) > -1 ? i14 : 0 - i14 | 0) | 0) > 131071) {
+      i8 = 10;
+      break;
+     }
+     i14 = HEAP32[i12 >> 2] & 16383 | (i14 << 14) + 2147467264;
+    } else {
+     i15 = i8 + ~i15 | 0;
+     if ((((i15 | 0) > -1 ? i15 : 0 - i15 | 0) | 0) > 131071) {
+      i8 = 13;
+      break;
+     }
+     i14 = (i15 << 14) + 2147467264 | i14 & 16383;
+    }
+    HEAP32[i12 >> 2] = i14;
+    if ((i13 | 0) == -1) {
+     i8 = 16;
+     break;
+    } else {
+     i15 = i13;
+    }
+   }
+   if ((i8 | 0) == 10) {
+    _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10624);
+   } else if ((i8 | 0) == 13) {
+    _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10624);
+   } else if ((i8 | 0) == 16) {
+    i6 = HEAP32[i3 >> 2] | 0;
+    break;
+   }
+  } else {
+   i6 = i8;
+  }
+ } while (0);
+ HEAP32[i7 >> 2] = -1;
+ i7 = i1 + 48 | 0;
+ if ((i6 | 0) < (HEAP32[i7 >> 2] | 0)) {
+  i7 = i1 + 12 | 0;
+ } else {
+  i6 = i1 + 12 | 0;
+  HEAP32[i6 >> 2] = _luaM_growaux_(HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 52 >> 2] | 0, HEAP32[i6 >> 2] | 0, i7, 4, 2147483645, 10616) | 0;
+  i7 = i6;
+  i6 = HEAP32[i3 >> 2] | 0;
+ }
+ HEAP32[(HEAP32[i7 >> 2] | 0) + (i6 << 2) >> 2] = i5;
+ i5 = HEAP32[i3 >> 2] | 0;
+ i6 = i1 + 52 | 0;
+ i4 = i4 + 12 | 0;
+ if ((i5 | 0) < (HEAP32[i6 >> 2] | 0)) {
+  i15 = i1 + 20 | 0;
+  i17 = i5;
+  i16 = HEAP32[i4 >> 2] | 0;
+  i16 = i16 + 8 | 0;
+  i16 = HEAP32[i16 >> 2] | 0;
+  i15 = HEAP32[i15 >> 2] | 0;
+  i17 = i15 + (i17 << 2) | 0;
+  HEAP32[i17 >> 2] = i16;
+  i17 = HEAP32[i3 >> 2] | 0;
+  i16 = i17 + 1 | 0;
+  HEAP32[i3 >> 2] = i16;
+  STACKTOP = i2;
+  return i17 | 0;
+ } else {
+  i15 = i1 + 20 | 0;
+  HEAP32[i15 >> 2] = _luaM_growaux_(HEAP32[(HEAP32[i4 >> 2] | 0) + 52 >> 2] | 0, HEAP32[i15 >> 2] | 0, i6, 4, 2147483645, 10616) | 0;
+  i17 = HEAP32[i3 >> 2] | 0;
+  i16 = HEAP32[i4 >> 2] | 0;
+  i16 = i16 + 8 | 0;
+  i16 = HEAP32[i16 >> 2] | 0;
+  i15 = HEAP32[i15 >> 2] | 0;
+  i17 = i15 + (i17 << 2) | 0;
+  HEAP32[i17 >> 2] = i16;
+  i17 = HEAP32[i3 >> 2] | 0;
+  i16 = i17 + 1 | 0;
+  HEAP32[i3 >> 2] = i16;
+  STACKTOP = i2;
+  return i17 | 0;
+ }
+ return 0;
+}
+function _luaH_next(i9, i5, i2) {
+ i9 = i9 | 0;
+ i5 = i5 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, d14 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i8 = i1 + 8 | 0;
+ i11 = i1;
+ i3 = i2 + 8 | 0;
+ i10 = HEAP32[i3 >> 2] | 0;
+ do {
+  if ((i10 | 0) != 0) {
+   if ((((i10 | 0) == 3 ? (d14 = +HEAPF64[i2 >> 3], HEAPF64[i11 >> 3] = d14 + 6755399441055744.0, i12 = HEAP32[i11 >> 2] | 0, +(i12 | 0) == d14) : 0) ? (i12 | 0) > 0 : 0) ? (i13 = HEAP32[i5 + 28 >> 2] | 0, (i12 | 0) <= (i13 | 0)) : 0) {
+    i6 = i13;
+    i7 = i12 + -1 | 0;
+    break;
+   }
+   i10 = _mainposition(i5, i2) | 0;
+   while (1) {
+    i4 = i10 + 16 | 0;
+    i11 = i10 + 24 | 0;
+    i12 = HEAP32[i11 >> 2] | 0;
+    if ((i12 | 0) == (HEAP32[i3 >> 2] | 0)) {
+     if ((_luaV_equalobj_(0, i4, i2) | 0) != 0) {
+      i4 = 15;
+      break;
+     }
+     i12 = HEAP32[i11 >> 2] | 0;
+    }
+    if (((i12 | 0) == 11 ? (HEAP32[i3 >> 2] & 64 | 0) != 0 : 0) ? (HEAP32[i4 >> 2] | 0) == (HEAP32[i2 >> 2] | 0) : 0) {
+     i4 = 15;
+     break;
+    }
+    i10 = HEAP32[i10 + 28 >> 2] | 0;
+    if ((i10 | 0) == 0) {
+     i4 = 18;
+     break;
+    }
+   }
+   if ((i4 | 0) == 15) {
+    i7 = HEAP32[i5 + 28 >> 2] | 0;
+    i6 = i7;
+    i7 = (i10 - (HEAP32[i5 + 16 >> 2] | 0) >> 5) + i7 | 0;
+    break;
+   } else if ((i4 | 0) == 18) {
+    _luaG_runerror(i9, 8064, i8);
+   }
+  } else {
+   i6 = HEAP32[i5 + 28 >> 2] | 0;
+   i7 = -1;
+  }
+ } while (0);
+ i8 = i5 + 12 | 0;
+ while (1) {
+  i9 = i7 + 1 | 0;
+  if ((i9 | 0) >= (i6 | 0)) {
+   break;
+  }
+  i11 = HEAP32[i8 >> 2] | 0;
+  i10 = i11 + (i9 << 4) + 8 | 0;
+  if ((HEAP32[i10 >> 2] | 0) == 0) {
+   i7 = i9;
+  } else {
+   i4 = 21;
+   break;
+  }
+ }
+ if ((i4 | 0) == 21) {
+  HEAPF64[i2 >> 3] = +(i7 + 2 | 0);
+  HEAP32[i3 >> 2] = 3;
+  i11 = i11 + (i9 << 4) | 0;
+  i12 = HEAP32[i11 + 4 >> 2] | 0;
+  i13 = i2 + 16 | 0;
+  HEAP32[i13 >> 2] = HEAP32[i11 >> 2];
+  HEAP32[i13 + 4 >> 2] = i12;
+  HEAP32[i2 + 24 >> 2] = HEAP32[i10 >> 2];
+  i13 = 1;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ i8 = i9 - i6 | 0;
+ i6 = 1 << (HEAPU8[i5 + 7 | 0] | 0);
+ if ((i8 | 0) >= (i6 | 0)) {
+  i13 = 0;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ i7 = i5 + 16 | 0;
+ i5 = HEAP32[i7 >> 2] | 0;
+ while (1) {
+  i9 = i8 + 1 | 0;
+  if ((HEAP32[i5 + (i8 << 5) + 8 >> 2] | 0) != 0) {
+   break;
+  }
+  if ((i9 | 0) < (i6 | 0)) {
+   i8 = i9;
+  } else {
+   i2 = 0;
+   i4 = 27;
+   break;
+  }
+ }
+ if ((i4 | 0) == 27) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ i11 = i5 + (i8 << 5) + 16 | 0;
+ i10 = HEAP32[i11 + 4 >> 2] | 0;
+ i13 = i2;
+ HEAP32[i13 >> 2] = HEAP32[i11 >> 2];
+ HEAP32[i13 + 4 >> 2] = i10;
+ HEAP32[i3 >> 2] = HEAP32[i5 + (i8 << 5) + 24 >> 2];
+ i13 = HEAP32[i7 >> 2] | 0;
+ i10 = i13 + (i8 << 5) | 0;
+ i11 = HEAP32[i10 + 4 >> 2] | 0;
+ i12 = i2 + 16 | 0;
+ HEAP32[i12 >> 2] = HEAP32[i10 >> 2];
+ HEAP32[i12 + 4 >> 2] = i11;
+ HEAP32[i2 + 24 >> 2] = HEAP32[i13 + (i8 << 5) + 8 >> 2];
+ i13 = 1;
+ STACKTOP = i1;
+ return i13 | 0;
+}
+function _g_read(i1, i3, i2) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i7 = i4 + 8 | 0;
+ i9 = i4;
+ i10 = _lua_gettop(i1) | 0;
+ _clearerr(i3 | 0);
+ L1 : do {
+  if ((i10 | 0) == 1) {
+   i11 = i2 + 1 | 0;
+   i12 = _read_line(i1, i3, 1) | 0;
+  } else {
+   _luaL_checkstack(i1, i10 + 19 | 0, 3256);
+   i6 = i7 + 8 | 0;
+   i5 = i7 + 8 | 0;
+   i10 = i10 + -2 | 0;
+   i11 = i2;
+   L4 : while (1) {
+    do {
+     if ((_lua_type(i1, i11) | 0) == 3) {
+      i12 = _lua_tointegerx(i1, i11, 0) | 0;
+      if ((i12 | 0) == 0) {
+       i12 = _fgetc(i3 | 0) | 0;
+       _ungetc(i12 | 0, i3 | 0) | 0;
+       _lua_pushlstring(i1, 0, 0) | 0;
+       i12 = (i12 | 0) != -1 | 0;
+       break;
+      } else {
+       _luaL_buffinit(i1, i7);
+       i12 = _fread(_luaL_prepbuffsize(i7, i12) | 0, 1, i12 | 0, i3 | 0) | 0;
+       HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i12;
+       _luaL_pushresult(i7);
+       i12 = (i12 | 0) != 0 | 0;
+       break;
+      }
+     } else {
+      i12 = _lua_tolstring(i1, i11, 0) | 0;
+      if (!((i12 | 0) != 0 ? (HEAP8[i12] | 0) == 42 : 0)) {
+       _luaL_argerror(i1, i11, 3280) | 0;
+      }
+      i12 = HEAP8[i12 + 1 | 0] | 0;
+      if ((i12 | 0) == 110) {
+       HEAP32[i7 >> 2] = i9;
+       if ((_fscanf(i3 | 0, 3312, i7 | 0) | 0) != 1) {
+        i8 = 14;
+        break L4;
+       }
+       _lua_pushnumber(i1, +HEAPF64[i9 >> 3]);
+       i12 = 1;
+       break;
+      } else if ((i12 | 0) == 108) {
+       i12 = _read_line(i1, i3, 1) | 0;
+       break;
+      } else if ((i12 | 0) == 76) {
+       i12 = _read_line(i1, i3, 0) | 0;
+       break;
+      } else if ((i12 | 0) == 97) {
+       _luaL_buffinit(i1, i7);
+       i12 = _fread(_luaL_prepbuffsize(i7, 1024) | 0, 1, 1024, i3 | 0) | 0;
+       HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + i12;
+       if (!(i12 >>> 0 < 1024)) {
+        i12 = 1024;
+        do {
+         i12 = i12 << (i12 >>> 0 < 1073741824);
+         i13 = _fread(_luaL_prepbuffsize(i7, i12) | 0, 1, i12 | 0, i3 | 0) | 0;
+         HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + i13;
+        } while (!(i13 >>> 0 < i12 >>> 0));
+       }
+       _luaL_pushresult(i7);
+       i12 = 1;
+       break;
+      } else {
+       break L4;
+      }
+     }
+    } while (0);
+    i11 = i11 + 1 | 0;
+    if ((i10 | 0) == 0 | (i12 | 0) == 0) {
+     break L1;
+    } else {
+     i10 = i10 + -1 | 0;
+    }
+   }
+   if ((i8 | 0) == 14) {
+    _lua_pushnil(i1);
+    i11 = i11 + 1 | 0;
+    i12 = 0;
+    break;
+   }
+   i13 = _luaL_argerror(i1, i11, 3296) | 0;
+   STACKTOP = i4;
+   return i13 | 0;
+  }
+ } while (0);
+ if ((_ferror(i3 | 0) | 0) != 0) {
+  i13 = _luaL_fileresult(i1, 0, 0) | 0;
+  STACKTOP = i4;
+  return i13 | 0;
+ }
+ if ((i12 | 0) == 0) {
+  _lua_settop(i1, -2);
+  _lua_pushnil(i1);
+ }
+ i13 = i11 - i2 | 0;
+ STACKTOP = i4;
+ return i13 | 0;
+}
+function _luaY_parser(i8, i12, i10, i11, i9, i13) {
+ i8 = i8 | 0;
+ i12 = i12 | 0;
+ i10 = i10 | 0;
+ i11 = i11 | 0;
+ i9 = i9 | 0;
+ i13 = i13 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i14 = 0, i15 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 176 | 0;
+ i5 = i2 + 156 | 0;
+ i7 = i2 + 80 | 0;
+ i4 = i2;
+ i6 = i2 + 104 | 0;
+ i3 = _luaF_newLclosure(i8, 1) | 0;
+ i15 = i8 + 8 | 0;
+ i14 = HEAP32[i15 >> 2] | 0;
+ HEAP32[i14 >> 2] = i3;
+ HEAP32[i14 + 8 >> 2] = 70;
+ i14 = (HEAP32[i15 >> 2] | 0) + 16 | 0;
+ HEAP32[i15 >> 2] = i14;
+ if (((HEAP32[i8 + 24 >> 2] | 0) - i14 | 0) < 16) {
+  _luaD_growstack(i8, 0);
+ }
+ i14 = _luaF_newproto(i8) | 0;
+ HEAP32[i3 + 12 >> 2] = i14;
+ HEAP32[i6 >> 2] = i14;
+ i9 = _luaS_new(i8, i9) | 0;
+ HEAP32[(HEAP32[i6 >> 2] | 0) + 36 >> 2] = i9;
+ HEAP32[i4 + 60 >> 2] = i10;
+ i9 = i4 + 64 | 0;
+ HEAP32[i9 >> 2] = i11;
+ HEAP32[i11 + 28 >> 2] = 0;
+ HEAP32[i11 + 16 >> 2] = 0;
+ HEAP32[i11 + 4 >> 2] = 0;
+ _luaX_setinput(i8, i4, i12, HEAP32[(HEAP32[i6 >> 2] | 0) + 36 >> 2] | 0, i13);
+ i10 = HEAP32[i4 + 52 >> 2] | 0;
+ i13 = i4 + 48 | 0;
+ HEAP32[i6 + 8 >> 2] = HEAP32[i13 >> 2];
+ i8 = i6 + 12 | 0;
+ HEAP32[i8 >> 2] = i4;
+ HEAP32[i13 >> 2] = i6;
+ HEAP32[i6 + 20 >> 2] = 0;
+ HEAP32[i6 + 24 >> 2] = 0;
+ HEAP32[i6 + 28 >> 2] = -1;
+ HEAP32[i6 + 32 >> 2] = 0;
+ HEAP32[i6 + 36 >> 2] = 0;
+ i13 = i6 + 44 | 0;
+ HEAP32[i13 + 0 >> 2] = 0;
+ HEAP8[i13 + 4 | 0] = 0;
+ HEAP32[i6 + 40 >> 2] = HEAP32[(HEAP32[i9 >> 2] | 0) + 4 >> 2];
+ i9 = i6 + 16 | 0;
+ HEAP32[i9 >> 2] = 0;
+ i13 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i13 + 36 >> 2] = HEAP32[i4 + 68 >> 2];
+ HEAP8[i13 + 78 | 0] = 2;
+ i13 = _luaH_new(i10) | 0;
+ HEAP32[i6 + 4 >> 2] = i13;
+ i14 = i10 + 8 | 0;
+ i15 = HEAP32[i14 >> 2] | 0;
+ HEAP32[i15 >> 2] = i13;
+ HEAP32[i15 + 8 >> 2] = 69;
+ i15 = (HEAP32[i14 >> 2] | 0) + 16 | 0;
+ HEAP32[i14 >> 2] = i15;
+ if (((HEAP32[i10 + 24 >> 2] | 0) - i15 | 0) < 16) {
+  _luaD_growstack(i10, 0);
+ }
+ HEAP8[i5 + 10 | 0] = 0;
+ HEAP8[i5 + 8 | 0] = HEAP8[i6 + 46 | 0] | 0;
+ i15 = HEAP32[(HEAP32[i8 >> 2] | 0) + 64 >> 2] | 0;
+ HEAP16[i5 + 4 >> 1] = HEAP32[i15 + 28 >> 2];
+ HEAP16[i5 + 6 >> 1] = HEAP32[i15 + 16 >> 2];
+ HEAP8[i5 + 9 | 0] = 0;
+ HEAP32[i5 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i9 >> 2] = i5;
+ HEAP8[(HEAP32[i6 >> 2] | 0) + 77 | 0] = 1;
+ HEAP32[i7 + 16 >> 2] = -1;
+ HEAP32[i7 + 20 >> 2] = -1;
+ HEAP32[i7 >> 2] = 7;
+ HEAP32[i7 + 8 >> 2] = 0;
+ _newupvalue(i6, HEAP32[i4 + 72 >> 2] | 0, i7) | 0;
+ _luaX_next(i4);
+ i5 = i4 + 16 | 0;
+ L7 : while (1) {
+  i6 = HEAP32[i5 >> 2] | 0;
+  switch (i6 | 0) {
+  case 277:
+  case 286:
+  case 262:
+  case 261:
+  case 260:
+   {
+    break L7;
+   }
+  default:
+   {}
+  }
+  _statement(i4);
+  if ((i6 | 0) == 274) {
+   i1 = 8;
+   break;
+  }
+ }
+ if ((i1 | 0) == 8) {
+  i6 = HEAP32[i5 >> 2] | 0;
+ }
+ if ((i6 | 0) == 286) {
+  _close_func(i4);
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  _error_expected(i4, 286);
+ }
+ return 0;
+}
+function _luaV_lessthan(i5, i4, i2) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ i6 = i4 + 8 | 0;
+ i7 = HEAP32[i6 >> 2] | 0;
+ if ((i7 | 0) == 3) {
+  if ((HEAP32[i2 + 8 >> 2] | 0) == 3) {
+   i9 = +HEAPF64[i4 >> 3] < +HEAPF64[i2 >> 3] | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ } else {
+  if ((i7 & 15 | 0) == 4 ? (HEAP32[i2 + 8 >> 2] & 15 | 0) == 4 : 0) {
+   i6 = HEAP32[i4 >> 2] | 0;
+   i4 = HEAP32[i2 >> 2] | 0;
+   i3 = i6 + 16 | 0;
+   i5 = i4 + 16 | 0;
+   i7 = _strcmp(i3, i5) | 0;
+   L8 : do {
+    if ((i7 | 0) == 0) {
+     i2 = HEAP32[i6 + 12 >> 2] | 0;
+     i4 = HEAP32[i4 + 12 >> 2] | 0;
+     while (1) {
+      i7 = _strlen(i3 | 0) | 0;
+      i6 = (i7 | 0) == (i2 | 0);
+      if ((i7 | 0) == (i4 | 0)) {
+       break;
+      }
+      if (i6) {
+       i7 = -1;
+       break L8;
+      }
+      i6 = i7 + 1 | 0;
+      i3 = i3 + i6 | 0;
+      i5 = i5 + i6 | 0;
+      i7 = _strcmp(i3, i5) | 0;
+      if ((i7 | 0) == 0) {
+       i2 = i2 - i6 | 0;
+       i4 = i4 - i6 | 0;
+      } else {
+       break L8;
+      }
+     }
+     i7 = i6 & 1 ^ 1;
+    }
+   } while (0);
+   i9 = i7 >>> 31;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ }
+ i8 = i5 + 8 | 0;
+ i7 = HEAP32[i8 >> 2] | 0;
+ i9 = _luaT_gettmbyobj(i5, i4, 13) | 0;
+ if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+  i9 = _luaT_gettmbyobj(i5, i2, 13) | 0;
+  if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+   _luaG_ordererror(i5, i4, i2);
+  } else {
+   i3 = i9;
+  }
+ } else {
+  i3 = i9;
+ }
+ i10 = i5 + 28 | 0;
+ i9 = i7 - (HEAP32[i10 >> 2] | 0) | 0;
+ i11 = HEAP32[i8 >> 2] | 0;
+ HEAP32[i8 >> 2] = i11 + 16;
+ i13 = i3;
+ i12 = HEAP32[i13 + 4 >> 2] | 0;
+ i7 = i11;
+ HEAP32[i7 >> 2] = HEAP32[i13 >> 2];
+ HEAP32[i7 + 4 >> 2] = i12;
+ HEAP32[i11 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+ i3 = HEAP32[i8 >> 2] | 0;
+ HEAP32[i8 >> 2] = i3 + 16;
+ i11 = i4;
+ i7 = HEAP32[i11 + 4 >> 2] | 0;
+ i4 = i3;
+ HEAP32[i4 >> 2] = HEAP32[i11 >> 2];
+ HEAP32[i4 + 4 >> 2] = i7;
+ HEAP32[i3 + 8 >> 2] = HEAP32[i6 >> 2];
+ i3 = HEAP32[i8 >> 2] | 0;
+ HEAP32[i8 >> 2] = i3 + 16;
+ i4 = i2;
+ i7 = HEAP32[i4 + 4 >> 2] | 0;
+ i6 = i3;
+ HEAP32[i6 >> 2] = HEAP32[i4 >> 2];
+ HEAP32[i6 + 4 >> 2] = i7;
+ HEAP32[i3 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+ _luaD_call(i5, (HEAP32[i8 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i5 + 16 >> 2] | 0) + 18 | 0] & 1);
+ i2 = HEAP32[i10 >> 2] | 0;
+ i3 = HEAP32[i8 >> 2] | 0;
+ i5 = i3 + -16 | 0;
+ HEAP32[i8 >> 2] = i5;
+ i6 = HEAP32[i5 + 4 >> 2] | 0;
+ i7 = i2 + i9 | 0;
+ HEAP32[i7 >> 2] = HEAP32[i5 >> 2];
+ HEAP32[i7 + 4 >> 2] = i6;
+ HEAP32[i2 + (i9 + 8) >> 2] = HEAP32[i3 + -8 >> 2];
+ i2 = HEAP32[i8 >> 2] | 0;
+ i3 = HEAP32[i2 + 8 >> 2] | 0;
+ if ((i3 | 0) != 0) {
+  if ((i3 | 0) == 1) {
+   i2 = (HEAP32[i2 >> 2] | 0) != 0;
+  } else {
+   i2 = 1;
+  }
+ } else {
+  i2 = 0;
+ }
+ i13 = i2 & 1;
+ STACKTOP = i1;
+ return i13 | 0;
+}
+function _discharge2reg(i4, i3, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, d11 = 0.0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i9 = i2 + 16 | 0;
+ i8 = i2;
+ _luaK_dischargevars(i4, i3);
+ i10 = HEAP32[i3 >> 2] | 0;
+ L1 : do {
+  switch (i10 | 0) {
+  case 5:
+   {
+    d11 = +HEAPF64[i3 + 8 >> 3];
+    HEAPF64[i9 >> 3] = d11;
+    i5 = HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 52 >> 2] | 0;
+    HEAPF64[i8 >> 3] = d11;
+    HEAP32[i8 + 8 >> 2] = 3;
+    if (d11 != d11 | 0.0 != 0.0 | d11 == 0.0) {
+     i10 = i5 + 8 | 0;
+     i7 = HEAP32[i10 >> 2] | 0;
+     HEAP32[i10 >> 2] = i7 + 16;
+     i5 = _luaS_newlstr(i5, i9, 8) | 0;
+     HEAP32[i7 >> 2] = i5;
+     HEAP32[i7 + 8 >> 2] = HEAPU8[i5 + 4 | 0] | 0 | 64;
+     i5 = _addk(i4, (HEAP32[i10 >> 2] | 0) + -16 | 0, i8) | 0;
+     HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + -16;
+    } else {
+     i5 = _addk(i4, i8, i8) | 0;
+    }
+    i6 = i1 << 6;
+    if ((i5 | 0) < 262144) {
+     _luaK_code(i4, i6 | i5 << 14 | 1) | 0;
+     break L1;
+    } else {
+     _luaK_code(i4, i6 | 2) | 0;
+     _luaK_code(i4, i5 << 6 | 39) | 0;
+     break L1;
+    }
+   }
+  case 2:
+  case 3:
+   {
+    _luaK_code(i4, i1 << 6 | ((i10 | 0) == 2) << 23 | 3) | 0;
+    break;
+   }
+  case 4:
+   {
+    i6 = HEAP32[i3 + 8 >> 2] | 0;
+    i5 = i1 << 6;
+    if ((i6 | 0) < 262144) {
+     _luaK_code(i4, i5 | i6 << 14 | 1) | 0;
+     break L1;
+    } else {
+     _luaK_code(i4, i5 | 2) | 0;
+     _luaK_code(i4, i6 << 6 | 39) | 0;
+     break L1;
+    }
+   }
+  case 1:
+   {
+    i9 = i1 + 1 | 0;
+    i8 = HEAP32[i4 + 20 >> 2] | 0;
+    do {
+     if ((i8 | 0) > (HEAP32[i4 + 24 >> 2] | 0) ? (i5 = (HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0) + (i8 + -1 << 2) | 0, i6 = HEAP32[i5 >> 2] | 0, (i6 & 63 | 0) == 4) : 0) {
+      i10 = i6 >>> 6 & 255;
+      i8 = i10 + (i6 >>> 23) | 0;
+      if (!((i10 | 0) <= (i1 | 0) ? (i8 + 1 | 0) >= (i1 | 0) : 0)) {
+       i7 = 6;
+      }
+      if ((i7 | 0) == 6 ? (i10 | 0) < (i1 | 0) | (i10 | 0) > (i9 | 0) : 0) {
+       break;
+      }
+      i4 = (i10 | 0) < (i1 | 0) ? i10 : i1;
+      HEAP32[i5 >> 2] = i4 << 6 & 16320 | i6 & 8372287 | ((i8 | 0) > (i1 | 0) ? i8 : i1) - i4 << 23;
+      break L1;
+     }
+    } while (0);
+    _luaK_code(i4, i1 << 6 | 4) | 0;
+    break;
+   }
+  case 6:
+   {
+    i5 = HEAP32[i3 + 8 >> 2] | 0;
+    if ((i5 | 0) != (i1 | 0)) {
+     _luaK_code(i4, i5 << 23 | i1 << 6) | 0;
+    }
+    break;
+   }
+  case 11:
+   {
+    i10 = (HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i3 + 8 >> 2] << 2) | 0;
+    HEAP32[i10 >> 2] = HEAP32[i10 >> 2] & -16321 | i1 << 6 & 16320;
+    break;
+   }
+  default:
+   {
+    STACKTOP = i2;
+    return;
+   }
+  }
+ } while (0);
+ HEAP32[i3 + 8 >> 2] = i1;
+ HEAP32[i3 >> 2] = 6;
+ STACKTOP = i2;
+ return;
+}
+function _unroll(i3, i4) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0;
+ i9 = STACKTOP;
+ i11 = i3 + 16 | 0;
+ i13 = HEAP32[i11 >> 2] | 0;
+ i5 = i3 + 72 | 0;
+ if ((i13 | 0) == (i5 | 0)) {
+  STACKTOP = i9;
+  return;
+ }
+ i6 = i3 + 8 | 0;
+ i10 = i3 + 40 | 0;
+ i7 = i3 + 20 | 0;
+ i8 = i3 + 28 | 0;
+ i4 = i3 + 68 | 0;
+ do {
+  i12 = i13 + 18 | 0;
+  i14 = HEAP8[i12] | 0;
+  if ((i14 & 1) == 0) {
+   i14 = i14 & 255;
+   if ((i14 & 16 | 0) != 0) {
+    HEAP8[i12] = i14 & 239;
+    HEAP32[i4 >> 2] = HEAP32[i13 + 32 >> 2];
+   }
+   if ((HEAP16[i13 + 16 >> 1] | 0) == -1 ? (i2 = (HEAP32[i11 >> 2] | 0) + 4 | 0, i1 = HEAP32[i6 >> 2] | 0, (HEAP32[i2 >> 2] | 0) >>> 0 < i1 >>> 0) : 0) {
+    HEAP32[i2 >> 2] = i1;
+   }
+   i14 = HEAP8[i12] | 0;
+   if ((i14 & 32) == 0) {
+    HEAP8[i13 + 37 | 0] = 1;
+   }
+   HEAP8[i12] = i14 & 199 | 8;
+   i14 = FUNCTION_TABLE_ii[HEAP32[i13 + 28 >> 2] & 255](i3) | 0;
+   i14 = (HEAP32[i6 >> 2] | 0) + (0 - i14 << 4) | 0;
+   i13 = HEAP32[i11 >> 2] | 0;
+   i12 = HEAPU8[i10] | 0;
+   if ((i12 & 6 | 0) == 0) {
+    i15 = i13 + 8 | 0;
+   } else {
+    if ((i12 & 2 | 0) != 0) {
+     i14 = i14 - (HEAP32[i8 >> 2] | 0) | 0;
+     _luaD_hook(i3, 1, -1);
+     i14 = (HEAP32[i8 >> 2] | 0) + i14 | 0;
+    }
+    i15 = i13 + 8 | 0;
+    HEAP32[i7 >> 2] = HEAP32[(HEAP32[i15 >> 2] | 0) + 28 >> 2];
+   }
+   i12 = HEAP32[i13 >> 2] | 0;
+   i13 = HEAP16[i13 + 16 >> 1] | 0;
+   HEAP32[i11 >> 2] = HEAP32[i15 >> 2];
+   L25 : do {
+    if (!(i13 << 16 >> 16 == 0)) {
+     i15 = i13 << 16 >> 16;
+     if (i14 >>> 0 < (HEAP32[i6 >> 2] | 0) >>> 0) {
+      i13 = i14;
+      i14 = i15;
+      i15 = i12;
+      while (1) {
+       i12 = i15 + 16 | 0;
+       i18 = i13;
+       i17 = HEAP32[i18 + 4 >> 2] | 0;
+       i16 = i15;
+       HEAP32[i16 >> 2] = HEAP32[i18 >> 2];
+       HEAP32[i16 + 4 >> 2] = i17;
+       HEAP32[i15 + 8 >> 2] = HEAP32[i13 + 8 >> 2];
+       i14 = i14 + -1 | 0;
+       i13 = i13 + 16 | 0;
+       if ((i14 | 0) == 0) {
+        break L25;
+       }
+       if (i13 >>> 0 < (HEAP32[i6 >> 2] | 0) >>> 0) {
+        i15 = i12;
+       } else {
+        i13 = i14;
+        break;
+       }
+      }
+     } else {
+      i13 = i15;
+     }
+     if ((i13 | 0) > 0) {
+      i14 = i13;
+      i15 = i12;
+      while (1) {
+       i14 = i14 + -1 | 0;
+       HEAP32[i15 + 8 >> 2] = 0;
+       if ((i14 | 0) <= 0) {
+        break;
+       } else {
+        i15 = i15 + 16 | 0;
+       }
+      }
+      i12 = i12 + (i13 << 4) | 0;
+     }
+    }
+   } while (0);
+   HEAP32[i6 >> 2] = i12;
+  } else {
+   _luaV_finishOp(i3);
+   _luaV_execute(i3);
+  }
+  i13 = HEAP32[i11 >> 2] | 0;
+ } while ((i13 | 0) != (i5 | 0));
+ STACKTOP = i9;
+ return;
+}
+function _traverseephemeron(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i3 = STACKTOP;
+ i11 = i2 + 16 | 0;
+ i9 = HEAP32[i11 >> 2] | 0;
+ i5 = i9 + (1 << (HEAPU8[i2 + 7 | 0] | 0) << 5) | 0;
+ i10 = i2 + 28 | 0;
+ i13 = HEAP32[i10 >> 2] | 0;
+ if ((i13 | 0) > 0) {
+  i9 = i2 + 12 | 0;
+  i12 = 0;
+  i8 = 0;
+  do {
+   i14 = HEAP32[i9 >> 2] | 0;
+   if ((HEAP32[i14 + (i12 << 4) + 8 >> 2] & 64 | 0) != 0 ? (i7 = HEAP32[i14 + (i12 << 4) >> 2] | 0, !((HEAP8[i7 + 5 | 0] & 3) == 0)) : 0) {
+    _reallymarkobject(i1, i7);
+    i13 = HEAP32[i10 >> 2] | 0;
+    i8 = 1;
+   }
+   i12 = i12 + 1 | 0;
+  } while ((i12 | 0) < (i13 | 0));
+  i9 = HEAP32[i11 >> 2] | 0;
+ } else {
+  i8 = 0;
+ }
+ if (i9 >>> 0 < i5 >>> 0) {
+  i7 = 0;
+  i10 = 0;
+  do {
+   i11 = i9 + 8 | 0;
+   i12 = HEAP32[i11 >> 2] | 0;
+   i14 = i9 + 24 | 0;
+   i13 = HEAP32[i14 >> 2] | 0;
+   i15 = (i13 & 64 | 0) == 0;
+   L14 : do {
+    if ((i12 | 0) == 0) {
+     if (!i15 ? !((HEAP8[(HEAP32[i9 + 16 >> 2] | 0) + 5 | 0] & 3) == 0) : 0) {
+      HEAP32[i14 >> 2] = 11;
+     }
+    } else {
+     do {
+      if (i15) {
+       i6 = i12;
+       i4 = 18;
+      } else {
+       i14 = HEAP32[i9 + 16 >> 2] | 0;
+       if ((i13 & 15 | 0) == 4) {
+        if ((i14 | 0) == 0) {
+         i6 = i12;
+         i4 = 18;
+         break;
+        }
+        if ((HEAP8[i14 + 5 | 0] & 3) == 0) {
+         i6 = i12;
+         i4 = 18;
+         break;
+        }
+        _reallymarkobject(i1, i14);
+        i6 = HEAP32[i11 >> 2] | 0;
+        i4 = 18;
+        break;
+       }
+       i11 = (i12 & 64 | 0) == 0;
+       if ((HEAP8[i14 + 5 | 0] & 3) == 0) {
+        if (i11) {
+         break L14;
+        } else {
+         break;
+        }
+       }
+       if (i11) {
+        i7 = 1;
+        break L14;
+       }
+       i7 = 1;
+       i10 = (HEAP8[(HEAP32[i9 >> 2] | 0) + 5 | 0] & 3) == 0 ? i10 : 1;
+       break L14;
+      }
+     } while (0);
+     if ((i4 | 0) == 18 ? (i4 = 0, (i6 & 64 | 0) == 0) : 0) {
+      break;
+     }
+     i11 = HEAP32[i9 >> 2] | 0;
+     if (!((HEAP8[i11 + 5 | 0] & 3) == 0)) {
+      _reallymarkobject(i1, i11);
+      i8 = 1;
+     }
+    }
+   } while (0);
+   i9 = i9 + 32 | 0;
+  } while (i9 >>> 0 < i5 >>> 0);
+  if ((i10 | 0) != 0) {
+   i15 = i1 + 96 | 0;
+   HEAP32[i2 + 24 >> 2] = HEAP32[i15 >> 2];
+   HEAP32[i15 >> 2] = i2;
+   i15 = i8;
+   STACKTOP = i3;
+   return i15 | 0;
+  }
+  if ((i7 | 0) != 0) {
+   i15 = i1 + 100 | 0;
+   HEAP32[i2 + 24 >> 2] = HEAP32[i15 >> 2];
+   HEAP32[i15 >> 2] = i2;
+   i15 = i8;
+   STACKTOP = i3;
+   return i15 | 0;
+  }
+ }
+ i15 = i1 + 88 | 0;
+ HEAP32[i2 + 24 >> 2] = HEAP32[i15 >> 2];
+ HEAP32[i15 >> 2] = i2;
+ i15 = i8;
+ STACKTOP = i3;
+ return i15 | 0;
+}
+function _luaV_gettable(i2, i7, i5, i1) {
+ i2 = i2 | 0;
+ i7 = i7 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i3 = 0, i4 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i6;
+ i8 = i2 + 12 | 0;
+ i3 = i7;
+ i10 = HEAP32[i7 + 8 >> 2] | 0;
+ i9 = 0;
+ while (1) {
+  i7 = i3 + 8 | 0;
+  if ((i10 | 0) != 69) {
+   i12 = _luaT_gettmbyobj(i2, i3, 0) | 0;
+   i10 = HEAP32[i12 + 8 >> 2] | 0;
+   if ((i10 | 0) == 0) {
+    i8 = 11;
+    break;
+   }
+  } else {
+   i12 = HEAP32[i3 >> 2] | 0;
+   i11 = _luaH_get(i12, i5) | 0;
+   i10 = i11 + 8 | 0;
+   if ((HEAP32[i10 >> 2] | 0) != 0) {
+    i8 = 9;
+    break;
+   }
+   i12 = HEAP32[i12 + 8 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    i8 = 9;
+    break;
+   }
+   if (!((HEAP8[i12 + 6 | 0] & 1) == 0)) {
+    i8 = 9;
+    break;
+   }
+   i12 = _luaT_gettm(i12, 0, HEAP32[(HEAP32[i8 >> 2] | 0) + 184 >> 2] | 0) | 0;
+   if ((i12 | 0) == 0) {
+    i8 = 9;
+    break;
+   }
+   i10 = HEAP32[i12 + 8 >> 2] | 0;
+  }
+  i9 = i9 + 1 | 0;
+  if ((i10 & 15 | 0) == 6) {
+   i8 = 13;
+   break;
+  }
+  if ((i9 | 0) < 100) {
+   i3 = i12;
+  } else {
+   i8 = 14;
+   break;
+  }
+ }
+ if ((i8 | 0) == 9) {
+  i9 = i11;
+  i11 = HEAP32[i9 + 4 >> 2] | 0;
+  i12 = i1;
+  HEAP32[i12 >> 2] = HEAP32[i9 >> 2];
+  HEAP32[i12 + 4 >> 2] = i11;
+  HEAP32[i1 + 8 >> 2] = HEAP32[i10 >> 2];
+  STACKTOP = i6;
+  return;
+ } else if ((i8 | 0) == 11) {
+  _luaG_typeerror(i2, i3, 8944);
+ } else if ((i8 | 0) == 13) {
+  i10 = i2 + 28 | 0;
+  i11 = i1 - (HEAP32[i10 >> 2] | 0) | 0;
+  i8 = i2 + 8 | 0;
+  i9 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i9 + 16;
+  i13 = i12;
+  i1 = HEAP32[i13 + 4 >> 2] | 0;
+  i4 = i9;
+  HEAP32[i4 >> 2] = HEAP32[i13 >> 2];
+  HEAP32[i4 + 4 >> 2] = i1;
+  HEAP32[i9 + 8 >> 2] = HEAP32[i12 + 8 >> 2];
+  i12 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i12 + 16;
+  i9 = HEAP32[i3 + 4 >> 2] | 0;
+  i4 = i12;
+  HEAP32[i4 >> 2] = HEAP32[i3 >> 2];
+  HEAP32[i4 + 4 >> 2] = i9;
+  HEAP32[i12 + 8 >> 2] = HEAP32[i7 >> 2];
+  i12 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i12 + 16;
+  i4 = i5;
+  i9 = HEAP32[i4 + 4 >> 2] | 0;
+  i7 = i12;
+  HEAP32[i7 >> 2] = HEAP32[i4 >> 2];
+  HEAP32[i7 + 4 >> 2] = i9;
+  HEAP32[i12 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+  _luaD_call(i2, (HEAP32[i8 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i2 + 16 >> 2] | 0) + 18 | 0] & 1);
+  i12 = HEAP32[i10 >> 2] | 0;
+  i10 = HEAP32[i8 >> 2] | 0;
+  i7 = i10 + -16 | 0;
+  HEAP32[i8 >> 2] = i7;
+  i8 = HEAP32[i7 + 4 >> 2] | 0;
+  i9 = i12 + i11 | 0;
+  HEAP32[i9 >> 2] = HEAP32[i7 >> 2];
+  HEAP32[i9 + 4 >> 2] = i8;
+  HEAP32[i12 + (i11 + 8) >> 2] = HEAP32[i10 + -8 >> 2];
+  STACKTOP = i6;
+  return;
+ } else if ((i8 | 0) == 14) {
+  _luaG_runerror(i2, 8952, i4);
+ }
+}
+function _db_getinfo(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i3 = i2;
+ if ((_lua_type(i1, 1) | 0) == 8) {
+  i4 = _lua_tothread(i1, 1) | 0;
+  i7 = 1;
+ } else {
+  i4 = i1;
+  i7 = 0;
+ }
+ i5 = i7 | 2;
+ i6 = _luaL_optlstring(i1, i5, 11784, 0) | 0;
+ i7 = i7 + 1 | 0;
+ do {
+  if ((_lua_isnumber(i1, i7) | 0) != 0) {
+   if ((_lua_getstack(i4, _lua_tointegerx(i1, i7, 0) | 0, i3) | 0) == 0) {
+    _lua_pushnil(i1);
+    i7 = 1;
+    STACKTOP = i2;
+    return i7 | 0;
+   }
+  } else {
+   if ((_lua_type(i1, i7) | 0) == 6) {
+    HEAP32[i3 >> 2] = i6;
+    _lua_pushfstring(i1, 11792, i3) | 0;
+    i6 = _lua_tolstring(i1, -1, 0) | 0;
+    _lua_pushvalue(i1, i7);
+    _lua_xmove(i1, i4, 1);
+    break;
+   }
+   i7 = _luaL_argerror(i1, i7, 11800) | 0;
+   STACKTOP = i2;
+   return i7 | 0;
+  }
+ } while (0);
+ if ((_lua_getinfo(i4, i6, i3) | 0) == 0) {
+  i7 = _luaL_argerror(i1, i5, 11832) | 0;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ _lua_createtable(i1, 0, 2);
+ if ((_strchr(i6, 83) | 0) != 0) {
+  _lua_pushstring(i1, HEAP32[i3 + 16 >> 2] | 0) | 0;
+  _lua_setfield(i1, -2, 11848);
+  _lua_pushstring(i1, i3 + 36 | 0) | 0;
+  _lua_setfield(i1, -2, 11856);
+  _lua_pushinteger(i1, HEAP32[i3 + 24 >> 2] | 0);
+  _lua_setfield(i1, -2, 11872);
+  _lua_pushinteger(i1, HEAP32[i3 + 28 >> 2] | 0);
+  _lua_setfield(i1, -2, 11888);
+  _lua_pushstring(i1, HEAP32[i3 + 12 >> 2] | 0) | 0;
+  _lua_setfield(i1, -2, 11904);
+ }
+ if ((_strchr(i6, 108) | 0) != 0) {
+  _lua_pushinteger(i1, HEAP32[i3 + 20 >> 2] | 0);
+  _lua_setfield(i1, -2, 11912);
+ }
+ if ((_strchr(i6, 117) | 0) != 0) {
+  _lua_pushinteger(i1, HEAPU8[i3 + 32 | 0] | 0);
+  _lua_setfield(i1, -2, 11928);
+  _lua_pushinteger(i1, HEAPU8[i3 + 33 | 0] | 0);
+  _lua_setfield(i1, -2, 11936);
+  _lua_pushboolean(i1, HEAP8[i3 + 34 | 0] | 0);
+  _lua_setfield(i1, -2, 11944);
+ }
+ if ((_strchr(i6, 110) | 0) != 0) {
+  _lua_pushstring(i1, HEAP32[i3 + 4 >> 2] | 0) | 0;
+  _lua_setfield(i1, -2, 11960);
+  _lua_pushstring(i1, HEAP32[i3 + 8 >> 2] | 0) | 0;
+  _lua_setfield(i1, -2, 11968);
+ }
+ if ((_strchr(i6, 116) | 0) != 0) {
+  _lua_pushboolean(i1, HEAP8[i3 + 35 | 0] | 0);
+  _lua_setfield(i1, -2, 11984);
+ }
+ if ((_strchr(i6, 76) | 0) != 0) {
+  if ((i4 | 0) == (i1 | 0)) {
+   _lua_pushvalue(i1, -2);
+   _lua_remove(i1, -3);
+  } else {
+   _lua_xmove(i4, i1, 1);
+  }
+  _lua_setfield(i1, -2, 12e3);
+ }
+ if ((_strchr(i6, 102) | 0) == 0) {
+  i7 = 1;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ if ((i4 | 0) == (i1 | 0)) {
+  _lua_pushvalue(i1, -2);
+  _lua_remove(i1, -3);
+ } else {
+  _lua_xmove(i4, i1, 1);
+ }
+ _lua_setfield(i1, -2, 12016);
+ i7 = 1;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _luaL_traceback(i4, i1, i9, i7) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i9 = i9 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 208 | 0;
+ i6 = i3;
+ i5 = i3 + 100 | 0;
+ i2 = _lua_gettop(i4) | 0;
+ i8 = 1;
+ i10 = 1;
+ while (1) {
+  if ((_lua_getstack(i1, i8, i6) | 0) == 0) {
+   break;
+  } else {
+   i10 = i8;
+   i8 = i8 << 1;
+  }
+ }
+ if ((i10 | 0) < (i8 | 0)) {
+  while (1) {
+   i11 = (i8 + i10 | 0) / 2 | 0;
+   i12 = (_lua_getstack(i1, i11, i6) | 0) == 0;
+   i8 = i12 ? i11 : i8;
+   i10 = i12 ? i10 : i11 + 1 | 0;
+   if ((i10 | 0) >= (i8 | 0)) {
+    i10 = i8;
+    break;
+   }
+  }
+ } else {
+  i10 = i8;
+ }
+ i8 = (i10 + -1 | 0) > 22 ? 12 : 0;
+ if ((i9 | 0) != 0) {
+  HEAP32[i6 >> 2] = i9;
+  _lua_pushfstring(i4, 944, i6) | 0;
+ }
+ _lua_pushlstring(i4, 952, 16) | 0;
+ if ((_lua_getstack(i1, i7, i5) | 0) == 0) {
+  i17 = _lua_gettop(i4) | 0;
+  i17 = i17 - i2 | 0;
+  _lua_concat(i4, i17);
+  STACKTOP = i3;
+  return;
+ }
+ i10 = i10 + -11 | 0;
+ i13 = i5 + 36 | 0;
+ i9 = i5 + 20 | 0;
+ i16 = i5 + 8 | 0;
+ i12 = i5 + 12 | 0;
+ i15 = i5 + 24 | 0;
+ i14 = i5 + 35 | 0;
+ i11 = i5 + 4 | 0;
+ do {
+  i7 = i7 + 1 | 0;
+  if ((i7 | 0) == (i8 | 0)) {
+   _lua_pushlstring(i4, 976, 5) | 0;
+   i7 = i10;
+  } else {
+   _lua_getinfo(i1, 984, i5) | 0;
+   HEAP32[i6 >> 2] = i13;
+   _lua_pushfstring(i4, 992, i6) | 0;
+   i17 = HEAP32[i9 >> 2] | 0;
+   if ((i17 | 0) > 0) {
+    HEAP32[i6 >> 2] = i17;
+    _lua_pushfstring(i4, 1e3, i6) | 0;
+   }
+   _lua_pushlstring(i4, 1008, 4) | 0;
+   do {
+    if ((HEAP8[HEAP32[i16 >> 2] | 0] | 0) == 0) {
+     i17 = HEAP8[HEAP32[i12 >> 2] | 0] | 0;
+     if (i17 << 24 >> 24 == 109) {
+      _lua_pushlstring(i4, 1800, 10) | 0;
+      break;
+     } else if (i17 << 24 >> 24 == 67) {
+      if ((_pushglobalfuncname(i4, i5) | 0) == 0) {
+       _lua_pushlstring(i4, 1112, 1) | 0;
+       break;
+      } else {
+       HEAP32[i6 >> 2] = _lua_tolstring(i4, -1, 0) | 0;
+       _lua_pushfstring(i4, 1784, i6) | 0;
+       _lua_remove(i4, -2);
+       break;
+      }
+     } else {
+      i17 = HEAP32[i15 >> 2] | 0;
+      HEAP32[i6 >> 2] = i13;
+      HEAP32[i6 + 4 >> 2] = i17;
+      _lua_pushfstring(i4, 1816, i6) | 0;
+      break;
+     }
+    } else {
+     HEAP32[i6 >> 2] = HEAP32[i11 >> 2];
+     _lua_pushfstring(i4, 1784, i6) | 0;
+    }
+   } while (0);
+   if ((HEAP8[i14] | 0) != 0) {
+    _lua_pushlstring(i4, 1016, 20) | 0;
+   }
+   _lua_concat(i4, (_lua_gettop(i4) | 0) - i2 | 0);
+  }
+ } while ((_lua_getstack(i1, i7, i5) | 0) != 0);
+ i17 = _lua_gettop(i4) | 0;
+ i17 = i17 - i2 | 0;
+ _lua_concat(i4, i17);
+ STACKTOP = i3;
+ return;
+}
+function _luaK_exp2RK(i3, i1) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, d11 = 0.0, i12 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i7 = i2 + 16 | 0;
+ i6 = i2;
+ i4 = i1 + 16 | 0;
+ i5 = i1 + 20 | 0;
+ i10 = (HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0);
+ _luaK_dischargevars(i3, i1);
+ do {
+  if (!i10) {
+   if ((HEAP32[i1 >> 2] | 0) == 6) {
+    i10 = HEAP32[i1 + 8 >> 2] | 0;
+    if ((HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0)) {
+     break;
+    }
+    if ((i10 | 0) >= (HEAPU8[i3 + 46 | 0] | 0 | 0)) {
+     _exp2reg(i3, i1, i10);
+     break;
+    }
+   }
+   _luaK_exp2nextreg(i3, i1);
+  }
+ } while (0);
+ i10 = HEAP32[i1 >> 2] | 0;
+ switch (i10 | 0) {
+ case 4:
+  {
+   i8 = HEAP32[i1 + 8 >> 2] | 0;
+   i9 = 18;
+   break;
+  }
+ case 1:
+ case 3:
+ case 2:
+  {
+   if ((HEAP32[i3 + 32 >> 2] | 0) < 256) {
+    if ((i10 | 0) == 1) {
+     HEAP32[i6 + 8 >> 2] = 0;
+     HEAP32[i7 >> 2] = HEAP32[i3 + 4 >> 2];
+     HEAP32[i7 + 8 >> 2] = 69;
+     i3 = _addk(i3, i7, i6) | 0;
+    } else {
+     HEAP32[i7 >> 2] = (i10 | 0) == 2;
+     HEAP32[i7 + 8 >> 2] = 1;
+     i3 = _addk(i3, i7, i7) | 0;
+    }
+    HEAP32[i1 + 8 >> 2] = i3;
+    HEAP32[i1 >> 2] = 4;
+    i10 = i3 | 256;
+    STACKTOP = i2;
+    return i10 | 0;
+   }
+   break;
+  }
+ case 5:
+  {
+   i9 = i1 + 8 | 0;
+   d11 = +HEAPF64[i9 >> 3];
+   HEAPF64[i7 >> 3] = d11;
+   i8 = HEAP32[(HEAP32[i3 + 12 >> 2] | 0) + 52 >> 2] | 0;
+   HEAPF64[i6 >> 3] = d11;
+   HEAP32[i6 + 8 >> 2] = 3;
+   if (d11 != d11 | 0.0 != 0.0 | d11 == 0.0) {
+    i10 = i8 + 8 | 0;
+    i12 = HEAP32[i10 >> 2] | 0;
+    HEAP32[i10 >> 2] = i12 + 16;
+    i8 = _luaS_newlstr(i8, i7, 8) | 0;
+    HEAP32[i12 >> 2] = i8;
+    HEAP32[i12 + 8 >> 2] = HEAPU8[i8 + 4 | 0] | 0 | 64;
+    i8 = _addk(i3, (HEAP32[i10 >> 2] | 0) + -16 | 0, i6) | 0;
+    HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + -16;
+   } else {
+    i8 = _addk(i3, i6, i6) | 0;
+   }
+   HEAP32[i9 >> 2] = i8;
+   HEAP32[i1 >> 2] = 4;
+   i9 = 18;
+   break;
+  }
+ default:
+  {}
+ }
+ if ((i9 | 0) == 18 ? (i8 | 0) < 256 : 0) {
+  i12 = i8 | 256;
+  STACKTOP = i2;
+  return i12 | 0;
+ }
+ _luaK_dischargevars(i3, i1);
+ if ((HEAP32[i1 >> 2] | 0) == 6) {
+  i7 = i1 + 8 | 0;
+  i6 = HEAP32[i7 >> 2] | 0;
+  if ((HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0)) {
+   i12 = i6;
+   STACKTOP = i2;
+   return i12 | 0;
+  }
+  if ((i6 | 0) >= (HEAPU8[i3 + 46 | 0] | 0 | 0)) {
+   _exp2reg(i3, i1, i6);
+   i12 = HEAP32[i7 >> 2] | 0;
+   STACKTOP = i2;
+   return i12 | 0;
+  }
+ } else {
+  i7 = i1 + 8 | 0;
+ }
+ _luaK_exp2nextreg(i3, i1);
+ i12 = HEAP32[i7 >> 2] | 0;
+ STACKTOP = i2;
+ return i12 | 0;
+}
+function _os_date(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 1264 | 0;
+ i4 = i2;
+ i7 = i2 + 1048 | 0;
+ i6 = i2 + 1256 | 0;
+ i3 = i2 + 8 | 0;
+ i5 = i2 + 1056 | 0;
+ i12 = _luaL_optlstring(i1, 1, 6064, 0) | 0;
+ if ((_lua_type(i1, 2) | 0) < 1) {
+  i8 = _time(0) | 0;
+ } else {
+  i8 = ~~+_luaL_checknumber(i1, 2);
+ }
+ HEAP32[i7 >> 2] = i8;
+ if ((HEAP8[i12] | 0) == 33) {
+  i12 = i12 + 1 | 0;
+  i10 = _gmtime(i7 | 0) | 0;
+ } else {
+  i10 = _localtime(i7 | 0) | 0;
+ }
+ if ((i10 | 0) == 0) {
+  _lua_pushnil(i1);
+  STACKTOP = i2;
+  return 1;
+ }
+ if ((_strcmp(i12, 6072) | 0) == 0) {
+  _lua_createtable(i1, 0, 9);
+  _lua_pushinteger(i1, HEAP32[i10 >> 2] | 0);
+  _lua_setfield(i1, -2, 5864);
+  _lua_pushinteger(i1, HEAP32[i10 + 4 >> 2] | 0);
+  _lua_setfield(i1, -2, 5872);
+  _lua_pushinteger(i1, HEAP32[i10 + 8 >> 2] | 0);
+  _lua_setfield(i1, -2, 5880);
+  _lua_pushinteger(i1, HEAP32[i10 + 12 >> 2] | 0);
+  _lua_setfield(i1, -2, 5888);
+  _lua_pushinteger(i1, (HEAP32[i10 + 16 >> 2] | 0) + 1 | 0);
+  _lua_setfield(i1, -2, 5896);
+  _lua_pushinteger(i1, (HEAP32[i10 + 20 >> 2] | 0) + 1900 | 0);
+  _lua_setfield(i1, -2, 5904);
+  _lua_pushinteger(i1, (HEAP32[i10 + 24 >> 2] | 0) + 1 | 0);
+  _lua_setfield(i1, -2, 6080);
+  _lua_pushinteger(i1, (HEAP32[i10 + 28 >> 2] | 0) + 1 | 0);
+  _lua_setfield(i1, -2, 6088);
+  i3 = HEAP32[i10 + 32 >> 2] | 0;
+  if ((i3 | 0) < 0) {
+   STACKTOP = i2;
+   return 1;
+  }
+  _lua_pushboolean(i1, i3);
+  _lua_setfield(i1, -2, 5912);
+  STACKTOP = i2;
+  return 1;
+ }
+ HEAP8[i6] = 37;
+ _luaL_buffinit(i1, i3);
+ i11 = i3 + 8 | 0;
+ i9 = i3 + 4 | 0;
+ i8 = i6 + 1 | 0;
+ i7 = i6 + 2 | 0;
+ while (1) {
+  i14 = HEAP8[i12] | 0;
+  if (i14 << 24 >> 24 == 0) {
+   break;
+  } else if (!(i14 << 24 >> 24 == 37)) {
+   i13 = HEAP32[i11 >> 2] | 0;
+   if (!(i13 >>> 0 < (HEAP32[i9 >> 2] | 0) >>> 0)) {
+    _luaL_prepbuffsize(i3, 1) | 0;
+    i13 = HEAP32[i11 >> 2] | 0;
+    i14 = HEAP8[i12] | 0;
+   }
+   HEAP32[i11 >> 2] = i13 + 1;
+   HEAP8[(HEAP32[i3 >> 2] | 0) + i13 | 0] = i14;
+   i12 = i12 + 1 | 0;
+   continue;
+  }
+  i13 = i12 + 1 | 0;
+  i12 = i12 + 2 | 0;
+  i14 = HEAP8[i13] | 0;
+  if (!(i14 << 24 >> 24 == 0) ? (_memchr(6096, i14 << 24 >> 24, 23) | 0) != 0 : 0) {
+   HEAP8[i8] = i14;
+   HEAP8[i7] = 0;
+  } else {
+   HEAP32[i4 >> 2] = i13;
+   _luaL_argerror(i1, 1, _lua_pushfstring(i1, 6120, i4) | 0) | 0;
+   i12 = i13;
+  }
+  _luaL_addlstring(i3, i5, _strftime(i5 | 0, 200, i6 | 0, i10 | 0) | 0);
+ }
+ _luaL_pushresult(i3);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaV_finishOp(i3) {
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i1 = STACKTOP;
+ i8 = HEAP32[i3 + 16 >> 2] | 0;
+ i7 = i8 + 24 | 0;
+ i4 = HEAP32[i7 >> 2] | 0;
+ i5 = i8 + 28 | 0;
+ i2 = HEAP32[(HEAP32[i5 >> 2] | 0) + -4 >> 2] | 0;
+ i6 = i2 & 63;
+ switch (i6 | 0) {
+ case 34:
+  {
+   HEAP32[i3 + 8 >> 2] = HEAP32[i8 + 4 >> 2];
+   STACKTOP = i1;
+   return;
+  }
+ case 24:
+ case 25:
+ case 26:
+  {
+   i7 = i3 + 8 | 0;
+   i8 = HEAP32[i7 >> 2] | 0;
+   i9 = HEAP32[i8 + -8 >> 2] | 0;
+   if ((i9 | 0) != 0) {
+    if ((i9 | 0) == 1) {
+     i9 = (HEAP32[i8 + -16 >> 2] | 0) == 0;
+    } else {
+     i9 = 0;
+    }
+   } else {
+    i9 = 1;
+   }
+   i9 = i9 & 1;
+   i10 = i9 ^ 1;
+   HEAP32[i7 >> 2] = i8 + -16;
+   if ((i6 | 0) == 26) {
+    i8 = (HEAP32[(_luaT_gettmbyobj(i3, i4 + (i2 >>> 23 << 4) | 0, 14) | 0) + 8 >> 2] | 0) == 0;
+    i10 = i8 ? i9 : i10;
+   }
+   if ((i10 | 0) == (i2 >>> 6 & 255 | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 4;
+   STACKTOP = i1;
+   return;
+  }
+ case 22:
+  {
+   i5 = i3 + 8 | 0;
+   i10 = HEAP32[i5 >> 2] | 0;
+   i6 = i10 + -32 | 0;
+   i4 = i6 - (i4 + (i2 >>> 23 << 4)) | 0;
+   i12 = i10 + -16 | 0;
+   i11 = HEAP32[i12 + 4 >> 2] | 0;
+   i9 = i10 + -48 | 0;
+   HEAP32[i9 >> 2] = HEAP32[i12 >> 2];
+   HEAP32[i9 + 4 >> 2] = i11;
+   HEAP32[i10 + -40 >> 2] = HEAP32[i10 + -8 >> 2];
+   if ((i4 | 0) > 16) {
+    HEAP32[i5 >> 2] = i6;
+    _luaV_concat(i3, i4 >> 4);
+   }
+   i10 = HEAP32[i5 >> 2] | 0;
+   i11 = HEAP32[i7 >> 2] | 0;
+   i12 = i2 >>> 6 & 255;
+   i6 = i10 + -16 | 0;
+   i7 = HEAP32[i6 + 4 >> 2] | 0;
+   i9 = i11 + (i12 << 4) | 0;
+   HEAP32[i9 >> 2] = HEAP32[i6 >> 2];
+   HEAP32[i9 + 4 >> 2] = i7;
+   HEAP32[i11 + (i12 << 4) + 8 >> 2] = HEAP32[i10 + -8 >> 2];
+   HEAP32[i5 >> 2] = HEAP32[i8 + 4 >> 2];
+   STACKTOP = i1;
+   return;
+  }
+ case 12:
+ case 7:
+ case 6:
+ case 21:
+ case 19:
+ case 18:
+ case 17:
+ case 16:
+ case 15:
+ case 14:
+ case 13:
+  {
+   i12 = i3 + 8 | 0;
+   i11 = HEAP32[i12 >> 2] | 0;
+   i8 = i11 + -16 | 0;
+   HEAP32[i12 >> 2] = i8;
+   i12 = i2 >>> 6 & 255;
+   i9 = HEAP32[i8 + 4 >> 2] | 0;
+   i10 = i4 + (i12 << 4) | 0;
+   HEAP32[i10 >> 2] = HEAP32[i8 >> 2];
+   HEAP32[i10 + 4 >> 2] = i9;
+   HEAP32[i4 + (i12 << 4) + 8 >> 2] = HEAP32[i11 + -8 >> 2];
+   STACKTOP = i1;
+   return;
+  }
+ case 29:
+  {
+   if ((i2 & 8372224 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[i3 + 8 >> 2] = HEAP32[i8 + 4 >> 2];
+   STACKTOP = i1;
+   return;
+  }
+ default:
+  {
+   STACKTOP = i1;
+   return;
+  }
+ }
+}
+function _auxsort(i2, i4, i5) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ if ((i4 | 0) >= (i5 | 0)) {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  _lua_rawgeti(i2, 1, i4);
+  _lua_rawgeti(i2, 1, i5);
+  if ((_sort_comp(i2, -1, -2) | 0) == 0) {
+   _lua_settop(i2, -3);
+  } else {
+   _lua_rawseti(i2, 1, i4);
+   _lua_rawseti(i2, 1, i5);
+  }
+  i6 = i5 - i4 | 0;
+  if ((i6 | 0) == 1) {
+   i2 = 24;
+   break;
+  }
+  i7 = (i5 + i4 | 0) / 2 | 0;
+  _lua_rawgeti(i2, 1, i7);
+  _lua_rawgeti(i2, 1, i4);
+  do {
+   if ((_sort_comp(i2, -2, -1) | 0) == 0) {
+    _lua_settop(i2, -2);
+    _lua_rawgeti(i2, 1, i5);
+    if ((_sort_comp(i2, -1, -2) | 0) == 0) {
+     _lua_settop(i2, -3);
+     break;
+    } else {
+     _lua_rawseti(i2, 1, i7);
+     _lua_rawseti(i2, 1, i5);
+     break;
+    }
+   } else {
+    _lua_rawseti(i2, 1, i7);
+    _lua_rawseti(i2, 1, i4);
+   }
+  } while (0);
+  if ((i6 | 0) == 2) {
+   i2 = 24;
+   break;
+  }
+  _lua_rawgeti(i2, 1, i7);
+  _lua_pushvalue(i2, -1);
+  i6 = i5 + -1 | 0;
+  _lua_rawgeti(i2, 1, i6);
+  _lua_rawseti(i2, 1, i7);
+  _lua_rawseti(i2, 1, i6);
+  i7 = i4;
+  i9 = i6;
+  while (1) {
+   i8 = i7 + 1 | 0;
+   _lua_rawgeti(i2, 1, i8);
+   if ((_sort_comp(i2, -1, -2) | 0) != 0) {
+    i7 = i8;
+    while (1) {
+     if ((i7 | 0) >= (i5 | 0)) {
+      _luaL_error(i2, 8216, i3) | 0;
+     }
+     _lua_settop(i2, -2);
+     i8 = i7 + 1 | 0;
+     _lua_rawgeti(i2, 1, i8);
+     if ((_sort_comp(i2, -1, -2) | 0) == 0) {
+      break;
+     } else {
+      i7 = i8;
+     }
+    }
+   }
+   i10 = i9 + -1 | 0;
+   _lua_rawgeti(i2, 1, i10);
+   if ((_sort_comp(i2, -3, -1) | 0) != 0) {
+    i9 = i10;
+    while (1) {
+     if ((i9 | 0) <= (i4 | 0)) {
+      _luaL_error(i2, 8216, i3) | 0;
+     }
+     _lua_settop(i2, -2);
+     i10 = i9 + -1 | 0;
+     _lua_rawgeti(i2, 1, i10);
+     if ((_sort_comp(i2, -3, -1) | 0) == 0) {
+      break;
+     } else {
+      i9 = i10;
+     }
+    }
+   }
+   if ((i9 | 0) <= (i8 | 0)) {
+    break;
+   }
+   _lua_rawseti(i2, 1, i8);
+   _lua_rawseti(i2, 1, i10);
+   i7 = i8;
+   i9 = i10;
+  }
+  _lua_settop(i2, -4);
+  _lua_rawgeti(i2, 1, i6);
+  _lua_rawgeti(i2, 1, i8);
+  _lua_rawseti(i2, 1, i6);
+  _lua_rawseti(i2, 1, i8);
+  i8 = (i8 - i4 | 0) < (i5 - i8 | 0);
+  i9 = i7 + 2 | 0;
+  i10 = i8 ? i9 : i4;
+  i6 = i8 ? i5 : i7;
+  _auxsort(i2, i8 ? i4 : i9, i8 ? i7 : i5);
+  if ((i10 | 0) < (i6 | 0)) {
+   i4 = i10;
+   i5 = i6;
+  } else {
+   i2 = 24;
+   break;
+  }
+ }
+ if ((i2 | 0) == 24) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function _skip_sep(i3) {
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ i2 = HEAP32[i3 >> 2] | 0;
+ i4 = i3 + 60 | 0;
+ i10 = HEAP32[i4 >> 2] | 0;
+ i8 = i10 + 4 | 0;
+ i11 = HEAP32[i8 >> 2] | 0;
+ i7 = i10 + 8 | 0;
+ i5 = HEAP32[i7 >> 2] | 0;
+ do {
+  if ((i11 + 1 | 0) >>> 0 > i5 >>> 0) {
+   if (i5 >>> 0 > 2147483645) {
+    _lexerror(i3, 12368, 0);
+   }
+   i12 = i5 << 1;
+   i11 = HEAP32[i3 + 52 >> 2] | 0;
+   if ((i12 | 0) == -2) {
+    _luaM_toobig(i11);
+   } else {
+    i9 = _luaM_realloc_(i11, HEAP32[i10 >> 2] | 0, i5, i12) | 0;
+    HEAP32[i10 >> 2] = i9;
+    HEAP32[i7 >> 2] = i12;
+    i6 = HEAP32[i8 >> 2] | 0;
+    break;
+   }
+  } else {
+   i6 = i11;
+   i9 = HEAP32[i10 >> 2] | 0;
+  }
+ } while (0);
+ HEAP32[i8 >> 2] = i6 + 1;
+ HEAP8[i9 + i6 | 0] = i2;
+ i5 = i3 + 56 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ i13 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i6 >> 2] = i13 + -1;
+ if ((i13 | 0) == 0) {
+  i6 = _luaZ_fill(i6) | 0;
+ } else {
+  i13 = i6 + 4 | 0;
+  i6 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i13 >> 2] = i6 + 1;
+  i6 = HEAPU8[i6] | 0;
+ }
+ HEAP32[i3 >> 2] = i6;
+ if ((i6 | 0) != 61) {
+  i12 = i6;
+  i13 = 0;
+  i12 = (i12 | 0) != (i2 | 0);
+  i12 = i12 << 31 >> 31;
+  i13 = i12 ^ i13;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ i6 = i3 + 52 | 0;
+ i7 = 0;
+ while (1) {
+  i9 = HEAP32[i4 >> 2] | 0;
+  i8 = i9 + 4 | 0;
+  i10 = HEAP32[i8 >> 2] | 0;
+  i11 = i9 + 8 | 0;
+  i12 = HEAP32[i11 >> 2] | 0;
+  if ((i10 + 1 | 0) >>> 0 > i12 >>> 0) {
+   if (i12 >>> 0 > 2147483645) {
+    i4 = 16;
+    break;
+   }
+   i13 = i12 << 1;
+   i10 = HEAP32[i6 >> 2] | 0;
+   if ((i13 | 0) == -2) {
+    i4 = 18;
+    break;
+   }
+   i12 = _luaM_realloc_(i10, HEAP32[i9 >> 2] | 0, i12, i13) | 0;
+   HEAP32[i9 >> 2] = i12;
+   HEAP32[i11 >> 2] = i13;
+   i10 = HEAP32[i8 >> 2] | 0;
+   i9 = i12;
+  } else {
+   i9 = HEAP32[i9 >> 2] | 0;
+  }
+  HEAP32[i8 >> 2] = i10 + 1;
+  HEAP8[i9 + i10 | 0] = 61;
+  i8 = HEAP32[i5 >> 2] | 0;
+  i13 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i13 + -1;
+  if ((i13 | 0) == 0) {
+   i8 = _luaZ_fill(i8) | 0;
+  } else {
+   i13 = i8 + 4 | 0;
+   i8 = HEAP32[i13 >> 2] | 0;
+   HEAP32[i13 >> 2] = i8 + 1;
+   i8 = HEAPU8[i8] | 0;
+  }
+  HEAP32[i3 >> 2] = i8;
+  i7 = i7 + 1 | 0;
+  if ((i8 | 0) != 61) {
+   i4 = 24;
+   break;
+  }
+ }
+ if ((i4 | 0) == 16) {
+  _lexerror(i3, 12368, 0);
+ } else if ((i4 | 0) == 18) {
+  _luaM_toobig(i10);
+ } else if ((i4 | 0) == 24) {
+  i13 = (i8 | 0) != (i2 | 0);
+  i13 = i13 << 31 >> 31;
+  i13 = i13 ^ i7;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ return 0;
+}
+function _luaV_arith(i8, i2, i3, i5, i4) {
+ i8 = i8 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i6 = 0, i7 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, d14 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i9 = i1 + 24 | 0;
+ i13 = i1 + 16 | 0;
+ i12 = i1;
+ i6 = i3 + 8 | 0;
+ i11 = HEAP32[i6 >> 2] | 0;
+ if ((i11 | 0) != 3) {
+  if ((i11 & 15 | 0) == 4 ? (i11 = HEAP32[i3 >> 2] | 0, (_luaO_str2d(i11 + 16 | 0, HEAP32[i11 + 12 >> 2] | 0, i13) | 0) != 0) : 0) {
+   HEAPF64[i12 >> 3] = +HEAPF64[i13 >> 3];
+   HEAP32[i12 + 8 >> 2] = 3;
+   i10 = 5;
+  }
+ } else {
+  i12 = i3;
+  i10 = 5;
+ }
+ do {
+  if ((i10 | 0) == 5) {
+   i10 = HEAP32[i5 + 8 >> 2] | 0;
+   if ((i10 | 0) == 3) {
+    if ((i5 | 0) == 0) {
+     break;
+    }
+    d14 = +HEAPF64[i5 >> 3];
+   } else {
+    if ((i10 & 15 | 0) != 4) {
+     break;
+    }
+    i13 = HEAP32[i5 >> 2] | 0;
+    if ((_luaO_str2d(i13 + 16 | 0, HEAP32[i13 + 12 >> 2] | 0, i9) | 0) == 0) {
+     break;
+    }
+    d14 = +HEAPF64[i9 >> 3];
+   }
+   HEAPF64[i2 >> 3] = +_luaO_arith(i4 + -6 | 0, +HEAPF64[i12 >> 3], d14);
+   HEAP32[i2 + 8 >> 2] = 3;
+   STACKTOP = i1;
+   return;
+  }
+ } while (0);
+ i9 = _luaT_gettmbyobj(i8, i3, i4) | 0;
+ if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+  i4 = _luaT_gettmbyobj(i8, i5, i4) | 0;
+  if ((HEAP32[i4 + 8 >> 2] | 0) == 0) {
+   _luaG_aritherror(i8, i3, i5);
+  } else {
+   i7 = i4;
+  }
+ } else {
+  i7 = i9;
+ }
+ i12 = i8 + 28 | 0;
+ i13 = i2 - (HEAP32[i12 >> 2] | 0) | 0;
+ i9 = i8 + 8 | 0;
+ i11 = HEAP32[i9 >> 2] | 0;
+ HEAP32[i9 >> 2] = i11 + 16;
+ i2 = i7;
+ i10 = HEAP32[i2 + 4 >> 2] | 0;
+ i4 = i11;
+ HEAP32[i4 >> 2] = HEAP32[i2 >> 2];
+ HEAP32[i4 + 4 >> 2] = i10;
+ HEAP32[i11 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+ i11 = HEAP32[i9 >> 2] | 0;
+ HEAP32[i9 >> 2] = i11 + 16;
+ i4 = i3;
+ i10 = HEAP32[i4 + 4 >> 2] | 0;
+ i7 = i11;
+ HEAP32[i7 >> 2] = HEAP32[i4 >> 2];
+ HEAP32[i7 + 4 >> 2] = i10;
+ HEAP32[i11 + 8 >> 2] = HEAP32[i6 >> 2];
+ i11 = HEAP32[i9 >> 2] | 0;
+ HEAP32[i9 >> 2] = i11 + 16;
+ i6 = i5;
+ i7 = HEAP32[i6 + 4 >> 2] | 0;
+ i10 = i11;
+ HEAP32[i10 >> 2] = HEAP32[i6 >> 2];
+ HEAP32[i10 + 4 >> 2] = i7;
+ HEAP32[i11 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+ _luaD_call(i8, (HEAP32[i9 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i8 + 16 >> 2] | 0) + 18 | 0] & 1);
+ i12 = HEAP32[i12 >> 2] | 0;
+ i11 = HEAP32[i9 >> 2] | 0;
+ i8 = i11 + -16 | 0;
+ HEAP32[i9 >> 2] = i8;
+ i9 = HEAP32[i8 + 4 >> 2] | 0;
+ i10 = i12 + i13 | 0;
+ HEAP32[i10 >> 2] = HEAP32[i8 >> 2];
+ HEAP32[i10 + 4 >> 2] = i9;
+ HEAP32[i12 + (i13 + 8) >> 2] = HEAP32[i11 + -8 >> 2];
+ STACKTOP = i1;
+ return;
+}
+function _new_localvar(i1, i8) {
+ i1 = i1 | 0;
+ i8 = i8 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i3;
+ i5 = HEAP32[i1 + 48 >> 2] | 0;
+ i2 = HEAP32[i1 + 64 >> 2] | 0;
+ i7 = HEAP32[i5 >> 2] | 0;
+ i10 = i7 + 60 | 0;
+ i11 = HEAP32[i10 >> 2] | 0;
+ i6 = i5 + 44 | 0;
+ if ((HEAP16[i6 >> 1] | 0) < (i11 | 0)) {
+  i9 = i7 + 24 | 0;
+  i10 = i11;
+ } else {
+  i9 = i7 + 24 | 0;
+  HEAP32[i9 >> 2] = _luaM_growaux_(HEAP32[i1 + 52 >> 2] | 0, HEAP32[i9 >> 2] | 0, i10, 12, 32767, 6496) | 0;
+  i10 = HEAP32[i10 >> 2] | 0;
+ }
+ if ((i11 | 0) < (i10 | 0)) {
+  i12 = i11;
+  while (1) {
+   i11 = i12 + 1 | 0;
+   HEAP32[(HEAP32[i9 >> 2] | 0) + (i12 * 12 | 0) >> 2] = 0;
+   if ((i11 | 0) == (i10 | 0)) {
+    break;
+   } else {
+    i12 = i11;
+   }
+  }
+ }
+ i10 = HEAP16[i6 >> 1] | 0;
+ HEAP32[(HEAP32[i9 >> 2] | 0) + ((i10 << 16 >> 16) * 12 | 0) >> 2] = i8;
+ if (!((HEAP8[i8 + 5 | 0] & 3) == 0) ? !((HEAP8[i7 + 5 | 0] & 4) == 0) : 0) {
+  _luaC_barrier_(HEAP32[i1 + 52 >> 2] | 0, i7, i8);
+  i7 = HEAP16[i6 >> 1] | 0;
+ } else {
+  i7 = i10;
+ }
+ HEAP16[i6 >> 1] = i7 + 1 << 16 >> 16;
+ i6 = i2 + 4 | 0;
+ i8 = HEAP32[i6 >> 2] | 0;
+ if ((i8 + 1 - (HEAP32[i5 + 40 >> 2] | 0) | 0) > 200) {
+  i10 = i5 + 12 | 0;
+  i9 = HEAP32[(HEAP32[i10 >> 2] | 0) + 52 >> 2] | 0;
+  i5 = HEAP32[(HEAP32[i5 >> 2] | 0) + 64 >> 2] | 0;
+  if ((i5 | 0) == 0) {
+   i11 = 6552;
+   HEAP32[i4 >> 2] = 6496;
+   i12 = i4 + 4 | 0;
+   HEAP32[i12 >> 2] = 200;
+   i12 = i4 + 8 | 0;
+   HEAP32[i12 >> 2] = i11;
+   i12 = _luaO_pushfstring(i9, 6592, i4) | 0;
+   i11 = HEAP32[i10 >> 2] | 0;
+   _luaX_syntaxerror(i11, i12);
+  }
+  HEAP32[i4 >> 2] = i5;
+  i11 = _luaO_pushfstring(i9, 6568, i4) | 0;
+  HEAP32[i4 >> 2] = 6496;
+  i12 = i4 + 4 | 0;
+  HEAP32[i12 >> 2] = 200;
+  i12 = i4 + 8 | 0;
+  HEAP32[i12 >> 2] = i11;
+  i12 = _luaO_pushfstring(i9, 6592, i4) | 0;
+  i11 = HEAP32[i10 >> 2] | 0;
+  _luaX_syntaxerror(i11, i12);
+ }
+ i4 = i2 + 8 | 0;
+ if ((i8 + 2 | 0) > (HEAP32[i4 >> 2] | 0)) {
+  i11 = _luaM_growaux_(HEAP32[i1 + 52 >> 2] | 0, HEAP32[i2 >> 2] | 0, i4, 2, 2147483645, 6496) | 0;
+  HEAP32[i2 >> 2] = i11;
+  i12 = HEAP32[i6 >> 2] | 0;
+  i10 = i12 + 1 | 0;
+  HEAP32[i6 >> 2] = i10;
+  i12 = i11 + (i12 << 1) | 0;
+  HEAP16[i12 >> 1] = i7;
+  STACKTOP = i3;
+  return;
+ } else {
+  i12 = i8;
+  i11 = HEAP32[i2 >> 2] | 0;
+  i10 = i12 + 1 | 0;
+  HEAP32[i6 >> 2] = i10;
+  i12 = i11 + (i12 << 1) | 0;
+  HEAP16[i12 >> 1] = i7;
+  STACKTOP = i3;
+  return;
+ }
+}
+function _luaC_fullgc(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i2 = STACKTOP;
+ i4 = i1 + 12 | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ i6 = i3 + 62 | 0;
+ i8 = HEAP8[i6] | 0;
+ i5 = (i5 | 0) != 0;
+ if (!i5) {
+  HEAP8[i6] = 0;
+  i9 = (HEAP32[i4 >> 2] | 0) + 104 | 0;
+  i10 = HEAP32[i9 >> 2] | 0;
+  if ((i10 | 0) != 0) {
+   do {
+    i11 = i10 + 5 | 0;
+    HEAP8[i11] = HEAP8[i11] & 191;
+    _GCTM(i1, 1);
+    i10 = HEAP32[i9 >> 2] | 0;
+   } while ((i10 | 0) != 0);
+   if ((HEAP8[i6] | 0) == 2) {
+    i9 = 7;
+   } else {
+    i9 = 6;
+   }
+  } else {
+   i9 = 6;
+  }
+ } else {
+  HEAP8[i6] = 1;
+  i9 = 6;
+ }
+ if ((i9 | 0) == 6 ? (HEAPU8[i3 + 61 | 0] | 0) < 2 : 0) {
+  i9 = 7;
+ }
+ if ((i9 | 0) == 7) {
+  i9 = HEAP32[i4 >> 2] | 0;
+  HEAP8[i9 + 61 | 0] = 2;
+  HEAP32[i9 + 64 >> 2] = 0;
+  i10 = i9 + 72 | 0;
+  do {
+   i11 = _sweeplist(i1, i10, 1) | 0;
+  } while ((i11 | 0) == (i10 | 0));
+  HEAP32[i9 + 80 >> 2] = i11;
+  i11 = i9 + 68 | 0;
+  do {
+   i10 = _sweeplist(i1, i11, 1) | 0;
+  } while ((i10 | 0) == (i11 | 0));
+  HEAP32[i9 + 76 >> 2] = i10;
+ }
+ i11 = HEAP32[i4 >> 2] | 0;
+ i9 = i11 + 61 | 0;
+ if ((HEAP8[i9] | 0) == 5) {
+  i9 = 5;
+ } else {
+  do {
+   _singlestep(i1) | 0;
+  } while ((HEAP8[i9] | 0) != 5);
+  i9 = HEAP32[i4 >> 2] | 0;
+  i11 = i9;
+  i9 = HEAP8[i9 + 61 | 0] | 0;
+ }
+ i10 = i11 + 61 | 0;
+ if ((1 << (i9 & 255) & -33 | 0) == 0) {
+  do {
+   _singlestep(i1) | 0;
+  } while ((1 << HEAPU8[i10] & -33 | 0) == 0);
+  i9 = HEAP32[i4 >> 2] | 0;
+  i11 = i9;
+  i9 = HEAP8[i9 + 61 | 0] | 0;
+ }
+ i10 = i11 + 61 | 0;
+ if (!(i9 << 24 >> 24 == 5)) {
+  do {
+   _singlestep(i1) | 0;
+  } while ((HEAP8[i10] | 0) != 5);
+ }
+ if (i8 << 24 >> 24 == 2 ? (i7 = (HEAP32[i4 >> 2] | 0) + 61 | 0, (HEAP8[i7] | 0) != 0) : 0) {
+  do {
+   _singlestep(i1) | 0;
+  } while ((HEAP8[i7] | 0) != 0);
+ }
+ HEAP8[i6] = i8;
+ i6 = HEAP32[i3 + 8 >> 2] | 0;
+ i7 = HEAP32[i3 + 12 >> 2] | 0;
+ i8 = (i7 + i6 | 0) / 100 | 0;
+ i9 = HEAP32[i3 + 156 >> 2] | 0;
+ if ((i9 | 0) < (2147483644 / (i8 | 0) | 0 | 0)) {
+  i8 = Math_imul(i9, i8) | 0;
+ } else {
+  i8 = 2147483644;
+ }
+ _luaE_setdebt(i3, i6 - i8 + i7 | 0);
+ if (i5) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = (HEAP32[i4 >> 2] | 0) + 104 | 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ if ((i4 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ do {
+  i11 = i4 + 5 | 0;
+  HEAP8[i11] = HEAP8[i11] & 191;
+  _GCTM(i1, 1);
+  i4 = HEAP32[i3 >> 2] | 0;
+ } while ((i4 | 0) != 0);
+ STACKTOP = i2;
+ return;
+}
+function _scanexp(i3, i6) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0;
+ i1 = STACKTOP;
+ i2 = i3 + 4 | 0;
+ i5 = HEAP32[i2 >> 2] | 0;
+ i4 = i3 + 100 | 0;
+ if (i5 >>> 0 < (HEAP32[i4 >> 2] | 0) >>> 0) {
+  HEAP32[i2 >> 2] = i5 + 1;
+  i8 = HEAPU8[i5] | 0;
+ } else {
+  i8 = ___shgetc(i3) | 0;
+ }
+ if ((i8 | 0) == 43 | (i8 | 0) == 45) {
+  i5 = (i8 | 0) == 45 | 0;
+  i7 = HEAP32[i2 >> 2] | 0;
+  if (i7 >>> 0 < (HEAP32[i4 >> 2] | 0) >>> 0) {
+   HEAP32[i2 >> 2] = i7 + 1;
+   i8 = HEAPU8[i7] | 0;
+  } else {
+   i8 = ___shgetc(i3) | 0;
+  }
+  if (!((i8 + -48 | 0) >>> 0 < 10 | (i6 | 0) == 0) ? (HEAP32[i4 >> 2] | 0) != 0 : 0) {
+   HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + -1;
+  }
+ } else {
+  i5 = 0;
+ }
+ if ((i8 + -48 | 0) >>> 0 > 9) {
+  if ((HEAP32[i4 >> 2] | 0) == 0) {
+   i7 = -2147483648;
+   i8 = 0;
+   tempRet0 = i7;
+   STACKTOP = i1;
+   return i8 | 0;
+  }
+  HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + -1;
+  i7 = -2147483648;
+  i8 = 0;
+  tempRet0 = i7;
+  STACKTOP = i1;
+  return i8 | 0;
+ } else {
+  i6 = 0;
+ }
+ while (1) {
+  i6 = i8 + -48 + i6 | 0;
+  i7 = HEAP32[i2 >> 2] | 0;
+  if (i7 >>> 0 < (HEAP32[i4 >> 2] | 0) >>> 0) {
+   HEAP32[i2 >> 2] = i7 + 1;
+   i8 = HEAPU8[i7] | 0;
+  } else {
+   i8 = ___shgetc(i3) | 0;
+  }
+  if (!((i8 + -48 | 0) >>> 0 < 10 & (i6 | 0) < 214748364)) {
+   break;
+  }
+  i6 = i6 * 10 | 0;
+ }
+ i7 = ((i6 | 0) < 0) << 31 >> 31;
+ if ((i8 + -48 | 0) >>> 0 < 10) {
+  do {
+   i7 = ___muldi3(i6 | 0, i7 | 0, 10, 0) | 0;
+   i6 = tempRet0;
+   i8 = _i64Add(i8 | 0, ((i8 | 0) < 0) << 31 >> 31 | 0, -48, -1) | 0;
+   i6 = _i64Add(i8 | 0, tempRet0 | 0, i7 | 0, i6 | 0) | 0;
+   i7 = tempRet0;
+   i8 = HEAP32[i2 >> 2] | 0;
+   if (i8 >>> 0 < (HEAP32[i4 >> 2] | 0) >>> 0) {
+    HEAP32[i2 >> 2] = i8 + 1;
+    i8 = HEAPU8[i8] | 0;
+   } else {
+    i8 = ___shgetc(i3) | 0;
+   }
+  } while ((i8 + -48 | 0) >>> 0 < 10 & ((i7 | 0) < 21474836 | (i7 | 0) == 21474836 & i6 >>> 0 < 2061584302));
+ }
+ if ((i8 + -48 | 0) >>> 0 < 10) {
+  do {
+   i8 = HEAP32[i2 >> 2] | 0;
+   if (i8 >>> 0 < (HEAP32[i4 >> 2] | 0) >>> 0) {
+    HEAP32[i2 >> 2] = i8 + 1;
+    i8 = HEAPU8[i8] | 0;
+   } else {
+    i8 = ___shgetc(i3) | 0;
+   }
+  } while ((i8 + -48 | 0) >>> 0 < 10);
+ }
+ if ((HEAP32[i4 >> 2] | 0) != 0) {
+  HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + -1;
+ }
+ i3 = (i5 | 0) != 0;
+ i2 = _i64Subtract(0, 0, i6 | 0, i7 | 0) | 0;
+ i4 = i3 ? tempRet0 : i7;
+ i8 = i3 ? i2 : i6;
+ tempRet0 = i4;
+ STACKTOP = i1;
+ return i8 | 0;
+}
+function _sweeplist(i3, i8, i9) {
+ i3 = i3 | 0;
+ i8 = i8 | 0;
+ i9 = i9 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i1 = STACKTOP;
+ i5 = i3 + 12 | 0;
+ i7 = HEAP32[i5 >> 2] | 0;
+ i6 = HEAPU8[i7 + 60 | 0] | 0;
+ i2 = i6 ^ 3;
+ i7 = (HEAP8[i7 + 62 | 0] | 0) == 2;
+ i4 = i7 ? 255 : 184;
+ i6 = i7 ? 64 : i6 & 3;
+ i7 = i7 ? 64 : 0;
+ i10 = HEAP32[i8 >> 2] | 0;
+ L1 : do {
+  if ((i10 | 0) == 0) {
+   i10 = 0;
+  } else {
+   i11 = i9;
+   L2 : while (1) {
+    i9 = i11 + -1 | 0;
+    if ((i11 | 0) == 0) {
+     break L1;
+    }
+    i11 = i10 + 5 | 0;
+    i12 = HEAPU8[i11] | 0;
+    L5 : do {
+     if (((i12 ^ 3) & i2 | 0) == 0) {
+      HEAP32[i8 >> 2] = HEAP32[i10 >> 2];
+      switch (HEAPU8[i10 + 4 | 0] | 0) {
+      case 4:
+       {
+        i12 = (HEAP32[i5 >> 2] | 0) + 28 | 0;
+        HEAP32[i12 >> 2] = (HEAP32[i12 >> 2] | 0) + -1;
+        break;
+       }
+      case 38:
+       {
+        _luaM_realloc_(i3, i10, (HEAPU8[i10 + 6 | 0] << 4) + 16 | 0, 0) | 0;
+        break L5;
+       }
+      case 6:
+       {
+        _luaM_realloc_(i3, i10, (HEAPU8[i10 + 6 | 0] << 2) + 16 | 0, 0) | 0;
+        break L5;
+       }
+      case 20:
+       {
+        break;
+       }
+      case 5:
+       {
+        _luaH_free(i3, i10);
+        break L5;
+       }
+      case 10:
+       {
+        _luaF_freeupval(i3, i10);
+        break L5;
+       }
+      case 8:
+       {
+        _luaE_freethread(i3, i10);
+        break L5;
+       }
+      case 9:
+       {
+        _luaF_freeproto(i3, i10);
+        break L5;
+       }
+      case 7:
+       {
+        _luaM_realloc_(i3, i10, (HEAP32[i10 + 16 >> 2] | 0) + 24 | 0, 0) | 0;
+        break L5;
+       }
+      default:
+       {
+        break L5;
+       }
+      }
+      _luaM_realloc_(i3, i10, (HEAP32[i10 + 12 >> 2] | 0) + 17 | 0, 0) | 0;
+     } else {
+      if ((i12 & i7 | 0) != 0) {
+       i2 = 0;
+       break L2;
+      }
+      if (((HEAP8[i10 + 4 | 0] | 0) == 8 ? (HEAP32[i10 + 28 >> 2] | 0) != 0 : 0) ? (_sweeplist(i3, i10 + 56 | 0, -3) | 0, _luaE_freeCI(i10), (HEAP8[(HEAP32[i5 >> 2] | 0) + 62 | 0] | 0) != 1) : 0) {
+       _luaD_shrinkstack(i10);
+      }
+      HEAP8[i11] = i12 & i4 | i6;
+      i8 = i10;
+     }
+    } while (0);
+    i10 = HEAP32[i8 >> 2] | 0;
+    if ((i10 | 0) == 0) {
+     i10 = 0;
+     break L1;
+    } else {
+     i11 = i9;
+    }
+   }
+   STACKTOP = i1;
+   return i2 | 0;
+  }
+ } while (0);
+ i12 = (i10 | 0) == 0 ? 0 : i8;
+ STACKTOP = i1;
+ return i12 | 0;
+}
+function _resume(i1, i6) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i2 = STACKTOP;
+ i3 = i1 + 16 | 0;
+ i5 = HEAP32[i3 >> 2] | 0;
+ if ((HEAPU16[i1 + 38 >> 1] | 0) > 199) {
+  _resume_error(i1, 2240, i6);
+ }
+ i4 = i1 + 6 | 0;
+ i7 = HEAP8[i4] | 0;
+ if (i7 << 24 >> 24 == 0) {
+  if ((i5 | 0) != (i1 + 72 | 0)) {
+   _resume_error(i1, 2448, i6);
+  }
+  if ((_luaD_precall(i1, i6 + -16 | 0, -1) | 0) != 0) {
+   STACKTOP = i2;
+   return;
+  }
+  _luaV_execute(i1);
+  STACKTOP = i2;
+  return;
+ } else if (i7 << 24 >> 24 == 1) {
+  HEAP8[i4] = 0;
+  i4 = i1 + 28 | 0;
+  HEAP32[i5 >> 2] = (HEAP32[i4 >> 2] | 0) + (HEAP32[i5 + 20 >> 2] | 0);
+  i8 = i5 + 18 | 0;
+  i7 = HEAP8[i8] | 0;
+  if ((i7 & 1) == 0) {
+   i9 = HEAP32[i5 + 28 >> 2] | 0;
+   if ((i9 | 0) != 0) {
+    HEAP8[i5 + 37 | 0] = 1;
+    HEAP8[i8] = i7 & 255 | 8;
+    i6 = FUNCTION_TABLE_ii[i9 & 255](i1) | 0;
+    i6 = (HEAP32[i1 + 8 >> 2] | 0) + (0 - i6 << 4) | 0;
+   }
+   i5 = HEAP32[i3 >> 2] | 0;
+   i7 = HEAPU8[i1 + 40 | 0] | 0;
+   if ((i7 & 6 | 0) == 0) {
+    i7 = i5 + 8 | 0;
+   } else {
+    if ((i7 & 2 | 0) != 0) {
+     i6 = i6 - (HEAP32[i4 >> 2] | 0) | 0;
+     _luaD_hook(i1, 1, -1);
+     i6 = (HEAP32[i4 >> 2] | 0) + i6 | 0;
+    }
+    i7 = i5 + 8 | 0;
+    HEAP32[i1 + 20 >> 2] = HEAP32[(HEAP32[i7 >> 2] | 0) + 28 >> 2];
+   }
+   i4 = HEAP32[i5 >> 2] | 0;
+   i5 = HEAP16[i5 + 16 >> 1] | 0;
+   HEAP32[i3 >> 2] = HEAP32[i7 >> 2];
+   i3 = i1 + 8 | 0;
+   L27 : do {
+    if (!(i5 << 16 >> 16 == 0)) {
+     i5 = i5 << 16 >> 16;
+     while (1) {
+      if (!(i6 >>> 0 < (HEAP32[i3 >> 2] | 0) >>> 0)) {
+       break;
+      }
+      i7 = i4 + 16 | 0;
+      i10 = i6;
+      i8 = HEAP32[i10 + 4 >> 2] | 0;
+      i9 = i4;
+      HEAP32[i9 >> 2] = HEAP32[i10 >> 2];
+      HEAP32[i9 + 4 >> 2] = i8;
+      HEAP32[i4 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+      i5 = i5 + -1 | 0;
+      if ((i5 | 0) == 0) {
+       i4 = i7;
+       break L27;
+      }
+      i6 = i6 + 16 | 0;
+      i4 = i7;
+     }
+     if ((i5 | 0) > 0) {
+      i7 = i5;
+      i6 = i4;
+      while (1) {
+       i7 = i7 + -1 | 0;
+       HEAP32[i6 + 8 >> 2] = 0;
+       if ((i7 | 0) <= 0) {
+        break;
+       } else {
+        i6 = i6 + 16 | 0;
+       }
+      }
+      i4 = i4 + (i5 << 4) | 0;
+     }
+    }
+   } while (0);
+   HEAP32[i3 >> 2] = i4;
+  } else {
+   _luaV_execute(i1);
+  }
+  _unroll(i1, 0);
+  STACKTOP = i2;
+  return;
+ } else {
+  _resume_error(i1, 2488, i6);
+ }
+}
+function _lua_setupvalue(i1, i5, i3) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i2 = STACKTOP;
+ i6 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i5 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i5 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i6 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i6 >> 2] | 0, (i5 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i4 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i6 >> 2] | 0) + (i5 << 4) | 0;
+   i5 = i4 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i4 = HEAP32[i5 + 8 >> 2] & 63;
+ do {
+  if ((i4 | 0) == 6) {
+   i5 = HEAP32[i5 >> 2] | 0;
+   i4 = HEAP32[i5 + 12 >> 2] | 0;
+   if ((i3 | 0) <= 0) {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+   if ((HEAP32[i4 + 40 >> 2] | 0) < (i3 | 0)) {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+   i6 = i3 + -1 | 0;
+   i3 = HEAP32[i5 + 16 + (i6 << 2) >> 2] | 0;
+   i5 = HEAP32[i3 + 8 >> 2] | 0;
+   i4 = HEAP32[(HEAP32[i4 + 28 >> 2] | 0) + (i6 << 3) >> 2] | 0;
+   if ((i4 | 0) == 0) {
+    i4 = 936;
+   } else {
+    i4 = i4 + 16 | 0;
+   }
+  } else if ((i4 | 0) == 38) {
+   i6 = HEAP32[i5 >> 2] | 0;
+   if ((i3 | 0) <= 0) {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+   if ((HEAPU8[i6 + 6 | 0] | 0 | 0) >= (i3 | 0)) {
+    i4 = 936;
+    i5 = i6 + (i3 + -1 << 4) + 16 | 0;
+    i3 = i6;
+    break;
+   } else {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+  } else {
+   i6 = 0;
+   STACKTOP = i2;
+   return i6 | 0;
+  }
+ } while (0);
+ i6 = i1 + 8 | 0;
+ i7 = HEAP32[i6 >> 2] | 0;
+ i10 = i7 + -16 | 0;
+ HEAP32[i6 >> 2] = i10;
+ i9 = HEAP32[i10 + 4 >> 2] | 0;
+ i8 = i5;
+ HEAP32[i8 >> 2] = HEAP32[i10 >> 2];
+ HEAP32[i8 + 4 >> 2] = i9;
+ HEAP32[i5 + 8 >> 2] = HEAP32[i7 + -8 >> 2];
+ i5 = HEAP32[i6 >> 2] | 0;
+ if ((HEAP32[i5 + 8 >> 2] & 64 | 0) == 0) {
+  i10 = i4;
+  STACKTOP = i2;
+  return i10 | 0;
+ }
+ i5 = HEAP32[i5 >> 2] | 0;
+ if ((HEAP8[i5 + 5 | 0] & 3) == 0) {
+  i10 = i4;
+  STACKTOP = i2;
+  return i10 | 0;
+ }
+ if ((HEAP8[i3 + 5 | 0] & 4) == 0) {
+  i10 = i4;
+  STACKTOP = i2;
+  return i10 | 0;
+ }
+ _luaC_barrier_(i1, i3, i5);
+ i10 = i4;
+ STACKTOP = i2;
+ return i10 | 0;
+}
+function _luaC_forcestep(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i1 = STACKTOP;
+ i3 = HEAP32[i2 + 12 >> 2] | 0;
+ do {
+  if ((HEAP8[i3 + 62 | 0] | 0) == 2) {
+   i4 = i3 + 20 | 0;
+   i6 = HEAP32[i4 >> 2] | 0;
+   do {
+    if ((i6 | 0) != 0) {
+     i5 = i3 + 61 | 0;
+     if ((HEAP8[i5] | 0) != 5) {
+      do {
+       _singlestep(i2) | 0;
+      } while ((HEAP8[i5] | 0) != 5);
+     }
+     HEAP8[i5] = 0;
+     i5 = HEAP32[i3 + 8 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     if ((i7 + i5 | 0) >>> 0 > (Math_imul(HEAP32[i3 + 160 >> 2] | 0, (i6 >>> 0) / 100 | 0) | 0) >>> 0) {
+      HEAP32[i4 >> 2] = 0;
+      break;
+     } else {
+      HEAP32[i4 >> 2] = i6;
+      break;
+     }
+    } else {
+     _luaC_fullgc(i2, 0);
+     i5 = HEAP32[i3 + 8 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     HEAP32[i4 >> 2] = i7 + i5;
+    }
+   } while (0);
+   i4 = i5 + i7 | 0;
+   i5 = (i4 | 0) / 100 | 0;
+   i6 = HEAP32[i3 + 156 >> 2] | 0;
+   if ((i6 | 0) < (2147483644 / (i5 | 0) | 0 | 0)) {
+    i5 = Math_imul(i6, i5) | 0;
+   } else {
+    i5 = 2147483644;
+   }
+   _luaE_setdebt(i3, i4 - i5 | 0);
+   i5 = i3 + 61 | 0;
+  } else {
+   i4 = i3 + 12 | 0;
+   i5 = HEAP32[i3 + 164 >> 2] | 0;
+   i7 = (i5 | 0) < 40 ? 40 : i5;
+   i5 = ((HEAP32[i4 >> 2] | 0) / 200 | 0) + 1 | 0;
+   if ((i5 | 0) < (2147483644 / (i7 | 0) | 0 | 0)) {
+    i8 = Math_imul(i5, i7) | 0;
+   } else {
+    i8 = 2147483644;
+   }
+   i5 = i3 + 61 | 0;
+   do {
+    i8 = i8 - (_singlestep(i2) | 0) | 0;
+    i9 = (HEAP8[i5] | 0) == 5;
+    if (!((i8 | 0) > -1600)) {
+     i6 = 17;
+     break;
+    }
+   } while (!i9);
+   if ((i6 | 0) == 17 ? !i9 : 0) {
+    _luaE_setdebt(i3, ((i8 | 0) / (i7 | 0) | 0) * 200 | 0);
+    break;
+   }
+   i6 = (HEAP32[i3 + 20 >> 2] | 0) / 100 | 0;
+   i7 = HEAP32[i3 + 156 >> 2] | 0;
+   if ((i7 | 0) < (2147483644 / (i6 | 0) | 0 | 0)) {
+    i6 = Math_imul(i7, i6) | 0;
+   } else {
+    i6 = 2147483644;
+   }
+   _luaE_setdebt(i3, (HEAP32[i3 + 8 >> 2] | 0) - i6 + (HEAP32[i4 >> 2] | 0) | 0);
+  }
+ } while (0);
+ i3 = i3 + 104 | 0;
+ if ((HEAP32[i3 >> 2] | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ } else {
+  i4 = 0;
+ }
+ while (1) {
+  if ((i4 | 0) >= 4 ? (HEAP8[i5] | 0) != 5 : 0) {
+   i6 = 26;
+   break;
+  }
+  _GCTM(i2, 1);
+  if ((HEAP32[i3 >> 2] | 0) == 0) {
+   i6 = 26;
+   break;
+  } else {
+   i4 = i4 + 1 | 0;
+  }
+ }
+ if ((i6 | 0) == 26) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function _luaL_loadfilex(i1, i9, i7) {
+ i1 = i1 | 0;
+ i9 = i9 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i10 = 0, i11 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i3 = i5;
+ i6 = i5 + 16 | 0;
+ i8 = i5 + 12 | 0;
+ i2 = (_lua_gettop(i1) | 0) + 1 | 0;
+ i4 = (i9 | 0) == 0;
+ if (!i4) {
+  HEAP32[i3 >> 2] = i9;
+  _lua_pushfstring(i1, 1304, i3) | 0;
+  i10 = _fopen(i9 | 0, 1312) | 0;
+  HEAP32[i6 + 4 >> 2] = i10;
+  if ((i10 | 0) == 0) {
+   i10 = _strerror(HEAP32[(___errno_location() | 0) >> 2] | 0) | 0;
+   i9 = (_lua_tolstring(i1, i2, 0) | 0) + 1 | 0;
+   HEAP32[i3 >> 2] = 1320;
+   HEAP32[i3 + 4 >> 2] = i9;
+   HEAP32[i3 + 8 >> 2] = i10;
+   _lua_pushfstring(i1, 1720, i3) | 0;
+   _lua_remove(i1, i2);
+   i10 = 7;
+   STACKTOP = i5;
+   return i10 | 0;
+  }
+ } else {
+  _lua_pushlstring(i1, 1296, 6) | 0;
+  HEAP32[i6 + 4 >> 2] = HEAP32[_stdin >> 2];
+ }
+ if ((_skipcomment(i6, i8) | 0) != 0) {
+  i10 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i10 + 1;
+  HEAP8[i6 + i10 + 8 | 0] = 10;
+ }
+ i10 = HEAP32[i8 >> 2] | 0;
+ do {
+  if (!((i10 | 0) != 27 | i4)) {
+   i11 = i6 + 4 | 0;
+   i10 = _freopen(i9 | 0, 1328, HEAP32[i11 >> 2] | 0) | 0;
+   HEAP32[i11 >> 2] = i10;
+   if ((i10 | 0) != 0) {
+    _skipcomment(i6, i8) | 0;
+    i10 = HEAP32[i8 >> 2] | 0;
+    break;
+   }
+   i11 = _strerror(HEAP32[(___errno_location() | 0) >> 2] | 0) | 0;
+   i10 = (_lua_tolstring(i1, i2, 0) | 0) + 1 | 0;
+   HEAP32[i3 >> 2] = 1336;
+   HEAP32[i3 + 4 >> 2] = i10;
+   HEAP32[i3 + 8 >> 2] = i11;
+   _lua_pushfstring(i1, 1720, i3) | 0;
+   _lua_remove(i1, i2);
+   i11 = 7;
+   STACKTOP = i5;
+   return i11 | 0;
+  }
+ } while (0);
+ if (!((i10 | 0) == -1)) {
+  i11 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i11 + 1;
+  HEAP8[i6 + i11 + 8 | 0] = i10;
+ }
+ i7 = _lua_load(i1, 1, i6, _lua_tolstring(i1, -1, 0) | 0, i7) | 0;
+ i8 = HEAP32[i6 + 4 >> 2] | 0;
+ i6 = _ferror(i8 | 0) | 0;
+ if (!i4) {
+  _fclose(i8 | 0) | 0;
+ }
+ if ((i6 | 0) == 0) {
+  _lua_remove(i1, i2);
+  i11 = i7;
+  STACKTOP = i5;
+  return i11 | 0;
+ } else {
+  _lua_settop(i1, i2);
+  i11 = _strerror(HEAP32[(___errno_location() | 0) >> 2] | 0) | 0;
+  i10 = (_lua_tolstring(i1, i2, 0) | 0) + 1 | 0;
+  HEAP32[i3 >> 2] = 1344;
+  HEAP32[i3 + 4 >> 2] = i10;
+  HEAP32[i3 + 8 >> 2] = i11;
+  _lua_pushfstring(i1, 1720, i3) | 0;
+  _lua_remove(i1, i2);
+  i11 = 7;
+  STACKTOP = i5;
+  return i11 | 0;
+ }
+ return 0;
+}
+function _newupvalue(i3, i1, i2) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i12 = i4;
+ i5 = HEAP32[i3 >> 2] | 0;
+ i9 = i5 + 40 | 0;
+ i7 = HEAP32[i9 >> 2] | 0;
+ i6 = i3 + 47 | 0;
+ i10 = HEAPU8[i6] | 0;
+ if ((i10 + 1 | 0) >>> 0 > 255) {
+  i11 = i3 + 12 | 0;
+  i8 = HEAP32[(HEAP32[i11 >> 2] | 0) + 52 >> 2] | 0;
+  i13 = HEAP32[i5 + 64 >> 2] | 0;
+  if ((i13 | 0) == 0) {
+   i15 = 6552;
+   HEAP32[i12 >> 2] = 6880;
+   i14 = i12 + 4 | 0;
+   HEAP32[i14 >> 2] = 255;
+   i14 = i12 + 8 | 0;
+   HEAP32[i14 >> 2] = i15;
+   i14 = _luaO_pushfstring(i8, 6592, i12) | 0;
+   i15 = HEAP32[i11 >> 2] | 0;
+   _luaX_syntaxerror(i15, i14);
+  }
+  HEAP32[i12 >> 2] = i13;
+  i14 = _luaO_pushfstring(i8, 6568, i12) | 0;
+  HEAP32[i12 >> 2] = 6880;
+  i15 = i12 + 4 | 0;
+  HEAP32[i15 >> 2] = 255;
+  i15 = i12 + 8 | 0;
+  HEAP32[i15 >> 2] = i14;
+  i15 = _luaO_pushfstring(i8, 6592, i12) | 0;
+  i14 = HEAP32[i11 >> 2] | 0;
+  _luaX_syntaxerror(i14, i15);
+ }
+ if ((i10 | 0) < (i7 | 0)) {
+  i8 = i7;
+ } else {
+  i8 = i5 + 28 | 0;
+  HEAP32[i8 >> 2] = _luaM_growaux_(HEAP32[(HEAP32[i3 + 12 >> 2] | 0) + 52 >> 2] | 0, HEAP32[i8 >> 2] | 0, i9, 8, 255, 6880) | 0;
+  i8 = HEAP32[i9 >> 2] | 0;
+ }
+ i9 = i5 + 28 | 0;
+ if ((i7 | 0) < (i8 | 0)) {
+  while (1) {
+   i10 = i7 + 1 | 0;
+   HEAP32[(HEAP32[i9 >> 2] | 0) + (i7 << 3) >> 2] = 0;
+   if ((i10 | 0) < (i8 | 0)) {
+    i7 = i10;
+   } else {
+    break;
+   }
+  }
+ }
+ HEAP8[(HEAP32[i9 >> 2] | 0) + ((HEAPU8[i6] | 0) << 3) + 4 | 0] = (HEAP32[i2 >> 2] | 0) == 7 | 0;
+ HEAP8[(HEAP32[i9 >> 2] | 0) + ((HEAPU8[i6] | 0) << 3) + 5 | 0] = HEAP32[i2 + 8 >> 2];
+ HEAP32[(HEAP32[i9 >> 2] | 0) + ((HEAPU8[i6] | 0) << 3) >> 2] = i1;
+ if ((HEAP8[i1 + 5 | 0] & 3) == 0) {
+  i15 = HEAP8[i6] | 0;
+  i14 = i15 + 1 << 24 >> 24;
+  HEAP8[i6] = i14;
+  i15 = i15 & 255;
+  STACKTOP = i4;
+  return i15 | 0;
+ }
+ if ((HEAP8[i5 + 5 | 0] & 4) == 0) {
+  i15 = HEAP8[i6] | 0;
+  i14 = i15 + 1 << 24 >> 24;
+  HEAP8[i6] = i14;
+  i15 = i15 & 255;
+  STACKTOP = i4;
+  return i15 | 0;
+ }
+ _luaC_barrier_(HEAP32[(HEAP32[i3 + 12 >> 2] | 0) + 52 >> 2] | 0, i5, i1);
+ i15 = HEAP8[i6] | 0;
+ i14 = i15 + 1 << 24 >> 24;
+ HEAP8[i6] = i14;
+ i15 = i15 & 255;
+ STACKTOP = i4;
+ return i15 | 0;
+}
+function _close_func(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i6 = STACKTOP;
+ i2 = HEAP32[i1 + 52 >> 2] | 0;
+ i5 = i1 + 48 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ _luaK_ret(i4, 0, 0);
+ _leaveblock(i4);
+ i7 = i4 + 20 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ if ((i8 + 1 | 0) >>> 0 > 1073741823) {
+  _luaM_toobig(i2);
+ }
+ i10 = i3 + 12 | 0;
+ i9 = i3 + 48 | 0;
+ HEAP32[i10 >> 2] = _luaM_realloc_(i2, HEAP32[i10 >> 2] | 0, HEAP32[i9 >> 2] << 2, i8 << 2) | 0;
+ HEAP32[i9 >> 2] = HEAP32[i7 >> 2];
+ i8 = HEAP32[i7 >> 2] | 0;
+ if ((i8 + 1 | 0) >>> 0 > 1073741823) {
+  _luaM_toobig(i2);
+ }
+ i9 = i3 + 20 | 0;
+ i10 = i3 + 52 | 0;
+ HEAP32[i9 >> 2] = _luaM_realloc_(i2, HEAP32[i9 >> 2] | 0, HEAP32[i10 >> 2] << 2, i8 << 2) | 0;
+ HEAP32[i10 >> 2] = HEAP32[i7 >> 2];
+ i8 = i4 + 32 | 0;
+ i7 = HEAP32[i8 >> 2] | 0;
+ if ((i7 + 1 | 0) >>> 0 > 268435455) {
+  _luaM_toobig(i2);
+ }
+ i9 = i3 + 8 | 0;
+ i10 = i3 + 44 | 0;
+ HEAP32[i9 >> 2] = _luaM_realloc_(i2, HEAP32[i9 >> 2] | 0, HEAP32[i10 >> 2] << 4, i7 << 4) | 0;
+ HEAP32[i10 >> 2] = HEAP32[i8 >> 2];
+ i8 = i4 + 36 | 0;
+ i7 = HEAP32[i8 >> 2] | 0;
+ if ((i7 + 1 | 0) >>> 0 > 1073741823) {
+  _luaM_toobig(i2);
+ }
+ i9 = i3 + 16 | 0;
+ i10 = i3 + 56 | 0;
+ HEAP32[i9 >> 2] = _luaM_realloc_(i2, HEAP32[i9 >> 2] | 0, HEAP32[i10 >> 2] << 2, i7 << 2) | 0;
+ HEAP32[i10 >> 2] = HEAP32[i8 >> 2];
+ i7 = i4 + 44 | 0;
+ i8 = HEAP16[i7 >> 1] | 0;
+ if ((i8 + 1 | 0) >>> 0 > 357913941) {
+  _luaM_toobig(i2);
+ }
+ i10 = i3 + 24 | 0;
+ i9 = i3 + 60 | 0;
+ HEAP32[i10 >> 2] = _luaM_realloc_(i2, HEAP32[i10 >> 2] | 0, (HEAP32[i9 >> 2] | 0) * 12 | 0, i8 * 12 | 0) | 0;
+ HEAP32[i9 >> 2] = HEAP16[i7 >> 1] | 0;
+ i9 = i4 + 47 | 0;
+ i8 = i3 + 28 | 0;
+ i10 = i3 + 40 | 0;
+ HEAP32[i8 >> 2] = _luaM_realloc_(i2, HEAP32[i8 >> 2] | 0, HEAP32[i10 >> 2] << 3, HEAPU8[i9] << 3) | 0;
+ HEAP32[i10 >> 2] = HEAPU8[i9] | 0;
+ HEAP32[i5 >> 2] = HEAP32[i4 + 8 >> 2];
+ if (((HEAP32[i1 + 16 >> 2] | 0) + -288 | 0) >>> 0 < 2) {
+  i10 = HEAP32[i1 + 24 >> 2] | 0;
+  _luaX_newstring(i1, i10 + 16 | 0, HEAP32[i10 + 12 >> 2] | 0) | 0;
+ }
+ i10 = i2 + 8 | 0;
+ HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + -16;
+ if ((HEAP32[(HEAP32[i2 + 12 >> 2] | 0) + 12 >> 2] | 0) <= 0) {
+  STACKTOP = i6;
+  return;
+ }
+ _luaC_step(i2);
+ STACKTOP = i6;
+ return;
+}
+function _lua_topointer(i3, i6) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i3 + 16 >> 2] | 0;
+ i5 = (i6 | 0) > 0;
+ do {
+  if (!i5) {
+   if (!((i6 | 0) < -1000999)) {
+    i7 = (HEAP32[i3 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i7 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i8 = -1001e3 - i6 | 0;
+   i9 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i9 + 8 >> 2] | 0) != 22 ? (i7 = HEAP32[i9 >> 2] | 0, (i8 | 0) <= (HEAPU8[i7 + 6 | 0] | 0 | 0)) : 0) {
+    i7 = i7 + (i8 + -1 << 4) + 16 | 0;
+   } else {
+    i7 = 5192;
+   }
+  } else {
+   i7 = (HEAP32[i4 >> 2] | 0) + (i6 << 4) | 0;
+   i7 = i7 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i7 : 5192;
+  }
+ } while (0);
+ switch (HEAP32[i7 + 8 >> 2] & 63 | 0) {
+ case 22:
+  {
+   i9 = HEAP32[i7 >> 2] | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ case 2:
+ case 7:
+  {
+   do {
+    if (!i5) {
+     if (!((i6 | 0) < -1000999)) {
+      i2 = (HEAP32[i3 + 8 >> 2] | 0) + (i6 << 4) | 0;
+      break;
+     }
+     if ((i6 | 0) == -1001e3) {
+      i2 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+      break;
+     }
+     i3 = -1001e3 - i6 | 0;
+     i4 = HEAP32[i4 >> 2] | 0;
+     if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i2 = HEAP32[i4 >> 2] | 0, (i3 | 0) <= (HEAPU8[i2 + 6 | 0] | 0 | 0)) : 0) {
+      i2 = i2 + (i3 + -1 << 4) + 16 | 0;
+     } else {
+      i2 = 5192;
+     }
+    } else {
+     i2 = (HEAP32[i4 >> 2] | 0) + (i6 << 4) | 0;
+     i2 = i2 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i2 : 5192;
+    }
+   } while (0);
+   i3 = HEAP32[i2 + 8 >> 2] & 15;
+   if ((i3 | 0) == 7) {
+    i9 = (HEAP32[i2 >> 2] | 0) + 24 | 0;
+    STACKTOP = i1;
+    return i9 | 0;
+   } else if ((i3 | 0) == 2) {
+    i9 = HEAP32[i2 >> 2] | 0;
+    STACKTOP = i1;
+    return i9 | 0;
+   } else {
+    i9 = 0;
+    STACKTOP = i1;
+    return i9 | 0;
+   }
+  }
+ case 8:
+  {
+   i9 = HEAP32[i7 >> 2] | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ case 5:
+  {
+   i9 = HEAP32[i7 >> 2] | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ case 38:
+  {
+   i9 = HEAP32[i7 >> 2] | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ case 6:
+  {
+   i9 = HEAP32[i7 >> 2] | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ default:
+  {
+   i9 = 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ }
+ return 0;
+}
+function _luaH_get(i4, i6) {
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, d5 = 0.0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, d11 = 0.0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i8 = i3 + 8 | 0;
+ i9 = i3;
+ i7 = i6 + 8 | 0;
+ i10 = HEAP32[i7 >> 2] & 63;
+ if ((i10 | 0) == 4) {
+  i6 = HEAP32[i6 >> 2] | 0;
+  i7 = (HEAP32[i4 + 16 >> 2] | 0) + (((1 << (HEAPU8[i4 + 7 | 0] | 0)) + -1 & HEAP32[i6 + 8 >> 2]) << 5) | 0;
+  while (1) {
+   if ((HEAP32[i7 + 24 >> 2] | 0) == 68 ? (HEAP32[i7 + 16 >> 2] | 0) == (i6 | 0) : 0) {
+    break;
+   }
+   i4 = HEAP32[i7 + 28 >> 2] | 0;
+   if ((i4 | 0) == 0) {
+    i2 = 5192;
+    i1 = 22;
+    break;
+   } else {
+    i7 = i4;
+   }
+  }
+  if ((i1 | 0) == 22) {
+   STACKTOP = i3;
+   return i2 | 0;
+  }
+  i10 = i7;
+  STACKTOP = i3;
+  return i10 | 0;
+ } else if ((i10 | 0) == 3) {
+  d11 = +HEAPF64[i6 >> 3];
+  HEAPF64[i9 >> 3] = d11 + 6755399441055744.0;
+  i9 = HEAP32[i9 >> 2] | 0;
+  d5 = +(i9 | 0);
+  if (d5 == d11) {
+   i6 = i9 + -1 | 0;
+   if (i6 >>> 0 < (HEAP32[i4 + 28 >> 2] | 0) >>> 0) {
+    i10 = (HEAP32[i4 + 12 >> 2] | 0) + (i6 << 4) | 0;
+    STACKTOP = i3;
+    return i10 | 0;
+   }
+   HEAPF64[i8 >> 3] = d5 + 1.0;
+   i6 = (HEAP32[i8 + 4 >> 2] | 0) + (HEAP32[i8 >> 2] | 0) | 0;
+   if ((i6 | 0) < 0) {
+    i7 = 0 - i6 | 0;
+    i6 = (i6 | 0) == (i7 | 0) ? 0 : i7;
+   }
+   i4 = (HEAP32[i4 + 16 >> 2] | 0) + (((i6 | 0) % ((1 << (HEAPU8[i4 + 7 | 0] | 0)) + -1 | 1 | 0) | 0) << 5) | 0;
+   while (1) {
+    if ((HEAP32[i4 + 24 >> 2] | 0) == 3 ? +HEAPF64[i4 + 16 >> 3] == d5 : 0) {
+     break;
+    }
+    i6 = HEAP32[i4 + 28 >> 2] | 0;
+    if ((i6 | 0) == 0) {
+     i2 = 5192;
+     i1 = 22;
+     break;
+    } else {
+     i4 = i6;
+    }
+   }
+   if ((i1 | 0) == 22) {
+    STACKTOP = i3;
+    return i2 | 0;
+   }
+   i10 = i4;
+   STACKTOP = i3;
+   return i10 | 0;
+  }
+ } else if ((i10 | 0) == 0) {
+  i10 = 5192;
+  STACKTOP = i3;
+  return i10 | 0;
+ }
+ i8 = _mainposition(i4, i6) | 0;
+ while (1) {
+  if ((HEAP32[i8 + 24 >> 2] | 0) == (HEAP32[i7 >> 2] | 0) ? (_luaV_equalobj_(0, i8 + 16 | 0, i6) | 0) != 0 : 0) {
+   break;
+  }
+  i4 = HEAP32[i8 + 28 >> 2] | 0;
+  if ((i4 | 0) == 0) {
+   i2 = 5192;
+   i1 = 22;
+   break;
+  } else {
+   i8 = i4;
+  }
+ }
+ if ((i1 | 0) == 22) {
+  STACKTOP = i3;
+  return i2 | 0;
+ }
+ i10 = i8;
+ STACKTOP = i3;
+ return i10 | 0;
+}
+function _suffixedexp(i1, i8) {
+ i1 = i1 | 0;
+ i8 = i8 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 80 | 0;
+ i10 = i2 + 48 | 0;
+ i3 = i2 + 24 | 0;
+ i6 = i2;
+ i4 = i1 + 48 | 0;
+ i9 = HEAP32[i4 >> 2] | 0;
+ i5 = HEAP32[i1 + 4 >> 2] | 0;
+ i7 = i1 + 16 | 0;
+ i12 = HEAP32[i7 >> 2] | 0;
+ if ((i12 | 0) == 40) {
+  _luaX_next(i1);
+  _subexpr(i1, i8, 0) | 0;
+  _check_match(i1, 41, 40, i5);
+  _luaK_dischargevars(HEAP32[i4 >> 2] | 0, i8);
+  i11 = i1 + 24 | 0;
+ } else if ((i12 | 0) == 288) {
+  i11 = i1 + 24 | 0;
+  i13 = HEAP32[i11 >> 2] | 0;
+  _luaX_next(i1);
+  i12 = HEAP32[i4 >> 2] | 0;
+  if ((_singlevaraux(i12, i13, i8, 1) | 0) == 0) {
+   _singlevaraux(i12, HEAP32[i1 + 72 >> 2] | 0, i8, 1) | 0;
+   i13 = _luaK_stringK(HEAP32[i4 >> 2] | 0, i13) | 0;
+   HEAP32[i10 + 16 >> 2] = -1;
+   HEAP32[i10 + 20 >> 2] = -1;
+   HEAP32[i10 >> 2] = 4;
+   HEAP32[i10 + 8 >> 2] = i13;
+   _luaK_indexed(i12, i8, i10);
+  }
+ } else {
+  _luaX_syntaxerror(i1, 6656);
+ }
+ i10 = i6 + 16 | 0;
+ i12 = i6 + 20 | 0;
+ i13 = i6 + 8 | 0;
+ L7 : while (1) {
+  switch (HEAP32[i7 >> 2] | 0) {
+  case 46:
+   {
+    _fieldsel(i1, i8);
+    continue L7;
+   }
+  case 91:
+   {
+    _luaK_exp2anyregup(i9, i8);
+    _luaX_next(i1);
+    _subexpr(i1, i3, 0) | 0;
+    _luaK_exp2val(HEAP32[i4 >> 2] | 0, i3);
+    if ((HEAP32[i7 >> 2] | 0) != 93) {
+     i3 = 10;
+     break L7;
+    }
+    _luaX_next(i1);
+    _luaK_indexed(i9, i8, i3);
+    continue L7;
+   }
+  case 58:
+   {
+    _luaX_next(i1);
+    if ((HEAP32[i7 >> 2] | 0) != 288) {
+     i3 = 13;
+     break L7;
+    }
+    i14 = HEAP32[i11 >> 2] | 0;
+    _luaX_next(i1);
+    i14 = _luaK_stringK(HEAP32[i4 >> 2] | 0, i14) | 0;
+    HEAP32[i10 >> 2] = -1;
+    HEAP32[i12 >> 2] = -1;
+    HEAP32[i6 >> 2] = 4;
+    HEAP32[i13 >> 2] = i14;
+    _luaK_self(i9, i8, i6);
+    _funcargs(i1, i8, i5);
+    continue L7;
+   }
+  case 123:
+  case 289:
+  case 40:
+   {
+    _luaK_exp2nextreg(i9, i8);
+    _funcargs(i1, i8, i5);
+    continue L7;
+   }
+  default:
+   {
+    i3 = 16;
+    break L7;
+   }
+  }
+ }
+ if ((i3 | 0) == 10) {
+  _error_expected(i1, 93);
+ } else if ((i3 | 0) == 13) {
+  _error_expected(i1, 288);
+ } else if ((i3 | 0) == 16) {
+  STACKTOP = i2;
+  return;
+ }
+}
+function _luaK_patchlist(i2, i7, i3) {
+ i2 = i2 | 0;
+ i7 = i7 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i1 = STACKTOP;
+ if ((HEAP32[i2 + 20 >> 2] | 0) == (i3 | 0)) {
+  HEAP32[i2 + 24 >> 2] = i3;
+  i3 = i2 + 28 | 0;
+  if ((i7 | 0) == -1) {
+   STACKTOP = i1;
+   return;
+  }
+  i6 = HEAP32[i3 >> 2] | 0;
+  if ((i6 | 0) == -1) {
+   HEAP32[i3 >> 2] = i7;
+   STACKTOP = i1;
+   return;
+  }
+  i5 = HEAP32[(HEAP32[i2 >> 2] | 0) + 12 >> 2] | 0;
+  while (1) {
+   i3 = i5 + (i6 << 2) | 0;
+   i4 = HEAP32[i3 >> 2] | 0;
+   i8 = (i4 >>> 14) + -131071 | 0;
+   if ((i8 | 0) == -1) {
+    break;
+   }
+   i8 = i6 + 1 + i8 | 0;
+   if ((i8 | 0) == -1) {
+    break;
+   } else {
+    i6 = i8;
+   }
+  }
+  i5 = ~i6 + i7 | 0;
+  if ((((i5 | 0) > -1 ? i5 : 0 - i5 | 0) | 0) > 131071) {
+   _luaX_syntaxerror(HEAP32[i2 + 12 >> 2] | 0, 10624);
+  }
+  HEAP32[i3 >> 2] = (i5 << 14) + 2147467264 | i4 & 16383;
+  STACKTOP = i1;
+  return;
+ }
+ if ((i7 | 0) == -1) {
+  STACKTOP = i1;
+  return;
+ }
+ i6 = HEAP32[(HEAP32[i2 >> 2] | 0) + 12 >> 2] | 0;
+ i10 = i7;
+ while (1) {
+  i7 = i6 + (i10 << 2) | 0;
+  i9 = HEAP32[i7 >> 2] | 0;
+  i8 = (i9 >>> 14) + -131071 | 0;
+  if ((i8 | 0) == -1) {
+   i8 = -1;
+  } else {
+   i8 = i10 + 1 + i8 | 0;
+  }
+  if ((i10 | 0) > 0 ? (i4 = i6 + (i10 + -1 << 2) | 0, i5 = HEAP32[i4 >> 2] | 0, (HEAP8[5584 + (i5 & 63) | 0] | 0) < 0) : 0) {
+   i12 = i4;
+   i11 = i5;
+  } else {
+   i12 = i7;
+   i11 = i9;
+  }
+  if ((i11 & 63 | 0) == 28) {
+   HEAP32[i12 >> 2] = i11 & 8372224 | i11 >>> 23 << 6 | 27;
+   i9 = ~i10 + i3 | 0;
+   if ((((i9 | 0) > -1 ? i9 : 0 - i9 | 0) | 0) > 131071) {
+    i3 = 20;
+    break;
+   }
+   i9 = HEAP32[i7 >> 2] & 16383 | (i9 << 14) + 2147467264;
+  } else {
+   i10 = ~i10 + i3 | 0;
+   if ((((i10 | 0) > -1 ? i10 : 0 - i10 | 0) | 0) > 131071) {
+    i3 = 23;
+    break;
+   }
+   i9 = i9 & 16383 | (i10 << 14) + 2147467264;
+  }
+  HEAP32[i7 >> 2] = i9;
+  if ((i8 | 0) == -1) {
+   i3 = 26;
+   break;
+  } else {
+   i10 = i8;
+  }
+ }
+ if ((i3 | 0) == 20) {
+  _luaX_syntaxerror(HEAP32[i2 + 12 >> 2] | 0, 10624);
+ } else if ((i3 | 0) == 23) {
+  _luaX_syntaxerror(HEAP32[i2 + 12 >> 2] | 0, 10624);
+ } else if ((i3 | 0) == 26) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function _luaG_typeerror(i5, i6, i1) {
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i3 = i2;
+ i2 = i2 + 16 | 0;
+ i8 = HEAP32[i5 + 16 >> 2] | 0;
+ HEAP32[i2 >> 2] = 0;
+ i4 = HEAP32[8528 + ((HEAP32[i6 + 8 >> 2] & 15) + 1 << 2) >> 2] | 0;
+ L1 : do {
+  if (!((HEAP8[i8 + 18 | 0] & 1) == 0)) {
+   i7 = HEAP32[HEAP32[i8 >> 2] >> 2] | 0;
+   i10 = HEAP8[i7 + 6 | 0] | 0;
+   L3 : do {
+    if (!(i10 << 24 >> 24 == 0)) {
+     i9 = i7 + 16 | 0;
+     i11 = i10 & 255;
+     i10 = 0;
+     while (1) {
+      i12 = i10 + 1 | 0;
+      if ((HEAP32[(HEAP32[i9 + (i10 << 2) >> 2] | 0) + 8 >> 2] | 0) == (i6 | 0)) {
+       break;
+      }
+      if ((i12 | 0) < (i11 | 0)) {
+       i10 = i12;
+      } else {
+       break L3;
+      }
+     }
+     i9 = HEAP32[(HEAP32[(HEAP32[i7 + 12 >> 2] | 0) + 28 >> 2] | 0) + (i10 << 3) >> 2] | 0;
+     if ((i9 | 0) == 0) {
+      i9 = 2104;
+     } else {
+      i9 = i9 + 16 | 0;
+     }
+     HEAP32[i2 >> 2] = i9;
+     i11 = i9;
+     i10 = 2072;
+     HEAP32[i3 >> 2] = i1;
+     i12 = i3 + 4 | 0;
+     HEAP32[i12 >> 2] = i10;
+     i12 = i3 + 8 | 0;
+     HEAP32[i12 >> 2] = i11;
+     i12 = i3 + 12 | 0;
+     HEAP32[i12 >> 2] = i4;
+     _luaG_runerror(i5, 1840, i3);
+    }
+   } while (0);
+   i9 = HEAP32[i8 + 24 >> 2] | 0;
+   i10 = HEAP32[i8 + 4 >> 2] | 0;
+   if (i9 >>> 0 < i10 >>> 0) {
+    i12 = i9;
+    while (1) {
+     i11 = i12 + 16 | 0;
+     if ((i12 | 0) == (i6 | 0)) {
+      break;
+     }
+     if (i11 >>> 0 < i10 >>> 0) {
+      i12 = i11;
+     } else {
+      break L1;
+     }
+    }
+    i12 = HEAP32[i7 + 12 >> 2] | 0;
+    i6 = _getobjname(i12, ((HEAP32[i8 + 28 >> 2] | 0) - (HEAP32[i12 + 12 >> 2] | 0) >> 2) + -1 | 0, i6 - i9 >> 4, i2) | 0;
+    if ((i6 | 0) != 0) {
+     i11 = HEAP32[i2 >> 2] | 0;
+     i10 = i6;
+     HEAP32[i3 >> 2] = i1;
+     i12 = i3 + 4 | 0;
+     HEAP32[i12 >> 2] = i10;
+     i12 = i3 + 8 | 0;
+     HEAP32[i12 >> 2] = i11;
+     i12 = i3 + 12 | 0;
+     HEAP32[i12 >> 2] = i4;
+     _luaG_runerror(i5, 1840, i3);
+    }
+   }
+  }
+ } while (0);
+ HEAP32[i3 >> 2] = i1;
+ HEAP32[i3 + 4 >> 2] = i4;
+ _luaG_runerror(i5, 1880, i3);
+}
+function _lua_setmetatable(i1, i7) {
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0;
+ i4 = STACKTOP;
+ i6 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i7 | 0) <= 0) {
+   if (!((i7 | 0) < -1000999)) {
+    i5 = (HEAP32[i1 + 8 >> 2] | 0) + (i7 << 4) | 0;
+    break;
+   }
+   if ((i7 | 0) == -1001e3) {
+    i5 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i7 = -1001e3 - i7 | 0;
+   i6 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) != 22 ? (i5 = HEAP32[i6 >> 2] | 0, (i7 | 0) <= (HEAPU8[i5 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i5 + (i7 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i5 = (HEAP32[i6 >> 2] | 0) + (i7 << 4) | 0;
+   i5 = i5 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i5 : 5192;
+  }
+ } while (0);
+ i6 = i1 + 8 | 0;
+ i7 = HEAP32[i6 >> 2] | 0;
+ if ((HEAP32[i7 + -8 >> 2] | 0) == 0) {
+  i7 = 0;
+ } else {
+  i7 = HEAP32[i7 + -16 >> 2] | 0;
+ }
+ i8 = HEAP32[i5 + 8 >> 2] & 15;
+ if ((i8 | 0) == 5) {
+  HEAP32[(HEAP32[i5 >> 2] | 0) + 8 >> 2] = i7;
+  if ((i7 | 0) == 0) {
+   i8 = HEAP32[i6 >> 2] | 0;
+   i8 = i8 + -16 | 0;
+   HEAP32[i6 >> 2] = i8;
+   STACKTOP = i4;
+   return 1;
+  }
+  if (!((HEAP8[i7 + 5 | 0] & 3) == 0) ? (i2 = HEAP32[i5 >> 2] | 0, !((HEAP8[i2 + 5 | 0] & 4) == 0)) : 0) {
+   _luaC_barrierback_(i1, i2);
+  }
+  _luaC_checkfinalizer(i1, HEAP32[i5 >> 2] | 0, i7);
+  i8 = HEAP32[i6 >> 2] | 0;
+  i8 = i8 + -16 | 0;
+  HEAP32[i6 >> 2] = i8;
+  STACKTOP = i4;
+  return 1;
+ } else if ((i8 | 0) == 7) {
+  HEAP32[(HEAP32[i5 >> 2] | 0) + 8 >> 2] = i7;
+  if ((i7 | 0) == 0) {
+   i8 = HEAP32[i6 >> 2] | 0;
+   i8 = i8 + -16 | 0;
+   HEAP32[i6 >> 2] = i8;
+   STACKTOP = i4;
+   return 1;
+  }
+  if (!((HEAP8[i7 + 5 | 0] & 3) == 0) ? (i3 = HEAP32[i5 >> 2] | 0, !((HEAP8[i3 + 5 | 0] & 4) == 0)) : 0) {
+   _luaC_barrier_(i1, i3, i7);
+  }
+  _luaC_checkfinalizer(i1, HEAP32[i5 >> 2] | 0, i7);
+  i8 = HEAP32[i6 >> 2] | 0;
+  i8 = i8 + -16 | 0;
+  HEAP32[i6 >> 2] = i8;
+  STACKTOP = i4;
+  return 1;
+ } else {
+  HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + (i8 << 2) + 252 >> 2] = i7;
+  i8 = HEAP32[i6 >> 2] | 0;
+  i8 = i8 + -16 | 0;
+  HEAP32[i6 >> 2] = i8;
+  STACKTOP = i4;
+  return 1;
+ }
+ return 0;
+}
+function _recfield(i2, i10) {
+ i2 = i2 | 0;
+ i10 = i10 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i9 = i1 + 48 | 0;
+ i6 = i1 + 24 | 0;
+ i3 = i1;
+ i13 = i2 + 48 | 0;
+ i8 = HEAP32[i13 >> 2] | 0;
+ i5 = i8 + 48 | 0;
+ i4 = HEAP8[i5] | 0;
+ i7 = i2 + 16 | 0;
+ do {
+  if ((HEAP32[i7 >> 2] | 0) != 288) {
+   _luaX_next(i2);
+   _subexpr(i2, i6, 0) | 0;
+   _luaK_exp2val(HEAP32[i13 >> 2] | 0, i6);
+   if ((HEAP32[i7 >> 2] | 0) == 93) {
+    _luaX_next(i2);
+    i11 = i10 + 28 | 0;
+    break;
+   } else {
+    _error_expected(i2, 93);
+   }
+  } else {
+   i12 = i10 + 28 | 0;
+   if ((HEAP32[i12 >> 2] | 0) <= 2147483645) {
+    i11 = HEAP32[i2 + 24 >> 2] | 0;
+    _luaX_next(i2);
+    i11 = _luaK_stringK(HEAP32[i13 >> 2] | 0, i11) | 0;
+    HEAP32[i6 + 16 >> 2] = -1;
+    HEAP32[i6 + 20 >> 2] = -1;
+    HEAP32[i6 >> 2] = 4;
+    HEAP32[i6 + 8 >> 2] = i11;
+    i11 = i12;
+    break;
+   }
+   i14 = i8 + 12 | 0;
+   i13 = HEAP32[(HEAP32[i14 >> 2] | 0) + 52 >> 2] | 0;
+   i12 = HEAP32[(HEAP32[i8 >> 2] | 0) + 64 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    i16 = 6552;
+    HEAP32[i9 >> 2] = 6528;
+    i15 = i9 + 4 | 0;
+    HEAP32[i15 >> 2] = 2147483645;
+    i15 = i9 + 8 | 0;
+    HEAP32[i15 >> 2] = i16;
+    i15 = _luaO_pushfstring(i13, 6592, i9) | 0;
+    i16 = HEAP32[i14 >> 2] | 0;
+    _luaX_syntaxerror(i16, i15);
+   }
+   HEAP32[i9 >> 2] = i12;
+   i15 = _luaO_pushfstring(i13, 6568, i9) | 0;
+   HEAP32[i9 >> 2] = 6528;
+   i16 = i9 + 4 | 0;
+   HEAP32[i16 >> 2] = 2147483645;
+   i16 = i9 + 8 | 0;
+   HEAP32[i16 >> 2] = i15;
+   i16 = _luaO_pushfstring(i13, 6592, i9) | 0;
+   i15 = HEAP32[i14 >> 2] | 0;
+   _luaX_syntaxerror(i15, i16);
+  }
+ } while (0);
+ HEAP32[i11 >> 2] = (HEAP32[i11 >> 2] | 0) + 1;
+ if ((HEAP32[i7 >> 2] | 0) == 61) {
+  _luaX_next(i2);
+  i16 = _luaK_exp2RK(i8, i6) | 0;
+  _subexpr(i2, i3, 0) | 0;
+  i15 = HEAP32[(HEAP32[i10 + 24 >> 2] | 0) + 8 >> 2] | 0;
+  _luaK_codeABC(i8, 10, i15, i16, _luaK_exp2RK(i8, i3) | 0) | 0;
+  HEAP8[i5] = i4;
+  STACKTOP = i1;
+  return;
+ } else {
+  _error_expected(i2, 61);
+ }
+}
+function _lua_newstate(i3, i6) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i5 = i1 + 8 | 0;
+ i4 = i1;
+ i2 = FUNCTION_TABLE_iiiii[i3 & 3](i6, 0, 8, 400) | 0;
+ if ((i2 | 0) == 0) {
+  i6 = 0;
+  STACKTOP = i1;
+  return i6 | 0;
+ }
+ i7 = i2 + 112 | 0;
+ HEAP32[i2 >> 2] = 0;
+ HEAP8[i2 + 4 | 0] = 8;
+ HEAP8[i2 + 172 | 0] = 33;
+ HEAP8[i2 + 5 | 0] = 1;
+ HEAP8[i2 + 174 | 0] = 0;
+ HEAP32[i2 + 12 >> 2] = i7;
+ HEAP32[i2 + 28 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ HEAP32[i2 + 32 >> 2] = 0;
+ HEAP32[i2 + 64 >> 2] = 0;
+ HEAP16[i2 + 38 >> 1] = 0;
+ HEAP32[i2 + 52 >> 2] = 0;
+ HEAP8[i2 + 40 | 0] = 0;
+ HEAP32[i2 + 44 >> 2] = 0;
+ HEAP8[i2 + 41 | 0] = 1;
+ HEAP32[i2 + 48 >> 2] = 0;
+ HEAP32[i2 + 56 >> 2] = 0;
+ HEAP16[i2 + 36 >> 1] = 1;
+ HEAP8[i2 + 6 | 0] = 0;
+ HEAP32[i2 + 68 >> 2] = 0;
+ HEAP32[i7 >> 2] = i3;
+ HEAP32[i2 + 116 >> 2] = i6;
+ HEAP32[i2 + 284 >> 2] = i2;
+ i3 = _time(0) | 0;
+ HEAP32[i4 >> 2] = i3;
+ HEAP32[i5 >> 2] = i2;
+ HEAP32[i5 + 4 >> 2] = i4;
+ HEAP32[i5 + 8 >> 2] = 5192;
+ HEAP32[i5 + 12 >> 2] = 1;
+ HEAP32[i2 + 168 >> 2] = _luaS_hash(i5, 16, i3) | 0;
+ i4 = i2 + 224 | 0;
+ HEAP32[i2 + 240 >> 2] = i4;
+ HEAP32[i2 + 244 >> 2] = i4;
+ HEAP8[i2 + 175 | 0] = 0;
+ i4 = i2 + 132 | 0;
+ HEAP32[i2 + 160 >> 2] = 0;
+ HEAP32[i2 + 256 >> 2] = 0;
+ HEAP32[i2 + 264 >> 2] = 0;
+ HEAP32[i2 + 280 >> 2] = 0;
+ HEAP32[i4 + 0 >> 2] = 0;
+ HEAP32[i4 + 4 >> 2] = 0;
+ HEAP32[i4 + 8 >> 2] = 0;
+ HEAP32[i4 + 12 >> 2] = 0;
+ HEAP32[i2 + 288 >> 2] = _lua_version(0) | 0;
+ HEAP8[i2 + 173 | 0] = 5;
+ i4 = i2 + 120 | 0;
+ i5 = i2 + 180 | 0;
+ i3 = i5 + 40 | 0;
+ do {
+  HEAP32[i5 >> 2] = 0;
+  i5 = i5 + 4 | 0;
+ } while ((i5 | 0) < (i3 | 0));
+ HEAP32[i4 >> 2] = 400;
+ HEAP32[i2 + 124 >> 2] = 0;
+ HEAP32[i2 + 268 >> 2] = 200;
+ HEAP32[i2 + 272 >> 2] = 200;
+ HEAP32[i2 + 276 >> 2] = 200;
+ i5 = i2 + 364 | 0;
+ i3 = i5 + 36 | 0;
+ do {
+  HEAP32[i5 >> 2] = 0;
+  i5 = i5 + 4 | 0;
+ } while ((i5 | 0) < (i3 | 0));
+ if ((_luaD_rawrunprotected(i2, 8, 0) | 0) == 0) {
+  i7 = i2;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ _close_state(i2);
+ i7 = 0;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _luaU_undump(i1, i7, i8, i9) {
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ i8 = i8 | 0;
+ i9 = i9 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i4 = i2 + 16 | 0;
+ i5 = i2 + 34 | 0;
+ i3 = i2;
+ i6 = HEAP8[i9] | 0;
+ if (i6 << 24 >> 24 == 27) {
+  HEAP32[i3 + 12 >> 2] = 8800;
+ } else if (i6 << 24 >> 24 == 61 | i6 << 24 >> 24 == 64) {
+  HEAP32[i3 + 12 >> 2] = i9 + 1;
+ } else {
+  HEAP32[i3 + 12 >> 2] = i9;
+ }
+ HEAP32[i3 >> 2] = i1;
+ HEAP32[i3 + 4 >> 2] = i7;
+ HEAP32[i3 + 8 >> 2] = i8;
+ HEAP32[i4 >> 2] = 1635077147;
+ HEAP8[i4 + 4 | 0] = 82;
+ HEAP8[i4 + 5 | 0] = 0;
+ HEAP8[i4 + 6 | 0] = 1;
+ HEAP8[i4 + 7 | 0] = 4;
+ HEAP8[i4 + 8 | 0] = 4;
+ HEAP8[i4 + 9 | 0] = 4;
+ HEAP8[i4 + 10 | 0] = 8;
+ i9 = i4 + 12 | 0;
+ HEAP8[i4 + 11 | 0] = 0;
+ HEAP8[i9 + 0 | 0] = HEAP8[8816 | 0] | 0;
+ HEAP8[i9 + 1 | 0] = HEAP8[8817 | 0] | 0;
+ HEAP8[i9 + 2 | 0] = HEAP8[8818 | 0] | 0;
+ HEAP8[i9 + 3 | 0] = HEAP8[8819 | 0] | 0;
+ HEAP8[i9 + 4 | 0] = HEAP8[8820 | 0] | 0;
+ HEAP8[i9 + 5 | 0] = HEAP8[8821 | 0] | 0;
+ HEAP8[i5] = 27;
+ if ((_luaZ_read(i7, i5 + 1 | 0, 17) | 0) != 0) {
+  _error(i3, 8824);
+ }
+ if ((_memcmp(i4, i5, 18) | 0) == 0) {
+  i4 = _luaF_newLclosure(i1, 1) | 0;
+  i5 = i1 + 8 | 0;
+  i9 = HEAP32[i5 >> 2] | 0;
+  HEAP32[i9 >> 2] = i4;
+  HEAP32[i9 + 8 >> 2] = 70;
+  i9 = (HEAP32[i5 >> 2] | 0) + 16 | 0;
+  HEAP32[i5 >> 2] = i9;
+  if (((HEAP32[i1 + 24 >> 2] | 0) - i9 | 0) < 16) {
+   _luaD_growstack(i1, 0);
+  }
+  i9 = _luaF_newproto(i1) | 0;
+  i6 = i4 + 12 | 0;
+  HEAP32[i6 >> 2] = i9;
+  _LoadFunction(i3, i9);
+  i6 = HEAP32[i6 >> 2] | 0;
+  i3 = HEAP32[i6 + 40 >> 2] | 0;
+  if ((i3 | 0) == 1) {
+   i9 = i4;
+   STACKTOP = i2;
+   return i9 | 0;
+  }
+  i9 = _luaF_newLclosure(i1, i3) | 0;
+  HEAP32[i9 + 12 >> 2] = i6;
+  i8 = HEAP32[i5 >> 2] | 0;
+  HEAP32[i8 + -16 >> 2] = i9;
+  HEAP32[i8 + -8 >> 2] = 70;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ if ((_memcmp(i4, i5, 4) | 0) != 0) {
+  _error(i3, 8888);
+ }
+ if ((_memcmp(i4, i5, 6) | 0) != 0) {
+  _error(i3, 8896);
+ }
+ if ((_memcmp(i4, i5, 12) | 0) == 0) {
+  _error(i3, 8872);
+ } else {
+  _error(i3, 8920);
+ }
+ return 0;
+}
+function _lua_compare(i2, i7, i5, i3) {
+ i2 = i2 | 0;
+ i7 = i7 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i6 = 0, i8 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i7 | 0) <= 0) {
+   if (!((i7 | 0) < -1000999)) {
+    i6 = (HEAP32[i2 + 8 >> 2] | 0) + (i7 << 4) | 0;
+    break;
+   }
+   if ((i7 | 0) == -1001e3) {
+    i6 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i7 = -1001e3 - i7 | 0;
+   i8 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i8 + 8 >> 2] | 0) != 22 ? (i6 = HEAP32[i8 >> 2] | 0, (i7 | 0) <= (HEAPU8[i6 + 6 | 0] | 0 | 0)) : 0) {
+    i6 = i6 + (i7 + -1 << 4) + 16 | 0;
+   } else {
+    i6 = 5192;
+   }
+  } else {
+   i6 = (HEAP32[i4 >> 2] | 0) + (i7 << 4) | 0;
+   i6 = i6 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i6 : 5192;
+  }
+ } while (0);
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i4 = (HEAP32[i2 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i4 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) == 22) {
+    i8 = 0;
+    STACKTOP = i1;
+    return i8 | 0;
+   }
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((i5 | 0) > (HEAPU8[i4 + 6 | 0] | 0 | 0)) {
+    i8 = 0;
+    STACKTOP = i1;
+    return i8 | 0;
+   } else {
+    i4 = i4 + (i5 + -1 << 4) + 16 | 0;
+    break;
+   }
+  } else {
+   i4 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ if ((i6 | 0) == 5192 | (i4 | 0) == 5192) {
+  i8 = 0;
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ if ((i3 | 0) == 1) {
+  i8 = _luaV_lessthan(i2, i6, i4) | 0;
+  STACKTOP = i1;
+  return i8 | 0;
+ } else if ((i3 | 0) == 2) {
+  i8 = _luaV_lessequal(i2, i6, i4) | 0;
+  STACKTOP = i1;
+  return i8 | 0;
+ } else if ((i3 | 0) == 0) {
+  if ((HEAP32[i6 + 8 >> 2] | 0) == (HEAP32[i4 + 8 >> 2] | 0)) {
+   i2 = (_luaV_equalobj_(i2, i6, i4) | 0) != 0;
+  } else {
+   i2 = 0;
+  }
+  i8 = i2 & 1;
+  STACKTOP = i1;
+  return i8 | 0;
+ } else {
+  i8 = 0;
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ return 0;
+}
+function _lexerror(i7, i3, i8) {
+ i7 = i7 | 0;
+ i3 = i3 | 0;
+ i8 = i8 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i12 = STACKTOP;
+ STACKTOP = STACKTOP + 80 | 0;
+ i2 = i12;
+ i12 = i12 + 12 | 0;
+ _luaO_chunkid(i12, (HEAP32[i7 + 68 >> 2] | 0) + 16 | 0, 60);
+ i1 = i7 + 52 | 0;
+ i4 = HEAP32[i1 >> 2] | 0;
+ i13 = HEAP32[i7 + 4 >> 2] | 0;
+ HEAP32[i2 >> 2] = i12;
+ HEAP32[i2 + 4 >> 2] = i13;
+ HEAP32[i2 + 8 >> 2] = i3;
+ i4 = _luaO_pushfstring(i4, 12592, i2) | 0;
+ if ((i8 | 0) == 0) {
+  i13 = HEAP32[i1 >> 2] | 0;
+  _luaD_throw(i13, 3);
+ }
+ i3 = HEAP32[i1 >> 2] | 0;
+ do {
+  if (!((i8 + -287 | 0) >>> 0 < 3)) {
+   if ((i8 | 0) >= 257) {
+    i5 = HEAP32[12096 + (i8 + -257 << 2) >> 2] | 0;
+    if ((i8 | 0) >= 286) {
+     break;
+    }
+    HEAP32[i2 >> 2] = i5;
+    i5 = _luaO_pushfstring(i3, 12256, i2) | 0;
+    break;
+   }
+   if ((HEAP8[i8 + 10913 | 0] & 4) == 0) {
+    HEAP32[i2 >> 2] = i8;
+    i5 = _luaO_pushfstring(i3, 12240, i2) | 0;
+    break;
+   } else {
+    HEAP32[i2 >> 2] = i8;
+    i5 = _luaO_pushfstring(i3, 12232, i2) | 0;
+    break;
+   }
+  } else {
+   i11 = i7 + 60 | 0;
+   i12 = HEAP32[i11 >> 2] | 0;
+   i10 = i12 + 4 | 0;
+   i13 = HEAP32[i10 >> 2] | 0;
+   i8 = i12 + 8 | 0;
+   i9 = HEAP32[i8 >> 2] | 0;
+   do {
+    if ((i13 + 1 | 0) >>> 0 > i9 >>> 0) {
+     if (i9 >>> 0 > 2147483645) {
+      _lexerror(i7, 12368, 0);
+     }
+     i7 = i9 << 1;
+     if ((i7 | 0) == -2) {
+      _luaM_toobig(i3);
+     } else {
+      i6 = _luaM_realloc_(i3, HEAP32[i12 >> 2] | 0, i9, i7) | 0;
+      HEAP32[i12 >> 2] = i6;
+      HEAP32[i8 >> 2] = i7;
+      i5 = HEAP32[i10 >> 2] | 0;
+      break;
+     }
+    } else {
+     i5 = i13;
+     i6 = HEAP32[i12 >> 2] | 0;
+    }
+   } while (0);
+   HEAP32[i10 >> 2] = i5 + 1;
+   HEAP8[i6 + i5 | 0] = 0;
+   i5 = HEAP32[i1 >> 2] | 0;
+   HEAP32[i2 >> 2] = HEAP32[HEAP32[i11 >> 2] >> 2];
+   i5 = _luaO_pushfstring(i5, 12256, i2) | 0;
+  }
+ } while (0);
+ HEAP32[i2 >> 2] = i4;
+ HEAP32[i2 + 4 >> 2] = i5;
+ _luaO_pushfstring(i3, 12608, i2) | 0;
+ i13 = HEAP32[i1 >> 2] | 0;
+ _luaD_throw(i13, 3);
+}
+function _luaV_objlen(i2, i5, i1) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i3 = STACKTOP;
+ i4 = i1 + 8 | 0;
+ i8 = HEAP32[i4 >> 2] & 15;
+ do {
+  if ((i8 | 0) == 5) {
+   i7 = HEAP32[i1 >> 2] | 0;
+   i8 = HEAP32[i7 + 8 >> 2] | 0;
+   if (((i8 | 0) != 0 ? (HEAP8[i8 + 6 | 0] & 16) == 0 : 0) ? (i6 = _luaT_gettm(i8, 4, HEAP32[(HEAP32[i2 + 12 >> 2] | 0) + 200 >> 2] | 0) | 0, (i6 | 0) != 0) : 0) {
+    i7 = i6;
+    break;
+   }
+   HEAPF64[i5 >> 3] = +(_luaH_getn(i7) | 0);
+   HEAP32[i5 + 8 >> 2] = 3;
+   STACKTOP = i3;
+   return;
+  } else if ((i8 | 0) != 4) {
+   i6 = _luaT_gettmbyobj(i2, i1, 4) | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) == 0) {
+    _luaG_typeerror(i2, i1, 9024);
+   } else {
+    i7 = i6;
+   }
+  } else {
+   HEAPF64[i5 >> 3] = +((HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0) >>> 0);
+   HEAP32[i5 + 8 >> 2] = 3;
+   STACKTOP = i3;
+   return;
+  }
+ } while (0);
+ i6 = i2 + 28 | 0;
+ i8 = i5 - (HEAP32[i6 >> 2] | 0) | 0;
+ i5 = i2 + 8 | 0;
+ i11 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i11 + 16;
+ i12 = i7;
+ i10 = HEAP32[i12 + 4 >> 2] | 0;
+ i9 = i11;
+ HEAP32[i9 >> 2] = HEAP32[i12 >> 2];
+ HEAP32[i9 + 4 >> 2] = i10;
+ HEAP32[i11 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+ i7 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i7 + 16;
+ i11 = i1;
+ i9 = HEAP32[i11 + 4 >> 2] | 0;
+ i10 = i7;
+ HEAP32[i10 >> 2] = HEAP32[i11 >> 2];
+ HEAP32[i10 + 4 >> 2] = i9;
+ HEAP32[i7 + 8 >> 2] = HEAP32[i4 >> 2];
+ i7 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i7 + 16;
+ i10 = i1;
+ i9 = HEAP32[i10 + 4 >> 2] | 0;
+ i1 = i7;
+ HEAP32[i1 >> 2] = HEAP32[i10 >> 2];
+ HEAP32[i1 + 4 >> 2] = i9;
+ HEAP32[i7 + 8 >> 2] = HEAP32[i4 >> 2];
+ _luaD_call(i2, (HEAP32[i5 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i2 + 16 >> 2] | 0) + 18 | 0] & 1);
+ i7 = HEAP32[i6 >> 2] | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ i2 = i6 + -16 | 0;
+ HEAP32[i5 >> 2] = i2;
+ i4 = HEAP32[i2 + 4 >> 2] | 0;
+ i5 = i7 + i8 | 0;
+ HEAP32[i5 >> 2] = HEAP32[i2 >> 2];
+ HEAP32[i5 + 4 >> 2] = i4;
+ HEAP32[i7 + (i8 + 8) >> 2] = HEAP32[i6 + -8 >> 2];
+ STACKTOP = i3;
+ return;
+}
+function _get_equalTM(i6, i5, i4) {
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i7 = 0;
+ i1 = STACKTOP;
+ L1 : do {
+  if (((i5 | 0) != 0 ? (HEAP8[i5 + 6 | 0] & 32) == 0 : 0) ? (i7 = i6 + 12 | 0, i2 = _luaT_gettm(i5, 5, HEAP32[(HEAP32[i7 >> 2] | 0) + 204 >> 2] | 0) | 0, (i2 | 0) != 0) : 0) {
+   if ((i5 | 0) != (i4 | 0)) {
+    if (((i4 | 0) != 0 ? (HEAP8[i4 + 6 | 0] & 32) == 0 : 0) ? (i3 = _luaT_gettm(i4, 5, HEAP32[(HEAP32[i7 >> 2] | 0) + 204 >> 2] | 0) | 0, (i3 | 0) != 0) : 0) {
+     i4 = HEAP32[i2 + 8 >> 2] | 0;
+     L9 : do {
+      if ((i4 | 0) == (HEAP32[i3 + 8 >> 2] | 0)) {
+       switch (i4 & 63 | 0) {
+       case 3:
+        {
+         i3 = +HEAPF64[i2 >> 3] == +HEAPF64[i3 >> 3] | 0;
+         break;
+        }
+       case 22:
+        {
+         i3 = (HEAP32[i2 >> 2] | 0) == (HEAP32[i3 >> 2] | 0) | 0;
+         break;
+        }
+       case 5:
+        {
+         if ((HEAP32[i2 >> 2] | 0) == (HEAP32[i3 >> 2] | 0)) {
+          break L1;
+         } else {
+          break L9;
+         }
+        }
+       case 1:
+        {
+         i3 = (HEAP32[i2 >> 2] | 0) == (HEAP32[i3 >> 2] | 0) | 0;
+         break;
+        }
+       case 4:
+        {
+         i3 = (HEAP32[i2 >> 2] | 0) == (HEAP32[i3 >> 2] | 0) | 0;
+         break;
+        }
+       case 0:
+        {
+         break L1;
+        }
+       case 7:
+        {
+         if ((HEAP32[i2 >> 2] | 0) == (HEAP32[i3 >> 2] | 0)) {
+          break L1;
+         } else {
+          break L9;
+         }
+        }
+       case 2:
+        {
+         i3 = (HEAP32[i2 >> 2] | 0) == (HEAP32[i3 >> 2] | 0) | 0;
+         break;
+        }
+       case 20:
+        {
+         i3 = _luaS_eqlngstr(HEAP32[i2 >> 2] | 0, HEAP32[i3 >> 2] | 0) | 0;
+         break;
+        }
+       default:
+        {
+         i3 = (HEAP32[i2 >> 2] | 0) == (HEAP32[i3 >> 2] | 0) | 0;
+        }
+       }
+       if ((i3 | 0) != 0) {
+        break L1;
+       }
+      }
+     } while (0);
+     i2 = 0;
+    } else {
+     i2 = 0;
+    }
+   }
+  } else {
+   i2 = 0;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _luaS_newlstr(i2, i4, i3) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i1 = STACKTOP;
+ if (!(i3 >>> 0 < 41)) {
+  if ((i3 + 1 | 0) >>> 0 > 4294967277) {
+   _luaM_toobig(i2);
+  }
+  i10 = HEAP32[(HEAP32[i2 + 12 >> 2] | 0) + 56 >> 2] | 0;
+  i11 = _luaC_newobj(i2, 20, i3 + 17 | 0, 0, 0) | 0;
+  HEAP32[i11 + 12 >> 2] = i3;
+  HEAP32[i11 + 8 >> 2] = i10;
+  HEAP8[i11 + 6 | 0] = 0;
+  i10 = i11 + 16 | 0;
+  _memcpy(i10 | 0, i4 | 0, i3 | 0) | 0;
+  HEAP8[i10 + i3 | 0] = 0;
+  STACKTOP = i1;
+  return i11 | 0;
+ }
+ i5 = HEAP32[i2 + 12 >> 2] | 0;
+ i6 = HEAP32[i5 + 56 >> 2] ^ i3;
+ i7 = (i3 >>> 5) + 1 | 0;
+ if (!(i7 >>> 0 > i3 >>> 0)) {
+  i8 = i3;
+  do {
+   i6 = (i6 << 5) + (i6 >>> 2) + (HEAPU8[i4 + (i8 + -1) | 0] | 0) ^ i6;
+   i8 = i8 - i7 | 0;
+  } while (!(i8 >>> 0 < i7 >>> 0));
+ }
+ i10 = i5 + 32 | 0;
+ i9 = HEAP32[i10 >> 2] | 0;
+ i7 = i5 + 24 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ i11 = HEAP32[i8 + ((i9 + -1 & i6) << 2) >> 2] | 0;
+ L12 : do {
+  if ((i11 | 0) != 0) {
+   while (1) {
+    if (((i6 | 0) == (HEAP32[i11 + 8 >> 2] | 0) ? (HEAP32[i11 + 12 >> 2] | 0) == (i3 | 0) : 0) ? (_memcmp(i4, i11 + 16 | 0, i3) | 0) == 0 : 0) {
+     break;
+    }
+    i11 = HEAP32[i11 >> 2] | 0;
+    if ((i11 | 0) == 0) {
+     break L12;
+    }
+   }
+   i2 = i11 + 5 | 0;
+   i3 = (HEAPU8[i2] | 0) ^ 3;
+   if ((((HEAPU8[i5 + 60 | 0] | 0) ^ 3) & i3 | 0) != 0) {
+    STACKTOP = i1;
+    return i11 | 0;
+   }
+   HEAP8[i2] = i3;
+   STACKTOP = i1;
+   return i11 | 0;
+  }
+ } while (0);
+ i5 = i5 + 28 | 0;
+ if ((HEAP32[i5 >> 2] | 0) >>> 0 >= i9 >>> 0 & (i9 | 0) < 1073741823) {
+  _luaS_resize(i2, i9 << 1);
+  i9 = HEAP32[i10 >> 2] | 0;
+  i8 = HEAP32[i7 >> 2] | 0;
+ }
+ i11 = _luaC_newobj(i2, 4, i3 + 17 | 0, i8 + ((i9 + -1 & i6) << 2) | 0, 0) | 0;
+ HEAP32[i11 + 12 >> 2] = i3;
+ HEAP32[i11 + 8 >> 2] = i6;
+ HEAP8[i11 + 6 | 0] = 0;
+ i10 = i11 + 16 | 0;
+ _memcpy(i10 | 0, i4 | 0, i3 | 0) | 0;
+ HEAP8[i10 + i3 | 0] = 0;
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 1;
+ STACKTOP = i1;
+ return i11 | 0;
+}
+function _lua_pcallk(i3, i7, i2, i9, i6, i5) {
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ i2 = i2 | 0;
+ i9 = i9 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i4 = 0, i8 = 0, i10 = 0, i11 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i1;
+ if ((i9 | 0) == 0) {
+  i9 = 0;
+ } else {
+  i10 = HEAP32[i3 + 16 >> 2] | 0;
+  do {
+   if ((i9 | 0) <= 0) {
+    if (!((i9 | 0) < -1000999)) {
+     i8 = (HEAP32[i3 + 8 >> 2] | 0) + (i9 << 4) | 0;
+     break;
+    }
+    if ((i9 | 0) == -1001e3) {
+     i8 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+     break;
+    }
+    i9 = -1001e3 - i9 | 0;
+    i10 = HEAP32[i10 >> 2] | 0;
+    if ((HEAP32[i10 + 8 >> 2] | 0) != 22 ? (i8 = HEAP32[i10 >> 2] | 0, (i9 | 0) <= (HEAPU8[i8 + 6 | 0] | 0)) : 0) {
+     i8 = i8 + (i9 + -1 << 4) + 16 | 0;
+    } else {
+     i8 = 5192;
+    }
+   } else {
+    i8 = (HEAP32[i10 >> 2] | 0) + (i9 << 4) | 0;
+    i8 = i8 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i8 : 5192;
+   }
+  } while (0);
+  i9 = i8 - (HEAP32[i3 + 28 >> 2] | 0) | 0;
+ }
+ i8 = i3 + 8 | 0;
+ i7 = (HEAP32[i8 >> 2] | 0) + (~i7 << 4) | 0;
+ HEAP32[i4 >> 2] = i7;
+ if ((i5 | 0) != 0 ? (HEAP16[i3 + 36 >> 1] | 0) == 0 : 0) {
+  i11 = HEAP32[i3 + 16 >> 2] | 0;
+  HEAP32[i11 + 28 >> 2] = i5;
+  HEAP32[i11 + 24 >> 2] = i6;
+  HEAP32[i11 + 20 >> 2] = (HEAP32[i4 >> 2] | 0) - (HEAP32[i3 + 28 >> 2] | 0);
+  HEAP8[i11 + 36 | 0] = HEAP8[i3 + 41 | 0] | 0;
+  i10 = i3 + 68 | 0;
+  i7 = i11 + 32 | 0;
+  HEAP32[i7 >> 2] = HEAP32[i10 >> 2];
+  HEAP32[i10 >> 2] = i9;
+  i9 = i11 + 18 | 0;
+  HEAP8[i9] = HEAPU8[i9] | 16;
+  _luaD_call(i3, HEAP32[i4 >> 2] | 0, i2, 1);
+  HEAP8[i9] = HEAP8[i9] & 239;
+  HEAP32[i10 >> 2] = HEAP32[i7 >> 2];
+  i4 = 0;
+ } else {
+  HEAP32[i4 + 4 >> 2] = i2;
+  i4 = _luaD_pcall(i3, 3, i4, i7 - (HEAP32[i3 + 28 >> 2] | 0) | 0, i9) | 0;
+ }
+ if (!((i2 | 0) == -1)) {
+  STACKTOP = i1;
+  return i4 | 0;
+ }
+ i2 = (HEAP32[i3 + 16 >> 2] | 0) + 4 | 0;
+ i3 = HEAP32[i8 >> 2] | 0;
+ if (!((HEAP32[i2 >> 2] | 0) >>> 0 < i3 >>> 0)) {
+  STACKTOP = i1;
+  return i4 | 0;
+ }
+ HEAP32[i2 >> 2] = i3;
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _lua_getupvalue(i1, i6, i3) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ i5 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i4 = (HEAP32[i1 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i4 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i6 = -1001e3 - i6 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i5 >> 2] | 0, (i6 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i4 + (i6 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i5 >> 2] | 0) + (i6 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i5 = HEAP32[i4 + 8 >> 2] & 63;
+ do {
+  if ((i5 | 0) == 38) {
+   i5 = HEAP32[i4 >> 2] | 0;
+   if ((i3 | 0) <= 0) {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+   if ((HEAPU8[i5 + 6 | 0] | 0 | 0) < (i3 | 0)) {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   } else {
+    i4 = 936;
+    i3 = i5 + (i3 + -1 << 4) + 16 | 0;
+    break;
+   }
+  } else if ((i5 | 0) == 6) {
+   i5 = HEAP32[i4 >> 2] | 0;
+   i4 = HEAP32[i5 + 12 >> 2] | 0;
+   if ((i3 | 0) <= 0) {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+   if ((HEAP32[i4 + 40 >> 2] | 0) < (i3 | 0)) {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+   i6 = i3 + -1 | 0;
+   i3 = HEAP32[(HEAP32[i5 + 16 + (i6 << 2) >> 2] | 0) + 8 >> 2] | 0;
+   i4 = HEAP32[(HEAP32[i4 + 28 >> 2] | 0) + (i6 << 3) >> 2] | 0;
+   if ((i4 | 0) == 0) {
+    i4 = 936;
+   } else {
+    i4 = i4 + 16 | 0;
+   }
+  } else {
+   i6 = 0;
+   STACKTOP = i2;
+   return i6 | 0;
+  }
+ } while (0);
+ i6 = i1 + 8 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ i8 = i3;
+ i7 = HEAP32[i8 + 4 >> 2] | 0;
+ i1 = i5;
+ HEAP32[i1 >> 2] = HEAP32[i8 >> 2];
+ HEAP32[i1 + 4 >> 2] = i7;
+ HEAP32[i5 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+ HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 16;
+ i6 = i4;
+ STACKTOP = i2;
+ return i6 | 0;
+}
+function _lua_copy(i1, i8, i4) {
+ i1 = i1 | 0;
+ i8 = i8 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i9 = 0;
+ i2 = STACKTOP;
+ i3 = i1 + 16 | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ do {
+  if ((i8 | 0) <= 0) {
+   if (!((i8 | 0) < -1000999)) {
+    i7 = (HEAP32[i1 + 8 >> 2] | 0) + (i8 << 4) | 0;
+    break;
+   }
+   if ((i8 | 0) == -1001e3) {
+    i7 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i8 = -1001e3 - i8 | 0;
+   i9 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i9 + 8 >> 2] | 0) != 22 ? (i7 = HEAP32[i9 >> 2] | 0, (i8 | 0) <= (HEAPU8[i7 + 6 | 0] | 0 | 0)) : 0) {
+    i7 = i7 + (i8 + -1 << 4) + 16 | 0;
+   } else {
+    i7 = 5192;
+   }
+  } else {
+   i7 = (HEAP32[i6 >> 2] | 0) + (i8 << 4) | 0;
+   i7 = i7 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i7 : 5192;
+  }
+ } while (0);
+ do {
+  if ((i4 | 0) <= 0) {
+   if (!((i4 | 0) < -1000999)) {
+    i5 = (HEAP32[i1 + 8 >> 2] | 0) + (i4 << 4) | 0;
+    break;
+   }
+   if ((i4 | 0) == -1001e3) {
+    i5 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i8 = -1001e3 - i4 | 0;
+   i6 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) != 22 ? (i5 = HEAP32[i6 >> 2] | 0, (i8 | 0) <= (HEAPU8[i5 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i5 + (i8 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i5 = (HEAP32[i6 >> 2] | 0) + (i4 << 4) | 0;
+   i5 = i5 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i5 : 5192;
+  }
+ } while (0);
+ i8 = i7;
+ i9 = HEAP32[i8 + 4 >> 2] | 0;
+ i6 = i5;
+ HEAP32[i6 >> 2] = HEAP32[i8 >> 2];
+ HEAP32[i6 + 4 >> 2] = i9;
+ i6 = i7 + 8 | 0;
+ HEAP32[i5 + 8 >> 2] = HEAP32[i6 >> 2];
+ if (!((i4 | 0) < -1001e3)) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP32[i6 >> 2] & 64 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i4 = HEAP32[i7 >> 2] | 0;
+ if ((HEAP8[i4 + 5 | 0] & 3) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = HEAP32[HEAP32[HEAP32[i3 >> 2] >> 2] >> 2] | 0;
+ if ((HEAP8[i3 + 5 | 0] & 4) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ _luaC_barrier_(i1, i3, i4);
+ STACKTOP = i2;
+ return;
+}
+function _lua_tolstring(i4, i5, i1) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i2 = STACKTOP;
+ i7 = i4 + 16 | 0;
+ i10 = HEAP32[i7 >> 2] | 0;
+ i6 = (i5 | 0) > 0;
+ do {
+  if (!i6) {
+   if (!((i5 | 0) < -1000999)) {
+    i8 = (HEAP32[i4 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i8 = (HEAP32[i4 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i9 = -1001e3 - i5 | 0;
+   i10 = HEAP32[i10 >> 2] | 0;
+   if ((HEAP32[i10 + 8 >> 2] | 0) != 22 ? (i8 = HEAP32[i10 >> 2] | 0, (i9 | 0) <= (HEAPU8[i8 + 6 | 0] | 0 | 0)) : 0) {
+    i8 = i8 + (i9 + -1 << 4) + 16 | 0;
+   } else {
+    i8 = 5192;
+   }
+  } else {
+   i8 = (HEAP32[i10 >> 2] | 0) + (i5 << 4) | 0;
+   i8 = i8 >>> 0 < (HEAP32[i4 + 8 >> 2] | 0) >>> 0 ? i8 : 5192;
+  }
+ } while (0);
+ do {
+  if ((HEAP32[i8 + 8 >> 2] & 15 | 0) != 4) {
+   if ((_luaV_tostring(i4, i8) | 0) == 0) {
+    if ((i1 | 0) == 0) {
+     i10 = 0;
+     STACKTOP = i2;
+     return i10 | 0;
+    }
+    HEAP32[i1 >> 2] = 0;
+    i10 = 0;
+    STACKTOP = i2;
+    return i10 | 0;
+   }
+   i8 = i4 + 12 | 0;
+   if ((HEAP32[(HEAP32[i8 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+    _luaC_step(i4);
+   }
+   i7 = HEAP32[i7 >> 2] | 0;
+   if (i6) {
+    i3 = (HEAP32[i7 >> 2] | 0) + (i5 << 4) | 0;
+    i8 = i3 >>> 0 < (HEAP32[i4 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+    break;
+   }
+   if (!((i5 | 0) < -1000999)) {
+    i8 = (HEAP32[i4 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i8 = (HEAP32[i8 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i4 = -1001e3 - i5 | 0;
+   i5 = HEAP32[i7 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i5 >> 2] | 0, (i4 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i8 = i3 + (i4 + -1 << 4) + 16 | 0;
+   } else {
+    i8 = 5192;
+   }
+  }
+ } while (0);
+ i3 = HEAP32[i8 >> 2] | 0;
+ if ((i1 | 0) != 0) {
+  HEAP32[i1 >> 2] = HEAP32[i3 + 12 >> 2];
+ }
+ i10 = i3 + 16 | 0;
+ STACKTOP = i2;
+ return i10 | 0;
+}
+function _luaD_pcall(i3, i6, i5, i13, i14) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i13 = i13 | 0;
+ i14 = i14 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0;
+ i1 = STACKTOP;
+ i10 = i3 + 16 | 0;
+ i11 = HEAP32[i10 >> 2] | 0;
+ i12 = i3 + 41 | 0;
+ i7 = HEAP8[i12] | 0;
+ i9 = i3 + 36 | 0;
+ i8 = HEAP16[i9 >> 1] | 0;
+ i4 = i3 + 68 | 0;
+ i2 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i4 >> 2] = i14;
+ i5 = _luaD_rawrunprotected(i3, i6, i5) | 0;
+ if ((i5 | 0) == 0) {
+  HEAP32[i4 >> 2] = i2;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ i6 = i3 + 28 | 0;
+ i14 = HEAP32[i6 >> 2] | 0;
+ i15 = i14 + i13 | 0;
+ _luaF_close(i3, i15);
+ if ((i5 | 0) == 6) {
+  i16 = _luaS_newlstr(i3, 2424, 23) | 0;
+  HEAP32[i15 >> 2] = i16;
+  HEAP32[i14 + (i13 + 8) >> 2] = HEAPU8[i16 + 4 | 0] | 0 | 64;
+ } else if ((i5 | 0) == 4) {
+  i16 = HEAP32[(HEAP32[i3 + 12 >> 2] | 0) + 180 >> 2] | 0;
+  HEAP32[i15 >> 2] = i16;
+  HEAP32[i14 + (i13 + 8) >> 2] = HEAPU8[i16 + 4 | 0] | 0 | 64;
+ } else {
+  i16 = HEAP32[i3 + 8 >> 2] | 0;
+  i18 = i16 + -16 | 0;
+  i17 = HEAP32[i18 + 4 >> 2] | 0;
+  HEAP32[i15 >> 2] = HEAP32[i18 >> 2];
+  HEAP32[i15 + 4 >> 2] = i17;
+  HEAP32[i14 + (i13 + 8) >> 2] = HEAP32[i16 + -8 >> 2];
+ }
+ i13 = i14 + (i13 + 16) | 0;
+ HEAP32[i3 + 8 >> 2] = i13;
+ HEAP32[i10 >> 2] = i11;
+ HEAP8[i12] = i7;
+ HEAP16[i9 >> 1] = i8;
+ if ((i11 | 0) != 0) {
+  do {
+   i7 = HEAP32[i11 + 4 >> 2] | 0;
+   i13 = i13 >>> 0 < i7 >>> 0 ? i7 : i13;
+   i11 = HEAP32[i11 + 8 >> 2] | 0;
+  } while ((i11 | 0) != 0);
+ }
+ i6 = i13 - (HEAP32[i6 >> 2] | 0) | 0;
+ i7 = (i6 >> 4) + 1 | 0;
+ i7 = ((i7 | 0) / 8 | 0) + 10 + i7 | 0;
+ i7 = (i7 | 0) > 1e6 ? 1e6 : i7;
+ if ((i6 | 0) > 15999984) {
+  HEAP32[i4 >> 2] = i2;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ if ((i7 | 0) >= (HEAP32[i3 + 32 >> 2] | 0)) {
+  HEAP32[i4 >> 2] = i2;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ _luaD_reallocstack(i3, i7);
+ HEAP32[i4 >> 2] = i2;
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _luaH_resize(i1, i4, i6, i9) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i9 = i9 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0;
+ i3 = STACKTOP;
+ i8 = i4 + 28 | 0;
+ i5 = HEAP32[i8 >> 2] | 0;
+ i7 = HEAPU8[i4 + 7 | 0] | 0;
+ i2 = HEAP32[i4 + 16 >> 2] | 0;
+ if ((i5 | 0) < (i6 | 0)) {
+  if ((i6 + 1 | 0) >>> 0 > 268435455) {
+   _luaM_toobig(i1);
+  }
+  i11 = i4 + 12 | 0;
+  i10 = _luaM_realloc_(i1, HEAP32[i11 >> 2] | 0, i5 << 4, i6 << 4) | 0;
+  HEAP32[i11 >> 2] = i10;
+  i11 = HEAP32[i8 >> 2] | 0;
+  if ((i11 | 0) < (i6 | 0)) {
+   do {
+    HEAP32[i10 + (i11 << 4) + 8 >> 2] = 0;
+    i11 = i11 + 1 | 0;
+   } while ((i11 | 0) != (i6 | 0));
+  }
+  HEAP32[i8 >> 2] = i6;
+ }
+ _setnodevector(i1, i4, i9);
+ do {
+  if ((i5 | 0) > (i6 | 0)) {
+   HEAP32[i8 >> 2] = i6;
+   i8 = i4 + 12 | 0;
+   i9 = i6;
+   do {
+    i10 = HEAP32[i8 >> 2] | 0;
+    if ((HEAP32[i10 + (i9 << 4) + 8 >> 2] | 0) == 0) {
+     i9 = i9 + 1 | 0;
+    } else {
+     i11 = i9 + 1 | 0;
+     _luaH_setint(i1, i4, i11, i10 + (i9 << 4) | 0);
+     i9 = i11;
+    }
+   } while ((i9 | 0) != (i5 | 0));
+   if ((i6 + 1 | 0) >>> 0 > 268435455) {
+    _luaM_toobig(i1);
+   } else {
+    i11 = i4 + 12 | 0;
+    HEAP32[i11 >> 2] = _luaM_realloc_(i1, HEAP32[i11 >> 2] | 0, i5 << 4, i6 << 4) | 0;
+    break;
+   }
+  }
+ } while (0);
+ i5 = 1 << i7;
+ if ((i5 | 0) > 0) {
+  i6 = i5;
+  do {
+   i6 = i6 + -1 | 0;
+   i7 = i2 + (i6 << 5) + 8 | 0;
+   if ((HEAP32[i7 >> 2] | 0) != 0) {
+    i8 = i2 + (i6 << 5) + 16 | 0;
+    i9 = _luaH_get(i4, i8) | 0;
+    if ((i9 | 0) == 5192) {
+     i9 = _luaH_newkey(i1, i4, i8) | 0;
+    }
+    i8 = i2 + (i6 << 5) | 0;
+    i10 = HEAP32[i8 + 4 >> 2] | 0;
+    i11 = i9;
+    HEAP32[i11 >> 2] = HEAP32[i8 >> 2];
+    HEAP32[i11 + 4 >> 2] = i10;
+    HEAP32[i9 + 8 >> 2] = HEAP32[i7 >> 2];
+   }
+  } while ((i6 | 0) > 0);
+ }
+ if ((i2 | 0) == 8016) {
+  STACKTOP = i3;
+  return;
+ }
+ _luaM_realloc_(i1, i2, i5 << 5, 0) | 0;
+ STACKTOP = i3;
+ return;
+}
+function _codearith(i4, i3, i2, i6, i5) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, d13 = 0.0;
+ i7 = STACKTOP;
+ if (((((((HEAP32[i2 >> 2] | 0) == 5 ? (HEAP32[i2 + 16 >> 2] | 0) == -1 : 0) ? (HEAP32[i2 + 20 >> 2] | 0) == -1 : 0) ? (HEAP32[i6 >> 2] | 0) == 5 : 0) ? (HEAP32[i6 + 16 >> 2] | 0) == -1 : 0) ? (HEAP32[i6 + 20 >> 2] | 0) == -1 : 0) ? (d13 = +HEAPF64[i6 + 8 >> 3], !((i3 & -2 | 0) == 16 & d13 == 0.0)) : 0) {
+  i12 = i2 + 8 | 0;
+  HEAPF64[i12 >> 3] = +_luaO_arith(i3 + -13 | 0, +HEAPF64[i12 >> 3], d13);
+  STACKTOP = i7;
+  return;
+ }
+ if ((i3 | 0) == 19 | (i3 | 0) == 21) {
+  i11 = 0;
+ } else {
+  i11 = _luaK_exp2RK(i4, i6) | 0;
+ }
+ i12 = _luaK_exp2RK(i4, i2) | 0;
+ if ((i12 | 0) > (i11 | 0)) {
+  if (((HEAP32[i2 >> 2] | 0) == 6 ? (i8 = HEAP32[i2 + 8 >> 2] | 0, (i8 & 256 | 0) == 0) : 0) ? (HEAPU8[i4 + 46 | 0] | 0 | 0) <= (i8 | 0) : 0) {
+   i10 = i4 + 48 | 0;
+   HEAP8[i10] = (HEAP8[i10] | 0) + -1 << 24 >> 24;
+  }
+  if (((HEAP32[i6 >> 2] | 0) == 6 ? (i1 = HEAP32[i6 + 8 >> 2] | 0, (i1 & 256 | 0) == 0) : 0) ? (HEAPU8[i4 + 46 | 0] | 0 | 0) <= (i1 | 0) : 0) {
+   i10 = i4 + 48 | 0;
+   HEAP8[i10] = (HEAP8[i10] | 0) + -1 << 24 >> 24;
+  }
+ } else {
+  if (((HEAP32[i6 >> 2] | 0) == 6 ? (i10 = HEAP32[i6 + 8 >> 2] | 0, (i10 & 256 | 0) == 0) : 0) ? (HEAPU8[i4 + 46 | 0] | 0 | 0) <= (i10 | 0) : 0) {
+   i10 = i4 + 48 | 0;
+   HEAP8[i10] = (HEAP8[i10] | 0) + -1 << 24 >> 24;
+  }
+  if (((HEAP32[i2 >> 2] | 0) == 6 ? (i9 = HEAP32[i2 + 8 >> 2] | 0, (i9 & 256 | 0) == 0) : 0) ? (HEAPU8[i4 + 46 | 0] | 0 | 0) <= (i9 | 0) : 0) {
+   i10 = i4 + 48 | 0;
+   HEAP8[i10] = (HEAP8[i10] | 0) + -1 << 24 >> 24;
+  }
+ }
+ HEAP32[i2 + 8 >> 2] = _luaK_code(i4, i11 << 14 | i3 | i12 << 23) | 0;
+ HEAP32[i2 >> 2] = 11;
+ HEAP32[(HEAP32[(HEAP32[i4 >> 2] | 0) + 20 >> 2] | 0) + ((HEAP32[i4 + 20 >> 2] | 0) + -1 << 2) >> 2] = i5;
+ STACKTOP = i7;
+ return;
+}
+function _GCTM(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i2 = i4 + 16 | 0;
+ i5 = i4;
+ i6 = HEAP32[i1 + 12 >> 2] | 0;
+ i9 = i6 + 104 | 0;
+ i8 = HEAP32[i9 >> 2] | 0;
+ HEAP32[i9 >> 2] = HEAP32[i8 >> 2];
+ i9 = i6 + 68 | 0;
+ HEAP32[i8 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i9 >> 2] = i8;
+ i9 = i8 + 5 | 0;
+ i7 = HEAPU8[i9] | 0;
+ HEAP8[i9] = i7 & 239;
+ if ((HEAPU8[i6 + 61 | 0] | 0) >= 2) {
+  HEAP8[i9] = HEAP8[i6 + 60 | 0] & 3 | i7 & 168;
+ }
+ HEAP32[i5 >> 2] = i8;
+ i7 = i5 + 8 | 0;
+ HEAP32[i7 >> 2] = HEAPU8[i8 + 4 | 0] | 0 | 64;
+ i8 = _luaT_gettmbyobj(i1, i5, 2) | 0;
+ if ((i8 | 0) == 0) {
+  STACKTOP = i4;
+  return;
+ }
+ i9 = i8 + 8 | 0;
+ if ((HEAP32[i9 >> 2] & 15 | 0) != 6) {
+  STACKTOP = i4;
+  return;
+ }
+ i12 = i1 + 41 | 0;
+ i13 = HEAP8[i12] | 0;
+ i10 = i6 + 63 | 0;
+ i11 = HEAP8[i10] | 0;
+ HEAP8[i12] = 0;
+ HEAP8[i10] = 0;
+ i6 = i1 + 8 | 0;
+ i14 = HEAP32[i6 >> 2] | 0;
+ i16 = i8;
+ i15 = HEAP32[i16 + 4 >> 2] | 0;
+ i8 = i14;
+ HEAP32[i8 >> 2] = HEAP32[i16 >> 2];
+ HEAP32[i8 + 4 >> 2] = i15;
+ HEAP32[i14 + 8 >> 2] = HEAP32[i9 >> 2];
+ i9 = HEAP32[i6 >> 2] | 0;
+ i14 = i5;
+ i8 = HEAP32[i14 + 4 >> 2] | 0;
+ i5 = i9 + 16 | 0;
+ HEAP32[i5 >> 2] = HEAP32[i14 >> 2];
+ HEAP32[i5 + 4 >> 2] = i8;
+ HEAP32[i9 + 24 >> 2] = HEAP32[i7 >> 2];
+ i5 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i6 >> 2] = i5 + 32;
+ i5 = _luaD_pcall(i1, 7, 0, i5 - (HEAP32[i1 + 28 >> 2] | 0) | 0, 0) | 0;
+ HEAP8[i12] = i13;
+ HEAP8[i10] = i11;
+ if ((i5 | 0) == 0 | (i3 | 0) == 0) {
+  STACKTOP = i4;
+  return;
+ }
+ if ((i5 | 0) != 2) {
+  i16 = i5;
+  _luaD_throw(i1, i16);
+ }
+ i3 = HEAP32[i6 >> 2] | 0;
+ if ((HEAP32[i3 + -8 >> 2] & 15 | 0) == 4) {
+  i3 = (HEAP32[i3 + -16 >> 2] | 0) + 16 | 0;
+ } else {
+  i3 = 2528;
+ }
+ HEAP32[i2 >> 2] = i3;
+ _luaO_pushfstring(i1, 2544, i2) | 0;
+ i16 = 5;
+ _luaD_throw(i1, i16);
+}
+function _lua_gc(i3, i5, i4) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0;
+ i1 = STACKTOP;
+ i2 = HEAP32[i3 + 12 >> 2] | 0;
+ L1 : do {
+  switch (i5 | 0) {
+  case 8:
+   {
+    i5 = i2 + 160 | 0;
+    i2 = HEAP32[i5 >> 2] | 0;
+    HEAP32[i5 >> 2] = i4;
+    break;
+   }
+  case 11:
+   {
+    _luaC_changemode(i3, 0);
+    i2 = 0;
+    break;
+   }
+  case 2:
+   {
+    _luaC_fullgc(i3, 0);
+    i2 = 0;
+    break;
+   }
+  case 5:
+   {
+    if ((HEAP8[i2 + 62 | 0] | 0) == 2) {
+     i2 = (HEAP32[i2 + 20 >> 2] | 0) == 0 | 0;
+     _luaC_forcestep(i3);
+     break L1;
+    }
+    i4 = (i4 << 10) + -1600 | 0;
+    if ((HEAP8[i2 + 63 | 0] | 0) == 0) {
+     i5 = i4;
+     _luaE_setdebt(i2, i5);
+     _luaC_forcestep(i3);
+     i5 = i2 + 61 | 0;
+     i5 = HEAP8[i5] | 0;
+     i5 = i5 << 24 >> 24 == 5;
+     i5 = i5 & 1;
+     STACKTOP = i1;
+     return i5 | 0;
+    }
+    i5 = (HEAP32[i2 + 12 >> 2] | 0) + i4 | 0;
+    _luaE_setdebt(i2, i5);
+    _luaC_forcestep(i3);
+    i5 = i2 + 61 | 0;
+    i5 = HEAP8[i5] | 0;
+    i5 = i5 << 24 >> 24 == 5;
+    i5 = i5 & 1;
+    STACKTOP = i1;
+    return i5 | 0;
+   }
+  case 4:
+   {
+    i2 = (HEAP32[i2 + 12 >> 2] | 0) + (HEAP32[i2 + 8 >> 2] | 0) & 1023;
+    break;
+   }
+  case 1:
+   {
+    _luaE_setdebt(i2, 0);
+    HEAP8[i2 + 63 | 0] = 1;
+    i2 = 0;
+    break;
+   }
+  case 3:
+   {
+    i2 = ((HEAP32[i2 + 12 >> 2] | 0) + (HEAP32[i2 + 8 >> 2] | 0) | 0) >>> 10;
+    break;
+   }
+  case 7:
+   {
+    i5 = i2 + 164 | 0;
+    i2 = HEAP32[i5 >> 2] | 0;
+    HEAP32[i5 >> 2] = i4;
+    break;
+   }
+  case 0:
+   {
+    HEAP8[i2 + 63 | 0] = 0;
+    i2 = 0;
+    break;
+   }
+  case 6:
+   {
+    i5 = i2 + 156 | 0;
+    i2 = HEAP32[i5 >> 2] | 0;
+    HEAP32[i5 >> 2] = i4;
+    break;
+   }
+  case 9:
+   {
+    i2 = HEAPU8[i2 + 63 | 0] | 0;
+    break;
+   }
+  case 10:
+   {
+    _luaC_changemode(i3, 2);
+    i2 = 0;
+    break;
+   }
+  default:
+   {
+    i2 = -1;
+   }
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _os_time(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i4 = i2;
+ i5 = i2 + 48 | 0;
+ i3 = i2 + 4 | 0;
+ if ((_lua_type(i1, 1) | 0) < 1) {
+  i3 = _time(0) | 0;
+ } else {
+  _luaL_checktype(i1, 1, 5);
+  _lua_settop(i1, 1);
+  _lua_getfield(i1, -1, 5864);
+  i6 = _lua_tointegerx(i1, -1, i4) | 0;
+  i6 = (HEAP32[i4 >> 2] | 0) == 0 ? 0 : i6;
+  _lua_settop(i1, -2);
+  HEAP32[i3 >> 2] = i6;
+  _lua_getfield(i1, -1, 5872);
+  i6 = _lua_tointegerx(i1, -1, i4) | 0;
+  i6 = (HEAP32[i4 >> 2] | 0) == 0 ? 0 : i6;
+  _lua_settop(i1, -2);
+  HEAP32[i3 + 4 >> 2] = i6;
+  _lua_getfield(i1, -1, 5880);
+  i6 = _lua_tointegerx(i1, -1, i4) | 0;
+  i6 = (HEAP32[i4 >> 2] | 0) == 0 ? 12 : i6;
+  _lua_settop(i1, -2);
+  HEAP32[i3 + 8 >> 2] = i6;
+  _lua_getfield(i1, -1, 5888);
+  i6 = _lua_tointegerx(i1, -1, i5) | 0;
+  if ((HEAP32[i5 >> 2] | 0) == 0) {
+   HEAP32[i4 >> 2] = 5888;
+   i6 = _luaL_error(i1, 5920, i4) | 0;
+  } else {
+   _lua_settop(i1, -2);
+  }
+  HEAP32[i3 + 12 >> 2] = i6;
+  _lua_getfield(i1, -1, 5896);
+  i6 = _lua_tointegerx(i1, -1, i5) | 0;
+  if ((HEAP32[i5 >> 2] | 0) == 0) {
+   HEAP32[i4 >> 2] = 5896;
+   i6 = _luaL_error(i1, 5920, i4) | 0;
+  } else {
+   _lua_settop(i1, -2);
+  }
+  HEAP32[i3 + 16 >> 2] = i6 + -1;
+  _lua_getfield(i1, -1, 5904);
+  i6 = _lua_tointegerx(i1, -1, i5) | 0;
+  if ((HEAP32[i5 >> 2] | 0) == 0) {
+   HEAP32[i4 >> 2] = 5904;
+   i6 = _luaL_error(i1, 5920, i4) | 0;
+  } else {
+   _lua_settop(i1, -2);
+  }
+  HEAP32[i3 + 20 >> 2] = i6 + -1900;
+  _lua_getfield(i1, -1, 5912);
+  if ((_lua_type(i1, -1) | 0) == 0) {
+   i4 = -1;
+  } else {
+   i4 = _lua_toboolean(i1, -1) | 0;
+  }
+  _lua_settop(i1, -2);
+  HEAP32[i3 + 32 >> 2] = i4;
+  i3 = _mktime(i3 | 0) | 0;
+ }
+ if ((i3 | 0) == -1) {
+  _lua_pushnil(i1);
+  STACKTOP = i2;
+  return 1;
+ } else {
+  _lua_pushnumber(i1, +(i3 | 0));
+  STACKTOP = i2;
+  return 1;
+ }
+ return 0;
+}
+function _addk(i6, i4, i3) {
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i10 = i1;
+ i2 = HEAP32[(HEAP32[i6 + 12 >> 2] | 0) + 52 >> 2] | 0;
+ i8 = _luaH_set(i2, HEAP32[i6 + 4 >> 2] | 0, i4) | 0;
+ i4 = HEAP32[i6 >> 2] | 0;
+ i9 = i8 + 8 | 0;
+ if (((HEAP32[i9 >> 2] | 0) == 3 ? (HEAPF64[i10 >> 3] = +HEAPF64[i8 >> 3] + 6755399441055744.0, i7 = HEAP32[i10 >> 2] | 0, i5 = HEAP32[i4 + 8 >> 2] | 0, (HEAP32[i5 + (i7 << 4) + 8 >> 2] | 0) == (HEAP32[i3 + 8 >> 2] | 0)) : 0) ? (_luaV_equalobj_(0, i5 + (i7 << 4) | 0, i3) | 0) != 0 : 0) {
+  i10 = i7;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ i5 = i4 + 44 | 0;
+ i10 = HEAP32[i5 >> 2] | 0;
+ i7 = i6 + 32 | 0;
+ i6 = HEAP32[i7 >> 2] | 0;
+ HEAPF64[i8 >> 3] = +(i6 | 0);
+ HEAP32[i9 >> 2] = 3;
+ i9 = HEAP32[i5 >> 2] | 0;
+ if ((i6 | 0) >= (i9 | 0)) {
+  i9 = i4 + 8 | 0;
+  HEAP32[i9 >> 2] = _luaM_growaux_(i2, HEAP32[i9 >> 2] | 0, i5, 16, 67108863, 10600) | 0;
+  i9 = HEAP32[i5 >> 2] | 0;
+ }
+ i8 = HEAP32[i4 + 8 >> 2] | 0;
+ if ((i10 | 0) < (i9 | 0)) {
+  while (1) {
+   i9 = i10 + 1 | 0;
+   HEAP32[i8 + (i10 << 4) + 8 >> 2] = 0;
+   if ((i9 | 0) < (HEAP32[i5 >> 2] | 0)) {
+    i10 = i9;
+   } else {
+    break;
+   }
+  }
+ }
+ i5 = i3;
+ i9 = HEAP32[i5 + 4 >> 2] | 0;
+ i10 = i8 + (i6 << 4) | 0;
+ HEAP32[i10 >> 2] = HEAP32[i5 >> 2];
+ HEAP32[i10 + 4 >> 2] = i9;
+ i10 = i3 + 8 | 0;
+ HEAP32[i8 + (i6 << 4) + 8 >> 2] = HEAP32[i10 >> 2];
+ HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + 1;
+ if ((HEAP32[i10 >> 2] & 64 | 0) == 0) {
+  i10 = i6;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ i3 = HEAP32[i3 >> 2] | 0;
+ if ((HEAP8[i3 + 5 | 0] & 3) == 0) {
+  i10 = i6;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ if ((HEAP8[i4 + 5 | 0] & 4) == 0) {
+  i10 = i6;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ _luaC_barrier_(i2, i4, i3);
+ i10 = i6;
+ STACKTOP = i1;
+ return i10 | 0;
+}
+function _singlevaraux(i5, i4, i2, i11) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i11 = i11 | 0;
+ var i1 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ if ((i5 | 0) == 0) {
+  i11 = 0;
+  STACKTOP = i1;
+  return i11 | 0;
+ }
+ i7 = i5 + 12 | 0;
+ i8 = i5 + 40 | 0;
+ i9 = HEAPU8[i5 + 46 | 0] | 0;
+ while (1) {
+  i6 = i9 + -1 | 0;
+  i10 = HEAP32[i5 >> 2] | 0;
+  if ((i9 | 0) <= 0) {
+   break;
+  }
+  if ((_luaS_eqstr(i4, HEAP32[(HEAP32[i10 + 24 >> 2] | 0) + ((HEAP16[(HEAP32[HEAP32[(HEAP32[i7 >> 2] | 0) + 64 >> 2] >> 2] | 0) + ((HEAP32[i8 >> 2] | 0) + i6 << 1) >> 1] | 0) * 12 | 0) >> 2] | 0) | 0) == 0) {
+   i9 = i6;
+  } else {
+   i3 = 5;
+   break;
+  }
+ }
+ if ((i3 | 0) == 5) {
+  HEAP32[i2 + 16 >> 2] = -1;
+  HEAP32[i2 + 20 >> 2] = -1;
+  HEAP32[i2 >> 2] = 7;
+  HEAP32[i2 + 8 >> 2] = i6;
+  if ((i11 | 0) != 0) {
+   i11 = 7;
+   STACKTOP = i1;
+   return i11 | 0;
+  }
+  i2 = i5 + 16 | 0;
+  do {
+   i2 = HEAP32[i2 >> 2] | 0;
+  } while ((HEAPU8[i2 + 8 | 0] | 0) > (i6 | 0));
+  HEAP8[i2 + 9 | 0] = 1;
+  i11 = 7;
+  STACKTOP = i1;
+  return i11 | 0;
+ }
+ i7 = HEAP32[i10 + 28 >> 2] | 0;
+ i6 = i5 + 47 | 0;
+ L17 : do {
+  if ((HEAP8[i6] | 0) != 0) {
+   i8 = 0;
+   while (1) {
+    i9 = i8 + 1 | 0;
+    if ((_luaS_eqstr(HEAP32[i7 + (i8 << 3) >> 2] | 0, i4) | 0) != 0) {
+     break;
+    }
+    if ((i9 | 0) < (HEAPU8[i6] | 0)) {
+     i8 = i9;
+    } else {
+     i3 = 13;
+     break L17;
+    }
+   }
+   if ((i8 | 0) < 0) {
+    i3 = 13;
+   }
+  } else {
+   i3 = 13;
+  }
+ } while (0);
+ do {
+  if ((i3 | 0) == 13) {
+   if ((_singlevaraux(HEAP32[i5 + 8 >> 2] | 0, i4, i2, 0) | 0) == 0) {
+    i11 = 0;
+    STACKTOP = i1;
+    return i11 | 0;
+   } else {
+    i8 = _newupvalue(i5, i4, i2) | 0;
+    break;
+   }
+  }
+ } while (0);
+ HEAP32[i2 + 16 >> 2] = -1;
+ HEAP32[i2 + 20 >> 2] = -1;
+ HEAP32[i2 >> 2] = 8;
+ HEAP32[i2 + 8 >> 2] = i8;
+ i11 = 8;
+ STACKTOP = i1;
+ return i11 | 0;
+}
+function _mainposition(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ switch (HEAP32[i3 + 8 >> 2] & 63 | 0) {
+ case 3:
+  {
+   HEAPF64[i4 >> 3] = +HEAPF64[i3 >> 3] + 1.0;
+   i3 = (HEAP32[i4 + 4 >> 2] | 0) + (HEAP32[i4 >> 2] | 0) | 0;
+   if ((i3 | 0) < 0) {
+    i4 = 0 - i3 | 0;
+    i3 = (i3 | 0) == (i4 | 0) ? 0 : i4;
+   }
+   i5 = (HEAP32[i1 + 16 >> 2] | 0) + (((i3 | 0) % ((1 << HEAPU8[i1 + 7 | 0]) + -1 | 1 | 0) | 0) << 5) | 0;
+   STACKTOP = i2;
+   return i5 | 0;
+  }
+ case 2:
+  {
+   i5 = (HEAP32[i1 + 16 >> 2] | 0) + ((((HEAP32[i3 >> 2] | 0) >>> 0) % (((1 << HEAPU8[i1 + 7 | 0]) + -1 | 1) >>> 0) | 0) << 5) | 0;
+   STACKTOP = i2;
+   return i5 | 0;
+  }
+ case 20:
+  {
+   i5 = HEAP32[i3 >> 2] | 0;
+   i4 = i5 + 6 | 0;
+   if ((HEAP8[i4] | 0) == 0) {
+    i6 = i5 + 8 | 0;
+    HEAP32[i6 >> 2] = _luaS_hash(i5 + 16 | 0, HEAP32[i5 + 12 >> 2] | 0, HEAP32[i6 >> 2] | 0) | 0;
+    HEAP8[i4] = 1;
+    i5 = HEAP32[i3 >> 2] | 0;
+   }
+   i6 = (HEAP32[i1 + 16 >> 2] | 0) + (((1 << HEAPU8[i1 + 7 | 0]) + -1 & HEAP32[i5 + 8 >> 2]) << 5) | 0;
+   STACKTOP = i2;
+   return i6 | 0;
+  }
+ case 22:
+  {
+   i6 = (HEAP32[i1 + 16 >> 2] | 0) + ((((HEAP32[i3 >> 2] | 0) >>> 0) % (((1 << HEAPU8[i1 + 7 | 0]) + -1 | 1) >>> 0) | 0) << 5) | 0;
+   STACKTOP = i2;
+   return i6 | 0;
+  }
+ case 4:
+  {
+   i6 = (HEAP32[i1 + 16 >> 2] | 0) + (((1 << HEAPU8[i1 + 7 | 0]) + -1 & HEAP32[(HEAP32[i3 >> 2] | 0) + 8 >> 2]) << 5) | 0;
+   STACKTOP = i2;
+   return i6 | 0;
+  }
+ case 1:
+  {
+   i6 = (HEAP32[i1 + 16 >> 2] | 0) + (((1 << HEAPU8[i1 + 7 | 0]) + -1 & HEAP32[i3 >> 2]) << 5) | 0;
+   STACKTOP = i2;
+   return i6 | 0;
+  }
+ default:
+  {
+   i6 = (HEAP32[i1 + 16 >> 2] | 0) + ((((HEAP32[i3 >> 2] | 0) >>> 0) % (((1 << HEAPU8[i1 + 7 | 0]) + -1 | 1) >>> 0) | 0) << 5) | 0;
+   STACKTOP = i2;
+   return i6 | 0;
+  }
+ }
+ return 0;
+}
+function _clearvalues(i2, i5, i1) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i4 = STACKTOP;
+ if ((i5 | 0) == (i1 | 0)) {
+  STACKTOP = i4;
+  return;
+ }
+ do {
+  i7 = i5 + 16 | 0;
+  i9 = HEAP32[i7 >> 2] | 0;
+  i6 = i9 + (1 << (HEAPU8[i5 + 7 | 0] | 0) << 5) | 0;
+  i8 = i5 + 28 | 0;
+  if ((HEAP32[i8 >> 2] | 0) > 0) {
+   i11 = i5 + 12 | 0;
+   i12 = 0;
+   do {
+    i13 = HEAP32[i11 >> 2] | 0;
+    i10 = i13 + (i12 << 4) + 8 | 0;
+    i9 = HEAP32[i10 >> 2] | 0;
+    do {
+     if ((i9 & 64 | 0) != 0) {
+      i13 = HEAP32[i13 + (i12 << 4) >> 2] | 0;
+      if ((i9 & 15 | 0) != 4) {
+       if ((HEAP8[i13 + 5 | 0] & 3) == 0) {
+        break;
+       }
+       HEAP32[i10 >> 2] = 0;
+       break;
+      }
+      if ((i13 | 0) != 0 ? !((HEAP8[i13 + 5 | 0] & 3) == 0) : 0) {
+       _reallymarkobject(i2, i13);
+      }
+     }
+    } while (0);
+    i12 = i12 + 1 | 0;
+   } while ((i12 | 0) < (HEAP32[i8 >> 2] | 0));
+   i7 = HEAP32[i7 >> 2] | 0;
+  } else {
+   i7 = i9;
+  }
+  if (i7 >>> 0 < i6 >>> 0) {
+   do {
+    i8 = i7 + 8 | 0;
+    i9 = HEAP32[i8 >> 2] | 0;
+    do {
+     if (!((i9 | 0) == 0 | (i9 & 64 | 0) == 0)) {
+      i10 = HEAP32[i7 >> 2] | 0;
+      if ((i9 & 15 | 0) == 4) {
+       if ((i10 | 0) == 0) {
+        break;
+       }
+       if ((HEAP8[i10 + 5 | 0] & 3) == 0) {
+        break;
+       }
+       _reallymarkobject(i2, i10);
+       break;
+      }
+      if ((!((HEAP8[i10 + 5 | 0] & 3) == 0) ? (HEAP32[i8 >> 2] = 0, i3 = i7 + 24 | 0, (HEAP32[i3 >> 2] & 64 | 0) != 0) : 0) ? !((HEAP8[(HEAP32[i7 + 16 >> 2] | 0) + 5 | 0] & 3) == 0) : 0) {
+       HEAP32[i3 >> 2] = 11;
+      }
+     }
+    } while (0);
+    i7 = i7 + 32 | 0;
+   } while (i7 >>> 0 < i6 >>> 0);
+  }
+  i5 = HEAP32[i5 + 24 >> 2] | 0;
+ } while ((i5 | 0) != (i1 | 0));
+ STACKTOP = i4;
+ return;
+}
+function _reallymarkobject(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i3 = STACKTOP;
+ i2 = i4 + 5 | 0;
+ HEAP8[i2] = HEAP8[i2] & 252;
+ switch (HEAPU8[i4 + 4 | 0] | 0 | 0) {
+ case 6:
+  {
+   i7 = i1 + 84 | 0;
+   HEAP32[i4 + 8 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i7 >> 2] = i4;
+   STACKTOP = i3;
+   return;
+  }
+ case 20:
+ case 4:
+  {
+   i4 = (HEAP32[i4 + 12 >> 2] | 0) + 17 | 0;
+   break;
+  }
+ case 7:
+  {
+   i5 = HEAP32[i4 + 8 >> 2] | 0;
+   if ((i5 | 0) != 0 ? !((HEAP8[i5 + 5 | 0] & 3) == 0) : 0) {
+    _reallymarkobject(i1, i5);
+   }
+   i5 = HEAP32[i4 + 12 >> 2] | 0;
+   if ((i5 | 0) != 0 ? !((HEAP8[i5 + 5 | 0] & 3) == 0) : 0) {
+    _reallymarkobject(i1, i5);
+   }
+   i4 = (HEAP32[i4 + 16 >> 2] | 0) + 24 | 0;
+   break;
+  }
+ case 8:
+  {
+   i7 = i1 + 84 | 0;
+   HEAP32[i4 + 60 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i7 >> 2] = i4;
+   STACKTOP = i3;
+   return;
+  }
+ case 10:
+  {
+   i6 = i4 + 8 | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i7 + 8 >> 2] & 64 | 0) != 0 ? (i5 = HEAP32[i7 >> 2] | 0, !((HEAP8[i5 + 5 | 0] & 3) == 0)) : 0) {
+    _reallymarkobject(i1, i5);
+    i7 = HEAP32[i6 >> 2] | 0;
+   }
+   if ((i7 | 0) == (i4 + 16 | 0)) {
+    i4 = 32;
+   } else {
+    STACKTOP = i3;
+    return;
+   }
+   break;
+  }
+ case 5:
+  {
+   i7 = i1 + 84 | 0;
+   HEAP32[i4 + 24 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i7 >> 2] = i4;
+   STACKTOP = i3;
+   return;
+  }
+ case 38:
+  {
+   i7 = i1 + 84 | 0;
+   HEAP32[i4 + 8 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i7 >> 2] = i4;
+   STACKTOP = i3;
+   return;
+  }
+ case 9:
+  {
+   i7 = i1 + 84 | 0;
+   HEAP32[i4 + 72 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i7 >> 2] = i4;
+   STACKTOP = i3;
+   return;
+  }
+ default:
+  {
+   STACKTOP = i3;
+   return;
+  }
+ }
+ HEAP8[i2] = HEAPU8[i2] | 0 | 4;
+ i7 = i1 + 16 | 0;
+ HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + i4;
+ STACKTOP = i3;
+ return;
+}
+function _lua_upvaluejoin(i1, i9, i7, i6, i3) {
+ i1 = i1 | 0;
+ i9 = i9 | 0;
+ i7 = i7 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i8 = 0, i10 = 0;
+ i2 = STACKTOP;
+ i5 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i9 | 0) <= 0) {
+   if (!((i9 | 0) < -1000999)) {
+    i8 = (HEAP32[i1 + 8 >> 2] | 0) + (i9 << 4) | 0;
+    break;
+   }
+   if ((i9 | 0) == -1001e3) {
+    i8 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i10 = -1001e3 - i9 | 0;
+   i9 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i9 + 8 >> 2] | 0) != 22 ? (i8 = HEAP32[i9 >> 2] | 0, (i10 | 0) <= (HEAPU8[i8 + 6 | 0] | 0 | 0)) : 0) {
+    i8 = i8 + (i10 + -1 << 4) + 16 | 0;
+   } else {
+    i8 = 5192;
+   }
+  } else {
+   i8 = (HEAP32[i5 >> 2] | 0) + (i9 << 4) | 0;
+   i8 = i8 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i8 : 5192;
+  }
+ } while (0);
+ i8 = HEAP32[i8 >> 2] | 0;
+ i7 = i8 + 16 + (i7 + -1 << 2) | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i4 = (HEAP32[i1 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i4 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i6 = -1001e3 - i6 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i5 >> 2] | 0, (i6 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i4 + (i6 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i5 >> 2] | 0) + (i6 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i3 = (HEAP32[i4 >> 2] | 0) + 16 + (i3 + -1 << 2) | 0;
+ HEAP32[i7 >> 2] = HEAP32[i3 >> 2];
+ i3 = HEAP32[i3 >> 2] | 0;
+ if ((HEAP8[i3 + 5 | 0] & 3) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP8[i8 + 5 | 0] & 4) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ _luaC_barrier_(i1, i8, i3);
+ STACKTOP = i2;
+ return;
+}
+function _lua_upvalueid(i5, i7, i1) {
+ i5 = i5 | 0;
+ i7 = i7 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i5 + 16 >> 2] | 0;
+ i6 = (i7 | 0) > 0;
+ do {
+  if (!i6) {
+   if (!((i7 | 0) < -1000999)) {
+    i8 = (HEAP32[i5 + 8 >> 2] | 0) + (i7 << 4) | 0;
+    break;
+   }
+   if ((i7 | 0) == -1001e3) {
+    i8 = (HEAP32[i5 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i10 = -1001e3 - i7 | 0;
+   i9 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i9 + 8 >> 2] | 0) != 22 ? (i8 = HEAP32[i9 >> 2] | 0, (i10 | 0) <= (HEAPU8[i8 + 6 | 0] | 0 | 0)) : 0) {
+    i8 = i8 + (i10 + -1 << 4) + 16 | 0;
+   } else {
+    i8 = 5192;
+   }
+  } else {
+   i8 = (HEAP32[i4 >> 2] | 0) + (i7 << 4) | 0;
+   i8 = i8 >>> 0 < (HEAP32[i5 + 8 >> 2] | 0) >>> 0 ? i8 : 5192;
+  }
+ } while (0);
+ i9 = HEAP32[i8 + 8 >> 2] & 63;
+ if ((i9 | 0) == 38) {
+  i10 = (HEAP32[i8 >> 2] | 0) + (i1 + -1 << 4) + 16 | 0;
+  STACKTOP = i2;
+  return i10 | 0;
+ } else if ((i9 | 0) == 6) {
+  do {
+   if (!i6) {
+    if (!((i7 | 0) < -1000999)) {
+     i3 = (HEAP32[i5 + 8 >> 2] | 0) + (i7 << 4) | 0;
+     break;
+    }
+    if ((i7 | 0) == -1001e3) {
+     i3 = (HEAP32[i5 + 12 >> 2] | 0) + 40 | 0;
+     break;
+    }
+    i5 = -1001e3 - i7 | 0;
+    i4 = HEAP32[i4 >> 2] | 0;
+    if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+     i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+    } else {
+     i3 = 5192;
+    }
+   } else {
+    i3 = (HEAP32[i4 >> 2] | 0) + (i7 << 4) | 0;
+    i3 = i3 >>> 0 < (HEAP32[i5 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+   }
+  } while (0);
+  i10 = HEAP32[(HEAP32[i3 >> 2] | 0) + 16 + (i1 + -1 << 2) >> 2] | 0;
+  STACKTOP = i2;
+  return i10 | 0;
+ } else {
+  i10 = 0;
+  STACKTOP = i2;
+  return i10 | 0;
+ }
+ return 0;
+}
+function _lua_rawequal(i2, i6, i4) {
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0, i5 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i3 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i5 = (HEAP32[i2 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i5 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i7 = -1001e3 - i6 | 0;
+   i6 = HEAP32[i3 >> 2] | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) != 22 ? (i5 = HEAP32[i6 >> 2] | 0, (i7 | 0) <= (HEAPU8[i5 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i5 + (i7 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i5 = (HEAP32[i3 >> 2] | 0) + (i6 << 4) | 0;
+   i5 = i5 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i5 : 5192;
+  }
+ } while (0);
+ do {
+  if ((i4 | 0) <= 0) {
+   if (!((i4 | 0) < -1000999)) {
+    i2 = (HEAP32[i2 + 8 >> 2] | 0) + (i4 << 4) | 0;
+    break;
+   }
+   if ((i4 | 0) == -1001e3) {
+    i2 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i2 = -1001e3 - i4 | 0;
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((HEAP32[i3 + 8 >> 2] | 0) == 22) {
+    i7 = 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((i2 | 0) > (HEAPU8[i3 + 6 | 0] | 0 | 0)) {
+    i7 = 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   } else {
+    i2 = i3 + (i2 + -1 << 4) + 16 | 0;
+    break;
+   }
+  } else {
+   i3 = (HEAP32[i3 >> 2] | 0) + (i4 << 4) | 0;
+   i2 = i3 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ if ((i5 | 0) == 5192 | (i2 | 0) == 5192) {
+  i7 = 0;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ if ((HEAP32[i5 + 8 >> 2] | 0) == (HEAP32[i2 + 8 >> 2] | 0)) {
+  i2 = (_luaV_equalobj_(0, i5, i2) | 0) != 0;
+ } else {
+  i2 = 0;
+ }
+ i7 = i2 & 1;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _luaO_chunkid(i1, i4, i6) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ i3 = _strlen(i4 | 0) | 0;
+ i5 = HEAP8[i4] | 0;
+ if (i5 << 24 >> 24 == 64) {
+  if (i3 >>> 0 > i6 >>> 0) {
+   HEAP8[i1 + 0 | 0] = HEAP8[5552 | 0] | 0;
+   HEAP8[i1 + 1 | 0] = HEAP8[5553 | 0] | 0;
+   HEAP8[i1 + 2 | 0] = HEAP8[5554 | 0] | 0;
+   _memcpy(i1 + 3 | 0, i4 + (4 - i6 + i3) | 0, i6 + -3 | 0) | 0;
+   STACKTOP = i2;
+   return;
+  } else {
+   _memcpy(i1 | 0, i4 + 1 | 0, i3 | 0) | 0;
+   STACKTOP = i2;
+   return;
+  }
+ } else if (i5 << 24 >> 24 == 61) {
+  i4 = i4 + 1 | 0;
+  if (i3 >>> 0 > i6 >>> 0) {
+   i9 = i6 + -1 | 0;
+   _memcpy(i1 | 0, i4 | 0, i9 | 0) | 0;
+   HEAP8[i1 + i9 | 0] = 0;
+   STACKTOP = i2;
+   return;
+  } else {
+   _memcpy(i1 | 0, i4 | 0, i3 | 0) | 0;
+   STACKTOP = i2;
+   return;
+  }
+ } else {
+  i5 = _strchr(i4, 10) | 0;
+  i9 = i1 + 0 | 0;
+  i8 = 5560 | 0;
+  i7 = i9 + 9 | 0;
+  do {
+   HEAP8[i9] = HEAP8[i8] | 0;
+   i9 = i9 + 1 | 0;
+   i8 = i8 + 1 | 0;
+  } while ((i9 | 0) < (i7 | 0));
+  i7 = i1 + 9 | 0;
+  i6 = i6 + -15 | 0;
+  i8 = (i5 | 0) == 0;
+  if (i3 >>> 0 < i6 >>> 0 & i8) {
+   _memcpy(i7 | 0, i4 | 0, i3 | 0) | 0;
+   i3 = i3 + 9 | 0;
+  } else {
+   if (!i8) {
+    i3 = i5 - i4 | 0;
+   }
+   i3 = i3 >>> 0 > i6 >>> 0 ? i6 : i3;
+   _memcpy(i7 | 0, i4 | 0, i3 | 0) | 0;
+   i9 = i1 + (i3 + 9) | 0;
+   HEAP8[i9 + 0 | 0] = HEAP8[5552 | 0] | 0;
+   HEAP8[i9 + 1 | 0] = HEAP8[5553 | 0] | 0;
+   HEAP8[i9 + 2 | 0] = HEAP8[5554 | 0] | 0;
+   i3 = i3 + 12 | 0;
+  }
+  i9 = i1 + i3 | 0;
+  HEAP8[i9 + 0 | 0] = HEAP8[5576 | 0] | 0;
+  HEAP8[i9 + 1 | 0] = HEAP8[5577 | 0] | 0;
+  HEAP8[i9 + 2 | 0] = HEAP8[5578 | 0] | 0;
+  STACKTOP = i2;
+  return;
+ }
+}
+function _luaS_resize(i4, i1) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i3 = STACKTOP;
+ i5 = HEAP32[i4 + 12 >> 2] | 0;
+ i2 = i5 + 24 | 0;
+ _luaC_runtilstate(i4, -5);
+ i5 = i5 + 32 | 0;
+ i8 = HEAP32[i5 >> 2] | 0;
+ L1 : do {
+  if ((i8 | 0) < (i1 | 0)) {
+   if ((i1 + 1 | 0) >>> 0 > 1073741823) {
+    _luaM_toobig(i4);
+   }
+   i7 = _luaM_realloc_(i4, HEAP32[i2 >> 2] | 0, i8 << 2, i1 << 2) | 0;
+   HEAP32[i2 >> 2] = i7;
+   i6 = HEAP32[i5 >> 2] | 0;
+   if ((i6 | 0) < (i1 | 0)) {
+    i8 = i6;
+    while (1) {
+     HEAP32[i7 + (i8 << 2) >> 2] = 0;
+     i8 = i8 + 1 | 0;
+     if ((i8 | 0) == (i1 | 0)) {
+      i8 = i6;
+      break L1;
+     }
+     i7 = HEAP32[i2 >> 2] | 0;
+    }
+   } else {
+    i8 = i6;
+   }
+  }
+ } while (0);
+ if ((i8 | 0) > 0) {
+  i6 = i1 + -1 | 0;
+  i7 = 0;
+  do {
+   i10 = (HEAP32[i2 >> 2] | 0) + (i7 << 2) | 0;
+   i9 = HEAP32[i10 >> 2] | 0;
+   HEAP32[i10 >> 2] = 0;
+   if ((i9 | 0) != 0) {
+    while (1) {
+     i8 = HEAP32[i9 >> 2] | 0;
+     i10 = HEAP32[i9 + 8 >> 2] & i6;
+     HEAP32[i9 >> 2] = HEAP32[(HEAP32[i2 >> 2] | 0) + (i10 << 2) >> 2];
+     HEAP32[(HEAP32[i2 >> 2] | 0) + (i10 << 2) >> 2] = i9;
+     i10 = i9 + 5 | 0;
+     HEAP8[i10] = HEAP8[i10] & 191;
+     if ((i8 | 0) == 0) {
+      break;
+     } else {
+      i9 = i8;
+     }
+    }
+    i8 = HEAP32[i5 >> 2] | 0;
+   }
+   i7 = i7 + 1 | 0;
+  } while ((i7 | 0) < (i8 | 0));
+ }
+ if ((i8 | 0) <= (i1 | 0)) {
+  HEAP32[i5 >> 2] = i1;
+  STACKTOP = i3;
+  return;
+ }
+ if ((i1 + 1 | 0) >>> 0 > 1073741823) {
+  _luaM_toobig(i4);
+ }
+ HEAP32[i2 >> 2] = _luaM_realloc_(i4, HEAP32[i2 >> 2] | 0, i8 << 2, i1 << 2) | 0;
+ HEAP32[i5 >> 2] = i1;
+ STACKTOP = i3;
+ return;
+}
+function _luaD_poscall(i6, i7) {
+ i6 = i6 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i1 = STACKTOP;
+ i4 = i6 + 16 | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ i5 = HEAPU8[i6 + 40 | 0] | 0;
+ if ((i5 & 6 | 0) == 0) {
+  i8 = i3 + 8 | 0;
+ } else {
+  if ((i5 & 2 | 0) != 0) {
+   i8 = i6 + 28 | 0;
+   i7 = i7 - (HEAP32[i8 >> 2] | 0) | 0;
+   _luaD_hook(i6, 1, -1);
+   i7 = (HEAP32[i8 >> 2] | 0) + i7 | 0;
+  }
+  i8 = i3 + 8 | 0;
+  HEAP32[i6 + 20 >> 2] = HEAP32[(HEAP32[i8 >> 2] | 0) + 28 >> 2];
+ }
+ i5 = HEAP32[i3 >> 2] | 0;
+ i9 = HEAP16[i3 + 16 >> 1] | 0;
+ i3 = i9 << 16 >> 16;
+ HEAP32[i4 >> 2] = HEAP32[i8 >> 2];
+ i4 = i6 + 8 | 0;
+ if (i9 << 16 >> 16 == 0) {
+  i9 = i5;
+  HEAP32[i4 >> 2] = i9;
+  i9 = i3 + 1 | 0;
+  STACKTOP = i1;
+  return i9 | 0;
+ } else {
+  i6 = i3;
+ }
+ while (1) {
+  if (!(i7 >>> 0 < (HEAP32[i4 >> 2] | 0) >>> 0)) {
+   break;
+  }
+  i8 = i5 + 16 | 0;
+  i11 = i7;
+  i10 = HEAP32[i11 + 4 >> 2] | 0;
+  i9 = i5;
+  HEAP32[i9 >> 2] = HEAP32[i11 >> 2];
+  HEAP32[i9 + 4 >> 2] = i10;
+  HEAP32[i5 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+  i6 = i6 + -1 | 0;
+  if ((i6 | 0) == 0) {
+   i2 = 12;
+   break;
+  } else {
+   i7 = i7 + 16 | 0;
+   i5 = i8;
+  }
+ }
+ if ((i2 | 0) == 12) {
+  HEAP32[i4 >> 2] = i8;
+  i11 = i3 + 1 | 0;
+  STACKTOP = i1;
+  return i11 | 0;
+ }
+ if ((i6 | 0) > 0) {
+  i2 = i6;
+  i7 = i5;
+ } else {
+  i11 = i5;
+  HEAP32[i4 >> 2] = i11;
+  i11 = i3 + 1 | 0;
+  STACKTOP = i1;
+  return i11 | 0;
+ }
+ while (1) {
+  i2 = i2 + -1 | 0;
+  HEAP32[i7 + 8 >> 2] = 0;
+  if ((i2 | 0) <= 0) {
+   break;
+  } else {
+   i7 = i7 + 16 | 0;
+  }
+ }
+ i11 = i5 + (i6 << 4) | 0;
+ HEAP32[i4 >> 2] = i11;
+ i11 = i3 + 1 | 0;
+ STACKTOP = i1;
+ return i11 | 0;
+}
+function _lua_rawset(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ i5 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i4 | 0) <= 0) {
+   if (!((i4 | 0) < -1000999)) {
+    i5 = (HEAP32[i1 + 8 >> 2] | 0) + (i4 << 4) | 0;
+    break;
+   }
+   if ((i4 | 0) == -1001e3) {
+    i5 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i4 = -1001e3 - i4 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i5 >> 2] | 0, (i4 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i3 + (i4 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i5 >> 2] | 0) + (i4 << 4) | 0;
+   i5 = i3 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i4 = i1 + 8 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ i3 = _luaH_set(i1, HEAP32[i5 >> 2] | 0, i6 + -32 | 0) | 0;
+ i9 = i6 + -16 | 0;
+ i8 = HEAP32[i9 + 4 >> 2] | 0;
+ i7 = i3;
+ HEAP32[i7 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i7 + 4 >> 2] = i8;
+ HEAP32[i3 + 8 >> 2] = HEAP32[i6 + -8 >> 2];
+ HEAP8[(HEAP32[i5 >> 2] | 0) + 6 | 0] = 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ if ((HEAP32[i3 + -8 >> 2] & 64 | 0) == 0) {
+  i9 = i3;
+  i9 = i9 + -32 | 0;
+  HEAP32[i4 >> 2] = i9;
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP8[(HEAP32[i3 + -16 >> 2] | 0) + 5 | 0] & 3) == 0) {
+  i9 = i3;
+  i9 = i9 + -32 | 0;
+  HEAP32[i4 >> 2] = i9;
+  STACKTOP = i2;
+  return;
+ }
+ i5 = HEAP32[i5 >> 2] | 0;
+ if ((HEAP8[i5 + 5 | 0] & 4) == 0) {
+  i9 = i3;
+  i9 = i9 + -32 | 0;
+  HEAP32[i4 >> 2] = i9;
+  STACKTOP = i2;
+  return;
+ }
+ _luaC_barrierback_(i1, i5);
+ i9 = HEAP32[i4 >> 2] | 0;
+ i9 = i9 + -32 | 0;
+ HEAP32[i4 >> 2] = i9;
+ STACKTOP = i2;
+ return;
+}
+function _saveSetjmp(i4, i3, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0;
+ setjmpId = setjmpId + 1 | 0;
+ HEAP32[i4 >> 2] = setjmpId;
+ while ((i2 | 0) < 40) {
+  if ((HEAP32[i1 + (i2 << 2) >> 2] | 0) == 0) {
+   HEAP32[i1 + (i2 << 2) >> 2] = setjmpId;
+   HEAP32[i1 + ((i2 << 2) + 4) >> 2] = i3;
+   HEAP32[i1 + ((i2 << 2) + 8) >> 2] = 0;
+   return 0;
+  }
+  i2 = i2 + 2 | 0;
+ }
+ _putchar(116);
+ _putchar(111);
+ _putchar(111);
+ _putchar(32);
+ _putchar(109);
+ _putchar(97);
+ _putchar(110);
+ _putchar(121);
+ _putchar(32);
+ _putchar(115);
+ _putchar(101);
+ _putchar(116);
+ _putchar(106);
+ _putchar(109);
+ _putchar(112);
+ _putchar(115);
+ _putchar(32);
+ _putchar(105);
+ _putchar(110);
+ _putchar(32);
+ _putchar(97);
+ _putchar(32);
+ _putchar(102);
+ _putchar(117);
+ _putchar(110);
+ _putchar(99);
+ _putchar(116);
+ _putchar(105);
+ _putchar(111);
+ _putchar(110);
+ _putchar(32);
+ _putchar(99);
+ _putchar(97);
+ _putchar(108);
+ _putchar(108);
+ _putchar(44);
+ _putchar(32);
+ _putchar(98);
+ _putchar(117);
+ _putchar(105);
+ _putchar(108);
+ _putchar(100);
+ _putchar(32);
+ _putchar(119);
+ _putchar(105);
+ _putchar(116);
+ _putchar(104);
+ _putchar(32);
+ _putchar(97);
+ _putchar(32);
+ _putchar(104);
+ _putchar(105);
+ _putchar(103);
+ _putchar(104);
+ _putchar(101);
+ _putchar(114);
+ _putchar(32);
+ _putchar(118);
+ _putchar(97);
+ _putchar(108);
+ _putchar(117);
+ _putchar(101);
+ _putchar(32);
+ _putchar(102);
+ _putchar(111);
+ _putchar(114);
+ _putchar(32);
+ _putchar(77);
+ _putchar(65);
+ _putchar(88);
+ _putchar(95);
+ _putchar(83);
+ _putchar(69);
+ _putchar(84);
+ _putchar(74);
+ _putchar(77);
+ _putchar(80);
+ _putchar(83);
+ _putchar(10);
+ abort(0);
+ return 0;
+}
+function _lua_newthread(i5) {
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ i3 = i5 + 12 | 0;
+ if ((HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i5);
+ }
+ i2 = _luaC_newobj(i5, 8, 112, 0, 0) | 0;
+ i6 = i5 + 8 | 0;
+ i4 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i4 >> 2] = i2;
+ HEAP32[i4 + 8 >> 2] = 72;
+ HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 16;
+ HEAP32[i2 + 12 >> 2] = HEAP32[i3 >> 2];
+ i6 = i2 + 28 | 0;
+ HEAP32[i6 >> 2] = 0;
+ i4 = i2 + 16 | 0;
+ HEAP32[i4 >> 2] = 0;
+ i3 = i2 + 32 | 0;
+ HEAP32[i3 >> 2] = 0;
+ HEAP32[i2 + 64 >> 2] = 0;
+ HEAP16[i2 + 38 >> 1] = 0;
+ i9 = i2 + 52 | 0;
+ HEAP32[i9 >> 2] = 0;
+ i8 = i2 + 40 | 0;
+ HEAP8[i8] = 0;
+ i10 = i2 + 44 | 0;
+ HEAP32[i10 >> 2] = 0;
+ HEAP8[i2 + 41 | 0] = 1;
+ i7 = i2 + 48 | 0;
+ HEAP32[i7 >> 2] = 0;
+ HEAP32[i2 + 56 >> 2] = 0;
+ HEAP16[i2 + 36 >> 1] = 1;
+ HEAP8[i2 + 6 | 0] = 0;
+ HEAP32[i2 + 68 >> 2] = 0;
+ HEAP8[i8] = HEAP8[i5 + 40 | 0] | 0;
+ i8 = HEAP32[i5 + 44 >> 2] | 0;
+ HEAP32[i10 >> 2] = i8;
+ HEAP32[i9 >> 2] = HEAP32[i5 + 52 >> 2];
+ HEAP32[i7 >> 2] = i8;
+ i5 = _luaM_realloc_(i5, 0, 0, 640) | 0;
+ HEAP32[i6 >> 2] = i5;
+ HEAP32[i3 >> 2] = 40;
+ i6 = 0;
+ do {
+  HEAP32[i5 + (i6 << 4) + 8 >> 2] = 0;
+  i6 = i6 + 1 | 0;
+ } while ((i6 | 0) != 40);
+ HEAP32[i2 + 24 >> 2] = i5 + ((HEAP32[i3 >> 2] | 0) + -5 << 4);
+ i10 = i2 + 72 | 0;
+ HEAP32[i2 + 80 >> 2] = 0;
+ HEAP32[i2 + 84 >> 2] = 0;
+ HEAP8[i2 + 90 | 0] = 0;
+ HEAP32[i10 >> 2] = i5;
+ HEAP32[i2 + 8 >> 2] = i5 + 16;
+ HEAP32[i5 + 8 >> 2] = 0;
+ HEAP32[i2 + 76 >> 2] = i5 + 336;
+ HEAP32[i4 >> 2] = i10;
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _luaK_self(i2, i5, i3) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ _luaK_dischargevars(i2, i5);
+ if ((HEAP32[i5 >> 2] | 0) == 6) {
+  i6 = i5 + 8 | 0;
+  i8 = HEAP32[i6 >> 2] | 0;
+  if ((HEAP32[i5 + 16 >> 2] | 0) != (HEAP32[i5 + 20 >> 2] | 0)) {
+   if ((i8 | 0) < (HEAPU8[i2 + 46 | 0] | 0 | 0)) {
+    i7 = 6;
+   } else {
+    _exp2reg(i2, i5, i8);
+   }
+  }
+ } else {
+  i6 = i5 + 8 | 0;
+  i7 = 6;
+ }
+ if ((i7 | 0) == 6) {
+  _luaK_exp2nextreg(i2, i5);
+ }
+ i8 = HEAP32[i6 >> 2] | 0;
+ if (((HEAP32[i5 >> 2] | 0) == 6 ? (i8 & 256 | 0) == 0 : 0) ? (HEAPU8[i2 + 46 | 0] | 0 | 0) <= (i8 | 0) : 0) {
+  i10 = i2 + 48 | 0;
+  HEAP8[i10] = (HEAP8[i10] | 0) + -1 << 24 >> 24;
+ }
+ i7 = i2 + 48 | 0;
+ HEAP32[i6 >> 2] = HEAPU8[i7] | 0;
+ HEAP32[i5 >> 2] = 6;
+ i10 = HEAP8[i7] | 0;
+ i5 = (i10 & 255) + 2 | 0;
+ i9 = (HEAP32[i2 >> 2] | 0) + 78 | 0;
+ do {
+  if (i5 >>> 0 > (HEAPU8[i9] | 0) >>> 0) {
+   if (i5 >>> 0 > 249) {
+    _luaX_syntaxerror(HEAP32[i2 + 12 >> 2] | 0, 10536);
+   } else {
+    HEAP8[i9] = i5;
+    i4 = HEAP8[i7] | 0;
+    break;
+   }
+  } else {
+   i4 = i10;
+  }
+ } while (0);
+ HEAP8[i7] = (i4 & 255) + 2;
+ i10 = HEAP32[i6 >> 2] | 0;
+ _luaK_code(i2, i8 << 23 | i10 << 6 | (_luaK_exp2RK(i2, i3) | 0) << 14 | 12) | 0;
+ if ((HEAP32[i3 >> 2] | 0) != 6) {
+  STACKTOP = i1;
+  return;
+ }
+ i3 = HEAP32[i3 + 8 >> 2] | 0;
+ if ((i3 & 256 | 0) != 0) {
+  STACKTOP = i1;
+  return;
+ }
+ if ((HEAPU8[i2 + 46 | 0] | 0 | 0) > (i3 | 0)) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP8[i7] = (HEAP8[i7] | 0) + -1 << 24 >> 24;
+ STACKTOP = i1;
+ return;
+}
+function _luaD_rawrunprotected(i10, i9, i11) {
+ i10 = i10 | 0;
+ i9 = i9 | 0;
+ i11 = i11 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i12 = 0, i13 = 0;
+ i7 = STACKTOP;
+ STACKTOP = STACKTOP + 176 | 0;
+ i8 = STACKTOP;
+ STACKTOP = STACKTOP + 168 | 0;
+ HEAP32[i8 >> 2] = 0;
+ i6 = i7;
+ i5 = i10 + 38 | 0;
+ i4 = HEAP16[i5 >> 1] | 0;
+ i1 = i6 + 160 | 0;
+ HEAP32[i1 >> 2] = 0;
+ i3 = i10 + 64 | 0;
+ HEAP32[i6 >> 2] = HEAP32[i3 >> 2];
+ HEAP32[i3 >> 2] = i6;
+ _saveSetjmp(i6 + 4 | 0, 1, i8 | 0) | 0;
+ __THREW__ = 0;
+ i13 = __THREW__;
+ __THREW__ = 0;
+ if ((i13 | 0) != 0 & (threwValue | 0) != 0) {
+  i12 = _testSetjmp(HEAP32[i13 >> 2] | 0, i8) | 0;
+  if ((i12 | 0) == 0) {
+   _longjmp(i13 | 0, threwValue | 0);
+  }
+  tempRet0 = threwValue;
+ } else {
+  i12 = -1;
+ }
+ if ((i12 | 0) == 1) {
+  i12 = tempRet0;
+ } else {
+  i12 = 0;
+ }
+ while (1) {
+  if ((i12 | 0) != 0) {
+   i2 = 6;
+   break;
+  }
+  __THREW__ = 0;
+  invoke_vii(i9 | 0, i10 | 0, i11 | 0);
+  i13 = __THREW__;
+  __THREW__ = 0;
+  if ((i13 | 0) != 0 & (threwValue | 0) != 0) {
+   i12 = _testSetjmp(HEAP32[i13 >> 2] | 0, i8) | 0;
+   if ((i12 | 0) == 0) {
+    _longjmp(i13 | 0, threwValue | 0);
+   }
+   tempRet0 = threwValue;
+  } else {
+   i12 = -1;
+  }
+  if ((i12 | 0) == 1) {
+   i12 = tempRet0;
+  } else {
+   break;
+  }
+ }
+ if ((i2 | 0) == 6) {
+  i13 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i3 >> 2] = i13;
+  HEAP16[i5 >> 1] = i4;
+  i13 = HEAP32[i1 >> 2] | 0;
+  STACKTOP = i7;
+  return i13 | 0;
+ }
+ i13 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i3 >> 2] = i13;
+ HEAP16[i5 >> 1] = i4;
+ i13 = HEAP32[i1 >> 2] | 0;
+ STACKTOP = i7;
+ return i13 | 0;
+}
+function _luaB_tonumber(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, d6 = 0.0, i7 = 0, d8 = 0.0, i9 = 0, i10 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2 + 4 | 0;
+ i4 = i2;
+ do {
+  if ((_lua_type(i1, 2) | 0) >= 1) {
+   i9 = _luaL_checklstring(i1, 1, i4) | 0;
+   i3 = i9 + (HEAP32[i4 >> 2] | 0) | 0;
+   i5 = _luaL_checkinteger(i1, 2) | 0;
+   if (!((i5 + -2 | 0) >>> 0 < 35)) {
+    _luaL_argerror(i1, 2, 9648) | 0;
+   }
+   i10 = _strspn(i9, 9672) | 0;
+   i7 = i9 + i10 | 0;
+   i4 = HEAP8[i7] | 0;
+   if (i4 << 24 >> 24 == 43) {
+    i4 = 0;
+    i7 = i9 + (i10 + 1) | 0;
+   } else if (i4 << 24 >> 24 == 45) {
+    i4 = 1;
+    i7 = i9 + (i10 + 1) | 0;
+   } else {
+    i4 = 0;
+   }
+   if ((_isalnum(HEAPU8[i7] | 0 | 0) | 0) != 0) {
+    d6 = +(i5 | 0);
+    d8 = 0.0;
+    do {
+     i9 = HEAP8[i7] | 0;
+     i10 = i9 & 255;
+     if ((i10 + -48 | 0) >>> 0 < 10) {
+      i9 = (i9 << 24 >> 24) + -48 | 0;
+     } else {
+      i9 = (_toupper(i10 | 0) | 0) + -55 | 0;
+     }
+     if ((i9 | 0) >= (i5 | 0)) {
+      break;
+     }
+     d8 = d6 * d8 + +(i9 | 0);
+     i7 = i7 + 1 | 0;
+    } while ((_isalnum(HEAPU8[i7] | 0 | 0) | 0) != 0);
+    if ((i7 + (_strspn(i7, 9672) | 0) | 0) == (i3 | 0)) {
+     if ((i4 | 0) != 0) {
+      d8 = -d8;
+     }
+     _lua_pushnumber(i1, d8);
+     STACKTOP = i2;
+     return 1;
+    }
+   }
+  } else {
+   d6 = +_lua_tonumberx(i1, 1, i3);
+   if ((HEAP32[i3 >> 2] | 0) == 0) {
+    _luaL_checkany(i1, 1);
+    break;
+   }
+   _lua_pushnumber(i1, d6);
+   STACKTOP = i2;
+   return 1;
+  }
+ } while (0);
+ _lua_pushnil(i1);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaK_storevar(i1, i5, i3) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ i7 = HEAP32[i5 >> 2] | 0;
+ if ((i7 | 0) == 7) {
+  if (((HEAP32[i3 >> 2] | 0) == 6 ? (i6 = HEAP32[i3 + 8 >> 2] | 0, (i6 & 256 | 0) == 0) : 0) ? (HEAPU8[i1 + 46 | 0] | 0) <= (i6 | 0) : 0) {
+   i7 = i1 + 48 | 0;
+   HEAP8[i7] = (HEAP8[i7] | 0) + -1 << 24 >> 24;
+  }
+  _exp2reg(i1, i3, HEAP32[i5 + 8 >> 2] | 0);
+  STACKTOP = i2;
+  return;
+ } else if ((i7 | 0) == 9) {
+  i4 = i5 + 8 | 0;
+  i7 = (HEAP8[i4 + 3 | 0] | 0) == 7 ? 10 : 8;
+  i6 = _luaK_exp2RK(i1, i3) | 0;
+  _luaK_code(i1, i6 << 14 | i7 | HEAPU8[i4 + 2 | 0] << 6 | HEAPU16[i4 >> 1] << 23) | 0;
+ } else if ((i7 | 0) == 8) {
+  _luaK_dischargevars(i1, i3);
+  if ((HEAP32[i3 >> 2] | 0) == 6) {
+   i6 = i3 + 8 | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i3 + 16 >> 2] | 0) != (HEAP32[i3 + 20 >> 2] | 0)) {
+    if ((i7 | 0) < (HEAPU8[i1 + 46 | 0] | 0)) {
+     i4 = 12;
+    } else {
+     _exp2reg(i1, i3, i7);
+     i7 = HEAP32[i6 >> 2] | 0;
+    }
+   }
+  } else {
+   i6 = i3 + 8 | 0;
+   i4 = 12;
+  }
+  if ((i4 | 0) == 12) {
+   _luaK_exp2nextreg(i1, i3);
+   i7 = HEAP32[i6 >> 2] | 0;
+  }
+  _luaK_code(i1, i7 << 6 | HEAP32[i5 + 8 >> 2] << 23 | 9) | 0;
+ }
+ if ((HEAP32[i3 >> 2] | 0) != 6) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = HEAP32[i3 + 8 >> 2] | 0;
+ if ((i3 & 256 | 0) != 0) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAPU8[i1 + 46 | 0] | 0) > (i3 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i7 = i1 + 48 | 0;
+ HEAP8[i7] = (HEAP8[i7] | 0) + -1 << 24 >> 24;
+ STACKTOP = i2;
+ return;
+}
+function _closegoto(i10, i3, i9) {
+ i10 = i10 | 0;
+ i3 = i3 | 0;
+ i9 = i9 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i11 = 0, i12 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i7 = i1;
+ i4 = HEAP32[i10 + 48 >> 2] | 0;
+ i6 = HEAP32[i10 + 64 >> 2] | 0;
+ i2 = i6 + 12 | 0;
+ i5 = HEAP32[i2 >> 2] | 0;
+ i8 = HEAP8[i5 + (i3 << 4) + 12 | 0] | 0;
+ if ((i8 & 255) < (HEAPU8[i9 + 12 | 0] | 0)) {
+  i11 = HEAP32[i10 + 52 >> 2] | 0;
+  i12 = HEAP32[i5 + (i3 << 4) + 8 >> 2] | 0;
+  i8 = (HEAP32[(HEAP32[(HEAP32[i4 >> 2] | 0) + 24 >> 2] | 0) + ((HEAP16[(HEAP32[HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 64 >> 2] >> 2] | 0) + ((HEAP32[i4 + 40 >> 2] | 0) + (i8 & 255) << 1) >> 1] | 0) * 12 | 0) >> 2] | 0) + 16 | 0;
+  HEAP32[i7 >> 2] = (HEAP32[i5 + (i3 << 4) >> 2] | 0) + 16;
+  HEAP32[i7 + 4 >> 2] = i12;
+  HEAP32[i7 + 8 >> 2] = i8;
+  _semerror(i10, _luaO_pushfstring(i11, 6248, i7) | 0);
+ }
+ _luaK_patchlist(i4, HEAP32[i5 + (i3 << 4) + 4 >> 2] | 0, HEAP32[i9 + 4 >> 2] | 0);
+ i4 = i6 + 16 | 0;
+ i5 = (HEAP32[i4 >> 2] | 0) + -1 | 0;
+ if ((i5 | 0) <= (i3 | 0)) {
+  i12 = i5;
+  HEAP32[i4 >> 2] = i12;
+  STACKTOP = i1;
+  return;
+ }
+ do {
+  i12 = HEAP32[i2 >> 2] | 0;
+  i5 = i12 + (i3 << 4) | 0;
+  i3 = i3 + 1 | 0;
+  i12 = i12 + (i3 << 4) | 0;
+  HEAP32[i5 + 0 >> 2] = HEAP32[i12 + 0 >> 2];
+  HEAP32[i5 + 4 >> 2] = HEAP32[i12 + 4 >> 2];
+  HEAP32[i5 + 8 >> 2] = HEAP32[i12 + 8 >> 2];
+  HEAP32[i5 + 12 >> 2] = HEAP32[i12 + 12 >> 2];
+  i5 = (HEAP32[i4 >> 2] | 0) + -1 | 0;
+ } while ((i3 | 0) < (i5 | 0));
+ HEAP32[i4 >> 2] = i5;
+ STACKTOP = i1;
+ return;
+}
+function _luaM_growaux_(i4, i5, i1, i7, i8, i9) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ i8 = i8 | 0;
+ i9 = i9 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i10 = 0, i11 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i10 = i2;
+ i6 = HEAP32[i1 >> 2] | 0;
+ if ((i6 | 0) >= ((i8 | 0) / 2 | 0 | 0)) {
+  if ((i6 | 0) < (i8 | 0)) {
+   i3 = i8;
+  } else {
+   HEAP32[i10 >> 2] = i9;
+   HEAP32[i10 + 4 >> 2] = i8;
+   _luaG_runerror(i4, 4112, i10);
+  }
+ } else {
+  i3 = i6 << 1;
+  i3 = (i3 | 0) < 4 ? 4 : i3;
+ }
+ if ((i3 + 1 | 0) >>> 0 > (4294967293 / (i7 >>> 0) | 0) >>> 0) {
+  _luaM_toobig(i4);
+ }
+ i6 = Math_imul(i6, i7) | 0;
+ i8 = Math_imul(i3, i7) | 0;
+ i9 = HEAP32[i4 + 12 >> 2] | 0;
+ i7 = (i5 | 0) != 0;
+ i11 = i9 + 4 | 0;
+ i10 = FUNCTION_TABLE_iiiii[HEAP32[i9 >> 2] & 3](HEAP32[i11 >> 2] | 0, i5, i6, i8) | 0;
+ if ((i10 | 0) != 0 | (i8 | 0) == 0) {
+  i5 = i9 + 12 | 0;
+  i4 = HEAP32[i5 >> 2] | 0;
+  i6 = 0 - i6 | 0;
+  i11 = i7 ? i6 : 0;
+  i11 = i11 + i8 | 0;
+  i11 = i11 + i4 | 0;
+  HEAP32[i5 >> 2] = i11;
+  HEAP32[i1 >> 2] = i3;
+  STACKTOP = i2;
+  return i10 | 0;
+ }
+ if ((HEAP8[i9 + 63 | 0] | 0) == 0) {
+  _luaD_throw(i4, 4);
+ }
+ _luaC_fullgc(i4, 1);
+ i10 = FUNCTION_TABLE_iiiii[HEAP32[i9 >> 2] & 3](HEAP32[i11 >> 2] | 0, i5, i6, i8) | 0;
+ if ((i10 | 0) == 0) {
+  _luaD_throw(i4, 4);
+ } else {
+  i5 = i9 + 12 | 0;
+  i4 = HEAP32[i5 >> 2] | 0;
+  i6 = 0 - i6 | 0;
+  i11 = i7 ? i6 : 0;
+  i11 = i11 + i8 | 0;
+  i11 = i11 + i4 | 0;
+  HEAP32[i5 >> 2] = i11;
+  HEAP32[i1 >> 2] = i3;
+  STACKTOP = i2;
+  return i10 | 0;
+ }
+ return 0;
+}
+function _luaD_hook(i5, i14, i13) {
+ i5 = i5 | 0;
+ i14 = i14 | 0;
+ i13 = i13 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i15 = 0, i16 = 0;
+ i11 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i4 = i11;
+ i3 = HEAP32[i5 + 52 >> 2] | 0;
+ if ((i3 | 0) == 0) {
+  STACKTOP = i11;
+  return;
+ }
+ i8 = i5 + 41 | 0;
+ if ((HEAP8[i8] | 0) == 0) {
+  STACKTOP = i11;
+  return;
+ }
+ i10 = HEAP32[i5 + 16 >> 2] | 0;
+ i6 = i5 + 8 | 0;
+ i15 = HEAP32[i6 >> 2] | 0;
+ i1 = i5 + 28 | 0;
+ i16 = i15;
+ i12 = HEAP32[i1 >> 2] | 0;
+ i7 = i16 - i12 | 0;
+ i9 = i10 + 4 | 0;
+ i12 = (HEAP32[i9 >> 2] | 0) - i12 | 0;
+ HEAP32[i4 >> 2] = i14;
+ HEAP32[i4 + 20 >> 2] = i13;
+ HEAP32[i4 + 96 >> 2] = i10;
+ do {
+  if (((HEAP32[i5 + 24 >> 2] | 0) - i16 | 0) < 336) {
+   i14 = HEAP32[i5 + 32 >> 2] | 0;
+   if ((i14 | 0) > 1e6) {
+    _luaD_throw(i5, 6);
+   }
+   i13 = (i7 >> 4) + 25 | 0;
+   i14 = i14 << 1;
+   i14 = (i14 | 0) > 1e6 ? 1e6 : i14;
+   i13 = (i14 | 0) < (i13 | 0) ? i13 : i14;
+   if ((i13 | 0) > 1e6) {
+    _luaD_reallocstack(i5, 1000200);
+    _luaG_runerror(i5, 2224, i4);
+   } else {
+    _luaD_reallocstack(i5, i13);
+    i2 = HEAP32[i6 >> 2] | 0;
+    break;
+   }
+  } else {
+   i2 = i15;
+  }
+ } while (0);
+ HEAP32[i9 >> 2] = i2 + 320;
+ HEAP8[i8] = 0;
+ i16 = i10 + 18 | 0;
+ HEAP8[i16] = HEAPU8[i16] | 2;
+ FUNCTION_TABLE_vii[i3 & 15](i5, i4);
+ HEAP8[i8] = 1;
+ HEAP32[i9 >> 2] = (HEAP32[i1 >> 2] | 0) + i12;
+ HEAP32[i6 >> 2] = (HEAP32[i1 >> 2] | 0) + i7;
+ HEAP8[i16] = HEAP8[i16] & 253;
+ STACKTOP = i11;
+ return;
+}
+function _funcargs(i10, i2, i1) {
+ i10 = i10 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i6 = i3;
+ i9 = i10 + 48 | 0;
+ i5 = HEAP32[i9 >> 2] | 0;
+ i7 = i10 + 16 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ if ((i8 | 0) == 289) {
+  i9 = _luaK_stringK(i5, HEAP32[i10 + 24 >> 2] | 0) | 0;
+  HEAP32[i6 + 16 >> 2] = -1;
+  HEAP32[i6 + 20 >> 2] = -1;
+  HEAP32[i6 >> 2] = 4;
+  HEAP32[i6 + 8 >> 2] = i9;
+  _luaX_next(i10);
+ } else if ((i8 | 0) == 40) {
+  _luaX_next(i10);
+  if ((HEAP32[i7 >> 2] | 0) == 41) {
+   HEAP32[i6 >> 2] = 0;
+  } else {
+   _subexpr(i10, i6, 0) | 0;
+   if ((HEAP32[i7 >> 2] | 0) == 44) {
+    do {
+     _luaX_next(i10);
+     _luaK_exp2nextreg(HEAP32[i9 >> 2] | 0, i6);
+     _subexpr(i10, i6, 0) | 0;
+    } while ((HEAP32[i7 >> 2] | 0) == 44);
+   }
+   _luaK_setreturns(i5, i6, -1);
+  }
+  _check_match(i10, 41, 40, i1);
+ } else if ((i8 | 0) == 123) {
+  _constructor(i10, i6);
+ } else {
+  _luaX_syntaxerror(i10, 6624);
+ }
+ i8 = i2 + 8 | 0;
+ i7 = HEAP32[i8 >> 2] | 0;
+ i9 = HEAP32[i6 >> 2] | 0;
+ if ((i9 | 0) == 0) {
+  i4 = 13;
+ } else if ((i9 | 0) == 13 | (i9 | 0) == 12) {
+  i6 = 0;
+ } else {
+  _luaK_exp2nextreg(i5, i6);
+  i4 = 13;
+ }
+ if ((i4 | 0) == 13) {
+  i6 = (HEAPU8[i5 + 48 | 0] | 0) - i7 | 0;
+ }
+ i10 = _luaK_codeABC(i5, 29, i7, i6, 2) | 0;
+ HEAP32[i2 + 16 >> 2] = -1;
+ HEAP32[i2 + 20 >> 2] = -1;
+ HEAP32[i2 >> 2] = 12;
+ HEAP32[i8 >> 2] = i10;
+ _luaK_fixline(i5, i1);
+ HEAP8[i5 + 48 | 0] = i7 + 1;
+ STACKTOP = i3;
+ return;
+}
+function _luaD_reallocstack(i3, i6) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i1 = STACKTOP;
+ i2 = i3 + 28 | 0;
+ i8 = HEAP32[i2 >> 2] | 0;
+ i7 = i3 + 32 | 0;
+ i9 = HEAP32[i7 >> 2] | 0;
+ if ((i6 + 1 | 0) >>> 0 > 268435455) {
+  _luaM_toobig(i3);
+ }
+ i5 = _luaM_realloc_(i3, i8, i9 << 4, i6 << 4) | 0;
+ HEAP32[i2 >> 2] = i5;
+ if ((i9 | 0) < (i6 | 0)) {
+  do {
+   HEAP32[i5 + (i9 << 4) + 8 >> 2] = 0;
+   i9 = i9 + 1 | 0;
+  } while ((i9 | 0) != (i6 | 0));
+ }
+ HEAP32[i7 >> 2] = i6;
+ HEAP32[i3 + 24 >> 2] = i5 + (i6 + -5 << 4);
+ i6 = i3 + 8 | 0;
+ HEAP32[i6 >> 2] = i5 + ((HEAP32[i6 >> 2] | 0) - i8 >> 4 << 4);
+ i6 = HEAP32[i3 + 56 >> 2] | 0;
+ if ((i6 | 0) != 0 ? (i4 = i6 + 8 | 0, HEAP32[i4 >> 2] = i5 + ((HEAP32[i4 >> 2] | 0) - i8 >> 4 << 4), i4 = HEAP32[i6 >> 2] | 0, (i4 | 0) != 0) : 0) {
+  do {
+   i9 = i4 + 8 | 0;
+   HEAP32[i9 >> 2] = (HEAP32[i2 >> 2] | 0) + ((HEAP32[i9 >> 2] | 0) - i8 >> 4 << 4);
+   i4 = HEAP32[i4 >> 2] | 0;
+  } while ((i4 | 0) != 0);
+ }
+ i3 = HEAP32[i3 + 16 >> 2] | 0;
+ if ((i3 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ do {
+  i9 = i3 + 4 | 0;
+  HEAP32[i9 >> 2] = (HEAP32[i2 >> 2] | 0) + ((HEAP32[i9 >> 2] | 0) - i8 >> 4 << 4);
+  HEAP32[i3 >> 2] = (HEAP32[i2 >> 2] | 0) + ((HEAP32[i3 >> 2] | 0) - i8 >> 4 << 4);
+  if (!((HEAP8[i3 + 18 | 0] & 1) == 0)) {
+   i9 = i3 + 24 | 0;
+   HEAP32[i9 >> 2] = (HEAP32[i2 >> 2] | 0) + ((HEAP32[i9 >> 2] | 0) - i8 >> 4 << 4);
+  }
+  i3 = HEAP32[i3 + 8 >> 2] | 0;
+ } while ((i3 | 0) != 0);
+ STACKTOP = i1;
+ return;
+}
+function _luaF_close(i7, i6) {
+ i7 = i7 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i7 + 12 >> 2] | 0;
+ i3 = i7 + 56 | 0;
+ i8 = HEAP32[i3 >> 2] | 0;
+ if ((i8 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i5 = i4 + 60 | 0;
+ i2 = i4 + 68 | 0;
+ while (1) {
+  i9 = i8 + 8 | 0;
+  if ((HEAP32[i9 >> 2] | 0) >>> 0 < i6 >>> 0) {
+   i2 = 10;
+   break;
+  }
+  HEAP32[i3 >> 2] = HEAP32[i8 >> 2];
+  if ((((HEAPU8[i5] | 0) ^ 3) & ((HEAPU8[i8 + 5 | 0] | 0) ^ 3) | 0) == 0) {
+   if ((HEAP32[i9 >> 2] | 0) != (i8 + 16 | 0)) {
+    i9 = i8 + 16 | 0;
+    i10 = i9 + 4 | 0;
+    HEAP32[(HEAP32[i10 >> 2] | 0) + 16 >> 2] = HEAP32[i9 >> 2];
+    HEAP32[(HEAP32[i9 >> 2] | 0) + 20 >> 2] = HEAP32[i10 >> 2];
+   }
+   _luaM_realloc_(i7, i8, 32, 0) | 0;
+  } else {
+   i11 = i8 + 16 | 0;
+   i10 = i11 + 4 | 0;
+   HEAP32[(HEAP32[i10 >> 2] | 0) + 16 >> 2] = HEAP32[i11 >> 2];
+   HEAP32[(HEAP32[i11 >> 2] | 0) + 20 >> 2] = HEAP32[i10 >> 2];
+   i11 = HEAP32[i9 >> 2] | 0;
+   i10 = i8 + 16 | 0;
+   i14 = i11;
+   i13 = HEAP32[i14 + 4 >> 2] | 0;
+   i12 = i10;
+   HEAP32[i12 >> 2] = HEAP32[i14 >> 2];
+   HEAP32[i12 + 4 >> 2] = i13;
+   HEAP32[i8 + 24 >> 2] = HEAP32[i11 + 8 >> 2];
+   HEAP32[i9 >> 2] = i10;
+   HEAP32[i8 >> 2] = HEAP32[i2 >> 2];
+   HEAP32[i2 >> 2] = i8;
+   _luaC_checkupvalcolor(i4, i8);
+  }
+  i8 = HEAP32[i3 >> 2] | 0;
+  if ((i8 | 0) == 0) {
+   i2 = 10;
+   break;
+  }
+ }
+ if ((i2 | 0) == 10) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function _luaK_dischargevars(i3, i1) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ switch (HEAP32[i1 >> 2] | 0) {
+ case 12:
+  {
+   HEAP32[i1 >> 2] = 6;
+   i6 = i1 + 8 | 0;
+   HEAP32[i6 >> 2] = (HEAP32[(HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i6 >> 2] << 2) >> 2] | 0) >>> 6 & 255;
+   STACKTOP = i2;
+   return;
+  }
+ case 13:
+  {
+   i6 = (HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i1 + 8 >> 2] << 2) | 0;
+   HEAP32[i6 >> 2] = HEAP32[i6 >> 2] & 8388607 | 16777216;
+   HEAP32[i1 >> 2] = 11;
+   STACKTOP = i2;
+   return;
+  }
+ case 9:
+  {
+   i4 = i1 + 8 | 0;
+   i5 = HEAP16[i4 >> 1] | 0;
+   if ((i5 & 256 | 0) == 0 ? (HEAPU8[i3 + 46 | 0] | 0) <= (i5 | 0) : 0) {
+    i6 = i3 + 48 | 0;
+    HEAP8[i6] = (HEAP8[i6] | 0) + -1 << 24 >> 24;
+   }
+   i5 = i4 + 2 | 0;
+   if ((HEAP8[i4 + 3 | 0] | 0) == 7) {
+    if ((HEAPU8[i3 + 46 | 0] | 0) > (HEAPU8[i5] | 0)) {
+     i6 = 7;
+    } else {
+     i6 = i3 + 48 | 0;
+     HEAP8[i6] = (HEAP8[i6] | 0) + -1 << 24 >> 24;
+     i6 = 7;
+    }
+   } else {
+    i6 = 6;
+   }
+   HEAP32[i4 >> 2] = _luaK_code(i3, HEAPU8[i5] << 23 | i6 | HEAP16[i4 >> 1] << 14) | 0;
+   HEAP32[i1 >> 2] = 11;
+   STACKTOP = i2;
+   return;
+  }
+ case 7:
+  {
+   HEAP32[i1 >> 2] = 6;
+   STACKTOP = i2;
+   return;
+  }
+ case 8:
+  {
+   i6 = i1 + 8 | 0;
+   HEAP32[i6 >> 2] = _luaK_code(i3, HEAP32[i6 >> 2] << 23 | 5) | 0;
+   HEAP32[i1 >> 2] = 11;
+   STACKTOP = i2;
+   return;
+  }
+ default:
+  {
+   STACKTOP = i2;
+   return;
+  }
+ }
+}
+function _gmatch_aux(i10) {
+ i10 = i10 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i11 = 0, i12 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 288 | 0;
+ i2 = i1 + 8 | 0;
+ i12 = i1 + 4 | 0;
+ i3 = i1;
+ i8 = _lua_tolstring(i10, -1001001, i12) | 0;
+ i7 = _lua_tolstring(i10, -1001002, i3) | 0;
+ i5 = i2 + 16 | 0;
+ HEAP32[i5 >> 2] = i10;
+ HEAP32[i2 >> 2] = 200;
+ HEAP32[i2 + 4 >> 2] = i8;
+ i9 = i2 + 8 | 0;
+ HEAP32[i9 >> 2] = i8 + (HEAP32[i12 >> 2] | 0);
+ HEAP32[i2 + 12 >> 2] = i7 + (HEAP32[i3 >> 2] | 0);
+ i3 = i8 + (_lua_tointegerx(i10, -1001003, 0) | 0) | 0;
+ if (i3 >>> 0 > (HEAP32[i9 >> 2] | 0) >>> 0) {
+  i12 = 0;
+  STACKTOP = i1;
+  return i12 | 0;
+ }
+ i11 = i2 + 20 | 0;
+ while (1) {
+  HEAP32[i11 >> 2] = 0;
+  i4 = _match(i2, i3, i7) | 0;
+  i12 = i3 + 1 | 0;
+  if ((i4 | 0) != 0) {
+   break;
+  }
+  if (i12 >>> 0 > (HEAP32[i9 >> 2] | 0) >>> 0) {
+   i2 = 0;
+   i6 = 7;
+   break;
+  } else {
+   i3 = i12;
+  }
+ }
+ if ((i6 | 0) == 7) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ _lua_pushinteger(i10, i4 - i8 + ((i4 | 0) == (i3 | 0)) | 0);
+ _lua_replace(i10, -1001003);
+ i7 = HEAP32[i11 >> 2] | 0;
+ i6 = (i7 | 0) != 0 | (i3 | 0) == 0 ? i7 : 1;
+ _luaL_checkstack(HEAP32[i5 >> 2] | 0, i6, 7200);
+ if ((i6 | 0) > 0) {
+  i5 = 0;
+ } else {
+  i12 = i7;
+  STACKTOP = i1;
+  return i12 | 0;
+ }
+ while (1) {
+  _push_onecapture(i2, i5, i3, i4);
+  i5 = i5 + 1 | 0;
+  if ((i5 | 0) == (i6 | 0)) {
+   i2 = i6;
+   break;
+  }
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _lua_rawseti(i1, i5, i3) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i6 = 0;
+ i2 = STACKTOP;
+ i6 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i5 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i5 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i6 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i6 >> 2] | 0, (i5 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i4 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i6 >> 2] | 0) + (i5 << 4) | 0;
+   i5 = i4 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i4 = i1 + 8 | 0;
+ _luaH_setint(i1, HEAP32[i5 >> 2] | 0, i3, (HEAP32[i4 >> 2] | 0) + -16 | 0);
+ i3 = HEAP32[i4 >> 2] | 0;
+ if ((HEAP32[i3 + -8 >> 2] & 64 | 0) == 0) {
+  i6 = i3;
+  i6 = i6 + -16 | 0;
+  HEAP32[i4 >> 2] = i6;
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP8[(HEAP32[i3 + -16 >> 2] | 0) + 5 | 0] & 3) == 0) {
+  i6 = i3;
+  i6 = i6 + -16 | 0;
+  HEAP32[i4 >> 2] = i6;
+  STACKTOP = i2;
+  return;
+ }
+ i5 = HEAP32[i5 >> 2] | 0;
+ if ((HEAP8[i5 + 5 | 0] & 4) == 0) {
+  i6 = i3;
+  i6 = i6 + -16 | 0;
+  HEAP32[i4 >> 2] = i6;
+  STACKTOP = i2;
+  return;
+ }
+ _luaC_barrierback_(i1, i5);
+ i6 = HEAP32[i4 >> 2] | 0;
+ i6 = i6 + -16 | 0;
+ HEAP32[i4 >> 2] = i6;
+ STACKTOP = i2;
+ return;
+}
+function _ll_require(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i5 = i2;
+ i4 = i2 + 8 | 0;
+ i3 = _luaL_checklstring(i1, 1, 0) | 0;
+ _lua_settop(i1, 1);
+ _lua_getfield(i1, -1001e3, 4576);
+ _lua_getfield(i1, 2, i3);
+ if ((_lua_toboolean(i1, -1) | 0) != 0) {
+  STACKTOP = i2;
+  return 1;
+ }
+ _lua_settop(i1, -2);
+ _luaL_buffinit(i1, i4);
+ _lua_getfield(i1, -1001001, 4240);
+ if ((_lua_type(i1, 3) | 0) == 5) {
+  i6 = 1;
+ } else {
+  _luaL_error(i1, 4656, i5) | 0;
+  i6 = 1;
+ }
+ while (1) {
+  _lua_rawgeti(i1, 3, i6);
+  if ((_lua_type(i1, -1) | 0) == 0) {
+   _lua_settop(i1, -2);
+   _luaL_pushresult(i4);
+   i7 = _lua_tolstring(i1, -1, 0) | 0;
+   HEAP32[i5 >> 2] = i3;
+   HEAP32[i5 + 4 >> 2] = i7;
+   _luaL_error(i1, 4696, i5) | 0;
+  }
+  _lua_pushstring(i1, i3) | 0;
+  _lua_callk(i1, 1, 2, 0, 0);
+  if ((_lua_type(i1, -2) | 0) == 6) {
+   break;
+  }
+  if ((_lua_isstring(i1, -2) | 0) == 0) {
+   _lua_settop(i1, -3);
+  } else {
+   _lua_settop(i1, -2);
+   _luaL_addvalue(i4);
+  }
+  i6 = i6 + 1 | 0;
+ }
+ _lua_pushstring(i1, i3) | 0;
+ _lua_insert(i1, -2);
+ _lua_callk(i1, 2, 1, 0, 0);
+ if ((_lua_type(i1, -1) | 0) != 0) {
+  _lua_setfield(i1, 2, i3);
+ }
+ _lua_getfield(i1, 2, i3);
+ if ((_lua_type(i1, -1) | 0) != 0) {
+  STACKTOP = i2;
+  return 1;
+ }
+ _lua_pushboolean(i1, 1);
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, 2, i3);
+ STACKTOP = i2;
+ return 1;
+}
+function _f_parser(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i5 = HEAP32[i3 >> 2] | 0;
+ i8 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i8 + -1;
+ if ((i8 | 0) == 0) {
+  i6 = _luaZ_fill(i5) | 0;
+ } else {
+  i8 = i5 + 4 | 0;
+  i6 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i6 + 1;
+  i6 = HEAPU8[i6] | 0;
+ }
+ i5 = HEAP32[i3 + 52 >> 2] | 0;
+ i7 = (i5 | 0) == 0;
+ if ((i6 | 0) == 27) {
+  if (!i7 ? (_strchr(i5, 98) | 0) == 0 : 0) {
+   HEAP32[i4 >> 2] = 2360;
+   HEAP32[i4 + 4 >> 2] = i5;
+   _luaO_pushfstring(i1, 2376, i4) | 0;
+   _luaD_throw(i1, 3);
+  }
+  i8 = _luaU_undump(i1, HEAP32[i3 >> 2] | 0, i3 + 4 | 0, HEAP32[i3 + 56 >> 2] | 0) | 0;
+ } else {
+  if (!i7 ? (_strchr(i5, 116) | 0) == 0 : 0) {
+   HEAP32[i4 >> 2] = 2368;
+   HEAP32[i4 + 4 >> 2] = i5;
+   _luaO_pushfstring(i1, 2376, i4) | 0;
+   _luaD_throw(i1, 3);
+  }
+  i8 = _luaY_parser(i1, HEAP32[i3 >> 2] | 0, i3 + 4 | 0, i3 + 16 | 0, HEAP32[i3 + 56 >> 2] | 0, i6) | 0;
+ }
+ i7 = i8 + 6 | 0;
+ if ((HEAP8[i7] | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i5 = i8 + 16 | 0;
+ i6 = i8 + 5 | 0;
+ i4 = 0;
+ do {
+  i3 = _luaF_newupval(i1) | 0;
+  HEAP32[i5 + (i4 << 2) >> 2] = i3;
+  if (!((HEAP8[i3 + 5 | 0] & 3) == 0) ? !((HEAP8[i6] & 4) == 0) : 0) {
+   _luaC_barrier_(i1, i8, i3);
+  }
+  i4 = i4 + 1 | 0;
+ } while ((i4 | 0) < (HEAPU8[i7] | 0));
+ STACKTOP = i2;
+ return;
+}
+function _str_rep(i9) {
+ i9 = i9 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i4 = i6;
+ i2 = i6 + 1044 | 0;
+ i3 = i6 + 1040 | 0;
+ i1 = _luaL_checklstring(i9, 1, i2) | 0;
+ i8 = _luaL_checkinteger(i9, 2) | 0;
+ i5 = _luaL_optlstring(i9, 3, 7040, i3) | 0;
+ if ((i8 | 0) < 1) {
+  _lua_pushlstring(i9, 7040, 0) | 0;
+  i12 = 1;
+  STACKTOP = i6;
+  return i12 | 0;
+ }
+ i7 = HEAP32[i2 >> 2] | 0;
+ i10 = HEAP32[i3 >> 2] | 0;
+ i11 = i10 + i7 | 0;
+ if (!(i11 >>> 0 < i7 >>> 0) ? i11 >>> 0 < (2147483647 / (i8 >>> 0) | 0) >>> 0 : 0) {
+  i7 = (Math_imul(i10, i8 + -1 | 0) | 0) + (Math_imul(i7, i8) | 0) | 0;
+  i11 = _luaL_buffinitsize(i9, i4, i7) | 0;
+  _memcpy(i11 | 0, i1 | 0, HEAP32[i2 >> 2] | 0) | 0;
+  if ((i8 | 0) > 1) {
+   while (1) {
+    i8 = i8 + -1 | 0;
+    i9 = HEAP32[i2 >> 2] | 0;
+    i10 = i11 + i9 | 0;
+    i12 = HEAP32[i3 >> 2] | 0;
+    if ((i12 | 0) == 0) {
+     i12 = i9;
+    } else {
+     _memcpy(i10 | 0, i5 | 0, i12 | 0) | 0;
+     i12 = HEAP32[i2 >> 2] | 0;
+     i10 = i11 + ((HEAP32[i3 >> 2] | 0) + i9) | 0;
+    }
+    _memcpy(i10 | 0, i1 | 0, i12 | 0) | 0;
+    if ((i8 | 0) <= 1) {
+     break;
+    } else {
+     i11 = i10;
+    }
+   }
+  }
+  _luaL_pushresultsize(i4, i7);
+  i12 = 1;
+  STACKTOP = i6;
+  return i12 | 0;
+ }
+ i12 = _luaL_error(i9, 7168, i4) | 0;
+ STACKTOP = i6;
+ return i12 | 0;
+}
+function ___strchrnul(i6, i2) {
+ i6 = i6 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i3 = i2 & 255;
+ if ((i3 | 0) == 0) {
+  i7 = i6 + (_strlen(i6 | 0) | 0) | 0;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ L5 : do {
+  if ((i6 & 3 | 0) != 0) {
+   i4 = i2 & 255;
+   while (1) {
+    i5 = HEAP8[i6] | 0;
+    if (i5 << 24 >> 24 == 0) {
+     i4 = i6;
+     i5 = 13;
+     break;
+    }
+    i7 = i6 + 1 | 0;
+    if (i5 << 24 >> 24 == i4 << 24 >> 24) {
+     i4 = i6;
+     i5 = 13;
+     break;
+    }
+    if ((i7 & 3 | 0) == 0) {
+     i4 = i7;
+     break L5;
+    } else {
+     i6 = i7;
+    }
+   }
+   if ((i5 | 0) == 13) {
+    STACKTOP = i1;
+    return i4 | 0;
+   }
+  } else {
+   i4 = i6;
+  }
+ } while (0);
+ i3 = Math_imul(i3, 16843009) | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ L15 : do {
+  if (((i6 & -2139062144 ^ -2139062144) & i6 + -16843009 | 0) == 0) {
+   while (1) {
+    i7 = i6 ^ i3;
+    i5 = i4 + 4 | 0;
+    if (((i7 & -2139062144 ^ -2139062144) & i7 + -16843009 | 0) != 0) {
+     break L15;
+    }
+    i6 = HEAP32[i5 >> 2] | 0;
+    if (((i6 & -2139062144 ^ -2139062144) & i6 + -16843009 | 0) == 0) {
+     i4 = i5;
+    } else {
+     i4 = i5;
+     break;
+    }
+   }
+  }
+ } while (0);
+ i2 = i2 & 255;
+ while (1) {
+  i7 = HEAP8[i4] | 0;
+  if (i7 << 24 >> 24 == 0 | i7 << 24 >> 24 == i2 << 24 >> 24) {
+   break;
+  } else {
+   i4 = i4 + 1 | 0;
+  }
+ }
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _lua_replace(i2, i6) {
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i3 = STACKTOP;
+ i7 = i2 + 8 | 0;
+ i9 = HEAP32[i7 >> 2] | 0;
+ i5 = i9 + -16 | 0;
+ i4 = i2 + 16 | 0;
+ i12 = HEAP32[i4 >> 2] | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i10 = i9 + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i10 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i11 = -1001e3 - i6 | 0;
+   i12 = HEAP32[i12 >> 2] | 0;
+   if ((HEAP32[i12 + 8 >> 2] | 0) != 22 ? (i10 = HEAP32[i12 >> 2] | 0, (i11 | 0) <= (HEAPU8[i10 + 6 | 0] | 0 | 0)) : 0) {
+    i10 = i10 + (i11 + -1 << 4) + 16 | 0;
+   } else {
+    i10 = 5192;
+   }
+  } else {
+   i10 = (HEAP32[i12 >> 2] | 0) + (i6 << 4) | 0;
+   i10 = i10 >>> 0 < i9 >>> 0 ? i10 : 5192;
+  }
+ } while (0);
+ i13 = i5;
+ i11 = HEAP32[i13 + 4 >> 2] | 0;
+ i12 = i10;
+ HEAP32[i12 >> 2] = HEAP32[i13 >> 2];
+ HEAP32[i12 + 4 >> 2] = i11;
+ i9 = i9 + -8 | 0;
+ HEAP32[i10 + 8 >> 2] = HEAP32[i9 >> 2];
+ if ((((i6 | 0) < -1001e3 ? (HEAP32[i9 >> 2] & 64 | 0) != 0 : 0) ? (i1 = HEAP32[i5 >> 2] | 0, !((HEAP8[i1 + 5 | 0] & 3) == 0)) : 0) ? (i8 = HEAP32[HEAP32[HEAP32[i4 >> 2] >> 2] >> 2] | 0, !((HEAP8[i8 + 5 | 0] & 4) == 0)) : 0) {
+  _luaC_barrier_(i2, i8, i1);
+ }
+ HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + -16;
+ STACKTOP = i3;
+ return;
+}
+function _memchr(i4, i3, i6) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i2 = i3 & 255;
+ i7 = (i6 | 0) == 0;
+ L1 : do {
+  if ((i4 & 3 | 0) == 0 | i7) {
+   i5 = i6;
+   i6 = 5;
+  } else {
+   i5 = i3 & 255;
+   while (1) {
+    if ((HEAP8[i4] | 0) == i5 << 24 >> 24) {
+     i5 = i6;
+     i6 = 6;
+     break L1;
+    }
+    i4 = i4 + 1 | 0;
+    i6 = i6 + -1 | 0;
+    i7 = (i6 | 0) == 0;
+    if ((i4 & 3 | 0) == 0 | i7) {
+     i5 = i6;
+     i6 = 5;
+     break;
+    }
+   }
+  }
+ } while (0);
+ if ((i6 | 0) == 5) {
+  if (i7) {
+   i5 = 0;
+  } else {
+   i6 = 6;
+  }
+ }
+ L8 : do {
+  if ((i6 | 0) == 6) {
+   i3 = i3 & 255;
+   if (!((HEAP8[i4] | 0) == i3 << 24 >> 24)) {
+    i2 = Math_imul(i2, 16843009) | 0;
+    L11 : do {
+     if (i5 >>> 0 > 3) {
+      do {
+       i7 = HEAP32[i4 >> 2] ^ i2;
+       if (((i7 & -2139062144 ^ -2139062144) & i7 + -16843009 | 0) != 0) {
+        break L11;
+       }
+       i4 = i4 + 4 | 0;
+       i5 = i5 + -4 | 0;
+      } while (i5 >>> 0 > 3);
+     }
+    } while (0);
+    if ((i5 | 0) == 0) {
+     i5 = 0;
+    } else {
+     while (1) {
+      if ((HEAP8[i4] | 0) == i3 << 24 >> 24) {
+       break L8;
+      }
+      i4 = i4 + 1 | 0;
+      i5 = i5 + -1 | 0;
+      if ((i5 | 0) == 0) {
+       i5 = 0;
+       break;
+      }
+     }
+    }
+   }
+  }
+ } while (0);
+ STACKTOP = i1;
+ return ((i5 | 0) != 0 ? i4 : 0) | 0;
+}
+function _lua_insert(i2, i5) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i2 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i2 = i2 + 8 | 0;
+ i4 = HEAP32[i2 >> 2] | 0;
+ if (i4 >>> 0 > i3 >>> 0) {
+  while (1) {
+   i5 = i4 + -16 | 0;
+   i8 = i5;
+   i7 = HEAP32[i8 + 4 >> 2] | 0;
+   i6 = i4;
+   HEAP32[i6 >> 2] = HEAP32[i8 >> 2];
+   HEAP32[i6 + 4 >> 2] = i7;
+   HEAP32[i4 + 8 >> 2] = HEAP32[i4 + -8 >> 2];
+   if (i5 >>> 0 > i3 >>> 0) {
+    i4 = i5;
+   } else {
+    break;
+   }
+  }
+  i4 = HEAP32[i2 >> 2] | 0;
+ }
+ i6 = i4;
+ i7 = HEAP32[i6 + 4 >> 2] | 0;
+ i8 = i3;
+ HEAP32[i8 >> 2] = HEAP32[i6 >> 2];
+ HEAP32[i8 + 4 >> 2] = i7;
+ HEAP32[i3 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+ STACKTOP = i1;
+ return;
+}
+function _findlocal(i6, i4, i1, i2) {
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i5 = 0, i7 = 0, i8 = 0;
+ i3 = STACKTOP;
+ do {
+  if ((HEAP8[i4 + 18 | 0] & 1) == 0) {
+   i7 = (HEAP32[i4 >> 2] | 0) + 16 | 0;
+   i5 = 7;
+  } else {
+   if ((i1 | 0) >= 0) {
+    i8 = HEAP32[i4 + 24 >> 2] | 0;
+    i7 = HEAP32[(HEAP32[HEAP32[i4 >> 2] >> 2] | 0) + 12 >> 2] | 0;
+    i7 = _luaF_getlocalname(i7, i1, ((HEAP32[i4 + 28 >> 2] | 0) - (HEAP32[i7 + 12 >> 2] | 0) >> 2) + -1 | 0) | 0;
+    if ((i7 | 0) == 0) {
+     i7 = i8;
+     i5 = 7;
+     break;
+    } else {
+     break;
+    }
+   }
+   i5 = HEAP32[i4 >> 2] | 0;
+   i6 = HEAPU8[(HEAP32[(HEAP32[i5 >> 2] | 0) + 12 >> 2] | 0) + 76 | 0] | 0;
+   if ((((HEAP32[i4 + 24 >> 2] | 0) - i5 >> 4) - i6 | 0) <= (0 - i1 | 0)) {
+    i8 = 0;
+    STACKTOP = i3;
+    return i8 | 0;
+   }
+   HEAP32[i2 >> 2] = i5 + (i6 - i1 << 4);
+   i8 = 2208;
+   STACKTOP = i3;
+   return i8 | 0;
+  }
+ } while (0);
+ if ((i5 | 0) == 7) {
+  if ((HEAP32[i6 + 16 >> 2] | 0) == (i4 | 0)) {
+   i4 = i6 + 8 | 0;
+  } else {
+   i4 = HEAP32[i4 + 12 >> 2] | 0;
+  }
+  if (((HEAP32[i4 >> 2] | 0) - i7 >> 4 | 0) >= (i1 | 0) & (i1 | 0) > 0) {
+   i8 = i7;
+   i7 = 2192;
+  } else {
+   i8 = 0;
+   STACKTOP = i3;
+   return i8 | 0;
+  }
+ }
+ HEAP32[i2 >> 2] = i8 + (i1 + -1 << 4);
+ i8 = i7;
+ STACKTOP = i3;
+ return i8 | 0;
+}
+function _luaH_setint(i4, i5, i6, i1) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, d7 = 0.0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i8 = i2 + 16 | 0;
+ i3 = i2;
+ i9 = i6 + -1 | 0;
+ L1 : do {
+  if (i9 >>> 0 < (HEAP32[i5 + 28 >> 2] | 0) >>> 0) {
+   i9 = (HEAP32[i5 + 12 >> 2] | 0) + (i9 << 4) | 0;
+   i8 = 10;
+  } else {
+   d7 = +(i6 | 0);
+   HEAPF64[i8 >> 3] = d7 + 1.0;
+   i8 = (HEAP32[i8 + 4 >> 2] | 0) + (HEAP32[i8 >> 2] | 0) | 0;
+   if ((i8 | 0) < 0) {
+    i9 = 0 - i8 | 0;
+    i8 = (i8 | 0) == (i9 | 0) ? 0 : i9;
+   }
+   i9 = (HEAP32[i5 + 16 >> 2] | 0) + (((i8 | 0) % ((1 << (HEAPU8[i5 + 7 | 0] | 0)) + -1 | 1 | 0) | 0) << 5) | 0;
+   while (1) {
+    if ((HEAP32[i9 + 24 >> 2] | 0) == 3 ? +HEAPF64[i9 + 16 >> 3] == d7 : 0) {
+     break;
+    }
+    i9 = HEAP32[i9 + 28 >> 2] | 0;
+    if ((i9 | 0) == 0) {
+     i8 = 12;
+     break L1;
+    }
+   }
+   i8 = 10;
+  }
+ } while (0);
+ if ((i8 | 0) == 10) {
+  if ((i9 | 0) == 5192) {
+   d7 = +(i6 | 0);
+   i8 = 12;
+  }
+ }
+ if ((i8 | 0) == 12) {
+  HEAPF64[i3 >> 3] = d7;
+  HEAP32[i3 + 8 >> 2] = 3;
+  i9 = _luaH_newkey(i4, i5, i3) | 0;
+ }
+ i5 = i1;
+ i6 = HEAP32[i5 + 4 >> 2] | 0;
+ i8 = i9;
+ HEAP32[i8 >> 2] = HEAP32[i5 >> 2];
+ HEAP32[i8 + 4 >> 2] = i6;
+ HEAP32[i9 + 8 >> 2] = HEAP32[i1 + 8 >> 2];
+ STACKTOP = i2;
+ return;
+}
+function _lua_tounsignedx(i6, i8, i1) {
+ i6 = i6 | 0;
+ i8 = i8 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i4 = i2 + 8 | 0;
+ i3 = i2;
+ i7 = HEAP32[i6 + 16 >> 2] | 0;
+ do {
+  if ((i8 | 0) <= 0) {
+   if (!((i8 | 0) < -1000999)) {
+    i5 = (HEAP32[i6 + 8 >> 2] | 0) + (i8 << 4) | 0;
+    break;
+   }
+   if ((i8 | 0) == -1001e3) {
+    i5 = (HEAP32[i6 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i6 = -1001e3 - i8 | 0;
+   i7 = HEAP32[i7 >> 2] | 0;
+   if ((HEAP32[i7 + 8 >> 2] | 0) != 22 ? (i5 = HEAP32[i7 >> 2] | 0, (i6 | 0) <= (HEAPU8[i5 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i5 + (i6 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i5 = (HEAP32[i7 >> 2] | 0) + (i8 << 4) | 0;
+   i5 = i5 >>> 0 < (HEAP32[i6 + 8 >> 2] | 0) >>> 0 ? i5 : 5192;
+  }
+ } while (0);
+ if ((HEAP32[i5 + 8 >> 2] | 0) != 3) {
+  i5 = _luaV_tonumber(i5, i4) | 0;
+  if ((i5 | 0) == 0) {
+   if ((i1 | 0) == 0) {
+    i8 = 0;
+    STACKTOP = i2;
+    return i8 | 0;
+   }
+   HEAP32[i1 >> 2] = 0;
+   i8 = 0;
+   STACKTOP = i2;
+   return i8 | 0;
+  }
+ }
+ HEAPF64[i3 >> 3] = +HEAPF64[i5 >> 3] + 6755399441055744.0;
+ i3 = HEAP32[i3 >> 2] | 0;
+ if ((i1 | 0) == 0) {
+  i8 = i3;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ HEAP32[i1 >> 2] = 1;
+ i8 = i3;
+ STACKTOP = i2;
+ return i8 | 0;
+}
+function _luaC_freeallobjects(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ i5 = i1 + 12 | 0;
+ i3 = HEAP32[i5 >> 2] | 0;
+ i7 = i3 + 104 | 0;
+ while (1) {
+  i4 = HEAP32[i7 >> 2] | 0;
+  if ((i4 | 0) == 0) {
+   break;
+  } else {
+   i7 = i4;
+  }
+ }
+ i4 = i3 + 72 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  i5 = i3;
+ } else {
+  while (1) {
+   i8 = i6 + 5 | 0;
+   HEAP8[i8] = HEAPU8[i8] | 0 | 8;
+   HEAP32[i4 >> 2] = HEAP32[i6 >> 2];
+   HEAP32[i6 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i7 >> 2] = i6;
+   i7 = HEAP32[i4 >> 2] | 0;
+   if ((i7 | 0) == 0) {
+    break;
+   } else {
+    i8 = i6;
+    i6 = i7;
+    i7 = i8;
+   }
+  }
+  i5 = HEAP32[i5 >> 2] | 0;
+ }
+ i5 = i5 + 104 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ if ((i6 | 0) != 0) {
+  do {
+   i8 = i6 + 5 | 0;
+   HEAP8[i8] = HEAP8[i8] & 191;
+   _GCTM(i1, 0);
+   i6 = HEAP32[i5 >> 2] | 0;
+  } while ((i6 | 0) != 0);
+ }
+ HEAP8[i3 + 60 | 0] = 3;
+ HEAP8[i3 + 62 | 0] = 0;
+ _sweeplist(i1, i4, -3) | 0;
+ _sweeplist(i1, i3 + 68 | 0, -3) | 0;
+ i4 = i3 + 32 | 0;
+ if ((HEAP32[i4 >> 2] | 0) <= 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = i3 + 24 | 0;
+ i5 = 0;
+ do {
+  _sweeplist(i1, (HEAP32[i3 >> 2] | 0) + (i5 << 2) | 0, -3) | 0;
+  i5 = i5 + 1 | 0;
+ } while ((i5 | 0) < (HEAP32[i4 >> 2] | 0));
+ STACKTOP = i2;
+ return;
+}
+function _strspn(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i3 = i2;
+ HEAP32[i3 + 0 >> 2] = 0;
+ HEAP32[i3 + 4 >> 2] = 0;
+ HEAP32[i3 + 8 >> 2] = 0;
+ HEAP32[i3 + 12 >> 2] = 0;
+ HEAP32[i3 + 16 >> 2] = 0;
+ HEAP32[i3 + 20 >> 2] = 0;
+ HEAP32[i3 + 24 >> 2] = 0;
+ HEAP32[i3 + 28 >> 2] = 0;
+ i4 = HEAP8[i5] | 0;
+ if (i4 << 24 >> 24 == 0) {
+  i6 = 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ if ((HEAP8[i5 + 1 | 0] | 0) == 0) {
+  i3 = i1;
+  while (1) {
+   if ((HEAP8[i3] | 0) == i4 << 24 >> 24) {
+    i3 = i3 + 1 | 0;
+   } else {
+    break;
+   }
+  }
+  i6 = i3 - i1 | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ do {
+  i7 = i4 & 255;
+  i6 = i3 + (i7 >>> 5 << 2) | 0;
+  HEAP32[i6 >> 2] = HEAP32[i6 >> 2] | 1 << (i7 & 31);
+  i5 = i5 + 1 | 0;
+  i4 = HEAP8[i5] | 0;
+ } while (!(i4 << 24 >> 24 == 0));
+ i5 = HEAP8[i1] | 0;
+ L12 : do {
+  if (i5 << 24 >> 24 == 0) {
+   i4 = i1;
+  } else {
+   i4 = i1;
+   while (1) {
+    i7 = i5 & 255;
+    i6 = i4 + 1 | 0;
+    if ((HEAP32[i3 + (i7 >>> 5 << 2) >> 2] & 1 << (i7 & 31) | 0) == 0) {
+     break L12;
+    }
+    i5 = HEAP8[i6] | 0;
+    if (i5 << 24 >> 24 == 0) {
+     i4 = i6;
+     break;
+    } else {
+     i4 = i6;
+    }
+   }
+  }
+ } while (0);
+ i7 = i4 - i1 | 0;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _lua_remove(i2, i4) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i5 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i4 | 0) <= 0) {
+   if (!((i4 | 0) < -1000999)) {
+    i3 = (HEAP32[i2 + 8 >> 2] | 0) + (i4 << 4) | 0;
+    break;
+   }
+   if ((i4 | 0) == -1001e3) {
+    i3 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i4 = -1001e3 - i4 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i5 >> 2] | 0, (i4 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i4 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i5 >> 2] | 0) + (i4 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i4 = i3 + 16 | 0;
+ i2 = i2 + 8 | 0;
+ i5 = HEAP32[i2 >> 2] | 0;
+ if (!(i4 >>> 0 < i5 >>> 0)) {
+  i5 = i5 + -16 | 0;
+  HEAP32[i2 >> 2] = i5;
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i7 = i4;
+  i6 = HEAP32[i7 + 4 >> 2] | 0;
+  i5 = i3;
+  HEAP32[i5 >> 2] = HEAP32[i7 >> 2];
+  HEAP32[i5 + 4 >> 2] = i6;
+  HEAP32[i3 + 8 >> 2] = HEAP32[i3 + 24 >> 2];
+  i5 = i4 + 16 | 0;
+  i3 = HEAP32[i2 >> 2] | 0;
+  if (i5 >>> 0 < i3 >>> 0) {
+   i3 = i4;
+   i4 = i5;
+  } else {
+   break;
+  }
+ }
+ i7 = i3 + -16 | 0;
+ HEAP32[i2 >> 2] = i7;
+ STACKTOP = i1;
+ return;
+}
+function _luaD_protectedparser(i1, i4, i3, i2) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i13 = i5;
+ i6 = i1 + 36 | 0;
+ HEAP16[i6 >> 1] = (HEAP16[i6 >> 1] | 0) + 1 << 16 >> 16;
+ HEAP32[i13 >> 2] = i4;
+ HEAP32[i13 + 56 >> 2] = i3;
+ HEAP32[i13 + 52 >> 2] = i2;
+ i10 = i13 + 16 | 0;
+ HEAP32[i10 >> 2] = 0;
+ i9 = i13 + 24 | 0;
+ HEAP32[i9 >> 2] = 0;
+ i8 = i13 + 28 | 0;
+ HEAP32[i8 >> 2] = 0;
+ i7 = i13 + 36 | 0;
+ HEAP32[i7 >> 2] = 0;
+ i2 = i13 + 40 | 0;
+ HEAP32[i2 >> 2] = 0;
+ i3 = i13 + 48 | 0;
+ HEAP32[i3 >> 2] = 0;
+ i12 = i13 + 4 | 0;
+ HEAP32[i12 >> 2] = 0;
+ i11 = i13 + 12 | 0;
+ HEAP32[i11 >> 2] = 0;
+ i4 = _luaD_pcall(i1, 6, i13, (HEAP32[i1 + 8 >> 2] | 0) - (HEAP32[i1 + 28 >> 2] | 0) | 0, HEAP32[i1 + 68 >> 2] | 0) | 0;
+ HEAP32[i12 >> 2] = _luaM_realloc_(i1, HEAP32[i12 >> 2] | 0, HEAP32[i11 >> 2] | 0, 0) | 0;
+ HEAP32[i11 >> 2] = 0;
+ _luaM_realloc_(i1, HEAP32[i10 >> 2] | 0, HEAP32[i9 >> 2] << 1, 0) | 0;
+ _luaM_realloc_(i1, HEAP32[i8 >> 2] | 0, HEAP32[i7 >> 2] << 4, 0) | 0;
+ _luaM_realloc_(i1, HEAP32[i2 >> 2] | 0, HEAP32[i3 >> 2] << 4, 0) | 0;
+ HEAP16[i6 >> 1] = (HEAP16[i6 >> 1] | 0) + -1 << 16 >> 16;
+ STACKTOP = i5;
+ return i4 | 0;
+}
+function _markmt(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i1 + 252 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 256 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 260 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 264 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 268 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 272 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 276 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 280 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 284 >> 2] | 0;
+ if ((i3 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP8[i3 + 5 | 0] & 3) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ _reallymarkobject(i1, i3);
+ STACKTOP = i2;
+ return;
+}
+function _findlabel(i9, i2) {
+ i9 = i9 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i1 = STACKTOP;
+ i3 = i9 + 48 | 0;
+ i7 = HEAP32[(HEAP32[i3 >> 2] | 0) + 16 >> 2] | 0;
+ i10 = HEAP32[i9 + 64 >> 2] | 0;
+ i4 = HEAP32[i10 + 12 >> 2] | 0;
+ i6 = i7 + 4 | 0;
+ i13 = HEAP16[i6 >> 1] | 0;
+ i5 = i10 + 28 | 0;
+ if ((i13 | 0) >= (HEAP32[i5 >> 2] | 0)) {
+  i15 = 0;
+  STACKTOP = i1;
+  return i15 | 0;
+ }
+ i10 = i10 + 24 | 0;
+ i11 = i4 + (i2 << 4) | 0;
+ while (1) {
+  i14 = HEAP32[i10 >> 2] | 0;
+  i12 = i14 + (i13 << 4) | 0;
+  i15 = i13 + 1 | 0;
+  if ((_luaS_eqstr(HEAP32[i12 >> 2] | 0, HEAP32[i11 >> 2] | 0) | 0) != 0) {
+   break;
+  }
+  if ((i15 | 0) < (HEAP32[i5 >> 2] | 0)) {
+   i13 = i15;
+  } else {
+   i2 = 0;
+   i8 = 10;
+   break;
+  }
+ }
+ if ((i8 | 0) == 10) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ i8 = HEAP8[i14 + (i13 << 4) + 12 | 0] | 0;
+ do {
+  if ((HEAPU8[i4 + (i2 << 4) + 12 | 0] | 0) > (i8 & 255)) {
+   if ((HEAP8[i7 + 9 | 0] | 0) == 0 ? (HEAP32[i5 >> 2] | 0) <= (HEAP16[i6 >> 1] | 0) : 0) {
+    break;
+   }
+   _luaK_patchclose(HEAP32[i3 >> 2] | 0, HEAP32[i4 + (i2 << 4) + 4 >> 2] | 0, i8 & 255);
+  }
+ } while (0);
+ _closegoto(i9, i2, i12);
+ i15 = 1;
+ STACKTOP = i1;
+ return i15 | 0;
+}
+function _lua_getmetatable(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i4 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i4 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i4 = i3 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i3 = HEAP32[i4 + 8 >> 2] & 15;
+ if ((i3 | 0) == 7) {
+  i3 = HEAP32[(HEAP32[i4 >> 2] | 0) + 8 >> 2] | 0;
+ } else if ((i3 | 0) == 5) {
+  i3 = HEAP32[(HEAP32[i4 >> 2] | 0) + 8 >> 2] | 0;
+ } else {
+  i3 = HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + (i3 << 2) + 252 >> 2] | 0;
+ }
+ if ((i3 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ i5 = i1 + 8 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i4 >> 2] = i3;
+ HEAP32[i4 + 8 >> 2] = 69;
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 16;
+ i5 = 1;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _str_byte(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i6 = i1;
+ i4 = i1 + 4 | 0;
+ i3 = _luaL_checklstring(i2, 1, i4) | 0;
+ i5 = _luaL_optinteger(i2, 2, 1) | 0;
+ i7 = HEAP32[i4 >> 2] | 0;
+ if (!((i5 | 0) > -1)) {
+  if (i7 >>> 0 < (0 - i5 | 0) >>> 0) {
+   i5 = 0;
+  } else {
+   i5 = i5 + 1 + i7 | 0;
+  }
+ }
+ i8 = _luaL_optinteger(i2, 3, i5) | 0;
+ i7 = HEAP32[i4 >> 2] | 0;
+ if (!((i8 | 0) > -1)) {
+  if (i7 >>> 0 < (0 - i8 | 0) >>> 0) {
+   i8 = 0;
+  } else {
+   i8 = i8 + 1 + i7 | 0;
+  }
+ }
+ i9 = (i5 | 0) == 0 ? 1 : i5;
+ i10 = i8 >>> 0 > i7 >>> 0 ? i7 : i8;
+ if (i9 >>> 0 > i10 >>> 0) {
+  i10 = 0;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ i4 = i10 - i9 + 1 | 0;
+ if ((i10 | 0) == -1) {
+  i10 = _luaL_error(i2, 7944, i6) | 0;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ _luaL_checkstack(i2, i4, 7944);
+ if ((i4 | 0) <= 0) {
+  i10 = i4;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ i6 = i9 + -1 | 0;
+ i8 = ~i8;
+ i7 = ~i7;
+ i5 = 0 - (i8 >>> 0 > i7 >>> 0 ? i8 : i7) - (i5 >>> 0 > 1 ? i5 : 1) | 0;
+ i7 = 0;
+ do {
+  _lua_pushinteger(i2, HEAPU8[i3 + (i6 + i7) | 0] | 0);
+  i7 = i7 + 1 | 0;
+ } while ((i7 | 0) != (i5 | 0));
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _lua_setuservalue(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i3 = STACKTOP;
+ i6 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i5 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i5 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i6 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i6 >> 2] | 0, (i5 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i4 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i6 >> 2] | 0) + (i5 << 4) | 0;
+   i5 = i4 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i4 = i1 + 8 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ if ((HEAP32[i6 + -8 >> 2] | 0) != 0) {
+  HEAP32[(HEAP32[i5 >> 2] | 0) + 12 >> 2] = HEAP32[i6 + -16 >> 2];
+  i6 = HEAP32[(HEAP32[i4 >> 2] | 0) + -16 >> 2] | 0;
+  if (!((HEAP8[i6 + 5 | 0] & 3) == 0) ? (i2 = HEAP32[i5 >> 2] | 0, !((HEAP8[i2 + 5 | 0] & 4) == 0)) : 0) {
+   _luaC_barrier_(i1, i2, i6);
+  }
+ } else {
+  HEAP32[(HEAP32[i5 >> 2] | 0) + 12 >> 2] = 0;
+ }
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + -16;
+ STACKTOP = i3;
+ return;
+}
+function _f_luaopen(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i6;
+ i4 = HEAP32[i1 + 12 >> 2] | 0;
+ i2 = _luaM_realloc_(i1, 0, 0, 640) | 0;
+ HEAP32[i1 + 28 >> 2] = i2;
+ i3 = i1 + 32 | 0;
+ HEAP32[i3 >> 2] = 40;
+ i7 = 0;
+ do {
+  HEAP32[i2 + (i7 << 4) + 8 >> 2] = 0;
+  i7 = i7 + 1 | 0;
+ } while ((i7 | 0) != 40);
+ HEAP32[i1 + 24 >> 2] = i2 + ((HEAP32[i3 >> 2] | 0) + -5 << 4);
+ i7 = i1 + 72 | 0;
+ HEAP32[i1 + 80 >> 2] = 0;
+ HEAP32[i1 + 84 >> 2] = 0;
+ HEAP8[i1 + 90 | 0] = 0;
+ HEAP32[i7 >> 2] = i2;
+ HEAP32[i1 + 8 >> 2] = i2 + 16;
+ HEAP32[i2 + 8 >> 2] = 0;
+ HEAP32[i1 + 76 >> 2] = i2 + 336;
+ HEAP32[i1 + 16 >> 2] = i7;
+ i7 = _luaH_new(i1) | 0;
+ HEAP32[i4 + 40 >> 2] = i7;
+ HEAP32[i4 + 48 >> 2] = 69;
+ _luaH_resize(i1, i7, 2, 0);
+ HEAP32[i5 >> 2] = i1;
+ i3 = i5 + 8 | 0;
+ HEAP32[i3 >> 2] = 72;
+ _luaH_setint(i1, i7, 1, i5);
+ HEAP32[i5 >> 2] = _luaH_new(i1) | 0;
+ HEAP32[i3 >> 2] = 69;
+ _luaH_setint(i1, i7, 2, i5);
+ _luaS_resize(i1, 32);
+ _luaT_init(i1);
+ _luaX_init(i1);
+ i7 = _luaS_newlstr(i1, 6896, 17) | 0;
+ HEAP32[i4 + 180 >> 2] = i7;
+ i7 = i7 + 5 | 0;
+ HEAP8[i7] = HEAPU8[i7] | 0 | 32;
+ HEAP8[i4 + 63 | 0] = 1;
+ STACKTOP = i6;
+ return;
+}
+function _lua_tointegerx(i6, i7, i1) {
+ i6 = i6 | 0;
+ i7 = i7 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i5 = HEAP32[i6 + 16 >> 2] | 0;
+ do {
+  if ((i7 | 0) <= 0) {
+   if (!((i7 | 0) < -1000999)) {
+    i4 = (HEAP32[i6 + 8 >> 2] | 0) + (i7 << 4) | 0;
+    break;
+   }
+   if ((i7 | 0) == -1001e3) {
+    i4 = (HEAP32[i6 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i6 = -1001e3 - i7 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i5 >> 2] | 0, (i6 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i4 + (i6 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i5 >> 2] | 0) + (i7 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i6 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ if ((HEAP32[i4 + 8 >> 2] | 0) != 3) {
+  i4 = _luaV_tonumber(i4, i3) | 0;
+  if ((i4 | 0) == 0) {
+   if ((i1 | 0) == 0) {
+    i7 = 0;
+    STACKTOP = i2;
+    return i7 | 0;
+   }
+   HEAP32[i1 >> 2] = 0;
+   i7 = 0;
+   STACKTOP = i2;
+   return i7 | 0;
+  }
+ }
+ i3 = ~~+HEAPF64[i4 >> 3];
+ if ((i1 | 0) == 0) {
+  i7 = i3;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ HEAP32[i1 >> 2] = 1;
+ i7 = i3;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _close_state(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ i6 = i1 + 12 | 0;
+ i3 = HEAP32[i6 >> 2] | 0;
+ i4 = i1 + 28 | 0;
+ _luaF_close(i1, HEAP32[i4 >> 2] | 0);
+ _luaC_freeallobjects(i1);
+ i6 = HEAP32[i6 >> 2] | 0;
+ _luaM_realloc_(i1, HEAP32[i6 + 24 >> 2] | 0, HEAP32[i6 + 32 >> 2] << 2, 0) | 0;
+ i6 = i3 + 144 | 0;
+ i5 = i3 + 152 | 0;
+ HEAP32[i6 >> 2] = _luaM_realloc_(i1, HEAP32[i6 >> 2] | 0, HEAP32[i5 >> 2] | 0, 0) | 0;
+ HEAP32[i5 >> 2] = 0;
+ i5 = HEAP32[i4 >> 2] | 0;
+ if ((i5 | 0) == 0) {
+  i5 = HEAP32[i3 >> 2] | 0;
+  i6 = i3 + 4 | 0;
+  i6 = HEAP32[i6 >> 2] | 0;
+  FUNCTION_TABLE_iiiii[i5 & 3](i6, i1, 400, 0) | 0;
+  STACKTOP = i2;
+  return;
+ }
+ HEAP32[i1 + 16 >> 2] = i1 + 72;
+ i7 = i1 + 84 | 0;
+ i6 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = 0;
+ if ((i6 | 0) != 0) {
+  while (1) {
+   i5 = HEAP32[i6 + 12 >> 2] | 0;
+   _luaM_realloc_(i1, i6, 40, 0) | 0;
+   if ((i5 | 0) == 0) {
+    break;
+   } else {
+    i6 = i5;
+   }
+  }
+  i5 = HEAP32[i4 >> 2] | 0;
+ }
+ _luaM_realloc_(i1, i5, HEAP32[i1 + 32 >> 2] << 4, 0) | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ i7 = i3 + 4 | 0;
+ i7 = HEAP32[i7 >> 2] | 0;
+ FUNCTION_TABLE_iiiii[i6 & 3](i7, i1, 400, 0) | 0;
+ STACKTOP = i2;
+ return;
+}
+function _ll_module(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i4 = i2;
+ i5 = i2 + 4 | 0;
+ i6 = _luaL_checklstring(i1, 1, 0) | 0;
+ i3 = _lua_gettop(i1) | 0;
+ _luaL_pushmodule(i1, i6, 1);
+ _lua_getfield(i1, -1, 4728);
+ i7 = (_lua_type(i1, -1) | 0) == 0;
+ _lua_settop(i1, -2);
+ if (i7) {
+  _lua_pushvalue(i1, -1);
+  _lua_setfield(i1, -2, 4784);
+  _lua_pushstring(i1, i6) | 0;
+  _lua_setfield(i1, -2, 4728);
+  i7 = _strrchr(i6, 46) | 0;
+  _lua_pushlstring(i1, i6, ((i7 | 0) == 0 ? i6 : i7 + 1 | 0) - i6 | 0) | 0;
+  _lua_setfield(i1, -2, 4792);
+ }
+ _lua_pushvalue(i1, -1);
+ if (!(((_lua_getstack(i1, 1, i5) | 0) != 0 ? (_lua_getinfo(i1, 4736, i5) | 0) != 0 : 0) ? (_lua_iscfunction(i1, -1) | 0) == 0 : 0)) {
+  _luaL_error(i1, 4744, i4) | 0;
+ }
+ _lua_pushvalue(i1, -2);
+ _lua_setupvalue(i1, -2, 1) | 0;
+ _lua_settop(i1, -2);
+ if ((i3 | 0) < 2) {
+  STACKTOP = i2;
+  return 1;
+ } else {
+  i4 = 2;
+ }
+ while (1) {
+  if ((_lua_type(i1, i4) | 0) == 6) {
+   _lua_pushvalue(i1, i4);
+   _lua_pushvalue(i1, -2);
+   _lua_callk(i1, 1, 0, 0, 0);
+  }
+  if ((i4 | 0) == (i3 | 0)) {
+   break;
+  } else {
+   i4 = i4 + 1 | 0;
+  }
+ }
+ STACKTOP = i2;
+ return 1;
+}
+function _strcspn(i2, i5) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i3 = i1;
+ i4 = HEAP8[i5] | 0;
+ if (!(i4 << 24 >> 24 == 0) ? (HEAP8[i5 + 1 | 0] | 0) != 0 : 0) {
+  HEAP32[i3 + 0 >> 2] = 0;
+  HEAP32[i3 + 4 >> 2] = 0;
+  HEAP32[i3 + 8 >> 2] = 0;
+  HEAP32[i3 + 12 >> 2] = 0;
+  HEAP32[i3 + 16 >> 2] = 0;
+  HEAP32[i3 + 20 >> 2] = 0;
+  HEAP32[i3 + 24 >> 2] = 0;
+  HEAP32[i3 + 28 >> 2] = 0;
+  do {
+   i7 = i4 & 255;
+   i6 = i3 + (i7 >>> 5 << 2) | 0;
+   HEAP32[i6 >> 2] = HEAP32[i6 >> 2] | 1 << (i7 & 31);
+   i5 = i5 + 1 | 0;
+   i4 = HEAP8[i5] | 0;
+  } while (!(i4 << 24 >> 24 == 0));
+  i5 = HEAP8[i2] | 0;
+  L7 : do {
+   if (i5 << 24 >> 24 == 0) {
+    i4 = i2;
+   } else {
+    i4 = i2;
+    while (1) {
+     i7 = i5 & 255;
+     i6 = i4 + 1 | 0;
+     if ((HEAP32[i3 + (i7 >>> 5 << 2) >> 2] & 1 << (i7 & 31) | 0) != 0) {
+      break L7;
+     }
+     i5 = HEAP8[i6] | 0;
+     if (i5 << 24 >> 24 == 0) {
+      i4 = i6;
+      break;
+     } else {
+      i4 = i6;
+     }
+    }
+   }
+  } while (0);
+  i7 = i4 - i2 | 0;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ i7 = (___strchrnul(i2, i4 << 24 >> 24) | 0) - i2 | 0;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _main(i4, i5) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ i3 = _luaL_newstate() | 0;
+ if ((i3 | 0) == 0) {
+  i4 = HEAP32[i5 >> 2] | 0;
+  i3 = HEAP32[_stderr >> 2] | 0;
+  if ((i4 | 0) != 0) {
+   HEAP32[i2 >> 2] = i4;
+   _fprintf(i3 | 0, 496, i2 | 0) | 0;
+   _fflush(i3 | 0) | 0;
+  }
+  HEAP32[i2 >> 2] = 8;
+  _fprintf(i3 | 0, 912, i2 | 0) | 0;
+  _fflush(i3 | 0) | 0;
+  i8 = 1;
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ _lua_pushcclosure(i3, 141, 0);
+ _lua_pushinteger(i3, i4);
+ _lua_pushlightuserdata(i3, i5);
+ i6 = _lua_pcallk(i3, 2, 1, 0, 0, 0) | 0;
+ i7 = _lua_toboolean(i3, -1) | 0;
+ i6 = (i6 | 0) == 0;
+ if (!i6) {
+  if ((_lua_type(i3, -1) | 0) == 4) {
+   i8 = _lua_tolstring(i3, -1, 0) | 0;
+  } else {
+   i8 = 0;
+  }
+  i4 = HEAP32[20] | 0;
+  i5 = HEAP32[_stderr >> 2] | 0;
+  if ((i4 | 0) != 0) {
+   HEAP32[i2 >> 2] = i4;
+   _fprintf(i5 | 0, 496, i2 | 0) | 0;
+   _fflush(i5 | 0) | 0;
+  }
+  HEAP32[i2 >> 2] = (i8 | 0) == 0 ? 48 : i8;
+  _fprintf(i5 | 0, 912, i2 | 0) | 0;
+  _fflush(i5 | 0) | 0;
+  _lua_settop(i3, -2);
+ }
+ _lua_close(i3);
+ i8 = i6 & (i7 | 0) != 0 & 1 ^ 1;
+ STACKTOP = i1;
+ return i8 | 0;
+}
+function _db_sethook(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i4 = STACKTOP;
+ if ((_lua_type(i1, 1) | 0) == 8) {
+  i2 = _lua_tothread(i1, 1) | 0;
+  i5 = 1;
+ } else {
+  i2 = i1;
+  i5 = 0;
+ }
+ i3 = i5 + 1 | 0;
+ if ((_lua_type(i1, i3) | 0) < 1) {
+  _lua_settop(i1, i3);
+  i6 = 0;
+  i7 = 0;
+  i5 = 0;
+ } else {
+  i6 = _luaL_checklstring(i1, i5 | 2, 0) | 0;
+  _luaL_checktype(i1, i3, 6);
+  i5 = _luaL_optinteger(i1, i5 + 3 | 0, 0) | 0;
+  i7 = (_strchr(i6, 99) | 0) != 0 | 0;
+  i8 = (_strchr(i6, 114) | 0) == 0;
+  i7 = i8 ? i7 : i7 | 2;
+  i8 = (_strchr(i6, 108) | 0) == 0;
+  i8 = i8 ? i7 : i7 | 4;
+  i6 = i5;
+  i7 = 9;
+  i5 = (i5 | 0) > 0 ? i8 | 8 : i8;
+ }
+ if ((_luaL_getsubtable(i1, -1001e3, 11584) | 0) != 0) {
+  _lua_pushthread(i2) | 0;
+  _lua_xmove(i2, i1, 1);
+  _lua_pushvalue(i1, i3);
+  _lua_rawset(i1, -3);
+  _lua_sethook(i2, i7, i5, i6) | 0;
+  STACKTOP = i4;
+  return 0;
+ }
+ _lua_pushstring(i1, 11592) | 0;
+ _lua_setfield(i1, -2, 11600);
+ _lua_pushvalue(i1, -1);
+ _lua_setmetatable(i1, -2) | 0;
+ _lua_pushthread(i2) | 0;
+ _lua_xmove(i2, i1, 1);
+ _lua_pushvalue(i1, i3);
+ _lua_rawset(i1, -3);
+ _lua_sethook(i2, i7, i5, i6) | 0;
+ STACKTOP = i4;
+ return 0;
+}
+function _tconcat(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i6 = i3;
+ i2 = i3 + 16 | 0;
+ i5 = i3 + 8 | 0;
+ i4 = _luaL_optlstring(i1, 2, 8208, i5) | 0;
+ _luaL_checktype(i1, 1, 5);
+ i8 = _luaL_optinteger(i1, 3, 1) | 0;
+ if ((_lua_type(i1, 4) | 0) < 1) {
+  i7 = _luaL_len(i1, 1) | 0;
+ } else {
+  i7 = _luaL_checkinteger(i1, 4) | 0;
+ }
+ _luaL_buffinit(i1, i2);
+ if ((i8 | 0) >= (i7 | 0)) {
+  if ((i8 | 0) != (i7 | 0)) {
+   _luaL_pushresult(i2);
+   STACKTOP = i3;
+   return 1;
+  }
+ } else {
+  do {
+   _lua_rawgeti(i1, 1, i8);
+   if ((_lua_isstring(i1, -1) | 0) == 0) {
+    HEAP32[i6 >> 2] = _lua_typename(i1, _lua_type(i1, -1) | 0) | 0;
+    HEAP32[i6 + 4 >> 2] = i8;
+    _luaL_error(i1, 8360, i6) | 0;
+   }
+   _luaL_addvalue(i2);
+   _luaL_addlstring(i2, i4, HEAP32[i5 >> 2] | 0);
+   i8 = i8 + 1 | 0;
+  } while ((i8 | 0) != (i7 | 0));
+ }
+ _lua_rawgeti(i1, 1, i7);
+ if ((_lua_isstring(i1, -1) | 0) == 0) {
+  HEAP32[i6 >> 2] = _lua_typename(i1, _lua_type(i1, -1) | 0) | 0;
+  HEAP32[i6 + 4 >> 2] = i7;
+  _luaL_error(i1, 8360, i6) | 0;
+ }
+ _luaL_addvalue(i2);
+ _luaL_pushresult(i2);
+ STACKTOP = i3;
+ return 1;
+}
+function _searcher_Croot(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i4 = _luaL_checklstring(i1, 1, 0) | 0;
+ i5 = _strchr(i4, 46) | 0;
+ if ((i5 | 0) == 0) {
+  i6 = 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ _lua_pushlstring(i1, i4, i5 - i4 | 0) | 0;
+ i5 = _lua_tolstring(i1, -1, 0) | 0;
+ _lua_getfield(i1, -1001001, 4440);
+ i6 = _lua_tolstring(i1, -1, 0) | 0;
+ if ((i6 | 0) == 0) {
+  HEAP32[i3 >> 2] = 4440;
+  _luaL_error(i1, 5032, i3) | 0;
+ }
+ i5 = _searchpath(i1, i5, i6, 4936, 4848) | 0;
+ if ((i5 | 0) == 0) {
+  i6 = 1;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ i6 = _loadfunc(i1, i5, i4) | 0;
+ if ((i6 | 0) == 2) {
+  HEAP32[i3 >> 2] = i4;
+  HEAP32[i3 + 4 >> 2] = i5;
+  _lua_pushfstring(i1, 4856, i3) | 0;
+  i6 = 1;
+  STACKTOP = i2;
+  return i6 | 0;
+ } else if ((i6 | 0) == 0) {
+  _lua_pushstring(i1, i5) | 0;
+  i6 = 2;
+  STACKTOP = i2;
+  return i6 | 0;
+ } else {
+  i4 = _lua_tolstring(i1, 1, 0) | 0;
+  i6 = _lua_tolstring(i1, -1, 0) | 0;
+  HEAP32[i3 >> 2] = i4;
+  HEAP32[i3 + 4 >> 2] = i5;
+  HEAP32[i3 + 8 >> 2] = i6;
+  i6 = _luaL_error(i1, 4888, i3) | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ return 0;
+}
+function _lua_tonumberx(i5, i7, i1) {
+ i5 = i5 | 0;
+ i7 = i7 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, d8 = 0.0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i6 = HEAP32[i5 + 16 >> 2] | 0;
+ do {
+  if ((i7 | 0) <= 0) {
+   if (!((i7 | 0) < -1000999)) {
+    i4 = (HEAP32[i5 + 8 >> 2] | 0) + (i7 << 4) | 0;
+    break;
+   }
+   if ((i7 | 0) == -1001e3) {
+    i4 = (HEAP32[i5 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i7 | 0;
+   i6 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i6 >> 2] | 0, (i5 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i4 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i6 >> 2] | 0) + (i7 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i5 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ if ((HEAP32[i4 + 8 >> 2] | 0) != 3) {
+  i4 = _luaV_tonumber(i4, i3) | 0;
+  if ((i4 | 0) == 0) {
+   if ((i1 | 0) == 0) {
+    d8 = 0.0;
+    STACKTOP = i2;
+    return +d8;
+   }
+   HEAP32[i1 >> 2] = 0;
+   d8 = 0.0;
+   STACKTOP = i2;
+   return +d8;
+  }
+ }
+ if ((i1 | 0) != 0) {
+  HEAP32[i1 >> 2] = 1;
+ }
+ d8 = +HEAPF64[i4 >> 3];
+ STACKTOP = i2;
+ return +d8;
+}
+function _luaopen_package(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_getsubtable(i1, -1001e3, 4184) | 0;
+ _lua_createtable(i1, 0, 1);
+ _lua_pushcclosure(i1, 158, 0);
+ _lua_setfield(i1, -2, 4192);
+ _lua_setmetatable(i1, -2) | 0;
+ _lua_createtable(i1, 0, 3);
+ _luaL_setfuncs(i1, 4200, 0);
+ _lua_createtable(i1, 4, 0);
+ _lua_pushvalue(i1, -2);
+ _lua_pushcclosure(i1, 159, 1);
+ _lua_rawseti(i1, -2, 1);
+ _lua_pushvalue(i1, -2);
+ _lua_pushcclosure(i1, 160, 1);
+ _lua_rawseti(i1, -2, 2);
+ _lua_pushvalue(i1, -2);
+ _lua_pushcclosure(i1, 161, 1);
+ _lua_rawseti(i1, -2, 3);
+ _lua_pushvalue(i1, -2);
+ _lua_pushcclosure(i1, 162, 1);
+ _lua_rawseti(i1, -2, 4);
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, -3, 4232);
+ _lua_setfield(i1, -2, 4240);
+ _setpath(i1, 4256, 4264, 4280, 4296);
+ _setpath(i1, 4440, 4448, 4464, 4480);
+ _lua_pushlstring(i1, 4552, 10) | 0;
+ _lua_setfield(i1, -2, 4568);
+ _luaL_getsubtable(i1, -1001e3, 4576) | 0;
+ _lua_setfield(i1, -2, 4584);
+ _luaL_getsubtable(i1, -1001e3, 4592) | 0;
+ _lua_setfield(i1, -2, 4608);
+ _lua_rawgeti(i1, -1001e3, 2);
+ _lua_pushvalue(i1, -2);
+ _luaL_setfuncs(i1, 4616, 1);
+ _lua_settop(i1, -2);
+ STACKTOP = i2;
+ return 1;
+}
+function _lua_rawlen(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i3 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i2 = (HEAP32[i3 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i2 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i3 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i2 = HEAP32[i4 >> 2] | 0, (i3 | 0) <= (HEAPU8[i2 + 6 | 0] | 0 | 0)) : 0) {
+    i2 = i2 + (i3 + -1 << 4) + 16 | 0;
+   } else {
+    i2 = 5192;
+   }
+  } else {
+   i2 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i2 = i2 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i2 : 5192;
+  }
+ } while (0);
+ i3 = HEAP32[i2 + 8 >> 2] & 15;
+ if ((i3 | 0) == 5) {
+  i5 = _luaH_getn(HEAP32[i2 >> 2] | 0) | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ } else if ((i3 | 0) == 4) {
+  i5 = HEAP32[(HEAP32[i2 >> 2] | 0) + 12 >> 2] | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ } else if ((i3 | 0) == 7) {
+  i5 = HEAP32[(HEAP32[i2 >> 2] | 0) + 16 >> 2] | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ } else {
+  i5 = 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _searchpath(i3, i5, i6, i7, i8) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ i7 = i7 | 0;
+ i8 = i8 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i4 = i2;
+ i1 = i2 + 8 | 0;
+ _luaL_buffinit(i3, i1);
+ if ((HEAP8[i7] | 0) != 0) {
+  i5 = _luaL_gsub(i3, i5, i7, i8) | 0;
+ }
+ while (1) {
+  i7 = HEAP8[i6] | 0;
+  if (i7 << 24 >> 24 == 59) {
+   i6 = i6 + 1 | 0;
+   continue;
+  } else if (i7 << 24 >> 24 == 0) {
+   i3 = 12;
+   break;
+  }
+  i8 = _strchr(i6, 59) | 0;
+  if ((i8 | 0) == 0) {
+   i8 = i6 + (_strlen(i6 | 0) | 0) | 0;
+  }
+  _lua_pushlstring(i3, i6, i8 - i6 | 0) | 0;
+  if ((i8 | 0) == 0) {
+   i3 = 12;
+   break;
+  }
+  i6 = _luaL_gsub(i3, _lua_tolstring(i3, -1, 0) | 0, 5064, i5) | 0;
+  _lua_remove(i3, -2);
+  i7 = _fopen(i6 | 0, 5088) | 0;
+  if ((i7 | 0) != 0) {
+   i3 = 10;
+   break;
+  }
+  HEAP32[i4 >> 2] = i6;
+  _lua_pushfstring(i3, 5072, i4) | 0;
+  _lua_remove(i3, -2);
+  _luaL_addvalue(i1);
+  i6 = i8;
+ }
+ if ((i3 | 0) == 10) {
+  _fclose(i7 | 0) | 0;
+  i8 = i6;
+  STACKTOP = i2;
+  return i8 | 0;
+ } else if ((i3 | 0) == 12) {
+  _luaL_pushresult(i1);
+  i8 = 0;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ return 0;
+}
+function _io_readline(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i4 = _lua_touserdata(i1, -1001001) | 0;
+ i5 = _lua_tointegerx(i1, -1001002, 0) | 0;
+ if ((HEAP32[i4 + 4 >> 2] | 0) == 0) {
+  i6 = _luaL_error(i1, 3344, i3) | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ _lua_settop(i1, 1);
+ if ((i5 | 0) >= 1) {
+  i6 = 1;
+  while (1) {
+   _lua_pushvalue(i1, -1001003 - i6 | 0);
+   if ((i6 | 0) == (i5 | 0)) {
+    break;
+   } else {
+    i6 = i6 + 1 | 0;
+   }
+  }
+ }
+ i4 = _g_read(i1, HEAP32[i4 >> 2] | 0, 2) | 0;
+ if ((_lua_type(i1, 0 - i4 | 0) | 0) != 0) {
+  i6 = i4;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ if ((i4 | 0) > 1) {
+  HEAP32[i3 >> 2] = _lua_tolstring(i1, 1 - i4 | 0, 0) | 0;
+  i6 = _luaL_error(i1, 3368, i3) | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ if ((_lua_toboolean(i1, -1001003) | 0) == 0) {
+  i6 = 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ _lua_settop(i1, 0);
+ _lua_pushvalue(i1, -1001001);
+ i5 = (_luaL_checkudata(i1, 1, 2832) | 0) + 4 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = 0;
+ FUNCTION_TABLE_ii[i6 & 255](i1) | 0;
+ i6 = 0;
+ STACKTOP = i2;
+ return i6 | 0;
+}
+function _luaK_setreturns(i3, i5, i6) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i5 >> 2] | 0;
+ if ((i4 | 0) == 13) {
+  i7 = i5 + 8 | 0;
+  i8 = HEAP32[i3 >> 2] | 0;
+  i4 = HEAP32[i8 + 12 >> 2] | 0;
+  i5 = i4 + (HEAP32[i7 >> 2] << 2) | 0;
+  HEAP32[i5 >> 2] = HEAP32[i5 >> 2] & 8388607 | (i6 << 23) + 8388608;
+  i7 = i4 + (HEAP32[i7 >> 2] << 2) | 0;
+  i4 = i3 + 48 | 0;
+  HEAP32[i7 >> 2] = (HEAPU8[i4] | 0) << 6 | HEAP32[i7 >> 2] & -16321;
+  i7 = HEAP8[i4] | 0;
+  i5 = (i7 & 255) + 1 | 0;
+  i6 = i8 + 78 | 0;
+  do {
+   if (i5 >>> 0 > (HEAPU8[i6] | 0) >>> 0) {
+    if (i5 >>> 0 > 249) {
+     _luaX_syntaxerror(HEAP32[i3 + 12 >> 2] | 0, 10536);
+    } else {
+     HEAP8[i6] = i5;
+     i1 = HEAP8[i4] | 0;
+     break;
+    }
+   } else {
+    i1 = i7;
+   }
+  } while (0);
+  HEAP8[i4] = (i1 & 255) + 1;
+  STACKTOP = i2;
+  return;
+ } else if ((i4 | 0) == 12) {
+  i8 = (HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i5 + 8 >> 2] << 2) | 0;
+  HEAP32[i8 >> 2] = HEAP32[i8 >> 2] & -8372225 | (i6 << 14) + 16384 & 8372224;
+  STACKTOP = i2;
+  return;
+ } else {
+  STACKTOP = i2;
+  return;
+ }
+}
+function _luaZ_read(i2, i9, i8) {
+ i2 = i2 | 0;
+ i9 = i9 | 0;
+ i8 = i8 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i10 = 0, i11 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ if ((i8 | 0) == 0) {
+  i11 = 0;
+  STACKTOP = i1;
+  return i11 | 0;
+ }
+ i7 = i2 + 16 | 0;
+ i6 = i2 + 8 | 0;
+ i4 = i2 + 12 | 0;
+ i5 = i2 + 4 | 0;
+ i11 = HEAP32[i2 >> 2] | 0;
+ while (1) {
+  if ((i11 | 0) == 0) {
+   i10 = FUNCTION_TABLE_iiii[HEAP32[i6 >> 2] & 3](HEAP32[i7 >> 2] | 0, HEAP32[i4 >> 2] | 0, i3) | 0;
+   if ((i10 | 0) == 0) {
+    i2 = 9;
+    break;
+   }
+   i11 = HEAP32[i3 >> 2] | 0;
+   if ((i11 | 0) == 0) {
+    i2 = 9;
+    break;
+   }
+   HEAP32[i2 >> 2] = i11;
+   HEAP32[i5 >> 2] = i10;
+  } else {
+   i10 = HEAP32[i5 >> 2] | 0;
+  }
+  i11 = i8 >>> 0 > i11 >>> 0 ? i11 : i8;
+  _memcpy(i9 | 0, i10 | 0, i11 | 0) | 0;
+  i10 = (HEAP32[i2 >> 2] | 0) - i11 | 0;
+  HEAP32[i2 >> 2] = i10;
+  HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + i11;
+  if ((i8 | 0) == (i11 | 0)) {
+   i8 = 0;
+   i2 = 9;
+   break;
+  } else {
+   i8 = i8 - i11 | 0;
+   i9 = i9 + i11 | 0;
+   i11 = i10;
+  }
+ }
+ if ((i2 | 0) == 9) {
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ return 0;
+}
+function _lua_load(i1, i5, i4, i3, i6) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i7 = i2;
+ _luaZ_init(i1, i7, i5, i4);
+ i3 = _luaD_protectedparser(i1, i7, (i3 | 0) == 0 ? 928 : i3, i6) | 0;
+ if ((i3 | 0) != 0) {
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ i4 = HEAP32[(HEAP32[i1 + 8 >> 2] | 0) + -16 >> 2] | 0;
+ if ((HEAP8[i4 + 6 | 0] | 0) != 1) {
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ i5 = _luaH_getint(HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 40 >> 2] | 0, 2) | 0;
+ i4 = i4 + 16 | 0;
+ i6 = HEAP32[(HEAP32[i4 >> 2] | 0) + 8 >> 2] | 0;
+ i9 = i5;
+ i8 = HEAP32[i9 + 4 >> 2] | 0;
+ i7 = i6;
+ HEAP32[i7 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i7 + 4 >> 2] = i8;
+ i7 = i5 + 8 | 0;
+ HEAP32[i6 + 8 >> 2] = HEAP32[i7 >> 2];
+ if ((HEAP32[i7 >> 2] & 64 | 0) == 0) {
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ i5 = HEAP32[i5 >> 2] | 0;
+ if ((HEAP8[i5 + 5 | 0] & 3) == 0) {
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ i4 = HEAP32[i4 >> 2] | 0;
+ if ((HEAP8[i4 + 5 | 0] & 4) == 0) {
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ _luaC_barrier_(i1, i4, i5);
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _g_write(i1, i4, i8) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i8 = i8 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i9 = 0, d10 = 0.0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i5;
+ i3 = i5 + 8 | 0;
+ i7 = _lua_gettop(i1) | 0;
+ if ((i7 | 0) == (i8 | 0)) {
+  i9 = 1;
+  STACKTOP = i5;
+  return i9 | 0;
+ }
+ i6 = i8;
+ i7 = i7 - i8 | 0;
+ i9 = 1;
+ while (1) {
+  i7 = i7 + -1 | 0;
+  if ((_lua_type(i1, i6) | 0) == 3) {
+   if ((i9 | 0) == 0) {
+    i8 = 0;
+   } else {
+    d10 = +_lua_tonumberx(i1, i6, 0);
+    HEAPF64[tempDoublePtr >> 3] = d10;
+    HEAP32[i2 >> 2] = HEAP32[tempDoublePtr >> 2];
+    HEAP32[i2 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+    i8 = (_fprintf(i4 | 0, 3072, i2 | 0) | 0) > 0;
+   }
+  } else {
+   i8 = _luaL_checklstring(i1, i6, i3) | 0;
+   if ((i9 | 0) == 0) {
+    i8 = 0;
+   } else {
+    i8 = _fwrite(i8 | 0, 1, HEAP32[i3 >> 2] | 0, i4 | 0) | 0;
+    i8 = (i8 | 0) == (HEAP32[i3 >> 2] | 0);
+   }
+  }
+  if ((i7 | 0) == 0) {
+   break;
+  } else {
+   i6 = i6 + 1 | 0;
+   i9 = i8 & 1;
+  }
+ }
+ if (i8) {
+  i9 = 1;
+  STACKTOP = i5;
+  return i9 | 0;
+ }
+ i9 = _luaL_fileresult(i1, 0, 0) | 0;
+ STACKTOP = i5;
+ return i9 | 0;
+}
+function _lua_getuservalue(i2, i5) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i2 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i3 = HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0;
+ i2 = i2 + 8 | 0;
+ i4 = HEAP32[i2 >> 2] | 0;
+ if ((i3 | 0) == 0) {
+  HEAP32[i4 + 8 >> 2] = 0;
+  i5 = i4;
+  i5 = i5 + 16 | 0;
+  HEAP32[i2 >> 2] = i5;
+  STACKTOP = i1;
+  return;
+ } else {
+  HEAP32[i4 >> 2] = i3;
+  HEAP32[i4 + 8 >> 2] = 69;
+  i5 = HEAP32[i2 >> 2] | 0;
+  i5 = i5 + 16 | 0;
+  HEAP32[i2 >> 2] = i5;
+  STACKTOP = i1;
+  return;
+ }
+}
+function _luaL_addlstring(i7, i6, i1) {
+ i7 = i7 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i8 = 0, i9 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = HEAP32[i7 + 12 >> 2] | 0;
+ i3 = i7 + 4 | 0;
+ i9 = HEAP32[i3 >> 2] | 0;
+ i2 = i7 + 8 | 0;
+ i8 = HEAP32[i2 >> 2] | 0;
+ if (!((i9 - i8 | 0) >>> 0 < i1 >>> 0)) {
+  i7 = HEAP32[i7 >> 2] | 0;
+  i9 = i8;
+  i9 = i7 + i9 | 0;
+  _memcpy(i9 | 0, i6 | 0, i1 | 0) | 0;
+  i9 = HEAP32[i2 >> 2] | 0;
+  i9 = i9 + i1 | 0;
+  HEAP32[i2 >> 2] = i9;
+  STACKTOP = i5;
+  return;
+ }
+ i9 = i9 << 1;
+ i9 = (i9 - i8 | 0) >>> 0 < i1 >>> 0 ? i8 + i1 | 0 : i9;
+ if (i9 >>> 0 < i8 >>> 0 | (i9 - i8 | 0) >>> 0 < i1 >>> 0) {
+  _luaL_error(i4, 1272, i5) | 0;
+ }
+ i8 = _lua_newuserdata(i4, i9) | 0;
+ _memcpy(i8 | 0, HEAP32[i7 >> 2] | 0, HEAP32[i2 >> 2] | 0) | 0;
+ if ((HEAP32[i7 >> 2] | 0) != (i7 + 16 | 0)) {
+  _lua_remove(i4, -2);
+ }
+ HEAP32[i7 >> 2] = i8;
+ HEAP32[i3 >> 2] = i9;
+ i9 = HEAP32[i2 >> 2] | 0;
+ i9 = i8 + i9 | 0;
+ _memcpy(i9 | 0, i6 | 0, i1 | 0) | 0;
+ i9 = HEAP32[i2 >> 2] | 0;
+ i9 = i9 + i1 | 0;
+ HEAP32[i2 >> 2] = i9;
+ STACKTOP = i5;
+ return;
+}
+function _lua_rawgeti(i3, i6, i1) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i7 = 0;
+ i2 = STACKTOP;
+ i5 = HEAP32[i3 + 16 >> 2] | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i4 = (HEAP32[i3 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i4 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i6 = -1001e3 - i6 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i5 >> 2] | 0, (i6 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i4 + (i6 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i5 >> 2] | 0) + (i6 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i4 = _luaH_getint(HEAP32[i4 >> 2] | 0, i1) | 0;
+ i6 = i3 + 8 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ i7 = i4;
+ i1 = HEAP32[i7 + 4 >> 2] | 0;
+ i3 = i5;
+ HEAP32[i3 >> 2] = HEAP32[i7 >> 2];
+ HEAP32[i3 + 4 >> 2] = i1;
+ HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+ HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 16;
+ STACKTOP = i2;
+ return;
+}
+function _lua_setfield(i1, i6, i3) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i5 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i4 = (HEAP32[i1 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i4 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i6 = -1001e3 - i6 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i5 >> 2] | 0, (i6 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i4 + (i6 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i5 >> 2] | 0) + (i6 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i6 = i1 + 8 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i6 >> 2] = i5 + 16;
+ i3 = _luaS_new(i1, i3) | 0;
+ HEAP32[i5 >> 2] = i3;
+ HEAP32[i5 + 8 >> 2] = HEAPU8[i3 + 4 | 0] | 0 | 64;
+ i5 = HEAP32[i6 >> 2] | 0;
+ _luaV_settable(i1, i4, i5 + -16 | 0, i5 + -32 | 0);
+ HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + -32;
+ STACKTOP = i2;
+ return;
+}
+function _luaopen_io(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 11);
+ _luaL_setfuncs(i1, 2680, 0);
+ _luaL_newmetatable(i1, 2832) | 0;
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, -2, 2872);
+ _luaL_setfuncs(i1, 2880, 0);
+ _lua_settop(i1, -2);
+ i5 = HEAP32[_stdin >> 2] | 0;
+ i4 = _lua_newuserdata(i1, 8) | 0;
+ i3 = i4 + 4 | 0;
+ HEAP32[i3 >> 2] = 0;
+ _luaL_setmetatable(i1, 2832);
+ HEAP32[i4 >> 2] = i5;
+ HEAP32[i3 >> 2] = 154;
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, -1001e3, 2776);
+ _lua_setfield(i1, -2, 2792);
+ i3 = HEAP32[_stdout >> 2] | 0;
+ i4 = _lua_newuserdata(i1, 8) | 0;
+ i5 = i4 + 4 | 0;
+ HEAP32[i5 >> 2] = 0;
+ _luaL_setmetatable(i1, 2832);
+ HEAP32[i4 >> 2] = i3;
+ HEAP32[i5 >> 2] = 154;
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, -1001e3, 2800);
+ _lua_setfield(i1, -2, 2816);
+ i5 = HEAP32[_stderr >> 2] | 0;
+ i4 = _lua_newuserdata(i1, 8) | 0;
+ i3 = i4 + 4 | 0;
+ HEAP32[i3 >> 2] = 0;
+ _luaL_setmetatable(i1, 2832);
+ HEAP32[i4 >> 2] = i5;
+ HEAP32[i3 >> 2] = 154;
+ _lua_setfield(i1, -2, 2824);
+ STACKTOP = i2;
+ return 1;
+}
+function _lua_pushcclosure(i1, i4, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ if ((i5 | 0) == 0) {
+  i6 = HEAP32[i1 + 8 >> 2] | 0;
+  HEAP32[i6 >> 2] = i4;
+  HEAP32[i6 + 8 >> 2] = 22;
+  i6 = i1 + 8 | 0;
+  i5 = HEAP32[i6 >> 2] | 0;
+  i5 = i5 + 16 | 0;
+  HEAP32[i6 >> 2] = i5;
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i1);
+ }
+ i3 = _luaF_newCclosure(i1, i5) | 0;
+ HEAP32[i3 + 12 >> 2] = i4;
+ i4 = i1 + 8 | 0;
+ i6 = (HEAP32[i4 >> 2] | 0) + (0 - i5 << 4) | 0;
+ HEAP32[i4 >> 2] = i6;
+ do {
+  i5 = i5 + -1 | 0;
+  i9 = i6 + (i5 << 4) | 0;
+  i8 = HEAP32[i9 + 4 >> 2] | 0;
+  i7 = i3 + (i5 << 4) + 16 | 0;
+  HEAP32[i7 >> 2] = HEAP32[i9 >> 2];
+  HEAP32[i7 + 4 >> 2] = i8;
+  HEAP32[i3 + (i5 << 4) + 24 >> 2] = HEAP32[i6 + (i5 << 4) + 8 >> 2];
+  i6 = HEAP32[i4 >> 2] | 0;
+ } while ((i5 | 0) != 0);
+ HEAP32[i6 >> 2] = i3;
+ HEAP32[i6 + 8 >> 2] = 102;
+ i9 = i1 + 8 | 0;
+ i8 = HEAP32[i9 >> 2] | 0;
+ i8 = i8 + 16 | 0;
+ HEAP32[i9 >> 2] = i8;
+ STACKTOP = i2;
+ return;
+}
+function _luaF_findupval(i3, i4) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i2 = HEAP32[i3 + 12 >> 2] | 0;
+ i6 = i3 + 56 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ L1 : do {
+  if ((i5 | 0) == 0) {
+   i5 = i6;
+  } else {
+   while (1) {
+    i7 = HEAP32[i5 + 8 >> 2] | 0;
+    if (i7 >>> 0 < i4 >>> 0) {
+     i5 = i6;
+     break L1;
+    }
+    if ((i7 | 0) == (i4 | 0)) {
+     break;
+    }
+    i6 = HEAP32[i5 >> 2] | 0;
+    if ((i6 | 0) == 0) {
+     break L1;
+    } else {
+     i7 = i5;
+     i5 = i6;
+     i6 = i7;
+    }
+   }
+   i4 = i5 + 5 | 0;
+   i3 = (HEAPU8[i4] | 0) ^ 3;
+   if ((((HEAPU8[i2 + 60 | 0] | 0) ^ 3) & i3 | 0) != 0) {
+    i7 = i5;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+   HEAP8[i4] = i3;
+   i7 = i5;
+   STACKTOP = i1;
+   return i7 | 0;
+  }
+ } while (0);
+ i7 = _luaC_newobj(i3, 10, 32, i5, 0) | 0;
+ HEAP32[i7 + 8 >> 2] = i4;
+ i4 = i7 + 16 | 0;
+ HEAP32[i4 >> 2] = i2 + 112;
+ i6 = i2 + 132 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i4 + 4 >> 2] = i5;
+ HEAP32[i5 + 16 >> 2] = i7;
+ HEAP32[i6 >> 2] = i7;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _luaC_checkfinalizer(i5, i4, i6) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i7 = 0, i8 = 0;
+ i3 = STACKTOP;
+ i1 = HEAP32[i5 + 12 >> 2] | 0;
+ i2 = i4 + 5 | 0;
+ if ((HEAP8[i2] & 24) != 0 | (i6 | 0) == 0) {
+  STACKTOP = i3;
+  return;
+ }
+ if (!((HEAP8[i6 + 6 | 0] & 4) == 0)) {
+  STACKTOP = i3;
+  return;
+ }
+ if ((_luaT_gettm(i6, 2, HEAP32[i1 + 192 >> 2] | 0) | 0) == 0) {
+  STACKTOP = i3;
+  return;
+ }
+ i7 = i1 + 76 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ if ((i8 | 0) == (i4 | 0)) {
+  do {
+   i6 = _sweeplist(i5, i8, 1) | 0;
+  } while ((i6 | 0) == (i8 | 0));
+  HEAP32[i7 >> 2] = i6;
+ }
+ i5 = i1 + 68 | 0;
+ while (1) {
+  i6 = HEAP32[i5 >> 2] | 0;
+  if ((i6 | 0) == (i4 | 0)) {
+   break;
+  } else {
+   i5 = i6;
+  }
+ }
+ HEAP32[i5 >> 2] = HEAP32[i4 >> 2];
+ i8 = i1 + 72 | 0;
+ HEAP32[i4 >> 2] = HEAP32[i8 >> 2];
+ HEAP32[i8 >> 2] = i4;
+ i4 = HEAPU8[i2] | 0 | 16;
+ HEAP8[i2] = i4;
+ if ((HEAPU8[i1 + 61 | 0] | 0) < 2) {
+  HEAP8[i2] = i4 & 191;
+  STACKTOP = i3;
+  return;
+ } else {
+  HEAP8[i2] = HEAP8[i1 + 60 | 0] & 3 | i4 & 184;
+  STACKTOP = i3;
+  return;
+ }
+}
+function _io_lines(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ if ((_lua_type(i1, 1) | 0) == -1) {
+  _lua_pushnil(i1);
+ }
+ if ((_lua_type(i1, 1) | 0) == 0) {
+  _lua_getfield(i1, -1001e3, 2776);
+  _lua_replace(i1, 1);
+  if ((HEAP32[(_luaL_checkudata(i1, 1, 2832) | 0) + 4 >> 2] | 0) != 0) {
+   i4 = 0;
+   _aux_lines(i1, i4);
+   STACKTOP = i2;
+   return 1;
+  }
+  _luaL_error(i1, 3080, i3) | 0;
+  i4 = 0;
+  _aux_lines(i1, i4);
+  STACKTOP = i2;
+  return 1;
+ } else {
+  i4 = _luaL_checklstring(i1, 1, 0) | 0;
+  i6 = _lua_newuserdata(i1, 8) | 0;
+  i5 = i6 + 4 | 0;
+  HEAP32[i5 >> 2] = 0;
+  _luaL_setmetatable(i1, 2832);
+  HEAP32[i6 >> 2] = 0;
+  HEAP32[i5 >> 2] = 156;
+  i5 = _fopen(i4 | 0, 3480) | 0;
+  HEAP32[i6 >> 2] = i5;
+  if ((i5 | 0) == 0) {
+   i6 = _strerror(HEAP32[(___errno_location() | 0) >> 2] | 0) | 0;
+   HEAP32[i3 >> 2] = i4;
+   HEAP32[i3 + 4 >> 2] = i6;
+   _luaL_error(i1, 3520, i3) | 0;
+  }
+  _lua_replace(i1, 1);
+  i6 = 1;
+  _aux_lines(i1, i6);
+  STACKTOP = i2;
+  return 1;
+ }
+ return 0;
+}
+function _luaC_changemode(i2, i6) {
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i1 = STACKTOP;
+ i3 = i2 + 12 | 0;
+ i5 = HEAP32[i3 >> 2] | 0;
+ i4 = i5 + 62 | 0;
+ if ((HEAPU8[i4] | 0) == (i6 | 0)) {
+  STACKTOP = i1;
+  return;
+ }
+ if ((i6 | 0) == 2) {
+  i3 = i5 + 61 | 0;
+  if ((HEAP8[i3] | 0) != 0) {
+   do {
+    _singlestep(i2) | 0;
+   } while ((HEAP8[i3] | 0) != 0);
+  }
+  HEAP32[i5 + 20 >> 2] = (HEAP32[i5 + 12 >> 2] | 0) + (HEAP32[i5 + 8 >> 2] | 0);
+  HEAP8[i4] = 2;
+  STACKTOP = i1;
+  return;
+ }
+ HEAP8[i4] = 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ HEAP8[i4 + 61 | 0] = 2;
+ HEAP32[i4 + 64 >> 2] = 0;
+ i5 = i4 + 72 | 0;
+ do {
+  i6 = _sweeplist(i2, i5, 1) | 0;
+ } while ((i6 | 0) == (i5 | 0));
+ HEAP32[i4 + 80 >> 2] = i6;
+ i5 = i4 + 68 | 0;
+ do {
+  i6 = _sweeplist(i2, i5, 1) | 0;
+ } while ((i6 | 0) == (i5 | 0));
+ HEAP32[i4 + 76 >> 2] = i6;
+ i3 = (HEAP32[i3 >> 2] | 0) + 61 | 0;
+ if ((1 << HEAPU8[i3] & -29 | 0) != 0) {
+  STACKTOP = i1;
+  return;
+ }
+ do {
+  _singlestep(i2) | 0;
+ } while ((1 << HEAPU8[i3] & -29 | 0) == 0);
+ STACKTOP = i1;
+ return;
+}
+function _lua_rawget(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i5 = i1 + 8 | 0;
+ i4 = _luaH_get(HEAP32[i3 >> 2] | 0, (HEAP32[i5 >> 2] | 0) + -16 | 0) | 0;
+ i5 = HEAP32[i5 >> 2] | 0;
+ i6 = i4;
+ i1 = HEAP32[i6 + 4 >> 2] | 0;
+ i3 = i5 + -16 | 0;
+ HEAP32[i3 >> 2] = HEAP32[i6 >> 2];
+ HEAP32[i3 + 4 >> 2] = i1;
+ HEAP32[i5 + -8 >> 2] = HEAP32[i4 + 8 >> 2];
+ STACKTOP = i2;
+ return;
+}
+function _lua_isstring(i2, i4) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i3 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i4 | 0) <= 0) {
+   if (!((i4 | 0) < -1000999)) {
+    i2 = (HEAP32[i2 + 8 >> 2] | 0) + (i4 << 4) | 0;
+    break;
+   }
+   if ((i4 | 0) == -1001e3) {
+    i2 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i2 = -1001e3 - i4 | 0;
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((HEAP32[i3 + 8 >> 2] | 0) == 22) {
+    i4 = 0;
+    i4 = i4 & 1;
+    STACKTOP = i1;
+    return i4 | 0;
+   }
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((i2 | 0) > (HEAPU8[i3 + 6 | 0] | 0 | 0)) {
+    i4 = 0;
+    i4 = i4 & 1;
+    STACKTOP = i1;
+    return i4 | 0;
+   } else {
+    i2 = i3 + (i2 + -1 << 4) + 16 | 0;
+    break;
+   }
+  } else {
+   i3 = (HEAP32[i3 >> 2] | 0) + (i4 << 4) | 0;
+   i2 = i3 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ if ((i2 | 0) == 5192) {
+  i4 = 0;
+  i4 = i4 & 1;
+  STACKTOP = i1;
+  return i4 | 0;
+ }
+ i4 = ((HEAP32[i2 + 8 >> 2] & 15) + -3 | 0) >>> 0 < 2;
+ i4 = i4 & 1;
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _setnodevector(i5, i1, i3) {
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ if ((i3 | 0) == 0) {
+  HEAP32[i1 + 16 >> 2] = 8016;
+  i6 = 0;
+  i7 = 8016;
+  i4 = 0;
+  i5 = i1 + 7 | 0;
+  HEAP8[i5] = i4;
+  i6 = i7 + (i6 << 5) | 0;
+  i7 = i1 + 20 | 0;
+  HEAP32[i7 >> 2] = i6;
+  STACKTOP = i2;
+  return;
+ }
+ i4 = _luaO_ceillog2(i3) | 0;
+ if ((i4 | 0) > 30) {
+  _luaG_runerror(i5, 8048, i2);
+ }
+ i3 = 1 << i4;
+ if ((i3 + 1 | 0) >>> 0 > 134217727) {
+  _luaM_toobig(i5);
+ }
+ i6 = _luaM_realloc_(i5, 0, 0, i3 << 5) | 0;
+ i5 = i1 + 16 | 0;
+ HEAP32[i5 >> 2] = i6;
+ if ((i3 | 0) > 0) {
+  i7 = 0;
+  do {
+   HEAP32[i6 + (i7 << 5) + 28 >> 2] = 0;
+   HEAP32[i6 + (i7 << 5) + 24 >> 2] = 0;
+   HEAP32[i6 + (i7 << 5) + 8 >> 2] = 0;
+   i7 = i7 + 1 | 0;
+   i6 = HEAP32[i5 >> 2] | 0;
+  } while ((i7 | 0) != (i3 | 0));
+ }
+ i7 = i3;
+ i4 = i4 & 255;
+ i5 = i1 + 7 | 0;
+ HEAP8[i5] = i4;
+ i6 = i6 + (i7 << 5) | 0;
+ i7 = i1 + 20 | 0;
+ HEAP32[i7 >> 2] = i6;
+ STACKTOP = i2;
+ return;
+}
+function _lua_pushvalue(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i5 = i1 + 8 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ i7 = i3;
+ i6 = HEAP32[i7 + 4 >> 2] | 0;
+ i1 = i4;
+ HEAP32[i1 >> 2] = HEAP32[i7 >> 2];
+ HEAP32[i1 + 4 >> 2] = i6;
+ HEAP32[i4 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 16;
+ STACKTOP = i2;
+ return;
+}
+function _luaL_setfuncs(i3, i6, i1) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ _luaL_checkversion_(i3, 502.0);
+ if ((_lua_checkstack(i3, i1 + 20 | 0) | 0) == 0) {
+  HEAP32[i4 >> 2] = 1472;
+  _luaL_error(i3, 1216, i4) | 0;
+ }
+ if ((HEAP32[i6 >> 2] | 0) == 0) {
+  i7 = ~i1;
+  _lua_settop(i3, i7);
+  STACKTOP = i2;
+  return;
+ }
+ i4 = -2 - i1 | 0;
+ i5 = 0 - i1 | 0;
+ if ((i1 | 0) <= 0) {
+  do {
+   _lua_pushcclosure(i3, HEAP32[i6 + 4 >> 2] | 0, i1);
+   _lua_setfield(i3, i4, HEAP32[i6 >> 2] | 0);
+   i6 = i6 + 8 | 0;
+  } while ((HEAP32[i6 >> 2] | 0) != 0);
+  i7 = ~i1;
+  _lua_settop(i3, i7);
+  STACKTOP = i2;
+  return;
+ }
+ do {
+  i7 = 0;
+  do {
+   _lua_pushvalue(i3, i5);
+   i7 = i7 + 1 | 0;
+  } while ((i7 | 0) != (i1 | 0));
+  _lua_pushcclosure(i3, HEAP32[i6 + 4 >> 2] | 0, i1);
+  _lua_setfield(i3, i4, HEAP32[i6 >> 2] | 0);
+  i6 = i6 + 8 | 0;
+ } while ((HEAP32[i6 >> 2] | 0) != 0);
+ i7 = ~i1;
+ _lua_settop(i3, i7);
+ STACKTOP = i2;
+ return;
+}
+function _lua_touserdata(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i3 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i2 = (HEAP32[i3 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i2 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i3 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i2 = HEAP32[i4 >> 2] | 0, (i3 | 0) <= (HEAPU8[i2 + 6 | 0] | 0 | 0)) : 0) {
+    i2 = i2 + (i3 + -1 << 4) + 16 | 0;
+   } else {
+    i2 = 5192;
+   }
+  } else {
+   i2 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i2 = i2 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i2 : 5192;
+  }
+ } while (0);
+ i3 = HEAP32[i2 + 8 >> 2] & 15;
+ if ((i3 | 0) == 2) {
+  i5 = HEAP32[i2 >> 2] | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ } else if ((i3 | 0) == 7) {
+  i5 = (HEAP32[i2 >> 2] | 0) + 24 | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ } else {
+  i5 = 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _luaL_checkoption(i2, i3, i6, i4) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i1;
+ if ((i6 | 0) == 0) {
+  i6 = _lua_tolstring(i2, i3, 0) | 0;
+  if ((i6 | 0) == 0) {
+   i9 = _lua_typename(i2, 4) | 0;
+   i6 = _lua_typename(i2, _lua_type(i2, i3) | 0) | 0;
+   HEAP32[i5 >> 2] = i9;
+   HEAP32[i5 + 4 >> 2] = i6;
+   _luaL_argerror(i2, i3, _lua_pushfstring(i2, 1744, i5) | 0) | 0;
+   i6 = 0;
+  }
+ } else {
+  i6 = _luaL_optlstring(i2, i3, i6, 0) | 0;
+ }
+ i9 = HEAP32[i4 >> 2] | 0;
+ L6 : do {
+  if ((i9 | 0) != 0) {
+   i8 = 0;
+   while (1) {
+    i7 = i8 + 1 | 0;
+    if ((_strcmp(i9, i6) | 0) == 0) {
+     break;
+    }
+    i9 = HEAP32[i4 + (i7 << 2) >> 2] | 0;
+    if ((i9 | 0) == 0) {
+     break L6;
+    } else {
+     i8 = i7;
+    }
+   }
+   STACKTOP = i1;
+   return i8 | 0;
+  }
+ } while (0);
+ HEAP32[i5 >> 2] = i6;
+ i9 = _luaL_argerror(i2, i3, _lua_pushfstring(i2, 1192, i5) | 0) | 0;
+ STACKTOP = i1;
+ return i9 | 0;
+}
+function _lua_toboolean(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i3 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i3 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i3 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i2 = HEAP32[i4 >> 2] | 0, (i3 | 0) <= (HEAPU8[i2 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i2 + (i3 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i2 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i2 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i2 : 5192;
+  }
+ } while (0);
+ i2 = HEAP32[i3 + 8 >> 2] | 0;
+ if ((i2 | 0) == 0) {
+  i5 = 0;
+  i5 = i5 & 1;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ if ((i2 | 0) != 1) {
+  i5 = 1;
+  i5 = i5 & 1;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ i5 = (HEAP32[i3 >> 2] | 0) != 0;
+ i5 = i5 & 1;
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _lua_getfield(i1, i6, i3) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i5 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i4 = (HEAP32[i1 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i4 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i6 = -1001e3 - i6 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i5 >> 2] | 0, (i6 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i4 + (i6 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i5 >> 2] | 0) + (i6 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i5 = i1 + 8 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ i3 = _luaS_new(i1, i3) | 0;
+ HEAP32[i6 >> 2] = i3;
+ HEAP32[i6 + 8 >> 2] = HEAPU8[i3 + 4 | 0] | 0 | 64;
+ i6 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i6 + 16;
+ _luaV_gettable(i1, i4, i6, i6);
+ STACKTOP = i2;
+ return;
+}
+function _luaL_argerror(i1, i6, i3) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i2 = i4;
+ i5 = i4 + 12 | 0;
+ if ((_lua_getstack(i1, 0, i5) | 0) == 0) {
+  HEAP32[i2 >> 2] = i6;
+  HEAP32[i2 + 4 >> 2] = i3;
+  i8 = _luaL_error(i1, 1040, i2) | 0;
+  STACKTOP = i4;
+  return i8 | 0;
+ }
+ _lua_getinfo(i1, 1064, i5) | 0;
+ if ((_strcmp(HEAP32[i5 + 8 >> 2] | 0, 1072) | 0) == 0) {
+  i6 = i6 + -1 | 0;
+  if ((i6 | 0) == 0) {
+   HEAP32[i2 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i2 + 4 >> 2] = i3;
+   i8 = _luaL_error(i1, 1080, i2) | 0;
+   STACKTOP = i4;
+   return i8 | 0;
+  }
+ }
+ i7 = i5 + 4 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ if ((i8 | 0) == 0) {
+  if ((_pushglobalfuncname(i1, i5) | 0) == 0) {
+   i8 = 1112;
+  } else {
+   i8 = _lua_tolstring(i1, -1, 0) | 0;
+  }
+  HEAP32[i7 >> 2] = i8;
+ }
+ HEAP32[i2 >> 2] = i6;
+ HEAP32[i2 + 4 >> 2] = i8;
+ HEAP32[i2 + 8 >> 2] = i3;
+ i8 = _luaL_error(i1, 1120, i2) | 0;
+ STACKTOP = i4;
+ return i8 | 0;
+}
+function _match_class(i3, i2) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i1 = 0;
+ i1 = STACKTOP;
+ switch (_tolower(i2 | 0) | 0) {
+ case 117:
+  {
+   i3 = _isupper(i3 | 0) | 0;
+   break;
+  }
+ case 97:
+  {
+   i3 = _isalpha(i3 | 0) | 0;
+   break;
+  }
+ case 99:
+  {
+   i3 = _iscntrl(i3 | 0) | 0;
+   break;
+  }
+ case 120:
+  {
+   i3 = _isxdigit(i3 | 0) | 0;
+   break;
+  }
+ case 119:
+  {
+   i3 = _isalnum(i3 | 0) | 0;
+   break;
+  }
+ case 112:
+  {
+   i3 = _ispunct(i3 | 0) | 0;
+   break;
+  }
+ case 100:
+  {
+   i3 = (i3 + -48 | 0) >>> 0 < 10 | 0;
+   break;
+  }
+ case 108:
+  {
+   i3 = _islower(i3 | 0) | 0;
+   break;
+  }
+ case 122:
+  {
+   i3 = (i3 | 0) == 0 | 0;
+   break;
+  }
+ case 103:
+  {
+   i3 = _isgraph(i3 | 0) | 0;
+   break;
+  }
+ case 115:
+  {
+   i3 = _isspace(i3 | 0) | 0;
+   break;
+  }
+ default:
+  {
+   i3 = (i2 | 0) == (i3 | 0) | 0;
+   STACKTOP = i1;
+   return i3 | 0;
+  }
+ }
+ if ((_islower(i2 | 0) | 0) != 0) {
+  STACKTOP = i1;
+  return i3 | 0;
+ }
+ i3 = (i3 | 0) == 0 | 0;
+ STACKTOP = i1;
+ return i3 | 0;
+}
+function _condjump(i1, i3, i6, i4, i5) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ _luaK_code(i1, i6 << 6 | i3 | i4 << 23 | i5 << 14) | 0;
+ i3 = i1 + 28 | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ HEAP32[i3 >> 2] = -1;
+ i3 = _luaK_code(i1, 2147450903) | 0;
+ if ((i6 | 0) == -1) {
+  i9 = i3;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ if ((i3 | 0) == -1) {
+  i9 = i6;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ i8 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+ i7 = i3;
+ while (1) {
+  i4 = i8 + (i7 << 2) | 0;
+  i5 = HEAP32[i4 >> 2] | 0;
+  i9 = (i5 >>> 14) + -131071 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  }
+  i9 = i7 + 1 + i9 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  } else {
+   i7 = i9;
+  }
+ }
+ i6 = i6 + ~i7 | 0;
+ if ((((i6 | 0) > -1 ? i6 : 0 - i6 | 0) | 0) > 131071) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+ }
+ HEAP32[i4 >> 2] = (i6 << 14) + 2147467264 | i5 & 16383;
+ i9 = i3;
+ STACKTOP = i2;
+ return i9 | 0;
+}
+function _skipcomment(i6, i1) {
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ HEAP32[i6 >> 2] = 0;
+ i3 = i6 + 4 | 0;
+ i5 = 1712;
+ while (1) {
+  i7 = _fgetc(HEAP32[i3 >> 2] | 0) | 0;
+  if ((i7 | 0) == -1) {
+   i4 = 3;
+   break;
+  }
+  i8 = i5 + 1 | 0;
+  if ((i7 | 0) != (HEAPU8[i5] | 0)) {
+   break;
+  }
+  i5 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i5 + 1;
+  HEAP8[i6 + i5 + 8 | 0] = i7;
+  if ((HEAP8[i8] | 0) == 0) {
+   i4 = 6;
+   break;
+  } else {
+   i5 = i8;
+  }
+ }
+ if ((i4 | 0) == 3) {
+  HEAP32[i1 >> 2] = -1;
+  i8 = 0;
+  STACKTOP = i2;
+  return i8 | 0;
+ } else if ((i4 | 0) == 6) {
+  HEAP32[i6 >> 2] = 0;
+  i7 = _fgetc(HEAP32[i3 >> 2] | 0) | 0;
+ }
+ HEAP32[i1 >> 2] = i7;
+ if ((i7 | 0) != 35) {
+  i8 = 0;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ do {
+  i8 = _fgetc(HEAP32[i3 >> 2] | 0) | 0;
+ } while (!((i8 | 0) == 10 | (i8 | 0) == -1));
+ HEAP32[i1 >> 2] = _fgetc(HEAP32[i3 >> 2] | 0) | 0;
+ i8 = 1;
+ STACKTOP = i2;
+ return i8 | 0;
+}
+function _lua_isnumber(i4, i6) {
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ i5 = HEAP32[i4 + 16 >> 2] | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i3 = (HEAP32[i4 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i3 = (HEAP32[i4 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i4 = -1001e3 - i6 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i5 >> 2] | 0, (i4 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i4 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i5 >> 2] | 0) + (i6 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i4 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ if ((HEAP32[i3 + 8 >> 2] | 0) == 3) {
+  i6 = 1;
+  i6 = i6 & 1;
+  STACKTOP = i1;
+  return i6 | 0;
+ }
+ i6 = (_luaV_tonumber(i3, i2) | 0) != 0;
+ i6 = i6 & 1;
+ STACKTOP = i1;
+ return i6 | 0;
+}
+function ___shgetc(i3) {
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ i7 = i3 + 104 | 0;
+ i6 = HEAP32[i7 >> 2] | 0;
+ if (!((i6 | 0) != 0 ? (HEAP32[i3 + 108 >> 2] | 0) >= (i6 | 0) : 0)) {
+  i8 = 3;
+ }
+ if ((i8 | 0) == 3 ? (i1 = ___uflow(i3) | 0, (i1 | 0) >= 0) : 0) {
+  i7 = HEAP32[i7 >> 2] | 0;
+  i6 = HEAP32[i3 + 8 >> 2] | 0;
+  if ((i7 | 0) != 0 ? (i4 = HEAP32[i3 + 4 >> 2] | 0, i5 = i7 - (HEAP32[i3 + 108 >> 2] | 0) + -1 | 0, (i6 - i4 | 0) > (i5 | 0)) : 0) {
+   HEAP32[i3 + 100 >> 2] = i4 + i5;
+  } else {
+   HEAP32[i3 + 100 >> 2] = i6;
+  }
+  i4 = HEAP32[i3 + 4 >> 2] | 0;
+  if ((i6 | 0) != 0) {
+   i8 = i3 + 108 | 0;
+   HEAP32[i8 >> 2] = i6 + 1 - i4 + (HEAP32[i8 >> 2] | 0);
+  }
+  i3 = i4 + -1 | 0;
+  if ((HEAPU8[i3] | 0 | 0) == (i1 | 0)) {
+   i8 = i1;
+   STACKTOP = i2;
+   return i8 | 0;
+  }
+  HEAP8[i3] = i1;
+  i8 = i1;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ HEAP32[i3 + 100 >> 2] = 0;
+ i8 = -1;
+ STACKTOP = i2;
+ return i8 | 0;
+}
+function _lua_type(i2, i4) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i3 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i4 | 0) <= 0) {
+   if (!((i4 | 0) < -1000999)) {
+    i2 = (HEAP32[i2 + 8 >> 2] | 0) + (i4 << 4) | 0;
+    break;
+   }
+   if ((i4 | 0) == -1001e3) {
+    i2 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i2 = -1001e3 - i4 | 0;
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((HEAP32[i3 + 8 >> 2] | 0) == 22) {
+    i4 = -1;
+    STACKTOP = i1;
+    return i4 | 0;
+   }
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((i2 | 0) > (HEAPU8[i3 + 6 | 0] | 0 | 0)) {
+    i4 = -1;
+    STACKTOP = i1;
+    return i4 | 0;
+   } else {
+    i2 = i3 + (i2 + -1 << 4) + 16 | 0;
+    break;
+   }
+  } else {
+   i3 = (HEAP32[i3 >> 2] | 0) + (i4 << 4) | 0;
+   i2 = i3 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ if ((i2 | 0) == 5192) {
+  i4 = -1;
+  STACKTOP = i1;
+  return i4 | 0;
+ }
+ i4 = HEAP32[i2 + 8 >> 2] & 15;
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _g_iofile(i4, i1, i5) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ if ((_lua_type(i4, 1) | 0) < 1) {
+  _lua_getfield(i4, -1001e3, i1);
+  STACKTOP = i2;
+  return;
+ }
+ i6 = _lua_tolstring(i4, 1, 0) | 0;
+ if ((i6 | 0) != 0) {
+  i7 = _lua_newuserdata(i4, 8) | 0;
+  i8 = i7 + 4 | 0;
+  HEAP32[i8 >> 2] = 0;
+  _luaL_setmetatable(i4, 2832);
+  HEAP32[i7 >> 2] = 0;
+  HEAP32[i8 >> 2] = 156;
+  i5 = _fopen(i6 | 0, i5 | 0) | 0;
+  HEAP32[i7 >> 2] = i5;
+  if ((i5 | 0) == 0) {
+   i8 = _strerror(HEAP32[(___errno_location() | 0) >> 2] | 0) | 0;
+   HEAP32[i3 >> 2] = i6;
+   HEAP32[i3 + 4 >> 2] = i8;
+   _luaL_error(i4, 3520, i3) | 0;
+  }
+ } else {
+  if ((HEAP32[(_luaL_checkudata(i4, 1, 2832) | 0) + 4 >> 2] | 0) == 0) {
+   _luaL_error(i4, 3080, i3) | 0;
+  }
+  _lua_pushvalue(i4, 1);
+ }
+ _lua_setfield(i4, -1001e3, i1);
+ _lua_getfield(i4, -1001e3, i1);
+ STACKTOP = i2;
+ return;
+}
+function _lua_getlocal(i4, i5, i2) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ if ((i5 | 0) == 0) {
+  i3 = HEAP32[i4 + 8 >> 2] | 0;
+  if ((HEAP32[i3 + -8 >> 2] | 0) != 70) {
+   i5 = 0;
+   STACKTOP = i1;
+   return i5 | 0;
+  }
+  i5 = _luaF_getlocalname(HEAP32[(HEAP32[i3 + -16 >> 2] | 0) + 12 >> 2] | 0, i2, 0) | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ } else {
+  HEAP32[i3 >> 2] = 0;
+  i2 = _findlocal(i4, HEAP32[i5 + 96 >> 2] | 0, i2, i3) | 0;
+  if ((i2 | 0) == 0) {
+   i5 = 0;
+   STACKTOP = i1;
+   return i5 | 0;
+  }
+  i3 = HEAP32[i3 >> 2] | 0;
+  i5 = i4 + 8 | 0;
+  i4 = HEAP32[i5 >> 2] | 0;
+  i8 = i3;
+  i7 = HEAP32[i8 + 4 >> 2] | 0;
+  i6 = i4;
+  HEAP32[i6 >> 2] = HEAP32[i8 >> 2];
+  HEAP32[i6 + 4 >> 2] = i7;
+  HEAP32[i4 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+  HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 16;
+  i5 = i2;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _lua_checkstack(i7, i4) {
+ i7 = i7 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i8 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ HEAP32[i3 >> 2] = i4;
+ i2 = HEAP32[i7 + 16 >> 2] | 0;
+ i5 = i7 + 8 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ i8 = i6;
+ do {
+  if (((HEAP32[i7 + 24 >> 2] | 0) - i8 >> 4 | 0) <= (i4 | 0)) {
+   if (((i8 - (HEAP32[i7 + 28 >> 2] | 0) >> 4) + 5 | 0) > (1e6 - i4 | 0)) {
+    i8 = 0;
+    STACKTOP = i1;
+    return i8 | 0;
+   }
+   i6 = (_luaD_rawrunprotected(i7, 2, i3) | 0) == 0;
+   if (i6) {
+    i5 = HEAP32[i5 >> 2] | 0;
+    i4 = HEAP32[i3 >> 2] | 0;
+    i3 = i6 & 1;
+    break;
+   } else {
+    i8 = 0;
+    STACKTOP = i1;
+    return i8 | 0;
+   }
+  } else {
+   i5 = i6;
+   i3 = 1;
+  }
+ } while (0);
+ i2 = i2 + 4 | 0;
+ i4 = i5 + (i4 << 4) | 0;
+ if (!((HEAP32[i2 >> 2] | 0) >>> 0 < i4 >>> 0)) {
+  i8 = i3;
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ HEAP32[i2 >> 2] = i4;
+ i8 = i3;
+ STACKTOP = i1;
+ return i8 | 0;
+}
+function _luaK_exp2nextreg(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ _luaK_dischargevars(i1, i3);
+ if (((HEAP32[i3 >> 2] | 0) == 6 ? (i4 = HEAP32[i3 + 8 >> 2] | 0, (i4 & 256 | 0) == 0) : 0) ? (HEAPU8[i1 + 46 | 0] | 0 | 0) <= (i4 | 0) : 0) {
+  i7 = i1 + 48 | 0;
+  HEAP8[i7] = (HEAP8[i7] | 0) + -1 << 24 >> 24;
+ }
+ i4 = i1 + 48 | 0;
+ i5 = HEAP8[i4] | 0;
+ i6 = (i5 & 255) + 1 | 0;
+ i7 = (HEAP32[i1 >> 2] | 0) + 78 | 0;
+ if (!(i6 >>> 0 > (HEAPU8[i7] | 0) >>> 0)) {
+  i7 = i5;
+  i7 = i7 & 255;
+  i7 = i7 + 1 | 0;
+  i6 = i7 & 255;
+  HEAP8[i4] = i6;
+  i7 = i7 & 255;
+  i7 = i7 + -1 | 0;
+  _exp2reg(i1, i3, i7);
+  STACKTOP = i2;
+  return;
+ }
+ if (i6 >>> 0 > 249) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10536);
+ }
+ HEAP8[i7] = i6;
+ i7 = HEAP8[i4] | 0;
+ i7 = i7 & 255;
+ i7 = i7 + 1 | 0;
+ i6 = i7 & 255;
+ HEAP8[i4] = i6;
+ i7 = i7 & 255;
+ i7 = i7 + -1 | 0;
+ _exp2reg(i1, i3, i7);
+ STACKTOP = i2;
+ return;
+}
+function _lua_next(i2, i4) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0, i5 = 0;
+ i1 = STACKTOP;
+ i5 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i4 | 0) <= 0) {
+   if (!((i4 | 0) < -1000999)) {
+    i4 = (HEAP32[i2 + 8 >> 2] | 0) + (i4 << 4) | 0;
+    break;
+   }
+   if ((i4 | 0) == -1001e3) {
+    i4 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i4 = -1001e3 - i4 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i5 >> 2] | 0, (i4 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i3 + (i4 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i5 >> 2] | 0) + (i4 << 4) | 0;
+   i4 = i3 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i3 = i2 + 8 | 0;
+ i2 = _luaH_next(i2, HEAP32[i4 >> 2] | 0, (HEAP32[i3 >> 2] | 0) + -16 | 0) | 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ HEAP32[i3 >> 2] = (i2 | 0) == 0 ? i4 + -16 | 0 : i4 + 16 | 0;
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _inclinenumber(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 >> 2] | 0;
+ i3 = i1 + 56 | 0;
+ i5 = HEAP32[i3 >> 2] | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i6 + -1;
+ if ((i6 | 0) == 0) {
+  i5 = _luaZ_fill(i5) | 0;
+ } else {
+  i6 = i5 + 4 | 0;
+  i5 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i5 + 1;
+  i5 = HEAPU8[i5] | 0;
+ }
+ HEAP32[i1 >> 2] = i5;
+ if ((i5 | 0) == 13 | (i5 | 0) == 10 ? (i5 | 0) != (i4 | 0) : 0) {
+  i3 = HEAP32[i3 >> 2] | 0;
+  i6 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i6 + -1;
+  if ((i6 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i6 = i3 + 4 | 0;
+   i3 = HEAP32[i6 >> 2] | 0;
+   HEAP32[i6 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i1 >> 2] = i3;
+ }
+ i5 = i1 + 4 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i6 + 1;
+ if ((i6 | 0) > 2147483643) {
+  _luaX_syntaxerror(i1, 12560);
+ } else {
+  STACKTOP = i2;
+  return;
+ }
+}
+function _lua_yieldk(i5, i6, i1, i7) {
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i3 = HEAP32[i5 + 16 >> 2] | 0;
+ if ((HEAP16[i5 + 36 >> 1] | 0) != 0) {
+  if ((HEAP32[(HEAP32[i5 + 12 >> 2] | 0) + 172 >> 2] | 0) == (i5 | 0)) {
+   _luaG_runerror(i5, 2312, i4);
+  } else {
+   _luaG_runerror(i5, 2264, i4);
+  }
+ }
+ HEAP8[i5 + 6 | 0] = 1;
+ HEAP32[i3 + 20 >> 2] = (HEAP32[i3 >> 2] | 0) - (HEAP32[i5 + 28 >> 2] | 0);
+ if (!((HEAP8[i3 + 18 | 0] & 1) == 0)) {
+  STACKTOP = i2;
+  return 0;
+ }
+ HEAP32[i3 + 28 >> 2] = i7;
+ if ((i7 | 0) == 0) {
+  i4 = i5 + 8 | 0;
+  i4 = HEAP32[i4 >> 2] | 0;
+  i7 = ~i6;
+  i7 = i4 + (i7 << 4) | 0;
+  HEAP32[i3 >> 2] = i7;
+  _luaD_throw(i5, 1);
+ }
+ HEAP32[i3 + 24 >> 2] = i1;
+ i4 = i5 + 8 | 0;
+ i4 = HEAP32[i4 >> 2] | 0;
+ i7 = ~i6;
+ i7 = i4 + (i7 << 4) | 0;
+ HEAP32[i3 >> 2] = i7;
+ _luaD_throw(i5, 1);
+ return 0;
+}
+function _luaH_getint(i4, i6) {
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, d3 = 0.0, i5 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i1;
+ i7 = i6 + -1 | 0;
+ if (i7 >>> 0 < (HEAP32[i4 + 28 >> 2] | 0) >>> 0) {
+  i7 = (HEAP32[i4 + 12 >> 2] | 0) + (i7 << 4) | 0;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ d3 = +(i6 | 0);
+ HEAPF64[i5 >> 3] = d3 + 1.0;
+ i5 = (HEAP32[i5 + 4 >> 2] | 0) + (HEAP32[i5 >> 2] | 0) | 0;
+ if ((i5 | 0) < 0) {
+  i6 = 0 - i5 | 0;
+  i5 = (i5 | 0) == (i6 | 0) ? 0 : i6;
+ }
+ i4 = (HEAP32[i4 + 16 >> 2] | 0) + (((i5 | 0) % ((1 << (HEAPU8[i4 + 7 | 0] | 0)) + -1 | 1 | 0) | 0) << 5) | 0;
+ while (1) {
+  if ((HEAP32[i4 + 24 >> 2] | 0) == 3 ? +HEAPF64[i4 + 16 >> 3] == d3 : 0) {
+   break;
+  }
+  i4 = HEAP32[i4 + 28 >> 2] | 0;
+  if ((i4 | 0) == 0) {
+   i4 = 5192;
+   i2 = 10;
+   break;
+  }
+ }
+ if ((i2 | 0) == 10) {
+  STACKTOP = i1;
+  return i4 | 0;
+ }
+ i7 = i4;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _luaL_checkversion_(i1, d4) {
+ i1 = i1 | 0;
+ d4 = +d4;
+ var i2 = 0, i3 = 0, i5 = 0, d6 = 0.0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i5 = _lua_version(i1) | 0;
+ if ((i5 | 0) == (_lua_version(0) | 0)) {
+  d6 = +HEAPF64[i5 >> 3];
+  if (d6 != d4) {
+   HEAPF64[tempDoublePtr >> 3] = d4;
+   HEAP32[i3 >> 2] = HEAP32[tempDoublePtr >> 2];
+   HEAP32[i3 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+   i5 = i3 + 8 | 0;
+   HEAPF64[tempDoublePtr >> 3] = d6;
+   HEAP32[i5 >> 2] = HEAP32[tempDoublePtr >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+   _luaL_error(i1, 1528, i3) | 0;
+  }
+ } else {
+  _luaL_error(i1, 1496, i3) | 0;
+ }
+ _lua_pushnumber(i1, -4660.0);
+ if ((_lua_tointegerx(i1, -1, 0) | 0) == -4660 ? (_lua_tounsignedx(i1, -1, 0) | 0) == -4660 : 0) {
+  _lua_settop(i1, -2);
+  STACKTOP = i2;
+  return;
+ }
+ _luaL_error(i1, 1584, i3) | 0;
+ _lua_settop(i1, -2);
+ STACKTOP = i2;
+ return;
+}
+function _math_random(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0, i4 = 0, i5 = 0, d6 = 0.0, d7 = 0.0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ d3 = +((_rand() | 0) % 2147483647 | 0 | 0) / 2147483647.0;
+ i5 = _lua_gettop(i1) | 0;
+ if ((i5 | 0) == 0) {
+  _lua_pushnumber(i1, d3);
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ } else if ((i5 | 0) == 1) {
+  d6 = +_luaL_checknumber(i1, 1);
+  if (!(d6 >= 1.0)) {
+   _luaL_argerror(i1, 1, 4056) | 0;
+  }
+  _lua_pushnumber(i1, +Math_floor(+(d3 * d6)) + 1.0);
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ } else if ((i5 | 0) == 2) {
+  d6 = +_luaL_checknumber(i1, 1);
+  d7 = +_luaL_checknumber(i1, 2);
+  if (!(d6 <= d7)) {
+   _luaL_argerror(i1, 2, 4056) | 0;
+  }
+  _lua_pushnumber(i1, d6 + +Math_floor(+(d3 * (d7 - d6 + 1.0))));
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ } else {
+  i5 = _luaL_error(i1, 4080, i4) | 0;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _push_onecapture(i2, i3, i4, i6) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i5 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i1;
+ if ((HEAP32[i2 + 20 >> 2] | 0) <= (i3 | 0)) {
+  i2 = HEAP32[i2 + 16 >> 2] | 0;
+  if ((i3 | 0) == 0) {
+   _lua_pushlstring(i2, i4, i6 - i4 | 0) | 0;
+   STACKTOP = i1;
+   return;
+  } else {
+   _luaL_error(i2, 7224, i5) | 0;
+   STACKTOP = i1;
+   return;
+  }
+ }
+ i4 = HEAP32[i2 + (i3 << 3) + 28 >> 2] | 0;
+ if (!((i4 | 0) == -1)) {
+  i5 = HEAP32[i2 + 16 >> 2] | 0;
+  i3 = HEAP32[i2 + (i3 << 3) + 24 >> 2] | 0;
+  if ((i4 | 0) == -2) {
+   _lua_pushinteger(i5, i3 + 1 - (HEAP32[i2 + 4 >> 2] | 0) | 0);
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  i6 = i2 + 16 | 0;
+  _luaL_error(HEAP32[i6 >> 2] | 0, 7248, i5) | 0;
+  i5 = HEAP32[i6 >> 2] | 0;
+  i3 = HEAP32[i2 + (i3 << 3) + 24 >> 2] | 0;
+ }
+ _lua_pushlstring(i5, i3, i4) | 0;
+ STACKTOP = i1;
+ return;
+}
+function _luaK_nil(i7, i6, i5) {
+ i7 = i7 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i2 = STACKTOP;
+ i9 = i5 + i6 | 0;
+ i1 = i9 + -1 | 0;
+ i10 = HEAP32[i7 + 20 >> 2] | 0;
+ do {
+  if ((i10 | 0) > (HEAP32[i7 + 24 >> 2] | 0) ? (i4 = (HEAP32[(HEAP32[i7 >> 2] | 0) + 12 >> 2] | 0) + (i10 + -1 << 2) | 0, i3 = HEAP32[i4 >> 2] | 0, (i3 & 63 | 0) == 4) : 0) {
+   i11 = i3 >>> 6 & 255;
+   i10 = i11 + (i3 >>> 23) | 0;
+   if (!((i11 | 0) <= (i6 | 0) ? (i10 + 1 | 0) >= (i6 | 0) : 0)) {
+    i8 = 5;
+   }
+   if ((i8 | 0) == 5 ? (i11 | 0) < (i6 | 0) | (i11 | 0) > (i9 | 0) : 0) {
+    break;
+   }
+   i5 = (i11 | 0) < (i6 | 0) ? i11 : i6;
+   HEAP32[i4 >> 2] = ((i10 | 0) > (i1 | 0) ? i10 : i1) - i5 << 23 | i5 << 6 & 16320 | i3 & 8372287;
+   STACKTOP = i2;
+   return;
+  }
+ } while (0);
+ _luaK_code(i7, i6 << 6 | (i5 << 23) + -8388608 | 4) | 0;
+ STACKTOP = i2;
+ return;
+}
+function _lua_settable(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i5 = i1 + 8 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ _luaV_settable(i1, i3, i4 + -32 | 0, i4 + -16 | 0);
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + -32;
+ STACKTOP = i2;
+ return;
+}
+function _luaL_findtable(i3, i6, i5, i4) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i7 = 0;
+ i2 = STACKTOP;
+ if ((i6 | 0) != 0) {
+  _lua_pushvalue(i3, i6);
+ }
+ while (1) {
+  i6 = _strchr(i5, 46) | 0;
+  if ((i6 | 0) == 0) {
+   i6 = i5 + (_strlen(i5 | 0) | 0) | 0;
+  }
+  i7 = i6 - i5 | 0;
+  _lua_pushlstring(i3, i5, i7) | 0;
+  _lua_rawget(i3, -2);
+  if ((_lua_type(i3, -1) | 0) != 0) {
+   if ((_lua_type(i3, -1) | 0) != 5) {
+    break;
+   }
+  } else {
+   _lua_settop(i3, -2);
+   _lua_createtable(i3, 0, (HEAP8[i6] | 0) == 46 ? 1 : i4);
+   _lua_pushlstring(i3, i5, i7) | 0;
+   _lua_pushvalue(i3, -2);
+   _lua_settable(i3, -4);
+  }
+  _lua_remove(i3, -2);
+  if ((HEAP8[i6] | 0) == 46) {
+   i5 = i6 + 1 | 0;
+  } else {
+   i3 = 0;
+   i1 = 10;
+   break;
+  }
+ }
+ if ((i1 | 0) == 10) {
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ _lua_settop(i3, -3);
+ i7 = i5;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _luaD_call(i1, i4, i5, i8) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i8 = i8 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i7 = i3;
+ i2 = i1 + 38 | 0;
+ i6 = (HEAP16[i2 >> 1] | 0) + 1 << 16 >> 16;
+ HEAP16[i2 >> 1] = i6;
+ if ((i6 & 65535) > 199) {
+  if (i6 << 16 >> 16 == 200) {
+   _luaG_runerror(i1, 2240, i7);
+  }
+  if ((i6 & 65535) > 224) {
+   _luaD_throw(i1, 6);
+  }
+ }
+ i6 = (i8 | 0) != 0;
+ if (!i6) {
+  i8 = i1 + 36 | 0;
+  HEAP16[i8 >> 1] = (HEAP16[i8 >> 1] | 0) + 1 << 16 >> 16;
+ }
+ if ((_luaD_precall(i1, i4, i5) | 0) == 0) {
+  _luaV_execute(i1);
+ }
+ if (i6) {
+  i8 = HEAP16[i2 >> 1] | 0;
+  i8 = i8 + -1 << 16 >> 16;
+  HEAP16[i2 >> 1] = i8;
+  STACKTOP = i3;
+  return;
+ }
+ i8 = i1 + 36 | 0;
+ HEAP16[i8 >> 1] = (HEAP16[i8 >> 1] | 0) + -1 << 16 >> 16;
+ i8 = HEAP16[i2 >> 1] | 0;
+ i8 = i8 + -1 << 16 >> 16;
+ HEAP16[i2 >> 1] = i8;
+ STACKTOP = i3;
+ return;
+}
+function _pushline(i6, i1) {
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 528 | 0;
+ i4 = i2;
+ i3 = i2 + 8 | 0;
+ i7 = (i1 | 0) != 0;
+ _lua_getglobal(i6, i7 ? 288 : 296);
+ i8 = _lua_tolstring(i6, -1, 0) | 0;
+ if ((i8 | 0) == 0) {
+  i8 = i7 ? 312 : 320;
+ }
+ i7 = HEAP32[_stdout >> 2] | 0;
+ _fputs(i8 | 0, i7 | 0) | 0;
+ _fflush(i7 | 0) | 0;
+ i8 = (_fgets(i3 | 0, 512, HEAP32[_stdin >> 2] | 0) | 0) == 0;
+ _lua_settop(i6, -2);
+ if (i8) {
+  i8 = 0;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ i7 = _strlen(i3 | 0) | 0;
+ if ((i7 | 0) != 0 ? (i5 = i3 + (i7 + -1) | 0, (HEAP8[i5] | 0) == 10) : 0) {
+  HEAP8[i5] = 0;
+ }
+ if ((i1 | 0) != 0 ? (HEAP8[i3] | 0) == 61 : 0) {
+  HEAP32[i4 >> 2] = i3 + 1;
+  _lua_pushfstring(i6, 272, i4) | 0;
+  i8 = 1;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ _lua_pushstring(i6, i3) | 0;
+ i8 = 1;
+ STACKTOP = i2;
+ return i8 | 0;
+}
+function _db_getlocal(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i4 = i2;
+ if ((_lua_type(i1, 1) | 0) == 8) {
+  i3 = _lua_tothread(i1, 1) | 0;
+  i6 = 1;
+ } else {
+  i3 = i1;
+  i6 = 0;
+ }
+ i5 = _luaL_checkinteger(i1, i6 | 2) | 0;
+ i6 = i6 + 1 | 0;
+ if ((_lua_type(i1, i6) | 0) == 6) {
+  _lua_pushvalue(i1, i6);
+  _lua_pushstring(i1, _lua_getlocal(i1, 0, i5) | 0) | 0;
+  i6 = 1;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ if ((_lua_getstack(i3, _luaL_checkinteger(i1, i6) | 0, i4) | 0) == 0) {
+  i6 = _luaL_argerror(i1, i6, 11560) | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ i4 = _lua_getlocal(i3, i4, i5) | 0;
+ if ((i4 | 0) == 0) {
+  _lua_pushnil(i1);
+  i6 = 1;
+  STACKTOP = i2;
+  return i6 | 0;
+ } else {
+  _lua_xmove(i3, i1, 1);
+  _lua_pushstring(i1, i4) | 0;
+  _lua_pushvalue(i1, -2);
+  i6 = 2;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ return 0;
+}
+function _luaB_print(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i3;
+ i4 = i3 + 4 | 0;
+ i6 = _lua_gettop(i1) | 0;
+ _lua_getglobal(i1, 9584);
+ i5 = HEAP32[_stdout >> 2] | 0;
+ L1 : do {
+  if ((i6 | 0) >= 1) {
+   i7 = 1;
+   while (1) {
+    _lua_pushvalue(i1, -1);
+    _lua_pushvalue(i1, i7);
+    _lua_callk(i1, 1, 1, 0, 0);
+    i8 = _lua_tolstring(i1, -1, i4) | 0;
+    if ((i8 | 0) == 0) {
+     break;
+    }
+    if ((i7 | 0) > 1) {
+     _fputc(9, i5 | 0) | 0;
+    }
+    _fwrite(i8 | 0, 1, HEAP32[i4 >> 2] | 0, i5 | 0) | 0;
+    _lua_settop(i1, -2);
+    if ((i7 | 0) < (i6 | 0)) {
+     i7 = i7 + 1 | 0;
+    } else {
+     break L1;
+    }
+   }
+   i8 = _luaL_error(i1, 9816, i2) | 0;
+   STACKTOP = i3;
+   return i8 | 0;
+  }
+ } while (0);
+ _fputc(10, i5 | 0) | 0;
+ _fflush(i5 | 0) | 0;
+ i8 = 0;
+ STACKTOP = i3;
+ return i8 | 0;
+}
+function _luaB_load(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i2;
+ i6 = _lua_tolstring(i1, 1, i5) | 0;
+ i4 = _luaL_optlstring(i1, 3, 9872, 0) | 0;
+ i3 = (_lua_type(i1, 4) | 0) != -1;
+ if ((i6 | 0) == 0) {
+  i6 = _luaL_optlstring(i1, 2, 9880, 0) | 0;
+  _luaL_checktype(i1, 1, 6);
+  _lua_settop(i1, 5);
+  i4 = _lua_load(i1, 3, 0, i6, i4) | 0;
+ } else {
+  i7 = _luaL_optlstring(i1, 2, i6, 0) | 0;
+  i4 = _luaL_loadbufferx(i1, i6, HEAP32[i5 >> 2] | 0, i7, i4) | 0;
+ }
+ if ((i4 | 0) != 0) {
+  _lua_pushnil(i1);
+  _lua_insert(i1, -2);
+  i7 = 2;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ if (!i3) {
+  i7 = 1;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ _lua_pushvalue(i1, i3 ? 4 : 0);
+ if ((_lua_setupvalue(i1, -2, 1) | 0) != 0) {
+  i7 = 1;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ _lua_settop(i1, -2);
+ i7 = 1;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _db_debug(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 256 | 0;
+ i6 = i1;
+ i4 = i1 + 4 | 0;
+ i3 = HEAP32[_stderr >> 2] | 0;
+ _fwrite(12040, 11, 1, i3 | 0) | 0;
+ _fflush(i3 | 0) | 0;
+ i5 = HEAP32[_stdin >> 2] | 0;
+ if ((_fgets(i4 | 0, 250, i5 | 0) | 0) == 0) {
+  STACKTOP = i1;
+  return 0;
+ }
+ while (1) {
+  if ((_strcmp(i4, 12056) | 0) == 0) {
+   i2 = 7;
+   break;
+  }
+  if (!((_luaL_loadbufferx(i2, i4, _strlen(i4 | 0) | 0, 12064, 0) | 0) == 0 ? (_lua_pcallk(i2, 0, 0, 0, 0, 0) | 0) == 0 : 0)) {
+   HEAP32[i6 >> 2] = _lua_tolstring(i2, -1, 0) | 0;
+   _fprintf(i3 | 0, 12088, i6 | 0) | 0;
+   _fflush(i3 | 0) | 0;
+  }
+  _lua_settop(i2, 0);
+  _fwrite(12040, 11, 1, i3 | 0) | 0;
+  _fflush(i3 | 0) | 0;
+  if ((_fgets(i4 | 0, 250, i5 | 0) | 0) == 0) {
+   i2 = 7;
+   break;
+  }
+ }
+ if ((i2 | 0) == 7) {
+  STACKTOP = i1;
+  return 0;
+ }
+ return 0;
+}
+function _luaL_prepbuffsize(i2, i7) {
+ i2 = i2 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i1 = HEAP32[i2 + 12 >> 2] | 0;
+ i4 = i2 + 4 | 0;
+ i8 = HEAP32[i4 >> 2] | 0;
+ i5 = i2 + 8 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ if (!((i8 - i6 | 0) >>> 0 < i7 >>> 0)) {
+  i7 = HEAP32[i2 >> 2] | 0;
+  i8 = i6;
+  i8 = i7 + i8 | 0;
+  STACKTOP = i3;
+  return i8 | 0;
+ }
+ i8 = i8 << 1;
+ i8 = (i8 - i6 | 0) >>> 0 < i7 >>> 0 ? i6 + i7 | 0 : i8;
+ if (i8 >>> 0 < i6 >>> 0 | (i8 - i6 | 0) >>> 0 < i7 >>> 0) {
+  _luaL_error(i1, 1272, i3) | 0;
+ }
+ i6 = _lua_newuserdata(i1, i8) | 0;
+ _memcpy(i6 | 0, HEAP32[i2 >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0;
+ if ((HEAP32[i2 >> 2] | 0) != (i2 + 16 | 0)) {
+  _lua_remove(i1, -2);
+ }
+ HEAP32[i2 >> 2] = i6;
+ HEAP32[i4 >> 2] = i8;
+ i7 = i6;
+ i8 = HEAP32[i5 >> 2] | 0;
+ i8 = i7 + i8 | 0;
+ STACKTOP = i3;
+ return i8 | 0;
+}
+function _luaG_runerror(i1, i5, i4) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 96 | 0;
+ i2 = i6;
+ i3 = i6 + 32 | 0;
+ i6 = i6 + 16 | 0;
+ HEAP32[i6 >> 2] = i4;
+ i4 = _luaO_pushvfstring(i1, i5, i6) | 0;
+ i6 = HEAP32[i1 + 16 >> 2] | 0;
+ if ((HEAP8[i6 + 18 | 0] & 1) == 0) {
+  _luaG_errormsg(i1);
+ }
+ i5 = HEAP32[(HEAP32[HEAP32[i6 >> 2] >> 2] | 0) + 12 >> 2] | 0;
+ i7 = HEAP32[i5 + 20 >> 2] | 0;
+ if ((i7 | 0) == 0) {
+  i6 = 0;
+ } else {
+  i6 = HEAP32[i7 + (((HEAP32[i6 + 28 >> 2] | 0) - (HEAP32[i5 + 12 >> 2] | 0) >> 2) + -1 << 2) >> 2] | 0;
+ }
+ i5 = HEAP32[i5 + 36 >> 2] | 0;
+ if ((i5 | 0) == 0) {
+  HEAP8[i3] = 63;
+  HEAP8[i3 + 1 | 0] = 0;
+ } else {
+  _luaO_chunkid(i3, i5 + 16 | 0, 60);
+ }
+ HEAP32[i2 >> 2] = i3;
+ HEAP32[i2 + 4 >> 2] = i6;
+ HEAP32[i2 + 8 >> 2] = i4;
+ _luaO_pushfstring(i1, 2024, i2) | 0;
+ _luaG_errormsg(i1);
+}
+function _db_upvaluejoin(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i4 = i3;
+ i2 = _luaL_checkinteger(i1, 2) | 0;
+ _luaL_checktype(i1, 1, 6);
+ _lua_pushvalue(i1, 1);
+ _lua_getinfo(i1, 11728, i4) | 0;
+ if (!((i2 | 0) > 0 ? (i2 | 0) <= (HEAPU8[i4 + 32 | 0] | 0 | 0) : 0)) {
+  _luaL_argerror(i1, 2, 11736) | 0;
+ }
+ i5 = _luaL_checkinteger(i1, 4) | 0;
+ _luaL_checktype(i1, 3, 6);
+ _lua_pushvalue(i1, 3);
+ _lua_getinfo(i1, 11728, i4) | 0;
+ if (!((i5 | 0) > 0 ? (i5 | 0) <= (HEAPU8[i4 + 32 | 0] | 0 | 0) : 0)) {
+  _luaL_argerror(i1, 4, 11736) | 0;
+ }
+ if ((_lua_iscfunction(i1, 1) | 0) != 0) {
+  _luaL_argerror(i1, 1, 11760) | 0;
+ }
+ if ((_lua_iscfunction(i1, 3) | 0) == 0) {
+  _lua_upvaluejoin(i1, 1, i2, 3, i5);
+  STACKTOP = i3;
+  return 0;
+ }
+ _luaL_argerror(i1, 3, 11760) | 0;
+ _lua_upvaluejoin(i1, 1, i2, 3, i5);
+ STACKTOP = i3;
+ return 0;
+}
+function _luaK_jump(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i3 = STACKTOP;
+ i2 = i1 + 28 | 0;
+ i7 = HEAP32[i2 >> 2] | 0;
+ HEAP32[i2 >> 2] = -1;
+ i2 = _luaK_code(i1, 2147450903) | 0;
+ if ((i7 | 0) == -1) {
+  i9 = i2;
+  STACKTOP = i3;
+  return i9 | 0;
+ }
+ if ((i2 | 0) == -1) {
+  i9 = i7;
+  STACKTOP = i3;
+  return i9 | 0;
+ }
+ i6 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+ i8 = i2;
+ while (1) {
+  i5 = i6 + (i8 << 2) | 0;
+  i4 = HEAP32[i5 >> 2] | 0;
+  i9 = (i4 >>> 14) + -131071 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  }
+  i9 = i8 + 1 + i9 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  } else {
+   i8 = i9;
+  }
+ }
+ i6 = i7 + ~i8 | 0;
+ if ((((i6 | 0) > -1 ? i6 : 0 - i6 | 0) | 0) > 131071) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+ }
+ HEAP32[i5 >> 2] = (i6 << 14) + 2147467264 | i4 & 16383;
+ i9 = i2;
+ STACKTOP = i3;
+ return i9 | 0;
+}
+function _findfield(i2, i3, i4) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i1 = 0;
+ i1 = STACKTOP;
+ L1 : do {
+  if (((i4 | 0) != 0 ? (_lua_type(i2, -1) | 0) == 5 : 0) ? (_lua_pushnil(i2), (_lua_next(i2, -2) | 0) != 0) : 0) {
+   i4 = i4 + -1 | 0;
+   while (1) {
+    if ((_lua_type(i2, -2) | 0) == 4) {
+     if ((_lua_rawequal(i2, i3, -1) | 0) != 0) {
+      i3 = 7;
+      break;
+     }
+     if ((_findfield(i2, i3, i4) | 0) != 0) {
+      i3 = 9;
+      break;
+     }
+    }
+    _lua_settop(i2, -2);
+    if ((_lua_next(i2, -2) | 0) == 0) {
+     i2 = 0;
+     break L1;
+    }
+   }
+   if ((i3 | 0) == 7) {
+    _lua_settop(i2, -2);
+    i2 = 1;
+    break;
+   } else if ((i3 | 0) == 9) {
+    _lua_remove(i2, -2);
+    _lua_pushlstring(i2, 1776, 1) | 0;
+    _lua_insert(i2, -2);
+    _lua_concat(i2, 3);
+    i2 = 1;
+    break;
+   }
+  } else {
+   i2 = 0;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _db_gethook(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i3;
+ if ((_lua_type(i1, 1) | 0) == 8) {
+  i4 = _lua_tothread(i1, 1) | 0;
+ } else {
+  i4 = i1;
+ }
+ i5 = _lua_gethookmask(i4) | 0;
+ i6 = _lua_gethook(i4) | 0;
+ if ((i6 | 0) != 0 & (i6 | 0) != 9) {
+  _lua_pushlstring(i1, 12024, 13) | 0;
+ } else {
+  _luaL_getsubtable(i1, -1001e3, 11584) | 0;
+  _lua_pushthread(i4) | 0;
+  _lua_xmove(i4, i1, 1);
+  _lua_rawget(i1, -2);
+  _lua_remove(i1, -2);
+ }
+ if ((i5 & 1 | 0) == 0) {
+  i6 = 0;
+ } else {
+  HEAP8[i2] = 99;
+  i6 = 1;
+ }
+ if ((i5 & 2 | 0) != 0) {
+  HEAP8[i2 + i6 | 0] = 114;
+  i6 = i6 + 1 | 0;
+ }
+ if ((i5 & 4 | 0) != 0) {
+  HEAP8[i2 + i6 | 0] = 108;
+  i6 = i6 + 1 | 0;
+ }
+ HEAP8[i2 + i6 | 0] = 0;
+ _lua_pushstring(i1, i2) | 0;
+ _lua_pushinteger(i1, _lua_gethookcount(i4) | 0);
+ STACKTOP = i3;
+ return 3;
+}
+function _lua_tothread(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i3 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i2 = (HEAP32[i3 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i2 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i3 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i2 = HEAP32[i4 >> 2] | 0, (i3 | 0) <= (HEAPU8[i2 + 6 | 0] | 0 | 0)) : 0) {
+    i2 = i2 + (i3 + -1 << 4) + 16 | 0;
+   } else {
+    i2 = 5192;
+   }
+  } else {
+   i2 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i2 = i2 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i2 : 5192;
+  }
+ } while (0);
+ if ((HEAP32[i2 + 8 >> 2] | 0) != 72) {
+  i5 = 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ i5 = HEAP32[i2 >> 2] | 0;
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _luaD_throw(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i3 = i1 + 64 | 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ if ((i4 | 0) != 0) {
+  HEAP32[i4 + 160 >> 2] = i2;
+  _longjmp((HEAP32[i3 >> 2] | 0) + 4 | 0, 1);
+ }
+ HEAP8[i1 + 6 | 0] = i2;
+ i4 = i1 + 12 | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ i5 = HEAP32[i3 + 172 >> 2] | 0;
+ if ((HEAP32[i5 + 64 >> 2] | 0) != 0) {
+  i6 = HEAP32[i1 + 8 >> 2] | 0;
+  i9 = i5 + 8 | 0;
+  i5 = HEAP32[i9 >> 2] | 0;
+  HEAP32[i9 >> 2] = i5 + 16;
+  i9 = i6 + -16 | 0;
+  i8 = HEAP32[i9 + 4 >> 2] | 0;
+  i7 = i5;
+  HEAP32[i7 >> 2] = HEAP32[i9 >> 2];
+  HEAP32[i7 + 4 >> 2] = i8;
+  HEAP32[i5 + 8 >> 2] = HEAP32[i6 + -8 >> 2];
+  _luaD_throw(HEAP32[(HEAP32[i4 >> 2] | 0) + 172 >> 2] | 0, i2);
+ }
+ i2 = HEAP32[i3 + 168 >> 2] | 0;
+ if ((i2 | 0) == 0) {
+  _abort();
+ }
+ FUNCTION_TABLE_ii[i2 & 255](i1) | 0;
+ _abort();
+}
+function _lua_len(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i5 = i1 + 8 | 0;
+ _luaV_objlen(i1, HEAP32[i5 >> 2] | 0, i3);
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 16;
+ STACKTOP = i2;
+ return;
+}
+function _read_line(i4, i5, i1) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 1040 | 0;
+ i2 = i3;
+ _luaL_buffinit(i4, i2);
+ i7 = _luaL_prepbuffsize(i2, 1024) | 0;
+ L1 : do {
+  if ((_fgets(i7 | 0, 1024, i5 | 0) | 0) != 0) {
+   i6 = i2 + 8 | 0;
+   while (1) {
+    i8 = _strlen(i7 | 0) | 0;
+    if ((i8 | 0) != 0 ? (HEAP8[i7 + (i8 + -1) | 0] | 0) == 10 : 0) {
+     break;
+    }
+    HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i8;
+    i7 = _luaL_prepbuffsize(i2, 1024) | 0;
+    if ((_fgets(i7 | 0, 1024, i5 | 0) | 0) == 0) {
+     break L1;
+    }
+   }
+   HEAP32[i6 >> 2] = i8 - i1 + (HEAP32[i6 >> 2] | 0);
+   _luaL_pushresult(i2);
+   i8 = 1;
+   STACKTOP = i3;
+   return i8 | 0;
+  }
+ } while (0);
+ _luaL_pushresult(i2);
+ i8 = (_lua_rawlen(i4, -1) | 0) != 0 | 0;
+ STACKTOP = i3;
+ return i8 | 0;
+}
+function _luaL_tolstring(i1, i5, i4) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ do {
+  if ((_luaL_callmeta(i1, i5, 1384) | 0) == 0) {
+   i6 = _lua_type(i1, i5) | 0;
+   if ((i6 | 0) == 0) {
+    _lua_pushlstring(i1, 1416, 3) | 0;
+    break;
+   } else if ((i6 | 0) == 1) {
+    i6 = (_lua_toboolean(i1, i5) | 0) != 0;
+    _lua_pushstring(i1, i6 ? 1400 : 1408) | 0;
+    break;
+   } else if ((i6 | 0) == 4 | (i6 | 0) == 3) {
+    _lua_pushvalue(i1, i5);
+    break;
+   } else {
+    i7 = _lua_typename(i1, _lua_type(i1, i5) | 0) | 0;
+    i6 = _lua_topointer(i1, i5) | 0;
+    HEAP32[i3 >> 2] = i7;
+    HEAP32[i3 + 4 >> 2] = i6;
+    _lua_pushfstring(i1, 1424, i3) | 0;
+    break;
+   }
+  }
+ } while (0);
+ i7 = _lua_tolstring(i1, -1, i4) | 0;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _save(i7, i1) {
+ i7 = i7 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i7 + 60 >> 2] | 0;
+ i3 = i4 + 4 | 0;
+ i8 = HEAP32[i3 >> 2] | 0;
+ i6 = i4 + 8 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ if (!((i8 + 1 | 0) >>> 0 > i5 >>> 0)) {
+  i6 = HEAP32[i4 >> 2] | 0;
+  i7 = i1 & 255;
+  i5 = i8 + 1 | 0;
+  HEAP32[i3 >> 2] = i5;
+  i8 = i6 + i8 | 0;
+  HEAP8[i8] = i7;
+  STACKTOP = i2;
+  return;
+ }
+ if (i5 >>> 0 > 2147483645) {
+  _lexerror(i7, 12368, 0);
+ }
+ i8 = i5 << 1;
+ i7 = HEAP32[i7 + 52 >> 2] | 0;
+ if ((i8 | 0) == -2) {
+  _luaM_toobig(i7);
+ }
+ i7 = _luaM_realloc_(i7, HEAP32[i4 >> 2] | 0, i5, i8) | 0;
+ HEAP32[i4 >> 2] = i7;
+ HEAP32[i6 >> 2] = i8;
+ i8 = HEAP32[i3 >> 2] | 0;
+ i6 = i7;
+ i7 = i1 & 255;
+ i5 = i8 + 1 | 0;
+ HEAP32[i3 >> 2] = i5;
+ i8 = i6 + i8 | 0;
+ HEAP8[i8] = i7;
+ STACKTOP = i2;
+ return;
+}
+function _luaK_patchtohere(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ HEAP32[i1 + 24 >> 2] = HEAP32[i1 + 20 >> 2];
+ i4 = i1 + 28 | 0;
+ if ((i3 | 0) == -1) {
+  STACKTOP = i2;
+  return;
+ }
+ i7 = HEAP32[i4 >> 2] | 0;
+ if ((i7 | 0) == -1) {
+  HEAP32[i4 >> 2] = i3;
+  STACKTOP = i2;
+  return;
+ }
+ i4 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+ while (1) {
+  i6 = i4 + (i7 << 2) | 0;
+  i5 = HEAP32[i6 >> 2] | 0;
+  i8 = (i5 >>> 14) + -131071 | 0;
+  if ((i8 | 0) == -1) {
+   break;
+  }
+  i8 = i7 + 1 + i8 | 0;
+  if ((i8 | 0) == -1) {
+   break;
+  } else {
+   i7 = i8;
+  }
+ }
+ i3 = ~i7 + i3 | 0;
+ if ((((i3 | 0) > -1 ? i3 : 0 - i3 | 0) | 0) > 131071) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+ }
+ HEAP32[i6 >> 2] = (i3 << 14) + 2147467264 | i5 & 16383;
+ STACKTOP = i2;
+ return;
+}
+function _tinsert(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i7 = i2;
+ _luaL_checktype(i1, 1, 5);
+ i4 = _luaL_len(i1, 1) | 0;
+ i3 = i4 + 1 | 0;
+ i6 = _lua_gettop(i1) | 0;
+ if ((i6 | 0) == 3) {
+  i5 = 2;
+ } else if ((i6 | 0) != 2) {
+  i7 = _luaL_error(i1, 8320, i7) | 0;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ if ((i5 | 0) == 2) {
+  i5 = _luaL_checkinteger(i1, 2) | 0;
+  if ((i5 | 0) < 1 | (i5 | 0) > (i3 | 0)) {
+   _luaL_argerror(i1, 2, 8256) | 0;
+  }
+  if ((i4 | 0) < (i5 | 0)) {
+   i3 = i5;
+  } else {
+   while (1) {
+    i4 = i3 + -1 | 0;
+    _lua_rawgeti(i1, 1, i4);
+    _lua_rawseti(i1, 1, i3);
+    if ((i4 | 0) > (i5 | 0)) {
+     i3 = i4;
+    } else {
+     i3 = i5;
+     break;
+    }
+   }
+  }
+ }
+ _lua_rawseti(i1, 1, i3);
+ i7 = 0;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _lua_iscfunction(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i3 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i2 = (HEAP32[i3 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i2 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i3 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i2 = HEAP32[i4 >> 2] | 0, (i3 | 0) <= (HEAPU8[i2 + 6 | 0] | 0 | 0)) : 0) {
+    i2 = i2 + (i3 + -1 << 4) + 16 | 0;
+   } else {
+    i2 = 5192;
+   }
+  } else {
+   i2 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i2 = i2 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i2 : 5192;
+  }
+ } while (0);
+ i5 = HEAP32[i2 + 8 >> 2] | 0;
+ STACKTOP = i1;
+ return ((i5 | 0) == 22 | (i5 | 0) == 102) & 1 | 0;
+}
+function _lua_gettable(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i5 = (HEAP32[i1 + 8 >> 2] | 0) + -16 | 0;
+ _luaV_gettable(i1, i3, i5, i5);
+ STACKTOP = i2;
+ return;
+}
+function _luaG_errormsg(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = HEAP32[i1 + 68 >> 2] | 0;
+ if ((i2 | 0) == 0) {
+  _luaD_throw(i1, 2);
+ }
+ i4 = HEAP32[i1 + 28 >> 2] | 0;
+ i3 = i4 + (i2 + 8) | 0;
+ if ((HEAP32[i3 >> 2] & 15 | 0) != 6) {
+  _luaD_throw(i1, 6);
+ }
+ i5 = i1 + 8 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ i9 = i6 + -16 | 0;
+ i8 = HEAP32[i9 + 4 >> 2] | 0;
+ i7 = i6;
+ HEAP32[i7 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i7 + 4 >> 2] = i8;
+ HEAP32[i6 + 8 >> 2] = HEAP32[i6 + -8 >> 2];
+ i6 = HEAP32[i5 >> 2] | 0;
+ i7 = i4 + i2 | 0;
+ i2 = HEAP32[i7 + 4 >> 2] | 0;
+ i4 = i6 + -16 | 0;
+ HEAP32[i4 >> 2] = HEAP32[i7 >> 2];
+ HEAP32[i4 + 4 >> 2] = i2;
+ HEAP32[i6 + -8 >> 2] = HEAP32[i3 >> 2];
+ i4 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i4 + 16;
+ _luaD_call(i1, i4 + -16 | 0, 1, 0);
+ _luaD_throw(i1, 2);
+}
+function _luaB_costatus(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i3 = i4;
+ i2 = _lua_tothread(i1, 1) | 0;
+ if ((i2 | 0) == 0) {
+  _luaL_argerror(i1, 1, 10856) | 0;
+ }
+ do {
+  if ((i2 | 0) != (i1 | 0)) {
+   i5 = _lua_status(i2) | 0;
+   if ((i5 | 0) == 0) {
+    if ((_lua_getstack(i2, 0, i3) | 0) > 0) {
+     _lua_pushlstring(i1, 10896, 6) | 0;
+     break;
+    }
+    if ((_lua_gettop(i2) | 0) == 0) {
+     _lua_pushlstring(i1, 10904, 4) | 0;
+     break;
+    } else {
+     _lua_pushlstring(i1, 10880, 9) | 0;
+     break;
+    }
+   } else if ((i5 | 0) == 1) {
+    _lua_pushlstring(i1, 10880, 9) | 0;
+    break;
+   } else {
+    _lua_pushlstring(i1, 10904, 4) | 0;
+    break;
+   }
+  } else {
+   _lua_pushlstring(i1, 10728, 7) | 0;
+  }
+ } while (0);
+ STACKTOP = i4;
+ return 1;
+}
+function _searcher_Lua(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i4 = _luaL_checklstring(i1, 1, 0) | 0;
+ _lua_getfield(i1, -1001001, 4256);
+ i5 = _lua_tolstring(i1, -1, 0) | 0;
+ if ((i5 | 0) == 0) {
+  HEAP32[i3 >> 2] = 4256;
+  _luaL_error(i1, 5032, i3) | 0;
+ }
+ i4 = _searchpath(i1, i4, i5, 4936, 4848) | 0;
+ if ((i4 | 0) == 0) {
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ if ((_luaL_loadfilex(i1, i4, 0) | 0) == 0) {
+  _lua_pushstring(i1, i4) | 0;
+  i5 = 2;
+  STACKTOP = i2;
+  return i5 | 0;
+ } else {
+  i6 = _lua_tolstring(i1, 1, 0) | 0;
+  i5 = _lua_tolstring(i1, -1, 0) | 0;
+  HEAP32[i3 >> 2] = i6;
+  HEAP32[i3 + 4 >> 2] = i4;
+  HEAP32[i3 + 8 >> 2] = i5;
+  i5 = _luaL_error(i1, 4888, i3) | 0;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _str_sub(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i3;
+ i2 = _luaL_checklstring(i1, 1, i4) | 0;
+ i5 = _luaL_checkinteger(i1, 2) | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ if (!((i5 | 0) > -1)) {
+  if (i6 >>> 0 < (0 - i5 | 0) >>> 0) {
+   i5 = 0;
+  } else {
+   i5 = i5 + 1 + i6 | 0;
+  }
+ }
+ i6 = _luaL_optinteger(i1, 3, -1) | 0;
+ i4 = HEAP32[i4 >> 2] | 0;
+ if (!((i6 | 0) > -1)) {
+  if (i4 >>> 0 < (0 - i6 | 0) >>> 0) {
+   i6 = 0;
+  } else {
+   i6 = i6 + 1 + i4 | 0;
+  }
+ }
+ i5 = (i5 | 0) == 0 ? 1 : i5;
+ i4 = i6 >>> 0 > i4 >>> 0 ? i4 : i6;
+ if (i5 >>> 0 > i4 >>> 0) {
+  _lua_pushlstring(i1, 7040, 0) | 0;
+  STACKTOP = i3;
+  return 1;
+ } else {
+  _lua_pushlstring(i1, i2 + (i5 + -1) | 0, 1 - i5 + i4 | 0) | 0;
+  STACKTOP = i3;
+  return 1;
+ }
+ return 0;
+}
+function _searcher_C(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i4 = _luaL_checklstring(i1, 1, 0) | 0;
+ _lua_getfield(i1, -1001001, 4440);
+ i5 = _lua_tolstring(i1, -1, 0) | 0;
+ if ((i5 | 0) == 0) {
+  HEAP32[i3 >> 2] = 4440;
+  _luaL_error(i1, 5032, i3) | 0;
+ }
+ i5 = _searchpath(i1, i4, i5, 4936, 4848) | 0;
+ if ((i5 | 0) == 0) {
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ if ((_loadfunc(i1, i5, i4) | 0) == 0) {
+  _lua_pushstring(i1, i5) | 0;
+  i5 = 2;
+  STACKTOP = i2;
+  return i5 | 0;
+ } else {
+  i6 = _lua_tolstring(i1, 1, 0) | 0;
+  i4 = _lua_tolstring(i1, -1, 0) | 0;
+  HEAP32[i3 >> 2] = i6;
+  HEAP32[i3 + 4 >> 2] = i5;
+  HEAP32[i3 + 8 >> 2] = i4;
+  i5 = _luaL_error(i1, 4888, i3) | 0;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _io_open(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i5 = STACKTOP;
+ i2 = _luaL_checklstring(i1, 1, 0) | 0;
+ i3 = _luaL_optlstring(i1, 2, 3480, 0) | 0;
+ i4 = _lua_newuserdata(i1, 8) | 0;
+ i6 = i4 + 4 | 0;
+ HEAP32[i6 >> 2] = 0;
+ _luaL_setmetatable(i1, 2832);
+ HEAP32[i4 >> 2] = 0;
+ HEAP32[i6 >> 2] = 156;
+ i6 = HEAP8[i3] | 0;
+ if (!((!(i6 << 24 >> 24 == 0) ? (i7 = i3 + 1 | 0, (_memchr(3552, i6 << 24 >> 24, 4) | 0) != 0) : 0) ? (i6 = (HEAP8[i7] | 0) == 43 ? i3 + 2 | 0 : i7, (HEAP8[(HEAP8[i6] | 0) == 98 ? i6 + 1 | 0 : i6] | 0) == 0) : 0)) {
+  _luaL_argerror(i1, 2, 3560) | 0;
+ }
+ i7 = _fopen(i2 | 0, i3 | 0) | 0;
+ HEAP32[i4 >> 2] = i7;
+ if ((i7 | 0) != 0) {
+  i7 = 1;
+  STACKTOP = i5;
+  return i7 | 0;
+ }
+ i7 = _luaL_fileresult(i1, 0, i2) | 0;
+ STACKTOP = i5;
+ return i7 | 0;
+}
+function _unpack(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i6 = i1;
+ _luaL_checktype(i2, 1, 5);
+ i5 = _luaL_optinteger(i2, 2, 1) | 0;
+ if ((_lua_type(i2, 3) | 0) < 1) {
+  i3 = _luaL_len(i2, 1) | 0;
+ } else {
+  i3 = _luaL_checkinteger(i2, 3) | 0;
+ }
+ if ((i5 | 0) > (i3 | 0)) {
+  i6 = 0;
+  STACKTOP = i1;
+  return i6 | 0;
+ }
+ i7 = i3 - i5 | 0;
+ i4 = i7 + 1 | 0;
+ if ((i7 | 0) >= 0 ? (_lua_checkstack(i2, i4) | 0) != 0 : 0) {
+  _lua_rawgeti(i2, 1, i5);
+  if ((i5 | 0) >= (i3 | 0)) {
+   i7 = i4;
+   STACKTOP = i1;
+   return i7 | 0;
+  }
+  do {
+   i5 = i5 + 1 | 0;
+   _lua_rawgeti(i2, 1, i5);
+  } while ((i5 | 0) != (i3 | 0));
+  STACKTOP = i1;
+  return i4 | 0;
+ }
+ i7 = _luaL_error(i2, 8280, i6) | 0;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _luaF_getlocalname(i4, i6, i2) {
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i5 = 0;
+ i1 = STACKTOP;
+ i3 = HEAP32[i4 + 60 >> 2] | 0;
+ if ((i3 | 0) <= 0) {
+  i6 = 0;
+  STACKTOP = i1;
+  return i6 | 0;
+ }
+ i4 = HEAP32[i4 + 24 >> 2] | 0;
+ i5 = 0;
+ while (1) {
+  if ((HEAP32[i4 + (i5 * 12 | 0) + 4 >> 2] | 0) > (i2 | 0)) {
+   i3 = 0;
+   i2 = 8;
+   break;
+  }
+  if ((HEAP32[i4 + (i5 * 12 | 0) + 8 >> 2] | 0) > (i2 | 0)) {
+   i6 = i6 + -1 | 0;
+   if ((i6 | 0) == 0) {
+    i2 = 6;
+    break;
+   }
+  }
+  i5 = i5 + 1 | 0;
+  if ((i5 | 0) >= (i3 | 0)) {
+   i3 = 0;
+   i2 = 8;
+   break;
+  }
+ }
+ if ((i2 | 0) == 6) {
+  i6 = (HEAP32[i4 + (i5 * 12 | 0) >> 2] | 0) + 16 | 0;
+  STACKTOP = i1;
+  return i6 | 0;
+ } else if ((i2 | 0) == 8) {
+  STACKTOP = i1;
+  return i3 | 0;
+ }
+ return 0;
+}
+function _luaK_concat(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ if ((i3 | 0) == -1) {
+  STACKTOP = i2;
+  return;
+ }
+ i7 = HEAP32[i4 >> 2] | 0;
+ if ((i7 | 0) == -1) {
+  HEAP32[i4 >> 2] = i3;
+  STACKTOP = i2;
+  return;
+ }
+ i4 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+ while (1) {
+  i6 = i4 + (i7 << 2) | 0;
+  i5 = HEAP32[i6 >> 2] | 0;
+  i8 = (i5 >>> 14) + -131071 | 0;
+  if ((i8 | 0) == -1) {
+   break;
+  }
+  i8 = i7 + 1 + i8 | 0;
+  if ((i8 | 0) == -1) {
+   break;
+  } else {
+   i7 = i8;
+  }
+ }
+ i3 = ~i7 + i3 | 0;
+ if ((((i3 | 0) > -1 ? i3 : 0 - i3 | 0) | 0) > 131071) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+ }
+ HEAP32[i6 >> 2] = i5 & 16383 | (i3 << 14) + 2147467264;
+ STACKTOP = i2;
+ return;
+}
+function _scalbn(d3, i2) {
+ d3 = +d3;
+ i2 = i2 | 0;
+ var i1 = 0, i4 = 0;
+ i1 = STACKTOP;
+ if ((i2 | 0) > 1023) {
+  d3 = d3 * 8.98846567431158e+307;
+  i4 = i2 + -1023 | 0;
+  if ((i4 | 0) > 1023) {
+   i2 = i2 + -2046 | 0;
+   i2 = (i2 | 0) > 1023 ? 1023 : i2;
+   d3 = d3 * 8.98846567431158e+307;
+  } else {
+   i2 = i4;
+  }
+ } else {
+  if ((i2 | 0) < -1022) {
+   d3 = d3 * 2.2250738585072014e-308;
+   i4 = i2 + 1022 | 0;
+   if ((i4 | 0) < -1022) {
+    i2 = i2 + 2044 | 0;
+    i2 = (i2 | 0) < -1022 ? -1022 : i2;
+    d3 = d3 * 2.2250738585072014e-308;
+   } else {
+    i2 = i4;
+   }
+  }
+ }
+ i2 = _bitshift64Shl(i2 + 1023 | 0, 0, 52) | 0;
+ i4 = tempRet0;
+ HEAP32[tempDoublePtr >> 2] = i2;
+ HEAP32[tempDoublePtr + 4 >> 2] = i4;
+ d3 = d3 * +HEAPF64[tempDoublePtr >> 3];
+ STACKTOP = i1;
+ return +d3;
+}
+function _luaK_numberK(i1, d6) {
+ i1 = i1 | 0;
+ d6 = +d6;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i4 = i2 + 16 | 0;
+ i3 = i2;
+ HEAPF64[i4 >> 3] = d6;
+ i5 = HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 52 >> 2] | 0;
+ HEAPF64[i3 >> 3] = d6;
+ HEAP32[i3 + 8 >> 2] = 3;
+ if (d6 != d6 | 0.0 != 0.0 | d6 == 0.0) {
+  i7 = i5 + 8 | 0;
+  i8 = HEAP32[i7 >> 2] | 0;
+  HEAP32[i7 >> 2] = i8 + 16;
+  i5 = _luaS_newlstr(i5, i4, 8) | 0;
+  HEAP32[i8 >> 2] = i5;
+  HEAP32[i8 + 8 >> 2] = HEAPU8[i5 + 4 | 0] | 0 | 64;
+  i5 = _addk(i1, (HEAP32[i7 >> 2] | 0) + -16 | 0, i3) | 0;
+  HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + -16;
+  STACKTOP = i2;
+  return i5 | 0;
+ } else {
+  i8 = _addk(i1, i3, i3) | 0;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ return 0;
+}
+function _auxresume(i2, i3, i4) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i1 = 0;
+ i1 = STACKTOP;
+ do {
+  if ((_lua_checkstack(i3, i4) | 0) != 0) {
+   if ((_lua_status(i3) | 0) == 0 ? (_lua_gettop(i3) | 0) == 0 : 0) {
+    _lua_pushlstring(i2, 10792, 28) | 0;
+    i4 = -1;
+    break;
+   }
+   _lua_xmove(i2, i3, i4);
+   if (!((_lua_resume(i3, i2, i4) | 0) >>> 0 < 2)) {
+    _lua_xmove(i3, i2, 1);
+    i4 = -1;
+    break;
+   }
+   i4 = _lua_gettop(i3) | 0;
+   if ((_lua_checkstack(i2, i4 + 1 | 0) | 0) == 0) {
+    _lua_settop(i3, ~i4);
+    _lua_pushlstring(i2, 10824, 26) | 0;
+    i4 = -1;
+    break;
+   } else {
+    _lua_xmove(i3, i2, i4);
+    break;
+   }
+  } else {
+   _lua_pushlstring(i2, 10760, 28) | 0;
+   i4 = -1;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _luaX_setinput(i2, i1, i4, i3, i5) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i6 = 0, i7 = 0;
+ i6 = STACKTOP;
+ HEAP8[i1 + 76 | 0] = 46;
+ i7 = i1 + 52 | 0;
+ HEAP32[i7 >> 2] = i2;
+ HEAP32[i1 >> 2] = i5;
+ HEAP32[i1 + 32 >> 2] = 286;
+ HEAP32[i1 + 56 >> 2] = i4;
+ HEAP32[i1 + 48 >> 2] = 0;
+ HEAP32[i1 + 4 >> 2] = 1;
+ HEAP32[i1 + 8 >> 2] = 1;
+ HEAP32[i1 + 68 >> 2] = i3;
+ i5 = _luaS_new(i2, 12264) | 0;
+ HEAP32[i1 + 72 >> 2] = i5;
+ i5 = i5 + 5 | 0;
+ HEAP8[i5] = HEAPU8[i5] | 0 | 32;
+ i5 = i1 + 60 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ i4 = _luaM_realloc_(HEAP32[i7 >> 2] | 0, HEAP32[i4 >> 2] | 0, HEAP32[i4 + 8 >> 2] | 0, 32) | 0;
+ HEAP32[HEAP32[i5 >> 2] >> 2] = i4;
+ HEAP32[(HEAP32[i5 >> 2] | 0) + 8 >> 2] = 32;
+ STACKTOP = i6;
+ return;
+}
+function _luaL_optlstring(i2, i4, i6, i5) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ if ((_lua_type(i2, i4) | 0) >= 1) {
+  i5 = _lua_tolstring(i2, i4, i5) | 0;
+  if ((i5 | 0) != 0) {
+   i6 = i5;
+   STACKTOP = i1;
+   return i6 | 0;
+  }
+  i5 = _lua_typename(i2, 4) | 0;
+  i6 = _lua_typename(i2, _lua_type(i2, i4) | 0) | 0;
+  HEAP32[i3 >> 2] = i5;
+  HEAP32[i3 + 4 >> 2] = i6;
+  _luaL_argerror(i2, i4, _lua_pushfstring(i2, 1744, i3) | 0) | 0;
+  i6 = 0;
+  STACKTOP = i1;
+  return i6 | 0;
+ }
+ if ((i5 | 0) == 0) {
+  STACKTOP = i1;
+  return i6 | 0;
+ }
+ if ((i6 | 0) == 0) {
+  i2 = 0;
+ } else {
+  i2 = _strlen(i6 | 0) | 0;
+ }
+ HEAP32[i5 >> 2] = i2;
+ STACKTOP = i1;
+ return i6 | 0;
+}
+function _lua_xmove(i3, i4, i1) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i2 = STACKTOP;
+ if ((i3 | 0) == (i4 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = i3 + 8 | 0;
+ i5 = (HEAP32[i3 >> 2] | 0) + (0 - i1 << 4) | 0;
+ HEAP32[i3 >> 2] = i5;
+ if ((i1 | 0) <= 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i4 = i4 + 8 | 0;
+ i6 = 0;
+ while (1) {
+  i7 = HEAP32[i4 >> 2] | 0;
+  HEAP32[i4 >> 2] = i7 + 16;
+  i10 = i5 + (i6 << 4) | 0;
+  i9 = HEAP32[i10 + 4 >> 2] | 0;
+  i8 = i7;
+  HEAP32[i8 >> 2] = HEAP32[i10 >> 2];
+  HEAP32[i8 + 4 >> 2] = i9;
+  HEAP32[i7 + 8 >> 2] = HEAP32[i5 + (i6 << 4) + 8 >> 2];
+  i6 = i6 + 1 | 0;
+  if ((i6 | 0) == (i1 | 0)) {
+   break;
+  }
+  i5 = HEAP32[i3 >> 2] | 0;
+ }
+ STACKTOP = i2;
+ return;
+}
+function _luaM_realloc_(i7, i10, i3, i2) {
+ i7 = i7 | 0;
+ i10 = i10 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0;
+ i5 = STACKTOP;
+ i6 = HEAP32[i7 + 12 >> 2] | 0;
+ i4 = (i10 | 0) != 0;
+ i9 = i6 + 4 | 0;
+ i8 = FUNCTION_TABLE_iiiii[HEAP32[i6 >> 2] & 3](HEAP32[i9 >> 2] | 0, i10, i3, i2) | 0;
+ if (!((i8 | 0) != 0 | (i2 | 0) == 0)) {
+  if ((HEAP8[i6 + 63 | 0] | 0) == 0) {
+   _luaD_throw(i7, 4);
+  }
+  _luaC_fullgc(i7, 1);
+  i8 = FUNCTION_TABLE_iiiii[HEAP32[i6 >> 2] & 3](HEAP32[i9 >> 2] | 0, i10, i3, i2) | 0;
+  if ((i8 | 0) == 0) {
+   _luaD_throw(i7, 4);
+  } else {
+   i1 = i8;
+  }
+ } else {
+  i1 = i8;
+ }
+ i6 = i6 + 12 | 0;
+ HEAP32[i6 >> 2] = (i4 ? 0 - i3 | 0 : 0) + i2 + (HEAP32[i6 >> 2] | 0);
+ STACKTOP = i5;
+ return i1 | 0;
+}
+function _realloc(i2, i3) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i5 = 0;
+ i1 = STACKTOP;
+ do {
+  if ((i2 | 0) != 0) {
+   if (i3 >>> 0 > 4294967231) {
+    HEAP32[(___errno_location() | 0) >> 2] = 12;
+    i4 = 0;
+    break;
+   }
+   if (i3 >>> 0 < 11) {
+    i4 = 16;
+   } else {
+    i4 = i3 + 11 & -8;
+   }
+   i4 = _try_realloc_chunk(i2 + -8 | 0, i4) | 0;
+   if ((i4 | 0) != 0) {
+    i4 = i4 + 8 | 0;
+    break;
+   }
+   i4 = _malloc(i3) | 0;
+   if ((i4 | 0) == 0) {
+    i4 = 0;
+   } else {
+    i5 = HEAP32[i2 + -4 >> 2] | 0;
+    i5 = (i5 & -8) - ((i5 & 3 | 0) == 0 ? 8 : 4) | 0;
+    _memcpy(i4 | 0, i2 | 0, (i5 >>> 0 < i3 >>> 0 ? i5 : i3) | 0) | 0;
+    _free(i2);
+   }
+  } else {
+   i4 = _malloc(i3) | 0;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _lua_setlocal(i3, i5, i4) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ HEAP32[i2 >> 2] = 0;
+ i4 = _findlocal(i3, HEAP32[i5 + 96 >> 2] | 0, i4, i2) | 0;
+ i3 = i3 + 8 | 0;
+ if ((i4 | 0) == 0) {
+  i5 = HEAP32[i3 >> 2] | 0;
+  i5 = i5 + -16 | 0;
+  HEAP32[i3 >> 2] = i5;
+  STACKTOP = i1;
+  return i4 | 0;
+ }
+ i6 = HEAP32[i3 >> 2] | 0;
+ i5 = HEAP32[i2 >> 2] | 0;
+ i8 = i6 + -16 | 0;
+ i7 = HEAP32[i8 + 4 >> 2] | 0;
+ i2 = i5;
+ HEAP32[i2 >> 2] = HEAP32[i8 >> 2];
+ HEAP32[i2 + 4 >> 2] = i7;
+ HEAP32[i5 + 8 >> 2] = HEAP32[i6 + -8 >> 2];
+ i5 = HEAP32[i3 >> 2] | 0;
+ i5 = i5 + -16 | 0;
+ HEAP32[i3 >> 2] = i5;
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function ___remdi3(i1, i4, i5, i6) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 8 | 0;
+ i2 = i3 | 0;
+ i7 = i4 >> 31 | ((i4 | 0) < 0 ? -1 : 0) << 1;
+ i8 = ((i4 | 0) < 0 ? -1 : 0) >> 31 | ((i4 | 0) < 0 ? -1 : 0) << 1;
+ i9 = i6 >> 31 | ((i6 | 0) < 0 ? -1 : 0) << 1;
+ i10 = ((i6 | 0) < 0 ? -1 : 0) >> 31 | ((i6 | 0) < 0 ? -1 : 0) << 1;
+ i1 = _i64Subtract(i7 ^ i1, i8 ^ i4, i7, i8) | 0;
+ i4 = tempRet0;
+ ___udivmoddi4(i1, i4, _i64Subtract(i9 ^ i5, i10 ^ i6, i9, i10) | 0, tempRet0, i2) | 0;
+ i9 = _i64Subtract(HEAP32[i2 >> 2] ^ i7, HEAP32[i2 + 4 >> 2] ^ i8, i7, i8) | 0;
+ i8 = tempRet0;
+ STACKTOP = i3;
+ return (tempRet0 = i8, i9) | 0;
+}
+function _luaC_barrierproto_(i3, i4, i2) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i5 = 0;
+ i1 = STACKTOP;
+ if ((HEAP32[i4 + 32 >> 2] | 0) != 0) {
+  i5 = HEAP32[i3 + 12 >> 2] | 0;
+  i3 = i4 + 5 | 0;
+  HEAP8[i3] = HEAP8[i3] & 251;
+  i5 = i5 + 88 | 0;
+  HEAP32[i4 + 72 >> 2] = HEAP32[i5 >> 2];
+  HEAP32[i5 >> 2] = i4;
+  STACKTOP = i1;
+  return;
+ }
+ if ((HEAP8[i2 + 5 | 0] & 3) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i5 = i4 + 5 | 0;
+ i4 = HEAP8[i5] | 0;
+ if ((i4 & 4) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i3 = HEAP32[i3 + 12 >> 2] | 0;
+ if ((HEAPU8[i3 + 61 | 0] | 0) < 2) {
+  _reallymarkobject(i3, i2);
+  STACKTOP = i1;
+  return;
+ } else {
+  HEAP8[i5] = HEAP8[i3 + 60 | 0] & 3 | i4 & 184;
+  STACKTOP = i1;
+  return;
+ }
+}
+function _luaL_openlibs(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_requiref(i1, 2592, 144, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2600, 145, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2608, 146, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2624, 147, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2632, 148, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2640, 149, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2648, 150, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2656, 151, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2664, 152, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2672, 153, 1);
+ _lua_settop(i1, -2);
+ _luaL_getsubtable(i1, -1001e3, 2576) | 0;
+ _lua_settop(i1, -2);
+ STACKTOP = i2;
+ return;
+}
+function _luaX_token2str(i4, i3) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i5 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ if ((i3 | 0) >= 257) {
+  i5 = HEAP32[12096 + (i3 + -257 << 2) >> 2] | 0;
+  if ((i3 | 0) >= 286) {
+   STACKTOP = i1;
+   return i5 | 0;
+  }
+  i4 = HEAP32[i4 + 52 >> 2] | 0;
+  HEAP32[i2 >> 2] = i5;
+  i5 = _luaO_pushfstring(i4, 12256, i2) | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ i4 = HEAP32[i4 + 52 >> 2] | 0;
+ if ((HEAP8[i3 + 10913 | 0] & 4) == 0) {
+  HEAP32[i2 >> 2] = i3;
+  i5 = _luaO_pushfstring(i4, 12240, i2) | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ } else {
+  HEAP32[i2 >> 2] = i3;
+  i5 = _luaO_pushfstring(i4, 12232, i2) | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _luaL_buffinitsize(i6, i1, i7) {
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i8 = 0;
+ i2 = STACKTOP;
+ HEAP32[i1 + 12 >> 2] = i6;
+ i3 = i1 + 16 | 0;
+ HEAP32[i1 >> 2] = i3;
+ i5 = i1 + 8 | 0;
+ HEAP32[i5 >> 2] = 0;
+ i4 = i1 + 4 | 0;
+ HEAP32[i4 >> 2] = 1024;
+ if (!(i7 >>> 0 > 1024)) {
+  i7 = i3;
+  i8 = 0;
+  i8 = i7 + i8 | 0;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ i8 = i7 >>> 0 > 2048 ? i7 : 2048;
+ i7 = _lua_newuserdata(i6, i8) | 0;
+ _memcpy(i7 | 0, HEAP32[i1 >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0;
+ if ((HEAP32[i1 >> 2] | 0) != (i3 | 0)) {
+  _lua_remove(i6, -2);
+ }
+ HEAP32[i1 >> 2] = i7;
+ HEAP32[i4 >> 2] = i8;
+ i8 = HEAP32[i5 >> 2] | 0;
+ i8 = i7 + i8 | 0;
+ STACKTOP = i2;
+ return i8 | 0;
+}
+function _luaE_freethread(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ i4 = i3 + 28 | 0;
+ _luaF_close(i3, HEAP32[i4 >> 2] | 0);
+ i5 = HEAP32[i4 >> 2] | 0;
+ if ((i5 | 0) == 0) {
+  _luaM_realloc_(i1, i3, 112, 0) | 0;
+  STACKTOP = i2;
+  return;
+ }
+ HEAP32[i3 + 16 >> 2] = i3 + 72;
+ i7 = i3 + 84 | 0;
+ i6 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = 0;
+ if ((i6 | 0) != 0) {
+  while (1) {
+   i5 = HEAP32[i6 + 12 >> 2] | 0;
+   _luaM_realloc_(i3, i6, 40, 0) | 0;
+   if ((i5 | 0) == 0) {
+    break;
+   } else {
+    i6 = i5;
+   }
+  }
+  i5 = HEAP32[i4 >> 2] | 0;
+ }
+ _luaM_realloc_(i3, i5, HEAP32[i3 + 32 >> 2] << 4, 0) | 0;
+ _luaM_realloc_(i1, i3, 112, 0) | 0;
+ STACKTOP = i2;
+ return;
+}
+function ___toread(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i3 = STACKTOP;
+ i4 = i1 + 74 | 0;
+ i2 = HEAP8[i4] | 0;
+ HEAP8[i4] = i2 + 255 | i2;
+ i4 = i1 + 20 | 0;
+ i2 = i1 + 44 | 0;
+ if ((HEAP32[i4 >> 2] | 0) >>> 0 > (HEAP32[i2 >> 2] | 0) >>> 0) {
+  FUNCTION_TABLE_iiii[HEAP32[i1 + 36 >> 2] & 3](i1, 0, 0) | 0;
+ }
+ HEAP32[i1 + 16 >> 2] = 0;
+ HEAP32[i1 + 28 >> 2] = 0;
+ HEAP32[i4 >> 2] = 0;
+ i4 = HEAP32[i1 >> 2] | 0;
+ if ((i4 & 20 | 0) == 0) {
+  i4 = HEAP32[i2 >> 2] | 0;
+  HEAP32[i1 + 8 >> 2] = i4;
+  HEAP32[i1 + 4 >> 2] = i4;
+  i4 = 0;
+  STACKTOP = i3;
+  return i4 | 0;
+ }
+ if ((i4 & 4 | 0) == 0) {
+  i4 = -1;
+  STACKTOP = i3;
+  return i4 | 0;
+ }
+ HEAP32[i1 >> 2] = i4 | 32;
+ i4 = -1;
+ STACKTOP = i3;
+ return i4 | 0;
+}
+function _lua_callk(i3, i7, i4, i6, i5) {
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i8 = 0;
+ i1 = STACKTOP;
+ i2 = i3 + 8 | 0;
+ i7 = (HEAP32[i2 >> 2] | 0) + (~i7 << 4) | 0;
+ if ((i5 | 0) != 0 ? (HEAP16[i3 + 36 >> 1] | 0) == 0 : 0) {
+  i8 = i3 + 16 | 0;
+  HEAP32[(HEAP32[i8 >> 2] | 0) + 28 >> 2] = i5;
+  HEAP32[(HEAP32[i8 >> 2] | 0) + 24 >> 2] = i6;
+  _luaD_call(i3, i7, i4, 1);
+ } else {
+  _luaD_call(i3, i7, i4, 0);
+ }
+ if (!((i4 | 0) == -1)) {
+  STACKTOP = i1;
+  return;
+ }
+ i3 = (HEAP32[i3 + 16 >> 2] | 0) + 4 | 0;
+ i2 = HEAP32[i2 >> 2] | 0;
+ if (!((HEAP32[i3 >> 2] | 0) >>> 0 < i2 >>> 0)) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP32[i3 >> 2] = i2;
+ STACKTOP = i1;
+ return;
+}
+function _luaX_newstring(i3, i5, i4) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i6 = 0;
+ i1 = STACKTOP;
+ i2 = HEAP32[i3 + 52 >> 2] | 0;
+ i5 = _luaS_newlstr(i2, i5, i4) | 0;
+ i4 = i2 + 8 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i4 >> 2] = i6 + 16;
+ HEAP32[i6 >> 2] = i5;
+ HEAP32[i6 + 8 >> 2] = HEAPU8[i5 + 4 | 0] | 0 | 64;
+ i6 = _luaH_set(i2, HEAP32[(HEAP32[i3 + 48 >> 2] | 0) + 4 >> 2] | 0, (HEAP32[i4 >> 2] | 0) + -16 | 0) | 0;
+ i3 = i6 + 8 | 0;
+ if ((HEAP32[i3 >> 2] | 0) == 0 ? (HEAP32[i6 >> 2] = 1, HEAP32[i3 >> 2] = 1, (HEAP32[(HEAP32[i2 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) : 0) {
+  _luaC_step(i2);
+ }
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + -16;
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _strtod(i3, i2) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i4 = 0, d5 = 0.0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i4 = i1;
+ i7 = i4 + 0 | 0;
+ i6 = i7 + 112 | 0;
+ do {
+  HEAP32[i7 >> 2] = 0;
+  i7 = i7 + 4 | 0;
+ } while ((i7 | 0) < (i6 | 0));
+ i6 = i4 + 4 | 0;
+ HEAP32[i6 >> 2] = i3;
+ i7 = i4 + 8 | 0;
+ HEAP32[i7 >> 2] = -1;
+ HEAP32[i4 + 44 >> 2] = i3;
+ HEAP32[i4 + 76 >> 2] = -1;
+ ___shlim(i4, 0);
+ d5 = +___floatscan(i4, 1, 1);
+ i4 = (HEAP32[i6 >> 2] | 0) - (HEAP32[i7 >> 2] | 0) + (HEAP32[i4 + 108 >> 2] | 0) | 0;
+ if ((i2 | 0) == 0) {
+  STACKTOP = i1;
+  return +d5;
+ }
+ if ((i4 | 0) != 0) {
+  i3 = i3 + i4 | 0;
+ }
+ HEAP32[i2 >> 2] = i3;
+ STACKTOP = i1;
+ return +d5;
+}
+function _f_seek(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, d6 = 0.0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _luaL_checkudata(i1, 1, 2832) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 3080, i2) | 0;
+ }
+ i3 = HEAP32[i3 >> 2] | 0;
+ i5 = _luaL_checkoption(i1, 2, 3208, 3184) | 0;
+ d6 = +_luaL_optnumber(i1, 3, 0.0);
+ i4 = ~~d6;
+ if (!(+(i4 | 0) == d6)) {
+  _luaL_argerror(i1, 3, 3224) | 0;
+ }
+ if ((_fseek(i3 | 0, i4 | 0, HEAP32[3168 + (i5 << 2) >> 2] | 0) | 0) == 0) {
+  _lua_pushnumber(i1, +(_ftell(i3 | 0) | 0));
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ } else {
+  i5 = _luaL_fileresult(i1, 0, 0) | 0;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _setpath(i1, i4, i8, i7, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i8 = i8 | 0;
+ i7 = i7 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ i8 = _getenv(i8 | 0) | 0;
+ if ((i8 | 0) == 0) {
+  i7 = _getenv(i7 | 0) | 0;
+  if ((i7 | 0) != 0) {
+   i5 = i7;
+   i6 = 3;
+  }
+ } else {
+  i5 = i8;
+  i6 = 3;
+ }
+ if ((i6 | 0) == 3 ? (_lua_getfield(i1, -1001e3, 4832), i8 = _lua_toboolean(i1, -1) | 0, _lua_settop(i1, -2), (i8 | 0) == 0) : 0) {
+  _luaL_gsub(i1, _luaL_gsub(i1, i5, 4808, 4816) | 0, 4824, i3) | 0;
+  _lua_remove(i1, -2);
+  _lua_setfield(i1, -2, i4);
+  STACKTOP = i2;
+  return;
+ }
+ _lua_pushstring(i1, i3) | 0;
+ _lua_setfield(i1, -2, i4);
+ STACKTOP = i2;
+ return;
+}
+function _luaU_header(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ HEAP8[i1] = 1635077147;
+ HEAP8[i1 + 1 | 0] = 6387020;
+ HEAP8[i1 + 2 | 0] = 24949;
+ HEAP8[i1 + 3 | 0] = 97;
+ HEAP8[i1 + 4 | 0] = 82;
+ HEAP8[i1 + 5 | 0] = 0;
+ HEAP8[i1 + 6 | 0] = 1;
+ HEAP8[i1 + 7 | 0] = 4;
+ HEAP8[i1 + 8 | 0] = 4;
+ HEAP8[i1 + 9 | 0] = 4;
+ HEAP8[i1 + 10 | 0] = 8;
+ i3 = i1 + 12 | 0;
+ HEAP8[i1 + 11 | 0] = 0;
+ HEAP8[i3 + 0 | 0] = HEAP8[8816 | 0] | 0;
+ HEAP8[i3 + 1 | 0] = HEAP8[8817 | 0] | 0;
+ HEAP8[i3 + 2 | 0] = HEAP8[8818 | 0] | 0;
+ HEAP8[i3 + 3 | 0] = HEAP8[8819 | 0] | 0;
+ HEAP8[i3 + 4 | 0] = HEAP8[8820 | 0] | 0;
+ HEAP8[i3 + 5 | 0] = HEAP8[8821 | 0] | 0;
+ STACKTOP = i2;
+ return;
+}
+function _db_setlocal(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i3 = i2;
+ if ((_lua_type(i1, 1) | 0) == 8) {
+  i5 = _lua_tothread(i1, 1) | 0;
+  i4 = 1;
+ } else {
+  i5 = i1;
+  i4 = 0;
+ }
+ i6 = i4 + 1 | 0;
+ if ((_lua_getstack(i5, _luaL_checkinteger(i1, i6) | 0, i3) | 0) == 0) {
+  i6 = _luaL_argerror(i1, i6, 11560) | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ } else {
+  i6 = i4 + 3 | 0;
+  _luaL_checkany(i1, i6);
+  _lua_settop(i1, i6);
+  _lua_xmove(i1, i5, 1);
+  _lua_pushstring(i1, _lua_setlocal(i5, i3, _luaL_checkinteger(i1, i4 | 2) | 0) | 0) | 0;
+  i6 = 1;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ return 0;
+}
+function _tremove(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 5);
+ i3 = _luaL_len(i1, 1) | 0;
+ i4 = _luaL_optinteger(i1, 2, i3) | 0;
+ if ((i4 | 0) != (i3 | 0) ? (i4 | 0) < 1 | (i4 | 0) > (i3 + 1 | 0) : 0) {
+  _luaL_argerror(i1, 1, 8256) | 0;
+ }
+ _lua_rawgeti(i1, 1, i4);
+ if ((i4 | 0) >= (i3 | 0)) {
+  i5 = i4;
+  _lua_pushnil(i1);
+  _lua_rawseti(i1, 1, i5);
+  STACKTOP = i2;
+  return 1;
+ }
+ while (1) {
+  i5 = i4 + 1 | 0;
+  _lua_rawgeti(i1, 1, i5);
+  _lua_rawseti(i1, 1, i4);
+  if ((i5 | 0) == (i3 | 0)) {
+   break;
+  } else {
+   i4 = i5;
+  }
+ }
+ _lua_pushnil(i1);
+ _lua_rawseti(i1, 1, i3);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaL_checkudata(i1, i7, i5) {
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i3 = _lua_touserdata(i1, i7) | 0;
+ if (((i3 | 0) != 0 ? (_lua_getmetatable(i1, i7) | 0) != 0 : 0) ? (_lua_getfield(i1, -1001e3, i5), i6 = (_lua_rawequal(i1, -1, -2) | 0) == 0, i6 = i6 ? 0 : i3, _lua_settop(i1, -3), (i6 | 0) != 0) : 0) {
+  i7 = i6;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ i6 = _lua_typename(i1, _lua_type(i1, i7) | 0) | 0;
+ HEAP32[i4 >> 2] = i5;
+ HEAP32[i4 + 4 >> 2] = i6;
+ _luaL_argerror(i1, i7, _lua_pushfstring(i1, 1744, i4) | 0) | 0;
+ i7 = 0;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _luaL_error(i1, i5, i7) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 128 | 0;
+ i3 = i4;
+ i2 = i4 + 24 | 0;
+ i4 = i4 + 8 | 0;
+ HEAP32[i4 >> 2] = i7;
+ if ((_lua_getstack(i1, 1, i2) | 0) != 0 ? (_lua_getinfo(i1, 1152, i2) | 0, i6 = HEAP32[i2 + 20 >> 2] | 0, (i6 | 0) > 0) : 0) {
+  HEAP32[i3 >> 2] = i2 + 36;
+  HEAP32[i3 + 4 >> 2] = i6;
+  _lua_pushfstring(i1, 1160, i3) | 0;
+  _lua_pushvfstring(i1, i5, i4) | 0;
+  _lua_concat(i1, 2);
+  _lua_error(i1) | 0;
+ }
+ _lua_pushlstring(i1, 1168, 0) | 0;
+ _lua_pushvfstring(i1, i5, i4) | 0;
+ _lua_concat(i1, 2);
+ _lua_error(i1) | 0;
+ return 0;
+}
+function _luaK_infix(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ L1 : do {
+  switch (i4 | 0) {
+  case 6:
+   {
+    _luaK_exp2nextreg(i1, i3);
+    break;
+   }
+  case 5:
+  case 4:
+  case 3:
+  case 2:
+  case 1:
+  case 0:
+   {
+    if (((HEAP32[i3 >> 2] | 0) == 5 ? (HEAP32[i3 + 16 >> 2] | 0) == -1 : 0) ? (HEAP32[i3 + 20 >> 2] | 0) == -1 : 0) {
+     break L1;
+    }
+    _luaK_exp2RK(i1, i3) | 0;
+    break;
+   }
+  case 13:
+   {
+    _luaK_goiftrue(i1, i3);
+    break;
+   }
+  case 14:
+   {
+    _luaK_goiffalse(i1, i3);
+    break;
+   }
+  default:
+   {
+    _luaK_exp2RK(i1, i3) | 0;
+   }
+  }
+ } while (0);
+ STACKTOP = i2;
+ return;
+}
+function _luaD_shrinkstack(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 8 >> 2] | 0;
+ i3 = HEAP32[i1 + 16 >> 2] | 0;
+ if ((i3 | 0) != 0) {
+  do {
+   i5 = HEAP32[i3 + 4 >> 2] | 0;
+   i4 = i4 >>> 0 < i5 >>> 0 ? i5 : i4;
+   i3 = HEAP32[i3 + 8 >> 2] | 0;
+  } while ((i3 | 0) != 0);
+ }
+ i3 = i4 - (HEAP32[i1 + 28 >> 2] | 0) | 0;
+ i4 = (i3 >> 4) + 1 | 0;
+ i4 = ((i4 | 0) / 8 | 0) + 10 + i4 | 0;
+ i4 = (i4 | 0) > 1e6 ? 1e6 : i4;
+ if ((i3 | 0) > 15999984) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((i4 | 0) >= (HEAP32[i1 + 32 >> 2] | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ _luaD_reallocstack(i1, i4);
+ STACKTOP = i2;
+ return;
+}
+function _luaF_newproto(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _luaC_newobj(i1, 9, 80, 0, 0) | 0;
+ HEAP32[i1 + 8 >> 2] = 0;
+ HEAP32[i1 + 44 >> 2] = 0;
+ HEAP32[i1 + 16 >> 2] = 0;
+ HEAP32[i1 + 56 >> 2] = 0;
+ HEAP32[i1 + 12 >> 2] = 0;
+ HEAP32[i1 + 32 >> 2] = 0;
+ HEAP32[i1 + 48 >> 2] = 0;
+ HEAP32[i1 + 20 >> 2] = 0;
+ HEAP32[i1 + 52 >> 2] = 0;
+ HEAP32[i1 + 28 >> 2] = 0;
+ HEAP32[i1 + 40 >> 2] = 0;
+ HEAP8[i1 + 76 | 0] = 0;
+ HEAP8[i1 + 77 | 0] = 0;
+ HEAP8[i1 + 78 | 0] = 0;
+ HEAP32[i1 + 24 >> 2] = 0;
+ HEAP32[i1 + 60 >> 2] = 0;
+ HEAP32[i1 + 64 >> 2] = 0;
+ HEAP32[i1 + 68 >> 2] = 0;
+ HEAP32[i1 + 36 >> 2] = 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaF_freeproto(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ _luaM_realloc_(i2, HEAP32[i1 + 12 >> 2] | 0, HEAP32[i1 + 48 >> 2] << 2, 0) | 0;
+ _luaM_realloc_(i2, HEAP32[i1 + 16 >> 2] | 0, HEAP32[i1 + 56 >> 2] << 2, 0) | 0;
+ _luaM_realloc_(i2, HEAP32[i1 + 8 >> 2] | 0, HEAP32[i1 + 44 >> 2] << 4, 0) | 0;
+ _luaM_realloc_(i2, HEAP32[i1 + 20 >> 2] | 0, HEAP32[i1 + 52 >> 2] << 2, 0) | 0;
+ _luaM_realloc_(i2, HEAP32[i1 + 24 >> 2] | 0, (HEAP32[i1 + 60 >> 2] | 0) * 12 | 0, 0) | 0;
+ _luaM_realloc_(i2, HEAP32[i1 + 28 >> 2] | 0, HEAP32[i1 + 40 >> 2] << 3, 0) | 0;
+ _luaM_realloc_(i2, i1, 80, 0) | 0;
+ STACKTOP = i3;
+ return;
+}
+function _luaK_patchclose(i3, i7, i4) {
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i6 = 0, i8 = 0;
+ i2 = STACKTOP;
+ if ((i7 | 0) == -1) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0;
+ i4 = (i4 << 6) + 64 & 16320;
+ while (1) {
+  i6 = i3 + (i7 << 2) | 0;
+  i5 = HEAP32[i6 >> 2] | 0;
+  i8 = (i5 >>> 14) + -131071 | 0;
+  if ((i8 | 0) == -1) {
+   break;
+  }
+  i7 = i7 + 1 + i8 | 0;
+  HEAP32[i6 >> 2] = i5 & -16321 | i4;
+  if ((i7 | 0) == -1) {
+   i1 = 6;
+   break;
+  }
+ }
+ if ((i1 | 0) == 6) {
+  STACKTOP = i2;
+  return;
+ }
+ HEAP32[i6 >> 2] = i5 & -16321 | i4;
+ STACKTOP = i2;
+ return;
+}
+function _loadfunc(i1, i4, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i6 = _luaL_gsub(i1, i5, 4936, 4944) | 0;
+ i5 = _strchr(i6, 45) | 0;
+ do {
+  if ((i5 | 0) != 0) {
+   HEAP32[i3 >> 2] = _lua_pushlstring(i1, i6, i5 - i6 | 0) | 0;
+   i6 = _ll_loadfunc(i1, i4, _lua_pushfstring(i1, 4952, i3) | 0) | 0;
+   if ((i6 | 0) == 2) {
+    i6 = i5 + 1 | 0;
+    break;
+   } else {
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+  }
+ } while (0);
+ HEAP32[i3 >> 2] = i6;
+ i6 = _ll_loadfunc(i1, i4, _lua_pushfstring(i1, 4952, i3) | 0) | 0;
+ STACKTOP = i2;
+ return i6 | 0;
+}
+function _luaK_setlist(i1, i3, i4, i5) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i4 = ((i4 + -1 | 0) / 50 | 0) + 1 | 0;
+ i5 = (i5 | 0) == -1 ? 0 : i5;
+ if ((i4 | 0) < 512) {
+  _luaK_code(i1, i3 << 6 | i5 << 23 | i4 << 14 | 36) | 0;
+  i4 = i3 + 1 | 0;
+  i4 = i4 & 255;
+  i5 = i1 + 48 | 0;
+  HEAP8[i5] = i4;
+  STACKTOP = i2;
+  return;
+ }
+ if ((i4 | 0) >= 67108864) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10576);
+ }
+ _luaK_code(i1, i3 << 6 | i5 << 23 | 36) | 0;
+ _luaK_code(i1, i4 << 6 | 39) | 0;
+ i4 = i3 + 1 | 0;
+ i4 = i4 & 255;
+ i5 = i1 + 48 | 0;
+ HEAP8[i5] = i4;
+ STACKTOP = i2;
+ return;
+}
+function _lua_getstack(i2, i6, i3) {
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i5 = 0;
+ i1 = STACKTOP;
+ L1 : do {
+  if ((i6 | 0) >= 0) {
+   i5 = HEAP32[i2 + 16 >> 2] | 0;
+   if ((i6 | 0) > 0) {
+    i4 = i2 + 72 | 0;
+    do {
+     if ((i5 | 0) == (i4 | 0)) {
+      i2 = 0;
+      break L1;
+     }
+     i6 = i6 + -1 | 0;
+     i5 = HEAP32[i5 + 8 >> 2] | 0;
+    } while ((i6 | 0) > 0);
+    if ((i6 | 0) != 0) {
+     i2 = 0;
+     break;
+    }
+   }
+   if ((i5 | 0) != (i2 + 72 | 0)) {
+    HEAP32[i3 + 96 >> 2] = i5;
+    i2 = 1;
+   } else {
+    i2 = 0;
+   }
+  } else {
+   i2 = 0;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _luaC_checkupvalcolor(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = i5 + 5 | 0;
+ i3 = HEAPU8[i4] | 0;
+ if ((i3 & 7 | 0) != 0) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP8[i1 + 62 | 0] | 0) != 2 ? (HEAPU8[i1 + 61 | 0] | 0) >= 2 : 0) {
+  HEAP8[i4] = HEAP8[i1 + 60 | 0] & 3 | i3 & 184;
+  STACKTOP = i2;
+  return;
+ }
+ HEAP8[i4] = i3 & 187 | 4;
+ i3 = HEAP32[i5 + 8 >> 2] | 0;
+ if ((HEAP32[i3 + 8 >> 2] & 64 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = HEAP32[i3 >> 2] | 0;
+ if ((HEAP8[i3 + 5 | 0] & 3) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ _reallymarkobject(i1, i3);
+ STACKTOP = i2;
+ return;
+}
+function _luaB_collectgarbage(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[10160 + ((_luaL_checkoption(i1, 1, 10040, 9976) | 0) << 2) >> 2] | 0;
+ i3 = _lua_gc(i1, i4, _luaL_optinteger(i1, 2, 0) | 0) | 0;
+ if ((i4 | 0) == 3) {
+  i4 = _lua_gc(i1, 4, 0) | 0;
+  _lua_pushnumber(i1, +(i3 | 0) + +(i4 | 0) * .0009765625);
+  _lua_pushinteger(i1, i4);
+  i4 = 2;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else if ((i4 | 0) == 9 | (i4 | 0) == 5) {
+  _lua_pushboolean(i1, i3);
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else {
+  _lua_pushinteger(i1, i3);
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ return 0;
+}
+function _maxn(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0, d4 = 0.0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 5);
+ _lua_pushnil(i1);
+ L1 : do {
+  if ((_lua_next(i1, 1) | 0) == 0) {
+   d3 = 0.0;
+  } else {
+   d4 = 0.0;
+   while (1) {
+    while (1) {
+     _lua_settop(i1, -2);
+     if ((_lua_type(i1, -1) | 0) == 3 ? (d3 = +_lua_tonumberx(i1, -1, 0), d3 > d4) : 0) {
+      break;
+     }
+     if ((_lua_next(i1, 1) | 0) == 0) {
+      d3 = d4;
+      break L1;
+     }
+    }
+    if ((_lua_next(i1, 1) | 0) == 0) {
+     break;
+    } else {
+     d4 = d3;
+    }
+   }
+  }
+ } while (0);
+ _lua_pushnumber(i1, d3);
+ STACKTOP = i2;
+ return 1;
+}
+function _str_char(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 1040 | 0;
+ i4 = i2;
+ i3 = _lua_gettop(i1) | 0;
+ i5 = _luaL_buffinitsize(i1, i4, i3) | 0;
+ if ((i3 | 0) < 1) {
+  _luaL_pushresultsize(i4, i3);
+  STACKTOP = i2;
+  return 1;
+ } else {
+  i6 = 1;
+ }
+ while (1) {
+  i7 = _luaL_checkinteger(i1, i6) | 0;
+  if ((i7 & 255 | 0) != (i7 | 0)) {
+   _luaL_argerror(i1, i6, 7920) | 0;
+  }
+  HEAP8[i5 + (i6 + -1) | 0] = i7;
+  if ((i6 | 0) == (i3 | 0)) {
+   break;
+  } else {
+   i6 = i6 + 1 | 0;
+  }
+ }
+ _luaL_pushresultsize(i4, i3);
+ STACKTOP = i2;
+ return 1;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function _luaK_exp2val(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i2 = STACKTOP;
+ i3 = i5 + 16 | 0;
+ i4 = i5 + 20 | 0;
+ if ((HEAP32[i3 >> 2] | 0) == (HEAP32[i4 >> 2] | 0)) {
+  _luaK_dischargevars(i1, i5);
+  STACKTOP = i2;
+  return;
+ }
+ _luaK_dischargevars(i1, i5);
+ if ((HEAP32[i5 >> 2] | 0) == 6) {
+  i6 = HEAP32[i5 + 8 >> 2] | 0;
+  if ((HEAP32[i3 >> 2] | 0) == (HEAP32[i4 >> 2] | 0)) {
+   STACKTOP = i2;
+   return;
+  }
+  if ((i6 | 0) >= (HEAPU8[i1 + 46 | 0] | 0 | 0)) {
+   _exp2reg(i1, i5, i6);
+   STACKTOP = i2;
+   return;
+  }
+ }
+ _luaK_exp2nextreg(i1, i5);
+ STACKTOP = i2;
+ return;
+}
+function _str_reverse(i5) {
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i4 = i2 + 1040 | 0;
+ i1 = i2;
+ i3 = _luaL_checklstring(i5, 1, i4) | 0;
+ i5 = _luaL_buffinitsize(i5, i1, HEAP32[i4 >> 2] | 0) | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  i7 = 0;
+  _luaL_pushresultsize(i1, i7);
+  STACKTOP = i2;
+  return 1;
+ } else {
+  i7 = 0;
+ }
+ do {
+  HEAP8[i5 + i7 | 0] = HEAP8[i3 + (i6 + ~i7) | 0] | 0;
+  i7 = i7 + 1 | 0;
+  i6 = HEAP32[i4 >> 2] | 0;
+ } while (i7 >>> 0 < i6 >>> 0);
+ _luaL_pushresultsize(i1, i6);
+ STACKTOP = i2;
+ return 1;
+}
+function _str_upper(i5) {
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i4 = i1 + 1040 | 0;
+ i2 = i1;
+ i3 = _luaL_checklstring(i5, 1, i4) | 0;
+ i5 = _luaL_buffinitsize(i5, i2, HEAP32[i4 >> 2] | 0) | 0;
+ if ((HEAP32[i4 >> 2] | 0) == 0) {
+  i7 = 0;
+  _luaL_pushresultsize(i2, i7);
+  STACKTOP = i1;
+  return 1;
+ } else {
+  i6 = 0;
+ }
+ do {
+  HEAP8[i5 + i6 | 0] = _toupper(HEAPU8[i3 + i6 | 0] | 0 | 0) | 0;
+  i6 = i6 + 1 | 0;
+  i7 = HEAP32[i4 >> 2] | 0;
+ } while (i6 >>> 0 < i7 >>> 0);
+ _luaL_pushresultsize(i2, i7);
+ STACKTOP = i1;
+ return 1;
+}
+function _str_lower(i5) {
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i4 = i1 + 1040 | 0;
+ i2 = i1;
+ i3 = _luaL_checklstring(i5, 1, i4) | 0;
+ i5 = _luaL_buffinitsize(i5, i2, HEAP32[i4 >> 2] | 0) | 0;
+ if ((HEAP32[i4 >> 2] | 0) == 0) {
+  i7 = 0;
+  _luaL_pushresultsize(i2, i7);
+  STACKTOP = i1;
+  return 1;
+ } else {
+  i6 = 0;
+ }
+ do {
+  HEAP8[i5 + i6 | 0] = _tolower(HEAPU8[i3 + i6 | 0] | 0 | 0) | 0;
+  i6 = i6 + 1 | 0;
+  i7 = HEAP32[i4 >> 2] | 0;
+ } while (i6 >>> 0 < i7 >>> 0);
+ _luaL_pushresultsize(i2, i7);
+ STACKTOP = i1;
+ return 1;
+}
+function ___divdi3(i1, i2, i3, i4) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i5 = i2 >> 31 | ((i2 | 0) < 0 ? -1 : 0) << 1;
+ i6 = ((i2 | 0) < 0 ? -1 : 0) >> 31 | ((i2 | 0) < 0 ? -1 : 0) << 1;
+ i7 = i4 >> 31 | ((i4 | 0) < 0 ? -1 : 0) << 1;
+ i8 = ((i4 | 0) < 0 ? -1 : 0) >> 31 | ((i4 | 0) < 0 ? -1 : 0) << 1;
+ i1 = _i64Subtract(i5 ^ i1, i6 ^ i2, i5, i6) | 0;
+ i2 = tempRet0;
+ i5 = i7 ^ i5;
+ i6 = i8 ^ i6;
+ i7 = _i64Subtract((___udivmoddi4(i1, i2, _i64Subtract(i7 ^ i3, i8 ^ i4, i7, i8) | 0, tempRet0, 0) | 0) ^ i5, tempRet0 ^ i6, i5, i6) | 0;
+ return i7 | 0;
+}
+function _luaK_setoneret(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i4 >> 2] | 0;
+ if ((i3 | 0) == 13) {
+  i3 = (HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i4 + 8 >> 2] << 2) | 0;
+  HEAP32[i3 >> 2] = HEAP32[i3 >> 2] & 8388607 | 16777216;
+  HEAP32[i4 >> 2] = 11;
+  STACKTOP = i2;
+  return;
+ } else if ((i3 | 0) == 12) {
+  HEAP32[i4 >> 2] = 6;
+  i4 = i4 + 8 | 0;
+  HEAP32[i4 >> 2] = (HEAP32[(HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i4 >> 2] << 2) >> 2] | 0) >>> 6 & 255;
+  STACKTOP = i2;
+  return;
+ } else {
+  STACKTOP = i2;
+  return;
+ }
+}
+function _luaV_tostring(i6, i1) {
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i3 = i2;
+ i4 = i2 + 8 | 0;
+ i5 = i1 + 8 | 0;
+ if ((HEAP32[i5 >> 2] | 0) != 3) {
+  i6 = 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ HEAPF64[tempDoublePtr >> 3] = +HEAPF64[i1 >> 3];
+ HEAP32[i3 >> 2] = HEAP32[tempDoublePtr >> 2];
+ HEAP32[i3 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+ i6 = _luaS_newlstr(i6, i4, _sprintf(i4 | 0, 8936, i3 | 0) | 0) | 0;
+ HEAP32[i1 >> 2] = i6;
+ HEAP32[i5 >> 2] = HEAPU8[i6 + 4 | 0] | 0 | 64;
+ i6 = 1;
+ STACKTOP = i2;
+ return i6 | 0;
+}
+function _strcmp(i4, i2) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i5 = 0;
+ i1 = STACKTOP;
+ i5 = HEAP8[i4] | 0;
+ i3 = HEAP8[i2] | 0;
+ if (i5 << 24 >> 24 != i3 << 24 >> 24 | i5 << 24 >> 24 == 0 | i3 << 24 >> 24 == 0) {
+  i4 = i5;
+  i5 = i3;
+  i4 = i4 & 255;
+  i5 = i5 & 255;
+  i5 = i4 - i5 | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ do {
+  i4 = i4 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i5 = HEAP8[i4] | 0;
+  i3 = HEAP8[i2] | 0;
+ } while (!(i5 << 24 >> 24 != i3 << 24 >> 24 | i5 << 24 >> 24 == 0 | i3 << 24 >> 24 == 0));
+ i4 = i5 & 255;
+ i5 = i3 & 255;
+ i5 = i4 - i5 | 0;
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _lua_pushstring(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ if ((i3 | 0) == 0) {
+  i3 = i1 + 8 | 0;
+  i1 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i1 + 8 >> 2] = 0;
+  HEAP32[i3 >> 2] = i1 + 16;
+  i3 = 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ if ((HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i1);
+ }
+ i3 = _luaS_new(i1, i3) | 0;
+ i1 = i1 + 8 | 0;
+ i4 = HEAP32[i1 >> 2] | 0;
+ HEAP32[i4 >> 2] = i3;
+ HEAP32[i4 + 8 >> 2] = HEAPU8[i3 + 4 | 0] | 0 | 64;
+ HEAP32[i1 >> 2] = (HEAP32[i1 >> 2] | 0) + 16;
+ i3 = i3 + 16 | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _luaK_exp2anyreg(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ _luaK_dischargevars(i1, i3);
+ if ((HEAP32[i3 >> 2] | 0) == 6) {
+  i5 = i3 + 8 | 0;
+  i4 = HEAP32[i5 >> 2] | 0;
+  if ((HEAP32[i3 + 16 >> 2] | 0) == (HEAP32[i3 + 20 >> 2] | 0)) {
+   i5 = i4;
+   STACKTOP = i2;
+   return i5 | 0;
+  }
+  if ((i4 | 0) >= (HEAPU8[i1 + 46 | 0] | 0 | 0)) {
+   _exp2reg(i1, i3, i4);
+   i5 = HEAP32[i5 >> 2] | 0;
+   STACKTOP = i2;
+   return i5 | 0;
+  }
+ } else {
+  i5 = i3 + 8 | 0;
+ }
+ _luaK_exp2nextreg(i1, i3);
+ i5 = HEAP32[i5 >> 2] | 0;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _check_match(i1, i4, i5, i6) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ if ((HEAP32[i1 + 16 >> 2] | 0) == (i4 | 0)) {
+  _luaX_next(i1);
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP32[i1 + 4 >> 2] | 0) == (i6 | 0)) {
+  _error_expected(i1, i4);
+ } else {
+  i2 = HEAP32[i1 + 52 >> 2] | 0;
+  i4 = _luaX_token2str(i1, i4) | 0;
+  i5 = _luaX_token2str(i1, i5) | 0;
+  HEAP32[i3 >> 2] = i4;
+  HEAP32[i3 + 4 >> 2] = i5;
+  HEAP32[i3 + 8 >> 2] = i6;
+  _luaX_syntaxerror(i1, _luaO_pushfstring(i2, 6840, i3) | 0);
+ }
+}
+function _fieldsel(i1, i6) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i3 = i2;
+ i5 = i1 + 48 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ _luaK_exp2anyregup(i4, i6);
+ _luaX_next(i1);
+ if ((HEAP32[i1 + 16 >> 2] | 0) == 288) {
+  i7 = HEAP32[i1 + 24 >> 2] | 0;
+  _luaX_next(i1);
+  i5 = _luaK_stringK(HEAP32[i5 >> 2] | 0, i7) | 0;
+  HEAP32[i3 + 16 >> 2] = -1;
+  HEAP32[i3 + 20 >> 2] = -1;
+  HEAP32[i3 >> 2] = 4;
+  HEAP32[i3 + 8 >> 2] = i5;
+  _luaK_indexed(i4, i6, i3);
+  STACKTOP = i2;
+  return;
+ } else {
+  _error_expected(i1, 288);
+ }
+}
+function _luaK_exp2anyregup(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[i3 >> 2] | 0) == 8 ? (HEAP32[i3 + 16 >> 2] | 0) == (HEAP32[i3 + 20 >> 2] | 0) : 0) {
+  STACKTOP = i2;
+  return;
+ }
+ _luaK_dischargevars(i1, i3);
+ if ((HEAP32[i3 >> 2] | 0) == 6) {
+  i4 = HEAP32[i3 + 8 >> 2] | 0;
+  if ((HEAP32[i3 + 16 >> 2] | 0) == (HEAP32[i3 + 20 >> 2] | 0)) {
+   STACKTOP = i2;
+   return;
+  }
+  if ((i4 | 0) >= (HEAPU8[i1 + 46 | 0] | 0 | 0)) {
+   _exp2reg(i1, i3, i4);
+   STACKTOP = i2;
+   return;
+  }
+ }
+ _luaK_exp2nextreg(i1, i3);
+ STACKTOP = i2;
+ return;
+}
+function _lua_settop(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i1 = STACKTOP;
+ if (!((i5 | 0) > -1)) {
+  i4 = i3 + 8 | 0;
+  HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + (i5 + 1 << 4);
+  STACKTOP = i1;
+  return;
+ }
+ i2 = i3 + 8 | 0;
+ i4 = HEAP32[i2 >> 2] | 0;
+ i3 = (HEAP32[HEAP32[i3 + 16 >> 2] >> 2] | 0) + (i5 + 1 << 4) | 0;
+ if (i4 >>> 0 < i3 >>> 0) {
+  while (1) {
+   i5 = i4 + 16 | 0;
+   HEAP32[i4 + 8 >> 2] = 0;
+   if (i5 >>> 0 < i3 >>> 0) {
+    i4 = i5;
+   } else {
+    break;
+   }
+  }
+  HEAP32[i2 >> 2] = i5;
+ }
+ HEAP32[i2 >> 2] = i3;
+ STACKTOP = i1;
+ return;
+}
+function _luaL_fileresult(i1, i6, i5) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i3 = HEAP32[(___errno_location() | 0) >> 2] | 0;
+ if ((i6 | 0) != 0) {
+  _lua_pushboolean(i1, 1);
+  i6 = 1;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ _lua_pushnil(i1);
+ i6 = _strerror(i3 | 0) | 0;
+ if ((i5 | 0) == 0) {
+  _lua_pushstring(i1, i6) | 0;
+ } else {
+  HEAP32[i4 >> 2] = i5;
+  HEAP32[i4 + 4 >> 2] = i6;
+  _lua_pushfstring(i1, 1176, i4) | 0;
+ }
+ _lua_pushinteger(i1, i3);
+ i6 = 3;
+ STACKTOP = i2;
+ return i6 | 0;
+}
+function _luaL_pushmodule(i1, i4, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ _luaL_findtable(i1, -1001e3, 1432, 1) | 0;
+ _lua_getfield(i1, -1, i4);
+ if ((_lua_type(i1, -1) | 0) == 5) {
+  _lua_remove(i1, -2);
+  STACKTOP = i2;
+  return;
+ }
+ _lua_settop(i1, -2);
+ _lua_rawgeti(i1, -1001e3, 2);
+ if ((_luaL_findtable(i1, 0, i4, i5) | 0) != 0) {
+  HEAP32[i3 >> 2] = i4;
+  _luaL_error(i1, 1440, i3) | 0;
+ }
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, -3, i4);
+ _lua_remove(i1, -2);
+ STACKTOP = i2;
+ return;
+}
+function _b_replace(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _luaL_checkunsigned(i1, 1) | 0;
+ i5 = _luaL_checkunsigned(i1, 2) | 0;
+ i4 = _luaL_checkinteger(i1, 3) | 0;
+ i2 = _luaL_optinteger(i1, 4, 1) | 0;
+ if (!((i4 | 0) > -1)) {
+  _luaL_argerror(i1, 3, 10440) | 0;
+ }
+ if ((i2 | 0) <= 0) {
+  _luaL_argerror(i1, 4, 10472) | 0;
+ }
+ if ((i2 + i4 | 0) > 32) {
+  _luaL_error(i1, 10496, i6) | 0;
+ }
+ i2 = ~(-2 << i2 + -1);
+ _lua_pushunsigned(i1, i3 & ~(i2 << i4) | (i5 & i2) << i4);
+ STACKTOP = i6;
+ return 1;
+}
+function _luaT_gettmbyobj(i1, i5, i3) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i5 + 8 >> 2] & 15;
+ if ((i4 | 0) == 5) {
+  i4 = HEAP32[(HEAP32[i5 >> 2] | 0) + 8 >> 2] | 0;
+ } else if ((i4 | 0) == 7) {
+  i4 = HEAP32[(HEAP32[i5 >> 2] | 0) + 8 >> 2] | 0;
+ } else {
+  i4 = HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + (i4 << 2) + 252 >> 2] | 0;
+ }
+ if ((i4 | 0) == 0) {
+  i5 = 5192;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ i5 = _luaH_getstr(i4, HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + (i3 << 2) + 184 >> 2] | 0) | 0;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _luaS_eqstr(i2, i3) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP8[i2 + 4 | 0] | 0;
+ do {
+  if (i4 << 24 >> 24 == (HEAP8[i3 + 4 | 0] | 0)) {
+   if (i4 << 24 >> 24 == 4) {
+    i2 = (i2 | 0) == (i3 | 0);
+    break;
+   }
+   i4 = HEAP32[i2 + 12 >> 2] | 0;
+   if ((i2 | 0) != (i3 | 0)) {
+    if ((i4 | 0) == (HEAP32[i3 + 12 >> 2] | 0)) {
+     i2 = (_memcmp(i2 + 16 | 0, i3 + 16 | 0, i4) | 0) == 0;
+    } else {
+     i2 = 0;
+    }
+   } else {
+    i2 = 1;
+   }
+  } else {
+   i2 = 0;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 & 1 | 0;
+}
+function _lua_concat(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ if ((i3 | 0) > 1) {
+  if ((HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+   _luaC_step(i1);
+  }
+  _luaV_concat(i1, i3);
+  STACKTOP = i2;
+  return;
+ } else {
+  if ((i3 | 0) != 0) {
+   STACKTOP = i2;
+   return;
+  }
+  i3 = i1 + 8 | 0;
+  i4 = HEAP32[i3 >> 2] | 0;
+  i1 = _luaS_newlstr(i1, 936, 0) | 0;
+  HEAP32[i4 >> 2] = i1;
+  HEAP32[i4 + 8 >> 2] = HEAPU8[i1 + 4 | 0] | 0 | 64;
+  HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + 16;
+  STACKTOP = i2;
+  return;
+ }
+}
+function _ll_loadfunc(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_getfield(i1, -1001e3, 4184);
+ _lua_getfield(i1, -1, i4);
+ i4 = _lua_touserdata(i1, -1) | 0;
+ _lua_settop(i1, -3);
+ if ((i4 | 0) == 0) {
+  _lua_pushlstring(i1, 4968, 58) | 0;
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ if ((HEAP8[i3] | 0) == 42) {
+  _lua_pushboolean(i1, 1);
+  i4 = 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else {
+  _lua_pushlstring(i1, 4968, 58) | 0;
+  i4 = 2;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ return 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function _luaD_growstack(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = HEAP32[i1 + 32 >> 2] | 0;
+ if ((i4 | 0) > 1e6) {
+  _luaD_throw(i1, 6);
+ }
+ i3 = i3 + 5 + ((HEAP32[i1 + 8 >> 2] | 0) - (HEAP32[i1 + 28 >> 2] | 0) >> 4) | 0;
+ i4 = i4 << 1;
+ i4 = (i4 | 0) > 1e6 ? 1e6 : i4;
+ i3 = (i4 | 0) < (i3 | 0) ? i3 : i4;
+ if ((i3 | 0) > 1e6) {
+  _luaD_reallocstack(i1, 1000200);
+  _luaG_runerror(i1, 2224, i2);
+ } else {
+  _luaD_reallocstack(i1, i3);
+  STACKTOP = i2;
+  return;
+ }
+}
+function _luaL_callmeta(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i4 = _lua_absindex(i1, i4) | 0;
+ if ((_lua_getmetatable(i1, i4) | 0) == 0) {
+  i4 = 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ _lua_pushstring(i1, i3) | 0;
+ _lua_rawget(i1, -2);
+ if ((_lua_type(i1, -1) | 0) == 0) {
+  _lua_settop(i1, -3);
+  i4 = 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else {
+  _lua_remove(i1, -2);
+  _lua_pushvalue(i1, i4);
+  _lua_callk(i1, 1, 1, 0, 0);
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ return 0;
+}
+function _luaK_reserveregs(i8, i7) {
+ i8 = i8 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i3 = STACKTOP;
+ i2 = i8 + 48 | 0;
+ i6 = HEAP8[i2] | 0;
+ i4 = (i6 & 255) + i7 | 0;
+ i5 = (HEAP32[i8 >> 2] | 0) + 78 | 0;
+ do {
+  if ((i4 | 0) > (HEAPU8[i5] | 0 | 0)) {
+   if ((i4 | 0) > 249) {
+    _luaX_syntaxerror(HEAP32[i8 + 12 >> 2] | 0, 10536);
+   } else {
+    HEAP8[i5] = i4;
+    i1 = HEAP8[i2] | 0;
+    break;
+   }
+  } else {
+   i1 = i6;
+  }
+ } while (0);
+ HEAP8[i2] = (i1 & 255) + i7;
+ STACKTOP = i3;
+ return;
+}
+function _aux_lines(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i4 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ i2 = i3 + -1 | 0;
+ if ((i3 | 0) >= 19) {
+  _luaL_argerror(i1, 17, 3320) | 0;
+ }
+ _lua_pushvalue(i1, 1);
+ _lua_pushinteger(i1, i2);
+ _lua_pushboolean(i1, i5);
+ if ((i3 | 0) >= 2) {
+  i5 = 1;
+  while (1) {
+   i6 = i5 + 1 | 0;
+   _lua_pushvalue(i1, i6);
+   if ((i5 | 0) < (i2 | 0)) {
+    i5 = i6;
+   } else {
+    break;
+   }
+  }
+ }
+ _lua_pushcclosure(i1, 155, i3 + 2 | 0);
+ STACKTOP = i4;
+ return;
+}
+function _memcmp(i2, i4, i3) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i5 = 0, i6 = 0;
+ i1 = STACKTOP;
+ L1 : do {
+  if ((i3 | 0) == 0) {
+   i2 = 0;
+  } else {
+   while (1) {
+    i6 = HEAP8[i2] | 0;
+    i5 = HEAP8[i4] | 0;
+    if (!(i6 << 24 >> 24 == i5 << 24 >> 24)) {
+     break;
+    }
+    i3 = i3 + -1 | 0;
+    if ((i3 | 0) == 0) {
+     i2 = 0;
+     break L1;
+    } else {
+     i2 = i2 + 1 | 0;
+     i4 = i4 + 1 | 0;
+    }
+   }
+   i2 = (i6 & 255) - (i5 & 255) | 0;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _b_arshift(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checkunsigned(i1, 1) | 0;
+ i4 = _luaL_checkinteger(i1, 2) | 0;
+ if ((i4 | 0) > -1 & (i3 | 0) < 0) {
+  if ((i4 | 0) > 31) {
+   i3 = -1;
+  } else {
+   i3 = i3 >>> i4 | ~(-1 >>> i4);
+  }
+  _lua_pushunsigned(i1, i3);
+  STACKTOP = i2;
+  return 1;
+ }
+ i5 = 0 - i4 | 0;
+ if ((i4 | 0) > 0) {
+  i3 = (i4 | 0) > 31 ? 0 : i3 >>> i4;
+ } else {
+  i3 = (i5 | 0) > 31 ? 0 : i3 << i5;
+ }
+ _lua_pushunsigned(i1, i3);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaL_checkunsigned(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i3;
+ i6 = i3 + 8 | 0;
+ i2 = _lua_tounsignedx(i1, i5, i6) | 0;
+ if ((HEAP32[i6 >> 2] | 0) != 0) {
+  STACKTOP = i3;
+  return i2 | 0;
+ }
+ i7 = _lua_typename(i1, 3) | 0;
+ i6 = _lua_typename(i1, _lua_type(i1, i5) | 0) | 0;
+ HEAP32[i4 >> 2] = i7;
+ HEAP32[i4 + 4 >> 2] = i6;
+ _luaL_argerror(i1, i5, _lua_pushfstring(i1, 1744, i4) | 0) | 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _luaB_loadfile(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i1 = STACKTOP;
+ i4 = _luaL_optlstring(i2, 1, 0, 0) | 0;
+ i5 = _luaL_optlstring(i2, 2, 0, 0) | 0;
+ i3 = (_lua_type(i2, 3) | 0) != -1;
+ i6 = i3 ? 3 : 0;
+ if ((_luaL_loadfilex(i2, i4, i5) | 0) == 0) {
+  if (i3 ? (_lua_pushvalue(i2, i6), (_lua_setupvalue(i2, -2, 1) | 0) == 0) : 0) {
+   _lua_settop(i2, -2);
+   i2 = 1;
+  } else {
+   i2 = 1;
+  }
+ } else {
+  _lua_pushnil(i2);
+  _lua_insert(i2, -2);
+  i2 = 2;
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _luaL_checkinteger(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i3;
+ i6 = i3 + 8 | 0;
+ i2 = _lua_tointegerx(i1, i5, i6) | 0;
+ if ((HEAP32[i6 >> 2] | 0) != 0) {
+  STACKTOP = i3;
+  return i2 | 0;
+ }
+ i7 = _lua_typename(i1, 3) | 0;
+ i6 = _lua_typename(i1, _lua_type(i1, i5) | 0) | 0;
+ HEAP32[i4 >> 2] = i7;
+ HEAP32[i4 + 4 >> 2] = i6;
+ _luaL_argerror(i1, i5, _lua_pushfstring(i1, 1744, i4) | 0) | 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _luaB_select(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i3 = STACKTOP;
+ i2 = _lua_gettop(i1) | 0;
+ if ((_lua_type(i1, 1) | 0) == 4 ? (HEAP8[_lua_tolstring(i1, 1, 0) | 0] | 0) == 35 : 0) {
+  _lua_pushinteger(i1, i2 + -1 | 0);
+  i4 = 1;
+  STACKTOP = i3;
+  return i4 | 0;
+ }
+ i4 = _luaL_checkinteger(i1, 1) | 0;
+ if ((i4 | 0) < 0) {
+  i4 = i4 + i2 | 0;
+ } else {
+  i4 = (i4 | 0) > (i2 | 0) ? i2 : i4;
+ }
+ if ((i4 | 0) <= 0) {
+  _luaL_argerror(i1, 1, 9760) | 0;
+ }
+ i4 = i2 - i4 | 0;
+ STACKTOP = i3;
+ return i4 | 0;
+}
+function _luaX_next(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ HEAP32[i1 + 8 >> 2] = HEAP32[i1 + 4 >> 2];
+ i3 = i1 + 32 | 0;
+ if ((HEAP32[i3 >> 2] | 0) == 286) {
+  HEAP32[i1 + 16 >> 2] = _llex(i1, i1 + 24 | 0) | 0;
+  STACKTOP = i2;
+  return;
+ } else {
+  i1 = i1 + 16 | 0;
+  HEAP32[i1 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+  HEAP32[i1 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+  HEAP32[i1 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+  HEAP32[i1 + 12 >> 2] = HEAP32[i3 + 12 >> 2];
+  HEAP32[i3 >> 2] = 286;
+  STACKTOP = i2;
+  return;
+ }
+}
+function _lua_setglobal(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i3 = STACKTOP;
+ i5 = _luaH_getint(HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 40 >> 2] | 0, 2) | 0;
+ i4 = i1 + 8 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i4 >> 2] = i6 + 16;
+ i2 = _luaS_new(i1, i2) | 0;
+ HEAP32[i6 >> 2] = i2;
+ HEAP32[i6 + 8 >> 2] = HEAPU8[i2 + 4 | 0] | 0 | 64;
+ i2 = HEAP32[i4 >> 2] | 0;
+ _luaV_settable(i1, i5, i2 + -16 | 0, i2 + -32 | 0);
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + -32;
+ STACKTOP = i3;
+ return;
+}
+function _luaL_checknumber(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var d2 = 0.0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i3;
+ i6 = i3 + 8 | 0;
+ d2 = +_lua_tonumberx(i1, i5, i6);
+ if ((HEAP32[i6 >> 2] | 0) != 0) {
+  STACKTOP = i3;
+  return +d2;
+ }
+ i7 = _lua_typename(i1, 3) | 0;
+ i6 = _lua_typename(i1, _lua_type(i1, i5) | 0) | 0;
+ HEAP32[i4 >> 2] = i7;
+ HEAP32[i4 + 4 >> 2] = i6;
+ _luaL_argerror(i1, i5, _lua_pushfstring(i1, 1744, i4) | 0) | 0;
+ STACKTOP = i3;
+ return +d2;
+}
+function _luaZ_fill(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i3 = FUNCTION_TABLE_iiii[HEAP32[i1 + 8 >> 2] & 3](HEAP32[i1 + 16 >> 2] | 0, HEAP32[i1 + 12 >> 2] | 0, i4) | 0;
+ if ((i3 | 0) == 0) {
+  i4 = -1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ i4 = HEAP32[i4 >> 2] | 0;
+ if ((i4 | 0) == 0) {
+  i4 = -1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ HEAP32[i1 >> 2] = i4 + -1;
+ HEAP32[i1 + 4 >> 2] = i3 + 1;
+ i4 = HEAPU8[i3] | 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _lua_createtable(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i1);
+ }
+ i5 = _luaH_new(i1) | 0;
+ i6 = i1 + 8 | 0;
+ i7 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i7 >> 2] = i5;
+ HEAP32[i7 + 8 >> 2] = 69;
+ HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 16;
+ if (!((i3 | 0) > 0 | (i4 | 0) > 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ _luaH_resize(i1, i5, i3, i4);
+ STACKTOP = i2;
+ return;
+}
+function _generic_reader(i1, i3, i2) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ _luaL_checkstack(i1, 2, 9888);
+ _lua_pushvalue(i1, 1);
+ _lua_callk(i1, 0, 1, 0, 0);
+ if ((_lua_type(i1, -1) | 0) == 0) {
+  _lua_settop(i1, -2);
+  HEAP32[i2 >> 2] = 0;
+  i2 = 0;
+  STACKTOP = i3;
+  return i2 | 0;
+ }
+ if ((_lua_isstring(i1, -1) | 0) == 0) {
+  _luaL_error(i1, 9920, i3) | 0;
+ }
+ _lua_replace(i1, 5);
+ i2 = _lua_tolstring(i1, 5, i2) | 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _luaZ_openspace(i5, i1, i6) {
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = i1 + 8 | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ if (!(i3 >>> 0 < i6 >>> 0)) {
+  i6 = HEAP32[i1 >> 2] | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ i6 = i6 >>> 0 < 32 ? 32 : i6;
+ if ((i6 + 1 | 0) >>> 0 > 4294967293) {
+  _luaM_toobig(i5);
+ }
+ i5 = _luaM_realloc_(i5, HEAP32[i1 >> 2] | 0, i3, i6) | 0;
+ HEAP32[i1 >> 2] = i5;
+ HEAP32[i4 >> 2] = i6;
+ i6 = i5;
+ STACKTOP = i2;
+ return i6 | 0;
+}
+function _luaH_getstr(i4, i3) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0;
+ i2 = STACKTOP;
+ i4 = (HEAP32[i4 + 16 >> 2] | 0) + (((1 << (HEAPU8[i4 + 7 | 0] | 0)) + -1 & HEAP32[i3 + 8 >> 2]) << 5) | 0;
+ while (1) {
+  if ((HEAP32[i4 + 24 >> 2] | 0) == 68 ? (HEAP32[i4 + 16 >> 2] | 0) == (i3 | 0) : 0) {
+   break;
+  }
+  i4 = HEAP32[i4 + 28 >> 2] | 0;
+  if ((i4 | 0) == 0) {
+   i3 = 5192;
+   i1 = 6;
+   break;
+  }
+ }
+ if ((i1 | 0) == 6) {
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _b_extract(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = _luaL_checkunsigned(i1, 1) | 0;
+ i3 = _luaL_checkinteger(i1, 2) | 0;
+ i4 = _luaL_optinteger(i1, 3, 1) | 0;
+ if (!((i3 | 0) > -1)) {
+  _luaL_argerror(i1, 2, 10440) | 0;
+ }
+ if ((i4 | 0) <= 0) {
+  _luaL_argerror(i1, 3, 10472) | 0;
+ }
+ if ((i4 + i3 | 0) > 32) {
+  _luaL_error(i1, 10496, i5) | 0;
+ }
+ _lua_pushunsigned(i1, i2 >>> i3 & ~(-2 << i4 + -1));
+ STACKTOP = i5;
+ return 1;
+}
+function _luaL_checklstring(i1, i4, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i5 = _lua_tolstring(i1, i4, i5) | 0;
+ if ((i5 | 0) != 0) {
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ i7 = _lua_typename(i1, 4) | 0;
+ i6 = _lua_typename(i1, _lua_type(i1, i4) | 0) | 0;
+ HEAP32[i3 >> 2] = i7;
+ HEAP32[i3 + 4 >> 2] = i6;
+ _luaL_argerror(i1, i4, _lua_pushfstring(i1, 1744, i3) | 0) | 0;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _db_traceback(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ if ((_lua_type(i1, 1) | 0) == 8) {
+  i3 = _lua_tothread(i1, 1) | 0;
+  i4 = 1;
+ } else {
+  i3 = i1;
+  i4 = 0;
+ }
+ i5 = i4 + 1 | 0;
+ i6 = _lua_tolstring(i1, i5, 0) | 0;
+ if ((i6 | 0) == 0 ? (_lua_type(i1, i5) | 0) >= 1 : 0) {
+  _lua_pushvalue(i1, i5);
+  STACKTOP = i2;
+  return 1;
+ }
+ _luaL_traceback(i1, i3, i6, _luaL_optinteger(i1, i4 | 2, (i3 | 0) == (i1 | 0) | 0) | 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _f_setvbuf(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _luaL_checkudata(i1, 1, 2832) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 3080, i2) | 0;
+ }
+ i5 = HEAP32[i3 >> 2] | 0;
+ i4 = _luaL_checkoption(i1, 2, 0, 3128) | 0;
+ i3 = _luaL_optinteger(i1, 3, 1024) | 0;
+ i3 = _luaL_fileresult(i1, (_setvbuf(i5 | 0, 0, HEAP32[3112 + (i4 << 2) >> 2] | 0, i3 | 0) | 0) == 0 | 0, 0) | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _luaU_dump(i3, i1, i4, i2, i5) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i6 = 0, i7 = 0, i8 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i8 = i6 + 20 | 0;
+ i7 = i6;
+ HEAP32[i7 >> 2] = i3;
+ HEAP32[i7 + 4 >> 2] = i4;
+ HEAP32[i7 + 8 >> 2] = i2;
+ HEAP32[i7 + 12 >> 2] = i5;
+ i5 = i7 + 16 | 0;
+ _luaU_header(i8);
+ HEAP32[i5 >> 2] = FUNCTION_TABLE_iiiii[i4 & 3](i3, i8, 18, i2) | 0;
+ _DumpFunction(i1, i7);
+ STACKTOP = i6;
+ return HEAP32[i5 >> 2] | 0;
+}
+function _luaB_setmetatable(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _lua_type(i1, 2) | 0;
+ _luaL_checktype(i1, 1, 5);
+ if (!((i3 | 0) == 0 | (i3 | 0) == 5)) {
+  _luaL_argerror(i1, 2, 9680) | 0;
+ }
+ if ((_luaL_getmetafield(i1, 1, 9704) | 0) == 0) {
+  _lua_settop(i1, 2);
+  _lua_setmetatable(i1, 1) | 0;
+  i3 = 1;
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  i3 = _luaL_error(i1, 9720, i2) | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ return 0;
+}
+function _getF(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ i3 = STACKTOP;
+ i4 = HEAP32[i2 >> 2] | 0;
+ if ((i4 | 0) > 0) {
+  HEAP32[i1 >> 2] = i4;
+  HEAP32[i2 >> 2] = 0;
+  i4 = i2 + 8 | 0;
+  STACKTOP = i3;
+  return i4 | 0;
+ }
+ i4 = i2 + 4 | 0;
+ if ((_feof(HEAP32[i4 >> 2] | 0) | 0) != 0) {
+  i4 = 0;
+  STACKTOP = i3;
+  return i4 | 0;
+ }
+ i2 = i2 + 8 | 0;
+ HEAP32[i1 >> 2] = _fread(i2 | 0, 1, 1024, HEAP32[i4 >> 2] | 0) | 0;
+ i4 = i2;
+ STACKTOP = i3;
+ return i4 | 0;
+}
+function _luaL_where(i1, i6) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i3 = i4;
+ i2 = i4 + 8 | 0;
+ if ((_lua_getstack(i1, i6, i2) | 0) != 0 ? (_lua_getinfo(i1, 1152, i2) | 0, i5 = HEAP32[i2 + 20 >> 2] | 0, (i5 | 0) > 0) : 0) {
+  HEAP32[i3 >> 2] = i2 + 36;
+  HEAP32[i3 + 4 >> 2] = i5;
+  _lua_pushfstring(i1, 1160, i3) | 0;
+  STACKTOP = i4;
+  return;
+ }
+ _lua_pushlstring(i1, 1168, 0) | 0;
+ STACKTOP = i4;
+ return;
+}
+function _hookf(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_getsubtable(i1, -1001e3, 11584) | 0;
+ _lua_pushthread(i1) | 0;
+ _lua_rawget(i1, -2);
+ if ((_lua_type(i1, -1) | 0) != 6) {
+  STACKTOP = i2;
+  return;
+ }
+ _lua_pushstring(i1, HEAP32[11608 + (HEAP32[i3 >> 2] << 2) >> 2] | 0) | 0;
+ i3 = HEAP32[i3 + 20 >> 2] | 0;
+ if ((i3 | 0) > -1) {
+  _lua_pushinteger(i1, i3);
+ } else {
+  _lua_pushnil(i1);
+ }
+ _lua_callk(i1, 2, 0, 0, 0);
+ STACKTOP = i2;
+ return;
+}
+function _luaV_tonumber(i5, i2) {
+ i5 = i5 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ i4 = HEAP32[i5 + 8 >> 2] | 0;
+ if ((i4 | 0) != 3) {
+  if ((i4 & 15 | 0) == 4 ? (i5 = HEAP32[i5 >> 2] | 0, (_luaO_str2d(i5 + 16 | 0, HEAP32[i5 + 12 >> 2] | 0, i3) | 0) != 0) : 0) {
+   HEAPF64[i2 >> 3] = +HEAPF64[i3 >> 3];
+   HEAP32[i2 + 8 >> 2] = 3;
+  } else {
+   i2 = 0;
+  }
+ } else {
+  i2 = i5;
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _luaO_arith(i3, d1, d2) {
+ i3 = i3 | 0;
+ d1 = +d1;
+ d2 = +d2;
+ switch (i3 | 0) {
+ case 4:
+  {
+   d1 = d1 - +Math_floor(+(d1 / d2)) * d2;
+   break;
+  }
+ case 6:
+  {
+   d1 = -d1;
+   break;
+  }
+ case 0:
+  {
+   d1 = d1 + d2;
+   break;
+  }
+ case 1:
+  {
+   d1 = d1 - d2;
+   break;
+  }
+ case 5:
+  {
+   d1 = +Math_pow(+d1, +d2);
+   break;
+  }
+ case 3:
+  {
+   d1 = d1 / d2;
+   break;
+  }
+ case 2:
+  {
+   d1 = d1 * d2;
+   break;
+  }
+ default:
+  {
+   d1 = 0.0;
+  }
+ }
+ return +d1;
+}
+function _luaB_coresume(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_tothread(i1, 1) | 0;
+ if ((i3 | 0) == 0) {
+  _luaL_argerror(i1, 1, 10856) | 0;
+ }
+ i3 = _auxresume(i1, i3, (_lua_gettop(i1) | 0) + -1 | 0) | 0;
+ if ((i3 | 0) < 0) {
+  _lua_pushboolean(i1, 0);
+  _lua_insert(i1, -2);
+  i3 = 2;
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  _lua_pushboolean(i1, 1);
+  _lua_insert(i1, ~i3);
+  i3 = i3 + 1 | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ return 0;
+}
+function _pairsmeta(i1, i5, i4, i3) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((_luaL_getmetafield(i1, 1, i5) | 0) != 0) {
+  _lua_pushvalue(i1, 1);
+  _lua_callk(i1, 1, 3, 0, 0);
+  STACKTOP = i2;
+  return;
+ }
+ _luaL_checktype(i1, 1, 5);
+ _lua_pushcclosure(i1, i3, 0);
+ _lua_pushvalue(i1, 1);
+ if ((i4 | 0) == 0) {
+  _lua_pushnil(i1);
+  STACKTOP = i2;
+  return;
+ } else {
+  _lua_pushinteger(i1, 0);
+  STACKTOP = i2;
+  return;
+ }
+}
+function _io_close(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ if ((_lua_type(i1, 1) | 0) == -1) {
+  _lua_getfield(i1, -1001e3, 2800);
+ }
+ if ((HEAP32[(_luaL_checkudata(i1, 1, 2832) | 0) + 4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 3080, i2) | 0;
+ }
+ i4 = (_luaL_checkudata(i1, 1, 2832) | 0) + 4 | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i4 >> 2] = 0;
+ i1 = FUNCTION_TABLE_ii[i3 & 255](i1) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _pack(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ _lua_createtable(i1, i3, 1);
+ _lua_pushinteger(i1, i3);
+ _lua_setfield(i1, -2, 8312);
+ if ((i3 | 0) <= 0) {
+  STACKTOP = i2;
+  return 1;
+ }
+ _lua_pushvalue(i1, 1);
+ _lua_rawseti(i1, -2, 1);
+ _lua_replace(i1, 1);
+ if ((i3 | 0) <= 1) {
+  STACKTOP = i2;
+  return 1;
+ }
+ do {
+  _lua_rawseti(i1, 1, i3);
+  i3 = i3 + -1 | 0;
+ } while ((i3 | 0) > 1);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaL_execresult(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((i3 | 0) == -1) {
+  i3 = HEAP32[(___errno_location() | 0) >> 2] | 0;
+  _lua_pushnil(i1);
+  _lua_pushstring(i1, _strerror(i3 | 0) | 0) | 0;
+  _lua_pushinteger(i1, i3);
+  STACKTOP = i2;
+  return 3;
+ } else if ((i3 | 0) == 0) {
+  _lua_pushboolean(i1, 1);
+ } else {
+  _lua_pushnil(i1);
+ }
+ _lua_pushstring(i1, 1184) | 0;
+ _lua_pushinteger(i1, i3);
+ STACKTOP = i2;
+ return 3;
+}
+function _lua_getglobal(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i3 = STACKTOP;
+ i4 = _luaH_getint(HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 40 >> 2] | 0, 2) | 0;
+ i5 = i1 + 8 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i6 + 16;
+ i2 = _luaS_new(i1, i2) | 0;
+ HEAP32[i6 >> 2] = i2;
+ HEAP32[i6 + 8 >> 2] = HEAPU8[i2 + 4 | 0] | 0 | 64;
+ i2 = (HEAP32[i5 >> 2] | 0) + -16 | 0;
+ _luaV_gettable(i1, i4, i2, i2);
+ STACKTOP = i3;
+ return;
+}
+function _luaL_checktype(i1, i5, i4) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ if ((_lua_type(i1, i5) | 0) == (i4 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i6 = _lua_typename(i1, i4) | 0;
+ i4 = _lua_typename(i1, _lua_type(i1, i5) | 0) | 0;
+ HEAP32[i3 >> 2] = i6;
+ HEAP32[i3 + 4 >> 2] = i4;
+ _luaL_argerror(i1, i5, _lua_pushfstring(i1, 1744, i3) | 0) | 0;
+ STACKTOP = i2;
+ return;
+}
+function _luaC_newobj(i7, i4, i6, i5, i1) {
+ i7 = i7 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i7 + 12 >> 2] | 0;
+ i7 = _luaM_realloc_(i7, 0, i4 & 15, i6) | 0;
+ i6 = i7 + i1 | 0;
+ i5 = (i5 | 0) == 0 ? i3 + 68 | 0 : i5;
+ HEAP8[i7 + (i1 + 5) | 0] = HEAP8[i3 + 60 | 0] & 3;
+ HEAP8[i7 + (i1 + 4) | 0] = i4;
+ HEAP32[i6 >> 2] = HEAP32[i5 >> 2];
+ HEAP32[i5 >> 2] = i6;
+ STACKTOP = i2;
+ return i6 | 0;
+}
+function _luaL_requiref(i1, i3, i5, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushcclosure(i1, i5, 0);
+ _lua_pushstring(i1, i3) | 0;
+ _lua_callk(i1, 1, 1, 0, 0);
+ _luaL_getsubtable(i1, -1001e3, 1432) | 0;
+ _lua_pushvalue(i1, -2);
+ _lua_setfield(i1, -2, i3);
+ _lua_settop(i1, -2);
+ if ((i4 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ _lua_pushvalue(i1, -1);
+ _lua_setglobal(i1, i3);
+ STACKTOP = i2;
+ return;
+}
+function _luaG_ordererror(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = HEAP32[8528 + ((HEAP32[i3 + 8 >> 2] & 15) + 1 << 2) >> 2] | 0;
+ i4 = HEAP32[8528 + ((HEAP32[i4 + 8 >> 2] & 15) + 1 << 2) >> 2] | 0;
+ if ((i3 | 0) == (i4 | 0)) {
+  HEAP32[i2 >> 2] = i3;
+  _luaG_runerror(i1, 1952, i2);
+ } else {
+  HEAP32[i2 >> 2] = i3;
+  HEAP32[i2 + 4 >> 2] = i4;
+  _luaG_runerror(i1, 1992, i2);
+ }
+}
+function _io_popen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _luaL_checklstring(i1, 1, 0) | 0;
+ _luaL_optlstring(i1, 2, 3480, 0) | 0;
+ i5 = _lua_newuserdata(i1, 8) | 0;
+ i4 = i5 + 4 | 0;
+ HEAP32[i4 >> 2] = 0;
+ _luaL_setmetatable(i1, 2832);
+ _luaL_error(i1, 3488, i2) | 0;
+ HEAP32[i5 >> 2] = 0;
+ HEAP32[i4 >> 2] = 157;
+ i1 = _luaL_fileresult(i1, 0, i3) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _sort_comp(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((_lua_type(i1, 2) | 0) == 0) {
+  i4 = _lua_compare(i1, i3, i4, 1) | 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else {
+  _lua_pushvalue(i1, 2);
+  _lua_pushvalue(i1, i3 + -1 | 0);
+  _lua_pushvalue(i1, i4 + -2 | 0);
+  _lua_callk(i1, 2, 1, 0, 0);
+  i4 = _lua_toboolean(i1, -1) | 0;
+  _lua_settop(i1, -2);
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ return 0;
+}
+function _db_upvalueid(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i4 = i3;
+ i2 = _luaL_checkinteger(i1, 2) | 0;
+ _luaL_checktype(i1, 1, 6);
+ _lua_pushvalue(i1, 1);
+ _lua_getinfo(i1, 11728, i4) | 0;
+ if (!((i2 | 0) > 0 ? (i2 | 0) <= (HEAPU8[i4 + 32 | 0] | 0 | 0) : 0)) {
+  _luaL_argerror(i1, 2, 11736) | 0;
+ }
+ _lua_pushlightuserdata(i1, _lua_upvalueid(i1, 1, i2) | 0);
+ STACKTOP = i3;
+ return 1;
+}
+function _luaL_getmetafield(i2, i4, i3) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0;
+ i1 = STACKTOP;
+ do {
+  if ((_lua_getmetatable(i2, i4) | 0) != 0) {
+   _lua_pushstring(i2, i3) | 0;
+   _lua_rawget(i2, -2);
+   if ((_lua_type(i2, -1) | 0) == 0) {
+    _lua_settop(i2, -3);
+    i2 = 0;
+    break;
+   } else {
+    _lua_remove(i2, -2);
+    i2 = 1;
+    break;
+   }
+  } else {
+   i2 = 0;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _luaF_freeupval(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[i3 + 8 >> 2] | 0) == (i3 + 16 | 0)) {
+  _luaM_realloc_(i1, i3, 32, 0) | 0;
+  STACKTOP = i2;
+  return;
+ }
+ i4 = i3 + 16 | 0;
+ i5 = i4 + 4 | 0;
+ HEAP32[(HEAP32[i5 >> 2] | 0) + 16 >> 2] = HEAP32[i4 >> 2];
+ HEAP32[(HEAP32[i4 >> 2] | 0) + 20 >> 2] = HEAP32[i5 >> 2];
+ _luaM_realloc_(i1, i3, 32, 0) | 0;
+ STACKTOP = i2;
+ return;
+}
+function _luaL_addvalue(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i5 = HEAP32[i1 + 12 >> 2] | 0;
+ i3 = _lua_tolstring(i5, -1, i4) | 0;
+ i6 = i1 + 16 | 0;
+ if ((HEAP32[i1 >> 2] | 0) != (i6 | 0)) {
+  _lua_insert(i5, -2);
+ }
+ _luaL_addlstring(i1, i3, HEAP32[i4 >> 2] | 0);
+ _lua_remove(i5, (HEAP32[i1 >> 2] | 0) != (i6 | 0) ? -2 : -1);
+ STACKTOP = i2;
+ return;
+}
+function _escerror(i1, i4, i3, i2) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i5 = 0, i6 = 0;
+ HEAP32[(HEAP32[i1 + 60 >> 2] | 0) + 4 >> 2] = 0;
+ _save(i1, 92);
+ L1 : do {
+  if ((i3 | 0) > 0) {
+   i5 = 0;
+   do {
+    i6 = HEAP32[i4 + (i5 << 2) >> 2] | 0;
+    if ((i6 | 0) == -1) {
+     break L1;
+    }
+    _save(i1, i6);
+    i5 = i5 + 1 | 0;
+   } while ((i5 | 0) < (i3 | 0));
+  }
+ } while (0);
+ _lexerror(i1, i2, 289);
+}
+function _pushglobalfuncname(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ _lua_getinfo(i1, 1768, i4) | 0;
+ _lua_rawgeti(i1, -1001e3, 2);
+ i4 = i3 + 1 | 0;
+ if ((_findfield(i1, i4, 2) | 0) == 0) {
+  _lua_settop(i1, i3);
+  i4 = 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else {
+  _lua_copy(i1, -1, i4);
+  _lua_settop(i1, -3);
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ return 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function _lua_pushlstring(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i1);
+ }
+ i4 = _luaS_newlstr(i1, i3, i4) | 0;
+ i3 = i1 + 8 | 0;
+ i1 = HEAP32[i3 >> 2] | 0;
+ HEAP32[i1 >> 2] = i4;
+ HEAP32[i1 + 8 >> 2] = HEAPU8[i4 + 4 | 0] | 0 | 64;
+ HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + 16;
+ STACKTOP = i2;
+ return i4 + 16 | 0;
+}
+function _ll_searchpath(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i5 = _luaL_checklstring(i1, 1, 0) | 0;
+ i4 = _luaL_checklstring(i1, 2, 0) | 0;
+ i3 = _luaL_optlstring(i1, 3, 4936, 0) | 0;
+ if ((_searchpath(i1, i5, i4, i3, _luaL_optlstring(i1, 4, 4848, 0) | 0) | 0) != 0) {
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ _lua_pushnil(i1);
+ _lua_insert(i1, -2);
+ i5 = 2;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _math_log(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0, d4 = 0.0;
+ i2 = STACKTOP;
+ d3 = +_luaL_checknumber(i1, 1);
+ do {
+  if ((_lua_type(i1, 2) | 0) >= 1) {
+   d4 = +_luaL_checknumber(i1, 2);
+   if (d4 == 10.0) {
+    d3 = +_log10(+d3);
+    break;
+   } else {
+    d3 = +Math_log(+d3) / +Math_log(+d4);
+    break;
+   }
+  } else {
+   d3 = +Math_log(+d3);
+  }
+ } while (0);
+ _lua_pushnumber(i1, d3);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaT_init(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i3 = i1 + 12 | 0;
+ i4 = 0;
+ do {
+  i5 = _luaS_new(i1, HEAP32[8576 + (i4 << 2) >> 2] | 0) | 0;
+  HEAP32[(HEAP32[i3 >> 2] | 0) + (i4 << 2) + 184 >> 2] = i5;
+  i5 = (HEAP32[(HEAP32[i3 >> 2] | 0) + (i4 << 2) + 184 >> 2] | 0) + 5 | 0;
+  HEAP8[i5] = HEAPU8[i5] | 0 | 32;
+  i4 = i4 + 1 | 0;
+ } while ((i4 | 0) != 17);
+ STACKTOP = i2;
+ return;
+}
+function _f_gc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checkudata(i1, 1, 2832) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  STACKTOP = i2;
+  return 0;
+ }
+ if ((HEAP32[i3 >> 2] | 0) == 0) {
+  STACKTOP = i2;
+  return 0;
+ }
+ i4 = (_luaL_checkudata(i1, 1, 2832) | 0) + 4 | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i4 >> 2] = 0;
+ FUNCTION_TABLE_ii[i3 & 255](i1) | 0;
+ STACKTOP = i2;
+ return 0;
+}
+function ___shlim(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i2 = STACKTOP;
+ HEAP32[i1 + 104 >> 2] = i5;
+ i4 = HEAP32[i1 + 8 >> 2] | 0;
+ i3 = HEAP32[i1 + 4 >> 2] | 0;
+ i6 = i4 - i3 | 0;
+ HEAP32[i1 + 108 >> 2] = i6;
+ if ((i5 | 0) != 0 & (i6 | 0) > (i5 | 0)) {
+  HEAP32[i1 + 100 >> 2] = i3 + i5;
+  STACKTOP = i2;
+  return;
+ } else {
+  HEAP32[i1 + 100 >> 2] = i4;
+  STACKTOP = i2;
+  return;
+ }
+}
+function _lua_sethook(i4, i6, i1, i5) {
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = (i6 | 0) == 0 | (i1 | 0) == 0;
+ i3 = HEAP32[i4 + 16 >> 2] | 0;
+ if (!((HEAP8[i3 + 18 | 0] & 1) == 0)) {
+  HEAP32[i4 + 20 >> 2] = HEAP32[i3 + 28 >> 2];
+ }
+ HEAP32[i4 + 52 >> 2] = i2 ? 0 : i6;
+ HEAP32[i4 + 44 >> 2] = i5;
+ HEAP32[i4 + 48 >> 2] = i5;
+ HEAP8[i4 + 40 | 0] = i2 ? 0 : i1 & 255;
+ return 1;
+}
+function _io_tmpfile(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = _lua_newuserdata(i1, 8) | 0;
+ i3 = i4 + 4 | 0;
+ HEAP32[i3 >> 2] = 0;
+ _luaL_setmetatable(i1, 2832);
+ HEAP32[i4 >> 2] = 0;
+ HEAP32[i3 >> 2] = 156;
+ i3 = _tmpfile() | 0;
+ HEAP32[i4 >> 2] = i3;
+ if ((i3 | 0) != 0) {
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ i4 = _luaL_fileresult(i1, 0, 0) | 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _luaL_checkstack(i1, i5, i4) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ if ((_lua_checkstack(i1, i5 + 20 | 0) | 0) != 0) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((i4 | 0) == 0) {
+  _luaL_error(i1, 1240, i3) | 0;
+  STACKTOP = i2;
+  return;
+ } else {
+  HEAP32[i3 >> 2] = i4;
+  _luaL_error(i1, 1216, i3) | 0;
+  STACKTOP = i2;
+  return;
+ }
+}
+function _b_rshift(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i4 = _luaL_checkunsigned(i1, 1) | 0;
+ i3 = _luaL_checkinteger(i1, 2) | 0;
+ i5 = 0 - i3 | 0;
+ if ((i3 | 0) > 0) {
+  i5 = (i3 | 0) > 31 ? 0 : i4 >>> i3;
+  _lua_pushunsigned(i1, i5);
+  STACKTOP = i2;
+  return 1;
+ } else {
+  i5 = (i5 | 0) > 31 ? 0 : i4 << i5;
+  _lua_pushunsigned(i1, i5);
+  STACKTOP = i2;
+  return 1;
+ }
+ return 0;
+}
+function _b_lshift(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checkunsigned(i1, 1) | 0;
+ i4 = _luaL_checkinteger(i1, 2) | 0;
+ if ((i4 | 0) < 0) {
+  i4 = 0 - i4 | 0;
+  i4 = (i4 | 0) > 31 ? 0 : i3 >>> i4;
+  _lua_pushunsigned(i1, i4);
+  STACKTOP = i2;
+  return 1;
+ } else {
+  i4 = (i4 | 0) > 31 ? 0 : i3 << i4;
+  _lua_pushunsigned(i1, i4);
+  STACKTOP = i2;
+  return 1;
+ }
+ return 0;
+}
+function _math_min(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, d5 = 0.0, d6 = 0.0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ d5 = +_luaL_checknumber(i1, 1);
+ if ((i3 | 0) >= 2) {
+  i4 = 2;
+  while (1) {
+   d6 = +_luaL_checknumber(i1, i4);
+   d5 = d6 < d5 ? d6 : d5;
+   if ((i4 | 0) == (i3 | 0)) {
+    break;
+   } else {
+    i4 = i4 + 1 | 0;
+   }
+  }
+ }
+ _lua_pushnumber(i1, d5);
+ STACKTOP = i2;
+ return 1;
+}
+function _math_max(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, d5 = 0.0, d6 = 0.0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ d5 = +_luaL_checknumber(i1, 1);
+ if ((i3 | 0) >= 2) {
+  i4 = 2;
+  while (1) {
+   d6 = +_luaL_checknumber(i1, i4);
+   d5 = d6 > d5 ? d6 : d5;
+   if ((i4 | 0) == (i3 | 0)) {
+    break;
+   } else {
+    i4 = i4 + 1 | 0;
+   }
+  }
+ }
+ _lua_pushnumber(i1, d5);
+ STACKTOP = i2;
+ return 1;
+}
+function _io_type(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 1);
+ i3 = _luaL_testudata(i1, 1, 2832) | 0;
+ if ((i3 | 0) == 0) {
+  _lua_pushnil(i1);
+  STACKTOP = i2;
+  return 1;
+ }
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  _lua_pushlstring(i1, 3456, 11) | 0;
+  STACKTOP = i2;
+  return 1;
+ } else {
+  _lua_pushlstring(i1, 3472, 4) | 0;
+  STACKTOP = i2;
+  return 1;
+ }
+ return 0;
+}
+function _luaF_newLclosure(i3, i2) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i3 = _luaC_newobj(i3, 6, (i2 << 2) + 16 | 0, 0, 0) | 0;
+ HEAP32[i3 + 12 >> 2] = 0;
+ HEAP8[i3 + 6 | 0] = i2;
+ if ((i2 | 0) == 0) {
+  STACKTOP = i1;
+  return i3 | 0;
+ }
+ i4 = i3 + 16 | 0;
+ do {
+  i2 = i2 + -1 | 0;
+  HEAP32[i4 + (i2 << 2) >> 2] = 0;
+ } while ((i2 | 0) != 0);
+ STACKTOP = i1;
+ return i3 | 0;
+}
+function _io_flush(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ _lua_getfield(i1, -1001e3, 2800);
+ i3 = _lua_touserdata(i1, -1) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  HEAP32[i4 >> 2] = 2804;
+  _luaL_error(i1, 3424, i4) | 0;
+ }
+ i4 = _luaL_fileresult(i1, (_fflush(HEAP32[i3 >> 2] | 0) | 0) == 0 | 0, 0) | 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _b_test(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ if ((i3 | 0) < 1) {
+  i3 = 1;
+ } else {
+  i4 = 1;
+  i5 = -1;
+  while (1) {
+   i5 = (_luaL_checkunsigned(i1, i4) | 0) & i5;
+   if ((i4 | 0) == (i3 | 0)) {
+    break;
+   } else {
+    i4 = i4 + 1 | 0;
+   }
+  }
+  i3 = (i5 | 0) != 0;
+ }
+ _lua_pushboolean(i1, i3 & 1);
+ STACKTOP = i2;
+ return 1;
+}
+function ___muldsi3(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i6 = i2 & 65535;
+ i4 = i1 & 65535;
+ i3 = Math_imul(i4, i6) | 0;
+ i5 = i2 >>> 16;
+ i4 = (i3 >>> 16) + (Math_imul(i4, i5) | 0) | 0;
+ i1 = i1 >>> 16;
+ i2 = Math_imul(i1, i6) | 0;
+ return (tempRet0 = (i4 >>> 16) + (Math_imul(i1, i5) | 0) + (((i4 & 65535) + i2 | 0) >>> 16) | 0, i4 + i2 << 16 | i3 & 65535 | 0) | 0;
+}
+function _str_dump(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i3 = i2 + 8 | 0;
+ _luaL_checktype(i1, 1, 6);
+ _lua_settop(i1, 1);
+ _luaL_buffinit(i1, i3);
+ if ((_lua_dump(i1, 2, i3) | 0) == 0) {
+  _luaL_pushresult(i3);
+  i3 = 1;
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  i3 = _luaL_error(i1, 7888, i2) | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ return 0;
+}
+function ___memrchr(i2, i3, i5) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i3 = i3 & 255;
+ while (1) {
+  i4 = i5 + -1 | 0;
+  if ((i5 | 0) == 0) {
+   i5 = 0;
+   i2 = 4;
+   break;
+  }
+  i5 = i2 + i4 | 0;
+  if ((HEAP8[i5] | 0) == i3 << 24 >> 24) {
+   i2 = 4;
+   break;
+  } else {
+   i5 = i4;
+  }
+ }
+ if ((i2 | 0) == 4) {
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _luaL_getsubtable(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_getfield(i1, i3, i4);
+ if ((_lua_type(i1, -1) | 0) == 5) {
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ _lua_settop(i1, -2);
+ i3 = _lua_absindex(i1, i3) | 0;
+ _lua_createtable(i1, 0, 0);
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, i3, i4);
+ i4 = 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _luaE_freeCI(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = (HEAP32[i1 + 16 >> 2] | 0) + 12 | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i4 >> 2] = 0;
+ if ((i3 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ while (1) {
+  i4 = HEAP32[i3 + 12 >> 2] | 0;
+  _luaM_realloc_(i1, i3, 40, 0) | 0;
+  if ((i4 | 0) == 0) {
+   break;
+  } else {
+   i3 = i4;
+  }
+ }
+ STACKTOP = i2;
+ return;
+}
+function _f_tostring(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i4 = _luaL_checkudata(i1, 1, 2832) | 0;
+ if ((HEAP32[i4 + 4 >> 2] | 0) == 0) {
+  _lua_pushlstring(i1, 3040, 13) | 0;
+  STACKTOP = i2;
+  return 1;
+ } else {
+  HEAP32[i3 >> 2] = HEAP32[i4 >> 2];
+  _lua_pushfstring(i1, 3056, i3) | 0;
+  STACKTOP = i2;
+  return 1;
+ }
+ return 0;
+}
+function _lua_newuserdata(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i1);
+ }
+ i3 = _luaS_newudata(i1, i3, 0) | 0;
+ i1 = i1 + 8 | 0;
+ i4 = HEAP32[i1 >> 2] | 0;
+ HEAP32[i4 >> 2] = i3;
+ HEAP32[i4 + 8 >> 2] = 71;
+ HEAP32[i1 >> 2] = (HEAP32[i1 >> 2] | 0) + 16;
+ STACKTOP = i2;
+ return i3 + 24 | 0;
+}
+function _luaL_pushresultsize(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i5 = i1 + 8 | 0;
+ i4 = (HEAP32[i5 >> 2] | 0) + i3 | 0;
+ HEAP32[i5 >> 2] = i4;
+ i3 = HEAP32[i1 + 12 >> 2] | 0;
+ _lua_pushlstring(i3, HEAP32[i1 >> 2] | 0, i4) | 0;
+ if ((HEAP32[i1 >> 2] | 0) == (i1 + 16 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ _lua_remove(i3, -2);
+ STACKTOP = i2;
+ return;
+}
+function _luaL_testudata(i2, i5, i4) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i3 = _lua_touserdata(i2, i5) | 0;
+ if ((i3 | 0) != 0 ? (_lua_getmetatable(i2, i5) | 0) != 0 : 0) {
+  _lua_getfield(i2, -1001e3, i4);
+  i5 = (_lua_rawequal(i2, -1, -2) | 0) == 0;
+  _lua_settop(i2, -3);
+  i2 = i5 ? 0 : i3;
+ } else {
+  i2 = 0;
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _finishpcall(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((_lua_checkstack(i1, 1) | 0) == 0) {
+  _lua_settop(i1, 0);
+  _lua_pushboolean(i1, 0);
+  _lua_pushstring(i1, 9632) | 0;
+  i3 = 2;
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  _lua_pushboolean(i1, i3);
+  _lua_replace(i1, 1);
+  i3 = _lua_gettop(i1) | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ return 0;
+}
+function _searcher_preload(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i3 = _luaL_checklstring(i1, 1, 0) | 0;
+ _lua_getfield(i1, -1001e3, 4592);
+ _lua_getfield(i1, -1, i3);
+ if ((_lua_type(i1, -1) | 0) != 0) {
+  STACKTOP = i2;
+  return 1;
+ }
+ HEAP32[i4 >> 2] = i3;
+ _lua_pushfstring(i1, 5096, i4) | 0;
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_auxwrap(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i3 = STACKTOP;
+ i2 = _lua_tothread(i1, -1001001) | 0;
+ i2 = _auxresume(i1, i2, _lua_gettop(i1) | 0) | 0;
+ if ((i2 | 0) >= 0) {
+  STACKTOP = i3;
+  return i2 | 0;
+ }
+ if ((_lua_isstring(i1, -1) | 0) == 0) {
+  _lua_error(i1) | 0;
+ }
+ _luaL_where(i1, 1);
+ _lua_insert(i1, -2);
+ _lua_concat(i1, 2);
+ _lua_error(i1) | 0;
+ return 0;
+}
+function _ll_loadlib(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checklstring(i1, 1, 0) | 0;
+ i3 = _ll_loadfunc(i1, i3, _luaL_checklstring(i1, 2, 0) | 0) | 0;
+ if ((i3 | 0) == 0) {
+  i3 = 1;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ _lua_pushnil(i1);
+ _lua_insert(i1, -2);
+ _lua_pushstring(i1, (i3 | 0) == 1 ? 5176 : 5184) | 0;
+ i3 = 3;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _luaS_hash(i2, i4, i3) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i5 = 0;
+ i1 = STACKTOP;
+ i5 = i3 ^ i4;
+ i3 = (i4 >>> 5) + 1 | 0;
+ if (i3 >>> 0 > i4 >>> 0) {
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ do {
+  i5 = (i5 << 5) + (i5 >>> 2) + (HEAPU8[i2 + (i4 + -1) | 0] | 0) ^ i5;
+  i4 = i4 - i3 | 0;
+ } while (!(i4 >>> 0 < i3 >>> 0));
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _b_and(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ if ((i3 | 0) < 1) {
+  i5 = -1;
+ } else {
+  i4 = 1;
+  i5 = -1;
+  while (1) {
+   i5 = (_luaL_checkunsigned(i1, i4) | 0) & i5;
+   if ((i4 | 0) == (i3 | 0)) {
+    break;
+   } else {
+    i4 = i4 + 1 | 0;
+   }
+  }
+ }
+ _lua_pushunsigned(i1, i5);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaopen_string(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 14);
+ _luaL_setfuncs(i1, 6920, 0);
+ _lua_createtable(i1, 0, 1);
+ _lua_pushlstring(i1, 7040, 0) | 0;
+ _lua_pushvalue(i1, -2);
+ _lua_setmetatable(i1, -2) | 0;
+ _lua_settop(i1, -2);
+ _lua_pushvalue(i1, -2);
+ _lua_setfield(i1, -2, 7048);
+ _lua_settop(i1, -2);
+ STACKTOP = i2;
+ return 1;
+}
+function _b_xor(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ if ((i3 | 0) < 1) {
+  i5 = 0;
+ } else {
+  i4 = 1;
+  i5 = 0;
+  while (1) {
+   i5 = (_luaL_checkunsigned(i1, i4) | 0) ^ i5;
+   if ((i4 | 0) == (i3 | 0)) {
+    break;
+   } else {
+    i4 = i4 + 1 | 0;
+   }
+  }
+ }
+ _lua_pushunsigned(i1, i5);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_assert(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ if ((_lua_toboolean(i1, 1) | 0) == 0) {
+  HEAP32[i3 >> 2] = _luaL_optlstring(i1, 2, 10216, 0) | 0;
+  i3 = _luaL_error(i1, 10208, i3) | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  i3 = _lua_gettop(i1) | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ return 0;
+}
+function _b_or(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ if ((i3 | 0) < 1) {
+  i5 = 0;
+ } else {
+  i4 = 1;
+  i5 = 0;
+  while (1) {
+   i5 = _luaL_checkunsigned(i1, i4) | 0 | i5;
+   if ((i4 | 0) == (i3 | 0)) {
+    break;
+   } else {
+    i4 = i4 + 1 | 0;
+   }
+  }
+ }
+ _lua_pushunsigned(i1, i5);
+ STACKTOP = i2;
+ return 1;
+}
+function _io_write(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ _lua_getfield(i1, -1001e3, 2800);
+ i3 = _lua_touserdata(i1, -1) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  HEAP32[i4 >> 2] = 2804;
+  _luaL_error(i1, 3424, i4) | 0;
+ }
+ i4 = _g_write(i1, HEAP32[i3 >> 2] | 0, 1) | 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _luaK_checkstack(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i3 = (HEAPU8[i1 + 48 | 0] | 0) + i3 | 0;
+ i4 = (HEAP32[i1 >> 2] | 0) + 78 | 0;
+ if ((i3 | 0) <= (HEAPU8[i4] | 0 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((i3 | 0) > 249) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10536);
+ }
+ HEAP8[i4] = i3;
+ STACKTOP = i2;
+ return;
+}
+function _io_read(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ _lua_getfield(i1, -1001e3, 2776);
+ i3 = _lua_touserdata(i1, -1) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  HEAP32[i4 >> 2] = 2780;
+  _luaL_error(i1, 3424, i4) | 0;
+ }
+ i4 = _g_read(i1, HEAP32[i3 >> 2] | 0, 1) | 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _db_setupvalue(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 3);
+ i3 = _luaL_checkinteger(i1, 2) | 0;
+ _luaL_checktype(i1, 1, 6);
+ i3 = _lua_setupvalue(i1, 1, i3) | 0;
+ if ((i3 | 0) == 0) {
+  i3 = 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ _lua_pushstring(i1, i3) | 0;
+ _lua_insert(i1, -1);
+ i3 = 1;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function ___uflow(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ if ((HEAP32[i2 + 8 >> 2] | 0) == 0 ? (___toread(i2) | 0) != 0 : 0) {
+  i2 = -1;
+ } else {
+  if ((FUNCTION_TABLE_iiii[HEAP32[i2 + 32 >> 2] & 3](i2, i3, 1) | 0) == 1) {
+   i2 = HEAPU8[i3] | 0;
+  } else {
+   i2 = -1;
+  }
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _llvm_cttz_i32(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = HEAP8[cttz_i8 + (i1 & 255) | 0] | 0;
+ if ((i2 | 0) < 8) return i2 | 0;
+ i2 = HEAP8[cttz_i8 + (i1 >> 8 & 255) | 0] | 0;
+ if ((i2 | 0) < 8) return i2 + 8 | 0;
+ i2 = HEAP8[cttz_i8 + (i1 >> 16 & 255) | 0] | 0;
+ if ((i2 | 0) < 8) return i2 + 16 | 0;
+ return (HEAP8[cttz_i8 + (i1 >>> 24) | 0] | 0) + 24 | 0;
+}
+function _llvm_ctlz_i32(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = HEAP8[ctlz_i8 + (i1 >>> 24) | 0] | 0;
+ if ((i2 | 0) < 8) return i2 | 0;
+ i2 = HEAP8[ctlz_i8 + (i1 >> 16 & 255) | 0] | 0;
+ if ((i2 | 0) < 8) return i2 + 8 | 0;
+ i2 = HEAP8[ctlz_i8 + (i1 >> 8 & 255) | 0] | 0;
+ if ((i2 | 0) < 8) return i2 + 16 | 0;
+ return (HEAP8[ctlz_i8 + (i1 & 255) | 0] | 0) + 24 | 0;
+}
+function _luaO_ceillog2(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i2 = i2 + -1 | 0;
+ if (i2 >>> 0 > 255) {
+  i3 = 0;
+  while (1) {
+   i3 = i3 + 8 | 0;
+   i4 = i2 >>> 8;
+   if (i2 >>> 0 > 65535) {
+    i2 = i4;
+   } else {
+    i2 = i4;
+    break;
+   }
+  }
+ } else {
+  i3 = 0;
+ }
+ STACKTOP = i1;
+ return (HEAPU8[5208 + i2 | 0] | 0) + i3 | 0;
+}
+function _os_exit(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ if ((_lua_type(i1, 1) | 0) == 1) {
+  i3 = (_lua_toboolean(i1, 1) | 0) == 0 | 0;
+ } else {
+  i3 = _luaL_optinteger(i1, 1, 0) | 0;
+ }
+ if ((_lua_toboolean(i1, 2) | 0) != 0) {
+  _lua_close(i1);
+ }
+ if ((i1 | 0) == 0) {
+  STACKTOP = i2;
+  return 0;
+ } else {
+  _exit(i3 | 0);
+ }
+ return 0;
+}
+function _luaL_newmetatable(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_getfield(i1, -1001e3, i3);
+ if ((_lua_type(i1, -1) | 0) != 0) {
+  i3 = 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ _lua_settop(i1, -2);
+ _lua_createtable(i1, 0, 0);
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, -1001e3, i3);
+ i3 = 1;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _luaH_free(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i4 + 16 >> 2] | 0;
+ if ((i3 | 0) != 8016) {
+  _luaM_realloc_(i1, i3, 32 << (HEAPU8[i4 + 7 | 0] | 0), 0) | 0;
+ }
+ _luaM_realloc_(i1, HEAP32[i4 + 12 >> 2] | 0, HEAP32[i4 + 28 >> 2] << 4, 0) | 0;
+ _luaM_realloc_(i1, i4, 32, 0) | 0;
+ STACKTOP = i2;
+ return;
+}
+function _luaO_int2fb(i3) {
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i1 = STACKTOP;
+ if (i3 >>> 0 < 8) {
+  STACKTOP = i1;
+  return i3 | 0;
+ }
+ if (i3 >>> 0 > 15) {
+  i2 = 1;
+  do {
+   i4 = i3 + 1 | 0;
+   i3 = i4 >>> 1;
+   i2 = i2 + 1 | 0;
+  } while (i4 >>> 0 > 31);
+  i2 = i2 << 3;
+ } else {
+  i2 = 8;
+ }
+ i4 = i2 | i3 + -8;
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _luaK_codek(i3, i4, i1) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i4 = i4 << 6;
+ if ((i1 | 0) < 262144) {
+  i4 = _luaK_code(i3, i4 | i1 << 14 | 1) | 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else {
+  i4 = _luaK_code(i3, i4 | 2) | 0;
+  _luaK_code(i3, i1 << 6 | 39) | 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ return 0;
+}
+function _luaB_xpcall(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ if ((i3 | 0) <= 1) {
+  _luaL_argerror(i1, 2, 9616) | 0;
+ }
+ _lua_pushvalue(i1, 1);
+ _lua_copy(i1, 2, 1);
+ _lua_replace(i1, 2);
+ i3 = _finishpcall(i1, (_lua_pcallk(i1, i3 + -2 | 0, -1, 1, 0, 166) | 0) == 0 | 0) | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _luaS_newudata(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if (i3 >>> 0 > 4294967269) {
+  _luaM_toobig(i1);
+ } else {
+  i1 = _luaC_newobj(i1, 7, i3 + 24 | 0, 0, 0) | 0;
+  HEAP32[i1 + 16 >> 2] = i3;
+  HEAP32[i1 + 8 >> 2] = 0;
+  HEAP32[i1 + 12 >> 2] = i4;
+  STACKTOP = i2;
+  return i1 | 0;
+ }
+ return 0;
+}
+function _lua_dump(i1, i4, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i1 + 8 >> 2] | 0;
+ if ((HEAP32[i3 + -8 >> 2] | 0) != 70) {
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ i5 = _luaU_dump(i1, HEAP32[(HEAP32[i3 + -16 >> 2] | 0) + 12 >> 2] | 0, i4, i5, 0) | 0;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _luaS_eqlngstr(i2, i4) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i3 = HEAP32[i2 + 12 >> 2] | 0;
+ if ((i2 | 0) != (i4 | 0)) {
+  if ((i3 | 0) == (HEAP32[i4 + 12 >> 2] | 0)) {
+   i2 = (_memcmp(i2 + 16 | 0, i4 + 16 | 0, i3) | 0) == 0;
+  } else {
+   i2 = 0;
+  }
+ } else {
+  i2 = 1;
+ }
+ STACKTOP = i1;
+ return i2 & 1 | 0;
+}
+function _luaC_barrier_(i4, i3, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i4 + 12 >> 2] | 0;
+ if ((HEAPU8[i4 + 61 | 0] | 0) < 2) {
+  _reallymarkobject(i4, i1);
+  STACKTOP = i2;
+  return;
+ } else {
+  i3 = i3 + 5 | 0;
+  HEAP8[i3] = HEAP8[i4 + 60 | 0] & 3 | HEAP8[i3] & 184;
+  STACKTOP = i2;
+  return;
+ }
+}
+function _db_getupvalue(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checkinteger(i1, 2) | 0;
+ _luaL_checktype(i1, 1, 6);
+ i3 = _lua_getupvalue(i1, 1, i3) | 0;
+ if ((i3 | 0) == 0) {
+  i3 = 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ _lua_pushstring(i1, i3) | 0;
+ _lua_insert(i1, -2);
+ i3 = 2;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _os_execute(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = _luaL_optlstring(i1, 1, 0, 0) | 0;
+ i3 = _system(i4 | 0) | 0;
+ if ((i4 | 0) == 0) {
+  _lua_pushboolean(i1, i3);
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else {
+  i4 = _luaL_execresult(i1, i3) | 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ return 0;
+}
+function _lua_pushfstring(i4, i5, i1) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ if ((HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i4);
+ }
+ HEAP32[i3 >> 2] = i1;
+ i5 = _luaO_pushvfstring(i4, i5, i3) | 0;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _luaB_dofile(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_optlstring(i1, 1, 0, 0) | 0;
+ _lua_settop(i1, 1);
+ if ((_luaL_loadfilex(i1, i3, 0) | 0) == 0) {
+  _lua_callk(i1, 0, -1, 0, 164);
+  i3 = (_lua_gettop(i1) | 0) + -1 | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  _lua_error(i1) | 0;
+ }
+ return 0;
+}
+function _f_write(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _luaL_checkudata(i1, 1, 2832) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 3080, i2) | 0;
+ }
+ i3 = HEAP32[i3 >> 2] | 0;
+ _lua_pushvalue(i1, 1);
+ i3 = _g_write(i1, i3, 2) | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _lua_getctx(i3, i1) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i3 + 16 >> 2] | 0;
+ if ((HEAP8[i3 + 18 | 0] & 8) == 0) {
+  i3 = 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ if ((i1 | 0) != 0) {
+  HEAP32[i1 >> 2] = HEAP32[i3 + 24 >> 2];
+ }
+ i3 = HEAPU8[i3 + 37 | 0] | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _f_flush(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _luaL_checkudata(i1, 1, 2832) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 3080, i2) | 0;
+ }
+ i3 = _luaL_fileresult(i1, (_fflush(HEAP32[i3 >> 2] | 0) | 0) == 0 | 0, 0) | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _os_tmpname(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i3 = i2 + 4 | 0;
+ if ((_tmpnam(i3 | 0) | 0) == 0) {
+  i3 = _luaL_error(i1, 5824, i2) | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  _lua_pushstring(i1, i3) | 0;
+  i3 = 1;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ return 0;
+}
+function _traceback(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_tolstring(i1, 1, 0) | 0;
+ if ((i3 | 0) == 0) {
+  if ((_lua_type(i1, 1) | 0) >= 1 ? (_luaL_callmeta(i1, 1, 216) | 0) == 0 : 0) {
+   _lua_pushlstring(i1, 232, 18) | 0;
+  }
+ } else {
+  _luaL_traceback(i1, i1, i3, 1);
+ }
+ STACKTOP = i2;
+ return 1;
+}
+function _luaH_new(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _luaC_newobj(i1, 5, 32, 0, 0) | 0;
+ HEAP32[i1 + 8 >> 2] = 0;
+ HEAP8[i1 + 6 | 0] = -1;
+ HEAP32[i1 + 12 >> 2] = 0;
+ HEAP32[i1 + 28 >> 2] = 0;
+ HEAP32[i1 + 16 >> 2] = 8016;
+ HEAP8[i1 + 7 | 0] = 0;
+ HEAP32[i1 + 20 >> 2] = 8016;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaL_len(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2 + 4 | 0;
+ _lua_len(i1, i3);
+ i3 = _lua_tointegerx(i1, -1, i4) | 0;
+ if ((HEAP32[i4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 1352, i2) | 0;
+ }
+ _lua_settop(i1, -2);
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _getS(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0, i5 = 0;
+ i3 = STACKTOP;
+ i5 = i2 + 4 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ if ((i4 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i3;
+  return i5 | 0;
+ }
+ HEAP32[i1 >> 2] = i4;
+ HEAP32[i5 >> 2] = 0;
+ i5 = HEAP32[i2 >> 2] | 0;
+ STACKTOP = i3;
+ return i5 | 0;
+}
+function _luaC_runtilstate(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = (HEAP32[i1 + 12 >> 2] | 0) + 61 | 0;
+ if ((1 << (HEAPU8[i3] | 0) & i4 | 0) != 0) {
+  STACKTOP = i2;
+  return;
+ }
+ do {
+  _singlestep(i1) | 0;
+ } while ((1 << (HEAPU8[i3] | 0) & i4 | 0) == 0);
+ STACKTOP = i2;
+ return;
+}
+function _luaX_init(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i3 = 0;
+ do {
+  i4 = _luaS_new(i1, HEAP32[12096 + (i3 << 2) >> 2] | 0) | 0;
+  i5 = i4 + 5 | 0;
+  HEAP8[i5] = HEAPU8[i5] | 0 | 32;
+  i3 = i3 + 1 | 0;
+  HEAP8[i4 + 6 | 0] = i3;
+ } while ((i3 | 0) != 22);
+ STACKTOP = i2;
+ return;
+}
+function _luaK_indexed(i5, i1, i4) {
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0;
+ i3 = STACKTOP;
+ i2 = i1 + 8 | 0;
+ HEAP8[i2 + 2 | 0] = HEAP32[i2 >> 2];
+ HEAP16[i2 >> 1] = _luaK_exp2RK(i5, i4) | 0;
+ HEAP8[i2 + 3 | 0] = (HEAP32[i1 >> 2] | 0) == 8 ? 8 : 7;
+ HEAP32[i1 >> 2] = 9;
+ STACKTOP = i3;
+ return;
+}
+function _db_setuservalue(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((_lua_type(i1, 1) | 0) == 2) {
+  _luaL_argerror(i1, 1, 11680) | 0;
+ }
+ _luaL_checktype(i1, 1, 7);
+ if ((_lua_type(i1, 2) | 0) >= 1) {
+  _luaL_checktype(i1, 2, 5);
+ }
+ _lua_settop(i1, 2);
+ _lua_setuservalue(i1, 1);
+ STACKTOP = i2;
+ return 1;
+}
+function _ll_seeall(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 5);
+ if ((_lua_getmetatable(i1, 1) | 0) == 0) {
+  _lua_createtable(i1, 0, 1);
+  _lua_pushvalue(i1, -1);
+  _lua_setmetatable(i1, 1) | 0;
+ }
+ _lua_rawgeti(i1, -1001e3, 2);
+ _lua_setfield(i1, -2, 5168);
+ STACKTOP = i2;
+ return 0;
+}
+function _luaL_loadbufferx(i3, i5, i4, i2, i1) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i6 = 0, i7 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i7 = i6;
+ HEAP32[i7 >> 2] = i5;
+ HEAP32[i7 + 4 >> 2] = i4;
+ i5 = _lua_load(i3, 2, i7, i2, i1) | 0;
+ STACKTOP = i6;
+ return i5 | 0;
+}
+function _luaT_gettm(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i4 = _luaH_getstr(i1, i4) | 0;
+ if ((HEAP32[i4 + 8 >> 2] | 0) != 0) {
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ i4 = i1 + 6 | 0;
+ HEAP8[i4] = HEAPU8[i4] | 0 | 1 << i3;
+ i4 = 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _luaL_pushresult(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i1 + 12 >> 2] | 0;
+ _lua_pushlstring(i3, HEAP32[i1 >> 2] | 0, HEAP32[i1 + 8 >> 2] | 0) | 0;
+ if ((HEAP32[i1 >> 2] | 0) == (i1 + 16 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ _lua_remove(i3, -2);
+ STACKTOP = i2;
+ return;
+}
+function _resume_error(i1, i3, i2) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i4 = 0;
+ i4 = i1 + 8 | 0;
+ HEAP32[i4 >> 2] = i2;
+ i3 = _luaS_new(i1, i3) | 0;
+ HEAP32[i2 >> 2] = i3;
+ HEAP32[i2 + 8 >> 2] = HEAPU8[i3 + 4 | 0] | 0 | 64;
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + 16;
+ _luaD_throw(i1, -1);
+}
+function _lua_absindex(i3, i1) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((i1 + 1000999 | 0) >>> 0 > 1000999) {
+  i3 = i1;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ i3 = ((HEAP32[i3 + 8 >> 2] | 0) - (HEAP32[HEAP32[i3 + 16 >> 2] >> 2] | 0) >> 4) + i1 | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function ___uremdi3(i4, i3, i2, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i5 = 0, i6 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 8 | 0;
+ i5 = i6 | 0;
+ ___udivmoddi4(i4, i3, i2, i1, i5) | 0;
+ STACKTOP = i6;
+ return (tempRet0 = HEAP32[i5 + 4 >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0;
+}
+function _f_read(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _luaL_checkudata(i1, 1, 2832) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 3080, i2) | 0;
+ }
+ i3 = _g_read(i1, HEAP32[i3 >> 2] | 0, 2) | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _sort(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 5);
+ i3 = _luaL_len(i1, 1) | 0;
+ _luaL_checkstack(i1, 40, 8208);
+ if ((_lua_type(i1, 2) | 0) >= 1) {
+  _luaL_checktype(i1, 2, 6);
+ }
+ _lua_settop(i1, 2);
+ _auxsort(i1, 1, i3);
+ STACKTOP = i2;
+ return 0;
+}
+function _luaB_error(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = _luaL_optinteger(i1, 2, 1) | 0;
+ _lua_settop(i1, 1);
+ if (!((_lua_isstring(i1, 1) | 0) != 0 & (i2 | 0) > 0)) {
+  _lua_error(i1) | 0;
+ }
+ _luaL_where(i1, i2);
+ _lua_pushvalue(i1, 1);
+ _lua_concat(i1, 2);
+ _lua_error(i1) | 0;
+ return 0;
+}
+function _error(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = HEAP32[i1 >> 2] | 0;
+ HEAP32[i3 >> 2] = HEAP32[i1 + 12 >> 2];
+ HEAP32[i3 + 4 >> 2] = i2;
+ _luaO_pushfstring(i4, 8840, i3) | 0;
+ _luaD_throw(HEAP32[i1 >> 2] | 0, 3);
+}
+function _ipairsaux(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checkinteger(i1, 2) | 0;
+ _luaL_checktype(i1, 1, 5);
+ i3 = i3 + 1 | 0;
+ _lua_pushinteger(i1, i3);
+ _lua_rawgeti(i1, 1, i3);
+ i1 = (_lua_type(i1, -1) | 0) == 0;
+ STACKTOP = i2;
+ return (i1 ? 1 : 2) | 0;
+}
+function _panic(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i3 = HEAP32[_stderr >> 2] | 0;
+ HEAP32[i4 >> 2] = _lua_tolstring(i1, -1, 0) | 0;
+ _fprintf(i3 | 0, 1656, i4 | 0) | 0;
+ _fflush(i3 | 0) | 0;
+ STACKTOP = i2;
+ return 0;
+}
+function _testSetjmp(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0;
+ while ((i3 | 0) < 20) {
+  i4 = HEAP32[i2 + (i3 << 2) >> 2] | 0;
+  if ((i4 | 0) == 0) break;
+  if ((i4 | 0) == (i1 | 0)) {
+   return HEAP32[i2 + ((i3 << 2) + 4) >> 2] | 0;
+  }
+  i3 = i3 + 2 | 0;
+ }
+ return 0;
+}
+function _luaopen_math(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 28);
+ _luaL_setfuncs(i1, 3576, 0);
+ _lua_pushnumber(i1, 3.141592653589793);
+ _lua_setfield(i1, -2, 3808);
+ _lua_pushnumber(i1, inf);
+ _lua_setfield(i1, -2, 3816);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaopen_base(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_rawgeti(i1, -1001e3, 2);
+ _lua_rawgeti(i1, -1001e3, 2);
+ _lua_setfield(i1, -2, 9144);
+ _luaL_setfuncs(i1, 9152, 0);
+ _lua_pushlstring(i1, 9344, 7) | 0;
+ _lua_setfield(i1, -2, 9352);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaE_extendCI(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i3 = STACKTOP;
+ i2 = _luaM_realloc_(i1, 0, 0, 40) | 0;
+ i1 = i1 + 16 | 0;
+ HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] = i2;
+ HEAP32[i2 + 8 >> 2] = HEAP32[i1 >> 2];
+ HEAP32[i2 + 12 >> 2] = 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _luaB_getmetatable(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 1);
+ if ((_lua_getmetatable(i1, 1) | 0) == 0) {
+  _lua_pushnil(i1);
+  STACKTOP = i2;
+  return 1;
+ } else {
+  _luaL_getmetafield(i1, 1, 9704) | 0;
+  STACKTOP = i2;
+  return 1;
+ }
+ return 0;
+}
+function _lua_pushunsigned(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var d3 = 0.0;
+ if ((i2 | 0) > -1) {
+  d3 = +(i2 | 0);
+ } else {
+  d3 = +(i2 >>> 0);
+ }
+ i2 = i1 + 8 | 0;
+ i1 = HEAP32[i2 >> 2] | 0;
+ HEAPF64[i1 >> 3] = d3;
+ HEAP32[i1 + 8 >> 2] = 3;
+ HEAP32[i2 >> 2] = i1 + 16;
+ return;
+}
+function _lua_pushthread(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = i1 + 8 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ HEAP32[i3 >> 2] = i1;
+ HEAP32[i3 + 8 >> 2] = 72;
+ HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + 16;
+ return (HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 172 >> 2] | 0) == (i1 | 0) | 0;
+}
+function _gctm(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_len(i1, 1) | 0;
+ if ((i3 | 0) <= 0) {
+  STACKTOP = i2;
+  return 0;
+ }
+ do {
+  _lua_rawgeti(i1, 1, i3);
+  _lua_settop(i1, -2);
+  i3 = i3 + -1 | 0;
+ } while ((i3 | 0) > 0);
+ STACKTOP = i2;
+ return 0;
+}
+function ___muldi3(i4, i2, i3, i1) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0, i6 = 0;
+ i5 = i4;
+ i6 = i3;
+ i4 = ___muldsi3(i5, i6) | 0;
+ i3 = tempRet0;
+ return (tempRet0 = (Math_imul(i2, i6) | 0) + (Math_imul(i1, i5) | 0) + i3 | i3 & 0, i4 | 0 | 0) | 0;
+}
+function _luaH_resizearray(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i5 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[i3 + 16 >> 2] | 0) == 8016) {
+  i5 = 0;
+ } else {
+  i5 = 1 << (HEAPU8[i3 + 7 | 0] | 0);
+ }
+ _luaH_resize(i1, i3, i4, i5);
+ STACKTOP = i2;
+ return;
+}
+function _luaK_stringK(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i3;
+ HEAP32[i4 >> 2] = i2;
+ HEAP32[i4 + 8 >> 2] = HEAPU8[i2 + 4 | 0] | 0 | 64;
+ i2 = _addk(i1, i4, i4) | 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _math_modf(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ d3 = +_modf(+(+_luaL_checknumber(i1, 1)), i4 | 0);
+ _lua_pushnumber(i1, +HEAPF64[i4 >> 3]);
+ _lua_pushnumber(i1, d3);
+ STACKTOP = i2;
+ return 2;
+}
+function _os_setlocale(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_optlstring(i1, 1, 0, 0) | 0;
+ _lua_pushstring(i1, _setlocale(HEAP32[5960 + ((_luaL_checkoption(i1, 2, 6016, 5984) | 0) << 2) >> 2] | 0, i3 | 0) | 0) | 0;
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_pcall(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 1);
+ _lua_pushnil(i1);
+ _lua_insert(i1, 1);
+ i1 = _finishpcall(i1, (_lua_pcallk(i1, (_lua_gettop(i1) | 0) + -2 | 0, -1, 0, 0, 166) | 0) == 0 | 0) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _error_expected(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = HEAP32[i1 + 52 >> 2] | 0;
+ HEAP32[i3 >> 2] = _luaX_token2str(i1, i2) | 0;
+ _luaX_syntaxerror(i1, _luaO_pushfstring(i4, 6328, i3) | 0);
+}
+function _lua_pushvfstring(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i1);
+ }
+ i4 = _luaO_pushvfstring(i1, i3, i4) | 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _db_setmetatable(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_type(i1, 2) | 0;
+ if (!((i3 | 0) == 0 | (i3 | 0) == 5)) {
+  _luaL_argerror(i1, 2, 11536) | 0;
+ }
+ _lua_settop(i1, 2);
+ _lua_setmetatable(i1, 1) | 0;
+ STACKTOP = i2;
+ return 1;
+}
+function _b_rrot(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i3 = 0 - (_luaL_checkinteger(i1, 2) | 0) | 0;
+ i4 = _luaL_checkunsigned(i1, 1) | 0;
+ i3 = i3 & 31;
+ _lua_pushunsigned(i1, i4 >>> (32 - i3 | 0) | i4 << i3);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaC_step(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i1 + 12 >> 2] | 0;
+ if ((HEAP8[i3 + 63 | 0] | 0) == 0) {
+  _luaE_setdebt(i3, -1600);
+  STACKTOP = i2;
+  return;
+ } else {
+  _luaC_forcestep(i1);
+  STACKTOP = i2;
+  return;
+ }
+}
+function _math_frexp(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ _lua_pushnumber(i1, +_frexp(+(+_luaL_checknumber(i1, 1)), i3 | 0));
+ _lua_pushinteger(i1, HEAP32[i3 >> 2] | 0);
+ STACKTOP = i2;
+ return 2;
+}
+function _luaO_pushfstring(i2, i1, i3) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i4 = 0, i5 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i4;
+ HEAP32[i5 >> 2] = i3;
+ i3 = _luaO_pushvfstring(i2, i1, i5) | 0;
+ STACKTOP = i4;
+ return i3 | 0;
+}
+function _luaO_hexavalue(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((HEAP8[i1 + 10913 | 0] & 2) == 0) {
+  i1 = (i1 | 32) + -87 | 0;
+  STACKTOP = i2;
+  return i1 | 0;
+ } else {
+  i1 = i1 + -48 | 0;
+  STACKTOP = i2;
+  return i1 | 0;
+ }
+ return 0;
+}
+function _b_lrot(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checkinteger(i1, 2) | 0;
+ i4 = _luaL_checkunsigned(i1, 1) | 0;
+ i3 = i3 & 31;
+ _lua_pushunsigned(i1, i4 >>> (32 - i3 | 0) | i4 << i3);
+ STACKTOP = i2;
+ return 1;
+}
+function _f_lines(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ if ((HEAP32[(_luaL_checkudata(i1, 1, 2832) | 0) + 4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 3080, i2) | 0;
+ }
+ _aux_lines(i1, 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaC_barrierback_(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i2 = HEAP32[i2 + 12 >> 2] | 0;
+ i3 = i1 + 5 | 0;
+ HEAP8[i3] = HEAP8[i3] & 251;
+ i2 = i2 + 88 | 0;
+ HEAP32[i1 + 24 >> 2] = HEAP32[i2 >> 2];
+ HEAP32[i2 >> 2] = i1;
+ return;
+}
+function _os_rename(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checklstring(i1, 1, 0) | 0;
+ i1 = _luaL_fileresult(i1, (_rename(i3 | 0, _luaL_checklstring(i1, 2, 0) | 0) | 0) == 0 | 0, 0) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _bitshift64Ashr(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ if ((i1 | 0) < 32) {
+  tempRet0 = i2 >> i1;
+  return i3 >>> i1 | (i2 & (1 << i1) - 1) << 32 - i1;
+ }
+ tempRet0 = (i2 | 0) < 0 ? -1 : 0;
+ return i2 >> i1 - 32 | 0;
+}
+function _luaB_cowrap(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 6);
+ i3 = _lua_newthread(i1) | 0;
+ _lua_pushvalue(i1, 1);
+ _lua_xmove(i1, i3, 1);
+ _lua_pushcclosure(i1, 167, 1);
+ STACKTOP = i2;
+ return 1;
+}
+function _gmatch(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checklstring(i1, 1, 0) | 0;
+ _luaL_checklstring(i1, 2, 0) | 0;
+ _lua_settop(i1, 2);
+ _lua_pushinteger(i1, 0);
+ _lua_pushcclosure(i1, 163, 3);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_next(i2) {
+ i2 = i2 | 0;
+ var i1 = 0;
+ i1 = STACKTOP;
+ _luaL_checktype(i2, 1, 5);
+ _lua_settop(i2, 2);
+ if ((_lua_next(i2, 1) | 0) == 0) {
+  _lua_pushnil(i2);
+  i2 = 1;
+ } else {
+  i2 = 2;
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _luaK_codeABC(i5, i3, i4, i2, i1) {
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i6 = 0;
+ i6 = STACKTOP;
+ i5 = _luaK_code(i5, i4 << 6 | i3 | i2 << 23 | i1 << 14) | 0;
+ STACKTOP = i6;
+ return i5 | 0;
+}
+function _luaH_set(i2, i4, i5) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i3 = _luaH_get(i4, i5) | 0;
+ if ((i3 | 0) == 5192) {
+  i3 = _luaH_newkey(i2, i4, i5) | 0;
+ }
+ STACKTOP = i1;
+ return i3 | 0;
+}
+function _luaZ_init(i4, i1, i3, i2) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ HEAP32[i1 + 16 >> 2] = i4;
+ HEAP32[i1 + 8 >> 2] = i3;
+ HEAP32[i1 + 12 >> 2] = i2;
+ HEAP32[i1 >> 2] = 0;
+ HEAP32[i1 + 4 >> 2] = 0;
+ return;
+}
+function _lua_pushlightuserdata(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i2 = i2 + 8 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ HEAP32[i3 >> 2] = i1;
+ HEAP32[i3 + 8 >> 2] = 2;
+ HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + 16;
+ return;
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function _bitshift64Shl(i2, i3, i1) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ if ((i1 | 0) < 32) {
+  tempRet0 = i3 << i1 | (i2 & (1 << i1) - 1 << 32 - i1) >>> 32 - i1;
+  return i2 << i1;
+ }
+ tempRet0 = i2 << i1 - 32;
+ return 0;
+}
+function _luaB_rawlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if (((_lua_type(i1, 1) | 0) & -2 | 0) != 4) {
+  _luaL_argerror(i1, 1, 9784) | 0;
+ }
+ _lua_pushinteger(i1, _lua_rawlen(i1, 1) | 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _l_alloc(i3, i1, i4, i2) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i3 = STACKTOP;
+ if ((i2 | 0) == 0) {
+  _free(i1);
+  i1 = 0;
+ } else {
+  i1 = _realloc(i1, i2) | 0;
+ }
+ STACKTOP = i3;
+ return i1 | 0;
+}
+function _bitshift64Lshr(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ if ((i1 | 0) < 32) {
+  tempRet0 = i2 >>> i1;
+  return i3 >>> i1 | (i2 & (1 << i1) - 1) << 32 - i1;
+ }
+ tempRet0 = 0;
+ return i2 >>> i1 - 32 | 0;
+}
+function _luaG_aritherror(i3, i1, i2) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i4 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = (_luaV_tonumber(i1, i4) | 0) == 0;
+ _luaG_typeerror(i3, i4 ? i1 : i2, 1928);
+}
+function _str_len(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ _luaL_checklstring(i1, 1, i3) | 0;
+ _lua_pushinteger(i1, HEAP32[i3 >> 2] | 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaL_optinteger(i3, i4, i2) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0;
+ i1 = STACKTOP;
+ if ((_lua_type(i3, i4) | 0) >= 1) {
+  i2 = _luaL_checkinteger(i3, i4) | 0;
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _os_difftime(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = ~~+_luaL_checknumber(i1, 1);
+ _lua_pushnumber(i1, +_difftime(i3 | 0, ~~+_luaL_optnumber(i1, 2, 0.0) | 0));
+ STACKTOP = i2;
+ return 1;
+}
+function _lua_pushboolean(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i2 = i2 + 8 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ HEAP32[i3 >> 2] = (i1 | 0) != 0;
+ HEAP32[i3 + 8 >> 2] = 1;
+ HEAP32[i2 >> 2] = i3 + 16;
+ return;
+}
+function _os_remove(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checklstring(i1, 1, 0) | 0;
+ i1 = _luaL_fileresult(i1, (_remove(i3 | 0) | 0) == 0 | 0, i3) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaopen_table(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 7);
+ _luaL_setfuncs(i1, 8088, 0);
+ _lua_getfield(i1, -1, 8152);
+ _lua_setglobal(i1, 8152);
+ STACKTOP = i2;
+ return 1;
+}
+function _lua_pushinteger(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i2 = i2 + 8 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ HEAPF64[i3 >> 3] = +(i1 | 0);
+ HEAP32[i3 + 8 >> 2] = 3;
+ HEAP32[i2 >> 2] = i3 + 16;
+ return;
+}
+function _luaB_rawset(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 5);
+ _luaL_checkany(i1, 2);
+ _luaL_checkany(i1, 3);
+ _lua_settop(i1, 3);
+ _lua_rawset(i1, 1);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaE_setdebt(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = i2 + 12 | 0;
+ i2 = i2 + 8 | 0;
+ HEAP32[i2 >> 2] = (HEAP32[i3 >> 2] | 0) - i1 + (HEAP32[i2 >> 2] | 0);
+ HEAP32[i3 >> 2] = i1;
+ return;
+}
+function _luaB_cocreate(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 6);
+ i3 = _lua_newthread(i1) | 0;
+ _lua_pushvalue(i1, 1);
+ _lua_xmove(i1, i3, 1);
+ STACKTOP = i2;
+ return 1;
+}
+function _io_noclose(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ HEAP32[(_luaL_checkudata(i1, 1, 2832) | 0) + 4 >> 2] = 154;
+ _lua_pushnil(i1);
+ _lua_pushlstring(i1, 2840, 26) | 0;
+ STACKTOP = i2;
+ return 2;
+}
+function _io_fclose(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _luaL_fileresult(i1, (_fclose(HEAP32[(_luaL_checkudata(i1, 1, 2832) | 0) >> 2] | 0) | 0) == 0 | 0, 0) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaL_optnumber(i3, i4, d2) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ d2 = +d2;
+ var i1 = 0;
+ i1 = STACKTOP;
+ if ((_lua_type(i3, i4) | 0) >= 1) {
+  d2 = +_luaL_checknumber(i3, i4);
+ }
+ STACKTOP = i1;
+ return +d2;
+}
+function _math_atan2(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0;
+ i2 = STACKTOP;
+ d3 = +_luaL_checknumber(i1, 1);
+ _lua_pushnumber(i1, +Math_atan2(+d3, +(+_luaL_checknumber(i1, 2))));
+ STACKTOP = i2;
+ return 1;
+}
+function _luaK_codeABx(i4, i2, i3, i1) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0;
+ i5 = STACKTOP;
+ i4 = _luaK_code(i4, i3 << 6 | i2 | i1 << 14) | 0;
+ STACKTOP = i5;
+ return i4 | 0;
+}
+function _luaF_newCclosure(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ i2 = _luaC_newobj(i2, 38, (i1 << 4) + 16 | 0, 0, 0) | 0;
+ HEAP8[i2 + 6 | 0] = i1;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _math_pow(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0;
+ i2 = STACKTOP;
+ d3 = +_luaL_checknumber(i1, 1);
+ _lua_pushnumber(i1, +Math_pow(+d3, +(+_luaL_checknumber(i1, 2))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_ldexp(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0;
+ i2 = STACKTOP;
+ d3 = +_luaL_checknumber(i1, 1);
+ _lua_pushnumber(i1, +_ldexp(d3, _luaL_checkinteger(i1, 2) | 0));
+ STACKTOP = i2;
+ return 1;
+}
+function _luaF_newupval(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _luaC_newobj(i1, 10, 32, 0, 0) | 0;
+ HEAP32[i1 + 8 >> 2] = i1 + 16;
+ HEAP32[i1 + 24 >> 2] = 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _lua_pushnumber(i2, d1) {
+ i2 = i2 | 0;
+ d1 = +d1;
+ var i3 = 0;
+ i2 = i2 + 8 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ HEAPF64[i3 >> 3] = d1;
+ HEAP32[i3 + 8 >> 2] = 3;
+ HEAP32[i2 >> 2] = i3 + 16;
+ return;
+}
+function _math_fmod(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0;
+ i2 = STACKTOP;
+ d3 = +_luaL_checknumber(i1, 1);
+ _lua_pushnumber(i1, +_fmod(+d3, +(+_luaL_checknumber(i1, 2))));
+ STACKTOP = i2;
+ return 1;
+}
+function _luaG_concaterror(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ i4 = HEAP32[i2 + 8 >> 2] | 0;
+ _luaG_typeerror(i3, (i4 & 15 | 0) == 4 | (i4 | 0) == 3 ? i1 : i2, 1912);
+}
+function _luaB_rawequal(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 1);
+ _luaL_checkany(i1, 2);
+ _lua_pushboolean(i1, _lua_rawequal(i1, 1, 2) | 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _db_getuservalue(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((_lua_type(i1, 1) | 0) == 7) {
+  _lua_getuservalue(i1, 1);
+ } else {
+  _lua_pushnil(i1);
+ }
+ STACKTOP = i2;
+ return 1;
+}
+function _strchr(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ i2 = ___strchrnul(i2, i1) | 0;
+ STACKTOP = i3;
+ return ((HEAP8[i2] | 0) == (i1 & 255) << 24 >> 24 ? i2 : 0) | 0;
+}
+function runPostSets() {}
+function _rand_r(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = (Math_imul(HEAP32[i1 >> 2] | 0, 31010991) | 0) + 1735287159 & 2147483647;
+ HEAP32[i1 >> 2] = i2;
+ return i2 | 0;
+}
+function _luaL_checkany(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((_lua_type(i1, i3) | 0) == -1) {
+  _luaL_argerror(i1, i3, 1256) | 0;
+ }
+ STACKTOP = i2;
+ return;
+}
+function _i64Subtract(i2, i4, i1, i3) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 - i3 - (i1 >>> 0 > i2 >>> 0 | 0) >>> 0;
+ return (tempRet0 = i4, i2 - i1 >>> 0 | 0) | 0;
+}
+function _db_getmetatable(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 1);
+ if ((_lua_getmetatable(i1, 1) | 0) == 0) {
+  _lua_pushnil(i1);
+ }
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_rawget(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 5);
+ _luaL_checkany(i1, 2);
+ _lua_settop(i1, 2);
+ _lua_rawget(i1, 1);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_type(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 1);
+ _lua_pushstring(i1, _lua_typename(i1, _lua_type(i1, 1) | 0) | 0) | 0;
+ STACKTOP = i2;
+ return 1;
+}
+function dynCall_iiiii(i5, i4, i3, i2, i1) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iiiii[i5 & 3](i4 | 0, i3 | 0, i2 | 0, i1 | 0) | 0;
+}
+function _lstop(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ _lua_sethook(i1, 0, 0, 0) | 0;
+ _luaL_error(i1, 200, i2) | 0;
+ STACKTOP = i2;
+ return;
+}
+function _i64Add(i1, i3, i4, i2) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i4 = i1 + i4 >>> 0;
+ return (tempRet0 = i3 + i2 + (i4 >>> 0 < i1 >>> 0 | 0) >>> 0, i4 | 0) | 0;
+}
+function _luaK_ret(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ i4 = STACKTOP;
+ _luaK_code(i3, i2 << 6 | (i1 << 23) + 8388608 | 31) | 0;
+ STACKTOP = i4;
+ return;
+}
+function _strpbrk(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ i1 = i2 + (_strcspn(i2, i1) | 0) | 0;
+ STACKTOP = i3;
+ return ((HEAP8[i1] | 0) != 0 ? i1 : 0) | 0;
+}
+function _luaL_setmetatable(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ _lua_getfield(i1, -1001e3, i2);
+ _lua_setmetatable(i1, -2) | 0;
+ STACKTOP = i3;
+ return;
+}
+function _lua_atpanic(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = (HEAP32[i2 + 12 >> 2] | 0) + 168 | 0;
+ i2 = HEAP32[i3 >> 2] | 0;
+ HEAP32[i3 >> 2] = i1;
+ return i2 | 0;
+}
+function _luaL_newstate() {
+ var i1 = 0, i2 = 0;
+ i2 = STACKTOP;
+ i1 = _lua_newstate(1, 0) | 0;
+ if ((i1 | 0) != 0) {
+  _lua_atpanic(i1, 143) | 0;
+ }
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaL_buffinit(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ HEAP32[i1 + 12 >> 2] = i2;
+ HEAP32[i1 >> 2] = i1 + 16;
+ HEAP32[i1 + 8 >> 2] = 0;
+ HEAP32[i1 + 4 >> 2] = 1024;
+ return;
+}
+function _strrchr(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ i2 = ___memrchr(i1, i2, (_strlen(i1 | 0) | 0) + 1 | 0) | 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _luaK_fixline(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ HEAP32[(HEAP32[(HEAP32[i1 >> 2] | 0) + 20 >> 2] | 0) + ((HEAP32[i1 + 20 >> 2] | 0) + -1 << 2) >> 2] = i2;
+ return;
+}
+function _luaX_lookahead(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i3 = STACKTOP;
+ i2 = _llex(i1, i1 + 40 | 0) | 0;
+ HEAP32[i1 + 32 >> 2] = i2;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _f_call(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ _luaD_call(i2, HEAP32[i1 >> 2] | 0, HEAP32[i1 + 4 >> 2] | 0, 0);
+ STACKTOP = i3;
+ return;
+}
+function _io_pclose(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checkudata(i1, 1, 2832) | 0;
+ i1 = _luaL_execresult(i1, -1) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaS_new(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ i2 = _luaS_newlstr(i2, i1, _strlen(i1 | 0) | 0) | 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _os_getenv(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushstring(i1, _getenv(_luaL_checklstring(i1, 1, 0) | 0) | 0) | 0;
+ STACKTOP = i2;
+ return 1;
+}
+function _math_rad(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +_luaL_checknumber(i1, 1) * .017453292519943295);
+ STACKTOP = i2;
+ return 1;
+}
+function _math_deg(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +_luaL_checknumber(i1, 1) / .017453292519943295);
+ STACKTOP = i2;
+ return 1;
+}
+function _writer(i4, i2, i1, i3) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = STACKTOP;
+ _luaL_addlstring(i3, i2, i1);
+ STACKTOP = i4;
+ return 0;
+}
+function _luaL_addstring(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ _luaL_addlstring(i2, i1, _strlen(i1 | 0) | 0);
+ STACKTOP = i3;
+ return;
+}
+function _pcallcont(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _finishpcall(i1, (_lua_getctx(i1, 0) | 0) == 1 | 0) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaopen_coroutine(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 6);
+ _luaL_setfuncs(i1, 10656, 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _lua_version(i1) {
+ i1 = i1 | 0;
+ if ((i1 | 0) == 0) {
+  i1 = 920;
+ } else {
+  i1 = HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 176 >> 2] | 0;
+ }
+ return i1 | 0;
+}
+function _lua_pushnil(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i1 = i1 + 8 | 0;
+ i2 = HEAP32[i1 >> 2] | 0;
+ HEAP32[i2 + 8 >> 2] = 0;
+ HEAP32[i1 >> 2] = i2 + 16;
+ return;
+}
+function _math_floor(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_floor(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _laction(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _signal(i1 | 0, 0) | 0;
+ _lua_sethook(HEAP32[48] | 0, 1, 11, 1) | 0;
+ STACKTOP = i2;
+ return;
+}
+function dynCall_iiii(i4, i3, i2, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iiii[i4 & 3](i3 | 0, i2 | 0, i1 | 0) | 0;
+}
+function _luaopen_debug(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 16);
+ _luaL_setfuncs(i1, 11176, 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaopen_bit32(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 12);
+ _luaL_setfuncs(i1, 10240, 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _math_sqrt(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_sqrt(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_ceil(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_ceil(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_atan(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_atan(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_asin(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_asin(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_acos(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_acos(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _lua_close(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _close_state(HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 172 >> 2] | 0);
+ STACKTOP = i2;
+ return;
+}
+function _dothecall(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i2 = STACKTOP;
+ _luaD_call(i1, (HEAP32[i1 + 8 >> 2] | 0) + -32 | 0, 0, 0);
+ STACKTOP = i2;
+ return;
+}
+function _math_tan(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_tan(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_sin(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_sin(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_log10(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +_log10(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_exp(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_exp(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_cos(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_cos(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_abs(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_abs(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_randomseed(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _srand(_luaL_checkunsigned(i1, 1) | 0);
+ _rand() | 0;
+ STACKTOP = i2;
+ return 0;
+}
+function _luaopen_os(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 11);
+ _luaL_setfuncs(i1, 5624, 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _math_tanh(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +_tanh(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_sinh(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +_sinh(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_cosh(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +_cosh(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_yield(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _lua_yieldk(i1, _lua_gettop(i1) | 0, 0, 0) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaB_tostring(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 1);
+ _luaL_tolstring(i1, 1, 0) | 0;
+ STACKTOP = i2;
+ return 1;
+}
+function _growstack(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ _luaD_growstack(i2, HEAP32[i1 >> 2] | 0);
+ STACKTOP = i3;
+ return;
+}
+function ___udivdi3(i4, i3, i2, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ i4 = ___udivmoddi4(i4, i3, i2, i1, 0) | 0;
+ return i4 | 0;
+}
+function _b_not(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushunsigned(i1, ~(_luaL_checkunsigned(i1, 1) | 0));
+ STACKTOP = i2;
+ return 1;
+}
+function _luaO_fb2int(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1 >>> 3 & 31;
+ if ((i2 | 0) != 0) {
+  i1 = (i1 & 7 | 8) << i2 + -1;
+ }
+ return i1 | 0;
+}
+function _luaB_corunning(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushboolean(i1, _lua_pushthread(i1) | 0);
+ STACKTOP = i2;
+ return 2;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function _strcoll(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ i2 = _strcmp(i2, i1) | 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _os_clock(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +(_clock() | 0) / 1.0e6);
+ STACKTOP = i2;
+ return 1;
+}
+function _dofilecont(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = (_lua_gettop(i1) | 0) + -1 | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _scalbnl(d2, i1) {
+ d2 = +d2;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ d2 = +_scalbn(d2, i1);
+ STACKTOP = i3;
+ return +d2;
+}
+function _tolower(i1) {
+ i1 = i1 | 0;
+ if ((i1 | 0) < 65) return i1 | 0;
+ if ((i1 | 0) > 90) return i1 | 0;
+ return i1 - 65 + 97 | 0;
+}
+function _lua_gettop(i1) {
+ i1 = i1 | 0;
+ return (HEAP32[i1 + 8 >> 2] | 0) - ((HEAP32[HEAP32[i1 + 16 >> 2] >> 2] | 0) + 16) >> 4 | 0;
+}
+function dynCall_iii(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iii[i3 & 1](i2 | 0, i1 | 0) | 0;
+}
+function _str_match(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _str_find_aux(i1, 0) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaM_toobig(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ _luaG_runerror(i1, 4144, i2);
+}
+function _luaK_getlabel(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = HEAP32[i1 + 20 >> 2] | 0;
+ HEAP32[i1 + 24 >> 2] = i2;
+ return i2 | 0;
+}
+function _ldexp(d2, i1) {
+ d2 = +d2;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ d2 = +_scalbn(d2, i1);
+ STACKTOP = i3;
+ return +d2;
+}
+function _str_find(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _str_find_aux(i1, 1) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _db_getregistry(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushvalue(i1, -1001e3);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_ipairs(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _pairsmeta(i1, 9960, 1, 165);
+ STACKTOP = i2;
+ return 3;
+}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function _luaB_pairs(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _pairsmeta(i1, 9864, 0, 93);
+ STACKTOP = i2;
+ return 3;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function _io_output(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _g_iofile(i1, 2800, 3512);
+ STACKTOP = i2;
+ return 1;
+}
+function dynCall_vii(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_vii[i3 & 15](i2 | 0, i1 | 0);
+}
+function _io_input(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _g_iofile(i1, 2776, 3480);
+ STACKTOP = i2;
+ return 1;
+}
+function _semerror(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ _luaX_syntaxerror(i2, i1);
+}
+function _luaX_syntaxerror(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ _lexerror(i1, i2, HEAP32[i1 + 16 >> 2] | 0);
+}
+function b4(i1, i2, i3, i4) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ abort(4);
+ return 0;
+}
+function _lua_typename(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return HEAP32[8528 + (i1 + 1 << 2) >> 2] | 0;
+}
+function dynCall_ii(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_ii[i2 & 255](i1 | 0) | 0;
+}
+function dynCall_vi(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_vi[i2 & 1](i1 | 0);
+}
+function b0(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ abort(0);
+ return 0;
+}
+function _lua_gethookmask(i1) {
+ i1 = i1 | 0;
+ return HEAPU8[i1 + 40 | 0] | 0 | 0;
+}
+function _lua_gethookcount(i1) {
+ i1 = i1 | 0;
+ return HEAP32[i1 + 44 >> 2] | 0;
+}
+function _lua_status(i1) {
+ i1 = i1 | 0;
+ return HEAPU8[i1 + 6 | 0] | 0 | 0;
+}
+function _lua_gethook(i1) {
+ i1 = i1 | 0;
+ return HEAP32[i1 + 52 >> 2] | 0;
+}
+function b5(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ abort(5);
+ return 0;
+}
+function _lua_error(i1) {
+ i1 = i1 | 0;
+ _luaG_errormsg(i1);
+ return 0;
+}
+function b2(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ abort(2);
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function b3(i1) {
+ i1 = i1 | 0;
+ abort(3);
+ return 0;
+}
+function _rand() {
+ return _rand_r(___rand_seed) | 0;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+function b1(i1) {
+ i1 = i1 | 0;
+ abort(1);
+}
+
+// EMSCRIPTEN_END_FUNCS
+  var FUNCTION_TABLE_iiii = [b0,_getF,_getS,_generic_reader];
+  var FUNCTION_TABLE_vi = [b1,_laction];
+  var FUNCTION_TABLE_vii = [b2,_lstop,_growstack,_f_call,_resume,_unroll,_f_parser,_dothecall,_f_luaopen,_hookf,b2,b2,b2,b2,b2,b2];
+  var FUNCTION_TABLE_ii = [b3,_io_close,_io_flush,_io_input,_io_lines,_io_open,_io_output,_io_popen,_io_read,_io_tmpfile,_io_type,_io_write,_f_flush,_f_lines,_f_read,_f_seek,_f_setvbuf,_f_write,_f_gc,_f_tostring,_math_abs,_math_acos,_math_asin,_math_atan2,_math_atan,_math_ceil,_math_cosh,_math_cos,_math_deg
+  ,_math_exp,_math_floor,_math_fmod,_math_frexp,_math_ldexp,_math_log10,_math_log,_math_max,_math_min,_math_modf,_math_pow,_math_rad,_math_random,_math_randomseed,_math_sinh,_math_sin,_math_sqrt,_math_tanh,_math_tan,_ll_loadlib,_ll_searchpath,_ll_seeall,_ll_module,_ll_require,_os_clock,_os_date,_os_difftime,_os_execute,_os_exit,_os_getenv
+  ,_os_remove,_os_rename,_os_setlocale,_os_time,_os_tmpname,_str_byte,_str_char,_str_dump,_str_find,_str_format,_gmatch,_str_gsub,_str_len,_str_lower,_str_match,_str_rep,_str_reverse,_str_sub,_str_upper,_tconcat,_maxn,_tinsert,_pack,_unpack,_tremove,_sort,_luaB_assert,_luaB_collectgarbage,_luaB_dofile,_luaB_error
+  ,_luaB_getmetatable,_luaB_ipairs,_luaB_loadfile,_luaB_load,_luaB_next,_luaB_pairs,_luaB_pcall,_luaB_print,_luaB_rawequal,_luaB_rawlen,_luaB_rawget,_luaB_rawset,_luaB_select,_luaB_setmetatable,_luaB_tonumber,_luaB_tostring,_luaB_type,_luaB_xpcall,_b_arshift,_b_and,_b_not,_b_or,_b_xor,_b_test,_b_extract,_b_lrot,_b_lshift,_b_replace,_b_rrot,_b_rshift
+  ,_luaB_cocreate,_luaB_coresume,_luaB_corunning,_luaB_costatus,_luaB_cowrap,_luaB_yield,_db_debug,_db_getuservalue,_db_gethook,_db_getinfo,_db_getlocal,_db_getregistry,_db_getmetatable,_db_getupvalue,_db_upvaluejoin,_db_upvalueid,_db_setuservalue,_db_sethook,_db_setlocal,_db_setmetatable,_db_setupvalue,_db_traceback,_pmain,_traceback,_panic,_luaopen_base,_luaopen_package,_luaopen_coroutine,_luaopen_table,_luaopen_io
+  ,_luaopen_os,_luaopen_string,_luaopen_bit32,_luaopen_math,_luaopen_debug,_io_noclose,_io_readline,_io_fclose,_io_pclose,_gctm,_searcher_preload,_searcher_Lua,_searcher_C,_searcher_Croot,_gmatch_aux,_dofilecont,_ipairsaux,_pcallcont,_luaB_auxwrap,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3
+  ,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3
+  ,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3
+  ,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3];
+  var FUNCTION_TABLE_iiiii = [b4,_l_alloc,_writer,b4];
+  var FUNCTION_TABLE_iii = [b5,_lua_newstate];
+
+  return { _testSetjmp: _testSetjmp, _i64Subtract: _i64Subtract, _free: _free, _main: _main, _rand_r: _rand_r, _realloc: _realloc, _i64Add: _i64Add, _tolower: _tolower, _saveSetjmp: _saveSetjmp, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, _strlen: _strlen, _rand: _rand, _bitshift64Shl: _bitshift64Shl, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9, dynCall_iiii: dynCall_iiii, dynCall_vi: dynCall_vi, dynCall_vii: dynCall_vii, dynCall_ii: dynCall_ii, dynCall_iiiii: dynCall_iiiii, dynCall_iii: dynCall_iii };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "invoke_iiii": invoke_iiii, "invoke_vi": invoke_vi, "invoke_vii": invoke_vii, "invoke_ii": invoke_ii, "invoke_iiiii": invoke_iiiii, "invoke_iii": invoke_iii, "_isalnum": _isalnum, "_fabs": _fabs, "_frexp": _frexp, "_exp": _exp, "_fread": _fread, "__reallyNegative": __reallyNegative, "_longjmp": _longjmp, "__addDays": __addDays, "_fsync": _fsync, "_signal": _signal, "_rename": _rename, "_sbrk": _sbrk, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_sinh": _sinh, "_sysconf": _sysconf, "_close": _close, "_ferror": _ferror, "_clock": _clock, "_cos": _cos, "_tanh": _tanh, "_unlink": _unlink, "_write": _write, "__isLeapYear": __isLeapYear, "_ftell": _ftell, "_isupper": _isupper, "_gmtime_r": _gmtime_r, "_islower": _islower, "_tmpnam": _tmpnam, "_tmpfile": _tmpfile, "_send": _send, "_abort": _abort, "_setvbuf": _setvbuf, "_atan2": _atan2, "_setlocale": _setlocale, "_isgraph": _isgraph, "_modf": _modf, "_strerror_r": _strerror_r, "_fscanf": _fscanf, "___setErrNo": ___setErrNo, "_isalpha": _isalpha, "_srand": _srand, "_mktime": _mktime, "_putchar": _putchar, "_gmtime": _gmtime, "_localeconv": _localeconv, "_sprintf": _sprintf, "_localtime": _localtime, "_read": _read, "_fwrite": _fwrite, "_time": _time, "_fprintf": _fprintf, "_exit": _exit, "_freopen": _freopen, "_llvm_pow_f64": _llvm_pow_f64, "_fgetc": _fgetc, "_fmod": _fmod, "_lseek": _lseek, "_rmdir": _rmdir, "_asin": _asin, "_floor": _floor, "_pwrite": _pwrite, "_localtime_r": _localtime_r, "_tzset": _tzset, "_open": _open, "_remove": _remove, "_snprintf": _snprintf, "__scanString": __scanString, "_strftime": _strftime, "_fseek": _fseek, "_iscntrl": _iscntrl, "_isxdigit": _isxdigit, "_fclose": _fclose, "_log": _log, "_recv": _recv, "_tan": _tan, "_copysign": _copysign, "__getFloat": __getFloat, "_fputc": _fputc, "_ispunct": _ispunct, "_ceil": _ceil, "_isspace": _isspace, "_fopen": _fopen, "_sin": _sin, "_acos": _acos, "_cosh": _cosh, "___buildEnvironment": ___buildEnvironment, "_difftime": _difftime, "_ungetc": _ungetc, "_system": _system, "_fflush": _fflush, "_log10": _log10, "_fileno": _fileno, "__exit": __exit, "__arraySum": __arraySum, "_fgets": _fgets, "_atan": _atan, "_pread": _pread, "_mkport": _mkport, "_toupper": _toupper, "_feof": _feof, "___errno_location": ___errno_location, "_clearerr": _clearerr, "_getenv": _getenv, "_strerror": _strerror, "_emscripten_longjmp": _emscripten_longjmp, "__formatString": __formatString, "_fputs": _fputs, "_sqrt": _sqrt, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "cttz_i8": cttz_i8, "ctlz_i8": ctlz_i8, "___rand_seed": ___rand_seed, "NaN": NaN, "Infinity": Infinity, "_stderr": _stderr, "_stdin": _stdin, "_stdout": _stdout }, buffer);
+var _testSetjmp = Module["_testSetjmp"] = asm["_testSetjmp"];
+var _i64Subtract = Module["_i64Subtract"] = asm["_i64Subtract"];
+var _free = Module["_free"] = asm["_free"];
+var _main = Module["_main"] = asm["_main"];
+var _rand_r = Module["_rand_r"] = asm["_rand_r"];
+var _realloc = Module["_realloc"] = asm["_realloc"];
+var _i64Add = Module["_i64Add"] = asm["_i64Add"];
+var _tolower = Module["_tolower"] = asm["_tolower"];
+var _saveSetjmp = Module["_saveSetjmp"] = asm["_saveSetjmp"];
+var _memset = Module["_memset"] = asm["_memset"];
+var _malloc = Module["_malloc"] = asm["_malloc"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _rand = Module["_rand"] = asm["_rand"];
+var _bitshift64Shl = Module["_bitshift64Shl"] = asm["_bitshift64Shl"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+var dynCall_iiii = Module["dynCall_iiii"] = asm["dynCall_iiii"];
+var dynCall_vi = Module["dynCall_vi"] = asm["dynCall_vi"];
+var dynCall_vii = Module["dynCall_vii"] = asm["dynCall_vii"];
+var dynCall_ii = Module["dynCall_ii"] = asm["dynCall_ii"];
+var dynCall_iiiii = Module["dynCall_iiiii"] = asm["dynCall_iiiii"];
+var dynCall_iii = Module["dynCall_iii"] = asm["dynCall_iii"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// TODO: strip out parts of this we do not need
+
+//======= begin closure i64 code =======
+
+// Copyright 2009 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Defines a Long class for representing a 64-bit two's-complement
+ * integer value, which faithfully simulates the behavior of a Java "long". This
+ * implementation is derived from LongLib in GWT.
+ *
+ */
+
+var i64Math = (function() { // Emscripten wrapper
+  var goog = { math: {} };
+
+
+  /**
+   * Constructs a 64-bit two's-complement integer, given its low and high 32-bit
+   * values as *signed* integers.  See the from* functions below for more
+   * convenient ways of constructing Longs.
+   *
+   * The internal representation of a long is the two given signed, 32-bit values.
+   * We use 32-bit pieces because these are the size of integers on which
+   * Javascript performs bit-operations.  For operations like addition and
+   * multiplication, we split each number into 16-bit pieces, which can easily be
+   * multiplied within Javascript's floating-point representation without overflow
+   * or change in sign.
+   *
+   * In the algorithms below, we frequently reduce the negative case to the
+   * positive case by negating the input(s) and then post-processing the result.
+   * Note that we must ALWAYS check specially whether those values are MIN_VALUE
+   * (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as
+   * a positive number, it overflows back into a negative).  Not handling this
+   * case would often result in infinite recursion.
+   *
+   * @param {number} low  The low (signed) 32 bits of the long.
+   * @param {number} high  The high (signed) 32 bits of the long.
+   * @constructor
+   */
+  goog.math.Long = function(low, high) {
+    /**
+     * @type {number}
+     * @private
+     */
+    this.low_ = low | 0;  // force into 32 signed bits.
+
+    /**
+     * @type {number}
+     * @private
+     */
+    this.high_ = high | 0;  // force into 32 signed bits.
+  };
+
+
+  // NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the
+  // from* methods on which they depend.
+
+
+  /**
+   * A cache of the Long representations of small integer values.
+   * @type {!Object}
+   * @private
+   */
+  goog.math.Long.IntCache_ = {};
+
+
+  /**
+   * Returns a Long representing the given (32-bit) integer value.
+   * @param {number} value The 32-bit integer in question.
+   * @return {!goog.math.Long} The corresponding Long value.
+   */
+  goog.math.Long.fromInt = function(value) {
+    if (-128 <= value && value < 128) {
+      var cachedObj = goog.math.Long.IntCache_[value];
+      if (cachedObj) {
+        return cachedObj;
+      }
+    }
+
+    var obj = new goog.math.Long(value | 0, value < 0 ? -1 : 0);
+    if (-128 <= value && value < 128) {
+      goog.math.Long.IntCache_[value] = obj;
+    }
+    return obj;
+  };
+
+
+  /**
+   * Returns a Long representing the given value, provided that it is a finite
+   * number.  Otherwise, zero is returned.
+   * @param {number} value The number in question.
+   * @return {!goog.math.Long} The corresponding Long value.
+   */
+  goog.math.Long.fromNumber = function(value) {
+    if (isNaN(value) || !isFinite(value)) {
+      return goog.math.Long.ZERO;
+    } else if (value <= -goog.math.Long.TWO_PWR_63_DBL_) {
+      return goog.math.Long.MIN_VALUE;
+    } else if (value + 1 >= goog.math.Long.TWO_PWR_63_DBL_) {
+      return goog.math.Long.MAX_VALUE;
+    } else if (value < 0) {
+      return goog.math.Long.fromNumber(-value).negate();
+    } else {
+      return new goog.math.Long(
+          (value % goog.math.Long.TWO_PWR_32_DBL_) | 0,
+          (value / goog.math.Long.TWO_PWR_32_DBL_) | 0);
+    }
+  };
+
+
+  /**
+   * Returns a Long representing the 64-bit integer that comes by concatenating
+   * the given high and low bits.  Each is assumed to use 32 bits.
+   * @param {number} lowBits The low 32-bits.
+   * @param {number} highBits The high 32-bits.
+   * @return {!goog.math.Long} The corresponding Long value.
+   */
+  goog.math.Long.fromBits = function(lowBits, highBits) {
+    return new goog.math.Long(lowBits, highBits);
+  };
+
+
+  /**
+   * Returns a Long representation of the given string, written using the given
+   * radix.
+   * @param {string} str The textual representation of the Long.
+   * @param {number=} opt_radix The radix in which the text is written.
+   * @return {!goog.math.Long} The corresponding Long value.
+   */
+  goog.math.Long.fromString = function(str, opt_radix) {
+    if (str.length == 0) {
+      throw Error('number format error: empty string');
+    }
+
+    var radix = opt_radix || 10;
+    if (radix < 2 || 36 < radix) {
+      throw Error('radix out of range: ' + radix);
+    }
+
+    if (str.charAt(0) == '-') {
+      return goog.math.Long.fromString(str.substring(1), radix).negate();
+    } else if (str.indexOf('-') >= 0) {
+      throw Error('number format error: interior "-" character: ' + str);
+    }
+
+    // Do several (8) digits each time through the loop, so as to
+    // minimize the calls to the very expensive emulated div.
+    var radixToPower = goog.math.Long.fromNumber(Math.pow(radix, 8));
+
+    var result = goog.math.Long.ZERO;
+    for (var i = 0; i < str.length; i += 8) {
+      var size = Math.min(8, str.length - i);
+      var value = parseInt(str.substring(i, i + size), radix);
+      if (size < 8) {
+        var power = goog.math.Long.fromNumber(Math.pow(radix, size));
+        result = result.multiply(power).add(goog.math.Long.fromNumber(value));
+      } else {
+        result = result.multiply(radixToPower);
+        result = result.add(goog.math.Long.fromNumber(value));
+      }
+    }
+    return result;
+  };
+
+
+  // NOTE: the compiler should inline these constant values below and then remove
+  // these variables, so there should be no runtime penalty for these.
+
+
+  /**
+   * Number used repeated below in calculations.  This must appear before the
+   * first call to any from* function below.
+   * @type {number}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_16_DBL_ = 1 << 16;
+
+
+  /**
+   * @type {number}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_24_DBL_ = 1 << 24;
+
+
+  /**
+   * @type {number}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_32_DBL_ =
+      goog.math.Long.TWO_PWR_16_DBL_ * goog.math.Long.TWO_PWR_16_DBL_;
+
+
+  /**
+   * @type {number}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_31_DBL_ =
+      goog.math.Long.TWO_PWR_32_DBL_ / 2;
+
+
+  /**
+   * @type {number}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_48_DBL_ =
+      goog.math.Long.TWO_PWR_32_DBL_ * goog.math.Long.TWO_PWR_16_DBL_;
+
+
+  /**
+   * @type {number}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_64_DBL_ =
+      goog.math.Long.TWO_PWR_32_DBL_ * goog.math.Long.TWO_PWR_32_DBL_;
+
+
+  /**
+   * @type {number}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_63_DBL_ =
+      goog.math.Long.TWO_PWR_64_DBL_ / 2;
+
+
+  /** @type {!goog.math.Long} */
+  goog.math.Long.ZERO = goog.math.Long.fromInt(0);
+
+
+  /** @type {!goog.math.Long} */
+  goog.math.Long.ONE = goog.math.Long.fromInt(1);
+
+
+  /** @type {!goog.math.Long} */
+  goog.math.Long.NEG_ONE = goog.math.Long.fromInt(-1);
+
+
+  /** @type {!goog.math.Long} */
+  goog.math.Long.MAX_VALUE =
+      goog.math.Long.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0);
+
+
+  /** @type {!goog.math.Long} */
+  goog.math.Long.MIN_VALUE = goog.math.Long.fromBits(0, 0x80000000 | 0);
+
+
+  /**
+   * @type {!goog.math.Long}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_24_ = goog.math.Long.fromInt(1 << 24);
+
+
+  /** @return {number} The value, assuming it is a 32-bit integer. */
+  goog.math.Long.prototype.toInt = function() {
+    return this.low_;
+  };
+
+
+  /** @return {number} The closest floating-point representation to this value. */
+  goog.math.Long.prototype.toNumber = function() {
+    return this.high_ * goog.math.Long.TWO_PWR_32_DBL_ +
+           this.getLowBitsUnsigned();
+  };
+
+
+  /**
+   * @param {number=} opt_radix The radix in which the text should be written.
+   * @return {string} The textual representation of this value.
+   */
+  goog.math.Long.prototype.toString = function(opt_radix) {
+    var radix = opt_radix || 10;
+    if (radix < 2 || 36 < radix) {
+      throw Error('radix out of range: ' + radix);
+    }
+
+    if (this.isZero()) {
+      return '0';
+    }
+
+    if (this.isNegative()) {
+      if (this.equals(goog.math.Long.MIN_VALUE)) {
+        // We need to change the Long value before it can be negated, so we remove
+        // the bottom-most digit in this base and then recurse to do the rest.
+        var radixLong = goog.math.Long.fromNumber(radix);
+        var div = this.div(radixLong);
+        var rem = div.multiply(radixLong).subtract(this);
+        return div.toString(radix) + rem.toInt().toString(radix);
+      } else {
+        return '-' + this.negate().toString(radix);
+      }
+    }
+
+    // Do several (6) digits each time through the loop, so as to
+    // minimize the calls to the very expensive emulated div.
+    var radixToPower = goog.math.Long.fromNumber(Math.pow(radix, 6));
+
+    var rem = this;
+    var result = '';
+    while (true) {
+      var remDiv = rem.div(radixToPower);
+      var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt();
+      var digits = intval.toString(radix);
+
+      rem = remDiv;
+      if (rem.isZero()) {
+        return digits + result;
+      } else {
+        while (digits.length < 6) {
+          digits = '0' + digits;
+        }
+        result = '' + digits + result;
+      }
+    }
+  };
+
+
+  /** @return {number} The high 32-bits as a signed value. */
+  goog.math.Long.prototype.getHighBits = function() {
+    return this.high_;
+  };
+
+
+  /** @return {number} The low 32-bits as a signed value. */
+  goog.math.Long.prototype.getLowBits = function() {
+    return this.low_;
+  };
+
+
+  /** @return {number} The low 32-bits as an unsigned value. */
+  goog.math.Long.prototype.getLowBitsUnsigned = function() {
+    return (this.low_ >= 0) ?
+        this.low_ : goog.math.Long.TWO_PWR_32_DBL_ + this.low_;
+  };
+
+
+  /**
+   * @return {number} Returns the number of bits needed to represent the absolute
+   *     value of this Long.
+   */
+  goog.math.Long.prototype.getNumBitsAbs = function() {
+    if (this.isNegative()) {
+      if (this.equals(goog.math.Long.MIN_VALUE)) {
+        return 64;
+      } else {
+        return this.negate().getNumBitsAbs();
+      }
+    } else {
+      var val = this.high_ != 0 ? this.high_ : this.low_;
+      for (var bit = 31; bit > 0; bit--) {
+        if ((val & (1 << bit)) != 0) {
+          break;
+        }
+      }
+      return this.high_ != 0 ? bit + 33 : bit + 1;
+    }
+  };
+
+
+  /** @return {boolean} Whether this value is zero. */
+  goog.math.Long.prototype.isZero = function() {
+    return this.high_ == 0 && this.low_ == 0;
+  };
+
+
+  /** @return {boolean} Whether this value is negative. */
+  goog.math.Long.prototype.isNegative = function() {
+    return this.high_ < 0;
+  };
+
+
+  /** @return {boolean} Whether this value is odd. */
+  goog.math.Long.prototype.isOdd = function() {
+    return (this.low_ & 1) == 1;
+  };
+
+
+  /**
+   * @param {goog.math.Long} other Long to compare against.
+   * @return {boolean} Whether this Long equals the other.
+   */
+  goog.math.Long.prototype.equals = function(other) {
+    return (this.high_ == other.high_) && (this.low_ == other.low_);
+  };
+
+
+  /**
+   * @param {goog.math.Long} other Long to compare against.
+   * @return {boolean} Whether this Long does not equal the other.
+   */
+  goog.math.Long.prototype.notEquals = function(other) {
+    return (this.high_ != other.high_) || (this.low_ != other.low_);
+  };
+
+
+  /**
+   * @param {goog.math.Long} other Long to compare against.
+   * @return {boolean} Whether this Long is less than the other.
+   */
+  goog.math.Long.prototype.lessThan = function(other) {
+    return this.compare(other) < 0;
+  };
+
+
+  /**
+   * @param {goog.math.Long} other Long to compare against.
+   * @return {boolean} Whether this Long is less than or equal to the other.
+   */
+  goog.math.Long.prototype.lessThanOrEqual = function(other) {
+    return this.compare(other) <= 0;
+  };
+
+
+  /**
+   * @param {goog.math.Long} other Long to compare against.
+   * @return {boolean} Whether this Long is greater than the other.
+   */
+  goog.math.Long.prototype.greaterThan = function(other) {
+    return this.compare(other) > 0;
+  };
+
+
+  /**
+   * @param {goog.math.Long} other Long to compare against.
+   * @return {boolean} Whether this Long is greater than or equal to the other.
+   */
+  goog.math.Long.prototype.greaterThanOrEqual = function(other) {
+    return this.compare(other) >= 0;
+  };
+
+
+  /**
+   * Compares this Long with the given one.
+   * @param {goog.math.Long} other Long to compare against.
+   * @return {number} 0 if they are the same, 1 if the this is greater, and -1
+   *     if the given one is greater.
+   */
+  goog.math.Long.prototype.compare = function(other) {
+    if (this.equals(other)) {
+      return 0;
+    }
+
+    var thisNeg = this.isNegative();
+    var otherNeg = other.isNegative();
+    if (thisNeg && !otherNeg) {
+      return -1;
+    }
+    if (!thisNeg && otherNeg) {
+      return 1;
+    }
+
+    // at this point, the signs are the same, so subtraction will not overflow
+    if (this.subtract(other).isNegative()) {
+      return -1;
+    } else {
+      return 1;
+    }
+  };
+
+
+  /** @return {!goog.math.Long} The negation of this value. */
+  goog.math.Long.prototype.negate = function() {
+    if (this.equals(goog.math.Long.MIN_VALUE)) {
+      return goog.math.Long.MIN_VALUE;
+    } else {
+      return this.not().add(goog.math.Long.ONE);
+    }
+  };
+
+
+  /**
+   * Returns the sum of this and the given Long.
+   * @param {goog.math.Long} other Long to add to this one.
+   * @return {!goog.math.Long} The sum of this and the given Long.
+   */
+  goog.math.Long.prototype.add = function(other) {
+    // Divide each number into 4 chunks of 16 bits, and then sum the chunks.
+
+    var a48 = this.high_ >>> 16;
+    var a32 = this.high_ & 0xFFFF;
+    var a16 = this.low_ >>> 16;
+    var a00 = this.low_ & 0xFFFF;
+
+    var b48 = other.high_ >>> 16;
+    var b32 = other.high_ & 0xFFFF;
+    var b16 = other.low_ >>> 16;
+    var b00 = other.low_ & 0xFFFF;
+
+    var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
+    c00 += a00 + b00;
+    c16 += c00 >>> 16;
+    c00 &= 0xFFFF;
+    c16 += a16 + b16;
+    c32 += c16 >>> 16;
+    c16 &= 0xFFFF;
+    c32 += a32 + b32;
+    c48 += c32 >>> 16;
+    c32 &= 0xFFFF;
+    c48 += a48 + b48;
+    c48 &= 0xFFFF;
+    return goog.math.Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32);
+  };
+
+
+  /**
+   * Returns the difference of this and the given Long.
+   * @param {goog.math.Long} other Long to subtract from this.
+   * @return {!goog.math.Long} The difference of this and the given Long.
+   */
+  goog.math.Long.prototype.subtract = function(other) {
+    return this.add(other.negate());
+  };
+
+
+  /**
+   * Returns the product of this and the given long.
+   * @param {goog.math.Long} other Long to multiply with this.
+   * @return {!goog.math.Long} The product of this and the other.
+   */
+  goog.math.Long.prototype.multiply = function(other) {
+    if (this.isZero()) {
+      return goog.math.Long.ZERO;
+    } else if (other.isZero()) {
+      return goog.math.Long.ZERO;
+    }
+
+    if (this.equals(goog.math.Long.MIN_VALUE)) {
+      return other.isOdd() ? goog.math.Long.MIN_VALUE : goog.math.Long.ZERO;
+    } else if (other.equals(goog.math.Long.MIN_VALUE)) {
+      return this.isOdd() ? goog.math.Long.MIN_VALUE : goog.math.Long.ZERO;
+    }
+
+    if (this.isNegative()) {
+      if (other.isNegative()) {
+        return this.negate().multiply(other.negate());
+      } else {
+        return this.negate().multiply(other).negate();
+      }
+    } else if (other.isNegative()) {
+      return this.multiply(other.negate()).negate();
+    }
+
+    // If both longs are small, use float multiplication
+    if (this.lessThan(goog.math.Long.TWO_PWR_24_) &&
+        other.lessThan(goog.math.Long.TWO_PWR_24_)) {
+      return goog.math.Long.fromNumber(this.toNumber() * other.toNumber());
+    }
+
+    // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products.
+    // We can skip products that would overflow.
+
+    var a48 = this.high_ >>> 16;
+    var a32 = this.high_ & 0xFFFF;
+    var a16 = this.low_ >>> 16;
+    var a00 = this.low_ & 0xFFFF;
+
+    var b48 = other.high_ >>> 16;
+    var b32 = other.high_ & 0xFFFF;
+    var b16 = other.low_ >>> 16;
+    var b00 = other.low_ & 0xFFFF;
+
+    var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
+    c00 += a00 * b00;
+    c16 += c00 >>> 16;
+    c00 &= 0xFFFF;
+    c16 += a16 * b00;
+    c32 += c16 >>> 16;
+    c16 &= 0xFFFF;
+    c16 += a00 * b16;
+    c32 += c16 >>> 16;
+    c16 &= 0xFFFF;
+    c32 += a32 * b00;
+    c48 += c32 >>> 16;
+    c32 &= 0xFFFF;
+    c32 += a16 * b16;
+    c48 += c32 >>> 16;
+    c32 &= 0xFFFF;
+    c32 += a00 * b32;
+    c48 += c32 >>> 16;
+    c32 &= 0xFFFF;
+    c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48;
+    c48 &= 0xFFFF;
+    return goog.math.Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32);
+  };
+
+
+  /**
+   * Returns this Long divided by the given one.
+   * @param {goog.math.Long} other Long by which to divide.
+   * @return {!goog.math.Long} This Long divided by the given one.
+   */
+  goog.math.Long.prototype.div = function(other) {
+    if (other.isZero()) {
+      throw Error('division by zero');
+    } else if (this.isZero()) {
+      return goog.math.Long.ZERO;
+    }
+
+    if (this.equals(goog.math.Long.MIN_VALUE)) {
+      if (other.equals(goog.math.Long.ONE) ||
+          other.equals(goog.math.Long.NEG_ONE)) {
+        return goog.math.Long.MIN_VALUE;  // recall that -MIN_VALUE == MIN_VALUE
+      } else if (other.equals(goog.math.Long.MIN_VALUE)) {
+        return goog.math.Long.ONE;
+      } else {
+        // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
+        var halfThis = this.shiftRight(1);
+        var approx = halfThis.div(other).shiftLeft(1);
+        if (approx.equals(goog.math.Long.ZERO)) {
+          return other.isNegative() ? goog.math.Long.ONE : goog.math.Long.NEG_ONE;
+        } else {
+          var rem = this.subtract(other.multiply(approx));
+          var result = approx.add(rem.div(other));
+          return result;
+        }
+      }
+    } else if (other.equals(goog.math.Long.MIN_VALUE)) {
+      return goog.math.Long.ZERO;
+    }
+
+    if (this.isNegative()) {
+      if (other.isNegative()) {
+        return this.negate().div(other.negate());
+      } else {
+        return this.negate().div(other).negate();
+      }
+    } else if (other.isNegative()) {
+      return this.div(other.negate()).negate();
+    }
+
+    // Repeat the following until the remainder is less than other:  find a
+    // floating-point that approximates remainder / other *from below*, add this
+    // into the result, and subtract it from the remainder.  It is critical that
+    // the approximate value is less than or equal to the real value so that the
+    // remainder never becomes negative.
+    var res = goog.math.Long.ZERO;
+    var rem = this;
+    while (rem.greaterThanOrEqual(other)) {
+      // Approximate the result of division. This may be a little greater or
+      // smaller than the actual value.
+      var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber()));
+
+      // We will tweak the approximate result by changing it in the 48-th digit or
+      // the smallest non-fractional digit, whichever is larger.
+      var log2 = Math.ceil(Math.log(approx) / Math.LN2);
+      var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48);
+
+      // Decrease the approximation until it is smaller than the remainder.  Note
+      // that if it is too large, the product overflows and is negative.
+      var approxRes = goog.math.Long.fromNumber(approx);
+      var approxRem = approxRes.multiply(other);
+      while (approxRem.isNegative() || approxRem.greaterThan(rem)) {
+        approx -= delta;
+        approxRes = goog.math.Long.fromNumber(approx);
+        approxRem = approxRes.multiply(other);
+      }
+
+      // We know the answer can't be zero... and actually, zero would cause
+      // infinite recursion since we would make no progress.
+      if (approxRes.isZero()) {
+        approxRes = goog.math.Long.ONE;
+      }
+
+      res = res.add(approxRes);
+      rem = rem.subtract(approxRem);
+    }
+    return res;
+  };
+
+
+  /**
+   * Returns this Long modulo the given one.
+   * @param {goog.math.Long} other Long by which to mod.
+   * @return {!goog.math.Long} This Long modulo the given one.
+   */
+  goog.math.Long.prototype.modulo = function(other) {
+    return this.subtract(this.div(other).multiply(other));
+  };
+
+
+  /** @return {!goog.math.Long} The bitwise-NOT of this value. */
+  goog.math.Long.prototype.not = function() {
+    return goog.math.Long.fromBits(~this.low_, ~this.high_);
+  };
+
+
+  /**
+   * Returns the bitwise-AND of this Long and the given one.
+   * @param {goog.math.Long} other The Long with which to AND.
+   * @return {!goog.math.Long} The bitwise-AND of this and the other.
+   */
+  goog.math.Long.prototype.and = function(other) {
+    return goog.math.Long.fromBits(this.low_ & other.low_,
+                                   this.high_ & other.high_);
+  };
+
+
+  /**
+   * Returns the bitwise-OR of this Long and the given one.
+   * @param {goog.math.Long} other The Long with which to OR.
+   * @return {!goog.math.Long} The bitwise-OR of this and the other.
+   */
+  goog.math.Long.prototype.or = function(other) {
+    return goog.math.Long.fromBits(this.low_ | other.low_,
+                                   this.high_ | other.high_);
+  };
+
+
+  /**
+   * Returns the bitwise-XOR of this Long and the given one.
+   * @param {goog.math.Long} other The Long with which to XOR.
+   * @return {!goog.math.Long} The bitwise-XOR of this and the other.
+   */
+  goog.math.Long.prototype.xor = function(other) {
+    return goog.math.Long.fromBits(this.low_ ^ other.low_,
+                                   this.high_ ^ other.high_);
+  };
+
+
+  /**
+   * Returns this Long with bits shifted to the left by the given amount.
+   * @param {number} numBits The number of bits by which to shift.
+   * @return {!goog.math.Long} This shifted to the left by the given amount.
+   */
+  goog.math.Long.prototype.shiftLeft = function(numBits) {
+    numBits &= 63;
+    if (numBits == 0) {
+      return this;
+    } else {
+      var low = this.low_;
+      if (numBits < 32) {
+        var high = this.high_;
+        return goog.math.Long.fromBits(
+            low << numBits,
+            (high << numBits) | (low >>> (32 - numBits)));
+      } else {
+        return goog.math.Long.fromBits(0, low << (numBits - 32));
+      }
+    }
+  };
+
+
+  /**
+   * Returns this Long with bits shifted to the right by the given amount.
+   * @param {number} numBits The number of bits by which to shift.
+   * @return {!goog.math.Long} This shifted to the right by the given amount.
+   */
+  goog.math.Long.prototype.shiftRight = function(numBits) {
+    numBits &= 63;
+    if (numBits == 0) {
+      return this;
+    } else {
+      var high = this.high_;
+      if (numBits < 32) {
+        var low = this.low_;
+        return goog.math.Long.fromBits(
+            (low >>> numBits) | (high << (32 - numBits)),
+            high >> numBits);
+      } else {
+        return goog.math.Long.fromBits(
+            high >> (numBits - 32),
+            high >= 0 ? 0 : -1);
+      }
+    }
+  };
+
+
+  /**
+   * Returns this Long with bits shifted to the right by the given amount, with
+   * the new top bits matching the current sign bit.
+   * @param {number} numBits The number of bits by which to shift.
+   * @return {!goog.math.Long} This shifted to the right by the given amount, with
+   *     zeros placed into the new leading bits.
+   */
+  goog.math.Long.prototype.shiftRightUnsigned = function(numBits) {
+    numBits &= 63;
+    if (numBits == 0) {
+      return this;
+    } else {
+      var high = this.high_;
+      if (numBits < 32) {
+        var low = this.low_;
+        return goog.math.Long.fromBits(
+            (low >>> numBits) | (high << (32 - numBits)),
+            high >>> numBits);
+      } else if (numBits == 32) {
+        return goog.math.Long.fromBits(high, 0);
+      } else {
+        return goog.math.Long.fromBits(high >>> (numBits - 32), 0);
+      }
+    }
+  };
+
+  //======= begin jsbn =======
+
+  var navigator = { appName: 'Modern Browser' }; // polyfill a little
+
+  // Copyright (c) 2005  Tom Wu
+  // All Rights Reserved.
+  // http://www-cs-students.stanford.edu/~tjw/jsbn/
+
+  /*
+   * Copyright (c) 2003-2005  Tom Wu
+   * All Rights Reserved.
+   *
+   * Permission is hereby granted, free of charge, to any person obtaining
+   * a copy of this software and associated documentation files (the
+   * "Software"), to deal in the Software without restriction, including
+   * without limitation the rights to use, copy, modify, merge, publish,
+   * distribute, sublicense, and/or sell copies of the Software, and to
+   * permit persons to whom the Software is furnished to do so, subject to
+   * the following conditions:
+   *
+   * The above copyright notice and this permission notice shall be
+   * included in all copies or substantial portions of the Software.
+   *
+   * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+   * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+   * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+   *
+   * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+   * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+   * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+   * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+   * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+   *
+   * In addition, the following condition applies:
+   *
+   * All redistributions must retain an intact copy of this copyright notice
+   * and disclaimer.
+   */
+
+  // Basic JavaScript BN library - subset useful for RSA encryption.
+
+  // Bits per digit
+  var dbits;
+
+  // JavaScript engine analysis
+  var canary = 0xdeadbeefcafe;
+  var j_lm = ((canary&0xffffff)==0xefcafe);
+
+  // (public) Constructor
+  function BigInteger(a,b,c) {
+    if(a != null)
+      if("number" == typeof a) this.fromNumber(a,b,c);
+      else if(b == null && "string" != typeof a) this.fromString(a,256);
+      else this.fromString(a,b);
+  }
+
+  // return new, unset BigInteger
+  function nbi() { return new BigInteger(null); }
+
+  // am: Compute w_j += (x*this_i), propagate carries,
+  // c is initial carry, returns final carry.
+  // c < 3*dvalue, x < 2*dvalue, this_i < dvalue
+  // We need to select the fastest one that works in this environment.
+
+  // am1: use a single mult and divide to get the high bits,
+  // max digit bits should be 26 because
+  // max internal value = 2*dvalue^2-2*dvalue (< 2^53)
+  function am1(i,x,w,j,c,n) {
+    while(--n >= 0) {
+      var v = x*this[i++]+w[j]+c;
+      c = Math.floor(v/0x4000000);
+      w[j++] = v&0x3ffffff;
+    }
+    return c;
+  }
+  // am2 avoids a big mult-and-extract completely.
+  // Max digit bits should be <= 30 because we do bitwise ops
+  // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
+  function am2(i,x,w,j,c,n) {
+    var xl = x&0x7fff, xh = x>>15;
+    while(--n >= 0) {
+      var l = this[i]&0x7fff;
+      var h = this[i++]>>15;
+      var m = xh*l+h*xl;
+      l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
+      c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
+      w[j++] = l&0x3fffffff;
+    }
+    return c;
+  }
+  // Alternately, set max digit bits to 28 since some
+  // browsers slow down when dealing with 32-bit numbers.
+  function am3(i,x,w,j,c,n) {
+    var xl = x&0x3fff, xh = x>>14;
+    while(--n >= 0) {
+      var l = this[i]&0x3fff;
+      var h = this[i++]>>14;
+      var m = xh*l+h*xl;
+      l = xl*l+((m&0x3fff)<<14)+w[j]+c;
+      c = (l>>28)+(m>>14)+xh*h;
+      w[j++] = l&0xfffffff;
+    }
+    return c;
+  }
+  if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
+    BigInteger.prototype.am = am2;
+    dbits = 30;
+  }
+  else if(j_lm && (navigator.appName != "Netscape")) {
+    BigInteger.prototype.am = am1;
+    dbits = 26;
+  }
+  else { // Mozilla/Netscape seems to prefer am3
+    BigInteger.prototype.am = am3;
+    dbits = 28;
+  }
+
+  BigInteger.prototype.DB = dbits;
+  BigInteger.prototype.DM = ((1<<dbits)-1);
+  BigInteger.prototype.DV = (1<<dbits);
+
+  var BI_FP = 52;
+  BigInteger.prototype.FV = Math.pow(2,BI_FP);
+  BigInteger.prototype.F1 = BI_FP-dbits;
+  BigInteger.prototype.F2 = 2*dbits-BI_FP;
+
+  // Digit conversions
+  var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
+  var BI_RC = new Array();
+  var rr,vv;
+  rr = "0".charCodeAt(0);
+  for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
+  rr = "a".charCodeAt(0);
+  for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
+  rr = "A".charCodeAt(0);
+  for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
+
+  function int2char(n) { return BI_RM.charAt(n); }
+  function intAt(s,i) {
+    var c = BI_RC[s.charCodeAt(i)];
+    return (c==null)?-1:c;
+  }
+
+  // (protected) copy this to r
+  function bnpCopyTo(r) {
+    for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
+    r.t = this.t;
+    r.s = this.s;
+  }
+
+  // (protected) set from integer value x, -DV <= x < DV
+  function bnpFromInt(x) {
+    this.t = 1;
+    this.s = (x<0)?-1:0;
+    if(x > 0) this[0] = x;
+    else if(x < -1) this[0] = x+DV;
+    else this.t = 0;
+  }
+
+  // return bigint initialized to value
+  function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
+
+  // (protected) set from string and radix
+  function bnpFromString(s,b) {
+    var k;
+    if(b == 16) k = 4;
+    else if(b == 8) k = 3;
+    else if(b == 256) k = 8; // byte array
+    else if(b == 2) k = 1;
+    else if(b == 32) k = 5;
+    else if(b == 4) k = 2;
+    else { this.fromRadix(s,b); return; }
+    this.t = 0;
+    this.s = 0;
+    var i = s.length, mi = false, sh = 0;
+    while(--i >= 0) {
+      var x = (k==8)?s[i]&0xff:intAt(s,i);
+      if(x < 0) {
+        if(s.charAt(i) == "-") mi = true;
+        continue;
+      }
+      mi = false;
+      if(sh == 0)
+        this[this.t++] = x;
+      else if(sh+k > this.DB) {
+        this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
+        this[this.t++] = (x>>(this.DB-sh));
+      }
+      else
+        this[this.t-1] |= x<<sh;
+      sh += k;
+      if(sh >= this.DB) sh -= this.DB;
+    }
+    if(k == 8 && (s[0]&0x80) != 0) {
+      this.s = -1;
+      if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
+    }
+    this.clamp();
+    if(mi) BigInteger.ZERO.subTo(this,this);
+  }
+
+  // (protected) clamp off excess high words
+  function bnpClamp() {
+    var c = this.s&this.DM;
+    while(this.t > 0 && this[this.t-1] == c) --this.t;
+  }
+
+  // (public) return string representation in given radix
+  function bnToString(b) {
+    if(this.s < 0) return "-"+this.negate().toString(b);
+    var k;
+    if(b == 16) k = 4;
+    else if(b == 8) k = 3;
+    else if(b == 2) k = 1;
+    else if(b == 32) k = 5;
+    else if(b == 4) k = 2;
+    else return this.toRadix(b);
+    var km = (1<<k)-1, d, m = false, r = "", i = this.t;
+    var p = this.DB-(i*this.DB)%k;
+    if(i-- > 0) {
+      if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
+      while(i >= 0) {
+        if(p < k) {
+          d = (this[i]&((1<<p)-1))<<(k-p);
+          d |= this[--i]>>(p+=this.DB-k);
+        }
+        else {
+          d = (this[i]>>(p-=k))&km;
+          if(p <= 0) { p += this.DB; --i; }
+        }
+        if(d > 0) m = true;
+        if(m) r += int2char(d);
+      }
+    }
+    return m?r:"0";
+  }
+
+  // (public) -this
+  function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
+
+  // (public) |this|
+  function bnAbs() { return (this.s<0)?this.negate():this; }
+
+  // (public) return + if this > a, - if this < a, 0 if equal
+  function bnCompareTo(a) {
+    var r = this.s-a.s;
+    if(r != 0) return r;
+    var i = this.t;
+    r = i-a.t;
+    if(r != 0) return (this.s<0)?-r:r;
+    while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
+    return 0;
+  }
+
+  // returns bit length of the integer x
+  function nbits(x) {
+    var r = 1, t;
+    if((t=x>>>16) != 0) { x = t; r += 16; }
+    if((t=x>>8) != 0) { x = t; r += 8; }
+    if((t=x>>4) != 0) { x = t; r += 4; }
+    if((t=x>>2) != 0) { x = t; r += 2; }
+    if((t=x>>1) != 0) { x = t; r += 1; }
+    return r;
+  }
+
+  // (public) return the number of bits in "this"
+  function bnBitLength() {
+    if(this.t <= 0) return 0;
+    return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
+  }
+
+  // (protected) r = this << n*DB
+  function bnpDLShiftTo(n,r) {
+    var i;
+    for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
+    for(i = n-1; i >= 0; --i) r[i] = 0;
+    r.t = this.t+n;
+    r.s = this.s;
+  }
+
+  // (protected) r = this >> n*DB
+  function bnpDRShiftTo(n,r) {
+    for(var i = n; i < this.t; ++i) r[i-n] = this[i];
+    r.t = Math.max(this.t-n,0);
+    r.s = this.s;
+  }
+
+  // (protected) r = this << n
+  function bnpLShiftTo(n,r) {
+    var bs = n%this.DB;
+    var cbs = this.DB-bs;
+    var bm = (1<<cbs)-1;
+    var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
+    for(i = this.t-1; i >= 0; --i) {
+      r[i+ds+1] = (this[i]>>cbs)|c;
+      c = (this[i]&bm)<<bs;
+    }
+    for(i = ds-1; i >= 0; --i) r[i] = 0;
+    r[ds] = c;
+    r.t = this.t+ds+1;
+    r.s = this.s;
+    r.clamp();
+  }
+
+  // (protected) r = this >> n
+  function bnpRShiftTo(n,r) {
+    r.s = this.s;
+    var ds = Math.floor(n/this.DB);
+    if(ds >= this.t) { r.t = 0; return; }
+    var bs = n%this.DB;
+    var cbs = this.DB-bs;
+    var bm = (1<<bs)-1;
+    r[0] = this[ds]>>bs;
+    for(var i = ds+1; i < this.t; ++i) {
+      r[i-ds-1] |= (this[i]&bm)<<cbs;
+      r[i-ds] = this[i]>>bs;
+    }
+    if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
+    r.t = this.t-ds;
+    r.clamp();
+  }
+
+  // (protected) r = this - a
+  function bnpSubTo(a,r) {
+    var i = 0, c = 0, m = Math.min(a.t,this.t);
+    while(i < m) {
+      c += this[i]-a[i];
+      r[i++] = c&this.DM;
+      c >>= this.DB;
+    }
+    if(a.t < this.t) {
+      c -= a.s;
+      while(i < this.t) {
+        c += this[i];
+        r[i++] = c&this.DM;
+        c >>= this.DB;
+      }
+      c += this.s;
+    }
+    else {
+      c += this.s;
+      while(i < a.t) {
+        c -= a[i];
+        r[i++] = c&this.DM;
+        c >>= this.DB;
+      }
+      c -= a.s;
+    }
+    r.s = (c<0)?-1:0;
+    if(c < -1) r[i++] = this.DV+c;
+    else if(c > 0) r[i++] = c;
+    r.t = i;
+    r.clamp();
+  }
+
+  // (protected) r = this * a, r != this,a (HAC 14.12)
+  // "this" should be the larger one if appropriate.
+  function bnpMultiplyTo(a,r) {
+    var x = this.abs(), y = a.abs();
+    var i = x.t;
+    r.t = i+y.t;
+    while(--i >= 0) r[i] = 0;
+    for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
+    r.s = 0;
+    r.clamp();
+    if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
+  }
+
+  // (protected) r = this^2, r != this (HAC 14.16)
+  function bnpSquareTo(r) {
+    var x = this.abs();
+    var i = r.t = 2*x.t;
+    while(--i >= 0) r[i] = 0;
+    for(i = 0; i < x.t-1; ++i) {
+      var c = x.am(i,x[i],r,2*i,0,1);
+      if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
+        r[i+x.t] -= x.DV;
+        r[i+x.t+1] = 1;
+      }
+    }
+    if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
+    r.s = 0;
+    r.clamp();
+  }
+
+  // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
+  // r != q, this != m.  q or r may be null.
+  function bnpDivRemTo(m,q,r) {
+    var pm = m.abs();
+    if(pm.t <= 0) return;
+    var pt = this.abs();
+    if(pt.t < pm.t) {
+      if(q != null) q.fromInt(0);
+      if(r != null) this.copyTo(r);
+      return;
+    }
+    if(r == null) r = nbi();
+    var y = nbi(), ts = this.s, ms = m.s;
+    var nsh = this.DB-nbits(pm[pm.t-1]);  // normalize modulus
+    if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
+    else { pm.copyTo(y); pt.copyTo(r); }
+    var ys = y.t;
+    var y0 = y[ys-1];
+    if(y0 == 0) return;
+    var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
+    var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
+    var i = r.t, j = i-ys, t = (q==null)?nbi():q;
+    y.dlShiftTo(j,t);
+    if(r.compareTo(t) >= 0) {
+      r[r.t++] = 1;
+      r.subTo(t,r);
+    }
+    BigInteger.ONE.dlShiftTo(ys,t);
+    t.subTo(y,y);  // "negative" y so we can replace sub with am later
+    while(y.t < ys) y[y.t++] = 0;
+    while(--j >= 0) {
+      // Estimate quotient digit
+      var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
+      if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) {  // Try it out
+        y.dlShiftTo(j,t);
+        r.subTo(t,r);
+        while(r[i] < --qd) r.subTo(t,r);
+      }
+    }
+    if(q != null) {
+      r.drShiftTo(ys,q);
+      if(ts != ms) BigInteger.ZERO.subTo(q,q);
+    }
+    r.t = ys;
+    r.clamp();
+    if(nsh > 0) r.rShiftTo(nsh,r);  // Denormalize remainder
+    if(ts < 0) BigInteger.ZERO.subTo(r,r);
+  }
+
+  // (public) this mod a
+  function bnMod(a) {
+    var r = nbi();
+    this.abs().divRemTo(a,null,r);
+    if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
+    return r;
+  }
+
+  // Modular reduction using "classic" algorithm
+  function Classic(m) { this.m = m; }
+  function cConvert(x) {
+    if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
+    else return x;
+  }
+  function cRevert(x) { return x; }
+  function cReduce(x) { x.divRemTo(this.m,null,x); }
+  function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
+  function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
+
+  Classic.prototype.convert = cConvert;
+  Classic.prototype.revert = cRevert;
+  Classic.prototype.reduce = cReduce;
+  Classic.prototype.mulTo = cMulTo;
+  Classic.prototype.sqrTo = cSqrTo;
+
+  // (protected) return "-1/this % 2^DB"; useful for Mont. reduction
+  // justification:
+  //         xy == 1 (mod m)
+  //         xy =  1+km
+  //   xy(2-xy) = (1+km)(1-km)
+  // x[y(2-xy)] = 1-k^2m^2
+  // x[y(2-xy)] == 1 (mod m^2)
+  // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
+  // should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
+  // JS multiply "overflows" differently from C/C++, so care is needed here.
+  function bnpInvDigit() {
+    if(this.t < 1) return 0;
+    var x = this[0];
+    if((x&1) == 0) return 0;
+    var y = x&3;    // y == 1/x mod 2^2
+    y = (y*(2-(x&0xf)*y))&0xf;  // y == 1/x mod 2^4
+    y = (y*(2-(x&0xff)*y))&0xff;  // y == 1/x mod 2^8
+    y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff;  // y == 1/x mod 2^16
+    // last step - calculate inverse mod DV directly;
+    // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
+    y = (y*(2-x*y%this.DV))%this.DV;    // y == 1/x mod 2^dbits
+    // we really want the negative inverse, and -DV < y < DV
+    return (y>0)?this.DV-y:-y;
+  }
+
+  // Montgomery reduction
+  function Montgomery(m) {
+    this.m = m;
+    this.mp = m.invDigit();
+    this.mpl = this.mp&0x7fff;
+    this.mph = this.mp>>15;
+    this.um = (1<<(m.DB-15))-1;
+    this.mt2 = 2*m.t;
+  }
+
+  // xR mod m
+  function montConvert(x) {
+    var r = nbi();
+    x.abs().dlShiftTo(this.m.t,r);
+    r.divRemTo(this.m,null,r);
+    if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
+    return r;
+  }
+
+  // x/R mod m
+  function montRevert(x) {
+    var r = nbi();
+    x.copyTo(r);
+    this.reduce(r);
+    return r;
+  }
+
+  // x = x/R mod m (HAC 14.32)
+  function montReduce(x) {
+    while(x.t <= this.mt2)  // pad x so am has enough room later
+      x[x.t++] = 0;
+    for(var i = 0; i < this.m.t; ++i) {
+      // faster way of calculating u0 = x[i]*mp mod DV
+      var j = x[i]&0x7fff;
+      var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
+      // use am to combine the multiply-shift-add into one call
+      j = i+this.m.t;
+      x[j] += this.m.am(0,u0,x,i,0,this.m.t);
+      // propagate carry
+      while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
+    }
+    x.clamp();
+    x.drShiftTo(this.m.t,x);
+    if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
+  }
+
+  // r = "x^2/R mod m"; x != r
+  function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
+
+  // r = "xy/R mod m"; x,y != r
+  function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
+
+  Montgomery.prototype.convert = montConvert;
+  Montgomery.prototype.revert = montRevert;
+  Montgomery.prototype.reduce = montReduce;
+  Montgomery.prototype.mulTo = montMulTo;
+  Montgomery.prototype.sqrTo = montSqrTo;
+
+  // (protected) true iff this is even
+  function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
+
+  // (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
+  function bnpExp(e,z) {
+    if(e > 0xffffffff || e < 1) return BigInteger.ONE;
+    var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
+    g.copyTo(r);
+    while(--i >= 0) {
+      z.sqrTo(r,r2);
+      if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
+      else { var t = r; r = r2; r2 = t; }
+    }
+    return z.revert(r);
+  }
+
+  // (public) this^e % m, 0 <= e < 2^32
+  function bnModPowInt(e,m) {
+    var z;
+    if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
+    return this.exp(e,z);
+  }
+
+  // protected
+  BigInteger.prototype.copyTo = bnpCopyTo;
+  BigInteger.prototype.fromInt = bnpFromInt;
+  BigInteger.prototype.fromString = bnpFromString;
+  BigInteger.prototype.clamp = bnpClamp;
+  BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
+  BigInteger.prototype.drShiftTo = bnpDRShiftTo;
+  BigInteger.prototype.lShiftTo = bnpLShiftTo;
+  BigInteger.prototype.rShiftTo = bnpRShiftTo;
+  BigInteger.prototype.subTo = bnpSubTo;
+  BigInteger.prototype.multiplyTo = bnpMultiplyTo;
+  BigInteger.prototype.squareTo = bnpSquareTo;
+  BigInteger.prototype.divRemTo = bnpDivRemTo;
+  BigInteger.prototype.invDigit = bnpInvDigit;
+  BigInteger.prototype.isEven = bnpIsEven;
+  BigInteger.prototype.exp = bnpExp;
+
+  // public
+  BigInteger.prototype.toString = bnToString;
+  BigInteger.prototype.negate = bnNegate;
+  BigInteger.prototype.abs = bnAbs;
+  BigInteger.prototype.compareTo = bnCompareTo;
+  BigInteger.prototype.bitLength = bnBitLength;
+  BigInteger.prototype.mod = bnMod;
+  BigInteger.prototype.modPowInt = bnModPowInt;
+
+  // "constants"
+  BigInteger.ZERO = nbv(0);
+  BigInteger.ONE = nbv(1);
+
+  // jsbn2 stuff
+
+  // (protected) convert from radix string
+  function bnpFromRadix(s,b) {
+    this.fromInt(0);
+    if(b == null) b = 10;
+    var cs = this.chunkSize(b);
+    var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
+    for(var i = 0; i < s.length; ++i) {
+      var x = intAt(s,i);
+      if(x < 0) {
+        if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
+        continue;
+      }
+      w = b*w+x;
+      if(++j >= cs) {
+        this.dMultiply(d);
+        this.dAddOffset(w,0);
+        j = 0;
+        w = 0;
+      }
+    }
+    if(j > 0) {
+      this.dMultiply(Math.pow(b,j));
+      this.dAddOffset(w,0);
+    }
+    if(mi) BigInteger.ZERO.subTo(this,this);
+  }
+
+  // (protected) return x s.t. r^x < DV
+  function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
+
+  // (public) 0 if this == 0, 1 if this > 0
+  function bnSigNum() {
+    if(this.s < 0) return -1;
+    else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
+    else return 1;
+  }
+
+  // (protected) this *= n, this >= 0, 1 < n < DV
+  function bnpDMultiply(n) {
+    this[this.t] = this.am(0,n-1,this,0,0,this.t);
+    ++this.t;
+    this.clamp();
+  }
+
+  // (protected) this += n << w words, this >= 0
+  function bnpDAddOffset(n,w) {
+    if(n == 0) return;
+    while(this.t <= w) this[this.t++] = 0;
+    this[w] += n;
+    while(this[w] >= this.DV) {
+      this[w] -= this.DV;
+      if(++w >= this.t) this[this.t++] = 0;
+      ++this[w];
+    }
+  }
+
+  // (protected) convert to radix string
+  function bnpToRadix(b) {
+    if(b == null) b = 10;
+    if(this.signum() == 0 || b < 2 || b > 36) return "0";
+    var cs = this.chunkSize(b);
+    var a = Math.pow(b,cs);
+    var d = nbv(a), y = nbi(), z = nbi(), r = "";
+    this.divRemTo(d,y,z);
+    while(y.signum() > 0) {
+      r = (a+z.intValue()).toString(b).substr(1) + r;
+      y.divRemTo(d,y,z);
+    }
+    return z.intValue().toString(b) + r;
+  }
+
+  // (public) return value as integer
+  function bnIntValue() {
+    if(this.s < 0) {
+      if(this.t == 1) return this[0]-this.DV;
+      else if(this.t == 0) return -1;
+    }
+    else if(this.t == 1) return this[0];
+    else if(this.t == 0) return 0;
+    // assumes 16 < DB < 32
+    return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
+  }
+
+  // (protected) r = this + a
+  function bnpAddTo(a,r) {
+    var i = 0, c = 0, m = Math.min(a.t,this.t);
+    while(i < m) {
+      c += this[i]+a[i];
+      r[i++] = c&this.DM;
+      c >>= this.DB;
+    }
+    if(a.t < this.t) {
+      c += a.s;
+      while(i < this.t) {
+        c += this[i];
+        r[i++] = c&this.DM;
+        c >>= this.DB;
+      }
+      c += this.s;
+    }
+    else {
+      c += this.s;
+      while(i < a.t) {
+        c += a[i];
+        r[i++] = c&this.DM;
+        c >>= this.DB;
+      }
+      c += a.s;
+    }
+    r.s = (c<0)?-1:0;
+    if(c > 0) r[i++] = c;
+    else if(c < -1) r[i++] = this.DV+c;
+    r.t = i;
+    r.clamp();
+  }
+
+  BigInteger.prototype.fromRadix = bnpFromRadix;
+  BigInteger.prototype.chunkSize = bnpChunkSize;
+  BigInteger.prototype.signum = bnSigNum;
+  BigInteger.prototype.dMultiply = bnpDMultiply;
+  BigInteger.prototype.dAddOffset = bnpDAddOffset;
+  BigInteger.prototype.toRadix = bnpToRadix;
+  BigInteger.prototype.intValue = bnIntValue;
+  BigInteger.prototype.addTo = bnpAddTo;
+
+  //======= end jsbn =======
+
+  // Emscripten wrapper
+  var Wrapper = {
+    abs: function(l, h) {
+      var x = new goog.math.Long(l, h);
+      var ret;
+      if (x.isNegative()) {
+        ret = x.negate();
+      } else {
+        ret = x;
+      }
+      HEAP32[tempDoublePtr>>2] = ret.low_;
+      HEAP32[tempDoublePtr+4>>2] = ret.high_;
+    },
+    ensureTemps: function() {
+      if (Wrapper.ensuredTemps) return;
+      Wrapper.ensuredTemps = true;
+      Wrapper.two32 = new BigInteger();
+      Wrapper.two32.fromString('4294967296', 10);
+      Wrapper.two64 = new BigInteger();
+      Wrapper.two64.fromString('18446744073709551616', 10);
+      Wrapper.temp1 = new BigInteger();
+      Wrapper.temp2 = new BigInteger();
+    },
+    lh2bignum: function(l, h) {
+      var a = new BigInteger();
+      a.fromString(h.toString(), 10);
+      var b = new BigInteger();
+      a.multiplyTo(Wrapper.two32, b);
+      var c = new BigInteger();
+      c.fromString(l.toString(), 10);
+      var d = new BigInteger();
+      c.addTo(b, d);
+      return d;
+    },
+    stringify: function(l, h, unsigned) {
+      var ret = new goog.math.Long(l, h).toString();
+      if (unsigned && ret[0] == '-') {
+        // unsign slowly using jsbn bignums
+        Wrapper.ensureTemps();
+        var bignum = new BigInteger();
+        bignum.fromString(ret, 10);
+        ret = new BigInteger();
+        Wrapper.two64.addTo(bignum, ret);
+        ret = ret.toString(10);
+      }
+      return ret;
+    },
+    fromString: function(str, base, min, max, unsigned) {
+      Wrapper.ensureTemps();
+      var bignum = new BigInteger();
+      bignum.fromString(str, base);
+      var bigmin = new BigInteger();
+      bigmin.fromString(min, 10);
+      var bigmax = new BigInteger();
+      bigmax.fromString(max, 10);
+      if (unsigned && bignum.compareTo(BigInteger.ZERO) < 0) {
+        var temp = new BigInteger();
+        bignum.addTo(Wrapper.two64, temp);
+        bignum = temp;
+      }
+      var error = false;
+      if (bignum.compareTo(bigmin) < 0) {
+        bignum = bigmin;
+        error = true;
+      } else if (bignum.compareTo(bigmax) > 0) {
+        bignum = bigmax;
+        error = true;
+      }
+      var ret = goog.math.Long.fromString(bignum.toString()); // min-max checks should have clamped this to a range goog.math.Long can handle well
+      HEAP32[tempDoublePtr>>2] = ret.low_;
+      HEAP32[tempDoublePtr+4>>2] = ret.high_;
+      if (error) throw 'range error';
+    }
+  };
+  return Wrapper;
+})();
+
+//======= end closure i64 code =======
+
+
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run(['binarytrees.lua'].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run(['binarytrees.lua'].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/memops.js b/test/mjsunit/asm/embenchen/memops.js
new file mode 100644
index 0000000..e8e607c
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/memops.js
@@ -0,0 +1,8087 @@
+var EXPECTED_OUTPUT = 'final: 840.\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(531);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([101,114,114,111,114,58,32,37,100,10,0,0,0,0,0,0,102,105,110,97,108,58,32,37,100,46,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+  function _sbrk(bytes) {
+      // Implement a Linux-like 'memory area' for our 'process'.
+      // Changes the size of the memory area by |bytes|; returns the
+      // address of the previous top ('break') of the memory area
+      // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
+      var self = _sbrk;
+      if (!self.called) {
+        DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
+        self.called = true;
+        assert(Runtime.dynamicAlloc);
+        self.alloc = Runtime.dynamicAlloc;
+        Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
+      }
+      var ret = DYNAMICTOP;
+      if (bytes != 0) self.alloc(bytes);
+      return ret;  // Previous break location.
+    }
+
+  function _sysconf(name) {
+      // long sysconf(int name);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
+      switch(name) {
+        case 30: return PAGE_SIZE;
+        case 132:
+        case 133:
+        case 12:
+        case 137:
+        case 138:
+        case 15:
+        case 235:
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 149:
+        case 13:
+        case 10:
+        case 236:
+        case 153:
+        case 9:
+        case 21:
+        case 22:
+        case 159:
+        case 154:
+        case 14:
+        case 77:
+        case 78:
+        case 139:
+        case 80:
+        case 81:
+        case 79:
+        case 82:
+        case 68:
+        case 67:
+        case 164:
+        case 11:
+        case 29:
+        case 47:
+        case 48:
+        case 95:
+        case 52:
+        case 51:
+        case 46:
+          return 200809;
+        case 27:
+        case 246:
+        case 127:
+        case 128:
+        case 23:
+        case 24:
+        case 160:
+        case 161:
+        case 181:
+        case 182:
+        case 242:
+        case 183:
+        case 184:
+        case 243:
+        case 244:
+        case 245:
+        case 165:
+        case 178:
+        case 179:
+        case 49:
+        case 50:
+        case 168:
+        case 169:
+        case 175:
+        case 170:
+        case 171:
+        case 172:
+        case 97:
+        case 76:
+        case 32:
+        case 173:
+        case 35:
+          return -1;
+        case 176:
+        case 177:
+        case 7:
+        case 155:
+        case 8:
+        case 157:
+        case 125:
+        case 126:
+        case 92:
+        case 93:
+        case 129:
+        case 130:
+        case 131:
+        case 94:
+        case 91:
+          return 1;
+        case 74:
+        case 60:
+        case 69:
+        case 70:
+        case 4:
+          return 1024;
+        case 31:
+        case 42:
+        case 72:
+          return 32;
+        case 87:
+        case 26:
+        case 33:
+          return 2147483647;
+        case 34:
+        case 1:
+          return 47839;
+        case 38:
+        case 36:
+          return 99;
+        case 43:
+        case 37:
+          return 2048;
+        case 0: return 2097152;
+        case 3: return 65536;
+        case 28: return 32768;
+        case 44: return 32767;
+        case 75: return 16384;
+        case 39: return 1000;
+        case 89: return 700;
+        case 71: return 256;
+        case 40: return 255;
+        case 2: return 100;
+        case 180: return 64;
+        case 25: return 20;
+        case 5: return 16;
+        case 6: return 6;
+        case 73: return 4;
+        case 84: return 1;
+      }
+      ___setErrNo(ERRNO_CODES.EINVAL);
+      return -1;
+    }
+
+
+  Module["_memset"] = _memset;
+
+  function ___errno_location() {
+      return ___errno_state;
+    }
+
+  function _abort() {
+      Module['abort']();
+    }
+
+  var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+    Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+    Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+    // just add the mouse delta to the current absolut mouse position
+    // FIXME: ideally this should be clamped against the canvas size and zero
+    Browser.mouseX += Browser.mouseMovementX;
+    Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+  function _time(ptr) {
+      var ret = Math.floor(Date.now()/1000);
+      if (ptr) {
+        HEAP32[((ptr)>>2)]=ret;
+      }
+      return ret;
+    }
+
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var _fflush=env._fflush;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _printf=env._printf;
+  var _send=env._send;
+  var _pwrite=env._pwrite;
+  var _abort=env._abort;
+  var ___setErrNo=env.___setErrNo;
+  var _fwrite=env._fwrite;
+  var _sbrk=env._sbrk;
+  var _time=env._time;
+  var _mkport=env._mkport;
+  var __reallyNegative=env.__reallyNegative;
+  var __formatString=env.__formatString;
+  var _fileno=env._fileno;
+  var _write=env._write;
+  var _fprintf=env._fprintf;
+  var _sysconf=env._sysconf;
+  var ___errno_location=env.___errno_location;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _malloc(i12) {
+ i12 = i12 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0;
+ i1 = STACKTOP;
+ do {
+  if (i12 >>> 0 < 245) {
+   if (i12 >>> 0 < 11) {
+    i12 = 16;
+   } else {
+    i12 = i12 + 11 & -8;
+   }
+   i20 = i12 >>> 3;
+   i18 = HEAP32[10] | 0;
+   i21 = i18 >>> i20;
+   if ((i21 & 3 | 0) != 0) {
+    i6 = (i21 & 1 ^ 1) + i20 | 0;
+    i5 = i6 << 1;
+    i3 = 80 + (i5 << 2) | 0;
+    i5 = 80 + (i5 + 2 << 2) | 0;
+    i7 = HEAP32[i5 >> 2] | 0;
+    i2 = i7 + 8 | 0;
+    i4 = HEAP32[i2 >> 2] | 0;
+    do {
+     if ((i3 | 0) != (i4 | 0)) {
+      if (i4 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i8 = i4 + 12 | 0;
+      if ((HEAP32[i8 >> 2] | 0) == (i7 | 0)) {
+       HEAP32[i8 >> 2] = i3;
+       HEAP32[i5 >> 2] = i4;
+       break;
+      } else {
+       _abort();
+      }
+     } else {
+      HEAP32[10] = i18 & ~(1 << i6);
+     }
+    } while (0);
+    i32 = i6 << 3;
+    HEAP32[i7 + 4 >> 2] = i32 | 3;
+    i32 = i7 + (i32 | 4) | 0;
+    HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+    i32 = i2;
+    STACKTOP = i1;
+    return i32 | 0;
+   }
+   if (i12 >>> 0 > (HEAP32[48 >> 2] | 0) >>> 0) {
+    if ((i21 | 0) != 0) {
+     i7 = 2 << i20;
+     i7 = i21 << i20 & (i7 | 0 - i7);
+     i7 = (i7 & 0 - i7) + -1 | 0;
+     i2 = i7 >>> 12 & 16;
+     i7 = i7 >>> i2;
+     i6 = i7 >>> 5 & 8;
+     i7 = i7 >>> i6;
+     i5 = i7 >>> 2 & 4;
+     i7 = i7 >>> i5;
+     i4 = i7 >>> 1 & 2;
+     i7 = i7 >>> i4;
+     i3 = i7 >>> 1 & 1;
+     i3 = (i6 | i2 | i5 | i4 | i3) + (i7 >>> i3) | 0;
+     i7 = i3 << 1;
+     i4 = 80 + (i7 << 2) | 0;
+     i7 = 80 + (i7 + 2 << 2) | 0;
+     i5 = HEAP32[i7 >> 2] | 0;
+     i2 = i5 + 8 | 0;
+     i6 = HEAP32[i2 >> 2] | 0;
+     do {
+      if ((i4 | 0) != (i6 | 0)) {
+       if (i6 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       i8 = i6 + 12 | 0;
+       if ((HEAP32[i8 >> 2] | 0) == (i5 | 0)) {
+        HEAP32[i8 >> 2] = i4;
+        HEAP32[i7 >> 2] = i6;
+        break;
+       } else {
+        _abort();
+       }
+      } else {
+       HEAP32[10] = i18 & ~(1 << i3);
+      }
+     } while (0);
+     i6 = i3 << 3;
+     i4 = i6 - i12 | 0;
+     HEAP32[i5 + 4 >> 2] = i12 | 3;
+     i3 = i5 + i12 | 0;
+     HEAP32[i5 + (i12 | 4) >> 2] = i4 | 1;
+     HEAP32[i5 + i6 >> 2] = i4;
+     i6 = HEAP32[48 >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      i5 = HEAP32[60 >> 2] | 0;
+      i8 = i6 >>> 3;
+      i9 = i8 << 1;
+      i6 = 80 + (i9 << 2) | 0;
+      i7 = HEAP32[10] | 0;
+      i8 = 1 << i8;
+      if ((i7 & i8 | 0) != 0) {
+       i7 = 80 + (i9 + 2 << 2) | 0;
+       i8 = HEAP32[i7 >> 2] | 0;
+       if (i8 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i28 = i7;
+        i27 = i8;
+       }
+      } else {
+       HEAP32[10] = i7 | i8;
+       i28 = 80 + (i9 + 2 << 2) | 0;
+       i27 = i6;
+      }
+      HEAP32[i28 >> 2] = i5;
+      HEAP32[i27 + 12 >> 2] = i5;
+      HEAP32[i5 + 8 >> 2] = i27;
+      HEAP32[i5 + 12 >> 2] = i6;
+     }
+     HEAP32[48 >> 2] = i4;
+     HEAP32[60 >> 2] = i3;
+     i32 = i2;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i18 = HEAP32[44 >> 2] | 0;
+    if ((i18 | 0) != 0) {
+     i2 = (i18 & 0 - i18) + -1 | 0;
+     i31 = i2 >>> 12 & 16;
+     i2 = i2 >>> i31;
+     i30 = i2 >>> 5 & 8;
+     i2 = i2 >>> i30;
+     i32 = i2 >>> 2 & 4;
+     i2 = i2 >>> i32;
+     i6 = i2 >>> 1 & 2;
+     i2 = i2 >>> i6;
+     i3 = i2 >>> 1 & 1;
+     i3 = HEAP32[344 + ((i30 | i31 | i32 | i6 | i3) + (i2 >>> i3) << 2) >> 2] | 0;
+     i2 = (HEAP32[i3 + 4 >> 2] & -8) - i12 | 0;
+     i6 = i3;
+     while (1) {
+      i5 = HEAP32[i6 + 16 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       i5 = HEAP32[i6 + 20 >> 2] | 0;
+       if ((i5 | 0) == 0) {
+        break;
+       }
+      }
+      i6 = (HEAP32[i5 + 4 >> 2] & -8) - i12 | 0;
+      i4 = i6 >>> 0 < i2 >>> 0;
+      i2 = i4 ? i6 : i2;
+      i6 = i5;
+      i3 = i4 ? i5 : i3;
+     }
+     i6 = HEAP32[56 >> 2] | 0;
+     if (i3 >>> 0 < i6 >>> 0) {
+      _abort();
+     }
+     i4 = i3 + i12 | 0;
+     if (!(i3 >>> 0 < i4 >>> 0)) {
+      _abort();
+     }
+     i5 = HEAP32[i3 + 24 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     do {
+      if ((i7 | 0) == (i3 | 0)) {
+       i8 = i3 + 20 | 0;
+       i7 = HEAP32[i8 >> 2] | 0;
+       if ((i7 | 0) == 0) {
+        i8 = i3 + 16 | 0;
+        i7 = HEAP32[i8 >> 2] | 0;
+        if ((i7 | 0) == 0) {
+         i26 = 0;
+         break;
+        }
+       }
+       while (1) {
+        i10 = i7 + 20 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) != 0) {
+         i7 = i9;
+         i8 = i10;
+         continue;
+        }
+        i10 = i7 + 16 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) == 0) {
+         break;
+        } else {
+         i7 = i9;
+         i8 = i10;
+        }
+       }
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i8 >> 2] = 0;
+        i26 = i7;
+        break;
+       }
+      } else {
+       i8 = HEAP32[i3 + 8 >> 2] | 0;
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       }
+       i6 = i8 + 12 | 0;
+       if ((HEAP32[i6 >> 2] | 0) != (i3 | 0)) {
+        _abort();
+       }
+       i9 = i7 + 8 | 0;
+       if ((HEAP32[i9 >> 2] | 0) == (i3 | 0)) {
+        HEAP32[i6 >> 2] = i7;
+        HEAP32[i9 >> 2] = i8;
+        i26 = i7;
+        break;
+       } else {
+        _abort();
+       }
+      }
+     } while (0);
+     do {
+      if ((i5 | 0) != 0) {
+       i7 = HEAP32[i3 + 28 >> 2] | 0;
+       i6 = 344 + (i7 << 2) | 0;
+       if ((i3 | 0) == (HEAP32[i6 >> 2] | 0)) {
+        HEAP32[i6 >> 2] = i26;
+        if ((i26 | 0) == 0) {
+         HEAP32[44 >> 2] = HEAP32[44 >> 2] & ~(1 << i7);
+         break;
+        }
+       } else {
+        if (i5 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        i6 = i5 + 16 | 0;
+        if ((HEAP32[i6 >> 2] | 0) == (i3 | 0)) {
+         HEAP32[i6 >> 2] = i26;
+        } else {
+         HEAP32[i5 + 20 >> 2] = i26;
+        }
+        if ((i26 | 0) == 0) {
+         break;
+        }
+       }
+       if (i26 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       HEAP32[i26 + 24 >> 2] = i5;
+       i5 = HEAP32[i3 + 16 >> 2] | 0;
+       do {
+        if ((i5 | 0) != 0) {
+         if (i5 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i26 + 16 >> 2] = i5;
+          HEAP32[i5 + 24 >> 2] = i26;
+          break;
+         }
+        }
+       } while (0);
+       i5 = HEAP32[i3 + 20 >> 2] | 0;
+       if ((i5 | 0) != 0) {
+        if (i5 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i26 + 20 >> 2] = i5;
+         HEAP32[i5 + 24 >> 2] = i26;
+         break;
+        }
+       }
+      }
+     } while (0);
+     if (i2 >>> 0 < 16) {
+      i32 = i2 + i12 | 0;
+      HEAP32[i3 + 4 >> 2] = i32 | 3;
+      i32 = i3 + (i32 + 4) | 0;
+      HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+     } else {
+      HEAP32[i3 + 4 >> 2] = i12 | 3;
+      HEAP32[i3 + (i12 | 4) >> 2] = i2 | 1;
+      HEAP32[i3 + (i2 + i12) >> 2] = i2;
+      i6 = HEAP32[48 >> 2] | 0;
+      if ((i6 | 0) != 0) {
+       i5 = HEAP32[60 >> 2] | 0;
+       i8 = i6 >>> 3;
+       i9 = i8 << 1;
+       i6 = 80 + (i9 << 2) | 0;
+       i7 = HEAP32[10] | 0;
+       i8 = 1 << i8;
+       if ((i7 & i8 | 0) != 0) {
+        i7 = 80 + (i9 + 2 << 2) | 0;
+        i8 = HEAP32[i7 >> 2] | 0;
+        if (i8 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         i25 = i7;
+         i24 = i8;
+        }
+       } else {
+        HEAP32[10] = i7 | i8;
+        i25 = 80 + (i9 + 2 << 2) | 0;
+        i24 = i6;
+       }
+       HEAP32[i25 >> 2] = i5;
+       HEAP32[i24 + 12 >> 2] = i5;
+       HEAP32[i5 + 8 >> 2] = i24;
+       HEAP32[i5 + 12 >> 2] = i6;
+      }
+      HEAP32[48 >> 2] = i2;
+      HEAP32[60 >> 2] = i4;
+     }
+     i32 = i3 + 8 | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+   }
+  } else {
+   if (!(i12 >>> 0 > 4294967231)) {
+    i24 = i12 + 11 | 0;
+    i12 = i24 & -8;
+    i26 = HEAP32[44 >> 2] | 0;
+    if ((i26 | 0) != 0) {
+     i25 = 0 - i12 | 0;
+     i24 = i24 >>> 8;
+     if ((i24 | 0) != 0) {
+      if (i12 >>> 0 > 16777215) {
+       i27 = 31;
+      } else {
+       i31 = (i24 + 1048320 | 0) >>> 16 & 8;
+       i32 = i24 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i27 = (i32 + 245760 | 0) >>> 16 & 2;
+       i27 = 14 - (i30 | i31 | i27) + (i32 << i27 >>> 15) | 0;
+       i27 = i12 >>> (i27 + 7 | 0) & 1 | i27 << 1;
+      }
+     } else {
+      i27 = 0;
+     }
+     i30 = HEAP32[344 + (i27 << 2) >> 2] | 0;
+     L126 : do {
+      if ((i30 | 0) == 0) {
+       i29 = 0;
+       i24 = 0;
+      } else {
+       if ((i27 | 0) == 31) {
+        i24 = 0;
+       } else {
+        i24 = 25 - (i27 >>> 1) | 0;
+       }
+       i29 = 0;
+       i28 = i12 << i24;
+       i24 = 0;
+       while (1) {
+        i32 = HEAP32[i30 + 4 >> 2] & -8;
+        i31 = i32 - i12 | 0;
+        if (i31 >>> 0 < i25 >>> 0) {
+         if ((i32 | 0) == (i12 | 0)) {
+          i25 = i31;
+          i29 = i30;
+          i24 = i30;
+          break L126;
+         } else {
+          i25 = i31;
+          i24 = i30;
+         }
+        }
+        i31 = HEAP32[i30 + 20 >> 2] | 0;
+        i30 = HEAP32[i30 + (i28 >>> 31 << 2) + 16 >> 2] | 0;
+        i29 = (i31 | 0) == 0 | (i31 | 0) == (i30 | 0) ? i29 : i31;
+        if ((i30 | 0) == 0) {
+         break;
+        } else {
+         i28 = i28 << 1;
+        }
+       }
+      }
+     } while (0);
+     if ((i29 | 0) == 0 & (i24 | 0) == 0) {
+      i32 = 2 << i27;
+      i26 = i26 & (i32 | 0 - i32);
+      if ((i26 | 0) == 0) {
+       break;
+      }
+      i32 = (i26 & 0 - i26) + -1 | 0;
+      i28 = i32 >>> 12 & 16;
+      i32 = i32 >>> i28;
+      i27 = i32 >>> 5 & 8;
+      i32 = i32 >>> i27;
+      i30 = i32 >>> 2 & 4;
+      i32 = i32 >>> i30;
+      i31 = i32 >>> 1 & 2;
+      i32 = i32 >>> i31;
+      i29 = i32 >>> 1 & 1;
+      i29 = HEAP32[344 + ((i27 | i28 | i30 | i31 | i29) + (i32 >>> i29) << 2) >> 2] | 0;
+     }
+     if ((i29 | 0) != 0) {
+      while (1) {
+       i27 = (HEAP32[i29 + 4 >> 2] & -8) - i12 | 0;
+       i26 = i27 >>> 0 < i25 >>> 0;
+       i25 = i26 ? i27 : i25;
+       i24 = i26 ? i29 : i24;
+       i26 = HEAP32[i29 + 16 >> 2] | 0;
+       if ((i26 | 0) != 0) {
+        i29 = i26;
+        continue;
+       }
+       i29 = HEAP32[i29 + 20 >> 2] | 0;
+       if ((i29 | 0) == 0) {
+        break;
+       }
+      }
+     }
+     if ((i24 | 0) != 0 ? i25 >>> 0 < ((HEAP32[48 >> 2] | 0) - i12 | 0) >>> 0 : 0) {
+      i4 = HEAP32[56 >> 2] | 0;
+      if (i24 >>> 0 < i4 >>> 0) {
+       _abort();
+      }
+      i2 = i24 + i12 | 0;
+      if (!(i24 >>> 0 < i2 >>> 0)) {
+       _abort();
+      }
+      i3 = HEAP32[i24 + 24 >> 2] | 0;
+      i6 = HEAP32[i24 + 12 >> 2] | 0;
+      do {
+       if ((i6 | 0) == (i24 | 0)) {
+        i6 = i24 + 20 | 0;
+        i5 = HEAP32[i6 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         i6 = i24 + 16 | 0;
+         i5 = HEAP32[i6 >> 2] | 0;
+         if ((i5 | 0) == 0) {
+          i22 = 0;
+          break;
+         }
+        }
+        while (1) {
+         i8 = i5 + 20 | 0;
+         i7 = HEAP32[i8 >> 2] | 0;
+         if ((i7 | 0) != 0) {
+          i5 = i7;
+          i6 = i8;
+          continue;
+         }
+         i7 = i5 + 16 | 0;
+         i8 = HEAP32[i7 >> 2] | 0;
+         if ((i8 | 0) == 0) {
+          break;
+         } else {
+          i5 = i8;
+          i6 = i7;
+         }
+        }
+        if (i6 >>> 0 < i4 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i6 >> 2] = 0;
+         i22 = i5;
+         break;
+        }
+       } else {
+        i5 = HEAP32[i24 + 8 >> 2] | 0;
+        if (i5 >>> 0 < i4 >>> 0) {
+         _abort();
+        }
+        i7 = i5 + 12 | 0;
+        if ((HEAP32[i7 >> 2] | 0) != (i24 | 0)) {
+         _abort();
+        }
+        i4 = i6 + 8 | 0;
+        if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+         HEAP32[i7 >> 2] = i6;
+         HEAP32[i4 >> 2] = i5;
+         i22 = i6;
+         break;
+        } else {
+         _abort();
+        }
+       }
+      } while (0);
+      do {
+       if ((i3 | 0) != 0) {
+        i4 = HEAP32[i24 + 28 >> 2] | 0;
+        i5 = 344 + (i4 << 2) | 0;
+        if ((i24 | 0) == (HEAP32[i5 >> 2] | 0)) {
+         HEAP32[i5 >> 2] = i22;
+         if ((i22 | 0) == 0) {
+          HEAP32[44 >> 2] = HEAP32[44 >> 2] & ~(1 << i4);
+          break;
+         }
+        } else {
+         if (i3 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+          _abort();
+         }
+         i4 = i3 + 16 | 0;
+         if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+          HEAP32[i4 >> 2] = i22;
+         } else {
+          HEAP32[i3 + 20 >> 2] = i22;
+         }
+         if ((i22 | 0) == 0) {
+          break;
+         }
+        }
+        if (i22 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        HEAP32[i22 + 24 >> 2] = i3;
+        i3 = HEAP32[i24 + 16 >> 2] | 0;
+        do {
+         if ((i3 | 0) != 0) {
+          if (i3 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i22 + 16 >> 2] = i3;
+           HEAP32[i3 + 24 >> 2] = i22;
+           break;
+          }
+         }
+        } while (0);
+        i3 = HEAP32[i24 + 20 >> 2] | 0;
+        if ((i3 | 0) != 0) {
+         if (i3 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i22 + 20 >> 2] = i3;
+          HEAP32[i3 + 24 >> 2] = i22;
+          break;
+         }
+        }
+       }
+      } while (0);
+      L204 : do {
+       if (!(i25 >>> 0 < 16)) {
+        HEAP32[i24 + 4 >> 2] = i12 | 3;
+        HEAP32[i24 + (i12 | 4) >> 2] = i25 | 1;
+        HEAP32[i24 + (i25 + i12) >> 2] = i25;
+        i4 = i25 >>> 3;
+        if (i25 >>> 0 < 256) {
+         i6 = i4 << 1;
+         i3 = 80 + (i6 << 2) | 0;
+         i5 = HEAP32[10] | 0;
+         i4 = 1 << i4;
+         if ((i5 & i4 | 0) != 0) {
+          i5 = 80 + (i6 + 2 << 2) | 0;
+          i4 = HEAP32[i5 >> 2] | 0;
+          if (i4 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           i21 = i5;
+           i20 = i4;
+          }
+         } else {
+          HEAP32[10] = i5 | i4;
+          i21 = 80 + (i6 + 2 << 2) | 0;
+          i20 = i3;
+         }
+         HEAP32[i21 >> 2] = i2;
+         HEAP32[i20 + 12 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i20;
+         HEAP32[i24 + (i12 + 12) >> 2] = i3;
+         break;
+        }
+        i3 = i25 >>> 8;
+        if ((i3 | 0) != 0) {
+         if (i25 >>> 0 > 16777215) {
+          i3 = 31;
+         } else {
+          i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+          i32 = i3 << i31;
+          i30 = (i32 + 520192 | 0) >>> 16 & 4;
+          i32 = i32 << i30;
+          i3 = (i32 + 245760 | 0) >>> 16 & 2;
+          i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+          i3 = i25 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+         }
+        } else {
+         i3 = 0;
+        }
+        i6 = 344 + (i3 << 2) | 0;
+        HEAP32[i24 + (i12 + 28) >> 2] = i3;
+        HEAP32[i24 + (i12 + 20) >> 2] = 0;
+        HEAP32[i24 + (i12 + 16) >> 2] = 0;
+        i4 = HEAP32[44 >> 2] | 0;
+        i5 = 1 << i3;
+        if ((i4 & i5 | 0) == 0) {
+         HEAP32[44 >> 2] = i4 | i5;
+         HEAP32[i6 >> 2] = i2;
+         HEAP32[i24 + (i12 + 24) >> 2] = i6;
+         HEAP32[i24 + (i12 + 12) >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i2;
+         break;
+        }
+        i4 = HEAP32[i6 >> 2] | 0;
+        if ((i3 | 0) == 31) {
+         i3 = 0;
+        } else {
+         i3 = 25 - (i3 >>> 1) | 0;
+        }
+        L225 : do {
+         if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i25 | 0)) {
+          i3 = i25 << i3;
+          while (1) {
+           i6 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+           i5 = HEAP32[i6 >> 2] | 0;
+           if ((i5 | 0) == 0) {
+            break;
+           }
+           if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i25 | 0)) {
+            i18 = i5;
+            break L225;
+           } else {
+            i3 = i3 << 1;
+            i4 = i5;
+           }
+          }
+          if (i6 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i6 >> 2] = i2;
+           HEAP32[i24 + (i12 + 24) >> 2] = i4;
+           HEAP32[i24 + (i12 + 12) >> 2] = i2;
+           HEAP32[i24 + (i12 + 8) >> 2] = i2;
+           break L204;
+          }
+         } else {
+          i18 = i4;
+         }
+        } while (0);
+        i4 = i18 + 8 | 0;
+        i3 = HEAP32[i4 >> 2] | 0;
+        i5 = HEAP32[56 >> 2] | 0;
+        if (i18 >>> 0 < i5 >>> 0) {
+         _abort();
+        }
+        if (i3 >>> 0 < i5 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i3 + 12 >> 2] = i2;
+         HEAP32[i4 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i3;
+         HEAP32[i24 + (i12 + 12) >> 2] = i18;
+         HEAP32[i24 + (i12 + 24) >> 2] = 0;
+         break;
+        }
+       } else {
+        i32 = i25 + i12 | 0;
+        HEAP32[i24 + 4 >> 2] = i32 | 3;
+        i32 = i24 + (i32 + 4) | 0;
+        HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+       }
+      } while (0);
+      i32 = i24 + 8 | 0;
+      STACKTOP = i1;
+      return i32 | 0;
+     }
+    }
+   } else {
+    i12 = -1;
+   }
+  }
+ } while (0);
+ i18 = HEAP32[48 >> 2] | 0;
+ if (!(i12 >>> 0 > i18 >>> 0)) {
+  i3 = i18 - i12 | 0;
+  i2 = HEAP32[60 >> 2] | 0;
+  if (i3 >>> 0 > 15) {
+   HEAP32[60 >> 2] = i2 + i12;
+   HEAP32[48 >> 2] = i3;
+   HEAP32[i2 + (i12 + 4) >> 2] = i3 | 1;
+   HEAP32[i2 + i18 >> 2] = i3;
+   HEAP32[i2 + 4 >> 2] = i12 | 3;
+  } else {
+   HEAP32[48 >> 2] = 0;
+   HEAP32[60 >> 2] = 0;
+   HEAP32[i2 + 4 >> 2] = i18 | 3;
+   i32 = i2 + (i18 + 4) | 0;
+   HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+  }
+  i32 = i2 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i18 = HEAP32[52 >> 2] | 0;
+ if (i12 >>> 0 < i18 >>> 0) {
+  i31 = i18 - i12 | 0;
+  HEAP32[52 >> 2] = i31;
+  i32 = HEAP32[64 >> 2] | 0;
+  HEAP32[64 >> 2] = i32 + i12;
+  HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+  HEAP32[i32 + 4 >> 2] = i12 | 3;
+  i32 = i32 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ do {
+  if ((HEAP32[128] | 0) == 0) {
+   i18 = _sysconf(30) | 0;
+   if ((i18 + -1 & i18 | 0) == 0) {
+    HEAP32[520 >> 2] = i18;
+    HEAP32[516 >> 2] = i18;
+    HEAP32[524 >> 2] = -1;
+    HEAP32[528 >> 2] = -1;
+    HEAP32[532 >> 2] = 0;
+    HEAP32[484 >> 2] = 0;
+    HEAP32[128] = (_time(0) | 0) & -16 ^ 1431655768;
+    break;
+   } else {
+    _abort();
+   }
+  }
+ } while (0);
+ i20 = i12 + 48 | 0;
+ i25 = HEAP32[520 >> 2] | 0;
+ i21 = i12 + 47 | 0;
+ i22 = i25 + i21 | 0;
+ i25 = 0 - i25 | 0;
+ i18 = i22 & i25;
+ if (!(i18 >>> 0 > i12 >>> 0)) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i24 = HEAP32[480 >> 2] | 0;
+ if ((i24 | 0) != 0 ? (i31 = HEAP32[472 >> 2] | 0, i32 = i31 + i18 | 0, i32 >>> 0 <= i31 >>> 0 | i32 >>> 0 > i24 >>> 0) : 0) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ L269 : do {
+  if ((HEAP32[484 >> 2] & 4 | 0) == 0) {
+   i26 = HEAP32[64 >> 2] | 0;
+   L271 : do {
+    if ((i26 | 0) != 0) {
+     i24 = 488 | 0;
+     while (1) {
+      i27 = HEAP32[i24 >> 2] | 0;
+      if (!(i27 >>> 0 > i26 >>> 0) ? (i23 = i24 + 4 | 0, (i27 + (HEAP32[i23 >> 2] | 0) | 0) >>> 0 > i26 >>> 0) : 0) {
+       break;
+      }
+      i24 = HEAP32[i24 + 8 >> 2] | 0;
+      if ((i24 | 0) == 0) {
+       i13 = 182;
+       break L271;
+      }
+     }
+     if ((i24 | 0) != 0) {
+      i25 = i22 - (HEAP32[52 >> 2] | 0) & i25;
+      if (i25 >>> 0 < 2147483647) {
+       i13 = _sbrk(i25 | 0) | 0;
+       i26 = (i13 | 0) == ((HEAP32[i24 >> 2] | 0) + (HEAP32[i23 >> 2] | 0) | 0);
+       i22 = i13;
+       i24 = i25;
+       i23 = i26 ? i13 : -1;
+       i25 = i26 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i13 = 182;
+     }
+    } else {
+     i13 = 182;
+    }
+   } while (0);
+   do {
+    if ((i13 | 0) == 182) {
+     i23 = _sbrk(0) | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i24 = i23;
+      i22 = HEAP32[516 >> 2] | 0;
+      i25 = i22 + -1 | 0;
+      if ((i25 & i24 | 0) == 0) {
+       i25 = i18;
+      } else {
+       i25 = i18 - i24 + (i25 + i24 & 0 - i22) | 0;
+      }
+      i24 = HEAP32[472 >> 2] | 0;
+      i26 = i24 + i25 | 0;
+      if (i25 >>> 0 > i12 >>> 0 & i25 >>> 0 < 2147483647) {
+       i22 = HEAP32[480 >> 2] | 0;
+       if ((i22 | 0) != 0 ? i26 >>> 0 <= i24 >>> 0 | i26 >>> 0 > i22 >>> 0 : 0) {
+        i25 = 0;
+        break;
+       }
+       i22 = _sbrk(i25 | 0) | 0;
+       i13 = (i22 | 0) == (i23 | 0);
+       i24 = i25;
+       i23 = i13 ? i23 : -1;
+       i25 = i13 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i25 = 0;
+     }
+    }
+   } while (0);
+   L291 : do {
+    if ((i13 | 0) == 191) {
+     i13 = 0 - i24 | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i17 = i23;
+      i14 = i25;
+      i13 = 202;
+      break L269;
+     }
+     do {
+      if ((i22 | 0) != (-1 | 0) & i24 >>> 0 < 2147483647 & i24 >>> 0 < i20 >>> 0 ? (i19 = HEAP32[520 >> 2] | 0, i19 = i21 - i24 + i19 & 0 - i19, i19 >>> 0 < 2147483647) : 0) {
+       if ((_sbrk(i19 | 0) | 0) == (-1 | 0)) {
+        _sbrk(i13 | 0) | 0;
+        break L291;
+       } else {
+        i24 = i19 + i24 | 0;
+        break;
+       }
+      }
+     } while (0);
+     if ((i22 | 0) != (-1 | 0)) {
+      i17 = i22;
+      i14 = i24;
+      i13 = 202;
+      break L269;
+     }
+    }
+   } while (0);
+   HEAP32[484 >> 2] = HEAP32[484 >> 2] | 4;
+   i13 = 199;
+  } else {
+   i25 = 0;
+   i13 = 199;
+  }
+ } while (0);
+ if ((((i13 | 0) == 199 ? i18 >>> 0 < 2147483647 : 0) ? (i17 = _sbrk(i18 | 0) | 0, i16 = _sbrk(0) | 0, (i16 | 0) != (-1 | 0) & (i17 | 0) != (-1 | 0) & i17 >>> 0 < i16 >>> 0) : 0) ? (i15 = i16 - i17 | 0, i14 = i15 >>> 0 > (i12 + 40 | 0) >>> 0, i14) : 0) {
+  i14 = i14 ? i15 : i25;
+  i13 = 202;
+ }
+ if ((i13 | 0) == 202) {
+  i15 = (HEAP32[472 >> 2] | 0) + i14 | 0;
+  HEAP32[472 >> 2] = i15;
+  if (i15 >>> 0 > (HEAP32[476 >> 2] | 0) >>> 0) {
+   HEAP32[476 >> 2] = i15;
+  }
+  i15 = HEAP32[64 >> 2] | 0;
+  L311 : do {
+   if ((i15 | 0) != 0) {
+    i21 = 488 | 0;
+    while (1) {
+     i16 = HEAP32[i21 >> 2] | 0;
+     i19 = i21 + 4 | 0;
+     i20 = HEAP32[i19 >> 2] | 0;
+     if ((i17 | 0) == (i16 + i20 | 0)) {
+      i13 = 214;
+      break;
+     }
+     i18 = HEAP32[i21 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i21 = i18;
+     }
+    }
+    if (((i13 | 0) == 214 ? (HEAP32[i21 + 12 >> 2] & 8 | 0) == 0 : 0) ? i15 >>> 0 >= i16 >>> 0 & i15 >>> 0 < i17 >>> 0 : 0) {
+     HEAP32[i19 >> 2] = i20 + i14;
+     i2 = (HEAP32[52 >> 2] | 0) + i14 | 0;
+     i3 = i15 + 8 | 0;
+     if ((i3 & 7 | 0) == 0) {
+      i3 = 0;
+     } else {
+      i3 = 0 - i3 & 7;
+     }
+     i32 = i2 - i3 | 0;
+     HEAP32[64 >> 2] = i15 + i3;
+     HEAP32[52 >> 2] = i32;
+     HEAP32[i15 + (i3 + 4) >> 2] = i32 | 1;
+     HEAP32[i15 + (i2 + 4) >> 2] = 40;
+     HEAP32[68 >> 2] = HEAP32[528 >> 2];
+     break;
+    }
+    if (i17 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+     HEAP32[56 >> 2] = i17;
+    }
+    i19 = i17 + i14 | 0;
+    i16 = 488 | 0;
+    while (1) {
+     if ((HEAP32[i16 >> 2] | 0) == (i19 | 0)) {
+      i13 = 224;
+      break;
+     }
+     i18 = HEAP32[i16 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i16 = i18;
+     }
+    }
+    if ((i13 | 0) == 224 ? (HEAP32[i16 + 12 >> 2] & 8 | 0) == 0 : 0) {
+     HEAP32[i16 >> 2] = i17;
+     i6 = i16 + 4 | 0;
+     HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i14;
+     i6 = i17 + 8 | 0;
+     if ((i6 & 7 | 0) == 0) {
+      i6 = 0;
+     } else {
+      i6 = 0 - i6 & 7;
+     }
+     i7 = i17 + (i14 + 8) | 0;
+     if ((i7 & 7 | 0) == 0) {
+      i13 = 0;
+     } else {
+      i13 = 0 - i7 & 7;
+     }
+     i15 = i17 + (i13 + i14) | 0;
+     i8 = i6 + i12 | 0;
+     i7 = i17 + i8 | 0;
+     i10 = i15 - (i17 + i6) - i12 | 0;
+     HEAP32[i17 + (i6 + 4) >> 2] = i12 | 3;
+     L348 : do {
+      if ((i15 | 0) != (HEAP32[64 >> 2] | 0)) {
+       if ((i15 | 0) == (HEAP32[60 >> 2] | 0)) {
+        i32 = (HEAP32[48 >> 2] | 0) + i10 | 0;
+        HEAP32[48 >> 2] = i32;
+        HEAP32[60 >> 2] = i7;
+        HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+        HEAP32[i17 + (i32 + i8) >> 2] = i32;
+        break;
+       }
+       i12 = i14 + 4 | 0;
+       i18 = HEAP32[i17 + (i12 + i13) >> 2] | 0;
+       if ((i18 & 3 | 0) == 1) {
+        i11 = i18 & -8;
+        i16 = i18 >>> 3;
+        do {
+         if (!(i18 >>> 0 < 256)) {
+          i9 = HEAP32[i17 + ((i13 | 24) + i14) >> 2] | 0;
+          i19 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          do {
+           if ((i19 | 0) == (i15 | 0)) {
+            i19 = i13 | 16;
+            i18 = i17 + (i12 + i19) | 0;
+            i16 = HEAP32[i18 >> 2] | 0;
+            if ((i16 | 0) == 0) {
+             i18 = i17 + (i19 + i14) | 0;
+             i16 = HEAP32[i18 >> 2] | 0;
+             if ((i16 | 0) == 0) {
+              i5 = 0;
+              break;
+             }
+            }
+            while (1) {
+             i20 = i16 + 20 | 0;
+             i19 = HEAP32[i20 >> 2] | 0;
+             if ((i19 | 0) != 0) {
+              i16 = i19;
+              i18 = i20;
+              continue;
+             }
+             i19 = i16 + 16 | 0;
+             i20 = HEAP32[i19 >> 2] | 0;
+             if ((i20 | 0) == 0) {
+              break;
+             } else {
+              i16 = i20;
+              i18 = i19;
+             }
+            }
+            if (i18 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i18 >> 2] = 0;
+             i5 = i16;
+             break;
+            }
+           } else {
+            i18 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+            if (i18 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i18 + 12 | 0;
+            if ((HEAP32[i16 >> 2] | 0) != (i15 | 0)) {
+             _abort();
+            }
+            i20 = i19 + 8 | 0;
+            if ((HEAP32[i20 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i19;
+             HEAP32[i20 >> 2] = i18;
+             i5 = i19;
+             break;
+            } else {
+             _abort();
+            }
+           }
+          } while (0);
+          if ((i9 | 0) != 0) {
+           i16 = HEAP32[i17 + (i14 + 28 + i13) >> 2] | 0;
+           i18 = 344 + (i16 << 2) | 0;
+           if ((i15 | 0) == (HEAP32[i18 >> 2] | 0)) {
+            HEAP32[i18 >> 2] = i5;
+            if ((i5 | 0) == 0) {
+             HEAP32[44 >> 2] = HEAP32[44 >> 2] & ~(1 << i16);
+             break;
+            }
+           } else {
+            if (i9 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i9 + 16 | 0;
+            if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i5;
+            } else {
+             HEAP32[i9 + 20 >> 2] = i5;
+            }
+            if ((i5 | 0) == 0) {
+             break;
+            }
+           }
+           if (i5 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           HEAP32[i5 + 24 >> 2] = i9;
+           i15 = i13 | 16;
+           i9 = HEAP32[i17 + (i15 + i14) >> 2] | 0;
+           do {
+            if ((i9 | 0) != 0) {
+             if (i9 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+              _abort();
+             } else {
+              HEAP32[i5 + 16 >> 2] = i9;
+              HEAP32[i9 + 24 >> 2] = i5;
+              break;
+             }
+            }
+           } while (0);
+           i9 = HEAP32[i17 + (i12 + i15) >> 2] | 0;
+           if ((i9 | 0) != 0) {
+            if (i9 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i5 + 20 >> 2] = i9;
+             HEAP32[i9 + 24 >> 2] = i5;
+             break;
+            }
+           }
+          }
+         } else {
+          i5 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+          i12 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          i18 = 80 + (i16 << 1 << 2) | 0;
+          if ((i5 | 0) != (i18 | 0)) {
+           if (i5 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           if ((HEAP32[i5 + 12 >> 2] | 0) != (i15 | 0)) {
+            _abort();
+           }
+          }
+          if ((i12 | 0) == (i5 | 0)) {
+           HEAP32[10] = HEAP32[10] & ~(1 << i16);
+           break;
+          }
+          if ((i12 | 0) != (i18 | 0)) {
+           if (i12 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           i16 = i12 + 8 | 0;
+           if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+            i9 = i16;
+           } else {
+            _abort();
+           }
+          } else {
+           i9 = i12 + 8 | 0;
+          }
+          HEAP32[i5 + 12 >> 2] = i12;
+          HEAP32[i9 >> 2] = i5;
+         }
+        } while (0);
+        i15 = i17 + ((i11 | i13) + i14) | 0;
+        i10 = i11 + i10 | 0;
+       }
+       i5 = i15 + 4 | 0;
+       HEAP32[i5 >> 2] = HEAP32[i5 >> 2] & -2;
+       HEAP32[i17 + (i8 + 4) >> 2] = i10 | 1;
+       HEAP32[i17 + (i10 + i8) >> 2] = i10;
+       i5 = i10 >>> 3;
+       if (i10 >>> 0 < 256) {
+        i10 = i5 << 1;
+        i2 = 80 + (i10 << 2) | 0;
+        i9 = HEAP32[10] | 0;
+        i5 = 1 << i5;
+        if ((i9 & i5 | 0) != 0) {
+         i9 = 80 + (i10 + 2 << 2) | 0;
+         i5 = HEAP32[i9 >> 2] | 0;
+         if (i5 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          i3 = i9;
+          i4 = i5;
+         }
+        } else {
+         HEAP32[10] = i9 | i5;
+         i3 = 80 + (i10 + 2 << 2) | 0;
+         i4 = i2;
+        }
+        HEAP32[i3 >> 2] = i7;
+        HEAP32[i4 + 12 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        break;
+       }
+       i3 = i10 >>> 8;
+       if ((i3 | 0) != 0) {
+        if (i10 >>> 0 > 16777215) {
+         i3 = 31;
+        } else {
+         i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+         i32 = i3 << i31;
+         i30 = (i32 + 520192 | 0) >>> 16 & 4;
+         i32 = i32 << i30;
+         i3 = (i32 + 245760 | 0) >>> 16 & 2;
+         i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+         i3 = i10 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+        }
+       } else {
+        i3 = 0;
+       }
+       i4 = 344 + (i3 << 2) | 0;
+       HEAP32[i17 + (i8 + 28) >> 2] = i3;
+       HEAP32[i17 + (i8 + 20) >> 2] = 0;
+       HEAP32[i17 + (i8 + 16) >> 2] = 0;
+       i9 = HEAP32[44 >> 2] | 0;
+       i5 = 1 << i3;
+       if ((i9 & i5 | 0) == 0) {
+        HEAP32[44 >> 2] = i9 | i5;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 24) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i7;
+        break;
+       }
+       i4 = HEAP32[i4 >> 2] | 0;
+       if ((i3 | 0) == 31) {
+        i3 = 0;
+       } else {
+        i3 = 25 - (i3 >>> 1) | 0;
+       }
+       L444 : do {
+        if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i10 | 0)) {
+         i3 = i10 << i3;
+         while (1) {
+          i5 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+          i9 = HEAP32[i5 >> 2] | 0;
+          if ((i9 | 0) == 0) {
+           break;
+          }
+          if ((HEAP32[i9 + 4 >> 2] & -8 | 0) == (i10 | 0)) {
+           i2 = i9;
+           break L444;
+          } else {
+           i3 = i3 << 1;
+           i4 = i9;
+          }
+         }
+         if (i5 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i5 >> 2] = i7;
+          HEAP32[i17 + (i8 + 24) >> 2] = i4;
+          HEAP32[i17 + (i8 + 12) >> 2] = i7;
+          HEAP32[i17 + (i8 + 8) >> 2] = i7;
+          break L348;
+         }
+        } else {
+         i2 = i4;
+        }
+       } while (0);
+       i4 = i2 + 8 | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       i5 = HEAP32[56 >> 2] | 0;
+       if (i2 >>> 0 < i5 >>> 0) {
+        _abort();
+       }
+       if (i3 >>> 0 < i5 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i3 + 12 >> 2] = i7;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i3;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        HEAP32[i17 + (i8 + 24) >> 2] = 0;
+        break;
+       }
+      } else {
+       i32 = (HEAP32[52 >> 2] | 0) + i10 | 0;
+       HEAP32[52 >> 2] = i32;
+       HEAP32[64 >> 2] = i7;
+       HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+      }
+     } while (0);
+     i32 = i17 + (i6 | 8) | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i3 = 488 | 0;
+    while (1) {
+     i2 = HEAP32[i3 >> 2] | 0;
+     if (!(i2 >>> 0 > i15 >>> 0) ? (i11 = HEAP32[i3 + 4 >> 2] | 0, i10 = i2 + i11 | 0, i10 >>> 0 > i15 >>> 0) : 0) {
+      break;
+     }
+     i3 = HEAP32[i3 + 8 >> 2] | 0;
+    }
+    i3 = i2 + (i11 + -39) | 0;
+    if ((i3 & 7 | 0) == 0) {
+     i3 = 0;
+    } else {
+     i3 = 0 - i3 & 7;
+    }
+    i2 = i2 + (i11 + -47 + i3) | 0;
+    i2 = i2 >>> 0 < (i15 + 16 | 0) >>> 0 ? i15 : i2;
+    i3 = i2 + 8 | 0;
+    i4 = i17 + 8 | 0;
+    if ((i4 & 7 | 0) == 0) {
+     i4 = 0;
+    } else {
+     i4 = 0 - i4 & 7;
+    }
+    i32 = i14 + -40 - i4 | 0;
+    HEAP32[64 >> 2] = i17 + i4;
+    HEAP32[52 >> 2] = i32;
+    HEAP32[i17 + (i4 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[68 >> 2] = HEAP32[528 >> 2];
+    HEAP32[i2 + 4 >> 2] = 27;
+    HEAP32[i3 + 0 >> 2] = HEAP32[488 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[492 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[496 >> 2];
+    HEAP32[i3 + 12 >> 2] = HEAP32[500 >> 2];
+    HEAP32[488 >> 2] = i17;
+    HEAP32[492 >> 2] = i14;
+    HEAP32[500 >> 2] = 0;
+    HEAP32[496 >> 2] = i3;
+    i4 = i2 + 28 | 0;
+    HEAP32[i4 >> 2] = 7;
+    if ((i2 + 32 | 0) >>> 0 < i10 >>> 0) {
+     while (1) {
+      i3 = i4 + 4 | 0;
+      HEAP32[i3 >> 2] = 7;
+      if ((i4 + 8 | 0) >>> 0 < i10 >>> 0) {
+       i4 = i3;
+      } else {
+       break;
+      }
+     }
+    }
+    if ((i2 | 0) != (i15 | 0)) {
+     i2 = i2 - i15 | 0;
+     i3 = i15 + (i2 + 4) | 0;
+     HEAP32[i3 >> 2] = HEAP32[i3 >> 2] & -2;
+     HEAP32[i15 + 4 >> 2] = i2 | 1;
+     HEAP32[i15 + i2 >> 2] = i2;
+     i3 = i2 >>> 3;
+     if (i2 >>> 0 < 256) {
+      i4 = i3 << 1;
+      i2 = 80 + (i4 << 2) | 0;
+      i5 = HEAP32[10] | 0;
+      i3 = 1 << i3;
+      if ((i5 & i3 | 0) != 0) {
+       i4 = 80 + (i4 + 2 << 2) | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       if (i3 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i7 = i4;
+        i8 = i3;
+       }
+      } else {
+       HEAP32[10] = i5 | i3;
+       i7 = 80 + (i4 + 2 << 2) | 0;
+       i8 = i2;
+      }
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i8 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i8;
+      HEAP32[i15 + 12 >> 2] = i2;
+      break;
+     }
+     i3 = i2 >>> 8;
+     if ((i3 | 0) != 0) {
+      if (i2 >>> 0 > 16777215) {
+       i3 = 31;
+      } else {
+       i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+       i32 = i3 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i3 = (i32 + 245760 | 0) >>> 16 & 2;
+       i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+       i3 = i2 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+      }
+     } else {
+      i3 = 0;
+     }
+     i7 = 344 + (i3 << 2) | 0;
+     HEAP32[i15 + 28 >> 2] = i3;
+     HEAP32[i15 + 20 >> 2] = 0;
+     HEAP32[i15 + 16 >> 2] = 0;
+     i4 = HEAP32[44 >> 2] | 0;
+     i5 = 1 << i3;
+     if ((i4 & i5 | 0) == 0) {
+      HEAP32[44 >> 2] = i4 | i5;
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i7;
+      HEAP32[i15 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i15;
+      break;
+     }
+     i4 = HEAP32[i7 >> 2] | 0;
+     if ((i3 | 0) == 31) {
+      i3 = 0;
+     } else {
+      i3 = 25 - (i3 >>> 1) | 0;
+     }
+     L499 : do {
+      if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i2 | 0)) {
+       i3 = i2 << i3;
+       while (1) {
+        i7 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+        i5 = HEAP32[i7 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         break;
+        }
+        if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i2 | 0)) {
+         i6 = i5;
+         break L499;
+        } else {
+         i3 = i3 << 1;
+         i4 = i5;
+        }
+       }
+       if (i7 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i7 >> 2] = i15;
+        HEAP32[i15 + 24 >> 2] = i4;
+        HEAP32[i15 + 12 >> 2] = i15;
+        HEAP32[i15 + 8 >> 2] = i15;
+        break L311;
+       }
+      } else {
+       i6 = i4;
+      }
+     } while (0);
+     i4 = i6 + 8 | 0;
+     i3 = HEAP32[i4 >> 2] | 0;
+     i2 = HEAP32[56 >> 2] | 0;
+     if (i6 >>> 0 < i2 >>> 0) {
+      _abort();
+     }
+     if (i3 >>> 0 < i2 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i3 + 12 >> 2] = i15;
+      HEAP32[i4 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i3;
+      HEAP32[i15 + 12 >> 2] = i6;
+      HEAP32[i15 + 24 >> 2] = 0;
+      break;
+     }
+    }
+   } else {
+    i32 = HEAP32[56 >> 2] | 0;
+    if ((i32 | 0) == 0 | i17 >>> 0 < i32 >>> 0) {
+     HEAP32[56 >> 2] = i17;
+    }
+    HEAP32[488 >> 2] = i17;
+    HEAP32[492 >> 2] = i14;
+    HEAP32[500 >> 2] = 0;
+    HEAP32[76 >> 2] = HEAP32[128];
+    HEAP32[72 >> 2] = -1;
+    i2 = 0;
+    do {
+     i32 = i2 << 1;
+     i31 = 80 + (i32 << 2) | 0;
+     HEAP32[80 + (i32 + 3 << 2) >> 2] = i31;
+     HEAP32[80 + (i32 + 2 << 2) >> 2] = i31;
+     i2 = i2 + 1 | 0;
+    } while ((i2 | 0) != 32);
+    i2 = i17 + 8 | 0;
+    if ((i2 & 7 | 0) == 0) {
+     i2 = 0;
+    } else {
+     i2 = 0 - i2 & 7;
+    }
+    i32 = i14 + -40 - i2 | 0;
+    HEAP32[64 >> 2] = i17 + i2;
+    HEAP32[52 >> 2] = i32;
+    HEAP32[i17 + (i2 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[68 >> 2] = HEAP32[528 >> 2];
+   }
+  } while (0);
+  i2 = HEAP32[52 >> 2] | 0;
+  if (i2 >>> 0 > i12 >>> 0) {
+   i31 = i2 - i12 | 0;
+   HEAP32[52 >> 2] = i31;
+   i32 = HEAP32[64 >> 2] | 0;
+   HEAP32[64 >> 2] = i32 + i12;
+   HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+   HEAP32[i32 + 4 >> 2] = i12 | 3;
+   i32 = i32 + 8 | 0;
+   STACKTOP = i1;
+   return i32 | 0;
+  }
+ }
+ HEAP32[(___errno_location() | 0) >> 2] = 12;
+ i32 = 0;
+ STACKTOP = i1;
+ return i32 | 0;
+}
+function _free(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i1 = STACKTOP;
+ if ((i7 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i15 = i7 + -8 | 0;
+ i16 = HEAP32[56 >> 2] | 0;
+ if (i15 >>> 0 < i16 >>> 0) {
+  _abort();
+ }
+ i13 = HEAP32[i7 + -4 >> 2] | 0;
+ i12 = i13 & 3;
+ if ((i12 | 0) == 1) {
+  _abort();
+ }
+ i8 = i13 & -8;
+ i6 = i7 + (i8 + -8) | 0;
+ do {
+  if ((i13 & 1 | 0) == 0) {
+   i19 = HEAP32[i15 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   i15 = -8 - i19 | 0;
+   i13 = i7 + i15 | 0;
+   i12 = i19 + i8 | 0;
+   if (i13 >>> 0 < i16 >>> 0) {
+    _abort();
+   }
+   if ((i13 | 0) == (HEAP32[60 >> 2] | 0)) {
+    i2 = i7 + (i8 + -4) | 0;
+    if ((HEAP32[i2 >> 2] & 3 | 0) != 3) {
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    HEAP32[48 >> 2] = i12;
+    HEAP32[i2 >> 2] = HEAP32[i2 >> 2] & -2;
+    HEAP32[i7 + (i15 + 4) >> 2] = i12 | 1;
+    HEAP32[i6 >> 2] = i12;
+    STACKTOP = i1;
+    return;
+   }
+   i18 = i19 >>> 3;
+   if (i19 >>> 0 < 256) {
+    i2 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+    i11 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+    i14 = 80 + (i18 << 1 << 2) | 0;
+    if ((i2 | 0) != (i14 | 0)) {
+     if (i2 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i2 + 12 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+    }
+    if ((i11 | 0) == (i2 | 0)) {
+     HEAP32[10] = HEAP32[10] & ~(1 << i18);
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    if ((i11 | 0) != (i14 | 0)) {
+     if (i11 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i14 = i11 + 8 | 0;
+     if ((HEAP32[i14 >> 2] | 0) == (i13 | 0)) {
+      i17 = i14;
+     } else {
+      _abort();
+     }
+    } else {
+     i17 = i11 + 8 | 0;
+    }
+    HEAP32[i2 + 12 >> 2] = i11;
+    HEAP32[i17 >> 2] = i2;
+    i2 = i13;
+    i11 = i12;
+    break;
+   }
+   i17 = HEAP32[i7 + (i15 + 24) >> 2] | 0;
+   i18 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+   do {
+    if ((i18 | 0) == (i13 | 0)) {
+     i19 = i7 + (i15 + 20) | 0;
+     i18 = HEAP32[i19 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      i19 = i7 + (i15 + 16) | 0;
+      i18 = HEAP32[i19 >> 2] | 0;
+      if ((i18 | 0) == 0) {
+       i14 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i21 = i18 + 20 | 0;
+      i20 = HEAP32[i21 >> 2] | 0;
+      if ((i20 | 0) != 0) {
+       i18 = i20;
+       i19 = i21;
+       continue;
+      }
+      i20 = i18 + 16 | 0;
+      i21 = HEAP32[i20 >> 2] | 0;
+      if ((i21 | 0) == 0) {
+       break;
+      } else {
+       i18 = i21;
+       i19 = i20;
+      }
+     }
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i19 >> 2] = 0;
+      i14 = i18;
+      break;
+     }
+    } else {
+     i19 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i16 = i19 + 12 | 0;
+     if ((HEAP32[i16 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+     i20 = i18 + 8 | 0;
+     if ((HEAP32[i20 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i18;
+      HEAP32[i20 >> 2] = i19;
+      i14 = i18;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i17 | 0) != 0) {
+    i18 = HEAP32[i7 + (i15 + 28) >> 2] | 0;
+    i16 = 344 + (i18 << 2) | 0;
+    if ((i13 | 0) == (HEAP32[i16 >> 2] | 0)) {
+     HEAP32[i16 >> 2] = i14;
+     if ((i14 | 0) == 0) {
+      HEAP32[44 >> 2] = HEAP32[44 >> 2] & ~(1 << i18);
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     if (i17 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i16 = i17 + 16 | 0;
+     if ((HEAP32[i16 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i14;
+     } else {
+      HEAP32[i17 + 20 >> 2] = i14;
+     }
+     if ((i14 | 0) == 0) {
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    }
+    if (i14 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i14 + 24 >> 2] = i17;
+    i16 = HEAP32[i7 + (i15 + 16) >> 2] | 0;
+    do {
+     if ((i16 | 0) != 0) {
+      if (i16 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i14 + 16 >> 2] = i16;
+       HEAP32[i16 + 24 >> 2] = i14;
+       break;
+      }
+     }
+    } while (0);
+    i15 = HEAP32[i7 + (i15 + 20) >> 2] | 0;
+    if ((i15 | 0) != 0) {
+     if (i15 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i14 + 20 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i14;
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     i2 = i13;
+     i11 = i12;
+    }
+   } else {
+    i2 = i13;
+    i11 = i12;
+   }
+  } else {
+   i2 = i15;
+   i11 = i8;
+  }
+ } while (0);
+ if (!(i2 >>> 0 < i6 >>> 0)) {
+  _abort();
+ }
+ i12 = i7 + (i8 + -4) | 0;
+ i13 = HEAP32[i12 >> 2] | 0;
+ if ((i13 & 1 | 0) == 0) {
+  _abort();
+ }
+ if ((i13 & 2 | 0) == 0) {
+  if ((i6 | 0) == (HEAP32[64 >> 2] | 0)) {
+   i21 = (HEAP32[52 >> 2] | 0) + i11 | 0;
+   HEAP32[52 >> 2] = i21;
+   HEAP32[64 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   if ((i2 | 0) != (HEAP32[60 >> 2] | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[60 >> 2] = 0;
+   HEAP32[48 >> 2] = 0;
+   STACKTOP = i1;
+   return;
+  }
+  if ((i6 | 0) == (HEAP32[60 >> 2] | 0)) {
+   i21 = (HEAP32[48 >> 2] | 0) + i11 | 0;
+   HEAP32[48 >> 2] = i21;
+   HEAP32[60 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   HEAP32[i2 + i21 >> 2] = i21;
+   STACKTOP = i1;
+   return;
+  }
+  i11 = (i13 & -8) + i11 | 0;
+  i12 = i13 >>> 3;
+  do {
+   if (!(i13 >>> 0 < 256)) {
+    i10 = HEAP32[i7 + (i8 + 16) >> 2] | 0;
+    i15 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    do {
+     if ((i15 | 0) == (i6 | 0)) {
+      i13 = i7 + (i8 + 12) | 0;
+      i12 = HEAP32[i13 >> 2] | 0;
+      if ((i12 | 0) == 0) {
+       i13 = i7 + (i8 + 8) | 0;
+       i12 = HEAP32[i13 >> 2] | 0;
+       if ((i12 | 0) == 0) {
+        i9 = 0;
+        break;
+       }
+      }
+      while (1) {
+       i14 = i12 + 20 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) != 0) {
+        i12 = i15;
+        i13 = i14;
+        continue;
+       }
+       i14 = i12 + 16 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) == 0) {
+        break;
+       } else {
+        i12 = i15;
+        i13 = i14;
+       }
+      }
+      if (i13 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 >> 2] = 0;
+       i9 = i12;
+       break;
+      }
+     } else {
+      i13 = HEAP32[i7 + i8 >> 2] | 0;
+      if (i13 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i14 = i13 + 12 | 0;
+      if ((HEAP32[i14 >> 2] | 0) != (i6 | 0)) {
+       _abort();
+      }
+      i12 = i15 + 8 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i14 >> 2] = i15;
+       HEAP32[i12 >> 2] = i13;
+       i9 = i15;
+       break;
+      } else {
+       _abort();
+      }
+     }
+    } while (0);
+    if ((i10 | 0) != 0) {
+     i12 = HEAP32[i7 + (i8 + 20) >> 2] | 0;
+     i13 = 344 + (i12 << 2) | 0;
+     if ((i6 | 0) == (HEAP32[i13 >> 2] | 0)) {
+      HEAP32[i13 >> 2] = i9;
+      if ((i9 | 0) == 0) {
+       HEAP32[44 >> 2] = HEAP32[44 >> 2] & ~(1 << i12);
+       break;
+      }
+     } else {
+      if (i10 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i12 = i10 + 16 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i12 >> 2] = i9;
+      } else {
+       HEAP32[i10 + 20 >> 2] = i9;
+      }
+      if ((i9 | 0) == 0) {
+       break;
+      }
+     }
+     if (i9 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     HEAP32[i9 + 24 >> 2] = i10;
+     i6 = HEAP32[i7 + (i8 + 8) >> 2] | 0;
+     do {
+      if ((i6 | 0) != 0) {
+       if (i6 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i9 + 16 >> 2] = i6;
+        HEAP32[i6 + 24 >> 2] = i9;
+        break;
+       }
+      }
+     } while (0);
+     i6 = HEAP32[i7 + (i8 + 12) >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      if (i6 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i9 + 20 >> 2] = i6;
+       HEAP32[i6 + 24 >> 2] = i9;
+       break;
+      }
+     }
+    }
+   } else {
+    i9 = HEAP32[i7 + i8 >> 2] | 0;
+    i7 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    i8 = 80 + (i12 << 1 << 2) | 0;
+    if ((i9 | 0) != (i8 | 0)) {
+     if (i9 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i9 + 12 >> 2] | 0) != (i6 | 0)) {
+      _abort();
+     }
+    }
+    if ((i7 | 0) == (i9 | 0)) {
+     HEAP32[10] = HEAP32[10] & ~(1 << i12);
+     break;
+    }
+    if ((i7 | 0) != (i8 | 0)) {
+     if (i7 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i8 = i7 + 8 | 0;
+     if ((HEAP32[i8 >> 2] | 0) == (i6 | 0)) {
+      i10 = i8;
+     } else {
+      _abort();
+     }
+    } else {
+     i10 = i7 + 8 | 0;
+    }
+    HEAP32[i9 + 12 >> 2] = i7;
+    HEAP32[i10 >> 2] = i9;
+   }
+  } while (0);
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+  if ((i2 | 0) == (HEAP32[60 >> 2] | 0)) {
+   HEAP32[48 >> 2] = i11;
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  HEAP32[i12 >> 2] = i13 & -2;
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+ }
+ i6 = i11 >>> 3;
+ if (i11 >>> 0 < 256) {
+  i7 = i6 << 1;
+  i3 = 80 + (i7 << 2) | 0;
+  i8 = HEAP32[10] | 0;
+  i6 = 1 << i6;
+  if ((i8 & i6 | 0) != 0) {
+   i6 = 80 + (i7 + 2 << 2) | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if (i7 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+    _abort();
+   } else {
+    i4 = i6;
+    i5 = i7;
+   }
+  } else {
+   HEAP32[10] = i8 | i6;
+   i4 = 80 + (i7 + 2 << 2) | 0;
+   i5 = i3;
+  }
+  HEAP32[i4 >> 2] = i2;
+  HEAP32[i5 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i5;
+  HEAP32[i2 + 12 >> 2] = i3;
+  STACKTOP = i1;
+  return;
+ }
+ i4 = i11 >>> 8;
+ if ((i4 | 0) != 0) {
+  if (i11 >>> 0 > 16777215) {
+   i4 = 31;
+  } else {
+   i20 = (i4 + 1048320 | 0) >>> 16 & 8;
+   i21 = i4 << i20;
+   i19 = (i21 + 520192 | 0) >>> 16 & 4;
+   i21 = i21 << i19;
+   i4 = (i21 + 245760 | 0) >>> 16 & 2;
+   i4 = 14 - (i19 | i20 | i4) + (i21 << i4 >>> 15) | 0;
+   i4 = i11 >>> (i4 + 7 | 0) & 1 | i4 << 1;
+  }
+ } else {
+  i4 = 0;
+ }
+ i5 = 344 + (i4 << 2) | 0;
+ HEAP32[i2 + 28 >> 2] = i4;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ i7 = HEAP32[44 >> 2] | 0;
+ i6 = 1 << i4;
+ L199 : do {
+  if ((i7 & i6 | 0) != 0) {
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((i4 | 0) == 31) {
+    i4 = 0;
+   } else {
+    i4 = 25 - (i4 >>> 1) | 0;
+   }
+   L205 : do {
+    if ((HEAP32[i5 + 4 >> 2] & -8 | 0) != (i11 | 0)) {
+     i4 = i11 << i4;
+     i7 = i5;
+     while (1) {
+      i6 = i7 + (i4 >>> 31 << 2) + 16 | 0;
+      i5 = HEAP32[i6 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       break;
+      }
+      if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i11 | 0)) {
+       i3 = i5;
+       break L205;
+      } else {
+       i4 = i4 << 1;
+       i7 = i5;
+      }
+     }
+     if (i6 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i6 >> 2] = i2;
+      HEAP32[i2 + 24 >> 2] = i7;
+      HEAP32[i2 + 12 >> 2] = i2;
+      HEAP32[i2 + 8 >> 2] = i2;
+      break L199;
+     }
+    } else {
+     i3 = i5;
+    }
+   } while (0);
+   i5 = i3 + 8 | 0;
+   i4 = HEAP32[i5 >> 2] | 0;
+   i6 = HEAP32[56 >> 2] | 0;
+   if (i3 >>> 0 < i6 >>> 0) {
+    _abort();
+   }
+   if (i4 >>> 0 < i6 >>> 0) {
+    _abort();
+   } else {
+    HEAP32[i4 + 12 >> 2] = i2;
+    HEAP32[i5 >> 2] = i2;
+    HEAP32[i2 + 8 >> 2] = i4;
+    HEAP32[i2 + 12 >> 2] = i3;
+    HEAP32[i2 + 24 >> 2] = 0;
+    break;
+   }
+  } else {
+   HEAP32[44 >> 2] = i7 | i6;
+   HEAP32[i5 >> 2] = i2;
+   HEAP32[i2 + 24 >> 2] = i5;
+   HEAP32[i2 + 12 >> 2] = i2;
+   HEAP32[i2 + 8 >> 2] = i2;
+  }
+ } while (0);
+ i21 = (HEAP32[72 >> 2] | 0) + -1 | 0;
+ HEAP32[72 >> 2] = i21;
+ if ((i21 | 0) == 0) {
+  i2 = 496 | 0;
+ } else {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i2 = HEAP32[i2 >> 2] | 0;
+  if ((i2 | 0) == 0) {
+   break;
+  } else {
+   i2 = i2 + 8 | 0;
+  }
+ }
+ HEAP32[72 >> 2] = -1;
+ STACKTOP = i1;
+ return;
+}
+function _main(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ L1 : do {
+  if ((i3 | 0) > 1) {
+   i3 = HEAP8[HEAP32[i5 + 4 >> 2] | 0] | 0;
+   switch (i3 | 0) {
+   case 50:
+    {
+     i3 = 400;
+     break L1;
+    }
+   case 51:
+    {
+     i4 = 4;
+     break L1;
+    }
+   case 52:
+    {
+     i3 = 4e3;
+     break L1;
+    }
+   case 53:
+    {
+     i3 = 8e3;
+     break L1;
+    }
+   case 49:
+    {
+     i3 = 55;
+     break L1;
+    }
+   case 48:
+    {
+     i7 = 0;
+     STACKTOP = i1;
+     return i7 | 0;
+    }
+   default:
+    {
+     HEAP32[i2 >> 2] = i3 + -48;
+     _printf(8, i2 | 0) | 0;
+     i7 = -1;
+     STACKTOP = i1;
+     return i7 | 0;
+    }
+   }
+  } else {
+   i4 = 4;
+  }
+ } while (0);
+ if ((i4 | 0) == 4) {
+  i3 = 800;
+ }
+ i5 = _malloc(1048576) | 0;
+ i6 = 0;
+ i4 = 0;
+ do {
+  i7 = 0;
+  while (1) {
+   HEAP8[i5 + i7 | 0] = i7 + i6;
+   i7 = i7 + 1 | 0;
+   if ((i7 | 0) == 1048576) {
+    i7 = 0;
+    break;
+   }
+  }
+  do {
+   i6 = (HEAP8[i5 + i7 | 0] & 1) + i6 | 0;
+   i7 = i7 + 1 | 0;
+  } while ((i7 | 0) != 1048576);
+  i6 = (i6 | 0) % 1e3 | 0;
+  i4 = i4 + 1 | 0;
+ } while ((i4 | 0) < (i3 | 0));
+ HEAP32[i2 >> 2] = i6;
+ _printf(24, i2 | 0) | 0;
+ i7 = 0;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function runPostSets() {}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+
+// EMSCRIPTEN_END_FUNCS
+
+
+  return { _strlen: _strlen, _free: _free, _main: _main, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9 };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "_fflush": _fflush, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_printf": _printf, "_send": _send, "_pwrite": _pwrite, "_abort": _abort, "___setErrNo": ___setErrNo, "_fwrite": _fwrite, "_sbrk": _sbrk, "_time": _time, "_mkport": _mkport, "__reallyNegative": __reallyNegative, "__formatString": __formatString, "_fileno": _fileno, "_write": _write, "_fprintf": _fprintf, "_sysconf": _sysconf, "___errno_location": ___errno_location, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _free = Module["_free"] = asm["_free"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var _malloc = Module["_malloc"] = asm["_malloc"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/primes.js b/test/mjsunit/asm/embenchen/primes.js
new file mode 100644
index 0000000..32f80b8
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/primes.js
@@ -0,0 +1,5984 @@
+var EXPECTED_OUTPUT = 'lastprime: 387677.\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(35);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([101,114,114,111,114,58,32,37,100,92,110,0,0,0,0,0,108,97,115,116,112,114,105,109,101,58,32,37,100,46,10,0], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+  function _malloc(bytes) {
+      /* Over-allocate to make sure it is byte-aligned by 8.
+       * This will leak memory, but this is only the dummy
+       * implementation (replaced by dlmalloc normally) so
+       * not an issue.
+       */
+      var ptr = Runtime.dynamicAlloc(bytes + 8);
+      return (ptr+8) & 0xFFFFFFF8;
+    }
+  Module["_malloc"] = _malloc;
+
+
+  Module["_memset"] = _memset;
+
+  function _free() {
+  }
+  Module["_free"] = _free;
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+            Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+            Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+            // just add the mouse delta to the current absolut mouse position
+            // FIXME: ideally this should be clamped against the canvas size and zero
+            Browser.mouseX += Browser.mouseMovementX;
+            Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+
+
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+
+  var _sqrtf=Math_sqrt;
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var _free=env._free;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _printf=env._printf;
+  var _send=env._send;
+  var _pwrite=env._pwrite;
+  var _sqrtf=env._sqrtf;
+  var __reallyNegative=env.__reallyNegative;
+  var _fwrite=env._fwrite;
+  var _malloc=env._malloc;
+  var _mkport=env._mkport;
+  var _fprintf=env._fprintf;
+  var ___setErrNo=env.___setErrNo;
+  var __formatString=env.__formatString;
+  var _fileno=env._fileno;
+  var _fflush=env._fflush;
+  var _write=env._write;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _main(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i6 = 0, i7 = 0, d8 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ L1 : do {
+  if ((i3 | 0) > 1) {
+   i3 = HEAP8[HEAP32[i5 + 4 >> 2] | 0] | 0;
+   switch (i3 | 0) {
+   case 50:
+    {
+     i3 = 13e4;
+     break L1;
+    }
+   case 51:
+    {
+     i4 = 4;
+     break L1;
+    }
+   case 52:
+    {
+     i3 = 61e4;
+     break L1;
+    }
+   case 53:
+    {
+     i3 = 101e4;
+     break L1;
+    }
+   case 49:
+    {
+     i3 = 33e3;
+     break L1;
+    }
+   case 48:
+    {
+     i7 = 0;
+     STACKTOP = i1;
+     return i7 | 0;
+    }
+   default:
+    {
+     HEAP32[i2 >> 2] = i3 + -48;
+     _printf(8, i2 | 0) | 0;
+     i7 = -1;
+     STACKTOP = i1;
+     return i7 | 0;
+    }
+   }
+  } else {
+   i4 = 4;
+  }
+ } while (0);
+ if ((i4 | 0) == 4) {
+  i3 = 22e4;
+ }
+ i4 = 2;
+ i5 = 0;
+ while (1) {
+  d8 = +Math_sqrt(+(+(i4 | 0)));
+  L15 : do {
+   if (d8 > 2.0) {
+    i7 = 2;
+    while (1) {
+     i6 = i7 + 1 | 0;
+     if (((i4 | 0) % (i7 | 0) | 0 | 0) == 0) {
+      i6 = 0;
+      break L15;
+     }
+     if (+(i6 | 0) < d8) {
+      i7 = i6;
+     } else {
+      i6 = 1;
+      break;
+     }
+    }
+   } else {
+    i6 = 1;
+   }
+  } while (0);
+  i5 = i6 + i5 | 0;
+  if ((i5 | 0) >= (i3 | 0)) {
+   break;
+  } else {
+   i4 = i4 + 1 | 0;
+  }
+ }
+ HEAP32[i2 >> 2] = i4;
+ _printf(24, i2 | 0) | 0;
+ i7 = 0;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function runPostSets() {}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+
+// EMSCRIPTEN_END_FUNCS
+
+
+  return { _strlen: _strlen, _memcpy: _memcpy, _main: _main, _memset: _memset, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9 };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "_free": _free, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_printf": _printf, "_send": _send, "_pwrite": _pwrite, "_sqrtf": _sqrtf, "__reallyNegative": __reallyNegative, "_fwrite": _fwrite, "_malloc": _malloc, "_mkport": _mkport, "_fprintf": _fprintf, "___setErrNo": ___setErrNo, "__formatString": __formatString, "_fileno": _fileno, "_fflush": _fflush, "_write": _write, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/zlib.js b/test/mjsunit/asm/embenchen/zlib.js
new file mode 100644
index 0000000..d90ee38
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/zlib.js
@@ -0,0 +1,14752 @@
+var EXPECTED_OUTPUT = 'sizes: 100000,25906\nok.\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(14963);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,115,105,122,101,115,58,32,37,100,44,37,100,10,0,0,0,100,101,99,111,109,112,114,101,115,115,101,100,83,105,122,101,32,61,61,32,115,105,122,101,0,0,0,0,0,0,0,0,47,116,109,112,47,101,109,115,99,114,105,112,116,101,110,95,116,101,109,112,47,122,108,105,98,46,99,0,0,0,0,0,100,111,105,116,0,0,0,0,115,116,114,99,109,112,40,98,117,102,102,101,114,44,32,98,117,102,102,101,114,51,41,32,61,61,32,48,0,0,0,0,101,114,114,111,114,58,32,37,100,92,110,0,0,0,0,0,111,107,46,0,0,0,0,0,49,46,50,46,53,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,0,4,0,8,0,4,0,2,0,0,0,4,0,5,0,16,0,8,0,2,0,0,0,4,0,6,0,32,0,32,0,2,0,0,0,4,0,4,0,16,0,16,0,3,0,0,0,8,0,16,0,32,0,32,0,3,0,0,0,8,0,16,0,128,0,128,0,3,0,0,0,8,0,32,0,128,0,0,1,3,0,0,0,32,0,128,0,2,1,0,4,3,0,0,0,32,0,2,1,2,1,0,16,3,0,0,0,0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,0,0,16,17,18,18,19,19,20,20,20,20,21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,1,2,3,4,5,6,7,8,8,9,9,10,10,11,11,12,12,12,12,13,13,13,13,14,14,14,14,15,15,15,15,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,112,4,0,0,104,9,0,0,1,1,0,0,30,1,0,0,15,0,0,0,0,0,0,0,240,8,0,0,88,10,0,0,0,0,0,0,30,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,96,11,0,0,0,0,0,0,19,0,0,0,7,0,0,0,0,0,0,0,12,0,8,0,140,0,8,0,76,0,8,0,204,0,8,0,44,0,8,0,172,0,8,0,108,0,8,0,236,0,8,0,28,0,8,0,156,0,8,0,92,0,8,0,220,0,8,0,60,0,8,0,188,0,8,0,124,0,8,0,252,0,8,0,2,0,8,0,130,0,8,0,66,0,8,0,194,0,8,0,34,0,8,0,162,0,8,0,98,0,8,0,226,0,8,0,18,0,8,0,146,0,8,0,82,0,8,0,210,0,8,0,50,0,8,0,178,0,8,0,114,0,8,0,242,0,8,0,10,0,8,0,138,0,8,0,74,0,8,0,202,0,8,0,42,0,8,0,170,0,8,0,106,0,8,0,234,0,8,0,26,0,8,0,154,0,8,0,90,0,8,0,218,0,8,0,58,0,8,0,186,0,8,0,122,0,8,0,250,0,8,0,6,0,8,0,134,0,8,0,70,0,8,0,198,0,8,0,38,0,8,0,166,0,8,0,102,0,8,0,230,0,8,0,22,0,8,0,150,0,8,0,86,0,8,0,214,0,8,0,54,0,8,0,182,0,8,0,118,0,8,0,246,0,8,0,14,0,8,0,142,0,8,0,78,0,8,0,206,0,8,0,46,0,8,0,174,0,8,0,110,0,8,0,238,0,8,0,30,0,8,0,158,0,8,0,94,0,8,0,222,0,8,0,62,0,8,0,190,0,8,0,126,0,8,0,254,0,8,0,1,0,8,0,129,0,8,0,65,0,8,0,193,0,8,0,33,0,8,0,161,0,8,0,97,0,8,0,225,0,8,0,17,0,8,0,145,0,8,0,81,0,8,0,209,0,8,0,49,0,8,0,177,0,8,0,113,0,8,0,241,0,8,0,9,0,8,0,137,0,8,0,73,0,8,0,201,0,8,0,41,0,8,0,169,0,8,0,105,0,8,0,233,0,8,0,25,0,8,0,153,0,8,0,89,0,8,0,217,0,8,0,57,0,8,0,185,0,8,0,121,0,8,0,249,0,8,0,5,0,8,0,133,0,8,0,69,0,8,0,197,0,8,0,37,0,8,0,165,0,8,0,101,0,8,0,229,0,8,0,21,0,8,0,149,0,8,0,85,0,8,0,213,0,8,0,53,0,8,0,181,0,8,0,117,0,8,0,245,0,8,0,13,0,8,0,141,0,8,0,77,0,8,0,205,0,8,0,45,0,8,0,173,0,8,0,109,0,8,0,237,0,8,0,29,0,8,0,157,0,8,0,93,0,8,0,221,0,8,0,61,0,8,0,189,0,8,0,125,0,8,0,253,0,8,0,19,0,9,0,19,1,9,0,147,0,9,0,147,1,9,0,83,0,9,0,83,1,9,0,211,0,9,0,211,1,9,0,51,0,9,0,51,1,9,0,179,0,9,0,179,1,9,0,115,0,9,0,115,1,9,0,243,0,9,0,243,1,9,0,11,0,9,0,11,1,9,0,139,0,9,0,139,1,9,0,75,0,9,0,75,1,9,0,203,0,9,0,203,1,9,0,43,0,9,0,43,1,9,0,171,0,9,0,171,1,9,0,107,0,9,0,107,1,9,0,235,0,9,0,235,1,9,0,27,0,9,0,27,1,9,0,155,0,9,0,155,1,9,0,91,0,9,0,91,1,9,0,219,0,9,0,219,1,9,0,59,0,9,0,59,1,9,0,187,0,9,0,187,1,9,0,123,0,9,0,123,1,9,0,251,0,9,0,251,1,9,0,7,0,9,0,7,1,9,0,135,0,9,0,135,1,9,0,71,0,9,0,71,1,9,0,199,0,9,0,199,1,9,0,39,0,9,0,39,1,9,0,167,0,9,0,167,1,9,0,103,0,9,0,103,1,9,0,231,0,9,0,231,1,9,0,23,0,9,0,23,1,9,0,151,0,9,0,151,1,9,0,87,0,9,0,87,1,9,0,215,0,9,0,215,1,9,0,55,0,9,0,55,1,9,0,183,0,9,0,183,1,9,0,119,0,9,0,119,1,9,0,247,0,9,0,247,1,9,0,15,0,9,0,15,1,9,0,143,0,9,0,143,1,9,0,79,0,9,0,79,1,9,0,207,0,9,0,207,1,9,0,47,0,9,0,47,1,9,0,175,0,9,0,175,1,9,0,111,0,9,0,111,1,9,0,239,0,9,0,239,1,9,0,31,0,9,0,31,1,9,0,159,0,9,0,159,1,9,0,95,0,9,0,95,1,9,0,223,0,9,0,223,1,9,0,63,0,9,0,63,1,9,0,191,0,9,0,191,1,9,0,127,0,9,0,127,1,9,0,255,0,9,0,255,1,9,0,0,0,7,0,64,0,7,0,32,0,7,0,96,0,7,0,16,0,7,0,80,0,7,0,48,0,7,0,112,0,7,0,8,0,7,0,72,0,7,0,40,0,7,0,104,0,7,0,24,0,7,0,88,0,7,0,56,0,7,0,120,0,7,0,4,0,7,0,68,0,7,0,36,0,7,0,100,0,7,0,20,0,7,0,84,0,7,0,52,0,7,0,116,0,7,0,3,0,8,0,131,0,8,0,67,0,8,0,195,0,8,0,35,0,8,0,163,0,8,0,99,0,8,0,227,0,8,0,0,0,5,0,16,0,5,0,8,0,5,0,24,0,5,0,4,0,5,0,20,0,5,0,12,0,5,0,28,0,5,0,2,0,5,0,18,0,5,0,10,0,5,0,26,0,5,0,6,0,5,0,22,0,5,0,14,0,5,0,30,0,5,0,1,0,5,0,17,0,5,0,9,0,5,0,25,0,5,0,5,0,5,0,21,0,5,0,13,0,5,0,29,0,5,0,3,0,5,0,19,0,5,0,11,0,5,0,27,0,5,0,7,0,5,0,23,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,2,0,0,0,2,0,0,0,2,0,0,0,2,0,0,0,3,0,0,0,3,0,0,0,3,0,0,0,3,0,0,0,4,0,0,0,4,0,0,0,4,0,0,0,4,0,0,0,5,0,0,0,5,0,0,0,5,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,5,0,0,0,6,0,0,0,7,0,0,0,8,0,0,0,10,0,0,0,12,0,0,0,14,0,0,0,16,0,0,0,20,0,0,0,24,0,0,0,28,0,0,0,32,0,0,0,40,0,0,0,48,0,0,0,56,0,0,0,64,0,0,0,80,0,0,0,96,0,0,0,112,0,0,0,128,0,0,0,160,0,0,0,192,0,0,0,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,2,0,0,0,2,0,0,0,3,0,0,0,3,0,0,0,4,0,0,0,4,0,0,0,5,0,0,0,5,0,0,0,6,0,0,0,6,0,0,0,7,0,0,0,7,0,0,0,8,0,0,0,8,0,0,0,9,0,0,0,9,0,0,0,10,0,0,0,10,0,0,0,11,0,0,0,11,0,0,0,12,0,0,0,12,0,0,0,13,0,0,0,13,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,6,0,0,0,8,0,0,0,12,0,0,0,16,0,0,0,24,0,0,0,32,0,0,0,48,0,0,0,64,0,0,0,96,0,0,0,128,0,0,0,192,0,0,0,0,1,0,0,128,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,6,0,0,0,8,0,0,0,12,0,0,0,16,0,0,0,24,0,0,0,32,0,0,0,48,0,0,0,64,0,0,0,96,0,0,16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,3,0,0,0,7,0,0,0,0,0,0,0,49,46,50,46,53,0,0,0,110,101,101,100,32,100,105,99,116,105,111,110,97,114,121,0,115,116,114,101,97,109,32,101,110,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,102,105,108,101,32,101,114,114,111,114,0,0,0,0,0,0,115,116,114,101,97,109,32,101,114,114,111,114,0,0,0,0,100,97,116,97,32,101,114,114,111,114,0,0,0,0,0,0,105,110,115,117,102,102,105,99,105,101,110,116,32,109,101,109,111,114,121,0,0,0,0,0,98,117,102,102,101,114,32,101,114,114,111,114,0,0,0,0,105,110,99,111,109,112,97,116,105,98,108,101,32,118,101,114,115,105,111,110,0,0,0,0,184,11,0,0,200,11,0,0,216,11,0,0,224,11,0,0,240,11,0,0,0,12,0,0,16,12,0,0,40,12,0,0,56,12,0,0,216,11,0,0,0,0,0,0,150,48,7,119,44,97,14,238,186,81,9,153,25,196,109,7,143,244,106,112,53,165,99,233,163,149,100,158,50,136,219,14,164,184,220,121,30,233,213,224,136,217,210,151,43,76,182,9,189,124,177,126,7,45,184,231,145,29,191,144,100,16,183,29,242,32,176,106,72,113,185,243,222,65,190,132,125,212,218,26,235,228,221,109,81,181,212,244,199,133,211,131,86,152,108,19,192,168,107,100,122,249,98,253,236,201,101,138,79,92,1,20,217,108,6,99,99,61,15,250,245,13,8,141,200,32,110,59,94,16,105,76,228,65,96,213,114,113,103,162,209,228,3,60,71,212,4,75,253,133,13,210,107,181,10,165,250,168,181,53,108,152,178,66,214,201,187,219,64,249,188,172,227,108,216,50,117,92,223,69,207,13,214,220,89,61,209,171,172,48,217,38,58,0,222,81,128,81,215,200,22,97,208,191,181,244,180,33,35,196,179,86,153,149,186,207,15,165,189,184,158,184,2,40,8,136,5,95,178,217,12,198,36,233,11,177,135,124,111,47,17,76,104,88,171,29,97,193,61,45,102,182,144,65,220,118,6,113,219,1,188,32,210,152,42,16,213,239,137,133,177,113,31,181,182,6,165,228,191,159,51,212,184,232,162,201,7,120,52,249,0,15,142,168,9,150,24,152,14,225,187,13,106,127,45,61,109,8,151,108,100,145,1,92,99,230,244,81,107,107,98,97,108,28,216,48,101,133,78,0,98,242,237,149,6,108,123,165,1,27,193,244,8,130,87,196,15,245,198,217,176,101,80,233,183,18,234,184,190,139,124,136,185,252,223,29,221,98,73,45,218,21,243,124,211,140,101,76,212,251,88,97,178,77,206,81,181,58,116,0,188,163,226,48,187,212,65,165,223,74,215,149,216,61,109,196,209,164,251,244,214,211,106,233,105,67,252,217,110,52,70,136,103,173,208,184,96,218,115,45,4,68,229,29,3,51,95,76,10,170,201,124,13,221,60,113,5,80,170,65,2,39,16,16,11,190,134,32,12,201,37,181,104,87,179,133,111,32,9,212,102,185,159,228,97,206,14,249,222,94,152,201,217,41,34,152,208,176,180,168,215,199,23,61,179,89,129,13,180,46,59,92,189,183,173,108,186,192,32,131,184,237,182,179,191,154,12,226,182,3,154,210,177,116,57,71,213,234,175,119,210,157,21,38,219,4,131,22,220,115,18,11,99,227,132,59,100,148,62,106,109,13,168,90,106,122,11,207,14,228,157,255,9,147,39,174,0,10,177,158,7,125,68,147,15,240,210,163,8,135,104,242,1,30,254,194,6,105,93,87,98,247,203,103,101,128,113,54,108,25,231,6,107,110,118,27,212,254,224,43,211,137,90,122,218,16,204,74,221,103,111,223,185,249,249,239,190,142,67,190,183,23,213,142,176,96,232,163,214,214,126,147,209,161,196,194,216,56,82,242,223,79,241,103,187,209,103,87,188,166,221,6,181,63,75,54,178,72,218,43,13,216,76,27,10,175,246,74,3,54,96,122,4,65,195,239,96,223,85,223,103,168,239,142,110,49,121,190,105,70,140,179,97,203,26,131,102,188,160,210,111,37,54,226,104,82,149,119,12,204,3,71,11,187,185,22,2,34,47,38,5,85,190,59,186,197,40,11,189,178,146,90,180,43,4,106,179,92,167,255,215,194,49,207,208,181,139,158,217,44,29,174,222,91,176,194,100,155,38,242,99,236,156,163,106,117,10,147,109,2,169,6,9,156,63,54,14,235,133,103,7,114,19,87,0,5,130,74,191,149,20,122,184,226,174,43,177,123,56,27,182,12,155,142,210,146,13,190,213,229,183,239,220,124,33,223,219,11,212,210,211,134,66,226,212,241,248,179,221,104,110,131,218,31,205,22,190,129,91,38,185,246,225,119,176,111,119,71,183,24,230,90,8,136,112,106,15,255,202,59,6,102,92,11,1,17,255,158,101,143,105,174,98,248,211,255,107,97,69,207,108,22,120,226,10,160,238,210,13,215,84,131,4,78,194,179,3,57,97,38,103,167,247,22,96,208,77,71,105,73,219,119,110,62,74,106,209,174,220,90,214,217,102,11,223,64,240,59,216,55,83,174,188,169,197,158,187,222,127,207,178,71,233,255,181,48,28,242,189,189,138,194,186,202,48,147,179,83,166,163,180,36,5,54,208,186,147,6,215,205,41,87,222,84,191,103,217,35,46,122,102,179,184,74,97,196,2,27,104,93,148,43,111,42,55,190,11,180,161,142,12,195,27,223,5,90,141,239,2,45,0,0,0,0,65,49,27,25,130,98,54,50,195,83,45,43,4,197,108,100,69,244,119,125,134,167,90,86,199,150,65,79,8,138,217,200,73,187,194,209,138,232,239,250,203,217,244,227,12,79,181,172,77,126,174,181,142,45,131,158,207,28,152,135,81,18,194,74,16,35,217,83,211,112,244,120,146,65,239,97,85,215,174,46,20,230,181,55,215,181,152,28,150,132,131,5,89,152,27,130,24,169,0,155,219,250,45,176,154,203,54,169,93,93,119,230,28,108,108,255,223,63,65,212,158,14,90,205,162,36,132,149,227,21,159,140,32,70,178,167,97,119,169,190,166,225,232,241,231,208,243,232,36,131,222,195,101,178,197,218,170,174,93,93,235,159,70,68,40,204,107,111,105,253,112,118,174,107,49,57,239,90,42,32,44,9,7,11,109,56,28,18,243,54,70,223,178,7,93,198,113,84,112,237,48,101,107,244,247,243,42,187,182,194,49,162,117,145,28,137,52,160,7,144,251,188,159,23,186,141,132,14,121,222,169,37,56,239,178,60,255,121,243,115,190,72,232,106,125,27,197,65,60,42,222,88,5,79,121,240,68,126,98,233,135,45,79,194,198,28,84,219,1,138,21,148,64,187,14,141,131,232,35,166,194,217,56,191,13,197,160,56,76,244,187,33,143,167,150,10,206,150,141,19,9,0,204,92,72,49,215,69,139,98,250,110,202,83,225,119,84,93,187,186,21,108,160,163,214,63,141,136,151,14,150,145,80,152,215,222,17,169,204,199,210,250,225,236,147,203,250,245,92,215,98,114,29,230,121,107,222,181,84,64,159,132,79,89,88,18,14,22,25,35,21,15,218,112,56,36,155,65,35,61,167,107,253,101,230,90,230,124,37,9,203,87,100,56,208,78,163,174,145,1,226,159,138,24,33,204,167,51,96,253,188,42,175,225,36,173,238,208,63,180,45,131,18,159,108,178,9,134,171,36,72,201,234,21,83,208,41,70,126,251,104,119,101,226,246,121,63,47,183,72,36,54,116,27,9,29,53,42,18,4,242,188,83,75,179,141,72,82,112,222,101,121,49,239,126,96,254,243,230,231,191,194,253,254,124,145,208,213,61,160,203,204,250,54,138,131,187,7,145,154,120,84,188,177,57,101,167,168,75,152,131,59,10,169,152,34,201,250,181,9,136,203,174,16,79,93,239,95,14,108,244,70,205,63,217,109,140,14,194,116,67,18,90,243,2,35,65,234,193,112,108,193,128,65,119,216,71,215,54,151,6,230,45,142,197,181,0,165,132,132,27,188,26,138,65,113,91,187,90,104,152,232,119,67,217,217,108,90,30,79,45,21,95,126,54,12,156,45,27,39,221,28,0,62,18,0,152,185,83,49,131,160,144,98,174,139,209,83,181,146,22,197,244,221,87,244,239,196,148,167,194,239,213,150,217,246,233,188,7,174,168,141,28,183,107,222,49,156,42,239,42,133,237,121,107,202,172,72,112,211,111,27,93,248,46,42,70,225,225,54,222,102,160,7,197,127,99,84,232,84,34,101,243,77,229,243,178,2,164,194,169,27,103,145,132,48,38,160,159,41,184,174,197,228,249,159,222,253,58,204,243,214,123,253,232,207,188,107,169,128,253,90,178,153,62,9,159,178,127,56,132,171,176,36,28,44,241,21,7,53,50,70,42,30,115,119,49,7,180,225,112,72,245,208,107,81,54,131,70,122,119,178,93,99,78,215,250,203,15,230,225,210,204,181,204,249,141,132,215,224,74,18,150,175,11,35,141,182,200,112,160,157,137,65,187,132,70,93,35,3,7,108,56,26,196,63,21,49,133,14,14,40,66,152,79,103,3,169,84,126,192,250,121,85,129,203,98,76,31,197,56,129,94,244,35,152,157,167,14,179,220,150,21,170,27,0,84,229,90,49,79,252,153,98,98,215,216,83,121,206,23,79,225,73,86,126,250,80,149,45,215,123,212,28,204,98,19,138,141,45,82,187,150,52,145,232,187,31,208,217,160,6,236,243,126,94,173,194,101,71,110,145,72,108,47,160,83,117,232,54,18,58,169,7,9,35,106,84,36,8,43,101,63,17,228,121,167,150,165,72,188,143,102,27,145,164,39,42,138,189,224,188,203,242,161,141,208,235,98,222,253,192,35,239,230,217,189,225,188,20,252,208,167,13,63,131,138,38,126,178,145,63,185,36,208,112,248,21,203,105,59,70,230,66,122,119,253,91,181,107,101,220,244,90,126,197,55,9,83,238,118,56,72,247,177,174,9,184,240,159,18,161,51,204,63,138,114,253,36,147,0,0,0,0,55,106,194,1,110,212,132,3,89,190,70,2,220,168,9,7,235,194,203,6,178,124,141,4,133,22,79,5,184,81,19,14,143,59,209,15,214,133,151,13,225,239,85,12,100,249,26,9,83,147,216,8,10,45,158,10,61,71,92,11,112,163,38,28,71,201,228,29,30,119,162,31,41,29,96,30,172,11,47,27,155,97,237,26,194,223,171,24,245,181,105,25,200,242,53,18,255,152,247,19,166,38,177,17,145,76,115,16,20,90,60,21,35,48,254,20,122,142,184,22,77,228,122,23,224,70,77,56,215,44,143,57,142,146,201,59,185,248,11,58,60,238,68,63,11,132,134,62,82,58,192,60,101,80,2,61,88,23,94,54,111,125,156,55,54,195,218,53,1,169,24,52,132,191,87,49,179,213,149,48,234,107,211,50,221,1,17,51,144,229,107,36,167,143,169,37,254,49,239,39,201,91,45,38,76,77,98,35,123,39,160,34,34,153,230,32,21,243,36,33,40,180,120,42,31,222,186,43,70,96,252,41,113,10,62,40,244,28,113,45,195,118,179,44,154,200,245,46,173,162,55,47,192,141,154,112,247,231,88,113,174,89,30,115,153,51,220,114,28,37,147,119,43,79,81,118,114,241,23,116,69,155,213,117,120,220,137,126,79,182,75,127,22,8,13,125,33,98,207,124,164,116,128,121,147,30,66,120,202,160,4,122,253,202,198,123,176,46,188,108,135,68,126,109,222,250,56,111,233,144,250,110,108,134,181,107,91,236,119,106,2,82,49,104,53,56,243,105,8,127,175,98,63,21,109,99,102,171,43,97,81,193,233,96,212,215,166,101,227,189,100,100,186,3,34,102,141,105,224,103,32,203,215,72,23,161,21,73,78,31,83,75,121,117,145,74,252,99,222,79,203,9,28,78,146,183,90,76,165,221,152,77,152,154,196,70,175,240,6,71,246,78,64,69,193,36,130,68,68,50,205,65,115,88,15,64,42,230,73,66,29,140,139,67,80,104,241,84,103,2,51,85,62,188,117,87,9,214,183,86,140,192,248,83,187,170,58,82,226,20,124,80,213,126,190,81,232,57,226,90,223,83,32,91,134,237,102,89,177,135,164,88,52,145,235,93,3,251,41,92,90,69,111,94,109,47,173,95,128,27,53,225,183,113,247,224,238,207,177,226,217,165,115,227,92,179,60,230,107,217,254,231,50,103,184,229,5,13,122,228,56,74,38,239,15,32,228,238,86,158,162,236,97,244,96,237,228,226,47,232,211,136,237,233,138,54,171,235,189,92,105,234,240,184,19,253,199,210,209,252,158,108,151,254,169,6,85,255,44,16,26,250,27,122,216,251,66,196,158,249,117,174,92,248,72,233,0,243,127,131,194,242,38,61,132,240,17,87,70,241,148,65,9,244,163,43,203,245,250,149,141,247,205,255,79,246,96,93,120,217,87,55,186,216,14,137,252,218,57,227,62,219,188,245,113,222,139,159,179,223,210,33,245,221,229,75,55,220,216,12,107,215,239,102,169,214,182,216,239,212,129,178,45,213,4,164,98,208,51,206,160,209,106,112,230,211,93,26,36,210,16,254,94,197,39,148,156,196,126,42,218,198,73,64,24,199,204,86,87,194,251,60,149,195,162,130,211,193,149,232,17,192,168,175,77,203,159,197,143,202,198,123,201,200,241,17,11,201,116,7,68,204,67,109,134,205,26,211,192,207,45,185,2,206,64,150,175,145,119,252,109,144,46,66,43,146,25,40,233,147,156,62,166,150,171,84,100,151,242,234,34,149,197,128,224,148,248,199,188,159,207,173,126,158,150,19,56,156,161,121,250,157,36,111,181,152,19,5,119,153,74,187,49,155,125,209,243,154,48,53,137,141,7,95,75,140,94,225,13,142,105,139,207,143,236,157,128,138,219,247,66,139,130,73,4,137,181,35,198,136,136,100,154,131,191,14,88,130,230,176,30,128,209,218,220,129,84,204,147,132,99,166,81,133,58,24,23,135,13,114,213,134,160,208,226,169,151,186,32,168,206,4,102,170,249,110,164,171,124,120,235,174,75,18,41,175,18,172,111,173,37,198,173,172,24,129,241,167,47,235,51,166,118,85,117,164,65,63,183,165,196,41,248,160,243,67,58,161,170,253,124,163,157,151,190,162,208,115,196,181,231,25,6,180,190,167,64,182,137,205,130,183,12,219,205,178,59,177,15,179,98,15,73,177,85,101,139,176,104,34,215,187,95,72,21,186,6,246,83,184,49,156,145,185,180,138,222,188,131,224,28,189,218,94,90,191,237,52,152,190,0,0,0,0,101,103,188,184,139,200,9,170,238,175,181,18,87,151,98,143,50,240,222,55,220,95,107,37,185,56,215,157,239,40,180,197,138,79,8,125,100,224,189,111,1,135,1,215,184,191,214,74,221,216,106,242,51,119,223,224,86,16,99,88,159,87,25,80,250,48,165,232,20,159,16,250,113,248,172,66,200,192,123,223,173,167,199,103,67,8,114,117,38,111,206,205,112,127,173,149,21,24,17,45,251,183,164,63,158,208,24,135,39,232,207,26,66,143,115,162,172,32,198,176,201,71,122,8,62,175,50,160,91,200,142,24,181,103,59,10,208,0,135,178,105,56,80,47,12,95,236,151,226,240,89,133,135,151,229,61,209,135,134,101,180,224,58,221,90,79,143,207,63,40,51,119,134,16,228,234,227,119,88,82,13,216,237,64,104,191,81,248,161,248,43,240,196,159,151,72,42,48,34,90,79,87,158,226,246,111,73,127,147,8,245,199,125,167,64,213,24,192,252,109,78,208,159,53,43,183,35,141,197,24,150,159,160,127,42,39,25,71,253,186,124,32,65,2,146,143,244,16,247,232,72,168,61,88,20,155,88,63,168,35,182,144,29,49,211,247,161,137,106,207,118,20,15,168,202,172,225,7,127,190,132,96,195,6,210,112,160,94,183,23,28,230,89,184,169,244,60,223,21,76,133,231,194,209,224,128,126,105,14,47,203,123,107,72,119,195,162,15,13,203,199,104,177,115,41,199,4,97,76,160,184,217,245,152,111,68,144,255,211,252,126,80,102,238,27,55,218,86,77,39,185,14,40,64,5,182,198,239,176,164,163,136,12,28,26,176,219,129,127,215,103,57,145,120,210,43,244,31,110,147,3,247,38,59,102,144,154,131,136,63,47,145,237,88,147,41,84,96,68,180,49,7,248,12,223,168,77,30,186,207,241,166,236,223,146,254,137,184,46,70,103,23,155,84,2,112,39,236,187,72,240,113,222,47,76,201,48,128,249,219,85,231,69,99,156,160,63,107,249,199,131,211,23,104,54,193,114,15,138,121,203,55,93,228,174,80,225,92,64,255,84,78,37,152,232,246,115,136,139,174,22,239,55,22,248,64,130,4,157,39,62,188,36,31,233,33,65,120,85,153,175,215,224,139,202,176,92,51,59,182,89,237,94,209,229,85,176,126,80,71,213,25,236,255,108,33,59,98,9,70,135,218,231,233,50,200,130,142,142,112,212,158,237,40,177,249,81,144,95,86,228,130,58,49,88,58,131,9,143,167,230,110,51,31,8,193,134,13,109,166,58,181,164,225,64,189,193,134,252,5,47,41,73,23,74,78,245,175,243,118,34,50,150,17,158,138,120,190,43,152,29,217,151,32,75,201,244,120,46,174,72,192,192,1,253,210,165,102,65,106,28,94,150,247,121,57,42,79,151,150,159,93,242,241,35,229,5,25,107,77,96,126,215,245,142,209,98,231,235,182,222,95,82,142,9,194,55,233,181,122,217,70,0,104,188,33,188,208,234,49,223,136,143,86,99,48,97,249,214,34,4,158,106,154,189,166,189,7,216,193,1,191,54,110,180,173,83,9,8,21,154,78,114,29,255,41,206,165,17,134,123,183,116,225,199,15,205,217,16,146,168,190,172,42,70,17,25,56,35,118,165,128,117,102,198,216,16,1,122,96,254,174,207,114,155,201,115,202,34,241,164,87,71,150,24,239,169,57,173,253,204,94,17,69,6,238,77,118,99,137,241,206,141,38,68,220,232,65,248,100,81,121,47,249,52,30,147,65,218,177,38,83,191,214,154,235,233,198,249,179,140,161,69,11,98,14,240,25,7,105,76,161,190,81,155,60,219,54,39,132,53,153,146,150,80,254,46,46,153,185,84,38,252,222,232,158,18,113,93,140,119,22,225,52,206,46,54,169,171,73,138,17,69,230,63,3,32,129,131,187,118,145,224,227,19,246,92,91,253,89,233,73,152,62,85,241,33,6,130,108,68,97,62,212,170,206,139,198,207,169,55,126,56,65,127,214,93,38,195,110,179,137,118,124,214,238,202,196,111,214,29,89,10,177,161,225,228,30,20,243,129,121,168,75,215,105,203,19,178,14,119,171,92,161,194,185,57,198,126,1,128,254,169,156,229,153,21,36,11,54,160,54,110,81,28,142,167,22,102,134,194,113,218,62,44,222,111,44,73,185,211,148,240,129,4,9,149,230,184,177,123,73,13,163,30,46,177,27,72,62,210,67,45,89,110,251,195,246,219,233,166,145,103,81,31,169,176,204,122,206,12,116,148,97,185,102,241,6,5,222,0,0,0,0,119,7,48,150,238,14,97,44,153,9,81,186,7,109,196,25,112,106,244,143,233,99,165,53,158,100,149,163,14,219,136,50,121,220,184,164,224,213,233,30,151,210,217,136,9,182,76,43,126,177,124,189,231,184,45,7,144,191,29,145,29,183,16,100,106,176,32,242,243,185,113,72,132,190,65,222,26,218,212,125,109,221,228,235,244,212,181,81,131,211,133,199,19,108,152,86,100,107,168,192,253,98,249,122,138,101,201,236,20,1,92,79,99,6,108,217,250,15,61,99,141,8,13,245,59,110,32,200,76,105,16,94,213,96,65,228,162,103,113,114,60,3,228,209,75,4,212,71,210,13,133,253,165,10,181,107,53,181,168,250,66,178,152,108,219,187,201,214,172,188,249,64,50,216,108,227,69,223,92,117,220,214,13,207,171,209,61,89,38,217,48,172,81,222,0,58,200,215,81,128,191,208,97,22,33,180,244,181,86,179,196,35,207,186,149,153,184,189,165,15,40,2,184,158,95,5,136,8,198,12,217,178,177,11,233,36,47,111,124,135,88,104,76,17,193,97,29,171,182,102,45,61,118,220,65,144,1,219,113,6,152,210,32,188,239,213,16,42,113,177,133,137,6,182,181,31,159,191,228,165,232,184,212,51,120,7,201,162,15,0,249,52,150,9,168,142,225,14,152,24,127,106,13,187,8,109,61,45,145,100,108,151,230,99,92,1,107,107,81,244,28,108,97,98,133,101,48,216,242,98,0,78,108,6,149,237,27,1,165,123,130,8,244,193,245,15,196,87,101,176,217,198,18,183,233,80,139,190,184,234,252,185,136,124,98,221,29,223,21,218,45,73,140,211,124,243,251,212,76,101,77,178,97,88,58,181,81,206,163,188,0,116,212,187,48,226,74,223,165,65,61,216,149,215,164,209,196,109,211,214,244,251,67,105,233,106,52,110,217,252,173,103,136,70,218,96,184,208,68,4,45,115,51,3,29,229,170,10,76,95,221,13,124,201,80,5,113,60,39,2,65,170,190,11,16,16,201,12,32,134,87,104,181,37,32,111,133,179,185,102,212,9,206,97,228,159,94,222,249,14,41,217,201,152,176,208,152,34,199,215,168,180,89,179,61,23,46,180,13,129,183,189,92,59,192,186,108,173,237,184,131,32,154,191,179,182,3,182,226,12,116,177,210,154,234,213,71,57,157,210,119,175,4,219,38,21,115,220,22,131,227,99,11,18,148,100,59,132,13,109,106,62,122,106,90,168,228,14,207,11,147,9,255,157,10,0,174,39,125,7,158,177,240,15,147,68,135,8,163,210,30,1,242,104,105,6,194,254,247,98,87,93,128,101,103,203,25,108,54,113,110,107,6,231,254,212,27,118,137,211,43,224,16,218,122,90,103,221,74,204,249,185,223,111,142,190,239,249,23,183,190,67,96,176,142,213,214,214,163,232,161,209,147,126,56,216,194,196,79,223,242,82,209,187,103,241,166,188,87,103,63,181,6,221,72,178,54,75,216,13,43,218,175,10,27,76,54,3,74,246,65,4,122,96,223,96,239,195,168,103,223,85,49,110,142,239,70,105,190,121,203,97,179,140,188,102,131,26,37,111,210,160,82,104,226,54,204,12,119,149,187,11,71,3,34,2,22,185,85,5,38,47,197,186,59,190,178,189,11,40,43,180,90,146,92,179,106,4,194,215,255,167,181,208,207,49,44,217,158,139,91,222,174,29,155,100,194,176,236,99,242,38,117,106,163,156,2,109,147,10,156,9,6,169,235,14,54,63,114,7,103,133,5,0,87,19,149,191,74,130,226,184,122,20,123,177,43,174,12,182,27,56,146,210,142,155,229,213,190,13,124,220,239,183,11,219,223,33,134,211,210,212,241,212,226,66,104,221,179,248,31,218,131,110,129,190,22,205,246,185,38,91,111,176,119,225,24,183,71,119,136,8,90,230,255,15,106,112,102,6,59,202,17,1,11,92,143,101,158,255,248,98,174,105,97,107,255,211,22,108,207,69,160,10,226,120,215,13,210,238,78,4,131,84,57,3,179,194,167,103,38,97,208,96,22,247,73,105,71,77,62,110,119,219,174,209,106,74,217,214,90,220,64,223,11,102,55,216,59,240,169,188,174,83,222,187,158,197,71,178,207,127,48,181,255,233,189,189,242,28,202,186,194,138,83,179,147,48,36,180,163,166,186,208,54,5,205,215,6,147,84,222,87,41,35,217,103,191,179,102,122,46,196,97,74,184,93,104,27,2,42,111,43,148,180,11,190,55,195,12,142,161,90,5,223,27,45,2,239,141,0,0,0,0,25,27,49,65,50,54,98,130,43,45,83,195,100,108,197,4,125,119,244,69,86,90,167,134,79,65,150,199,200,217,138,8,209,194,187,73,250,239,232,138,227,244,217,203,172,181,79,12,181,174,126,77,158,131,45,142,135,152,28,207,74,194,18,81,83,217,35,16,120,244,112,211,97,239,65,146,46,174,215,85,55,181,230,20,28,152,181,215,5,131,132,150,130,27,152,89,155,0,169,24,176,45,250,219,169,54,203,154,230,119,93,93,255,108,108,28,212,65,63,223,205,90,14,158,149,132,36,162,140,159,21,227,167,178,70,32,190,169,119,97,241,232,225,166,232,243,208,231,195,222,131,36,218,197,178,101,93,93,174,170,68,70,159,235,111,107,204,40,118,112,253,105,57,49,107,174,32,42,90,239,11,7,9,44,18,28,56,109,223,70,54,243,198,93,7,178,237,112,84,113,244,107,101,48,187,42,243,247,162,49,194,182,137,28,145,117,144,7,160,52,23,159,188,251,14,132,141,186,37,169,222,121,60,178,239,56,115,243,121,255,106,232,72,190,65,197,27,125,88,222,42,60,240,121,79,5,233,98,126,68,194,79,45,135,219,84,28,198,148,21,138,1,141,14,187,64,166,35,232,131,191,56,217,194,56,160,197,13,33,187,244,76,10,150,167,143,19,141,150,206,92,204,0,9,69,215,49,72,110,250,98,139,119,225,83,202,186,187,93,84,163,160,108,21,136,141,63,214,145,150,14,151,222,215,152,80,199,204,169,17,236,225,250,210,245,250,203,147,114,98,215,92,107,121,230,29,64,84,181,222,89,79,132,159,22,14,18,88,15,21,35,25,36,56,112,218,61,35,65,155,101,253,107,167,124,230,90,230,87,203,9,37,78,208,56,100,1,145,174,163,24,138,159,226,51,167,204,33,42,188,253,96,173,36,225,175,180,63,208,238,159,18,131,45,134,9,178,108,201,72,36,171,208,83,21,234,251,126,70,41,226,101,119,104,47,63,121,246,54,36,72,183,29,9,27,116,4,18,42,53,75,83,188,242,82,72,141,179,121,101,222,112,96,126,239,49,231,230,243,254,254,253,194,191,213,208,145,124,204,203,160,61,131,138,54,250,154,145,7,187,177,188,84,120,168,167,101,57,59,131,152,75,34,152,169,10,9,181,250,201,16,174,203,136,95,239,93,79,70,244,108,14,109,217,63,205,116,194,14,140,243,90,18,67,234,65,35,2,193,108,112,193,216,119,65,128,151,54,215,71,142,45,230,6,165,0,181,197,188,27,132,132,113,65,138,26,104,90,187,91,67,119,232,152,90,108,217,217,21,45,79,30,12,54,126,95,39,27,45,156,62,0,28,221,185,152,0,18,160,131,49,83,139,174,98,144,146,181,83,209,221,244,197,22,196,239,244,87,239,194,167,148,246,217,150,213,174,7,188,233,183,28,141,168,156,49,222,107,133,42,239,42,202,107,121,237,211,112,72,172,248,93,27,111,225,70,42,46,102,222,54,225,127,197,7,160,84,232,84,99,77,243,101,34,2,178,243,229,27,169,194,164,48,132,145,103,41,159,160,38,228,197,174,184,253,222,159,249,214,243,204,58,207,232,253,123,128,169,107,188,153,178,90,253,178,159,9,62,171,132,56,127,44,28,36,176,53,7,21,241,30,42,70,50,7,49,119,115,72,112,225,180,81,107,208,245,122,70,131,54,99,93,178,119,203,250,215,78,210,225,230,15,249,204,181,204,224,215,132,141,175,150,18,74,182,141,35,11,157,160,112,200,132,187,65,137,3,35,93,70,26,56,108,7,49,21,63,196,40,14,14,133,103,79,152,66,126,84,169,3,85,121,250,192,76,98,203,129,129,56,197,31,152,35,244,94,179,14,167,157,170,21,150,220,229,84,0,27,252,79,49,90,215,98,98,153,206,121,83,216,73,225,79,23,80,250,126,86,123,215,45,149,98,204,28,212,45,141,138,19,52,150,187,82,31,187,232,145,6,160,217,208,94,126,243,236,71,101,194,173,108,72,145,110,117,83,160,47,58,18,54,232,35,9,7,169,8,36,84,106,17,63,101,43,150,167,121,228,143,188,72,165,164,145,27,102,189,138,42,39,242,203,188,224,235,208,141,161,192,253,222,98,217,230,239,35,20,188,225,189,13,167,208,252,38,138,131,63,63,145,178,126,112,208,36,185,105,203,21,248,66,230,70,59,91,253,119,122,220,101,107,181,197,126,90,244,238,83,9,55,247,72,56,118,184,9,174,177,161,18,159,240,138,63,204,51,147,36,253,114,0,0,0,0,1,194,106,55,3,132,212,110,2,70,190,89,7,9,168,220,6,203,194,235,4,141,124,178,5,79,22,133,14,19,81,184,15,209,59,143,13,151,133,214,12,85,239,225,9,26,249,100,8,216,147,83,10,158,45,10,11,92,71,61,28,38,163,112,29,228,201,71,31,162,119,30,30,96,29,41,27,47,11,172,26,237,97,155,24,171,223,194,25,105,181,245,18,53,242,200,19,247,152,255,17,177,38,166,16,115,76,145,21,60,90,20,20,254,48,35,22,184,142,122,23,122,228,77,56,77,70,224,57,143,44,215,59,201,146,142,58,11,248,185,63,68,238,60,62,134,132,11,60,192,58,82,61,2,80,101,54,94,23,88,55,156,125,111,53,218,195,54,52,24,169,1,49,87,191,132,48,149,213,179,50,211,107,234,51,17,1,221,36,107,229,144,37,169,143,167,39,239,49,254,38,45,91,201,35,98,77,76,34,160,39,123,32,230,153,34,33,36,243,21,42,120,180,40,43,186,222,31,41,252,96,70,40,62,10,113,45,113,28,244,44,179,118,195,46,245,200,154,47,55,162,173,112,154,141,192,113,88,231,247,115,30,89,174,114,220,51,153,119,147,37,28,118,81,79,43,116,23,241,114,117,213,155,69,126,137,220,120,127,75,182,79,125,13,8,22,124,207,98,33,121,128,116,164,120,66,30,147,122,4,160,202,123,198,202,253,108,188,46,176,109,126,68,135,111,56,250,222,110,250,144,233,107,181,134,108,106,119,236,91,104,49,82,2,105,243,56,53,98,175,127,8,99,109,21,63,97,43,171,102,96,233,193,81,101,166,215,212,100,100,189,227,102,34,3,186,103,224,105,141,72,215,203,32,73,21,161,23,75,83,31,78,74,145,117,121,79,222,99,252,78,28,9,203,76,90,183,146,77,152,221,165,70,196,154,152,71,6,240,175,69,64,78,246,68,130,36,193,65,205,50,68,64,15,88,115,66,73,230,42,67,139,140,29,84,241,104,80,85,51,2,103,87,117,188,62,86,183,214,9,83,248,192,140,82,58,170,187,80,124,20,226,81,190,126,213,90,226,57,232,91,32,83,223,89,102,237,134,88,164,135,177,93,235,145,52,92,41,251,3,94,111,69,90,95,173,47,109,225,53,27,128,224,247,113,183,226,177,207,238,227,115,165,217,230,60,179,92,231,254,217,107,229,184,103,50,228,122,13,5,239,38,74,56,238,228,32,15,236,162,158,86,237,96,244,97,232,47,226,228,233,237,136,211,235,171,54,138,234,105,92,189,253,19,184,240,252,209,210,199,254,151,108,158,255,85,6,169,250,26,16,44,251,216,122,27,249,158,196,66,248,92,174,117,243,0,233,72,242,194,131,127,240,132,61,38,241,70,87,17,244,9,65,148,245,203,43,163,247,141,149,250,246,79,255,205,217,120,93,96,216,186,55,87,218,252,137,14,219,62,227,57,222,113,245,188,223,179,159,139,221,245,33,210,220,55,75,229,215,107,12,216,214,169,102,239,212,239,216,182,213,45,178,129,208,98,164,4,209,160,206,51,211,230,112,106,210,36,26,93,197,94,254,16,196,156,148,39,198,218,42,126,199,24,64,73,194,87,86,204,195,149,60,251,193,211,130,162,192,17,232,149,203,77,175,168,202,143,197,159,200,201,123,198,201,11,17,241,204,68,7,116,205,134,109,67,207,192,211,26,206,2,185,45,145,175,150,64,144,109,252,119,146,43,66,46,147,233,40,25,150,166,62,156,151,100,84,171,149,34,234,242,148,224,128,197,159,188,199,248,158,126,173,207,156,56,19,150,157,250,121,161,152,181,111,36,153,119,5,19,155,49,187,74,154,243,209,125,141,137,53,48,140,75,95,7,142,13,225,94,143,207,139,105,138,128,157,236,139,66,247,219,137,4,73,130,136,198,35,181,131,154,100,136,130,88,14,191,128,30,176,230,129,220,218,209,132,147,204,84,133,81,166,99,135,23,24,58,134,213,114,13,169,226,208,160,168,32,186,151,170,102,4,206,171,164,110,249], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+/* memory initializer */ allocate([174,235,120,124,175,41,18,75,173,111,172,18,172,173,198,37,167,241,129,24,166,51,235,47,164,117,85,118,165,183,63,65,160,248,41,196,161,58,67,243,163,124,253,170,162,190,151,157,181,196,115,208,180,6,25,231,182,64,167,190,183,130,205,137,178,205,219,12,179,15,177,59,177,73,15,98,176,139,101,85,187,215,34,104,186,21,72,95,184,83,246,6,185,145,156,49,188,222,138,180,189,28,224,131,191,90,94,218,190,152,52,237,0,0,0,0,184,188,103,101,170,9,200,139,18,181,175,238,143,98,151,87,55,222,240,50,37,107,95,220,157,215,56,185,197,180,40,239,125,8,79,138,111,189,224,100,215,1,135,1,74,214,191,184,242,106,216,221,224,223,119,51,88,99,16,86,80,25,87,159,232,165,48,250,250,16,159,20,66,172,248,113,223,123,192,200,103,199,167,173,117,114,8,67,205,206,111,38,149,173,127,112,45,17,24,21,63,164,183,251,135,24,208,158,26,207,232,39,162,115,143,66,176,198,32,172,8,122,71,201,160,50,175,62,24,142,200,91,10,59,103,181,178,135,0,208,47,80,56,105,151,236,95,12,133,89,240,226,61,229,151,135,101,134,135,209,221,58,224,180,207,143,79,90,119,51,40,63,234,228,16,134,82,88,119,227,64,237,216,13,248,81,191,104,240,43,248,161,72,151,159,196,90,34,48,42,226,158,87,79,127,73,111,246,199,245,8,147,213,64,167,125,109,252,192,24,53,159,208,78,141,35,183,43,159,150,24,197,39,42,127,160,186,253,71,25,2,65,32,124,16,244,143,146,168,72,232,247,155,20,88,61,35,168,63,88,49,29,144,182,137,161,247,211,20,118,207,106,172,202,168,15,190,127,7,225,6,195,96,132,94,160,112,210,230,28,23,183,244,169,184,89,76,21,223,60,209,194,231,133,105,126,128,224,123,203,47,14,195,119,72,107,203,13,15,162,115,177,104,199,97,4,199,41,217,184,160,76,68,111,152,245,252,211,255,144,238,102,80,126,86,218,55,27,14,185,39,77,182,5,64,40,164,176,239,198,28,12,136,163,129,219,176,26,57,103,215,127,43,210,120,145,147,110,31,244,59,38,247,3,131,154,144,102,145,47,63,136,41,147,88,237,180,68,96,84,12,248,7,49,30,77,168,223,166,241,207,186,254,146,223,236,70,46,184,137,84,155,23,103,236,39,112,2,113,240,72,187,201,76,47,222,219,249,128,48,99,69,231,85,107,63,160,156,211,131,199,249,193,54,104,23,121,138,15,114,228,93,55,203,92,225,80,174,78,84,255,64,246,232,152,37,174,139,136,115,22,55,239,22,4,130,64,248,188,62,39,157,33,233,31,36,153,85,120,65,139,224,215,175,51,92,176,202,237,89,182,59,85,229,209,94,71,80,126,176,255,236,25,213,98,59,33,108,218,135,70,9,200,50,233,231,112,142,142,130,40,237,158,212,144,81,249,177,130,228,86,95,58,88,49,58,167,143,9,131,31,51,110,230,13,134,193,8,181,58,166,109,189,64,225,164,5,252,134,193,23,73,41,47,175,245,78,74,50,34,118,243,138,158,17,150,152,43,190,120,32,151,217,29,120,244,201,75,192,72,174,46,210,253,1,192,106,65,102,165,247,150,94,28,79,42,57,121,93,159,150,151,229,35,241,242,77,107,25,5,245,215,126,96,231,98,209,142,95,222,182,235,194,9,142,82,122,181,233,55,104,0,70,217,208,188,33,188,136,223,49,234,48,99,86,143,34,214,249,97,154,106,158,4,7,189,166,189,191,1,193,216,173,180,110,54,21,8,9,83,29,114,78,154,165,206,41,255,183,123,134,17,15,199,225,116,146,16,217,205,42,172,190,168,56,25,17,70,128,165,118,35,216,198,102,117,96,122,1,16,114,207,174,254,202,115,201,155,87,164,241,34,239,24,150,71,253,173,57,169,69,17,94,204,118,77,238,6,206,241,137,99,220,68,38,141,100,248,65,232,249,47,121,81,65,147,30,52,83,38,177,218,235,154,214,191,179,249,198,233,11,69,161,140,25,240,14,98,161,76,105,7,60,155,81,190,132,39,54,219,150,146,153,53,46,46,254,80,38,84,185,153,158,232,222,252,140,93,113,18,52,225,22,119,169,54,46,206,17,138,73,171,3,63,230,69,187,131,129,32,227,224,145,118,91,92,246,19,73,233,89,253,241,85,62,152,108,130,6,33,212,62,97,68,198,139,206,170,126,55,169,207,214,127,65,56,110,195,38,93,124,118,137,179,196,202,238,214,89,29,214,111,225,161,177,10,243,20,30,228,75,168,121,129,19,203,105,215,171,119,14,178,185,194,161,92,1,126,198,57,156,169,254,128,36,21,153,229,54,160,54,11,142,28,81,110,134,102,22,167,62,218,113,194,44,111,222,44,148,211,185,73,9,4,129,240,177,184,230,149,163,13,73,123,27,177,46,30,67,210,62,72,251,110,89,45,233,219,246,195,81,103,145,166,204,176,169,31,116,12,206,122,102,185,97,148,222,5,6,241,16,0,17,0,18,0,0,0,8,0,7,0,9,0,6,0,10,0,5,0,11,0,4,0,12,0,3,0,13,0,2,0,14,0,1,0,15,0,0,0,105,110,99,111,114,114,101,99,116,32,104,101,97,100,101,114,32,99,104,101,99,107,0,0,117,110,107,110,111,119,110,32,99,111,109,112,114,101,115,115,105,111,110,32,109,101,116,104,111,100,0,0,0,0,0,0,105,110,118,97,108,105,100,32,119,105,110,100,111,119,32,115,105,122,101,0,0,0,0,0,117,110,107,110,111,119,110,32,104,101,97,100,101,114,32,102,108,97,103,115,32,115,101,116,0,0,0,0,0,0,0,0,104,101,97,100,101,114,32,99,114,99,32,109,105,115,109,97,116,99,104,0,0,0,0,0,105,110,118,97,108,105,100,32,98,108,111,99,107,32,116,121,112,101,0,0,0,0,0,0,105,110,118,97,108,105,100,32,115,116,111,114,101,100,32,98,108,111,99,107,32,108,101,110,103,116,104,115,0,0,0,0,116,111,111,32,109,97,110,121,32,108,101,110,103,116,104,32,111,114,32,100,105,115,116,97,110,99,101,32,115,121,109,98,111,108,115,0,0,0,0,0,105,110,118,97,108,105,100,32,99,111,100,101,32,108,101,110,103,116,104,115,32,115,101,116,0,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,98,105,116,32,108,101,110,103,116,104,32,114,101,112,101,97,116,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,99,111,100,101,32,45,45,32,109,105,115,115,105,110,103,32,101,110,100,45,111,102,45,98,108,111,99,107,0,0,0,0,105,110,118,97,108,105,100,32,108,105,116,101,114,97,108,47,108,101,110,103,116,104,115,32,115,101,116,0,0,0,0,0,105,110,118,97,108,105,100,32,100,105,115,116,97,110,99,101,115,32,115,101,116,0,0,0,105,110,118,97,108,105,100,32,108,105,116,101,114,97,108,47,108,101,110,103,116,104,32,99,111,100,101,0,0,0,0,0,105,110,118,97,108,105,100,32,100,105,115,116,97,110,99,101,32,99,111,100,101,0,0,0,105,110,118,97,108,105,100,32,100,105,115,116,97,110,99,101,32,116,111,111,32,102,97,114,32,98,97,99,107,0,0,0,105,110,99,111,114,114,101,99,116,32,100,97,116,97,32,99,104,101,99,107,0,0,0,0,105,110,99,111,114,114,101,99,116,32,108,101,110,103,116,104,32,99,104,101,99,107,0,0,96,7,0,0,0,8,80,0,0,8,16,0,20,8,115,0,18,7,31,0,0,8,112,0,0,8,48,0,0,9,192,0,16,7,10,0,0,8,96,0,0,8,32,0,0,9,160,0,0,8,0,0,0,8,128,0,0,8,64,0,0,9,224,0,16,7,6,0,0,8,88,0,0,8,24,0,0,9,144,0,19,7,59,0,0,8,120,0,0,8,56,0,0,9,208,0,17,7,17,0,0,8,104,0,0,8,40,0,0,9,176,0,0,8,8,0,0,8,136,0,0,8,72,0,0,9,240,0,16,7,4,0,0,8,84,0,0,8,20,0,21,8,227,0,19,7,43,0,0,8,116,0,0,8,52,0,0,9,200,0,17,7,13,0,0,8,100,0,0,8,36,0,0,9,168,0,0,8,4,0,0,8,132,0,0,8,68,0,0,9,232,0,16,7,8,0,0,8,92,0,0,8,28,0,0,9,152,0,20,7,83,0,0,8,124,0,0,8,60,0,0,9,216,0,18,7,23,0,0,8,108,0,0,8,44,0,0,9,184,0,0,8,12,0,0,8,140,0,0,8,76,0,0,9,248,0,16,7,3,0,0,8,82,0,0,8,18,0,21,8,163,0,19,7,35,0,0,8,114,0,0,8,50,0,0,9,196,0,17,7,11,0,0,8,98,0,0,8,34,0,0,9,164,0,0,8,2,0,0,8,130,0,0,8,66,0,0,9,228,0,16,7,7,0,0,8,90,0,0,8,26,0,0,9,148,0,20,7,67,0,0,8,122,0,0,8,58,0,0,9,212,0,18,7,19,0,0,8,106,0,0,8,42,0,0,9,180,0,0,8,10,0,0,8,138,0,0,8,74,0,0,9,244,0,16,7,5,0,0,8,86,0,0,8,22,0,64,8,0,0,19,7,51,0,0,8,118,0,0,8,54,0,0,9,204,0,17,7,15,0,0,8,102,0,0,8,38,0,0,9,172,0,0,8,6,0,0,8,134,0,0,8,70,0,0,9,236,0,16,7,9,0,0,8,94,0,0,8,30,0,0,9,156,0,20,7,99,0,0,8,126,0,0,8,62,0,0,9,220,0,18,7,27,0,0,8,110,0,0,8,46,0,0,9,188,0,0,8,14,0,0,8,142,0,0,8,78,0,0,9,252,0,96,7,0,0,0,8,81,0,0,8,17,0,21,8,131,0,18,7,31,0,0,8,113,0,0,8,49,0,0,9,194,0,16,7,10,0,0,8,97,0,0,8,33,0,0,9,162,0,0,8,1,0,0,8,129,0,0,8,65,0,0,9,226,0,16,7,6,0,0,8,89,0,0,8,25,0,0,9,146,0,19,7,59,0,0,8,121,0,0,8,57,0,0,9,210,0,17,7,17,0,0,8,105,0,0,8,41,0,0,9,178,0,0,8,9,0,0,8,137,0,0,8,73,0,0,9,242,0,16,7,4,0,0,8,85,0,0,8,21,0,16,8,2,1,19,7,43,0,0,8,117,0,0,8,53,0,0,9,202,0,17,7,13,0,0,8,101,0,0,8,37,0,0,9,170,0,0,8,5,0,0,8,133,0,0,8,69,0,0,9,234,0,16,7,8,0,0,8,93,0,0,8,29,0,0,9,154,0,20,7,83,0,0,8,125,0,0,8,61,0,0,9,218,0,18,7,23,0,0,8,109,0,0,8,45,0,0,9,186,0,0,8,13,0,0,8,141,0,0,8,77,0,0,9,250,0,16,7,3,0,0,8,83,0,0,8,19,0,21,8,195,0,19,7,35,0,0,8,115,0,0,8,51,0,0,9,198,0,17,7,11,0,0,8,99,0,0,8,35,0,0,9,166,0,0,8,3,0,0,8,131,0,0,8,67,0,0,9,230,0,16,7,7,0,0,8,91,0,0,8,27,0,0,9,150,0,20,7,67,0,0,8,123,0,0,8,59,0,0,9,214,0,18,7,19,0,0,8,107,0,0,8,43,0,0,9,182,0,0,8,11,0,0,8,139,0,0,8,75,0,0,9,246,0,16,7,5,0,0,8,87,0,0,8,23,0,64,8,0,0,19,7,51,0,0,8,119,0,0,8,55,0,0,9,206,0,17,7,15,0,0,8,103,0,0,8,39,0,0,9,174,0,0,8,7,0,0,8,135,0,0,8,71,0,0,9,238,0,16,7,9,0,0,8,95,0,0,8,31,0,0,9,158,0,20,7,99,0,0,8,127,0,0,8,63,0,0,9,222,0,18,7,27,0,0,8,111,0,0,8,47,0,0,9,190,0,0,8,15,0,0,8,143,0,0,8,79,0,0,9,254,0,96,7,0,0,0,8,80,0,0,8,16,0,20,8,115,0,18,7,31,0,0,8,112,0,0,8,48,0,0,9,193,0,16,7,10,0,0,8,96,0,0,8,32,0,0,9,161,0,0,8,0,0,0,8,128,0,0,8,64,0,0,9,225,0,16,7,6,0,0,8,88,0,0,8,24,0,0,9,145,0,19,7,59,0,0,8,120,0,0,8,56,0,0,9,209,0,17,7,17,0,0,8,104,0,0,8,40,0,0,9,177,0,0,8,8,0,0,8,136,0,0,8,72,0,0,9,241,0,16,7,4,0,0,8,84,0,0,8,20,0,21,8,227,0,19,7,43,0,0,8,116,0,0,8,52,0,0,9,201,0,17,7,13,0,0,8,100,0,0,8,36,0,0,9,169,0,0,8,4,0,0,8,132,0,0,8,68,0,0,9,233,0,16,7,8,0,0,8,92,0,0,8,28,0,0,9,153,0,20,7,83,0,0,8,124,0,0,8,60,0,0,9,217,0,18,7,23,0,0,8,108,0,0,8,44,0,0,9,185,0,0,8,12,0,0,8,140,0,0,8,76,0,0,9,249,0,16,7,3,0,0,8,82,0,0,8,18,0,21,8,163,0,19,7,35,0,0,8,114,0,0,8,50,0,0,9,197,0,17,7,11,0,0,8,98,0,0,8,34,0,0,9,165,0,0,8,2,0,0,8,130,0,0,8,66,0,0,9,229,0,16,7,7,0,0,8,90,0,0,8,26,0,0,9,149,0,20,7,67,0,0,8,122,0,0,8,58,0,0,9,213,0,18,7,19,0,0,8,106,0,0,8,42,0,0,9,181,0,0,8,10,0,0,8,138,0,0,8,74,0,0,9,245,0,16,7,5,0,0,8,86,0,0,8,22,0,64,8,0,0,19,7,51,0,0,8,118,0,0,8,54,0,0,9,205,0,17,7,15,0,0,8,102,0,0,8,38,0,0,9,173,0,0,8,6,0,0,8,134,0,0,8,70,0,0,9,237,0,16,7,9,0,0,8,94,0,0,8,30,0,0,9,157,0,20,7,99,0,0,8,126,0,0,8,62,0,0,9,221,0,18,7,27,0,0,8,110,0,0,8,46,0,0,9,189,0,0,8,14,0,0,8,142,0,0,8,78,0,0,9,253,0,96,7,0,0,0,8,81,0,0,8,17,0,21,8,131,0,18,7,31,0,0,8,113,0,0,8,49,0,0,9,195,0,16,7,10,0,0,8,97,0,0,8,33,0,0,9,163,0,0,8,1,0,0,8,129,0,0,8,65,0,0,9,227,0,16,7,6,0,0,8,89,0,0,8,25,0,0,9,147,0,19,7,59,0,0,8,121,0,0,8,57,0,0,9,211,0,17,7,17,0,0,8,105,0,0,8,41,0,0,9,179,0,0,8,9,0,0,8,137,0,0,8,73,0,0,9,243,0,16,7,4,0,0,8,85,0,0,8,21,0,16,8,2,1,19,7,43,0,0,8,117,0,0,8,53,0,0,9,203,0,17,7,13,0,0,8,101,0,0,8,37,0,0,9,171,0,0,8,5,0,0,8,133,0,0,8,69,0,0,9,235,0,16,7,8,0,0,8,93,0,0,8,29,0,0,9,155,0,20,7,83,0,0,8,125,0,0,8,61,0,0,9,219,0,18,7,23,0,0,8,109,0,0,8,45,0,0,9,187,0,0,8,13,0,0,8,141,0,0,8,77,0,0,9,251,0,16,7,3,0,0,8,83,0,0,8,19,0,21,8,195,0,19,7,35,0,0,8,115,0,0,8,51,0,0,9,199,0,17,7,11,0,0,8,99,0,0,8,35,0,0,9,167,0,0,8,3,0,0,8,131,0,0,8,67,0,0,9,231,0,16,7,7,0,0,8,91,0,0,8,27,0,0,9,151,0,20,7,67,0,0,8,123,0,0,8,59,0,0,9,215,0,18,7,19,0,0,8,107,0,0,8,43,0,0,9,183,0,0,8,11,0,0,8,139,0,0,8,75,0,0,9,247,0,16,7,5,0,0,8,87,0,0,8,23,0,64,8,0,0,19,7,51,0,0,8,119,0,0,8,55,0,0,9,207,0,17,7,15,0,0,8,103,0,0,8,39,0,0,9,175,0,0,8,7,0,0,8,135,0,0,8,71,0,0,9,239,0,16,7,9,0,0,8,95,0,0,8,31,0,0,9,159,0,20,7,99,0,0,8,127,0,0,8,63,0,0,9,223,0,18,7,27,0,0,8,111,0,0,8,47,0,0,9,191,0,0,8,15,0,0,8,143,0,0,8,79,0,0,9,255,0,16,5,1,0,23,5,1,1,19,5,17,0,27,5,1,16,17,5,5,0,25,5,1,4,21,5,65,0,29,5,1,64,16,5,3,0,24,5,1,2,20,5,33,0,28,5,1,32,18,5,9,0,26,5,1,8,22,5,129,0,64,5,0,0,16,5,2,0,23,5,129,1,19,5,25,0,27,5,1,24,17,5,7,0,25,5,1,6,21,5,97,0,29,5,1,96,16,5,4,0,24,5,1,3,20,5,49,0,28,5,1,48,18,5,13,0,26,5,1,12,22,5,193,0,64,5,0,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,13,0,15,0,17,0,19,0,23,0,27,0,31,0,35,0,43,0,51,0,59,0,67,0,83,0,99,0,115,0,131,0,163,0,195,0,227,0,2,1,0,0,0,0,0,0,16,0,16,0,16,0,16,0,16,0,16,0,16,0,16,0,17,0,17,0,17,0,17,0,18,0,18,0,18,0,18,0,19,0,19,0,19,0,19,0,20,0,20,0,20,0,20,0,21,0,21,0,21,0,21,0,16,0,73,0,195,0,0,0,1,0,2,0,3,0,4,0,5,0,7,0,9,0,13,0,17,0,25,0,33,0,49,0,65,0,97,0,129,0,193,0,1,1,129,1,1,2,1,3,1,4,1,6,1,8,1,12,1,16,1,24,1,32,1,48,1,64,1,96,0,0,0,0,16,0,16,0,16,0,16,0,17,0,17,0,18,0,18,0,19,0,19,0,20,0,20,0,21,0,21,0,22,0,22,0,23,0,23,0,24,0,24,0,25,0,25,0,26,0,26,0,27,0,27,0,28,0,28,0,29,0,29,0,64,0,64,0,105,110,118,97,108,105,100,32,100,105,115,116,97,110,99,101,32,116,111,111,32,102,97,114,32,98,97,99,107,0,0,0,105,110,118,97,108,105,100,32,100,105,115,116,97,110,99,101,32,99,111,100,101,0,0,0,105,110,118,97,108,105,100,32,108,105,116,101,114,97,108,47,108,101,110,103,116,104,32,99,111,100,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE+10240);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+
+  function _fputs(s, stream) {
+      // int fputs(const char *restrict s, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputs.html
+      var fd = _fileno(stream);
+      return _write(fd, s, _strlen(s));
+    }
+
+  function _fputc(c, stream) {
+      // int fputc(int c, FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html
+      var chr = unSign(c & 0xFF);
+      HEAP8[((_fputc.ret)|0)]=chr;
+      var fd = _fileno(stream);
+      var ret = _write(fd, _fputc.ret, 1);
+      if (ret == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return -1;
+      } else {
+        return chr;
+      }
+    }function _puts(s) {
+      // int puts(const char *s);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/puts.html
+      // NOTE: puts() always writes an extra newline.
+      var stdout = HEAP32[((_stdout)>>2)];
+      var ret = _fputs(s, stdout);
+      if (ret < 0) {
+        return ret;
+      } else {
+        var newlineRet = _fputc(10, stdout);
+        return (newlineRet < 0) ? -1 : ret + 1;
+      }
+    }
+
+  function _sysconf(name) {
+      // long sysconf(int name);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
+      switch(name) {
+        case 30: return PAGE_SIZE;
+        case 132:
+        case 133:
+        case 12:
+        case 137:
+        case 138:
+        case 15:
+        case 235:
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 149:
+        case 13:
+        case 10:
+        case 236:
+        case 153:
+        case 9:
+        case 21:
+        case 22:
+        case 159:
+        case 154:
+        case 14:
+        case 77:
+        case 78:
+        case 139:
+        case 80:
+        case 81:
+        case 79:
+        case 82:
+        case 68:
+        case 67:
+        case 164:
+        case 11:
+        case 29:
+        case 47:
+        case 48:
+        case 95:
+        case 52:
+        case 51:
+        case 46:
+          return 200809;
+        case 27:
+        case 246:
+        case 127:
+        case 128:
+        case 23:
+        case 24:
+        case 160:
+        case 161:
+        case 181:
+        case 182:
+        case 242:
+        case 183:
+        case 184:
+        case 243:
+        case 244:
+        case 245:
+        case 165:
+        case 178:
+        case 179:
+        case 49:
+        case 50:
+        case 168:
+        case 169:
+        case 175:
+        case 170:
+        case 171:
+        case 172:
+        case 97:
+        case 76:
+        case 32:
+        case 173:
+        case 35:
+          return -1;
+        case 176:
+        case 177:
+        case 7:
+        case 155:
+        case 8:
+        case 157:
+        case 125:
+        case 126:
+        case 92:
+        case 93:
+        case 129:
+        case 130:
+        case 131:
+        case 94:
+        case 91:
+          return 1;
+        case 74:
+        case 60:
+        case 69:
+        case 70:
+        case 4:
+          return 1024;
+        case 31:
+        case 42:
+        case 72:
+          return 32;
+        case 87:
+        case 26:
+        case 33:
+          return 2147483647;
+        case 34:
+        case 1:
+          return 47839;
+        case 38:
+        case 36:
+          return 99;
+        case 43:
+        case 37:
+          return 2048;
+        case 0: return 2097152;
+        case 3: return 65536;
+        case 28: return 32768;
+        case 44: return 32767;
+        case 75: return 16384;
+        case 39: return 1000;
+        case 89: return 700;
+        case 71: return 256;
+        case 40: return 255;
+        case 2: return 100;
+        case 180: return 64;
+        case 25: return 20;
+        case 5: return 16;
+        case 6: return 6;
+        case 73: return 4;
+        case 84: return 1;
+      }
+      ___setErrNo(ERRNO_CODES.EINVAL);
+      return -1;
+    }
+
+
+  Module["_memset"] = _memset;
+
+  function ___errno_location() {
+      return ___errno_state;
+    }
+
+  function _abort() {
+      Module['abort']();
+    }
+
+  var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+    Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+    Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+    // just add the mouse delta to the current absolut mouse position
+    // FIXME: ideally this should be clamped against the canvas size and zero
+    Browser.mouseX += Browser.mouseMovementX;
+    Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+  function _sbrk(bytes) {
+      // Implement a Linux-like 'memory area' for our 'process'.
+      // Changes the size of the memory area by |bytes|; returns the
+      // address of the previous top ('break') of the memory area
+      // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
+      var self = _sbrk;
+      if (!self.called) {
+        DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
+        self.called = true;
+        assert(Runtime.dynamicAlloc);
+        self.alloc = Runtime.dynamicAlloc;
+        Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
+      }
+      var ret = DYNAMICTOP;
+      if (bytes != 0) self.alloc(bytes);
+      return ret;  // Previous break location.
+    }
+
+  function ___assert_fail(condition, filename, line, func) {
+      ABORT = true;
+      throw 'Assertion failed: ' + Pointer_stringify(condition) + ', at: ' + [filename ? Pointer_stringify(filename) : 'unknown filename', line, func ? Pointer_stringify(func) : 'unknown function'] + ' at ' + stackTrace();
+    }
+
+  function _time(ptr) {
+      var ret = Math.floor(Date.now()/1000);
+      if (ptr) {
+        HEAP32[((ptr)>>2)]=ret;
+      }
+      return ret;
+    }
+
+  function _llvm_bswap_i32(x) {
+      return ((x&0xff)<<24) | (((x>>8)&0xff)<<16) | (((x>>16)&0xff)<<8) | (x>>>24);
+    }
+
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+_fputc.ret = allocate([0], "i8", ALLOC_STATIC);
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function invoke_iiii(index,a1,a2,a3) {
+  try {
+    return Module["dynCall_iiii"](index,a1,a2,a3);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_vii(index,a1,a2) {
+  try {
+    Module["dynCall_vii"](index,a1,a2);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_iii(index,a1,a2) {
+  try {
+    return Module["dynCall_iii"](index,a1,a2);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var invoke_iiii=env.invoke_iiii;
+  var invoke_vii=env.invoke_vii;
+  var invoke_iii=env.invoke_iii;
+  var _send=env._send;
+  var ___setErrNo=env.___setErrNo;
+  var ___assert_fail=env.___assert_fail;
+  var _fflush=env._fflush;
+  var _pwrite=env._pwrite;
+  var __reallyNegative=env.__reallyNegative;
+  var _sbrk=env._sbrk;
+  var ___errno_location=env.___errno_location;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _fileno=env._fileno;
+  var _sysconf=env._sysconf;
+  var _puts=env._puts;
+  var _mkport=env._mkport;
+  var _write=env._write;
+  var _llvm_bswap_i32=env._llvm_bswap_i32;
+  var _fputc=env._fputc;
+  var _abort=env._abort;
+  var _fwrite=env._fwrite;
+  var _time=env._time;
+  var _fprintf=env._fprintf;
+  var __formatString=env.__formatString;
+  var _fputs=env._fputs;
+  var _printf=env._printf;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _inflate(i2, i3) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0, i38 = 0, i39 = 0, i40 = 0, i41 = 0, i42 = 0, i43 = 0, i44 = 0, i45 = 0, i46 = 0, i47 = 0, i48 = 0, i49 = 0, i50 = 0, i51 = 0, i52 = 0, i53 = 0, i54 = 0, i55 = 0, i56 = 0, i57 = 0, i58 = 0, i59 = 0, i60 = 0, i61 = 0, i62 = 0, i63 = 0, i64 = 0, i65 = 0, i66 = 0, i67 = 0, i68 = 0, i69 = 0, i70 = 0, i71 = 0, i72 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i25 = i1;
+ if ((i2 | 0) == 0) {
+  i72 = -2;
+  STACKTOP = i1;
+  return i72 | 0;
+ }
+ i4 = HEAP32[i2 + 28 >> 2] | 0;
+ if ((i4 | 0) == 0) {
+  i72 = -2;
+  STACKTOP = i1;
+  return i72 | 0;
+ }
+ i8 = i2 + 12 | 0;
+ i19 = HEAP32[i8 >> 2] | 0;
+ if ((i19 | 0) == 0) {
+  i72 = -2;
+  STACKTOP = i1;
+  return i72 | 0;
+ }
+ i62 = HEAP32[i2 >> 2] | 0;
+ if ((i62 | 0) == 0 ? (HEAP32[i2 + 4 >> 2] | 0) != 0 : 0) {
+  i72 = -2;
+  STACKTOP = i1;
+  return i72 | 0;
+ }
+ i68 = HEAP32[i4 >> 2] | 0;
+ if ((i68 | 0) == 11) {
+  HEAP32[i4 >> 2] = 12;
+  i68 = 12;
+  i62 = HEAP32[i2 >> 2] | 0;
+  i19 = HEAP32[i8 >> 2] | 0;
+ }
+ i15 = i2 + 16 | 0;
+ i59 = HEAP32[i15 >> 2] | 0;
+ i16 = i2 + 4 | 0;
+ i5 = HEAP32[i16 >> 2] | 0;
+ i17 = i4 + 56 | 0;
+ i6 = i4 + 60 | 0;
+ i12 = i4 + 8 | 0;
+ i10 = i4 + 24 | 0;
+ i39 = i25 + 1 | 0;
+ i11 = i4 + 16 | 0;
+ i38 = i4 + 32 | 0;
+ i35 = i2 + 24 | 0;
+ i40 = i4 + 36 | 0;
+ i41 = i4 + 20 | 0;
+ i9 = i2 + 48 | 0;
+ i42 = i4 + 64 | 0;
+ i46 = i4 + 12 | 0;
+ i47 = (i3 + -5 | 0) >>> 0 < 2;
+ i7 = i4 + 4 | 0;
+ i48 = i4 + 76 | 0;
+ i49 = i4 + 84 | 0;
+ i50 = i4 + 80 | 0;
+ i51 = i4 + 88 | 0;
+ i43 = (i3 | 0) == 6;
+ i57 = i4 + 7108 | 0;
+ i37 = i4 + 72 | 0;
+ i58 = i4 + 7112 | 0;
+ i54 = i4 + 68 | 0;
+ i28 = i4 + 44 | 0;
+ i29 = i4 + 7104 | 0;
+ i30 = i4 + 48 | 0;
+ i31 = i4 + 52 | 0;
+ i18 = i4 + 40 | 0;
+ i13 = i2 + 20 | 0;
+ i14 = i4 + 28 | 0;
+ i32 = i4 + 96 | 0;
+ i33 = i4 + 100 | 0;
+ i34 = i4 + 92 | 0;
+ i36 = i4 + 104 | 0;
+ i52 = i4 + 1328 | 0;
+ i53 = i4 + 108 | 0;
+ i27 = i4 + 112 | 0;
+ i55 = i4 + 752 | 0;
+ i56 = i4 + 624 | 0;
+ i44 = i25 + 2 | 0;
+ i45 = i25 + 3 | 0;
+ i67 = HEAP32[i6 >> 2] | 0;
+ i65 = i5;
+ i64 = HEAP32[i17 >> 2] | 0;
+ i26 = i59;
+ i61 = 0;
+ L17 : while (1) {
+  L19 : do {
+   switch (i68 | 0) {
+   case 16:
+    {
+     if (i67 >>> 0 < 14) {
+      i63 = i67;
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i66 = i62 + 1 | 0;
+       i64 = (HEAPU8[i62] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       if (i63 >>> 0 < 14) {
+        i62 = i66;
+       } else {
+        i62 = i66;
+        break;
+       }
+      }
+     } else {
+      i63 = i67;
+     }
+     i71 = (i64 & 31) + 257 | 0;
+     HEAP32[i32 >> 2] = i71;
+     i72 = (i64 >>> 5 & 31) + 1 | 0;
+     HEAP32[i33 >> 2] = i72;
+     HEAP32[i34 >> 2] = (i64 >>> 10 & 15) + 4;
+     i64 = i64 >>> 14;
+     i63 = i63 + -14 | 0;
+     if (i71 >>> 0 > 286 | i72 >>> 0 > 30) {
+      HEAP32[i35 >> 2] = 11616;
+      HEAP32[i4 >> 2] = 29;
+      i66 = i26;
+      break L19;
+     } else {
+      HEAP32[i36 >> 2] = 0;
+      HEAP32[i4 >> 2] = 17;
+      i66 = 0;
+      i60 = 154;
+      break L19;
+     }
+    }
+   case 2:
+    {
+     if (i67 >>> 0 < 32) {
+      i63 = i67;
+      i60 = 47;
+     } else {
+      i60 = 49;
+     }
+     break;
+    }
+   case 23:
+    {
+     i66 = HEAP32[i37 >> 2] | 0;
+     i63 = i67;
+     i60 = 240;
+     break;
+    }
+   case 18:
+    {
+     i63 = HEAP32[i36 >> 2] | 0;
+     i69 = i65;
+     i60 = 164;
+     break;
+    }
+   case 1:
+    {
+     if (i67 >>> 0 < 16) {
+      i63 = i67;
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i66 = i62 + 1 | 0;
+       i64 = (HEAPU8[i62] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       if (i63 >>> 0 < 16) {
+        i62 = i66;
+       } else {
+        i62 = i66;
+        break;
+       }
+      }
+     } else {
+      i63 = i67;
+     }
+     HEAP32[i11 >> 2] = i64;
+     if ((i64 & 255 | 0) != 8) {
+      HEAP32[i35 >> 2] = 11448;
+      HEAP32[i4 >> 2] = 29;
+      i66 = i26;
+      break L19;
+     }
+     if ((i64 & 57344 | 0) != 0) {
+      HEAP32[i35 >> 2] = 11504;
+      HEAP32[i4 >> 2] = 29;
+      i66 = i26;
+      break L19;
+     }
+     i60 = HEAP32[i38 >> 2] | 0;
+     if ((i60 | 0) == 0) {
+      i60 = i64;
+     } else {
+      HEAP32[i60 >> 2] = i64 >>> 8 & 1;
+      i60 = HEAP32[i11 >> 2] | 0;
+     }
+     if ((i60 & 512 | 0) != 0) {
+      HEAP8[i25] = i64;
+      HEAP8[i39] = i64 >>> 8;
+      HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i25, 2) | 0;
+     }
+     HEAP32[i4 >> 2] = 2;
+     i63 = 0;
+     i64 = 0;
+     i60 = 47;
+     break;
+    }
+   case 8:
+    {
+     i63 = i67;
+     i60 = 109;
+     break;
+    }
+   case 22:
+    {
+     i63 = i67;
+     i60 = 228;
+     break;
+    }
+   case 24:
+    {
+     i63 = i67;
+     i60 = 246;
+     break;
+    }
+   case 19:
+    {
+     i63 = i67;
+     i60 = 201;
+     break;
+    }
+   case 20:
+    {
+     i63 = i67;
+     i60 = 202;
+     break;
+    }
+   case 21:
+    {
+     i66 = HEAP32[i37 >> 2] | 0;
+     i63 = i67;
+     i60 = 221;
+     break;
+    }
+   case 10:
+    {
+     i63 = i67;
+     i60 = 121;
+     break;
+    }
+   case 11:
+    {
+     i63 = i67;
+     i60 = 124;
+     break;
+    }
+   case 12:
+    {
+     i63 = i67;
+     i60 = 125;
+     break;
+    }
+   case 5:
+    {
+     i63 = i67;
+     i60 = 73;
+     break;
+    }
+   case 4:
+    {
+     i63 = i67;
+     i60 = 62;
+     break;
+    }
+   case 0:
+    {
+     i66 = HEAP32[i12 >> 2] | 0;
+     if ((i66 | 0) == 0) {
+      HEAP32[i4 >> 2] = 12;
+      i63 = i67;
+      i66 = i26;
+      break L19;
+     }
+     if (i67 >>> 0 < 16) {
+      i63 = i67;
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i67 = i62 + 1 | 0;
+       i64 = (HEAPU8[i62] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       if (i63 >>> 0 < 16) {
+        i62 = i67;
+       } else {
+        i62 = i67;
+        break;
+       }
+      }
+     } else {
+      i63 = i67;
+     }
+     if ((i66 & 2 | 0) != 0 & (i64 | 0) == 35615) {
+      HEAP32[i10 >> 2] = _crc32(0, 0, 0) | 0;
+      HEAP8[i25] = 31;
+      HEAP8[i39] = -117;
+      HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i25, 2) | 0;
+      HEAP32[i4 >> 2] = 1;
+      i63 = 0;
+      i64 = 0;
+      i66 = i26;
+      break L19;
+     }
+     HEAP32[i11 >> 2] = 0;
+     i67 = HEAP32[i38 >> 2] | 0;
+     if ((i67 | 0) != 0) {
+      HEAP32[i67 + 48 >> 2] = -1;
+      i66 = HEAP32[i12 >> 2] | 0;
+     }
+     if ((i66 & 1 | 0) != 0 ? ((((i64 << 8 & 65280) + (i64 >>> 8) | 0) >>> 0) % 31 | 0 | 0) == 0 : 0) {
+      if ((i64 & 15 | 0) != 8) {
+       HEAP32[i35 >> 2] = 11448;
+       HEAP32[i4 >> 2] = 29;
+       i66 = i26;
+       break L19;
+      }
+      i66 = i64 >>> 4;
+      i63 = i63 + -4 | 0;
+      i68 = (i66 & 15) + 8 | 0;
+      i67 = HEAP32[i40 >> 2] | 0;
+      if ((i67 | 0) != 0) {
+       if (i68 >>> 0 > i67 >>> 0) {
+        HEAP32[i35 >> 2] = 11480;
+        HEAP32[i4 >> 2] = 29;
+        i64 = i66;
+        i66 = i26;
+        break L19;
+       }
+      } else {
+       HEAP32[i40 >> 2] = i68;
+      }
+      HEAP32[i41 >> 2] = 1 << i68;
+      i63 = _adler32(0, 0, 0) | 0;
+      HEAP32[i10 >> 2] = i63;
+      HEAP32[i9 >> 2] = i63;
+      HEAP32[i4 >> 2] = i64 >>> 12 & 2 ^ 11;
+      i63 = 0;
+      i64 = 0;
+      i66 = i26;
+      break L19;
+     }
+     HEAP32[i35 >> 2] = 11424;
+     HEAP32[i4 >> 2] = 29;
+     i66 = i26;
+     break;
+    }
+   case 26:
+    {
+     if ((HEAP32[i12 >> 2] | 0) != 0) {
+      if (i67 >>> 0 < 32) {
+       i63 = i67;
+       while (1) {
+        if ((i65 | 0) == 0) {
+         i65 = 0;
+         break L17;
+        }
+        i65 = i65 + -1 | 0;
+        i66 = i62 + 1 | 0;
+        i64 = (HEAPU8[i62] << i63) + i64 | 0;
+        i63 = i63 + 8 | 0;
+        if (i63 >>> 0 < 32) {
+         i62 = i66;
+        } else {
+         i62 = i66;
+         break;
+        }
+       }
+      } else {
+       i63 = i67;
+      }
+      i66 = i59 - i26 | 0;
+      HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + i66;
+      HEAP32[i14 >> 2] = (HEAP32[i14 >> 2] | 0) + i66;
+      if ((i59 | 0) != (i26 | 0)) {
+       i59 = HEAP32[i10 >> 2] | 0;
+       i67 = i19 + (0 - i66) | 0;
+       if ((HEAP32[i11 >> 2] | 0) == 0) {
+        i59 = _adler32(i59, i67, i66) | 0;
+       } else {
+        i59 = _crc32(i59, i67, i66) | 0;
+       }
+       HEAP32[i10 >> 2] = i59;
+       HEAP32[i9 >> 2] = i59;
+      }
+      if ((HEAP32[i11 >> 2] | 0) == 0) {
+       i59 = _llvm_bswap_i32(i64 | 0) | 0;
+      } else {
+       i59 = i64;
+      }
+      if ((i59 | 0) == (HEAP32[i10 >> 2] | 0)) {
+       i63 = 0;
+       i64 = 0;
+       i59 = i26;
+      } else {
+       HEAP32[i35 >> 2] = 11904;
+       HEAP32[i4 >> 2] = 29;
+       i66 = i26;
+       i59 = i26;
+       break L19;
+      }
+     } else {
+      i63 = i67;
+     }
+     HEAP32[i4 >> 2] = 27;
+     i60 = 277;
+     break;
+    }
+   case 27:
+    {
+     i63 = i67;
+     i60 = 277;
+     break;
+    }
+   case 28:
+    {
+     i63 = i67;
+     i61 = 1;
+     i60 = 285;
+     break L17;
+    }
+   case 29:
+    {
+     i63 = i67;
+     i61 = -3;
+     break L17;
+    }
+   case 25:
+    {
+     if ((i26 | 0) == 0) {
+      i63 = i67;
+      i26 = 0;
+      i60 = 285;
+      break L17;
+     }
+     HEAP8[i19] = HEAP32[i42 >> 2];
+     HEAP32[i4 >> 2] = 20;
+     i63 = i67;
+     i66 = i26 + -1 | 0;
+     i19 = i19 + 1 | 0;
+     break;
+    }
+   case 17:
+    {
+     i66 = HEAP32[i36 >> 2] | 0;
+     if (i66 >>> 0 < (HEAP32[i34 >> 2] | 0) >>> 0) {
+      i63 = i67;
+      i60 = 154;
+     } else {
+      i60 = 158;
+     }
+     break;
+    }
+   case 13:
+    {
+     i63 = i67 & 7;
+     i64 = i64 >>> i63;
+     i63 = i67 - i63 | 0;
+     if (i63 >>> 0 < 32) {
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i66 = i62 + 1 | 0;
+       i64 = (HEAPU8[i62] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       if (i63 >>> 0 < 32) {
+        i62 = i66;
+       } else {
+        i62 = i66;
+        break;
+       }
+      }
+     }
+     i66 = i64 & 65535;
+     if ((i66 | 0) == (i64 >>> 16 ^ 65535 | 0)) {
+      HEAP32[i42 >> 2] = i66;
+      HEAP32[i4 >> 2] = 14;
+      if (i43) {
+       i63 = 0;
+       i64 = 0;
+       i60 = 285;
+       break L17;
+      } else {
+       i63 = 0;
+       i64 = 0;
+       i60 = 143;
+       break L19;
+      }
+     } else {
+      HEAP32[i35 >> 2] = 11584;
+      HEAP32[i4 >> 2] = 29;
+      i66 = i26;
+      break L19;
+     }
+    }
+   case 7:
+    {
+     i63 = i67;
+     i60 = 96;
+     break;
+    }
+   case 14:
+    {
+     i63 = i67;
+     i60 = 143;
+     break;
+    }
+   case 15:
+    {
+     i63 = i67;
+     i60 = 144;
+     break;
+    }
+   case 9:
+    {
+     if (i67 >>> 0 < 32) {
+      i63 = i67;
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i66 = i62 + 1 | 0;
+       i64 = (HEAPU8[i62] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       if (i63 >>> 0 < 32) {
+        i62 = i66;
+       } else {
+        i62 = i66;
+        break;
+       }
+      }
+     }
+     i63 = _llvm_bswap_i32(i64 | 0) | 0;
+     HEAP32[i10 >> 2] = i63;
+     HEAP32[i9 >> 2] = i63;
+     HEAP32[i4 >> 2] = 10;
+     i63 = 0;
+     i64 = 0;
+     i60 = 121;
+     break;
+    }
+   case 30:
+    {
+     i60 = 299;
+     break L17;
+    }
+   case 6:
+    {
+     i63 = i67;
+     i60 = 83;
+     break;
+    }
+   case 3:
+    {
+     if (i67 >>> 0 < 16) {
+      i63 = i67;
+      i66 = i62;
+      i60 = 55;
+     } else {
+      i60 = 57;
+     }
+     break;
+    }
+   default:
+    {
+     i2 = -2;
+     i60 = 300;
+     break L17;
+    }
+   }
+  } while (0);
+  if ((i60 | 0) == 47) {
+   while (1) {
+    i60 = 0;
+    if ((i65 | 0) == 0) {
+     i65 = 0;
+     break L17;
+    }
+    i65 = i65 + -1 | 0;
+    i60 = i62 + 1 | 0;
+    i64 = (HEAPU8[i62] << i63) + i64 | 0;
+    i63 = i63 + 8 | 0;
+    if (i63 >>> 0 < 32) {
+     i62 = i60;
+     i60 = 47;
+    } else {
+     i62 = i60;
+     i60 = 49;
+     break;
+    }
+   }
+  } else if ((i60 | 0) == 121) {
+   if ((HEAP32[i46 >> 2] | 0) == 0) {
+    i60 = 122;
+    break;
+   }
+   i60 = _adler32(0, 0, 0) | 0;
+   HEAP32[i10 >> 2] = i60;
+   HEAP32[i9 >> 2] = i60;
+   HEAP32[i4 >> 2] = 11;
+   i60 = 124;
+  } else if ((i60 | 0) == 143) {
+   HEAP32[i4 >> 2] = 15;
+   i60 = 144;
+  } else if ((i60 | 0) == 154) {
+   while (1) {
+    i60 = 0;
+    if (i63 >>> 0 < 3) {
+     while (1) {
+      if ((i65 | 0) == 0) {
+       i65 = 0;
+       break L17;
+      }
+      i65 = i65 + -1 | 0;
+      i67 = i62 + 1 | 0;
+      i64 = (HEAPU8[i62] << i63) + i64 | 0;
+      i63 = i63 + 8 | 0;
+      if (i63 >>> 0 < 3) {
+       i62 = i67;
+      } else {
+       i62 = i67;
+       break;
+      }
+     }
+    }
+    HEAP32[i36 >> 2] = i66 + 1;
+    HEAP16[i4 + (HEAPU16[11384 + (i66 << 1) >> 1] << 1) + 112 >> 1] = i64 & 7;
+    i64 = i64 >>> 3;
+    i63 = i63 + -3 | 0;
+    i66 = HEAP32[i36 >> 2] | 0;
+    if (i66 >>> 0 < (HEAP32[i34 >> 2] | 0) >>> 0) {
+     i60 = 154;
+    } else {
+     i67 = i63;
+     i60 = 158;
+     break;
+    }
+   }
+  } else if ((i60 | 0) == 277) {
+   i60 = 0;
+   if ((HEAP32[i12 >> 2] | 0) == 0) {
+    i60 = 284;
+    break;
+   }
+   if ((HEAP32[i11 >> 2] | 0) == 0) {
+    i60 = 284;
+    break;
+   }
+   if (i63 >>> 0 < 32) {
+    i66 = i62;
+    while (1) {
+     if ((i65 | 0) == 0) {
+      i65 = 0;
+      i62 = i66;
+      break L17;
+     }
+     i65 = i65 + -1 | 0;
+     i62 = i66 + 1 | 0;
+     i64 = (HEAPU8[i66] << i63) + i64 | 0;
+     i63 = i63 + 8 | 0;
+     if (i63 >>> 0 < 32) {
+      i66 = i62;
+     } else {
+      break;
+     }
+    }
+   }
+   if ((i64 | 0) == (HEAP32[i14 >> 2] | 0)) {
+    i63 = 0;
+    i64 = 0;
+    i60 = 284;
+    break;
+   }
+   HEAP32[i35 >> 2] = 11928;
+   HEAP32[i4 >> 2] = 29;
+   i66 = i26;
+  }
+  do {
+   if ((i60 | 0) == 49) {
+    i60 = HEAP32[i38 >> 2] | 0;
+    if ((i60 | 0) != 0) {
+     HEAP32[i60 + 4 >> 2] = i64;
+    }
+    if ((HEAP32[i11 >> 2] & 512 | 0) != 0) {
+     HEAP8[i25] = i64;
+     HEAP8[i39] = i64 >>> 8;
+     HEAP8[i44] = i64 >>> 16;
+     HEAP8[i45] = i64 >>> 24;
+     HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i25, 4) | 0;
+    }
+    HEAP32[i4 >> 2] = 3;
+    i63 = 0;
+    i64 = 0;
+    i66 = i62;
+    i60 = 55;
+   } else if ((i60 | 0) == 124) {
+    if (i47) {
+     i60 = 285;
+     break L17;
+    } else {
+     i60 = 125;
+    }
+   } else if ((i60 | 0) == 144) {
+    i60 = 0;
+    i66 = HEAP32[i42 >> 2] | 0;
+    if ((i66 | 0) == 0) {
+     HEAP32[i4 >> 2] = 11;
+     i66 = i26;
+     break;
+    }
+    i66 = i66 >>> 0 > i65 >>> 0 ? i65 : i66;
+    i67 = i66 >>> 0 > i26 >>> 0 ? i26 : i66;
+    if ((i67 | 0) == 0) {
+     i60 = 285;
+     break L17;
+    }
+    _memcpy(i19 | 0, i62 | 0, i67 | 0) | 0;
+    HEAP32[i42 >> 2] = (HEAP32[i42 >> 2] | 0) - i67;
+    i65 = i65 - i67 | 0;
+    i66 = i26 - i67 | 0;
+    i62 = i62 + i67 | 0;
+    i19 = i19 + i67 | 0;
+   } else if ((i60 | 0) == 158) {
+    i60 = 0;
+    if (i66 >>> 0 < 19) {
+     while (1) {
+      i61 = i66 + 1 | 0;
+      HEAP16[i4 + (HEAPU16[11384 + (i66 << 1) >> 1] << 1) + 112 >> 1] = 0;
+      if ((i61 | 0) == 19) {
+       break;
+      } else {
+       i66 = i61;
+      }
+     }
+     HEAP32[i36 >> 2] = 19;
+    }
+    HEAP32[i53 >> 2] = i52;
+    HEAP32[i48 >> 2] = i52;
+    HEAP32[i49 >> 2] = 7;
+    i61 = _inflate_table(0, i27, 19, i53, i49, i55) | 0;
+    if ((i61 | 0) == 0) {
+     HEAP32[i36 >> 2] = 0;
+     HEAP32[i4 >> 2] = 18;
+     i63 = 0;
+     i69 = i65;
+     i61 = 0;
+     i60 = 164;
+     break;
+    } else {
+     HEAP32[i35 >> 2] = 11656;
+     HEAP32[i4 >> 2] = 29;
+     i63 = i67;
+     i66 = i26;
+     break;
+    }
+   }
+  } while (0);
+  L163 : do {
+   if ((i60 | 0) == 55) {
+    while (1) {
+     i60 = 0;
+     if ((i65 | 0) == 0) {
+      i65 = 0;
+      i62 = i66;
+      break L17;
+     }
+     i65 = i65 + -1 | 0;
+     i62 = i66 + 1 | 0;
+     i64 = (HEAPU8[i66] << i63) + i64 | 0;
+     i63 = i63 + 8 | 0;
+     if (i63 >>> 0 < 16) {
+      i66 = i62;
+      i60 = 55;
+     } else {
+      i60 = 57;
+      break;
+     }
+    }
+   } else if ((i60 | 0) == 125) {
+    i60 = 0;
+    if ((HEAP32[i7 >> 2] | 0) != 0) {
+     i66 = i63 & 7;
+     HEAP32[i4 >> 2] = 26;
+     i63 = i63 - i66 | 0;
+     i64 = i64 >>> i66;
+     i66 = i26;
+     break;
+    }
+    if (i63 >>> 0 < 3) {
+     while (1) {
+      if ((i65 | 0) == 0) {
+       i65 = 0;
+       break L17;
+      }
+      i65 = i65 + -1 | 0;
+      i66 = i62 + 1 | 0;
+      i64 = (HEAPU8[i62] << i63) + i64 | 0;
+      i63 = i63 + 8 | 0;
+      if (i63 >>> 0 < 3) {
+       i62 = i66;
+      } else {
+       i62 = i66;
+       break;
+      }
+     }
+    }
+    HEAP32[i7 >> 2] = i64 & 1;
+    i66 = i64 >>> 1 & 3;
+    if ((i66 | 0) == 0) {
+     HEAP32[i4 >> 2] = 13;
+    } else if ((i66 | 0) == 1) {
+     HEAP32[i48 >> 2] = 11952;
+     HEAP32[i49 >> 2] = 9;
+     HEAP32[i50 >> 2] = 14e3;
+     HEAP32[i51 >> 2] = 5;
+     HEAP32[i4 >> 2] = 19;
+     if (i43) {
+      i60 = 133;
+      break L17;
+     }
+    } else if ((i66 | 0) == 2) {
+     HEAP32[i4 >> 2] = 16;
+    } else if ((i66 | 0) == 3) {
+     HEAP32[i35 >> 2] = 11560;
+     HEAP32[i4 >> 2] = 29;
+    }
+    i63 = i63 + -3 | 0;
+    i64 = i64 >>> 3;
+    i66 = i26;
+   } else if ((i60 | 0) == 164) {
+    i60 = 0;
+    i65 = HEAP32[i32 >> 2] | 0;
+    i66 = HEAP32[i33 >> 2] | 0;
+    do {
+     if (i63 >>> 0 < (i66 + i65 | 0) >>> 0) {
+      i71 = i67;
+      L181 : while (1) {
+       i70 = (1 << HEAP32[i49 >> 2]) + -1 | 0;
+       i72 = i70 & i64;
+       i68 = HEAP32[i48 >> 2] | 0;
+       i67 = HEAPU8[i68 + (i72 << 2) + 1 | 0] | 0;
+       if (i67 >>> 0 > i71 >>> 0) {
+        i67 = i71;
+        while (1) {
+         if ((i69 | 0) == 0) {
+          i63 = i67;
+          i65 = 0;
+          break L17;
+         }
+         i69 = i69 + -1 | 0;
+         i71 = i62 + 1 | 0;
+         i64 = (HEAPU8[i62] << i67) + i64 | 0;
+         i62 = i67 + 8 | 0;
+         i72 = i70 & i64;
+         i67 = HEAPU8[i68 + (i72 << 2) + 1 | 0] | 0;
+         if (i67 >>> 0 > i62 >>> 0) {
+          i67 = i62;
+          i62 = i71;
+         } else {
+          i70 = i62;
+          i62 = i71;
+          break;
+         }
+        }
+       } else {
+        i70 = i71;
+       }
+       i68 = HEAP16[i68 + (i72 << 2) + 2 >> 1] | 0;
+       L188 : do {
+        if ((i68 & 65535) < 16) {
+         if (i70 >>> 0 < i67 >>> 0) {
+          while (1) {
+           if ((i69 | 0) == 0) {
+            i63 = i70;
+            i65 = 0;
+            break L17;
+           }
+           i69 = i69 + -1 | 0;
+           i65 = i62 + 1 | 0;
+           i64 = (HEAPU8[i62] << i70) + i64 | 0;
+           i70 = i70 + 8 | 0;
+           if (i70 >>> 0 < i67 >>> 0) {
+            i62 = i65;
+           } else {
+            i62 = i65;
+            break;
+           }
+          }
+         }
+         HEAP32[i36 >> 2] = i63 + 1;
+         HEAP16[i4 + (i63 << 1) + 112 >> 1] = i68;
+         i71 = i70 - i67 | 0;
+         i64 = i64 >>> i67;
+        } else {
+         if (i68 << 16 >> 16 == 16) {
+          i68 = i67 + 2 | 0;
+          if (i70 >>> 0 < i68 >>> 0) {
+           i71 = i62;
+           while (1) {
+            if ((i69 | 0) == 0) {
+             i63 = i70;
+             i65 = 0;
+             i62 = i71;
+             break L17;
+            }
+            i69 = i69 + -1 | 0;
+            i62 = i71 + 1 | 0;
+            i64 = (HEAPU8[i71] << i70) + i64 | 0;
+            i70 = i70 + 8 | 0;
+            if (i70 >>> 0 < i68 >>> 0) {
+             i71 = i62;
+            } else {
+             break;
+            }
+           }
+          }
+          i64 = i64 >>> i67;
+          i67 = i70 - i67 | 0;
+          if ((i63 | 0) == 0) {
+           i60 = 181;
+           break L181;
+          }
+          i67 = i67 + -2 | 0;
+          i68 = (i64 & 3) + 3 | 0;
+          i64 = i64 >>> 2;
+          i70 = HEAP16[i4 + (i63 + -1 << 1) + 112 >> 1] | 0;
+         } else if (i68 << 16 >> 16 == 17) {
+          i68 = i67 + 3 | 0;
+          if (i70 >>> 0 < i68 >>> 0) {
+           i71 = i62;
+           while (1) {
+            if ((i69 | 0) == 0) {
+             i63 = i70;
+             i65 = 0;
+             i62 = i71;
+             break L17;
+            }
+            i69 = i69 + -1 | 0;
+            i62 = i71 + 1 | 0;
+            i64 = (HEAPU8[i71] << i70) + i64 | 0;
+            i70 = i70 + 8 | 0;
+            if (i70 >>> 0 < i68 >>> 0) {
+             i71 = i62;
+            } else {
+             break;
+            }
+           }
+          }
+          i64 = i64 >>> i67;
+          i67 = -3 - i67 + i70 | 0;
+          i68 = (i64 & 7) + 3 | 0;
+          i64 = i64 >>> 3;
+          i70 = 0;
+         } else {
+          i68 = i67 + 7 | 0;
+          if (i70 >>> 0 < i68 >>> 0) {
+           i71 = i62;
+           while (1) {
+            if ((i69 | 0) == 0) {
+             i63 = i70;
+             i65 = 0;
+             i62 = i71;
+             break L17;
+            }
+            i69 = i69 + -1 | 0;
+            i62 = i71 + 1 | 0;
+            i64 = (HEAPU8[i71] << i70) + i64 | 0;
+            i70 = i70 + 8 | 0;
+            if (i70 >>> 0 < i68 >>> 0) {
+             i71 = i62;
+            } else {
+             break;
+            }
+           }
+          }
+          i64 = i64 >>> i67;
+          i67 = -7 - i67 + i70 | 0;
+          i68 = (i64 & 127) + 11 | 0;
+          i64 = i64 >>> 7;
+          i70 = 0;
+         }
+         if ((i63 + i68 | 0) >>> 0 > (i66 + i65 | 0) >>> 0) {
+          i60 = 190;
+          break L181;
+         }
+         while (1) {
+          i68 = i68 + -1 | 0;
+          HEAP32[i36 >> 2] = i63 + 1;
+          HEAP16[i4 + (i63 << 1) + 112 >> 1] = i70;
+          if ((i68 | 0) == 0) {
+           i71 = i67;
+           break L188;
+          }
+          i63 = HEAP32[i36 >> 2] | 0;
+         }
+        }
+       } while (0);
+       i63 = HEAP32[i36 >> 2] | 0;
+       i65 = HEAP32[i32 >> 2] | 0;
+       i66 = HEAP32[i33 >> 2] | 0;
+       if (!(i63 >>> 0 < (i66 + i65 | 0) >>> 0)) {
+        i60 = 193;
+        break;
+       }
+      }
+      if ((i60 | 0) == 181) {
+       i60 = 0;
+       HEAP32[i35 >> 2] = 11688;
+       HEAP32[i4 >> 2] = 29;
+       i63 = i67;
+       i65 = i69;
+       i66 = i26;
+       break L163;
+      } else if ((i60 | 0) == 190) {
+       i60 = 0;
+       HEAP32[i35 >> 2] = 11688;
+       HEAP32[i4 >> 2] = 29;
+       i63 = i67;
+       i65 = i69;
+       i66 = i26;
+       break L163;
+      } else if ((i60 | 0) == 193) {
+       i60 = 0;
+       if ((HEAP32[i4 >> 2] | 0) == 29) {
+        i63 = i71;
+        i65 = i69;
+        i66 = i26;
+        break L163;
+       } else {
+        i63 = i71;
+        break;
+       }
+      }
+     } else {
+      i63 = i67;
+     }
+    } while (0);
+    if ((HEAP16[i56 >> 1] | 0) == 0) {
+     HEAP32[i35 >> 2] = 11720;
+     HEAP32[i4 >> 2] = 29;
+     i65 = i69;
+     i66 = i26;
+     break;
+    }
+    HEAP32[i53 >> 2] = i52;
+    HEAP32[i48 >> 2] = i52;
+    HEAP32[i49 >> 2] = 9;
+    i61 = _inflate_table(1, i27, i65, i53, i49, i55) | 0;
+    if ((i61 | 0) != 0) {
+     HEAP32[i35 >> 2] = 11760;
+     HEAP32[i4 >> 2] = 29;
+     i65 = i69;
+     i66 = i26;
+     break;
+    }
+    HEAP32[i50 >> 2] = HEAP32[i53 >> 2];
+    HEAP32[i51 >> 2] = 6;
+    i61 = _inflate_table(2, i4 + (HEAP32[i32 >> 2] << 1) + 112 | 0, HEAP32[i33 >> 2] | 0, i53, i51, i55) | 0;
+    if ((i61 | 0) == 0) {
+     HEAP32[i4 >> 2] = 19;
+     if (i43) {
+      i65 = i69;
+      i61 = 0;
+      i60 = 285;
+      break L17;
+     } else {
+      i65 = i69;
+      i61 = 0;
+      i60 = 201;
+      break;
+     }
+    } else {
+     HEAP32[i35 >> 2] = 11792;
+     HEAP32[i4 >> 2] = 29;
+     i65 = i69;
+     i66 = i26;
+     break;
+    }
+   }
+  } while (0);
+  if ((i60 | 0) == 57) {
+   i60 = HEAP32[i38 >> 2] | 0;
+   if ((i60 | 0) != 0) {
+    HEAP32[i60 + 8 >> 2] = i64 & 255;
+    HEAP32[i60 + 12 >> 2] = i64 >>> 8;
+   }
+   if ((HEAP32[i11 >> 2] & 512 | 0) != 0) {
+    HEAP8[i25] = i64;
+    HEAP8[i39] = i64 >>> 8;
+    HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i25, 2) | 0;
+   }
+   HEAP32[i4 >> 2] = 4;
+   i63 = 0;
+   i64 = 0;
+   i60 = 62;
+  } else if ((i60 | 0) == 201) {
+   HEAP32[i4 >> 2] = 20;
+   i60 = 202;
+  }
+  do {
+   if ((i60 | 0) == 62) {
+    i60 = 0;
+    i66 = HEAP32[i11 >> 2] | 0;
+    if ((i66 & 1024 | 0) == 0) {
+     i60 = HEAP32[i38 >> 2] | 0;
+     if ((i60 | 0) != 0) {
+      HEAP32[i60 + 16 >> 2] = 0;
+     }
+    } else {
+     if (i63 >>> 0 < 16) {
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i67 = i62 + 1 | 0;
+       i64 = (HEAPU8[i62] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       if (i63 >>> 0 < 16) {
+        i62 = i67;
+       } else {
+        i62 = i67;
+        break;
+       }
+      }
+     }
+     HEAP32[i42 >> 2] = i64;
+     i60 = HEAP32[i38 >> 2] | 0;
+     if ((i60 | 0) != 0) {
+      HEAP32[i60 + 20 >> 2] = i64;
+      i66 = HEAP32[i11 >> 2] | 0;
+     }
+     if ((i66 & 512 | 0) == 0) {
+      i63 = 0;
+      i64 = 0;
+     } else {
+      HEAP8[i25] = i64;
+      HEAP8[i39] = i64 >>> 8;
+      HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i25, 2) | 0;
+      i63 = 0;
+      i64 = 0;
+     }
+    }
+    HEAP32[i4 >> 2] = 5;
+    i60 = 73;
+   } else if ((i60 | 0) == 202) {
+    i60 = 0;
+    if (i65 >>> 0 > 5 & i26 >>> 0 > 257) {
+     HEAP32[i8 >> 2] = i19;
+     HEAP32[i15 >> 2] = i26;
+     HEAP32[i2 >> 2] = i62;
+     HEAP32[i16 >> 2] = i65;
+     HEAP32[i17 >> 2] = i64;
+     HEAP32[i6 >> 2] = i63;
+     _inflate_fast(i2, i59);
+     i19 = HEAP32[i8 >> 2] | 0;
+     i66 = HEAP32[i15 >> 2] | 0;
+     i62 = HEAP32[i2 >> 2] | 0;
+     i65 = HEAP32[i16 >> 2] | 0;
+     i64 = HEAP32[i17 >> 2] | 0;
+     i63 = HEAP32[i6 >> 2] | 0;
+     if ((HEAP32[i4 >> 2] | 0) != 11) {
+      break;
+     }
+     HEAP32[i57 >> 2] = -1;
+     break;
+    }
+    HEAP32[i57 >> 2] = 0;
+    i69 = (1 << HEAP32[i49 >> 2]) + -1 | 0;
+    i71 = i69 & i64;
+    i66 = HEAP32[i48 >> 2] | 0;
+    i68 = HEAP8[i66 + (i71 << 2) + 1 | 0] | 0;
+    i67 = i68 & 255;
+    if (i67 >>> 0 > i63 >>> 0) {
+     while (1) {
+      if ((i65 | 0) == 0) {
+       i65 = 0;
+       break L17;
+      }
+      i65 = i65 + -1 | 0;
+      i70 = i62 + 1 | 0;
+      i64 = (HEAPU8[i62] << i63) + i64 | 0;
+      i63 = i63 + 8 | 0;
+      i71 = i69 & i64;
+      i68 = HEAP8[i66 + (i71 << 2) + 1 | 0] | 0;
+      i67 = i68 & 255;
+      if (i67 >>> 0 > i63 >>> 0) {
+       i62 = i70;
+      } else {
+       i62 = i70;
+       break;
+      }
+     }
+    }
+    i69 = HEAP8[i66 + (i71 << 2) | 0] | 0;
+    i70 = HEAP16[i66 + (i71 << 2) + 2 >> 1] | 0;
+    i71 = i69 & 255;
+    if (!(i69 << 24 >> 24 == 0)) {
+     if ((i71 & 240 | 0) == 0) {
+      i69 = i70 & 65535;
+      i70 = (1 << i67 + i71) + -1 | 0;
+      i71 = ((i64 & i70) >>> i67) + i69 | 0;
+      i68 = HEAP8[i66 + (i71 << 2) + 1 | 0] | 0;
+      if (((i68 & 255) + i67 | 0) >>> 0 > i63 >>> 0) {
+       while (1) {
+        if ((i65 | 0) == 0) {
+         i65 = 0;
+         break L17;
+        }
+        i65 = i65 + -1 | 0;
+        i71 = i62 + 1 | 0;
+        i64 = (HEAPU8[i62] << i63) + i64 | 0;
+        i63 = i63 + 8 | 0;
+        i62 = ((i64 & i70) >>> i67) + i69 | 0;
+        i68 = HEAP8[i66 + (i62 << 2) + 1 | 0] | 0;
+        if (((i68 & 255) + i67 | 0) >>> 0 > i63 >>> 0) {
+         i62 = i71;
+        } else {
+         i69 = i62;
+         i62 = i71;
+         break;
+        }
+       }
+      } else {
+       i69 = i71;
+      }
+      i70 = HEAP16[i66 + (i69 << 2) + 2 >> 1] | 0;
+      i69 = HEAP8[i66 + (i69 << 2) | 0] | 0;
+      HEAP32[i57 >> 2] = i67;
+      i66 = i67;
+      i63 = i63 - i67 | 0;
+      i64 = i64 >>> i67;
+     } else {
+      i66 = 0;
+     }
+    } else {
+     i66 = 0;
+     i69 = 0;
+    }
+    i72 = i68 & 255;
+    i64 = i64 >>> i72;
+    i63 = i63 - i72 | 0;
+    HEAP32[i57 >> 2] = i66 + i72;
+    HEAP32[i42 >> 2] = i70 & 65535;
+    i66 = i69 & 255;
+    if (i69 << 24 >> 24 == 0) {
+     HEAP32[i4 >> 2] = 25;
+     i66 = i26;
+     break;
+    }
+    if ((i66 & 32 | 0) != 0) {
+     HEAP32[i57 >> 2] = -1;
+     HEAP32[i4 >> 2] = 11;
+     i66 = i26;
+     break;
+    }
+    if ((i66 & 64 | 0) == 0) {
+     i66 = i66 & 15;
+     HEAP32[i37 >> 2] = i66;
+     HEAP32[i4 >> 2] = 21;
+     i60 = 221;
+     break;
+    } else {
+     HEAP32[i35 >> 2] = 11816;
+     HEAP32[i4 >> 2] = 29;
+     i66 = i26;
+     break;
+    }
+   }
+  } while (0);
+  if ((i60 | 0) == 73) {
+   i68 = HEAP32[i11 >> 2] | 0;
+   if ((i68 & 1024 | 0) != 0) {
+    i67 = HEAP32[i42 >> 2] | 0;
+    i60 = i67 >>> 0 > i65 >>> 0 ? i65 : i67;
+    if ((i60 | 0) != 0) {
+     i66 = HEAP32[i38 >> 2] | 0;
+     if ((i66 | 0) != 0 ? (i20 = HEAP32[i66 + 16 >> 2] | 0, (i20 | 0) != 0) : 0) {
+      i67 = (HEAP32[i66 + 20 >> 2] | 0) - i67 | 0;
+      i66 = HEAP32[i66 + 24 >> 2] | 0;
+      _memcpy(i20 + i67 | 0, i62 | 0, ((i67 + i60 | 0) >>> 0 > i66 >>> 0 ? i66 - i67 | 0 : i60) | 0) | 0;
+      i68 = HEAP32[i11 >> 2] | 0;
+     }
+     if ((i68 & 512 | 0) != 0) {
+      HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i62, i60) | 0;
+     }
+     i67 = (HEAP32[i42 >> 2] | 0) - i60 | 0;
+     HEAP32[i42 >> 2] = i67;
+     i65 = i65 - i60 | 0;
+     i62 = i62 + i60 | 0;
+    }
+    if ((i67 | 0) != 0) {
+     i60 = 285;
+     break;
+    }
+   }
+   HEAP32[i42 >> 2] = 0;
+   HEAP32[i4 >> 2] = 6;
+   i60 = 83;
+  } else if ((i60 | 0) == 221) {
+   i60 = 0;
+   if ((i66 | 0) == 0) {
+    i60 = HEAP32[i42 >> 2] | 0;
+   } else {
+    if (i63 >>> 0 < i66 >>> 0) {
+     while (1) {
+      if ((i65 | 0) == 0) {
+       i65 = 0;
+       break L17;
+      }
+      i65 = i65 + -1 | 0;
+      i67 = i62 + 1 | 0;
+      i64 = (HEAPU8[i62] << i63) + i64 | 0;
+      i63 = i63 + 8 | 0;
+      if (i63 >>> 0 < i66 >>> 0) {
+       i62 = i67;
+      } else {
+       i62 = i67;
+       break;
+      }
+     }
+    }
+    i60 = (HEAP32[i42 >> 2] | 0) + ((1 << i66) + -1 & i64) | 0;
+    HEAP32[i42 >> 2] = i60;
+    HEAP32[i57 >> 2] = (HEAP32[i57 >> 2] | 0) + i66;
+    i63 = i63 - i66 | 0;
+    i64 = i64 >>> i66;
+   }
+   HEAP32[i58 >> 2] = i60;
+   HEAP32[i4 >> 2] = 22;
+   i60 = 228;
+  }
+  do {
+   if ((i60 | 0) == 83) {
+    if ((HEAP32[i11 >> 2] & 2048 | 0) == 0) {
+     i60 = HEAP32[i38 >> 2] | 0;
+     if ((i60 | 0) != 0) {
+      HEAP32[i60 + 28 >> 2] = 0;
+     }
+    } else {
+     if ((i65 | 0) == 0) {
+      i65 = 0;
+      i60 = 285;
+      break L17;
+     } else {
+      i66 = 0;
+     }
+     while (1) {
+      i60 = i66 + 1 | 0;
+      i67 = HEAP8[i62 + i66 | 0] | 0;
+      i66 = HEAP32[i38 >> 2] | 0;
+      if (((i66 | 0) != 0 ? (i23 = HEAP32[i66 + 28 >> 2] | 0, (i23 | 0) != 0) : 0) ? (i21 = HEAP32[i42 >> 2] | 0, i21 >>> 0 < (HEAP32[i66 + 32 >> 2] | 0) >>> 0) : 0) {
+       HEAP32[i42 >> 2] = i21 + 1;
+       HEAP8[i23 + i21 | 0] = i67;
+      }
+      i66 = i67 << 24 >> 24 != 0;
+      if (i66 & i60 >>> 0 < i65 >>> 0) {
+       i66 = i60;
+      } else {
+       break;
+      }
+     }
+     if ((HEAP32[i11 >> 2] & 512 | 0) != 0) {
+      HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i62, i60) | 0;
+     }
+     i65 = i65 - i60 | 0;
+     i62 = i62 + i60 | 0;
+     if (i66) {
+      i60 = 285;
+      break L17;
+     }
+    }
+    HEAP32[i42 >> 2] = 0;
+    HEAP32[i4 >> 2] = 7;
+    i60 = 96;
+   } else if ((i60 | 0) == 228) {
+    i60 = 0;
+    i69 = (1 << HEAP32[i51 >> 2]) + -1 | 0;
+    i71 = i69 & i64;
+    i66 = HEAP32[i50 >> 2] | 0;
+    i68 = HEAP8[i66 + (i71 << 2) + 1 | 0] | 0;
+    i67 = i68 & 255;
+    if (i67 >>> 0 > i63 >>> 0) {
+     while (1) {
+      if ((i65 | 0) == 0) {
+       i65 = 0;
+       break L17;
+      }
+      i65 = i65 + -1 | 0;
+      i70 = i62 + 1 | 0;
+      i64 = (HEAPU8[i62] << i63) + i64 | 0;
+      i63 = i63 + 8 | 0;
+      i71 = i69 & i64;
+      i68 = HEAP8[i66 + (i71 << 2) + 1 | 0] | 0;
+      i67 = i68 & 255;
+      if (i67 >>> 0 > i63 >>> 0) {
+       i62 = i70;
+      } else {
+       i62 = i70;
+       break;
+      }
+     }
+    }
+    i69 = HEAP8[i66 + (i71 << 2) | 0] | 0;
+    i70 = HEAP16[i66 + (i71 << 2) + 2 >> 1] | 0;
+    i71 = i69 & 255;
+    if ((i71 & 240 | 0) == 0) {
+     i69 = i70 & 65535;
+     i70 = (1 << i67 + i71) + -1 | 0;
+     i71 = ((i64 & i70) >>> i67) + i69 | 0;
+     i68 = HEAP8[i66 + (i71 << 2) + 1 | 0] | 0;
+     if (((i68 & 255) + i67 | 0) >>> 0 > i63 >>> 0) {
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i71 = i62 + 1 | 0;
+       i64 = (HEAPU8[i62] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       i62 = ((i64 & i70) >>> i67) + i69 | 0;
+       i68 = HEAP8[i66 + (i62 << 2) + 1 | 0] | 0;
+       if (((i68 & 255) + i67 | 0) >>> 0 > i63 >>> 0) {
+        i62 = i71;
+       } else {
+        i69 = i62;
+        i62 = i71;
+        break;
+       }
+      }
+     } else {
+      i69 = i71;
+     }
+     i70 = HEAP16[i66 + (i69 << 2) + 2 >> 1] | 0;
+     i69 = HEAP8[i66 + (i69 << 2) | 0] | 0;
+     i66 = (HEAP32[i57 >> 2] | 0) + i67 | 0;
+     HEAP32[i57 >> 2] = i66;
+     i63 = i63 - i67 | 0;
+     i64 = i64 >>> i67;
+    } else {
+     i66 = HEAP32[i57 >> 2] | 0;
+    }
+    i72 = i68 & 255;
+    i64 = i64 >>> i72;
+    i63 = i63 - i72 | 0;
+    HEAP32[i57 >> 2] = i66 + i72;
+    i66 = i69 & 255;
+    if ((i66 & 64 | 0) == 0) {
+     HEAP32[i54 >> 2] = i70 & 65535;
+     i66 = i66 & 15;
+     HEAP32[i37 >> 2] = i66;
+     HEAP32[i4 >> 2] = 23;
+     i60 = 240;
+     break;
+    } else {
+     HEAP32[i35 >> 2] = 11848;
+     HEAP32[i4 >> 2] = 29;
+     i66 = i26;
+     break;
+    }
+   }
+  } while (0);
+  if ((i60 | 0) == 96) {
+   if ((HEAP32[i11 >> 2] & 4096 | 0) == 0) {
+    i60 = HEAP32[i38 >> 2] | 0;
+    if ((i60 | 0) != 0) {
+     HEAP32[i60 + 36 >> 2] = 0;
+    }
+   } else {
+    if ((i65 | 0) == 0) {
+     i65 = 0;
+     i60 = 285;
+     break;
+    } else {
+     i66 = 0;
+    }
+    while (1) {
+     i60 = i66 + 1 | 0;
+     i66 = HEAP8[i62 + i66 | 0] | 0;
+     i67 = HEAP32[i38 >> 2] | 0;
+     if (((i67 | 0) != 0 ? (i24 = HEAP32[i67 + 36 >> 2] | 0, (i24 | 0) != 0) : 0) ? (i22 = HEAP32[i42 >> 2] | 0, i22 >>> 0 < (HEAP32[i67 + 40 >> 2] | 0) >>> 0) : 0) {
+      HEAP32[i42 >> 2] = i22 + 1;
+      HEAP8[i24 + i22 | 0] = i66;
+     }
+     i66 = i66 << 24 >> 24 != 0;
+     if (i66 & i60 >>> 0 < i65 >>> 0) {
+      i66 = i60;
+     } else {
+      break;
+     }
+    }
+    if ((HEAP32[i11 >> 2] & 512 | 0) != 0) {
+     HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i62, i60) | 0;
+    }
+    i65 = i65 - i60 | 0;
+    i62 = i62 + i60 | 0;
+    if (i66) {
+     i60 = 285;
+     break;
+    }
+   }
+   HEAP32[i4 >> 2] = 8;
+   i60 = 109;
+  } else if ((i60 | 0) == 240) {
+   i60 = 0;
+   if ((i66 | 0) != 0) {
+    if (i63 >>> 0 < i66 >>> 0) {
+     i67 = i62;
+     while (1) {
+      if ((i65 | 0) == 0) {
+       i65 = 0;
+       i62 = i67;
+       break L17;
+      }
+      i65 = i65 + -1 | 0;
+      i62 = i67 + 1 | 0;
+      i64 = (HEAPU8[i67] << i63) + i64 | 0;
+      i63 = i63 + 8 | 0;
+      if (i63 >>> 0 < i66 >>> 0) {
+       i67 = i62;
+      } else {
+       break;
+      }
+     }
+    }
+    HEAP32[i54 >> 2] = (HEAP32[i54 >> 2] | 0) + ((1 << i66) + -1 & i64);
+    HEAP32[i57 >> 2] = (HEAP32[i57 >> 2] | 0) + i66;
+    i63 = i63 - i66 | 0;
+    i64 = i64 >>> i66;
+   }
+   HEAP32[i4 >> 2] = 24;
+   i60 = 246;
+  }
+  do {
+   if ((i60 | 0) == 109) {
+    i60 = 0;
+    i66 = HEAP32[i11 >> 2] | 0;
+    if ((i66 & 512 | 0) != 0) {
+     if (i63 >>> 0 < 16) {
+      i67 = i62;
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        i62 = i67;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i62 = i67 + 1 | 0;
+       i64 = (HEAPU8[i67] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       if (i63 >>> 0 < 16) {
+        i67 = i62;
+       } else {
+        break;
+       }
+      }
+     }
+     if ((i64 | 0) == (HEAP32[i10 >> 2] & 65535 | 0)) {
+      i63 = 0;
+      i64 = 0;
+     } else {
+      HEAP32[i35 >> 2] = 11536;
+      HEAP32[i4 >> 2] = 29;
+      i66 = i26;
+      break;
+     }
+    }
+    i67 = HEAP32[i38 >> 2] | 0;
+    if ((i67 | 0) != 0) {
+     HEAP32[i67 + 44 >> 2] = i66 >>> 9 & 1;
+     HEAP32[i67 + 48 >> 2] = 1;
+    }
+    i66 = _crc32(0, 0, 0) | 0;
+    HEAP32[i10 >> 2] = i66;
+    HEAP32[i9 >> 2] = i66;
+    HEAP32[i4 >> 2] = 11;
+    i66 = i26;
+   } else if ((i60 | 0) == 246) {
+    i60 = 0;
+    if ((i26 | 0) == 0) {
+     i26 = 0;
+     i60 = 285;
+     break L17;
+    }
+    i67 = i59 - i26 | 0;
+    i66 = HEAP32[i54 >> 2] | 0;
+    if (i66 >>> 0 > i67 >>> 0) {
+     i67 = i66 - i67 | 0;
+     if (i67 >>> 0 > (HEAP32[i28 >> 2] | 0) >>> 0 ? (HEAP32[i29 >> 2] | 0) != 0 : 0) {
+      HEAP32[i35 >> 2] = 11872;
+      HEAP32[i4 >> 2] = 29;
+      i66 = i26;
+      break;
+     }
+     i68 = HEAP32[i30 >> 2] | 0;
+     if (i67 >>> 0 > i68 >>> 0) {
+      i68 = i67 - i68 | 0;
+      i66 = i68;
+      i68 = (HEAP32[i31 >> 2] | 0) + ((HEAP32[i18 >> 2] | 0) - i68) | 0;
+     } else {
+      i66 = i67;
+      i68 = (HEAP32[i31 >> 2] | 0) + (i68 - i67) | 0;
+     }
+     i69 = HEAP32[i42 >> 2] | 0;
+     i67 = i69;
+     i69 = i66 >>> 0 > i69 >>> 0 ? i69 : i66;
+    } else {
+     i69 = HEAP32[i42 >> 2] | 0;
+     i67 = i69;
+     i68 = i19 + (0 - i66) | 0;
+    }
+    i66 = i69 >>> 0 > i26 >>> 0 ? i26 : i69;
+    HEAP32[i42 >> 2] = i67 - i66;
+    i67 = ~i26;
+    i69 = ~i69;
+    i67 = i67 >>> 0 > i69 >>> 0 ? i67 : i69;
+    i69 = i66;
+    i70 = i19;
+    while (1) {
+     HEAP8[i70] = HEAP8[i68] | 0;
+     i69 = i69 + -1 | 0;
+     if ((i69 | 0) == 0) {
+      break;
+     } else {
+      i68 = i68 + 1 | 0;
+      i70 = i70 + 1 | 0;
+     }
+    }
+    i66 = i26 - i66 | 0;
+    i19 = i19 + ~i67 | 0;
+    if ((HEAP32[i42 >> 2] | 0) == 0) {
+     HEAP32[i4 >> 2] = 20;
+    }
+   }
+  } while (0);
+  i68 = HEAP32[i4 >> 2] | 0;
+  i67 = i63;
+  i26 = i66;
+ }
+ if ((i60 | 0) == 122) {
+  HEAP32[i8 >> 2] = i19;
+  HEAP32[i15 >> 2] = i26;
+  HEAP32[i2 >> 2] = i62;
+  HEAP32[i16 >> 2] = i65;
+  HEAP32[i17 >> 2] = i64;
+  HEAP32[i6 >> 2] = i63;
+  i72 = 2;
+  STACKTOP = i1;
+  return i72 | 0;
+ } else if ((i60 | 0) == 133) {
+  i63 = i63 + -3 | 0;
+  i64 = i64 >>> 3;
+ } else if ((i60 | 0) == 284) {
+  HEAP32[i4 >> 2] = 28;
+  i61 = 1;
+ } else if ((i60 | 0) != 285) if ((i60 | 0) == 299) {
+  i72 = -4;
+  STACKTOP = i1;
+  return i72 | 0;
+ } else if ((i60 | 0) == 300) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ HEAP32[i8 >> 2] = i19;
+ HEAP32[i15 >> 2] = i26;
+ HEAP32[i2 >> 2] = i62;
+ HEAP32[i16 >> 2] = i65;
+ HEAP32[i17 >> 2] = i64;
+ HEAP32[i6 >> 2] = i63;
+ if ((HEAP32[i18 >> 2] | 0) == 0) {
+  if ((HEAP32[i4 >> 2] | 0) >>> 0 < 26 ? (i59 | 0) != (HEAP32[i15 >> 2] | 0) : 0) {
+   i60 = 289;
+  }
+ } else {
+  i60 = 289;
+ }
+ if ((i60 | 0) == 289 ? (_updatewindow(i2, i59) | 0) != 0 : 0) {
+  HEAP32[i4 >> 2] = 30;
+  i72 = -4;
+  STACKTOP = i1;
+  return i72 | 0;
+ }
+ i16 = HEAP32[i16 >> 2] | 0;
+ i72 = HEAP32[i15 >> 2] | 0;
+ i15 = i59 - i72 | 0;
+ i71 = i2 + 8 | 0;
+ HEAP32[i71 >> 2] = i5 - i16 + (HEAP32[i71 >> 2] | 0);
+ HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + i15;
+ HEAP32[i14 >> 2] = (HEAP32[i14 >> 2] | 0) + i15;
+ i13 = (i59 | 0) == (i72 | 0);
+ if (!((HEAP32[i12 >> 2] | 0) == 0 | i13)) {
+  i12 = HEAP32[i10 >> 2] | 0;
+  i8 = (HEAP32[i8 >> 2] | 0) + (0 - i15) | 0;
+  if ((HEAP32[i11 >> 2] | 0) == 0) {
+   i8 = _adler32(i12, i8, i15) | 0;
+  } else {
+   i8 = _crc32(i12, i8, i15) | 0;
+  }
+  HEAP32[i10 >> 2] = i8;
+  HEAP32[i9 >> 2] = i8;
+ }
+ i4 = HEAP32[i4 >> 2] | 0;
+ if ((i4 | 0) == 19) {
+  i8 = 256;
+ } else {
+  i8 = (i4 | 0) == 14 ? 256 : 0;
+ }
+ HEAP32[i2 + 44 >> 2] = ((HEAP32[i7 >> 2] | 0) != 0 ? 64 : 0) + (HEAP32[i6 >> 2] | 0) + ((i4 | 0) == 11 ? 128 : 0) + i8;
+ i72 = ((i5 | 0) == (i16 | 0) & i13 | (i3 | 0) == 4) & (i61 | 0) == 0 ? -5 : i61;
+ STACKTOP = i1;
+ return i72 | 0;
+}
+function _malloc(i12) {
+ i12 = i12 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0;
+ i1 = STACKTOP;
+ do {
+  if (i12 >>> 0 < 245) {
+   if (i12 >>> 0 < 11) {
+    i12 = 16;
+   } else {
+    i12 = i12 + 11 & -8;
+   }
+   i20 = i12 >>> 3;
+   i18 = HEAP32[3618] | 0;
+   i21 = i18 >>> i20;
+   if ((i21 & 3 | 0) != 0) {
+    i6 = (i21 & 1 ^ 1) + i20 | 0;
+    i5 = i6 << 1;
+    i3 = 14512 + (i5 << 2) | 0;
+    i5 = 14512 + (i5 + 2 << 2) | 0;
+    i7 = HEAP32[i5 >> 2] | 0;
+    i2 = i7 + 8 | 0;
+    i4 = HEAP32[i2 >> 2] | 0;
+    do {
+     if ((i3 | 0) != (i4 | 0)) {
+      if (i4 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i8 = i4 + 12 | 0;
+      if ((HEAP32[i8 >> 2] | 0) == (i7 | 0)) {
+       HEAP32[i8 >> 2] = i3;
+       HEAP32[i5 >> 2] = i4;
+       break;
+      } else {
+       _abort();
+      }
+     } else {
+      HEAP32[3618] = i18 & ~(1 << i6);
+     }
+    } while (0);
+    i32 = i6 << 3;
+    HEAP32[i7 + 4 >> 2] = i32 | 3;
+    i32 = i7 + (i32 | 4) | 0;
+    HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+    i32 = i2;
+    STACKTOP = i1;
+    return i32 | 0;
+   }
+   if (i12 >>> 0 > (HEAP32[14480 >> 2] | 0) >>> 0) {
+    if ((i21 | 0) != 0) {
+     i7 = 2 << i20;
+     i7 = i21 << i20 & (i7 | 0 - i7);
+     i7 = (i7 & 0 - i7) + -1 | 0;
+     i2 = i7 >>> 12 & 16;
+     i7 = i7 >>> i2;
+     i6 = i7 >>> 5 & 8;
+     i7 = i7 >>> i6;
+     i5 = i7 >>> 2 & 4;
+     i7 = i7 >>> i5;
+     i4 = i7 >>> 1 & 2;
+     i7 = i7 >>> i4;
+     i3 = i7 >>> 1 & 1;
+     i3 = (i6 | i2 | i5 | i4 | i3) + (i7 >>> i3) | 0;
+     i7 = i3 << 1;
+     i4 = 14512 + (i7 << 2) | 0;
+     i7 = 14512 + (i7 + 2 << 2) | 0;
+     i5 = HEAP32[i7 >> 2] | 0;
+     i2 = i5 + 8 | 0;
+     i6 = HEAP32[i2 >> 2] | 0;
+     do {
+      if ((i4 | 0) != (i6 | 0)) {
+       if (i6 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       i8 = i6 + 12 | 0;
+       if ((HEAP32[i8 >> 2] | 0) == (i5 | 0)) {
+        HEAP32[i8 >> 2] = i4;
+        HEAP32[i7 >> 2] = i6;
+        break;
+       } else {
+        _abort();
+       }
+      } else {
+       HEAP32[3618] = i18 & ~(1 << i3);
+      }
+     } while (0);
+     i6 = i3 << 3;
+     i4 = i6 - i12 | 0;
+     HEAP32[i5 + 4 >> 2] = i12 | 3;
+     i3 = i5 + i12 | 0;
+     HEAP32[i5 + (i12 | 4) >> 2] = i4 | 1;
+     HEAP32[i5 + i6 >> 2] = i4;
+     i6 = HEAP32[14480 >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      i5 = HEAP32[14492 >> 2] | 0;
+      i8 = i6 >>> 3;
+      i9 = i8 << 1;
+      i6 = 14512 + (i9 << 2) | 0;
+      i7 = HEAP32[3618] | 0;
+      i8 = 1 << i8;
+      if ((i7 & i8 | 0) != 0) {
+       i7 = 14512 + (i9 + 2 << 2) | 0;
+       i8 = HEAP32[i7 >> 2] | 0;
+       if (i8 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i28 = i7;
+        i27 = i8;
+       }
+      } else {
+       HEAP32[3618] = i7 | i8;
+       i28 = 14512 + (i9 + 2 << 2) | 0;
+       i27 = i6;
+      }
+      HEAP32[i28 >> 2] = i5;
+      HEAP32[i27 + 12 >> 2] = i5;
+      HEAP32[i5 + 8 >> 2] = i27;
+      HEAP32[i5 + 12 >> 2] = i6;
+     }
+     HEAP32[14480 >> 2] = i4;
+     HEAP32[14492 >> 2] = i3;
+     i32 = i2;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i18 = HEAP32[14476 >> 2] | 0;
+    if ((i18 | 0) != 0) {
+     i2 = (i18 & 0 - i18) + -1 | 0;
+     i31 = i2 >>> 12 & 16;
+     i2 = i2 >>> i31;
+     i30 = i2 >>> 5 & 8;
+     i2 = i2 >>> i30;
+     i32 = i2 >>> 2 & 4;
+     i2 = i2 >>> i32;
+     i6 = i2 >>> 1 & 2;
+     i2 = i2 >>> i6;
+     i3 = i2 >>> 1 & 1;
+     i3 = HEAP32[14776 + ((i30 | i31 | i32 | i6 | i3) + (i2 >>> i3) << 2) >> 2] | 0;
+     i2 = (HEAP32[i3 + 4 >> 2] & -8) - i12 | 0;
+     i6 = i3;
+     while (1) {
+      i5 = HEAP32[i6 + 16 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       i5 = HEAP32[i6 + 20 >> 2] | 0;
+       if ((i5 | 0) == 0) {
+        break;
+       }
+      }
+      i6 = (HEAP32[i5 + 4 >> 2] & -8) - i12 | 0;
+      i4 = i6 >>> 0 < i2 >>> 0;
+      i2 = i4 ? i6 : i2;
+      i6 = i5;
+      i3 = i4 ? i5 : i3;
+     }
+     i6 = HEAP32[14488 >> 2] | 0;
+     if (i3 >>> 0 < i6 >>> 0) {
+      _abort();
+     }
+     i4 = i3 + i12 | 0;
+     if (!(i3 >>> 0 < i4 >>> 0)) {
+      _abort();
+     }
+     i5 = HEAP32[i3 + 24 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     do {
+      if ((i7 | 0) == (i3 | 0)) {
+       i8 = i3 + 20 | 0;
+       i7 = HEAP32[i8 >> 2] | 0;
+       if ((i7 | 0) == 0) {
+        i8 = i3 + 16 | 0;
+        i7 = HEAP32[i8 >> 2] | 0;
+        if ((i7 | 0) == 0) {
+         i26 = 0;
+         break;
+        }
+       }
+       while (1) {
+        i10 = i7 + 20 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) != 0) {
+         i7 = i9;
+         i8 = i10;
+         continue;
+        }
+        i10 = i7 + 16 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) == 0) {
+         break;
+        } else {
+         i7 = i9;
+         i8 = i10;
+        }
+       }
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i8 >> 2] = 0;
+        i26 = i7;
+        break;
+       }
+      } else {
+       i8 = HEAP32[i3 + 8 >> 2] | 0;
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       }
+       i6 = i8 + 12 | 0;
+       if ((HEAP32[i6 >> 2] | 0) != (i3 | 0)) {
+        _abort();
+       }
+       i9 = i7 + 8 | 0;
+       if ((HEAP32[i9 >> 2] | 0) == (i3 | 0)) {
+        HEAP32[i6 >> 2] = i7;
+        HEAP32[i9 >> 2] = i8;
+        i26 = i7;
+        break;
+       } else {
+        _abort();
+       }
+      }
+     } while (0);
+     do {
+      if ((i5 | 0) != 0) {
+       i7 = HEAP32[i3 + 28 >> 2] | 0;
+       i6 = 14776 + (i7 << 2) | 0;
+       if ((i3 | 0) == (HEAP32[i6 >> 2] | 0)) {
+        HEAP32[i6 >> 2] = i26;
+        if ((i26 | 0) == 0) {
+         HEAP32[14476 >> 2] = HEAP32[14476 >> 2] & ~(1 << i7);
+         break;
+        }
+       } else {
+        if (i5 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        i6 = i5 + 16 | 0;
+        if ((HEAP32[i6 >> 2] | 0) == (i3 | 0)) {
+         HEAP32[i6 >> 2] = i26;
+        } else {
+         HEAP32[i5 + 20 >> 2] = i26;
+        }
+        if ((i26 | 0) == 0) {
+         break;
+        }
+       }
+       if (i26 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       HEAP32[i26 + 24 >> 2] = i5;
+       i5 = HEAP32[i3 + 16 >> 2] | 0;
+       do {
+        if ((i5 | 0) != 0) {
+         if (i5 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i26 + 16 >> 2] = i5;
+          HEAP32[i5 + 24 >> 2] = i26;
+          break;
+         }
+        }
+       } while (0);
+       i5 = HEAP32[i3 + 20 >> 2] | 0;
+       if ((i5 | 0) != 0) {
+        if (i5 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i26 + 20 >> 2] = i5;
+         HEAP32[i5 + 24 >> 2] = i26;
+         break;
+        }
+       }
+      }
+     } while (0);
+     if (i2 >>> 0 < 16) {
+      i32 = i2 + i12 | 0;
+      HEAP32[i3 + 4 >> 2] = i32 | 3;
+      i32 = i3 + (i32 + 4) | 0;
+      HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+     } else {
+      HEAP32[i3 + 4 >> 2] = i12 | 3;
+      HEAP32[i3 + (i12 | 4) >> 2] = i2 | 1;
+      HEAP32[i3 + (i2 + i12) >> 2] = i2;
+      i6 = HEAP32[14480 >> 2] | 0;
+      if ((i6 | 0) != 0) {
+       i5 = HEAP32[14492 >> 2] | 0;
+       i8 = i6 >>> 3;
+       i9 = i8 << 1;
+       i6 = 14512 + (i9 << 2) | 0;
+       i7 = HEAP32[3618] | 0;
+       i8 = 1 << i8;
+       if ((i7 & i8 | 0) != 0) {
+        i7 = 14512 + (i9 + 2 << 2) | 0;
+        i8 = HEAP32[i7 >> 2] | 0;
+        if (i8 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         i25 = i7;
+         i24 = i8;
+        }
+       } else {
+        HEAP32[3618] = i7 | i8;
+        i25 = 14512 + (i9 + 2 << 2) | 0;
+        i24 = i6;
+       }
+       HEAP32[i25 >> 2] = i5;
+       HEAP32[i24 + 12 >> 2] = i5;
+       HEAP32[i5 + 8 >> 2] = i24;
+       HEAP32[i5 + 12 >> 2] = i6;
+      }
+      HEAP32[14480 >> 2] = i2;
+      HEAP32[14492 >> 2] = i4;
+     }
+     i32 = i3 + 8 | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+   }
+  } else {
+   if (!(i12 >>> 0 > 4294967231)) {
+    i24 = i12 + 11 | 0;
+    i12 = i24 & -8;
+    i26 = HEAP32[14476 >> 2] | 0;
+    if ((i26 | 0) != 0) {
+     i25 = 0 - i12 | 0;
+     i24 = i24 >>> 8;
+     if ((i24 | 0) != 0) {
+      if (i12 >>> 0 > 16777215) {
+       i27 = 31;
+      } else {
+       i31 = (i24 + 1048320 | 0) >>> 16 & 8;
+       i32 = i24 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i27 = (i32 + 245760 | 0) >>> 16 & 2;
+       i27 = 14 - (i30 | i31 | i27) + (i32 << i27 >>> 15) | 0;
+       i27 = i12 >>> (i27 + 7 | 0) & 1 | i27 << 1;
+      }
+     } else {
+      i27 = 0;
+     }
+     i30 = HEAP32[14776 + (i27 << 2) >> 2] | 0;
+     L126 : do {
+      if ((i30 | 0) == 0) {
+       i29 = 0;
+       i24 = 0;
+      } else {
+       if ((i27 | 0) == 31) {
+        i24 = 0;
+       } else {
+        i24 = 25 - (i27 >>> 1) | 0;
+       }
+       i29 = 0;
+       i28 = i12 << i24;
+       i24 = 0;
+       while (1) {
+        i32 = HEAP32[i30 + 4 >> 2] & -8;
+        i31 = i32 - i12 | 0;
+        if (i31 >>> 0 < i25 >>> 0) {
+         if ((i32 | 0) == (i12 | 0)) {
+          i25 = i31;
+          i29 = i30;
+          i24 = i30;
+          break L126;
+         } else {
+          i25 = i31;
+          i24 = i30;
+         }
+        }
+        i31 = HEAP32[i30 + 20 >> 2] | 0;
+        i30 = HEAP32[i30 + (i28 >>> 31 << 2) + 16 >> 2] | 0;
+        i29 = (i31 | 0) == 0 | (i31 | 0) == (i30 | 0) ? i29 : i31;
+        if ((i30 | 0) == 0) {
+         break;
+        } else {
+         i28 = i28 << 1;
+        }
+       }
+      }
+     } while (0);
+     if ((i29 | 0) == 0 & (i24 | 0) == 0) {
+      i32 = 2 << i27;
+      i26 = i26 & (i32 | 0 - i32);
+      if ((i26 | 0) == 0) {
+       break;
+      }
+      i32 = (i26 & 0 - i26) + -1 | 0;
+      i28 = i32 >>> 12 & 16;
+      i32 = i32 >>> i28;
+      i27 = i32 >>> 5 & 8;
+      i32 = i32 >>> i27;
+      i30 = i32 >>> 2 & 4;
+      i32 = i32 >>> i30;
+      i31 = i32 >>> 1 & 2;
+      i32 = i32 >>> i31;
+      i29 = i32 >>> 1 & 1;
+      i29 = HEAP32[14776 + ((i27 | i28 | i30 | i31 | i29) + (i32 >>> i29) << 2) >> 2] | 0;
+     }
+     if ((i29 | 0) != 0) {
+      while (1) {
+       i27 = (HEAP32[i29 + 4 >> 2] & -8) - i12 | 0;
+       i26 = i27 >>> 0 < i25 >>> 0;
+       i25 = i26 ? i27 : i25;
+       i24 = i26 ? i29 : i24;
+       i26 = HEAP32[i29 + 16 >> 2] | 0;
+       if ((i26 | 0) != 0) {
+        i29 = i26;
+        continue;
+       }
+       i29 = HEAP32[i29 + 20 >> 2] | 0;
+       if ((i29 | 0) == 0) {
+        break;
+       }
+      }
+     }
+     if ((i24 | 0) != 0 ? i25 >>> 0 < ((HEAP32[14480 >> 2] | 0) - i12 | 0) >>> 0 : 0) {
+      i4 = HEAP32[14488 >> 2] | 0;
+      if (i24 >>> 0 < i4 >>> 0) {
+       _abort();
+      }
+      i2 = i24 + i12 | 0;
+      if (!(i24 >>> 0 < i2 >>> 0)) {
+       _abort();
+      }
+      i3 = HEAP32[i24 + 24 >> 2] | 0;
+      i6 = HEAP32[i24 + 12 >> 2] | 0;
+      do {
+       if ((i6 | 0) == (i24 | 0)) {
+        i6 = i24 + 20 | 0;
+        i5 = HEAP32[i6 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         i6 = i24 + 16 | 0;
+         i5 = HEAP32[i6 >> 2] | 0;
+         if ((i5 | 0) == 0) {
+          i22 = 0;
+          break;
+         }
+        }
+        while (1) {
+         i8 = i5 + 20 | 0;
+         i7 = HEAP32[i8 >> 2] | 0;
+         if ((i7 | 0) != 0) {
+          i5 = i7;
+          i6 = i8;
+          continue;
+         }
+         i7 = i5 + 16 | 0;
+         i8 = HEAP32[i7 >> 2] | 0;
+         if ((i8 | 0) == 0) {
+          break;
+         } else {
+          i5 = i8;
+          i6 = i7;
+         }
+        }
+        if (i6 >>> 0 < i4 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i6 >> 2] = 0;
+         i22 = i5;
+         break;
+        }
+       } else {
+        i5 = HEAP32[i24 + 8 >> 2] | 0;
+        if (i5 >>> 0 < i4 >>> 0) {
+         _abort();
+        }
+        i7 = i5 + 12 | 0;
+        if ((HEAP32[i7 >> 2] | 0) != (i24 | 0)) {
+         _abort();
+        }
+        i4 = i6 + 8 | 0;
+        if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+         HEAP32[i7 >> 2] = i6;
+         HEAP32[i4 >> 2] = i5;
+         i22 = i6;
+         break;
+        } else {
+         _abort();
+        }
+       }
+      } while (0);
+      do {
+       if ((i3 | 0) != 0) {
+        i4 = HEAP32[i24 + 28 >> 2] | 0;
+        i5 = 14776 + (i4 << 2) | 0;
+        if ((i24 | 0) == (HEAP32[i5 >> 2] | 0)) {
+         HEAP32[i5 >> 2] = i22;
+         if ((i22 | 0) == 0) {
+          HEAP32[14476 >> 2] = HEAP32[14476 >> 2] & ~(1 << i4);
+          break;
+         }
+        } else {
+         if (i3 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+          _abort();
+         }
+         i4 = i3 + 16 | 0;
+         if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+          HEAP32[i4 >> 2] = i22;
+         } else {
+          HEAP32[i3 + 20 >> 2] = i22;
+         }
+         if ((i22 | 0) == 0) {
+          break;
+         }
+        }
+        if (i22 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        HEAP32[i22 + 24 >> 2] = i3;
+        i3 = HEAP32[i24 + 16 >> 2] | 0;
+        do {
+         if ((i3 | 0) != 0) {
+          if (i3 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i22 + 16 >> 2] = i3;
+           HEAP32[i3 + 24 >> 2] = i22;
+           break;
+          }
+         }
+        } while (0);
+        i3 = HEAP32[i24 + 20 >> 2] | 0;
+        if ((i3 | 0) != 0) {
+         if (i3 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i22 + 20 >> 2] = i3;
+          HEAP32[i3 + 24 >> 2] = i22;
+          break;
+         }
+        }
+       }
+      } while (0);
+      L204 : do {
+       if (!(i25 >>> 0 < 16)) {
+        HEAP32[i24 + 4 >> 2] = i12 | 3;
+        HEAP32[i24 + (i12 | 4) >> 2] = i25 | 1;
+        HEAP32[i24 + (i25 + i12) >> 2] = i25;
+        i4 = i25 >>> 3;
+        if (i25 >>> 0 < 256) {
+         i6 = i4 << 1;
+         i3 = 14512 + (i6 << 2) | 0;
+         i5 = HEAP32[3618] | 0;
+         i4 = 1 << i4;
+         if ((i5 & i4 | 0) != 0) {
+          i5 = 14512 + (i6 + 2 << 2) | 0;
+          i4 = HEAP32[i5 >> 2] | 0;
+          if (i4 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           i21 = i5;
+           i20 = i4;
+          }
+         } else {
+          HEAP32[3618] = i5 | i4;
+          i21 = 14512 + (i6 + 2 << 2) | 0;
+          i20 = i3;
+         }
+         HEAP32[i21 >> 2] = i2;
+         HEAP32[i20 + 12 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i20;
+         HEAP32[i24 + (i12 + 12) >> 2] = i3;
+         break;
+        }
+        i3 = i25 >>> 8;
+        if ((i3 | 0) != 0) {
+         if (i25 >>> 0 > 16777215) {
+          i3 = 31;
+         } else {
+          i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+          i32 = i3 << i31;
+          i30 = (i32 + 520192 | 0) >>> 16 & 4;
+          i32 = i32 << i30;
+          i3 = (i32 + 245760 | 0) >>> 16 & 2;
+          i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+          i3 = i25 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+         }
+        } else {
+         i3 = 0;
+        }
+        i6 = 14776 + (i3 << 2) | 0;
+        HEAP32[i24 + (i12 + 28) >> 2] = i3;
+        HEAP32[i24 + (i12 + 20) >> 2] = 0;
+        HEAP32[i24 + (i12 + 16) >> 2] = 0;
+        i4 = HEAP32[14476 >> 2] | 0;
+        i5 = 1 << i3;
+        if ((i4 & i5 | 0) == 0) {
+         HEAP32[14476 >> 2] = i4 | i5;
+         HEAP32[i6 >> 2] = i2;
+         HEAP32[i24 + (i12 + 24) >> 2] = i6;
+         HEAP32[i24 + (i12 + 12) >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i2;
+         break;
+        }
+        i4 = HEAP32[i6 >> 2] | 0;
+        if ((i3 | 0) == 31) {
+         i3 = 0;
+        } else {
+         i3 = 25 - (i3 >>> 1) | 0;
+        }
+        L225 : do {
+         if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i25 | 0)) {
+          i3 = i25 << i3;
+          while (1) {
+           i6 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+           i5 = HEAP32[i6 >> 2] | 0;
+           if ((i5 | 0) == 0) {
+            break;
+           }
+           if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i25 | 0)) {
+            i18 = i5;
+            break L225;
+           } else {
+            i3 = i3 << 1;
+            i4 = i5;
+           }
+          }
+          if (i6 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i6 >> 2] = i2;
+           HEAP32[i24 + (i12 + 24) >> 2] = i4;
+           HEAP32[i24 + (i12 + 12) >> 2] = i2;
+           HEAP32[i24 + (i12 + 8) >> 2] = i2;
+           break L204;
+          }
+         } else {
+          i18 = i4;
+         }
+        } while (0);
+        i4 = i18 + 8 | 0;
+        i3 = HEAP32[i4 >> 2] | 0;
+        i5 = HEAP32[14488 >> 2] | 0;
+        if (i18 >>> 0 < i5 >>> 0) {
+         _abort();
+        }
+        if (i3 >>> 0 < i5 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i3 + 12 >> 2] = i2;
+         HEAP32[i4 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i3;
+         HEAP32[i24 + (i12 + 12) >> 2] = i18;
+         HEAP32[i24 + (i12 + 24) >> 2] = 0;
+         break;
+        }
+       } else {
+        i32 = i25 + i12 | 0;
+        HEAP32[i24 + 4 >> 2] = i32 | 3;
+        i32 = i24 + (i32 + 4) | 0;
+        HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+       }
+      } while (0);
+      i32 = i24 + 8 | 0;
+      STACKTOP = i1;
+      return i32 | 0;
+     }
+    }
+   } else {
+    i12 = -1;
+   }
+  }
+ } while (0);
+ i18 = HEAP32[14480 >> 2] | 0;
+ if (!(i12 >>> 0 > i18 >>> 0)) {
+  i3 = i18 - i12 | 0;
+  i2 = HEAP32[14492 >> 2] | 0;
+  if (i3 >>> 0 > 15) {
+   HEAP32[14492 >> 2] = i2 + i12;
+   HEAP32[14480 >> 2] = i3;
+   HEAP32[i2 + (i12 + 4) >> 2] = i3 | 1;
+   HEAP32[i2 + i18 >> 2] = i3;
+   HEAP32[i2 + 4 >> 2] = i12 | 3;
+  } else {
+   HEAP32[14480 >> 2] = 0;
+   HEAP32[14492 >> 2] = 0;
+   HEAP32[i2 + 4 >> 2] = i18 | 3;
+   i32 = i2 + (i18 + 4) | 0;
+   HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+  }
+  i32 = i2 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i18 = HEAP32[14484 >> 2] | 0;
+ if (i12 >>> 0 < i18 >>> 0) {
+  i31 = i18 - i12 | 0;
+  HEAP32[14484 >> 2] = i31;
+  i32 = HEAP32[14496 >> 2] | 0;
+  HEAP32[14496 >> 2] = i32 + i12;
+  HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+  HEAP32[i32 + 4 >> 2] = i12 | 3;
+  i32 = i32 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ do {
+  if ((HEAP32[3736] | 0) == 0) {
+   i18 = _sysconf(30) | 0;
+   if ((i18 + -1 & i18 | 0) == 0) {
+    HEAP32[14952 >> 2] = i18;
+    HEAP32[14948 >> 2] = i18;
+    HEAP32[14956 >> 2] = -1;
+    HEAP32[14960 >> 2] = -1;
+    HEAP32[14964 >> 2] = 0;
+    HEAP32[14916 >> 2] = 0;
+    HEAP32[3736] = (_time(0) | 0) & -16 ^ 1431655768;
+    break;
+   } else {
+    _abort();
+   }
+  }
+ } while (0);
+ i20 = i12 + 48 | 0;
+ i25 = HEAP32[14952 >> 2] | 0;
+ i21 = i12 + 47 | 0;
+ i22 = i25 + i21 | 0;
+ i25 = 0 - i25 | 0;
+ i18 = i22 & i25;
+ if (!(i18 >>> 0 > i12 >>> 0)) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i24 = HEAP32[14912 >> 2] | 0;
+ if ((i24 | 0) != 0 ? (i31 = HEAP32[14904 >> 2] | 0, i32 = i31 + i18 | 0, i32 >>> 0 <= i31 >>> 0 | i32 >>> 0 > i24 >>> 0) : 0) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ L269 : do {
+  if ((HEAP32[14916 >> 2] & 4 | 0) == 0) {
+   i26 = HEAP32[14496 >> 2] | 0;
+   L271 : do {
+    if ((i26 | 0) != 0) {
+     i24 = 14920 | 0;
+     while (1) {
+      i27 = HEAP32[i24 >> 2] | 0;
+      if (!(i27 >>> 0 > i26 >>> 0) ? (i23 = i24 + 4 | 0, (i27 + (HEAP32[i23 >> 2] | 0) | 0) >>> 0 > i26 >>> 0) : 0) {
+       break;
+      }
+      i24 = HEAP32[i24 + 8 >> 2] | 0;
+      if ((i24 | 0) == 0) {
+       i13 = 182;
+       break L271;
+      }
+     }
+     if ((i24 | 0) != 0) {
+      i25 = i22 - (HEAP32[14484 >> 2] | 0) & i25;
+      if (i25 >>> 0 < 2147483647) {
+       i13 = _sbrk(i25 | 0) | 0;
+       i26 = (i13 | 0) == ((HEAP32[i24 >> 2] | 0) + (HEAP32[i23 >> 2] | 0) | 0);
+       i22 = i13;
+       i24 = i25;
+       i23 = i26 ? i13 : -1;
+       i25 = i26 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i13 = 182;
+     }
+    } else {
+     i13 = 182;
+    }
+   } while (0);
+   do {
+    if ((i13 | 0) == 182) {
+     i23 = _sbrk(0) | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i24 = i23;
+      i22 = HEAP32[14948 >> 2] | 0;
+      i25 = i22 + -1 | 0;
+      if ((i25 & i24 | 0) == 0) {
+       i25 = i18;
+      } else {
+       i25 = i18 - i24 + (i25 + i24 & 0 - i22) | 0;
+      }
+      i24 = HEAP32[14904 >> 2] | 0;
+      i26 = i24 + i25 | 0;
+      if (i25 >>> 0 > i12 >>> 0 & i25 >>> 0 < 2147483647) {
+       i22 = HEAP32[14912 >> 2] | 0;
+       if ((i22 | 0) != 0 ? i26 >>> 0 <= i24 >>> 0 | i26 >>> 0 > i22 >>> 0 : 0) {
+        i25 = 0;
+        break;
+       }
+       i22 = _sbrk(i25 | 0) | 0;
+       i13 = (i22 | 0) == (i23 | 0);
+       i24 = i25;
+       i23 = i13 ? i23 : -1;
+       i25 = i13 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i25 = 0;
+     }
+    }
+   } while (0);
+   L291 : do {
+    if ((i13 | 0) == 191) {
+     i13 = 0 - i24 | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i17 = i23;
+      i14 = i25;
+      i13 = 202;
+      break L269;
+     }
+     do {
+      if ((i22 | 0) != (-1 | 0) & i24 >>> 0 < 2147483647 & i24 >>> 0 < i20 >>> 0 ? (i19 = HEAP32[14952 >> 2] | 0, i19 = i21 - i24 + i19 & 0 - i19, i19 >>> 0 < 2147483647) : 0) {
+       if ((_sbrk(i19 | 0) | 0) == (-1 | 0)) {
+        _sbrk(i13 | 0) | 0;
+        break L291;
+       } else {
+        i24 = i19 + i24 | 0;
+        break;
+       }
+      }
+     } while (0);
+     if ((i22 | 0) != (-1 | 0)) {
+      i17 = i22;
+      i14 = i24;
+      i13 = 202;
+      break L269;
+     }
+    }
+   } while (0);
+   HEAP32[14916 >> 2] = HEAP32[14916 >> 2] | 4;
+   i13 = 199;
+  } else {
+   i25 = 0;
+   i13 = 199;
+  }
+ } while (0);
+ if ((((i13 | 0) == 199 ? i18 >>> 0 < 2147483647 : 0) ? (i17 = _sbrk(i18 | 0) | 0, i16 = _sbrk(0) | 0, (i16 | 0) != (-1 | 0) & (i17 | 0) != (-1 | 0) & i17 >>> 0 < i16 >>> 0) : 0) ? (i15 = i16 - i17 | 0, i14 = i15 >>> 0 > (i12 + 40 | 0) >>> 0, i14) : 0) {
+  i14 = i14 ? i15 : i25;
+  i13 = 202;
+ }
+ if ((i13 | 0) == 202) {
+  i15 = (HEAP32[14904 >> 2] | 0) + i14 | 0;
+  HEAP32[14904 >> 2] = i15;
+  if (i15 >>> 0 > (HEAP32[14908 >> 2] | 0) >>> 0) {
+   HEAP32[14908 >> 2] = i15;
+  }
+  i15 = HEAP32[14496 >> 2] | 0;
+  L311 : do {
+   if ((i15 | 0) != 0) {
+    i21 = 14920 | 0;
+    while (1) {
+     i16 = HEAP32[i21 >> 2] | 0;
+     i19 = i21 + 4 | 0;
+     i20 = HEAP32[i19 >> 2] | 0;
+     if ((i17 | 0) == (i16 + i20 | 0)) {
+      i13 = 214;
+      break;
+     }
+     i18 = HEAP32[i21 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i21 = i18;
+     }
+    }
+    if (((i13 | 0) == 214 ? (HEAP32[i21 + 12 >> 2] & 8 | 0) == 0 : 0) ? i15 >>> 0 >= i16 >>> 0 & i15 >>> 0 < i17 >>> 0 : 0) {
+     HEAP32[i19 >> 2] = i20 + i14;
+     i2 = (HEAP32[14484 >> 2] | 0) + i14 | 0;
+     i3 = i15 + 8 | 0;
+     if ((i3 & 7 | 0) == 0) {
+      i3 = 0;
+     } else {
+      i3 = 0 - i3 & 7;
+     }
+     i32 = i2 - i3 | 0;
+     HEAP32[14496 >> 2] = i15 + i3;
+     HEAP32[14484 >> 2] = i32;
+     HEAP32[i15 + (i3 + 4) >> 2] = i32 | 1;
+     HEAP32[i15 + (i2 + 4) >> 2] = 40;
+     HEAP32[14500 >> 2] = HEAP32[14960 >> 2];
+     break;
+    }
+    if (i17 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+     HEAP32[14488 >> 2] = i17;
+    }
+    i19 = i17 + i14 | 0;
+    i16 = 14920 | 0;
+    while (1) {
+     if ((HEAP32[i16 >> 2] | 0) == (i19 | 0)) {
+      i13 = 224;
+      break;
+     }
+     i18 = HEAP32[i16 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i16 = i18;
+     }
+    }
+    if ((i13 | 0) == 224 ? (HEAP32[i16 + 12 >> 2] & 8 | 0) == 0 : 0) {
+     HEAP32[i16 >> 2] = i17;
+     i6 = i16 + 4 | 0;
+     HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i14;
+     i6 = i17 + 8 | 0;
+     if ((i6 & 7 | 0) == 0) {
+      i6 = 0;
+     } else {
+      i6 = 0 - i6 & 7;
+     }
+     i7 = i17 + (i14 + 8) | 0;
+     if ((i7 & 7 | 0) == 0) {
+      i13 = 0;
+     } else {
+      i13 = 0 - i7 & 7;
+     }
+     i15 = i17 + (i13 + i14) | 0;
+     i8 = i6 + i12 | 0;
+     i7 = i17 + i8 | 0;
+     i10 = i15 - (i17 + i6) - i12 | 0;
+     HEAP32[i17 + (i6 + 4) >> 2] = i12 | 3;
+     L348 : do {
+      if ((i15 | 0) != (HEAP32[14496 >> 2] | 0)) {
+       if ((i15 | 0) == (HEAP32[14492 >> 2] | 0)) {
+        i32 = (HEAP32[14480 >> 2] | 0) + i10 | 0;
+        HEAP32[14480 >> 2] = i32;
+        HEAP32[14492 >> 2] = i7;
+        HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+        HEAP32[i17 + (i32 + i8) >> 2] = i32;
+        break;
+       }
+       i12 = i14 + 4 | 0;
+       i18 = HEAP32[i17 + (i12 + i13) >> 2] | 0;
+       if ((i18 & 3 | 0) == 1) {
+        i11 = i18 & -8;
+        i16 = i18 >>> 3;
+        do {
+         if (!(i18 >>> 0 < 256)) {
+          i9 = HEAP32[i17 + ((i13 | 24) + i14) >> 2] | 0;
+          i19 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          do {
+           if ((i19 | 0) == (i15 | 0)) {
+            i19 = i13 | 16;
+            i18 = i17 + (i12 + i19) | 0;
+            i16 = HEAP32[i18 >> 2] | 0;
+            if ((i16 | 0) == 0) {
+             i18 = i17 + (i19 + i14) | 0;
+             i16 = HEAP32[i18 >> 2] | 0;
+             if ((i16 | 0) == 0) {
+              i5 = 0;
+              break;
+             }
+            }
+            while (1) {
+             i20 = i16 + 20 | 0;
+             i19 = HEAP32[i20 >> 2] | 0;
+             if ((i19 | 0) != 0) {
+              i16 = i19;
+              i18 = i20;
+              continue;
+             }
+             i19 = i16 + 16 | 0;
+             i20 = HEAP32[i19 >> 2] | 0;
+             if ((i20 | 0) == 0) {
+              break;
+             } else {
+              i16 = i20;
+              i18 = i19;
+             }
+            }
+            if (i18 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i18 >> 2] = 0;
+             i5 = i16;
+             break;
+            }
+           } else {
+            i18 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+            if (i18 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i18 + 12 | 0;
+            if ((HEAP32[i16 >> 2] | 0) != (i15 | 0)) {
+             _abort();
+            }
+            i20 = i19 + 8 | 0;
+            if ((HEAP32[i20 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i19;
+             HEAP32[i20 >> 2] = i18;
+             i5 = i19;
+             break;
+            } else {
+             _abort();
+            }
+           }
+          } while (0);
+          if ((i9 | 0) != 0) {
+           i16 = HEAP32[i17 + (i14 + 28 + i13) >> 2] | 0;
+           i18 = 14776 + (i16 << 2) | 0;
+           if ((i15 | 0) == (HEAP32[i18 >> 2] | 0)) {
+            HEAP32[i18 >> 2] = i5;
+            if ((i5 | 0) == 0) {
+             HEAP32[14476 >> 2] = HEAP32[14476 >> 2] & ~(1 << i16);
+             break;
+            }
+           } else {
+            if (i9 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i9 + 16 | 0;
+            if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i5;
+            } else {
+             HEAP32[i9 + 20 >> 2] = i5;
+            }
+            if ((i5 | 0) == 0) {
+             break;
+            }
+           }
+           if (i5 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           HEAP32[i5 + 24 >> 2] = i9;
+           i15 = i13 | 16;
+           i9 = HEAP32[i17 + (i15 + i14) >> 2] | 0;
+           do {
+            if ((i9 | 0) != 0) {
+             if (i9 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+              _abort();
+             } else {
+              HEAP32[i5 + 16 >> 2] = i9;
+              HEAP32[i9 + 24 >> 2] = i5;
+              break;
+             }
+            }
+           } while (0);
+           i9 = HEAP32[i17 + (i12 + i15) >> 2] | 0;
+           if ((i9 | 0) != 0) {
+            if (i9 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i5 + 20 >> 2] = i9;
+             HEAP32[i9 + 24 >> 2] = i5;
+             break;
+            }
+           }
+          }
+         } else {
+          i5 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+          i12 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          i18 = 14512 + (i16 << 1 << 2) | 0;
+          if ((i5 | 0) != (i18 | 0)) {
+           if (i5 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           if ((HEAP32[i5 + 12 >> 2] | 0) != (i15 | 0)) {
+            _abort();
+           }
+          }
+          if ((i12 | 0) == (i5 | 0)) {
+           HEAP32[3618] = HEAP32[3618] & ~(1 << i16);
+           break;
+          }
+          if ((i12 | 0) != (i18 | 0)) {
+           if (i12 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           i16 = i12 + 8 | 0;
+           if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+            i9 = i16;
+           } else {
+            _abort();
+           }
+          } else {
+           i9 = i12 + 8 | 0;
+          }
+          HEAP32[i5 + 12 >> 2] = i12;
+          HEAP32[i9 >> 2] = i5;
+         }
+        } while (0);
+        i15 = i17 + ((i11 | i13) + i14) | 0;
+        i10 = i11 + i10 | 0;
+       }
+       i5 = i15 + 4 | 0;
+       HEAP32[i5 >> 2] = HEAP32[i5 >> 2] & -2;
+       HEAP32[i17 + (i8 + 4) >> 2] = i10 | 1;
+       HEAP32[i17 + (i10 + i8) >> 2] = i10;
+       i5 = i10 >>> 3;
+       if (i10 >>> 0 < 256) {
+        i10 = i5 << 1;
+        i2 = 14512 + (i10 << 2) | 0;
+        i9 = HEAP32[3618] | 0;
+        i5 = 1 << i5;
+        if ((i9 & i5 | 0) != 0) {
+         i9 = 14512 + (i10 + 2 << 2) | 0;
+         i5 = HEAP32[i9 >> 2] | 0;
+         if (i5 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          i3 = i9;
+          i4 = i5;
+         }
+        } else {
+         HEAP32[3618] = i9 | i5;
+         i3 = 14512 + (i10 + 2 << 2) | 0;
+         i4 = i2;
+        }
+        HEAP32[i3 >> 2] = i7;
+        HEAP32[i4 + 12 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        break;
+       }
+       i3 = i10 >>> 8;
+       if ((i3 | 0) != 0) {
+        if (i10 >>> 0 > 16777215) {
+         i3 = 31;
+        } else {
+         i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+         i32 = i3 << i31;
+         i30 = (i32 + 520192 | 0) >>> 16 & 4;
+         i32 = i32 << i30;
+         i3 = (i32 + 245760 | 0) >>> 16 & 2;
+         i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+         i3 = i10 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+        }
+       } else {
+        i3 = 0;
+       }
+       i4 = 14776 + (i3 << 2) | 0;
+       HEAP32[i17 + (i8 + 28) >> 2] = i3;
+       HEAP32[i17 + (i8 + 20) >> 2] = 0;
+       HEAP32[i17 + (i8 + 16) >> 2] = 0;
+       i9 = HEAP32[14476 >> 2] | 0;
+       i5 = 1 << i3;
+       if ((i9 & i5 | 0) == 0) {
+        HEAP32[14476 >> 2] = i9 | i5;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 24) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i7;
+        break;
+       }
+       i4 = HEAP32[i4 >> 2] | 0;
+       if ((i3 | 0) == 31) {
+        i3 = 0;
+       } else {
+        i3 = 25 - (i3 >>> 1) | 0;
+       }
+       L444 : do {
+        if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i10 | 0)) {
+         i3 = i10 << i3;
+         while (1) {
+          i5 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+          i9 = HEAP32[i5 >> 2] | 0;
+          if ((i9 | 0) == 0) {
+           break;
+          }
+          if ((HEAP32[i9 + 4 >> 2] & -8 | 0) == (i10 | 0)) {
+           i2 = i9;
+           break L444;
+          } else {
+           i3 = i3 << 1;
+           i4 = i9;
+          }
+         }
+         if (i5 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i5 >> 2] = i7;
+          HEAP32[i17 + (i8 + 24) >> 2] = i4;
+          HEAP32[i17 + (i8 + 12) >> 2] = i7;
+          HEAP32[i17 + (i8 + 8) >> 2] = i7;
+          break L348;
+         }
+        } else {
+         i2 = i4;
+        }
+       } while (0);
+       i4 = i2 + 8 | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       i5 = HEAP32[14488 >> 2] | 0;
+       if (i2 >>> 0 < i5 >>> 0) {
+        _abort();
+       }
+       if (i3 >>> 0 < i5 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i3 + 12 >> 2] = i7;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i3;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        HEAP32[i17 + (i8 + 24) >> 2] = 0;
+        break;
+       }
+      } else {
+       i32 = (HEAP32[14484 >> 2] | 0) + i10 | 0;
+       HEAP32[14484 >> 2] = i32;
+       HEAP32[14496 >> 2] = i7;
+       HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+      }
+     } while (0);
+     i32 = i17 + (i6 | 8) | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i3 = 14920 | 0;
+    while (1) {
+     i2 = HEAP32[i3 >> 2] | 0;
+     if (!(i2 >>> 0 > i15 >>> 0) ? (i11 = HEAP32[i3 + 4 >> 2] | 0, i10 = i2 + i11 | 0, i10 >>> 0 > i15 >>> 0) : 0) {
+      break;
+     }
+     i3 = HEAP32[i3 + 8 >> 2] | 0;
+    }
+    i3 = i2 + (i11 + -39) | 0;
+    if ((i3 & 7 | 0) == 0) {
+     i3 = 0;
+    } else {
+     i3 = 0 - i3 & 7;
+    }
+    i2 = i2 + (i11 + -47 + i3) | 0;
+    i2 = i2 >>> 0 < (i15 + 16 | 0) >>> 0 ? i15 : i2;
+    i3 = i2 + 8 | 0;
+    i4 = i17 + 8 | 0;
+    if ((i4 & 7 | 0) == 0) {
+     i4 = 0;
+    } else {
+     i4 = 0 - i4 & 7;
+    }
+    i32 = i14 + -40 - i4 | 0;
+    HEAP32[14496 >> 2] = i17 + i4;
+    HEAP32[14484 >> 2] = i32;
+    HEAP32[i17 + (i4 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[14500 >> 2] = HEAP32[14960 >> 2];
+    HEAP32[i2 + 4 >> 2] = 27;
+    HEAP32[i3 + 0 >> 2] = HEAP32[14920 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[14924 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[14928 >> 2];
+    HEAP32[i3 + 12 >> 2] = HEAP32[14932 >> 2];
+    HEAP32[14920 >> 2] = i17;
+    HEAP32[14924 >> 2] = i14;
+    HEAP32[14932 >> 2] = 0;
+    HEAP32[14928 >> 2] = i3;
+    i4 = i2 + 28 | 0;
+    HEAP32[i4 >> 2] = 7;
+    if ((i2 + 32 | 0) >>> 0 < i10 >>> 0) {
+     while (1) {
+      i3 = i4 + 4 | 0;
+      HEAP32[i3 >> 2] = 7;
+      if ((i4 + 8 | 0) >>> 0 < i10 >>> 0) {
+       i4 = i3;
+      } else {
+       break;
+      }
+     }
+    }
+    if ((i2 | 0) != (i15 | 0)) {
+     i2 = i2 - i15 | 0;
+     i3 = i15 + (i2 + 4) | 0;
+     HEAP32[i3 >> 2] = HEAP32[i3 >> 2] & -2;
+     HEAP32[i15 + 4 >> 2] = i2 | 1;
+     HEAP32[i15 + i2 >> 2] = i2;
+     i3 = i2 >>> 3;
+     if (i2 >>> 0 < 256) {
+      i4 = i3 << 1;
+      i2 = 14512 + (i4 << 2) | 0;
+      i5 = HEAP32[3618] | 0;
+      i3 = 1 << i3;
+      if ((i5 & i3 | 0) != 0) {
+       i4 = 14512 + (i4 + 2 << 2) | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       if (i3 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i7 = i4;
+        i8 = i3;
+       }
+      } else {
+       HEAP32[3618] = i5 | i3;
+       i7 = 14512 + (i4 + 2 << 2) | 0;
+       i8 = i2;
+      }
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i8 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i8;
+      HEAP32[i15 + 12 >> 2] = i2;
+      break;
+     }
+     i3 = i2 >>> 8;
+     if ((i3 | 0) != 0) {
+      if (i2 >>> 0 > 16777215) {
+       i3 = 31;
+      } else {
+       i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+       i32 = i3 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i3 = (i32 + 245760 | 0) >>> 16 & 2;
+       i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+       i3 = i2 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+      }
+     } else {
+      i3 = 0;
+     }
+     i7 = 14776 + (i3 << 2) | 0;
+     HEAP32[i15 + 28 >> 2] = i3;
+     HEAP32[i15 + 20 >> 2] = 0;
+     HEAP32[i15 + 16 >> 2] = 0;
+     i4 = HEAP32[14476 >> 2] | 0;
+     i5 = 1 << i3;
+     if ((i4 & i5 | 0) == 0) {
+      HEAP32[14476 >> 2] = i4 | i5;
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i7;
+      HEAP32[i15 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i15;
+      break;
+     }
+     i4 = HEAP32[i7 >> 2] | 0;
+     if ((i3 | 0) == 31) {
+      i3 = 0;
+     } else {
+      i3 = 25 - (i3 >>> 1) | 0;
+     }
+     L499 : do {
+      if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i2 | 0)) {
+       i3 = i2 << i3;
+       while (1) {
+        i7 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+        i5 = HEAP32[i7 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         break;
+        }
+        if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i2 | 0)) {
+         i6 = i5;
+         break L499;
+        } else {
+         i3 = i3 << 1;
+         i4 = i5;
+        }
+       }
+       if (i7 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i7 >> 2] = i15;
+        HEAP32[i15 + 24 >> 2] = i4;
+        HEAP32[i15 + 12 >> 2] = i15;
+        HEAP32[i15 + 8 >> 2] = i15;
+        break L311;
+       }
+      } else {
+       i6 = i4;
+      }
+     } while (0);
+     i4 = i6 + 8 | 0;
+     i3 = HEAP32[i4 >> 2] | 0;
+     i2 = HEAP32[14488 >> 2] | 0;
+     if (i6 >>> 0 < i2 >>> 0) {
+      _abort();
+     }
+     if (i3 >>> 0 < i2 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i3 + 12 >> 2] = i15;
+      HEAP32[i4 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i3;
+      HEAP32[i15 + 12 >> 2] = i6;
+      HEAP32[i15 + 24 >> 2] = 0;
+      break;
+     }
+    }
+   } else {
+    i32 = HEAP32[14488 >> 2] | 0;
+    if ((i32 | 0) == 0 | i17 >>> 0 < i32 >>> 0) {
+     HEAP32[14488 >> 2] = i17;
+    }
+    HEAP32[14920 >> 2] = i17;
+    HEAP32[14924 >> 2] = i14;
+    HEAP32[14932 >> 2] = 0;
+    HEAP32[14508 >> 2] = HEAP32[3736];
+    HEAP32[14504 >> 2] = -1;
+    i2 = 0;
+    do {
+     i32 = i2 << 1;
+     i31 = 14512 + (i32 << 2) | 0;
+     HEAP32[14512 + (i32 + 3 << 2) >> 2] = i31;
+     HEAP32[14512 + (i32 + 2 << 2) >> 2] = i31;
+     i2 = i2 + 1 | 0;
+    } while ((i2 | 0) != 32);
+    i2 = i17 + 8 | 0;
+    if ((i2 & 7 | 0) == 0) {
+     i2 = 0;
+    } else {
+     i2 = 0 - i2 & 7;
+    }
+    i32 = i14 + -40 - i2 | 0;
+    HEAP32[14496 >> 2] = i17 + i2;
+    HEAP32[14484 >> 2] = i32;
+    HEAP32[i17 + (i2 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[14500 >> 2] = HEAP32[14960 >> 2];
+   }
+  } while (0);
+  i2 = HEAP32[14484 >> 2] | 0;
+  if (i2 >>> 0 > i12 >>> 0) {
+   i31 = i2 - i12 | 0;
+   HEAP32[14484 >> 2] = i31;
+   i32 = HEAP32[14496 >> 2] | 0;
+   HEAP32[14496 >> 2] = i32 + i12;
+   HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+   HEAP32[i32 + 4 >> 2] = i12 | 3;
+   i32 = i32 + 8 | 0;
+   STACKTOP = i1;
+   return i32 | 0;
+  }
+ }
+ HEAP32[(___errno_location() | 0) >> 2] = 12;
+ i32 = 0;
+ STACKTOP = i1;
+ return i32 | 0;
+}
+function _deflate(i2, i10) {
+ i2 = i2 | 0;
+ i10 = i10 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0;
+ i1 = STACKTOP;
+ if ((i2 | 0) == 0) {
+  i37 = -2;
+  STACKTOP = i1;
+  return i37 | 0;
+ }
+ i5 = i2 + 28 | 0;
+ i7 = HEAP32[i5 >> 2] | 0;
+ if ((i7 | 0) == 0 | i10 >>> 0 > 5) {
+  i37 = -2;
+  STACKTOP = i1;
+  return i37 | 0;
+ }
+ i4 = i2 + 12 | 0;
+ do {
+  if ((HEAP32[i4 >> 2] | 0) != 0) {
+   if ((HEAP32[i2 >> 2] | 0) == 0 ? (HEAP32[i2 + 4 >> 2] | 0) != 0 : 0) {
+    break;
+   }
+   i11 = i7 + 4 | 0;
+   i29 = HEAP32[i11 >> 2] | 0;
+   i9 = (i10 | 0) == 4;
+   if ((i29 | 0) != 666 | i9) {
+    i3 = i2 + 16 | 0;
+    if ((HEAP32[i3 >> 2] | 0) == 0) {
+     HEAP32[i2 + 24 >> 2] = HEAP32[3180 >> 2];
+     i37 = -5;
+     STACKTOP = i1;
+     return i37 | 0;
+    }
+    HEAP32[i7 >> 2] = i2;
+    i8 = i7 + 40 | 0;
+    i18 = HEAP32[i8 >> 2] | 0;
+    HEAP32[i8 >> 2] = i10;
+    do {
+     if ((i29 | 0) == 42) {
+      if ((HEAP32[i7 + 24 >> 2] | 0) != 2) {
+       i17 = (HEAP32[i7 + 48 >> 2] << 12) + -30720 | 0;
+       if ((HEAP32[i7 + 136 >> 2] | 0) <= 1 ? (i28 = HEAP32[i7 + 132 >> 2] | 0, (i28 | 0) >= 2) : 0) {
+        if ((i28 | 0) < 6) {
+         i28 = 64;
+        } else {
+         i28 = (i28 | 0) == 6 ? 128 : 192;
+        }
+       } else {
+        i28 = 0;
+       }
+       i28 = i28 | i17;
+       i17 = i7 + 108 | 0;
+       i37 = (HEAP32[i17 >> 2] | 0) == 0 ? i28 : i28 | 32;
+       HEAP32[i11 >> 2] = 113;
+       i29 = i7 + 20 | 0;
+       i30 = HEAP32[i29 >> 2] | 0;
+       HEAP32[i29 >> 2] = i30 + 1;
+       i28 = i7 + 8 | 0;
+       HEAP8[(HEAP32[i28 >> 2] | 0) + i30 | 0] = i37 >>> 8;
+       i30 = HEAP32[i29 >> 2] | 0;
+       HEAP32[i29 >> 2] = i30 + 1;
+       HEAP8[(HEAP32[i28 >> 2] | 0) + i30 | 0] = (i37 | ((i37 >>> 0) % 31 | 0)) ^ 31;
+       i30 = i2 + 48 | 0;
+       if ((HEAP32[i17 >> 2] | 0) != 0) {
+        i37 = HEAP32[i30 >> 2] | 0;
+        i36 = HEAP32[i29 >> 2] | 0;
+        HEAP32[i29 >> 2] = i36 + 1;
+        HEAP8[(HEAP32[i28 >> 2] | 0) + i36 | 0] = i37 >>> 24;
+        i36 = HEAP32[i29 >> 2] | 0;
+        HEAP32[i29 >> 2] = i36 + 1;
+        HEAP8[(HEAP32[i28 >> 2] | 0) + i36 | 0] = i37 >>> 16;
+        i36 = HEAP32[i30 >> 2] | 0;
+        i37 = HEAP32[i29 >> 2] | 0;
+        HEAP32[i29 >> 2] = i37 + 1;
+        HEAP8[(HEAP32[i28 >> 2] | 0) + i37 | 0] = i36 >>> 8;
+        i37 = HEAP32[i29 >> 2] | 0;
+        HEAP32[i29 >> 2] = i37 + 1;
+        HEAP8[(HEAP32[i28 >> 2] | 0) + i37 | 0] = i36;
+       }
+       HEAP32[i30 >> 2] = _adler32(0, 0, 0) | 0;
+       i31 = HEAP32[i11 >> 2] | 0;
+       i17 = 32;
+       break;
+      }
+      i32 = i2 + 48 | 0;
+      HEAP32[i32 >> 2] = _crc32(0, 0, 0) | 0;
+      i30 = i7 + 20 | 0;
+      i28 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i28 + 1;
+      i29 = i7 + 8 | 0;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i28 | 0] = 31;
+      i28 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i28 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i28 | 0] = -117;
+      i28 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i28 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i28 | 0] = 8;
+      i28 = i7 + 28 | 0;
+      i33 = HEAP32[i28 >> 2] | 0;
+      if ((i33 | 0) == 0) {
+       i22 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i22 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i22 | 0] = 0;
+       i22 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i22 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i22 | 0] = 0;
+       i22 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i22 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i22 | 0] = 0;
+       i22 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i22 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i22 | 0] = 0;
+       i22 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i22 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i22 | 0] = 0;
+       i22 = HEAP32[i7 + 132 >> 2] | 0;
+       if ((i22 | 0) != 9) {
+        if ((HEAP32[i7 + 136 >> 2] | 0) > 1) {
+         i22 = 4;
+        } else {
+         i22 = (i22 | 0) < 2 ? 4 : 0;
+        }
+       } else {
+        i22 = 2;
+       }
+       i37 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i37 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i37 | 0] = i22;
+       i37 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i37 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i37 | 0] = 3;
+       HEAP32[i11 >> 2] = 113;
+       break;
+      }
+      i37 = (((HEAP32[i33 + 44 >> 2] | 0) != 0 ? 2 : 0) | (HEAP32[i33 >> 2] | 0) != 0 | ((HEAP32[i33 + 16 >> 2] | 0) == 0 ? 0 : 4) | ((HEAP32[i33 + 28 >> 2] | 0) == 0 ? 0 : 8) | ((HEAP32[i33 + 36 >> 2] | 0) == 0 ? 0 : 16)) & 255;
+      i17 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i17 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i17 | 0] = i37;
+      i17 = HEAP32[(HEAP32[i28 >> 2] | 0) + 4 >> 2] & 255;
+      i37 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i37 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i37 | 0] = i17;
+      i37 = (HEAP32[(HEAP32[i28 >> 2] | 0) + 4 >> 2] | 0) >>> 8 & 255;
+      i17 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i17 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i17 | 0] = i37;
+      i17 = (HEAP32[(HEAP32[i28 >> 2] | 0) + 4 >> 2] | 0) >>> 16 & 255;
+      i37 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i37 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i37 | 0] = i17;
+      i37 = (HEAP32[(HEAP32[i28 >> 2] | 0) + 4 >> 2] | 0) >>> 24 & 255;
+      i17 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i17 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i17 | 0] = i37;
+      i17 = HEAP32[i7 + 132 >> 2] | 0;
+      if ((i17 | 0) != 9) {
+       if ((HEAP32[i7 + 136 >> 2] | 0) > 1) {
+        i17 = 4;
+       } else {
+        i17 = (i17 | 0) < 2 ? 4 : 0;
+       }
+      } else {
+       i17 = 2;
+      }
+      i37 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i37 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i37 | 0] = i17;
+      i37 = HEAP32[(HEAP32[i28 >> 2] | 0) + 12 >> 2] & 255;
+      i17 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i17 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i17 | 0] = i37;
+      i17 = HEAP32[i28 >> 2] | 0;
+      if ((HEAP32[i17 + 16 >> 2] | 0) != 0) {
+       i17 = HEAP32[i17 + 20 >> 2] & 255;
+       i37 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i37 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i37 | 0] = i17;
+       i37 = (HEAP32[(HEAP32[i28 >> 2] | 0) + 20 >> 2] | 0) >>> 8 & 255;
+       i17 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i17 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i17 | 0] = i37;
+       i17 = HEAP32[i28 >> 2] | 0;
+      }
+      if ((HEAP32[i17 + 44 >> 2] | 0) != 0) {
+       HEAP32[i32 >> 2] = _crc32(HEAP32[i32 >> 2] | 0, HEAP32[i29 >> 2] | 0, HEAP32[i30 >> 2] | 0) | 0;
+      }
+      HEAP32[i7 + 32 >> 2] = 0;
+      HEAP32[i11 >> 2] = 69;
+      i17 = 34;
+     } else {
+      i31 = i29;
+      i17 = 32;
+     }
+    } while (0);
+    if ((i17 | 0) == 32) {
+     if ((i31 | 0) == 69) {
+      i28 = i7 + 28 | 0;
+      i17 = 34;
+     } else {
+      i17 = 55;
+     }
+    }
+    do {
+     if ((i17 | 0) == 34) {
+      i37 = HEAP32[i28 >> 2] | 0;
+      if ((HEAP32[i37 + 16 >> 2] | 0) == 0) {
+       HEAP32[i11 >> 2] = 73;
+       i17 = 57;
+       break;
+      }
+      i29 = i7 + 20 | 0;
+      i34 = HEAP32[i29 >> 2] | 0;
+      i17 = i7 + 32 | 0;
+      i36 = HEAP32[i17 >> 2] | 0;
+      L55 : do {
+       if (i36 >>> 0 < (HEAP32[i37 + 20 >> 2] & 65535) >>> 0) {
+        i30 = i7 + 12 | 0;
+        i32 = i2 + 48 | 0;
+        i31 = i7 + 8 | 0;
+        i33 = i2 + 20 | 0;
+        i35 = i34;
+        while (1) {
+         if ((i35 | 0) == (HEAP32[i30 >> 2] | 0)) {
+          if ((HEAP32[i37 + 44 >> 2] | 0) != 0 & i35 >>> 0 > i34 >>> 0) {
+           HEAP32[i32 >> 2] = _crc32(HEAP32[i32 >> 2] | 0, (HEAP32[i31 >> 2] | 0) + i34 | 0, i35 - i34 | 0) | 0;
+          }
+          i34 = HEAP32[i5 >> 2] | 0;
+          i35 = HEAP32[i34 + 20 >> 2] | 0;
+          i36 = HEAP32[i3 >> 2] | 0;
+          i35 = i35 >>> 0 > i36 >>> 0 ? i36 : i35;
+          if ((i35 | 0) != 0 ? (_memcpy(HEAP32[i4 >> 2] | 0, HEAP32[i34 + 16 >> 2] | 0, i35 | 0) | 0, HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + i35, i27 = (HEAP32[i5 >> 2] | 0) + 16 | 0, HEAP32[i27 >> 2] = (HEAP32[i27 >> 2] | 0) + i35, HEAP32[i33 >> 2] = (HEAP32[i33 >> 2] | 0) + i35, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) - i35, i27 = HEAP32[i5 >> 2] | 0, i36 = i27 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i35, (i37 | 0) == (i35 | 0)) : 0) {
+           HEAP32[i27 + 16 >> 2] = HEAP32[i27 + 8 >> 2];
+          }
+          i34 = HEAP32[i29 >> 2] | 0;
+          if ((i34 | 0) == (HEAP32[i30 >> 2] | 0)) {
+           break;
+          }
+          i37 = HEAP32[i28 >> 2] | 0;
+          i36 = HEAP32[i17 >> 2] | 0;
+          i35 = i34;
+         }
+         i36 = HEAP8[(HEAP32[i37 + 16 >> 2] | 0) + i36 | 0] | 0;
+         HEAP32[i29 >> 2] = i35 + 1;
+         HEAP8[(HEAP32[i31 >> 2] | 0) + i35 | 0] = i36;
+         i36 = (HEAP32[i17 >> 2] | 0) + 1 | 0;
+         HEAP32[i17 >> 2] = i36;
+         i37 = HEAP32[i28 >> 2] | 0;
+         if (!(i36 >>> 0 < (HEAP32[i37 + 20 >> 2] & 65535) >>> 0)) {
+          break L55;
+         }
+         i35 = HEAP32[i29 >> 2] | 0;
+        }
+        i37 = HEAP32[i28 >> 2] | 0;
+       }
+      } while (0);
+      if ((HEAP32[i37 + 44 >> 2] | 0) != 0 ? (i26 = HEAP32[i29 >> 2] | 0, i26 >>> 0 > i34 >>> 0) : 0) {
+       i37 = i2 + 48 | 0;
+       HEAP32[i37 >> 2] = _crc32(HEAP32[i37 >> 2] | 0, (HEAP32[i7 + 8 >> 2] | 0) + i34 | 0, i26 - i34 | 0) | 0;
+       i37 = HEAP32[i28 >> 2] | 0;
+      }
+      if ((HEAP32[i17 >> 2] | 0) == (HEAP32[i37 + 20 >> 2] | 0)) {
+       HEAP32[i17 >> 2] = 0;
+       HEAP32[i11 >> 2] = 73;
+       i17 = 57;
+       break;
+      } else {
+       i31 = HEAP32[i11 >> 2] | 0;
+       i17 = 55;
+       break;
+      }
+     }
+    } while (0);
+    if ((i17 | 0) == 55) {
+     if ((i31 | 0) == 73) {
+      i37 = HEAP32[i7 + 28 >> 2] | 0;
+      i17 = 57;
+     } else {
+      i17 = 76;
+     }
+    }
+    do {
+     if ((i17 | 0) == 57) {
+      i26 = i7 + 28 | 0;
+      if ((HEAP32[i37 + 28 >> 2] | 0) == 0) {
+       HEAP32[i11 >> 2] = 91;
+       i17 = 78;
+       break;
+      }
+      i27 = i7 + 20 | 0;
+      i35 = HEAP32[i27 >> 2] | 0;
+      i32 = i7 + 12 | 0;
+      i29 = i2 + 48 | 0;
+      i28 = i7 + 8 | 0;
+      i31 = i2 + 20 | 0;
+      i30 = i7 + 32 | 0;
+      i33 = i35;
+      while (1) {
+       if ((i33 | 0) == (HEAP32[i32 >> 2] | 0)) {
+        if ((HEAP32[(HEAP32[i26 >> 2] | 0) + 44 >> 2] | 0) != 0 & i33 >>> 0 > i35 >>> 0) {
+         HEAP32[i29 >> 2] = _crc32(HEAP32[i29 >> 2] | 0, (HEAP32[i28 >> 2] | 0) + i35 | 0, i33 - i35 | 0) | 0;
+        }
+        i33 = HEAP32[i5 >> 2] | 0;
+        i34 = HEAP32[i33 + 20 >> 2] | 0;
+        i35 = HEAP32[i3 >> 2] | 0;
+        i34 = i34 >>> 0 > i35 >>> 0 ? i35 : i34;
+        if ((i34 | 0) != 0 ? (_memcpy(HEAP32[i4 >> 2] | 0, HEAP32[i33 + 16 >> 2] | 0, i34 | 0) | 0, HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + i34, i25 = (HEAP32[i5 >> 2] | 0) + 16 | 0, HEAP32[i25 >> 2] = (HEAP32[i25 >> 2] | 0) + i34, HEAP32[i31 >> 2] = (HEAP32[i31 >> 2] | 0) + i34, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) - i34, i25 = HEAP32[i5 >> 2] | 0, i36 = i25 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i34, (i37 | 0) == (i34 | 0)) : 0) {
+         HEAP32[i25 + 16 >> 2] = HEAP32[i25 + 8 >> 2];
+        }
+        i35 = HEAP32[i27 >> 2] | 0;
+        if ((i35 | 0) == (HEAP32[i32 >> 2] | 0)) {
+         i25 = 1;
+         break;
+        } else {
+         i33 = i35;
+        }
+       }
+       i34 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i34 + 1;
+       i34 = HEAP8[(HEAP32[(HEAP32[i26 >> 2] | 0) + 28 >> 2] | 0) + i34 | 0] | 0;
+       HEAP32[i27 >> 2] = i33 + 1;
+       HEAP8[(HEAP32[i28 >> 2] | 0) + i33 | 0] = i34;
+       if (i34 << 24 >> 24 == 0) {
+        i17 = 68;
+        break;
+       }
+       i33 = HEAP32[i27 >> 2] | 0;
+      }
+      if ((i17 | 0) == 68) {
+       i25 = i34 & 255;
+      }
+      if ((HEAP32[(HEAP32[i26 >> 2] | 0) + 44 >> 2] | 0) != 0 ? (i24 = HEAP32[i27 >> 2] | 0, i24 >>> 0 > i35 >>> 0) : 0) {
+       HEAP32[i29 >> 2] = _crc32(HEAP32[i29 >> 2] | 0, (HEAP32[i28 >> 2] | 0) + i35 | 0, i24 - i35 | 0) | 0;
+      }
+      if ((i25 | 0) == 0) {
+       HEAP32[i30 >> 2] = 0;
+       HEAP32[i11 >> 2] = 91;
+       i17 = 78;
+       break;
+      } else {
+       i31 = HEAP32[i11 >> 2] | 0;
+       i17 = 76;
+       break;
+      }
+     }
+    } while (0);
+    if ((i17 | 0) == 76) {
+     if ((i31 | 0) == 91) {
+      i26 = i7 + 28 | 0;
+      i17 = 78;
+     } else {
+      i17 = 97;
+     }
+    }
+    do {
+     if ((i17 | 0) == 78) {
+      if ((HEAP32[(HEAP32[i26 >> 2] | 0) + 36 >> 2] | 0) == 0) {
+       HEAP32[i11 >> 2] = 103;
+       i17 = 99;
+       break;
+      }
+      i24 = i7 + 20 | 0;
+      i32 = HEAP32[i24 >> 2] | 0;
+      i29 = i7 + 12 | 0;
+      i27 = i2 + 48 | 0;
+      i25 = i7 + 8 | 0;
+      i28 = i2 + 20 | 0;
+      i30 = i7 + 32 | 0;
+      i31 = i32;
+      while (1) {
+       if ((i31 | 0) == (HEAP32[i29 >> 2] | 0)) {
+        if ((HEAP32[(HEAP32[i26 >> 2] | 0) + 44 >> 2] | 0) != 0 & i31 >>> 0 > i32 >>> 0) {
+         HEAP32[i27 >> 2] = _crc32(HEAP32[i27 >> 2] | 0, (HEAP32[i25 >> 2] | 0) + i32 | 0, i31 - i32 | 0) | 0;
+        }
+        i31 = HEAP32[i5 >> 2] | 0;
+        i33 = HEAP32[i31 + 20 >> 2] | 0;
+        i32 = HEAP32[i3 >> 2] | 0;
+        i32 = i33 >>> 0 > i32 >>> 0 ? i32 : i33;
+        if ((i32 | 0) != 0 ? (_memcpy(HEAP32[i4 >> 2] | 0, HEAP32[i31 + 16 >> 2] | 0, i32 | 0) | 0, HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + i32, i23 = (HEAP32[i5 >> 2] | 0) + 16 | 0, HEAP32[i23 >> 2] = (HEAP32[i23 >> 2] | 0) + i32, HEAP32[i28 >> 2] = (HEAP32[i28 >> 2] | 0) + i32, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) - i32, i23 = HEAP32[i5 >> 2] | 0, i36 = i23 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i32, (i37 | 0) == (i32 | 0)) : 0) {
+         HEAP32[i23 + 16 >> 2] = HEAP32[i23 + 8 >> 2];
+        }
+        i32 = HEAP32[i24 >> 2] | 0;
+        if ((i32 | 0) == (HEAP32[i29 >> 2] | 0)) {
+         i23 = 1;
+         break;
+        } else {
+         i31 = i32;
+        }
+       }
+       i33 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i33 + 1;
+       i33 = HEAP8[(HEAP32[(HEAP32[i26 >> 2] | 0) + 36 >> 2] | 0) + i33 | 0] | 0;
+       HEAP32[i24 >> 2] = i31 + 1;
+       HEAP8[(HEAP32[i25 >> 2] | 0) + i31 | 0] = i33;
+       if (i33 << 24 >> 24 == 0) {
+        i17 = 89;
+        break;
+       }
+       i31 = HEAP32[i24 >> 2] | 0;
+      }
+      if ((i17 | 0) == 89) {
+       i23 = i33 & 255;
+      }
+      if ((HEAP32[(HEAP32[i26 >> 2] | 0) + 44 >> 2] | 0) != 0 ? (i22 = HEAP32[i24 >> 2] | 0, i22 >>> 0 > i32 >>> 0) : 0) {
+       HEAP32[i27 >> 2] = _crc32(HEAP32[i27 >> 2] | 0, (HEAP32[i25 >> 2] | 0) + i32 | 0, i22 - i32 | 0) | 0;
+      }
+      if ((i23 | 0) == 0) {
+       HEAP32[i11 >> 2] = 103;
+       i17 = 99;
+       break;
+      } else {
+       i31 = HEAP32[i11 >> 2] | 0;
+       i17 = 97;
+       break;
+      }
+     }
+    } while (0);
+    if ((i17 | 0) == 97 ? (i31 | 0) == 103 : 0) {
+     i26 = i7 + 28 | 0;
+     i17 = 99;
+    }
+    do {
+     if ((i17 | 0) == 99) {
+      if ((HEAP32[(HEAP32[i26 >> 2] | 0) + 44 >> 2] | 0) == 0) {
+       HEAP32[i11 >> 2] = 113;
+       break;
+      }
+      i17 = i7 + 20 | 0;
+      i22 = i7 + 12 | 0;
+      if ((((HEAP32[i17 >> 2] | 0) + 2 | 0) >>> 0 > (HEAP32[i22 >> 2] | 0) >>> 0 ? (i20 = HEAP32[i5 >> 2] | 0, i21 = HEAP32[i20 + 20 >> 2] | 0, i23 = HEAP32[i3 >> 2] | 0, i21 = i21 >>> 0 > i23 >>> 0 ? i23 : i21, (i21 | 0) != 0) : 0) ? (_memcpy(HEAP32[i4 >> 2] | 0, HEAP32[i20 + 16 >> 2] | 0, i21 | 0) | 0, HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + i21, i19 = (HEAP32[i5 >> 2] | 0) + 16 | 0, HEAP32[i19 >> 2] = (HEAP32[i19 >> 2] | 0) + i21, i19 = i2 + 20 | 0, HEAP32[i19 >> 2] = (HEAP32[i19 >> 2] | 0) + i21, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) - i21, i19 = HEAP32[i5 >> 2] | 0, i36 = i19 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i21, (i37 | 0) == (i21 | 0)) : 0) {
+       HEAP32[i19 + 16 >> 2] = HEAP32[i19 + 8 >> 2];
+      }
+      i19 = HEAP32[i17 >> 2] | 0;
+      if (!((i19 + 2 | 0) >>> 0 > (HEAP32[i22 >> 2] | 0) >>> 0)) {
+       i37 = i2 + 48 | 0;
+       i34 = HEAP32[i37 >> 2] & 255;
+       HEAP32[i17 >> 2] = i19 + 1;
+       i35 = i7 + 8 | 0;
+       HEAP8[(HEAP32[i35 >> 2] | 0) + i19 | 0] = i34;
+       i34 = (HEAP32[i37 >> 2] | 0) >>> 8 & 255;
+       i36 = HEAP32[i17 >> 2] | 0;
+       HEAP32[i17 >> 2] = i36 + 1;
+       HEAP8[(HEAP32[i35 >> 2] | 0) + i36 | 0] = i34;
+       HEAP32[i37 >> 2] = _crc32(0, 0, 0) | 0;
+       HEAP32[i11 >> 2] = 113;
+      }
+     }
+    } while (0);
+    i19 = i7 + 20 | 0;
+    if ((HEAP32[i19 >> 2] | 0) == 0) {
+     if ((HEAP32[i2 + 4 >> 2] | 0) == 0 ? (i18 | 0) >= (i10 | 0) & (i10 | 0) != 4 : 0) {
+      HEAP32[i2 + 24 >> 2] = HEAP32[3180 >> 2];
+      i37 = -5;
+      STACKTOP = i1;
+      return i37 | 0;
+     }
+    } else {
+     i17 = HEAP32[i5 >> 2] | 0;
+     i20 = HEAP32[i17 + 20 >> 2] | 0;
+     i18 = HEAP32[i3 >> 2] | 0;
+     i20 = i20 >>> 0 > i18 >>> 0 ? i18 : i20;
+     if ((i20 | 0) != 0) {
+      _memcpy(HEAP32[i4 >> 2] | 0, HEAP32[i17 + 16 >> 2] | 0, i20 | 0) | 0;
+      HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + i20;
+      i17 = (HEAP32[i5 >> 2] | 0) + 16 | 0;
+      HEAP32[i17 >> 2] = (HEAP32[i17 >> 2] | 0) + i20;
+      i17 = i2 + 20 | 0;
+      HEAP32[i17 >> 2] = (HEAP32[i17 >> 2] | 0) + i20;
+      HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) - i20;
+      i17 = HEAP32[i5 >> 2] | 0;
+      i36 = i17 + 20 | 0;
+      i37 = HEAP32[i36 >> 2] | 0;
+      HEAP32[i36 >> 2] = i37 - i20;
+      if ((i37 | 0) == (i20 | 0)) {
+       HEAP32[i17 + 16 >> 2] = HEAP32[i17 + 8 >> 2];
+      }
+      i18 = HEAP32[i3 >> 2] | 0;
+     }
+     if ((i18 | 0) == 0) {
+      HEAP32[i8 >> 2] = -1;
+      i37 = 0;
+      STACKTOP = i1;
+      return i37 | 0;
+     }
+    }
+    i18 = (HEAP32[i11 >> 2] | 0) == 666;
+    i17 = (HEAP32[i2 + 4 >> 2] | 0) == 0;
+    if (i18) {
+     if (i17) {
+      i17 = 121;
+     } else {
+      HEAP32[i2 + 24 >> 2] = HEAP32[3180 >> 2];
+      i37 = -5;
+      STACKTOP = i1;
+      return i37 | 0;
+     }
+    } else {
+     if (i17) {
+      i17 = 121;
+     } else {
+      i17 = 124;
+     }
+    }
+    do {
+     if ((i17 | 0) == 121) {
+      if ((HEAP32[i7 + 116 >> 2] | 0) == 0) {
+       if ((i10 | 0) != 0) {
+        if (i18) {
+         break;
+        } else {
+         i17 = 124;
+         break;
+        }
+       } else {
+        i37 = 0;
+        STACKTOP = i1;
+        return i37 | 0;
+       }
+      } else {
+       i17 = 124;
+      }
+     }
+    } while (0);
+    do {
+     if ((i17 | 0) == 124) {
+      i18 = HEAP32[i7 + 136 >> 2] | 0;
+      L185 : do {
+       if ((i18 | 0) == 2) {
+        i22 = i7 + 116 | 0;
+        i18 = i7 + 96 | 0;
+        i13 = i7 + 108 | 0;
+        i14 = i7 + 56 | 0;
+        i21 = i7 + 5792 | 0;
+        i20 = i7 + 5796 | 0;
+        i24 = i7 + 5784 | 0;
+        i23 = i7 + 5788 | 0;
+        i12 = i7 + 92 | 0;
+        while (1) {
+         if ((HEAP32[i22 >> 2] | 0) == 0 ? (_fill_window(i7), (HEAP32[i22 >> 2] | 0) == 0) : 0) {
+          break;
+         }
+         HEAP32[i18 >> 2] = 0;
+         i37 = HEAP8[(HEAP32[i14 >> 2] | 0) + (HEAP32[i13 >> 2] | 0) | 0] | 0;
+         i26 = HEAP32[i21 >> 2] | 0;
+         HEAP16[(HEAP32[i20 >> 2] | 0) + (i26 << 1) >> 1] = 0;
+         HEAP32[i21 >> 2] = i26 + 1;
+         HEAP8[(HEAP32[i24 >> 2] | 0) + i26 | 0] = i37;
+         i37 = i7 + ((i37 & 255) << 2) + 148 | 0;
+         HEAP16[i37 >> 1] = (HEAP16[i37 >> 1] | 0) + 1 << 16 >> 16;
+         i37 = (HEAP32[i21 >> 2] | 0) == ((HEAP32[i23 >> 2] | 0) + -1 | 0);
+         HEAP32[i22 >> 2] = (HEAP32[i22 >> 2] | 0) + -1;
+         i26 = (HEAP32[i13 >> 2] | 0) + 1 | 0;
+         HEAP32[i13 >> 2] = i26;
+         if (!i37) {
+          continue;
+         }
+         i25 = HEAP32[i12 >> 2] | 0;
+         if ((i25 | 0) > -1) {
+          i27 = (HEAP32[i14 >> 2] | 0) + i25 | 0;
+         } else {
+          i27 = 0;
+         }
+         __tr_flush_block(i7, i27, i26 - i25 | 0, 0);
+         HEAP32[i12 >> 2] = HEAP32[i13 >> 2];
+         i26 = HEAP32[i7 >> 2] | 0;
+         i25 = i26 + 28 | 0;
+         i27 = HEAP32[i25 >> 2] | 0;
+         i30 = HEAP32[i27 + 20 >> 2] | 0;
+         i28 = i26 + 16 | 0;
+         i29 = HEAP32[i28 >> 2] | 0;
+         i29 = i30 >>> 0 > i29 >>> 0 ? i29 : i30;
+         if ((i29 | 0) != 0 ? (i16 = i26 + 12 | 0, _memcpy(HEAP32[i16 >> 2] | 0, HEAP32[i27 + 16 >> 2] | 0, i29 | 0) | 0, HEAP32[i16 >> 2] = (HEAP32[i16 >> 2] | 0) + i29, i16 = (HEAP32[i25 >> 2] | 0) + 16 | 0, HEAP32[i16 >> 2] = (HEAP32[i16 >> 2] | 0) + i29, i16 = i26 + 20 | 0, HEAP32[i16 >> 2] = (HEAP32[i16 >> 2] | 0) + i29, HEAP32[i28 >> 2] = (HEAP32[i28 >> 2] | 0) - i29, i16 = HEAP32[i25 >> 2] | 0, i36 = i16 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i29, (i37 | 0) == (i29 | 0)) : 0) {
+          HEAP32[i16 + 16 >> 2] = HEAP32[i16 + 8 >> 2];
+         }
+         if ((HEAP32[(HEAP32[i7 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+          break L185;
+         }
+        }
+        if ((i10 | 0) != 0) {
+         i16 = HEAP32[i12 >> 2] | 0;
+         if ((i16 | 0) > -1) {
+          i14 = (HEAP32[i14 >> 2] | 0) + i16 | 0;
+         } else {
+          i14 = 0;
+         }
+         __tr_flush_block(i7, i14, (HEAP32[i13 >> 2] | 0) - i16 | 0, i9 & 1);
+         HEAP32[i12 >> 2] = HEAP32[i13 >> 2];
+         i14 = HEAP32[i7 >> 2] | 0;
+         i13 = i14 + 28 | 0;
+         i12 = HEAP32[i13 >> 2] | 0;
+         i17 = HEAP32[i12 + 20 >> 2] | 0;
+         i16 = i14 + 16 | 0;
+         i18 = HEAP32[i16 >> 2] | 0;
+         i17 = i17 >>> 0 > i18 >>> 0 ? i18 : i17;
+         if ((i17 | 0) != 0 ? (i15 = i14 + 12 | 0, _memcpy(HEAP32[i15 >> 2] | 0, HEAP32[i12 + 16 >> 2] | 0, i17 | 0) | 0, HEAP32[i15 >> 2] = (HEAP32[i15 >> 2] | 0) + i17, i15 = (HEAP32[i13 >> 2] | 0) + 16 | 0, HEAP32[i15 >> 2] = (HEAP32[i15 >> 2] | 0) + i17, i15 = i14 + 20 | 0, HEAP32[i15 >> 2] = (HEAP32[i15 >> 2] | 0) + i17, HEAP32[i16 >> 2] = (HEAP32[i16 >> 2] | 0) - i17, i15 = HEAP32[i13 >> 2] | 0, i36 = i15 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i17, (i37 | 0) == (i17 | 0)) : 0) {
+          HEAP32[i15 + 16 >> 2] = HEAP32[i15 + 8 >> 2];
+         }
+         if ((HEAP32[(HEAP32[i7 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+          i12 = i9 ? 2 : 0;
+          i17 = 183;
+          break;
+         } else {
+          i12 = i9 ? 3 : 1;
+          i17 = 183;
+          break;
+         }
+        }
+       } else if ((i18 | 0) == 3) {
+        i27 = i7 + 116 | 0;
+        i26 = (i10 | 0) == 0;
+        i22 = i7 + 96 | 0;
+        i15 = i7 + 108 | 0;
+        i20 = i7 + 5792 | 0;
+        i24 = i7 + 5796 | 0;
+        i23 = i7 + 5784 | 0;
+        i21 = i7 + (HEAPU8[296] << 2) + 2440 | 0;
+        i25 = i7 + 5788 | 0;
+        i18 = i7 + 56 | 0;
+        i16 = i7 + 92 | 0;
+        while (1) {
+         i29 = HEAP32[i27 >> 2] | 0;
+         if (i29 >>> 0 < 258) {
+          _fill_window(i7);
+          i29 = HEAP32[i27 >> 2] | 0;
+          if (i29 >>> 0 < 258 & i26) {
+           break L185;
+          }
+          if ((i29 | 0) == 0) {
+           break;
+          }
+          HEAP32[i22 >> 2] = 0;
+          if (i29 >>> 0 > 2) {
+           i17 = 151;
+          } else {
+           i28 = HEAP32[i15 >> 2] | 0;
+           i17 = 166;
+          }
+         } else {
+          HEAP32[i22 >> 2] = 0;
+          i17 = 151;
+         }
+         if ((i17 | 0) == 151) {
+          i17 = 0;
+          i28 = HEAP32[i15 >> 2] | 0;
+          if ((i28 | 0) != 0) {
+           i31 = HEAP32[i18 >> 2] | 0;
+           i30 = HEAP8[i31 + (i28 + -1) | 0] | 0;
+           if ((i30 << 24 >> 24 == (HEAP8[i31 + i28 | 0] | 0) ? i30 << 24 >> 24 == (HEAP8[i31 + (i28 + 1) | 0] | 0) : 0) ? (i14 = i31 + (i28 + 2) | 0, i30 << 24 >> 24 == (HEAP8[i14] | 0)) : 0) {
+            i31 = i31 + (i28 + 258) | 0;
+            i32 = i14;
+            do {
+             i33 = i32 + 1 | 0;
+             if (!(i30 << 24 >> 24 == (HEAP8[i33] | 0))) {
+              i32 = i33;
+              break;
+             }
+             i33 = i32 + 2 | 0;
+             if (!(i30 << 24 >> 24 == (HEAP8[i33] | 0))) {
+              i32 = i33;
+              break;
+             }
+             i33 = i32 + 3 | 0;
+             if (!(i30 << 24 >> 24 == (HEAP8[i33] | 0))) {
+              i32 = i33;
+              break;
+             }
+             i33 = i32 + 4 | 0;
+             if (!(i30 << 24 >> 24 == (HEAP8[i33] | 0))) {
+              i32 = i33;
+              break;
+             }
+             i33 = i32 + 5 | 0;
+             if (!(i30 << 24 >> 24 == (HEAP8[i33] | 0))) {
+              i32 = i33;
+              break;
+             }
+             i33 = i32 + 6 | 0;
+             if (!(i30 << 24 >> 24 == (HEAP8[i33] | 0))) {
+              i32 = i33;
+              break;
+             }
+             i33 = i32 + 7 | 0;
+             if (!(i30 << 24 >> 24 == (HEAP8[i33] | 0))) {
+              i32 = i33;
+              break;
+             }
+             i32 = i32 + 8 | 0;
+            } while (i30 << 24 >> 24 == (HEAP8[i32] | 0) & i32 >>> 0 < i31 >>> 0);
+            i30 = i32 - i31 + 258 | 0;
+            i29 = i30 >>> 0 > i29 >>> 0 ? i29 : i30;
+            HEAP32[i22 >> 2] = i29;
+            if (i29 >>> 0 > 2) {
+             i29 = i29 + 253 | 0;
+             i28 = HEAP32[i20 >> 2] | 0;
+             HEAP16[(HEAP32[i24 >> 2] | 0) + (i28 << 1) >> 1] = 1;
+             HEAP32[i20 >> 2] = i28 + 1;
+             HEAP8[(HEAP32[i23 >> 2] | 0) + i28 | 0] = i29;
+             i29 = i7 + ((HEAPU8[808 + (i29 & 255) | 0] | 256) + 1 << 2) + 148 | 0;
+             HEAP16[i29 >> 1] = (HEAP16[i29 >> 1] | 0) + 1 << 16 >> 16;
+             HEAP16[i21 >> 1] = (HEAP16[i21 >> 1] | 0) + 1 << 16 >> 16;
+             i29 = (HEAP32[i20 >> 2] | 0) == ((HEAP32[i25 >> 2] | 0) + -1 | 0) | 0;
+             i28 = HEAP32[i22 >> 2] | 0;
+             HEAP32[i27 >> 2] = (HEAP32[i27 >> 2] | 0) - i28;
+             i28 = (HEAP32[i15 >> 2] | 0) + i28 | 0;
+             HEAP32[i15 >> 2] = i28;
+             HEAP32[i22 >> 2] = 0;
+            } else {
+             i17 = 166;
+            }
+           } else {
+            i17 = 166;
+           }
+          } else {
+           i28 = 0;
+           i17 = 166;
+          }
+         }
+         if ((i17 | 0) == 166) {
+          i17 = 0;
+          i29 = HEAP8[(HEAP32[i18 >> 2] | 0) + i28 | 0] | 0;
+          i28 = HEAP32[i20 >> 2] | 0;
+          HEAP16[(HEAP32[i24 >> 2] | 0) + (i28 << 1) >> 1] = 0;
+          HEAP32[i20 >> 2] = i28 + 1;
+          HEAP8[(HEAP32[i23 >> 2] | 0) + i28 | 0] = i29;
+          i29 = i7 + ((i29 & 255) << 2) + 148 | 0;
+          HEAP16[i29 >> 1] = (HEAP16[i29 >> 1] | 0) + 1 << 16 >> 16;
+          i29 = (HEAP32[i20 >> 2] | 0) == ((HEAP32[i25 >> 2] | 0) + -1 | 0) | 0;
+          HEAP32[i27 >> 2] = (HEAP32[i27 >> 2] | 0) + -1;
+          i28 = (HEAP32[i15 >> 2] | 0) + 1 | 0;
+          HEAP32[i15 >> 2] = i28;
+         }
+         if ((i29 | 0) == 0) {
+          continue;
+         }
+         i29 = HEAP32[i16 >> 2] | 0;
+         if ((i29 | 0) > -1) {
+          i30 = (HEAP32[i18 >> 2] | 0) + i29 | 0;
+         } else {
+          i30 = 0;
+         }
+         __tr_flush_block(i7, i30, i28 - i29 | 0, 0);
+         HEAP32[i16 >> 2] = HEAP32[i15 >> 2];
+         i30 = HEAP32[i7 >> 2] | 0;
+         i28 = i30 + 28 | 0;
+         i29 = HEAP32[i28 >> 2] | 0;
+         i33 = HEAP32[i29 + 20 >> 2] | 0;
+         i31 = i30 + 16 | 0;
+         i32 = HEAP32[i31 >> 2] | 0;
+         i32 = i33 >>> 0 > i32 >>> 0 ? i32 : i33;
+         if ((i32 | 0) != 0 ? (i13 = i30 + 12 | 0, _memcpy(HEAP32[i13 >> 2] | 0, HEAP32[i29 + 16 >> 2] | 0, i32 | 0) | 0, HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + i32, i13 = (HEAP32[i28 >> 2] | 0) + 16 | 0, HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + i32, i13 = i30 + 20 | 0, HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + i32, HEAP32[i31 >> 2] = (HEAP32[i31 >> 2] | 0) - i32, i13 = HEAP32[i28 >> 2] | 0, i36 = i13 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i32, (i37 | 0) == (i32 | 0)) : 0) {
+          HEAP32[i13 + 16 >> 2] = HEAP32[i13 + 8 >> 2];
+         }
+         if ((HEAP32[(HEAP32[i7 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+          break L185;
+         }
+        }
+        i13 = HEAP32[i16 >> 2] | 0;
+        if ((i13 | 0) > -1) {
+         i14 = (HEAP32[i18 >> 2] | 0) + i13 | 0;
+        } else {
+         i14 = 0;
+        }
+        __tr_flush_block(i7, i14, (HEAP32[i15 >> 2] | 0) - i13 | 0, i9 & 1);
+        HEAP32[i16 >> 2] = HEAP32[i15 >> 2];
+        i14 = HEAP32[i7 >> 2] | 0;
+        i16 = i14 + 28 | 0;
+        i15 = HEAP32[i16 >> 2] | 0;
+        i18 = HEAP32[i15 + 20 >> 2] | 0;
+        i13 = i14 + 16 | 0;
+        i17 = HEAP32[i13 >> 2] | 0;
+        i17 = i18 >>> 0 > i17 >>> 0 ? i17 : i18;
+        if ((i17 | 0) != 0 ? (i12 = i14 + 12 | 0, _memcpy(HEAP32[i12 >> 2] | 0, HEAP32[i15 + 16 >> 2] | 0, i17 | 0) | 0, HEAP32[i12 >> 2] = (HEAP32[i12 >> 2] | 0) + i17, i12 = (HEAP32[i16 >> 2] | 0) + 16 | 0, HEAP32[i12 >> 2] = (HEAP32[i12 >> 2] | 0) + i17, i12 = i14 + 20 | 0, HEAP32[i12 >> 2] = (HEAP32[i12 >> 2] | 0) + i17, HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) - i17, i12 = HEAP32[i16 >> 2] | 0, i36 = i12 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i17, (i37 | 0) == (i17 | 0)) : 0) {
+         HEAP32[i12 + 16 >> 2] = HEAP32[i12 + 8 >> 2];
+        }
+        if ((HEAP32[(HEAP32[i7 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+         i12 = i9 ? 2 : 0;
+         i17 = 183;
+         break;
+        } else {
+         i12 = i9 ? 3 : 1;
+         i17 = 183;
+         break;
+        }
+       } else {
+        i12 = FUNCTION_TABLE_iii[HEAP32[184 + ((HEAP32[i7 + 132 >> 2] | 0) * 12 | 0) >> 2] & 3](i7, i10) | 0;
+        i17 = 183;
+       }
+      } while (0);
+      if ((i17 | 0) == 183) {
+       if ((i12 & -2 | 0) == 2) {
+        HEAP32[i11 >> 2] = 666;
+       }
+       if ((i12 & -3 | 0) != 0) {
+        if ((i12 | 0) != 1) {
+         break;
+        }
+        if ((i10 | 0) == 1) {
+         __tr_align(i7);
+        } else if (((i10 | 0) != 5 ? (__tr_stored_block(i7, 0, 0, 0), (i10 | 0) == 3) : 0) ? (i37 = HEAP32[i7 + 76 >> 2] | 0, i36 = HEAP32[i7 + 68 >> 2] | 0, HEAP16[i36 + (i37 + -1 << 1) >> 1] = 0, _memset(i36 | 0, 0, (i37 << 1) + -2 | 0) | 0, (HEAP32[i7 + 116 >> 2] | 0) == 0) : 0) {
+         HEAP32[i7 + 108 >> 2] = 0;
+         HEAP32[i7 + 92 >> 2] = 0;
+        }
+        i11 = HEAP32[i5 >> 2] | 0;
+        i12 = HEAP32[i11 + 20 >> 2] | 0;
+        i10 = HEAP32[i3 >> 2] | 0;
+        i12 = i12 >>> 0 > i10 >>> 0 ? i10 : i12;
+        if ((i12 | 0) != 0) {
+         _memcpy(HEAP32[i4 >> 2] | 0, HEAP32[i11 + 16 >> 2] | 0, i12 | 0) | 0;
+         HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + i12;
+         i10 = (HEAP32[i5 >> 2] | 0) + 16 | 0;
+         HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + i12;
+         i10 = i2 + 20 | 0;
+         HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + i12;
+         HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) - i12;
+         i10 = HEAP32[i5 >> 2] | 0;
+         i36 = i10 + 20 | 0;
+         i37 = HEAP32[i36 >> 2] | 0;
+         HEAP32[i36 >> 2] = i37 - i12;
+         if ((i37 | 0) == (i12 | 0)) {
+          HEAP32[i10 + 16 >> 2] = HEAP32[i10 + 8 >> 2];
+         }
+         i10 = HEAP32[i3 >> 2] | 0;
+        }
+        if ((i10 | 0) != 0) {
+         break;
+        }
+        HEAP32[i8 >> 2] = -1;
+        i37 = 0;
+        STACKTOP = i1;
+        return i37 | 0;
+       }
+      }
+      if ((HEAP32[i3 >> 2] | 0) != 0) {
+       i37 = 0;
+       STACKTOP = i1;
+       return i37 | 0;
+      }
+      HEAP32[i8 >> 2] = -1;
+      i37 = 0;
+      STACKTOP = i1;
+      return i37 | 0;
+     }
+    } while (0);
+    if (!i9) {
+     i37 = 0;
+     STACKTOP = i1;
+     return i37 | 0;
+    }
+    i8 = i7 + 24 | 0;
+    i10 = HEAP32[i8 >> 2] | 0;
+    if ((i10 | 0) < 1) {
+     i37 = 1;
+     STACKTOP = i1;
+     return i37 | 0;
+    }
+    i11 = i2 + 48 | 0;
+    i9 = HEAP32[i11 >> 2] | 0;
+    if ((i10 | 0) == 2) {
+     i34 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i34 + 1;
+     i36 = i7 + 8 | 0;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i34 | 0] = i9;
+     i34 = (HEAP32[i11 >> 2] | 0) >>> 8 & 255;
+     i35 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i35 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i35 | 0] = i34;
+     i35 = (HEAP32[i11 >> 2] | 0) >>> 16 & 255;
+     i34 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i34 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i34 | 0] = i35;
+     i34 = (HEAP32[i11 >> 2] | 0) >>> 24 & 255;
+     i35 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i35 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i35 | 0] = i34;
+     i35 = i2 + 8 | 0;
+     i34 = HEAP32[i35 >> 2] & 255;
+     i37 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i37 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i37 | 0] = i34;
+     i37 = (HEAP32[i35 >> 2] | 0) >>> 8 & 255;
+     i34 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i34 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i34 | 0] = i37;
+     i34 = (HEAP32[i35 >> 2] | 0) >>> 16 & 255;
+     i37 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i37 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i37 | 0] = i34;
+     i35 = (HEAP32[i35 >> 2] | 0) >>> 24 & 255;
+     i37 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i37 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i37 | 0] = i35;
+    } else {
+     i35 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i35 + 1;
+     i36 = i7 + 8 | 0;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i35 | 0] = i9 >>> 24;
+     i35 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i35 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i35 | 0] = i9 >>> 16;
+     i35 = HEAP32[i11 >> 2] | 0;
+     i37 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i37 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i37 | 0] = i35 >>> 8;
+     i37 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i37 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i37 | 0] = i35;
+    }
+    i7 = HEAP32[i5 >> 2] | 0;
+    i10 = HEAP32[i7 + 20 >> 2] | 0;
+    i9 = HEAP32[i3 >> 2] | 0;
+    i9 = i10 >>> 0 > i9 >>> 0 ? i9 : i10;
+    if ((i9 | 0) != 0 ? (_memcpy(HEAP32[i4 >> 2] | 0, HEAP32[i7 + 16 >> 2] | 0, i9 | 0) | 0, HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + i9, i6 = (HEAP32[i5 >> 2] | 0) + 16 | 0, HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i9, i6 = i2 + 20 | 0, HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i9, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) - i9, i6 = HEAP32[i5 >> 2] | 0, i36 = i6 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i9, (i37 | 0) == (i9 | 0)) : 0) {
+     HEAP32[i6 + 16 >> 2] = HEAP32[i6 + 8 >> 2];
+    }
+    i2 = HEAP32[i8 >> 2] | 0;
+    if ((i2 | 0) > 0) {
+     HEAP32[i8 >> 2] = 0 - i2;
+    }
+    i37 = (HEAP32[i19 >> 2] | 0) == 0 | 0;
+    STACKTOP = i1;
+    return i37 | 0;
+   }
+  }
+ } while (0);
+ HEAP32[i2 + 24 >> 2] = HEAP32[3168 >> 2];
+ i37 = -2;
+ STACKTOP = i1;
+ return i37 | 0;
+}
+function _free(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i1 = STACKTOP;
+ if ((i7 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i15 = i7 + -8 | 0;
+ i16 = HEAP32[14488 >> 2] | 0;
+ if (i15 >>> 0 < i16 >>> 0) {
+  _abort();
+ }
+ i13 = HEAP32[i7 + -4 >> 2] | 0;
+ i12 = i13 & 3;
+ if ((i12 | 0) == 1) {
+  _abort();
+ }
+ i8 = i13 & -8;
+ i6 = i7 + (i8 + -8) | 0;
+ do {
+  if ((i13 & 1 | 0) == 0) {
+   i19 = HEAP32[i15 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   i15 = -8 - i19 | 0;
+   i13 = i7 + i15 | 0;
+   i12 = i19 + i8 | 0;
+   if (i13 >>> 0 < i16 >>> 0) {
+    _abort();
+   }
+   if ((i13 | 0) == (HEAP32[14492 >> 2] | 0)) {
+    i2 = i7 + (i8 + -4) | 0;
+    if ((HEAP32[i2 >> 2] & 3 | 0) != 3) {
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    HEAP32[14480 >> 2] = i12;
+    HEAP32[i2 >> 2] = HEAP32[i2 >> 2] & -2;
+    HEAP32[i7 + (i15 + 4) >> 2] = i12 | 1;
+    HEAP32[i6 >> 2] = i12;
+    STACKTOP = i1;
+    return;
+   }
+   i18 = i19 >>> 3;
+   if (i19 >>> 0 < 256) {
+    i2 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+    i11 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+    i14 = 14512 + (i18 << 1 << 2) | 0;
+    if ((i2 | 0) != (i14 | 0)) {
+     if (i2 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i2 + 12 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+    }
+    if ((i11 | 0) == (i2 | 0)) {
+     HEAP32[3618] = HEAP32[3618] & ~(1 << i18);
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    if ((i11 | 0) != (i14 | 0)) {
+     if (i11 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i14 = i11 + 8 | 0;
+     if ((HEAP32[i14 >> 2] | 0) == (i13 | 0)) {
+      i17 = i14;
+     } else {
+      _abort();
+     }
+    } else {
+     i17 = i11 + 8 | 0;
+    }
+    HEAP32[i2 + 12 >> 2] = i11;
+    HEAP32[i17 >> 2] = i2;
+    i2 = i13;
+    i11 = i12;
+    break;
+   }
+   i17 = HEAP32[i7 + (i15 + 24) >> 2] | 0;
+   i18 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+   do {
+    if ((i18 | 0) == (i13 | 0)) {
+     i19 = i7 + (i15 + 20) | 0;
+     i18 = HEAP32[i19 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      i19 = i7 + (i15 + 16) | 0;
+      i18 = HEAP32[i19 >> 2] | 0;
+      if ((i18 | 0) == 0) {
+       i14 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i21 = i18 + 20 | 0;
+      i20 = HEAP32[i21 >> 2] | 0;
+      if ((i20 | 0) != 0) {
+       i18 = i20;
+       i19 = i21;
+       continue;
+      }
+      i20 = i18 + 16 | 0;
+      i21 = HEAP32[i20 >> 2] | 0;
+      if ((i21 | 0) == 0) {
+       break;
+      } else {
+       i18 = i21;
+       i19 = i20;
+      }
+     }
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i19 >> 2] = 0;
+      i14 = i18;
+      break;
+     }
+    } else {
+     i19 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i16 = i19 + 12 | 0;
+     if ((HEAP32[i16 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+     i20 = i18 + 8 | 0;
+     if ((HEAP32[i20 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i18;
+      HEAP32[i20 >> 2] = i19;
+      i14 = i18;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i17 | 0) != 0) {
+    i18 = HEAP32[i7 + (i15 + 28) >> 2] | 0;
+    i16 = 14776 + (i18 << 2) | 0;
+    if ((i13 | 0) == (HEAP32[i16 >> 2] | 0)) {
+     HEAP32[i16 >> 2] = i14;
+     if ((i14 | 0) == 0) {
+      HEAP32[14476 >> 2] = HEAP32[14476 >> 2] & ~(1 << i18);
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     if (i17 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i16 = i17 + 16 | 0;
+     if ((HEAP32[i16 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i14;
+     } else {
+      HEAP32[i17 + 20 >> 2] = i14;
+     }
+     if ((i14 | 0) == 0) {
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    }
+    if (i14 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i14 + 24 >> 2] = i17;
+    i16 = HEAP32[i7 + (i15 + 16) >> 2] | 0;
+    do {
+     if ((i16 | 0) != 0) {
+      if (i16 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i14 + 16 >> 2] = i16;
+       HEAP32[i16 + 24 >> 2] = i14;
+       break;
+      }
+     }
+    } while (0);
+    i15 = HEAP32[i7 + (i15 + 20) >> 2] | 0;
+    if ((i15 | 0) != 0) {
+     if (i15 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i14 + 20 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i14;
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     i2 = i13;
+     i11 = i12;
+    }
+   } else {
+    i2 = i13;
+    i11 = i12;
+   }
+  } else {
+   i2 = i15;
+   i11 = i8;
+  }
+ } while (0);
+ if (!(i2 >>> 0 < i6 >>> 0)) {
+  _abort();
+ }
+ i12 = i7 + (i8 + -4) | 0;
+ i13 = HEAP32[i12 >> 2] | 0;
+ if ((i13 & 1 | 0) == 0) {
+  _abort();
+ }
+ if ((i13 & 2 | 0) == 0) {
+  if ((i6 | 0) == (HEAP32[14496 >> 2] | 0)) {
+   i21 = (HEAP32[14484 >> 2] | 0) + i11 | 0;
+   HEAP32[14484 >> 2] = i21;
+   HEAP32[14496 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   if ((i2 | 0) != (HEAP32[14492 >> 2] | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[14492 >> 2] = 0;
+   HEAP32[14480 >> 2] = 0;
+   STACKTOP = i1;
+   return;
+  }
+  if ((i6 | 0) == (HEAP32[14492 >> 2] | 0)) {
+   i21 = (HEAP32[14480 >> 2] | 0) + i11 | 0;
+   HEAP32[14480 >> 2] = i21;
+   HEAP32[14492 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   HEAP32[i2 + i21 >> 2] = i21;
+   STACKTOP = i1;
+   return;
+  }
+  i11 = (i13 & -8) + i11 | 0;
+  i12 = i13 >>> 3;
+  do {
+   if (!(i13 >>> 0 < 256)) {
+    i10 = HEAP32[i7 + (i8 + 16) >> 2] | 0;
+    i15 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    do {
+     if ((i15 | 0) == (i6 | 0)) {
+      i13 = i7 + (i8 + 12) | 0;
+      i12 = HEAP32[i13 >> 2] | 0;
+      if ((i12 | 0) == 0) {
+       i13 = i7 + (i8 + 8) | 0;
+       i12 = HEAP32[i13 >> 2] | 0;
+       if ((i12 | 0) == 0) {
+        i9 = 0;
+        break;
+       }
+      }
+      while (1) {
+       i14 = i12 + 20 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) != 0) {
+        i12 = i15;
+        i13 = i14;
+        continue;
+       }
+       i14 = i12 + 16 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) == 0) {
+        break;
+       } else {
+        i12 = i15;
+        i13 = i14;
+       }
+      }
+      if (i13 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 >> 2] = 0;
+       i9 = i12;
+       break;
+      }
+     } else {
+      i13 = HEAP32[i7 + i8 >> 2] | 0;
+      if (i13 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i14 = i13 + 12 | 0;
+      if ((HEAP32[i14 >> 2] | 0) != (i6 | 0)) {
+       _abort();
+      }
+      i12 = i15 + 8 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i14 >> 2] = i15;
+       HEAP32[i12 >> 2] = i13;
+       i9 = i15;
+       break;
+      } else {
+       _abort();
+      }
+     }
+    } while (0);
+    if ((i10 | 0) != 0) {
+     i12 = HEAP32[i7 + (i8 + 20) >> 2] | 0;
+     i13 = 14776 + (i12 << 2) | 0;
+     if ((i6 | 0) == (HEAP32[i13 >> 2] | 0)) {
+      HEAP32[i13 >> 2] = i9;
+      if ((i9 | 0) == 0) {
+       HEAP32[14476 >> 2] = HEAP32[14476 >> 2] & ~(1 << i12);
+       break;
+      }
+     } else {
+      if (i10 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i12 = i10 + 16 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i12 >> 2] = i9;
+      } else {
+       HEAP32[i10 + 20 >> 2] = i9;
+      }
+      if ((i9 | 0) == 0) {
+       break;
+      }
+     }
+     if (i9 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     HEAP32[i9 + 24 >> 2] = i10;
+     i6 = HEAP32[i7 + (i8 + 8) >> 2] | 0;
+     do {
+      if ((i6 | 0) != 0) {
+       if (i6 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i9 + 16 >> 2] = i6;
+        HEAP32[i6 + 24 >> 2] = i9;
+        break;
+       }
+      }
+     } while (0);
+     i6 = HEAP32[i7 + (i8 + 12) >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      if (i6 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i9 + 20 >> 2] = i6;
+       HEAP32[i6 + 24 >> 2] = i9;
+       break;
+      }
+     }
+    }
+   } else {
+    i9 = HEAP32[i7 + i8 >> 2] | 0;
+    i7 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    i8 = 14512 + (i12 << 1 << 2) | 0;
+    if ((i9 | 0) != (i8 | 0)) {
+     if (i9 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i9 + 12 >> 2] | 0) != (i6 | 0)) {
+      _abort();
+     }
+    }
+    if ((i7 | 0) == (i9 | 0)) {
+     HEAP32[3618] = HEAP32[3618] & ~(1 << i12);
+     break;
+    }
+    if ((i7 | 0) != (i8 | 0)) {
+     if (i7 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i8 = i7 + 8 | 0;
+     if ((HEAP32[i8 >> 2] | 0) == (i6 | 0)) {
+      i10 = i8;
+     } else {
+      _abort();
+     }
+    } else {
+     i10 = i7 + 8 | 0;
+    }
+    HEAP32[i9 + 12 >> 2] = i7;
+    HEAP32[i10 >> 2] = i9;
+   }
+  } while (0);
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+  if ((i2 | 0) == (HEAP32[14492 >> 2] | 0)) {
+   HEAP32[14480 >> 2] = i11;
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  HEAP32[i12 >> 2] = i13 & -2;
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+ }
+ i6 = i11 >>> 3;
+ if (i11 >>> 0 < 256) {
+  i7 = i6 << 1;
+  i3 = 14512 + (i7 << 2) | 0;
+  i8 = HEAP32[3618] | 0;
+  i6 = 1 << i6;
+  if ((i8 & i6 | 0) != 0) {
+   i6 = 14512 + (i7 + 2 << 2) | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if (i7 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+    _abort();
+   } else {
+    i4 = i6;
+    i5 = i7;
+   }
+  } else {
+   HEAP32[3618] = i8 | i6;
+   i4 = 14512 + (i7 + 2 << 2) | 0;
+   i5 = i3;
+  }
+  HEAP32[i4 >> 2] = i2;
+  HEAP32[i5 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i5;
+  HEAP32[i2 + 12 >> 2] = i3;
+  STACKTOP = i1;
+  return;
+ }
+ i4 = i11 >>> 8;
+ if ((i4 | 0) != 0) {
+  if (i11 >>> 0 > 16777215) {
+   i4 = 31;
+  } else {
+   i20 = (i4 + 1048320 | 0) >>> 16 & 8;
+   i21 = i4 << i20;
+   i19 = (i21 + 520192 | 0) >>> 16 & 4;
+   i21 = i21 << i19;
+   i4 = (i21 + 245760 | 0) >>> 16 & 2;
+   i4 = 14 - (i19 | i20 | i4) + (i21 << i4 >>> 15) | 0;
+   i4 = i11 >>> (i4 + 7 | 0) & 1 | i4 << 1;
+  }
+ } else {
+  i4 = 0;
+ }
+ i5 = 14776 + (i4 << 2) | 0;
+ HEAP32[i2 + 28 >> 2] = i4;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ i7 = HEAP32[14476 >> 2] | 0;
+ i6 = 1 << i4;
+ L199 : do {
+  if ((i7 & i6 | 0) != 0) {
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((i4 | 0) == 31) {
+    i4 = 0;
+   } else {
+    i4 = 25 - (i4 >>> 1) | 0;
+   }
+   L204 : do {
+    if ((HEAP32[i5 + 4 >> 2] & -8 | 0) != (i11 | 0)) {
+     i4 = i11 << i4;
+     i7 = i5;
+     while (1) {
+      i6 = i7 + (i4 >>> 31 << 2) + 16 | 0;
+      i5 = HEAP32[i6 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       break;
+      }
+      if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i11 | 0)) {
+       i3 = i5;
+       break L204;
+      } else {
+       i4 = i4 << 1;
+       i7 = i5;
+      }
+     }
+     if (i6 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i6 >> 2] = i2;
+      HEAP32[i2 + 24 >> 2] = i7;
+      HEAP32[i2 + 12 >> 2] = i2;
+      HEAP32[i2 + 8 >> 2] = i2;
+      break L199;
+     }
+    } else {
+     i3 = i5;
+    }
+   } while (0);
+   i5 = i3 + 8 | 0;
+   i4 = HEAP32[i5 >> 2] | 0;
+   i6 = HEAP32[14488 >> 2] | 0;
+   if (i3 >>> 0 < i6 >>> 0) {
+    _abort();
+   }
+   if (i4 >>> 0 < i6 >>> 0) {
+    _abort();
+   } else {
+    HEAP32[i4 + 12 >> 2] = i2;
+    HEAP32[i5 >> 2] = i2;
+    HEAP32[i2 + 8 >> 2] = i4;
+    HEAP32[i2 + 12 >> 2] = i3;
+    HEAP32[i2 + 24 >> 2] = 0;
+    break;
+   }
+  } else {
+   HEAP32[14476 >> 2] = i7 | i6;
+   HEAP32[i5 >> 2] = i2;
+   HEAP32[i2 + 24 >> 2] = i5;
+   HEAP32[i2 + 12 >> 2] = i2;
+   HEAP32[i2 + 8 >> 2] = i2;
+  }
+ } while (0);
+ i21 = (HEAP32[14504 >> 2] | 0) + -1 | 0;
+ HEAP32[14504 >> 2] = i21;
+ if ((i21 | 0) == 0) {
+  i2 = 14928 | 0;
+ } else {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i2 = HEAP32[i2 >> 2] | 0;
+  if ((i2 | 0) == 0) {
+   break;
+  } else {
+   i2 = i2 + 8 | 0;
+  }
+ }
+ HEAP32[14504 >> 2] = -1;
+ STACKTOP = i1;
+ return;
+}
+function _build_tree(i4, i9) {
+ i4 = i4 | 0;
+ i9 = i9 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i1 = i2;
+ i3 = HEAP32[i9 >> 2] | 0;
+ i7 = i9 + 8 | 0;
+ i11 = HEAP32[i7 >> 2] | 0;
+ i12 = HEAP32[i11 >> 2] | 0;
+ i11 = HEAP32[i11 + 12 >> 2] | 0;
+ i8 = i4 + 5200 | 0;
+ HEAP32[i8 >> 2] = 0;
+ i6 = i4 + 5204 | 0;
+ HEAP32[i6 >> 2] = 573;
+ if ((i11 | 0) > 0) {
+  i5 = -1;
+  i13 = 0;
+  do {
+   if ((HEAP16[i3 + (i13 << 2) >> 1] | 0) == 0) {
+    HEAP16[i3 + (i13 << 2) + 2 >> 1] = 0;
+   } else {
+    i5 = (HEAP32[i8 >> 2] | 0) + 1 | 0;
+    HEAP32[i8 >> 2] = i5;
+    HEAP32[i4 + (i5 << 2) + 2908 >> 2] = i13;
+    HEAP8[i4 + i13 + 5208 | 0] = 0;
+    i5 = i13;
+   }
+   i13 = i13 + 1 | 0;
+  } while ((i13 | 0) != (i11 | 0));
+  i14 = HEAP32[i8 >> 2] | 0;
+  if ((i14 | 0) < 2) {
+   i10 = 3;
+  }
+ } else {
+  i14 = 0;
+  i5 = -1;
+  i10 = 3;
+ }
+ if ((i10 | 0) == 3) {
+  i10 = i4 + 5800 | 0;
+  i13 = i4 + 5804 | 0;
+  if ((i12 | 0) == 0) {
+   do {
+    i12 = (i5 | 0) < 2;
+    i13 = i5 + 1 | 0;
+    i5 = i12 ? i13 : i5;
+    i23 = i12 ? i13 : 0;
+    i14 = i14 + 1 | 0;
+    HEAP32[i8 >> 2] = i14;
+    HEAP32[i4 + (i14 << 2) + 2908 >> 2] = i23;
+    HEAP16[i3 + (i23 << 2) >> 1] = 1;
+    HEAP8[i4 + i23 + 5208 | 0] = 0;
+    HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + -1;
+    i14 = HEAP32[i8 >> 2] | 0;
+   } while ((i14 | 0) < 2);
+  } else {
+   do {
+    i15 = (i5 | 0) < 2;
+    i16 = i5 + 1 | 0;
+    i5 = i15 ? i16 : i5;
+    i23 = i15 ? i16 : 0;
+    i14 = i14 + 1 | 0;
+    HEAP32[i8 >> 2] = i14;
+    HEAP32[i4 + (i14 << 2) + 2908 >> 2] = i23;
+    HEAP16[i3 + (i23 << 2) >> 1] = 1;
+    HEAP8[i4 + i23 + 5208 | 0] = 0;
+    HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + -1;
+    HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) - (HEAPU16[i12 + (i23 << 2) + 2 >> 1] | 0);
+    i14 = HEAP32[i8 >> 2] | 0;
+   } while ((i14 | 0) < 2);
+  }
+ }
+ i10 = i9 + 4 | 0;
+ HEAP32[i10 >> 2] = i5;
+ i12 = HEAP32[i8 >> 2] | 0;
+ if ((i12 | 0) > 1) {
+  i18 = i12;
+  i13 = (i12 | 0) / 2 | 0;
+  do {
+   i12 = HEAP32[i4 + (i13 << 2) + 2908 >> 2] | 0;
+   i14 = i4 + i12 + 5208 | 0;
+   i17 = i13 << 1;
+   L21 : do {
+    if ((i17 | 0) > (i18 | 0)) {
+     i15 = i13;
+    } else {
+     i16 = i3 + (i12 << 2) | 0;
+     i15 = i13;
+     while (1) {
+      do {
+       if ((i17 | 0) < (i18 | 0)) {
+        i18 = i17 | 1;
+        i19 = HEAP32[i4 + (i18 << 2) + 2908 >> 2] | 0;
+        i22 = HEAP16[i3 + (i19 << 2) >> 1] | 0;
+        i20 = HEAP32[i4 + (i17 << 2) + 2908 >> 2] | 0;
+        i21 = HEAP16[i3 + (i20 << 2) >> 1] | 0;
+        if (!((i22 & 65535) < (i21 & 65535))) {
+         if (!(i22 << 16 >> 16 == i21 << 16 >> 16)) {
+          break;
+         }
+         if ((HEAPU8[i4 + i19 + 5208 | 0] | 0) > (HEAPU8[i4 + i20 + 5208 | 0] | 0)) {
+          break;
+         }
+        }
+        i17 = i18;
+       }
+      } while (0);
+      i19 = HEAP16[i16 >> 1] | 0;
+      i18 = HEAP32[i4 + (i17 << 2) + 2908 >> 2] | 0;
+      i20 = HEAP16[i3 + (i18 << 2) >> 1] | 0;
+      if ((i19 & 65535) < (i20 & 65535)) {
+       break L21;
+      }
+      if (i19 << 16 >> 16 == i20 << 16 >> 16 ? (HEAPU8[i14] | 0) <= (HEAPU8[i4 + i18 + 5208 | 0] | 0) : 0) {
+       break L21;
+      }
+      HEAP32[i4 + (i15 << 2) + 2908 >> 2] = i18;
+      i19 = i17 << 1;
+      i18 = HEAP32[i8 >> 2] | 0;
+      if ((i19 | 0) > (i18 | 0)) {
+       i15 = i17;
+       break;
+      } else {
+       i15 = i17;
+       i17 = i19;
+      }
+     }
+    }
+   } while (0);
+   HEAP32[i4 + (i15 << 2) + 2908 >> 2] = i12;
+   i13 = i13 + -1 | 0;
+   i18 = HEAP32[i8 >> 2] | 0;
+  } while ((i13 | 0) > 0);
+ } else {
+  i18 = i12;
+ }
+ i12 = i4 + 2912 | 0;
+ while (1) {
+  i13 = HEAP32[i12 >> 2] | 0;
+  i20 = i18 + -1 | 0;
+  HEAP32[i8 >> 2] = i20;
+  i14 = HEAP32[i4 + (i18 << 2) + 2908 >> 2] | 0;
+  HEAP32[i12 >> 2] = i14;
+  i15 = i4 + i14 + 5208 | 0;
+  L40 : do {
+   if ((i18 | 0) < 3) {
+    i17 = 1;
+   } else {
+    i16 = i3 + (i14 << 2) | 0;
+    i17 = 1;
+    i18 = 2;
+    while (1) {
+     do {
+      if ((i18 | 0) < (i20 | 0)) {
+       i22 = i18 | 1;
+       i21 = HEAP32[i4 + (i22 << 2) + 2908 >> 2] | 0;
+       i23 = HEAP16[i3 + (i21 << 2) >> 1] | 0;
+       i20 = HEAP32[i4 + (i18 << 2) + 2908 >> 2] | 0;
+       i19 = HEAP16[i3 + (i20 << 2) >> 1] | 0;
+       if (!((i23 & 65535) < (i19 & 65535))) {
+        if (!(i23 << 16 >> 16 == i19 << 16 >> 16)) {
+         break;
+        }
+        if ((HEAPU8[i4 + i21 + 5208 | 0] | 0) > (HEAPU8[i4 + i20 + 5208 | 0] | 0)) {
+         break;
+        }
+       }
+       i18 = i22;
+      }
+     } while (0);
+     i21 = HEAP16[i16 >> 1] | 0;
+     i20 = HEAP32[i4 + (i18 << 2) + 2908 >> 2] | 0;
+     i19 = HEAP16[i3 + (i20 << 2) >> 1] | 0;
+     if ((i21 & 65535) < (i19 & 65535)) {
+      break L40;
+     }
+     if (i21 << 16 >> 16 == i19 << 16 >> 16 ? (HEAPU8[i15] | 0) <= (HEAPU8[i4 + i20 + 5208 | 0] | 0) : 0) {
+      break L40;
+     }
+     HEAP32[i4 + (i17 << 2) + 2908 >> 2] = i20;
+     i19 = i18 << 1;
+     i20 = HEAP32[i8 >> 2] | 0;
+     if ((i19 | 0) > (i20 | 0)) {
+      i17 = i18;
+      break;
+     } else {
+      i17 = i18;
+      i18 = i19;
+     }
+    }
+   }
+  } while (0);
+  HEAP32[i4 + (i17 << 2) + 2908 >> 2] = i14;
+  i17 = HEAP32[i12 >> 2] | 0;
+  i14 = (HEAP32[i6 >> 2] | 0) + -1 | 0;
+  HEAP32[i6 >> 2] = i14;
+  HEAP32[i4 + (i14 << 2) + 2908 >> 2] = i13;
+  i14 = (HEAP32[i6 >> 2] | 0) + -1 | 0;
+  HEAP32[i6 >> 2] = i14;
+  HEAP32[i4 + (i14 << 2) + 2908 >> 2] = i17;
+  i14 = i3 + (i11 << 2) | 0;
+  HEAP16[i14 >> 1] = (HEAPU16[i3 + (i17 << 2) >> 1] | 0) + (HEAPU16[i3 + (i13 << 2) >> 1] | 0);
+  i18 = HEAP8[i4 + i13 + 5208 | 0] | 0;
+  i16 = HEAP8[i4 + i17 + 5208 | 0] | 0;
+  i15 = i4 + i11 + 5208 | 0;
+  HEAP8[i15] = (((i18 & 255) < (i16 & 255) ? i16 : i18) & 255) + 1;
+  i19 = i11 & 65535;
+  HEAP16[i3 + (i17 << 2) + 2 >> 1] = i19;
+  HEAP16[i3 + (i13 << 2) + 2 >> 1] = i19;
+  i13 = i11 + 1 | 0;
+  HEAP32[i12 >> 2] = i11;
+  i19 = HEAP32[i8 >> 2] | 0;
+  L56 : do {
+   if ((i19 | 0) < 2) {
+    i16 = 1;
+   } else {
+    i16 = 1;
+    i17 = 2;
+    while (1) {
+     do {
+      if ((i17 | 0) < (i19 | 0)) {
+       i21 = i17 | 1;
+       i22 = HEAP32[i4 + (i21 << 2) + 2908 >> 2] | 0;
+       i19 = HEAP16[i3 + (i22 << 2) >> 1] | 0;
+       i18 = HEAP32[i4 + (i17 << 2) + 2908 >> 2] | 0;
+       i20 = HEAP16[i3 + (i18 << 2) >> 1] | 0;
+       if (!((i19 & 65535) < (i20 & 65535))) {
+        if (!(i19 << 16 >> 16 == i20 << 16 >> 16)) {
+         break;
+        }
+        if ((HEAPU8[i4 + i22 + 5208 | 0] | 0) > (HEAPU8[i4 + i18 + 5208 | 0] | 0)) {
+         break;
+        }
+       }
+       i17 = i21;
+      }
+     } while (0);
+     i19 = HEAP16[i14 >> 1] | 0;
+     i20 = HEAP32[i4 + (i17 << 2) + 2908 >> 2] | 0;
+     i18 = HEAP16[i3 + (i20 << 2) >> 1] | 0;
+     if ((i19 & 65535) < (i18 & 65535)) {
+      break L56;
+     }
+     if (i19 << 16 >> 16 == i18 << 16 >> 16 ? (HEAPU8[i15] | 0) <= (HEAPU8[i4 + i20 + 5208 | 0] | 0) : 0) {
+      break L56;
+     }
+     HEAP32[i4 + (i16 << 2) + 2908 >> 2] = i20;
+     i18 = i17 << 1;
+     i19 = HEAP32[i8 >> 2] | 0;
+     if ((i18 | 0) > (i19 | 0)) {
+      i16 = i17;
+      break;
+     } else {
+      i16 = i17;
+      i17 = i18;
+     }
+    }
+   }
+  } while (0);
+  HEAP32[i4 + (i16 << 2) + 2908 >> 2] = i11;
+  i18 = HEAP32[i8 >> 2] | 0;
+  if ((i18 | 0) > 1) {
+   i11 = i13;
+  } else {
+   break;
+  }
+ }
+ i12 = HEAP32[i12 >> 2] | 0;
+ i8 = (HEAP32[i6 >> 2] | 0) + -1 | 0;
+ HEAP32[i6 >> 2] = i8;
+ HEAP32[i4 + (i8 << 2) + 2908 >> 2] = i12;
+ i8 = HEAP32[i9 >> 2] | 0;
+ i9 = HEAP32[i10 >> 2] | 0;
+ i7 = HEAP32[i7 >> 2] | 0;
+ i12 = HEAP32[i7 >> 2] | 0;
+ i11 = HEAP32[i7 + 4 >> 2] | 0;
+ i10 = HEAP32[i7 + 8 >> 2] | 0;
+ i7 = HEAP32[i7 + 16 >> 2] | 0;
+ i13 = i4 + 2876 | 0;
+ i14 = i13 + 32 | 0;
+ do {
+  HEAP16[i13 >> 1] = 0;
+  i13 = i13 + 2 | 0;
+ } while ((i13 | 0) < (i14 | 0));
+ i14 = HEAP32[i6 >> 2] | 0;
+ HEAP16[i8 + (HEAP32[i4 + (i14 << 2) + 2908 >> 2] << 2) + 2 >> 1] = 0;
+ i14 = i14 + 1 | 0;
+ L72 : do {
+  if ((i14 | 0) < 573) {
+   i6 = i4 + 5800 | 0;
+   i13 = i4 + 5804 | 0;
+   if ((i12 | 0) == 0) {
+    i18 = 0;
+    do {
+     i12 = HEAP32[i4 + (i14 << 2) + 2908 >> 2] | 0;
+     i13 = i8 + (i12 << 2) + 2 | 0;
+     i15 = HEAPU16[i8 + (HEAPU16[i13 >> 1] << 2) + 2 >> 1] | 0;
+     i16 = (i15 | 0) < (i7 | 0);
+     i15 = i16 ? i15 + 1 | 0 : i7;
+     i18 = (i16 & 1 ^ 1) + i18 | 0;
+     HEAP16[i13 >> 1] = i15;
+     if ((i12 | 0) <= (i9 | 0)) {
+      i23 = i4 + (i15 << 1) + 2876 | 0;
+      HEAP16[i23 >> 1] = (HEAP16[i23 >> 1] | 0) + 1 << 16 >> 16;
+      if ((i12 | 0) < (i10 | 0)) {
+       i13 = 0;
+      } else {
+       i13 = HEAP32[i11 + (i12 - i10 << 2) >> 2] | 0;
+      }
+      i23 = Math_imul(HEAPU16[i8 + (i12 << 2) >> 1] | 0, i13 + i15 | 0) | 0;
+      HEAP32[i6 >> 2] = i23 + (HEAP32[i6 >> 2] | 0);
+     }
+     i14 = i14 + 1 | 0;
+    } while ((i14 | 0) != 573);
+   } else {
+    i18 = 0;
+    do {
+     i15 = HEAP32[i4 + (i14 << 2) + 2908 >> 2] | 0;
+     i16 = i8 + (i15 << 2) + 2 | 0;
+     i17 = HEAPU16[i8 + (HEAPU16[i16 >> 1] << 2) + 2 >> 1] | 0;
+     i19 = (i17 | 0) < (i7 | 0);
+     i17 = i19 ? i17 + 1 | 0 : i7;
+     i18 = (i19 & 1 ^ 1) + i18 | 0;
+     HEAP16[i16 >> 1] = i17;
+     if ((i15 | 0) <= (i9 | 0)) {
+      i23 = i4 + (i17 << 1) + 2876 | 0;
+      HEAP16[i23 >> 1] = (HEAP16[i23 >> 1] | 0) + 1 << 16 >> 16;
+      if ((i15 | 0) < (i10 | 0)) {
+       i16 = 0;
+      } else {
+       i16 = HEAP32[i11 + (i15 - i10 << 2) >> 2] | 0;
+      }
+      i23 = HEAPU16[i8 + (i15 << 2) >> 1] | 0;
+      i22 = Math_imul(i23, i16 + i17 | 0) | 0;
+      HEAP32[i6 >> 2] = i22 + (HEAP32[i6 >> 2] | 0);
+      i23 = Math_imul((HEAPU16[i12 + (i15 << 2) + 2 >> 1] | 0) + i16 | 0, i23) | 0;
+      HEAP32[i13 >> 2] = i23 + (HEAP32[i13 >> 2] | 0);
+     }
+     i14 = i14 + 1 | 0;
+    } while ((i14 | 0) != 573);
+   }
+   if ((i18 | 0) != 0) {
+    i10 = i4 + (i7 << 1) + 2876 | 0;
+    do {
+     i12 = i7;
+     while (1) {
+      i11 = i12 + -1 | 0;
+      i13 = i4 + (i11 << 1) + 2876 | 0;
+      i14 = HEAP16[i13 >> 1] | 0;
+      if (i14 << 16 >> 16 == 0) {
+       i12 = i11;
+      } else {
+       break;
+      }
+     }
+     HEAP16[i13 >> 1] = i14 + -1 << 16 >> 16;
+     i11 = i4 + (i12 << 1) + 2876 | 0;
+     HEAP16[i11 >> 1] = (HEAPU16[i11 >> 1] | 0) + 2;
+     i11 = (HEAP16[i10 >> 1] | 0) + -1 << 16 >> 16;
+     HEAP16[i10 >> 1] = i11;
+     i18 = i18 + -2 | 0;
+    } while ((i18 | 0) > 0);
+    if ((i7 | 0) != 0) {
+     i12 = 573;
+     while (1) {
+      i10 = i7 & 65535;
+      if (!(i11 << 16 >> 16 == 0)) {
+       i11 = i11 & 65535;
+       do {
+        do {
+         i12 = i12 + -1 | 0;
+         i15 = HEAP32[i4 + (i12 << 2) + 2908 >> 2] | 0;
+        } while ((i15 | 0) > (i9 | 0));
+        i13 = i8 + (i15 << 2) + 2 | 0;
+        i14 = HEAPU16[i13 >> 1] | 0;
+        if ((i14 | 0) != (i7 | 0)) {
+         i23 = Math_imul(HEAPU16[i8 + (i15 << 2) >> 1] | 0, i7 - i14 | 0) | 0;
+         HEAP32[i6 >> 2] = i23 + (HEAP32[i6 >> 2] | 0);
+         HEAP16[i13 >> 1] = i10;
+        }
+        i11 = i11 + -1 | 0;
+       } while ((i11 | 0) != 0);
+      }
+      i7 = i7 + -1 | 0;
+      if ((i7 | 0) == 0) {
+       break L72;
+      }
+      i11 = HEAP16[i4 + (i7 << 1) + 2876 >> 1] | 0;
+     }
+    }
+   }
+  }
+ } while (0);
+ i7 = 1;
+ i6 = 0;
+ do {
+  i6 = (HEAPU16[i4 + (i7 + -1 << 1) + 2876 >> 1] | 0) + (i6 & 65534) << 1;
+  HEAP16[i1 + (i7 << 1) >> 1] = i6;
+  i7 = i7 + 1 | 0;
+ } while ((i7 | 0) != 16);
+ if ((i5 | 0) < 0) {
+  STACKTOP = i2;
+  return;
+ } else {
+  i4 = 0;
+ }
+ while (1) {
+  i23 = HEAP16[i3 + (i4 << 2) + 2 >> 1] | 0;
+  i7 = i23 & 65535;
+  if (!(i23 << 16 >> 16 == 0)) {
+   i8 = i1 + (i7 << 1) | 0;
+   i6 = HEAP16[i8 >> 1] | 0;
+   HEAP16[i8 >> 1] = i6 + 1 << 16 >> 16;
+   i6 = i6 & 65535;
+   i8 = 0;
+   while (1) {
+    i8 = i8 | i6 & 1;
+    i7 = i7 + -1 | 0;
+    if ((i7 | 0) <= 0) {
+     break;
+    } else {
+     i6 = i6 >>> 1;
+     i8 = i8 << 1;
+    }
+   }
+   HEAP16[i3 + (i4 << 2) >> 1] = i8;
+  }
+  if ((i4 | 0) == (i5 | 0)) {
+   break;
+  } else {
+   i4 = i4 + 1 | 0;
+  }
+ }
+ STACKTOP = i2;
+ return;
+}
+function _deflate_slow(i2, i6) {
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0;
+ i1 = STACKTOP;
+ i15 = i2 + 116 | 0;
+ i16 = (i6 | 0) == 0;
+ i17 = i2 + 72 | 0;
+ i18 = i2 + 88 | 0;
+ i5 = i2 + 108 | 0;
+ i7 = i2 + 56 | 0;
+ i19 = i2 + 84 | 0;
+ i20 = i2 + 68 | 0;
+ i22 = i2 + 52 | 0;
+ i21 = i2 + 64 | 0;
+ i9 = i2 + 96 | 0;
+ i10 = i2 + 120 | 0;
+ i11 = i2 + 112 | 0;
+ i12 = i2 + 100 | 0;
+ i26 = i2 + 5792 | 0;
+ i27 = i2 + 5796 | 0;
+ i29 = i2 + 5784 | 0;
+ i23 = i2 + 5788 | 0;
+ i8 = i2 + 104 | 0;
+ i4 = i2 + 92 | 0;
+ i24 = i2 + 128 | 0;
+ i14 = i2 + 44 | 0;
+ i13 = i2 + 136 | 0;
+ L1 : while (1) {
+  i30 = HEAP32[i15 >> 2] | 0;
+  while (1) {
+   if (i30 >>> 0 < 262) {
+    _fill_window(i2);
+    i30 = HEAP32[i15 >> 2] | 0;
+    if (i30 >>> 0 < 262 & i16) {
+     i2 = 0;
+     i30 = 50;
+     break L1;
+    }
+    if ((i30 | 0) == 0) {
+     i30 = 40;
+     break L1;
+    }
+    if (!(i30 >>> 0 > 2)) {
+     HEAP32[i10 >> 2] = HEAP32[i9 >> 2];
+     HEAP32[i12 >> 2] = HEAP32[i11 >> 2];
+     HEAP32[i9 >> 2] = 2;
+     i32 = 2;
+     i30 = 16;
+    } else {
+     i30 = 8;
+    }
+   } else {
+    i30 = 8;
+   }
+   do {
+    if ((i30 | 0) == 8) {
+     i30 = 0;
+     i34 = HEAP32[i5 >> 2] | 0;
+     i31 = ((HEAPU8[(HEAP32[i7 >> 2] | 0) + (i34 + 2) | 0] | 0) ^ HEAP32[i17 >> 2] << HEAP32[i18 >> 2]) & HEAP32[i19 >> 2];
+     HEAP32[i17 >> 2] = i31;
+     i31 = (HEAP32[i20 >> 2] | 0) + (i31 << 1) | 0;
+     i35 = HEAP16[i31 >> 1] | 0;
+     HEAP16[(HEAP32[i21 >> 2] | 0) + ((HEAP32[i22 >> 2] & i34) << 1) >> 1] = i35;
+     i32 = i35 & 65535;
+     HEAP16[i31 >> 1] = i34;
+     i31 = HEAP32[i9 >> 2] | 0;
+     HEAP32[i10 >> 2] = i31;
+     HEAP32[i12 >> 2] = HEAP32[i11 >> 2];
+     HEAP32[i9 >> 2] = 2;
+     if (!(i35 << 16 >> 16 == 0)) {
+      if (i31 >>> 0 < (HEAP32[i24 >> 2] | 0) >>> 0) {
+       if (!(((HEAP32[i5 >> 2] | 0) - i32 | 0) >>> 0 > ((HEAP32[i14 >> 2] | 0) + -262 | 0) >>> 0)) {
+        i32 = _longest_match(i2, i32) | 0;
+        HEAP32[i9 >> 2] = i32;
+        if (i32 >>> 0 < 6) {
+         if ((HEAP32[i13 >> 2] | 0) != 1) {
+          if ((i32 | 0) != 3) {
+           i30 = 16;
+           break;
+          }
+          if (!(((HEAP32[i5 >> 2] | 0) - (HEAP32[i11 >> 2] | 0) | 0) >>> 0 > 4096)) {
+           i32 = 3;
+           i30 = 16;
+           break;
+          }
+         }
+         HEAP32[i9 >> 2] = 2;
+         i32 = 2;
+         i30 = 16;
+        } else {
+         i30 = 16;
+        }
+       } else {
+        i32 = 2;
+        i30 = 16;
+       }
+      } else {
+       i32 = 2;
+      }
+     } else {
+      i32 = 2;
+      i30 = 16;
+     }
+    }
+   } while (0);
+   if ((i30 | 0) == 16) {
+    i31 = HEAP32[i10 >> 2] | 0;
+   }
+   if (!(i31 >>> 0 < 3 | i32 >>> 0 > i31 >>> 0)) {
+    break;
+   }
+   if ((HEAP32[i8 >> 2] | 0) == 0) {
+    HEAP32[i8 >> 2] = 1;
+    HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 1;
+    i30 = (HEAP32[i15 >> 2] | 0) + -1 | 0;
+    HEAP32[i15 >> 2] = i30;
+    continue;
+   }
+   i35 = HEAP8[(HEAP32[i7 >> 2] | 0) + ((HEAP32[i5 >> 2] | 0) + -1) | 0] | 0;
+   i34 = HEAP32[i26 >> 2] | 0;
+   HEAP16[(HEAP32[i27 >> 2] | 0) + (i34 << 1) >> 1] = 0;
+   HEAP32[i26 >> 2] = i34 + 1;
+   HEAP8[(HEAP32[i29 >> 2] | 0) + i34 | 0] = i35;
+   i35 = i2 + ((i35 & 255) << 2) + 148 | 0;
+   HEAP16[i35 >> 1] = (HEAP16[i35 >> 1] | 0) + 1 << 16 >> 16;
+   if ((HEAP32[i26 >> 2] | 0) == ((HEAP32[i23 >> 2] | 0) + -1 | 0)) {
+    i30 = HEAP32[i4 >> 2] | 0;
+    if ((i30 | 0) > -1) {
+     i31 = (HEAP32[i7 >> 2] | 0) + i30 | 0;
+    } else {
+     i31 = 0;
+    }
+    __tr_flush_block(i2, i31, (HEAP32[i5 >> 2] | 0) - i30 | 0, 0);
+    HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+    i33 = HEAP32[i2 >> 2] | 0;
+    i32 = i33 + 28 | 0;
+    i30 = HEAP32[i32 >> 2] | 0;
+    i35 = HEAP32[i30 + 20 >> 2] | 0;
+    i31 = i33 + 16 | 0;
+    i34 = HEAP32[i31 >> 2] | 0;
+    i34 = i35 >>> 0 > i34 >>> 0 ? i34 : i35;
+    if ((i34 | 0) != 0 ? (i28 = i33 + 12 | 0, _memcpy(HEAP32[i28 >> 2] | 0, HEAP32[i30 + 16 >> 2] | 0, i34 | 0) | 0, HEAP32[i28 >> 2] = (HEAP32[i28 >> 2] | 0) + i34, i28 = (HEAP32[i32 >> 2] | 0) + 16 | 0, HEAP32[i28 >> 2] = (HEAP32[i28 >> 2] | 0) + i34, i28 = i33 + 20 | 0, HEAP32[i28 >> 2] = (HEAP32[i28 >> 2] | 0) + i34, HEAP32[i31 >> 2] = (HEAP32[i31 >> 2] | 0) - i34, i28 = HEAP32[i32 >> 2] | 0, i33 = i28 + 20 | 0, i35 = HEAP32[i33 >> 2] | 0, HEAP32[i33 >> 2] = i35 - i34, (i35 | 0) == (i34 | 0)) : 0) {
+     HEAP32[i28 + 16 >> 2] = HEAP32[i28 + 8 >> 2];
+    }
+   }
+   HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 1;
+   i30 = (HEAP32[i15 >> 2] | 0) + -1 | 0;
+   HEAP32[i15 >> 2] = i30;
+   if ((HEAP32[(HEAP32[i2 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+    i2 = 0;
+    i30 = 50;
+    break L1;
+   }
+  }
+  i34 = HEAP32[i5 >> 2] | 0;
+  i30 = i34 + -3 + (HEAP32[i15 >> 2] | 0) | 0;
+  i35 = i31 + 253 | 0;
+  i31 = i34 + 65535 - (HEAP32[i12 >> 2] | 0) | 0;
+  i34 = HEAP32[i26 >> 2] | 0;
+  HEAP16[(HEAP32[i27 >> 2] | 0) + (i34 << 1) >> 1] = i31;
+  HEAP32[i26 >> 2] = i34 + 1;
+  HEAP8[(HEAP32[i29 >> 2] | 0) + i34 | 0] = i35;
+  i35 = i2 + ((HEAPU8[808 + (i35 & 255) | 0] | 0 | 256) + 1 << 2) + 148 | 0;
+  HEAP16[i35 >> 1] = (HEAP16[i35 >> 1] | 0) + 1 << 16 >> 16;
+  i31 = i31 + 65535 & 65535;
+  if (!(i31 >>> 0 < 256)) {
+   i31 = (i31 >>> 7) + 256 | 0;
+  }
+  i32 = i2 + ((HEAPU8[296 + i31 | 0] | 0) << 2) + 2440 | 0;
+  HEAP16[i32 >> 1] = (HEAP16[i32 >> 1] | 0) + 1 << 16 >> 16;
+  i32 = HEAP32[i26 >> 2] | 0;
+  i31 = (HEAP32[i23 >> 2] | 0) + -1 | 0;
+  i34 = HEAP32[i10 >> 2] | 0;
+  HEAP32[i15 >> 2] = 1 - i34 + (HEAP32[i15 >> 2] | 0);
+  i34 = i34 + -2 | 0;
+  HEAP32[i10 >> 2] = i34;
+  i33 = HEAP32[i5 >> 2] | 0;
+  while (1) {
+   i35 = i33 + 1 | 0;
+   HEAP32[i5 >> 2] = i35;
+   if (!(i35 >>> 0 > i30 >>> 0)) {
+    i36 = ((HEAPU8[(HEAP32[i7 >> 2] | 0) + (i33 + 3) | 0] | 0) ^ HEAP32[i17 >> 2] << HEAP32[i18 >> 2]) & HEAP32[i19 >> 2];
+    HEAP32[i17 >> 2] = i36;
+    i36 = (HEAP32[i20 >> 2] | 0) + (i36 << 1) | 0;
+    HEAP16[(HEAP32[i21 >> 2] | 0) + ((HEAP32[i22 >> 2] & i35) << 1) >> 1] = HEAP16[i36 >> 1] | 0;
+    HEAP16[i36 >> 1] = i35;
+   }
+   i34 = i34 + -1 | 0;
+   HEAP32[i10 >> 2] = i34;
+   if ((i34 | 0) == 0) {
+    break;
+   } else {
+    i33 = i35;
+   }
+  }
+  HEAP32[i8 >> 2] = 0;
+  HEAP32[i9 >> 2] = 2;
+  i30 = i33 + 2 | 0;
+  HEAP32[i5 >> 2] = i30;
+  if ((i32 | 0) != (i31 | 0)) {
+   continue;
+  }
+  i32 = HEAP32[i4 >> 2] | 0;
+  if ((i32 | 0) > -1) {
+   i31 = (HEAP32[i7 >> 2] | 0) + i32 | 0;
+  } else {
+   i31 = 0;
+  }
+  __tr_flush_block(i2, i31, i30 - i32 | 0, 0);
+  HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+  i33 = HEAP32[i2 >> 2] | 0;
+  i31 = i33 + 28 | 0;
+  i32 = HEAP32[i31 >> 2] | 0;
+  i35 = HEAP32[i32 + 20 >> 2] | 0;
+  i30 = i33 + 16 | 0;
+  i34 = HEAP32[i30 >> 2] | 0;
+  i34 = i35 >>> 0 > i34 >>> 0 ? i34 : i35;
+  if ((i34 | 0) != 0 ? (i25 = i33 + 12 | 0, _memcpy(HEAP32[i25 >> 2] | 0, HEAP32[i32 + 16 >> 2] | 0, i34 | 0) | 0, HEAP32[i25 >> 2] = (HEAP32[i25 >> 2] | 0) + i34, i25 = (HEAP32[i31 >> 2] | 0) + 16 | 0, HEAP32[i25 >> 2] = (HEAP32[i25 >> 2] | 0) + i34, i25 = i33 + 20 | 0, HEAP32[i25 >> 2] = (HEAP32[i25 >> 2] | 0) + i34, HEAP32[i30 >> 2] = (HEAP32[i30 >> 2] | 0) - i34, i25 = HEAP32[i31 >> 2] | 0, i35 = i25 + 20 | 0, i36 = HEAP32[i35 >> 2] | 0, HEAP32[i35 >> 2] = i36 - i34, (i36 | 0) == (i34 | 0)) : 0) {
+   HEAP32[i25 + 16 >> 2] = HEAP32[i25 + 8 >> 2];
+  }
+  if ((HEAP32[(HEAP32[i2 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+   i2 = 0;
+   i30 = 50;
+   break;
+  }
+ }
+ if ((i30 | 0) == 40) {
+  if ((HEAP32[i8 >> 2] | 0) != 0) {
+   i36 = HEAP8[(HEAP32[i7 >> 2] | 0) + ((HEAP32[i5 >> 2] | 0) + -1) | 0] | 0;
+   i35 = HEAP32[i26 >> 2] | 0;
+   HEAP16[(HEAP32[i27 >> 2] | 0) + (i35 << 1) >> 1] = 0;
+   HEAP32[i26 >> 2] = i35 + 1;
+   HEAP8[(HEAP32[i29 >> 2] | 0) + i35 | 0] = i36;
+   i36 = i2 + ((i36 & 255) << 2) + 148 | 0;
+   HEAP16[i36 >> 1] = (HEAP16[i36 >> 1] | 0) + 1 << 16 >> 16;
+   HEAP32[i8 >> 2] = 0;
+  }
+  i8 = HEAP32[i4 >> 2] | 0;
+  if ((i8 | 0) > -1) {
+   i7 = (HEAP32[i7 >> 2] | 0) + i8 | 0;
+  } else {
+   i7 = 0;
+  }
+  i6 = (i6 | 0) == 4;
+  __tr_flush_block(i2, i7, (HEAP32[i5 >> 2] | 0) - i8 | 0, i6 & 1);
+  HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+  i4 = HEAP32[i2 >> 2] | 0;
+  i7 = i4 + 28 | 0;
+  i5 = HEAP32[i7 >> 2] | 0;
+  i10 = HEAP32[i5 + 20 >> 2] | 0;
+  i8 = i4 + 16 | 0;
+  i9 = HEAP32[i8 >> 2] | 0;
+  i9 = i10 >>> 0 > i9 >>> 0 ? i9 : i10;
+  if ((i9 | 0) != 0 ? (i3 = i4 + 12 | 0, _memcpy(HEAP32[i3 >> 2] | 0, HEAP32[i5 + 16 >> 2] | 0, i9 | 0) | 0, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + i9, i3 = (HEAP32[i7 >> 2] | 0) + 16 | 0, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + i9, i3 = i4 + 20 | 0, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + i9, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) - i9, i3 = HEAP32[i7 >> 2] | 0, i35 = i3 + 20 | 0, i36 = HEAP32[i35 >> 2] | 0, HEAP32[i35 >> 2] = i36 - i9, (i36 | 0) == (i9 | 0)) : 0) {
+   HEAP32[i3 + 16 >> 2] = HEAP32[i3 + 8 >> 2];
+  }
+  if ((HEAP32[(HEAP32[i2 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+   i36 = i6 ? 2 : 0;
+   STACKTOP = i1;
+   return i36 | 0;
+  } else {
+   i36 = i6 ? 3 : 1;
+   STACKTOP = i1;
+   return i36 | 0;
+  }
+ } else if ((i30 | 0) == 50) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ return 0;
+}
+function _inflate_fast(i7, i19) {
+ i7 = i7 | 0;
+ i19 = i19 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0;
+ i1 = STACKTOP;
+ i11 = HEAP32[i7 + 28 >> 2] | 0;
+ i29 = HEAP32[i7 >> 2] | 0;
+ i5 = i7 + 4 | 0;
+ i8 = i29 + ((HEAP32[i5 >> 2] | 0) + -6) | 0;
+ i9 = i7 + 12 | 0;
+ i28 = HEAP32[i9 >> 2] | 0;
+ i4 = i7 + 16 | 0;
+ i25 = HEAP32[i4 >> 2] | 0;
+ i6 = i28 + (i25 + -258) | 0;
+ i17 = HEAP32[i11 + 44 >> 2] | 0;
+ i12 = HEAP32[i11 + 48 >> 2] | 0;
+ i18 = HEAP32[i11 + 52 >> 2] | 0;
+ i3 = i11 + 56 | 0;
+ i2 = i11 + 60 | 0;
+ i16 = HEAP32[i11 + 76 >> 2] | 0;
+ i13 = HEAP32[i11 + 80 >> 2] | 0;
+ i14 = (1 << HEAP32[i11 + 84 >> 2]) + -1 | 0;
+ i15 = (1 << HEAP32[i11 + 88 >> 2]) + -1 | 0;
+ i19 = i28 + (i25 + ~i19) | 0;
+ i25 = i11 + 7104 | 0;
+ i20 = i18 + -1 | 0;
+ i27 = (i12 | 0) == 0;
+ i24 = (HEAP32[i11 + 40 >> 2] | 0) + -1 | 0;
+ i21 = i24 + i12 | 0;
+ i22 = i12 + -1 | 0;
+ i23 = i19 + -1 | 0;
+ i26 = i19 - i12 | 0;
+ i31 = HEAP32[i2 >> 2] | 0;
+ i30 = HEAP32[i3 >> 2] | 0;
+ i29 = i29 + -1 | 0;
+ i28 = i28 + -1 | 0;
+ L1 : do {
+  if (i31 >>> 0 < 15) {
+   i37 = i29 + 2 | 0;
+   i33 = i31 + 16 | 0;
+   i30 = ((HEAPU8[i29 + 1 | 0] | 0) << i31) + i30 + ((HEAPU8[i37] | 0) << i31 + 8) | 0;
+   i29 = i37;
+  } else {
+   i33 = i31;
+  }
+  i31 = i30 & i14;
+  i34 = HEAP8[i16 + (i31 << 2) | 0] | 0;
+  i32 = HEAP16[i16 + (i31 << 2) + 2 >> 1] | 0;
+  i31 = HEAPU8[i16 + (i31 << 2) + 1 | 0] | 0;
+  i30 = i30 >>> i31;
+  i31 = i33 - i31 | 0;
+  do {
+   if (!(i34 << 24 >> 24 == 0)) {
+    i33 = i34 & 255;
+    while (1) {
+     if ((i33 & 16 | 0) != 0) {
+      break;
+     }
+     if ((i33 & 64 | 0) != 0) {
+      i10 = 55;
+      break L1;
+     }
+     i37 = (i30 & (1 << i33) + -1) + (i32 & 65535) | 0;
+     i33 = HEAP8[i16 + (i37 << 2) | 0] | 0;
+     i32 = HEAP16[i16 + (i37 << 2) + 2 >> 1] | 0;
+     i37 = HEAPU8[i16 + (i37 << 2) + 1 | 0] | 0;
+     i30 = i30 >>> i37;
+     i31 = i31 - i37 | 0;
+     if (i33 << 24 >> 24 == 0) {
+      i10 = 6;
+      break;
+     } else {
+      i33 = i33 & 255;
+     }
+    }
+    if ((i10 | 0) == 6) {
+     i32 = i32 & 255;
+     i10 = 7;
+     break;
+    }
+    i32 = i32 & 65535;
+    i33 = i33 & 15;
+    if ((i33 | 0) != 0) {
+     if (i31 >>> 0 < i33 >>> 0) {
+      i29 = i29 + 1 | 0;
+      i35 = i31 + 8 | 0;
+      i34 = ((HEAPU8[i29] | 0) << i31) + i30 | 0;
+     } else {
+      i35 = i31;
+      i34 = i30;
+     }
+     i31 = i35 - i33 | 0;
+     i30 = i34 >>> i33;
+     i32 = (i34 & (1 << i33) + -1) + i32 | 0;
+    }
+    if (i31 >>> 0 < 15) {
+     i37 = i29 + 2 | 0;
+     i34 = i31 + 16 | 0;
+     i30 = ((HEAPU8[i29 + 1 | 0] | 0) << i31) + i30 + ((HEAPU8[i37] | 0) << i31 + 8) | 0;
+     i29 = i37;
+    } else {
+     i34 = i31;
+    }
+    i37 = i30 & i15;
+    i33 = HEAP16[i13 + (i37 << 2) + 2 >> 1] | 0;
+    i31 = HEAPU8[i13 + (i37 << 2) + 1 | 0] | 0;
+    i30 = i30 >>> i31;
+    i31 = i34 - i31 | 0;
+    i34 = HEAPU8[i13 + (i37 << 2) | 0] | 0;
+    if ((i34 & 16 | 0) == 0) {
+     do {
+      if ((i34 & 64 | 0) != 0) {
+       i10 = 52;
+       break L1;
+      }
+      i34 = (i30 & (1 << i34) + -1) + (i33 & 65535) | 0;
+      i33 = HEAP16[i13 + (i34 << 2) + 2 >> 1] | 0;
+      i37 = HEAPU8[i13 + (i34 << 2) + 1 | 0] | 0;
+      i30 = i30 >>> i37;
+      i31 = i31 - i37 | 0;
+      i34 = HEAPU8[i13 + (i34 << 2) | 0] | 0;
+     } while ((i34 & 16 | 0) == 0);
+    }
+    i33 = i33 & 65535;
+    i34 = i34 & 15;
+    if (i31 >>> 0 < i34 >>> 0) {
+     i35 = i29 + 1 | 0;
+     i30 = ((HEAPU8[i35] | 0) << i31) + i30 | 0;
+     i36 = i31 + 8 | 0;
+     if (i36 >>> 0 < i34 >>> 0) {
+      i29 = i29 + 2 | 0;
+      i31 = i31 + 16 | 0;
+      i30 = ((HEAPU8[i29] | 0) << i36) + i30 | 0;
+     } else {
+      i31 = i36;
+      i29 = i35;
+     }
+    }
+    i33 = (i30 & (1 << i34) + -1) + i33 | 0;
+    i30 = i30 >>> i34;
+    i31 = i31 - i34 | 0;
+    i35 = i28;
+    i34 = i35 - i19 | 0;
+    if (!(i33 >>> 0 > i34 >>> 0)) {
+     i34 = i28 + (0 - i33) | 0;
+     while (1) {
+      HEAP8[i28 + 1 | 0] = HEAP8[i34 + 1 | 0] | 0;
+      HEAP8[i28 + 2 | 0] = HEAP8[i34 + 2 | 0] | 0;
+      i35 = i34 + 3 | 0;
+      i33 = i28 + 3 | 0;
+      HEAP8[i33] = HEAP8[i35] | 0;
+      i32 = i32 + -3 | 0;
+      if (!(i32 >>> 0 > 2)) {
+       break;
+      } else {
+       i34 = i35;
+       i28 = i33;
+      }
+     }
+     if ((i32 | 0) == 0) {
+      i28 = i33;
+      break;
+     }
+     i33 = i28 + 4 | 0;
+     HEAP8[i33] = HEAP8[i34 + 4 | 0] | 0;
+     if (!(i32 >>> 0 > 1)) {
+      i28 = i33;
+      break;
+     }
+     i28 = i28 + 5 | 0;
+     HEAP8[i28] = HEAP8[i34 + 5 | 0] | 0;
+     break;
+    }
+    i34 = i33 - i34 | 0;
+    if (i34 >>> 0 > i17 >>> 0 ? (HEAP32[i25 >> 2] | 0) != 0 : 0) {
+     i10 = 22;
+     break L1;
+    }
+    do {
+     if (i27) {
+      i36 = i18 + (i24 - i34) | 0;
+      if (i34 >>> 0 < i32 >>> 0) {
+       i32 = i32 - i34 | 0;
+       i35 = i33 - i35 | 0;
+       i37 = i28;
+       do {
+        i36 = i36 + 1 | 0;
+        i37 = i37 + 1 | 0;
+        HEAP8[i37] = HEAP8[i36] | 0;
+        i34 = i34 + -1 | 0;
+       } while ((i34 | 0) != 0);
+       i33 = i28 + (i23 + i35 + (1 - i33)) | 0;
+       i28 = i28 + (i19 + i35) | 0;
+      } else {
+       i33 = i36;
+      }
+     } else {
+      if (!(i12 >>> 0 < i34 >>> 0)) {
+       i36 = i18 + (i22 - i34) | 0;
+       if (!(i34 >>> 0 < i32 >>> 0)) {
+        i33 = i36;
+        break;
+       }
+       i32 = i32 - i34 | 0;
+       i35 = i33 - i35 | 0;
+       i37 = i28;
+       do {
+        i36 = i36 + 1 | 0;
+        i37 = i37 + 1 | 0;
+        HEAP8[i37] = HEAP8[i36] | 0;
+        i34 = i34 + -1 | 0;
+       } while ((i34 | 0) != 0);
+       i33 = i28 + (i23 + i35 + (1 - i33)) | 0;
+       i28 = i28 + (i19 + i35) | 0;
+       break;
+      }
+      i37 = i18 + (i21 - i34) | 0;
+      i36 = i34 - i12 | 0;
+      if (i36 >>> 0 < i32 >>> 0) {
+       i32 = i32 - i36 | 0;
+       i34 = i33 - i35 | 0;
+       i35 = i28;
+       do {
+        i37 = i37 + 1 | 0;
+        i35 = i35 + 1 | 0;
+        HEAP8[i35] = HEAP8[i37] | 0;
+        i36 = i36 + -1 | 0;
+       } while ((i36 | 0) != 0);
+       i35 = i28 + (i26 + i34) | 0;
+       if (i12 >>> 0 < i32 >>> 0) {
+        i32 = i32 - i12 | 0;
+        i37 = i20;
+        i36 = i12;
+        do {
+         i37 = i37 + 1 | 0;
+         i35 = i35 + 1 | 0;
+         HEAP8[i35] = HEAP8[i37] | 0;
+         i36 = i36 + -1 | 0;
+        } while ((i36 | 0) != 0);
+        i33 = i28 + (i23 + i34 + (1 - i33)) | 0;
+        i28 = i28 + (i19 + i34) | 0;
+       } else {
+        i33 = i20;
+        i28 = i35;
+       }
+      } else {
+       i33 = i37;
+      }
+     }
+    } while (0);
+    if (i32 >>> 0 > 2) {
+     do {
+      HEAP8[i28 + 1 | 0] = HEAP8[i33 + 1 | 0] | 0;
+      HEAP8[i28 + 2 | 0] = HEAP8[i33 + 2 | 0] | 0;
+      i33 = i33 + 3 | 0;
+      i28 = i28 + 3 | 0;
+      HEAP8[i28] = HEAP8[i33] | 0;
+      i32 = i32 + -3 | 0;
+     } while (i32 >>> 0 > 2);
+    }
+    if ((i32 | 0) != 0) {
+     i34 = i28 + 1 | 0;
+     HEAP8[i34] = HEAP8[i33 + 1 | 0] | 0;
+     if (i32 >>> 0 > 1) {
+      i28 = i28 + 2 | 0;
+      HEAP8[i28] = HEAP8[i33 + 2 | 0] | 0;
+     } else {
+      i28 = i34;
+     }
+    }
+   } else {
+    i32 = i32 & 255;
+    i10 = 7;
+   }
+  } while (0);
+  if ((i10 | 0) == 7) {
+   i10 = 0;
+   i28 = i28 + 1 | 0;
+   HEAP8[i28] = i32;
+  }
+ } while (i29 >>> 0 < i8 >>> 0 & i28 >>> 0 < i6 >>> 0);
+ do {
+  if ((i10 | 0) == 22) {
+   HEAP32[i7 + 24 >> 2] = 14384;
+   HEAP32[i11 >> 2] = 29;
+  } else if ((i10 | 0) == 52) {
+   HEAP32[i7 + 24 >> 2] = 14416;
+   HEAP32[i11 >> 2] = 29;
+  } else if ((i10 | 0) == 55) {
+   if ((i33 & 32 | 0) == 0) {
+    HEAP32[i7 + 24 >> 2] = 14440;
+    HEAP32[i11 >> 2] = 29;
+    break;
+   } else {
+    HEAP32[i11 >> 2] = 11;
+    break;
+   }
+  }
+ } while (0);
+ i37 = i31 >>> 3;
+ i11 = i29 + (0 - i37) | 0;
+ i10 = i31 - (i37 << 3) | 0;
+ i12 = (1 << i10) + -1 & i30;
+ HEAP32[i7 >> 2] = i29 + (1 - i37);
+ HEAP32[i9 >> 2] = i28 + 1;
+ if (i11 >>> 0 < i8 >>> 0) {
+  i7 = i8 - i11 | 0;
+ } else {
+  i7 = i8 - i11 | 0;
+ }
+ HEAP32[i5 >> 2] = i7 + 5;
+ if (i28 >>> 0 < i6 >>> 0) {
+  i37 = i6 - i28 | 0;
+  i37 = i37 + 257 | 0;
+  HEAP32[i4 >> 2] = i37;
+  HEAP32[i3 >> 2] = i12;
+  HEAP32[i2 >> 2] = i10;
+  STACKTOP = i1;
+  return;
+ } else {
+  i37 = i6 - i28 | 0;
+  i37 = i37 + 257 | 0;
+  HEAP32[i4 >> 2] = i37;
+  HEAP32[i3 >> 2] = i12;
+  HEAP32[i2 >> 2] = i10;
+  STACKTOP = i1;
+  return;
+ }
+}
+function _send_tree(i2, i13, i12) {
+ i2 = i2 | 0;
+ i13 = i13 | 0;
+ i12 = i12 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0;
+ i11 = STACKTOP;
+ i15 = HEAP16[i13 + 2 >> 1] | 0;
+ i16 = i15 << 16 >> 16 == 0;
+ i7 = i2 + 2754 | 0;
+ i4 = i2 + 5820 | 0;
+ i8 = i2 + 2752 | 0;
+ i3 = i2 + 5816 | 0;
+ i14 = i2 + 20 | 0;
+ i10 = i2 + 8 | 0;
+ i9 = i2 + 2758 | 0;
+ i1 = i2 + 2756 | 0;
+ i5 = i2 + 2750 | 0;
+ i6 = i2 + 2748 | 0;
+ i21 = i16 ? 138 : 7;
+ i23 = i16 ? 3 : 4;
+ i18 = 0;
+ i15 = i15 & 65535;
+ i24 = -1;
+ L1 : while (1) {
+  i20 = 0;
+  while (1) {
+   if ((i18 | 0) > (i12 | 0)) {
+    break L1;
+   }
+   i18 = i18 + 1 | 0;
+   i19 = HEAP16[i13 + (i18 << 2) + 2 >> 1] | 0;
+   i16 = i19 & 65535;
+   i22 = i20 + 1 | 0;
+   i17 = (i15 | 0) == (i16 | 0);
+   if (!((i22 | 0) < (i21 | 0) & i17)) {
+    break;
+   } else {
+    i20 = i22;
+   }
+  }
+  do {
+   if ((i22 | 0) >= (i23 | 0)) {
+    if ((i15 | 0) != 0) {
+     if ((i15 | 0) == (i24 | 0)) {
+      i23 = HEAP16[i3 >> 1] | 0;
+      i21 = HEAP32[i4 >> 2] | 0;
+      i20 = i22;
+     } else {
+      i22 = HEAPU16[i2 + (i15 << 2) + 2686 >> 1] | 0;
+      i21 = HEAP32[i4 >> 2] | 0;
+      i24 = HEAPU16[i2 + (i15 << 2) + 2684 >> 1] | 0;
+      i25 = HEAPU16[i3 >> 1] | 0 | i24 << i21;
+      i23 = i25 & 65535;
+      HEAP16[i3 >> 1] = i23;
+      if ((i21 | 0) > (16 - i22 | 0)) {
+       i23 = HEAP32[i14 >> 2] | 0;
+       HEAP32[i14 >> 2] = i23 + 1;
+       HEAP8[(HEAP32[i10 >> 2] | 0) + i23 | 0] = i25;
+       i23 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+       i21 = HEAP32[i14 >> 2] | 0;
+       HEAP32[i14 >> 2] = i21 + 1;
+       HEAP8[(HEAP32[i10 >> 2] | 0) + i21 | 0] = i23;
+       i21 = HEAP32[i4 >> 2] | 0;
+       i23 = i24 >>> (16 - i21 | 0) & 65535;
+       HEAP16[i3 >> 1] = i23;
+       i21 = i22 + -16 + i21 | 0;
+      } else {
+       i21 = i21 + i22 | 0;
+      }
+      HEAP32[i4 >> 2] = i21;
+     }
+     i22 = HEAPU16[i5 >> 1] | 0;
+     i24 = HEAPU16[i6 >> 1] | 0;
+     i23 = i23 & 65535 | i24 << i21;
+     HEAP16[i3 >> 1] = i23;
+     if ((i21 | 0) > (16 - i22 | 0)) {
+      i21 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i21 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i21 | 0] = i23;
+      i23 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+      i21 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i21 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i21 | 0] = i23;
+      i21 = HEAP32[i4 >> 2] | 0;
+      i23 = i24 >>> (16 - i21 | 0);
+      HEAP16[i3 >> 1] = i23;
+      i21 = i22 + -16 + i21 | 0;
+     } else {
+      i21 = i21 + i22 | 0;
+     }
+     HEAP32[i4 >> 2] = i21;
+     i20 = i20 + 65533 & 65535;
+     i22 = i23 & 65535 | i20 << i21;
+     HEAP16[i3 >> 1] = i22;
+     if ((i21 | 0) > 14) {
+      i26 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i26 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i26 | 0] = i22;
+      i26 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+      i27 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i27 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i27 | 0] = i26;
+      i27 = HEAP32[i4 >> 2] | 0;
+      HEAP16[i3 >> 1] = i20 >>> (16 - i27 | 0);
+      HEAP32[i4 >> 2] = i27 + -14;
+      break;
+     } else {
+      HEAP32[i4 >> 2] = i21 + 2;
+      break;
+     }
+    }
+    if ((i22 | 0) < 11) {
+     i24 = HEAPU16[i7 >> 1] | 0;
+     i23 = HEAP32[i4 >> 2] | 0;
+     i21 = HEAPU16[i8 >> 1] | 0;
+     i22 = HEAPU16[i3 >> 1] | 0 | i21 << i23;
+     HEAP16[i3 >> 1] = i22;
+     if ((i23 | 0) > (16 - i24 | 0)) {
+      i27 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i27 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i27 | 0] = i22;
+      i22 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+      i27 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i27 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i27 | 0] = i22;
+      i27 = HEAP32[i4 >> 2] | 0;
+      i22 = i21 >>> (16 - i27 | 0);
+      HEAP16[i3 >> 1] = i22;
+      i21 = i24 + -16 + i27 | 0;
+     } else {
+      i21 = i23 + i24 | 0;
+     }
+     HEAP32[i4 >> 2] = i21;
+     i20 = i20 + 65534 & 65535;
+     i22 = i22 & 65535 | i20 << i21;
+     HEAP16[i3 >> 1] = i22;
+     if ((i21 | 0) > 13) {
+      i26 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i26 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i26 | 0] = i22;
+      i26 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+      i27 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i27 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i27 | 0] = i26;
+      i27 = HEAP32[i4 >> 2] | 0;
+      HEAP16[i3 >> 1] = i20 >>> (16 - i27 | 0);
+      HEAP32[i4 >> 2] = i27 + -13;
+      break;
+     } else {
+      HEAP32[i4 >> 2] = i21 + 3;
+      break;
+     }
+    } else {
+     i21 = HEAPU16[i9 >> 1] | 0;
+     i24 = HEAP32[i4 >> 2] | 0;
+     i23 = HEAPU16[i1 >> 1] | 0;
+     i22 = HEAPU16[i3 >> 1] | 0 | i23 << i24;
+     HEAP16[i3 >> 1] = i22;
+     if ((i24 | 0) > (16 - i21 | 0)) {
+      i27 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i27 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i27 | 0] = i22;
+      i22 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+      i27 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i27 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i27 | 0] = i22;
+      i27 = HEAP32[i4 >> 2] | 0;
+      i22 = i23 >>> (16 - i27 | 0);
+      HEAP16[i3 >> 1] = i22;
+      i21 = i21 + -16 + i27 | 0;
+     } else {
+      i21 = i24 + i21 | 0;
+     }
+     HEAP32[i4 >> 2] = i21;
+     i20 = i20 + 65526 & 65535;
+     i22 = i22 & 65535 | i20 << i21;
+     HEAP16[i3 >> 1] = i22;
+     if ((i21 | 0) > 9) {
+      i26 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i26 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i26 | 0] = i22;
+      i26 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+      i27 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i27 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i27 | 0] = i26;
+      i27 = HEAP32[i4 >> 2] | 0;
+      HEAP16[i3 >> 1] = i20 >>> (16 - i27 | 0);
+      HEAP32[i4 >> 2] = i27 + -9;
+      break;
+     } else {
+      HEAP32[i4 >> 2] = i21 + 7;
+      break;
+     }
+    }
+   } else {
+    i20 = i2 + (i15 << 2) + 2686 | 0;
+    i21 = i2 + (i15 << 2) + 2684 | 0;
+    i23 = HEAP32[i4 >> 2] | 0;
+    i26 = HEAP16[i3 >> 1] | 0;
+    do {
+     i24 = HEAPU16[i20 >> 1] | 0;
+     i25 = HEAPU16[i21 >> 1] | 0;
+     i27 = i26 & 65535 | i25 << i23;
+     i26 = i27 & 65535;
+     HEAP16[i3 >> 1] = i26;
+     if ((i23 | 0) > (16 - i24 | 0)) {
+      i26 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i26 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i26 | 0] = i27;
+      i26 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+      i23 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i23 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i23 | 0] = i26;
+      i23 = HEAP32[i4 >> 2] | 0;
+      i26 = i25 >>> (16 - i23 | 0) & 65535;
+      HEAP16[i3 >> 1] = i26;
+      i23 = i24 + -16 + i23 | 0;
+     } else {
+      i23 = i23 + i24 | 0;
+     }
+     HEAP32[i4 >> 2] = i23;
+     i22 = i22 + -1 | 0;
+    } while ((i22 | 0) != 0);
+   }
+  } while (0);
+  if (i19 << 16 >> 16 == 0) {
+   i24 = i15;
+   i21 = 138;
+   i23 = 3;
+   i15 = i16;
+   continue;
+  }
+  i24 = i15;
+  i21 = i17 ? 6 : 7;
+  i23 = i17 ? 3 : 4;
+  i15 = i16;
+ }
+ STACKTOP = i11;
+ return;
+}
+function __tr_flush_block(i2, i4, i6, i3) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i1 = STACKTOP;
+ if ((HEAP32[i2 + 132 >> 2] | 0) > 0) {
+  i5 = (HEAP32[i2 >> 2] | 0) + 44 | 0;
+  if ((HEAP32[i5 >> 2] | 0) == 2) {
+   i8 = -201342849;
+   i9 = 0;
+   while (1) {
+    if ((i8 & 1 | 0) != 0 ? (HEAP16[i2 + (i9 << 2) + 148 >> 1] | 0) != 0 : 0) {
+     i8 = 0;
+     break;
+    }
+    i9 = i9 + 1 | 0;
+    if ((i9 | 0) < 32) {
+     i8 = i8 >>> 1;
+    } else {
+     i7 = 6;
+     break;
+    }
+   }
+   L9 : do {
+    if ((i7 | 0) == 6) {
+     if (((HEAP16[i2 + 184 >> 1] | 0) == 0 ? (HEAP16[i2 + 188 >> 1] | 0) == 0 : 0) ? (HEAP16[i2 + 200 >> 1] | 0) == 0 : 0) {
+      i8 = 32;
+      while (1) {
+       i7 = i8 + 1 | 0;
+       if ((HEAP16[i2 + (i8 << 2) + 148 >> 1] | 0) != 0) {
+        i8 = 1;
+        break L9;
+       }
+       if ((i7 | 0) < 256) {
+        i8 = i7;
+       } else {
+        i8 = 0;
+        break;
+       }
+      }
+     } else {
+      i8 = 1;
+     }
+    }
+   } while (0);
+   HEAP32[i5 >> 2] = i8;
+  }
+  _build_tree(i2, i2 + 2840 | 0);
+  _build_tree(i2, i2 + 2852 | 0);
+  _scan_tree(i2, i2 + 148 | 0, HEAP32[i2 + 2844 >> 2] | 0);
+  _scan_tree(i2, i2 + 2440 | 0, HEAP32[i2 + 2856 >> 2] | 0);
+  _build_tree(i2, i2 + 2864 | 0);
+  i5 = 18;
+  while (1) {
+   i7 = i5 + -1 | 0;
+   if ((HEAP16[i2 + (HEAPU8[2888 + i5 | 0] << 2) + 2686 >> 1] | 0) != 0) {
+    break;
+   }
+   if ((i7 | 0) > 2) {
+    i5 = i7;
+   } else {
+    i5 = i7;
+    break;
+   }
+  }
+  i10 = i2 + 5800 | 0;
+  i7 = (i5 * 3 | 0) + 17 + (HEAP32[i10 >> 2] | 0) | 0;
+  HEAP32[i10 >> 2] = i7;
+  i7 = (i7 + 10 | 0) >>> 3;
+  i10 = ((HEAP32[i2 + 5804 >> 2] | 0) + 10 | 0) >>> 3;
+  i9 = i10 >>> 0 > i7 >>> 0 ? i7 : i10;
+ } else {
+  i10 = i6 + 5 | 0;
+  i5 = 0;
+  i9 = i10;
+ }
+ do {
+  if ((i6 + 4 | 0) >>> 0 > i9 >>> 0 | (i4 | 0) == 0) {
+   i4 = i2 + 5820 | 0;
+   i7 = HEAP32[i4 >> 2] | 0;
+   i8 = (i7 | 0) > 13;
+   if ((HEAP32[i2 + 136 >> 2] | 0) == 4 | (i10 | 0) == (i9 | 0)) {
+    i9 = i3 + 2 & 65535;
+    i6 = i2 + 5816 | 0;
+    i5 = HEAPU16[i6 >> 1] | i9 << i7;
+    HEAP16[i6 >> 1] = i5;
+    if (i8) {
+     i12 = i2 + 20 | 0;
+     i13 = HEAP32[i12 >> 2] | 0;
+     HEAP32[i12 >> 2] = i13 + 1;
+     i14 = i2 + 8 | 0;
+     HEAP8[(HEAP32[i14 >> 2] | 0) + i13 | 0] = i5;
+     i13 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+     i5 = HEAP32[i12 >> 2] | 0;
+     HEAP32[i12 >> 2] = i5 + 1;
+     HEAP8[(HEAP32[i14 >> 2] | 0) + i5 | 0] = i13;
+     i5 = HEAP32[i4 >> 2] | 0;
+     HEAP16[i6 >> 1] = i9 >>> (16 - i5 | 0);
+     i5 = i5 + -13 | 0;
+    } else {
+     i5 = i7 + 3 | 0;
+    }
+    HEAP32[i4 >> 2] = i5;
+    _compress_block(i2, 1136, 2288);
+    break;
+   }
+   i10 = i3 + 4 & 65535;
+   i6 = i2 + 5816 | 0;
+   i9 = HEAPU16[i6 >> 1] | i10 << i7;
+   HEAP16[i6 >> 1] = i9;
+   if (i8) {
+    i13 = i2 + 20 | 0;
+    i12 = HEAP32[i13 >> 2] | 0;
+    HEAP32[i13 >> 2] = i12 + 1;
+    i14 = i2 + 8 | 0;
+    HEAP8[(HEAP32[i14 >> 2] | 0) + i12 | 0] = i9;
+    i9 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+    i12 = HEAP32[i13 >> 2] | 0;
+    HEAP32[i13 >> 2] = i12 + 1;
+    HEAP8[(HEAP32[i14 >> 2] | 0) + i12 | 0] = i9;
+    i12 = HEAP32[i4 >> 2] | 0;
+    i9 = i10 >>> (16 - i12 | 0);
+    HEAP16[i6 >> 1] = i9;
+    i12 = i12 + -13 | 0;
+   } else {
+    i12 = i7 + 3 | 0;
+   }
+   HEAP32[i4 >> 2] = i12;
+   i7 = HEAP32[i2 + 2844 >> 2] | 0;
+   i8 = HEAP32[i2 + 2856 >> 2] | 0;
+   i10 = i7 + 65280 & 65535;
+   i11 = i9 & 65535 | i10 << i12;
+   HEAP16[i6 >> 1] = i11;
+   if ((i12 | 0) > 11) {
+    i13 = i2 + 20 | 0;
+    i9 = HEAP32[i13 >> 2] | 0;
+    HEAP32[i13 >> 2] = i9 + 1;
+    i14 = i2 + 8 | 0;
+    HEAP8[(HEAP32[i14 >> 2] | 0) + i9 | 0] = i11;
+    i11 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+    i9 = HEAP32[i13 >> 2] | 0;
+    HEAP32[i13 >> 2] = i9 + 1;
+    HEAP8[(HEAP32[i14 >> 2] | 0) + i9 | 0] = i11;
+    i9 = HEAP32[i4 >> 2] | 0;
+    i11 = i10 >>> (16 - i9 | 0);
+    HEAP16[i6 >> 1] = i11;
+    i9 = i9 + -11 | 0;
+   } else {
+    i9 = i12 + 5 | 0;
+   }
+   HEAP32[i4 >> 2] = i9;
+   i10 = i8 & 65535;
+   i11 = i10 << i9 | i11 & 65535;
+   HEAP16[i6 >> 1] = i11;
+   if ((i9 | 0) > 11) {
+    i13 = i2 + 20 | 0;
+    i9 = HEAP32[i13 >> 2] | 0;
+    HEAP32[i13 >> 2] = i9 + 1;
+    i14 = i2 + 8 | 0;
+    HEAP8[(HEAP32[i14 >> 2] | 0) + i9 | 0] = i11;
+    i11 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+    i9 = HEAP32[i13 >> 2] | 0;
+    HEAP32[i13 >> 2] = i9 + 1;
+    HEAP8[(HEAP32[i14 >> 2] | 0) + i9 | 0] = i11;
+    i9 = HEAP32[i4 >> 2] | 0;
+    i11 = i10 >>> (16 - i9 | 0);
+    HEAP16[i6 >> 1] = i11;
+    i9 = i9 + -11 | 0;
+   } else {
+    i9 = i9 + 5 | 0;
+   }
+   HEAP32[i4 >> 2] = i9;
+   i10 = i5 + 65533 & 65535;
+   i14 = i10 << i9 | i11 & 65535;
+   HEAP16[i6 >> 1] = i14;
+   if ((i9 | 0) > 12) {
+    i12 = i2 + 20 | 0;
+    i11 = HEAP32[i12 >> 2] | 0;
+    HEAP32[i12 >> 2] = i11 + 1;
+    i13 = i2 + 8 | 0;
+    HEAP8[(HEAP32[i13 >> 2] | 0) + i11 | 0] = i14;
+    i14 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+    i11 = HEAP32[i12 >> 2] | 0;
+    HEAP32[i12 >> 2] = i11 + 1;
+    HEAP8[(HEAP32[i13 >> 2] | 0) + i11 | 0] = i14;
+    i11 = HEAP32[i4 >> 2] | 0;
+    i14 = i10 >>> (16 - i11 | 0);
+    HEAP16[i6 >> 1] = i14;
+    i11 = i11 + -12 | 0;
+   } else {
+    i11 = i9 + 4 | 0;
+   }
+   HEAP32[i4 >> 2] = i11;
+   if ((i5 | 0) > -1) {
+    i10 = i2 + 20 | 0;
+    i9 = i2 + 8 | 0;
+    i12 = 0;
+    while (1) {
+     i13 = HEAPU16[i2 + (HEAPU8[2888 + i12 | 0] << 2) + 2686 >> 1] | 0;
+     i14 = i13 << i11 | i14 & 65535;
+     HEAP16[i6 >> 1] = i14;
+     if ((i11 | 0) > 13) {
+      i11 = HEAP32[i10 >> 2] | 0;
+      HEAP32[i10 >> 2] = i11 + 1;
+      HEAP8[(HEAP32[i9 >> 2] | 0) + i11 | 0] = i14;
+      i14 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+      i11 = HEAP32[i10 >> 2] | 0;
+      HEAP32[i10 >> 2] = i11 + 1;
+      HEAP8[(HEAP32[i9 >> 2] | 0) + i11 | 0] = i14;
+      i11 = HEAP32[i4 >> 2] | 0;
+      i14 = i13 >>> (16 - i11 | 0);
+      HEAP16[i6 >> 1] = i14;
+      i11 = i11 + -13 | 0;
+     } else {
+      i11 = i11 + 3 | 0;
+     }
+     HEAP32[i4 >> 2] = i11;
+     if ((i12 | 0) == (i5 | 0)) {
+      break;
+     } else {
+      i12 = i12 + 1 | 0;
+     }
+    }
+   }
+   i13 = i2 + 148 | 0;
+   _send_tree(i2, i13, i7);
+   i14 = i2 + 2440 | 0;
+   _send_tree(i2, i14, i8);
+   _compress_block(i2, i13, i14);
+  } else {
+   __tr_stored_block(i2, i4, i6, i3);
+  }
+ } while (0);
+ _init_block(i2);
+ if ((i3 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i3 = i2 + 5820 | 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ if ((i4 | 0) <= 8) {
+  i5 = i2 + 5816 | 0;
+  if ((i4 | 0) > 0) {
+   i13 = HEAP16[i5 >> 1] & 255;
+   i12 = i2 + 20 | 0;
+   i14 = HEAP32[i12 >> 2] | 0;
+   HEAP32[i12 >> 2] = i14 + 1;
+   HEAP8[(HEAP32[i2 + 8 >> 2] | 0) + i14 | 0] = i13;
+  }
+ } else {
+  i5 = i2 + 5816 | 0;
+  i14 = HEAP16[i5 >> 1] & 255;
+  i11 = i2 + 20 | 0;
+  i12 = HEAP32[i11 >> 2] | 0;
+  HEAP32[i11 >> 2] = i12 + 1;
+  i13 = i2 + 8 | 0;
+  HEAP8[(HEAP32[i13 >> 2] | 0) + i12 | 0] = i14;
+  i12 = (HEAPU16[i5 >> 1] | 0) >>> 8 & 255;
+  i14 = HEAP32[i11 >> 2] | 0;
+  HEAP32[i11 >> 2] = i14 + 1;
+  HEAP8[(HEAP32[i13 >> 2] | 0) + i14 | 0] = i12;
+ }
+ HEAP16[i5 >> 1] = 0;
+ HEAP32[i3 >> 2] = 0;
+ STACKTOP = i1;
+ return;
+}
+function _deflate_fast(i3, i6) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0;
+ i1 = STACKTOP;
+ i20 = i3 + 116 | 0;
+ i22 = (i6 | 0) == 0;
+ i23 = i3 + 72 | 0;
+ i24 = i3 + 88 | 0;
+ i5 = i3 + 108 | 0;
+ i7 = i3 + 56 | 0;
+ i9 = i3 + 84 | 0;
+ i10 = i3 + 68 | 0;
+ i11 = i3 + 52 | 0;
+ i12 = i3 + 64 | 0;
+ i19 = i3 + 44 | 0;
+ i21 = i3 + 96 | 0;
+ i16 = i3 + 112 | 0;
+ i13 = i3 + 5792 | 0;
+ i17 = i3 + 5796 | 0;
+ i18 = i3 + 5784 | 0;
+ i14 = i3 + 5788 | 0;
+ i15 = i3 + 128 | 0;
+ i4 = i3 + 92 | 0;
+ while (1) {
+  if ((HEAP32[i20 >> 2] | 0) >>> 0 < 262) {
+   _fill_window(i3);
+   i25 = HEAP32[i20 >> 2] | 0;
+   if (i25 >>> 0 < 262 & i22) {
+    i2 = 0;
+    i25 = 34;
+    break;
+   }
+   if ((i25 | 0) == 0) {
+    i25 = 26;
+    break;
+   }
+   if (!(i25 >>> 0 > 2)) {
+    i25 = 9;
+   } else {
+    i25 = 6;
+   }
+  } else {
+   i25 = 6;
+  }
+  if ((i25 | 0) == 6) {
+   i25 = 0;
+   i26 = HEAP32[i5 >> 2] | 0;
+   i34 = ((HEAPU8[(HEAP32[i7 >> 2] | 0) + (i26 + 2) | 0] | 0) ^ HEAP32[i23 >> 2] << HEAP32[i24 >> 2]) & HEAP32[i9 >> 2];
+   HEAP32[i23 >> 2] = i34;
+   i34 = (HEAP32[i10 >> 2] | 0) + (i34 << 1) | 0;
+   i35 = HEAP16[i34 >> 1] | 0;
+   HEAP16[(HEAP32[i12 >> 2] | 0) + ((HEAP32[i11 >> 2] & i26) << 1) >> 1] = i35;
+   i27 = i35 & 65535;
+   HEAP16[i34 >> 1] = i26;
+   if (!(i35 << 16 >> 16 == 0) ? !((i26 - i27 | 0) >>> 0 > ((HEAP32[i19 >> 2] | 0) + -262 | 0) >>> 0) : 0) {
+    i26 = _longest_match(i3, i27) | 0;
+    HEAP32[i21 >> 2] = i26;
+   } else {
+    i25 = 9;
+   }
+  }
+  if ((i25 | 0) == 9) {
+   i26 = HEAP32[i21 >> 2] | 0;
+  }
+  do {
+   if (i26 >>> 0 > 2) {
+    i35 = i26 + 253 | 0;
+    i25 = (HEAP32[i5 >> 2] | 0) - (HEAP32[i16 >> 2] | 0) | 0;
+    i34 = HEAP32[i13 >> 2] | 0;
+    HEAP16[(HEAP32[i17 >> 2] | 0) + (i34 << 1) >> 1] = i25;
+    HEAP32[i13 >> 2] = i34 + 1;
+    HEAP8[(HEAP32[i18 >> 2] | 0) + i34 | 0] = i35;
+    i35 = i3 + ((HEAPU8[808 + (i35 & 255) | 0] | 0 | 256) + 1 << 2) + 148 | 0;
+    HEAP16[i35 >> 1] = (HEAP16[i35 >> 1] | 0) + 1 << 16 >> 16;
+    i25 = i25 + 65535 & 65535;
+    if (!(i25 >>> 0 < 256)) {
+     i25 = (i25 >>> 7) + 256 | 0;
+    }
+    i25 = i3 + ((HEAPU8[296 + i25 | 0] | 0) << 2) + 2440 | 0;
+    HEAP16[i25 >> 1] = (HEAP16[i25 >> 1] | 0) + 1 << 16 >> 16;
+    i25 = (HEAP32[i13 >> 2] | 0) == ((HEAP32[i14 >> 2] | 0) + -1 | 0) | 0;
+    i26 = HEAP32[i21 >> 2] | 0;
+    i35 = (HEAP32[i20 >> 2] | 0) - i26 | 0;
+    HEAP32[i20 >> 2] = i35;
+    if (!(i26 >>> 0 <= (HEAP32[i15 >> 2] | 0) >>> 0 & i35 >>> 0 > 2)) {
+     i26 = (HEAP32[i5 >> 2] | 0) + i26 | 0;
+     HEAP32[i5 >> 2] = i26;
+     HEAP32[i21 >> 2] = 0;
+     i34 = HEAP32[i7 >> 2] | 0;
+     i35 = HEAPU8[i34 + i26 | 0] | 0;
+     HEAP32[i23 >> 2] = i35;
+     HEAP32[i23 >> 2] = ((HEAPU8[i34 + (i26 + 1) | 0] | 0) ^ i35 << HEAP32[i24 >> 2]) & HEAP32[i9 >> 2];
+     break;
+    }
+    i30 = i26 + -1 | 0;
+    HEAP32[i21 >> 2] = i30;
+    i34 = HEAP32[i24 >> 2] | 0;
+    i33 = HEAP32[i7 >> 2] | 0;
+    i35 = HEAP32[i9 >> 2] | 0;
+    i32 = HEAP32[i10 >> 2] | 0;
+    i27 = HEAP32[i11 >> 2] | 0;
+    i29 = HEAP32[i12 >> 2] | 0;
+    i26 = HEAP32[i5 >> 2] | 0;
+    i31 = HEAP32[i23 >> 2] | 0;
+    while (1) {
+     i28 = i26 + 1 | 0;
+     HEAP32[i5 >> 2] = i28;
+     i31 = ((HEAPU8[i33 + (i26 + 3) | 0] | 0) ^ i31 << i34) & i35;
+     HEAP32[i23 >> 2] = i31;
+     i36 = i32 + (i31 << 1) | 0;
+     HEAP16[i29 + ((i27 & i28) << 1) >> 1] = HEAP16[i36 >> 1] | 0;
+     HEAP16[i36 >> 1] = i28;
+     i30 = i30 + -1 | 0;
+     HEAP32[i21 >> 2] = i30;
+     if ((i30 | 0) == 0) {
+      break;
+     } else {
+      i26 = i28;
+     }
+    }
+    i26 = i26 + 2 | 0;
+    HEAP32[i5 >> 2] = i26;
+   } else {
+    i25 = HEAP8[(HEAP32[i7 >> 2] | 0) + (HEAP32[i5 >> 2] | 0) | 0] | 0;
+    i26 = HEAP32[i13 >> 2] | 0;
+    HEAP16[(HEAP32[i17 >> 2] | 0) + (i26 << 1) >> 1] = 0;
+    HEAP32[i13 >> 2] = i26 + 1;
+    HEAP8[(HEAP32[i18 >> 2] | 0) + i26 | 0] = i25;
+    i25 = i3 + ((i25 & 255) << 2) + 148 | 0;
+    HEAP16[i25 >> 1] = (HEAP16[i25 >> 1] | 0) + 1 << 16 >> 16;
+    i25 = (HEAP32[i13 >> 2] | 0) == ((HEAP32[i14 >> 2] | 0) + -1 | 0) | 0;
+    HEAP32[i20 >> 2] = (HEAP32[i20 >> 2] | 0) + -1;
+    i26 = (HEAP32[i5 >> 2] | 0) + 1 | 0;
+    HEAP32[i5 >> 2] = i26;
+   }
+  } while (0);
+  if ((i25 | 0) == 0) {
+   continue;
+  }
+  i25 = HEAP32[i4 >> 2] | 0;
+  if ((i25 | 0) > -1) {
+   i27 = (HEAP32[i7 >> 2] | 0) + i25 | 0;
+  } else {
+   i27 = 0;
+  }
+  __tr_flush_block(i3, i27, i26 - i25 | 0, 0);
+  HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+  i27 = HEAP32[i3 >> 2] | 0;
+  i28 = i27 + 28 | 0;
+  i25 = HEAP32[i28 >> 2] | 0;
+  i30 = HEAP32[i25 + 20 >> 2] | 0;
+  i26 = i27 + 16 | 0;
+  i29 = HEAP32[i26 >> 2] | 0;
+  i29 = i30 >>> 0 > i29 >>> 0 ? i29 : i30;
+  if ((i29 | 0) != 0 ? (i8 = i27 + 12 | 0, _memcpy(HEAP32[i8 >> 2] | 0, HEAP32[i25 + 16 >> 2] | 0, i29 | 0) | 0, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) + i29, i8 = (HEAP32[i28 >> 2] | 0) + 16 | 0, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) + i29, i8 = i27 + 20 | 0, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) + i29, HEAP32[i26 >> 2] = (HEAP32[i26 >> 2] | 0) - i29, i8 = HEAP32[i28 >> 2] | 0, i35 = i8 + 20 | 0, i36 = HEAP32[i35 >> 2] | 0, HEAP32[i35 >> 2] = i36 - i29, (i36 | 0) == (i29 | 0)) : 0) {
+   HEAP32[i8 + 16 >> 2] = HEAP32[i8 + 8 >> 2];
+  }
+  if ((HEAP32[(HEAP32[i3 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+   i2 = 0;
+   i25 = 34;
+   break;
+  }
+ }
+ if ((i25 | 0) == 26) {
+  i8 = HEAP32[i4 >> 2] | 0;
+  if ((i8 | 0) > -1) {
+   i7 = (HEAP32[i7 >> 2] | 0) + i8 | 0;
+  } else {
+   i7 = 0;
+  }
+  i6 = (i6 | 0) == 4;
+  __tr_flush_block(i3, i7, (HEAP32[i5 >> 2] | 0) - i8 | 0, i6 & 1);
+  HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+  i5 = HEAP32[i3 >> 2] | 0;
+  i7 = i5 + 28 | 0;
+  i4 = HEAP32[i7 >> 2] | 0;
+  i10 = HEAP32[i4 + 20 >> 2] | 0;
+  i8 = i5 + 16 | 0;
+  i9 = HEAP32[i8 >> 2] | 0;
+  i9 = i10 >>> 0 > i9 >>> 0 ? i9 : i10;
+  if ((i9 | 0) != 0 ? (i2 = i5 + 12 | 0, _memcpy(HEAP32[i2 >> 2] | 0, HEAP32[i4 + 16 >> 2] | 0, i9 | 0) | 0, HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + i9, i2 = (HEAP32[i7 >> 2] | 0) + 16 | 0, HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + i9, i2 = i5 + 20 | 0, HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + i9, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) - i9, i2 = HEAP32[i7 >> 2] | 0, i35 = i2 + 20 | 0, i36 = HEAP32[i35 >> 2] | 0, HEAP32[i35 >> 2] = i36 - i9, (i36 | 0) == (i9 | 0)) : 0) {
+   HEAP32[i2 + 16 >> 2] = HEAP32[i2 + 8 >> 2];
+  }
+  if ((HEAP32[(HEAP32[i3 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+   i36 = i6 ? 2 : 0;
+   STACKTOP = i1;
+   return i36 | 0;
+  } else {
+   i36 = i6 ? 3 : 1;
+   STACKTOP = i1;
+   return i36 | 0;
+  }
+ } else if ((i25 | 0) == 34) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ return 0;
+}
+function _inflate_table(i11, i5, i13, i2, i1, i10) {
+ i11 = i11 | 0;
+ i5 = i5 | 0;
+ i13 = i13 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ i10 = i10 | 0;
+ var i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i12 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i7 = i3 + 32 | 0;
+ i12 = i3;
+ i4 = i7 + 0 | 0;
+ i9 = i4 + 32 | 0;
+ do {
+  HEAP16[i4 >> 1] = 0;
+  i4 = i4 + 2 | 0;
+ } while ((i4 | 0) < (i9 | 0));
+ i14 = (i13 | 0) == 0;
+ if (!i14) {
+  i4 = 0;
+  do {
+   i32 = i7 + (HEAPU16[i5 + (i4 << 1) >> 1] << 1) | 0;
+   HEAP16[i32 >> 1] = (HEAP16[i32 >> 1] | 0) + 1 << 16 >> 16;
+   i4 = i4 + 1 | 0;
+  } while ((i4 | 0) != (i13 | 0));
+ }
+ i4 = HEAP32[i1 >> 2] | 0;
+ i9 = 15;
+ while (1) {
+  i15 = i9 + -1 | 0;
+  if ((HEAP16[i7 + (i9 << 1) >> 1] | 0) != 0) {
+   break;
+  }
+  if ((i15 | 0) == 0) {
+   i6 = 7;
+   break;
+  } else {
+   i9 = i15;
+  }
+ }
+ if ((i6 | 0) == 7) {
+  i32 = HEAP32[i2 >> 2] | 0;
+  HEAP32[i2 >> 2] = i32 + 4;
+  HEAP8[i32] = 64;
+  HEAP8[i32 + 1 | 0] = 1;
+  HEAP16[i32 + 2 >> 1] = 0;
+  i32 = HEAP32[i2 >> 2] | 0;
+  HEAP32[i2 >> 2] = i32 + 4;
+  HEAP8[i32] = 64;
+  HEAP8[i32 + 1 | 0] = 1;
+  HEAP16[i32 + 2 >> 1] = 0;
+  HEAP32[i1 >> 2] = 1;
+  i32 = 0;
+  STACKTOP = i3;
+  return i32 | 0;
+ }
+ i4 = i4 >>> 0 > i9 >>> 0 ? i9 : i4;
+ L12 : do {
+  if (i9 >>> 0 > 1) {
+   i27 = 1;
+   while (1) {
+    i15 = i27 + 1 | 0;
+    if ((HEAP16[i7 + (i27 << 1) >> 1] | 0) != 0) {
+     break L12;
+    }
+    if (i15 >>> 0 < i9 >>> 0) {
+     i27 = i15;
+    } else {
+     i27 = i15;
+     break;
+    }
+   }
+  } else {
+   i27 = 1;
+  }
+ } while (0);
+ i4 = i4 >>> 0 < i27 >>> 0 ? i27 : i4;
+ i16 = 1;
+ i15 = 1;
+ do {
+  i16 = (i16 << 1) - (HEAPU16[i7 + (i15 << 1) >> 1] | 0) | 0;
+  i15 = i15 + 1 | 0;
+  if ((i16 | 0) < 0) {
+   i8 = -1;
+   i6 = 56;
+   break;
+  }
+ } while (i15 >>> 0 < 16);
+ if ((i6 | 0) == 56) {
+  STACKTOP = i3;
+  return i8 | 0;
+ }
+ if ((i16 | 0) > 0 ? !((i11 | 0) != 0 & (i9 | 0) == 1) : 0) {
+  i32 = -1;
+  STACKTOP = i3;
+  return i32 | 0;
+ }
+ HEAP16[i12 + 2 >> 1] = 0;
+ i16 = 0;
+ i15 = 1;
+ do {
+  i16 = (HEAPU16[i7 + (i15 << 1) >> 1] | 0) + (i16 & 65535) | 0;
+  i15 = i15 + 1 | 0;
+  HEAP16[i12 + (i15 << 1) >> 1] = i16;
+ } while ((i15 | 0) != 15);
+ if (!i14) {
+  i15 = 0;
+  do {
+   i14 = HEAP16[i5 + (i15 << 1) >> 1] | 0;
+   if (!(i14 << 16 >> 16 == 0)) {
+    i31 = i12 + ((i14 & 65535) << 1) | 0;
+    i32 = HEAP16[i31 >> 1] | 0;
+    HEAP16[i31 >> 1] = i32 + 1 << 16 >> 16;
+    HEAP16[i10 + ((i32 & 65535) << 1) >> 1] = i15;
+   }
+   i15 = i15 + 1 | 0;
+  } while ((i15 | 0) != (i13 | 0));
+ }
+ if ((i11 | 0) == 1) {
+  i14 = 1 << i4;
+  if (i14 >>> 0 > 851) {
+   i32 = 1;
+   STACKTOP = i3;
+   return i32 | 0;
+  } else {
+   i16 = 0;
+   i20 = 1;
+   i17 = 14128 + -514 | 0;
+   i19 = 256;
+   i18 = 14192 + -514 | 0;
+  }
+ } else if ((i11 | 0) != 0) {
+  i14 = 1 << i4;
+  i16 = (i11 | 0) == 2;
+  if (i16 & i14 >>> 0 > 591) {
+   i32 = 1;
+   STACKTOP = i3;
+   return i32 | 0;
+  } else {
+   i20 = 0;
+   i17 = 14256;
+   i19 = -1;
+   i18 = 14320;
+  }
+ } else {
+  i16 = 0;
+  i14 = 1 << i4;
+  i20 = 0;
+  i17 = i10;
+  i19 = 19;
+  i18 = i10;
+ }
+ i11 = i14 + -1 | 0;
+ i12 = i4 & 255;
+ i22 = i4;
+ i21 = 0;
+ i25 = 0;
+ i13 = -1;
+ i15 = HEAP32[i2 >> 2] | 0;
+ i24 = 0;
+ L44 : while (1) {
+  i23 = 1 << i22;
+  while (1) {
+   i29 = i27 - i21 | 0;
+   i22 = i29 & 255;
+   i28 = HEAP16[i10 + (i24 << 1) >> 1] | 0;
+   i30 = i28 & 65535;
+   if ((i30 | 0) >= (i19 | 0)) {
+    if ((i30 | 0) > (i19 | 0)) {
+     i26 = HEAP16[i18 + (i30 << 1) >> 1] & 255;
+     i28 = HEAP16[i17 + (i30 << 1) >> 1] | 0;
+    } else {
+     i26 = 96;
+     i28 = 0;
+    }
+   } else {
+    i26 = 0;
+   }
+   i31 = 1 << i29;
+   i30 = i25 >>> i21;
+   i32 = i23;
+   while (1) {
+    i29 = i32 - i31 | 0;
+    i33 = i29 + i30 | 0;
+    HEAP8[i15 + (i33 << 2) | 0] = i26;
+    HEAP8[i15 + (i33 << 2) + 1 | 0] = i22;
+    HEAP16[i15 + (i33 << 2) + 2 >> 1] = i28;
+    if ((i32 | 0) == (i31 | 0)) {
+     break;
+    } else {
+     i32 = i29;
+    }
+   }
+   i26 = 1 << i27 + -1;
+   while (1) {
+    if ((i26 & i25 | 0) == 0) {
+     break;
+    } else {
+     i26 = i26 >>> 1;
+    }
+   }
+   if ((i26 | 0) == 0) {
+    i25 = 0;
+   } else {
+    i25 = (i26 + -1 & i25) + i26 | 0;
+   }
+   i24 = i24 + 1 | 0;
+   i32 = i7 + (i27 << 1) | 0;
+   i33 = (HEAP16[i32 >> 1] | 0) + -1 << 16 >> 16;
+   HEAP16[i32 >> 1] = i33;
+   if (i33 << 16 >> 16 == 0) {
+    if ((i27 | 0) == (i9 | 0)) {
+     break L44;
+    }
+    i27 = HEAPU16[i5 + (HEAPU16[i10 + (i24 << 1) >> 1] << 1) >> 1] | 0;
+   }
+   if (!(i27 >>> 0 > i4 >>> 0)) {
+    continue;
+   }
+   i26 = i25 & i11;
+   if ((i26 | 0) != (i13 | 0)) {
+    break;
+   }
+  }
+  i28 = (i21 | 0) == 0 ? i4 : i21;
+  i23 = i15 + (i23 << 2) | 0;
+  i31 = i27 - i28 | 0;
+  L67 : do {
+   if (i27 >>> 0 < i9 >>> 0) {
+    i29 = i27;
+    i30 = i31;
+    i31 = 1 << i31;
+    while (1) {
+     i31 = i31 - (HEAPU16[i7 + (i29 << 1) >> 1] | 0) | 0;
+     if ((i31 | 0) < 1) {
+      break L67;
+     }
+     i30 = i30 + 1 | 0;
+     i29 = i30 + i28 | 0;
+     if (i29 >>> 0 < i9 >>> 0) {
+      i31 = i31 << 1;
+     } else {
+      break;
+     }
+    }
+   } else {
+    i30 = i31;
+   }
+  } while (0);
+  i29 = (1 << i30) + i14 | 0;
+  if (i20 & i29 >>> 0 > 851 | i16 & i29 >>> 0 > 591) {
+   i8 = 1;
+   i6 = 56;
+   break;
+  }
+  HEAP8[(HEAP32[i2 >> 2] | 0) + (i26 << 2) | 0] = i30;
+  HEAP8[(HEAP32[i2 >> 2] | 0) + (i26 << 2) + 1 | 0] = i12;
+  i22 = HEAP32[i2 >> 2] | 0;
+  HEAP16[i22 + (i26 << 2) + 2 >> 1] = (i23 - i22 | 0) >>> 2;
+  i22 = i30;
+  i21 = i28;
+  i13 = i26;
+  i15 = i23;
+  i14 = i29;
+ }
+ if ((i6 | 0) == 56) {
+  STACKTOP = i3;
+  return i8 | 0;
+ }
+ L77 : do {
+  if ((i25 | 0) != 0) {
+   do {
+    if ((i21 | 0) != 0) {
+     if ((i25 & i11 | 0) != (i13 | 0)) {
+      i21 = 0;
+      i22 = i12;
+      i9 = i4;
+      i15 = HEAP32[i2 >> 2] | 0;
+     }
+    } else {
+     i21 = 0;
+    }
+    i5 = i25 >>> i21;
+    HEAP8[i15 + (i5 << 2) | 0] = 64;
+    HEAP8[i15 + (i5 << 2) + 1 | 0] = i22;
+    HEAP16[i15 + (i5 << 2) + 2 >> 1] = 0;
+    i5 = 1 << i9 + -1;
+    while (1) {
+     if ((i5 & i25 | 0) == 0) {
+      break;
+     } else {
+      i5 = i5 >>> 1;
+     }
+    }
+    if ((i5 | 0) == 0) {
+     break L77;
+    }
+    i25 = (i5 + -1 & i25) + i5 | 0;
+   } while ((i25 | 0) != 0);
+  }
+ } while (0);
+ HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + (i14 << 2);
+ HEAP32[i1 >> 2] = i4;
+ i33 = 0;
+ STACKTOP = i3;
+ return i33 | 0;
+}
+function _compress_block(i1, i3, i7) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0;
+ i2 = STACKTOP;
+ i11 = i1 + 5792 | 0;
+ if ((HEAP32[i11 >> 2] | 0) == 0) {
+  i14 = HEAP32[i1 + 5820 >> 2] | 0;
+  i17 = HEAP16[i1 + 5816 >> 1] | 0;
+ } else {
+  i9 = i1 + 5796 | 0;
+  i10 = i1 + 5784 | 0;
+  i8 = i1 + 5820 | 0;
+  i12 = i1 + 5816 | 0;
+  i5 = i1 + 20 | 0;
+  i6 = i1 + 8 | 0;
+  i14 = 0;
+  while (1) {
+   i20 = HEAP16[(HEAP32[i9 >> 2] | 0) + (i14 << 1) >> 1] | 0;
+   i13 = i20 & 65535;
+   i4 = i14 + 1 | 0;
+   i14 = HEAPU8[(HEAP32[i10 >> 2] | 0) + i14 | 0] | 0;
+   do {
+    if (i20 << 16 >> 16 == 0) {
+     i15 = HEAPU16[i3 + (i14 << 2) + 2 >> 1] | 0;
+     i13 = HEAP32[i8 >> 2] | 0;
+     i14 = HEAPU16[i3 + (i14 << 2) >> 1] | 0;
+     i16 = HEAPU16[i12 >> 1] | 0 | i14 << i13;
+     i17 = i16 & 65535;
+     HEAP16[i12 >> 1] = i17;
+     if ((i13 | 0) > (16 - i15 | 0)) {
+      i17 = HEAP32[i5 >> 2] | 0;
+      HEAP32[i5 >> 2] = i17 + 1;
+      HEAP8[(HEAP32[i6 >> 2] | 0) + i17 | 0] = i16;
+      i17 = (HEAPU16[i12 >> 1] | 0) >>> 8 & 255;
+      i20 = HEAP32[i5 >> 2] | 0;
+      HEAP32[i5 >> 2] = i20 + 1;
+      HEAP8[(HEAP32[i6 >> 2] | 0) + i20 | 0] = i17;
+      i20 = HEAP32[i8 >> 2] | 0;
+      i17 = i14 >>> (16 - i20 | 0) & 65535;
+      HEAP16[i12 >> 1] = i17;
+      i14 = i15 + -16 + i20 | 0;
+      HEAP32[i8 >> 2] = i14;
+      break;
+     } else {
+      i14 = i13 + i15 | 0;
+      HEAP32[i8 >> 2] = i14;
+      break;
+     }
+    } else {
+     i15 = HEAPU8[808 + i14 | 0] | 0;
+     i19 = (i15 | 256) + 1 | 0;
+     i18 = HEAPU16[i3 + (i19 << 2) + 2 >> 1] | 0;
+     i17 = HEAP32[i8 >> 2] | 0;
+     i19 = HEAPU16[i3 + (i19 << 2) >> 1] | 0;
+     i20 = HEAPU16[i12 >> 1] | 0 | i19 << i17;
+     i16 = i20 & 65535;
+     HEAP16[i12 >> 1] = i16;
+     if ((i17 | 0) > (16 - i18 | 0)) {
+      i16 = HEAP32[i5 >> 2] | 0;
+      HEAP32[i5 >> 2] = i16 + 1;
+      HEAP8[(HEAP32[i6 >> 2] | 0) + i16 | 0] = i20;
+      i16 = (HEAPU16[i12 >> 1] | 0) >>> 8 & 255;
+      i20 = HEAP32[i5 >> 2] | 0;
+      HEAP32[i5 >> 2] = i20 + 1;
+      HEAP8[(HEAP32[i6 >> 2] | 0) + i20 | 0] = i16;
+      i20 = HEAP32[i8 >> 2] | 0;
+      i16 = i19 >>> (16 - i20 | 0) & 65535;
+      HEAP16[i12 >> 1] = i16;
+      i18 = i18 + -16 + i20 | 0;
+     } else {
+      i18 = i17 + i18 | 0;
+     }
+     HEAP32[i8 >> 2] = i18;
+     i17 = HEAP32[2408 + (i15 << 2) >> 2] | 0;
+     do {
+      if ((i15 + -8 | 0) >>> 0 < 20) {
+       i14 = i14 - (HEAP32[2528 + (i15 << 2) >> 2] | 0) & 65535;
+       i15 = i14 << i18 | i16 & 65535;
+       i16 = i15 & 65535;
+       HEAP16[i12 >> 1] = i16;
+       if ((i18 | 0) > (16 - i17 | 0)) {
+        i16 = HEAP32[i5 >> 2] | 0;
+        HEAP32[i5 >> 2] = i16 + 1;
+        HEAP8[(HEAP32[i6 >> 2] | 0) + i16 | 0] = i15;
+        i16 = (HEAPU16[i12 >> 1] | 0) >>> 8 & 255;
+        i20 = HEAP32[i5 >> 2] | 0;
+        HEAP32[i5 >> 2] = i20 + 1;
+        HEAP8[(HEAP32[i6 >> 2] | 0) + i20 | 0] = i16;
+        i20 = HEAP32[i8 >> 2] | 0;
+        i16 = i14 >>> (16 - i20 | 0) & 65535;
+        HEAP16[i12 >> 1] = i16;
+        i14 = i17 + -16 + i20 | 0;
+        HEAP32[i8 >> 2] = i14;
+        break;
+       } else {
+        i14 = i18 + i17 | 0;
+        HEAP32[i8 >> 2] = i14;
+        break;
+       }
+      } else {
+       i14 = i18;
+      }
+     } while (0);
+     i13 = i13 + -1 | 0;
+     if (i13 >>> 0 < 256) {
+      i15 = i13;
+     } else {
+      i15 = (i13 >>> 7) + 256 | 0;
+     }
+     i15 = HEAPU8[296 + i15 | 0] | 0;
+     i17 = HEAPU16[i7 + (i15 << 2) + 2 >> 1] | 0;
+     i18 = HEAPU16[i7 + (i15 << 2) >> 1] | 0;
+     i19 = i16 & 65535 | i18 << i14;
+     i16 = i19 & 65535;
+     HEAP16[i12 >> 1] = i16;
+     if ((i14 | 0) > (16 - i17 | 0)) {
+      i20 = HEAP32[i5 >> 2] | 0;
+      HEAP32[i5 >> 2] = i20 + 1;
+      HEAP8[(HEAP32[i6 >> 2] | 0) + i20 | 0] = i19;
+      i20 = (HEAPU16[i12 >> 1] | 0) >>> 8 & 255;
+      i14 = HEAP32[i5 >> 2] | 0;
+      HEAP32[i5 >> 2] = i14 + 1;
+      HEAP8[(HEAP32[i6 >> 2] | 0) + i14 | 0] = i20;
+      i14 = HEAP32[i8 >> 2] | 0;
+      i20 = i18 >>> (16 - i14 | 0) & 65535;
+      HEAP16[i12 >> 1] = i20;
+      i14 = i17 + -16 + i14 | 0;
+      i17 = i20;
+     } else {
+      i14 = i14 + i17 | 0;
+      i17 = i16;
+     }
+     HEAP32[i8 >> 2] = i14;
+     i16 = HEAP32[2648 + (i15 << 2) >> 2] | 0;
+     if ((i15 + -4 | 0) >>> 0 < 26) {
+      i13 = i13 - (HEAP32[2768 + (i15 << 2) >> 2] | 0) & 65535;
+      i15 = i13 << i14 | i17 & 65535;
+      i17 = i15 & 65535;
+      HEAP16[i12 >> 1] = i17;
+      if ((i14 | 0) > (16 - i16 | 0)) {
+       i17 = HEAP32[i5 >> 2] | 0;
+       HEAP32[i5 >> 2] = i17 + 1;
+       HEAP8[(HEAP32[i6 >> 2] | 0) + i17 | 0] = i15;
+       i17 = (HEAPU16[i12 >> 1] | 0) >>> 8 & 255;
+       i14 = HEAP32[i5 >> 2] | 0;
+       HEAP32[i5 >> 2] = i14 + 1;
+       HEAP8[(HEAP32[i6 >> 2] | 0) + i14 | 0] = i17;
+       i14 = HEAP32[i8 >> 2] | 0;
+       i17 = i13 >>> (16 - i14 | 0) & 65535;
+       HEAP16[i12 >> 1] = i17;
+       i14 = i16 + -16 + i14 | 0;
+       HEAP32[i8 >> 2] = i14;
+       break;
+      } else {
+       i14 = i14 + i16 | 0;
+       HEAP32[i8 >> 2] = i14;
+       break;
+      }
+     }
+    }
+   } while (0);
+   if (i4 >>> 0 < (HEAP32[i11 >> 2] | 0) >>> 0) {
+    i14 = i4;
+   } else {
+    break;
+   }
+  }
+ }
+ i5 = i3 + 1026 | 0;
+ i6 = HEAPU16[i5 >> 1] | 0;
+ i4 = i1 + 5820 | 0;
+ i3 = HEAPU16[i3 + 1024 >> 1] | 0;
+ i7 = i1 + 5816 | 0;
+ i8 = i17 & 65535 | i3 << i14;
+ HEAP16[i7 >> 1] = i8;
+ if ((i14 | 0) > (16 - i6 | 0)) {
+  i17 = i1 + 20 | 0;
+  i18 = HEAP32[i17 >> 2] | 0;
+  HEAP32[i17 >> 2] = i18 + 1;
+  i20 = i1 + 8 | 0;
+  HEAP8[(HEAP32[i20 >> 2] | 0) + i18 | 0] = i8;
+  i18 = (HEAPU16[i7 >> 1] | 0) >>> 8 & 255;
+  i19 = HEAP32[i17 >> 2] | 0;
+  HEAP32[i17 >> 2] = i19 + 1;
+  HEAP8[(HEAP32[i20 >> 2] | 0) + i19 | 0] = i18;
+  i19 = HEAP32[i4 >> 2] | 0;
+  HEAP16[i7 >> 1] = i3 >>> (16 - i19 | 0);
+  i19 = i6 + -16 + i19 | 0;
+  HEAP32[i4 >> 2] = i19;
+  i19 = HEAP16[i5 >> 1] | 0;
+  i19 = i19 & 65535;
+  i20 = i1 + 5812 | 0;
+  HEAP32[i20 >> 2] = i19;
+  STACKTOP = i2;
+  return;
+ } else {
+  i19 = i14 + i6 | 0;
+  HEAP32[i4 >> 2] = i19;
+  i19 = HEAP16[i5 >> 1] | 0;
+  i19 = i19 & 65535;
+  i20 = i1 + 5812 | 0;
+  HEAP32[i20 >> 2] = i19;
+  STACKTOP = i2;
+  return;
+ }
+}
+function _deflate_stored(i2, i5) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0;
+ i1 = STACKTOP;
+ i4 = (HEAP32[i2 + 12 >> 2] | 0) + -5 | 0;
+ i11 = i4 >>> 0 < 65535 ? i4 : 65535;
+ i12 = i2 + 116 | 0;
+ i4 = i2 + 108 | 0;
+ i6 = i2 + 92 | 0;
+ i10 = i2 + 44 | 0;
+ i7 = i2 + 56 | 0;
+ while (1) {
+  i13 = HEAP32[i12 >> 2] | 0;
+  if (i13 >>> 0 < 2) {
+   _fill_window(i2);
+   i13 = HEAP32[i12 >> 2] | 0;
+   if ((i13 | i5 | 0) == 0) {
+    i2 = 0;
+    i8 = 28;
+    break;
+   }
+   if ((i13 | 0) == 0) {
+    i8 = 20;
+    break;
+   }
+  }
+  i13 = (HEAP32[i4 >> 2] | 0) + i13 | 0;
+  HEAP32[i4 >> 2] = i13;
+  HEAP32[i12 >> 2] = 0;
+  i14 = HEAP32[i6 >> 2] | 0;
+  i15 = i14 + i11 | 0;
+  if (!((i13 | 0) != 0 & i13 >>> 0 < i15 >>> 0)) {
+   HEAP32[i12 >> 2] = i13 - i15;
+   HEAP32[i4 >> 2] = i15;
+   if ((i14 | 0) > -1) {
+    i13 = (HEAP32[i7 >> 2] | 0) + i14 | 0;
+   } else {
+    i13 = 0;
+   }
+   __tr_flush_block(i2, i13, i11, 0);
+   HEAP32[i6 >> 2] = HEAP32[i4 >> 2];
+   i16 = HEAP32[i2 >> 2] | 0;
+   i14 = i16 + 28 | 0;
+   i15 = HEAP32[i14 >> 2] | 0;
+   i17 = HEAP32[i15 + 20 >> 2] | 0;
+   i13 = i16 + 16 | 0;
+   i18 = HEAP32[i13 >> 2] | 0;
+   i17 = i17 >>> 0 > i18 >>> 0 ? i18 : i17;
+   if ((i17 | 0) != 0 ? (i8 = i16 + 12 | 0, _memcpy(HEAP32[i8 >> 2] | 0, HEAP32[i15 + 16 >> 2] | 0, i17 | 0) | 0, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) + i17, i8 = (HEAP32[i14 >> 2] | 0) + 16 | 0, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) + i17, i8 = i16 + 20 | 0, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) + i17, HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) - i17, i8 = HEAP32[i14 >> 2] | 0, i16 = i8 + 20 | 0, i18 = HEAP32[i16 >> 2] | 0, HEAP32[i16 >> 2] = i18 - i17, (i18 | 0) == (i17 | 0)) : 0) {
+    HEAP32[i8 + 16 >> 2] = HEAP32[i8 + 8 >> 2];
+   }
+   if ((HEAP32[(HEAP32[i2 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+    i2 = 0;
+    i8 = 28;
+    break;
+   }
+   i14 = HEAP32[i6 >> 2] | 0;
+   i13 = HEAP32[i4 >> 2] | 0;
+  }
+  i13 = i13 - i14 | 0;
+  if (i13 >>> 0 < ((HEAP32[i10 >> 2] | 0) + -262 | 0) >>> 0) {
+   continue;
+  }
+  if ((i14 | 0) > -1) {
+   i14 = (HEAP32[i7 >> 2] | 0) + i14 | 0;
+  } else {
+   i14 = 0;
+  }
+  __tr_flush_block(i2, i14, i13, 0);
+  HEAP32[i6 >> 2] = HEAP32[i4 >> 2];
+  i16 = HEAP32[i2 >> 2] | 0;
+  i14 = i16 + 28 | 0;
+  i15 = HEAP32[i14 >> 2] | 0;
+  i17 = HEAP32[i15 + 20 >> 2] | 0;
+  i13 = i16 + 16 | 0;
+  i18 = HEAP32[i13 >> 2] | 0;
+  i17 = i17 >>> 0 > i18 >>> 0 ? i18 : i17;
+  if ((i17 | 0) != 0 ? (i9 = i16 + 12 | 0, _memcpy(HEAP32[i9 >> 2] | 0, HEAP32[i15 + 16 >> 2] | 0, i17 | 0) | 0, HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + i17, i9 = (HEAP32[i14 >> 2] | 0) + 16 | 0, HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + i17, i9 = i16 + 20 | 0, HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + i17, HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) - i17, i9 = HEAP32[i14 >> 2] | 0, i16 = i9 + 20 | 0, i18 = HEAP32[i16 >> 2] | 0, HEAP32[i16 >> 2] = i18 - i17, (i18 | 0) == (i17 | 0)) : 0) {
+   HEAP32[i9 + 16 >> 2] = HEAP32[i9 + 8 >> 2];
+  }
+  if ((HEAP32[(HEAP32[i2 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+   i2 = 0;
+   i8 = 28;
+   break;
+  }
+ }
+ if ((i8 | 0) == 20) {
+  i8 = HEAP32[i6 >> 2] | 0;
+  if ((i8 | 0) > -1) {
+   i7 = (HEAP32[i7 >> 2] | 0) + i8 | 0;
+  } else {
+   i7 = 0;
+  }
+  i5 = (i5 | 0) == 4;
+  __tr_flush_block(i2, i7, (HEAP32[i4 >> 2] | 0) - i8 | 0, i5 & 1);
+  HEAP32[i6 >> 2] = HEAP32[i4 >> 2];
+  i4 = HEAP32[i2 >> 2] | 0;
+  i7 = i4 + 28 | 0;
+  i6 = HEAP32[i7 >> 2] | 0;
+  i9 = HEAP32[i6 + 20 >> 2] | 0;
+  i8 = i4 + 16 | 0;
+  i10 = HEAP32[i8 >> 2] | 0;
+  i9 = i9 >>> 0 > i10 >>> 0 ? i10 : i9;
+  if ((i9 | 0) != 0 ? (i3 = i4 + 12 | 0, _memcpy(HEAP32[i3 >> 2] | 0, HEAP32[i6 + 16 >> 2] | 0, i9 | 0) | 0, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + i9, i3 = (HEAP32[i7 >> 2] | 0) + 16 | 0, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + i9, i3 = i4 + 20 | 0, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + i9, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) - i9, i3 = HEAP32[i7 >> 2] | 0, i17 = i3 + 20 | 0, i18 = HEAP32[i17 >> 2] | 0, HEAP32[i17 >> 2] = i18 - i9, (i18 | 0) == (i9 | 0)) : 0) {
+   HEAP32[i3 + 16 >> 2] = HEAP32[i3 + 8 >> 2];
+  }
+  if ((HEAP32[(HEAP32[i2 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+   i18 = i5 ? 2 : 0;
+   STACKTOP = i1;
+   return i18 | 0;
+  } else {
+   i18 = i5 ? 3 : 1;
+   STACKTOP = i1;
+   return i18 | 0;
+  }
+ } else if ((i8 | 0) == 28) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ return 0;
+}
+function _fill_window(i15) {
+ i15 = i15 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0;
+ i2 = STACKTOP;
+ i16 = i15 + 44 | 0;
+ i9 = HEAP32[i16 >> 2] | 0;
+ i4 = i15 + 60 | 0;
+ i8 = i15 + 116 | 0;
+ i3 = i15 + 108 | 0;
+ i5 = i9 + -262 | 0;
+ i1 = i15 + 56 | 0;
+ i17 = i15 + 72 | 0;
+ i6 = i15 + 88 | 0;
+ i7 = i15 + 84 | 0;
+ i11 = i15 + 112 | 0;
+ i12 = i15 + 92 | 0;
+ i13 = i15 + 76 | 0;
+ i14 = i15 + 68 | 0;
+ i10 = i15 + 64 | 0;
+ i19 = HEAP32[i8 >> 2] | 0;
+ i21 = i9;
+ while (1) {
+  i20 = HEAP32[i3 >> 2] | 0;
+  i19 = (HEAP32[i4 >> 2] | 0) - i19 - i20 | 0;
+  if (!(i20 >>> 0 < (i5 + i21 | 0) >>> 0)) {
+   i20 = HEAP32[i1 >> 2] | 0;
+   _memcpy(i20 | 0, i20 + i9 | 0, i9 | 0) | 0;
+   HEAP32[i11 >> 2] = (HEAP32[i11 >> 2] | 0) - i9;
+   i20 = (HEAP32[i3 >> 2] | 0) - i9 | 0;
+   HEAP32[i3 >> 2] = i20;
+   HEAP32[i12 >> 2] = (HEAP32[i12 >> 2] | 0) - i9;
+   i22 = HEAP32[i13 >> 2] | 0;
+   i21 = i22;
+   i22 = (HEAP32[i14 >> 2] | 0) + (i22 << 1) | 0;
+   do {
+    i22 = i22 + -2 | 0;
+    i23 = HEAPU16[i22 >> 1] | 0;
+    if (i23 >>> 0 < i9 >>> 0) {
+     i23 = 0;
+    } else {
+     i23 = i23 - i9 & 65535;
+    }
+    HEAP16[i22 >> 1] = i23;
+    i21 = i21 + -1 | 0;
+   } while ((i21 | 0) != 0);
+   i22 = i9;
+   i21 = (HEAP32[i10 >> 2] | 0) + (i9 << 1) | 0;
+   do {
+    i21 = i21 + -2 | 0;
+    i23 = HEAPU16[i21 >> 1] | 0;
+    if (i23 >>> 0 < i9 >>> 0) {
+     i23 = 0;
+    } else {
+     i23 = i23 - i9 & 65535;
+    }
+    HEAP16[i21 >> 1] = i23;
+    i22 = i22 + -1 | 0;
+   } while ((i22 | 0) != 0);
+   i19 = i19 + i9 | 0;
+  }
+  i21 = HEAP32[i15 >> 2] | 0;
+  i24 = i21 + 4 | 0;
+  i23 = HEAP32[i24 >> 2] | 0;
+  if ((i23 | 0) == 0) {
+   i18 = 28;
+   break;
+  }
+  i22 = HEAP32[i8 >> 2] | 0;
+  i20 = (HEAP32[i1 >> 2] | 0) + (i22 + i20) | 0;
+  i19 = i23 >>> 0 > i19 >>> 0 ? i19 : i23;
+  if ((i19 | 0) == 0) {
+   i19 = 0;
+  } else {
+   HEAP32[i24 >> 2] = i23 - i19;
+   i22 = HEAP32[(HEAP32[i21 + 28 >> 2] | 0) + 24 >> 2] | 0;
+   if ((i22 | 0) == 1) {
+    i22 = i21 + 48 | 0;
+    HEAP32[i22 >> 2] = _adler32(HEAP32[i22 >> 2] | 0, HEAP32[i21 >> 2] | 0, i19) | 0;
+    i22 = i21;
+   } else if ((i22 | 0) == 2) {
+    i22 = i21 + 48 | 0;
+    HEAP32[i22 >> 2] = _crc32(HEAP32[i22 >> 2] | 0, HEAP32[i21 >> 2] | 0, i19) | 0;
+    i22 = i21;
+   } else {
+    i22 = i21;
+   }
+   _memcpy(i20 | 0, HEAP32[i22 >> 2] | 0, i19 | 0) | 0;
+   HEAP32[i22 >> 2] = (HEAP32[i22 >> 2] | 0) + i19;
+   i22 = i21 + 8 | 0;
+   HEAP32[i22 >> 2] = (HEAP32[i22 >> 2] | 0) + i19;
+   i22 = HEAP32[i8 >> 2] | 0;
+  }
+  i19 = i22 + i19 | 0;
+  HEAP32[i8 >> 2] = i19;
+  if (i19 >>> 0 > 2 ? (i23 = HEAP32[i3 >> 2] | 0, i22 = HEAP32[i1 >> 2] | 0, i24 = HEAPU8[i22 + i23 | 0] | 0, HEAP32[i17 >> 2] = i24, HEAP32[i17 >> 2] = ((HEAPU8[i22 + (i23 + 1) | 0] | 0) ^ i24 << HEAP32[i6 >> 2]) & HEAP32[i7 >> 2], !(i19 >>> 0 < 262)) : 0) {
+   break;
+  }
+  if ((HEAP32[(HEAP32[i15 >> 2] | 0) + 4 >> 2] | 0) == 0) {
+   break;
+  }
+  i21 = HEAP32[i16 >> 2] | 0;
+ }
+ if ((i18 | 0) == 28) {
+  STACKTOP = i2;
+  return;
+ }
+ i5 = i15 + 5824 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ i4 = HEAP32[i4 >> 2] | 0;
+ if (!(i6 >>> 0 < i4 >>> 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = i19 + (HEAP32[i3 >> 2] | 0) | 0;
+ if (i6 >>> 0 < i3 >>> 0) {
+  i4 = i4 - i3 | 0;
+  i24 = i4 >>> 0 > 258 ? 258 : i4;
+  _memset((HEAP32[i1 >> 2] | 0) + i3 | 0, 0, i24 | 0) | 0;
+  HEAP32[i5 >> 2] = i24 + i3;
+  STACKTOP = i2;
+  return;
+ }
+ i3 = i3 + 258 | 0;
+ if (!(i6 >>> 0 < i3 >>> 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = i3 - i6 | 0;
+ i4 = i4 - i6 | 0;
+ i24 = i3 >>> 0 > i4 >>> 0 ? i4 : i3;
+ _memset((HEAP32[i1 >> 2] | 0) + i6 | 0, 0, i24 | 0) | 0;
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + i24;
+ STACKTOP = i2;
+ return;
+}
+function __tr_align(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ i3 = i1 + 5820 | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ i4 = i1 + 5816 | 0;
+ i7 = HEAPU16[i4 >> 1] | 0 | 2 << i6;
+ i5 = i7 & 65535;
+ HEAP16[i4 >> 1] = i5;
+ if ((i6 | 0) > 13) {
+  i8 = i1 + 20 | 0;
+  i6 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i6 + 1;
+  i5 = i1 + 8 | 0;
+  HEAP8[(HEAP32[i5 >> 2] | 0) + i6 | 0] = i7;
+  i7 = (HEAPU16[i4 >> 1] | 0) >>> 8 & 255;
+  i6 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i6 + 1;
+  HEAP8[(HEAP32[i5 >> 2] | 0) + i6 | 0] = i7;
+  i6 = HEAP32[i3 >> 2] | 0;
+  i5 = 2 >>> (16 - i6 | 0) & 65535;
+  HEAP16[i4 >> 1] = i5;
+  i6 = i6 + -13 | 0;
+ } else {
+  i6 = i6 + 3 | 0;
+ }
+ HEAP32[i3 >> 2] = i6;
+ if ((i6 | 0) > 9) {
+  i7 = i1 + 20 | 0;
+  i6 = HEAP32[i7 >> 2] | 0;
+  HEAP32[i7 >> 2] = i6 + 1;
+  i8 = i1 + 8 | 0;
+  HEAP8[(HEAP32[i8 >> 2] | 0) + i6 | 0] = i5;
+  i5 = (HEAPU16[i4 >> 1] | 0) >>> 8 & 255;
+  i6 = HEAP32[i7 >> 2] | 0;
+  HEAP32[i7 >> 2] = i6 + 1;
+  HEAP8[(HEAP32[i8 >> 2] | 0) + i6 | 0] = i5;
+  HEAP16[i4 >> 1] = 0;
+  i6 = (HEAP32[i3 >> 2] | 0) + -9 | 0;
+  i5 = 0;
+ } else {
+  i6 = i6 + 7 | 0;
+ }
+ HEAP32[i3 >> 2] = i6;
+ if ((i6 | 0) != 16) {
+  if ((i6 | 0) > 7) {
+   i6 = i1 + 20 | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   HEAP32[i6 >> 2] = i7 + 1;
+   HEAP8[(HEAP32[i1 + 8 >> 2] | 0) + i7 | 0] = i5;
+   i7 = (HEAPU16[i4 >> 1] | 0) >>> 8;
+   HEAP16[i4 >> 1] = i7;
+   i6 = (HEAP32[i3 >> 2] | 0) + -8 | 0;
+   HEAP32[i3 >> 2] = i6;
+  } else {
+   i7 = i5;
+  }
+ } else {
+  i9 = i1 + 20 | 0;
+  i8 = HEAP32[i9 >> 2] | 0;
+  HEAP32[i9 >> 2] = i8 + 1;
+  i7 = i1 + 8 | 0;
+  HEAP8[(HEAP32[i7 >> 2] | 0) + i8 | 0] = i5;
+  i8 = (HEAPU16[i4 >> 1] | 0) >>> 8 & 255;
+  i6 = HEAP32[i9 >> 2] | 0;
+  HEAP32[i9 >> 2] = i6 + 1;
+  HEAP8[(HEAP32[i7 >> 2] | 0) + i6 | 0] = i8;
+  HEAP16[i4 >> 1] = 0;
+  HEAP32[i3 >> 2] = 0;
+  i6 = 0;
+  i7 = 0;
+ }
+ i5 = i1 + 5812 | 0;
+ if ((11 - i6 + (HEAP32[i5 >> 2] | 0) | 0) >= 9) {
+  HEAP32[i5 >> 2] = 7;
+  STACKTOP = i2;
+  return;
+ }
+ i7 = i7 & 65535 | 2 << i6;
+ HEAP16[i4 >> 1] = i7;
+ if ((i6 | 0) > 13) {
+  i8 = i1 + 20 | 0;
+  i6 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i6 + 1;
+  i9 = i1 + 8 | 0;
+  HEAP8[(HEAP32[i9 >> 2] | 0) + i6 | 0] = i7;
+  i7 = (HEAPU16[i4 >> 1] | 0) >>> 8 & 255;
+  i6 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i6 + 1;
+  HEAP8[(HEAP32[i9 >> 2] | 0) + i6 | 0] = i7;
+  i6 = HEAP32[i3 >> 2] | 0;
+  i7 = 2 >>> (16 - i6 | 0);
+  HEAP16[i4 >> 1] = i7;
+  i6 = i6 + -13 | 0;
+ } else {
+  i6 = i6 + 3 | 0;
+ }
+ i7 = i7 & 255;
+ HEAP32[i3 >> 2] = i6;
+ if ((i6 | 0) > 9) {
+  i8 = i1 + 20 | 0;
+  i9 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i9 + 1;
+  i6 = i1 + 8 | 0;
+  HEAP8[(HEAP32[i6 >> 2] | 0) + i9 | 0] = i7;
+  i9 = (HEAPU16[i4 >> 1] | 0) >>> 8 & 255;
+  i7 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i7 + 1;
+  HEAP8[(HEAP32[i6 >> 2] | 0) + i7 | 0] = i9;
+  HEAP16[i4 >> 1] = 0;
+  i7 = 0;
+  i6 = (HEAP32[i3 >> 2] | 0) + -9 | 0;
+ } else {
+  i6 = i6 + 7 | 0;
+ }
+ HEAP32[i3 >> 2] = i6;
+ if ((i6 | 0) == 16) {
+  i6 = i1 + 20 | 0;
+  i9 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i9 + 1;
+  i8 = i1 + 8 | 0;
+  HEAP8[(HEAP32[i8 >> 2] | 0) + i9 | 0] = i7;
+  i7 = (HEAPU16[i4 >> 1] | 0) >>> 8 & 255;
+  i9 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i9 + 1;
+  HEAP8[(HEAP32[i8 >> 2] | 0) + i9 | 0] = i7;
+  HEAP16[i4 >> 1] = 0;
+  HEAP32[i3 >> 2] = 0;
+  HEAP32[i5 >> 2] = 7;
+  STACKTOP = i2;
+  return;
+ }
+ if ((i6 | 0) <= 7) {
+  HEAP32[i5 >> 2] = 7;
+  STACKTOP = i2;
+  return;
+ }
+ i8 = i1 + 20 | 0;
+ i9 = HEAP32[i8 >> 2] | 0;
+ HEAP32[i8 >> 2] = i9 + 1;
+ HEAP8[(HEAP32[i1 + 8 >> 2] | 0) + i9 | 0] = i7;
+ HEAP16[i4 >> 1] = (HEAPU16[i4 >> 1] | 0) >>> 8;
+ HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + -8;
+ HEAP32[i5 >> 2] = 7;
+ STACKTOP = i2;
+ return;
+}
+function _adler32(i6, i4, i5) {
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0;
+ i1 = STACKTOP;
+ i3 = i6 >>> 16;
+ i6 = i6 & 65535;
+ if ((i5 | 0) == 1) {
+  i2 = (HEAPU8[i4] | 0) + i6 | 0;
+  i2 = i2 >>> 0 > 65520 ? i2 + -65521 | 0 : i2;
+  i3 = i2 + i3 | 0;
+  i8 = (i3 >>> 0 > 65520 ? i3 + 15 | 0 : i3) << 16 | i2;
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ if ((i4 | 0) == 0) {
+  i8 = 1;
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ if (i5 >>> 0 < 16) {
+  if ((i5 | 0) != 0) {
+   while (1) {
+    i5 = i5 + -1 | 0;
+    i6 = (HEAPU8[i4] | 0) + i6 | 0;
+    i3 = i6 + i3 | 0;
+    if ((i5 | 0) == 0) {
+     break;
+    } else {
+     i4 = i4 + 1 | 0;
+    }
+   }
+  }
+  i8 = ((i3 >>> 0) % 65521 | 0) << 16 | (i6 >>> 0 > 65520 ? i6 + -65521 | 0 : i6);
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ if (i5 >>> 0 > 5551) {
+  do {
+   i5 = i5 + -5552 | 0;
+   i7 = i4;
+   i8 = 347;
+   while (1) {
+    i23 = (HEAPU8[i7] | 0) + i6 | 0;
+    i22 = i23 + (HEAPU8[i7 + 1 | 0] | 0) | 0;
+    i21 = i22 + (HEAPU8[i7 + 2 | 0] | 0) | 0;
+    i20 = i21 + (HEAPU8[i7 + 3 | 0] | 0) | 0;
+    i19 = i20 + (HEAPU8[i7 + 4 | 0] | 0) | 0;
+    i18 = i19 + (HEAPU8[i7 + 5 | 0] | 0) | 0;
+    i17 = i18 + (HEAPU8[i7 + 6 | 0] | 0) | 0;
+    i16 = i17 + (HEAPU8[i7 + 7 | 0] | 0) | 0;
+    i15 = i16 + (HEAPU8[i7 + 8 | 0] | 0) | 0;
+    i14 = i15 + (HEAPU8[i7 + 9 | 0] | 0) | 0;
+    i13 = i14 + (HEAPU8[i7 + 10 | 0] | 0) | 0;
+    i12 = i13 + (HEAPU8[i7 + 11 | 0] | 0) | 0;
+    i11 = i12 + (HEAPU8[i7 + 12 | 0] | 0) | 0;
+    i10 = i11 + (HEAPU8[i7 + 13 | 0] | 0) | 0;
+    i9 = i10 + (HEAPU8[i7 + 14 | 0] | 0) | 0;
+    i6 = i9 + (HEAPU8[i7 + 15 | 0] | 0) | 0;
+    i3 = i23 + i3 + i22 + i21 + i20 + i19 + i18 + i17 + i16 + i15 + i14 + i13 + i12 + i11 + i10 + i9 + i6 | 0;
+    i8 = i8 + -1 | 0;
+    if ((i8 | 0) == 0) {
+     break;
+    } else {
+     i7 = i7 + 16 | 0;
+    }
+   }
+   i4 = i4 + 5552 | 0;
+   i6 = (i6 >>> 0) % 65521 | 0;
+   i3 = (i3 >>> 0) % 65521 | 0;
+  } while (i5 >>> 0 > 5551);
+  if ((i5 | 0) != 0) {
+   if (i5 >>> 0 > 15) {
+    i2 = 15;
+   } else {
+    i2 = 16;
+   }
+  }
+ } else {
+  i2 = 15;
+ }
+ if ((i2 | 0) == 15) {
+  while (1) {
+   i5 = i5 + -16 | 0;
+   i9 = (HEAPU8[i4] | 0) + i6 | 0;
+   i10 = i9 + (HEAPU8[i4 + 1 | 0] | 0) | 0;
+   i11 = i10 + (HEAPU8[i4 + 2 | 0] | 0) | 0;
+   i12 = i11 + (HEAPU8[i4 + 3 | 0] | 0) | 0;
+   i13 = i12 + (HEAPU8[i4 + 4 | 0] | 0) | 0;
+   i14 = i13 + (HEAPU8[i4 + 5 | 0] | 0) | 0;
+   i15 = i14 + (HEAPU8[i4 + 6 | 0] | 0) | 0;
+   i16 = i15 + (HEAPU8[i4 + 7 | 0] | 0) | 0;
+   i17 = i16 + (HEAPU8[i4 + 8 | 0] | 0) | 0;
+   i18 = i17 + (HEAPU8[i4 + 9 | 0] | 0) | 0;
+   i19 = i18 + (HEAPU8[i4 + 10 | 0] | 0) | 0;
+   i20 = i19 + (HEAPU8[i4 + 11 | 0] | 0) | 0;
+   i21 = i20 + (HEAPU8[i4 + 12 | 0] | 0) | 0;
+   i22 = i21 + (HEAPU8[i4 + 13 | 0] | 0) | 0;
+   i23 = i22 + (HEAPU8[i4 + 14 | 0] | 0) | 0;
+   i6 = i23 + (HEAPU8[i4 + 15 | 0] | 0) | 0;
+   i3 = i9 + i3 + i10 + i11 + i12 + i13 + i14 + i15 + i16 + i17 + i18 + i19 + i20 + i21 + i22 + i23 + i6 | 0;
+   i4 = i4 + 16 | 0;
+   if (!(i5 >>> 0 > 15)) {
+    break;
+   } else {
+    i2 = 15;
+   }
+  }
+  if ((i5 | 0) == 0) {
+   i2 = 17;
+  } else {
+   i2 = 16;
+  }
+ }
+ if ((i2 | 0) == 16) {
+  while (1) {
+   i5 = i5 + -1 | 0;
+   i6 = (HEAPU8[i4] | 0) + i6 | 0;
+   i3 = i6 + i3 | 0;
+   if ((i5 | 0) == 0) {
+    i2 = 17;
+    break;
+   } else {
+    i4 = i4 + 1 | 0;
+    i2 = 16;
+   }
+  }
+ }
+ if ((i2 | 0) == 17) {
+  i6 = (i6 >>> 0) % 65521 | 0;
+  i3 = (i3 >>> 0) % 65521 | 0;
+ }
+ i23 = i3 << 16 | i6;
+ STACKTOP = i1;
+ return i23 | 0;
+}
+function _crc32(i4, i2, i3) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i5 = 0;
+ i1 = STACKTOP;
+ if ((i2 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ i4 = ~i4;
+ L4 : do {
+  if ((i3 | 0) != 0) {
+   while (1) {
+    if ((i2 & 3 | 0) == 0) {
+     break;
+    }
+    i4 = HEAP32[3192 + (((HEAPU8[i2] | 0) ^ i4 & 255) << 2) >> 2] ^ i4 >>> 8;
+    i3 = i3 + -1 | 0;
+    if ((i3 | 0) == 0) {
+     break L4;
+    } else {
+     i2 = i2 + 1 | 0;
+    }
+   }
+   if (i3 >>> 0 > 31) {
+    while (1) {
+     i4 = HEAP32[i2 >> 2] ^ i4;
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2] ^ HEAP32[i2 + 4 >> 2];
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2] ^ HEAP32[i2 + 8 >> 2];
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2] ^ HEAP32[i2 + 12 >> 2];
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2] ^ HEAP32[i2 + 16 >> 2];
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2] ^ HEAP32[i2 + 20 >> 2];
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2] ^ HEAP32[i2 + 24 >> 2];
+     i5 = i2 + 32 | 0;
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2] ^ HEAP32[i2 + 28 >> 2];
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2];
+     i3 = i3 + -32 | 0;
+     if (i3 >>> 0 > 31) {
+      i2 = i5;
+     } else {
+      i2 = i5;
+      break;
+     }
+    }
+   }
+   if (i3 >>> 0 > 3) {
+    while (1) {
+     i5 = i2 + 4 | 0;
+     i4 = HEAP32[i2 >> 2] ^ i4;
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2];
+     i3 = i3 + -4 | 0;
+     if (i3 >>> 0 > 3) {
+      i2 = i5;
+     } else {
+      i2 = i5;
+      break;
+     }
+    }
+   }
+   if ((i3 | 0) != 0) {
+    while (1) {
+     i4 = HEAP32[3192 + (((HEAPU8[i2] | 0) ^ i4 & 255) << 2) >> 2] ^ i4 >>> 8;
+     i3 = i3 + -1 | 0;
+     if ((i3 | 0) == 0) {
+      break;
+     } else {
+      i2 = i2 + 1 | 0;
+     }
+    }
+   }
+  }
+ } while (0);
+ i5 = ~i4;
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _deflateInit2_(i3, i7, i8, i10, i4, i1, i5, i6) {
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ i8 = i8 | 0;
+ i10 = i10 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i9 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i2 = STACKTOP;
+ if ((i5 | 0) == 0) {
+  i12 = -6;
+  STACKTOP = i2;
+  return i12 | 0;
+ }
+ if (!((HEAP8[i5] | 0) == 49 & (i6 | 0) == 56)) {
+  i12 = -6;
+  STACKTOP = i2;
+  return i12 | 0;
+ }
+ if ((i3 | 0) == 0) {
+  i12 = -2;
+  STACKTOP = i2;
+  return i12 | 0;
+ }
+ i5 = i3 + 24 | 0;
+ HEAP32[i5 >> 2] = 0;
+ i6 = i3 + 32 | 0;
+ i9 = HEAP32[i6 >> 2] | 0;
+ if ((i9 | 0) == 0) {
+  HEAP32[i6 >> 2] = 1;
+  HEAP32[i3 + 40 >> 2] = 0;
+  i9 = 1;
+ }
+ i11 = i3 + 36 | 0;
+ if ((HEAP32[i11 >> 2] | 0) == 0) {
+  HEAP32[i11 >> 2] = 1;
+ }
+ i7 = (i7 | 0) == -1 ? 6 : i7;
+ if ((i10 | 0) < 0) {
+  i10 = 0 - i10 | 0;
+  i11 = 0;
+ } else {
+  i11 = (i10 | 0) > 15;
+  i10 = i11 ? i10 + -16 | 0 : i10;
+  i11 = i11 ? 2 : 1;
+ }
+ if (!((i4 + -1 | 0) >>> 0 < 9 & (i8 | 0) == 8)) {
+  i12 = -2;
+  STACKTOP = i2;
+  return i12 | 0;
+ }
+ if ((i10 + -8 | 0) >>> 0 > 7 | i7 >>> 0 > 9 | i1 >>> 0 > 4) {
+  i12 = -2;
+  STACKTOP = i2;
+  return i12 | 0;
+ }
+ i12 = (i10 | 0) == 8 ? 9 : i10;
+ i10 = i3 + 40 | 0;
+ i8 = FUNCTION_TABLE_iiii[i9 & 1](HEAP32[i10 >> 2] | 0, 1, 5828) | 0;
+ if ((i8 | 0) == 0) {
+  i12 = -4;
+  STACKTOP = i2;
+  return i12 | 0;
+ }
+ HEAP32[i3 + 28 >> 2] = i8;
+ HEAP32[i8 >> 2] = i3;
+ HEAP32[i8 + 24 >> 2] = i11;
+ HEAP32[i8 + 28 >> 2] = 0;
+ HEAP32[i8 + 48 >> 2] = i12;
+ i14 = 1 << i12;
+ i11 = i8 + 44 | 0;
+ HEAP32[i11 >> 2] = i14;
+ HEAP32[i8 + 52 >> 2] = i14 + -1;
+ i12 = i4 + 7 | 0;
+ HEAP32[i8 + 80 >> 2] = i12;
+ i12 = 1 << i12;
+ i13 = i8 + 76 | 0;
+ HEAP32[i13 >> 2] = i12;
+ HEAP32[i8 + 84 >> 2] = i12 + -1;
+ HEAP32[i8 + 88 >> 2] = ((i4 + 9 | 0) >>> 0) / 3 | 0;
+ i12 = i8 + 56 | 0;
+ HEAP32[i12 >> 2] = FUNCTION_TABLE_iiii[HEAP32[i6 >> 2] & 1](HEAP32[i10 >> 2] | 0, i14, 2) | 0;
+ i14 = FUNCTION_TABLE_iiii[HEAP32[i6 >> 2] & 1](HEAP32[i10 >> 2] | 0, HEAP32[i11 >> 2] | 0, 2) | 0;
+ i9 = i8 + 64 | 0;
+ HEAP32[i9 >> 2] = i14;
+ _memset(i14 | 0, 0, HEAP32[i11 >> 2] << 1 | 0) | 0;
+ i11 = i8 + 68 | 0;
+ HEAP32[i11 >> 2] = FUNCTION_TABLE_iiii[HEAP32[i6 >> 2] & 1](HEAP32[i10 >> 2] | 0, HEAP32[i13 >> 2] | 0, 2) | 0;
+ HEAP32[i8 + 5824 >> 2] = 0;
+ i4 = 1 << i4 + 6;
+ i13 = i8 + 5788 | 0;
+ HEAP32[i13 >> 2] = i4;
+ i4 = FUNCTION_TABLE_iiii[HEAP32[i6 >> 2] & 1](HEAP32[i10 >> 2] | 0, i4, 4) | 0;
+ HEAP32[i8 + 8 >> 2] = i4;
+ i6 = HEAP32[i13 >> 2] | 0;
+ HEAP32[i8 + 12 >> 2] = i6 << 2;
+ if (((HEAP32[i12 >> 2] | 0) != 0 ? (HEAP32[i9 >> 2] | 0) != 0 : 0) ? !((HEAP32[i11 >> 2] | 0) == 0 | (i4 | 0) == 0) : 0) {
+  HEAP32[i8 + 5796 >> 2] = i4 + (i6 >>> 1 << 1);
+  HEAP32[i8 + 5784 >> 2] = i4 + (i6 * 3 | 0);
+  HEAP32[i8 + 132 >> 2] = i7;
+  HEAP32[i8 + 136 >> 2] = i1;
+  HEAP8[i8 + 36 | 0] = 8;
+  i14 = _deflateReset(i3) | 0;
+  STACKTOP = i2;
+  return i14 | 0;
+ }
+ HEAP32[i8 + 4 >> 2] = 666;
+ HEAP32[i5 >> 2] = HEAP32[3176 >> 2];
+ _deflateEnd(i3) | 0;
+ i14 = -4;
+ STACKTOP = i2;
+ return i14 | 0;
+}
+function _longest_match(i19, i16) {
+ i19 = i19 | 0;
+ i16 = i16 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i17 = 0, i18 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0;
+ i1 = STACKTOP;
+ i18 = HEAP32[i19 + 124 >> 2] | 0;
+ i3 = HEAP32[i19 + 56 >> 2] | 0;
+ i5 = HEAP32[i19 + 108 >> 2] | 0;
+ i4 = i3 + i5 | 0;
+ i20 = HEAP32[i19 + 120 >> 2] | 0;
+ i10 = HEAP32[i19 + 144 >> 2] | 0;
+ i2 = (HEAP32[i19 + 44 >> 2] | 0) + -262 | 0;
+ i8 = i5 >>> 0 > i2 >>> 0 ? i5 - i2 | 0 : 0;
+ i6 = HEAP32[i19 + 64 >> 2] | 0;
+ i7 = HEAP32[i19 + 52 >> 2] | 0;
+ i9 = i3 + (i5 + 258) | 0;
+ i2 = HEAP32[i19 + 116 >> 2] | 0;
+ i12 = i10 >>> 0 > i2 >>> 0 ? i2 : i10;
+ i11 = i19 + 112 | 0;
+ i15 = i3 + (i5 + 1) | 0;
+ i14 = i3 + (i5 + 2) | 0;
+ i13 = i9;
+ i10 = i5 + 257 | 0;
+ i17 = i20;
+ i18 = i20 >>> 0 < (HEAP32[i19 + 140 >> 2] | 0) >>> 0 ? i18 : i18 >>> 2;
+ i19 = HEAP8[i3 + (i20 + i5) | 0] | 0;
+ i20 = HEAP8[i3 + (i5 + -1 + i20) | 0] | 0;
+ while (1) {
+  i21 = i3 + i16 | 0;
+  if ((((HEAP8[i3 + (i16 + i17) | 0] | 0) == i19 << 24 >> 24 ? (HEAP8[i3 + (i17 + -1 + i16) | 0] | 0) == i20 << 24 >> 24 : 0) ? (HEAP8[i21] | 0) == (HEAP8[i4] | 0) : 0) ? (HEAP8[i3 + (i16 + 1) | 0] | 0) == (HEAP8[i15] | 0) : 0) {
+   i21 = i3 + (i16 + 2) | 0;
+   i22 = i14;
+   do {
+    i23 = i22 + 1 | 0;
+    if ((HEAP8[i23] | 0) != (HEAP8[i21 + 1 | 0] | 0)) {
+     i22 = i23;
+     break;
+    }
+    i23 = i22 + 2 | 0;
+    if ((HEAP8[i23] | 0) != (HEAP8[i21 + 2 | 0] | 0)) {
+     i22 = i23;
+     break;
+    }
+    i23 = i22 + 3 | 0;
+    if ((HEAP8[i23] | 0) != (HEAP8[i21 + 3 | 0] | 0)) {
+     i22 = i23;
+     break;
+    }
+    i23 = i22 + 4 | 0;
+    if ((HEAP8[i23] | 0) != (HEAP8[i21 + 4 | 0] | 0)) {
+     i22 = i23;
+     break;
+    }
+    i23 = i22 + 5 | 0;
+    if ((HEAP8[i23] | 0) != (HEAP8[i21 + 5 | 0] | 0)) {
+     i22 = i23;
+     break;
+    }
+    i23 = i22 + 6 | 0;
+    if ((HEAP8[i23] | 0) != (HEAP8[i21 + 6 | 0] | 0)) {
+     i22 = i23;
+     break;
+    }
+    i23 = i22 + 7 | 0;
+    if ((HEAP8[i23] | 0) != (HEAP8[i21 + 7 | 0] | 0)) {
+     i22 = i23;
+     break;
+    }
+    i22 = i22 + 8 | 0;
+    i21 = i21 + 8 | 0;
+   } while ((HEAP8[i22] | 0) == (HEAP8[i21] | 0) & i22 >>> 0 < i9 >>> 0);
+   i21 = i22 - i13 | 0;
+   i22 = i21 + 258 | 0;
+   if ((i22 | 0) > (i17 | 0)) {
+    HEAP32[i11 >> 2] = i16;
+    if ((i22 | 0) >= (i12 | 0)) {
+     i17 = i22;
+     i3 = 20;
+     break;
+    }
+    i17 = i22;
+    i19 = HEAP8[i3 + (i22 + i5) | 0] | 0;
+    i20 = HEAP8[i3 + (i10 + i21) | 0] | 0;
+   }
+  }
+  i16 = HEAPU16[i6 + ((i16 & i7) << 1) >> 1] | 0;
+  if (!(i16 >>> 0 > i8 >>> 0)) {
+   i3 = 20;
+   break;
+  }
+  i18 = i18 + -1 | 0;
+  if ((i18 | 0) == 0) {
+   i3 = 20;
+   break;
+  }
+ }
+ if ((i3 | 0) == 20) {
+  STACKTOP = i1;
+  return (i17 >>> 0 > i2 >>> 0 ? i2 : i17) | 0;
+ }
+ return 0;
+}
+function __tr_stored_block(i3, i2, i5, i6) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i4 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i1 = STACKTOP;
+ i4 = i3 + 5820 | 0;
+ i7 = HEAP32[i4 >> 2] | 0;
+ i9 = i6 & 65535;
+ i6 = i3 + 5816 | 0;
+ i8 = HEAPU16[i6 >> 1] | 0 | i9 << i7;
+ HEAP16[i6 >> 1] = i8;
+ if ((i7 | 0) > 13) {
+  i11 = i3 + 20 | 0;
+  i7 = HEAP32[i11 >> 2] | 0;
+  HEAP32[i11 >> 2] = i7 + 1;
+  i10 = i3 + 8 | 0;
+  HEAP8[(HEAP32[i10 >> 2] | 0) + i7 | 0] = i8;
+  i8 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+  i7 = HEAP32[i11 >> 2] | 0;
+  HEAP32[i11 >> 2] = i7 + 1;
+  HEAP8[(HEAP32[i10 >> 2] | 0) + i7 | 0] = i8;
+  i7 = HEAP32[i4 >> 2] | 0;
+  i8 = i9 >>> (16 - i7 | 0);
+  HEAP16[i6 >> 1] = i8;
+  i7 = i7 + -13 | 0;
+ } else {
+  i7 = i7 + 3 | 0;
+ }
+ i8 = i8 & 255;
+ HEAP32[i4 >> 2] = i7;
+ do {
+  if ((i7 | 0) <= 8) {
+   i9 = i3 + 20 | 0;
+   if ((i7 | 0) > 0) {
+    i7 = HEAP32[i9 >> 2] | 0;
+    HEAP32[i9 >> 2] = i7 + 1;
+    i11 = i3 + 8 | 0;
+    HEAP8[(HEAP32[i11 >> 2] | 0) + i7 | 0] = i8;
+    i7 = i9;
+    i8 = i11;
+    break;
+   } else {
+    i7 = i9;
+    i8 = i3 + 8 | 0;
+    break;
+   }
+  } else {
+   i7 = i3 + 20 | 0;
+   i10 = HEAP32[i7 >> 2] | 0;
+   HEAP32[i7 >> 2] = i10 + 1;
+   i11 = i3 + 8 | 0;
+   HEAP8[(HEAP32[i11 >> 2] | 0) + i10 | 0] = i8;
+   i10 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+   i8 = HEAP32[i7 >> 2] | 0;
+   HEAP32[i7 >> 2] = i8 + 1;
+   HEAP8[(HEAP32[i11 >> 2] | 0) + i8 | 0] = i10;
+   i8 = i11;
+  }
+ } while (0);
+ HEAP16[i6 >> 1] = 0;
+ HEAP32[i4 >> 2] = 0;
+ HEAP32[i3 + 5812 >> 2] = 8;
+ i10 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i10 + 1;
+ HEAP8[(HEAP32[i8 >> 2] | 0) + i10 | 0] = i5;
+ i10 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i10 + 1;
+ HEAP8[(HEAP32[i8 >> 2] | 0) + i10 | 0] = i5 >>> 8;
+ i10 = i5 & 65535 ^ 65535;
+ i11 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i11 + 1;
+ HEAP8[(HEAP32[i8 >> 2] | 0) + i11 | 0] = i10;
+ i11 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i11 + 1;
+ HEAP8[(HEAP32[i8 >> 2] | 0) + i11 | 0] = i10 >>> 8;
+ if ((i5 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i5 = i5 + -1 | 0;
+  i10 = HEAP8[i2] | 0;
+  i11 = HEAP32[i7 >> 2] | 0;
+  HEAP32[i7 >> 2] = i11 + 1;
+  HEAP8[(HEAP32[i8 >> 2] | 0) + i11 | 0] = i10;
+  if ((i5 | 0) == 0) {
+   break;
+  } else {
+   i2 = i2 + 1 | 0;
+  }
+ }
+ STACKTOP = i1;
+ return;
+}
+function _inflateInit_(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i2 = STACKTOP;
+ if ((i3 | 0) == 0) {
+  i11 = -6;
+  STACKTOP = i2;
+  return i11 | 0;
+ }
+ if (!((HEAP8[i3] | 0) == 49 & (i4 | 0) == 56)) {
+  i11 = -6;
+  STACKTOP = i2;
+  return i11 | 0;
+ }
+ if ((i1 | 0) == 0) {
+  i11 = -2;
+  STACKTOP = i2;
+  return i11 | 0;
+ }
+ i3 = i1 + 24 | 0;
+ HEAP32[i3 >> 2] = 0;
+ i4 = i1 + 32 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  HEAP32[i4 >> 2] = 1;
+  HEAP32[i1 + 40 >> 2] = 0;
+  i6 = 1;
+ }
+ i4 = i1 + 36 | 0;
+ if ((HEAP32[i4 >> 2] | 0) == 0) {
+  HEAP32[i4 >> 2] = 1;
+ }
+ i5 = i1 + 40 | 0;
+ i8 = FUNCTION_TABLE_iiii[i6 & 1](HEAP32[i5 >> 2] | 0, 1, 7116) | 0;
+ if ((i8 | 0) == 0) {
+  i11 = -4;
+  STACKTOP = i2;
+  return i11 | 0;
+ }
+ i6 = i1 + 28 | 0;
+ HEAP32[i6 >> 2] = i8;
+ HEAP32[i8 + 52 >> 2] = 0;
+ i9 = HEAP32[i6 >> 2] | 0;
+ do {
+  if ((i9 | 0) != 0) {
+   i10 = i9 + 52 | 0;
+   i11 = HEAP32[i10 >> 2] | 0;
+   i7 = i9 + 36 | 0;
+   if ((i11 | 0) != 0) {
+    if ((HEAP32[i7 >> 2] | 0) == 15) {
+     i10 = i9;
+    } else {
+     FUNCTION_TABLE_vii[HEAP32[i4 >> 2] & 1](HEAP32[i5 >> 2] | 0, i11);
+     HEAP32[i10 >> 2] = 0;
+     i10 = HEAP32[i6 >> 2] | 0;
+    }
+    HEAP32[i9 + 8 >> 2] = 1;
+    HEAP32[i7 >> 2] = 15;
+    if ((i10 | 0) == 0) {
+     break;
+    } else {
+     i9 = i10;
+    }
+   } else {
+    HEAP32[i9 + 8 >> 2] = 1;
+    HEAP32[i7 >> 2] = 15;
+   }
+   HEAP32[i9 + 28 >> 2] = 0;
+   HEAP32[i1 + 20 >> 2] = 0;
+   HEAP32[i1 + 8 >> 2] = 0;
+   HEAP32[i3 >> 2] = 0;
+   HEAP32[i1 + 48 >> 2] = 1;
+   HEAP32[i9 >> 2] = 0;
+   HEAP32[i9 + 4 >> 2] = 0;
+   HEAP32[i9 + 12 >> 2] = 0;
+   HEAP32[i9 + 20 >> 2] = 32768;
+   HEAP32[i9 + 32 >> 2] = 0;
+   HEAP32[i9 + 40 >> 2] = 0;
+   HEAP32[i9 + 44 >> 2] = 0;
+   HEAP32[i9 + 48 >> 2] = 0;
+   HEAP32[i9 + 56 >> 2] = 0;
+   HEAP32[i9 + 60 >> 2] = 0;
+   i11 = i9 + 1328 | 0;
+   HEAP32[i9 + 108 >> 2] = i11;
+   HEAP32[i9 + 80 >> 2] = i11;
+   HEAP32[i9 + 76 >> 2] = i11;
+   HEAP32[i9 + 7104 >> 2] = 1;
+   HEAP32[i9 + 7108 >> 2] = -1;
+   i11 = 0;
+   STACKTOP = i2;
+   return i11 | 0;
+  }
+ } while (0);
+ FUNCTION_TABLE_vii[HEAP32[i4 >> 2] & 1](HEAP32[i5 >> 2] | 0, i8);
+ HEAP32[i6 >> 2] = 0;
+ i11 = -2;
+ STACKTOP = i2;
+ return i11 | 0;
+}
+function _init_block(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = 0;
+ do {
+  HEAP16[i1 + (i3 << 2) + 148 >> 1] = 0;
+  i3 = i3 + 1 | 0;
+ } while ((i3 | 0) != 286);
+ HEAP16[i1 + 2440 >> 1] = 0;
+ HEAP16[i1 + 2444 >> 1] = 0;
+ HEAP16[i1 + 2448 >> 1] = 0;
+ HEAP16[i1 + 2452 >> 1] = 0;
+ HEAP16[i1 + 2456 >> 1] = 0;
+ HEAP16[i1 + 2460 >> 1] = 0;
+ HEAP16[i1 + 2464 >> 1] = 0;
+ HEAP16[i1 + 2468 >> 1] = 0;
+ HEAP16[i1 + 2472 >> 1] = 0;
+ HEAP16[i1 + 2476 >> 1] = 0;
+ HEAP16[i1 + 2480 >> 1] = 0;
+ HEAP16[i1 + 2484 >> 1] = 0;
+ HEAP16[i1 + 2488 >> 1] = 0;
+ HEAP16[i1 + 2492 >> 1] = 0;
+ HEAP16[i1 + 2496 >> 1] = 0;
+ HEAP16[i1 + 2500 >> 1] = 0;
+ HEAP16[i1 + 2504 >> 1] = 0;
+ HEAP16[i1 + 2508 >> 1] = 0;
+ HEAP16[i1 + 2512 >> 1] = 0;
+ HEAP16[i1 + 2516 >> 1] = 0;
+ HEAP16[i1 + 2520 >> 1] = 0;
+ HEAP16[i1 + 2524 >> 1] = 0;
+ HEAP16[i1 + 2528 >> 1] = 0;
+ HEAP16[i1 + 2532 >> 1] = 0;
+ HEAP16[i1 + 2536 >> 1] = 0;
+ HEAP16[i1 + 2540 >> 1] = 0;
+ HEAP16[i1 + 2544 >> 1] = 0;
+ HEAP16[i1 + 2548 >> 1] = 0;
+ HEAP16[i1 + 2552 >> 1] = 0;
+ HEAP16[i1 + 2556 >> 1] = 0;
+ HEAP16[i1 + 2684 >> 1] = 0;
+ HEAP16[i1 + 2688 >> 1] = 0;
+ HEAP16[i1 + 2692 >> 1] = 0;
+ HEAP16[i1 + 2696 >> 1] = 0;
+ HEAP16[i1 + 2700 >> 1] = 0;
+ HEAP16[i1 + 2704 >> 1] = 0;
+ HEAP16[i1 + 2708 >> 1] = 0;
+ HEAP16[i1 + 2712 >> 1] = 0;
+ HEAP16[i1 + 2716 >> 1] = 0;
+ HEAP16[i1 + 2720 >> 1] = 0;
+ HEAP16[i1 + 2724 >> 1] = 0;
+ HEAP16[i1 + 2728 >> 1] = 0;
+ HEAP16[i1 + 2732 >> 1] = 0;
+ HEAP16[i1 + 2736 >> 1] = 0;
+ HEAP16[i1 + 2740 >> 1] = 0;
+ HEAP16[i1 + 2744 >> 1] = 0;
+ HEAP16[i1 + 2748 >> 1] = 0;
+ HEAP16[i1 + 2752 >> 1] = 0;
+ HEAP16[i1 + 2756 >> 1] = 0;
+ HEAP16[i1 + 1172 >> 1] = 1;
+ HEAP32[i1 + 5804 >> 2] = 0;
+ HEAP32[i1 + 5800 >> 2] = 0;
+ HEAP32[i1 + 5808 >> 2] = 0;
+ HEAP32[i1 + 5792 >> 2] = 0;
+ STACKTOP = i2;
+ return;
+}
+function _deflateReset(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ if ((i1 | 0) == 0) {
+  i5 = -2;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ i3 = HEAP32[i1 + 28 >> 2] | 0;
+ if ((i3 | 0) == 0) {
+  i5 = -2;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ if ((HEAP32[i1 + 32 >> 2] | 0) == 0) {
+  i5 = -2;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ if ((HEAP32[i1 + 36 >> 2] | 0) == 0) {
+  i5 = -2;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ HEAP32[i1 + 20 >> 2] = 0;
+ HEAP32[i1 + 8 >> 2] = 0;
+ HEAP32[i1 + 24 >> 2] = 0;
+ HEAP32[i1 + 44 >> 2] = 2;
+ HEAP32[i3 + 20 >> 2] = 0;
+ HEAP32[i3 + 16 >> 2] = HEAP32[i3 + 8 >> 2];
+ i4 = i3 + 24 | 0;
+ i5 = HEAP32[i4 >> 2] | 0;
+ if ((i5 | 0) < 0) {
+  i5 = 0 - i5 | 0;
+  HEAP32[i4 >> 2] = i5;
+ }
+ HEAP32[i3 + 4 >> 2] = (i5 | 0) != 0 ? 42 : 113;
+ if ((i5 | 0) == 2) {
+  i4 = _crc32(0, 0, 0) | 0;
+ } else {
+  i4 = _adler32(0, 0, 0) | 0;
+ }
+ HEAP32[i1 + 48 >> 2] = i4;
+ HEAP32[i3 + 40 >> 2] = 0;
+ __tr_init(i3);
+ HEAP32[i3 + 60 >> 2] = HEAP32[i3 + 44 >> 2] << 1;
+ i5 = HEAP32[i3 + 76 >> 2] | 0;
+ i4 = HEAP32[i3 + 68 >> 2] | 0;
+ HEAP16[i4 + (i5 + -1 << 1) >> 1] = 0;
+ _memset(i4 | 0, 0, (i5 << 1) + -2 | 0) | 0;
+ i5 = HEAP32[i3 + 132 >> 2] | 0;
+ HEAP32[i3 + 128 >> 2] = HEAPU16[178 + (i5 * 12 | 0) >> 1] | 0;
+ HEAP32[i3 + 140 >> 2] = HEAPU16[176 + (i5 * 12 | 0) >> 1] | 0;
+ HEAP32[i3 + 144 >> 2] = HEAPU16[180 + (i5 * 12 | 0) >> 1] | 0;
+ HEAP32[i3 + 124 >> 2] = HEAPU16[182 + (i5 * 12 | 0) >> 1] | 0;
+ HEAP32[i3 + 108 >> 2] = 0;
+ HEAP32[i3 + 92 >> 2] = 0;
+ HEAP32[i3 + 116 >> 2] = 0;
+ HEAP32[i3 + 120 >> 2] = 2;
+ HEAP32[i3 + 96 >> 2] = 2;
+ HEAP32[i3 + 112 >> 2] = 0;
+ HEAP32[i3 + 104 >> 2] = 0;
+ HEAP32[i3 + 72 >> 2] = 0;
+ i5 = 0;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _updatewindow(i6, i4) {
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ i2 = HEAP32[i6 + 28 >> 2] | 0;
+ i3 = i2 + 52 | 0;
+ i8 = HEAP32[i3 >> 2] | 0;
+ if ((i8 | 0) == 0) {
+  i8 = FUNCTION_TABLE_iiii[HEAP32[i6 + 32 >> 2] & 1](HEAP32[i6 + 40 >> 2] | 0, 1 << HEAP32[i2 + 36 >> 2], 1) | 0;
+  HEAP32[i3 >> 2] = i8;
+  if ((i8 | 0) == 0) {
+   i10 = 1;
+   STACKTOP = i1;
+   return i10 | 0;
+  }
+ }
+ i5 = i2 + 40 | 0;
+ i10 = HEAP32[i5 >> 2] | 0;
+ if ((i10 | 0) == 0) {
+  i10 = 1 << HEAP32[i2 + 36 >> 2];
+  HEAP32[i5 >> 2] = i10;
+  HEAP32[i2 + 48 >> 2] = 0;
+  HEAP32[i2 + 44 >> 2] = 0;
+ }
+ i4 = i4 - (HEAP32[i6 + 16 >> 2] | 0) | 0;
+ if (!(i4 >>> 0 < i10 >>> 0)) {
+  _memcpy(i8 | 0, (HEAP32[i6 + 12 >> 2] | 0) + (0 - i10) | 0, i10 | 0) | 0;
+  HEAP32[i2 + 48 >> 2] = 0;
+  HEAP32[i2 + 44 >> 2] = HEAP32[i5 >> 2];
+  i10 = 0;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ i7 = i2 + 48 | 0;
+ i9 = HEAP32[i7 >> 2] | 0;
+ i10 = i10 - i9 | 0;
+ i10 = i10 >>> 0 > i4 >>> 0 ? i4 : i10;
+ i6 = i6 + 12 | 0;
+ _memcpy(i8 + i9 | 0, (HEAP32[i6 >> 2] | 0) + (0 - i4) | 0, i10 | 0) | 0;
+ i8 = i4 - i10 | 0;
+ if ((i4 | 0) != (i10 | 0)) {
+  _memcpy(HEAP32[i3 >> 2] | 0, (HEAP32[i6 >> 2] | 0) + (0 - i8) | 0, i8 | 0) | 0;
+  HEAP32[i7 >> 2] = i8;
+  HEAP32[i2 + 44 >> 2] = HEAP32[i5 >> 2];
+  i10 = 0;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ i6 = (HEAP32[i7 >> 2] | 0) + i4 | 0;
+ i3 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i7 >> 2] = (i6 | 0) == (i3 | 0) ? 0 : i6;
+ i5 = i2 + 44 | 0;
+ i2 = HEAP32[i5 >> 2] | 0;
+ if (!(i2 >>> 0 < i3 >>> 0)) {
+  i10 = 0;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ HEAP32[i5 >> 2] = i2 + i4;
+ i10 = 0;
+ STACKTOP = i1;
+ return i10 | 0;
+}
+function _scan_tree(i1, i5, i6) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0;
+ i8 = STACKTOP;
+ i10 = HEAP16[i5 + 2 >> 1] | 0;
+ i9 = i10 << 16 >> 16 == 0;
+ HEAP16[i5 + (i6 + 1 << 2) + 2 >> 1] = -1;
+ i2 = i1 + 2752 | 0;
+ i3 = i1 + 2756 | 0;
+ i4 = i1 + 2748 | 0;
+ i7 = i9 ? 138 : 7;
+ i9 = i9 ? 3 : 4;
+ i13 = 0;
+ i11 = i10 & 65535;
+ i12 = -1;
+ L1 : while (1) {
+  i14 = 0;
+  do {
+   if ((i13 | 0) > (i6 | 0)) {
+    break L1;
+   }
+   i13 = i13 + 1 | 0;
+   i16 = HEAP16[i5 + (i13 << 2) + 2 >> 1] | 0;
+   i10 = i16 & 65535;
+   i14 = i14 + 1 | 0;
+   i15 = (i11 | 0) == (i10 | 0);
+  } while ((i14 | 0) < (i7 | 0) & i15);
+  do {
+   if ((i14 | 0) >= (i9 | 0)) {
+    if ((i11 | 0) == 0) {
+     if ((i14 | 0) < 11) {
+      HEAP16[i2 >> 1] = (HEAP16[i2 >> 1] | 0) + 1 << 16 >> 16;
+      break;
+     } else {
+      HEAP16[i3 >> 1] = (HEAP16[i3 >> 1] | 0) + 1 << 16 >> 16;
+      break;
+     }
+    } else {
+     if ((i11 | 0) != (i12 | 0)) {
+      i14 = i1 + (i11 << 2) + 2684 | 0;
+      HEAP16[i14 >> 1] = (HEAP16[i14 >> 1] | 0) + 1 << 16 >> 16;
+     }
+     HEAP16[i4 >> 1] = (HEAP16[i4 >> 1] | 0) + 1 << 16 >> 16;
+     break;
+    }
+   } else {
+    i12 = i1 + (i11 << 2) + 2684 | 0;
+    HEAP16[i12 >> 1] = (HEAPU16[i12 >> 1] | 0) + i14;
+   }
+  } while (0);
+  if (i16 << 16 >> 16 == 0) {
+   i12 = i11;
+   i7 = 138;
+   i9 = 3;
+   i11 = i10;
+   continue;
+  }
+  i12 = i11;
+  i7 = i15 ? 6 : 7;
+  i9 = i15 ? 3 : 4;
+  i11 = i10;
+ }
+ STACKTOP = i8;
+ return;
+}
+function _deflateEnd(i4) {
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i3 = STACKTOP;
+ if ((i4 | 0) == 0) {
+  i7 = -2;
+  STACKTOP = i3;
+  return i7 | 0;
+ }
+ i1 = i4 + 28 | 0;
+ i6 = HEAP32[i1 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  i7 = -2;
+  STACKTOP = i3;
+  return i7 | 0;
+ }
+ i2 = HEAP32[i6 + 4 >> 2] | 0;
+ switch (i2 | 0) {
+ case 42:
+ case 69:
+ case 73:
+ case 91:
+ case 103:
+ case 113:
+ case 666:
+  {
+   break;
+  }
+ default:
+  {
+   i7 = -2;
+   STACKTOP = i3;
+   return i7 | 0;
+  }
+ }
+ i5 = HEAP32[i6 + 8 >> 2] | 0;
+ if ((i5 | 0) != 0) {
+  FUNCTION_TABLE_vii[HEAP32[i4 + 36 >> 2] & 1](HEAP32[i4 + 40 >> 2] | 0, i5);
+  i6 = HEAP32[i1 >> 2] | 0;
+ }
+ i5 = HEAP32[i6 + 68 >> 2] | 0;
+ if ((i5 | 0) != 0) {
+  FUNCTION_TABLE_vii[HEAP32[i4 + 36 >> 2] & 1](HEAP32[i4 + 40 >> 2] | 0, i5);
+  i6 = HEAP32[i1 >> 2] | 0;
+ }
+ i5 = HEAP32[i6 + 64 >> 2] | 0;
+ if ((i5 | 0) != 0) {
+  FUNCTION_TABLE_vii[HEAP32[i4 + 36 >> 2] & 1](HEAP32[i4 + 40 >> 2] | 0, i5);
+  i6 = HEAP32[i1 >> 2] | 0;
+ }
+ i7 = HEAP32[i6 + 56 >> 2] | 0;
+ i5 = i4 + 36 | 0;
+ if ((i7 | 0) == 0) {
+  i4 = i4 + 40 | 0;
+ } else {
+  i4 = i4 + 40 | 0;
+  FUNCTION_TABLE_vii[HEAP32[i5 >> 2] & 1](HEAP32[i4 >> 2] | 0, i7);
+  i6 = HEAP32[i1 >> 2] | 0;
+ }
+ FUNCTION_TABLE_vii[HEAP32[i5 >> 2] & 1](HEAP32[i4 >> 2] | 0, i6);
+ HEAP32[i1 >> 2] = 0;
+ i7 = (i2 | 0) == 113 ? -3 : 0;
+ STACKTOP = i3;
+ return i7 | 0;
+}
+function _main(i4, i5) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i6 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ L1 : do {
+  if ((i4 | 0) > 1) {
+   i4 = HEAP8[HEAP32[i5 + 4 >> 2] | 0] | 0;
+   switch (i4 | 0) {
+   case 50:
+    {
+     i2 = 250;
+     break L1;
+    }
+   case 51:
+    {
+     i3 = 4;
+     break L1;
+    }
+   case 52:
+    {
+     i2 = 2500;
+     break L1;
+    }
+   case 53:
+    {
+     i2 = 5e3;
+     break L1;
+    }
+   case 48:
+    {
+     i6 = 0;
+     STACKTOP = i1;
+     return i6 | 0;
+    }
+   case 49:
+    {
+     i2 = 60;
+     break L1;
+    }
+   default:
+    {
+     HEAP32[i2 >> 2] = i4 + -48;
+     _printf(144, i2 | 0) | 0;
+     i6 = -1;
+     STACKTOP = i1;
+     return i6 | 0;
+    }
+   }
+  } else {
+   i3 = 4;
+  }
+ } while (0);
+ if ((i3 | 0) == 4) {
+  i2 = 500;
+ }
+ i3 = _malloc(1e5) | 0;
+ i4 = 0;
+ i6 = 0;
+ i5 = 17;
+ while (1) {
+  do {
+   if ((i6 | 0) <= 0) {
+    if ((i4 & 7 | 0) == 0) {
+     i6 = i4 & 31;
+     i5 = 0;
+     break;
+    } else {
+     i5 = (((Math_imul(i4, i4) | 0) >>> 0) % 6714 | 0) & 255;
+     break;
+    }
+   } else {
+    i6 = i6 + -1 | 0;
+   }
+  } while (0);
+  HEAP8[i3 + i4 | 0] = i5;
+  i4 = i4 + 1 | 0;
+  if ((i4 | 0) == 1e5) {
+   i4 = 0;
+   break;
+  }
+ }
+ do {
+  _doit(i3, 1e5, i4);
+  i4 = i4 + 1 | 0;
+ } while ((i4 | 0) < (i2 | 0));
+ _puts(160) | 0;
+ i6 = 0;
+ STACKTOP = i1;
+ return i6 | 0;
+}
+function _doit(i6, i1, i7) {
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i8 = 0, i9 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i5;
+ i3 = i5 + 12 | 0;
+ i2 = i5 + 8 | 0;
+ i8 = _compressBound(i1) | 0;
+ i9 = HEAP32[2] | 0;
+ if ((i9 | 0) == 0) {
+  i9 = _malloc(i8) | 0;
+  HEAP32[2] = i9;
+ }
+ if ((HEAP32[4] | 0) == 0) {
+  HEAP32[4] = _malloc(i1) | 0;
+ }
+ HEAP32[i3 >> 2] = i8;
+ _compress(i9, i3, i6, i1) | 0;
+ i7 = (i7 | 0) == 0;
+ if (i7) {
+  i9 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i4 >> 2] = i1;
+  HEAP32[i4 + 4 >> 2] = i9;
+  _printf(24, i4 | 0) | 0;
+ }
+ HEAP32[i2 >> 2] = i1;
+ _uncompress(HEAP32[4] | 0, i2, HEAP32[2] | 0, HEAP32[i3 >> 2] | 0) | 0;
+ if ((HEAP32[i2 >> 2] | 0) != (i1 | 0)) {
+  ___assert_fail(40, 72, 24, 104);
+ }
+ if (!i7) {
+  STACKTOP = i5;
+  return;
+ }
+ if ((_strcmp(i6, HEAP32[4] | 0) | 0) == 0) {
+  STACKTOP = i5;
+  return;
+ } else {
+  ___assert_fail(112, 72, 25, 104);
+ }
+}
+function _uncompress(i6, i1, i5, i7) {
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i3 = i2;
+ HEAP32[i3 >> 2] = i5;
+ i5 = i3 + 4 | 0;
+ HEAP32[i5 >> 2] = i7;
+ HEAP32[i3 + 12 >> 2] = i6;
+ HEAP32[i3 + 16 >> 2] = HEAP32[i1 >> 2];
+ HEAP32[i3 + 32 >> 2] = 0;
+ HEAP32[i3 + 36 >> 2] = 0;
+ i6 = _inflateInit_(i3, 2992, 56) | 0;
+ if ((i6 | 0) != 0) {
+  i7 = i6;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ i6 = _inflate(i3, 4) | 0;
+ if ((i6 | 0) == 1) {
+  HEAP32[i1 >> 2] = HEAP32[i3 + 20 >> 2];
+  i7 = _inflateEnd(i3) | 0;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ _inflateEnd(i3) | 0;
+ if ((i6 | 0) == 2) {
+  i7 = -3;
+  STACKTOP = i2;
+  return i7 | 0;
+ } else if ((i6 | 0) == -5) {
+  i4 = 4;
+ }
+ if ((i4 | 0) == 4 ? (HEAP32[i5 >> 2] | 0) == 0 : 0) {
+  i7 = -3;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ i7 = i6;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _compress(i4, i1, i6, i5) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i3 = i2;
+ HEAP32[i3 >> 2] = i6;
+ HEAP32[i3 + 4 >> 2] = i5;
+ HEAP32[i3 + 12 >> 2] = i4;
+ HEAP32[i3 + 16 >> 2] = HEAP32[i1 >> 2];
+ HEAP32[i3 + 32 >> 2] = 0;
+ HEAP32[i3 + 36 >> 2] = 0;
+ HEAP32[i3 + 40 >> 2] = 0;
+ i4 = _deflateInit_(i3, -1, 168, 56) | 0;
+ if ((i4 | 0) != 0) {
+  i6 = i4;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ i4 = _deflate(i3, 4) | 0;
+ if ((i4 | 0) == 1) {
+  HEAP32[i1 >> 2] = HEAP32[i3 + 20 >> 2];
+  i6 = _deflateEnd(i3) | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ } else {
+  _deflateEnd(i3) | 0;
+  i6 = (i4 | 0) == 0 ? -5 : i4;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ return 0;
+}
+function _inflateEnd(i4) {
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ if ((i4 | 0) == 0) {
+  i7 = -2;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ i2 = i4 + 28 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ if ((i3 | 0) == 0) {
+  i7 = -2;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ i6 = i4 + 36 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ if ((i5 | 0) == 0) {
+  i7 = -2;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ i7 = HEAP32[i3 + 52 >> 2] | 0;
+ i4 = i4 + 40 | 0;
+ if ((i7 | 0) != 0) {
+  FUNCTION_TABLE_vii[i5 & 1](HEAP32[i4 >> 2] | 0, i7);
+  i5 = HEAP32[i6 >> 2] | 0;
+  i3 = HEAP32[i2 >> 2] | 0;
+ }
+ FUNCTION_TABLE_vii[i5 & 1](HEAP32[i4 >> 2] | 0, i3);
+ HEAP32[i2 >> 2] = 0;
+ i7 = 0;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function _strcmp(i4, i2) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i5 = 0;
+ i1 = STACKTOP;
+ i5 = HEAP8[i4] | 0;
+ i3 = HEAP8[i2] | 0;
+ if (i5 << 24 >> 24 != i3 << 24 >> 24 | i5 << 24 >> 24 == 0 | i3 << 24 >> 24 == 0) {
+  i4 = i5;
+  i5 = i3;
+  i4 = i4 & 255;
+  i5 = i5 & 255;
+  i5 = i4 - i5 | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ do {
+  i4 = i4 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i5 = HEAP8[i4] | 0;
+  i3 = HEAP8[i2] | 0;
+ } while (!(i5 << 24 >> 24 != i3 << 24 >> 24 | i5 << 24 >> 24 == 0 | i3 << 24 >> 24 == 0));
+ i4 = i5 & 255;
+ i5 = i3 & 255;
+ i5 = i4 - i5 | 0;
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function __tr_init(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ HEAP32[i1 + 2840 >> 2] = i1 + 148;
+ HEAP32[i1 + 2848 >> 2] = 1064;
+ HEAP32[i1 + 2852 >> 2] = i1 + 2440;
+ HEAP32[i1 + 2860 >> 2] = 1088;
+ HEAP32[i1 + 2864 >> 2] = i1 + 2684;
+ HEAP32[i1 + 2872 >> 2] = 1112;
+ HEAP16[i1 + 5816 >> 1] = 0;
+ HEAP32[i1 + 5820 >> 2] = 0;
+ HEAP32[i1 + 5812 >> 2] = 8;
+ _init_block(i1);
+ STACKTOP = i2;
+ return;
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function _deflateInit_(i4, i3, i2, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i5 = 0;
+ i5 = STACKTOP;
+ i4 = _deflateInit2_(i4, i3, 8, 15, 8, 0, i2, i1) | 0;
+ STACKTOP = i5;
+ return i4 | 0;
+}
+function _zcalloc(i3, i1, i2) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i4 = 0;
+ i4 = STACKTOP;
+ i3 = _malloc(Math_imul(i2, i1) | 0) | 0;
+ STACKTOP = i4;
+ return i3 | 0;
+}
+function dynCall_iiii(i4, i3, i2, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iiii[i4 & 1](i3 | 0, i2 | 0, i1 | 0) | 0;
+}
+function runPostSets() {}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function dynCall_iii(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iii[i3 & 3](i2 | 0, i1 | 0) | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function dynCall_vii(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_vii[i3 & 1](i2 | 0, i1 | 0);
+}
+function _zcfree(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ i2 = STACKTOP;
+ _free(i1);
+ STACKTOP = i2;
+ return;
+}
+function _compressBound(i1) {
+ i1 = i1 | 0;
+ return i1 + 13 + (i1 >>> 12) + (i1 >>> 14) + (i1 >>> 25) | 0;
+}
+function b0(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ abort(0);
+ return 0;
+}
+function b2(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ abort(2);
+ return 0;
+}
+function b1(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ abort(1);
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+
+// EMSCRIPTEN_END_FUNCS
+  var FUNCTION_TABLE_iiii = [b0,_zcalloc];
+  var FUNCTION_TABLE_vii = [b1,_zcfree];
+  var FUNCTION_TABLE_iii = [b2,_deflate_stored,_deflate_fast,_deflate_slow];
+
+  return { _strlen: _strlen, _free: _free, _main: _main, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9, dynCall_iiii: dynCall_iiii, dynCall_vii: dynCall_vii, dynCall_iii: dynCall_iii };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "invoke_iiii": invoke_iiii, "invoke_vii": invoke_vii, "invoke_iii": invoke_iii, "_send": _send, "___setErrNo": ___setErrNo, "___assert_fail": ___assert_fail, "_fflush": _fflush, "_pwrite": _pwrite, "__reallyNegative": __reallyNegative, "_sbrk": _sbrk, "___errno_location": ___errno_location, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_fileno": _fileno, "_sysconf": _sysconf, "_puts": _puts, "_mkport": _mkport, "_write": _write, "_llvm_bswap_i32": _llvm_bswap_i32, "_fputc": _fputc, "_abort": _abort, "_fwrite": _fwrite, "_time": _time, "_fprintf": _fprintf, "__formatString": __formatString, "_fputs": _fputs, "_printf": _printf, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _free = Module["_free"] = asm["_free"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var _malloc = Module["_malloc"] = asm["_malloc"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+var dynCall_iiii = Module["dynCall_iiii"] = asm["dynCall_iiii"];
+var dynCall_vii = Module["dynCall_vii"] = asm["dynCall_vii"];
+var dynCall_iii = Module["dynCall_iii"] = asm["dynCall_iii"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/float32array-negative-offset.js b/test/mjsunit/asm/float32array-negative-offset.js
new file mode 100644
index 0000000..524bdc8
--- /dev/null
+++ b/test/mjsunit/asm/float32array-negative-offset.js
@@ -0,0 +1,42 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+
+var m = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Float32Array(heap);
+  function load(i) {
+    i = i|0;
+    i = +MEM32[i >> 2];
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = +v;
+    MEM32[i >> 2] = v;
+  }
+  function load8(i) {
+    i = i|0;
+    i = +MEM32[i + 8 >> 2];
+    return i;
+  }
+  function store8(i, v) {
+    i = i|0;
+    v = +v;
+    MEM32[i + 8 >> 2] = v;
+  }
+  return { load: load, store: store, load8: load8, store8: store8 };
+})(stdlib, foreign, buffer);
+
+assertEquals(NaN, m.load(-8));
+assertEquals(NaN, m.load8(-16));
+m.store(0, 42.0);
+assertEquals(42.0, m.load8(-8));
+m.store8(-8, 99.0);
+assertEquals(99.0, m.load(0));
+assertEquals(99.0, m.load8(-8));
diff --git a/test/mjsunit/asm/float32array-outofbounds.js b/test/mjsunit/asm/float32array-outofbounds.js
new file mode 100644
index 0000000..8709b70
--- /dev/null
+++ b/test/mjsunit/asm/float32array-outofbounds.js
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Float32Array(heap);
+  function load(i) {
+    i = i|0;
+    i = +MEM32[i >> 2];
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = +v;
+    MEM32[i >> 2] = v;
+  }
+  return { load: load, store: store };
+}
+
+var m = Module(this, {}, new ArrayBuffer(4));
+
+m.store(0, 42.0);
+for (var i = 1; i < 64; ++i) {
+  m.store(i * 4 * 32 * 1024, i);
+}
+assertEquals(42.0, m.load(0));
+for (var i = 1; i < 64; ++i) {
+  assertEquals(NaN, m.load(i * 4 * 32 * 1024));
+}
diff --git a/test/mjsunit/asm/float32array-store-div.js b/test/mjsunit/asm/float32array-store-div.js
new file mode 100644
index 0000000..78224f9
--- /dev/null
+++ b/test/mjsunit/asm/float32array-store-div.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Float32Array(heap);
+  function foo(i) {
+    MEM32[0] = (i >>> 0) / 2;
+    return MEM32[0];
+  }
+  return { foo: foo };
+}
+
+var foo = Module(this, {}, new ArrayBuffer(64 * 1024)).foo;
+assertEquals(0.5, foo(1));
diff --git a/test/mjsunit/asm/float64array-negative-offset.js b/test/mjsunit/asm/float64array-negative-offset.js
new file mode 100644
index 0000000..154bd82
--- /dev/null
+++ b/test/mjsunit/asm/float64array-negative-offset.js
@@ -0,0 +1,42 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+
+var m = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM64 = new stdlib.Float64Array(heap);
+  function load(i) {
+    i = i|0;
+    i = +MEM64[i >> 3];
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = +v;
+    MEM64[i >> 3] = v;
+  }
+  function load8(i) {
+    i = i|0;
+    i = +MEM64[i + 8 >> 3];
+    return i;
+  }
+  function store8(i, v) {
+    i = i|0;
+    v = +v;
+    MEM64[i + 8 >> 3] = v;
+  }
+  return { load: load, store: store, load8: load8, store8: store8 };
+})(stdlib, foreign, buffer);
+
+assertEquals(NaN, m.load(-8));
+assertEquals(NaN, m.load8(-16));
+m.store(0, 42.0);
+assertEquals(42.0, m.load8(-8));
+m.store8(-8, 99.0);
+assertEquals(99.0, m.load(0));
+assertEquals(99.0, m.load8(-8));
diff --git a/test/mjsunit/asm/float64array-outofbounds.js b/test/mjsunit/asm/float64array-outofbounds.js
new file mode 100644
index 0000000..106d8e4
--- /dev/null
+++ b/test/mjsunit/asm/float64array-outofbounds.js
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM64 = new stdlib.Float64Array(heap);
+  function load(i) {
+    i = i|0;
+    i = +MEM64[i >> 3];
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = +v;
+    MEM64[i >> 3] = v;
+  }
+  return { load: load, store: store };
+}
+
+var m = Module(this, {}, new ArrayBuffer(8));
+
+m.store(0, 3.12);
+for (var i = 1; i < 64; ++i) {
+  m.store(i * 8 * 32 * 1024, i);
+}
+assertEquals(3.12, m.load(0));
+for (var i = 1; i < 64; ++i) {
+  assertEquals(NaN, m.load(i * 8 * 32 * 1024));
+}
diff --git a/test/mjsunit/asm/float64array-store-div.js b/test/mjsunit/asm/float64array-store-div.js
new file mode 100644
index 0000000..10b0011
--- /dev/null
+++ b/test/mjsunit/asm/float64array-store-div.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM64 = new stdlib.Float64Array(heap);
+  function foo(i) {
+    MEM64[0] = (i >>> 0) / 2;
+    return MEM64[0];
+  }
+  return { foo: foo };
+}
+
+var foo = Module(this, {}, new ArrayBuffer(64 * 1024)).foo;
+assertEquals(0.5, foo(1));
diff --git a/test/mjsunit/asm/float64mul.js b/test/mjsunit/asm/float64mul.js
new file mode 100644
index 0000000..9cd9582
--- /dev/null
+++ b/test/mjsunit/asm/float64mul.js
@@ -0,0 +1,43 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function f1(i) {
+    i = +i;
+    return +(i * -1);
+  }
+  function f2(i) {
+    i = +i;
+    return +(-1 * i);
+  }
+  function f3(i) {
+    i = +i;
+    return +(-i);
+  }
+  return { f1: f1, f2: f2, f3: f3 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(64 * 1024));
+
+assertEquals(NaN, m.f1(NaN));
+assertEquals(NaN, m.f2(NaN));
+assertEquals(NaN, m.f3(NaN));
+assertEquals(Infinity, 1 / m.f1(-0));
+assertEquals(Infinity, 1 / m.f2(-0));
+assertEquals(Infinity, 1 / m.f3(-0));
+assertEquals(Infinity, m.f1(-Infinity));
+assertEquals(Infinity, m.f2(-Infinity));
+assertEquals(Infinity, m.f3(-Infinity));
+assertEquals(-Infinity, 1 / m.f1(0));
+assertEquals(-Infinity, 1 / m.f2(0));
+assertEquals(-Infinity, 1 / m.f3(0));
+assertEquals(-Infinity, m.f1(Infinity));
+assertEquals(-Infinity, m.f2(Infinity));
+assertEquals(-Infinity, m.f3(Infinity));
+for (var i = -2147483648; i < 2147483648; i += 3999777) {
+  assertEquals(-i, m.f1(i));
+  assertEquals(-i, m.f2(i));
+  assertEquals(-i, m.f3(i));
+}
diff --git a/test/mjsunit/asm/if-folding.js b/test/mjsunit/asm/if-folding.js
new file mode 100644
index 0000000..80070ee
--- /dev/null
+++ b/test/mjsunit/asm/if-folding.js
@@ -0,0 +1,100 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module() {
+  "use asm";
+
+  function if0() {
+    if (0) return 11;
+    return 12;
+  }
+
+  function if1() {
+    if (1) return 13;
+    return 14;
+  }
+
+  function if2() {
+    if (0) return 15;
+    else return 16;
+  }
+
+  function if3() {
+    if (1) return 17;
+    else return 18;
+  }
+
+  function if4() {
+    return 1 ? 19 : 20;
+  }
+
+  function if5() {
+    return 0 ? 21 : 22;
+  }
+
+  function if6() {
+    var x = 0 ? 23 : 24;
+    return x;
+  }
+
+  function if7() {
+    if (0) { var x = 0 ? 25 : 26; }
+    else { var x = 0 ? 27 : 28; }
+    return x;
+  }
+
+  function if8() {
+    if (0) {
+      if (0) { var x = 0 ? 29 : 30; }
+      else { var x = 0 ? 31 : 32; }
+    } else {
+      if (0) { var x = 0 ? 33 : 34; }
+      else { var x = 0 ? 35 : 36; }
+    }
+    return x;
+  }
+
+  return {if0: if0, if1: if1, if2: if2, if3: if3, if4: if4, if5: if5, if6: if6, if7: if7, if8: if8 };
+}
+
+var m = Module();
+assertEquals(12, m.if0());
+assertEquals(13, m.if1());
+assertEquals(16, m.if2());
+assertEquals(17, m.if3());
+assertEquals(19, m.if4());
+assertEquals(22, m.if5());
+assertEquals(24, m.if6());
+assertEquals(28, m.if7());
+assertEquals(36, m.if8());
+
+
+function Spec(a,b,c) {
+  "use asm";
+
+  var xx = a | 0;
+  var yy = b | 0;
+  var zz = c | 0;
+
+  function f() {
+    if (xx) {
+      if (yy) { var x = zz ? 29 : 30; }
+      else { var x = zz ? 31 : 32; }
+    } else {
+      if (yy) { var x = zz ? 33 : 34; }
+      else { var x = zz ? 35 : 36; }
+    }
+    return x;
+  }
+  return {f: f};
+}
+
+assertEquals(36, Spec(0,0,0).f());
+assertEquals(35, Spec(0,0,1).f());
+assertEquals(34, Spec(0,1,0).f());
+assertEquals(33, Spec(0,1,1).f());
+assertEquals(32, Spec(1,0,0).f());
+assertEquals(31, Spec(1,0,1).f());
+assertEquals(30, Spec(1,1,0).f());
+assertEquals(29, Spec(1,1,1).f());
diff --git a/test/mjsunit/asm/if-reduction.js b/test/mjsunit/asm/if-reduction.js
new file mode 100644
index 0000000..b0dcc13
--- /dev/null
+++ b/test/mjsunit/asm/if-reduction.js
@@ -0,0 +1,111 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module() {
+  "use asm";
+
+  function if0() {
+    var x = 0 ? 11 : 12;
+    return (x == 11) | 0;
+  }
+
+  function if1() {
+    var x = 1 ? 13 : 14;
+    return (x == 13) | 0;
+  }
+
+  function if2() {
+    var x = 0 ? 15 : 16;
+    return (x != 15) | 0;
+  }
+
+  function if3() {
+    var x = 1 ? 17 : 18;
+    return (x != 17) | 0;
+  }
+
+  function if4() {
+    var x = 0 ? 19 : 20;
+    var y = (x == 19) ? 21 : 22;
+    return y;
+  }
+
+  function if5() {
+    var x = 1 ? 23 : 24;
+    var y = (x == 23) ? 25 : 26;
+    return y;
+  }
+
+  function if6() {
+    var x = 0 ? 27 : 28;
+    var y = (x == 27) ? 29 : 30;
+    var z = (y == 29) ? 31 : 32;
+    return z;
+  }
+
+  function if7() {
+    var x = 1 ? 33 : 34;
+    var y = (x == 33) ? 35 : 36;
+    var z = (y == 35) ? 37 : 38;
+    var w = (z == 37) ? 39 : 40;
+    return w;
+  }
+
+  function if8() {
+    if (0) {
+      var x = 0 ? 43 : 44;
+      var y = (x == 43) ? 45 : 46;
+      var z = (y == 45) ? 47 : 48;
+      var w = (z == 47) ? 49 : 50;
+    } else {
+      var x = 1 ? 53 : 54;
+      var y = (x == 53) ? 55 : 56;
+      var z = (y == 55) ? 57 : 58;
+      var w = (z == 57) ? 59 : 60;
+    }
+    return w;
+  }
+
+  return {if0: if0, if1: if1, if2: if2, if3: if3, if4: if4, if5: if5, if6: if6, if7: if7, if8: if8 };
+}
+
+var m = Module();
+assertEquals(0, m.if0());
+assertEquals(1, m.if1());
+assertEquals(1, m.if2());
+assertEquals(0, m.if3());
+assertEquals(22, m.if4());
+assertEquals(25, m.if5());
+assertEquals(32, m.if6());
+assertEquals(39, m.if7());
+assertEquals(59, m.if8());
+
+
+function Spec(a,b) {
+  "use asm";
+
+  var xx = a | 0;
+  var yy = b | 0;
+
+  function f() {
+    if (xx) {
+      var x = yy ? 43 : 44;
+      var y = (x == 43) ? 45 : 46;
+      var z = (y == 45) ? 47 : 48;
+      var w = (z == 47) ? 49 : 50;
+    } else {
+      var x = yy ? 53 : 54;
+      var y = (x == 53) ? 55 : 56;
+      var z = (y == 55) ? 57 : 58;
+      var w = (z == 57) ? 59 : 60;
+    }
+    return w;
+  }
+  return {f: f};
+}
+
+assertEquals(60, Spec(0,0).f());
+assertEquals(59, Spec(0,1).f());
+assertEquals(50, Spec(1,0).f());
+assertEquals(49, Spec(1,1).f());
diff --git a/test/mjsunit/asm/if-tonumber.js b/test/mjsunit/asm/if-tonumber.js
new file mode 100644
index 0000000..dd3f73b
--- /dev/null
+++ b/test/mjsunit/asm/if-tonumber.js
@@ -0,0 +1,31 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function foo(i) {
+    i = i|0;
+    if (i > 0) {
+      i = i == 1;
+    } else {
+      i = 1;
+    }
+    return i & 1|0;
+  }
+  return { foo: foo };
+}
+
+var m = Module(stdlib, foreign, buffer);
+
+assertEquals(1, m.foo(-1));
+assertEquals(1, m.foo(-0));
+assertEquals(1, m.foo(0));
+assertEquals(1, m.foo(1));
+assertEquals(0, m.foo(2));
+assertEquals(1, m.foo(true));
+assertEquals(1, m.foo(false));
diff --git a/test/mjsunit/asm/infinite-loops-taken.js b/test/mjsunit/asm/infinite-loops-taken.js
new file mode 100644
index 0000000..d136c62
--- /dev/null
+++ b/test/mjsunit/asm/infinite-loops-taken.js
@@ -0,0 +1,41 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var error = "error";
+function counter(x) {
+  return (function() { if (x-- == 0) throw error;});
+}
+
+function Module() {
+  "use asm";
+
+  function w0(f) {
+    while (1) f();
+    return 108;
+  }
+
+  function w1(f) {
+    if (1) while (1) f();
+    return 109;
+  }
+
+  function w2(f) {
+    if (1) while (1) f();
+    else while (1) f();
+    return 110;
+  }
+
+  function w3(f) {
+    if (0) while (1) f();
+    return 111;
+  }
+
+  return { w0: w0, w1: w1, w2: w2, w3: w3 };
+}
+
+var m = Module();
+assertThrows(function() { m.w0(counter(5)) }, error);
+assertThrows(function() { m.w1(counter(5)) }, error);
+assertThrows(function() { m.w2(counter(5)) }, error);
+assertEquals(111, m.w3(counter(5)));
diff --git a/test/mjsunit/asm/infinite-loops.js b/test/mjsunit/asm/infinite-loops.js
new file mode 100644
index 0000000..03f4f6b
--- /dev/null
+++ b/test/mjsunit/asm/infinite-loops.js
@@ -0,0 +1,53 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module() {
+  "use asm";
+
+  function w0(a) {
+    a = a | 0;
+    if (a) while (1);
+    return 42;
+  }
+
+  function w1(a) {
+    a = a | 0;
+    while (1) return 42;
+    return 106;
+  }
+
+  function d0(a) {
+    a = a | 0;
+    if (a) do ; while(1);
+    return 42;
+  }
+
+  function d1(a) {
+    a = a | 0;
+    do return 42; while(1);
+    return 107;
+  }
+
+  function f0(a) {
+    a = a | 0;
+    if (a) for (;;) ;
+    return 42;
+  }
+
+  function f1(a) {
+    a = a | 0;
+    for(;;) return 42;
+    return 108;
+  }
+
+  return { w0: w0, w1: w1, d0: d0, d1: d1, f0: f0, f1: f1 };
+}
+
+var m = Module();
+assertEquals(42, m.w0(0));
+assertEquals(42, m.w1(0));
+assertEquals(42, m.d0(0));
+assertEquals(42, m.d1(0));
+assertEquals(42, m.f0(0));
+assertEquals(42, m.f1(0));
diff --git a/test/mjsunit/asm/int16array-negative-offset.js b/test/mjsunit/asm/int16array-negative-offset.js
new file mode 100644
index 0000000..5d33115
--- /dev/null
+++ b/test/mjsunit/asm/int16array-negative-offset.js
@@ -0,0 +1,42 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+
+var m = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM16 = new stdlib.Int16Array(heap);
+  function load(i) {
+    i = i|0;
+    i = MEM16[i >> 1]|0;
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM16[i >> 1] = v;
+  }
+  function load8(i) {
+    i = i|0;
+    i = MEM16[i + 8 >> 1]|0;
+    return i;
+  }
+  function store8(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM16[i + 8 >> 1] = v;
+  }
+  return { load: load, store: store, load8: load8, store8: store8 };
+})(stdlib, foreign, buffer);
+
+assertEquals(0, m.load(-8));
+assertEquals(0, m.load8(-16));
+m.store(0, 42);
+assertEquals(42, m.load8(-8));
+m.store8(-8, 99);
+assertEquals(99, m.load(0));
+assertEquals(99, m.load8(-8));
diff --git a/test/mjsunit/asm/int16array-outofbounds.js b/test/mjsunit/asm/int16array-outofbounds.js
new file mode 100644
index 0000000..7982c00
--- /dev/null
+++ b/test/mjsunit/asm/int16array-outofbounds.js
@@ -0,0 +1,42 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM16 = new stdlib.Int16Array(heap);
+  function load(i) {
+    i = i|0;
+    i = MEM16[i >> 1] | 0;
+    return i;
+  }
+  function loadm1() {
+    return MEM16[-1] | 0;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM16[i >> 1] = v;
+  }
+  function storem1(v) {
+    v = v|0;
+    MEM16[-1] = v;
+  }
+  return {load: load, loadm1: loadm1, store: store, storem1: storem1};
+}
+
+var m = Module(this, {}, new ArrayBuffer(2));
+
+m.store(-1000, 4);
+assertEquals(0, m.load(-1000));
+assertEquals(0, m.loadm1());
+m.storem1(1);
+assertEquals(0, m.loadm1());
+m.store(0, 32767);
+for (var i = 1; i < 64; ++i) {
+  m.store(i * 2 * 32 * 1024, i);
+}
+assertEquals(32767, m.load(0));
+for (var i = 1; i < 64; ++i) {
+  assertEquals(0, m.load(i * 2 * 32 * 1024));
+}
diff --git a/test/mjsunit/asm/int32-div.js b/test/mjsunit/asm/int32-div.js
new file mode 100644
index 0000000..b4d0fef
--- /dev/null
+++ b/test/mjsunit/asm/int32-div.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function f1(i) {
+    i = i|0;
+    return i / 3 | 0;
+  }
+  function f2(i) {
+    i = i|0;
+    return i / 13 | 0;
+  }
+  function f3(i) {
+    i = i|0;
+    return i / 1024 | 0;
+  }
+  function f4(i) {
+    i = i|0;
+    return i / 3733331 | 0;
+  }
+  return { f1: f1, f2: f2, f3: f3, f4: f4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1024));
+
+for (var i = -2147483648; i < 2147483648; i += 3999777) {
+  assertEquals(i / 3 | 0, m.f1(i));
+  assertEquals(i / 13 | 0, m.f2(i));
+  assertEquals(i / 1024 | 0, m.f3(i));
+  assertEquals(i / 3733331 | 0, m.f4(i));
+}
diff --git a/test/mjsunit/asm/int32-mod.js b/test/mjsunit/asm/int32-mod.js
new file mode 100644
index 0000000..b3a7c0e
--- /dev/null
+++ b/test/mjsunit/asm/int32-mod.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function f1(i) {
+    i = i|0;
+    return i % 3;
+  }
+  function f2(i) {
+    i = i|0;
+    return i % 9;
+  }
+  function f3(i) {
+    i = i|0;
+    return i % 1024;
+  }
+  function f4(i) {
+    i = i|0;
+    return i % 3133335;
+  }
+  return { f1: f1, f2: f2, f3: f3, f4: f4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1024));
+
+for (var i = -2147483648; i < 2147483648; i += 3999773) {
+  assertEquals(i % 3, m.f1(i));
+  assertEquals(i % 9, m.f2(i));
+  assertEquals(i % 1024, m.f3(i));
+  assertEquals(i % 3133335, m.f4(i));
+}
diff --git a/test/mjsunit/asm/int32-mul.js b/test/mjsunit/asm/int32-mul.js
new file mode 100644
index 0000000..c5af8a0
--- /dev/null
+++ b/test/mjsunit/asm/int32-mul.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function f1(i) {
+    i = i|0;
+    return i * 3 | 0;
+  }
+  function f2(i) {
+    i = i|0;
+    return i * 7 | 0;
+  }
+  function f3(i) {
+    i = i|0;
+    return i * 1024 | 0;
+  }
+  function f4(i) {
+    i = i|0;
+    return i * 3333339 | 0;
+  }
+  return { f1: f1, f2: f2, f3: f3, f4: f4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1024));
+
+for (var i = -2147483648; i < 2147483648; i += 3999771) {
+  assertEquals(i * 3 | 0, m.f1(i));
+  assertEquals(i * 7 | 0, m.f2(i));
+  assertEquals(i * 1024 | 0, m.f3(i));
+  assertEquals(i * 3333339 | 0, m.f4(i));
+}
diff --git a/test/mjsunit/asm/int32-tmod.js b/test/mjsunit/asm/int32-tmod.js
new file mode 100644
index 0000000..0e294d3
--- /dev/null
+++ b/test/mjsunit/asm/int32-tmod.js
@@ -0,0 +1,38 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function f0(i) {
+    i = i|0;
+    return i % 2 | 0;
+  }
+  function f1(i) {
+    i = i|0;
+    return i % 3 | 0;
+  }
+  function f2(i) {
+    i = i|0;
+    return i % 9 | 0;
+  }
+  function f3(i) {
+    i = i|0;
+    return i % 1024 | 0;
+  }
+  function f4(i) {
+    i = i|0;
+    return i % 3333339 | 0;
+  }
+  return { f0: f0, f1: f1, f2: f2, f3: f3, f4: f4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1024));
+
+for (var i = -2147483648; i < 2147483648; i += 3999773) {
+  assertEquals(i % 2 | 0, m.f0(i));
+  assertEquals(i % 3 | 0, m.f1(i));
+  assertEquals(i % 9 | 0, m.f2(i));
+  assertEquals(i % 1024 | 0, m.f3(i));
+  assertEquals(i % 3333339 | 0, m.f4(i));
+}
diff --git a/test/mjsunit/asm/int32-udiv.js b/test/mjsunit/asm/int32-udiv.js
new file mode 100644
index 0000000..9c67d6f
--- /dev/null
+++ b/test/mjsunit/asm/int32-udiv.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function f1(i) {
+    i = i>>>0;
+    return i / 3 | 0;
+  }
+  function f2(i) {
+    i = i>>>0;
+    return i / 17 | 0;
+  }
+  function f3(i) {
+    i = i>>>0;
+    return i / 1024 | 0;
+  }
+  function f4(i) {
+    i = i>>>0;
+    return i / 3343330 | 0;
+  }
+  return { f1: f1, f2: f2, f3: f3, f4: f4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1024));
+
+for (var i = 0; i < 4294967296; i += 3999777) {
+  assertEquals(i / 3 | 0, m.f1(i));
+  assertEquals(i / 17 | 0, m.f2(i));
+  assertEquals(i / 1024 | 0, m.f3(i));
+  assertEquals(i / 3343330 | 0, m.f4(i));
+}
diff --git a/test/mjsunit/asm/int32-umod.js b/test/mjsunit/asm/int32-umod.js
new file mode 100644
index 0000000..2268966
--- /dev/null
+++ b/test/mjsunit/asm/int32-umod.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function f1(i) {
+    i = i>>>0;
+    return i % 3;
+  }
+  function f2(i) {
+    i = i>>>0;
+    return i % 11;
+  }
+  function f3(i) {
+    i = i>>>0;
+    return i % 1024;
+  }
+  function f4(i) {
+    i = i>>>0;
+    return i % 3333337;
+  }
+  return { f1: f1, f2: f2, f3: f3, f4: f4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1024));
+
+for (var i = 0; i < 4294967296; i += 3999777) {
+  assertEquals(i % 3, m.f1(i));
+  assertEquals(i % 11, m.f2(i));
+  assertEquals(i % 1024, m.f3(i));
+  assertEquals(i % 3333337, m.f4(i));
+}
diff --git a/test/mjsunit/asm/int32array-constant-key.js b/test/mjsunit/asm/int32array-constant-key.js
new file mode 100644
index 0000000..bb5b650
--- /dev/null
+++ b/test/mjsunit/asm/int32array-constant-key.js
@@ -0,0 +1,62 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Int32Array(heap);
+  function loadm4194304() {
+    return MEM32[-4194304];
+  }
+  function loadm0() {
+    return MEM32[-0];
+  }
+  function load0() {
+    return MEM32[0];
+  }
+  function load4() {
+    return MEM32[4];
+  }
+  function storem4194304(v) {
+    MEM32[-4194304] = v;
+  }
+  function storem0(v) {
+    MEM32[-0] = v;
+  }
+  function store0(v) {
+    MEM32[0] = v;
+  }
+  function store4(v) {
+    MEM32[4] = v;
+  }
+  return { loadm4194304: loadm4194304, storem4194304: storem4194304,
+           loadm0: loadm0, storem0: storem0, load0: load0, store0: store0,
+           load4: load4, store4: store4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(4));
+
+assertEquals(undefined, m.loadm4194304());
+assertEquals(0, m.loadm0());
+assertEquals(0, m.load0());
+assertEquals(undefined, m.load4());
+m.storem4194304(123456789);
+assertEquals(undefined, m.loadm4194304());
+assertEquals(0, m.loadm0());
+assertEquals(0, m.load0());
+assertEquals(undefined, m.load4());
+m.storem0(987654321);
+assertEquals(undefined, m.loadm4194304());
+assertEquals(987654321, m.loadm0());
+assertEquals(987654321, m.load0());
+assertEquals(undefined, m.load4());
+m.store0(0x12345678);
+assertEquals(undefined, m.loadm4194304());
+assertEquals(0x12345678, m.loadm0());
+assertEquals(0x12345678, m.load0());
+assertEquals(undefined, m.load4());
+m.store4(43);
+assertEquals(undefined, m.loadm4194304());
+assertEquals(0x12345678, m.loadm0());
+assertEquals(0x12345678, m.load0());
+assertEquals(undefined, m.load4());
diff --git a/test/mjsunit/asm/int32array-negative-offset.js b/test/mjsunit/asm/int32array-negative-offset.js
new file mode 100644
index 0000000..d1a8efa
--- /dev/null
+++ b/test/mjsunit/asm/int32array-negative-offset.js
@@ -0,0 +1,42 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+
+var m = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Int32Array(heap);
+  function load(i) {
+    i = i|0;
+    i = MEM32[i >> 2]|0;
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM32[i >> 2] = v;
+  }
+  function load8(i) {
+    i = i|0;
+    i = MEM32[i + 8 >> 2]|0;
+    return i;
+  }
+  function store8(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM32[i + 8 >> 2] = v;
+  }
+  return { load: load, store: store, load8: load8, store8: store8 };
+})(stdlib, foreign, buffer);
+
+assertEquals(0, m.load(-8));
+assertEquals(0, m.load8(-16));
+m.store(0, 42);
+assertEquals(42, m.load8(-8));
+m.store8(-8, 99);
+assertEquals(99, m.load(0));
+assertEquals(99, m.load8(-8));
diff --git a/test/mjsunit/asm/int32array-outofbounds.js b/test/mjsunit/asm/int32array-outofbounds.js
new file mode 100644
index 0000000..ba7043d
--- /dev/null
+++ b/test/mjsunit/asm/int32array-outofbounds.js
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Int32Array(heap);
+  function load(i) {
+    i = i|0;
+    i = MEM32[i >> 2] | 0;
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM32[i >> 2] = v;
+  }
+  return { load: load, store: store };
+}
+
+var m = Module(this, {}, new ArrayBuffer(4));
+
+m.store(0, 0x12345678);
+for (var i = 1; i < 64; ++i) {
+  m.store(i * 4 * 32 * 1024, i);
+}
+assertEquals(0x12345678, m.load(0));
+for (var i = 1; i < 64; ++i) {
+  assertEquals(0, m.load(i * 4 * 32 * 1024));
+}
diff --git a/test/mjsunit/asm/int32array-unaligned.js b/test/mjsunit/asm/int32array-unaligned.js
new file mode 100644
index 0000000..698ec5e
--- /dev/null
+++ b/test/mjsunit/asm/int32array-unaligned.js
@@ -0,0 +1,43 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Int32Array(heap);
+  function load(i) {
+    i = i|0;
+    i = MEM32[i >> 2] | 0;
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM32[i >> 2] = v;
+  }
+  return { load: load, store: store };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1024));
+
+m.store(0, 0x12345678);
+m.store(4, -1);
+m.store(8, -1);
+for (var i = 0; i < 4; ++i) {
+  assertEquals(0x12345678, m.load(i));
+}
+for (var i = 4; i < 12; ++i) {
+  assertEquals(-1, m.load(i));
+}
+for (var j = 4; j < 8; ++j) {
+  m.store(j, 0x11223344);
+  for (var i = 0; i < 4; ++i) {
+    assertEquals(0x12345678, m.load(i));
+  }
+  for (var i = 4; i < 8; ++i) {
+    assertEquals(0x11223344, m.load(i));
+  }
+  for (var i = 8; i < 12; ++i) {
+    assertEquals(-1, m.load(i));
+  }
+}
diff --git a/test/mjsunit/asm/int32div.js b/test/mjsunit/asm/int32div.js
new file mode 100644
index 0000000..f5d2433
--- /dev/null
+++ b/test/mjsunit/asm/int32div.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+function Int32Div(divisor) {
+  var name = "div_";
+  if (divisor < 0) {
+    name += "minus_";
+  }
+  name += Math.abs(divisor);
+  var m = eval("function Module(stdlib, foreign, heap) {\n"
+      + " \"use asm\";\n"
+      + " function " + name + "(dividend) {\n"
+      + "  return ((dividend | 0) / " + divisor + ") | 0;\n"
+      + " }\n"
+      + " return { f: " + name + "}\n"
+      + "}; Module");
+  return m(stdlib, foreign, heap).f;
+}
+
+var divisors = [-2147483648, -32 * 1024, -1000, -16, -7, -2, -1, 0,
+                1, 3, 4, 10, 64, 100, 1024, 2147483647];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  var div = Int32Div(divisor);
+  for (var dividend = -2147483648; dividend < 2147483648; dividend += 3999773) {
+    assertEquals((dividend / divisor) | 0, div(dividend));
+  }
+}
diff --git a/test/mjsunit/asm/int32mod-constant.js b/test/mjsunit/asm/int32mod-constant.js
new file mode 100644
index 0000000..fdbdc5d
--- /dev/null
+++ b/test/mjsunit/asm/int32mod-constant.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+function Int32Mod(divisor) {
+  var name = "mod_";
+  if (divisor < 0) {
+    name += "minus_";
+  }
+  name += Math.abs(divisor);
+  var m = eval("function Module(stdlib, foreign, heap) {\n"
+      + " \"use asm\";\n"
+      + " function " + name + "(dividend) {\n"
+      + "  return ((dividend | 0) % " + divisor + ") | 0;\n"
+      + " }\n"
+      + " return { f: " + name + "}\n"
+      + "}; Module");
+  return m(stdlib, foreign, heap).f;
+}
+
+var divisors = [-2147483648, -32 * 1024, -1000, -16, -7, -2, -1, 0,
+                1, 3, 4, 10, 64, 100, 1024, 2147483647];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  var mod = Int32Mod(divisor);
+  for (var dividend = -2147483648; dividend < 2147483648; dividend += 3999773) {
+    assertEquals((dividend % divisor) | 0, mod(dividend));
+  }
+}
diff --git a/test/mjsunit/asm/int32mod.js b/test/mjsunit/asm/int32mod.js
new file mode 100644
index 0000000..22fa813
--- /dev/null
+++ b/test/mjsunit/asm/int32mod.js
@@ -0,0 +1,26 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+var mod = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function mod(dividend, divisor) {
+    dividend = dividend|0;
+    divisor = divisor|0;
+    return (dividend % divisor) | 0;
+  }
+  return { mod: mod };
+})(stdlib, foreign, heap).mod;
+
+var divisors = [-2147483648, -32 * 1024, -1000, -16, -7, -2, -1, 0,
+                1, 3, 4, 10, 64, 100, 1024, 2147483647];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  for (var dividend = -2147483648; dividend < 2147483648; dividend += 3999773) {
+    assertEquals((dividend % divisor) | 0, mod(dividend, divisor));
+  }
+}
diff --git a/test/mjsunit/asm/int8array-negative-offset.js b/test/mjsunit/asm/int8array-negative-offset.js
new file mode 100644
index 0000000..47dbc1b
--- /dev/null
+++ b/test/mjsunit/asm/int8array-negative-offset.js
@@ -0,0 +1,42 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+
+var m = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM8 = new stdlib.Int8Array(heap);
+  function load(i) {
+    i = i|0;
+    i = MEM8[i >> 0]|0;
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM8[i >> 0] = v;
+  }
+  function load8(i) {
+    i = i|0;
+    i = MEM8[i + 8 >> 0]|0;
+    return i;
+  }
+  function store8(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM8[i + 8 >> 0] = v;
+  }
+  return { load: load, store: store, load8: load8, store8: store8 };
+})(stdlib, foreign, buffer);
+
+assertEquals(0, m.load(-8));
+assertEquals(0, m.load8(-16));
+m.store(0, 42);
+assertEquals(42, m.load8(-8));
+m.store8(-8, 99);
+assertEquals(99, m.load(0));
+assertEquals(99, m.load8(-8));
diff --git a/test/mjsunit/asm/math-abs.js b/test/mjsunit/asm/math-abs.js
new file mode 100644
index 0000000..6387749
--- /dev/null
+++ b/test/mjsunit/asm/math-abs.js
@@ -0,0 +1,84 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib) {
+  "use asm";
+
+  var abs = stdlib.Math.abs;
+
+  // f: double -> double
+  function f(a) {
+    a = +a;
+    return +abs(a);
+  }
+
+  // g: unsigned -> double
+  function g(a) {
+    a = a>>>0;
+    return +abs(a);
+  }
+
+  // h: signed -> double
+  function h(a) {
+    a = a|0;
+    return +abs(a);
+  }
+
+  return { f: f, g: g, h: h };
+}
+
+var m = Module({ Math: Math });
+var f = m.f;
+var g = m.g;
+var h = m.h;
+
+assertTrue(isNaN(f(NaN)));
+assertTrue(isNaN(f(undefined)));
+assertTrue(isNaN(f(function() {})));
+
+assertEquals("Infinity", String(1/f(0)));
+assertEquals("Infinity", String(1/f(-0)));
+assertEquals("Infinity", String(f(Infinity)));
+assertEquals("Infinity", String(f(-Infinity)));
+
+assertEquals(0,   f(0));
+assertEquals(0.1, f(0.1));
+assertEquals(0.5, f(0.5));
+assertEquals(0.1, f(-0.1));
+assertEquals(0.5, f(-0.5));
+assertEquals(1,   f(1));
+assertEquals(1.1, f(1.1));
+assertEquals(1.5, f(1.5));
+assertEquals(1,   f(-1));
+assertEquals(1.1, f(-1.1));
+assertEquals(1.5, f(-1.5));
+
+assertEquals(0,          g(0));
+assertEquals(0,          g(0.1));
+assertEquals(0,          g(0.5));
+assertEquals(0,          g(-0.1));
+assertEquals(0,          g(-0.5));
+assertEquals(1,          g(1));
+assertEquals(1,          g(1.1));
+assertEquals(1,          g(1.5));
+assertEquals(4294967295, g(-1));
+assertEquals(4294967295, g(-1.1));
+assertEquals(4294967295, g(-1.5));
+
+assertEquals(0, h(0));
+assertEquals(0, h(0.1));
+assertEquals(0, h(0.5));
+assertEquals(0, h(-0.1));
+assertEquals(0, h(-0.5));
+assertEquals(1, h(1));
+assertEquals(1, h(1.1));
+assertEquals(1, h(1.5));
+assertEquals(1, h(-1));
+assertEquals(1, h(-1.1));
+assertEquals(1, h(-1.5));
+
+assertEquals(Number.MIN_VALUE, f(Number.MIN_VALUE));
+assertEquals(Number.MIN_VALUE, f(-Number.MIN_VALUE));
+assertEquals(Number.MAX_VALUE, f(Number.MAX_VALUE));
+assertEquals(Number.MAX_VALUE, f(-Number.MAX_VALUE));
diff --git a/test/mjsunit/asm/math-ceil.js b/test/mjsunit/asm/math-ceil.js
new file mode 100644
index 0000000..edb9493
--- /dev/null
+++ b/test/mjsunit/asm/math-ceil.js
@@ -0,0 +1,38 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib) {
+  "use asm";
+
+  var ceil = stdlib.Math.ceil;
+
+  // f: double -> float
+  function f(a) {
+    a = +a;
+    return ceil(a);
+  }
+
+  return { f: f };
+}
+
+var f = Module({ Math: Math }).f;
+
+assertTrue(isNaN(f(NaN)));
+assertTrue(isNaN(f(undefined)));
+assertTrue(isNaN(f(function() {})));
+
+assertEquals(0,                   f(0));
+assertEquals(+0,                  f(+0));
+assertEquals(-0,                  f(-0));
+assertEquals(1,                   f(0.49999));
+assertEquals(1,                   f(0.6));
+assertEquals(1,                   f(0.5));
+assertEquals(-0,                  f(-0.1));
+assertEquals(-0,                  f(-0.5));
+assertEquals(-0,                  f(-0.6));
+assertEquals(-1,                  f(-1.6));
+assertEquals(-0,                  f(-0.50001));
+
+assertEquals("Infinity", String(f(Infinity)));
+assertEquals("-Infinity", String(f(-Infinity)));
diff --git a/test/mjsunit/asm/math-floor.js b/test/mjsunit/asm/math-floor.js
new file mode 100644
index 0000000..e8c3f34
--- /dev/null
+++ b/test/mjsunit/asm/math-floor.js
@@ -0,0 +1,38 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib) {
+  "use asm";
+
+  var floor = stdlib.Math.floor;
+
+  // f: double -> float
+  function f(a) {
+    a = +a;
+    return floor(a);
+  }
+
+  return { f: f };
+}
+
+var f = Module({ Math: Math }).f;
+
+assertTrue(isNaN(f(NaN)));
+assertTrue(isNaN(f(undefined)));
+assertTrue(isNaN(f(function() {})));
+
+assertEquals(0,                   f(0));
+assertEquals(+0,                  f(+0));
+assertEquals(-0,                  f(-0));
+assertEquals(0,                   f(0.49999));
+assertEquals(+0,                  f(0.6));
+assertEquals(+0,                  f(0.5));
+assertEquals(-1,                  f(-0.1));
+assertEquals(-1,                  f(-0.5));
+assertEquals(-1,                  f(-0.6));
+assertEquals(-2,                  f(-1.6));
+assertEquals(-1,                  f(-0.50001));
+
+assertEquals("Infinity", String(f(Infinity)));
+assertEquals("-Infinity", String(f(-Infinity)));
diff --git a/test/mjsunit/asm/math-fround.js b/test/mjsunit/asm/math-fround.js
new file mode 100644
index 0000000..b1d37e9
--- /dev/null
+++ b/test/mjsunit/asm/math-fround.js
@@ -0,0 +1,38 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib) {
+  "use asm";
+
+  var fround = stdlib.Math.fround;
+
+  // f: double -> float
+  function f(a) {
+    a = +a;
+    return fround(a);
+  }
+
+  return { f: f };
+}
+
+var f = Module({ Math: Math }).f;
+
+assertTrue(isNaN(f(NaN)));
+assertTrue(isNaN(f(undefined)));
+assertTrue(isNaN(f(function() {})));
+
+assertEquals("Infinity", String(1/f(0)));
+assertEquals("-Infinity", String(1/f(-0)));
+assertEquals("Infinity", String(f(Infinity)));
+assertEquals("-Infinity", String(f(-Infinity)));
+assertEquals("Infinity", String(f(1E200)));
+assertEquals("-Infinity", String(f(-1E200)));
+assertEquals("Infinity", String(1/f(1E-300)));
+assertEquals("-Infinity", String(1/f(-1E-300)));
+
+assertEquals(0,                  f(0));
+assertEquals(1,                  f(1));
+assertEquals(1.5,                f(1.5));
+assertEquals(1.3370000123977661, f(1.337));
+assertEquals(-4.300000190734863, f(-4.3));
diff --git a/test/mjsunit/asm/sign-extend.js b/test/mjsunit/asm/sign-extend.js
new file mode 100644
index 0000000..62d8d34
--- /dev/null
+++ b/test/mjsunit/asm/sign-extend.js
@@ -0,0 +1,45 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+
+var sext8 = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function sext8(i) {
+    i = i|0;
+    i = i << 24 >> 24;
+    return i|0;
+  }
+  return { sext8: sext8 };
+})(stdlib, foreign, buffer).sext8;
+
+assertEquals(-128, sext8(128));
+assertEquals(-1, sext8(-1));
+assertEquals(-1, sext8(255));
+assertEquals(0, sext8(0));
+assertEquals(0, sext8(256));
+assertEquals(42, sext8(42));
+assertEquals(127, sext8(127));
+
+
+var sext16 = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function sext16(i) {
+    i = i|0;
+    i = i << 16 >> 16;
+    return i|0;
+  }
+  return { sext16: sext16 };
+})(stdlib, foreign, buffer).sext16;
+
+assertEquals(-32768, sext16(32768));
+assertEquals(-1, sext16(-1));
+assertEquals(-1, sext16(65535));
+assertEquals(0, sext16(0));
+assertEquals(0, sext16(65536));
+assertEquals(128, sext16(128));
+assertEquals(32767, sext16(32767));
diff --git a/test/mjsunit/asm/uint32-less-than-shift.js b/test/mjsunit/asm/uint32-less-than-shift.js
new file mode 100644
index 0000000..7384e21
--- /dev/null
+++ b/test/mjsunit/asm/uint32-less-than-shift.js
@@ -0,0 +1,61 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  'use asm';
+
+  function foo1(i1) {
+    i1 = i1 | 0;
+    var i10 = i1 >> 5;
+    if (i10 >>> 0 < 5) {
+      return 1;
+    } else {
+      return 0;
+    }
+    return 0;
+  }
+
+  function foo2(i1) {
+    i1 = i1 | 0;
+    var i10 = i1 / 32 | 0;
+    if (i10 >>> 0 < 5) {
+      return 1;
+    } else {
+      return 0;
+    }
+    return 0;
+  }
+
+  function foo3(i1) {
+    i1 = i1 | 0;
+    var i10 = (i1 + 32 | 0) / 32 | 0;
+    if (i10 >>> 0 < 5) {
+      return 1;
+    } else {
+      return 0;
+    }
+    return 0;
+  }
+  return {foo1: foo1, foo2: foo2, foo3: foo3};
+}
+
+var m = Module(this, {}, undefined);
+
+for (var i = 0; i < 4 * 32; i++) {
+  assertEquals(1, m.foo1(i));
+  assertEquals(1, m.foo2(i));
+  assertEquals(1, m.foo3(i));
+}
+
+for (var i = 4 * 32; i < 5 * 32; i++) {
+  assertEquals(1, m.foo1(i));
+  assertEquals(1, m.foo2(i));
+  assertEquals(0, m.foo3(i));
+}
+
+for (var i = 5 * 32; i < 10 * 32; i++) {
+  assertEquals(0, m.foo1(i));
+  assertEquals(0, m.foo2(i));
+  assertEquals(0, m.foo3(i));
+}
diff --git a/test/mjsunit/asm/uint32div.js b/test/mjsunit/asm/uint32div.js
new file mode 100644
index 0000000..dcbb73b
--- /dev/null
+++ b/test/mjsunit/asm/uint32div.js
@@ -0,0 +1,45 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+function Uint32Div(divisor) {
+  var name = "div_";
+  name += divisor;
+  var m = eval("function Module(stdlib, foreign, heap) {\n"
+      + " \"use asm\";\n"
+      + " function " + name + "(dividend) {\n"
+      + "  return ((dividend >>> 0) / " + divisor + ") >>> 0;\n"
+      + " }\n"
+      + " return { f: " + name + "}\n"
+      + "}; Module");
+  return m(stdlib, foreign, heap).f;
+}
+
+var divisors = [0, 1, 3, 4, 10, 42, 64, 100, 1024, 2147483647, 4294967295];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  var div = Uint32Div(divisor);
+  for (var dividend = 0; dividend < 4294967296; dividend += 3999773) {
+    assertEquals((dividend / divisor) >>> 0, div(dividend));
+  }
+}
+
+var div = (function(stdlib, foreign, heap) {
+  "use asm";
+  function div(dividend, divisor) {
+    return (dividend >>> 0) / (divisor >>> 0) | 0;
+  }
+  return {div: div};
+})(stdlib, foreign, heap).div;
+
+for (var i in divisors) {
+  var divisor =  divisors[i];
+  for (var dividend = 0; dividend < 4294967296; dividend += 3999773) {
+    assertEquals((dividend >>> 0) / (divisor >>> 0) | 0,
+                 div(dividend, divisor));
+  }
+}
diff --git a/test/mjsunit/asm/uint32mod-constant.js b/test/mjsunit/asm/uint32mod-constant.js
new file mode 100644
index 0000000..4ba94da
--- /dev/null
+++ b/test/mjsunit/asm/uint32mod-constant.js
@@ -0,0 +1,29 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+function Uint32Mod(divisor) {
+  var name = "mod_";
+  name += divisor;
+  var m = eval("function Module(stdlib, foreign, heap) {\n"
+      + " \"use asm\";\n"
+      + " function " + name + "(dividend) {\n"
+      + "  return ((dividend >>> 0) % " + divisor + ") >>> 0;\n"
+      + " }\n"
+      + " return { f: " + name + "}\n"
+      + "}; Module");
+  return m(stdlib, foreign, heap).f;
+}
+
+var divisors = [0, 1, 3, 4, 10, 42, 64, 100, 1024, 2147483647, 4294967295];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  var mod = Uint32Mod(divisor);
+  for (var dividend = 0; dividend < 4294967296; dividend += 3999773) {
+    assertEquals((dividend % divisor) >>> 0, mod(dividend));
+  }
+}
diff --git a/test/mjsunit/asm/uint32mod.js b/test/mjsunit/asm/uint32mod.js
new file mode 100644
index 0000000..fa40507
--- /dev/null
+++ b/test/mjsunit/asm/uint32mod.js
@@ -0,0 +1,25 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+var mod = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function mod(dividend, divisor) {
+    dividend = dividend >>> 0;
+    divisor = divisor >>> 0;
+    return (dividend % divisor) >>> 0;
+  }
+  return { mod: mod };
+})(stdlib, foreign, heap).mod;
+
+var divisors = [0, 1, 3, 4, 10, 42, 64, 100, 1024, 2147483647, 4294967295];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  for (var dividend = 0; dividend < 4294967296; dividend += 3999773) {
+    assertEquals((dividend % divisor) >>> 0, mod(dividend, divisor));
+  }
+}
diff --git a/test/mjsunit/asm/uint8array-outofbounds.js b/test/mjsunit/asm/uint8array-outofbounds.js
new file mode 100644
index 0000000..179efa4
--- /dev/null
+++ b/test/mjsunit/asm/uint8array-outofbounds.js
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM8 = new stdlib.Uint8Array(heap);
+  function load(i) {
+    i = i|0;
+    i = MEM8[i] | 0;
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM8[i] = v;
+  }
+  return { load: load, store: store };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1));
+
+m.store(0, 255);
+for (var i = 1; i < 64; ++i) {
+  m.store(i * 1 * 32 * 1024, i);
+}
+assertEquals(255, m.load(0));
+for (var i = 1; i < 64; ++i) {
+  assertEquals(0, m.load(i * 1 * 32 * 1024));
+}
diff --git a/test/mjsunit/asm/word32and.js b/test/mjsunit/asm/word32and.js
new file mode 100644
index 0000000..6c41f88
--- /dev/null
+++ b/test/mjsunit/asm/word32and.js
@@ -0,0 +1,29 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+function Word32And(rhs) {
+  var name = "and_0x" + Number(rhs).toString(16);
+  var m = eval("function Module(stdlib, foreign, heap) {\n"
+      + " \"use asm\";\n"
+      + " function " + name + "(lhs) {\n"
+      + "  return (lhs | 0) & 0x" + Number(rhs).toString(16) + ";\n"
+      + " }\n"
+      + " return { f: " + name + "}\n"
+      + "}; Module");
+  return m(stdlib, foreign, heap).f;
+}
+
+var masks = [0xffffffff, 0xf0f0f0f0, 0x80ffffff, 0x07f77f0f, 0xdeadbeef,
+             0x0fffff00, 0x0ff0, 0xff, 0x00];
+for (var i in masks) {
+  var rhs = masks[i];
+  var and = Word32And(rhs);
+  for (var lhs = -2147483648; lhs < 2147483648; lhs += 3999773) {
+    assertEquals(lhs & rhs, and(lhs));
+  }
+}
diff --git a/test/mjsunit/asm/word32ror.js b/test/mjsunit/asm/word32ror.js
new file mode 100644
index 0000000..9535bde
--- /dev/null
+++ b/test/mjsunit/asm/word32ror.js
@@ -0,0 +1,37 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+var rol = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function rol(x, y) {
+    x = x | 0;
+    y = y | 0;
+    return (x << y) | (x >>> (32 - y));
+  }
+  return { rol: rol };
+})(stdlib, foreign, heap).rol;
+
+assertEquals(10, rol(10, 0));
+assertEquals(2, rol(1, 1));
+assertEquals(0x40000000, rol(1, 30));
+assertEquals(-0x80000000, rol(1, 31));
+
+var ror = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function ror(x, y) {
+    x = x | 0;
+    y = y | 0;
+    return (x << (32 - y)) | (x >>> y);
+  }
+  return { ror: ror };
+})(stdlib, foreign, heap).ror;
+
+assertEquals(10, ror(10, 0));
+assertEquals(-0x80000000, ror(1, 1));
+assertEquals(0x40000000, ror(1, 2));
+assertEquals(2, ror(1, 31));
diff --git a/test/mjsunit/asm/zero-extend.js b/test/mjsunit/asm/zero-extend.js
new file mode 100644
index 0000000..a1f9da6
--- /dev/null
+++ b/test/mjsunit/asm/zero-extend.js
@@ -0,0 +1,37 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+
+var zext8 = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function zext8(i) {
+    i = i|0;
+    return i & 0xff;
+  }
+  return { zext8: zext8 };
+})(stdlib, foreign, buffer).zext8;
+
+assertEquals(0, zext8(0));
+assertEquals(0, zext8(0x100));
+assertEquals(0xff, zext8(-1));
+assertEquals(0xff, zext8(0xff));
+
+
+var zext16 = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function zext16(i) {
+    i = i|0;
+    return i & 0xffff;
+  }
+  return { zext16: zext16 };
+})(stdlib, foreign, buffer).zext16;
+
+assertEquals(0, zext16(0));
+assertEquals(0, zext16(0x10000));
+assertEquals(0xffff, zext16(-1));
+assertEquals(0xffff, zext16(0xffff));
diff --git a/test/mjsunit/big-array-literal.js b/test/mjsunit/big-array-literal.js
index 13f91f8..401807f 100644
--- a/test/mjsunit/big-array-literal.js
+++ b/test/mjsunit/big-array-literal.js
@@ -27,6 +27,7 @@
 
 // On MacOS X 10.7.5, this test needs a stack size of at least 788 kBytes.
 // Flags: --stack-size=800
+// Flags: --turbo-deoptimization
 
 // Test that we can make large object literals that work.
 // Also test that we can attempt to make even larger object literals without
diff --git a/test/mjsunit/boolean.js b/test/mjsunit/boolean.js
index d955855..9b9edd2 100644
--- a/test/mjsunit/boolean.js
+++ b/test/mjsunit/boolean.js
@@ -72,3 +72,10 @@
 assertEquals('foo', o.p || (o.p == 0));
 assertEquals('foo', o.p || (o.p == null));
 assertEquals('foo', o.p || (o.p == o.p));
+
+// JSToBoolean(x:string)
+function f(x) { return !!("" + x); }
+assertEquals(false, f(""));
+assertEquals(true, f("narf"));
+assertEquals(true, f(12345678));
+assertEquals(true, f(undefined));
diff --git a/test/mjsunit/bugs/bug-2615.js b/test/mjsunit/bugs/bug-2615.js
deleted file mode 100644
index 51aeaf4..0000000
--- a/test/mjsunit/bugs/bug-2615.js
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-var a = [];
-a[0xfffffffe] = 10;
-assertThrows("a.unshift(1);", RangeError);
-assertEquals(0xffffffff, a.length);
-assertEquals(10, a[0xffffffff]);
-assertEquals(undefined, a[0xfffffffe]);
-
-a = [1,2,3];
-a[0xfffffffe] = 10;
-assertThrows("a.splice(1,1,7,7,7,7,7);", RangeError);
-assertEquals([1,7,7,7,7,7,3], a.slice(0, 7));
-assertEquals(0xffffffff, a.length);
-assertEquals(10, a[0xfffffffe + 5 - 1]);
-
-a = [1];
-Object.defineProperty(a, "1", {writable:false, configurable:false, value: 100});
-assertThrows("a.unshift(4);", TypeError);
-assertEquals([1, 100, 100], a);
-var desc = Object.getOwnPropertyDescriptor(a, "1");
-assertEquals(false, desc.writable);
-assertEquals(false, desc.configurable);
-
-a = [1];
-var g = function() { return 100; };
-Object.defineProperty(a, "1", {get:g});
-assertThrows("a.unshift(0);", TypeError);
-assertEquals([1, 100, 100], a);
-desc = Object.getOwnPropertyDescriptor(a, "1");
-assertEquals(false, desc.configurable);
-assertEquals(g, desc.get);
-
-a = [1];
-var c = 0;
-var s = function(v) { c += 1; };
-Object.defineProperty(a, "1", {set:s});
-a.unshift(10);
-assertEquals([10, undefined, undefined], a);
-assertEquals(1, c);
-desc = Object.getOwnPropertyDescriptor(a, "1");
-assertEquals(false, desc.configurable);
-assertEquals(s, desc.set);
-
-a = [1];
-Object.defineProperty(a, "1", {configurable:false, value:10});
-assertThrows("a.splice(1,1);", TypeError);
-assertEquals([1, 10], a);
-desc = Object.getOwnPropertyDescriptor(a, "1");
-assertEquals(false, desc.configurable);
-
-a = [0,1,2,3,4,5,6];
-Object.defineProperty(a, "3", {configurable:false, writable:false, value:3});
-assertThrows("a.splice(1,4);", TypeError);
-assertEquals([0,5,6,3,,,,,], a);
-desc = Object.getOwnPropertyDescriptor(a, "3");
-assertEquals(false, desc.configurable);
-assertEquals(false, desc.writable);
-
-a = [0,1,2,3,4,5,6];
-Object.defineProperty(a, "5", {configurable:false, value:5});
-assertThrows("a.splice(1,4);", TypeError);
-assertEquals([0,5,6,3,4,5,,,], a);
-desc = Object.getOwnPropertyDescriptor(a, "5");
-assertEquals(false, desc.configurable);
-
-a = [1,2,3,,5];
-Object.defineProperty(a, "1", {configurable:false, writable:true, value:2});
-assertEquals(1, a.shift());
-assertEquals([2,3,,5], a);
-desc = Object.getOwnPropertyDescriptor(a, "1");
-assertEquals(false, desc.configurable);
-assertEquals(true, desc.writable);
-assertThrows("a.shift();", TypeError);
-assertEquals([3,3,,5], a);
-desc = Object.getOwnPropertyDescriptor(a, "1");
-assertEquals(false, desc.configurable);
-assertEquals(true, desc.writable);
-
-a = [1,2,3];
-Object.defineProperty(a, "2", {configurable:false, value:3});
-assertThrows("a.pop();", TypeError);
-assertEquals([1,2,3], a);
-desc = Object.getOwnPropertyDescriptor(a, "2");
-assertEquals(false, desc.configurable);
-
-a = [1,2,,,5];
-Object.defineProperty(a, "4", {writable:true, configurable:false, value:5});
-assertThrows("a.sort();", TypeError);
-assertEquals([1,2,5,,5], a);
-desc = Object.getOwnPropertyDescriptor(a, "2");
-assertEquals(true, desc.configurable);
-desc = Object.getOwnPropertyDescriptor(a, "4");
-assertEquals(false, desc.configurable);
-
-a = [1,2,3,,5,6];
-Object.defineProperty(a, "4", {value:5, writable:false});
-assertThrows("a.sort();", TypeError);
-assertEquals([1,2,3,5,5,6], a);
-desc = Object.getOwnPropertyDescriptor(a, "4");
-assertEquals(false, desc.writable);
diff --git a/test/mjsunit/compiler/deopt-inlined-from-call.js b/test/mjsunit/compiler/deopt-inlined-from-call.js
new file mode 100644
index 0000000..24d7354
--- /dev/null
+++ b/test/mjsunit/compiler/deopt-inlined-from-call.js
@@ -0,0 +1,154 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//   * Redistributions of source code must retain the above copyright
+//   notice, this list of conditions and the following disclaimer.
+//   * Redistributions in binary form must reproduce the above
+//   copyright notice, this list of conditions and the following
+//   disclaimer in the documentation and/or other materials provided
+//   with the distribution.
+//   * Neither the name of Google Inc. nor the names of its
+//   contributors may be used to endorse or promote products derived
+//   from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --noalways-opt
+
+var global = this;
+
+Array.prototype.f = function() {
+  return 0;
+};
+
+(function() {
+  var called = 0;
+
+  function g(x, y, called) {
+    return called + 1;
+  }
+
+  function f(deopt, called) {
+    return g([].f.call({}), deopt + 1, called);
+  }
+
+  called = f(0, called);
+  called = f(0, called);
+  %OptimizeFunctionOnNextCall(f);
+  called = f(0, called);
+  assertOptimized(f);
+  called = f({}, called);
+  assertUnoptimized(f);
+  assertEquals(4, called);
+})();
+
+(function() {
+  // The array built-ins are only inlined if the receiver is a
+  // HConstant, this seems to require a *unique* global identifier
+  // each time.
+  global.a1 = [1,2,3,4];
+  var obj = {value: 3};
+
+  function f(b) {
+    return [].pop.call(a1) + b.value;
+  }
+
+  assertEquals(7, f(obj));
+  assertEquals(6, f(obj));
+  %OptimizeFunctionOnNextCall(f);
+  assertEquals(5, f(obj));
+  assertOptimized(f);
+  assertEquals(4, f({d: 0, value: 3}));
+  assertUnoptimized(f);
+  assertEquals(0, a1.length);
+})();
+
+
+(function() {
+  global.a2 = [1,2,3,4];
+  var obj = {value: 3};
+
+  function f(b) {
+    return [].shift.call(a2) + b.value;
+  }
+
+  assertEquals(4, f(obj));
+  assertEquals(5, f(obj));
+  %OptimizeFunctionOnNextCall(f);
+  assertEquals(6, f(obj));
+  assertOptimized(f);
+  assertEquals(7, f({d: 0, value: 3}));
+  assertUnoptimized(f);
+  assertEquals(0, a2.length);
+})();
+
+(function() {
+  global.a3 = [1,2,3,4];
+  var obj = {value: 3};
+
+  function f(b) {
+    return [].push.call(a3, b.value);
+  }
+
+  assertEquals(5, f(obj));
+  assertEquals(6, f(obj));
+  %OptimizeFunctionOnNextCall(f);
+  assertEquals(7, f(obj));
+  assertOptimized(f);
+  assertEquals(8, f({d: 0, value: 3}));
+  assertUnoptimized(f);
+  assertEquals(8, a3.length);
+  assertEquals(3, a3[7]);
+})();
+
+(function() {
+  global.a4 = [1,2,3,4];
+  var obj = {value: 3};
+
+  function f(b) {
+    return [].indexOf.call(a4, b.value);
+  }
+
+  f(obj);
+  f(obj);
+  %OptimizeFunctionOnNextCall(f);
+  var index1 = f(obj);
+  assertOptimized(f);
+  var index2 = f({d: 0, value: 3});
+  assertUnoptimized(f);
+
+  assertEquals(2, index1);
+  assertEquals(index1, index2);
+})();
+
+(function() {
+  global.a5 = [1,2,3,4];
+  var obj = {value: 3};
+
+  function f(b) {
+    return [].lastIndexOf.call(a5, b.value);
+  }
+
+  f(obj);
+  f(obj);
+  %OptimizeFunctionOnNextCall(f);
+  var index1 = f(obj);
+  assertOptimized(f);
+  var index2 = f({d: 0, value: 3});
+  assertUnoptimized(f);
+
+  assertEquals(2, index1);
+  assertEquals(index1, index2);
+})();
diff --git a/test/mjsunit/compiler/division-by-constant.js b/test/mjsunit/compiler/division-by-constant.js
index 0778e95..d3f3ac3 100644
--- a/test/mjsunit/compiler/division-by-constant.js
+++ b/test/mjsunit/compiler/division-by-constant.js
@@ -101,6 +101,7 @@
 
 // -----------------------------------------------------------------------------
 
+
 function TestDivisionLike(ref, construct, values, divisor) {
   // Define the function to test.
   var OptFun = new Function("dividend", construct(divisor));
@@ -111,12 +112,14 @@
   %OptimizeFunctionOnNextCall(OptFun);
   OptFun(13);
 
-  // Check results.
-  values.forEach(function(dividend) {
+function dude(dividend) {
     // Avoid deopt caused by overflow, we do not want to test this here.
     if (dividend === -2147483648 && divisor === -1) return;
     assertEquals(ref(dividend, divisor), OptFun(dividend));
-  });
+  }
+
+  // Check results.
+  values.forEach(dude);
 }
 
 function Test(ref, construct) {
diff --git a/test/mjsunit/compiler/inlined-call-mapcheck.js b/test/mjsunit/compiler/inlined-call-mapcheck.js
new file mode 100644
index 0000000..84ec1d2
--- /dev/null
+++ b/test/mjsunit/compiler/inlined-call-mapcheck.js
@@ -0,0 +1,43 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//   * Redistributions of source code must retain the above copyright
+//     notice, this list of conditions and the following disclaimer.
+//   * Redistributions in binary form must reproduce the above
+//     copyright notice, this list of conditions and the following
+//     disclaimer in the documentation and/or other materials provided
+//     with the distribution.
+//   * Neither the name of Google Inc. nor the names of its
+//     contributors may be used to endorse or promote products derived
+//     from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --noalways-opt
+
+(function() {
+    function f(x) {
+        for (i = 0; i < 1; i++) {
+            x.call(this);
+        }
+    }
+
+    function g() {}
+
+    f(g);
+    f(g);
+    %OptimizeFunctionOnNextCall(f);
+    assertThrows(function() { f('whatever') }, TypeError);
+})();
diff --git a/test/mjsunit/compiler/inlined-call.js b/test/mjsunit/compiler/inlined-call.js
new file mode 100644
index 0000000..dfa1675
--- /dev/null
+++ b/test/mjsunit/compiler/inlined-call.js
@@ -0,0 +1,190 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//   * Redistributions of source code must retain the above copyright
+//     notice, this list of conditions and the following disclaimer.
+//   * Redistributions in binary form must reproduce the above
+//     copyright notice, this list of conditions and the following
+//     disclaimer in the documentation and/or other materials provided
+//     with the distribution.
+//   * Neither the name of Google Inc. nor the names of its
+//     contributors may be used to endorse or promote products derived
+//     from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --noalways-opt
+
+var global = this;
+
+// For the HConstant
+Array.prototype.fun = function() {
+  funRecv = this;
+  called++;
+  assertEquals(0, arguments.length);
+};
+
+Array.prototype.funStrict = function() {
+  "use strict";
+  funStrictRecv = this;
+  called++;
+  assertEquals(0, arguments.length);
+};
+
+Array.prototype.manyArgs = function() {
+  "use strict";
+  assertEquals(5, arguments.length);
+  assertEquals(0, this);
+  assertEquals(5, arguments[4]);
+  called++;
+}
+
+Array.prototype.manyArgsSloppy = function() {
+  assertEquals(global, this);
+  assertEquals(5, arguments.length);
+  assertEquals(5, arguments[4]);
+  called++;
+}
+
+var array = [];
+for (var i = 0; i < 100; ++i) {
+  array[i] = i;
+}
+
+var copy = array.slice();
+
+function unshiftsArray(num) {
+  [].unshift.call(array, num);
+}
+
+unshiftsArray(50);
+unshiftsArray(60);
+%OptimizeFunctionOnNextCall(unshiftsArray);
+unshiftsArray(80);
+unshiftsArray(50);
+unshiftsArray(60);
+
+copy.unshift(50);
+copy.unshift(60);
+copy.unshift(80);
+copy.unshift(50);
+copy.unshift(60);
+
+assertOptimized(unshiftsArray);
+assertArrayEquals(array, copy);
+
+
+var called = 0;
+var funRecv;
+
+function callNoArgs() {
+  [].fun.call();
+}
+
+callNoArgs();
+callNoArgs();
+assertEquals(this, funRecv);
+%OptimizeFunctionOnNextCall(callNoArgs);
+callNoArgs();
+assertEquals(this, funRecv);
+assertEquals(3, called);
+assertOptimized(callNoArgs);
+
+var funStrictRecv;
+called = 0;
+
+function callStrictNoArgs() {
+  [].funStrict.call();
+}
+
+callStrictNoArgs();
+callStrictNoArgs();
+assertEquals(undefined, funStrictRecv);
+%OptimizeFunctionOnNextCall(callStrictNoArgs);
+callStrictNoArgs();
+assertEquals(undefined, funStrictRecv);
+assertEquals(3, called);
+assertOptimized(callStrictNoArgs);
+
+called = 0;
+
+
+function callManyArgs() {
+  [].manyArgs.call(0, 1, 2, 3, 4, 5);
+}
+
+callManyArgs();
+callManyArgs();
+%OptimizeFunctionOnNextCall(callManyArgs);
+callManyArgs();
+assertOptimized(callManyArgs);
+assertEquals(called, 3);
+
+called = 0;
+
+
+function callManyArgsSloppy() {
+  [].manyArgsSloppy.call(null, 1, 2, 3, 4, 5);
+}
+
+callManyArgsSloppy();
+callManyArgsSloppy();
+%OptimizeFunctionOnNextCall(callManyArgsSloppy);
+callManyArgsSloppy();
+assertOptimized(callManyArgsSloppy);
+assertEquals(called, 3);
+
+var str = "hello";
+var code = str.charCodeAt(3);
+called = 0;
+function callBuiltinIndirectly() {
+  called++;
+  return "".charCodeAt.call(str, 3);
+}
+
+callBuiltinIndirectly();
+callBuiltinIndirectly();
+%OptimizeFunctionOnNextCall(callBuiltinIndirectly);
+assertEquals(code, callBuiltinIndirectly());
+assertOptimized(callBuiltinIndirectly);
+assertEquals(3, called);
+
+this.array = [1,2,3,4,5,6,7,8,9];
+var copy = this.array.slice();
+called = 0;
+
+function callInlineableBuiltinIndirectlyWhileInlined() {
+    called++;
+    return [].push.apply(array, arguments);
+}
+
+function callInlined(num) {
+  return callInlineableBuiltinIndirectlyWhileInlined(num);
+}
+
+callInlineableBuiltinIndirectlyWhileInlined(1);
+callInlineableBuiltinIndirectlyWhileInlined(2);
+%OptimizeFunctionOnNextCall(callInlineableBuiltinIndirectlyWhileInlined);
+callInlineableBuiltinIndirectlyWhileInlined(3);
+assertOptimized(callInlineableBuiltinIndirectlyWhileInlined);
+
+callInlined(1);
+callInlined(2);
+%OptimizeFunctionOnNextCall(callInlined);
+callInlined(3);
+copy.push(1, 2, 3, 1, 2, 3);
+assertOptimized(callInlined);
+assertArrayEquals(copy, this.array);
+assertEquals(6, called);
diff --git a/test/mjsunit/compiler/literals.js b/test/mjsunit/compiler/literals.js
index 8607cd9..3bda9fc 100644
--- a/test/mjsunit/compiler/literals.js
+++ b/test/mjsunit/compiler/literals.js
@@ -38,8 +38,8 @@
 // "/" comes just before "0".
 assertThrows('"\\x1/"');
 assertThrows('"\\u111/"');
-assertEquals("\\x1/", RegExp("\\x1/").source);
-assertEquals("\\u111/", RegExp("\\u111/").source);
+assertEquals("\\x1\\/", RegExp("\\x1/").source);
+assertEquals("\\u111\\/", RegExp("\\u111/").source);
 
 // ":" comes just after "9".
 assertThrows('"\\x1:"');
diff --git a/test/mjsunit/compiler/regress-3786.js b/test/mjsunit/compiler/regress-3786.js
new file mode 100644
index 0000000..d30ac0e
--- /dev/null
+++ b/test/mjsunit/compiler/regress-3786.js
@@ -0,0 +1,12 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var foo = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  var f = stdlib.Math.cos;
+  function foo() {
+    return f(48,48,48,59,32,102,111,110,116,45,119,101,105,103,104,116,58,98,111,108,100,59,102,111,110,116,45,102,97,109,105,108,121,58,65,114,105,97,108,44,32,72,101,108,118,101,116,105,99,97,44,32,115,97,110,115,45,115,101,114,105,102,44,86,101,114,100,97,110,97,34,32,99,111,108,111,114,61,34,35,70,70,48,48,48,48,34,62,70,79,82,69,88,47,80,65,82,38,35,51,48,52,59,60,119,98,114,32,47,62,84,69,32,38,35,51,48,52,59,38,35,51,53,48,59,76,69,77,76,69,82,38,35,51,48,52,59,60,47,102,111,110,116,62,60,47,115,112,97,110,62,60,47,116,100,62,10,60,47,116,114,62,60,116,114,62,10,60,116,100,32,97,108,105,103,110,61,34,108,101,102,116,34,62,60,115,112,97,110,32,105,100,61,34,97,99,95,100,101,115,99,34,62,60,102,111,110,116,32,115,116,121,108,101,61,34,102,111,110,116,45,115,105,122,101,58,49,49,112,120,59,32,99,111,108,111,114,58,35,48,48,48,48,48,48,59,32,102,111,110,116,45,102,97,109,105,108,121,58,65,114,105,97,108,44,32,72,101,108,118,101,116,105,99,97,44,32,115,97,110,115,45,115,101,114,105,102,44,86,101,114,100,97,110,97,34,62,38,112,111,117,110,100,59,47,36,32,50,32,112,105,112,44,32,89,84,76,32,49,50,32,112,105,112,44,65,108,116,38,35,51,48,53,59,110,32,51,32,99,101,110,116,46,32,83,97,98,105,116,32,83,112,114,101,97,100,45,84,38,117,117,109,108,59,114,60,119,98,114,32,47,62,107,32,66,97,110,107,97,115,38,35,51,48,53,59,32,65,86,65,78,84,65,74,73,60,47,102,111,110,116,62,60,47,115,112,97,110,62,60,47,116,100,62,10,60,47,116,114,62,60,116,114,62,10,60,116,100,32,97,108,105,103,110,61,34,108,101,102,116,34,62,60,100,105,118,32,105,100,61,34,97,99,95,117,114,108,34,62,60,102,111,110,116,32,115,116,121,108,101,61,34,102,111,110,116,45,115,105,122,101,58,49,48,112,120,59,32,99,111,108,111,114,58,35,70,70,54,54,57,57,59,32,102,111,110,116,45,102,97114,105,97);
+  }
+  return { foo: foo };
+})(this, {}).foo();
diff --git a/test/mjsunit/compiler/regress-439743.js b/test/mjsunit/compiler/regress-439743.js
new file mode 100644
index 0000000..288e2a4
--- /dev/null
+++ b/test/mjsunit/compiler/regress-439743.js
@@ -0,0 +1,17 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function module(stdlib, foreign, heap) {
+    "use asm";
+    var MEM32 = new stdlib.Int32Array(heap);
+    function foo(i) {
+      i = i|0;
+      MEM32[0] = i;
+      return MEM32[i + 4 >> 2]|0;
+    }
+    return { foo: foo };
+}
+
+var foo = module(this, {}, new ArrayBuffer(64*1024)).foo;
+assertEquals(-4, foo(-4));
diff --git a/test/mjsunit/compiler/regress-443744.js b/test/mjsunit/compiler/regress-443744.js
new file mode 100644
index 0000000..5e7f3bc
--- /dev/null
+++ b/test/mjsunit/compiler/regress-443744.js
@@ -0,0 +1,14 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var m = (function(stdlib, foreign, heap) {
+  "use asm";
+  var MEM = new stdlib.Uint8Array(heap);
+  function f(x) {
+    x = x | 0;
+    MEM[x] = 0;
+  }
+  return {f: f};
+})(this, {}, new ArrayBuffer(1));
+m.f(-926416896 * 32 * 1024);
diff --git a/test/mjsunit/compiler/regress-444508.js b/test/mjsunit/compiler/regress-444508.js
new file mode 100644
index 0000000..e7d51ae
--- /dev/null
+++ b/test/mjsunit/compiler/regress-444508.js
@@ -0,0 +1,11 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function Module(stdlib, foreign, heap) {
+  "use asm";
+  // This is not valid asm.js, but should nevertheless work.
+  var MEM = new Uint8ClampedArray(heap);
+  function foo(i) { MEM[0] = 1; }
+  return {foo: foo};
+})(this, {}, new ArrayBuffer(64 * 1024)).foo();
diff --git a/test/mjsunit/compiler/regress-444695.js b/test/mjsunit/compiler/regress-444695.js
new file mode 100644
index 0000000..168ae25
--- /dev/null
+++ b/test/mjsunit/compiler/regress-444695.js
@@ -0,0 +1,11 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var foo = (function(stdlib, foreign, heap) {
+  "use asm";
+  var MEM = new stdlib.Uint8Array(heap);
+  function foo(x) { MEM[x | 0] *= 0; }
+  return {foo: foo};
+})(this, {}, new ArrayBuffer(1)).foo;
+foo(-926416896 * 8 * 1024);
diff --git a/test/mjsunit/compiler/regress-445267.js b/test/mjsunit/compiler/regress-445267.js
new file mode 100644
index 0000000..465168b
--- /dev/null
+++ b/test/mjsunit/compiler/regress-445267.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var foo = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM16 = new stdlib.Int16Array(heap);
+  function foo(i) {
+    i = i|0;
+    i = MEM16[i + 2147483650 >> 1]|0;
+    return i;
+  }
+  return { foo: foo };
+})(this, {}, new ArrayBuffer(64 * 1024)).foo;
+
+foo(0);
diff --git a/test/mjsunit/compiler/regress-445732.js b/test/mjsunit/compiler/regress-445732.js
new file mode 100644
index 0000000..199a29a
--- /dev/null
+++ b/test/mjsunit/compiler/regress-445732.js
@@ -0,0 +1,11 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --turbo-asm
+
+"use asm";
+
+%NeverOptimizeFunction(f);
+function f() { }
+f();
diff --git a/test/mjsunit/compiler/regress-445858.js b/test/mjsunit/compiler/regress-445858.js
new file mode 100644
index 0000000..b2214ea
--- /dev/null
+++ b/test/mjsunit/compiler/regress-445858.js
@@ -0,0 +1,15 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var foo = (function module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM = new stdlib.Int8Array(heap);
+  function foo(i) {
+    i = i|0;
+    i[0] = i;
+    return MEM[i + 1 >> 0]|0;
+  }
+  return { foo: foo };
+})(this, {}, new ArrayBuffer(64 * 1024)).foo;
+foo(-1);
diff --git a/test/mjsunit/compiler/regress-445859.js b/test/mjsunit/compiler/regress-445859.js
new file mode 100644
index 0000000..256af3e
--- /dev/null
+++ b/test/mjsunit/compiler/regress-445859.js
@@ -0,0 +1,11 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var foo = (function Module(global, env, buffer) {
+  "use asm";
+  var i8 = new global.Int8Array(buffer);
+  function foo() { i8[0] += 4294967295; }
+  return { foo: foo };
+})(this, {}, new ArrayBuffer(64 * 1024)).foo;
+foo();
diff --git a/test/mjsunit/compiler/regress-445876.js b/test/mjsunit/compiler/regress-445876.js
new file mode 100644
index 0000000..30e10e5
--- /dev/null
+++ b/test/mjsunit/compiler/regress-445876.js
@@ -0,0 +1,12 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function f(x) {
+  while (1) { s++; }
+  while (x) { s++; }
+}
+
+assertThrows(function () { f(1); });
diff --git a/test/mjsunit/compiler/regress-446156.js b/test/mjsunit/compiler/regress-446156.js
new file mode 100644
index 0000000..f3cd2dd
--- /dev/null
+++ b/test/mjsunit/compiler/regress-446156.js
@@ -0,0 +1,11 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function Module(stdlib, foreign, heap) {
+  "use asm";
+  // This is not valid asm.js, but should nevertheless work.
+  var MEM = new Uint8ClampedArray(heap);
+  function foo(  )  { MEM[0] ^=  1; }
+  return {foo: foo};
+})(this, {}, new ArrayBuffer(  ) ).foo();
diff --git a/test/mjsunit/compiler/regress-446778.js b/test/mjsunit/compiler/regress-446778.js
new file mode 100644
index 0000000..a7fa3fd
--- /dev/null
+++ b/test/mjsunit/compiler/regress-446778.js
@@ -0,0 +1,17 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module() {
+  "use asm";
+  function f() {
+   var i = (140737463189505);
+   do {
+    i = i + i | 0;
+    x = undefined + i | 0;
+   } while (!i);
+  }
+  return { f: f };
+}
+
+Module().f();
diff --git a/test/mjsunit/compiler/regress-bit-number-constant.js b/test/mjsunit/compiler/regress-bit-number-constant.js
new file mode 100644
index 0000000..d36fe30
--- /dev/null
+++ b/test/mjsunit/compiler/regress-bit-number-constant.js
@@ -0,0 +1,17 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+var foo = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function foo(i) {
+    return !(i ? 1 : false);
+  }
+  return {foo:foo};
+})(stdlib, foreign, buffer).foo;
+
+assertFalse(foo(1));
diff --git a/test/mjsunit/compiler/regress-int32array-outofbounds-nan.js b/test/mjsunit/compiler/regress-int32array-outofbounds-nan.js
new file mode 100644
index 0000000..2eba2a4
--- /dev/null
+++ b/test/mjsunit/compiler/regress-int32array-outofbounds-nan.js
@@ -0,0 +1,17 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Int32Array(heap);
+  function foo(i) {
+    i = i|0;
+    return +MEM32[i >> 2];
+  }
+  return {foo: foo};
+}
+
+var foo = Module(this, {}, new ArrayBuffer(4)).foo;
+assertEquals(NaN, foo(-4));
+assertEquals(NaN, foo(4));
diff --git a/test/mjsunit/compiler/regress-ntl-effect.js b/test/mjsunit/compiler/regress-ntl-effect.js
new file mode 100644
index 0000000..708fe32
--- /dev/null
+++ b/test/mjsunit/compiler/regress-ntl-effect.js
@@ -0,0 +1,16 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function g() {
+  throw 0;
+}
+
+function f() {
+  g();
+  while (1) {}
+}
+
+assertThrows(function () { f(); });
diff --git a/test/mjsunit/compiler/regress-register-allocator.js b/test/mjsunit/compiler/regress-register-allocator.js
new file mode 100644
index 0000000..08877ee
--- /dev/null
+++ b/test/mjsunit/compiler/regress-register-allocator.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, buffer) {
+  "use asm";
+  var HEAP32 = new stdlib.Int32Array(buffer);
+  function g(a) {
+    HEAP32[a] = 9982 * 100;
+    return a;
+  }
+  function f(i1) {
+    i1 = i1 | 0;
+    var i2 = HEAP32[i1 >> 2] | 0;
+    g(i1);
+    L2909: {
+      L2: {
+        if (0) {
+          if (0) break L2;
+          g(i2);
+          break L2909;
+        }
+      }
+      var r = (HEAP32[1] | 0) / 100 | 0;
+      g(r);
+      return r;
+    }
+  }
+  return {f: f};
+}
+
+var f = Module(this, {}, new ArrayBuffer(64 * 1024)).f;
+assertEquals(9982, f(1));
diff --git a/test/mjsunit/compiler/regress-register-allocator2.js b/test/mjsunit/compiler/regress-register-allocator2.js
new file mode 100644
index 0000000..06e0c49
--- /dev/null
+++ b/test/mjsunit/compiler/regress-register-allocator2.js
@@ -0,0 +1,17 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function f() {
+  var x = 0;
+  var y = 0;
+  x ^= undefined;
+  assertEquals(x /= 1);
+  assertEquals(NaN, y %= 1);
+  assertEquals(y = 1);
+  f();
+  y = -2;
+  assertEquals(x >>= 1);
+  assertEquals(0, ((y+(y+(y+((y^(x%5))+y)))+(y+y))>>y)+y);
+}
+try { f(); } catch (e) {}
diff --git a/test/mjsunit/compiler/regress-register-allocator3.js b/test/mjsunit/compiler/regress-register-allocator3.js
new file mode 100644
index 0000000..f412c57
--- /dev/null
+++ b/test/mjsunit/compiler/regress-register-allocator3.js
@@ -0,0 +1,46 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+function Module() {
+  "use asm";
+  function f() {
+   var $0 = 0, $25 = 0, $i$014$i = 0, $sum$013$i = 0, $v_0$01$i = 0, $v_1$02$i = 0, $v_10$011$i = 0, $v_11$012$i = 0, $v_2$03$i = 0, $v_3$04$i = 0, $v_4$05$i = 0, $v_5$06$i = 0, $v_6$07$i = 0, $v_7$08$i = 0, $v_8$09$i = 0, $v_9$010$i = 0;
+   $i$014$i = 0;
+   $sum$013$i = 0;
+   $v_0$01$i = 8;
+   $v_1$02$i = 9;
+   $v_10$011$i = 18;
+   $v_11$012$i = 19;
+   $v_2$03$i = 10;
+   $v_3$04$i = 11;
+   $v_4$05$i = 12;
+   $v_5$06$i = 13;
+   $v_6$07$i = 14;
+   $v_7$08$i = 15;
+   $v_8$09$i = 16;
+   $v_9$010$i = 17;
+   do {
+    $v_0$01$i = $v_3$04$i + $v_9$010$i + $v_0$01$i | 0;
+    $v_1$02$i = $v_4$05$i + $v_10$011$i + $v_1$02$i | 0;
+    $v_2$03$i = $v_5$06$i + $v_11$012$i + $v_2$03$i | 0;
+    $v_3$04$i = $v_3$04$i + $v_6$07$i + $v_0$01$i | 0;
+    $v_4$05$i = $v_4$05$i + $v_7$08$i + $v_1$02$i | 0;
+    $v_5$06$i = $v_5$06$i + $v_8$09$i + $v_2$03$i | 0;
+    $v_6$07$i = $v_6$07$i + $v_9$010$i + $v_3$04$i | 0;
+    $v_7$08$i = $v_7$08$i + $v_10$011$i + $v_4$05$i | 0;
+    $v_8$09$i = $v_8$09$i + $v_11$012$i + $v_5$06$i | 0;
+    $v_9$010$i = $v_0$01$i + $v_9$010$i + $v_6$07$i | 0;
+    $v_10$011$i = $v_1$02$i + $v_10$011$i + $v_7$08$i | 0;
+    $v_11$012$i = $v_2$03$i + $v_11$012$i + $v_8$09$i | 0;
+    $25 = $v_0$01$i + $v_1$02$i | 0;
+    $sum$013$i = $v_2$03$i + $sum$013$i + $v_5$06$i + $v_4$05$i + $v_8$09$i + $v_3$04$i + $25 + $v_7$08$i + $v_11$012$i + $v_6$07$i + $v_10$011$i + $v_9$010$i | 0;
+    $i$014$i = $i$014$i + 1 | 0;
+   } while (($i$014$i | 0) <= 0);
+   return $sum$013$i - ($v_5$06$i + $v_2$03$i + $v_4$05$i + $v_8$09$i + $25 + $v_3$04$i + $v_7$08$i + $v_11$012$i + $v_6$07$i + $v_10$011$i + $v_9$010$i);
+  }
+  return { f: f };
+}
+
+Module().f();
diff --git a/test/mjsunit/compiler/regress-uint8-deopt.js b/test/mjsunit/compiler/regress-uint8-deopt.js
new file mode 100644
index 0000000..ba2823f
--- /dev/null
+++ b/test/mjsunit/compiler/regress-uint8-deopt.js
@@ -0,0 +1,17 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --turbo-asm --turbo-deoptimization --allow-natives-syntax
+
+function Module(heap) {
+  "use asm";
+  var a = new Uint8Array(heap);
+  function f() {
+    var x = a[0] | 0;
+    %DeoptimizeFunction(f);
+    return x;
+  }
+  return f;
+}
+assertEquals(0, Module(new ArrayBuffer(1))());
diff --git a/test/mjsunit/compiler/shift-shr.js b/test/mjsunit/compiler/shift-shr.js
index a300b2a..52cd370 100644
--- a/test/mjsunit/compiler/shift-shr.js
+++ b/test/mjsunit/compiler/shift-shr.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Flags: --allow-natives-syntax --noopt-safe-uint32-operations
+// Flags: --allow-natives-syntax
 
 // Check the results of `left >>> right`. The result is always unsigned (and
 // therefore positive).
diff --git a/test/mjsunit/compiler/truncating-store.js b/test/mjsunit/compiler/truncating-store.js
new file mode 100644
index 0000000..9e3dd38
--- /dev/null
+++ b/test/mjsunit/compiler/truncating-store.js
@@ -0,0 +1,98 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function() {
+  var asm = (function Module(global, env, buffer) {
+    "use asm";
+
+    var i8 = new global.Int8Array(buffer);
+    var u8 = new global.Uint8Array(buffer);
+    var i16 = new global.Int16Array(buffer);
+    var u16 = new global.Uint16Array(buffer);
+    var i32 = new global.Int32Array(buffer);
+    var u32 = new global.Uint32Array(buffer);
+
+    var H = 0;
+
+    function store_i8() {
+      H = 4294967295;
+      i8[0 >> 0]= H;
+      return i8[0 >> 0];
+    }
+
+    function store_u8() {
+      H = 4294967295;
+      u8[0 >> 0]= H;
+      return u8[0 >> 0];
+    }
+
+    function store_i16() {
+      H = 4294967295;
+      i16[0 >> 0]= H;
+      return i16[0 >> 0];
+    }
+
+    function store_u16() {
+      H = 4294967295;
+      u16[0 >> 0]= H;
+      return u16[0 >> 0];
+    }
+
+    function store_i32() {
+      H = 4294967295;
+      i32[0 >> 0]= H;
+      return i32[0 >> 0];
+    }
+
+    function store_u32() {
+      H = 4294967295;
+      u32[0 >> 0]= H;
+      return u32[0 >> 0];
+    }
+
+    return { store_i8: store_i8,
+             store_u8: store_u8,
+             store_i16: store_i16,
+             store_u16: store_u16,
+             store_i32: store_i32,
+             store_u32: store_u32 };
+  })({
+    "Int8Array": Int8Array,
+    "Uint8Array": Uint8Array,
+    "Int16Array": Int16Array,
+    "Uint16Array": Uint16Array,
+    "Int32Array": Int32Array,
+    "Uint32Array": Uint32Array
+  }, {}, new ArrayBuffer(64 * 1024));
+
+  assertEquals(-1, asm.store_i8());
+  assertEquals(255, asm.store_u8());
+  assertEquals(-1, asm.store_i16());
+  assertEquals(65535, asm.store_u16());
+  assertEquals(-1, asm.store_i32());
+  assertEquals(4294967295, asm.store_u32());
+})();
+
+(function() {
+  var asm = (function Module(global, env, buffer) {
+    "use asm";
+
+    var i32 = new global.Int32Array(buffer);
+
+    var H = 0;
+
+    // This is not valid asm.js, but we should still generate correct code.
+    function store_i32_from_string() {
+      H = "3";
+      i32[0 >> 0]= H;
+      return i32[0 >> 0];
+    }
+
+    return { store_i32_from_string: store_i32_from_string };
+  })({
+    "Int32Array": Int32Array
+  }, {}, new ArrayBuffer(64 * 1024));
+
+  assertEquals(3, asm.store_i32_from_string());
+})();
diff --git a/test/mjsunit/debug-clearbreakpointgroup.js b/test/mjsunit/debug-clearbreakpointgroup.js
index 137dfec..3c03bda 100644
--- a/test/mjsunit/debug-clearbreakpointgroup.js
+++ b/test/mjsunit/debug-clearbreakpointgroup.js
@@ -36,13 +36,17 @@
 
 var base_request = '"seq":0,"type":"request","command":"clearbreakpointgroup"';
 var scriptId = null;
+var muteListener = false;
 
 function safeEval(code) {
   try {
+    muteListener = true;
     return eval('(' + code + ')');
   } catch (e) {
     assertEquals(void 0, e);
     return undefined;
+  } finally {
+    muteListener = false;
   }
 }
 
@@ -58,6 +62,7 @@
 }
 
 function listener(event, exec_state, event_data, data) {
+  if (muteListener) return;
   try {
     if (event == Debug.DebugEvent.Break) {
       // Get the debug command processor.
diff --git a/test/mjsunit/debug-compile-event.js b/test/mjsunit/debug-compile-event.js
index c38cd84..8623406 100644
--- a/test/mjsunit/debug-compile-event.js
+++ b/test/mjsunit/debug-compile-event.js
@@ -37,7 +37,7 @@
 var source_count = 0;  // Total number of scources compiled.
 var host_compilations = 0;  // Number of scources compiled through the API.
 var eval_compilations = 0;  // Number of scources compiled through eval.
-
+var mute_listener = false;
 
 function compileSource(source) {
   current_source = source;
@@ -45,8 +45,20 @@
   source_count++;
 }
 
+function safeEval(code) {
+  try {
+    mute_listener = true;
+    return eval('(' + code + ')');
+  } catch (e) {
+    assertEquals(void 0, e);
+    return undefined;
+  } finally {
+    mute_listener = false;
+  }
+}
 
 function listener(event, exec_state, event_data, data) {
+  if (mute_listener) return;
   try {
     if (event == Debug.DebugEvent.BeforeCompile ||
         event == Debug.DebugEvent.AfterCompile ||
@@ -81,7 +93,7 @@
       }
       // Check that script context is included into the event message.
       var json = event_data.toJSONProtocol();
-      var msg = eval('(' + json + ')');
+      var msg = safeEval(json);
       assertTrue('context' in msg.body.script);
 
       // Check that we pick script name from //# sourceURL, iff present
diff --git a/test/mjsunit/debug-evaluate-locals-optimized-double.js b/test/mjsunit/debug-evaluate-locals-optimized-double.js
index 6696ec5..84b7e20 100644
--- a/test/mjsunit/debug-evaluate-locals-optimized-double.js
+++ b/test/mjsunit/debug-evaluate-locals-optimized-double.js
@@ -89,9 +89,10 @@
           }
 
           // All frames except the bottom one have two scopes.
-          assertEquals(2, frame.scopeCount());
+          assertEquals(3, frame.scopeCount());
           assertEquals(debug.ScopeType.Local, frame.scope(0).scopeType());
-          assertEquals(debug.ScopeType.Global, frame.scope(1).scopeType());
+          assertEquals(debug.ScopeType.Script, frame.scope(1).scopeType());
+          assertEquals(debug.ScopeType.Global, frame.scope(2).scopeType());
 
           Object.keys(expected_locals).forEach(function (name) {
             assertEquals(expected_locals[name],
@@ -134,8 +135,9 @@
                        frame.evaluate(arguments_sum).value());
         } else {
           // The bottom frame only have the global scope.
-          assertEquals(1, frame.scopeCount());
-          assertEquals(debug.ScopeType.Global, frame.scope(0).scopeType());
+          assertEquals(2, frame.scopeCount());
+          assertEquals(debug.ScopeType.Script, frame.scope(0).scopeType());
+          assertEquals(debug.ScopeType.Global, frame.scope(1).scopeType());
         }
 
         // Check the frame function.
diff --git a/test/mjsunit/debug-evaluate-locals-optimized.js b/test/mjsunit/debug-evaluate-locals-optimized.js
index d424001..9d539fe 100644
--- a/test/mjsunit/debug-evaluate-locals-optimized.js
+++ b/test/mjsunit/debug-evaluate-locals-optimized.js
@@ -79,10 +79,11 @@
                          frame.argumentValue(j).value());
           }
 
-          // All frames except the bottom one have two scopes.
-          assertEquals(2, frame.scopeCount());
+          // All frames except the bottom one have three scopes.
+          assertEquals(3, frame.scopeCount());
           assertEquals(debug.ScopeType.Local, frame.scope(0).scopeType());
-          assertEquals(debug.ScopeType.Global, frame.scope(1).scopeType());
+          assertEquals(debug.ScopeType.Script, frame.scope(1).scopeType());
+          assertEquals(debug.ScopeType.Global, frame.scope(2).scopeType());
 
           Object.keys(expected_locals).forEach(function (name) {
             assertEquals(expected_locals[name],
@@ -124,9 +125,10 @@
           assertEquals(expected_args_sum,
                        frame.evaluate(arguments_sum).value());
         } else {
-          // The bottom frame only have the global scope.
-          assertEquals(1, frame.scopeCount());
-          assertEquals(debug.ScopeType.Global, frame.scope(0).scopeType());
+          // The bottom frame only have the script scope and the global scope.
+          assertEquals(2, frame.scopeCount());
+          assertEquals(debug.ScopeType.Script, frame.scope(0).scopeType());
+          assertEquals(debug.ScopeType.Global, frame.scope(1).scopeType());
         }
 
         // Check the frame function.
diff --git a/test/mjsunit/debug-evaluate-with-context.js b/test/mjsunit/debug-evaluate-with-context.js
index 5e1c83c..fa615ad 100644
--- a/test/mjsunit/debug-evaluate-with-context.js
+++ b/test/mjsunit/debug-evaluate-with-context.js
@@ -32,6 +32,7 @@
 var evaluate_callback;
 
 function listener(event, exec_state, event_data, data) {
+  if (event !== Debug.DebugEvent.Break) return;
   try {
     var context = { what_is_capybara: "a fish" };
     var context2 = { what_is_capybara: "a fish", what_is_parrot: "a beard" };
diff --git a/test/mjsunit/debug-function-scopes.js b/test/mjsunit/debug-function-scopes.js
index b51e8b4..8992fe7 100644
--- a/test/mjsunit/debug-function-scopes.js
+++ b/test/mjsunit/debug-function-scopes.js
@@ -48,7 +48,8 @@
                   With: 2,
                   Closure: 3,
                   Catch: 4,
-                  Block: 5 };
+                  Block: 5,
+                  Script: 6};
 
 var f1 = (function F1(x) {
   function F2(y) {
@@ -68,21 +69,23 @@
 
 var mirror = Debug.MakeMirror(f1);
 
-assertEquals(5, mirror.scopeCount());
+assertEquals(6, mirror.scopeCount());
 
 CheckScope(mirror.scope(0), { a: 4, b: 5 }, ScopeType.Closure);
 CheckScope(mirror.scope(1), { w: 5, v: "Capybara" }, ScopeType.With);
 CheckScope(mirror.scope(2), { y: 17, z: 22 }, ScopeType.Closure);
 CheckScope(mirror.scope(3), { x: 5 }, ScopeType.Closure);
-CheckScope(mirror.scope(4), {}, ScopeType.Global);
+CheckScope(mirror.scope(4), {}, ScopeType.Script);
+CheckScope(mirror.scope(5), {}, ScopeType.Global);
 
 var f2 = function() { return 5; }
 
 var mirror = Debug.MakeMirror(f2);
 
-assertEquals(1, mirror.scopeCount());
+assertEquals(2, mirror.scopeCount());
 
-CheckScope(mirror.scope(0), {}, ScopeType.Global);
+CheckScope(mirror.scope(0), {}, ScopeType.Script);
+CheckScope(mirror.scope(1), {}, ScopeType.Global);
 
 var f3 = (function F1(invisible_parameter) {
   var invisible1 = 1;
@@ -99,11 +102,12 @@
 
 var mirror = Debug.MakeMirror(f3);
 
-assertEquals(3, mirror.scopeCount());
+assertEquals(4, mirror.scopeCount());
 
 CheckScope(mirror.scope(0), { visible2: 20 }, ScopeType.Closure);
 CheckScope(mirror.scope(1), { visible1: 10 }, ScopeType.Closure);
-CheckScope(mirror.scope(2), {}, ScopeType.Global);
+CheckScope(mirror.scope(2), {}, ScopeType.Script);
+CheckScope(mirror.scope(3), {}, ScopeType.Global);
 
 
 var f4 = (function One() {
@@ -122,11 +126,12 @@
 
 var mirror = Debug.MakeMirror(f4);
 
-assertEquals(3, mirror.scopeCount());
+assertEquals(4, mirror.scopeCount());
 
 CheckScope(mirror.scope(0), { e2: "I'm error 2" }, ScopeType.Catch);
 CheckScope(mirror.scope(1), { e1: "I'm error 1" }, ScopeType.Catch);
-CheckScope(mirror.scope(2), {}, ScopeType.Global);
+CheckScope(mirror.scope(2), {}, ScopeType.Script);
+CheckScope(mirror.scope(3), {}, ScopeType.Global);
 
 
 var f5 = (function Raz(p1, p2) {
@@ -141,11 +146,12 @@
 
 var mirror = Debug.MakeMirror(f5);
 
-assertEquals(3, mirror.scopeCount());
+assertEquals(4, mirror.scopeCount());
 
 CheckScope(mirror.scope(0), { p4: 20, p6: 22 }, ScopeType.Closure);
 CheckScope(mirror.scope(1), { p1: 1 }, ScopeType.Closure);
-CheckScope(mirror.scope(2), {}, ScopeType.Global);
+CheckScope(mirror.scope(2), {}, ScopeType.Script);
+CheckScope(mirror.scope(3), {}, ScopeType.Global);
 
 
 function CheckNoScopeVisible(f) {
diff --git a/test/mjsunit/debug-references.js b/test/mjsunit/debug-references.js
index 763e354..bb33976 100644
--- a/test/mjsunit/debug-references.js
+++ b/test/mjsunit/debug-references.js
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --expose-debug-as debug
+// Flags: --expose-debug-as debug --turbo-deoptimization
 // Get the Debug object exposed from the debug context global object.
 Debug = debug.Debug
 
diff --git a/test/mjsunit/debug-scopes.js b/test/mjsunit/debug-scopes.js
index 4823496..7c08120 100644
--- a/test/mjsunit/debug-scopes.js
+++ b/test/mjsunit/debug-scopes.js
@@ -130,6 +130,7 @@
     assertEquals(i, response.body.scopes[i].index);
     assertEquals(scopes[i], response.body.scopes[i].type);
     if (scopes[i] == debug.ScopeType.Local ||
+        scopes[i] == debug.ScopeType.Script ||
         scopes[i] == debug.ScopeType.Closure) {
       assertTrue(response.body.scopes[i].object.ref < 0);
     } else {
@@ -193,6 +194,7 @@
   assertEquals(scope.scopeType(), response.body.type);
   assertEquals(number, response.body.index);
   if (scope.scopeType() == debug.ScopeType.Local ||
+      scope.scopeType() == debug.ScopeType.Script ||
       scope.scopeType() == debug.ScopeType.Closure) {
     assertTrue(response.body.object.ref < 0);
   } else {
@@ -215,6 +217,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
 };
@@ -231,6 +234,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1}, 0, exec_state);
 };
@@ -248,6 +252,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,x:3}, 0, exec_state);
 };
@@ -266,6 +271,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,b:2,x:3,y:4}, 0, exec_state);
 };
@@ -283,6 +289,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
 };
@@ -300,6 +307,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({i:5}, 0, exec_state);
 };
@@ -321,6 +329,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,b:2,x:3,y:4,i:5,j:6}, 0, exec_state);
 };
@@ -340,6 +349,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
 };
@@ -362,6 +372,7 @@
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.With,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
   CheckScopeContent({}, 1, exec_state);
@@ -382,6 +393,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,b:2}, 0, exec_state);
 };
@@ -404,6 +416,7 @@
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.With,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:2,b:1}, 0, exec_state);
   CheckScopeContent({a:1,b:2}, 1, exec_state);
@@ -428,6 +441,7 @@
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.With,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent(with_object, 0, exec_state);
   CheckScopeContent(with_object, 1, exec_state);
@@ -443,6 +457,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.With,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent(with_object, 0, exec_state);
   CheckScopeContent(with_object, 1, exec_state);
@@ -472,6 +487,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
 };
@@ -494,6 +510,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1}, 1, exec_state);
 };
@@ -519,6 +536,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,x:3}, 1, exec_state);
 };
@@ -545,6 +563,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,b:2,x:3,y:4}, 1, exec_state);
 };
@@ -574,6 +593,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,b:2,x:3,y:4,f:function(){}}, 1, exec_state);
 };
@@ -602,6 +622,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,b:2,x:3,y:4,f:function(){}}, 1, exec_state);
 };
@@ -631,6 +652,7 @@
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1}, 1, exec_state);
   CheckScopeContent({f:function(){}}, 2, exec_state);
@@ -665,6 +687,7 @@
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
   CheckScopeContent({a:1,b:2,x:3,y:4,i:5,j:6}, 1, exec_state);
@@ -684,6 +707,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x: 2}, 0, exec_state);
 };
@@ -705,6 +729,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
 };
 closure_9();
@@ -746,6 +771,7 @@
                    debug.ScopeType.With,
                    debug.ScopeType.Closure,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({b:16}, 0, exec_state);
   CheckScopeContent({a:15}, 1, exec_state);
@@ -771,6 +797,7 @@
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.With,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x: 2}, 0, exec_state);
 };
@@ -794,6 +821,7 @@
                    debug.ScopeType.Local,
                    debug.ScopeType.With,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x: 3}, 0, exec_state);
   CheckScopeContent({x: 2}, 1, exec_state);
@@ -826,6 +854,7 @@
                    debug.ScopeType.Local,
                    debug.ScopeType.Closure,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
 }
 closure_in_with_3();
@@ -836,6 +865,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.With,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x: 2}, 0, exec_state);
   CheckScopeContent({x: 1}, 1, exec_state);
@@ -852,7 +882,7 @@
 // Test global scope.
 BeginTest("Global");
 listener_delegate = function(exec_state) {
-  CheckScopeChain([debug.ScopeType.Global], exec_state);
+  CheckScopeChain([debug.ScopeType.Script, debug.ScopeType.Global], exec_state);
 };
 debugger;
 EndTest();
@@ -871,6 +901,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Catch,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({e:'Exception'}, 0, exec_state);
 };
@@ -894,6 +925,7 @@
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.Catch,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({n:10}, 0, exec_state);
   CheckScopeContent({e:'Exception'}, 1, exec_state);
@@ -918,6 +950,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Catch,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({e:'Exception'}, 0, exec_state);
   CheckScopeContent({y:78}, 1, exec_state);
@@ -944,6 +977,7 @@
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.Catch,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({n:10}, 0, exec_state);
   CheckScopeContent({e:'Exception'}, 1, exec_state);
@@ -957,6 +991,7 @@
 BeginTest("Catch block 5");
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Catch,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({e:'Exception'}, 0, exec_state);
 };
@@ -975,6 +1010,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Catch,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x: 2}, 0, exec_state);
   CheckScopeContent({e:'Exception'}, 1, exec_state);
@@ -1005,6 +1041,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Catch,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({e:'Exception'}, 0, exec_state);
 };
diff --git a/test/mjsunit/debug-script.js b/test/mjsunit/debug-script.js
index 5ffada1..07f0e3c 100644
--- a/test/mjsunit/debug-script.js
+++ b/test/mjsunit/debug-script.js
@@ -26,6 +26,13 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // Flags: --expose-debug-as debug --expose-gc --send-idle-notification
+// Flags: --allow-natives-syntax
+// Flags: --noharmony-shipping
+// Note: this test checks that that the number of scripts reported as native
+// by Debug.scripts() is the same as a number of core native scripts.
+// Native scripts that are added by --harmony-shipping are classified
+// as 'experimental', but are still returned by Debug.scripts(), so
+// we disable harmony-shipping for this test
 
 // Get the Debug object exposed from the debug context global object.
 Debug = debug.Debug;
@@ -59,7 +66,7 @@
 }
 
 // This has to be updated if the number of native scripts change.
-assertTrue(named_native_count == 26 || named_native_count == 27);
+assertEquals(%NativeScriptsCount(), named_native_count);
 // Only the 'gc' extension is loaded.
 assertEquals(1, extension_count);
 // This script and mjsunit.js has been loaded.  If using d8, d8 loads
diff --git a/test/mjsunit/debug-step-turbofan.js b/test/mjsunit/debug-step-turbofan.js
new file mode 100644
index 0000000..c8c346b
--- /dev/null
+++ b/test/mjsunit/debug-step-turbofan.js
@@ -0,0 +1,57 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --turbo-filter=g --allow-natives-syntax
+
+// Test that Debug::PrepareForBreakPoints can deal with turbofan code (g)
+// on the stack.  Without deoptimization support, we will not be able to
+// replace optimized code for g by unoptimized code with debug break slots.
+// This would cause stepping to fail (V8 issue 3660).
+
+function f(x) {
+  g(x);
+  var a = 0;              // Break 6
+  return a;               // Break 7
+}                         // Break 8
+
+function g(x) {
+  if (x) h();
+  var a = 0;              // Break 2
+  var b = 1;              // Break 3
+  return a + b;           // Break 4
+}                         // Break 5
+
+function h() {
+  debugger;               // Break 0
+}                         // Break 1
+
+Debug = debug.Debug;
+var exception = null;
+var break_count = 0;
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    exec_state.prepareStep(Debug.StepAction.StepNext, 1);
+    print(exec_state.frame(0).sourceLineText());
+    var match = exec_state.frame(0).sourceLineText().match(/Break (\d)/);
+    assertNotNull(match);
+    assertEquals(break_count++, parseInt(match[1]));
+  } catch (e) {
+    print(e + e.stack);
+    exception = e;
+  }
+}
+
+f(0);
+f(0);
+%OptimizeFunctionOnNextCall(g);
+
+Debug.setListener(listener);
+
+f(1);
+
+Debug.setListener(null);  // Break 9
+assertNull(exception);
+assertEquals(10, break_count);
diff --git a/test/mjsunit/debug-step.js b/test/mjsunit/debug-step.js
index 2233e36..45f077f 100644
--- a/test/mjsunit/debug-step.js
+++ b/test/mjsunit/debug-step.js
@@ -68,7 +68,7 @@
 state = 0;
 result = -1;
 f();
-assertEquals(499, result);
+assertEquals(332, result);
 
 // Check that performing 1000 steps with a break point on the statement in the
 // for loop (line 2) will only make i 0 as a real break point breaks even when
diff --git a/test/mjsunit/debug-stepframe.js b/test/mjsunit/debug-stepframe.js
new file mode 100644
index 0000000..8f4ee4c
--- /dev/null
+++ b/test/mjsunit/debug-stepframe.js
@@ -0,0 +1,111 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+
+function f0() {
+  var v00 = 0;              // Break 1
+  var v01 = 1;
+  // Normal function call in a catch scope.
+  try {
+    throw 1;
+  } catch (e) {
+    try{
+      f1();
+    } catch (e) {
+      var v02 = 2;          // Break 13
+    }
+  }
+  var v03 = 3;
+  var v04 = 4;
+}
+
+function f1() {
+  var v10 = 0;              // Break 2
+  var v11 = 1;
+  // Getter call.
+  var v12 = o.get;
+  var v13 = 3               // Break 4
+  // Setter call.
+  o.set = 2;
+  var v14 = 4;              // Break 6
+  // Function.prototype.call.
+  f2.call();
+  var v15 = 5;              // Break 12
+  var v16 = 6;
+  // Exit function by throw.
+  throw 1;
+  var v17 = 7;
+}
+
+function get() {
+  var g0 = 0;               // Break 3
+  var g1 = 1;
+  return 3;
+}
+
+function set() {
+  var s0 = 0;               // Break 5
+  return 3;
+}
+
+function f2() {
+  var v20 = 0;              // Break 7
+  // Construct call.
+  var v21 = new c0();
+  var v22 = 2;              // Break 9
+  // Bound function.
+  b0();
+  return 2;                 // Break 11
+}
+
+function c0() {
+  this.v0 = 0;              // Break 8
+  this.v1 = 1;
+}
+
+function f3() {
+  var v30 = 0;              // Break 10
+  var v31 = 1;
+  return 3;
+}
+
+var b0 = f3.bind(o);
+
+var o = {};
+Object.defineProperty(o, "get", { get : get });
+Object.defineProperty(o, "set", { set : set });
+
+Debug = debug.Debug;
+var break_count = 0
+var exception = null;
+var step_size;
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    var line = exec_state.frame(0).sourceLineText();
+    print(line);
+    var match = line.match(/\/\/ Break (\d+)$/);
+    assertEquals(2, match.length);
+    assertEquals(break_count, parseInt(match[1]));
+    break_count += step_size;
+    exec_state.prepareStep(Debug.StepAction.StepFrame, step_size);
+  } catch (e) {
+    print(e + e.stack);
+    exception = e;
+  }
+}
+
+for (step_size = 1; step_size < 6; step_size++) {
+  print("step size = " + step_size);
+  break_count = 0;
+  Debug.setListener(listener);
+  debugger;                 // Break 0
+  f0();
+  Debug.setListener(null);  // Break 14
+  assertTrue(break_count > 14);
+}
+
+assertNull(exception);
diff --git a/test/mjsunit/debug-stepin-foreach.js b/test/mjsunit/debug-stepin-foreach.js
new file mode 100644
index 0000000..fa728e0
--- /dev/null
+++ b/test/mjsunit/debug-stepin-foreach.js
@@ -0,0 +1,51 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+// Tests stepping into through Array.prototype.forEach callbacks.
+
+Debug = debug.Debug
+var exception = null;
+var break_count = 0;
+var expected_breaks = -1;
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      assertTrue(exec_state.frameCount() != 0, "FAIL: Empty stack trace");
+      if (!break_count) {
+        // Count number of expected breakpoints in this source file.
+        var source_text = exec_state.frame(0).func().script().source();
+        expected_breaks = source_text.match(/\/\/\s*Break\s+\d+\./g).length;
+        print("Expected breaks: " + expected_breaks);
+      }
+      var source = exec_state.frame(0).sourceLineText();
+      print("paused at: " + source);
+      assertTrue(source.indexOf("// Break " + break_count + ".") > 0,
+                 "Unexpected pause at: " + source + "\n" +
+                 "Expected: // Break " + break_count + ".");
+      ++break_count;
+      if (break_count !== expected_breaks) {
+        exec_state.prepareStep(Debug.StepAction.StepIn, 1);
+      }
+    }
+  } catch(e) {
+    exception = e;
+    print(e, e.stack);
+  }
+};
+
+Debug.setListener(listener);
+
+debugger; // Break 0.
+[1,2].forEach(callback); // Break 1.
+
+function callback(x) {
+  return x; // Break 2. // Break 4.
+} // Break 3. // Break 5.
+
+assertNull(exception); // Break 6.
+assertEquals(expected_breaks, break_count);
+
+Debug.setListener(null);
diff --git a/test/mjsunit/debug-stepin-property-function-call.js b/test/mjsunit/debug-stepin-property-function-call.js
new file mode 100644
index 0000000..081fb24
--- /dev/null
+++ b/test/mjsunit/debug-stepin-property-function-call.js
@@ -0,0 +1,153 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug --nocrankshaft
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+var exception = null;
+var state = 1;
+
+// Simple debug event handler which first time will cause 'step in' action
+// to get into g.call and than check that execution is stopped inside
+// function 'g'.
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      if (state == 1) {
+        exec_state.prepareStep(Debug.StepAction.StepIn, 3);
+        state = 2;
+      } else if (state == 2) {
+        assertTrue(event_data.sourceLineText().indexOf("Expected to step") > 0,
+          "source line: \"" + event_data.sourceLineText() + "\"");
+        state = 3;
+      }
+    }
+  } catch(e) {
+    print("Exception: " + e);
+    exception = e;
+  }
+};
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+var count = 0;
+var obj = {
+  fun: function() {
+    ++count;
+    return count; // Expected to step
+  }
+};
+obj.fun2 = obj.fun;
+
+function testCall_Dots() {
+  debugger;
+  obj.fun();
+}
+
+function testCall_Quotes() {
+  debugger;
+  obj["fun"]();
+}
+
+function testCall_Call() {
+  debugger;
+  obj.fun.call(obj);
+}
+
+function testCall_Apply() {
+  debugger;
+  obj.fun.apply(obj);
+}
+
+function testCall_Variable() {
+  var functionName = "fun";
+  debugger;
+  obj[functionName]();
+}
+
+function testCall_Fun2() {
+  debugger;
+  obj.fun2();
+}
+
+function testCall_InternStrings() {
+  var cache = { "fun": "fun" };
+  var functionName = "fu" + "n";
+  debugger;
+  obj[cache[functionName]]();
+}
+
+function testCall_ViaFunRef() {
+  var functionName = "fu" + "n";
+  var funRef = obj[functionName];
+  debugger;
+  funRef();
+}
+
+// bug 2888
+function testCall_RuntimeVariable1() {
+  var functionName = "fu" + "n";
+  debugger;
+  obj[functionName]();
+}
+
+// bug 2888
+function testCall_RuntimeVariable2() {
+  var functionName = "un".replace(/u/, "fu");
+  debugger;
+  obj[functionName]();
+}
+
+// bug 2888
+function testCall_RuntimeVariable3() {
+  var expr = "fu" + "n";
+  const functionName = expr;
+  assertEquals("fun", functionName);
+  debugger;
+  obj[functionName]();
+}
+
+var functionsCalled = 0;
+for (var n in this) {
+  if (n.substr(0, 4) != 'test' || typeof this[n] !== "function") {
+    continue;
+  }
+  state = 1;
+  print("Running " + n + "...");
+  this[n]();
+  ++functionsCalled;
+  assertNull(exception, n);
+  assertEquals(3, state, n);
+  assertEquals(functionsCalled, count, n);
+}
+
+assertEquals(11, functionsCalled);
+
+// Get rid of the debug event listener.
+Debug.setListener(null);
diff --git a/test/mjsunit/deserialize-optimize-inner.js b/test/mjsunit/deserialize-optimize-inner.js
new file mode 100644
index 0000000..72df320
--- /dev/null
+++ b/test/mjsunit/deserialize-optimize-inner.js
@@ -0,0 +1,13 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --cache=code --no-lazy --serialize-inner
+
+function f(x, y) { return x + y; }
+
+assertEquals(1, f(0, 1));
+assertEquals(5, f(2, 3));
+%OptimizeFunctionOnNextCall(f);
+assertEquals(9, f(4, 5));
+assertOptimized(f);
diff --git a/test/mjsunit/es6/array-iterator.js b/test/mjsunit/es6/array-iterator.js
index 96122cd..767991e 100644
--- a/test/mjsunit/es6/array-iterator.js
+++ b/test/mjsunit/es6/array-iterator.js
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --allow-natives-syntax
+// Flags: --allow-natives-syntax --harmony-tostring
 
 
 var NONE = 0;
@@ -158,6 +158,15 @@
       Object.getOwnPropertyNames(ArrayIteratorPrototype));
   assertHasOwnProperty(ArrayIteratorPrototype, 'next', DONT_ENUM);
   assertHasOwnProperty(ArrayIteratorPrototype, Symbol.iterator, DONT_ENUM);
+
+  assertEquals("[object Array Iterator]",
+      Object.prototype.toString.call(iterator));
+  assertEquals("Array Iterator", ArrayIteratorPrototype[Symbol.toStringTag]);
+  var desc = Object.getOwnPropertyDescriptor(
+      ArrayIteratorPrototype, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.writable);
+  assertEquals("Array Iterator", desc.value);
 }
 TestArrayIteratorPrototype();
 
diff --git a/test/mjsunit/es6/collection-iterator.js b/test/mjsunit/es6/collection-iterator.js
index 5503fe5..18b3f1a 100644
--- a/test/mjsunit/es6/collection-iterator.js
+++ b/test/mjsunit/es6/collection-iterator.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Flags: --allow-natives-syntax
+// Flags: --allow-natives-syntax --harmony-tostring
 
 
 (function TestSetIterator() {
@@ -19,6 +19,15 @@
 
   assertEquals(new Set().values().__proto__, SetIteratorPrototype);
   assertEquals(new Set().entries().__proto__, SetIteratorPrototype);
+
+  assertEquals("[object Set Iterator]",
+      Object.prototype.toString.call(iter));
+  assertEquals("Set Iterator", SetIteratorPrototype[Symbol.toStringTag]);
+  var desc = Object.getOwnPropertyDescriptor(
+      SetIteratorPrototype, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.writable);
+  assertEquals("Set Iterator", desc.value);
 })();
 
 
@@ -120,6 +129,15 @@
   assertEquals(new Map().values().__proto__, MapIteratorPrototype);
   assertEquals(new Map().keys().__proto__, MapIteratorPrototype);
   assertEquals(new Map().entries().__proto__, MapIteratorPrototype);
+
+  assertEquals("[object Map Iterator]",
+      Object.prototype.toString.call(iter));
+  assertEquals("Map Iterator", MapIteratorPrototype[Symbol.toStringTag]);
+  var desc = Object.getOwnPropertyDescriptor(
+      MapIteratorPrototype, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.writable);
+  assertEquals("Map Iterator", desc.value);
 })();
 
 
diff --git a/test/mjsunit/es6/collections.js b/test/mjsunit/es6/collections.js
index 940c0b9..92cd087 100644
--- a/test/mjsunit/es6/collections.js
+++ b/test/mjsunit/es6/collections.js
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --expose-gc --allow-natives-syntax
+// Flags: --expose-gc --allow-natives-syntax --harmony-tostring
 
 
 function assertSize(expected, collection) {
@@ -266,7 +266,6 @@
 assertTrue(WeakMap.prototype.get instanceof Function)
 assertTrue(WeakMap.prototype.has instanceof Function)
 assertTrue(WeakMap.prototype.delete instanceof Function)
-assertTrue(WeakMap.prototype.clear instanceof Function)
 
 
 // Test some common JavaScript idioms for WeakSets
@@ -275,7 +274,6 @@
 assertTrue(WeakSet.prototype.add instanceof Function)
 assertTrue(WeakSet.prototype.has instanceof Function)
 assertTrue(WeakSet.prototype.delete instanceof Function)
-assertTrue(WeakSet.prototype.clear instanceof Function)
 
 
 // Test class of instance and prototype.
@@ -300,7 +298,7 @@
 function TestPrototype(C) {
   assertTrue(C.prototype instanceof Object);
   assertEquals({
-    value: {},
+    value: C.prototype,
     writable: false,
     enumerable: false,
     configurable: false
@@ -471,30 +469,6 @@
 })();
 
 
-// Test WeakMap clear
-(function() {
-  var k = new Object();
-  var w = new WeakMap();
-  w.set(k, 23);
-  assertTrue(w.has(k));
-  assertEquals(23, w.get(k));
-  w.clear();
-  assertFalse(w.has(k));
-  assertEquals(undefined, w.get(k));
-})();
-
-
-// Test WeakSet clear
-(function() {
-  var k = new Object();
-  var w = new WeakSet();
-  w.add(k);
-  assertTrue(w.has(k));
-  w.clear();
-  assertFalse(w.has(k));
-})();
-
-
 (function TestMinusZeroSet() {
   var s = new Set();
   s.add(-0);
@@ -691,6 +665,33 @@
   assertEquals(4950, accumulated);
 })();
 
+
+(function TestSetForEachReceiverAsObject() {
+  var set = new Set(["1", "2"]);
+
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  var a = [];
+  set.forEach(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  set.forEach(function() { a.push(this); }, {});
+  assertEquals(a[0], a[1]);
+})();
+
+
+(function TestSetForEachReceiverAsObjectInStrictMode() {
+  var set = new Set(["1", "2"]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  var a = [];
+  set.forEach(function() { 'use strict'; a.push(this); }, "");
+  assertTrue(a[0] === "" && a[0] === a[1]);
+})();
+
+
 (function TestMapForEachInvalidTypes() {
   assertThrows(function() {
     Map.prototype.map.forEach.call({});
@@ -998,6 +999,36 @@
 })();
 
 
+(function TestMapForEachReceiverAsObject() {
+  var map = new Map();
+  map.set("key1", "value1");
+  map.set("key2", "value2");
+
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  var a = [];
+  map.forEach(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  map.forEach(function() { a.push(this); }, {});
+  assertEquals(a[0], a[1]);
+})();
+
+
+(function TestMapForEachReceiverAsObjectInStrictMode() {
+  var map = new Map();
+  map.set("key1", "value1");
+  map.set("key2", "value2");
+
+  // In strict mode primitive values should not be coerced to an object.
+  var a = [];
+  map.forEach(function() { 'use strict'; a.push(this); }, "");
+  assertTrue(a[0] === "" && a[0] === a[1]);
+})();
+
+
 // Allows testing iterator-based constructors easily.
 var oneAndTwo = new Map();
 var k0 = {key: 0};
@@ -1366,3 +1397,12 @@
 }
 TestMapConstructorIterableValue(Map);
 TestMapConstructorIterableValue(WeakMap);
+
+function TestCollectionToString(C) {
+  assertEquals("[object " + C.name + "]",
+      Object.prototype.toString.call(new C()));
+}
+TestCollectionToString(Map);
+TestCollectionToString(Set);
+TestCollectionToString(WeakMap);
+TestCollectionToString(WeakSet);
diff --git a/test/mjsunit/es6/debug-stepin-microtasks.js b/test/mjsunit/es6/debug-stepin-microtasks.js
new file mode 100644
index 0000000..8dbdb34
--- /dev/null
+++ b/test/mjsunit/es6/debug-stepin-microtasks.js
@@ -0,0 +1,101 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --expose-debug-as debug
+
+Debug = debug.Debug
+var exception = null;
+var break_count = 0;
+var expected_breaks = -1;
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      assertTrue(exec_state.frameCount() != 0, "FAIL: Empty stack trace");
+      if (!break_count) {
+        // Count number of expected breakpoints in this source file.
+        var source_text = exec_state.frame(0).func().script().source();
+        expected_breaks = source_text.match(/\/\/\s*Break\s+\d+\./g).length;
+        print("Expected breaks: " + expected_breaks);
+      }
+      var source = exec_state.frame(0).sourceLineText();
+      print("paused at: " + source);
+      assertTrue(source.indexOf("// Break " + break_count + ".") > 0,
+                 "Unexpected pause at: " + source + "\n" +
+                 "Expected: // Break " + break_count + ".");
+      if (source.indexOf("StepOver.") !== -1) {
+        exec_state.prepareStep(Debug.StepAction.StepNext, 1);
+      } else {
+        exec_state.prepareStep(Debug.StepAction.StepIn, 1);
+      }
+      ++break_count;
+    }
+  } catch (e) {
+    exception = e;
+    print(e, e.stack);
+  }
+};
+
+Debug.setListener(listener);
+
+Promise.resolve(42)
+  .then(promise1)
+  .then(Object) // Should skip stepping into native.
+  .then(Boolean) // Should skip stepping into native.
+  .then(promise2)
+  .catch(promise3)
+  .catch(function(e) {
+    %AbortJS("FAIL: uncaught exception " + e);
+  });
+
+function promise1() {
+  debugger; // Break 0.
+  return exception || 1; // Break 1.
+} // Break 2.
+
+function promise2() {
+  throw new Error; // Break 3.
+}
+
+function promise3() {
+  installObservers(); // Break 4. StepOver.
+  return break_count; // Break 5.
+} // Break 6.
+
+function installObservers() {
+  var dummy = {};
+  Object.observe(dummy, observer1);
+  Object.observe(dummy, Object); // Should skip stepping into native.
+  Object.observe(dummy, Boolean); // Should skip stepping into native.
+  Object.observe(dummy, observer2);
+  dummy.foo = 1;
+}
+
+function observer1() {
+  return exception || 3; // Break 7.
+} // Break 8.
+
+function observer2() {
+  Promise.resolve().then(promise4); // Break 9. StepOver.
+  return break_count + 1; // Break 10.
+} // Break 11.
+
+function promise4() {
+  finalize(); // Break 12. StepOver.
+  return 0; // Break 13.
+} // Break 14. StepOver.
+
+function finalize() {
+  var dummy = {};
+  Object.observe(dummy, function() {
+    if (expected_breaks !== break_count) {
+      %AbortJS("FAIL: expected <" + expected_breaks + "> breaks instead of <" +
+               break_count + ">");
+    }
+    if (exception !== null) {
+      %AbortJS("FAIL: exception: " + exception);
+    }
+  });
+  dummy.foo = 1;
+}
diff --git a/test/mjsunit/es6/debug-stepnext-for.js b/test/mjsunit/es6/debug-stepnext-for.js
new file mode 100644
index 0000000..98af911
--- /dev/null
+++ b/test/mjsunit/es6/debug-stepnext-for.js
@@ -0,0 +1,116 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug --harmony
+
+Debug = debug.Debug;
+var break_count = 0
+var exception = null;
+var log = []
+
+var s = 0;
+var a = [1, 2, 3];
+var i = 0;
+
+function f() {
+  "use strict";
+  debugger;                      // Break a
+  var j;                         // Break b
+
+  for (var i in null) {          // Break c
+    s += a[i];
+  }
+
+  for (j in null) {              // Break d
+    s += a[j];
+  }
+
+  for (var i in a) {             // Break e
+    s += a[i];                   // Break E
+  }
+
+  for (j in a) {                 // Break f
+    s += a[j];                   // Break F
+  }
+
+  for (let i in a) {             // Break g
+    s += a[i];                   // Break G
+  }
+
+  for (var i of a) {             // Break h
+    s += i;                      // Break H
+  }
+
+  for (j of a) {                 // Break i
+    s += j;                      // Break I
+  }
+
+  for (let i of a) {             // Break j
+    s += i;                      // Break J
+  }
+
+  for (var i = 0; i < 3; i++) {  // Break k
+    s += a[i];                   // Break K
+  }
+
+  for (j = 0; j < 3; j++) {      // Break l
+    s += a[j];                   // Break L
+  }
+
+  // TODO(yangguo): add test case for for-let.
+}                                // Break y
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    var line = exec_state.frame(0).sourceLineText();
+    var col = exec_state.frame(0).sourceColumn();
+    print(line);
+    var match = line.match(/\/\/ Break (\w)$/);
+    assertEquals(2, match.length);
+    log.push(match[1] + col);
+    exec_state.prepareStep(Debug.StepAction.StepNext, 1);
+    break_count++;
+  } catch (e) {
+    exception = e;
+  }
+}
+
+Debug.setListener(listener);
+f();
+Debug.setListener(null);         // Break z
+
+print(JSON.stringify(log));
+// The let declaration differs from var in that the loop variable
+// is declared in every iteration.
+var expected = [
+  // Entry
+  "a2","b2",
+  // Empty for-in-var: var decl, get enumerable
+  "c7","c16",
+  // Empty for-in: get enumerable
+  "d12",
+  // For-in-var: var decl, get enumerable, assign, body, assign, body, ...
+  "e7","e16","e11","E4","e11","E4","e11","E4","e11",
+  // For-in: get enumerable, assign, body, assign, body, ...
+  "f12","f7","F4","f7","F4","f7","F4","f7",
+  // For-in-let: get enumerable, next, new let, body, next, new let, ...
+  "g16","g11","g7","G4","g11","g7","G4","g11","g7","G4","g11",
+  // For-of-var: var decl, next(), body, next(), body, ...
+  "h7","h16","H4","h16","H4","h16","H4","h16",
+  // For-of: next(), body, next(), body, ...
+  "i12","I4","i12","I4","i12","I4","i12",
+  // For-of-let: next(), new let, body, next(), new let, ...
+  "j16","j7","J4","j16","j7","J4","j16","j7","J4","j16",
+  // For-var: var decl, condition, body, next, condition, body, ...
+  "k7","k20","K4","k23","k20","K4","k23","k20","K4","k23","k20",
+  // For: init, condition, body, next, condition, body, ...
+  "l11","l16","L4","l19","l16","L4","l19","l16","L4","l19","l16",
+  // Exit.
+  "y0","z0",
+]
+
+assertArrayEquals(expected, log);
+assertEquals(48, s);
+assertNull(exception);
diff --git a/test/mjsunit/es6/generators-debug-scopes.js b/test/mjsunit/es6/generators-debug-scopes.js
index d55e561..126572d 100644
--- a/test/mjsunit/es6/generators-debug-scopes.js
+++ b/test/mjsunit/es6/generators-debug-scopes.js
@@ -97,6 +97,7 @@
     assertEquals(i, response.body.scopes[i].index);
     assertEquals(scopes[i], response.body.scopes[i].type);
     if (scopes[i] == debug.ScopeType.Local ||
+        scopes[i] == debug.ScopeType.Script ||
         scopes[i] == debug.ScopeType.Closure) {
       assertTrue(response.body.scopes[i].object.ref < 0);
     } else {
@@ -159,6 +160,7 @@
   assertEquals(scope.scopeType(), response.body.type);
   assertEquals(number, response.body.index);
   if (scope.scopeType() == debug.ScopeType.Local ||
+      scope.scopeType() == debug.ScopeType.Script ||
       scope.scopeType() == debug.ScopeType.Closure) {
     assertTrue(response.body.object.ref < 0);
   } else {
@@ -178,6 +180,7 @@
         [],
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({}, 0, exec_state);
         });
@@ -188,6 +191,7 @@
         [1],
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({a:1}, 0, exec_state);
         });
@@ -198,6 +202,7 @@
         [1],
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({a:1,x:3}, 0, exec_state);
         });
@@ -208,6 +213,7 @@
         [1, 2],
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({a:1,b:2,x:3,y:4}, 0, exec_state);
         });
@@ -218,6 +224,7 @@
         [],
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({}, 0, exec_state);
         });
@@ -228,6 +235,7 @@
         [],
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({i:5}, 0, exec_state);
         });
@@ -242,6 +250,7 @@
         [1, 2],
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({a:1,b:2,x:3,y:4,i:5,j:6}, 0, exec_state);
         });
@@ -254,6 +263,7 @@
           CheckScopeChain([debug.ScopeType.With,
                            debug.ScopeType.With,
                            debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({}, 0, exec_state);
           CheckScopeContent({}, 1, exec_state);
@@ -267,6 +277,7 @@
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
                            debug.ScopeType.Closure,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({a:1}, 1, exec_state);
         },
@@ -305,6 +316,7 @@
                            debug.ScopeType.With,
                            debug.ScopeType.Closure,
                            debug.ScopeType.Closure,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({b:16}, 0, exec_state);
           CheckScopeContent({a:15}, 1, exec_state);
@@ -321,6 +333,7 @@
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Catch,
                            debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({e:'Exception'}, 0, exec_state);
         });
diff --git a/test/mjsunit/es6/generators-iteration.js b/test/mjsunit/es6/generators-iteration.js
index b6fcdaa..faeb683 100644
--- a/test/mjsunit/es6/generators-iteration.js
+++ b/test/mjsunit/es6/generators-iteration.js
@@ -41,10 +41,7 @@
 }
 
 function assertThrownIteratorIsClosed(iter) {
-  // TODO(yusukesuzuki): Since status of a thrown generator is "executing",
-  // following tests are failed.
-  // https://code.google.com/p/v8/issues/detail?id=3096
-  // assertIteratorIsClosed(iter);
+  assertIteratorIsClosed(iter);
 }
 
 function TestGeneratorResultPrototype() {
diff --git a/test/mjsunit/es6/generators-mirror.js b/test/mjsunit/es6/generators-mirror.js
index 6925285..bf21f4d 100644
--- a/test/mjsunit/es6/generators-mirror.js
+++ b/test/mjsunit/es6/generators-mirror.js
@@ -24,7 +24,7 @@
   return this.refs_[handle];
 }
 
-function TestGeneratorMirror(g, test) {
+function TestGeneratorMirror(g, status, line, column, receiver) {
   // Create mirror and JSON representation.
   var mirror = debug.MakeMirror(g);
   var serializer = debug.MakeMirrorSerializer();
@@ -44,41 +44,69 @@
   assertFalse(mirror.isPrimitive());
   assertEquals('Generator', mirror.className());
 
-  assertTrue(mirror.receiver().isUndefined());
+  assertEquals(receiver, mirror.receiver().value());
   assertEquals(generator, mirror.func().value());
 
-  test(mirror);
+  assertEquals(status, mirror.status());
+
+  // Note that line numbers are 0-based, not 1-based.
+  var loc = mirror.sourceLocation();
+  if (status === 'suspended') {
+    assertTrue(!!loc);
+    assertEquals(line, loc.line);
+    assertEquals(column, loc.column);
+  } else {
+    assertEquals(undefined, loc);
+  }
+
+  TestInternalProperties(mirror, status, receiver);
 }
 
-var iter = generator(function () {
-  assertEquals('running', debug.MakeMirror(iter).status());
-})
-
-// Note that line numbers are 0-based, not 1-based.
-function assertSourceLocation(loc, line, column) {
-  assertEquals(line, loc.line);
-  assertEquals(column, loc.column);
+function TestInternalProperties(mirror, status, receiver) {
+  var properties = mirror.internalProperties();
+  assertEquals(3, properties.length);
+  assertEquals("[[GeneratorStatus]]", properties[0].name());
+  assertEquals(status, properties[0].value().value());
+  assertEquals("[[GeneratorFunction]]", properties[1].name());
+  assertEquals(generator, properties[1].value().value());
+  assertEquals("[[GeneratorReceiver]]", properties[2].name());
+  assertEquals(receiver, properties[2].value().value());
 }
 
-TestGeneratorMirror(iter, function (mirror) {
-  assertEquals('suspended', mirror.status())
-  assertSourceLocation(mirror.sourceLocation(), 7, 19);
-});
-
-iter.next();
-TestGeneratorMirror(iter, function (mirror) {
-  assertEquals('suspended', mirror.status())
-  assertSourceLocation(mirror.sourceLocation(), 9, 2);
-});
-
-iter.next();
-TestGeneratorMirror(iter, function (mirror) {
-  assertEquals('suspended', mirror.status())
-  assertSourceLocation(mirror.sourceLocation(), 11, 2);
-});
-
-iter.next();
-TestGeneratorMirror(iter, function (mirror) {
-  assertEquals('closed', mirror.status())
+var iter = generator(function() {
+  var mirror = debug.MakeMirror(iter);
+  assertEquals('running', mirror.status());
   assertEquals(undefined, mirror.sourceLocation());
+  TestInternalProperties(mirror, 'running');
 });
+
+TestGeneratorMirror(iter, 'suspended', 7, 19);
+
+iter.next();
+TestGeneratorMirror(iter, 'suspended', 9, 2);
+
+iter.next();
+TestGeneratorMirror(iter, 'suspended', 11, 2);
+
+iter.next();
+TestGeneratorMirror(iter, 'closed');
+
+// Test generator with receiver.
+var obj = {foo: 42};
+var iter2 = generator.call(obj, function() {
+  var mirror = debug.MakeMirror(iter2);
+  assertEquals('running', mirror.status());
+  assertEquals(undefined, mirror.sourceLocation());
+  TestInternalProperties(mirror, 'running', obj);
+});
+
+TestGeneratorMirror(iter2, 'suspended', 7, 19, obj);
+
+iter2.next();
+TestGeneratorMirror(iter2, 'suspended', 9, 2, obj);
+
+iter2.next();
+TestGeneratorMirror(iter2, 'suspended', 11, 2, obj);
+
+iter2.next();
+TestGeneratorMirror(iter2, 'closed', 0, 0, obj);
diff --git a/test/mjsunit/es6/generators-objects.js b/test/mjsunit/es6/generators-objects.js
index 8a052ff..8039ca8 100644
--- a/test/mjsunit/es6/generators-objects.js
+++ b/test/mjsunit/es6/generators-objects.js
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --harmony-scoping --allow-natives-syntax
+// Flags: --harmony-scoping --allow-natives-syntax --harmony-tostring
 
 // Test instantations of generators.
 
@@ -66,6 +66,9 @@
   assertTrue(iter instanceof g);
   assertEquals("Generator", %_ClassOf(iter));
   assertEquals("[object Generator]", String(iter));
+  assertEquals("[object Generator]", Object.prototype.toString.call(iter));
+  var gf = iter.__proto__.constructor;
+  assertEquals("[object GeneratorFunction]", Object.prototype.toString.call(gf));
   assertEquals([], Object.getOwnPropertyNames(iter));
   assertTrue(iter !== new g());
 }
diff --git a/test/mjsunit/es6/generators-states.js b/test/mjsunit/es6/generators-states.js
new file mode 100644
index 0000000..0a2173a
--- /dev/null
+++ b/test/mjsunit/es6/generators-states.js
@@ -0,0 +1,67 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Test generator states.
+
+function Foo() {}
+function Bar() {}
+
+function assertIteratorResult(value, done, result) {
+  assertEquals({ value: value, done: done}, result);
+}
+
+function assertIteratorIsClosed(iter) {
+  assertIteratorResult(undefined, true, iter.next());
+  // Next and throw on a closed iterator.
+  assertDoesNotThrow(function() { iter.next(); });
+  assertThrows(function() { iter.throw(new Bar); }, Bar);
+}
+
+var iter;
+function* nextGenerator() { yield iter.next(); }
+function* throwGenerator() { yield iter.throw(new Bar); }
+
+// Throw on a suspendedStart iterator.
+iter = nextGenerator();
+assertThrows(function() { iter.throw(new Foo) }, Foo)
+assertThrows(function() { iter.throw(new Foo) }, Foo)
+assertIteratorIsClosed(iter);
+
+// The same.
+iter = throwGenerator();
+assertThrows(function() { iter.throw(new Foo) }, Foo)
+assertThrows(function() { iter.throw(new Foo) }, Foo)
+assertIteratorIsClosed(iter);
+
+// Next on an executing iterator raises a TypeError.
+iter = nextGenerator();
+assertThrows(function() { iter.next() }, TypeError)
+assertIteratorIsClosed(iter);
+
+// Throw on an executing iterator raises a TypeError.
+iter = throwGenerator();
+assertThrows(function() { iter.next() }, TypeError)
+assertIteratorIsClosed(iter);
+
+// Next on an executing iterator doesn't change the state of the
+// generator.
+iter = (function* () {
+  try {
+    iter.next();
+    yield 1;
+  } catch (e) {
+    try {
+      // This next() should raise the same exception, because the first
+      // next() left the iter in the executing state.
+      iter.next();
+      yield 2;
+    } catch (e) {
+      yield 3;
+    }
+  }
+  yield 4;
+})();
+assertIteratorResult(3, false, iter.next());
+assertIteratorResult(4, false, iter.next());
+assertIteratorIsClosed(iter);
diff --git a/test/mjsunit/es6/json.js b/test/mjsunit/es6/json.js
new file mode 100644
index 0000000..3fad083
--- /dev/null
+++ b/test/mjsunit/es6/json.js
@@ -0,0 +1,15 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-tostring
+
+function testJSONToString() {
+  assertEquals('[object JSON]', "" + JSON);
+  assertEquals("JSON", JSON[Symbol.toStringTag]);
+  var desc = Object.getOwnPropertyDescriptor(JSON, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.writable);
+  assertEquals("JSON", desc.value);
+}
+testJSONToString();
diff --git a/test/mjsunit/es6/math-log2-log10.js b/test/mjsunit/es6/math-log2-log10.js
index 4479894..fa3f468 100644
--- a/test/mjsunit/es6/math-log2-log10.js
+++ b/test/mjsunit/es6/math-log2-log10.js
@@ -25,6 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Flags: --allow-natives-syntax
+
 [Math.log10, Math.log2].forEach( function(fun) {
   assertTrue(isNaN(fun(NaN)));
   assertTrue(isNaN(fun(fun)));
@@ -39,7 +41,59 @@
   assertEquals("Infinity", String(fun(Infinity)));
 });
 
-for (var i = -300; i < 300; i += 0.7) {
-  assertEqualsDelta(i, Math.log10(Math.pow(10, i)), 1E-13);
-  assertEqualsDelta(i, Math.log2(Math.pow(2, i)), 1E-13);
+for (var i = -310; i <= 308; i += 0.5) {
+  assertEquals(i, Math.log10(Math.pow(10, i)));
+  // Square roots are tested below.
+  if (i != -0.5 && i != 0.5) assertEquals(i, Math.log2(Math.pow(2, i)));
+}
+
+// Test denormals.
+assertEquals(-307.77759430519706, Math.log10(1.5 * Math.pow(2, -1023)));
+
+// Test Math.log2(2^k) for -1074 <= k <= 1023.
+var n = -1074;
+// This loop covers n from -1074 to -1043
+for (var lowbits = 1; lowbits <= 0x80000000; lowbits *= 2) {
+  var x = %_ConstructDouble(0, lowbits);
+  assertEquals(n, Math.log2(x));
+  n++;
+}
+// This loop covers n from -1042 to -1023
+for (var hibits = 1; hibits <= 0x80000; hibits *= 2) {
+  var x = %_ConstructDouble(hibits, 0);
+  assertEquals(n, Math.log2(x));
+  n++;
+}
+// The rest of the normal values of 2^n
+var x = 1;
+for (var n = -1022; n <= 1023; ++n) {
+  var x = Math.pow(2, n);
+  assertEquals(n, Math.log2(x));
+}
+
+// Test special values.
+// Expectation isn't exactly 1/2 because Math.SQRT2 isn't exactly sqrt(2).
+assertEquals(0.5000000000000001, Math.log2(Math.SQRT2));
+
+// Expectation isn't exactly -1/2 because Math.SQRT1_2 isn't exactly sqrt(1/2).
+assertEquals(-0.4999999999999999, Math.log2(Math.SQRT1_2));
+
+assertEquals(3.321928094887362, Math.log2(10));
+assertEquals(6.643856189774724, Math.log2(100));
+
+// Test relationships
+x = 1;
+for (var k = 0; k < 1000; ++k) {
+  var y = Math.abs(Math.log2(x) + Math.log2(1/x));
+  assertEqualsDelta(0, y, 1.5e-14);
+  x *= 1.1;
+}
+
+x = Math.pow(2, -100);
+for (var k = 0; k < 1000; ++k) {
+  var y = Math.log2(x);
+  var expected = Math.log(x) / Math.LN2;
+  var err = Math.abs(y - expected) / expected;
+  assertEqualsDelta(0, err, 1e-15);
+  x *= 1.1;
 }
diff --git a/test/mjsunit/es6/math.js b/test/mjsunit/es6/math.js
new file mode 100644
index 0000000..3f76f11
--- /dev/null
+++ b/test/mjsunit/es6/math.js
@@ -0,0 +1,15 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-tostring
+
+function testMathToString() {
+  assertEquals('[object Math]', "" + Math);
+  assertEquals("Math", Math[Symbol.toStringTag]);
+  var desc = Object.getOwnPropertyDescriptor(Math, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.writable);
+  assertEquals("Math", desc.value);
+}
+testMathToString();
diff --git a/test/mjsunit/es6/mirror-collections.js b/test/mjsunit/es6/mirror-collections.js
index e10f5c1..81a98b8 100644
--- a/test/mjsunit/es6/mirror-collections.js
+++ b/test/mjsunit/es6/mirror-collections.js
@@ -51,6 +51,7 @@
 map.delete(o1);
 var mapMirror = debug.MakeMirror(map);
 testMapMirror(mapMirror);
+
 var entries = mapMirror.entries();
 assertEquals(1, entries.length);
 assertSame(o2, entries[0].key);
@@ -59,6 +60,7 @@
 map.set(o3, o2);
 map.delete(o2);
 map.set(undefined, 44);
+
 entries = mapMirror.entries();
 assertEquals(3, entries.length);
 assertSame(o1, entries[0].key);
@@ -68,6 +70,10 @@
 assertEquals(undefined, entries[2].key);
 assertEquals(44, entries[2].value);
 
+assertEquals(3, mapMirror.entries(0).length);
+assertEquals(1, mapMirror.entries(1).length);
+assertEquals(2, mapMirror.entries(2).length);
+
 // Test the mirror object for Sets
 var set = new Set();
 set.add(o1);
@@ -78,6 +84,7 @@
 testSetMirror(setMirror);
 var values = setMirror.values();
 assertEquals(2, values.length);
+assertEquals(1, setMirror.values(1).length);
 assertSame(o2, values[0]);
 assertEquals(undefined, values[1]);
 
@@ -96,6 +103,8 @@
 function testWeakMapEntries(weakMapMirror) {
   var entries = weakMapMirror.entries();
   assertEquals(2, entries.length);
+  assertEquals(2, weakMapMirror.entries(0).length);
+  assertEquals(1, weakMapMirror.entries(1).length);
   var found = 0;
   for (var i = 0; i < entries.length; i++) {
     if (Object.is(entries[i].key, o1)) {
@@ -129,6 +138,8 @@
 function testWeakSetValues(weakSetMirror) {
   var values = weakSetMirror.values();
   assertEquals(2, values.length);
+  assertEquals(2, weakSetMirror.values(0).length);
+  assertEquals(1, weakSetMirror.values(1).length);
   var found = 0;
   for (var i = 0; i < values.length; i++) {
     if (Object.is(values[i], o1)) {
diff --git a/test/mjsunit/es6/mirror-iterators.js b/test/mjsunit/es6/mirror-iterators.js
new file mode 100644
index 0000000..22ce424
--- /dev/null
+++ b/test/mjsunit/es6/mirror-iterators.js
@@ -0,0 +1,103 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for collection iterators.
+
+function testIteratorMirror(iter, offset, expected, opt_limit) {
+  while (offset-- > 0) iter.next();
+
+  var mirror = debug.MakeMirror(iter);
+  assertTrue(mirror.isIterator());
+
+  var preview = mirror.preview(opt_limit);
+  assertArrayEquals(expected, preview);
+
+  // Check that iterator has not changed after taking preview.
+  var values = [];
+  for (var i of iter) {
+    if (opt_limit && values.length >= opt_limit) break;
+    values.push(i);
+  }
+  assertArrayEquals(expected, values);
+}
+
+function testIteratorInternalProperties(iter, offset, kind, index, has_more) {
+  while (offset-- > 0) iter.next();
+
+  var mirror = debug.MakeMirror(iter);
+  assertTrue(mirror.isIterator());
+
+  var properties = mirror.internalProperties();
+  assertEquals(3, properties.length);
+  assertEquals("[[IteratorHasMore]]", properties[0].name());
+  assertEquals(has_more, properties[0].value().value());
+  assertEquals("[[IteratorIndex]]", properties[1].name());
+  assertEquals(index, properties[1].value().value());
+  assertEquals("[[IteratorKind]]", properties[2].name());
+  assertEquals(kind, properties[2].value().value());
+}
+
+var o1 = { foo: 1 };
+var o2 = { foo: 2 };
+
+var map = new Map();
+map.set(41, 42);
+map.set(o1, o2);
+
+testIteratorMirror(map.keys(), 0, [41, o1]);
+testIteratorMirror(map.values(), 0, [42, o2]);
+testIteratorMirror(map.entries(), 0, [[41, 42], [o1, o2]]);
+
+testIteratorMirror(map.keys(), 1, [o1]);
+testIteratorMirror(map.values(), 1, [o2]);
+testIteratorMirror(map.entries(), 1, [[o1, o2]]);
+
+testIteratorMirror(map.keys(), 2, []);
+testIteratorMirror(map.values(), 2, []);
+testIteratorMirror(map.entries(), 2, []);
+
+// Test with maximum limit.
+testIteratorMirror(map.keys(), 0, [41], 1);
+testIteratorMirror(map.values(), 0, [42], 1);
+testIteratorMirror(map.entries(), 0, [[41, 42]], 1);
+
+testIteratorInternalProperties(map.keys(), 0, "keys", 0, true);
+testIteratorInternalProperties(map.values(), 1, "values", 1, true);
+testIteratorInternalProperties(map.entries(), 2, "entries", 2, false);
+testIteratorInternalProperties(map.keys(), 3, "keys", 2, false);
+
+var set = new Set();
+set.add(41);
+set.add(42);
+set.add(o1);
+set.add(o2);
+
+testIteratorMirror(set.keys(), 0, [41, 42, o1, o2]);
+testIteratorMirror(set.values(), 0, [41, 42, o1, o2]);
+testIteratorMirror(set.entries(), 0, [[41, 41], [42, 42], [o1, o1], [o2, o2]]);
+
+testIteratorMirror(set.keys(), 1, [42, o1, o2]);
+testIteratorMirror(set.values(), 1, [42, o1, o2]);
+testIteratorMirror(set.entries(), 1, [[42, 42], [o1, o1], [o2, o2]]);
+
+testIteratorMirror(set.keys(), 3, [o2]);
+testIteratorMirror(set.values(), 3, [o2]);
+testIteratorMirror(set.entries(), 3, [[o2, o2]]);
+
+testIteratorMirror(set.keys(), 5, []);
+testIteratorMirror(set.values(), 5, []);
+testIteratorMirror(set.entries(), 5, []);
+
+// Test with maximum limit.
+testIteratorMirror(set.keys(), 1, [42, o1], 2);
+testIteratorMirror(set.values(), 1, [42, o1], 2);
+testIteratorMirror(set.entries(), 1, [[42, 42], [o1, o1]], 2);
+
+testIteratorInternalProperties(set.keys(), 0, "values", 0, true);
+testIteratorInternalProperties(set.values(), 1, "values", 1, true);
+testIteratorInternalProperties(set.entries(), 2, "entries", 2, true);
+testIteratorInternalProperties(set.keys(), 3, "values", 3, true);
+testIteratorInternalProperties(set.values(), 4, "values", 4, false);
+testIteratorInternalProperties(set.entries(), 5, "entries", 4, false);
diff --git a/test/mjsunit/harmony/numeric-literals.js b/test/mjsunit/es6/numeric-literals.js
similarity index 100%
rename from test/mjsunit/harmony/numeric-literals.js
rename to test/mjsunit/es6/numeric-literals.js
diff --git a/test/mjsunit/es6/object-tostring.js b/test/mjsunit/es6/object-tostring.js
new file mode 100644
index 0000000..26dff14
--- /dev/null
+++ b/test/mjsunit/es6/object-tostring.js
@@ -0,0 +1,133 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-tostring
+
+var global = this;
+
+var funs = {
+  Object:   [ Object ],
+  Function: [ Function ],
+  Array:    [ Array ],
+  String:   [ String ],
+  Boolean:  [ Boolean ],
+  Number:   [ Number ],
+  Date:     [ Date ],
+  RegExp:   [ RegExp ],
+  Error:    [ Error, TypeError, RangeError, SyntaxError, ReferenceError,
+              EvalError, URIError ]
+}
+for (f in funs) {
+  for (i in funs[f]) {
+    assertEquals("[object " + f + "]",
+                 Object.prototype.toString.call(new funs[f][i]),
+                 funs[f][i]);
+    assertEquals("[object Function]",
+                 Object.prototype.toString.call(funs[f][i]),
+                 funs[f][i]);
+  }
+}
+
+function testToStringTag(className) {
+  // Using builtin toStringTags
+  var obj = {};
+  obj[Symbol.toStringTag] = className;
+  assertEquals("[object ~" + className + "]",
+               Object.prototype.toString.call(obj));
+
+  // Getter throws
+  obj = {};
+  Object.defineProperty(obj, Symbol.toStringTag, {
+    get: function() { throw className; }
+  });
+  assertThrows(function() {
+    Object.prototype.toString.call(obj);
+  }, className);
+
+  // Getter does not throw
+  obj = {};
+  Object.defineProperty(obj, Symbol.toStringTag, {
+    get: function() { return className; }
+  });
+  assertEquals("[object ~" + className + "]",
+               Object.prototype.toString.call(obj));
+
+  // Custom, non-builtin toStringTags
+  obj = {};
+  obj[Symbol.toStringTag] = "X" + className;
+  assertEquals("[object X" + className + "]",
+               Object.prototype.toString.call(obj));
+
+  // With getter
+  obj = {};
+  Object.defineProperty(obj, Symbol.toStringTag, {
+    get: function() { return "X" + className; }
+  });
+  assertEquals("[object X" + className + "]",
+               Object.prototype.toString.call(obj));
+
+  // Undefined toStringTag should return [object className]
+  var obj = className === "Arguments" ?
+      (function() { return arguments; })() : new global[className];
+  obj[Symbol.toStringTag] = undefined;
+  assertEquals("[object " + className + "]",
+               Object.prototype.toString.call(obj));
+
+  // With getter
+  var obj = className === "Arguments" ?
+      (function() { return arguments; })() : new global[className];
+  Object.defineProperty(obj, Symbol.toStringTag, {
+    get: function() { return undefined; }
+  });
+  assertEquals("[object " + className + "]",
+               Object.prototype.toString.call(obj));
+}
+
+[
+  "Arguments",
+  "Array",
+  "Boolean",
+  "Date",
+  "Error",
+  "Function",
+  "Number",
+  "RegExp",
+  "String"
+].forEach(testToStringTag);
+
+function testToStringTagNonString(value) {
+  var obj = {};
+  obj[Symbol.toStringTag] = value;
+  assertEquals("[object ???]", Object.prototype.toString.call(obj));
+
+  // With getter
+  obj = {};
+  Object.defineProperty(obj, Symbol.toStringTag, {
+    get: function() { return value; }
+  });
+  assertEquals("[object ???]", Object.prototype.toString.call(obj));
+}
+
+[
+  null,
+  function() {},
+  [],
+  {},
+  /regexp/,
+  42,
+  Symbol("sym"),
+  new Date(),
+  (function() { return arguments; })(),
+  true,
+  new Error("oops"),
+  new String("str")
+].forEach(testToStringTagNonString);
+
+function testObjectToStringPropertyDesc() {
+  var desc = Object.getOwnPropertyDescriptor(Object.prototype, "toString");
+  assertTrue(desc.writable);
+  assertFalse(desc.enumerable);
+  assertTrue(desc.configurable);
+}
+testObjectToStringPropertyDesc();
diff --git a/test/mjsunit/es6/promises.js b/test/mjsunit/es6/promises.js
index faf154e..04059aa 100644
--- a/test/mjsunit/es6/promises.js
+++ b/test/mjsunit/es6/promises.js
@@ -25,13 +25,21 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --allow-natives-syntax
+// Flags: --allow-natives-syntax --harmony-tostring
 
 // Make sure we don't rely on functions patchable by monkeys.
 var call = Function.prototype.call.call.bind(Function.prototype.call)
 var observe = Object.observe;
-var getOwnPropertyNames = Object.getOwnPropertyNames
-var defineProperty = Object.defineProperty
+var getOwnPropertyNames = Object.getOwnPropertyNames;
+var defineProperty = Object.defineProperty;
+
+
+(function() {
+  // Test before clearing global (fails otherwise)
+  assertEquals("[object Promise]",
+      Object.prototype.toString.call(new Promise(function() {})));
+})();
+
 
 function clear(o) {
   if (o === null || (typeof o !== 'object' && typeof o !== 'function')) return
diff --git a/test/mjsunit/es6/regress/regress-3902.js b/test/mjsunit/es6/regress/regress-3902.js
new file mode 100644
index 0000000..768a4a1
--- /dev/null
+++ b/test/mjsunit/es6/regress/regress-3902.js
@@ -0,0 +1,15 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function* g() {}
+assertTrue(Object.getOwnPropertyDescriptor(g.__proto__, "constructor").configurable);
+assertTrue(Object.getOwnPropertyDescriptor(g.prototype.__proto__, "constructor").configurable);
+
+function FakeGeneratorFunctionConstructor() {}
+Object.defineProperty(g.__proto__, "constructor", {value: FakeGeneratorFunctionConstructor});
+assertSame(g.__proto__.constructor, FakeGeneratorFunctionConstructor);
+
+function FakeGeneratorObjectConstructor() {}
+Object.defineProperty(g.prototype.__proto__, "constructor", {value: FakeGeneratorObjectConstructor});
+assertSame(g.prototype.__proto__.constructor, FakeGeneratorObjectConstructor);
diff --git a/test/mjsunit/es6/string-iterator.js b/test/mjsunit/es6/string-iterator.js
index e6bea6d..769f549 100644
--- a/test/mjsunit/es6/string-iterator.js
+++ b/test/mjsunit/es6/string-iterator.js
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// Flags: --harmony-tostring
 
 function TestStringPrototypeIterator() {
   assertTrue(String.prototype.hasOwnProperty(Symbol.iterator));
@@ -59,6 +60,12 @@
   assertArrayEquals(['next'],
       Object.getOwnPropertyNames(StringIteratorPrototype));
   assertEquals('[object String Iterator]', "" + iterator);
+  assertEquals("String Iterator", StringIteratorPrototype[Symbol.toStringTag]);
+  var desc = Object.getOwnPropertyDescriptor(
+      StringIteratorPrototype, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.writable);
+  assertEquals("String Iterator", desc.value);
 }
 TestStringIteratorPrototype();
 
diff --git a/test/mjsunit/es6/symbols.js b/test/mjsunit/es6/symbols.js
index 60737af..b9811f5 100644
--- a/test/mjsunit/es6/symbols.js
+++ b/test/mjsunit/es6/symbols.js
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --expose-gc --allow-natives-syntax
+// Flags: --expose-gc --allow-natives-syntax --harmony-tostring
 
 var symbols = []
 
@@ -501,3 +501,11 @@
   assertSame("x3", Symbol.keyFor(symbol3))
 }
 TestRegistry()
+
+
+function TestGetOwnPropertySymbolsOnPrimitives() {
+  assertEquals(Object.getOwnPropertySymbols(true), []);
+  assertEquals(Object.getOwnPropertySymbols(5000), []);
+  assertEquals(Object.getOwnPropertySymbols("OK"), []);
+}
+TestGetOwnPropertySymbolsOnPrimitives();
diff --git a/test/mjsunit/es6/unscopables.js b/test/mjsunit/es6/unscopables.js
index 36365d2..03612be 100644
--- a/test/mjsunit/es6/unscopables.js
+++ b/test/mjsunit/es6/unscopables.js
@@ -143,6 +143,13 @@
     assertEquals(2, y);
     assertEquals(3, z);
   }
+
+  object[Symbol.unscopables] = {x: 0, y: undefined};
+  with (object) {
+    assertEquals(1, x);
+    assertEquals(5, y);
+    assertEquals(3, z);
+  }
 }
 runTest(TestBasics);
 
@@ -161,6 +168,13 @@
   with (object) {
     assertEquals(1, x);
   }
+
+  object[Symbol.unscopables] = {
+    __proto__: {x: undefined}
+  };
+  with (object) {
+    assertEquals(2, x);
+  }
 }
 runTest(TestUnscopableChain);
 
@@ -222,6 +236,14 @@
     assertEquals(5, y);
     assertEquals(3, z);
   }
+
+  proto[Symbol.unscopables] = {y: true};
+  object[Symbol.unscopables] = {x: true, y: undefined};
+  with (object) {
+    assertEquals(1, x);
+    assertEquals(5, y);
+    assertEquals(3, z);
+  }
 }
 runTest(TestOnProto);
 
@@ -341,6 +363,20 @@
 TestChangeDuringWithWithPossibleOptimization4({});
 
 
+function TestChangeDuringWithWithPossibleOptimization4(object) {
+  var x = 1;
+  object.x = 2;
+  object[Symbol.unscopables] = {x: true};
+  with (object) {
+    for (var i = 0; i < 1000; i++) {
+      if (i === 500) object[Symbol.unscopables].x = undefined;
+      assertEquals(i < 500 ? 1 : 2, x);
+    }
+  }
+}
+TestChangeDuringWithWithPossibleOptimization4({});
+
+
 function TestAccessorReceiver(object, proto) {
   var x = 'local';
 
@@ -532,9 +568,11 @@
   var x = 1;
   object.x = 2;
 
+  var calls = 0;
   var unscopables = {
     get x() {
-      assertUnreachable();
+      calls++;
+      return calls === 1 ? true : undefined;
     }
   };
 
@@ -542,7 +580,9 @@
     assertEquals(2, x);
     object[Symbol.unscopables] = unscopables;
     assertEquals(1, x);
+    assertEquals(2, x);
   }
+  assertEquals(2, calls);
 }
 runTest(TestAccessorOnUnscopables);
 
@@ -659,3 +699,25 @@
   }, CustomError);
 }
 TestGetUnscopablesGetterThrows();
+
+
+function TestGetUnscopablesGetterThrows2() {
+  var object = {
+    get x() {
+      assertUnreachable();
+    }
+  };
+  function CustomError() {}
+
+  object[Symbol.unscopables] = {
+    get x() {
+      throw new CustomError();
+    }
+  };
+  assertThrows(function() {
+    with (object) {
+      x;
+    }
+  }, CustomError);
+}
+TestGetUnscopablesGetterThrows();
diff --git a/test/mjsunit/es7/regress/regress-443982.js b/test/mjsunit/es7/regress/regress-443982.js
new file mode 100644
index 0000000..5a2e9cd
--- /dev/null
+++ b/test/mjsunit/es7/regress/regress-443982.js
@@ -0,0 +1,22 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var records;
+function observer(r) {
+  records = r;
+}
+
+Object.defineProperty(Array.prototype, '0', {
+  get: function() { return 0; },
+  set: function() { throw "boom!"; }
+});
+arr = [1, 2];
+Array.observe(arr, observer);
+arr.length = 0;
+assertEquals(0, arr.length);
+
+Object.deliverChangeRecords(observer);
+assertEquals(1, records.length);
+assertEquals('splice', records[0].type);
+assertArrayEquals([1, 2], records[0].removed);
diff --git a/test/mjsunit/fast-prototype.js b/test/mjsunit/fast-prototype.js
index 9864761..c59ec94 100644
--- a/test/mjsunit/fast-prototype.js
+++ b/test/mjsunit/fast-prototype.js
@@ -114,9 +114,9 @@
   assertTrue(key == 'a');
   break;
 }
-assertFalse(%HasFastProperties(x));
+assertTrue(%HasFastProperties(x));
 x.d = 4;
-assertFalse(%HasFastProperties(x));
+assertTrue(%HasFastProperties(x));
 for (key in x) {
   assertTrue(key == 'a');
   break;
diff --git a/test/mjsunit/function-call.js b/test/mjsunit/function-call.js
index 88df353..fb91dcd 100644
--- a/test/mjsunit/function-call.js
+++ b/test/mjsunit/function-call.js
@@ -162,13 +162,10 @@
 
   var exception = false;
   try {
-    // We call all functions with no parameters, which means that essential
-    // parameters will have the undefined value.
-    // The test for whether the "this" value is null or undefined is always
-    // performed before access to the other parameters, so even if the
-    // undefined value is an invalid argument value, it mustn't change
-    // the result of the test.
-    should_throw_on_null_and_undefined[i].call(null);
+    // We need to pass a dummy object argument ({}) to these functions because
+    // of Object.prototype.isPrototypeOf's special behavior, see issue 3483
+    // for more details.
+    should_throw_on_null_and_undefined[i].call(null, {});
   } catch (e) {
     exception = true;
     checkExpectedMessage(e);
@@ -177,7 +174,7 @@
 
   exception = false;
   try {
-    should_throw_on_null_and_undefined[i].call(undefined);
+    should_throw_on_null_and_undefined[i].call(undefined, {});
   } catch (e) {
     exception = true;
     checkExpectedMessage(e);
@@ -186,7 +183,7 @@
 
   exception = false;
   try {
-    should_throw_on_null_and_undefined[i].apply(null);
+    should_throw_on_null_and_undefined[i].apply(null, [{}]);
   } catch (e) {
     exception = true;
     checkExpectedMessage(e);
@@ -195,7 +192,7 @@
 
   exception = false;
   try {
-    should_throw_on_null_and_undefined[i].apply(undefined);
+    should_throw_on_null_and_undefined[i].apply(undefined, [{}]);
   } catch (e) {
     exception = true;
     checkExpectedMessage(e);
@@ -248,7 +245,9 @@
 
 // Test that we still throw when calling with thisArg null or undefined
 // through an array mapping function.
-var array = [1,2,3,4,5];
+// We need to make sure that the elements of `array` are all object values,
+// see issue 3483 for more details.
+var array = [{}, [], new Number, new Map, new WeakSet];
 for (var j = 0; j < mapping_functions.length; j++) {
   for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) {
     exception = false;
diff --git a/test/mjsunit/function-length-accessor.js b/test/mjsunit/function-length-accessor.js
index 357ac3f..97c9f65 100644
--- a/test/mjsunit/function-length-accessor.js
+++ b/test/mjsunit/function-length-accessor.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Flags: --harmony-scoping
+// Flags: --harmony-scoping --lazy
 
 function foo(a, b, c, d) {
   "use strict"
diff --git a/test/mjsunit/getters-on-elements.js b/test/mjsunit/getters-on-elements.js
index 3bc360f..7f2c98b 100644
--- a/test/mjsunit/getters-on-elements.js
+++ b/test/mjsunit/getters-on-elements.js
@@ -176,7 +176,7 @@
           create_func_double,
           create_func_fast];
 
-for(var c = 0; c < 3; c++) {
+for(var c = 0; c < cf.length; c++) {
   base_getter_test(cf[c]);
 }
 
diff --git a/test/mjsunit/harmony/array-concat.js b/test/mjsunit/harmony/array-concat.js
new file mode 100644
index 0000000..286aefd
--- /dev/null
+++ b/test/mjsunit/harmony/array-concat.js
@@ -0,0 +1,686 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-arrays --harmony-classes
+
+(function testArrayConcatArity() {
+  "use strict";
+  assertEquals(1, Array.prototype.concat.length);
+})();
+
+
+(function testArrayConcatNoPrototype() {
+  "use strict";
+  assertEquals(void 0, Array.prototype.concat.prototype);
+})();
+
+
+(function testArrayConcatDescriptor() {
+  "use strict";
+  var desc = Object.getOwnPropertyDescriptor(Array.prototype, 'concat');
+  assertEquals(false, desc.enumerable);
+})();
+
+
+(function testConcatArrayLike() {
+  "use strict";
+  var obj = {
+    "length": 6,
+    "1": "A",
+    "3": "B",
+    "5": "C"
+  };
+  obj[Symbol.isConcatSpreadable] = true;
+  var obj2 = { length: 3, "0": "0", "1": "1", "2": "2" };
+  var arr = ["X", "Y", "Z"];
+  assertEquals([void 0, "A", void 0, "B", void 0, "C",
+               { "length": 3, "0": "0", "1": "1", "2": "2" },
+               "X", "Y", "Z"], Array.prototype.concat.call(obj, obj2, arr));
+})();
+
+
+(function testConcatArrayLikeStringLength() {
+  "use strict";
+  var obj = {
+    "length": "6",
+    "1": "A",
+    "3": "B",
+    "5": "C"
+  };
+  obj[Symbol.isConcatSpreadable] = true;
+  var obj2 = { length: 3, "0": "0", "1": "1", "2": "2" };
+  var arr = ["X", "Y", "Z"];
+  assertEquals([void 0, "A", void 0, "B", void 0, "C",
+               { "length": 3, "0": "0", "1": "1", "2": "2" },
+               "X", "Y", "Z"], Array.prototype.concat.call(obj, obj2, arr));
+})();
+
+
+(function testConcatArrayLikeNegativeLength() {
+  "use strict";
+  var obj = {
+    "length": -6,
+    "1": "A",
+    "3": "B",
+    "5": "C"
+  };
+  obj[Symbol.isConcatSpreadable] = true;
+  assertEquals([], [].concat(obj));
+  obj.length = -6.7;
+  assertEquals([], [].concat(obj));
+  obj.length = "-6";
+  assertEquals([], [].concat(obj));
+})();
+
+
+(function testConcatArrayLikeToLengthThrows() {
+  "use strict";
+  var obj = {
+    "length": {valueOf: null, toString: null},
+    "1": "A",
+    "3": "B",
+    "5": "C"
+  };
+  obj[Symbol.isConcatSpreadable] = true;
+  var obj2 = { length: 3, "0": "0", "1": "1", "2": "2" };
+  var arr = ["X", "Y", "Z"];
+  assertThrows(function() {
+    Array.prototype.concat.call(obj, obj2, arr);
+  }, TypeError);
+})();
+
+
+(function testConcatArrayLikePrimitiveNonNumberLength() {
+  "use strict";
+  var obj = {
+    "1": "A",
+    "3": "B",
+    "5": "C"
+  };
+  obj[Symbol.isConcatSpreadable] = true;
+  obj.length = {toString: function() { return "SIX"; }, valueOf: null };
+  assertEquals([], [].concat(obj));
+  obj.length = {toString: null, valueOf: function() { return "SIX"; } };
+  assertEquals([], [].concat(obj));
+})();
+
+
+(function testConcatArrayLikeLengthToStringThrows() {
+  "use strict";
+  function MyError() {}
+  var obj = {
+    "length": { toString: function() {
+        throw new MyError();
+      }, valueOf: null
+    },
+    "1": "A",
+    "3": "B",
+    "5": "C"
+  };
+  obj[Symbol.isConcatSpreadable] = true;
+  assertThrows(function() {
+    [].concat(obj);
+  }, MyError);
+})();
+
+
+(function testConcatArrayLikeLengthValueOfThrows() {
+  "use strict";
+  function MyError() {}
+  var obj = {
+    "length": { valueOf: function() {
+      throw new MyError();
+    }, toString: null
+  },
+  "1": "A",
+  "3": "B",
+  "5": "C"
+};
+obj[Symbol.isConcatSpreadable] = true;
+assertThrows(function() {
+  [].concat(obj);
+}, MyError);
+})();
+
+
+(function testConcatHoleyArray() {
+  "use strict";
+  var arr = [];
+  arr[4] = "Item 4";
+  arr[8] = "Item 8";
+  var arr2 = [".", "!", "?"];
+  assertEquals([void 0, void 0, void 0, void 0, "Item 4", void 0, void 0,
+                void 0, "Item 8", ".", "!", "?"], arr.concat(arr2));
+})();
+
+
+(function testIsConcatSpreadableGetterThrows() {
+  "use strict";
+  function MyError() {}
+  var obj = {};
+  Object.defineProperty(obj, Symbol.isConcatSpreadable, {
+    get: function() { throw new MyError(); }
+  });
+
+  assertThrows(function() {
+    [].concat(obj);
+  }, MyError);
+
+  assertThrows(function() {
+    Array.prototype.concat.call(obj, 1, 2, 3);
+  }, MyError);
+})();
+
+
+(function testConcatLengthThrows() {
+  "use strict";
+  function MyError() {}
+  var obj = {};
+  obj[Symbol.isConcatSpreadable] = true;
+  Object.defineProperty(obj, "length", {
+    get: function() { throw new MyError(); }
+  });
+
+  assertThrows(function() {
+    [].concat(obj);
+  }, MyError);
+
+  assertThrows(function() {
+    Array.prototype.concat.call(obj, 1, 2, 3);
+  }, MyError);
+})();
+
+
+(function testConcatArraySubclass() {
+  "use strict";
+  // TODO(caitp): when concat is called on instances of classes which extend
+  // Array, they should:
+  //
+  // - return an instance of the class, rather than an Array instance (if from
+  //   same Realm)
+  // - always treat such classes as concat-spreadable
+})();
+
+
+(function testConcatNonArray() {
+  "use strict";
+  class NonArray {
+    constructor() { Array.apply(this, arguments); }
+  };
+
+  var obj = new NonArray(1,2,3);
+  var result = Array.prototype.concat.call(obj, 4, 5, 6);
+  assertEquals(Array, result.constructor);
+  assertEquals([obj,4,5,6], result);
+  assertFalse(result instanceof NonArray);
+})();
+
+
+function testConcatTypedArray(type, elems, modulo) {
+  "use strict";
+  var items = new Array(elems);
+  var ta_by_len = new type(elems);
+  for (var i = 0; i < elems; ++i) {
+    ta_by_len[i] = items[i] = modulo === false ? i : elems % modulo;
+  }
+  var ta = new type(items);
+  assertEquals([ta, ta], [].concat(ta, ta));
+  ta[Symbol.isConcatSpreadable] = true;
+  assertEquals(items, [].concat(ta));
+
+  assertEquals([ta_by_len, ta_by_len], [].concat(ta_by_len, ta_by_len));
+  ta_by_len[Symbol.isConcatSpreadable] = true;
+  assertEquals(items, [].concat(ta_by_len));
+
+  // TypedArray with fake `length`.
+  ta = new type(1);
+  var defValue = ta[0];
+  var expected = new Array(4000);
+  expected[0] = defValue;
+
+  Object.defineProperty(ta, "length", { value: 4000 });
+  ta[Symbol.isConcatSpreadable] = true;
+  assertEquals(expected, [].concat(ta));
+}
+
+(function testConcatSmallTypedArray() {
+  var max = [2^8, 2^16, 2^32, false, false];
+  [
+    Uint8Array,
+    Uint16Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array
+  ].forEach(function(ctor, i) {
+    testConcatTypedArray(ctor, 1, max[i]);
+  });
+})();
+
+
+(function testConcatLargeTypedArray() {
+  var max = [2^8, 2^16, 2^32, false, false];
+  [
+    Uint8Array,
+    Uint16Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array
+  ].forEach(function(ctor, i) {
+    testConcatTypedArray(ctor, 4000, max[i]);
+  });
+})();
+
+
+(function testConcatStrictArguments() {
+  var args = (function(a, b, c) { "use strict"; return arguments; })(1,2,3);
+  args[Symbol.isConcatSpreadable] = true;
+  assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args));
+
+  Object.defineProperty(args, "length", { value: 6 });
+  assertEquals([1, 2, 3, void 0, void 0, void 0], [].concat(args));
+})();
+
+
+(function testConcatSloppyArguments() {
+  var args = (function(a, b, c) { return arguments; })(1,2,3);
+  args[Symbol.isConcatSpreadable] = true;
+  assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args));
+
+  Object.defineProperty(args, "length", { value: 6 });
+  assertEquals([1, 2, 3, void 0, void 0, void 0], [].concat(args));
+})();
+
+
+(function testConcatSloppyArgumentsWithDupes() {
+  var args = (function(a, a, a) { return arguments; })(1,2,3);
+  args[Symbol.isConcatSpreadable] = true;
+  assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args));
+
+  Object.defineProperty(args, "length", { value: 6 });
+  assertEquals([1, 2, 3, void 0, void 0, void 0], [].concat(args));
+})();
+
+
+(function testConcatSloppyArgumentsThrows() {
+  function MyError() {}
+  var args = (function(a) { return arguments; })(1,2,3);
+  Object.defineProperty(args, 0, {
+    get: function() { throw new MyError(); }
+  });
+  args[Symbol.isConcatSpreadable] = true;
+  assertThrows(function() {
+    return [].concat(args, args);
+  }, MyError);
+})();
+
+
+(function testConcatHoleySloppyArguments() {
+  var args = (function(a) { return arguments; })(1,2,3);
+  delete args[1];
+  args[Symbol.isConcatSpreadable] = true;
+  assertEquals([1, void 0, 3, 1, void 0, 3], [].concat(args, args));
+})();
+
+
+(function testConcatSpreadableStringWrapper() {
+  "use strict";
+  var str1 = new String("yuck\uD83D\uDCA9")
+  // String wrapper objects are not concat-spreadable by default
+  assertEquals([str1], [].concat(str1));
+
+  // String wrapper objects may be individually concat-spreadable
+  str1[Symbol.isConcatSpreadable] = true;
+  assertEquals(["y", "u", "c", "k", "\uD83D", "\uDCA9"],
+               [].concat(str1));
+
+  String.prototype[Symbol.isConcatSpreadable] = true;
+  // String wrapper objects may be concat-spreadable
+  assertEquals(["y", "u", "c", "k", "\uD83D", "\uDCA9"],
+               [].concat(new String("yuck\uD83D\uDCA9")));
+
+  // String values are never concat-spreadable
+  assertEquals(["yuck\uD83D\uDCA9"], [].concat("yuck\uD83D\uDCA9"));
+  delete String.prototype[Symbol.isConcatSpreadable];
+})();
+
+
+(function testConcatSpreadableBooleanWrapper() {
+  "use strict";
+  var bool = new Boolean(true)
+  // Boolean wrapper objects are not concat-spreadable by default
+  assertEquals([bool], [].concat(bool));
+
+  // Boolean wrapper objects may be individually concat-spreadable
+  bool[Symbol.isConcatSpreadable] = true;
+  bool.length = 3;
+  bool[0] = 1, bool[1] = 2, bool[2] = 3;
+  assertEquals([1, 2, 3], [].concat(bool));
+
+  Boolean.prototype[Symbol.isConcatSpreadable] = true;
+  // Boolean wrapper objects may be concat-spreadable
+  assertEquals([], [].concat(new Boolean(true)));
+  Boolean.prototype[0] = 1;
+  Boolean.prototype[1] = 2;
+  Boolean.prototype[2] = 3;
+  Boolean.prototype.length = 3;
+  assertEquals([1,2,3], [].concat(new Boolean(true)));
+
+  // Boolean values are never concat-spreadable
+  assertEquals([true], [].concat(true));
+  delete Boolean.prototype[Symbol.isConcatSpreadable];
+  delete Boolean.prototype[0];
+  delete Boolean.prototype[1];
+  delete Boolean.prototype[2];
+  delete Boolean.prototype.length;
+})();
+
+
+(function testConcatSpreadableNumberWrapper() {
+  "use strict";
+  var num = new Number(true)
+  // Number wrapper objects are not concat-spreadable by default
+  assertEquals([num], [].concat(num));
+
+  // Number wrapper objects may be individually concat-spreadable
+  num[Symbol.isConcatSpreadable] = true;
+  num.length = 3;
+  num[0] = 1, num[1] = 2, num[2] = 3;
+  assertEquals([1, 2, 3], [].concat(num));
+
+  Number.prototype[Symbol.isConcatSpreadable] = true;
+  // Number wrapper objects may be concat-spreadable
+  assertEquals([], [].concat(new Number(123)));
+  Number.prototype[0] = 1;
+  Number.prototype[1] = 2;
+  Number.prototype[2] = 3;
+  Number.prototype.length = 3;
+  assertEquals([1,2,3], [].concat(new Number(123)));
+
+  // Number values are never concat-spreadable
+  assertEquals([true], [].concat(true));
+  delete Number.prototype[Symbol.isConcatSpreadable];
+  delete Number.prototype[0];
+  delete Number.prototype[1];
+  delete Number.prototype[2];
+  delete Number.prototype.length;
+})();
+
+
+(function testConcatSpreadableFunction() {
+  "use strict";
+  var fn = function(a, b, c) {}
+  // Functions are not concat-spreadable by default
+  assertEquals([fn], [].concat(fn));
+
+  // Functions may be individually concat-spreadable
+  fn[Symbol.isConcatSpreadable] = true;
+  fn[0] = 1, fn[1] = 2, fn[2] = 3;
+  assertEquals([1, 2, 3], [].concat(fn));
+
+  Function.prototype[Symbol.isConcatSpreadable] = true;
+  // Functions may be concat-spreadable
+  assertEquals([void 0, void 0, void 0], [].concat(function(a,b,c) {}));
+  Function.prototype[0] = 1;
+  Function.prototype[1] = 2;
+  Function.prototype[2] = 3;
+  assertEquals([1,2,3], [].concat(function(a, b, c) {}));
+
+  delete Function.prototype[Symbol.isConcatSpreadable];
+  delete Function.prototype[0];
+  delete Function.prototype[1];
+  delete Function.prototype[2];
+})();
+
+
+(function testConcatSpreadableRegExp() {
+  "use strict";
+  var re = /abc/;
+  // RegExps are not concat-spreadable by default
+  assertEquals([re], [].concat(re));
+
+  // RegExps may be individually concat-spreadable
+  re[Symbol.isConcatSpreadable] = true;
+  re[0] = 1, re[1] = 2, re[2] = 3, re.length = 3;
+  assertEquals([1, 2, 3], [].concat(re));
+
+  // RegExps may be concat-spreadable
+  RegExp.prototype[Symbol.isConcatSpreadable] = true;
+  RegExp.prototype.length = 3;
+
+  assertEquals([void 0, void 0, void 0], [].concat(/abc/));
+  RegExp.prototype[0] = 1;
+  RegExp.prototype[1] = 2;
+  RegExp.prototype[2] = 3;
+  assertEquals([1,2,3], [].concat(/abc/));
+
+  delete RegExp.prototype[Symbol.isConcatSpreadable];
+  delete RegExp.prototype[0];
+  delete RegExp.prototype[1];
+  delete RegExp.prototype[2];
+  delete RegExp.prototype.length;
+})();
+
+
+(function testArrayConcatSpreadableSparseObject() {
+  "use strict";
+  var obj = { length: 5 };
+  obj[Symbol.isConcatSpreadable] = true;
+  assertEquals([void 0, void 0, void 0, void 0, void 0], [].concat(obj));
+
+  obj.length = 4000;
+  assertEquals(new Array(4000), [].concat(obj));
+})();
+
+
+// ES5 tests
+(function testArrayConcatES5() {
+  "use strict";
+  var poses;
+  var pos;
+
+  poses = [140, 4000000000];
+  while (pos = poses.shift()) {
+    var a = new Array(pos);
+    var array_proto = [];
+    a.__proto__ = array_proto;
+    assertEquals(pos, a.length);
+    a.push('foo');
+    assertEquals(pos + 1, a.length);
+    var b = ['bar'];
+    var c = a.concat(b);
+    assertEquals(pos + 2, c.length);
+    assertEquals("undefined", typeof(c[pos - 1]));
+    assertEquals("foo", c[pos]);
+    assertEquals("bar", c[pos + 1]);
+
+    // Can we fool the system by putting a number in a string?
+    var onetwofour = "124";
+    a[onetwofour] = 'doo';
+    assertEquals(a[124], 'doo');
+    c = a.concat(b);
+    assertEquals(c[124], 'doo');
+
+    // If we put a number in the prototype, then the spec says it should be
+    // copied on concat.
+    array_proto["123"] = 'baz';
+    assertEquals(a[123], 'baz');
+
+    c = a.concat(b);
+    assertEquals(pos + 2, c.length);
+    assertEquals("baz", c[123]);
+    assertEquals("undefined", typeof(c[pos - 1]));
+    assertEquals("foo", c[pos]);
+    assertEquals("bar", c[pos + 1]);
+
+    // When we take the number off the prototype it disappears from a, but
+    // the concat put it in c itself.
+    array_proto["123"] = undefined;
+    assertEquals("undefined", typeof(a[123]));
+    assertEquals("baz", c[123]);
+
+    // If the element of prototype is shadowed, the element on the instance
+    // should be copied, but not the one on the prototype.
+    array_proto[123] = 'baz';
+    a[123] = 'xyz';
+    assertEquals('xyz', a[123]);
+    c = a.concat(b);
+    assertEquals('xyz', c[123]);
+
+    // Non-numeric properties on the prototype or the array shouldn't get
+    // copied.
+    array_proto.moe = 'joe';
+    a.ben = 'jerry';
+    assertEquals(a["moe"], 'joe');
+    assertEquals(a["ben"], 'jerry');
+    c = a.concat(b);
+    // ben was not copied
+    assertEquals("undefined", typeof(c.ben));
+
+    // When we take moe off the prototype it disappears from all arrays.
+    array_proto.moe = undefined;
+    assertEquals("undefined", typeof(c.moe));
+
+    // Negative indices don't get concated.
+    a[-1] = 'minus1';
+    assertEquals("minus1", a[-1]);
+    assertEquals("undefined", typeof(a[0xffffffff]));
+    c = a.concat(b);
+    assertEquals("undefined", typeof(c[-1]));
+    assertEquals("undefined", typeof(c[0xffffffff]));
+    assertEquals(c.length, a.length + 1);
+  }
+
+  poses = [140, 4000000000];
+  while (pos = poses.shift()) {
+    var a = new Array(pos);
+    assertEquals(pos, a.length);
+    a.push('foo');
+    assertEquals(pos + 1, a.length);
+    var b = ['bar'];
+    var c = a.concat(b);
+    assertEquals(pos + 2, c.length);
+    assertEquals("undefined", typeof(c[pos - 1]));
+    assertEquals("foo", c[pos]);
+    assertEquals("bar", c[pos + 1]);
+
+    // Can we fool the system by putting a number in a string?
+    var onetwofour = "124";
+    a[onetwofour] = 'doo';
+    assertEquals(a[124], 'doo');
+    c = a.concat(b);
+    assertEquals(c[124], 'doo');
+
+    // If we put a number in the prototype, then the spec says it should be
+    // copied on concat.
+    Array.prototype["123"] = 'baz';
+    assertEquals(a[123], 'baz');
+
+    c = a.concat(b);
+    assertEquals(pos + 2, c.length);
+    assertEquals("baz", c[123]);
+    assertEquals("undefined", typeof(c[pos - 1]));
+    assertEquals("foo", c[pos]);
+    assertEquals("bar", c[pos + 1]);
+
+    // When we take the number off the prototype it disappears from a, but
+    // the concat put it in c itself.
+    Array.prototype["123"] = undefined;
+    assertEquals("undefined", typeof(a[123]));
+    assertEquals("baz", c[123]);
+
+    // If the element of prototype is shadowed, the element on the instance
+    // should be copied, but not the one on the prototype.
+    Array.prototype[123] = 'baz';
+    a[123] = 'xyz';
+    assertEquals('xyz', a[123]);
+    c = a.concat(b);
+    assertEquals('xyz', c[123]);
+
+    // Non-numeric properties on the prototype or the array shouldn't get
+    // copied.
+    Array.prototype.moe = 'joe';
+    a.ben = 'jerry';
+    assertEquals(a["moe"], 'joe');
+    assertEquals(a["ben"], 'jerry');
+    c = a.concat(b);
+    // ben was not copied
+    assertEquals("undefined", typeof(c.ben));
+    // moe was not copied, but we can see it through the prototype
+    assertEquals("joe", c.moe);
+
+    // When we take moe off the prototype it disappears from all arrays.
+    Array.prototype.moe = undefined;
+    assertEquals("undefined", typeof(c.moe));
+
+    // Negative indices don't get concated.
+    a[-1] = 'minus1';
+    assertEquals("minus1", a[-1]);
+    assertEquals("undefined", typeof(a[0xffffffff]));
+    c = a.concat(b);
+    assertEquals("undefined", typeof(c[-1]));
+    assertEquals("undefined", typeof(c[0xffffffff]));
+    assertEquals(c.length, a.length + 1);
+
+  }
+
+  a = [];
+  c = a.concat('Hello');
+  assertEquals(1, c.length);
+  assertEquals("Hello", c[0]);
+  assertEquals("Hello", c.toString());
+
+  // Check that concat preserves holes.
+  var holey = [void 0,'a',,'c'].concat(['d',,'f',[0,,2],void 0])
+  assertEquals(9, holey.length);  // hole in embedded array is ignored
+  for (var i = 0; i < holey.length; i++) {
+    if (i == 2 || i == 5) {
+      assertFalse(i in holey);
+    } else {
+      assertTrue(i in holey);
+    }
+  }
+
+  // Polluted prototype from prior tests.
+  delete Array.prototype[123];
+
+  // Check that concat reads getters in the correct order.
+  var arr1 = [,2];
+  var arr2 = [1,3];
+  var r1 = [].concat(arr1, arr2);  // [,2,1,3]
+  assertEquals([,2,1,3], r1);
+
+  // Make first array change length of second array.
+  Object.defineProperty(arr1, 0, {get: function() {
+        arr2.push("X");
+        return undefined;
+      }, configurable: true})
+  var r2 = [].concat(arr1, arr2);  // [undefined,2,1,3,"X"]
+  assertEquals([undefined,2,1,3,"X"], r2);
+
+  // Make first array change length of second array massively.
+  arr2.length = 2;
+  Object.defineProperty(arr1, 0, {get: function() {
+        arr2[500000] = "X";
+        return undefined;
+      }, configurable: true})
+  var r3 = [].concat(arr1, arr2);  // [undefined,2,1,3,"X"]
+  var expected = [undefined,2,1,3];
+  expected[500000 + 2] = "X";
+
+  assertEquals(expected, r3);
+
+  var arr3 = [];
+  var trace = [];
+  var expectedTrace = []
+  function mkGetter(i) { return function() { trace.push(i); }; }
+  arr3.length = 10000;
+  for (var i = 0; i < 100; i++) {
+    Object.defineProperty(arr3, i * i, {get: mkGetter(i)});
+    expectedTrace[i] = i;
+    expectedTrace[100 + i] = i;
+  }
+  var r4 = [0].concat(arr3, arr3);
+  assertEquals(1 + arr3.length * 2, r4.length);
+  assertEquals(expectedTrace, trace);
+})();
diff --git a/test/mjsunit/harmony/array-find.js b/test/mjsunit/harmony/array-find.js
index 9f5750e..eb32082 100644
--- a/test/mjsunit/harmony/array-find.js
+++ b/test/mjsunit/harmony/array-find.js
@@ -237,6 +237,24 @@
     return this.elementAt(key) === val;
   }, thisArg);
   assertEquals("b", found);
+
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  a = [];
+  [1, 2].find(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  [1, 2].find(function() { a.push(this) }, {});
+  assertEquals(a[0], a[1]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  a = [];
+  [1, 2].find(function() { 'use strict'; a.push(this); }, "");
+  assertEquals("", a[0]);
+  assertEquals(a[0], a[1]);
+
 })();
 
 // Test exceptions
diff --git a/test/mjsunit/harmony/array-findindex.js b/test/mjsunit/harmony/array-findindex.js
index a33849d..a5df05a 100644
--- a/test/mjsunit/harmony/array-findindex.js
+++ b/test/mjsunit/harmony/array-findindex.js
@@ -237,6 +237,24 @@
     return this.elementAt(key) === val;
   }, thisArg);
   assertEquals(1, index);
+
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  a = [];
+  [1, 2].findIndex(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  [1, 2].findIndex(function() { a.push(this) }, {});
+  assertEquals(a[0], a[1]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  a = [];
+  [1, 2].findIndex(function() { 'use strict'; a.push(this); }, "");
+  assertEquals("", a[0]);
+  assertEquals(a[0], a[1]);
+
 })();
 
 // Test exceptions
diff --git a/test/mjsunit/harmony/array-from.js b/test/mjsunit/harmony/array-from.js
new file mode 100644
index 0000000..e7c9fef
--- /dev/null
+++ b/test/mjsunit/harmony/array-from.js
@@ -0,0 +1,123 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-arrays --harmony-generators
+(function() {
+
+assertEquals(1, Array.from.length);
+
+function assertArrayLikeEquals(value, expected, type) {
+  assertInstanceof(value, type);
+  assertEquals(expected.length, value.length);
+  for (var i=0; i<value.length; ++i) {
+    assertEquals(expected[i], value[i]);
+  }
+}
+
+// Assert that constructor is called with "length" for array-like objects
+var myCollectionCalled = false;
+function MyCollection(length) {
+  myCollectionCalled = true;
+  assertEquals(1, arguments.length);
+  assertEquals(5, length);
+}
+
+Array.from.call(MyCollection, {length: 5});
+assertTrue(myCollectionCalled);
+
+// Assert that calling mapfn with / without thisArg in sloppy and strict modes
+// works as expected.
+var global = this;
+function non_strict(){ assertEquals(global, this); }
+function strict(){ "use strict"; assertEquals(void 0, this); }
+function strict_null(){ "use strict"; assertEquals(null, this); }
+Array.from([1], non_strict);
+Array.from([1], non_strict, void 0);
+Array.from([1], non_strict, null);
+Array.from([1], strict);
+Array.from([1], strict, void 0);
+Array.from([1], strict_null, null);
+
+function testArrayFrom(thisArg, constructor) {
+  assertArrayLikeEquals(Array.from.call(thisArg, [], undefined), [],
+      constructor);
+  assertArrayLikeEquals(Array.from.call(thisArg, NaN), [], constructor);
+  assertArrayLikeEquals(Array.from.call(thisArg, Infinity), [], constructor);
+  assertArrayLikeEquals(Array.from.call(thisArg, 10000000), [], constructor);
+  assertArrayLikeEquals(Array.from.call(thisArg, 'test'), ['t', 'e', 's', 't'],
+      constructor);
+
+  assertArrayLikeEquals(Array.from.call(thisArg,
+      { length: 1, '0': { 'foo': 'bar' } }), [{'foo': 'bar'}], constructor);
+
+  assertArrayLikeEquals(Array.from.call(thisArg,
+      { length: -1, '0': { 'foo': 'bar' } }), [], constructor);
+
+  assertArrayLikeEquals(Array.from.call(thisArg,
+      [ 'foo', 'bar', 'baz' ]), ['foo', 'bar', 'baz'], constructor);
+
+  var kSet = new Set(['foo', 'bar', 'baz']);
+  assertArrayLikeEquals(Array.from.call(thisArg, kSet), ['foo', 'bar', 'baz'],
+      constructor);
+
+  var kMap = new Map(['foo', 'bar', 'baz'].entries());
+  assertArrayLikeEquals(Array.from.call(thisArg, kMap),
+      [[0, 'foo'], [1, 'bar'], [2, 'baz']], constructor);
+
+
+  function* generator() {
+    yield 'a';
+    yield 'b';
+    yield 'c';
+  }
+
+  assertArrayLikeEquals(Array.from.call(thisArg, generator()),
+                        ['a', 'b', 'c'], constructor);
+
+  // Mozilla:
+  // Array.from on a string handles surrogate pairs correctly.
+  var gclef = "\uD834\uDD1E"; // U+1D11E MUSICAL SYMBOL G CLEF
+  assertArrayLikeEquals(Array.from.call(thisArg, gclef), [gclef], constructor);
+  assertArrayLikeEquals(Array.from.call(thisArg, gclef + " G"),
+      [gclef, " ", "G"], constructor);
+
+  assertArrayLikeEquals(Array.from.call(thisArg, 'test', function(x) {
+    return this.filter(x);
+  }, {
+    filter: function(x) { return x.toUpperCase(); }
+  }), ['T', 'E', 'S', 'T'], constructor);
+  assertArrayLikeEquals(Array.from.call(thisArg, 'test', function(x) {
+    return x.toUpperCase();
+  }), ['T', 'E', 'S', 'T'], constructor);
+
+  this.thisArg = thisArg;
+  assertThrows('Array.from.call(thisArg, null)', TypeError);
+  assertThrows('Array.from.call(thisArg, undefined)', TypeError);
+  assertThrows('Array.from.call(thisArg, [], null)', TypeError);
+  assertThrows('Array.from.call(thisArg, [], "noncallable")', TypeError);
+
+  this.nullIterator = {};
+  nullIterator[Symbol.iterator] = null;
+  assertThrows('Array.from.call(thisArg, nullIterator)', TypeError);
+
+  this.nonObjIterator = {};
+  nonObjIterator[Symbol.iterator] = function() { return "nonObject"; };
+  assertThrows('Array.from.call(thisArg, nonObjIterator)', TypeError);
+
+  assertThrows('Array.from.call(thisArg, [], null)', TypeError);
+}
+
+function Other() {}
+
+var boundFn = (function() {}).bind(Array, 27);
+
+testArrayFrom(Array, Array);
+testArrayFrom(null, Array);
+testArrayFrom({}, Array);
+testArrayFrom(Object, Object);
+testArrayFrom(Other, Other);
+testArrayFrom(Math.cos, Array);
+testArrayFrom(boundFn, Array);
+
+})();
diff --git a/test/mjsunit/harmony/array-includes-to-object-sloppy.js b/test/mjsunit/harmony/array-includes-to-object-sloppy.js
new file mode 100644
index 0000000..0f5d731
--- /dev/null
+++ b/test/mjsunit/harmony/array-includes-to-object-sloppy.js
@@ -0,0 +1,29 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-array-includes
+
+// Ported from
+// https://github.com/tc39/Array.prototype.includes/blob/master/test/number-this.js
+// using https://www.npmjs.org/package/test262-to-mjsunit
+
+// Array.prototype.includes should use ToObject on this, so that when called
+// with a number, it picks up numeric properties from Number.prototype
+(function() {
+  Number.prototype[0] = "a";
+  Number.prototype[1] = "b";
+
+  Object.defineProperty(Number.prototype, 2, {
+    get: function() {
+      assertEquals("object", typeof this);
+      return "c";
+    }
+  });
+
+  Number.prototype.length = 3;
+  assertTrue(Array.prototype.includes.call(5, "a"));
+  assertTrue(Array.prototype.includes.call(5, "b"));
+  assertTrue(Array.prototype.includes.call(5, "c"));
+  assertFalse(Array.prototype.includes.call(5, "d"));
+})();
diff --git a/test/mjsunit/harmony/array-includes-to-object-strict.js b/test/mjsunit/harmony/array-includes-to-object-strict.js
new file mode 100644
index 0000000..ee87136
--- /dev/null
+++ b/test/mjsunit/harmony/array-includes-to-object-strict.js
@@ -0,0 +1,32 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-array-includes
+
+// Ported from
+// https://github.com/tc39/Array.prototype.includes/blob/master/test/number-this.js
+// using https://www.npmjs.org/package/test262-to-mjsunit
+
+// Array.prototype.includes should use ToObject on this, so that when called
+// with a number, it picks up numeric properties from Number.prototype (even in
+// strict mode)
+(function() {
+  "use strict";
+
+  Number.prototype[0] = "a";
+  Number.prototype[1] = "b";
+
+  Object.defineProperty(Number.prototype, 2, {
+    get: function() {
+      assertEquals("object", typeof this);
+      return "c";
+    }
+  });
+
+  Number.prototype.length = 3;
+  assertTrue(Array.prototype.includes.call(5, "a"));
+  assertTrue(Array.prototype.includes.call(5, "b"));
+  assertTrue(Array.prototype.includes.call(5, "c"));
+  assertFalse(Array.prototype.includes.call(5, "d"));
+})();
diff --git a/test/mjsunit/harmony/array-includes.js b/test/mjsunit/harmony/array-includes.js
new file mode 100644
index 0000000..2cdd112
--- /dev/null
+++ b/test/mjsunit/harmony/array-includes.js
@@ -0,0 +1,677 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-array-includes
+
+// Largely ported from
+// https://github.com/tc39/Array.prototype.includes/tree/master/test
+// using https://www.npmjs.org/package/test262-to-mjsunit with further edits
+
+
+// Array.prototype.includes sees a new element added by a getter that is hit
+// during iteration
+(function() {
+  var arrayLike = {
+    length: 5,
+    0: "a",
+
+    get 1() {
+      this[2] = "c";
+      return "b";
+    }
+  };
+
+  assertTrue(Array.prototype.includes.call(arrayLike, "c"));
+})();
+
+
+// Array.prototype.includes works on array-like objects
+(function() {
+  var arrayLike1 = {
+    length: 5,
+    0: "a",
+    1: "b"
+  };
+
+  assertTrue(Array.prototype.includes.call(arrayLike1, "a"));
+  assertFalse(Array.prototype.includes.call(arrayLike1, "c"));
+
+  var arrayLike2 = {
+    length: 2,
+    0: "a",
+    1: "b",
+    2: "c"
+  };
+
+  assertTrue(Array.prototype.includes.call(arrayLike2, "b"));
+  assertFalse(Array.prototype.includes.call(arrayLike2, "c"));
+})();
+
+
+// Array.prototype.includes should fail if used on a null or undefined this
+(function() {
+  assertThrows(function() {
+    Array.prototype.includes.call(null, "a");
+  }, TypeError);
+
+  assertThrows(function() {
+    Array.prototype.includes.call(undefined, "a");
+  }, TypeError);
+})();
+
+
+// Array.prototype.includes should terminate if getting an index throws an
+// exception
+(function() {
+  function Test262Error() {}
+
+  var trappedZero = {
+    length: 2,
+
+    get 0() {
+      throw new Test262Error();
+    },
+
+    get 1() {
+      assertUnreachable("Should not try to get the first element");
+    }
+  };
+
+  assertThrows(function() {
+    Array.prototype.includes.call(trappedZero, "a");
+  }, Test262Error);
+})();
+
+
+// Array.prototype.includes should terminate if ToNumber ends up being called on
+// a symbol fromIndex
+(function() {
+  var trappedZero = {
+    length: 1,
+
+    get 0() {
+      assertUnreachable("Should not try to get the zeroth element");
+    }
+  };
+
+  assertThrows(function() {
+    Array.prototype.includes.call(trappedZero, "a", Symbol());
+  }, TypeError);
+})();
+
+
+// Array.prototype.includes should terminate if an exception occurs converting
+// the fromIndex to a number
+(function() {
+  function Test262Error() {}
+
+  var fromIndex = {
+    valueOf: function() {
+      throw new Test262Error();
+    }
+  };
+
+  var trappedZero = {
+    length: 1,
+
+    get 0() {
+      assertUnreachable("Should not try to get the zeroth element");
+    }
+  };
+
+  assertThrows(function() {
+    Array.prototype.includes.call(trappedZero, "a", fromIndex);
+  }, Test262Error);
+})();
+
+
+// Array.prototype.includes should terminate if an exception occurs getting the
+// length
+(function() {
+  function Test262Error() {}
+
+  var fromIndexTrap = {
+    valueOf: function() {
+      assertUnreachable("Should not try to call ToInteger on valueOf");
+    }
+  };
+
+  var throwingLength = {
+    get length() {
+      throw new Test262Error();
+    },
+
+    get 0() {
+      assertUnreachable("Should not try to get the zeroth element");
+    }
+  };
+
+  assertThrows(function() {
+    Array.prototype.includes.call(throwingLength, "a", fromIndexTrap);
+  }, Test262Error);
+})();
+
+
+// Array.prototype.includes should terminate if ToLength ends up being called on
+// a symbol length
+(function() {
+  var fromIndexTrap = {
+    valueOf: function() {
+      assertUnreachable("Should not try to call ToInteger on valueOf");
+    }
+  };
+
+  var badLength = {
+    length: Symbol(),
+
+    get 0() {
+      assertUnreachable("Should not try to get the zeroth element");
+    }
+  };
+
+  assertThrows(function() {
+    Array.prototype.includes.call(badLength, "a", fromIndexTrap);
+  }, TypeError);
+})();
+
+
+// Array.prototype.includes should terminate if an exception occurs converting
+// the length to a number
+(function() {
+  function Test262Error() {}
+
+  var fromIndexTrap = {
+    valueOf: function() {
+      assertUnreachable("Should not try to call ToInteger on valueOf");
+    }
+  };
+
+  var badLength = {
+    length: {
+      valueOf: function() {
+        throw new Test262Error();
+      }
+    },
+
+    get 0() {
+      assertUnreachable("Should not try to get the zeroth element");
+    }
+  };
+
+  assertThrows(function() {
+    Array.prototype.includes.call(badLength, "a", fromIndexTrap);
+  }, Test262Error);
+})();
+
+
+// Array.prototype.includes should search the whole array, as the optional
+// second argument fromIndex defaults to 0
+(function() {
+  assertTrue([10, 11].includes(10));
+  assertTrue([10, 11].includes(11));
+
+  var arrayLike = {
+    length: 2,
+
+    get 0() {
+      return "1";
+    },
+
+    get 1() {
+      return "2";
+    }
+  };
+
+  assertTrue(Array.prototype.includes.call(arrayLike, "1"));
+  assertTrue(Array.prototype.includes.call(arrayLike, "2"));
+})();
+
+
+// Array.prototype.includes returns false if fromIndex is greater or equal to
+// the length of the array
+(function() {
+  assertFalse([1, 2].includes(2, 3));
+  assertFalse([1, 2].includes(2, 2));
+
+  var arrayLikeWithTrap = {
+    length: 2,
+
+    get 0() {
+      assertUnreachable("Getter for 0 was called");
+    },
+
+    get 1() {
+      assertUnreachable("Getter for 1 was called");
+    }
+  };
+
+  assertFalse(Array.prototype.includes.call(arrayLikeWithTrap, "c", 2));
+  assertFalse(Array.prototype.includes.call(arrayLikeWithTrap, "c", 3));
+})();
+
+
+// Array.prototype.includes searches the whole array if the computed index from
+// the given negative fromIndex argument is less than 0
+(function() {
+  assertTrue([1, 3].includes(1, -4));
+  assertTrue([1, 3].includes(3, -4));
+
+  var arrayLike = {
+    length: 2,
+    0: "a",
+
+    get 1() {
+      return "b";
+    },
+
+    get "-1"() {
+      assertUnreachable("Should not try to get the element at index -1");
+    }
+  };
+
+  assertTrue(Array.prototype.includes.call(arrayLike, "a", -4));
+  assertTrue(Array.prototype.includes.call(arrayLike, "b", -4));
+})();
+
+
+// Array.prototype.includes should use a negative value as the offset from the
+// end of the array to compute fromIndex
+(function() {
+  assertTrue([12, 13].includes(13, -1));
+  assertFalse([12, 13].includes(12, -1));
+  assertTrue([12, 13].includes(12, -2));
+
+  var arrayLike = {
+    length: 2,
+
+    get 0() {
+      return "a";
+    },
+
+    get 1() {
+      return "b";
+    }
+  };
+
+  assertTrue(Array.prototype.includes.call(arrayLike, "b", -1));
+  assertFalse(Array.prototype.includes.call(arrayLike, "a", -1));
+  assertTrue(Array.prototype.includes.call(arrayLike, "a", -2));
+})();
+
+
+// Array.prototype.includes converts its fromIndex parameter to an integer
+(function() {
+  assertFalse(["a", "b"].includes("a", 2.3));
+
+  var arrayLikeWithTraps = {
+    length: 2,
+
+    get 0() {
+      assertUnreachable("Getter for 0 was called");
+    },
+
+    get 1() {
+      assertUnreachable("Getter for 1 was called");
+    }
+  };
+
+  assertFalse(Array.prototype.includes.call(arrayLikeWithTraps, "c", 2.1));
+  assertFalse(Array.prototype.includes.call(arrayLikeWithTraps, "c", +Infinity));
+  assertTrue(["a", "b", "c"].includes("a", -Infinity));
+  assertTrue(["a", "b", "c"].includes("c", 2.9));
+  assertTrue(["a", "b", "c"].includes("c", NaN));
+
+  var arrayLikeWithTrapAfterZero = {
+    length: 2,
+
+    get 0() {
+      return "a";
+    },
+
+    get 1() {
+      assertUnreachable("Getter for 1 was called");
+    }
+  };
+
+  assertTrue(Array.prototype.includes.call(arrayLikeWithTrapAfterZero, "a", NaN));
+
+  var numberLike = {
+    valueOf: function() {
+      return 2;
+    }
+  };
+
+  assertFalse(["a", "b", "c"].includes("a", numberLike));
+  assertFalse(["a", "b", "c"].includes("a", "2"));
+  assertTrue(["a", "b", "c"].includes("c", numberLike));
+  assertTrue(["a", "b", "c"].includes("c", "2"));
+})();
+
+
+// Array.prototype.includes should have length 1
+(function() {
+  assertEquals(1, Array.prototype.includes.length);
+})();
+
+
+// Array.prototype.includes should have name property with value 'includes'
+(function() {
+  assertEquals("includes", Array.prototype.includes.name);
+})();
+
+
+// !!! Test failed to convert:
+// Cannot convert tests with includes.
+// !!!
+
+
+// Array.prototype.includes does not skip holes; if the array has a prototype it
+// gets from that
+(function() {
+  var holesEverywhere = [,,,];
+
+  holesEverywhere.__proto__ = {
+    1: "a"
+  };
+
+  holesEverywhere.__proto__.__proto__ = Array.prototype;
+  assertTrue(holesEverywhere.includes("a"));
+  var oneHole = ["a", "b",, "d"];
+
+  oneHole.__proto__ = {
+    get 2() {
+      return "c";
+    }
+  };
+
+  assertTrue(Array.prototype.includes.call(oneHole, "c"));
+})();
+
+
+// Array.prototype.includes does not skip holes; instead it treates them as
+// undefined
+(function() {
+  assertTrue([,,,].includes(undefined));
+  assertTrue(["a", "b",, "d"].includes(undefined));
+})();
+
+
+// Array.prototype.includes gets length property from the prototype if it's
+// available
+(function() {
+  var proto = {
+    length: 1
+  };
+
+  var arrayLike = Object.create(proto);
+  arrayLike[0] = "a";
+
+  Object.defineProperty(arrayLike, "1", {
+    get: function() {
+      assertUnreachable("Getter for 1 was called");
+    }
+  });
+
+  assertTrue(Array.prototype.includes.call(arrayLike, "a"));
+})();
+
+
+// Array.prototype.includes treats a missing length property as zero
+(function() {
+  var arrayLikeWithTraps = {
+    get 0() {
+      assertUnreachable("Getter for 0 was called");
+    },
+
+    get 1() {
+      assertUnreachable("Getter for 1 was called");
+    }
+  };
+
+  assertFalse(Array.prototype.includes.call(arrayLikeWithTraps, "a"));
+})();
+
+
+// Array.prototype.includes should always return false on negative-length
+// objects
+(function() {
+  assertFalse(Array.prototype.includes.call({
+    length: -1
+  }, 2));
+
+  assertFalse(Array.prototype.includes.call({
+    length: -2
+  }));
+
+  assertFalse(Array.prototype.includes.call({
+    length: -Infinity
+  }, undefined));
+
+  assertFalse(Array.prototype.includes.call({
+    length: -Math.pow(2, 53)
+  }, NaN));
+
+  assertFalse(Array.prototype.includes.call({
+    length: -1,
+    "-1": 2
+  }, 2));
+
+  assertFalse(Array.prototype.includes.call({
+    length: -3,
+    "-1": 2
+  }, 2));
+
+  assertFalse(Array.prototype.includes.call({
+    length: -Infinity,
+    "-1": 2
+  }, 2));
+
+  var arrayLikeWithTrap = {
+    length: -1,
+
+    get 0() {
+      assertUnreachable("Getter for 0 was called");
+    }
+  };
+
+  assertFalse(Array.prototype.includes.call(arrayLikeWithTrap, 2));
+})();
+
+
+// Array.prototype.includes should clamp positive lengths to 2^53 - 1
+(function() {
+  var fromIndexForLargeIndexTests = 9007199254740990;
+
+  assertFalse(Array.prototype.includes.call({
+    length: 1
+  }, 2));
+
+  assertTrue(Array.prototype.includes.call({
+    length: 1,
+    0: "a"
+  }, "a"));
+
+  assertTrue(Array.prototype.includes.call({
+    length: +Infinity,
+    0: "a"
+  }, "a"));
+
+  assertFalse(Array.prototype.includes.call({
+    length: +Infinity
+  }, "a", fromIndexForLargeIndexTests));
+
+  var arrayLikeWithTrap = {
+    length: +Infinity,
+
+    get 9007199254740992() {
+      assertUnreachable("Getter for 9007199254740992 (i.e. 2^53) was called");
+    },
+
+    "9007199254740993": "a"
+  };
+
+  assertFalse(
+    Array.prototype.includes.call(arrayLikeWithTrap, "a", fromIndexForLargeIndexTests)
+  );
+
+  var arrayLikeWithTooBigLength = {
+    length: 9007199254740996,
+    "9007199254740992": "a"
+  };
+
+  assertFalse(
+    Array.prototype.includes.call(arrayLikeWithTooBigLength, "a", fromIndexForLargeIndexTests)
+  );
+})();
+
+
+// Array.prototype.includes should always return false on zero-length objects
+(function() {
+  assertFalse([].includes(2));
+  assertFalse([].includes());
+  assertFalse([].includes(undefined));
+  assertFalse([].includes(NaN));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0
+  }, 2));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0
+  }));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0
+  }, undefined));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0
+  }, NaN));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0,
+    0: 2
+  }, 2));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0,
+    0: undefined
+  }));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0,
+    0: undefined
+  }, undefined));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0,
+    0: NaN
+  }, NaN));
+
+  var arrayLikeWithTrap = {
+    length: 0,
+
+    get 0() {
+      assertUnreachable("Getter for 0 was called");
+    }
+  };
+
+  Array.prototype.includes.call(arrayLikeWithTrap);
+
+  var trappedFromIndex = {
+    valueOf: function() {
+      assertUnreachable("Should not try to convert fromIndex to a number on a zero-length array");
+    }
+  };
+
+  [].includes("a", trappedFromIndex);
+
+  Array.prototype.includes.call({
+    length: 0
+  }, trappedFromIndex);
+})();
+
+
+// Array.prototype.includes works on objects
+(function() {
+  assertFalse(["a", "b", "c"].includes({}));
+  assertFalse([{}, {}].includes({}));
+  var obj = {};
+  assertTrue([obj].includes(obj));
+  assertFalse([obj].includes(obj, 1));
+  assertTrue([obj, obj].includes(obj, 1));
+
+  var stringyObject = {
+    toString: function() {
+      return "a";
+    }
+  };
+
+  assertFalse(["a", "b", obj].includes(stringyObject));
+})();
+
+
+// Array.prototype.includes does not see an element removed by a getter that is
+// hit during iteration
+(function() {
+  var arrayLike = {
+    length: 5,
+    0: "a",
+
+    get 1() {
+      delete this[2];
+      return "b";
+    },
+
+    2: "c"
+  };
+
+  assertFalse(Array.prototype.includes.call(arrayLike, "c"));
+})();
+
+
+// Array.prototype.includes should use the SameValueZero algorithm to compare
+(function() {
+  assertTrue([1, 2, 3].includes(2));
+  assertFalse([1, 2, 3].includes(4));
+  assertTrue([1, 2, NaN].includes(NaN));
+  assertTrue([1, 2, -0].includes(+0));
+  assertTrue([1, 2, -0].includes(-0));
+  assertTrue([1, 2, +0].includes(-0));
+  assertTrue([1, 2, +0].includes(+0));
+  assertFalse([1, 2, -Infinity].includes(+Infinity));
+  assertTrue([1, 2, -Infinity].includes(-Infinity));
+  assertFalse([1, 2, +Infinity].includes(-Infinity));
+  assertTrue([1, 2, +Infinity].includes(+Infinity));
+})();
+
+
+// Array.prototype.includes stops once it hits the length of an array-like, even
+// if there are more after
+(function() {
+  var arrayLike = {
+    length: 2,
+    0: "a",
+    1: "b",
+
+    get 2() {
+      assertUnreachable("Should not try to get the second element");
+    }
+  };
+
+  assertFalse(Array.prototype.includes.call(arrayLike, "c"));
+})();
+
+
+// Array.prototype.includes works on typed arrays
+(function() {
+  assertTrue(Array.prototype.includes.call(new Uint8Array([1, 2, 3]), 2));
+
+  assertTrue(
+    Array.prototype.includes.call(new Float32Array([2.5, 3.14, Math.PI]), 3.1415927410125732)
+  );
+
+  assertFalse(Array.prototype.includes.call(new Uint8Array([1, 2, 3]), 4));
+  assertFalse(Array.prototype.includes.call(new Uint8Array([1, 2, 3]), 2, 2));
+})();
diff --git a/test/mjsunit/harmony/block-conflicts.js b/test/mjsunit/harmony/block-conflicts.js
index 1eedb68..d19a34a 100644
--- a/test/mjsunit/harmony/block-conflicts.js
+++ b/test/mjsunit/harmony/block-conflicts.js
@@ -1,30 +1,7 @@
 // Copyright 2011 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 //
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
 // Flags: --harmony-scoping
 
 // Test for conflicting variable bindings.
@@ -175,7 +152,7 @@
 
 // Test conflicting catch/var bindings.
 for (var v = 0; v < varbinds.length; ++v) {
-  TestConflict('try {} catch(x) {' + varbinds[v] + '}');
+  TestNoConflict('try {} catch(x) {' + varbinds[v] + '}');
 }
 
 // Test conflicting parameter/var bindings.
diff --git a/test/mjsunit/harmony/block-const-assign.js b/test/mjsunit/harmony/block-const-assign.js
index b71729e..c21a0a3 100644
--- a/test/mjsunit/harmony/block-const-assign.js
+++ b/test/mjsunit/harmony/block-const-assign.js
@@ -35,61 +35,61 @@
 
 // Function local const.
 function constDecl0(use) {
-  return "(function() { const constvar = 1; " + use + "; });";
+  return "(function() { const constvar = 1; " + use + "; })();";
 }
 
 
 function constDecl1(use) {
-  return "(function() { " + use + "; const constvar = 1; });";
+  return "(function() { " + use + "; const constvar = 1; })();";
 }
 
 
 // Function local const, assign from eval.
 function constDecl2(use) {
-  use = "eval('(function() { " + use + " })')";
+  use = "eval('(function() { " + use + " })')()";
   return "(function() { const constvar = 1; " + use + "; })();";
 }
 
 
 function constDecl3(use) {
-  use = "eval('(function() { " + use + " })')";
+  use = "eval('(function() { " + use + " })')()";
   return "(function() { " + use + "; const constvar = 1; })();";
 }
 
 
 // Block local const.
 function constDecl4(use) {
-  return "(function() { { const constvar = 1; " + use + "; } });";
+  return "(function() { { const constvar = 1; " + use + "; } })();";
 }
 
 
 function constDecl5(use) {
-  return "(function() { { " + use + "; const constvar = 1; } });";
+  return "(function() { { " + use + "; const constvar = 1; } })();";
 }
 
 
 // Block local const, assign from eval.
 function constDecl6(use) {
-  use = "eval('(function() {" + use + "})')";
+  use = "eval('(function() {" + use + "})')()";
   return "(function() { { const constvar = 1; " + use + "; } })();";
 }
 
 
 function constDecl7(use) {
-  use = "eval('(function() {" + use + "})')";
+  use = "eval('(function() {" + use + "})')()";
   return "(function() { { " + use + "; const constvar = 1; } })();";
 }
 
 
 // Function expression name.
 function constDecl8(use) {
-  return "(function constvar() { " + use + "; });";
+  return "(function constvar() { " + use + "; })();";
 }
 
 
 // Function expression name, assign from eval.
 function constDecl9(use) {
-  use = "eval('(function(){" + use + "})')";
+  use = "eval('(function(){" + use + "})')()";
   return "(function constvar() { " + use + "; })();";
 }
 
@@ -104,6 +104,7 @@
               constDecl8,
               constDecl9
               ];
+let declsForTDZ = new Set([constDecl1, constDecl3, constDecl5, constDecl7]);
 let uses = [ 'constvar = 1;',
              'constvar += 1;',
              '++constvar;',
@@ -116,7 +117,13 @@
     print(d(u));
     eval(d(u));
   } catch (e) {
-    assertInstanceof(e, SyntaxError);
+    if (declsForTDZ.has(d) && u !== uses[0]) {
+      // In these cases, read of a const variable occurs
+      // before a write to it, so TDZ kicks in before const check.
+      assertInstanceof(e, ReferenceError);
+      return;
+    }
+    assertInstanceof(e, TypeError);
     assertTrue(e.toString().indexOf("Assignment to constant variable") >= 0);
     return;
   }
diff --git a/test/mjsunit/harmony/block-non-strict-errors.js b/test/mjsunit/harmony/block-non-strict-errors.js
new file mode 100644
index 0000000..11fa5c6
--- /dev/null
+++ b/test/mjsunit/harmony/block-non-strict-errors.js
@@ -0,0 +1,41 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-scoping --harmony-classes
+
+function CheckError(source) {
+  var exception = null;
+  try {
+    eval(source);
+  } catch (e) {
+    exception = e;
+  }
+  assertNotNull(exception);
+  assertEquals(
+      "Block-scoped declarations (let, const, function, class) not yet supported outside strict mode",
+      exception.message);
+}
+
+
+function CheckOk(source) {
+  eval(source);
+}
+
+CheckError("let x = 1;");
+CheckError("{ let x = 1; }");
+CheckError("function f() { let x = 1; }");
+CheckError("for (let x = 1; x < 1; x++) {}");
+CheckError("for (let x of []) {}");
+CheckError("for (let x in []) {}");
+CheckError("class C {}");
+CheckError("class C extends Array {}");
+CheckError("(class {});");
+CheckError("(class extends Array {});");
+CheckError("(class C {});");
+CheckError("(class C exends Array {});");
+
+CheckOk("let = 1;");
+CheckOk("{ let = 1; }");
+CheckOk("function f() { let = 1; }");
+CheckOk("for (let = 1; let < 1; let++) {}");
diff --git a/test/mjsunit/harmony/classes.js b/test/mjsunit/harmony/classes.js
new file mode 100644
index 0000000..29ffbf8
--- /dev/null
+++ b/test/mjsunit/harmony/classes.js
@@ -0,0 +1,879 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-classes --harmony-sloppy
+
+(function TestBasics() {
+  var C = class C {}
+  assertEquals(typeof C, 'function');
+  assertEquals(C.__proto__, Function.prototype);
+  assertEquals(Object.prototype, Object.getPrototypeOf(C.prototype));
+  assertEquals(Function.prototype, Object.getPrototypeOf(C));
+  assertEquals('C', C.name);
+
+  class D {}
+  assertEquals(typeof D, 'function');
+  assertEquals(D.__proto__, Function.prototype);
+  assertEquals(Object.prototype, Object.getPrototypeOf(D.prototype));
+  assertEquals(Function.prototype, Object.getPrototypeOf(D));
+  assertEquals('D', D.name);
+
+  class D2 { constructor() {} }
+  assertEquals('D2', D2.name);
+
+  // TODO(arv): The logic for the name of anonymous functions in ES6 requires
+  // the below to be 'E';
+  var E = class {}
+  assertEquals('', E.name);  // Should be 'E'.
+
+  var F = class { constructor() {} };
+  assertEquals('', F.name);  // Should be 'F'.
+})();
+
+
+(function TestBasicsExtends() {
+  class C extends null {}
+  assertEquals(typeof C, 'function');
+  assertEquals(C.__proto__, Function.prototype);
+  assertEquals(null, Object.getPrototypeOf(C.prototype));
+
+  class D extends C {}
+  assertEquals(typeof D, 'function');
+  assertEquals(D.__proto__, C);
+  assertEquals(C.prototype, Object.getPrototypeOf(D.prototype));
+})();
+
+
+(function TestSideEffectInExtends() {
+  var calls = 0;
+  class C {}
+  class D extends (calls++, C) {}
+  assertEquals(1, calls);
+  assertEquals(typeof D, 'function');
+  assertEquals(D.__proto__, C);
+  assertEquals(C.prototype, Object.getPrototypeOf(D.prototype));
+})();
+
+
+(function TestInvalidExtends() {
+  assertThrows(function() {
+    class C extends 42 {}
+  }, TypeError);
+
+  assertThrows(function() {
+    // Function but its .prototype is not null or a function.
+    class C extends Math.abs {}
+  }, TypeError);
+
+  assertThrows(function() {
+    Math.abs.prototype = 42;
+    class C extends Math.abs {}
+  }, TypeError);
+  delete Math.abs.prototype;
+})();
+
+
+(function TestConstructorProperty() {
+  class C {}
+  assertEquals(C, C.prototype.constructor);
+  var descr = Object.getOwnPropertyDescriptor(C.prototype, 'constructor');
+  assertTrue(descr.configurable);
+  assertFalse(descr.enumerable);
+  assertTrue(descr.writable);
+})();
+
+
+(function TestPrototypeProperty() {
+  class C {}
+  var descr = Object.getOwnPropertyDescriptor(C, 'prototype');
+  assertFalse(descr.configurable);
+  assertFalse(descr.enumerable);
+  assertFalse(descr.writable);
+})();
+
+
+(function TestConstructor() {
+  var count = 0;
+  class C {
+    constructor() {
+      assertEquals(Object.getPrototypeOf(this), C.prototype);
+      count++;
+    }
+  }
+  assertEquals(C, C.prototype.constructor);
+  var descr = Object.getOwnPropertyDescriptor(C.prototype, 'constructor');
+  assertTrue(descr.configurable);
+  assertFalse(descr.enumerable);
+  assertTrue(descr.writable);
+
+  var c = new C();
+  assertEquals(1, count);
+  assertEquals(Object.getPrototypeOf(c), C.prototype);
+})();
+
+
+(function TestImplicitConstructor() {
+  class C {}
+  var c = new C();
+  assertEquals(Object.getPrototypeOf(c), C.prototype);
+})();
+
+
+(function TestConstructorStrict() {
+  class C {
+    constructor() {
+      assertThrows(function() {
+        nonExistingBinding = 42;
+      }, ReferenceError);
+    }
+  }
+  new C();
+})();
+
+
+(function TestSuperInConstructor() {
+  var calls = 0;
+  class B {}
+  B.prototype.x = 42;
+
+  class C extends B {
+    constructor() {
+      calls++;
+      assertEquals(42, super.x);
+    }
+  }
+
+  new C;
+  assertEquals(1, calls);
+})();
+
+
+(function TestStrictMode() {
+  class C {}
+
+  with ({a: 1}) {
+    assertEquals(1, a);
+  }
+
+  assertThrows('class C extends function B() { with ({}); return B; }() {}',
+               SyntaxError);
+
+  var D = class extends function() {
+    arguments.caller;
+  } {};
+  assertThrows(function() {
+    Object.getPrototypeOf(D).arguments;
+  }, TypeError);
+  assertThrows(function() {
+    new D;
+  }, TypeError);
+})();
+
+
+(function TestToString() {
+  class C {}
+  assertEquals('class C {}', C.toString());
+
+  class D { constructor() { 42; } }
+  assertEquals('class D { constructor() { 42; } }', D.toString());
+
+  class E { x() { 42; } }
+  assertEquals('class E { x() { 42; } }', E.toString());
+})();
+
+
+function assertMethodDescriptor(object, name) {
+  var descr = Object.getOwnPropertyDescriptor(object, name);
+  assertTrue(descr.configurable);
+  assertTrue(descr.enumerable);
+  assertTrue(descr.writable);
+  assertEquals('function', typeof descr.value);
+  assertFalse('prototype' in descr.value);
+}
+
+
+function assertGetterDescriptor(object, name) {
+  var descr = Object.getOwnPropertyDescriptor(object, name);
+  assertTrue(descr.configurable);
+  assertTrue(descr.enumerable);
+  assertEquals('function', typeof descr.get);
+  assertEquals(undefined, descr.set);
+}
+
+
+function assertSetterDescriptor(object, name) {
+  var descr = Object.getOwnPropertyDescriptor(object, name);
+  assertTrue(descr.configurable);
+  assertTrue(descr.enumerable);
+  assertEquals(undefined, descr.get);
+  assertEquals('function', typeof descr.set);
+}
+
+
+function assertAccessorDescriptor(object, name) {
+  var descr = Object.getOwnPropertyDescriptor(object, name);
+  assertTrue(descr.configurable);
+  assertTrue(descr.enumerable);
+  assertEquals('function', typeof descr.get);
+  assertEquals('function', typeof descr.set);
+}
+
+
+(function TestMethods() {
+  class C {
+    method() { return 1; }
+    static staticMethod() { return 2; }
+    method2() { return 3; }
+    static staticMethod2() { return 4; }
+  }
+
+  assertMethodDescriptor(C.prototype, 'method');
+  assertMethodDescriptor(C.prototype, 'method2');
+  assertMethodDescriptor(C, 'staticMethod');
+  assertMethodDescriptor(C, 'staticMethod2');
+
+  assertEquals(1, new C().method());
+  assertEquals(2, C.staticMethod());
+  assertEquals(3, new C().method2());
+  assertEquals(4, C.staticMethod2());
+})();
+
+
+(function TestGetters() {
+  class C {
+    get x() { return 1; }
+    static get staticX() { return 2; }
+    get y() { return 3; }
+    static get staticY() { return 4; }
+  }
+
+  assertGetterDescriptor(C.prototype, 'x');
+  assertGetterDescriptor(C.prototype, 'y');
+  assertGetterDescriptor(C, 'staticX');
+  assertGetterDescriptor(C, 'staticY');
+
+  assertEquals(1, new C().x);
+  assertEquals(2, C.staticX);
+  assertEquals(3, new C().y);
+  assertEquals(4, C.staticY);
+})();
+
+
+
+(function TestSetters() {
+  var x, staticX, y, staticY;
+  class C {
+    set x(v) { x = v; }
+    static set staticX(v) { staticX = v; }
+    set y(v) { y = v; }
+    static set staticY(v) { staticY = v; }
+  }
+
+  assertSetterDescriptor(C.prototype, 'x');
+  assertSetterDescriptor(C.prototype, 'y');
+  assertSetterDescriptor(C, 'staticX');
+  assertSetterDescriptor(C, 'staticY');
+
+  assertEquals(1, new C().x = 1);
+  assertEquals(1, x);
+  assertEquals(2, C.staticX = 2);
+  assertEquals(2, staticX);
+  assertEquals(3, new C().y = 3);
+  assertEquals(3, y);
+  assertEquals(4, C.staticY = 4);
+  assertEquals(4, staticY);
+})();
+
+
+(function TestSideEffectsInPropertyDefine() {
+  function B() {}
+  B.prototype = {
+    constructor: B,
+    set m(v) {
+      throw Error();
+    }
+  };
+
+  class C extends B {
+    m() { return 1; }
+  }
+
+  assertEquals(1, new C().m());
+})();
+
+
+(function TestAccessors() {
+  class C {
+    constructor(x) {
+      this._x = x;
+    }
+
+    get x() { return this._x; }
+    set x(v) { this._x = v; }
+
+    static get staticX() { return this._x; }
+    static set staticX(v) { this._x = v; }
+  }
+
+  assertAccessorDescriptor(C.prototype, 'x');
+  assertAccessorDescriptor(C, 'staticX');
+
+  var c = new C(1);
+  c._x = 1;
+  assertEquals(1, c.x);
+  c.x = 2;
+  assertEquals(2, c._x);
+
+  C._x = 3;
+  assertEquals(3, C.staticX);
+  C._x = 4;
+  assertEquals(4, C.staticX );
+})();
+
+
+(function TestProto() {
+  class C {
+    __proto__() { return 1; }
+  }
+  assertMethodDescriptor(C.prototype, '__proto__');
+  assertEquals(1, new C().__proto__());
+})();
+
+
+(function TestProtoStatic() {
+  class C {
+    static __proto__() { return 1; }
+  }
+  assertMethodDescriptor(C, '__proto__');
+  assertEquals(1, C.__proto__());
+})();
+
+
+(function TestProtoAccessor() {
+  class C {
+    get __proto__() { return this._p; }
+    set __proto__(v) { this._p = v; }
+  }
+  assertAccessorDescriptor(C.prototype, '__proto__');
+  var c = new C();
+  c._p = 1;
+  assertEquals(1, c.__proto__);
+  c.__proto__ = 2;
+  assertEquals(2, c.__proto__);
+})();
+
+
+(function TestStaticProtoAccessor() {
+  class C {
+    static get __proto__() { return this._p; }
+    static set __proto__(v) { this._p = v; }
+  }
+  assertAccessorDescriptor(C, '__proto__');
+  C._p = 1;
+  assertEquals(1, C.__proto__);
+  C.__proto__ = 2;
+  assertEquals(2, C.__proto__);
+})();
+
+
+(function TestSettersOnProto() {
+  function Base() {}
+  Base.prototype = {
+    set constructor(_) {
+      assertUnreachable();
+    },
+    set m(_) {
+      assertUnreachable();
+    }
+  };
+  Object.defineProperty(Base, 'staticM', {
+    set: function() {
+      assertUnreachable();
+    }
+  });
+
+  class C extends Base {
+    m() {
+      return 1;
+    }
+    static staticM() {
+      return 2;
+    }
+  }
+
+  assertEquals(1, new C().m());
+  assertEquals(2, C.staticM());
+})();
+
+
+(function TestConstructableButNoPrototype() {
+  var Base = function() {}.bind();
+  assertThrows(function() {
+    class C extends Base {}
+  }, TypeError);
+})();
+
+
+(function TestPrototypeGetter() {
+  var calls = 0;
+  var Base = function() {}.bind();
+  Object.defineProperty(Base, 'prototype', {
+    get: function() {
+      calls++;
+      return null;
+    },
+    configurable: true
+  });
+  class C extends Base {}
+  assertEquals(1, calls);
+
+  calls = 0;
+  Object.defineProperty(Base, 'prototype', {
+    get: function() {
+      calls++;
+      return 42;
+    },
+    configurable: true
+  });
+  assertThrows(function() {
+    class C extends Base {}
+  }, TypeError);
+  assertEquals(1, calls);
+})();
+
+
+(function TestPrototypeSetter() {
+  var Base = function() {}.bind();
+  Object.defineProperty(Base, 'prototype', {
+    set: function() {
+      assertUnreachable();
+    }
+  });
+  assertThrows(function() {
+    class C extends Base {}
+  }, TypeError);
+})();
+
+
+(function TestSuperInMethods() {
+  class B {
+    method() {
+      return 1;
+    }
+    get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    method() {
+      assertEquals(2, super.x);
+      return super.method();
+    }
+  }
+  assertEquals(1, new C().method());
+})();
+
+
+(function TestSuperInGetter() {
+  class B {
+    method() {
+      return 1;
+    }
+    get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    get y() {
+      assertEquals(2, super.x);
+      return super.method();
+    }
+  }
+  assertEquals(1, new C().y);
+})();
+
+
+(function TestSuperInSetter() {
+  class B {
+    method() {
+      return 1;
+    }
+    get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    set y(v) {
+      assertEquals(3, v);
+      assertEquals(2, super.x);
+      assertEquals(1, super.method());
+    }
+  }
+  assertEquals(3, new C().y = 3);
+})();
+
+
+(function TestSuperInStaticMethods() {
+  class B {
+    static method() {
+      return 1;
+    }
+    static get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    static method() {
+      assertEquals(2, super.x);
+      return super.method();
+    }
+  }
+  assertEquals(1, C.method());
+})();
+
+
+(function TestSuperInStaticGetter() {
+  class B {
+    static method() {
+      return 1;
+    }
+    static get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    static get x() {
+      assertEquals(2, super.x);
+      return super.method();
+    }
+  }
+  assertEquals(1, C.x);
+})();
+
+
+(function TestSuperInStaticSetter() {
+  class B {
+    static method() {
+      return 1;
+    }
+    static get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    static set x(v) {
+      assertEquals(3, v);
+      assertEquals(2, super.x);
+      assertEquals(1, super.method());
+    }
+  }
+  assertEquals(3, C.x = 3);
+})();
+
+
+(function TestNumericPropertyNames() {
+  class B {
+    1() { return 1; }
+    get 2() { return 2; }
+    set 3(_) {}
+
+    static 4() { return 4; }
+    static get 5() { return 5; }
+    static set 6(_) {}
+  }
+
+  assertMethodDescriptor(B.prototype, '1');
+  assertGetterDescriptor(B.prototype, '2');
+  assertSetterDescriptor(B.prototype, '3');
+
+  assertMethodDescriptor(B, '4');
+  assertGetterDescriptor(B, '5');
+  assertSetterDescriptor(B, '6');
+
+  class C extends B {
+    1() { return super[1](); }
+    get 2() { return super[2]; }
+
+    static 4() { return super[4](); }
+    static get 5() { return super[5]; }
+  }
+
+  assertEquals(1, new C()[1]());
+  assertEquals(2, new C()[2]);
+  assertEquals(4, C[4]());
+  assertEquals(5, C[5]);
+})();
+
+
+(function TestDefaultConstructorNoCrash() {
+  // Regression test for https://code.google.com/p/v8/issues/detail?id=3661
+  class C {}
+  assertEquals(undefined, C());
+  assertEquals(undefined, C(1));
+  assertTrue(new C() instanceof C);
+  assertTrue(new C(1) instanceof C);
+})();
+
+
+(function TestDefaultConstructor() {
+  var calls = 0;
+  class Base {
+    constructor() {
+      calls++;
+    }
+  }
+  class Derived extends Base {}
+  var object = new Derived;
+  assertEquals(1, calls);
+
+  calls = 0;
+  Derived();
+  assertEquals(1, calls);
+})();
+
+
+(function TestDefaultConstructorArguments() {
+  var args, self;
+  class Base {
+    constructor() {
+      self = this;
+      args = arguments;
+    }
+  }
+  class Derived extends Base {}
+
+  new Derived;
+  assertEquals(0, args.length);
+
+  new Derived(0, 1, 2);
+  assertEquals(3, args.length);
+  assertTrue(self instanceof Derived);
+
+  var arr = new Array(100);
+  var obj = {};
+  Derived.apply(obj, arr);
+  assertEquals(100, args.length);
+  assertEquals(obj, self);
+})();
+
+
+(function TestDefaultConstructorArguments2() {
+  var args;
+  class Base {
+    constructor(x, y) {
+      args = arguments;
+    }
+  }
+  class Derived extends Base {}
+
+  new Derived;
+  assertEquals(0, args.length);
+
+  new Derived(1);
+  assertEquals(1, args.length);
+  assertEquals(1, args[0]);
+
+  new Derived(1, 2, 3);
+  assertEquals(3, args.length);
+  assertEquals(1, args[0]);
+  assertEquals(2, args[1]);
+  assertEquals(3, args[2]);
+})();
+
+
+(function TestNameBindingConst() {
+  assertThrows('class C { constructor() { C = 42; } }; new C();', TypeError);
+  assertThrows('new (class C { constructor() { C = 42; } })', TypeError);
+  assertThrows('class C { m() { C = 42; } }; new C().m()', TypeError);
+  assertThrows('new (class C { m() { C = 42; } }).m()', TypeError);
+  assertThrows('class C { get x() { C = 42; } }; new C().x', TypeError);
+  assertThrows('(new (class C { get x() { C = 42; } })).x', TypeError);
+  assertThrows('class C { set x(_) { C = 42; } }; new C().x = 15;', TypeError);
+  assertThrows('(new (class C { set x(_) { C = 42; } })).x = 15;', TypeError);
+})();
+
+
+(function TestNameBinding() {
+  var C2;
+  class C {
+    constructor() {
+      C2 = C;
+    }
+    m() {
+      C2 = C;
+    }
+    get x() {
+      C2 = C;
+    }
+    set x(_) {
+      C2 = C;
+    }
+  }
+  new C();
+  assertEquals(C, C2);
+
+  C2 = undefined;
+  new C().m();
+  assertEquals(C, C2);
+
+  C2 = undefined;
+  new C().x;
+  assertEquals(C, C2);
+
+  C2 = undefined;
+  new C().x = 1;
+  assertEquals(C, C2);
+})();
+
+
+(function TestNameBindingExpression() {
+  var C3;
+  var C = class C2 {
+    constructor() {
+      assertEquals(C2, C);
+      C3 = C2;
+    }
+    m() {
+      assertEquals(C2, C);
+      C3 = C2;
+    }
+    get x() {
+      assertEquals(C2, C);
+      C3 = C2;
+    }
+    set x(_) {
+      assertEquals(C2, C);
+      C3 = C2;
+    }
+  }
+  new C();
+  assertEquals(C, C3);
+
+  C3 = undefined;
+  new C().m();
+  assertEquals(C, C3);
+
+  C3 = undefined;
+  new C().x;
+  assertEquals(C, C3);
+
+  C3 = undefined;
+  new C().x = 1;
+  assertEquals(C, C3);
+})();
+
+
+(function TestNameBindingInExtendsExpression() {
+  assertThrows(function() {
+    class x extends x {}
+  }, ReferenceError);
+
+  assertThrows(function() {
+    (class x extends x {});
+  }, ReferenceError);
+
+  assertThrows(function() {
+    var x = (class x extends x {});
+  }, ReferenceError);
+})();
+
+
+(function TestSuperCallSyntacticRestriction() {
+  assertThrows(function() {
+    class C {
+      constructor() {
+        var y;
+        super();
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super(this.x);
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super(this);
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super.method();
+        super(this);
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super(super.method());
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super(super());
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super(1, 2, Object.getPrototypeOf(this));
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        { super(1, 2); }
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        if (1) super();
+      }
+    }; new C();
+  }, TypeError);
+
+  class C1 extends Object {
+    constructor() {
+      'use strict';
+      super();
+    }
+  };
+  new C1();
+
+  class C2 extends Object {
+    constructor() {
+      ; 'use strict';;;;;
+      super();
+    }
+  };
+  new C2();
+
+  class C3 extends Object {
+    constructor() {
+      ; 'use strict';;;;;
+      // This is a comment.
+      super();
+    }
+  };
+  new C3();
+
+  class C4 extends Object {
+    constructor() {
+      super(new super());
+    }
+  }; new C4();
+}());
diff --git a/test/mjsunit/harmony/debug-blockscopes.js b/test/mjsunit/harmony/debug-blockscopes.js
index 2db4942..8180377 100644
--- a/test/mjsunit/harmony/debug-blockscopes.js
+++ b/test/mjsunit/harmony/debug-blockscopes.js
@@ -73,7 +73,7 @@
 // Check result of a test.
 function EndTest() {
   assertTrue(listener_called, "listerner not called for " + test_name);
-  assertNull(exception, test_name);
+  assertNull(exception, test_name, exception);
   end_test_count++;
 }
 
@@ -108,6 +108,7 @@
     assertEquals(i, response.body.scopes[i].index);
     assertEquals(scopes[i], response.body.scopes[i].type);
     if (scopes[i] == debug.ScopeType.Local ||
+        scopes[i] == debug.ScopeType.Script ||
         scopes[i] == debug.ScopeType.Closure) {
       assertTrue(response.body.scopes[i].object.ref < 0);
     } else {
@@ -197,6 +198,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
 };
@@ -215,6 +217,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1}, 0, exec_state);
 };
@@ -232,6 +235,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,x:3}, 0, exec_state);
 };
@@ -250,6 +254,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,b:2,x:3,y:4}, 0, exec_state);
 };
@@ -270,6 +275,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:5}, 0, exec_state);
   CheckScopeContent({a:1}, 1, exec_state);
@@ -292,6 +298,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:6,y:7}, 0, exec_state);
   CheckScopeContent({a:1}, 1, exec_state);
@@ -315,6 +322,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:8}, 0, exec_state);
   CheckScopeContent({a:1}, 1, exec_state);
@@ -344,6 +352,7 @@
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Block,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
   CheckScopeContent({a:1,x:2,y:3}, 2, exec_state);
@@ -364,6 +373,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:'y'}, 0, exec_state);
   // The function scope contains a temporary iteration variable, but it is
@@ -389,6 +399,7 @@
   CheckScopeChain([debug.ScopeType.Block,
                    debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:3}, 0, exec_state);
   CheckScopeContent({x:'y'}, 1, exec_state);
@@ -413,6 +424,7 @@
   CheckScopeChain([debug.ScopeType.Block,
                    debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:3}, 0, exec_state);
   CheckScopeContent({x:3}, 1, exec_state);
@@ -437,6 +449,7 @@
                    debug.ScopeType.Block,
                    debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:5}, 0, exec_state);
   CheckScopeContent({x:3}, 1, exec_state);
@@ -460,6 +473,7 @@
   CheckScopeChain([debug.ScopeType.Block,
                    debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:3,y:5}, 0, exec_state);
   CheckScopeContent({x:3,y:5}, 1, exec_state);
@@ -467,3 +481,24 @@
 };
 for_loop_5();
 EndTest();
+
+
+// Uninitialized variables
+BeginTest("Uninitialized 1");
+
+function uninitialized_1() {
+  {
+    debugger;
+    let x = 1;
+  }
+}
+
+listener_delegate = function(exec_state) {
+  CheckScopeChain([debug.ScopeType.Block,
+                   debug.ScopeType.Local,
+                   debug.ScopeType.Script,
+                   debug.ScopeType.Global], exec_state);
+  CheckScopeContent({}, 0, exec_state);
+};
+uninitialized_1();
+EndTest();
diff --git a/test/mjsunit/harmony/debug-evaluate-blockscopes.js b/test/mjsunit/harmony/debug-evaluate-blockscopes.js
index 16885d0..d133cc0 100644
--- a/test/mjsunit/harmony/debug-evaluate-blockscopes.js
+++ b/test/mjsunit/harmony/debug-evaluate-blockscopes.js
@@ -67,3 +67,43 @@
 Debug.clearBreakPoint(bp);
 // Get rid of the debug event listener.
 Debug.setListener(null);
+
+
+function f1() {
+  {
+    let i = 1;
+    debugger;
+    assertEquals(2, i);
+  }
+}
+
+function f2() {
+  {
+    let i = 1;
+    debugger;
+    assertEquals(2, i);
+    return function() { return i++; }
+  }
+}
+
+var exception;
+Debug.setListener(function (event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      var frame = exec_state.frame();
+      assertEquals(1, frame.evaluate("i").value());
+      var allScopes = frame.allScopes();
+      assertEquals(1, allScopes[0].scopeObject().value().i);
+      allScopes[0].setVariableValue("i", 2);
+    }
+  } catch (e) {
+    exception = e;
+  }
+});
+
+exception = null;
+f1();
+assertEquals(null, exception, exception);
+exception = null;
+f2();
+assertEquals(null, exception, exception);
diff --git a/test/mjsunit/harmony/debug-function-scopes.js b/test/mjsunit/harmony/debug-function-scopes.js
index 0113be6..1b380c2 100644
--- a/test/mjsunit/harmony/debug-function-scopes.js
+++ b/test/mjsunit/harmony/debug-function-scopes.js
@@ -28,6 +28,7 @@
 // Flags: --expose-debug-as debug --harmony-scoping
 
 "use strict";
+let top_level_let = 255;
 
 // Get the Debug object exposed from the debug context global object.
 var Debug = debug.Debug;
@@ -50,7 +51,8 @@
                   With: 2,
                   Closure: 3,
                   Catch: 4,
-                  Block: 5 };
+                  Block: 5,
+                  Script: 6};
 
 var f1 = (function F1(x) {
   function F2(y) {
@@ -72,12 +74,13 @@
 
 var mirror = Debug.MakeMirror(f1);
 
-assertEquals(4, mirror.scopeCount());
+assertEquals(5, mirror.scopeCount());
 
 CheckScope(mirror.scope(0), { a: 4, b: 5 }, ScopeType.Closure);
 CheckScope(mirror.scope(1), { z: 22, w: 5, v: "Capybara" }, ScopeType.Closure);
 CheckScope(mirror.scope(2), { x: 5 }, ScopeType.Closure);
-CheckScope(mirror.scope(3), {}, ScopeType.Global);
+CheckScope(mirror.scope(3), { top_level_let: 255 }, ScopeType.Script);
+CheckScope(mirror.scope(4), {}, ScopeType.Global);
 
 var f2 = (function() {
   var v1 = 3;
@@ -104,7 +107,7 @@
 
 var mirror = Debug.MakeMirror(f2);
 
-assertEquals(5, mirror.scopeCount());
+assertEquals(6, mirror.scopeCount());
 
 // Implementation artifact: l4 isn't used in closure, but still it is saved.
 CheckScope(mirror.scope(0), { l4: 11 }, ScopeType.Block);
@@ -112,4 +115,5 @@
 CheckScope(mirror.scope(1), { l3: 9 }, ScopeType.Block);
 CheckScope(mirror.scope(2), { l1: 6, l2: 7 }, ScopeType.Block);
 CheckScope(mirror.scope(3), { v1:3, l0: 0, v3: 5, v6: 11 }, ScopeType.Closure);
-CheckScope(mirror.scope(4), {}, ScopeType.Global);
+CheckScope(mirror.scope(4), { top_level_let: 255 }, ScopeType.Script);
+CheckScope(mirror.scope(5), {}, ScopeType.Global);
diff --git a/test/mjsunit/harmony/debug-step-into-class-extends.js b/test/mjsunit/harmony/debug-step-into-class-extends.js
new file mode 100644
index 0000000..ffc6fda
--- /dev/null
+++ b/test/mjsunit/harmony/debug-step-into-class-extends.js
@@ -0,0 +1,42 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug --harmony-classes
+
+'use strict';
+
+var Debug = debug.Debug
+
+var done = false;
+var stepCount = 0;
+
+function listener(event, execState, eventData, data) {
+  if (event == Debug.DebugEvent.Break) {
+    if (!done) {
+      execState.prepareStep(Debug.StepAction.StepInto);
+      var s = execState.frame().sourceLineText();
+      assertTrue(s.indexOf('// ' + stepCount + '.') !== -1);
+      stepCount++;
+    }
+  }
+};
+
+Debug.setListener(listener);
+
+function GetBase() {
+  var x = 1;   // 1.
+  var y = 2;   // 2.
+  done = true; // 3.
+  return null;
+}
+
+function f() {
+  class Derived extends GetBase() {} // 0.
+}
+
+var bp = Debug.setBreakPoint(f, 0);
+f();
+assertEquals(4, stepCount);
+
+Debug.setListener(null);
diff --git a/test/mjsunit/harmony/debug-step-into-constructor.js b/test/mjsunit/harmony/debug-step-into-constructor.js
new file mode 100644
index 0000000..dbef60f
--- /dev/null
+++ b/test/mjsunit/harmony/debug-step-into-constructor.js
@@ -0,0 +1,113 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug --harmony-classes
+
+'use strict';
+
+var Debug = debug.Debug
+var done, stepCount;
+
+function listener(event, execState, eventData, data) {
+  if (event == Debug.DebugEvent.Break) {
+    if (!done) {
+      execState.prepareStep(Debug.StepAction.StepInto);
+      var s = execState.frame().sourceLineText();
+      assertTrue(s.indexOf('// ' + stepCount + '.') !== -1);
+      stepCount++;
+    }
+  }
+};
+
+Debug.setListener(listener);
+
+
+class Base {
+  constructor() {
+    var x = 1;   // 1.
+    var y = 2;   // 2.
+    done = true; // 3.
+  }
+}
+
+class Derived extends Base {}
+
+
+(function TestBreakPointInConstructor() {
+  done = false;
+  stepCount = 1;
+  var bp = Debug.setBreakPoint(Base, 0);
+
+  new Base();
+  assertEquals(4, stepCount);
+
+  Debug.clearBreakPoint(bp);
+})();
+
+
+(function TestDefaultConstructor() {
+  done = false;
+  stepCount = 1;
+
+  var bp = Debug.setBreakPoint(Base, 0);
+  new Derived();
+  assertEquals(4, stepCount);
+
+  Debug.clearBreakPoint(bp);
+})();
+
+
+(function TestStepInto() {
+  done = false;
+  stepCount = 0;
+
+  function f() {
+    new Derived();  // 0.
+  }
+
+  var bp = Debug.setBreakPoint(f, 0);
+  f();
+  assertEquals(4, stepCount);
+
+  Debug.clearBreakPoint(bp);
+})();
+
+
+(function TestExtraIndirection() {
+  done = false;
+  stepCount = 0;
+
+  class Derived2 extends Derived {}
+
+  function f() {
+    new Derived2();  // 0.
+  }
+
+  var bp = Debug.setBreakPoint(f, 0);
+  f();
+  assertEquals(4, stepCount);
+
+  Debug.clearBreakPoint(bp);
+})();
+
+
+(function TestBoundClass() {
+  done = false;
+  stepCount = 0;
+
+  var bound = Derived.bind(null);
+
+  function f() {
+    new bound();  // 0.
+  }
+
+  var bp = Debug.setBreakPoint(f, 0);
+  f();
+  assertEquals(4, stepCount);
+
+  Debug.clearBreakPoint(bp);
+})();
+
+
+Debug.setListener(null);
diff --git a/test/mjsunit/harmony/disable-harmony-string.js b/test/mjsunit/harmony/disable-harmony-string.js
new file mode 100644
index 0000000..0b88ae0
--- /dev/null
+++ b/test/mjsunit/harmony/disable-harmony-string.js
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --noharmony-strings
+
+assertEquals(undefined, String.prototype.includes);
diff --git a/test/mjsunit/harmony/module-linking.js b/test/mjsunit/harmony/module-linking.js
index 3c0f18c..3a5bc89 100644
--- a/test/mjsunit/harmony/module-linking.js
+++ b/test/mjsunit/harmony/module-linking.js
@@ -109,7 +109,7 @@
   assertThrows(function() { l }, ReferenceError)
   assertThrows(function() { R.l }, ReferenceError)
 
-  assertThrows(function() { eval("c = -1") }, SyntaxError)
+  assertThrows(function() { eval("c = -1") }, TypeError)
   assertThrows(function() { R.c = -2 }, TypeError)
 
   // Initialize first bunch of variables.
@@ -129,7 +129,7 @@
   assertEquals(-4, R.v = -4)
   assertEquals(-3, l = -3)
   assertEquals(-4, R.l = -4)
-  assertThrows(function() { eval("c = -3") }, SyntaxError)
+  assertThrows(function() { eval("c = -3") }, TypeError)
   assertThrows(function() { R.c = -4 }, TypeError)
 
   assertEquals(-4, v)
diff --git a/test/mjsunit/harmony/numeric-literals-off.js b/test/mjsunit/harmony/numeric-literals-off.js
deleted file mode 100644
index 37204ed..0000000
--- a/test/mjsunit/harmony/numeric-literals-off.js
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// This is to ensure that we do not support 0b and 0o in Number when
-// the --harmony-numeric-literals flag is not set.
-
-
-function TestOctalLiteralUsingNumberFunction() {
-  assertEquals(NaN, Number('0o0'));
-}
-TestOctalLiteralUsingNumberFunction();
-
-
-function TestBinaryLiteralUsingNumberFunction() {
-  assertEquals(NaN, Number('0b0'));
-}
-TestBinaryLiteralUsingNumberFunction();
diff --git a/test/mjsunit/harmony/object-literals-property-shorthand.js b/test/mjsunit/harmony/object-literals-property-shorthand.js
new file mode 100644
index 0000000..2921495
--- /dev/null
+++ b/test/mjsunit/harmony/object-literals-property-shorthand.js
@@ -0,0 +1,51 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-object-literals
+
+
+(function TestBasics() {
+  var x = 1;
+  var object = {x};
+  assertEquals(1, object.x);
+})();
+
+
+(function TestDescriptor() {
+  var x = 1;
+  var object = {x};
+  var descr = Object.getOwnPropertyDescriptor(object, 'x');
+  assertEquals(1, descr.value);
+  assertTrue(descr.enumerable);
+  assertTrue(descr.writable);
+  assertTrue(descr.configurable);
+})();
+
+
+(function TestNotDefined() {
+  'use strict';
+  assertThrows(function() {
+    return {notDefined};
+  }, ReferenceError);
+})();
+
+
+(function TestLet() {
+  var let = 1;
+  var object = {let};
+  assertEquals(1, object.let);
+})();
+
+
+(function TestYieldInFunction() {
+  var yield = 1;
+  var object = {yield};
+  assertEquals(1, object.yield);
+})();
+
+
+(function TestToString() {
+  function f(x) { return {x}; }
+  assertEquals('function f(x) { return {x}; }', f.toString());
+})();
diff --git a/test/mjsunit/harmony/object-literals-super.js b/test/mjsunit/harmony/object-literals-super.js
new file mode 100644
index 0000000..ec22b8a
--- /dev/null
+++ b/test/mjsunit/harmony/object-literals-super.js
@@ -0,0 +1,168 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-classes --allow-natives-syntax
+
+
+(function TestHomeObject() {
+  var object = {
+    method() {
+      return super.method();
+    },
+    get getter() {
+      return super.getter;
+    },
+    set setter(v) {
+      super.setter = v;
+    },
+    get accessor() {
+      return super.accessor;
+    },
+    set accessor(v) {
+      super.accessor = v;
+    },
+    property: function() {
+      super.property();
+    },
+    propertyWithParen: (function() {
+      super.property();
+    }),
+    propertyWithParens: ((function() {
+      super.property();
+    })),
+
+    methodNoSuper() {},
+    get getterNoSuper() {},
+    set setterNoSuper(v) {},
+    get accessorNoSuper() {},
+    set accessorNoSuper(v) {},
+    propertyNoSuper: function() {},
+    propertyWithParenNoSuper: (function() {}),
+    propertyWithParensNoSuper: ((function() {}))
+  };
+
+  assertEquals(object, object.method[%HomeObjectSymbol()]);
+  var desc = Object.getOwnPropertyDescriptor(object, 'getter');
+  assertEquals(object, desc.get[%HomeObjectSymbol()]);
+  desc = Object.getOwnPropertyDescriptor(object, 'setter');
+  assertEquals(object, desc.set[%HomeObjectSymbol()]);
+  desc = Object.getOwnPropertyDescriptor(object, 'accessor');
+  assertEquals(object, desc.get[%HomeObjectSymbol()]);
+  assertEquals(object, desc.set[%HomeObjectSymbol()]);
+  assertEquals(object, object.property[%HomeObjectSymbol()]);
+  assertEquals(object, object.propertyWithParen[%HomeObjectSymbol()]);
+  assertEquals(object, object.propertyWithParens[%HomeObjectSymbol()]);
+
+  assertEquals(undefined, object.methodNoSuper[%HomeObjectSymbol()]);
+  desc = Object.getOwnPropertyDescriptor(object, 'getterNoSuper');
+  assertEquals(undefined, desc.get[%HomeObjectSymbol()]);
+  desc = Object.getOwnPropertyDescriptor(object, 'setterNoSuper');
+  assertEquals(undefined, desc.set[%HomeObjectSymbol()]);
+  desc = Object.getOwnPropertyDescriptor(object, 'accessorNoSuper');
+  assertEquals(undefined, desc.get[%HomeObjectSymbol()]);
+  assertEquals(undefined, desc.set[%HomeObjectSymbol()]);
+  assertEquals(undefined, object.propertyNoSuper[%HomeObjectSymbol()]);
+  assertEquals(undefined, object.propertyWithParenNoSuper[%HomeObjectSymbol()]);
+  assertEquals(undefined,
+               object.propertyWithParensNoSuper[%HomeObjectSymbol()]);
+})();
+
+
+(function TestMethod() {
+  var object = {
+    __proto__: {
+      method(x) {
+        return 'proto' + x;
+      }
+    },
+    method(x) {
+      return super.method(x);
+    }
+  };
+  assertEquals('proto42', object.method(42));
+})();
+
+
+(function TestGetter() {
+  var object = {
+    __proto__: {
+      _x: 42,
+      get x() {
+        return 'proto' + this._x;
+      }
+    },
+    get x() {
+      return super.x;
+    }
+  };
+  assertEquals('proto42', object.x);
+})();
+
+
+(function TestSetter() {
+  var object = {
+    __proto__: {
+      _x: 0,
+      set x(v) {
+        return this._x = v;
+      }
+    },
+    set x(v) {
+      super.x = v;
+    }
+  };
+  assertEquals(1, object.x = 1);
+  assertEquals(1, object._x);
+  assertEquals(0, Object.getPrototypeOf(object)._x);
+})();
+
+
+(function TestMethodAsProperty() {
+  var object = {
+    __proto__: {
+      method: function(x) {
+        return 'proto' + x;
+      }
+    },
+    method: function(x) {
+      return super.method(x);
+    }
+  };
+  assertEquals('proto42', object.method(42));
+})();
+
+
+(function TestOptimized() {
+  // Object literals without any accessors get optimized.
+  var object = {
+    method() {
+      return super.toString;
+    }
+  };
+  assertEquals(Object.prototype.toString, object.method());
+})();
+
+
+(function TestConciseGenerator() {
+  var o = {
+    __proto__: {
+      m() {
+        return 42;
+      }
+    },
+    *g() {
+      yield super.m();
+    },
+    g2: function*() {
+      yield super.m() + 1;
+    },
+    g3: (function*() {
+      yield super.m() + 2;
+    })
+  };
+
+  assertEquals(42, o.g().next().value);
+  assertEquals(43, o.g2().next().value);
+  assertEquals(44, o.g3().next().value);
+})();
diff --git a/test/mjsunit/harmony/proxies-with-unscopables.js b/test/mjsunit/harmony/proxies-with-unscopables.js
index 191bad3..8a03ef4 100644
--- a/test/mjsunit/harmony/proxies-with-unscopables.js
+++ b/test/mjsunit/harmony/proxies-with-unscopables.js
@@ -74,12 +74,17 @@
   var calls = 0;
   var proxy = Proxy.create({
     has: function(key) {
-      calls++;
-      assertEquals('x', key);
-      return calls === 2;
+      assertUnreachable();
     },
     getPropertyDescriptor: function(key) {
-      assertUnreachable();
+      calls++;
+      assertEquals('x', key);
+      return {
+        value: calls === 2 ? true : undefined,
+        configurable: true,
+        enumerable: true,
+        writable: true,
+      };
     }
   });
 
@@ -107,12 +112,12 @@
   var calls = 0;
   var proxy = Proxy.create({
     has: function(key) {
-      if (calls++ === 0) {
-        throw new CustomError();
-      }
       assertUnreachable();
     },
     getPropertyDescriptor: function(key) {
+      if (calls++ === 0) {
+        throw new CustomError();
+      }
       assertUnreachable();
     }
   });
diff --git a/test/mjsunit/harmony/proxies.js b/test/mjsunit/harmony/proxies.js
index b082c06..2b0ec76 100644
--- a/test/mjsunit/harmony/proxies.js
+++ b/test/mjsunit/harmony/proxies.js
@@ -29,7 +29,7 @@
 // test enters an infinite recursion which goes through the runtime and we
 // overflow the system stack before the simulator stack.
 
-// Flags: --harmony-proxies --sim-stack-size=500
+// Flags: --harmony-proxies --sim-stack-size=500 --turbo-deoptimization
 
 
 // Helper.
diff --git a/test/mjsunit/harmony/regexp-flags.js b/test/mjsunit/harmony/regexp-flags.js
new file mode 100644
index 0000000..475fda4
--- /dev/null
+++ b/test/mjsunit/harmony/regexp-flags.js
@@ -0,0 +1,61 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-regexps
+
+RegExp.prototype.flags = 'setter should be undefined';
+
+assertEquals('', RegExp('').flags);
+assertEquals('', /./.flags);
+assertEquals('gimy', RegExp('', 'ygmi').flags);
+assertEquals('gimy', /foo/ymig.flags);
+
+// TODO(dslomov): When support for the `u` flag is added, uncomment the first
+// line below and remove the second line.
+//assertEquals(RegExp('', 'yumig').flags, 'gimuy');
+assertThrows(function() { RegExp('', 'yumig').flags; }, SyntaxError);
+
+var descriptor = Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags');
+assertTrue(descriptor.configurable);
+assertFalse(descriptor.enumerable);
+assertInstanceof(descriptor.get, Function);
+assertEquals(undefined, descriptor.set);
+
+function testGenericFlags(object) {
+  return descriptor.get.call(object);
+}
+
+assertEquals('', testGenericFlags({}));
+assertEquals('i', testGenericFlags({ ignoreCase: true }));
+assertEquals('uy', testGenericFlags({ global: 0, sticky: 1, unicode: 1 }));
+assertEquals('m', testGenericFlags({ __proto__: { multiline: true } }));
+assertThrows(function() { testGenericFlags(); }, TypeError);
+assertThrows(function() { testGenericFlags(undefined); }, TypeError);
+assertThrows(function() { testGenericFlags(null); }, TypeError);
+assertThrows(function() { testGenericFlags(true); }, TypeError);
+assertThrows(function() { testGenericFlags(false); }, TypeError);
+assertThrows(function() { testGenericFlags(''); }, TypeError);
+assertThrows(function() { testGenericFlags(42); }, TypeError);
+
+var counter = 0;
+var map = {};
+var object = {
+  get global() {
+    map.g = counter++;
+  },
+  get ignoreCase() {
+    map.i = counter++;
+  },
+  get multiline() {
+    map.m = counter++;
+  },
+  get unicode() {
+    map.u = counter++;
+  },
+  get sticky() {
+    map.y = counter++;
+  }
+};
+testGenericFlags(object);
+assertEquals({ g: 0, i: 1, m: 2, u: 3, y: 4 }, map);
diff --git a/test/mjsunit/harmony/regress/regress-2243.js b/test/mjsunit/harmony/regress/regress-2243.js
index 31c2e55..e2411d2 100644
--- a/test/mjsunit/harmony/regress/regress-2243.js
+++ b/test/mjsunit/harmony/regress/regress-2243.js
@@ -27,5 +27,5 @@
 
 // Flags: --harmony-scoping
 
-assertThrows("'use strict'; (function f() { f = 123; })", SyntaxError);
-assertThrows("(function f() { 'use strict'; f = 123; })", SyntaxError);
+assertThrows("'use strict'; (function f() { f = 123; })()", TypeError);
+assertThrows("(function f() { 'use strict'; f = 123; })()", TypeError);
diff --git a/test/mjsunit/harmony/regress/regress-2858.js b/test/mjsunit/harmony/regress/regress-2858.js
new file mode 100644
index 0000000..4ce9478
--- /dev/null
+++ b/test/mjsunit/harmony/regress/regress-2858.js
@@ -0,0 +1,27 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-scoping
+"use strict";
+
+function f() {
+    var y = 1;
+    var q1;
+    var q;
+    var z = new Error();
+    try {
+        throw z;
+    } catch (y) {
+      assertTrue(z === y);
+      q1 = function() { return y; }
+      var y = 15;
+      q = function() { return y; }
+      assertSame(15, y);
+    }
+    assertSame(1, y);
+    assertSame(15, q1());
+    assertSame(15, q());
+}
+
+f();
diff --git a/test/mjsunit/harmony/regress/regress-343928.js b/test/mjsunit/harmony/regress/regress-343928.js
index b102ab9..f2ff371 100644
--- a/test/mjsunit/harmony/regress/regress-343928.js
+++ b/test/mjsunit/harmony/regress/regress-343928.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Flags: --harmony --expose-debug-as=debug
+// Flags: --harmony-modules --expose-debug-as=debug
 
 (function () {  // Scope for utility functions.
   escaping_function = function(object) {
diff --git a/test/mjsunit/harmony/regress/regress-3683.js b/test/mjsunit/harmony/regress/regress-3683.js
new file mode 100644
index 0000000..a00d82b
--- /dev/null
+++ b/test/mjsunit/harmony/regress/regress-3683.js
@@ -0,0 +1,84 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-scoping
+
+"use strict";
+
+// Simplest case
+var count = 0;
+for (let x = 0; x < 10;) {
+  x++;
+  count++;
+  continue;
+}
+assertEquals(10, count);
+
+// Labeled
+count = 0;
+label: for (let x = 0; x < 10;) {
+  while (true) {
+    x++;
+    count++;
+    continue label;
+  }
+}
+assertEquals(10, count);
+
+// Simple and labeled
+count = 0;
+label: for (let x = 0; x < 10;) {
+  x++;
+  count++;
+  continue label;
+}
+assertEquals(10, count);
+
+// Shadowing loop variable in same scope as continue
+count = 0;
+for (let x = 0; x < 10;) {
+  x++;
+  count++;
+  {
+    let x = "hello";
+    continue;
+  }
+}
+assertEquals(10, count);
+
+// Nested let-bound for loops, inner continue
+count = 0;
+for (let x = 0; x < 10;) {
+  x++;
+  for (let y = 0; y < 2;) {
+    y++;
+    count++;
+    continue;
+  }
+}
+assertEquals(20, count);
+
+// Nested let-bound for loops, outer continue
+count = 0;
+for (let x = 0; x < 10;) {
+  x++;
+  for (let y = 0; y < 2;) {
+    y++;
+    count++;
+  }
+  continue;
+}
+assertEquals(20, count);
+
+// Nested let-bound for loops, labeled continue
+count = 0;
+outer: for (let x = 0; x < 10;) {
+  x++;
+  for (let y = 0; y < 2;) {
+    y++;
+    count++;
+    if (y == 2) continue outer;
+  }
+}
+assertEquals(20, count);
diff --git a/test/mjsunit/harmony/regress/regress-3741.js b/test/mjsunit/harmony/regress/regress-3741.js
new file mode 100644
index 0000000..8a9dd9e
--- /dev/null
+++ b/test/mjsunit/harmony/regress/regress-3741.js
@@ -0,0 +1,26 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-scoping --allow-natives-syntax
+'use strict';
+function f24(deopt) {
+  let x = 1;
+  {
+    let x = 2;
+    {
+      let x = 3;
+      assertEquals(3, x);
+    }
+    deopt + 1;
+    assertEquals(2, x);
+  }
+  assertEquals(1, x);
+}
+
+
+for (var j = 0; j < 10; ++j) {
+  f24(12);
+}
+%OptimizeFunctionOnNextCall(f24);
+f24({});
diff --git a/test/mjsunit/harmony/regress/regress-3750.js b/test/mjsunit/harmony/regress/regress-3750.js
new file mode 100644
index 0000000..d1f21f9
--- /dev/null
+++ b/test/mjsunit/harmony/regress/regress-3750.js
@@ -0,0 +1,8 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-classes
+'use strict';
+class Example { }
+Object.observe(Example.prototype, function(){});
diff --git a/test/mjsunit/harmony/string-contains.js b/test/mjsunit/harmony/string-contains.js
deleted file mode 100644
index b853ed9..0000000
--- a/test/mjsunit/harmony/string-contains.js
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Flags: --harmony-strings
-
-assertEquals(1, String.prototype.contains.length);
-
-var reString = "asdf[a-z]+(asdf)?";
-assertTrue(reString.contains("[a-z]+"));
-assertTrue(reString.contains("(asdf)?"));
-
-// Random greek letters
-var twoByteString = "\u039a\u0391\u03a3\u03a3\u0395";
-
-// Test single char pattern
-assertTrue(twoByteString.contains("\u039a"), "Lamda");
-assertTrue(twoByteString.contains("\u0391"), "Alpha");
-assertTrue(twoByteString.contains("\u03a3"), "First Sigma");
-assertTrue(twoByteString.contains("\u03a3",3), "Second Sigma");
-assertTrue(twoByteString.contains("\u0395"), "Epsilon");
-assertFalse(twoByteString.contains("\u0392"), "Not beta");
-
-// Test multi-char pattern
-assertTrue(twoByteString.contains("\u039a\u0391"), "lambda Alpha");
-assertTrue(twoByteString.contains("\u0391\u03a3"), "Alpha Sigma");
-assertTrue(twoByteString.contains("\u03a3\u03a3"), "Sigma Sigma");
-assertTrue(twoByteString.contains("\u03a3\u0395"), "Sigma Epsilon");
-
-assertFalse(twoByteString.contains("\u0391\u03a3\u0395"),
-    "Not Alpha Sigma Epsilon");
-
-//single char pattern
-assertTrue(twoByteString.contains("\u0395"));
-
-assertThrows("String.prototype.contains.call(null, 'test')", TypeError);
-assertThrows("String.prototype.contains.call(null, null)", TypeError);
-assertThrows("String.prototype.contains.call(undefined, undefined)", TypeError);
-
-assertThrows("String.prototype.contains.apply(null, ['test'])", TypeError);
-assertThrows("String.prototype.contains.apply(null, [null])", TypeError);
-assertThrows("String.prototype.contains.apply(undefined, [undefined])", TypeError);
-
-var TEST_INPUT = [{
-  msg: "Empty string", val: ""
-}, {
-  msg: "Number 1234.34", val: 1234.34
-}, {
-  msg: "Integer number 0", val: 0
-}, {
-  msg: "Negative number -1", val: -1
-}, {
-  msg: "Boolean true", val: true
-}, {
-  msg: "Boolean false", val: false
-}, {
-  msg: "Empty array []", val: []
-}, {
-  msg: "Empty object {}", val: {}
-}, {
-  msg: "Array of size 3", val: new Array(3)
-}];
-
-var i = 0;
-var l = TEST_INPUT.length;
-
-for (; i < l; i++) {
-  var e = TEST_INPUT[i];
-  var v = e.val;
-  var s = String(v);
-  assertTrue(s.contains(v), e.msg);
-  assertTrue(String.prototype.contains.call(v, v), e.msg);
-  assertTrue(String.prototype.contains.apply(v, [v]), e.msg);
-}
-
-// Test cases found in FF
-assertTrue("abc".contains("a"));
-assertTrue("abc".contains("b"));
-assertTrue("abc".contains("abc"));
-assertTrue("abc".contains("bc"));
-assertFalse("abc".contains("d"));
-assertFalse("abc".contains("abcd"));
-assertFalse("abc".contains("ac"));
-assertTrue("abc".contains("abc", 0));
-assertTrue("abc".contains("bc", 0));
-assertFalse("abc".contains("de", 0));
-assertTrue("abc".contains("bc", 1));
-assertTrue("abc".contains("c", 1));
-assertFalse("abc".contains("a", 1));
-assertFalse("abc".contains("abc", 1));
-assertTrue("abc".contains("c", 2));
-assertFalse("abc".contains("d", 2));
-assertFalse("abc".contains("dcd", 2));
-assertFalse("abc".contains("a", 42));
-assertFalse("abc".contains("a", Infinity));
-assertTrue("abc".contains("ab", -43));
-assertFalse("abc".contains("cd", -42));
-assertTrue("abc".contains("ab", -Infinity));
-assertFalse("abc".contains("cd", -Infinity));
-assertTrue("abc".contains("ab", NaN));
-assertFalse("abc".contains("cd", NaN));
-assertFalse("xyzzy".contains("zy\0", 2));
-
-var dots = Array(10000).join(".");
-assertFalse(dots.contains("\x01", 10000));
-assertFalse(dots.contains("\0", 10000));
-
-var myobj = {
-  toString: function () {
-    return "abc";
-  },
-  contains: String.prototype.contains
-};
-assertTrue(myobj.contains("abc"));
-assertFalse(myobj.contains("cd"));
-
-var gotStr = false;
-var gotPos = false;
-myobj = {
-  toString: function () {
-    assertFalse(gotPos);
-    gotStr = true;
-    return "xyz";
-  },
-  contains: String.prototype.contains
-};
-
-assertEquals("foo[a-z]+(bar)?".contains("[a-z]+"), true);
-assertThrows("'foo[a-z]+(bar)?'.contains(/[a-z]+/)", TypeError);
-assertThrows("'foo/[a-z]+/(bar)?'.contains(/[a-z]+/)", TypeError);
-assertEquals("foo[a-z]+(bar)?".contains("(bar)?"), true);
-assertThrows("'foo[a-z]+(bar)?'.contains(/(bar)?/)", TypeError);
-assertThrows("'foo[a-z]+/(bar)?/'.contains(/(bar)?/)", TypeError);
-
-assertThrows("String.prototype.contains.call({ 'toString': function() { " +
-  "throw RangeError(); } }, /./)", RangeError);
-assertThrows("String.prototype.contains.call({ 'toString': function() { " +
-  "return 'abc'; } }, /./)", TypeError);
-
-assertThrows("String.prototype.contains.apply({ 'toString': function() { " +
-  "throw RangeError(); } }, [/./])", RangeError);
-assertThrows("String.prototype.contains.apply({ 'toString': function() { " +
-  "return 'abc'; } }, [/./])", TypeError);
diff --git a/test/mjsunit/harmony/string-includes.js b/test/mjsunit/harmony/string-includes.js
new file mode 100644
index 0000000..33ed8ea
--- /dev/null
+++ b/test/mjsunit/harmony/string-includes.js
@@ -0,0 +1,166 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-strings
+
+assertEquals(1, String.prototype.includes.length);
+
+var reString = "asdf[a-z]+(asdf)?";
+assertTrue(reString.includes("[a-z]+"));
+assertTrue(reString.includes("(asdf)?"));
+
+// Random greek letters
+var twoByteString = "\u039a\u0391\u03a3\u03a3\u0395";
+
+// Test single char pattern
+assertTrue(twoByteString.includes("\u039a"), "Lamda");
+assertTrue(twoByteString.includes("\u0391"), "Alpha");
+assertTrue(twoByteString.includes("\u03a3"), "First Sigma");
+assertTrue(twoByteString.includes("\u03a3",3), "Second Sigma");
+assertTrue(twoByteString.includes("\u0395"), "Epsilon");
+assertFalse(twoByteString.includes("\u0392"), "Not beta");
+
+// Test multi-char pattern
+assertTrue(twoByteString.includes("\u039a\u0391"), "lambda Alpha");
+assertTrue(twoByteString.includes("\u0391\u03a3"), "Alpha Sigma");
+assertTrue(twoByteString.includes("\u03a3\u03a3"), "Sigma Sigma");
+assertTrue(twoByteString.includes("\u03a3\u0395"), "Sigma Epsilon");
+
+assertFalse(twoByteString.includes("\u0391\u03a3\u0395"),
+    "Not Alpha Sigma Epsilon");
+
+//single char pattern
+assertTrue(twoByteString.includes("\u0395"));
+
+assertThrows("String.prototype.includes.call(null, 'test')", TypeError);
+assertThrows("String.prototype.includes.call(null, null)", TypeError);
+assertThrows("String.prototype.includes.call(undefined, undefined)", TypeError);
+
+assertThrows("String.prototype.includes.apply(null, ['test'])", TypeError);
+assertThrows("String.prototype.includes.apply(null, [null])", TypeError);
+assertThrows("String.prototype.includes.apply(undefined, [undefined])", TypeError);
+
+var TEST_INPUT = [{
+  msg: "Empty string", val: ""
+}, {
+  msg: "Number 1234.34", val: 1234.34
+}, {
+  msg: "Integer number 0", val: 0
+}, {
+  msg: "Negative number -1", val: -1
+}, {
+  msg: "Boolean true", val: true
+}, {
+  msg: "Boolean false", val: false
+}, {
+  msg: "Empty array []", val: []
+}, {
+  msg: "Empty object {}", val: {}
+}, {
+  msg: "Array of size 3", val: new Array(3)
+}];
+
+var i = 0;
+var l = TEST_INPUT.length;
+
+for (; i < l; i++) {
+  var e = TEST_INPUT[i];
+  var v = e.val;
+  var s = String(v);
+  assertTrue(s.includes(v), e.msg);
+  assertTrue(String.prototype.includes.call(v, v), e.msg);
+  assertTrue(String.prototype.includes.apply(v, [v]), e.msg);
+}
+
+// Test cases found in FF
+assertTrue("abc".includes("a"));
+assertTrue("abc".includes("b"));
+assertTrue("abc".includes("abc"));
+assertTrue("abc".includes("bc"));
+assertFalse("abc".includes("d"));
+assertFalse("abc".includes("abcd"));
+assertFalse("abc".includes("ac"));
+assertTrue("abc".includes("abc", 0));
+assertTrue("abc".includes("bc", 0));
+assertFalse("abc".includes("de", 0));
+assertTrue("abc".includes("bc", 1));
+assertTrue("abc".includes("c", 1));
+assertFalse("abc".includes("a", 1));
+assertFalse("abc".includes("abc", 1));
+assertTrue("abc".includes("c", 2));
+assertFalse("abc".includes("d", 2));
+assertFalse("abc".includes("dcd", 2));
+assertFalse("abc".includes("a", 42));
+assertFalse("abc".includes("a", Infinity));
+assertTrue("abc".includes("ab", -43));
+assertFalse("abc".includes("cd", -42));
+assertTrue("abc".includes("ab", -Infinity));
+assertFalse("abc".includes("cd", -Infinity));
+assertTrue("abc".includes("ab", NaN));
+assertFalse("abc".includes("cd", NaN));
+assertFalse("xyzzy".includes("zy\0", 2));
+
+var dots = Array(10000).join(".");
+assertFalse(dots.includes("\x01", 10000));
+assertFalse(dots.includes("\0", 10000));
+
+var myobj = {
+  toString: function () {
+    return "abc";
+  },
+  includes: String.prototype.includes
+};
+assertTrue(myobj.includes("abc"));
+assertFalse(myobj.includes("cd"));
+
+var gotStr = false;
+var gotPos = false;
+myobj = {
+  toString: function () {
+    assertFalse(gotPos);
+    gotStr = true;
+    return "xyz";
+  },
+  includes: String.prototype.includes
+};
+
+assertEquals("foo[a-z]+(bar)?".includes("[a-z]+"), true);
+assertThrows("'foo[a-z]+(bar)?'.includes(/[a-z]+/)", TypeError);
+assertThrows("'foo/[a-z]+/(bar)?'.includes(/[a-z]+/)", TypeError);
+assertEquals("foo[a-z]+(bar)?".includes("(bar)?"), true);
+assertThrows("'foo[a-z]+(bar)?'.includes(/(bar)?/)", TypeError);
+assertThrows("'foo[a-z]+/(bar)?/'.includes(/(bar)?/)", TypeError);
+
+assertThrows("String.prototype.includes.call({ 'toString': function() { " +
+  "throw RangeError(); } }, /./)", RangeError);
+assertThrows("String.prototype.includes.call({ 'toString': function() { " +
+  "return 'abc'; } }, /./)", TypeError);
+
+assertThrows("String.prototype.includes.apply({ 'toString': function() { " +
+  "throw RangeError(); } }, [/./])", RangeError);
+assertThrows("String.prototype.includes.apply({ 'toString': function() { " +
+  "return 'abc'; } }, [/./])", TypeError);
diff --git a/test/mjsunit/harmony/string-raw.js b/test/mjsunit/harmony/string-raw.js
new file mode 100644
index 0000000..28e2af9
--- /dev/null
+++ b/test/mjsunit/harmony/string-raw.js
@@ -0,0 +1,258 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-templates
+
+(function testStringRawArity() {
+  assertEquals(1, String.raw.length);
+})();
+
+
+(function testStringRawCallSiteToObject() {
+  assertThrows("String.raw()", TypeError);
+})();
+
+
+(function testStringRawCallSiteRawToObject() {
+  assertThrows("String.raw([])", TypeError);
+})();
+
+
+(function testStringRawUndefinedLength() {
+  var callSiteObj = [];
+  callSiteObj.raw = {};
+  assertEquals("", String.raw(callSiteObj));
+
+  callSiteObj.raw = { lengt: 0 };
+  assertEquals("", String.raw(callSiteObj));
+})();
+
+
+(function testStringRawZeroLength() {
+  var callSiteObj = [];
+  callSiteObj.raw = { length: 0 };
+  assertEquals("", String.raw(callSiteObj));
+  assertEquals("", String.raw(callSiteObj, "a", "b", "c"));
+
+  callSiteObj.raw = [];
+  assertEquals("", String.raw(callSiteObj));
+  assertEquals("", String.raw(callSiteObj, "a", "b", "c"));
+})();
+
+
+(function testStringRawNegativeLength() {
+  var callSiteObj = [];
+  callSiteObj.raw = { length: -85 };
+  assertEquals("", String.raw(callSiteObj));
+  assertEquals("", String.raw(callSiteObj, "a", "b", "c"));
+
+  callSiteObj.raw = [];
+  assertEquals("", String.raw(callSiteObj));
+  assertEquals("", String.raw(callSiteObj, "a", "b", "c"));
+})();
+
+
+(function testStringRawNaNLength() {
+  var callSiteObj = [];
+  callSiteObj.raw = { length: NaN };
+  assertEquals("", String.raw(callSiteObj));
+  assertEquals("", String.raw(callSiteObj, "a", "b", "c"));
+
+  callSiteObj.raw = [];
+  assertEquals("", String.raw(callSiteObj));
+  assertEquals("", String.raw(callSiteObj, "a", "b", "c"));
+})();
+
+
+(function testStringRawBasic() {
+  var callSiteObj = [];
+  callSiteObj.raw = ["a"];
+  assertEquals("a", String.raw(callSiteObj));
+})();
+
+
+(function testStringRawNoSubst() {
+  var callSiteObj = [];
+  callSiteObj.raw = ["a", "b"];
+  assertEquals("ab", String.raw(callSiteObj));
+})();
+
+
+(function testStringRawSubst() {
+  var callSiteObj = [];
+  callSiteObj.raw = ["a", "b"];
+  assertEquals("a!b", String.raw(callSiteObj, "!"));
+
+  callSiteObj.raw = ["a", "b", "c"];
+  assertEquals("abc", String.raw(callSiteObj));
+
+  callSiteObj.raw = ["a", "b", "c"];
+  assertEquals("a!bc", String.raw(callSiteObj, "!"));
+
+  callSiteObj.raw = ["a", "b", "c"];
+  assertEquals("a!b?c", String.raw(callSiteObj, "!", "?"));
+
+  callSiteObj.raw = ["\n", "\r\n", "\r"];
+  assertEquals("\nx\r\ny\r", String.raw(callSiteObj, "x", "y"));
+
+  callSiteObj.raw = ["\n", "\r\n", "\r"];
+  assertEquals("\n\r\r\r\n\n\r", String.raw(callSiteObj, "\r\r", "\n"));
+})();
+
+
+(function testStringRawArrayLikeSubst() {
+  var callSiteObj = [];
+  callSiteObj.raw = {"length": 2, "0": "a", "1": "b", "2": "c"};
+  assertEquals("axb", String.raw(callSiteObj, "x", "y"));
+
+  callSiteObj.raw = {"length": 4, "0": "a", "1": "b", "2": "c"};
+  assertEquals("axbycundefined", String.raw(callSiteObj, "x", "y"));
+})();
+
+
+(function testStringRawAccessors() {
+  var callSiteObj = {};
+  callSiteObj.raw = {};
+  Object.defineProperties(callSiteObj, {
+    "length": {
+      get: function() { assertUnreachable(); },
+      set: function(v) { assertUnreachable(); }
+    },
+    "0": {
+      get: function() { assertUnreachable(); },
+      set: function(v) { assertUnreachable(); }
+    },
+    "1": {
+      get: function() { assertUnreachable(); },
+      set: function(v) { assertUnreachable(); }
+    }
+  });
+  Object.defineProperties(callSiteObj.raw, {
+    "length": {
+      get: function() { return 2; },
+      set: function(v) { assertUnreachable(); }
+    },
+    "0": {
+      get: function() { return "getter values"; },
+      set: function(v) { assertUnreachable(); }
+    },
+    "1": {
+      get: function() { return "are nice"; },
+      set: function(v) { assertUnreachable(); }
+    }
+  });
+  assertEquals("getter values are nice", String.raw(callSiteObj, " "));
+})();
+
+
+(function testStringRawHoleyArray() {
+  var callSiteObj = [];
+  callSiteObj.raw = ["1."];
+  callSiteObj.raw[2] = ".2";
+  assertEquals("1.undefined.2", String.raw(callSiteObj));
+})();
+
+
+(function testStringRawAccessorThrows() {
+  var callSiteObj = [];
+  callSiteObj.raw = [1];
+  function MyError() {}
+  Object.defineProperty(callSiteObj.raw, "0", {
+    get: function() { throw new MyError(); }
+  });
+  assertThrows(function() { String.raw(callSiteObj); }, MyError);
+})();
+
+
+(function testStringRawToStringSafe() {
+  var callSiteObj = [];
+  callSiteObj.raw = [null, undefined, 1, "str", true, false, NaN, Infinity, {}];
+  assertEquals("nullundefined1strtruefalseNaNInfinity[object Object]",
+               String.raw(callSiteObj));
+
+  callSiteObj.raw = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
+  assertEquals("0null1undefined213str4true5false6NaN7Infinity8[object Object]9",
+               String.raw(callSiteObj, null, void 0, 1, "str", true, false,
+               NaN, Infinity, {}));
+})();
+
+
+(function testStringRawToStringSymbolThrows() {
+  var callSiteObj = [];
+  callSiteObj.raw = [Symbol("foo")];
+  assertThrows(function() {
+    String.raw(callSiteObj);
+  }, TypeError);
+
+  callSiteObj.raw = ["1", "2"];
+  assertThrows(function() {
+    String.raw(callSiteObj, Symbol("foo"));
+  }, TypeError);
+})();
+
+
+(function testStringRawToStringThrows() {
+  var callSiteObj = [];
+  var thrower = {};
+  function MyError() {}
+  thrower.toString = function() {
+    throw new MyError();
+  }
+
+  callSiteObj.raw = [thrower];
+  assertThrows(function() {
+    String.raw(callSiteObj);
+  }, MyError);
+
+  callSiteObj.raw = ["1", "2"];
+  assertThrows(function() {
+    String.raw(callSiteObj, thrower);
+  }, MyError);
+})();
+
+
+(function testStringRawToStringValueOfThrows() {
+  var callSiteObj = [];
+  var thrower = {};
+  function MyError() {}
+  thrower.toString = null;
+  thrower.valueOf = function() {
+    throw new MyError();
+  }
+
+  callSiteObj.raw = [thrower];
+  assertThrows(function() {
+    String.raw(callSiteObj);
+  }, MyError);
+
+  callSiteObj.raw = ["1", "2"];
+  assertThrows(function() {
+    String.raw(callSiteObj, thrower);
+  }, MyError);
+})();
+
+
+(function testStringRawOrder() {
+  var order = [];
+  var callSiteObj = [];
+  callSiteObj.raw = {};
+  function arg(v) {
+    var result = {};
+    result.toString = null;
+    result.valueOf = function() { order.push("arg" + v); return v; }
+    return result;
+  }
+
+  Object.defineProperty(callSiteObj.raw, "length", {
+    get: function() { order.push("length"); return 3; }
+  });
+  [1, 3, 5].forEach(function(v, i) {
+    Object.defineProperty(callSiteObj.raw, i, {
+      get: function() { order.push("raw" + v); return v; }
+    });
+  });
+
+  assertEquals("12345", String.raw(callSiteObj, arg(2), arg(4), arg(6)));
+  assertEquals(["length", "raw1", "arg2", "raw3", "arg4", "raw5"], order);
+})();
diff --git a/test/mjsunit/harmony/string-repeat.js b/test/mjsunit/harmony/string-repeat.js
index 761089b..0af7448 100644
--- a/test/mjsunit/harmony/string-repeat.js
+++ b/test/mjsunit/harmony/string-repeat.js
@@ -61,8 +61,11 @@
 assertEquals("", "abc".repeat(0));
 assertEquals("abcabc", "abc".repeat(2.0));
 
+assertEquals("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "a".repeat(37));
 assertThrows('"a".repeat(-1)', RangeError);
 assertThrows('"a".repeat(Number.POSITIVE_INFINITY)', RangeError);
+assertThrows('"a".repeat(Math.pow(2, 30))', RangeError);
+assertThrows('"a".repeat(Math.pow(2, 40))', RangeError);
 
 var myobj = {
   toString: function() {
diff --git a/test/mjsunit/harmony/super.js b/test/mjsunit/harmony/super.js
index 89fb4b1..6dcc393 100644
--- a/test/mjsunit/harmony/super.js
+++ b/test/mjsunit/harmony/super.js
@@ -18,6 +18,8 @@
 
   function fDerived() {
      assertEquals("Base this is Derived", super.f());
+     var a = super.x;
+     assertEquals(15, a);
      assertEquals(15, super.x);
      assertEquals(27, this.x);
 
@@ -34,6 +36,77 @@
   assertEquals("Derived", new Derived().f());
 }());
 
+
+(function TestSuperKeyedLoads() {
+  var x = 'x';
+  var derivedDataProperty = 'derivedDataProperty';
+  var f = 'f';
+  function Base() { }
+  function Derived() {
+    this[derivedDataProperty] = 'xxx';
+  }
+  Derived.prototype = Object.create(Base.prototype);
+
+  function fBase() { return "Base " + this.toString(); }
+
+  Base.prototype[f] = fBase.toMethod(Base.prototype);
+
+  function fDerived() {
+     assertEquals("Base this is Derived", super[f]());
+     var a = super[x];
+     assertEquals(15, a);
+     assertEquals(15, super[x]);
+     assertEquals(27, this[x]);
+
+     return "Derived"
+  }
+
+  Base.prototype[x] = 15;
+  Base.prototype.toString = function() { return "this is Base"; };
+  Derived.prototype.toString = function() { return "this is Derived"; };
+  Derived.prototype[x] = 27;
+  Derived.prototype[f] = fDerived.toMethod(Derived.prototype);
+
+  assertEquals("Base this is Base", new Base().f());
+  assertEquals("Derived", new Derived().f());
+}());
+
+
+(function TestSuperNumericKeyedLoads() {
+  var x = 1;
+  var derivedDataProperty = 2;
+  var f = 3;
+  function Base() { }
+  function Derived() {
+    this[derivedDataProperty] = 'xxx';
+  }
+  Derived.prototype = Object.create(Base.prototype);
+
+  function fBase() { return "Base " + this.toString(); }
+
+  Base.prototype[f] = fBase.toMethod(Base.prototype);
+
+  function fDerived() {
+     assertEquals("Base this is Derived", super[f]());
+     var a = super[x];
+     assertEquals(15, a);
+     assertEquals(15, super[x]);
+     assertEquals(27, this[x]);
+
+     return "Derived"
+  }
+
+  Base.prototype[x] = 15;
+  Base.prototype.toString = function() { return "this is Base"; };
+  Derived.prototype.toString = function() { return "this is Derived"; };
+  Derived.prototype[x] = 27;
+  Derived.prototype[f] = fDerived.toMethod(Derived.prototype);
+
+  assertEquals("Base this is Base", new Base()[f]());
+  assertEquals("Derived", new Derived()[f]());
+}());
+
+
 (function TestSuperKeywordNonMethod() {
   function f() {
     super.unknown();
@@ -65,12 +138,149 @@
   Derived.prototype.testGetter = function() {
     return super.x;
   }.toMethod(Derived.prototype);
+  Derived.prototype.testGetterStrict = function() {
+    'use strict';
+    return super.x;
+  }.toMethod(Derived.prototype);
   derived = new Derived();
   assertEquals('derived', derived.testGetter());
+  derived = new Derived();
+  assertEquals('derived', derived.testGetterStrict());
 }());
 
-/*
- * TODO[dslomov]: named stores and keyed loads/stores not implemented yet.
+
+(function TestGetterKeyed() {
+  var x = 'x';
+  function Base() {}
+  var derived;
+  Base.prototype = {
+    constructor: Base,
+    get x() {
+      assertSame(this, derived);
+      return this._x;
+    },
+    _x: 'base'
+  };
+
+  function Derived() {}
+  Derived.__proto__ = Base;
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+    _x: 'derived'
+  };
+  Derived.prototype.testGetter = function() {
+    return super[x];
+  }.toMethod(Derived.prototype);
+  Derived.prototype.testGetterStrict = function() {
+    'use strict';
+    return super[x];
+  }.toMethod(Derived.prototype);
+  Derived.prototype.testGetterWithToString = function() {
+    var toStringCalled;
+    var o = { toString: function() {
+      toStringCalled++;
+      return 'x';
+    } };
+
+    toStringCalled = 0;
+    assertEquals('derived', super[o]);
+    assertEquals(1, toStringCalled);
+
+    var eToThrow = new Error();
+    var oThrowsInToString = { toString: function() {
+      throw eToThrow;
+    } };
+
+    var ex = null;
+    try {
+      super[oThrowsInToString];
+    } catch(e) { ex = e }
+    assertEquals(eToThrow, ex);
+
+    var oReturnsNumericString = { toString: function() {
+      return "1";
+    } };
+
+    assertEquals(undefined, super[oReturnsNumericString]);
+    assertEquals(undefined, super[1]);
+  }.toMethod(Derived.prototype);
+  derived = new Derived();
+  assertEquals('derived', derived.testGetter());
+  derived = new Derived();
+  assertEquals('derived', derived.testGetterStrict());
+  derived = new Derived();
+  derived.testGetterWithToString();
+}());
+
+
+(function TestGetterNumericKeyed() {
+  var x = 42;
+  function Base() {}
+  var derived;
+  Base.prototype = {
+    constructor: Base,
+    _x: 'base'
+  };
+
+  Object.defineProperty(Base.prototype, x, { get: function() {
+      assertSame(this, derived);
+      return this._x;
+  }});
+
+  function Derived() {}
+  Derived.__proto__ = Base;
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+    _x: 'derived'
+  };
+  Derived.prototype.testGetter = function() {
+    return super[x];
+  }.toMethod(Derived.prototype);
+  Derived.prototype.testGetterStrict = function() {
+    'use strict';
+    return super[x];
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testGetterWithToString = function() {
+    var toStringCalled;
+    var o = { toString: function() {
+      toStringCalled++;
+      return '42';
+    } };
+
+    toStringCalled = 0;
+    assertEquals('derived', super[o]);
+    assertEquals(1, toStringCalled);
+
+    var eToThrow = new Error();
+    var oThrowsInToString = { toString: function() {
+      throw eToThrow;
+    } };
+
+    var ex = null;
+    try {
+      super[oThrowsInToString];
+    } catch(e) { ex = e }
+    assertEquals(eToThrow, ex);
+
+    var oReturnsNumericString = { toString: function() {
+      return "42";
+    } };
+
+    assertEquals('derived', super[oReturnsNumericString]);
+    assertEquals('derived', super[42]);
+  }.toMethod(Derived.prototype);
+  derived = new Derived();
+  assertEquals('derived', derived.testGetter());
+  derived = new Derived();
+  assertEquals('derived', derived.testGetterStrict());
+  derived = new Derived();
+  derived.testGetterWithToString();
+}());
+
+
 (function TestSetter() {
   function Base() {}
   Base.prototype = {
@@ -92,24 +302,37 @@
     _x: 'derived'
   };
   Derived.prototype.testSetter = function() {
-      super.x = 'foobar';
-    }.toMethod(Derived.prototype);
+    assertEquals('foobar', super.x = 'foobar');
+    assertEquals('foobarabc', super.x += 'abc');
+  }.toMethod(Derived.prototype);
   var d = new Derived();
   d.testSetter();
   assertEquals('base', Base.prototype._x);
-  assertEquals('foobar', d._x);
+  assertEquals('foobarabc', d._x);
+  d._x = '';
+  Derived.prototype.testSetterStrict = function() {
+    'use strict';
+    assertEquals('foobar', super.x = 'foobar');
+    assertEquals('foobarabc', super.x += 'abc');
+  }.toMethod(Derived.prototype);
+  d.testSetterStrict();
+  assertEquals('base', Base.prototype._x);
+  assertEquals('foobarabc', d._x);
 }());
 
 
-(function TestKeyedGetter() {
+(function TestSetterNumericKeyed() {
+  var x = 42;
   function Base() {}
   Base.prototype = {
     constructor: Base,
     _x: 'base'
   };
 
-  Object.defineProperty(Base.prototype, '0',
-        { get: function() { return this._x; } });
+  Object.defineProperty(Base.prototype, x,
+    { get: function() { return this._x; },
+      set: function(v) { this._x = v; }
+    });
 
   function Derived() {}
   Derived.__proto__ = Base;
@@ -118,10 +341,1581 @@
     constructor: Derived,
     _x: 'derived'
   };
-  Derived.prototype.testGetter = function() {
-      return super[0];
-    }.toMethod(Derived.prototype);
-  assertEquals('derived', new Derived()[0]);
-  // assertEquals('derived', new Derived().testGetter());
+  Derived.prototype.testSetter = function() {
+    assertEquals('foobar', super[x] = 'foobar');
+    assertEquals('foobarabc', super[x] += 'abc');
+  }.toMethod(Derived.prototype);
+  var d = new Derived();
+  d.testSetter();
+  assertEquals('base', Base.prototype._x);
+  assertEquals('foobarabc', d._x);
+  d._x = '';
+  Derived.prototype.testSetterStrict = function() {
+    'use strict';
+    assertEquals('foobar', super[x] = 'foobar');
+    assertEquals('foobarabc', super[x] += 'abc');
+  }.toMethod(Derived.prototype);
+  d.testSetterStrict();
+  assertEquals('base', Base.prototype._x);
+  assertEquals('foobarabc', d._x);
+
+
+  Derived.prototype.testSetterWithToString = function() {
+    var toStringCalled;
+    var o = { toString: function() {
+      toStringCalled++;
+      return x;
+    } };
+
+    toStringCalled = 0;
+    super[o] = 'set';
+    assertEquals(1, toStringCalled);
+    assertEquals('set', this._x);
+
+    var eToThrow = new Error();
+    var oThrowsInToString = { toString: function() {
+      throw eToThrow;
+    } };
+
+    var ex = null;
+    try {
+      super[oThrowsInToString] = 'xyz';
+    } catch(e) { ex = e }
+    assertEquals(eToThrow, ex);
+    assertEquals('set', this._x);
+  }.toMethod(Derived.prototype);
+  d = new Derived();
+  d.testSetterWithToString();
 }());
-*/
+
+
+(function TestSetterKeyed() {
+  var x = 'x';
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    get x() {
+      return this._x;
+    },
+    set x(v) {
+      this._x = v;
+    },
+    _x: 'base'
+  };
+
+  function Derived() {}
+  Derived.__proto__ = Base;
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+    _x: 'derived'
+  };
+  Derived.prototype.testSetter = function() {
+    assertEquals('foobar', super[x] = 'foobar');
+    assertEquals('foobarabc', super[x] += 'abc');
+  }.toMethod(Derived.prototype);
+  var d = new Derived();
+  d.testSetter();
+  assertEquals('base', Base.prototype._x);
+  assertEquals('foobarabc', d._x);
+  d._x = '';
+  Derived.prototype.testSetterStrict = function() {
+    'use strict';
+    assertEquals('foobar', super[x] = 'foobar');
+    assertEquals('foobarabc', super[x] += 'abc');
+  }.toMethod(Derived.prototype);
+  d.testSetterStrict();
+  assertEquals('base', Base.prototype._x);
+  assertEquals('foobarabc', d._x);
+
+
+  Derived.prototype.testSetterWithToString = function() {
+    var toStringCalled;
+    var o = { toString: function() {
+      toStringCalled++;
+      return 'x';
+    } };
+
+    toStringCalled = 0;
+    super[o] = 'set';
+    assertEquals(1, toStringCalled);
+    assertEquals('set', this._x);
+
+    var eToThrow = new Error();
+    var oThrowsInToString = { toString: function() {
+      throw eToThrow;
+    } };
+
+    var ex = null;
+    try {
+      super[oThrowsInToString] = 'xyz';
+    } catch(e) { ex = e }
+    assertEquals(eToThrow, ex);
+    assertEquals('set', this._x);
+
+    var oReturnsNumericString = { toString: function() {
+      return "1";
+    } };
+
+    assertEquals('abc', super[oReturnsNumericString] = 'abc');
+
+    assertEquals('set', this._x);
+
+    assertEquals(10,  super[1] = 10);
+  }.toMethod(Derived.prototype);
+  d = new Derived();
+  d.testSetterWithToString();
+}());
+
+
+(function TestSetterDataProperties() {
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    x: 'x from Base'
+  };
+
+  function Derived() {}
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+
+  Derived.prototype.testSetter = function() {
+    assertEquals('x from Base', super.x);
+    super.x = 'data property';
+    assertEquals('x from Base', super.x);
+    assertEquals('data property', this.x);
+  }.toMethod(Derived.prototype);
+
+  new Derived().testSetter();
+}());
+
+
+(function TestKeyedSetterDataProperties() {
+  var x = 'x';
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    x: 'x from Base'
+  };
+
+  function Derived() {}
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+
+  Derived.prototype.testSetter = function() {
+    assertEquals('x from Base', super[x]);
+    super[x] = 'data property';
+    assertEquals('x from Base', super[x]);
+    assertEquals('data property', this[x]);
+  }.toMethod(Derived.prototype);
+
+  new Derived().testSetter();
+}());
+
+
+(function TestKeyedNumericSetterDataProperties() {
+  var x = 42;
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    42: 'x from Base'
+  };
+
+  function Derived() {}
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+
+  Derived.prototype.testSetter = function() {
+    assertEquals('x from Base', super[x]);
+    super[x] = 'data property';
+    assertEquals('x from Base', super[x]);
+    assertEquals('data property', this[x]);
+  }.toMethod(Derived.prototype);
+
+  new Derived().testSetter();
+}());
+
+
+(function TestAccessorsOnPrimitives() {
+  var getCalled = 0;
+  var setCalled = 0;
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    get x() {
+      getCalled++;
+      return 1;
+    },
+    set x(v) {
+      setCalled++;
+      return v;
+    },
+  };
+
+  function Derived() {}
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+  Derived.prototype.testSetter = function() {
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals('object', typeof this);
+    assertTrue(this instanceof Number)
+    assertEquals(42, this.valueOf());
+    assertEquals(1, super.x);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    assertEquals(5, super.x = 5);
+    assertEquals(1, getCalled);
+    assertEquals(1, setCalled);
+
+    assertEquals(6, super.x += 5);
+    assertEquals(2, getCalled);
+    assertEquals(2, setCalled);
+
+    super.newProperty = 15;
+    assertEquals(15, this.newProperty);
+    assertEquals(undefined, super.newProperty);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testSetterStrict = function() {
+    'use strict';
+    getCalled = 0;
+    setCalled = 0;
+    assertTrue(42 === this);
+
+    assertEquals(1, super.x);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    assertEquals(5, super.x = 5);
+    assertEquals(1, getCalled);
+    assertEquals(1, setCalled);
+
+    assertEquals(6, super.x += 5);
+    assertEquals(2, getCalled);
+    assertEquals(2, setCalled);
+
+    var ex;
+    try {
+      super.newProperty = 15;
+    } catch (e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testSetter.call(42);
+  Derived.prototype.testSetterStrict.call(42);
+
+  function DerivedFromString() {}
+  DerivedFromString.prototype = Object.create(String.prototype);
+
+  function f() {
+    'use strict';
+    assertTrue(42 === this);
+    assertEquals(String.prototype.toString, super.toString);
+    var ex;
+    try {
+      super.toString();
+    } catch(e) { ex = e; }
+
+    assertTrue(ex instanceof TypeError);
+  }
+  f.toMethod(DerivedFromString.prototype).call(42);
+}());
+
+
+(function TestKeyedAccessorsOnPrimitives() {
+  var x = 'x';
+  var newProperty = 'newProperty';
+  var toString = 'toString';
+  var getCalled = 0;
+  var setCalled = 0;
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    get x() {
+      getCalled++;
+      return 1;
+    },
+    set x(v) {
+      setCalled++;
+      return v;
+    },
+  };
+
+  function Derived() {}
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+  Derived.prototype.testSetter = function() {
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals('object', typeof this);
+    assertTrue(this instanceof Number)
+    assertEquals(42, this.valueOf());
+    assertEquals(1, super[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    assertEquals(5, super[x] = 5);
+    assertEquals(1, getCalled);
+    assertEquals(1, setCalled);
+
+    assertEquals(6, super[x] += 5);
+    assertEquals(2, getCalled);
+    assertEquals(2, setCalled);
+
+    super[newProperty] = 15;
+    assertEquals(15, this[newProperty]);
+    assertEquals(undefined, super[newProperty]);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testSetterStrict = function() {
+    'use strict';
+    getCalled = 0;
+    setCalled = 0;
+    assertTrue(42 === this);
+
+    assertEquals(1, super[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    assertEquals(5, super[x] = 5);
+    assertEquals(1, getCalled);
+    assertEquals(1, setCalled);
+
+    assertEquals(6, super[x] += 5);
+    assertEquals(2, getCalled);
+    assertEquals(2, setCalled);
+
+    var ex;
+    try {
+      super[newProperty] = 15;
+    } catch (e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testSetter.call(42);
+  Derived.prototype.testSetterStrict.call(42);
+
+  function DerivedFromString() {}
+  DerivedFromString.prototype = Object.create(String.prototype);
+
+  function f() {
+    'use strict';
+    assertTrue(42 === this);
+    assertEquals(String.prototype.toString, super[toString]);
+    var ex;
+    try {
+      super[toString]();
+    } catch(e) { ex = e; }
+
+    assertTrue(ex instanceof TypeError);
+  }
+  f.toMethod(DerivedFromString.prototype).call(42);
+}());
+
+
+(function TestNumericKeyedAccessorsOnPrimitives() {
+  var x = 42;
+  var newProperty = 43;
+  var getCalled = 0;
+  var setCalled = 0;
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+  };
+
+  Object.defineProperty(Base.prototype, x, {
+    get: function() {
+      getCalled++;
+      return 1;
+    },
+    set: function(v) {
+      setCalled++;
+      return v;
+    }
+  });
+
+  function Derived() {}
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+  Derived.prototype.testSetter = function() {
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals('object', typeof this);
+    assertTrue(this instanceof Number)
+    assertEquals(42, this.valueOf());
+    assertEquals(1, super[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    assertEquals(5, super[x] = 5);
+    assertEquals(1, getCalled);
+    assertEquals(1, setCalled);
+
+    assertEquals(6, super[x] += 5);
+    assertEquals(2, getCalled);
+    assertEquals(2, setCalled);
+
+    super[newProperty] = 15;
+    assertEquals(15, this[newProperty]);
+    assertEquals(undefined, super[newProperty]);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testSetterStrict = function() {
+    'use strict';
+    getCalled = 0;
+    setCalled = 0;
+    assertTrue(42 === this);
+
+    assertEquals(1, super[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    assertEquals(5, super[x] = 5);
+    assertEquals(1, getCalled);
+    assertEquals(1, setCalled);
+
+    assertEquals(6, super[x] += 5);
+    assertEquals(2, getCalled);
+    assertEquals(2, setCalled);
+
+    var ex;
+    try {
+      super[newProperty] = 15;
+    } catch (e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testSetter.call(42);
+  Derived.prototype.testSetterStrict.call(42);
+}());
+
+
+(function TestKeyedNumericSetterOnExotics() {
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__: Base.prototype };
+
+  Derived.prototype.callSetterOnArray = function() {
+    super[42] = 1;
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.callStrictSetterOnString = function() {
+    'use strict';
+    assertEquals('string', typeof this);
+    assertTrue('abcdef' === this);
+    var ex = null;
+    try {
+      super[5] = 'q';
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+
+    ex = null;
+    try {
+      super[1024] = 'q';
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+  }.toMethod(Derived.prototype);
+
+  var x = [];
+  assertEquals(0, x.length);
+  Derived.prototype.callSetterOnArray.call(x);
+  assertEquals(43, x.length);
+  assertEquals(1, x[42]);
+
+  var s = 'abcdef';
+  Derived.prototype.callStrictSetterOnString.call(s)
+}());
+
+
+(function TestSetterUndefinedProperties() {
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__ : Base.prototype };
+  Derived.prototype.mSloppy = function () {
+    assertEquals(undefined, super.x);
+    assertEquals(undefined, this.x);
+    super.x = 10;
+    assertEquals(10, this.x);
+    assertEquals(undefined, super.x);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function () {
+    'use strict';
+    assertEquals(undefined, super.x);
+    assertEquals(undefined, this.x);
+    super.x = 10;
+    assertEquals(10, this.x);
+    assertEquals(undefined, super.x);
+  }.toMethod(Derived.prototype);
+  var d = new Derived();
+  d.mSloppy();
+  assertEquals(10, d.x);
+  var d1 = new Derived();
+  d1.mStrict();
+  assertEquals(10, d.x);
+}());
+
+
+(function TestKeyedSetterUndefinedProperties() {
+  var x = 'x';
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__ : Base.prototype };
+  Derived.prototype.mSloppy = function () {
+    assertEquals(undefined, super[x]);
+    assertEquals(undefined, this[x]);
+    super[x] = 10;
+    assertEquals(10, this[x]);
+    assertEquals(undefined, super[x]);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function () {
+    'use strict';
+    assertEquals(undefined, super[x]);
+    assertEquals(undefined, this[x]);
+    super[x] = 10;
+    assertEquals(10, this[x]);
+    assertEquals(undefined, super[x]);
+  }.toMethod(Derived.prototype);
+  var d = new Derived();
+  d.mSloppy();
+  assertEquals(10, d.x);
+  var d1 = new Derived();
+  d1.mStrict();
+  assertEquals(10, d.x);
+}());
+
+
+(function TestKeyedNumericSetterUndefinedProperties() {
+  var x = 42;
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__ : Base.prototype };
+  Derived.prototype.mSloppy = function () {
+    assertEquals(undefined, super[x]);
+    assertEquals(undefined, this[x]);
+    super[x] = 10;
+    assertEquals(10, this[x]);
+    assertEquals(undefined, super[x]);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function () {
+    'use strict';
+    assertEquals(undefined, super[x]);
+    assertEquals(undefined, this[x]);
+    super[x] = 10;
+    assertEquals(10, this[x]);
+    assertEquals(undefined, super[x]);
+  }.toMethod(Derived.prototype);
+  var d = new Derived();
+  d.mSloppy();
+  assertEquals(10, d[x]);
+  var d1 = new Derived();
+  d1.mStrict();
+  assertEquals(10, d[x]);
+}());
+
+
+(function TestSetterCreatingOwnProperties() {
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__ : Base.prototype };
+  var setterCalled;
+
+  Derived.prototype.mSloppy = function() {
+    assertEquals(42, this.ownReadOnly);
+    super.ownReadOnly = 55;
+    assertEquals(42, this.ownReadOnly);
+
+    assertEquals(15, this.ownReadonlyAccessor);
+    super.ownReadonlyAccessor = 55;
+    assertEquals(15, this.ownReadonlyAccessor);
+
+    setterCalled = 0;
+    super.ownSetter = 42;
+    assertEquals(1, setterCalled);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    assertEquals(42, this.ownReadOnly);
+    var ex;
+    try {
+      super.ownReadOnly = 55;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(42, this.ownReadOnly);
+
+    assertEquals(15, this.ownReadonlyAccessor);
+    ex = null;
+    try {
+      super.ownReadonlyAccessor = 55;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(15, this.ownReadonlyAccessor);
+
+    setterCalled = 0;
+    super.ownSetter = 42;
+    assertEquals(1, setterCalled);
+  }.toMethod(Derived.prototype);
+
+  var d = new Derived();
+  Object.defineProperty(d, 'ownReadOnly', { value : 42, writable : false });
+  Object.defineProperty(d, 'ownSetter',
+      { set : function() { setterCalled++; } });
+  Object.defineProperty(d, 'ownReadonlyAccessor',
+      { get : function() { return 15; }});
+  d.mSloppy();
+  d.mStrict();
+}());
+
+
+(function TestSetterInForIn() {
+  var setCalled = 0;
+  var getCalled = 0;
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    get x() {
+      getCalled++;
+      return 1;
+    },
+    set x(v) {
+      setCalled++;
+      this.x_.push(v);
+    },
+  };
+
+  function Derived() {
+    this.x_ = [];
+  }
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+
+  Derived.prototype.testIter = function() {
+    setCalled = 0;
+    getCalled = 0;
+    for (super.x in [1,2,3]) {}
+    assertEquals(0, getCalled);
+    assertEquals(3, setCalled);
+    assertEquals(["0","1","2"], this.x_);
+  }.toMethod(Derived.prototype);
+
+  new Derived().testIter();
+
+  var x = 'x';
+  Derived.prototype.testIterKeyed = function() {
+    setCalled = 0;
+    getCalled = 0;
+    for (super[x] in [1,2,3]) {}
+    assertEquals(0, getCalled);
+    assertEquals(3, setCalled);
+    assertEquals(["0","1","2"], this.x_);
+
+    this.x_ = [];
+    setCalled = 0;
+    getCalled = 0;
+    var toStringCalled = 0;
+    var o = {toString: function () { toStringCalled++; return x }};
+    for (super[o] in [1,2,3]) {}
+    assertEquals(0, getCalled);
+    assertEquals(3, setCalled);
+    assertEquals(3, toStringCalled);
+    assertEquals(["0","1","2"], this.x_);
+  }.toMethod(Derived.prototype);
+
+  new Derived().testIterKeyed();
+}());
+
+
+(function TestKeyedSetterCreatingOwnProperties() {
+  var ownReadOnly = 'ownReadOnly';
+  var ownReadonlyAccessor = 'ownReadonlyAccessor';
+  var ownSetter = 'ownSetter';
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__ : Base.prototype };
+  var setterCalled;
+
+  Derived.prototype.mSloppy = function() {
+    assertEquals(42, this[ownReadOnly]);
+    super[ownReadOnly] = 55;
+    assertEquals(42, this[ownReadOnly]);
+
+    assertEquals(15, this[ownReadonlyAccessor]);
+    super[ownReadonlyAccessor] = 55;
+    assertEquals(15, this[ownReadonlyAccessor]);
+
+    setterCalled = 0;
+    super[ownSetter] = 42;
+    assertEquals(1, setterCalled);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    assertEquals(42, this[ownReadOnly]);
+    var ex;
+    try {
+      super[ownReadOnly] = 55;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(42, this[ownReadOnly]);
+
+    assertEquals(15, this[ownReadonlyAccessor]);
+    ex = null;
+    try {
+      super[ownReadonlyAccessor] = 55;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(15, this[ownReadonlyAccessor]);
+
+    setterCalled = 0;
+    super[ownSetter] = 42;
+    assertEquals(1, setterCalled);
+  }.toMethod(Derived.prototype);
+
+  var d = new Derived();
+  Object.defineProperty(d, 'ownReadOnly', { value : 42, writable : false });
+  Object.defineProperty(d, 'ownSetter',
+      { set : function() { setterCalled++; } });
+  Object.defineProperty(d, 'ownReadonlyAccessor',
+      { get : function() { return 15; }});
+  d.mSloppy();
+  d.mStrict();
+}());
+
+
+(function TestKeyedNumericSetterCreatingOwnProperties() {
+  var ownReadOnly = 42;
+  var ownReadonlyAccessor = 43;
+  var ownSetter = 44;
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__ : Base.prototype };
+  var setterCalled;
+
+  Derived.prototype.mSloppy = function() {
+    assertEquals(42, this[ownReadOnly]);
+    super[ownReadOnly] = 55;
+    assertEquals(42, this[ownReadOnly]);
+
+    assertEquals(15, this[ownReadonlyAccessor]);
+    super[ownReadonlyAccessor] = 55;
+    assertEquals(15, this[ownReadonlyAccessor]);
+
+    setterCalled = 0;
+    super[ownSetter] = 42;
+    assertEquals(1, setterCalled);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    assertEquals(42, this[ownReadOnly]);
+    var ex;
+    try {
+      super[ownReadOnly] = 55;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(42, this[ownReadOnly]);
+
+    assertEquals(15, this[ownReadonlyAccessor]);
+    ex = null;
+    try {
+      super[ownReadonlyAccessor] = 55;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(15, this[ownReadonlyAccessor]);
+
+    setterCalled = 0;
+    super[ownSetter] = 42;
+    assertEquals(1, setterCalled);
+  }.toMethod(Derived.prototype);
+
+  var d = new Derived();
+  Object.defineProperty(d, ownReadOnly, { value : 42, writable : false });
+  Object.defineProperty(d, ownSetter,
+      { set : function() { setterCalled++; } });
+  Object.defineProperty(d, ownReadonlyAccessor,
+      { get : function() { return 15; }});
+  d.mSloppy();
+  d.mStrict();
+}());
+
+
+(function TestSetterNoProtoWalk() {
+  function Base() {}
+  function Derived() {}
+  var getCalled;
+  var setCalled;
+  Derived.prototype = {
+    __proto__ : Base.prototype,
+    get x() { getCalled++; return 42; },
+    set x(v) { setCalled++; }
+  };
+
+  Derived.prototype.mSloppy = function() {
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals(42, this.x);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    this.x = 43;
+    assertEquals(0, getCalled);
+    assertEquals(1, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    super.x = 15;
+    assertEquals(0, setCalled);
+    assertEquals(0, getCalled);
+
+    assertEquals(15, this.x);
+    assertEquals(0, getCalled);
+    assertEquals(0, setCalled);
+
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals(42, this.x);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    this.x = 43;
+    assertEquals(0, getCalled);
+    assertEquals(1, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    super.x = 15;
+    assertEquals(0, setCalled);
+    assertEquals(0, getCalled);
+
+    assertEquals(15, this.x);
+    assertEquals(0, getCalled);
+    assertEquals(0, setCalled);
+
+  }.toMethod(Derived.prototype);
+
+  new Derived().mSloppy();
+  new Derived().mStrict();
+}());
+
+
+(function TestKeyedSetterNoProtoWalk() {
+  var x = 'x';
+  function Base() {}
+  function Derived() {}
+  var getCalled;
+  var setCalled;
+  Derived.prototype = {
+    __proto__ : Base.prototype,
+    get x() { getCalled++; return 42; },
+    set x(v) { setCalled++; }
+  };
+
+  Derived.prototype.mSloppy = function() {
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals(42, this[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    this[x] = 43;
+    assertEquals(0, getCalled);
+    assertEquals(1, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    super[x] = 15;
+    assertEquals(0, setCalled);
+    assertEquals(0, getCalled);
+
+    assertEquals(15, this[x]);
+    assertEquals(0, getCalled);
+    assertEquals(0, setCalled);
+
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals(42, this[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    this[x] = 43;
+    assertEquals(0, getCalled);
+    assertEquals(1, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    super[x] = 15;
+    assertEquals(0, setCalled);
+    assertEquals(0, getCalled);
+
+    assertEquals(15, this[x]);
+    assertEquals(0, getCalled);
+    assertEquals(0, setCalled);
+
+  }.toMethod(Derived.prototype);
+
+  new Derived().mSloppy();
+  new Derived().mStrict();
+}());
+
+
+(function TestKeyedNumericSetterNoProtoWalk() {
+  var x = 42;
+  function Base() {}
+  function Derived() {}
+  var getCalled;
+  var setCalled;
+  Derived.prototype = {
+    __proto__ : Base.prototype,
+  };
+
+  Object.defineProperty(Derived.prototype, x, {
+    get: function() { getCalled++; return 42; },
+    set: function(v) { setCalled++; }
+  });
+
+  Derived.prototype.mSloppy = function() {
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals(42, this[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    this[x] = 43;
+    assertEquals(0, getCalled);
+    assertEquals(1, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    super[x] = 15;
+    assertEquals(0, setCalled);
+    assertEquals(0, getCalled);
+
+    assertEquals(15, this[x]);
+    assertEquals(0, getCalled);
+    assertEquals(0, setCalled);
+
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals(42, this[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    this[x] = 43;
+    assertEquals(0, getCalled);
+    assertEquals(1, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    super[x] = 15;
+    assertEquals(0, setCalled);
+    assertEquals(0, getCalled);
+
+    assertEquals(15, this[x]);
+    assertEquals(0, getCalled);
+    assertEquals(0, setCalled);
+
+  }.toMethod(Derived.prototype);
+
+  new Derived().mSloppy();
+  new Derived().mStrict();
+}());
+
+
+(function TestSetterDoesNotReconfigure() {
+  function Base() {}
+  function Derived() {}
+
+  Derived.prototype.mStrict = function (){
+    'use strict';
+    super.nonEnumConfig = 5;
+    var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumConfig');
+    assertEquals(5, d1.value);
+    assertTrue(d1.configurable);
+    assertFalse(d1.enumerable);
+
+    super.nonEnumNonConfig = 5;
+    var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumNonConfig');
+    assertEquals(5, d1.value);
+    assertFalse(d1.configurable);
+    assertFalse(d1.enumerable);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mSloppy = function (){
+    super.nonEnumConfig = 42;
+    var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumConfig');
+    assertEquals(42, d1.value);
+    assertTrue(d1.configurable);
+    assertFalse(d1.enumerable);
+
+    super.nonEnumNonConfig = 42;
+    var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumNonConfig');
+    assertEquals(42, d1.value);
+    assertFalse(d1.configurable);
+    assertFalse(d1.enumerable);
+  }.toMethod(Derived.prototype);
+
+  var d = new Derived();
+  Object.defineProperty(d, 'nonEnumConfig',
+      { value : 0, enumerable : false, configurable : true, writable : true });
+  Object.defineProperty(d, 'nonEnumNonConfig',
+      { value : 0, enumerable : false, configurable : false, writable : true });
+  d.mStrict();
+  d.mSloppy();
+}());
+
+
+(function TestKeyedSetterDoesNotReconfigure() {
+  var nonEnumConfig = 'nonEnumConfig';
+  var nonEnumNonConfig = 'nonEnumNonConfig';
+  function Base() {}
+  function Derived() {}
+
+  Derived.prototype = { __proto__: Base.prototype };
+
+  Derived.prototype.mStrict = function (){
+    'use strict';
+    super[nonEnumConfig] = 5;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig);
+    assertEquals(5, d1.value);
+    assertTrue(d1.configurable);
+    assertFalse(d1.enumerable);
+
+    super[nonEnumNonConfig] = 5;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig);
+    assertEquals(5, d1.value);
+    assertFalse(d1.configurable);
+    assertFalse(d1.enumerable);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mSloppy = function (){
+    super[nonEnumConfig] = 42;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig);
+    assertEquals(42, d1.value);
+    assertTrue(d1.configurable);
+    assertFalse(d1.enumerable);
+
+    super[nonEnumNonConfig] = 42;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig);
+    assertEquals(42, d1.value);
+    assertFalse(d1.configurable);
+    assertFalse(d1.enumerable);
+  }.toMethod(Derived.prototype);
+
+  var d = new Derived();
+  Object.defineProperty(d, nonEnumConfig,
+      { value : 0, enumerable : false, configurable : true, writable : true });
+  Object.defineProperty(d, nonEnumNonConfig,
+      { value : 0, enumerable : false, configurable : false, writable : true });
+  d.mStrict();
+  d.mSloppy();
+}());
+
+
+(function TestKeyedNumericSetterDoesNotReconfigure() {
+  var nonEnumConfig = 42;
+  var nonEnumNonConfig = 43;
+  function Base() {}
+  function Derived() {}
+
+  Derived.prototype = { __proto__: Base.prototype };
+
+  Derived.prototype.mStrict = function (){
+    'use strict';
+    super[nonEnumConfig] = 5;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig);
+    assertEquals(5, d1.value);
+    assertTrue(d1.configurable);
+    assertFalse(d1.enumerable);
+
+    super[nonEnumNonConfig] = 5;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig);
+    assertEquals(5, d1.value);
+    assertFalse(d1.configurable);
+    assertFalse(d1.enumerable);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mSloppy = function (){
+    super[nonEnumConfig] = 42;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig);
+    assertEquals(42, d1.value);
+    assertTrue(d1.configurable);
+    assertFalse(d1.enumerable);
+
+    super[nonEnumNonConfig] = 42;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig);
+    assertEquals(42, d1.value);
+    assertFalse(d1.configurable);
+    assertFalse(d1.enumerable);
+  }.toMethod(Derived.prototype);
+
+  var d = new Derived();
+  Object.defineProperty(d, nonEnumConfig,
+      { value : 0, enumerable : false, configurable : true, writable : true });
+  Object.defineProperty(d, nonEnumNonConfig,
+      { value : 0, enumerable : false, configurable : false, writable : true });
+  d.mStrict();
+  d.mSloppy();
+}());
+
+
+(function TestCountOperations() {
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    get x() {
+      return this._x;
+    },
+    set x(v) {
+      this._x = v;
+    },
+    _x: 1
+  };
+
+  function Derived() {}
+  Derived.__proto__ = Base;
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+    _x: 2
+  };
+
+  Derived.prototype.testCounts = function() {
+    assertEquals(2, this._x);
+    assertEquals(2, super.x);
+    super.x++;
+    assertEquals(3, super.x);
+    ++super.x;
+    assertEquals(4, super.x);
+    assertEquals(4, super.x++);
+    assertEquals(5, super.x);
+    assertEquals(6, ++super.x);
+    assertEquals(6, super.x);
+    assertEquals(6, this._x);
+
+    super.x--;
+    assertEquals(5, super.x);
+    --super.x;
+    assertEquals(4, super.x);
+    assertEquals(4, super.x--);
+    assertEquals(3, super.x);
+    assertEquals(2, --super.x);
+    assertEquals(2, super.x);
+    assertEquals(2, this._x);
+  }.toMethod(Derived.prototype);
+  new Derived().testCounts();
+}());
+
+
+(function TestKeyedCountOperations() {
+  var x = 'x';
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    get x() {
+      return this._x;
+    },
+    set x(v) {
+      this._x = v;
+    },
+    _x: 1
+  };
+
+  function Derived() {}
+  Derived.__proto__ = Base;
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+    _x: 2
+  };
+
+  Derived.prototype.testCounts = function() {
+    assertEquals(2, this._x);
+    assertEquals(2, super[x]);
+    super[x]++;
+    assertEquals(3, super[x]);
+    ++super[x];
+    assertEquals(4, super[x]);
+    assertEquals(4, super[x]++);
+    assertEquals(5, super[x]);
+    assertEquals(6, ++super[x]);
+    assertEquals(6, super[x]);
+    assertEquals(6, this._x);
+
+    super[x]--;
+    assertEquals(5, super[x]);
+    --super[x];
+    assertEquals(4, super[x]);
+    assertEquals(4, super[x]--);
+    assertEquals(3, super[x]);
+    assertEquals(2, --super[x]);
+    assertEquals(2, super[x]);
+    assertEquals(2, this._x);
+  }.toMethod(Derived.prototype);
+  new Derived().testCounts();
+}());
+
+
+(function TestKeyedNumericCountOperations() {
+  var x = 42;
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    _x: 1
+  };
+
+  Object.defineProperty(Base.prototype, x, {
+    get: function() { return this._x; },
+    set: function(v) { this._x = v;; }
+  });
+
+  function Derived() {}
+  Derived.__proto__ = Base;
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+    _x: 2
+  };
+
+  Derived.prototype.testCounts = function() {
+    assertEquals(2, this._x);
+    assertEquals(2, super[x]);
+    super[x]++;
+    assertEquals(3, super[x]);
+    ++super[x];
+    assertEquals(4, super[x]);
+    assertEquals(4, super[x]++);
+    assertEquals(5, super[x]);
+    assertEquals(6, ++super[x]);
+    assertEquals(6, super[x]);
+    assertEquals(6, this._x);
+
+    super[x]--;
+    assertEquals(5, super[x]);
+    --super[x];
+    assertEquals(4, super[x]);
+    assertEquals(4, super[x]--);
+    assertEquals(3, super[x]);
+    assertEquals(2, --super[x]);
+    assertEquals(2, super[x]);
+    assertEquals(2, this._x);
+  }.toMethod(Derived.prototype);
+  new Derived().testCounts();
+}());
+
+
+(function TestSetterSuperNonWritable() {
+  function Base() {}
+  Object.defineProperty(Base.prototype, 'x', { value : 27, writable: false });
+  function Derived() {}
+
+  Derived.prototype = { __proto__: Base.prototype, constructor: Derived };
+
+  Derived.prototype.mSloppy = function() {
+    assertEquals(27, super.x);
+    assertEquals(27, this.x);
+    super.x = 10;
+    assertEquals(27, super.x);
+    assertEquals(27, this.x);
+  }.toMethod(Derived.prototype);
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    assertEquals(27, super.x);
+    assertEquals(27, this.x);
+    var ex = null;
+    try { super.x = 10; } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(27, super.x);
+    assertEquals(27, this.x);
+  }.toMethod(Derived.prototype);
+  new Derived().mSloppy();
+  new Derived().mStrict();
+}());
+
+
+(function TestSetterKeyedSuperNonWritable() {
+  var x = 'xyz';
+  function Base() {}
+  Object.defineProperty(Base.prototype, x, { value : 27, writable: false });
+  function Derived() {}
+
+  Derived.prototype = { __proto__: Base.prototype, constructor: Derived };
+
+  Derived.prototype.mSloppy = function() {
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+    super[x] = 10;
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+  }.toMethod(Derived.prototype);
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+    var ex = null;
+    try { super[x] = 10; } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+  }.toMethod(Derived.prototype);
+  new Derived().mSloppy();
+  new Derived().mStrict();
+}());
+
+
+(function TestSetterKeyedNumericSuperNonWritable() {
+  var x = 42;
+  function Base() {}
+  Object.defineProperty(Base.prototype, x, { value : 27, writable: false });
+  function Derived() {}
+
+  Derived.prototype = { __proto__: Base.prototype, constructor: Derived };
+
+  Derived.prototype.mSloppy = function() {
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+    super[x] = 10;
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+  }.toMethod(Derived.prototype);
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+    var ex = null;
+    try { super[x] = 10; } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+  }.toMethod(Derived.prototype);
+  new Derived().mSloppy();
+  new Derived().mStrict();
+}());
+
+
+function Subclass(base, constructor) {
+  var homeObject = {
+    __proto__: base.prototype,
+    constructor: constructor
+  };
+  constructor.__proto__ = base;
+  constructor.prototype = homeObject;
+  // not doing toMethod: home object is not required for
+  // super constructor calls.
+  return constructor;
+}
+
+(function TestSuperCall() {
+  var baseCalled = 0;
+  var derivedCalled = 0;
+  var derivedDerivedCalled = 0;
+
+  function Base() {
+    baseCalled++;
+  }
+
+  var Derived = Subclass(Base, function () {
+    super();
+    derivedCalled++;
+  });
+
+  assertEquals(Base, Base.prototype.constructor);
+  assertEquals(Base.prototype, Derived.prototype.__proto__);
+
+  baseCalled = 0;
+  derivedCalled = 0;
+  new Derived();
+  assertEquals(1, baseCalled);
+  assertEquals(1, derivedCalled);
+
+  var DerivedDerived = Subclass(Derived, function () {
+    super();
+    derivedDerivedCalled++;
+  });
+
+  baseCalled = 0;
+  derivedCalled = 0;
+  derivedDerivedCalled = 0;
+  new DerivedDerived();
+  assertEquals(1, baseCalled);
+  assertEquals(1, derivedCalled);
+  assertEquals(1, derivedDerivedCalled);
+
+  function Base2(v) {
+    this.fromBase = v;
+  }
+  var Derived2 = Subclass(Base2, function (v1, v2) {
+    super(v1);
+    this.fromDerived = v2;
+  });
+
+  var d = new Derived2("base", "derived");
+  assertEquals("base", d.fromBase);
+  assertEquals("derived", d.fromDerived);
+
+  function ImplicitSubclassOfFunction() {
+    super();
+    this.x = 123;
+  }
+
+  var o = new ImplicitSubclassOfFunction();
+  assertEquals(123, o.x);
+
+  var calls = 0;
+  function G() {
+    calls++;
+  }
+  function F() {
+    super();
+  }
+  F.__proto__ = G;
+  new F();
+  assertEquals(1, calls);
+  F.__proto__ = function() {};
+  new F();
+  assertEquals(1, calls);
+}());
+
+
+(function TestNewSuper() {
+  var baseCalled = 0;
+  var derivedCalled = 0;
+
+  function Base() {
+    baseCalled++;
+    this.x = 15;
+  }
+
+
+  var Derived = Subclass(Base, function() {
+    baseCalled = 0;
+    var b = new super();
+    assertEquals(1, baseCalled)
+    assertEquals(Base.prototype, b.__proto__);
+    assertEquals(15, b.x);
+    assertEquals(undefined, this.x);
+    derivedCalled++;
+  });
+
+  derivedCalled = 0;
+  new Derived();
+  assertEquals(1, derivedCalled);
+}());
+
+
+(function TestSuperCallErrorCases() {
+  function T() {
+    super();
+  }
+  T.__proto__ = null;
+  // Spec says ReferenceError here, but for other IsCallable failures
+  // we throw TypeError.
+  // Filed https://bugs.ecmascript.org/show_bug.cgi?id=3282
+  assertThrows(function() { new T(); }, TypeError);
+
+  function T1() {
+    var b = new super();
+  }
+  T1.__proto = null;
+  assertThrows(function() { new T1(); }, TypeError);
+}());
+
+
+(function TestSuperCallSyntacticRestriction() {
+  assertThrows(function() {
+    function C() {
+        var y;
+        super();
+    }
+    new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      super(this.x);
+    }
+    new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      super(this);
+    }
+    new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      super(1, 2, Object.getPrototypeOf(this));
+    }
+    new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      { super(1, 2); }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      if (1) super();
+    }; new C();
+  }, TypeError);
+
+  function C1() {
+    'use strict';
+    super();
+  };
+  new C1();
+
+  function C2() {
+    ; 'use strict';;;;;
+    super();
+  };
+  new C2();
+
+  function C3() {
+    ; 'use strict';;;;;
+    // This is a comment.
+    super();
+  }
+  new C3();
+}());
diff --git a/test/mjsunit/harmony/templates.js b/test/mjsunit/harmony/templates.js
new file mode 100644
index 0000000..c339bb8
--- /dev/null
+++ b/test/mjsunit/harmony/templates.js
@@ -0,0 +1,507 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-templates --harmony-unicode
+
+var num = 5;
+var str = "str";
+function fn() { return "result"; }
+var obj = {
+  num: num,
+  str: str,
+  fn: function() { return "result"; }
+};
+
+(function testBasicExpressions() {
+  assertEquals("foo 5 bar", `foo ${num} bar`);
+  assertEquals("foo str bar", `foo ${str} bar`);
+  assertEquals("foo [object Object] bar", `foo ${obj} bar`);
+  assertEquals("foo result bar", `foo ${fn()} bar`);
+  assertEquals("foo 5 bar", `foo ${obj.num} bar`);
+  assertEquals("foo str bar", `foo ${obj.str} bar`);
+  assertEquals("foo result bar", `foo ${obj.fn()} bar`);
+})();
+
+(function testExpressionsContainingTemplates() {
+  assertEquals("foo bar 5", `foo ${`bar ${num}`}`);
+})();
+
+(function testMultilineTemplates() {
+  assertEquals("foo\n    bar\n    baz", `foo
+    bar
+    baz`);
+
+  assertEquals("foo\n  bar\n  baz", eval("`foo\r\n  bar\r  baz`"));
+})();
+
+(function testLineContinuation() {
+  assertEquals("\n", `\
+
+`);
+})();
+
+(function testTaggedTemplates() {
+  var calls = 0;
+  (function(s) {
+    calls++;
+  })`test`;
+  assertEquals(1, calls);
+
+  calls = 0;
+  // assert tag is invoked in right context
+  obj = {
+    fn: function() {
+      calls++;
+      assertEquals(obj, this);
+    }
+  };
+
+  obj.fn`test`;
+  assertEquals(1, calls);
+
+  calls = 0;
+  // Simple templates only have a callSiteObj
+  (function(s) {
+    calls++;
+    assertEquals(1, arguments.length);
+  })`test`;
+  assertEquals(1, calls);
+
+  // Templates containing expressions have the values of evaluated expressions
+  calls = 0;
+  (function(site, n, s, o, f, r) {
+    calls++;
+    assertEquals(6, arguments.length);
+    assertEquals("number", typeof n);
+    assertEquals("string", typeof s);
+    assertEquals("object", typeof o);
+    assertEquals("function", typeof f);
+    assertEquals("result", r);
+  })`${num}${str}${obj}${fn}${fn()}`;
+  assertEquals(1, calls);
+
+  // The TV and TRV of NoSubstitutionTemplate :: `` is the empty code unit
+  // sequence.
+  calls = 0;
+  (function(s) {
+    calls++;
+    assertEquals(1, s.length);
+    assertEquals(1, s.raw.length);
+    assertEquals("", s[0]);
+
+    // Failure: expected <""> found <"foo  barfoo  barfoo foo foo foo testtest">
+    assertEquals("", s.raw[0]);
+  })``;
+  assertEquals(1, calls);
+
+  // The TV and TRV of TemplateHead :: `${ is the empty code unit sequence.
+  calls = 0;
+  (function(s) {
+    calls++;
+    assertEquals(2, s.length);
+    assertEquals(2, s.raw.length);
+    assertEquals("", s[0]);
+    assertEquals("", s.raw[0]);
+  })`${1}`;
+  assertEquals(1, calls);
+
+  // The TV and TRV of TemplateMiddle :: }${ is the empty code unit sequence.
+  calls = 0;
+  (function(s) {
+    calls++;
+    assertEquals(3, s.length);
+    assertEquals(3, s.raw.length);
+    assertEquals("", s[1]);
+    assertEquals("", s.raw[1]);
+  })`${1}${2}`;
+  assertEquals(1, calls);
+
+  // The TV and TRV of TemplateTail :: }` is the empty code unit sequence.
+  calls = 0;
+  (function(s) {
+    calls++;
+    assertEquals(2, s.length);
+    assertEquals(2, s.raw.length);
+    assertEquals("", s[1]);
+    assertEquals("", s.raw[1]);
+  })`${1}`;
+  assertEquals(1, calls);
+
+  // The TV of NoSubstitutionTemplate :: ` TemplateCharacters ` is the TV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("foo", s[0]); })`foo`;
+  assertEquals(1, calls);
+
+  // The TV of TemplateHead :: ` TemplateCharacters ${ is the TV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("foo", s[0]); })`foo${1}`;
+  assertEquals(1, calls);
+
+  // The TV of TemplateMiddle :: } TemplateCharacters ${ is the TV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("foo", s[1]); })`${1}foo${2}`;
+  assertEquals(1, calls);
+
+  // The TV of TemplateTail :: } TemplateCharacters ` is the TV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("foo", s[1]); })`${1}foo`;
+  assertEquals(1, calls);
+
+  // The TV of TemplateCharacters :: TemplateCharacter is the TV of
+  // TemplateCharacter.
+  calls = 0;
+  (function(s) { calls++; assertEquals("f", s[0]); })`f`;
+  assertEquals(1, calls);
+
+  // The TV of TemplateCharacter :: $ is the code unit value 0x0024.
+  calls = 0;
+  (function(s) { calls++; assertEquals("$", s[0]); })`$`;
+  assertEquals(1, calls);
+
+  // The TV of TemplateCharacter :: \ EscapeSequence is the CV of
+  // EscapeSequence.
+  calls = 0;
+  (function(s) { calls++; assertEquals("안녕", s[0]); })`\uc548\uB155`;
+  (function(s) { calls++; assertEquals("\xff", s[0]); })`\xff`;
+  (function(s) { calls++; assertEquals("\n", s[0]); })`\n`;
+  assertEquals(3, calls);
+
+  // The TV of TemplateCharacter :: LineContinuation is the TV of
+  // LineContinuation. The TV of LineContinuation :: \ LineTerminatorSequence is
+  // the empty code unit sequence.
+  calls = 0;
+  (function(s) { calls++; assertEquals("", s[0]); })`\
+`;
+  assertEquals(1, calls);
+
+  // The TRV of NoSubstitutionTemplate :: ` TemplateCharacters ` is the TRV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("test", s.raw[0]); })`test`;
+  assertEquals(1, calls);
+
+  // The TRV of TemplateHead :: ` TemplateCharacters ${ is the TRV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("test", s.raw[0]); })`test${1}`;
+  assertEquals(1, calls);
+
+  // The TRV of TemplateMiddle :: } TemplateCharacters ${ is the TRV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("test", s.raw[1]); })`${1}test${2}`;
+  assertEquals(1, calls);
+
+  // The TRV of TemplateTail :: } TemplateCharacters ` is the TRV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("test", s.raw[1]); })`${1}test`;
+  assertEquals(1, calls);
+
+  // The TRV of TemplateCharacters :: TemplateCharacter is the TRV of
+  // TemplateCharacter.
+  calls = 0;
+  (function(s) { calls++; assertEquals("f", s.raw[0]); })`f`;
+  assertEquals(1, calls);
+
+  // The TRV of TemplateCharacter :: $ is the code unit value 0x0024.
+  calls = 0;
+  (function(s) { calls++; assertEquals("\u0024", s.raw[0]); })`$`;
+  assertEquals(1, calls);
+
+  // The TRV of EscapeSequence :: 0 is the code unit value 0x0030.
+  calls = 0;
+  (function(s) { calls++; assertEquals("\u005C\u0030", s.raw[0]); })`\0`;
+  assertEquals(1, calls);
+
+  // The TRV of TemplateCharacter :: \ EscapeSequence is the sequence consisting
+  // of the code unit value 0x005C followed by the code units of TRV of
+  // EscapeSequence.
+
+  //   The TRV of EscapeSequence :: HexEscapeSequence is the TRV of the
+  //   HexEscapeSequence.
+  calls = 0;
+  (function(s) { calls++; assertEquals("\u005Cxff", s.raw[0]); })`\xff`;
+  assertEquals(1, calls);
+
+  //   The TRV of EscapeSequence :: UnicodeEscapeSequence is the TRV of the
+  //   UnicodeEscapeSequence.
+  calls = 0;
+  (function(s) { calls++; assertEquals("\u005Cuc548", s.raw[0]); })`\uc548`;
+  assertEquals(1, calls);
+
+  //   The TRV of CharacterEscapeSequence :: SingleEscapeCharacter is the TRV of
+  //   the SingleEscapeCharacter.
+  calls = 0;
+  (function(s) { calls++; assertEquals("\u005C\u0027", s.raw[0]); })`\'`;
+  (function(s) { calls++; assertEquals("\u005C\u0022", s.raw[0]); })`\"`;
+  (function(s) { calls++; assertEquals("\u005C\u005C", s.raw[0]); })`\\`;
+  (function(s) { calls++; assertEquals("\u005Cb", s.raw[0]); })`\b`;
+  (function(s) { calls++; assertEquals("\u005Cf", s.raw[0]); })`\f`;
+  (function(s) { calls++; assertEquals("\u005Cn", s.raw[0]); })`\n`;
+  (function(s) { calls++; assertEquals("\u005Cr", s.raw[0]); })`\r`;
+  (function(s) { calls++; assertEquals("\u005Ct", s.raw[0]); })`\t`;
+  (function(s) { calls++; assertEquals("\u005Cv", s.raw[0]); })`\v`;
+  (function(s) { calls++; assertEquals("\u005C`", s.raw[0]); })`\``;
+  assertEquals(10, calls);
+
+  //   The TRV of CharacterEscapeSequence :: NonEscapeCharacter is the CV of the
+  //   NonEscapeCharacter.
+  calls = 0;
+  (function(s) { calls++; assertEquals("\u005Cz", s.raw[0]); })`\z`;
+  assertEquals(1, calls);
+
+  // The TRV of LineTerminatorSequence :: <LF> is the code unit value 0x000A.
+  // The TRV of LineTerminatorSequence :: <CR> is the code unit value 0x000A.
+  // The TRV of LineTerminatorSequence :: <CR><LF> is the sequence consisting of
+  // the code unit value 0x000A.
+  calls = 0;
+  function testRawLineNormalization(cs) {
+    calls++;
+    assertEquals(cs.raw[0], "\n\n\n");
+    assertEquals(cs.raw[1], "\n\n\n");
+  }
+  eval("testRawLineNormalization`\r\n\n\r${1}\r\n\n\r`");
+  assertEquals(1, calls);
+
+  // The TRV of LineContinuation :: \ LineTerminatorSequence is the sequence
+  // consisting of the code unit value 0x005C followed by the code units of TRV
+  // of LineTerminatorSequence.
+  calls = 0;
+  function testRawLineContinuation(cs) {
+    calls++;
+    assertEquals(cs.raw[0], "\u005C\n\u005C\n\u005C\n");
+    assertEquals(cs.raw[1], "\u005C\n\u005C\n\u005C\n");
+  }
+  eval("testRawLineContinuation`\\\r\n\\\n\\\r${1}\\\r\n\\\n\\\r`");
+  assertEquals(1, calls);
+})();
+
+
+(function testCallSiteObj() {
+  var calls = 0;
+  function tag(cs) {
+    calls++;
+    assertTrue(cs.hasOwnProperty("raw"));
+    assertTrue(Object.isFrozen(cs));
+    assertTrue(Object.isFrozen(cs.raw));
+    var raw = Object.getOwnPropertyDescriptor(cs, "raw");
+    assertFalse(raw.writable);
+    assertFalse(raw.configurable);
+    assertFalse(raw.enumerable);
+    assertEquals(Array.prototype, Object.getPrototypeOf(cs.raw));
+    assertTrue(Array.isArray(cs.raw));
+    assertEquals(Array.prototype, Object.getPrototypeOf(cs));
+    assertTrue(Array.isArray(cs));
+
+    var cooked0 = Object.getOwnPropertyDescriptor(cs, "0");
+    assertFalse(cooked0.writable);
+    assertFalse(cooked0.configurable);
+    assertTrue(cooked0.enumerable);
+
+    var raw0 = Object.getOwnPropertyDescriptor(cs.raw, "0");
+    assertFalse(cooked0.writable);
+    assertFalse(cooked0.configurable);
+    assertTrue(cooked0.enumerable);
+
+    var length = Object.getOwnPropertyDescriptor(cs, "length");
+    assertFalse(length.writable);
+    assertFalse(length.configurable);
+    assertFalse(length.enumerable);
+
+    length = Object.getOwnPropertyDescriptor(cs.raw, "length");
+    assertFalse(length.writable);
+    assertFalse(length.configurable);
+    assertFalse(length.enumerable);
+  }
+  tag`${1}`;
+  assertEquals(1, calls);
+})();
+
+
+(function testUTF16ByteOrderMark() {
+  assertEquals("\uFEFFtest", `\uFEFFtest`);
+  assertEquals("\uFEFFtest", eval("`\uFEFFtest`"));
+})();
+
+
+(function testStringRawAsTagFn() {
+  assertEquals("\\u0065\\`\\r\\r\\n\\ntestcheck",
+               String.raw`\u0065\`\r\r\n\n${"test"}check`);
+  assertEquals("\\\n\\\n\\\n", eval("String.raw`\\\r\\\r\n\\\n`"));
+  assertEquals("", String.raw``);
+})();
+
+
+(function testCallSiteCaching() {
+  var callSites = [];
+  function tag(cs) { callSites.push(cs); }
+  var a = 1;
+  var b = 2;
+
+  tag`head${a}tail`;
+  tag`head${b}tail`;
+
+  assertEquals(2, callSites.length);
+  assertSame(callSites[0], callSites[1]);
+
+  eval("tag`head${a}tail`");
+  assertEquals(3, callSites.length);
+  assertSame(callSites[1], callSites[2]);
+
+  eval("tag`head${b}tail`");
+  assertEquals(4, callSites.length);
+  assertSame(callSites[2], callSites[3]);
+
+  (new Function("tag", "a", "b", "return tag`head${a}tail`;"))(tag, 1, 2);
+  assertEquals(5, callSites.length);
+  assertSame(callSites[3], callSites[4]);
+
+  (new Function("tag", "a", "b", "return tag`head${b}tail`;"))(tag, 1, 2);
+  assertEquals(6, callSites.length);
+  assertSame(callSites[4], callSites[5]);
+
+  callSites = [];
+
+  tag`foo${a}bar`;
+  tag`foo\${.}bar`;
+  assertEquals(2, callSites.length);
+  assertEquals(2, callSites[0].length);
+  assertEquals(1, callSites[1].length);
+
+  callSites = [];
+
+  eval("tag`\\\r\n\\\n\\\r`");
+  eval("tag`\\\r\n\\\n\\\r`");
+  assertEquals(2, callSites.length);
+  assertSame(callSites[0], callSites[1]);
+  assertEquals("", callSites[0][0]);
+  assertEquals("\\\n\\\n\\\n", callSites[0].raw[0]);
+
+  callSites = [];
+
+  tag`\uc548\ub155`;
+  tag`\uc548\ub155`;
+  assertEquals(2, callSites.length);
+  assertSame(callSites[0], callSites[1]);
+  assertEquals("안녕", callSites[0][0]);
+  assertEquals("\\uc548\\ub155", callSites[0].raw[0]);
+
+  callSites = [];
+
+  tag`\uc548\ub155`;
+  tag`안녕`;
+  assertEquals(2, callSites.length);
+  assertTrue(callSites[0] !== callSites[1]);
+  assertEquals("안녕", callSites[0][0]);
+  assertEquals("\\uc548\\ub155", callSites[0].raw[0]);
+  assertEquals("안녕", callSites[1][0]);
+  assertEquals("안녕", callSites[1].raw[0]);
+
+  // Extra-thorough UTF8 decoding test.
+  callSites = [];
+
+  tag`Iñtërnâtiônàlizætiøn\u2603\uD83D\uDCA9`;
+  tag`Iñtërnâtiônàlizætiøn☃💩`;
+
+  assertEquals(2, callSites.length);
+  assertTrue(callSites[0] !== callSites[1]);
+  assertEquals("Iñtërnâtiônàlizætiøn☃💩", callSites[0][0]);
+  assertEquals(
+      "Iñtërnâtiônàlizætiøn\\u2603\\uD83D\\uDCA9", callSites[0].raw[0]);
+  assertEquals("Iñtërnâtiônàlizætiøn☃💩", callSites[1][0]);
+  assertEquals("Iñtërnâtiônàlizætiøn☃💩", callSites[1].raw[0]);
+})();
+
+
+(function testExtendedArrayPrototype() {
+  Object.defineProperty(Array.prototype, 0, {
+    set: function() {
+      assertUnreachable();
+    }
+  });
+  function tag(){}
+  tag`a${1}b`;
+})();
+
+
+(function testRawLineNormalization() {
+  function raw0(callSiteObj) {
+    return callSiteObj.raw[0];
+  }
+  assertEquals(eval("raw0`\r`"), "\n");
+  assertEquals(eval("raw0`\r\n`"), "\n");
+  assertEquals(eval("raw0`\r\r\n`"), "\n\n");
+  assertEquals(eval("raw0`\r\n\r\n`"), "\n\n");
+  assertEquals(eval("raw0`\r\r\r\n`"), "\n\n\n");
+})();
+
+
+(function testHarmonyUnicode() {
+  function raw0(callSiteObj) {
+    return callSiteObj.raw[0];
+  }
+  assertEquals(raw0`a\u{62}c`, "a\\u{62}c");
+  assertEquals(raw0`a\u{000062}c`, "a\\u{000062}c");
+  assertEquals(raw0`a\u{0}c`, "a\\u{0}c");
+
+  assertEquals(`a\u{62}c`, "abc");
+  assertEquals(`a\u{000062}c`, "abc");
+})();
+
+
+(function testLiteralAfterRightBrace() {
+  // Regression test for https://code.google.com/p/v8/issues/detail?id=3734
+  function f() {}
+  `abc`;
+
+  function g() {}`def`;
+
+  {
+    // block
+  }
+  `ghi`;
+
+  {
+    // block
+  }`jkl`;
+})();
+
+
+(function testLegacyOctal() {
+  assertEquals('\u0000', `\0`);
+  assertEquals('\u0000a', `\0a`);
+  for (var i = 0; i < 8; i++) {
+    var code = "`\\0" + i + "`";
+    assertThrows(code, SyntaxError);
+    code = "(function(){})" + code;
+    assertThrows(code, SyntaxError);
+  }
+
+  assertEquals('\\0', String.raw`\0`);
+})();
+
+
+(function testSyntaxErrorsNonEscapeCharacter() {
+  assertThrows("`\\x`", SyntaxError);
+  assertThrows("`\\u`", SyntaxError);
+  for (var i = 1; i < 8; i++) {
+    var code = "`\\" + i + "`";
+    assertThrows(code, SyntaxError);
+    code = "(function(){})" + code;
+    assertThrows(code, SyntaxError);
+  }
+})();
+
+
+(function testValidNumericEscapes() {
+  assertEquals("8", `\8`);
+  assertEquals("9", `\9`);
+  assertEquals("\u00008", `\08`);
+  assertEquals("\u00009", `\09`);
+})();
diff --git a/test/mjsunit/harmony/typedarrays-foreach.js b/test/mjsunit/harmony/typedarrays-foreach.js
new file mode 100644
index 0000000..4bfa655
--- /dev/null
+++ b/test/mjsunit/harmony/typedarrays-foreach.js
@@ -0,0 +1,140 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-arrays --allow-natives-syntax
+
+var typedArrayConstructors = [
+  Uint8Array,
+  Int8Array,
+  Uint16Array,
+  Int16Array,
+  Uint32Array,
+  Int32Array,
+  Uint8ClampedArray,
+  Float32Array,
+  Float64Array];
+
+function CheckTypedArrayIsNeutered(array) {
+  assertEquals(0, array.byteLength);
+  assertEquals(0, array.byteOffset);
+  assertEquals(0, array.length);
+}
+
+function TestTypedArrayForEach(constructor) {
+  assertEquals(1, constructor.prototype.forEach.length);
+
+  var a = new constructor(2);
+  a[0] = 0;
+  a[1] = 1;
+
+  var count = 0;
+  a.forEach(function (n) { count++; });
+  assertEquals(2, count);
+
+  // Use specified object as this object when calling the function.
+  var o = { value: 42 };
+  var result = [];
+  a.forEach(function (n, index, array) { result.push(this.value); }, o);
+  assertArrayEquals([42, 42], result);
+
+  // Modify the original array.
+  count = 0;
+  a.forEach(function (n, index, array) { array[index] = n + 1; count++ });
+  assertEquals(2, count);
+  assertArrayEquals([1, 2], a);
+
+  // Check that values passed as second argument are wrapped into
+  // objects when calling into sloppy mode functions.
+  function CheckWrapping(value, wrapper) {
+    var wrappedValue = new wrapper(value);
+
+    a.forEach(function () {
+      assertEquals("object", typeof this);
+      assertEquals(wrappedValue, this);
+    }, value);
+
+    a.forEach(function () {
+      "use strict";
+      assertEquals(typeof value, typeof this);
+      assertEquals(value, this);
+    }, value);
+  }
+  CheckWrapping(true, Boolean);
+  CheckWrapping(false, Boolean);
+  CheckWrapping("xxx", String);
+  CheckWrapping(42, Number);
+  CheckWrapping(3.14, Number);
+  CheckWrapping({}, Object);
+
+  // Throw before completing iteration, only the first element
+  // should be modified when thorwing mid-way.
+  count = 0;
+  a[0] = 42;
+  a[1] = 42;
+  try {
+    a.forEach(function (n, index, array) {
+      if (count > 0) throw "meh";
+      array[index] = n + 1;
+      count++;
+    });
+  } catch (e) {
+  }
+  assertEquals(1, count);
+  assertEquals(43, a[0]);
+  assertEquals(42, a[1]);
+
+  // Neutering the buffer backing the typed array mid-way should
+  // still make .forEach() finish, and the array should keep being
+  // empty after neutering it.
+  count = 0;
+  a.forEach(function (n, index, array) {
+    if (count > 0) %ArrayBufferNeuter(array.buffer);
+    array[index] = n + 1;
+    count++;
+  });
+  assertEquals(2, count);
+  CheckTypedArrayIsNeutered(a);
+  assertEquals(undefined, a[0]);
+
+  // The method must work for typed arrays created from ArrayBuffer.
+  // The length of the ArrayBuffer is chosen so it is a multiple of
+  // all lengths of the typed array items.
+  a = new constructor(new ArrayBuffer(64));
+  count = 0;
+  a.forEach(function (n) { count++ });
+  assertEquals(a.length, count);
+
+  // Externalizing the array mid-way accessing the .buffer property
+  // should work.
+  a = new constructor(2);
+  count = 0;
+  var buffer = undefined;
+  a.forEach(function (n, index, array) {
+    if (count++ > 0)
+      buffer = array.buffer;
+  });
+  assertEquals(2, count);
+  assertTrue(!!buffer);
+  assertEquals("ArrayBuffer", %_ClassOf(buffer));
+  assertSame(buffer, a.buffer);
+
+  // The %TypedArray%.forEach() method should not work when
+  // transplanted to objects that are not typed arrays.
+  assertThrows(function () { constructor.prototype.forEach.call([1, 2, 3], function (x) {}) }, TypeError);
+  assertThrows(function () { constructor.prototype.forEach.call("abc", function (x) {}) }, TypeError);
+  assertThrows(function () { constructor.prototype.forEach.call({}, function (x) {}) }, TypeError);
+  assertThrows(function () { constructor.prototype.forEach.call(0, function (x) {}) }, TypeError);
+
+  // Method must be useable on instances of other typed arrays.
+  for (var i = 0; i < typedArrayConstructors.length; i++) {
+    count = 0;
+    a = new typedArrayConstructors[i](4);
+    constructor.prototype.forEach.call(a, function (x) { count++ });
+    assertEquals(a.length, count);
+  }
+}
+
+for (i = 0; i < typedArrayConstructors.length; i++) {
+  TestTypedArrayForEach(typedArrayConstructors[i]);
+}
diff --git a/test/mjsunit/harmony/typedarrays-of.js b/test/mjsunit/harmony/typedarrays-of.js
new file mode 100644
index 0000000..9df1d30
--- /dev/null
+++ b/test/mjsunit/harmony/typedarrays-of.js
@@ -0,0 +1,135 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Based on Mozilla Array.of() tests at http://dxr.mozilla.org/mozilla-central/source/js/src/jit-test/tests/collections
+
+// Flags: --harmony-arrays
+
+var typedArrayConstructors = [
+  Uint8Array,
+  Int8Array,
+  Uint16Array,
+  Int16Array,
+  Uint32Array,
+  Int32Array,
+  Uint8ClampedArray,
+  Float32Array,
+  Float64Array];
+
+
+function TestTypedArrayOf(constructor) {
+  // %TypedArray%.of basics.
+  var a = constructor.of();
+  assertEquals(0, a.length);
+  assertEquals(constructor.prototype, Object.getPrototypeOf(a));
+  assertEquals(false, Array.isArray(a));
+
+  // Items are coerced to numerical values.
+  a = constructor.of(undefined, null, [], true, false, 3.14);
+
+  // For typed arrays of floating point values, values are not rounded.
+  if (constructor === Float32Array || constructor === Float64Array) {
+    assertEquals(NaN, a[0]);
+    assertEquals(0, a[1]);
+    assertEquals(0, a[2]);
+    assertEquals(1, a[3]);
+    assertEquals(0, a[4]);
+    assertEquals(true, Math.abs(a[5] - 3.14) < 1e-6);
+  } else {
+    assertEquals(0, a[0]);
+    assertEquals(0, a[1]);
+    assertEquals(0, a[2]);
+    assertEquals(1, a[3]);
+    assertEquals(0, a[4]);
+    assertEquals(3, a[5]);
+  }
+
+  var aux = [];
+  for (var i = 0; i < 100; i++)
+    aux[i] = i;
+
+  a = constructor.of.apply(constructor, aux);
+  assertEquals(aux.length, a.length);
+  assertArrayEquals(aux, a);
+
+  // %TypedArray%.of can be transplanted to other constructors.
+  var hits = 0;
+  function Bag(length) {
+    assertEquals(arguments.length, 1);
+    assertEquals(length, 2);
+    this.length = length;
+    hits++;
+  }
+  Bag.of = constructor.of;
+
+  hits = 0;
+  a = Bag.of("zero", "one");
+  assertEquals(1, hits);
+  assertEquals(2, a.length);
+  assertArrayEquals(["zero", "one"], a);
+  assertEquals(Bag.prototype, a.__proto__);
+
+  hits = 0;
+  actual = constructor.of.call(Bag, "zero", "one");
+  assertEquals(1, hits);
+  assertEquals(2, a.length);
+  assertArrayEquals(["zero", "one"], a);
+  assertEquals(Bag.prototype, a.__proto__);
+
+  // %TypedArray%.of does not trigger prototype setters.
+  // (It defines elements rather than assigning to them.)
+  var status = "pass";
+  Object.defineProperty(constructor.prototype, "0", {
+    set: function(v) { status = "fail"; }
+  });
+  assertEquals(1, constructor.of(1)[0], 1);
+  assertEquals("pass", status);
+
+  // Note that %TypedArray%.of does not trigger "length" setter itself, as
+  // it relies on the constructor to set "length" to the value passed to it.
+  // If the constructor does not assign "length", the setter should not be
+  // invoked.
+
+  // Setter on the newly created object.
+  function Pack() {
+    Object.defineProperty(this, "length", {
+      set: function (v) { status = "fail"; }
+    });
+  }
+  Pack.of = constructor.of;
+  var pack = Pack.of("wolves", "cards", "cigarettes", "lies");
+  assertEquals("pass", status);
+
+  // when the setter is on the new object's prototype
+  function Bevy() {}
+  Object.defineProperty(Bevy.prototype, "length", {
+    set: function (v) { status = "fail"; }
+  });
+  Bevy.of = constructor.of;
+  var bevy = Bevy.of("quail");
+  assertEquals("pass", status);
+
+  // Check superficial features of %TypedArray%.of.
+  var desc = Object.getOwnPropertyDescriptor(constructor, "of");
+
+  assertEquals(desc.configurable, false);
+  assertEquals(desc.enumerable, false);
+  assertEquals(desc.writable, false);
+  assertEquals(constructor.of.length, 0);
+
+  // %TypedArray%.of is not a constructor.
+  assertThrows(function() { new constructor.of(); }, TypeError);
+
+  // For receivers which are not constructors %TypedArray%.of does not
+  // allocate a typed array using a default constructor, but throws an
+  // exception. Note that this is different from Array.of, which uses
+  // Array as default constructor.
+  for (var x of [undefined, null, false, true, "cow", 42, 3.14]) {
+    assertThrows(function () { constructor.of.call(x); }, TypeError);
+  }
+}
+
+for (var constructor of typedArrayConstructors) {
+  TestTypedArrayOf(constructor);
+}
diff --git a/test/mjsunit/harmony/typedarrays.js b/test/mjsunit/harmony/typedarrays.js
index f26b0be..a4d6e79 100644
--- a/test/mjsunit/harmony/typedarrays.js
+++ b/test/mjsunit/harmony/typedarrays.js
@@ -25,6 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Flags: --harmony-tostring
+
 // ArrayBuffer
 
 function TestByteLength(param, expectedByteLength) {
@@ -52,6 +54,8 @@
 
   var ab = new ArrayBuffer();
   assertSame(0, ab.byteLength);
+  assertEquals("[object ArrayBuffer]",
+      Object.prototype.toString.call(ab));
 }
 
 TestArrayBufferCreation();
@@ -123,6 +127,9 @@
   var ab = new ArrayBuffer(256*elementSize);
 
   var a0 = new constr(30);
+  assertEquals("[object " + constr.name + "]",
+      Object.prototype.toString.call(a0));
+
   assertTrue(ArrayBuffer.isView(a0));
   assertSame(elementSize, a0.BYTES_PER_ELEMENT);
   assertSame(30, a0.length);
@@ -258,6 +265,17 @@
   assertSame(0, aNoParam.length);
   assertSame(0, aNoParam.byteLength);
   assertSame(0, aNoParam.byteOffset);
+
+  var a = new constr(ab, 64*elementSize, 128);
+  assertEquals("[object " + constr.name + "]",
+      Object.prototype.toString.call(a));
+  var desc = Object.getOwnPropertyDescriptor(
+      constr.prototype, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.enumerable);
+  assertFalse(!!desc.writable);
+  assertFalse(!!desc.set);
+  assertEquals("function", typeof desc.get);
 }
 
 TestTypedArray(Uint8Array, 1, 0xFF);
@@ -361,14 +379,18 @@
   Float64Array];
 
 function TestPropertyTypeChecks(constructor) {
-  var a = new constructor();
   function CheckProperty(name) {
     var d = Object.getOwnPropertyDescriptor(constructor.prototype, name);
-    var o = {}
+    var o = {};
     assertThrows(function() {d.get.call(o);}, TypeError);
-    d.get.call(a); // shouldn't throw
-    for (var i = 0 ; i < typedArrayConstructors.length; i++) {
-      d.get.call(new typedArrayConstructors[i](10));
+    for (var i = 0; i < typedArrayConstructors.length; i++) {
+      var ctor = typedArrayConstructors[i];
+      var a = new ctor(10);
+      if (ctor === constructor) {
+        d.get.call(a); // shouldn't throw
+      } else {
+        assertThrows(function() {d.get.call(a);}, TypeError);
+      }
     }
   }
 
@@ -378,7 +400,7 @@
   CheckProperty("length");
 }
 
-for(i = 0; i < typedArrayConstructors.lenght; i++) {
+for(i = 0; i < typedArrayConstructors.length; i++) {
   TestPropertyTypeChecks(typedArrayConstructors[i]);
 }
 
@@ -477,6 +499,103 @@
 
 TestTypedArraySet();
 
+function TestTypedArraysWithIllegalIndices() {
+  var a = new Int32Array(100);
+
+  a[-10] = 10;
+  assertEquals(undefined, a[-10]);
+  a["-10"] = 10;
+  assertEquals(undefined, a["-10"]);
+
+  var s = "    -10";
+  a[s] = 10;
+  assertEquals(10, a[s]);
+  var s1 = "    -10   ";
+  a[s] = 10;
+  assertEquals(10, a[s]);
+
+  a["-1e2"] = 10;
+  assertEquals(10, a["-1e2"]);
+  assertEquals(undefined, a[-1e2]);
+
+  a["-0"] = 256;
+  var s2 = "     -0";
+  a[s2] = 255;
+  assertEquals(undefined, a["-0"]);
+  assertEquals(255, a[s2]);
+  assertEquals(0, a[-0]);
+
+  /* Chromium bug: 424619
+   * a[-Infinity] = 50;
+   * assertEquals(undefined, a[-Infinity]);
+   */
+  a[1.5] = 10;
+  assertEquals(undefined, a[1.5]);
+  var nan = Math.sqrt(-1);
+  a[nan] = 5;
+  assertEquals(5, a[nan]);
+
+  var x = 0;
+  var y = -0;
+  assertEquals(Infinity, 1/x);
+  assertEquals(-Infinity, 1/y);
+  a[x] = 5;
+  a[y] = 27;
+  assertEquals(27, a[x]);
+  assertEquals(27, a[y]);
+}
+
+TestTypedArraysWithIllegalIndices();
+
+function TestTypedArraysWithIllegalIndicesStrict() {
+  'use strict';
+  var a = new Int32Array(100);
+
+  a[-10] = 10;
+  assertEquals(undefined, a[-10]);
+  a["-10"] = 10;
+  assertEquals(undefined, a["-10"]);
+
+  var s = "    -10";
+  a[s] = 10;
+  assertEquals(10, a[s]);
+  var s1 = "    -10   ";
+  a[s] = 10;
+  assertEquals(10, a[s]);
+
+  a["-1e2"] = 10;
+  assertEquals(10, a["-1e2"]);
+  assertEquals(undefined, a[-1e2]);
+
+  a["-0"] = 256;
+  var s2 = "     -0";
+  a[s2] = 255;
+  assertEquals(undefined, a["-0"]);
+  assertEquals(255, a[s2]);
+  assertEquals(0, a[-0]);
+
+  /* Chromium bug: 424619
+   * a[-Infinity] = 50;
+   * assertEquals(undefined, a[-Infinity]);
+   */
+  a[1.5] = 10;
+  assertEquals(undefined, a[1.5]);
+  var nan = Math.sqrt(-1);
+  a[nan] = 5;
+  assertEquals(5, a[nan]);
+
+  var x = 0;
+  var y = -0;
+  assertEquals(Infinity, 1/x);
+  assertEquals(-Infinity, 1/y);
+  a[x] = 5;
+  a[y] = 27;
+  assertEquals(27, a[x]);
+  assertEquals(27, a[y]);
+}
+
+TestTypedArraysWithIllegalIndicesStrict();
+
 // DataView
 function TestDataViewConstructor() {
   var ab = new ArrayBuffer(256);
@@ -546,6 +665,19 @@
 
 TestDataViewPropertyTypeChecks();
 
+
+function TestDataViewToStringTag() {
+  var a = new DataView(new ArrayBuffer(10));
+  assertEquals("[object DataView]", Object.prototype.toString.call(a));
+  var desc = Object.getOwnPropertyDescriptor(
+      DataView.prototype, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.enumerable);
+  assertFalse(desc.writable);
+  assertEquals("DataView", desc.value);
+}
+
+
 // General tests for properties
 
 // Test property attribute [[Enumerable]]
@@ -561,7 +693,7 @@
     assertArrayEquals([], props(obj));
 }
 TestEnumerable(ArrayBuffer, new ArrayBuffer());
-for(i = 0; i < typedArrayConstructors.lenght; i++) {
+for(i = 0; i < typedArrayConstructors.length; i++) {
   TestEnumerable(typedArrayConstructors[i]);
 }
 TestEnumerable(DataView, new DataView(new ArrayBuffer()));
@@ -573,13 +705,13 @@
     assertEquals(value, map[property]);
   }
   for (var i = 0; i < 20; i++) {
-    TestProperty(m, i, 'val' + i);
+    TestProperty(m, 'key' + i, 'val' + i);
     TestProperty(m, 'foo' + i, 'bar' + i);
   }
 }
 TestArbitrary(new ArrayBuffer(256));
-for(i = 0; i < typedArrayConstructors.lenght; i++) {
-  TestArbitary(new typedArrayConstructors[i](10));
+for(i = 0; i < typedArrayConstructors.length; i++) {
+  TestArbitrary(new typedArrayConstructors[i](10));
 }
 TestArbitrary(new DataView(new ArrayBuffer(256)));
 
diff --git a/test/mjsunit/harmony/unicode-escapes.js b/test/mjsunit/harmony/unicode-escapes.js
new file mode 100644
index 0000000..b39ee1a
--- /dev/null
+++ b/test/mjsunit/harmony/unicode-escapes.js
@@ -0,0 +1,46 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ES6 extends the \uxxxx escape and also allows \u{xxxxx}.
+
+// Flags: --harmony-unicode
+
+// Unicode escapes in variable names.
+
+(function TestVariableNames1() {
+  var foobar = 1;
+  assertEquals(foob\u0061r, 1);
+  assertEquals(foob\u{0061}r, 1);
+  assertEquals(foob\u{61}r, 1);
+  assertEquals(foob\u{0000000061}r, 1);
+})();
+
+(function TestVariableNames2() {
+  var foobar = 1;
+  assertEquals(\u0066oobar, 1);
+  assertEquals(\u{0066}oobar, 1);
+  assertEquals(\u{66}oobar, 1);
+  assertEquals(\u{0000000066}oobar, 1);
+})();
+
+// Unicode escapes in strings.
+
+(function TestStrings() {
+  var s1 = "foob\u0061r";
+  assertEquals(s1, "foobar");
+  var s2 = "foob\u{0061}r";
+  assertEquals(s2, "foobar");
+  var s3 = "foob\u{61}r";
+  assertEquals(s3, "foobar");
+  var s4 = "foob\u{0000000061}r";
+  assertEquals(s4, "foobar");
+})();
+
+
+(function TestSurrogates() {
+  // U+10E6D corresponds to the surrogate pair [U+D803, U+DE6D].
+  var s1 = "foo\u{10e6d}";
+  var s2 = "foo\u{d803}\u{de6d}";
+  assertEquals(s1, s2);
+})();
diff --git a/test/mjsunit/keyed-load-with-string-key.js b/test/mjsunit/keyed-load-with-string-key.js
new file mode 100644
index 0000000..4388946
--- /dev/null
+++ b/test/mjsunit/keyed-load-with-string-key.js
@@ -0,0 +1,46 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+
+var o = {
+  "foo": "bar",
+}
+
+function get(obj, key) {
+  return obj[key];
+}
+
+get(o, "foo");
+get(o, "foo");
+get(o, "foo");
+
+%OptimizeFunctionOnNextCall(get);
+get(o, "foo");
+
+assertOptimized(get);
diff --git a/test/mjsunit/mirror-object.js b/test/mjsunit/mirror-object.js
index 7020338..91d0f82 100644
--- a/test/mjsunit/mirror-object.js
+++ b/test/mjsunit/mirror-object.js
@@ -125,12 +125,7 @@
         // Check that serialized name is correct.
         assertEquals(properties[i].name(), fromJSON.properties[i].name, 'Unexpected serialized name');
 
-        // If property type is normal property type is not serialized.
-        if (properties[i].propertyType() != debug.PropertyType.Normal) {
-          assertEquals(properties[i].propertyType(), fromJSON.properties[i].propertyType, 'Unexpected serialized property type');
-        } else {
-          assertTrue(typeof(fromJSON.properties[i].propertyType) === 'undefined', 'Unexpected serialized property type');
-        }
+        assertEquals(properties[i].propertyType(), fromJSON.properties[i].propertyType, 'Unexpected serialized property type');
 
         // If there are no attributes attributes are not serialized.
         if (properties[i].attributes() != debug.PropertyAttribute.None) {
diff --git a/test/mjsunit/mjsunit.js b/test/mjsunit/mjsunit.js
index 0430279..b360425 100644
--- a/test/mjsunit/mjsunit.js
+++ b/test/mjsunit/mjsunit.js
@@ -231,16 +231,7 @@
     return deepObjectEquals(a, b);
   }
 
-  function checkArity(args, arity, name) {
-    if (args.length < arity) {
-      fail(PrettyPrint(arity), args.length,
-           name + " requires " + arity + " or more arguments");
-    }
-  }
-
   assertSame = function assertSame(expected, found, name_opt) {
-    checkArity(arguments, 2, "assertSame");
-
     // TODO(mstarzinger): We should think about using Harmony's egal operator
     // or the function equivalent Object.is() here.
     if (found === expected) {
@@ -253,8 +244,6 @@
 
 
   assertEquals = function assertEquals(expected, found, name_opt) {
-    checkArity(arguments, 2, "assertEquals");
-
     if (!deepEquals(found, expected)) {
       fail(PrettyPrint(expected), found, name_opt);
     }
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index bba86bd..26ec10b 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -51,9 +51,8 @@
   # Issue 3389: deopt_every_n_garbage_collections is unsafe
   'regress/regress-2653': [SKIP],
 
-  # This test relies on --noopt-safe-uint32-operations, which is broken. See
-  # issue 3487 for details.
-  'compiler/shift-shr': [SKIP],
+  # Issue 3784: setters-on-elements is flaky
+  'setters-on-elements': [PASS, FAIL],
 
   ##############################################################################
   # TurboFan compiler failures.
@@ -63,16 +62,10 @@
   # from the deoptimizer to do that.
   'arguments-indirect': [PASS, NO_VARIANTS],
 
-  # TODO(rossberg): Typer doesn't like contexts very much.
-  'harmony/block-conflicts': [PASS, NO_VARIANTS],
-  'harmony/block-for': [PASS, NO_VARIANTS],
-  'harmony/block-leave': [PASS, NO_VARIANTS],
-  'harmony/block-let-crankshaft': [PASS, NO_VARIANTS],
-  'harmony/empty-for': [PASS, NO_VARIANTS],
-
-  # Some tests are over-restrictive about object layout.
+  # TODO(verwaest): Some tests are over-restrictive about object layout.
   'array-constructor-feedback': [PASS, NO_VARIANTS],
   'array-feedback': [PASS, NO_VARIANTS],
+  'compare-known-objects-slow': [PASS, NO_VARIANTS],
   'elements-kind': [PASS, NO_VARIANTS],
 
   # Some tests are just too slow to run for now.
@@ -84,6 +77,10 @@
   'compiler/osr-assert': [PASS, NO_VARIANTS],
   'regress/regress-2185-2': [PASS, NO_VARIANTS],
 
+  # Issue 3660: Replacing activated TurboFan frames by unoptimized code does
+  # not work, but we expect it to not crash.
+  'debug-step-turbofan': [PASS, FAIL],
+
   # Support for %GetFrameDetails is missing and requires checkpoints.
   'debug-evaluate-bool-constructor': [PASS, NO_VARIANTS],
   'debug-evaluate-const': [PASS, NO_VARIANTS],
@@ -123,6 +120,9 @@
   'regress/regress-crbug-259300': [PASS, NO_VARIANTS],
   'regress/regress-frame-details-null-receiver': [PASS, NO_VARIANTS],
 
+  # TODO(arv): TurboFan does not yet add [[HomeObject]] as needed.
+  'harmony/object-literals-super': [PASS, NO_VARIANTS],
+
   ##############################################################################
   # Too slow in debug mode with --stress-opt mode.
   'compiler/regress-stacktrace-methods': [PASS, ['mode == debug', SKIP]],
@@ -177,7 +177,7 @@
   ##############################################################################
   # Tests verifying CHECK and ASSERT.
   'verify-check-false': [FAIL, NO_VARIANTS],
-  'verify-assert-false': [NO_VARIANTS, ['mode == release', PASS], ['mode == debug', FAIL]],
+  'verify-assert-false': [NO_VARIANTS, ['mode == release and dcheck_always_on == False', PASS], ['mode == debug or dcheck_always_on == True', FAIL]],
 
   ##############################################################################
   # Tests with different versions for release and debug.
@@ -195,8 +195,13 @@
 
   # Skip endain dependent test for mips due to different typed views of the same
   # array buffer.
-  'nans': [PASS, ['arch == mips', SKIP]],
+  'nans': [PASS, ],
 
+  # This test variant makes only sense on arm.
+  'math-floor-of-div-nosudiv': [PASS, SLOW, ['arch not in [arm, arm64, android_arm, android_arm64]', SKIP]],
+
+  # Too slow for slow variants.
+  'asm/embenchen/*': [PASS, SLOW, FAST_VARIANTS],
 }],  # ALWAYS
 
 ##############################################################################
@@ -211,10 +216,12 @@
   'elements-kind': [SKIP],
   'elements-transition-hoisting': [SKIP],
   'fast-prototype': [SKIP],
+  'field-type-tracking': [SKIP],
   'getters-on-elements': [SKIP],
   'harmony/block-let-crankshaft': [SKIP],
   'opt-elements-kind': [SKIP],
   'osr-elements-kind': [SKIP],
+  'regress/regress-crbug-137689': [SKIP],
   'regress/regress-165637': [SKIP],
   'regress/regress-2249': [SKIP],
   # Tests taking too long
@@ -233,6 +240,20 @@
   # TODO(mstarzinger): Takes too long with TF.
   'array-sort': [PASS, NO_VARIANTS],
   'regress/regress-91008': [PASS, NO_VARIANTS],
+  'regress/regress-417709a': [PASS, ['arch == arm64', NO_VARIANTS]],
+  'regress/regress-transcendental': [PASS, ['arch == arm64', NO_VARIANTS]],
+  'compiler/osr-regress-max-locals': [PASS, NO_VARIANTS],
+  'math-floor-of-div': [PASS, NO_VARIANTS],
+  'unicodelctest': [PASS, NO_VARIANTS],
+  'unicodelctest-no-optimization': [PASS, NO_VARIANTS],
+
+  # Too slow for gc stress.
+  'asm/embenchen/box2d': [SKIP],
+
+  # Issue 3723.
+  'regress/regress-3717': [SKIP],
+  # Issue 3776.
+  'debug-stepframe': [SKIP],
 }],  # 'gc_stress == True'
 
 ##############################################################################
@@ -249,6 +270,8 @@
   # Pass but take too long to run. Skip.
   # Some similar tests (with fewer iterations) may be included in arm64-js
   # tests.
+  'asm/embenchen/box2d': [SKIP],
+  'asm/embenchen/lua_binarytrees': [SKIP],
   'big-object-literal': [SKIP],
   'compiler/regress-arguments': [SKIP],
   'compiler/regress-gvn': [SKIP],
@@ -313,11 +336,16 @@
 ['arch == arm64 and mode == debug and simulator_run == True', {
 
   # Pass but take too long with the simulator in debug mode.
+  'array-iterate-backwards': [PASS, TIMEOUT],
   'array-sort': [PASS, TIMEOUT],
   'packed-elements': [SKIP],
   'regexp-global': [SKIP],
   'compiler/alloc-numbers': [SKIP],
   'harmony/symbols': [SKIP],
+  'math-floor-of-div': [PASS, TIMEOUT],
+  'math-floor-of-div-nosudiv': [PASS, TIMEOUT],
+  'unicodelctest': [PASS, TIMEOUT],
+  'unicodelctest-no-optimization': [PASS, TIMEOUT],
   # Issue 3219:
   'getters-on-elements': [PASS, ['gc_stress == True', FAIL]],
 }],  # 'arch == arm64 and mode == debug and simulator_run == True'
@@ -414,6 +442,15 @@
 }],  # 'arch == mipsel or arch == mips'
 
 ##############################################################################
+['arch == mips', {
+  # Flaky with TF.
+  'mirror-script': [PASS, NO_VARIANTS],
+
+  # Emscripten requires little-endian, skip all tests on MIPS EB.
+  'asm/embenchen/*': [SKIP],
+}],  # 'arch == mips'
+
+##############################################################################
 ['arch == mips64el', {
 
   # Slow tests which times out in debug mode.
@@ -472,6 +509,10 @@
 ['system == windows', {
   # TODO(mstarzinger): Too slow with turbo fan.
   'big-object-literal': [PASS, ['mode == debug', SKIP]],
+  'math-floor-of-div': [PASS, ['mode == debug', SKIP]],
+  'math-floor-of-div-nosudiv': [PASS, ['mode == debug', SKIP]],
+  'osr-regress-max-locals': [PASS, ['mode == debug', SKIP]],
+  'unicodelctest': [PASS, ['mode == debug', SKIP]],
 
   # BUG(v8:3435)
   'debug-script-breakpoints': [PASS, FAIL],
diff --git a/test/mjsunit/mod-range.js b/test/mjsunit/mod-range.js
new file mode 100644
index 0000000..0cded89
--- /dev/null
+++ b/test/mjsunit/mod-range.js
@@ -0,0 +1,79 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function g1(i) {
+  var x = i * 1;
+  return (x >>> 0) % 1000000000000;
+}
+
+function g2(i) {
+  var x = i * 1;
+  return ((x >>> 0) % 1000000000000) | 0;
+}
+
+function test1() {
+  assertEquals(2294967296, g1(-2000000000));
+  assertEquals(2294967295, g1(-2000000001));
+  assertEquals(2294967290, g1(-2000000006));
+
+  assertEquals(2147483651, g1(-2147483645));
+  assertEquals(2147483650, g1(-2147483646));
+  assertEquals(2147483649, g1(-2147483647));
+  assertEquals(2147483648, g1(-2147483648));
+  assertEquals(2147483647, g1(-2147483649));
+
+  assertEquals(3000000000, g1(3000000000));
+  assertEquals(3000000001, g1(3000000001));
+  assertEquals(3000000002, g1(3000000002));
+
+  assertEquals(4000000000, g1(4000000000));
+  assertEquals(4000400001, g1(4000400001));
+  assertEquals(4000400002, g1(4000400002));
+
+  assertEquals(3, g1(4294967299));
+  assertEquals(2, g1(4294967298));
+  assertEquals(1, g1(4294967297));
+  assertEquals(0, g1(4294967296));
+  assertEquals(4294967295, g1(4294967295));
+  assertEquals(4294967294, g1(4294967294));
+  assertEquals(4294967293, g1(4294967293));
+  assertEquals(4294967292, g1(4294967292));
+}
+
+%NeverOptimizeFunction(test1);
+test1();
+
+function test2() {
+  assertEquals(-2000000000, g2(-2000000000));
+  assertEquals(-2000000001, g2(-2000000001));
+  assertEquals(-2000000006, g2(-2000000006));
+
+  assertEquals(-2147483645, g2(-2147483645));
+  assertEquals(-2147483646, g2(-2147483646));
+  assertEquals(-2147483647, g2(-2147483647));
+  assertEquals(-2147483648, g2(-2147483648));
+  assertEquals(2147483647, g2(-2147483649));
+
+  assertEquals(-1294967296, g2(3000000000));
+  assertEquals(-1294967295, g2(3000000001));
+  assertEquals(-1294967294, g2(3000000002));
+
+  assertEquals(-294967296, g2(4000000000));
+  assertEquals(-294567295, g2(4000400001));
+  assertEquals(-294567294, g2(4000400002));
+
+  assertEquals(3, g2(4294967299));
+  assertEquals(2, g2(4294967298));
+  assertEquals(1, g2(4294967297));
+  assertEquals(0, g2(4294967296));
+  assertEquals(-1, g2(4294967295));
+  assertEquals(-2, g2(4294967294));
+  assertEquals(-3, g2(4294967293));
+  assertEquals(-4, g2(4294967292));
+}
+
+%NeverOptimizeFunction(test2);
+test2();
diff --git a/test/mjsunit/nans.js b/test/mjsunit/nans.js
index 987ad6e..5630e5b 100644
--- a/test/mjsunit/nans.js
+++ b/test/mjsunit/nans.js
@@ -27,6 +27,11 @@
 
 // Flags: --allow-natives-syntax
 
+// Helper to determine endian - returns true on little endian platforms
+function isLittleEndian() {
+  return ((new Uint32Array((new Uint8Array([4,3,2,1])).buffer))[0])
+           == 0x01020304;
+}
 
 // Test that both kinds of NaNs (signaling or quiet) do not signal
 
@@ -41,7 +46,11 @@
 function TestDoubleSignalingNan() {
   // NaN with signal bit set
   function f() {
-    var bytes = new Uint32Array([1, 0x7FF00000]);
+    if(isLittleEndian()) {
+      var bytes = new Uint32Array([1, 0x7FF00000]);
+    } else {
+      var bytes = new Uint32Array([0x7FF00000, 1]);
+    }
     var doubles = new Float64Array(bytes.buffer);
     assertTrue(isNaN(doubles[0]));
     assertTrue(isNaN(doubles[0]*2.0));
@@ -56,7 +65,11 @@
 function TestDoubleQuietNan() {
   // NaN with signal bit cleared
   function f() {
-    var bytes = new Uint32Array([0, 0x7FF80000]);
+    if(isLittleEndian()) {
+      var bytes = new Uint32Array([0, 0x7FF80000]);
+    } else {
+      var bytes = new Uint32Array([0x7FF80000, 0]);
+    }
     var doubles = new Float64Array(bytes.buffer);
     assertTrue(isNaN(doubles[0]));
     assertTrue(isNaN(doubles[0]*2.0));
diff --git a/test/mjsunit/object-freeze-global.js b/test/mjsunit/object-freeze-global.js
new file mode 100644
index 0000000..8ab5b85
--- /dev/null
+++ b/test/mjsunit/object-freeze-global.js
@@ -0,0 +1,6 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+Object.freeze(this);
+assertTrue(Object.isFrozen(this));
diff --git a/test/mjsunit/object-freeze.js b/test/mjsunit/object-freeze.js
index 4144936..5d1f8b7 100644
--- a/test/mjsunit/object-freeze.js
+++ b/test/mjsunit/object-freeze.js
@@ -303,7 +303,7 @@
 
 // Also test a simpler case
 obj = {};
-Object.defineProperty(obj, 'accessor', {
+Object.defineProperty(obj, 'accessor2', {
   get: function() { return 42 },
   set: function() { accessorDidRun = true },
   configurable: true,
@@ -339,3 +339,12 @@
 assertEquals(1, obj[1]);
 Object.freeze(obj);
 assertThrows(function() { obj.unshift(); }, TypeError);
+
+// Sealing and then Freezing should do the right thing.
+var obj = { foo: 'bar', 0: 'element' };
+Object.seal(obj);
+assertTrue(Object.isSealed(obj));
+assertFalse(Object.isFrozen(obj));
+Object.freeze(obj);
+assertTrue(Object.isSealed(obj));
+assertTrue(Object.isFrozen(obj));
diff --git a/test/mjsunit/object-get-own-property-names.js b/test/mjsunit/object-get-own-property-names.js
index 64607c6..aee6585 100644
--- a/test/mjsunit/object-get-own-property-names.js
+++ b/test/mjsunit/object-get-own-property-names.js
@@ -87,30 +87,20 @@
 assertSame(Array.prototype, propertyNames.__proto__);
 Array.prototype.concat = savedConcat;
 
-try {
-  Object.getOwnPropertyNames(4);
-  assertTrue(false);
-} catch (e) {
-  assertTrue(/on non-object/.test(e));
-}
-
-try {
-  Object.getOwnPropertyNames("foo");
-  assertTrue(false);
-} catch (e) {
-  assertTrue(/on non-object/.test(e));
-}
+assertEquals(Object.getOwnPropertyNames(4), []);
+assertEquals(Object.getOwnPropertyNames("foo"), ["0", "1", "2", "length"]);
+assertEquals(Object.getOwnPropertyNames(true), []);
 
 try {
   Object.getOwnPropertyNames(undefined);
   assertTrue(false);
 } catch (e) {
-  assertTrue(/on non-object/.test(e));
+  assertTrue(/Cannot convert undefined or null to object/.test(e));
 }
 
 try {
   Object.getOwnPropertyNames(null);
   assertTrue(false);
 } catch (e) {
-  assertTrue(/on non-object/.test(e));
+  assertTrue(/Cannot convert undefined or null to object/.test(e));
 }
diff --git a/test/mjsunit/object-is.js b/test/mjsunit/object-is.js
index b9fdc84..c57542f 100644
--- a/test/mjsunit/object-is.js
+++ b/test/mjsunit/object-is.js
@@ -32,8 +32,8 @@
   assertSame(expected, Object.is(x, y));
 }
 
-var test_set = [ {}, [], 1/0, -1/0, "s", 0, 0/-1, null, undefined ];
-print(test_set);
+var test_set = [ {}, [], Infinity, -Infinity, "s", "ã‚¢", 0, 0/-1, null,
+    undefined, true, false, Symbol("foo"), NaN ];
 for (var i = 0; i < test_set.length; i++) {
   for (var j = 0; j < test_set.length; j++) {
     if (i == j) {
diff --git a/test/mjsunit/object-prevent-extensions.js b/test/mjsunit/object-prevent-extensions.js
index 6b9184d..bde3161 100644
--- a/test/mjsunit/object-prevent-extensions.js
+++ b/test/mjsunit/object-prevent-extensions.js
@@ -27,6 +27,8 @@
 
 // Tests the Object.preventExtensions method - ES 15.2.3.10
 
+// Flags: --allow-natives-syntax
+
 
 var obj1 = {};
 // Extensible defaults to true.
@@ -126,3 +128,35 @@
 var n = o[0] = 100;
 assertEquals(undefined, o[0]);
 assertEquals(100, n);
+
+// Fast properties should remain fast
+obj = { x: 42, y: 'foo' };
+assertTrue(%HasFastProperties(obj));
+Object.preventExtensions(obj);
+assertFalse(Object.isExtensible(obj));
+assertFalse(Object.isSealed(obj));
+assertTrue(%HasFastProperties(obj));
+
+// Non-extensible objects should share maps where possible
+obj = { prop1: 1, prop2: 2 };
+obj2 = { prop1: 3, prop2: 4 };
+assertTrue(%HaveSameMap(obj, obj2));
+Object.preventExtensions(obj);
+Object.preventExtensions(obj2);
+assertFalse(Object.isExtensible(obj));
+assertFalse(Object.isExtensible(obj2));
+assertFalse(Object.isSealed(obj));
+assertFalse(Object.isSealed(obj2));
+assertTrue(%HaveSameMap(obj, obj2));
+
+// Non-extensible objects should share maps even when they have elements
+obj = { prop1: 1, prop2: 2, 75: 'foo' };
+obj2 = { prop1: 3, prop2: 4, 150: 'bar' };
+assertTrue(%HaveSameMap(obj, obj2));
+Object.preventExtensions(obj);
+Object.preventExtensions(obj2);
+assertFalse(Object.isExtensible(obj));
+assertFalse(Object.isExtensible(obj2));
+assertFalse(Object.isSealed(obj));
+assertFalse(Object.isSealed(obj2));
+assertTrue(%HaveSameMap(obj, obj2));
diff --git a/test/mjsunit/object-seal-global.js b/test/mjsunit/object-seal-global.js
new file mode 100644
index 0000000..ec9f82e
--- /dev/null
+++ b/test/mjsunit/object-seal-global.js
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+Object.seal(this);
+assertTrue(Object.isSealed(this));
+assertFalse(Object.isFrozen(this));
diff --git a/test/mjsunit/object-seal.js b/test/mjsunit/object-seal.js
index 3afddb9..3c46ab2 100644
--- a/test/mjsunit/object-seal.js
+++ b/test/mjsunit/object-seal.js
@@ -267,3 +267,132 @@
 assertDoesNotThrow(function() { obj.splice(1,2000,1,2); });
 assertThrows(function() { obj.splice(0,0,1); }, TypeError);
 assertThrows(function() { obj.splice(1,2000,1,2,3); }, TypeError);
+
+// Test that the enumerable attribute is unperturbed by sealing.
+obj = { x: 42, y: 'foo' };
+Object.defineProperty(obj, 'y', {enumerable: false});
+Object.seal(obj);
+assertTrue(Object.isSealed(obj));
+assertFalse(Object.isFrozen(obj));
+desc = Object.getOwnPropertyDescriptor(obj, 'x');
+assertTrue(desc.enumerable);
+desc = Object.getOwnPropertyDescriptor(obj, 'y');
+assertFalse(desc.enumerable);
+
+// Fast properties should remain fast
+obj = { x: 42, y: 'foo' };
+assertTrue(%HasFastProperties(obj));
+Object.seal(obj);
+assertTrue(Object.isSealed(obj));
+assertFalse(Object.isFrozen(obj));
+assertTrue(%HasFastProperties(obj));
+
+// Sealed objects should share maps where possible
+obj = { prop1: 1, prop2: 2 };
+obj2 = { prop1: 3, prop2: 4 };
+assertTrue(%HaveSameMap(obj, obj2));
+Object.seal(obj);
+Object.seal(obj2);
+assertTrue(Object.isSealed(obj));
+assertTrue(Object.isSealed(obj2));
+assertFalse(Object.isFrozen(obj));
+assertFalse(Object.isFrozen(obj2));
+assertTrue(%HaveSameMap(obj, obj2));
+
+// Sealed objects should share maps even when they have elements
+obj = { prop1: 1, prop2: 2, 75: 'foo' };
+obj2 = { prop1: 3, prop2: 4, 150: 'bar' };
+assertTrue(%HaveSameMap(obj, obj2));
+Object.seal(obj);
+Object.seal(obj2);
+assertTrue(Object.isSealed(obj));
+assertTrue(Object.isSealed(obj2));
+assertFalse(Object.isFrozen(obj));
+assertFalse(Object.isFrozen(obj));
+assertTrue(%HaveSameMap(obj, obj2));
+
+// Setting elements after sealing should not be allowed
+obj = { prop: 'thing' };
+Object.seal(obj);
+assertTrue(Object.isSealed(obj));
+assertFalse(Object.isFrozen(obj));
+obj[0] = 'hello';
+assertFalse(obj.hasOwnProperty(0));
+
+// Sealing an object in dictionary mode should work
+// Also testing that getter/setter properties work after sealing
+obj = { };
+for (var i = 0; i < 100; ++i) {
+  obj['x' + i] = i;
+}
+var accessorDidRun = false;
+Object.defineProperty(obj, 'accessor', {
+  get: function() { return 42 },
+  set: function() { accessorDidRun = true },
+  configurable: true,
+  enumerable: true
+});
+
+assertFalse(%HasFastProperties(obj));
+Object.seal(obj);
+assertFalse(%HasFastProperties(obj));
+assertTrue(Object.isSealed(obj));
+assertFalse(Object.isFrozen(obj));
+assertFalse(Object.isExtensible(obj));
+for (var i = 0; i < 100; ++i) {
+  desc = Object.getOwnPropertyDescriptor(obj, 'x' + i);
+  assertFalse(desc.configurable);
+}
+assertEquals(42, obj.accessor);
+assertFalse(accessorDidRun);
+obj.accessor = 'ignored value';
+assertTrue(accessorDidRun);
+
+// Sealing arguments should work
+var func = function(arg) {
+  Object.seal(arguments);
+  assertTrue(Object.isSealed(arguments));
+};
+func('hello', 'world');
+func('goodbye', 'world');
+
+// Sealing sparse arrays
+var sparseArr = [0, 1];
+sparseArr[10000] = 10000;
+Object.seal(sparseArr);
+assertTrue(Object.isSealed(sparseArr));
+
+// Accessors on fast object should behavior properly after sealing
+obj = {};
+Object.defineProperty(obj, 'accessor', {
+  get: function() { return 42 },
+  set: function() { accessorDidRun = true },
+  configurable: true,
+  enumerable: true
+});
+assertTrue(%HasFastProperties(obj));
+Object.seal(obj);
+assertTrue(Object.isSealed(obj));
+assertTrue(%HasFastProperties(obj));
+assertEquals(42, obj.accessor);
+accessorDidRun = false;
+obj.accessor = 'ignored value';
+assertTrue(accessorDidRun);
+
+// Test for regression in mixed accessor/data property objects.
+// The strict function is one such object.
+assertTrue(Object.isSealed(Object.seal(function(){"use strict";})));
+
+// Also test a simpler case
+obj = {};
+Object.defineProperty(obj, 'accessor2', {
+  get: function() { return 42 },
+  set: function() { accessorDidRun = true },
+  configurable: true,
+  enumerable: true
+});
+obj.data = 'foo';
+assertTrue(%HasFastProperties(obj));
+Object.seal(obj);
+assertTrue(%HasFastProperties(obj));
+assertTrue(Object.isSealed(obj));
diff --git a/test/mjsunit/opt-elements-kind.js b/test/mjsunit/opt-elements-kind.js
index be7303b..5f4f437 100644
--- a/test/mjsunit/opt-elements-kind.js
+++ b/test/mjsunit/opt-elements-kind.js
@@ -142,10 +142,16 @@
   assertTrue(%HaveSameMap(smis, doubles));
 }
 
+function clear_ic_state() {
+  %ClearFunctionTypeFeedback(construct_smis);
+  %ClearFunctionTypeFeedback(construct_doubles);
+  %ClearFunctionTypeFeedback(convert_mixed);
+}
+
 test1();
-gc(); // clear IC state
+clear_ic_state();
 test1();
-gc(); // clear IC state
+clear_ic_state();
 %OptimizeFunctionOnNextCall(test1);
 test1();
-gc(); // clear IC state
+clear_ic_state();
diff --git a/test/mjsunit/parse-surrogates.js b/test/mjsunit/parse-surrogates.js
new file mode 100644
index 0000000..5ed9b52
--- /dev/null
+++ b/test/mjsunit/parse-surrogates.js
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Test that the parser throws on unmatched surrogates.
+assertThrows("var \uD801\uABCD;", SyntaxError);
+assertThrows("'\\u000\uD801\uABCD'", SyntaxError);
diff --git a/test/mjsunit/polymorph-arrays.js b/test/mjsunit/polymorph-arrays.js
index 2bb0433..6a05c9f 100644
--- a/test/mjsunit/polymorph-arrays.js
+++ b/test/mjsunit/polymorph-arrays.js
@@ -36,7 +36,7 @@
   for (var i = 0; i < 10; ++i ){
     a[i] = i;
   }
-  a[5000000] = 256;
+  a[200000] = 256;
   return %NormalizeElements(a);
 }
 
@@ -115,7 +115,7 @@
     var sparse_object_array = new Object;
     var js_array = new Array(10);
     var sparse_js_array = [];
-    sparse_js_array.length = 5000001;
+    sparse_js_array.length = 200001;
 
     init_array(object_array);
     init_array(js_array);
@@ -134,7 +134,8 @@
   var sparse_object_array = new Object;
   var js_array = new Array(10);
   var sparse_js_array = %NormalizeElements([]);
-  sparse_js_array.length = 5000001;
+  sparse_js_array.length = 200001;
+  assertTrue(%HasDictionaryElements(sparse_js_array));
 
   init_array(object_array);
   init_array(js_array);
diff --git a/test/mjsunit/regress-ntl.js b/test/mjsunit/regress-ntl.js
new file mode 100644
index 0000000..993599e
--- /dev/null
+++ b/test/mjsunit/regress-ntl.js
@@ -0,0 +1,41 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function mod1() {
+  var v_1 = 1;
+  var v_2 = 1;
+  v_1++;
+  v_2 = {valueOf: function() { throw "gagh"; }};
+
+  function bug1() {
+    for (var i = 0; i < 1; v_2++) {
+      if (v_1 == 1) ;
+    }
+  }
+
+  return bug1;
+}
+
+var f = mod1();
+assertThrows(f);
+%OptimizeFunctionOnNextCall(f);
+assertThrows(f);
+
+
+var v_3 = 1;
+var v_4 = 1;
+v_3++;
+v_4 = {valueOf: function() { throw "gagh"; }};
+
+function bug2() {
+  for (var i = 0; i < 1; v_4++) {
+    if (v_3 == 1) ;
+  }
+}
+
+assertThrows(bug2);
+%OptimizeFunctionOnNextCall(bug2);
+assertThrows(bug2);
diff --git a/test/mjsunit/regress/regress-136048.js b/test/mjsunit/regress/regress-136048.js
index c9972e9..21ae622 100644
--- a/test/mjsunit/regress/regress-136048.js
+++ b/test/mjsunit/regress/regress-136048.js
@@ -26,9 +26,9 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 try {
-  /foo/\u0069
+  eval("/foo/\\u0069")
 } catch (e) {
   assertEquals(
-      "SyntaxError: Invalid flags supplied to RegExp constructor '\\u0069'",
+      "SyntaxError: Invalid regular expression flags",
       e.toString());
 }
diff --git a/test/mjsunit/regress/regress-1757.js b/test/mjsunit/regress/regress-1757.js
index 35e7355..a850f70 100644
--- a/test/mjsunit/regress/regress-1757.js
+++ b/test/mjsunit/regress/regress-1757.js
@@ -27,6 +27,7 @@
 
 // Flags: --string-slices --expose-externalize-string
 
-var a = "abcdefghijklmnopqrstuvqxy"+"z";
+var a = "internalized dummy";
+a = "abcdefghijklmnopqrstuvqxy"+"z";
 externalizeString(a, true);
 assertEquals('b', a.substring(1).charAt(0));
diff --git a/test/mjsunit/regress/regress-2506.js b/test/mjsunit/regress/regress-2506.js
new file mode 100644
index 0000000..0eb2770
--- /dev/null
+++ b/test/mjsunit/regress/regress-2506.js
@@ -0,0 +1,78 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-scoping
+
+'use strict';
+
+// Top-level code
+let s = 0;
+let f = [undefined, undefined, undefined]
+for (const x of [1,2,3]) {
+  s += x;
+  f[x-1] = function() { return x; }
+}
+assertEquals(6, s);
+assertEquals(1, f[0]());
+assertEquals(2, f[1]());
+assertEquals(3, f[2]());
+
+let x = 1;
+s = 0;
+for (const x of [x, x+1, x+2]) {
+  s += x;
+}
+assertEquals(6, s);
+
+s = 0;
+var q = 1;
+for (const q of [q, q+1, q+2]) {
+  s += q;
+}
+assertEquals(6, s);
+
+let z = 1;
+s = 0;
+for (const x = 1; z < 2; z++) {
+  s += x + z;
+}
+assertEquals(2, s);
+
+
+s = "";
+for (const x in [1,2,3]) {
+  s += x;
+}
+assertEquals("012", s);
+
+assertThrows("'use strict'; for (const x in [1,2,3]) { x++ }", TypeError);
+
+// Function scope
+(function() {
+  let s = 0;
+  for (const x of [1,2,3]) {
+    s += x;
+  }
+  assertEquals(6, s);
+
+  let x = 1;
+  s = 0;
+  for (const x of [x, x+1, x+2]) {
+    s += x;
+  }
+  assertEquals(6, s);
+
+  s = 0;
+  var q = 1;
+  for (const q of [q, q+1, q+2]) {
+    s += q;
+  }
+  assertEquals(6, s);
+
+  s = "";
+  for (const x in [1,2,3]) {
+    s += x;
+  }
+  assertEquals("012", s);
+}());
diff --git a/test/mjsunit/regress/regress-2615.js b/test/mjsunit/regress/regress-2615.js
new file mode 100644
index 0000000..6b277e8
--- /dev/null
+++ b/test/mjsunit/regress/regress-2615.js
@@ -0,0 +1,96 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+a = [1];
+Object.defineProperty(a, "1", {writable:false, configurable:false, value: 100});
+assertThrows("a.unshift(4);", TypeError);
+assertEquals([1, 100, 100], a);
+var desc = Object.getOwnPropertyDescriptor(a, "1");
+assertEquals(false, desc.writable);
+assertEquals(false, desc.configurable);
+
+a = [1];
+var g = function() { return 100; };
+Object.defineProperty(a, "1", {get:g});
+assertThrows("a.unshift(0);", TypeError);
+assertEquals([1, 100, 100], a);
+desc = Object.getOwnPropertyDescriptor(a, "1");
+assertEquals(false, desc.configurable);
+assertEquals(g, desc.get);
+
+a = [1];
+var c = 0;
+var s = function(v) { c += 1; };
+Object.defineProperty(a, "1", {set:s});
+a.unshift(10);
+assertEquals([10, undefined, undefined], a);
+assertEquals(1, c);
+desc = Object.getOwnPropertyDescriptor(a, "1");
+assertEquals(false, desc.configurable);
+assertEquals(s, desc.set);
+
+a = [1];
+Object.defineProperty(a, "1", {configurable:false, value:10});
+assertThrows("a.splice(1,1);", TypeError);
+assertEquals([1, 10], a);
+desc = Object.getOwnPropertyDescriptor(a, "1");
+assertEquals(false, desc.configurable);
+
+a = [0,1,2,3,4,5,6];
+Object.defineProperty(a, "3", {configurable:false, writable:false, value:3});
+assertThrows("a.splice(1,4);", TypeError);
+assertEquals([0,5,6,3,,,,], a);
+desc = Object.getOwnPropertyDescriptor(a, "3");
+assertEquals(false, desc.configurable);
+assertEquals(false, desc.writable);
+
+a = [0,1,2,3,4,5,6];
+Object.defineProperty(a, "5", {configurable:false, value:5});
+assertThrows("a.splice(1,4);", TypeError);
+assertEquals([0,5,6,3,4,5,,], a);
+desc = Object.getOwnPropertyDescriptor(a, "5");
+assertEquals(false, desc.configurable);
+
+a = [1,2,3,,5];
+Object.defineProperty(a, "1", {configurable:false, writable:true, value:2});
+assertEquals(1, a.shift());
+assertEquals([2,3,,5], a);
+desc = Object.getOwnPropertyDescriptor(a, "1");
+assertEquals(false, desc.configurable);
+assertEquals(true, desc.writable);
+assertThrows("a.shift();", TypeError);
+assertEquals([3,3,,5], a);
+desc = Object.getOwnPropertyDescriptor(a, "1");
+assertEquals(false, desc.configurable);
+assertEquals(true, desc.writable);
+
+a = [1,2,3];
+Object.defineProperty(a, "2", {configurable:false, value:3});
+assertThrows("a.pop();", TypeError);
+assertEquals([1,2,3], a);
+desc = Object.getOwnPropertyDescriptor(a, "2");
+assertEquals(false, desc.configurable);
diff --git a/test/mjsunit/regress/regress-3229.js b/test/mjsunit/regress/regress-3229.js
new file mode 100644
index 0000000..1a0ed64
--- /dev/null
+++ b/test/mjsunit/regress/regress-3229.js
@@ -0,0 +1,26 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Escape '/'.
+function testEscapes(expected, regexp) {
+  assertEquals(expected, regexp.source);
+  assertEquals("/" + expected + "/", regexp.toString());
+}
+
+testEscapes("\\/", /\//);
+testEscapes("\\/\\/", /\/\//);
+testEscapes("\\/", new RegExp("/"));
+testEscapes("\\/", new RegExp("\\/"));
+testEscapes("\\\\/", new RegExp("\\\\/"));
+testEscapes("\\/\\/", new RegExp("\\/\\/"));
+testEscapes("\\/\\/\\/\\/", new RegExp("////"));
+testEscapes("\\/\\/\\/\\/", new RegExp("\\//\\//"));
+testEscapes("(?:)", new RegExp(""));
+testEscapes("(?:)", RegExp.prototype);
+
+// Read-only property.
+var r = /\/\//;
+testEscapes("\\/\\/", r);
+r.source = "garbage";
+testEscapes("\\/\\/", r);
diff --git a/test/mjsunit/regress/regress-3483.js b/test/mjsunit/regress/regress-3483.js
new file mode 100644
index 0000000..dec95c4
--- /dev/null
+++ b/test/mjsunit/regress/regress-3483.js
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+assertFalse(Object.prototype.isPrototypeOf.call());
+assertFalse(Object.prototype.isPrototypeOf.call(null, 1));
+assertFalse(Object.prototype.isPrototypeOf.call(undefined, 1));
diff --git a/test/mjsunit/regress/regress-3612.js b/test/mjsunit/regress/regress-3612.js
new file mode 100644
index 0000000..8c30ebf
--- /dev/null
+++ b/test/mjsunit/regress/regress-3612.js
@@ -0,0 +1,21 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var a = [1];
+var getterValue = 2;
+var endIndex = 0xffff;
+Object.defineProperty(a, endIndex, {
+  get: function() {
+    this[1] = 3;
+    return getterValue;
+  },
+  set: function(val) {
+    getterValue = val;
+  },
+  configurable: true,
+  enumerable: true
+});
+a.reverse();
+assertFalse(a.hasOwnProperty(1));
+assertEquals(3, a[endIndex-1]);
diff --git a/test/mjsunit/regress/regress-3621.js b/test/mjsunit/regress/regress-3621.js
new file mode 100644
index 0000000..16ddde1
--- /dev/null
+++ b/test/mjsunit/regress/regress-3621.js
@@ -0,0 +1,11 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var a = [];
+var endIndex = 0xffff;
+a[endIndex] = 3;
+Object.defineProperty(a, 0, { get: function() { this[1] = 2; return 1; } });
+assertEquals('123', a.join(''));
+delete a[1];  // reset the array
+assertEquals('1,2,', a.join().slice(0, 4));
diff --git a/test/mjsunit/regress/regress-3643.js b/test/mjsunit/regress/regress-3643.js
new file mode 100644
index 0000000..bbc94fd
--- /dev/null
+++ b/test/mjsunit/regress/regress-3643.js
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function newArrayWithGetter() {
+  var arr = [1, 2, 3];
+  Object.defineProperty(arr, '1', {
+    get: function() { delete this[1]; return undefined; },
+    configurable: true
+  });
+  return arr;
+}
+
+var a = newArrayWithGetter();
+var s = a.slice(1);
+assertTrue('0' in s);
+
+// Sparse case should hit the same code as above due to presence of the getter.
+a = newArrayWithGetter();
+a[0xffff] = 4;
+s = a.slice(1);
+assertTrue('0' in s);
+
+a = newArrayWithGetter();
+a.shift();
+assertTrue('0' in a);
+
+a = newArrayWithGetter();
+a.unshift(0);
+assertTrue('2' in a);
diff --git a/test/mjsunit/regress/regress-3687.js b/test/mjsunit/regress/regress-3687.js
new file mode 100644
index 0000000..e1df1b4
--- /dev/null
+++ b/test/mjsunit/regress/regress-3687.js
@@ -0,0 +1,22 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+var t1 = { f1: 0 };
+var t2 = { f2: 0 };
+
+var z = {
+  x: {
+    x: t1,
+    y: {
+      x: {},
+      z1: {
+        x: t2,
+        y: 1
+      }
+    }
+  },
+  z2: 0
+};
diff --git a/test/mjsunit/regress/regress-3709.js b/test/mjsunit/regress/regress-3709.js
new file mode 100644
index 0000000..d2de711
--- /dev/null
+++ b/test/mjsunit/regress/regress-3709.js
@@ -0,0 +1,28 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function getobj() {
+  return { bar : function() { return 0}};
+}
+
+function foo() {
+  var obj = getobj();
+  var length = arguments.length;
+  if (length == 0) {
+     obj.bar();
+  } else {
+     obj.bar.apply(obj, arguments);
+  }
+}
+
+foo();
+foo();
+%OptimizeFunctionOnNextCall(foo);
+foo();
+assertOptimized(foo);
+foo(10);
+assertUnoptimized(foo);
+%ClearFunctionTypeFeedback(foo);
diff --git a/test/mjsunit/regress/regress-3717.js b/test/mjsunit/regress/regress-3717.js
new file mode 100644
index 0000000..1f7bc7d
--- /dev/null
+++ b/test/mjsunit/regress/regress-3717.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug --no-lazy
+
+Debug = debug.Debug;
+var exception = null;
+var break_count = 0;
+
+function f() {
+  function g(p) {
+    return 1;
+  }
+  g(1);
+};
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) break_count++;
+  } catch (e) {
+    exception = e;
+  }
+}
+
+Debug.setListener(listener);
+var bp = Debug.setBreakPoint(f, 2);
+f();
+Debug.clearBreakPoint(bp);
+Debug.setListener(null);
+
+assertEquals(1, break_count);
+assertNull(exception);
diff --git a/test/mjsunit/regress/regress-3756.js b/test/mjsunit/regress/regress-3756.js
new file mode 100644
index 0000000..6b1f029
--- /dev/null
+++ b/test/mjsunit/regress/regress-3756.js
@@ -0,0 +1,74 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function TestIdentityEscapes() {
+  // \u not followed by 4 hex digits is treated as an identity escape.
+  var r0 = /\u/;
+  assertTrue(r0.test("u"));
+
+  r0 = RegExp("\\u");
+  assertTrue(r0.test("u"));
+
+  var r1 = /\usecond/;
+  assertTrue(r1.test("usecond"));
+
+  r1 = RegExp("\\usecond");
+  assertTrue(r1.test("usecond"));
+
+  var r2 = /first\u/;
+  assertTrue(r2.test("firstu"));
+  // This used to return true (which was a bug).
+  assertFalse(r2.test("first\\u"));
+
+  r2 = RegExp("first\\u");
+  assertTrue(r2.test("firstu"));
+  // This used to return true (which was a bug).
+  assertFalse(r2.test("first\\u"));
+
+  var r3 = /first\usecond/;
+  assertTrue(r3.test("firstusecond"));
+  assertFalse(r3.test("first\\usecond"));
+
+  r3 = RegExp("first\\usecond");
+  assertTrue(r3.test("firstusecond"));
+  assertFalse(r3.test("first\\usecond"));
+
+  var r4 = /first\u123second/;
+  assertTrue(r4.test("firstu123second"));
+  assertFalse(r4.test("first\\u123second"));
+
+  r4 = RegExp("first\\u123second");
+  assertTrue(r4.test("firstu123second"));
+  assertFalse(r4.test("first\\u123second"));
+
+  // \X where X is not a legal escape character is treated as identity escape
+  // too.
+  var r5 = /\a/;
+  assertTrue(r5.test("a"));
+
+  r5 = RegExp("\\a");
+  assertTrue(r5.test("a"));
+
+  var r6 = /\asecond/;
+  assertTrue(r6.test("asecond"));
+
+  r6 = RegExp("\\asecond");
+  assertTrue(r6.test("asecond"));
+
+  var r7 = /first\a/;
+  assertTrue(r7.test("firsta"));
+  assertFalse(r7.test("first\\a"));
+
+  r7 = RegExp("first\\a");
+  assertTrue(r7.test("firsta"));
+  assertFalse(r7.test("first\\a"));
+
+  var r8 = /first\asecond/;
+  assertTrue(r8.test("firstasecond"));
+  assertFalse(r8.test("first\\asecond"));
+
+  r8 = RegExp("first\\asecond");
+  assertTrue(r8.test("firstasecond"));
+  assertFalse(r8.test("first\\asecond"));
+})();
diff --git a/test/mjsunit/regress/regress-385565.js b/test/mjsunit/regress/regress-385565.js
new file mode 100644
index 0000000..d2a0875
--- /dev/null
+++ b/test/mjsunit/regress/regress-385565.js
@@ -0,0 +1,70 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//   * Redistributions of source code must retain the above copyright
+//     notice, this list of conditions and the following disclaimer.
+//   * Redistributions in binary form must reproduce the above
+//     copyright notice, this list of conditions and the following
+//     disclaimer in the documentation and/or other materials provided
+//     with the distribution.
+//   * Neither the name of Google Inc. nor the names of its
+//     contributors may be used to endorse or promote products derived
+//     from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --noalways-opt
+
+var calls = 0;
+
+function callsFReceiver(o) {
+    return [].f.call(new Number(o.m), 1, 2, 3);
+}
+
+// For the HConstant
+Array.prototype.f = function() {
+    calls++;
+    return +this;
+};
+
+
+var o1 = {m: 1};
+var o2 = {a: 0, m:1};
+
+var r1 = callsFReceiver(o1);
+callsFReceiver(o1);
+%OptimizeFunctionOnNextCall(callsFReceiver);
+var r2 = callsFReceiver(o1);
+assertOptimized(callsFReceiver);
+callsFReceiver(o2);
+assertUnoptimized(callsFReceiver);
+var r3 = callsFReceiver(o1);
+
+assertEquals(1, r1);
+assertTrue(r1 === r2);
+assertTrue(r2 === r3);
+
+r1 = callsFReceiver(o1);
+callsFReceiver(o1);
+%OptimizeFunctionOnNextCall(callsFReceiver);
+r2 = callsFReceiver(o1);
+callsFReceiver(o2);
+r3 = callsFReceiver(o1);
+
+assertEquals(1, r1);
+assertTrue(r1 === r2);
+assertTrue(r2 === r3);
+
+assertEquals(10, calls);
diff --git a/test/mjsunit/regress/regress-410030.js b/test/mjsunit/regress/regress-410030.js
new file mode 100644
index 0000000..efd4b1e
--- /dev/null
+++ b/test/mjsunit/regress/regress-410030.js
@@ -0,0 +1,43 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+try {
+  throw 0;
+} catch(e) {
+  assertSame(3, eval("delete x; const x=3; x"));
+}
+
+
+try {
+  throw 0;
+} catch(e) {
+  assertSame(3, (1,eval)("delete x1; const x1=3; x1"));
+}
+
+
+try {
+  throw 0;
+} catch(e) {
+  with({}) {
+    assertSame(3, eval("delete x2; const x2=3; x2"));
+  }
+}
+
+
+(function f() {
+  try {
+    throw 0;
+  } catch(e) {
+    assertSame(3, eval("delete x; const x=3; x"));
+  }
+}());
+
+
+(function f() {
+  try {
+    throw 0;
+  } catch(e) {
+    assertSame(3, (1,eval)("delete x4; const x4=3; x4"));
+  }
+}());
diff --git a/test/mjsunit/regress/regress-416730.js b/test/mjsunit/regress/regress-416730.js
new file mode 100644
index 0000000..8d7f207
--- /dev/null
+++ b/test/mjsunit/regress/regress-416730.js
@@ -0,0 +1,24 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+var d = {x: undefined, y: undefined};
+
+function Crash(left, right) {
+  var c = {
+    x: right.x - left.x,
+    y: right.y - left.y
+  };
+  return c.x * c.y;
+}
+
+var a = {x: 0.5, y: 0};
+var b = {x: 1, y: 0};
+
+for (var i = 0; i < 3; i++) Crash(a, b);
+%OptimizeFunctionOnNextCall(Crash);
+Crash(a, b);
+
+Crash({x: 0, y: 0.5}, b);
diff --git a/test/mjsunit/regress/regress-417709a.js b/test/mjsunit/regress/regress-417709a.js
new file mode 100644
index 0000000..7c4d4f7
--- /dev/null
+++ b/test/mjsunit/regress/regress-417709a.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --stack-size=100 --turbo-deoptimization
+
+var a = [];
+
+Object.observe(a, function() {});
+
+function f(a, x) {
+  a.length = x;
+  f(a, x + 1);
+}
+
+assertThrows(function() { f(a, 1); }, RangeError);
diff --git a/test/mjsunit/regress/regress-417709b.js b/test/mjsunit/regress/regress-417709b.js
new file mode 100644
index 0000000..7680543
--- /dev/null
+++ b/test/mjsunit/regress/regress-417709b.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --stack-size=100
+
+var a = [];
+
+Array.observe(a, function() {});
+
+function f(a, x) {
+  a.length = x;
+  f(a, x + 1);
+}
+
+assertThrows(function() { f(a, 1); }, RangeError);
diff --git a/test/mjsunit/regress/regress-419663.js b/test/mjsunit/regress/regress-419663.js
new file mode 100644
index 0000000..6f51741
--- /dev/null
+++ b/test/mjsunit/regress/regress-419663.js
@@ -0,0 +1,37 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+
+var o = {
+  f: function(x) {
+    var a = x + 1;
+    o = 1;
+  }
+}
+
+function sentinel() {}
+
+var Debug = debug.Debug;
+
+Debug.setListener(function() {});
+
+var script = Debug.findScript(sentinel);
+
+// Used in Debug.setScriptBreakPointById.
+var p = Debug.findScriptSourcePosition(script, 9, 0);
+var q = Debug.setBreakPointByScriptIdAndPosition(script.id, p).actual_position;
+var r = Debug.setBreakPointByScriptIdAndPosition(script.id, q).actual_position;
+
+assertEquals(q, r);
+
+function assertLocation(p, l, c) {
+  var location = script.locationFromPosition(p, false);
+  assertEquals(l, location.line);
+  assertEquals(c, location.column);
+}
+
+assertLocation(p, 9, 0);
+assertLocation(q, 9, 4);
+assertLocation(r, 9, 4);
diff --git a/test/mjsunit/regress/regress-423633.js b/test/mjsunit/regress/regress-423633.js
new file mode 100644
index 0000000..12d2483
--- /dev/null
+++ b/test/mjsunit/regress/regress-423633.js
@@ -0,0 +1,18 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+Object.defineProperty(Array.prototype, '0', {
+  get: function() { return false; },
+});
+var a = [1, 2, 3];
+assertEquals(a, a.slice());
+assertEquals([3], a.splice(2, 1));
+
+a = [1, 2, 3];
+a[0xffff] = 4;
+// nulling the prototype lets us stay in the sparse case; otherwise the
+// getter on Array.prototype would force us into the non-sparse code.
+a.__proto__ = null;
+assertEquals(a, Array.prototype.slice.call(a));
+assertEquals([3], Array.prototype.splice.call(a, 2, 1));
diff --git a/test/mjsunit/regress/regress-425551.js b/test/mjsunit/regress/regress-425551.js
new file mode 100644
index 0000000..eee5e32
--- /dev/null
+++ b/test/mjsunit/regress/regress-425551.js
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var array = new Int8Array(10);
+array[/\u007d\u00fc\u0043/] = 1.499
+assertEquals(1.499, array[/\u007d\u00fc\u0043/]);
diff --git a/test/mjsunit/regress/regress-430201.js b/test/mjsunit/regress/regress-430201.js
new file mode 100644
index 0000000..b53383e
--- /dev/null
+++ b/test/mjsunit/regress/regress-430201.js
@@ -0,0 +1,41 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --expose-gc
+
+var array_1 = [];
+
+%SetFlags("--stress-compaction");
+for (var a = 0; a < 10000; a++) { array_1[a * 100] = 0; }
+
+gc();
+gc();
+
+var array_2 = [];
+for (var i = 0; i < 321361; i++) {
+  array_2[i] = String.fromCharCode(i)[0];
+}
diff --git a/test/mjsunit/regress/regress-435073.js b/test/mjsunit/regress/regress-435073.js
new file mode 100644
index 0000000..dbaa612
--- /dev/null
+++ b/test/mjsunit/regress/regress-435073.js
@@ -0,0 +1,12 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --verify-heap
+
+function test(x) { [x,,]; }
+
+test(0);
+test(0);
+%OptimizeFunctionOnNextCall(test);
+test(0);
diff --git a/test/mjsunit/regress/regress-435477.js b/test/mjsunit/regress/regress-435477.js
new file mode 100644
index 0000000..0a15000
--- /dev/null
+++ b/test/mjsunit/regress/regress-435477.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+var a = new Array(128);
+
+function f(a, base) {
+  a[base] = 2;
+}
+
+f(a, undefined);
+f("r12", undefined);
+f(a, 0);
+%OptimizeFunctionOnNextCall(f);
+f(a, 0);
diff --git a/test/mjsunit/regress/regress-436893.js b/test/mjsunit/regress/regress-436893.js
new file mode 100644
index 0000000..38e7b5f
--- /dev/null
+++ b/test/mjsunit/regress/regress-436893.js
@@ -0,0 +1,37 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+var x = 11;
+function foo() {
+  return 42;
+}
+// Test passing null or undefined as receiver.
+function g() { return foo.apply(null, x()++); }
+%OptimizeFunctionOnNextCall(g);
+assertThrows(g);
diff --git a/test/mjsunit/regress/regress-436896.js b/test/mjsunit/regress/regress-436896.js
new file mode 100644
index 0000000..344a7a3
--- /dev/null
+++ b/test/mjsunit/regress/regress-436896.js
@@ -0,0 +1,17 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function f(x) {
+  const x = 0;
+  return x;
+}
+
+function g(x) {
+  return f(x);
+}
+
+%OptimizeFunctionOnNextCall(g);
+assertThrows(function() { g(42); }, TypeError);
diff --git a/test/mjsunit/regress/regress-437765.js b/test/mjsunit/regress/regress-437765.js
new file mode 100644
index 0000000..88d5388
--- /dev/null
+++ b/test/mjsunit/regress/regress-437765.js
@@ -0,0 +1,22 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --no-fold-constants
+
+function foo(x, y) {
+  return Math.floor(x / y);
+}
+
+function bar(x, y) {
+  return foo(x + 1, y + 1);
+}
+
+function baz() {
+  bar(64, 2);
+}
+
+baz();
+baz();
+%OptimizeFunctionOnNextCall(baz);
+baz();
diff --git a/test/mjsunit/regress/regress-441099.js b/test/mjsunit/regress/regress-441099.js
new file mode 100644
index 0000000..63aecfd
--- /dev/null
+++ b/test/mjsunit/regress/regress-441099.js
@@ -0,0 +1,53 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var Module;
+if (!Module) Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');
+else if (ENVIRONMENT_IS_SHELL) {
+}
+var Runtime = {
+  stackSave: function () {
+  },
+  alignMemory: function (quantum) { var ret = size = Math.ceil()*(quantum ? quantum : 8); return ret; }}
+function allocate() {
+}
+function callRuntimeCallbacks(callbacks) {
+    var callback = callbacks.shift();
+    var func = callback.func;
+    if (typeof func === 'number') {
+    } else {
+      func();
+    }
+}
+var __ATINIT__    = []; // functions called during startup
+function ensureInitRuntime() {
+  callRuntimeCallbacks(__ATINIT__);
+}
+/* global initializers */ __ATINIT__.push({ func: function() { runPostSets() } });
+    function __formatString() {
+            switch (next) {
+            }
+    }
+  var Browser={mainLoop:{queue:[],pause:function () {
+        }},moduleContextCreatedCallbacks:[],workers:[],init:function () {
+      }};
+var asm = (function() {
+  'use asm';
+function setThrew() {
+}
+function runPostSets() {
+}
+function _main() {
+}
+function _free() {
+}
+  return { runPostSets: runPostSets};
+})
+();
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+var i64Math = (function() { // Emscripten wrapper
+  /**
+   */
+})();
+    ensureInitRuntime();
diff --git a/test/mjsunit/regress/regress-447756.js b/test/mjsunit/regress/regress-447756.js
new file mode 100644
index 0000000..1fc7518
--- /dev/null
+++ b/test/mjsunit/regress/regress-447756.js
@@ -0,0 +1,48 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --allow-natives-syntax
+
+function TestConstructor(c) {
+  var a = new c(-0);
+  assertSame(Infinity, 1 / a.length);
+  assertSame(Infinity, 1 / a.byteLength);
+
+  var ab = new ArrayBuffer(-0);
+  assertSame(Infinity, 1 / ab.byteLength);
+
+  var a1 = new c(ab, -0, -0);
+  assertSame(Infinity, 1 / a1.length);
+  assertSame(Infinity, 1 / a1.byteLength);
+  assertSame(Infinity, 1 / a1.byteOffset);
+}
+
+var constructors =
+  [ Uint8Array, Int8Array, Uint8ClampedArray,
+    Uint16Array, Int16Array,
+    Uint32Array, Int32Array,
+    Float32Array, Float64Array ];
+for (var i = 0; i < constructors.length; i++) {
+  TestConstructor(constructors[i]);
+}
+
+
+function TestOptimizedCode() {
+  var a = new Uint8Array(-0);
+  assertSame(Infinity, 1 / a.length);
+  assertSame(Infinity, 1 / a.byteLength);
+
+  var ab = new ArrayBuffer(-0);
+  assertSame(Infinity, 1 / ab.byteLength);
+
+  var a1 = new Uint8Array(ab, -0, -0);
+  assertSame(Infinity, 1 / a1.length);
+  assertSame(Infinity, 1 / a1.byteLength);
+  assertSame(Infinity, 1 / a1.byteOffset);
+}
+
+%OptimizeFunctionOnNextCall(Uint8Array);
+for (var i = 0; i < 1000; i++) {
+  TestOptimizedCode();
+}
diff --git a/test/mjsunit/regress/regress-78270.js b/test/mjsunit/regress/regress-78270.js
index b9ce286..02c4b14 100644
--- a/test/mjsunit/regress/regress-78270.js
+++ b/test/mjsunit/regress/regress-78270.js
@@ -25,6 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Flags: --turbo-deoptimization
+
 for (var i = 0; i < 10000; i++) {
   try {
     var object = { };
diff --git a/test/mjsunit/regress/regress-assignment-in-test-context.js b/test/mjsunit/regress/regress-assignment-in-test-context.js
new file mode 100644
index 0000000..bc40985
--- /dev/null
+++ b/test/mjsunit/regress/regress-assignment-in-test-context.js
@@ -0,0 +1,20 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --always-opt
+// Flags: --turbo-filter=* --turbo-deoptimization
+
+function assertEquals() {}
+
+function f(o) {
+  if (o.setterProperty = 0) {
+    return 1;
+  }
+  return 2;
+}
+
+function deopt() { %DeoptimizeFunction(f); }
+
+assertEquals(2,
+             f(Object.defineProperty({}, "setterProperty", { set: deopt })));
diff --git a/test/mjsunit/regress/regress-crbug-109362.js b/test/mjsunit/regress/regress-crbug-109362.js
new file mode 100644
index 0000000..b156013
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-109362.js
@@ -0,0 +1,26 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+function test(expectation, f) {
+  var stack;
+  try {
+    f();
+  } catch (e) {
+    stack = e.stack;
+  }
+  print(stack);
+  assertTrue(stack.indexOf("at eval (evaltest:" + expectation + ")") > 0);
+}
+
+test("1:5", new Function(
+    '1 + reference_error //@ sourceURL=evaltest'));
+test("2:6", new Function(
+    'x', '\n 1 + reference_error //@ sourceURL=evaltest'));
+test("2:6", new Function(
+    'x\n\n', "z//\n", "y", '\n 1 + reference_error //@ sourceURL=evaltest'));
+test("1:5", new Function(
+    'x/*', "z//\n", "y*/", '1 + reference_error //@ sourceURL=evaltest'));
+test("2:6", eval(
+    '(function () {\n 1 + reference_error //@ sourceURL=evaltest\n})'));
diff --git a/test/mjsunit/regress/regress-crbug-320922.js b/test/mjsunit/regress/regress-crbug-320922.js
index 9ba759a..f199628 100644
--- a/test/mjsunit/regress/regress-crbug-320922.js
+++ b/test/mjsunit/regress/regress-crbug-320922.js
@@ -27,8 +27,10 @@
 
 // Flags: --allow-natives-syntax
 
-var string = "hello world";
-var expected = "Hello " + "world";
+var string = "internalized dummy";
+var expected = "internalized dummy";
+string = "hello world";
+expected = "Hello " + "world";
 function Capitalize() {
   %_OneByteSeqStringSetChar(0, 0x48, string);
 }
diff --git a/test/mjsunit/regress/regress-crbug-323936.js b/test/mjsunit/regress/regress-crbug-323936.js
new file mode 100644
index 0000000..d896ead
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-323936.js
@@ -0,0 +1,46 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+
+Debug = debug.Debug;
+
+var step = 0;
+var exception = null;
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    if (step == 0) {
+      assertEquals("error", exec_state.frame(0).evaluate("e").value());
+      exec_state.frame(0).evaluate("e = 'foo'");
+      exec_state.frame(0).evaluate("x = 'modified'");
+    } else {
+      assertEquals("argument", exec_state.frame(0).evaluate("e").value());
+      exec_state.frame(0).evaluate("e = 'bar'");
+    }
+    step++;
+  } catch (e) {
+    print(e + e.stack);
+    exception = e;
+  }
+}
+
+Debug.setListener(listener);
+
+function f(e, x) {
+  try {
+    throw "error";
+  } catch(e) {
+    debugger;
+    assertEquals("foo", e);
+  }
+  debugger;
+  assertEquals("bar", e);
+  assertEquals("modified", x);
+}
+
+f("argument")
+assertNull(exception);
+assertEquals(2, step);
diff --git a/test/mjsunit/regress/regress-crbug-409614.js b/test/mjsunit/regress/regress-crbug-409614.js
new file mode 100644
index 0000000..7b27404
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-409614.js
@@ -0,0 +1,37 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+
+Debug = debug.Debug;
+var exception = null;
+var error_count = 0;
+
+function f() {
+  return 0;  // Break
+}
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    if (exec_state.frame(0).sourceLineText().indexOf("Break") <0) {
+      error_count++;
+    }
+    exec_state.prepareStep(Debug.StepAction.StepIn, 2);
+    f();  // We should not break in this call of f().
+  } catch (e) {
+    print(e + e.stack);
+    exception = e;
+  }
+}
+
+Debug.setListener(listener);
+
+debugger;  // Break
+f();
+
+Debug.setListener(null);  // Break
+
+assertNull(exception);
+assertEquals(0, error_count);
diff --git a/test/mjsunit/regress/regress-crbug-410033.js b/test/mjsunit/regress/regress-crbug-410033.js
new file mode 100644
index 0000000..63693e6
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-410033.js
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --expose-gc
+
+%GetScript('v8/gc');
diff --git a/test/mjsunit/regress/regress-crbug-412319.js b/test/mjsunit/regress/regress-crbug-412319.js
index 21386e3..c597b0d 100644
--- a/test/mjsunit/regress/regress-crbug-412319.js
+++ b/test/mjsunit/regress/regress-crbug-412319.js
@@ -15,5 +15,5 @@
 %OptimizeFunctionOnNextCall(__f_6);
 __f_6();
 function __f_7(__v_7) {
-  __v_7.push(Infinity);
+  __v_7.pop();
 }
diff --git a/test/mjsunit/regress/regress-crbug-416558.js b/test/mjsunit/regress/regress-crbug-416558.js
new file mode 100644
index 0000000..375ad40
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-416558.js
@@ -0,0 +1,115 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = /x/;
+  store(c);
+  function get_hole() {
+    var b = /x/;
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = new Date();
+  store(c);
+  function get_hole() {
+    var b = new Date();
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = new Number(1);
+  store(c);
+  function get_hole() {
+    var b = new Number(1);
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = new Boolean();
+  store(c);
+  function get_hole() {
+    var b = new Boolean();
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = new Map();
+  store(c);
+  function get_hole() {
+    var b = new Map();
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = new Set();
+  store(c);
+  function get_hole() {
+    var b = new Set();
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = new WeakMap();
+  store(c);
+  function get_hole() {
+    var b = new WeakMap();
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = new WeakSet();
+  store(c);
+  function get_hole() {
+    var b = new WeakSet();
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
diff --git a/test/mjsunit/regress/regress-crbug-424142.js b/test/mjsunit/regress/regress-crbug-424142.js
new file mode 100644
index 0000000..0a370d4
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-424142.js
@@ -0,0 +1,36 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+
+(function outer() {
+  var C = (function C_() {
+    var y = 1;
+    function CC() {
+      this.x = 0;
+    }
+    CC.prototype.f = function CCf() {
+      this.x += y;
+      return this.x;
+    };
+    return CC;
+  })();
+
+  var c = new C(0);
+})
+
+function sentinel() {}
+
+Debug = debug.Debug;
+
+var script = Debug.findScript(sentinel);
+var line = 14;
+var line_start = Debug.findScriptSourcePosition(script, line, 0);
+var line_end = Debug.findScriptSourcePosition(script, line + 1, 0) - 1;
+var actual = Debug.setBreakPointByScriptIdAndPosition(
+                 script.id, line_start).actual_position;
+// Make sure the actual break position is within the line where we set
+// the break point.
+assertTrue(line_start <= actual);
+assertTrue(actual <= line_end);
diff --git a/test/mjsunit/regress/regress-crbug-425519.js b/test/mjsunit/regress/regress-crbug-425519.js
new file mode 100644
index 0000000..d08e7b9
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-425519.js
@@ -0,0 +1,15 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function load(a, i) {
+  return a[i];
+}
+
+load([]);
+load(0);
+load("x", 0);
+%OptimizeFunctionOnNextCall(load);
+load([], 0);
diff --git a/test/mjsunit/regress/regress-crbug-425585.js b/test/mjsunit/regress/regress-crbug-425585.js
new file mode 100644
index 0000000..c27febb
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-425585.js
@@ -0,0 +1,48 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+var correct_result = "This is the correct result.";
+
+function foo(recursion_depth) {
+   if (recursion_depth > 0) return foo(recursion_depth - 1);
+   return new String(correct_result, 1, 2, 3, 4, 5, 6);
+}
+
+// Roll our own non-strict assertEquals replacement.
+function test(i) {
+   var actual = foo(i);
+   if (correct_result != actual) {
+     var msg = "Expected \"" + correct_result + "\", found " + actual;
+     throw new MjsUnitAssertionError(msg);
+   }
+}
+
+test(1);
+test(1);
+test(10);
+test(100);
diff --git a/test/mjsunit/regress/regress-crbug-429159.js b/test/mjsunit/regress/regress-crbug-429159.js
new file mode 100644
index 0000000..69f1856
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-429159.js
@@ -0,0 +1,12 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+try {
+  var src = "return " + Array(12000).join("src,") + "src";
+  var fun = Function(src);
+  assertEquals(src, fun());
+} catch (e) {
+  // Some architectures throw a RangeError, that is fine.
+  assertInstanceof(e, RangeError);
+}
diff --git a/test/mjsunit/regress/regress-crbug-430846.js b/test/mjsunit/regress/regress-crbug-430846.js
new file mode 100644
index 0000000..3047c7f
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-430846.js
@@ -0,0 +1,14 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function foo() { return 1; };
+var o1 = {};
+o1.foo = foo;
+
+var json = '{"foo": {"x": 1}}';
+var o2 = JSON.parse(json);
+var o3 = JSON.parse(json);
+assertTrue(%HaveSameMap(o2, o3));
diff --git a/test/mjsunit/regress/regress-crbug-431602.js b/test/mjsunit/regress/regress-crbug-431602.js
new file mode 100644
index 0000000..2467aaf
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-431602.js
@@ -0,0 +1,23 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --always-opt
+
+var heap_number_producer = {y:1.5};
+heap_number_producer.y = 0;
+var heap_number_zero = heap_number_producer.y;
+var non_constant_eight = {};
+non_constant_eight = 8;
+
+function BreakIt() {
+  return heap_number_zero | (1 | non_constant_eight);
+}
+
+function expose(a, b, c) {
+  return b;
+}
+
+assertEquals(9, expose(8, 9, 10));
+assertEquals(9, expose(8, BreakIt(), 10));
+assertEquals(9, BreakIt());
diff --git a/test/mjsunit/regress/regress-crbug-432493.js b/test/mjsunit/regress/regress-crbug-432493.js
new file mode 100644
index 0000000..87c4f83
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-432493.js
@@ -0,0 +1,57 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+
+function f() {
+  var a = 1;
+  var b = 2;
+  return a + b;
+}
+
+var exception = null;
+var break_count = 0;
+var throw_count = 0;
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      break_count++;
+      // Disable all breakpoints from within the debug event callback.
+      Debug.debuggerFlags().breakPointsActive.setValue(false);
+    } else if (event = Debug.DebugEvent.Exception) {
+      throw_count++;
+      // Enable all breakpoints from within the debug event callback.
+      Debug.debuggerFlags().breakPointsActive.setValue(true);
+    }
+  } catch (e) {
+    exception = e;
+  }
+}
+
+Debug = debug.Debug;
+
+Debug.setListener(listener);
+Debug.setBreakOnException();
+Debug.setBreakPoint(f, 2);
+
+f();
+f();
+
+assertEquals(1, break_count);
+assertEquals(0, throw_count);
+
+// Trigger exception event.
+try { throw 1; } catch (e) {}
+
+f();
+f();
+
+Debug.setListener(null);
+Debug.clearBreakOnException();
+Debug.debuggerFlags().breakPointsActive.setValue(true);
+
+assertEquals(2, break_count);
+assertEquals(1, throw_count);
+assertNull(exception);
diff --git a/test/mjsunit/regress/regress-crbug-433332.js b/test/mjsunit/regress/regress-crbug-433332.js
new file mode 100644
index 0000000..d763243
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-433332.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function f(foo) {
+  var g;
+  true ? (g = 0.1) : g |=  null;
+  if (null != g) {}
+};
+
+f(1.4);
+f(1.4);
+%OptimizeFunctionOnNextCall(f);
+f(1.4);
diff --git a/test/mjsunit/regress/regress-crbug-433766.js b/test/mjsunit/regress/regress-crbug-433766.js
new file mode 100644
index 0000000..fae9483
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-433766.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var filler = "//" + new Array(('@')).join('x');
+
+// Test strict eval in global context.
+eval(
+  "'use strict';" +
+  "var x = 23;" +
+  "var f = function bozo1() {" +
+  "  return x;" +
+  "};" +
+  "f;" +
+  filler
+)();
diff --git a/test/mjsunit/regress/regress-crbug-435825.js b/test/mjsunit/regress/regress-crbug-435825.js
new file mode 100644
index 0000000..e10b812
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-435825.js
@@ -0,0 +1,11 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+Error.prepareStackTrace = function (a,b) { return b; };
+
+try {
+  /(invalid regexp/;
+} catch (e) {
+  e.stack[0].getThis().toString();
+}
diff --git a/test/mjsunit/regress/regress-crbug-436820.js b/test/mjsunit/regress/regress-crbug-436820.js
new file mode 100644
index 0000000..eea386c
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-436820.js
@@ -0,0 +1,13 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function c(p) {
+  return {__proto__: p};
+}
+var p = {};
+var o = c(p);
+p.x = 0.6;
+Object.defineProperty(p, "x", { writable: false });
diff --git a/test/mjsunit/regress/regress-eval-cache.js b/test/mjsunit/regress/regress-eval-cache.js
new file mode 100644
index 0000000..8f8dc18
--- /dev/null
+++ b/test/mjsunit/regress/regress-eval-cache.js
@@ -0,0 +1,19 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function f() {
+  try {
+    throw 1;
+  } catch (e) {
+    var a = 0;
+    var b = 0;
+    var c = 0;
+    var x = 1;
+    var result = eval('eval("x")').toString();
+    assertEquals("1", result);
+  }
+  var x = 2;
+  var result = eval('eval("x")').toString();
+  assertEquals("2", result);
+})();
diff --git a/test/mjsunit/regress/regress-lea-matching.js b/test/mjsunit/regress/regress-lea-matching.js
new file mode 100644
index 0000000..988368a
--- /dev/null
+++ b/test/mjsunit/regress/regress-lea-matching.js
@@ -0,0 +1,14 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function f(a, b, c) {
+  a = a|0;
+  b = b|0;
+  c = c|0;
+  var r = 0;
+  r = a + ((b << 1) + c) | 0;
+  return r|0;
+}
+
+assertEquals(8, f(1, 2, 3));
diff --git a/test/mjsunit/regress/regress-parse-object-literal.js b/test/mjsunit/regress/regress-parse-object-literal.js
index 96d63c2..93725eb 100644
--- a/test/mjsunit/regress/regress-parse-object-literal.js
+++ b/test/mjsunit/regress/regress-parse-object-literal.js
@@ -24,6 +24,8 @@
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Flags: --noharmony-classes --noharmony-object-literals
 
 // Should throw, not crash.
 assertThrows("var o = { get /*space*/ () {} }");
diff --git a/test/mjsunit/regress/regress-shift-enumerable.js b/test/mjsunit/regress/regress-shift-enumerable.js
new file mode 100644
index 0000000..f3ee258
--- /dev/null
+++ b/test/mjsunit/regress/regress-shift-enumerable.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var arr = [1, 2];
+Object.defineProperty(arr, 0xfffe, {
+  value: 3,
+  configurable: true,
+  writable: true,
+  enumerable: false
+});
+arr[0xffff] = 4;
+arr.shift();
+var desc = Object.getOwnPropertyDescriptor(arr, 0xfffe);
+assertEquals(4, desc.value);
+assertFalse(desc.enumerable);
diff --git a/test/mjsunit/regress/regress-splice-large-index.js b/test/mjsunit/regress/regress-splice-large-index.js
new file mode 100644
index 0000000..5da17ee
--- /dev/null
+++ b/test/mjsunit/regress/regress-splice-large-index.js
@@ -0,0 +1,40 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var a = [];
+a[0xfffffffe] = 10;
+assertThrows("a.unshift(1);", RangeError);
+assertEquals(0xffffffff, a.length);
+assertEquals(10, a[0xffffffff]);
+assertEquals(undefined, a[0xfffffffe]);
+
+a = [1,2,3];
+a[0xfffffffe] = 10;
+assertThrows("a.splice(1,1,7,7,7,7,7);", RangeError);
+assertEquals([1,7,7,7,7,7,3], a.slice(0, 7));
+assertEquals(0xffffffff, a.length);
+assertEquals(10, a[0xfffffffe + 5 - 1]);
diff --git a/test/mjsunit/regress/regress-unsigned-mul-add.js b/test/mjsunit/regress/regress-unsigned-mul-add.js
new file mode 100644
index 0000000..0a2fc65
--- /dev/null
+++ b/test/mjsunit/regress/regress-unsigned-mul-add.js
@@ -0,0 +1,10 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function f(a) {
+  var x = a >>> 0;
+  return (x * 1.0 + x * 1.0) << 0;
+}
+
+assertEquals(-2, f(-1));
diff --git a/test/mjsunit/regress/regress-weakening-multiplication.js b/test/mjsunit/regress/regress-weakening-multiplication.js
new file mode 100644
index 0000000..dcf0011
--- /dev/null
+++ b/test/mjsunit/regress/regress-weakening-multiplication.js
@@ -0,0 +1,12 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function f() {
+  for (var j = 1; j < 1; j *= -8) {
+  }
+  for (var i = 1; i < 1; j += 2) {
+    j * -1;
+  }
+}
+f();
diff --git a/test/mjsunit/runtime-gen/loadfromsuper.js b/test/mjsunit/runtime-gen/loadfromsuper.js
deleted file mode 100644
index 25f4ff9..0000000
--- a/test/mjsunit/runtime-gen/loadfromsuper.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
-// Flags: --allow-natives-syntax --harmony --harmony-proxies
-var _home_object = new Object();
-var _receiver = new Object();
-var _name = "name";
-%LoadFromSuper(_home_object, _receiver, _name);
diff --git a/test/mjsunit/serialize-embedded-error.js b/test/mjsunit/serialize-embedded-error.js
new file mode 100644
index 0000000..473c931
--- /dev/null
+++ b/test/mjsunit/serialize-embedded-error.js
@@ -0,0 +1,13 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// --serialize-toplevel --cache=code
+
+var caught = false;
+try {
+  parseInt() = 0;
+} catch(e) {
+  caught = true;
+}
+assertTrue(caught);
diff --git a/test/mjsunit/serialize-ic.js b/test/mjsunit/serialize-ic.js
new file mode 100644
index 0000000..8e5cd2f
--- /dev/null
+++ b/test/mjsunit/serialize-ic.js
@@ -0,0 +1,18 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --cache=code --serialize-toplevel
+
+var foo = [];
+foo[0] = "bar";
+assertEquals(["bar"], foo);
+
+var a;
+var b = 1;
+a = [2];               // STORE_IC
+a[0] = a[0] + 1;       // KEYED_STORE_IC, KEYED_LOAD_IC, BINARY_OP_IC
+assertTrue(a[0] > b);  // CALL_IC, COMPARE_IC
+b = b == null;         // COMPARE_NIL_IC
+b = b || Boolean('');  // TO_BOOLEAN_IC
+assertFalse(b);
diff --git a/test/mjsunit/setters-on-elements.js b/test/mjsunit/setters-on-elements.js
index dd3fabf..001906c 100644
--- a/test/mjsunit/setters-on-elements.js
+++ b/test/mjsunit/setters-on-elements.js
@@ -191,8 +191,8 @@
 
 var values = [3, 3.5, true];
 
-for(var c = 0; c < 3; c++) {
-  for(var s = 0; s < 3; s++) {
+for(var c = 0; c < cf.length; c++) {
+  for(var s = 0; s < values.length; s++) {
     base_setter_test(cf[c], 0, values[s]);
     base_setter_test(cf[c], 1, values[s]);
   }
diff --git a/test/mjsunit/strict-mode.js b/test/mjsunit/strict-mode.js
index 5fb404a..62d003f 100644
--- a/test/mjsunit/strict-mode.js
+++ b/test/mjsunit/strict-mode.js
@@ -25,6 +25,9 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Flags: --turbo-deoptimization --noharmony-scoping
+// Flags: --noharmony-classes --noharmony-object-literals
+
 function CheckStrictMode(code, exception) {
   assertDoesNotThrow(code);
   assertThrows("'use strict';\n" + code, exception);
diff --git a/test/mjsunit/string-slices.js b/test/mjsunit/string-slices.js
index c3f889b..52f1506 100644
--- a/test/mjsunit/string-slices.js
+++ b/test/mjsunit/string-slices.js
@@ -193,7 +193,8 @@
     utf.substring(5,1) + utf.substring(3,7));
 
 // Externalizing strings.
-var a = "123456789" + "qwertyuiopasdfghjklzxcvbnm";
+var a = "internalized dummy";
+a = "123456789" + "qwertyuiopasdfghjklzxcvbnm";
 var b = "23456789qwertyuiopasdfghjklzxcvbn"
 assertEquals(a.slice(1,-1), b);
 
diff --git a/test/mjsunit/test-hidden-string.js b/test/mjsunit/test-hidden-string.js
deleted file mode 100644
index a5d32c8..0000000
--- a/test/mjsunit/test-hidden-string.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Flags: --allow-natives-syntax
-
-var o = {};
-%SetHiddenProperty(o, "test", 1);
-// Create non-internalized ""
-var empty = "a".substring(1, 1);
-assertEquals(undefined, o[empty]);
diff --git a/test/mjsunit/third_party/object-keys.js b/test/mjsunit/third_party/object-keys.js
index d09265c..c800374 100644
--- a/test/mjsunit/third_party/object-keys.js
+++ b/test/mjsunit/third_party/object-keys.js
@@ -31,8 +31,8 @@
 
 // Based on LayoutTests/fast/js/Object-keys.html
 
-assertThrows(function () { Object.keys(2) }, TypeError);
-assertThrows(function () { Object.keys("foo") }, TypeError);
+assertEquals(Object.keys(2), []);
+assertEquals(Object.keys("foo"), ["0", "1", "2"]);
 assertThrows(function () { Object.keys(null) }, TypeError);
 assertThrows(function () { Object.keys(undefined) }, TypeError);
 
diff --git a/test/mjsunit/tools/tickprocessor-test.default b/test/mjsunit/tools/tickprocessor-test.default
index 3e01532..c2fe441 100644
--- a/test/mjsunit/tools/tickprocessor-test.default
+++ b/test/mjsunit/tools/tickprocessor-test.default
@@ -24,6 +24,13 @@
       4   30.8%          Shared libraries
       2   15.4%          Unaccounted
 
+ [C++ entry points]:
+   ticks    cpp   total   name
+      2   40.0%   15.4%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      1   20.0%    7.7%  v8::internal::JSObject::LookupOwnRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1   20.0%    7.7%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1   20.0%    7.7%  exp
+
  [Bottom up (heavy) profile]:
   Note: percentage shows a share of a particular caller in the total
   amount of its parent calls.
diff --git a/test/mjsunit/tools/tickprocessor-test.func-info b/test/mjsunit/tools/tickprocessor-test.func-info
index c93b6ec..1f34cfb 100644
--- a/test/mjsunit/tools/tickprocessor-test.func-info
+++ b/test/mjsunit/tools/tickprocessor-test.func-info
@@ -18,6 +18,9 @@
       0    0.0%    0.0%  GC
       0    0.0%          Shared libraries
 
+ [C++ entry points]:
+   ticks    cpp   total   name
+
  [Bottom up (heavy) profile]:
   Note: percentage shows a share of a particular caller in the total
   amount of its parent calls.
diff --git a/test/mjsunit/tools/tickprocessor-test.gc-state b/test/mjsunit/tools/tickprocessor-test.gc-state
index 6b1a6a3..d96acf5 100644
--- a/test/mjsunit/tools/tickprocessor-test.gc-state
+++ b/test/mjsunit/tools/tickprocessor-test.gc-state
@@ -16,6 +16,9 @@
       0    0.0%    0.0%  GC
       0    0.0%          Shared libraries
 
+ [C++ entry points]:
+   ticks    cpp   total   name
+
  [Bottom up (heavy) profile]:
   Note: percentage shows a share of a particular caller in the total
   amount of its parent calls.
diff --git a/test/mjsunit/tools/tickprocessor-test.ignore-unknown b/test/mjsunit/tools/tickprocessor-test.ignore-unknown
index de70527..263cec5 100644
--- a/test/mjsunit/tools/tickprocessor-test.ignore-unknown
+++ b/test/mjsunit/tools/tickprocessor-test.ignore-unknown
@@ -23,6 +23,13 @@
       0    0.0%    0.0%  GC
       4   36.4%          Shared libraries
 
+ [C++ entry points]:
+   ticks    cpp   total   name
+      2   40.0%   18.2%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      1   20.0%    9.1%  v8::internal::JSObject::LookupOwnRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1   20.0%    9.1%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1   20.0%    9.1%  exp
+
  [Bottom up (heavy) profile]:
   Note: percentage shows a share of a particular caller in the total
   amount of its parent calls.
diff --git a/test/mjsunit/tools/tickprocessor-test.separate-ic b/test/mjsunit/tools/tickprocessor-test.separate-ic
index 119ccbe..aee1d1f 100644
--- a/test/mjsunit/tools/tickprocessor-test.separate-ic
+++ b/test/mjsunit/tools/tickprocessor-test.separate-ic
@@ -26,6 +26,13 @@
       4   30.8%          Shared libraries
       2   15.4%          Unaccounted
 
+ [C++ entry points]:
+   ticks    cpp   total   name
+      2   40.0%   15.4%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      1   20.0%    7.7%  v8::internal::JSObject::LookupOwnRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1   20.0%    7.7%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1   20.0%    7.7%  exp
+
  [Bottom up (heavy) profile]:
   Note: percentage shows a share of a particular caller in the total
   amount of its parent calls.
diff --git a/test/mjsunit/unused-context-in-with.js b/test/mjsunit/unused-context-in-with.js
new file mode 100644
index 0000000..2973ca2
--- /dev/null
+++ b/test/mjsunit/unused-context-in-with.js
@@ -0,0 +1,13 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var x = 1;
+function foo(object) {
+  with(object) {
+    x;
+  }
+  return 100;
+}
+
+assertEquals(100,foo("str"));
diff --git a/test/mjsunit/var.js b/test/mjsunit/var.js
index 5999d70..c3c331e 100644
--- a/test/mjsunit/var.js
+++ b/test/mjsunit/var.js
@@ -35,3 +35,22 @@
 assertTrue(!z && typeof z == 'undefined');
 if (false) { var z; }
 assertTrue(!z && typeof z == 'undefined');
+
+assertThrows("var \u2E2F;", SyntaxError);
+assertThrows("var \\u2E2F;", SyntaxError);
+
+assertDoesNotThrow("var \u2118;");
+assertDoesNotThrow("var \\u2118;");
+assertDoesNotThrow("var \u212E;");
+assertDoesNotThrow("var \\u212E;");
+assertDoesNotThrow("var \u309B;");
+assertDoesNotThrow("var \\u309B;");
+assertDoesNotThrow("var \u309C;");
+assertDoesNotThrow("var \\u309C;");
+
+assertDoesNotThrow("var $\u00B7;");
+assertDoesNotThrow("var $\u0387;");
+assertDoesNotThrow("var $\u1369;");
+assertDoesNotThrow("var $\u1370;");
+assertDoesNotThrow("var $\u1371;");
+assertDoesNotThrow("var $\u19DA;");
diff --git a/test/mozilla/mozilla.status b/test/mozilla/mozilla.status
index e9f58c6..9ba07f7 100644
--- a/test/mozilla/mozilla.status
+++ b/test/mozilla/mozilla.status
@@ -117,6 +117,11 @@
   'js1_5/GC/regress-348532': [SKIP],
 
 
+  # Runs for too long: huge array with getters and setters. As it says
+  # in the test: "This test will probably run out of memory".
+  'js1_5/extensions/regress-345967': [SKIP],
+
+
   ##################### FLAKY TESTS #####################
 
   # These tests time out in debug mode but pass in product mode
@@ -216,7 +221,8 @@
 
   # Test that depends on timer resolution. Fails every now and then
   # if we're unlucky enough to get a context switch at a bad time.
-  'js1_5/extensions/regress-363258': [PASS, FAIL],
+  # TODO(mstarzinger): Switch off TF on windows due to timeouts.
+  'js1_5/extensions/regress-363258': [PASS, FAIL, ['system == windows', NO_VARIANTS]],
 
 
   # Test that assumes specific runtime for a regexp, flaky in debug mode.
@@ -273,21 +279,6 @@
   # RegExp flags.
   'ecma_3/RegExp/15.10.4.1-6': [FAIL_OK],
 
-  # PCRE doesn't allow subpattern nesting deeper than 200, this tests
-  # depth 500.  JSC detects the case, and return null from the match,
-  # and passes this test (the test doesn't check for a correct return
-  # value).
-  'ecma_3/RegExp/regress-119909': [PASS, FAIL_OK],
-
-
-  # Difference in the way capturing subpatterns work.  In JS, when the
-  # 'minimum repeat count' is reached, the empty string must not match.
-  # In this case, we are similar but not identical to JSC.  Hard to
-  # support the JS behavior with PCRE, so maybe emulate JSC?
-  'ecma_3/RegExp/regress-209919': [PASS, FAIL_OK],
-  'js1_5/extensions/regress-459606': [PASS, FAIL_OK],
-
-
   # PCRE's match limit is reached.  SpiderMonkey hangs on the first one,
   # JSC returns true somehow.  Maybe they up the match limit?  There is
   # an open V8 bug 676063 about this.
@@ -310,12 +301,12 @@
   'js1_5/Regress/regress-230216-2': [FAIL_OK],
 
 
-  # Regexp too long for PCRE.
-  'js1_5/Regress/regress-280769': [PASS, FAIL],
-  'js1_5/Regress/regress-280769-1': [PASS, FAIL],
-  'js1_5/Regress/regress-280769-2': [PASS, FAIL],
-  'js1_5/Regress/regress-280769-4': [PASS, FAIL],
-  'js1_5/Regress/regress-280769-5': [PASS, FAIL],
+  # BUG(v8:3767)
+  'js1_5/Regress/regress-280769-2': [PASS, ['arch == arm64', SKIP]],
+
+  # Regexps too big.
+  'js1_5/Regress/regress-280769-1': [SKIP],
+  'js1_5/Regress/regress-280769-5': [SKIP],
 
 
   # We do not support static RegExp.multiline - should we?.
@@ -361,9 +352,9 @@
 
 
   # No support for toSource().
-  'js1_5/Regress/regress-248444': [FAIL_OK],
   'js1_5/Regress/regress-313967-01': [FAIL_OK],
   'js1_5/Regress/regress-313967-02': [FAIL_OK],
+  'js1_5/extensions/regress-459606': [FAIL_OK],
 
   # This fails because we don't have stack space for Function.prototype.apply
   # with very large numbers of arguments.  The test uses 2^24 arguments.
@@ -567,11 +558,6 @@
   'js1_5/Regress/regress-336100': [FAIL_OK],
 
 
-  # Regular expression test failures due to PCRE. We match JSC (ie, perl)
-  # behavior and not the ECMA spec.
-  'ecma_3/RegExp/perlstress-001': [PASS, FAIL_OK],
-  'ecma_3/RegExp/regress-334158': [PASS, FAIL],
-
   # This test fails due to http://code.google.com/p/v8/issues/detail?id=187
   # Failure to clear captures when a lookahead is unwound.
   'ecma_3/RegExp/15.10.2-1': [PASS, FAIL_OK],
@@ -674,7 +660,6 @@
   'js1_5/extensions/regress-311792-01': [FAIL_OK],
   'js1_5/extensions/regress-312278': [FAIL_OK],
   'js1_5/extensions/regress-313630': [FAIL_OK],
-  'js1_5/extensions/regress-313763': [FAIL_OK],
   'js1_5/extensions/regress-313803': [FAIL_OK],
   'js1_5/extensions/regress-314874': [FAIL_OK],
   'js1_5/extensions/regress-322957': [FAIL_OK],
@@ -684,8 +669,6 @@
   'js1_5/extensions/regress-336409-1': [FAIL_OK],
   'js1_5/extensions/regress-336409-2': [FAIL_OK],
   'js1_5/extensions/regress-336410-2': [FAIL_OK],
-  'js1_5/extensions/regress-341956-01': [FAIL_OK],
-  'js1_5/extensions/regress-345967': [FAIL_OK],
   'js1_5/extensions/regress-346494-01': [FAIL_OK],
   'js1_5/extensions/regress-346494': [FAIL_OK],
   'js1_5/extensions/regress-347306-02': [FAIL_OK],
@@ -863,11 +846,10 @@
 
 
 ['arch ==  arm64', {
-  # BUG(v8:3152): Runs out of stack in debug mode.
-  'js1_5/extensions/regress-355497': [FAIL_OK, ['mode == debug', SKIP]],
-
   # BUG(v8:3503): Times out in debug mode.
   'js1_5/Regress/regress-280769-2': [PASS, FAIL, ['mode == debug', SKIP]],
+  # BUG(v8:3716): Flaky failure.
+  'ecma/Date/15.9.5.26-1': [PASS, FAIL],
 }],  # 'arch ==  arm64'
 
 
@@ -890,6 +872,10 @@
   'js1_5/GC/regress-203278-2': [PASS, TIMEOUT, NO_VARIANTS],
 }],  # 'arch == mipsel or arch == mips64el'
 
+['arch == mips64el and simulator_run == True', {
+  'js1_5/extensions/regress-355497': [FAIL_OK, 'Flags: --sim-stack-size=512'],
+}],
+
 ['arch == mips', {
 
   # BUG(3251229): Times out when running new crankshaft test script.
@@ -928,5 +914,8 @@
   'js1_5/extensions/regress-330569': [SKIP],
   'js1_5/extensions/regress-351448': [SKIP],
   'js1_5/extensions/regress-336410-1': [SKIP],
+
+  #BUG(3152): Avoid C stack overflow.
+  'js1_5/extensions/regress-355497': [FAIL_OK, 'Flags: --sim-stack-size=512'],
 }],  # 'arch == arm64 and simulator_run == True'
 ]
diff --git a/test/perf-test/Collections/Collections.json b/test/perf-test/Collections/Collections.json
deleted file mode 100644
index bf735c0..0000000
--- a/test/perf-test/Collections/Collections.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "path": ["."],
-  "main": "run.js",
-  "flags": ["--harmony-collections"],
-  "run_count": 5,
-  "units": "score",
-  "results_regexp": "^%s\\-Collections\\(Score\\): (.+)$",
-  "total": true,
-  "tests": [
-    {"name": "Map"},
-    {"name": "Set"},
-    {"name": "WeakMap"},
-    {"name": "WeakSet"}
-  ]
-}
diff --git a/test/perf-test/Collections/map.js b/test/perf-test/Collections/map.js
deleted file mode 100644
index b310a71..0000000
--- a/test/perf-test/Collections/map.js
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-
-var MapBenchmark = new BenchmarkSuite('Map', [1000], [
-  new Benchmark('Set', false, false, 0, MapSet),
-  new Benchmark('Has', false, false, 0, MapHas, MapSetup, MapTearDown),
-  new Benchmark('Get', false, false, 0, MapGet, MapSetup, MapTearDown),
-  new Benchmark('Delete', false, false, 0, MapDelete, MapSetup, MapTearDown),
-  new Benchmark('ForEach', false, false, 0, MapForEach, MapSetup, MapTearDown),
-]);
-
-
-var map;
-var N = 10;
-
-
-function MapSetup() {
-  map = new Map;
-  for (var i = 0; i < N; i++) {
-    map.set(i, i);
-  }
-}
-
-
-function MapTearDown() {
-  map = null;
-}
-
-
-function MapSet() {
-  MapSetup();
-  MapTearDown();
-}
-
-
-function MapHas() {
-  for (var i = 0; i < N; i++) {
-    if (!map.has(i)) {
-      throw new Error();
-    }
-  }
-  for (var i = N; i < 2 * N; i++) {
-    if (map.has(i)) {
-      throw new Error();
-    }
-  }
-}
-
-
-function MapGet() {
-  for (var i = 0; i < N; i++) {
-    if (map.get(i) !== i) {
-      throw new Error();
-    }
-  }
-  for (var i = N; i < 2 * N; i++) {
-    if (map.get(i) !== undefined) {
-      throw new Error();
-    }
-  }
-}
-
-
-function MapDelete() {
-  // This is run more than once per setup so we will end up deleting items
-  // more than once. Therefore, we do not the return value of delete.
-  for (var i = 0; i < N; i++) {
-    map.delete(i);
-  }
-}
-
-
-function MapForEach() {
-  map.forEach(function(v, k) {
-    if (v !== k) {
-      throw new Error();
-    }
-  });
-}
diff --git a/test/perf-test/Collections/run.js b/test/perf-test/Collections/run.js
deleted file mode 100644
index cfd1aef..0000000
--- a/test/perf-test/Collections/run.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-
-load('base.js');
-load('map.js');
-load('set.js');
-load('weakmap.js');
-load('weakset.js');
-
-
-var success = true;
-
-function PrintResult(name, result) {
-  print(name + '-Collections(Score): ' + result);
-}
-
-
-function PrintError(name, error) {
-  PrintResult(name, error);
-  success = false;
-}
-
-
-BenchmarkSuite.config.doWarmup = undefined;
-BenchmarkSuite.config.doDeterministic = undefined;
-
-BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
-                           NotifyError: PrintError });
diff --git a/test/perf-test/Collections/set.js b/test/perf-test/Collections/set.js
deleted file mode 100644
index e6455e1..0000000
--- a/test/perf-test/Collections/set.js
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-
-var SetBenchmark = new BenchmarkSuite('Set', [1000], [
-  new Benchmark('Add', false, false, 0, SetAdd),
-  new Benchmark('Has', false, false, 0, SetHas, SetSetup, SetTearDown),
-  new Benchmark('Delete', false, false, 0, SetDelete, SetSetup, SetTearDown),
-  new Benchmark('ForEach', false, false, 0, SetForEach, SetSetup, SetTearDown),
-]);
-
-
-var set;
-var N = 10;
-
-
-function SetSetup() {
-  set = new Set;
-  for (var i = 0; i < N; i++) {
-    set.add(i);
-  }
-}
-
-
-function SetTearDown() {
-  map = null;
-}
-
-
-function SetAdd() {
-  SetSetup();
-  SetTearDown();
-}
-
-
-function SetHas() {
-  for (var i = 0; i < N; i++) {
-    if (!set.has(i)) {
-      throw new Error();
-    }
-  }
-  for (var i = N; i < 2 * N; i++) {
-    if (set.has(i)) {
-      throw new Error();
-    }
-  }
-}
-
-
-function SetDelete() {
-  // This is run more than once per setup so we will end up deleting items
-  // more than once. Therefore, we do not the return value of delete.
-  for (var i = 0; i < N; i++) {
-    set.delete(i);
-  }
-}
-
-
-function SetForEach() {
-  set.forEach(function(v, k) {
-    if (v !== k) {
-      throw new Error();
-    }
-  });
-}
diff --git a/test/perf-test/Collections/weakmap.js b/test/perf-test/Collections/weakmap.js
deleted file mode 100644
index 8736dfd..0000000
--- a/test/perf-test/Collections/weakmap.js
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-
-var MapBenchmark = new BenchmarkSuite('WeakMap', [1000], [
-  new Benchmark('Set', false, false, 0, WeakMapSet),
-  new Benchmark('Has', false, false, 0, WeakMapHas, WeakMapSetup,
-      WeakMapTearDown),
-  new Benchmark('Get', false, false, 0, WeakMapGet, WeakMapSetup,
-      WeakMapTearDown),
-  new Benchmark('Delete', false, false, 0, WeakMapDelete, WeakMapSetup,
-      WeakMapTearDown),
-]);
-
-
-var wm;
-var N = 10;
-var keys = [];
-
-
-for (var i = 0; i < N * 2; i++) {
-  keys[i] = {};
-}
-
-
-function WeakMapSetup() {
-  wm = new WeakMap;
-  for (var i = 0; i < N; i++) {
-    wm.set(keys[i], i);
-  }
-}
-
-
-function WeakMapTearDown() {
-  wm = null;
-}
-
-
-function WeakMapSet() {
-  WeakMapSetup();
-  WeakMapTearDown();
-}
-
-
-function WeakMapHas() {
-  for (var i = 0; i < N; i++) {
-    if (!wm.has(keys[i])) {
-      throw new Error();
-    }
-  }
-  for (var i = N; i < 2 * N; i++) {
-    if (wm.has(keys[i])) {
-      throw new Error();
-    }
-  }
-}
-
-
-function WeakMapGet() {
-  for (var i = 0; i < N; i++) {
-    if (wm.get(keys[i]) !== i) {
-      throw new Error();
-    }
-  }
-  for (var i = N; i < 2 * N; i++) {
-    if (wm.get(keys[i]) !== undefined) {
-      throw new Error();
-    }
-  }
-}
-
-
-function WeakMapDelete() {
-  // This is run more than once per setup so we will end up deleting items
-  // more than once. Therefore, we do not the return value of delete.
-  for (var i = 0; i < N; i++) {
-    wm.delete(keys[i]);
-  }
-}
diff --git a/test/perf-test/Collections/weakset.js b/test/perf-test/Collections/weakset.js
deleted file mode 100644
index a7d0f3d..0000000
--- a/test/perf-test/Collections/weakset.js
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-
-var SetBenchmark = new BenchmarkSuite('WeakSet', [1000], [
-  new Benchmark('Add', false, false, 0, WeakSetAdd),
-  new Benchmark('Has', false, false, 0, WeakSetHas, WeakSetSetup,
-      WeakSetTearDown),
-  new Benchmark('Delete', false, false, 0, WeakSetDelete, WeakSetSetup,
-      WeakSetTearDown),
-]);
-
-
-var ws;
-var N = 10;
-var keys = [];
-
-
-for (var i = 0; i < N * 2; i++) {
-  keys[i] = {};
-}
-
-
-function WeakSetSetup() {
-  ws = new WeakSet;
-  for (var i = 0; i < N; i++) {
-    ws.add(keys[i]);
-  }
-}
-
-
-function WeakSetTearDown() {
-  ws = null;
-}
-
-
-function WeakSetAdd() {
-  WeakSetSetup();
-  WeakSetTearDown();
-}
-
-
-function WeakSetHas() {
-  for (var i = 0; i < N; i++) {
-    if (!ws.has(keys[i])) {
-      throw new Error();
-    }
-  }
-  for (var i = N; i < 2 * N; i++) {
-    if (ws.has(keys[i])) {
-      throw new Error();
-    }
-  }
-}
-
-
-function WeakSetDelete() {
-  // This is run more than once per setup so we will end up deleting items
-  // more than once. Therefore, we do not the return value of delete.
-  for (var i = 0; i < N; i++) {
-    ws.delete(keys[i]);
-  }
-}
diff --git a/test/preparser/strict-const.js b/test/preparser/strict-const.js
index 2b9230c..97b9081 100644
--- a/test/preparser/strict-const.js
+++ b/test/preparser/strict-const.js
@@ -24,6 +24,8 @@
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Flags: --noharmony-scoping
 
 "use strict";
 const x = 42;
diff --git a/test/preparser/strict-function-statement.pyt b/test/preparser/strict-function-statement.pyt
index 08c4288..cc3d7bb 100644
--- a/test/preparser/strict-function-statement.pyt
+++ b/test/preparser/strict-function-statement.pyt
@@ -29,71 +29,81 @@
 
 # A template that performs the same strict-mode test in different
 # scopes (global scope, function scope, and nested function scope).
-def StrictTest(name, source):
-  Test(name, '"use strict";\n' + source, "strict_function")
+def StrictTest(name, source, legacy):
+  if legacy:
+    extra_flags = [
+      "--noharmony-scoping",
+      "--noharmony-classes",
+      "--noharmony-object-literals"]
+  else:
+    extra_flags = []
+  Test(name, '"use strict";\n' + source, "strict_function",
+       extra_flags)
   Test(name + '-infunc',
        'function foo() {\n "use strict";\n' + source +'\n}\n',
-       "strict_function")
+       "strict_function", 
+       extra_flags)
   Test(name + '-infunc2',
        'function foo() {\n "use strict";\n  function bar() {\n' +
        source +'\n }\n}\n',
-       "strict_function")
+       "strict_function",
+       extra_flags)
 
 # Not testing with-scope, since with is not allowed in strict mode at all.
 
 StrictTest("block", """
   { function foo() { } }
-""")
+""", True)
 
 StrictTest("try-w-catch", """
   try { function foo() { } } catch (e) { }
-""")
+""", True)
 
 StrictTest("try-w-finally", """
   try { function foo() { } } finally { }
-""")
+""", True)
 
 StrictTest("catch", """
   try { } catch (e) { function foo() { } }
-""")
+""", True)
 
 StrictTest("finally", """
   try { } finally { function foo() { } }
-""")
+""", True)
 
 StrictTest("for", """
   for (;;) { function foo() { } }
-""")
+""", True)
 
 StrictTest("while", """
   while (true) { function foo() { } }
-""")
+""", True)
 
 StrictTest("do", """
   do { function foo() { } } while (true);
-""")
+""", True)
 
 StrictTest("then", """
   if (true) { function foo() { } }
-""")
+""", True)
 
 
 StrictTest("then-w-else", """
   if (true) { function foo() { } } else { }
-""")
+""", True)
 
 
 StrictTest("else", """
   if (true) { } else { function foo() { } }
-""")
+""", True)
 
 StrictTest("switch-case", """
   switch (true) { case true: function foo() { } }
-""")
+""", False)
 
 StrictTest("labeled", """
   label: function foo() { }
-""")
+""", False)
 
 
 
diff --git a/test/preparser/testcfg.py b/test/preparser/testcfg.py
index 850c0a4..ddd311c 100644
--- a/test/preparser/testcfg.py
+++ b/test/preparser/testcfg.py
@@ -34,6 +34,10 @@
 from testrunner.objects import testcase
 
 
+FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
+INVALID_FLAGS = ["--enable-slow-asserts"]
+
+
 class PreparserTestSuite(testsuite.TestSuite):
   def __init__(self, name, root):
     super(PreparserTestSuite, self).__init__(name, root)
@@ -59,12 +63,13 @@
 
   def _ParsePythonTestTemplates(self, result, filename):
     pathname = os.path.join(self.root, filename + ".pyt")
-    def Test(name, source, expectation):
+    def Test(name, source, expectation, extra_flags=[]):
       source = source.replace("\n", " ")
       testname = os.path.join(filename, name)
       flags = ["-e", source]
       if expectation:
         flags += ["--throws"]
+      flags += extra_flags
       test = testcase.TestCase(self, testname, flags=flags)
       result.append(test)
     def Template(name, source):
@@ -104,6 +109,15 @@
     first = testcase.flags[0]
     if first != "-e":
       testcase.flags[0] = os.path.join(self.root, first)
+      source = self.GetSourceForTest(testcase)
+      result = []
+      flags_match = re.findall(FLAGS_PATTERN, source)
+      for match in flags_match:
+        result += match.strip().split()
+      result += context.mode_flags
+      result = [x for x in result if x not in INVALID_FLAGS]
+      result.append(os.path.join(self.root, testcase.path + ".js"))
+      return testcase.flags + result
     return testcase.flags
 
   def GetSourceForTest(self, testcase):
diff --git a/test/test262-es6/README b/test/test262-es6/README
index d0b3b42..86fa0dc 100644
--- a/test/test262-es6/README
+++ b/test/test262-es6/README
@@ -4,13 +4,13 @@
 
   https://github.com/tc39/test262
 
-at hash 9bd6686 (2014/08/25 revision) as 'data' in this directory.  Using later
+at hash 61113db (2014/10/23 revision) as 'data' in this directory.  Using later
 version may be possible but the tests are only known to pass (and indeed run)
 with that revision.
 
   git clone https://github.com/tc39/test262 data
   cd data
-  git checkout 9bd6686
+  git checkout 61113db
 
 If you do update to a newer revision you may have to change the test
 harness adapter code since it uses internal functionality from the
diff --git a/test/test262-es6/test262-es6.status b/test/test262-es6/test262-es6.status
index c4c94f3..8662159 100644
--- a/test/test262-es6/test262-es6.status
+++ b/test/test262-es6/test262-es6.status
@@ -29,12 +29,13 @@
 [ALWAYS, {
   ############################### BUGS ###################################
 
-  '15.5.4.9_CE': [['no_i18n', SKIP]],
-
   # BUG(v8:3455)
   '11.2.3_b': [FAIL],
   '12.2.3_b': [FAIL],
 
+  # Unicode canonicalization is not available with i18n turned off.
+  '15.5.4.9_CE': [['no_i18n', SKIP]],
+
   ###################### NEEDS INVESTIGATION #######################
 
   # Possibly same cause as S8.5_A2.1, below: floating-point tests.
@@ -49,6 +50,25 @@
 
   ###################### MISSING ES6 FEATURES #######################
 
+  # Array.fill (currently requires --harmony-arrays)
+  'S22.1.3.6_T1': [FAIL],
+
+  # Array.find (currently requires --harmony-arrays)
+  'S22.1.2.3_T1': [FAIL],
+  'S22.1.2.3_T2': [FAIL],
+  'Array.prototype.find_empty-array-undefined': [FAIL],
+  'Array.prototype.find_length-property': [FAIL],
+  'Array.prototype.find_modify-after-start': [FAIL],
+  'Array.prototype.find_non-returning-predicate': [FAIL],
+  'Array.prototype.find_predicate-arguments': [FAIL],
+  'Array.prototype.find_push-after-start': [FAIL],
+  'Array.prototype.find_remove-after-start': [FAIL],
+  'Array.prototype.find_return-found-value': [FAIL],
+  'Array.prototype.find_skip-empty': [FAIL],
+  'Array.prototype.find_this-defined': [FAIL],
+  'Array.prototype.find_this-is-object': [FAIL],
+  'Array.prototype.find_this-undefined': [FAIL],
+
   # Array.from
   'S22.1.2.1_T1': [FAIL],
   'S22.1.2.1_T2': [FAIL],
@@ -70,6 +90,11 @@
   # '11.1.5_4-4-d-3': [FAIL],
   # '11.1.5_4-4-d-4': [FAIL],
 
+  # ES6 does ToObject for Object.prototype.getOwnPropertyNames
+  '15.2.3.4-1': [FAIL],
+  '15.2.3.4-1-4': [FAIL],
+  '15.2.3.4-1-5': [FAIL],
+
   # ES6 allows block-local functions.
   'Sbp_A1_T1': [FAIL],
   'Sbp_A2_T1': [FAIL],
@@ -137,6 +162,20 @@
   # Test262 Bug: https://bugs.ecmascript.org/show_bug.cgi?id=596
   'bug_596_1': [PASS, FAIL_OK],
 
+  # Tests do not return boolean.
+  '15.2.3.14-1-1': [PASS, FAIL_OK],
+  '15.2.3.14-1-2': [PASS, FAIL_OK],
+  '15.2.3.14-1-3': [PASS, FAIL_OK],
+
+  # String.prototype.contains renamed to 'S.p.includes'
+  'String.prototype.contains_FailBadLocation' : [FAIL_OK],
+  'String.prototype.contains_FailLocation' : [FAIL_OK],
+  'String.prototype.contains_FailMissingLetter' : [FAIL_OK],
+  'String.prototype.contains_lengthProp' : [FAIL_OK],
+  'String.prototype.contains_Success' : [FAIL_OK],
+  'String.prototype.contains_SuccessNoLocation' : [FAIL_OK],
+
+
   ############################ SKIPPED TESTS #############################
 
   # These tests take a looong time to run in debug mode.
diff --git a/test/test262-es6/testcfg.py b/test/test262-es6/testcfg.py
index 59eda32..0a89410 100644
--- a/test/test262-es6/testcfg.py
+++ b/test/test262-es6/testcfg.py
@@ -37,8 +37,8 @@
 from testrunner.local import utils
 from testrunner.objects import testcase
 
-TEST_262_ARCHIVE_REVISION = "9bd6686"  # This is the 2014-08-25 revision.
-TEST_262_ARCHIVE_MD5 = "0f5928b391864890d5a397f8cdc82705"
+TEST_262_ARCHIVE_REVISION = "61113db"  # This is the 2014-10-23 revision.
+TEST_262_ARCHIVE_MD5 = "261e69b4a97a4bfc18225cf3938daf50"
 TEST_262_URL = "https://github.com/tc39/test262/tarball/%s"
 TEST_262_HARNESS_FILES = ["sta.js"]
 
@@ -147,9 +147,11 @@
       with open(archive_name, "rb") as f:
         for chunk in iter(lambda: f.read(8192), ""):
           md5.update(chunk)
+      print "MD5 hash is %s" % md5.hexdigest()
       if md5.hexdigest() != TEST_262_ARCHIVE_MD5:
         os.remove(archive_name)
-        raise Exception("Hash mismatch of test data file")
+        print "MD5 expected %s" % TEST_262_ARCHIVE_MD5
+        raise Exception("MD5 hash mismatch of test data file")
       archive = tarfile.open(archive_name, "r:gz")
       if sys.platform in ("win32", "cygwin"):
         # Magic incantation to allow longer path names on Windows.
diff --git a/test/test262/test262.status b/test/test262/test262.status
index 8666313..d32f8f3 100644
--- a/test/test262/test262.status
+++ b/test/test262/test262.status
@@ -35,6 +35,22 @@
   '11.2.3_b': [FAIL],
   '12.2.3_b': [FAIL],
 
+  ############################### ES6 ###################################
+  # ES6 allows block-local functions.
+  'Sbp_A1_T1': [PASS, FAIL_OK],
+  'Sbp_A2_T1': [PASS, FAIL_OK],
+  'Sbp_A2_T2': [PASS, FAIL_OK],
+  'Sbp_A3_T1': [PASS, FAIL_OK],
+  'Sbp_A3_T2': [PASS, FAIL_OK],
+  'Sbp_A4_T1': [PASS, FAIL_OK],
+  'Sbp_A4_T2': [PASS, FAIL_OK],
+  'Sbp_A5_T1': [PASS], # Test is broken (strict reference to unbound variable)
+  'Sbp_A5_T2': [PASS, FAIL_OK],
+
+  # Passes in ES6 since {__arr} syntax is parsed as object literal.
+  'S12.1_A4_T2': [PASS, FAIL_OK],
+  'S12.6.4_A15': [PASS, FAIL_OK],
+
   ######################## NEEDS INVESTIGATION ###########################
 
   # These test failures are specific to the intl402 suite and need investigation
@@ -87,6 +103,17 @@
   'S15.9.3.1_A5_T5': [PASS, FAIL_OK],
   'S15.9.3.1_A5_T6': [PASS, FAIL_OK],
 
+  # ObjectKeys() no longer throws TypeError when passed a primitive value which
+  # is not null or undefined (per ES6).
+  '15.2.3.14-1-1': [FAIL_OK],
+  '15.2.3.14-1-2': [FAIL_OK],
+  '15.2.3.14-1-3': [FAIL_OK],
+
+  # Object.getOwnPropertyNames(O) no longer throws when passed a primitive value.
+  '15.2.3.4-1-4': [FAIL_OK],
+  '15.2.3.4-1-5': [FAIL_OK],
+  '15.2.3.4-1': [FAIL_OK],
+
   ############################ SKIPPED TESTS #############################
 
   # These tests take a looong time to run in debug mode.
diff --git a/test/unittests/DEPS b/test/unittests/DEPS
new file mode 100644
index 0000000..4df37f8
--- /dev/null
+++ b/test/unittests/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+src",
+  "+testing"
+]
diff --git a/test/unittests/base/bits-unittest.cc b/test/unittests/base/bits-unittest.cc
new file mode 100644
index 0000000..9caba84
--- /dev/null
+++ b/test/unittests/base/bits-unittest.cc
@@ -0,0 +1,281 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "src/base/bits.h"
+#include "src/base/macros.h"
+#include "testing/gtest-support.h"
+
+#ifdef DEBUG
+#define DISABLE_IN_RELEASE(Name) Name
+#else
+#define DISABLE_IN_RELEASE(Name) DISABLED_##Name
+#endif
+
+namespace v8 {
+namespace base {
+namespace bits {
+
+TEST(Bits, CountPopulation32) {
+  EXPECT_EQ(0u, CountPopulation32(0));
+  EXPECT_EQ(1u, CountPopulation32(1));
+  EXPECT_EQ(8u, CountPopulation32(0x11111111));
+  EXPECT_EQ(16u, CountPopulation32(0xf0f0f0f0));
+  EXPECT_EQ(24u, CountPopulation32(0xfff0f0ff));
+  EXPECT_EQ(32u, CountPopulation32(0xffffffff));
+}
+
+
+TEST(Bits, CountPopulation64) {
+  EXPECT_EQ(0u, CountPopulation64(0));
+  EXPECT_EQ(1u, CountPopulation64(1));
+  EXPECT_EQ(2u, CountPopulation64(0x8000000000000001));
+  EXPECT_EQ(8u, CountPopulation64(0x11111111));
+  EXPECT_EQ(16u, CountPopulation64(0xf0f0f0f0));
+  EXPECT_EQ(24u, CountPopulation64(0xfff0f0ff));
+  EXPECT_EQ(32u, CountPopulation64(0xffffffff));
+  EXPECT_EQ(16u, CountPopulation64(0x1111111111111111));
+  EXPECT_EQ(32u, CountPopulation64(0xf0f0f0f0f0f0f0f0));
+  EXPECT_EQ(48u, CountPopulation64(0xfff0f0fffff0f0ff));
+  EXPECT_EQ(64u, CountPopulation64(0xffffffffffffffff));
+}
+
+
+TEST(Bits, CountLeadingZeros32) {
+  EXPECT_EQ(32u, CountLeadingZeros32(0));
+  EXPECT_EQ(31u, CountLeadingZeros32(1));
+  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
+    EXPECT_EQ(31u - shift, CountLeadingZeros32(1u << shift));
+  }
+  EXPECT_EQ(4u, CountLeadingZeros32(0x0f0f0f0f));
+}
+
+
+TEST(Bits, CountLeadingZeros64) {
+  EXPECT_EQ(64u, CountLeadingZeros64(0));
+  EXPECT_EQ(63u, CountLeadingZeros64(1));
+  TRACED_FORRANGE(uint32_t, shift, 0, 63) {
+    EXPECT_EQ(63u - shift, CountLeadingZeros64(V8_UINT64_C(1) << shift));
+  }
+  EXPECT_EQ(36u, CountLeadingZeros64(0x0f0f0f0f));
+  EXPECT_EQ(4u, CountLeadingZeros64(0x0f0f0f0f00000000));
+}
+
+
+TEST(Bits, CountTrailingZeros32) {
+  EXPECT_EQ(32u, CountTrailingZeros32(0));
+  EXPECT_EQ(31u, CountTrailingZeros32(0x80000000));
+  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
+    EXPECT_EQ(shift, CountTrailingZeros32(1u << shift));
+  }
+  EXPECT_EQ(4u, CountTrailingZeros32(0xf0f0f0f0));
+}
+
+
+TEST(Bits, CountTrailingZeros64) {
+  EXPECT_EQ(64u, CountTrailingZeros64(0));
+  EXPECT_EQ(63u, CountTrailingZeros64(0x8000000000000000));
+  TRACED_FORRANGE(uint32_t, shift, 0, 63) {
+    EXPECT_EQ(shift, CountTrailingZeros64(V8_UINT64_C(1) << shift));
+  }
+  EXPECT_EQ(4u, CountTrailingZeros64(0xf0f0f0f0));
+  EXPECT_EQ(36u, CountTrailingZeros64(0xf0f0f0f000000000));
+}
+
+
+TEST(Bits, IsPowerOfTwo32) {
+  EXPECT_FALSE(IsPowerOfTwo32(0U));
+  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
+    EXPECT_TRUE(IsPowerOfTwo32(1U << shift));
+    EXPECT_FALSE(IsPowerOfTwo32((1U << shift) + 5U));
+    EXPECT_FALSE(IsPowerOfTwo32(~(1U << shift)));
+  }
+  TRACED_FORRANGE(uint32_t, shift, 2, 31) {
+    EXPECT_FALSE(IsPowerOfTwo32((1U << shift) - 1U));
+  }
+  EXPECT_FALSE(IsPowerOfTwo32(0xffffffff));
+}
+
+
+TEST(Bits, IsPowerOfTwo64) {
+  EXPECT_FALSE(IsPowerOfTwo64(0U));
+  TRACED_FORRANGE(uint32_t, shift, 0, 63) {
+    EXPECT_TRUE(IsPowerOfTwo64(V8_UINT64_C(1) << shift));
+    EXPECT_FALSE(IsPowerOfTwo64((V8_UINT64_C(1) << shift) + 5U));
+    EXPECT_FALSE(IsPowerOfTwo64(~(V8_UINT64_C(1) << shift)));
+  }
+  TRACED_FORRANGE(uint32_t, shift, 2, 63) {
+    EXPECT_FALSE(IsPowerOfTwo64((V8_UINT64_C(1) << shift) - 1U));
+  }
+  EXPECT_FALSE(IsPowerOfTwo64(V8_UINT64_C(0xffffffffffffffff)));
+}
+
+
+TEST(Bits, RoundUpToPowerOfTwo32) {
+  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
+    EXPECT_EQ(1u << shift, RoundUpToPowerOfTwo32(1u << shift));
+  }
+  EXPECT_EQ(0u, RoundUpToPowerOfTwo32(0));
+  EXPECT_EQ(4u, RoundUpToPowerOfTwo32(3));
+  EXPECT_EQ(0x80000000u, RoundUpToPowerOfTwo32(0x7fffffffu));
+}
+
+
+TEST(BitsDeathTest, DISABLE_IN_RELEASE(RoundUpToPowerOfTwo32)) {
+  ASSERT_DEATH_IF_SUPPORTED({ RoundUpToPowerOfTwo32(0x80000001u); },
+                            "0x80000000");
+}
+
+
+TEST(Bits, RoundDownToPowerOfTwo32) {
+  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
+    EXPECT_EQ(1u << shift, RoundDownToPowerOfTwo32(1u << shift));
+  }
+  EXPECT_EQ(0u, RoundDownToPowerOfTwo32(0));
+  EXPECT_EQ(4u, RoundDownToPowerOfTwo32(5));
+  EXPECT_EQ(0x80000000u, RoundDownToPowerOfTwo32(0x80000001u));
+}
+
+
+TEST(Bits, RotateRight32) {
+  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
+    EXPECT_EQ(0u, RotateRight32(0u, shift));
+  }
+  EXPECT_EQ(1u, RotateRight32(1, 0));
+  EXPECT_EQ(1u, RotateRight32(2, 1));
+  EXPECT_EQ(0x80000000u, RotateRight32(1, 1));
+}
+
+
+TEST(Bits, RotateRight64) {
+  TRACED_FORRANGE(uint64_t, shift, 0, 63) {
+    EXPECT_EQ(0u, RotateRight64(0u, shift));
+  }
+  EXPECT_EQ(1u, RotateRight64(1, 0));
+  EXPECT_EQ(1u, RotateRight64(2, 1));
+  EXPECT_EQ(V8_UINT64_C(0x8000000000000000), RotateRight64(1, 1));
+}
+
+
+TEST(Bits, SignedAddOverflow32) {
+  int32_t val = 0;
+  EXPECT_FALSE(SignedAddOverflow32(0, 0, &val));
+  EXPECT_EQ(0, val);
+  EXPECT_TRUE(
+      SignedAddOverflow32(std::numeric_limits<int32_t>::max(), 1, &val));
+  EXPECT_EQ(std::numeric_limits<int32_t>::min(), val);
+  EXPECT_TRUE(
+      SignedAddOverflow32(std::numeric_limits<int32_t>::min(), -1, &val));
+  EXPECT_EQ(std::numeric_limits<int32_t>::max(), val);
+  EXPECT_TRUE(SignedAddOverflow32(std::numeric_limits<int32_t>::max(),
+                                  std::numeric_limits<int32_t>::max(), &val));
+  EXPECT_EQ(-2, val);
+  TRACED_FORRANGE(int32_t, i, 1, 50) {
+    TRACED_FORRANGE(int32_t, j, 1, i) {
+      EXPECT_FALSE(SignedAddOverflow32(i, j, &val));
+      EXPECT_EQ(i + j, val);
+    }
+  }
+}
+
+
+TEST(Bits, SignedSubOverflow32) {
+  int32_t val = 0;
+  EXPECT_FALSE(SignedSubOverflow32(0, 0, &val));
+  EXPECT_EQ(0, val);
+  EXPECT_TRUE(
+      SignedSubOverflow32(std::numeric_limits<int32_t>::min(), 1, &val));
+  EXPECT_EQ(std::numeric_limits<int32_t>::max(), val);
+  EXPECT_TRUE(
+      SignedSubOverflow32(std::numeric_limits<int32_t>::max(), -1, &val));
+  EXPECT_EQ(std::numeric_limits<int32_t>::min(), val);
+  TRACED_FORRANGE(int32_t, i, 1, 50) {
+    TRACED_FORRANGE(int32_t, j, 1, i) {
+      EXPECT_FALSE(SignedSubOverflow32(i, j, &val));
+      EXPECT_EQ(i - j, val);
+    }
+  }
+}
+
+
+TEST(Bits, SignedMulHigh32) {
+  EXPECT_EQ(0, SignedMulHigh32(0, 0));
+  TRACED_FORRANGE(int32_t, i, 1, 50) {
+    TRACED_FORRANGE(int32_t, j, 1, i) { EXPECT_EQ(0, SignedMulHigh32(i, j)); }
+  }
+  EXPECT_EQ(-1073741824, SignedMulHigh32(std::numeric_limits<int32_t>::max(),
+                                         std::numeric_limits<int32_t>::min()));
+  EXPECT_EQ(-1073741824, SignedMulHigh32(std::numeric_limits<int32_t>::min(),
+                                         std::numeric_limits<int32_t>::max()));
+  EXPECT_EQ(1, SignedMulHigh32(1024 * 1024 * 1024, 4));
+  EXPECT_EQ(2, SignedMulHigh32(8 * 1024, 1024 * 1024));
+}
+
+
+TEST(Bits, SignedMulHighAndAdd32) {
+  TRACED_FORRANGE(int32_t, i, 1, 50) {
+    EXPECT_EQ(i, SignedMulHighAndAdd32(0, 0, i));
+    TRACED_FORRANGE(int32_t, j, 1, i) {
+      EXPECT_EQ(i, SignedMulHighAndAdd32(j, j, i));
+    }
+    EXPECT_EQ(i + 1, SignedMulHighAndAdd32(1024 * 1024 * 1024, 4, i));
+  }
+}
+
+
+TEST(Bits, SignedDiv32) {
+  EXPECT_EQ(std::numeric_limits<int32_t>::min(),
+            SignedDiv32(std::numeric_limits<int32_t>::min(), -1));
+  EXPECT_EQ(std::numeric_limits<int32_t>::max(),
+            SignedDiv32(std::numeric_limits<int32_t>::max(), 1));
+  TRACED_FORRANGE(int32_t, i, 0, 50) {
+    EXPECT_EQ(0, SignedDiv32(i, 0));
+    TRACED_FORRANGE(int32_t, j, 1, i) {
+      EXPECT_EQ(1, SignedDiv32(j, j));
+      EXPECT_EQ(i / j, SignedDiv32(i, j));
+      EXPECT_EQ(-i / j, SignedDiv32(i, -j));
+    }
+  }
+}
+
+
+TEST(Bits, SignedMod32) {
+  EXPECT_EQ(0, SignedMod32(std::numeric_limits<int32_t>::min(), -1));
+  EXPECT_EQ(0, SignedMod32(std::numeric_limits<int32_t>::max(), 1));
+  TRACED_FORRANGE(int32_t, i, 0, 50) {
+    EXPECT_EQ(0, SignedMod32(i, 0));
+    TRACED_FORRANGE(int32_t, j, 1, i) {
+      EXPECT_EQ(0, SignedMod32(j, j));
+      EXPECT_EQ(i % j, SignedMod32(i, j));
+      EXPECT_EQ(i % j, SignedMod32(i, -j));
+    }
+  }
+}
+
+
+TEST(Bits, UnsignedDiv32) {
+  TRACED_FORRANGE(uint32_t, i, 0, 50) {
+    EXPECT_EQ(0u, UnsignedDiv32(i, 0));
+    TRACED_FORRANGE(uint32_t, j, i + 1, 100) {
+      EXPECT_EQ(1u, UnsignedDiv32(j, j));
+      EXPECT_EQ(i / j, UnsignedDiv32(i, j));
+    }
+  }
+}
+
+
+TEST(Bits, UnsignedMod32) {
+  TRACED_FORRANGE(uint32_t, i, 0, 50) {
+    EXPECT_EQ(0u, UnsignedMod32(i, 0));
+    TRACED_FORRANGE(uint32_t, j, i + 1, 100) {
+      EXPECT_EQ(0u, UnsignedMod32(j, j));
+      EXPECT_EQ(i % j, UnsignedMod32(i, j));
+    }
+  }
+}
+
+}  // namespace bits
+}  // namespace base
+}  // namespace v8
diff --git a/src/base/cpu-unittest.cc b/test/unittests/base/cpu-unittest.cc
similarity index 100%
rename from src/base/cpu-unittest.cc
rename to test/unittests/base/cpu-unittest.cc
diff --git a/test/unittests/base/division-by-constant-unittest.cc b/test/unittests/base/division-by-constant-unittest.cc
new file mode 100644
index 0000000..58816db
--- /dev/null
+++ b/test/unittests/base/division-by-constant-unittest.cc
@@ -0,0 +1,134 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Check all examples from table 10-1 of "Hacker's Delight".
+
+#include "src/base/division-by-constant.h"
+
+#include <stdint.h>
+
+#include <ostream>  // NOLINT
+
+#include "testing/gtest-support.h"
+
+namespace v8 {
+namespace base {
+
+template <class T>
+std::ostream& operator<<(std::ostream& os,
+                         const MagicNumbersForDivision<T>& mag) {
+  return os << "{ multiplier: " << mag.multiplier << ", shift: " << mag.shift
+            << ", add: " << mag.add << " }";
+}
+
+
+// Some abbreviations...
+
+typedef MagicNumbersForDivision<uint32_t> M32;
+typedef MagicNumbersForDivision<uint64_t> M64;
+
+
+static M32 s32(int32_t d) {
+  return SignedDivisionByConstant<uint32_t>(static_cast<uint32_t>(d));
+}
+
+
+static M64 s64(int64_t d) {
+  return SignedDivisionByConstant<uint64_t>(static_cast<uint64_t>(d));
+}
+
+
+static M32 u32(uint32_t d) { return UnsignedDivisionByConstant<uint32_t>(d); }
+static M64 u64(uint64_t d) { return UnsignedDivisionByConstant<uint64_t>(d); }
+
+
+TEST(DivisionByConstant, Signed32) {
+  EXPECT_EQ(M32(0x99999999U, 1, false), s32(-5));
+  EXPECT_EQ(M32(0x55555555U, 1, false), s32(-3));
+  int32_t d = -1;
+  for (unsigned k = 1; k <= 32 - 1; ++k) {
+    d *= 2;
+    EXPECT_EQ(M32(0x7FFFFFFFU, k - 1, false), s32(d));
+  }
+  for (unsigned k = 1; k <= 32 - 2; ++k) {
+    EXPECT_EQ(M32(0x80000001U, k - 1, false), s32(1 << k));
+  }
+  EXPECT_EQ(M32(0x55555556U, 0, false), s32(3));
+  EXPECT_EQ(M32(0x66666667U, 1, false), s32(5));
+  EXPECT_EQ(M32(0x2AAAAAABU, 0, false), s32(6));
+  EXPECT_EQ(M32(0x92492493U, 2, false), s32(7));
+  EXPECT_EQ(M32(0x38E38E39U, 1, false), s32(9));
+  EXPECT_EQ(M32(0x66666667U, 2, false), s32(10));
+  EXPECT_EQ(M32(0x2E8BA2E9U, 1, false), s32(11));
+  EXPECT_EQ(M32(0x2AAAAAABU, 1, false), s32(12));
+  EXPECT_EQ(M32(0x51EB851FU, 3, false), s32(25));
+  EXPECT_EQ(M32(0x10624DD3U, 3, false), s32(125));
+  EXPECT_EQ(M32(0x68DB8BADU, 8, false), s32(625));
+}
+
+
+TEST(DivisionByConstant, Unsigned32) {
+  EXPECT_EQ(M32(0x00000000U, 0, true), u32(1));
+  for (unsigned k = 1; k <= 30; ++k) {
+    EXPECT_EQ(M32(1U << (32 - k), 0, false), u32(1U << k));
+  }
+  EXPECT_EQ(M32(0xAAAAAAABU, 1, false), u32(3));
+  EXPECT_EQ(M32(0xCCCCCCCDU, 2, false), u32(5));
+  EXPECT_EQ(M32(0xAAAAAAABU, 2, false), u32(6));
+  EXPECT_EQ(M32(0x24924925U, 3, true), u32(7));
+  EXPECT_EQ(M32(0x38E38E39U, 1, false), u32(9));
+  EXPECT_EQ(M32(0xCCCCCCCDU, 3, false), u32(10));
+  EXPECT_EQ(M32(0xBA2E8BA3U, 3, false), u32(11));
+  EXPECT_EQ(M32(0xAAAAAAABU, 3, false), u32(12));
+  EXPECT_EQ(M32(0x51EB851FU, 3, false), u32(25));
+  EXPECT_EQ(M32(0x10624DD3U, 3, false), u32(125));
+  EXPECT_EQ(M32(0xD1B71759U, 9, false), u32(625));
+}
+
+
+TEST(DivisionByConstant, Signed64) {
+  EXPECT_EQ(M64(0x9999999999999999ULL, 1, false), s64(-5));
+  EXPECT_EQ(M64(0x5555555555555555ULL, 1, false), s64(-3));
+  int64_t d = -1;
+  for (unsigned k = 1; k <= 64 - 1; ++k) {
+    d *= 2;
+    EXPECT_EQ(M64(0x7FFFFFFFFFFFFFFFULL, k - 1, false), s64(d));
+  }
+  for (unsigned k = 1; k <= 64 - 2; ++k) {
+    EXPECT_EQ(M64(0x8000000000000001ULL, k - 1, false), s64(1LL << k));
+  }
+  EXPECT_EQ(M64(0x5555555555555556ULL, 0, false), s64(3));
+  EXPECT_EQ(M64(0x6666666666666667ULL, 1, false), s64(5));
+  EXPECT_EQ(M64(0x2AAAAAAAAAAAAAABULL, 0, false), s64(6));
+  EXPECT_EQ(M64(0x4924924924924925ULL, 1, false), s64(7));
+  EXPECT_EQ(M64(0x1C71C71C71C71C72ULL, 0, false), s64(9));
+  EXPECT_EQ(M64(0x6666666666666667ULL, 2, false), s64(10));
+  EXPECT_EQ(M64(0x2E8BA2E8BA2E8BA3ULL, 1, false), s64(11));
+  EXPECT_EQ(M64(0x2AAAAAAAAAAAAAABULL, 1, false), s64(12));
+  EXPECT_EQ(M64(0xA3D70A3D70A3D70BULL, 4, false), s64(25));
+  EXPECT_EQ(M64(0x20C49BA5E353F7CFULL, 4, false), s64(125));
+  EXPECT_EQ(M64(0x346DC5D63886594BULL, 7, false), s64(625));
+}
+
+
+TEST(DivisionByConstant, Unsigned64) {
+  EXPECT_EQ(M64(0x0000000000000000ULL, 0, true), u64(1));
+  for (unsigned k = 1; k <= 64 - 2; ++k) {
+    EXPECT_EQ(M64(1ULL << (64 - k), 0, false), u64(1ULL << k));
+  }
+  EXPECT_EQ(M64(0xAAAAAAAAAAAAAAABULL, 1, false), u64(3));
+  EXPECT_EQ(M64(0xCCCCCCCCCCCCCCCDULL, 2, false), u64(5));
+  EXPECT_EQ(M64(0xAAAAAAAAAAAAAAABULL, 2, false), u64(6));
+  EXPECT_EQ(M64(0x2492492492492493ULL, 3, true), u64(7));
+  EXPECT_EQ(M64(0xE38E38E38E38E38FULL, 3, false), u64(9));
+  EXPECT_EQ(M64(0xCCCCCCCCCCCCCCCDULL, 3, false), u64(10));
+  EXPECT_EQ(M64(0x2E8BA2E8BA2E8BA3ULL, 1, false), u64(11));
+  EXPECT_EQ(M64(0xAAAAAAAAAAAAAAABULL, 3, false), u64(12));
+  EXPECT_EQ(M64(0x47AE147AE147AE15ULL, 5, true), u64(25));
+  EXPECT_EQ(M64(0x0624DD2F1A9FBE77ULL, 7, true), u64(125));
+  EXPECT_EQ(M64(0x346DC5D63886594BULL, 7, false), u64(625));
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/flags-unittest.cc b/test/unittests/base/flags-unittest.cc
new file mode 100644
index 0000000..6f19399
--- /dev/null
+++ b/test/unittests/base/flags-unittest.cc
@@ -0,0 +1,104 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+#include "src/base/flags.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace base {
+
+namespace {
+
+enum Flag1 {
+  kFlag1None = 0,
+  kFlag1First = 1u << 1,
+  kFlag1Second = 1u << 2,
+  kFlag1All = kFlag1None | kFlag1First | kFlag1Second
+};
+typedef Flags<Flag1> Flags1;
+
+
+DEFINE_OPERATORS_FOR_FLAGS(Flags1)
+
+
+Flags1 bar(Flags1 flags1) { return flags1; }
+
+}  // namespace
+
+
+TEST(FlagsTest, BasicOperations) {
+  Flags1 a;
+  EXPECT_EQ(kFlag1None, static_cast<int>(a));
+  a |= kFlag1First;
+  EXPECT_EQ(kFlag1First, static_cast<int>(a));
+  a = a | kFlag1Second;
+  EXPECT_EQ(kFlag1All, static_cast<int>(a));
+  a &= kFlag1Second;
+  EXPECT_EQ(kFlag1Second, static_cast<int>(a));
+  a = kFlag1None & a;
+  EXPECT_EQ(kFlag1None, static_cast<int>(a));
+  a ^= (kFlag1All | kFlag1None);
+  EXPECT_EQ(kFlag1All, static_cast<int>(a));
+  Flags1 b = ~a;
+  EXPECT_EQ(kFlag1All, static_cast<int>(a));
+  EXPECT_EQ(~static_cast<int>(a), static_cast<int>(b));
+  Flags1 c = a;
+  EXPECT_EQ(a, c);
+  EXPECT_NE(a, b);
+  EXPECT_EQ(a, bar(a));
+  EXPECT_EQ(a, bar(kFlag1All));
+}
+
+
+namespace {
+namespace foo {
+
+enum Option {
+  kNoOptions = 0,
+  kOption1 = 1,
+  kOption2 = 2,
+  kAllOptions = kNoOptions | kOption1 | kOption2
+};
+typedef Flags<Option> Options;
+
+}  // namespace foo
+
+
+DEFINE_OPERATORS_FOR_FLAGS(foo::Options)
+
+}  // namespace
+
+
+TEST(FlagsTest, NamespaceScope) {
+  foo::Options options;
+  options ^= foo::kNoOptions;
+  options |= foo::kOption1 | foo::kOption2;
+  EXPECT_EQ(foo::kAllOptions, static_cast<int>(options));
+}
+
+
+namespace {
+
+struct Foo {
+  enum Enum { kEnum1 = 1, kEnum2 = 2 };
+  typedef Flags<Enum, uint32_t> Enums;
+};
+
+
+DEFINE_OPERATORS_FOR_FLAGS(Foo::Enums)
+
+}  // namespace
+
+
+TEST(FlagsTest, ClassScope) {
+  Foo::Enums enums;
+  enums |= Foo::kEnum1;
+  enums |= Foo::kEnum2;
+  EXPECT_TRUE(enums & Foo::kEnum1);
+  EXPECT_TRUE(enums & Foo::kEnum2);
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/functional-unittest.cc b/test/unittests/base/functional-unittest.cc
new file mode 100644
index 0000000..97a27a4
--- /dev/null
+++ b/test/unittests/base/functional-unittest.cc
@@ -0,0 +1,196 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/functional.h"
+
+#include <limits>
+#include <set>
+
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace base {
+
+TEST(FunctionalTest, HashBool) {
+  hash<bool> h, h1, h2;
+  EXPECT_EQ(h1(true), h2(true));
+  EXPECT_EQ(h1(false), h2(false));
+  EXPECT_NE(h(true), h(false));
+}
+
+
+TEST(FunctionalTest, HashFloatZero) {
+  hash<float> h;
+  EXPECT_EQ(h(0.0f), h(-0.0f));
+}
+
+
+TEST(FunctionalTest, HashDoubleZero) {
+  hash<double> h;
+  EXPECT_EQ(h(0.0), h(-0.0));
+}
+
+
+template <typename T>
+class FunctionalTest : public TestWithRandomNumberGenerator {};
+
+typedef ::testing::Types<signed char, unsigned char,
+                         short,                    // NOLINT(runtime/int)
+                         unsigned short,           // NOLINT(runtime/int)
+                         int, unsigned int, long,  // NOLINT(runtime/int)
+                         unsigned long,            // NOLINT(runtime/int)
+                         long long,                // NOLINT(runtime/int)
+                         unsigned long long,       // NOLINT(runtime/int)
+                         int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
+                         int64_t, uint64_t, float, double> FunctionalTypes;
+
+TYPED_TEST_CASE(FunctionalTest, FunctionalTypes);
+
+
+TYPED_TEST(FunctionalTest, EqualToImpliesSameHashCode) {
+  hash<TypeParam> h;
+  std::equal_to<TypeParam> e;
+  TypeParam values[32];
+  this->rng()->NextBytes(values, sizeof(values));
+  TRACED_FOREACH(TypeParam, v1, values) {
+    TRACED_FOREACH(TypeParam, v2, values) {
+      if (e(v1, v2)) EXPECT_EQ(h(v1), h(v2));
+    }
+  }
+}
+
+
+TYPED_TEST(FunctionalTest, HashEqualsHashValue) {
+  for (int i = 0; i < 128; ++i) {
+    TypeParam v;
+    this->rng()->NextBytes(&v, sizeof(v));
+    hash<TypeParam> h;
+    EXPECT_EQ(h(v), hash_value(v));
+  }
+}
+
+
+TYPED_TEST(FunctionalTest, HashIsStateless) {
+  hash<TypeParam> h1, h2;
+  for (int i = 0; i < 128; ++i) {
+    TypeParam v;
+    this->rng()->NextBytes(&v, sizeof(v));
+    EXPECT_EQ(h1(v), h2(v));
+  }
+}
+
+
+TYPED_TEST(FunctionalTest, HashIsOkish) {
+  std::set<TypeParam> vs;
+  for (size_t i = 0; i < 128; ++i) {
+    TypeParam v;
+    this->rng()->NextBytes(&v, sizeof(v));
+    vs.insert(v);
+  }
+  std::set<size_t> hs;
+  for (const auto& v : vs) {
+    hash<TypeParam> h;
+    hs.insert(h(v));
+  }
+  EXPECT_LE(vs.size() / 4u, hs.size());
+}
+
+
+TYPED_TEST(FunctionalTest, HashValueArrayUsesHashRange) {
+  TypeParam values[128];
+  this->rng()->NextBytes(&values, sizeof(values));
+  EXPECT_EQ(hash_range(values, values + arraysize(values)), hash_value(values));
+}
+
+
+TYPED_TEST(FunctionalTest, BitEqualTo) {
+  bit_equal_to<TypeParam> pred;
+  for (size_t i = 0; i < 128; ++i) {
+    TypeParam v1, v2;
+    this->rng()->NextBytes(&v1, sizeof(v1));
+    this->rng()->NextBytes(&v2, sizeof(v2));
+    EXPECT_PRED2(pred, v1, v1);
+    EXPECT_PRED2(pred, v2, v2);
+    EXPECT_EQ(memcmp(&v1, &v2, sizeof(TypeParam)) == 0, pred(v1, v2));
+  }
+}
+
+
+TYPED_TEST(FunctionalTest, BitEqualToImpliesSameBitHash) {
+  bit_hash<TypeParam> h;
+  bit_equal_to<TypeParam> e;
+  TypeParam values[32];
+  this->rng()->NextBytes(&values, sizeof(values));
+  TRACED_FOREACH(TypeParam, v1, values) {
+    TRACED_FOREACH(TypeParam, v2, values) {
+      if (e(v1, v2)) EXPECT_EQ(h(v1), h(v2));
+    }
+  }
+}
+
+
+namespace {
+
+struct Foo {
+  int x;
+  double y;
+};
+
+
+size_t hash_value(Foo const& v) { return hash_combine(v.x, v.y); }
+
+}  // namespace
+
+
+TEST(FunctionalTest, HashUsesArgumentDependentLookup) {
+  const int kIntValues[] = {std::numeric_limits<int>::min(), -1, 0, 1, 42,
+                            std::numeric_limits<int>::max()};
+  const double kDoubleValues[] = {
+      std::numeric_limits<double>::min(), -1, -0, 0, 1,
+      std::numeric_limits<double>::max()};
+  TRACED_FOREACH(int, x, kIntValues) {
+    TRACED_FOREACH(double, y, kDoubleValues) {
+      hash<Foo> h;
+      Foo foo = {x, y};
+      EXPECT_EQ(hash_combine(x, y), h(foo));
+    }
+  }
+}
+
+
+TEST(FunctionalTest, BitEqualToFloat) {
+  bit_equal_to<float> pred;
+  EXPECT_FALSE(pred(0.0f, -0.0f));
+  EXPECT_FALSE(pred(-0.0f, 0.0f));
+  float const qNaN = std::numeric_limits<float>::quiet_NaN();
+  float const sNaN = std::numeric_limits<float>::signaling_NaN();
+  EXPECT_PRED2(pred, qNaN, qNaN);
+  EXPECT_PRED2(pred, sNaN, sNaN);
+}
+
+
+TEST(FunctionalTest, BitHashFloatDifferentForZeroAndMinusZero) {
+  bit_hash<float> h;
+  EXPECT_NE(h(0.0f), h(-0.0f));
+}
+
+
+TEST(FunctionalTest, BitEqualToDouble) {
+  bit_equal_to<double> pred;
+  EXPECT_FALSE(pred(0.0, -0.0));
+  EXPECT_FALSE(pred(-0.0, 0.0));
+  double const qNaN = std::numeric_limits<double>::quiet_NaN();
+  double const sNaN = std::numeric_limits<double>::signaling_NaN();
+  EXPECT_PRED2(pred, qNaN, qNaN);
+  EXPECT_PRED2(pred, sNaN, sNaN);
+}
+
+
+TEST(FunctionalTest, BitHashDoubleDifferentForZeroAndMinusZero) {
+  bit_hash<double> h;
+  EXPECT_NE(h(0.0), h(-0.0));
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/iterator-unittest.cc b/test/unittests/base/iterator-unittest.cc
new file mode 100644
index 0000000..8da26ce
--- /dev/null
+++ b/test/unittests/base/iterator-unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/iterator.h"
+
+#include <deque>
+
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace base {
+
+TEST(IteratorTest, IteratorRangeEmpty) {
+  base::iterator_range<char*> r;
+  EXPECT_EQ(r.begin(), r.end());
+  EXPECT_EQ(r.end(), r.cend());
+  EXPECT_EQ(r.begin(), r.cbegin());
+  EXPECT_TRUE(r.empty());
+  EXPECT_EQ(0, r.size());
+}
+
+
+TEST(IteratorTest, IteratorRangeArray) {
+  int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+  base::iterator_range<int*> r1(&array[0], &array[10]);
+  for (auto i : r1) {
+    EXPECT_EQ(array[i], i);
+  }
+  EXPECT_EQ(10, r1.size());
+  EXPECT_FALSE(r1.empty());
+  for (size_t i = 0; i < arraysize(array); ++i) {
+    EXPECT_EQ(r1[i], array[i]);
+  }
+  base::iterator_range<int*> r2(&array[0], &array[0]);
+  EXPECT_EQ(0, r2.size());
+  EXPECT_TRUE(r2.empty());
+  for (auto i : array) {
+    EXPECT_EQ(r2.end(), std::find(r2.begin(), r2.end(), i));
+  }
+}
+
+
+TEST(IteratorTest, IteratorRangeDeque) {
+  typedef std::deque<unsigned> C;
+  C c;
+  c.push_back(1);
+  c.push_back(2);
+  c.push_back(2);
+  base::iterator_range<typename C::iterator> r(c.begin(), c.end());
+  EXPECT_EQ(3, r.size());
+  EXPECT_FALSE(r.empty());
+  EXPECT_TRUE(c.begin() == r.begin());
+  EXPECT_TRUE(c.end() == r.end());
+  EXPECT_EQ(0, std::count(r.begin(), r.end(), 0));
+  EXPECT_EQ(1, std::count(r.begin(), r.end(), 1));
+  EXPECT_EQ(2, std::count(r.begin(), r.end(), 2));
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/src/base/platform/condition-variable-unittest.cc b/test/unittests/base/platform/condition-variable-unittest.cc
similarity index 100%
rename from src/base/platform/condition-variable-unittest.cc
rename to test/unittests/base/platform/condition-variable-unittest.cc
diff --git a/src/base/platform/mutex-unittest.cc b/test/unittests/base/platform/mutex-unittest.cc
similarity index 100%
rename from src/base/platform/mutex-unittest.cc
rename to test/unittests/base/platform/mutex-unittest.cc
diff --git a/test/unittests/base/platform/platform-unittest.cc b/test/unittests/base/platform/platform-unittest.cc
new file mode 100644
index 0000000..b17a9b9
--- /dev/null
+++ b/test/unittests/base/platform/platform-unittest.cc
@@ -0,0 +1,118 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/platform/platform.h"
+
+#if V8_OS_POSIX
+#include <unistd.h>  // NOLINT
+#endif
+
+#if V8_OS_WIN
+#include "src/base/win32-headers.h"
+#endif
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if V8_OS_ANDROID
+#define DISABLE_ON_ANDROID(Name) DISABLED_##Name
+#else
+#define DISABLE_ON_ANDROID(Name) Name
+#endif
+
+namespace v8 {
+namespace base {
+
+TEST(OS, GetCurrentProcessId) {
+#if V8_OS_POSIX
+  EXPECT_EQ(static_cast<int>(getpid()), OS::GetCurrentProcessId());
+#endif
+
+#if V8_OS_WIN
+  EXPECT_EQ(static_cast<int>(::GetCurrentProcessId()),
+            OS::GetCurrentProcessId());
+#endif
+}
+
+
+namespace {
+
+class SelfJoinThread FINAL : public Thread {
+ public:
+  SelfJoinThread() : Thread(Options("SelfJoinThread")) {}
+  void Run() FINAL { Join(); }
+};
+
+}  // namespace
+
+
+TEST(Thread, DISABLE_ON_ANDROID(SelfJoin)) {
+  SelfJoinThread thread;
+  thread.Start();
+  thread.Join();
+}
+
+
+namespace {
+
+class ThreadLocalStorageTest : public Thread, public ::testing::Test {
+ public:
+  ThreadLocalStorageTest() : Thread(Options("ThreadLocalStorageTest")) {
+    for (size_t i = 0; i < arraysize(keys_); ++i) {
+      keys_[i] = Thread::CreateThreadLocalKey();
+    }
+  }
+  ~ThreadLocalStorageTest() {
+    for (size_t i = 0; i < arraysize(keys_); ++i) {
+      Thread::DeleteThreadLocalKey(keys_[i]);
+    }
+  }
+
+  void Run() FINAL {
+    for (size_t i = 0; i < arraysize(keys_); i++) {
+      CHECK(!Thread::HasThreadLocal(keys_[i]));
+    }
+    for (size_t i = 0; i < arraysize(keys_); i++) {
+      Thread::SetThreadLocal(keys_[i], GetValue(i));
+    }
+    for (size_t i = 0; i < arraysize(keys_); i++) {
+      CHECK(Thread::HasThreadLocal(keys_[i]));
+    }
+    for (size_t i = 0; i < arraysize(keys_); i++) {
+      CHECK_EQ(GetValue(i), Thread::GetThreadLocal(keys_[i]));
+      CHECK_EQ(GetValue(i), Thread::GetExistingThreadLocal(keys_[i]));
+    }
+    for (size_t i = 0; i < arraysize(keys_); i++) {
+      Thread::SetThreadLocal(keys_[i], GetValue(arraysize(keys_) - i - 1));
+    }
+    for (size_t i = 0; i < arraysize(keys_); i++) {
+      CHECK(Thread::HasThreadLocal(keys_[i]));
+    }
+    for (size_t i = 0; i < arraysize(keys_); i++) {
+      CHECK_EQ(GetValue(arraysize(keys_) - i - 1),
+               Thread::GetThreadLocal(keys_[i]));
+      CHECK_EQ(GetValue(arraysize(keys_) - i - 1),
+               Thread::GetExistingThreadLocal(keys_[i]));
+    }
+  }
+
+ private:
+  static void* GetValue(size_t x) {
+    return bit_cast<void*>(static_cast<uintptr_t>(x + 1));
+  }
+
+  // Older versions of Android have fewer TLS slots (nominally 64, but the
+  // system uses "about 5 of them" itself).
+  Thread::LocalStorageKey keys_[32];
+};
+
+}  // namespace
+
+
+TEST_F(ThreadLocalStorageTest, DoTest) {
+  Run();
+  Start();
+  Join();
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/src/base/platform/semaphore-unittest.cc b/test/unittests/base/platform/semaphore-unittest.cc
similarity index 100%
rename from src/base/platform/semaphore-unittest.cc
rename to test/unittests/base/platform/semaphore-unittest.cc
diff --git a/src/base/platform/time-unittest.cc b/test/unittests/base/platform/time-unittest.cc
similarity index 100%
rename from src/base/platform/time-unittest.cc
rename to test/unittests/base/platform/time-unittest.cc
diff --git a/src/base/sys-info-unittest.cc b/test/unittests/base/sys-info-unittest.cc
similarity index 100%
rename from src/base/sys-info-unittest.cc
rename to test/unittests/base/sys-info-unittest.cc
diff --git a/src/base/utils/random-number-generator-unittest.cc b/test/unittests/base/utils/random-number-generator-unittest.cc
similarity index 100%
rename from src/base/utils/random-number-generator-unittest.cc
rename to test/unittests/base/utils/random-number-generator-unittest.cc
diff --git a/test/unittests/char-predicates-unittest.cc b/test/unittests/char-predicates-unittest.cc
new file mode 100644
index 0000000..d1ba2c5
--- /dev/null
+++ b/test/unittests/char-predicates-unittest.cc
@@ -0,0 +1,121 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/char-predicates.h"
+#include "src/unicode.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace internal {
+
+TEST(CharPredicatesTest, WhiteSpace) {
+  // As of Unicode 6.3.0, \u180E is no longer a white space. We still consider
+  // it to be one though, since JS recognizes all white spaces in Unicode 5.1.
+  EXPECT_TRUE(WhiteSpace::Is(0x0009));
+  EXPECT_TRUE(WhiteSpace::Is(0x000B));
+  EXPECT_TRUE(WhiteSpace::Is(0x000C));
+  EXPECT_TRUE(WhiteSpace::Is(' '));
+  EXPECT_TRUE(WhiteSpace::Is(0x00A0));
+  EXPECT_TRUE(WhiteSpace::Is(0x180E));
+  EXPECT_TRUE(WhiteSpace::Is(0xFEFF));
+}
+
+
+TEST(CharPredicatesTest, WhiteSpaceOrLineTerminator) {
+  // As of Unicode 6.3.0, \u180E is no longer a white space. We still consider
+  // it to be one though, since JS recognizes all white spaces in Unicode 5.1.
+  // White spaces
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x0009));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x000B));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x000C));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(' '));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x00A0));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x180E));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0xFEFF));
+  // Line terminators
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x000A));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x000D));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x2028));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x2029));
+}
+
+
+TEST(CharPredicatesTest, IdentifierStart) {
+  EXPECT_TRUE(IdentifierStart::Is('$'));
+  EXPECT_TRUE(IdentifierStart::Is('_'));
+  EXPECT_TRUE(IdentifierStart::Is('\\'));
+
+  // http://www.unicode.org/reports/tr31/
+  // Other_ID_Start
+  EXPECT_TRUE(IdentifierStart::Is(0x2118));
+  EXPECT_TRUE(IdentifierStart::Is(0x212E));
+  EXPECT_TRUE(IdentifierStart::Is(0x309B));
+  EXPECT_TRUE(IdentifierStart::Is(0x309C));
+
+  // Issue 2892:
+  // \u2E2F has the Pattern_Syntax property, excluding it from ID_Start.
+  EXPECT_FALSE(unibrow::ID_Start::Is(0x2E2F));
+}
+
+
+TEST(CharPredicatesTest, IdentifierPart) {
+  EXPECT_TRUE(IdentifierPart::Is('$'));
+  EXPECT_TRUE(IdentifierPart::Is('_'));
+  EXPECT_TRUE(IdentifierPart::Is('\\'));
+  EXPECT_TRUE(IdentifierPart::Is(0x200C));
+  EXPECT_TRUE(IdentifierPart::Is(0x200D));
+
+  // http://www.unicode.org/reports/tr31/
+  // Other_ID_Start
+  EXPECT_TRUE(IdentifierPart::Is(0x2118));
+  EXPECT_TRUE(IdentifierPart::Is(0x212E));
+  EXPECT_TRUE(IdentifierPart::Is(0x309B));
+  EXPECT_TRUE(IdentifierPart::Is(0x309C));
+
+  // Other_ID_Continue
+  EXPECT_TRUE(IdentifierPart::Is(0x00B7));
+  EXPECT_TRUE(IdentifierPart::Is(0x0387));
+  EXPECT_TRUE(IdentifierPart::Is(0x1369));
+  EXPECT_TRUE(IdentifierPart::Is(0x1370));
+  EXPECT_TRUE(IdentifierPart::Is(0x1371));
+  EXPECT_TRUE(IdentifierPart::Is(0x19DA));
+
+  // Issue 2892:
+  // \u2E2F has the Pattern_Syntax property, excluding it from ID_Start.
+  EXPECT_FALSE(IdentifierPart::Is(0x2E2F));
+}
+
+
+#ifdef V8_I18N_SUPPORT
+TEST(CharPredicatesTest, SupplementaryPlaneIdentifiers) {
+  // Both ID_Start and ID_Continue.
+  EXPECT_TRUE(IdentifierStart::Is(0x10403));  // Category Lu
+  EXPECT_TRUE(IdentifierPart::Is(0x10403));
+  EXPECT_TRUE(IdentifierStart::Is(0x1043C));  // Category Ll
+  EXPECT_TRUE(IdentifierPart::Is(0x1043C));
+  EXPECT_TRUE(IdentifierStart::Is(0x16F9C));  // Category Lm
+  EXPECT_TRUE(IdentifierPart::Is(0x16F9C));
+  EXPECT_TRUE(IdentifierStart::Is(0x10048));  // Category Lo
+  EXPECT_TRUE(IdentifierPart::Is(0x10048));
+  EXPECT_TRUE(IdentifierStart::Is(0x1014D));  // Category Nl
+  EXPECT_TRUE(IdentifierPart::Is(0x1014D));
+
+  // Only ID_Continue.
+  EXPECT_FALSE(IdentifierStart::Is(0x101FD));  // Category Mn
+  EXPECT_TRUE(IdentifierPart::Is(0x101FD));
+  EXPECT_FALSE(IdentifierStart::Is(0x11002));  // Category Mc
+  EXPECT_TRUE(IdentifierPart::Is(0x11002));
+  EXPECT_FALSE(IdentifierStart::Is(0x104A9));  // Category Nd
+  EXPECT_TRUE(IdentifierPart::Is(0x104A9));
+
+  // Neither.
+  EXPECT_FALSE(IdentifierStart::Is(0x10111));  // Category No
+  EXPECT_FALSE(IdentifierPart::Is(0x10111));
+  EXPECT_FALSE(IdentifierStart::Is(0x1F4A9));  // Category So
+  EXPECT_FALSE(IdentifierPart::Is(0x1F4A9));
+}
+#endif  // V8_I18N_SUPPORT
+
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc b/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
new file mode 100644
index 0000000..fbdf87a
--- /dev/null
+++ b/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
@@ -0,0 +1,2352 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "test/unittests/compiler/instruction-selector-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+typedef RawMachineAssembler::Label MLabel;
+typedef Node* (RawMachineAssembler::*Constructor)(Node*, Node*);
+
+
+// Data processing instructions.
+struct DPI {
+  Constructor constructor;
+  const char* constructor_name;
+  ArchOpcode arch_opcode;
+  ArchOpcode reverse_arch_opcode;
+  ArchOpcode test_arch_opcode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const DPI& dpi) {
+  return os << dpi.constructor_name;
+}
+
+
+static const DPI kDPIs[] = {
+    {&RawMachineAssembler::Word32And, "Word32And", kArmAnd, kArmAnd, kArmTst},
+    {&RawMachineAssembler::Word32Or, "Word32Or", kArmOrr, kArmOrr, kArmOrr},
+    {&RawMachineAssembler::Word32Xor, "Word32Xor", kArmEor, kArmEor, kArmTeq},
+    {&RawMachineAssembler::Int32Add, "Int32Add", kArmAdd, kArmAdd, kArmCmn},
+    {&RawMachineAssembler::Int32Sub, "Int32Sub", kArmSub, kArmRsb, kArmCmp}};
+
+
+// Data processing instructions with overflow.
+struct ODPI {
+  Constructor constructor;
+  const char* constructor_name;
+  ArchOpcode arch_opcode;
+  ArchOpcode reverse_arch_opcode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const ODPI& odpi) {
+  return os << odpi.constructor_name;
+}
+
+
+static const ODPI kODPIs[] = {{&RawMachineAssembler::Int32AddWithOverflow,
+                               "Int32AddWithOverflow", kArmAdd, kArmAdd},
+                              {&RawMachineAssembler::Int32SubWithOverflow,
+                               "Int32SubWithOverflow", kArmSub, kArmRsb}};
+
+
+// Shifts.
+struct Shift {
+  Constructor constructor;
+  const char* constructor_name;
+  int32_t i_low;          // lowest possible immediate
+  int32_t i_high;         // highest possible immediate
+  AddressingMode i_mode;  // Operand2_R_<shift>_I
+  AddressingMode r_mode;  // Operand2_R_<shift>_R
+};
+
+
+std::ostream& operator<<(std::ostream& os, const Shift& shift) {
+  return os << shift.constructor_name;
+}
+
+
+static const Shift kShifts[] = {
+    {&RawMachineAssembler::Word32Sar, "Word32Sar", 1, 32,
+     kMode_Operand2_R_ASR_I, kMode_Operand2_R_ASR_R},
+    {&RawMachineAssembler::Word32Shl, "Word32Shl", 0, 31,
+     kMode_Operand2_R_LSL_I, kMode_Operand2_R_LSL_R},
+    {&RawMachineAssembler::Word32Shr, "Word32Shr", 1, 32,
+     kMode_Operand2_R_LSR_I, kMode_Operand2_R_LSR_R},
+    {&RawMachineAssembler::Word32Ror, "Word32Ror", 1, 31,
+     kMode_Operand2_R_ROR_I, kMode_Operand2_R_ROR_R}};
+
+
+// Immediates (random subset).
+static const int32_t kImmediates[] = {
+    std::numeric_limits<int32_t>::min(), -2147483617, -2147483606, -2113929216,
+    -2080374784,                         -1996488704, -1879048192, -1459617792,
+    -1358954496,                         -1342177265, -1275068414, -1073741818,
+    -1073741777,                         -855638016,  -805306368,  -402653184,
+    -268435444,                          -16777216,   0,           35,
+    61,                                  105,         116,         171,
+    245,                                 255,         692,         1216,
+    1248,                                1520,        1600,        1888,
+    3744,                                4080,        5888,        8384,
+    9344,                                9472,        9792,        13312,
+    15040,                               15360,       20736,       22272,
+    23296,                               32000,       33536,       37120,
+    45824,                               47872,       56320,       59392,
+    65280,                               72704,       101376,      147456,
+    161792,                              164864,      167936,      173056,
+    195584,                              209920,      212992,      356352,
+    655360,                              704512,      716800,      851968,
+    901120,                              1044480,     1523712,     2572288,
+    3211264,                             3588096,     3833856,     3866624,
+    4325376,                             5177344,     6488064,     7012352,
+    7471104,                             14090240,    16711680,    19398656,
+    22282240,                            28573696,    30408704,    30670848,
+    43253760,                            54525952,    55312384,    56623104,
+    68157440,                            115343360,   131072000,   187695104,
+    188743680,                           195035136,   197132288,   203423744,
+    218103808,                           267386880,   268435470,   285212672,
+    402653185,                           415236096,   595591168,   603979776,
+    603979778,                           629145600,   1073741835,  1073741855,
+    1073741861,                          1073741884,  1157627904,  1476395008,
+    1476395010,                          1610612741,  2030043136,  2080374785,
+    2097152000};
+
+}  // namespace
+
+
+// -----------------------------------------------------------------------------
+// Data processing instructions.
+
+
+typedef InstructionSelectorTestWithParam<DPI> InstructionSelectorDPITest;
+
+
+TEST_P(InstructionSelectorDPITest, Parameters) {
+  const DPI dpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorDPITest, Immediate) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorDPITest, ShiftByParameter) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return((m.*dpi.constructor)(
+        m.Parameter(0),
+        (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return((m.*dpi.constructor)(
+        (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
+        m.Parameter(2)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorDPITest, ShiftByImmediate) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      m.Return((m.*dpi.constructor)(
+          m.Parameter(0),
+          (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      m.Return((m.*dpi.constructor)(
+          (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)),
+          m.Parameter(1)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchWithParameters) {
+  const DPI dpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  MLabel a, b;
+  m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b);
+  m.Bind(&a);
+  m.Return(m.Int32Constant(1));
+  m.Bind(&b);
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchWithImmediate) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)), &a,
+             &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)), &a,
+             &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchWithShiftByParameter) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch((m.*dpi.constructor)(
+                 m.Parameter(0),
+                 (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))),
+             &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch((m.*dpi.constructor)(
+                 (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
+                 m.Parameter(2)),
+             &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchWithShiftByImmediate) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      MLabel a, b;
+      m.Branch((m.*dpi.constructor)(m.Parameter(0),
+                                    (m.*shift.constructor)(
+                                        m.Parameter(1), m.Int32Constant(imm))),
+               &a, &b);
+      m.Bind(&a);
+      m.Return(m.Int32Constant(1));
+      m.Bind(&b);
+      m.Return(m.Int32Constant(0));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(5U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+      EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+    }
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      MLabel a, b;
+      m.Branch((m.*dpi.constructor)(
+                   (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)),
+                   m.Parameter(1)),
+               &a, &b);
+      m.Bind(&a);
+      m.Return(m.Int32Constant(1));
+      m.Bind(&b);
+      m.Return(m.Int32Constant(0));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(5U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+      EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+    }
+  }
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchIfZeroWithParameters) {
+  const DPI dpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  MLabel a, b;
+  m.Branch(m.Word32Equal((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)),
+                         m.Int32Constant(0)),
+           &a, &b);
+  m.Bind(&a);
+  m.Return(m.Int32Constant(1));
+  m.Bind(&b);
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kEqual, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchIfNotZeroWithParameters) {
+  const DPI dpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  MLabel a, b;
+  m.Branch(
+      m.Word32NotEqual((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)),
+                       m.Int32Constant(0)),
+      &a, &b);
+  m.Bind(&a);
+  m.Return(m.Int32Constant(1));
+  m.Bind(&b);
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchIfZeroWithImmediate) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32Equal(
+                 (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)),
+                 m.Int32Constant(0)),
+             &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32Equal(
+                 (m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)),
+                 m.Int32Constant(0)),
+             &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchIfNotZeroWithImmediate) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32NotEqual(
+                 (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)),
+                 m.Int32Constant(0)),
+             &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32NotEqual(
+                 (m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)),
+                 m.Int32Constant(0)),
+             &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorDPITest,
+                        ::testing::ValuesIn(kDPIs));
+
+
+// -----------------------------------------------------------------------------
+// Data processing instructions with overflow.
+
+
+typedef InstructionSelectorTestWithParam<ODPI> InstructionSelectorODPITest;
+
+
+TEST_P(InstructionSelectorODPITest, OvfWithParameters) {
+  const ODPI odpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(
+      m.Projection(1, (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_LE(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kOverflow, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorODPITest, OvfWithImmediate) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        1, (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        1, (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, OvfWithShiftByParameter) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        1, (m.*odpi.constructor)(
+               m.Parameter(0),
+               (m.*shift.constructor)(m.Parameter(1), m.Parameter(2)))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        1, (m.*odpi.constructor)(
+               (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
+               m.Parameter(0))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, OvfWithShiftByImmediate) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      m.Return(m.Projection(
+          1, (m.*odpi.constructor)(m.Parameter(0),
+                                   (m.*shift.constructor)(
+                                       m.Parameter(1), m.Int32Constant(imm)))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_LE(1U, s[0]->OutputCount());
+      EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+      EXPECT_EQ(kOverflow, s[0]->flags_condition());
+    }
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      m.Return(m.Projection(
+          1, (m.*odpi.constructor)(
+                 (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)),
+                 m.Parameter(0))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_LE(1U, s[0]->OutputCount());
+      EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+      EXPECT_EQ(kOverflow, s[0]->flags_condition());
+    }
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, ValWithParameters) {
+  const ODPI odpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(
+      m.Projection(0, (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_LE(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+}
+
+
+TEST_P(InstructionSelectorODPITest, ValWithImmediate) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        0, (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        0, (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, ValWithShiftByParameter) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        0, (m.*odpi.constructor)(
+               m.Parameter(0),
+               (m.*shift.constructor)(m.Parameter(1), m.Parameter(2)))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        0, (m.*odpi.constructor)(
+               (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
+               m.Parameter(0))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, ValWithShiftByImmediate) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      m.Return(m.Projection(
+          0, (m.*odpi.constructor)(m.Parameter(0),
+                                   (m.*shift.constructor)(
+                                       m.Parameter(1), m.Int32Constant(imm)))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_LE(1U, s[0]->OutputCount());
+      EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+    }
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      m.Return(m.Projection(
+          0, (m.*odpi.constructor)(
+                 (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)),
+                 m.Parameter(0))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_LE(1U, s[0]->OutputCount());
+      EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+    }
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, BothWithParameters) {
+  const ODPI odpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
+  m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+  Stream s = m.Build();
+  ASSERT_LE(1U, s.size());
+  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(2U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kOverflow, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorODPITest, BothWithImmediate) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
+    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+    Stream s = m.Build();
+    ASSERT_LE(1U, s.size());
+    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(2U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* n = (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0));
+    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+    Stream s = m.Build();
+    ASSERT_LE(1U, s.size());
+    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(2U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, BothWithShiftByParameter) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    Node* n = (m.*odpi.constructor)(
+        m.Parameter(0), (m.*shift.constructor)(m.Parameter(1), m.Parameter(2)));
+    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+    Stream s = m.Build();
+    ASSERT_LE(1U, s.size());
+    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(2U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    Node* n = (m.*odpi.constructor)(
+        (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)), m.Parameter(2));
+    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+    Stream s = m.Build();
+    ASSERT_LE(1U, s.size());
+    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(2U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, BothWithShiftByImmediate) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      Node* n = (m.*odpi.constructor)(
+          m.Parameter(0),
+          (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)));
+      m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+      Stream s = m.Build();
+      ASSERT_LE(1U, s.size());
+      EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_EQ(2U, s[0]->OutputCount());
+      EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+      EXPECT_EQ(kOverflow, s[0]->flags_condition());
+    }
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      Node* n = (m.*odpi.constructor)(
+          (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)),
+          m.Parameter(1));
+      m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+      Stream s = m.Build();
+      ASSERT_LE(1U, s.size());
+      EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_EQ(2U, s[0]->OutputCount());
+      EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+      EXPECT_EQ(kOverflow, s[0]->flags_condition());
+    }
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, BranchWithParameters) {
+  const ODPI odpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  MLabel a, b;
+  Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
+  m.Branch(m.Projection(1, n), &a, &b);
+  m.Bind(&a);
+  m.Return(m.Int32Constant(0));
+  m.Bind(&b);
+  m.Return(m.Projection(0, n));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(4U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kOverflow, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorODPITest, BranchWithImmediate) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
+    m.Branch(m.Projection(1, n), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(0));
+    m.Bind(&b);
+    m.Return(m.Projection(0, n));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    Node* n = (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0));
+    m.Branch(m.Projection(1, n), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(0));
+    m.Bind(&b);
+    m.Return(m.Projection(0, n));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, BranchIfZeroWithParameters) {
+  const ODPI odpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  MLabel a, b;
+  Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
+  m.Branch(m.Word32Equal(m.Projection(1, n), m.Int32Constant(0)), &a, &b);
+  m.Bind(&a);
+  m.Return(m.Projection(0, n));
+  m.Bind(&b);
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(4U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kNotOverflow, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorODPITest, BranchIfNotZeroWithParameters) {
+  const ODPI odpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  MLabel a, b;
+  Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
+  m.Branch(m.Word32NotEqual(m.Projection(1, n), m.Int32Constant(0)), &a, &b);
+  m.Bind(&a);
+  m.Return(m.Projection(0, n));
+  m.Bind(&b);
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(4U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kOverflow, s[0]->flags_condition());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorODPITest,
+                        ::testing::ValuesIn(kODPIs));
+
+
+// -----------------------------------------------------------------------------
+// Shifts.
+
+
+typedef InstructionSelectorTestWithParam<Shift> InstructionSelectorShiftTest;
+
+
+TEST_P(InstructionSelectorShiftTest, Parameters) {
+  const Shift shift = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return((m.*shift.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmMov, s[0]->arch_opcode());
+  EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Immediate) {
+  const Shift shift = GetParam();
+  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return((m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmMov, s[0]->arch_opcode());
+    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32EqualWithParameter) {
+  const Shift shift = GetParam();
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(
+        m.Word32Equal(m.Parameter(0),
+                      (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(
+        m.Word32Equal((m.*shift.constructor)(m.Parameter(1), m.Parameter(2)),
+                      m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32EqualWithParameterAndImmediate) {
+  const Shift shift = GetParam();
+  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(
+        (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)),
+        m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(
+        m.Parameter(0),
+        (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32EqualToZeroWithParameters) {
+  const Shift shift = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(
+      m.Word32Equal(m.Int32Constant(0),
+                    (m.*shift.constructor)(m.Parameter(0), m.Parameter(1))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmMov, s[0]->arch_opcode());
+  EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(2U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kEqual, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32EqualToZeroWithImmediate) {
+  const Shift shift = GetParam();
+  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(
+        m.Int32Constant(0),
+        (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmMov, s[0]->arch_opcode());
+    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(2U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32NotWithParameters) {
+  const Shift shift = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Word32Not((m.*shift.constructor)(m.Parameter(0), m.Parameter(1))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmMvn, s[0]->arch_opcode());
+  EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32NotWithImmediate) {
+  const Shift shift = GetParam();
+  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Not(
+        (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmMvn, s[0]->arch_opcode());
+    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32AndWithWord32NotWithParameters) {
+  const Shift shift = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Word32And(m.Parameter(0), m.Word32Not((m.*shift.constructor)(
+                                           m.Parameter(1), m.Parameter(2)))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmBic, s[0]->arch_opcode());
+  EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+  EXPECT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32AndWithWord32NotWithImmediate) {
+  const Shift shift = GetParam();
+  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Word32And(m.Parameter(0),
+                         m.Word32Not((m.*shift.constructor)(
+                             m.Parameter(1), m.Int32Constant(imm)))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmBic, s[0]->arch_opcode());
+    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
+                        ::testing::ValuesIn(kShifts));
+
+
+// -----------------------------------------------------------------------------
+// Memory access instructions.
+
+
+namespace {
+
+struct MemoryAccess {
+  MachineType type;
+  ArchOpcode ldr_opcode;
+  ArchOpcode str_opcode;
+  bool (InstructionSelectorTest::Stream::*val_predicate)(
+      const InstructionOperand*) const;
+  const int32_t immediates[40];
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
+  return os << memacc.type;
+}
+
+
+static const MemoryAccess kMemoryAccesses[] = {
+    {kMachInt8,
+     kArmLdrsb,
+     kArmStrb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachUint8,
+     kArmLdrb,
+     kArmStrb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3914, -3536, -3234, -3185, -3169, -1073, -990, -859, -720, -434,
+      -127, -124, -122, -105, -91, -86, -64, -55, -53, -30, -10, -3, 0, 20, 28,
+      39, 58, 64, 73, 75, 100, 108, 121, 686, 963, 1363, 2759, 3449, 4095}},
+    {kMachInt16,
+     kArmLdrsh,
+     kArmStrh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-255, -251, -232, -220, -144, -138, -130, -126, -116, -115, -102, -101,
+      -98, -69, -59, -56, -39, -35, -23, -19, -7, 0, 22, 26, 37, 68, 83, 87, 98,
+      102, 108, 111, 117, 171, 195, 203, 204, 245, 246, 255}},
+    {kMachUint16,
+     kArmLdrh,
+     kArmStrh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-255, -230, -201, -172, -125, -119, -118, -105, -98, -79, -54, -42, -41,
+      -32, -12, -11, -5, -4, 0, 5, 9, 25, 28, 51, 58, 60, 89, 104, 108, 109,
+      114, 116, 120, 138, 150, 161, 166, 172, 228, 255}},
+    {kMachInt32,
+     kArmLdr,
+     kArmStr,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -1898, -1685, -1562, -1408, -1313, -344, -128, -116, -100, -92,
+      -80, -72, -71, -56, -25, -21, -11, -9, 0, 3, 5, 27, 28, 42, 52, 63, 88,
+      93, 97, 125, 846, 1037, 2102, 2403, 2597, 2632, 2997, 3935, 4095}},
+    {kMachFloat32,
+     kArmVldrF32,
+     kArmVstrF32,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-1020, -928, -896, -772, -728, -680, -660, -488, -372, -112, -100, -92,
+      -84, -80, -72, -64, -60, -56, -52, -48, -36, -32, -20, -8, -4, 0, 8, 20,
+      24, 40, 64, 112, 204, 388, 516, 852, 856, 976, 988, 1020}},
+    {kMachFloat64,
+     kArmVldrF64,
+     kArmVstrF64,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-1020, -948, -796, -696, -612, -364, -320, -308, -128, -112, -108, -104,
+      -96, -84, -80, -56, -48, -40, -20, 0, 24, 28, 36, 48, 64, 84, 96, 100,
+      108, 116, 120, 140, 156, 408, 432, 444, 772, 832, 940, 1020}}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccess>
+    InstructionSelectorMemoryAccessTest;
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
+  m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Offset_RR, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output()));
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Offset_RI, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output()));
+  }
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
+  m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Offset_RR, s[0]->addressing_mode());
+  EXPECT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(0U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
+    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
+            m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Offset_RI, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(0U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessTest,
+                        ::testing::ValuesIn(kMemoryAccesses));
+
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+
+TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat32);
+  m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVcvtF64F32, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) {
+  StreamBuilder m(this, kMachFloat32, kMachFloat64);
+  m.Return(m.TruncateFloat64ToFloat32(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVcvtF32F64, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+// -----------------------------------------------------------------------------
+// Comparisons.
+
+
+namespace {
+
+struct Comparison {
+  Constructor constructor;
+  const char* constructor_name;
+  FlagsCondition flags_condition;
+  FlagsCondition negated_flags_condition;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const Comparison& cmp) {
+  return os << cmp.constructor_name;
+}
+
+
+const Comparison kComparisons[] = {
+    {&RawMachineAssembler::Word32Equal, "Word32Equal", kEqual, kNotEqual},
+    {&RawMachineAssembler::Int32LessThan, "Int32LessThan", kSignedLessThan,
+     kSignedGreaterThanOrEqual},
+    {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
+     kSignedLessThanOrEqual, kSignedGreaterThan},
+    {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kUnsignedLessThan,
+     kUnsignedGreaterThanOrEqual},
+    {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
+     kUnsignedLessThanOrEqual, kUnsignedGreaterThan}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<Comparison>
+    InstructionSelectorComparisonTest;
+
+
+TEST_P(InstructionSelectorComparisonTest, Parameters) {
+  const Comparison& cmp = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const r = (m.*cmp.constructor)(p0, p1);
+  m.Return(r);
+  Stream const s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->OutputAt(0)));
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorComparisonTest, Word32EqualWithZero) {
+  {
+    const Comparison& cmp = GetParam();
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r =
+        m.Word32Equal((m.*cmp.constructor)(p0, p1), m.Int32Constant(0));
+    m.Return(r);
+    Stream const s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->OutputAt(0)));
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(cmp.negated_flags_condition, s[0]->flags_condition());
+  }
+  {
+    const Comparison& cmp = GetParam();
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r =
+        m.Word32Equal(m.Int32Constant(0), (m.*cmp.constructor)(p0, p1));
+    m.Return(r);
+    Stream const s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->OutputAt(0)));
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(cmp.negated_flags_condition, s[0]->flags_condition());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorComparisonTest,
+                        ::testing::ValuesIn(kComparisons));
+
+
+// -----------------------------------------------------------------------------
+// Miscellaneous.
+
+
+TEST_F(InstructionSelectorTest, Float64SubWithMinusZero) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat64);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float64Sub(m.Float64Constant(-0.0), p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVnegF64, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddWithInt32Mul) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Int32Add(p0, m.Int32Mul(p1, p2));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmMla, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Int32Add(m.Int32Mul(p1, p2), p0);
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmMla, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddWithInt32MulHigh) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Int32Add(p0, m.Int32MulHigh(p1, p2));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSmmla, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Int32Add(m.Int32MulHigh(p1, p2), p0);
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSmmla, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddWithWord32And) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(m.Word32And(p0, m.Int32Constant(0xff)), p1);
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUxtab, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(p1, m.Word32And(p0, m.Int32Constant(0xff)));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUxtab, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(m.Word32And(p0, m.Int32Constant(0xffff)), p1);
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUxtah, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(p1, m.Word32And(p0, m.Int32Constant(0xffff)));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUxtah, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddWithWord32SarWithWord32Shl) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24)),
+        p1);
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSxtab, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(
+        p1,
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24)));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSxtab, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16)),
+        p1);
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSxtah, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(
+        p1,
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16)));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSxtah, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32SubWithInt32Mul) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(
+      m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArmMul, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArmSub, s[1]->arch_opcode());
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32SubWithInt32MulForMLS) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(
+      m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
+  Stream s = m.Build(MLS);
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmMls, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(3U, s[0]->InputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32DivWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(4U, s.size());
+  EXPECT_EQ(kArmVcvtF64S32, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArmVcvtF64S32, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
+  ASSERT_EQ(2U, s[2]->InputCount());
+  ASSERT_EQ(1U, s[2]->OutputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
+  EXPECT_EQ(kArmVcvtS32F64, s[3]->arch_opcode());
+  ASSERT_EQ(1U, s[3]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32DivWithParametersForSUDIV) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build(SUDIV);
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmSdiv, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32ModWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(6U, s.size());
+  EXPECT_EQ(kArmVcvtF64S32, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArmVcvtF64S32, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
+  ASSERT_EQ(2U, s[2]->InputCount());
+  ASSERT_EQ(1U, s[2]->OutputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
+  EXPECT_EQ(kArmVcvtS32F64, s[3]->arch_opcode());
+  ASSERT_EQ(1U, s[3]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
+  EXPECT_EQ(kArmMul, s[4]->arch_opcode());
+  ASSERT_EQ(1U, s[4]->OutputCount());
+  ASSERT_EQ(2U, s[4]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[3]->Output()), s.ToVreg(s[4]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->InputAt(0)), s.ToVreg(s[4]->InputAt(1)));
+  EXPECT_EQ(kArmSub, s[5]->arch_opcode());
+  ASSERT_EQ(1U, s[5]->OutputCount());
+  ASSERT_EQ(2U, s[5]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[5]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[4]->Output()), s.ToVreg(s[5]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32ModWithParametersForSUDIV) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build(SUDIV);
+  ASSERT_EQ(3U, s.size());
+  EXPECT_EQ(kArmSdiv, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(kArmMul, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
+  EXPECT_EQ(kArmSub, s[2]->arch_opcode());
+  ASSERT_EQ(1U, s[2]->OutputCount());
+  ASSERT_EQ(2U, s[2]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[2]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32ModWithParametersForSUDIVAndMLS) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build(MLS, SUDIV);
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArmSdiv, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(kArmMls, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  ASSERT_EQ(3U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[1]->InputAt(2)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32MulWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Mul(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmMul, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32MulWithImmediate) {
+  // x * (2^k + 1) -> x + (x >> k)
+  TRACED_FORRANGE(int32_t, k, 1, 30) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) + 1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmAdd, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  // x * (2^k - 1) -> -x + (x >> k)
+  TRACED_FORRANGE(int32_t, k, 3, 30) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) - 1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmRsb, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  // (2^k + 1) * x -> x + (x >> k)
+  TRACED_FORRANGE(int32_t, k, 1, 30) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmAdd, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  // x * (2^k - 1) -> -x + (x >> k)
+  TRACED_FORRANGE(int32_t, k, 3, 30) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Int32Mul(m.Int32Constant((1 << k) - 1), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmRsb, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Int32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmSmmul, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32MulHighWithParameters) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Uint32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmUmull, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(2U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->OutputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32DivWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Uint32Div(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(4U, s.size());
+  EXPECT_EQ(kArmVcvtF64U32, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArmVcvtF64U32, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
+  ASSERT_EQ(2U, s[2]->InputCount());
+  ASSERT_EQ(1U, s[2]->OutputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
+  EXPECT_EQ(kArmVcvtU32F64, s[3]->arch_opcode());
+  ASSERT_EQ(1U, s[3]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32DivWithParametersForSUDIV) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Uint32Div(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build(SUDIV);
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmUdiv, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32ModWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Uint32Mod(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(6U, s.size());
+  EXPECT_EQ(kArmVcvtF64U32, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArmVcvtF64U32, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
+  ASSERT_EQ(2U, s[2]->InputCount());
+  ASSERT_EQ(1U, s[2]->OutputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
+  EXPECT_EQ(kArmVcvtU32F64, s[3]->arch_opcode());
+  ASSERT_EQ(1U, s[3]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
+  EXPECT_EQ(kArmMul, s[4]->arch_opcode());
+  ASSERT_EQ(1U, s[4]->OutputCount());
+  ASSERT_EQ(2U, s[4]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[3]->Output()), s.ToVreg(s[4]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->InputAt(0)), s.ToVreg(s[4]->InputAt(1)));
+  EXPECT_EQ(kArmSub, s[5]->arch_opcode());
+  ASSERT_EQ(1U, s[5]->OutputCount());
+  ASSERT_EQ(2U, s[5]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[5]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[4]->Output()), s.ToVreg(s[5]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32ModWithParametersForSUDIV) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Uint32Mod(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build(SUDIV);
+  ASSERT_EQ(3U, s.size());
+  EXPECT_EQ(kArmUdiv, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(kArmMul, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
+  EXPECT_EQ(kArmSub, s[2]->arch_opcode());
+  ASSERT_EQ(1U, s[2]->OutputCount());
+  ASSERT_EQ(2U, s[2]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[2]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32ModWithParametersForSUDIVAndMLS) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Uint32Mod(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build(MLS, SUDIV);
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArmUdiv, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(kArmMls, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  ASSERT_EQ(3U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[1]->InputAt(2)));
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndWithUbfxImmediateForARMv7) {
+  TRACED_FORRANGE(int32_t, width, 1, 32) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32And(m.Parameter(0),
+                         m.Int32Constant(0xffffffffu >> (32 - width))));
+    Stream s = m.Build(ARMv7);
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+  }
+  TRACED_FORRANGE(int32_t, width, 1, 32) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)),
+                         m.Parameter(0)));
+    Stream s = m.Build(ARMv7);
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndWithBfcImmediateForARMv7) {
+  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
+    TRACED_FORRANGE(int32_t, width, 9, (32 - lsb) - 1) {
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32And(
+          m.Parameter(0),
+          m.Int32Constant(~((0xffffffffu >> (32 - width)) << lsb))));
+      Stream s = m.Build(ARMv7);
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArmBfc, s[0]->arch_opcode());
+      ASSERT_EQ(1U, s[0]->OutputCount());
+      EXPECT_TRUE(
+          UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
+    TRACED_FORRANGE(int32_t, width, 9, (32 - lsb) - 1) {
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(
+          m.Word32And(m.Int32Constant(~((0xffffffffu >> (32 - width)) << lsb)),
+                      m.Parameter(0)));
+      Stream s = m.Build(ARMv7);
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArmBfc, s[0]->arch_opcode());
+      ASSERT_EQ(1U, s[0]->OutputCount());
+      EXPECT_TRUE(
+          UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndWith0xffff) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const r = m.Word32And(p0, m.Int32Constant(0xffff));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUxth, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const r = m.Word32And(m.Int32Constant(0xffff), p0);
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUxth, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const r =
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSxtb, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const r =
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSxth, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediateForARMv7) {
+  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
+      uint32_t max = 1 << lsb;
+      if (max > static_cast<uint32_t>(kMaxInt)) max -= 1;
+      uint32_t jnk = rng()->NextInt(max);
+      uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)),
+                           m.Int32Constant(lsb)));
+      Stream s = m.Build(ARMv7);
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
+      uint32_t max = 1 << lsb;
+      if (max > static_cast<uint32_t>(kMaxInt)) max -= 1;
+      uint32_t jnk = rng()->NextInt(max);
+      uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)),
+                           m.Int32Constant(lsb)));
+      Stream s = m.Build(ARMv7);
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndWithWord32Not) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Word32And(m.Parameter(0), m.Word32Not(m.Parameter(1))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmBic, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Word32And(m.Word32Not(m.Parameter(0)), m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmBic, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32EqualWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Word32Equal(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kEqual, s[0]->flags_condition());
+}
+
+
+TEST_F(InstructionSelectorTest, Word32EqualWithImmediate) {
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    if (imm == 0) continue;
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    if (imm == 0) continue;
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Int32Constant(imm), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmTst, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmTst, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32NotWithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  m.Return(m.Word32Not(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmMvn, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrWithImmediateForARMv7) {
+  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)),
+                           m.Int32Constant(0xffffffffu >> (32 - width))));
+      Stream s = m.Build(ARMv7);
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)),
+                           m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb))));
+      Stream s = m.Build(ARMv7);
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc b/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
new file mode 100644
index 0000000..cd3ce09
--- /dev/null
+++ b/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
@@ -0,0 +1,2176 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/compiler/instruction-selector-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+typedef RawMachineAssembler::Label MLabel;
+
+template <typename T>
+struct MachInst {
+  T constructor;
+  const char* constructor_name;
+  ArchOpcode arch_opcode;
+  MachineType machine_type;
+};
+
+typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1;
+typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2;
+
+
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) {
+  return os << mi.constructor_name;
+}
+
+
+struct Shift {
+  MachInst2 mi;
+  AddressingMode mode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const Shift& shift) {
+  return os << shift.mi;
+}
+
+
+// Helper to build Int32Constant or Int64Constant depending on the given
+// machine type.
+Node* BuildConstant(InstructionSelectorTest::StreamBuilder& m, MachineType type,
+                    int64_t value) {
+  switch (type) {
+    case kMachInt32:
+      return m.Int32Constant(value);
+      break;
+
+    case kMachInt64:
+      return m.Int64Constant(value);
+      break;
+
+    default:
+      UNIMPLEMENTED();
+  }
+  return NULL;
+}
+
+
+// ARM64 logical instructions.
+static const MachInst2 kLogicalInstructions[] = {
+    {&RawMachineAssembler::Word32And, "Word32And", kArm64And32, kMachInt32},
+    {&RawMachineAssembler::Word64And, "Word64And", kArm64And, kMachInt64},
+    {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Or32, kMachInt32},
+    {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Or, kMachInt64},
+    {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eor32, kMachInt32},
+    {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eor, kMachInt64}};
+
+
+// ARM64 logical immediates: contiguous set bits, rotated about a power of two
+// sized block. The block is then duplicated across the word. Below is a random
+// subset of the 32-bit immediates.
+static const uint32_t kLogical32Immediates[] = {
+    0x00000002, 0x00000003, 0x00000070, 0x00000080, 0x00000100, 0x000001c0,
+    0x00000300, 0x000007e0, 0x00003ffc, 0x00007fc0, 0x0003c000, 0x0003f000,
+    0x0003ffc0, 0x0003fff8, 0x0007ff00, 0x0007ffe0, 0x000e0000, 0x001e0000,
+    0x001ffffc, 0x003f0000, 0x003f8000, 0x00780000, 0x007fc000, 0x00ff0000,
+    0x01800000, 0x01800180, 0x01f801f8, 0x03fe0000, 0x03ffffc0, 0x03fffffc,
+    0x06000000, 0x07fc0000, 0x07ffc000, 0x07ffffc0, 0x07ffffe0, 0x0ffe0ffe,
+    0x0ffff800, 0x0ffffff0, 0x0fffffff, 0x18001800, 0x1f001f00, 0x1f801f80,
+    0x30303030, 0x3ff03ff0, 0x3ff83ff8, 0x3fff0000, 0x3fff8000, 0x3fffffc0,
+    0x70007000, 0x7f7f7f7f, 0x7fc00000, 0x7fffffc0, 0x8000001f, 0x800001ff,
+    0x81818181, 0x9fff9fff, 0xc00007ff, 0xc0ffffff, 0xdddddddd, 0xe00001ff,
+    0xe00003ff, 0xe007ffff, 0xefffefff, 0xf000003f, 0xf001f001, 0xf3fff3ff,
+    0xf800001f, 0xf80fffff, 0xf87ff87f, 0xfbfbfbfb, 0xfc00001f, 0xfc0000ff,
+    0xfc0001ff, 0xfc03fc03, 0xfe0001ff, 0xff000001, 0xff03ff03, 0xff800000,
+    0xff800fff, 0xff801fff, 0xff87ffff, 0xffc0003f, 0xffc007ff, 0xffcfffcf,
+    0xffe00003, 0xffe1ffff, 0xfff0001f, 0xfff07fff, 0xfff80007, 0xfff87fff,
+    0xfffc00ff, 0xfffe07ff, 0xffff00ff, 0xffffc001, 0xfffff007, 0xfffff3ff,
+    0xfffff807, 0xfffff9ff, 0xfffffc0f, 0xfffffeff};
+
+
+// Random subset of 64-bit logical immediates.
+static const uint64_t kLogical64Immediates[] = {
+    0x0000000000000001, 0x0000000000000002, 0x0000000000000003,
+    0x0000000000000070, 0x0000000000000080, 0x0000000000000100,
+    0x00000000000001c0, 0x0000000000000300, 0x0000000000000600,
+    0x00000000000007e0, 0x0000000000003ffc, 0x0000000000007fc0,
+    0x0000000600000000, 0x0000003ffffffffc, 0x000000f000000000,
+    0x000001f800000000, 0x0003fc0000000000, 0x0003fc000003fc00,
+    0x0003ffffffc00000, 0x0003ffffffffffc0, 0x0006000000060000,
+    0x003ffffffffc0000, 0x0180018001800180, 0x01f801f801f801f8,
+    0x0600000000000000, 0x1000000010000000, 0x1000100010001000,
+    0x1010101010101010, 0x1111111111111111, 0x1f001f001f001f00,
+    0x1f1f1f1f1f1f1f1f, 0x1ffffffffffffffe, 0x3ffc3ffc3ffc3ffc,
+    0x5555555555555555, 0x7f7f7f7f7f7f7f7f, 0x8000000000000000,
+    0x8000001f8000001f, 0x8181818181818181, 0x9999999999999999,
+    0x9fff9fff9fff9fff, 0xaaaaaaaaaaaaaaaa, 0xdddddddddddddddd,
+    0xe0000000000001ff, 0xf800000000000000, 0xf8000000000001ff,
+    0xf807f807f807f807, 0xfefefefefefefefe, 0xfffefffefffefffe,
+    0xfffff807fffff807, 0xfffff9fffffff9ff, 0xfffffc0ffffffc0f,
+    0xfffffc0fffffffff, 0xfffffefffffffeff, 0xfffffeffffffffff,
+    0xffffff8000000000, 0xfffffffefffffffe, 0xffffffffefffffff,
+    0xfffffffff9ffffff, 0xffffffffff800000, 0xffffffffffffc0ff,
+    0xfffffffffffffffe};
+
+
+// ARM64 arithmetic instructions.
+struct AddSub {
+  MachInst2 mi;
+  ArchOpcode negate_arch_opcode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const AddSub& op) {
+  return os << op.mi;
+}
+
+
+static const AddSub kAddSubInstructions[] = {
+    {{&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32, kMachInt32},
+     kArm64Sub32},
+    {{&RawMachineAssembler::Int64Add, "Int64Add", kArm64Add, kMachInt64},
+     kArm64Sub},
+    {{&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32, kMachInt32},
+     kArm64Add32},
+    {{&RawMachineAssembler::Int64Sub, "Int64Sub", kArm64Sub, kMachInt64},
+     kArm64Add}};
+
+
+// ARM64 Add/Sub immediates: 12-bit immediate optionally shifted by 12.
+// Below is a combination of a random subset and some edge values.
+static const int32_t kAddSubImmediates[] = {
+    0,        1,        69,       493,      599,      701,      719,
+    768,      818,      842,      945,      1246,     1286,     1429,
+    1669,     2171,     2179,     2182,     2254,     2334,     2338,
+    2343,     2396,     2449,     2610,     2732,     2855,     2876,
+    2944,     3377,     3458,     3475,     3476,     3540,     3574,
+    3601,     3813,     3871,     3917,     4095,     4096,     16384,
+    364544,   462848,   970752,   1523712,  1863680,  2363392,  3219456,
+    3280896,  4247552,  4526080,  4575232,  4960256,  5505024,  5894144,
+    6004736,  6193152,  6385664,  6795264,  7114752,  7233536,  7348224,
+    7499776,  7573504,  7729152,  8634368,  8937472,  9465856,  10354688,
+    10682368, 11059200, 11460608, 13168640, 13176832, 14336000, 15028224,
+    15597568, 15892480, 16773120};
+
+
+// ARM64 flag setting data processing instructions.
+static const MachInst2 kDPFlagSetInstructions[] = {
+    {&RawMachineAssembler::Word32And, "Word32And", kArm64Tst32, kMachInt32},
+    {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Cmn32, kMachInt32},
+    {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Cmp32, kMachInt32},
+    {&RawMachineAssembler::Word64And, "Word64And", kArm64Tst, kMachInt64}};
+
+
+// ARM64 arithmetic with overflow instructions.
+static const MachInst2 kOvfAddSubInstructions[] = {
+    {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
+     kArm64Add32, kMachInt32},
+    {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow",
+     kArm64Sub32, kMachInt32}};
+
+
+// ARM64 shift instructions.
+static const Shift kShiftInstructions[] = {
+    {{&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Lsl32, kMachInt32},
+     kMode_Operand2_R_LSL_I},
+    {{&RawMachineAssembler::Word64Shl, "Word64Shl", kArm64Lsl, kMachInt64},
+     kMode_Operand2_R_LSL_I},
+    {{&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Lsr32, kMachInt32},
+     kMode_Operand2_R_LSR_I},
+    {{&RawMachineAssembler::Word64Shr, "Word64Shr", kArm64Lsr, kMachInt64},
+     kMode_Operand2_R_LSR_I},
+    {{&RawMachineAssembler::Word32Sar, "Word32Sar", kArm64Asr32, kMachInt32},
+     kMode_Operand2_R_ASR_I},
+    {{&RawMachineAssembler::Word64Sar, "Word64Sar", kArm64Asr, kMachInt64},
+     kMode_Operand2_R_ASR_I},
+    {{&RawMachineAssembler::Word32Ror, "Word32Ror", kArm64Ror32, kMachInt32},
+     kMode_Operand2_R_ROR_I},
+    {{&RawMachineAssembler::Word64Ror, "Word64Ror", kArm64Ror, kMachInt64},
+     kMode_Operand2_R_ROR_I}};
+
+
+// ARM64 Mul/Div instructions.
+static const MachInst2 kMulDivInstructions[] = {
+    {&RawMachineAssembler::Int32Mul, "Int32Mul", kArm64Mul32, kMachInt32},
+    {&RawMachineAssembler::Int64Mul, "Int64Mul", kArm64Mul, kMachInt64},
+    {&RawMachineAssembler::Int32Div, "Int32Div", kArm64Idiv32, kMachInt32},
+    {&RawMachineAssembler::Int64Div, "Int64Div", kArm64Idiv, kMachInt64},
+    {&RawMachineAssembler::Uint32Div, "Uint32Div", kArm64Udiv32, kMachInt32},
+    {&RawMachineAssembler::Uint64Div, "Uint64Div", kArm64Udiv, kMachInt64}};
+
+
+// ARM64 FP arithmetic instructions.
+static const MachInst2 kFPArithInstructions[] = {
+    {&RawMachineAssembler::Float64Add, "Float64Add", kArm64Float64Add,
+     kMachFloat64},
+    {&RawMachineAssembler::Float64Sub, "Float64Sub", kArm64Float64Sub,
+     kMachFloat64},
+    {&RawMachineAssembler::Float64Mul, "Float64Mul", kArm64Float64Mul,
+     kMachFloat64},
+    {&RawMachineAssembler::Float64Div, "Float64Div", kArm64Float64Div,
+     kMachFloat64}};
+
+
+struct FPCmp {
+  MachInst2 mi;
+  FlagsCondition cond;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const FPCmp& cmp) {
+  return os << cmp.mi;
+}
+
+
+// ARM64 FP comparison instructions.
+static const FPCmp kFPCmpInstructions[] = {
+    {{&RawMachineAssembler::Float64Equal, "Float64Equal", kArm64Float64Cmp,
+      kMachFloat64},
+     kUnorderedEqual},
+    {{&RawMachineAssembler::Float64LessThan, "Float64LessThan",
+      kArm64Float64Cmp, kMachFloat64},
+     kUnorderedLessThan},
+    {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
+      kArm64Float64Cmp, kMachFloat64},
+     kUnorderedLessThanOrEqual}};
+
+
+struct Conversion {
+  // The machine_type field in MachInst1 represents the destination type.
+  MachInst1 mi;
+  MachineType src_machine_type;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const Conversion& conv) {
+  return os << conv.mi;
+}
+
+
+// ARM64 type conversion instructions.
+static const Conversion kConversionInstructions[] = {
+    {{&RawMachineAssembler::ChangeFloat32ToFloat64, "ChangeFloat32ToFloat64",
+      kArm64Float32ToFloat64, kMachFloat64},
+     kMachFloat32},
+    {{&RawMachineAssembler::TruncateFloat64ToFloat32,
+      "TruncateFloat64ToFloat32", kArm64Float64ToFloat32, kMachFloat32},
+     kMachFloat64},
+    {{&RawMachineAssembler::ChangeInt32ToInt64, "ChangeInt32ToInt64",
+      kArm64Sxtw, kMachInt64},
+     kMachInt32},
+    {{&RawMachineAssembler::ChangeUint32ToUint64, "ChangeUint32ToUint64",
+      kArm64Mov32, kMachUint64},
+     kMachUint32},
+    {{&RawMachineAssembler::TruncateInt64ToInt32, "TruncateInt64ToInt32",
+      kArm64Mov32, kMachInt32},
+     kMachInt64},
+    {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
+      kArm64Int32ToFloat64, kMachFloat64},
+     kMachInt32},
+    {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
+      kArm64Uint32ToFloat64, kMachFloat64},
+     kMachUint32},
+    {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
+      kArm64Float64ToInt32, kMachInt32},
+     kMachFloat64},
+    {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
+      kArm64Float64ToUint32, kMachUint32},
+     kMachFloat64}};
+
+}  // namespace
+
+
+// -----------------------------------------------------------------------------
+// Logical instructions.
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorLogicalTest;
+
+
+TEST_P(InstructionSelectorLogicalTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorLogicalTest, Immediate) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  // TODO(all): Add support for testing 64-bit immediates.
+  if (type == kMachInt32) {
+    // Immediate on the right.
+    TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
+      StreamBuilder m(this, type, type);
+      m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+      ASSERT_EQ(2U, s[0]->InputCount());
+      EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+
+    // Immediate on the left; all logical ops should commute.
+    TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
+      StreamBuilder m(this, type, type);
+      m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+      ASSERT_EQ(2U, s[0]->InputCount());
+      EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+}
+
+
+TEST_P(InstructionSelectorLogicalTest, ShiftByImmediate) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  TRACED_FOREACH(Shift, shift, kShiftInstructions) {
+    // Only test 64-bit shifted operands with 64-bit instructions.
+    if (shift.mi.machine_type != type) continue;
+
+    TRACED_FORRANGE(int, imm, 0, ((type == kMachInt32) ? 31 : 63)) {
+      StreamBuilder m(this, type, type, type);
+      m.Return((m.*dpi.constructor)(
+          m.Parameter(0),
+          (m.*shift.mi.constructor)(m.Parameter(1),
+                                    BuildConstant(m, type, imm))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.mode, s[0]->addressing_mode());
+      EXPECT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+
+    TRACED_FORRANGE(int, imm, 0, ((type == kMachInt32) ? 31 : 63)) {
+      StreamBuilder m(this, type, type, type);
+      m.Return((m.*dpi.constructor)(
+          (m.*shift.mi.constructor)(m.Parameter(1),
+                                    BuildConstant(m, type, imm)),
+          m.Parameter(0)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.mode, s[0]->addressing_mode());
+      EXPECT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest,
+                        ::testing::ValuesIn(kLogicalInstructions));
+
+
+// -----------------------------------------------------------------------------
+// Add and Sub instructions.
+
+typedef InstructionSelectorTestWithParam<AddSub> InstructionSelectorAddSubTest;
+
+
+TEST_P(InstructionSelectorAddSubTest, Parameter) {
+  const AddSub dpi = GetParam();
+  const MachineType type = dpi.mi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.mi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorAddSubTest, ImmediateOnRight) {
+  const AddSub dpi = GetParam();
+  const MachineType type = dpi.mi.machine_type;
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, type, type);
+    m.Return(
+        (m.*dpi.mi.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+    EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorAddSubTest, NegImmediateOnRight) {
+  const AddSub dpi = GetParam();
+  const MachineType type = dpi.mi.machine_type;
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    if (imm == 0) continue;
+    StreamBuilder m(this, type, type);
+    m.Return(
+        (m.*dpi.mi.constructor)(m.Parameter(0), BuildConstant(m, type, -imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.negate_arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorAddSubTest, ShiftByImmediateOnRight) {
+  const AddSub dpi = GetParam();
+  const MachineType type = dpi.mi.machine_type;
+  TRACED_FOREACH(Shift, shift, kShiftInstructions) {
+    // Only test 64-bit shifted operands with 64-bit instructions.
+    if (shift.mi.machine_type != type) continue;
+
+    if ((shift.mi.arch_opcode == kArm64Ror32) ||
+        (shift.mi.arch_opcode == kArm64Ror)) {
+      // Not supported by add/sub instructions.
+      continue;
+    }
+
+    TRACED_FORRANGE(int, imm, 0, ((type == kMachInt32) ? 31 : 63)) {
+      StreamBuilder m(this, type, type, type);
+      m.Return((m.*dpi.mi.constructor)(
+          m.Parameter(0),
+          (m.*shift.mi.constructor)(m.Parameter(1),
+                                    BuildConstant(m, type, imm))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.mode, s[0]->addressing_mode());
+      EXPECT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest,
+                        ::testing::ValuesIn(kAddSubInstructions));
+
+
+TEST_F(InstructionSelectorTest, AddImmediateOnLeft) {
+  {
+    // 32-bit add.
+    TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+      ASSERT_EQ(2U, s[0]->InputCount());
+      EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+  {
+    // 64-bit add.
+    TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+      StreamBuilder m(this, kMachInt64, kMachInt64);
+      m.Return(m.Int64Add(m.Int64Constant(imm), m.Parameter(0)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
+      ASSERT_EQ(2U, s[0]->InputCount());
+      EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, SubZeroOnLeft) {
+  // Subtraction with zero on the left maps to Neg.
+  {
+    // 32-bit subtract.
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Sub(m.Int32Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Neg32, s[0]->arch_opcode());
+    EXPECT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    // 64-bit subtract.
+    StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64);
+    m.Return(m.Int64Sub(m.Int64Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Neg, s[0]->arch_opcode());
+    EXPECT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, AddNegImmediateOnLeft) {
+  {
+    // 32-bit add.
+    TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+      if (imm == 0) continue;
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Int32Constant(-imm), m.Parameter(0)));
+      Stream s = m.Build();
+
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Sub32, s[0]->arch_opcode());
+      ASSERT_EQ(2U, s[0]->InputCount());
+      ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+  {
+    // 64-bit add.
+    TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+      if (imm == 0) continue;
+      StreamBuilder m(this, kMachInt64, kMachInt64);
+      m.Return(m.Int64Add(m.Int64Constant(-imm), m.Parameter(0)));
+      Stream s = m.Build();
+
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Sub, s[0]->arch_opcode());
+      ASSERT_EQ(2U, s[0]->InputCount());
+      ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate());
+      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, AddShiftByImmediateOnLeft) {
+  // 32-bit add.
+  TRACED_FOREACH(Shift, shift, kShiftInstructions) {
+    // Only test relevant shifted operands.
+    if (shift.mi.machine_type != kMachInt32) continue;
+    if (shift.mi.arch_opcode == kArm64Ror32) continue;
+
+    TRACED_FORRANGE(int, imm, 0, 31) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      m.Return((m.Int32Add)(
+          (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm)),
+          m.Parameter(0)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+      EXPECT_EQ(shift.mode, s[0]->addressing_mode());
+      EXPECT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+
+  // 64-bit add.
+  TRACED_FOREACH(Shift, shift, kShiftInstructions) {
+    // Only test relevant shifted operands.
+    if (shift.mi.machine_type != kMachInt64) continue;
+    if (shift.mi.arch_opcode == kArm64Ror) continue;
+
+    TRACED_FORRANGE(int, imm, 0, 63) {
+      StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64);
+      m.Return((m.Int64Add)(
+          (m.*shift.mi.constructor)(m.Parameter(1), m.Int64Constant(imm)),
+          m.Parameter(0)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
+      EXPECT_EQ(shift.mode, s[0]->addressing_mode());
+      EXPECT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Data processing controlled branches.
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorDPFlagSetTest;
+
+
+TEST_P(InstructionSelectorDPFlagSetTest, BranchWithParameters) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  MLabel a, b;
+  m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b);
+  m.Bind(&a);
+  m.Return(m.Int32Constant(1));
+  m.Bind(&b);
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorDPFlagSetTest,
+                        ::testing::ValuesIn(kDPFlagSetInstructions));
+
+
+TEST_F(InstructionSelectorTest, Word32AndBranchWithImmediateOnRight) {
+  TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
+    // Skip the cases where the instruction selector would use tbz/tbnz.
+    if (base::bits::CountPopulation32(imm) == 1) continue;
+
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64AndBranchWithImmediateOnRight) {
+  TRACED_FOREACH(int64_t, imm, kLogical64Immediates) {
+    // Skip the cases where the instruction selector would use tbz/tbnz.
+    if (base::bits::CountPopulation64(imm) == 1) continue;
+
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    MLabel a, b;
+    m.Branch(m.Word64And(m.Parameter(0), m.Int64Constant(imm)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnRight) {
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, SubBranchWithImmediateOnRight) {
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndBranchWithImmediateOnLeft) {
+  TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
+    // Skip the cases where the instruction selector would use tbz/tbnz.
+    if (base::bits::CountPopulation32(imm) == 1) continue;
+
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32And(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    ASSERT_LE(1U, s[0]->InputCount());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64AndBranchWithImmediateOnLeft) {
+  TRACED_FOREACH(int64_t, imm, kLogical64Immediates) {
+    // Skip the cases where the instruction selector would use tbz/tbnz.
+    if (base::bits::CountPopulation64(imm) == 1) continue;
+
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    MLabel a, b;
+    m.Branch(m.Word64And(m.Int64Constant(imm), m.Parameter(0)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    ASSERT_LE(1U, s[0]->InputCount());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnLeft) {
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
+    ASSERT_LE(1U, s[0]->InputCount());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndBranchWithOneBitMaskOnRight) {
+  TRACED_FORRANGE(int, bit, 0, 31) {
+    uint32_t mask = 1 << bit;
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(mask)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
+  }
+
+  TRACED_FORRANGE(int, bit, 0, 31) {
+    uint32_t mask = 1 << bit;
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(
+        m.Word32BinaryNot(m.Word32And(m.Parameter(0), m.Int32Constant(mask))),
+        &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndBranchWithOneBitMaskOnLeft) {
+  TRACED_FORRANGE(int, bit, 0, 31) {
+    uint32_t mask = 1 << bit;
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32And(m.Int32Constant(mask), m.Parameter(0)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
+  }
+
+  TRACED_FORRANGE(int, bit, 0, 31) {
+    uint32_t mask = 1 << bit;
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(
+        m.Word32BinaryNot(m.Word32And(m.Int32Constant(mask), m.Parameter(0))),
+        &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnRight) {
+  TRACED_FORRANGE(int, bit, 0, 63) {
+    uint64_t mask = 1L << bit;
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    MLabel a, b;
+    m.Branch(m.Word64And(m.Parameter(0), m.Int64Constant(mask)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
+  }
+
+  TRACED_FORRANGE(int, bit, 0, 63) {
+    uint64_t mask = 1L << bit;
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    MLabel a, b;
+    m.Branch(
+        m.Word64BinaryNot(m.Word64And(m.Parameter(0), m.Int64Constant(mask))),
+        &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnLeft) {
+  TRACED_FORRANGE(int, bit, 0, 63) {
+    uint64_t mask = 1L << bit;
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    MLabel a, b;
+    m.Branch(m.Word64And(m.Int64Constant(mask), m.Parameter(0)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
+  }
+
+  TRACED_FORRANGE(int, bit, 0, 63) {
+    uint64_t mask = 1L << bit;
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    MLabel a, b;
+    m.Branch(
+        m.Word64BinaryNot(m.Word64And(m.Int64Constant(mask), m.Parameter(0))),
+        &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, CompareAgainstZeroAndBranch) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    Node* p0 = m.Parameter(0);
+    m.Branch(p0, &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  }
+
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    Node* p0 = m.Parameter(0);
+    m.Branch(m.Word32BinaryNot(p0), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Add and subtract instructions with overflow.
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorOvfAddSubTest;
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, OvfParameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return(
+      m.Projection(1, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_LE(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kOverflow, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, OvfImmediateOnRight) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, type, type);
+    m.Return(m.Projection(
+        1, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, ValParameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return(
+      m.Projection(0, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_LE(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+}
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, ValImmediateOnRight) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, type, type);
+    m.Return(m.Projection(
+        0, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+}
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, BothParameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
+  m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+  Stream s = m.Build();
+  ASSERT_LE(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(2U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kOverflow, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, BothImmediateOnRight) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, type, type);
+    Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
+    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+    Stream s = m.Build();
+    ASSERT_LE(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(2U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, BranchWithParameters) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  MLabel a, b;
+  Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
+  m.Branch(m.Projection(1, n), &a, &b);
+  m.Bind(&a);
+  m.Return(m.Int32Constant(0));
+  m.Bind(&b);
+  m.Return(m.Projection(0, n));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(4U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kOverflow, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, BranchWithImmediateOnRight) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, type, type);
+    MLabel a, b;
+    Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
+    m.Branch(m.Projection(1, n), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(0));
+    m.Bind(&b);
+    m.Return(m.Projection(0, n));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorOvfAddSubTest,
+                        ::testing::ValuesIn(kOvfAddSubInstructions));
+
+
+TEST_F(InstructionSelectorTest, OvfFlagAddImmediateOnLeft) {
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        1, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
+    Stream s = m.Build();
+
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, OvfValAddImmediateOnLeft) {
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        0, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
+    Stream s = m.Build();
+
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, OvfBothAddImmediateOnLeft) {
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
+    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+    Stream s = m.Build();
+
+    ASSERT_LE(1U, s.size());
+    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(2U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, OvfBranchWithImmediateOnLeft) {
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
+    m.Branch(m.Projection(1, n), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(0));
+    m.Bind(&b);
+    m.Return(m.Projection(0, n));
+    Stream s = m.Build();
+
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+    ASSERT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Shift instructions.
+
+
+typedef InstructionSelectorTestWithParam<Shift> InstructionSelectorShiftTest;
+
+
+TEST_P(InstructionSelectorShiftTest, Parameter) {
+  const Shift shift = GetParam();
+  const MachineType type = shift.mi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*shift.mi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(shift.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Immediate) {
+  const Shift shift = GetParam();
+  const MachineType type = shift.mi.machine_type;
+  TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) {
+    StreamBuilder m(this, type, type);
+    m.Return((m.*shift.mi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(shift.mi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
+                        ::testing::ValuesIn(kShiftInstructions));
+
+
+TEST_F(InstructionSelectorTest, Word64ShlWithChangeInt32ToInt64) {
+  TRACED_FORRANGE(int64_t, x, 32, 63) {
+    StreamBuilder m(this, kMachInt64, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const n = m.Word64Shl(m.ChangeInt32ToInt64(p0), m.Int64Constant(x));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Lsl, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64ShlWithChangeUint32ToUint64) {
+  TRACED_FORRANGE(int64_t, x, 32, 63) {
+    StreamBuilder m(this, kMachInt64, kMachUint32);
+    Node* const p0 = m.Parameter(0);
+    Node* const n = m.Word64Shl(m.ChangeUint32ToUint64(p0), m.Int64Constant(x));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Lsl, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Sar) {
+  StreamBuilder m(this, kMachInt32, kMachInt64);
+  Node* const p = m.Parameter(0);
+  Node* const t = m.TruncateInt64ToInt32(m.Word64Sar(p, m.Int64Constant(32)));
+  m.Return(t);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArm64Lsr, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(32, s.ToInt64(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Shr) {
+  TRACED_FORRANGE(int64_t, x, 32, 63) {
+    StreamBuilder m(this, kMachInt32, kMachInt64);
+    Node* const p = m.Parameter(0);
+    Node* const t = m.TruncateInt64ToInt32(m.Word64Shr(p, m.Int64Constant(x)));
+    m.Return(t);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Lsr, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Mul and Div instructions.
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorMulDivTest;
+
+
+TEST_P(InstructionSelectorMulDivTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest,
+                        ::testing::ValuesIn(kMulDivInstructions));
+
+
+namespace {
+
+struct MulDPInst {
+  const char* mul_constructor_name;
+  Node* (RawMachineAssembler::*mul_constructor)(Node*, Node*);
+  Node* (RawMachineAssembler::*add_constructor)(Node*, Node*);
+  Node* (RawMachineAssembler::*sub_constructor)(Node*, Node*);
+  ArchOpcode add_arch_opcode;
+  ArchOpcode sub_arch_opcode;
+  ArchOpcode neg_arch_opcode;
+  MachineType machine_type;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MulDPInst& inst) {
+  return os << inst.mul_constructor_name;
+}
+
+}  // namespace
+
+
+static const MulDPInst kMulDPInstructions[] = {
+    {"Int32Mul", &RawMachineAssembler::Int32Mul, &RawMachineAssembler::Int32Add,
+     &RawMachineAssembler::Int32Sub, kArm64Madd32, kArm64Msub32, kArm64Mneg32,
+     kMachInt32},
+    {"Int64Mul", &RawMachineAssembler::Int64Mul, &RawMachineAssembler::Int64Add,
+     &RawMachineAssembler::Int64Sub, kArm64Madd, kArm64Msub, kArm64Mneg,
+     kMachInt64}};
+
+
+typedef InstructionSelectorTestWithParam<MulDPInst>
+    InstructionSelectorIntDPWithIntMulTest;
+
+
+TEST_P(InstructionSelectorIntDPWithIntMulTest, AddWithMul) {
+  const MulDPInst mdpi = GetParam();
+  const MachineType type = mdpi.machine_type;
+  {
+    StreamBuilder m(this, type, type, type, type);
+    Node* n = (m.*mdpi.mul_constructor)(m.Parameter(1), m.Parameter(2));
+    m.Return((m.*mdpi.add_constructor)(m.Parameter(0), n));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(mdpi.add_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, type, type, type, type);
+    Node* n = (m.*mdpi.mul_constructor)(m.Parameter(0), m.Parameter(1));
+    m.Return((m.*mdpi.add_constructor)(n, m.Parameter(2)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(mdpi.add_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorIntDPWithIntMulTest, SubWithMul) {
+  const MulDPInst mdpi = GetParam();
+  const MachineType type = mdpi.machine_type;
+  {
+    StreamBuilder m(this, type, type, type, type);
+    Node* n = (m.*mdpi.mul_constructor)(m.Parameter(1), m.Parameter(2));
+    m.Return((m.*mdpi.sub_constructor)(m.Parameter(0), n));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(mdpi.sub_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorIntDPWithIntMulTest, NegativeMul) {
+  const MulDPInst mdpi = GetParam();
+  const MachineType type = mdpi.machine_type;
+  {
+    StreamBuilder m(this, type, type, type);
+    Node* n =
+        (m.*mdpi.sub_constructor)(BuildConstant(m, type, 0), m.Parameter(0));
+    m.Return((m.*mdpi.mul_constructor)(n, m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(mdpi.neg_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, type, type, type);
+    Node* n =
+        (m.*mdpi.sub_constructor)(BuildConstant(m, type, 0), m.Parameter(1));
+    m.Return((m.*mdpi.mul_constructor)(m.Parameter(0), n));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(mdpi.neg_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorIntDPWithIntMulTest,
+                        ::testing::ValuesIn(kMulDPInstructions));
+
+
+// -----------------------------------------------------------------------------
+// Floating point instructions.
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorFPArithTest;
+
+
+TEST_P(InstructionSelectorFPArithTest, Parameter) {
+  const MachInst2 fpa = GetParam();
+  StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type);
+  m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest,
+                        ::testing::ValuesIn(kFPArithInstructions));
+
+
+typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest;
+
+
+TEST_P(InstructionSelectorFPCmpTest, Parameter) {
+  const FPCmp cmp = GetParam();
+  StreamBuilder m(this, kMachInt32, cmp.mi.machine_type, cmp.mi.machine_type);
+  m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(cmp.cond, s[0]->flags_condition());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
+                        ::testing::ValuesIn(kFPCmpInstructions));
+
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+typedef InstructionSelectorTestWithParam<Conversion>
+    InstructionSelectorConversionTest;
+
+
+TEST_P(InstructionSelectorConversionTest, Parameter) {
+  const Conversion conv = GetParam();
+  StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
+  m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorConversionTest,
+                        ::testing::ValuesIn(kConversionInstructions));
+
+
+// -----------------------------------------------------------------------------
+// Memory access instructions.
+
+
+namespace {
+
+struct MemoryAccess {
+  MachineType type;
+  ArchOpcode ldr_opcode;
+  ArchOpcode str_opcode;
+  const int32_t immediates[20];
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
+  return os << memacc.type;
+}
+
+}  // namespace
+
+
+static const MemoryAccess kMemoryAccesses[] = {
+    {kMachInt8,
+     kArm64Ldrsb,
+     kArm64Strb,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, 2121,
+      2442, 4093, 4094, 4095}},
+    {kMachUint8,
+     kArm64Ldrb,
+     kArm64Strb,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, 2121,
+      2442, 4093, 4094, 4095}},
+    {kMachInt16,
+     kArm64Ldrsh,
+     kArm64Strh,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, 4100,
+      4242, 6786, 8188, 8190}},
+    {kMachUint16,
+     kArm64Ldrh,
+     kArm64Strh,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, 4100,
+      4242, 6786, 8188, 8190}},
+    {kMachInt32,
+     kArm64LdrW,
+     kArm64StrW,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196,
+      3276, 3280, 16376, 16380}},
+    {kMachUint32,
+     kArm64LdrW,
+     kArm64StrW,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196,
+      3276, 3280, 16376, 16380}},
+    {kMachInt64,
+     kArm64Ldr,
+     kArm64Str,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200,
+      16384, 16392, 32752, 32760}},
+    {kMachUint64,
+     kArm64Ldr,
+     kArm64Str,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200,
+      16384, 16392, 32752, 32760}},
+    {kMachFloat32,
+     kArm64LdrS,
+     kArm64StrS,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196,
+      3276, 3280, 16376, 16380}},
+    {kMachFloat64,
+     kArm64LdrD,
+     kArm64StrD,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200,
+      16384, 16392, 32752, 32760}}};
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccess>
+    InstructionSelectorMemoryAccessTest;
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
+  m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
+  m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
+  EXPECT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(0U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
+    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
+            m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(0U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessTest,
+                        ::testing::ValuesIn(kMemoryAccesses));
+
+
+// -----------------------------------------------------------------------------
+// Comparison instructions.
+
+static const MachInst2 kComparisonInstructions[] = {
+    {&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, kMachInt32},
+    {&RawMachineAssembler::Word64Equal, "Word64Equal", kArm64Cmp, kMachInt64},
+};
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorComparisonTest;
+
+
+TEST_P(InstructionSelectorComparisonTest, WithParameters) {
+  const MachInst2 cmp = GetParam();
+  const MachineType type = cmp.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kEqual, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorComparisonTest, WithImmediate) {
+  const MachInst2 cmp = GetParam();
+  const MachineType type = cmp.machine_type;
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    // Compare with 0 are turned into tst instruction.
+    if (imm == 0) continue;
+    StreamBuilder m(this, type, type);
+    m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    // Compare with 0 are turned into tst instruction.
+    if (imm == 0) continue;
+    StreamBuilder m(this, type, type);
+    m.Return((m.*cmp.constructor)(BuildConstant(m, type, imm), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorComparisonTest,
+                        ::testing::ValuesIn(kComparisonInstructions));
+
+
+TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64EqualWithZero) {
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    m.Return(m.Word64Equal(m.Int64Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Miscellaneous
+
+
+static const MachInst2 kLogicalWithNotRHSs[] = {
+    {&RawMachineAssembler::Word32And, "Word32And", kArm64Bic32, kMachInt32},
+    {&RawMachineAssembler::Word64And, "Word64And", kArm64Bic, kMachInt64},
+    {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Orn32, kMachInt32},
+    {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Orn, kMachInt64},
+    {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eon32, kMachInt32},
+    {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eon, kMachInt64}};
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorLogicalWithNotRHSTest;
+
+
+TEST_P(InstructionSelectorLogicalWithNotRHSTest, Parameter) {
+  const MachInst2 inst = GetParam();
+  const MachineType type = inst.machine_type;
+  // Test cases where RHS is Xor(x, -1).
+  {
+    StreamBuilder m(this, type, type, type);
+    if (type == kMachInt32) {
+      m.Return((m.*inst.constructor)(
+          m.Parameter(0), m.Word32Xor(m.Parameter(1), m.Int32Constant(-1))));
+    } else {
+      ASSERT_EQ(kMachInt64, type);
+      m.Return((m.*inst.constructor)(
+          m.Parameter(0), m.Word64Xor(m.Parameter(1), m.Int64Constant(-1))));
+    }
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, type, type, type);
+    if (type == kMachInt32) {
+      m.Return((m.*inst.constructor)(
+          m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)), m.Parameter(1)));
+    } else {
+      ASSERT_EQ(kMachInt64, type);
+      m.Return((m.*inst.constructor)(
+          m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)), m.Parameter(1)));
+    }
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  // Test cases where RHS is Not(x).
+  {
+    StreamBuilder m(this, type, type, type);
+    if (type == kMachInt32) {
+      m.Return(
+          (m.*inst.constructor)(m.Parameter(0), m.Word32Not(m.Parameter(1))));
+    } else {
+      ASSERT_EQ(kMachInt64, type);
+      m.Return(
+          (m.*inst.constructor)(m.Parameter(0), m.Word64Not(m.Parameter(1))));
+    }
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, type, type, type);
+    if (type == kMachInt32) {
+      m.Return(
+          (m.*inst.constructor)(m.Word32Not(m.Parameter(0)), m.Parameter(1)));
+    } else {
+      ASSERT_EQ(kMachInt64, type);
+      m.Return(
+          (m.*inst.constructor)(m.Word64Not(m.Parameter(0)), m.Parameter(1)));
+    }
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorLogicalWithNotRHSTest,
+                        ::testing::ValuesIn(kLogicalWithNotRHSs));
+
+
+TEST_F(InstructionSelectorTest, Word32NotWithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  m.Return(m.Word32Not(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, Word64NotWithParameter) {
+  StreamBuilder m(this, kMachInt64, kMachInt64);
+  m.Return(m.Word64Not(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, Word32XorMinusOneWithParameter) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
+    EXPECT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
+    EXPECT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64XorMinusOneWithParameter) {
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    m.Return(m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
+    EXPECT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    m.Return(m.Word64Xor(m.Int64Constant(-1), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
+    EXPECT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediate) {
+  TRACED_FORRANGE(int32_t, lsb, 1, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
+      uint32_t jnk = rng()->NextInt();
+      jnk >>= 32 - lsb;
+      uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)),
+                           m.Int32Constant(lsb)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+  TRACED_FORRANGE(int32_t, lsb, 1, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
+      uint32_t jnk = rng()->NextInt();
+      jnk >>= 32 - lsb;
+      uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)),
+                           m.Int32Constant(lsb)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64ShrWithWord64AndWithImmediate) {
+  TRACED_FORRANGE(int32_t, lsb, 1, 63) {
+    TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) {
+      uint64_t jnk = rng()->NextInt64();
+      jnk >>= 64 - lsb;
+      uint64_t msk =
+          ((V8_UINT64_C(0xffffffffffffffff) >> (64 - width)) << lsb) | jnk;
+      StreamBuilder m(this, kMachInt64, kMachInt64);
+      m.Return(m.Word64Shr(m.Word64And(m.Parameter(0), m.Int64Constant(msk)),
+                           m.Int64Constant(lsb)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2)));
+    }
+  }
+  TRACED_FORRANGE(int32_t, lsb, 1, 63) {
+    TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) {
+      uint64_t jnk = rng()->NextInt64();
+      jnk >>= 64 - lsb;
+      uint64_t msk =
+          ((V8_UINT64_C(0xffffffffffffffff) >> (64 - width)) << lsb) | jnk;
+      StreamBuilder m(this, kMachInt64, kMachInt64);
+      m.Return(m.Word64Shr(m.Word64And(m.Int64Constant(msk), m.Parameter(0)),
+                           m.Int64Constant(lsb)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2)));
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndWithImmediateWithWord32Shr) {
+  TRACED_FORRANGE(int32_t, lsb, 1, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 31) {
+      uint32_t msk = (1 << width) - 1;
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)),
+                           m.Int32Constant(msk)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width;
+      EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+  TRACED_FORRANGE(int32_t, lsb, 1, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 31) {
+      uint32_t msk = (1 << width) - 1;
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32And(m.Int32Constant(msk),
+                           m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width;
+      EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64AndWithImmediateWithWord64Shr) {
+  TRACED_FORRANGE(int64_t, lsb, 1, 63) {
+    TRACED_FORRANGE(int64_t, width, 1, 63) {
+      uint64_t msk = (V8_UINT64_C(1) << width) - 1;
+      StreamBuilder m(this, kMachInt64, kMachInt64);
+      m.Return(m.Word64And(m.Word64Shr(m.Parameter(0), m.Int64Constant(lsb)),
+                           m.Int64Constant(msk)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
+      int64_t actual_width = (lsb + width > 64) ? (64 - lsb) : width;
+      EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2)));
+    }
+  }
+  TRACED_FORRANGE(int64_t, lsb, 1, 63) {
+    TRACED_FORRANGE(int64_t, width, 1, 63) {
+      uint64_t msk = (V8_UINT64_C(1) << width) - 1;
+      StreamBuilder m(this, kMachInt64, kMachInt64);
+      m.Return(m.Word64And(m.Int64Constant(msk),
+                           m.Word64Shr(m.Parameter(0), m.Int64Constant(lsb))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
+      int64_t actual_width = (lsb + width > 64) ? (64 - lsb) : width;
+      EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2)));
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Int32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArm64Smull, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArm64Asr, s[1]->arch_opcode());
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(32, s.ToInt64(s[1]->InputAt(1)));
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[1]->Output()));
+}
+
+
+TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const r =
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Sxtb32, s[0]->arch_opcode());
+    ASSERT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const r =
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Sxth32, s[0]->arch_opcode());
+    ASSERT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/change-lowering-unittest.cc b/test/unittests/compiler/change-lowering-unittest.cc
new file mode 100644
index 0000000..060b1c1
--- /dev/null
+++ b/test/unittests/compiler/change-lowering-unittest.cc
@@ -0,0 +1,463 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/code-stubs.h"
+#include "src/compiler/change-lowering.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/linkage.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/simplified-operator.h"
+#include "test/unittests/compiler/compiler-test-utils.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::_;
+using testing::AllOf;
+using testing::BitEq;
+using testing::Capture;
+using testing::CaptureEq;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class ChangeLoweringTest : public GraphTest {
+ public:
+  ChangeLoweringTest() : simplified_(zone()) {}
+  ~ChangeLoweringTest() OVERRIDE {}
+
+  virtual MachineType WordRepresentation() const = 0;
+
+ protected:
+  int HeapNumberValueOffset() const {
+    STATIC_ASSERT(HeapNumber::kValueOffset % kApiPointerSize == 0);
+    return (HeapNumber::kValueOffset / kApiPointerSize) * PointerSize() -
+           kHeapObjectTag;
+  }
+  bool Is32() const { return WordRepresentation() == kRepWord32; }
+  int PointerSize() const {
+    switch (WordRepresentation()) {
+      case kRepWord32:
+        return 4;
+      case kRepWord64:
+        return 8;
+      default:
+        break;
+    }
+    UNREACHABLE();
+    return 0;
+  }
+  int SmiMaxValue() const { return -(SmiMinValue() + 1); }
+  int SmiMinValue() const {
+    return static_cast<int>(0xffffffffu << (SmiValueSize() - 1));
+  }
+  int SmiShiftAmount() const { return kSmiTagSize + SmiShiftSize(); }
+  int SmiShiftSize() const {
+    return Is32() ? SmiTagging<4>::SmiShiftSize()
+                  : SmiTagging<8>::SmiShiftSize();
+  }
+  int SmiValueSize() const {
+    return Is32() ? SmiTagging<4>::SmiValueSize()
+                  : SmiTagging<8>::SmiValueSize();
+  }
+
+  Reduction Reduce(Node* node) {
+    MachineOperatorBuilder machine(zone(), WordRepresentation());
+    JSOperatorBuilder javascript(zone());
+    JSGraph jsgraph(graph(), common(), &javascript, &machine);
+    CompilationInfo info(isolate(), zone());
+    Linkage linkage(zone(), &info);
+    ChangeLowering reducer(&jsgraph, &linkage);
+    return reducer.Reduce(node);
+  }
+
+  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
+
+  Matcher<Node*> IsAllocateHeapNumber(const Matcher<Node*>& effect_matcher,
+                                      const Matcher<Node*>& control_matcher) {
+    return IsCall(_, IsHeapConstant(Unique<HeapObject>::CreateImmovable(
+                         AllocateHeapNumberStub(isolate()).GetCode())),
+                  IsNumberConstant(BitEq(0.0)), effect_matcher,
+                  control_matcher);
+  }
+  Matcher<Node*> IsLoadHeapNumber(const Matcher<Node*>& value_matcher,
+                                  const Matcher<Node*>& control_matcher) {
+    return IsLoad(kMachFloat64, value_matcher,
+                  IsIntPtrConstant(HeapNumberValueOffset()), graph()->start(),
+                  control_matcher);
+  }
+  Matcher<Node*> IsIntPtrConstant(int value) {
+    return Is32() ? IsInt32Constant(value) : IsInt64Constant(value);
+  }
+  Matcher<Node*> IsWordEqual(const Matcher<Node*>& lhs_matcher,
+                             const Matcher<Node*>& rhs_matcher) {
+    return Is32() ? IsWord32Equal(lhs_matcher, rhs_matcher)
+                  : IsWord64Equal(lhs_matcher, rhs_matcher);
+  }
+
+ private:
+  SimplifiedOperatorBuilder simplified_;
+};
+
+
+// -----------------------------------------------------------------------------
+// Common.
+
+
+class ChangeLoweringCommonTest
+    : public ChangeLoweringTest,
+      public ::testing::WithParamInterface<MachineType> {
+ public:
+  ~ChangeLoweringCommonTest() OVERRIDE {}
+
+  MachineType WordRepresentation() const FINAL { return GetParam(); }
+};
+
+
+TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBitToBool) {
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeBitToBool(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(),
+              IsSelect(static_cast<MachineType>(kTypeBool | kRepTagged), val,
+                       IsTrueConstant(), IsFalseConstant()));
+}
+
+
+TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBoolToBit) {
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeBoolToBit(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  EXPECT_THAT(reduction.replacement(), IsWordEqual(val, IsTrueConstant()));
+}
+
+
+TARGET_TEST_P(ChangeLoweringCommonTest, ChangeFloat64ToTagged) {
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeFloat64ToTagged(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* finish = reduction.replacement();
+  Capture<Node*> heap_number;
+  EXPECT_THAT(
+      finish,
+      IsFinish(
+          AllOf(CaptureEq(&heap_number),
+                IsAllocateHeapNumber(IsValueEffect(val), graph()->start())),
+          IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
+                  CaptureEq(&heap_number),
+                  IsIntPtrConstant(HeapNumberValueOffset()), val,
+                  CaptureEq(&heap_number), graph()->start())));
+}
+
+
+TARGET_TEST_P(ChangeLoweringCommonTest, StringAdd) {
+  Node* node =
+      graph()->NewNode(simplified()->StringAdd(), Parameter(0), Parameter(1));
+  Reduction reduction = Reduce(node);
+  EXPECT_FALSE(reduction.Changed());
+}
+
+
+INSTANTIATE_TEST_CASE_P(ChangeLoweringTest, ChangeLoweringCommonTest,
+                        ::testing::Values(kRepWord32, kRepWord64));
+
+
+// -----------------------------------------------------------------------------
+// 32-bit
+
+
+class ChangeLowering32Test : public ChangeLoweringTest {
+ public:
+  ~ChangeLowering32Test() OVERRIDE {}
+  MachineType WordRepresentation() const FINAL { return kRepWord32; }
+};
+
+
+TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) {
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
+  NodeProperties::SetBounds(val, Bounds(Type::None(), Type::Signed32()));
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> add, branch, heap_number, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(kMachAnyTagged,
+            IsFinish(AllOf(CaptureEq(&heap_number),
+                           IsAllocateHeapNumber(_, CaptureEq(&if_true))),
+                     IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
+                             CaptureEq(&heap_number),
+                             IsIntPtrConstant(HeapNumberValueOffset()),
+                             IsChangeInt32ToFloat64(val),
+                             CaptureEq(&heap_number), CaptureEq(&if_true))),
+            IsProjection(
+                0, AllOf(CaptureEq(&add), IsInt32AddWithOverflow(val, val))),
+            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                    IsIfFalse(AllOf(CaptureEq(&branch),
+                                    IsBranch(IsProjection(1, CaptureEq(&add)),
+                                             graph()->start()))))));
+}
+
+
+TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTaggedSmall) {
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
+  NodeProperties::SetBounds(val, Bounds(Type::None(), Type::SignedSmall()));
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* change = reduction.replacement();
+  Capture<Node*> add, branch, heap_number, if_true;
+  EXPECT_THAT(change, IsWord32Shl(val, IsInt32Constant(SmiShiftAmount())));
+}
+
+
+TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(
+          kMachFloat64, IsLoadHeapNumber(val, CaptureEq(&if_true)),
+          IsChangeInt32ToFloat64(
+              IsWord32Sar(val, IsInt32Constant(SmiShiftAmount()))),
+          IsMerge(
+              AllOf(CaptureEq(&if_true),
+                    IsIfTrue(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
+                                 graph()->start())))),
+              IsIfFalse(CaptureEq(&branch)))));
+}
+
+
+TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(kMachInt32,
+            IsChangeFloat64ToInt32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
+            IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())),
+            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                    IsIfFalse(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
+                                 graph()->start()))))));
+}
+
+
+TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToUint32) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(kMachUint32,
+            IsChangeFloat64ToUint32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
+            IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())),
+            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                    IsIfFalse(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
+                                 graph()->start()))))));
+}
+
+
+TARGET_TEST_F(ChangeLowering32Test, ChangeUint32ToTagged) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, heap_number, if_false;
+  EXPECT_THAT(
+      phi,
+      IsPhi(
+          kMachAnyTagged, IsWord32Shl(val, IsInt32Constant(SmiShiftAmount())),
+          IsFinish(AllOf(CaptureEq(&heap_number),
+                         IsAllocateHeapNumber(_, CaptureEq(&if_false))),
+                   IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
+                           CaptureEq(&heap_number),
+                           IsInt32Constant(HeapNumberValueOffset()),
+                           IsChangeUint32ToFloat64(val),
+                           CaptureEq(&heap_number), CaptureEq(&if_false))),
+          IsMerge(
+              IsIfTrue(AllOf(CaptureEq(&branch),
+                             IsBranch(IsUint32LessThanOrEqual(
+                                          val, IsInt32Constant(SmiMaxValue())),
+                                      graph()->start()))),
+              AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
+}
+
+
+// -----------------------------------------------------------------------------
+// 64-bit
+
+
+class ChangeLowering64Test : public ChangeLoweringTest {
+ public:
+  ~ChangeLowering64Test() OVERRIDE {}
+  MachineType WordRepresentation() const FINAL { return kRepWord64; }
+};
+
+
+TARGET_TEST_F(ChangeLowering64Test, ChangeInt32ToTagged) {
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  EXPECT_THAT(reduction.replacement(),
+              IsWord64Shl(IsChangeInt32ToInt64(val),
+                          IsInt64Constant(SmiShiftAmount())));
+}
+
+
+TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(
+          kMachFloat64, IsLoadHeapNumber(val, CaptureEq(&if_true)),
+          IsChangeInt32ToFloat64(IsTruncateInt64ToInt32(
+              IsWord64Sar(val, IsInt64Constant(SmiShiftAmount())))),
+          IsMerge(
+              AllOf(CaptureEq(&if_true),
+                    IsIfTrue(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)),
+                                 graph()->start())))),
+              IsIfFalse(CaptureEq(&branch)))));
+}
+
+
+TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(kMachInt32,
+            IsChangeFloat64ToInt32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
+            IsTruncateInt64ToInt32(
+                IsWord64Sar(val, IsInt64Constant(SmiShiftAmount()))),
+            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                    IsIfFalse(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)),
+                                 graph()->start()))))));
+}
+
+
+TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToUint32) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(kMachUint32,
+            IsChangeFloat64ToUint32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
+            IsTruncateInt64ToInt32(
+                IsWord64Sar(val, IsInt64Constant(SmiShiftAmount()))),
+            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                    IsIfFalse(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)),
+                                 graph()->start()))))));
+}
+
+
+TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, heap_number, if_false;
+  EXPECT_THAT(
+      phi,
+      IsPhi(
+          kMachAnyTagged, IsWord64Shl(IsChangeUint32ToUint64(val),
+                                      IsInt64Constant(SmiShiftAmount())),
+          IsFinish(AllOf(CaptureEq(&heap_number),
+                         IsAllocateHeapNumber(_, CaptureEq(&if_false))),
+                   IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
+                           CaptureEq(&heap_number),
+                           IsInt64Constant(HeapNumberValueOffset()),
+                           IsChangeUint32ToFloat64(val),
+                           CaptureEq(&heap_number), CaptureEq(&if_false))),
+          IsMerge(
+              IsIfTrue(AllOf(CaptureEq(&branch),
+                             IsBranch(IsUint32LessThanOrEqual(
+                                          val, IsInt32Constant(SmiMaxValue())),
+                                      graph()->start()))),
+              AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/common-operator-reducer-unittest.cc b/test/unittests/compiler/common-operator-reducer-unittest.cc
new file mode 100644
index 0000000..c713815
--- /dev/null
+++ b/test/unittests/compiler/common-operator-reducer-unittest.cc
@@ -0,0 +1,110 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/common-operator-reducer.h"
+#include "src/compiler/machine-type.h"
+#include "test/unittests/compiler/graph-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class CommonOperatorReducerTest : public GraphTest {
+ public:
+  explicit CommonOperatorReducerTest(int num_parameters = 1)
+      : GraphTest(num_parameters) {}
+  ~CommonOperatorReducerTest() OVERRIDE {}
+
+ protected:
+  Reduction Reduce(Node* node) {
+    CommonOperatorReducer reducer;
+    return reducer.Reduce(node);
+  }
+};
+
+
+namespace {
+
+const BranchHint kBranchHints[] = {BranchHint::kNone, BranchHint::kFalse,
+                                   BranchHint::kTrue};
+
+
+const MachineType kMachineTypes[] = {
+    kMachFloat32, kMachFloat64,   kMachInt8,   kMachUint8,  kMachInt16,
+    kMachUint16,  kMachInt32,     kMachUint32, kMachInt64,  kMachUint64,
+    kMachPtr,     kMachAnyTagged, kRepBit,     kRepWord8,   kRepWord16,
+    kRepWord32,   kRepWord64,     kRepFloat32, kRepFloat64, kRepTagged};
+
+
+const Operator kOp0(0, Operator::kNoProperties, "Op0", 0, 0, 0, 1, 1, 0);
+
+}  // namespace
+
+
+// -----------------------------------------------------------------------------
+// EffectPhi
+
+
+TEST_F(CommonOperatorReducerTest, RedundantEffectPhi) {
+  const int kMaxInputs = 64;
+  Node* inputs[kMaxInputs];
+  Node* const input = graph()->NewNode(&kOp0);
+  TRACED_FORRANGE(int, input_count, 2, kMaxInputs - 1) {
+    int const value_input_count = input_count - 1;
+    for (int i = 0; i < value_input_count; ++i) {
+      inputs[i] = input;
+    }
+    inputs[value_input_count] = graph()->start();
+    Reduction r = Reduce(graph()->NewNode(
+        common()->EffectPhi(value_input_count), input_count, inputs));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(input, r.replacement());
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Phi
+
+
+TEST_F(CommonOperatorReducerTest, RedundantPhi) {
+  const int kMaxInputs = 64;
+  Node* inputs[kMaxInputs];
+  Node* const input = graph()->NewNode(&kOp0);
+  TRACED_FORRANGE(int, input_count, 2, kMaxInputs - 1) {
+    int const value_input_count = input_count - 1;
+    TRACED_FOREACH(MachineType, type, kMachineTypes) {
+      for (int i = 0; i < value_input_count; ++i) {
+        inputs[i] = input;
+      }
+      inputs[value_input_count] = graph()->start();
+      Reduction r = Reduce(graph()->NewNode(
+          common()->Phi(type, value_input_count), input_count, inputs));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_EQ(input, r.replacement());
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Select
+
+
+TEST_F(CommonOperatorReducerTest, RedundantSelect) {
+  Node* const input = graph()->NewNode(&kOp0);
+  TRACED_FOREACH(BranchHint, hint, kBranchHints) {
+    TRACED_FOREACH(MachineType, type, kMachineTypes) {
+      Reduction r = Reduce(
+          graph()->NewNode(common()->Select(type, hint), input, input, input));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_EQ(input, r.replacement());
+    }
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/common-operator-unittest.cc b/test/unittests/compiler/common-operator-unittest.cc
new file mode 100644
index 0000000..d0ac145
--- /dev/null
+++ b/test/unittests/compiler/common-operator-unittest.cc
@@ -0,0 +1,293 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/opcodes.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/operator-properties.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+
+// -----------------------------------------------------------------------------
+// Shared operators.
+
+
+namespace {
+
+struct SharedOperator {
+  const Operator* (CommonOperatorBuilder::*constructor)();
+  IrOpcode::Value opcode;
+  Operator::Properties properties;
+  int value_input_count;
+  int effect_input_count;
+  int control_input_count;
+  int effect_output_count;
+  int control_output_count;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const SharedOperator& fop) {
+  return os << IrOpcode::Mnemonic(fop.opcode);
+}
+
+
+const SharedOperator kSharedOperators[] = {
+#define SHARED(Name, properties, value_input_count, effect_input_count,        \
+               control_input_count, effect_output_count, control_output_count) \
+  {                                                                            \
+    &CommonOperatorBuilder::Name, IrOpcode::k##Name, properties,               \
+        value_input_count, effect_input_count, control_input_count,            \
+        effect_output_count, control_output_count                              \
+  }
+    SHARED(Dead, Operator::kFoldable, 0, 0, 0, 0, 1),
+    SHARED(End, Operator::kFoldable, 0, 0, 1, 0, 0),
+    SHARED(IfTrue, Operator::kFoldable, 0, 0, 1, 0, 1),
+    SHARED(IfFalse, Operator::kFoldable, 0, 0, 1, 0, 1),
+    SHARED(Throw, Operator::kFoldable, 1, 1, 1, 0, 1),
+    SHARED(Return, Operator::kNoProperties, 1, 1, 1, 0, 1)
+#undef SHARED
+};
+
+
+class CommonSharedOperatorTest
+    : public TestWithZone,
+      public ::testing::WithParamInterface<SharedOperator> {};
+
+}  // namespace
+
+
+TEST_P(CommonSharedOperatorTest, InstancesAreGloballyShared) {
+  const SharedOperator& sop = GetParam();
+  CommonOperatorBuilder common1(zone());
+  CommonOperatorBuilder common2(zone());
+  EXPECT_EQ((common1.*sop.constructor)(), (common2.*sop.constructor)());
+}
+
+
+TEST_P(CommonSharedOperatorTest, NumberOfInputsAndOutputs) {
+  CommonOperatorBuilder common(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (common.*sop.constructor)();
+
+  EXPECT_EQ(sop.value_input_count, op->ValueInputCount());
+  EXPECT_EQ(sop.effect_input_count, op->EffectInputCount());
+  EXPECT_EQ(sop.control_input_count, op->ControlInputCount());
+  EXPECT_EQ(
+      sop.value_input_count + sop.effect_input_count + sop.control_input_count,
+      OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(0, op->ValueOutputCount());
+  EXPECT_EQ(sop.effect_output_count, op->EffectOutputCount());
+  EXPECT_EQ(sop.control_output_count, op->ControlOutputCount());
+}
+
+
+TEST_P(CommonSharedOperatorTest, OpcodeIsCorrect) {
+  CommonOperatorBuilder common(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (common.*sop.constructor)();
+  EXPECT_EQ(sop.opcode, op->opcode());
+}
+
+
+TEST_P(CommonSharedOperatorTest, Properties) {
+  CommonOperatorBuilder common(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (common.*sop.constructor)();
+  EXPECT_EQ(sop.properties, op->properties());
+}
+
+
+INSTANTIATE_TEST_CASE_P(CommonOperatorTest, CommonSharedOperatorTest,
+                        ::testing::ValuesIn(kSharedOperators));
+
+
+// -----------------------------------------------------------------------------
+// Other operators.
+
+
+namespace {
+
+class CommonOperatorTest : public TestWithZone {
+ public:
+  CommonOperatorTest() : common_(zone()) {}
+  ~CommonOperatorTest() OVERRIDE {}
+
+  CommonOperatorBuilder* common() { return &common_; }
+
+ private:
+  CommonOperatorBuilder common_;
+};
+
+
+const int kArguments[] = {1, 5, 6, 42, 100, 10000, 65000};
+
+
+const float kFloatValues[] = {-std::numeric_limits<float>::infinity(),
+                              std::numeric_limits<float>::min(),
+                              -1.0f,
+                              -0.0f,
+                              0.0f,
+                              1.0f,
+                              std::numeric_limits<float>::max(),
+                              std::numeric_limits<float>::infinity(),
+                              std::numeric_limits<float>::quiet_NaN(),
+                              std::numeric_limits<float>::signaling_NaN()};
+
+
+const double kDoubleValues[] = {-std::numeric_limits<double>::infinity(),
+                                std::numeric_limits<double>::min(),
+                                -1.0,
+                                -0.0,
+                                0.0,
+                                1.0,
+                                std::numeric_limits<double>::max(),
+                                std::numeric_limits<double>::infinity(),
+                                std::numeric_limits<double>::quiet_NaN(),
+                                std::numeric_limits<double>::signaling_NaN()};
+
+
+const BranchHint kHints[] = {BranchHint::kNone, BranchHint::kTrue,
+                             BranchHint::kFalse};
+
+}  // namespace
+
+
+TEST_F(CommonOperatorTest, Branch) {
+  TRACED_FOREACH(BranchHint, hint, kHints) {
+    const Operator* const op = common()->Branch(hint);
+    EXPECT_EQ(IrOpcode::kBranch, op->opcode());
+    EXPECT_EQ(Operator::kFoldable, op->properties());
+    EXPECT_EQ(hint, BranchHintOf(op));
+    EXPECT_EQ(1, op->ValueInputCount());
+    EXPECT_EQ(0, op->EffectInputCount());
+    EXPECT_EQ(1, op->ControlInputCount());
+    EXPECT_EQ(2, OperatorProperties::GetTotalInputCount(op));
+    EXPECT_EQ(0, op->ValueOutputCount());
+    EXPECT_EQ(0, op->EffectOutputCount());
+    EXPECT_EQ(2, op->ControlOutputCount());
+  }
+}
+
+
+TEST_F(CommonOperatorTest, Select) {
+  static const MachineType kTypes[] = {
+      kMachInt8,    kMachUint8,   kMachInt16,    kMachUint16,
+      kMachInt32,   kMachUint32,  kMachInt64,    kMachUint64,
+      kMachFloat32, kMachFloat64, kMachAnyTagged};
+  TRACED_FOREACH(MachineType, type, kTypes) {
+    TRACED_FOREACH(BranchHint, hint, kHints) {
+      const Operator* const op = common()->Select(type, hint);
+      EXPECT_EQ(IrOpcode::kSelect, op->opcode());
+      EXPECT_EQ(Operator::kPure, op->properties());
+      EXPECT_EQ(type, SelectParametersOf(op).type());
+      EXPECT_EQ(hint, SelectParametersOf(op).hint());
+      EXPECT_EQ(3, op->ValueInputCount());
+      EXPECT_EQ(0, op->EffectInputCount());
+      EXPECT_EQ(0, op->ControlInputCount());
+      EXPECT_EQ(3, OperatorProperties::GetTotalInputCount(op));
+      EXPECT_EQ(1, op->ValueOutputCount());
+      EXPECT_EQ(0, op->EffectOutputCount());
+      EXPECT_EQ(0, op->ControlOutputCount());
+    }
+  }
+}
+
+
+TEST_F(CommonOperatorTest, Float32Constant) {
+  TRACED_FOREACH(float, value, kFloatValues) {
+    const Operator* op = common()->Float32Constant(value);
+    EXPECT_PRED2(base::bit_equal_to<float>(), value, OpParameter<float>(op));
+    EXPECT_EQ(0, op->ValueInputCount());
+    EXPECT_EQ(0, OperatorProperties::GetTotalInputCount(op));
+    EXPECT_EQ(0, op->ControlOutputCount());
+    EXPECT_EQ(0, op->EffectOutputCount());
+    EXPECT_EQ(1, op->ValueOutputCount());
+  }
+  TRACED_FOREACH(float, v1, kFloatValues) {
+    TRACED_FOREACH(float, v2, kFloatValues) {
+      const Operator* op1 = common()->Float32Constant(v1);
+      const Operator* op2 = common()->Float32Constant(v2);
+      EXPECT_EQ(bit_cast<uint32_t>(v1) == bit_cast<uint32_t>(v2),
+                op1->Equals(op2));
+    }
+  }
+}
+
+
+TEST_F(CommonOperatorTest, Float64Constant) {
+  TRACED_FOREACH(double, value, kFloatValues) {
+    const Operator* op = common()->Float64Constant(value);
+    EXPECT_PRED2(base::bit_equal_to<double>(), value, OpParameter<double>(op));
+    EXPECT_EQ(0, op->ValueInputCount());
+    EXPECT_EQ(0, OperatorProperties::GetTotalInputCount(op));
+    EXPECT_EQ(0, op->ControlOutputCount());
+    EXPECT_EQ(0, op->EffectOutputCount());
+    EXPECT_EQ(1, op->ValueOutputCount());
+  }
+  TRACED_FOREACH(double, v1, kFloatValues) {
+    TRACED_FOREACH(double, v2, kFloatValues) {
+      const Operator* op1 = common()->Float64Constant(v1);
+      const Operator* op2 = common()->Float64Constant(v2);
+      EXPECT_EQ(bit_cast<uint64_t>(v1) == bit_cast<uint64_t>(v2),
+                op1->Equals(op2));
+    }
+  }
+}
+
+
+TEST_F(CommonOperatorTest, NumberConstant) {
+  TRACED_FOREACH(double, value, kFloatValues) {
+    const Operator* op = common()->NumberConstant(value);
+    EXPECT_PRED2(base::bit_equal_to<double>(), value, OpParameter<double>(op));
+    EXPECT_EQ(0, op->ValueInputCount());
+    EXPECT_EQ(0, OperatorProperties::GetTotalInputCount(op));
+    EXPECT_EQ(0, op->ControlOutputCount());
+    EXPECT_EQ(0, op->EffectOutputCount());
+    EXPECT_EQ(1, op->ValueOutputCount());
+  }
+  TRACED_FOREACH(double, v1, kFloatValues) {
+    TRACED_FOREACH(double, v2, kFloatValues) {
+      const Operator* op1 = common()->NumberConstant(v1);
+      const Operator* op2 = common()->NumberConstant(v2);
+      EXPECT_EQ(bit_cast<uint64_t>(v1) == bit_cast<uint64_t>(v2),
+                op1->Equals(op2));
+    }
+  }
+}
+
+
+TEST_F(CommonOperatorTest, ValueEffect) {
+  TRACED_FOREACH(int, arguments, kArguments) {
+    const Operator* op = common()->ValueEffect(arguments);
+    EXPECT_EQ(arguments, op->ValueInputCount());
+    EXPECT_EQ(arguments, OperatorProperties::GetTotalInputCount(op));
+    EXPECT_EQ(0, op->ControlOutputCount());
+    EXPECT_EQ(1, op->EffectOutputCount());
+    EXPECT_EQ(0, op->ValueOutputCount());
+  }
+}
+
+
+TEST_F(CommonOperatorTest, Finish) {
+  TRACED_FOREACH(int, arguments, kArguments) {
+    const Operator* op = common()->Finish(arguments);
+    EXPECT_EQ(1, op->ValueInputCount());
+    EXPECT_EQ(arguments, op->EffectInputCount());
+    EXPECT_EQ(arguments + 1, OperatorProperties::GetTotalInputCount(op));
+    EXPECT_EQ(0, op->ControlOutputCount());
+    EXPECT_EQ(0, op->EffectOutputCount());
+    EXPECT_EQ(1, op->ValueOutputCount());
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/compiler-test-utils.h b/test/unittests/compiler/compiler-test-utils.h
new file mode 100644
index 0000000..6ce28f9
--- /dev/null
+++ b/test/unittests/compiler/compiler-test-utils.h
@@ -0,0 +1,57 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UNITTESTS_COMPILER_COMPILER_TEST_UTILS_H_
+#define V8_UNITTESTS_COMPILER_COMPILER_TEST_UTILS_H_
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// The TARGET_TEST(Case, Name) macro works just like
+// TEST(Case, Name), except that the test is disabled
+// if the platform is not a supported TurboFan target.
+#if V8_TURBOFAN_TARGET
+#define TARGET_TEST(Case, Name) TEST(Case, Name)
+#else
+#define TARGET_TEST(Case, Name) TEST(Case, DISABLED_##Name)
+#endif
+
+
+// The TARGET_TEST_F(Case, Name) macro works just like
+// TEST_F(Case, Name), except that the test is disabled
+// if the platform is not a supported TurboFan target.
+#if V8_TURBOFAN_TARGET
+#define TARGET_TEST_F(Case, Name) TEST_F(Case, Name)
+#else
+#define TARGET_TEST_F(Case, Name) TEST_F(Case, DISABLED_##Name)
+#endif
+
+
+// The TARGET_TEST_P(Case, Name) macro works just like
+// TEST_P(Case, Name), except that the test is disabled
+// if the platform is not a supported TurboFan target.
+#if V8_TURBOFAN_TARGET
+#define TARGET_TEST_P(Case, Name) TEST_P(Case, Name)
+#else
+#define TARGET_TEST_P(Case, Name) TEST_P(Case, DISABLED_##Name)
+#endif
+
+
+// The TARGET_TYPED_TEST(Case, Name) macro works just like
+// TYPED_TEST(Case, Name), except that the test is disabled
+// if the platform is not a supported TurboFan target.
+#if V8_TURBOFAN_TARGET
+#define TARGET_TYPED_TEST(Case, Name) TYPED_TEST(Case, Name)
+#else
+#define TARGET_TYPED_TEST(Case, Name) TYPED_TEST(Case, DISABLED_##Name)
+#endif
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_UNITTESTS_COMPILER_COMPILER_TEST_UTILS_H_
diff --git a/test/unittests/compiler/control-equivalence-unittest.cc b/test/unittests/compiler/control-equivalence-unittest.cc
new file mode 100644
index 0000000..56b4a2b
--- /dev/null
+++ b/test/unittests/compiler/control-equivalence-unittest.cc
@@ -0,0 +1,255 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/bit-vector.h"
+#include "src/compiler/control-equivalence.h"
+#include "src/compiler/graph-visualizer.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/zone-containers.h"
+#include "test/unittests/compiler/graph-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+#define ASSERT_EQUIVALENCE(...)                           \
+  do {                                                    \
+    Node* __n[] = {__VA_ARGS__};                          \
+    ASSERT_TRUE(IsEquivalenceClass(arraysize(__n), __n)); \
+  } while (false);
+
+class ControlEquivalenceTest : public GraphTest {
+ public:
+  ControlEquivalenceTest() : all_nodes_(zone()), classes_(zone()) {
+    Store(graph()->start());
+  }
+
+ protected:
+  void ComputeEquivalence(Node* node) {
+    graph()->SetEnd(graph()->NewNode(common()->End(), node));
+    if (FLAG_trace_turbo) {
+      OFStream os(stdout);
+      os << AsDOT(*graph());
+    }
+    ControlEquivalence equivalence(zone(), graph());
+    equivalence.Run(node);
+    classes_.resize(graph()->NodeCount());
+    for (Node* node : all_nodes_) {
+      classes_[node->id()] = equivalence.ClassOf(node);
+    }
+  }
+
+  bool IsEquivalenceClass(size_t length, Node** nodes) {
+    BitVector in_class(graph()->NodeCount(), zone());
+    size_t expected_class = classes_[nodes[0]->id()];
+    for (size_t i = 0; i < length; ++i) {
+      in_class.Add(nodes[i]->id());
+    }
+    for (Node* node : all_nodes_) {
+      if (in_class.Contains(node->id())) {
+        if (classes_[node->id()] != expected_class) return false;
+      } else {
+        if (classes_[node->id()] == expected_class) return false;
+      }
+    }
+    return true;
+  }
+
+  Node* Value() { return NumberConstant(0.0); }
+
+  Node* Branch(Node* control) {
+    return Store(graph()->NewNode(common()->Branch(), Value(), control));
+  }
+
+  Node* IfTrue(Node* control) {
+    return Store(graph()->NewNode(common()->IfTrue(), control));
+  }
+
+  Node* IfFalse(Node* control) {
+    return Store(graph()->NewNode(common()->IfFalse(), control));
+  }
+
+  Node* Merge2(Node* control1, Node* control2) {
+    return Store(graph()->NewNode(common()->Merge(2), control1, control2));
+  }
+
+  Node* Loop2(Node* control) {
+    return Store(graph()->NewNode(common()->Loop(2), control, control));
+  }
+
+  Node* End(Node* control) {
+    return Store(graph()->NewNode(common()->End(), control));
+  }
+
+ private:
+  Node* Store(Node* node) {
+    all_nodes_.push_back(node);
+    return node;
+  }
+
+  ZoneVector<Node*> all_nodes_;
+  ZoneVector<size_t> classes_;
+};
+
+
+// -----------------------------------------------------------------------------
+// Test cases.
+
+
+TEST_F(ControlEquivalenceTest, Empty1) {
+  Node* start = graph()->start();
+  ComputeEquivalence(start);
+
+  ASSERT_EQUIVALENCE(start);
+}
+
+
+TEST_F(ControlEquivalenceTest, Empty2) {
+  Node* start = graph()->start();
+  Node* end = End(start);
+  ComputeEquivalence(end);
+
+  ASSERT_EQUIVALENCE(start, end);
+}
+
+
+TEST_F(ControlEquivalenceTest, Diamond1) {
+  Node* start = graph()->start();
+  Node* b = Branch(start);
+  Node* t = IfTrue(b);
+  Node* f = IfFalse(b);
+  Node* m = Merge2(t, f);
+  ComputeEquivalence(m);
+
+  ASSERT_EQUIVALENCE(b, m, start);
+  ASSERT_EQUIVALENCE(f);
+  ASSERT_EQUIVALENCE(t);
+}
+
+
+TEST_F(ControlEquivalenceTest, Diamond2) {
+  Node* start = graph()->start();
+  Node* b1 = Branch(start);
+  Node* t1 = IfTrue(b1);
+  Node* f1 = IfFalse(b1);
+  Node* b2 = Branch(f1);
+  Node* t2 = IfTrue(b2);
+  Node* f2 = IfFalse(b2);
+  Node* m2 = Merge2(t2, f2);
+  Node* m1 = Merge2(t1, m2);
+  ComputeEquivalence(m1);
+
+  ASSERT_EQUIVALENCE(b1, m1, start);
+  ASSERT_EQUIVALENCE(t1);
+  ASSERT_EQUIVALENCE(f1, b2, m2);
+  ASSERT_EQUIVALENCE(t2);
+  ASSERT_EQUIVALENCE(f2);
+}
+
+
+TEST_F(ControlEquivalenceTest, Diamond3) {
+  Node* start = graph()->start();
+  Node* b1 = Branch(start);
+  Node* t1 = IfTrue(b1);
+  Node* f1 = IfFalse(b1);
+  Node* m1 = Merge2(t1, f1);
+  Node* b2 = Branch(m1);
+  Node* t2 = IfTrue(b2);
+  Node* f2 = IfFalse(b2);
+  Node* m2 = Merge2(t2, f2);
+  ComputeEquivalence(m2);
+
+  ASSERT_EQUIVALENCE(b1, m1, b2, m2, start);
+  ASSERT_EQUIVALENCE(t1);
+  ASSERT_EQUIVALENCE(f1);
+  ASSERT_EQUIVALENCE(t2);
+  ASSERT_EQUIVALENCE(f2);
+}
+
+
+TEST_F(ControlEquivalenceTest, Switch1) {
+  Node* start = graph()->start();
+  Node* b1 = Branch(start);
+  Node* t1 = IfTrue(b1);
+  Node* f1 = IfFalse(b1);
+  Node* b2 = Branch(f1);
+  Node* t2 = IfTrue(b2);
+  Node* f2 = IfFalse(b2);
+  Node* b3 = Branch(f2);
+  Node* t3 = IfTrue(b3);
+  Node* f3 = IfFalse(b3);
+  Node* m1 = Merge2(t1, t2);
+  Node* m2 = Merge2(m1, t3);
+  Node* m3 = Merge2(m2, f3);
+  ComputeEquivalence(m3);
+
+  ASSERT_EQUIVALENCE(b1, m3, start);
+  ASSERT_EQUIVALENCE(t1);
+  ASSERT_EQUIVALENCE(f1, b2);
+  ASSERT_EQUIVALENCE(t2);
+  ASSERT_EQUIVALENCE(f2, b3);
+  ASSERT_EQUIVALENCE(t3);
+  ASSERT_EQUIVALENCE(f3);
+  ASSERT_EQUIVALENCE(m1);
+  ASSERT_EQUIVALENCE(m2);
+}
+
+
+TEST_F(ControlEquivalenceTest, Loop1) {
+  Node* start = graph()->start();
+  Node* l = Loop2(start);
+  l->ReplaceInput(1, l);
+  ComputeEquivalence(l);
+
+  ASSERT_EQUIVALENCE(start);
+  ASSERT_EQUIVALENCE(l);
+}
+
+
+TEST_F(ControlEquivalenceTest, Loop2) {
+  Node* start = graph()->start();
+  Node* l = Loop2(start);
+  Node* b = Branch(l);
+  Node* t = IfTrue(b);
+  Node* f = IfFalse(b);
+  l->ReplaceInput(1, t);
+  ComputeEquivalence(f);
+
+  ASSERT_EQUIVALENCE(f, start);
+  ASSERT_EQUIVALENCE(t);
+  ASSERT_EQUIVALENCE(l, b);
+}
+
+
+TEST_F(ControlEquivalenceTest, Irreducible) {
+  Node* start = graph()->start();
+  Node* b1 = Branch(start);
+  Node* t1 = IfTrue(b1);
+  Node* f1 = IfFalse(b1);
+  Node* lp = Loop2(f1);
+  Node* m1 = Merge2(t1, lp);
+  Node* b2 = Branch(m1);
+  Node* t2 = IfTrue(b2);
+  Node* f2 = IfFalse(b2);
+  Node* m2 = Merge2(t2, f2);
+  Node* b3 = Branch(m2);
+  Node* t3 = IfTrue(b3);
+  Node* f3 = IfFalse(b3);
+  lp->ReplaceInput(1, f3);
+  ComputeEquivalence(t3);
+
+  ASSERT_EQUIVALENCE(b1, t3, start);
+  ASSERT_EQUIVALENCE(t1);
+  ASSERT_EQUIVALENCE(f1);
+  ASSERT_EQUIVALENCE(m1, b2, m2, b3);
+  ASSERT_EQUIVALENCE(t2);
+  ASSERT_EQUIVALENCE(f2);
+  ASSERT_EQUIVALENCE(f3);
+  ASSERT_EQUIVALENCE(lp);
+}
+
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/diamond-unittest.cc b/test/unittests/compiler/diamond-unittest.cc
new file mode 100644
index 0000000..c14886f
--- /dev/null
+++ b/test/unittests/compiler/diamond-unittest.cc
@@ -0,0 +1,161 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/diamond.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::AllOf;
+using testing::Capture;
+using testing::CaptureEq;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class DiamondTest : public GraphTest {
+ public:
+  DiamondTest() : GraphTest(5) {}
+};
+
+
+TEST_F(DiamondTest, SimpleDiamond) {
+  Node* p = Parameter(0);
+  Diamond d(graph(), common(), p);
+  EXPECT_THAT(d.branch, IsBranch(p, graph()->start()));
+  EXPECT_THAT(d.if_true, IsIfTrue(d.branch));
+  EXPECT_THAT(d.if_false, IsIfFalse(d.branch));
+  EXPECT_THAT(d.merge, IsMerge(d.if_true, d.if_false));
+}
+
+
+TEST_F(DiamondTest, DiamondChainDiamond) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Diamond d0(graph(), common(), p0);
+  Diamond d1(graph(), common(), p1);
+  d1.Chain(d0);
+  EXPECT_THAT(d1.branch, IsBranch(p1, d0.merge));
+  EXPECT_THAT(d0.branch, IsBranch(p0, graph()->start()));
+}
+
+
+TEST_F(DiamondTest, DiamondChainNode) {
+  Node* p1 = Parameter(1);
+  Diamond d1(graph(), common(), p1);
+  Node* other = graph()->NewNode(common()->Merge(0));
+  d1.Chain(other);
+  EXPECT_THAT(d1.branch, IsBranch(p1, other));
+}
+
+
+TEST_F(DiamondTest, DiamondChainN) {
+  Node* params[5] = {Parameter(0), Parameter(1), Parameter(2), Parameter(3),
+                     Parameter(4)};
+  Diamond d[5] = {Diamond(graph(), common(), params[0]),
+                  Diamond(graph(), common(), params[1]),
+                  Diamond(graph(), common(), params[2]),
+                  Diamond(graph(), common(), params[3]),
+                  Diamond(graph(), common(), params[4])};
+
+  for (int i = 1; i < 5; i++) {
+    d[i].Chain(d[i - 1]);
+    EXPECT_THAT(d[i].branch, IsBranch(params[i], d[i - 1].merge));
+  }
+}
+
+
+TEST_F(DiamondTest, DiamondNested_true) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Diamond d0(graph(), common(), p0);
+  Diamond d1(graph(), common(), p1);
+
+  d1.Nest(d0, true);
+
+  EXPECT_THAT(d0.branch, IsBranch(p0, graph()->start()));
+  EXPECT_THAT(d0.if_true, IsIfTrue(d0.branch));
+  EXPECT_THAT(d0.if_false, IsIfFalse(d0.branch));
+  EXPECT_THAT(d0.merge, IsMerge(d1.merge, d0.if_false));
+
+  EXPECT_THAT(d1.branch, IsBranch(p1, d0.if_true));
+  EXPECT_THAT(d1.if_true, IsIfTrue(d1.branch));
+  EXPECT_THAT(d1.if_false, IsIfFalse(d1.branch));
+  EXPECT_THAT(d1.merge, IsMerge(d1.if_true, d1.if_false));
+}
+
+
+TEST_F(DiamondTest, DiamondNested_false) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Diamond d0(graph(), common(), p0);
+  Diamond d1(graph(), common(), p1);
+
+  d1.Nest(d0, false);
+
+  EXPECT_THAT(d0.branch, IsBranch(p0, graph()->start()));
+  EXPECT_THAT(d0.if_true, IsIfTrue(d0.branch));
+  EXPECT_THAT(d0.if_false, IsIfFalse(d0.branch));
+  EXPECT_THAT(d0.merge, IsMerge(d0.if_true, d1.merge));
+
+  EXPECT_THAT(d1.branch, IsBranch(p1, d0.if_false));
+  EXPECT_THAT(d1.if_true, IsIfTrue(d1.branch));
+  EXPECT_THAT(d1.if_false, IsIfFalse(d1.branch));
+  EXPECT_THAT(d1.merge, IsMerge(d1.if_true, d1.if_false));
+}
+
+
+TEST_F(DiamondTest, DiamondPhis) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Node* p2 = Parameter(2);
+  Diamond d(graph(), common(), p0);
+
+  MachineType types[] = {kMachAnyTagged, kMachUint32, kMachInt32};
+
+  for (size_t i = 0; i < arraysize(types); i++) {
+    Node* phi = d.Phi(types[i], p1, p2);
+
+    EXPECT_THAT(d.branch, IsBranch(p0, graph()->start()));
+    EXPECT_THAT(d.if_true, IsIfTrue(d.branch));
+    EXPECT_THAT(d.if_false, IsIfFalse(d.branch));
+    EXPECT_THAT(d.merge, IsMerge(d.if_true, d.if_false));
+    EXPECT_THAT(phi, IsPhi(types[i], p1, p2, d.merge));
+  }
+}
+
+
+TEST_F(DiamondTest, DiamondEffectPhis) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Node* p2 = Parameter(2);
+  Diamond d(graph(), common(), p0);
+
+  Node* phi = d.EffectPhi(p1, p2);
+
+  EXPECT_THAT(d.branch, IsBranch(p0, graph()->start()));
+  EXPECT_THAT(d.if_true, IsIfTrue(d.branch));
+  EXPECT_THAT(d.if_false, IsIfFalse(d.branch));
+  EXPECT_THAT(d.merge, IsMerge(d.if_true, d.if_false));
+  EXPECT_THAT(phi, IsEffectPhi(p1, p2, d.merge));
+}
+
+
+TEST_F(DiamondTest, BranchHint) {
+  Diamond dn(graph(), common(), Parameter(0));
+  CHECK(BranchHint::kNone == BranchHintOf(dn.branch->op()));
+
+  Diamond dt(graph(), common(), Parameter(0), BranchHint::kTrue);
+  CHECK(BranchHint::kTrue == BranchHintOf(dt.branch->op()));
+
+  Diamond df(graph(), common(), Parameter(0), BranchHint::kFalse);
+  CHECK(BranchHint::kFalse == BranchHintOf(df.branch->op()));
+}
+
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/graph-reducer-unittest.cc b/test/unittests/compiler/graph-reducer-unittest.cc
new file mode 100644
index 0000000..dbdd4bb
--- /dev/null
+++ b/test/unittests/compiler/graph-reducer-unittest.cc
@@ -0,0 +1,123 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/graph.h"
+#include "src/compiler/graph-reducer.h"
+#include "src/compiler/operator.h"
+#include "test/unittests/test-utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::_;
+using testing::DefaultValue;
+using testing::Return;
+using testing::Sequence;
+using testing::StrictMock;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+struct TestOperator : public Operator {
+  TestOperator(Operator::Opcode opcode, Operator::Properties properties,
+               size_t value_in, size_t value_out)
+      : Operator(opcode, properties, "TestOp", value_in, 0, 0, value_out, 0,
+                 0) {}
+};
+
+
+namespace {
+
+TestOperator OP0(0, Operator::kNoWrite, 0, 1);
+TestOperator OP1(1, Operator::kNoProperties, 1, 1);
+
+
+struct MockReducer : public Reducer {
+  MOCK_METHOD1(Reduce, Reduction(Node*));
+};
+
+}  // namespace
+
+
+class GraphReducerTest : public TestWithZone {
+ public:
+  GraphReducerTest() : graph_(zone()) {}
+
+  static void SetUpTestCase() {
+    TestWithZone::SetUpTestCase();
+    DefaultValue<Reduction>::Set(Reducer::NoChange());
+  }
+
+  static void TearDownTestCase() {
+    DefaultValue<Reduction>::Clear();
+    TestWithZone::TearDownTestCase();
+  }
+
+ protected:
+  void ReduceNode(Node* node, Reducer* r) {
+    GraphReducer reducer(graph(), zone());
+    reducer.AddReducer(r);
+    reducer.ReduceNode(node);
+  }
+
+  void ReduceNode(Node* node, Reducer* r1, Reducer* r2) {
+    GraphReducer reducer(graph(), zone());
+    reducer.AddReducer(r1);
+    reducer.AddReducer(r2);
+    reducer.ReduceNode(node);
+  }
+
+  void ReduceNode(Node* node, Reducer* r1, Reducer* r2, Reducer* r3) {
+    GraphReducer reducer(graph(), zone());
+    reducer.AddReducer(r1);
+    reducer.AddReducer(r2);
+    reducer.AddReducer(r3);
+    reducer.ReduceNode(node);
+  }
+
+  Graph* graph() { return &graph_; }
+
+ private:
+  Graph graph_;
+};
+
+
+TEST_F(GraphReducerTest, NodeIsDeadAfterReplace) {
+  StrictMock<MockReducer> r;
+  Node* node0 = graph()->NewNode(&OP0);
+  Node* node1 = graph()->NewNode(&OP1, node0);
+  Node* node2 = graph()->NewNode(&OP1, node0);
+  EXPECT_CALL(r, Reduce(node0)).WillOnce(Return(Reducer::NoChange()));
+  EXPECT_CALL(r, Reduce(node1)).WillOnce(Return(Reducer::Replace(node2)));
+  ReduceNode(node1, &r);
+  EXPECT_FALSE(node0->IsDead());
+  EXPECT_TRUE(node1->IsDead());
+  EXPECT_FALSE(node2->IsDead());
+}
+
+
+TEST_F(GraphReducerTest, ReduceOnceForEveryReducer) {
+  StrictMock<MockReducer> r1, r2;
+  Node* node0 = graph()->NewNode(&OP0);
+  EXPECT_CALL(r1, Reduce(node0));
+  EXPECT_CALL(r2, Reduce(node0));
+  ReduceNode(node0, &r1, &r2);
+}
+
+
+TEST_F(GraphReducerTest, ReduceAgainAfterChanged) {
+  Sequence s1, s2, s3;
+  StrictMock<MockReducer> r1, r2, r3;
+  Node* node0 = graph()->NewNode(&OP0);
+  EXPECT_CALL(r1, Reduce(node0));
+  EXPECT_CALL(r2, Reduce(node0));
+  EXPECT_CALL(r3, Reduce(node0)).InSequence(s1, s2, s3).WillOnce(
+      Return(Reducer::Changed(node0)));
+  EXPECT_CALL(r1, Reduce(node0)).InSequence(s1);
+  EXPECT_CALL(r2, Reduce(node0)).InSequence(s2);
+  ReduceNode(node0, &r1, &r2, &r3);
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/graph-unittest.cc b/test/unittests/compiler/graph-unittest.cc
new file mode 100644
index 0000000..9543258
--- /dev/null
+++ b/test/unittests/compiler/graph-unittest.cc
@@ -0,0 +1,110 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/compiler/graph-unittest.h"
+
+#include "src/compiler/node-properties-inl.h"
+#include "test/unittests/compiler/node-test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+GraphTest::GraphTest(int num_parameters) : common_(zone()), graph_(zone()) {
+  graph()->SetStart(graph()->NewNode(common()->Start(num_parameters)));
+}
+
+
+GraphTest::~GraphTest() {}
+
+
+Node* GraphTest::Parameter(int32_t index) {
+  return graph()->NewNode(common()->Parameter(index), graph()->start());
+}
+
+
+Node* GraphTest::Float32Constant(volatile float value) {
+  return graph()->NewNode(common()->Float32Constant(value));
+}
+
+
+Node* GraphTest::Float64Constant(volatile double value) {
+  return graph()->NewNode(common()->Float64Constant(value));
+}
+
+
+Node* GraphTest::Int32Constant(int32_t value) {
+  return graph()->NewNode(common()->Int32Constant(value));
+}
+
+
+Node* GraphTest::Int64Constant(int64_t value) {
+  return graph()->NewNode(common()->Int64Constant(value));
+}
+
+
+Node* GraphTest::NumberConstant(volatile double value) {
+  return graph()->NewNode(common()->NumberConstant(value));
+}
+
+
+Node* GraphTest::HeapConstant(const Handle<HeapObject>& value) {
+  return HeapConstant(Unique<HeapObject>::CreateUninitialized(value));
+}
+
+
+Node* GraphTest::HeapConstant(const Unique<HeapObject>& value) {
+  Node* node = graph()->NewNode(common()->HeapConstant(value));
+  Type* type = Type::Constant(value.handle(), zone());
+  NodeProperties::SetBounds(node, Bounds(type));
+  return node;
+}
+
+
+Node* GraphTest::FalseConstant() {
+  return HeapConstant(
+      Unique<HeapObject>::CreateImmovable(factory()->false_value()));
+}
+
+
+Node* GraphTest::TrueConstant() {
+  return HeapConstant(
+      Unique<HeapObject>::CreateImmovable(factory()->true_value()));
+}
+
+
+Node* GraphTest::UndefinedConstant() {
+  return HeapConstant(
+      Unique<HeapObject>::CreateImmovable(factory()->undefined_value()));
+}
+
+
+Matcher<Node*> GraphTest::IsFalseConstant() {
+  return IsHeapConstant(
+      Unique<HeapObject>::CreateImmovable(factory()->false_value()));
+}
+
+
+Matcher<Node*> GraphTest::IsTrueConstant() {
+  return IsHeapConstant(
+      Unique<HeapObject>::CreateImmovable(factory()->true_value()));
+}
+
+
+TypedGraphTest::TypedGraphTest(int num_parameters)
+    : GraphTest(num_parameters), typer_(graph(), MaybeHandle<Context>()) {}
+
+
+TypedGraphTest::~TypedGraphTest() {}
+
+
+Node* TypedGraphTest::Parameter(Type* type, int32_t index) {
+  Node* node = GraphTest::Parameter(index);
+  NodeProperties::SetBounds(node, Bounds(type));
+  return node;
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/graph-unittest.h b/test/unittests/compiler/graph-unittest.h
new file mode 100644
index 0000000..7c75161
--- /dev/null
+++ b/test/unittests/compiler/graph-unittest.h
@@ -0,0 +1,81 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UNITTESTS_COMPILER_GRAPH_UNITTEST_H_
+#define V8_UNITTESTS_COMPILER_GRAPH_UNITTEST_H_
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/typer.h"
+#include "test/unittests/test-utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+template <class T>
+class Handle;
+class HeapObject;
+template <class T>
+class Unique;
+
+namespace compiler {
+
+using ::testing::Matcher;
+
+
+class GraphTest : public TestWithContext, public TestWithZone {
+ public:
+  explicit GraphTest(int num_parameters = 1);
+  ~GraphTest() OVERRIDE;
+
+ protected:
+  Node* Parameter(int32_t index = 0);
+  Node* Float32Constant(volatile float value);
+  Node* Float64Constant(volatile double value);
+  Node* Int32Constant(int32_t value);
+  Node* Uint32Constant(uint32_t value) {
+    return Int32Constant(bit_cast<int32_t>(value));
+  }
+  Node* Int64Constant(int64_t value);
+  Node* NumberConstant(volatile double value);
+  Node* HeapConstant(const Handle<HeapObject>& value);
+  Node* HeapConstant(const Unique<HeapObject>& value);
+  Node* FalseConstant();
+  Node* TrueConstant();
+  Node* UndefinedConstant();
+
+  Matcher<Node*> IsFalseConstant();
+  Matcher<Node*> IsTrueConstant();
+
+  CommonOperatorBuilder* common() { return &common_; }
+  Graph* graph() { return &graph_; }
+
+ private:
+  CommonOperatorBuilder common_;
+  Graph graph_;
+};
+
+
+class TypedGraphTest : public GraphTest {
+ public:
+  explicit TypedGraphTest(int num_parameters = 1);
+  ~TypedGraphTest() OVERRIDE;
+
+ protected:
+  Node* Parameter(int32_t index = 0) { return GraphTest::Parameter(index); }
+  Node* Parameter(Type* type, int32_t index = 0);
+
+  Typer* typer() { return &typer_; }
+
+ private:
+  Typer typer_;
+};
+
+}  //  namespace compiler
+}  //  namespace internal
+}  //  namespace v8
+
+#endif  // V8_UNITTESTS_COMPILER_GRAPH_UNITTEST_H_
diff --git a/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc b/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc
new file mode 100644
index 0000000..afa1e94
--- /dev/null
+++ b/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc
@@ -0,0 +1,671 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/compiler/instruction-selector-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+// Immediates (random subset).
+static const int32_t kImmediates[] = {
+    kMinInt, -42, -1, 0,  1,  2,    3,      4,          5,
+    6,       7,   8,  16, 42, 0xff, 0xffff, 0x0f0f0f0f, kMaxInt};
+
+}  // namespace
+
+
+TEST_F(InstructionSelectorTest, Int32AddWithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Add(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddWithImmediate) {
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    {
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
+      if (imm == 0) {
+        ASSERT_EQ(1U, s[0]->InputCount());
+      } else {
+        ASSERT_EQ(2U, s[0]->InputCount());
+        EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+      }
+    }
+    {
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
+      if (imm == 0) {
+        ASSERT_EQ(1U, s[0]->InputCount());
+      } else {
+        ASSERT_EQ(2U, s[0]->InputCount());
+        EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+      }
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32SubWithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Sub(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kIA32Sub, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32SubWithImmediate) {
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kIA32Sub, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+
+TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) {
+  StreamBuilder m(this, kMachFloat32, kMachFloat64);
+  m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSECvtss2sd, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat32);
+  m.Return(m.TruncateFloat64ToFloat32(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSECvtsd2ss, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+// -----------------------------------------------------------------------------
+// Better left operand for commutative binops
+
+
+TEST_F(InstructionSelectorTest, BetterLeftOperandTestAddBinop) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* param1 = m.Parameter(0);
+  Node* param2 = m.Parameter(1);
+  Node* add = m.Int32Add(param1, param2);
+  m.Return(m.Int32Add(add, param1));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  ASSERT_TRUE(s[0]->InputAt(0)->IsUnallocated());
+  EXPECT_EQ(s.ToVreg(param1), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(param2), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(param1), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, BetterLeftOperandTestMulBinop) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* param1 = m.Parameter(0);
+  Node* param2 = m.Parameter(1);
+  Node* mul = m.Int32Mul(param1, param2);
+  m.Return(m.Int32Mul(mul, param1));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kIA32Imul, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  ASSERT_TRUE(s[0]->InputAt(0)->IsUnallocated());
+  EXPECT_EQ(s.ToVreg(param2), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(param1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+
+TEST_F(InstructionSelectorTest, ChangeUint32ToFloat64WithParameter) {
+  StreamBuilder m(this, kMachFloat64, kMachUint32);
+  m.Return(m.ChangeUint32ToFloat64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSEUint32ToFloat64, s[0]->arch_opcode());
+}
+
+
+// -----------------------------------------------------------------------------
+// Loads and stores
+
+
+namespace {
+
+struct MemoryAccess {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
+  return os << memacc.type;
+}
+
+
+static const MemoryAccess kMemoryAccesses[] = {
+    {kMachInt8, kIA32Movsxbl, kIA32Movb},
+    {kMachUint8, kIA32Movzxbl, kIA32Movb},
+    {kMachInt16, kIA32Movsxwl, kIA32Movw},
+    {kMachUint16, kIA32Movzxwl, kIA32Movw},
+    {kMachInt32, kIA32Movl, kIA32Movl},
+    {kMachUint32, kIA32Movl, kIA32Movl},
+    {kMachFloat32, kIA32Movss, kIA32Movss},
+    {kMachFloat64, kIA32Movsd, kIA32Movsd}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccess>
+    InstructionSelectorMemoryAccessTest;
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
+  m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateBase) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, base, kImmediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Int32Constant(base), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+    if (base == 0) {
+      ASSERT_EQ(1U, s[0]->InputCount());
+    } else {
+      ASSERT_EQ(2U, s[0]->InputCount());
+      ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+      EXPECT_EQ(base, s.ToInt32(s[0]->InputAt(1)));
+    }
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, kImmediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+    if (index == 0) {
+      ASSERT_EQ(1U, s[0]->InputCount());
+    } else {
+      ASSERT_EQ(2U, s[0]->InputCount());
+      ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+      EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    }
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
+  m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(0U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateBase) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, base, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, memacc.type);
+    m.Store(memacc.type, m.Int32Constant(base), m.Parameter(0), m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+    if (base == 0) {
+      ASSERT_EQ(2U, s[0]->InputCount());
+    } else {
+      ASSERT_EQ(3U, s[0]->InputCount());
+      ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+      EXPECT_EQ(base, s.ToInt32(s[0]->InputAt(1)));
+    }
+    EXPECT_EQ(0U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
+    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
+            m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+    if (index == 0) {
+      ASSERT_EQ(2U, s[0]->InputCount());
+    } else {
+      ASSERT_EQ(3U, s[0]->InputCount());
+      ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+      EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    }
+    EXPECT_EQ(0U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessTest,
+                        ::testing::ValuesIn(kMemoryAccesses));
+
+
+// -----------------------------------------------------------------------------
+// AddressingMode for loads and stores.
+
+
+class AddressingModeUnitTest : public InstructionSelectorTest {
+ public:
+  AddressingModeUnitTest() : m(NULL) { Reset(); }
+  ~AddressingModeUnitTest() { delete m; }
+
+  void Run(Node* base, Node* load_index, Node* store_index,
+           AddressingMode mode) {
+    Node* load = m->Load(kMachInt32, base, load_index);
+    m->Store(kMachInt32, base, store_index, load);
+    m->Return(m->Int32Constant(0));
+    Stream s = m->Build();
+    ASSERT_EQ(2U, s.size());
+    EXPECT_EQ(mode, s[0]->addressing_mode());
+    EXPECT_EQ(mode, s[1]->addressing_mode());
+  }
+
+  Node* zero;
+  Node* null_ptr;
+  Node* non_zero;
+  Node* base_reg;   // opaque value to generate base as register
+  Node* index_reg;  // opaque value to generate index as register
+  Node* scales[4];
+  StreamBuilder* m;
+
+  void Reset() {
+    delete m;
+    m = new StreamBuilder(this, kMachInt32, kMachInt32, kMachInt32);
+    zero = m->Int32Constant(0);
+    null_ptr = m->Int32Constant(0);
+    non_zero = m->Int32Constant(127);
+    base_reg = m->Parameter(0);
+    index_reg = m->Parameter(0);
+
+    scales[0] = m->Int32Constant(1);
+    scales[1] = m->Int32Constant(2);
+    scales[2] = m->Int32Constant(4);
+    scales[3] = m->Int32Constant(8);
+  }
+};
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MR) {
+  Node* base = base_reg;
+  Node* index = zero;
+  Run(base, index, index, kMode_MR);
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MRI) {
+  Node* base = base_reg;
+  Node* index = non_zero;
+  Run(base, index, index, kMode_MRI);
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MR1) {
+  Node* base = base_reg;
+  Node* index = index_reg;
+  Run(base, index, index, kMode_MR1);
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MRN) {
+  AddressingMode expected[] = {kMode_MR1, kMode_MR2, kMode_MR4, kMode_MR8};
+  for (size_t i = 0; i < arraysize(scales); ++i) {
+    Reset();
+    Node* base = base_reg;
+    Node* load_index = m->Int32Mul(index_reg, scales[i]);
+    Node* store_index = m->Int32Mul(index_reg, scales[i]);
+    Run(base, load_index, store_index, expected[i]);
+  }
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MR1I) {
+  Node* base = base_reg;
+  Node* load_index = m->Int32Add(index_reg, non_zero);
+  Node* store_index = m->Int32Add(index_reg, non_zero);
+  Run(base, load_index, store_index, kMode_MR1I);
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MRNI) {
+  AddressingMode expected[] = {kMode_MR1I, kMode_MR2I, kMode_MR4I, kMode_MR8I};
+  for (size_t i = 0; i < arraysize(scales); ++i) {
+    Reset();
+    Node* base = base_reg;
+    Node* load_index = m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero);
+    Node* store_index =
+        m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero);
+    Run(base, load_index, store_index, expected[i]);
+  }
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_M1ToMR) {
+  Node* base = null_ptr;
+  Node* index = index_reg;
+  // M1 maps to MR
+  Run(base, index, index, kMode_MR);
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MN) {
+  AddressingMode expected[] = {kMode_MR, kMode_M2, kMode_M4, kMode_M8};
+  for (size_t i = 0; i < arraysize(scales); ++i) {
+    Reset();
+    Node* base = null_ptr;
+    Node* load_index = m->Int32Mul(index_reg, scales[i]);
+    Node* store_index = m->Int32Mul(index_reg, scales[i]);
+    Run(base, load_index, store_index, expected[i]);
+  }
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_M1IToMRI) {
+  Node* base = null_ptr;
+  Node* load_index = m->Int32Add(index_reg, non_zero);
+  Node* store_index = m->Int32Add(index_reg, non_zero);
+  // M1I maps to MRI
+  Run(base, load_index, store_index, kMode_MRI);
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MNI) {
+  AddressingMode expected[] = {kMode_MRI, kMode_M2I, kMode_M4I, kMode_M8I};
+  for (size_t i = 0; i < arraysize(scales); ++i) {
+    Reset();
+    Node* base = null_ptr;
+    Node* load_index = m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero);
+    Node* store_index =
+        m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero);
+    Run(base, load_index, store_index, expected[i]);
+  }
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MI) {
+  Node* bases[] = {null_ptr, non_zero};
+  Node* indices[] = {zero, non_zero};
+  for (size_t i = 0; i < arraysize(bases); ++i) {
+    for (size_t j = 0; j < arraysize(indices); ++j) {
+      Reset();
+      Node* base = bases[i];
+      Node* index = indices[j];
+      Run(base, index, index, kMode_MI);
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Multiplication.
+
+
+namespace {
+
+struct MultParam {
+  int value;
+  bool lea_expected;
+  AddressingMode addressing_mode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MultParam& m) {
+  return os << m.value << "." << m.lea_expected << "." << m.addressing_mode;
+}
+
+
+const MultParam kMultParams[] = {{-1, false, kMode_None},
+                                 {0, false, kMode_None},
+                                 {1, true, kMode_MR},
+                                 {2, true, kMode_M2},
+                                 {3, true, kMode_MR2},
+                                 {4, true, kMode_M4},
+                                 {5, true, kMode_MR4},
+                                 {6, false, kMode_None},
+                                 {7, false, kMode_None},
+                                 {8, true, kMode_M8},
+                                 {9, true, kMode_MR8},
+                                 {10, false, kMode_None},
+                                 {11, false, kMode_None}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<MultParam> InstructionSelectorMultTest;
+
+
+static unsigned InputCountForLea(AddressingMode mode) {
+  switch (mode) {
+    case kMode_MR1I:
+    case kMode_MR2I:
+    case kMode_MR4I:
+    case kMode_MR8I:
+      return 3U;
+    case kMode_M1I:
+    case kMode_M2I:
+    case kMode_M4I:
+    case kMode_M8I:
+      return 2U;
+    case kMode_MR1:
+    case kMode_MR2:
+    case kMode_MR4:
+    case kMode_MR8:
+    case kMode_MRI:
+      return 2U;
+    case kMode_M1:
+    case kMode_M2:
+    case kMode_M4:
+    case kMode_M8:
+    case kMode_MI:
+    case kMode_MR:
+      return 1U;
+    default:
+      UNREACHABLE();
+      return 0U;
+  }
+}
+
+
+static AddressingMode AddressingModeForAddMult(int32_t imm,
+                                               const MultParam& m) {
+  if (imm == 0) return m.addressing_mode;
+  switch (m.addressing_mode) {
+    case kMode_MR1:
+      return kMode_MR1I;
+    case kMode_MR2:
+      return kMode_MR2I;
+    case kMode_MR4:
+      return kMode_MR4I;
+    case kMode_MR8:
+      return kMode_MR8I;
+    case kMode_M1:
+      return kMode_M1I;
+    case kMode_M2:
+      return kMode_M2I;
+    case kMode_M4:
+      return kMode_M4I;
+    case kMode_M8:
+      return kMode_M8I;
+    case kMode_MR:
+      return kMode_MRI;
+    default:
+      UNREACHABLE();
+      return kMode_None;
+  }
+}
+
+
+TEST_P(InstructionSelectorMultTest, Mult32) {
+  const MultParam m_param = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* param = m.Parameter(0);
+  Node* mult = m.Int32Mul(param, m.Int32Constant(m_param.value));
+  m.Return(mult);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(m_param.addressing_mode, s[0]->addressing_mode());
+  if (m_param.lea_expected) {
+    EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
+    ASSERT_EQ(InputCountForLea(s[0]->addressing_mode()), s[0]->InputCount());
+  } else {
+    EXPECT_EQ(kIA32Imul, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+  }
+  EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_P(InstructionSelectorMultTest, MultAdd32) {
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    const MultParam m_param = GetParam();
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* param = m.Parameter(0);
+    Node* mult = m.Int32Add(m.Int32Mul(param, m.Int32Constant(m_param.value)),
+                            m.Int32Constant(imm));
+    m.Return(mult);
+    Stream s = m.Build();
+    if (m_param.lea_expected) {
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
+      EXPECT_EQ(AddressingModeForAddMult(imm, m_param),
+                s[0]->addressing_mode());
+      unsigned input_count = InputCountForLea(s[0]->addressing_mode());
+      ASSERT_EQ(input_count, s[0]->InputCount());
+      if (imm != 0) {
+        ASSERT_EQ(InstructionOperand::IMMEDIATE,
+                  s[0]->InputAt(input_count - 1)->kind());
+        EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(input_count - 1)));
+      }
+    } else {
+      ASSERT_EQ(2U, s.size());
+      EXPECT_EQ(kIA32Imul, s[0]->arch_opcode());
+      EXPECT_EQ(kIA32Lea, s[1]->arch_opcode());
+    }
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMultTest,
+                        ::testing::ValuesIn(kMultParams));
+
+
+TEST_F(InstructionSelectorTest, Int32MulHigh) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Int32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kIA32ImulHigh, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), eax));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), edx));
+}
+
+
+TEST_F(InstructionSelectorTest, Float64BinopArithmetic) {
+  {
+    StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64);
+    Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1));
+    Node* mul = m.Float64Mul(add, m.Parameter(1));
+    Node* sub = m.Float64Sub(mul, add);
+    Node* ret = m.Float64Div(mul, sub);
+    m.Return(ret);
+    Stream s = m.Build(AVX);
+    ASSERT_EQ(4U, s.size());
+    EXPECT_EQ(kAVXFloat64Add, s[0]->arch_opcode());
+    EXPECT_EQ(kAVXFloat64Mul, s[1]->arch_opcode());
+    EXPECT_EQ(kAVXFloat64Sub, s[2]->arch_opcode());
+    EXPECT_EQ(kAVXFloat64Div, s[3]->arch_opcode());
+  }
+  {
+    StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64);
+    Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1));
+    Node* mul = m.Float64Mul(add, m.Parameter(1));
+    Node* sub = m.Float64Sub(mul, add);
+    Node* ret = m.Float64Div(mul, sub);
+    m.Return(ret);
+    Stream s = m.Build();
+    ASSERT_EQ(4U, s.size());
+    EXPECT_EQ(kSSEFloat64Add, s[0]->arch_opcode());
+    EXPECT_EQ(kSSEFloat64Mul, s[1]->arch_opcode());
+    EXPECT_EQ(kSSEFloat64Sub, s[2]->arch_opcode());
+    EXPECT_EQ(kSSEFloat64Div, s[3]->arch_opcode());
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/instruction-selector-unittest.cc b/test/unittests/compiler/instruction-selector-unittest.cc
new file mode 100644
index 0000000..c79a9e4
--- /dev/null
+++ b/test/unittests/compiler/instruction-selector-unittest.cc
@@ -0,0 +1,589 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/compiler/instruction-selector-unittest.h"
+
+#include "src/compiler/graph-inl.h"
+#include "src/flags.h"
+#include "test/unittests/compiler/compiler-test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+typedef RawMachineAssembler::Label MLabel;
+
+}  // namespace
+
+
+InstructionSelectorTest::InstructionSelectorTest() : rng_(FLAG_random_seed) {}
+
+
+InstructionSelectorTest::~InstructionSelectorTest() {}
+
+
+InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
+    InstructionSelector::Features features,
+    InstructionSelectorTest::StreamBuilderMode mode) {
+  Schedule* schedule = Export();
+  if (FLAG_trace_turbo) {
+    OFStream out(stdout);
+    out << "=== Schedule before instruction selection ===" << std::endl
+        << *schedule;
+  }
+  EXPECT_NE(0, graph()->NodeCount());
+  int initial_node_count = graph()->NodeCount();
+  Linkage linkage(test_->zone(), call_descriptor());
+  InstructionBlocks* instruction_blocks =
+      InstructionSequence::InstructionBlocksFor(test_->zone(), schedule);
+  InstructionSequence sequence(test_->zone(), instruction_blocks);
+  SourcePositionTable source_position_table(graph());
+  InstructionSelector selector(test_->zone(), graph(), &linkage, &sequence,
+                               schedule, &source_position_table, features);
+  selector.SelectInstructions();
+  if (FLAG_trace_turbo) {
+    OFStream out(stdout);
+    PrintableInstructionSequence printable = {
+        RegisterConfiguration::ArchDefault(), &sequence};
+    out << "=== Code sequence after instruction selection ===" << std::endl
+        << printable;
+  }
+  Stream s;
+  // Map virtual registers.
+  {
+    const NodeToVregMap& node_map = selector.GetNodeMapForTesting();
+    for (int i = 0; i < initial_node_count; ++i) {
+      if (node_map[i] != InstructionSelector::kNodeUnmapped) {
+        s.virtual_registers_.insert(std::make_pair(i, node_map[i]));
+      }
+    }
+  }
+  std::set<int> virtual_registers;
+  for (InstructionSequence::const_iterator i = sequence.begin();
+       i != sequence.end(); ++i) {
+    Instruction* instr = *i;
+    if (instr->opcode() < 0) continue;
+    if (mode == kTargetInstructions) {
+      switch (instr->arch_opcode()) {
+#define CASE(Name) \
+  case k##Name:    \
+    break;
+        TARGET_ARCH_OPCODE_LIST(CASE)
+#undef CASE
+        default:
+          continue;
+      }
+    }
+    if (mode == kAllExceptNopInstructions && instr->arch_opcode() == kArchNop) {
+      continue;
+    }
+    for (size_t i = 0; i < instr->OutputCount(); ++i) {
+      InstructionOperand* output = instr->OutputAt(i);
+      EXPECT_NE(InstructionOperand::IMMEDIATE, output->kind());
+      if (output->IsConstant()) {
+        s.constants_.insert(std::make_pair(
+            output->index(), sequence.GetConstant(output->index())));
+        virtual_registers.insert(output->index());
+      } else if (output->IsUnallocated()) {
+        virtual_registers.insert(
+            UnallocatedOperand::cast(output)->virtual_register());
+      }
+    }
+    for (size_t i = 0; i < instr->InputCount(); ++i) {
+      InstructionOperand* input = instr->InputAt(i);
+      EXPECT_NE(InstructionOperand::CONSTANT, input->kind());
+      if (input->IsImmediate()) {
+        s.immediates_.insert(std::make_pair(
+            input->index(), sequence.GetImmediate(input->index())));
+      } else if (input->IsUnallocated()) {
+        virtual_registers.insert(
+            UnallocatedOperand::cast(input)->virtual_register());
+      }
+    }
+    s.instructions_.push_back(instr);
+  }
+  for (std::set<int>::const_iterator i = virtual_registers.begin();
+       i != virtual_registers.end(); ++i) {
+    int virtual_register = *i;
+    if (sequence.IsDouble(virtual_register)) {
+      EXPECT_FALSE(sequence.IsReference(virtual_register));
+      s.doubles_.insert(virtual_register);
+    }
+    if (sequence.IsReference(virtual_register)) {
+      EXPECT_FALSE(sequence.IsDouble(virtual_register));
+      s.references_.insert(virtual_register);
+    }
+  }
+  for (int i = 0; i < sequence.GetFrameStateDescriptorCount(); i++) {
+    s.deoptimization_entries_.push_back(sequence.GetFrameStateDescriptor(
+        InstructionSequence::StateId::FromInt(i)));
+  }
+  return s;
+}
+
+
+int InstructionSelectorTest::Stream::ToVreg(const Node* node) const {
+  VirtualRegisters::const_iterator i = virtual_registers_.find(node->id());
+  CHECK(i != virtual_registers_.end());
+  return i->second;
+}
+
+
+bool InstructionSelectorTest::Stream::IsFixed(const InstructionOperand* operand,
+                                              Register reg) const {
+  if (!operand->IsUnallocated()) return false;
+  const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand);
+  if (!unallocated->HasFixedRegisterPolicy()) return false;
+  const int index = Register::ToAllocationIndex(reg);
+  return unallocated->fixed_register_index() == index;
+}
+
+
+bool InstructionSelectorTest::Stream::IsSameAsFirst(
+    const InstructionOperand* operand) const {
+  if (!operand->IsUnallocated()) return false;
+  const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand);
+  return unallocated->HasSameAsInputPolicy();
+}
+
+
+bool InstructionSelectorTest::Stream::IsUsedAtStart(
+    const InstructionOperand* operand) const {
+  if (!operand->IsUnallocated()) return false;
+  const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand);
+  return unallocated->IsUsedAtStart();
+}
+
+
+// -----------------------------------------------------------------------------
+// Return.
+
+
+TARGET_TEST_F(InstructionSelectorTest, ReturnFloat32Constant) {
+  const float kValue = 4.2f;
+  StreamBuilder m(this, kMachFloat32);
+  m.Return(m.Float32Constant(kValue));
+  Stream s = m.Build(kAllInstructions);
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
+  ASSERT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind());
+  EXPECT_FLOAT_EQ(kValue, s.ToFloat32(s[0]->OutputAt(0)));
+  EXPECT_EQ(kArchRet, s[1]->arch_opcode());
+  EXPECT_EQ(1U, s[1]->InputCount());
+}
+
+
+TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  m.Return(m.Parameter(0));
+  Stream s = m.Build(kAllInstructions);
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArchRet, s[1]->arch_opcode());
+  EXPECT_EQ(1U, s[1]->InputCount());
+}
+
+
+TARGET_TEST_F(InstructionSelectorTest, ReturnZero) {
+  StreamBuilder m(this, kMachInt32);
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build(kAllInstructions);
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind());
+  EXPECT_EQ(0, s.ToInt32(s[0]->OutputAt(0)));
+  EXPECT_EQ(kArchRet, s[1]->arch_opcode());
+  EXPECT_EQ(1U, s[1]->InputCount());
+}
+
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+
+TARGET_TEST_F(InstructionSelectorTest, TruncateFloat64ToInt32WithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachFloat64);
+  m.Return(m.TruncateFloat64ToInt32(m.Parameter(0)));
+  Stream s = m.Build(kAllInstructions);
+  ASSERT_EQ(3U, s.size());
+  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
+  EXPECT_EQ(kArchTruncateDoubleToI, s[1]->arch_opcode());
+  EXPECT_EQ(1U, s[1]->InputCount());
+  EXPECT_EQ(1U, s[1]->OutputCount());
+  EXPECT_EQ(kArchRet, s[2]->arch_opcode());
+}
+
+
+// -----------------------------------------------------------------------------
+// Parameters.
+
+
+TARGET_TEST_F(InstructionSelectorTest, DoubleParameter) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat64);
+  Node* param = m.Parameter(0);
+  m.Return(param);
+  Stream s = m.Build(kAllInstructions);
+  EXPECT_TRUE(s.IsDouble(param));
+}
+
+
+TARGET_TEST_F(InstructionSelectorTest, ReferenceParameter) {
+  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged);
+  Node* param = m.Parameter(0);
+  m.Return(param);
+  Stream s = m.Build(kAllInstructions);
+  EXPECT_TRUE(s.IsReference(param));
+}
+
+
+// -----------------------------------------------------------------------------
+// Finish.
+
+
+TARGET_TEST_F(InstructionSelectorTest, Finish) {
+  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged);
+  Node* param = m.Parameter(0);
+  Node* finish = m.NewNode(m.common()->Finish(1), param, m.graph()->start());
+  m.Return(finish);
+  Stream s = m.Build(kAllInstructions);
+  ASSERT_EQ(3U, s.size());
+  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  ASSERT_TRUE(s[0]->Output()->IsUnallocated());
+  EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->Output()));
+  EXPECT_EQ(kArchNop, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->InputCount());
+  ASSERT_TRUE(s[1]->InputAt(0)->IsUnallocated());
+  EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[1]->InputAt(0)));
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  ASSERT_TRUE(s[1]->Output()->IsUnallocated());
+  EXPECT_TRUE(UnallocatedOperand::cast(s[1]->Output())->HasSameAsInputPolicy());
+  EXPECT_EQ(s.ToVreg(finish), s.ToVreg(s[1]->Output()));
+  EXPECT_TRUE(s.IsReference(finish));
+}
+
+
+// -----------------------------------------------------------------------------
+// Phi.
+
+
+typedef InstructionSelectorTestWithParam<MachineType>
+    InstructionSelectorPhiTest;
+
+
+TARGET_TEST_P(InstructionSelectorPhiTest, Doubleness) {
+  const MachineType type = GetParam();
+  StreamBuilder m(this, type, type, type);
+  Node* param0 = m.Parameter(0);
+  Node* param1 = m.Parameter(1);
+  MLabel a, b, c;
+  m.Branch(m.Int32Constant(0), &a, &b);
+  m.Bind(&a);
+  m.Goto(&c);
+  m.Bind(&b);
+  m.Goto(&c);
+  m.Bind(&c);
+  Node* phi = m.Phi(type, param0, param1);
+  m.Return(phi);
+  Stream s = m.Build(kAllInstructions);
+  EXPECT_EQ(s.IsDouble(phi), s.IsDouble(param0));
+  EXPECT_EQ(s.IsDouble(phi), s.IsDouble(param1));
+}
+
+
+TARGET_TEST_P(InstructionSelectorPhiTest, Referenceness) {
+  const MachineType type = GetParam();
+  StreamBuilder m(this, type, type, type);
+  Node* param0 = m.Parameter(0);
+  Node* param1 = m.Parameter(1);
+  MLabel a, b, c;
+  m.Branch(m.Int32Constant(1), &a, &b);
+  m.Bind(&a);
+  m.Goto(&c);
+  m.Bind(&b);
+  m.Goto(&c);
+  m.Bind(&c);
+  Node* phi = m.Phi(type, param0, param1);
+  m.Return(phi);
+  Stream s = m.Build(kAllInstructions);
+  EXPECT_EQ(s.IsReference(phi), s.IsReference(param0));
+  EXPECT_EQ(s.IsReference(phi), s.IsReference(param1));
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorPhiTest,
+                        ::testing::Values(kMachFloat64, kMachInt8, kMachUint8,
+                                          kMachInt16, kMachUint16, kMachInt32,
+                                          kMachUint32, kMachInt64, kMachUint64,
+                                          kMachPtr, kMachAnyTagged));
+
+
+// -----------------------------------------------------------------------------
+// ValueEffect.
+
+
+TARGET_TEST_F(InstructionSelectorTest, ValueEffect) {
+  StreamBuilder m1(this, kMachInt32, kMachPtr);
+  Node* p1 = m1.Parameter(0);
+  m1.Return(m1.Load(kMachInt32, p1, m1.Int32Constant(0)));
+  Stream s1 = m1.Build(kAllInstructions);
+  StreamBuilder m2(this, kMachInt32, kMachPtr);
+  Node* p2 = m2.Parameter(0);
+  m2.Return(m2.NewNode(m2.machine()->Load(kMachInt32), p2, m2.Int32Constant(0),
+                       m2.NewNode(m2.common()->ValueEffect(1), p2)));
+  Stream s2 = m2.Build(kAllInstructions);
+  EXPECT_LE(3U, s1.size());
+  ASSERT_EQ(s1.size(), s2.size());
+  TRACED_FORRANGE(size_t, i, 0, s1.size() - 1) {
+    const Instruction* i1 = s1[i];
+    const Instruction* i2 = s2[i];
+    EXPECT_EQ(i1->arch_opcode(), i2->arch_opcode());
+    EXPECT_EQ(i1->InputCount(), i2->InputCount());
+    EXPECT_EQ(i1->OutputCount(), i2->OutputCount());
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Calls with deoptimization.
+
+
+TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
+  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
+                  kMachAnyTagged);
+
+  BailoutId bailout_id(42);
+
+  Node* function_node = m.Parameter(0);
+  Node* receiver = m.Parameter(1);
+  Node* context = m.Parameter(2);
+
+  Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(1));
+  Node* locals = m.NewNode(m.common()->StateValues(0));
+  Node* stack = m.NewNode(m.common()->StateValues(0));
+  Node* context_dummy = m.Int32Constant(0);
+
+  Node* state_node = m.NewNode(
+      m.common()->FrameState(JS_FRAME, bailout_id,
+                             OutputFrameStateCombine::Push()),
+      parameters, locals, stack, context_dummy, m.UndefinedConstant());
+  Node* call = m.CallJS0(function_node, receiver, context, state_node);
+  m.Return(call);
+
+  Stream s = m.Build(kAllExceptNopInstructions);
+
+  // Skip until kArchCallJSFunction.
+  size_t index = 0;
+  for (; index < s.size() && s[index]->arch_opcode() != kArchCallJSFunction;
+       index++) {
+  }
+  // Now we should have two instructions: call and return.
+  ASSERT_EQ(index + 2, s.size());
+
+  EXPECT_EQ(kArchCallJSFunction, s[index++]->arch_opcode());
+  EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
+
+  // TODO(jarin) Check deoptimization table.
+}
+
+
+TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
+  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
+                  kMachAnyTagged);
+
+  BailoutId bailout_id_before(42);
+
+  // Some arguments for the call node.
+  Node* function_node = m.Parameter(0);
+  Node* receiver = m.Parameter(1);
+  Node* context = m.Int32Constant(1);  // Context is ignored.
+
+  // Build frame state for the state before the call.
+  Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
+  Node* locals = m.NewNode(m.common()->StateValues(1), m.Float64Constant(0.5));
+  Node* stack = m.NewNode(m.common()->StateValues(1), m.UndefinedConstant());
+
+  Node* context_sentinel = m.Int32Constant(0);
+  Node* frame_state_before = m.NewNode(
+      m.common()->FrameState(JS_FRAME, bailout_id_before,
+                             OutputFrameStateCombine::Push()),
+      parameters, locals, stack, context_sentinel, m.UndefinedConstant());
+
+  // Build the call.
+  Node* call = m.CallFunctionStub0(function_node, receiver, context,
+                                   frame_state_before, CALL_AS_METHOD);
+
+  m.Return(call);
+
+  Stream s = m.Build(kAllExceptNopInstructions);
+
+  // Skip until kArchCallJSFunction.
+  size_t index = 0;
+  for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject;
+       index++) {
+  }
+  // Now we should have two instructions: call, return.
+  ASSERT_EQ(index + 2, s.size());
+
+  // Check the call instruction
+  const Instruction* call_instr = s[index++];
+  EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode());
+  size_t num_operands =
+      1 +  // Code object.
+      1 +
+      4 +  // Frame state deopt id + one input for each value in frame state.
+      1 +  // Function.
+      1;   // Context.
+  ASSERT_EQ(num_operands, call_instr->InputCount());
+
+  // Code object.
+  EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate());
+
+  // Deoptimization id.
+  int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1));
+  FrameStateDescriptor* desc_before =
+      s.GetFrameStateDescriptor(deopt_id_before);
+  EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
+  EXPECT_EQ(OutputFrameStateCombine::kPushOutput,
+            desc_before->state_combine().kind());
+  EXPECT_EQ(1u, desc_before->parameters_count());
+  EXPECT_EQ(1u, desc_before->locals_count());
+  EXPECT_EQ(1u, desc_before->stack_count());
+  EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2)));
+  EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3)));  // This should be a context.
+                                                    // We inserted 0 here.
+  EXPECT_EQ(0.5, s.ToFloat64(call_instr->InputAt(4)));
+  EXPECT_TRUE(s.ToHeapObject(call_instr->InputAt(5))->IsUndefined());
+  EXPECT_EQ(kMachInt32, desc_before->GetType(0));
+  EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1));  // context is always
+                                                       // tagged/any.
+  EXPECT_EQ(kMachFloat64, desc_before->GetType(2));
+  EXPECT_EQ(kMachAnyTagged, desc_before->GetType(3));
+
+  // Function.
+  EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(6)));
+  // Context.
+  EXPECT_EQ(s.ToVreg(context), s.ToVreg(call_instr->InputAt(7)));
+
+  EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
+
+  EXPECT_EQ(index, s.size());
+}
+
+
+TARGET_TEST_F(InstructionSelectorTest,
+              CallFunctionStubDeoptRecursiveFrameState) {
+  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
+                  kMachAnyTagged);
+
+  BailoutId bailout_id_before(42);
+  BailoutId bailout_id_parent(62);
+
+  // Some arguments for the call node.
+  Node* function_node = m.Parameter(0);
+  Node* receiver = m.Parameter(1);
+  Node* context = m.Int32Constant(66);
+
+  // Build frame state for the state before the call.
+  Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63));
+  Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64));
+  Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65));
+  Node* frame_state_parent =
+      m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_parent,
+                                       OutputFrameStateCombine::Ignore()),
+                parameters, locals, stack, context, m.UndefinedConstant());
+
+  Node* context2 = m.Int32Constant(46);
+  Node* parameters2 =
+      m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
+  Node* locals2 =
+      m.NewNode(m.common()->StateValues(1), m.Float64Constant(0.25));
+  Node* stack2 = m.NewNode(m.common()->StateValues(2), m.Int32Constant(44),
+                           m.Int32Constant(45));
+  Node* frame_state_before =
+      m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before,
+                                       OutputFrameStateCombine::Push()),
+                parameters2, locals2, stack2, context2, frame_state_parent);
+
+  // Build the call.
+  Node* call = m.CallFunctionStub0(function_node, receiver, context2,
+                                   frame_state_before, CALL_AS_METHOD);
+
+  m.Return(call);
+
+  Stream s = m.Build(kAllExceptNopInstructions);
+
+  // Skip until kArchCallJSFunction.
+  size_t index = 0;
+  for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject;
+       index++) {
+  }
+  // Now we should have three instructions: call, return.
+  EXPECT_EQ(index + 2, s.size());
+
+  // Check the call instruction
+  const Instruction* call_instr = s[index++];
+  EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode());
+  size_t num_operands =
+      1 +  // Code object.
+      1 +  // Frame state deopt id
+      5 +  // One input for each value in frame state + context.
+      4 +  // One input for each value in the parent frame state + context.
+      1 +  // Function.
+      1;   // Context.
+  EXPECT_EQ(num_operands, call_instr->InputCount());
+  // Code object.
+  EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate());
+
+  // Deoptimization id.
+  int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1));
+  FrameStateDescriptor* desc_before =
+      s.GetFrameStateDescriptor(deopt_id_before);
+  FrameStateDescriptor* desc_before_outer = desc_before->outer_state();
+  EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
+  EXPECT_EQ(1u, desc_before_outer->parameters_count());
+  EXPECT_EQ(1u, desc_before_outer->locals_count());
+  EXPECT_EQ(1u, desc_before_outer->stack_count());
+  // Values from parent environment.
+  EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2)));
+  EXPECT_EQ(kMachInt32, desc_before_outer->GetType(0));
+  // Context:
+  EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(3)));
+  EXPECT_EQ(kMachAnyTagged, desc_before_outer->GetType(1));
+  EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(4)));
+  EXPECT_EQ(kMachInt32, desc_before_outer->GetType(2));
+  EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(5)));
+  EXPECT_EQ(kMachInt32, desc_before_outer->GetType(3));
+  // Values from the nested frame.
+  EXPECT_EQ(1u, desc_before->parameters_count());
+  EXPECT_EQ(1u, desc_before->locals_count());
+  EXPECT_EQ(2u, desc_before->stack_count());
+  EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(6)));
+  EXPECT_EQ(kMachInt32, desc_before->GetType(0));
+  EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(7)));
+  EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1));
+  EXPECT_EQ(0.25, s.ToFloat64(call_instr->InputAt(8)));
+  EXPECT_EQ(kMachFloat64, desc_before->GetType(2));
+  EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(9)));
+  EXPECT_EQ(kMachInt32, desc_before->GetType(3));
+  EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(10)));
+  EXPECT_EQ(kMachInt32, desc_before->GetType(4));
+
+  // Function.
+  EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(11)));
+  // Context.
+  EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(12)));
+  // Continuation.
+
+  EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
+  EXPECT_EQ(index, s.size());
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/instruction-selector-unittest.h b/test/unittests/compiler/instruction-selector-unittest.h
new file mode 100644
index 0000000..e65d68b
--- /dev/null
+++ b/test/unittests/compiler/instruction-selector-unittest.h
@@ -0,0 +1,241 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
+#define V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
+
+#include <deque>
+#include <set>
+
+#include "src/base/utils/random-number-generator.h"
+#include "src/compiler/instruction-selector.h"
+#include "src/compiler/raw-machine-assembler.h"
+#include "src/macro-assembler.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class InstructionSelectorTest : public TestWithContext, public TestWithZone {
+ public:
+  InstructionSelectorTest();
+  ~InstructionSelectorTest() OVERRIDE;
+
+  base::RandomNumberGenerator* rng() { return &rng_; }
+
+  class Stream;
+
+  enum StreamBuilderMode {
+    kAllInstructions,
+    kTargetInstructions,
+    kAllExceptNopInstructions
+  };
+
+  class StreamBuilder FINAL : public RawMachineAssembler {
+   public:
+    StreamBuilder(InstructionSelectorTest* test, MachineType return_type)
+        : RawMachineAssembler(new (test->zone()) Graph(test->zone()),
+                              MakeMachineSignature(test->zone(), return_type)),
+          test_(test) {}
+    StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
+                  MachineType parameter0_type)
+        : RawMachineAssembler(
+              new (test->zone()) Graph(test->zone()),
+              MakeMachineSignature(test->zone(), return_type, parameter0_type)),
+          test_(test) {}
+    StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
+                  MachineType parameter0_type, MachineType parameter1_type)
+        : RawMachineAssembler(
+              new (test->zone()) Graph(test->zone()),
+              MakeMachineSignature(test->zone(), return_type, parameter0_type,
+                                   parameter1_type)),
+          test_(test) {}
+    StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
+                  MachineType parameter0_type, MachineType parameter1_type,
+                  MachineType parameter2_type)
+        : RawMachineAssembler(
+              new (test->zone()) Graph(test->zone()),
+              MakeMachineSignature(test->zone(), return_type, parameter0_type,
+                                   parameter1_type, parameter2_type)),
+          test_(test) {}
+
+    Stream Build(CpuFeature feature) {
+      return Build(InstructionSelector::Features(feature));
+    }
+    Stream Build(CpuFeature feature1, CpuFeature feature2) {
+      return Build(InstructionSelector::Features(feature1, feature2));
+    }
+    Stream Build(StreamBuilderMode mode = kTargetInstructions) {
+      return Build(InstructionSelector::Features(), mode);
+    }
+    Stream Build(InstructionSelector::Features features,
+                 StreamBuilderMode mode = kTargetInstructions);
+
+   private:
+    MachineSignature* MakeMachineSignature(Zone* zone,
+                                           MachineType return_type) {
+      MachineSignature::Builder builder(zone, 1, 0);
+      builder.AddReturn(return_type);
+      return builder.Build();
+    }
+
+    MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
+                                           MachineType parameter0_type) {
+      MachineSignature::Builder builder(zone, 1, 1);
+      builder.AddReturn(return_type);
+      builder.AddParam(parameter0_type);
+      return builder.Build();
+    }
+
+    MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
+                                           MachineType parameter0_type,
+                                           MachineType parameter1_type) {
+      MachineSignature::Builder builder(zone, 1, 2);
+      builder.AddReturn(return_type);
+      builder.AddParam(parameter0_type);
+      builder.AddParam(parameter1_type);
+      return builder.Build();
+    }
+
+    MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
+                                           MachineType parameter0_type,
+                                           MachineType parameter1_type,
+                                           MachineType parameter2_type) {
+      MachineSignature::Builder builder(zone, 1, 3);
+      builder.AddReturn(return_type);
+      builder.AddParam(parameter0_type);
+      builder.AddParam(parameter1_type);
+      builder.AddParam(parameter2_type);
+      return builder.Build();
+    }
+
+   private:
+    InstructionSelectorTest* test_;
+  };
+
+  class Stream FINAL {
+   public:
+    size_t size() const { return instructions_.size(); }
+    const Instruction* operator[](size_t index) const {
+      EXPECT_LT(index, size());
+      return instructions_[index];
+    }
+
+    bool IsDouble(const InstructionOperand* operand) const {
+      return IsDouble(ToVreg(operand));
+    }
+
+    bool IsDouble(const Node* node) const { return IsDouble(ToVreg(node)); }
+
+    bool IsInteger(const InstructionOperand* operand) const {
+      return IsInteger(ToVreg(operand));
+    }
+
+    bool IsInteger(const Node* node) const { return IsInteger(ToVreg(node)); }
+
+    bool IsReference(const InstructionOperand* operand) const {
+      return IsReference(ToVreg(operand));
+    }
+
+    bool IsReference(const Node* node) const {
+      return IsReference(ToVreg(node));
+    }
+
+    float ToFloat32(const InstructionOperand* operand) const {
+      return ToConstant(operand).ToFloat32();
+    }
+
+    double ToFloat64(const InstructionOperand* operand) const {
+      return ToConstant(operand).ToFloat64();
+    }
+
+    int32_t ToInt32(const InstructionOperand* operand) const {
+      return ToConstant(operand).ToInt32();
+    }
+
+    int64_t ToInt64(const InstructionOperand* operand) const {
+      return ToConstant(operand).ToInt64();
+    }
+
+    Handle<HeapObject> ToHeapObject(const InstructionOperand* operand) const {
+      return ToConstant(operand).ToHeapObject();
+    }
+
+    int ToVreg(const InstructionOperand* operand) const {
+      if (operand->IsConstant()) return operand->index();
+      EXPECT_EQ(InstructionOperand::UNALLOCATED, operand->kind());
+      return UnallocatedOperand::cast(operand)->virtual_register();
+    }
+
+    int ToVreg(const Node* node) const;
+
+    bool IsFixed(const InstructionOperand* operand, Register reg) const;
+    bool IsSameAsFirst(const InstructionOperand* operand) const;
+    bool IsUsedAtStart(const InstructionOperand* operand) const;
+
+    FrameStateDescriptor* GetFrameStateDescriptor(int deoptimization_id) {
+      EXPECT_LT(deoptimization_id, GetFrameStateDescriptorCount());
+      return deoptimization_entries_[deoptimization_id];
+    }
+
+    int GetFrameStateDescriptorCount() {
+      return static_cast<int>(deoptimization_entries_.size());
+    }
+
+   private:
+    bool IsDouble(int virtual_register) const {
+      return doubles_.find(virtual_register) != doubles_.end();
+    }
+
+    bool IsInteger(int virtual_register) const {
+      return !IsDouble(virtual_register) && !IsReference(virtual_register);
+    }
+
+    bool IsReference(int virtual_register) const {
+      return references_.find(virtual_register) != references_.end();
+    }
+
+    Constant ToConstant(const InstructionOperand* operand) const {
+      ConstantMap::const_iterator i;
+      if (operand->IsConstant()) {
+        i = constants_.find(operand->index());
+        EXPECT_FALSE(constants_.end() == i);
+      } else {
+        EXPECT_EQ(InstructionOperand::IMMEDIATE, operand->kind());
+        i = immediates_.find(operand->index());
+        EXPECT_FALSE(immediates_.end() == i);
+      }
+      EXPECT_EQ(operand->index(), i->first);
+      return i->second;
+    }
+
+    friend class StreamBuilder;
+
+    typedef std::map<int, Constant> ConstantMap;
+    typedef std::map<NodeId, int> VirtualRegisters;
+
+    ConstantMap constants_;
+    ConstantMap immediates_;
+    std::deque<Instruction*> instructions_;
+    std::set<int> doubles_;
+    std::set<int> references_;
+    VirtualRegisters virtual_registers_;
+    std::deque<FrameStateDescriptor*> deoptimization_entries_;
+  };
+
+  base::RandomNumberGenerator rng_;
+};
+
+
+template <typename T>
+class InstructionSelectorTestWithParam
+    : public InstructionSelectorTest,
+      public ::testing::WithParamInterface<T> {};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
diff --git a/test/unittests/compiler/instruction-sequence-unittest.cc b/test/unittests/compiler/instruction-sequence-unittest.cc
new file mode 100644
index 0000000..9546376
--- /dev/null
+++ b/test/unittests/compiler/instruction-sequence-unittest.cc
@@ -0,0 +1,475 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/utils/random-number-generator.h"
+#include "src/compiler/pipeline.h"
+#include "test/unittests/compiler/instruction-sequence-unittest.h"
+#include "test/unittests/test-utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+static const char*
+    general_register_names_[RegisterConfiguration::kMaxGeneralRegisters];
+static const char*
+    double_register_names_[RegisterConfiguration::kMaxDoubleRegisters];
+static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters +
+                                  RegisterConfiguration::kMaxDoubleRegisters)];
+
+
+static void InitializeRegisterNames() {
+  char* loc = register_names_;
+  for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) {
+    general_register_names_[i] = loc;
+    loc += base::OS::SNPrintF(loc, 100, "gp_%d", i);
+    *loc++ = 0;
+  }
+  for (int i = 0; i < RegisterConfiguration::kMaxDoubleRegisters; ++i) {
+    double_register_names_[i] = loc;
+    loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1;
+    *loc++ = 0;
+  }
+}
+
+
+InstructionSequenceTest::InstructionSequenceTest()
+    : sequence_(nullptr),
+      num_general_registers_(kDefaultNRegs),
+      num_double_registers_(kDefaultNRegs),
+      instruction_blocks_(zone()),
+      current_instruction_index_(-1),
+      current_block_(nullptr),
+      block_returns_(false) {
+  InitializeRegisterNames();
+}
+
+
+void InstructionSequenceTest::SetNumRegs(int num_general_registers,
+                                         int num_double_registers) {
+  CHECK(config_.is_empty());
+  CHECK(instructions_.empty());
+  CHECK(instruction_blocks_.empty());
+  num_general_registers_ = num_general_registers;
+  num_double_registers_ = num_double_registers;
+}
+
+
+RegisterConfiguration* InstructionSequenceTest::config() {
+  if (config_.is_empty()) {
+    config_.Reset(new RegisterConfiguration(
+        num_general_registers_, num_double_registers_, num_double_registers_,
+        general_register_names_, double_register_names_));
+  }
+  return config_.get();
+}
+
+
+InstructionSequence* InstructionSequenceTest::sequence() {
+  if (sequence_ == nullptr) {
+    sequence_ = new (zone()) InstructionSequence(zone(), &instruction_blocks_);
+  }
+  return sequence_;
+}
+
+
+void InstructionSequenceTest::StartLoop(int loop_blocks) {
+  CHECK(current_block_ == nullptr);
+  if (!loop_blocks_.empty()) {
+    CHECK(!loop_blocks_.back().loop_header_.IsValid());
+  }
+  LoopData loop_data = {Rpo::Invalid(), loop_blocks};
+  loop_blocks_.push_back(loop_data);
+}
+
+
+void InstructionSequenceTest::EndLoop() {
+  CHECK(current_block_ == nullptr);
+  CHECK(!loop_blocks_.empty());
+  CHECK_EQ(0, loop_blocks_.back().expected_blocks_);
+  loop_blocks_.pop_back();
+}
+
+
+void InstructionSequenceTest::StartBlock() {
+  block_returns_ = false;
+  NewBlock();
+}
+
+
+int InstructionSequenceTest::EndBlock(BlockCompletion completion) {
+  int instruction_index = kMinInt;
+  if (block_returns_) {
+    CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough);
+    completion.type_ = kBlockEnd;
+  }
+  switch (completion.type_) {
+    case kBlockEnd:
+      break;
+    case kFallThrough:
+      instruction_index = EmitFallThrough();
+      break;
+    case kJump:
+      CHECK(!block_returns_);
+      instruction_index = EmitJump();
+      break;
+    case kBranch:
+      CHECK(!block_returns_);
+      instruction_index = EmitBranch(completion.op_);
+      break;
+  }
+  completions_.push_back(completion);
+  CHECK(current_block_ != nullptr);
+  sequence()->EndBlock(current_block_->rpo_number());
+  current_block_ = nullptr;
+  return instruction_index;
+}
+
+
+InstructionSequenceTest::TestOperand InstructionSequenceTest::Imm(int32_t imm) {
+  int index = sequence()->AddImmediate(Constant(imm));
+  return TestOperand(kImmediate, index);
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::Define(
+    TestOperand output_op) {
+  VReg vreg = NewReg();
+  InstructionOperand* outputs[1]{ConvertOutputOp(vreg, output_op)};
+  Emit(vreg.value_, kArchNop, 1, outputs);
+  return vreg;
+}
+
+
+int InstructionSequenceTest::Return(TestOperand input_op_0) {
+  block_returns_ = true;
+  InstructionOperand* inputs[1]{ConvertInputOp(input_op_0)};
+  return Emit(NewIndex(), kArchRet, 0, nullptr, 1, inputs);
+}
+
+
+PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0,
+                                             VReg incoming_vreg_1,
+                                             VReg incoming_vreg_2,
+                                             VReg incoming_vreg_3) {
+  auto phi = new (zone()) PhiInstruction(zone(), NewReg().value_, 10);
+  VReg inputs[] = {incoming_vreg_0, incoming_vreg_1, incoming_vreg_2,
+                   incoming_vreg_3};
+  for (size_t i = 0; i < arraysize(inputs); ++i) {
+    if (inputs[i].value_ == kNoValue) break;
+    Extend(phi, inputs[i]);
+  }
+  current_block_->AddPhi(phi);
+  return phi;
+}
+
+
+void InstructionSequenceTest::Extend(PhiInstruction* phi, VReg vreg) {
+  phi->Extend(zone(), vreg.value_);
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant(
+    int32_t imm) {
+  VReg vreg = NewReg();
+  sequence()->AddConstant(vreg.value_, Constant(imm));
+  InstructionOperand* outputs[1]{ConstantOperand::Create(vreg.value_, zone())};
+  Emit(vreg.value_, kArchNop, 1, outputs);
+  return vreg;
+}
+
+
+int InstructionSequenceTest::EmitNop() { return Emit(NewIndex(), kArchNop); }
+
+
+static size_t CountInputs(size_t size,
+                          InstructionSequenceTest::TestOperand* inputs) {
+  size_t i = 0;
+  for (; i < size; ++i) {
+    if (inputs[i].type_ == InstructionSequenceTest::kInvalid) break;
+  }
+  return i;
+}
+
+
+int InstructionSequenceTest::EmitI(size_t input_size, TestOperand* inputs) {
+  InstructionOperand** mapped_inputs = ConvertInputs(input_size, inputs);
+  return Emit(NewIndex(), kArchNop, 0, nullptr, input_size, mapped_inputs);
+}
+
+
+int InstructionSequenceTest::EmitI(TestOperand input_op_0,
+                                   TestOperand input_op_1,
+                                   TestOperand input_op_2,
+                                   TestOperand input_op_3) {
+  TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
+  return EmitI(CountInputs(arraysize(inputs), inputs), inputs);
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
+    TestOperand output_op, size_t input_size, TestOperand* inputs) {
+  VReg output_vreg = NewReg();
+  InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
+  InstructionOperand** mapped_inputs = ConvertInputs(input_size, inputs);
+  Emit(output_vreg.value_, kArchNop, 1, outputs, input_size, mapped_inputs);
+  return output_vreg;
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
+    TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1,
+    TestOperand input_op_2, TestOperand input_op_3) {
+  TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
+  return EmitOI(output_op, CountInputs(arraysize(inputs), inputs), inputs);
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
+    TestOperand output_op, size_t input_size, TestOperand* inputs) {
+  VReg output_vreg = NewReg();
+  InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
+  CHECK(UnallocatedOperand::cast(outputs[0])->HasFixedPolicy());
+  InstructionOperand** mapped_inputs = ConvertInputs(input_size, inputs);
+  Emit(output_vreg.value_, kArchCallCodeObject, 1, outputs, input_size,
+       mapped_inputs, 0, nullptr, true);
+  return output_vreg;
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
+    TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1,
+    TestOperand input_op_2, TestOperand input_op_3) {
+  TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
+  return EmitCall(output_op, CountInputs(arraysize(inputs), inputs), inputs);
+}
+
+
+const Instruction* InstructionSequenceTest::GetInstruction(
+    int instruction_index) {
+  auto it = instructions_.find(instruction_index);
+  CHECK(it != instructions_.end());
+  return it->second;
+}
+
+
+int InstructionSequenceTest::EmitBranch(TestOperand input_op) {
+  InstructionOperand* inputs[4]{ConvertInputOp(input_op), ConvertInputOp(Imm()),
+                                ConvertInputOp(Imm()), ConvertInputOp(Imm())};
+  InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) |
+                           FlagsConditionField::encode(kEqual);
+  auto instruction =
+      NewInstruction(opcode, 0, nullptr, 4, inputs)->MarkAsControl();
+  return AddInstruction(NewIndex(), instruction);
+}
+
+
+int InstructionSequenceTest::EmitFallThrough() {
+  auto instruction = NewInstruction(kArchNop, 0, nullptr)->MarkAsControl();
+  return AddInstruction(NewIndex(), instruction);
+}
+
+
+int InstructionSequenceTest::EmitJump() {
+  InstructionOperand* inputs[1]{ConvertInputOp(Imm())};
+  auto instruction =
+      NewInstruction(kArchJmp, 0, nullptr, 1, inputs)->MarkAsControl();
+  return AddInstruction(NewIndex(), instruction);
+}
+
+
+Instruction* InstructionSequenceTest::NewInstruction(
+    InstructionCode code, size_t outputs_size, InstructionOperand** outputs,
+    size_t inputs_size, InstructionOperand** inputs, size_t temps_size,
+    InstructionOperand** temps) {
+  CHECK_NE(nullptr, current_block_);
+  return Instruction::New(zone(), code, outputs_size, outputs, inputs_size,
+                          inputs, temps_size, temps);
+}
+
+
+InstructionOperand* InstructionSequenceTest::Unallocated(
+    TestOperand op, UnallocatedOperand::ExtendedPolicy policy) {
+  auto unallocated = new (zone()) UnallocatedOperand(policy);
+  unallocated->set_virtual_register(op.vreg_.value_);
+  return unallocated;
+}
+
+
+InstructionOperand* InstructionSequenceTest::Unallocated(
+    TestOperand op, UnallocatedOperand::ExtendedPolicy policy,
+    UnallocatedOperand::Lifetime lifetime) {
+  auto unallocated = new (zone()) UnallocatedOperand(policy, lifetime);
+  unallocated->set_virtual_register(op.vreg_.value_);
+  return unallocated;
+}
+
+
+InstructionOperand* InstructionSequenceTest::Unallocated(
+    TestOperand op, UnallocatedOperand::ExtendedPolicy policy, int index) {
+  auto unallocated = new (zone()) UnallocatedOperand(policy, index);
+  unallocated->set_virtual_register(op.vreg_.value_);
+  return unallocated;
+}
+
+
+InstructionOperand* InstructionSequenceTest::Unallocated(
+    TestOperand op, UnallocatedOperand::BasicPolicy policy, int index) {
+  auto unallocated = new (zone()) UnallocatedOperand(policy, index);
+  unallocated->set_virtual_register(op.vreg_.value_);
+  return unallocated;
+}
+
+
+InstructionOperand** InstructionSequenceTest::ConvertInputs(
+    size_t input_size, TestOperand* inputs) {
+  InstructionOperand** mapped_inputs =
+      zone()->NewArray<InstructionOperand*>(static_cast<int>(input_size));
+  for (size_t i = 0; i < input_size; ++i) {
+    mapped_inputs[i] = ConvertInputOp(inputs[i]);
+  }
+  return mapped_inputs;
+}
+
+
+InstructionOperand* InstructionSequenceTest::ConvertInputOp(TestOperand op) {
+  if (op.type_ == kImmediate) {
+    CHECK_EQ(op.vreg_.value_, kNoValue);
+    return ImmediateOperand::Create(op.value_, zone());
+  }
+  CHECK_NE(op.vreg_.value_, kNoValue);
+  switch (op.type_) {
+    case kNone:
+      return Unallocated(op, UnallocatedOperand::NONE,
+                         UnallocatedOperand::USED_AT_START);
+    case kUnique:
+      return Unallocated(op, UnallocatedOperand::NONE);
+    case kUniqueRegister:
+      return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
+    case kRegister:
+      return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER,
+                         UnallocatedOperand::USED_AT_START);
+    case kFixedRegister:
+      CHECK(0 <= op.value_ && op.value_ < num_general_registers_);
+      return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_);
+    case kFixedSlot:
+      return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
+    default:
+      break;
+  }
+  CHECK(false);
+  return NULL;
+}
+
+
+InstructionOperand* InstructionSequenceTest::ConvertOutputOp(VReg vreg,
+                                                             TestOperand op) {
+  CHECK_EQ(op.vreg_.value_, kNoValue);
+  op.vreg_ = vreg;
+  switch (op.type_) {
+    case kSameAsFirst:
+      return Unallocated(op, UnallocatedOperand::SAME_AS_FIRST_INPUT);
+    case kRegister:
+      return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
+    case kFixedSlot:
+      return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
+    case kFixedRegister:
+      CHECK(0 <= op.value_ && op.value_ < num_general_registers_);
+      return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_);
+    default:
+      break;
+  }
+  CHECK(false);
+  return NULL;
+}
+
+
+InstructionBlock* InstructionSequenceTest::NewBlock() {
+  CHECK(current_block_ == nullptr);
+  auto block_id = BasicBlock::Id::FromSize(instruction_blocks_.size());
+  Rpo rpo = Rpo::FromInt(block_id.ToInt());
+  Rpo loop_header = Rpo::Invalid();
+  Rpo loop_end = Rpo::Invalid();
+  if (!loop_blocks_.empty()) {
+    auto& loop_data = loop_blocks_.back();
+    // This is a loop header.
+    if (!loop_data.loop_header_.IsValid()) {
+      loop_end = Rpo::FromInt(block_id.ToInt() + loop_data.expected_blocks_);
+      loop_data.expected_blocks_--;
+      loop_data.loop_header_ = rpo;
+    } else {
+      // This is a loop body.
+      CHECK_NE(0, loop_data.expected_blocks_);
+      // TODO(dcarney): handle nested loops.
+      loop_data.expected_blocks_--;
+      loop_header = loop_data.loop_header_;
+    }
+  }
+  // Construct instruction block.
+  auto instruction_block = new (zone())
+      InstructionBlock(zone(), block_id, rpo, loop_header, loop_end, false);
+  instruction_blocks_.push_back(instruction_block);
+  current_block_ = instruction_block;
+  sequence()->StartBlock(rpo);
+  return instruction_block;
+}
+
+
+void InstructionSequenceTest::WireBlocks() {
+  CHECK_EQ(nullptr, current_block());
+  CHECK(instruction_blocks_.size() == completions_.size());
+  size_t offset = 0;
+  for (const auto& completion : completions_) {
+    switch (completion.type_) {
+      case kBlockEnd:
+        break;
+      case kFallThrough:  // Fallthrough.
+      case kJump:
+        WireBlock(offset, completion.offset_0_);
+        break;
+      case kBranch:
+        WireBlock(offset, completion.offset_0_);
+        WireBlock(offset, completion.offset_1_);
+        break;
+    }
+    ++offset;
+  }
+}
+
+
+void InstructionSequenceTest::WireBlock(size_t block_offset, int jump_offset) {
+  size_t target_block_offset = block_offset + static_cast<size_t>(jump_offset);
+  CHECK(block_offset < instruction_blocks_.size());
+  CHECK(target_block_offset < instruction_blocks_.size());
+  auto block = instruction_blocks_[block_offset];
+  auto target = instruction_blocks_[target_block_offset];
+  block->successors().push_back(target->rpo_number());
+  target->predecessors().push_back(block->rpo_number());
+}
+
+
+int InstructionSequenceTest::Emit(int instruction_index, InstructionCode code,
+                                  size_t outputs_size,
+                                  InstructionOperand** outputs,
+                                  size_t inputs_size,
+                                  InstructionOperand** inputs,
+                                  size_t temps_size, InstructionOperand** temps,
+                                  bool is_call) {
+  auto instruction = NewInstruction(code, outputs_size, outputs, inputs_size,
+                                    inputs, temps_size, temps);
+  if (is_call) instruction->MarkAsCall();
+  return AddInstruction(instruction_index, instruction);
+}
+
+
+int InstructionSequenceTest::AddInstruction(int instruction_index,
+                                            Instruction* instruction) {
+  sequence()->AddInstruction(instruction);
+  return instruction_index;
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/instruction-sequence-unittest.h b/test/unittests/compiler/instruction-sequence-unittest.h
new file mode 100644
index 0000000..ce0a5b4
--- /dev/null
+++ b/test/unittests/compiler/instruction-sequence-unittest.h
@@ -0,0 +1,239 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UNITTESTS_COMPILER_INSTRUCTION_SEQUENCE_UNITTEST_H_
+#define V8_UNITTESTS_COMPILER_INSTRUCTION_SEQUENCE_UNITTEST_H_
+
+#include "src/compiler/instruction.h"
+#include "test/unittests/test-utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class InstructionSequenceTest : public TestWithZone {
+ public:
+  static const int kDefaultNRegs = 4;
+  static const int kNoValue = kMinInt;
+
+  typedef BasicBlock::RpoNumber Rpo;
+
+  struct VReg {
+    VReg() : value_(kNoValue) {}
+    VReg(PhiInstruction* phi) : value_(phi->virtual_register()) {}  // NOLINT
+    explicit VReg(int value) : value_(value) {}
+    int value_;
+  };
+
+  enum TestOperandType {
+    kInvalid,
+    kSameAsFirst,
+    kRegister,
+    kFixedRegister,
+    kSlot,
+    kFixedSlot,
+    kImmediate,
+    kNone,
+    kConstant,
+    kUnique,
+    kUniqueRegister
+  };
+
+  struct TestOperand {
+    TestOperand() : type_(kInvalid), vreg_(), value_(kNoValue) {}
+    TestOperand(TestOperandType type, int imm)
+        : type_(type), vreg_(), value_(imm) {}
+    TestOperand(TestOperandType type, VReg vreg, int value = kNoValue)
+        : type_(type), vreg_(vreg), value_(value) {}
+
+    TestOperandType type_;
+    VReg vreg_;
+    int value_;
+  };
+
+  static TestOperand Same() { return TestOperand(kSameAsFirst, VReg()); }
+
+  static TestOperand Reg(VReg vreg, int index = kNoValue) {
+    TestOperandType type = kRegister;
+    if (index != kNoValue) type = kFixedRegister;
+    return TestOperand(type, vreg, index);
+  }
+
+  static TestOperand Reg(int index = kNoValue) { return Reg(VReg(), index); }
+
+  static TestOperand Slot(VReg vreg, int index = kNoValue) {
+    TestOperandType type = kSlot;
+    if (index != kNoValue) type = kFixedSlot;
+    return TestOperand(type, vreg, index);
+  }
+
+  static TestOperand Slot(int index = kNoValue) { return Slot(VReg(), index); }
+
+  static TestOperand Const(int index) {
+    CHECK_NE(kNoValue, index);
+    return TestOperand(kConstant, VReg(), index);
+  }
+
+  static TestOperand Use(VReg vreg) { return TestOperand(kNone, vreg); }
+
+  static TestOperand Use() { return Use(VReg()); }
+
+  static TestOperand Unique(VReg vreg) { return TestOperand(kUnique, vreg); }
+
+  static TestOperand UniqueReg(VReg vreg) {
+    return TestOperand(kUniqueRegister, vreg);
+  }
+
+  enum BlockCompletionType { kBlockEnd, kFallThrough, kBranch, kJump };
+
+  struct BlockCompletion {
+    BlockCompletionType type_;
+    TestOperand op_;
+    int offset_0_;
+    int offset_1_;
+  };
+
+  static BlockCompletion FallThrough() {
+    BlockCompletion completion = {kFallThrough, TestOperand(), 1, kNoValue};
+    return completion;
+  }
+
+  static BlockCompletion Jump(int offset) {
+    BlockCompletion completion = {kJump, TestOperand(), offset, kNoValue};
+    return completion;
+  }
+
+  static BlockCompletion Branch(TestOperand op, int left_offset,
+                                int right_offset) {
+    BlockCompletion completion = {kBranch, op, left_offset, right_offset};
+    return completion;
+  }
+
+  static BlockCompletion Last() {
+    BlockCompletion completion = {kBlockEnd, TestOperand(), kNoValue, kNoValue};
+    return completion;
+  }
+
+  InstructionSequenceTest();
+
+  void SetNumRegs(int num_general_registers, int num_double_registers);
+  RegisterConfiguration* config();
+  InstructionSequence* sequence();
+
+  void StartLoop(int loop_blocks);
+  void EndLoop();
+  void StartBlock();
+  int EndBlock(BlockCompletion completion = FallThrough());
+
+  TestOperand Imm(int32_t imm = 0);
+  VReg Define(TestOperand output_op);
+  VReg Parameter(TestOperand output_op = Reg()) { return Define(output_op); }
+
+  int Return(TestOperand input_op_0);
+  int Return(VReg vreg) { return Return(Reg(vreg, 0)); }
+
+  PhiInstruction* Phi(VReg incoming_vreg_0 = VReg(),
+                      VReg incoming_vreg_1 = VReg(),
+                      VReg incoming_vreg_2 = VReg(),
+                      VReg incoming_vreg_3 = VReg());
+  void Extend(PhiInstruction* phi, VReg vreg);
+
+  VReg DefineConstant(int32_t imm = 0);
+  int EmitNop();
+  int EmitI(size_t input_size, TestOperand* inputs);
+  int EmitI(TestOperand input_op_0 = TestOperand(),
+            TestOperand input_op_1 = TestOperand(),
+            TestOperand input_op_2 = TestOperand(),
+            TestOperand input_op_3 = TestOperand());
+  VReg EmitOI(TestOperand output_op, size_t input_size, TestOperand* inputs);
+  VReg EmitOI(TestOperand output_op, TestOperand input_op_0 = TestOperand(),
+              TestOperand input_op_1 = TestOperand(),
+              TestOperand input_op_2 = TestOperand(),
+              TestOperand input_op_3 = TestOperand());
+  VReg EmitCall(TestOperand output_op, size_t input_size, TestOperand* inputs);
+  VReg EmitCall(TestOperand output_op, TestOperand input_op_0 = TestOperand(),
+                TestOperand input_op_1 = TestOperand(),
+                TestOperand input_op_2 = TestOperand(),
+                TestOperand input_op_3 = TestOperand());
+
+  // Get defining instruction vreg or value returned at instruction creation
+  // time when there is no return value.
+  const Instruction* GetInstruction(int instruction_index);
+
+  InstructionBlock* current_block() const { return current_block_; }
+  int num_general_registers() const { return num_general_registers_; }
+  int num_double_registers() const { return num_double_registers_; }
+
+  // Called after all instructions have been inserted.
+  void WireBlocks();
+
+ private:
+  VReg NewReg() { return VReg(sequence()->NextVirtualRegister()); }
+  int NewIndex() { return current_instruction_index_--; }
+
+  static TestOperand Invalid() { return TestOperand(kInvalid, VReg()); }
+
+  int EmitBranch(TestOperand input_op);
+  int EmitFallThrough();
+  int EmitJump();
+  Instruction* NewInstruction(InstructionCode code, size_t outputs_size,
+                              InstructionOperand** outputs,
+                              size_t inputs_size = 0,
+                              InstructionOperand* *inputs = nullptr,
+                              size_t temps_size = 0,
+                              InstructionOperand* *temps = nullptr);
+  InstructionOperand* Unallocated(TestOperand op,
+                                  UnallocatedOperand::ExtendedPolicy policy);
+  InstructionOperand* Unallocated(TestOperand op,
+                                  UnallocatedOperand::ExtendedPolicy policy,
+                                  UnallocatedOperand::Lifetime lifetime);
+  InstructionOperand* Unallocated(TestOperand op,
+                                  UnallocatedOperand::ExtendedPolicy policy,
+                                  int index);
+  InstructionOperand* Unallocated(TestOperand op,
+                                  UnallocatedOperand::BasicPolicy policy,
+                                  int index);
+  InstructionOperand** ConvertInputs(size_t input_size, TestOperand* inputs);
+  InstructionOperand* ConvertInputOp(TestOperand op);
+  InstructionOperand* ConvertOutputOp(VReg vreg, TestOperand op);
+  InstructionBlock* NewBlock();
+  void WireBlock(size_t block_offset, int jump_offset);
+
+  int Emit(int instruction_index, InstructionCode code, size_t outputs_size = 0,
+           InstructionOperand* *outputs = nullptr, size_t inputs_size = 0,
+           InstructionOperand* *inputs = nullptr, size_t temps_size = 0,
+           InstructionOperand* *temps = nullptr, bool is_call = false);
+
+  int AddInstruction(int instruction_index, Instruction* instruction);
+
+  struct LoopData {
+    Rpo loop_header_;
+    int expected_blocks_;
+  };
+
+  typedef std::vector<LoopData> LoopBlocks;
+  typedef std::map<int, const Instruction*> Instructions;
+  typedef std::vector<BlockCompletion> Completions;
+
+  SmartPointer<RegisterConfiguration> config_;
+  InstructionSequence* sequence_;
+  int num_general_registers_;
+  int num_double_registers_;
+
+  // Block building state.
+  InstructionBlocks instruction_blocks_;
+  Instructions instructions_;
+  int current_instruction_index_;
+  Completions completions_;
+  LoopBlocks loop_blocks_;
+  InstructionBlock* current_block_;
+  bool block_returns_;
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_UNITTESTS_COMPILER_INSTRUCTION_SEQUENCE_UNITTEST_H_
diff --git a/test/unittests/compiler/js-builtin-reducer-unittest.cc b/test/unittests/compiler/js-builtin-reducer-unittest.cc
new file mode 100644
index 0000000..9c57282
--- /dev/null
+++ b/test/unittests/compiler/js-builtin-reducer-unittest.cc
@@ -0,0 +1,303 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/js-builtin-reducer.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/typer.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::BitEq;
+using testing::Capture;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class JSBuiltinReducerTest : public TypedGraphTest {
+ public:
+  JSBuiltinReducerTest() : javascript_(zone()) {}
+
+ protected:
+  Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
+                                   MachineOperatorBuilder::Flag::kNoFlags) {
+    MachineOperatorBuilder machine(zone(), kMachPtr, flags);
+    JSGraph jsgraph(graph(), common(), javascript(), &machine);
+    JSBuiltinReducer reducer(&jsgraph);
+    return reducer.Reduce(node);
+  }
+
+  Handle<JSFunction> MathFunction(const char* name) {
+    Handle<Object> m =
+        JSObject::GetProperty(isolate()->global_object(),
+                              isolate()->factory()->NewStringFromAsciiChecked(
+                                  "Math")).ToHandleChecked();
+    Handle<JSFunction> f = Handle<JSFunction>::cast(
+        JSObject::GetProperty(
+            m, isolate()->factory()->NewStringFromAsciiChecked(name))
+            .ToHandleChecked());
+    return f;
+  }
+
+  JSOperatorBuilder* javascript() { return &javascript_; }
+
+ private:
+  JSOperatorBuilder javascript_;
+};
+
+
+namespace {
+
+// TODO(mstarzinger): Find a common place and unify with test-js-typed-lowering.
+Type* const kNumberTypes[] = {
+    Type::UnsignedSmall(),       Type::NegativeSigned32(),
+    Type::NonNegativeSigned32(), Type::SignedSmall(),
+    Type::Signed32(),            Type::Unsigned32(),
+    Type::Integral32(),          Type::MinusZero(),
+    Type::NaN(),                 Type::OrderedNumber(),
+    Type::PlainNumber(),         Type::Number()};
+
+}  // namespace
+
+
+// -----------------------------------------------------------------------------
+// Math.abs
+
+
+TEST_F(JSBuiltinReducerTest, MathAbs) {
+  Handle<JSFunction> f = MathFunction("abs");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call);
+
+    if (t0->Is(Type::Unsigned32())) {
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(), p0);
+    } else {
+      Capture<Node*> branch;
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(
+          r.replacement(),
+          IsSelect(kMachNone,
+                   IsNumberLessThan(IsNumberConstant(BitEq(0.0)), p0), p0,
+                   IsNumberSubtract(IsNumberConstant(BitEq(0.0)), p0)));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Math.sqrt
+
+
+TEST_F(JSBuiltinReducerTest, MathSqrt) {
+  Handle<JSFunction> f = MathFunction("sqrt");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call);
+
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsFloat64Sqrt(p0));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Math.max
+
+
+TEST_F(JSBuiltinReducerTest, MathMax0) {
+  Handle<JSFunction> f = MathFunction("max");
+
+  Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+  Node* call =
+      graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS),
+                       fun, UndefinedConstant());
+  Reduction r = Reduce(call);
+
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY));
+}
+
+
+TEST_F(JSBuiltinReducerTest, MathMax1) {
+  Handle<JSFunction> f = MathFunction("max");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call);
+
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), p0);
+  }
+}
+
+
+TEST_F(JSBuiltinReducerTest, MathMax2) {
+  Handle<JSFunction> f = MathFunction("max");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    TRACED_FOREACH(Type*, t1, kNumberTypes) {
+      Node* p0 = Parameter(t0, 0);
+      Node* p1 = Parameter(t1, 1);
+      Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+      Node* call = graph()->NewNode(
+          javascript()->CallFunction(4, NO_CALL_FUNCTION_FLAGS), fun,
+          UndefinedConstant(), p0, p1);
+      Reduction r = Reduce(call);
+
+      if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
+        ASSERT_TRUE(r.Changed());
+        EXPECT_THAT(r.replacement(),
+                    IsSelect(kMachNone, IsNumberLessThan(p1, p0), p1, p0));
+      } else {
+        ASSERT_FALSE(r.Changed());
+        EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
+      }
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Math.imul
+
+
+TEST_F(JSBuiltinReducerTest, MathImul) {
+  Handle<JSFunction> f = MathFunction("imul");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    TRACED_FOREACH(Type*, t1, kNumberTypes) {
+      Node* p0 = Parameter(t0, 0);
+      Node* p1 = Parameter(t1, 1);
+      Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+      Node* call = graph()->NewNode(
+          javascript()->CallFunction(4, NO_CALL_FUNCTION_FLAGS), fun,
+          UndefinedConstant(), p0, p1);
+      Reduction r = Reduce(call);
+
+      if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
+        ASSERT_TRUE(r.Changed());
+        EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1));
+      } else {
+        ASSERT_FALSE(r.Changed());
+        EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
+      }
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Math.fround
+
+
+TEST_F(JSBuiltinReducerTest, MathFround) {
+  Handle<JSFunction> f = MathFunction("fround");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call);
+
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsTruncateFloat64ToFloat32(p0));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Math.floor
+
+
+TEST_F(JSBuiltinReducerTest, MathFloorAvailable) {
+  Handle<JSFunction> f = MathFunction("floor");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kFloat64Floor);
+
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsFloat64Floor(p0));
+  }
+}
+
+
+TEST_F(JSBuiltinReducerTest, MathFloorUnavailable) {
+  Handle<JSFunction> f = MathFunction("floor");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kNoFlags);
+
+    ASSERT_FALSE(r.Changed());
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Math.ceil
+
+
+TEST_F(JSBuiltinReducerTest, MathCeilAvailable) {
+  Handle<JSFunction> f = MathFunction("ceil");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kFloat64Ceil);
+
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsFloat64Ceil(p0));
+  }
+}
+
+
+TEST_F(JSBuiltinReducerTest, MathCeilUnavailable) {
+  Handle<JSFunction> f = MathFunction("ceil");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kNoFlags);
+
+    ASSERT_FALSE(r.Changed());
+  }
+}
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/js-operator-unittest.cc b/test/unittests/compiler/js-operator-unittest.cc
new file mode 100644
index 0000000..7aa0c64
--- /dev/null
+++ b/test/unittests/compiler/js-operator-unittest.cc
@@ -0,0 +1,217 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/js-operator.h"
+#include "src/compiler/opcodes.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/operator-properties.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// -----------------------------------------------------------------------------
+// Shared operators.
+
+
+namespace {
+
+struct SharedOperator {
+  const Operator* (JSOperatorBuilder::*constructor)();
+  IrOpcode::Value opcode;
+  Operator::Properties properties;
+  int value_input_count;
+  int frame_state_input_count;
+  int effect_input_count;
+  int control_input_count;
+  int value_output_count;
+  int effect_output_count;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const SharedOperator& sop) {
+  return os << IrOpcode::Mnemonic(sop.opcode);
+}
+
+
+const SharedOperator kSharedOperators[] = {
+#define SHARED(Name, properties, value_input_count, frame_state_input_count, \
+               effect_input_count, control_input_count, value_output_count,  \
+               effect_output_count)                                          \
+  {                                                                          \
+    &JSOperatorBuilder::Name, IrOpcode::kJS##Name, properties,               \
+        value_input_count, frame_state_input_count, effect_input_count,      \
+        control_input_count, value_output_count, effect_output_count         \
+  }
+    SHARED(Equal, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(NotEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(StrictEqual, Operator::kPure, 2, 0, 0, 0, 1, 0),
+    SHARED(StrictNotEqual, Operator::kPure, 2, 0, 0, 0, 1, 0),
+    SHARED(LessThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(GreaterThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(BitwiseOr, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(BitwiseXor, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(BitwiseAnd, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(ShiftLeft, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(ShiftRight, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(ShiftRightLogical, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Add, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Subtract, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Multiply, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Divide, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Modulus, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(UnaryNot, Operator::kPure, 1, 0, 0, 0, 1, 0),
+    SHARED(ToBoolean, Operator::kPure, 1, 0, 0, 0, 1, 0),
+    SHARED(ToNumber, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(ToString, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(ToName, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(ToObject, Operator::kNoProperties, 1, 1, 1, 1, 1, 1),
+    SHARED(Yield, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(Create, Operator::kEliminatable, 0, 0, 1, 1, 1, 1),
+    SHARED(HasProperty, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0),
+    SHARED(InstanceOf, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Debugger, Operator::kNoProperties, 0, 0, 1, 1, 0, 1),
+    SHARED(CreateFunctionContext, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(CreateWithContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1),
+    SHARED(CreateBlockContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1),
+    SHARED(CreateModuleContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1),
+    SHARED(CreateScriptContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1)
+#undef SHARED
+};
+
+}  // namespace
+
+
+class JSSharedOperatorTest
+    : public TestWithZone,
+      public ::testing::WithParamInterface<SharedOperator> {};
+
+
+TEST_P(JSSharedOperatorTest, InstancesAreGloballyShared) {
+  const SharedOperator& sop = GetParam();
+  JSOperatorBuilder javascript1(zone());
+  JSOperatorBuilder javascript2(zone());
+  EXPECT_EQ((javascript1.*sop.constructor)(), (javascript2.*sop.constructor)());
+}
+
+
+TEST_P(JSSharedOperatorTest, NumberOfInputsAndOutputs) {
+  JSOperatorBuilder javascript(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (javascript.*sop.constructor)();
+
+  const int context_input_count = 1;
+  // TODO(jarin): Get rid of this hack.
+  const int frame_state_input_count =
+      FLAG_turbo_deoptimization ? sop.frame_state_input_count : 0;
+  EXPECT_EQ(sop.value_input_count, op->ValueInputCount());
+  EXPECT_EQ(context_input_count, OperatorProperties::GetContextInputCount(op));
+  EXPECT_EQ(frame_state_input_count,
+            OperatorProperties::GetFrameStateInputCount(op));
+  EXPECT_EQ(sop.effect_input_count, op->EffectInputCount());
+  EXPECT_EQ(sop.control_input_count, op->ControlInputCount());
+  EXPECT_EQ(sop.value_input_count + context_input_count +
+                frame_state_input_count + sop.effect_input_count +
+                sop.control_input_count,
+            OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(sop.value_output_count, op->ValueOutputCount());
+  EXPECT_EQ(sop.effect_output_count, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(JSSharedOperatorTest, OpcodeIsCorrect) {
+  JSOperatorBuilder javascript(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (javascript.*sop.constructor)();
+  EXPECT_EQ(sop.opcode, op->opcode());
+}
+
+
+TEST_P(JSSharedOperatorTest, Properties) {
+  JSOperatorBuilder javascript(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (javascript.*sop.constructor)();
+  EXPECT_EQ(sop.properties, op->properties());
+}
+
+
+INSTANTIATE_TEST_CASE_P(JSOperatorTest, JSSharedOperatorTest,
+                        ::testing::ValuesIn(kSharedOperators));
+
+
+// -----------------------------------------------------------------------------
+// JSStoreProperty.
+
+
+class JSStorePropertyOperatorTest
+    : public TestWithZone,
+      public ::testing::WithParamInterface<StrictMode> {};
+
+
+TEST_P(JSStorePropertyOperatorTest, InstancesAreGloballyShared) {
+  const StrictMode mode = GetParam();
+  JSOperatorBuilder javascript1(zone());
+  JSOperatorBuilder javascript2(zone());
+  EXPECT_EQ(javascript1.StoreProperty(mode), javascript2.StoreProperty(mode));
+}
+
+
+TEST_P(JSStorePropertyOperatorTest, NumberOfInputsAndOutputs) {
+  JSOperatorBuilder javascript(zone());
+  const StrictMode mode = GetParam();
+  const Operator* op = javascript.StoreProperty(mode);
+
+  // TODO(jarin): Get rid of this hack.
+  const int frame_state_input_count = FLAG_turbo_deoptimization ? 1 : 0;
+  EXPECT_EQ(3, op->ValueInputCount());
+  EXPECT_EQ(1, OperatorProperties::GetContextInputCount(op));
+  EXPECT_EQ(frame_state_input_count,
+            OperatorProperties::GetFrameStateInputCount(op));
+  EXPECT_EQ(1, op->EffectInputCount());
+  EXPECT_EQ(1, op->ControlInputCount());
+  EXPECT_EQ(6 + frame_state_input_count,
+            OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(0, op->ValueOutputCount());
+  EXPECT_EQ(1, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(JSStorePropertyOperatorTest, OpcodeIsCorrect) {
+  JSOperatorBuilder javascript(zone());
+  const StrictMode mode = GetParam();
+  const Operator* op = javascript.StoreProperty(mode);
+  EXPECT_EQ(IrOpcode::kJSStoreProperty, op->opcode());
+}
+
+
+TEST_P(JSStorePropertyOperatorTest, OpParameter) {
+  JSOperatorBuilder javascript(zone());
+  const StrictMode mode = GetParam();
+  const Operator* op = javascript.StoreProperty(mode);
+  EXPECT_EQ(mode, OpParameter<StrictMode>(op));
+}
+
+
+TEST_P(JSStorePropertyOperatorTest, Properties) {
+  JSOperatorBuilder javascript(zone());
+  const StrictMode mode = GetParam();
+  const Operator* op = javascript.StoreProperty(mode);
+  EXPECT_EQ(Operator::kNoProperties, op->properties());
+}
+
+
+INSTANTIATE_TEST_CASE_P(JSOperatorTest, JSStorePropertyOperatorTest,
+                        ::testing::Values(SLOPPY, STRICT));
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/js-typed-lowering-unittest.cc b/test/unittests/compiler/js-typed-lowering-unittest.cc
new file mode 100644
index 0000000..97ff106
--- /dev/null
+++ b/test/unittests/compiler/js-typed-lowering-unittest.cc
@@ -0,0 +1,808 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/js-typed-lowering.h"
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/node-properties-inl.h"
+#include "test/unittests/compiler/compiler-test-utils.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::BitEq;
+using testing::IsNaN;
+
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+const ExternalArrayType kExternalArrayTypes[] = {
+    kExternalUint8Array,   kExternalInt8Array,   kExternalUint16Array,
+    kExternalInt16Array,   kExternalUint32Array, kExternalInt32Array,
+    kExternalFloat32Array, kExternalFloat64Array};
+
+
+const double kFloat64Values[] = {
+    -V8_INFINITY, -4.23878e+275, -5.82632e+265, -6.60355e+220, -6.26172e+212,
+    -2.56222e+211, -4.82408e+201, -1.84106e+157, -1.63662e+127, -1.55772e+100,
+    -1.67813e+72, -2.3382e+55, -3.179e+30, -1.441e+09, -1.0647e+09,
+    -7.99361e+08, -5.77375e+08, -2.20984e+08, -32757, -13171, -9970, -3984,
+    -107, -105, -92, -77, -61, -0.000208163, -1.86685e-06, -1.17296e-10,
+    -9.26358e-11, -5.08004e-60, -1.74753e-65, -1.06561e-71, -5.67879e-79,
+    -5.78459e-130, -2.90989e-171, -7.15489e-243, -3.76242e-252, -1.05639e-263,
+    -4.40497e-267, -2.19666e-273, -4.9998e-276, -5.59821e-278, -2.03855e-282,
+    -5.99335e-283, -7.17554e-284, -3.11744e-309, -0.0, 0.0, 2.22507e-308,
+    1.30127e-270, 7.62898e-260, 4.00313e-249, 3.16829e-233, 1.85244e-228,
+    2.03544e-129, 1.35126e-110, 1.01182e-106, 5.26333e-94, 1.35292e-90,
+    2.85394e-83, 1.78323e-77, 5.4967e-57, 1.03207e-25, 4.57401e-25, 1.58738e-05,
+    2, 125, 2310, 9636, 14802, 17168, 28945, 29305, 4.81336e+07, 1.41207e+08,
+    4.65962e+08, 1.40499e+09, 2.12648e+09, 8.80006e+30, 1.4446e+45, 1.12164e+54,
+    2.48188e+89, 6.71121e+102, 3.074e+112, 4.9699e+152, 5.58383e+166,
+    4.30654e+172, 7.08824e+185, 9.6586e+214, 2.028e+223, 6.63277e+243,
+    1.56192e+261, 1.23202e+269, 5.72883e+289, 8.5798e+290, 1.40256e+294,
+    1.79769e+308, V8_INFINITY};
+
+
+const size_t kIndices[] = {0, 1, 42, 100, 1024};
+
+
+const double kIntegerValues[] = {-V8_INFINITY, INT_MIN, -1000.0,  -42.0,
+                                 -1.0,         0.0,     1.0,      42.0,
+                                 1000.0,       INT_MAX, UINT_MAX, V8_INFINITY};
+
+
+Type* const kJSTypes[] = {Type::Undefined(), Type::Null(),   Type::Boolean(),
+                          Type::Number(),    Type::String(), Type::Object()};
+
+
+const StrictMode kStrictModes[] = {SLOPPY, STRICT};
+
+}  // namespace
+
+
+class JSTypedLoweringTest : public TypedGraphTest {
+ public:
+  JSTypedLoweringTest() : TypedGraphTest(3), javascript_(zone()) {}
+  ~JSTypedLoweringTest() OVERRIDE {}
+
+ protected:
+  Reduction Reduce(Node* node) {
+    MachineOperatorBuilder machine(zone());
+    JSGraph jsgraph(graph(), common(), javascript(), &machine);
+    JSTypedLowering reducer(&jsgraph, zone());
+    return reducer.Reduce(node);
+  }
+
+  Handle<JSArrayBuffer> NewArrayBuffer(void* bytes, size_t byte_length) {
+    Handle<JSArrayBuffer> buffer = factory()->NewJSArrayBuffer();
+    Runtime::SetupArrayBuffer(isolate(), buffer, true, bytes, byte_length);
+    return buffer;
+  }
+
+  Matcher<Node*> IsIntPtrConstant(intptr_t value) {
+    return sizeof(value) == 4 ? IsInt32Constant(static_cast<int32_t>(value))
+                              : IsInt64Constant(static_cast<int64_t>(value));
+  }
+
+  JSOperatorBuilder* javascript() { return &javascript_; }
+
+ private:
+  JSOperatorBuilder javascript_;
+};
+
+
+// -----------------------------------------------------------------------------
+// JSUnaryNot
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithBoolean) {
+  Node* input = Parameter(Type::Boolean(), 0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsBooleanNot(input));
+}
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithFalsish) {
+  Handle<Object> zero = factory()->NewNumber(0);
+  Node* input = Parameter(
+      Type::Union(
+          Type::MinusZero(),
+          Type::Union(
+              Type::NaN(),
+              Type::Union(
+                  Type::Null(),
+                  Type::Union(
+                      Type::Undefined(),
+                      Type::Union(
+                          Type::Undetectable(),
+                          Type::Union(
+                              Type::Constant(factory()->false_value(), zone()),
+                              Type::Range(zero, zero, zone()), zone()),
+                          zone()),
+                      zone()),
+                  zone()),
+              zone()),
+          zone()),
+      0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsTrueConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithTruish) {
+  Node* input = Parameter(
+      Type::Union(
+          Type::Constant(factory()->true_value(), zone()),
+          Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
+          zone()),
+      0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFalseConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithNonZeroPlainNumber) {
+  Node* input = Parameter(
+      Type::Range(factory()->NewNumber(1), factory()->NewNumber(42), zone()),
+      0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFalseConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithAny) {
+  Node* input = Parameter(Type::Any(), 0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsBooleanNot(IsAnyToBoolean(input)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Constant propagation
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithMinusZero) {
+  {
+    Reduction r = Reduce(
+        Parameter(Type::Constant(factory()->minus_zero_value(), zone())));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
+  }
+  {
+    Reduction r = Reduce(Parameter(Type::MinusZero()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
+  }
+  {
+    Reduction r = Reduce(Parameter(
+        Type::Union(Type::MinusZero(),
+                    Type::Constant(factory()->NewNumber(0), zone()), zone())));
+    EXPECT_FALSE(r.Changed());
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithNull) {
+  Handle<HeapObject> null = factory()->null_value();
+  {
+    Reduction r = Reduce(Parameter(Type::Constant(null, zone())));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsHeapConstant(Unique<HeapObject>::CreateImmovable(null)));
+  }
+  {
+    Reduction r = Reduce(Parameter(Type::Null()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsHeapConstant(Unique<HeapObject>::CreateImmovable(null)));
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithNaN) {
+  const double kNaNs[] = {base::OS::nan_value(),
+                          std::numeric_limits<double>::quiet_NaN(),
+                          std::numeric_limits<double>::signaling_NaN()};
+  TRACED_FOREACH(double, nan, kNaNs) {
+    Handle<Object> constant = factory()->NewNumber(nan);
+    Reduction r = Reduce(Parameter(Type::Constant(constant, zone())));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
+  }
+  {
+    Reduction r =
+        Reduce(Parameter(Type::Constant(factory()->nan_value(), zone())));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
+  }
+  {
+    Reduction r = Reduce(Parameter(Type::NaN()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithPlainNumber) {
+  TRACED_FOREACH(double, value, kFloat64Values) {
+    Handle<Object> constant = factory()->NewNumber(value);
+    Reduction r = Reduce(Parameter(Type::Constant(constant, zone())));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsNumberConstant(value));
+  }
+  TRACED_FOREACH(double, value, kIntegerValues) {
+    Handle<Object> constant = factory()->NewNumber(value);
+    Reduction r = Reduce(Parameter(Type::Range(constant, constant, zone())));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsNumberConstant(value));
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithUndefined) {
+  Handle<HeapObject> undefined = factory()->undefined_value();
+  {
+    Reduction r = Reduce(Parameter(Type::Undefined()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsHeapConstant(Unique<HeapObject>::CreateImmovable(undefined)));
+  }
+  {
+    Reduction r = Reduce(Parameter(Type::Constant(undefined, zone())));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsHeapConstant(Unique<HeapObject>::CreateImmovable(undefined)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSToBoolean
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) {
+  Node* input = Parameter(Type::Boolean(), 0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_EQ(input, r.replacement());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithFalsish) {
+  Handle<Object> zero = factory()->NewNumber(0);
+  Node* input = Parameter(
+      Type::Union(
+          Type::MinusZero(),
+          Type::Union(
+              Type::NaN(),
+              Type::Union(
+                  Type::Null(),
+                  Type::Union(
+                      Type::Undefined(),
+                      Type::Union(
+                          Type::Undetectable(),
+                          Type::Union(
+                              Type::Constant(factory()->false_value(), zone()),
+                              Type::Range(zero, zero, zone()), zone()),
+                          zone()),
+                      zone()),
+                  zone()),
+              zone()),
+          zone()),
+      0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFalseConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithTruish) {
+  Node* input = Parameter(
+      Type::Union(
+          Type::Constant(factory()->true_value(), zone()),
+          Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
+          zone()),
+      0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsTrueConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) {
+  Node* input =
+      Parameter(Type::Range(factory()->NewNumber(1),
+                            factory()->NewNumber(V8_INFINITY), zone()),
+                0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsTrueConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithAny) {
+  Node* input = Parameter(Type::Any(), 0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsAnyToBoolean(input));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSToNumber
+
+
+TEST_F(JSTypedLoweringTest, JSToNumberWithPlainPrimitive) {
+  Node* const input = Parameter(Type::PlainPrimitive(), 0);
+  Node* const context = Parameter(Type::Any(), 1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction r = Reduce(graph()->NewNode(javascript()->ToNumber(), input,
+                                        context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsToNumber(input, IsNumberConstant(BitEq(0.0)),
+                                          graph()->start(), control));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSStrictEqual
+
+
+TEST_F(JSTypedLoweringTest, JSStrictEqualWithTheHole) {
+  Node* const the_hole = HeapConstant(factory()->the_hole_value());
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FOREACH(Type*, type, kJSTypes) {
+    Node* const lhs = Parameter(type);
+    Reduction r = Reduce(graph()->NewNode(javascript()->StrictEqual(), lhs,
+                                          the_hole, context, effect, control));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsFalseConstant());
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSShiftLeft
+
+
+TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) {
+  Node* const lhs = Parameter(Type::Signed32());
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FORRANGE(double, rhs, 0, 31) {
+    Reduction r =
+        Reduce(graph()->NewNode(javascript()->ShiftLeft(), lhs,
+                                NumberConstant(rhs), context, effect, control));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsWord32Shl(lhs, IsNumberConstant(BitEq(rhs))));
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) {
+  Node* const lhs = Parameter(Type::Signed32());
+  Node* const rhs = Parameter(Type::Unsigned32());
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction r = Reduce(graph()->NewNode(javascript()->ShiftLeft(), lhs, rhs,
+                                        context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(),
+              IsWord32Shl(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSShiftRight
+
+
+TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) {
+  Node* const lhs = Parameter(Type::Signed32());
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FORRANGE(double, rhs, 0, 31) {
+    Reduction r =
+        Reduce(graph()->NewNode(javascript()->ShiftRight(), lhs,
+                                NumberConstant(rhs), context, effect, control));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsWord32Sar(lhs, IsNumberConstant(BitEq(rhs))));
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) {
+  Node* const lhs = Parameter(Type::Signed32());
+  Node* const rhs = Parameter(Type::Unsigned32());
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRight(), lhs, rhs,
+                                        context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(),
+              IsWord32Sar(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSShiftRightLogical
+
+
+TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndConstant) {
+  Node* const lhs = Parameter(Type::Unsigned32());
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FORRANGE(double, rhs, 0, 31) {
+    Reduction r =
+        Reduce(graph()->NewNode(javascript()->ShiftRightLogical(), lhs,
+                                NumberConstant(rhs), context, effect, control));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsWord32Shr(lhs, IsNumberConstant(BitEq(rhs))));
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndUnsigned32) {
+  Node* const lhs = Parameter(Type::Unsigned32());
+  Node* const rhs = Parameter(Type::Unsigned32());
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRightLogical(), lhs,
+                                        rhs, context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(),
+              IsWord32Shr(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSLoadContext
+
+
+TEST_F(JSTypedLoweringTest, JSLoadContext) {
+  Node* const context = Parameter(Type::Any());
+  Node* const effect = graph()->start();
+  static bool kBooleans[] = {false, true};
+  TRACED_FOREACH(size_t, index, kIndices) {
+    TRACED_FOREACH(bool, immutable, kBooleans) {
+      Reduction const r1 = Reduce(
+          graph()->NewNode(javascript()->LoadContext(0, index, immutable),
+                           context, context, effect));
+      ASSERT_TRUE(r1.Changed());
+      EXPECT_THAT(r1.replacement(),
+                  IsLoadField(AccessBuilder::ForContextSlot(index), context,
+                              effect, graph()->start()));
+
+      Reduction const r2 = Reduce(
+          graph()->NewNode(javascript()->LoadContext(1, index, immutable),
+                           context, context, effect));
+      ASSERT_TRUE(r2.Changed());
+      EXPECT_THAT(r2.replacement(),
+                  IsLoadField(AccessBuilder::ForContextSlot(index),
+                              IsLoadField(AccessBuilder::ForContextSlot(
+                                              Context::PREVIOUS_INDEX),
+                                          context, effect, graph()->start()),
+                              effect, graph()->start()));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSStoreContext
+
+
+TEST_F(JSTypedLoweringTest, JSStoreContext) {
+  Node* const context = Parameter(Type::Any());
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FOREACH(size_t, index, kIndices) {
+    TRACED_FOREACH(Type*, type, kJSTypes) {
+      Node* const value = Parameter(type);
+
+      Reduction const r1 =
+          Reduce(graph()->NewNode(javascript()->StoreContext(0, index), context,
+                                  value, context, effect, control));
+      ASSERT_TRUE(r1.Changed());
+      EXPECT_THAT(r1.replacement(),
+                  IsStoreField(AccessBuilder::ForContextSlot(index), context,
+                               value, effect, control));
+
+      Reduction const r2 =
+          Reduce(graph()->NewNode(javascript()->StoreContext(1, index), context,
+                                  value, context, effect, control));
+      ASSERT_TRUE(r2.Changed());
+      EXPECT_THAT(r2.replacement(),
+                  IsStoreField(AccessBuilder::ForContextSlot(index),
+                               IsLoadField(AccessBuilder::ForContextSlot(
+                                               Context::PREVIOUS_INDEX),
+                                           context, effect, graph()->start()),
+                               value, effect, control));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSLoadProperty
+
+
+TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
+  const size_t kLength = 17;
+  double backing_store[kLength];
+  Handle<JSArrayBuffer> buffer =
+      NewArrayBuffer(backing_store, sizeof(backing_store));
+  VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
+                          FeedbackVectorICSlot::Invalid());
+  TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+    Handle<JSTypedArray> array =
+        factory()->NewJSTypedArray(type, buffer, 0, kLength);
+    int const element_size = static_cast<int>(array->element_size());
+
+    Node* key = Parameter(
+        Type::Range(factory()->NewNumber(kMinInt / element_size),
+                    factory()->NewNumber(kMaxInt / element_size), zone()));
+    Node* base = HeapConstant(array);
+    Node* context = UndefinedConstant();
+    Node* effect = graph()->start();
+    Node* control = graph()->start();
+    Node* node = graph()->NewNode(javascript()->LoadProperty(feedback), base,
+                                  key, context);
+    if (FLAG_turbo_deoptimization) {
+      node->AppendInput(zone(), UndefinedConstant());
+    }
+    node->AppendInput(zone(), effect);
+    node->AppendInput(zone(), control);
+    Reduction r = Reduce(node);
+
+    Matcher<Node*> offset_matcher =
+        element_size == 1
+            ? key
+            : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
+
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsLoadBuffer(BufferAccess(type),
+                     IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+                     offset_matcher,
+                     IsNumberConstant(array->byte_length()->Number()), effect,
+                     control));
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) {
+  const size_t kLength = 17;
+  double backing_store[kLength];
+  Handle<JSArrayBuffer> buffer =
+      NewArrayBuffer(backing_store, sizeof(backing_store));
+  VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
+                          FeedbackVectorICSlot::Invalid());
+  TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+    Handle<JSTypedArray> array =
+        factory()->NewJSTypedArray(type, buffer, 0, kLength);
+    ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true);
+
+    int min = random_number_generator()->NextInt(static_cast<int>(kLength));
+    int max = random_number_generator()->NextInt(static_cast<int>(kLength));
+    if (min > max) std::swap(min, max);
+    Node* key = Parameter(Type::Range(factory()->NewNumber(min),
+                                      factory()->NewNumber(max), zone()));
+    Node* base = HeapConstant(array);
+    Node* context = UndefinedConstant();
+    Node* effect = graph()->start();
+    Node* control = graph()->start();
+    Node* node = graph()->NewNode(javascript()->LoadProperty(feedback), base,
+                                  key, context);
+    if (FLAG_turbo_deoptimization) {
+      node->AppendInput(zone(), UndefinedConstant());
+    }
+    node->AppendInput(zone(), effect);
+    node->AppendInput(zone(), control);
+    Reduction r = Reduce(node);
+
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsLoadElement(access,
+                      IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+                      key, effect, control));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSStoreProperty
+
+
+TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) {
+  const size_t kLength = 17;
+  double backing_store[kLength];
+  Handle<JSArrayBuffer> buffer =
+      NewArrayBuffer(backing_store, sizeof(backing_store));
+  TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+    TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) {
+      Handle<JSTypedArray> array =
+          factory()->NewJSTypedArray(type, buffer, 0, kLength);
+      int const element_size = static_cast<int>(array->element_size());
+
+      Node* key = Parameter(
+          Type::Range(factory()->NewNumber(kMinInt / element_size),
+                      factory()->NewNumber(kMaxInt / element_size), zone()));
+      Node* base = HeapConstant(array);
+      Node* value =
+          Parameter(AccessBuilder::ForTypedArrayElement(type, true).type);
+      Node* context = UndefinedConstant();
+      Node* effect = graph()->start();
+      Node* control = graph()->start();
+      Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode),
+                                    base, key, value, context);
+      if (FLAG_turbo_deoptimization) {
+        node->AppendInput(zone(), UndefinedConstant());
+      }
+      node->AppendInput(zone(), effect);
+      node->AppendInput(zone(), control);
+      Reduction r = Reduce(node);
+
+      Matcher<Node*> offset_matcher =
+          element_size == 1
+              ? key
+              : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
+
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(
+          r.replacement(),
+          IsStoreBuffer(BufferAccess(type),
+                        IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+                        offset_matcher,
+                        IsNumberConstant(array->byte_length()->Number()), value,
+                        effect, control));
+    }
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithConversion) {
+  const size_t kLength = 17;
+  double backing_store[kLength];
+  Handle<JSArrayBuffer> buffer =
+      NewArrayBuffer(backing_store, sizeof(backing_store));
+  TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+    TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) {
+      Handle<JSTypedArray> array =
+          factory()->NewJSTypedArray(type, buffer, 0, kLength);
+      int const element_size = static_cast<int>(array->element_size());
+
+      Node* key = Parameter(
+          Type::Range(factory()->NewNumber(kMinInt / element_size),
+                      factory()->NewNumber(kMaxInt / element_size), zone()));
+      Node* base = HeapConstant(array);
+      Node* value = Parameter(Type::Any());
+      Node* context = UndefinedConstant();
+      Node* effect = graph()->start();
+      Node* control = graph()->start();
+      Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode),
+                                    base, key, value, context);
+      if (FLAG_turbo_deoptimization) {
+        node->AppendInput(zone(), UndefinedConstant());
+      }
+      node->AppendInput(zone(), effect);
+      node->AppendInput(zone(), control);
+      Reduction r = Reduce(node);
+
+      Matcher<Node*> offset_matcher =
+          element_size == 1
+              ? key
+              : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
+
+      Matcher<Node*> value_matcher =
+          IsToNumber(value, context, effect, control);
+      Matcher<Node*> effect_matcher = value_matcher;
+      if (AccessBuilder::ForTypedArrayElement(type, true)
+              .type->Is(Type::Signed32())) {
+        value_matcher = IsNumberToInt32(value_matcher);
+      } else if (AccessBuilder::ForTypedArrayElement(type, true)
+                     .type->Is(Type::Unsigned32())) {
+        value_matcher = IsNumberToUint32(value_matcher);
+      }
+
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(
+          r.replacement(),
+          IsStoreBuffer(BufferAccess(type),
+                        IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+                        offset_matcher,
+                        IsNumberConstant(array->byte_length()->Number()),
+                        value_matcher, effect_matcher, control));
+    }
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithSafeKey) {
+  const size_t kLength = 17;
+  double backing_store[kLength];
+  Handle<JSArrayBuffer> buffer =
+      NewArrayBuffer(backing_store, sizeof(backing_store));
+  TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+    TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) {
+      Handle<JSTypedArray> array =
+          factory()->NewJSTypedArray(type, buffer, 0, kLength);
+      ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true);
+
+      int min = random_number_generator()->NextInt(static_cast<int>(kLength));
+      int max = random_number_generator()->NextInt(static_cast<int>(kLength));
+      if (min > max) std::swap(min, max);
+      Node* key = Parameter(Type::Range(factory()->NewNumber(min),
+                                        factory()->NewNumber(max), zone()));
+      Node* base = HeapConstant(array);
+      Node* value = Parameter(access.type);
+      Node* context = UndefinedConstant();
+      Node* effect = graph()->start();
+      Node* control = graph()->start();
+      Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode),
+                                    base, key, value, context);
+      if (FLAG_turbo_deoptimization) {
+        node->AppendInput(zone(), UndefinedConstant());
+      }
+      node->AppendInput(zone(), effect);
+      node->AppendInput(zone(), control);
+      Reduction r = Reduce(node);
+
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(
+          r.replacement(),
+          IsStoreElement(
+              access, IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+              key, value, effect, control));
+    }
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/load-elimination-unittest.cc b/test/unittests/compiler/load-elimination-unittest.cc
new file mode 100644
index 0000000..f0cd60e
--- /dev/null
+++ b/test/unittests/compiler/load-elimination-unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/load-elimination.h"
+#include "src/compiler/simplified-operator.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class LoadEliminationTest : public GraphTest {
+ public:
+  LoadEliminationTest() : GraphTest(3), simplified_(zone()) {}
+  ~LoadEliminationTest() OVERRIDE {}
+
+ protected:
+  Reduction Reduce(Node* node) {
+    LoadElimination reducer;
+    return reducer.Reduce(node);
+  }
+
+  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
+
+ private:
+  SimplifiedOperatorBuilder simplified_;
+};
+
+
+TEST_F(LoadEliminationTest, LoadFieldWithStoreField) {
+  Node* object1 = Parameter(0);
+  Node* object2 = Parameter(1);
+  Node* value = Parameter(2);
+  Node* effect = graph()->start();
+  Node* control = graph()->start();
+
+  FieldAccess access1 = AccessBuilder::ForContextSlot(42);
+  Node* store1 = graph()->NewNode(simplified()->StoreField(access1), object1,
+                                  value, effect, control);
+  Reduction r1 = Reduce(graph()->NewNode(simplified()->LoadField(access1),
+                                         object1, store1, control));
+  ASSERT_TRUE(r1.Changed());
+  EXPECT_EQ(value, r1.replacement());
+
+  FieldAccess access2 = AccessBuilder::ForMap();
+  Node* store2 = graph()->NewNode(simplified()->StoreField(access2), object1,
+                                  object2, store1, control);
+  Reduction r2 = Reduce(graph()->NewNode(simplified()->LoadField(access2),
+                                         object1, store2, control));
+  ASSERT_TRUE(r2.Changed());
+  EXPECT_EQ(object2, r2.replacement());
+
+  Node* store3 = graph()->NewNode(
+      simplified()->StoreBuffer(BufferAccess(kExternalInt8Array)), object2,
+      value, Int32Constant(10), object1, store2, control);
+
+  Reduction r3 = Reduce(graph()->NewNode(simplified()->LoadField(access1),
+                                         object2, store3, control));
+  ASSERT_FALSE(r3.Changed());
+
+  Reduction r4 = Reduce(graph()->NewNode(simplified()->LoadField(access1),
+                                         object1, store3, control));
+  ASSERT_TRUE(r4.Changed());
+  EXPECT_EQ(value, r4.replacement());
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/machine-operator-reducer-unittest.cc b/test/unittests/compiler/machine-operator-reducer-unittest.cc
new file mode 100644
index 0000000..6fdba35
--- /dev/null
+++ b/test/unittests/compiler/machine-operator-reducer-unittest.cc
@@ -0,0 +1,1383 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/bits.h"
+#include "src/base/division-by-constant.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/machine-operator-reducer.h"
+#include "src/compiler/typer.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::AllOf;
+using testing::BitEq;
+using testing::Capture;
+using testing::CaptureEq;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class MachineOperatorReducerTest : public TypedGraphTest {
+ public:
+  explicit MachineOperatorReducerTest(int num_parameters = 2)
+      : TypedGraphTest(num_parameters), machine_(zone()) {}
+
+ protected:
+  Reduction Reduce(Node* node) {
+    JSOperatorBuilder javascript(zone());
+    JSGraph jsgraph(graph(), common(), &javascript, &machine_);
+    MachineOperatorReducer reducer(&jsgraph);
+    return reducer.Reduce(node);
+  }
+
+  Matcher<Node*> IsTruncatingDiv(const Matcher<Node*>& dividend_matcher,
+                                 const int32_t divisor) {
+    base::MagicNumbersForDivision<uint32_t> const mag =
+        base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
+    int32_t const multiplier = bit_cast<int32_t>(mag.multiplier);
+    int32_t const shift = bit_cast<int32_t>(mag.shift);
+    Matcher<Node*> quotient_matcher =
+        IsInt32MulHigh(dividend_matcher, IsInt32Constant(multiplier));
+    if (divisor > 0 && multiplier < 0) {
+      quotient_matcher = IsInt32Add(quotient_matcher, dividend_matcher);
+    } else if (divisor < 0 && multiplier > 0) {
+      quotient_matcher = IsInt32Sub(quotient_matcher, dividend_matcher);
+    }
+    if (shift) {
+      quotient_matcher = IsWord32Sar(quotient_matcher, IsInt32Constant(shift));
+    }
+    return IsInt32Add(quotient_matcher,
+                      IsWord32Shr(dividend_matcher, IsInt32Constant(31)));
+  }
+
+  MachineOperatorBuilder* machine() { return &machine_; }
+
+ private:
+  MachineOperatorBuilder machine_;
+};
+
+
+template <typename T>
+class MachineOperatorReducerTestWithParam
+    : public MachineOperatorReducerTest,
+      public ::testing::WithParamInterface<T> {
+ public:
+  explicit MachineOperatorReducerTestWithParam(int num_parameters = 2)
+      : MachineOperatorReducerTest(num_parameters) {}
+  ~MachineOperatorReducerTestWithParam() OVERRIDE {}
+};
+
+
+namespace {
+
+const float kFloat32Values[] = {
+    -std::numeric_limits<float>::infinity(), -2.70497e+38f, -1.4698e+37f,
+    -1.22813e+35f,                           -1.20555e+35f, -1.34584e+34f,
+    -1.0079e+32f,                            -6.49364e+26f, -3.06077e+25f,
+    -1.46821e+25f,                           -1.17658e+23f, -1.9617e+22f,
+    -2.7357e+20f,                            -1.48708e+13f, -1.89633e+12f,
+    -4.66622e+11f,                           -2.22581e+11f, -1.45381e+10f,
+    -1.3956e+09f,                            -1.32951e+09f, -1.30721e+09f,
+    -1.19756e+09f,                           -9.26822e+08f, -6.35647e+08f,
+    -4.00037e+08f,                           -1.81227e+08f, -5.09256e+07f,
+    -964300.0f,                              -192446.0f,    -28455.0f,
+    -27194.0f,                               -26401.0f,     -20575.0f,
+    -17069.0f,                               -9167.0f,      -960.178f,
+    -113.0f,                                 -62.0f,        -15.0f,
+    -7.0f,                                   -0.0256635f,   -4.60374e-07f,
+    -3.63759e-10f,                           -4.30175e-14f, -5.27385e-15f,
+    -1.48084e-15f,                           -1.05755e-19f, -3.2995e-21f,
+    -1.67354e-23f,                           -1.11885e-23f, -1.78506e-30f,
+    -5.07594e-31f,                           -3.65799e-31f, -1.43718e-34f,
+    -1.27126e-38f,                           -0.0f,         0.0f,
+    1.17549e-38f,                            1.56657e-37f,  4.08512e-29f,
+    3.31357e-28f,                            6.25073e-22f,  4.1723e-13f,
+    1.44343e-09f,                            5.27004e-08f,  9.48298e-08f,
+    5.57888e-07f,                            4.89988e-05f,  0.244326f,
+    12.4895f,                                19.0f,         47.0f,
+    106.0f,                                  538.324f,      564.536f,
+    819.124f,                                7048.0f,       12611.0f,
+    19878.0f,                                20309.0f,      797056.0f,
+    1.77219e+09f,                            1.51116e+11f,  4.18193e+13f,
+    3.59167e+16f,                            3.38211e+19f,  2.67488e+20f,
+    1.78831e+21f,                            9.20914e+21f,  8.35654e+23f,
+    1.4495e+24f,                             5.94015e+25f,  4.43608e+30f,
+    2.44502e+33f,                            2.61152e+33f,  1.38178e+37f,
+    1.71306e+37f,                            3.31899e+38f,  3.40282e+38f,
+    std::numeric_limits<float>::infinity()};
+
+
+const double kFloat64Values[] = {
+    -V8_INFINITY,  -4.23878e+275, -5.82632e+265, -6.60355e+220, -6.26172e+212,
+    -2.56222e+211, -4.82408e+201, -1.84106e+157, -1.63662e+127, -1.55772e+100,
+    -1.67813e+72,  -2.3382e+55,   -3.179e+30,    -1.441e+09,    -1.0647e+09,
+    -7.99361e+08,  -5.77375e+08,  -2.20984e+08,  -32757,        -13171,
+    -9970,         -3984,         -107,          -105,          -92,
+    -77,           -61,           -0.000208163,  -1.86685e-06,  -1.17296e-10,
+    -9.26358e-11,  -5.08004e-60,  -1.74753e-65,  -1.06561e-71,  -5.67879e-79,
+    -5.78459e-130, -2.90989e-171, -7.15489e-243, -3.76242e-252, -1.05639e-263,
+    -4.40497e-267, -2.19666e-273, -4.9998e-276,  -5.59821e-278, -2.03855e-282,
+    -5.99335e-283, -7.17554e-284, -3.11744e-309, -0.0,          0.0,
+    2.22507e-308,  1.30127e-270,  7.62898e-260,  4.00313e-249,  3.16829e-233,
+    1.85244e-228,  2.03544e-129,  1.35126e-110,  1.01182e-106,  5.26333e-94,
+    1.35292e-90,   2.85394e-83,   1.78323e-77,   5.4967e-57,    1.03207e-25,
+    4.57401e-25,   1.58738e-05,   2,             125,           2310,
+    9636,          14802,         17168,         28945,         29305,
+    4.81336e+07,   1.41207e+08,   4.65962e+08,   1.40499e+09,   2.12648e+09,
+    8.80006e+30,   1.4446e+45,    1.12164e+54,   2.48188e+89,   6.71121e+102,
+    3.074e+112,    4.9699e+152,   5.58383e+166,  4.30654e+172,  7.08824e+185,
+    9.6586e+214,   2.028e+223,    6.63277e+243,  1.56192e+261,  1.23202e+269,
+    5.72883e+289,  8.5798e+290,   1.40256e+294,  1.79769e+308,  V8_INFINITY};
+
+
+const int32_t kInt32Values[] = {
+    std::numeric_limits<int32_t>::min(), -1914954528, -1698749618,
+    -1578693386,                         -1577976073, -1573998034,
+    -1529085059,                         -1499540537, -1299205097,
+    -1090814845,                         -938186388,  -806828902,
+    -750927650,                          -520676892,  -513661538,
+    -453036354,                          -433622833,  -282638793,
+    -28375,                              -27788,      -22770,
+    -18806,                              -14173,      -11956,
+    -11200,                              -10212,      -8160,
+    -3751,                               -2758,       -1522,
+    -121,                                -120,        -118,
+    -117,                                -106,        -84,
+    -80,                                 -74,         -59,
+    -52,                                 -48,         -39,
+    -35,                                 -17,         -11,
+    -10,                                 -9,          -7,
+    -5,                                  0,           9,
+    12,                                  17,          23,
+    29,                                  31,          33,
+    35,                                  40,          47,
+    55,                                  56,          62,
+    64,                                  67,          68,
+    69,                                  74,          79,
+    84,                                  89,          90,
+    97,                                  104,         118,
+    124,                                 126,         127,
+    7278,                                17787,       24136,
+    24202,                               25570,       26680,
+    30242,                               32399,       420886487,
+    642166225,                           821912648,   822577803,
+    851385718,                           1212241078,  1411419304,
+    1589626102,                          1596437184,  1876245816,
+    1954730266,                          2008792749,  2045320228,
+    std::numeric_limits<int32_t>::max()};
+
+
+const int64_t kInt64Values[] = {
+    std::numeric_limits<int64_t>::min(), V8_INT64_C(-8974392461363618006),
+    V8_INT64_C(-8874367046689588135),    V8_INT64_C(-8269197512118230839),
+    V8_INT64_C(-8146091527100606733),    V8_INT64_C(-7550917981466150848),
+    V8_INT64_C(-7216590251577894337),    V8_INT64_C(-6464086891160048440),
+    V8_INT64_C(-6365616494908257190),    V8_INT64_C(-6305630541365849726),
+    V8_INT64_C(-5982222642272245453),    V8_INT64_C(-5510103099058504169),
+    V8_INT64_C(-5496838675802432701),    V8_INT64_C(-4047626578868642657),
+    V8_INT64_C(-4033755046900164544),    V8_INT64_C(-3554299241457877041),
+    V8_INT64_C(-2482258764588614470),    V8_INT64_C(-1688515425526875335),
+    V8_INT64_C(-924784137176548532),     V8_INT64_C(-725316567157391307),
+    V8_INT64_C(-439022654781092241),     V8_INT64_C(-105545757668917080),
+    V8_INT64_C(-2088319373),             V8_INT64_C(-2073699916),
+    V8_INT64_C(-1844949911),             V8_INT64_C(-1831090548),
+    V8_INT64_C(-1756711933),             V8_INT64_C(-1559409497),
+    V8_INT64_C(-1281179700),             V8_INT64_C(-1211513985),
+    V8_INT64_C(-1182371520),             V8_INT64_C(-785934753),
+    V8_INT64_C(-767480697),              V8_INT64_C(-705745662),
+    V8_INT64_C(-514362436),              V8_INT64_C(-459916580),
+    V8_INT64_C(-312328082),              V8_INT64_C(-302949707),
+    V8_INT64_C(-285499304),              V8_INT64_C(-125701262),
+    V8_INT64_C(-95139843),               V8_INT64_C(-32768),
+    V8_INT64_C(-27542),                  V8_INT64_C(-23600),
+    V8_INT64_C(-18582),                  V8_INT64_C(-17770),
+    V8_INT64_C(-9086),                   V8_INT64_C(-9010),
+    V8_INT64_C(-8244),                   V8_INT64_C(-2890),
+    V8_INT64_C(-103),                    V8_INT64_C(-34),
+    V8_INT64_C(-27),                     V8_INT64_C(-25),
+    V8_INT64_C(-9),                      V8_INT64_C(-7),
+    V8_INT64_C(0),                       V8_INT64_C(2),
+    V8_INT64_C(38),                      V8_INT64_C(58),
+    V8_INT64_C(65),                      V8_INT64_C(93),
+    V8_INT64_C(111),                     V8_INT64_C(1003),
+    V8_INT64_C(1267),                    V8_INT64_C(12797),
+    V8_INT64_C(23122),                   V8_INT64_C(28200),
+    V8_INT64_C(30888),                   V8_INT64_C(42648848),
+    V8_INT64_C(116836693),               V8_INT64_C(263003643),
+    V8_INT64_C(571039860),               V8_INT64_C(1079398689),
+    V8_INT64_C(1145196402),              V8_INT64_C(1184846321),
+    V8_INT64_C(1758281648),              V8_INT64_C(1859991374),
+    V8_INT64_C(1960251588),              V8_INT64_C(2042443199),
+    V8_INT64_C(296220586027987448),      V8_INT64_C(1015494173071134726),
+    V8_INT64_C(1151237951914455318),     V8_INT64_C(1331941174616854174),
+    V8_INT64_C(2022020418667972654),     V8_INT64_C(2450251424374977035),
+    V8_INT64_C(3668393562685561486),     V8_INT64_C(4858229301215502171),
+    V8_INT64_C(4919426235170669383),     V8_INT64_C(5034286595330341762),
+    V8_INT64_C(5055797915536941182),     V8_INT64_C(6072389716149252074),
+    V8_INT64_C(6185309910199801210),     V8_INT64_C(6297328311011094138),
+    V8_INT64_C(6932372858072165827),     V8_INT64_C(8483640924987737210),
+    V8_INT64_C(8663764179455849203),     V8_INT64_C(8877197042645298254),
+    V8_INT64_C(8901543506779157333),     std::numeric_limits<int64_t>::max()};
+
+
+const uint32_t kUint32Values[] = {
+    0x00000000, 0x00000001, 0xffffffff, 0x1b09788b, 0x04c5fce8, 0xcc0de5bf,
+    0x273a798e, 0x187937a3, 0xece3af83, 0x5495a16b, 0x0b668ecc, 0x11223344,
+    0x0000009e, 0x00000043, 0x0000af73, 0x0000116b, 0x00658ecc, 0x002b3b4c,
+    0x88776655, 0x70000000, 0x07200000, 0x7fffffff, 0x56123761, 0x7fffff00,
+    0x761c4761, 0x80000000, 0x88888888, 0xa0000000, 0xdddddddd, 0xe0000000,
+    0xeeeeeeee, 0xfffffffd, 0xf0000000, 0x007fffff, 0x003fffff, 0x001fffff,
+    0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff, 0x0000ffff, 0x00007fff,
+    0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff};
+
+}  // namespace
+
+
+// -----------------------------------------------------------------------------
+// Unary operators
+
+
+namespace {
+
+struct UnaryOperator {
+  const Operator* (MachineOperatorBuilder::*constructor)();
+  const char* constructor_name;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const UnaryOperator& unop) {
+  return os << unop.constructor_name;
+}
+
+
+static const UnaryOperator kUnaryOperators[] = {
+    {&MachineOperatorBuilder::ChangeInt32ToFloat64, "ChangeInt32ToFloat64"},
+    {&MachineOperatorBuilder::ChangeUint32ToFloat64, "ChangeUint32ToFloat64"},
+    {&MachineOperatorBuilder::ChangeFloat64ToInt32, "ChangeFloat64ToInt32"},
+    {&MachineOperatorBuilder::ChangeFloat64ToUint32, "ChangeFloat64ToUint32"},
+    {&MachineOperatorBuilder::ChangeInt32ToInt64, "ChangeInt32ToInt64"},
+    {&MachineOperatorBuilder::ChangeUint32ToUint64, "ChangeUint32ToUint64"},
+    {&MachineOperatorBuilder::TruncateFloat64ToInt32, "TruncateFloat64ToInt32"},
+    {&MachineOperatorBuilder::TruncateInt64ToInt32, "TruncateInt64ToInt32"}};
+
+}  // namespace
+
+
+typedef MachineOperatorReducerTestWithParam<UnaryOperator>
+    MachineUnaryOperatorReducerTest;
+
+
+TEST_P(MachineUnaryOperatorReducerTest, Parameter) {
+  const UnaryOperator unop = GetParam();
+  Reduction reduction =
+      Reduce(graph()->NewNode((machine()->*unop.constructor)(), Parameter(0)));
+  EXPECT_FALSE(reduction.Changed());
+}
+
+
+INSTANTIATE_TEST_CASE_P(MachineOperatorReducerTest,
+                        MachineUnaryOperatorReducerTest,
+                        ::testing::ValuesIn(kUnaryOperators));
+
+
+// -----------------------------------------------------------------------------
+// ChangeFloat64ToFloat32
+
+
+TEST_F(MachineOperatorReducerTest, ChangeFloat64ToFloat32WithConstant) {
+  TRACED_FOREACH(float, x, kFloat32Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        machine()->ChangeFloat32ToFloat64(), Float32Constant(x)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq<double>(x)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeFloat64ToInt32
+
+
+TEST_F(MachineOperatorReducerTest,
+       ChangeFloat64ToInt32WithChangeInt32ToFloat64) {
+  Node* value = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      machine()->ChangeFloat64ToInt32(),
+      graph()->NewNode(machine()->ChangeInt32ToFloat64(), value)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(value, reduction.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, ChangeFloat64ToInt32WithConstant) {
+  TRACED_FOREACH(int32_t, x, kInt32Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        machine()->ChangeFloat64ToInt32(), Float64Constant(FastI2D(x))));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsInt32Constant(x));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeFloat64ToUint32
+
+
+TEST_F(MachineOperatorReducerTest,
+       ChangeFloat64ToUint32WithChangeUint32ToFloat64) {
+  Node* value = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      machine()->ChangeFloat64ToUint32(),
+      graph()->NewNode(machine()->ChangeUint32ToFloat64(), value)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(value, reduction.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, ChangeFloat64ToUint32WithConstant) {
+  TRACED_FOREACH(uint32_t, x, kUint32Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        machine()->ChangeFloat64ToUint32(), Float64Constant(FastUI2D(x))));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsInt32Constant(bit_cast<int32_t>(x)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeInt32ToFloat64
+
+
+TEST_F(MachineOperatorReducerTest, ChangeInt32ToFloat64WithConstant) {
+  TRACED_FOREACH(int32_t, x, kInt32Values) {
+    Reduction reduction = Reduce(
+        graph()->NewNode(machine()->ChangeInt32ToFloat64(), Int32Constant(x)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq(FastI2D(x))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeInt32ToInt64
+
+
+TEST_F(MachineOperatorReducerTest, ChangeInt32ToInt64WithConstant) {
+  TRACED_FOREACH(int32_t, x, kInt32Values) {
+    Reduction reduction = Reduce(
+        graph()->NewNode(machine()->ChangeInt32ToInt64(), Int32Constant(x)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsInt64Constant(x));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeUint32ToFloat64
+
+
+TEST_F(MachineOperatorReducerTest, ChangeUint32ToFloat64WithConstant) {
+  TRACED_FOREACH(uint32_t, x, kUint32Values) {
+    Reduction reduction =
+        Reduce(graph()->NewNode(machine()->ChangeUint32ToFloat64(),
+                                Int32Constant(bit_cast<int32_t>(x))));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq(FastUI2D(x))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeUint32ToUint64
+
+
+TEST_F(MachineOperatorReducerTest, ChangeUint32ToUint64WithConstant) {
+  TRACED_FOREACH(uint32_t, x, kUint32Values) {
+    Reduction reduction =
+        Reduce(graph()->NewNode(machine()->ChangeUint32ToUint64(),
+                                Int32Constant(bit_cast<int32_t>(x))));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(),
+                IsInt64Constant(bit_cast<int64_t>(static_cast<uint64_t>(x))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// TruncateFloat64ToFloat32
+
+
+TEST_F(MachineOperatorReducerTest,
+       TruncateFloat64ToFloat32WithChangeFloat32ToFloat64) {
+  Node* value = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      machine()->TruncateFloat64ToFloat32(),
+      graph()->NewNode(machine()->ChangeFloat32ToFloat64(), value)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(value, reduction.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, TruncateFloat64ToFloat32WithConstant) {
+  TRACED_FOREACH(double, x, kFloat64Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        machine()->TruncateFloat64ToFloat32(), Float64Constant(x)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(),
+                IsFloat32Constant(BitEq(DoubleToFloat32(x))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// TruncateFloat64ToInt32
+
+
+TEST_F(MachineOperatorReducerTest,
+       TruncateFloat64ToInt32WithChangeInt32ToFloat64) {
+  Node* value = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      machine()->TruncateFloat64ToInt32(),
+      graph()->NewNode(machine()->ChangeInt32ToFloat64(), value)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(value, reduction.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, TruncateFloat64ToInt32WithConstant) {
+  TRACED_FOREACH(double, x, kFloat64Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        machine()->TruncateFloat64ToInt32(), Float64Constant(x)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsInt32Constant(DoubleToInt32(x)));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, TruncateFloat64ToInt32WithPhi) {
+  Node* const p0 = Parameter(0);
+  Node* const p1 = Parameter(1);
+  Node* const merge = graph()->start();
+  Reduction reduction = Reduce(graph()->NewNode(
+      machine()->TruncateFloat64ToInt32(),
+      graph()->NewNode(common()->Phi(kMachFloat64, 2), p0, p1, merge)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(),
+              IsPhi(kMachInt32, IsTruncateFloat64ToInt32(p0),
+                    IsTruncateFloat64ToInt32(p1), merge));
+}
+
+
+// -----------------------------------------------------------------------------
+// TruncateInt64ToInt32
+
+
+TEST_F(MachineOperatorReducerTest, TruncateInt64ToInt32WithChangeInt32ToInt64) {
+  Node* value = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      machine()->TruncateInt64ToInt32(),
+      graph()->NewNode(machine()->ChangeInt32ToInt64(), value)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(value, reduction.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, TruncateInt64ToInt32WithConstant) {
+  TRACED_FOREACH(int64_t, x, kInt64Values) {
+    Reduction reduction = Reduce(
+        graph()->NewNode(machine()->TruncateInt64ToInt32(), Int64Constant(x)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(),
+                IsInt32Constant(bit_cast<int32_t>(
+                    static_cast<uint32_t>(bit_cast<uint64_t>(x)))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Word32And
+
+
+TEST_F(MachineOperatorReducerTest, Word32AndWithWord32AndWithConstant) {
+  Node* const p0 = Parameter(0);
+
+  TRACED_FOREACH(int32_t, k, kInt32Values) {
+    TRACED_FOREACH(int32_t, l, kInt32Values) {
+      if (k == 0 || k == -1 || l == 0 || l == -1) continue;
+
+      // (x & K) & L => x & (K & L)
+      Reduction const r1 = Reduce(graph()->NewNode(
+          machine()->Word32And(),
+          graph()->NewNode(machine()->Word32And(), p0, Int32Constant(k)),
+          Int32Constant(l)));
+      ASSERT_TRUE(r1.Changed());
+      EXPECT_THAT(r1.replacement(),
+                  (k & l) ? IsWord32And(p0, IsInt32Constant(k & l))
+                          : IsInt32Constant(0));
+
+      // (K & x) & L => x & (K & L)
+      Reduction const r2 = Reduce(graph()->NewNode(
+          machine()->Word32And(),
+          graph()->NewNode(machine()->Word32And(), Int32Constant(k), p0),
+          Int32Constant(l)));
+      ASSERT_TRUE(r2.Changed());
+      EXPECT_THAT(r2.replacement(),
+                  (k & l) ? IsWord32And(p0, IsInt32Constant(k & l))
+                          : IsInt32Constant(0));
+    }
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Word32AndWithInt32AddAndConstant) {
+  Node* const p0 = Parameter(0);
+  Node* const p1 = Parameter(1);
+
+  TRACED_FORRANGE(int32_t, l, 1, 31) {
+    TRACED_FOREACH(int32_t, k, kInt32Values) {
+      if ((k << l) == 0) continue;
+      // (x + (K << L)) & (-1 << L) => (x & (-1 << L)) + (K << L)
+      Reduction const r = Reduce(graph()->NewNode(
+          machine()->Word32And(),
+          graph()->NewNode(machine()->Int32Add(), p0, Int32Constant(k << l)),
+          Int32Constant(-1 << l)));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)),
+                             IsInt32Constant(k << l)));
+    }
+
+    Node* s1 = graph()->NewNode(machine()->Word32Shl(), p1, Int32Constant(l));
+
+    // (y << L + x) & (-1 << L) => (x & (-1 << L)) + y << L
+    Reduction const r1 = Reduce(graph()->NewNode(
+        machine()->Word32And(), graph()->NewNode(machine()->Int32Add(), s1, p0),
+        Int32Constant(-1 << l)));
+    ASSERT_TRUE(r1.Changed());
+    EXPECT_THAT(r1.replacement(),
+                IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)), s1));
+
+    // (x + y << L) & (-1 << L) => (x & (-1 << L)) + y << L
+    Reduction const r2 = Reduce(graph()->NewNode(
+        machine()->Word32And(), graph()->NewNode(machine()->Int32Add(), p0, s1),
+        Int32Constant(-1 << l)));
+    ASSERT_TRUE(r2.Changed());
+    EXPECT_THAT(r2.replacement(),
+                IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)), s1));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest,
+       Word32AndWithInt32AddAndInt32MulAndConstant) {
+  Node* const p0 = Parameter(0);
+  Node* const p1 = Parameter(1);
+
+  TRACED_FORRANGE(int32_t, l, 1, 31) {
+    TRACED_FOREACH(int32_t, k, kInt32Values) {
+      if ((k << l) == 0) continue;
+      // (y * (K << L) + x) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
+      Reduction const r1 = Reduce(graph()->NewNode(
+          machine()->Word32And(),
+          graph()->NewNode(machine()->Int32Add(),
+                           graph()->NewNode(machine()->Int32Mul(), p1,
+                                            Int32Constant(k << l)),
+                           p0),
+          Int32Constant(-1 << l)));
+      ASSERT_TRUE(r1.Changed());
+      EXPECT_THAT(r1.replacement(),
+                  IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)),
+                             IsInt32Mul(p1, IsInt32Constant(k << l))));
+
+      // (x + y * (K << L)) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
+      Reduction const r2 = Reduce(graph()->NewNode(
+          machine()->Word32And(),
+          graph()->NewNode(machine()->Int32Add(), p0,
+                           graph()->NewNode(machine()->Int32Mul(), p1,
+                                            Int32Constant(k << l))),
+          Int32Constant(-1 << l)));
+      ASSERT_TRUE(r2.Changed());
+      EXPECT_THAT(r2.replacement(),
+                  IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)),
+                             IsInt32Mul(p1, IsInt32Constant(k << l))));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Word32Xor
+
+
+TEST_F(MachineOperatorReducerTest, Word32XorWithWord32XorAndMinusOne) {
+  Node* const p0 = Parameter(0);
+
+  // (x ^ -1) ^ -1 => x
+  Reduction r1 = Reduce(graph()->NewNode(
+      machine()->Word32Xor(),
+      graph()->NewNode(machine()->Word32Xor(), p0, Int32Constant(-1)),
+      Int32Constant(-1)));
+  ASSERT_TRUE(r1.Changed());
+  EXPECT_EQ(r1.replacement(), p0);
+
+  // -1 ^ (x ^ -1) => x
+  Reduction r2 = Reduce(graph()->NewNode(
+      machine()->Word32Xor(), Int32Constant(-1),
+      graph()->NewNode(machine()->Word32Xor(), p0, Int32Constant(-1))));
+  ASSERT_TRUE(r2.Changed());
+  EXPECT_EQ(r2.replacement(), p0);
+
+  // (-1 ^ x) ^ -1 => x
+  Reduction r3 = Reduce(graph()->NewNode(
+      machine()->Word32Xor(),
+      graph()->NewNode(machine()->Word32Xor(), Int32Constant(-1), p0),
+      Int32Constant(-1)));
+  ASSERT_TRUE(r3.Changed());
+  EXPECT_EQ(r3.replacement(), p0);
+
+  // -1 ^ (-1 ^ x) => x
+  Reduction r4 = Reduce(graph()->NewNode(
+      machine()->Word32Xor(), Int32Constant(-1),
+      graph()->NewNode(machine()->Word32Xor(), Int32Constant(-1), p0)));
+  ASSERT_TRUE(r4.Changed());
+  EXPECT_EQ(r4.replacement(), p0);
+}
+
+
+// -----------------------------------------------------------------------------
+// Word32Ror
+
+
+TEST_F(MachineOperatorReducerTest, ReduceToWord32RorWithParameters) {
+  Node* value = Parameter(0);
+  Node* shift = Parameter(1);
+  Node* sub = graph()->NewNode(machine()->Int32Sub(), Int32Constant(32), shift);
+
+  // Testing rotate left.
+  Node* shl_l = graph()->NewNode(machine()->Word32Shl(), value, shift);
+  Node* shr_l = graph()->NewNode(machine()->Word32Shr(), value, sub);
+
+  // (x << y) | (x >>> (32 - y)) => x ror (32 - y)
+  Node* node1 = graph()->NewNode(machine()->Word32Or(), shl_l, shr_l);
+  Reduction reduction1 = Reduce(node1);
+  EXPECT_TRUE(reduction1.Changed());
+  EXPECT_EQ(reduction1.replacement(), node1);
+  EXPECT_THAT(reduction1.replacement(), IsWord32Ror(value, sub));
+
+  // (x >>> (32 - y)) | (x << y) => x ror (32 - y)
+  Node* node2 = graph()->NewNode(machine()->Word32Or(), shr_l, shl_l);
+  Reduction reduction2 = Reduce(node2);
+  EXPECT_TRUE(reduction2.Changed());
+  EXPECT_EQ(reduction2.replacement(), node2);
+  EXPECT_THAT(reduction2.replacement(), IsWord32Ror(value, sub));
+
+  // Testing rotate right.
+  Node* shl_r = graph()->NewNode(machine()->Word32Shl(), value, sub);
+  Node* shr_r = graph()->NewNode(machine()->Word32Shr(), value, shift);
+
+  // (x << (32 - y)) | (x >>> y) => x ror y
+  Node* node3 = graph()->NewNode(machine()->Word32Or(), shl_r, shr_r);
+  Reduction reduction3 = Reduce(node3);
+  EXPECT_TRUE(reduction3.Changed());
+  EXPECT_EQ(reduction3.replacement(), node3);
+  EXPECT_THAT(reduction3.replacement(), IsWord32Ror(value, shift));
+
+  // (x >>> y) | (x << (32 - y)) => x ror y
+  Node* node4 = graph()->NewNode(machine()->Word32Or(), shr_r, shl_r);
+  Reduction reduction4 = Reduce(node4);
+  EXPECT_TRUE(reduction4.Changed());
+  EXPECT_EQ(reduction4.replacement(), node4);
+  EXPECT_THAT(reduction4.replacement(), IsWord32Ror(value, shift));
+}
+
+
+TEST_F(MachineOperatorReducerTest, ReduceToWord32RorWithConstant) {
+  Node* value = Parameter(0);
+  TRACED_FORRANGE(int32_t, k, 0, 31) {
+    Node* shl =
+        graph()->NewNode(machine()->Word32Shl(), value, Int32Constant(k));
+    Node* shr =
+        graph()->NewNode(machine()->Word32Shr(), value, Int32Constant(32 - k));
+
+    // (x << K) | (x >>> ((32 - K) - y)) => x ror (32 - K)
+    Node* node1 = graph()->NewNode(machine()->Word32Or(), shl, shr);
+    Reduction reduction1 = Reduce(node1);
+    EXPECT_TRUE(reduction1.Changed());
+    EXPECT_EQ(reduction1.replacement(), node1);
+    EXPECT_THAT(reduction1.replacement(),
+                IsWord32Ror(value, IsInt32Constant(32 - k)));
+
+    // (x >>> (32 - K)) | (x << K) => x ror (32 - K)
+    Node* node2 = graph()->NewNode(machine()->Word32Or(), shr, shl);
+    Reduction reduction2 = Reduce(node2);
+    EXPECT_TRUE(reduction2.Changed());
+    EXPECT_EQ(reduction2.replacement(), node2);
+    EXPECT_THAT(reduction2.replacement(),
+                IsWord32Ror(value, IsInt32Constant(32 - k)));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Word32RorWithZeroShift) {
+  Node* value = Parameter(0);
+  Node* node =
+      graph()->NewNode(machine()->Word32Ror(), value, Int32Constant(0));
+  Reduction reduction = Reduce(node);
+  EXPECT_TRUE(reduction.Changed());
+  EXPECT_EQ(reduction.replacement(), value);
+}
+
+
+TEST_F(MachineOperatorReducerTest, Word32RorWithConstants) {
+  TRACED_FOREACH(int32_t, x, kUint32Values) {
+    TRACED_FORRANGE(int32_t, y, 0, 31) {
+      Node* node = graph()->NewNode(machine()->Word32Ror(), Int32Constant(x),
+                                    Int32Constant(y));
+      Reduction reduction = Reduce(node);
+      EXPECT_TRUE(reduction.Changed());
+      EXPECT_THAT(reduction.replacement(),
+                  IsInt32Constant(base::bits::RotateRight32(x, y)));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Word32Sar
+
+
+TEST_F(MachineOperatorReducerTest, Word32SarWithWord32ShlAndLoad) {
+  Node* const p0 = Parameter(0);
+  Node* const p1 = Parameter(1);
+  {
+    Node* const l = graph()->NewNode(machine()->Load(kMachInt8), p0, p1,
+                                     graph()->start(), graph()->start());
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Word32Sar(),
+        graph()->NewNode(machine()->Word32Shl(), l, Int32Constant(24)),
+        Int32Constant(24)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(l, r.replacement());
+  }
+  {
+    Node* const l = graph()->NewNode(machine()->Load(kMachInt16), p0, p1,
+                                     graph()->start(), graph()->start());
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Word32Sar(),
+        graph()->NewNode(machine()->Word32Shl(), l, Int32Constant(16)),
+        Int32Constant(16)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(l, r.replacement());
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Word32Shl
+
+
+TEST_F(MachineOperatorReducerTest, Word32ShlWithZeroShift) {
+  Node* p0 = Parameter(0);
+  Node* node = graph()->NewNode(machine()->Word32Shl(), p0, Int32Constant(0));
+  Reduction r = Reduce(node);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_EQ(p0, r.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, Word32ShlWithWord32Sar) {
+  Node* p0 = Parameter(0);
+  TRACED_FORRANGE(int32_t, x, 1, 31) {
+    Node* node = graph()->NewNode(
+        machine()->Word32Shl(),
+        graph()->NewNode(machine()->Word32Sar(), p0, Int32Constant(x)),
+        Int32Constant(x));
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+    int32_t m = bit_cast<int32_t>(~((1U << x) - 1U));
+    EXPECT_THAT(r.replacement(), IsWord32And(p0, IsInt32Constant(m)));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest,
+       Word32ShlWithWord32SarAndInt32AddAndConstant) {
+  Node* const p0 = Parameter(0);
+  TRACED_FOREACH(int32_t, k, kInt32Values) {
+    TRACED_FORRANGE(int32_t, l, 1, 31) {
+      if ((k << l) == 0) continue;
+      // (x + (K << L)) >> L << L => (x & (-1 << L)) + (K << L)
+      Reduction const r = Reduce(graph()->NewNode(
+          machine()->Word32Shl(),
+          graph()->NewNode(machine()->Word32Sar(),
+                           graph()->NewNode(machine()->Int32Add(), p0,
+                                            Int32Constant(k << l)),
+                           Int32Constant(l)),
+          Int32Constant(l)));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)),
+                             IsInt32Constant(k << l)));
+    }
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Word32ShlWithWord32Shr) {
+  Node* p0 = Parameter(0);
+  TRACED_FORRANGE(int32_t, x, 1, 31) {
+    Node* node = graph()->NewNode(
+        machine()->Word32Shl(),
+        graph()->NewNode(machine()->Word32Shr(), p0, Int32Constant(x)),
+        Int32Constant(x));
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+    int32_t m = bit_cast<int32_t>(~((1U << x) - 1U));
+    EXPECT_THAT(r.replacement(), IsWord32And(p0, IsInt32Constant(m)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Int32Div
+
+
+TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
+  Node* const p0 = Parameter(0);
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(0), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(1), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(r.replacement(), p0);
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(-1), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Sub(IsInt32Constant(0), p0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(2), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsWord32Sar(IsInt32Add(IsWord32Shr(p0, IsInt32Constant(31)), p0),
+                    IsInt32Constant(1)));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(-2), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsInt32Sub(
+            IsInt32Constant(0),
+            IsWord32Sar(IsInt32Add(IsWord32Shr(p0, IsInt32Constant(31)), p0),
+                        IsInt32Constant(1))));
+  }
+  TRACED_FORRANGE(int32_t, shift, 2, 30) {
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Int32Div(), p0,
+                                Int32Constant(1 << shift), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsWord32Sar(IsInt32Add(IsWord32Shr(IsWord32Sar(p0, IsInt32Constant(31)),
+                                           IsInt32Constant(32 - shift)),
+                               p0),
+                    IsInt32Constant(shift)));
+  }
+  TRACED_FORRANGE(int32_t, shift, 2, 31) {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0,
+        Uint32Constant(bit_cast<uint32_t, int32_t>(-1) << shift),
+        graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsInt32Sub(
+            IsInt32Constant(0),
+            IsWord32Sar(
+                IsInt32Add(IsWord32Shr(IsWord32Sar(p0, IsInt32Constant(31)),
+                                       IsInt32Constant(32 - shift)),
+                           p0),
+                IsInt32Constant(shift))));
+  }
+  TRACED_FOREACH(int32_t, divisor, kInt32Values) {
+    if (divisor < 0) {
+      if (base::bits::IsPowerOfTwo32(-divisor)) continue;
+      Reduction const r = Reduce(graph()->NewNode(
+          machine()->Int32Div(), p0, Int32Constant(divisor), graph()->start()));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(), IsInt32Sub(IsInt32Constant(0),
+                                              IsTruncatingDiv(p0, -divisor)));
+    } else if (divisor > 0) {
+      if (base::bits::IsPowerOfTwo32(divisor)) continue;
+      Reduction const r = Reduce(graph()->NewNode(
+          machine()->Int32Div(), p0, Int32Constant(divisor), graph()->start()));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(), IsTruncatingDiv(p0, divisor));
+    }
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Int32DivWithParameters) {
+  Node* const p0 = Parameter(0);
+  Reduction const r =
+      Reduce(graph()->NewNode(machine()->Int32Div(), p0, p0, graph()->start()));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(
+      r.replacement(),
+      IsWord32Equal(IsWord32Equal(p0, IsInt32Constant(0)), IsInt32Constant(0)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Uint32Div
+
+
+TEST_F(MachineOperatorReducerTest, Uint32DivWithConstant) {
+  Node* const p0 = Parameter(0);
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Div(), Int32Constant(0), p0, graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Div(), p0, Int32Constant(0), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Div(), p0, Int32Constant(1), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(r.replacement(), p0);
+  }
+  TRACED_FOREACH(uint32_t, dividend, kUint32Values) {
+    TRACED_FOREACH(uint32_t, divisor, kUint32Values) {
+      Reduction const r = Reduce(
+          graph()->NewNode(machine()->Uint32Div(), Uint32Constant(dividend),
+                           Uint32Constant(divisor), graph()->start()));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsInt32Constant(bit_cast<int32_t>(
+                      base::bits::UnsignedDiv32(dividend, divisor))));
+    }
+  }
+  TRACED_FORRANGE(uint32_t, shift, 1, 31) {
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Uint32Div(), p0,
+                                Uint32Constant(1u << shift), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsWord32Shr(p0, IsInt32Constant(bit_cast<int32_t>(shift))));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Uint32DivWithParameters) {
+  Node* const p0 = Parameter(0);
+  Reduction const r = Reduce(
+      graph()->NewNode(machine()->Uint32Div(), p0, p0, graph()->start()));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(
+      r.replacement(),
+      IsWord32Equal(IsWord32Equal(p0, IsInt32Constant(0)), IsInt32Constant(0)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Int32Mod
+
+
+TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
+  Node* const p0 = Parameter(0);
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), Int32Constant(0), p0, graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0, Int32Constant(0), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0, Int32Constant(1), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0, Int32Constant(-1), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  TRACED_FOREACH(int32_t, dividend, kInt32Values) {
+    TRACED_FOREACH(int32_t, divisor, kInt32Values) {
+      Reduction const r = Reduce(
+          graph()->NewNode(machine()->Int32Mod(), Int32Constant(dividend),
+                           Int32Constant(divisor), graph()->start()));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsInt32Constant(base::bits::SignedMod32(dividend, divisor)));
+    }
+  }
+  TRACED_FORRANGE(int32_t, shift, 1, 30) {
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Int32Mod(), p0,
+                                Int32Constant(1 << shift), graph()->start()));
+    int32_t const mask = (1 << shift) - 1;
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsSelect(kMachInt32, IsInt32LessThan(p0, IsInt32Constant(0)),
+                 IsInt32Sub(IsInt32Constant(0),
+                            IsWord32And(IsInt32Sub(IsInt32Constant(0), p0),
+                                        IsInt32Constant(mask))),
+                 IsWord32And(p0, IsInt32Constant(mask))));
+  }
+  TRACED_FORRANGE(int32_t, shift, 1, 31) {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0,
+        Uint32Constant(bit_cast<uint32_t, int32_t>(-1) << shift),
+        graph()->start()));
+    int32_t const mask = bit_cast<int32_t, uint32_t>((1U << shift) - 1);
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsSelect(kMachInt32, IsInt32LessThan(p0, IsInt32Constant(0)),
+                 IsInt32Sub(IsInt32Constant(0),
+                            IsWord32And(IsInt32Sub(IsInt32Constant(0), p0),
+                                        IsInt32Constant(mask))),
+                 IsWord32And(p0, IsInt32Constant(mask))));
+  }
+  TRACED_FOREACH(int32_t, divisor, kInt32Values) {
+    if (divisor == 0 || base::bits::IsPowerOfTwo32(Abs(divisor))) continue;
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0, Int32Constant(divisor), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsInt32Sub(p0, IsInt32Mul(IsTruncatingDiv(p0, Abs(divisor)),
+                                          IsInt32Constant(Abs(divisor)))));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Int32ModWithParameters) {
+  Node* const p0 = Parameter(0);
+  Reduction const r =
+      Reduce(graph()->NewNode(machine()->Int32Mod(), p0, p0, graph()->start()));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+}
+
+
+// -----------------------------------------------------------------------------
+// Uint32Mod
+
+
+TEST_F(MachineOperatorReducerTest, Uint32ModWithConstant) {
+  Node* const p0 = Parameter(0);
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Mod(), p0, Int32Constant(0), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Mod(), Int32Constant(0), p0, graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Mod(), p0, Int32Constant(1), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  TRACED_FOREACH(uint32_t, dividend, kUint32Values) {
+    TRACED_FOREACH(uint32_t, divisor, kUint32Values) {
+      Reduction const r = Reduce(
+          graph()->NewNode(machine()->Uint32Mod(), Uint32Constant(dividend),
+                           Uint32Constant(divisor), graph()->start()));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsInt32Constant(bit_cast<int32_t>(
+                      base::bits::UnsignedMod32(dividend, divisor))));
+    }
+  }
+  TRACED_FORRANGE(uint32_t, shift, 1, 31) {
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Uint32Mod(), p0,
+                                Uint32Constant(1u << shift), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsWord32And(p0, IsInt32Constant(
+                                    bit_cast<int32_t>((1u << shift) - 1u))));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Uint32ModWithParameters) {
+  Node* const p0 = Parameter(0);
+  Reduction const r = Reduce(
+      graph()->NewNode(machine()->Uint32Mod(), p0, p0, graph()->start()));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+}
+
+
+// -----------------------------------------------------------------------------
+// Int32AddWithOverflow
+
+
+TEST_F(MachineOperatorReducerTest, Int32AddWithOverflowWithZero) {
+  Node* p0 = Parameter(0);
+  {
+    Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(),
+                                 Int32Constant(0), p0);
+
+    Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+
+    r = Reduce(graph()->NewNode(common()->Projection(0), add));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(p0, r.replacement());
+  }
+  {
+    Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), p0,
+                                 Int32Constant(0));
+
+    Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+
+    r = Reduce(graph()->NewNode(common()->Projection(0), add));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(p0, r.replacement());
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Int32AddWithOverflowWithConstant) {
+  TRACED_FOREACH(int32_t, x, kInt32Values) {
+    TRACED_FOREACH(int32_t, y, kInt32Values) {
+      int32_t z;
+      Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(),
+                                   Int32Constant(x), Int32Constant(y));
+
+      Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsInt32Constant(base::bits::SignedAddOverflow32(x, y, &z)));
+
+      r = Reduce(graph()->NewNode(common()->Projection(0), add));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(), IsInt32Constant(z));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Int32SubWithOverflow
+
+
+TEST_F(MachineOperatorReducerTest, Int32SubWithOverflowWithZero) {
+  Node* p0 = Parameter(0);
+  Node* add =
+      graph()->NewNode(machine()->Int32SubWithOverflow(), p0, Int32Constant(0));
+
+  Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+
+  r = Reduce(graph()->NewNode(common()->Projection(0), add));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_EQ(p0, r.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, Int32SubWithOverflowWithConstant) {
+  TRACED_FOREACH(int32_t, x, kInt32Values) {
+    TRACED_FOREACH(int32_t, y, kInt32Values) {
+      int32_t z;
+      Node* add = graph()->NewNode(machine()->Int32SubWithOverflow(),
+                                   Int32Constant(x), Int32Constant(y));
+
+      Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsInt32Constant(base::bits::SignedSubOverflow32(x, y, &z)));
+
+      r = Reduce(graph()->NewNode(common()->Projection(0), add));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(), IsInt32Constant(z));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Uint32LessThan
+
+
+TEST_F(MachineOperatorReducerTest, Uint32LessThanWithWord32Sar) {
+  Node* const p0 = Parameter(0);
+  TRACED_FORRANGE(uint32_t, shift, 1, 3) {
+    const uint32_t limit = (kMaxInt >> shift) - 1;
+    Node* const node = graph()->NewNode(
+        machine()->Uint32LessThan(),
+        graph()->NewNode(machine()->Word32Sar(), p0, Uint32Constant(shift)),
+        Uint32Constant(limit));
+
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsUint32LessThan(
+                    p0, IsInt32Constant(bit_cast<int32_t>(limit << shift))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Float64Mul
+
+
+TEST_F(MachineOperatorReducerTest, Float64MulWithMinusOne) {
+  Node* const p0 = Parameter(0);
+  {
+    Reduction r = Reduce(
+        graph()->NewNode(machine()->Float64Mul(), p0, Float64Constant(-1.0)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsFloat64Sub(IsFloat64Constant(BitEq(-0.0)), p0));
+  }
+  {
+    Reduction r = Reduce(
+        graph()->NewNode(machine()->Float64Mul(), Float64Constant(-1.0), p0));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsFloat64Sub(IsFloat64Constant(BitEq(-0.0)), p0));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Store
+
+
+TEST_F(MachineOperatorReducerTest, StoreRepWord8WithWord32And) {
+  const StoreRepresentation rep(kRepWord8, kNoWriteBarrier);
+  Node* const base = Parameter(0);
+  Node* const index = Parameter(1);
+  Node* const value = Parameter(2);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FOREACH(uint32_t, x, kUint32Values) {
+    Node* const node =
+        graph()->NewNode(machine()->Store(rep), base, index,
+                         graph()->NewNode(machine()->Word32And(), value,
+                                          Uint32Constant(x | 0xffu)),
+                         effect, control);
+
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsStore(rep, base, index, value, effect, control));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, StoreRepWord8WithWord32SarAndWord32Shl) {
+  const StoreRepresentation rep(kRepWord8, kNoWriteBarrier);
+  Node* const base = Parameter(0);
+  Node* const index = Parameter(1);
+  Node* const value = Parameter(2);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FORRANGE(int32_t, x, 1, 24) {
+    Node* const node = graph()->NewNode(
+        machine()->Store(rep), base, index,
+        graph()->NewNode(
+            machine()->Word32Sar(),
+            graph()->NewNode(machine()->Word32Shl(), value, Int32Constant(x)),
+            Int32Constant(x)),
+        effect, control);
+
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsStore(rep, base, index, value, effect, control));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, StoreRepWord16WithWord32And) {
+  const StoreRepresentation rep(kRepWord16, kNoWriteBarrier);
+  Node* const base = Parameter(0);
+  Node* const index = Parameter(1);
+  Node* const value = Parameter(2);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FOREACH(uint32_t, x, kUint32Values) {
+    Node* const node =
+        graph()->NewNode(machine()->Store(rep), base, index,
+                         graph()->NewNode(machine()->Word32And(), value,
+                                          Uint32Constant(x | 0xffffu)),
+                         effect, control);
+
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsStore(rep, base, index, value, effect, control));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, StoreRepWord16WithWord32SarAndWord32Shl) {
+  const StoreRepresentation rep(kRepWord16, kNoWriteBarrier);
+  Node* const base = Parameter(0);
+  Node* const index = Parameter(1);
+  Node* const value = Parameter(2);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FORRANGE(int32_t, x, 1, 16) {
+    Node* const node = graph()->NewNode(
+        machine()->Store(rep), base, index,
+        graph()->NewNode(
+            machine()->Word32Sar(),
+            graph()->NewNode(machine()->Word32Shl(), value, Int32Constant(x)),
+            Int32Constant(x)),
+        effect, control);
+
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsStore(rep, base, index, value, effect, control));
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/machine-operator-unittest.cc b/test/unittests/compiler/machine-operator-unittest.cc
new file mode 100644
index 0000000..6e0df2a
--- /dev/null
+++ b/test/unittests/compiler/machine-operator-unittest.cc
@@ -0,0 +1,324 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/opcodes.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/operator-properties.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+#if GTEST_HAS_COMBINE
+
+template <typename T>
+class MachineOperatorTestWithParam
+    : public TestWithZone,
+      public ::testing::WithParamInterface< ::testing::tuple<MachineType, T> > {
+ protected:
+  MachineType type() const { return ::testing::get<0>(B::GetParam()); }
+  const T& GetParam() const { return ::testing::get<1>(B::GetParam()); }
+
+ private:
+  typedef ::testing::WithParamInterface< ::testing::tuple<MachineType, T> > B;
+};
+
+
+namespace {
+
+const MachineType kMachineReps[] = {kRepWord32, kRepWord64};
+
+
+const MachineType kMachineTypes[] = {
+    kMachFloat32, kMachFloat64,   kMachInt8,   kMachUint8,  kMachInt16,
+    kMachUint16,  kMachInt32,     kMachUint32, kMachInt64,  kMachUint64,
+    kMachPtr,     kMachAnyTagged, kRepBit,     kRepWord8,   kRepWord16,
+    kRepWord32,   kRepWord64,     kRepFloat32, kRepFloat64, kRepTagged};
+
+}  // namespace
+
+
+// -----------------------------------------------------------------------------
+// Load operator.
+
+
+typedef MachineOperatorTestWithParam<LoadRepresentation>
+    MachineLoadOperatorTest;
+
+
+TEST_P(MachineLoadOperatorTest, InstancesAreGloballyShared) {
+  MachineOperatorBuilder machine1(zone(), type());
+  MachineOperatorBuilder machine2(zone(), type());
+  EXPECT_EQ(machine1.Load(GetParam()), machine2.Load(GetParam()));
+}
+
+
+TEST_P(MachineLoadOperatorTest, NumberOfInputsAndOutputs) {
+  MachineOperatorBuilder machine(zone(), type());
+  const Operator* op = machine.Load(GetParam());
+
+  EXPECT_EQ(2, op->ValueInputCount());
+  EXPECT_EQ(1, op->EffectInputCount());
+  EXPECT_EQ(1, op->ControlInputCount());
+  EXPECT_EQ(4, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(1, op->ValueOutputCount());
+  EXPECT_EQ(1, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(MachineLoadOperatorTest, OpcodeIsCorrect) {
+  MachineOperatorBuilder machine(zone(), type());
+  EXPECT_EQ(IrOpcode::kLoad, machine.Load(GetParam())->opcode());
+}
+
+
+TEST_P(MachineLoadOperatorTest, ParameterIsCorrect) {
+  MachineOperatorBuilder machine(zone(), type());
+  EXPECT_EQ(GetParam(),
+            OpParameter<LoadRepresentation>(machine.Load(GetParam())));
+}
+
+
+INSTANTIATE_TEST_CASE_P(MachineOperatorTest, MachineLoadOperatorTest,
+                        ::testing::Combine(::testing::ValuesIn(kMachineReps),
+                                           ::testing::ValuesIn(kMachineTypes)));
+
+
+// -----------------------------------------------------------------------------
+// Store operator.
+
+
+class MachineStoreOperatorTest
+    : public MachineOperatorTestWithParam<
+          ::testing::tuple<MachineType, WriteBarrierKind> > {
+ protected:
+  StoreRepresentation GetParam() const {
+    return StoreRepresentation(
+        ::testing::get<0>(MachineOperatorTestWithParam<
+            ::testing::tuple<MachineType, WriteBarrierKind> >::GetParam()),
+        ::testing::get<1>(MachineOperatorTestWithParam<
+            ::testing::tuple<MachineType, WriteBarrierKind> >::GetParam()));
+  }
+};
+
+
+TEST_P(MachineStoreOperatorTest, InstancesAreGloballyShared) {
+  MachineOperatorBuilder machine1(zone(), type());
+  MachineOperatorBuilder machine2(zone(), type());
+  EXPECT_EQ(machine1.Store(GetParam()), machine2.Store(GetParam()));
+}
+
+
+TEST_P(MachineStoreOperatorTest, NumberOfInputsAndOutputs) {
+  MachineOperatorBuilder machine(zone(), type());
+  const Operator* op = machine.Store(GetParam());
+
+  EXPECT_EQ(3, op->ValueInputCount());
+  EXPECT_EQ(1, op->EffectInputCount());
+  EXPECT_EQ(1, op->ControlInputCount());
+  EXPECT_EQ(5, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(0, op->ValueOutputCount());
+  EXPECT_EQ(1, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(MachineStoreOperatorTest, OpcodeIsCorrect) {
+  MachineOperatorBuilder machine(zone(), type());
+  EXPECT_EQ(IrOpcode::kStore, machine.Store(GetParam())->opcode());
+}
+
+
+TEST_P(MachineStoreOperatorTest, ParameterIsCorrect) {
+  MachineOperatorBuilder machine(zone(), type());
+  EXPECT_EQ(GetParam(),
+            OpParameter<StoreRepresentation>(machine.Store(GetParam())));
+}
+
+
+INSTANTIATE_TEST_CASE_P(
+    MachineOperatorTest, MachineStoreOperatorTest,
+    ::testing::Combine(
+        ::testing::ValuesIn(kMachineReps),
+        ::testing::Combine(::testing::ValuesIn(kMachineTypes),
+                           ::testing::Values(kNoWriteBarrier,
+                                             kFullWriteBarrier))));
+
+
+// -----------------------------------------------------------------------------
+// Pure operators.
+
+
+namespace {
+
+struct PureOperator {
+  const Operator* (MachineOperatorBuilder::*constructor)();
+  IrOpcode::Value opcode;
+  int value_input_count;
+  int control_input_count;
+  int value_output_count;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const PureOperator& pop) {
+  return os << IrOpcode::Mnemonic(pop.opcode);
+}
+
+
+const PureOperator kPureOperators[] = {
+#define PURE(Name, value_input_count, control_input_count, value_output_count) \
+  {                                                                            \
+    &MachineOperatorBuilder::Name, IrOpcode::k##Name, value_input_count,       \
+        control_input_count, value_output_count                                \
+  }
+    PURE(Word32And, 2, 0, 1), PURE(Word32Or, 2, 0, 1), PURE(Word32Xor, 2, 0, 1),
+    PURE(Word32Shl, 2, 0, 1), PURE(Word32Shr, 2, 0, 1),
+    PURE(Word32Sar, 2, 0, 1), PURE(Word32Ror, 2, 0, 1),
+    PURE(Word32Equal, 2, 0, 1), PURE(Word64And, 2, 0, 1),
+    PURE(Word64Or, 2, 0, 1), PURE(Word64Xor, 2, 0, 1), PURE(Word64Shl, 2, 0, 1),
+    PURE(Word64Shr, 2, 0, 1), PURE(Word64Sar, 2, 0, 1),
+    PURE(Word64Ror, 2, 0, 1), PURE(Word64Equal, 2, 0, 1),
+    PURE(Int32Add, 2, 0, 1), PURE(Int32AddWithOverflow, 2, 0, 2),
+    PURE(Int32Sub, 2, 0, 1), PURE(Int32SubWithOverflow, 2, 0, 2),
+    PURE(Int32Mul, 2, 0, 1), PURE(Int32MulHigh, 2, 0, 1),
+    PURE(Int32Div, 2, 1, 1), PURE(Uint32Div, 2, 1, 1), PURE(Int32Mod, 2, 1, 1),
+    PURE(Uint32Mod, 2, 1, 1), PURE(Int32LessThan, 2, 0, 1),
+    PURE(Int32LessThanOrEqual, 2, 0, 1), PURE(Uint32LessThan, 2, 0, 1),
+    PURE(Uint32LessThanOrEqual, 2, 0, 1), PURE(Int64Add, 2, 0, 1),
+    PURE(Int64Sub, 2, 0, 1), PURE(Int64Mul, 2, 0, 1), PURE(Int64Div, 2, 0, 1),
+    PURE(Uint64Div, 2, 0, 1), PURE(Int64Mod, 2, 0, 1), PURE(Uint64Mod, 2, 0, 1),
+    PURE(Int64LessThan, 2, 0, 1), PURE(Int64LessThanOrEqual, 2, 0, 1),
+    PURE(Uint64LessThan, 2, 0, 1), PURE(ChangeFloat32ToFloat64, 1, 0, 1),
+    PURE(ChangeFloat64ToInt32, 1, 0, 1), PURE(ChangeFloat64ToUint32, 1, 0, 1),
+    PURE(ChangeInt32ToInt64, 1, 0, 1), PURE(ChangeUint32ToFloat64, 1, 0, 1),
+    PURE(ChangeUint32ToUint64, 1, 0, 1),
+    PURE(TruncateFloat64ToFloat32, 1, 0, 1),
+    PURE(TruncateFloat64ToInt32, 1, 0, 1), PURE(TruncateInt64ToInt32, 1, 0, 1),
+    PURE(Float64Add, 2, 0, 1), PURE(Float64Sub, 2, 0, 1),
+    PURE(Float64Mul, 2, 0, 1), PURE(Float64Div, 2, 0, 1),
+    PURE(Float64Mod, 2, 0, 1), PURE(Float64Sqrt, 1, 0, 1),
+    PURE(Float64Equal, 2, 0, 1), PURE(Float64LessThan, 2, 0, 1),
+    PURE(Float64LessThanOrEqual, 2, 0, 1), PURE(LoadStackPointer, 0, 0, 1),
+    PURE(Float64Floor, 1, 0, 1), PURE(Float64Ceil, 1, 0, 1),
+    PURE(Float64RoundTruncate, 1, 0, 1), PURE(Float64RoundTiesAway, 1, 0, 1)
+#undef PURE
+};
+
+
+typedef MachineOperatorTestWithParam<PureOperator> MachinePureOperatorTest;
+
+}  // namespace
+
+
+TEST_P(MachinePureOperatorTest, InstancesAreGloballyShared) {
+  const PureOperator& pop = GetParam();
+  MachineOperatorBuilder machine1(zone(), type());
+  MachineOperatorBuilder machine2(zone(), type());
+  EXPECT_EQ((machine1.*pop.constructor)(), (machine2.*pop.constructor)());
+}
+
+
+TEST_P(MachinePureOperatorTest, NumberOfInputsAndOutputs) {
+  MachineOperatorBuilder machine(zone(), type());
+  const PureOperator& pop = GetParam();
+  const Operator* op = (machine.*pop.constructor)();
+
+  EXPECT_EQ(pop.value_input_count, op->ValueInputCount());
+  EXPECT_EQ(0, op->EffectInputCount());
+  EXPECT_EQ(pop.control_input_count, op->ControlInputCount());
+  EXPECT_EQ(pop.value_input_count + pop.control_input_count,
+            OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(pop.value_output_count, op->ValueOutputCount());
+  EXPECT_EQ(0, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(MachinePureOperatorTest, MarkedAsPure) {
+  MachineOperatorBuilder machine(zone(), type());
+  const PureOperator& pop = GetParam();
+  const Operator* op = (machine.*pop.constructor)();
+  EXPECT_TRUE(op->HasProperty(Operator::kPure));
+}
+
+
+TEST_P(MachinePureOperatorTest, OpcodeIsCorrect) {
+  MachineOperatorBuilder machine(zone(), type());
+  const PureOperator& pop = GetParam();
+  const Operator* op = (machine.*pop.constructor)();
+  EXPECT_EQ(pop.opcode, op->opcode());
+}
+
+
+INSTANTIATE_TEST_CASE_P(
+    MachineOperatorTest, MachinePureOperatorTest,
+    ::testing::Combine(::testing::ValuesIn(kMachineReps),
+                       ::testing::ValuesIn(kPureOperators)));
+
+#endif  // GTEST_HAS_COMBINE
+
+
+// -----------------------------------------------------------------------------
+// Pseudo operators.
+
+
+namespace {
+
+typedef TestWithZone MachineOperatorTest;
+
+}  // namespace
+
+
+TEST_F(MachineOperatorTest, PseudoOperatorsWhenWordSizeIs32Bit) {
+  MachineOperatorBuilder machine(zone(), kRepWord32);
+  EXPECT_EQ(machine.Word32And(), machine.WordAnd());
+  EXPECT_EQ(machine.Word32Or(), machine.WordOr());
+  EXPECT_EQ(machine.Word32Xor(), machine.WordXor());
+  EXPECT_EQ(machine.Word32Shl(), machine.WordShl());
+  EXPECT_EQ(machine.Word32Shr(), machine.WordShr());
+  EXPECT_EQ(machine.Word32Sar(), machine.WordSar());
+  EXPECT_EQ(machine.Word32Ror(), machine.WordRor());
+  EXPECT_EQ(machine.Word32Equal(), machine.WordEqual());
+  EXPECT_EQ(machine.Int32Add(), machine.IntAdd());
+  EXPECT_EQ(machine.Int32Sub(), machine.IntSub());
+  EXPECT_EQ(machine.Int32Mul(), machine.IntMul());
+  EXPECT_EQ(machine.Int32Div(), machine.IntDiv());
+  EXPECT_EQ(machine.Uint32Div(), machine.UintDiv());
+  EXPECT_EQ(machine.Int32Mod(), machine.IntMod());
+  EXPECT_EQ(machine.Uint32Mod(), machine.UintMod());
+  EXPECT_EQ(machine.Int32LessThan(), machine.IntLessThan());
+  EXPECT_EQ(machine.Int32LessThanOrEqual(), machine.IntLessThanOrEqual());
+}
+
+
+TEST_F(MachineOperatorTest, PseudoOperatorsWhenWordSizeIs64Bit) {
+  MachineOperatorBuilder machine(zone(), kRepWord64);
+  EXPECT_EQ(machine.Word64And(), machine.WordAnd());
+  EXPECT_EQ(machine.Word64Or(), machine.WordOr());
+  EXPECT_EQ(machine.Word64Xor(), machine.WordXor());
+  EXPECT_EQ(machine.Word64Shl(), machine.WordShl());
+  EXPECT_EQ(machine.Word64Shr(), machine.WordShr());
+  EXPECT_EQ(machine.Word64Sar(), machine.WordSar());
+  EXPECT_EQ(machine.Word64Ror(), machine.WordRor());
+  EXPECT_EQ(machine.Word64Equal(), machine.WordEqual());
+  EXPECT_EQ(machine.Int64Add(), machine.IntAdd());
+  EXPECT_EQ(machine.Int64Sub(), machine.IntSub());
+  EXPECT_EQ(machine.Int64Mul(), machine.IntMul());
+  EXPECT_EQ(machine.Int64Div(), machine.IntDiv());
+  EXPECT_EQ(machine.Uint64Div(), machine.UintDiv());
+  EXPECT_EQ(machine.Int64Mod(), machine.IntMod());
+  EXPECT_EQ(machine.Uint64Mod(), machine.UintMod());
+  EXPECT_EQ(machine.Int64LessThan(), machine.IntLessThan());
+  EXPECT_EQ(machine.Int64LessThanOrEqual(), machine.IntLessThanOrEqual());
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/mips/OWNERS b/test/unittests/compiler/mips/OWNERS
new file mode 100644
index 0000000..5508ba6
--- /dev/null
+++ b/test/unittests/compiler/mips/OWNERS
@@ -0,0 +1,5 @@
+paul.lind@imgtec.com
+gergely.kis@imgtec.com
+akos.palfi@imgtec.com
+balazs.kilvady@imgtec.com
+dusan.milosavljevic@imgtec.com
diff --git a/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc b/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc
new file mode 100644
index 0000000..0b3a0f5
--- /dev/null
+++ b/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc
@@ -0,0 +1,805 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file
+
+#include "test/unittests/compiler/instruction-selector-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+template <typename T>
+struct MachInst {
+  T constructor;
+  const char* constructor_name;
+  ArchOpcode arch_opcode;
+  MachineType machine_type;
+};
+
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) {
+  return os << mi.constructor_name;
+}
+
+typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1;
+typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2;
+
+// To avoid duplicated code IntCmp helper structure
+// is created. It contains MachInst2 with two nodes and expected_size
+// because different cmp instructions have different size.
+struct IntCmp {
+  MachInst2 mi;
+  uint32_t expected_size;
+};
+
+struct FPCmp {
+  MachInst2 mi;
+  FlagsCondition cond;
+};
+
+const FPCmp kFPCmpInstructions[] = {
+    {{&RawMachineAssembler::Float64Equal, "Float64Equal", kMipsCmpD,
+      kMachFloat64},
+     kUnorderedEqual},
+    {{&RawMachineAssembler::Float64LessThan, "Float64LessThan", kMipsCmpD,
+      kMachFloat64},
+     kUnorderedLessThan},
+    {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
+      kMipsCmpD, kMachFloat64},
+     kUnorderedLessThanOrEqual},
+    {{&RawMachineAssembler::Float64GreaterThan, "Float64GreaterThan", kMipsCmpD,
+      kMachFloat64},
+     kUnorderedLessThan},
+    {{&RawMachineAssembler::Float64GreaterThanOrEqual,
+      "Float64GreaterThanOrEqual", kMipsCmpD, kMachFloat64},
+     kUnorderedLessThanOrEqual}};
+
+struct Conversion {
+  // The machine_type field in MachInst1 represents the destination type.
+  MachInst1 mi;
+  MachineType src_machine_type;
+};
+
+
+// ----------------------------------------------------------------------------
+// Logical instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kLogicalInstructions[] = {
+    {&RawMachineAssembler::WordAnd, "WordAnd", kMipsAnd, kMachInt16},
+    {&RawMachineAssembler::WordOr, "WordOr", kMipsOr, kMachInt16},
+    {&RawMachineAssembler::WordXor, "WordXor", kMipsXor, kMachInt16},
+    {&RawMachineAssembler::Word32And, "Word32And", kMipsAnd, kMachInt32},
+    {&RawMachineAssembler::Word32Or, "Word32Or", kMipsOr, kMachInt32},
+    {&RawMachineAssembler::Word32Xor, "Word32Xor", kMipsXor, kMachInt32}};
+
+
+// ----------------------------------------------------------------------------
+// Shift instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kShiftInstructions[] = {
+    {&RawMachineAssembler::WordShl, "WordShl", kMipsShl, kMachInt16},
+    {&RawMachineAssembler::WordShr, "WordShr", kMipsShr, kMachInt16},
+    {&RawMachineAssembler::WordSar, "WordSar", kMipsSar, kMachInt16},
+    {&RawMachineAssembler::WordRor, "WordRor", kMipsRor, kMachInt16},
+    {&RawMachineAssembler::Word32Shl, "Word32Shl", kMipsShl, kMachInt32},
+    {&RawMachineAssembler::Word32Shr, "Word32Shr", kMipsShr, kMachInt32},
+    {&RawMachineAssembler::Word32Sar, "Word32Sar", kMipsSar, kMachInt32},
+    {&RawMachineAssembler::Word32Ror, "Word32Ror", kMipsRor, kMachInt32}};
+
+
+// ----------------------------------------------------------------------------
+// MUL/DIV instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kMulDivInstructions[] = {
+    {&RawMachineAssembler::Int32Mul, "Int32Mul", kMipsMul, kMachInt32},
+    {&RawMachineAssembler::Int32Div, "Int32Div", kMipsDiv, kMachInt32},
+    {&RawMachineAssembler::Uint32Div, "Uint32Div", kMipsDivU, kMachUint32},
+    {&RawMachineAssembler::Float64Mul, "Float64Mul", kMipsMulD, kMachFloat64},
+    {&RawMachineAssembler::Float64Div, "Float64Div", kMipsDivD, kMachFloat64}};
+
+
+// ----------------------------------------------------------------------------
+// MOD instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kModInstructions[] = {
+    {&RawMachineAssembler::Int32Mod, "Int32Mod", kMipsMod, kMachInt32},
+    {&RawMachineAssembler::Uint32Mod, "Int32UMod", kMipsModU, kMachInt32},
+    {&RawMachineAssembler::Float64Mod, "Float64Mod", kMipsModD, kMachFloat64}};
+
+
+// ----------------------------------------------------------------------------
+// Arithmetic FPU instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kFPArithInstructions[] = {
+    {&RawMachineAssembler::Float64Add, "Float64Add", kMipsAddD, kMachFloat64},
+    {&RawMachineAssembler::Float64Sub, "Float64Sub", kMipsSubD, kMachFloat64}};
+
+
+// ----------------------------------------------------------------------------
+// IntArithTest instructions, two nodes.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kAddSubInstructions[] = {
+    {&RawMachineAssembler::Int32Add, "Int32Add", kMipsAdd, kMachInt32},
+    {&RawMachineAssembler::Int32Sub, "Int32Sub", kMipsSub, kMachInt32},
+    {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
+     kMipsAddOvf, kMachInt32},
+    {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow",
+     kMipsSubOvf, kMachInt32}};
+
+
+// ----------------------------------------------------------------------------
+// IntArithTest instructions, one node.
+// ----------------------------------------------------------------------------
+
+
+const MachInst1 kAddSubOneInstructions[] = {
+    {&RawMachineAssembler::Int32Neg, "Int32Neg", kMipsSub, kMachInt32},
+    // TODO(dusmil): check this ...
+    // {&RawMachineAssembler::WordEqual  , "WordEqual"  , kMipsTst, kMachInt32}
+};
+
+
+// ----------------------------------------------------------------------------
+// Arithmetic compare instructions.
+// ----------------------------------------------------------------------------
+
+
+const IntCmp kCmpInstructions[] = {
+    {{&RawMachineAssembler::WordEqual, "WordEqual", kMipsCmp, kMachInt16}, 1U},
+    {{&RawMachineAssembler::WordNotEqual, "WordNotEqual", kMipsCmp, kMachInt16},
+     1U},
+    {{&RawMachineAssembler::Word32Equal, "Word32Equal", kMipsCmp, kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kMipsCmp,
+      kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kMipsCmp,
+      kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
+      kMipsCmp, kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32GreaterThan, "Int32GreaterThan", kMipsCmp,
+      kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32GreaterThanOrEqual, "Int32GreaterThanOrEqual",
+      kMipsCmp, kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kMipsCmp,
+      kMachUint32},
+     1U},
+    {{&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
+      kMipsCmp, kMachUint32},
+     1U}};
+
+
+// ----------------------------------------------------------------------------
+// Conversion instructions.
+// ----------------------------------------------------------------------------
+
+const Conversion kConversionInstructions[] = {
+    // Conversion instructions are related to machine_operator.h:
+    // FPU conversions:
+    // Convert representation of integers between float64 and int32/uint32.
+    // The precise rounding mode and handling of out of range inputs are *not*
+    // defined for these operators, since they are intended only for use with
+    // integers.
+    // mips instruction: cvt_d_w
+    {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
+      kMipsCvtDW, kMachFloat64},
+     kMachInt32},
+
+    // mips instruction: cvt_d_uw
+    {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
+      kMipsCvtDUw, kMachFloat64},
+     kMachInt32},
+
+    // mips instruction: trunc_w_d
+    {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
+      kMipsTruncWD, kMachFloat64},
+     kMachInt32},
+
+    // mips instruction: trunc_uw_d
+    {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
+      kMipsTruncUwD, kMachFloat64},
+     kMachInt32}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest;
+
+
+TEST_P(InstructionSelectorFPCmpTest, Parameter) {
+  const FPCmp cmp = GetParam();
+  StreamBuilder m(this, kMachInt32, cmp.mi.machine_type, cmp.mi.machine_type);
+  m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(cmp.cond, s[0]->flags_condition());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
+                        ::testing::ValuesIn(kFPCmpInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Arithmetic compare instructions integers.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<IntCmp> InstructionSelectorCmpTest;
+
+
+TEST_P(InstructionSelectorCmpTest, Parameter) {
+  const IntCmp cmp = GetParam();
+  const MachineType type = cmp.mi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(cmp.expected_size, s.size());
+  EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorCmpTest,
+                        ::testing::ValuesIn(kCmpInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Shift instructions.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorShiftTest;
+
+
+TEST_P(InstructionSelectorShiftTest, Immediate) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) {
+    StreamBuilder m(this, type, type);
+    m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
+                        ::testing::ValuesIn(kShiftInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Logical instructions.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorLogicalTest;
+
+
+TEST_P(InstructionSelectorLogicalTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest,
+                        ::testing::ValuesIn(kLogicalInstructions));
+
+
+// ----------------------------------------------------------------------------
+// MUL/DIV instructions.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorMulDivTest;
+
+
+TEST_P(InstructionSelectorMulDivTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest,
+                        ::testing::ValuesIn(kMulDivInstructions));
+
+
+// ----------------------------------------------------------------------------
+// MOD instructions.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst2> InstructionSelectorModTest;
+
+
+TEST_P(InstructionSelectorModTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorModTest,
+                        ::testing::ValuesIn(kModInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Floating point instructions.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorFPArithTest;
+
+
+TEST_P(InstructionSelectorFPArithTest, Parameter) {
+  const MachInst2 fpa = GetParam();
+  StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type);
+  m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest,
+                        ::testing::ValuesIn(kFPArithInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Integer arithmetic.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorIntArithTwoTest;
+
+
+TEST_P(InstructionSelectorIntArithTwoTest, Parameter) {
+  const MachInst2 intpa = GetParam();
+  StreamBuilder m(this, intpa.machine_type, intpa.machine_type,
+                  intpa.machine_type);
+  m.Return((m.*intpa.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(intpa.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorIntArithTwoTest,
+                        ::testing::ValuesIn(kAddSubInstructions));
+
+
+// ----------------------------------------------------------------------------
+// One node.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst1>
+    InstructionSelectorIntArithOneTest;
+
+
+TEST_P(InstructionSelectorIntArithOneTest, Parameter) {
+  const MachInst1 intpa = GetParam();
+  StreamBuilder m(this, intpa.machine_type, intpa.machine_type,
+                  intpa.machine_type);
+  m.Return((m.*intpa.constructor)(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(intpa.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorIntArithOneTest,
+                        ::testing::ValuesIn(kAddSubOneInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Conversions.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<Conversion>
+    InstructionSelectorConversionTest;
+
+
+TEST_P(InstructionSelectorConversionTest, Parameter) {
+  const Conversion conv = GetParam();
+  StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
+  m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorConversionTest,
+                        ::testing::ValuesIn(kConversionInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Loads and stores.
+// ----------------------------------------------------------------------------
+
+namespace {
+
+struct MemoryAccess {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+};
+
+
+static const MemoryAccess kMemoryAccesses[] = {
+    {kMachInt8, kMipsLb, kMipsSb},
+    {kMachUint8, kMipsLbu, kMipsSb},
+    {kMachInt16, kMipsLh, kMipsSh},
+    {kMachUint16, kMipsLhu, kMipsSh},
+    {kMachInt32, kMipsLw, kMipsSw},
+    {kRepFloat32, kMipsLwc1, kMipsSwc1},
+    {kRepFloat64, kMipsLdc1, kMipsSdc1}};
+
+
+struct MemoryAccessImm {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+  bool (InstructionSelectorTest::Stream::*val_predicate)(
+      const InstructionOperand*) const;
+  const int32_t immediates[40];
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccessImm& acc) {
+  return os << acc.type;
+}
+
+
+struct MemoryAccessImm1 {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+  bool (InstructionSelectorTest::Stream::*val_predicate)(
+      const InstructionOperand*) const;
+  const int32_t immediates[5];
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccessImm1& acc) {
+  return os << acc.type;
+}
+
+
+// ----------------------------------------------------------------------------
+// Loads and stores immediate values.
+// ----------------------------------------------------------------------------
+
+
+const MemoryAccessImm kMemoryAccessesImm[] = {
+    {kMachInt8,
+     kMipsLb,
+     kMipsSb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachUint8,
+     kMipsLbu,
+     kMipsSb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachInt16,
+     kMipsLh,
+     kMipsSh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachUint16,
+     kMipsLhu,
+     kMipsSh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachInt32,
+     kMipsLw,
+     kMipsSw,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachFloat32,
+     kMipsLwc1,
+     kMipsSwc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachFloat64,
+     kMipsLdc1,
+     kMipsSdc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}};
+
+
+const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = {
+    {kMachInt8,
+     kMipsLb,
+     kMipsSb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt8,
+     kMipsLbu,
+     kMipsSb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt16,
+     kMipsLh,
+     kMipsSh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt16,
+     kMipsLhu,
+     kMipsSh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt32,
+     kMipsLw,
+     kMipsSw,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachFloat32,
+     kMipsLwc1,
+     kMipsSwc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachFloat64,
+     kMipsLdc1,
+     kMipsSdc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-65000, -55000, 32777, 55000, 65000}}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccess>
+    InstructionSelectorMemoryAccessTest;
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
+  m.Return(m.Load(memacc.type, m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
+  m.Store(memacc.type, m.Parameter(0), m.Parameter(1));
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessTest,
+                        ::testing::ValuesIn(kMemoryAccesses));
+
+
+// ----------------------------------------------------------------------------
+// Load immediate.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccessImm>
+    InstructionSelectorMemoryAccessImmTest;
+
+
+TEST_P(InstructionSelectorMemoryAccessImmTest, LoadWithImmediateIndex) {
+  const MemoryAccessImm memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output()));
+  }
+}
+
+
+// ----------------------------------------------------------------------------
+// Store immediate.
+// ----------------------------------------------------------------------------
+
+
+TEST_P(InstructionSelectorMemoryAccessImmTest, StoreWithImmediateIndex) {
+  const MemoryAccessImm memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
+    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
+            m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(0U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessImmTest,
+                        ::testing::ValuesIn(kMemoryAccessesImm));
+
+
+// ----------------------------------------------------------------------------
+// Load/store offsets more than 16 bits.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccessImm1>
+    InstructionSelectorMemoryAccessImmMoreThan16bitTest;
+
+
+TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,
+       LoadWithImmediateIndex) {
+  const MemoryAccessImm1 memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
+    Stream s = m.Build();
+    ASSERT_EQ(2U, s.size());
+    // kMipsAdd is expected opcode.
+    // size more than 16 bits wide.
+    EXPECT_EQ(kMipsAdd, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,
+       StoreWithImmediateIndex) {
+  const MemoryAccessImm1 memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
+    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
+            m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(2U, s.size());
+    // kMipsAdd is expected opcode
+    // size more than 16 bits wide
+    EXPECT_EQ(kMipsAdd, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessImmMoreThan16bitTest,
+                        ::testing::ValuesIn(kMemoryAccessImmMoreThan16bit));
+
+
+// ----------------------------------------------------------------------------
+// kMipsTst testing.
+// ----------------------------------------------------------------------------
+
+
+TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kMipsCmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kMipsCmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/mips64/OWNERS b/test/unittests/compiler/mips64/OWNERS
new file mode 100644
index 0000000..5508ba6
--- /dev/null
+++ b/test/unittests/compiler/mips64/OWNERS
@@ -0,0 +1,5 @@
+paul.lind@imgtec.com
+gergely.kis@imgtec.com
+akos.palfi@imgtec.com
+balazs.kilvady@imgtec.com
+dusan.milosavljevic@imgtec.com
diff --git a/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc b/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc
new file mode 100644
index 0000000..a39ae75
--- /dev/null
+++ b/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc
@@ -0,0 +1,807 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file
+
+#include "test/unittests/compiler/instruction-selector-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+template <typename T>
+struct MachInst {
+  T constructor;
+  const char* constructor_name;
+  ArchOpcode arch_opcode;
+  MachineType machine_type;
+};
+
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) {
+  return os << mi.constructor_name;
+}
+
+typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1;
+typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2;
+
+
+// To avoid duplicated code IntCmp helper structure
+// is created. It contains MachInst2 with two nodes and expected_size
+// because different cmp instructions have different size.
+struct IntCmp {
+  MachInst2 mi;
+  uint32_t expected_size;
+};
+
+struct FPCmp {
+  MachInst2 mi;
+  FlagsCondition cond;
+};
+
+const FPCmp kFPCmpInstructions[] = {
+    {{&RawMachineAssembler::Float64Equal, "Float64Equal", kMips64CmpD,
+      kMachFloat64},
+     kUnorderedEqual},
+    {{&RawMachineAssembler::Float64LessThan, "Float64LessThan", kMips64CmpD,
+      kMachFloat64},
+     kUnorderedLessThan},
+    {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
+      kMips64CmpD, kMachFloat64},
+     kUnorderedLessThanOrEqual},
+    {{&RawMachineAssembler::Float64GreaterThan, "Float64GreaterThan",
+      kMips64CmpD, kMachFloat64},
+     kUnorderedLessThan},
+    {{&RawMachineAssembler::Float64GreaterThanOrEqual,
+      "Float64GreaterThanOrEqual", kMips64CmpD, kMachFloat64},
+     kUnorderedLessThanOrEqual}};
+
+struct Conversion {
+  // The machine_type field in MachInst1 represents the destination type.
+  MachInst1 mi;
+  MachineType src_machine_type;
+};
+
+
+// ----------------------------------------------------------------------------
+// Logical instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kLogicalInstructions[] = {
+    {&RawMachineAssembler::Word32And, "Word32And", kMips64And, kMachInt32},
+    {&RawMachineAssembler::Word64And, "Word64And", kMips64And, kMachInt64},
+    {&RawMachineAssembler::Word32Or, "Word32Or", kMips64Or, kMachInt32},
+    {&RawMachineAssembler::Word64Or, "Word64Or", kMips64Or, kMachInt64},
+    {&RawMachineAssembler::Word32Xor, "Word32Xor", kMips64Xor, kMachInt32},
+    {&RawMachineAssembler::Word64Xor, "Word64Xor", kMips64Xor, kMachInt64}};
+
+
+// ----------------------------------------------------------------------------
+// Shift instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kShiftInstructions[] = {
+    {&RawMachineAssembler::Word32Shl, "Word32Shl", kMips64Shl, kMachInt32},
+    {&RawMachineAssembler::Word64Shl, "Word64Shl", kMips64Dshl, kMachInt64},
+    {&RawMachineAssembler::Word32Shr, "Word32Shr", kMips64Shr, kMachInt32},
+    {&RawMachineAssembler::Word64Shr, "Word64Shr", kMips64Dshr, kMachInt64},
+    {&RawMachineAssembler::Word32Sar, "Word32Sar", kMips64Sar, kMachInt32},
+    {&RawMachineAssembler::Word64Sar, "Word64Sar", kMips64Dsar, kMachInt64},
+    {&RawMachineAssembler::Word32Ror, "Word32Ror", kMips64Ror, kMachInt32},
+    {&RawMachineAssembler::Word64Ror, "Word64Ror", kMips64Dror, kMachInt64}};
+
+
+// ----------------------------------------------------------------------------
+// MUL/DIV instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kMulDivInstructions[] = {
+    {&RawMachineAssembler::Int32Mul, "Int32Mul", kMips64Mul, kMachInt32},
+    {&RawMachineAssembler::Int32Div, "Int32Div", kMips64Div, kMachInt32},
+    {&RawMachineAssembler::Uint32Div, "Uint32Div", kMips64DivU, kMachUint32},
+    {&RawMachineAssembler::Int64Mul, "Int64Mul", kMips64Dmul, kMachInt64},
+    {&RawMachineAssembler::Int64Div, "Int64Div", kMips64Ddiv, kMachInt64},
+    {&RawMachineAssembler::Uint64Div, "Uint64Div", kMips64DdivU, kMachUint64},
+    {&RawMachineAssembler::Float64Mul, "Float64Mul", kMips64MulD, kMachFloat64},
+    {&RawMachineAssembler::Float64Div, "Float64Div", kMips64DivD,
+     kMachFloat64}};
+
+
+// ----------------------------------------------------------------------------
+// MOD instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kModInstructions[] = {
+    {&RawMachineAssembler::Int32Mod, "Int32Mod", kMips64Mod, kMachInt32},
+    {&RawMachineAssembler::Uint32Mod, "Uint32Mod", kMips64ModU, kMachInt32},
+    {&RawMachineAssembler::Float64Mod, "Float64Mod", kMips64ModD,
+     kMachFloat64}};
+
+
+// ----------------------------------------------------------------------------
+// Arithmetic FPU instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kFPArithInstructions[] = {
+    {&RawMachineAssembler::Float64Add, "Float64Add", kMips64AddD, kMachFloat64},
+    {&RawMachineAssembler::Float64Sub, "Float64Sub", kMips64SubD,
+     kMachFloat64}};
+
+
+// ----------------------------------------------------------------------------
+// IntArithTest instructions, two nodes.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kAddSubInstructions[] = {
+    {&RawMachineAssembler::Int32Add, "Int32Add", kMips64Add, kMachInt32},
+    {&RawMachineAssembler::Int64Add, "Int64Add", kMips64Dadd, kMachInt64},
+    {&RawMachineAssembler::Int32Sub, "Int32Sub", kMips64Sub, kMachInt32},
+    {&RawMachineAssembler::Int64Sub, "Int64Sub", kMips64Dsub, kMachInt64}};
+
+
+// ----------------------------------------------------------------------------
+// IntArithTest instructions, one node.
+// ----------------------------------------------------------------------------
+
+
+const MachInst1 kAddSubOneInstructions[] = {
+    {&RawMachineAssembler::Int32Neg, "Int32Neg", kMips64Sub, kMachInt32},
+    {&RawMachineAssembler::Int64Neg, "Int64Neg", kMips64Dsub, kMachInt64}};
+
+
+// ----------------------------------------------------------------------------
+// Arithmetic compare instructions.
+// ----------------------------------------------------------------------------
+
+
+const IntCmp kCmpInstructions[] = {
+    {{&RawMachineAssembler::WordEqual, "WordEqual", kMips64Cmp, kMachInt64},
+     1U},
+    {{&RawMachineAssembler::WordNotEqual, "WordNotEqual", kMips64Cmp,
+      kMachInt64},
+     1U},
+    {{&RawMachineAssembler::Word32Equal, "Word32Equal", kMips64Cmp32,
+      kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kMips64Cmp32,
+      kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kMips64Cmp32,
+      kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
+      kMips64Cmp32, kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32GreaterThan, "Int32GreaterThan", kMips64Cmp32,
+      kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32GreaterThanOrEqual, "Int32GreaterThanOrEqual",
+      kMips64Cmp32, kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kMips64Cmp32,
+      kMachUint32},
+     1U},
+    {{&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
+      kMips64Cmp32, kMachUint32},
+     1U}};
+
+
+// ----------------------------------------------------------------------------
+// Conversion instructions.
+// ----------------------------------------------------------------------------
+
+const Conversion kConversionInstructions[] = {
+    // Conversion instructions are related to machine_operator.h:
+    // FPU conversions:
+    // Convert representation of integers between float64 and int32/uint32.
+    // The precise rounding mode and handling of out of range inputs are *not*
+    // defined for these operators, since they are intended only for use with
+    // integers.
+    // mips instructions:
+    // mtc1, cvt.d.w
+    {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
+      kMips64CvtDW, kMachFloat64},
+     kMachInt32},
+
+    // mips instructions:
+    // cvt.d.uw
+    {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
+      kMips64CvtDUw, kMachFloat64},
+     kMachInt32},
+
+    // mips instructions:
+    // mfc1, trunc double to word, for more details look at mips macro
+    // asm and mips asm file
+    {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
+      kMips64TruncWD, kMachFloat64},
+     kMachInt32},
+
+    // mips instructions:
+    // trunc double to unsigned word, for more details look at mips macro
+    // asm and mips asm file
+    {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
+      kMips64TruncUwD, kMachFloat64},
+     kMachInt32}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest;
+
+TEST_P(InstructionSelectorFPCmpTest, Parameter) {
+  const FPCmp cmp = GetParam();
+  StreamBuilder m(this, kMachInt32, cmp.mi.machine_type, cmp.mi.machine_type);
+  m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(cmp.cond, s[0]->flags_condition());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
+                        ::testing::ValuesIn(kFPCmpInstructions));
+
+// ----------------------------------------------------------------------------
+// Arithmetic compare instructions integers
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<IntCmp> InstructionSelectorCmpTest;
+
+
+TEST_P(InstructionSelectorCmpTest, Parameter) {
+  const IntCmp cmp = GetParam();
+  const MachineType type = cmp.mi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(cmp.expected_size, s.size());
+  EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorCmpTest,
+                        ::testing::ValuesIn(kCmpInstructions));
+
+// ----------------------------------------------------------------------------
+// Shift instructions.
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorShiftTest;
+
+TEST_P(InstructionSelectorShiftTest, Immediate) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) {
+    StreamBuilder m(this, type, type);
+    m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
+                        ::testing::ValuesIn(kShiftInstructions));
+
+// ----------------------------------------------------------------------------
+// Logical instructions.
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorLogicalTest;
+
+
+TEST_P(InstructionSelectorLogicalTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest,
+                        ::testing::ValuesIn(kLogicalInstructions));
+
+// ----------------------------------------------------------------------------
+// MUL/DIV instructions.
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorMulDivTest;
+
+TEST_P(InstructionSelectorMulDivTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest,
+                        ::testing::ValuesIn(kMulDivInstructions));
+
+// ----------------------------------------------------------------------------
+// MOD instructions.
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<MachInst2> InstructionSelectorModTest;
+
+TEST_P(InstructionSelectorModTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorModTest,
+                        ::testing::ValuesIn(kModInstructions));
+
+// ----------------------------------------------------------------------------
+// Floating point instructions.
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorFPArithTest;
+
+TEST_P(InstructionSelectorFPArithTest, Parameter) {
+  const MachInst2 fpa = GetParam();
+  StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type);
+  m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest,
+                        ::testing::ValuesIn(kFPArithInstructions));
+// ----------------------------------------------------------------------------
+// Integer arithmetic
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorIntArithTwoTest;
+
+TEST_P(InstructionSelectorIntArithTwoTest, Parameter) {
+  const MachInst2 intpa = GetParam();
+  StreamBuilder m(this, intpa.machine_type, intpa.machine_type,
+                  intpa.machine_type);
+  m.Return((m.*intpa.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(intpa.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorIntArithTwoTest,
+                        ::testing::ValuesIn(kAddSubInstructions));
+
+
+// ----------------------------------------------------------------------------
+// One node.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst1>
+    InstructionSelectorIntArithOneTest;
+
+TEST_P(InstructionSelectorIntArithOneTest, Parameter) {
+  const MachInst1 intpa = GetParam();
+  StreamBuilder m(this, intpa.machine_type, intpa.machine_type,
+                  intpa.machine_type);
+  m.Return((m.*intpa.constructor)(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(intpa.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorIntArithOneTest,
+                        ::testing::ValuesIn(kAddSubOneInstructions));
+// ----------------------------------------------------------------------------
+// Conversions.
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<Conversion>
+    InstructionSelectorConversionTest;
+
+TEST_P(InstructionSelectorConversionTest, Parameter) {
+  const Conversion conv = GetParam();
+  StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
+  m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorConversionTest,
+                        ::testing::ValuesIn(kConversionInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Loads and stores.
+// ----------------------------------------------------------------------------
+
+
+namespace {
+
+struct MemoryAccess {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+};
+
+static const MemoryAccess kMemoryAccesses[] = {
+    {kMachInt8, kMips64Lb, kMips64Sb},
+    {kMachUint8, kMips64Lbu, kMips64Sb},
+    {kMachInt16, kMips64Lh, kMips64Sh},
+    {kMachUint16, kMips64Lhu, kMips64Sh},
+    {kMachInt32, kMips64Lw, kMips64Sw},
+    {kRepFloat32, kMips64Lwc1, kMips64Swc1},
+    {kRepFloat64, kMips64Ldc1, kMips64Sdc1},
+    {kMachInt64, kMips64Ld, kMips64Sd}};
+
+
+struct MemoryAccessImm {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+  bool (InstructionSelectorTest::Stream::*val_predicate)(
+      const InstructionOperand*) const;
+  const int32_t immediates[40];
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccessImm& acc) {
+  return os << acc.type;
+}
+
+
+struct MemoryAccessImm1 {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+  bool (InstructionSelectorTest::Stream::*val_predicate)(
+      const InstructionOperand*) const;
+  const int32_t immediates[5];
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccessImm1& acc) {
+  return os << acc.type;
+}
+
+
+// ----------------------------------------------------------------------------
+// Loads and stores immediate values
+// ----------------------------------------------------------------------------
+
+
+const MemoryAccessImm kMemoryAccessesImm[] = {
+    {kMachInt8,
+     kMips64Lb,
+     kMips64Sb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachUint8,
+     kMips64Lbu,
+     kMips64Sb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachInt16,
+     kMips64Lh,
+     kMips64Sh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachUint16,
+     kMips64Lhu,
+     kMips64Sh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachInt32,
+     kMips64Lw,
+     kMips64Sw,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachFloat32,
+     kMips64Lwc1,
+     kMips64Swc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachFloat64,
+     kMips64Ldc1,
+     kMips64Sdc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachInt64,
+     kMips64Ld,
+     kMips64Sd,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}};
+
+
+const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = {
+    {kMachInt8,
+     kMips64Lb,
+     kMips64Sb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt8,
+     kMips64Lbu,
+     kMips64Sb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt16,
+     kMips64Lh,
+     kMips64Sh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt16,
+     kMips64Lhu,
+     kMips64Sh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt32,
+     kMips64Lw,
+     kMips64Sw,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachFloat32,
+     kMips64Lwc1,
+     kMips64Swc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachFloat64,
+     kMips64Ldc1,
+     kMips64Sdc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt64,
+     kMips64Ld,
+     kMips64Sd,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccess>
+    InstructionSelectorMemoryAccessTest;
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
+  m.Return(m.Load(memacc.type, m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
+  m.Store(memacc.type, m.Parameter(0), m.Parameter(1));
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessTest,
+                        ::testing::ValuesIn(kMemoryAccesses));
+
+
+// ----------------------------------------------------------------------------
+// Load immediate.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccessImm>
+    InstructionSelectorMemoryAccessImmTest;
+
+TEST_P(InstructionSelectorMemoryAccessImmTest, LoadWithImmediateIndex) {
+  const MemoryAccessImm memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output()));
+  }
+}
+
+
+// ----------------------------------------------------------------------------
+// Store immediate.
+// ----------------------------------------------------------------------------
+
+
+TEST_P(InstructionSelectorMemoryAccessImmTest, StoreWithImmediateIndex) {
+  const MemoryAccessImm memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
+    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
+            m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(0U, s[0]->OutputCount());
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessImmTest,
+                        ::testing::ValuesIn(kMemoryAccessesImm));
+
+
+// ----------------------------------------------------------------------------
+// Load/store offsets more than 16 bits.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccessImm1>
+    InstructionSelectorMemoryAccessImmMoreThan16bitTest;
+
+TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,
+       LoadWithImmediateIndex) {
+  const MemoryAccessImm1 memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
+    Stream s = m.Build();
+    ASSERT_EQ(2U, s.size());
+    // kMips64Dadd is expected opcode
+    // size more than 16 bits wide
+    EXPECT_EQ(kMips64Dadd, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,
+       StoreWithImmediateIndex) {
+  const MemoryAccessImm1 memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
+    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
+            m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(2U, s.size());
+    // kMips64Add is expected opcode
+    // size more than 16 bits wide
+    EXPECT_EQ(kMips64Dadd, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessImmMoreThan16bitTest,
+                        ::testing::ValuesIn(kMemoryAccessImmMoreThan16bit));
+
+
+// ----------------------------------------------------------------------------
+// kMips64Cmp with zero testing.
+// ----------------------------------------------------------------------------
+
+
+TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kMips64Cmp32, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kMips64Cmp32, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64EqualWithZero) {
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kMips64Cmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    m.Return(m.Word64Equal(m.Int32Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kMips64Cmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/move-optimizer-unittest.cc b/test/unittests/compiler/move-optimizer-unittest.cc
new file mode 100644
index 0000000..5b956f0
--- /dev/null
+++ b/test/unittests/compiler/move-optimizer-unittest.cc
@@ -0,0 +1,133 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/move-optimizer.h"
+#include "test/unittests/compiler/instruction-sequence-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class MoveOptimizerTest : public InstructionSequenceTest {
+ public:
+  GapInstruction* LastGap() {
+    auto instruction = sequence()->instructions().back();
+    if (!instruction->IsGapMoves()) {
+      instruction = *(sequence()->instructions().rbegin() + 1);
+    }
+    return GapInstruction::cast(instruction);
+  }
+
+  void AddMove(GapInstruction* gap, TestOperand from, TestOperand to,
+               GapInstruction::InnerPosition pos = GapInstruction::START) {
+    auto parallel_move = gap->GetOrCreateParallelMove(pos, zone());
+    parallel_move->AddMove(ConvertMoveArg(from), ConvertMoveArg(to), zone());
+  }
+
+  int NonRedundantSize(ParallelMove* move) {
+    int i = 0;
+    auto ops = move->move_operands();
+    for (auto op = ops->begin(); op != ops->end(); ++op) {
+      if (op->IsRedundant()) continue;
+      i++;
+    }
+    return i;
+  }
+
+  bool Contains(ParallelMove* move, TestOperand from_op, TestOperand to_op) {
+    auto from = ConvertMoveArg(from_op);
+    auto to = ConvertMoveArg(to_op);
+    auto ops = move->move_operands();
+    for (auto op = ops->begin(); op != ops->end(); ++op) {
+      if (op->IsRedundant()) continue;
+      if (op->source()->Equals(from) && op->destination()->Equals(to)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // TODO(dcarney): add a verifier.
+  void Optimize() {
+    WireBlocks();
+    if (FLAG_trace_turbo) {
+      OFStream os(stdout);
+      PrintableInstructionSequence printable = {config(), sequence()};
+      os << "----- Instruction sequence before move optimization -----\n"
+         << printable;
+    }
+    MoveOptimizer move_optimizer(zone(), sequence());
+    move_optimizer.Run();
+    if (FLAG_trace_turbo) {
+      OFStream os(stdout);
+      PrintableInstructionSequence printable = {config(), sequence()};
+      os << "----- Instruction sequence after move optimization -----\n"
+         << printable;
+    }
+  }
+
+ private:
+  InstructionOperand* ConvertMoveArg(TestOperand op) {
+    CHECK_EQ(kNoValue, op.vreg_.value_);
+    CHECK_NE(kNoValue, op.value_);
+    switch (op.type_) {
+      case kConstant:
+        return ConstantOperand::Create(op.value_, zone());
+      case kFixedSlot:
+        return StackSlotOperand::Create(op.value_, zone());
+      case kFixedRegister:
+        CHECK(0 <= op.value_ && op.value_ < num_general_registers());
+        return RegisterOperand::Create(op.value_, zone());
+      default:
+        break;
+    }
+    CHECK(false);
+    return nullptr;
+  }
+};
+
+
+TEST_F(MoveOptimizerTest, RemovesRedundant) {
+  StartBlock();
+  AddMove(LastGap(), Reg(0), Reg(1));
+  EmitNop();
+  AddMove(LastGap(), Reg(1), Reg(0));
+  EmitNop();
+  EndBlock(Last());
+
+  Optimize();
+
+  auto gap = LastGap();
+  auto move = gap->parallel_moves()[0];
+  CHECK_EQ(1, NonRedundantSize(move));
+  CHECK(Contains(move, Reg(0), Reg(1)));
+}
+
+
+TEST_F(MoveOptimizerTest, SplitsConstants) {
+  StartBlock();
+  EndBlock(Last());
+
+  auto gap = LastGap();
+  AddMove(gap, Const(1), Slot(0));
+  AddMove(gap, Const(1), Slot(1));
+  AddMove(gap, Const(1), Reg(0));
+  AddMove(gap, Const(1), Slot(2));
+
+  Optimize();
+
+  auto move = gap->parallel_moves()[0];
+  CHECK_EQ(1, NonRedundantSize(move));
+  CHECK(Contains(move, Const(1), Reg(0)));
+
+  move = gap->parallel_moves()[1];
+  CHECK_EQ(3, NonRedundantSize(move));
+  CHECK(Contains(move, Reg(0), Slot(0)));
+  CHECK(Contains(move, Reg(0), Slot(1)));
+  CHECK(Contains(move, Reg(0), Slot(2)));
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/node-matchers-unittest.cc b/test/unittests/compiler/node-matchers-unittest.cc
new file mode 100644
index 0000000..85db9db
--- /dev/null
+++ b/test/unittests/compiler/node-matchers-unittest.cc
@@ -0,0 +1,733 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/node.h"
+#include "src/compiler/node-matchers.h"
+#include "src/compiler/opcodes.h"
+
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class NodeMatcherTest : public GraphTest {
+ public:
+  NodeMatcherTest() : machine_(zone()) {}
+  ~NodeMatcherTest() OVERRIDE {}
+
+  MachineOperatorBuilder* machine() { return &machine_; }
+
+ private:
+  MachineOperatorBuilder machine_;
+};
+
+namespace {
+
+template <class Matcher>
+void CheckBaseWithIndexAndDisplacement(Matcher* matcher, Node* index, int scale,
+                                       Node* base, Node* displacement) {
+  EXPECT_TRUE(matcher->matches());
+  EXPECT_EQ(index, matcher->index());
+  EXPECT_EQ(scale, matcher->scale());
+  EXPECT_EQ(base, matcher->base());
+  EXPECT_EQ(displacement, matcher->displacement());
+}
+};
+
+
+TEST_F(NodeMatcherTest, ScaledWithOffset32Matcher) {
+  graph()->SetStart(graph()->NewNode(common()->Start(0)));
+
+  const Operator* d0_op = common()->Int32Constant(0);
+  Node* d0 = graph()->NewNode(d0_op);
+  USE(d0);
+  const Operator* d1_op = common()->Int32Constant(1);
+  Node* d1 = graph()->NewNode(d1_op);
+  USE(d1);
+  const Operator* d2_op = common()->Int32Constant(2);
+  Node* d2 = graph()->NewNode(d2_op);
+  USE(d2);
+  const Operator* d3_op = common()->Int32Constant(3);
+  Node* d3 = graph()->NewNode(d3_op);
+  USE(d3);
+  const Operator* d4_op = common()->Int32Constant(4);
+  Node* d4 = graph()->NewNode(d4_op);
+  USE(d4);
+  const Operator* d5_op = common()->Int32Constant(5);
+  Node* d5 = graph()->NewNode(d5_op);
+  USE(d5);
+  const Operator* d7_op = common()->Int32Constant(7);
+  Node* d7 = graph()->NewNode(d7_op);
+  USE(d4);
+  const Operator* d8_op = common()->Int32Constant(8);
+  Node* d8 = graph()->NewNode(d8_op);
+  USE(d8);
+  const Operator* d9_op = common()->Int32Constant(9);
+  Node* d9 = graph()->NewNode(d9_op);
+  USE(d9);
+  const Operator* d15_op = common()->Int32Constant(15);
+  Node* d15 = graph()->NewNode(d15_op);
+  USE(d15);
+
+  const Operator* b0_op = common()->Parameter(0);
+  Node* b0 = graph()->NewNode(b0_op, graph()->start());
+  USE(b0);
+  const Operator* b1_op = common()->Parameter(1);
+  Node* b1 = graph()->NewNode(b1_op, graph()->start());
+  USE(b0);
+
+  const Operator* p1_op = common()->Parameter(3);
+  Node* p1 = graph()->NewNode(p1_op, graph()->start());
+  USE(p1);
+
+  const Operator* a_op = machine()->Int32Add();
+  USE(a_op);
+
+  const Operator* m_op = machine()->Int32Mul();
+  Node* m1 = graph()->NewNode(m_op, p1, d1);
+  Node* m2 = graph()->NewNode(m_op, p1, d2);
+  Node* m3 = graph()->NewNode(m_op, p1, d3);
+  Node* m4 = graph()->NewNode(m_op, p1, d4);
+  Node* m5 = graph()->NewNode(m_op, p1, d5);
+  Node* m7 = graph()->NewNode(m_op, p1, d7);
+  Node* m8 = graph()->NewNode(m_op, p1, d8);
+  Node* m9 = graph()->NewNode(m_op, p1, d9);
+  USE(m1);
+  USE(m2);
+  USE(m3);
+  USE(m4);
+  USE(m5);
+  USE(m7);
+  USE(m8);
+  USE(m9);
+
+  const Operator* s_op = machine()->Word32Shl();
+  Node* s0 = graph()->NewNode(s_op, p1, d0);
+  Node* s1 = graph()->NewNode(s_op, p1, d1);
+  Node* s2 = graph()->NewNode(s_op, p1, d2);
+  Node* s3 = graph()->NewNode(s_op, p1, d3);
+  Node* s4 = graph()->NewNode(s_op, p1, d4);
+  USE(s0);
+  USE(s1);
+  USE(s2);
+  USE(s3);
+  USE(s4);
+
+  // 1 INPUT
+
+  // Only relevant test dases is Checking for non-match.
+  BaseWithIndexAndDisplacement32Matcher match0(d15);
+  EXPECT_FALSE(match0.matches());
+
+  // 2 INPUT
+
+  // (B0 + B1) -> [B0, 0, B1, NULL]
+  BaseWithIndexAndDisplacement32Matcher match1(graph()->NewNode(a_op, b0, b1));
+  CheckBaseWithIndexAndDisplacement(&match1, b1, 0, b0, NULL);
+
+  // (B0 + D15) -> [NULL, 0, B0, D15]
+  BaseWithIndexAndDisplacement32Matcher match2(graph()->NewNode(a_op, b0, d15));
+  CheckBaseWithIndexAndDisplacement(&match2, NULL, 0, b0, d15);
+
+  // (D15 + B0) -> [NULL, 0, B0, D15]
+  BaseWithIndexAndDisplacement32Matcher match3(graph()->NewNode(a_op, d15, b0));
+  CheckBaseWithIndexAndDisplacement(&match3, NULL, 0, b0, d15);
+
+  // (B0 + M1) -> [p1, 0, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match4(graph()->NewNode(a_op, b0, m1));
+  CheckBaseWithIndexAndDisplacement(&match4, p1, 0, b0, NULL);
+
+  // (M1 + B0) -> [p1, 0, B0, NULL]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match5(graph()->NewNode(a_op, m1, b0));
+  CheckBaseWithIndexAndDisplacement(&match5, p1, 0, b0, NULL);
+
+  // (D15 + M1) -> [P1, 0, NULL, D15]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match6(graph()->NewNode(a_op, d15, m1));
+  CheckBaseWithIndexAndDisplacement(&match6, p1, 0, NULL, d15);
+
+  // (M1 + D15) -> [P1, 0, NULL, D15]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match7(graph()->NewNode(a_op, m1, d15));
+  CheckBaseWithIndexAndDisplacement(&match7, p1, 0, NULL, d15);
+
+  // (B0 + S0) -> [p1, 0, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match8(graph()->NewNode(a_op, b0, s0));
+  CheckBaseWithIndexAndDisplacement(&match8, p1, 0, b0, NULL);
+
+  // (S0 + B0) -> [p1, 0, B0, NULL]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement32Matcher match9(graph()->NewNode(a_op, s0, b0));
+  CheckBaseWithIndexAndDisplacement(&match9, p1, 0, b0, NULL);
+
+  // (D15 + S0) -> [P1, 0, NULL, D15]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement32Matcher match10(
+      graph()->NewNode(a_op, d15, s0));
+  CheckBaseWithIndexAndDisplacement(&match10, p1, 0, NULL, d15);
+
+  // (S0 + D15) -> [P1, 0, NULL, D15]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement32Matcher match11(
+      graph()->NewNode(a_op, s0, d15));
+  CheckBaseWithIndexAndDisplacement(&match11, p1, 0, NULL, d15);
+
+  // (B0 + M2) -> [p1, 1, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match12(graph()->NewNode(a_op, b0, m2));
+  CheckBaseWithIndexAndDisplacement(&match12, p1, 1, b0, NULL);
+
+  // (M2 + B0) -> [p1, 1, B0, NULL]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match13(graph()->NewNode(a_op, m2, b0));
+  CheckBaseWithIndexAndDisplacement(&match13, p1, 1, b0, NULL);
+
+  // (D15 + M2) -> [P1, 1, NULL, D15]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match14(
+      graph()->NewNode(a_op, d15, m2));
+  CheckBaseWithIndexAndDisplacement(&match14, p1, 1, NULL, d15);
+
+  // (M2 + D15) -> [P1, 1, NULL, D15]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match15(
+      graph()->NewNode(a_op, m2, d15));
+  CheckBaseWithIndexAndDisplacement(&match15, p1, 1, NULL, d15);
+
+  // (B0 + S1) -> [p1, 1, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match16(graph()->NewNode(a_op, b0, s1));
+  CheckBaseWithIndexAndDisplacement(&match16, p1, 1, b0, NULL);
+
+  // (S1 + B0) -> [p1, 1, B0, NULL]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match17(graph()->NewNode(a_op, s1, b0));
+  CheckBaseWithIndexAndDisplacement(&match17, p1, 1, b0, NULL);
+
+  // (D15 + S1) -> [P1, 1, NULL, D15]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match18(
+      graph()->NewNode(a_op, d15, s1));
+  CheckBaseWithIndexAndDisplacement(&match18, p1, 1, NULL, d15);
+
+  // (S1 + D15) -> [P1, 1, NULL, D15]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match19(
+      graph()->NewNode(a_op, s1, d15));
+  CheckBaseWithIndexAndDisplacement(&match19, p1, 1, NULL, d15);
+
+  // (B0 + M4) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match20(graph()->NewNode(a_op, b0, m4));
+  CheckBaseWithIndexAndDisplacement(&match20, p1, 2, b0, NULL);
+
+  // (M4 + B0) -> [p1, 2, B0, NULL]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement32Matcher match21(graph()->NewNode(a_op, m4, b0));
+  CheckBaseWithIndexAndDisplacement(&match21, p1, 2, b0, NULL);
+
+  // (D15 + M4) -> [p1, 2, NULL, D15]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement32Matcher match22(
+      graph()->NewNode(a_op, d15, m4));
+  CheckBaseWithIndexAndDisplacement(&match22, p1, 2, NULL, d15);
+
+  // (M4 + D15) -> [p1, 2, NULL, D15]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement32Matcher match23(
+      graph()->NewNode(a_op, m4, d15));
+  CheckBaseWithIndexAndDisplacement(&match23, p1, 2, NULL, d15);
+
+  // (B0 + S2) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match24(graph()->NewNode(a_op, b0, s2));
+  CheckBaseWithIndexAndDisplacement(&match24, p1, 2, b0, NULL);
+
+  // (S2 + B0) -> [p1, 2, B0, NULL]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match25(graph()->NewNode(a_op, s2, b0));
+  CheckBaseWithIndexAndDisplacement(&match25, p1, 2, b0, NULL);
+
+  // (D15 + S2) -> [p1, 2, NULL, D15]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match26(
+      graph()->NewNode(a_op, d15, s2));
+  CheckBaseWithIndexAndDisplacement(&match26, p1, 2, NULL, d15);
+
+  // (S2 + D15) -> [p1, 2, NULL, D15]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match27(
+      graph()->NewNode(a_op, s2, d15));
+  CheckBaseWithIndexAndDisplacement(&match27, p1, 2, NULL, d15);
+
+  // (B0 + M8) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match28(graph()->NewNode(a_op, b0, m8));
+  CheckBaseWithIndexAndDisplacement(&match28, p1, 3, b0, NULL);
+
+  // (M8 + B0) -> [p1, 2, B0, NULL]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement32Matcher match29(graph()->NewNode(a_op, m8, b0));
+  CheckBaseWithIndexAndDisplacement(&match29, p1, 3, b0, NULL);
+
+  // (D15 + M8) -> [p1, 2, NULL, D15]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement32Matcher match30(
+      graph()->NewNode(a_op, d15, m8));
+  CheckBaseWithIndexAndDisplacement(&match30, p1, 3, NULL, d15);
+
+  // (M8 + D15) -> [p1, 2, NULL, D15]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement32Matcher match31(
+      graph()->NewNode(a_op, m8, d15));
+  CheckBaseWithIndexAndDisplacement(&match31, p1, 3, NULL, d15);
+
+  // (B0 + S3) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match32(graph()->NewNode(a_op, b0, s3));
+  CheckBaseWithIndexAndDisplacement(&match32, p1, 3, b0, NULL);
+
+  // (S3 + B0) -> [p1, 2, B0, NULL]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match33(graph()->NewNode(a_op, s3, b0));
+  CheckBaseWithIndexAndDisplacement(&match33, p1, 3, b0, NULL);
+
+  // (D15 + S3) -> [p1, 2, NULL, D15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match34(
+      graph()->NewNode(a_op, d15, s3));
+  CheckBaseWithIndexAndDisplacement(&match34, p1, 3, NULL, d15);
+
+  // (S3 + D15) -> [p1, 2, NULL, D15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match35(
+      graph()->NewNode(a_op, s3, d15));
+  CheckBaseWithIndexAndDisplacement(&match35, p1, 3, NULL, d15);
+
+  // 2 INPUT - NEGATIVE CASES
+
+  // (M3 + B1) -> [B0, 0, M3, NULL]
+  BaseWithIndexAndDisplacement32Matcher match36(graph()->NewNode(a_op, b1, m3));
+  CheckBaseWithIndexAndDisplacement(&match36, m3, 0, b1, NULL);
+
+  // (S4 + B1) -> [B0, 0, S4, NULL]
+  BaseWithIndexAndDisplacement32Matcher match37(graph()->NewNode(a_op, b1, s4));
+  CheckBaseWithIndexAndDisplacement(&match37, s4, 0, b1, NULL);
+
+  // 3 INPUT
+
+  // (D15 + S3) + B0 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match38(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, d15, s3), b0));
+  CheckBaseWithIndexAndDisplacement(&match38, p1, 3, b0, d15);
+
+  // (B0 + D15) + S3 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match39(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, b0, d15), s3));
+  CheckBaseWithIndexAndDisplacement(&match39, p1, 3, b0, d15);
+
+  // (S3 + B0) + D15 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match40(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, s3, b0), d15));
+  CheckBaseWithIndexAndDisplacement(&match40, p1, 3, b0, d15);
+
+  // D15 + (S3 + B0) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match41(
+      graph()->NewNode(a_op, d15, graph()->NewNode(a_op, s3, b0)));
+  CheckBaseWithIndexAndDisplacement(&match41, p1, 3, b0, d15);
+
+  // B0 + (D15 + S3) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match42(
+      graph()->NewNode(a_op, b0, graph()->NewNode(a_op, d15, s3)));
+  CheckBaseWithIndexAndDisplacement(&match42, p1, 3, b0, d15);
+
+  // S3 + (B0 + D15) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match43(
+      graph()->NewNode(a_op, s3, graph()->NewNode(a_op, b0, d15)));
+  CheckBaseWithIndexAndDisplacement(&match43, p1, 3, b0, d15);
+
+  // Check that scales that require using the base address work dorrectly.
+}
+
+
+TEST_F(NodeMatcherTest, ScaledWithOffset64Matcher) {
+  graph()->SetStart(graph()->NewNode(common()->Start(0)));
+
+  const Operator* d0_op = common()->Int64Constant(0);
+  Node* d0 = graph()->NewNode(d0_op);
+  USE(d0);
+  const Operator* d1_op = common()->Int64Constant(1);
+  Node* d1 = graph()->NewNode(d1_op);
+  USE(d1);
+  const Operator* d2_op = common()->Int64Constant(2);
+  Node* d2 = graph()->NewNode(d2_op);
+  USE(d2);
+  const Operator* d3_op = common()->Int64Constant(3);
+  Node* d3 = graph()->NewNode(d3_op);
+  USE(d3);
+  const Operator* d4_op = common()->Int64Constant(4);
+  Node* d4 = graph()->NewNode(d4_op);
+  USE(d4);
+  const Operator* d5_op = common()->Int64Constant(5);
+  Node* d5 = graph()->NewNode(d5_op);
+  USE(d5);
+  const Operator* d7_op = common()->Int64Constant(7);
+  Node* d7 = graph()->NewNode(d7_op);
+  USE(d7);
+  const Operator* d8_op = common()->Int64Constant(8);
+  Node* d8 = graph()->NewNode(d8_op);
+  USE(d8);
+  const Operator* d9_op = common()->Int64Constant(9);
+  Node* d9 = graph()->NewNode(d9_op);
+  USE(d8);
+  const Operator* d15_op = common()->Int64Constant(15);
+  Node* d15 = graph()->NewNode(d15_op);
+  USE(d15);
+  const Operator* d15_32_op = common()->Int32Constant(15);
+  Node* d15_32 = graph()->NewNode(d15_32_op);
+  USE(d15_32);
+
+  const Operator* b0_op = common()->Parameter(0);
+  Node* b0 = graph()->NewNode(b0_op, graph()->start());
+  USE(b0);
+  const Operator* b1_op = common()->Parameter(1);
+  Node* b1 = graph()->NewNode(b1_op, graph()->start());
+  USE(b0);
+
+  const Operator* p1_op = common()->Parameter(3);
+  Node* p1 = graph()->NewNode(p1_op, graph()->start());
+  USE(p1);
+
+  const Operator* a_op = machine()->Int64Add();
+  USE(a_op);
+
+  const Operator* m_op = machine()->Int64Mul();
+  Node* m1 = graph()->NewNode(m_op, p1, d1);
+  Node* m2 = graph()->NewNode(m_op, p1, d2);
+  Node* m3 = graph()->NewNode(m_op, p1, d3);
+  Node* m4 = graph()->NewNode(m_op, p1, d4);
+  Node* m5 = graph()->NewNode(m_op, p1, d5);
+  Node* m7 = graph()->NewNode(m_op, p1, d7);
+  Node* m8 = graph()->NewNode(m_op, p1, d8);
+  Node* m9 = graph()->NewNode(m_op, p1, d9);
+  USE(m1);
+  USE(m2);
+  USE(m3);
+  USE(m4);
+  USE(m5);
+  USE(m7);
+  USE(m8);
+  USE(m9);
+
+  const Operator* s_op = machine()->Word64Shl();
+  Node* s0 = graph()->NewNode(s_op, p1, d0);
+  Node* s1 = graph()->NewNode(s_op, p1, d1);
+  Node* s2 = graph()->NewNode(s_op, p1, d2);
+  Node* s3 = graph()->NewNode(s_op, p1, d3);
+  Node* s4 = graph()->NewNode(s_op, p1, d4);
+  USE(s0);
+  USE(s1);
+  USE(s2);
+  USE(s3);
+  USE(s4);
+
+  // 1 INPUT
+
+  // Only relevant test dases is Checking for non-match.
+  BaseWithIndexAndDisplacement64Matcher match0(d15);
+  EXPECT_FALSE(match0.matches());
+
+  // 2 INPUT
+
+  // (B0 + B1) -> [B0, 0, B1, NULL]
+  BaseWithIndexAndDisplacement64Matcher match1(graph()->NewNode(a_op, b0, b1));
+  CheckBaseWithIndexAndDisplacement(&match1, b1, 0, b0, NULL);
+
+  // (B0 + D15) -> [NULL, 0, B0, D15]
+  BaseWithIndexAndDisplacement64Matcher match2(graph()->NewNode(a_op, b0, d15));
+  CheckBaseWithIndexAndDisplacement(&match2, NULL, 0, b0, d15);
+
+  BaseWithIndexAndDisplacement64Matcher match2_32(
+      graph()->NewNode(a_op, b0, d15_32));
+  CheckBaseWithIndexAndDisplacement(&match2_32, NULL, 0, b0, d15_32);
+
+  // (D15 + B0) -> [NULL, 0, B0, D15]
+  BaseWithIndexAndDisplacement64Matcher match3(graph()->NewNode(a_op, d15, b0));
+  CheckBaseWithIndexAndDisplacement(&match3, NULL, 0, b0, d15);
+
+  // (B0 + M1) -> [p1, 0, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match4(graph()->NewNode(a_op, b0, m1));
+  CheckBaseWithIndexAndDisplacement(&match4, p1, 0, b0, NULL);
+
+  // (M1 + B0) -> [p1, 0, B0, NULL]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match5(graph()->NewNode(a_op, m1, b0));
+  CheckBaseWithIndexAndDisplacement(&match5, p1, 0, b0, NULL);
+
+  // (D15 + M1) -> [P1, 0, NULL, D15]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match6(graph()->NewNode(a_op, d15, m1));
+  CheckBaseWithIndexAndDisplacement(&match6, p1, 0, NULL, d15);
+
+  // (M1 + D15) -> [P1, 0, NULL, D15]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match7(graph()->NewNode(a_op, m1, d15));
+  CheckBaseWithIndexAndDisplacement(&match7, p1, 0, NULL, d15);
+
+  // (B0 + S0) -> [p1, 0, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match8(graph()->NewNode(a_op, b0, s0));
+  CheckBaseWithIndexAndDisplacement(&match8, p1, 0, b0, NULL);
+
+  // (S0 + B0) -> [p1, 0, B0, NULL]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement64Matcher match9(graph()->NewNode(a_op, s0, b0));
+  CheckBaseWithIndexAndDisplacement(&match9, p1, 0, b0, NULL);
+
+  // (D15 + S0) -> [P1, 0, NULL, D15]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement64Matcher match10(
+      graph()->NewNode(a_op, d15, s0));
+  CheckBaseWithIndexAndDisplacement(&match10, p1, 0, NULL, d15);
+
+  // (S0 + D15) -> [P1, 0, NULL, D15]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement64Matcher match11(
+      graph()->NewNode(a_op, s0, d15));
+  CheckBaseWithIndexAndDisplacement(&match11, p1, 0, NULL, d15);
+
+  // (B0 + M2) -> [p1, 1, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match12(graph()->NewNode(a_op, b0, m2));
+  CheckBaseWithIndexAndDisplacement(&match12, p1, 1, b0, NULL);
+
+  // (M2 + B0) -> [p1, 1, B0, NULL]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match13(graph()->NewNode(a_op, m2, b0));
+  CheckBaseWithIndexAndDisplacement(&match13, p1, 1, b0, NULL);
+
+  // (D15 + M2) -> [P1, 1, NULL, D15]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match14(
+      graph()->NewNode(a_op, d15, m2));
+  CheckBaseWithIndexAndDisplacement(&match14, p1, 1, NULL, d15);
+
+  // (M2 + D15) -> [P1, 1, NULL, D15]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match15(
+      graph()->NewNode(a_op, m2, d15));
+  CheckBaseWithIndexAndDisplacement(&match15, p1, 1, NULL, d15);
+
+  // (B0 + S1) -> [p1, 1, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match16(graph()->NewNode(a_op, b0, s1));
+  CheckBaseWithIndexAndDisplacement(&match16, p1, 1, b0, NULL);
+
+  // (S1 + B0) -> [p1, 1, B0, NULL]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match17(graph()->NewNode(a_op, s1, b0));
+  CheckBaseWithIndexAndDisplacement(&match17, p1, 1, b0, NULL);
+
+  // (D15 + S1) -> [P1, 1, NULL, D15]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match18(
+      graph()->NewNode(a_op, d15, s1));
+  CheckBaseWithIndexAndDisplacement(&match18, p1, 1, NULL, d15);
+
+  // (S1 + D15) -> [P1, 1, NULL, D15]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match19(
+      graph()->NewNode(a_op, s1, d15));
+  CheckBaseWithIndexAndDisplacement(&match19, p1, 1, NULL, d15);
+
+  // (B0 + M4) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match20(graph()->NewNode(a_op, b0, m4));
+  CheckBaseWithIndexAndDisplacement(&match20, p1, 2, b0, NULL);
+
+  // (M4 + B0) -> [p1, 2, B0, NULL]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement64Matcher match21(graph()->NewNode(a_op, m4, b0));
+  CheckBaseWithIndexAndDisplacement(&match21, p1, 2, b0, NULL);
+
+  // (D15 + M4) -> [p1, 2, NULL, D15]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement64Matcher match22(
+      graph()->NewNode(a_op, d15, m4));
+  CheckBaseWithIndexAndDisplacement(&match22, p1, 2, NULL, d15);
+
+  // (M4 + D15) -> [p1, 2, NULL, D15]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement64Matcher match23(
+      graph()->NewNode(a_op, m4, d15));
+  CheckBaseWithIndexAndDisplacement(&match23, p1, 2, NULL, d15);
+
+  // (B0 + S2) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match24(graph()->NewNode(a_op, b0, s2));
+  CheckBaseWithIndexAndDisplacement(&match24, p1, 2, b0, NULL);
+
+  // (S2 + B0) -> [p1, 2, B0, NULL]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match25(graph()->NewNode(a_op, s2, b0));
+  CheckBaseWithIndexAndDisplacement(&match25, p1, 2, b0, NULL);
+
+  // (D15 + S2) -> [p1, 2, NULL, D15]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match26(
+      graph()->NewNode(a_op, d15, s2));
+  CheckBaseWithIndexAndDisplacement(&match26, p1, 2, NULL, d15);
+
+  // (S2 + D15) -> [p1, 2, NULL, D15]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match27(
+      graph()->NewNode(a_op, s2, d15));
+  CheckBaseWithIndexAndDisplacement(&match27, p1, 2, NULL, d15);
+
+  // (B0 + M8) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match28(graph()->NewNode(a_op, b0, m8));
+  CheckBaseWithIndexAndDisplacement(&match28, p1, 3, b0, NULL);
+
+  // (M8 + B0) -> [p1, 2, B0, NULL]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement64Matcher match29(graph()->NewNode(a_op, m8, b0));
+  CheckBaseWithIndexAndDisplacement(&match29, p1, 3, b0, NULL);
+
+  // (D15 + M8) -> [p1, 2, NULL, D15]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement64Matcher match30(
+      graph()->NewNode(a_op, d15, m8));
+  CheckBaseWithIndexAndDisplacement(&match30, p1, 3, NULL, d15);
+
+  // (M8 + D15) -> [p1, 2, NULL, D15]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement64Matcher match31(
+      graph()->NewNode(a_op, m8, d15));
+  CheckBaseWithIndexAndDisplacement(&match31, p1, 3, NULL, d15);
+
+  // (B0 + S3) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match64(graph()->NewNode(a_op, b0, s3));
+  CheckBaseWithIndexAndDisplacement(&match64, p1, 3, b0, NULL);
+
+  // (S3 + B0) -> [p1, 2, B0, NULL]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match33(graph()->NewNode(a_op, s3, b0));
+  CheckBaseWithIndexAndDisplacement(&match33, p1, 3, b0, NULL);
+
+  // (D15 + S3) -> [p1, 2, NULL, D15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match34(
+      graph()->NewNode(a_op, d15, s3));
+  CheckBaseWithIndexAndDisplacement(&match34, p1, 3, NULL, d15);
+
+  // (S3 + D15) -> [p1, 2, NULL, D15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match35(
+      graph()->NewNode(a_op, s3, d15));
+  CheckBaseWithIndexAndDisplacement(&match35, p1, 3, NULL, d15);
+
+  // 2 INPUT - NEGATIVE CASES
+
+  // (M3 + B1) -> [B0, 0, M3, NULL]
+  BaseWithIndexAndDisplacement64Matcher match36(graph()->NewNode(a_op, b1, m3));
+  CheckBaseWithIndexAndDisplacement(&match36, m3, 0, b1, NULL);
+
+  // (S4 + B1) -> [B0, 0, S4, NULL]
+  BaseWithIndexAndDisplacement64Matcher match37(graph()->NewNode(a_op, b1, s4));
+  CheckBaseWithIndexAndDisplacement(&match37, s4, 0, b1, NULL);
+
+  // 3 INPUT
+
+  // (D15 + S3) + B0 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match38(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, d15, s3), b0));
+  CheckBaseWithIndexAndDisplacement(&match38, p1, 3, b0, d15);
+
+  // (B0 + D15) + S3 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match39(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, b0, d15), s3));
+  CheckBaseWithIndexAndDisplacement(&match39, p1, 3, b0, d15);
+
+  // (S3 + B0) + D15 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match40(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, s3, b0), d15));
+  CheckBaseWithIndexAndDisplacement(&match40, p1, 3, b0, d15);
+
+  // D15 + (S3 + B0) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match41(
+      graph()->NewNode(a_op, d15, graph()->NewNode(a_op, s3, b0)));
+  CheckBaseWithIndexAndDisplacement(&match41, p1, 3, b0, d15);
+
+  // B0 + (D15 + S3) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match42(
+      graph()->NewNode(a_op, b0, graph()->NewNode(a_op, d15, s3)));
+  CheckBaseWithIndexAndDisplacement(&match42, p1, 3, b0, d15);
+
+  // S3 + (B0 + D15) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match43(
+      graph()->NewNode(a_op, s3, graph()->NewNode(a_op, b0, d15)));
+  CheckBaseWithIndexAndDisplacement(&match43, p1, 3, b0, d15);
+
+  // 2 INPUT with non-power of 2 scale
+
+  // (M3 + D15) -> [p1, 1, p1, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match44(
+      graph()->NewNode(a_op, m3, d15));
+  CheckBaseWithIndexAndDisplacement(&match44, p1, 1, p1, d15);
+
+  // (M5 + D15) -> [p1, 2, p1, D15]
+  m5 = graph()->NewNode(m_op, p1, d5);
+  BaseWithIndexAndDisplacement64Matcher match45(
+      graph()->NewNode(a_op, m5, d15));
+  CheckBaseWithIndexAndDisplacement(&match45, p1, 2, p1, d15);
+
+  // (M9 + D15) -> [p1, 3, p1, D15]
+  m9 = graph()->NewNode(m_op, p1, d9);
+  BaseWithIndexAndDisplacement64Matcher match46(
+      graph()->NewNode(a_op, m9, d15));
+  CheckBaseWithIndexAndDisplacement(&match46, p1, 3, p1, d15);
+
+  // 3 INPUT negative cases: non-power of 2 scale but with a base
+
+  // ((M3 + B0) + D15) -> [m3, 0, b0, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  Node* temp = graph()->NewNode(a_op, m3, b0);
+  BaseWithIndexAndDisplacement64Matcher match47(
+      graph()->NewNode(a_op, temp, d15));
+  CheckBaseWithIndexAndDisplacement(&match47, m3, 0, b0, d15);
+
+  // (M3 + (B0 + D15)) -> [m3, 0, b0, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  temp = graph()->NewNode(a_op, d15, b0);
+  BaseWithIndexAndDisplacement64Matcher match48(
+      graph()->NewNode(a_op, m3, temp));
+  CheckBaseWithIndexAndDisplacement(&match48, m3, 0, b0, d15);
+
+  // ((B0 + M3) + D15) -> [m3, 0, b0, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  temp = graph()->NewNode(a_op, b0, m3);
+  BaseWithIndexAndDisplacement64Matcher match49(
+      graph()->NewNode(a_op, temp, d15));
+  CheckBaseWithIndexAndDisplacement(&match49, m3, 0, b0, d15);
+
+  // (M3 + (D15 + B0)) -> [m3, 0, b0, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  temp = graph()->NewNode(a_op, b0, d15);
+  BaseWithIndexAndDisplacement64Matcher match50(
+      graph()->NewNode(a_op, m3, temp));
+  CheckBaseWithIndexAndDisplacement(&match50, m3, 0, b0, d15);
+}
+
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/node-test-utils.cc b/test/unittests/compiler/node-test-utils.cc
new file mode 100644
index 0000000..74afda9
--- /dev/null
+++ b/test/unittests/compiler/node-test-utils.cc
@@ -0,0 +1,1315 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/compiler/node-test-utils.h"
+
+#include "src/assembler.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/simplified-operator.h"
+
+using testing::_;
+using testing::MakeMatcher;
+using testing::MatcherInterface;
+using testing::MatchResultListener;
+using testing::StringMatchResultListener;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+template <typename T>
+bool PrintMatchAndExplain(const T& value, const char* value_name,
+                          const Matcher<T>& value_matcher,
+                          MatchResultListener* listener) {
+  StringMatchResultListener value_listener;
+  if (!value_matcher.MatchAndExplain(value, &value_listener)) {
+    *listener << "whose " << value_name << " " << value << " doesn't match";
+    if (value_listener.str() != "") {
+      *listener << ", " << value_listener.str();
+    }
+    return false;
+  }
+  return true;
+}
+
+
+class NodeMatcher : public MatcherInterface<Node*> {
+ public:
+  explicit NodeMatcher(IrOpcode::Value opcode) : opcode_(opcode) {}
+
+  void DescribeTo(std::ostream* os) const OVERRIDE {
+    *os << "is a " << IrOpcode::Mnemonic(opcode_) << " node";
+  }
+
+  bool MatchAndExplain(Node* node,
+                       MatchResultListener* listener) const OVERRIDE {
+    if (node == NULL) {
+      *listener << "which is NULL";
+      return false;
+    }
+    if (node->opcode() != opcode_) {
+      *listener << "whose opcode is " << IrOpcode::Mnemonic(node->opcode())
+                << " but should have been " << IrOpcode::Mnemonic(opcode_);
+      return false;
+    }
+    return true;
+  }
+
+ private:
+  const IrOpcode::Value opcode_;
+};
+
+
+class IsBranchMatcher FINAL : public NodeMatcher {
+ public:
+  IsBranchMatcher(const Matcher<Node*>& value_matcher,
+                  const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kBranch),
+        value_matcher_(value_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose value (";
+    value_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "value", value_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> value_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsMergeMatcher FINAL : public NodeMatcher {
+ public:
+  IsMergeMatcher(const Matcher<Node*>& control0_matcher,
+                 const Matcher<Node*>& control1_matcher)
+      : NodeMatcher(IrOpcode::kMerge),
+        control0_matcher_(control0_matcher),
+        control1_matcher_(control1_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose control0 (";
+    control0_matcher_.DescribeTo(os);
+    *os << ") and control1 (";
+    control1_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node, 0),
+                                 "control0", control0_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node, 1),
+                                 "control1", control1_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> control0_matcher_;
+  const Matcher<Node*> control1_matcher_;
+};
+
+
+class IsControl1Matcher FINAL : public NodeMatcher {
+ public:
+  IsControl1Matcher(IrOpcode::Value opcode,
+                    const Matcher<Node*>& control_matcher)
+      : NodeMatcher(opcode), control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsFinishMatcher FINAL : public NodeMatcher {
+ public:
+  IsFinishMatcher(const Matcher<Node*>& value_matcher,
+                  const Matcher<Node*>& effect_matcher)
+      : NodeMatcher(IrOpcode::kFinish),
+        value_matcher_(value_matcher),
+        effect_matcher_(effect_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose value (";
+    value_matcher_.DescribeTo(os);
+    *os << ") and effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "value", value_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> value_matcher_;
+  const Matcher<Node*> effect_matcher_;
+};
+
+
+template <typename T>
+class IsConstantMatcher FINAL : public NodeMatcher {
+ public:
+  IsConstantMatcher(IrOpcode::Value opcode, const Matcher<T>& value_matcher)
+      : NodeMatcher(opcode), value_matcher_(value_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose value (";
+    value_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<T>(node), "value", value_matcher_,
+                                 listener));
+  }
+
+ private:
+  const Matcher<T> value_matcher_;
+};
+
+
+class IsSelectMatcher FINAL : public NodeMatcher {
+ public:
+  IsSelectMatcher(const Matcher<MachineType>& type_matcher,
+                  const Matcher<Node*>& value0_matcher,
+                  const Matcher<Node*>& value1_matcher,
+                  const Matcher<Node*>& value2_matcher)
+      : NodeMatcher(IrOpcode::kSelect),
+        type_matcher_(type_matcher),
+        value0_matcher_(value0_matcher),
+        value1_matcher_(value1_matcher),
+        value2_matcher_(value2_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose type (";
+    type_matcher_.DescribeTo(os);
+    *os << "), value0 (";
+    value0_matcher_.DescribeTo(os);
+    *os << "), value1 (";
+    value1_matcher_.DescribeTo(os);
+    *os << ") and value2 (";
+    value2_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<MachineType>(node), "type",
+                                 type_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "value0", value0_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "value1", value1_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+                                 "value2", value2_matcher_, listener));
+  }
+
+ private:
+  const Matcher<MachineType> type_matcher_;
+  const Matcher<Node*> value0_matcher_;
+  const Matcher<Node*> value1_matcher_;
+  const Matcher<Node*> value2_matcher_;
+};
+
+
+class IsPhiMatcher FINAL : public NodeMatcher {
+ public:
+  IsPhiMatcher(const Matcher<MachineType>& type_matcher,
+               const Matcher<Node*>& value0_matcher,
+               const Matcher<Node*>& value1_matcher,
+               const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kPhi),
+        type_matcher_(type_matcher),
+        value0_matcher_(value0_matcher),
+        value1_matcher_(value1_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose type (";
+    type_matcher_.DescribeTo(os);
+    *os << "), value0 (";
+    value0_matcher_.DescribeTo(os);
+    *os << "), value1 (";
+    value1_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<MachineType>(node), "type",
+                                 type_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "value0", value0_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "value1", value1_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<MachineType> type_matcher_;
+  const Matcher<Node*> value0_matcher_;
+  const Matcher<Node*> value1_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsEffectPhiMatcher FINAL : public NodeMatcher {
+ public:
+  IsEffectPhiMatcher(const Matcher<Node*>& effect0_matcher,
+                     const Matcher<Node*>& effect1_matcher,
+                     const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kEffectPhi),
+        effect0_matcher_(effect0_matcher),
+        effect1_matcher_(effect1_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << "), effect0 (";
+    effect0_matcher_.DescribeTo(os);
+    *os << "), effect1 (";
+    effect1_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node, 0),
+                                 "effect0", effect0_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node, 1),
+                                 "effect1", effect1_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> effect0_matcher_;
+  const Matcher<Node*> effect1_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsProjectionMatcher FINAL : public NodeMatcher {
+ public:
+  IsProjectionMatcher(const Matcher<size_t>& index_matcher,
+                      const Matcher<Node*>& base_matcher)
+      : NodeMatcher(IrOpcode::kProjection),
+        index_matcher_(index_matcher),
+        base_matcher_(base_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose index (";
+    index_matcher_.DescribeTo(os);
+    *os << ") and base (";
+    base_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<size_t>(node), "index",
+                                 index_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener));
+  }
+
+ private:
+  const Matcher<size_t> index_matcher_;
+  const Matcher<Node*> base_matcher_;
+};
+
+
+class IsCall2Matcher FINAL : public NodeMatcher {
+ public:
+  IsCall2Matcher(const Matcher<CallDescriptor*>& descriptor_matcher,
+                 const Matcher<Node*>& value0_matcher,
+                 const Matcher<Node*>& value1_matcher,
+                 const Matcher<Node*>& effect_matcher,
+                 const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kCall),
+        descriptor_matcher_(descriptor_matcher),
+        value0_matcher_(value0_matcher),
+        value1_matcher_(value1_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose value0 (";
+    value0_matcher_.DescribeTo(os);
+    *os << ") and value1 (";
+    value1_matcher_.DescribeTo(os);
+    *os << ") and effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<CallDescriptor*>(node),
+                                 "descriptor", descriptor_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "value0", value0_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "value1", value1_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<CallDescriptor*> descriptor_matcher_;
+  const Matcher<Node*> value0_matcher_;
+  const Matcher<Node*> value1_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsCall4Matcher FINAL : public NodeMatcher {
+ public:
+  IsCall4Matcher(const Matcher<CallDescriptor*>& descriptor_matcher,
+                 const Matcher<Node*>& value0_matcher,
+                 const Matcher<Node*>& value1_matcher,
+                 const Matcher<Node*>& value2_matcher,
+                 const Matcher<Node*>& value3_matcher,
+                 const Matcher<Node*>& effect_matcher,
+                 const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kCall),
+        descriptor_matcher_(descriptor_matcher),
+        value0_matcher_(value0_matcher),
+        value1_matcher_(value1_matcher),
+        value2_matcher_(value2_matcher),
+        value3_matcher_(value3_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose value0 (";
+    value0_matcher_.DescribeTo(os);
+    *os << ") and value1 (";
+    value1_matcher_.DescribeTo(os);
+    *os << ") and value2 (";
+    value2_matcher_.DescribeTo(os);
+    *os << ") and value3 (";
+    value3_matcher_.DescribeTo(os);
+    *os << ") and effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<CallDescriptor*>(node),
+                                 "descriptor", descriptor_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "value0", value0_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "value1", value1_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+                                 "value2", value2_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 3),
+                                 "value3", value3_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<CallDescriptor*> descriptor_matcher_;
+  const Matcher<Node*> value0_matcher_;
+  const Matcher<Node*> value1_matcher_;
+  const Matcher<Node*> value2_matcher_;
+  const Matcher<Node*> value3_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsLoadFieldMatcher FINAL : public NodeMatcher {
+ public:
+  IsLoadFieldMatcher(const Matcher<FieldAccess>& access_matcher,
+                     const Matcher<Node*>& base_matcher,
+                     const Matcher<Node*>& effect_matcher,
+                     const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kLoadField),
+        access_matcher_(access_matcher),
+        base_matcher_(base_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose access (";
+    access_matcher_.DescribeTo(os);
+    *os << "), base (";
+    base_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<FieldAccess>(node), "access",
+                                 access_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<FieldAccess> access_matcher_;
+  const Matcher<Node*> base_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsStoreFieldMatcher FINAL : public NodeMatcher {
+ public:
+  IsStoreFieldMatcher(const Matcher<FieldAccess>& access_matcher,
+                      const Matcher<Node*>& base_matcher,
+                      const Matcher<Node*>& value_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kStoreField),
+        access_matcher_(access_matcher),
+        base_matcher_(base_matcher),
+        value_matcher_(value_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose access (";
+    access_matcher_.DescribeTo(os);
+    *os << "), base (";
+    base_matcher_.DescribeTo(os);
+    *os << "), value (";
+    value_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<FieldAccess>(node), "access",
+                                 access_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "value", value_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<FieldAccess> access_matcher_;
+  const Matcher<Node*> base_matcher_;
+  const Matcher<Node*> value_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsLoadBufferMatcher FINAL : public NodeMatcher {
+ public:
+  IsLoadBufferMatcher(const Matcher<BufferAccess>& access_matcher,
+                      const Matcher<Node*>& buffer_matcher,
+                      const Matcher<Node*>& offset_matcher,
+                      const Matcher<Node*>& length_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kLoadBuffer),
+        access_matcher_(access_matcher),
+        buffer_matcher_(buffer_matcher),
+        offset_matcher_(offset_matcher),
+        length_matcher_(length_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose access (";
+    access_matcher_.DescribeTo(os);
+    *os << "), buffer (";
+    buffer_matcher_.DescribeTo(os);
+    *os << "), offset (";
+    offset_matcher_.DescribeTo(os);
+    *os << "), length (";
+    length_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(BufferAccessOf(node->op()), "access",
+                                 access_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "buffer", buffer_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "offset", offset_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+                                 "length", length_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<BufferAccess> access_matcher_;
+  const Matcher<Node*> buffer_matcher_;
+  const Matcher<Node*> offset_matcher_;
+  const Matcher<Node*> length_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsStoreBufferMatcher FINAL : public NodeMatcher {
+ public:
+  IsStoreBufferMatcher(const Matcher<BufferAccess>& access_matcher,
+                       const Matcher<Node*>& buffer_matcher,
+                       const Matcher<Node*>& offset_matcher,
+                       const Matcher<Node*>& length_matcher,
+                       const Matcher<Node*>& value_matcher,
+                       const Matcher<Node*>& effect_matcher,
+                       const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kStoreBuffer),
+        access_matcher_(access_matcher),
+        buffer_matcher_(buffer_matcher),
+        offset_matcher_(offset_matcher),
+        length_matcher_(length_matcher),
+        value_matcher_(value_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose access (";
+    access_matcher_.DescribeTo(os);
+    *os << "), buffer (";
+    buffer_matcher_.DescribeTo(os);
+    *os << "), offset (";
+    offset_matcher_.DescribeTo(os);
+    *os << "), length (";
+    length_matcher_.DescribeTo(os);
+    *os << "), value (";
+    value_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(BufferAccessOf(node->op()), "access",
+                                 access_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "buffer", buffer_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "offset", offset_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+                                 "length", length_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 3),
+                                 "value", value_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<BufferAccess> access_matcher_;
+  const Matcher<Node*> buffer_matcher_;
+  const Matcher<Node*> offset_matcher_;
+  const Matcher<Node*> length_matcher_;
+  const Matcher<Node*> value_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsLoadElementMatcher FINAL : public NodeMatcher {
+ public:
+  IsLoadElementMatcher(const Matcher<ElementAccess>& access_matcher,
+                       const Matcher<Node*>& base_matcher,
+                       const Matcher<Node*>& index_matcher,
+                       const Matcher<Node*>& effect_matcher,
+                       const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kLoadElement),
+        access_matcher_(access_matcher),
+        base_matcher_(base_matcher),
+        index_matcher_(index_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose access (";
+    access_matcher_.DescribeTo(os);
+    *os << "), base (";
+    base_matcher_.DescribeTo(os);
+    *os << "), index (";
+    index_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<ElementAccess>(node), "access",
+                                 access_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "index", index_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<ElementAccess> access_matcher_;
+  const Matcher<Node*> base_matcher_;
+  const Matcher<Node*> index_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsStoreElementMatcher FINAL : public NodeMatcher {
+ public:
+  IsStoreElementMatcher(const Matcher<ElementAccess>& access_matcher,
+                        const Matcher<Node*>& base_matcher,
+                        const Matcher<Node*>& index_matcher,
+                        const Matcher<Node*>& value_matcher,
+                        const Matcher<Node*>& effect_matcher,
+                        const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kStoreElement),
+        access_matcher_(access_matcher),
+        base_matcher_(base_matcher),
+        index_matcher_(index_matcher),
+        value_matcher_(value_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose access (";
+    access_matcher_.DescribeTo(os);
+    *os << "), base (";
+    base_matcher_.DescribeTo(os);
+    *os << "), index (";
+    index_matcher_.DescribeTo(os);
+    *os << "), value (";
+    value_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<ElementAccess>(node), "access",
+                                 access_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "index", index_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+                                 "value", value_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<ElementAccess> access_matcher_;
+  const Matcher<Node*> base_matcher_;
+  const Matcher<Node*> index_matcher_;
+  const Matcher<Node*> value_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsLoadMatcher FINAL : public NodeMatcher {
+ public:
+  IsLoadMatcher(const Matcher<LoadRepresentation>& rep_matcher,
+                const Matcher<Node*>& base_matcher,
+                const Matcher<Node*>& index_matcher,
+                const Matcher<Node*>& effect_matcher,
+                const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kLoad),
+        rep_matcher_(rep_matcher),
+        base_matcher_(base_matcher),
+        index_matcher_(index_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose rep (";
+    rep_matcher_.DescribeTo(os);
+    *os << "), base (";
+    base_matcher_.DescribeTo(os);
+    *os << "), index (";
+    index_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<LoadRepresentation>(node), "rep",
+                                 rep_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "index", index_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<LoadRepresentation> rep_matcher_;
+  const Matcher<Node*> base_matcher_;
+  const Matcher<Node*> index_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsToNumberMatcher FINAL : public NodeMatcher {
+ public:
+  IsToNumberMatcher(const Matcher<Node*>& base_matcher,
+                    const Matcher<Node*>& context_matcher,
+                    const Matcher<Node*>& effect_matcher,
+                    const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kJSToNumber),
+        base_matcher_(base_matcher),
+        context_matcher_(context_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose base (";
+    base_matcher_.DescribeTo(os);
+    *os << "), context (";
+    context_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetContextInput(node),
+                                 "context", context_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> base_matcher_;
+  const Matcher<Node*> context_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsStoreMatcher FINAL : public NodeMatcher {
+ public:
+  IsStoreMatcher(const Matcher<StoreRepresentation>& rep_matcher,
+                 const Matcher<Node*>& base_matcher,
+                 const Matcher<Node*>& index_matcher,
+                 const Matcher<Node*>& value_matcher,
+                 const Matcher<Node*>& effect_matcher,
+                 const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kStore),
+        rep_matcher_(rep_matcher),
+        base_matcher_(base_matcher),
+        index_matcher_(index_matcher),
+        value_matcher_(value_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose rep (";
+    rep_matcher_.DescribeTo(os);
+    *os << "), base (";
+    base_matcher_.DescribeTo(os);
+    *os << "), index (";
+    index_matcher_.DescribeTo(os);
+    *os << "), value (";
+    value_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<StoreRepresentation>(node), "rep",
+                                 rep_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "index", index_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+                                 "value", value_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<StoreRepresentation> rep_matcher_;
+  const Matcher<Node*> base_matcher_;
+  const Matcher<Node*> index_matcher_;
+  const Matcher<Node*> value_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsBinopMatcher FINAL : public NodeMatcher {
+ public:
+  IsBinopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& lhs_matcher,
+                 const Matcher<Node*>& rhs_matcher)
+      : NodeMatcher(opcode),
+        lhs_matcher_(lhs_matcher),
+        rhs_matcher_(rhs_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose lhs (";
+    lhs_matcher_.DescribeTo(os);
+    *os << ") and rhs (";
+    rhs_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "lhs",
+                                 lhs_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), "rhs",
+                                 rhs_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> lhs_matcher_;
+  const Matcher<Node*> rhs_matcher_;
+};
+
+
+class IsUnopMatcher FINAL : public NodeMatcher {
+ public:
+  IsUnopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& input_matcher)
+      : NodeMatcher(opcode), input_matcher_(input_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose input (";
+    input_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "input", input_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> input_matcher_;
+};
+}
+
+
+Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
+                        const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsBranchMatcher(value_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,
+                       const Matcher<Node*>& control1_matcher) {
+  return MakeMatcher(new IsMergeMatcher(control0_matcher, control1_matcher));
+}
+
+
+Matcher<Node*> IsIfTrue(const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsControl1Matcher(IrOpcode::kIfTrue, control_matcher));
+}
+
+
+Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(
+      new IsControl1Matcher(IrOpcode::kIfFalse, control_matcher));
+}
+
+
+Matcher<Node*> IsValueEffect(const Matcher<Node*>& value_matcher) {
+  return MakeMatcher(new IsUnopMatcher(IrOpcode::kValueEffect, value_matcher));
+}
+
+
+Matcher<Node*> IsFinish(const Matcher<Node*>& value_matcher,
+                        const Matcher<Node*>& effect_matcher) {
+  return MakeMatcher(new IsFinishMatcher(value_matcher, effect_matcher));
+}
+
+
+Matcher<Node*> IsExternalConstant(
+    const Matcher<ExternalReference>& value_matcher) {
+  return MakeMatcher(new IsConstantMatcher<ExternalReference>(
+      IrOpcode::kExternalConstant, value_matcher));
+}
+
+
+Matcher<Node*> IsHeapConstant(
+    const Matcher<Unique<HeapObject> >& value_matcher) {
+  return MakeMatcher(new IsConstantMatcher<Unique<HeapObject> >(
+      IrOpcode::kHeapConstant, value_matcher));
+}
+
+
+Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher) {
+  return MakeMatcher(
+      new IsConstantMatcher<int32_t>(IrOpcode::kInt32Constant, value_matcher));
+}
+
+
+Matcher<Node*> IsInt64Constant(const Matcher<int64_t>& value_matcher) {
+  return MakeMatcher(
+      new IsConstantMatcher<int64_t>(IrOpcode::kInt64Constant, value_matcher));
+}
+
+
+Matcher<Node*> IsFloat32Constant(const Matcher<float>& value_matcher) {
+  return MakeMatcher(
+      new IsConstantMatcher<float>(IrOpcode::kFloat32Constant, value_matcher));
+}
+
+
+Matcher<Node*> IsFloat64Constant(const Matcher<double>& value_matcher) {
+  return MakeMatcher(
+      new IsConstantMatcher<double>(IrOpcode::kFloat64Constant, value_matcher));
+}
+
+
+Matcher<Node*> IsNumberConstant(const Matcher<double>& value_matcher) {
+  return MakeMatcher(
+      new IsConstantMatcher<double>(IrOpcode::kNumberConstant, value_matcher));
+}
+
+
+Matcher<Node*> IsSelect(const Matcher<MachineType>& type_matcher,
+                        const Matcher<Node*>& value0_matcher,
+                        const Matcher<Node*>& value1_matcher,
+                        const Matcher<Node*>& value2_matcher) {
+  return MakeMatcher(new IsSelectMatcher(type_matcher, value0_matcher,
+                                         value1_matcher, value2_matcher));
+}
+
+
+Matcher<Node*> IsPhi(const Matcher<MachineType>& type_matcher,
+                     const Matcher<Node*>& value0_matcher,
+                     const Matcher<Node*>& value1_matcher,
+                     const Matcher<Node*>& merge_matcher) {
+  return MakeMatcher(new IsPhiMatcher(type_matcher, value0_matcher,
+                                      value1_matcher, merge_matcher));
+}
+
+
+Matcher<Node*> IsEffectPhi(const Matcher<Node*>& effect0_matcher,
+                           const Matcher<Node*>& effect1_matcher,
+                           const Matcher<Node*>& merge_matcher) {
+  return MakeMatcher(
+      new IsEffectPhiMatcher(effect0_matcher, effect1_matcher, merge_matcher));
+}
+
+
+Matcher<Node*> IsProjection(const Matcher<size_t>& index_matcher,
+                            const Matcher<Node*>& base_matcher) {
+  return MakeMatcher(new IsProjectionMatcher(index_matcher, base_matcher));
+}
+
+
+Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
+                      const Matcher<Node*>& value0_matcher,
+                      const Matcher<Node*>& value1_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsCall2Matcher(descriptor_matcher, value0_matcher,
+                                        value1_matcher, effect_matcher,
+                                        control_matcher));
+}
+
+
+Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
+                      const Matcher<Node*>& value0_matcher,
+                      const Matcher<Node*>& value1_matcher,
+                      const Matcher<Node*>& value2_matcher,
+                      const Matcher<Node*>& value3_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsCall4Matcher(
+      descriptor_matcher, value0_matcher, value1_matcher, value2_matcher,
+      value3_matcher, effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher,
+                           const Matcher<Node*>& base_matcher,
+                           const Matcher<Node*>& effect_matcher,
+                           const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsLoadFieldMatcher(access_matcher, base_matcher,
+                                            effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsStoreField(const Matcher<FieldAccess>& access_matcher,
+                            const Matcher<Node*>& base_matcher,
+                            const Matcher<Node*>& value_matcher,
+                            const Matcher<Node*>& effect_matcher,
+                            const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsStoreFieldMatcher(access_matcher, base_matcher,
+                                             value_matcher, effect_matcher,
+                                             control_matcher));
+}
+
+
+Matcher<Node*> IsLoadBuffer(const Matcher<BufferAccess>& access_matcher,
+                            const Matcher<Node*>& buffer_matcher,
+                            const Matcher<Node*>& offset_matcher,
+                            const Matcher<Node*>& length_matcher,
+                            const Matcher<Node*>& effect_matcher,
+                            const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsLoadBufferMatcher(access_matcher, buffer_matcher,
+                                             offset_matcher, length_matcher,
+                                             effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsStoreBuffer(const Matcher<BufferAccess>& access_matcher,
+                             const Matcher<Node*>& buffer_matcher,
+                             const Matcher<Node*>& offset_matcher,
+                             const Matcher<Node*>& length_matcher,
+                             const Matcher<Node*>& value_matcher,
+                             const Matcher<Node*>& effect_matcher,
+                             const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsStoreBufferMatcher(
+      access_matcher, buffer_matcher, offset_matcher, length_matcher,
+      value_matcher, effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsLoadElement(const Matcher<ElementAccess>& access_matcher,
+                             const Matcher<Node*>& base_matcher,
+                             const Matcher<Node*>& index_matcher,
+                             const Matcher<Node*>& effect_matcher,
+                             const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsLoadElementMatcher(access_matcher, base_matcher,
+                                              index_matcher, effect_matcher,
+                                              control_matcher));
+}
+
+
+Matcher<Node*> IsStoreElement(const Matcher<ElementAccess>& access_matcher,
+                              const Matcher<Node*>& base_matcher,
+                              const Matcher<Node*>& index_matcher,
+                              const Matcher<Node*>& value_matcher,
+                              const Matcher<Node*>& effect_matcher,
+                              const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsStoreElementMatcher(
+      access_matcher, base_matcher, index_matcher, value_matcher,
+      effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher,
+                      const Matcher<Node*>& base_matcher,
+                      const Matcher<Node*>& index_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsLoadMatcher(rep_matcher, base_matcher, index_matcher,
+                                       effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher,
+                          const Matcher<Node*>& context_matcher,
+                          const Matcher<Node*>& effect_matcher,
+                          const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsToNumberMatcher(base_matcher, context_matcher,
+                                           effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher,
+                       const Matcher<Node*>& base_matcher,
+                       const Matcher<Node*>& index_matcher,
+                       const Matcher<Node*>& value_matcher,
+                       const Matcher<Node*>& effect_matcher,
+                       const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsStoreMatcher(rep_matcher, base_matcher,
+                                        index_matcher, value_matcher,
+                                        effect_matcher, control_matcher));
+}
+
+
+#define IS_BINOP_MATCHER(Name)                                            \
+  Matcher<Node*> Is##Name(const Matcher<Node*>& lhs_matcher,              \
+                          const Matcher<Node*>& rhs_matcher) {            \
+    return MakeMatcher(                                                   \
+        new IsBinopMatcher(IrOpcode::k##Name, lhs_matcher, rhs_matcher)); \
+  }
+IS_BINOP_MATCHER(NumberEqual)
+IS_BINOP_MATCHER(NumberLessThan)
+IS_BINOP_MATCHER(NumberSubtract)
+IS_BINOP_MATCHER(NumberMultiply)
+IS_BINOP_MATCHER(Word32And)
+IS_BINOP_MATCHER(Word32Sar)
+IS_BINOP_MATCHER(Word32Shl)
+IS_BINOP_MATCHER(Word32Shr)
+IS_BINOP_MATCHER(Word32Ror)
+IS_BINOP_MATCHER(Word32Equal)
+IS_BINOP_MATCHER(Word64And)
+IS_BINOP_MATCHER(Word64Sar)
+IS_BINOP_MATCHER(Word64Shl)
+IS_BINOP_MATCHER(Word64Equal)
+IS_BINOP_MATCHER(Int32AddWithOverflow)
+IS_BINOP_MATCHER(Int32Add)
+IS_BINOP_MATCHER(Int32Sub)
+IS_BINOP_MATCHER(Int32Mul)
+IS_BINOP_MATCHER(Int32MulHigh)
+IS_BINOP_MATCHER(Int32LessThan)
+IS_BINOP_MATCHER(Uint32LessThan)
+IS_BINOP_MATCHER(Uint32LessThanOrEqual)
+IS_BINOP_MATCHER(Float64Sub)
+#undef IS_BINOP_MATCHER
+
+
+#define IS_UNOP_MATCHER(Name)                                                \
+  Matcher<Node*> Is##Name(const Matcher<Node*>& input_matcher) {             \
+    return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \
+  }
+IS_UNOP_MATCHER(AnyToBoolean)
+IS_UNOP_MATCHER(BooleanNot)
+IS_UNOP_MATCHER(ChangeFloat64ToInt32)
+IS_UNOP_MATCHER(ChangeFloat64ToUint32)
+IS_UNOP_MATCHER(ChangeInt32ToFloat64)
+IS_UNOP_MATCHER(ChangeInt32ToInt64)
+IS_UNOP_MATCHER(ChangeUint32ToFloat64)
+IS_UNOP_MATCHER(ChangeUint32ToUint64)
+IS_UNOP_MATCHER(TruncateFloat64ToFloat32)
+IS_UNOP_MATCHER(TruncateFloat64ToInt32)
+IS_UNOP_MATCHER(TruncateInt64ToInt32)
+IS_UNOP_MATCHER(Float64Sqrt)
+IS_UNOP_MATCHER(Float64Floor)
+IS_UNOP_MATCHER(Float64Ceil)
+IS_UNOP_MATCHER(Float64RoundTruncate)
+IS_UNOP_MATCHER(Float64RoundTiesAway)
+IS_UNOP_MATCHER(NumberToInt32)
+IS_UNOP_MATCHER(NumberToUint32)
+#undef IS_UNOP_MATCHER
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/node-test-utils.h b/test/unittests/compiler/node-test-utils.h
new file mode 100644
index 0000000..02b6e43
--- /dev/null
+++ b/test/unittests/compiler/node-test-utils.h
@@ -0,0 +1,196 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UNITTESTS_COMPILER_NODE_TEST_UTILS_H_
+#define V8_UNITTESTS_COMPILER_NODE_TEST_UTILS_H_
+
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/machine-type.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class ExternalReference;
+class HeapObject;
+template <class T>
+class Unique;
+
+namespace compiler {
+
+// Forward declarations.
+class BufferAccess;
+class CallDescriptor;
+struct ElementAccess;
+struct FieldAccess;
+class Node;
+
+
+using ::testing::Matcher;
+
+
+Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
+                        const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,
+                       const Matcher<Node*>& control1_matcher);
+Matcher<Node*> IsIfTrue(const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsValueEffect(const Matcher<Node*>& value_matcher);
+Matcher<Node*> IsFinish(const Matcher<Node*>& value_matcher,
+                        const Matcher<Node*>& effect_matcher);
+Matcher<Node*> IsExternalConstant(
+    const Matcher<ExternalReference>& value_matcher);
+Matcher<Node*> IsHeapConstant(
+    const Matcher<Unique<HeapObject> >& value_matcher);
+Matcher<Node*> IsFloat32Constant(const Matcher<float>& value_matcher);
+Matcher<Node*> IsFloat64Constant(const Matcher<double>& value_matcher);
+Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher);
+Matcher<Node*> IsInt64Constant(const Matcher<int64_t>& value_matcher);
+Matcher<Node*> IsNumberConstant(const Matcher<double>& value_matcher);
+Matcher<Node*> IsSelect(const Matcher<MachineType>& type_matcher,
+                        const Matcher<Node*>& value0_matcher,
+                        const Matcher<Node*>& value1_matcher,
+                        const Matcher<Node*>& value2_matcher);
+Matcher<Node*> IsPhi(const Matcher<MachineType>& type_matcher,
+                     const Matcher<Node*>& value0_matcher,
+                     const Matcher<Node*>& value1_matcher,
+                     const Matcher<Node*>& merge_matcher);
+Matcher<Node*> IsEffectPhi(const Matcher<Node*>& effect0_matcher,
+                           const Matcher<Node*>& effect1_matcher,
+                           const Matcher<Node*>& merge_matcher);
+Matcher<Node*> IsProjection(const Matcher<size_t>& index_matcher,
+                            const Matcher<Node*>& base_matcher);
+Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
+                      const Matcher<Node*>& value0_matcher,
+                      const Matcher<Node*>& value1_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
+                      const Matcher<Node*>& value0_matcher,
+                      const Matcher<Node*>& value1_matcher,
+                      const Matcher<Node*>& value2_matcher,
+                      const Matcher<Node*>& value3_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher);
+
+Matcher<Node*> IsAnyToBoolean(const Matcher<Node*>& value_matcher);
+Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher);
+Matcher<Node*> IsNumberEqual(const Matcher<Node*>& lhs_matcher,
+                             const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsNumberLessThan(const Matcher<Node*>& lhs_matcher,
+                                const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsNumberSubtract(const Matcher<Node*>& lhs_matcher,
+                                const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsNumberMultiply(const Matcher<Node*>& lhs_matcher,
+                                const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher,
+                           const Matcher<Node*>& base_matcher,
+                           const Matcher<Node*>& effect_matcher,
+                           const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsStoreField(const Matcher<FieldAccess>& access_matcher,
+                            const Matcher<Node*>& base_matcher,
+                            const Matcher<Node*>& value_matcher,
+                            const Matcher<Node*>& effect_matcher,
+                            const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsLoadBuffer(const Matcher<BufferAccess>& access_matcher,
+                            const Matcher<Node*>& buffer_matcher,
+                            const Matcher<Node*>& offset_matcher,
+                            const Matcher<Node*>& length_matcher,
+                            const Matcher<Node*>& effect_matcher,
+                            const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsStoreBuffer(const Matcher<BufferAccess>& access_matcher,
+                             const Matcher<Node*>& buffer_matcher,
+                             const Matcher<Node*>& offset_matcher,
+                             const Matcher<Node*>& length_matcher,
+                             const Matcher<Node*>& value_matcher,
+                             const Matcher<Node*>& effect_matcher,
+                             const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsLoadElement(const Matcher<ElementAccess>& access_matcher,
+                             const Matcher<Node*>& base_matcher,
+                             const Matcher<Node*>& index_matcher,
+                             const Matcher<Node*>& control_matcher,
+                             const Matcher<Node*>& effect_matcher);
+Matcher<Node*> IsStoreElement(const Matcher<ElementAccess>& access_matcher,
+                              const Matcher<Node*>& base_matcher,
+                              const Matcher<Node*>& index_matcher,
+                              const Matcher<Node*>& value_matcher,
+                              const Matcher<Node*>& effect_matcher,
+                              const Matcher<Node*>& control_matcher);
+
+Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher,
+                      const Matcher<Node*>& base_matcher,
+                      const Matcher<Node*>& index_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher,
+                       const Matcher<Node*>& base_matcher,
+                       const Matcher<Node*>& index_matcher,
+                       const Matcher<Node*>& value_matcher,
+                       const Matcher<Node*>& effect_matcher,
+                       const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsWord32And(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord32Sar(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord32Shl(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord32Shr(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord32Ror(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord32Equal(const Matcher<Node*>& lhs_matcher,
+                             const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord64And(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord64Shl(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord64Sar(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord64Equal(const Matcher<Node*>& lhs_matcher,
+                             const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32AddWithOverflow(const Matcher<Node*>& lhs_matcher,
+                                      const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32Add(const Matcher<Node*>& lhs_matcher,
+                          const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32Sub(const Matcher<Node*>& lhs_matcher,
+                          const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32Mul(const Matcher<Node*>& lhs_matcher,
+                          const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32MulHigh(const Matcher<Node*>& lhs_matcher,
+                              const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32LessThan(const Matcher<Node*>& lhs_matcher,
+                               const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsUint32LessThan(const Matcher<Node*>& lhs_matcher,
+                                const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsUint32LessThanOrEqual(const Matcher<Node*>& lhs_matcher,
+                                       const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsChangeFloat64ToInt32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsChangeFloat64ToUint32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsChangeInt32ToFloat64(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsChangeInt32ToInt64(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsChangeUint32ToFloat64(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsChangeUint32ToUint64(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsTruncateFloat64ToFloat32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsTruncateFloat64ToInt32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsTruncateInt64ToInt32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64Sub(const Matcher<Node*>& lhs_matcher,
+                            const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsFloat64Sqrt(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64Floor(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64Ceil(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64RoundTruncate(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64RoundTiesAway(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher,
+                          const Matcher<Node*>& context_matcher,
+                          const Matcher<Node*>& effect_matcher,
+                          const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsNumberToInt32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsNumberToUint32(const Matcher<Node*>& input_matcher);
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_UNITTESTS_COMPILER_NODE_TEST_UTILS_H_
diff --git a/test/unittests/compiler/register-allocator-unittest.cc b/test/unittests/compiler/register-allocator-unittest.cc
new file mode 100644
index 0000000..12dedbd
--- /dev/null
+++ b/test/unittests/compiler/register-allocator-unittest.cc
@@ -0,0 +1,437 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/pipeline.h"
+#include "test/unittests/compiler/instruction-sequence-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class RegisterAllocatorTest : public InstructionSequenceTest {
+ public:
+  void Allocate() {
+    WireBlocks();
+    Pipeline::AllocateRegistersForTesting(config(), sequence(), true);
+  }
+};
+
+
+TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) {
+  // return p0 + p1;
+  StartBlock();
+  auto a_reg = Parameter();
+  auto b_reg = Parameter();
+  auto c_reg = EmitOI(Reg(1), Reg(a_reg, 1), Reg(b_reg, 0));
+  Return(c_reg);
+  EndBlock(Last());
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, SimpleLoop) {
+  // i = K;
+  // while(true) { i++ }
+  StartBlock();
+  auto i_reg = DefineConstant();
+  EndBlock();
+
+  {
+    StartLoop(1);
+
+    StartBlock();
+    auto phi = Phi(i_reg);
+    auto ipp = EmitOI(Same(), Reg(phi), Use(DefineConstant()));
+    Extend(phi, ipp);
+    EndBlock(Jump(0));
+
+    EndLoop();
+  }
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, SimpleBranch) {
+  // return i ? K1 : K2
+  StartBlock();
+  auto i = DefineConstant();
+  EndBlock(Branch(Reg(i), 1, 2));
+
+  StartBlock();
+  Return(DefineConstant());
+  EndBlock(Last());
+
+  StartBlock();
+  Return(DefineConstant());
+  EndBlock(Last());
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, SimpleDiamond) {
+  // return p0 ? p0 : p0
+  StartBlock();
+  auto param = Parameter();
+  EndBlock(Branch(Reg(param), 1, 2));
+
+  StartBlock();
+  EndBlock(Jump(2));
+
+  StartBlock();
+  EndBlock(Jump(1));
+
+  StartBlock();
+  Return(param);
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, SimpleDiamondPhi) {
+  // return i ? K1 : K2
+  StartBlock();
+  EndBlock(Branch(Reg(DefineConstant()), 1, 2));
+
+  StartBlock();
+  auto t_val = DefineConstant();
+  EndBlock(Jump(2));
+
+  StartBlock();
+  auto f_val = DefineConstant();
+  EndBlock(Jump(1));
+
+  StartBlock();
+  Return(Reg(Phi(t_val, f_val)));
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, DiamondManyPhis) {
+  const int kPhis = kDefaultNRegs * 2;
+
+  StartBlock();
+  EndBlock(Branch(Reg(DefineConstant()), 1, 2));
+
+  StartBlock();
+  VReg t_vals[kPhis];
+  for (int i = 0; i < kPhis; ++i) {
+    t_vals[i] = DefineConstant();
+  }
+  EndBlock(Jump(2));
+
+  StartBlock();
+  VReg f_vals[kPhis];
+  for (int i = 0; i < kPhis; ++i) {
+    f_vals[i] = DefineConstant();
+  }
+  EndBlock(Jump(1));
+
+  StartBlock();
+  TestOperand merged[kPhis];
+  for (int i = 0; i < kPhis; ++i) {
+    merged[i] = Use(Phi(t_vals[i], f_vals[i]));
+  }
+  Return(EmitCall(Slot(-1), kPhis, merged));
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, DoubleDiamondManyRedundantPhis) {
+  const int kPhis = kDefaultNRegs * 2;
+
+  // First diamond.
+  StartBlock();
+  VReg vals[kPhis];
+  for (int i = 0; i < kPhis; ++i) {
+    vals[i] = Parameter(Slot(-1 - i));
+  }
+  EndBlock(Branch(Reg(DefineConstant()), 1, 2));
+
+  StartBlock();
+  EndBlock(Jump(2));
+
+  StartBlock();
+  EndBlock(Jump(1));
+
+  // Second diamond.
+  StartBlock();
+  EndBlock(Branch(Reg(DefineConstant()), 1, 2));
+
+  StartBlock();
+  EndBlock(Jump(2));
+
+  StartBlock();
+  EndBlock(Jump(1));
+
+  StartBlock();
+  TestOperand merged[kPhis];
+  for (int i = 0; i < kPhis; ++i) {
+    merged[i] = Use(Phi(vals[i], vals[i]));
+  }
+  Return(EmitCall(Reg(0), kPhis, merged));
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, RegressionPhisNeedTooManyRegisters) {
+  const size_t kNumRegs = 3;
+  const size_t kParams = kNumRegs + 1;
+  // Override number of registers.
+  SetNumRegs(kNumRegs, kNumRegs);
+
+  StartBlock();
+  auto constant = DefineConstant();
+  VReg parameters[kParams];
+  for (size_t i = 0; i < arraysize(parameters); ++i) {
+    parameters[i] = DefineConstant();
+  }
+  EndBlock();
+
+  PhiInstruction* phis[kParams];
+  {
+    StartLoop(2);
+
+    // Loop header.
+    StartBlock();
+
+    for (size_t i = 0; i < arraysize(parameters); ++i) {
+      phis[i] = Phi(parameters[i]);
+    }
+
+    // Perform some computations.
+    // something like phi[i] += const
+    for (size_t i = 0; i < arraysize(parameters); ++i) {
+      auto result = EmitOI(Same(), Reg(phis[i]), Use(constant));
+      Extend(phis[i], result);
+    }
+
+    EndBlock(Branch(Reg(DefineConstant()), 1, 2));
+
+    // Jump back to loop header.
+    StartBlock();
+    EndBlock(Jump(-1));
+
+    EndLoop();
+  }
+
+  StartBlock();
+  Return(DefineConstant());
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, SpillPhi) {
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 2));
+
+  StartBlock();
+  auto left = Define(Reg(0));
+  EndBlock(Jump(2));
+
+  StartBlock();
+  auto right = Define(Reg(0));
+  EndBlock();
+
+  StartBlock();
+  auto phi = Phi(left, right);
+  EmitCall(Slot(-1));
+  Return(Reg(phi));
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, MoveLotsOfConstants) {
+  StartBlock();
+  VReg constants[kDefaultNRegs];
+  for (size_t i = 0; i < arraysize(constants); ++i) {
+    constants[i] = DefineConstant();
+  }
+  TestOperand call_ops[kDefaultNRegs * 2];
+  for (int i = 0; i < kDefaultNRegs; ++i) {
+    call_ops[i] = Reg(constants[i], i);
+  }
+  for (int i = 0; i < kDefaultNRegs; ++i) {
+    call_ops[i + kDefaultNRegs] = Slot(constants[i], i);
+  }
+  EmitCall(Slot(-1), arraysize(call_ops), call_ops);
+  EndBlock(Last());
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, SplitBeforeInstruction) {
+  const int kNumRegs = 6;
+  SetNumRegs(kNumRegs, kNumRegs);
+
+  StartBlock();
+
+  // Stack parameters/spilled values.
+  auto p_0 = Define(Slot(-1));
+  auto p_1 = Define(Slot(-2));
+
+  // Fill registers.
+  VReg values[kNumRegs];
+  for (size_t i = 0; i < arraysize(values); ++i) {
+    values[i] = Define(Reg(static_cast<int>(i)));
+  }
+
+  // values[0] will be split in the second half of this instruction.
+  // Models Intel mod instructions.
+  EmitOI(Reg(0), Reg(p_0, 1), UniqueReg(p_1));
+  EmitI(Reg(values[0], 0));
+  EndBlock(Last());
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, NestedDiamondPhiMerge) {
+  // Outer diamond.
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 5));
+
+  // Diamond 1
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 2));
+
+  StartBlock();
+  auto ll = Define(Reg());
+  EndBlock(Jump(2));
+
+  StartBlock();
+  auto lr = Define(Reg());
+  EndBlock();
+
+  StartBlock();
+  auto l_phi = Phi(ll, lr);
+  EndBlock(Jump(5));
+
+  // Diamond 2
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 2));
+
+  StartBlock();
+  auto rl = Define(Reg());
+  EndBlock(Jump(2));
+
+  StartBlock();
+  auto rr = Define(Reg());
+  EndBlock();
+
+  StartBlock();
+  auto r_phi = Phi(rl, rr);
+  EndBlock();
+
+  // Outer diamond merge.
+  StartBlock();
+  auto phi = Phi(l_phi, r_phi);
+  Return(Reg(phi));
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, NestedDiamondPhiMergeDifferent) {
+  // Outer diamond.
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 5));
+
+  // Diamond 1
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 2));
+
+  StartBlock();
+  auto ll = Define(Reg(0));
+  EndBlock(Jump(2));
+
+  StartBlock();
+  auto lr = Define(Reg(1));
+  EndBlock();
+
+  StartBlock();
+  auto l_phi = Phi(ll, lr);
+  EndBlock(Jump(5));
+
+  // Diamond 2
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 2));
+
+  StartBlock();
+  auto rl = Define(Reg(2));
+  EndBlock(Jump(2));
+
+  StartBlock();
+  auto rr = Define(Reg(3));
+  EndBlock();
+
+  StartBlock();
+  auto r_phi = Phi(rl, rr);
+  EndBlock();
+
+  // Outer diamond merge.
+  StartBlock();
+  auto phi = Phi(l_phi, r_phi);
+  Return(Reg(phi));
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, RegressionSplitBeforeAndMove) {
+  StartBlock();
+
+  // Fill registers.
+  VReg values[kDefaultNRegs];
+  for (size_t i = 0; i < arraysize(values); ++i) {
+    if (i == 0 || i == 1) continue;  // Leave a hole for c_1 to take.
+    values[i] = Define(Reg(static_cast<int>(i)));
+  }
+
+  auto c_0 = DefineConstant();
+  auto c_1 = DefineConstant();
+
+  EmitOI(Reg(1), Reg(c_0, 0), UniqueReg(c_1));
+
+  // Use previous values to force c_1 to split before the previous instruction.
+  for (size_t i = 0; i < arraysize(values); ++i) {
+    if (i == 0 || i == 1) continue;
+    EmitI(Reg(values[i], static_cast<int>(i)));
+  }
+
+  EndBlock(Last());
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, RegressionSpillTwice) {
+  StartBlock();
+  auto p_0 = Parameter(Reg(1));
+  EmitCall(Slot(-2), Unique(p_0), Reg(p_0, 1));
+  EndBlock(Last());
+
+  Allocate();
+}
+
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/select-lowering-unittest.cc b/test/unittests/compiler/select-lowering-unittest.cc
new file mode 100644
index 0000000..51efc83
--- /dev/null
+++ b/test/unittests/compiler/select-lowering-unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/select-lowering.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::AllOf;
+using testing::Capture;
+using testing::CaptureEq;
+using testing::Not;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class SelectLoweringTest : public GraphTest {
+ public:
+  SelectLoweringTest() : GraphTest(5), lowering_(graph(), common()) {}
+
+ protected:
+  Reduction Reduce(Node* node) { return lowering_.Reduce(node); }
+
+ private:
+  SelectLowering lowering_;
+};
+
+
+TEST_F(SelectLoweringTest, SelectWithSameConditions) {
+  Node* const p0 = Parameter(0);
+  Node* const p1 = Parameter(1);
+  Node* const p2 = Parameter(2);
+  Node* const p3 = Parameter(3);
+  Node* const p4 = Parameter(4);
+  Node* const s0 = graph()->NewNode(common()->Select(kMachInt32), p0, p1, p2);
+
+  Capture<Node*> branch;
+  Capture<Node*> merge;
+  {
+    Reduction const r = Reduce(s0);
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsPhi(
+            kMachInt32, p1, p2,
+            AllOf(CaptureEq(&merge),
+                  IsMerge(IsIfTrue(CaptureEq(&branch)),
+                          IsIfFalse(AllOf(CaptureEq(&branch),
+                                          IsBranch(p0, graph()->start())))))));
+  }
+  {
+    Reduction const r =
+        Reduce(graph()->NewNode(common()->Select(kMachInt32), p0, p3, p4));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsPhi(kMachInt32, p3, p4, CaptureEq(&merge)));
+  }
+  {
+    // We must not reuse the diamond if it is reachable from either else/then
+    // values of the Select, because the resulting graph can not be scheduled.
+    Reduction const r =
+        Reduce(graph()->NewNode(common()->Select(kMachInt32), p0, s0, p0));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsPhi(kMachInt32, s0, p0, Not(CaptureEq(&merge))));
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/simplified-operator-reducer-unittest.cc b/test/unittests/compiler/simplified-operator-reducer-unittest.cc
new file mode 100644
index 0000000..e5f46c0
--- /dev/null
+++ b/test/unittests/compiler/simplified-operator-reducer-unittest.cc
@@ -0,0 +1,520 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/simplified-operator.h"
+#include "src/compiler/simplified-operator-reducer.h"
+#include "src/conversions.h"
+#include "src/types.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::BitEq;
+
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class SimplifiedOperatorReducerTest : public TypedGraphTest {
+ public:
+  explicit SimplifiedOperatorReducerTest(int num_parameters = 1)
+      : TypedGraphTest(num_parameters), simplified_(zone()) {}
+  ~SimplifiedOperatorReducerTest() OVERRIDE {}
+
+ protected:
+  Reduction Reduce(Node* node) {
+    MachineOperatorBuilder machine(zone());
+    JSOperatorBuilder javascript(zone());
+    JSGraph jsgraph(graph(), common(), &javascript, &machine);
+    SimplifiedOperatorReducer reducer(&jsgraph);
+    return reducer.Reduce(node);
+  }
+
+  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
+
+ private:
+  SimplifiedOperatorBuilder simplified_;
+};
+
+
+template <typename T>
+class SimplifiedOperatorReducerTestWithParam
+    : public SimplifiedOperatorReducerTest,
+      public ::testing::WithParamInterface<T> {
+ public:
+  explicit SimplifiedOperatorReducerTestWithParam(int num_parameters = 1)
+      : SimplifiedOperatorReducerTest(num_parameters) {}
+  ~SimplifiedOperatorReducerTestWithParam() OVERRIDE {}
+};
+
+
+namespace {
+
+static const double kFloat64Values[] = {
+    -V8_INFINITY,  -6.52696e+290, -1.05768e+290, -5.34203e+268, -1.01997e+268,
+    -8.22758e+266, -1.58402e+261, -5.15246e+241, -5.92107e+226, -1.21477e+226,
+    -1.67913e+188, -1.6257e+184,  -2.60043e+170, -2.52941e+168, -3.06033e+116,
+    -4.56201e+52,  -3.56788e+50,  -9.9066e+38,   -3.07261e+31,  -2.1271e+09,
+    -1.91489e+09,  -1.73053e+09,  -9.30675e+08,  -26030,        -20453,
+    -15790,        -11699,        -111,          -97,           -78,
+    -63,           -58,           -1.53858e-06,  -2.98914e-12,  -1.14741e-39,
+    -8.20347e-57,  -1.48932e-59,  -3.17692e-66,  -8.93103e-81,  -3.91337e-83,
+    -6.0489e-92,   -8.83291e-113, -4.28266e-117, -1.92058e-178, -2.0567e-192,
+    -1.68167e-194, -1.51841e-214, -3.98738e-234, -7.31851e-242, -2.21875e-253,
+    -1.11612e-293, -0.0,          0.0,           2.22507e-308,  1.06526e-307,
+    4.16643e-227,  6.76624e-223,  2.0432e-197,   3.16254e-184,  1.37315e-173,
+    2.88603e-172,  1.54155e-99,   4.42923e-81,   1.40539e-73,   5.4462e-73,
+    1.24064e-58,   3.11167e-58,   2.75826e-39,   0.143815,      58,
+    67,            601,           7941,          11644,         13697,
+    25680,         29882,         1.32165e+08,   1.62439e+08,   4.16837e+08,
+    9.59097e+08,   1.32491e+09,   1.8728e+09,    1.0672e+17,    2.69606e+46,
+    1.98285e+79,   1.0098e+82,    7.93064e+88,   3.67444e+121,  9.36506e+123,
+    7.27954e+162,  3.05316e+168,  1.16171e+175,  1.64771e+189,  1.1622e+202,
+    2.00748e+239,  2.51778e+244,  3.90282e+306,  1.79769e+308,  V8_INFINITY};
+
+
+static const int32_t kInt32Values[] = {
+    -2147483647 - 1, -2104508227, -2103151830, -1435284490, -1378926425,
+    -1318814539,     -1289388009, -1287537572, -1279026536, -1241605942,
+    -1226046939,     -941837148,  -779818051,  -413830641,  -245798087,
+    -184657557,      -127145950,  -105483328,  -32325,      -26653,
+    -23858,          -23834,      -22363,      -19858,      -19044,
+    -18744,          -15528,      -5309,       -3372,       -2093,
+    -104,            -98,         -97,         -93,         -84,
+    -80,             -78,         -76,         -72,         -58,
+    -57,             -56,         -55,         -45,         -40,
+    -34,             -32,         -25,         -24,         -5,
+    -2,              0,           3,           10,          24,
+    34,              42,          46,          47,          48,
+    52,              56,          64,          65,          71,
+    76,              79,          81,          82,          97,
+    102,             103,         104,         106,         107,
+    109,             116,         122,         3653,        4485,
+    12405,           16504,       26262,       28704,       29755,
+    30554,           16476817,    605431957,   832401070,   873617242,
+    914205764,       1062628108,  1087581664,  1488498068,  1534668023,
+    1661587028,      1696896187,  1866841746,  2032089723,  2147483647};
+
+
+static const uint32_t kUint32Values[] = {
+    0x0,        0x5,        0x8,        0xc,        0xd,        0x26,
+    0x28,       0x29,       0x30,       0x34,       0x3e,       0x42,
+    0x50,       0x5b,       0x63,       0x71,       0x77,       0x7c,
+    0x83,       0x88,       0x96,       0x9c,       0xa3,       0xfa,
+    0x7a7,      0x165d,     0x234d,     0x3acb,     0x43a5,     0x4573,
+    0x5b4f,     0x5f14,     0x6996,     0x6c6e,     0x7289,     0x7b9a,
+    0x7bc9,     0x86bb,     0xa839,     0xaa41,     0xb03b,     0xc942,
+    0xce68,     0xcf4c,     0xd3ad,     0xdea3,     0xe90c,     0xed86,
+    0xfba5,     0x172dcc6,  0x114d8fc1, 0x182d6c9d, 0x1b1e3fad, 0x1db033bf,
+    0x1e1de755, 0x1f625c80, 0x28f6cf00, 0x2acb6a94, 0x2c20240e, 0x2f0fe54e,
+    0x31863a7c, 0x33325474, 0x3532fae3, 0x3bab82ea, 0x4c4b83a2, 0x4cd93d1e,
+    0x4f7331d4, 0x5491b09b, 0x57cc6ff9, 0x60d3b4dc, 0x653f5904, 0x690ae256,
+    0x69fe3276, 0x6bebf0ba, 0x6e2c69a3, 0x73b84ff7, 0x7b3a1924, 0x7ed032d9,
+    0x84dd734b, 0x8552ea53, 0x8680754f, 0x8e9660eb, 0x94fe2b9c, 0x972d30cf,
+    0x9b98c482, 0xb158667e, 0xb432932c, 0xb5b70989, 0xb669971a, 0xb7c359d1,
+    0xbeb15c0d, 0xc171c53d, 0xc743dd38, 0xc8e2af50, 0xc98e2df0, 0xd9d1cdf9,
+    0xdcc91049, 0xe46f396d, 0xee991950, 0xef64e521, 0xf7aeefc9, 0xffffffff};
+
+}  // namespace
+
+
+// -----------------------------------------------------------------------------
+// Unary operators
+
+
+namespace {
+
+struct UnaryOperator {
+  const Operator* (SimplifiedOperatorBuilder::*constructor)();
+  const char* constructor_name;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const UnaryOperator& unop) {
+  return os << unop.constructor_name;
+}
+
+
+static const UnaryOperator kUnaryOperators[] = {
+    {&SimplifiedOperatorBuilder::AnyToBoolean, "AnyToBoolean"},
+    {&SimplifiedOperatorBuilder::BooleanNot, "BooleanNot"},
+    {&SimplifiedOperatorBuilder::ChangeBitToBool, "ChangeBitToBool"},
+    {&SimplifiedOperatorBuilder::ChangeBoolToBit, "ChangeBoolToBit"},
+    {&SimplifiedOperatorBuilder::ChangeFloat64ToTagged,
+     "ChangeFloat64ToTagged"},
+    {&SimplifiedOperatorBuilder::ChangeInt32ToTagged, "ChangeInt32ToTagged"},
+    {&SimplifiedOperatorBuilder::ChangeTaggedToFloat64,
+     "ChangeTaggedToFloat64"},
+    {&SimplifiedOperatorBuilder::ChangeTaggedToInt32, "ChangeTaggedToInt32"},
+    {&SimplifiedOperatorBuilder::ChangeTaggedToUint32, "ChangeTaggedToUint32"},
+    {&SimplifiedOperatorBuilder::ChangeUint32ToTagged, "ChangeUint32ToTagged"}};
+
+}  // namespace
+
+
+typedef SimplifiedOperatorReducerTestWithParam<UnaryOperator>
+    SimplifiedUnaryOperatorTest;
+
+
+TEST_P(SimplifiedUnaryOperatorTest, Parameter) {
+  const UnaryOperator& unop = GetParam();
+  Reduction reduction = Reduce(graph()->NewNode(
+      (simplified()->*unop.constructor)(), Parameter(Type::Any())));
+  EXPECT_FALSE(reduction.Changed());
+}
+
+
+INSTANTIATE_TEST_CASE_P(SimplifiedOperatorReducerTest,
+                        SimplifiedUnaryOperatorTest,
+                        ::testing::ValuesIn(kUnaryOperators));
+
+
+// -----------------------------------------------------------------------------
+// AnyToBoolean
+
+
+TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithBoolean) {
+  Node* p = Parameter(Type::Boolean());
+  Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_EQ(p, r.replacement());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithOrderedNumber) {
+  Node* p = Parameter(Type::OrderedNumber());
+  Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(),
+              IsBooleanNot(IsNumberEqual(p, IsNumberConstant(0))));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithString) {
+  Node* p = Parameter(Type::String());
+  Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(),
+              IsBooleanNot(
+                  IsNumberEqual(IsLoadField(AccessBuilder::ForStringLength(), p,
+                                            graph()->start(), graph()->start()),
+                                IsNumberConstant(0))));
+}
+
+
+// -----------------------------------------------------------------------------
+// BooleanNot
+
+
+TEST_F(SimplifiedOperatorReducerTest, BooleanNotWithBooleanNot) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(
+      graph()->NewNode(simplified()->BooleanNot(),
+                       graph()->NewNode(simplified()->BooleanNot(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(param0, reduction.replacement());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, BooleanNotWithFalseConstant) {
+  Reduction reduction0 =
+      Reduce(graph()->NewNode(simplified()->BooleanNot(), FalseConstant()));
+  ASSERT_TRUE(reduction0.Changed());
+  EXPECT_THAT(reduction0.replacement(), IsTrueConstant());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, BooleanNotWithTrueConstant) {
+  Reduction reduction1 =
+      Reduce(graph()->NewNode(simplified()->BooleanNot(), TrueConstant()));
+  ASSERT_TRUE(reduction1.Changed());
+  EXPECT_THAT(reduction1.replacement(), IsFalseConstant());
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeBoolToBit
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeBitToBoolWithChangeBoolToBit) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeBitToBool(),
+      graph()->NewNode(simplified()->ChangeBoolToBit(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(param0, reduction.replacement());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeBitToBoolWithZeroConstant) {
+  Reduction reduction = Reduce(
+      graph()->NewNode(simplified()->ChangeBitToBool(), Int32Constant(0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsFalseConstant());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeBitToBoolWithOneConstant) {
+  Reduction reduction = Reduce(
+      graph()->NewNode(simplified()->ChangeBitToBool(), Int32Constant(1)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsTrueConstant());
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeBoolToBit
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeBoolToBitWithFalseConstant) {
+  Reduction reduction = Reduce(
+      graph()->NewNode(simplified()->ChangeBoolToBit(), FalseConstant()));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeBoolToBitWithTrueConstant) {
+  Reduction reduction =
+      Reduce(graph()->NewNode(simplified()->ChangeBoolToBit(), TrueConstant()));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsInt32Constant(1));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeBoolToBitWithChangeBitToBool) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeBoolToBit(),
+      graph()->NewNode(simplified()->ChangeBitToBool(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(param0, reduction.replacement());
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeFloat64ToTagged
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeFloat64ToTaggedWithConstant) {
+  TRACED_FOREACH(double, n, kFloat64Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        simplified()->ChangeFloat64ToTagged(), Float64Constant(n)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsNumberConstant(BitEq(n)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeInt32ToTagged
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeInt32ToTaggedWithConstant) {
+  TRACED_FOREACH(int32_t, n, kInt32Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        simplified()->ChangeInt32ToTagged(), Int32Constant(n)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsNumberConstant(BitEq(FastI2D(n))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeTaggedToFloat64
+
+
+TEST_F(SimplifiedOperatorReducerTest,
+       ChangeTaggedToFloat64WithChangeFloat64ToTagged) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeTaggedToFloat64(),
+      graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(param0, reduction.replacement());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest,
+       ChangeTaggedToFloat64WithChangeInt32ToTagged) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeTaggedToFloat64(),
+      graph()->NewNode(simplified()->ChangeInt32ToTagged(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsChangeInt32ToFloat64(param0));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest,
+       ChangeTaggedToFloat64WithChangeUint32ToTagged) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeTaggedToFloat64(),
+      graph()->NewNode(simplified()->ChangeUint32ToTagged(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsChangeUint32ToFloat64(param0));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithConstant) {
+  TRACED_FOREACH(double, n, kFloat64Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        simplified()->ChangeTaggedToFloat64(), NumberConstant(n)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq(n)));
+  }
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithNaNConstant1) {
+  Reduction reduction =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
+                              NumberConstant(-base::OS::nan_value())));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(),
+              IsFloat64Constant(BitEq(-base::OS::nan_value())));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithNaNConstant2) {
+  Reduction reduction =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
+                              NumberConstant(base::OS::nan_value())));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(),
+              IsFloat64Constant(BitEq(base::OS::nan_value())));
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeTaggedToInt32
+
+
+TEST_F(SimplifiedOperatorReducerTest,
+       ChangeTaggedToInt32WithChangeFloat64ToTagged) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeTaggedToInt32(),
+      graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsChangeFloat64ToInt32(param0));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest,
+       ChangeTaggedToInt32WithChangeInt32ToTagged) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeTaggedToInt32(),
+      graph()->NewNode(simplified()->ChangeInt32ToTagged(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(param0, reduction.replacement());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToInt32WithConstant) {
+  TRACED_FOREACH(double, n, kFloat64Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        simplified()->ChangeTaggedToInt32(), NumberConstant(n)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsInt32Constant(DoubleToInt32(n)));
+  }
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToInt32WithNaNConstant1) {
+  Reduction reduction =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(),
+                              NumberConstant(-base::OS::nan_value())));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToInt32WithNaNConstant2) {
+  Reduction reduction =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(),
+                              NumberConstant(base::OS::nan_value())));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeTaggedToUint32
+
+
+TEST_F(SimplifiedOperatorReducerTest,
+       ChangeTaggedToUint32WithChangeFloat64ToTagged) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeTaggedToUint32(),
+      graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsChangeFloat64ToUint32(param0));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest,
+       ChangeTaggedToUint32WithChangeUint32ToTagged) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeTaggedToUint32(),
+      graph()->NewNode(simplified()->ChangeUint32ToTagged(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(param0, reduction.replacement());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToUint32WithConstant) {
+  TRACED_FOREACH(double, n, kFloat64Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        simplified()->ChangeTaggedToUint32(), NumberConstant(n)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(),
+                IsInt32Constant(bit_cast<int32_t>(DoubleToUint32(n))));
+  }
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToUint32WithNaNConstant1) {
+  Reduction reduction =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(),
+                              NumberConstant(-base::OS::nan_value())));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToUint32WithNaNConstant2) {
+  Reduction reduction =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(),
+                              NumberConstant(base::OS::nan_value())));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeUint32ToTagged
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeUint32ToTagged) {
+  TRACED_FOREACH(uint32_t, n, kUint32Values) {
+    Reduction reduction =
+        Reduce(graph()->NewNode(simplified()->ChangeUint32ToTagged(),
+                                Int32Constant(bit_cast<int32_t>(n))));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsNumberConstant(BitEq(FastUI2D(n))));
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/simplified-operator-unittest.cc b/test/unittests/compiler/simplified-operator-unittest.cc
new file mode 100644
index 0000000..bc537fd
--- /dev/null
+++ b/test/unittests/compiler/simplified-operator-unittest.cc
@@ -0,0 +1,288 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/opcodes.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/operator-properties.h"
+#include "src/compiler/simplified-operator.h"
+#include "src/types-inl.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// -----------------------------------------------------------------------------
+// Pure operators.
+
+
+namespace {
+
+struct PureOperator {
+  const Operator* (SimplifiedOperatorBuilder::*constructor)();
+  IrOpcode::Value opcode;
+  Operator::Properties properties;
+  int value_input_count;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const PureOperator& pop) {
+  return os << IrOpcode::Mnemonic(pop.opcode);
+}
+
+
+const PureOperator kPureOperators[] = {
+#define PURE(Name, properties, input_count)              \
+  {                                                      \
+    &SimplifiedOperatorBuilder::Name, IrOpcode::k##Name, \
+        Operator::kPure | properties, input_count        \
+  }
+    PURE(AnyToBoolean, Operator::kNoProperties, 1),
+    PURE(BooleanNot, Operator::kNoProperties, 1),
+    PURE(BooleanToNumber, Operator::kNoProperties, 1),
+    PURE(NumberEqual, Operator::kCommutative, 2),
+    PURE(NumberLessThan, Operator::kNoProperties, 2),
+    PURE(NumberLessThanOrEqual, Operator::kNoProperties, 2),
+    PURE(NumberAdd, Operator::kCommutative, 2),
+    PURE(NumberSubtract, Operator::kNoProperties, 2),
+    PURE(NumberMultiply, Operator::kCommutative, 2),
+    PURE(NumberDivide, Operator::kNoProperties, 2),
+    PURE(NumberModulus, Operator::kNoProperties, 2),
+    PURE(NumberToInt32, Operator::kNoProperties, 1),
+    PURE(NumberToUint32, Operator::kNoProperties, 1),
+    PURE(StringEqual, Operator::kCommutative, 2),
+    PURE(StringLessThan, Operator::kNoProperties, 2),
+    PURE(StringLessThanOrEqual, Operator::kNoProperties, 2),
+    PURE(StringAdd, Operator::kNoProperties, 2),
+    PURE(ChangeTaggedToInt32, Operator::kNoProperties, 1),
+    PURE(ChangeTaggedToUint32, Operator::kNoProperties, 1),
+    PURE(ChangeTaggedToFloat64, Operator::kNoProperties, 1),
+    PURE(ChangeInt32ToTagged, Operator::kNoProperties, 1),
+    PURE(ChangeUint32ToTagged, Operator::kNoProperties, 1),
+    PURE(ChangeFloat64ToTagged, Operator::kNoProperties, 1),
+    PURE(ChangeBoolToBit, Operator::kNoProperties, 1),
+    PURE(ChangeBitToBool, Operator::kNoProperties, 1),
+    PURE(ObjectIsSmi, Operator::kNoProperties, 1),
+    PURE(ObjectIsNonNegativeSmi, Operator::kNoProperties, 1)
+#undef PURE
+};
+
+}  // namespace
+
+
+class SimplifiedPureOperatorTest
+    : public TestWithZone,
+      public ::testing::WithParamInterface<PureOperator> {};
+
+
+TEST_P(SimplifiedPureOperatorTest, InstancesAreGloballyShared) {
+  const PureOperator& pop = GetParam();
+  SimplifiedOperatorBuilder simplified1(zone());
+  SimplifiedOperatorBuilder simplified2(zone());
+  EXPECT_EQ((simplified1.*pop.constructor)(), (simplified2.*pop.constructor)());
+}
+
+
+TEST_P(SimplifiedPureOperatorTest, NumberOfInputsAndOutputs) {
+  SimplifiedOperatorBuilder simplified(zone());
+  const PureOperator& pop = GetParam();
+  const Operator* op = (simplified.*pop.constructor)();
+
+  EXPECT_EQ(pop.value_input_count, op->ValueInputCount());
+  EXPECT_EQ(0, op->EffectInputCount());
+  EXPECT_EQ(0, op->ControlInputCount());
+  EXPECT_EQ(pop.value_input_count, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(1, op->ValueOutputCount());
+  EXPECT_EQ(0, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(SimplifiedPureOperatorTest, OpcodeIsCorrect) {
+  SimplifiedOperatorBuilder simplified(zone());
+  const PureOperator& pop = GetParam();
+  const Operator* op = (simplified.*pop.constructor)();
+  EXPECT_EQ(pop.opcode, op->opcode());
+}
+
+
+TEST_P(SimplifiedPureOperatorTest, Properties) {
+  SimplifiedOperatorBuilder simplified(zone());
+  const PureOperator& pop = GetParam();
+  const Operator* op = (simplified.*pop.constructor)();
+  EXPECT_EQ(pop.properties, op->properties() & pop.properties);
+}
+
+INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, SimplifiedPureOperatorTest,
+                        ::testing::ValuesIn(kPureOperators));
+
+
+// -----------------------------------------------------------------------------
+// Buffer access operators.
+
+
+namespace {
+
+const ExternalArrayType kExternalArrayTypes[] = {
+    kExternalUint8Array,   kExternalInt8Array,   kExternalUint16Array,
+    kExternalInt16Array,   kExternalUint32Array, kExternalInt32Array,
+    kExternalFloat32Array, kExternalFloat64Array};
+
+}  // namespace
+
+
+class SimplifiedBufferAccessOperatorTest
+    : public TestWithZone,
+      public ::testing::WithParamInterface<ExternalArrayType> {};
+
+
+TEST_P(SimplifiedBufferAccessOperatorTest, InstancesAreGloballyShared) {
+  BufferAccess const access(GetParam());
+  SimplifiedOperatorBuilder simplified1(zone());
+  SimplifiedOperatorBuilder simplified2(zone());
+  EXPECT_EQ(simplified1.LoadBuffer(access), simplified2.LoadBuffer(access));
+  EXPECT_EQ(simplified1.StoreBuffer(access), simplified2.StoreBuffer(access));
+}
+
+
+TEST_P(SimplifiedBufferAccessOperatorTest, LoadBuffer) {
+  SimplifiedOperatorBuilder simplified(zone());
+  BufferAccess const access(GetParam());
+  const Operator* op = simplified.LoadBuffer(access);
+
+  EXPECT_EQ(IrOpcode::kLoadBuffer, op->opcode());
+  EXPECT_EQ(Operator::kNoThrow | Operator::kNoWrite, op->properties());
+  EXPECT_EQ(access, BufferAccessOf(op));
+
+  EXPECT_EQ(3, op->ValueInputCount());
+  EXPECT_EQ(1, op->EffectInputCount());
+  EXPECT_EQ(1, op->ControlInputCount());
+  EXPECT_EQ(5, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(1, op->ValueOutputCount());
+  EXPECT_EQ(1, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(SimplifiedBufferAccessOperatorTest, StoreBuffer) {
+  SimplifiedOperatorBuilder simplified(zone());
+  BufferAccess const access(GetParam());
+  const Operator* op = simplified.StoreBuffer(access);
+
+  EXPECT_EQ(IrOpcode::kStoreBuffer, op->opcode());
+  EXPECT_EQ(Operator::kNoRead | Operator::kNoThrow, op->properties());
+  EXPECT_EQ(access, BufferAccessOf(op));
+
+  EXPECT_EQ(4, op->ValueInputCount());
+  EXPECT_EQ(1, op->EffectInputCount());
+  EXPECT_EQ(1, op->ControlInputCount());
+  EXPECT_EQ(6, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(0, op->ValueOutputCount());
+  EXPECT_EQ(1, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest,
+                        SimplifiedBufferAccessOperatorTest,
+                        ::testing::ValuesIn(kExternalArrayTypes));
+
+
+// -----------------------------------------------------------------------------
+// Element access operators.
+
+
+namespace {
+
+const ElementAccess kElementAccesses[] = {
+    {kTaggedBase, FixedArray::kHeaderSize, Type::Any(), kMachAnyTagged},
+    {kUntaggedBase, 0, Type::Any(), kMachInt8},
+    {kUntaggedBase, 0, Type::Any(), kMachInt16},
+    {kUntaggedBase, 0, Type::Any(), kMachInt32},
+    {kUntaggedBase, 0, Type::Any(), kMachUint8},
+    {kUntaggedBase, 0, Type::Any(), kMachUint16},
+    {kUntaggedBase, 0, Type::Any(), kMachUint32},
+    {kUntaggedBase, 0, Type::Signed32(), kMachInt8},
+    {kUntaggedBase, 0, Type::Unsigned32(), kMachUint8},
+    {kUntaggedBase, 0, Type::Signed32(), kMachInt16},
+    {kUntaggedBase, 0, Type::Unsigned32(), kMachUint16},
+    {kUntaggedBase, 0, Type::Signed32(), kMachInt32},
+    {kUntaggedBase, 0, Type::Unsigned32(), kMachUint32},
+    {kUntaggedBase, 0, Type::Number(), kRepFloat32},
+    {kUntaggedBase, 0, Type::Number(), kRepFloat64},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
+     kMachInt8},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
+     kMachUint8},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
+     kMachInt16},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
+     kMachUint16},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
+     kMachInt32},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
+     kMachUint32},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
+     kRepFloat32},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
+     kRepFloat64}};
+
+}  // namespace
+
+
+class SimplifiedElementAccessOperatorTest
+    : public TestWithZone,
+      public ::testing::WithParamInterface<ElementAccess> {};
+
+
+TEST_P(SimplifiedElementAccessOperatorTest, LoadElement) {
+  SimplifiedOperatorBuilder simplified(zone());
+  const ElementAccess& access = GetParam();
+  const Operator* op = simplified.LoadElement(access);
+
+  EXPECT_EQ(IrOpcode::kLoadElement, op->opcode());
+  EXPECT_EQ(Operator::kNoThrow | Operator::kNoWrite, op->properties());
+  EXPECT_EQ(access, ElementAccessOf(op));
+
+  EXPECT_EQ(2, op->ValueInputCount());
+  EXPECT_EQ(1, op->EffectInputCount());
+  EXPECT_EQ(1, op->ControlInputCount());
+  EXPECT_EQ(4, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(1, op->ValueOutputCount());
+  EXPECT_EQ(1, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(SimplifiedElementAccessOperatorTest, StoreElement) {
+  SimplifiedOperatorBuilder simplified(zone());
+  const ElementAccess& access = GetParam();
+  const Operator* op = simplified.StoreElement(access);
+
+  EXPECT_EQ(IrOpcode::kStoreElement, op->opcode());
+  EXPECT_EQ(Operator::kNoRead | Operator::kNoThrow, op->properties());
+  EXPECT_EQ(access, ElementAccessOf(op));
+
+  EXPECT_EQ(3, op->ValueInputCount());
+  EXPECT_EQ(1, op->EffectInputCount());
+  EXPECT_EQ(1, op->ControlInputCount());
+  EXPECT_EQ(5, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(0, op->ValueOutputCount());
+  EXPECT_EQ(1, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest,
+                        SimplifiedElementAccessOperatorTest,
+                        ::testing::ValuesIn(kElementAccesses));
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/value-numbering-reducer-unittest.cc b/test/unittests/compiler/value-numbering-reducer-unittest.cc
new file mode 100644
index 0000000..b6be0bf
--- /dev/null
+++ b/test/unittests/compiler/value-numbering-reducer-unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "src/compiler/graph.h"
+#include "src/compiler/value-numbering-reducer.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+struct TestOperator : public Operator {
+  TestOperator(Operator::Opcode opcode, Operator::Properties properties,
+               size_t value_in, size_t value_out)
+      : Operator(opcode, properties, "TestOp", value_in, 0, 0, value_out, 0,
+                 0) {}
+};
+
+
+static const TestOperator kOp0(0, Operator::kEliminatable, 0, 1);
+static const TestOperator kOp1(1, Operator::kEliminatable, 1, 1);
+
+
+class ValueNumberingReducerTest : public TestWithZone {
+ public:
+  ValueNumberingReducerTest() : graph_(zone()), reducer_(zone()) {}
+
+ protected:
+  Reduction Reduce(Node* node) { return reducer_.Reduce(node); }
+
+  Graph* graph() { return &graph_; }
+
+ private:
+  Graph graph_;
+  ValueNumberingReducer reducer_;
+};
+
+
+TEST_F(ValueNumberingReducerTest, AllInputsAreChecked) {
+  Node* na = graph()->NewNode(&kOp0);
+  Node* nb = graph()->NewNode(&kOp0);
+  Node* n1 = graph()->NewNode(&kOp0, na);
+  Node* n2 = graph()->NewNode(&kOp0, nb);
+  EXPECT_FALSE(Reduce(n1).Changed());
+  EXPECT_FALSE(Reduce(n2).Changed());
+}
+
+
+TEST_F(ValueNumberingReducerTest, DeadNodesAreNeverReturned) {
+  Node* n0 = graph()->NewNode(&kOp0);
+  Node* n1 = graph()->NewNode(&kOp1, n0);
+  EXPECT_FALSE(Reduce(n1).Changed());
+  n1->Kill();
+  EXPECT_FALSE(Reduce(graph()->NewNode(&kOp1, n0)).Changed());
+}
+
+
+TEST_F(ValueNumberingReducerTest, OnlyEliminatableNodesAreReduced) {
+  TestOperator op(0, Operator::kNoProperties, 0, 1);
+  Node* n0 = graph()->NewNode(&op);
+  Node* n1 = graph()->NewNode(&op);
+  EXPECT_FALSE(Reduce(n0).Changed());
+  EXPECT_FALSE(Reduce(n1).Changed());
+}
+
+
+TEST_F(ValueNumberingReducerTest, OperatorEqualityNotIdentity) {
+  static const size_t kMaxInputCount = 16;
+  Node* inputs[kMaxInputCount];
+  for (size_t i = 0; i < arraysize(inputs); ++i) {
+    Operator::Opcode opcode = static_cast<Operator::Opcode>(
+        std::numeric_limits<Operator::Opcode>::max() - i);
+    inputs[i] = graph()->NewNode(
+        new (zone()) TestOperator(opcode, Operator::kEliminatable, 0, 1));
+  }
+  TRACED_FORRANGE(size_t, input_count, 0, arraysize(inputs)) {
+    const TestOperator op1(static_cast<Operator::Opcode>(input_count),
+                           Operator::kEliminatable, input_count, 1);
+    Node* n1 = graph()->NewNode(&op1, static_cast<int>(input_count), inputs);
+    Reduction r1 = Reduce(n1);
+    EXPECT_FALSE(r1.Changed());
+
+    const TestOperator op2(static_cast<Operator::Opcode>(input_count),
+                           Operator::kEliminatable, input_count, 1);
+    Node* n2 = graph()->NewNode(&op2, static_cast<int>(input_count), inputs);
+    Reduction r2 = Reduce(n2);
+    EXPECT_TRUE(r2.Changed());
+    EXPECT_EQ(n1, r2.replacement());
+  }
+}
+
+
+TEST_F(ValueNumberingReducerTest, SubsequentReductionsYieldTheSameNode) {
+  static const size_t kMaxInputCount = 16;
+  Node* inputs[kMaxInputCount];
+  for (size_t i = 0; i < arraysize(inputs); ++i) {
+    Operator::Opcode opcode = static_cast<Operator::Opcode>(
+        std::numeric_limits<Operator::Opcode>::max() - i);
+    inputs[i] = graph()->NewNode(
+        new (zone()) TestOperator(opcode, Operator::kEliminatable, 0, 1));
+  }
+  TRACED_FORRANGE(size_t, input_count, 0, arraysize(inputs)) {
+    const TestOperator op1(1, Operator::kEliminatable, input_count, 1);
+    Node* n = graph()->NewNode(&op1, static_cast<int>(input_count), inputs);
+    Reduction r = Reduce(n);
+    EXPECT_FALSE(r.Changed());
+
+    r = Reduce(graph()->NewNode(&op1, static_cast<int>(input_count), inputs));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(n, r.replacement());
+
+    r = Reduce(graph()->NewNode(&op1, static_cast<int>(input_count), inputs));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(n, r.replacement());
+  }
+}
+
+
+TEST_F(ValueNumberingReducerTest, WontReplaceNodeWithItself) {
+  Node* n = graph()->NewNode(&kOp0);
+  EXPECT_FALSE(Reduce(n).Changed());
+  EXPECT_FALSE(Reduce(n).Changed());
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc b/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc
new file mode 100644
index 0000000..9ef0fa5
--- /dev/null
+++ b/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc
@@ -0,0 +1,1068 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/compiler/instruction-selector-unittest.h"
+
+#include "src/compiler/node-matchers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+
+TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) {
+  StreamBuilder m(this, kMachFloat32, kMachFloat64);
+  m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSECvtss2sd, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, ChangeInt32ToInt64WithParameter) {
+  StreamBuilder m(this, kMachInt64, kMachInt32);
+  m.Return(m.ChangeInt32ToInt64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Movsxlq, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, ChangeUint32ToFloat64WithParameter) {
+  StreamBuilder m(this, kMachFloat64, kMachUint32);
+  m.Return(m.ChangeUint32ToFloat64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSEUint32ToFloat64, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, ChangeUint32ToUint64WithParameter) {
+  StreamBuilder m(this, kMachUint64, kMachUint32);
+  m.Return(m.ChangeUint32ToUint64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat32);
+  m.Return(m.TruncateFloat64ToFloat32(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSECvtsd2ss, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachInt64);
+  m.Return(m.TruncateInt64ToInt32(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
+}
+
+
+// -----------------------------------------------------------------------------
+// Loads and stores
+
+namespace {
+
+struct MemoryAccess {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
+  return os << memacc.type;
+}
+
+
+static const MemoryAccess kMemoryAccesses[] = {
+    {kMachInt8, kX64Movsxbl, kX64Movb},
+    {kMachUint8, kX64Movzxbl, kX64Movb},
+    {kMachInt16, kX64Movsxwl, kX64Movw},
+    {kMachUint16, kX64Movzxwl, kX64Movw},
+    {kMachInt32, kX64Movl, kX64Movl},
+    {kMachUint32, kX64Movl, kX64Movl},
+    {kMachInt64, kX64Movq, kX64Movq},
+    {kMachUint64, kX64Movq, kX64Movq},
+    {kMachFloat32, kX64Movss, kX64Movss},
+    {kMachFloat64, kX64Movsd, kX64Movsd}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccess>
+    InstructionSelectorMemoryAccessTest;
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
+  m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
+  m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(0U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessTest,
+                        ::testing::ValuesIn(kMemoryAccesses));
+
+// -----------------------------------------------------------------------------
+// ChangeUint32ToUint64.
+
+
+namespace {
+
+typedef Node* (RawMachineAssembler::*Constructor)(Node*, Node*);
+
+
+struct BinaryOperation {
+  Constructor constructor;
+  const char* constructor_name;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const BinaryOperation& bop) {
+  return os << bop.constructor_name;
+}
+
+
+const BinaryOperation kWord32BinaryOperations[] = {
+    {&RawMachineAssembler::Word32And, "Word32And"},
+    {&RawMachineAssembler::Word32Or, "Word32Or"},
+    {&RawMachineAssembler::Word32Xor, "Word32Xor"},
+    {&RawMachineAssembler::Word32Shl, "Word32Shl"},
+    {&RawMachineAssembler::Word32Shr, "Word32Shr"},
+    {&RawMachineAssembler::Word32Sar, "Word32Sar"},
+    {&RawMachineAssembler::Word32Ror, "Word32Ror"},
+    {&RawMachineAssembler::Word32Equal, "Word32Equal"},
+    {&RawMachineAssembler::Int32Add, "Int32Add"},
+    {&RawMachineAssembler::Int32Sub, "Int32Sub"},
+    {&RawMachineAssembler::Int32Mul, "Int32Mul"},
+    {&RawMachineAssembler::Int32MulHigh, "Int32MulHigh"},
+    {&RawMachineAssembler::Int32Div, "Int32Div"},
+    {&RawMachineAssembler::Int32LessThan, "Int32LessThan"},
+    {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual"},
+    {&RawMachineAssembler::Int32Mod, "Int32Mod"},
+    {&RawMachineAssembler::Uint32Div, "Uint32Div"},
+    {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan"},
+    {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual"},
+    {&RawMachineAssembler::Uint32Mod, "Uint32Mod"}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<BinaryOperation>
+    InstructionSelectorChangeUint32ToUint64Test;
+
+
+TEST_P(InstructionSelectorChangeUint32ToUint64Test, ChangeUint32ToUint64) {
+  const BinaryOperation& bop = GetParam();
+  StreamBuilder m(this, kMachUint64, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  m.Return(m.ChangeUint32ToUint64((m.*bop.constructor)(p0, p1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorChangeUint32ToUint64Test,
+                        ::testing::ValuesIn(kWord32BinaryOperations));
+
+
+// -----------------------------------------------------------------------------
+// TruncateInt64ToInt32.
+
+
+TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Sar) {
+  StreamBuilder m(this, kMachInt32, kMachInt64);
+  Node* const p = m.Parameter(0);
+  Node* const t = m.TruncateInt64ToInt32(m.Word64Sar(p, m.Int64Constant(32)));
+  m.Return(t);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Shr, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(32, s.ToInt32(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0)));
+  EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Shr) {
+  StreamBuilder m(this, kMachInt32, kMachInt64);
+  Node* const p = m.Parameter(0);
+  Node* const t = m.TruncateInt64ToInt32(m.Word64Shr(p, m.Int64Constant(32)));
+  m.Return(t);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Shr, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(32, s.ToInt32(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0)));
+  EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Addition.
+
+
+TEST_F(InstructionSelectorTest, Int32AddWithInt32ParametersLea) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const a0 = m.Int32Add(p0, p1);
+  // Additional uses of input to add chooses lea
+  Node* const a1 = m.Int32Div(p0, p1);
+  m.Return(m.Int32Div(a0, a1));
+  Stream s = m.Build();
+  ASSERT_EQ(3U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddConstantAsLeaSingle) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c0 = m.Int32Constant(15);
+  // If one of the add's operands is only used once, use an "leal", even though
+  // an "addl" could be used. The "leal" has proven faster--out best guess is
+  // that it gives the register allocation more freedom and it doesn't set
+  // flags, reducing pressure in the CPU's pipeline. If we're lucky with
+  // register allocation, then code generation will select an "addl" later for
+  // the cases that have been measured to be faster.
+  Node* const v0 = m.Int32Add(p0, c0);
+  m.Return(v0);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddConstantAsAdd) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c0 = m.Int32Constant(1);
+  // If there is only a single use of an add's input and the immediate constant
+  // for the add is 1, don't use an inc. It is much slower on modern Intel
+  // architectures.
+  m.Return(m.Int32Add(p0, c0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddConstantAsLeaDouble) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c0 = m.Int32Constant(15);
+  // A second use of an add's input uses lea
+  Node* const a0 = m.Int32Add(p0, c0);
+  m.Return(m.Int32Div(a0, p0));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddCommutedConstantAsLeaSingle) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c0 = m.Int32Constant(15);
+  // If one of the add's operands is only used once, use an "leal", even though
+  // an "addl" could be used. The "leal" has proven faster--out best guess is
+  // that it gives the register allocation more freedom and it doesn't set
+  // flags, reducing pressure in the CPU's pipeline. If we're lucky with
+  // register allocation, then code generation will select an "addl" later for
+  // the cases that have been measured to be faster.
+  m.Return(m.Int32Add(c0, p0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddCommutedConstantAsLeaDouble) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c0 = m.Int32Constant(15);
+  // A second use of an add's input uses lea
+  Node* const a0 = m.Int32Add(c0, p0);
+  USE(a0);
+  m.Return(m.Int32Div(a0, p0));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddSimpleAsAdd) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  // If one of the add's operands is only used once, use an "leal", even though
+  // an "addl" could be used. The "leal" has proven faster--out best guess is
+  // that it gives the register allocation more freedom and it doesn't set
+  // flags, reducing pressure in the CPU's pipeline. If we're lucky with
+  // register allocation, then code generation will select an "addl" later for
+  // the cases that have been measured to be faster.
+  m.Return(m.Int32Add(p0, p1));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddSimpleAsLea) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  // If all of of the add's operands are used multiple times, use an "leal".
+  Node* const v1 = m.Int32Add(p0, p1);
+  m.Return(m.Int32Add(m.Int32Add(v1, p1), p0));
+  Stream s = m.Build();
+  ASSERT_EQ(3U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2Mul) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  m.Return(m.Int32Add(p0, s0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddCommutedScaled2Mul) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  m.Return(m.Int32Add(s0, p0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2Shl) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1));
+  m.Return(m.Int32Add(p0, s0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddCommutedScaled2Shl) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1));
+  m.Return(m.Int32Add(s0, p0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled4Mul) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(4));
+  m.Return(m.Int32Add(p0, s0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR4, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled4Shl) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Word32Shl(p1, m.Int32Constant(2));
+  m.Return(m.Int32Add(p0, s0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR4, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled8Mul) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(8));
+  m.Return(m.Int32Add(p0, s0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR8, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled8Shl) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Word32Shl(p1, m.Int32Constant(3));
+  m.Return(m.Int32Add(p0, s0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR8, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstant) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle1) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(p0, m.Int32Add(s0, c0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle2) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(s0, m.Int32Add(c0, p0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle3) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(m.Int32Add(s0, c0), p0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle4) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(m.Int32Add(c0, p0), s0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle5) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(m.Int32Add(p0, s0), c0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2ShlWithConstant) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled4MulWithConstant) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(4));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR4I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled4ShlWithConstant) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Word32Shl(p1, m.Int32Constant(2));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR4I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled8MulWithConstant) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(8));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR8I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled8ShlWithConstant) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Word32Shl(p1, m.Int32Constant(3));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR8I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32SubConstantAsSub) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c0 = m.Int32Constant(-1);
+  // If there is only a single use of on of the sub's non-constant input, use a
+  // "subl" instruction.
+  m.Return(m.Int32Sub(p0, c0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32SubConstantAsLea) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c0 = m.Int32Constant(-1);
+  // If there are multiple uses of on of the sub's non-constant input, use a
+  // "leal" instruction.
+  Node* const v0 = m.Int32Sub(p0, c0);
+  m.Return(m.Int32Div(p0, v0));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2Other) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const p2 = m.Parameter(2);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  Node* const a0 = m.Int32Add(s0, p2);
+  Node* const a1 = m.Int32Add(p0, a0);
+  m.Return(a1);
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[0]->OutputAt(0)));
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(kX64Lea32, s[1]->arch_opcode());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[1]->InputAt(1)));
+  EXPECT_EQ(s.ToVreg(a1), s.ToVreg(s[1]->OutputAt(0)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Multiplication.
+
+
+TEST_F(InstructionSelectorTest, Int32MulWithInt32MulWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const m0 = m.Int32Mul(p0, p1);
+  m.Return(m.Int32Mul(m0, p0));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kX64Imul32, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(m0), s.ToVreg(s[0]->OutputAt(0)));
+  EXPECT_EQ(kX64Imul32, s[1]->arch_opcode());
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(m0), s.ToVreg(s[1]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32MulHigh) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Int32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64ImulHigh32, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
+  ASSERT_LE(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx));
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32MulHigh) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Uint32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64UmulHigh32, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
+  ASSERT_LE(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul2BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(2);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul3BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(3);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul4BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(4);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_M4, s[0]->addressing_mode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul5BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(5);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR4, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul8BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(8);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_M8, s[0]->addressing_mode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul9BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(9);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR8, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Word32Shl.
+
+
+TEST_F(InstructionSelectorTest, Int32Shl1BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(1);
+  Node* const n = m.Word32Shl(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Shl2BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(2);
+  Node* const n = m.Word32Shl(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_M4, s[0]->addressing_mode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Shl4BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(3);
+  Node* const n = m.Word32Shl(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_M8, s[0]->addressing_mode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Word64Shl.
+
+
+TEST_F(InstructionSelectorTest, Word64ShlWithChangeInt32ToInt64) {
+  TRACED_FORRANGE(int64_t, x, 32, 63) {
+    StreamBuilder m(this, kMachInt64, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const n = m.Word64Shl(m.ChangeInt32ToInt64(p0), m.Int64Constant(x));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kX64Shl, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(x, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output()));
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64ShlWithChangeUint32ToUint64) {
+  TRACED_FORRANGE(int64_t, x, 32, 63) {
+    StreamBuilder m(this, kMachInt64, kMachUint32);
+    Node* const p0 = m.Parameter(0);
+    Node* const n = m.Word64Shl(m.ChangeUint32ToUint64(p0), m.Int64Constant(x));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kX64Shl, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(x, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output()));
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Float64BinopArithmetic) {
+  {
+    StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64);
+    Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1));
+    Node* mul = m.Float64Mul(add, m.Parameter(1));
+    Node* sub = m.Float64Sub(mul, add);
+    Node* ret = m.Float64Div(mul, sub);
+    m.Return(ret);
+    Stream s = m.Build(AVX);
+    ASSERT_EQ(4U, s.size());
+    EXPECT_EQ(kAVXFloat64Add, s[0]->arch_opcode());
+    EXPECT_EQ(kAVXFloat64Mul, s[1]->arch_opcode());
+    EXPECT_EQ(kAVXFloat64Sub, s[2]->arch_opcode());
+    EXPECT_EQ(kAVXFloat64Div, s[3]->arch_opcode());
+  }
+  {
+    StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64);
+    Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1));
+    Node* mul = m.Float64Mul(add, m.Parameter(1));
+    Node* sub = m.Float64Sub(mul, add);
+    Node* ret = m.Float64Div(mul, sub);
+    m.Return(ret);
+    Stream s = m.Build();
+    ASSERT_EQ(4U, s.size());
+    EXPECT_EQ(kSSEFloat64Add, s[0]->arch_opcode());
+    EXPECT_EQ(kSSEFloat64Mul, s[1]->arch_opcode());
+    EXPECT_EQ(kSSEFloat64Sub, s[2]->arch_opcode());
+    EXPECT_EQ(kSSEFloat64Div, s[3]->arch_opcode());
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/zone-pool-unittest.cc b/test/unittests/compiler/zone-pool-unittest.cc
new file mode 100644
index 0000000..e23557a
--- /dev/null
+++ b/test/unittests/compiler/zone-pool-unittest.cc
@@ -0,0 +1,162 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/utils/random-number-generator.h"
+#include "src/compiler/zone-pool.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class ZonePoolTest : public TestWithIsolate {
+ public:
+  ZonePoolTest() : zone_pool_(isolate()) {}
+
+ protected:
+  ZonePool* zone_pool() { return &zone_pool_; }
+
+  void ExpectForPool(size_t current, size_t max, size_t total) {
+    ASSERT_EQ(current, zone_pool()->GetCurrentAllocatedBytes());
+    ASSERT_EQ(max, zone_pool()->GetMaxAllocatedBytes());
+    ASSERT_EQ(total, zone_pool()->GetTotalAllocatedBytes());
+  }
+
+  void Expect(ZonePool::StatsScope* stats, size_t current, size_t max,
+              size_t total) {
+    ASSERT_EQ(current, stats->GetCurrentAllocatedBytes());
+    ASSERT_EQ(max, stats->GetMaxAllocatedBytes());
+    ASSERT_EQ(total, stats->GetTotalAllocatedBytes());
+  }
+
+  size_t Allocate(Zone* zone) {
+    size_t bytes = rng.NextInt(25) + 7;
+    int size_before = zone->allocation_size();
+    zone->New(static_cast<int>(bytes));
+    return static_cast<size_t>(zone->allocation_size() - size_before);
+  }
+
+ private:
+  ZonePool zone_pool_;
+  base::RandomNumberGenerator rng;
+};
+
+
+TEST_F(ZonePoolTest, Empty) {
+  ExpectForPool(0, 0, 0);
+  {
+    ZonePool::StatsScope stats(zone_pool());
+    Expect(&stats, 0, 0, 0);
+  }
+  ExpectForPool(0, 0, 0);
+  {
+    ZonePool::Scope scope(zone_pool());
+    scope.zone();
+  }
+  ExpectForPool(0, 0, 0);
+}
+
+
+TEST_F(ZonePoolTest, MultipleZonesWithDeletion) {
+  static const size_t kArraySize = 10;
+
+  ZonePool::Scope* scopes[kArraySize];
+
+  // Initialize.
+  size_t before_stats = 0;
+  for (size_t i = 0; i < kArraySize; ++i) {
+    scopes[i] = new ZonePool::Scope(zone_pool());
+    before_stats += Allocate(scopes[i]->zone());  // Add some stuff.
+  }
+
+  ExpectForPool(before_stats, before_stats, before_stats);
+
+  ZonePool::StatsScope stats(zone_pool());
+
+  size_t before_deletion = 0;
+  for (size_t i = 0; i < kArraySize; ++i) {
+    before_deletion += Allocate(scopes[i]->zone());  // Add some stuff.
+  }
+
+  Expect(&stats, before_deletion, before_deletion, before_deletion);
+  ExpectForPool(before_stats + before_deletion, before_stats + before_deletion,
+                before_stats + before_deletion);
+
+  // Delete the scopes and create new ones.
+  for (size_t i = 0; i < kArraySize; ++i) {
+    delete scopes[i];
+    scopes[i] = new ZonePool::Scope(zone_pool());
+  }
+
+  Expect(&stats, 0, before_deletion, before_deletion);
+  ExpectForPool(0, before_stats + before_deletion,
+                before_stats + before_deletion);
+
+  size_t after_deletion = 0;
+  for (size_t i = 0; i < kArraySize; ++i) {
+    after_deletion += Allocate(scopes[i]->zone());  // Add some stuff.
+  }
+
+  Expect(&stats, after_deletion, std::max(after_deletion, before_deletion),
+         before_deletion + after_deletion);
+  ExpectForPool(after_deletion,
+                std::max(after_deletion, before_stats + before_deletion),
+                before_stats + before_deletion + after_deletion);
+
+  // Cleanup.
+  for (size_t i = 0; i < kArraySize; ++i) {
+    delete scopes[i];
+  }
+
+  Expect(&stats, 0, std::max(after_deletion, before_deletion),
+         before_deletion + after_deletion);
+  ExpectForPool(0, std::max(after_deletion, before_stats + before_deletion),
+                before_stats + before_deletion + after_deletion);
+}
+
+
+TEST_F(ZonePoolTest, SimpleAllocationLoop) {
+  int runs = 20;
+  size_t total_allocated = 0;
+  size_t max_loop_allocation = 0;
+  ZonePool::StatsScope outer_stats(zone_pool());
+  {
+    ZonePool::Scope outer_scope(zone_pool());
+    size_t outer_allocated = 0;
+    for (int i = 0; i < runs; ++i) {
+      {
+        size_t bytes = Allocate(outer_scope.zone());
+        outer_allocated += bytes;
+        total_allocated += bytes;
+      }
+      ZonePool::StatsScope inner_stats(zone_pool());
+      size_t allocated = 0;
+      {
+        ZonePool::Scope inner_scope(zone_pool());
+        for (int j = 0; j < 20; ++j) {
+          size_t bytes = Allocate(inner_scope.zone());
+          allocated += bytes;
+          total_allocated += bytes;
+          max_loop_allocation =
+              std::max(max_loop_allocation, outer_allocated + allocated);
+          Expect(&inner_stats, allocated, allocated, allocated);
+          Expect(&outer_stats, outer_allocated + allocated, max_loop_allocation,
+                 total_allocated);
+          ExpectForPool(outer_allocated + allocated, max_loop_allocation,
+                        total_allocated);
+        }
+      }
+      Expect(&inner_stats, 0, allocated, allocated);
+      Expect(&outer_stats, outer_allocated, max_loop_allocation,
+             total_allocated);
+      ExpectForPool(outer_allocated, max_loop_allocation, total_allocated);
+    }
+  }
+  Expect(&outer_stats, 0, max_loop_allocation, total_allocated);
+  ExpectForPool(0, max_loop_allocation, total_allocated);
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/heap/gc-idle-time-handler-unittest.cc b/test/unittests/heap/gc-idle-time-handler-unittest.cc
new file mode 100644
index 0000000..2076e60
--- /dev/null
+++ b/test/unittests/heap/gc-idle-time-handler-unittest.cc
@@ -0,0 +1,444 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "src/heap/gc-idle-time-handler.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+class GCIdleTimeHandlerTest : public ::testing::Test {
+ public:
+  GCIdleTimeHandlerTest() {}
+  virtual ~GCIdleTimeHandlerTest() {}
+
+  GCIdleTimeHandler* handler() { return &handler_; }
+
+  GCIdleTimeHandler::HeapState DefaultHeapState() {
+    GCIdleTimeHandler::HeapState result;
+    result.contexts_disposed = 0;
+    result.contexts_disposal_rate = GCIdleTimeHandler::kHighContextDisposalRate;
+    result.size_of_objects = kSizeOfObjects;
+    result.incremental_marking_stopped = false;
+    result.can_start_incremental_marking = true;
+    result.sweeping_in_progress = false;
+    result.mark_compact_speed_in_bytes_per_ms = kMarkCompactSpeed;
+    result.incremental_marking_speed_in_bytes_per_ms = kMarkingSpeed;
+    result.scavenge_speed_in_bytes_per_ms = kScavengeSpeed;
+    result.used_new_space_size = 0;
+    result.new_space_capacity = kNewSpaceCapacity;
+    result.new_space_allocation_throughput_in_bytes_per_ms =
+        kNewSpaceAllocationThroughput;
+    return result;
+  }
+
+  static const size_t kSizeOfObjects = 100 * MB;
+  static const size_t kMarkCompactSpeed = 200 * KB;
+  static const size_t kMarkingSpeed = 200 * KB;
+  static const size_t kScavengeSpeed = 100 * KB;
+  static const size_t kNewSpaceCapacity = 1 * MB;
+  static const size_t kNewSpaceAllocationThroughput = 10 * KB;
+
+ private:
+  GCIdleTimeHandler handler_;
+};
+
+}  // namespace
+
+
+TEST(GCIdleTimeHandler, EstimateMarkingStepSizeInitial) {
+  size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(1, 0);
+  EXPECT_EQ(
+      static_cast<size_t>(GCIdleTimeHandler::kInitialConservativeMarkingSpeed *
+                          GCIdleTimeHandler::kConservativeTimeRatio),
+      step_size);
+}
+
+
+TEST(GCIdleTimeHandler, EstimateMarkingStepSizeNonZero) {
+  size_t marking_speed_in_bytes_per_millisecond = 100;
+  size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
+      1, marking_speed_in_bytes_per_millisecond);
+  EXPECT_EQ(static_cast<size_t>(marking_speed_in_bytes_per_millisecond *
+                                GCIdleTimeHandler::kConservativeTimeRatio),
+            step_size);
+}
+
+
+TEST(GCIdleTimeHandler, EstimateMarkingStepSizeOverflow1) {
+  size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
+      10, std::numeric_limits<size_t>::max());
+  EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize),
+            step_size);
+}
+
+
+TEST(GCIdleTimeHandler, EstimateMarkingStepSizeOverflow2) {
+  size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
+      std::numeric_limits<size_t>::max(), 10);
+  EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize),
+            step_size);
+}
+
+
+TEST(GCIdleTimeHandler, EstimateMarkCompactTimeInitial) {
+  size_t size = 100 * MB;
+  size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, 0);
+  EXPECT_EQ(size / GCIdleTimeHandler::kInitialConservativeMarkCompactSpeed,
+            time);
+}
+
+
+TEST(GCIdleTimeHandler, EstimateMarkCompactTimeNonZero) {
+  size_t size = 100 * MB;
+  size_t speed = 1 * MB;
+  size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, speed);
+  EXPECT_EQ(size / speed, time);
+}
+
+
+TEST(GCIdleTimeHandler, EstimateMarkCompactTimeMax) {
+  size_t size = std::numeric_limits<size_t>::max();
+  size_t speed = 1;
+  size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, speed);
+  EXPECT_EQ(GCIdleTimeHandler::kMaxMarkCompactTimeInMs, time);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DoScavengeEmptyNewSpace) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  int idle_time_in_ms = 16;
+  EXPECT_FALSE(GCIdleTimeHandler::ShouldDoScavenge(
+      idle_time_in_ms, heap_state.new_space_capacity,
+      heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
+      heap_state.new_space_allocation_throughput_in_bytes_per_ms));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DoScavengeFullNewSpace) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.used_new_space_size = kNewSpaceCapacity;
+  int idle_time_in_ms = 16;
+  EXPECT_TRUE(GCIdleTimeHandler::ShouldDoScavenge(
+      idle_time_in_ms, heap_state.new_space_capacity,
+      heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
+      heap_state.new_space_allocation_throughput_in_bytes_per_ms));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DoScavengeUnknownScavengeSpeed) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.used_new_space_size = kNewSpaceCapacity;
+  heap_state.scavenge_speed_in_bytes_per_ms = 0;
+  int idle_time_in_ms = 16;
+  EXPECT_FALSE(GCIdleTimeHandler::ShouldDoScavenge(
+      idle_time_in_ms, heap_state.new_space_capacity,
+      heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
+      heap_state.new_space_allocation_throughput_in_bytes_per_ms));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DoScavengeLowScavengeSpeed) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.used_new_space_size = kNewSpaceCapacity;
+  heap_state.scavenge_speed_in_bytes_per_ms = 1 * KB;
+  int idle_time_in_ms = 16;
+  EXPECT_FALSE(GCIdleTimeHandler::ShouldDoScavenge(
+      idle_time_in_ms, heap_state.new_space_capacity,
+      heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
+      heap_state.new_space_allocation_throughput_in_bytes_per_ms));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DoScavengeHighScavengeSpeed) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.used_new_space_size = kNewSpaceCapacity;
+  heap_state.scavenge_speed_in_bytes_per_ms = kNewSpaceCapacity;
+  int idle_time_in_ms = 16;
+  EXPECT_TRUE(GCIdleTimeHandler::ShouldDoScavenge(
+      idle_time_in_ms, heap_state.new_space_capacity,
+      heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
+      heap_state.new_space_allocation_throughput_in_bytes_per_ms));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ShouldDoMarkCompact) {
+  size_t idle_time_in_ms = 16;
+  EXPECT_TRUE(GCIdleTimeHandler::ShouldDoMarkCompact(idle_time_in_ms, 0, 0));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DontDoMarkCompact) {
+  size_t idle_time_in_ms = 1;
+  EXPECT_FALSE(GCIdleTimeHandler::ShouldDoMarkCompact(
+      idle_time_in_ms, kSizeOfObjects, kMarkingSpeed));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ShouldDoFinalIncrementalMarkCompact) {
+  size_t idle_time_in_ms = 16;
+  EXPECT_TRUE(GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact(
+      idle_time_in_ms, 0, 0));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DontDoFinalIncrementalMarkCompact) {
+  size_t idle_time_in_ms = 1;
+  EXPECT_FALSE(GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact(
+      idle_time_in_ms, kSizeOfObjects, kMarkingSpeed));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ContextDisposeLowRate) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.contexts_disposed = 1;
+  heap_state.incremental_marking_stopped = true;
+  double idle_time_ms = 0;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_NOTHING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ContextDisposeHighRate) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.contexts_disposed = 1;
+  heap_state.contexts_disposal_rate =
+      GCIdleTimeHandler::kHighContextDisposalRate - 1;
+  heap_state.incremental_marking_stopped = true;
+  double idle_time_ms = 0;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_FULL_GC, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeLargeIdleTime) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.contexts_disposed = 1;
+  heap_state.contexts_disposal_rate = 1.0;
+  heap_state.incremental_marking_stopped = true;
+  heap_state.can_start_incremental_marking = false;
+  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
+  double idle_time_ms =
+      static_cast<double>((heap_state.size_of_objects + speed - 1) / speed);
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_FULL_GC, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeZeroIdleTime) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.contexts_disposed = 1;
+  heap_state.contexts_disposal_rate = 1.0;
+  heap_state.incremental_marking_stopped = true;
+  double idle_time_ms = 0;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_FULL_GC, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.contexts_disposed = 1;
+  heap_state.contexts_disposal_rate = 1.0;
+  heap_state.incremental_marking_stopped = true;
+  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
+  double idle_time_ms =
+      static_cast<double>(heap_state.size_of_objects / speed - 1);
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.contexts_disposed = 1;
+  heap_state.contexts_disposal_rate = 1.0;
+  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
+  double idle_time_ms =
+      static_cast<double>(heap_state.size_of_objects / speed - 1);
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms;
+  double idle_time_ms = 10;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+  EXPECT_GT(speed * static_cast<size_t>(idle_time_ms),
+            static_cast<size_t>(action.parameter));
+  EXPECT_LT(0, action.parameter);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, IncrementalMarking2) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.incremental_marking_stopped = true;
+  size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms;
+  double idle_time_ms = 10;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+  EXPECT_GT(speed * static_cast<size_t>(idle_time_ms),
+            static_cast<size_t>(action.parameter));
+  EXPECT_LT(0, action.parameter);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.incremental_marking_stopped = true;
+  heap_state.can_start_incremental_marking = false;
+  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
+  double idle_time_ms =
+      static_cast<double>(heap_state.size_of_objects / speed - 1);
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_NOTHING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, StopEventually1) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.incremental_marking_stopped = true;
+  heap_state.can_start_incremental_marking = false;
+  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
+  double idle_time_ms =
+      static_cast<double>(heap_state.size_of_objects / speed + 1);
+  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
+    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+    EXPECT_EQ(DO_FULL_GC, action.type);
+    handler()->NotifyIdleMarkCompact();
+  }
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DONE, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, StopEventually2) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  double idle_time_ms = 10;
+  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
+    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+    EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+    // In this case we emulate incremental marking steps that finish with a
+    // full gc.
+    handler()->NotifyIdleMarkCompact();
+  }
+  heap_state.can_start_incremental_marking = false;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DONE, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop1) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.incremental_marking_stopped = true;
+  heap_state.can_start_incremental_marking = false;
+  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
+  double idle_time_ms =
+      static_cast<double>(heap_state.size_of_objects / speed + 1);
+  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
+    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+    EXPECT_EQ(DO_FULL_GC, action.type);
+    handler()->NotifyIdleMarkCompact();
+  }
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DONE, action.type);
+  // Emulate mutator work.
+  for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
+    handler()->NotifyScavenge();
+  }
+  action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_FULL_GC, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop2) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  double idle_time_ms = 10;
+  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
+    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+    if (action.type == DONE) break;
+    EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+    // In this case we try to emulate incremental marking steps the finish with
+    // a full gc.
+    handler()->NotifyIdleMarkCompact();
+  }
+  heap_state.can_start_incremental_marking = false;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DONE, action.type);
+  // Emulate mutator work.
+  for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
+    handler()->NotifyScavenge();
+  }
+  heap_state.can_start_incremental_marking = true;
+  action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, Scavenge) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  int idle_time_ms = 10;
+  heap_state.used_new_space_size =
+      heap_state.new_space_capacity -
+      (kNewSpaceAllocationThroughput * idle_time_ms);
+  GCIdleTimeAction action =
+      handler()->Compute(static_cast<double>(idle_time_ms), heap_state);
+  EXPECT_EQ(DO_SCAVENGE, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ScavengeAndDone) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  int idle_time_ms = 10;
+  heap_state.can_start_incremental_marking = false;
+  heap_state.incremental_marking_stopped = true;
+  heap_state.used_new_space_size =
+      heap_state.new_space_capacity -
+      (kNewSpaceAllocationThroughput * idle_time_ms);
+  GCIdleTimeAction action =
+      handler()->Compute(static_cast<double>(idle_time_ms), heap_state);
+  EXPECT_EQ(DO_SCAVENGE, action.type);
+  heap_state.used_new_space_size = 0;
+  action = handler()->Compute(static_cast<double>(idle_time_ms), heap_state);
+  EXPECT_EQ(DO_NOTHING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeNothingToDo) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  double idle_time_ms = 0;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_NOTHING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeDoNothingButStartIdleRound) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  double idle_time_ms = 10;
+  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
+    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+    if (action.type == DONE) break;
+    EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+    // In this case we try to emulate incremental marking steps the finish with
+    // a full gc.
+    handler()->NotifyIdleMarkCompact();
+  }
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  // Emulate mutator work.
+  for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
+    handler()->NotifyScavenge();
+  }
+  action = handler()->Compute(0, heap_state);
+  EXPECT_EQ(DO_NOTHING, action.type);
+}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/libplatform/default-platform-unittest.cc b/test/unittests/libplatform/default-platform-unittest.cc
similarity index 100%
rename from src/libplatform/default-platform-unittest.cc
rename to test/unittests/libplatform/default-platform-unittest.cc
diff --git a/src/libplatform/task-queue-unittest.cc b/test/unittests/libplatform/task-queue-unittest.cc
similarity index 100%
rename from src/libplatform/task-queue-unittest.cc
rename to test/unittests/libplatform/task-queue-unittest.cc
diff --git a/src/libplatform/worker-thread-unittest.cc b/test/unittests/libplatform/worker-thread-unittest.cc
similarity index 100%
rename from src/libplatform/worker-thread-unittest.cc
rename to test/unittests/libplatform/worker-thread-unittest.cc
diff --git a/src/test/run-all-unittests.cc b/test/unittests/run-all-unittests.cc
similarity index 100%
rename from src/test/run-all-unittests.cc
rename to test/unittests/run-all-unittests.cc
diff --git a/test/unittests/test-utils.cc b/test/unittests/test-utils.cc
new file mode 100644
index 0000000..31d724a
--- /dev/null
+++ b/test/unittests/test-utils.cc
@@ -0,0 +1,109 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/test-utils.h"
+
+#include "src/base/platform/time.h"
+#include "src/flags.h"
+#include "src/isolate-inl.h"
+
+namespace v8 {
+
+std::ostream& operator<<(std::ostream& os, ExternalArrayType type) {
+  switch (type) {
+    case kExternalInt8Array:
+      return os << "ExternalInt8Array";
+    case kExternalUint8Array:
+      return os << "ExternalUint8Array";
+    case kExternalInt16Array:
+      return os << "ExternalInt16Array";
+    case kExternalUint16Array:
+      return os << "ExternalUint16Array";
+    case kExternalInt32Array:
+      return os << "ExternalInt32Array";
+    case kExternalUint32Array:
+      return os << "ExternalUint32Array";
+    case kExternalFloat32Array:
+      return os << "ExternalFloat32Array";
+    case kExternalFloat64Array:
+      return os << "ExternalFloat64Array";
+    case kExternalUint8ClampedArray:
+      return os << "ExternalUint8ClampedArray";
+  }
+  UNREACHABLE();
+  return os;
+}
+
+
+// static
+Isolate* TestWithIsolate::isolate_ = NULL;
+
+
+TestWithIsolate::TestWithIsolate()
+    : isolate_scope_(isolate()), handle_scope_(isolate()) {}
+
+
+TestWithIsolate::~TestWithIsolate() {}
+
+
+// static
+void TestWithIsolate::SetUpTestCase() {
+  Test::SetUpTestCase();
+  EXPECT_EQ(NULL, isolate_);
+  isolate_ = v8::Isolate::New();
+  EXPECT_TRUE(isolate_ != NULL);
+}
+
+
+// static
+void TestWithIsolate::TearDownTestCase() {
+  ASSERT_TRUE(isolate_ != NULL);
+  isolate_->Dispose();
+  isolate_ = NULL;
+  Test::TearDownTestCase();
+}
+
+
+TestWithContext::TestWithContext()
+    : context_(Context::New(isolate())), context_scope_(context_) {}
+
+
+TestWithContext::~TestWithContext() {}
+
+
+namespace base {
+namespace {
+
+inline int64_t GetRandomSeedFromFlag(int random_seed) {
+  return random_seed ? random_seed : TimeTicks::Now().ToInternalValue();
+}
+
+}  // namespace
+
+TestWithRandomNumberGenerator::TestWithRandomNumberGenerator()
+    : rng_(GetRandomSeedFromFlag(internal::FLAG_random_seed)) {}
+
+
+TestWithRandomNumberGenerator::~TestWithRandomNumberGenerator() {}
+
+}  // namespace base
+
+
+namespace internal {
+
+TestWithIsolate::~TestWithIsolate() {}
+
+
+Factory* TestWithIsolate::factory() const { return isolate()->factory(); }
+
+
+base::RandomNumberGenerator* TestWithIsolate::random_number_generator() const {
+  return isolate()->random_number_generator();
+}
+
+
+TestWithZone::~TestWithZone() {}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/test-utils.h b/test/unittests/test-utils.h
new file mode 100644
index 0000000..511e357
--- /dev/null
+++ b/test/unittests/test-utils.h
@@ -0,0 +1,109 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UNITTESTS_TEST_UTILS_H_
+#define V8_UNITTESTS_TEST_UTILS_H_
+
+#include "include/v8.h"
+#include "src/base/macros.h"
+#include "src/base/utils/random-number-generator.h"
+#include "src/zone.h"
+#include "testing/gtest-support.h"
+
+namespace v8 {
+
+std::ostream& operator<<(std::ostream&, ExternalArrayType);
+
+
+class TestWithIsolate : public ::testing::Test {
+ public:
+  TestWithIsolate();
+  virtual ~TestWithIsolate();
+
+  Isolate* isolate() const { return isolate_; }
+
+  static void SetUpTestCase();
+  static void TearDownTestCase();
+
+ private:
+  static Isolate* isolate_;
+  Isolate::Scope isolate_scope_;
+  HandleScope handle_scope_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestWithIsolate);
+};
+
+
+class TestWithContext : public virtual TestWithIsolate {
+ public:
+  TestWithContext();
+  virtual ~TestWithContext();
+
+  const Local<Context>& context() const { return context_; }
+
+ private:
+  Local<Context> context_;
+  Context::Scope context_scope_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestWithContext);
+};
+
+
+namespace base {
+
+class TestWithRandomNumberGenerator : public ::testing::Test {
+ public:
+  TestWithRandomNumberGenerator();
+  virtual ~TestWithRandomNumberGenerator();
+
+  RandomNumberGenerator* rng() { return &rng_; }
+
+ private:
+  RandomNumberGenerator rng_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestWithRandomNumberGenerator);
+};
+
+}  // namespace base
+
+
+namespace internal {
+
+// Forward declarations.
+class Factory;
+
+
+class TestWithIsolate : public virtual ::v8::TestWithIsolate {
+ public:
+  TestWithIsolate() {}
+  virtual ~TestWithIsolate();
+
+  Factory* factory() const;
+  Isolate* isolate() const {
+    return reinterpret_cast<Isolate*>(::v8::TestWithIsolate::isolate());
+  }
+  base::RandomNumberGenerator* random_number_generator() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestWithIsolate);
+};
+
+
+class TestWithZone : public TestWithIsolate {
+ public:
+  TestWithZone() : zone_(isolate()) {}
+  virtual ~TestWithZone();
+
+  Zone* zone() { return &zone_; }
+
+ private:
+  Zone zone_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestWithZone);
+};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_UNITTESTS_TEST_UTILS_H_
diff --git a/test/unittests/unittests.gyp b/test/unittests/unittests.gyp
new file mode 100644
index 0000000..2ead44f
--- /dev/null
+++ b/test/unittests/unittests.gyp
@@ -0,0 +1,140 @@
+# Copyright 2014 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'v8_code': 1,
+  },
+  'includes': ['../../build/toolchain.gypi', '../../build/features.gypi'],
+  'targets': [
+    {
+      'target_name': 'unittests',
+      'type': 'executable',
+      'variables': {
+        'optimize': 'max',
+      },
+      'dependencies': [
+        '../../testing/gmock.gyp:gmock',
+        '../../testing/gtest.gyp:gtest',
+        '../../tools/gyp/v8.gyp:v8_libplatform',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+      'sources': [  ### gcmole(all) ###
+        'base/bits-unittest.cc',
+        'base/cpu-unittest.cc',
+        'base/division-by-constant-unittest.cc',
+        'base/flags-unittest.cc',
+        'base/functional-unittest.cc',
+        'base/iterator-unittest.cc',
+        'base/platform/condition-variable-unittest.cc',
+        'base/platform/mutex-unittest.cc',
+        'base/platform/platform-unittest.cc',
+        'base/platform/semaphore-unittest.cc',
+        'base/platform/time-unittest.cc',
+        'base/sys-info-unittest.cc',
+        'base/utils/random-number-generator-unittest.cc',
+        'char-predicates-unittest.cc',
+        'compiler/change-lowering-unittest.cc',
+        'compiler/common-operator-reducer-unittest.cc',
+        'compiler/common-operator-unittest.cc',
+        'compiler/compiler-test-utils.h',
+        'compiler/control-equivalence-unittest.cc',
+        'compiler/diamond-unittest.cc',
+        'compiler/graph-reducer-unittest.cc',
+        'compiler/graph-unittest.cc',
+        'compiler/graph-unittest.h',
+        'compiler/instruction-selector-unittest.cc',
+        'compiler/instruction-selector-unittest.h',
+        'compiler/instruction-sequence-unittest.cc',
+        'compiler/instruction-sequence-unittest.h',
+        'compiler/js-builtin-reducer-unittest.cc',
+        'compiler/js-operator-unittest.cc',
+        'compiler/js-typed-lowering-unittest.cc',
+        'compiler/load-elimination-unittest.cc',
+        'compiler/machine-operator-reducer-unittest.cc',
+        'compiler/machine-operator-unittest.cc',
+        'compiler/move-optimizer-unittest.cc',
+        'compiler/node-matchers-unittest.cc',
+        'compiler/node-test-utils.cc',
+        'compiler/node-test-utils.h',
+        'compiler/register-allocator-unittest.cc',
+        'compiler/select-lowering-unittest.cc',
+        'compiler/simplified-operator-reducer-unittest.cc',
+        'compiler/simplified-operator-unittest.cc',
+        'compiler/value-numbering-reducer-unittest.cc',
+        'compiler/zone-pool-unittest.cc',
+        'libplatform/default-platform-unittest.cc',
+        'libplatform/task-queue-unittest.cc',
+        'libplatform/worker-thread-unittest.cc',
+        'heap/gc-idle-time-handler-unittest.cc',
+        'run-all-unittests.cc',
+        'test-utils.h',
+        'test-utils.cc',
+      ],
+      'conditions': [
+        ['v8_target_arch=="arm"', {
+          'sources': [  ### gcmole(arch:arm) ###
+            'compiler/arm/instruction-selector-arm-unittest.cc',
+          ],
+        }],
+        ['v8_target_arch=="arm64"', {
+          'sources': [  ### gcmole(arch:arm64) ###
+            'compiler/arm64/instruction-selector-arm64-unittest.cc',
+          ],
+        }],
+        ['v8_target_arch=="ia32"', {
+          'sources': [  ### gcmole(arch:ia32) ###
+            'compiler/ia32/instruction-selector-ia32-unittest.cc',
+          ],
+        }],
+        ['v8_target_arch=="mipsel"', {
+          'sources': [  ### gcmole(arch:mipsel) ###
+            'compiler/mips/instruction-selector-mips-unittest.cc',
+          ],
+        }],
+        ['v8_target_arch=="mips64el"', {
+          'sources': [  ### gcmole(arch:mips64el) ###
+            'compiler/mips64/instruction-selector-mips64-unittest.cc',
+          ],
+        }],
+        ['v8_target_arch=="x64"', {
+          'sources': [  ### gcmole(arch:x64) ###
+            'compiler/x64/instruction-selector-x64-unittest.cc',
+          ],
+        }],
+        ['component=="shared_library"', {
+          # compiler-unittests can't be built against a shared library, so we
+          # need to depend on the underlying static target in that case.
+          'conditions': [
+            ['v8_use_snapshot=="true" and v8_use_external_startup_data==0', {
+              'dependencies': ['../../tools/gyp/v8.gyp:v8_snapshot'],
+            }],
+            ['v8_use_snapshot=="true" and v8_use_external_startup_data==1', {
+              'dependencies': ['../../tools/gyp/v8.gyp:v8_external_snapshot'],
+            }],
+            ['v8_use_snapshot!="true"', {
+              'dependencies': ['../../tools/gyp/v8.gyp:v8_nosnapshot'],
+            }],
+          ],
+        }, {
+          'dependencies': ['../../tools/gyp/v8.gyp:v8'],
+        }],
+        ['os_posix == 1', {
+          # TODO(svenpanne): This is a temporary work-around to fix the warnings
+          # that show up because we use -std=gnu++0x instead of -std=c++11.
+          'cflags!': [
+            '-pedantic',
+          ],
+          'direct_dependent_settings': {
+            'cflags!': [
+              '-pedantic',
+            ],
+          },
+        }],
+      ],
+    },
+  ],
+}
diff --git a/test/base-unittests/base-unittests.status b/test/unittests/unittests.status
similarity index 100%
rename from test/base-unittests/base-unittests.status
rename to test/unittests/unittests.status
diff --git a/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt b/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt
index 030d7f9..0e00f23 100644
--- a/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt
+++ b/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt
@@ -1,25 +1,6 @@
-# Copyright 2013 the V8 project authors. All rights reserved.
-# Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1.  Redistributions of source code must retain the above copyright
-#     notice, this list of conditions and the following disclaimer.
-# 2.  Redistributions in binary form must reproduce the above copyright
-#     notice, this list of conditions and the following disclaimer in the
-#     documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
-# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# Copyright 2014 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 Test to ensure correct behaviour of Object.getOwnPropertyNames
 
@@ -69,8 +50,8 @@
 PASS getSortedOwnPropertyNames(Function.prototype) is ['apply', 'arguments', 'bind', 'call', 'caller', 'constructor', 'length', 'name', 'toString']
 PASS getSortedOwnPropertyNames(Array) is ['arguments', 'caller', 'isArray', 'length', 'name', 'observe', 'prototype', 'unobserve']
 PASS getSortedOwnPropertyNames(Array.prototype) is ['concat', 'constructor', 'entries', 'every', 'filter', 'forEach', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']
-PASS getSortedOwnPropertyNames(String) is ['arguments', 'caller', 'fromCharCode', 'length', 'name', 'prototype']
-PASS getSortedOwnPropertyNames(String.prototype) is ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'fixed', 'fontcolor', 'fontsize', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'normalize', 'replace', 'search', 'slice', 'small', 'split', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']
+PASS getSortedOwnPropertyNames(String) is ['arguments', 'caller', 'fromCharCode', 'fromCodePoint', 'length', 'name', 'prototype', 'raw']
+PASS getSortedOwnPropertyNames(String.prototype) is ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'codePointAt', 'concat', 'constructor', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'includes', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'normalize', 'repeat', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']
 PASS getSortedOwnPropertyNames(Boolean) is ['arguments', 'caller', 'length', 'name', 'prototype']
 PASS getSortedOwnPropertyNames(Boolean.prototype) is ['constructor', 'toString', 'valueOf']
 PASS getSortedOwnPropertyNames(Number) is ['EPSILON', 'MAX_SAFE_INTEGER', 'MAX_VALUE', 'MIN_SAFE_INTEGER', 'MIN_VALUE', 'NEGATIVE_INFINITY', 'NaN', 'POSITIVE_INFINITY', 'arguments', 'caller', 'isFinite', 'isInteger', 'isNaN', 'isSafeInteger', 'length', 'name', 'parseFloat', 'parseInt', 'prototype']
diff --git a/test/webkit/fast/js/Object-getOwnPropertyNames.js b/test/webkit/fast/js/Object-getOwnPropertyNames.js
index caa0111..72bd21b 100644
--- a/test/webkit/fast/js/Object-getOwnPropertyNames.js
+++ b/test/webkit/fast/js/Object-getOwnPropertyNames.js
@@ -77,8 +77,8 @@
     "Function.prototype": "['apply', 'arguments', 'bind', 'call', 'caller', 'constructor', 'length', 'name', 'toString']",
     "Array": "['arguments', 'caller', 'isArray', 'length', 'name', 'observe', 'prototype', 'unobserve']",
     "Array.prototype": "['concat', 'constructor', 'entries', 'every', 'filter', 'forEach', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']",
-    "String": "['arguments', 'caller', 'fromCharCode', 'length', 'name', 'prototype']",
-    "String.prototype": "['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'fixed', 'fontcolor', 'fontsize', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'normalize', 'replace', 'search', 'slice', 'small', 'split', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']",
+    "String": "['arguments', 'caller', 'fromCharCode', 'fromCodePoint', 'length', 'name', 'prototype', 'raw']",
+    "String.prototype": "['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'codePointAt', 'concat', 'constructor', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'includes', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'normalize', 'repeat', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']",
     "Boolean": "['arguments', 'caller', 'length', 'name', 'prototype']",
     "Boolean.prototype": "['constructor', 'toString', 'valueOf']",
     "Number": "['EPSILON', 'MAX_SAFE_INTEGER', 'MAX_VALUE', 'MIN_SAFE_INTEGER', 'MIN_VALUE', 'NEGATIVE_INFINITY', 'NaN', 'POSITIVE_INFINITY', 'arguments', 'caller', 'isFinite', 'isInteger', 'isNaN', 'isSafeInteger', 'length', 'name', 'parseFloat', 'parseInt', 'prototype']",
diff --git a/test/webkit/fast/js/basic-strict-mode-expected.txt b/test/webkit/fast/js/basic-strict-mode-expected.txt
index 45f71bf..0e6228e 100644
--- a/test/webkit/fast/js/basic-strict-mode-expected.txt
+++ b/test/webkit/fast/js/basic-strict-mode-expected.txt
@@ -129,7 +129,7 @@
 PASS (function(){(function (){ 'use strict'; delete someDeclaredGlobal;})}) threw exception SyntaxError: Delete of an unqualified identifier in strict mode..
 PASS 'use strict'; if (0) { someGlobal = 'Shouldn\'t be able to assign this.'; }; true; is true
 PASS 'use strict'; someGlobal = 'Shouldn\'t be able to assign this.';  threw exception ReferenceError: someGlobal is not defined.
-FAIL 'use strict'; (function f(){ f = 'shouldn\'t be able to assign to function expression name'; })() should throw an exception. Was undefined.
+PASS 'use strict'; (function f(){ f = 'shouldn\'t be able to assign to function expression name'; })() threw exception TypeError: Assignment to constant variable..
 PASS 'use strict'; eval('var introducedVariable = "FAIL: variable introduced into containing scope";'); introducedVariable threw exception ReferenceError: introducedVariable is not defined.
 PASS 'use strict'; objectWithReadonlyProperty.prop = 'fail' threw exception TypeError: Cannot assign to read only property 'prop' of #<Object>.
 PASS 'use strict'; delete objectWithReadonlyProperty.prop threw exception TypeError: Cannot delete property 'prop' of #<Object>.
diff --git a/test/webkit/fast/regex/toString-expected.txt b/test/webkit/fast/regex/toString-expected.txt
index a6eefd9..1024072 100644
--- a/test/webkit/fast/regex/toString-expected.txt
+++ b/test/webkit/fast/regex/toString-expected.txt
@@ -26,23 +26,23 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-FAIL RegExp('/').source should be \/. Was /.
+PASS RegExp('/').source is "\\/"
 PASS RegExp('').source is "(?:)"
 PASS RegExp.prototype.source is "(?:)"
-FAIL RegExp('/').toString() should be /\//. Was ///.
+PASS RegExp('/').toString() is "/\\//"
 PASS RegExp('').toString() is "/(?:)/"
 PASS RegExp.prototype.toString() is "/(?:)/"
-FAIL testForwardSlash("^/$", "/"); should be true. Threw exception SyntaxError: Unexpected end of input
-FAIL testForwardSlash("^/$", "/"); should be true. Threw exception SyntaxError: Unexpected end of input
-FAIL testForwardSlash("^\/$", "/"); should be true. Threw exception SyntaxError: Unexpected end of input
+PASS testForwardSlash("^/$", "/"); is true
+PASS testForwardSlash("^/$", "/"); is true
+PASS testForwardSlash("^\/$", "/"); is true
 PASS testForwardSlash("^\\/$", "\/"); is true
 PASS testForwardSlash("^\\\/$", "\/"); is true
 FAIL testForwardSlash("^\\\\/$", "\\/"); should be true. Threw exception SyntaxError: Unexpected end of input
 FAIL testForwardSlash("^\\\\\/$", "\\/"); should be true. Threw exception SyntaxError: Unexpected end of input
-FAIL testForwardSlash("x/x/x", "x\/x\/x"); should be true. Threw exception SyntaxError: Unexpected end of input
-FAIL testForwardSlash("x\/x/x", "x\/x\/x"); should be true. Threw exception SyntaxError: Unexpected end of input
-FAIL testForwardSlash("x/x\/x", "x\/x\/x"); should be true. Threw exception SyntaxError: Unexpected end of input
-FAIL testForwardSlash("x\/x\/x", "x\/x\/x"); should be true. Threw exception SyntaxError: Unexpected end of input
+PASS testForwardSlash("x/x/x", "x\/x\/x"); is true
+PASS testForwardSlash("x\/x/x", "x\/x\/x"); is true
+PASS testForwardSlash("x/x\/x", "x\/x\/x"); is true
+PASS testForwardSlash("x\/x\/x", "x\/x\/x"); is true
 FAIL testLineTerminator("\n"); should be false. Was true.
 PASS testLineTerminator("\\n"); is false
 FAIL testLineTerminator("\r"); should be false. Was true.
@@ -51,8 +51,8 @@
 PASS testLineTerminator("\\u2028"); is false
 FAIL testLineTerminator("\u2029"); should be false. Was true.
 PASS testLineTerminator("\\u2029"); is false
-PASS RegExp('[/]').source is '[/]'
-FAIL RegExp('\\[/]').source should be \[\/]. Was \[/].
+FAIL RegExp('[/]').source should be [/]. Was [\/].
+PASS RegExp('\\[/]').source is '\\[\\/]'
 PASS var o = new RegExp(); o.toString() === '/'+o.source+'/' && eval(o.toString()+'.exec(String())') is [""]
 PASS successfullyParsed is true
 
diff --git a/test/webkit/testcfg.py b/test/webkit/testcfg.py
index e4e3f8f..aa81964 100644
--- a/test/webkit/testcfg.py
+++ b/test/webkit/testcfg.py
@@ -109,7 +109,11 @@
             string.startswith("tools/nacl-run.py") or
             string.find("BYPASSING ALL ACL CHECKS") > 0 or
             string.find("Native Client module will be loaded") > 0 or
-            string.find("NaClHostDescOpen:") > 0)
+            string.find("NaClHostDescOpen:") > 0 or
+            # FIXME(machenbach): The test driver shouldn't try to use slow
+            # asserts if they weren't compiled. This fails in optdebug=2.
+            string == "Warning: unknown flag --enable-slow-asserts." or
+            string == "Try --help for options")
 
   def IsFailureOutput(self, output, testpath):
     if super(WebkitTestSuite, self).IsFailureOutput(output, testpath):
diff --git a/test/webkit/webkit.status b/test/webkit/webkit.status
index 3bb6574..c33f1b9 100644
--- a/test/webkit/webkit.status
+++ b/test/webkit/webkit.status
@@ -44,13 +44,23 @@
   'dfg-double-vote-fuzz': [SKIP],
   'reentrant-caching': [SKIP],
   'sort-large-array': [SKIP],
+  # Too slow on windows with --nocrankshaft.
+  # TODO(mstarzinger): Too slow with TF.
+  'array-iterate-backwards': [PASS, NO_VARIANTS],
 }],  # 'mode == debug'
 ['simulator', {
+  # Skip tests that timeout with turbofan.
+  'dfg-int-overflow-in-loop': [PASS, NO_VARIANTS],
+  'array-iterate-backwards': [PASS, NO_VARIANTS],
   'function-apply-aliased': [SKIP],
 }],  # 'simulator'
 ['arch == arm64 and simulator_run == True', {
   'dfg-int-overflow-in-loop': [SKIP],
 }],  # 'arch == arm64 and simulator_run == True'
+['dcheck_always_on == True and arch == arm64', {
+  # Doesn't work with gcc 4.6 on arm64 for some reason.
+  'reentrant-caching': [SKIP],
+}],  # 'dcheck_always_on == True and arch == arm64'
 
 
 ##############################################################################
@@ -59,5 +69,10 @@
   'fast/js/excessive-comma-usage': [SKIP]
 }],  # 'gc_stress == True'
 
+['gc_stress == True and mode == debug', {
+  # Skip tests that timeout.
+  'array-iterate-backwards': [SKIP]
+}],  # 'gc_stress == True and mode == debug'
+
 ##############################################################################
 ]
diff --git a/testing/gmock-support.h b/testing/gmock-support.h
index 44348b6..012775b 100644
--- a/testing/gmock-support.h
+++ b/testing/gmock-support.h
@@ -5,6 +5,9 @@
 #ifndef V8_TESTING_GMOCK_SUPPORT_H_
 #define V8_TESTING_GMOCK_SUPPORT_H_
 
+#include <cmath>
+#include <cstring>
+
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace testing {
@@ -31,6 +34,25 @@
 
 namespace internal {
 
+struct AnyBitEq {
+  template <typename A, typename B>
+  bool operator()(A const& a, B const& b) const {
+    if (sizeof(A) != sizeof(B)) return false;
+    return std::memcmp(&a, &b, sizeof(A)) == 0;
+  }
+};
+
+
+template <typename Rhs>
+class BitEqMatcher : public ComparisonBase<BitEqMatcher<Rhs>, Rhs, AnyBitEq> {
+ public:
+  explicit BitEqMatcher(Rhs const& rhs)
+      : ComparisonBase<BitEqMatcher<Rhs>, Rhs, AnyBitEq>(rhs) {}
+  static const char* Desc() { return "is bitwise equal to"; }
+  static const char* NegatedDesc() { return "isn't bitwise equal to"; }
+};
+
+
 template <typename T>
 class CaptureEqMatcher : public MatcherInterface<T> {
  public:
@@ -60,13 +82,27 @@
 }  // namespace internal
 
 
+// Creates a polymorphic matcher that matches anything whose bit representation
+// is equal to that of x.
+template <typename T>
+inline internal::BitEqMatcher<T> BitEq(T const& x) {
+  return internal::BitEqMatcher<T>(x);
+}
+
+
 // CaptureEq(capture) captures the value passed in during matching as long as it
 // is unset, and once set, compares the value for equality with the argument.
 template <typename T>
-Matcher<T> CaptureEq(Capture<T>* capture) {
+inline Matcher<T> CaptureEq(Capture<T>* capture) {
   return MakeMatcher(new internal::CaptureEqMatcher<T>(capture));
 }
 
+
+// Creates a polymorphic matcher that matches any floating point NaN value.
+MATCHER(IsNaN, std::string(negation ? "isn't" : "is") + " not a number") {
+  return std::isnan(arg);
+}
+
 }  // namespace testing
 
 #endif  // V8_TESTING_GMOCK_SUPPORT_H_
diff --git a/testing/gtest-support.h b/testing/gtest-support.h
index 66b1094..04daa55 100644
--- a/testing/gtest-support.h
+++ b/testing/gtest-support.h
@@ -5,7 +5,7 @@
 #ifndef V8_TESTING_GTEST_SUPPORT_H_
 #define V8_TESTING_GTEST_SUPPORT_H_
 
-#include "include/v8stdint.h"
+#include <stddef.h>
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace testing {
@@ -16,14 +16,17 @@
   inline std::string GetTypeName<type>() { \
     return #type;                          \
   }
-GET_TYPE_NAME(int8_t)
-GET_TYPE_NAME(uint8_t)
-GET_TYPE_NAME(int16_t)
-GET_TYPE_NAME(uint16_t)
-GET_TYPE_NAME(int32_t)
-GET_TYPE_NAME(uint32_t)
-GET_TYPE_NAME(int64_t)
-GET_TYPE_NAME(uint64_t)
+GET_TYPE_NAME(bool)
+GET_TYPE_NAME(signed char)
+GET_TYPE_NAME(unsigned char)
+GET_TYPE_NAME(short)
+GET_TYPE_NAME(unsigned short)
+GET_TYPE_NAME(int)
+GET_TYPE_NAME(unsigned int)
+GET_TYPE_NAME(long)
+GET_TYPE_NAME(unsigned long)
+GET_TYPE_NAME(long long)
+GET_TYPE_NAME(unsigned long long)
 GET_TYPE_NAME(float)
 GET_TYPE_NAME(double)
 #undef GET_TYPE_NAME
diff --git a/third_party/fdlibm/fdlibm.cc b/third_party/fdlibm/fdlibm.cc
deleted file mode 100644
index c009cd0..0000000
--- a/third_party/fdlibm/fdlibm.cc
+++ /dev/null
@@ -1,281 +0,0 @@
-// The following is adapted from fdlibm (http://www.netlib.org/fdlibm).
-//
-// ====================================================
-// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
-//
-// Developed at SunSoft, a Sun Microsystems, Inc. business.
-// Permission to use, copy, modify, and distribute this
-// software is freely granted, provided that this notice
-// is preserved.
-// ====================================================
-//
-// The original source code covered by the above license above has been
-// modified significantly by Google Inc.
-// Copyright 2014 the V8 project authors. All rights reserved.
-
-#include "src/v8.h"
-
-#include "src/double.h"
-#include "third_party/fdlibm/fdlibm.h"
-
-
-namespace v8 {
-namespace fdlibm {
-
-#ifdef _MSC_VER
-inline double scalbn(double x, int y) { return _scalb(x, y); }
-#endif  // _MSC_VER
-
-const double MathConstants::constants[] = {
-    6.36619772367581382433e-01,   // invpio2   0
-    1.57079632673412561417e+00,   // pio2_1    1
-    6.07710050650619224932e-11,   // pio2_1t   2
-    6.07710050630396597660e-11,   // pio2_2    3
-    2.02226624879595063154e-21,   // pio2_2t   4
-    2.02226624871116645580e-21,   // pio2_3    5
-    8.47842766036889956997e-32,   // pio2_3t   6
-    -1.66666666666666324348e-01,  // S1        7  coefficients for sin
-    8.33333333332248946124e-03,   //           8
-    -1.98412698298579493134e-04,  //           9
-    2.75573137070700676789e-06,   //          10
-    -2.50507602534068634195e-08,  //          11
-    1.58969099521155010221e-10,   // S6       12
-    4.16666666666666019037e-02,   // C1       13  coefficients for cos
-    -1.38888888888741095749e-03,  //          14
-    2.48015872894767294178e-05,   //          15
-    -2.75573143513906633035e-07,  //          16
-    2.08757232129817482790e-09,   //          17
-    -1.13596475577881948265e-11,  // C6       18
-    3.33333333333334091986e-01,   // T0       19  coefficients for tan
-    1.33333333333201242699e-01,   //          20
-    5.39682539762260521377e-02,   //          21
-    2.18694882948595424599e-02,   //          22
-    8.86323982359930005737e-03,   //          23
-    3.59207910759131235356e-03,   //          24
-    1.45620945432529025516e-03,   //          25
-    5.88041240820264096874e-04,   //          26
-    2.46463134818469906812e-04,   //          27
-    7.81794442939557092300e-05,   //          28
-    7.14072491382608190305e-05,   //          29
-    -1.85586374855275456654e-05,  //          30
-    2.59073051863633712884e-05,   // T12      31
-    7.85398163397448278999e-01,   // pio4     32
-    3.06161699786838301793e-17,   // pio4lo   33
-    6.93147180369123816490e-01,   // ln2_hi   34
-    1.90821492927058770002e-10,   // ln2_lo   35
-    1.80143985094819840000e+16,   // 2^54     36
-    6.666666666666666666e-01,     // 2/3      37
-    6.666666666666735130e-01,     // LP1      38  coefficients for log1p
-    3.999999999940941908e-01,     //          39
-    2.857142874366239149e-01,     //          40
-    2.222219843214978396e-01,     //          41
-    1.818357216161805012e-01,     //          42
-    1.531383769920937332e-01,     //          43
-    1.479819860511658591e-01,     // LP7      44
-    7.09782712893383973096e+02,   //          45  overflow threshold for expm1
-    1.44269504088896338700e+00,   // 1/ln2    46
-    -3.33333333333331316428e-02,  // Q1       47  coefficients for expm1
-    1.58730158725481460165e-03,   //          48
-    -7.93650757867487942473e-05,  //          49
-    4.00821782732936239552e-06,   //          50
-    -2.01099218183624371326e-07,  // Q5       51
-    710.4758600739439             //          52  overflow threshold sinh, cosh
-};
-
-
-// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
-static const int two_over_pi[] = {
-    0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C,
-    0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649,
-    0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, 0xA73EE8, 0x8235F5, 0x2EBB44,
-    0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, 0x845F8B,
-    0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D,
-    0x367ECF, 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
-    0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330,
-    0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, 0x91615E, 0xE61B08,
-    0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA,
-    0x73A8C9, 0x60E27B, 0xC08C6B};
-
-static const double zero = 0.0;
-static const double two24 = 1.6777216e+07;
-static const double one = 1.0;
-static const double twon24 = 5.9604644775390625e-08;
-
-static const double PIo2[] = {
-    1.57079625129699707031e+00,  // 0x3FF921FB, 0x40000000
-    7.54978941586159635335e-08,  // 0x3E74442D, 0x00000000
-    5.39030252995776476554e-15,  // 0x3CF84698, 0x80000000
-    3.28200341580791294123e-22,  // 0x3B78CC51, 0x60000000
-    1.27065575308067607349e-29,  // 0x39F01B83, 0x80000000
-    1.22933308981111328932e-36,  // 0x387A2520, 0x40000000
-    2.73370053816464559624e-44,  // 0x36E38222, 0x80000000
-    2.16741683877804819444e-51   // 0x3569F31D, 0x00000000
-};
-
-
-int __kernel_rem_pio2(double* x, double* y, int e0, int nx) {
-  static const int32_t jk = 3;
-  double fw;
-  int32_t jx = nx - 1;
-  int32_t jv = (e0 - 3) / 24;
-  if (jv < 0) jv = 0;
-  int32_t q0 = e0 - 24 * (jv + 1);
-  int32_t m = jx + jk;
-
-  double f[10];
-  for (int i = 0, j = jv - jx; i <= m; i++, j++) {
-    f[i] = (j < 0) ? zero : static_cast<double>(two_over_pi[j]);
-  }
-
-  double q[10];
-  for (int i = 0; i <= jk; i++) {
-    fw = 0.0;
-    for (int j = 0; j <= jx; j++) fw += x[j] * f[jx + i - j];
-    q[i] = fw;
-  }
-
-  int32_t jz = jk;
-
-recompute:
-
-  int32_t iq[10];
-  double z = q[jz];
-  for (int i = 0, j = jz; j > 0; i++, j--) {
-    fw = static_cast<double>(static_cast<int32_t>(twon24 * z));
-    iq[i] = static_cast<int32_t>(z - two24 * fw);
-    z = q[j - 1] + fw;
-  }
-
-  z = scalbn(z, q0);
-  z -= 8.0 * std::floor(z * 0.125);
-  int32_t n = static_cast<int32_t>(z);
-  z -= static_cast<double>(n);
-  int32_t ih = 0;
-  if (q0 > 0) {
-    int32_t i = (iq[jz - 1] >> (24 - q0));
-    n += i;
-    iq[jz - 1] -= i << (24 - q0);
-    ih = iq[jz - 1] >> (23 - q0);
-  } else if (q0 == 0) {
-    ih = iq[jz - 1] >> 23;
-  } else if (z >= 0.5) {
-    ih = 2;
-  }
-
-  if (ih > 0) {
-    n += 1;
-    int32_t carry = 0;
-    for (int i = 0; i < jz; i++) {
-      int32_t j = iq[i];
-      if (carry == 0) {
-        if (j != 0) {
-          carry = 1;
-          iq[i] = 0x1000000 - j;
-        }
-      } else {
-        iq[i] = 0xffffff - j;
-      }
-    }
-    if (q0 == 1) {
-      iq[jz - 1] &= 0x7fffff;
-    } else if (q0 == 2) {
-      iq[jz - 1] &= 0x3fffff;
-    }
-    if (ih == 2) {
-      z = one - z;
-      if (carry != 0) z -= scalbn(one, q0);
-    }
-  }
-
-  if (z == zero) {
-    int32_t j = 0;
-    for (int i = jz - 1; i >= jk; i--) j |= iq[i];
-    if (j == 0) {
-      int32_t k = 1;
-      while (iq[jk - k] == 0) k++;
-      for (int i = jz + 1; i <= jz + k; i++) {
-        f[jx + i] = static_cast<double>(two_over_pi[jv + i]);
-        for (j = 0, fw = 0.0; j <= jx; j++) fw += x[j] * f[jx + i - j];
-        q[i] = fw;
-      }
-      jz += k;
-      goto recompute;
-    }
-  }
-
-  if (z == 0.0) {
-    jz -= 1;
-    q0 -= 24;
-    while (iq[jz] == 0) {
-      jz--;
-      q0 -= 24;
-    }
-  } else {
-    z = scalbn(z, -q0);
-    if (z >= two24) {
-      fw = static_cast<double>(static_cast<int32_t>(twon24 * z));
-      iq[jz] = static_cast<int32_t>(z - two24 * fw);
-      jz += 1;
-      q0 += 24;
-      iq[jz] = static_cast<int32_t>(fw);
-    } else {
-      iq[jz] = static_cast<int32_t>(z);
-    }
-  }
-
-  fw = scalbn(one, q0);
-  for (int i = jz; i >= 0; i--) {
-    q[i] = fw * static_cast<double>(iq[i]);
-    fw *= twon24;
-  }
-
-  double fq[10];
-  for (int i = jz; i >= 0; i--) {
-    fw = 0.0;
-    for (int k = 0; k <= jk && k <= jz - i; k++) fw += PIo2[k] * q[i + k];
-    fq[jz - i] = fw;
-  }
-
-  fw = 0.0;
-  for (int i = jz; i >= 0; i--) fw += fq[i];
-  y[0] = (ih == 0) ? fw : -fw;
-  fw = fq[0] - fw;
-  for (int i = 1; i <= jz; i++) fw += fq[i];
-  y[1] = (ih == 0) ? fw : -fw;
-  return n & 7;
-}
-
-
-int rempio2(double x, double* y) {
-  int32_t hx = static_cast<int32_t>(internal::double_to_uint64(x) >> 32);
-  int32_t ix = hx & 0x7fffffff;
-
-  if (ix >= 0x7ff00000) {
-    *y = base::OS::nan_value();
-    return 0;
-  }
-
-  int32_t e0 = (ix >> 20) - 1046;
-  uint64_t zi = internal::double_to_uint64(x) & 0xFFFFFFFFu;
-  zi |= static_cast<uint64_t>(ix - (e0 << 20)) << 32;
-  double z = internal::uint64_to_double(zi);
-
-  double tx[3];
-  for (int i = 0; i < 2; i++) {
-    tx[i] = static_cast<double>(static_cast<int32_t>(z));
-    z = (z - tx[i]) * two24;
-  }
-  tx[2] = z;
-
-  int nx = 3;
-  while (tx[nx - 1] == zero) nx--;
-  int n = __kernel_rem_pio2(tx, y, e0, nx);
-  if (hx < 0) {
-    y[0] = -y[0];
-    y[1] = -y[1];
-    return -n;
-  }
-  return n;
-}
-}
-}  // namespace v8::internal
diff --git a/third_party/fdlibm/fdlibm.h b/third_party/fdlibm/fdlibm.h
deleted file mode 100644
index cadf85b..0000000
--- a/third_party/fdlibm/fdlibm.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// The following is adapted from fdlibm (http://www.netlib.org/fdlibm).
-//
-// ====================================================
-// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
-//
-// Developed at SunSoft, a Sun Microsystems, Inc. business.
-// Permission to use, copy, modify, and distribute this
-// software is freely granted, provided that this notice
-// is preserved.
-// ====================================================
-//
-// The original source code covered by the above license above has been
-// modified significantly by Google Inc.
-// Copyright 2014 the V8 project authors. All rights reserved.
-
-#ifndef V8_FDLIBM_H_
-#define V8_FDLIBM_H_
-
-namespace v8 {
-namespace fdlibm {
-
-int rempio2(double x, double* y);
-
-// Constants to be exposed to builtins via Float64Array.
-struct MathConstants {
-  static const double constants[53];
-};
-}
-}  // namespace v8::internal
-
-#endif  // V8_FDLIBM_H_
diff --git a/third_party/fdlibm/fdlibm.js b/third_party/fdlibm/fdlibm.js
deleted file mode 100644
index 7fd9adf..0000000
--- a/third_party/fdlibm/fdlibm.js
+++ /dev/null
@@ -1,814 +0,0 @@
-// The following is adapted from fdlibm (http://www.netlib.org/fdlibm),
-//
-// ====================================================
-// Copyright (C) 1993-2004 by Sun Microsystems, Inc. All rights reserved.
-//
-// Developed at SunSoft, a Sun Microsystems, Inc. business.
-// Permission to use, copy, modify, and distribute this
-// software is freely granted, provided that this notice
-// is preserved.
-// ====================================================
-//
-// The original source code covered by the above license above has been
-// modified significantly by Google Inc.
-// Copyright 2014 the V8 project authors. All rights reserved.
-//
-// The following is a straightforward translation of fdlibm routines
-// by Raymond Toy (rtoy@google.com).
-
-// Double constants that do not have empty lower 32 bits are found in fdlibm.cc
-// and exposed through kMath as typed array. We assume the compiler to convert
-// from decimal to binary accurately enough to produce the intended values.
-// kMath is initialized to a Float64Array during genesis and not writable.
-var kMath;
-
-const INVPIO2 = kMath[0];
-const PIO2_1  = kMath[1];
-const PIO2_1T = kMath[2];
-const PIO2_2  = kMath[3];
-const PIO2_2T = kMath[4];
-const PIO2_3  = kMath[5];
-const PIO2_3T = kMath[6];
-const PIO4    = kMath[32];
-const PIO4LO  = kMath[33];
-
-// Compute k and r such that x - k*pi/2 = r where |r| < pi/4. For
-// precision, r is returned as two values y0 and y1 such that r = y0 + y1
-// to more than double precision.
-macro REMPIO2(X)
-  var n, y0, y1;
-  var hx = %_DoubleHi(X);
-  var ix = hx & 0x7fffffff;
-
-  if (ix < 0x4002d97c) {
-    // |X| ~< 3*pi/4, special case with n = +/- 1
-    if (hx > 0) {
-      var z = X - PIO2_1;
-      if (ix != 0x3ff921fb) {
-        // 33+53 bit pi is good enough
-        y0 = z - PIO2_1T;
-        y1 = (z - y0) - PIO2_1T;
-      } else {
-        // near pi/2, use 33+33+53 bit pi
-        z -= PIO2_2;
-        y0 = z - PIO2_2T;
-        y1 = (z - y0) - PIO2_2T;
-      }
-      n = 1;
-    } else {
-      // Negative X
-      var z = X + PIO2_1;
-      if (ix != 0x3ff921fb) {
-        // 33+53 bit pi is good enough
-        y0 = z + PIO2_1T;
-        y1 = (z - y0) + PIO2_1T;
-      } else {
-        // near pi/2, use 33+33+53 bit pi
-        z += PIO2_2;
-        y0 = z + PIO2_2T;
-        y1 = (z - y0) + PIO2_2T;
-      }
-      n = -1;
-    }
-  } else if (ix <= 0x413921fb) {
-    // |X| ~<= 2^19*(pi/2), medium size
-    var t = MathAbs(X);
-    n = (t * INVPIO2 + 0.5) | 0;
-    var r = t - n * PIO2_1;
-    var w = n * PIO2_1T;
-    // First round good to 85 bit
-    y0 = r - w;
-    if (ix - (%_DoubleHi(y0) & 0x7ff00000) > 0x1000000) {
-      // 2nd iteration needed, good to 118
-      t = r;
-      w = n * PIO2_2;
-      r = t - w;
-      w = n * PIO2_2T - ((t - r) - w);
-      y0 = r - w;
-      if (ix - (%_DoubleHi(y0) & 0x7ff00000) > 0x3100000) {
-        // 3rd iteration needed. 151 bits accuracy
-        t = r;
-        w = n * PIO2_3;
-        r = t - w;
-        w = n * PIO2_3T - ((t - r) - w);
-        y0 = r - w;
-      }
-    }
-    y1 = (r - y0) - w;
-    if (hx < 0) {
-      n = -n;
-      y0 = -y0;
-      y1 = -y1;
-    }
-  } else {
-    // Need to do full Payne-Hanek reduction here.
-    var r = %RemPiO2(X);
-    n = r[0];
-    y0 = r[1];
-    y1 = r[2];
-  }
-endmacro
-
-
-// __kernel_sin(X, Y, IY)
-// kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854
-// Input X is assumed to be bounded by ~pi/4 in magnitude.
-// Input Y is the tail of X so that x = X + Y.
-//
-// Algorithm
-//  1. Since ieee_sin(-x) = -ieee_sin(x), we need only to consider positive x.
-//  2. ieee_sin(x) is approximated by a polynomial of degree 13 on
-//     [0,pi/4]
-//                           3            13
-//          sin(x) ~ x + S1*x + ... + S6*x
-//     where
-//
-//    |ieee_sin(x)    2     4     6     8     10     12  |     -58
-//    |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x  +S6*x   )| <= 2
-//    |  x                                               |
-//
-//  3. ieee_sin(X+Y) = ieee_sin(X) + sin'(X')*Y
-//              ~ ieee_sin(X) + (1-X*X/2)*Y
-//     For better accuracy, let
-//               3      2      2      2      2
-//          r = X *(S2+X *(S3+X *(S4+X *(S5+X *S6))))
-//     then                   3    2
-//          sin(x) = X + (S1*X + (X *(r-Y/2)+Y))
-//
-macro KSIN(x)
-kMath[7+x]
-endmacro
-
-macro RETURN_KERNELSIN(X, Y, SIGN)
-  var z = X * X;
-  var v = z * X;
-  var r = KSIN(1) + z * (KSIN(2) + z * (KSIN(3) +
-                    z * (KSIN(4) + z * KSIN(5))));
-  return (X - ((z * (0.5 * Y - v * r) - Y) - v * KSIN(0))) SIGN;
-endmacro
-
-// __kernel_cos(X, Y)
-// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
-// Input X is assumed to be bounded by ~pi/4 in magnitude.
-// Input Y is the tail of X so that x = X + Y.
-//
-// Algorithm
-//  1. Since ieee_cos(-x) = ieee_cos(x), we need only to consider positive x.
-//  2. ieee_cos(x) is approximated by a polynomial of degree 14 on
-//     [0,pi/4]
-//                                   4            14
-//          cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
-//     where the remez error is
-//
-//  |                   2     4     6     8     10    12     14 |     -58
-//  |ieee_cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  )| <= 2
-//  |                                                           |
-//
-//                 4     6     8     10    12     14
-//  3. let r = C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  , then
-//         ieee_cos(x) = 1 - x*x/2 + r
-//     since ieee_cos(X+Y) ~ ieee_cos(X) - ieee_sin(X)*Y
-//                    ~ ieee_cos(X) - X*Y,
-//     a correction term is necessary in ieee_cos(x) and hence
-//         cos(X+Y) = 1 - (X*X/2 - (r - X*Y))
-//     For better accuracy when x > 0.3, let qx = |x|/4 with
-//     the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125.
-//     Then
-//         cos(X+Y) = (1-qx) - ((X*X/2-qx) - (r-X*Y)).
-//     Note that 1-qx and (X*X/2-qx) is EXACT here, and the
-//     magnitude of the latter is at least a quarter of X*X/2,
-//     thus, reducing the rounding error in the subtraction.
-//
-macro KCOS(x)
-kMath[13+x]
-endmacro
-
-macro RETURN_KERNELCOS(X, Y, SIGN)
-  var ix = %_DoubleHi(X) & 0x7fffffff;
-  var z = X * X;
-  var r = z * (KCOS(0) + z * (KCOS(1) + z * (KCOS(2)+
-          z * (KCOS(3) + z * (KCOS(4) + z * KCOS(5))))));
-  if (ix < 0x3fd33333) {  // |x| ~< 0.3
-    return (1 - (0.5 * z - (z * r - X * Y))) SIGN;
-  } else {
-    var qx;
-    if (ix > 0x3fe90000) {  // |x| > 0.78125
-      qx = 0.28125;
-    } else {
-      qx = %_ConstructDouble(%_DoubleHi(0.25 * X), 0);
-    }
-    var hz = 0.5 * z - qx;
-    return (1 - qx - (hz - (z * r - X * Y))) SIGN;
-  }
-endmacro
-
-
-// kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854
-// Input x is assumed to be bounded by ~pi/4 in magnitude.
-// Input y is the tail of x.
-// Input k indicates whether ieee_tan (if k = 1) or -1/tan (if k = -1)
-// is returned.
-//
-// Algorithm
-//  1. Since ieee_tan(-x) = -ieee_tan(x), we need only to consider positive x.
-//  2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0.
-//  3. ieee_tan(x) is approximated by a odd polynomial of degree 27 on
-//     [0,0.67434]
-//                           3             27
-//          tan(x) ~ x + T1*x + ... + T13*x
-//     where
-//
-//     |ieee_tan(x)    2     4            26   |     -59.2
-//     |----- - (1+T1*x +T2*x +.... +T13*x    )| <= 2
-//     |  x                                    |
-//
-//     Note: ieee_tan(x+y) = ieee_tan(x) + tan'(x)*y
-//                    ~ ieee_tan(x) + (1+x*x)*y
-//     Therefore, for better accuracy in computing ieee_tan(x+y), let
-//               3      2      2       2       2
-//          r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
-//     then
-//                              3    2
-//          tan(x+y) = x + (T1*x + (x *(r+y)+y))
-//
-//  4. For x in [0.67434,pi/4],  let y = pi/4 - x, then
-//          tan(x) = ieee_tan(pi/4-y) = (1-ieee_tan(y))/(1+ieee_tan(y))
-//                 = 1 - 2*(ieee_tan(y) - (ieee_tan(y)^2)/(1+ieee_tan(y)))
-//
-// Set returnTan to 1 for tan; -1 for cot.  Anything else is illegal
-// and will cause incorrect results.
-//
-macro KTAN(x)
-kMath[19+x]
-endmacro
-
-function KernelTan(x, y, returnTan) {
-  var z;
-  var w;
-  var hx = %_DoubleHi(x);
-  var ix = hx & 0x7fffffff;
-
-  if (ix < 0x3e300000) {  // |x| < 2^-28
-    if (((ix | %_DoubleLo(x)) | (returnTan + 1)) == 0) {
-      // x == 0 && returnTan = -1
-      return 1 / MathAbs(x);
-    } else {
-      if (returnTan == 1) {
-        return x;
-      } else {
-        // Compute -1/(x + y) carefully
-        var w = x + y;
-        var z = %_ConstructDouble(%_DoubleHi(w), 0);
-        var v = y - (z - x);
-        var a = -1 / w;
-        var t = %_ConstructDouble(%_DoubleHi(a), 0);
-        var s = 1 + t * z;
-        return t + a * (s + t * v);
-      }
-    }
-  }
-  if (ix >= 0x3fe59428) {  // |x| > .6744
-    if (x < 0) {
-      x = -x;
-      y = -y;
-    }
-    z = PIO4 - x;
-    w = PIO4LO - y;
-    x = z + w;
-    y = 0;
-  }
-  z = x * x;
-  w = z * z;
-
-  // Break x^5 * (T1 + x^2*T2 + ...) into
-  // x^5 * (T1 + x^4*T3 + ... + x^20*T11) +
-  // x^5 * (x^2 * (T2 + x^4*T4 + ... + x^22*T12))
-  var r = KTAN(1) + w * (KTAN(3) + w * (KTAN(5) +
-                    w * (KTAN(7) + w * (KTAN(9) + w * KTAN(11)))));
-  var v = z * (KTAN(2) + w * (KTAN(4) + w * (KTAN(6) +
-                         w * (KTAN(8) + w * (KTAN(10) + w * KTAN(12))))));
-  var s = z * x;
-  r = y + z * (s * (r + v) + y);
-  r = r + KTAN(0) * s;
-  w = x + r;
-  if (ix >= 0x3fe59428) {
-    return (1 - ((hx >> 30) & 2)) *
-      (returnTan - 2.0 * (x - (w * w / (w + returnTan) - r)));
-  }
-  if (returnTan == 1) {
-    return w;
-  } else {
-    z = %_ConstructDouble(%_DoubleHi(w), 0);
-    v = r - (z - x);
-    var a = -1 / w;
-    var t = %_ConstructDouble(%_DoubleHi(a), 0);
-    s = 1 + t * z;
-    return t + a * (s + t * v);
-  }
-}
-
-function MathSinSlow(x) {
-  REMPIO2(x);
-  var sign = 1 - (n & 2);
-  if (n & 1) {
-    RETURN_KERNELCOS(y0, y1, * sign);
-  } else {
-    RETURN_KERNELSIN(y0, y1, * sign);
-  }
-}
-
-function MathCosSlow(x) {
-  REMPIO2(x);
-  if (n & 1) {
-    var sign = (n & 2) - 1;
-    RETURN_KERNELSIN(y0, y1, * sign);
-  } else {
-    var sign = 1 - (n & 2);
-    RETURN_KERNELCOS(y0, y1, * sign);
-  }
-}
-
-// ECMA 262 - 15.8.2.16
-function MathSin(x) {
-  x = x * 1;  // Convert to number.
-  if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
-    // |x| < pi/4, approximately.  No reduction needed.
-    RETURN_KERNELSIN(x, 0, /* empty */);
-  }
-  return MathSinSlow(x);
-}
-
-// ECMA 262 - 15.8.2.7
-function MathCos(x) {
-  x = x * 1;  // Convert to number.
-  if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
-    // |x| < pi/4, approximately.  No reduction needed.
-    RETURN_KERNELCOS(x, 0, /* empty */);
-  }
-  return MathCosSlow(x);
-}
-
-// ECMA 262 - 15.8.2.18
-function MathTan(x) {
-  x = x * 1;  // Convert to number.
-  if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
-    // |x| < pi/4, approximately.  No reduction needed.
-    return KernelTan(x, 0, 1);
-  }
-  REMPIO2(x);
-  return KernelTan(y0, y1, (n & 1) ? -1 : 1);
-}
-
-// ES6 draft 09-27-13, section 20.2.2.20.
-// Math.log1p
-//
-// Method :
-//   1. Argument Reduction: find k and f such that
-//                      1+x = 2^k * (1+f),
-//         where  sqrt(2)/2 < 1+f < sqrt(2) .
-//
-//      Note. If k=0, then f=x is exact. However, if k!=0, then f
-//      may not be representable exactly. In that case, a correction
-//      term is need. Let u=1+x rounded. Let c = (1+x)-u, then
-//      log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
-//      and add back the correction term c/u.
-//      (Note: when x > 2**53, one can simply return log(x))
-//
-//   2. Approximation of log1p(f).
-//      Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
-//            = 2s + 2/3 s**3 + 2/5 s**5 + .....,
-//            = 2s + s*R
-//      We use a special Reme algorithm on [0,0.1716] to generate
-//      a polynomial of degree 14 to approximate R The maximum error
-//      of this polynomial approximation is bounded by 2**-58.45. In
-//      other words,
-//                      2      4      6      8      10      12      14
-//          R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s  +Lp6*s  +Lp7*s
-//      (the values of Lp1 to Lp7 are listed in the program)
-//      and
-//          |      2          14          |     -58.45
-//          | Lp1*s +...+Lp7*s    -  R(z) | <= 2
-//          |                             |
-//      Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
-//      In order to guarantee error in log below 1ulp, we compute log
-//      by
-//              log1p(f) = f - (hfsq - s*(hfsq+R)).
-//
-//      3. Finally, log1p(x) = k*ln2 + log1p(f).
-//                           = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
-//         Here ln2 is split into two floating point number:
-//                      ln2_hi + ln2_lo,
-//         where n*ln2_hi is always exact for |n| < 2000.
-//
-// Special cases:
-//      log1p(x) is NaN with signal if x < -1 (including -INF) ;
-//      log1p(+INF) is +INF; log1p(-1) is -INF with signal;
-//      log1p(NaN) is that NaN with no signal.
-//
-// Accuracy:
-//      according to an error analysis, the error is always less than
-//      1 ulp (unit in the last place).
-//
-// Constants:
-//      Constants are found in fdlibm.cc. We assume the C++ compiler to convert
-//      from decimal to binary accurately enough to produce the intended values.
-//
-// Note: Assuming log() return accurate answer, the following
-//       algorithm can be used to compute log1p(x) to within a few ULP:
-//
-//              u = 1+x;
-//              if (u==1.0) return x ; else
-//                          return log(u)*(x/(u-1.0));
-//
-//       See HP-15C Advanced Functions Handbook, p.193.
-//
-const LN2_HI    = kMath[34];
-const LN2_LO    = kMath[35];
-const TWO54     = kMath[36];
-const TWO_THIRD = kMath[37];
-macro KLOG1P(x)
-(kMath[38+x])
-endmacro
-
-function MathLog1p(x) {
-  x = x * 1;  // Convert to number.
-  var hx = %_DoubleHi(x);
-  var ax = hx & 0x7fffffff;
-  var k = 1;
-  var f = x;
-  var hu = 1;
-  var c = 0;
-  var u = x;
-
-  if (hx < 0x3fda827a) {
-    // x < 0.41422
-    if (ax >= 0x3ff00000) {  // |x| >= 1
-      if (x === -1) {
-        return -INFINITY;  // log1p(-1) = -inf
-      } else {
-        return NAN;  // log1p(x<-1) = NaN
-      }
-    } else if (ax < 0x3c900000)  {
-      // For |x| < 2^-54 we can return x.
-      return x;
-    } else if (ax < 0x3e200000) {
-      // For |x| < 2^-29 we can use a simple two-term Taylor series.
-      return x - x * x * 0.5;
-    }
-
-    if ((hx > 0) || (hx <= -0x402D413D)) {  // (int) 0xbfd2bec3 = -0x402d413d
-      // -.2929 < x < 0.41422
-      k = 0;
-    }
-  }
-
-  // Handle Infinity and NAN
-  if (hx >= 0x7ff00000) return x;
-
-  if (k !== 0) {
-    if (hx < 0x43400000) {
-      // x < 2^53
-      u = 1 + x;
-      hu = %_DoubleHi(u);
-      k = (hu >> 20) - 1023;
-      c = (k > 0) ? 1 - (u - x) : x - (u - 1);
-      c = c / u;
-    } else {
-      hu = %_DoubleHi(u);
-      k = (hu >> 20) - 1023;
-    }
-    hu = hu & 0xfffff;
-    if (hu < 0x6a09e) {
-      u = %_ConstructDouble(hu | 0x3ff00000, %_DoubleLo(u));  // Normalize u.
-    } else {
-      ++k;
-      u = %_ConstructDouble(hu | 0x3fe00000, %_DoubleLo(u));  // Normalize u/2.
-      hu = (0x00100000 - hu) >> 2;
-    }
-    f = u - 1;
-  }
-
-  var hfsq = 0.5 * f * f;
-  if (hu === 0) {
-    // |f| < 2^-20;
-    if (f === 0) {
-      if (k === 0) {
-        return 0.0;
-      } else {
-        return k * LN2_HI + (c + k * LN2_LO);
-      }
-    }
-    var R = hfsq * (1 - TWO_THIRD * f);
-    if (k === 0) {
-      return f - R;
-    } else {
-      return k * LN2_HI - ((R - (k * LN2_LO + c)) - f);
-    }
-  }
-
-  var s = f / (2 + f);
-  var z = s * s;
-  var R = z * (KLOG1P(0) + z * (KLOG1P(1) + z *
-              (KLOG1P(2) + z * (KLOG1P(3) + z *
-              (KLOG1P(4) + z * (KLOG1P(5) + z * KLOG1P(6)))))));
-  if (k === 0) {
-    return f - (hfsq - s * (hfsq + R));
-  } else {
-    return k * LN2_HI - ((hfsq - (s * (hfsq + R) + (k * LN2_LO + c))) - f);
-  }
-}
-
-// ES6 draft 09-27-13, section 20.2.2.14.
-// Math.expm1
-// Returns exp(x)-1, the exponential of x minus 1.
-//
-// Method
-//   1. Argument reduction:
-//      Given x, find r and integer k such that
-//
-//               x = k*ln2 + r,  |r| <= 0.5*ln2 ~ 0.34658
-//
-//      Here a correction term c will be computed to compensate
-//      the error in r when rounded to a floating-point number.
-//
-//   2. Approximating expm1(r) by a special rational function on
-//      the interval [0,0.34658]:
-//      Since
-//          r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
-//      we define R1(r*r) by
-//          r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
-//      That is,
-//          R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
-//                   = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
-//                   = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
-//      We use a special Remes algorithm on [0,0.347] to generate
-//      a polynomial of degree 5 in r*r to approximate R1. The
-//      maximum error of this polynomial approximation is bounded
-//      by 2**-61. In other words,
-//          R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
-//      where   Q1  =  -1.6666666666666567384E-2,
-//              Q2  =   3.9682539681370365873E-4,
-//              Q3  =  -9.9206344733435987357E-6,
-//              Q4  =   2.5051361420808517002E-7,
-//              Q5  =  -6.2843505682382617102E-9;
-//      (where z=r*r, and the values of Q1 to Q5 are listed below)
-//      with error bounded by
-//          |                  5           |     -61
-//          | 1.0+Q1*z+...+Q5*z   -  R1(z) | <= 2
-//          |                              |
-//
-//      expm1(r) = exp(r)-1 is then computed by the following
-//      specific way which minimize the accumulation rounding error:
-//                             2     3
-//                            r     r    [ 3 - (R1 + R1*r/2)  ]
-//            expm1(r) = r + --- + --- * [--------------------]
-//                            2     2    [ 6 - r*(3 - R1*r/2) ]
-//
-//      To compensate the error in the argument reduction, we use
-//              expm1(r+c) = expm1(r) + c + expm1(r)*c
-//                         ~ expm1(r) + c + r*c
-//      Thus c+r*c will be added in as the correction terms for
-//      expm1(r+c). Now rearrange the term to avoid optimization
-//      screw up:
-//                      (      2                                    2 )
-//                      ({  ( r    [ R1 -  (3 - R1*r/2) ]  )  }    r  )
-//       expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
-//                      ({  ( 2    [ 6 - r*(3 - R1*r/2) ]  )  }    2  )
-//                      (                                             )
-//
-//                 = r - E
-//   3. Scale back to obtain expm1(x):
-//      From step 1, we have
-//         expm1(x) = either 2^k*[expm1(r)+1] - 1
-//                  = or     2^k*[expm1(r) + (1-2^-k)]
-//   4. Implementation notes:
-//      (A). To save one multiplication, we scale the coefficient Qi
-//           to Qi*2^i, and replace z by (x^2)/2.
-//      (B). To achieve maximum accuracy, we compute expm1(x) by
-//        (i)   if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
-//        (ii)  if k=0, return r-E
-//        (iii) if k=-1, return 0.5*(r-E)-0.5
-//        (iv)  if k=1 if r < -0.25, return 2*((r+0.5)- E)
-//                     else          return  1.0+2.0*(r-E);
-//        (v)   if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
-//        (vi)  if k <= 20, return 2^k((1-2^-k)-(E-r)), else
-//        (vii) return 2^k(1-((E+2^-k)-r))
-//
-// Special cases:
-//      expm1(INF) is INF, expm1(NaN) is NaN;
-//      expm1(-INF) is -1, and
-//      for finite argument, only expm1(0)=0 is exact.
-//
-// Accuracy:
-//      according to an error analysis, the error is always less than
-//      1 ulp (unit in the last place).
-//
-// Misc. info.
-//      For IEEE double
-//          if x > 7.09782712893383973096e+02 then expm1(x) overflow
-//
-const KEXPM1_OVERFLOW = kMath[45];
-const INVLN2          = kMath[46];
-macro KEXPM1(x)
-(kMath[47+x])
-endmacro
-
-function MathExpm1(x) {
-  x = x * 1;  // Convert to number.
-  var y;
-  var hi;
-  var lo;
-  var k;
-  var t;
-  var c;
-
-  var hx = %_DoubleHi(x);
-  var xsb = hx & 0x80000000;     // Sign bit of x
-  var y = (xsb === 0) ? x : -x;  // y = |x|
-  hx &= 0x7fffffff;              // High word of |x|
-
-  // Filter out huge and non-finite argument
-  if (hx >= 0x4043687a) {     // if |x| ~=> 56 * ln2
-    if (hx >= 0x40862e42) {   // if |x| >= 709.78
-      if (hx >= 0x7ff00000) {
-        // expm1(inf) = inf; expm1(-inf) = -1; expm1(nan) = nan;
-        return (x === -INFINITY) ? -1 : x;
-      }
-      if (x > KEXPM1_OVERFLOW) return INFINITY;  // Overflow
-    }
-    if (xsb != 0) return -1;  // x < -56 * ln2, return -1.
-  }
-
-  // Argument reduction
-  if (hx > 0x3fd62e42) {    // if |x| > 0.5 * ln2
-    if (hx < 0x3ff0a2b2) {  // and |x| < 1.5 * ln2
-      if (xsb === 0) {
-        hi = x - LN2_HI;
-        lo = LN2_LO;
-        k = 1;
-      } else {
-        hi = x + LN2_HI;
-        lo = -LN2_LO;
-        k = -1;
-      }
-    } else {
-      k = (INVLN2 * x + ((xsb === 0) ? 0.5 : -0.5)) | 0;
-      t = k;
-      // t * ln2_hi is exact here.
-      hi = x - t * LN2_HI;
-      lo = t * LN2_LO;
-    }
-    x = hi - lo;
-    c = (hi - x) - lo;
-  } else if (hx < 0x3c900000)	{
-    // When |x| < 2^-54, we can return x.
-    return x;
-  } else {
-    // Fall through.
-    k = 0;
-  }
-
-  // x is now in primary range
-  var hfx = 0.5 * x;
-  var hxs = x * hfx;
-  var r1 = 1 + hxs * (KEXPM1(0) + hxs * (KEXPM1(1) + hxs *
-                     (KEXPM1(2) + hxs * (KEXPM1(3) + hxs * KEXPM1(4)))));
-  t = 3 - r1 * hfx;
-  var e = hxs * ((r1 - t) / (6 - x * t));
-  if (k === 0) {  // c is 0
-    return x - (x*e - hxs);
-  } else {
-    e = (x * (e - c) - c);
-    e -= hxs;
-    if (k === -1) return 0.5 * (x - e) - 0.5;
-    if (k === 1) {
-      if (x < -0.25) return -2 * (e - (x + 0.5));
-      return 1 + 2 * (x - e);
-    }
-
-    if (k <= -2 || k > 56) {
-      // suffice to return exp(x) + 1
-      y = 1 - (e - x);
-      // Add k to y's exponent
-      y = %_ConstructDouble(%_DoubleHi(y) + (k << 20), %_DoubleLo(y));
-      return y - 1;
-    }
-    if (k < 20) {
-      // t = 1 - 2^k
-      t = %_ConstructDouble(0x3ff00000 - (0x200000 >> k), 0);
-      y = t - (e - x);
-      // Add k to y's exponent
-      y = %_ConstructDouble(%_DoubleHi(y) + (k << 20), %_DoubleLo(y));
-    } else {
-      // t = 2^-k
-      t = %_ConstructDouble((0x3ff - k) << 20, 0);
-      y = x - (e + t);
-      y += 1;
-      // Add k to y's exponent
-      y = %_ConstructDouble(%_DoubleHi(y) + (k << 20), %_DoubleLo(y));
-    }
-  }
-  return y;
-}
-
-
-// ES6 draft 09-27-13, section 20.2.2.30.
-// Math.sinh
-// Method :
-// mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
-//      1. Replace x by |x| (sinh(-x) = -sinh(x)).
-//      2.
-//                                                  E + E/(E+1)
-//          0        <= x <= 22     :  sinh(x) := --------------, E=expm1(x)
-//                                                      2
-//
-//          22       <= x <= lnovft :  sinh(x) := exp(x)/2
-//          lnovft   <= x <= ln2ovft:  sinh(x) := exp(x/2)/2 * exp(x/2)
-//          ln2ovft  <  x           :  sinh(x) := x*shuge (overflow)
-//
-// Special cases:
-//      sinh(x) is |x| if x is +Infinity, -Infinity, or NaN.
-//      only sinh(0)=0 is exact for finite x.
-//
-const KSINH_OVERFLOW = kMath[52];
-const TWO_M28 = 3.725290298461914e-9;  // 2^-28, empty lower half
-const LOG_MAXD = 709.7822265625;  // 0x40862e42 00000000, empty lower half
-
-function MathSinh(x) {
-  x = x * 1;  // Convert to number.
-  var h = (x < 0) ? -0.5 : 0.5;
-  // |x| in [0, 22]. return sign(x)*0.5*(E+E/(E+1))
-  var ax = MathAbs(x);
-  if (ax < 22) {
-    // For |x| < 2^-28, sinh(x) = x
-    if (ax < TWO_M28) return x;
-    var t = MathExpm1(ax);
-    if (ax < 1) return h * (2 * t - t * t / (t + 1));
-    return h * (t + t / (t + 1));
-  }
-  // |x| in [22, log(maxdouble)], return 0.5 * exp(|x|)
-  if (ax < LOG_MAXD) return h * MathExp(ax);
-  // |x| in [log(maxdouble), overflowthreshold]
-  // overflowthreshold = 710.4758600739426
-  if (ax <= KSINH_OVERFLOW) {
-    var w = MathExp(0.5 * ax);
-    var t = h * w;
-    return t * w;
-  }
-  // |x| > overflowthreshold or is NaN.
-  // Return Infinity of the appropriate sign or NaN.
-  return x * INFINITY;
-}
-
-
-// ES6 draft 09-27-13, section 20.2.2.12.
-// Math.cosh
-// Method :
-// mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
-//      1. Replace x by |x| (cosh(x) = cosh(-x)).
-//      2.
-//                                                      [ exp(x) - 1 ]^2
-//          0        <= x <= ln2/2  :  cosh(x) := 1 + -------------------
-//                                                         2*exp(x)
-//
-//                                                 exp(x) + 1/exp(x)
-//          ln2/2    <= x <= 22     :  cosh(x) := -------------------
-//                                                        2
-//          22       <= x <= lnovft :  cosh(x) := exp(x)/2
-//          lnovft   <= x <= ln2ovft:  cosh(x) := exp(x/2)/2 * exp(x/2)
-//          ln2ovft  <  x           :  cosh(x) := huge*huge (overflow)
-//
-// Special cases:
-//      cosh(x) is |x| if x is +INF, -INF, or NaN.
-//      only cosh(0)=1 is exact for finite x.
-//
-const KCOSH_OVERFLOW = kMath[52];
-
-function MathCosh(x) {
-  x = x * 1;  // Convert to number.
-  var ix = %_DoubleHi(x) & 0x7fffffff;
-  // |x| in [0,0.5*log2], return 1+expm1(|x|)^2/(2*exp(|x|))
-  if (ix < 0x3fd62e43) {
-    var t = MathExpm1(MathAbs(x));
-    var w = 1 + t;
-    // For |x| < 2^-55, cosh(x) = 1
-    if (ix < 0x3c800000) return w;
-    return 1 + (t * t) / (w + w);
-  }
-  // |x| in [0.5*log2, 22], return (exp(|x|)+1/exp(|x|)/2
-  if (ix < 0x40360000) {
-    var t = MathExp(MathAbs(x));
-    return 0.5 * t + 0.5 / t;
-  }
-  // |x| in [22, log(maxdouble)], return half*exp(|x|)
-  if (ix < 0x40862e42) return 0.5 * MathExp(MathAbs(x));
-  // |x| in [log(maxdouble), overflowthreshold]
-  if (MathAbs(x) <= KCOSH_OVERFLOW) {
-    var w = MathExp(0.5 * MathAbs(x));
-    var t = 0.5 * w;
-    return t * w;
-  }
-  if (NUMBER_IS_NAN(x)) return x;
-  // |x| > overflowthreshold.
-  return INFINITY;
-}
diff --git a/tools/android-sync.sh b/tools/android-sync.sh
index 460e92d..4acb1cc 100755
--- a/tools/android-sync.sh
+++ b/tools/android-sync.sh
@@ -88,6 +88,7 @@
 echo -n "sync to $ANDROID_V8/$OUTDIR/$ARCH_MODE"
 sync_file "$OUTDIR/$ARCH_MODE/cctest"
 sync_file "$OUTDIR/$ARCH_MODE/d8"
+sync_file "$OUTDIR/$ARCH_MODE/unittests"
 echo ""
 echo -n "sync to $ANDROID_V8/tools"
 sync_file tools/consarray.js
diff --git a/tools/check-name-clashes.py b/tools/check-name-clashes.py
index e448930..89a7dee 100755
--- a/tools/check-name-clashes.py
+++ b/tools/check-name-clashes.py
@@ -8,135 +8,53 @@
 import re
 import sys
 
-FILENAME = "src/runtime.cc"
-FUNCTION = re.compile("^RUNTIME_FUNCTION\(Runtime_(\w+)")
-FUNCTIONEND = "}\n"
-MACRO = re.compile(r"^#define ([^ ]+)\(([^)]*)\) *([^\\]*)\\?\n$")
-FIRST_WORD = re.compile("^\s*(.*?)[\s({\[]")
-
-# Expand these macros, they define further runtime functions.
-EXPAND_MACROS = [
-  "BUFFER_VIEW_GETTER",
-  "DATA_VIEW_GETTER",
-  "DATA_VIEW_SETTER",
-  "ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION",
-  "FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION",
-  "RUNTIME_UNARY_MATH",
-  "TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION",
-]
+FILENAME = "src/runtime/runtime.h"
+LISTHEAD = re.compile(r"#define\s+(\w+LIST\w*)\((\w+)\)")
+LISTBODY = re.compile(r".*\\$")
+BLACKLIST = ['INLINE_FUNCTION_LIST']
 
 
 class Function(object):
   def __init__(self, match):
-    self.name = match.group(1)
+    self.name = match.group(1).strip()
+
+def ListMacroRe(list):
+  macro = LISTHEAD.match(list[0]).group(2)
+  re_string = "\s*%s\((\w+)" % macro
+  return re.compile(re_string)
 
 
-class Macro(object):
-  def __init__(self, match):
-    self.name = match.group(1)
-    self.args = [s.strip() for s in match.group(2).split(",")]
-    self.lines = []
-    self.indentation = 0
-    self.AddLine(match.group(3))
-
-  def AddLine(self, line):
-    if not line: return
-    if not self.lines:
-      # This is the first line, detect indentation.
-      self.indentation = len(line) - len(line.lstrip())
-    line = line.rstrip("\\\n ")
-    if not line: return
-    assert len(line[:self.indentation].strip()) == 0, \
-        ("expected whitespace: '%s', full line: '%s'" %
-         (line[:self.indentation], line))
-    line = line[self.indentation:]
-    if not line: return
-    self.lines.append(line + "\n")
-
-  def Finalize(self):
-    for arg in self.args:
-      pattern = re.compile(r"(##|\b)%s(##|\b)" % arg)
-      for i in range(len(self.lines)):
-        self.lines[i] = re.sub(pattern, "%%(%s)s" % arg, self.lines[i])
-
-  def FillIn(self, arg_values):
-    filler = {}
-    assert len(arg_values) == len(self.args)
-    for i in range(len(self.args)):
-      filler[self.args[i]] = arg_values[i]
-    result = []
-    for line in self.lines:
-      result.append(line % filler)
-    return result
-
-
-def ReadFileAndExpandMacros(filename):
-  found_macros = {}
-  expanded_lines = []
+def FindLists(filename):
+  lists = []
+  current_list = []
+  mode = "SEARCHING"
   with open(filename, "r") as f:
-    found_macro = None
     for line in f:
-      if found_macro is not None:
-        found_macro.AddLine(line)
-        if not line.endswith("\\\n"):
-          found_macro.Finalize()
-          found_macro = None
-        continue
-
-      match = MACRO.match(line)
-      if match:
-        found_macro = Macro(match)
-        if found_macro.name in EXPAND_MACROS:
-          found_macros[found_macro.name] = found_macro
-        else:
-          found_macro = None
-        continue
-
-      match = FIRST_WORD.match(line)
-      if match:
-        first_word = match.group(1)
-        if first_word in found_macros:
-          MACRO_CALL = re.compile("%s\(([^)]*)\)" % first_word)
-          match = MACRO_CALL.match(line)
-          assert match
-          args = [s.strip() for s in match.group(1).split(",")]
-          expanded_lines += found_macros[first_word].FillIn(args)
-          continue
-
-      expanded_lines.append(line)
-  return expanded_lines
+      if mode == "SEARCHING":
+        match = LISTHEAD.match(line)
+        if match and match.group(1) not in BLACKLIST:
+          mode = "APPENDING"
+          current_list.append(line)
+      else:
+        current_list.append(line)
+        match = LISTBODY.match(line)
+        if not match:
+          mode = "SEARCHING"
+          lists.append(current_list)
+          current_list = []
+  return lists
 
 
 # Detects runtime functions by parsing FILENAME.
 def FindRuntimeFunctions():
   functions = []
-  expanded_lines = ReadFileAndExpandMacros(FILENAME)
-  function = None
-  partial_line = ""
-  for line in expanded_lines:
-    # Multi-line definition support, ignoring macros.
-    if line.startswith("RUNTIME_FUNCTION") and not line.endswith("{\n"):
-      if line.endswith("\\\n"): continue
-      partial_line = line.rstrip()
-      continue
-    if partial_line:
-      partial_line += " " + line.strip()
-      if partial_line.endswith("{"):
-        line = partial_line
-        partial_line = ""
-      else:
-        continue
-
-    match = FUNCTION.match(line)
-    if match:
-      function = Function(match)
-      continue
-    if function is None: continue
-
-    if line == FUNCTIONEND:
-      if function is not None:
-        functions.append(function)
-        function = None
+  lists = FindLists(FILENAME)
+  for list in lists:
+    function_re = ListMacroRe(list)
+    for line in list:
+      match = function_re.match(line)
+      if match:
+        functions.append(Function(match))
   return functions
 
 
diff --git a/tools/codemap.js b/tools/codemap.js
index 129179e..fa6c36b 100644
--- a/tools/codemap.js
+++ b/tools/codemap.js
@@ -258,11 +258,13 @@
  *
  * @param {number} size Code entry size in bytes.
  * @param {string} opt_name Code entry name.
+ * @param {string} opt_type Code entry type, e.g. SHARED_LIB, CPP.
  * @constructor
  */
-CodeMap.CodeEntry = function(size, opt_name) {
+CodeMap.CodeEntry = function(size, opt_name, opt_type) {
   this.size = size;
   this.name = opt_name || '';
+  this.type = opt_type || '';
   this.nameUpdated_ = false;
 };
 
diff --git a/tools/find-commit-for-patch.py b/tools/find-commit-for-patch.py
new file mode 100755
index 0000000..657826c
--- /dev/null
+++ b/tools/find-commit-for-patch.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+# Copyright 2014 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import subprocess
+import sys
+
+
+def GetArgs():
+  parser = argparse.ArgumentParser(
+      description="Finds a commit that a given patch can be applied to. "
+                  "Does not actually apply the patch or modify your checkout "
+                  "in any way.")
+  parser.add_argument("patch_file", help="Patch file to match")
+  parser.add_argument(
+      "--branch", "-b", default="origin/master", type=str,
+      help="Git tree-ish where to start searching for commits, "
+           "default: %(default)s")
+  parser.add_argument(
+      "--limit", "-l", default=500, type=int,
+      help="Maximum number of commits to search, default: %(default)s")
+  parser.add_argument(
+      "--verbose", "-v", default=False, action="store_true",
+      help="Print verbose output for your entertainment")
+  return parser.parse_args()
+
+
+def FindFilesInPatch(patch_file):
+  files = {}
+  next_file = ""
+  with open(patch_file) as patch:
+    for line in patch:
+      if line.startswith("diff --git "):
+        # diff --git a/src/objects.cc b/src/objects.cc
+        words = line.split()
+        assert words[2].startswith("a/") and len(words[2]) > 2
+        next_file = words[2][2:]
+      elif line.startswith("index "):
+        # index add3e61..d1bbf6a 100644
+        hashes = line.split()[1]
+        old_hash = hashes.split("..")[0]
+        if old_hash.startswith("0000000"): continue  # Ignore new files.
+        files[next_file] = old_hash
+  return files
+
+
+def GetGitCommitHash(treeish):
+  cmd = ["git", "log", "-1", "--format=%H", treeish]
+  return subprocess.check_output(cmd).strip()
+
+
+def CountMatchingFiles(commit, files):
+  matched_files = 0
+  # Calling out to git once and parsing the result Python-side is faster
+  # than calling 'git ls-tree' for every file.
+  cmd = ["git", "ls-tree", "-r", commit] + [f for f in files]
+  output = subprocess.check_output(cmd)
+  for line in output.splitlines():
+    # 100644 blob c6d5daaa7d42e49a653f9861224aad0a0244b944      src/objects.cc
+    _, _, actual_hash, filename = line.split()
+    expected_hash = files[filename]
+    if actual_hash.startswith(expected_hash): matched_files += 1
+  return matched_files
+
+
+def FindFirstMatchingCommit(start, files, limit, verbose):
+  commit = GetGitCommitHash(start)
+  num_files = len(files)
+  if verbose: print(">>> Found %d files modified by patch." % num_files)
+  for _ in range(limit):
+    matched_files = CountMatchingFiles(commit, files)
+    if verbose: print("Commit %s matched %d files" % (commit, matched_files))
+    if matched_files == num_files:
+      return commit
+    commit = GetGitCommitHash("%s^" % commit)
+  print("Sorry, no matching commit found. "
+        "Try running 'git fetch', specifying the correct --branch, "
+        "and/or setting a higher --limit.")
+  sys.exit(1)
+
+
+if __name__ == "__main__":
+  args = GetArgs()
+  files = FindFilesInPatch(args.patch_file)
+  commit = FindFirstMatchingCommit(args.branch, files, args.limit, args.verbose)
+  if args.verbose:
+    print(">>> Matching commit: %s" % commit)
+    print(subprocess.check_output(["git", "log", "-1", commit]))
+    print(">>> Kthxbai.")
+  else:
+    print(commit)
diff --git a/tools/find_depot_tools.py b/tools/find_depot_tools.py
new file mode 100644
index 0000000..95ae9e8
--- /dev/null
+++ b/tools/find_depot_tools.py
@@ -0,0 +1,40 @@
+# Copyright 2014 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Small utility function to find depot_tools and add it to the python path.
+"""
+
+import os
+import sys
+
+
+def directory_really_is_depot_tools(directory):
+  return os.path.isfile(os.path.join(directory, 'gclient.py'))
+
+
+def add_depot_tools_to_path():
+  """Search for depot_tools and add it to sys.path."""
+  # First look if depot_tools is already in PYTHONPATH.
+  for i in sys.path:
+    if i.rstrip(os.sep).endswith('depot_tools'):
+      if directory_really_is_depot_tools(i):
+        return i
+
+  # Then look if depot_tools is in PATH, common case.
+  for i in os.environ['PATH'].split(os.pathsep):
+    if i.rstrip(os.sep).endswith('depot_tools'):
+      if directory_really_is_depot_tools(i):
+        sys.path.insert(0, i.rstrip(os.sep))
+        return i
+  # Rare case, it's not even in PATH, look upward up to root.
+  root_dir = os.path.dirname(os.path.abspath(__file__))
+  previous_dir = os.path.abspath(__file__)
+  while root_dir and root_dir != previous_dir:
+    if directory_really_is_depot_tools(os.path.join(root_dir, 'depot_tools')):
+      i = os.path.join(root_dir, 'depot_tools')
+      sys.path.insert(0, i)
+      return i
+    previous_dir = root_dir
+    root_dir = os.path.dirname(root_dir)
+  print >> sys.stderr, 'Failed to find depot_tools'
+  return None
diff --git a/tools/gdbinit b/tools/gdbinit
index 20cdff6..8d0345a 100644
--- a/tools/gdbinit
+++ b/tools/gdbinit
@@ -20,9 +20,27 @@
 Usage: jco pc
 end
 
+# Print DescriptorArray.
+define jda
+print ((v8::internal::DescriptorArray*)($arg0))->Print()
+end
+document jda
+Print a v8 DescriptorArray object
+Usage: jda tagged_ptr
+end
+
+# Print TransitionArray.
+define jta
+print ((v8::internal::TransitionArray*)($arg0))->Print()
+end
+document jta
+Print a v8 TransitionArray object
+Usage: jta tagged_ptr
+end
+
 # Print JavaScript stack trace.
 define jst
-print v8::internal::Isolate::Current()->PrintStack(stdout)
+print v8::internal::Isolate::Current()->PrintStack((FILE*) stdout)
 end
 document jst
 Print the current JavaScript stack trace
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index c63cd94..696434d 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -164,7 +164,6 @@
         '<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
         '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
         '<(INTERMEDIATE_DIR)/snapshot.cc',
-        '../../src/snapshot-common.cc',
       ],
       'actions': [
         {
@@ -206,7 +205,6 @@
       'sources': [
         '<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
         '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
-        '../../src/snapshot-common.cc',
         '../../src/snapshot-empty.cc',
       ],
       'conditions': [
@@ -229,89 +227,105 @@
       'target_name': 'v8_external_snapshot',
       'type': 'static_library',
       'conditions': [
-        ['want_separate_host_toolset==1', {
-          'toolsets': ['host', 'target'],
-          'dependencies': [
-            'mksnapshot#host',
-            'js2c#host',
-            'natives_blob',
-        ]}, {
-          'toolsets': ['target'],
-          'dependencies': [
-            'mksnapshot',
-            'js2c',
-            'natives_blob',
-          ],
-        }],
-        ['component=="shared_library"', {
-          'defines': [
-            'V8_SHARED',
-            'BUILDING_V8_SHARED',
-          ],
-          'direct_dependent_settings': {
-            'defines': [
-              'V8_SHARED',
-              'USING_V8_SHARED',
-            ],
-          },
-        }],
-      ],
-      'dependencies': [
-        'v8_base',
-      ],
-      'include_dirs+': [
-        '../..',
-      ],
-      'sources': [
-        '../../src/natives-external.cc',
-        '../../src/snapshot-external.cc',
-      ],
-      'actions': [
-        {
-          'action_name': 'run_mksnapshot (external)',
-          'inputs': [
-            '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)mksnapshot<(EXECUTABLE_SUFFIX)',
-          ],
+        [ 'v8_use_external_startup_data==1', {
           'conditions': [
             ['want_separate_host_toolset==1', {
-              'target_conditions': [
-                ['_toolset=="host"', {
-                  'outputs': [
-                    '<(INTERMEDIATE_DIR)/snapshot.cc',
-                    '<(PRODUCT_DIR)/snapshot_blob_host.bin',
+              'toolsets': ['host', 'target'],
+              'dependencies': [
+                'mksnapshot#host',
+                'js2c#host',
+                'natives_blob',
+            ]}, {
+              'toolsets': ['target'],
+              'dependencies': [
+                'mksnapshot',
+                'js2c',
+                'natives_blob',
+              ],
+            }],
+            ['component=="shared_library"', {
+              'defines': [
+                'V8_SHARED',
+                'BUILDING_V8_SHARED',
+              ],
+              'direct_dependent_settings': {
+                'defines': [
+                  'V8_SHARED',
+                  'USING_V8_SHARED',
+                ],
+              },
+            }],
+          ],
+          'dependencies': [
+            'v8_base',
+          ],
+          'include_dirs+': [
+            '../..',
+          ],
+          'sources': [
+            '../../src/natives-external.cc',
+            '../../src/snapshot-external.cc',
+          ],
+          'actions': [
+            {
+              'action_name': 'run_mksnapshot (external)',
+              'inputs': [
+                '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)mksnapshot<(EXECUTABLE_SUFFIX)',
+              ],
+              'variables': {
+                'mksnapshot_flags': [
+                  '--log-snapshot-positions',
+                  '--logfile', '<(INTERMEDIATE_DIR)/snapshot.log',
+                ],
+                'conditions': [
+                  ['v8_random_seed!=0', {
+                    'mksnapshot_flags': ['--random-seed', '<(v8_random_seed)'],
+                  }],
+                ],
+              },
+              'conditions': [
+                ['want_separate_host_toolset==1', {
+                  'target_conditions': [
+                    ['_toolset=="host"', {
+                      'outputs': [
+                        '<(INTERMEDIATE_DIR)/snapshot.cc',
+                        '<(PRODUCT_DIR)/snapshot_blob_host.bin',
+                      ],
+                      'action': [
+                        '<@(_inputs)',
+                        '<@(mksnapshot_flags)',
+                        '<@(INTERMEDIATE_DIR)/snapshot.cc',
+                        '--startup_blob', '<(PRODUCT_DIR)/snapshot_blob_host.bin',
+                      ],
+                    }, {
+                      'outputs': [
+                        '<(INTERMEDIATE_DIR)/snapshot.cc',
+                        '<(PRODUCT_DIR)/snapshot_blob.bin',
+                      ],
+                      'action': [
+                        '<@(_inputs)',
+                        '<@(mksnapshot_flags)',
+                        '<@(INTERMEDIATE_DIR)/snapshot.cc',
+                        '--startup_blob', '<(PRODUCT_DIR)/snapshot_blob.bin',
+                      ],
+                    }],
                   ],
                 }, {
                   'outputs': [
                     '<(INTERMEDIATE_DIR)/snapshot.cc',
                     '<(PRODUCT_DIR)/snapshot_blob.bin',
                   ],
+                  'action': [
+                    '<@(_inputs)',
+                    '<@(mksnapshot_flags)',
+                    '<@(INTERMEDIATE_DIR)/snapshot.cc',
+                    '--startup_blob', '<(PRODUCT_DIR)/snapshot_blob.bin',
+                  ],
                 }],
               ],
-            }, {
-              'outputs': [
-                '<(INTERMEDIATE_DIR)/snapshot.cc',
-                '<(PRODUCT_DIR)/snapshot_blob.bin',
-              ],
-            }],
+            },
           ],
-          'variables': {
-            'mksnapshot_flags': [
-              '--log-snapshot-positions',
-              '--logfile', '<(INTERMEDIATE_DIR)/snapshot.log',
-            ],
-            'conditions': [
-              ['v8_random_seed!=0', {
-                'mksnapshot_flags': ['--random-seed', '<(v8_random_seed)'],
-              }],
-            ],
-          },
-          'action': [
-            '<@(_inputs)',
-            '<@(mksnapshot_flags)',
-            '<@(INTERMEDIATE_DIR)/snapshot.cc',
-            '--startup_blob', '<(PRODUCT_DIR)/snapshot_blob.bin',
-          ],
-        },
+        }],
       ],
     },
     {
@@ -343,18 +357,26 @@
         '../../src/assembler.h',
         '../../src/assert-scope.h',
         '../../src/assert-scope.cc',
+        '../../src/ast-this-access-visitor.cc',
+        '../../src/ast-this-access-visitor.h',
         '../../src/ast-value-factory.cc',
         '../../src/ast-value-factory.h',
+        '../../src/ast-numbering.cc',
+        '../../src/ast-numbering.h',
         '../../src/ast.cc',
         '../../src/ast.h',
         '../../src/background-parsing-task.cc',
         '../../src/background-parsing-task.h',
         '../../src/bailout-reason.cc',
         '../../src/bailout-reason.h',
+        '../../src/basic-block-profiler.cc',
+        '../../src/basic-block-profiler.h',
         '../../src/bignum-dtoa.cc',
         '../../src/bignum-dtoa.h',
         '../../src/bignum.cc',
         '../../src/bignum.h',
+        '../../src/bit-vector.cc',
+        '../../src/bit-vector.h',
         '../../src/bootstrapper.cc',
         '../../src/bootstrapper.h',
         '../../src/builtins.cc',
@@ -362,6 +384,7 @@
         '../../src/bytecodes-irregexp.h',
         '../../src/cached-powers.cc',
         '../../src/cached-powers.h',
+        '../../src/char-predicates.cc',
         '../../src/char-predicates-inl.h',
         '../../src/char-predicates.h',
         '../../src/checks.cc',
@@ -378,28 +401,37 @@
         '../../src/codegen.h',
         '../../src/compilation-cache.cc',
         '../../src/compilation-cache.h',
+        '../../src/compilation-statistics.cc',
+        '../../src/compilation-statistics.h',
         '../../src/compiler/access-builder.cc',
         '../../src/compiler/access-builder.h',
         '../../src/compiler/ast-graph-builder.cc',
         '../../src/compiler/ast-graph-builder.h',
+        '../../src/compiler/ast-loop-assignment-analyzer.cc',
+        '../../src/compiler/ast-loop-assignment-analyzer.h',
+        '../../src/compiler/basic-block-instrumentor.cc',
+        '../../src/compiler/basic-block-instrumentor.h',
         '../../src/compiler/change-lowering.cc',
         '../../src/compiler/change-lowering.h',
         '../../src/compiler/code-generator-impl.h',
         '../../src/compiler/code-generator.cc',
         '../../src/compiler/code-generator.h',
+        '../../src/compiler/common-node-cache.cc',
         '../../src/compiler/common-node-cache.h',
+        '../../src/compiler/common-operator-reducer.cc',
+        '../../src/compiler/common-operator-reducer.h',
         '../../src/compiler/common-operator.cc',
         '../../src/compiler/common-operator.h',
         '../../src/compiler/control-builders.cc',
         '../../src/compiler/control-builders.h',
+        '../../src/compiler/control-equivalence.h',
+        '../../src/compiler/control-reducer.cc',
+        '../../src/compiler/control-reducer.h',
+        '../../src/compiler/diamond.h',
         '../../src/compiler/frame.h',
         '../../src/compiler/gap-resolver.cc',
         '../../src/compiler/gap-resolver.h',
-        '../../src/compiler/generic-algorithm-inl.h',
         '../../src/compiler/generic-algorithm.h',
-        '../../src/compiler/generic-graph.h',
-        '../../src/compiler/generic-node-inl.h',
-        '../../src/compiler/generic-node.h',
         '../../src/compiler/graph-builder.cc',
         '../../src/compiler/graph-builder.h',
         '../../src/compiler/graph-inl.h',
@@ -427,18 +459,29 @@
         '../../src/compiler/js-graph.h',
         '../../src/compiler/js-inlining.cc',
         '../../src/compiler/js-inlining.h',
+        '../../src/compiler/js-intrinsic-builder.cc',
+        '../../src/compiler/js-intrinsic-builder.h',
+        '../../src/compiler/js-operator.cc',
         '../../src/compiler/js-operator.h',
         '../../src/compiler/js-typed-lowering.cc',
         '../../src/compiler/js-typed-lowering.h',
+        '../../src/compiler/jump-threading.cc',
+        '../../src/compiler/jump-threading.h',
         '../../src/compiler/linkage-impl.h',
         '../../src/compiler/linkage.cc',
         '../../src/compiler/linkage.h',
+        '../../src/compiler/load-elimination.cc',
+        '../../src/compiler/load-elimination.h',
+        '../../src/compiler/loop-analysis.cc',
+        '../../src/compiler/loop-analysis.h',
         '../../src/compiler/machine-operator-reducer.cc',
         '../../src/compiler/machine-operator-reducer.h',
         '../../src/compiler/machine-operator.cc',
         '../../src/compiler/machine-operator.h',
         '../../src/compiler/machine-type.cc',
         '../../src/compiler/machine-type.h',
+        '../../src/compiler/move-optimizer.cc',
+        '../../src/compiler/move-optimizer.h',
         '../../src/compiler/node-aux-data-inl.h',
         '../../src/compiler/node-aux-data.h',
         '../../src/compiler/node-cache.cc',
@@ -448,23 +491,31 @@
         '../../src/compiler/node-properties.h',
         '../../src/compiler/node.cc',
         '../../src/compiler/node.h',
+        '../../src/compiler/opcodes.cc',
         '../../src/compiler/opcodes.h',
-        '../../src/compiler/operator-properties-inl.h',
+        '../../src/compiler/operator-properties.cc',
         '../../src/compiler/operator-properties.h',
         '../../src/compiler/operator.cc',
         '../../src/compiler/operator.h',
-        '../../src/compiler/phi-reducer.h',
         '../../src/compiler/pipeline.cc',
         '../../src/compiler/pipeline.h',
+        '../../src/compiler/pipeline-statistics.cc',
+        '../../src/compiler/pipeline-statistics.h',
         '../../src/compiler/raw-machine-assembler.cc',
         '../../src/compiler/raw-machine-assembler.h',
         '../../src/compiler/register-allocator.cc',
         '../../src/compiler/register-allocator.h',
+        '../../src/compiler/register-allocator-verifier.cc',
+        '../../src/compiler/register-allocator-verifier.h',
+        '../../src/compiler/register-configuration.cc',
+        '../../src/compiler/register-configuration.h',
         '../../src/compiler/representation-change.h',
         '../../src/compiler/schedule.cc',
         '../../src/compiler/schedule.h',
         '../../src/compiler/scheduler.cc',
         '../../src/compiler/scheduler.h',
+        '../../src/compiler/select-lowering.cc',
+        '../../src/compiler/select-lowering.h',
         '../../src/compiler/simplified-lowering.cc',
         '../../src/compiler/simplified-lowering.h',
         '../../src/compiler/simplified-operator-reducer.cc',
@@ -479,6 +530,8 @@
         '../../src/compiler/value-numbering-reducer.h',
         '../../src/compiler/verifier.cc',
         '../../src/compiler/verifier.h',
+        '../../src/compiler/zone-pool.cc',
+        '../../src/compiler/zone-pool.h',
         '../../src/compiler.cc',
         '../../src/compiler.h',
         '../../src/contexts.cc',
@@ -491,8 +544,6 @@
         '../../src/cpu-profiler-inl.h',
         '../../src/cpu-profiler.cc',
         '../../src/cpu-profiler.h',
-        '../../src/data-flow.cc',
-        '../../src/data-flow.h',
         '../../src/date.cc',
         '../../src/date.h',
         '../../src/dateparser-inl.h',
@@ -531,7 +582,6 @@
         '../../src/factory.h',
         '../../src/fast-dtoa.cc',
         '../../src/fast-dtoa.h',
-        '../../src/feedback-slots.h',
         '../../src/field-index.h',
         '../../src/field-index-inl.h',
         '../../src/fixed-dtoa.cc',
@@ -582,8 +632,6 @@
         '../../src/heap/store-buffer-inl.h',
         '../../src/heap/store-buffer.cc',
         '../../src/heap/store-buffer.h',
-        '../../src/heap/sweeper-thread.h',
-        '../../src/heap/sweeper-thread.cc',
         '../../src/hydrogen-alias-analysis.h',
         '../../src/hydrogen-bce.cc',
         '../../src/hydrogen-bce.h',
@@ -666,6 +714,9 @@
         '../../src/jsregexp-inl.h',
         '../../src/jsregexp.cc',
         '../../src/jsregexp.h',
+	'../../src/layout-descriptor-inl.h',
+	'../../src/layout-descriptor.cc',
+	'../../src/layout-descriptor.h',
         '../../src/list-inl.h',
         '../../src/list.h',
         '../../src/lithium-allocator-inl.h',
@@ -731,8 +782,35 @@
         '../../src/rewriter.h',
         '../../src/runtime-profiler.cc',
         '../../src/runtime-profiler.h',
-        '../../src/runtime.cc',
-        '../../src/runtime.h',
+        '../../src/runtime/runtime-api.cc',
+        '../../src/runtime/runtime-array.cc',
+        '../../src/runtime/runtime-classes.cc',
+        '../../src/runtime/runtime-collections.cc',
+        '../../src/runtime/runtime-compiler.cc',
+        '../../src/runtime/runtime-date.cc',
+        '../../src/runtime/runtime-debug.cc',
+        '../../src/runtime/runtime-function.cc',
+        '../../src/runtime/runtime-generator.cc',
+        '../../src/runtime/runtime-i18n.cc',
+        '../../src/runtime/runtime-internal.cc',
+        '../../src/runtime/runtime-json.cc',
+        '../../src/runtime/runtime-literals.cc',
+        '../../src/runtime/runtime-liveedit.cc',
+        '../../src/runtime/runtime-maths.cc',
+        '../../src/runtime/runtime-numbers.cc',
+        '../../src/runtime/runtime-object.cc',
+        '../../src/runtime/runtime-observe.cc',
+        '../../src/runtime/runtime-proxy.cc',
+        '../../src/runtime/runtime-regexp.cc',
+        '../../src/runtime/runtime-scopes.cc',
+        '../../src/runtime/runtime-strings.cc',
+        '../../src/runtime/runtime-symbol.cc',
+        '../../src/runtime/runtime-test.cc',
+        '../../src/runtime/runtime-typedarray.cc',
+        '../../src/runtime/runtime-uri.cc',
+        '../../src/runtime/runtime-utils.h',
+        '../../src/runtime/runtime.cc',
+        '../../src/runtime/runtime.h',
         '../../src/safepoint-table.cc',
         '../../src/safepoint-table.h',
         '../../src/sampler.cc',
@@ -750,8 +828,11 @@
         '../../src/small-pointer-list.h',
         '../../src/smart-pointers.h',
         '../../src/snapshot.h',
+        '../../src/snapshot-common.cc',
         '../../src/snapshot-source-sink.cc',
         '../../src/snapshot-source-sink.h',
+        '../../src/string-builder.cc',
+        '../../src/string-builder.h',
         '../../src/string-search.cc',
         '../../src/string-search.h',
         '../../src/string-stream.cc',
@@ -780,8 +861,9 @@
         '../../src/unicode-inl.h',
         '../../src/unicode.cc',
         '../../src/unicode.h',
+        '../../src/unicode-decoder.cc',
+        '../../src/unicode-decoder.h',
         '../../src/unique.h',
-        '../../src/uri.h',
         '../../src/utils-inl.h',
         '../../src/utils.cc',
         '../../src/utils.h',
@@ -800,8 +882,8 @@
         '../../src/zone-inl.h',
         '../../src/zone.cc',
         '../../src/zone.h',
-        '../../third_party/fdlibm/fdlibm.cc',
-        '../../third_party/fdlibm/fdlibm.h',
+        '../../src/third_party/fdlibm/fdlibm.cc',
+        '../../src/third_party/fdlibm/fdlibm.h',
       ],
       'conditions': [
         ['want_separate_host_toolset==1', {
@@ -1014,6 +1096,10 @@
             '../../src/mips/regexp-macro-assembler-mips.cc',
             '../../src/mips/regexp-macro-assembler-mips.h',
             '../../src/mips/simulator-mips.cc',
+            '../../src/compiler/mips/code-generator-mips.cc',
+            '../../src/compiler/mips/instruction-codes-mips.h',
+            '../../src/compiler/mips/instruction-selector-mips.cc',
+            '../../src/compiler/mips/linkage-mips.cc',
             '../../src/ic/mips/access-compiler-mips.cc',
             '../../src/ic/mips/handler-compiler-mips.cc',
             '../../src/ic/mips/ic-mips.cc',
@@ -1052,6 +1138,10 @@
             '../../src/mips64/regexp-macro-assembler-mips64.cc',
             '../../src/mips64/regexp-macro-assembler-mips64.h',
             '../../src/mips64/simulator-mips64.cc',
+            '../../src/compiler/mips64/code-generator-mips64.cc',
+            '../../src/compiler/mips64/instruction-codes-mips64.h',
+            '../../src/compiler/mips64/instruction-selector-mips64.cc',
+            '../../src/compiler/mips64/linkage-mips64.cc',
             '../../src/ic/mips64/access-compiler-mips64.cc',
             '../../src/ic/mips64/handler-compiler-mips64.cc',
             '../../src/ic/mips64/ic-mips64.cc',
@@ -1087,10 +1177,6 @@
             '../../src/x64/macro-assembler-x64.h',
             '../../src/x64/regexp-macro-assembler-x64.cc',
             '../../src/x64/regexp-macro-assembler-x64.h',
-            '../../src/compiler/x64/code-generator-x64.cc',
-            '../../src/compiler/x64/instruction-codes-x64.h',
-            '../../src/compiler/x64/instruction-selector-x64.cc',
-            '../../src/compiler/x64/linkage-x64.cc',
             '../../src/ic/x64/access-compiler-x64.cc',
             '../../src/ic/x64/handler-compiler-x64.cc',
             '../../src/ic/x64/ic-x64.cc',
@@ -1098,18 +1184,14 @@
             '../../src/ic/x64/stub-cache-x64.cc',
           ],
         }],
-        ['OS=="linux"', {
-            'link_settings': {
-              'conditions': [
-                ['v8_compress_startup_data=="bz2"', {
-                  'libraries': [
-                    '-lbz2',
-                  ]
-                }],
-              ],
-            },
-          }
-        ],
+        ['v8_target_arch=="x64"', {
+          'sources': [
+            '../../src/compiler/x64/code-generator-x64.cc',
+            '../../src/compiler/x64/instruction-codes-x64.h',
+            '../../src/compiler/x64/instruction-selector-x64.cc',
+            '../../src/compiler/x64/linkage-x64.cc',
+          ],
+        }],
         ['OS=="win"', {
           'variables': {
             'gyp_generators': '<!(echo $GYP_GENERATORS)',
@@ -1185,6 +1267,9 @@
         '../../src/base/division-by-constant.cc',
         '../../src/base/division-by-constant.h',
         '../../src/base/flags.h',
+        '../../src/base/functional.cc',
+        '../../src/base/functional.h',
+        '../../src/base/iterator.h',
         '../../src/base/lazy-instance.h',
         '../../src/base/logging.cc',
         '../../src/base/logging.h',
@@ -1217,11 +1302,19 @@
           'toolsets': ['target'],
         }],
         ['OS=="linux"', {
-            'link_settings': {
-              'libraries': [
-                '-lrt'
-              ]
-            },
+            'conditions': [
+              ['nacl_target_arch=="none"', {
+                'link_settings': {
+                  'libraries': [
+                    '-lrt'
+                  ],
+                },
+              }, {
+                'defines': [
+                  'V8_LIBRT_NOT_AVAILABLE=1',
+                ],
+              }],
+            ],
             'sources': [
               '../../src/base/platform/platform-linux.cc',
               '../../src/base/platform/platform-posix.cc'
@@ -1349,7 +1442,7 @@
         ['OS=="solaris"', {
             'link_settings': {
               'libraries': [
-                '-lnsl',
+                '-lnsl -lrt',
             ]},
             'sources': [
               '../../src/base/platform/platform-solaris.cc',
@@ -1385,8 +1478,6 @@
                   'sources': [
                     '../../src/base/platform/platform-win32.cc',
                     '../../src/base/win32-headers.h',
-                    '../../src/base/win32-math.cc',
-                    '../../src/base/win32-math.h'
                   ],
                 }],
               ],
@@ -1397,8 +1488,6 @@
               'sources': [
                 '../../src/base/platform/platform-win32.cc',
                 '../../src/base/win32-headers.h',
-                '../../src/base/win32-math.cc',
-                '../../src/base/win32-math.h'
               ],
               'msvs_disabled_warnings': [4351, 4355, 4800],
               'link_settings':  {
@@ -1523,7 +1612,7 @@
           '../../src/array.js',
           '../../src/string.js',
           '../../src/uri.js',
-          '../../third_party/fdlibm/fdlibm.js',
+          '../../src/third_party/fdlibm/fdlibm.js',
           '../../src/math.js',
           '../../src/apinatives.js',
           '../../src/date.js',
@@ -1551,7 +1640,12 @@
           '../../src/generator.js',
           '../../src/harmony-string.js',
           '../../src/harmony-array.js',
+          '../../src/harmony-array-includes.js',
+          '../../src/harmony-tostring.js',
+          '../../src/harmony-typedarray.js',
           '../../src/harmony-classes.js',
+          '../../src/harmony-templates.js',
+          '../../src/harmony-regexp.js'
         ],
         'libraries_bin_file': '<(SHARED_INTERMEDIATE_DIR)/libraries.bin',
         'libraries_experimental_bin_file': '<(SHARED_INTERMEDIATE_DIR)/libraries-experimental.bin',
@@ -1572,7 +1666,6 @@
             '../../tools/js2c.py',
             '<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
             'CORE',
-            '<(v8_compress_startup_data)',
             '<@(library_files)',
             '<@(i18n_library_files)',
           ],
@@ -1599,7 +1692,6 @@
             '../../tools/js2c.py',
             '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
             'EXPERIMENTAL',
-            '<(v8_compress_startup_data)',
             '<@(experimental_library_files)'
           ],
           'conditions': [
@@ -1652,16 +1744,17 @@
         '../../src/mksnapshot.cc',
       ],
       'conditions': [
+        ['v8_enable_i18n_support==1', {
+          'dependencies': [
+            '<(icu_gyp_path):icui18n',
+            '<(icu_gyp_path):icuuc',
+          ]
+        }],
         ['want_separate_host_toolset==1', {
           'toolsets': ['host'],
         }, {
           'toolsets': ['target'],
         }],
-        ['v8_compress_startup_data=="bz2"', {
-          'libraries': [
-            '-lbz2',
-          ]
-        }],
       ],
     },
   ],
diff --git a/tools/js2c.py b/tools/js2c.py
index 77485f6..621ed5a 100755
--- a/tools/js2c.py
+++ b/tools/js2c.py
@@ -255,8 +255,6 @@
 
 %(sources_declaration)s\
 
-%(raw_sources_declaration)s\
-
   template <>
   int NativesCollection<%(type)s>::GetBuiltinsCount() {
     return %(builtin_count)i;
@@ -274,13 +272,8 @@
   }
 
   template <>
-  int NativesCollection<%(type)s>::GetRawScriptsSize() {
-    return %(raw_total_length)i;
-  }
-
-  template <>
-  Vector<const char> NativesCollection<%(type)s>::GetRawScriptSource(int index) {
-%(get_raw_script_source_cases)s\
+  Vector<const char> NativesCollection<%(type)s>::GetScriptSource(int index) {
+%(get_script_source_cases)s\
     return Vector<const char>("", 0);
   }
 
@@ -291,32 +284,15 @@
   }
 
   template <>
-  Vector<const byte> NativesCollection<%(type)s>::GetScriptsSource() {
-    return Vector<const byte>(sources, %(total_length)i);
+  Vector<const char> NativesCollection<%(type)s>::GetScriptsSource() {
+    return Vector<const char>(sources, %(total_length)i);
   }
-
-  template <>
-  void NativesCollection<%(type)s>::SetRawScriptsSource(Vector<const char> raw_source) {
-    DCHECK(%(raw_total_length)i == raw_source.length());
-    raw_sources = raw_source.start();
-  }
-
 }  // internal
 }  // v8
 """
 
 SOURCES_DECLARATION = """\
-  static const byte sources[] = { %s };
-"""
-
-
-RAW_SOURCES_COMPRESSION_DECLARATION = """\
-  static const char* raw_sources = NULL;
-"""
-
-
-RAW_SOURCES_DECLARATION = """\
-  static const char* raw_sources = reinterpret_cast<const char*>(sources);
+  static const char sources[] = { %s };
 """
 
 
@@ -325,8 +301,8 @@
 """
 
 
-GET_RAW_SCRIPT_SOURCE_CASE = """\
-    if (index == %(i)i) return Vector<const char>(raw_sources + %(offset)i, %(raw_length)i);
+GET_SCRIPT_SOURCE_CASE = """\
+    if (index == %(i)i) return Vector<const char>(sources + %(offset)i, %(source_length)i);
 """
 
 
@@ -440,7 +416,7 @@
   # Loop over modules and build up indices into the source blob:
   get_index_cases = []
   get_script_name_cases = []
-  get_raw_script_source_cases = []
+  get_script_source_cases = []
   offset = 0
   for i in xrange(len(sources.modules)):
     native_name = "native %s.js" % sources.names[i]
@@ -450,57 +426,38 @@
         "name": native_name,
         "length": len(native_name),
         "offset": offset,
-        "raw_length": len(sources.modules[i]),
+        "source_length": len(sources.modules[i]),
     }
     get_index_cases.append(GET_INDEX_CASE % d)
     get_script_name_cases.append(GET_SCRIPT_NAME_CASE % d)
-    get_raw_script_source_cases.append(GET_RAW_SCRIPT_SOURCE_CASE % d)
+    get_script_source_cases.append(GET_SCRIPT_SOURCE_CASE % d)
     offset += len(sources.modules[i])
   assert offset == len(raw_sources)
 
-  # If we have the raw sources we can declare them accordingly.
-  have_raw_sources = source_bytes == raw_sources
-  raw_sources_declaration = (RAW_SOURCES_DECLARATION
-      if have_raw_sources else RAW_SOURCES_COMPRESSION_DECLARATION)
-
   metadata = {
     "builtin_count": len(sources.modules),
     "debugger_count": sum(sources.is_debugger_id),
     "sources_declaration": SOURCES_DECLARATION % ToCArray(source_bytes),
-    "raw_sources_declaration": raw_sources_declaration,
-    "raw_total_length": sum(map(len, sources.modules)),
     "total_length": total_length,
     "get_index_cases": "".join(get_index_cases),
-    "get_raw_script_source_cases": "".join(get_raw_script_source_cases),
+    "get_script_source_cases": "".join(get_script_source_cases),
     "get_script_name_cases": "".join(get_script_name_cases),
     "type": native_type,
   }
   return metadata
 
 
-def CompressMaybe(sources, compression_type):
-  """Take the prepared sources and generate a sequence of bytes.
-
-  Args:
-    sources: A Sources instance with the prepared sourced.
-    compression_type: string, describing the desired compression.
-
-  Returns:
-    A sequence of bytes.
-  """
-  sources_bytes = "".join(sources.modules)
-  if compression_type == "off":
-    return sources_bytes
-  elif compression_type == "bz2":
-    return bz2.compress(sources_bytes)
-  else:
-    raise Error("Unknown compression type %s." % compression_type)
-
-
 def PutInt(blob_file, value):
-  assert(value >= 0 and value < (1 << 20))
-  size = 1 if (value < 1 << 6) else (2 if (value < 1 << 14) else 3)
-  value_with_length = (value << 2) | size
+  assert(value >= 0 and value < (1 << 28))
+  if (value < 1 << 6):
+    size = 1
+  elif (value < 1 << 14):
+    size = 2
+  elif (value < 1 << 22):
+    size = 3
+  else:
+    size = 4
+  value_with_length = (value << 2) | (size - 1)
 
   byte_sequence = bytearray()
   for i in xrange(size):
@@ -538,9 +495,9 @@
   output.close()
 
 
-def JS2C(source, target, native_type, compression_type, raw_file, startup_blob):
+def JS2C(source, target, native_type, raw_file, startup_blob):
   sources = PrepareSources(source)
-  sources_bytes = CompressMaybe(sources, compression_type)
+  sources_bytes = "".join(sources.modules)
   metadata = BuildMetadata(sources, sources_bytes, native_type)
 
   # Optionally emit raw file.
@@ -564,14 +521,13 @@
                     help="file to write the processed sources array to.")
   parser.add_option("--startup_blob", action="store",
                     help="file to write the startup blob to.")
-  parser.set_usage("""js2c out.cc type compression sources.js ...
+  parser.set_usage("""js2c out.cc type sources.js ...
       out.cc: C code to be generated.
       type: type parameter for NativesCollection template.
-      compression: type of compression used. [off|bz2]
       sources.js: JS internal sources or macros.py.""")
   (options, args) = parser.parse_args()
 
-  JS2C(args[3:], args[0], args[1], args[2], options.raw, options.startup_blob)
+  JS2C(args[2:], args[0], args[1], options.raw, options.startup_blob)
 
 
 if __name__ == "__main__":
diff --git a/tools/lexer-shell.cc b/tools/lexer-shell.cc
deleted file mode 100644
index f8ddc02..0000000
--- a/tools/lexer-shell.cc
+++ /dev/null
@@ -1,236 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <assert.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string>
-#include <vector>
-#include "src/v8.h"
-
-#include "include/libplatform/libplatform.h"
-#include "src/api.h"
-#include "src/base/platform/platform.h"
-#include "src/messages.h"
-#include "src/runtime.h"
-#include "src/scanner-character-streams.h"
-#include "src/scopeinfo.h"
-#include "tools/shell-utils.h"
-#include "src/string-stream.h"
-#include "src/scanner.h"
-
-
-using namespace v8::internal;
-
-
-class BaselineScanner {
- public:
-  BaselineScanner(const char* fname,
-                  Isolate* isolate,
-                  Encoding encoding,
-                  v8::base::ElapsedTimer* timer,
-                  int repeat)
-      : stream_(NULL) {
-    int length = 0;
-    source_ = ReadFileAndRepeat(fname, &length, repeat);
-    unicode_cache_ = new UnicodeCache();
-    scanner_ = new Scanner(unicode_cache_);
-    switch (encoding) {
-      case UTF8:
-        stream_ = new Utf8ToUtf16CharacterStream(source_, length);
-        break;
-      case UTF16: {
-        Handle<String> result = isolate->factory()->NewStringFromTwoByte(
-            Vector<const uint16_t>(
-                reinterpret_cast<const uint16_t*>(source_),
-                length / 2)).ToHandleChecked();
-        stream_ =
-            new GenericStringUtf16CharacterStream(result, 0, result->length());
-        break;
-      }
-      case LATIN1: {
-        Handle<String> result = isolate->factory()->NewStringFromOneByte(
-            Vector<const uint8_t>(source_, length)).ToHandleChecked();
-        stream_ =
-            new GenericStringUtf16CharacterStream(result, 0, result->length());
-        break;
-      }
-    }
-    timer->Start();
-    scanner_->Initialize(stream_);
-  }
-
-  ~BaselineScanner() {
-    delete scanner_;
-    delete stream_;
-    delete unicode_cache_;
-    delete[] source_;
-  }
-
-  Token::Value Next(int* beg_pos, int* end_pos) {
-    Token::Value res = scanner_->Next();
-    *beg_pos = scanner_->location().beg_pos;
-    *end_pos = scanner_->location().end_pos;
-    return res;
-  }
-
- private:
-  UnicodeCache* unicode_cache_;
-  Scanner* scanner_;
-  const byte* source_;
-  BufferedUtf16CharacterStream* stream_;
-};
-
-
-struct TokenWithLocation {
-  Token::Value value;
-  size_t beg;
-  size_t end;
-  TokenWithLocation() : value(Token::ILLEGAL), beg(0), end(0) { }
-  TokenWithLocation(Token::Value value, size_t beg, size_t end) :
-      value(value), beg(beg), end(end) { }
-  bool operator==(const TokenWithLocation& other) {
-    return value == other.value && beg == other.beg && end == other.end;
-  }
-  bool operator!=(const TokenWithLocation& other) {
-    return !(*this == other);
-  }
-  void Print(const char* prefix) const {
-    printf("%s %11s at (%d, %d)\n",
-           prefix, Token::Name(value),
-           static_cast<int>(beg), static_cast<int>(end));
-  }
-};
-
-
-v8::base::TimeDelta RunBaselineScanner(const char* fname, Isolate* isolate,
-                                       Encoding encoding, bool dump_tokens,
-                                       std::vector<TokenWithLocation>* tokens,
-                                       int repeat) {
-  v8::base::ElapsedTimer timer;
-  BaselineScanner scanner(fname, isolate, encoding, &timer, repeat);
-  Token::Value token;
-  int beg, end;
-  do {
-    token = scanner.Next(&beg, &end);
-    if (dump_tokens) {
-      tokens->push_back(TokenWithLocation(token, beg, end));
-    }
-  } while (token != Token::EOS);
-  return timer.Elapsed();
-}
-
-
-void PrintTokens(const char* name,
-                 const std::vector<TokenWithLocation>& tokens) {
-  printf("No of tokens: %d\n",
-         static_cast<int>(tokens.size()));
-  printf("%s:\n", name);
-  for (size_t i = 0; i < tokens.size(); ++i) {
-    tokens[i].Print("=>");
-  }
-}
-
-
-v8::base::TimeDelta ProcessFile(
-    const char* fname,
-    Encoding encoding,
-    Isolate* isolate,
-    bool print_tokens,
-    int repeat) {
-  if (print_tokens) {
-    printf("Processing file %s\n", fname);
-  }
-  HandleScope handle_scope(isolate);
-  std::vector<TokenWithLocation> baseline_tokens;
-  v8::base::TimeDelta baseline_time;
-  baseline_time = RunBaselineScanner(
-      fname, isolate, encoding, print_tokens,
-      &baseline_tokens, repeat);
-  if (print_tokens) {
-    PrintTokens("Baseline", baseline_tokens);
-  }
-  return baseline_time;
-}
-
-
-int main(int argc, char* argv[]) {
-  v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
-  v8::V8::InitializeICU();
-  v8::Platform* platform = v8::platform::CreateDefaultPlatform();
-  v8::V8::InitializePlatform(platform);
-  v8::V8::Initialize();
-  Encoding encoding = LATIN1;
-  bool print_tokens = false;
-  std::vector<std::string> fnames;
-  std::string benchmark;
-  int repeat = 1;
-  for (int i = 0; i < argc; ++i) {
-    if (strcmp(argv[i], "--latin1") == 0) {
-      encoding = LATIN1;
-    } else if (strcmp(argv[i], "--utf8") == 0) {
-      encoding = UTF8;
-    } else if (strcmp(argv[i], "--utf16") == 0) {
-      encoding = UTF16;
-    } else if (strcmp(argv[i], "--print-tokens") == 0) {
-      print_tokens = true;
-    } else if (strncmp(argv[i], "--benchmark=", 12) == 0) {
-      benchmark = std::string(argv[i]).substr(12);
-    } else if (strncmp(argv[i], "--repeat=", 9) == 0) {
-      std::string repeat_str = std::string(argv[i]).substr(9);
-      repeat = atoi(repeat_str.c_str());
-    } else if (i > 0 && argv[i][0] != '-') {
-      fnames.push_back(std::string(argv[i]));
-    }
-  }
-  v8::Isolate* isolate = v8::Isolate::New();
-  {
-    v8::Isolate::Scope isolate_scope(isolate);
-    v8::HandleScope handle_scope(isolate);
-    v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
-    v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
-    DCHECK(!context.IsEmpty());
-    {
-      v8::Context::Scope scope(context);
-      double baseline_total = 0;
-      for (size_t i = 0; i < fnames.size(); i++) {
-        v8::base::TimeDelta time;
-        time = ProcessFile(fnames[i].c_str(), encoding,
-                           reinterpret_cast<Isolate*>(isolate), print_tokens,
-                           repeat);
-        baseline_total += time.InMillisecondsF();
-      }
-      if (benchmark.empty()) benchmark = "Baseline";
-      printf("%s(RunTime): %.f ms\n", benchmark.c_str(), baseline_total);
-    }
-  }
-  v8::V8::Dispose();
-  v8::V8::ShutdownPlatform();
-  delete platform;
-  return 0;
-}
diff --git a/tools/lexer-shell.gyp b/tools/lexer-shell.gyp
deleted file mode 100644
index 836ea97..0000000
--- a/tools/lexer-shell.gyp
+++ /dev/null
@@ -1,82 +0,0 @@
-# Copyright 2013 the V8 project authors. All rights reserved.
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-#       notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-#       copyright notice, this list of conditions and the following
-#       disclaimer in the documentation and/or other materials provided
-#       with the distribution.
-#     * Neither the name of Google Inc. nor the names of its
-#       contributors may be used to endorse or promote products derived
-#       from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
-  'variables': {
-    'v8_code': 1,
-    'v8_enable_i18n_support%': 1,
-  },
-  'includes': ['../build/toolchain.gypi', '../build/features.gypi'],
-  'targets': [
-    {
-      'target_name': 'lexer-shell',
-      'type': 'executable',
-      'dependencies': [
-        '../tools/gyp/v8.gyp:v8',
-        '../tools/gyp/v8.gyp:v8_libplatform',
-      ],
-      'conditions': [
-        ['v8_enable_i18n_support==1', {
-          'dependencies': [
-            '<(icu_gyp_path):icui18n',
-            '<(icu_gyp_path):icuuc',
-          ],
-        }],
-      ],
-      'include_dirs+': [
-        '..',
-      ],
-      'sources': [
-        'lexer-shell.cc',
-        'shell-utils.h',
-      ],
-    },
-    {
-      'target_name': 'parser-shell',
-      'type': 'executable',
-      'dependencies': [
-        '../tools/gyp/v8.gyp:v8',
-        '../tools/gyp/v8.gyp:v8_libplatform',
-      ],
-      'conditions': [
-        ['v8_enable_i18n_support==1', {
-          'dependencies': [
-            '<(icu_gyp_path):icui18n',
-            '<(icu_gyp_path):icuuc',
-          ],
-        }],
-      ],
-      'include_dirs+': [
-        '..',
-      ],
-      'sources': [
-        'parser-shell.cc',
-        'shell-utils.h',
-      ],
-    },
-  ],
-}
diff --git a/tools/logreader.js b/tools/logreader.js
index a8141da..5f0ec7f 100644
--- a/tools/logreader.js
+++ b/tools/logreader.js
@@ -108,6 +108,8 @@
     // Filter out possible 'overflow' string.
     } else if (firstChar != 'o') {
       fullStack.push(parseInt(frame, 16));
+    } else {
+      print("dropping: " + frame);
     }
   }
   return fullStack;
diff --git a/tools/nacl-run.py b/tools/nacl-run.py
index 135172c..32055fe 100755
--- a/tools/nacl-run.py
+++ b/tools/nacl-run.py
@@ -32,6 +32,7 @@
 
 import os
 from os.path import join, dirname, abspath
+import re
 import subprocess
 import sys
 import tempfile
@@ -82,7 +83,7 @@
   try:
     p = subprocess.Popen(['file', nexe], stdout=subprocess.PIPE)
     out, err = p.communicate()
-    lines = out.split('\n')
+    lines = [re.sub("\s+", " " , line) for line in out.split('\n')]
     if lines[0].find(": ELF 32-bit LSB executable, Intel 80386") > 0:
       return "x86_32"
     if lines[0].find(": ELF 64-bit LSB executable, x86-64") > 0:
@@ -116,17 +117,13 @@
     print("NaCl V8 ARM support is not ready yet.")
     sys.exit(1)
   else:
-    print("Invalid nexe %s" % nexe)
+    print("Invalid nexe %s with NaCl arch %s" % (nexe, nacl_arch))
     sys.exit(1)
 
   nacl_sel_ldr = os.path.join(nacl_sdk_dir, "tools", sel_ldr)
   nacl_irt = os.path.join(nacl_sdk_dir, "tools", irt)
-  nacl_ld_so = os.path.join(nacl_sdk_dir, "toolchain", toolchain,
-                            "x86_64-nacl", libdir, "runnable-ld.so")
-  nacl_lib_path = os.path.join(nacl_sdk_dir, "toolchain", toolchain,
-                               "x86_64-nacl", libdir)
 
-  return (nacl_sdk_dir, nacl_sel_ldr, nacl_irt, nacl_ld_so, nacl_lib_path)
+  return (nacl_sdk_dir, nacl_sel_ldr, nacl_irt)
 
 def Main():
   if (len(sys.argv) == 1):
@@ -135,15 +132,14 @@
 
   args = [Escape(arg) for arg in sys.argv[1:]]
 
-  (nacl_sdk_dir, nacl_sel_ldr, nacl_irt, nacl_ld_so,
-   nacl_lib_path) = GetNaClResources(sys.argv[1])
+  (nacl_sdk_dir, nacl_sel_ldr, nacl_irt) = GetNaClResources(sys.argv[1])
 
   # sel_ldr Options:
   # -c -c: disable validation (for performance)
   # -a: allow file access
   # -B <irt>: load the IRT
-  command = ' '.join([nacl_sel_ldr, '-c', '-c', '-a', '-B', nacl_irt, '--',
-                     nacl_ld_so, '--library-path', nacl_lib_path] + args)
+  command = ' '.join([nacl_sel_ldr, '-c', '-c', '-a', '-B', nacl_irt, '--'] +
+                     args)
   error_code = Execute(command)
   return error_code
 
diff --git a/tools/parser-shell.gyp b/tools/parser-shell.gyp
new file mode 100644
index 0000000..f0f0b8b
--- /dev/null
+++ b/tools/parser-shell.gyp
@@ -0,0 +1,59 @@
+# Copyright 2013 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+{
+  'variables': {
+    'v8_code': 1,
+    'v8_enable_i18n_support%': 1,
+  },
+  'includes': ['../build/toolchain.gypi', '../build/features.gypi'],
+  'targets': [
+    {
+      'target_name': 'parser-shell',
+      'type': 'executable',
+      'dependencies': [
+        '../tools/gyp/v8.gyp:v8',
+        '../tools/gyp/v8.gyp:v8_libplatform',
+      ],
+      'conditions': [
+        ['v8_enable_i18n_support==1', {
+          'dependencies': [
+            '<(icu_gyp_path):icui18n',
+            '<(icu_gyp_path):icuuc',
+          ],
+        }],
+      ],
+      'include_dirs+': [
+        '..',
+      ],
+      'sources': [
+        'parser-shell.cc',
+        'shell-utils.h',
+      ],
+    },
+  ],
+}
diff --git a/tools/presubmit.py b/tools/presubmit.py
index 8a6ff2a..321d291 100755
--- a/tools/presubmit.py
+++ b/tools/presubmit.py
@@ -236,7 +236,8 @@
               or (name in CppLintProcessor.IGNORE_LINT))
 
   def GetPathsToSearch(self):
-    return ['src', 'include', 'samples', join('test', 'cctest')]
+    return ['src', 'include', 'samples', join('test', 'cctest'),
+            join('test', 'unittests')]
 
   def GetCpplintScript(self, prio_path):
     for path in [prio_path] + os.environ["PATH"].split(os.pathsep):
@@ -326,16 +327,25 @@
     return (super(SourceProcessor, self).IgnoreDir(name) or
             name in ('third_party', 'gyp', 'out', 'obj', 'DerivedSources'))
 
-  IGNORE_COPYRIGHTS = ['cpplint.py',
+  IGNORE_COPYRIGHTS = ['box2d.js',
+                       'cpplint.py',
+                       'copy.js',
+                       'corrections.js',
+                       'crypto.js',
                        'daemon.py',
                        'earley-boyer.js',
-                       'raytrace.js',
-                       'crypto.js',
+                       'fannkuch.js',
+                       'fasta.js',
+                       'jsmin.py',
                        'libraries.cc',
                        'libraries-empty.cc',
-                       'jsmin.py',
+                       'lua_binarytrees.js',
+                       'memops.js',
+                       'primes.js',
+                       'raytrace.js',
                        'regexp-pcre.js',
-                       'gnuplot-4.6.3-emscripten.js']
+                       'gnuplot-4.6.3-emscripten.js',
+                       'zlib.js']
   IGNORE_TABS = IGNORE_COPYRIGHTS + ['unicode-test.js', 'html-comments.js']
 
   def EndOfDeclaration(self, line):
diff --git a/tools/profile.js b/tools/profile.js
index 10a07f8..a06cd3a 100644
--- a/tools/profile.js
+++ b/tools/profile.js
@@ -36,6 +36,7 @@
   this.codeMap_ = new CodeMap();
   this.topDownTree_ = new CallTree();
   this.bottomUpTree_ = new CallTree();
+  this.c_entries_ = {};
 };
 
 
@@ -102,7 +103,7 @@
 Profile.prototype.addLibrary = function(
     name, startAddr, endAddr) {
   var entry = new CodeMap.CodeEntry(
-      endAddr - startAddr, name);
+      endAddr - startAddr, name, 'SHARED_LIB');
   this.codeMap_.addLibrary(startAddr, entry);
   return entry;
 };
@@ -118,7 +119,7 @@
 Profile.prototype.addStaticCode = function(
     name, startAddr, endAddr) {
   var entry = new CodeMap.CodeEntry(
-      endAddr - startAddr, name);
+      endAddr - startAddr, name, 'CPP');
   this.codeMap_.addStaticCode(startAddr, entry);
   return entry;
 };
@@ -250,10 +251,26 @@
  */
 Profile.prototype.resolveAndFilterFuncs_ = function(stack) {
   var result = [];
+  var last_seen_c_function = '';
+  var look_for_first_c_function = false;
   for (var i = 0; i < stack.length; ++i) {
     var entry = this.codeMap_.findEntry(stack[i]);
     if (entry) {
       var name = entry.getName();
+      if (i == 0 && (entry.type == 'CPP' || entry.type == 'SHARED_LIB')) {
+        look_for_first_c_function = true;
+      }
+      if (look_for_first_c_function) {
+        if (entry.type == 'CPP') {
+          last_seen_c_function = name;
+        } else if (i > 0 && last_seen_c_function != '') {
+          if (this.c_entries_[last_seen_c_function] === undefined) {
+            this.c_entries_[last_seen_c_function] = 0;
+          }
+          this.c_entries_[last_seen_c_function]++;
+          look_for_first_c_function = false;  // Found it, we're done.
+        }
+      }
       if (!this.skipThisFunction(name)) {
         result.push(name);
       }
@@ -381,6 +398,28 @@
 };
 
 
+Profile.CEntryNode = function(name, ticks) {
+  this.name = name;
+  this.ticks = ticks;
+}
+
+
+Profile.prototype.getCEntryProfile = function() {
+  var result = [new Profile.CEntryNode("TOTAL", 0)];
+  var total_ticks = 0;
+  for (var f in this.c_entries_) {
+    var ticks = this.c_entries_[f];
+    total_ticks += ticks;
+    result.push(new Profile.CEntryNode(f, ticks));
+  }
+  result[0].ticks = total_ticks;  // Sorting will keep this at index 0.
+  result.sort(function(n1, n2) {
+    return n2.ticks - n1.ticks || (n2.name < n1.name ? -1 : 1)
+  });
+  return result;
+}
+
+
 /**
  * Cleans up function entries that are not referenced by code entries.
  */
@@ -415,8 +454,7 @@
  * @constructor
  */
 Profile.DynamicCodeEntry = function(size, type, name) {
-  CodeMap.CodeEntry.call(this, size, name);
-  this.type = type;
+  CodeMap.CodeEntry.call(this, size, name, type);
 };
 
 
@@ -456,8 +494,7 @@
  * @constructor
  */
 Profile.DynamicFuncCodeEntry = function(size, type, func, state) {
-  CodeMap.CodeEntry.call(this, size);
-  this.type = type;
+  CodeMap.CodeEntry.call(this, size, '', type);
   this.func = func;
   this.state = state;
 };
diff --git a/tools/push-to-trunk/auto_push.py b/tools/push-to-trunk/auto_push.py
index fef3b53..34afa4a 100755
--- a/tools/push-to-trunk/auto_push.py
+++ b/tools/push-to-trunk/auto_push.py
@@ -36,7 +36,7 @@
 from common_includes import *
 import push_to_trunk
 
-PUSH_MESSAGE_RE = re.compile(r".* \(based on bleeding_edge revision r(\d+)\)$")
+PUSH_MESSAGE_RE = re.compile(r".* \(based on ([a-fA-F0-9]+)\)$")
 
 class Preparation(Step):
   MESSAGE = "Preparation."
@@ -70,13 +70,12 @@
                % self["tree_message"])
 
 
-class FetchLKGR(Step):
-  MESSAGE = "Fetching V8 LKGR."
+class FetchCandidate(Step):
+  MESSAGE = "Fetching V8 roll candidate ref."
 
   def RunStep(self):
-    lkgr_url = "https://v8-status.appspot.com/lkgr"
-    # Retry several times since app engine might have issues.
-    self["lkgr"] = self.ReadURL(lkgr_url, wait_plan=[5, 20, 300, 300])
+    self.Git("fetch origin +refs/heads/candidate:refs/heads/candidate")
+    self["candidate"] = self.Git("show-ref -s refs/heads/candidate").strip()
 
 
 class CheckLastPush(Step):
@@ -94,28 +93,30 @@
       self.Die("Could not retrieve bleeding edge revision for trunk push %s"
                % last_push)
 
-    # TODO(machenbach): This metric counts all revisions. It could be
-    # improved by counting only the revisions on bleeding_edge.
-    if int(self["lkgr"]) - int(last_push_be) < 10:  # pragma: no cover
-      # This makes sure the script doesn't push twice in a row when the cron
-      # job retries several times.
-      self.Die("Last push too recently: %s" % last_push_be)
+    if self["candidate"] == last_push_be:
+      print "Already pushed current candidate %s" % last_push_be
+      return True
 
 
-class PushToTrunk(Step):
-  MESSAGE = "Pushing to trunk if specified."
+class PushToCandidates(Step):
+  MESSAGE = "Pushing to candidates if specified."
 
   def RunStep(self):
-    print "Pushing lkgr %s to trunk." % self["lkgr"]
+    print "Pushing candidate %s to candidates." % self["candidate"]
+
+    args = [
+      "--author", self._options.author,
+      "--reviewer", self._options.reviewer,
+      "--revision", self["candidate"],
+      "--force",
+    ]
+
+    if self._options.work_dir:
+      args.extend(["--work-dir", self._options.work_dir])
 
     # TODO(machenbach): Update the script before calling it.
     if self._options.push:
-      self._side_effect_handler.Call(
-          push_to_trunk.PushToTrunk().Run,
-          ["--author", self._options.author,
-           "--reviewer", self._options.reviewer,
-           "--revision", self["lkgr"],
-           "--force"])
+      self._side_effect_handler.Call(push_to_trunk.PushToTrunk().Run, args)
 
 
 class AutoPush(ScriptsBase):
@@ -142,9 +143,9 @@
       Preparation,
       CheckAutoPushSettings,
       CheckTreeStatus,
-      FetchLKGR,
+      FetchCandidate,
       CheckLastPush,
-      PushToTrunk,
+      PushToCandidates,
     ]
 
 
diff --git a/tools/push-to-trunk/auto_roll.py b/tools/push-to-trunk/auto_roll.py
index 120e633..1b57097 100755
--- a/tools/push-to-trunk/auto_roll.py
+++ b/tools/push-to-trunk/auto_roll.py
@@ -42,8 +42,9 @@
   MESSAGE = "Detect commit ID of the last push to trunk."
 
   def RunStep(self):
+    self.vc.Fetch()
     push_hash = self.FindLastTrunkPush(
-        branch="origin/master", include_patches=True)
+        branch="origin/candidates", include_patches=True)
     self["last_push"] = self.GetCommitPositionNumber(push_hash)
 
 
@@ -99,6 +100,8 @@
             "--sheriff", "--googlers-mapping", self._options.googlers_mapping])
       if self._options.dry_run:
         args.extend(["--dry-run"])
+      if self._options.work_dir:
+        args.extend(["--work-dir", self._options.work_dir])
       self._side_effect_handler.Call(chromium_roll.ChromiumRoll().Run, args)
 
 
diff --git a/tools/push-to-trunk/auto_tag.py b/tools/push-to-trunk/auto_tag.py
index 175e10e..a52a028 100755
--- a/tools/push-to-trunk/auto_tag.py
+++ b/tools/push-to-trunk/auto_tag.py
@@ -13,10 +13,15 @@
   MESSAGE = "Preparation."
 
   def RunStep(self):
+    # TODO(machenbach): Remove after the git switch.
+    if self.Config("PERSISTFILE_BASENAME") == "/tmp/v8-auto-tag-tempfile":
+      print "This script is disabled until after the v8 git migration."
+      return True
+
     self.CommonPrepare()
     self.PrepareBranch()
     self.GitCheckout("master")
-    self.GitSVNRebase()
+    self.vc.Pull()
 
 
 class GetTags(Step):
@@ -24,13 +29,7 @@
 
   def RunStep(self):
     self.GitCreateBranch(self._config["BRANCHNAME"])
-
-    # Get remote tags.
-    tags = filter(lambda s: re.match(r"^svn/tags/[\d+\.]+$", s),
-                  self.GitRemotes())
-
-    # Remove 'svn/tags/' prefix.
-    self["tags"] = map(lambda s: s[9:], tags)
+    self["tags"] = self.vc.GetTags()
 
 
 class GetOldestUntaggedVersion(Step):
@@ -114,9 +113,9 @@
 
   def RunStep(self):
     # Get the lkgr after the tag candidate and before the next tag candidate.
-    candidate_svn = self.GitSVNFindSVNRev(self["candidate"])
+    candidate_svn = self.vc.GitSvn(self["candidate"])
     if self["next"]:
-      next_svn = self.GitSVNFindSVNRev(self["next"])
+      next_svn = self.vc.GitSvn(self["next"])
     else:
       # Don't include the version change commit itself if there is no upper
       # limit yet.
@@ -130,7 +129,7 @@
       return True
 
     # Let's check if the lkgr is at least three hours old.
-    self["lkgr"] = self.GitSVNFindGitHash(lkgr_svn)
+    self["lkgr"] = self.vc.SvnGit(lkgr_svn)
     if not self["lkgr"]:
       print "Couldn't find git hash for lkgr %s" % lkgr_svn
       self.CommonCleanup()
@@ -153,7 +152,10 @@
   def RunStep(self):
     if not self._options.dry_run:
       self.GitReset(self["lkgr"])
-      self.GitSVNTag(self["candidate_version"])
+      # FIXME(machenbach): Make this work with the git repo.
+      self.vc.Tag(self["candidate_version"],
+                  "svn/bleeding_edge",
+                  "This won't work!")
 
 
 class CleanUp(Step):
diff --git a/tools/push-to-trunk/bump_up_version.py b/tools/push-to-trunk/bump_up_version.py
index c9f052b..647708c 100755
--- a/tools/push-to-trunk/bump_up_version.py
+++ b/tools/push-to-trunk/bump_up_version.py
@@ -28,17 +28,23 @@
 VERSION_BRANCH = "auto-bump-up-version"
 
 
+# TODO(machenbach): Add vc interface that works on git mirror.
 class Preparation(Step):
   MESSAGE = "Preparation."
 
   def RunStep(self):
+    # TODO(machenbach): Remove after the git switch.
+    if(self.Config("PERSISTFILE_BASENAME") ==
+       "/tmp/v8-bump-up-version-tempfile"):
+      print "This script is disabled until after the v8 git migration."
+      return True
+
     # Check for a clean workdir.
     if not self.GitIsWorkdirClean():  # pragma: no cover
       # This is in case a developer runs this script on a dirty tree.
       self.GitStash()
 
-    # TODO(machenbach): This should be called master after the git switch.
-    self.GitCheckout("bleeding_edge")
+    self.GitCheckout("master")
 
     self.GitPull()
 
@@ -50,8 +56,7 @@
   MESSAGE = "Get latest bleeding edge version."
 
   def RunStep(self):
-    # TODO(machenbach): This should be called master after the git switch.
-    self.GitCheckout("bleeding_edge")
+    self.GitCheckout("master")
 
     # Store latest version and revision.
     self.ReadAndPersistVersion()
@@ -88,7 +93,7 @@
   MESSAGE = "Get bleeding edge lkgr version."
 
   def RunStep(self):
-    self.GitCheckout("bleeding_edge")
+    self.GitCheckout("master")
     # If the commit was made from svn, there is a mapping entry in the commit
     # message.
     self["lkgr"] = self.GitLog(
@@ -106,7 +111,7 @@
     print "LKGR version: %s" % self["lkgr_version"]
 
     # Ensure a clean version branch.
-    self.GitCheckout("bleeding_edge")
+    self.GitCheckout("master")
     self.DeleteBranch(VERSION_BRANCH)
 
 
@@ -131,8 +136,7 @@
   MESSAGE = "Get latest trunk version."
 
   def RunStep(self):
-    # TODO(machenbach): This should be called trunk after the git switch.
-    self.GitCheckout("master")
+    self.GitCheckout("candidates")
     self.GitPull()
     self.ReadAndPersistVersion("trunk_")
     self["trunk_version"] = self.ArrayToVersion("trunk_")
@@ -186,7 +190,7 @@
   MESSAGE = "Bump up the version."
 
   def RunStep(self):
-    self.GitCreateBranch(VERSION_BRANCH, "bleeding_edge")
+    self.GitCreateBranch(VERSION_BRANCH, "master")
 
     self.SetVersion(os.path.join(self.default_cwd, VERSION_FILE), "new_")
 
@@ -194,17 +198,14 @@
       msg = "[Auto-roll] Bump up version to %s" % self["new_version"]
       self.GitCommit("%s\n\nTBR=%s" % (msg, self._options.author),
                      author=self._options.author)
-      if self._options.svn:
-        self.SVNCommit("branches/bleeding_edge", msg)
-      else:
-        self.GitUpload(author=self._options.author,
-                       force=self._options.force_upload,
-                       bypass_hooks=True)
-        self.GitDCommit()
+      self.GitUpload(author=self._options.author,
+                     force=self._options.force_upload,
+                     bypass_hooks=True)
+      self.GitCLLand()
       print "Successfully changed the version."
     finally:
       # Clean up.
-      self.GitCheckout("bleeding_edge")
+      self.GitCheckout("master")
       self.DeleteBranch(VERSION_BRANCH)
 
 
@@ -225,6 +226,7 @@
   def _Config(self):
     return {
       "PERSISTFILE_BASENAME": "/tmp/v8-bump-up-version-tempfile",
+      "PATCH_FILE": "/tmp/v8-bump-up-version-tempfile-patch-file",
     }
 
   def _Steps(self):
diff --git a/tools/push-to-trunk/check_clusterfuzz.py b/tools/push-to-trunk/check_clusterfuzz.py
new file mode 100755
index 0000000..d4ba90b
--- /dev/null
+++ b/tools/push-to-trunk/check_clusterfuzz.py
@@ -0,0 +1,174 @@
+#!/usr/bin/env python
+# Copyright 2014 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Script to check for new clusterfuzz issues since the last rolled v8 revision.
+
+Returns a json list with test case IDs if any.
+
+Security considerations: The security key and request data must never be
+written to public logs. Public automated callers of this script should
+suppress stdout and stderr and only process contents of the results_file.
+"""
+
+
+import argparse
+import httplib
+import json
+import os
+import re
+import sys
+import urllib
+import urllib2
+
+
+# Constants to git repos.
+BASE_URL = "https://chromium.googlesource.com"
+DEPS_LOG = BASE_URL + "/chromium/src/+log/master/DEPS?format=JSON"
+
+# Constants for retrieving v8 rolls.
+CRREV = "https://cr-rev.appspot.com/_ah/api/crrev/v1/commit/%s"
+V8_COMMIT_RE = re.compile(
+    r"^Update V8 to version \d+\.\d+\.\d+ \(based on ([a-fA-F0-9]+)\)\..*")
+
+# Constants for the clusterfuzz backend.
+HOSTNAME = "backend-dot-cluster-fuzz.appspot.com"
+
+# Crash patterns.
+V8_INTERNAL_RE = re.compile(r"^v8::internal.*")
+ANY_RE = re.compile(r".*")
+
+# List of all api requests.
+BUG_SPECS = [
+  {
+    "args": {
+      "job_type": "linux_asan_chrome_v8",
+      "reproducible": "True",
+      "open": "True",
+      "bug_information": "",
+    },
+    "crash_state": V8_INTERNAL_RE,
+  },
+  {
+    "args": {
+      "job_type": "linux_asan_d8_dbg",
+      "reproducible": "True",
+      "open": "True",
+      "bug_information": "",
+    },
+    "crash_state": ANY_RE,
+  },
+]
+
+
+def GetRequest(url):
+  url_fh = urllib2.urlopen(url, None, 60)
+  try:
+    return url_fh.read()
+  finally:
+    url_fh.close()
+
+
+def GetLatestV8InChromium():
+  """Returns the commit position number of the latest v8 roll in chromium."""
+
+  # Check currently rolled v8 revision.
+  result = GetRequest(DEPS_LOG)
+  if not result:
+    return None
+
+  # Strip security header and load json.
+  commits = json.loads(result[5:])
+
+  git_revision = None
+  for commit in commits["log"]:
+    # Get latest commit that matches the v8 roll pattern. Ignore cherry-picks.
+    match = re.match(V8_COMMIT_RE, commit["message"])
+    if match:
+      git_revision = match.group(1)
+      break
+  else:
+    return None
+
+  # Get commit position number for v8 revision.
+  result = GetRequest(CRREV % git_revision)
+  if not result:
+    return None
+
+  commit = json.loads(result)
+  assert commit["repo"] == "v8/v8"
+  return commit["number"]
+
+
+def APIRequest(key, **params):
+  """Send a request to the clusterfuzz api.
+
+  Returns a json dict of the response.
+  """
+
+  params["api_key"] = key
+  params = urllib.urlencode(params)
+
+  headers = {"Content-type": "application/x-www-form-urlencoded"}
+
+  try:
+    conn = httplib.HTTPSConnection(HOSTNAME)
+    conn.request("POST", "/_api/", params, headers)
+
+    response = conn.getresponse()
+
+    # Never leak "data" into public logs.
+    data = response.read()
+  except:
+    raise Exception("ERROR: Connection problem.")
+
+  try:
+    return json.loads(data)
+  except:
+    raise Exception("ERROR: Could not read response. Is your key valid?")
+
+  return None
+
+
+def Main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument("-k", "--key-file", required=True,
+                      help="A file with the clusterfuzz api key.")
+  parser.add_argument("-r", "--results-file",
+                      help="A file to write the results to.")
+  options = parser.parse_args()
+
+  # Get api key. The key's content must never be logged.
+  assert options.key_file
+  with open(options.key_file) as f:
+    key = f.read().strip()
+  assert key
+
+  revision_number = GetLatestV8InChromium()
+
+  results = []
+  for spec in BUG_SPECS:
+    args = dict(spec["args"])
+    # Use incremented revision as we're interested in all revision greater than
+    # what's currently rolled into chromium.
+    if revision_number:
+      args["revision_greater_or_equal"] = str(int(revision_number) + 1)
+
+    # Never print issue details in public logs.
+    issues = APIRequest(key, **args)
+    assert issues is not None
+    for issue in issues:
+      if re.match(spec["crash_state"], issue["crash_state"]):
+        results.append(issue["id"])
+
+  if options.results_file:
+    with open(options.results_file, "w") as f:
+      f.write(json.dumps(results))
+  else:
+    print results
+
+
+if __name__ == "__main__":
+  sys.exit(Main())
diff --git a/tools/push-to-trunk/chromium_roll.py b/tools/push-to-trunk/chromium_roll.py
index dc5e6eb..5c9a38e 100755
--- a/tools/push-to-trunk/chromium_roll.py
+++ b/tools/push-to-trunk/chromium_roll.py
@@ -23,8 +23,7 @@
 
   def RunStep(self):
     self["last_push"] = self._options.last_push or self.FindLastTrunkPush(
-        branch="origin/master", include_patches=True)
-    self["trunk_revision"] = self.GetCommitPositionNumber(self["last_push"])
+        branch="origin/candidates", include_patches=True)
     self["push_title"] = self.GitLog(n=1, format="%s",
                                      git_hash=self["last_push"])
 
@@ -56,7 +55,7 @@
     # Update v8 remotes.
     self.GitFetchOrigin()
 
-    self.GitCreateBranch("v8-roll-%s" % self["trunk_revision"],
+    self.GitCreateBranch("v8-roll-%s" % self["last_push"],
                          cwd=self._options.chromium)
 
 
@@ -66,9 +65,9 @@
   def RunStep(self):
     # Patch DEPS file.
     if self.Command(
-        "roll-dep", "v8 %s" % self["trunk_revision"],
+        "roll-dep", "v8 %s" % self["last_push"],
         cwd=self._options.chromium) is None:
-      self.Die("Failed to create deps for %s" % self["trunk_revision"])
+      self.Die("Failed to create deps for %s" % self["last_push"])
 
     commit_title = "Update V8 to %s." % self["push_title"].lower()
     sheriff = ""
@@ -87,7 +86,7 @@
       print "CL uploaded."
     else:
       self.GitCheckout("master", cwd=self._options.chromium)
-      self.GitDeleteBranch("v8-roll-%s" % self["trunk_revision"],
+      self.GitDeleteBranch("v8-roll-%s" % self["last_push"],
                            cwd=self._options.chromium)
       print "Dry run - don't upload."
 
@@ -105,9 +104,9 @@
   MESSAGE = "Done!"
 
   def RunStep(self):
-    print("Congratulations, you have successfully rolled the push r%s it into "
+    print("Congratulations, you have successfully rolled %s into "
           "Chromium. Please don't forget to update the v8rel spreadsheet."
-          % self["trunk_revision"])
+          % self["last_push"])
 
     # Clean up all temporary files.
     Command("rm", "-f %s*" % self._config["PERSISTFILE_BASENAME"])
diff --git a/tools/push-to-trunk/common_includes.py b/tools/push-to-trunk/common_includes.py
index 00fb097..ac78ef8 100644
--- a/tools/push-to-trunk/common_includes.py
+++ b/tools/push-to-trunk/common_includes.py
@@ -45,10 +45,11 @@
 from git_recipes import GitRecipesMixin
 from git_recipes import GitFailedException
 
+CHANGELOG_FILE = "ChangeLog"
 VERSION_FILE = os.path.join("src", "version.cc")
 
 # V8 base directory.
-DEFAULT_CWD = os.path.dirname(
+V8_BASE = os.path.dirname(
     os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 
 
@@ -255,6 +256,107 @@
   pass
 
 
+class VCInterface(object):
+  def InjectStep(self, step):
+    self.step=step
+
+  def Pull(self):
+    raise NotImplementedError()
+
+  def Fetch(self):
+    raise NotImplementedError()
+
+  def GetTags(self):
+    raise NotImplementedError()
+
+  def GetBranches(self):
+    raise NotImplementedError()
+
+  def MasterBranch(self):
+    raise NotImplementedError()
+
+  def CandidateBranch(self):
+    raise NotImplementedError()
+
+  def RemoteMasterBranch(self):
+    raise NotImplementedError()
+
+  def RemoteCandidateBranch(self):
+    raise NotImplementedError()
+
+  def RemoteBranch(self, name):
+    raise NotImplementedError()
+
+  def CLLand(self):
+    raise NotImplementedError()
+
+  def Tag(self, tag, remote, message):
+    """Sets a tag for the current commit.
+
+    Assumptions: The commit already landed and the commit message is unique.
+    """
+    raise NotImplementedError()
+
+
+class GitInterface(VCInterface):
+  def Pull(self):
+    self.step.GitPull()
+
+  def Fetch(self):
+    self.step.Git("fetch")
+
+  def GetTags(self):
+     return self.step.Git("tag").strip().splitlines()
+
+  def GetBranches(self):
+    # Get relevant remote branches, e.g. "branch-heads/3.25".
+    branches = filter(
+        lambda s: re.match(r"^branch\-heads/\d+\.\d+$", s),
+        self.step.GitRemotes())
+    # Remove 'branch-heads/' prefix.
+    return map(lambda s: s[13:], branches)
+
+  def MasterBranch(self):
+    return "master"
+
+  def CandidateBranch(self):
+    return "candidates"
+
+  def RemoteMasterBranch(self):
+    return "origin/master"
+
+  def RemoteCandidateBranch(self):
+    return "origin/candidates"
+
+  def RemoteBranch(self, name):
+    if name in ["candidates", "master"]:
+      return "origin/%s" % name
+    return "branch-heads/%s" % name
+
+  def Tag(self, tag, remote, message):
+    # Wait for the commit to appear. Assumes unique commit message titles (this
+    # is the case for all automated merge and push commits - also no title is
+    # the prefix of another title).
+    commit = None
+    for wait_interval in [3, 7, 15, 35, 45, 60]:
+      self.step.Git("fetch")
+      commit = self.step.GitLog(n=1, format="%H", grep=message, branch=remote)
+      if commit:
+        break
+      print("The commit has not replicated to git. Waiting for %s seconds." %
+            wait_interval)
+      self.step._side_effect_handler.Sleep(wait_interval)
+    else:
+      self.step.Die("Couldn't determine commit for setting the tag. Maybe the "
+                    "git updater is lagging behind?")
+
+    self.step.Git("tag %s %s" % (tag, commit))
+    self.step.Git("push origin %s" % tag)
+
+  def CLLand(self):
+    self.step.GitCLLand()
+
+
 class Step(GitRecipesMixin):
   def __init__(self, text, number, config, state, options, handler):
     self._text = text
@@ -263,9 +365,12 @@
     self._state = state
     self._options = options
     self._side_effect_handler = handler
+    self.vc = GitInterface()
+    self.vc.InjectStep(self)
 
     # The testing configuration might set a different default cwd.
-    self.default_cwd = self._config.get("DEFAULT_CWD") or DEFAULT_CWD
+    self.default_cwd = (self._config.get("DEFAULT_CWD") or
+                        os.path.join(self._options.work_dir, "v8"))
 
     assert self._number >= 0
     assert self._config is not None
@@ -354,11 +459,6 @@
       raise GitFailedException("'git %s' failed." % args)
     return result
 
-  def SVN(self, args="", prefix="", pipe=True, retry_on=None, cwd=None):
-    cmd = lambda: self._side_effect_handler.Command(
-        "svn", args, prefix, pipe, cwd=cwd or self.default_cwd)
-    return self.Retry(cmd, retry_on, [5, 30])
-
   def Editor(self, args):
     if self._options.requires_editor:
       return self._side_effect_handler.Command(
@@ -422,14 +522,17 @@
     self["current_branch"] = self.GitCurrentBranch()
 
     # Fetch unfetched revisions.
-    self.GitSVNFetch()
+    self.vc.Fetch()
 
   def PrepareBranch(self):
     # Delete the branch that will be created later if it exists already.
     self.DeleteBranch(self._config["BRANCHNAME"])
 
   def CommonCleanup(self):
-    self.GitCheckout(self["current_branch"])
+    if ' ' in self["current_branch"]:
+      self.GitCheckout('master')
+    else:
+      self.GitCheckout(self["current_branch"])
     if self._config["BRANCHNAME"] != self["current_branch"]:
       self.GitDeleteBranch(self._config["BRANCHNAME"])
 
@@ -493,7 +596,7 @@
       # Non-patched versions only have three numbers followed by the "(based
       # on...) comment."
       push_pattern += " (based"
-    branch = "" if parent_hash else branch or "svn/trunk"
+    branch = "" if parent_hash else branch or self.vc.RemoteCandidateBranch()
     return self.GitLog(n=1, format="%H", grep=push_pattern,
                        parent_hash=parent_hash, branch=branch)
 
@@ -517,21 +620,18 @@
       output += "%s\n" % line
     TextToFile(output, version_file)
 
-  def SVNCommit(self, root, commit_message):
-    patch = self.GitDiff("HEAD^", "HEAD")
-    TextToFile(patch, self._config["PATCH_FILE"])
-    self.Command("svn", "update", cwd=self._options.svn)
-    if self.Command("svn", "status", cwd=self._options.svn) != "":
-      self.Die("SVN checkout not clean.")
-    if not self.Command("patch", "-d %s -p1 -i %s" %
-                        (root, self._config["PATCH_FILE"]),
-                        cwd=self._options.svn):
-      self.Die("Could not apply patch.")
-    self.Command(
-        "svn",
-        "commit --non-interactive --username=%s --config-dir=%s -m \"%s\"" %
-            (self._options.author, self._options.svn_config, commit_message),
-        cwd=self._options.svn)
+
+class BootstrapStep(Step):
+  MESSAGE = "Bootstapping v8 checkout."
+
+  def RunStep(self):
+    if os.path.realpath(self.default_cwd) == os.path.realpath(V8_BASE):
+      self.Die("Can't use v8 checkout with calling script as work checkout.")
+    # Directory containing the working v8 checkout.
+    if not os.path.exists(self._options.work_dir):
+      os.makedirs(self._options.work_dir)
+    if not os.path.exists(self.default_cwd):
+      self.Command("fetch", "v8", cwd=self._options.work_dir)
 
 
 class UploadStep(Step):
@@ -546,7 +646,8 @@
       self.DieNoManualMode("A reviewer must be specified in forced mode.")
       reviewer = self.ReadLine()
     self.GitUpload(reviewer, self._options.author, self._options.force_upload,
-                   bypass_hooks=self._options.bypass_upload_hooks)
+                   bypass_hooks=self._options.bypass_upload_hooks,
+                   cc=self._options.cc)
 
 
 class DetermineV8Sheriff(Step):
@@ -600,7 +701,6 @@
 
 
 class ScriptsBase(object):
-  # TODO(machenbach): Move static config here.
   def __init__(self,
                config=None,
                side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER,
@@ -638,14 +738,12 @@
                         help=("Determine current sheriff to review CLs. On "
                               "success, this will overwrite the reviewer "
                               "option."))
-    parser.add_argument("--svn",
-                        help=("Optional full svn checkout for the commit."
-                              "The folder needs to be the svn root."))
-    parser.add_argument("--svn-config",
-                        help=("Optional folder used as svn --config-dir."))
     parser.add_argument("-s", "--step",
         help="Specify the step where to start work. Default: 0.",
         default=0, type=int)
+    parser.add_argument("--work-dir",
+                        help=("Location where to bootstrap a working v8 "
+                              "checkout."))
     self._PrepareOptions(parser)
 
     if args is None:  # pragma: no cover
@@ -662,10 +760,6 @@
       print "To determine the current sheriff, requires the googler mapping"
       parser.print_help()
       return None
-    if options.svn and not options.svn_config:
-      print "Using pure svn for committing requires also --svn-config"
-      parser.print_help()
-      return None
 
     # Defaults for options, common to all scripts.
     options.manual = getattr(options, "manual", True)
@@ -682,6 +776,9 @@
     if not self._ProcessOptions(options):
       parser.print_help()
       return None
+
+    if not options.work_dir:
+      options.work_dir = "/tmp/v8-release-scripts-work-dir"
     return options
 
   def RunSteps(self, step_classes, args=None):
@@ -694,7 +791,7 @@
       os.remove(state_file)
 
     steps = []
-    for (number, step_class) in enumerate(step_classes):
+    for (number, step_class) in enumerate([BootstrapStep] + step_classes):
       steps.append(MakeStep(step_class, number, self._state, self._config,
                             options, self._side_effect_handler))
     for step in steps[options.step:]:
diff --git a/tools/push-to-trunk/generate_version.py b/tools/push-to-trunk/generate_version.py
new file mode 100755
index 0000000..b4a0221
--- /dev/null
+++ b/tools/push-to-trunk/generate_version.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# Copyright 2014 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Script to set v8's version file to the version given by the latest tag.
+"""
+
+
+import os
+import re
+import subprocess
+import sys
+
+
+CWD = os.path.abspath(
+    os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
+VERSION_CC = os.path.join(CWD, "src", "version.cc")
+
+def main():
+  tag = subprocess.check_output(
+      "git describe --tags",
+      shell=True,
+      cwd=CWD,
+  ).strip()
+  assert tag
+
+  # Check for commits not exactly matching a tag. Those are candidate builds
+  # for the next version. The output has the form
+  # <tag name>-<n commits>-<hash>.
+  if "-" in tag:
+    version = tag.split("-")[0]
+    candidate = "1"
+  else:
+    version = tag
+    candidate = "0"
+  version_levels = version.split(".")
+
+  # Set default patch level if none is given.
+  if len(version_levels) == 3:
+    version_levels.append("0")
+  assert len(version_levels) == 4
+
+  major, minor, build, patch = version_levels
+
+  # Increment build level for candidate builds.
+  if candidate == "1":
+    build = str(int(build) + 1)
+    patch = "0"
+
+  # Modify version.cc with the new values.
+  with open(VERSION_CC, "r") as f:
+    text = f.read()
+  output = []
+  for line in text.split("\n"):
+    for definition, substitute in (
+        ("MAJOR_VERSION", major),
+        ("MINOR_VERSION", minor),
+        ("BUILD_NUMBER", build),
+        ("PATCH_LEVEL", patch),
+        ("IS_CANDIDATE_VERSION", candidate)):
+      if line.startswith("#define %s" % definition):
+        line =  re.sub("\d+$", substitute, line)
+    output.append(line)
+  with open(VERSION_CC, "w") as f:
+    f.write("\n".join(output))
+
+  # Log what was done.
+  candidate_txt = " (candidate)" if candidate == "1" else ""
+  patch_txt = ".%s" % patch if patch != "0" else ""
+  version_txt = ("%s.%s.%s%s%s" %
+                 (major, minor, build, patch_txt, candidate_txt))
+  print "Modified version.cc. Set V8 version to %s" %  version_txt
+  return 0
+
+if __name__ == "__main__":
+  sys.exit(main())
diff --git a/tools/push-to-trunk/git_recipes.py b/tools/push-to-trunk/git_recipes.py
index 0f8fcef..3d2a9ef 100644
--- a/tools/push-to-trunk/git_recipes.py
+++ b/tools/push-to-trunk/git_recipes.py
@@ -45,7 +45,7 @@
 
 # e.g., git-svn-id: https://v8.googlecode.com/svn/trunk@23117
 #     ce2b1a6d-e550-0410-aec6-3dcde31c8c00
-GIT_SVN_ID_RE = re.compile(r'((?:\w+)://[^@]+)@(\d+)\s+(?:[a-zA-Z0-9\-]+)')
+GIT_SVN_ID_RE = re.compile(r'[^@]+@(\d+)\s+(?:[a-zA-Z0-9\-]+)')
 
 
 # Copied from bot_update.py.
@@ -80,7 +80,11 @@
 
 def Strip(f):
   def new_f(*args, **kwargs):
-    return f(*args, **kwargs).strip()
+    result = f(*args, **kwargs)
+    if result is None:
+      return result
+    else:
+      return result.strip()
   return new_f
 
 
@@ -101,9 +105,10 @@
   def GitBranch(self, **kwargs):
     return self.Git("branch", **kwargs)
 
-  def GitCreateBranch(self, name, branch="", **kwargs):
+  def GitCreateBranch(self, name, remote="", **kwargs):
     assert name
-    self.Git(MakeArgs(["checkout -b", name, branch]), **kwargs)
+    remote_args = ["--upstream", remote] if remote else []
+    self.Git(MakeArgs(["new-branch", name] + remote_args), **kwargs)
 
   def GitDeleteBranch(self, name, **kwargs):
     assert name
@@ -194,7 +199,7 @@
     self.Git(MakeArgs(args), **kwargs)
 
   def GitUpload(self, reviewer="", author="", force=False, cq=False,
-                bypass_hooks=False, **kwargs):
+                bypass_hooks=False, cc="", **kwargs):
     args = ["cl upload --send-mail"]
     if author:
       args += ["--email", Quoted(author)]
@@ -206,6 +211,8 @@
       args.append("--use-commit-queue")
     if bypass_hooks:
       args.append("--bypass-hooks")
+    if cc:
+      args += ["--cc", Quoted(cc)]
     # TODO(machenbach): Check output in forced mode. Verify that all required
     # base files were uploaded, if not retry.
     self.Git(MakeArgs(args), pipe=False, **kwargs)
@@ -224,9 +231,9 @@
   def GitPresubmit(self, **kwargs):
     self.Git("cl presubmit", "PRESUBMIT_TREE_CHECK=\"skip\"", **kwargs)
 
-  def GitDCommit(self, **kwargs):
+  def GitCLLand(self, **kwargs):
     self.Git(
-        "cl dcommit -f --bypass-hooks", retry_on=lambda x: x is None, **kwargs)
+        "cl land -f --bypass-hooks", retry_on=lambda x: x is None, **kwargs)
 
   def GitDiff(self, loc1, loc2, **kwargs):
     return self.Git(MakeArgs(["diff", loc1, loc2]), **kwargs)
@@ -237,17 +244,6 @@
   def GitFetchOrigin(self, **kwargs):
     self.Git("fetch origin", **kwargs)
 
-  def GitConvertToSVNRevision(self, git_hash, **kwargs):
-    result = self.Git(MakeArgs(["rev-list", "-n", "1", git_hash]), **kwargs)
-    if not result or not SHA1_RE.match(result):
-      raise GitFailedException("Git hash %s is unknown." % git_hash)
-    log = self.GitLog(n=1, format="%B", git_hash=git_hash, **kwargs)
-    for line in reversed(log.splitlines()):
-      match = ROLL_DEPS_GIT_SVN_ID_RE.match(line.strip())
-      if match:
-        return match.group(1)
-    raise GitFailedException("Couldn't convert %s to SVN." % git_hash)
-
   @Strip
   # Copied from bot_update.py and modified for svn-like numbers only.
   def GetCommitPositionNumber(self, git_hash, **kwargs):
@@ -274,36 +270,6 @@
     if value:
       match = GIT_SVN_ID_RE.match(value)
       if match:
-        return match.group(2)
-    return None
-
-  ### Git svn stuff
-
-  def GitSVNFetch(self, **kwargs):
-    self.Git("svn fetch", **kwargs)
-
-  def GitSVNRebase(self, **kwargs):
-    self.Git("svn rebase", **kwargs)
-
-  # TODO(machenbach): Unused? Remove.
-  @Strip
-  def GitSVNLog(self, **kwargs):
-    return self.Git("svn log -1 --oneline", **kwargs)
-
-  @Strip
-  def GitSVNFindGitHash(self, revision, branch="", **kwargs):
-    assert revision
-    return self.Git(
-        MakeArgs(["svn find-rev", "r%s" % revision, branch]), **kwargs)
-
-  @Strip
-  def GitSVNFindSVNRev(self, git_hash, branch="", **kwargs):
-    return self.Git(MakeArgs(["svn find-rev", git_hash, branch]), **kwargs)
-
-  def GitSVNDCommit(self, **kwargs):
-    return self.Git("svn dcommit 2>&1", retry_on=lambda x: x is None, **kwargs)
-
-  def GitSVNTag(self, version, **kwargs):
-    self.Git(("svn tag %s -m \"Tagging version %s\"" % (version, version)),
-             retry_on=lambda x: x is None,
-             **kwargs)
+        return match.group(1)
+    raise GitFailedException("Couldn't determine commit position for %s" %
+                             git_hash)
diff --git a/tools/push-to-trunk/merge_to_branch.py b/tools/push-to-trunk/merge_to_branch.py
index 3fd3450..9e7f1fb 100755
--- a/tools/push-to-trunk/merge_to_branch.py
+++ b/tools/push-to-trunk/merge_to_branch.py
@@ -32,6 +32,9 @@
 
 from common_includes import *
 
+def IsSvnNumber(rev):
+  return rev.isdigit() and len(rev) < 8
+
 class Preparation(Step):
   MESSAGE = "Preparation."
 
@@ -45,6 +48,7 @@
 
     self.InitialEnvironmentChecks(self.default_cwd)
     if self._options.revert_bleeding_edge:
+      # FIXME(machenbach): Make revert bleeding_edge obsolete?
       self["merge_to_branch"] = "bleeding_edge"
     elif self._options.branch:
       self["merge_to_branch"] = self._options.branch
@@ -60,7 +64,7 @@
 
   def RunStep(self):
     self.GitCreateBranch(self.Config("BRANCHNAME"),
-                         "svn/%s" % self["merge_to_branch"])
+                         self.vc.RemoteBranch(self["merge_to_branch"]))
 
 
 class SearchArchitecturePorts(Step):
@@ -71,24 +75,21 @@
         self._options.revisions))
     port_revision_list = []
     for revision in self["full_revision_list"]:
-      # Search for commits which matches the "Port rXXX" pattern.
+      # Search for commits which matches the "Port XXX" pattern.
       git_hashes = self.GitLog(reverse=True, format="%H",
-                               grep="Port r%d" % int(revision),
-                               branch="svn/bleeding_edge")
+                               grep="Port %s" % revision,
+                               branch=self.vc.RemoteMasterBranch())
       for git_hash in git_hashes.splitlines():
-        svn_revision = self.GitSVNFindSVNRev(git_hash, "svn/bleeding_edge")
-        if not svn_revision:  # pragma: no cover
-          self.Die("Cannot determine svn revision for %s" % git_hash)
         revision_title = self.GitLog(n=1, format="%s", git_hash=git_hash)
 
         # Is this revision included in the original revision list?
-        if svn_revision in self["full_revision_list"]:
-          print("Found port of r%s -> r%s (already included): %s"
-                % (revision, svn_revision, revision_title))
+        if git_hash in self["full_revision_list"]:
+          print("Found port of %s -> %s (already included): %s"
+                % (revision, git_hash, revision_title))
         else:
-          print("Found port of r%s -> r%s: %s"
-                % (revision, svn_revision, revision_title))
-          port_revision_list.append(svn_revision)
+          print("Found port of %s -> %s: %s"
+                % (revision, git_hash, revision_title))
+          port_revision_list.append(git_hash)
 
     # Do we find any port?
     if len(port_revision_list) > 0:
@@ -98,16 +99,10 @@
         self["full_revision_list"].extend(port_revision_list)
 
 
-class FindGitRevisions(Step):
-  MESSAGE = "Find the git revisions associated with the patches."
+class CreateCommitMessage(Step):
+  MESSAGE = "Create commit message."
 
   def RunStep(self):
-    self["patch_commit_hashes"] = []
-    for revision in self["full_revision_list"]:
-      next_hash = self.GitSVNFindGitHash(revision, "svn/bleeding_edge")
-      if not next_hash:  # pragma: no cover
-        self.Die("Cannot determine git hash for r%s" % revision)
-      self["patch_commit_hashes"].append(next_hash)
 
     # Stringify: [123, 234] -> "r123, r234"
     self["revision_list"] = ", ".join(map(lambda s: "r%s" % s,
@@ -116,29 +111,38 @@
     if not self["revision_list"]:  # pragma: no cover
       self.Die("Revision list is empty.")
 
-    # The commit message title is added below after the version is specified.
-    self["new_commit_msg"] = ""
+    if self._options.revert and not self._options.revert_bleeding_edge:
+      action_text = "Rollback of %s"
+    else:
+      action_text = "Merged %s"
 
-    for commit_hash in self["patch_commit_hashes"]:
+    # The commit message title is added below after the version is specified.
+    msg_pieces = [
+      "\n".join(action_text % s for s in self["full_revision_list"]),
+    ]
+    msg_pieces.append("\n\n")
+
+    for commit_hash in self["full_revision_list"]:
       patch_merge_desc = self.GitLog(n=1, format="%s", git_hash=commit_hash)
-      self["new_commit_msg"] += "%s\n\n" % patch_merge_desc
+      msg_pieces.append("%s\n\n" % patch_merge_desc)
 
     bugs = []
-    for commit_hash in self["patch_commit_hashes"]:
+    for commit_hash in self["full_revision_list"]:
       msg = self.GitLog(n=1, git_hash=commit_hash)
-      for bug in re.findall(r"^[ \t]*BUG[ \t]*=[ \t]*(.*?)[ \t]*$", msg,
-                            re.M):
-        bugs.extend(map(lambda s: s.strip(), bug.split(",")))
+      for bug in re.findall(r"^[ \t]*BUG[ \t]*=[ \t]*(.*?)[ \t]*$", msg, re.M):
+        bugs.extend(s.strip() for s in bug.split(","))
     bug_aggregate = ",".join(sorted(filter(lambda s: s and s != "none", bugs)))
     if bug_aggregate:
-      self["new_commit_msg"] += "BUG=%s\nLOG=N\n" % bug_aggregate
+      msg_pieces.append("BUG=%s\nLOG=N\n" % bug_aggregate)
+
+    self["new_commit_msg"] = "".join(msg_pieces)
 
 
 class ApplyPatches(Step):
   MESSAGE = "Apply patches for selected revisions."
 
   def RunStep(self):
-    for commit_hash in self["patch_commit_hashes"]:
+    for commit_hash in self["full_revision_list"]:
       print("Applying patch for %s to %s..."
             % (commit_hash, self["merge_to_branch"]))
       patch = self.GitGetPatch(commit_hash)
@@ -188,16 +192,14 @@
 
   def RunStep(self):
     # Add a commit message title.
-    if self._options.revert:
-      if not self._options.revert_bleeding_edge:
-        title = ("Version %s (rollback of %s)"
-                 % (self["version"], self["revision_list"]))
-      else:
-        title = "Revert %s." % self["revision_list"]
+    if self._options.revert and self._options.revert_bleeding_edge:
+      # TODO(machenbach): Find a better convention if multiple patches are
+      # reverted in one CL.
+      self["commit_title"] = "Revert on master"
     else:
-      title = ("Version %s (merged %s)"
-               % (self["version"], self["revision_list"]))
-    self["new_commit_msg"] = "%s\n\n%s" % (title, self["new_commit_msg"])
+      self["commit_title"] = "Version %s (cherry-pick)" % self["version"]
+    self["new_commit_msg"] = "%s\n\n%s" % (self["commit_title"],
+                                           self["new_commit_msg"])
     TextToFile(self["new_commit_msg"], self.Config("COMMITMSG_FILE"))
     self.GitCommit(file_name=self.Config("COMMITMSG_FILE"))
 
@@ -209,22 +211,7 @@
     self.GitCheckout(self.Config("BRANCHNAME"))
     self.WaitForLGTM()
     self.GitPresubmit()
-    self.GitDCommit()
-
-
-class PrepareSVN(Step):
-  MESSAGE = "Determine svn commit revision."
-
-  def RunStep(self):
-    if self._options.revert_bleeding_edge:
-      return
-    self.GitSVNFetch()
-    commit_hash = self.GitLog(n=1, format="%H", grep=self["new_commit_msg"],
-                              branch="svn/%s" % self["merge_to_branch"])
-    if not commit_hash:  # pragma: no cover
-      self.Die("Unable to map git commit to svn revision.")
-    self["svn_revision"] = self.GitSVNFindSVNRev(commit_hash)
-    print "subversion revision number is r%s" % self["svn_revision"]
+    self.vc.CLLand()
 
 
 class TagRevision(Step):
@@ -233,16 +220,10 @@
   def RunStep(self):
     if self._options.revert_bleeding_edge:
       return
-    print "Creating tag svn/tags/%s" % self["version"]
-    if self["merge_to_branch"] == "trunk":
-      self["to_url"] = "trunk"
-    else:
-      self["to_url"] = "branches/%s" % self["merge_to_branch"]
-    self.SVN("copy -r %s https://v8.googlecode.com/svn/%s "
-             "https://v8.googlecode.com/svn/tags/%s -m "
-             "\"Tagging version %s\""
-             % (self["svn_revision"], self["to_url"],
-                self["version"], self["version"]))
+    print "Creating tag %s" % self["version"]
+    self.vc.Tag(self["version"],
+                self.vc.RemoteBranch(self["merge_to_branch"]),
+                self["commit_title"])
 
 
 class CleanUp(Step):
@@ -253,8 +234,7 @@
     if not self._options.revert_bleeding_edge:
       print "*** SUMMARY ***"
       print "version: %s" % self["version"]
-      print "branch: %s" % self["to_url"]
-      print "svn revision: %s" % self["svn_revision"]
+      print "branch: %s" % self["merge_to_branch"]
       if self["revision_list"]:
         print "patches: %s" % self["revision_list"]
 
@@ -293,6 +273,16 @@
         print "You must specify a merge comment if no patches are specified"
         return False
     options.bypass_upload_hooks = True
+    # CC ulan to make sure that fixes are merged to Google3.
+    options.cc = "ulan@chromium.org"
+
+    # Make sure to use git hashes in the new workflows.
+    for revision in options.revisions:
+      if (IsSvnNumber(revision) or
+          (revision[0:1] == "r" and IsSvnNumber(revision[1:]))):
+        print "Please provide full git hashes of the patches to merge."
+        print "Got: %s" % revision
+        return False
     return True
 
   def _Config(self):
@@ -310,14 +300,13 @@
       Preparation,
       CreateBranch,
       SearchArchitecturePorts,
-      FindGitRevisions,
+      CreateCommitMessage,
       ApplyPatches,
       PrepareVersion,
       IncrementVersion,
       CommitLocal,
       UploadStep,
       CommitRepository,
-      PrepareSVN,
       TagRevision,
       CleanUp,
     ]
diff --git a/tools/push-to-trunk/push_to_trunk.py b/tools/push-to-trunk/push_to_trunk.py
index 8a9629e..6e821f2 100755
--- a/tools/push-to-trunk/push_to_trunk.py
+++ b/tools/push-to-trunk/push_to_trunk.py
@@ -34,8 +34,8 @@
 
 from common_includes import *
 
-PUSH_MESSAGE_SUFFIX = " (based on bleeding_edge revision r%d)"
-PUSH_MESSAGE_RE = re.compile(r".* \(based on bleeding_edge revision r(\d+)\)$")
+PUSH_MSG_GIT_SUFFIX = " (based on %s)"
+PUSH_MSG_GIT_RE = re.compile(r".* \(based on (?P<git_rev>[a-fA-F0-9]+)\)$")
 
 class Preparation(Step):
   MESSAGE = "Preparation."
@@ -56,7 +56,8 @@
   MESSAGE = "Create a fresh branch."
 
   def RunStep(self):
-    self.GitCreateBranch(self.Config("BRANCHNAME"), "svn/bleeding_edge")
+    self.GitCreateBranch(self.Config("BRANCHNAME"),
+                         self.vc.RemoteMasterBranch())
 
 
 class PreparePushRevision(Step):
@@ -64,7 +65,7 @@
 
   def RunStep(self):
     if self._options.revision:
-      self["push_hash"] = self.GitSVNFindGitHash(self._options.revision)
+      self["push_hash"] = self._options.revision
     else:
       self["push_hash"] = self.GitLog(n=1, format="%H", git_hash="HEAD")
     if not self["push_hash"]:  # pragma: no cover
@@ -91,16 +92,14 @@
       # Retrieve the bleeding edge revision of the last push from the text in
       # the push commit message.
       last_push_title = self.GitLog(n=1, format="%s", git_hash=last_push)
-      last_push_be_svn = PUSH_MESSAGE_RE.match(last_push_title).group(1)
-      if not last_push_be_svn:  # pragma: no cover
-        self.Die("Could not retrieve bleeding edge revision for trunk push %s"
-                 % last_push)
-      last_push_bleeding_edge = self.GitSVNFindGitHash(last_push_be_svn)
+      last_push_bleeding_edge = PUSH_MSG_GIT_RE.match(
+          last_push_title).group("git_rev")
+
       if not last_push_bleeding_edge:  # pragma: no cover
         self.Die("Could not retrieve bleeding edge git hash for trunk push %s"
                  % last_push)
 
-    # This points to the svn revision of the last push on trunk.
+    # This points to the git hash of the last push on trunk.
     self["last_push_trunk"] = last_push
     # This points to the last bleeding_edge revision that went into the last
     # push.
@@ -116,7 +115,7 @@
   MESSAGE = "Get latest bleeding edge version."
 
   def RunStep(self):
-    self.GitCheckoutFile(VERSION_FILE, "svn/bleeding_edge")
+    self.GitCheckoutFile(VERSION_FILE, self.vc.RemoteMasterBranch())
 
     # Store latest version.
     self.ReadAndPersistVersion("latest_")
@@ -140,7 +139,7 @@
 
     if SortingKey(self["trunk_version"]) < SortingKey(self["latest_version"]):
       # If the version on bleeding_edge is newer than on trunk, use it.
-      self.GitCheckoutFile(VERSION_FILE, "svn/bleeding_edge")
+      self.GitCheckoutFile(VERSION_FILE, self.vc.RemoteMasterBranch())
       self.ReadAndPersistVersion()
 
     if self.Confirm(("Automatically increment BUILD_NUMBER? (Saying 'n' will "
@@ -249,8 +248,8 @@
              "started.")
 
   def RunStep(self):
-    self.GitSVNFetch()
-    self.GitCheckout("svn/bleeding_edge")
+    self.vc.Fetch()
+    self.GitCheckout(self.vc.RemoteMasterBranch())
 
 
 class SquashCommits(Step):
@@ -259,7 +258,8 @@
   def RunStep(self):
     # Instead of relying on "git rebase -i", we'll just create a diff, because
     # that's easier to automate.
-    TextToFile(self.GitDiff("svn/trunk", self["push_hash"]),
+    TextToFile(self.GitDiff(self.vc.RemoteCandidateBranch(),
+                            self["push_hash"]),
                self.Config("PATCH_FILE"))
 
     # Convert the ChangeLog entry to commit message format.
@@ -268,10 +268,8 @@
     # Remove date and trailing white space.
     text = re.sub(r"^%s: " % self["date"], "", text.rstrip())
 
-    # Retrieve svn revision for showing the used bleeding edge revision in the
-    # commit message.
-    self["svn_revision"] = self.GitSVNFindSVNRev(self["push_hash"])
-    suffix = PUSH_MESSAGE_SUFFIX % int(self["svn_revision"])
+    # Show the used master hash in the commit message.
+    suffix = PUSH_MSG_GIT_SUFFIX % self["push_hash"]
     text = MSub(r"^(Version \d+\.\d+\.\d+)$", "\\1%s" % suffix, text)
 
     # Remove indentation and merge paragraphs into single long lines, keeping
@@ -283,6 +281,7 @@
 
     if not text:  # pragma: no cover
       self.Die("Commit message editing failed.")
+    self["commit_title"] = text.splitlines()[0]
     TextToFile(text, self.Config("COMMITMSG_FILE"))
 
 
@@ -290,7 +289,8 @@
   MESSAGE = "Create a new branch from trunk."
 
   def RunStep(self):
-    self.GitCreateBranch(self.Config("TRUNKBRANCH"), "svn/trunk")
+    self.GitCreateBranch(self.Config("TRUNKBRANCH"),
+                         self.vc.RemoteCandidateBranch())
 
 
 class ApplyChanges(Step):
@@ -308,11 +308,11 @@
     # The change log has been modified by the patch. Reset it to the version
     # on trunk and apply the exact changes determined by this PrepareChangeLog
     # step above.
-    self.GitCheckoutFile(self.Config("CHANGELOG_FILE"), "svn/trunk")
+    self.GitCheckoutFile(CHANGELOG_FILE, self.vc.RemoteCandidateBranch())
     changelog_entry = FileToText(self.Config("CHANGELOG_ENTRY_FILE"))
-    old_change_log = FileToText(self.Config("CHANGELOG_FILE"))
+    old_change_log = FileToText(os.path.join(self.default_cwd, CHANGELOG_FILE))
     new_change_log = "%s\n\n\n%s" % (changelog_entry, old_change_log)
-    TextToFile(new_change_log, self.Config("CHANGELOG_FILE"))
+    TextToFile(new_change_log, os.path.join(self.default_cwd, CHANGELOG_FILE))
     os.remove(self.Config("CHANGELOG_ENTRY_FILE"))
 
 
@@ -322,7 +322,7 @@
   def RunStep(self):
     # The version file has been modified by the patch. Reset it to the version
     # on trunk and apply the correct version.
-    self.GitCheckoutFile(VERSION_FILE, "svn/trunk")
+    self.GitCheckoutFile(VERSION_FILE, self.vc.RemoteCandidateBranch())
     self.SetVersion(os.path.join(self.default_cwd, VERSION_FILE), "new_")
 
 
@@ -346,35 +346,19 @@
       self.Die("Execution canceled.")  # pragma: no cover
 
 
-class CommitSVN(Step):
-  MESSAGE = "Commit to SVN."
+class Land(Step):
+  MESSAGE = "Land the patch."
 
   def RunStep(self):
-    result = self.GitSVNDCommit()
-    if not result:  # pragma: no cover
-      self.Die("'git svn dcommit' failed.")
-    result = filter(lambda x: re.search(r"^Committed r[0-9]+", x),
-                    result.splitlines())
-    if len(result) > 0:
-      self["trunk_revision"] = re.sub(r"^Committed r([0-9]+)", r"\1",result[0])
-
-    # Sometimes grepping for the revision fails. No idea why. If you figure
-    # out why it is flaky, please do fix it properly.
-    if not self["trunk_revision"]:
-      print("Sorry, grepping for the SVN revision failed. Please look for it "
-            "in the last command's output above and provide it manually (just "
-            "the number, without the leading \"r\").")
-      self.DieNoManualMode("Can't prompt in forced mode.")
-      while not self["trunk_revision"]:
-        print "> ",
-        self["trunk_revision"] = self.ReadLine()
+    self.vc.CLLand()
 
 
 class TagRevision(Step):
   MESSAGE = "Tag the new revision."
 
   def RunStep(self):
-    self.GitSVNTag(self["version"])
+    self.vc.Tag(
+        self["version"], self.vc.RemoteCandidateBranch(), self["commit_title"])
 
 
 class CleanUp(Step):
@@ -382,10 +366,8 @@
 
   def RunStep(self):
     print("Congratulations, you have successfully created the trunk "
-          "revision %s. Please don't forget to roll this new version into "
-          "Chromium, and to update the v8rel spreadsheet:"
+          "revision %s."
           % self["version"])
-    print "%s\ttrunk\t%s" % (self["version"], self["trunk_revision"])
 
     self.CommonCleanup()
     if self.Config("TRUNKBRANCH") != self["current_branch"]:
@@ -408,7 +390,7 @@
     parser.add_argument("-l", "--last-push",
                         help="The git commit ID of the last push to trunk.")
     parser.add_argument("-R", "--revision",
-                        help="The svn revision to push (defaults to HEAD).")
+                        help="The git commit ID to push (defaults to HEAD).")
 
   def _ProcessOptions(self, options):  # pragma: no cover
     if not options.manual and not options.reviewer:
@@ -417,10 +399,6 @@
     if not options.manual and not options.author:
       print "Specify your chromium.org email with -a in (semi-)automatic mode."
       return False
-    if options.revision and not int(options.revision) > 0:
-      print("The --revision flag must be a positiv integer pointing to a "
-            "valid svn revision.")
-      return False
 
     options.tbr_commit = not options.manual
     return True
@@ -430,7 +408,6 @@
       "BRANCHNAME": "prepare-push",
       "TRUNKBRANCH": "trunk-push",
       "PERSISTFILE_BASENAME": "/tmp/v8-push-to-trunk-tempfile",
-      "CHANGELOG_FILE": "ChangeLog",
       "CHANGELOG_ENTRY_FILE": "/tmp/v8-push-to-trunk-tempfile-changelog-entry",
       "PATCH_FILE": "/tmp/v8-push-to-trunk-tempfile-patch-file",
       "COMMITMSG_FILE": "/tmp/v8-push-to-trunk-tempfile-commitmsg",
@@ -454,7 +431,7 @@
       SetVersion,
       CommitTrunk,
       SanityCheck,
-      CommitSVN,
+      Land,
       TagRevision,
       CleanUp,
     ]
diff --git a/tools/push-to-trunk/releases.py b/tools/push-to-trunk/releases.py
index 1d26198..1a5b15c 100755
--- a/tools/push-to-trunk/releases.py
+++ b/tools/push-to-trunk/releases.py
@@ -26,16 +26,25 @@
 }
 
 # Expression for retrieving the bleeding edge revision from a commit message.
-PUSH_MESSAGE_RE = re.compile(r".* \(based on bleeding_edge revision r(\d+)\)$")
+PUSH_MSG_SVN_RE = re.compile(r".* \(based on bleeding_edge revision r(\d+)\)$")
+PUSH_MSG_GIT_RE = re.compile(r".* \(based on ([a-fA-F0-9]+)\)$")
 
 # Expression for retrieving the merged patches from a merge commit message
 # (old and new format).
 MERGE_MESSAGE_RE = re.compile(r"^.*[M|m]erged (.+)(\)| into).*$", re.M)
 
+CHERRY_PICK_TITLE_GIT_RE = re.compile(r"^.* \(cherry\-pick\)\.?$")
+
+# New git message for cherry-picked CLs. One message per line.
+MERGE_MESSAGE_GIT_RE = re.compile(r"^Merged ([a-fA-F0-9]+)\.?$")
+
 # Expression for retrieving reverted patches from a commit message (old and
 # new format).
 ROLLBACK_MESSAGE_RE = re.compile(r"^.*[R|r]ollback of (.+)(\)| in).*$", re.M)
 
+# New git message for reverted CLs. One message per line.
+ROLLBACK_MESSAGE_GIT_RE = re.compile(r"^Rollback of ([a-fA-F0-9]+)\.?$")
+
 # Expression for retrieving the code review link.
 REVIEW_LINK_RE = re.compile(r"^Review URL: (.+)$", re.M)
 
@@ -127,8 +136,8 @@
     return (self._options.max_releases > 0
             and len(releases) > self._options.max_releases)
 
-  def GetBleedingEdgeFromPush(self, title):
-    return MatchSafe(PUSH_MESSAGE_RE.match(title))
+  def GetBleedingEdgeGitFromPush(self, title):
+    return MatchSafe(PUSH_MSG_GIT_RE.match(title))
 
   def GetMergedPatches(self, body):
     patches = MatchSafe(MERGE_MESSAGE_RE.search(body))
@@ -139,14 +148,31 @@
         patches = "-%s" % patches
     return patches
 
+  def GetMergedPatchesGit(self, body):
+    patches = []
+    for line in body.splitlines():
+      patch = MatchSafe(MERGE_MESSAGE_GIT_RE.match(line))
+      if patch:
+        patches.append(patch)
+      patch = MatchSafe(ROLLBACK_MESSAGE_GIT_RE.match(line))
+      if patch:
+        patches.append("-%s" % patch)
+    return ", ".join(patches)
+
+
   def GetReleaseDict(
-      self, git_hash, bleeding_edge_rev, branch, version, patches, cl_body):
-    revision = self.GitSVNFindSVNRev(git_hash)
+      self, git_hash, bleeding_edge_rev, bleeding_edge_git, branch, version,
+      patches, cl_body):
+    revision = self.GetCommitPositionNumber(git_hash)
     return {
-      # The SVN revision on the branch.
+      # The cr commit position number on the branch.
       "revision": revision,
-      # The SVN revision on bleeding edge (only for newer trunk pushes).
+      # The git revision on the branch.
+      "revision_git": git_hash,
+      # The cr commit position number on master.
       "bleeding_edge": bleeding_edge_rev,
+      # The same for git.
+      "bleeding_edge_git": bleeding_edge_git,
       # The branch name.
       "branch": branch,
       # The version for displaying in the form 3.26.3 or 3.26.3.12.
@@ -176,29 +202,40 @@
     patches = ""
     if self["patch"] != "0":
       version += ".%s" % self["patch"]
-      patches = self.GetMergedPatches(body)
+      if CHERRY_PICK_TITLE_GIT_RE.match(body.splitlines()[0]):
+        patches = self.GetMergedPatchesGit(body)
+      else:
+        patches = self.GetMergedPatches(body)
 
     title = self.GitLog(n=1, format="%s", git_hash=git_hash)
+    bleeding_edge_git = self.GetBleedingEdgeGitFromPush(title)
+    bleeding_edge_position = ""
+    if bleeding_edge_git:
+      bleeding_edge_position = self.GetCommitPositionNumber(bleeding_edge_git)
+    # TODO(machenbach): Add the commit position number.
     return self.GetReleaseDict(
-        git_hash, self.GetBleedingEdgeFromPush(title), branch, version,
+        git_hash, bleeding_edge_position, bleeding_edge_git, branch, version,
         patches, body), self["patch"]
 
-  def GetReleasesFromBleedingEdge(self):
-    tag_text = self.SVN("log https://v8.googlecode.com/svn/tags -v --limit 20")
-    releases = []
-    for (tag, revision) in re.findall(BLEEDING_EDGE_TAGS_RE, tag_text):
-      git_hash = self.GitSVNFindGitHash(revision)
+  def GetReleasesFromMaster(self):
+    # TODO(machenbach): Implement this in git as soon as we tag again on
+    # master.
+    # tag_text = self.SVN("log https://v8.googlecode.com/svn/tags -v
+    # --limit 20")
+    # releases = []
+    # for (tag, revision) in re.findall(BLEEDING_EDGE_TAGS_RE, tag_text):
+    #   git_hash = self.vc.SvnGit(revision)
 
       # Add bleeding edge release. It does not contain patches or a code
       # review link, as tags are not uploaded.
-      releases.append(self.GetReleaseDict(
-        git_hash, revision, "bleeding_edge", tag, "", ""))
-    return releases
+    #   releases.append(self.GetReleaseDict(
+    #     git_hash, revision, git_hash, self.vc.MasterBranch(), tag, "", ""))
+    return []
 
   def GetReleasesFromBranch(self, branch):
-    self.GitReset("svn/%s" % branch)
-    if branch == 'bleeding_edge':
-      return self.GetReleasesFromBleedingEdge()
+    self.GitReset(self.vc.RemoteBranch(branch))
+    if branch == self.vc.MasterBranch():
+      return self.GetReleasesFromMaster()
 
     releases = []
     try:
@@ -217,7 +254,7 @@
         # TODO(machenbach): This omits patches if the version file wasn't
         # manipulated correctly. Find a better way to detect the point where
         # the parent of the branch head leads to the trunk branch.
-        if branch != "trunk" and patch_level == "0":
+        if branch != self.vc.CandidateBranch() and patch_level == "0":
           break
 
     # Allow Ctrl-C interrupt.
@@ -230,12 +267,7 @@
 
   def RunStep(self):
     self.GitCreateBranch(self._config["BRANCHNAME"])
-    # Get relevant remote branches, e.g. "svn/3.25".
-    branches = filter(lambda s: re.match(r"^svn/\d+\.\d+$", s),
-                      self.GitRemotes())
-    # Remove 'svn/' prefix.
-    branches = map(lambda s: s[4:], branches)
-
+    branches = self.vc.GetBranches()
     releases = []
     if self._options.branch == 'recent':
       # Get only recent development on trunk, beta and stable.
@@ -244,17 +276,18 @@
       beta, stable = SortBranches(branches)[0:2]
       releases += self.GetReleasesFromBranch(stable)
       releases += self.GetReleasesFromBranch(beta)
-      releases += self.GetReleasesFromBranch("trunk")
-      releases += self.GetReleasesFromBranch("bleeding_edge")
+      releases += self.GetReleasesFromBranch(self.vc.CandidateBranch())
+      releases += self.GetReleasesFromBranch(self.vc.MasterBranch())
     elif self._options.branch == 'all':  # pragma: no cover
       # Retrieve the full release history.
       for branch in branches:
         releases += self.GetReleasesFromBranch(branch)
-      releases += self.GetReleasesFromBranch("trunk")
-      releases += self.GetReleasesFromBranch("bleeding_edge")
+      releases += self.GetReleasesFromBranch(self.vc.CandidateBranch())
+      releases += self.GetReleasesFromBranch(self.vc.MasterBranch())
     else:  # pragma: no cover
       # Retrieve history for a specified branch.
-      assert self._options.branch in branches + ["trunk", "bleeding_edge"]
+      assert self._options.branch in (branches +
+          [self.vc.CandidateBranch(), self.vc.MasterBranch()])
       releases += self.GetReleasesFromBranch(self._options.branch)
 
     self["releases"] = sorted(releases,
@@ -289,7 +322,7 @@
   # Simple check for git hashes.
   if revision.isdigit() and len(revision) < 8:
     return revision
-  return step.GitConvertToSVNRevision(
+  return step.GetCommitPositionNumber(
       revision, cwd=os.path.join(step._options.chromium, "v8"))
 
 
@@ -299,7 +332,9 @@
   def RunStep(self):
     cwd = self._options.chromium
     releases = filter(
-        lambda r: r["branch"] in ["trunk", "bleeding_edge"], self["releases"])
+        lambda r: r["branch"] in [self.vc.CandidateBranch(),
+                                  self.vc.MasterBranch()],
+        self["releases"])
     if not releases:  # pragma: no cover
       print "No releases detected. Skipping chromium history."
       return True
@@ -351,7 +386,8 @@
 
   def RunStep(self):
     cwd = self._options.chromium
-    trunk_releases = filter(lambda r: r["branch"] == "trunk", self["releases"])
+    trunk_releases = filter(lambda r: r["branch"] == self.vc.CandidateBranch(),
+                            self["releases"])
     if not trunk_releases:  # pragma: no cover
       print "No trunk releases detected. Skipping chromium history."
       return True
diff --git a/tools/push-to-trunk/test_scripts.py b/tools/push-to-trunk/test_scripts.py
index b0d1c58..db702a3 100644
--- a/tools/push-to-trunk/test_scripts.py
+++ b/tools/push-to-trunk/test_scripts.py
@@ -57,7 +57,6 @@
   "BRANCHNAME": "test-prepare-push",
   "TRUNKBRANCH": "test-trunk-push",
   "PERSISTFILE_BASENAME": "/tmp/test-v8-push-to-trunk-tempfile",
-  "CHANGELOG_FILE": None,
   "CHANGELOG_ENTRY_FILE": "/tmp/test-v8-push-to-trunk-tempfile-changelog-entry",
   "PATCH_FILE": "/tmp/test-v8-push-to-trunk-tempfile-patch",
   "COMMITMSG_FILE": "/tmp/test-v8-push-to-trunk-tempfile-commitmsg",
@@ -446,7 +445,7 @@
     self.Expect([
       Cmd("git status -s -uno", ""),
       Cmd("git status -s -b -uno", "## some_branch"),
-      Cmd("git svn fetch", ""),
+      Cmd("git fetch", ""),
       Cmd("git branch", "  branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
       RL("Y"),
       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
@@ -459,7 +458,7 @@
     self.Expect([
       Cmd("git status -s -uno", ""),
       Cmd("git status -s -b -uno", "## some_branch"),
-      Cmd("git svn fetch", ""),
+      Cmd("git fetch", ""),
       Cmd("git branch", "  branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
       RL("n"),
     ])
@@ -471,7 +470,7 @@
     self.Expect([
       Cmd("git status -s -uno", ""),
       Cmd("git status -s -b -uno", "## some_branch"),
-      Cmd("git svn fetch", ""),
+      Cmd("git fetch", ""),
       Cmd("git branch", "  branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
       RL("Y"),
       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], None),
@@ -488,6 +487,23 @@
     ])
     self.MakeStep().InitialEnvironmentChecks(TEST_CONFIG["DEFAULT_CWD"])
 
+  def testTagTimeout(self):
+    self.Expect([
+      Cmd("git fetch", ""),
+      Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""),
+      Cmd("git fetch", ""),
+      Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""),
+      Cmd("git fetch", ""),
+      Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""),
+      Cmd("git fetch", ""),
+      Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""),
+    ])
+    args = ["--branch", "candidates", "ab12345"]
+    self._state["version"] = "tag_name"
+    self._state["commit_title"] = "Title"
+    self.assertRaises(Exception,
+        lambda: self.RunStep(MergeToBranch, TagRevision, args))
+
   def testReadAndPersistVersion(self):
     self.WriteFakeVersionFile(build=5)
     step = self.MakeStep()
@@ -610,7 +626,7 @@
 
     self.Expect([
       Cmd("git checkout -f hash1 -- src/version.cc", ""),
-      Cmd("git checkout -f svn/bleeding_edge -- src/version.cc",
+      Cmd("git checkout -f origin/master -- src/version.cc",
           "", cb=lambda: self.WriteFakeVersionFile(22, 6)),
       RL("Y"),  # Increment build number.
     ])
@@ -628,8 +644,7 @@
       f.write(change_log)
 
     self.Expect([
-      Cmd("git diff svn/trunk hash1", "patch content"),
-      Cmd("git svn find-rev hash1", "123455\n"),
+      Cmd("git diff origin/candidates hash1", "patch content"),
     ])
 
     self._state["push_hash"] = "hash1"
@@ -648,7 +663,7 @@
         Chromium issue 12345
 
         Performance and stability improvements on all platforms.\n"""
-    commit_msg = """Version 3.22.5 (based on bleeding_edge revision r123455)
+    commit_msg = """Version 3.22.5 (based on hash1)
 
 Log text 1. Chromium issue 12345
 
@@ -662,7 +677,7 @@
         12345).
 
         Performance and stability improvements on all platforms.\n"""
-    commit_msg = """Version 3.22.5 (based on bleeding_edge revision r123455)
+    commit_msg = """Version 3.22.5 (based on hash1)
 
 Long commit message that fills more than 80 characters (Chromium issue 12345).
 
@@ -674,6 +689,21 @@
     commit_msg = """Line with "quotation marks"."""
     self._TestSquashCommits(change_log, commit_msg)
 
+  def testBootstrapper(self):
+    work_dir = self.MakeEmptyTempDirectory()
+    class FakeScript(ScriptsBase):
+      def _Steps(self):
+        return []
+
+    # Use the test configuration without the fake testing default work dir.
+    fake_config = dict(TEST_CONFIG)
+    del(fake_config["DEFAULT_CWD"])
+
+    self.Expect([
+      Cmd("fetch v8", "", cwd=work_dir),
+    ])
+    FakeScript(fake_config, self).Run(["--work-dir", work_dir])
+
   def _PushToTrunk(self, force=False, manual=False):
     TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
 
@@ -682,9 +712,9 @@
     self.WriteFakeVersionFile(build=5)
 
     TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
-    TEST_CONFIG["CHANGELOG_FILE"] = self.MakeEmptyTempFile()
     bleeding_edge_change_log = "2014-03-17: Sentinel\n"
-    TextToFile(bleeding_edge_change_log, TEST_CONFIG["CHANGELOG_FILE"])
+    TextToFile(bleeding_edge_change_log,
+               os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
     os.environ["EDITOR"] = "vi"
 
     def ResetChangeLog():
@@ -693,7 +723,8 @@
       trunk_change_log = """1999-04-05: Version 3.22.4
 
         Performance and stability improvements on all platforms.\n"""
-      TextToFile(trunk_change_log, TEST_CONFIG["CHANGELOG_FILE"])
+      TextToFile(trunk_change_log,
+                 os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
 
     def ResetToTrunk():
       ResetChangeLog()
@@ -702,7 +733,7 @@
     def CheckSVNCommit():
       commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"])
       self.assertEquals(
-"""Version 3.22.5 (based on bleeding_edge revision r123455)
+"""Version 3.22.5 (based on push_hash)
 
 Log text 1 (issue 321).
 
@@ -716,7 +747,8 @@
       self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version))
 
       # Check that the change log on the trunk branch got correctly modified.
-      change_log = FileToText(TEST_CONFIG["CHANGELOG_FILE"])
+      change_log = FileToText(
+          os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
       self.assertEquals(
 """1999-07-31: Version 3.22.5
 
@@ -737,24 +769,23 @@
     expectations += [
       Cmd("git status -s -uno", ""),
       Cmd("git status -s -b -uno", "## some_branch\n"),
-      Cmd("git svn fetch", ""),
+      Cmd("git fetch", ""),
       Cmd("git branch", "  branch1\n* branch2\n"),
       Cmd("git branch", "  branch1\n* branch2\n"),
-      Cmd("git checkout -b %s svn/bleeding_edge" % TEST_CONFIG["BRANCHNAME"],
+      Cmd(("git new-branch %s --upstream origin/master" %
+           TEST_CONFIG["BRANCHNAME"]),
           ""),
-      Cmd("git svn find-rev r123455", "push_hash\n"),
       Cmd(("git log -1 --format=%H --grep="
            "\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based\" "
-           "svn/trunk"), "hash2\n"),
+           "origin/candidates"), "hash2\n"),
       Cmd("git log -1 hash2", "Log message\n"),
     ]
     if manual:
       expectations.append(RL("Y"))  # Confirm last push.
     expectations += [
       Cmd("git log -1 --format=%s hash2",
-       "Version 3.4.5 (based on bleeding_edge revision r1234)\n"),
-      Cmd("git svn find-rev r1234", "hash3\n"),
-      Cmd("git checkout -f svn/bleeding_edge -- src/version.cc",
+       "Version 3.4.5 (based on abc3)\n"),
+      Cmd("git checkout -f origin/master -- src/version.cc",
           "", cb=self.WriteFakeVersionFile),
       Cmd("git checkout -f hash2 -- src/version.cc", "",
           cb=self.WriteFakeVersionFile),
@@ -762,7 +793,7 @@
     if manual:
       expectations.append(RL(""))  # Increment build number.
     expectations += [
-      Cmd("git log --format=%H hash3..push_hash", "rev1\n"),
+      Cmd("git log --format=%H abc3..push_hash", "rev1\n"),
       Cmd("git log -1 --format=%s rev1", "Log text 1.\n"),
       Cmd("git log -1 --format=%B rev1", "Text\nLOG=YES\nBUG=v8:321\nText\n"),
       Cmd("git log -1 --format=%an rev1", "author1@chromium.org\n"),
@@ -773,16 +804,15 @@
       expectations.append(
           Cmd("vi %s" % TEST_CONFIG["CHANGELOG_ENTRY_FILE"], ""))
     expectations += [
-      Cmd("git svn fetch", "fetch result\n"),
-      Cmd("git checkout -f svn/bleeding_edge", ""),
-      Cmd("git diff svn/trunk push_hash", "patch content\n"),
-      Cmd("git svn find-rev push_hash", "123455\n"),
-      Cmd("git checkout -b %s svn/trunk" % TEST_CONFIG["TRUNKBRANCH"], "",
-          cb=ResetToTrunk),
+      Cmd("git fetch", ""),
+      Cmd("git checkout -f origin/master", ""),
+      Cmd("git diff origin/candidates push_hash", "patch content\n"),
+      Cmd(("git new-branch %s --upstream origin/candidates" %
+           TEST_CONFIG["TRUNKBRANCH"]), "", cb=ResetToTrunk),
       Cmd("git apply --index --reject \"%s\"" % TEST_CONFIG["PATCH_FILE"], ""),
-      Cmd("git checkout -f svn/trunk -- %s" % TEST_CONFIG["CHANGELOG_FILE"], "",
+      Cmd("git checkout -f origin/candidates -- ChangeLog", "",
           cb=ResetChangeLog),
-      Cmd("git checkout -f svn/trunk -- src/version.cc", "",
+      Cmd("git checkout -f origin/candidates -- src/version.cc", "",
           cb=self.WriteFakeVersionFile),
       Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], "",
           cb=CheckSVNCommit),
@@ -790,22 +820,26 @@
     if manual:
       expectations.append(RL("Y"))  # Sanity check.
     expectations += [
-      Cmd("git svn dcommit 2>&1",
-          "Some output\nCommitted r123456\nSome output\n"),
-      Cmd("git svn tag 3.22.5 -m \"Tagging version 3.22.5\"", ""),
+      Cmd("git cl land -f --bypass-hooks", ""),
+      Cmd("git fetch", ""),
+      Cmd("git log -1 --format=%H --grep="
+          "\"Version 3.22.5 (based on push_hash)\""
+          " origin/candidates", "hsh_to_tag"),
+      Cmd("git tag 3.22.5 hsh_to_tag", ""),
+      Cmd("git push origin 3.22.5", ""),
       Cmd("git checkout -f some_branch", ""),
       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
       Cmd("git branch -D %s" % TEST_CONFIG["TRUNKBRANCH"], ""),
     ]
     self.Expect(expectations)
 
-    args = ["-a", "author@chromium.org", "--revision", "123455"]
+    args = ["-a", "author@chromium.org", "--revision", "push_hash"]
     if force: args.append("-f")
     if manual: args.append("-m")
     else: args += ["-r", "reviewer@chromium.org"]
     PushToTrunk(TEST_CONFIG, self).Run(args)
 
-    cl = FileToText(TEST_CONFIG["CHANGELOG_FILE"])
+    cl = FileToText(os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
     self.assertTrue(re.search(r"^\d\d\d\d\-\d+\-\d+: Version 3\.22\.5", cl))
     self.assertTrue(re.search(r"        Log text 1 \(issue 321\).", cl))
     self.assertTrue(re.search(r"1999\-04\-05: Version 3\.22\.4", cl))
@@ -867,8 +901,7 @@
       Cmd("git fetch origin", ""),
       Cmd(("git log -1 --format=%H --grep="
            "\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*\" "
-           "origin/master"), "push_hash\n"),
-      Cmd("git log -1 --format=%B push_hash", self.C_V8_22624_LOG),
+           "origin/candidates"), "push_hash\n"),
       Cmd("git log -1 --format=%s push_hash",
           "Version 3.22.5 (based on bleeding_edge revision r22622)\n"),
       URL("https://chromium-build.appspot.com/p/chromium/sheriff_v8.js",
@@ -878,8 +911,8 @@
       Cmd("gclient sync --nohooks", "syncing...", cwd=chrome_dir),
       Cmd("git pull", "", cwd=chrome_dir),
       Cmd("git fetch origin", ""),
-      Cmd("git checkout -b v8-roll-22624", "", cwd=chrome_dir),
-      Cmd("roll-dep v8 22624", "rolled", cb=WriteDeps, cwd=chrome_dir),
+      Cmd("git new-branch v8-roll-push_hash", "", cwd=chrome_dir),
+      Cmd("roll-dep v8 push_hash", "rolled", cb=WriteDeps, cwd=chrome_dir),
       Cmd(("git commit -am \"Update V8 to version 3.22.5 "
            "(based on bleeding_edge revision r22622).\n\n"
            "Please reply to the V8 sheriff c_name@chromium.org in "
@@ -903,16 +936,14 @@
     self.Expect([
       Cmd(("git log -1 --format=%H --grep="
            "\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based\" "
-           "svn/trunk"), "hash2\n"),
+           "origin/candidates"), "hash2\n"),
       Cmd("git log -1 --format=%s hash2",
-          "Version 3.4.5 (based on bleeding_edge revision r99)\n"),
+          "Version 3.4.5 (based on abc123)\n"),
     ])
 
-    self._state["lkgr"] = "101"
-
-    self.assertRaises(Exception, lambda: self.RunStep(auto_push.AutoPush,
-                                                      CheckLastPush,
-                                                      AUTO_PUSH_ARGS))
+    self._state["candidate"] = "abc123"
+    self.assertEquals(0, self.RunStep(
+        auto_push.AutoPush, CheckLastPush, AUTO_PUSH_ARGS))
 
   def testAutoPush(self):
     TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
@@ -921,16 +952,16 @@
     self.Expect([
       Cmd("git status -s -uno", ""),
       Cmd("git status -s -b -uno", "## some_branch\n"),
-      Cmd("git svn fetch", ""),
+      Cmd("git fetch", ""),
       URL("https://v8-status.appspot.com/current?format=json",
           "{\"message\": \"Tree is throttled\"}"),
-      URL("https://v8-status.appspot.com/lkgr", Exception("Network problem")),
-      URL("https://v8-status.appspot.com/lkgr", "100"),
+      Cmd("git fetch origin +refs/heads/candidate:refs/heads/candidate", ""),
+      Cmd("git show-ref -s refs/heads/candidate", "abc123\n"),
       Cmd(("git log -1 --format=%H --grep=\""
            "^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based\""
-           " svn/trunk"), "push_hash\n"),
+           " origin/candidates"), "push_hash\n"),
       Cmd("git log -1 --format=%s push_hash",
-          "Version 3.4.5 (based on bleeding_edge revision r79)\n"),
+          "Version 3.4.5 (based on abc101)\n"),
     ])
 
     auto_push.AutoPush(TEST_CONFIG, self).Run(AUTO_PUSH_ARGS + ["--push"])
@@ -938,7 +969,7 @@
     state = json.loads(FileToText("%s-state.json"
                                   % TEST_CONFIG["PERSISTFILE_BASENAME"]))
 
-    self.assertEquals("100", state["lkgr"])
+    self.assertEquals("abc123", state["candidate"])
 
   def testAutoPushStoppedBySettings(self):
     TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
@@ -949,7 +980,7 @@
     self.Expect([
       Cmd("git status -s -uno", ""),
       Cmd("git status -s -b -uno", "## some_branch\n"),
-      Cmd("git svn fetch", ""),
+      Cmd("git fetch", ""),
     ])
 
     def RunAutoPush():
@@ -963,7 +994,7 @@
     self.Expect([
       Cmd("git status -s -uno", ""),
       Cmd("git status -s -b -uno", "## some_branch\n"),
-      Cmd("git svn fetch", ""),
+      Cmd("git fetch", ""),
       URL("https://v8-status.appspot.com/current?format=json",
           "{\"message\": \"Tree is throttled (no push)\"}"),
     ])
@@ -1003,9 +1034,10 @@
       URL("https://codereview.chromium.org/search",
           "owner=author%40chromium.org&limit=30&closed=3&format=json",
           ("{\"results\": [{\"subject\": \"different\"}]}")),
+      Cmd("git fetch", ""),
       Cmd(("git log -1 --format=%H --grep="
            "\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*\" "
-           "origin/master"), "push_hash\n"),
+           "origin/candidates"), "push_hash\n"),
       Cmd("git log -1 --format=%B push_hash", self.C_V8_22624_LOG),
       Cmd("git log -1 --format=%B abcd123455", self.C_V8_123455_LOG),
     ])
@@ -1024,9 +1056,10 @@
       URL("https://codereview.chromium.org/search",
           "owner=author%40chromium.org&limit=30&closed=3&format=json",
           ("{\"results\": [{\"subject\": \"different\"}]}")),
+      Cmd("git fetch", ""),
       Cmd(("git log -1 --format=%H --grep="
            "\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*\" "
-           "origin/master"), "push_hash\n"),
+           "origin/candidates"), "push_hash\n"),
       Cmd("git log -1 --format=%B push_hash", self.C_V8_123456_LOG),
       Cmd("git log -1 --format=%B abcd123455", self.C_V8_123455_LOG),
     ])
@@ -1046,7 +1079,13 @@
       return lambda: self.assertEquals(patch,
           FileToText(TEST_CONFIG["TEMPORARY_PATCH_FILE"]))
 
-    msg = """Version 3.22.5.1 (merged r12345, r23456, r34567, r45678, r56789)
+    msg = """Version 3.22.5.1 (cherry-pick)
+
+Merged ab12345
+Merged ab23456
+Merged ab34567
+Merged ab45678
+Merged ab56789
 
 Title4
 
@@ -1075,61 +1114,53 @@
     self.Expect([
       Cmd("git status -s -uno", ""),
       Cmd("git status -s -b -uno", "## some_branch\n"),
-      Cmd("git svn fetch", ""),
+      Cmd("git fetch", ""),
       Cmd("git branch", "  branch1\n* branch2\n"),
-      Cmd("git checkout -b %s svn/trunk" % TEST_CONFIG["BRANCHNAME"], ""),
-      Cmd(("git log --format=%H --grep=\"Port r12345\" "
-           "--reverse svn/bleeding_edge"),
-          "hash1\nhash2"),
-      Cmd("git svn find-rev hash1 svn/bleeding_edge", "45678"),
-      Cmd("git log -1 --format=%s hash1", "Title1"),
-      Cmd("git svn find-rev hash2 svn/bleeding_edge", "23456"),
-      Cmd("git log -1 --format=%s hash2", "Title2"),
-      Cmd(("git log --format=%H --grep=\"Port r23456\" "
-           "--reverse svn/bleeding_edge"),
+      Cmd("git new-branch %s --upstream origin/candidates" %
+          TEST_CONFIG["BRANCHNAME"], ""),
+      Cmd(("git log --format=%H --grep=\"Port ab12345\" "
+           "--reverse origin/master"),
+          "ab45678\nab23456"),
+      Cmd("git log -1 --format=%s ab45678", "Title1"),
+      Cmd("git log -1 --format=%s ab23456", "Title2"),
+      Cmd(("git log --format=%H --grep=\"Port ab23456\" "
+           "--reverse origin/master"),
           ""),
-      Cmd(("git log --format=%H --grep=\"Port r34567\" "
-           "--reverse svn/bleeding_edge"),
-          "hash3"),
-      Cmd("git svn find-rev hash3 svn/bleeding_edge", "56789"),
-      Cmd("git log -1 --format=%s hash3", "Title3"),
-      RL("Y"),  # Automatically add corresponding ports (34567, 56789)?
-      Cmd("git svn find-rev r12345 svn/bleeding_edge", "hash4"),
-      # Simulate svn being down which stops the script.
-      Cmd("git svn find-rev r23456 svn/bleeding_edge", None),
+      Cmd(("git log --format=%H --grep=\"Port ab34567\" "
+           "--reverse origin/master"),
+          "ab56789"),
+      Cmd("git log -1 --format=%s ab56789", "Title3"),
+      RL("Y"),  # Automatically add corresponding ports (ab34567, ab56789)?
+      # Simulate git being down which stops the script.
+      Cmd("git log -1 --format=%s ab12345", None),
       # Restart script in the failing step.
-      Cmd("git svn find-rev r12345 svn/bleeding_edge", "hash4"),
-      Cmd("git svn find-rev r23456 svn/bleeding_edge", "hash2"),
-      Cmd("git svn find-rev r34567 svn/bleeding_edge", "hash3"),
-      Cmd("git svn find-rev r45678 svn/bleeding_edge", "hash1"),
-      Cmd("git svn find-rev r56789 svn/bleeding_edge", "hash5"),
-      Cmd("git log -1 --format=%s hash4", "Title4"),
-      Cmd("git log -1 --format=%s hash2", "Title2"),
-      Cmd("git log -1 --format=%s hash3", "Title3"),
-      Cmd("git log -1 --format=%s hash1", "Title1"),
-      Cmd("git log -1 --format=%s hash5", "Revert \"Something\""),
-      Cmd("git log -1 hash4", "Title4\nBUG=123\nBUG=234"),
-      Cmd("git log -1 hash2", "Title2\n BUG = v8:123,345"),
-      Cmd("git log -1 hash3", "Title3\nLOG=n\nBUG=567, 456"),
-      Cmd("git log -1 hash1", "Title1\nBUG="),
-      Cmd("git log -1 hash5", "Revert \"Something\"\nBUG=none"),
-      Cmd("git log -1 -p hash4", "patch4"),
+      Cmd("git log -1 --format=%s ab12345", "Title4"),
+      Cmd("git log -1 --format=%s ab23456", "Title2"),
+      Cmd("git log -1 --format=%s ab34567", "Title3"),
+      Cmd("git log -1 --format=%s ab45678", "Title1"),
+      Cmd("git log -1 --format=%s ab56789", "Revert \"Something\""),
+      Cmd("git log -1 ab12345", "Title4\nBUG=123\nBUG=234"),
+      Cmd("git log -1 ab23456", "Title2\n BUG = v8:123,345"),
+      Cmd("git log -1 ab34567", "Title3\nLOG=n\nBUG=567, 456"),
+      Cmd("git log -1 ab45678", "Title1\nBUG="),
+      Cmd("git log -1 ab56789", "Revert \"Something\"\nBUG=none"),
+      Cmd("git log -1 -p ab12345", "patch4"),
       Cmd(("git apply --index --reject \"%s\"" %
            TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
           "", cb=VerifyPatch("patch4")),
-      Cmd("git log -1 -p hash2", "patch2"),
+      Cmd("git log -1 -p ab23456", "patch2"),
       Cmd(("git apply --index --reject \"%s\"" %
            TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
           "", cb=VerifyPatch("patch2")),
-      Cmd("git log -1 -p hash3", "patch3"),
+      Cmd("git log -1 -p ab34567", "patch3"),
       Cmd(("git apply --index --reject \"%s\"" %
            TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
           "", cb=VerifyPatch("patch3")),
-      Cmd("git log -1 -p hash1", "patch1"),
+      Cmd("git log -1 -p ab45678", "patch1"),
       Cmd(("git apply --index --reject \"%s\"" %
            TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
           "", cb=VerifyPatch("patch1")),
-      Cmd("git log -1 -p hash5", "patch5\n"),
+      Cmd("git log -1 -p ab56789", "patch5\n"),
       Cmd(("git apply --index --reject \"%s\"" %
            TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
           "", cb=VerifyPatch("patch5\n")),
@@ -1138,64 +1169,42 @@
       Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], ""),
       RL("reviewer@chromium.org"),  # V8 reviewer.
       Cmd("git cl upload --send-mail -r \"reviewer@chromium.org\" "
-          "--bypass-hooks", ""),
+          "--bypass-hooks --cc \"ulan@chromium.org\"", ""),
       Cmd("git checkout -f %s" % TEST_CONFIG["BRANCHNAME"], ""),
       RL("LGTM"),  # Enter LGTM for V8 CL.
       Cmd("git cl presubmit", "Presubmit successfull\n"),
-      Cmd("git cl dcommit -f --bypass-hooks", "Closing issue\n",
+      Cmd("git cl land -f --bypass-hooks", "Closing issue\n",
           cb=VerifySVNCommit),
-      Cmd("git svn fetch", ""),
-      Cmd(("git log -1 --format=%%H --grep=\"%s\" svn/trunk"
-           % msg.replace("\"", "\\\"")), "hash6"),
-      Cmd("git svn find-rev hash6", "1324"),
-      Cmd(("svn copy -r 1324 https://v8.googlecode.com/svn/trunk "
-           "https://v8.googlecode.com/svn/tags/3.22.5.1 -m "
-           "\"Tagging version 3.22.5.1\""), ""),
+      Cmd("git fetch", ""),
+      Cmd("git log -1 --format=%H --grep=\""
+          "Version 3.22.5.1 (cherry-pick)"
+          "\" origin/candidates",
+          ""),
+      Cmd("git fetch", ""),
+      Cmd("git log -1 --format=%H --grep=\""
+          "Version 3.22.5.1 (cherry-pick)"
+          "\" origin/candidates",
+          "hsh_to_tag"),
+      Cmd("git tag 3.22.5.1 hsh_to_tag", ""),
+      Cmd("git push origin 3.22.5.1", ""),
       Cmd("git checkout -f some_branch", ""),
       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
     ])
 
-    # r12345 and r34567 are patches. r23456 (included) and r45678 are the MIPS
-    # ports of r12345. r56789 is the MIPS port of r34567.
-    args = ["-f", "-p", extra_patch, "--branch", "trunk", "12345", "23456",
-            "34567"]
+    # ab12345 and ab34567 are patches. ab23456 (included) and ab45678 are the
+    # MIPS ports of ab12345. ab56789 is the MIPS port of ab34567.
+    args = ["-f", "-p", extra_patch, "--branch", "candidates",
+            "ab12345", "ab23456", "ab34567"]
 
-    # The first run of the script stops because of the svn being down.
+    # The first run of the script stops because of git being down.
     self.assertRaises(GitFailedException,
         lambda: MergeToBranch(TEST_CONFIG, self).Run(args))
 
     # Test that state recovery after restarting the script works.
-    args += ["-s", "3"]
+    args += ["-s", "4"]
     MergeToBranch(TEST_CONFIG, self).Run(args)
 
   def testReleases(self):
-    tag_response_text = """
-------------------------------------------------------------------------
-r22631 | author1@chromium.org | 2014-07-28 02:05:29 +0200 (Mon, 28 Jul 2014)
-Changed paths:
-   A /tags/3.28.43 (from /trunk:22630)
-
-Tagging version 3.28.43
-------------------------------------------------------------------------
-r22629 | author2@chromium.org | 2014-07-26 05:09:29 +0200 (Sat, 26 Jul 2014)
-Changed paths:
-   A /tags/3.28.41 (from /branches/bleeding_edge:22626)
-
-Tagging version 3.28.41
-------------------------------------------------------------------------
-r22556 | author3@chromium.org | 2014-07-23 13:31:59 +0200 (Wed, 23 Jul 2014)
-Changed paths:
-   A /tags/3.27.34.7 (from /branches/3.27:22555)
-
-Tagging version 3.27.34.7
-------------------------------------------------------------------------
-r22627 | author4@chromium.org | 2014-07-26 01:39:15 +0200 (Sat, 26 Jul 2014)
-Changed paths:
-   A /tags/3.28.40 (from /branches/bleeding_edge:22624)
-
-Tagging version 3.28.40
-------------------------------------------------------------------------
-"""
     c_hash2_commit_log = """Revert something.
 
 BUG=12345
@@ -1216,6 +1225,23 @@
 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3456 0039-1c4b
 
 """
+    c_hash_234_commit_log = """Version 3.3.1.1 (cherry-pick).
+
+Merged abc12.
+
+Review URL: fake.com
+
+Cr-Commit-Position: refs/heads/candidates@{#234}
+"""
+    c_hash_123_commit_log = """Version 3.3.1.0
+
+git-svn-id: googlecode@123 0039-1c4b
+"""
+    c_hash_345_commit_log = """Version 3.4.0.
+
+Cr-Commit-Position: refs/heads/candidates@{#345}
+"""
+
     json_output = self.MakeEmptyTempFile()
     csv_output = self.MakeEmptyTempFile()
     self.WriteFakeVersionFile()
@@ -1240,58 +1266,50 @@
     self.Expect([
       Cmd("git status -s -uno", ""),
       Cmd("git status -s -b -uno", "## some_branch\n"),
-      Cmd("git svn fetch", ""),
+      Cmd("git fetch", ""),
       Cmd("git branch", "  branch1\n* branch2\n"),
-      Cmd("git checkout -b %s" % TEST_CONFIG["BRANCHNAME"], ""),
-      Cmd("git branch -r", "  svn/3.21\n  svn/3.3\n"),
-      Cmd("git reset --hard svn/3.3", ""),
-      Cmd("git log --format=%H", "hash1\nhash2"),
+      Cmd("git new-branch %s" % TEST_CONFIG["BRANCHNAME"], ""),
+      Cmd("git branch -r", "  branch-heads/3.21\n  branch-heads/3.3\n"),
+      Cmd("git reset --hard branch-heads/3.3", ""),
+      Cmd("git log --format=%H", "hash1\nhash_234"),
       Cmd("git diff --name-only hash1 hash1^", ""),
-      Cmd("git diff --name-only hash2 hash2^", VERSION_FILE),
-      Cmd("git checkout -f hash2 -- %s" % VERSION_FILE, "",
+      Cmd("git diff --name-only hash_234 hash_234^", VERSION_FILE),
+      Cmd("git checkout -f hash_234 -- %s" % VERSION_FILE, "",
           cb=ResetVersion(3, 1, 1)),
-      Cmd("git log -1 --format=%B hash2",
-          "Version 3.3.1.1 (merged 12)\n\nReview URL: fake.com\n"),
-      Cmd("git log -1 --format=%s hash2", ""),
-      Cmd("git svn find-rev hash2", "234"),
-      Cmd("git log -1 --format=%ci hash2", "18:15"),
+      Cmd("git log -1 --format=%B hash_234", c_hash_234_commit_log),
+      Cmd("git log -1 --format=%s hash_234", ""),
+      Cmd("git log -1 --format=%B hash_234", c_hash_234_commit_log),
+      Cmd("git log -1 --format=%ci hash_234", "18:15"),
       Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
           cb=ResetVersion(22, 5)),
-      Cmd("git reset --hard svn/3.21", ""),
-      Cmd("git log --format=%H", "hash3\nhash4\nhash5\n"),
-      Cmd("git diff --name-only hash3 hash3^", VERSION_FILE),
-      Cmd("git checkout -f hash3 -- %s" % VERSION_FILE, "",
+      Cmd("git reset --hard branch-heads/3.21", ""),
+      Cmd("git log --format=%H", "hash_123\nhash4\nhash5\n"),
+      Cmd("git diff --name-only hash_123 hash_123^", VERSION_FILE),
+      Cmd("git checkout -f hash_123 -- %s" % VERSION_FILE, "",
           cb=ResetVersion(21, 2)),
-      Cmd("git log -1 --format=%B hash3", ""),
-      Cmd("git log -1 --format=%s hash3", ""),
-      Cmd("git svn find-rev hash3", "123"),
-      Cmd("git log -1 --format=%ci hash3", "03:15"),
+      Cmd("git log -1 --format=%B hash_123", c_hash_123_commit_log),
+      Cmd("git log -1 --format=%s hash_123", ""),
+      Cmd("git log -1 --format=%B hash_123", c_hash_123_commit_log),
+      Cmd("git log -1 --format=%ci hash_123", "03:15"),
       Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
           cb=ResetVersion(22, 5)),
-      Cmd("git reset --hard svn/trunk", ""),
-      Cmd("git log --format=%H", "hash6\n"),
-      Cmd("git diff --name-only hash6 hash6^", VERSION_FILE),
-      Cmd("git checkout -f hash6 -- %s" % VERSION_FILE, "",
+      Cmd("git reset --hard origin/candidates", ""),
+      Cmd("git log --format=%H", "hash_345\n"),
+      Cmd("git diff --name-only hash_345 hash_345^", VERSION_FILE),
+      Cmd("git checkout -f hash_345 -- %s" % VERSION_FILE, "",
           cb=ResetVersion(22, 3)),
-      Cmd("git log -1 --format=%B hash6", ""),
-      Cmd("git log -1 --format=%s hash6", ""),
-      Cmd("git svn find-rev hash6", "345"),
-      Cmd("git log -1 --format=%ci hash6", ""),
+      Cmd("git log -1 --format=%B hash_345", c_hash_345_commit_log),
+      Cmd("git log -1 --format=%s hash_345", ""),
+      Cmd("git log -1 --format=%B hash_345", c_hash_345_commit_log),
+      Cmd("git log -1 --format=%ci hash_345", ""),
       Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
           cb=ResetVersion(22, 5)),
-      Cmd("git reset --hard svn/bleeding_edge", ""),
-      Cmd("svn log https://v8.googlecode.com/svn/tags -v --limit 20",
-          tag_response_text),
-      Cmd("git svn find-rev r22626", "hash_22626"),
-      Cmd("git svn find-rev hash_22626", "22626"),
-      Cmd("git log -1 --format=%ci hash_22626", "01:23"),
-      Cmd("git svn find-rev r22624", "hash_22624"),
-      Cmd("git svn find-rev hash_22624", "22624"),
-      Cmd("git log -1 --format=%ci hash_22624", "02:34"),
+      Cmd("git reset --hard origin/master", ""),
       Cmd("git status -s -uno", "", cwd=chrome_dir),
       Cmd("git checkout -f master", "", cwd=chrome_dir),
       Cmd("git pull", "", cwd=chrome_dir),
-      Cmd("git checkout -b %s" % TEST_CONFIG["BRANCHNAME"], "", cwd=chrome_dir),
+      Cmd("git new-branch %s" % TEST_CONFIG["BRANCHNAME"], "",
+          cwd=chrome_dir),
       Cmd("git fetch origin", "", cwd=chrome_v8_dir),
       Cmd("git log --format=%H --grep=\"V8\"", "c_hash1\nc_hash2\nc_hash3\n",
           cwd=chrome_dir),
@@ -1302,8 +1320,6 @@
           cwd=chrome_dir),
       Cmd("git log -1 --format=%B c_hash2", c_hash2_commit_log,
           cwd=chrome_dir),
-      Cmd("git rev-list -n 1 0123456789012345678901234567890123456789",
-          "0123456789012345678901234567890123456789", cwd=chrome_v8_dir),
       Cmd("git log -1 --format=%B 0123456789012345678901234567890123456789",
           self.C_V8_22624_LOG, cwd=chrome_v8_dir),
       Cmd("git diff --name-only c_hash3 c_hash3^", "DEPS", cwd=chrome_dir),
@@ -1331,35 +1347,54 @@
     Releases(TEST_CONFIG, self).Run(args)
 
     # Check expected output.
-    csv = ("3.28.41,bleeding_edge,22626,,\r\n"
-           "3.28.40,bleeding_edge,22624,4567,\r\n"
-           "3.22.3,trunk,345,3456:4566,\r\n"
+    csv = ("3.22.3,candidates,345,3456:4566,\r\n"
            "3.21.2,3.21,123,,\r\n"
-           "3.3.1.1,3.3,234,,12\r\n")
+           "3.3.1.1,3.3,234,,abc12\r\n")
     self.assertEquals(csv, FileToText(csv_output))
 
     expected_json = [
-      {"bleeding_edge": "22626", "patches_merged": "", "version": "3.28.41",
-       "chromium_revision": "", "branch": "bleeding_edge", "revision": "22626",
-       "review_link": "", "date": "01:23", "chromium_branch": "",
-       "revision_link": "https://code.google.com/p/v8/source/detail?r=22626"},
-      {"bleeding_edge": "22624", "patches_merged": "", "version": "3.28.40",
-       "chromium_revision": "4567", "branch": "bleeding_edge",
-       "revision": "22624", "review_link": "", "date": "02:34",
-       "chromium_branch": "",
-       "revision_link": "https://code.google.com/p/v8/source/detail?r=22624"},
-      {"bleeding_edge": "", "patches_merged": "", "version": "3.22.3",
-       "chromium_revision": "3456:4566", "branch": "trunk", "revision": "345",
-       "review_link": "", "date": "", "chromium_branch": "7",
-       "revision_link": "https://code.google.com/p/v8/source/detail?r=345"},
-      {"patches_merged": "", "bleeding_edge": "", "version": "3.21.2",
-       "chromium_revision": "", "branch": "3.21", "revision": "123",
-       "review_link": "", "date": "03:15", "chromium_branch": "",
-       "revision_link": "https://code.google.com/p/v8/source/detail?r=123"},
-      {"patches_merged": "12", "bleeding_edge": "", "version": "3.3.1.1",
-       "chromium_revision": "", "branch": "3.3", "revision": "234",
-       "review_link": "fake.com", "date": "18:15", "chromium_branch": "",
-       "revision_link": "https://code.google.com/p/v8/source/detail?r=234"},
+      {
+        "revision": "345",
+        "revision_git": "hash_345",
+        "bleeding_edge": "",
+        "bleeding_edge_git": "",
+        "patches_merged": "",
+        "version": "3.22.3",
+        "chromium_revision": "3456:4566",
+        "branch": "candidates",
+        "review_link": "",
+        "date": "",
+        "chromium_branch": "7",
+        "revision_link": "https://code.google.com/p/v8/source/detail?r=345",
+      },
+      {
+        "revision": "123",
+        "revision_git": "hash_123",
+        "patches_merged": "",
+        "bleeding_edge": "",
+        "bleeding_edge_git": "",
+        "version": "3.21.2",
+        "chromium_revision": "",
+        "branch": "3.21",
+        "review_link": "",
+        "date": "03:15",
+        "chromium_branch": "",
+        "revision_link": "https://code.google.com/p/v8/source/detail?r=123",
+      },
+      {
+        "revision": "234",
+        "revision_git": "hash_234",
+        "patches_merged": "abc12",
+        "bleeding_edge": "",
+        "bleeding_edge_git": "",
+        "version": "3.3.1.1",
+        "chromium_revision": "",
+        "branch": "3.3",
+        "review_link": "fake.com",
+        "date": "18:15",
+        "chromium_branch": "",
+        "revision_link": "https://code.google.com/p/v8/source/detail?r=234",
+      },
     ]
     self.assertEquals(expected_json, json.loads(FileToText(json_output)))
 
@@ -1374,26 +1409,27 @@
 
     return [
       Cmd("git status -s -uno", ""),
-      Cmd("git checkout -f bleeding_edge", "", cb=ResetVersion(11, 4)),
+      Cmd("git checkout -f master", "", cb=ResetVersion(11, 4)),
       Cmd("git pull", ""),
       Cmd("git branch", ""),
-      Cmd("git checkout -f bleeding_edge", ""),
+      Cmd("git checkout -f master", ""),
       Cmd("git log -1 --format=%H", "latest_hash"),
       Cmd("git diff --name-only latest_hash latest_hash^", ""),
       URL("https://v8-status.appspot.com/lkgr", "12345"),
-      Cmd("git checkout -f bleeding_edge", ""),
+      Cmd("git checkout -f master", ""),
       Cmd(("git log --format=%H --grep="
            "\"^git-svn-id: [^@]*@12345 [A-Za-z0-9-]*$\""),
           "lkgr_hash"),
-      Cmd("git checkout -b auto-bump-up-version lkgr_hash", ""),
-      Cmd("git checkout -f bleeding_edge", ""),
-      Cmd("git branch", ""),
+      Cmd("git new-branch auto-bump-up-version --upstream lkgr_hash", ""),
+      Cmd("git checkout -f master", ""),
+      Cmd("git branch", "auto-bump-up-version\n* master"),
+      Cmd("git branch -D auto-bump-up-version", ""),
       Cmd("git diff --name-only lkgr_hash lkgr_hash^", ""),
-      Cmd("git checkout -f master", "", cb=ResetVersion(11, 5)),
+      Cmd("git checkout -f candidates", "", cb=ResetVersion(11, 5)),
       Cmd("git pull", ""),
       URL("https://v8-status.appspot.com/current?format=json",
           "{\"message\": \"Tree is open\"}"),
-      Cmd("git checkout -b auto-bump-up-version bleeding_edge", "",
+      Cmd("git new-branch auto-bump-up-version --upstream master", "",
           cb=ResetVersion(11, 4)),
       Cmd("git commit -am \"[Auto-roll] Bump up version to 3.11.6.0\n\n"
           "TBR=author@chromium.org\" "
@@ -1405,88 +1441,15 @@
     expectations += [
       Cmd("git cl upload --send-mail --email \"author@chromium.org\" -f "
           "--bypass-hooks", ""),
-      Cmd("git cl dcommit -f --bypass-hooks", ""),
-      Cmd("git checkout -f bleeding_edge", ""),
-      Cmd("git branch", "auto-bump-up-version\n* bleeding_edge"),
+      Cmd("git cl land -f --bypass-hooks", ""),
+      Cmd("git checkout -f master", ""),
+      Cmd("git branch", "auto-bump-up-version\n* master"),
       Cmd("git branch -D auto-bump-up-version", ""),
     ]
     self.Expect(expectations)
 
     BumpUpVersion(TEST_CONFIG, self).Run(["-a", "author@chromium.org"])
 
-  def testBumpUpVersionSvn(self):
-    svn_root = self.MakeEmptyTempDirectory()
-    expectations = self._bumpUpVersion()
-    expectations += [
-      Cmd("git diff HEAD^ HEAD", "patch content"),
-      Cmd("svn update", "", cwd=svn_root),
-      Cmd("svn status", "", cwd=svn_root),
-      Cmd("patch -d branches/bleeding_edge -p1 -i %s" %
-          TEST_CONFIG["PATCH_FILE"], "Applied patch...", cwd=svn_root),
-      Cmd("svn commit --non-interactive --username=author@chromium.org "
-          "--config-dir=[CONFIG_DIR] "
-          "-m \"[Auto-roll] Bump up version to 3.11.6.0\"",
-          "", cwd=svn_root),
-      Cmd("git checkout -f bleeding_edge", ""),
-      Cmd("git branch", "auto-bump-up-version\n* bleeding_edge"),
-      Cmd("git branch -D auto-bump-up-version", ""),
-    ]
-    self.Expect(expectations)
-
-    BumpUpVersion(TEST_CONFIG, self).Run(
-        ["-a", "author@chromium.org",
-         "--svn", svn_root,
-         "--svn-config", "[CONFIG_DIR]"])
-
-  def testAutoTag(self):
-    self.WriteFakeVersionFile()
-
-    def ResetVersion(minor, build, patch=0):
-      return lambda: self.WriteFakeVersionFile(minor=minor,
-                                               build=build,
-                                               patch=patch)
-
-    self.Expect([
-      Cmd("git status -s -uno", ""),
-      Cmd("git status -s -b -uno", "## some_branch\n"),
-      Cmd("git svn fetch", ""),
-      Cmd("git branch", "  branch1\n* branch2\n"),
-      Cmd("git checkout -f master", ""),
-      Cmd("git svn rebase", ""),
-      Cmd("git checkout -b %s" % TEST_CONFIG["BRANCHNAME"], "",
-          cb=ResetVersion(4, 5)),
-      Cmd("git branch -r",
-          "svn/tags/3.4.2\nsvn/tags/3.2.1.0\nsvn/branches/3.4"),
-      Cmd(("git log --format=%H --grep="
-           "\"\\[Auto\\-roll\\] Bump up version to\""),
-          "hash125\nhash118\nhash111\nhash101"),
-      Cmd("git checkout -f hash125 -- %s" % VERSION_FILE, "",
-          cb=ResetVersion(4, 4)),
-      Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
-          cb=ResetVersion(4, 5)),
-      Cmd("git checkout -f hash118 -- %s" % VERSION_FILE, "",
-          cb=ResetVersion(4, 3)),
-      Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
-          cb=ResetVersion(4, 5)),
-      Cmd("git checkout -f hash111 -- %s" % VERSION_FILE, "",
-          cb=ResetVersion(4, 2)),
-      Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
-          cb=ResetVersion(4, 5)),
-      URL("https://v8-status.appspot.com/revisions?format=json",
-          "[{\"revision\": \"126\", \"status\": true},"
-           "{\"revision\": \"123\", \"status\": true},"
-           "{\"revision\": \"112\", \"status\": true}]"),
-      Cmd("git svn find-rev hash118", "118"),
-      Cmd("git svn find-rev hash125", "125"),
-      Cmd("git svn find-rev r123", "hash123"),
-      Cmd("git log -1 --format=%at hash123", "1"),
-      Cmd("git reset --hard hash123", ""),
-      Cmd("git svn tag 3.4.3 -m \"Tagging version 3.4.3\"", ""),
-      Cmd("git checkout -f some_branch", ""),
-      Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
-    ])
-
-    AutoTag(TEST_CONFIG, self).Run(["-a", "author@chromium.org"])
 
   # Test that we bail out if the last change was a version change.
   def testBumpUpVersionBailout1(self):
@@ -1527,7 +1490,10 @@
 
 class SystemTest(unittest.TestCase):
   def testReload(self):
+    options = ScriptsBase(
+        TEST_CONFIG, DEFAULT_SIDE_EFFECT_HANDLER, {}).MakeOptions([])
     step = MakeStep(step_class=PrepareChangeLog, number=0, state={}, config={},
+                    options=options,
                     side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER)
     body = step.Reload(
 """------------------------------------------------------------------------
diff --git a/tools/run-deopt-fuzzer.py b/tools/run-deopt-fuzzer.py
index 57cb6b2..a6fdf31 100755
--- a/tools/run-deopt-fuzzer.py
+++ b/tools/run-deopt-fuzzer.py
@@ -160,6 +160,9 @@
   result.add_option("--buildbot",
                     help="Adapt to path structure used on buildbots",
                     default=False, action="store_true")
+  result.add_option("--dcheck-always-on",
+                    help="Indicates that V8 was compiled with DCHECKs enabled",
+                    default=False, action="store_true")
   result.add_option("--command-prefix",
                     help="Prepended to each shell command used to run a test",
                     default="")
@@ -389,6 +392,8 @@
     "simulator": utils.UseSimulator(arch),
     "system": utils.GuessOS(),
     "tsan": False,
+    "msan": False,
+    "dcheck_always_on": options.dcheck_always_on,
   }
   all_tests = []
   num_tests = 0
diff --git a/tools/run-llprof.sh b/tools/run-llprof.sh
index d526170..54a3881 100755
--- a/tools/run-llprof.sh
+++ b/tools/run-llprof.sh
@@ -66,4 +66,4 @@
 fi
 
 echo "Running benchmark..."
-perf record -R -e cycles -c $SAMPLE_EVERY_N_CYCLES -f -i $@ --ll-prof
+perf record -R -e cycles -c $SAMPLE_EVERY_N_CYCLES -i $@ --ll-prof
diff --git a/tools/run-tests.py b/tools/run-tests.py
index d48b70c..d68d1f8 100755
--- a/tools/run-tests.py
+++ b/tools/run-tests.py
@@ -44,6 +44,7 @@
 from testrunner.local import execution
 from testrunner.local import progress
 from testrunner.local import testsuite
+from testrunner.local.testsuite import VARIANT_FLAGS
 from testrunner.local import utils
 from testrunner.local import verbose
 from testrunner.network import network_execution
@@ -51,9 +52,13 @@
 
 
 ARCH_GUESS = utils.DefaultArch()
-DEFAULT_TESTS = ["mjsunit", "fuzz-natives", "base-unittests",
-                 "cctest", "compiler-unittests", "heap-unittests",
-                 "libplatform-unittests", "message", "preparser"]
+DEFAULT_TESTS = [
+  "mjsunit",
+  "unittests",
+  "cctest",
+  "message",
+  "preparser",
+]
 
 # Map of test name synonyms to lists of test suites. Should be ordered by
 # expected runtimes (suites with slow test cases first). These groups are
@@ -61,7 +66,6 @@
 TEST_MAP = {
   "default": [
     "mjsunit",
-    "fuzz-natives",
     "cctest",
     "message",
     "preparser",
@@ -72,10 +76,7 @@
     "webkit",
   ],
   "unittests": [
-    "compiler-unittests",
-    "heap-unittests",
-    "base-unittests",
-    "libplatform-unittests",
+    "unittests",
   ],
 }
 
@@ -83,13 +84,6 @@
 TIMEOUT_SCALEFACTOR = {"debug"   : 4,
                        "release" : 1 }
 
-# Use this to run several variants of the tests.
-VARIANT_FLAGS = {
-    "default": [],
-    "stress": ["--stress-opt", "--always-opt"],
-    "turbofan": ["--turbo-filter=*", "--always-opt"],
-    "nocrankshaft": ["--nocrankshaft"]}
-
 VARIANTS = ["default", "stress", "turbofan", "nocrankshaft"]
 
 MODE_FLAGS = {
@@ -147,6 +141,9 @@
   result.add_option("--buildbot",
                     help="Adapt to path structure used on buildbots",
                     default=False, action="store_true")
+  result.add_option("--dcheck-always-on",
+                    help="Indicates that V8 was compiled with DCHECKs enabled",
+                    default=False, action="store_true")
   result.add_option("--cat", help="Print the source of the tests",
                     default=False, action="store_true")
   result.add_option("--flaky-tests",
@@ -257,6 +254,9 @@
                     default="v8tests")
   result.add_option("--random-seed", default=0, dest="random_seed",
                     help="Default seed for initializing random generator")
+  result.add_option("--msan",
+                    help="Regard test expectations for MSAN",
+                    default=False, action="store_true")
   return result
 
 
@@ -309,6 +309,11 @@
 
   if options.tsan:
     VARIANTS = ["default"]
+    suppressions_file = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                                     'sanitizers', 'tsan_suppressions.txt')
+    tsan_options = '%s suppressions=%s' % (
+        os.environ.get('TSAN_OPTIONS', ''), suppressions_file)
+    os.environ['TSAN_OPTIONS'] = tsan_options
 
   if options.j == 0:
     options.j = multiprocessing.cpu_count()
@@ -489,7 +494,8 @@
 
   # TODO(all): Combine "simulator" and "simulator_run".
   simulator_run = not options.dont_skip_simulator_slow_tests and \
-      arch in ['arm64', 'arm', 'mips'] and ARCH_GUESS and arch != ARCH_GUESS
+      arch in ['arm64', 'arm', 'mipsel', 'mips', 'mips64el'] and \
+      ARCH_GUESS and arch != ARCH_GUESS
   # Find available test suites and read test cases from them.
   variables = {
     "arch": arch,
@@ -504,6 +510,8 @@
     "simulator": utils.UseSimulator(arch),
     "system": utils.GuessOS(),
     "tsan": options.tsan,
+    "msan": options.msan,
+    "dcheck_always_on": options.dcheck_always_on,
   }
   all_tests = []
   num_tests = 0
diff --git a/tools/run_perf.py b/tools/run_perf.py
index 920c18d..63c9148 100755
--- a/tools/run_perf.py
+++ b/tools/run_perf.py
@@ -15,9 +15,10 @@
   "archs": [<architecture name for which this suite is run>, ...],
   "binary": <name of binary to run, default "d8">,
   "flags": [<flag to d8>, ...],
+  "test_flags": [<flag to the test file>, ...],
   "run_count": <how often will this suite run (optional)>,
   "run_count_XXX": <how often will this suite run for arch XXX (optional)>,
-  "resources": [<js file to be loaded before main>, ...]
+  "resources": [<js file to be moved to android device>, ...]
   "main": <main js perf runner file>,
   "results_regexp": <optional regexp>,
   "results_processor": <optional python results processor script>,
@@ -54,6 +55,7 @@
 {
   "path": ["."],
   "flags": ["--expose-gc"],
+  "test_flags": ["5"],
   "archs": ["ia32", "x64"],
   "run_count": 5,
   "run_count_ia32": 3,
@@ -89,9 +91,13 @@
 }
 
 Path pieces are concatenated. D8 is always run with the suite's path as cwd.
+
+The test flags are passed to the js test file after '--'.
 """
 
+from collections import OrderedDict
 import json
+import logging
 import math
 import optparse
 import os
@@ -114,8 +120,25 @@
                    "x64",
                    "arm64"]
 
-GENERIC_RESULTS_RE = re.compile(
-    r"^Trace\(([^\)]+)\), Result\(([^\)]+)\), StdDev\(([^\)]+)\)$")
+GENERIC_RESULTS_RE = re.compile(r"^RESULT ([^:]+): ([^=]+)= ([^ ]+) ([^ ]*)$")
+RESULT_STDDEV_RE = re.compile(r"^\{([^\}]+)\}$")
+RESULT_LIST_RE = re.compile(r"^\[([^\]]+)\]$")
+
+
+def LoadAndroidBuildTools(path):  # pragma: no cover
+  assert os.path.exists(path)
+  sys.path.insert(0, path)
+
+  from pylib.device import device_utils  # pylint: disable=F0401
+  from pylib.device import device_errors  # pylint: disable=F0401
+  from pylib.perf import cache_control  # pylint: disable=F0401
+  from pylib.perf import perf_control  # pylint: disable=F0401
+  import pylib.android_commands  # pylint: disable=F0401
+  global cache_control
+  global device_errors
+  global device_utils
+  global perf_control
+  global pylib
 
 
 def GeometricMean(values):
@@ -168,6 +191,7 @@
     self.path = []
     self.graphs = []
     self.flags = []
+    self.test_flags = []
     self.resources = []
     self.results_regexp = None
     self.stddev_regexp = None
@@ -187,19 +211,24 @@
     assert isinstance(suite.get("path", []), list)
     assert isinstance(suite["name"], basestring)
     assert isinstance(suite.get("flags", []), list)
+    assert isinstance(suite.get("test_flags", []), list)
     assert isinstance(suite.get("resources", []), list)
 
     # Accumulated values.
     self.path = parent.path[:] + suite.get("path", [])
     self.graphs = parent.graphs[:] + [suite["name"]]
     self.flags = parent.flags[:] + suite.get("flags", [])
-    self.resources = parent.resources[:] + suite.get("resources", [])
+    self.test_flags = parent.test_flags[:] + suite.get("test_flags", [])
+
+    # Values independent of parent node.
+    self.resources = suite.get("resources", [])
 
     # Descrete values (with parent defaults).
     self.binary = suite.get("binary", parent.binary)
     self.run_count = suite.get("run_count", parent.run_count)
     self.run_count = suite.get("run_count_%s" % arch, self.run_count)
     self.timeout = suite.get("timeout", parent.timeout)
+    self.timeout = suite.get("timeout_%s" % arch, self.timeout)
     self.units = suite.get("units", parent.units)
     self.total = suite.get("total", parent.total)
 
@@ -236,8 +265,11 @@
 
   def ConsumeOutput(self, stdout):
     try:
-      self.results.append(
-          re.search(self.results_regexp, stdout, re.M).group(1))
+      result = re.search(self.results_regexp, stdout, re.M).group(1)
+      self.results.append(str(float(result)))
+    except ValueError:
+      self.errors.append("Regexp \"%s\" returned a non-numeric for test %s."
+                         % (self.results_regexp, self.graphs[-1]))
     except:
       self.errors.append("Regexp \"%s\" didn't match for test %s."
                          % (self.results_regexp, self.graphs[-1]))
@@ -277,14 +309,13 @@
     bench_dir = os.path.normpath(os.path.join(*self.path))
     os.chdir(os.path.join(suite_dir, bench_dir))
 
+  def GetCommandFlags(self):
+    suffix = ["--"] + self.test_flags if self.test_flags else []
+    return self.flags + [self.main] + suffix
+
   def GetCommand(self, shell_dir):
     # TODO(machenbach): This requires +.exe if run on windows.
-    return (
-      [os.path.join(shell_dir, self.binary)] +
-      self.flags +
-      self.resources +
-      [self.main]
-    )
+    return [os.path.join(shell_dir, self.binary)] + self.GetCommandFlags()
 
   def Run(self, runner):
     """Iterates over several runs and handles the output for all traces."""
@@ -334,21 +365,41 @@
 
   def Run(self, runner):
     """Iterates over several runs and handles the output."""
-    traces = {}
+    traces = OrderedDict()
     for stdout in runner():
       for line in stdout.strip().splitlines():
         match = GENERIC_RESULTS_RE.match(line)
         if match:
-          trace = match.group(1)
-          result = match.group(2)
-          stddev = match.group(3)
+          stddev = ""
+          graph = match.group(1)
+          trace = match.group(2)
+          body = match.group(3)
+          units = match.group(4)
+          match_stddev = RESULT_STDDEV_RE.match(body)
+          match_list = RESULT_LIST_RE.match(body)
+          errors = []
+          if match_stddev:
+            result, stddev = map(str.strip, match_stddev.group(1).split(","))
+            results = [result]
+          elif match_list:
+            results = map(str.strip, match_list.group(1).split(","))
+          else:
+            results = [body.strip()]
+
+          try:
+            results = map(lambda r: str(float(r)), results)
+          except ValueError:
+            results = []
+            errors = ["Found non-numeric in %s" %
+                      "/".join(self.graphs + [graph, trace])]
+
           trace_result = traces.setdefault(trace, Results([{
-            "graphs": self.graphs + [trace],
-            "units": self.units,
+            "graphs": self.graphs + [graph, trace],
+            "units": (units or self.units).strip(),
             "results": [],
             "stddev": "",
-          }], []))
-          trace_result.traces[0]["results"].append(result)
+          }], errors))
+          trace_result.traces[0]["results"].extend(results)
           trace_result.traces[0]["stddev"] = stddev
 
     return reduce(lambda r, t: r + t, traces.itervalues(), Results())
@@ -385,7 +436,7 @@
   parent = parent or DefaultSentinel()
 
   # TODO(machenbach): Implement notion of cpu type?
-  if arch not in suite.get("archs", ["ia32", "x64"]):
+  if arch not in suite.get("archs", SUPPORTED_ARCHS):
     return None
 
   graph = MakeGraph(suite, arch, parent)
@@ -395,23 +446,167 @@
   return graph
 
 
-def FlattenRunnables(node):
+def FlattenRunnables(node, node_cb):
   """Generator that traverses the tree structure and iterates over all
   runnables.
   """
+  node_cb(node)
   if isinstance(node, Runnable):
     yield node
   elif isinstance(node, Node):
     for child in node._children:
-      for result in FlattenRunnables(child):
+      for result in FlattenRunnables(child, node_cb):
         yield result
   else:  # pragma: no cover
     raise Exception("Invalid suite configuration.")
 
 
+class Platform(object):
+  @staticmethod
+  def GetPlatform(options):
+    if options.arch.startswith("android"):
+      return AndroidPlatform(options)
+    else:
+      return DesktopPlatform(options)
+
+
+class DesktopPlatform(Platform):
+  def __init__(self, options):
+    self.shell_dir = options.shell_dir
+
+  def PreExecution(self):
+    pass
+
+  def PostExecution(self):
+    pass
+
+  def PreTests(self, node, path):
+    if isinstance(node, Runnable):
+      node.ChangeCWD(path)
+
+  def Run(self, runnable, count):
+    output = commands.Execute(runnable.GetCommand(self.shell_dir),
+                              timeout=runnable.timeout)
+    print ">>> Stdout (#%d):" % (count + 1)
+    print output.stdout
+    if output.stderr:  # pragma: no cover
+      # Print stderr for debugging.
+      print ">>> Stderr (#%d):" % (count + 1)
+      print output.stderr
+    if output.timed_out:
+      print ">>> Test timed out after %ss." % runnable.timeout
+    return output.stdout
+
+
+class AndroidPlatform(Platform):  # pragma: no cover
+  DEVICE_DIR = "/data/local/tmp/v8/"
+
+  def __init__(self, options):
+    self.shell_dir = options.shell_dir
+    LoadAndroidBuildTools(options.android_build_tools)
+
+    if not options.device:
+      # Detect attached device if not specified.
+      devices = pylib.android_commands.GetAttachedDevices(
+          hardware=True, emulator=False, offline=False)
+      assert devices and len(devices) == 1, (
+          "None or multiple devices detected. Please specify the device on "
+          "the command-line with --device")
+      options.device = devices[0]
+    adb_wrapper = pylib.android_commands.AndroidCommands(options.device)
+    self.device = device_utils.DeviceUtils(adb_wrapper)
+    self.adb = adb_wrapper.Adb()
+
+  def PreExecution(self):
+    perf = perf_control.PerfControl(self.device)
+    perf.SetHighPerfMode()
+
+    # Remember what we have already pushed to the device.
+    self.pushed = set()
+
+  def PostExecution(self):
+    perf = perf_control.PerfControl(self.device)
+    perf.SetDefaultPerfMode()
+    self.device.RunShellCommand(["rm", "-rf", AndroidPlatform.DEVICE_DIR])
+
+  def _SendCommand(self, cmd):
+    logging.info("adb -s %s %s" % (str(self.device), cmd))
+    return self.adb.SendCommand(cmd, timeout_time=60)
+
+  def _PushFile(self, host_dir, file_name, target_rel="."):
+    file_on_host = os.path.join(host_dir, file_name)
+    file_on_device_tmp = os.path.join(
+        AndroidPlatform.DEVICE_DIR, "_tmp_", file_name)
+    file_on_device = os.path.join(
+        AndroidPlatform.DEVICE_DIR, target_rel, file_name)
+    folder_on_device = os.path.dirname(file_on_device)
+
+    # Only push files not yet pushed in one execution.
+    if file_on_host in self.pushed:
+      return
+    else:
+      self.pushed.add(file_on_host)
+
+    # Work-around for "text file busy" errors. Push the files to a temporary
+    # location and then copy them with a shell command.
+    output = self._SendCommand(
+        "push %s %s" % (file_on_host, file_on_device_tmp))
+    # Success looks like this: "3035 KB/s (12512056 bytes in 4.025s)".
+    # Errors look like this: "failed to copy  ... ".
+    if output and not re.search('^[0-9]', output.splitlines()[-1]):
+      logging.critical('PUSH FAILED: ' + output)
+    self._SendCommand("shell mkdir -p %s" % folder_on_device)
+    self._SendCommand("shell cp %s %s" % (file_on_device_tmp, file_on_device))
+
+  def PreTests(self, node, path):
+    suite_dir = os.path.abspath(os.path.dirname(path))
+    if node.path:
+      bench_rel = os.path.normpath(os.path.join(*node.path))
+      bench_abs = os.path.join(suite_dir, bench_rel)
+    else:
+      bench_rel = "."
+      bench_abs = suite_dir
+
+    self._PushFile(self.shell_dir, node.binary)
+    if isinstance(node, Runnable):
+      self._PushFile(bench_abs, node.main, bench_rel)
+    for resource in node.resources:
+      self._PushFile(bench_abs, resource, bench_rel)
+
+  def Run(self, runnable, count):
+    cache = cache_control.CacheControl(self.device)
+    cache.DropRamCaches()
+    binary_on_device = AndroidPlatform.DEVICE_DIR + runnable.binary
+    cmd = [binary_on_device] + runnable.GetCommandFlags()
+
+    # Relative path to benchmark directory.
+    if runnable.path:
+      bench_rel = os.path.normpath(os.path.join(*runnable.path))
+    else:
+      bench_rel = "."
+
+    try:
+      output = self.device.RunShellCommand(
+          cmd,
+          cwd=os.path.join(AndroidPlatform.DEVICE_DIR, bench_rel),
+          timeout=runnable.timeout,
+          retries=0,
+      )
+      stdout = "\n".join(output)
+      print ">>> Stdout (#%d):" % (count + 1)
+      print stdout
+    except device_errors.CommandTimeoutError:
+      print ">>> Test timed out after %ss." % runnable.timeout
+      stdout = ""
+    return stdout
+
+
 # TODO: Implement results_processor.
 def Main(args):
+  logging.getLogger().setLevel(logging.INFO)
   parser = optparse.OptionParser()
+  parser.add_option("--android-build-tools",
+                    help="Path to chromium's build/android.")
   parser.add_option("--arch",
                     help=("The architecture to run tests for, "
                           "'auto' or 'native' for auto-detect"),
@@ -419,6 +614,9 @@
   parser.add_option("--buildbot",
                     help="Adapt to path structure used on buildbots",
                     default=False, action="store_true")
+  parser.add_option("--device",
+                    help="The device ID to run Android tests on. If not given "
+                         "it will be autodetected.")
   parser.add_option("--json-test-results",
                     help="Path to a file for storing json results.")
   parser.add_option("--outdir", help="Base directory with compile output",
@@ -436,13 +634,26 @@
     print "Unknown architecture %s" % options.arch
     return 1
 
+  if (bool(options.arch.startswith("android")) !=
+      bool(options.android_build_tools)):  # pragma: no cover
+    print ("Android architectures imply setting --android-build-tools and the "
+           "other way around.")
+    return 1
+
+  if (options.device and not
+      options.arch.startswith("android")):  # pragma: no cover
+    print "Specifying a device requires an Android architecture to be used."
+    return 1
+
   workspace = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
 
   if options.buildbot:
-    shell_dir = os.path.join(workspace, options.outdir, "Release")
+    options.shell_dir = os.path.join(workspace, options.outdir, "Release")
   else:
-    shell_dir = os.path.join(workspace, options.outdir,
-                             "%s.release" % options.arch)
+    options.shell_dir = os.path.join(workspace, options.outdir,
+                                     "%s.release" % options.arch)
+
+  platform = Platform.GetPlatform(options)
 
   results = Results()
   for path in args:
@@ -458,30 +669,32 @@
     # If no name is given, default to the file name without .json.
     suite.setdefault("name", os.path.splitext(os.path.basename(path))[0])
 
-    for runnable in FlattenRunnables(BuildGraphs(suite, options.arch)):
+    # Setup things common to one test suite.
+    platform.PreExecution()
+
+    # Build the graph/trace tree structure.
+    root = BuildGraphs(suite, options.arch)
+
+    # Callback to be called on each node on traversal.
+    def NodeCB(node):
+      platform.PreTests(node, path)
+
+    # Traverse graph/trace tree and interate over all runnables.
+    for runnable in FlattenRunnables(root, NodeCB):
       print ">>> Running suite: %s" % "/".join(runnable.graphs)
-      runnable.ChangeCWD(path)
 
       def Runner():
         """Output generator that reruns several times."""
         for i in xrange(0, max(1, runnable.run_count)):
           # TODO(machenbach): Allow timeout per arch like with run_count per
           # arch.
-          output = commands.Execute(runnable.GetCommand(shell_dir),
-                                    timeout=runnable.timeout)
-          print ">>> Stdout (#%d):" % (i + 1)
-          print output.stdout
-          if output.stderr:  # pragma: no cover
-            # Print stderr for debugging.
-            print ">>> Stderr (#%d):" % (i + 1)
-            print output.stderr
-          if output.timed_out:
-            print ">>> Test timed out after %ss." % runnable.timeout
-          yield output.stdout
+          yield platform.Run(runnable, i)
 
       # Let runnable iterate over all runs and handle output.
       results += runnable.Run(Runner)
 
+    platform.PostExecution()
+
   if options.json_test_results:
     results.WriteToFile(options.json_test_results)
   else:  # pragma: no cover
diff --git a/tools/sanitizers/tsan_suppressions.txt b/tools/sanitizers/tsan_suppressions.txt
new file mode 100644
index 0000000..270340e
--- /dev/null
+++ b/tools/sanitizers/tsan_suppressions.txt
@@ -0,0 +1,6 @@
+# Suppressions for TSan v2
+# https://code.google.com/p/thread-sanitizer/wiki/Suppressions
+
+# Incorrectly detected lock cycles in test-lockers
+# https://code.google.com/p/thread-sanitizer/issues/detail?id=81
+deadlock:LockAndUnlockDifferentIsolatesThread::Run
diff --git a/tools/shell-utils.h b/tools/shell-utils.h
index ac61fb6..7b51d2f 100644
--- a/tools/shell-utils.h
+++ b/tools/shell-utils.h
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Utility functions used by parser-shell and lexer-shell.
+// Utility functions used by parser-shell.
 
 #include <stdio.h>
 
diff --git a/tools/testrunner/local/execution.py b/tools/testrunner/local/execution.py
index 36ce7be..5c5fbac 100644
--- a/tools/testrunner/local/execution.py
+++ b/tools/testrunner/local/execution.py
@@ -33,6 +33,7 @@
 from pool import Pool
 from . import commands
 from . import perfdata
+from . import statusfile
 from . import utils
 
 
@@ -98,6 +99,10 @@
         "--stress-opt" in self.context.mode_flags or
         "--stress-opt" in self.context.extra_flags):
       timeout *= 4
+    # FIXME(machenbach): Make this more OO. Don't expose default outcomes or
+    # the like.
+    if statusfile.IsSlow(test.outcomes or [statusfile.PASS]):
+      timeout *= 2
     if test.dependency is not None:
       dep_command = [ c.replace(test.path, test.dependency) for c in command ]
     else:
diff --git a/tools/testrunner/local/progress.py b/tools/testrunner/local/progress.py
index 8caa58c..2616958 100644
--- a/tools/testrunner/local/progress.py
+++ b/tools/testrunner/local/progress.py
@@ -333,6 +333,7 @@
       "stderr": test.output.stderr,
       "exit_code": test.output.exit_code,
       "result": test.suite.GetOutcome(test),
+      "expected": list(test.outcomes or ["PASS"]),
     })
 
 
diff --git a/tools/testrunner/local/statusfile.py b/tools/testrunner/local/statusfile.py
index 7c3ca7f..a313f05 100644
--- a/tools/testrunner/local/statusfile.py
+++ b/tools/testrunner/local/statusfile.py
@@ -35,6 +35,7 @@
 CRASH = "CRASH"
 SLOW = "SLOW"
 FLAKY = "FLAKY"
+FAST_VARIANTS = "FAST_VARIANTS"
 NO_VARIANTS = "NO_VARIANTS"
 # These are just for the status files and are mapped below in DEFS:
 FAIL_OK = "FAIL_OK"
@@ -44,7 +45,7 @@
 
 KEYWORDS = {}
 for key in [SKIP, FAIL, PASS, OKAY, TIMEOUT, CRASH, SLOW, FLAKY, FAIL_OK,
-            NO_VARIANTS, PASS_OR_FAIL, ALWAYS]:
+            FAST_VARIANTS, NO_VARIANTS, PASS_OR_FAIL, ALWAYS]:
   KEYWORDS[key] = key
 
 DEFS = {FAIL_OK: [FAIL, OKAY],
@@ -70,6 +71,10 @@
   return NO_VARIANTS in outcomes
 
 
+def OnlyFastVariants(outcomes):
+  return FAST_VARIANTS in outcomes
+
+
 def IsFlaky(outcomes):
   return FLAKY in outcomes
 
diff --git a/tools/testrunner/local/testsuite.py b/tools/testrunner/local/testsuite.py
index 47bc08f..84f07fe 100644
--- a/tools/testrunner/local/testsuite.py
+++ b/tools/testrunner/local/testsuite.py
@@ -34,6 +34,17 @@
 from . import utils
 from ..objects import testcase
 
+# Use this to run several variants of the tests.
+VARIANT_FLAGS = {
+    "default": [],
+    "stress": ["--stress-opt", "--always-opt"],
+    "turbofan": ["--turbo-asm", "--turbo-filter=*", "--always-opt"],
+    "nocrankshaft": ["--nocrankshaft"]}
+
+FAST_VARIANT_FLAGS = [
+    f for v, f in VARIANT_FLAGS.iteritems() if v in ["default", "turbofan"]
+]
+
 class TestSuite(object):
 
   @staticmethod
@@ -81,6 +92,8 @@
   def VariantFlags(self, testcase, default_flags):
     if testcase.outcomes and statusfile.OnlyStandardVariant(testcase.outcomes):
       return [[]]
+    if testcase.outcomes and statusfile.OnlyFastVariants(testcase.outcomes):
+      return filter(lambda flags: flags in FAST_VARIANT_FLAGS, default_flags)
     return default_flags
 
   def DownloadData(self):
@@ -123,6 +136,9 @@
         t.outcomes = self.rules[testname]
         if statusfile.DoSkip(t.outcomes):
           continue  # Don't add skipped tests to |filtered|.
+        for outcome in t.outcomes:
+          if outcome.startswith('Flags: '):
+            t.flags += outcome[7:].split()
         flaky = statusfile.IsFlaky(t.outcomes)
         slow = statusfile.IsSlow(t.outcomes)
         pass_fail = statusfile.IsPassOrFail(t.outcomes)
@@ -234,7 +250,7 @@
     if output.exit_code != 0:
       print output.stdout
       print output.stderr
-      return []
+      raise Exception("Test executable failed to list the tests.")
     tests = []
     test_case = ''
     for line in output.stdout.splitlines():
diff --git a/tools/testrunner/objects/testcase.py b/tools/testrunner/objects/testcase.py
index ca82606..6c55082 100644
--- a/tools/testrunner/objects/testcase.py
+++ b/tools/testrunner/objects/testcase.py
@@ -29,10 +29,10 @@
 from . import output
 
 class TestCase(object):
-  def __init__(self, suite, path, flags=[], dependency=None):
-    self.suite = suite  # TestSuite object
-    self.path = path    # string, e.g. 'div-mod', 'test-api/foo'
-    self.flags = flags  # list of strings, flags specific to this test case
+  def __init__(self, suite, path, flags=None, dependency=None):
+    self.suite = suite        # TestSuite object
+    self.path = path          # string, e.g. 'div-mod', 'test-api/foo'
+    self.flags = flags or []  # list of strings, flags specific to this test
     self.dependency = dependency  # |path| for testcase that must be run first
     self.outcomes = None
     self.output = None
diff --git a/tools/tickprocessor.js b/tools/tickprocessor.js
index acd7a71..d544717 100644
--- a/tools/tickprocessor.js
+++ b/tools/tickprocessor.js
@@ -485,6 +485,15 @@
                    this.ticks_.total, null);
   }
 
+  print('\n [C++ entry points]:');
+  print('   ticks    cpp   total   name');
+  var c_entry_functions = this.profile_.getCEntryProfile();
+  var total_c_entry = c_entry_functions[0].ticks;
+  for (var i = 1; i < c_entry_functions.length; i++) {
+    c = c_entry_functions[i];
+    this.printLine(c.name, c.ticks, total_c_entry, totalTicks);
+  }
+
   this.printHeavyProfHeader();
   var heavyProfile = this.profile_.getBottomUpProfile();
   var heavyView = this.viewBuilder_.buildView(heavyProfile);
diff --git a/tools/trace-maps-processor.py b/tools/trace-maps-processor.py
new file mode 100755
index 0000000..bf8c8a8
--- /dev/null
+++ b/tools/trace-maps-processor.py
@@ -0,0 +1,172 @@
+#!/usr/bin/env python
+# Copyright 2014 the V8 project authors. 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
+
+
+action = sys.argv[1]
+
+if action in ["help", "-h", "--help"] or len(sys.argv) != 3:
+  print("Usage: %s <action> <inputfile>, where action can be: \n"
+        "help    Print this message\n"
+        "plain   Print ASCII tree to stdout\n"
+        "dot     Print dot file to stdout\n"
+        "count   Count most frequent transition reasons\n" % sys.argv[0])
+  sys.exit(0)
+
+
+filename = sys.argv[2]
+maps = {}
+root_maps = []
+transitions = {}
+annotations = {}
+
+
+class Map(object):
+
+  def __init__(self, pointer, origin):
+    self.pointer = pointer
+    self.origin = origin
+
+  def __str__(self):
+    return "%s (%s)" % (self.pointer, self.origin)
+
+
+class Transition(object):
+
+  def __init__(self, from_map, to_map, reason):
+    self.from_map = from_map
+    self.to_map = to_map
+    self.reason = reason
+
+
+def RegisterNewMap(raw_map):
+  if raw_map in annotations:
+    annotations[raw_map] += 1
+  else:
+    annotations[raw_map] = 0
+  return AnnotateExistingMap(raw_map)
+
+
+def AnnotateExistingMap(raw_map):
+  return "%s_%d" % (raw_map, annotations[raw_map])
+
+
+def AddMap(pointer, origin):
+  pointer = RegisterNewMap(pointer)
+  maps[pointer] = Map(pointer, origin)
+  return pointer
+
+
+def AddTransition(from_map, to_map, reason):
+  from_map = AnnotateExistingMap(from_map)
+  to_map = AnnotateExistingMap(to_map)
+  if from_map not in transitions:
+    transitions[from_map] = {}
+  targets = transitions[from_map]
+  if to_map in targets:
+    # Some events get printed twice, that's OK. In some cases, ignore the
+    # second output...
+    old_reason = targets[to_map].reason
+    if old_reason.startswith("ReplaceDescriptors"):
+      return
+    # ...and in others use it for additional detail.
+    if reason in []:
+      targets[to_map].reason = reason
+      return
+    # Unexpected duplicate events? Warn.
+    print("// warning: already have a transition from %s to %s, reason: %s" %
+            (from_map, to_map, targets[to_map].reason))
+    return
+  targets[to_map] = Transition(from_map, to_map, reason)
+
+
+with open(filename, "r") as f:
+  last_to_map = ""
+  for line in f:
+    if not line.startswith("[TraceMaps: "): continue
+    words = line.split(" ")
+    event = words[1]
+    if event == "InitialMap":
+      assert words[2] == "map="
+      assert words[4] == "SFI="
+      new_map = AddMap(words[3], "SFI#%s" % words[5])
+      root_maps.append(new_map)
+      continue
+    if words[2] == "from=" and words[4] == "to=":
+      from_map = words[3]
+      to_map = words[5]
+      if from_map not in annotations:
+        print("// warning: unknown from_map %s" % from_map)
+        new_map = AddMap(from_map, "<unknown>")
+        root_maps.append(new_map)
+      if to_map != last_to_map:
+        AddMap(to_map, "<transition> (%s)" % event)
+      last_to_map = to_map
+      if event in ["Transition", "NoTransition"]:
+        assert words[6] == "name=", line
+        reason = "%s: %s" % (event, words[7])
+      elif event in ["Normalize", "ReplaceDescriptors", "SlowToFast"]:
+        assert words[6] == "reason=", line
+        reason = "%s: %s" % (event, words[7])
+        if words[8].strip() != "]":
+          reason = "%s_%s" % (reason, words[8])
+      else:
+        reason = event
+      AddTransition(from_map, to_map, reason)
+      continue
+
+
+def PlainPrint(m, indent, label):
+  print("%s%s (%s)" % (indent, m, label))
+  if m in transitions:
+    for t in transitions[m]:
+      PlainPrint(t, indent + "  ", transitions[m][t].reason)
+
+
+def CountTransitions(m):
+  if m not in transitions: return 0
+  return len(transitions[m])
+
+
+def DotPrint(m, label):
+  print("m%s [label=\"%s\"]" % (m[2:], label))
+  if m in transitions:
+    for t in transitions[m]:
+      # GraphViz doesn't like node labels looking like numbers, so use
+      # "m..." instead of "0x...".
+      print("m%s -> m%s" % (m[2:], t[2:]))
+      reason = transitions[m][t].reason
+      reason = reason.replace("\\", "BACKSLASH")
+      reason = reason.replace("\"", "\\\"")
+      DotPrint(t, reason)
+
+
+if action == "plain":
+  root_maps = sorted(root_maps, key=CountTransitions, reverse=True)
+  for m in root_maps:
+    PlainPrint(m, "", maps[m].origin)
+
+elif action == "dot":
+  print("digraph g {")
+  for m in root_maps:
+    DotPrint(m, maps[m].origin)
+  print("}")
+
+elif action == "count":
+  reasons = {}
+  for s in transitions:
+    for t in transitions[s]:
+      reason = transitions[s][t].reason
+      if reason not in reasons:
+        reasons[reason] = 1
+      else:
+        reasons[reason] += 1
+  reasons_list = []
+  for r in reasons:
+    reasons_list.append("%8d %s" % (reasons[r], r))
+  reasons_list.sort(reverse=True)
+  for r in reasons_list[:20]:
+    print r
diff --git a/tools/try_perf.py b/tools/try_perf.py
new file mode 100755
index 0000000..fcd1ddc
--- /dev/null
+++ b/tools/try_perf.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# Copyright 2014 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import find_depot_tools
+import sys
+
+find_depot_tools.add_depot_tools_to_path()
+
+from git_cl import Changelist
+
+BOTS = [
+  'v8_linux32_perf_try',
+  'v8_linux64_perf_try',
+]
+
+def main(tests):
+  cl = Changelist()
+  if not cl.GetIssue():
+    print 'Need to upload first'
+    return 1
+
+  props = cl.GetIssueProperties()
+  if props.get('closed'):
+    print 'Cannot send tryjobs for a closed CL'
+    return 1
+
+  if props.get('private'):
+    print 'Cannot use trybots with private issue'
+    return 1
+
+  if not tests:
+    print 'Please specify the benchmarks to run as arguments.'
+    return 1
+
+  masters = {'internal.client.v8': dict((b, tests) for b in BOTS)}
+  cl.RpcServer().trigger_distributed_try_jobs(
+        cl.GetIssue(), cl.GetMostRecentPatchset(), cl.GetBranch(),
+        False, None, masters)
+  return 0
+
+if __name__ == "__main__":  # pragma: no cover
+  sys.exit(main(sys.argv[1:]))
diff --git a/tools/unittests/run_perf_test.py b/tools/unittests/run_perf_test.py
index 76e8d23..f9ea0c0 100644
--- a/tools/unittests/run_perf_test.py
+++ b/tools/unittests/run_perf_test.py
@@ -174,11 +174,25 @@
     self.assertEquals(0, self._CallMain())
     self._VerifyResults("test", "score", [
       {"name": "Richards", "results": ["1.234"], "stddev": ""},
-      {"name": "DeltaBlue", "results": ["10657567"], "stddev": ""},
+      {"name": "DeltaBlue", "results": ["10657567.0"], "stddev": ""},
     ])
     self._VerifyErrors([])
     self._VerifyMock(path.join("out", "x64.release", "d7"), "--flag", "run.js")
 
+  def testOneRunWithTestFlags(self):
+    test_input = dict(V8_JSON)
+    test_input["test_flags"] = ["2", "test_name"]
+    self._WriteTestInput(test_input)
+    self._MockCommand(["."], ["Richards: 1.234\nDeltaBlue: 10657567"])
+    self.assertEquals(0, self._CallMain())
+    self._VerifyResults("test", "score", [
+      {"name": "Richards", "results": ["1.234"], "stddev": ""},
+      {"name": "DeltaBlue", "results": ["10657567.0"], "stddev": ""},
+    ])
+    self._VerifyErrors([])
+    self._VerifyMock(path.join("out", "x64.release", "d7"), "--flag", "run.js",
+                     "--", "2", "test_name")
+
   def testTwoRuns_Units_SuiteName(self):
     test_input = dict(V8_JSON)
     test_input["run_count"] = 2
@@ -190,8 +204,8 @@
                        "Richards: 50\nDeltaBlue: 300\n"])
     self.assertEquals(0, self._CallMain())
     self._VerifyResults("v8", "ms", [
-      {"name": "Richards", "results": ["50", "100"], "stddev": ""},
-      {"name": "DeltaBlue", "results": ["300", "200"], "stddev": ""},
+      {"name": "Richards", "results": ["50.0", "100.0"], "stddev": ""},
+      {"name": "DeltaBlue", "results": ["300.0", "200.0"], "stddev": ""},
     ])
     self._VerifyErrors([])
     self._VerifyMock(path.join("out", "x64.release", "d7"), "--flag", "run.js")
@@ -208,8 +222,8 @@
                        "Richards: 50\nDeltaBlue: 300\n"])
     self.assertEquals(0, self._CallMain())
     self._VerifyResults("test", "score", [
-      {"name": "Richards", "results": ["50", "100"], "stddev": ""},
-      {"name": "DeltaBlue", "results": ["300", "200"], "stddev": ""},
+      {"name": "Richards", "results": ["50.0", "100.0"], "stddev": ""},
+      {"name": "DeltaBlue", "results": ["300.0", "200.0"], "stddev": ""},
     ])
     self._VerifyErrors([])
     self._VerifyMock(path.join("out", "x64.release", "d7"), "--flag", "run.js")
@@ -227,23 +241,21 @@
     self.assertEquals([
       {"units": "score",
        "graphs": ["test", "Richards"],
-       "results": ["50", "100"],
+       "results": ["50.0", "100.0"],
        "stddev": ""},
       {"units": "ms",
        "graphs": ["test", "Sub", "Leaf"],
-       "results": ["3", "2", "1"],
+       "results": ["3.0", "2.0", "1.0"],
        "stddev": ""},
       {"units": "score",
        "graphs": ["test", "DeltaBlue"],
-       "results": ["200"],
+       "results": ["200.0"],
        "stddev": ""},
       ], self._LoadResults()["traces"])
     self._VerifyErrors([])
     self._VerifyMockMultiple(
-        (path.join("out", "x64.release", "d7"), "--flag", "file1.js",
-         "file2.js", "run.js"),
-        (path.join("out", "x64.release", "d7"), "--flag", "file1.js",
-         "file2.js", "run.js"),
+        (path.join("out", "x64.release", "d7"), "--flag", "run.js"),
+        (path.join("out", "x64.release", "d7"), "--flag", "run.js"),
         (path.join("out", "x64.release", "d8"), "--flag", "run.js"),
         (path.join("out", "x64.release", "d8"), "--flag", "run.js"),
         (path.join("out", "x64.release", "d8"), "--flag", "run.js"),
@@ -258,7 +270,7 @@
     self.assertEquals(0, self._CallMain())
     self._VerifyResults("test", "score", [
       {"name": "Richards", "results": ["1.234"], "stddev": "0.23"},
-      {"name": "DeltaBlue", "results": ["10657567"], "stddev": "106"},
+      {"name": "DeltaBlue", "results": ["10657567.0"], "stddev": "106"},
     ])
     self._VerifyErrors([])
     self._VerifyMock(path.join("out", "x64.release", "d7"), "--flag", "run.js")
@@ -274,8 +286,8 @@
                               "DeltaBlue: 5\nDeltaBlue-stddev: 0.8\n"])
     self.assertEquals(1, self._CallMain())
     self._VerifyResults("test", "score", [
-      {"name": "Richards", "results": ["2", "3"], "stddev": "0.7"},
-      {"name": "DeltaBlue", "results": ["5", "6"], "stddev": "0.8"},
+      {"name": "Richards", "results": ["2.0", "3.0"], "stddev": "0.7"},
+      {"name": "DeltaBlue", "results": ["5.0", "6.0"], "stddev": "0.8"},
     ])
     self._VerifyErrors(
         ["Test Richards should only run once since a stddev is provided "
@@ -292,7 +304,7 @@
     self.assertEquals(0, self._CallMain("--buildbot"))
     self._VerifyResults("test", "score", [
       {"name": "Richards", "results": ["1.234"], "stddev": ""},
-      {"name": "DeltaBlue", "results": ["10657567"], "stddev": ""},
+      {"name": "DeltaBlue", "results": ["10657567.0"], "stddev": ""},
     ])
     self._VerifyErrors([])
     self._VerifyMock(path.join("out", "Release", "d7"), "--flag", "run.js")
@@ -305,7 +317,7 @@
     self.assertEquals(0, self._CallMain("--buildbot"))
     self._VerifyResults("test", "score", [
       {"name": "Richards", "results": ["1.234"], "stddev": ""},
-      {"name": "DeltaBlue", "results": ["10657567"], "stddev": ""},
+      {"name": "DeltaBlue", "results": ["10657567.0"], "stddev": ""},
       {"name": "Total", "results": ["3626.49109719"], "stddev": ""},
     ])
     self._VerifyErrors([])
@@ -315,14 +327,15 @@
     test_input = dict(V8_JSON)
     test_input["total"] = True
     self._WriteTestInput(test_input)
-    self._MockCommand(["."], ["x\nRichaards: 1.234\nDeltaBlue: 10657567\ny\n"])
+    self._MockCommand(["."], ["x\nRichards: bla\nDeltaBlue: 10657567\ny\n"])
     self.assertEquals(1, self._CallMain("--buildbot"))
     self._VerifyResults("test", "score", [
       {"name": "Richards", "results": [], "stddev": ""},
-      {"name": "DeltaBlue", "results": ["10657567"], "stddev": ""},
+      {"name": "DeltaBlue", "results": ["10657567.0"], "stddev": ""},
     ])
     self._VerifyErrors(
-        ["Regexp \"^Richards: (.+)$\" didn't match for test Richards.",
+        ["Regexp \"^Richards: (.+)$\" "
+         "returned a non-numeric for test Richards.",
          "Not all traces have the same number of results."])
     self._VerifyMock(path.join("out", "Release", "d7"), "--flag", "run.js")
 
@@ -332,7 +345,7 @@
     self.assertEquals(1, self._CallMain())
     self._VerifyResults("test", "score", [
       {"name": "Richards", "results": [], "stddev": ""},
-      {"name": "DeltaBlue", "results": ["10657567"], "stddev": ""},
+      {"name": "DeltaBlue", "results": ["10657567.0"], "stddev": ""},
     ])
     self._VerifyErrors(
         ["Regexp \"^Richards: (.+)$\" didn't match for test Richards."])
@@ -342,14 +355,30 @@
     test_input = dict(V8_GENERIC_JSON)
     self._WriteTestInput(test_input)
     self._MockCommand(["."], [
-      "Trace(Test1), Result(1.234), StdDev(0.23)\n"
-      "Trace(Test2), Result(10657567), StdDev(106)\n"])
-    self.assertEquals(0, self._CallMain())
-    self._VerifyResults("test", "ms", [
-      {"name": "Test1", "results": ["1.234"], "stddev": "0.23"},
-      {"name": "Test2", "results": ["10657567"], "stddev": "106"},
-    ])
-    self._VerifyErrors([])
+      "RESULT Infra: Constant1= 11 count\n"
+      "RESULT Infra: Constant2= [10,5,10,15] count\n"
+      "RESULT Infra: Constant3= {12,1.2} count\n"
+      "RESULT Infra: Constant4= [10,5,error,15] count\n"])
+    self.assertEquals(1, self._CallMain())
+    self.assertEquals([
+      {"units": "count",
+       "graphs": ["test", "Infra", "Constant1"],
+       "results": ["11.0"],
+       "stddev": ""},
+      {"units": "count",
+       "graphs": ["test", "Infra", "Constant2"],
+       "results": ["10.0", "5.0", "10.0", "15.0"],
+       "stddev": ""},
+      {"units": "count",
+       "graphs": ["test", "Infra", "Constant3"],
+       "results": ["12.0"],
+       "stddev": "1.2"},
+      {"units": "count",
+       "graphs": ["test", "Infra", "Constant4"],
+       "results": [],
+       "stddev": ""},
+      ], self._LoadResults()["traces"])
+    self._VerifyErrors(["Found non-numeric in test/Infra/Constant4"])
     self._VerifyMock(path.join("out", "x64.release", "cc"), "--flag", "")
 
   def testOneRunTimingOut(self):
@@ -368,3 +397,22 @@
     ])
     self._VerifyMock(
         path.join("out", "x64.release", "d7"), "--flag", "run.js", timeout=70)
+
+  # Simple test that mocks out the android platform. Testing the platform would
+  # require lots of complicated mocks for the android tools.
+  def testAndroid(self):
+    self._WriteTestInput(V8_JSON)
+    platform = run_perf.Platform
+    platform.PreExecution = MagicMock(return_value=None)
+    platform.PostExecution = MagicMock(return_value=None)
+    platform.PreTests = MagicMock(return_value=None)
+    platform.Run = MagicMock(
+        return_value="Richards: 1.234\nDeltaBlue: 10657567\n")
+    run_perf.AndroidPlatform = MagicMock(return_value=platform)
+    self.assertEquals(
+        0, self._CallMain("--android-build-tools", "/some/dir",
+                          "--arch", "android_arm"))
+    self._VerifyResults("test", "score", [
+      {"name": "Richards", "results": ["1.234"], "stddev": ""},
+      {"name": "DeltaBlue", "results": ["10657567.0"], "stddev": ""},
+    ])
diff --git a/tools/whitespace.txt b/tools/whitespace.txt
index 305e8ed..657e68f 100644
--- a/tools/whitespace.txt
+++ b/tools/whitespace.txt
@@ -1,8 +1,8 @@
-You can modify this file to create no-op changelists..
+You can modify this file to create no-op changelists.
 
 Try to write something funny. And please don't add trailing whitespace.
 
 A Smi walks into a bar and says:
 "I'm so deoptimized today!"
 The doubles heard this and started to unbox.
-The Smi looked at them when a crazy v8-autoroll account showed up..............
+The Smi looked at them when a crazy v8-autoroll account showed up...........